DO NOT MERGE - Merge pi-platform-release (PPRL.190605.003) into stage-aosp-master
Bug: 134605042
Change-Id: I5be87422d75fb89d35135a5e087920fae1f6b2d6
diff --git a/Android.bp b/Android.bp
index fb0fdd9..c56d51d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -3,8 +3,12 @@
"build",
"btif",
"btcore",
+ "common",
"audio_a2dp_hw",
+ "audio_bluetooth_hw",
+ "audio_hal_interface",
"audio_hearing_aid_hw",
+ "gd",
"hci",
"utils",
"device",
@@ -22,3 +26,10 @@
"tools",
"proto",
]
+
+filegroup {
+ name: "BluetoothTestConfigTemplate",
+ srcs: [
+ "AndroidTestTemplate.xml",
+ ],
+}
diff --git a/Android.mk b/Android.mk
deleted file mode 100644
index 5053e7d..0000000
--- a/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/AndroidTestTemplate.xml b/AndroidTestTemplate.xml
new file mode 100644
index 0000000..601be93
--- /dev/null
+++ b/AndroidTestTemplate.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2018 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.
+-->
+<configuration description="Runs {MODULE}.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="{MODULE}->/data/local/tmp/{MODULE}" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="settings put global ble_scan_always_enabled 0" />
+ <option name="run-command" value="svc bluetooth disable" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.FolderSaver">
+ <option name="device-path" value="/data/vendor/ssrdump" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="{MODULE}" />
+ <option name="run-test-as" value="0" />
+ </test>
+</configuration>
diff --git a/BUILD.gn b/BUILD.gn
index 04c32a1..456fbeb 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -39,10 +39,3 @@
"//device:net_test_device",
]
}
-
-group("test_tools") {
- testonly = true
- deps = [
- "//tools/mcap_tool:mcap_tool"
- ]
-}
diff --git a/OWNERS b/OWNERS
index 2ddc791..aeb2b83 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,8 +1,11 @@
set noparent
# Project owners
-eisenbach@google.com
-apanicke@google.com
+zachoverflow@google.com
+cmanton@google.com
+hsz@google.com
jpawlowski@google.com
mylesgw@google.com
-pavlin@google.com
+optedoblivion@google.com
+siyuanh@google.com
+stng@google.com
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..5f6e378
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,81 @@
+{
+ "postsubmit" : [
+ {
+ "name" : "bluetooth_test_common"
+ },
+ {
+ "name" : "bluetoothtbd_test"
+ },
+ {
+ "name" : "net_test_audio_a2dp_hw"
+ },
+ {
+ "name" : "net_test_avrcp"
+ },
+ {
+ "name" : "net_test_btcore"
+ },
+ {
+ "name" : "net_test_btif"
+ },
+ {
+ "name" : "net_test_btif_profile_queue"
+ },
+ {
+ "name" : "net_test_btpackets"
+ },
+ {
+ "name" : "net_test_device"
+ },
+ {
+ "name" : "net_test_hci"
+ },
+ {
+ "name" : "net_test_performance"
+ },
+ {
+ "name" : "net_test_stack"
+ },
+ {
+ "name" : "net_test_stack_ad_parser"
+ },
+ {
+ "name" : "net_test_stack_multi_adv"
+ },
+ {
+ "name" : "net_test_stack_rfcomm"
+ },
+ {
+ "name" : "net_test_stack_smp"
+ },
+ {
+ "name" : "net_test_types"
+ }
+ ],
+ "presubmit" : [
+ {
+ "name" : "bluetooth_test_common",
+ "host" : true
+ },
+ {
+ "name" : "bluetoothtbd_test",
+ "host" : true
+ },
+ {
+ "name" : "net_test_avrcp",
+ "host" : true
+ },
+ {
+ "name" : "net_test_btcore",
+ "host" : true
+ },
+ {
+ "name" : "net_test_btpackets",
+ "host" : true
+ },
+ {
+ "name" : "net_test_types",
+ "host" : true
+ }
+ ]
+}
diff --git a/audio_a2dp_hw/Android.bp b/audio_a2dp_hw/Android.bp
index 7a23e27..fac3655 100644
--- a/audio_a2dp_hw/Android.bp
+++ b/audio_a2dp_hw/Android.bp
@@ -5,7 +5,7 @@
"system/bt",
"system/bt/include",
"system/bt/audio_a2dp_hw/include",
- ]
+ ],
}
// Audio A2DP shared library for target
diff --git a/audio_a2dp_hw/src/audio_a2dp_hw.cc b/audio_a2dp_hw/src/audio_a2dp_hw.cc
index 0e1a3c2..2fb139f 100644
--- a/audio_a2dp_hw/src/audio_a2dp_hw.cc
+++ b/audio_a2dp_hw/src/audio_a2dp_hw.cc
@@ -700,8 +700,8 @@
codec_config.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32;
break;
case AUDIO_FORMAT_PCM_8_24_BIT:
- // FALLTHROUGH
- // All 24-bit audio is expected in AUDIO_FORMAT_PCM_24_BIT_PACKED format
+ // All 24-bit audio is expected in AUDIO_FORMAT_PCM_24_BIT_PACKED format
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
default:
ERROR("Invalid audio format: 0x%x", common->cfg.format);
return -1;
diff --git a/audio_bluetooth_hw/Android.bp b/audio_bluetooth_hw/Android.bp
new file mode 100644
index 0000000..9cdd64a
--- /dev/null
+++ b/audio_bluetooth_hw/Android.bp
@@ -0,0 +1,50 @@
+// The format of the name is audio.<type>.<hardware/etc>.so
+
+cc_library_shared {
+ name: "audio.bluetooth.default",
+ relative_install_path: "hw",
+ proprietary: true,
+ srcs: [
+ "audio_bluetooth_hw.cc",
+ "stream_apis.cc",
+ "device_port_proxy.cc",
+ "utils.cc",
+ ],
+ header_libs: ["libhardware_headers"],
+ shared_libs: [
+ "android.hardware.bluetooth.audio@2.0",
+ "libaudioutils",
+ "libbase",
+ "libbluetooth_audio_session",
+ "libcutils",
+ "libfmq",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libutils",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-parameter",
+ ],
+}
+
+cc_test {
+ name: "audio_bluetooth_hw_test",
+ srcs: [
+ "utils.cc",
+ "utils_unittest.cc",
+ ],
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "liblog",
+ "libutils",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-parameter",
+ ],
+}
diff --git a/audio_bluetooth_hw/audio_bluetooth_hw.cc b/audio_bluetooth_hw/audio_bluetooth_hw.cc
new file mode 100644
index 0000000..e32d88b
--- /dev/null
+++ b/audio_bluetooth_hw/audio_bluetooth_hw.cc
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2019 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 "BTAudioHw"
+
+#include <android-base/logging.h>
+#include <errno.h>
+#include <hardware/audio.h>
+#include <hardware/hardware.h>
+#include <log/log.h>
+#include <malloc.h>
+#include <string.h>
+#include <system/audio.h>
+
+#include "stream_apis.h"
+#include "utils.h"
+
+static int adev_set_parameters(struct audio_hw_device* dev,
+ const char* kvpairs) {
+ LOG(VERBOSE) << __func__ << ": kevpairs=[" << kvpairs << "]";
+ return -ENOSYS;
+}
+
+static char* adev_get_parameters(const struct audio_hw_device* dev,
+ const char* keys) {
+ LOG(VERBOSE) << __func__ << ": keys=[" << keys << "]";
+ return strdup("");
+}
+
+static int adev_init_check(const struct audio_hw_device* dev) { return 0; }
+
+static int adev_set_voice_volume(struct audio_hw_device* dev, float volume) {
+ LOG(VERBOSE) << __func__ << ": volume=" << volume;
+ return -ENOSYS;
+}
+
+static int adev_set_master_volume(struct audio_hw_device* dev, float volume) {
+ LOG(VERBOSE) << __func__ << ": volume=" << volume;
+ return -ENOSYS;
+}
+
+static int adev_get_master_volume(struct audio_hw_device* dev, float* volume) {
+ return -ENOSYS;
+}
+
+static int adev_set_master_mute(struct audio_hw_device* dev, bool muted) {
+ LOG(VERBOSE) << __func__ << ": mute=" << muted;
+ return -ENOSYS;
+}
+
+static int adev_get_master_mute(struct audio_hw_device* dev, bool* muted) {
+ return -ENOSYS;
+}
+
+static int adev_set_mode(struct audio_hw_device* dev, audio_mode_t mode) {
+ LOG(VERBOSE) << __func__ << ": mode=" << mode;
+ return 0;
+}
+
+static int adev_set_mic_mute(struct audio_hw_device* dev, bool state) {
+ LOG(VERBOSE) << __func__ << ": state=" << state;
+ return -ENOSYS;
+}
+
+static int adev_get_mic_mute(const struct audio_hw_device* dev, bool* state) {
+ return -ENOSYS;
+}
+
+static int adev_dump(const audio_hw_device_t* device, int fd) { return 0; }
+
+static int adev_close(hw_device_t* device) {
+ free(device);
+ return 0;
+}
+
+static int adev_open(const hw_module_t* module, const char* name,
+ hw_device_t** device) {
+ LOG(VERBOSE) << __func__ << ": name=[" << name << "]";
+ if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) return -EINVAL;
+
+ struct audio_hw_device* adev =
+ (struct audio_hw_device*)calloc(1, sizeof(struct audio_hw_device));
+ if (!adev) return -ENOMEM;
+
+ adev->common.tag = HARDWARE_DEVICE_TAG;
+ adev->common.version = AUDIO_DEVICE_API_VERSION_2_0;
+ adev->common.module = (struct hw_module_t*)module;
+ adev->common.close = adev_close;
+
+ adev->init_check = adev_init_check;
+ adev->set_voice_volume = adev_set_voice_volume;
+ adev->set_master_volume = adev_set_master_volume;
+ adev->get_master_volume = adev_get_master_volume;
+ adev->set_mode = adev_set_mode;
+ adev->set_mic_mute = adev_set_mic_mute;
+ adev->get_mic_mute = adev_get_mic_mute;
+ adev->set_parameters = adev_set_parameters;
+ adev->get_parameters = adev_get_parameters;
+ adev->get_input_buffer_size = adev_get_input_buffer_size;
+ adev->open_output_stream = adev_open_output_stream;
+ adev->close_output_stream = adev_close_output_stream;
+ adev->open_input_stream = adev_open_input_stream;
+ adev->close_input_stream = adev_close_input_stream;
+ adev->dump = adev_dump;
+ adev->set_master_mute = adev_set_master_mute;
+ adev->get_master_mute = adev_get_master_mute;
+
+ *device = &adev->common;
+ return 0;
+}
+
+static struct hw_module_methods_t hal_module_methods = {
+ .open = adev_open,
+};
+
+struct audio_module HAL_MODULE_INFO_SYM = {
+ .common =
+ {
+ .tag = HARDWARE_MODULE_TAG,
+ .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
+ .hal_api_version = HARDWARE_HAL_API_VERSION,
+ .id = AUDIO_HARDWARE_MODULE_ID,
+ .name = "Bluetooth Audio HW HAL",
+ .author = "The Android Open Source Project",
+ .methods = &hal_module_methods,
+ },
+};
diff --git a/audio_bluetooth_hw/device_port_proxy.cc b/audio_bluetooth_hw/device_port_proxy.cc
new file mode 100644
index 0000000..6e1fda2
--- /dev/null
+++ b/audio_bluetooth_hw/device_port_proxy.cc
@@ -0,0 +1,445 @@
+/*
+ * Copyright 2019 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 "BTAudioHalDeviceProxy"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <audio_utils/primitives.h>
+#include <inttypes.h>
+#include <log/log.h>
+#include <stdlib.h>
+
+#include "BluetoothAudioSessionControl.h"
+#include "device_port_proxy.h"
+#include "stream_apis.h"
+#include "utils.h"
+
+namespace android {
+namespace bluetooth {
+namespace audio {
+
+using ::android::base::StringPrintf;
+using ::android::bluetooth::audio::BluetoothAudioSessionControl;
+using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
+using ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
+using ::android::hardware::bluetooth::audio::V2_0::PcmParameters;
+using ::android::hardware::bluetooth::audio::V2_0::SampleRate;
+using ::android::hardware::bluetooth::audio::V2_0::SessionType;
+using BluetoothAudioStatus =
+ ::android::hardware::bluetooth::audio::V2_0::Status;
+using ControlResultCallback = std::function<void(
+ uint16_t cookie, bool start_resp, const BluetoothAudioStatus& status)>;
+using SessionChangedCallback = std::function<void(uint16_t cookie)>;
+
+namespace {
+
+unsigned int SampleRateToAudioFormat(SampleRate sample_rate) {
+ switch (sample_rate) {
+ case SampleRate::RATE_16000:
+ return 16000;
+ case SampleRate::RATE_24000:
+ return 24000;
+ case SampleRate::RATE_44100:
+ return 44100;
+ case SampleRate::RATE_48000:
+ return 48000;
+ case SampleRate::RATE_88200:
+ return 88200;
+ case SampleRate::RATE_96000:
+ return 96000;
+ case SampleRate::RATE_176400:
+ return 176400;
+ case SampleRate::RATE_192000:
+ return 192000;
+ default:
+ return kBluetoothDefaultSampleRate;
+ }
+}
+audio_channel_mask_t ChannelModeToAudioFormat(ChannelMode channel_mode) {
+ switch (channel_mode) {
+ case ChannelMode::MONO:
+ return AUDIO_CHANNEL_OUT_MONO;
+ case ChannelMode::STEREO:
+ return AUDIO_CHANNEL_OUT_STEREO;
+ default:
+ return kBluetoothDefaultOutputChannelModeMask;
+ }
+}
+
+audio_format_t BitsPerSampleToAudioFormat(BitsPerSample bits_per_sample) {
+ switch (bits_per_sample) {
+ case BitsPerSample::BITS_16:
+ return AUDIO_FORMAT_PCM_16_BIT;
+ case BitsPerSample::BITS_24:
+ return AUDIO_FORMAT_PCM_24_BIT_PACKED;
+ case BitsPerSample::BITS_32:
+ return AUDIO_FORMAT_PCM_32_BIT;
+ default:
+ return kBluetoothDefaultAudioFormatBitsPerSample;
+ }
+}
+
+// The maximum time to wait in std::condition_variable::wait_for()
+constexpr unsigned int kMaxWaitingTimeMs = 4500;
+
+} // namespace
+
+BluetoothAudioPortOut::BluetoothAudioPortOut()
+ : state_(BluetoothStreamState::DISABLED),
+ session_type_(SessionType::UNKNOWN),
+ cookie_(android::bluetooth::audio::kObserversCookieUndefined) {}
+
+bool BluetoothAudioPortOut::SetUp(audio_devices_t devices) {
+ if (!init_session_type(devices)) return false;
+
+ state_ = BluetoothStreamState::STANDBY;
+
+ auto control_result_cb = [port = this](uint16_t cookie, bool start_resp,
+ const BluetoothAudioStatus& status) {
+ if (!port->in_use()) {
+ LOG(ERROR) << "control_result_cb: BluetoothAudioPortOut is not in use";
+ return;
+ }
+ if (port->cookie_ != cookie) {
+ LOG(ERROR) << "control_result_cb: proxy of device port (cookie=" << StringPrintf("%#hx", cookie)
+ << ") is corrupted";
+ return;
+ }
+ port->ControlResultHandler(status);
+ };
+ auto session_changed_cb = [port = this](uint16_t cookie) {
+ if (!port->in_use()) {
+ LOG(ERROR) << "session_changed_cb: BluetoothAudioPortOut is not in use";
+ return;
+ }
+ if (port->cookie_ != cookie) {
+ LOG(ERROR) << "session_changed_cb: proxy of device port (cookie=" << StringPrintf("%#hx", cookie)
+ << ") is corrupted";
+ return;
+ }
+ port->SessionChangedHandler();
+ };
+ ::android::bluetooth::audio::PortStatusCallbacks cbacks = {
+ .control_result_cb_ = control_result_cb,
+ .session_changed_cb_ = session_changed_cb};
+ cookie_ = BluetoothAudioSessionControl::RegisterControlResultCback(
+ session_type_, cbacks);
+ LOG(INFO) << __func__ << ": session_type=" << toString(session_type_) << ", cookie=" << StringPrintf("%#hx", cookie_);
+
+ return (cookie_ != android::bluetooth::audio::kObserversCookieUndefined);
+}
+
+bool BluetoothAudioPortOut::init_session_type(audio_devices_t device) {
+ switch (device) {
+ case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
+ LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_OUT_BLUETOOTH_A2DP (HEADPHONES/SPEAKER) ("
+ << StringPrintf("%#x", device) << ")";
+ session_type_ = SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH;
+ break;
+ case AUDIO_DEVICE_OUT_HEARING_AID:
+ LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_OUT_HEARING_AID (MEDIA/VOICE) (" << StringPrintf("%#x", device)
+ << ")";
+ session_type_ = SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH;
+ break;
+ default:
+ LOG(ERROR) << __func__ << ": unknown device=" << StringPrintf("%#x", device);
+ return false;
+ }
+
+ if (!BluetoothAudioSessionControl::IsSessionReady(session_type_)) {
+ LOG(ERROR) << __func__ << ": device=" << StringPrintf("%#x", device) << ", session_type=" << toString(session_type_)
+ << " is not ready";
+ return false;
+ }
+ return true;
+}
+
+void BluetoothAudioPortOut::TearDown() {
+ if (!in_use()) {
+ LOG(ERROR) << __func__ << ": session_type=" << toString(session_type_)
+ << ", cookie=" << StringPrintf("%#hx", cookie_) << " unknown monitor";
+ return;
+ }
+
+ LOG(INFO) << __func__ << ": session_type=" << toString(session_type_) << ", cookie=" << StringPrintf("%#hx", cookie_);
+ BluetoothAudioSessionControl::UnregisterControlResultCback(session_type_,
+ cookie_);
+ cookie_ = android::bluetooth::audio::kObserversCookieUndefined;
+}
+
+void BluetoothAudioPortOut::ControlResultHandler(
+ const BluetoothAudioStatus& status) {
+ if (!in_use()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
+ return;
+ }
+ std::unique_lock<std::mutex> port_lock(cv_mutex_);
+ BluetoothStreamState previous_state = state_;
+ LOG(INFO) << "control_result_cb: session_type=" << toString(session_type_)
+ << ", cookie=" << StringPrintf("%#hx", cookie_) << ", previous_state=" << previous_state
+ << ", status=" << toString(status);
+
+ switch (previous_state) {
+ case BluetoothStreamState::STARTING:
+ if (status == BluetoothAudioStatus::SUCCESS) {
+ state_ = BluetoothStreamState::STARTED;
+ } else {
+ // Set to standby since the stack may be busy switching between outputs
+ LOG(WARNING) << "control_result_cb: status=" << toString(status)
+ << " failure for session_type=" << toString(session_type_)
+ << ", cookie=" << StringPrintf("%#hx", cookie_) << ", previous_state=" << previous_state;
+ state_ = BluetoothStreamState::STANDBY;
+ }
+ break;
+ case BluetoothStreamState::SUSPENDING:
+ if (status == BluetoothAudioStatus::SUCCESS) {
+ state_ = BluetoothStreamState::STANDBY;
+ } else {
+ // It will be failed if the headset is disconnecting, and set to disable
+ // to wait for re-init again
+ LOG(WARNING) << "control_result_cb: status=" << toString(status)
+ << " failure for session_type=" << toString(session_type_)
+ << ", cookie=" << StringPrintf("%#hx", cookie_) << ", previous_state=" << previous_state;
+ state_ = BluetoothStreamState::DISABLED;
+ }
+ break;
+ default:
+ LOG(ERROR) << "control_result_cb: unexpected status=" << toString(status)
+ << " for session_type=" << toString(session_type_) << ", cookie=" << StringPrintf("%#hx", cookie_)
+ << ", previous_state=" << previous_state;
+ return;
+ }
+ port_lock.unlock();
+ internal_cv_.notify_all();
+}
+
+void BluetoothAudioPortOut::SessionChangedHandler() {
+ if (!in_use()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
+ return;
+ }
+ std::unique_lock<std::mutex> port_lock(cv_mutex_);
+ BluetoothStreamState previous_state = state_;
+ LOG(INFO) << "session_changed_cb: session_type=" << toString(session_type_)
+ << ", cookie=" << StringPrintf("%#hx", cookie_) << ", previous_state=" << previous_state;
+ if (previous_state != BluetoothStreamState::DISABLED) {
+ state_ = BluetoothStreamState::DISABLED;
+ } else {
+ state_ = BluetoothStreamState::STANDBY;
+ }
+ port_lock.unlock();
+ internal_cv_.notify_all();
+}
+
+bool BluetoothAudioPortOut::in_use() const {
+ return (cookie_ != android::bluetooth::audio::kObserversCookieUndefined);
+}
+
+bool BluetoothAudioPortOut::LoadAudioConfig(audio_config_t* audio_cfg) const {
+ if (!in_use()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
+ audio_cfg->sample_rate = kBluetoothDefaultSampleRate;
+ audio_cfg->channel_mask = kBluetoothDefaultOutputChannelModeMask;
+ audio_cfg->format = kBluetoothDefaultAudioFormatBitsPerSample;
+ return false;
+ }
+
+ const AudioConfiguration& hal_audio_cfg =
+ BluetoothAudioSessionControl::GetAudioConfig(session_type_);
+ if (hal_audio_cfg.getDiscriminator() !=
+ AudioConfiguration::hidl_discriminator::pcmConfig) {
+ audio_cfg->sample_rate = kBluetoothDefaultSampleRate;
+ audio_cfg->channel_mask = kBluetoothDefaultOutputChannelModeMask;
+ audio_cfg->format = kBluetoothDefaultAudioFormatBitsPerSample;
+ return false;
+ }
+ const PcmParameters& pcm_cfg = hal_audio_cfg.pcmConfig();
+ LOG(VERBOSE) << __func__ << ": session_type=" << toString(session_type_)
+ << ", cookie=" << StringPrintf("%#hx", cookie_) << ", state=" << state_ << ", PcmConfig=["
+ << toString(pcm_cfg) << "]";
+ if (pcm_cfg.sampleRate == SampleRate::RATE_UNKNOWN ||
+ pcm_cfg.channelMode == ChannelMode::UNKNOWN ||
+ pcm_cfg.bitsPerSample == BitsPerSample::BITS_UNKNOWN) {
+ return false;
+ }
+ audio_cfg->sample_rate = SampleRateToAudioFormat(pcm_cfg.sampleRate);
+ audio_cfg->channel_mask =
+ (is_stereo_to_mono_ ? AUDIO_CHANNEL_OUT_STEREO : ChannelModeToAudioFormat(pcm_cfg.channelMode));
+ audio_cfg->format = BitsPerSampleToAudioFormat(pcm_cfg.bitsPerSample);
+ return true;
+}
+
+bool BluetoothAudioPortOut::CondwaitState(BluetoothStreamState state) {
+ bool retval;
+ std::unique_lock<std::mutex> port_lock(cv_mutex_);
+ switch (state) {
+ case BluetoothStreamState::STARTING:
+ LOG(VERBOSE) << __func__ << ": session_type=" << toString(session_type_)
+ << ", cookie=" << StringPrintf("%#hx", cookie_) << " waiting for STARTED";
+ retval = internal_cv_.wait_for(
+ port_lock, std::chrono::milliseconds(kMaxWaitingTimeMs),
+ [this] { return this->state_ != BluetoothStreamState::STARTING; });
+ retval = retval && state_ == BluetoothStreamState::STARTED;
+ break;
+ case BluetoothStreamState::SUSPENDING:
+ LOG(VERBOSE) << __func__ << ": session_type=" << toString(session_type_)
+ << ", cookie=" << StringPrintf("%#hx", cookie_) << " waiting for SUSPENDED";
+ retval = internal_cv_.wait_for(
+ port_lock, std::chrono::milliseconds(kMaxWaitingTimeMs),
+ [this] { return this->state_ != BluetoothStreamState::SUSPENDING; });
+ retval = retval && state_ == BluetoothStreamState::STANDBY;
+ break;
+ default:
+ LOG(WARNING) << __func__ << ": session_type=" << toString(session_type_)
+ << ", cookie=" << StringPrintf("%#hx", cookie_) << " waiting for KNOWN";
+ return false;
+ }
+
+ return retval; // false if any failure like timeout
+}
+
+bool BluetoothAudioPortOut::Start() {
+ if (!in_use()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
+ return false;
+ }
+
+ LOG(INFO) << __func__ << ": session_type=" << toString(session_type_) << ", cookie=" << StringPrintf("%#hx", cookie_)
+ << ", state=" << state_ << ", mono=" << (is_stereo_to_mono_ ? "true" : "false") << " request";
+ bool retval = false;
+ if (state_ == BluetoothStreamState::STANDBY) {
+ state_ = BluetoothStreamState::STARTING;
+ if (BluetoothAudioSessionControl::StartStream(session_type_)) {
+ retval = CondwaitState(BluetoothStreamState::STARTING);
+ } else {
+ LOG(ERROR) << __func__ << ": session_type=" << toString(session_type_)
+ << ", cookie=" << StringPrintf("%#hx", cookie_) << ", state=" << state_ << " Hal fails";
+ }
+ }
+
+ if (retval) {
+ LOG(INFO) << __func__ << ": session_type=" << toString(session_type_)
+ << ", cookie=" << StringPrintf("%#hx", cookie_) << ", state=" << state_
+ << ", mono=" << (is_stereo_to_mono_ ? "true" : "false") << " done";
+ } else {
+ LOG(ERROR) << __func__ << ": session_type=" << toString(session_type_)
+ << ", cookie=" << StringPrintf("%#hx", cookie_) << ", state=" << state_ << " failure";
+ }
+
+ return retval; // false if any failure like timeout
+}
+
+bool BluetoothAudioPortOut::Suspend() {
+ if (!in_use()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
+ return false;
+ }
+
+ LOG(INFO) << __func__ << ": session_type=" << toString(session_type_) << ", cookie=" << StringPrintf("%#hx", cookie_)
+ << ", state=" << state_ << " request";
+ bool retval = false;
+ if (state_ == BluetoothStreamState::STARTED) {
+ state_ = BluetoothStreamState::SUSPENDING;
+ if (BluetoothAudioSessionControl::SuspendStream(session_type_)) {
+ retval = CondwaitState(BluetoothStreamState::SUSPENDING);
+ } else {
+ LOG(ERROR) << __func__ << ": session_type=" << toString(session_type_)
+ << ", cookie=" << StringPrintf("%#hx", cookie_) << ", state=" << state_ << " Hal fails";
+ }
+ }
+
+ if (retval) {
+ LOG(INFO) << __func__ << ": session_type=" << toString(session_type_)
+ << ", cookie=" << StringPrintf("%#hx", cookie_) << ", state=" << state_ << " done";
+ } else {
+ LOG(ERROR) << __func__ << ": session_type=" << toString(session_type_)
+ << ", cookie=" << StringPrintf("%#hx", cookie_) << ", state=" << state_ << " failure";
+ }
+
+ return retval; // false if any failure like timeout
+}
+
+void BluetoothAudioPortOut::Stop() {
+ if (!in_use()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
+ return;
+ }
+ LOG(INFO) << __func__ << ": session_type=" << toString(session_type_) << ", cookie=" << StringPrintf("%#hx", cookie_)
+ << ", state=" << state_ << " request";
+ state_ = BluetoothStreamState::DISABLED;
+ BluetoothAudioSessionControl::StopStream(session_type_);
+ LOG(INFO) << __func__ << ": session_type=" << toString(session_type_) << ", cookie=" << StringPrintf("%#hx", cookie_)
+ << ", state=" << state_ << " done";
+}
+
+size_t BluetoothAudioPortOut::WriteData(const void* buffer, size_t bytes) const {
+ if (!in_use()) return 0;
+ if (!is_stereo_to_mono_) {
+ return BluetoothAudioSessionControl::OutWritePcmData(session_type_, buffer, bytes);
+ }
+
+ // WAR to mix the stereo into Mono (16 bits per sample)
+ const size_t write_frames = bytes >> 2;
+ if (write_frames == 0) return 0;
+ auto src = static_cast<const int16_t*>(buffer);
+ std::unique_ptr<int16_t[]> dst{new int16_t[write_frames]};
+ downmix_to_mono_i16_from_stereo_i16(dst.get(), src, write_frames);
+ // a frame is 16 bits, and the size of a mono frame is equal to half a stereo.
+ return BluetoothAudioSessionControl::OutWritePcmData(session_type_, dst.get(), write_frames * 2) * 2;
+}
+
+bool BluetoothAudioPortOut::GetPresentationPosition(uint64_t* delay_ns,
+ uint64_t* bytes,
+ timespec* timestamp) const {
+ if (!in_use()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
+ return false;
+ }
+ bool retval = BluetoothAudioSessionControl::GetPresentationPosition(
+ session_type_, delay_ns, bytes, timestamp);
+ LOG(VERBOSE) << __func__ << ": session_type=" << StringPrintf("%#hhx", session_type_)
+ << ", cookie=" << StringPrintf("%#hx", cookie_) << ", state=" << state_ << ", delay=" << *delay_ns
+ << "ns, data=" << *bytes << " bytes, timestamp=" << timestamp->tv_sec << "."
+ << StringPrintf("%09ld", timestamp->tv_nsec) << "s";
+
+ return retval;
+}
+
+void BluetoothAudioPortOut::UpdateMetadata(
+ const source_metadata* source_metadata) const {
+ if (!in_use()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
+ return;
+ }
+ LOG(DEBUG) << __func__ << ": session_type=" << toString(session_type_) << ", cookie=" << StringPrintf("%#hx", cookie_)
+ << ", state=" << state_ << ", " << source_metadata->track_count << " track(s)";
+ if (source_metadata->track_count == 0) return;
+ BluetoothAudioSessionControl::UpdateTracksMetadata(session_type_,
+ source_metadata);
+}
+
+BluetoothStreamState BluetoothAudioPortOut::GetState() const { return state_; }
+
+void BluetoothAudioPortOut::SetState(BluetoothStreamState state) {
+ state_ = state;
+}
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace android
diff --git a/audio_bluetooth_hw/device_port_proxy.h b/audio_bluetooth_hw/device_port_proxy.h
new file mode 100644
index 0000000..16db274
--- /dev/null
+++ b/audio_bluetooth_hw/device_port_proxy.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2019 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 <android/hardware/bluetooth/audio/2.0/types.h>
+#include <hardware/audio.h>
+#include <condition_variable>
+#include <mutex>
+#include <unordered_map>
+
+enum class BluetoothStreamState : uint8_t;
+
+namespace android {
+namespace bluetooth {
+namespace audio {
+
+// Proxy for Bluetooth Audio HW Module to communicate with Bluetooth Audio
+// Session Control. All methods are not thread safe, so users must acquire a
+// lock. Note: currently, in stream_apis.cc, if GetState() is only used for
+// verbose logging, it is not locked, so the state may not be synchronized.
+class BluetoothAudioPortOut {
+ public:
+ BluetoothAudioPortOut();
+ ~BluetoothAudioPortOut() = default;
+
+ // Fetch output control / data path of BluetoothAudioPortOut and setup
+ // callbacks into BluetoothAudioProvider. If SetUp() returns false, the audio
+ // HAL must delete this BluetoothAudioPortOut and return EINVAL to caller
+ bool SetUp(audio_devices_t devices);
+
+ // Unregister this BluetoothAudioPortOut from BluetoothAudioSessionControl.
+ // Audio HAL must delete this BluetoothAudioPortOut after calling this.
+ void TearDown();
+
+ // When the Audio framework / HAL tries to query audio config about format,
+ // channel mask and sample rate, it uses this function to fetch from the
+ // Bluetooth stack
+ bool LoadAudioConfig(audio_config_t* audio_cfg) const;
+
+ // WAR to support Mono mode / 16 bits per sample
+ void ForcePcmStereoToMono(bool force) {
+ is_stereo_to_mono_ = force;
+ }
+
+ // When the Audio framework / HAL wants to change the stream state, it invokes
+ // these 3 functions to control the Bluetooth stack (Audio Control Path).
+ // Note: Both Start() and Suspend() will return ture when there are no errors.
+ // Called by Audio framework / HAL to start the stream
+ bool Start();
+ // Called by Audio framework / HAL to suspend the stream
+ bool Suspend();
+ // Called by Audio framework / HAL to stop the stream
+ void Stop();
+
+ // The audio data path to the Bluetooth stack (Software encoding)
+ size_t WriteData(const void* buffer, size_t bytes) const;
+
+ // Called by the Audio framework / HAL to fetch informaiton about audio frames
+ // presented to an external sink.
+ bool GetPresentationPosition(uint64_t* delay_ns, uint64_t* bytes,
+ timespec* timestamp) const;
+
+ // Called by the Audio framework / HAL when the metadata of the stream's
+ // source has been changed.
+ void UpdateMetadata(const source_metadata* source_metadata) const;
+
+ // Return the current BluetoothStreamState
+ BluetoothStreamState GetState() const;
+
+ // Set the current BluetoothStreamState
+ void SetState(BluetoothStreamState state);
+
+ private:
+ BluetoothStreamState state_;
+ ::android::hardware::bluetooth::audio::V2_0::SessionType session_type_;
+ uint16_t cookie_;
+ mutable std::mutex cv_mutex_;
+ std::condition_variable internal_cv_;
+ // WR to support Mono: True if fetching Stereo and mixing into Mono
+ bool is_stereo_to_mono_ = false;
+
+ // Check and initialize session type for |devices| If failed, this
+ // BluetoothAudioPortOut is not initialized and must be deleted.
+ bool init_session_type(audio_devices_t device);
+
+ bool in_use() const;
+
+ bool CondwaitState(BluetoothStreamState state);
+
+ void ControlResultHandler(
+ const ::android::hardware::bluetooth::audio::V2_0::Status& status);
+ void SessionChangedHandler();
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace android
diff --git a/audio_bluetooth_hw/stream_apis.cc b/audio_bluetooth_hw/stream_apis.cc
new file mode 100644
index 0000000..74b6f2a
--- /dev/null
+++ b/audio_bluetooth_hw/stream_apis.cc
@@ -0,0 +1,691 @@
+/*
+ * Copyright 2019 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 "BTAudioHalStream"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <cutils/properties.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <log/log.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "stream_apis.h"
+#include "utils.h"
+
+using ::android::base::StringPrintf;
+using ::android::bluetooth::audio::BluetoothAudioPortOut;
+using ::android::bluetooth::audio::utils::GetAudioParamString;
+using ::android::bluetooth::audio::utils::ParseAudioParams;
+
+namespace {
+
+constexpr unsigned int kMinimumDelayMs = 100;
+constexpr unsigned int kMaximumDelayMs = 1000;
+constexpr int kExtraAudioSyncMs = 200;
+
+std::ostream& operator<<(std::ostream& os, const audio_config& config) {
+ return os << "audio_config[sample_rate=" << config.sample_rate
+ << ", channels=" << StringPrintf("%#x", config.channel_mask) << ", format=" << config.format << "]";
+}
+
+} // namespace
+
+std::ostream& operator<<(std::ostream& os, const BluetoothStreamState& state) {
+ switch (state) {
+ case BluetoothStreamState::DISABLED:
+ return os << "DISABLED";
+ case BluetoothStreamState::STANDBY:
+ return os << "STANDBY";
+ case BluetoothStreamState::STARTING:
+ return os << "STARTING";
+ case BluetoothStreamState::STARTED:
+ return os << "STARTED";
+ case BluetoothStreamState::SUSPENDING:
+ return os << "SUSPENDING";
+ case BluetoothStreamState::UNKNOWN:
+ return os << "UNKNOWN";
+ default:
+ return os << StringPrintf("%#hhx", state);
+ }
+}
+
+static uint32_t out_get_sample_rate(const struct audio_stream* stream) {
+ const auto* out = reinterpret_cast<const BluetoothStreamOut*>(stream);
+ audio_config_t audio_cfg;
+ if (out->bluetooth_output_.LoadAudioConfig(&audio_cfg)) {
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << " audio_cfg=" << audio_cfg;
+ return audio_cfg.sample_rate;
+ } else {
+ LOG(WARNING) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << ", sample_rate=" << out->sample_rate_ << " failed";
+ return out->sample_rate_;
+ }
+}
+
+static int out_set_sample_rate(struct audio_stream* stream, uint32_t rate) {
+ auto* out = reinterpret_cast<BluetoothStreamOut*>(stream);
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << ", sample_rate=" << out->sample_rate_;
+ return (rate == out->sample_rate_ ? 0 : -1);
+}
+
+static size_t out_get_buffer_size(const struct audio_stream* stream) {
+ const auto* out = reinterpret_cast<const BluetoothStreamOut*>(stream);
+ size_t buffer_size =
+ out->frames_count_ * audio_stream_out_frame_size(&out->stream_out_);
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << ", buffer_size=" << buffer_size;
+ return buffer_size;
+}
+
+static audio_channel_mask_t out_get_channels(
+ const struct audio_stream* stream) {
+ const auto* out = reinterpret_cast<const BluetoothStreamOut*>(stream);
+ audio_config_t audio_cfg;
+ if (out->bluetooth_output_.LoadAudioConfig(&audio_cfg)) {
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << " audio_cfg=" << audio_cfg;
+ return audio_cfg.channel_mask;
+ } else {
+ LOG(WARNING) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << ", channels=" << StringPrintf("%#x", out->channel_mask_) << " failure";
+ return out->channel_mask_;
+ }
+}
+
+static audio_format_t out_get_format(const struct audio_stream* stream) {
+ const auto* out = reinterpret_cast<const BluetoothStreamOut*>(stream);
+ audio_config_t audio_cfg;
+ if (out->bluetooth_output_.LoadAudioConfig(&audio_cfg)) {
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << " audio_cfg=" << audio_cfg;
+ return audio_cfg.format;
+ } else {
+ LOG(WARNING) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << ", format=" << out->format_ << " failure";
+ return out->format_;
+ }
+}
+
+static int out_set_format(struct audio_stream* stream, audio_format_t format) {
+ auto* out = reinterpret_cast<BluetoothStreamOut*>(stream);
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << ", format=" << out->format_;
+ return (format == out->format_ ? 0 : -1);
+}
+
+static int out_standby(struct audio_stream* stream) {
+ auto* out = reinterpret_cast<BluetoothStreamOut*>(stream);
+ std::unique_lock<std::mutex> lock(out->mutex_);
+ int retval = 0;
+
+ // out->last_write_time_us_ = 0; unnecessary as a stale write time has same
+ // effect
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << " being standby (suspend)";
+ if (out->bluetooth_output_.GetState() == BluetoothStreamState::STARTED) {
+ out->frames_rendered_ = 0;
+ retval = (out->bluetooth_output_.Suspend() ? 0 : -EIO);
+ } else if (out->bluetooth_output_.GetState() ==
+ BluetoothStreamState::STARTING ||
+ out->bluetooth_output_.GetState() ==
+ BluetoothStreamState::SUSPENDING) {
+ LOG(WARNING) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << " NOT ready to be standby";
+ retval = -EBUSY;
+ } else {
+ LOG(DEBUG) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << " standby already";
+ }
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << " standby (suspend) retval=" << retval;
+
+ return retval;
+}
+
+static int out_dump(const struct audio_stream* stream, int fd) {
+ const auto* out = reinterpret_cast<const BluetoothStreamOut*>(stream);
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState();
+ return 0;
+}
+
+static int out_set_parameters(struct audio_stream* stream,
+ const char* kvpairs) {
+ auto* out = reinterpret_cast<BluetoothStreamOut*>(stream);
+ std::unique_lock<std::mutex> lock(out->mutex_);
+ int retval = 0;
+
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << ", kvpairs=[" << kvpairs << "]";
+
+ std::unordered_map<std::string, std::string> params =
+ ParseAudioParams(kvpairs);
+ if (params.empty()) return retval;
+
+ LOG(VERBOSE) << __func__ << ": ParamsMap=[" << GetAudioParamString(params)
+ << "]";
+
+ audio_config_t audio_cfg;
+ if (params.find(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES) != params.end() ||
+ params.find(AUDIO_PARAMETER_STREAM_SUP_CHANNELS) != params.end() ||
+ params.find(AUDIO_PARAMETER_STREAM_SUP_FORMATS) != params.end()) {
+ if (out->bluetooth_output_.LoadAudioConfig(&audio_cfg)) {
+ out->sample_rate_ = audio_cfg.sample_rate;
+ out->channel_mask_ = audio_cfg.channel_mask;
+ out->format_ = audio_cfg.format;
+ LOG(VERBOSE) << "state=" << out->bluetooth_output_.GetState() << ", sample_rate=" << out->sample_rate_
+ << ", channels=" << StringPrintf("%#x", out->channel_mask_) << ", format=" << out->format_;
+ } else {
+ LOG(WARNING) << __func__
+ << ": state=" << out->bluetooth_output_.GetState()
+ << " failed to get audio config";
+ }
+ }
+
+ if (params.find("routing") != params.end()) {
+ auto routing_param = params.find("routing");
+ LOG(INFO) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << ", stream param '" << routing_param->first.c_str() << "="
+ << routing_param->second.c_str() << "'";
+ }
+
+ if (params.find("A2dpSuspended") != params.end()) {
+ if (params["A2dpSuspended"] == "true") {
+ LOG(INFO) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << " stream param stopped";
+ if (out->bluetooth_output_.GetState() != BluetoothStreamState::DISABLED) {
+ out->frames_rendered_ = 0;
+ out->bluetooth_output_.Stop();
+ }
+ } else {
+ LOG(INFO) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << " stream param standby";
+ if (out->bluetooth_output_.GetState() == BluetoothStreamState::DISABLED) {
+ out->bluetooth_output_.SetState(BluetoothStreamState::STANDBY);
+ }
+ }
+ }
+
+ if (params.find("closing") != params.end()) {
+ if (params["closing"] == "true") {
+ LOG(INFO) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << " stream param closing, disallow any writes?";
+ if (out->bluetooth_output_.GetState() != BluetoothStreamState::DISABLED) {
+ out->frames_rendered_ = 0;
+ out->frames_presented_ = 0;
+ out->bluetooth_output_.Stop();
+ }
+ }
+ }
+
+ if (params.find("exiting") != params.end()) {
+ if (params["exiting"] == "1") {
+ LOG(INFO) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << " stream param exiting";
+ if (out->bluetooth_output_.GetState() != BluetoothStreamState::DISABLED) {
+ out->frames_rendered_ = 0;
+ out->frames_presented_ = 0;
+ out->bluetooth_output_.Stop();
+ }
+ }
+ }
+
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << ", kvpairs=[" << kvpairs << "], retval=" << retval;
+ return retval;
+}
+
+static char* out_get_parameters(const struct audio_stream* stream,
+ const char* keys) {
+ const auto* out = reinterpret_cast<const BluetoothStreamOut*>(stream);
+ std::unique_lock<std::mutex> lock(out->mutex_);
+
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << ", keys=[" << keys << "]";
+
+ std::unordered_map<std::string, std::string> params = ParseAudioParams(keys);
+ if (params.empty()) return strdup("");
+
+ audio_config_t audio_cfg;
+ if (out->bluetooth_output_.LoadAudioConfig(&audio_cfg)) {
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << " audio_cfg=" << audio_cfg;
+ } else {
+ LOG(ERROR) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << " failed to get audio config";
+ }
+
+ std::unordered_map<std::string, std::string> return_params;
+ if (params.find(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES) != params.end()) {
+ std::string param;
+ if (audio_cfg.sample_rate == 16000) {
+ param = "16000";
+ }
+ if (audio_cfg.sample_rate == 24000) {
+ param = "24000";
+ }
+ if (audio_cfg.sample_rate == 44100) {
+ param = "44100";
+ }
+ if (audio_cfg.sample_rate == 48000) {
+ param = "48000";
+ }
+ if (audio_cfg.sample_rate == 88200) {
+ param = "88200";
+ }
+ if (audio_cfg.sample_rate == 96000) {
+ param = "96000";
+ }
+ if (audio_cfg.sample_rate == 176400) {
+ param = "176400";
+ }
+ if (audio_cfg.sample_rate == 192000) {
+ param = "192000";
+ }
+ return_params[AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES] = param;
+ }
+
+ if (params.find(AUDIO_PARAMETER_STREAM_SUP_CHANNELS) != params.end()) {
+ std::string param;
+ if (audio_cfg.channel_mask == AUDIO_CHANNEL_OUT_MONO) {
+ param = "AUDIO_CHANNEL_OUT_MONO";
+ }
+ if (audio_cfg.channel_mask == AUDIO_CHANNEL_OUT_STEREO) {
+ param = "AUDIO_CHANNEL_OUT_STEREO";
+ }
+ return_params[AUDIO_PARAMETER_STREAM_SUP_CHANNELS] = param;
+ }
+
+ if (params.find(AUDIO_PARAMETER_STREAM_SUP_FORMATS) != params.end()) {
+ std::string param;
+ if (audio_cfg.format == AUDIO_FORMAT_PCM_16_BIT) {
+ param = "AUDIO_FORMAT_PCM_16_BIT";
+ }
+ if (audio_cfg.format == AUDIO_FORMAT_PCM_24_BIT_PACKED) {
+ param = "AUDIO_FORMAT_PCM_24_BIT_PACKED";
+ }
+ if (audio_cfg.format == AUDIO_FORMAT_PCM_32_BIT) {
+ param = "AUDIO_FORMAT_PCM_32_BIT";
+ }
+ return_params[AUDIO_PARAMETER_STREAM_SUP_FORMATS] = param;
+ }
+
+ std::string result;
+ for (const auto& ptr : return_params) {
+ result += ptr.first + "=" + ptr.second + ";";
+ }
+
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << ", result=[" << result << "]";
+ return strdup(result.c_str());
+}
+
+static uint32_t out_get_latency_ms(const struct audio_stream_out* stream) {
+ const auto* out = reinterpret_cast<const BluetoothStreamOut*>(stream);
+ std::unique_lock<std::mutex> lock(out->mutex_);
+ /***
+ * audio_a2dp_hw:
+ * frames_count = buffer_size / frame_size
+ * latency (sec.) = frames_count / sample_rate
+ */
+ uint32_t latency_ms = out->frames_count_ * 1000 / out->sample_rate_;
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << ", latency_ms=" << latency_ms;
+ // Sync from audio_a2dp_hw to add extra +200ms
+ return latency_ms + kExtraAudioSyncMs;
+}
+
+static int out_set_volume(struct audio_stream_out* stream, float left,
+ float right) {
+ auto* out = reinterpret_cast<BluetoothStreamOut*>(stream);
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << ", Left=" << left << ", Right=" << right;
+ return -1;
+}
+
+static ssize_t out_write(struct audio_stream_out* stream, const void* buffer,
+ size_t bytes) {
+ auto* out = reinterpret_cast<BluetoothStreamOut*>(stream);
+ std::unique_lock<std::mutex> lock(out->mutex_);
+ size_t totalWritten = 0;
+
+ if (out->bluetooth_output_.GetState() != BluetoothStreamState::STARTED) {
+ LOG(INFO) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << " first time bytes=" << bytes;
+ lock.unlock();
+ if (stream->resume(stream)) {
+ LOG(ERROR) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << " failed to resume";
+ usleep(kBluetoothDefaultOutputBufferMs * 1000);
+ return totalWritten;
+ }
+ lock.lock();
+ }
+ lock.unlock();
+ totalWritten = out->bluetooth_output_.WriteData(buffer, bytes);
+ lock.lock();
+
+ struct timespec ts = {.tv_sec = 0, .tv_nsec = 0};
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ if (totalWritten) {
+ const size_t frames = bytes / audio_stream_out_frame_size(stream);
+ out->frames_rendered_ += frames;
+ out->frames_presented_ += frames;
+ out->last_write_time_us_ = (ts.tv_sec * 1000000000LL + ts.tv_nsec) / 1000;
+ } else {
+ const int64_t now = (ts.tv_sec * 1000000000LL + ts.tv_nsec) / 1000;
+ const int64_t elapsed_time_since_last_write =
+ now - out->last_write_time_us_;
+ // frames_count = written_data / frame_size
+ // play_time (ms) = frames_count / (sample_rate (Sec.) / 1000000)
+ // sleep_time (ms) = play_time - elapsed_time
+ int64_t sleep_time = bytes * 1000000LL /
+ audio_stream_out_frame_size(stream) /
+ out_get_sample_rate(&stream->common) -
+ elapsed_time_since_last_write;
+ if (sleep_time > 0) {
+ LOG(VERBOSE) << __func__ << ": sleep " << (sleep_time / 1000)
+ << " ms when writting FMQ datapath";
+ lock.unlock();
+ usleep(sleep_time);
+ lock.lock();
+ } else {
+ // we don't sleep when we exit standby (this is typical for a real alsa
+ // buffer).
+ sleep_time = 0;
+ }
+ out->last_write_time_us_ = now + sleep_time;
+ }
+ return totalWritten;
+}
+
+static int out_get_render_position(const struct audio_stream_out* stream,
+ uint32_t* dsp_frames) {
+ const auto* out = reinterpret_cast<const BluetoothStreamOut*>(stream);
+ std::unique_lock<std::mutex> lock(out->mutex_);
+
+ if (dsp_frames == nullptr) return -EINVAL;
+
+ /* frames = (latency (ms) / 1000) * sample_per_seconds */
+ uint64_t latency_frames =
+ (uint64_t)out_get_latency_ms(stream) * out->sample_rate_ / 1000;
+ if (out->frames_rendered_ >= latency_frames) {
+ *dsp_frames = (uint32_t)(out->frames_rendered_ - latency_frames);
+ } else {
+ *dsp_frames = 0;
+ }
+
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << ", dsp_frames=" << *dsp_frames;
+ return 0;
+}
+
+static int out_add_audio_effect(const struct audio_stream* stream,
+ effect_handle_t effect) {
+ const auto* out = reinterpret_cast<const BluetoothStreamOut*>(stream);
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << ", effect=" << effect;
+ return 0;
+}
+
+static int out_remove_audio_effect(const struct audio_stream* stream,
+ effect_handle_t effect) {
+ const auto* out = reinterpret_cast<const BluetoothStreamOut*>(stream);
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << ", effect=" << effect;
+ return 0;
+}
+
+static int out_get_next_write_timestamp(const struct audio_stream_out* stream,
+ int64_t* timestamp) {
+ const auto* out = reinterpret_cast<const BluetoothStreamOut*>(stream);
+ *timestamp = 0;
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << ", timestamp=" << *timestamp;
+ return -EINVAL;
+}
+
+static int out_pause(struct audio_stream_out* stream) {
+ auto* out = reinterpret_cast<BluetoothStreamOut*>(stream);
+ std::unique_lock<std::mutex> lock(out->mutex_);
+ int retval = 0;
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << ", pausing (suspend)";
+ if (out->bluetooth_output_.GetState() == BluetoothStreamState::STARTED) {
+ out->frames_rendered_ = 0;
+ retval = (out->bluetooth_output_.Suspend() ? 0 : -EIO);
+ } else if (out->bluetooth_output_.GetState() ==
+ BluetoothStreamState::STARTING ||
+ out->bluetooth_output_.GetState() ==
+ BluetoothStreamState::SUSPENDING) {
+ LOG(WARNING) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << " NOT ready to pause?!";
+ retval = -EBUSY;
+ } else {
+ LOG(DEBUG) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << " paused already";
+ }
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << ", pausing (suspend) retval=" << retval;
+
+ return retval;
+}
+
+static int out_resume(struct audio_stream_out* stream) {
+ auto* out = reinterpret_cast<BluetoothStreamOut*>(stream);
+ std::unique_lock<std::mutex> lock(out->mutex_);
+ int retval = 0;
+
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << ", resuming (start)";
+ if (out->bluetooth_output_.GetState() == BluetoothStreamState::STANDBY) {
+ retval = (out->bluetooth_output_.Start() ? 0 : -EIO);
+ } else if (out->bluetooth_output_.GetState() ==
+ BluetoothStreamState::STARTING ||
+ out->bluetooth_output_.GetState() ==
+ BluetoothStreamState::SUSPENDING) {
+ LOG(WARNING) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << " NOT ready to resume?!";
+ retval = -EBUSY;
+ } else if (out->bluetooth_output_.GetState() ==
+ BluetoothStreamState::DISABLED) {
+ LOG(WARNING) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << " NOT allow to resume?!";
+ retval = -EINVAL;
+ } else {
+ LOG(DEBUG) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << " resumed already";
+ }
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << ", resuming (start) retval=" << retval;
+
+ return retval;
+}
+
+static int out_get_presentation_position(const struct audio_stream_out* stream,
+ uint64_t* frames,
+ struct timespec* timestamp) {
+ if (frames == nullptr || timestamp == nullptr) {
+ return -EINVAL;
+ }
+
+ // bytes is the total number of bytes sent by the Bluetooth stack to a
+ // remote headset
+ uint64_t bytes = 0;
+ // delay_report is the audio delay from the remote headset receiving data to
+ // the headset playing sound in units of nanoseconds
+ uint64_t delay_report_ns = 0;
+ const auto* out = reinterpret_cast<const BluetoothStreamOut*>(stream);
+ std::unique_lock<std::mutex> lock(out->mutex_);
+
+ if (out->bluetooth_output_.GetPresentationPosition(&delay_report_ns, &bytes,
+ timestamp)) {
+ // assume kMinimumDelayMs (100ms) < delay_report_ns < kMaximumDelayMs
+ // (1000ms), or it is invalid / ignored and use old delay calculated
+ // by ourselves.
+ if (delay_report_ns > kMinimumDelayMs * 1000000 &&
+ delay_report_ns < kMaximumDelayMs * 1000000) {
+ *frames = bytes / audio_stream_out_frame_size(stream);
+ timestamp->tv_nsec += delay_report_ns;
+ if (timestamp->tv_nsec > 1000000000) {
+ timestamp->tv_sec += static_cast<int>(timestamp->tv_nsec / 1000000000);
+ timestamp->tv_nsec %= 1000000000;
+ }
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState() << ", frames=" << *frames << " ("
+ << bytes << " bytes), timestamp=" << timestamp->tv_sec << "."
+ << StringPrintf("%09ld", timestamp->tv_nsec) << "s";
+ return 0;
+ } else if (delay_report_ns >= kMaximumDelayMs * 1000000) {
+ LOG(WARNING) << __func__
+ << ": state=" << out->bluetooth_output_.GetState()
+ << ", delay_report=" << delay_report_ns << "ns abnormal";
+ }
+ }
+
+ // default to old delay if any failure is found when fetching from ports
+ if (out->frames_presented_ >= out->frames_count_) {
+ clock_gettime(CLOCK_MONOTONIC, timestamp);
+ *frames = out->frames_presented_ - out->frames_count_;
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState() << ", frames=" << *frames << " ("
+ << bytes << " bytes), timestamp=" << timestamp->tv_sec << "."
+ << StringPrintf("%09ld", timestamp->tv_nsec) << "s";
+ return 0;
+ }
+
+ *frames = 0;
+ *timestamp = {};
+ return -EWOULDBLOCK;
+}
+
+static void out_update_source_metadata(
+ struct audio_stream_out* stream,
+ const struct source_metadata* source_metadata) {
+ auto* out = reinterpret_cast<BluetoothStreamOut*>(stream);
+ std::unique_lock<std::mutex> lock(out->mutex_);
+ if (source_metadata == nullptr || source_metadata->track_count == 0) {
+ return;
+ }
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << ", " << source_metadata->track_count << " track(s)";
+ out->bluetooth_output_.UpdateMetadata(source_metadata);
+}
+
+static size_t samples_per_ticks(size_t milliseconds, uint32_t sample_rate,
+ size_t channel_count) {
+ return milliseconds * sample_rate * channel_count / 1000;
+}
+
+int adev_open_output_stream(struct audio_hw_device* dev,
+ audio_io_handle_t handle, audio_devices_t devices,
+ audio_output_flags_t flags,
+ struct audio_config* config,
+ struct audio_stream_out** stream_out,
+ const char* address __unused) {
+ *stream_out = nullptr;
+ auto* out = new BluetoothStreamOut;
+ if (!out->bluetooth_output_.SetUp(devices)) {
+ delete out;
+ return -EINVAL;
+ }
+ LOG(VERBOSE) << __func__ << ": device=" << StringPrintf("%#x", devices);
+
+ out->stream_out_.common.get_sample_rate = out_get_sample_rate;
+ out->stream_out_.common.set_sample_rate = out_set_sample_rate;
+ out->stream_out_.common.get_buffer_size = out_get_buffer_size;
+ out->stream_out_.common.get_channels = out_get_channels;
+ out->stream_out_.common.get_format = out_get_format;
+ out->stream_out_.common.set_format = out_set_format;
+ out->stream_out_.common.standby = out_standby;
+ out->stream_out_.common.dump = out_dump;
+ out->stream_out_.common.set_parameters = out_set_parameters;
+ out->stream_out_.common.get_parameters = out_get_parameters;
+ out->stream_out_.common.add_audio_effect = out_add_audio_effect;
+ out->stream_out_.common.remove_audio_effect = out_remove_audio_effect;
+ out->stream_out_.get_latency = out_get_latency_ms;
+ out->stream_out_.set_volume = out_set_volume;
+ out->stream_out_.write = out_write;
+ out->stream_out_.get_render_position = out_get_render_position;
+ out->stream_out_.get_next_write_timestamp = out_get_next_write_timestamp;
+ out->stream_out_.pause = out_pause;
+ out->stream_out_.resume = out_resume;
+ out->stream_out_.get_presentation_position = out_get_presentation_position;
+ out->stream_out_.update_source_metadata = out_update_source_metadata;
+
+ if (!out->bluetooth_output_.LoadAudioConfig(config)) {
+ LOG(ERROR) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << " failed to get audio config";
+ }
+ // WAR to support Mono / 16 bits per sample as the Bluetooth stack required
+ if (config->channel_mask == AUDIO_CHANNEL_OUT_MONO && config->format == AUDIO_FORMAT_PCM_16_BIT) {
+ LOG(INFO) << __func__ << ": force channels=" << StringPrintf("%#x", out->channel_mask_)
+ << " to be AUDIO_CHANNEL_OUT_STEREO";
+ out->bluetooth_output_.ForcePcmStereoToMono(true);
+ config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+ }
+ out->sample_rate_ = config->sample_rate;
+ out->channel_mask_ = config->channel_mask;
+ out->format_ = config->format;
+ // frame is number of samples per channel
+ out->frames_count_ =
+ samples_per_ticks(kBluetoothDefaultOutputBufferMs, out->sample_rate_, 1);
+ out->frames_rendered_ = 0;
+ out->frames_presented_ = 0;
+
+ *stream_out = &out->stream_out_;
+ LOG(INFO) << __func__ << ": state=" << out->bluetooth_output_.GetState() << ", sample_rate=" << out->sample_rate_
+ << ", channels=" << StringPrintf("%#x", out->channel_mask_) << ", format=" << out->format_
+ << ", frames=" << out->frames_count_;
+ return 0;
+}
+
+void adev_close_output_stream(struct audio_hw_device* dev,
+ struct audio_stream_out* stream) {
+ auto* out = reinterpret_cast<BluetoothStreamOut*>(stream);
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << ", stopping";
+ if (out->bluetooth_output_.GetState() != BluetoothStreamState::DISABLED) {
+ out->frames_rendered_ = 0;
+ out->frames_presented_ = 0;
+ out->bluetooth_output_.Stop();
+ }
+ out->bluetooth_output_.TearDown();
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << ", stopped";
+ delete out;
+}
+
+size_t adev_get_input_buffer_size(const struct audio_hw_device* dev,
+ const struct audio_config* config) {
+ return 320;
+}
+
+int adev_open_input_stream(struct audio_hw_device* dev,
+ audio_io_handle_t handle, audio_devices_t devices,
+ struct audio_config* config,
+ struct audio_stream_in** stream_in,
+ audio_input_flags_t flags __unused,
+ const char* address __unused,
+ audio_source_t source __unused) {
+ return -EINVAL;
+}
+
+void adev_close_input_stream(struct audio_hw_device* dev,
+ struct audio_stream_in* stream_in) {}
diff --git a/audio_bluetooth_hw/stream_apis.h b/audio_bluetooth_hw/stream_apis.h
new file mode 100644
index 0000000..14a955c
--- /dev/null
+++ b/audio_bluetooth_hw/stream_apis.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2019 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 <hardware/audio.h>
+#include <system/audio.h>
+
+#include "device_port_proxy.h"
+
+constexpr unsigned int kBluetoothDefaultSampleRate = 44100;
+constexpr audio_format_t kBluetoothDefaultAudioFormatBitsPerSample =
+ AUDIO_FORMAT_PCM_16_BIT;
+
+constexpr unsigned int kBluetoothDefaultInputBufferMs = 20;
+
+constexpr unsigned int kBluetoothDefaultOutputBufferMs = 10;
+constexpr audio_channel_mask_t kBluetoothDefaultOutputChannelModeMask =
+ AUDIO_CHANNEL_OUT_STEREO;
+
+enum class BluetoothStreamState : uint8_t {
+ DISABLED = 0, // This stream is closing or set param "suspend=true"
+ STANDBY,
+ STARTING,
+ STARTED,
+ SUSPENDING,
+ UNKNOWN,
+};
+
+std::ostream& operator<<(std::ostream& os, const BluetoothStreamState& state);
+
+struct BluetoothStreamOut {
+ // Must be the first member so it can be cast from audio_stream
+ // or audio_stream_out pointer
+ audio_stream_out stream_out_;
+ ::android::bluetooth::audio::BluetoothAudioPortOut bluetooth_output_;
+ int64_t last_write_time_us_;
+ // Audio PCM Configs
+ uint32_t sample_rate_;
+ audio_channel_mask_t channel_mask_;
+ audio_format_t format_;
+ // frame is the number of samples per channel
+ // frames count per tick
+ size_t frames_count_;
+ // total frames written, reset on standby
+ uint64_t frames_rendered_;
+ // total frames written after opened, never reset
+ uint64_t frames_presented_;
+ mutable std::mutex mutex_;
+};
+
+int adev_open_output_stream(struct audio_hw_device* dev,
+ audio_io_handle_t handle, audio_devices_t devices,
+ audio_output_flags_t flags,
+ struct audio_config* config,
+ struct audio_stream_out** stream_out,
+ const char* address __unused);
+
+void adev_close_output_stream(struct audio_hw_device* dev,
+ struct audio_stream_out* stream);
+
+size_t adev_get_input_buffer_size(const struct audio_hw_device* dev,
+ const struct audio_config* config);
+
+int adev_open_input_stream(struct audio_hw_device* dev,
+ audio_io_handle_t handle, audio_devices_t devices,
+ struct audio_config* config,
+ struct audio_stream_in** stream_in,
+ audio_input_flags_t flags __unused,
+ const char* address __unused,
+ audio_source_t source __unused);
+
+void adev_close_input_stream(struct audio_hw_device* dev,
+ struct audio_stream_in* in);
diff --git a/audio_bluetooth_hw/utils.cc b/audio_bluetooth_hw/utils.cc
new file mode 100644
index 0000000..b3ac7a5
--- /dev/null
+++ b/audio_bluetooth_hw/utils.cc
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2019 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 "BTAudioHalUtils"
+
+#include "utils.h"
+
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <log/log.h>
+#include <stdlib.h>
+#include <sstream>
+#include <vector>
+
+namespace android {
+namespace bluetooth {
+namespace audio {
+namespace utils {
+
+std::unordered_map<std::string, std::string> ParseAudioParams(
+ const std::string& params) {
+ std::vector<std::string> segments = android::base::Split(params, ";");
+ std::unordered_map<std::string, std::string> params_map;
+ for (const auto& segment : segments) {
+ if (segment.length() == 0) {
+ continue;
+ }
+ std::vector<std::string> kv = android::base::Split(segment, "=");
+ if (kv[0].empty()) {
+ LOG(WARNING) << __func__ << ": Invalid audio parameter " << segment;
+ continue;
+ }
+ params_map[kv[0]] = (kv.size() > 1 ? kv[1] : "");
+ }
+ return params_map;
+}
+
+std::string GetAudioParamString(
+ std::unordered_map<std::string, std::string>& params_map) {
+ std::ostringstream sout;
+ for (const auto& ptr : params_map) {
+ sout << "key: '" << ptr.first << "' value: '" << ptr.second << "'\n";
+ }
+ return sout.str();
+}
+
+} // namespace utils
+} // namespace audio
+} // namespace bluetooth
+} // namespace android
diff --git a/audio_bluetooth_hw/utils.h b/audio_bluetooth_hw/utils.h
new file mode 100644
index 0000000..817a432
--- /dev/null
+++ b/audio_bluetooth_hw/utils.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2019 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 <unordered_map>
+
+namespace android {
+namespace bluetooth {
+namespace audio {
+namespace utils {
+
+// 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.
+// Examples:
+// "key0" -> map: [key0]=""
+// "key0=value0;key1=value1;" -> map: [key0]="value0" [key1]="value1"
+// "key0=;key1=value1;" -> map: [key0]="" [key1]="value1"
+// "=value0;key1=value1;" -> map: [key1]="value1"
+std::unordered_map<std::string, std::string> ParseAudioParams(
+ const std::string& 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 the |map|.
+std::string GetAudioParamString(
+ std::unordered_map<std::string, std::string>& params_map);
+
+} // namespace utils
+} // namespace audio
+} // namespace bluetooth
+} // namespace android
diff --git a/audio_bluetooth_hw/utils_unittest.cc b/audio_bluetooth_hw/utils_unittest.cc
new file mode 100644
index 0000000..665dea6
--- /dev/null
+++ b/audio_bluetooth_hw/utils_unittest.cc
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2019 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 <gtest/gtest.h>
+#include <unordered_map>
+
+#include "utils.h"
+
+namespace {
+
+using ::android::bluetooth::audio::utils::ParseAudioParams;
+
+class UtilsTest : public testing::Test {
+ protected:
+ void SetUp() override {}
+ void TearDown() override { map_.clear(); }
+
+ std::unordered_map<std::string, std::string> map_;
+};
+
+TEST_F(UtilsTest, HashMapEmptyParams) {
+ std::string params = "";
+ map_ = ParseAudioParams(params);
+ // map = {}
+ EXPECT_TRUE(map_.empty());
+}
+
+TEST_F(UtilsTest, HashMapDelimitOnly) {
+ std::string params = ";";
+ map_ = ParseAudioParams(params);
+ // map = {}
+ EXPECT_TRUE(map_.empty());
+}
+
+TEST_F(UtilsTest, HashMapNotKeyValuePair) {
+ std::string params = "key0";
+ map_ = ParseAudioParams(params);
+ // map = {[key0]=""}
+ EXPECT_EQ(map_.size(), 1);
+ EXPECT_NE(map_.find("key0"), map_.end());
+ EXPECT_EQ(map_["key0"].length(), 0);
+}
+
+TEST_F(UtilsTest, HashMapEmptyValue) {
+ std::string params = "key0=";
+ map_ = ParseAudioParams(params);
+ // map = {[key0]=""}
+ EXPECT_EQ(map_.size(), 1);
+ EXPECT_NE(map_.find("key0"), map_.end());
+ EXPECT_EQ(map_["key0"].length(), 0);
+}
+
+TEST_F(UtilsTest, HashMapEmptyValueWithDelimit) {
+ std::string params = "key0=;";
+ map_ = ParseAudioParams(params);
+ // map = {[key0]=""}
+ EXPECT_EQ(map_.size(), 1);
+ EXPECT_NE(map_.find("key0"), map_.end());
+ EXPECT_EQ(map_["key0"].length(), 0);
+}
+
+TEST_F(UtilsTest, HashMapOneKeyValuePair) {
+ std::string params = "key0=value0";
+ map_ = ParseAudioParams(params);
+ // map = {[key0]="value0"}
+ EXPECT_EQ(map_.size(), 1);
+ EXPECT_EQ(map_["key0"], "value0");
+}
+
+TEST_F(UtilsTest, HashMapOneKeyValuePairWithDelimit) {
+ std::string params = "key0=value0;";
+ map_ = ParseAudioParams(params);
+ // map = {[key0]="value0"}
+ EXPECT_EQ(map_.size(), 1);
+ EXPECT_EQ(map_["key0"], "value0");
+}
+
+TEST_F(UtilsTest, HashMapTwoKeyValuePairs) {
+ std::string params = "key0=value0;key1=value1";
+ map_ = ParseAudioParams(params);
+ // map = {[key0]="value0", [key1]="value1"}
+ EXPECT_EQ(map_.size(), 2);
+ EXPECT_EQ(map_["key0"], "value0");
+ EXPECT_EQ(map_["key1"], "value1");
+}
+
+TEST_F(UtilsTest, HashMapEmptyKey) {
+ std::string params = "=value";
+ map_ = ParseAudioParams(params);
+ // map = {}
+ EXPECT_TRUE(map_.empty());
+}
+
+TEST_F(UtilsTest, HashMapEmptyKeyWithDelimit) {
+ std::string params = "=value;";
+ map_ = ParseAudioParams(params);
+ // map = {}
+ EXPECT_TRUE(map_.empty());
+}
+
+TEST_F(UtilsTest, HashMapEquivalentOnly) {
+ std::string params = "=";
+ map_ = ParseAudioParams(params);
+ // map = {}
+ EXPECT_TRUE(map_.empty());
+}
+
+TEST_F(UtilsTest, HashMapNoKeyValuePair) {
+ std::string params = "=;";
+ map_ = ParseAudioParams(params);
+ // map = {}
+ EXPECT_TRUE(map_.empty());
+}
+
+TEST_F(UtilsTest, HashMapTwoPairsWithFirstKeyEmpty) {
+ std::string params = "=value0;key1=value1";
+ map_ = ParseAudioParams(params);
+ // map = {[key1]="value1"}
+ EXPECT_EQ(map_.size(), 1);
+ EXPECT_EQ(map_["key1"], "value1");
+}
+
+} // namespace
diff --git a/audio_hal_interface/Android.bp b/audio_hal_interface/Android.bp
new file mode 100644
index 0000000..4b10435
--- /dev/null
+++ b/audio_hal_interface/Android.bp
@@ -0,0 +1,60 @@
+// Bluetooth Audio library for target
+// ========================================================
+cc_library_static {
+ name: "libbt-audio-hal-interface",
+ defaults: ["fluoride_defaults"],
+ include_dirs: [
+ "system/bt",
+ "system/bt/bta/include",
+ "system/bt/bta/sys",
+ "system/bt/btif/include",
+ "system/bt/stack/include",
+ ],
+ srcs: [
+ "a2dp_encoding.cc",
+ "client_interface.cc",
+ "hearing_aid_software_encoding.cc",
+ ],
+ shared_libs: [
+ "android.hardware.bluetooth.audio@2.0",
+ "libfmq",
+ "libhidlbase",
+ "libhidltransport",
+ ],
+ static_libs: [
+ "libosi",
+ "libbt-common",
+ ],
+ cflags: [
+ "-DBUILDCFG",
+ ],
+}
+
+// Bluetooth Audio client interface library unit tests for target and host
+// ========================================================
+cc_test {
+ name: "bluetooth-test-audio-hal-interface",
+ defaults: ["fluoride_defaults"],
+ include_dirs: [
+ "system/bt",
+ ],
+ srcs: [
+ "client_interface_unittest.cc",
+ ],
+ shared_libs: [
+ "android.hardware.bluetooth.audio@2.0",
+ "libcutils",
+ "libfmq",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libutils",
+ ],
+ static_libs: [
+ "libbt-audio-hal-interface",
+ "libbt-common",
+ ],
+ cflags: [
+ "-DBUILDCFG",
+ ],
+}
diff --git a/audio_hal_interface/a2dp_encoding.cc b/audio_hal_interface/a2dp_encoding.cc
new file mode 100644
index 0000000..fc61128
--- /dev/null
+++ b/audio_hal_interface/a2dp_encoding.cc
@@ -0,0 +1,743 @@
+/*
+ * Copyright 2019 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 "a2dp_encoding.h"
+#include "client_interface.h"
+
+#include "a2dp_aac_constants.h"
+#include "a2dp_sbc_constants.h"
+#include "a2dp_vendor_ldac_constants.h"
+#include "bta/av/bta_av_int.h"
+#include "btif_a2dp_source.h"
+#include "btif_av.h"
+#include "btif_av_co.h"
+#include "btif_hf.h"
+#include "osi/include/properties.h"
+
+namespace {
+
+using ::android::hardware::bluetooth::audio::V2_0::AacObjectType;
+using ::android::hardware::bluetooth::audio::V2_0::AacVariableBitRate;
+using ::android::hardware::bluetooth::audio::V2_0::CodecType;
+using ::android::hardware::bluetooth::audio::V2_0::LdacChannelMode;
+using ::android::hardware::bluetooth::audio::V2_0::LdacQualityIndex;
+using ::android::hardware::bluetooth::audio::V2_0::SbcAllocMethod;
+using ::android::hardware::bluetooth::audio::V2_0::SbcBlockLength;
+using ::android::hardware::bluetooth::audio::V2_0::SbcChannelMode;
+using ::android::hardware::bluetooth::audio::V2_0::SbcNumSubbands;
+using ::bluetooth::audio::AudioConfiguration;
+using ::bluetooth::audio::BitsPerSample;
+using ::bluetooth::audio::BluetoothAudioCtrlAck;
+using ::bluetooth::audio::ChannelMode;
+using ::bluetooth::audio::CodecConfiguration;
+using ::bluetooth::audio::PcmParameters;
+using ::bluetooth::audio::SampleRate;
+using ::bluetooth::audio::SessionType;
+
+const CodecConfiguration kInvalidCodecConfiguration = {
+ .codecType = CodecType::UNKNOWN,
+ .encodedAudioBitrate = 0x00000000,
+ .peerMtu = 0xffff,
+ .isScmstEnabled = false,
+ .config = {}};
+
+BluetoothAudioCtrlAck a2dp_ack_to_bt_audio_ctrl_ack(tA2DP_CTRL_ACK ack);
+
+// Provide call-in APIs for the Bluetooth Audio HAL
+class A2dpTransport : public ::bluetooth::audio::IBluetoothTransportInstance {
+ public:
+ A2dpTransport(SessionType sessionType)
+ : IBluetoothTransportInstance(sessionType, {}),
+ a2dp_pending_cmd_(A2DP_CTRL_CMD_NONE),
+ remote_delay_report_(0),
+ total_bytes_read_(0),
+ data_position_({}){};
+
+ BluetoothAudioCtrlAck StartRequest() override {
+ // Check if a previous request is not finished
+ if (a2dp_pending_cmd_ == A2DP_CTRL_CMD_START) {
+ LOG(INFO) << __func__ << ": A2DP_CTRL_CMD_START in progress";
+ return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_PENDING);
+ } else if (a2dp_pending_cmd_ != A2DP_CTRL_CMD_NONE) {
+ LOG(WARNING) << __func__ << ": busy in pending_cmd=" << a2dp_pending_cmd_;
+ return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_FAILURE);
+ }
+
+ // Don't send START request to stack while we are in a call
+ if (!bluetooth::headset::IsCallIdle()) {
+ LOG(ERROR) << __func__ << ": call state is busy";
+ return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_INCALL_FAILURE);
+ }
+
+ if (btif_a2dp_source_is_streaming()) {
+ LOG(ERROR) << __func__ << ": source is busy streaming";
+ return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_FAILURE);
+ }
+
+ if (btif_av_stream_ready()) {
+ /*
+ * Post start event and wait for audio path to open.
+ * If we are the source, the ACK will be sent after the start
+ * procedure is completed, othewise send it now.
+ */
+ a2dp_pending_cmd_ = A2DP_CTRL_CMD_START;
+ btif_av_stream_start();
+ if (btif_av_get_peer_sep() != AVDT_TSEP_SRC) {
+ LOG(INFO) << __func__ << ": accepted";
+ return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_PENDING);
+ }
+ a2dp_pending_cmd_ = A2DP_CTRL_CMD_NONE;
+ return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_SUCCESS);
+ }
+
+ if (btif_av_stream_started_ready()) {
+ // Already started, ACK back immediately.
+ return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_SUCCESS);
+ }
+ LOG(ERROR) << __func__ << ": AV stream is not ready to start";
+ return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_FAILURE);
+ }
+
+ BluetoothAudioCtrlAck SuspendRequest() override {
+ // Previous request is not finished
+ if (a2dp_pending_cmd_ == A2DP_CTRL_CMD_SUSPEND) {
+ LOG(INFO) << __func__ << ": A2DP_CTRL_CMD_SUSPEND in progress";
+ return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_PENDING);
+ } else if (a2dp_pending_cmd_ != A2DP_CTRL_CMD_NONE) {
+ LOG(WARNING) << __func__ << ": busy in pending_cmd=" << a2dp_pending_cmd_;
+ return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_FAILURE);
+ }
+ // Local suspend
+ if (btif_av_stream_started_ready()) {
+ LOG(INFO) << __func__ << ": accepted";
+ a2dp_pending_cmd_ = A2DP_CTRL_CMD_SUSPEND;
+ btif_av_stream_suspend();
+ return BluetoothAudioCtrlAck::PENDING;
+ }
+ /* If we are not in started state, just ack back ok and let
+ * audioflinger close the channel. This can happen if we are
+ * remotely suspended, clear REMOTE SUSPEND flag.
+ */
+ btif_av_clear_remote_suspend_flag();
+ return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_SUCCESS);
+ }
+
+ void StopRequest() override {
+ if (btif_av_get_peer_sep() == AVDT_TSEP_SNK &&
+ !btif_a2dp_source_is_streaming()) {
+ return;
+ }
+ LOG(INFO) << __func__ << ": handling";
+ a2dp_pending_cmd_ = A2DP_CTRL_CMD_STOP;
+ btif_av_stream_stop(RawAddress::kEmpty);
+ }
+
+ bool GetPresentationPosition(uint64_t* remote_delay_report_ns,
+ uint64_t* total_bytes_read,
+ timespec* data_position) override {
+ *remote_delay_report_ns = remote_delay_report_ * 100000u;
+ *total_bytes_read = total_bytes_read_;
+ *data_position = data_position_;
+ VLOG(2) << __func__ << ": delay=" << remote_delay_report_
+ << "/10ms, data=" << total_bytes_read_
+ << " byte(s), timestamp=" << data_position_.tv_sec << "."
+ << data_position_.tv_nsec << "s";
+ return true;
+ }
+
+ void MetadataChanged(const source_metadata_t& source_metadata) override {
+ auto track_count = source_metadata.track_count;
+ auto tracks = source_metadata.tracks;
+ VLOG(1) << __func__ << ": " << track_count << " track(s) received";
+ while (track_count) {
+ VLOG(2) << __func__ << ": usage=" << tracks->usage
+ << ", content_type=" << tracks->content_type
+ << ", gain=" << tracks->gain;
+ --track_count;
+ ++tracks;
+ }
+ }
+
+ tA2DP_CTRL_CMD GetPendingCmd() const { return a2dp_pending_cmd_; }
+
+ void ResetPendingCmd() { a2dp_pending_cmd_ = A2DP_CTRL_CMD_NONE; }
+
+ void ResetPresentationPosition() override {
+ remote_delay_report_ = 0;
+ total_bytes_read_ = 0;
+ data_position_ = {};
+ }
+
+ void LogBytesRead(size_t bytes_read) override {
+ if (bytes_read != 0) {
+ total_bytes_read_ += bytes_read;
+ clock_gettime(CLOCK_MONOTONIC, &data_position_);
+ }
+ }
+
+ // delay reports from AVDTP is based on 1/10 ms (100us)
+ void SetRemoteDelay(uint16_t delay_report) {
+ remote_delay_report_ = delay_report;
+ }
+
+ private:
+ tA2DP_CTRL_CMD a2dp_pending_cmd_;
+ uint16_t remote_delay_report_;
+ uint64_t total_bytes_read_;
+ timespec data_position_;
+};
+
+A2dpTransport* a2dp_sink = nullptr;
+
+// Common interface to call-out into Bluetooth Audio HAL
+bluetooth::audio::BluetoothAudioClientInterface* a2dp_hal_clientif = nullptr;
+auto session_type = SessionType::UNKNOWN;
+
+// Save the value if the remote reports its delay before a2dp_sink is
+// initialized
+uint16_t remote_delay = 0;
+
+bool btaudio_a2dp_disabled = false;
+bool is_configured = false;
+
+BluetoothAudioCtrlAck a2dp_ack_to_bt_audio_ctrl_ack(tA2DP_CTRL_ACK ack) {
+ switch (ack) {
+ case A2DP_CTRL_ACK_SUCCESS:
+ return BluetoothAudioCtrlAck::SUCCESS_FINISHED;
+ case A2DP_CTRL_ACK_PENDING:
+ return BluetoothAudioCtrlAck::PENDING;
+ case A2DP_CTRL_ACK_INCALL_FAILURE:
+ return BluetoothAudioCtrlAck::FAILURE_BUSY;
+ case A2DP_CTRL_ACK_DISCONNECT_IN_PROGRESS:
+ return BluetoothAudioCtrlAck::FAILURE_DISCONNECTING;
+ case A2DP_CTRL_ACK_UNSUPPORTED: /* Offloading but resource failure */
+ return BluetoothAudioCtrlAck::FAILURE_UNSUPPORTED;
+ case A2DP_CTRL_ACK_FAILURE:
+ return BluetoothAudioCtrlAck::FAILURE;
+ default:
+ return BluetoothAudioCtrlAck::FAILURE;
+ }
+}
+
+SampleRate a2dp_codec_to_hal_sample_rate(
+ const btav_a2dp_codec_config_t& a2dp_codec_config) {
+ switch (a2dp_codec_config.sample_rate) {
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
+ return SampleRate::RATE_44100;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_48000:
+ return SampleRate::RATE_48000;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_88200:
+ return SampleRate::RATE_88200;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_96000:
+ return SampleRate::RATE_96000;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
+ return SampleRate::RATE_176400;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
+ return SampleRate::RATE_192000;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_16000:
+ return SampleRate::RATE_16000;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_24000:
+ return SampleRate::RATE_24000;
+ default:
+ return SampleRate::RATE_UNKNOWN;
+ }
+}
+
+BitsPerSample a2dp_codec_to_hal_bits_per_sample(
+ const btav_a2dp_codec_config_t& a2dp_codec_config) {
+ switch (a2dp_codec_config.bits_per_sample) {
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
+ return BitsPerSample::BITS_16;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24:
+ return BitsPerSample::BITS_24;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32:
+ return BitsPerSample::BITS_32;
+ default:
+ return BitsPerSample::BITS_UNKNOWN;
+ }
+}
+
+ChannelMode a2dp_codec_to_hal_channel_mode(
+ const btav_a2dp_codec_config_t& a2dp_codec_config) {
+ switch (a2dp_codec_config.channel_mode) {
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
+ return ChannelMode::MONO;
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO:
+ return ChannelMode::STEREO;
+ default:
+ return ChannelMode::UNKNOWN;
+ }
+}
+
+bool a2dp_get_selected_hal_codec_config(CodecConfiguration* codec_config) {
+ A2dpCodecConfig* a2dp_codec_configs = bta_av_get_a2dp_current_codec();
+ if (a2dp_codec_configs == nullptr) {
+ LOG(WARNING) << __func__ << ": failure to get A2DP codec config";
+ *codec_config = kInvalidCodecConfiguration;
+ return false;
+ }
+ btav_a2dp_codec_config_t current_codec = a2dp_codec_configs->getCodecConfig();
+ tBT_A2DP_OFFLOAD a2dp_offload;
+ a2dp_codec_configs->getCodecSpecificConfig(&a2dp_offload);
+ switch (current_codec.codec_type) {
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
+ [[fallthrough]];
+ case BTAV_A2DP_CODEC_INDEX_SINK_SBC: {
+ codec_config->codecType = CodecType::SBC;
+ codec_config->config.sbcConfig({});
+ auto sbc_config = codec_config->config.sbcConfig();
+ sbc_config.sampleRate = a2dp_codec_to_hal_sample_rate(current_codec);
+ if (sbc_config.sampleRate == SampleRate::RATE_UNKNOWN) {
+ LOG(ERROR) << __func__
+ << ": Unknown SBC sample_rate=" << current_codec.sample_rate;
+ return false;
+ }
+ uint8_t channel_mode = a2dp_offload.codec_info[3] & A2DP_SBC_IE_CH_MD_MSK;
+ switch (channel_mode) {
+ case A2DP_SBC_IE_CH_MD_JOINT:
+ sbc_config.channelMode = SbcChannelMode::JOINT_STEREO;
+ break;
+ case A2DP_SBC_IE_CH_MD_STEREO:
+ sbc_config.channelMode = SbcChannelMode::STEREO;
+ break;
+ case A2DP_SBC_IE_CH_MD_DUAL:
+ sbc_config.channelMode = SbcChannelMode::DUAL;
+ break;
+ case A2DP_SBC_IE_CH_MD_MONO:
+ sbc_config.channelMode = SbcChannelMode::MONO;
+ break;
+ default:
+ LOG(ERROR) << __func__
+ << ": Unknown SBC channel_mode=" << channel_mode;
+ sbc_config.channelMode = SbcChannelMode::UNKNOWN;
+ return false;
+ }
+ uint8_t block_length =
+ a2dp_offload.codec_info[0] & A2DP_SBC_IE_BLOCKS_MSK;
+ switch (block_length) {
+ case A2DP_SBC_IE_BLOCKS_4:
+ sbc_config.blockLength = SbcBlockLength::BLOCKS_4;
+ break;
+ case A2DP_SBC_IE_BLOCKS_8:
+ sbc_config.blockLength = SbcBlockLength::BLOCKS_8;
+ break;
+ case A2DP_SBC_IE_BLOCKS_12:
+ sbc_config.blockLength = SbcBlockLength::BLOCKS_12;
+ break;
+ case A2DP_SBC_IE_BLOCKS_16:
+ sbc_config.blockLength = SbcBlockLength::BLOCKS_16;
+ break;
+ default:
+ LOG(ERROR) << __func__
+ << ": Unknown SBC block_length=" << block_length;
+ return false;
+ }
+ uint8_t sub_bands = a2dp_offload.codec_info[0] & A2DP_SBC_IE_SUBBAND_MSK;
+ switch (sub_bands) {
+ case A2DP_SBC_IE_SUBBAND_4:
+ sbc_config.numSubbands = SbcNumSubbands::SUBBAND_4;
+ break;
+ case A2DP_SBC_IE_SUBBAND_8:
+ sbc_config.numSubbands = SbcNumSubbands::SUBBAND_8;
+ break;
+ default:
+ LOG(ERROR) << __func__ << ": Unknown SBC Subbands=" << sub_bands;
+ return false;
+ }
+ uint8_t alloc_method =
+ a2dp_offload.codec_info[0] & A2DP_SBC_IE_ALLOC_MD_MSK;
+ switch (alloc_method) {
+ case A2DP_SBC_IE_ALLOC_MD_S:
+ sbc_config.allocMethod = SbcAllocMethod::ALLOC_MD_S;
+ break;
+ case A2DP_SBC_IE_ALLOC_MD_L:
+ sbc_config.allocMethod = SbcAllocMethod::ALLOC_MD_L;
+ break;
+ default:
+ LOG(ERROR) << __func__
+ << ": Unknown SBC alloc_method=" << alloc_method;
+ return false;
+ }
+ sbc_config.minBitpool = a2dp_offload.codec_info[1];
+ sbc_config.maxBitpool = a2dp_offload.codec_info[2];
+ sbc_config.bitsPerSample =
+ a2dp_codec_to_hal_bits_per_sample(current_codec);
+ if (sbc_config.bitsPerSample == BitsPerSample::BITS_UNKNOWN) {
+ LOG(ERROR) << __func__ << ": Unknown SBC bits_per_sample="
+ << current_codec.bits_per_sample;
+ return false;
+ }
+ codec_config->config.sbcConfig(sbc_config);
+ break;
+ }
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
+ [[fallthrough]];
+ case BTAV_A2DP_CODEC_INDEX_SINK_AAC: {
+ codec_config->codecType = CodecType::AAC;
+ codec_config->config.aacConfig({});
+ auto aac_config = codec_config->config.aacConfig();
+ uint8_t object_type = a2dp_offload.codec_info[0];
+ switch (object_type) {
+ case A2DP_AAC_OBJECT_TYPE_MPEG2_LC:
+ aac_config.objectType = AacObjectType::MPEG2_LC;
+ break;
+ case A2DP_AAC_OBJECT_TYPE_MPEG4_LC:
+ aac_config.objectType = AacObjectType::MPEG4_LC;
+ break;
+ case A2DP_AAC_OBJECT_TYPE_MPEG4_LTP:
+ aac_config.objectType = AacObjectType::MPEG4_LTP;
+ break;
+ case A2DP_AAC_OBJECT_TYPE_MPEG4_SCALABLE:
+ aac_config.objectType = AacObjectType::MPEG4_SCALABLE;
+ break;
+ default:
+ LOG(ERROR) << __func__
+ << ": Unknown AAC object_type=" << +object_type;
+ return false;
+ }
+ aac_config.sampleRate = a2dp_codec_to_hal_sample_rate(current_codec);
+ if (aac_config.sampleRate == SampleRate::RATE_UNKNOWN) {
+ LOG(ERROR) << __func__
+ << ": Unknown AAC sample_rate=" << current_codec.sample_rate;
+ return false;
+ }
+ aac_config.channelMode = a2dp_codec_to_hal_channel_mode(current_codec);
+ if (aac_config.channelMode == ChannelMode::UNKNOWN) {
+ LOG(ERROR) << __func__ << ": Unknown AAC channel_mode="
+ << current_codec.channel_mode;
+ return false;
+ }
+ uint8_t vbr_enabled =
+ a2dp_offload.codec_info[1] & A2DP_AAC_VARIABLE_BIT_RATE_MASK;
+ switch (vbr_enabled) {
+ case A2DP_AAC_VARIABLE_BIT_RATE_ENABLED:
+ aac_config.variableBitRateEnabled = AacVariableBitRate::ENABLED;
+ break;
+ case A2DP_AAC_VARIABLE_BIT_RATE_DISABLED:
+ aac_config.variableBitRateEnabled = AacVariableBitRate::DISABLED;
+ break;
+ default:
+ LOG(ERROR) << __func__ << ": Unknown AAC VBR=" << +vbr_enabled;
+ return false;
+ }
+ aac_config.bitsPerSample =
+ a2dp_codec_to_hal_bits_per_sample(current_codec);
+ if (aac_config.bitsPerSample == BitsPerSample::BITS_UNKNOWN) {
+ LOG(ERROR) << __func__ << ": Unknown AAC bits_per_sample="
+ << current_codec.bits_per_sample;
+ return false;
+ }
+ codec_config->config.aacConfig(aac_config);
+ break;
+ }
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
+ [[fallthrough]];
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD: {
+ if (current_codec.codec_type == BTAV_A2DP_CODEC_INDEX_SOURCE_APTX) {
+ codec_config->codecType = CodecType::APTX;
+ } else {
+ codec_config->codecType = CodecType::APTX_HD;
+ }
+ codec_config->config.aptxConfig({});
+ auto aptx_config = codec_config->config.aptxConfig();
+ aptx_config.sampleRate = a2dp_codec_to_hal_sample_rate(current_codec);
+ if (aptx_config.sampleRate == SampleRate::RATE_UNKNOWN) {
+ LOG(ERROR) << __func__ << ": Unknown aptX sample_rate="
+ << current_codec.sample_rate;
+ return false;
+ }
+ aptx_config.channelMode = a2dp_codec_to_hal_channel_mode(current_codec);
+ if (aptx_config.channelMode == ChannelMode::UNKNOWN) {
+ LOG(ERROR) << __func__ << ": Unknown aptX channel_mode="
+ << current_codec.channel_mode;
+ return false;
+ }
+ aptx_config.bitsPerSample =
+ a2dp_codec_to_hal_bits_per_sample(current_codec);
+ if (aptx_config.bitsPerSample == BitsPerSample::BITS_UNKNOWN) {
+ LOG(ERROR) << __func__ << ": Unknown aptX bits_per_sample="
+ << current_codec.bits_per_sample;
+ return false;
+ }
+ codec_config->config.aptxConfig(aptx_config);
+ break;
+ }
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC: {
+ codec_config->codecType = CodecType::LDAC;
+ codec_config->config.ldacConfig({});
+ auto ldac_config = codec_config->config.ldacConfig();
+ ldac_config.sampleRate = a2dp_codec_to_hal_sample_rate(current_codec);
+ if (ldac_config.sampleRate == SampleRate::RATE_UNKNOWN) {
+ LOG(ERROR) << __func__ << ": Unknown LDAC sample_rate="
+ << current_codec.sample_rate;
+ return false;
+ }
+ switch (a2dp_offload.codec_info[7]) {
+ case A2DP_LDAC_CHANNEL_MODE_STEREO:
+ ldac_config.channelMode = LdacChannelMode::STEREO;
+ break;
+ case A2DP_LDAC_CHANNEL_MODE_DUAL:
+ ldac_config.channelMode = LdacChannelMode::DUAL;
+ break;
+ case A2DP_LDAC_CHANNEL_MODE_MONO:
+ ldac_config.channelMode = LdacChannelMode::MONO;
+ break;
+ default:
+ LOG(ERROR) << __func__ << ": Unknown LDAC channel_mode="
+ << a2dp_offload.codec_info[7];
+ ldac_config.channelMode = LdacChannelMode::UNKNOWN;
+ return false;
+ }
+ switch (a2dp_offload.codec_info[6]) {
+ case A2DP_LDAC_QUALITY_HIGH:
+ ldac_config.qualityIndex = LdacQualityIndex::QUALITY_HIGH;
+ break;
+ case A2DP_LDAC_QUALITY_MID:
+ ldac_config.qualityIndex = LdacQualityIndex::QUALITY_MID;
+ break;
+ case A2DP_LDAC_QUALITY_LOW:
+ ldac_config.qualityIndex = LdacQualityIndex::QUALITY_LOW;
+ break;
+ case A2DP_LDAC_QUALITY_ABR_OFFLOAD:
+ ldac_config.qualityIndex = LdacQualityIndex::QUALITY_ABR;
+ break;
+ default:
+ LOG(ERROR) << __func__ << ": Unknown LDAC QualityIndex="
+ << a2dp_offload.codec_info[6];
+ return false;
+ }
+ ldac_config.bitsPerSample =
+ a2dp_codec_to_hal_bits_per_sample(current_codec);
+ if (ldac_config.bitsPerSample == BitsPerSample::BITS_UNKNOWN) {
+ LOG(ERROR) << __func__ << ": Unknown LDAC bits_per_sample="
+ << current_codec.bits_per_sample;
+ return false;
+ }
+ codec_config->config.ldacConfig(ldac_config);
+ break;
+ }
+ case BTAV_A2DP_CODEC_INDEX_MAX:
+ [[fallthrough]];
+ default:
+ LOG(ERROR) << __func__
+ << ": Unknown codec_type=" << current_codec.codec_type;
+ codec_config->codecType = CodecType::UNKNOWN;
+ codec_config->config = {};
+ return false;
+ }
+ codec_config->encodedAudioBitrate = a2dp_codec_configs->getTrackBitRate();
+ // Obtain the MTU
+ RawAddress peer_addr = btif_av_source_active_peer();
+ tA2DP_ENCODER_INIT_PEER_PARAMS peer_param;
+ bta_av_co_get_peer_params(peer_addr, &peer_param);
+ int effectiveMtu = a2dp_codec_configs->getEffectiveMtu();
+ if (effectiveMtu > 0 && effectiveMtu < peer_param.peer_mtu) {
+ codec_config->peerMtu = effectiveMtu;
+ } else {
+ codec_config->peerMtu = peer_param.peer_mtu;
+ }
+ LOG(INFO) << __func__ << ": CodecConfiguration=" << toString(*codec_config);
+ return true;
+}
+
+bool a2dp_get_selected_hal_pcm_config(PcmParameters* pcm_config) {
+ if (pcm_config == nullptr) return false;
+ A2dpCodecConfig* a2dp_codec_configs = bta_av_get_a2dp_current_codec();
+ if (a2dp_codec_configs == nullptr) {
+ LOG(WARNING) << __func__ << ": failure to get A2DP codec config";
+ *pcm_config = ::bluetooth::audio::BluetoothAudioClientInterface::
+ kInvalidPcmConfiguration;
+ return false;
+ }
+
+ btav_a2dp_codec_config_t current_codec = a2dp_codec_configs->getCodecConfig();
+ pcm_config->sampleRate = a2dp_codec_to_hal_sample_rate(current_codec);
+ pcm_config->bitsPerSample = a2dp_codec_to_hal_bits_per_sample(current_codec);
+ pcm_config->channelMode = a2dp_codec_to_hal_channel_mode(current_codec);
+ return (pcm_config->sampleRate != SampleRate::RATE_UNKNOWN &&
+ pcm_config->bitsPerSample != BitsPerSample::BITS_UNKNOWN &&
+ pcm_config->channelMode != ChannelMode::UNKNOWN);
+}
+
+// Checking if new bluetooth_audio is supported
+bool is_hal_2_0_force_disabled() {
+ if (!is_configured) {
+ btaudio_a2dp_disabled = osi_property_get_bool(BLUETOOTH_AUDIO_HAL_PROP_DISABLED, false);
+ is_configured = true;
+ }
+ return btaudio_a2dp_disabled;
+}
+
+} // namespace
+
+namespace bluetooth {
+namespace audio {
+namespace a2dp {
+
+// Checking if new bluetooth_audio is enabled
+bool is_hal_2_0_enabled() { return a2dp_hal_clientif != nullptr; }
+
+// Initialize BluetoothAudio HAL: openProvider
+bool init(bluetooth::common::MessageLoopThread* message_loop) {
+ LOG(INFO) << __func__;
+
+ if (is_hal_2_0_force_disabled()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudio HAL is disabled";
+ return false;
+ }
+
+ if (btif_av_is_a2dp_offload_enabled()) {
+ session_type = SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH;
+ } else {
+ session_type = SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH;
+ }
+ a2dp_sink = new A2dpTransport(session_type);
+ a2dp_hal_clientif = new bluetooth::audio::BluetoothAudioClientInterface(
+ a2dp_sink, message_loop);
+ if (!a2dp_hal_clientif->IsValid()) {
+ LOG(WARNING) << __func__ << ": BluetoothAudio HAL for A2DP session=" << toString(session_type) << " is invalid?!";
+ delete a2dp_hal_clientif;
+ a2dp_hal_clientif = nullptr;
+ delete a2dp_sink;
+ a2dp_sink = nullptr;
+ return false;
+ }
+
+ if (remote_delay != 0) {
+ LOG(INFO) << __func__ << ": restore DELAY "
+ << static_cast<float>(remote_delay / 10.0) << " ms";
+ a2dp_sink->SetRemoteDelay(remote_delay);
+ remote_delay = 0;
+ }
+ return true;
+}
+
+// Clean up BluetoothAudio HAL
+void cleanup() {
+ if (!is_hal_2_0_enabled()) return;
+ end_session();
+ delete a2dp_hal_clientif;
+ a2dp_hal_clientif = nullptr;
+ delete a2dp_sink;
+ a2dp_sink = nullptr;
+ session_type = SessionType::UNKNOWN;
+ remote_delay = 0;
+}
+
+// Set up the codec into BluetoothAudio HAL
+bool setup_codec() {
+ if (!is_hal_2_0_enabled()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudio HAL is not enabled";
+ return false;
+ }
+ AudioConfiguration audio_config{};
+ if (session_type == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
+ CodecConfiguration codec_config{};
+ if (!a2dp_get_selected_hal_codec_config(&codec_config)) {
+ LOG(ERROR) << __func__ << ": Failed to get CodecConfiguration";
+ return false;
+ }
+ audio_config.codecConfig(codec_config);
+ } else if (session_type == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH) {
+ PcmParameters pcm_config{};
+ if (!a2dp_get_selected_hal_pcm_config(&pcm_config)) {
+ LOG(ERROR) << __func__ << ": Failed to get PcmConfiguration";
+ return false;
+ }
+ audio_config.pcmConfig(pcm_config);
+ }
+ return a2dp_hal_clientif->UpdateAudioConfig(audio_config);
+}
+
+void start_session() {
+ if (!is_hal_2_0_enabled()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudio HAL is not enabled";
+ return;
+ }
+ a2dp_hal_clientif->StartSession();
+}
+
+void end_session() {
+ if (!is_hal_2_0_enabled()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudio HAL is not enabled";
+ return;
+ }
+ a2dp_hal_clientif->EndSession();
+}
+
+void ack_stream_started(const tA2DP_CTRL_ACK& ack) {
+ auto ctrl_ack = a2dp_ack_to_bt_audio_ctrl_ack(ack);
+ LOG(INFO) << __func__ << ": result=" << ctrl_ack;
+ auto pending_cmd = a2dp_sink->GetPendingCmd();
+ if (pending_cmd == A2DP_CTRL_CMD_START) {
+ a2dp_hal_clientif->StreamStarted(ctrl_ack);
+ } else {
+ LOG(WARNING) << __func__ << ": pending=" << pending_cmd
+ << " ignore result=" << ctrl_ack;
+ return;
+ }
+ if (ctrl_ack != bluetooth::audio::BluetoothAudioCtrlAck::PENDING) {
+ a2dp_sink->ResetPendingCmd();
+ }
+}
+
+void ack_stream_suspended(const tA2DP_CTRL_ACK& ack) {
+ auto ctrl_ack = a2dp_ack_to_bt_audio_ctrl_ack(ack);
+ LOG(INFO) << __func__ << ": result=" << ctrl_ack;
+ auto pending_cmd = a2dp_sink->GetPendingCmd();
+ if (pending_cmd == A2DP_CTRL_CMD_SUSPEND) {
+ a2dp_hal_clientif->StreamSuspended(ctrl_ack);
+ } else if (pending_cmd == A2DP_CTRL_CMD_STOP) {
+ LOG(INFO) << __func__ << ": A2DP_CTRL_CMD_STOP result=" << ctrl_ack;
+ } else {
+ LOG(WARNING) << __func__ << ": pending=" << pending_cmd
+ << " ignore result=" << ctrl_ack;
+ return;
+ }
+ if (ctrl_ack != bluetooth::audio::BluetoothAudioCtrlAck::PENDING) {
+ a2dp_sink->ResetPendingCmd();
+ }
+}
+
+// Read from the FMQ of BluetoothAudio HAL
+size_t read(uint8_t* p_buf, uint32_t len) {
+ if (!is_hal_2_0_enabled()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudio HAL is not enabled";
+ return 0;
+ } else if (session_type != SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH) {
+ LOG(ERROR) << __func__ << ": session_type=" << toString(session_type)
+ << " is not A2DP_SOFTWARE_ENCODING_DATAPATH";
+ return 0;
+ }
+ return a2dp_hal_clientif->ReadAudioData(p_buf, len);
+}
+
+// Update A2DP delay report to BluetoothAudio HAL
+void set_remote_delay(uint16_t delay_report) {
+ if (!is_hal_2_0_enabled()) {
+ LOG(INFO) << __func__ << ": not ready for DelayReport "
+ << static_cast<float>(delay_report / 10.0) << " ms";
+ remote_delay = delay_report;
+ return;
+ }
+ LOG(INFO) << __func__ << ": DELAY " << static_cast<float>(delay_report / 10.0)
+ << " ms";
+ a2dp_sink->SetRemoteDelay(delay_report);
+}
+
+} // namespace a2dp
+} // namespace audio
+} // namespace bluetooth
diff --git a/audio_hal_interface/a2dp_encoding.h b/audio_hal_interface/a2dp_encoding.h
new file mode 100644
index 0000000..7b104ff
--- /dev/null
+++ b/audio_hal_interface/a2dp_encoding.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2019 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 "audio_a2dp_hw/include/audio_a2dp_hw.h"
+#include "common/message_loop_thread.h"
+
+namespace bluetooth {
+namespace audio {
+namespace a2dp {
+
+// Check if new bluetooth_audio is enabled
+bool is_hal_2_0_enabled();
+
+// Initialize BluetoothAudio HAL: openProvider
+bool init(bluetooth::common::MessageLoopThread* message_loop);
+
+// Clean up BluetoothAudio HAL
+void cleanup();
+
+// Set up the codec into BluetoothAudio HAL
+bool setup_codec();
+
+// Send command to the BluetoothAudio HAL: StartSession, EndSession,
+// StreamStarted, StreamSuspended
+void start_session();
+void end_session();
+void ack_stream_started(const tA2DP_CTRL_ACK& status);
+void ack_stream_suspended(const tA2DP_CTRL_ACK& status);
+
+// Read from the FMQ of BluetoothAudio HAL
+size_t read(uint8_t* p_buf, uint32_t len);
+
+// Update A2DP delay report to BluetoothAudio HAL
+void set_remote_delay(uint16_t delay_report);
+
+} // namespace a2dp
+} // namespace audio
+} // namespace bluetooth
diff --git a/audio_hal_interface/client_interface.cc b/audio_hal_interface/client_interface.cc
new file mode 100644
index 0000000..9f1be24
--- /dev/null
+++ b/audio_hal_interface/client_interface.cc
@@ -0,0 +1,501 @@
+/*
+ * Copyright 2019 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 "BTAudioClientIf"
+
+#include "client_interface.h"
+
+#include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioPort.h>
+#include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioProvidersFactory.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <base/logging.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/ServiceManagement.h>
+#include <future>
+
+#include "osi/include/log.h"
+
+namespace bluetooth {
+namespace audio {
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::audio::common::V5_0::SourceMetadata;
+using ::android::hardware::bluetooth::audio::V2_0::IBluetoothAudioPort;
+using ::android::hardware::bluetooth::audio::V2_0::
+ IBluetoothAudioProvidersFactory;
+using DataMQ = ::android::hardware::MessageQueue<
+ uint8_t, ::android::hardware::kSynchronizedReadWrite>;
+
+static constexpr int kDefaultDataReadTimeoutMs = 10; // 10 ms
+static constexpr int kDefaultDataReadPollIntervalMs = 1; // non-blocking poll
+static constexpr char kFullyQualifiedInterfaceName[] =
+ "android.hardware.bluetooth.audio@2.0::IBluetoothAudioProvidersFactory";
+
+std::ostream& operator<<(std::ostream& os, const BluetoothAudioCtrlAck& ack) {
+ switch (ack) {
+ case BluetoothAudioCtrlAck::SUCCESS_FINISHED:
+ return os << "SUCCESS_FINISHED";
+ case BluetoothAudioCtrlAck::PENDING:
+ return os << "PENDING";
+ case BluetoothAudioCtrlAck::FAILURE_UNSUPPORTED:
+ return os << "FAILURE_UNSUPPORTED";
+ case BluetoothAudioCtrlAck::FAILURE_BUSY:
+ return os << "FAILURE_BUSY";
+ case BluetoothAudioCtrlAck::FAILURE_DISCONNECTING:
+ return os << "FAILURE_DISCONNECTING";
+ case BluetoothAudioCtrlAck::FAILURE:
+ return os << "FAILURE";
+ default:
+ return os << "UNDEFINED " << static_cast<int8_t>(ack);
+ }
+}
+
+// Internal class within BluetoothAudioClientInterfaceace to implement
+// IBluetoothAudioPort (control interface used by Bluetooth Audio HAL)
+class BluetoothAudioPortImpl : public IBluetoothAudioPort {
+ public:
+ BluetoothAudioPortImpl(IBluetoothTransportInstance* sink,
+ const android::sp<IBluetoothAudioProvider>& provider)
+ : sink_(sink), provider_(provider){};
+
+ Return<void> startStream() override {
+ BluetoothAudioCtrlAck ack = sink_->StartRequest();
+ if (ack != BluetoothAudioCtrlAck::PENDING) {
+ auto hidl_retval =
+ provider_->streamStarted(BluetoothAudioCtrlAckToHalStatus(ack));
+ if (!hidl_retval.isOk()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioHal failure: " << hidl_retval.description();
+ }
+ }
+ return Void();
+ }
+
+ Return<void> suspendStream() override {
+ BluetoothAudioCtrlAck ack = sink_->SuspendRequest();
+ if (ack != BluetoothAudioCtrlAck::PENDING) {
+ auto hidl_retval =
+ provider_->streamSuspended(BluetoothAudioCtrlAckToHalStatus(ack));
+ if (!hidl_retval.isOk()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioHal failure: " << hidl_retval.description();
+ }
+ }
+ return Void();
+ }
+
+ Return<void> stopStream() override {
+ sink_->StopRequest();
+ return Void();
+ }
+
+ Return<void> getPresentationPosition(
+ getPresentationPosition_cb _hidl_cb) override {
+ uint64_t remote_delay_report_ns;
+ uint64_t total_bytes_read;
+ timespec data_position;
+ bool retval = sink_->GetPresentationPosition(
+ &remote_delay_report_ns, &total_bytes_read, &data_position);
+
+ TimeSpec transmittedOctetsTimeStamp;
+ if (retval) {
+ transmittedOctetsTimeStamp = timespec_convert_to_hal(data_position);
+ } else {
+ remote_delay_report_ns = 0;
+ total_bytes_read = 0;
+ transmittedOctetsTimeStamp = {};
+ }
+ VLOG(2) << __func__ << ": result=" << retval
+ << ", delay=" << remote_delay_report_ns
+ << ", data=" << total_bytes_read
+ << " byte(s), timestamp=" << toString(transmittedOctetsTimeStamp);
+ _hidl_cb((retval ? BluetoothAudioStatus::SUCCESS
+ : BluetoothAudioStatus::FAILURE),
+ remote_delay_report_ns, total_bytes_read,
+ transmittedOctetsTimeStamp);
+ return Void();
+ }
+
+ Return<void> updateMetadata(const SourceMetadata& sourceMetadata) override {
+ LOG(INFO) << __func__ << ": " << sourceMetadata.tracks.size()
+ << " track(s)";
+ // refer to StreamOut.impl.h within Audio HAL (AUDIO_HAL_VERSION_5_0)
+ std::vector<playback_track_metadata> metadata_vec;
+ metadata_vec.reserve(sourceMetadata.tracks.size());
+ for (const auto& metadata : sourceMetadata.tracks) {
+ metadata_vec.push_back({
+ .usage = static_cast<audio_usage_t>(metadata.usage),
+ .content_type =
+ static_cast<audio_content_type_t>(metadata.contentType),
+ .gain = metadata.gain,
+ });
+ }
+ const source_metadata_t source_metadata = {
+ .track_count = metadata_vec.size(), .tracks = metadata_vec.data()};
+ sink_->MetadataChanged(source_metadata);
+ return Void();
+ }
+
+ private:
+ IBluetoothTransportInstance* sink_;
+ const android::sp<IBluetoothAudioProvider> provider_;
+ TimeSpec timespec_convert_to_hal(const timespec& ts) {
+ return {.tvSec = static_cast<uint64_t>(ts.tv_sec),
+ .tvNSec = static_cast<uint64_t>(ts.tv_nsec)};
+ }
+};
+
+class BluetoothAudioDeathRecipient
+ : public ::android::hardware::hidl_death_recipient {
+ public:
+ BluetoothAudioDeathRecipient(
+ BluetoothAudioClientInterface* clientif,
+ bluetooth::common::MessageLoopThread* message_loop)
+ : bluetooth_audio_clientif_(clientif), message_loop_(message_loop) {}
+ void serviceDied(
+ uint64_t /*cookie*/,
+ const ::android::wp<::android::hidl::base::V1_0::IBase>& /*who*/)
+ override {
+ LOG(WARNING) << __func__ << ": restarting connection with new Audio Hal";
+ if (bluetooth_audio_clientif_ != nullptr && message_loop_ != nullptr) {
+ // restart the session on the correct thread
+ message_loop_->DoInThread(
+ FROM_HERE,
+ base::BindOnce(
+ &BluetoothAudioClientInterface::RenewAudioProviderAndSession,
+ base::Unretained(bluetooth_audio_clientif_)));
+ } else {
+ LOG(ERROR) << __func__ << ": BluetoothAudioClientInterface corrupted";
+ }
+ }
+
+ private:
+ BluetoothAudioClientInterface* bluetooth_audio_clientif_;
+ bluetooth::common::MessageLoopThread* message_loop_;
+};
+
+BluetoothAudioClientInterface::BluetoothAudioClientInterface(IBluetoothTransportInstance* sink,
+ bluetooth::common::MessageLoopThread* message_loop)
+ : sink_(sink), provider_(nullptr), session_started_(false), mDataMQ(nullptr),
+ death_recipient_(new BluetoothAudioDeathRecipient(this, message_loop)) {
+ auto service_manager = android::hardware::defaultServiceManager1_2();
+ CHECK(service_manager != nullptr);
+ size_t instance_count = 0;
+ auto listManifestByInterface_cb = [&instance_count](const hidl_vec<android::hardware::hidl_string>& instanceNames) {
+ instance_count = instanceNames.size();
+ LOG(INFO) << "listManifestByInterface_cb returns " << instance_count << " instance(s)";
+ };
+ auto hidl_retval = service_manager->listManifestByInterface(kFullyQualifiedInterfaceName, listManifestByInterface_cb);
+ if (!hidl_retval.isOk()) {
+ LOG(FATAL) << __func__ << ": IServiceManager::listByInterface failure: " << hidl_retval.description();
+ }
+ if (instance_count > 0) {
+ fetch_audio_provider();
+ } else {
+ LOG(WARNING) << "IBluetoothAudioProvidersFactory not declared";
+ }
+}
+
+BluetoothAudioClientInterface::~BluetoothAudioClientInterface() {
+ if (provider_ != nullptr) {
+ auto hidl_retval = provider_->unlinkToDeath(death_recipient_);
+ if (!hidl_retval.isOk()) {
+ LOG(FATAL) << __func__ << ": BluetoothAudioDeathRecipient failure: " << hidl_retval.description();
+ }
+ }
+}
+
+std::vector<AudioCapabilities>
+BluetoothAudioClientInterface::GetAudioCapabilities() const {
+ return capabilities_;
+}
+
+void BluetoothAudioClientInterface::fetch_audio_provider() {
+ if (provider_ != nullptr) {
+ LOG(WARNING) << __func__ << ": reflash";
+ }
+
+ android::sp<IBluetoothAudioProvidersFactory> providersFactory =
+ IBluetoothAudioProvidersFactory::getService();
+ CHECK(providersFactory != nullptr) << "IBluetoothAudioProvidersFactory::getService() failed";
+ LOG(INFO) << "IBluetoothAudioProvidersFactory::getService() returned "
+ << providersFactory.get()
+ << (providersFactory->isRemote() ? " (remote)" : " (local)");
+
+ std::promise<void> getProviderCapabilities_promise;
+ auto getProviderCapabilities_future =
+ getProviderCapabilities_promise.get_future();
+ auto getProviderCapabilities_cb =
+ [& capabilities = this->capabilities_, &getProviderCapabilities_promise](
+ const hidl_vec<AudioCapabilities>& audioCapabilities) {
+ for (auto capability : audioCapabilities) {
+ capabilities.push_back(capability);
+ }
+ getProviderCapabilities_promise.set_value();
+ };
+ auto hidl_retval = providersFactory->getProviderCapabilities(
+ sink_->GetSessionType(), getProviderCapabilities_cb);
+ getProviderCapabilities_future.get();
+ if (!hidl_retval.isOk()) {
+ LOG(FATAL) << __func__ << ": BluetoothAudioHal::getProviderCapabilities failure: " << hidl_retval.description();
+ return;
+ }
+ if (capabilities_.empty()) {
+ LOG(WARNING) << __func__
+ << ": SessionType=" << toString(sink_->GetSessionType())
+ << " Not supported by BluetoothAudioHal";
+ return;
+ }
+ LOG(INFO) << __func__ << ": BluetoothAudioHal SessionType="
+ << toString(sink_->GetSessionType()) << " has "
+ << capabilities_.size() << " AudioCapabilities";
+
+ std::promise<void> openProvider_promise;
+ auto openProvider_future = openProvider_promise.get_future();
+ auto openProvider_cb =
+ [& provider_ = this->provider_, &openProvider_promise](
+ BluetoothAudioStatus status,
+ const android::sp<IBluetoothAudioProvider>& provider) {
+ LOG(INFO) << "openProvider_cb(" << toString(status) << ")";
+ if (status == BluetoothAudioStatus::SUCCESS) {
+ provider_ = provider;
+ }
+ ALOGE_IF(!provider_, "Failed to open BluetoothAudio provider");
+ openProvider_promise.set_value();
+ };
+ hidl_retval =
+ providersFactory->openProvider(sink_->GetSessionType(), openProvider_cb);
+ openProvider_future.get();
+ if (!hidl_retval.isOk()) {
+ LOG(FATAL) << __func__ << ": BluetoothAudioHal::openProvider failure: " << hidl_retval.description();
+ }
+ CHECK(provider_ != nullptr);
+
+ if (!provider_->linkToDeath(death_recipient_, 0).isOk()) {
+ LOG(FATAL) << __func__ << ": BluetoothAudioDeathRecipient failure: " << hidl_retval.description();
+ }
+
+ LOG(INFO) << "IBluetoothAudioProvidersFactory::openProvider() returned "
+ << provider_.get()
+ << (provider_->isRemote() ? " (remote)" : " (local)");
+}
+
+bool BluetoothAudioClientInterface::UpdateAudioConfig(
+ const AudioConfiguration& audio_config) {
+ bool is_software_session =
+ (sink_->GetSessionType() ==
+ SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
+ sink_->GetSessionType() ==
+ SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH);
+ bool is_offload_session =
+ (sink_->GetSessionType() == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
+ auto audio_config_discriminator = audio_config.getDiscriminator();
+ bool is_software_audio_config =
+ (is_software_session &&
+ audio_config_discriminator ==
+ AudioConfiguration::hidl_discriminator::pcmConfig);
+ bool is_offload_audio_config =
+ (is_offload_session &&
+ audio_config_discriminator ==
+ AudioConfiguration::hidl_discriminator::codecConfig);
+ if (!is_software_audio_config && !is_offload_audio_config) {
+ return false;
+ }
+ sink_->UpdateAudioConfiguration(audio_config);
+ return true;
+}
+
+int BluetoothAudioClientInterface::StartSession() {
+ std::lock_guard<std::mutex> guard(internal_mutex_);
+ if (provider_ == nullptr) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioHal nullptr";
+ session_started_ = false;
+ return -EINVAL;
+ }
+ if (session_started_) {
+ LOG(ERROR) << __func__ << ": session started already";
+ return -EBUSY;
+ }
+
+ android::sp<IBluetoothAudioPort> stack_if =
+ new BluetoothAudioPortImpl(sink_, provider_);
+ std::unique_ptr<DataMQ> tempDataMQ;
+ BluetoothAudioStatus session_status;
+
+ std::promise<void> hidl_startSession_promise;
+ auto hidl_startSession_future = hidl_startSession_promise.get_future();
+ auto hidl_cb = [&session_status, &tempDataMQ, &hidl_startSession_promise](
+ BluetoothAudioStatus status,
+ const DataMQ::Descriptor& dataMQ) {
+ LOG(INFO) << "startSession_cb(" << toString(status) << ")";
+ session_status = status;
+ if (status == BluetoothAudioStatus::SUCCESS && dataMQ.isHandleValid()) {
+ tempDataMQ.reset(new DataMQ(dataMQ));
+ }
+ hidl_startSession_promise.set_value();
+ };
+ auto hidl_retval = provider_->startSession(
+ stack_if, sink_->GetAudioConfiguration(), hidl_cb);
+ hidl_startSession_future.get();
+ if (!hidl_retval.isOk()) {
+ LOG(FATAL) << __func__ << ": BluetoothAudioHal failure: " << hidl_retval.description();
+ return -EPROTO;
+ }
+
+ if (tempDataMQ && tempDataMQ->isValid()) {
+ mDataMQ = std::move(tempDataMQ);
+ } else if (sink_->GetSessionType() ==
+ SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH &&
+ session_status == BluetoothAudioStatus::SUCCESS) {
+ sink_->ResetPresentationPosition();
+ session_started_ = true;
+ return 0;
+ }
+ if (mDataMQ && mDataMQ->isValid()) {
+ sink_->ResetPresentationPosition();
+ session_started_ = true;
+ return 0;
+ } else {
+ ALOGE_IF(!mDataMQ, "Failed to obtain audio data path");
+ ALOGE_IF(mDataMQ && !mDataMQ->isValid(), "Audio data path is invalid");
+ session_started_ = false;
+ return -EIO;
+ }
+}
+
+void BluetoothAudioClientInterface::StreamStarted(
+ const BluetoothAudioCtrlAck& ack) {
+ if (provider_ == nullptr) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioHal nullptr";
+ return;
+ }
+ if (ack == BluetoothAudioCtrlAck::PENDING) {
+ LOG(INFO) << __func__ << ": " << ack << " ignored";
+ return;
+ }
+ BluetoothAudioStatus status = BluetoothAudioCtrlAckToHalStatus(ack);
+ auto hidl_retval = provider_->streamStarted(status);
+ if (!hidl_retval.isOk()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioHal failure: " << hidl_retval.description();
+ }
+}
+
+void BluetoothAudioClientInterface::StreamSuspended(
+ const BluetoothAudioCtrlAck& ack) {
+ if (provider_ == nullptr) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioHal nullptr";
+ return;
+ }
+ if (ack == BluetoothAudioCtrlAck::PENDING) {
+ LOG(INFO) << __func__ << ": " << ack << " ignored";
+ return;
+ }
+ BluetoothAudioStatus status = BluetoothAudioCtrlAckToHalStatus(ack);
+ auto hidl_retval = provider_->streamSuspended(status);
+ if (!hidl_retval.isOk()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioHal failure: " << hidl_retval.description();
+ }
+}
+
+int BluetoothAudioClientInterface::EndSession() {
+ std::lock_guard<std::mutex> guard(internal_mutex_);
+ if (!session_started_) {
+ LOG(INFO) << __func__ << ": sessoin ended already";
+ return 0;
+ }
+
+ session_started_ = false;
+ if (provider_ == nullptr) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioHal nullptr";
+ return -EINVAL;
+ }
+ mDataMQ = nullptr;
+ auto hidl_retval = provider_->endSession();
+ if (!hidl_retval.isOk()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioHal failure: " << hidl_retval.description();
+ return -EPROTO;
+ }
+ return 0;
+}
+
+size_t BluetoothAudioClientInterface::ReadAudioData(uint8_t* p_buf,
+ uint32_t len) {
+ if (provider_ == nullptr) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioHal nullptr";
+ return 0;
+ }
+ if (p_buf == nullptr || len == 0) return 0;
+
+ std::lock_guard<std::mutex> guard(internal_mutex_);
+
+ size_t total_read = 0;
+ int timeout_ms = kDefaultDataReadTimeoutMs;
+ do {
+ if (mDataMQ == nullptr || !mDataMQ->isValid()) break;
+
+ size_t avail_to_read = mDataMQ->availableToRead();
+ if (avail_to_read) {
+ if (avail_to_read > len - total_read) {
+ avail_to_read = len - total_read;
+ }
+ if (mDataMQ->read(p_buf + total_read, avail_to_read) == 0) {
+ LOG(WARNING) << __func__ << ": len=" << len
+ << " total_read=" << total_read << " failed";
+ break;
+ }
+ total_read += avail_to_read;
+ } else if (timeout_ms >= kDefaultDataReadPollIntervalMs) {
+ std::this_thread::sleep_for(
+ std::chrono::milliseconds(kDefaultDataReadPollIntervalMs));
+ timeout_ms -= kDefaultDataReadPollIntervalMs;
+ continue;
+ } else {
+ LOG(WARNING) << __func__ << ": " << (len - total_read) << "/" << len
+ << " no data " << (kDefaultDataReadTimeoutMs - timeout_ms)
+ << " ms";
+ break;
+ }
+ } while (total_read < len);
+
+ if (timeout_ms <
+ (kDefaultDataReadTimeoutMs - kDefaultDataReadPollIntervalMs) &&
+ timeout_ms >= kDefaultDataReadPollIntervalMs) {
+ VLOG(1) << __func__ << ": underflow " << len << " -> " << total_read
+ << " read " << (kDefaultDataReadTimeoutMs - timeout_ms) << " ms";
+ } else {
+ VLOG(2) << __func__ << ": " << len << " -> " << total_read << " read";
+ }
+
+ sink_->LogBytesRead(total_read);
+ return total_read;
+}
+
+size_t BluetoothAudioClientInterface::WriteAudioData(uint8_t* p_buf,
+ uint32_t len) {
+ // Not implemented!
+ return 0;
+}
+
+void BluetoothAudioClientInterface::RenewAudioProviderAndSession() {
+ // NOTE: must be invoked on the same thread where this
+ // BluetoothAudioClientInterface is running
+ fetch_audio_provider();
+ session_started_ = false;
+ StartSession();
+}
+
+} // namespace audio
+} // namespace bluetooth
diff --git a/audio_hal_interface/client_interface.h b/audio_hal_interface/client_interface.h
new file mode 100644
index 0000000..11984aa
--- /dev/null
+++ b/audio_hal_interface/client_interface.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2019 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 <time.h>
+#include <mutex>
+
+#include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioProvider.h>
+#include <android/hardware/bluetooth/audio/2.0/types.h>
+#include <fmq/MessageQueue.h>
+#include <hardware/audio.h>
+
+#include "common/message_loop_thread.h"
+
+#define BLUETOOTH_AUDIO_HAL_PROP_DISABLED "persist.bluetooth.bluetooth_audio_hal.disabled"
+
+namespace bluetooth {
+namespace audio {
+
+using ::android::hardware::bluetooth::audio::V2_0::AudioCapabilities;
+using ::android::hardware::bluetooth::audio::V2_0::AudioConfiguration;
+using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
+using ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
+using ::android::hardware::bluetooth::audio::V2_0::CodecConfiguration;
+using ::android::hardware::bluetooth::audio::V2_0::CodecType;
+using ::android::hardware::bluetooth::audio::V2_0::IBluetoothAudioProvider;
+using ::android::hardware::bluetooth::audio::V2_0::PcmParameters;
+using ::android::hardware::bluetooth::audio::V2_0::SampleRate;
+using ::android::hardware::bluetooth::audio::V2_0::SessionType;
+using ::android::hardware::bluetooth::audio::V2_0::TimeSpec;
+using BluetoothAudioStatus =
+ ::android::hardware::bluetooth::audio::V2_0::Status;
+
+enum class BluetoothAudioCtrlAck : uint8_t {
+ SUCCESS_FINISHED = 0,
+ PENDING,
+ FAILURE_UNSUPPORTED,
+ FAILURE_BUSY,
+ FAILURE_DISCONNECTING,
+ FAILURE
+};
+
+std::ostream& operator<<(std::ostream& os, const BluetoothAudioCtrlAck& ack);
+
+inline BluetoothAudioStatus BluetoothAudioCtrlAckToHalStatus(
+ const BluetoothAudioCtrlAck& ack) {
+ switch (ack) {
+ case BluetoothAudioCtrlAck::SUCCESS_FINISHED:
+ return BluetoothAudioStatus::SUCCESS;
+ case BluetoothAudioCtrlAck::FAILURE_UNSUPPORTED:
+ return BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION;
+ case BluetoothAudioCtrlAck::PENDING:
+ return BluetoothAudioStatus::FAILURE;
+ case BluetoothAudioCtrlAck::FAILURE_BUSY:
+ return BluetoothAudioStatus::FAILURE;
+ case BluetoothAudioCtrlAck::FAILURE_DISCONNECTING:
+ return BluetoothAudioStatus::FAILURE;
+ default:
+ return BluetoothAudioStatus::FAILURE;
+ }
+}
+
+// An IBluetoothTransportInstance needs to be implemented by a Bluetooth audio
+// transport, such as A2DP or Hearing Aid, to handle callbacks from Audio HAL.
+class IBluetoothTransportInstance {
+ public:
+ IBluetoothTransportInstance(SessionType sessionType,
+ AudioConfiguration audioConfig)
+ : session_type_(sessionType), audio_config_(std::move(audioConfig)){};
+ virtual ~IBluetoothTransportInstance() = default;
+
+ SessionType GetSessionType() const { return session_type_; }
+
+ AudioConfiguration GetAudioConfiguration() const { return audio_config_; }
+
+ void UpdateAudioConfiguration(const AudioConfiguration& audio_config) {
+ audio_config_ = audio_config;
+ }
+
+ virtual BluetoothAudioCtrlAck StartRequest() = 0;
+
+ virtual BluetoothAudioCtrlAck SuspendRequest() = 0;
+
+ virtual void StopRequest() = 0;
+
+ virtual bool GetPresentationPosition(uint64_t* remote_delay_report_ns,
+ uint64_t* total_bytes_readed,
+ timespec* data_position) = 0;
+
+ virtual void MetadataChanged(const source_metadata_t& source_metadata) = 0;
+
+ // Invoked when the transport is requested to reset presentation position
+ virtual void ResetPresentationPosition() = 0;
+
+ // Invoked when the transport is requested to log bytes read
+ virtual void LogBytesRead(size_t bytes_readed) = 0;
+
+ private:
+ const SessionType session_type_;
+ AudioConfiguration audio_config_;
+};
+
+// common object is shared between different kind of SessionType
+class BluetoothAudioDeathRecipient;
+
+// The client interface connects an IBluetoothTransportInstance to
+// IBluetoothAudioProvider and helps to route callbacks to
+// IBluetoothTransportInstance
+class BluetoothAudioClientInterface {
+ public:
+ // Constructs an BluetoothAudioClientInterface to communicate to
+ // BluetoothAudio HAL. |sink| is the implementation for the transport, and
+ // |message_loop| is the thread where callbacks are invoked.
+ BluetoothAudioClientInterface(
+ IBluetoothTransportInstance* sink,
+ bluetooth::common::MessageLoopThread* message_loop);
+
+ ~BluetoothAudioClientInterface();
+
+ bool IsValid() const {
+ return provider_ != nullptr;
+ }
+
+ std::vector<AudioCapabilities> GetAudioCapabilities() const;
+
+ bool UpdateAudioConfig(const AudioConfiguration& audioConfig);
+
+ int StartSession();
+
+ void StreamStarted(const BluetoothAudioCtrlAck& ack);
+
+ void StreamSuspended(const BluetoothAudioCtrlAck& ack);
+
+ int EndSession();
+
+ // Read data from audio HAL through fmq
+ size_t ReadAudioData(uint8_t* p_buf, uint32_t len);
+
+ // Write data to audio HAL through fmq
+ size_t WriteAudioData(uint8_t* p_buf, uint32_t len);
+
+ // Renew the connection and usually is used when HIDL restarted
+ void RenewAudioProviderAndSession();
+
+ static constexpr PcmParameters kInvalidPcmConfiguration = {
+ .sampleRate = SampleRate::RATE_UNKNOWN,
+ .bitsPerSample = BitsPerSample::BITS_UNKNOWN,
+ .channelMode = ChannelMode::UNKNOWN};
+
+ private:
+ // Helper function to connect to an IBluetoothAudioProvider
+ void fetch_audio_provider();
+
+ mutable std::mutex internal_mutex_;
+ IBluetoothTransportInstance* sink_;
+ android::sp<IBluetoothAudioProvider> provider_;
+ std::vector<AudioCapabilities> capabilities_;
+ bool session_started_;
+ std::unique_ptr<::android::hardware::MessageQueue<
+ uint8_t, ::android::hardware::kSynchronizedReadWrite>>
+ mDataMQ;
+ android::sp<BluetoothAudioDeathRecipient> death_recipient_;
+};
+
+} // namespace audio
+} // namespace bluetooth
diff --git a/audio_hal_interface/client_interface_unittest.cc b/audio_hal_interface/client_interface_unittest.cc
new file mode 100644
index 0000000..fd8c8dc
--- /dev/null
+++ b/audio_hal_interface/client_interface_unittest.cc
@@ -0,0 +1,474 @@
+/*
+ * Copyright 2019 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 <gtest/gtest.h>
+
+#include "client_interface.h"
+
+namespace {
+
+using ::android::hardware::bluetooth::audio::V2_0::AacObjectType;
+using ::android::hardware::bluetooth::audio::V2_0::AacParameters;
+using ::android::hardware::bluetooth::audio::V2_0::AacVariableBitRate;
+using ::android::hardware::bluetooth::audio::V2_0::AptxParameters;
+using ::android::hardware::bluetooth::audio::V2_0::CodecCapabilities;
+using ::android::hardware::bluetooth::audio::V2_0::CodecConfiguration;
+using ::android::hardware::bluetooth::audio::V2_0::CodecType;
+using ::android::hardware::bluetooth::audio::V2_0::LdacChannelMode;
+using ::android::hardware::bluetooth::audio::V2_0::LdacParameters;
+using ::android::hardware::bluetooth::audio::V2_0::LdacQualityIndex;
+using ::android::hardware::bluetooth::audio::V2_0::SbcAllocMethod;
+using ::android::hardware::bluetooth::audio::V2_0::SbcBlockLength;
+using ::android::hardware::bluetooth::audio::V2_0::SbcChannelMode;
+using ::android::hardware::bluetooth::audio::V2_0::SbcNumSubbands;
+using ::android::hardware::bluetooth::audio::V2_0::SbcParameters;
+
+using ::bluetooth::audio::AudioCapabilities;
+using ::bluetooth::audio::AudioConfiguration;
+using ::bluetooth::audio::BitsPerSample;
+using ::bluetooth::audio::BluetoothAudioClientInterface;
+using ::bluetooth::audio::BluetoothAudioStatus;
+using ::bluetooth::audio::ChannelMode;
+using ::bluetooth::audio::PcmParameters;
+using ::bluetooth::audio::SampleRate;
+using ::bluetooth::audio::SessionType;
+using ::testing::Test;
+
+constexpr SampleRate kSampleRates[9] = {
+ SampleRate::RATE_UNKNOWN, SampleRate::RATE_44100, SampleRate::RATE_48000,
+ SampleRate::RATE_88200, SampleRate::RATE_96000, SampleRate::RATE_176400,
+ SampleRate::RATE_192000, SampleRate::RATE_16000, SampleRate::RATE_24000};
+constexpr BitsPerSample kBitsPerSamples[4] = {
+ BitsPerSample::BITS_UNKNOWN, BitsPerSample::BITS_16, BitsPerSample::BITS_24,
+ BitsPerSample::BITS_32};
+constexpr ChannelMode kChannelModes[3] = {
+ ChannelMode::UNKNOWN, ChannelMode::MONO, ChannelMode::STEREO};
+constexpr uint16_t kPeerMtus[5] = {660, 663, 883, 1005, 1500};
+
+class TestTransport : public bluetooth::audio::IBluetoothTransportInstance {
+ private:
+ static constexpr uint64_t kRemoteDelayReportMs = 200;
+
+ public:
+ TestTransport(SessionType session_type)
+ : bluetooth::audio::IBluetoothTransportInstance(session_type, {}){};
+ bluetooth::audio::BluetoothAudioCtrlAck StartRequest() override {
+ return bluetooth::audio::BluetoothAudioCtrlAck::SUCCESS_FINISHED;
+ }
+ bluetooth::audio::BluetoothAudioCtrlAck SuspendRequest() override {
+ return bluetooth::audio::BluetoothAudioCtrlAck::SUCCESS_FINISHED;
+ }
+ void StopRequest() override {}
+ bool GetPresentationPosition(uint64_t* remote_delay_report_ns,
+ uint64_t* total_bytes_readed,
+ timespec* data_position) override {
+ if (remote_delay_report_ns) {
+ *remote_delay_report_ns = kRemoteDelayReportMs * 1000000;
+ }
+ if (total_bytes_readed) {
+ *total_bytes_readed = 0;
+ }
+ if (data_position) {
+ clock_gettime(CLOCK_MONOTONIC, data_position);
+ }
+ return true;
+ }
+ void MetadataChanged(
+ const source_metadata_t& source_metadata __unused) override {}
+ void ResetPresentationPosition() override{};
+ void LogBytesRead(size_t bytes_readed __unused) override{};
+};
+
+class BluetoothAudioClientInterfaceTest : public Test {
+ protected:
+ TestTransport* test_transport_;
+ BluetoothAudioClientInterface* clientif_;
+
+ static constexpr int kClientIfReturnSuccess = 0;
+
+ void SetUp() override {}
+
+ void TearDown() override {
+ clientif_ = nullptr;
+ test_transport_ = nullptr;
+ }
+
+ bool IsSoftwarePcmParametersSupported(const PcmParameters& pcm_config) {
+ const std::vector<AudioCapabilities>& capabilities =
+ clientif_->GetAudioCapabilities();
+ PcmParameters pcm_capabilities = capabilities[0].pcmCapabilities();
+ bool is_pcm_config_valid =
+ (pcm_config.sampleRate != SampleRate::RATE_UNKNOWN &&
+ pcm_config.bitsPerSample != BitsPerSample::BITS_UNKNOWN &&
+ pcm_config.channelMode != ChannelMode::UNKNOWN);
+ bool is_pcm_config_supported =
+ (pcm_config.sampleRate & pcm_capabilities.sampleRate &&
+ pcm_config.bitsPerSample & pcm_capabilities.bitsPerSample &&
+ pcm_config.channelMode & pcm_capabilities.channelMode);
+ return (is_pcm_config_valid && is_pcm_config_supported);
+ }
+
+ bool IsOffloadCodecConfigurationSupported(
+ const CodecConfiguration& codec_config) {
+ CodecCapabilities codec_capability = {};
+ for (auto audio_capability : clientif_->GetAudioCapabilities()) {
+ if (audio_capability.codecCapabilities().codecType ==
+ codec_config.codecType) {
+ codec_capability = audio_capability.codecCapabilities();
+ }
+ }
+ if (codec_capability.codecType != codec_config.codecType) {
+ // codec is unsupported
+ return false;
+ }
+ bool is_codec_config_supported = false;
+ switch (codec_config.codecType) {
+ case CodecType::SBC: {
+ SbcParameters sbc_config = codec_config.config.sbcConfig();
+ SbcParameters sbc_capability =
+ codec_capability.capabilities.sbcCapabilities();
+ is_codec_config_supported =
+ (sbc_config.sampleRate & sbc_capability.sampleRate &&
+ sbc_config.channelMode & sbc_capability.channelMode &&
+ sbc_config.blockLength & sbc_capability.blockLength &&
+ sbc_config.numSubbands & sbc_capability.numSubbands &&
+ sbc_config.allocMethod & sbc_capability.allocMethod &&
+ sbc_config.bitsPerSample & sbc_capability.bitsPerSample &&
+ (sbc_capability.minBitpool <= sbc_config.minBitpool &&
+ sbc_config.minBitpool <= sbc_config.maxBitpool &&
+ sbc_config.maxBitpool <= sbc_capability.maxBitpool));
+ return is_codec_config_supported;
+ }
+ case CodecType::AAC: {
+ AacParameters aac_config = codec_config.config.aacConfig();
+ AacParameters aac_capability =
+ codec_capability.capabilities.aacCapabilities();
+ is_codec_config_supported =
+ (aac_config.objectType & aac_capability.objectType &&
+ aac_config.sampleRate & aac_capability.sampleRate &&
+ aac_config.channelMode & aac_capability.channelMode &&
+ (aac_config.variableBitRateEnabled ==
+ AacVariableBitRate::DISABLED ||
+ aac_capability.variableBitRateEnabled ==
+ AacVariableBitRate::ENABLED) &&
+ aac_config.bitsPerSample & aac_capability.bitsPerSample);
+ return is_codec_config_supported;
+ }
+ case CodecType::LDAC: {
+ LdacParameters ldac_config = codec_config.config.ldacConfig();
+ LdacParameters ldac_capability =
+ codec_capability.capabilities.ldacCapabilities();
+ is_codec_config_supported =
+ (ldac_config.sampleRate & ldac_capability.sampleRate &&
+ ldac_config.channelMode & ldac_capability.channelMode &&
+ ldac_config.bitsPerSample & ldac_capability.bitsPerSample);
+ return is_codec_config_supported;
+ }
+ case CodecType::APTX:
+ [[fallthrough]];
+ case CodecType::APTX_HD: {
+ AptxParameters aptx_config = codec_config.config.aptxConfig();
+ AptxParameters aptx_capability =
+ codec_capability.capabilities.aptxCapabilities();
+ is_codec_config_supported =
+ (aptx_config.sampleRate & aptx_capability.sampleRate &&
+ aptx_config.channelMode & aptx_capability.channelMode &&
+ aptx_config.bitsPerSample & aptx_capability.bitsPerSample);
+ return is_codec_config_supported;
+ }
+ case CodecType::UNKNOWN:
+ return false;
+ }
+ }
+};
+
+} // namespace
+
+TEST_F(BluetoothAudioClientInterfaceTest, StartAndEndA2dpSoftwareSession) {
+ test_transport_ =
+ new TestTransport(SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH);
+ clientif_ = new BluetoothAudioClientInterface(test_transport_, nullptr);
+ AudioConfiguration audio_config = {};
+ PcmParameters pcm_config = {};
+ for (auto sample_rate : kSampleRates) {
+ pcm_config.sampleRate = sample_rate;
+ for (auto bits_per_sample : kBitsPerSamples) {
+ pcm_config.bitsPerSample = bits_per_sample;
+ for (auto channel_mode : kChannelModes) {
+ pcm_config.channelMode = channel_mode;
+ audio_config.pcmConfig(pcm_config);
+ clientif_->UpdateAudioConfig(audio_config);
+ if (IsSoftwarePcmParametersSupported(pcm_config)) {
+ EXPECT_EQ(clientif_->StartSession(), kClientIfReturnSuccess);
+ } else {
+ EXPECT_NE(clientif_->StartSession(), kClientIfReturnSuccess);
+ }
+ EXPECT_EQ(clientif_->EndSession(), kClientIfReturnSuccess);
+ } // ChannelMode
+ } // BitsPerSampple
+ } // SampleRate
+}
+
+TEST_F(BluetoothAudioClientInterfaceTest, StartAndEndA2dpOffloadSbcSession) {
+ test_transport_ =
+ new TestTransport(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
+ clientif_ = new BluetoothAudioClientInterface(test_transport_, nullptr);
+ AudioConfiguration audio_config = {};
+ CodecConfiguration codec_config = {};
+ SbcBlockLength block_lengths[4] = {
+ SbcBlockLength::BLOCKS_4, SbcBlockLength::BLOCKS_8,
+ SbcBlockLength::BLOCKS_12, SbcBlockLength::BLOCKS_16};
+ SbcNumSubbands num_subbands[2] = {SbcNumSubbands::SUBBAND_4,
+ SbcNumSubbands::SUBBAND_8};
+ SbcAllocMethod alloc_methods[2] = {SbcAllocMethod::ALLOC_MD_S,
+ SbcAllocMethod::ALLOC_MD_L};
+ for (auto sample_rate : kSampleRates) {
+ for (auto bits_per_sample : kBitsPerSamples) {
+ for (auto channel_mode : kChannelModes) {
+ for (auto peer_mtu : kPeerMtus) {
+ for (auto block_length : block_lengths) {
+ for (auto num_subband : num_subbands) {
+ for (auto alloc_method : alloc_methods) {
+ codec_config.codecType = CodecType::SBC;
+ codec_config.peerMtu = peer_mtu;
+ codec_config.isScmstEnabled = false;
+ // A2DP_SBC_DEFAULT_BITRATE
+ codec_config.encodedAudioBitrate = 328000;
+ SbcParameters sbc = {
+ .sampleRate = sample_rate,
+ .channelMode = (channel_mode == ChannelMode::MONO
+ ? SbcChannelMode::MONO
+ : SbcChannelMode::JOINT_STEREO),
+ .blockLength = block_length,
+ .numSubbands = num_subband,
+ .allocMethod = alloc_method,
+ .bitsPerSample = bits_per_sample,
+ .minBitpool = 2,
+ .maxBitpool = 53};
+ codec_config.config.sbcConfig(sbc);
+ audio_config.codecConfig(codec_config);
+ clientif_->UpdateAudioConfig(audio_config);
+ if (IsOffloadCodecConfigurationSupported(codec_config)) {
+ EXPECT_EQ(clientif_->StartSession(), kClientIfReturnSuccess);
+ } else {
+ EXPECT_NE(clientif_->StartSession(), kClientIfReturnSuccess);
+ }
+ EXPECT_EQ(clientif_->EndSession(), kClientIfReturnSuccess);
+ } // SbcAllocMethod
+ } // SbcNumSubbands
+ } // SbcBlockLength
+ } // peerMtu
+ } // ChannelMode
+ } // BitsPerSampple
+ } // SampleRate
+}
+
+TEST_F(BluetoothAudioClientInterfaceTest, StartAndEndA2dpOffloadAacSession) {
+ test_transport_ =
+ new TestTransport(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
+ clientif_ = new BluetoothAudioClientInterface(test_transport_, nullptr);
+ AudioConfiguration audio_config = {};
+ CodecConfiguration codec_config = {};
+ AacObjectType object_types[4] = {
+ AacObjectType::MPEG2_LC, AacObjectType::MPEG4_LC,
+ AacObjectType::MPEG4_LTP, AacObjectType::MPEG4_SCALABLE};
+ AacVariableBitRate variable_bitrates[2] = {AacVariableBitRate::DISABLED,
+ AacVariableBitRate::ENABLED};
+ for (auto sample_rate : kSampleRates) {
+ for (auto bits_per_sample : kBitsPerSamples) {
+ for (auto channel_mode : kChannelModes) {
+ for (auto peer_mtu : kPeerMtus) {
+ for (auto object_type : object_types) {
+ for (auto variable_bitrate : variable_bitrates) {
+ codec_config.codecType = CodecType::AAC;
+ codec_config.peerMtu = peer_mtu;
+ codec_config.isScmstEnabled = false;
+ // A2DP_AAC_DEFAULT_BITRATE
+ codec_config.encodedAudioBitrate = 320000;
+ AacParameters aac = {.objectType = object_type,
+ .sampleRate = sample_rate,
+ .channelMode = channel_mode,
+ .variableBitRateEnabled = variable_bitrate,
+ .bitsPerSample = bits_per_sample};
+ codec_config.config.aacConfig(aac);
+ audio_config.codecConfig(codec_config);
+ clientif_->UpdateAudioConfig(audio_config);
+ if (IsOffloadCodecConfigurationSupported(codec_config)) {
+ EXPECT_EQ(clientif_->StartSession(), kClientIfReturnSuccess);
+ } else {
+ EXPECT_NE(clientif_->StartSession(), kClientIfReturnSuccess);
+ }
+ EXPECT_EQ(clientif_->EndSession(), kClientIfReturnSuccess);
+ } // AacVariableBitRate
+ } // AacObjectType
+ } // peerMtu
+ } // ChannelMode
+ } // BitsPerSampple
+ } // SampleRate
+}
+
+TEST_F(BluetoothAudioClientInterfaceTest, StartAndEndA2dpOffloadLdacSession) {
+ test_transport_ =
+ new TestTransport(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
+ clientif_ = new BluetoothAudioClientInterface(test_transport_, nullptr);
+ AudioConfiguration audio_config = {};
+ CodecConfiguration codec_config = {};
+ LdacQualityIndex quality_indexes[4] = {
+ LdacQualityIndex::QUALITY_HIGH, LdacQualityIndex::QUALITY_MID,
+ LdacQualityIndex::QUALITY_LOW, LdacQualityIndex::QUALITY_ABR};
+ for (auto sample_rate : kSampleRates) {
+ for (auto bits_per_sample : kBitsPerSamples) {
+ for (auto channel_mode : kChannelModes) {
+ for (auto peer_mtu : kPeerMtus) {
+ for (auto quality_index : quality_indexes) {
+ codec_config.codecType = CodecType::LDAC;
+ codec_config.peerMtu = peer_mtu;
+ codec_config.isScmstEnabled = false;
+ codec_config.encodedAudioBitrate = 990000;
+ LdacParameters ldac = {
+ .sampleRate = sample_rate,
+ .channelMode = (channel_mode == ChannelMode::MONO
+ ? LdacChannelMode::MONO
+ : LdacChannelMode::STEREO),
+ .qualityIndex = quality_index,
+ .bitsPerSample = bits_per_sample};
+ codec_config.config.ldacConfig(ldac);
+ audio_config.codecConfig(codec_config);
+ clientif_->UpdateAudioConfig(audio_config);
+ if (IsOffloadCodecConfigurationSupported(codec_config)) {
+ EXPECT_EQ(clientif_->StartSession(), kClientIfReturnSuccess);
+ } else {
+ EXPECT_NE(clientif_->StartSession(), kClientIfReturnSuccess);
+ }
+ EXPECT_EQ(clientif_->EndSession(), kClientIfReturnSuccess);
+ } // LdacQualityIndex
+ } // peerMtu
+ } // ChannelMode
+ } // BitsPerSampple
+ } // SampleRate
+}
+
+TEST_F(BluetoothAudioClientInterfaceTest, StartAndEndA2dpOffloadAptxSession) {
+ test_transport_ =
+ new TestTransport(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
+ clientif_ = new BluetoothAudioClientInterface(test_transport_, nullptr);
+ AudioConfiguration audio_config = {};
+ CodecConfiguration codec_config = {};
+ for (auto sample_rate : kSampleRates) {
+ for (auto bits_per_sample : kBitsPerSamples) {
+ for (auto channel_mode : kChannelModes) {
+ for (auto peer_mtu : kPeerMtus) {
+ codec_config.codecType = CodecType::APTX;
+ codec_config.peerMtu = peer_mtu;
+ codec_config.isScmstEnabled = false;
+ codec_config.encodedAudioBitrate = 352000;
+ AptxParameters aptx = {.sampleRate = sample_rate,
+ .channelMode = channel_mode,
+ .bitsPerSample = bits_per_sample};
+ codec_config.config.aptxConfig(aptx);
+ audio_config.codecConfig(codec_config);
+ clientif_->UpdateAudioConfig(audio_config);
+ if (IsOffloadCodecConfigurationSupported(codec_config)) {
+ EXPECT_EQ(clientif_->StartSession(), kClientIfReturnSuccess);
+ } else {
+ EXPECT_NE(clientif_->StartSession(), kClientIfReturnSuccess);
+ }
+ EXPECT_EQ(clientif_->EndSession(), kClientIfReturnSuccess);
+ } // peerMtu
+ } // ChannelMode
+ } // BitsPerSampple
+ } // SampleRate
+}
+
+TEST_F(BluetoothAudioClientInterfaceTest, StartAndEndA2dpOffloadAptxHdSession) {
+ test_transport_ =
+ new TestTransport(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
+ clientif_ = new BluetoothAudioClientInterface(test_transport_, nullptr);
+ AudioConfiguration audio_config = {};
+ CodecConfiguration codec_config = {};
+ for (auto sample_rate : kSampleRates) {
+ for (auto bits_per_sample : kBitsPerSamples) {
+ for (auto channel_mode : kChannelModes) {
+ for (auto peer_mtu : kPeerMtus) {
+ codec_config.codecType = CodecType::APTX_HD;
+ codec_config.peerMtu = peer_mtu;
+ codec_config.isScmstEnabled = false;
+ codec_config.encodedAudioBitrate = 576000;
+ AptxParameters aptx = {.sampleRate = sample_rate,
+ .channelMode = channel_mode,
+ .bitsPerSample = bits_per_sample};
+ codec_config.config.aptxConfig(aptx);
+ audio_config.codecConfig(codec_config);
+ clientif_->UpdateAudioConfig(audio_config);
+ if (IsOffloadCodecConfigurationSupported(codec_config)) {
+ EXPECT_EQ(clientif_->StartSession(), kClientIfReturnSuccess);
+ } else {
+ EXPECT_NE(clientif_->StartSession(), kClientIfReturnSuccess);
+ }
+ EXPECT_EQ(clientif_->EndSession(), kClientIfReturnSuccess);
+ } // peerMtu
+ } // ChannelMode
+ } // BitsPerSampple
+ } // SampleRate
+}
+
+TEST_F(BluetoothAudioClientInterfaceTest,
+ StartAndEndA2dpOffloadUnknownSession) {
+ test_transport_ =
+ new TestTransport(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
+ clientif_ = new BluetoothAudioClientInterface(test_transport_, nullptr);
+ AudioConfiguration audio_config = {};
+ CodecConfiguration codec_config = {};
+ codec_config.codecType = CodecType::UNKNOWN;
+ codec_config.peerMtu = 1005;
+ codec_config.isScmstEnabled = false;
+ codec_config.encodedAudioBitrate = 328000;
+ codec_config.config = {};
+ audio_config.codecConfig(codec_config);
+ clientif_->UpdateAudioConfig(audio_config);
+ if (IsOffloadCodecConfigurationSupported(codec_config)) {
+ EXPECT_EQ(clientif_->StartSession(), kClientIfReturnSuccess);
+ } else {
+ EXPECT_NE(clientif_->StartSession(), kClientIfReturnSuccess);
+ }
+ EXPECT_EQ(clientif_->EndSession(), kClientIfReturnSuccess);
+}
+
+TEST_F(BluetoothAudioClientInterfaceTest,
+ StartAndEndHearingAidSoftwareSession) {
+ test_transport_ =
+ new TestTransport(SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH);
+ clientif_ = new BluetoothAudioClientInterface(test_transport_, nullptr);
+ AudioConfiguration audio_config = {};
+ PcmParameters pcm_config = {};
+ for (auto sample_rate : kSampleRates) {
+ pcm_config.sampleRate = sample_rate;
+ for (auto bits_per_sample : kBitsPerSamples) {
+ pcm_config.bitsPerSample = bits_per_sample;
+ for (auto channel_mode : kChannelModes) {
+ pcm_config.channelMode = channel_mode;
+ audio_config.pcmConfig(pcm_config);
+ clientif_->UpdateAudioConfig(audio_config);
+ if (IsSoftwarePcmParametersSupported(pcm_config)) {
+ EXPECT_EQ(clientif_->StartSession(), kClientIfReturnSuccess);
+ } else {
+ EXPECT_NE(clientif_->StartSession(), kClientIfReturnSuccess);
+ }
+ EXPECT_EQ(clientif_->EndSession(), kClientIfReturnSuccess);
+ } // ChannelMode
+ } // BitsPerSampple
+ } // SampleRate
+}
diff --git a/audio_hal_interface/hearing_aid_software_encoding.cc b/audio_hal_interface/hearing_aid_software_encoding.cc
new file mode 100644
index 0000000..5107d46
--- /dev/null
+++ b/audio_hal_interface/hearing_aid_software_encoding.cc
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2019 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 "BTAudioClientHearingAid"
+
+#include "hearing_aid_software_encoding.h"
+#include "client_interface.h"
+
+#include "audio_hearing_aid_hw/include/audio_hearing_aid_hw.h"
+#include "osi/include/log.h"
+#include "osi/include/properties.h"
+
+namespace {
+
+using ::android::hardware::bluetooth::audio::V2_0::CodecType;
+using ::bluetooth::audio::AudioConfiguration;
+using ::bluetooth::audio::BitsPerSample;
+using ::bluetooth::audio::BluetoothAudioCtrlAck;
+using ::bluetooth::audio::ChannelMode;
+using ::bluetooth::audio::PcmParameters;
+using ::bluetooth::audio::SampleRate;
+using ::bluetooth::audio::SessionType;
+using ::bluetooth::audio::hearing_aid::StreamCallbacks;
+
+// Transport implementation for Hearing Aids
+class HearingAidTransport
+ : public bluetooth::audio::IBluetoothTransportInstance {
+ public:
+ HearingAidTransport(StreamCallbacks stream_cb)
+ : IBluetoothTransportInstance(
+ SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH, {}),
+ stream_cb_(std::move(stream_cb)),
+ remote_delay_report_ms_(0),
+ total_bytes_read_(0),
+ data_position_({}){};
+
+ BluetoothAudioCtrlAck StartRequest() override {
+ LOG(INFO) << __func__;
+ if (stream_cb_.on_resume_(true)) {
+ return BluetoothAudioCtrlAck::SUCCESS_FINISHED;
+ }
+ return BluetoothAudioCtrlAck::FAILURE;
+ }
+
+ BluetoothAudioCtrlAck SuspendRequest() override {
+ LOG(INFO) << __func__;
+ if (stream_cb_.on_suspend_()) {
+ uint8_t p_buf[AUDIO_STREAM_OUTPUT_BUFFER_SZ * 2];
+ ::bluetooth::audio::hearing_aid::read(p_buf, sizeof(p_buf));
+ return BluetoothAudioCtrlAck::SUCCESS_FINISHED;
+ } else {
+ return BluetoothAudioCtrlAck::FAILURE;
+ }
+ }
+
+ void StopRequest() override {
+ LOG(INFO) << __func__;
+ if (stream_cb_.on_suspend_()) {
+ // flush
+ uint8_t p_buf[AUDIO_STREAM_OUTPUT_BUFFER_SZ * 2];
+ ::bluetooth::audio::hearing_aid::read(p_buf, sizeof(p_buf));
+ }
+ }
+
+ bool GetPresentationPosition(uint64_t* remote_delay_report_ns,
+ uint64_t* total_bytes_read,
+ timespec* data_position) override {
+ VLOG(2) << __func__ << ": data=" << total_bytes_read_
+ << " byte(s), timestamp=" << data_position_.tv_sec << "."
+ << data_position_.tv_nsec
+ << "s, delay report=" << remote_delay_report_ms_ << " msec.";
+ if (remote_delay_report_ns != nullptr) {
+ *remote_delay_report_ns = remote_delay_report_ms_ * 1000000u;
+ }
+ if (total_bytes_read != nullptr) *total_bytes_read = total_bytes_read_;
+ if (data_position != nullptr) *data_position = data_position_;
+
+ return true;
+ }
+
+ void MetadataChanged(const source_metadata_t& source_metadata) override {
+ auto track_count = source_metadata.track_count;
+ auto tracks = source_metadata.tracks;
+ LOG(INFO) << __func__ << ": " << track_count << " track(s) received";
+ while (track_count) {
+ VLOG(1) << __func__ << ": usage=" << tracks->usage
+ << ", content_type=" << tracks->content_type
+ << ", gain=" << tracks->gain;
+ --track_count;
+ ++tracks;
+ }
+ }
+
+ void ResetPresentationPosition() override {
+ VLOG(2) << __func__ << ": called.";
+ remote_delay_report_ms_ = 0;
+ total_bytes_read_ = 0;
+ data_position_ = {};
+ }
+
+ void LogBytesRead(size_t bytes_read) override {
+ if (bytes_read) {
+ total_bytes_read_ += bytes_read;
+ clock_gettime(CLOCK_MONOTONIC, &data_position_);
+ }
+ }
+
+ void SetRemoteDelay(uint16_t delay_report_ms) {
+ LOG(INFO) << __func__ << ": delay_report=" << delay_report_ms << " msec";
+ remote_delay_report_ms_ = delay_report_ms;
+ }
+
+ private:
+ StreamCallbacks stream_cb_;
+ uint16_t remote_delay_report_ms_;
+ uint64_t total_bytes_read_;
+ timespec data_position_;
+};
+
+bool HearingAidGetSelectedHalPcmConfig(PcmParameters* hal_pcm_config) {
+ if (hal_pcm_config == nullptr) return false;
+ // TODO: we only support one config for now!
+ hal_pcm_config->sampleRate = SampleRate::RATE_16000;
+ hal_pcm_config->bitsPerSample = BitsPerSample::BITS_16;
+ hal_pcm_config->channelMode = ChannelMode::STEREO;
+ return true;
+}
+
+// Sink instance of Hearing Aids to provide call-in APIs for Bluetooth Audio Hal
+HearingAidTransport* hearing_aid_sink = nullptr;
+// Common interface to call-out into Bluetooth Audio Hal
+bluetooth::audio::BluetoothAudioClientInterface*
+ hearing_aid_hal_clientinterface = nullptr;
+bool btaudio_hearing_aid_disabled = false;
+bool is_configured = false;
+
+// Save the value if the remote reports its delay before hearing_aid_sink is
+// initialized
+uint16_t remote_delay_ms = 0;
+
+bool is_hal_2_0_force_disabled() {
+ if (!is_configured) {
+ btaudio_hearing_aid_disabled = osi_property_get_bool(BLUETOOTH_AUDIO_HAL_PROP_DISABLED, false);
+ is_configured = true;
+ }
+ return btaudio_hearing_aid_disabled;
+}
+
+} // namespace
+
+namespace bluetooth {
+namespace audio {
+namespace hearing_aid {
+
+bool is_hal_2_0_enabled() { return hearing_aid_hal_clientinterface != nullptr; }
+
+bool init(StreamCallbacks stream_cb,
+ bluetooth::common::MessageLoopThread* message_loop) {
+ LOG(INFO) << __func__;
+
+ if (is_hal_2_0_force_disabled()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudio HAL is disabled";
+ return false;
+ }
+
+ hearing_aid_sink = new HearingAidTransport(std::move(stream_cb));
+ hearing_aid_hal_clientinterface =
+ new bluetooth::audio::BluetoothAudioClientInterface(hearing_aid_sink,
+ message_loop);
+ if (!hearing_aid_hal_clientinterface->IsValid()) {
+ LOG(WARNING) << __func__ << ": BluetoothAudio HAL for Hearing Aid is invalid?!";
+ delete hearing_aid_hal_clientinterface;
+ hearing_aid_hal_clientinterface = nullptr;
+ delete hearing_aid_sink;
+ hearing_aid_sink = nullptr;
+ return false;
+ }
+
+ if (remote_delay_ms != 0) {
+ LOG(INFO) << __func__ << ": restore DELAY " << remote_delay_ms << " ms";
+ hearing_aid_sink->SetRemoteDelay(remote_delay_ms);
+ remote_delay_ms = 0;
+ }
+
+ return true;
+}
+
+void cleanup() {
+ LOG(INFO) << __func__;
+ if (!is_hal_2_0_enabled()) return;
+ end_session();
+ delete hearing_aid_hal_clientinterface;
+ hearing_aid_hal_clientinterface = nullptr;
+ delete hearing_aid_sink;
+ hearing_aid_sink = nullptr;
+ remote_delay_ms = 0;
+}
+
+void start_session() {
+ LOG(INFO) << __func__;
+ if (!is_hal_2_0_enabled()) return;
+ AudioConfiguration audio_config;
+ PcmParameters pcm_config{};
+ if (!HearingAidGetSelectedHalPcmConfig(&pcm_config)) {
+ LOG(ERROR) << __func__ << ": cannot get PCM config";
+ return;
+ }
+ audio_config.pcmConfig(pcm_config);
+ if (!hearing_aid_hal_clientinterface->UpdateAudioConfig(audio_config)) {
+ LOG(ERROR) << __func__ << ": cannot update audio config to HAL";
+ return;
+ }
+ hearing_aid_hal_clientinterface->StartSession();
+}
+
+void end_session() {
+ LOG(INFO) << __func__;
+ if (!is_hal_2_0_enabled()) return;
+ hearing_aid_hal_clientinterface->EndSession();
+}
+
+size_t read(uint8_t* p_buf, uint32_t len) {
+ if (!is_hal_2_0_enabled()) return 0;
+ return hearing_aid_hal_clientinterface->ReadAudioData(p_buf, len);
+}
+
+// Update Hearing Aids delay report to BluetoothAudio HAL
+void set_remote_delay(uint16_t delay_report_ms) {
+ if (!is_hal_2_0_enabled()) {
+ LOG(INFO) << __func__ << ": not ready for DelayReport " << delay_report_ms
+ << " ms";
+ remote_delay_ms = delay_report_ms;
+ return;
+ }
+ LOG(INFO) << __func__ << ": delay_report_ms=" << delay_report_ms << " ms";
+ hearing_aid_sink->SetRemoteDelay(delay_report_ms);
+}
+
+} // namespace hearing_aid
+} // namespace audio
+} // namespace bluetooth
diff --git a/audio_hal_interface/hearing_aid_software_encoding.h b/audio_hal_interface/hearing_aid_software_encoding.h
new file mode 100644
index 0000000..8a64fcd
--- /dev/null
+++ b/audio_hal_interface/hearing_aid_software_encoding.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 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 "common/message_loop_thread.h"
+
+namespace bluetooth {
+namespace audio {
+namespace hearing_aid {
+
+struct StreamCallbacks {
+ std::function<bool(bool start_media_task)> on_resume_;
+ std::function<bool(void)> on_suspend_;
+};
+
+// Check if new bluetooth_audio is enabled
+bool is_hal_2_0_enabled();
+
+// Initialize BluetoothAudio HAL: openProvider
+bool init(StreamCallbacks stream_cb,
+ bluetooth::common::MessageLoopThread* message_loop);
+
+// Clean up BluetoothAudio HAL
+void cleanup();
+
+// Send command to the BluetoothAudio HAL: StartSession, EndSession
+void start_session();
+void end_session();
+
+void set_remote_delay(uint16_t delay_report_ms);
+
+// Read from the FMQ of BluetoothAudio HAL
+size_t read(uint8_t* p_buf, uint32_t len);
+
+} // namespace hearing_aid
+} // namespace audio
+} // namespace bluetooth
diff --git a/audio_hearing_aid_hw/Android.bp b/audio_hearing_aid_hw/Android.bp
index 229fc25..4ed9e76 100644
--- a/audio_hearing_aid_hw/Android.bp
+++ b/audio_hearing_aid_hw/Android.bp
@@ -5,7 +5,7 @@
"system/bt",
"system/bt/include",
"system/bt/audio_hearing_aid_hw/include",
- ]
+ ],
}
// Audio A2DP shared library for target
diff --git a/audio_hearing_aid_hw/src/audio_hearing_aid_hw.cc b/audio_hearing_aid_hw/src/audio_hearing_aid_hw.cc
index f3f535e..cac7302 100644
--- a/audio_hearing_aid_hw/src/audio_hearing_aid_hw.cc
+++ b/audio_hearing_aid_hw/src/audio_hearing_aid_hw.cc
@@ -693,8 +693,8 @@
codec_config.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32;
break;
case AUDIO_FORMAT_PCM_8_24_BIT:
- // FALLTHROUGH
- // All 24-bit audio is expected in AUDIO_FORMAT_PCM_24_BIT_PACKED format
+ // All 24-bit audio is expected in AUDIO_FORMAT_PCM_24_BIT_PACKED format
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
default:
ERROR("Invalid audio format: 0x%x", common->cfg.format);
return -1;
diff --git a/binder/Android.bp b/binder/Android.bp
index 18428c2..9e1695c 100644
--- a/binder/Android.bp
+++ b/binder/Android.bp
@@ -8,9 +8,8 @@
srcs: [
"android/bluetooth/bluetooth_device.cc",
"android/bluetooth/IBluetoothSocketManager.aidl",
- "android/os/parcel_file_descriptor.cc",
"android/os/parcel_uuid.cc",
-/* TODO: Uncomment this files as they get converted one-by-one into native implementation
+ /* TODO: Uncomment this files as they get converted one-by-one into native implementation
"android/bluetooth/IBluetooth.aidl",
"android/bluetooth/IBluetoothA2dp.aidl",
"android/bluetooth/IBluetoothA2dpSink.aidl",
@@ -20,8 +19,6 @@
"android/bluetooth/IBluetoothProfileServiceConnection.aidl",
"android/bluetooth/IBluetoothHeadset.aidl",
"android/bluetooth/IBluetoothHeadsetPhone.aidl",
- "android/bluetooth/IBluetoothHealth.aidl",
- "android/bluetooth/IBluetoothHealthCallback.aidl",
"android/bluetooth/IBluetoothHearingAid.aidl",
"android/bluetooth/IBluetoothHidHost.aidl",
"android/bluetooth/IBluetoothPan.aidl",
@@ -38,19 +35,20 @@
"android/bluetooth/IBluetoothHidDeviceCallback.aidl",
"android/bluetooth/IBluetoothGatt.aidl",
"android/bluetooth/IBluetoothGattCallback.aidl",
+ "android/bluetooth/IBluetoothMetadataListener.aidl",
"android/bluetooth/IBluetoothGattServerCallback.aidl",
"android/bluetooth/le/IAdvertisingSetCallback.aidl",
"android/bluetooth/le/IPeriodicAdvertisingCallback.aidl",
"android/bluetooth/le/IScannerCallback.aidl"
-*/
- ],
- export_include_dirs: [ "./"],
+ */
+ ],
+ export_include_dirs: ["./"],
aidl: {
export_aidl_headers: true,
include_dirs: [
"frameworks/native/aidl/binder",
- /* required for android.os.ParcelUuid, and android.os.ParcelFileDescriptor */
+ /* required for android.os.ParcelUuid, and android.os.ParcelFileDescriptor */
"frameworks/base/core/java",
"system/bt/binder",
],
@@ -93,8 +91,6 @@
"android/bluetooth/IBluetoothProfileServiceConnection.aidl",
"android/bluetooth/IBluetoothHeadset.aidl",
"android/bluetooth/IBluetoothHeadsetPhone.aidl",
- "android/bluetooth/IBluetoothHealth.aidl",
- "android/bluetooth/IBluetoothHealthCallback.aidl",
"android/bluetooth/IBluetoothHearingAid.aidl",
"android/bluetooth/IBluetoothHidHost.aidl",
"android/bluetooth/IBluetoothPan.aidl",
@@ -112,6 +108,7 @@
"android/bluetooth/IBluetoothHidDeviceCallback.aidl",
"android/bluetooth/IBluetoothGatt.aidl",
"android/bluetooth/IBluetoothGattCallback.aidl",
+ "android/bluetooth/IBluetoothMetadataListener.aidl",
"android/bluetooth/IBluetoothGattServerCallback.aidl",
"android/bluetooth/le/IAdvertisingSetCallback.aidl",
"android/bluetooth/le/IPeriodicAdvertisingCallback.aidl",
diff --git a/binder/android/bluetooth/BluetoothHealthAppConfiguration.aidl b/binder/android/bluetooth/BluetoothHealthAppConfiguration.aidl
deleted file mode 100644
index bc9e54f..0000000
--- a/binder/android/bluetooth/BluetoothHealthAppConfiguration.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
-** Copyright 2011, 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.
-*/
-
-package android.bluetooth;
-
-parcelable BluetoothHealthAppConfiguration;
diff --git a/binder/android/bluetooth/IBluetooth.aidl b/binder/android/bluetooth/IBluetooth.aidl
index 90c34b0..6bda14b 100644
--- a/binder/android/bluetooth/IBluetooth.aidl
+++ b/binder/android/bluetooth/IBluetooth.aidl
@@ -17,6 +17,7 @@
package android.bluetooth;
import android.bluetooth.IBluetoothCallback;
+import android.bluetooth.IBluetoothMetadataListener;
import android.bluetooth.IBluetoothSocketManager;
import android.bluetooth.IBluetoothStateChangeCallback;
import android.bluetooth.BluetoothActivityEnergyInfo;
@@ -47,13 +48,18 @@
BluetoothClass getBluetoothClass();
boolean setBluetoothClass(in BluetoothClass bluetoothClass);
+ int getIoCapability();
+ boolean setIoCapability(int capability);
+ int getLeIoCapability();
+ boolean setLeIoCapability(int capability);
+
int getScanMode();
boolean setScanMode(int mode, int duration);
int getDiscoverableTimeout();
boolean setDiscoverableTimeout(int timeout);
- boolean startDiscovery();
+ boolean startDiscovery(String callingPackage);
boolean cancelDiscovery();
boolean isDiscovering();
long getDiscoveryEndMillis();
@@ -88,6 +94,8 @@
boolean setPairingConfirmation(in BluetoothDevice device, boolean accept);
int getPhonebookAccessPermission(in BluetoothDevice device);
+ boolean setSilenceMode(in BluetoothDevice device, boolean silence);
+ boolean getSilenceMode(in BluetoothDevice device);
boolean setPhonebookAccessPermission(in BluetoothDevice device, int value);
int getMessageAccessPermission(in BluetoothDevice device);
boolean setMessageAccessPermission(in BluetoothDevice device, int value);
@@ -115,6 +123,13 @@
int getLeMaximumAdvertisingDataLength();
BluetoothActivityEnergyInfo reportActivityInfo();
+ // For Metadata
+ boolean registerMetadataListener(in IBluetoothMetadataListener listener, in BluetoothDevice device);
+ boolean unregisterMetadataListener(in BluetoothDevice device);
+ boolean setMetadata(in BluetoothDevice device, in int key, in byte[] value);
+ byte[] getMetadata(in BluetoothDevice device, in int key);
+
+
/**
* Requests the controller activity info asynchronously.
* The implementor is expected to reply with the
diff --git a/binder/android/bluetooth/IBluetoothHeadset.aidl b/binder/android/bluetooth/IBluetoothHeadset.aidl
index f8dfb65..0f6954c 100644
--- a/binder/android/bluetooth/IBluetoothHeadset.aidl
+++ b/binder/android/bluetooth/IBluetoothHeadset.aidl
@@ -53,7 +53,7 @@
void setForceScoAudio(boolean forced);
boolean startScoUsingVirtualVoiceCall();
boolean stopScoUsingVirtualVoiceCall();
- oneway void phoneStateChanged(int numActive, int numHeld, int callState, String number, int type);
+ oneway void phoneStateChanged(int numActive, int numHeld, int callState, String number, int type, String name);
void clccResponse(int index, int direction, int status, int mode, boolean mpty,
String number, int type);
boolean setActiveDevice(in BluetoothDevice device);
diff --git a/binder/android/bluetooth/IBluetoothHealth.aidl b/binder/android/bluetooth/IBluetoothHealth.aidl
deleted file mode 100644
index a3be367..0000000
--- a/binder/android/bluetooth/IBluetoothHealth.aidl
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2012 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.
- */
-
-package android.bluetooth;
-
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHealthAppConfiguration;
-import android.bluetooth.IBluetoothHealthCallback;
-import android.os.ParcelFileDescriptor;
-
-/**
- * API for Bluetooth Health service
- *
- * {@hide}
- */
-interface IBluetoothHealth
-{
- boolean registerAppConfiguration(in BluetoothHealthAppConfiguration config,
- in IBluetoothHealthCallback callback);
- boolean unregisterAppConfiguration(in BluetoothHealthAppConfiguration config);
- boolean connectChannelToSource(in BluetoothDevice device, in BluetoothHealthAppConfiguration config);
- boolean connectChannelToSink(in BluetoothDevice device, in BluetoothHealthAppConfiguration config,
- int channelType);
- boolean disconnectChannel(in BluetoothDevice device, in BluetoothHealthAppConfiguration config, int id);
- ParcelFileDescriptor getMainChannelFd(in BluetoothDevice device, in BluetoothHealthAppConfiguration config);
- List<BluetoothDevice> getConnectedHealthDevices();
- List<BluetoothDevice> getHealthDevicesMatchingConnectionStates(in int[] states);
- int getHealthDeviceConnectionState(in BluetoothDevice device);
-}
diff --git a/binder/android/bluetooth/IBluetoothHealthCallback.aidl b/binder/android/bluetooth/IBluetoothHealthCallback.aidl
deleted file mode 100644
index ef7c191..0000000
--- a/binder/android/bluetooth/IBluetoothHealthCallback.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2011, 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.
- */
-
-package android.bluetooth;
-
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHealthAppConfiguration;
-import android.os.ParcelFileDescriptor;
-
-/**
- *@hide
- */
-interface IBluetoothHealthCallback
-{
- void onHealthAppConfigurationStatusChange(in BluetoothHealthAppConfiguration config, int status);
- void onHealthChannelStateChange(in BluetoothHealthAppConfiguration config,
- in BluetoothDevice device, int prevState, int newState, in
- ParcelFileDescriptor fd, int id);
-}
diff --git a/binder/android/bluetooth/IBluetoothManager.aidl b/binder/android/bluetooth/IBluetoothManager.aidl
index a3ec1d8..2e12700 100644
--- a/binder/android/bluetooth/IBluetoothManager.aidl
+++ b/binder/android/bluetooth/IBluetoothManager.aidl
@@ -49,5 +49,6 @@
boolean isBleScanAlwaysAvailable();
int updateBleAppCount(IBinder b, boolean enable, String packageName);
boolean isBleAppPresent();
+ boolean isHearingAidProfileSupported();
}
diff --git a/binder/android/bluetooth/IBluetoothMapClient.aidl b/binder/android/bluetooth/IBluetoothMapClient.aidl
index 7ac91e9..54e2dd7 100644
--- a/binder/android/bluetooth/IBluetoothMapClient.aidl
+++ b/binder/android/bluetooth/IBluetoothMapClient.aidl
@@ -37,4 +37,5 @@
boolean sendMessage(in BluetoothDevice device, in Uri[] contacts, in String message,
in PendingIntent sentIntent, in PendingIntent deliveryIntent);
boolean getUnreadMessages(in BluetoothDevice device);
+ int getSupportedFeatures(in BluetoothDevice device);
}
diff --git a/binder/android/bluetooth/IBluetoothMetadataListener.aidl b/binder/android/bluetooth/IBluetoothMetadataListener.aidl
new file mode 100644
index 0000000..765b128
--- /dev/null
+++ b/binder/android/bluetooth/IBluetoothMetadataListener.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2019 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.
+ */
+
+package android.bluetooth;
+
+import android.os.ParcelUuid;
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * Callback definitions for interacting with database change
+ * @hide
+ */
+oneway interface IBluetoothMetadataListener {
+ void onMetadataChanged(in BluetoothDevice devices, in int key, in byte[] value);
+}
diff --git a/binder/android/os/parcel_file_descriptor.cc b/binder/android/os/parcel_file_descriptor.cc
deleted file mode 100644
index 37bef6d..0000000
--- a/binder/android/os/parcel_file_descriptor.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-//
-// Copyright 2017, 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 "android/os/parcel_file_descriptor.h"
-#include <base/logging.h>
-
-using android::OK;
-using android::Parcel;
-using android::status_t;
-
-namespace android {
-namespace os {
-
-status_t ParcelFileDescriptor::writeToParcel(Parcel* parcel) const {
- CHECK(fd_ >= 0);
- return parcel->writeParcelFileDescriptor(fd_, takeOwnership_);
-}
-
-status_t ParcelFileDescriptor::readFromParcel(const Parcel* parcel) {
- LOG(FATAL) << "Don't know how to read ParcelFileDescriptor";
- return OK;
-}
-
-void ParcelFileDescriptor::setFileDescriptor(int fd, bool takeOwnership) {
- fd_ = fd;
- takeOwnership_ = takeOwnership;
-}
-
-} // namespace os
-} // namespace android
diff --git a/binder/android/os/parcel_file_descriptor.h b/binder/android/os/parcel_file_descriptor.h
deleted file mode 100644
index a37b49c..0000000
--- a/binder/android/os/parcel_file_descriptor.h
+++ /dev/null
@@ -1,52 +0,0 @@
-//
-// Copyright 2017, 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 <binder/Parcel.h>
-#include <binder/Parcelable.h>
-
-namespace android {
-namespace os {
-
-class ParcelFileDescriptor : public android::Parcelable {
- public:
- ParcelFileDescriptor() : fd_(-1), takeOwnership_(false) {}
- ~ParcelFileDescriptor() = default;
-
- // Write |this| parcelable to the given |parcel|. Keep in mind that
- // implementations of writeToParcel must be manually kept in sync
- // with readFromParcel and the Java equivalent versions of these methods.
- //
- // Returns android::OK on success and an appropriate error otherwise.
- android::status_t writeToParcel(android::Parcel* parcel) const override;
-
- // Read data from the given |parcel| into |this|. After readFromParcel
- // completes, |this| should have equivalent state to the object that
- // wrote itself to the parcel.
- //
- // Returns android::OK on success and an appropriate error otherwise.
- android::status_t readFromParcel(const android::Parcel* parcel) override;
-
- void setFileDescriptor(int fd, bool takeOwnership);
-
- private:
- int fd_;
- bool takeOwnership_;
-};
-
-} // namespace os
-} // namespace android
diff --git a/bta/Android.bp b/bta/Android.bp
index d6919de..0e7bfe8 100644
--- a/bta/Android.bp
+++ b/bta/Android.bp
@@ -34,6 +34,7 @@
cc_library_static {
name: "libbt-bta",
defaults: ["fluoride_bta_defaults"],
+ cflags: ["-Wno-implicit-fallthrough"],
srcs: [
"ag/bta_ag_act.cc",
"ag/bta_ag_api.cc",
@@ -68,6 +69,8 @@
"gatt/bta_gatts_api.cc",
"gatt/bta_gatts_main.cc",
"gatt/bta_gatts_utils.cc",
+ "gatt/database.cc",
+ "gatt/database_builder.cc",
"hearing_aid/hearing_aid.cc",
"hearing_aid/hearing_aid_audio_source.cc",
"hf_client/bta_hf_client_act.cc",
@@ -83,12 +86,6 @@
"hh/bta_hh_le.cc",
"hh/bta_hh_main.cc",
"hh/bta_hh_utils.cc",
- "hl/bta_hl_act.cc",
- "hl/bta_hl_api.cc",
- "hl/bta_hl_ci.cc",
- "hl/bta_hl_main.cc",
- "hl/bta_hl_sdp.cc",
- "hl/bta_hl_utils.cc",
"hd/bta_hd_act.cc",
"hd/bta_hd_api.cc",
"hd/bta_hd_main.cc",
@@ -127,17 +124,22 @@
defaults: ["fluoride_bta_defaults"],
srcs: [
"test/bta_hf_client_test.cc",
- "test/gatt_cache_file_test.cc",
+ "test/gatt/database_builder_test.cc",
+ "test/gatt/database_builder_sample_device_test.cc",
+ "test/gatt/database_test.cc",
],
shared_libs: [
+ "libcrypto",
"liblog",
"libprotobuf-cpp-lite",
],
static_libs: [
"libbtcore",
"libbt-bta",
+ "libbt-audio-hal-interface",
"libbluetooth-types",
"libbt-protos-lite",
"libosi",
+ "libbt-common",
],
}
diff --git a/bta/BUILD.gn b/bta/BUILD.gn
index fa85e40..0bf6544 100644
--- a/bta/BUILD.gn
+++ b/bta/BUILD.gn
@@ -20,7 +20,6 @@
"ag/bta_ag_api.cc",
"ag/bta_ag_at.cc",
"ag/bta_ag_cfg.cc",
- "ag/bta_ag_ci.cc",
"ag/bta_ag_cmd.cc",
"ag/bta_ag_main.cc",
"ag/bta_ag_rfc.cc",
@@ -50,6 +49,10 @@
"gatt/bta_gatts_api.cc",
"gatt/bta_gatts_main.cc",
"gatt/bta_gatts_utils.cc",
+ "gatt/database.cc",
+ "gatt/database_builder.cc",
+ "hearing_aid/hearing_aid.cc",
+ "hearing_aid/hearing_aid_audio_source.cc",
"hf_client/bta_hf_client_act.cc",
"hf_client/bta_hf_client_api.cc",
"hf_client/bta_hf_client_at.cc",
@@ -66,12 +69,6 @@
"hd/bta_hd_act.cc",
"hd/bta_hd_api.cc",
"hd/bta_hd_main.cc",
- "hl/bta_hl_act.cc",
- "hl/bta_hl_api.cc",
- "hl/bta_hl_ci.cc",
- "hl/bta_hl_main.cc",
- "hl/bta_hl_sdp.cc",
- "hl/bta_hl_utils.cc",
"jv/bta_jv_act.cc",
"jv/bta_jv_api.cc",
"jv/bta_jv_cfg.cc",
@@ -100,6 +97,9 @@
"include",
"sys",
"//",
+ "//linux_include",
+ "//bta",
+ "//internal_include",
"//btcore/include",
"//hci/include",
"//internal_include",
@@ -108,10 +108,42 @@
"//udrv/include",
"//utils/include",
"//vnd/include",
+ "//btif/include",
+ "//btif/avrcp",
+ "//include/hardware/avrcp",
+ "//profile/avrcp",
+ "//packet/avrcp",
+ "//packet/base",
]
deps = [
"//third_party/libchrome:base"
]
-
}
+
+executable("net_test_bta") {
+ testonly = true
+ sources = [
+ "gatt/database_builder.cc",
+ "test/gatt/database_builder_test.cc",
+ "test/gatt/database_builder_sample_device_test.cc",
+ "test/gatt/database_test.cc",
+ ]
+
+ include_dirs = [
+ "include",
+ "//",
+ "//bta",
+ "//btcore/include",
+ "//hci/include",
+ "//internal_include",
+ "//stack/btm",
+ ]
+
+ deps = [
+ "//bta",
+ "//types",
+ "//third_party/googletest:gmock_main",
+ "//third_party/libchrome:base",
+ ]
+}
\ No newline at end of file
diff --git a/bta/ag/bta_ag_act.cc b/bta/ag/bta_ag_act.cc
index eb989eb..5a3697a 100644
--- a/bta/ag/bta_ag_act.cc
+++ b/bta/ag/bta_ag_act.cc
@@ -174,15 +174,13 @@
*
******************************************************************************/
void bta_ag_start_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
- RawAddress pending_bd_addr = {};
-
- /* store parameters */
p_scb->peer_addr = data.api_open.bd_addr;
p_scb->cli_sec_mask = data.api_open.sec_mask;
p_scb->open_services = p_scb->reg_services;
/* Check if RFCOMM has any incoming connection to avoid collision. */
- if (PORT_IsOpening(pending_bd_addr)) {
+ RawAddress pending_bd_addr = RawAddress::kEmpty;
+ if (PORT_IsOpening(&pending_bd_addr)) {
/* Let the incoming connection goes through. */
/* Issue collision for this scb for now. */
/* We will decide what to do when we find incoming connetion later. */
@@ -516,16 +514,15 @@
*
******************************************************************************/
void bta_ag_rfc_acp_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
+ APPL_TRACE_DEBUG("%s: serv_handle0 = %d serv_handle = %d", __func__,
+ p_scb->serv_handle[0], p_scb->serv_handle[1]);
/* set role */
p_scb->role = BTA_AG_ACP;
- APPL_TRACE_DEBUG("bta_ag_rfc_acp_open: serv_handle0 = %d serv_handle1 = %d",
- p_scb->serv_handle[0], p_scb->serv_handle[1]);
-
/* get bd addr of peer */
uint16_t lcid = 0;
RawAddress dev_addr = RawAddress::kEmpty;
- int status = PORT_CheckConnection(data.rfc.port_handle, dev_addr, &lcid);
+ int status = PORT_CheckConnection(data.rfc.port_handle, &dev_addr, &lcid);
if (status != PORT_SUCCESS) {
LOG(ERROR) << __func__ << ", PORT_CheckConnection returned " << status;
return;
@@ -568,7 +565,7 @@
p_scb->peer_addr = dev_addr;
/* determine connected service from port handle */
- for (int i = 0; i < BTA_AG_NUM_IDX; i++) {
+ for (uint8_t i = 0; i < BTA_AG_NUM_IDX; i++) {
APPL_TRACE_DEBUG(
"bta_ag_rfc_acp_open: i = %d serv_handle = %d port_handle = %d", i,
p_scb->serv_handle[i], data.rfc.port_handle);
diff --git a/bta/ag/bta_ag_api.cc b/bta/ag/bta_ag_api.cc
index 7497fa7..727ad0f 100644
--- a/bta/ag/bta_ag_api.cc
+++ b/bta/ag/bta_ag_api.cc
@@ -31,6 +31,7 @@
#include "bta_ag_int.h"
#include "bta_api.h"
#include "bta_sys.h"
+#include "stack/include/btu.h"
/*****************************************************************************
* Constants
@@ -61,7 +62,7 @@
}
}
bta_sys_register(BTA_ID_AG, &bta_ag_reg);
- do_in_bta_thread(FROM_HERE, base::Bind(&bta_ag_api_enable, p_cback));
+ do_in_main_thread(FROM_HERE, base::Bind(&bta_ag_api_enable, p_cback));
return BTA_SUCCESS;
}
@@ -76,7 +77,7 @@
*
******************************************************************************/
void BTA_AgDisable() {
- do_in_bta_thread(FROM_HERE, base::Bind(&bta_ag_api_disable));
+ do_in_main_thread(FROM_HERE, base::Bind(&bta_ag_api_disable));
}
/*******************************************************************************
@@ -93,7 +94,7 @@
tBTA_AG_FEAT features,
const std::vector<std::string>& service_names,
uint8_t app_id) {
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE, base::Bind(&bta_ag_api_register, services, sec_mask, features,
service_names, app_id));
}
@@ -109,9 +110,9 @@
*
******************************************************************************/
void BTA_AgDeregister(uint16_t handle) {
- do_in_bta_thread(FROM_HERE,
- base::Bind(&bta_ag_sm_execute_by_handle, handle,
- BTA_AG_API_DEREGISTER_EVT, tBTA_AG_DATA::kEmpty));
+ do_in_main_thread(
+ FROM_HERE, base::Bind(&bta_ag_sm_execute_by_handle, handle,
+ BTA_AG_API_DEREGISTER_EVT, tBTA_AG_DATA::kEmpty));
}
/*******************************************************************************
@@ -131,8 +132,8 @@
tBTA_AG_DATA data = {};
data.api_open.bd_addr = bd_addr;
data.api_open.sec_mask = sec_mask;
- do_in_bta_thread(FROM_HERE, base::Bind(&bta_ag_sm_execute_by_handle, handle,
- BTA_AG_API_OPEN_EVT, data));
+ do_in_main_thread(FROM_HERE, base::Bind(&bta_ag_sm_execute_by_handle, handle,
+ BTA_AG_API_OPEN_EVT, data));
}
/*******************************************************************************
@@ -147,9 +148,9 @@
*
******************************************************************************/
void BTA_AgClose(uint16_t handle) {
- do_in_bta_thread(FROM_HERE,
- base::Bind(&bta_ag_sm_execute_by_handle, handle,
- BTA_AG_API_CLOSE_EVT, tBTA_AG_DATA::kEmpty));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(&bta_ag_sm_execute_by_handle, handle,
+ BTA_AG_API_CLOSE_EVT, tBTA_AG_DATA::kEmpty));
}
/*******************************************************************************
@@ -164,9 +165,9 @@
*
******************************************************************************/
void BTA_AgAudioOpen(uint16_t handle) {
- do_in_bta_thread(FROM_HERE,
- base::Bind(&bta_ag_sm_execute_by_handle, handle,
- BTA_AG_API_AUDIO_OPEN_EVT, tBTA_AG_DATA::kEmpty));
+ do_in_main_thread(
+ FROM_HERE, base::Bind(&bta_ag_sm_execute_by_handle, handle,
+ BTA_AG_API_AUDIO_OPEN_EVT, tBTA_AG_DATA::kEmpty));
}
/*******************************************************************************
@@ -181,7 +182,7 @@
*
******************************************************************************/
void BTA_AgAudioClose(uint16_t handle) {
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE, base::Bind(&bta_ag_sm_execute_by_handle, handle,
BTA_AG_API_AUDIO_CLOSE_EVT, tBTA_AG_DATA::kEmpty));
}
@@ -200,8 +201,8 @@
******************************************************************************/
void BTA_AgResult(uint16_t handle, tBTA_AG_RES result,
const tBTA_AG_RES_DATA& data) {
- do_in_bta_thread(FROM_HERE,
- base::Bind(&bta_ag_api_result, handle, result, data));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(&bta_ag_api_result, handle, result, data));
}
/*******************************************************************************
@@ -219,15 +220,15 @@
void BTA_AgSetCodec(uint16_t handle, tBTA_AG_PEER_CODEC codec) {
tBTA_AG_DATA data = {};
data.api_setcodec.codec = codec;
- do_in_bta_thread(FROM_HERE, base::Bind(&bta_ag_sm_execute_by_handle, handle,
- BTA_AG_API_SETCODEC_EVT, data));
+ do_in_main_thread(FROM_HERE, base::Bind(&bta_ag_sm_execute_by_handle, handle,
+ BTA_AG_API_SETCODEC_EVT, data));
}
void BTA_AgSetScoAllowed(bool value) {
- do_in_bta_thread(FROM_HERE, base::Bind(&bta_ag_set_sco_allowed, value));
+ do_in_main_thread(FROM_HERE, base::Bind(&bta_ag_set_sco_allowed, value));
}
void BTA_AgSetActiveDevice(const RawAddress& active_device_addr) {
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE, base::Bind(&bta_ag_api_set_active_device, active_device_addr));
}
diff --git a/bta/ag/bta_ag_cmd.cc b/bta/ag/bta_ag_cmd.cc
index 2489915..bec5497 100644
--- a/bta/ag/bta_ag_cmd.cc
+++ b/bta/ag/bta_ag_cmd.cc
@@ -48,12 +48,6 @@
/* Invalid Chld command */
#define BTA_AG_INVALID_CHLD 255
-/* clip type constants */
-#define BTA_AG_CLIP_TYPE_MIN 128
-#define BTA_AG_CLIP_TYPE_MAX 175
-#define BTA_AG_CLIP_TYPE_DEFAULT 129
-#define BTA_AG_CLIP_TYPE_VOIP 255
-
#define COLON_IDX_4_VGSVGM 4
/* Local events which will not trigger a higher layer callback */
@@ -881,12 +875,22 @@
case BTA_AG_AT_A_EVT:
case BTA_AG_SPK_EVT:
case BTA_AG_MIC_EVT:
- case BTA_AG_AT_CHUP_EVT:
case BTA_AG_AT_CBC_EVT:
/* send OK */
bta_ag_send_ok(p_scb);
break;
+ case BTA_AG_AT_CHUP_EVT:
+ if (!bta_ag_sco_is_active_device(p_scb->peer_addr)) {
+ LOG(WARNING) << __func__ << ": AT+CHUP rejected as " << p_scb->peer_addr
+ << " is not the active device";
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_ALLOWED);
+ } else {
+ bta_ag_send_ok(p_scb);
+ }
+ break;
+
case BTA_AG_AT_BLDN_EVT:
/* Do not send OK, App will send error or OK depending on
** last dial number enabled or not */
@@ -1441,24 +1445,10 @@
/* tell sys to stop av if any */
bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
- /* Store caller id string.
- * Append type info at the end.
- * Make sure a valid type info is passed.
- * Otherwise add 129 as default type */
- uint16_t clip_type = result.data.num;
- if ((clip_type < BTA_AG_CLIP_TYPE_MIN) ||
- (clip_type > BTA_AG_CLIP_TYPE_MAX)) {
- if (clip_type != BTA_AG_CLIP_TYPE_VOIP) {
- clip_type = BTA_AG_CLIP_TYPE_DEFAULT;
- }
- }
-
- APPL_TRACE_DEBUG("CLIP type :%d", clip_type);
p_scb->clip[0] = 0;
- if (result.data.str[0] != 0)
- snprintf(p_scb->clip, sizeof(p_scb->clip), "%s,%d", result.data.str,
- clip_type);
-
+ if (result.data.str[0] != 0) {
+ snprintf(p_scb->clip, sizeof(p_scb->clip), "%s", result.data.str);
+ }
/* send callsetup indicator */
if (p_scb->post_sco == BTA_AG_POST_SCO_CALL_END) {
/* Need to sent 2 callsetup IND's(Call End and Incoming call) after SCO
diff --git a/bta/ag/bta_ag_main.cc b/bta/ag/bta_ag_main.cc
index 996aa25..f70027f 100644
--- a/bta/ag/bta_ag_main.cc
+++ b/bta/ag/bta_ag_main.cc
@@ -537,13 +537,13 @@
if (p_scb && (p_scb->state == BTA_AG_OPENING_ST)) {
if (id == BTA_ID_SYS) {
- LOG(WARNING) << __func__ << "AG found collision (ACL) for handle "
+ LOG(WARNING) << __func__ << ": AG found collision (ACL) for handle "
<< unsigned(handle) << " device " << peer_addr;
} else if (id == BTA_ID_AG) {
- LOG(WARNING) << __func__ << "AG found collision (RFCOMM) for handle "
+ LOG(WARNING) << __func__ << ": AG found collision (RFCOMM) for handle "
<< unsigned(handle) << " device " << peer_addr;
} else {
- LOG(WARNING) << __func__ << "AG found collision (UNKNOWN) for handle "
+ LOG(WARNING) << __func__ << ": AG found collision (UNKNOWN) for handle "
<< unsigned(handle) << " device " << peer_addr;
}
bta_ag_sm_execute(p_scb, BTA_AG_COLLISION_EVT, tBTA_AG_DATA::kEmpty);
diff --git a/bta/ag/bta_ag_rfc.cc b/bta/ag/bta_ag_rfc.cc
index ba9bd7f..d878afe 100644
--- a/bta/ag/bta_ag_rfc.cc
+++ b/bta/ag/bta_ag_rfc.cc
@@ -34,6 +34,7 @@
#include "osi/include/osi.h"
#include "port_api.h"
#include "rfcdefs.h"
+#include "stack/include/btu.h"
#include "utl.h"
/* Event mask for RfCOMM port callback */
@@ -89,9 +90,9 @@
<< handle << " peer_addr " << p_scb->peer_addr << " state "
<< std::to_string(p_scb->state);
}
- do_in_bta_thread(FROM_HERE,
- base::Bind(&bta_ag_sm_execute_by_handle, handle,
- BTA_AG_RFC_DATA_EVT, tBTA_AG_DATA::kEmpty));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(&bta_ag_sm_execute_by_handle, handle,
+ BTA_AG_RFC_DATA_EVT, tBTA_AG_DATA::kEmpty));
}
}
@@ -154,7 +155,7 @@
tBTA_AG_DATA data = {};
data.rfc.port_handle = port_handle;
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE, base::Bind(&bta_ag_sm_execute_by_handle, handle, event, data));
}
@@ -370,7 +371,7 @@
/* Close API was called while AG is in Opening state. */
/* Need to trigger the state machine to send callback to the app */
/* and move back to INIT state. */
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE,
base::Bind(&bta_ag_sm_execute_by_handle, bta_ag_scb_to_idx(p_scb),
BTA_AG_RFC_CLOSE_EVT, tBTA_AG_DATA::kEmpty));
diff --git a/bta/ag/bta_ag_sco.cc b/bta/ag/bta_ag_sco.cc
index 94825ea..297d93d 100644
--- a/bta/ag/bta_ag_sco.cc
+++ b/bta/ag/bta_ag_sco.cc
@@ -32,6 +32,7 @@
#include "device/include/controller.h"
#include "device/include/esco_parameters.h"
#include "osi/include/osi.h"
+#include "stack/include/btu.h"
#include "utl.h"
/* Codec negotiation timeout */
@@ -133,9 +134,9 @@
}
if (handle != 0) {
- do_in_bta_thread(FROM_HERE,
- base::Bind(&bta_ag_sm_execute_by_handle, handle,
- BTA_AG_SCO_OPEN_EVT, tBTA_AG_DATA::kEmpty));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(&bta_ag_sm_execute_by_handle, handle,
+ BTA_AG_SCO_OPEN_EVT, tBTA_AG_DATA::kEmpty));
} else {
/* no match found; disconnect sco, init sco variables */
bta_ag_cb.sco.p_curr_scb = nullptr;
@@ -216,9 +217,9 @@
bta_ag_cb.sco.p_curr_scb->inuse_codec = BTA_AG_CODEC_NONE;
- do_in_bta_thread(FROM_HERE,
- base::Bind(&bta_ag_sm_execute_by_handle, handle,
- BTA_AG_SCO_CLOSE_EVT, tBTA_AG_DATA::kEmpty));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(&bta_ag_sm_execute_by_handle, handle,
+ BTA_AG_SCO_CLOSE_EVT, tBTA_AG_DATA::kEmpty));
} else {
/* no match found */
APPL_TRACE_DEBUG("no scb for ag_sco_disc_cback");
@@ -372,7 +373,7 @@
<< " is not active, active_device=" << active_device_addr;
if (bta_ag_cb.sco.p_curr_scb != nullptr &&
bta_ag_cb.sco.p_curr_scb->in_use && p_scb == bta_ag_cb.sco.p_curr_scb) {
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE, base::Bind(&bta_ag_sm_execute, p_scb, BTA_AG_SCO_CLOSE_EVT,
tBTA_AG_DATA::kEmpty));
}
@@ -385,8 +386,10 @@
return;
}
+#if (DISABLE_WBS == FALSE)
if ((p_scb->sco_codec == BTA_AG_CODEC_MSBC) && !p_scb->codec_fallback)
esco_codec = BTA_AG_CODEC_MSBC;
+#endif
if (p_scb->codec_fallback) {
p_scb->codec_fallback = false;
@@ -558,12 +561,27 @@
void bta_ag_codec_negotiate(tBTA_AG_SCB* p_scb) {
APPL_TRACE_DEBUG("%s", __func__);
bta_ag_cb.sco.p_curr_scb = p_scb;
+ uint8_t* p_rem_feat = BTM_ReadRemoteFeatures(p_scb->peer_addr);
+ bool sdp_wbs_support = p_scb->peer_sdp_features & BTA_AG_FEAT_WBS_SUPPORT;
- // Workaround for misbehaving HFs such as Sony XAV AX100 car kit and Sony
- // MW600 Headset, which indicate WBS support in SDP, but no codec
- // negotiation support in BRSF. In this case, using mSBC codec can result
- // background noise or no audio. Thus, defaulting to CVSD instead.
- if (!(p_scb->peer_features & BTA_AG_PEER_FEAT_CODEC)) {
+ if (p_rem_feat == nullptr) {
+ LOG(WARNING) << __func__
+ << ": Fail to read remote feature, skip codec negotiation";
+ bta_ag_sco_codec_nego(p_scb, false);
+ return;
+ }
+
+ // Workaround for misbehaving HFs, which indicate which one is not support on
+ // Transparent Synchronous Data in Remote Supported Features, WBS in SDP and
+ // and Codec Negotiation in BRSF. Fluoride will assume CVSD codec by default.
+ // In Sony XAV AX100 car kit and Sony MW600 Headset case, which indicate
+ // Transparent Synchronous Data and WBS support, but no codec negotiation
+ // support, using mSBC codec can result background noise or no audio.
+ // In Skullcandy JIB case, which indicate WBS and codec negotiation support,
+ // but no Transparent Synchronous Data support, using mSBC codec can result
+ // SCO setup fail by Firmware reject.
+ if (!HCI_LMP_TRANSPNT_SUPPORTED(p_rem_feat) || !sdp_wbs_support ||
+ !(p_scb->peer_features & BTA_AG_PEER_FEAT_CODEC)) {
p_scb->sco_codec = UUID_CODEC_CVSD;
}
@@ -635,9 +653,14 @@
/* remove listening connection */
bta_ag_remove_sco(p_scb, false);
+#if (DISABLE_WBS == FALSE)
/* start codec negotiation */
p_sco->state = BTA_AG_SCO_CODEC_ST;
bta_ag_codec_negotiate(p_scb);
+#else
+ bta_ag_create_sco(p_scb, true);
+ p_sco->state = BTA_AG_SCO_OPENING_ST;
+#endif
break;
case BTA_AG_SCO_SHUTDOWN_E:
@@ -732,11 +755,13 @@
}
break;
+#if (DISABLE_WBS == FALSE)
case BTA_AG_SCO_REOPEN_E:
/* start codec negotiation */
p_sco->state = BTA_AG_SCO_CODEC_ST;
bta_ag_codec_negotiate(p_scb);
break;
+#endif
case BTA_AG_SCO_XFER_E:
/* save xfer scb */
@@ -1009,11 +1034,18 @@
bta_ag_create_sco(p_scb, false);
bta_ag_remove_sco(p_sco->p_xfer_scb, false);
+#if (DISABLE_WBS == FALSE)
/* start codec negotiation */
p_sco->state = BTA_AG_SCO_CODEC_ST;
tBTA_AG_SCB* p_cn_scb = p_sco->p_xfer_scb;
p_sco->p_xfer_scb = nullptr;
bta_ag_codec_negotiate(p_cn_scb);
+#else
+ /* create sco connection to peer */
+ bta_ag_create_sco(p_sco->p_xfer_scb, true);
+ p_sco->p_xfer_scb = nullptr;
+ p_sco->state = BTA_AG_SCO_OPENING_ST;
+#endif
break;
}
diff --git a/bta/ag/bta_ag_sdp.cc b/bta/ag/bta_ag_sdp.cc
index 5ab1215..ba955d3 100644
--- a/bta/ag/bta_ag_sdp.cc
+++ b/bta/ag/bta_ag_sdp.cc
@@ -36,6 +36,7 @@
#include "btm_api.h"
#include "osi/include/osi.h"
#include "sdp_api.h"
+#include "stack/include/btu.h"
#include "utl.h"
using bluetooth::Uuid;
@@ -87,8 +88,8 @@
event = BTA_AG_DISC_INT_RES_EVT;
}
tBTA_AG_DATA disc_result = {.disc_result.status = status};
- do_in_bta_thread(FROM_HERE, base::Bind(&bta_ag_sm_execute_by_handle, idx,
- event, disc_result));
+ do_in_main_thread(FROM_HERE, base::Bind(&bta_ag_sm_execute_by_handle, idx,
+ event, disc_result));
}
}
diff --git a/bta/av/bta_av_aact.cc b/bta/av/bta_av_aact.cc
index 297bba4..108af36 100644
--- a/bta/av/bta_av_aact.cc
+++ b/bta/av/bta_av_aact.cc
@@ -79,7 +79,6 @@
/* ACL quota we are letting FW use for A2DP Offload Tx. */
#define BTA_AV_A2DP_OFFLOAD_XMIT_QUOTA 4
-#define MAX_2MBPS_AVDTP_MTU 663
#define BTIF_A2DP_MAX_BITPOOL_MQ 35
static void bta_av_offload_codec_builder(tBTA_AV_SCB* p_scb,
@@ -1247,7 +1246,6 @@
open.chnl = p_scb->chnl;
open.hndl = p_scb->hndl;
open.status = BTA_AV_SUCCESS;
- open.starting = bta_av_chk_start(p_scb);
open.edr = 0;
p = BTM_ReadRemoteFeatures(p_scb->PeerAddress());
if (p != NULL) {
@@ -1263,8 +1261,10 @@
bta_ar_avdt_conn(BTA_ID_AV, open.bd_addr, p_scb->hdi);
#endif
if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC) {
+ open.starting = false;
open.sep = AVDT_TSEP_SNK;
} else if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK) {
+ open.starting = bta_av_chk_start(p_scb);
open.sep = AVDT_TSEP_SRC;
}
@@ -3247,7 +3247,7 @@
APPL_TRACE_ERROR("%s: Unknown Codec type ", __func__);
return;
}
- if (mtu > BTA_AV_MAX_A2DP_MTU) mtu = BTA_AV_MAX_A2DP_MTU;
+ if (mtu > MAX_3MBPS_AVDTP_MTU) mtu = MAX_3MBPS_AVDTP_MTU;
p_a2dp_offload->codec_type = codec_type;
p_a2dp_offload->max_latency = 0;
p_a2dp_offload->mtu = mtu;
diff --git a/bta/av/bta_av_act.cc b/bta/av/bta_av_act.cc
index 5625f90..a727842 100644
--- a/bta/av/bta_av_act.cc
+++ b/bta/av/bta_av_act.cc
@@ -314,18 +314,26 @@
tAVRC_CONN_CB ccb;
RawAddress bda = RawAddress::kAny;
uint8_t status = BTA_AV_RC_ROLE_ACP;
- tBTA_AV_SCB* p_scb = p_cb->p_scb[shdl - 1];
int i;
uint8_t rc_handle;
tBTA_AV_RCB* p_rcb;
if (role == AVCT_INT) {
+ // Can't grab a stream control block that doesn't have a valid handle
+ if (!shdl) {
+ APPL_TRACE_ERROR(
+ "%s: Can't grab stream control block for shdl = %d -> index = %d",
+ __func__, shdl, shdl - 1);
+ return BTA_AV_RC_HANDLE_NONE;
+ }
+ tBTA_AV_SCB* p_scb = p_cb->p_scb[shdl - 1];
bda = p_scb->PeerAddress();
status = BTA_AV_RC_ROLE_INT;
} else {
p_rcb = bta_av_get_rcb_by_shdl(shdl);
if (p_rcb != NULL) {
APPL_TRACE_ERROR("%s: ACP handle exist for shdl:%d", __func__, shdl);
+ p_rcb->lidx = lidx;
return p_rcb->handle;
}
}
@@ -1865,9 +1873,9 @@
/*
* In case scb is not created by the time we are done with SDP
* we still need to send RC feature event. So we need to get BD
- * from Message
+ * from Message. Note that lidx is 1 based not 0 based
*/
- rc_feat.peer_addr = p_cb->lcb[p_cb->rcb[rc_handle].lidx].addr;
+ rc_feat.peer_addr = p_cb->lcb[p_cb->rcb[rc_handle].lidx - 1].addr;
} else {
rc_feat.peer_addr = p_scb->PeerAddress();
}
@@ -1939,11 +1947,6 @@
} else {
/* AVCT CCB is still there. dealloc */
bta_av_del_rc(p_rcb);
-
- /* if the AVRCP is no longer listening, create the listening channel */
- if (bta_av_cb.rc_acp_handle == BTA_AV_RC_HANDLE_NONE &&
- bta_av_cb.features & BTA_AV_FEAT_RCTG)
- bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);
}
} else if ((p_rcb->handle != BTA_AV_RC_HANDLE_NONE) &&
(p_rcb->status & BTA_AV_RC_CONN_MASK)) {
@@ -1964,6 +1967,9 @@
tBTA_AV bta_av_data;
bta_av_data.rc_close = rc_close;
(*p_cb->p_cback)(BTA_AV_RC_CLOSE_EVT, &bta_av_data);
+ if (bta_av_cb.rc_acp_handle == BTA_AV_RC_HANDLE_NONE
+ && bta_av_cb.features & BTA_AV_FEAT_RCTG)
+ bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);
}
/*******************************************************************************
diff --git a/bta/av/bta_av_cfg.cc b/bta/av/bta_av_cfg.cc
index 76c9454..1da38b3 100644
--- a/bta/av/bta_av_cfg.cc
+++ b/bta/av/bta_av_cfg.cc
@@ -134,7 +134,7 @@
BTA_AV_RC_SUPF_CT, /* AVRCP controller categories */
BTA_AV_RC_SUPF_TG, /* AVRCP target categories */
672, /* AVDTP signaling channel MTU at L2CAP */
- BTA_AV_MAX_A2DP_MTU, /* AVDTP audio transport channel MTU at L2CAP */
+ MAX_3MBPS_AVDTP_MTU, /* AVDTP audio transport channel MTU at L2CAP */
bta_av_audio_flush_to, /* AVDTP audio transport channel flush
timeout */
6, /* AVDTP audio channel max data queue size */
@@ -161,7 +161,7 @@
BTA_AVK_RC_SUPF_CT, /* AVRCP controller categories */
BTA_AVK_RC_SUPF_TG, /* AVRCP target categories */
672, /* AVDTP signaling channel MTU at L2CAP */
- BTA_AV_MAX_A2DP_MTU, /* AVDTP audio transport channel MTU at L2CAP */
+ MAX_3MBPS_AVDTP_MTU, /* AVDTP audio transport channel MTU at L2CAP */
bta_av_audio_flush_to, /* AVDTP audio transport channel flush timeout */
6, /* AVDTP audio channel max data queue size */
false, /* true, to accept AVRC 1.3 group nevigation command */
@@ -186,7 +186,7 @@
BTA_AV_RC_SUPF_CT, /* AVRCP controller categories */
AVRC_SUPF_TG_CAT1, /* Only support CAT1 for AVRCP1.3 */
672, /* AVDTP signaling channel MTU at L2CAP */
- BTA_AV_MAX_A2DP_MTU, /* AVDTP audio transport channel MTU at L2CAP */
+ MAX_3MBPS_AVDTP_MTU, /* AVDTP audio transport channel MTU at L2CAP */
bta_av_audio_flush_to, /* AVDTP audio transport channel flush timeout */
6, /* AVDTP audio channel max data queue size */
false, /* true, to accept AVRC 1.3 group nevigation command */
diff --git a/bta/av/bta_av_main.cc b/bta/av/bta_av_main.cc
index 3679469..34516fc 100644
--- a/bta/av/bta_av_main.cc
+++ b/bta/av/bta_av_main.cc
@@ -635,6 +635,9 @@
for (int i = codec_index_min; i < codec_index_max; i++) {
btav_a2dp_codec_index_t codec_index =
static_cast<btav_a2dp_codec_index_t>(i);
+ if (!bta_av_co_is_supported_codec(codec_index)) {
+ continue;
+ }
if (!(*bta_av_a2dp_cos.init)(codec_index, &avdtp_stream_config.cfg)) {
continue;
}
@@ -1382,6 +1385,8 @@
}
void bta_debug_av_dump(int fd) {
+ if (appl_trace_level < BT_TRACE_LEVEL_DEBUG) return;
+
dprintf(fd, "\nBTA AV State:\n");
dprintf(fd, " State Machine State: %s\n", bta_av_st_code(bta_av_cb.state));
dprintf(fd, " Link signalling timer: %s\n",
@@ -1410,6 +1415,9 @@
for (size_t i = 0; i < sizeof(bta_av_cb.lcb) / sizeof(bta_av_cb.lcb[0]);
i++) {
const tBTA_AV_LCB& lcb = bta_av_cb.lcb[i];
+ if (lcb.addr.IsEmpty()) {
+ continue;
+ }
dprintf(fd, "\n Link control block: %zu peer: %s\n", i,
lcb.addr.ToString().c_str());
dprintf(fd, " Connected stream handle mask: 0x%x\n", lcb.conn_msk);
@@ -1420,12 +1428,18 @@
if (p_scb == nullptr) {
continue;
}
+ if (p_scb->PeerAddress().IsEmpty()) {
+ continue;
+ }
dprintf(fd, "\n BTA ID: %zu peer: %s\n", i,
p_scb->PeerAddress().ToString().c_str());
dprintf(fd, " SDP discovery started: %s\n",
p_scb->sdp_discovery_started ? "true" : "false");
for (size_t j = 0; j < BTAV_A2DP_CODEC_INDEX_MAX; j++) {
const tBTA_AV_SEP& sep = p_scb->seps[j];
+ if (sep.av_handle == 0) {
+ continue;
+ }
dprintf(fd, " SEP ID: %zu\n", j);
dprintf(fd, " SEP AVDTP handle: %d\n", sep.av_handle);
dprintf(fd, " Local SEP type: %d\n", sep.tsep);
diff --git a/bta/av/bta_av_ssm.cc b/bta/av/bta_av_ssm.cc
index 6c384e0..80effa3 100644
--- a/bta/av/bta_av_ssm.cc
+++ b/bta/av/bta_av_ssm.cc
@@ -131,7 +131,7 @@
/* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
/* STR_CLOSE_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
/* STR_CONFIG_IND_EVT */
- {BTA_AV_SETCONFIG_REJ, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ {BTA_AV_CONFIG_IND, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
/* STR_SECURITY_IND_EVT */
{BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
/* STR_SECURITY_CFM_EVT */
@@ -329,7 +329,7 @@
/* STR_RECONFIG_CFM_EVT */
{BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
/* AVRC_TIMER_EVT */
- {BTA_AV_OPEN_RC, BTA_AV_CHK_2ND_START, BTA_AV_OPEN_SST},
+ {BTA_AV_OPEN_RC, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
/* AVDT_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
/* AVDT_DISCONNECT_EVT */
{BTA_AV_STR_CLOSED, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
diff --git a/bta/dm/bta_dm_act.cc b/bta/dm/bta_dm_act.cc
index 5abda87..7ba3c74 100644
--- a/bta/dm/bta_dm_act.cc
+++ b/bta/dm/bta_dm_act.cc
@@ -38,6 +38,7 @@
#include "bta_dm_co.h"
#include "bta_dm_int.h"
#include "bta_sys.h"
+#include "btif_storage.h"
#include "btm_api.h"
#include "btm_int.h"
#include "btu.h"
@@ -46,6 +47,8 @@
#include "osi/include/log.h"
#include "osi/include/osi.h"
#include "sdp_api.h"
+#include "stack/gatt/connection_manager.h"
+#include "stack/include/gatt_api.h"
#include "utl.h"
#if (GAP_INCLUDED == TRUE)
@@ -71,7 +74,7 @@
BD_NAME bd_name, bool min_16_digit);
static uint8_t bta_dm_new_link_key_cback(const RawAddress& bd_addr,
DEV_CLASS dev_class, BD_NAME bd_name,
- LINK_KEY key, uint8_t key_type);
+ const LinkKey& key, uint8_t key_type);
static uint8_t bta_dm_authentication_complete_cback(const RawAddress& bd_addr,
DEV_CLASS dev_class,
BD_NAME bd_name,
@@ -189,12 +192,10 @@
/*
* NOTE : The number of element in bta_service_id_to_btm_srv_id_lkup_tbl should
- * be matching with
- * the value BTA_MAX_SERVICE_ID in bta_api.h
+ * be matching with the value BTA_MAX_SERVICE_ID in bta_api.h
*
- * i.e., If you add new Service ID for BTA, the correct security ID of
- * the new service
- * from Security service definitions (btm_api.h) should be added to
+ * i.e., If you add new Service ID for BTA, the correct security ID of the new
+ * service from Security service definitions (btm_api.h) should be added to
* this lookup table.
*/
const uint32_t bta_service_id_to_btm_srv_id_lkup_tbl[BTA_MAX_SERVICE_ID] = {
@@ -245,6 +246,9 @@
extern DEV_CLASS local_device_default_class;
+// Stores the local Input/Output Capabilities of the Bluetooth device.
+static uint8_t btm_local_io_caps;
+
/** Initialises the BT device manager */
void bta_dm_enable(tBTA_DM_SEC_CBACK* p_sec_cback) {
/* if already in use, return an error */
@@ -275,6 +279,8 @@
sys_enable_event->hw_module = BTA_SYS_HW_BLUETOOTH;
bta_sys_sendmsg(sys_enable_event);
+
+ btm_local_io_caps = btif_storage_get_local_io_caps();
}
/*******************************************************************************
@@ -337,7 +343,6 @@
DEV_CLASS dev_class;
tBTA_DM_SEC_CBACK* temp_cback;
uint8_t key_mask = 0;
- BT_OCTET16 er;
tBTA_BLE_LOCAL_ID_KEYS id_key;
APPL_TRACE_DEBUG("%s with event: %i", __func__, status);
@@ -400,7 +405,8 @@
BTM_SetDeviceClass(dev_class);
/* load BLE local information: ID keys, ER if available */
- bta_dm_co_ble_load_local_keys(&key_mask, er, &id_key);
+ Octet16 er;
+ bta_dm_co_ble_load_local_keys(&key_mask, &er, &id_key);
if (key_mask & BTA_BLE_LOCAL_KEY_TYPE_ER) {
BTM_BleLoadLocalKeys(BTA_BLE_LOCAL_KEY_TYPE_ER,
@@ -471,7 +477,7 @@
bta_dm_disable_search_and_disc();
bta_dm_cb.disabling = true;
- BTM_BleClearBgConnDev();
+ connection_manager::reset(false);
if (BTM_GetNumAclLinks() == 0) {
#if (BTA_DISABLE_DELAY > 0)
@@ -639,6 +645,10 @@
auto& peer_device = bta_dm_cb.device_list.peer_device[i];
if (peer_device.peer_bdaddr == bd_addr) {
peer_device.conn_state = BTA_DM_UNPAIRING;
+
+ /* Make sure device is not in white list before we disconnect */
+ GATT_CancelConnect(0, bd_addr, false);
+
btm_remove_acl(bd_addr, peer_device.transport);
APPL_TRACE_DEBUG("%s: transport: %d", __func__, peer_device.transport);
@@ -675,6 +685,10 @@
auto& peer_device = bta_dm_cb.device_list.peer_device[i];
if (peer_device.peer_bdaddr == other_address) {
peer_device.conn_state = BTA_DM_UNPAIRING;
+
+ /* Make sure device is not in white list before we disconnect */
+ GATT_CancelConnect(0, bd_addr, false);
+
btm_remove_acl(other_address, peer_device.transport);
break;
}
@@ -699,11 +713,10 @@
* Description This function adds a Link Key to an security database entry.
* It is normally called during host startup to restore all
* required information stored in the NVRAM.
- ***
******************************************************************************/
void bta_dm_add_device(std::unique_ptr<tBTA_DM_API_ADD_DEVICE> msg) {
uint8_t* p_dc = NULL;
- uint8_t* p_lc = NULL;
+ LinkKey* p_lc = NULL;
uint32_t trusted_services_mask[BTM_SEC_SERVICE_ARRAY_SIZE];
uint8_t index = 0;
uint8_t btm_mask_index = 0;
@@ -713,7 +726,7 @@
/* If not all zeros, the device class has been specified */
if (msg->dc_known) p_dc = (uint8_t*)msg->dc;
- if (msg->link_key_known) p_lc = (uint8_t*)msg->link_key;
+ if (msg->link_key_known) p_lc = &msg->link_key;
if (msg->is_trusted) {
/* covert BTA service mask to BTM mask */
@@ -757,6 +770,10 @@
} else {
APPL_TRACE_ERROR("unknown device, remove ACL failed");
}
+
+ /* Make sure device is not in white list before we disconnect */
+ GATT_CancelConnect(0, bd_addr, false);
+
/* Disconnect the ACL link */
btm_remove_acl(bd_addr, transport);
}
@@ -1968,12 +1985,13 @@
/* check whether connection already exists to the device
if connection exists, we don't have to wait for ACL
link to go down to start search on next device */
- if (BTM_IsAclConnectionUp(bta_dm_search_cb.peer_bdaddr,
- BT_TRANSPORT_BR_EDR))
- bta_dm_search_cb.wait_disc = false;
- else
- bta_dm_search_cb.wait_disc = true;
-
+ if (transport == BT_TRANSPORT_BR_EDR) {
+ if (BTM_IsAclConnectionUp(bta_dm_search_cb.peer_bdaddr,
+ BT_TRANSPORT_BR_EDR))
+ bta_dm_search_cb.wait_disc = false;
+ else
+ bta_dm_search_cb.wait_disc = true;
+ }
if (bta_dm_search_cb.p_btm_inq_info) {
APPL_TRACE_DEBUG(
"%s p_btm_inq_info 0x%x results.device_type 0x%x "
@@ -2359,7 +2377,7 @@
******************************************************************************/
static uint8_t bta_dm_new_link_key_cback(const RawAddress& bd_addr,
UNUSED_ATTR DEV_CLASS dev_class,
- BD_NAME bd_name, LINK_KEY key,
+ BD_NAME bd_name, const LinkKey& key,
uint8_t key_type) {
tBTA_DM_SEC sec_event;
tBTA_DM_AUTH_CMPL* p_auth_cmpl;
@@ -2376,12 +2394,10 @@
memcpy(p_auth_cmpl->bd_name, bd_name, (BD_NAME_LEN - 1));
p_auth_cmpl->bd_name[BD_NAME_LEN - 1] = 0;
-
p_auth_cmpl->key_present = true;
p_auth_cmpl->key_type = key_type;
p_auth_cmpl->success = true;
-
- memcpy(p_auth_cmpl->key, key, LINK_KEY_LEN);
+ p_auth_cmpl->key = key;
sec_event.auth_cmpl.fail_reason = HCI_SUCCESS;
// Report the BR link key based on the BR/EDR address and type
@@ -2463,20 +2479,20 @@
/* TODO_SP */
switch (event) {
case BTM_SP_IO_REQ_EVT:
-#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
- /* translate auth_req */
- bta_dm_co_io_req(p_data->io_req.bd_addr, &p_data->io_req.io_cap,
- &p_data->io_req.oob_data, &p_data->io_req.auth_req,
- p_data->io_req.is_orig);
-#endif
+ if (btm_local_io_caps != BTM_IO_CAP_NONE) {
+ /* translate auth_req */
+ bta_dm_co_io_req(p_data->io_req.bd_addr, &p_data->io_req.io_cap,
+ &p_data->io_req.oob_data, &p_data->io_req.auth_req,
+ p_data->io_req.is_orig);
+ }
APPL_TRACE_EVENT("io mitm: %d oob_data:%d", p_data->io_req.auth_req,
p_data->io_req.oob_data);
break;
case BTM_SP_IO_RSP_EVT:
-#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
- bta_dm_co_io_rsp(p_data->io_rsp.bd_addr, p_data->io_rsp.io_cap,
- p_data->io_rsp.oob_data, p_data->io_rsp.auth_req);
-#endif
+ if (btm_local_io_caps != BTM_IO_CAP_NONE) {
+ bta_dm_co_io_rsp(p_data->io_rsp.bd_addr, p_data->io_rsp.io_cap,
+ p_data->io_rsp.oob_data, p_data->io_rsp.auth_req);
+ }
break;
case BTM_SP_CFM_REQ_EVT:
@@ -2489,12 +2505,16 @@
sec_event.cfm_req.rmt_io_caps = p_data->cfm_req.rmt_io_caps;
/* continue to next case */
-#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
/* Passkey entry mode, mobile device with output capability is very
unlikely to receive key request, so skip this event */
/*case BTM_SP_KEY_REQ_EVT: */
case BTM_SP_KEY_NOTIF_EVT:
-#endif
+ if (btm_local_io_caps == BTM_IO_CAP_NONE &&
+ BTM_SP_KEY_NOTIF_EVT == event) {
+ status = BTM_NOT_AUTHORIZED;
+ break;
+ }
+
bta_dm_cb.num_val = sec_event.key_notif.passkey =
p_data->key_notif.passkey;
@@ -2774,7 +2794,9 @@
bta_dm_cb.device_list.le_count--;
conn.link_down.link_type = transport;
- if (bta_dm_search_cb.wait_disc && bta_dm_search_cb.peer_bdaddr == bd_addr) {
+ if ((transport == BT_TRANSPORT_BR_EDR) &&
+ (bta_dm_search_cb.wait_disc &&
+ bta_dm_search_cb.peer_bdaddr == bd_addr)) {
bta_dm_search_cb.wait_disc = false;
if (bta_dm_search_cb.sdp_results) {
@@ -2820,34 +2842,34 @@
switch (p_data->event) {
case BTM_BL_CONN_EVT:
/* connection up */
- do_in_bta_thread(FROM_HERE,
- base::Bind(bta_dm_acl_change, true, *p_data->conn.p_bda,
- p_data->conn.transport, p_data->conn.handle));
+ do_in_main_thread(
+ FROM_HERE, base::Bind(bta_dm_acl_change, true, *p_data->conn.p_bda,
+ p_data->conn.transport, p_data->conn.handle));
break;
case BTM_BL_DISCN_EVT:
/* connection down */
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE, base::Bind(bta_dm_acl_change, false, *p_data->discn.p_bda,
p_data->discn.transport, p_data->discn.handle));
break;
case BTM_BL_UPDATE_EVT: {
/* busy level update */
- do_in_bta_thread(FROM_HERE, base::Bind(send_busy_level_update,
- p_data->update.busy_level,
- p_data->update.busy_level_flags));
+ do_in_main_thread(FROM_HERE, base::Bind(send_busy_level_update,
+ p_data->update.busy_level,
+ p_data->update.busy_level_flags));
return;
}
case BTM_BL_ROLE_CHG_EVT: {
const auto& tmp = p_data->role_chg;
- do_in_bta_thread(FROM_HERE, base::Bind(handle_role_change, *tmp.p_bda,
- tmp.new_role, tmp.hci_status));
+ do_in_main_thread(FROM_HERE, base::Bind(handle_role_change, *tmp.p_bda,
+ tmp.new_role, tmp.hci_status));
return;
}
case BTM_BL_COLLISION_EVT:
/* Collision report from Stack: Notify profiles */
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE, base::Bind(bta_sys_notify_collision, *p_data->conn.p_bda));
return;
}
@@ -3766,13 +3788,10 @@
memset(&sec_event, 0, sizeof(tBTA_DM_SEC));
switch (event) {
case BTM_LE_IO_REQ_EVT:
-#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
-
bta_dm_co_ble_io_req(
bda, &p_data->io_req.io_cap, &p_data->io_req.oob_data,
&p_data->io_req.auth_req, &p_data->io_req.max_key_size,
&p_data->io_req.init_keys, &p_data->io_req.resp_keys);
-#endif
APPL_TRACE_EVENT("io mitm: %d oob_data:%d", p_data->io_req.auth_req,
p_data->io_req.oob_data);
@@ -3842,10 +3861,24 @@
if (p_data->complt.reason != 0) {
sec_event.auth_cmpl.fail_reason =
BTA_DM_AUTH_CONVERT_SMP_CODE(((uint8_t)p_data->complt.reason));
- /* delete this device entry from Sec Dev DB */
- bta_dm_remove_sec_dev_entry(bda);
+
+ if (btm_sec_is_a_bonded_dev(bda) &&
+ p_data->complt.reason == SMP_CONN_TOUT) {
+ // Bonded device failed to encrypt - to test this remove battery from
+ // HID device right after connection, but before encryption is
+ // established
+ LOG(INFO) << __func__
+ << ": bonded device disconnected when encrypting - no "
+ "reason to unbond";
+ } else {
+ /* delete this device entry from Sec Dev DB */
+ bta_dm_remove_sec_dev_entry(bda);
+ }
+
} else {
sec_event.auth_cmpl.success = true;
+ if (!p_data->complt.smp_over_br)
+ GATT_ConfigServiceChangeCCC(bda, true, BT_TRANSPORT_LE);
}
if (bta_dm_cb.p_sec_cback) {
@@ -4018,20 +4051,6 @@
}
}
}
-/*******************************************************************************
- *
- * Function bta_dm_ble_set_adv_params
- *
- * Description This function set the adv parameters.
- *
- * Parameters:
- *
- ******************************************************************************/
-void bta_dm_ble_set_adv_params(uint16_t adv_int_min, uint16_t adv_int_max,
- tBLE_BD_ADDR* p_dir_bda) {
- BTM_BleSetAdvParams(adv_int_min, adv_int_max, p_dir_bda,
- BTA_DM_BLE_ADV_CHNL_MAP);
-}
/** This function set the maximum transmission packet size */
void bta_dm_ble_set_data_length(const RawAddress& bd_addr,
diff --git a/bta/dm/bta_dm_api.cc b/bta/dm/bta_dm_api.cc
index e968bd1..979d2f6 100644
--- a/bta/dm/bta_dm_api.cc
+++ b/bta/dm/bta_dm_api.cc
@@ -26,13 +26,13 @@
#include "bt_common.h"
#include "bta_api.h"
-#include "bta_closure_api.h"
#include "bta_dm_int.h"
#include "bta_sys.h"
#include "bta_sys_int.h"
#include "btm_api.h"
#include "btm_int.h"
#include "osi/include/osi.h"
+#include "stack/include/btu.h"
#include "utl.h"
using bluetooth::Uuid;
@@ -64,7 +64,7 @@
/* if UUID list is not provided as static data */
bta_sys_eir_register(bta_dm_eir_update_uuid);
- do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_enable, p_cback));
+ do_in_main_thread(FROM_HERE, base::Bind(bta_dm_enable, p_cback));
return BTA_SUCCESS;
}
@@ -79,19 +79,19 @@
*
******************************************************************************/
tBTA_STATUS BTA_DisableBluetooth(void) {
- do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_disable));
+ do_in_main_thread(FROM_HERE, base::Bind(bta_dm_disable));
return BTA_SUCCESS;
}
/** Enables bluetooth device under test mode */
void BTA_EnableTestMode(void) {
- do_in_bta_thread(FROM_HERE,
- base::Bind(base::IgnoreResult(BTM_EnableTestMode)));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(base::IgnoreResult(BTM_EnableTestMode)));
}
/** Disable bluetooth device under test mode */
void BTA_DisableTestMode(void) {
- do_in_bta_thread(FROM_HERE, base::Bind(BTM_DeviceReset, nullptr));
+ do_in_main_thread(FROM_HERE, base::Bind(BTM_DeviceReset, nullptr));
}
/** This function sets the Bluetooth name of local device */
@@ -99,7 +99,7 @@
std::vector<uint8_t> name(BD_NAME_LEN);
strlcpy((char*)name.data(), p_name, BD_NAME_LEN);
- do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_set_dev_name, name));
+ do_in_main_thread(FROM_HERE, base::Bind(bta_dm_set_dev_name, name));
}
/** This function sets the Bluetooth connectable, discoverable, pairable and
@@ -107,9 +107,9 @@
*/
void BTA_DmSetVisibility(tBTA_DM_DISC disc_mode, tBTA_DM_CONN conn_mode,
uint8_t pairable_mode, uint8_t conn_paired_only) {
- do_in_bta_thread(FROM_HERE,
- base::Bind(bta_dm_set_visibility, disc_mode, conn_mode,
- pairable_mode, conn_paired_only));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(bta_dm_set_visibility, disc_mode, conn_mode,
+ pairable_mode, conn_paired_only));
}
/*******************************************************************************
@@ -211,20 +211,20 @@
/** This function initiates a bonding procedure with a peer device */
void BTA_DmBond(const RawAddress& bd_addr) {
- do_in_bta_thread(FROM_HERE,
- base::Bind(bta_dm_bond, bd_addr, BTA_TRANSPORT_UNKNOWN));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(bta_dm_bond, bd_addr, BTA_TRANSPORT_UNKNOWN));
}
/** This function initiates a bonding procedure with a peer device */
void BTA_DmBondByTransport(const RawAddress& bd_addr,
tBTA_TRANSPORT transport) {
- do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_bond, bd_addr, transport));
+ do_in_main_thread(FROM_HERE, base::Bind(bta_dm_bond, bd_addr, transport));
}
/** This function cancels the bonding procedure with a peer device
*/
void BTA_DmBondCancel(const RawAddress& bd_addr) {
- do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_bond_cancel, bd_addr));
+ do_in_main_thread(FROM_HERE, base::Bind(bta_dm_bond_cancel, bd_addr));
}
/*******************************************************************************
@@ -250,7 +250,8 @@
memcpy(msg->p_pin, p_pin, pin_len);
}
- do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_pin_reply, base::Passed(&msg)));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(bta_dm_pin_reply, base::Passed(&msg)));
}
/*******************************************************************************
@@ -267,7 +268,7 @@
*
******************************************************************************/
void BTA_DmLocalOob(void) {
- do_in_bta_thread(FROM_HERE, base::Bind(BTM_ReadLocalOobData));
+ do_in_main_thread(FROM_HERE, base::Bind(BTM_ReadLocalOobData));
}
/*******************************************************************************
@@ -281,7 +282,7 @@
*
******************************************************************************/
void BTA_DmConfirm(const RawAddress& bd_addr, bool accept) {
- do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_confirm, bd_addr, accept));
+ do_in_main_thread(FROM_HERE, base::Bind(bta_dm_confirm, bd_addr, accept));
}
/*******************************************************************************
@@ -296,7 +297,7 @@
*
******************************************************************************/
void BTA_DmAddDevice(const RawAddress& bd_addr, DEV_CLASS dev_class,
- LINK_KEY link_key, tBTA_SERVICE_MASK trusted_mask,
+ const LinkKey& link_key, tBTA_SERVICE_MASK trusted_mask,
bool is_trusted, uint8_t key_type, tBTA_IO_CAP io_cap,
uint8_t pin_length) {
std::unique_ptr<tBTA_DM_API_ADD_DEVICE> msg =
@@ -306,12 +307,9 @@
msg->tm = trusted_mask;
msg->is_trusted = is_trusted;
msg->io_cap = io_cap;
-
- if (link_key) {
- msg->link_key_known = true;
- msg->key_type = key_type;
- memcpy(msg->link_key, link_key, LINK_KEY_LEN);
- }
+ msg->link_key_known = true;
+ msg->key_type = key_type;
+ msg->link_key = link_key;
/* Load device class if specified */
if (dev_class) {
@@ -323,14 +321,14 @@
memset(msg->features, 0, sizeof(msg->features));
msg->pin_length = pin_length;
- do_in_bta_thread(FROM_HERE,
- base::Bind(bta_dm_add_device, base::Passed(&msg)));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(bta_dm_add_device, base::Passed(&msg)));
}
/** This function removes a device fromthe security database list of peer
* device. It manages unpairing even while connected */
tBTA_STATUS BTA_DmRemoveDevice(const RawAddress& bd_addr) {
- do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_remove_device, bd_addr));
+ do_in_main_thread(FROM_HERE, base::Bind(bta_dm_remove_device, bd_addr));
return BTA_SUCCESS;
}
@@ -443,8 +441,8 @@
******************************************************************************/
void BTA_DmAddBleKey(const RawAddress& bd_addr, tBTA_LE_KEY_VALUE* p_le_key,
tBTA_LE_KEY_TYPE key_type) {
- do_in_bta_thread(FROM_HERE,
- base::Bind(bta_dm_add_blekey, bd_addr, *p_le_key, key_type));
+ do_in_main_thread(
+ FROM_HERE, base::Bind(bta_dm_add_blekey, bd_addr, *p_le_key, key_type));
}
/*******************************************************************************
@@ -464,8 +462,8 @@
******************************************************************************/
void BTA_DmAddBleDevice(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type,
tBT_DEVICE_TYPE dev_type) {
- do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_add_ble_device, bd_addr,
- addr_type, dev_type));
+ do_in_main_thread(FROM_HERE, base::Bind(bta_dm_add_ble_device, bd_addr,
+ addr_type, dev_type));
}
/*******************************************************************************
@@ -484,8 +482,8 @@
******************************************************************************/
void BTA_DmBlePasskeyReply(const RawAddress& bd_addr, bool accept,
uint32_t passkey) {
- do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_ble_passkey_reply, bd_addr,
- accept, accept ? passkey : 0));
+ do_in_main_thread(FROM_HERE, base::Bind(bta_dm_ble_passkey_reply, bd_addr,
+ accept, accept ? passkey : 0));
}
/*******************************************************************************
@@ -502,8 +500,8 @@
*
******************************************************************************/
void BTA_DmBleConfirmReply(const RawAddress& bd_addr, bool accept) {
- do_in_bta_thread(FROM_HERE,
- base::Bind(bta_dm_ble_confirm_reply, bd_addr, accept));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(bta_dm_ble_confirm_reply, bd_addr, accept));
}
/*******************************************************************************
@@ -520,7 +518,7 @@
******************************************************************************/
void BTA_DmBleSecurityGrant(const RawAddress& bd_addr,
tBTA_DM_BLE_SEC_GRANT res) {
- do_in_bta_thread(FROM_HERE, base::Bind(BTM_SecurityGrant, bd_addr, res));
+ do_in_main_thread(FROM_HERE, base::Bind(BTM_SecurityGrant, bd_addr, res));
}
/*******************************************************************************
@@ -546,9 +544,9 @@
uint16_t min_conn_int, uint16_t max_conn_int,
uint16_t slave_latency,
uint16_t supervision_tout) {
- do_in_bta_thread(FROM_HERE,
- base::Bind(bta_dm_ble_set_conn_params, bd_addr, min_conn_int,
- max_conn_int, slave_latency, supervision_tout));
+ do_in_main_thread(
+ FROM_HERE, base::Bind(bta_dm_ble_set_conn_params, bd_addr, min_conn_int,
+ max_conn_int, slave_latency, supervision_tout));
}
/*******************************************************************************
@@ -565,13 +563,8 @@
*
******************************************************************************/
void BTA_DmSetBleConnScanParams(uint32_t scan_interval, uint32_t scan_window) {
- do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_ble_set_conn_scan_params,
- scan_interval, scan_window));
-}
-
-/** Set BLE connectable mode to auto connect */
-void BTA_DmBleStartAutoConn() {
- do_in_bta_thread(FROM_HERE, base::Bind(BTM_BleStartAutoConn));
+ do_in_main_thread(FROM_HERE, base::Bind(bta_dm_ble_set_conn_scan_params,
+ scan_interval, scan_window));
}
/*******************************************************************************
@@ -729,7 +722,7 @@
uint16_t min_int, uint16_t max_int,
uint16_t latency, uint16_t timeout,
uint16_t min_ce_len, uint16_t max_ce_len) {
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE, base::Bind(bta_dm_ble_update_conn_params, bd_addr, min_int,
max_int, latency, timeout, min_ce_len, max_ce_len));
}
@@ -747,8 +740,8 @@
******************************************************************************/
void BTA_DmBleConfigLocalPrivacy(bool privacy_enable) {
#if (BLE_PRIVACY_SPT == TRUE)
- do_in_bta_thread(FROM_HERE,
- base::Bind(bta_dm_ble_config_local_privacy, privacy_enable));
+ do_in_main_thread(
+ FROM_HERE, base::Bind(bta_dm_ble_config_local_privacy, privacy_enable));
#else
UNUSED(privacy_enable);
#endif
@@ -766,15 +759,15 @@
*
******************************************************************************/
void BTA_DmBleGetEnergyInfo(tBTA_BLE_ENERGY_INFO_CBACK* p_cmpl_cback) {
- do_in_bta_thread(FROM_HERE,
- base::Bind(bta_dm_ble_get_energy_info, p_cmpl_cback));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(bta_dm_ble_get_energy_info, p_cmpl_cback));
}
/** This function is to set maximum LE data packet size */
void BTA_DmBleSetDataLength(const RawAddress& remote_device,
uint16_t tx_data_length) {
- do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_ble_set_data_length,
- remote_device, tx_data_length));
+ do_in_main_thread(FROM_HERE, base::Bind(bta_dm_ble_set_data_length,
+ remote_device, tx_data_length));
}
/*******************************************************************************
@@ -803,8 +796,8 @@
tBTA_DM_ENCRYPT_CBACK* p_callback,
tBTA_DM_BLE_SEC_ACT sec_act) {
APPL_TRACE_API("%s", __func__);
- do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_set_encryption, bd_addr,
- transport, p_callback, sec_act));
+ do_in_main_thread(FROM_HERE, base::Bind(bta_dm_set_encryption, bd_addr,
+ transport, p_callback, sec_act));
}
/*******************************************************************************
@@ -822,7 +815,7 @@
******************************************************************************/
void BTA_DmCloseACL(const RawAddress& bd_addr, bool remove_dev,
tBTA_TRANSPORT transport) {
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE, base::Bind(bta_dm_close_acl, bd_addr, remove_dev, transport));
}
@@ -844,7 +837,7 @@
extern void BTA_DmBleObserve(bool start, uint8_t duration,
tBTA_DM_SEARCH_CBACK* p_results_cb) {
APPL_TRACE_API("%s:start = %d ", __func__, start);
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE, base::Bind(bta_dm_ble_observe, start, duration, p_results_cb));
}
diff --git a/bta/dm/bta_dm_cfg.cc b/bta/dm/bta_dm_cfg.cc
index 91053a1..438f329 100644
--- a/bta/dm/bta_dm_cfg.cc
+++ b/bta/dm/bta_dm_cfg.cc
@@ -28,6 +28,7 @@
#include "bt_target.h"
#include "bta_api.h"
#include "bta_dm_int.h"
+#include "bta_hh_api.h"
#include "bta_jv_api.h"
#include "bta_sys.h"
@@ -116,8 +117,8 @@
const tBTA_DM_RM* p_bta_dm_rm_cfg = &bta_dm_rm_cfg[0];
#define BTA_DM_NUM_PM_ENTRY \
- 23 /* number of entries in bta_dm_pm_cfg except the first */
-#define BTA_DM_NUM_PM_SPEC 15 /* number of entries in bta_dm_pm_spec */
+ 25 /* number of entries in bta_dm_pm_cfg except the first */
+#define BTA_DM_NUM_PM_SPEC 16 /* number of entries in bta_dm_pm_spec */
tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_CFG
bta_dm_pm_cfg[BTA_DM_NUM_PM_ENTRY + 1] = {
@@ -126,19 +127,23 @@
{BTA_ID_AG, BTA_ALL_APP_ID,
0}, /* ag uses first spec table for app id 0 */
{BTA_ID_CT, 1, 1}, /* ct (BTA_ID_CT,APP ID=1) spec table */
- {BTA_ID_CG, BTA_ALL_APP_ID, 1}, /* cg resue ct spec table */
- {BTA_ID_DG, BTA_ALL_APP_ID, 2}, /* dg spec table */
- {BTA_ID_AV, BTA_ALL_APP_ID, 4}, /* av spec table */
- {BTA_ID_AVK, BTA_ALL_APP_ID, 12}, /* avk spec table */
- {BTA_ID_FTC, BTA_ALL_APP_ID, 6}, /* ftc spec table */
- {BTA_ID_FTS, BTA_ALL_APP_ID, 7}, /* fts spec table */
- {BTA_ID_HD, BTA_ALL_APP_ID, 3}, /* hd spec table */
- {BTA_ID_HH, BTA_ALL_APP_ID, 5}, /* hh spec table */
- {BTA_ID_PBC, BTA_ALL_APP_ID, 2}, /* reuse dg spec table */
- {BTA_ID_PBS, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */
- {BTA_ID_OPC, BTA_ALL_APP_ID, 6}, /* reuse ftc spec table */
- {BTA_ID_OPS, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */
- {BTA_ID_MSE, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */
+ {BTA_ID_CG, BTA_ALL_APP_ID, 1}, /* cg resue ct spec table */
+ {BTA_ID_DG, BTA_ALL_APP_ID, 2}, /* dg spec table */
+ {BTA_ID_AV, BTA_ALL_APP_ID, 4}, /* av spec table */
+ {BTA_ID_AVK, BTA_ALL_APP_ID, 12}, /* avk spec table */
+ {BTA_ID_FTC, BTA_ALL_APP_ID, 6}, /* ftc spec table */
+ {BTA_ID_FTS, BTA_ALL_APP_ID, 7}, /* fts spec table */
+ {BTA_ID_HD, BTA_ALL_APP_ID, 3}, /* hd spec table */
+ {BTA_ID_HH, BTA_HH_APP_ID_JOY, 5}, /* app BTA_HH_APP_ID_JOY,
+ similar to hh spec table */
+ {BTA_ID_HH, BTA_HH_APP_ID_GPAD, 5}, /* app BTA_HH_APP_ID_GPAD,
+ similar to hh spec table */
+ {BTA_ID_HH, BTA_ALL_APP_ID, 6}, /* hh spec table */
+ {BTA_ID_PBC, BTA_ALL_APP_ID, 2}, /* reuse dg spec table */
+ {BTA_ID_PBS, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */
+ {BTA_ID_OPC, BTA_ALL_APP_ID, 6}, /* reuse ftc spec table */
+ {BTA_ID_OPS, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */
+ {BTA_ID_MSE, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */
{BTA_ID_JV, BTA_JV_PM_ID_1,
6}, /* app BTA_JV_PM_ID_1, reuse ftc spec table */
{BTA_ID_JV, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */
@@ -166,8 +171,9 @@
{BTA_DM_PM_NO_ACTION, 0}}, /* sco open, active */
{{BTA_DM_PM_SNIFF_A2DP_IDX, 7000},
{BTA_DM_PM_NO_ACTION, 0}}, /* sco close sniff */
- {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
- {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+ {{BTA_DM_PM_SNIFF_A2DP_IDX, 7000},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
{{BTA_DM_PM_RETRY, 7000},
{BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
}},
@@ -236,7 +242,7 @@
/* AV : 4 */
{(BTA_DM_PM_SNIFF), /* allow sniff */
#if (BTM_SSR_INCLUDED == TRUE)
- (BTA_DM_PM_SSR0), /* the SSR entry */
+ (BTA_DM_PM_SSR2), /* the SSR entry */
#endif
{
{{BTA_DM_PM_SNIFF_A2DP_IDX, 7000},
@@ -253,7 +259,29 @@
{BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
}},
- /* HH : 5 */
+ /* HH for joysticks and gamepad : 5 */
+ {(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+ (BTA_DM_PM_SSR1), /* the SSR entry */
+#endif
+ {
+ {{BTA_DM_PM_SNIFF6, BTA_DM_PM_HH_OPEN_DELAY},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */
+ {{BTA_DM_PM_NO_ACTION, 0},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* sco close, used for HH suspend */
+ {{BTA_DM_PM_SNIFF6, BTA_DM_PM_HH_IDLE_DELAY},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+ {{BTA_DM_PM_SNIFF6, BTA_DM_PM_HH_ACTIVE_DELAY},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+ {{BTA_DM_PM_NO_ACTION, 0},
+ {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+ }},
+
+ /* HH : 6 */
{(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
#if (BTM_SSR_INCLUDED == TRUE)
(BTA_DM_PM_SSR1), /* the SSR entry */
@@ -275,7 +303,7 @@
{BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
}},
- /* FTC, OPC, JV : 6 */
+ /* FTC, OPC, JV : 7 */
{(BTA_DM_PM_SNIFF), /* allow sniff */
#if (BTM_SSR_INCLUDED == TRUE)
(BTA_DM_PM_SSR2), /* the SSR entry */
@@ -295,7 +323,7 @@
{BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
}},
- /* FTS, PBS, OPS, MSE, BTA_JV_PM_ID_1 : 7 */
+ /* FTS, PBS, OPS, MSE, BTA_JV_PM_ID_1 : 8 */
{(BTA_DM_PM_SNIFF), /* allow sniff */
#if (BTM_SSR_INCLUDED == TRUE)
(BTA_DM_PM_SSR2), /* the SSR entry */
@@ -315,7 +343,7 @@
{BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
}},
- /* HL : 8 */
+ /* HL : 9 */
{(BTA_DM_PM_SNIFF), /* allow sniff */
#if (BTM_SSR_INCLUDED == TRUE)
(BTA_DM_PM_SSR2), /* the SSR entry */
@@ -336,7 +364,7 @@
{BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
}},
- /* PANU : 9 */
+ /* PANU : 10 */
{(BTA_DM_PM_SNIFF), /* allow sniff */
#if (BTM_SSR_INCLUDED == TRUE)
(BTA_DM_PM_SSR2), /* the SSR entry */
@@ -356,7 +384,7 @@
{BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
}},
- /* NAP : 10 */
+ /* NAP : 11 */
{(BTA_DM_PM_SNIFF), /* allow sniff */
#if (BTM_SSR_INCLUDED == TRUE)
(BTA_DM_PM_SSR2), /* the SSR entry */
@@ -377,7 +405,7 @@
{BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
}},
- /* HS : 11 */
+ /* HS : 12 */
{(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
#if (BTM_SSR_INCLUDED == TRUE)
(BTA_DM_PM_SSR2), /* the SSR entry */
@@ -398,7 +426,7 @@
{BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
}},
- /* AVK : 12 */
+ /* AVK : 13 */
{(BTA_DM_PM_SNIFF), /* allow sniff */
#if (BTM_SSR_INCLUDED == TRUE)
(BTA_DM_PM_SSR2), /* the SSR entry */
@@ -417,7 +445,7 @@
{BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
}}
- /* GATTC : 13 */
+ /* GATTC : 14 */
,
{(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
#if (BTM_SSR_INCLUDED == TRUE)
@@ -437,7 +465,7 @@
{{BTA_DM_PM_RETRY, 5000},
{BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
}}
- /* GATTS : 14 */
+ /* GATTS : 15 */
,
{(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
#if (BTM_SSR_INCLUDED == TRUE)
@@ -474,7 +502,7 @@
/* Please refer to the SNIFF table definitions in bta_api.h.
*
* Adding to or Modifying the Table
- * Additional sniff parameter entries can be added for BTA_DM_PM_SNIFF5 -
+ * Additional sniff parameter entries can be added for BTA_DM_PM_SNIFF6 -
* BTA_DM_PM_SNIFF7.
* Overrides of additional table entries can be specified in bdroid_buildcfg.h.
* If additional
@@ -521,6 +549,9 @@
{BTA_DM_PM_SNIFF5_MAX, BTA_DM_PM_SNIFF5_MIN, BTA_DM_PM_SNIFF5_ATTEMPT,
BTA_DM_PM_SNIFF5_TIMEOUT,
BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF5- HD active */
+ {BTA_DM_PM_SNIFF6_MAX, BTA_DM_PM_SNIFF6_MIN, BTA_DM_PM_SNIFF6_ATTEMPT,
+ BTA_DM_PM_SNIFF6_TIMEOUT,
+ BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF6- HD active */
{BTA_DM_PM_PARK_MAX, BTA_DM_PM_PARK_MIN, BTA_DM_PM_PARK_ATTEMPT,
BTA_DM_PM_PARK_TIMEOUT, BTM_PM_MD_PARK}
@@ -555,8 +586,9 @@
default max latency and min remote timeout as 0, and always read
individual device preference from HH module */
{0, 0, 2},
- {1200, 2, 2}, /* BTA_DM_PM_SSR2 - others (as long as sniff is allowed)*/
- {360, 160, 1600} /* BTA_DM_PM_SSR3 - HD */
+ {1200, 2, 2}, /* BTA_DM_PM_SSR2 - others (as long as sniff is allowed)*/
+ {360, 160, 1600}, /* BTA_DM_PM_SSR3 - HD */
+ {1200, 65534, 65534} /* BTA_DM_PM_SSR4 - A2DP streaming */
};
tBTA_DM_SSR_SPEC* p_bta_dm_ssr_spec = &bta_dm_ssr_spec[0];
diff --git a/bta/dm/bta_dm_ci.cc b/bta/dm/bta_dm_ci.cc
index 3d40480..45784c1 100644
--- a/bta/dm/bta_dm_ci.cc
+++ b/bta/dm/bta_dm_ci.cc
@@ -21,11 +21,12 @@
* This is the API implementation file for the BTA device manager.
*
******************************************************************************/
+#include "bta_dm_ci.h"
#include "bt_common.h"
#include "bta_api.h"
-#include "bta_dm_ci.h"
#include "bta_dm_int.h"
#include "bta_sys.h"
+#include "stack/include/btu.h"
#include <base/bind.h>
#include <memory>
@@ -45,8 +46,8 @@
tBTA_OOB_DATA oob_data, tBTA_AUTH_REQ auth_req)
{
- do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_ci_io_req_act, bd_addr, io_cap,
- oob_data, auth_req));
+ do_in_main_thread(FROM_HERE, base::Bind(bta_dm_ci_io_req_act, bd_addr, io_cap,
+ oob_data, auth_req));
}
/*******************************************************************************
@@ -60,17 +61,17 @@
* Returns void
*
******************************************************************************/
-void bta_dm_ci_rmt_oob(bool accept, const RawAddress& bd_addr, BT_OCTET16 c,
- BT_OCTET16 r) {
+void bta_dm_ci_rmt_oob(bool accept, const RawAddress& bd_addr, const Octet16& c,
+ const Octet16& r) {
std::unique_ptr<tBTA_DM_CI_RMT_OOB> msg =
std::make_unique<tBTA_DM_CI_RMT_OOB>();
msg->bd_addr = bd_addr;
msg->accept = accept;
- memcpy(msg->c, c, BT_OCTET16_LEN);
- memcpy(msg->r, r, BT_OCTET16_LEN);
+ msg->c = c;
+ msg->r = r;
- do_in_bta_thread(FROM_HERE,
- base::Bind(bta_dm_ci_rmt_oob_act, base::Passed(&msg)));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(bta_dm_ci_rmt_oob_act, base::Passed(&msg)));
}
diff --git a/bta/dm/bta_dm_int.h b/bta/dm/bta_dm_int.h
index 6aafd7d..97d7f80 100644
--- a/bta/dm/bta_dm_int.h
+++ b/bta/dm/bta_dm_int.h
@@ -118,8 +118,8 @@
typedef struct {
RawAddress bd_addr;
- BT_OCTET16 c;
- BT_OCTET16 r;
+ Octet16 c;
+ Octet16 r;
bool accept;
} tBTA_DM_CI_RMT_OOB;
@@ -150,7 +150,7 @@
typedef struct {
RawAddress bd_addr;
DEV_CLASS dc;
- LINK_KEY link_key;
+ LinkKey link_key;
tBTA_SERVICE_MASK tm;
bool is_trusted;
uint8_t key_type;
@@ -250,7 +250,7 @@
} tBTA_DM_SRVCS;
#ifndef BTA_DM_NUM_CONN_SRVS
-#define BTA_DM_NUM_CONN_SRVS 10
+#define BTA_DM_NUM_CONN_SRVS 30
#endif
typedef struct {
@@ -510,9 +510,6 @@
uint16_t, uint16_t, uint16_t,
uint16_t);
extern void bta_dm_ble_config_local_privacy(bool);
-extern void bta_dm_ble_set_adv_params(uint16_t adv_int_min,
- uint16_t adv_int_max,
- tBLE_BD_ADDR* p_dir_bda);
extern void bta_dm_ble_set_data_length(const RawAddress&, uint16_t);
diff --git a/bta/dm/bta_dm_pm.cc b/bta/dm/bta_dm_pm.cc
index 731d253..51be1b6 100644
--- a/bta/dm/bta_dm_pm.cc
+++ b/bta/dm/bta_dm_pm.cc
@@ -35,6 +35,7 @@
#include "bta_dm_int.h"
#include "bta_sys.h"
#include "btm_api.h"
+#include "stack/include/btu.h"
static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
uint8_t app_id, const RawAddress& peer_addr);
@@ -64,7 +65,7 @@
* can use it */
#define BTA_DM_PM_SSR_HH BTA_DM_PM_SSR1
#endif
-static void bta_dm_pm_ssr(const RawAddress& peer_addr);
+static void bta_dm_pm_ssr(const RawAddress& peer_addr, int ssr);
#endif
tBTA_DM_CONNECTED_SRVCS bta_dm_conn_srvcs;
@@ -272,7 +273,7 @@
*
******************************************************************************/
static void bta_dm_pm_start_timer(tBTA_PM_TIMER* p_timer, uint8_t timer_idx,
- period_ms_t timeout_ms, uint8_t srvc_id,
+ uint64_t timeout_ms, uint8_t srvc_id,
uint8_t pm_action) {
std::unique_lock<std::recursive_mutex> schedule_lock(pm_timer_schedule_mutex);
std::unique_lock<std::recursive_mutex> state_lock(pm_timer_state_mutex);
@@ -362,6 +363,13 @@
if ((BTA_SYS_CONN_OPEN == status) && p_dev &&
(p_dev->info & BTA_DM_DI_USE_SSR)) {
index = p_bta_dm_pm_spec[p_bta_dm_pm_cfg[i].spec_idx].ssr;
+ } else if (BTA_ID_AV == id) {
+ if (BTA_SYS_CONN_BUSY == status) {
+ /* set SSR4 for A2DP on SYS CONN BUSY */
+ index = BTA_DM_PM_SSR4;
+ } else if (BTA_SYS_CONN_IDLE == status) {
+ index = p_bta_dm_pm_spec[p_bta_dm_pm_cfg[i].spec_idx].ssr;
+ }
}
#endif
@@ -445,7 +453,7 @@
|| index == BTA_DM_PM_SSR_HH
#endif
) {
- bta_dm_pm_ssr(peer_addr);
+ bta_dm_pm_ssr(peer_addr, index);
} else {
uint8_t* p = NULL;
if (((NULL != (p = BTM_ReadLocalFeatures())) &&
@@ -458,7 +466,7 @@
BTM_SetSsrParams(peer_addr, 0, 0, 0);
} else if (status == BTA_SYS_SCO_CLOSE) {
APPL_TRACE_DEBUG("%s: SCO active, back to old SSR", __func__);
- bta_dm_pm_ssr(peer_addr);
+ bta_dm_pm_ssr(peer_addr, BTA_DM_PM_SSR0);
}
}
}
@@ -500,7 +508,7 @@
tBTA_DM_PM_ACTION pm_request,
tBTA_DM_PM_REQ pm_req) {
tBTA_DM_PM_ACTION pm_action = BTA_DM_PM_NO_ACTION;
- period_ms_t timeout_ms = 0;
+ uint64_t timeout_ms = 0;
uint8_t i, j;
tBTA_DM_PM_ACTION failed_pm = 0;
tBTA_DM_PEER_DEVICE* p_peer_device = NULL;
@@ -513,7 +521,7 @@
tBTA_DM_SRVCS* p_srvcs = NULL;
bool timer_started = false;
uint8_t timer_idx, available_timer = BTA_DM_PM_MODE_TIMER_MAX;
- period_ms_t remaining_ms = 0;
+ uint64_t remaining_ms = 0;
if (!bta_dm_cb.device_list.count) return;
@@ -750,9 +758,9 @@
*
******************************************************************************/
#if (BTM_SSR_INCLUDED == TRUE)
-static void bta_dm_pm_ssr(const RawAddress& peer_addr) {
+static void bta_dm_pm_ssr(const RawAddress& peer_addr, int ssr) {
int current_ssr_index;
- int ssr_index = BTA_DM_PM_SSR0;
+ int ssr_index = ssr;
tBTA_DM_SSR_SPEC* p_spec = &p_bta_dm_ssr_spec[ssr_index];
/* go through the connected services */
@@ -837,8 +845,8 @@
static void bta_dm_pm_btm_cback(const RawAddress& bd_addr,
tBTM_PM_STATUS status, uint16_t value,
uint8_t hci_status) {
- do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_pm_btm_status, bd_addr, status,
- value, hci_status));
+ do_in_main_thread(FROM_HERE, base::Bind(bta_dm_pm_btm_status, bd_addr, status,
+ value, hci_status));
}
/*******************************************************************************
@@ -878,7 +886,7 @@
/* no more timers */
if (i == BTA_DM_NUM_PM_TIMER) return;
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE, base::Bind(bta_dm_pm_timer, bta_dm_cb.pm_timer[i].peer_bdaddr,
bta_dm_cb.pm_timer[i].pm_action[j]));
}
@@ -912,7 +920,7 @@
#if (BTM_SSR_INCLUDED == TRUE)
if (p_dev->prev_low) {
/* need to send the SSR paramaters to controller again */
- bta_dm_pm_ssr(p_dev->peer_bdaddr);
+ bta_dm_pm_ssr(p_dev->peer_bdaddr, BTA_DM_PM_SSR0);
}
p_dev->prev_low = BTM_PM_STS_ACTIVE;
#endif
diff --git a/bta/gatt/bta_gattc_act.cc b/bta/gatt/bta_gattc_act.cc
index 8a137dc..90978f6 100644
--- a/bta/gatt/bta_gattc_act.cc
+++ b/bta/gatt/bta_gattc_act.cc
@@ -30,13 +30,13 @@
#include <base/callback.h>
#include "bt_common.h"
#include "bt_target.h"
-#include "bta_closure_api.h"
#include "bta_gattc_int.h"
#include "bta_sys.h"
#include "btif/include/btif_debug_conn.h"
#include "l2c_api.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
+#include "stack/include/btu.h"
#include "stack/l2cap/l2c_int.h"
#include "utl.h"
@@ -192,7 +192,8 @@
/* BTA use the same client interface as BTE GATT statck */
client_if = bta_gattc_cb.cl_rcb[i].client_if;
- do_in_bta_thread(FROM_HERE, base::Bind(&bta_gattc_start_if, client_if));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(&bta_gattc_start_if, client_if));
status = GATT_SUCCESS;
break;
@@ -337,8 +338,8 @@
void bta_gattc_open_fail(tBTA_GATTC_CLCB* p_clcb,
UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
LOG(WARNING) << __func__ << ": Cannot establish Connection. conn_id="
- << +p_clcb->bta_conn_id << ". Return GATT_ERROR(" << +GATT_ERROR
- << ")";
+ << loghex(p_clcb->bta_conn_id) << ". Return GATT_ERROR("
+ << +GATT_ERROR << ")";
bta_gattc_send_open_cback(p_clcb->p_rcb, GATT_ERROR, p_clcb->bda,
p_clcb->bta_conn_id, p_clcb->transport, 0);
@@ -461,7 +462,7 @@
VLOG(1) << __func__ << ": server cache state=" << +p_clcb->p_srcb->state;
if (p_data != NULL) {
- VLOG(1) << __func__ << ": conn_id=" << +p_data->hdr.layer_specific;
+ VLOG(1) << __func__ << ": conn_id=" << loghex(p_data->hdr.layer_specific);
p_clcb->bta_conn_id = p_data->int_conn.hdr.layer_specific;
GATT_GetConnectionInfor(p_data->hdr.layer_specific, &gatt_if, p_clcb->bda,
@@ -473,7 +474,7 @@
if (p_clcb->p_srcb->mtu == 0) p_clcb->p_srcb->mtu = GATT_DEF_BLE_MTU_SIZE;
/* start database cache if needed */
- if (p_clcb->p_srcb->srvc_cache.empty() ||
+ if (p_clcb->p_srcb->gatt_database.IsEmpty() ||
p_clcb->p_srcb->state != BTA_GATTC_SERV_IDLE) {
if (p_clcb->p_srcb->state == BTA_GATTC_SERV_IDLE) {
p_clcb->p_srcb->state = BTA_GATTC_SERV_LOAD;
@@ -534,7 +535,7 @@
tBTA_GATTC_RCB* p_clreg = p_clcb->p_rcb;
tBTA_GATTC cb_data;
- VLOG(1) << __func__ << ": conn_id=" << +p_clcb->bta_conn_id;
+ VLOG(1) << __func__ << ": conn_id=" << loghex(p_clcb->bta_conn_id);
cb_data.close.client_if = p_clcb->p_rcb->client_if;
cb_data.close.conn_id = p_clcb->bta_conn_id;
@@ -574,7 +575,8 @@
/** close a GATTC connection while in discovery state */
void bta_gattc_disc_close(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
- VLOG(1) << __func__ << ": Discovery cancel conn_id=" << +p_clcb->bta_conn_id;
+ VLOG(1) << __func__
+ << ": Discovery cancel conn_id=" << loghex(p_clcb->bta_conn_id);
if (p_clcb->disc_active)
bta_gattc_reset_discover_st(p_clcb->p_srcb, GATT_ERROR);
@@ -594,7 +596,6 @@
void bta_gattc_set_discover_st(tBTA_GATTC_SERV* p_srcb) {
uint8_t i;
- L2CA_EnableUpdateBleConnParams(p_srcb->server_bda, false);
for (i = 0; i < BTA_GATTC_CLCB_MAX; i++) {
if (bta_gattc_cb.clcb[i].p_srcb == p_srcb) {
bta_gattc_cb.clcb[i].status = GATT_SUCCESS;
@@ -632,7 +633,7 @@
/** Start a discovery on server */
void bta_gattc_start_discover(tBTA_GATTC_CLCB* p_clcb,
UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
- VLOG(1) << __func__ << ": conn_id:" << +p_clcb->bta_conn_id
+ VLOG(1) << __func__ << ": conn_id:" << loghex(p_clcb->bta_conn_id)
<< " p_clcb->p_srcb->state:" << +p_clcb->p_srcb->state;
if (((p_clcb->p_q_cmd == NULL ||
@@ -655,11 +656,9 @@
/* set all srcb related clcb into discovery ST */
bta_gattc_set_discover_st(p_clcb->p_srcb);
- p_clcb->status = bta_gattc_init_cache(p_clcb->p_srcb);
- if (p_clcb->status == GATT_SUCCESS) {
- p_clcb->status = bta_gattc_discover_pri_service(
- p_clcb->bta_conn_id, p_clcb->p_srcb, GATT_DISC_SRVC_ALL);
- }
+ bta_gattc_init_cache(p_clcb->p_srcb);
+ p_clcb->status = bta_gattc_discover_pri_service(
+ p_clcb->bta_conn_id, p_clcb->p_srcb, GATT_DISC_SRVC_ALL);
if (p_clcb->status != GATT_SUCCESS) {
LOG(ERROR) << "discovery on server failed";
bta_gattc_reset_discover_st(p_clcb->p_srcb, p_clcb->status);
@@ -683,7 +682,7 @@
UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
tBTA_GATTC_DATA* p_q_cmd = p_clcb->p_q_cmd;
- VLOG(1) << __func__ << ": conn_id=" << +p_clcb->bta_conn_id;
+ VLOG(1) << __func__ << ": conn_id=" << loghex(p_clcb->bta_conn_id);
if (p_clcb->transport == BTA_TRANSPORT_LE)
L2CA_EnableUpdateBleConnParams(p_clcb->p_srcb->server_bda, true);
@@ -693,16 +692,15 @@
if (p_clcb->status != GATT_SUCCESS) {
/* clean up cache */
if (p_clcb->p_srcb) {
- // clear reallocating
- std::vector<tBTA_GATTC_SERVICE>().swap(p_clcb->p_srcb->srvc_cache);
+ p_clcb->p_srcb->gatt_database.Clear();
}
/* used to reset cache in application */
bta_gattc_cache_reset(p_clcb->p_srcb->server_bda);
}
+
if (p_clcb->p_srcb) {
- /* release pending attribute list buffer */
- p_clcb->p_srcb->pending_discovery.clear();
+ p_clcb->p_srcb->pending_discovery.Clear();
}
if (p_clcb->auto_update == BTA_GATTC_DISC_WAITING) {
@@ -724,6 +722,12 @@
*/
if (p_q_cmd != p_clcb->p_q_cmd) osi_free_and_reset((void**)&p_q_cmd);
}
+
+ if (p_clcb->p_rcb->p_cback) {
+ tBTA_GATTC bta_gattc;
+ bta_gattc.remote_bda = p_clcb->p_srcb->server_bda;
+ (*p_clcb->p_rcb->p_cback)(BTA_GATTC_SRVC_DISC_DONE_EVT, &bta_gattc);
+ }
}
/** Read an attribute */
@@ -981,8 +985,8 @@
void bta_gattc_search(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
tGATT_STATUS status = GATT_INTERNAL_ERROR;
tBTA_GATTC cb_data;
- VLOG(1) << __func__ << ": conn_id=" << +p_clcb->bta_conn_id;
- if (p_clcb->p_srcb && !p_clcb->p_srcb->srvc_cache.empty()) {
+ VLOG(1) << __func__ << ": conn_id=" << loghex(p_clcb->bta_conn_id);
+ if (p_clcb->p_srcb && !p_clcb->p_srcb->gatt_database.IsEmpty()) {
status = GATT_SUCCESS;
/* search the local cache of a server device */
bta_gattc_search_service(p_clcb, p_data->api_search.p_srvc_uuid);
@@ -1080,8 +1084,8 @@
VLOG(1) << __func__ << ": cif:" << +gattc_if;
- do_in_bta_thread(FROM_HERE,
- base::Bind(&bta_gattc_process_enc_cmpl, gattc_if, bda));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(&bta_gattc_process_enc_cmpl, gattc_if, bda));
}
/** process refresh API to delete cache and start a new discovery if currently
@@ -1106,8 +1110,7 @@
}
/* in all other cases, mark it and delete the cache */
- // clear reallocating
- std::vector<tBTA_GATTC_SERVICE>().swap(p_srvc_cb->srvc_cache);
+ p_srvc_cb->gatt_database.Clear();
}
/* used to reset cache in application */
@@ -1124,10 +1127,10 @@
Uuid gattp_uuid = Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER);
Uuid srvc_chg_uuid = Uuid::From16Bit(GATT_UUID_GATT_SRV_CHGD);
- const tBTA_GATTC_CHARACTERISTIC* p_char =
+ const gatt::Characteristic* p_char =
bta_gattc_get_characteristic_srcb(p_srcb, p_notify->handle);
if (!p_char) return false;
- const tBTA_GATTC_SERVICE* p_svc =
+ const gatt::Service* p_svc =
bta_gattc_get_service_for_handle_srcb(p_srcb, p_char->value_handle);
if (!p_svc || p_svc->uuid != gattp_uuid || p_char->uuid != srvc_chg_uuid) {
return false;
@@ -1189,7 +1192,7 @@
<< StringPrintf(
": check p_data->att_value.handle=%d p_data->handle=%d",
p_data->att_value.handle, p_data->handle);
- VLOG(1) << "is_notify", p_notify->is_notify;
+ VLOG(1) << "is_notify " << p_notify->is_notify;
p_notify->is_notify = (op == GATTC_OPTYPE_INDICATION) ? false : true;
p_notify->len = p_data->att_value.len;
@@ -1237,6 +1240,20 @@
}
tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+ /* connection not open yet */
+ if (p_clcb == NULL) {
+ p_clcb = bta_gattc_clcb_alloc(gatt_if, remote_bda, transport);
+
+ if (p_clcb == NULL) {
+ LOG(ERROR) << __func__ << ": No resources";
+ return;
+ }
+
+ p_clcb->bta_conn_id = conn_id;
+ p_clcb->transport = transport;
+
+ bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CONN_EVT, NULL);
+ }
notify.handle = handle;
@@ -1247,21 +1264,6 @@
/* if app registered for the notification */
if (bta_gattc_check_notif_registry(p_clrcb, p_srcb, ¬ify)) {
- /* connection not open yet */
- if (p_clcb == NULL) {
- p_clcb = bta_gattc_clcb_alloc(gatt_if, remote_bda, transport);
-
- if (p_clcb == NULL) {
- LOG(ERROR) << "No resources";
- return;
- }
-
- p_clcb->bta_conn_id = conn_id;
- p_clcb->transport = transport;
-
- bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CONN_EVT, NULL);
- }
-
if (p_clcb != NULL)
bta_gattc_proc_other_indication(p_clcb, op, p_data, ¬ify);
}
diff --git a/bta/gatt/bta_gattc_api.cc b/bta/gatt/bta_gattc_api.cc
index bec0081..9b0bd9e 100644
--- a/bta/gatt/bta_gattc_api.cc
+++ b/bta/gatt/bta_gattc_api.cc
@@ -30,11 +30,11 @@
#include <base/bind_helpers.h>
#include <base/callback.h>
#include "bt_common.h"
-#include "bta_closure_api.h"
#include "bta_gatt_api.h"
#include "bta_gattc_int.h"
#include "bta_sys.h"
#include "device/include/controller.h"
+#include "stack/include/btu.h"
using bluetooth::Uuid;
@@ -62,7 +62,7 @@
return;
}
- do_in_bta_thread(FROM_HERE, base::Bind(&bta_gattc_disable));
+ do_in_main_thread(FROM_HERE, base::Bind(&bta_gattc_disable));
bta_sys_deregister(BTA_ID_GATTC);
}
@@ -76,8 +76,9 @@
if (!bta_sys_is_register(BTA_ID_GATTC))
bta_sys_register(BTA_ID_GATTC, &bta_gattc_reg);
- do_in_bta_thread(FROM_HERE, base::Bind(&bta_gattc_register, Uuid::GetRandom(),
- p_client_cb, std::move(cb)));
+ do_in_main_thread(
+ FROM_HERE, base::Bind(&bta_gattc_register, Uuid::GetRandom(), p_client_cb,
+ std::move(cb)));
}
static void app_deregister_impl(tGATT_IF client_if) {
@@ -96,7 +97,7 @@
*
******************************************************************************/
void BTA_GATTC_AppDeregister(tGATT_IF client_if) {
- do_in_bta_thread(FROM_HERE, base::Bind(&app_deregister_impl, client_if));
+ do_in_main_thread(FROM_HERE, base::Bind(&app_deregister_impl, client_if));
}
/*******************************************************************************
@@ -246,15 +247,14 @@
bta_sys_sendmsg(p_buf);
}
-void BTA_GATTC_DiscoverServiceByUuid(uint16_t conn_id,
- const Uuid& p_srvc_uuid) {
- tGATT_DISC_PARAM* param = new tGATT_DISC_PARAM;
- param->s_handle = 0x0001;
- param->e_handle = 0xFFFF;
- param->service = p_srvc_uuid;
- do_in_bta_thread(FROM_HERE,
- base::Bind(base::IgnoreResult(&GATTC_Discover), conn_id,
- GATT_DISC_SRVC_BY_UUID, base::Owned(param)));
+void BTA_GATTC_DiscoverServiceByUuid(uint16_t conn_id, const Uuid& srvc_uuid) {
+ do_in_main_thread(
+ FROM_HERE,
+ base::Bind(
+ base::IgnoreResult<tGATT_STATUS (*)(uint16_t, tGATT_DISC_TYPE,
+ uint16_t, uint16_t, const Uuid&)>(
+ &GATTC_Discover),
+ conn_id, GATT_DISC_SRVC_BY_UUID, 0x0001, 0xFFFF, srvc_uuid));
}
/*******************************************************************************
@@ -266,10 +266,10 @@
*
* Parameters conn_id: connection ID which identify the server.
*
- * Returns returns list of tBTA_GATTC_SERVICE or NULL.
+ * Returns returns list of gatt::Service or NULL.
*
******************************************************************************/
-const std::vector<tBTA_GATTC_SERVICE>* BTA_GATTC_GetServices(uint16_t conn_id) {
+const std::vector<gatt::Service>* BTA_GATTC_GetServices(uint16_t conn_id) {
return bta_gattc_get_services(conn_id);
}
@@ -283,11 +283,11 @@
* Parameters conn_id - connection ID which identify the server.
* handle - characteristic handle
*
- * Returns returns pointer to tBTA_GATTC_CHARACTERISTIC or NULL.
+ * Returns returns pointer to gatt::Characteristic or NULL.
*
******************************************************************************/
-const tBTA_GATTC_CHARACTERISTIC* BTA_GATTC_GetCharacteristic(uint16_t conn_id,
- uint16_t handle) {
+const gatt::Characteristic* BTA_GATTC_GetCharacteristic(uint16_t conn_id,
+ uint16_t handle) {
return bta_gattc_get_characteristic(conn_id, handle);
}
@@ -301,25 +301,25 @@
* Parameters conn_id - connection ID which identify the server.
* handle - descriptor handle
*
- * Returns returns pointer to tBTA_GATTC_DESCRIPTOR or NULL.
+ * Returns returns pointer to gatt::Descriptor or NULL.
*
******************************************************************************/
-const tBTA_GATTC_DESCRIPTOR* BTA_GATTC_GetDescriptor(uint16_t conn_id,
- uint16_t handle) {
+const gatt::Descriptor* BTA_GATTC_GetDescriptor(uint16_t conn_id,
+ uint16_t handle) {
return bta_gattc_get_descriptor(conn_id, handle);
}
/* Return characteristic that owns descriptor with handle equal to |handle|, or
* NULL */
-const tBTA_GATTC_CHARACTERISTIC* BTA_GATTC_GetOwningCharacteristic(
- uint16_t conn_id, uint16_t handle) {
+const gatt::Characteristic* BTA_GATTC_GetOwningCharacteristic(uint16_t conn_id,
+ uint16_t handle) {
return bta_gattc_get_owning_characteristic(conn_id, handle);
}
/* Return service that owns descriptor or characteristic with handle equal to
* |handle|, or NULL */
-const tBTA_GATTC_SERVICE* BTA_GATTC_GetOwningService(uint16_t conn_id,
- uint16_t handle) {
+const gatt::Service* BTA_GATTC_GetOwningService(uint16_t conn_id,
+ uint16_t handle) {
return bta_gattc_get_service_for_handle(conn_id, handle);
}
@@ -639,7 +639,7 @@
uint8_t i;
if (!handle) {
- LOG(ERROR) << "deregistration failed, handle is 0";
+ LOG(ERROR) << __func__ << ": registration failed, handle is 0";
return status;
}
@@ -735,6 +735,6 @@
*
******************************************************************************/
void BTA_GATTC_Refresh(const RawAddress& remote_bda) {
- do_in_bta_thread(FROM_HERE,
- base::Bind(&bta_gattc_process_api_refresh, remote_bda));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(&bta_gattc_process_api_refresh, remote_bda));
}
diff --git a/bta/gatt/bta_gattc_cache.cc b/bta/gatt/bta_gattc_cache.cc
index 60224a3..6c793f1 100644
--- a/bta/gatt/bta_gattc_cache.cc
+++ b/bta/gatt/bta_gattc_cache.cc
@@ -31,6 +31,7 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
+#include <sstream>
#include "bt_common.h"
#include "bta_gattc_int.h"
@@ -38,30 +39,39 @@
#include "btm_api.h"
#include "btm_ble_api.h"
#include "btm_int.h"
+#include "database.h"
+#include "database_builder.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
#include "sdp_api.h"
#include "sdpdefs.h"
#include "utl.h"
-using bluetooth::Uuid;
using base::StringPrintf;
+using bluetooth::Uuid;
+using gatt::Characteristic;
+using gatt::Database;
+using gatt::DatabaseBuilder;
+using gatt::Descriptor;
+using gatt::IncludedService;
+using gatt::Service;
+using gatt::StoredAttribute;
static void bta_gattc_cache_write(const RawAddress& server_bda,
- uint16_t num_attr, tBTA_GATTC_NV_ATTR* attr);
-static void bta_gattc_char_dscpt_disc_cmpl(uint16_t conn_id,
- tBTA_GATTC_SERV* p_srvc_cb);
+ const std::vector<StoredAttribute>& attr);
static tGATT_STATUS bta_gattc_sdp_service_disc(uint16_t conn_id,
tBTA_GATTC_SERV* p_server_cb);
-const tBTA_GATTC_DESCRIPTOR* bta_gattc_get_descriptor_srcb(
- tBTA_GATTC_SERV* p_srcb, uint16_t handle);
-tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_characteristic_srcb(
- tBTA_GATTC_SERV* p_srcb, uint16_t handle);
+const Descriptor* bta_gattc_get_descriptor_srcb(tBTA_GATTC_SERV* p_srcb,
+ uint16_t handle);
+const Characteristic* bta_gattc_get_characteristic_srcb(tBTA_GATTC_SERV* p_srcb,
+ uint16_t handle);
+static void bta_gattc_explore_srvc_finished(uint16_t conn_id,
+ tBTA_GATTC_SERV* p_srvc_cb);
#define BTA_GATT_SDP_DB_SIZE 4096
#define GATT_CACHE_PREFIX "/data/misc/bluetooth/gatt_cache_"
-#define GATT_CACHE_VERSION 4
+#define GATT_CACHE_VERSION 5
static void bta_gattc_generate_cache_file_name(char* buffer, size_t buffer_len,
const RawAddress& bda) {
@@ -83,195 +93,42 @@
/* utility functions */
/* debug function to display the server cache */
-static void display_db(const std::vector<tBTA_GATTC_SERVICE>& cache) {
- for (const tBTA_GATTC_SERVICE& service : cache) {
- LOG(ERROR) << "Service: s_handle=" << loghex(service.s_handle)
- << ", e_handle=" << loghex(service.e_handle)
- << ", inst=" << loghex(service.handle)
- << ", uuid=" << service.uuid;
-
- if (service.characteristics.empty()) {
- LOG(ERROR) << "\t No characteristics";
- continue;
- }
-
- for (const tBTA_GATTC_CHARACTERISTIC& c : service.characteristics) {
- LOG(ERROR) << "\t Characteristic value_handle=" << loghex(c.value_handle)
- << ", uuid=" << c.uuid << ", prop=" << loghex(c.properties);
-
- if (c.descriptors.empty()) {
- LOG(ERROR) << "\t\t No descriptors";
- continue;
- }
-
- for (const tBTA_GATTC_DESCRIPTOR& d : c.descriptors) {
- LOG(ERROR) << "\t\t Descriptor handle=" << loghex(d.handle)
- << ", uuid=" << d.uuid;
- }
- }
+static void bta_gattc_display_cache_server(const Database& database) {
+ LOG(INFO) << "<================Start Server Cache =============>";
+ std::istringstream iss(database.ToString());
+ for (std::string line; std::getline(iss, line);) {
+ LOG(INFO) << line;
}
-}
-
-/* debug function to display the server cache */
-static void bta_gattc_display_cache_server(
- const std::vector<tBTA_GATTC_SERVICE>& cache) {
- LOG(ERROR) << "<================Start Server Cache =============>";
- display_db(cache);
- LOG(ERROR) << "<================End Server Cache =============>";
- LOG(ERROR) << " ";
+ LOG(INFO) << "<================End Server Cache =============>";
}
/** debug function to display the exploration list */
-static void bta_gattc_display_explore_record(
- const std::vector<tBTA_GATTC_SERVICE>& cache) {
- LOG(ERROR) << "<================Start Explore Queue =============>";
- display_db(cache);
- LOG(ERROR) << "<================ End Explore Queue =============>";
- LOG(ERROR) << " ";
+static void bta_gattc_display_explore_record(const DatabaseBuilder& database) {
+ LOG(INFO) << "<================Start Explore Queue =============>";
+ std::istringstream iss(database.ToString());
+ for (std::string line; std::getline(iss, line);) {
+ LOG(INFO) << line;
+ }
+ LOG(INFO) << "<================ End Explore Queue =============>";
}
#endif /* BTA_GATT_DEBUG == TRUE */
-/*******************************************************************************
- *
- * Function bta_gattc_init_cache
- *
- * Description Initialize the database cache and discovery related
- * resources.
- *
- * Returns status
- *
- ******************************************************************************/
-tGATT_STATUS bta_gattc_init_cache(tBTA_GATTC_SERV* p_srvc_cb) {
- // clear reallocating
- std::vector<tBTA_GATTC_SERVICE>().swap(p_srvc_cb->srvc_cache);
- std::vector<tBTA_GATTC_SERVICE>().swap(p_srvc_cb->pending_discovery);
- return GATT_SUCCESS;
+/** Initialize the database cache and discovery related resources */
+void bta_gattc_init_cache(tBTA_GATTC_SERV* p_srvc_cb) {
+ p_srvc_cb->gatt_database = gatt::Database();
+ p_srvc_cb->pending_discovery.Clear();
}
-tBTA_GATTC_SERVICE* bta_gattc_find_matching_service(
- std::vector<tBTA_GATTC_SERVICE>& services, uint16_t handle) {
- for (tBTA_GATTC_SERVICE& service : services) {
- if (handle >= service.s_handle && handle <= service.e_handle)
+const Service* bta_gattc_find_matching_service(
+ const std::vector<Service>& services, uint16_t handle) {
+ for (const Service& service : services) {
+ if (handle >= service.handle && handle <= service.end_handle)
return &service;
}
return nullptr;
}
-/** Add a service into GATT database */
-static void add_service_to_gatt_db(std::vector<tBTA_GATTC_SERVICE>& gatt_db,
- uint16_t s_handle, uint16_t e_handle,
- const Uuid& uuid, bool is_primary) {
-#if (BTA_GATT_DEBUG == TRUE)
- VLOG(1) << "Add a service into GATT DB";
-#endif
-
- gatt_db.emplace_back(tBTA_GATTC_SERVICE{
- .s_handle = s_handle,
- .e_handle = e_handle,
- .is_primary = is_primary,
- .uuid = uuid,
- .handle = s_handle,
- });
-}
-
-/** Add a characteristic into GATT database */
-static void add_characteristic_to_gatt_db(
- std::vector<tBTA_GATTC_SERVICE>& gatt_db, uint16_t attr_handle,
- uint16_t value_handle, const Uuid& uuid, uint8_t property) {
-#if (BTA_GATT_DEBUG == TRUE)
- VLOG(1) << __func__
- << ": Add a characteristic into service. handle:" << +value_handle
- << " uuid:" << uuid << " property=0x" << std::hex << +property;
-#endif
-
- tBTA_GATTC_SERVICE* service =
- bta_gattc_find_matching_service(gatt_db, attr_handle);
- if (!service) {
- LOG(ERROR) << "Illegal action to add char/descr/incl srvc for non-existing "
- "service!";
- return;
- }
-
- /* TODO(jpawlowski): We should use attribute handle, not value handle to refer
- to characteristic.
- This is just a temporary workaround.
- */
- if (service->e_handle < value_handle) service->e_handle = value_handle;
-
- service->characteristics.emplace_back(
- tBTA_GATTC_CHARACTERISTIC{.declaration_handle = attr_handle,
- .value_handle = value_handle,
- .properties = property,
- .uuid = uuid});
- return;
-}
-
-/* Add an descriptor into database cache buffer */
-static void add_descriptor_to_gatt_db(std::vector<tBTA_GATTC_SERVICE>& gatt_db,
- uint16_t handle, const Uuid& uuid) {
-#if (BTA_GATT_DEBUG == TRUE)
- VLOG(1) << __func__ << ": add descriptor, handle=" << loghex(handle)
- << ", uuid=" << uuid;
-#endif
-
- tBTA_GATTC_SERVICE* service =
- bta_gattc_find_matching_service(gatt_db, handle);
- if (!service) {
- LOG(ERROR) << "Illegal action to add descriptor for non-existing service!";
- return;
- }
-
- if (service->characteristics.empty()) {
- LOG(ERROR) << __func__
- << ": Illegal action to add descriptor before adding a "
- "characteristic!";
- return;
- }
-
- tBTA_GATTC_CHARACTERISTIC* char_node = &service->characteristics.front();
- for (auto it = service->characteristics.begin();
- it != service->characteristics.end(); it++) {
- if (it->value_handle > handle) break;
- char_node = &(*it);
- }
-
- char_node->descriptors.emplace_back(
- tBTA_GATTC_DESCRIPTOR{.handle = handle, .uuid = uuid});
-}
-
-/* Add an attribute into database cache buffer */
-static void add_incl_srvc_to_gatt_db(std::vector<tBTA_GATTC_SERVICE>& gatt_db,
- uint16_t handle, const Uuid& uuid,
- uint16_t incl_srvc_s_handle) {
-#if (BTA_GATT_DEBUG == TRUE)
- VLOG(1) << __func__ << ": add included service, handle=" << loghex(handle)
- << ", uuid=" << uuid;
-#endif
-
- tBTA_GATTC_SERVICE* service =
- bta_gattc_find_matching_service(gatt_db, handle);
- if (!service) {
- LOG(ERROR) << "Illegal action to add incl srvc for non-existing service!";
- return;
- }
-
- tBTA_GATTC_SERVICE* included_service =
- bta_gattc_find_matching_service(gatt_db, incl_srvc_s_handle);
- if (!included_service) {
- LOG(ERROR) << __func__
- << ": Illegal action to add non-existing included service!";
- return;
- }
-
- service->included_svc.emplace_back(tBTA_GATTC_INCLUDED_SVC{
- .handle = handle,
- .uuid = uuid,
- .owning_service = service,
- .included_service = included_service,
- });
-}
-
/** Start primary service discovery */
tGATT_STATUS bta_gattc_discover_pri_service(uint16_t conn_id,
tBTA_GATTC_SERV* p_server_cb,
@@ -280,188 +137,154 @@
if (!p_clcb) return GATT_ERROR;
if (p_clcb->transport == BTA_TRANSPORT_LE) {
- tGATT_DISC_PARAM param{.s_handle = 0x0001, .e_handle = 0xFFFF};
- return GATTC_Discover(conn_id, disc_type, ¶m);
+ return GATTC_Discover(conn_id, disc_type, 0x0001, 0xFFFF);
}
+ // only for Classic transport
return bta_gattc_sdp_service_disc(conn_id, p_server_cb);
}
+/** start exploring next service, or finish discovery if no more services left
+ */
+static void bta_gattc_explore_next_service(uint16_t conn_id,
+ tBTA_GATTC_SERV* p_srvc_cb) {
+ tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+ if (!p_clcb) {
+ LOG(ERROR) << "unknown conn_id=" << loghex(conn_id);
+ return;
+ }
+
+ if (!p_srvc_cb->pending_discovery.StartNextServiceExploration()) {
+ bta_gattc_explore_srvc_finished(conn_id, p_srvc_cb);
+ return;
+ }
+
+ const auto& service = p_srvc_cb->pending_discovery.CurrentlyExploredService();
+ VLOG(1) << "Start service discovery";
+
+ /* start discovering included services */
+ GATTC_Discover(conn_id, GATT_DISC_INC_SRVC, service.first, service.second);
+}
+
+static void bta_gattc_explore_srvc_finished(uint16_t conn_id,
+ tBTA_GATTC_SERV* p_srvc_cb) {
+ tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+ if (!p_clcb) {
+ LOG(ERROR) << "unknown conn_id=" << loghex(conn_id);
+ return;
+ }
+
+ /* no service found at all, the end of server discovery*/
+ LOG(INFO) << __func__ << ": service discovery finished";
+
+ p_srvc_cb->gatt_database = p_srvc_cb->pending_discovery.Build();
+
+#if (BTA_GATT_DEBUG == TRUE)
+ bta_gattc_display_cache_server(p_srvc_cb->gatt_database);
+#endif
+ /* save cache to NV */
+ p_clcb->p_srcb->state = BTA_GATTC_SERV_SAVE;
+
+ if (btm_sec_is_a_bonded_dev(p_srvc_cb->server_bda)) {
+ bta_gattc_cache_write(p_clcb->p_srcb->server_bda,
+ p_clcb->p_srcb->gatt_database.Serialize());
+ }
+
+ bta_gattc_reset_discover_st(p_clcb->p_srcb, GATT_SUCCESS);
+}
+
/** Start discovery for characteristic descriptor */
void bta_gattc_start_disc_char_dscp(uint16_t conn_id,
tBTA_GATTC_SERV* p_srvc_cb) {
VLOG(1) << "starting discover characteristics descriptor";
- auto& characteristic = p_srvc_cb->pending_char;
- uint16_t end_handle = 0xFFFF;
- // if there are more characteristics in the service
- if (std::next(p_srvc_cb->pending_char) !=
- p_srvc_cb->pending_service->characteristics.end()) {
- // end at beginning of next characteristic
- end_handle = std::next(p_srvc_cb->pending_char)->declaration_handle - 1;
- } else {
- // end at the end of current service
- end_handle = p_srvc_cb->pending_service->e_handle;
+ std::pair<uint16_t, uint16_t> range =
+ p_srvc_cb->pending_discovery.NextDescriptorRangeToExplore();
+ if (range == DatabaseBuilder::EXPLORE_END) {
+ goto descriptor_discovery_done;
}
- tGATT_DISC_PARAM param{
- .s_handle = (uint16_t)(characteristic->value_handle + 1),
- .e_handle = end_handle};
- if (GATTC_Discover(conn_id, GATT_DISC_CHAR_DSCPT, ¶m) != 0) {
- bta_gattc_char_dscpt_disc_cmpl(conn_id, p_srvc_cb);
+ if (GATTC_Discover(conn_id, GATT_DISC_CHAR_DSCPT, range.first,
+ range.second) != 0) {
+ goto descriptor_discovery_done;
}
-}
+ return;
-/** process the service discovery complete event */
-static void bta_gattc_explore_srvc(uint16_t conn_id,
- tBTA_GATTC_SERV* p_srvc_cb) {
- tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
- if (!p_clcb) {
- LOG(ERROR) << "unknown conn_id=" << +conn_id;
- return;
- }
-
- /* start expore a service if there is service not been explored */
- if (p_srvc_cb->pending_service != p_srvc_cb->pending_discovery.end()) {
- auto& service = *p_srvc_cb->pending_service;
- VLOG(1) << "Start service discovery";
-
- /* start discovering included services */
- tGATT_DISC_PARAM param = {.s_handle = service.s_handle,
- .e_handle = service.e_handle};
- GATTC_Discover(conn_id, GATT_DISC_INC_SRVC, ¶m);
- return;
- }
-
- /* no service found at all, the end of server discovery*/
- LOG(INFO) << __func__ << ": no more services found";
-
- p_srvc_cb->srvc_cache.swap(p_srvc_cb->pending_discovery);
- std::vector<tBTA_GATTC_SERVICE>().swap(p_srvc_cb->pending_discovery);
-
-#if (BTA_GATT_DEBUG == TRUE)
- bta_gattc_display_cache_server(p_srvc_cb->srvc_cache);
-#endif
- /* save cache to NV */
- p_clcb->p_srcb->state = BTA_GATTC_SERV_SAVE;
-
- if (btm_sec_is_a_bonded_dev(p_srvc_cb->server_bda)) {
- bta_gattc_cache_save(p_clcb->p_srcb, p_clcb->bta_conn_id);
- }
-
- bta_gattc_reset_discover_st(p_clcb->p_srcb, GATT_SUCCESS);
-}
-
-/** process the char descriptor discovery complete event */
-static void bta_gattc_char_dscpt_disc_cmpl(uint16_t conn_id,
- tBTA_GATTC_SERV* p_srvc_cb) {
- ++p_srvc_cb->pending_char;
- if (p_srvc_cb->pending_char !=
- p_srvc_cb->pending_service->characteristics.end()) {
- /* start discoverying next characteristic for char descriptor */
- bta_gattc_start_disc_char_dscp(conn_id, p_srvc_cb);
- return;
- }
-
+descriptor_discovery_done:
/* all characteristic has been explored, start with next service if any */
-#if (BTA_GATT_DEBUG == TRUE)
- LOG(ERROR) << "all char has been explored";
-#endif
- p_srvc_cb->pending_service++;
- bta_gattc_explore_srvc(conn_id, p_srvc_cb);
+ DVLOG(3) << "all characteristics explored";
+
+ bta_gattc_explore_next_service(conn_id, p_srvc_cb);
+ return;
}
-static bool bta_gattc_srvc_in_list(std::vector<tBTA_GATTC_SERVICE>& services,
- uint16_t s_handle, uint16_t e_handle, Uuid) {
- if (!GATT_HANDLE_IS_VALID(s_handle) || !GATT_HANDLE_IS_VALID(e_handle)) {
- LOG(ERROR) << "invalid included service s_handle=" << loghex(s_handle)
- << ", e_handle=" << loghex(e_handle);
- return true;
- }
-
- for (tBTA_GATTC_SERVICE& service : services) {
- if (service.s_handle == s_handle || service.e_handle == e_handle)
- return true;
- }
-
- return false;
-}
-
-/*******************************************************************************
- *
- * Function bta_gattc_sdp_callback
- *
- * Description Process the discovery result from sdp
- *
- * Returns void
- *
- ******************************************************************************/
+/* Process the discovery result from sdp */
void bta_gattc_sdp_callback(uint16_t sdp_status, void* user_data) {
tBTA_GATTC_CB_DATA* cb_data = (tBTA_GATTC_CB_DATA*)user_data;
tBTA_GATTC_SERV* p_srvc_cb = bta_gattc_find_scb_by_cid(cb_data->sdp_conn_id);
if (p_srvc_cb == nullptr) {
LOG(ERROR) << "GATT service discovery is done on unknown connection";
- } else {
- bool no_pending_disc = p_srvc_cb->pending_discovery.empty();
-
- if ((sdp_status == SDP_SUCCESS) || (sdp_status == SDP_DB_FULL)) {
- tSDP_DISC_REC* p_sdp_rec = NULL;
- do {
- /* find a service record, report it */
- p_sdp_rec = SDP_FindServiceInDb(cb_data->p_sdp_db, 0, p_sdp_rec);
- if (p_sdp_rec) {
- Uuid service_uuid;
- if (SDP_FindServiceUUIDInRec(p_sdp_rec, &service_uuid)) {
- tSDP_PROTOCOL_ELEM pe;
- if (SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_ATT,
- &pe)) {
- uint16_t start_handle = (uint16_t)pe.params[0];
- uint16_t end_handle = (uint16_t)pe.params[1];
-
-#if (BTA_GATT_DEBUG == TRUE)
- VLOG(1) << "Found ATT service uuid=" << service_uuid
- << ", s_handle=" << loghex(start_handle)
- << ", e_handle=" << loghex(end_handle);
-#endif
-
- if (GATT_HANDLE_IS_VALID(start_handle) &&
- GATT_HANDLE_IS_VALID(end_handle) && p_srvc_cb != NULL) {
- /* discover services result, add services into a service list */
- add_service_to_gatt_db(p_srvc_cb->pending_discovery,
- start_handle, end_handle, service_uuid,
- true);
- } else {
- LOG(ERROR) << "invalid start_handle=" << loghex(start_handle)
- << ", end_handle=" << loghex(end_handle);
- }
- }
- }
- }
- } while (p_sdp_rec);
- }
-
- if (no_pending_disc) {
- p_srvc_cb->pending_service = p_srvc_cb->pending_discovery.begin();
- }
-
- /* start discover primary service */
- bta_gattc_explore_srvc(cb_data->sdp_conn_id, p_srvc_cb);
+ /* allocated in bta_gattc_sdp_service_disc */
+ osi_free(cb_data);
+ return;
}
- /* both were allocated in bta_gattc_sdp_service_disc */
- osi_free(cb_data->p_sdp_db);
+ if ((sdp_status != SDP_SUCCESS) && (sdp_status != SDP_DB_FULL)) {
+ bta_gattc_explore_srvc_finished(cb_data->sdp_conn_id, p_srvc_cb);
+
+ /* allocated in bta_gattc_sdp_service_disc */
+ osi_free(cb_data);
+ return;
+ }
+
+ bool no_pending_disc = !p_srvc_cb->pending_discovery.InProgress();
+
+ tSDP_DISC_REC* p_sdp_rec = SDP_FindServiceInDb(cb_data->p_sdp_db, 0, nullptr);
+ while (p_sdp_rec != nullptr) {
+ /* find a service record, report it */
+ Uuid service_uuid;
+ if (!SDP_FindServiceUUIDInRec(p_sdp_rec, &service_uuid)) continue;
+
+ tSDP_PROTOCOL_ELEM pe;
+ if (!SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_ATT, &pe))
+ continue;
+
+ uint16_t start_handle = (uint16_t)pe.params[0];
+ uint16_t end_handle = (uint16_t)pe.params[1];
+
+#if (BTA_GATT_DEBUG == TRUE)
+ VLOG(1) << "Found ATT service uuid=" << service_uuid
+ << ", s_handle=" << loghex(start_handle)
+ << ", e_handle=" << loghex(end_handle);
+#endif
+
+ if (!GATT_HANDLE_IS_VALID(start_handle) ||
+ !GATT_HANDLE_IS_VALID(end_handle)) {
+ LOG(ERROR) << "invalid start_handle=" << loghex(start_handle)
+ << ", end_handle=" << loghex(end_handle);
+ continue;
+ }
+
+ /* discover services result, add services into a service list */
+ p_srvc_cb->pending_discovery.AddService(start_handle, end_handle,
+ service_uuid, true);
+
+ p_sdp_rec = SDP_FindServiceInDb(cb_data->p_sdp_db, 0, p_sdp_rec);
+ }
+
+ // If discovery is already pending, no need to call
+ // bta_gattc_explore_next_service. Next service will be picked up to discovery
+ // once current one is discovered. If discovery is not pending, start one
+ if (no_pending_disc) {
+ bta_gattc_explore_next_service(cb_data->sdp_conn_id, p_srvc_cb);
+ }
+
+ /* allocated in bta_gattc_sdp_service_disc */
osi_free(cb_data);
}
-/*******************************************************************************
- *
- * Function bta_gattc_sdp_service_disc
- *
- * Description Start DSP Service Discovert
- *
- * Returns void
- *
- ******************************************************************************/
+
+/* Start DSP Service Discovery */
static tGATT_STATUS bta_gattc_sdp_service_disc(uint16_t conn_id,
tBTA_GATTC_SERV* p_server_cb) {
uint16_t num_attrs = 2;
@@ -471,10 +294,10 @@
* On success, cb_data will be freed inside bta_gattc_sdp_callback,
* otherwise it will be freed within this function.
*/
- tBTA_GATTC_CB_DATA* cb_data =
- (tBTA_GATTC_CB_DATA*)osi_malloc(sizeof(tBTA_GATTC_CB_DATA));
+ tBTA_GATTC_CB_DATA* cb_data = (tBTA_GATTC_CB_DATA*)osi_malloc(
+ sizeof(tBTA_GATTC_CB_DATA) + BTA_GATT_SDP_DB_SIZE);
- cb_data->p_sdp_db = (tSDP_DISCOVERY_DB*)osi_malloc(BTA_GATT_SDP_DB_SIZE);
+ cb_data->p_sdp_db = (tSDP_DISCOVERY_DB*)(cb_data + 1);
attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
@@ -485,7 +308,6 @@
if (!SDP_ServiceSearchAttributeRequest2(p_server_cb->server_bda,
cb_data->p_sdp_db,
&bta_gattc_sdp_callback, cb_data)) {
- osi_free(cb_data->p_sdp_db);
osi_free(cb_data);
return GATT_ERROR;
}
@@ -505,43 +327,27 @@
switch (disc_type) {
case GATT_DISC_SRVC_ALL:
case GATT_DISC_SRVC_BY_UUID:
- /* discover services result, add services into a service list */
- add_service_to_gatt_db(p_srvc_cb->pending_discovery, p_data->handle,
- p_data->value.group_value.e_handle,
- p_data->value.group_value.service_type, true);
+ p_srvc_cb->pending_discovery.AddService(
+ p_data->handle, p_data->value.group_value.e_handle,
+ p_data->value.group_value.service_type, true);
break;
case GATT_DISC_INC_SRVC:
- /* add included service into service list if it's secondary or it never
- showed up in the primary service search */
- if (!bta_gattc_srvc_in_list(p_srvc_cb->pending_discovery,
- p_data->value.incl_service.s_handle,
- p_data->value.incl_service.e_handle,
- p_data->value.incl_service.service_type)) {
- add_service_to_gatt_db(p_srvc_cb->pending_discovery,
- p_data->value.incl_service.s_handle,
- p_data->value.incl_service.e_handle,
- p_data->value.incl_service.service_type, false);
- }
-
- /* add into database */
- add_incl_srvc_to_gatt_db(p_srvc_cb->pending_discovery, p_data->handle,
- p_data->value.incl_service.service_type,
- p_data->value.incl_service.s_handle);
+ p_srvc_cb->pending_discovery.AddIncludedService(
+ p_data->handle, p_data->value.incl_service.service_type,
+ p_data->value.incl_service.s_handle,
+ p_data->value.incl_service.e_handle);
break;
case GATT_DISC_CHAR:
- /* add char value into database */
- add_characteristic_to_gatt_db(p_srvc_cb->pending_discovery,
- p_data->handle,
- p_data->value.dclr_value.val_handle,
- p_data->value.dclr_value.char_uuid,
- p_data->value.dclr_value.char_prop);
+ p_srvc_cb->pending_discovery.AddCharacteristic(
+ p_data->handle, p_data->value.dclr_value.val_handle,
+ p_data->value.dclr_value.char_uuid,
+ p_data->value.dclr_value.char_prop);
break;
case GATT_DISC_CHAR_DSCPT:
- add_descriptor_to_gatt_db(p_srvc_cb->pending_discovery, p_data->handle,
- p_data->type);
+ p_srvc_cb->pending_discovery.AddDescriptor(p_data->handle, p_data->type);
break;
}
}
@@ -567,18 +373,13 @@
#if (BTA_GATT_DEBUG == TRUE)
bta_gattc_display_explore_record(p_srvc_cb->pending_discovery);
#endif
- p_srvc_cb->pending_service = p_srvc_cb->pending_discovery.begin();
- bta_gattc_explore_srvc(conn_id, p_srvc_cb);
+ bta_gattc_explore_next_service(conn_id, p_srvc_cb);
break;
case GATT_DISC_INC_SRVC: {
- auto& service = *p_srvc_cb->pending_service;
-
- /* start discoverying characteristic */
-
- tGATT_DISC_PARAM param = {.s_handle = service.s_handle,
- .e_handle = service.e_handle};
- GATTC_Discover(conn_id, GATT_DISC_CHAR, ¶m);
+ auto& service = p_srvc_cb->pending_discovery.CurrentlyExploredService();
+ /* start discovering characteristic */
+ GATTC_Discover(conn_id, GATT_DISC_CHAR, service.first, service.second);
break;
}
@@ -586,33 +387,25 @@
#if (BTA_GATT_DEBUG == TRUE)
bta_gattc_display_explore_record(p_srvc_cb->pending_discovery);
#endif
- auto& service = *p_srvc_cb->pending_service;
- if (!service.characteristics.empty()) {
- /* discover descriptors */
- p_srvc_cb->pending_char = service.characteristics.begin();
- bta_gattc_start_disc_char_dscp(conn_id, p_srvc_cb);
- return;
- }
- /* start next service */
- ++p_srvc_cb->pending_service;
- bta_gattc_explore_srvc(conn_id, p_srvc_cb);
+ bta_gattc_start_disc_char_dscp(conn_id, p_srvc_cb);
break;
}
case GATT_DISC_CHAR_DSCPT:
- bta_gattc_char_dscpt_disc_cmpl(conn_id, p_srvc_cb);
+ /* start discovering next characteristic for char descriptor */
+ bta_gattc_start_disc_char_dscp(conn_id, p_srvc_cb);
break;
}
}
/** search local cache for matching service record */
void bta_gattc_search_service(tBTA_GATTC_CLCB* p_clcb, Uuid* p_uuid) {
- for (const tBTA_GATTC_SERVICE& service : p_clcb->p_srcb->srvc_cache) {
+ for (const Service& service : p_clcb->p_srcb->gatt_database.Services()) {
if (p_uuid && *p_uuid != service.uuid) continue;
#if (BTA_GATT_DEBUG == TRUE)
VLOG(1) << __func__ << "found service " << service.uuid
- << ", inst:" << +service.handle << " handle:" << +service.s_handle;
+ << " handle:" << +service.handle;
#endif
if (!p_clcb->p_rcb->p_cback) continue;
@@ -626,14 +419,14 @@
}
}
-std::vector<tBTA_GATTC_SERVICE>* bta_gattc_get_services_srcb(
+const std::vector<Service>* bta_gattc_get_services_srcb(
tBTA_GATTC_SERV* p_srcb) {
- if (!p_srcb || p_srcb->srvc_cache.empty()) return NULL;
+ if (!p_srcb || p_srcb->gatt_database.IsEmpty()) return NULL;
- return &p_srcb->srvc_cache;
+ return &p_srcb->gatt_database.Services();
}
-std::vector<tBTA_GATTC_SERVICE>* bta_gattc_get_services(uint16_t conn_id) {
+const std::vector<Service>* bta_gattc_get_services(uint16_t conn_id) {
tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
if (p_clcb == NULL) return NULL;
@@ -643,38 +436,37 @@
return bta_gattc_get_services_srcb(p_srcb);
}
-tBTA_GATTC_SERVICE* bta_gattc_get_service_for_handle_srcb(
- tBTA_GATTC_SERV* p_srcb, uint16_t handle) {
- std::vector<tBTA_GATTC_SERVICE>* services =
- bta_gattc_get_services_srcb(p_srcb);
+const Service* bta_gattc_get_service_for_handle_srcb(tBTA_GATTC_SERV* p_srcb,
+ uint16_t handle) {
+ const std::vector<Service>* services = bta_gattc_get_services_srcb(p_srcb);
if (services == NULL) return NULL;
return bta_gattc_find_matching_service(*services, handle);
}
-const tBTA_GATTC_SERVICE* bta_gattc_get_service_for_handle(uint16_t conn_id,
- uint16_t handle) {
- std::vector<tBTA_GATTC_SERVICE>* services = bta_gattc_get_services(conn_id);
+const Service* bta_gattc_get_service_for_handle(uint16_t conn_id,
+ uint16_t handle) {
+ const std::vector<Service>* services = bta_gattc_get_services(conn_id);
if (services == NULL) return NULL;
return bta_gattc_find_matching_service(*services, handle);
}
-tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_characteristic_srcb(
- tBTA_GATTC_SERV* p_srcb, uint16_t handle) {
- tBTA_GATTC_SERVICE* service =
+const Characteristic* bta_gattc_get_characteristic_srcb(tBTA_GATTC_SERV* p_srcb,
+ uint16_t handle) {
+ const Service* service =
bta_gattc_get_service_for_handle_srcb(p_srcb, handle);
if (!service) return NULL;
- for (tBTA_GATTC_CHARACTERISTIC& charac : service->characteristics) {
+ for (const Characteristic& charac : service->characteristics) {
if (handle == charac.value_handle) return &charac;
}
return NULL;
}
-tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_characteristic(uint16_t conn_id,
- uint16_t handle) {
+const Characteristic* bta_gattc_get_characteristic(uint16_t conn_id,
+ uint16_t handle) {
tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
if (p_clcb == NULL) return NULL;
@@ -683,17 +475,17 @@
return bta_gattc_get_characteristic_srcb(p_srcb, handle);
}
-const tBTA_GATTC_DESCRIPTOR* bta_gattc_get_descriptor_srcb(
- tBTA_GATTC_SERV* p_srcb, uint16_t handle) {
- const tBTA_GATTC_SERVICE* service =
+const Descriptor* bta_gattc_get_descriptor_srcb(tBTA_GATTC_SERV* p_srcb,
+ uint16_t handle) {
+ const Service* service =
bta_gattc_get_service_for_handle_srcb(p_srcb, handle);
if (!service) {
return NULL;
}
- for (const tBTA_GATTC_CHARACTERISTIC& charac : service->characteristics) {
- for (const tBTA_GATTC_DESCRIPTOR& desc : charac.descriptors) {
+ for (const Characteristic& charac : service->characteristics) {
+ for (const Descriptor& desc : charac.descriptors) {
if (handle == desc.handle) return &desc;
}
}
@@ -701,8 +493,7 @@
return NULL;
}
-const tBTA_GATTC_DESCRIPTOR* bta_gattc_get_descriptor(uint16_t conn_id,
- uint16_t handle) {
+const Descriptor* bta_gattc_get_descriptor(uint16_t conn_id, uint16_t handle) {
tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
if (p_clcb == NULL) return NULL;
@@ -711,15 +502,15 @@
return bta_gattc_get_descriptor_srcb(p_srcb, handle);
}
-tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_owning_characteristic_srcb(
+const Characteristic* bta_gattc_get_owning_characteristic_srcb(
tBTA_GATTC_SERV* p_srcb, uint16_t handle) {
- tBTA_GATTC_SERVICE* service =
+ const Service* service =
bta_gattc_get_service_for_handle_srcb(p_srcb, handle);
if (!service) return NULL;
- for (tBTA_GATTC_CHARACTERISTIC& charac : service->characteristics) {
- for (const tBTA_GATTC_DESCRIPTOR& desc : charac.descriptors) {
+ for (const Characteristic& charac : service->characteristics) {
+ for (const Descriptor& desc : charac.descriptors) {
if (handle == desc.handle) return &charac;
}
}
@@ -727,8 +518,8 @@
return NULL;
}
-const tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_owning_characteristic(
- uint16_t conn_id, uint16_t handle) {
+const Characteristic* bta_gattc_get_owning_characteristic(uint16_t conn_id,
+ uint16_t handle) {
tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
if (!p_clcb) return NULL;
@@ -765,27 +556,27 @@
/*******************************************************************************
* Returns number of elements inside db from start_handle to end_handle
******************************************************************************/
-static size_t bta_gattc_get_db_size(
- const std::vector<tBTA_GATTC_SERVICE>& services, uint16_t start_handle,
- uint16_t end_handle) {
+static size_t bta_gattc_get_db_size(const std::vector<Service>& services,
+ uint16_t start_handle,
+ uint16_t end_handle) {
if (services.empty()) return 0;
size_t db_size = 0;
- for (const tBTA_GATTC_SERVICE& service : services) {
- if (service.s_handle < start_handle) continue;
+ for (const Service& service : services) {
+ if (service.handle < start_handle) continue;
- if (service.e_handle > end_handle) break;
+ if (service.end_handle > end_handle) break;
db_size++;
- for (const tBTA_GATTC_CHARACTERISTIC& charac : service.characteristics) {
+ for (const Characteristic& charac : service.characteristics) {
db_size++;
db_size += charac.descriptors.size();
}
- db_size += service.included_svc.size();
+ db_size += service.included_services.size();
}
return db_size;
@@ -814,39 +605,39 @@
<< StringPrintf(": start_handle 0x%04x, end_handle 0x%04x",
start_handle, end_handle);
- if (p_srvc_cb->srvc_cache.empty()) {
+ if (p_srvc_cb->gatt_database.IsEmpty()) {
*count = 0;
*db = NULL;
return;
}
- size_t db_size =
- bta_gattc_get_db_size(p_srvc_cb->srvc_cache, start_handle, end_handle);
+ size_t db_size = bta_gattc_get_db_size(p_srvc_cb->gatt_database.Services(),
+ start_handle, end_handle);
void* buffer = osi_malloc(db_size * sizeof(btgatt_db_element_t));
btgatt_db_element_t* curr_db_attr = (btgatt_db_element_t*)buffer;
- for (const tBTA_GATTC_SERVICE& service : p_srvc_cb->srvc_cache) {
- if (service.s_handle < start_handle) continue;
+ for (const Service& service : p_srvc_cb->gatt_database.Services()) {
+ if (service.handle < start_handle) continue;
- if (service.e_handle > end_handle) break;
+ if (service.end_handle > end_handle) break;
bta_gattc_fill_gatt_db_el(curr_db_attr,
service.is_primary ? BTGATT_DB_PRIMARY_SERVICE
: BTGATT_DB_SECONDARY_SERVICE,
- 0 /* att_handle */, service.s_handle,
- service.e_handle, service.s_handle, service.uuid,
+ 0 /* att_handle */, service.handle,
+ service.end_handle, service.handle, service.uuid,
0 /* prop */);
curr_db_attr++;
- for (const tBTA_GATTC_CHARACTERISTIC& charac : service.characteristics) {
+ for (const Characteristic& charac : service.characteristics) {
bta_gattc_fill_gatt_db_el(curr_db_attr, BTGATT_DB_CHARACTERISTIC,
charac.value_handle, 0 /* s_handle */,
0 /* e_handle */, charac.value_handle,
charac.uuid, charac.properties);
curr_db_attr++;
- for (const tBTA_GATTC_DESCRIPTOR& desc : charac.descriptors) {
+ for (const Descriptor& desc : charac.descriptors) {
bta_gattc_fill_gatt_db_el(
curr_db_attr, BTGATT_DB_DESCRIPTOR, desc.handle, 0 /* s_handle */,
0 /* e_handle */, desc.handle, desc.uuid, 0 /* property */);
@@ -854,11 +645,11 @@
}
}
- for (const tBTA_GATTC_INCLUDED_SVC& p_isvc : service.included_svc) {
- bta_gattc_fill_gatt_db_el(
- curr_db_attr, BTGATT_DB_INCLUDED_SERVICE, p_isvc.handle,
- p_isvc.included_service ? p_isvc.included_service->s_handle : 0,
- 0 /* e_handle */, p_isvc.handle, p_isvc.uuid, 0 /* property */);
+ for (const IncludedService& p_isvc : service.included_services) {
+ bta_gattc_fill_gatt_db_el(curr_db_attr, BTGATT_DB_INCLUDED_SERVICE,
+ p_isvc.handle, p_isvc.start_handle,
+ 0 /* e_handle */, p_isvc.handle, p_isvc.uuid,
+ 0 /* property */);
curr_db_attr++;
}
}
@@ -897,9 +688,8 @@
return;
}
- if (!p_clcb->p_srcb ||
- !p_clcb->p_srcb->pending_discovery.empty() || /* no active discovery */
- p_clcb->p_srcb->srvc_cache.empty()) {
+ if (!p_clcb->p_srcb || p_clcb->p_srcb->pending_discovery.InProgress() ||
+ p_clcb->p_srcb->gatt_database.IsEmpty()) {
LOG(ERROR) << "No server cache available";
return;
}
@@ -908,114 +698,6 @@
count);
}
-/* rebuild server cache from NV cache */
-void bta_gattc_rebuild_cache(tBTA_GATTC_SERV* p_srvc_cb, uint16_t num_attr,
- tBTA_GATTC_NV_ATTR* p_attr) {
- /* first attribute loading, initialize buffer */
- LOG(INFO) << __func__ << " " << num_attr;
-
- // clear reallocating
- std::vector<tBTA_GATTC_SERVICE>().swap(p_srvc_cb->srvc_cache);
-
- while (num_attr > 0 && p_attr != NULL) {
- switch (p_attr->attr_type) {
- case BTA_GATTC_ATTR_TYPE_SRVC:
- add_service_to_gatt_db(p_srvc_cb->srvc_cache, p_attr->s_handle,
- p_attr->e_handle, p_attr->uuid,
- p_attr->is_primary);
- break;
-
- case BTA_GATTC_ATTR_TYPE_CHAR:
- add_characteristic_to_gatt_db(p_srvc_cb->srvc_cache, p_attr->s_handle,
- p_attr->s_handle, p_attr->uuid,
- p_attr->prop);
- break;
-
- case BTA_GATTC_ATTR_TYPE_CHAR_DESCR:
- add_descriptor_to_gatt_db(p_srvc_cb->srvc_cache, p_attr->s_handle,
- p_attr->uuid);
- break;
- case BTA_GATTC_ATTR_TYPE_INCL_SRVC:
- add_incl_srvc_to_gatt_db(p_srvc_cb->srvc_cache, p_attr->s_handle,
- p_attr->uuid, p_attr->incl_srvc_handle);
- break;
- }
- p_attr++;
- num_attr--;
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_gattc_fill_nv_attr
- *
- * Description fill a NV attribute entry value
- *
- * Returns None.
- *
- ******************************************************************************/
-void bta_gattc_fill_nv_attr(tBTA_GATTC_NV_ATTR* p_attr, uint8_t type,
- uint16_t s_handle, uint16_t e_handle, Uuid uuid,
- uint8_t prop, uint16_t incl_srvc_handle,
- bool is_primary) {
- p_attr->s_handle = s_handle;
- p_attr->e_handle = e_handle;
- p_attr->attr_type = type;
- p_attr->is_primary = is_primary;
- p_attr->id = 0;
- p_attr->prop = prop;
- p_attr->incl_srvc_handle = incl_srvc_handle;
- p_attr->uuid = uuid;
-}
-
-/*******************************************************************************
- *
- * Function bta_gattc_cache_save
- *
- * Description save the server cache into NV
- *
- * Returns None.
- *
- ******************************************************************************/
-void bta_gattc_cache_save(tBTA_GATTC_SERV* p_srvc_cb, uint16_t conn_id) {
- if (p_srvc_cb->srvc_cache.empty()) return;
-
- int i = 0;
- size_t db_size = bta_gattc_get_db_size(p_srvc_cb->srvc_cache, 0x0000, 0xFFFF);
- tBTA_GATTC_NV_ATTR* nv_attr =
- (tBTA_GATTC_NV_ATTR*)osi_malloc(db_size * sizeof(tBTA_GATTC_NV_ATTR));
-
- for (const tBTA_GATTC_SERVICE& service : p_srvc_cb->srvc_cache) {
- bta_gattc_fill_nv_attr(&nv_attr[i++], BTA_GATTC_ATTR_TYPE_SRVC,
- service.s_handle, service.e_handle, service.uuid,
- 0 /* properties */, 0 /* incl_srvc_handle */,
- service.is_primary);
- }
-
- for (const tBTA_GATTC_SERVICE& service : p_srvc_cb->srvc_cache) {
- for (const tBTA_GATTC_CHARACTERISTIC& charac : service.characteristics) {
- bta_gattc_fill_nv_attr(
- &nv_attr[i++], BTA_GATTC_ATTR_TYPE_CHAR, charac.value_handle, 0,
- charac.uuid, charac.properties, 0 /* incl_srvc_handle */, false);
-
- for (const tBTA_GATTC_DESCRIPTOR& desc : charac.descriptors) {
- bta_gattc_fill_nv_attr(&nv_attr[i++], BTA_GATTC_ATTR_TYPE_CHAR_DESCR,
- desc.handle, 0, desc.uuid, 0 /* properties */,
- 0 /* incl_srvc_handle */, false);
- }
- }
-
- for (const tBTA_GATTC_INCLUDED_SVC& p_isvc : service.included_svc) {
- bta_gattc_fill_nv_attr(&nv_attr[i++], BTA_GATTC_ATTR_TYPE_INCL_SRVC,
- p_isvc.handle, 0, p_isvc.uuid, 0 /* properties */,
- p_isvc.included_service->s_handle, false);
- }
- }
-
- bta_gattc_cache_write(p_srvc_cb->server_bda, db_size, nv_attr);
- osi_free(nv_attr);
-}
-
/*******************************************************************************
*
* Function bta_gattc_cache_load
@@ -1040,7 +722,6 @@
}
uint16_t cache_ver = 0;
- tBTA_GATTC_NV_ATTR* attr = NULL;
bool success = false;
uint16_t num_attr = 0;
@@ -1060,19 +741,18 @@
goto done;
}
- attr = (tBTA_GATTC_NV_ATTR*)osi_malloc(sizeof(tBTA_GATTC_NV_ATTR) * num_attr);
+ {
+ std::vector<StoredAttribute> attr(num_attr);
- if (fread(attr, sizeof(tBTA_GATTC_NV_ATTR), num_attr, fd) != num_attr) {
- LOG(ERROR) << __func__ << "s: can't read GATT attributes: " << fname;
- goto done;
+ if (fread(attr.data(), sizeof(StoredAttribute), num_attr, fd) != num_attr) {
+ LOG(ERROR) << __func__ << "s: can't read GATT attributes: " << fname;
+ goto done;
+ }
+
+ p_clcb->p_srcb->gatt_database = gatt::Database::Deserialize(attr, &success);
}
- bta_gattc_rebuild_cache(p_clcb->p_srcb, num_attr, attr);
-
- success = true;
-
done:
- osi_free(attr);
fclose(fd);
return success;
}
@@ -1085,13 +765,12 @@
* cache is available to save.
*
* Parameter server_bda: server bd address of this cache belongs to
- * num_attr: number of attribute to be save.
- * attr: pointer to the list of attributes to save.
+ * attr: attributes to save.
* Returns
*
******************************************************************************/
static void bta_gattc_cache_write(const RawAddress& server_bda,
- uint16_t num_attr, tBTA_GATTC_NV_ATTR* attr) {
+ const std::vector<StoredAttribute>& attr) {
char fname[255] = {0};
bta_gattc_generate_cache_file_name(fname, sizeof(fname), server_bda);
@@ -1109,6 +788,7 @@
return;
}
+ uint16_t num_attr = attr.size();
if (fwrite(&num_attr, sizeof(uint16_t), 1, fd) != 1) {
LOG(ERROR) << __func__
<< ": can't write GATT cache attribute count: " << fname;
@@ -1116,7 +796,7 @@
return;
}
- if (fwrite(attr, sizeof(tBTA_GATTC_NV_ATTR), num_attr, fd) != num_attr) {
+ if (fwrite(attr.data(), sizeof(StoredAttribute), num_attr, fd) != num_attr) {
LOG(ERROR) << __func__ << ": can't write GATT cache attributes: " << fname;
fclose(fd);
return;
diff --git a/bta/gatt/bta_gattc_int.h b/bta/gatt/bta_gattc_int.h
index 5b33eae..2b60ac7 100644
--- a/bta/gatt/bta_gattc_int.h
+++ b/bta/gatt/bta_gattc_int.h
@@ -28,6 +28,7 @@
#include "bta_gatt_api.h"
#include "bta_sys.h"
+#include "database_builder.h"
#include "osi/include/fixed_queue.h"
#include "bt_common.h"
@@ -206,13 +207,11 @@
uint8_t state;
- std::vector<tBTA_GATTC_SERVICE> srvc_cache;
+ gatt::Database gatt_database;
uint8_t update_count; /* indication received */
uint8_t num_clcb; /* number of associated CLCB */
- std::vector<tBTA_GATTC_SERVICE> pending_discovery;
- std::vector<tBTA_GATTC_SERVICE>::iterator pending_service;
- std::vector<tBTA_GATTC_CHARACTERISTIC>::iterator pending_char;
+ gatt::DatabaseBuilder pending_discovery;
uint8_t srvc_hdl_chg; /* service handle change indication pending */
uint16_t attr_index; /* cahce NV saving/loading attribute index */
@@ -427,27 +426,24 @@
uint8_t disc_type);
extern void bta_gattc_search_service(tBTA_GATTC_CLCB* p_clcb,
bluetooth::Uuid* p_uuid);
-extern std::vector<tBTA_GATTC_SERVICE>* bta_gattc_get_services(
+extern const std::vector<gatt::Service>* bta_gattc_get_services(
uint16_t conn_id);
-extern const tBTA_GATTC_SERVICE* bta_gattc_get_service_for_handle(
- uint16_t conn_id, uint16_t handle);
-tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_characteristic_srcb(
- tBTA_GATTC_SERV* p_srcb, uint16_t handle);
-extern tBTA_GATTC_SERVICE* bta_gattc_get_service_for_handle_srcb(
- tBTA_GATTC_SERV* p_srcb, uint16_t handle);
-extern tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_characteristic(uint16_t conn_id,
- uint16_t handle);
-extern const tBTA_GATTC_DESCRIPTOR* bta_gattc_get_descriptor(uint16_t conn_id,
+extern const gatt::Service* bta_gattc_get_service_for_handle(uint16_t conn_id,
uint16_t handle);
-extern const tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_owning_characteristic(
+const gatt::Characteristic* bta_gattc_get_characteristic_srcb(
+ tBTA_GATTC_SERV* p_srcb, uint16_t handle);
+extern const gatt::Service* bta_gattc_get_service_for_handle_srcb(
+ tBTA_GATTC_SERV* p_srcb, uint16_t handle);
+extern const gatt::Characteristic* bta_gattc_get_characteristic(
+ uint16_t conn_id, uint16_t handle);
+extern const gatt::Descriptor* bta_gattc_get_descriptor(uint16_t conn_id,
+ uint16_t handle);
+extern const gatt::Characteristic* bta_gattc_get_owning_characteristic(
uint16_t conn_id, uint16_t handle);
extern void bta_gattc_get_gatt_db(uint16_t conn_id, uint16_t start_handle,
uint16_t end_handle, btgatt_db_element_t** db,
int* count);
-extern tGATT_STATUS bta_gattc_init_cache(tBTA_GATTC_SERV* p_srvc_cb);
-extern void bta_gattc_rebuild_cache(tBTA_GATTC_SERV* p_srcv, uint16_t num_attr,
- tBTA_GATTC_NV_ATTR* attr);
-extern void bta_gattc_cache_save(tBTA_GATTC_SERV* p_srvc_cb, uint16_t conn_id);
+extern void bta_gattc_init_cache(tBTA_GATTC_SERV* p_srvc_cb);
extern void bta_gattc_reset_discover_st(tBTA_GATTC_SERV* p_srcb,
tGATT_STATUS status);
diff --git a/bta/gatt/bta_gattc_queue.cc b/bta/gatt/bta_gattc_queue.cc
index c00a885..6d9fff3 100644
--- a/bta/gatt/bta_gattc_queue.cc
+++ b/bta/gatt/bta_gattc_queue.cc
@@ -81,7 +81,7 @@
}
void BtaGattQueue::gatt_execute_next_op(uint16_t conn_id) {
- APPL_TRACE_DEBUG("%s:", __func__, conn_id);
+ APPL_TRACE_DEBUG("%s: conn_id=0x%x", __func__, conn_id);
if (gatt_op_queue.empty()) {
APPL_TRACE_DEBUG("%s: op queue is empty", __func__);
return;
diff --git a/bta/gatt/bta_gattc_utils.cc b/bta/gatt/bta_gattc_utils.cc
index 21b63c0..2c8e5fd 100644
--- a/bta/gatt/bta_gattc_utils.cc
+++ b/bta/gatt/bta_gattc_utils.cc
@@ -204,7 +204,7 @@
p_srcb->mtu = 0;
// clear reallocating
- std::vector<tBTA_GATTC_SERVICE>().swap(p_srcb->srvc_cache);
+ p_srcb->gatt_database.Clear();
}
osi_free_and_reset((void**)&p_clcb->p_q_cmd);
@@ -296,8 +296,8 @@
if (p_tcb != NULL) {
// clear reallocating
- std::vector<tBTA_GATTC_SERVICE>().swap(p_tcb->srvc_cache);
- std::vector<tBTA_GATTC_SERVICE>().swap(p_tcb->pending_discovery);
+ p_tcb->gatt_database.Clear();
+ p_tcb->pending_discovery.Clear();
*p_tcb = tBTA_GATTC_SERV();
p_tcb->in_use = true;
diff --git a/bta/gatt/bta_gatts_api.cc b/bta/gatt/bta_gatts_api.cc
index 9d7cda0..ef00269 100644
--- a/bta/gatt/bta_gatts_api.cc
+++ b/bta/gatt/bta_gatts_api.cc
@@ -28,10 +28,10 @@
#include <string.h>
#include "bt_common.h"
-#include "bta_closure_api.h"
#include "bta_gatt_api.h"
#include "bta_gatts_int.h"
#include "bta_sys.h"
+#include "stack/include/btu.h"
/*****************************************************************************
* Constants
@@ -168,8 +168,9 @@
extern void BTA_GATTS_AddService(tGATT_IF server_if,
std::vector<btgatt_db_element_t> service,
BTA_GATTS_AddServiceCb cb) {
- do_in_bta_thread(FROM_HERE, base::Bind(&bta_gatts_add_service_impl, server_if,
- std::move(service), std::move(cb)));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(&bta_gatts_add_service_impl, server_if,
+ std::move(service), std::move(cb)));
}
/*******************************************************************************
diff --git a/bta/gatt/database.cc b/bta/gatt/database.cc
new file mode 100644
index 0000000..5f99d55
--- /dev/null
+++ b/bta/gatt/database.cc
@@ -0,0 +1,185 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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 "database.h"
+#include "bt_trace.h"
+#include "stack/include/gattdefs.h"
+
+#include <base/logging.h>
+#include <memory>
+#include <sstream>
+
+using bluetooth::Uuid;
+
+namespace gatt {
+
+namespace {
+const Uuid PRIMARY_SERVICE = Uuid::From16Bit(GATT_UUID_PRI_SERVICE);
+const Uuid SECONDARY_SERVICE = Uuid::From16Bit(GATT_UUID_SEC_SERVICE);
+const Uuid INCLUDE = Uuid::From16Bit(GATT_UUID_INCLUDE_SERVICE);
+const Uuid CHARACTERISTIC = Uuid::From16Bit(GATT_UUID_CHAR_DECLARE);
+
+bool HandleInRange(const Service& svc, uint16_t handle) {
+ return handle >= svc.handle && handle <= svc.end_handle;
+}
+} // namespace
+
+Service* FindService(std::vector<Service>& services, uint16_t handle) {
+ for (Service& service : services) {
+ if (handle >= service.handle && handle <= service.end_handle)
+ return &service;
+ }
+
+ return nullptr;
+}
+
+std::string Database::ToString() const {
+ std::stringstream tmp;
+
+ for (const Service& service : services) {
+ tmp << "Service: handle=" << loghex(service.handle)
+ << ", end_handle=" << loghex(service.end_handle)
+ << ", uuid=" << service.uuid << "\n";
+
+ for (const auto& is : service.included_services) {
+ tmp << "\t Included service: handle=" << loghex(is.handle)
+ << ", start_handle=" << loghex(is.start_handle)
+ << ", end_handle=" << loghex(is.end_handle) << ", uuid=" << is.uuid
+ << "\n";
+ }
+
+ for (const Characteristic& c : service.characteristics) {
+ tmp << "\t Characteristic: declaration_handle="
+ << loghex(c.declaration_handle)
+ << ", value_handle=" << loghex(c.value_handle) << ", uuid=" << c.uuid
+ << ", prop=" << loghex(c.properties) << "\n";
+
+ for (const Descriptor& d : c.descriptors) {
+ tmp << "\t\t Descriptor: handle=" << loghex(d.handle)
+ << ", uuid=" << d.uuid << "\n";
+ }
+ }
+ }
+ return tmp.str();
+}
+
+std::vector<StoredAttribute> Database::Serialize() const {
+ std::vector<StoredAttribute> nv_attr;
+
+ if (services.empty()) return std::vector<StoredAttribute>();
+
+ for (const Service& service : services) {
+ // TODO: add constructor to NV_ATTR, use emplace_back
+ nv_attr.push_back({service.handle,
+ service.is_primary ? PRIMARY_SERVICE : SECONDARY_SERVICE,
+ {.service = {.uuid = service.uuid,
+ .end_handle = service.end_handle}}});
+ }
+
+ for (const Service& service : services) {
+ for (const IncludedService& p_isvc : service.included_services) {
+ nv_attr.push_back({p_isvc.handle,
+ INCLUDE,
+ {.included_service = {.handle = p_isvc.start_handle,
+ .end_handle = p_isvc.end_handle,
+ .uuid = p_isvc.uuid}}});
+ }
+
+ for (const Characteristic& charac : service.characteristics) {
+ nv_attr.push_back(
+ {charac.declaration_handle,
+ CHARACTERISTIC,
+ {.characteristic = {.properties = charac.properties,
+ .value_handle = charac.value_handle,
+ .uuid = charac.uuid}}});
+
+ for (const Descriptor& desc : charac.descriptors) {
+ nv_attr.push_back({desc.handle, desc.uuid, {}});
+ }
+ }
+ }
+
+ return nv_attr;
+}
+
+Database Database::Deserialize(const std::vector<StoredAttribute>& nv_attr,
+ bool* success) {
+ // clear reallocating
+ Database result;
+ auto it = nv_attr.cbegin();
+
+ for (; it != nv_attr.cend(); ++it) {
+ const auto& attr = *it;
+ if (attr.type != PRIMARY_SERVICE && attr.type != SECONDARY_SERVICE) break;
+ result.services.emplace_back(
+ Service{.handle = attr.handle,
+ .end_handle = attr.value.service.end_handle,
+ .is_primary = (attr.type == PRIMARY_SERVICE),
+ .uuid = attr.value.service.uuid});
+ }
+
+ auto current_service_it = result.services.begin();
+ for (; it != nv_attr.cend(); it++) {
+ const auto& attr = *it;
+
+ // go to the service this attribute belongs to; attributes are stored in
+ // order, so iterating just forward is enough
+ while (current_service_it != result.services.end() &&
+ current_service_it->end_handle < attr.handle) {
+ current_service_it++;
+ }
+
+ if (current_service_it == result.services.end() ||
+ !HandleInRange(*current_service_it, attr.handle)) {
+ LOG(ERROR) << "Can't find service for attribute with handle: "
+ << loghex(attr.handle);
+ *success = false;
+ return result;
+ }
+
+ if (attr.type == INCLUDE) {
+ Service* included_service =
+ FindService(result.services, attr.value.included_service.handle);
+ if (!included_service) {
+ LOG(ERROR) << __func__ << ": Non-existing included service!";
+ *success = false;
+ return result;
+ }
+ current_service_it->included_services.push_back(IncludedService{
+ .handle = attr.handle,
+ .uuid = attr.value.included_service.uuid,
+ .start_handle = attr.value.included_service.handle,
+ .end_handle = attr.value.included_service.end_handle,
+ });
+ } else if (attr.type == CHARACTERISTIC) {
+ current_service_it->characteristics.emplace_back(
+ Characteristic{.declaration_handle = attr.handle,
+ .value_handle = attr.value.characteristic.value_handle,
+ .properties = attr.value.characteristic.properties,
+ .uuid = attr.value.characteristic.uuid});
+
+ } else {
+ current_service_it->characteristics.back().descriptors.emplace_back(
+ Descriptor{.handle = attr.handle, .uuid = attr.type});
+ }
+ }
+ *success = true;
+ return result;
+}
+
+} // namespace gatt
\ No newline at end of file
diff --git a/bta/gatt/database.h b/bta/gatt/database.h
new file mode 100644
index 0000000..1e74809
--- /dev/null
+++ b/bta/gatt/database.h
@@ -0,0 +1,126 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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 <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "types/bluetooth/uuid.h"
+
+namespace gatt {
+constexpr uint16_t HANDLE_MIN = 0x0001;
+constexpr uint16_t HANDLE_MAX = 0xffff;
+
+/* Representation of GATT attribute for storage */
+struct StoredAttribute {
+ uint16_t handle;
+ bluetooth::Uuid type;
+
+ union {
+ /* primary or secondary service definition */
+ struct {
+ bluetooth::Uuid uuid;
+ uint16_t end_handle;
+ } service;
+
+ /* included service definition */
+ struct {
+ uint16_t handle;
+ uint16_t end_handle;
+ bluetooth::Uuid uuid;
+ } included_service;
+
+ /* characteristic deifnition */
+ struct {
+ uint8_t properties;
+ uint16_t value_handle;
+ bluetooth::Uuid uuid;
+ } characteristic;
+
+ /* for descriptor definition we don't store value*/
+ } value;
+};
+
+struct IncludedService;
+struct Characteristic;
+struct Descriptor;
+
+struct Service {
+ uint16_t handle;
+ bluetooth::Uuid uuid;
+ bool is_primary;
+ uint16_t end_handle;
+ std::vector<IncludedService> included_services;
+ std::vector<Characteristic> characteristics;
+};
+
+struct IncludedService {
+ uint16_t handle; /* definition handle */
+ bluetooth::Uuid uuid;
+ uint16_t start_handle; /* start handle of included service */
+ uint16_t end_handle; /* end handle of included service */
+};
+
+struct Characteristic {
+ uint16_t declaration_handle;
+ bluetooth::Uuid uuid;
+ uint16_t value_handle;
+ uint8_t properties;
+ std::vector<Descriptor> descriptors;
+};
+
+struct Descriptor {
+ uint16_t handle;
+ bluetooth::Uuid uuid;
+};
+
+class DatabaseBuilder;
+
+class Database {
+ public:
+ /* Return true if there are no services in this database. */
+ bool IsEmpty() const { return services.empty(); }
+
+ /* Clear the GATT database. This method forces relocation to ensure no extra
+ * space is used unnecesarly */
+ void Clear() { std::vector<Service>().swap(services); }
+
+ /* Return list of services available in this database */
+ const std::vector<Service>& Services() const { return services; }
+
+ std::string ToString() const;
+
+ std::vector<gatt::StoredAttribute> Serialize() const;
+
+ static Database Deserialize(const std::vector<gatt::StoredAttribute>& nv_attr,
+ bool* success);
+
+ friend class DatabaseBuilder;
+
+ private:
+ std::vector<Service> services;
+};
+
+/* Find a service that should contain handle. Helper method for internal use
+ * inside gatt namespace.*/
+Service* FindService(std::vector<Service>& services, uint16_t handle);
+
+} // namespace gatt
diff --git a/bta/gatt/database_builder.cc b/bta/gatt/database_builder.cc
new file mode 100644
index 0000000..ed065ab
--- /dev/null
+++ b/bta/gatt/database_builder.cc
@@ -0,0 +1,190 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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 "database_builder.h"
+
+#include "bt_trace.h"
+
+#include <base/logging.h>
+#include <algorithm>
+
+using bluetooth::Uuid;
+
+namespace gatt {
+
+void DatabaseBuilder::AddService(uint16_t handle, uint16_t end_handle,
+ const Uuid& uuid, bool is_primary) {
+ // general case optimization - we add services in order
+ if (database.services.empty() ||
+ database.services.back().end_handle < handle) {
+ database.services.emplace_back(Service{.handle = handle,
+ .end_handle = end_handle,
+ .is_primary = is_primary,
+ .uuid = uuid});
+ } else {
+ auto& vec = database.services;
+
+ // Find first service whose start handle is bigger than new service handle
+ auto it = std::lower_bound(
+ vec.begin(), vec.end(), handle,
+ [](Service s, uint16_t handle) { return s.end_handle < handle; });
+
+ // Insert new service just before it
+ vec.emplace(it, Service{.handle = handle,
+ .end_handle = end_handle,
+ .is_primary = is_primary,
+ .uuid = uuid});
+ }
+
+ services_to_discover.insert({handle, end_handle});
+}
+
+void DatabaseBuilder::AddIncludedService(uint16_t handle, const Uuid& uuid,
+ uint16_t start_handle,
+ uint16_t end_handle) {
+ Service* service = FindService(database.services, handle);
+ if (!service) {
+ LOG(ERROR) << "Illegal action to add to non-existing service!";
+ return;
+ }
+
+ /* We discover all Primary Services first. If included service was not seen
+ * before, it must be a Secondary Service */
+ if (!FindService(database.services, start_handle)) {
+ AddService(start_handle, end_handle, uuid, false /* not primary */);
+ }
+
+ service->included_services.push_back(IncludedService{
+ .handle = handle,
+ .uuid = uuid,
+ .start_handle = start_handle,
+ .end_handle = end_handle,
+ });
+}
+
+void DatabaseBuilder::AddCharacteristic(uint16_t handle, uint16_t value_handle,
+ const Uuid& uuid, uint8_t properties) {
+ Service* service = FindService(database.services, handle);
+ if (!service) {
+ LOG(ERROR) << "Illegal action to add to non-existing service!";
+ return;
+ }
+
+ if (service->end_handle < value_handle)
+ LOG(WARNING) << "Remote device violates spec: value_handle="
+ << loghex(value_handle) << " is after service end_handle="
+ << loghex(service->end_handle);
+
+ service->characteristics.emplace_back(
+ Characteristic{.declaration_handle = handle,
+ .value_handle = value_handle,
+ .properties = properties,
+ .uuid = uuid});
+ return;
+}
+
+void DatabaseBuilder::AddDescriptor(uint16_t handle, const Uuid& uuid) {
+ Service* service = FindService(database.services, handle);
+ if (!service) {
+ LOG(ERROR) << "Illegal action to add to non-existing service!";
+ return;
+ }
+
+ if (service->characteristics.empty()) {
+ LOG(ERROR) << __func__
+ << ": Illegal action to add to non-existing characteristic!";
+ return;
+ }
+
+ Characteristic* char_node = &service->characteristics.front();
+ for (auto it = service->characteristics.begin();
+ it != service->characteristics.end(); it++) {
+ if (it->declaration_handle > handle) break;
+ char_node = &(*it);
+ }
+
+ char_node->descriptors.emplace_back(
+ gatt::Descriptor{.handle = handle, .uuid = uuid});
+}
+
+bool DatabaseBuilder::StartNextServiceExploration() {
+ while (!services_to_discover.empty()) {
+ auto handle_range = services_to_discover.begin();
+ pending_service = *handle_range;
+ services_to_discover.erase(handle_range);
+
+ // Empty service declaration, nothing to explore, skip to next.
+ if (pending_service.first == pending_service.second) continue;
+
+ pending_characteristic = HANDLE_MIN;
+ return true;
+ }
+ return false;
+}
+
+const std::pair<uint16_t, uint16_t>&
+DatabaseBuilder::CurrentlyExploredService() {
+ return pending_service;
+}
+
+std::pair<uint16_t, uint16_t> DatabaseBuilder::NextDescriptorRangeToExplore() {
+ Service* service = FindService(database.services, pending_service.first);
+ if (!service || service->characteristics.empty()) {
+ return {HANDLE_MAX, HANDLE_MAX};
+ }
+
+ for (auto it = service->characteristics.cbegin();
+ it != service->characteristics.cend(); it++) {
+ if (it->declaration_handle > pending_characteristic) {
+ auto next = std::next(it);
+
+ /* Characteristic Declaration is followed by Characteristic Value
+ * Declaration, first descriptor is after that, see BT Spect 5.0 Vol 3,
+ * Part G 3.3.2 and 3.3.3 */
+ uint16_t start = it->declaration_handle + 2;
+ uint16_t end;
+ if (next != service->characteristics.end())
+ end = next->declaration_handle - 1;
+ else
+ end = service->end_handle;
+
+ // No place for descriptor - skip to next characteristic
+ if (start > end) continue;
+
+ pending_characteristic = start;
+ return {start, end};
+ }
+ }
+
+ pending_characteristic = HANDLE_MAX;
+ return {HANDLE_MAX, HANDLE_MAX};
+}
+
+bool DatabaseBuilder::InProgress() const { return !database.services.empty(); }
+
+Database DatabaseBuilder::Build() {
+ Database tmp = database;
+ database.Clear();
+ return tmp;
+}
+
+void DatabaseBuilder::Clear() { database.Clear(); }
+
+std::string DatabaseBuilder::ToString() const { return database.ToString(); }
+
+} // namespace gatt
diff --git a/bta/gatt/database_builder.h b/bta/gatt/database_builder.h
new file mode 100644
index 0000000..0913100
--- /dev/null
+++ b/bta/gatt/database_builder.h
@@ -0,0 +1,84 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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 "gatt/database.h"
+
+#include <utility>
+#include <vector>
+
+namespace gatt {
+
+class DatabaseBuilder {
+ public:
+ constexpr static std::pair<uint16_t, uint16_t> EXPLORE_END =
+ std::make_pair(0xFFFF, 0xFFFF);
+
+ void AddService(uint16_t handle, uint16_t end_handle,
+ const bluetooth::Uuid& uuid, bool is_primary);
+ void AddIncludedService(uint16_t handle, const bluetooth::Uuid& uuid,
+ uint16_t start_handle, uint16_t end_handle);
+ void AddCharacteristic(uint16_t handle, uint16_t value_handle,
+ const bluetooth::Uuid& uuid, uint8_t properties);
+ void AddDescriptor(uint16_t handle, const bluetooth::Uuid& uuid);
+
+ /* Returns true if next service exploration started, false if there are no
+ * more services to explore. */
+ bool StartNextServiceExploration();
+
+ /* Return pair with start and end handle of the currently explored service.
+ */
+ const std::pair<uint16_t, uint16_t>& CurrentlyExploredService();
+
+ /* Return pair with start and end handle of the descriptor range to discover,
+ * or DatabaseBuilder::EXPLORE_END if no more descriptors left.
+ */
+ std::pair<uint16_t, uint16_t> NextDescriptorRangeToExplore();
+
+ /* Returns true, if GATT discovery is in progress, false if discovery was not
+ * started, or is already finished.
+ */
+ // TODO(jpawlowski): in the future, we might create this object only for the
+ // time of discovery, in such case InProgress won't be needed, because object
+ // existence will mean discovery is pending
+ bool InProgress() const;
+
+ /* Call this method at end of GATT discovery, to obtain object representing
+ * the database of remote device */
+ Database Build();
+
+ void Clear();
+
+ /* Return text representation of internal state for debugging purposes */
+ std::string ToString() const;
+
+ private:
+ Database database;
+ /* Start and end handle of service that is currently being discovered on the
+ * remote device */
+ std::pair<uint16_t, uint16_t> pending_service;
+ /* Characteristic inside pending_service that is currently being explored */
+ uint16_t pending_characteristic;
+
+ /* sorted, unique set of start_handle, end_handle pair of all services that
+ * have not yet been discovered */
+ std::set<std::pair<uint16_t, uint16_t>> services_to_discover;
+};
+
+} // namespace gatt
diff --git a/bta/hearing_aid/hearing_aid.cc b/bta/hearing_aid/hearing_aid.cc
index 3643184..187c0ab 100644
--- a/bta/hearing_aid/hearing_aid.cc
+++ b/bta/hearing_aid/hearing_aid.cc
@@ -44,24 +44,22 @@
constexpr uint16_t CONNECTION_INTERVAL_10MS_PARAM = 0x0008;
constexpr uint16_t CONNECTION_INTERVAL_20MS_PARAM = 0x0010;
-void btif_storage_add_hearing_aid(const RawAddress& address, uint16_t psm,
- uint8_t capabilities, uint16_t codecs,
- uint16_t audio_control_point_handle,
- uint16_t volume_handle, uint64_t hiSyncId,
- uint16_t render_delay,
- uint16_t preparation_delay);
+void btif_storage_add_hearing_aid(const HearingDevice& dev_info);
+bool btif_storage_get_hearing_aid_prop(
+ const RawAddress& address, uint8_t* capabilities, uint64_t* hi_sync_id,
+ uint16_t* render_delay, uint16_t* preparation_delay, uint16_t* codecs);
constexpr uint8_t CODEC_G722_16KHZ = 0x01;
constexpr uint8_t CODEC_G722_24KHZ = 0x02;
-// Masks for checking capability support
-constexpr uint8_t CAPABILITY_SIDE = 0x01;
-constexpr uint8_t CAPABILITY_BINAURAL = 0x02;
-constexpr uint8_t CAPABILITY_RESERVED = 0xFC;
-
// audio control point opcodes
constexpr uint8_t CONTROL_POINT_OP_START = 0x01;
constexpr uint8_t CONTROL_POINT_OP_STOP = 0x02;
+constexpr uint8_t CONTROL_POINT_OP_STATE_CHANGE = 0x03;
+
+constexpr uint8_t STATE_CHANGE_OTHER_SIDE_DISCONNECTED = 0x00;
+constexpr uint8_t STATE_CHANGE_OTHER_SIDE_CONNECTED = 0x01;
+constexpr uint8_t STATE_CHANGE_CONN_UPDATE = 0x02;
// used to mark current_volume as not yet known, or possibly old
constexpr int8_t VOLUME_UNKNOWN = 127;
@@ -70,6 +68,17 @@
// audio type
constexpr uint8_t AUDIOTYPE_UNKNOWN = 0x00;
+// Status of the other side Hearing Aids device
+constexpr uint8_t OTHER_SIDE_NOT_STREAMING = 0x00;
+constexpr uint8_t OTHER_SIDE_IS_STREAMING = 0x01;
+
+// This ADD_RENDER_DELAY_INTERVALS is the number of connection intervals when
+// the audio data packet is send by Audio Engine to when the Hearing Aids device
+// received it from the air. We assumed that there is 2 data buffer queued from
+// audio subsystem to bluetooth chip. Then the estimated OTA delay is two
+// connnection intervals.
+constexpr uint16_t ADD_RENDER_DELAY_INTERVALS = 4;
+
namespace {
// clang-format off
@@ -84,6 +93,7 @@
void hearingaid_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data);
void encryption_callback(const RawAddress*, tGATT_TRANSPORT, void*,
tBTM_STATUS);
+void read_rssi_cb(void* p_void);
inline BT_HDR* malloc_l2cap_buf(uint16_t len) {
BT_HDR* msg = (BT_HDR*)osi_malloc(BT_HDR_SIZE + L2CAP_MIN_OFFSET +
@@ -97,116 +107,10 @@
return (uint8_t*)(msg) + BT_HDR_SIZE + L2CAP_MIN_OFFSET;
}
-struct AudioStats {
- size_t packet_flush_count;
- size_t packet_send_count;
- size_t frame_flush_count;
- size_t frame_send_count;
-
- AudioStats() { Reset(); }
-
- void Reset() {
- packet_flush_count = 0;
- packet_send_count = 0;
- frame_flush_count = 0;
- frame_send_count = 0;
- }
-};
-
class HearingAidImpl;
HearingAidImpl* instance;
HearingAidAudioReceiver* audioReceiver;
-/** Possible states for the Connection Update status */
-typedef enum {
- NONE, // Connection Update not pending or has completed
- AWAITING, // Waiting for start the Connection Update operation
- STARTED // Connection Update has started
-} connection_update_status_t;
-
-struct HearingDevice {
- RawAddress address;
- /* This is true only during first connection to profile, until we store the
- * device */
- bool first_connection;
-
- /* we are making active attempt to connect to this device, 'direct connect'.
- * This is true only during initial phase of first connection. */
- bool connecting_actively;
-
- /* For two hearing aids, you must update their parameters one after another,
- * not simulteanously, to ensure start of connection events for both devices
- * are far from each other. This status tracks whether this device is waiting
- * for update of parameters, that should happen after "LE Connection Update
- * Complete" event
- */
- connection_update_status_t connection_update_status;
- uint16_t requested_connection_interval;
-
- /* if true, we are connected, L2CAP socket is open, we can stream audio.
- However, the actual audio stream also depends on whether the
- Audio Service has resumed.
- */
- bool accepting_audio;
-
- uint16_t conn_id;
- uint16_t gap_handle;
- uint16_t audio_control_point_handle;
- uint16_t volume_handle;
- uint16_t psm;
-
- uint8_t capabilities;
- uint64_t hi_sync_id;
- uint16_t render_delay;
- uint16_t preparation_delay;
- uint16_t codecs;
-
- AudioStats audio_stats;
- /* Keep tracks of whether the "Start Cmd" has been send to this device. When
- the "Stop Cmd" is send or when this device disconnects, then this flag is
- cleared. Please note that the "Start Cmd" is not send during device
- connection in the case when the audio is suspended. */
- bool playback_started;
-
- HearingDevice(const RawAddress& address, uint16_t psm, uint8_t capabilities,
- uint16_t codecs, uint16_t audio_control_point_handle,
- uint16_t volume_handle, uint64_t hiSyncId,
- uint16_t render_delay, uint16_t preparation_delay)
- : address(address),
- first_connection(false),
- connecting_actively(false),
- connection_update_status(NONE),
- accepting_audio(false),
- conn_id(0),
- gap_handle(0),
- audio_control_point_handle(audio_control_point_handle),
- volume_handle(volume_handle),
- psm(psm),
- capabilities(capabilities),
- hi_sync_id(hiSyncId),
- render_delay(render_delay),
- preparation_delay(preparation_delay),
- codecs(codecs),
- playback_started(false) {}
-
- HearingDevice(const RawAddress& address, bool first_connection)
- : address(address),
- first_connection(first_connection),
- connecting_actively(first_connection),
- connection_update_status(NONE),
- accepting_audio(false),
- conn_id(0),
- gap_handle(0),
- psm(0),
- playback_started(false) {}
-
- HearingDevice() { HearingDevice(RawAddress::kEmpty, false); }
-
- /* return true if this device represents left Hearing Aid. Returned value is
- * valid only after capabilities are discovered */
- bool isLeft() const { return !(capabilities & CAPABILITY_SIDE); }
-};
-
class HearingDevices {
public:
void Add(HearingDevice device) {
@@ -262,25 +166,78 @@
return false;
}
+ void StartRssiLog() {
+ int read_rssi_start_interval_count = 0;
+
+ for (auto& d : devices) {
+ VLOG(1) << __func__ << ": device=" << d.address << ", read_rssi_count=" << d.read_rssi_count;
+
+ // Reset the count
+ if (d.read_rssi_count <= 0) {
+ d.read_rssi_count = READ_RSSI_NUM_TRIES;
+ d.num_intervals_since_last_rssi_read = read_rssi_start_interval_count;
+
+ // Spaced apart the Read RSSI commands to the BT controller.
+ read_rssi_start_interval_count += PERIOD_TO_READ_RSSI_IN_INTERVALS / 2;
+ read_rssi_start_interval_count %= PERIOD_TO_READ_RSSI_IN_INTERVALS;
+
+ std::deque<rssi_log>& rssi_logs = d.audio_stats.rssi_history;
+ if (rssi_logs.size() >= MAX_RSSI_HISTORY) {
+ rssi_logs.pop_front();
+ }
+ rssi_logs.emplace_back();
+ }
+ }
+ }
+
size_t size() { return (devices.size()); }
std::vector<HearingDevice> devices;
};
+static void write_rpt_ctl_cfg_cb(uint16_t conn_id, tGATT_STATUS status,
+ uint16_t handle, void* data) {
+ if (status != GATT_SUCCESS) {
+ LOG(ERROR) << __func__ << ": handle=" << handle << ", conn_id=" << conn_id
+ << ", status=" << loghex(status);
+ }
+}
+
g722_encode_state_t* encoder_state_left = nullptr;
g722_encode_state_t* encoder_state_right = nullptr;
+inline void encoder_state_init() {
+ if (encoder_state_left != nullptr) {
+ LOG(WARNING) << __func__ << ": encoder already initialized";
+ return;
+ }
+ encoder_state_left = g722_encode_init(nullptr, 64000, G722_PACKED);
+ encoder_state_right = g722_encode_init(nullptr, 64000, G722_PACKED);
+}
+
+inline void encoder_state_release() {
+ if (encoder_state_left != nullptr) {
+ g722_encode_release(encoder_state_left);
+ encoder_state_left = nullptr;
+ g722_encode_release(encoder_state_right);
+ encoder_state_right = nullptr;
+ }
+}
+
class HearingAidImpl : public HearingAid {
private:
// Keep track of whether the Audio Service has resumed audio playback
bool audio_running;
+ // For Testing: overwrite the MIN_CE_LEN during connection parameter updates
+ uint16_t overwrite_min_ce_len;
public:
- virtual ~HearingAidImpl() = default;
+ ~HearingAidImpl() override = default;
HearingAidImpl(bluetooth::hearing_aid::HearingAidCallbacks* callbacks,
Closure initCb)
: audio_running(false),
+ overwrite_min_ce_len(0),
gatt_if(0),
seq_counter(0),
current_volume(VOLUME_UNKNOWN),
@@ -298,6 +255,13 @@
VLOG(2) << __func__
<< ", default_data_interval_ms=" << default_data_interval_ms;
+ overwrite_min_ce_len = (uint16_t)osi_property_get_int32(
+ "persist.bluetooth.hearingaidmincelen", 0);
+ if (overwrite_min_ce_len) {
+ LOG(INFO) << __func__
+ << ": Overwrites MIN_CE_LEN=" << overwrite_min_ce_len;
+ }
+
BTA_GATTC_AppRegister(
hearingaid_gattc_callback,
base::Bind(
@@ -334,6 +298,12 @@
connection_interval = CONNECTION_INTERVAL_10MS_PARAM;
}
+ if (overwrite_min_ce_len != 0) {
+ VLOG(2) << __func__ << ": min_ce_len=" << min_ce_len
+ << " is overwritten to " << overwrite_min_ce_len;
+ min_ce_len = overwrite_min_ce_len;
+ }
+
L2CA_UpdateBleConnParams(address, connection_interval, connection_interval,
0x000A, 0x0064 /*1s*/, min_ce_len, min_ce_len);
return connection_interval;
@@ -349,37 +319,26 @@
VLOG(2) << __func__ << " address: " << address;
hearingDevices.Add(HearingDevice(address, true));
BTA_GATTC_Open(gatt_if, address, false, GATT_TRANSPORT_LE, false);
- BTA_DmBleStartAutoConn();
}
- void RemoveFromWhiteList(const RawAddress& address) override {
- VLOG(2) << __func__ << " address: " << address;
- BTA_GATTC_CancelOpen(gatt_if, address, false);
- }
-
- void AddFromStorage(const RawAddress& address, uint16_t psm,
- uint8_t capabilities, uint16_t codecs,
- uint16_t audio_control_point_handle,
- uint16_t volume_handle, uint64_t hiSyncId,
- uint16_t render_delay, uint16_t preparation_delay,
- uint16_t is_white_listed) {
- DVLOG(2) << __func__ << " " << address << ", hiSyncId=" << loghex(hiSyncId)
+ void AddFromStorage(const HearingDevice& dev_info, uint16_t is_white_listed) {
+ DVLOG(2) << __func__ << " " << dev_info.address
+ << ", hiSyncId=" << loghex(dev_info.hi_sync_id)
<< ", isWhiteListed=" << is_white_listed;
if (is_white_listed) {
- hearingDevices.Add(HearingDevice(
- address, psm, capabilities, codecs, audio_control_point_handle,
- volume_handle, hiSyncId, render_delay, preparation_delay));
+ hearingDevices.Add(dev_info);
// TODO: we should increase the scanning window for few seconds, to get
// faster initial connection, same after hearing aid disconnects, i.e.
// BTM_BleSetConnScanParams(2048, 1024);
/* add device into BG connection to accept remote initiated connection */
- BTA_GATTC_Open(gatt_if, address, false, GATT_TRANSPORT_LE, false);
- BTA_DmBleStartAutoConn();
+ BTA_GATTC_Open(gatt_if, dev_info.address, false, GATT_TRANSPORT_LE,
+ false);
}
- callbacks->OnDeviceAvailable(capabilities, hiSyncId, address);
+ callbacks->OnDeviceAvailable(dev_info.capabilities, dev_info.hi_sync_id,
+ dev_info.address);
}
int GetDeviceCount() { return (hearingDevices.size()); }
@@ -391,7 +350,11 @@
HearingDevice* hearingDevice = hearingDevices.FindByAddress(address);
if (!hearingDevice) {
- DVLOG(2) << "Skipping unknown device, address=" << address;
+ /* When Hearing Aid is quickly disabled and enabled in settings, this case
+ * might happen */
+ LOG(WARNING) << "Closing connection to non hearing-aid device, address="
+ << address;
+ BTA_GATTC_Close(conn_id);
return;
}
@@ -471,31 +434,72 @@
}
if (p_data) {
- if ((p_data->conn_update.status == 0) &&
- (hearingDevice->requested_connection_interval !=
- p_data->conn_update.interval)) {
- LOG(WARNING) << __func__ << ": Ignored. Different connection interval="
- << p_data->conn_update.interval << ", expected="
- << hearingDevice->requested_connection_interval
- << ", conn_id=" << conn_id;
- return;
- }
- LOG(INFO) << __func__ << ": interval=" << p_data->conn_update.interval
- << ": status=" << loghex(p_data->conn_update.status)
- << ", conn_id=" << conn_id;
- }
+ if (p_data->conn_update.status == 0) {
+ bool same_conn_interval =
+ (hearingDevice->requested_connection_interval ==
+ p_data->conn_update.interval);
- if (hearingDevice->connection_update_status != STARTED) {
- // TODO: We may get extra connection updates during service discovery and
- // these updates are not accounted for.
- LOG(INFO) << __func__
- << ": Unexpected connection update complete. Expecting "
- "state=STARTED but current="
- << hearingDevice->connection_update_status
- << ", conn_id=" << conn_id
- << ", device=" << hearingDevice->address;
+ switch (hearingDevice->connection_update_status) {
+ case COMPLETED:
+ if (!same_conn_interval) {
+ LOG(WARNING) << __func__
+ << ": Unexpected change. Redo. connection interval="
+ << p_data->conn_update.interval << ", expected="
+ << hearingDevice->requested_connection_interval
+ << ", conn_id=" << conn_id
+ << ", connection_update_status="
+ << hearingDevice->connection_update_status;
+ // Redo this connection interval change.
+ hearingDevice->connection_update_status = AWAITING;
+ }
+ break;
+ case STARTED:
+ if (same_conn_interval) {
+ LOG(INFO) << __func__
+ << ": Connection update completed. conn_id=" << conn_id
+ << ", device=" << hearingDevice->address;
+ hearingDevice->connection_update_status = COMPLETED;
+ } else {
+ LOG(WARNING) << __func__
+ << ": Ignored. Different connection interval="
+ << p_data->conn_update.interval << ", expected="
+ << hearingDevice->requested_connection_interval
+ << ", conn_id=" << conn_id
+ << ", connection_update_status="
+ << hearingDevice->connection_update_status;
+ // Wait for the right Connection Update Completion.
+ return;
+ }
+ break;
+ case AWAITING:
+ case NONE:
+ break;
+ }
+
+ // Inform this side and other side device (if any) of Connection
+ // Updates.
+ std::vector<uint8_t> conn_update(
+ {CONTROL_POINT_OP_STATE_CHANGE, STATE_CHANGE_CONN_UPDATE,
+ (uint8_t)p_data->conn_update.interval});
+ send_state_change_to_other_side(hearingDevice, conn_update);
+ send_state_change(hearingDevice, conn_update);
+ } else {
+ LOG(INFO) << __func__
+ << ": error status=" << loghex(p_data->conn_update.status)
+ << ", conn_id=" << conn_id
+ << ", device=" << hearingDevice->address
+ << ", connection_update_status="
+ << hearingDevice->connection_update_status;
+
+ if (hearingDevice->connection_update_status == STARTED) {
+ // Redo this connection interval change.
+ LOG(ERROR) << __func__ << ": Redo Connection Interval change";
+ hearingDevice->connection_update_status = AWAITING;
+ }
+ }
+ } else {
+ hearingDevice->connection_update_status = NONE;
}
- hearingDevice->connection_update_status = NONE;
for (auto& device : hearingDevices.devices) {
if (device.conn_id && (device.connection_update_status == AWAITING)) {
@@ -507,6 +511,34 @@
}
}
+ // Completion Callback for the RSSI read operation.
+ void OnReadRssiComplete(const RawAddress& address, int8_t rssi_value) {
+ HearingDevice* hearingDevice = hearingDevices.FindByAddress(address);
+ if (!hearingDevice) {
+ LOG(INFO) << "Skipping unknown device" << address;
+ return;
+ }
+
+ VLOG(1) << __func__ << ": device=" << address << ", rssi=" << (int)rssi_value;
+
+ if (hearingDevice->read_rssi_count <= 0) {
+ LOG(ERROR) << __func__ << ": device=" << address
+ << ", invalid read_rssi_count=" << hearingDevice->read_rssi_count;
+ return;
+ }
+
+ rssi_log& last_log_set = hearingDevice->audio_stats.rssi_history.back();
+
+ if (hearingDevice->read_rssi_count == READ_RSSI_NUM_TRIES) {
+ // Store the timestamp only for the first one after packet flush
+ clock_gettime(CLOCK_REALTIME, &last_log_set.timestamp);
+ LOG(INFO) << __func__ << ": store time. device=" << address << ", rssi=" << (int)rssi_value;
+ }
+
+ last_log_set.rssi.emplace_back(rssi_value);
+ hearingDevice->read_rssi_count--;
+ }
+
void OnEncryptionComplete(const RawAddress& address, bool success) {
HearingDevice* hearingDevice = hearingDevices.FindByAddress(address);
if (!hearingDevice) {
@@ -525,13 +557,43 @@
DVLOG(2) << __func__ << " " << address;
- if (!hearingDevice->first_connection) {
- // Use cached data, jump to connecting socket
- ConnectSocket(hearingDevice);
+ if (hearingDevice->audio_control_point_handle &&
+ hearingDevice->audio_status_handle &&
+ hearingDevice->audio_status_ccc_handle &&
+ hearingDevice->volume_handle && hearingDevice->read_psm_handle) {
+ // Use cached data, jump to read PSM
+ ReadPSM(hearingDevice);
+ } else {
+ hearingDevice->first_connection = true;
+ BTA_GATTC_ServiceSearchRequest(hearingDevice->conn_id, &HEARING_AID_UUID);
+ }
+ }
+
+ void OnServiceChangeEvent(const RawAddress& address) {
+ HearingDevice* hearingDevice = hearingDevices.FindByAddress(address);
+ if (!hearingDevice) {
+ VLOG(2) << "Skipping unknown device" << address;
return;
}
+ LOG(INFO) << __func__ << ": address=" << address;
+ hearingDevice->first_connection = true;
+ hearingDevice->service_changed_rcvd = true;
+ BtaGattQueue::Clean(hearingDevice->conn_id);
+ if (hearingDevice->gap_handle) {
+ GAP_ConnClose(hearingDevice->gap_handle);
+ hearingDevice->gap_handle = 0;
+ }
+ }
- BTA_GATTC_ServiceSearchRequest(hearingDevice->conn_id, &HEARING_AID_UUID);
+ void OnServiceDiscDoneEvent(const RawAddress& address) {
+ HearingDevice* hearingDevice = hearingDevices.FindByAddress(address);
+ if (!hearingDevice) {
+ VLOG(2) << "Skipping unknown device" << address;
+ return;
+ }
+ if (hearingDevice->service_changed_rcvd) {
+ BTA_GATTC_ServiceSearchRequest(hearingDevice->conn_id, &HEARING_AID_UUID);
+ }
}
void OnServiceSearchComplete(uint16_t conn_id, tGATT_STATUS status) {
@@ -554,15 +616,19 @@
return;
}
- const std::vector<tBTA_GATTC_SERVICE>* services =
- BTA_GATTC_GetServices(conn_id);
+ const std::vector<gatt::Service>* services = BTA_GATTC_GetServices(conn_id);
- const tBTA_GATTC_SERVICE* service = nullptr;
- for (const tBTA_GATTC_SERVICE& tmp : *services) {
- if (tmp.uuid != HEARING_AID_UUID) continue;
- LOG(INFO) << "Found Hearing Aid service, handle=" << loghex(tmp.handle);
- service = &tmp;
- break;
+ const gatt::Service* service = nullptr;
+ for (const gatt::Service& tmp : *services) {
+ if (tmp.uuid == Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER)) {
+ LOG(INFO) << "Found UUID_SERVCLASS_GATT_SERVER, handle="
+ << loghex(tmp.handle);
+ const gatt::Service* service_changed_service = &tmp;
+ find_server_changed_ccc_handle(conn_id, service_changed_service);
+ } else if (tmp.uuid == HEARING_AID_UUID) {
+ LOG(INFO) << "Found Hearing Aid service, handle=" << loghex(tmp.handle);
+ service = &tmp;
+ }
}
if (!service) {
@@ -572,36 +638,92 @@
return;
}
- uint16_t psm_handle = 0x0000;
- for (const tBTA_GATTC_CHARACTERISTIC& charac : service->characteristics) {
+ for (const gatt::Characteristic& charac : service->characteristics) {
if (charac.uuid == READ_ONLY_PROPERTIES_UUID) {
- DVLOG(2) << "Reading read only properties "
- << loghex(charac.value_handle);
- BtaGattQueue::ReadCharacteristic(
- conn_id, charac.value_handle,
- HearingAidImpl::OnReadOnlyPropertiesReadStatic, nullptr);
+ if (!btif_storage_get_hearing_aid_prop(
+ hearingDevice->address, &hearingDevice->capabilities,
+ &hearingDevice->hi_sync_id, &hearingDevice->render_delay,
+ &hearingDevice->preparation_delay, &hearingDevice->codecs)) {
+ VLOG(2) << "Reading read only properties "
+ << loghex(charac.value_handle);
+ BtaGattQueue::ReadCharacteristic(
+ conn_id, charac.value_handle,
+ HearingAidImpl::OnReadOnlyPropertiesReadStatic, nullptr);
+ }
} else if (charac.uuid == AUDIO_CONTROL_POINT_UUID) {
hearingDevice->audio_control_point_handle = charac.value_handle;
// store audio control point!
} else if (charac.uuid == AUDIO_STATUS_UUID) {
- DVLOG(2) << "Reading Audio status " << loghex(charac.value_handle);
- BtaGattQueue::ReadCharacteristic(conn_id, charac.value_handle,
- HearingAidImpl::OnAudioStatusStatic,
- nullptr);
+ hearingDevice->audio_status_handle = charac.value_handle;
+
+ hearingDevice->audio_status_ccc_handle =
+ find_ccc_handle(conn_id, charac.value_handle);
+ if (!hearingDevice->audio_status_ccc_handle) {
+ LOG(ERROR) << __func__ << ": cannot find Audio Status CCC descriptor";
+ continue;
+ }
+
+ LOG(INFO) << __func__
+ << ": audio_status_handle=" << loghex(charac.value_handle)
+ << ", ccc=" << loghex(hearingDevice->audio_status_ccc_handle);
} else if (charac.uuid == VOLUME_UUID) {
hearingDevice->volume_handle = charac.value_handle;
} else if (charac.uuid == LE_PSM_UUID) {
- psm_handle = charac.value_handle;
+ hearingDevice->read_psm_handle = charac.value_handle;
} else {
LOG(WARNING) << "Unknown characteristic found:" << charac.uuid;
}
}
- if (psm_handle) {
- DVLOG(2) << "Reading PSM " << loghex(psm_handle);
- BtaGattQueue::ReadCharacteristic(
- conn_id, psm_handle, HearingAidImpl::OnPsmReadStatic, nullptr);
+ if (hearingDevice->service_changed_rcvd) {
+ hearingDevice->service_changed_rcvd = false;
}
+
+ ReadPSM(hearingDevice);
+ }
+
+ void ReadPSM(HearingDevice* hearingDevice) {
+ if (hearingDevice->read_psm_handle) {
+ LOG(INFO) << "Reading PSM " << loghex(hearingDevice->read_psm_handle)
+ << ", device=" << hearingDevice->address;
+ BtaGattQueue::ReadCharacteristic(
+ hearingDevice->conn_id, hearingDevice->read_psm_handle,
+ HearingAidImpl::OnPsmReadStatic, nullptr);
+ }
+ }
+
+ void OnNotificationEvent(uint16_t conn_id, uint16_t handle, uint16_t len,
+ uint8_t* value) {
+ HearingDevice* device = hearingDevices.FindByConnId(conn_id);
+ if (!device) {
+ LOG(INFO) << __func__
+ << ": Skipping unknown device, conn_id=" << loghex(conn_id);
+ return;
+ }
+
+ if (device->audio_status_handle != handle) {
+ LOG(INFO) << __func__ << ": Mismatched handle, "
+ << loghex(device->audio_status_handle)
+ << "!=" << loghex(handle);
+ return;
+ }
+
+ if (len < 1) {
+ LOG(ERROR) << __func__ << ": Data Length too small, len=" << len
+ << ", expecting at least 1";
+ return;
+ }
+
+ if (value[0] != 0) {
+ LOG(INFO) << __func__
+ << ": Invalid returned status. data=" << loghex(value[0]);
+ return;
+ }
+
+ LOG(INFO) << __func__
+ << ": audio status success notification. command_acked="
+ << device->command_acked;
+ device->command_acked = true;
}
void OnReadOnlyPropertiesRead(uint16_t conn_id, tGATT_STATUS status,
@@ -712,7 +834,7 @@
void OnAudioStatus(uint16_t conn_id, tGATT_STATUS status, uint16_t handle,
uint16_t len, uint8_t* value, void* data) {
- DVLOG(2) << __func__ << " " << base::HexEncode(value, len);
+ LOG(INFO) << __func__ << " " << base::HexEncode(value, len);
}
void OnPsmRead(uint16_t conn_id, tGATT_STATUS status, uint16_t handle,
@@ -733,24 +855,25 @@
return;
}
- uint16_t psm_val = *((uint16_t*)value);
- hearingDevice->psm = psm_val;
- VLOG(2) << "read psm:" << loghex(hearingDevice->psm);
+ uint16_t psm = *((uint16_t*)value);
+ VLOG(2) << "read psm:" << loghex(psm);
- ConnectSocket(hearingDevice);
+ ConnectSocket(hearingDevice, psm);
}
- void ConnectSocket(HearingDevice* hearingDevice) {
+ void ConnectSocket(HearingDevice* hearingDevice, uint16_t psm) {
tL2CAP_CFG_INFO cfg_info = tL2CAP_CFG_INFO{.mtu = 512};
+ SendEnableServiceChangedInd(hearingDevice);
+
uint8_t service_id = hearingDevice->isLeft()
? BTM_SEC_SERVICE_HEARING_AID_LEFT
: BTM_SEC_SERVICE_HEARING_AID_RIGHT;
uint16_t gap_handle = GAP_ConnOpen(
- "", service_id, false, &hearingDevice->address, hearingDevice->psm,
- 514 /* MPS */, &cfg_info, nullptr,
- BTM_SEC_NONE /* TODO: request security ? */, L2CAP_FCR_LE_COC_MODE,
- HearingAidImpl::GapCallbackStatic, BT_TRANSPORT_LE);
+ "", service_id, false, &hearingDevice->address, psm, 514 /* MPS */,
+ &cfg_info, nullptr, BTM_SEC_NONE /* TODO: request security ? */,
+ L2CAP_FCR_LE_COC_MODE, HearingAidImpl::GapCallbackStatic,
+ BT_TRANSPORT_LE);
if (gap_handle == GAP_INVALID_HANDLE) {
LOG(ERROR) << "UNABLE TO GET gap_handle";
return;
@@ -793,25 +916,50 @@
if (hearingDevice->first_connection) {
/* add device into BG connection to accept remote initiated connection */
BTA_GATTC_Open(gatt_if, address, false, GATT_TRANSPORT_LE, false);
- BTA_DmBleStartAutoConn();
- btif_storage_add_hearing_aid(
- address, hearingDevice->psm, hearingDevice->capabilities,
- hearingDevice->codecs, hearingDevice->audio_control_point_handle,
- hearingDevice->volume_handle, hearingDevice->hi_sync_id,
- hearingDevice->render_delay, hearingDevice->preparation_delay);
+ btif_storage_add_hearing_aid(*hearingDevice);
hearingDevice->first_connection = false;
}
+ LOG(INFO) << __func__ << ": audio_status_handle="
+ << loghex(hearingDevice->audio_status_handle)
+ << ", audio_status_ccc_handle="
+ << loghex(hearingDevice->audio_status_ccc_handle);
+
+ /* Register and enable the Audio Status Notification */
+ tGATT_STATUS register_status;
+ register_status = BTA_GATTC_RegisterForNotifications(
+ gatt_if, address, hearingDevice->audio_status_handle);
+ if (register_status != GATT_SUCCESS) {
+ LOG(ERROR) << __func__
+ << ": BTA_GATTC_RegisterForNotifications failed, status="
+ << loghex(register_status);
+ return;
+ }
+ std::vector<uint8_t> value(2);
+ uint8_t* ptr = value.data();
+ UINT16_TO_STREAM(ptr, GATT_CHAR_CLIENT_CONFIG_NOTIFICATION);
+ BtaGattQueue::WriteDescriptor(
+ hearingDevice->conn_id, hearingDevice->audio_status_ccc_handle,
+ std::move(value), GATT_WRITE, write_rpt_ctl_cfg_cb, nullptr);
+
ChooseCodec(*hearingDevice);
SendStart(hearingDevice);
+ if (audio_running) {
+ // Inform the other side (if any) of this connection
+ std::vector<uint8_t> inform_conn_state(
+ {CONTROL_POINT_OP_STATE_CHANGE, STATE_CHANGE_OTHER_SIDE_CONNECTED});
+ send_state_change_to_other_side(hearingDevice, inform_conn_state);
+ }
+
hearingDevice->accepting_audio = true;
LOG(INFO) << __func__ << ": address=" << address
<< ", hi_sync_id=" << loghex(hearingDevice->hi_sync_id)
- << ", codec_in_use=" << loghex(codec_in_use);
+ << ", codec_in_use=" << loghex(codec_in_use)
+ << ", audio_running=" << audio_running;
StartSendingAudio(*hearingDevice);
@@ -821,11 +969,10 @@
}
void StartSendingAudio(const HearingDevice& hearingDevice) {
- VLOG(0) << __func__ << hearingDevice.address;
+ VLOG(0) << __func__ << ": device=" << hearingDevice.address;
if (encoder_state_left == nullptr) {
- encoder_state_left = g722_encode_init(nullptr, 64000, G722_PACKED);
- encoder_state_right = g722_encode_init(nullptr, 64000, G722_PACKED);
+ encoder_state_init();
seq_counter = 0;
// use the best codec avaliable for this pair of devices.
@@ -847,7 +994,14 @@
codec.bit_rate = 16;
codec.data_interval_ms = default_data_interval_ms;
- HearingAidAudioSource::Start(codec, audioReceiver);
+ uint16_t delay_report_ms = 0;
+ if (hearingDevice.render_delay != 0) {
+ delay_report_ms =
+ hearingDevice.render_delay +
+ (ADD_RENDER_DELAY_INTERVALS * default_data_interval_ms);
+ }
+
+ HearingAidAudioSource::Start(codec, audioReceiver, delay_report_ms);
}
}
@@ -870,6 +1024,7 @@
} else {
LOG(INFO) << __func__ << ": send Stop cmd, device=" << device.address;
device.playback_started = false;
+ device.command_acked = false;
BtaGattQueue::WriteCharacteristic(device.conn_id,
device.audio_control_point_handle,
stop, GATT_WRITE, nullptr, nullptr);
@@ -886,12 +1041,8 @@
audio_running = true;
// TODO: shall we also reset the encoder ?
- if (encoder_state_left != nullptr) {
- g722_encode_release(encoder_state_left);
- g722_encode_release(encoder_state_right);
- encoder_state_left = g722_encode_init(nullptr, 64000, G722_PACKED);
- encoder_state_right = g722_encode_init(nullptr, 64000, G722_PACKED);
- }
+ encoder_state_release();
+ encoder_state_init();
seq_counter = 0;
for (auto& device : hearingDevices.devices) {
@@ -900,9 +1051,36 @@
}
}
+ uint8_t GetOtherSideStreamStatus(HearingDevice* this_side_device) {
+ for (auto& device : hearingDevices.devices) {
+ if ((device.address == this_side_device->address) ||
+ (device.hi_sync_id != this_side_device->hi_sync_id)) {
+ continue;
+ }
+ if (audio_running && (device.conn_id != 0)) {
+ return (OTHER_SIDE_IS_STREAMING);
+ } else {
+ return (OTHER_SIDE_NOT_STREAMING);
+ }
+ }
+ return (OTHER_SIDE_NOT_STREAMING);
+ }
+
+ void SendEnableServiceChangedInd(HearingDevice* device) {
+ VLOG(2) << __func__ << " Enable " << device->address
+ << "service changed ind.";
+ std::vector<uint8_t> value(2);
+ uint8_t* ptr = value.data();
+ UINT16_TO_STREAM(ptr, GATT_CHAR_CLIENT_CONFIG_INDICTION);
+ BtaGattQueue::WriteDescriptor(
+ device->conn_id, device->service_changed_ccc_handle, std::move(value),
+ GATT_WRITE, nullptr, nullptr);
+ }
+
void SendStart(HearingDevice* device) {
std::vector<uint8_t> start({CONTROL_POINT_OP_START, codec_in_use,
- AUDIOTYPE_UNKNOWN, (uint8_t)current_volume});
+ AUDIOTYPE_UNKNOWN, (uint8_t)current_volume,
+ OTHER_SIDE_NOT_STREAMING});
if (!audio_running) {
if (!device->playback_started) {
@@ -924,10 +1102,13 @@
<< ": Playback already started, skip send Start cmd, device="
<< device->address;
} else {
+ start[4] = GetOtherSideStreamStatus(device);
LOG(INFO) << __func__ << ": send Start cmd, volume=" << loghex(start[3])
<< ", audio type=" << loghex(start[2])
- << ", device=" << device->address;
+ << ", device=" << device->address
+ << ", other side streaming=" << loghex(start[4]);
device->playback_started = true;
+ device->command_acked = false;
BtaGattQueue::WriteCharacteristic(device->conn_id,
device->audio_control_point_handle,
start, GATT_WRITE, nullptr, nullptr);
@@ -960,6 +1141,8 @@
if (left == nullptr && right == nullptr) {
HearingAidAudioSource::Stop();
+ audio_running = false;
+ encoder_state_release();
current_volume = VOLUME_UNKNOWN;
return;
}
@@ -1016,9 +1199,11 @@
<< " packets";
left->audio_stats.packet_flush_count += packets_to_flush;
left->audio_stats.frame_flush_count++;
+ hearingDevices.StartRssiLog();
}
// flush all packets stuck in queue
L2CA_FlushChannel(cid, 0xffff);
+ check_and_do_rssi_read(left);
}
std::vector<uint8_t> encoded_data_right;
@@ -1038,9 +1223,11 @@
<< " packets";
right->audio_stats.packet_flush_count += packets_to_flush;
right->audio_stats.frame_flush_count++;
+ hearingDevices.StartRssiLog();
}
// flush all packets stuck in queue
L2CA_FlushChannel(cid, 0xffff);
+ check_and_do_rssi_read(right);
}
size_t encoded_data_size =
@@ -1066,9 +1253,11 @@
void SendAudio(uint8_t* encoded_data, uint16_t packet_size,
HearingDevice* hearingAid) {
- if (!hearingAid->playback_started) {
- LOG(INFO) << __func__
- << ": Playback not started, device=" << hearingAid->address;
+ if (!hearingAid->playback_started || !hearingAid->command_acked) {
+ VLOG(2) << __func__
+ << ": Playback stalled, device=" << hearingAid->address
+ << ", cmd send=" << hearingAid->playback_started
+ << ", cmd acked=" << hearingAid->command_acked;
return;
}
@@ -1112,6 +1301,7 @@
hearingDevice->accepting_audio = false;
hearingDevice->gap_handle = 0;
hearingDevice->playback_started = false;
+ hearingDevice->command_acked = false;
break;
case GAP_EVT_CONN_DATA_AVAIL: {
DVLOG(2) << "GAP_EVT_CONN_DATA_AVAIL";
@@ -1176,6 +1366,40 @@
if (instance) instance->GapCallback(gap_handle, event, data);
}
+ void DumpRssi(int fd, const HearingDevice& device) {
+ const struct AudioStats* stats = &device.audio_stats;
+
+ if (stats->rssi_history.size() <= 0) {
+ dprintf(fd, " No RSSI history for %s:\n", device.address.ToString().c_str());
+ return;
+ }
+ dprintf(fd, " RSSI history for %s:\n", device.address.ToString().c_str());
+
+ dprintf(fd, " Time of RSSI 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9\n");
+ for (auto& rssi_logs : stats->rssi_history) {
+ if (rssi_logs.rssi.size() <= 0) {
+ break;
+ }
+
+ char eventtime[20];
+ char temptime[20];
+ struct tm* tstamp = localtime(&rssi_logs.timestamp.tv_sec);
+ if (!strftime(temptime, sizeof(temptime), "%H:%M:%S", tstamp)) {
+ LOG(ERROR) << __func__ << ": strftime fails. tm_sec=" << tstamp->tm_sec << ", tm_min=" << tstamp->tm_min
+ << ", tm_hour=" << tstamp->tm_hour;
+ strlcpy(temptime, "UNKNOWN TIME", sizeof(temptime));
+ }
+ snprintf(eventtime, sizeof(eventtime), "%s.%03ld", temptime, rssi_logs.timestamp.tv_nsec / 1000000);
+
+ dprintf(fd, " %s: ", eventtime);
+
+ for (auto rssi_value : rssi_logs.rssi) {
+ dprintf(fd, " %04d", rssi_value);
+ }
+ dprintf(fd, "\n");
+ }
+ }
+
void Dump(int fd) {
std::stringstream stream;
for (const auto& device : hearingDevices.devices) {
@@ -1193,6 +1417,8 @@
<< "\n Frame counts (enqueued/flushed) : "
<< device.audio_stats.frame_send_count << " / "
<< device.audio_stats.frame_flush_count << std::endl;
+
+ DumpRssi(fd, device);
}
dprintf(fd, "%s", stream.str().c_str());
}
@@ -1208,28 +1434,23 @@
VLOG(2) << __func__ << ": " << address;
bool connected = hearingDevice->accepting_audio;
- hearingDevice->accepting_audio = false;
LOG(INFO) << "GAP_EVT_CONN_CLOSED: " << hearingDevice->address
- << ", playback_started=" << hearingDevice->playback_started;
- hearingDevice->playback_started = false;
+ << ", playback_started=" << hearingDevice->playback_started
+ << ", accepting_audio=" << hearingDevice->accepting_audio;
if (hearingDevice->connecting_actively) {
// cancel pending direct connect
BTA_GATTC_CancelOpen(gatt_if, address, true);
}
- if (hearingDevice->conn_id) {
- BTA_GATTC_Close(hearingDevice->conn_id);
- }
+ // Removes all registrations for connection.
+ BTA_GATTC_CancelOpen(0, address, false);
- if (hearingDevice->gap_handle) {
- GAP_ConnClose(hearingDevice->gap_handle);
- hearingDevice->gap_handle = 0;
- }
-
- // cancel autoconnect
- BTA_GATTC_CancelOpen(gatt_if, address, false);
+ // Inform the other side (if any) of this disconnection
+ std::vector<uint8_t> inform_disconn_state(
+ {CONTROL_POINT_OP_STATE_CHANGE, STATE_CHANGE_OTHER_SIDE_DISCONNECTED});
+ send_state_change_to_other_side(hearingDevice, inform_disconn_state);
DoDisconnectCleanUp(hearingDevice);
@@ -1244,9 +1465,17 @@
tBTA_GATT_REASON reason) {
HearingDevice* hearingDevice = hearingDevices.FindByConnId(conn_id);
if (!hearingDevice) {
- VLOG(2) << "Skipping unknown device disconnect, conn_id=" << conn_id;
+ VLOG(2) << "Skipping unknown device disconnect, conn_id="
+ << loghex(conn_id);
return;
}
+ VLOG(2) << __func__ << ": conn_id=" << loghex(conn_id)
+ << ", reason=" << loghex(reason) << ", remote_bda=" << remote_bda;
+
+ // Inform the other side (if any) of this disconnection
+ std::vector<uint8_t> inform_disconn_state(
+ {CONTROL_POINT_OP_STATE_CHANGE, STATE_CHANGE_OTHER_SIDE_DISCONNECTED});
+ send_state_change_to_other_side(hearingDevice, inform_disconn_state);
DoDisconnectCleanUp(hearingDevice);
@@ -1254,7 +1483,7 @@
}
void DoDisconnectCleanUp(HearingDevice* hearingDevice) {
- if (hearingDevice->connection_update_status != NONE) {
+ if (hearingDevice->connection_update_status != COMPLETED) {
LOG(INFO) << __func__ << ": connection update not completed. Current="
<< hearingDevice->connection_update_status
<< ", device=" << hearingDevice->address;
@@ -1262,16 +1491,25 @@
if (hearingDevice->connection_update_status == STARTED) {
OnConnectionUpdateComplete(hearingDevice->conn_id, NULL);
}
- hearingDevice->connection_update_status = NONE;
+ }
+ hearingDevice->connection_update_status = NONE;
+
+ if (hearingDevice->conn_id) {
+ BtaGattQueue::Clean(hearingDevice->conn_id);
+ BTA_GATTC_Close(hearingDevice->conn_id);
+ hearingDevice->conn_id = 0;
}
- BtaGattQueue::Clean(hearingDevice->conn_id);
+ if (hearingDevice->gap_handle) {
+ GAP_ConnClose(hearingDevice->gap_handle);
+ hearingDevice->gap_handle = 0;
+ }
hearingDevice->accepting_audio = false;
- hearingDevice->conn_id = 0;
LOG(INFO) << __func__ << ": device=" << hearingDevice->address
<< ", playback_started=" << hearingDevice->playback_started;
hearingDevice->playback_started = false;
+ hearingDevice->command_acked = false;
}
void SetVolume(int8_t volume) override {
@@ -1290,14 +1528,12 @@
void CleanUp() {
BTA_GATTC_AppDeregister(gatt_if);
for (HearingDevice& device : hearingDevices.devices) {
- if (!device.gap_handle) continue;
-
- GAP_ConnClose(device.gap_handle);
- device.gap_handle = 0;
+ DoDisconnectCleanUp(&device);
}
hearingDevices.devices.clear();
- HearingAidAudioSource::Stop();
+
+ encoder_state_release();
}
private:
@@ -1313,8 +1549,99 @@
uint16_t default_data_interval_ms;
HearingDevices hearingDevices;
+
+ void find_server_changed_ccc_handle(uint16_t conn_id,
+ const gatt::Service* service) {
+ HearingDevice* hearingDevice = hearingDevices.FindByConnId(conn_id);
+ if (!hearingDevice) {
+ DVLOG(2) << "Skipping unknown device, conn_id=" << loghex(conn_id);
+ return;
+ }
+ for (const gatt::Characteristic& charac : service->characteristics) {
+ if (charac.uuid == Uuid::From16Bit(GATT_UUID_GATT_SRV_CHGD)) {
+ hearingDevice->service_changed_ccc_handle =
+ find_ccc_handle(conn_id, charac.value_handle);
+ if (!hearingDevice->service_changed_ccc_handle) {
+ LOG(ERROR) << __func__
+ << ": cannot find service changed CCC descriptor";
+ continue;
+ }
+ LOG(INFO) << __func__ << " service_changed_ccc="
+ << loghex(hearingDevice->service_changed_ccc_handle);
+ break;
+ }
+ }
+ }
+
+ // Find the handle for the client characteristics configuration of a given
+ // characteristics
+ uint16_t find_ccc_handle(uint16_t conn_id, uint16_t char_handle) {
+ const gatt::Characteristic* p_char =
+ BTA_GATTC_GetCharacteristic(conn_id, char_handle);
+
+ if (!p_char) {
+ LOG(WARNING) << __func__ << ": No such characteristic: " << char_handle;
+ return 0;
+ }
+
+ for (const gatt::Descriptor& desc : p_char->descriptors) {
+ if (desc.uuid == Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG))
+ return desc.handle;
+ }
+
+ return 0;
+ }
+
+ void send_state_change(HearingDevice* device, std::vector<uint8_t> payload) {
+ if (device->conn_id != 0) {
+ if (device->service_changed_rcvd) {
+ LOG(INFO)
+ << __func__
+ << ": service discover is in progress, skip send State Change cmd.";
+ return;
+ }
+ // Send the data packet
+ LOG(INFO) << __func__ << ": Send State Change. device=" << device->address
+ << ", status=" << loghex(payload[1]);
+ BtaGattQueue::WriteCharacteristic(
+ device->conn_id, device->audio_control_point_handle, payload,
+ GATT_WRITE_NO_RSP, nullptr, nullptr);
+ }
+ }
+
+ void send_state_change_to_other_side(HearingDevice* this_side_device,
+ std::vector<uint8_t> payload) {
+ for (auto& device : hearingDevices.devices) {
+ if ((device.address == this_side_device->address) ||
+ (device.hi_sync_id != this_side_device->hi_sync_id)) {
+ continue;
+ }
+ send_state_change(&device, payload);
+ }
+ }
+
+ void check_and_do_rssi_read(HearingDevice* device) {
+ if (device->read_rssi_count > 0) {
+ device->num_intervals_since_last_rssi_read++;
+ if (device->num_intervals_since_last_rssi_read >= PERIOD_TO_READ_RSSI_IN_INTERVALS) {
+ device->num_intervals_since_last_rssi_read = 0;
+ VLOG(1) << __func__ << ": device=" << device->address;
+ BTM_ReadRSSI(device->address, read_rssi_cb);
+ }
+ }
+ }
};
+void read_rssi_cb(void* p_void) {
+ tBTM_RSSI_RESULT* p_result = (tBTM_RSSI_RESULT*)p_void;
+
+ if (!p_result) return;
+
+ if ((instance) && (p_result->status == BTM_SUCCESS)) {
+ instance->OnReadRssiComplete(p_result->rem_bda, p_result->rssi);
+ }
+}
+
void hearingaid_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
VLOG(2) << __func__ << " event = " << +event;
@@ -1346,6 +1673,16 @@
break;
case BTA_GATTC_NOTIF_EVT:
+ if (!instance) return;
+ if (!p_data->notify.is_notify || p_data->notify.len > GATT_MAX_ATTR_LEN) {
+ LOG(ERROR) << __func__ << ": rejected BTA_GATTC_NOTIF_EVT. is_notify="
+ << p_data->notify.is_notify
+ << ", len=" << p_data->notify.len;
+ break;
+ }
+ instance->OnNotificationEvent(p_data->notify.conn_id,
+ p_data->notify.handle, p_data->notify.len,
+ p_data->notify.value);
break;
case BTA_GATTC_ENC_CMPL_CB_EVT:
@@ -1358,6 +1695,16 @@
instance->OnConnectionUpdateComplete(p_data->conn_update.conn_id, p_data);
break;
+ case BTA_GATTC_SRVC_CHG_EVT:
+ if (!instance) return;
+ instance->OnServiceChangeEvent(p_data->remote_bda);
+ break;
+
+ case BTA_GATTC_SRVC_DISC_DONE_EVT:
+ if (!instance) return;
+ instance->OnServiceDiscDoneEvent(p_data->remote_bda);
+ break;
+
default:
break;
}
@@ -1402,27 +1749,20 @@
HearingAidAudioSource::Initialize();
}
-bool HearingAid::IsInitialized() { return instance; }
+bool HearingAid::IsHearingAidRunning() { return instance; }
HearingAid* HearingAid::Get() {
CHECK(instance);
return instance;
};
-void HearingAid::AddFromStorage(const RawAddress& address, uint16_t psm,
- uint8_t capabilities, uint16_t codecs,
- uint16_t audio_control_point_handle,
- uint16_t volume_handle, uint64_t hiSyncId,
- uint16_t render_delay,
- uint16_t preparation_delay,
+void HearingAid::AddFromStorage(const HearingDevice& dev_info,
uint16_t is_white_listed) {
if (!instance) {
LOG(ERROR) << "Not initialized yet";
}
- instance->AddFromStorage(address, psm, capabilities, codecs,
- audio_control_point_handle, volume_handle, hiSyncId,
- render_delay, preparation_delay, is_white_listed);
+ instance->AddFromStorage(dev_info, is_white_listed);
};
int HearingAid::GetDeviceCount() {
@@ -1438,16 +1778,19 @@
// Must stop audio source to make sure it doesn't call any of callbacks on our
// soon to be null instance
HearingAidAudioSource::Stop();
- HearingAidAudioSource::CleanUp();
- instance->CleanUp();
HearingAidImpl* ptr = instance;
instance = nullptr;
+ HearingAidAudioSource::CleanUp();
+
+ ptr->CleanUp();
+
delete ptr;
};
void HearingAid::DebugDump(int fd) {
- dprintf(fd, "\nHearing Aid Manager:\n");
+ dprintf(fd, "Hearing Aid Manager:\n");
if (instance) instance->Dump(fd);
HearingAidAudioSource::DebugDump(fd);
-}
\ No newline at end of file
+ dprintf(fd, "\n");
+}
diff --git a/bta/hearing_aid/hearing_aid_audio_source.cc b/bta/hearing_aid/hearing_aid_audio_source.cc
index 48eaea3..3b92d41 100644
--- a/bta/hearing_aid/hearing_aid_audio_source.cc
+++ b/bta/hearing_aid/hearing_aid_audio_source.cc
@@ -16,15 +16,19 @@
*
******************************************************************************/
+#include "audio_hal_interface/hearing_aid_software_encoding.h"
#include "audio_hearing_aid_hw/include/audio_hearing_aid_hw.h"
-#include "bta_closure_api.h"
#include "bta_hearing_aid_api.h"
-#include "osi/include/alarm.h"
+#include "btu.h"
+#include "osi/include/wakelock.h"
#include "uipc.h"
#include <base/files/file_util.h>
#include <include/hardware/bt_av.h>
+#include "common/repeating_timer.h"
+#include "common/time_util.h"
+
using base::FilePath;
extern const char* audio_ha_hw_dump_ctrl_event(tHEARING_AID_CTRL_CMD event);
@@ -33,10 +37,9 @@
int sample_rate = -1;
int data_interval_ms = -1;
int num_channels = 2;
-alarm_t* audio_timer = nullptr;
-
-HearingAidAudioReceiver* localAudioReceiver;
-std::unique_ptr<tUIPC_STATE> uipc_hearing_aid;
+bluetooth::common::RepeatingTimer audio_timer;
+HearingAidAudioReceiver* localAudioReceiver = nullptr;
+std::unique_ptr<tUIPC_STATE> uipc_hearing_aid = nullptr;
struct AudioHalStats {
size_t media_read_total_underflow_bytes;
@@ -54,26 +57,37 @@
AudioHalStats stats;
-void send_audio_data(void*) {
+bool hearing_aid_on_resume_req(bool start_media_task);
+bool hearing_aid_on_suspend_req();
+
+void send_audio_data() {
uint32_t bytes_per_tick =
(num_channels * sample_rate * data_interval_ms * (bit_rate / 8)) / 1000;
uint16_t event;
uint8_t p_buf[bytes_per_tick];
- uint32_t bytes_read = UIPC_Read(*uipc_hearing_aid, UIPC_CH_ID_AV_AUDIO,
- &event, p_buf, bytes_per_tick);
+ uint32_t bytes_read;
+ if (bluetooth::audio::hearing_aid::is_hal_2_0_enabled()) {
+ bytes_read = bluetooth::audio::hearing_aid::read(p_buf, bytes_per_tick);
+ } else {
+ bytes_read = UIPC_Read(*uipc_hearing_aid, UIPC_CH_ID_AV_AUDIO, &event,
+ p_buf, bytes_per_tick);
+ }
VLOG(2) << "bytes_read: " << bytes_read;
if (bytes_read < bytes_per_tick) {
stats.media_read_total_underflow_bytes += bytes_per_tick - bytes_read;
stats.media_read_total_underflow_count++;
- stats.media_read_last_underflow_us = time_get_os_boottime_us();
+ stats.media_read_last_underflow_us =
+ bluetooth::common::time_get_os_boottime_us();
}
std::vector<uint8_t> data(p_buf, p_buf + bytes_read);
- localAudioReceiver->OnAudioDataReady(data);
+ if (localAudioReceiver != nullptr) {
+ localAudioReceiver->OnAudioDataReady(data);
+ }
}
void hearing_aid_send_ack(tHEARING_AID_CTRL_ACK status) {
@@ -82,10 +96,22 @@
UIPC_Send(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, 0, &ack, sizeof(ack));
}
+void start_audio_ticks() {
+ wakelock_acquire();
+ audio_timer.SchedulePeriodic(get_main_thread()->GetWeakPtr(), FROM_HERE, base::Bind(&send_audio_data),
+ base::TimeDelta::FromMilliseconds(data_interval_ms));
+}
+
+void stop_audio_ticks() {
+ audio_timer.CancelAndWait();
+ wakelock_release();
+}
+
void hearing_aid_data_cb(tUIPC_CH_ID, tUIPC_EVENT event) {
DVLOG(2) << "Hearing Aid audio data event: " << event;
switch (event) {
case UIPC_OPEN_EVT:
+ LOG(INFO) << __func__ << ": UIPC_OPEN_EVT";
/*
* Read directly from media task from here on (keep callback for
* connection events.
@@ -100,15 +126,12 @@
LOG(FATAL) << " Unsupported data interval: " << data_interval_ms;
}
- audio_timer = alarm_new_periodic("hearing_aid_data_timer");
- alarm_set_on_mloop(audio_timer, data_interval_ms, send_audio_data,
- nullptr);
+ start_audio_ticks();
break;
case UIPC_CLOSE_EVT:
+ LOG(INFO) << __func__ << ": UIPC_CLOSE_EVT";
hearing_aid_send_ack(HEARING_AID_CTRL_ACK_SUCCESS);
- if (audio_timer) {
- alarm_cancel(audio_timer);
- }
+ stop_audio_ticks();
break;
default:
LOG(ERROR) << "Hearing Aid audio data event not recognized:" << event;
@@ -133,46 +156,38 @@
LOG(INFO) << __func__ << " " << audio_ha_hw_dump_ctrl_event(cmd);
// a2dp_cmd_pending = cmd;
+ tHEARING_AID_CTRL_ACK ctrl_ack_status;
+
switch (cmd) {
case HEARING_AID_CTRL_CMD_CHECK_READY:
hearing_aid_send_ack(HEARING_AID_CTRL_ACK_SUCCESS);
break;
case HEARING_AID_CTRL_CMD_START:
- if (localAudioReceiver) {
- // Call OnAudioResume and block till it returns.
- std::promise<void> do_resume_promise;
- std::future<void> do_resume_future = do_resume_promise.get_future();
- do_in_bta_thread_once(
- FROM_HERE, base::BindOnce(&HearingAidAudioReceiver::OnAudioResume,
- base::Unretained(localAudioReceiver),
- std::move(do_resume_promise)));
- do_resume_future.wait();
- }
-
+ ctrl_ack_status = HEARING_AID_CTRL_ACK_SUCCESS;
// timer is restarted in UIPC_Open
- UIPC_Open(*uipc_hearing_aid, UIPC_CH_ID_AV_AUDIO, hearing_aid_data_cb,
- HEARING_AID_DATA_PATH);
- hearing_aid_send_ack(HEARING_AID_CTRL_ACK_SUCCESS);
+ if (!hearing_aid_on_resume_req(false)) {
+ ctrl_ack_status = HEARING_AID_CTRL_ACK_FAILURE;
+ } else {
+ UIPC_Open(*uipc_hearing_aid, UIPC_CH_ID_AV_AUDIO, hearing_aid_data_cb,
+ HEARING_AID_DATA_PATH);
+ }
+ hearing_aid_send_ack(ctrl_ack_status);
break;
case HEARING_AID_CTRL_CMD_STOP:
+ if (!hearing_aid_on_suspend_req()) {
+ LOG(INFO) << __func__ << ":HEARING_AID_CTRL_CMD_STOP: hearing_aid_on_suspend_req() errs, but ignored.";
+ }
hearing_aid_send_ack(HEARING_AID_CTRL_ACK_SUCCESS);
break;
case HEARING_AID_CTRL_CMD_SUSPEND:
- if (audio_timer) alarm_cancel(audio_timer);
- if (localAudioReceiver) {
- // Call OnAudioSuspend and block till it returns.
- std::promise<void> do_suspend_promise;
- std::future<void> do_suspend_future = do_suspend_promise.get_future();
- do_in_bta_thread_once(
- FROM_HERE, base::BindOnce(&HearingAidAudioReceiver::OnAudioSuspend,
- base::Unretained(localAudioReceiver),
- std::move(do_suspend_promise)));
- do_suspend_future.wait();
+ ctrl_ack_status = HEARING_AID_CTRL_ACK_SUCCESS;
+ if (!hearing_aid_on_suspend_req()) {
+ ctrl_ack_status = HEARING_AID_CTRL_ACK_FAILURE;
}
- hearing_aid_send_ack(HEARING_AID_CTRL_ACK_SUCCESS);
+ hearing_aid_send_ack(ctrl_ack_status);
break;
case HEARING_AID_CTRL_GET_OUTPUT_AUDIO_CONFIG: {
@@ -276,8 +291,11 @@
case UIPC_OPEN_EVT:
break;
case UIPC_CLOSE_EVT:
- UIPC_Open(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, hearing_aid_ctrl_cb,
- HEARING_AID_CTRL_PATH);
+ /* restart ctrl server unless we are shutting down */
+ if (HearingAid::IsHearingAidRunning()) {
+ UIPC_Open(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, hearing_aid_ctrl_cb,
+ HEARING_AID_CTRL_PATH);
+ }
break;
case UIPC_RX_DATA_READY_EVT:
hearing_aid_recv_ctrl_data();
@@ -286,38 +304,122 @@
LOG(ERROR) << "Hearing Aid audio ctrl unrecognized event: " << event;
}
}
+
+bool hearing_aid_on_resume_req(bool start_media_task) {
+ // hearing_aid_recv_ctrl_data(HEARING_AID_CTRL_CMD_START)
+ if (localAudioReceiver != nullptr) {
+ // Call OnAudioResume and block till it returns.
+ std::promise<void> do_resume_promise;
+ std::future<void> do_resume_future = do_resume_promise.get_future();
+ bt_status_t status = do_in_main_thread(
+ FROM_HERE, base::BindOnce(&HearingAidAudioReceiver::OnAudioResume,
+ base::Unretained(localAudioReceiver),
+ std::move(do_resume_promise)));
+ if (status == BT_STATUS_SUCCESS) {
+ do_resume_future.wait();
+ } else {
+ LOG(ERROR) << __func__
+ << ": HEARING_AID_CTRL_CMD_START: do_in_main_thread err="
+ << status;
+ return false;
+ }
+ } else {
+ LOG(ERROR) << __func__
+ << ": HEARING_AID_CTRL_CMD_START: audio receiver not started";
+ return false;
+ }
+
+ // hearing_aid_data_cb(UIPC_OPEN_EVT): start_media_task
+ if (start_media_task) {
+ if (data_interval_ms != HA_INTERVAL_10_MS &&
+ data_interval_ms != HA_INTERVAL_20_MS) {
+ LOG(FATAL) << " Unsupported data interval: " << data_interval_ms;
+ data_interval_ms = HA_INTERVAL_10_MS;
+ }
+ start_audio_ticks();
+ }
+ return true;
+}
+
+bool hearing_aid_on_suspend_req() {
+ // hearing_aid_recv_ctrl_data(HEARING_AID_CTRL_CMD_SUSPEND): stop_media_task
+ stop_audio_ticks();
+ if (localAudioReceiver != nullptr) {
+ // Call OnAudioSuspend and block till it returns.
+ std::promise<void> do_suspend_promise;
+ std::future<void> do_suspend_future = do_suspend_promise.get_future();
+ bt_status_t status = do_in_main_thread(
+ FROM_HERE, base::BindOnce(&HearingAidAudioReceiver::OnAudioSuspend,
+ base::Unretained(localAudioReceiver),
+ std::move(do_suspend_promise)));
+ if (status == BT_STATUS_SUCCESS) {
+ do_suspend_future.wait();
+ return true;
+ } else {
+ LOG(ERROR) << __func__
+ << ": HEARING_AID_CTRL_CMD_SUSPEND: do_in_main_thread err="
+ << status;
+ }
+ } else {
+ LOG(ERROR) << __func__
+ << ": HEARING_AID_CTRL_CMD_SUSPEND: audio receiver not started";
+ }
+ return false;
+}
} // namespace
void HearingAidAudioSource::Start(const CodecConfiguration& codecConfiguration,
- HearingAidAudioReceiver* audioReceiver) {
- localAudioReceiver = audioReceiver;
- VLOG(2) << "Hearing Aid UIPC Open";
+ HearingAidAudioReceiver* audioReceiver,
+ uint16_t remote_delay_ms) {
+ LOG(INFO) << __func__ << ": Hearing Aid Source Open";
bit_rate = codecConfiguration.bit_rate;
sample_rate = codecConfiguration.sample_rate;
data_interval_ms = codecConfiguration.data_interval_ms;
stats.Reset();
+
+ if (bluetooth::audio::hearing_aid::is_hal_2_0_enabled()) {
+ bluetooth::audio::hearing_aid::start_session();
+ bluetooth::audio::hearing_aid::set_remote_delay(remote_delay_ms);
+ }
+ localAudioReceiver = audioReceiver;
}
void HearingAidAudioSource::Stop() {
- if (audio_timer) {
- alarm_cancel(audio_timer);
+ LOG(INFO) << __func__ << ": Hearing Aid Source Close";
+
+ localAudioReceiver = nullptr;
+ if (bluetooth::audio::hearing_aid::is_hal_2_0_enabled()) {
+ bluetooth::audio::hearing_aid::end_session();
}
+
+ stop_audio_ticks();
}
void HearingAidAudioSource::Initialize() {
- uipc_hearing_aid = UIPC_Init();
- UIPC_Open(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, hearing_aid_ctrl_cb,
- HEARING_AID_CTRL_PATH);
+ auto stream_cb = bluetooth::audio::hearing_aid::StreamCallbacks{
+ .on_resume_ = hearing_aid_on_resume_req,
+ .on_suspend_ = hearing_aid_on_suspend_req,
+ };
+ if (!bluetooth::audio::hearing_aid::init(stream_cb, get_main_thread())) {
+ LOG(WARNING) << __func__ << ": Using legacy HAL";
+ uipc_hearing_aid = UIPC_Init();
+ UIPC_Open(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, hearing_aid_ctrl_cb, HEARING_AID_CTRL_PATH);
+ }
}
void HearingAidAudioSource::CleanUp() {
- UIPC_Close(*uipc_hearing_aid, UIPC_CH_ID_ALL);
+ if (bluetooth::audio::hearing_aid::is_hal_2_0_enabled()) {
+ bluetooth::audio::hearing_aid::cleanup();
+ } else {
+ UIPC_Close(*uipc_hearing_aid, UIPC_CH_ID_ALL);
+ uipc_hearing_aid = nullptr;
+ }
}
void HearingAidAudioSource::DebugDump(int fd) {
- uint64_t now_us = time_get_os_boottime_us();
+ uint64_t now_us = bluetooth::common::time_get_os_boottime_us();
std::stringstream stream;
stream << " Hearing Aid Audio HAL:"
<< "\n Counts (underflow) : "
diff --git a/bta/hf_client/bta_hf_client_act.cc b/bta/hf_client/bta_hf_client_act.cc
index 3e6c22d..e3f25f6 100644
--- a/bta/hf_client/bta_hf_client_act.cc
+++ b/bta/hf_client/bta_hf_client_act.cc
@@ -103,8 +103,8 @@
}
/* Check if RFCOMM has any incoming connection to avoid collision. */
- RawAddress pending_bd_addr;
- if (PORT_IsOpening(pending_bd_addr)) {
+ RawAddress pending_bd_addr = RawAddress::kEmpty;
+ if (PORT_IsOpening(&pending_bd_addr)) {
/* Let the incoming connection goes through. */
/* Issue collision for now. */
/* We will decide what to do when we find incoming connection later.*/
@@ -164,21 +164,17 @@
p_data->hdr.layer_specific);
return;
}
-
- uint16_t lcid;
- RawAddress dev_addr;
- int status;
-
/* set role */
client_cb->role = BTA_HF_CLIENT_ACP;
APPL_TRACE_DEBUG("%s: conn_handle %d", __func__, client_cb->conn_handle);
/* get bd addr of peer */
- if (PORT_SUCCESS != (status = PORT_CheckConnection(client_cb->conn_handle,
- dev_addr, &lcid))) {
- APPL_TRACE_DEBUG("%s: error PORT_CheckConnection returned status %d",
- __func__, status);
+ uint16_t lcid = 0;
+ RawAddress dev_addr = RawAddress::kEmpty;
+ int status = PORT_CheckConnection(client_cb->conn_handle, &dev_addr, &lcid);
+ if (status != PORT_SUCCESS) {
+ LOG(ERROR) << __func__ << ": PORT_CheckConnection returned " << status;
}
/* Collision Handling */
diff --git a/bta/hf_client/bta_hf_client_main.cc b/bta/hf_client/bta_hf_client_main.cc
index 4f717ae..fac61c7 100644
--- a/bta/hf_client/bta_hf_client_main.cc
+++ b/bta/hf_client/bta_hf_client_main.cc
@@ -329,6 +329,8 @@
client_cb->state = BTA_HF_CLIENT_OPENING_ST;
tBTA_HF_CLIENT_DATA msg;
msg.hdr.layer_specific = client_cb->handle;
+ msg.api_open.bd_addr = client_cb->peer_addr;
+ msg.api_open.sec_mask = client_cb->cli_sec_mask;
bta_hf_client_start_open(&msg);
}
}
@@ -386,7 +388,7 @@
/* reopen registered server */
/* Collision may be detected before or after we close servers. */
- // bta_hf_client_start_server();
+ bta_hf_client_start_server();
/* Start timer to handle connection opening restart */
alarm_set_on_mloop(client_cb->collision_timer,
@@ -749,19 +751,14 @@
evt.bd_addr = client_cb->peer_addr;
if (client_cb->state == BTA_HF_CLIENT_INIT_ST) {
bta_hf_client_app_callback(BTA_HF_CLIENT_CLOSE_EVT, &evt);
+ APPL_TRACE_DEBUG("%s: marking CB handle %d to false", __func__, client_cb->handle);
+ client_cb->is_allocated = false;
} else if (client_cb->state == BTA_HF_CLIENT_OPEN_ST) {
evt.open.handle = client_cb->handle;
bta_hf_client_app_callback(BTA_HF_CLIENT_OPEN_EVT, &evt);
}
}
- /* if the next state is INIT then release the cb for future use */
- if (client_cb->state == BTA_HF_CLIENT_INIT_ST) {
- APPL_TRACE_DEBUG("%s: marking CB handle %d to false", __func__,
- client_cb->handle);
- client_cb->is_allocated = false;
- }
-
VLOG(2) << __func__ << ": device " << client_cb->peer_addr
<< "state change: [" << bta_hf_client_state_str(in_state) << "] -> ["
<< bta_hf_client_state_str(client_cb->state) << "] after Event ["
diff --git a/bta/hf_client/bta_hf_client_rfc.cc b/bta/hf_client/bta_hf_client_rfc.cc
index e261c16..f3e0947 100644
--- a/bta/hf_client/bta_hf_client_rfc.cc
+++ b/bta/hf_client/bta_hf_client_rfc.cc
@@ -98,9 +98,12 @@
APPL_TRACE_DEBUG("%s: allocating a new CB for incoming connection",
__func__);
// Find the BDADDR of the peer device
- RawAddress peer_addr;
- uint16_t lcid;
- PORT_CheckConnection(port_handle, peer_addr, &lcid);
+ RawAddress peer_addr = RawAddress::kEmpty;
+ uint16_t lcid = 0;
+ int status = PORT_CheckConnection(port_handle, &peer_addr, &lcid);
+ if (status != PORT_SUCCESS) {
+ LOG(ERROR) << __func__ << ": PORT_CheckConnection returned " << status;
+ }
// Since we accepted a remote request we should allocate a handle first.
uint16_t tmp_handle = -1;
diff --git a/bta/hf_client/bta_hf_client_sco.cc b/bta/hf_client/bta_hf_client_sco.cc
index e03de4f..50820bd 100644
--- a/bta/hf_client/bta_hf_client_sco.cc
+++ b/bta/hf_client/bta_hf_client_sco.cc
@@ -112,7 +112,7 @@
resp = esco_parameters_for_codec(ESCO_CODEC_CVSD);
} else {
if (client_cb->negotiated_codec == BTA_AG_CODEC_MSBC) {
- resp = esco_parameters_for_codec(ESCO_CODEC_MSBC_T1);
+ resp = esco_parameters_for_codec(ESCO_CODEC_MSBC_T2);
} else {
// default codec
resp = esco_parameters_for_codec(ESCO_CODEC_CVSD);
diff --git a/bta/hh/bta_hh_act.cc b/bta/hh/bta_hh_act.cc
index a7bdc9c..f64fbf0 100644
--- a/bta/hh/bta_hh_act.cc
+++ b/bta/hh/bta_hh_act.cc
@@ -633,7 +633,7 @@
*
* Function bta_hh_handsk_act
*
- * Description HID Host process a handshake acknoledgement.
+ * Description HID Host process a handshake acknowledgement.
*
*
* Returns void
@@ -652,7 +652,7 @@
/* GET_ transsaction, handshake indicate unsupported request */
case BTA_HH_GET_PROTO_EVT:
bta_hh.hs_data.rsp_data.proto_mode = BTA_HH_PROTO_UNKNOWN;
- /* fall through */
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case BTA_HH_GET_RPT_EVT:
case BTA_HH_GET_IDLE_EVT:
bta_hh.hs_data.handle = p_cb->hid_handle;
@@ -660,7 +660,9 @@
bta_hh.hs_data.status = bta_hh_get_trans_status(p_data->hid_cback.data);
if (bta_hh.hs_data.status == BTA_HH_OK)
bta_hh.hs_data.status = BTA_HH_HS_TRANS_NOT_SPT;
-
+ if (p_cb->w4_evt == BTA_HH_GET_RPT_EVT)
+ bta_hh_co_get_rpt_rsp(bta_hh.dev_status.handle, bta_hh.hs_data.status,
+ NULL, 0);
(*bta_hh_cb.p_cback)(p_cb->w4_evt, &bta_hh);
p_cb->w4_evt = 0;
break;
@@ -672,6 +674,9 @@
bta_hh.dev_status.handle = p_cb->hid_handle;
bta_hh.dev_status.status =
bta_hh_get_trans_status(p_data->hid_cback.data);
+ if (p_cb->w4_evt == BTA_HH_SET_RPT_EVT)
+ bta_hh_co_set_rpt_rsp(bta_hh.dev_status.handle,
+ bta_hh.dev_status.status);
(*bta_hh_cb.p_cback)(p_cb->w4_evt, &bta_hh);
p_cb->w4_evt = 0;
break;
@@ -733,6 +738,8 @@
break;
case BTA_HH_GET_RPT_EVT:
hs_data.rsp_data.p_rpt_data = pdata;
+ bta_hh_co_get_rpt_rsp(hs_data.handle, hs_data.status, pdata->data,
+ pdata->len);
break;
case BTA_HH_GET_PROTO_EVT:
/* match up BTE/BTA report/boot mode def*/
@@ -748,11 +755,11 @@
break;
/* should not expect control DATA for SET_ transaction */
case BTA_HH_SET_PROTO_EVT:
- /* fall through */
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case BTA_HH_SET_RPT_EVT:
- /* fall through */
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case BTA_HH_SET_IDLE_EVT:
- /* fall through */
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
default:
#if (BTA_HH_DEBUG == TRUE)
APPL_TRACE_DEBUG("invalid transaction type for DATA payload: 4_evt[%s]",
@@ -1054,21 +1061,21 @@
} else {
switch (p_data->api_sndcmd.t_type) {
case HID_TRANS_SET_PROTOCOL:
- /* fall through */
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case HID_TRANS_GET_REPORT:
- /* fall through */
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case HID_TRANS_SET_REPORT:
- /* fall through */
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case HID_TRANS_GET_PROTOCOL:
- /* fall through */
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case HID_TRANS_GET_IDLE:
- /* fall through */
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case HID_TRANS_SET_IDLE: /* set w4_handsk event name for callback
function use */
p_cb->w4_evt = event;
break;
case HID_TRANS_DATA: /* output report */
- /* fall through */
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case HID_TRANS_CONTROL:
/* no handshake event will be generated */
/* if VC_UNPLUG is issued, set flag */
diff --git a/bta/hh/bta_hh_api.cc b/bta/hh/bta_hh_api.cc
index e9b3f64..cd32ede 100644
--- a/bta/hh/bta_hh_api.cc
+++ b/bta/hh/bta_hh_api.cc
@@ -172,7 +172,13 @@
******************************************************************************/
void BTA_HhSetReport(uint8_t dev_handle, tBTA_HH_RPT_TYPE r_type,
BT_HDR* p_data) {
- bta_hh_snd_write_dev(dev_handle, HID_TRANS_SET_REPORT, r_type, 0, 0, p_data);
+ /* send feature report on control channel */
+ if (r_type == BTA_HH_RPTT_FEATURE)
+ bta_hh_snd_write_dev(dev_handle, HID_TRANS_SET_REPORT, r_type, 0, 0,
+ p_data);
+ /* send output data report on interrupt channel */
+ else
+ bta_hh_snd_write_dev(dev_handle, HID_TRANS_DATA, r_type, 0, 0, p_data);
}
/*******************************************************************************
*
diff --git a/bta/hh/bta_hh_le.cc b/bta/hh/bta_hh_le.cc
index adeb957..eb87cdf 100644
--- a/bta/hh/bta_hh_le.cc
+++ b/bta/hh/bta_hh_le.cc
@@ -457,9 +457,9 @@
return NULL;
}
-static const tBTA_GATTC_DESCRIPTOR* find_descriptor_by_short_uuid(
+static const gatt::Descriptor* find_descriptor_by_short_uuid(
uint16_t conn_id, uint16_t char_handle, uint16_t short_uuid) {
- const tBTA_GATTC_CHARACTERISTIC* p_char =
+ const gatt::Characteristic* p_char =
BTA_GATTC_GetCharacteristic(conn_id, char_handle);
if (!p_char) {
@@ -467,7 +467,7 @@
return NULL;
}
- for (const tBTA_GATTC_DESCRIPTOR& desc : p_char->descriptors) {
+ for (const gatt::Descriptor& desc : p_char->descriptors) {
if (desc.uuid == Uuid::From16Bit(short_uuid)) return &desc;
}
@@ -486,7 +486,7 @@
uint16_t short_uuid,
GATT_READ_OP_CB cb,
void* cb_data) {
- const tBTA_GATTC_DESCRIPTOR* p_desc =
+ const gatt::Descriptor* p_desc =
find_descriptor_by_short_uuid(p_cb->conn_id, char_handle, short_uuid);
if (!p_desc) return BTA_HH_ERR;
@@ -671,7 +671,7 @@
bool bta_hh_le_write_ccc(tBTA_HH_DEV_CB* p_cb, uint8_t char_handle,
uint16_t clt_cfg_value, GATT_WRITE_OP_CB cb,
void* cb_data) {
- const tBTA_GATTC_DESCRIPTOR* p_desc = find_descriptor_by_short_uuid(
+ const gatt::Descriptor* p_desc = find_descriptor_by_short_uuid(
p_cb->conn_id, char_handle, GATT_UUID_CHAR_CLIENT_CONFIG);
if (!p_desc) return false;
@@ -691,7 +691,7 @@
uint8_t srvc_inst_id, hid_inst_id;
tBTA_HH_DEV_CB* p_dev_cb = (tBTA_HH_DEV_CB*)data;
- const tBTA_GATTC_CHARACTERISTIC* characteristic =
+ const gatt::Characteristic* characteristic =
BTA_GATTC_GetOwningCharacteristic(conn_id, handle);
uint16_t char_uuid = characteristic->uuid.As16Bit();
@@ -701,7 +701,7 @@
case GATT_UUID_BATTERY_LEVEL: /* battery level clt cfg registered */
hid_inst_id = bta_hh_le_find_service_inst_by_battery_inst_id(
p_dev_cb, srvc_inst_id);
- /* FALLTHROUGH */
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case GATT_UUID_HID_BT_KB_INPUT:
case GATT_UUID_HID_BT_MOUSE_INPUT:
case GATT_UUID_HID_REPORT:
@@ -1310,17 +1310,16 @@
}
tBTA_HH_DEV_CB* p_dev_cb = (tBTA_HH_DEV_CB*)data;
- const tBTA_GATTC_DESCRIPTOR* p_desc =
- BTA_GATTC_GetDescriptor(conn_id, handle);
+ const gatt::Descriptor* p_desc = BTA_GATTC_GetDescriptor(conn_id, handle);
if (!p_desc) {
APPL_TRACE_ERROR("%s: error: descriptor is null!", __func__);
return;
}
- const tBTA_GATTC_CHARACTERISTIC* characteristic =
+ const gatt::Characteristic* characteristic =
BTA_GATTC_GetOwningCharacteristic(conn_id, handle);
- const tBTA_GATTC_SERVICE* service =
+ const gatt::Service* service =
BTA_GATTC_GetOwningService(conn_id, characteristic->value_handle);
tBTA_HH_LE_RPT* p_rpt;
@@ -1398,10 +1397,10 @@
*
******************************************************************************/
static void bta_hh_le_search_hid_chars(tBTA_HH_DEV_CB* p_dev_cb,
- const tBTA_GATTC_SERVICE* service) {
+ const gatt::Service* service) {
tBTA_HH_LE_RPT* p_rpt;
- for (const tBTA_GATTC_CHARACTERISTIC& charac : service->characteristics) {
+ for (const gatt::Characteristic& charac : service->characteristics) {
if (!charac.uuid.Is16Bit()) continue;
uint16_t uuid16 = charac.uuid.As16Bit();
@@ -1460,7 +1459,7 @@
}
/* Make sure PROTO_MODE is processed as last */
- for (const tBTA_GATTC_CHARACTERISTIC& charac : service->characteristics) {
+ for (const gatt::Characteristic& charac : service->characteristics) {
if (charac.uuid == Uuid::From16Bit(GATT_UUID_HID_PROTO_MODE)) {
p_dev_cb->hid_srvc.proto_mode_handle = charac.value_handle;
bta_hh_le_set_protocol_mode(p_dev_cb, p_dev_cb->mode);
@@ -1491,11 +1490,11 @@
return;
}
- const std::vector<tBTA_GATTC_SERVICE>* services =
+ const std::vector<gatt::Service>* services =
BTA_GATTC_GetServices(p_data->conn_id);
bool have_hid = false;
- for (const tBTA_GATTC_SERVICE& service : *services) {
+ for (const gatt::Service& service : *services) {
if (service.uuid == Uuid::From16Bit(UUID_SERVCLASS_LE_HID) &&
service.is_primary && !have_hid) {
have_hid = true;
@@ -1513,7 +1512,7 @@
} else if (service.uuid == Uuid::From16Bit(UUID_SERVCLASS_SCAN_PARAM)) {
p_dev_cb->scan_refresh_char_handle = 0;
- for (const tBTA_GATTC_CHARACTERISTIC& charac : service.characteristics) {
+ for (const gatt::Characteristic& charac : service.characteristics) {
if (charac.uuid == Uuid::From16Bit(GATT_UUID_SCAN_REFRESH)) {
p_dev_cb->scan_refresh_char_handle = charac.value_handle;
@@ -1528,7 +1527,7 @@
} else if (service.uuid == Uuid::From16Bit(UUID_SERVCLASS_GAP_SERVER)) {
// TODO(jpawlowski): this should be done by GAP profile, remove when GAP
// is fixed.
- for (const tBTA_GATTC_CHARACTERISTIC& charac : service.characteristics) {
+ for (const gatt::Characteristic& charac : service.characteristics) {
if (charac.uuid == Uuid::From16Bit(GATT_UUID_GAP_PREF_CONN_PARAM)) {
/* read the char value */
BtaGattQueue::ReadCharacteristic(p_dev_cb->conn_id,
@@ -1565,7 +1564,7 @@
return;
}
- const tBTA_GATTC_CHARACTERISTIC* p_char =
+ const gatt::Characteristic* p_char =
BTA_GATTC_GetCharacteristic(p_dev_cb->conn_id, p_data->handle);
if (p_char == NULL) {
APPL_TRACE_ERROR(
@@ -1719,7 +1718,7 @@
static void read_report_cb(uint16_t conn_id, tGATT_STATUS status,
uint16_t handle, uint16_t len, uint8_t* value,
void* data) {
- const tBTA_GATTC_CHARACTERISTIC* p_char =
+ const gatt::Characteristic* p_char =
BTA_GATTC_GetCharacteristic(conn_id, handle);
if (p_char == NULL) return;
@@ -1752,7 +1751,7 @@
hs_data.handle = p_dev_cb->hid_handle;
if (status == GATT_SUCCESS) {
- const tBTA_GATTC_SERVICE* p_svc =
+ const gatt::Service* p_svc =
BTA_GATTC_GetOwningService(conn_id, p_char->value_handle);
p_rpt = bta_hh_le_find_report_entry(p_dev_cb, p_svc->handle, char_uuid,
@@ -1818,7 +1817,7 @@
APPL_TRACE_DEBUG("bta_hh_le_write_cmpl w4_evt: %d", p_dev_cb->w4_evt);
#endif
- const tBTA_GATTC_CHARACTERISTIC* p_char =
+ const gatt::Characteristic* p_char =
BTA_GATTC_GetCharacteristic(conn_id, handle);
uint16_t uuid = p_char->uuid.As16Bit();
if (uuid != GATT_UUID_HID_REPORT && uuid != GATT_UUID_HID_BT_KB_INPUT &&
@@ -1867,7 +1866,7 @@
p_cb->w4_evt = w4_evt;
- const tBTA_GATTC_CHARACTERISTIC* p_char =
+ const gatt::Characteristic* p_char =
BTA_GATTC_GetCharacteristic(p_cb->conn_id, p_rpt->char_inst_id);
tGATT_WRITE_TYPE write_type = GATT_WRITE;
@@ -1996,8 +1995,6 @@
BTA_GATTC_Open(bta_hh_cb.gatt_if, p_cb->addr, false, GATT_TRANSPORT_LE,
false);
p_cb->in_bg_conn = true;
-
- BTA_DmBleStartAutoConn();
}
return;
}
diff --git a/bta/hl/bta_hl_act.cc b/bta/hl/bta_hl_act.cc
deleted file mode 100644
index 6d37bdf..0000000
--- a/bta/hl/bta_hl_act.cc
+++ /dev/null
@@ -1,2377 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2003-2012 Broadcom 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.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- * This file contains the HeaLth device profile (HL) action functions for
- * the state machine.
- *
- ******************************************************************************/
-
-#include <string.h>
-
-#include "bt_target.h"
-#if (HL_INCLUDED == TRUE)
-
-#include "bt_common.h"
-#include "bta_hl_api.h"
-#include "bta_hl_int.h"
-#include "bta_sys.h"
-#include "mca_api.h"
-#include "mca_defs.h"
-#include "osi/include/osi.h"
-#include "port_api.h"
-#include "sdp_api.h"
-#include "utl.h"
-
-using bluetooth::Uuid;
-
-/*****************************************************************************
- * Local Function prototypes
- ****************************************************************************/
-#if (BTA_HL_DEBUG == TRUE)
-static const char* bta_hl_mcap_evt_code(uint8_t evt_code);
-static const char* bta_hl_dch_oper_code(tBTA_HL_DCH_OPER oper_code);
-static const char* bta_hl_cback_evt_code(uint8_t evt_code);
-#endif
-static void bta_hl_sdp_cback(uint8_t sdp_op, uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, uint16_t status);
-static void bta_hl_sdp_cback0(uint16_t status);
-static void bta_hl_sdp_cback1(uint16_t status);
-static void bta_hl_sdp_cback2(uint16_t status);
-static void bta_hl_sdp_cback3(uint16_t status);
-static void bta_hl_sdp_cback4(uint16_t status);
-static void bta_hl_sdp_cback5(uint16_t status);
-static void bta_hl_sdp_cback6(uint16_t status);
-
-static tSDP_DISC_CMPL_CB* const bta_hl_sdp_cback_arr[] = {
- bta_hl_sdp_cback0, bta_hl_sdp_cback1, bta_hl_sdp_cback2, bta_hl_sdp_cback3,
- bta_hl_sdp_cback4, bta_hl_sdp_cback5, bta_hl_sdp_cback6};
-
-/*******************************************************************************
- *
- * Function bta_hl_dch_mca_cong_change
- *
- * Description Action routine for processing congestion change notification
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_dch_mca_cong_change(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
- tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
- tMCA_CONG_CHG* p_cong_chg = &p_data->mca_evt.mca_data.cong_chg;
- tBTA_HL evt_data;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_dch_mca_cong_change mdl_id=%d cong=%d",
- p_cong_chg->mdl_id, p_cong_chg->cong);
-#endif
- evt_data.dch_cong_ind.cong = p_dcb->cong = p_cong_chg->cong;
- evt_data.dch_cong_ind.mdl_handle = p_dcb->mdl_handle;
- evt_data.dch_cong_ind.mcl_handle = p_mcb->mcl_handle;
- evt_data.dch_cong_ind.app_handle = p_acb->app_handle;
-
- p_acb->p_cback(BTA_HL_CONG_CHG_IND_EVT, (tBTA_HL*)&evt_data);
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_dch_echo_test
- *
- * Description Action routine for processing echo test request
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_dch_echo_test(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
- UNUSED_ATTR tBTA_HL_DATA* p_data) {
- tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_dch_echo_test");
-#endif
-
- p_dcb->echo_oper = BTA_HL_ECHO_OP_CI_GET_ECHO_DATA;
- p_dcb->cout_oper |= BTA_HL_CO_GET_ECHO_DATA_MASK;
-
- bta_hl_co_get_echo_data(
- p_acb->app_id, p_mcb->mcl_handle, p_dcb->p_echo_tx_pkt->len,
- BTA_HL_GET_BUF_PTR(p_dcb->p_echo_tx_pkt), BTA_HL_CI_GET_ECHO_DATA_EVT);
-}
-/*******************************************************************************
- *
- * Function bta_hl_dch_sdp_init
- *
- * Description Action routine for processing DCH SDP initiation
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_dch_sdp_init(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
- tBTA_HL_DATA* p_data) {
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_dch_sdp_init");
-#endif
- if (p_mcb->sdp_oper == BTA_HL_SDP_OP_NONE) {
- p_mcb->sdp_mdl_idx = mdl_idx;
- if (p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_OPEN) {
- p_mcb->sdp_oper = BTA_HL_SDP_OP_DCH_OPEN_INIT;
-
- } else {
- p_mcb->sdp_oper = BTA_HL_SDP_OP_DCH_RECONNECT_INIT;
- }
-
- if (bta_hl_init_sdp(p_mcb->sdp_oper, app_idx, mcl_idx, mdl_idx) !=
- BTA_HL_STATUS_OK) {
- APPL_TRACE_ERROR("SDP INIT failed");
- p_mcb->sdp_oper = BTA_HL_SDP_OP_NONE;
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_SDP_FAIL_EVT,
- p_data);
- }
- } else {
- APPL_TRACE_ERROR("SDP in use");
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_SDP_FAIL_EVT,
- p_data);
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_dch_close_echo_test
- *
- * Description Action routine for processing the closing of echo test
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_dch_close_echo_test(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_dch_close_echo_test");
-#endif
-
- switch (p_dcb->echo_oper) {
- case BTA_HL_ECHO_OP_DCH_CLOSE_CFM:
- case BTA_HL_ECHO_OP_OPEN_IND:
- case BTA_HL_ECHO_OP_ECHO_PKT:
- p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST;
- break;
- case BTA_HL_ECHO_OP_MDL_CREATE_CFM:
- case BTA_HL_ECHO_OP_DCH_OPEN_CFM:
- case BTA_HL_ECHO_OP_LOOP_BACK:
- default:
- break;
- }
-
- if (MCA_CloseReq((tMCA_DL)p_dcb->mdl_handle) != MCA_SUCCESS) {
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT,
- p_data);
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_dch_mca_rcv_data
- *
- * Description Action routine for processing the received data
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_dch_mca_rcv_data(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
- tBTA_HL_DATA* p_data) {
- tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_dch_mca_rcv_data");
-#endif
-
- if (p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID) {
- switch (p_dcb->echo_oper) {
- case BTA_HL_ECHO_OP_ECHO_PKT:
-
- if (MCA_WriteReq((tMCA_DL)p_dcb->mdl_handle,
- p_data->mca_rcv_data_evt.p_pkt) != MCA_SUCCESS) {
- osi_free_and_reset((void**)&p_data->mca_rcv_data_evt.p_pkt);
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
- BTA_HL_DCH_CLOSE_ECHO_TEST_EVT, p_data);
- }
- break;
- case BTA_HL_ECHO_OP_LOOP_BACK:
-
- p_dcb->p_echo_rx_pkt = p_data->mca_rcv_data_evt.p_pkt;
- p_dcb->echo_oper = BTA_HL_ECHO_OP_CI_PUT_ECHO_DATA;
- p_dcb->cout_oper |= BTA_HL_CO_PUT_ECHO_DATA_MASK;
- p_dcb->ci_put_echo_data_status = BTA_HL_STATUS_FAIL;
-
- bta_hl_co_put_echo_data(p_acb->app_id, p_mcb->mcl_handle,
- p_dcb->p_echo_rx_pkt->len,
- BTA_HL_GET_BUF_PTR(p_dcb->p_echo_rx_pkt),
- BTA_HL_CI_PUT_ECHO_DATA_EVT);
- break;
- default:
- APPL_TRACE_ERROR("Unknonw echo_oper=%d", p_dcb->echo_oper);
- break;
- }
-
- } else {
- p_dcb->cout_oper |= BTA_HL_CO_PUT_RX_DATA_MASK;
- p_dcb->p_rx_pkt = p_data->mca_rcv_data_evt.p_pkt;
-
- bta_hl_co_put_rx_data(
- p_acb->app_id, p_dcb->mdl_handle, p_dcb->p_rx_pkt->len,
- BTA_HL_GET_BUF_PTR(p_dcb->p_rx_pkt), BTA_HL_CI_PUT_RX_DATA_EVT);
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_dch_ci_put_echo_data
- *
- * Description Action routine for processing the call-in of the
- * put echo data event
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_dch_ci_put_echo_data(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_dch_ci_put_echo_data");
-#endif
-
- p_dcb->cout_oper &= ~BTA_HL_CO_PUT_ECHO_DATA_MASK;
- osi_free_and_reset((void**)&p_dcb->p_echo_rx_pkt);
- p_dcb->ci_put_echo_data_status = p_data->ci_get_put_echo_data.status;
-
- p_dcb->echo_oper = BTA_HL_ECHO_OP_DCH_CLOSE_CFM;
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
- BTA_HL_DCH_CLOSE_ECHO_TEST_EVT, p_data);
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_dch_ci_get_echo_data
- *
- * Description Action routine for processing the call-in of the
- * get echo data event
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_dch_ci_get_echo_data(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
- tBTA_HL_STATUS status;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_dch_ci_get_echo_data");
-#endif
-
- p_dcb->cout_oper &= ~BTA_HL_CO_GET_ECHO_DATA_MASK;
-
- if (!p_dcb->abort_oper) {
- status = p_data->ci_get_put_echo_data.status;
- if (status == BTA_HL_STATUS_OK) {
- p_dcb->echo_oper = BTA_HL_ECHO_OP_MDL_CREATE_CFM;
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_OPEN_EVT,
- p_data);
- } else {
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
- BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
- }
- } else {
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT,
- p_data);
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_dch_ci_put_rx_data
- *
- * Description Action routine for processing the call-in of the
- * put rx data event
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_dch_ci_put_rx_data(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
- tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
- tBTA_HL evt_data;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_dch_ci_put_rx_data");
-#endif
-
- p_dcb->cout_oper &= ~BTA_HL_CO_PUT_RX_DATA_MASK;
- osi_free_and_reset((void**)&p_dcb->p_rx_pkt);
- bta_hl_build_rcv_data_ind(&evt_data, p_acb->app_handle, p_mcb->mcl_handle,
- p_dcb->mdl_handle);
- p_acb->p_cback(BTA_HL_DCH_RCV_DATA_IND_EVT, (tBTA_HL*)&evt_data);
- if (p_dcb->close_pending) {
- if (!p_dcb->cout_oper) {
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_EVT,
- p_data);
- }
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_dch_ci_get_tx_data
- *
- * Description Action routine for processing the call-in of the
- * get tx data event
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_dch_ci_get_tx_data(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
- tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
- tMCA_RESULT result;
- tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
- bool free_buf = false;
- bool close_dch = false;
- tBTA_HL evt_data;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_dch_ci_get_tx_data");
-#endif
-
- if (p_data != NULL) {
- status = p_data->ci_get_put_data.status;
- APPL_TRACE_WARNING("%s: status=%d", __func__, status);
- }
-
- p_dcb->cout_oper &= ~BTA_HL_CO_GET_TX_DATA_MASK;
-
- if (p_dcb->close_pending) {
- status = BTA_HL_STATUS_FAIL;
- free_buf = true;
-
- if (!p_dcb->cout_oper) {
- close_dch = true;
- }
- } else if (status == BTA_HL_STATUS_FAIL) {
- free_buf = TRUE;
- } else {
- result = MCA_WriteReq((tMCA_DL)p_dcb->mdl_handle, p_dcb->p_tx_pkt);
- if (result != MCA_SUCCESS) {
- if (result == MCA_BUSY) {
- status = BTA_HL_STATUS_DCH_BUSY;
- } else {
- status = BTA_HL_STATUS_FAIL;
- }
- free_buf = true;
- } else {
- p_dcb->p_tx_pkt = NULL;
- }
- }
-
- if (free_buf) osi_free_and_reset((void**)&p_dcb->p_tx_pkt);
-
- bta_hl_build_send_data_cfm(&evt_data, p_acb->app_handle, p_mcb->mcl_handle,
- p_dcb->mdl_handle, status);
- p_acb->p_cback(BTA_HL_DCH_SEND_DATA_CFM_EVT, (tBTA_HL*)&evt_data);
-
- if (close_dch) {
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_EVT,
- p_data);
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_dch_send_data
- *
- * Description Action routine for processing api send data request
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_dch_send_data(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
- tBTA_HL_DATA* p_data) {
- tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
- tBTA_HL evt_data;
- bool success = true;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_dch_send_data");
-#endif
-
- if (!(p_dcb->cout_oper & BTA_HL_CO_GET_TX_DATA_MASK)) {
- // p_dcb->chnl_cfg.fcs may be BTA_HL_MCA_USE_FCS (0x11) or BTA_HL_MCA_NO_FCS
- // (0x10) or BTA_HL_DEFAULT_SOURCE_FCS (1)
- bool fcs_use = (bool)(p_dcb->chnl_cfg.fcs & BTA_HL_MCA_FCS_USE_MASK);
- p_dcb->p_tx_pkt = bta_hl_get_buf(p_data->api_send_data.pkt_size, fcs_use);
- if (p_dcb->p_tx_pkt != NULL) {
- bta_hl_co_get_tx_data(
- p_acb->app_id, p_dcb->mdl_handle, p_data->api_send_data.pkt_size,
- BTA_HL_GET_BUF_PTR(p_dcb->p_tx_pkt), BTA_HL_CI_GET_TX_DATA_EVT);
- p_dcb->cout_oper |= BTA_HL_CO_GET_TX_DATA_MASK;
- } else {
- success = false;
- }
- } else {
- success = false;
- }
-
- if (!success) {
- bta_hl_build_send_data_cfm(&evt_data, p_acb->app_handle, p_mcb->mcl_handle,
- p_dcb->mdl_handle, BTA_HL_STATUS_FAIL);
- p_acb->p_cback(BTA_HL_DCH_SEND_DATA_CFM_EVT, (tBTA_HL*)&evt_data);
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_dch_close_cmpl
- *
- * Description Action routine for processing the close complete event
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_dch_close_cmpl(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
- tBTA_HL_DATA* p_data) {
- tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
- tBTA_HL evt_data;
- tBTA_HL_EVT event = 0;
- bool send_evt = true;
- tBTA_HL_STATUS status;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_dch_close_cmpl dch oper=%s",
- bta_hl_dch_oper_code(p_dcb->dch_oper));
-#endif
-
- switch (p_dcb->dch_oper) {
- case BTA_HL_DCH_OP_LOCAL_OPEN:
- case BTA_HL_DCH_OP_LOCAL_RECONNECT:
-
- if (p_dcb->abort_oper & BTA_HL_ABORT_LOCAL_MASK) {
- bta_hl_build_abort_cfm(&evt_data, p_acb->app_handle, p_mcb->mcl_handle,
- BTA_HL_STATUS_OK);
- event = BTA_HL_DCH_ABORT_CFM_EVT;
- } else if (p_dcb->abort_oper & BTA_HL_ABORT_REMOTE_MASK) {
- bta_hl_build_abort_ind(&evt_data, p_acb->app_handle, p_mcb->mcl_handle);
- event = BTA_HL_DCH_ABORT_IND_EVT;
- } else {
- bta_hl_build_dch_open_cfm(&evt_data, p_acb->app_handle,
- p_mcb->mcl_handle, BTA_HL_INVALID_MDL_HANDLE,
- 0, 0, 0, 0, 0, BTA_HL_STATUS_FAIL);
- event = BTA_HL_DCH_OPEN_CFM_EVT;
- if (p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_RECONNECT) {
- event = BTA_HL_DCH_RECONNECT_CFM_EVT;
- }
- }
- break;
-
- case BTA_HL_DCH_OP_LOCAL_CLOSE:
- case BTA_HL_DCH_OP_REMOTE_DELETE:
- case BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT:
- case BTA_HL_DCH_OP_NONE:
-
- bta_hl_build_dch_close_cfm(&evt_data, p_acb->app_handle,
- p_mcb->mcl_handle, p_dcb->mdl_handle,
- BTA_HL_STATUS_OK);
- event = BTA_HL_DCH_CLOSE_CFM_EVT;
- break;
-
- case BTA_HL_DCH_OP_REMOTE_CLOSE:
- bta_hl_build_dch_close_ind(&evt_data, p_acb->app_handle,
- p_mcb->mcl_handle, p_dcb->mdl_handle,
- p_dcb->intentional_close);
- event = BTA_HL_DCH_CLOSE_IND_EVT;
- break;
-
- case BTA_HL_DCH_OP_REMOTE_OPEN:
-
- if (p_dcb->abort_oper & BTA_HL_ABORT_LOCAL_MASK) {
- bta_hl_build_abort_cfm(&evt_data, p_acb->app_handle, p_mcb->mcl_handle,
- BTA_HL_STATUS_OK);
- event = BTA_HL_DCH_ABORT_CFM_EVT;
- } else if (p_dcb->abort_oper & BTA_HL_ABORT_REMOTE_MASK) {
- bta_hl_build_abort_ind(&evt_data, p_acb->app_handle, p_mcb->mcl_handle);
- event = BTA_HL_DCH_ABORT_IND_EVT;
- } else {
- bta_hl_build_dch_close_ind(&evt_data, p_acb->app_handle,
- p_mcb->mcl_handle, p_dcb->mdl_handle,
- p_dcb->intentional_close);
- event = BTA_HL_DCH_CLOSE_IND_EVT;
- }
- break;
-
- case BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST:
- /* this is normal echo test close */
- case BTA_HL_DCH_OP_REMOTE_CREATE:
- case BTA_HL_DCH_OP_REMOTE_RECONNECT:
- send_evt = false;
- break;
-
- default:
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_ERROR("DCH operation not found oper=%s",
- bta_hl_dch_oper_code(p_dcb->dch_oper));
-#endif
- send_evt = false;
- break;
- }
-
- if (p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID) {
- p_mcb->echo_test = false;
- send_evt = false;
-
- if (p_dcb->dch_oper != BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST) {
- switch (p_dcb->echo_oper) {
- case BTA_HL_ECHO_OP_CI_GET_ECHO_DATA:
- case BTA_HL_ECHO_OP_SDP_INIT:
- case BTA_HL_ECHO_OP_MDL_CREATE_CFM:
- case BTA_HL_ECHO_OP_DCH_OPEN_CFM:
- case BTA_HL_ECHO_OP_LOOP_BACK:
-
- status = BTA_HL_STATUS_FAIL;
- send_evt = true;
- break;
- case BTA_HL_ECHO_OP_OPEN_IND:
- case BTA_HL_ECHO_OP_ECHO_PKT:
- break;
- default:
- APPL_TRACE_ERROR("Invalid echo_oper=%d", p_dcb->echo_oper);
- break;
- }
- } else {
- status = p_dcb->ci_put_echo_data_status;
- send_evt = true;
- }
-
- if (send_evt) {
- bta_hl_build_echo_test_cfm(&evt_data, p_acb->app_handle,
- p_mcb->mcl_handle, status);
- event = BTA_HL_DCH_ECHO_TEST_CFM_EVT;
- }
- }
-
- bta_hl_clean_mdl_cb(app_idx, mcl_idx, mdl_idx);
-
- if (send_evt) {
- if (p_acb->p_cback) {
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("Send Event: %s", bta_hl_cback_evt_code(event));
-#endif
- p_acb->p_cback(event, (tBTA_HL*)&evt_data);
- }
- }
- /* check cch close is in progress or not */
- bta_hl_check_cch_close(app_idx, mcl_idx, p_data, false);
-}
-/*******************************************************************************
- *
- * Function bta_hl_dch_mca_close_ind
- *
- * Description Action routine for processing the close indication
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_dch_mca_close_ind(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
- tBTA_HL_DATA* p_data) {
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_dch_mca_close_ind dch oper=%s",
- bta_hl_dch_oper_code(p_dcb->dch_oper));
-#endif
-
- p_dcb->intentional_close = false;
- if (p_data->mca_evt.mca_data.close_ind.reason == L2CAP_DISC_OK) {
- p_dcb->intentional_close = true;
- }
-
- if (!p_dcb->cout_oper) {
- if ((p_dcb->dch_oper != BTA_HL_DCH_OP_REMOTE_OPEN) &&
- (p_dcb->dch_oper != BTA_HL_DCH_OP_REMOTE_RECONNECT)) {
- p_dcb->dch_oper = BTA_HL_DCH_OP_REMOTE_CLOSE;
- }
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT,
- p_data);
- } else {
- p_dcb->close_pending = true;
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_dch_mca_close_cfm
- *
- * Description Action routine for processing the close confirmation
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_dch_mca_close_cfm(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
- tBTA_HL_DATA* p_data) {
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_dch_mca_close_cfm dch_oper=%s",
- bta_hl_dch_oper_code(p_dcb->dch_oper));
-#endif
-
- switch (p_dcb->dch_oper) {
- case BTA_HL_DCH_OP_LOCAL_CLOSE:
- case BTA_HL_DCH_OP_LOCAL_OPEN:
- case BTA_HL_DCH_OP_LOCAL_RECONNECT:
- case BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST:
- case BTA_HL_DCH_OP_REMOTE_DELETE:
- case BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT:
- case BTA_HL_DCH_OP_NONE:
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
- BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
- break;
- default:
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_ERROR("Invalid dch_oper=%s for close cfm",
- bta_hl_dch_oper_code(p_dcb->dch_oper));
-#endif
- break;
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_dch_mca_close
- *
- * Description Action routine for processing the DCH close request
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_dch_mca_close(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
- tBTA_HL_DATA* p_data) {
- tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
- tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
- tBTA_HL evt_data;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_dch_mca_close");
-#endif
- if (!p_dcb->cout_oper) {
- p_dcb->close_pending = false;
- if (MCA_CloseReq((tMCA_DL)p_dcb->mdl_handle) == MCA_SUCCESS) {
- p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_CLOSE;
- } else {
- status = BTA_HL_STATUS_FAIL;
- }
-
- if ((status != BTA_HL_STATUS_OK) &&
- (p_mcb->cch_close_dch_oper != BTA_HL_CCH_CLOSE_OP_DCH_CLOSE)) {
- bta_hl_build_dch_close_cfm(&evt_data, p_acb->app_handle,
- p_mcb->mcl_handle,
- p_data->api_dch_close.mdl_handle, status);
- p_acb->p_cback(BTA_HL_DCH_CLOSE_CFM_EVT, (tBTA_HL*)&evt_data);
- }
- } else {
- p_dcb->close_pending = true;
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_dch_mca_open_ind
- *
- * Description Action routine for processing the open indication
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_dch_mca_open_ind(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
- tBTA_HL_DATA* p_data) {
- tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
- tMCA_DL_OPEN* p_open_ind = &p_data->mca_evt.mca_data.open_ind;
- tBTA_HL evt_data;
- tBTA_HL_EVT event;
- uint8_t old_dch_oper = BTA_HL_DCH_OP_NONE;
- bool send_event = false;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_dch_mca_open_ind");
-#endif
- if ((p_dcb->dch_oper == BTA_HL_DCH_OP_REMOTE_OPEN) ||
- (p_dcb->dch_oper == BTA_HL_DCH_OP_REMOTE_RECONNECT)) {
- p_dcb->mdl_handle = (tBTA_HL_MDL_HANDLE)p_open_ind->mdl;
- p_dcb->mtu = p_open_ind->mtu;
-
- evt_data.dch_open_ind.mdl_handle = p_dcb->mdl_handle;
- evt_data.dch_open_ind.mcl_handle = p_mcb->mcl_handle;
- evt_data.dch_open_ind.app_handle = p_acb->app_handle;
-
- evt_data.dch_open_ind.local_mdep_id = p_dcb->local_mdep_id;
- evt_data.dch_open_ind.mdl_id = p_dcb->mdl_id;
- evt_data.dch_open_ind.mtu = p_dcb->mtu;
-
- if (p_dcb->chnl_cfg.fcr_opt.mode == L2CAP_FCR_ERTM_MODE) {
- evt_data.dch_open_ind.dch_mode = BTA_HL_DCH_MODE_RELIABLE;
- if (!bta_hl_is_the_first_reliable_existed(app_idx, mcl_idx)) {
- p_dcb->is_the_first_reliable = true;
- }
- } else {
- evt_data.dch_open_ind.dch_mode = BTA_HL_DCH_MODE_STREAMING;
- }
- evt_data.dch_open_ind.first_reliable = p_dcb->is_the_first_reliable;
-
- old_dch_oper = p_dcb->dch_oper;
- p_dcb->dch_oper = BTA_HL_DCH_OP_NONE;
- }
-
- switch (old_dch_oper) {
- case BTA_HL_DCH_OP_REMOTE_OPEN:
-
- p_dcb->dch_mode = evt_data.dch_open_ind.dch_mode;
- if (p_dcb->local_mdep_id != BTA_HL_ECHO_TEST_MDEP_ID) {
- bta_hl_save_mdl_cfg(app_idx, mcl_idx, mdl_idx);
- event = BTA_HL_DCH_OPEN_IND_EVT;
- send_event = true;
- } else {
- p_dcb->echo_oper = BTA_HL_ECHO_OP_ECHO_PKT;
- }
-
- break;
-
- case BTA_HL_DCH_OP_REMOTE_RECONNECT:
-
- if (bta_hl_validate_chan_cfg(app_idx, mcl_idx, mdl_idx)) {
- bta_hl_save_mdl_cfg(app_idx, mcl_idx, mdl_idx);
- event = BTA_HL_DCH_RECONNECT_IND_EVT;
- send_event = true;
- } else {
- if (MCA_CloseReq((tMCA_DL)p_dcb->mdl_handle) == MCA_SUCCESS) {
- p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT;
- } else {
- APPL_TRACE_ERROR("Unabel to close DCH for reconnect cfg mismatch");
- }
- }
- break;
- default:
- break;
- }
-
- if (send_event) {
- p_acb->p_cback(event, (tBTA_HL*)&evt_data);
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_dch_mca_open_cfm
- *
- * Description Action routine for processing the open confirmation
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_dch_mca_open_cfm(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
- tBTA_HL_DATA* p_data) {
- tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
- tMCA_DL_OPEN* p_open_cfm = &p_data->mca_evt.mca_data.open_cfm;
- tBTA_HL evt_data;
- tBTA_HL_EVT event;
- uint8_t old_dch_oper = BTA_HL_DCH_OP_NONE;
- tBTA_HL_DCH_MODE dch_mode = BTA_HL_DCH_MODE_STREAMING;
- bool send_event = false;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_dch_mca_open_cfm");
-#endif
- if ((p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_OPEN) ||
- (p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_RECONNECT)) {
- p_dcb->mdl_handle = (tBTA_HL_MDL_HANDLE)p_open_cfm->mdl;
- p_dcb->mtu = p_open_cfm->mtu;
-
- /*todo verify dch_mode, mtu and fcs for reconnect */
- if (p_dcb->chnl_cfg.fcr_opt.mode == L2CAP_FCR_ERTM_MODE) {
- dch_mode = BTA_HL_DCH_MODE_RELIABLE;
- }
-
- if (p_dcb->local_mdep_id != BTA_HL_ECHO_TEST_MDEP_ID) {
- if (dch_mode == BTA_HL_DCH_MODE_RELIABLE) {
- if (!bta_hl_is_the_first_reliable_existed(app_idx, mcl_idx)) {
- p_dcb->is_the_first_reliable = true;
- }
- }
- }
-
- bta_hl_build_dch_open_cfm(
- &evt_data, p_acb->app_handle, p_mcb->mcl_handle, p_dcb->mdl_handle,
- p_dcb->local_mdep_id, p_dcb->mdl_id, dch_mode,
- p_dcb->is_the_first_reliable, p_dcb->mtu, BTA_HL_STATUS_OK);
-
- old_dch_oper = p_dcb->dch_oper;
- p_dcb->dch_oper = BTA_HL_DCH_OP_NONE;
- } else {
- APPL_TRACE_ERROR("Error dch oper =%d", p_dcb->dch_oper);
- return;
- }
-
- switch (old_dch_oper) {
- case BTA_HL_DCH_OP_LOCAL_OPEN:
-
- p_dcb->dch_mode = dch_mode;
- if (p_dcb->local_mdep_id != BTA_HL_ECHO_TEST_MDEP_ID) {
- bta_hl_save_mdl_cfg(app_idx, mcl_idx, mdl_idx);
- event = BTA_HL_DCH_OPEN_CFM_EVT;
- send_event = true;
- } else {
- p_dcb->echo_oper = BTA_HL_ECHO_OP_LOOP_BACK;
- if (MCA_WriteReq((tMCA_DL)p_dcb->mdl_handle, p_dcb->p_echo_tx_pkt) !=
- MCA_SUCCESS) {
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
- BTA_HL_DCH_CLOSE_ECHO_TEST_EVT, p_data);
- } else {
- p_dcb->p_echo_tx_pkt = NULL;
- }
- }
- break;
-
- case BTA_HL_DCH_OP_LOCAL_RECONNECT:
-
- if (bta_hl_validate_chan_cfg(app_idx, mcl_idx, mdl_idx)) {
- bta_hl_save_mdl_cfg(app_idx, mcl_idx, mdl_idx);
- event = BTA_HL_DCH_RECONNECT_CFM_EVT;
- send_event = true;
- } else {
- if (MCA_CloseReq((tMCA_DL)p_dcb->mdl_handle) == MCA_SUCCESS) {
- p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT;
- } else {
- APPL_TRACE_ERROR("Unabel to close DCH for reconnect cfg mismatch");
- }
- }
- break;
- default:
- break;
- }
-
- if (send_event) p_acb->p_cback(event, (tBTA_HL*)&evt_data);
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_dch_mca_abort_ind
- *
- * Description Action routine for processing the abort indication
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_dch_mca_abort_ind(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
- tBTA_HL_DATA* p_data) {
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_dch_mca_abort_ind");
-#endif
-
- p_dcb->abort_oper |= BTA_HL_ABORT_REMOTE_MASK;
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT,
- p_data);
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_dch_mca_abort_cfm
- *
- * Description Action routine for processing the abort confirmation
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_dch_mca_abort_cfm(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
- tBTA_HL_DATA* p_data) {
- tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
- tBTA_HL evt_data;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_dch_mca_abort_cfm");
-#endif
-
- if (p_dcb->abort_oper) {
- if (p_data->mca_evt.mca_data.abort_cfm.rsp_code != MCA_RSP_SUCCESS) {
- if (p_dcb->abort_oper & BTA_HL_ABORT_LOCAL_MASK) {
- bta_hl_build_abort_cfm(&evt_data, p_acb->app_handle, p_mcb->mcl_handle,
- BTA_HL_STATUS_FAIL);
- p_acb->p_cback(BTA_HL_DCH_ABORT_CFM_EVT, (tBTA_HL*)&evt_data);
- }
- } else {
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
- BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
- }
- } else {
- APPL_TRACE_ERROR("Not expecting Abort CFM ");
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_dch_mca_abort
- *
- * Description Action routine for processing the abort request
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_dch_mca_abort(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
- tBTA_HL_DATA* p_data) {
- tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
- tMCA_RESULT mca_result;
- tBTA_HL evt_data;
-
- if (((p_mcb->sdp_oper == BTA_HL_SDP_OP_DCH_OPEN_INIT) ||
- (p_mcb->sdp_oper == BTA_HL_SDP_OP_DCH_RECONNECT_INIT)) &&
- (p_mcb->sdp_mdl_idx == mdl_idx)) {
- p_dcb->abort_oper |= BTA_HL_ABORT_PENDING_MASK;
- return;
- } else if (p_dcb->echo_oper == BTA_HL_ECHO_OP_CI_GET_ECHO_DATA) {
- p_dcb->abort_oper |= BTA_HL_ABORT_PENDING_MASK;
- return;
- }
-
- p_dcb->abort_oper &= ~BTA_HL_ABORT_PENDING_MASK;
-
- mca_result = MCA_Abort((tMCA_CL)p_mcb->mcl_handle);
- if (mca_result != MCA_SUCCESS) {
- if (mca_result == MCA_NO_RESOURCES) {
- p_dcb->abort_oper |= BTA_HL_ABORT_PENDING_MASK;
- } else {
- if (p_dcb->abort_oper & BTA_HL_ABORT_LOCAL_MASK) {
- bta_hl_build_abort_cfm(&evt_data, p_acb->app_handle, p_mcb->mcl_handle,
- BTA_HL_STATUS_FAIL);
- p_acb->p_cback(BTA_HL_DCH_ABORT_CFM_EVT, (tBTA_HL*)&evt_data);
- }
- bta_hl_check_cch_close(app_idx, mcl_idx, p_data, false);
- }
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_dch_mca_abort abort_oper=0x%x", p_dcb->abort_oper);
-#endif
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_dch_mca_reconnect_ind
- *
- * Description Action routine for processing the reconnect indication
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_dch_mca_reconnect_ind(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
- tBTA_HL_MDL_CFG* p_mdl_cfg;
- tMCA_EVT_HDR* p_reconnect_ind = &p_data->mca_evt.mca_data.reconnect_ind;
- uint8_t mdl_cfg_idx, in_use_mdl_idx, mdep_cfg_idx;
- uint8_t rsp_code = MCA_RSP_SUCCESS;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_dch_mca_reconnect_ind mdl_id=%d",
- p_reconnect_ind->mdl_id);
-#endif
-
- if (bta_hl_find_mdl_cfg_idx(app_idx, mcl_idx, p_reconnect_ind->mdl_id,
- &mdl_cfg_idx)) {
- if (!bta_hl_find_mdl_idx(app_idx, mcl_idx, p_reconnect_ind->mdl_id,
- &in_use_mdl_idx)) {
- p_mdl_cfg = BTA_HL_GET_MDL_CFG_PTR(app_idx, mdl_cfg_idx);
-
- if (bta_hl_find_mdep_cfg_idx(app_idx, p_mdl_cfg->local_mdep_id,
- &mdep_cfg_idx)) {
- p_dcb->in_use = true;
- p_dcb->dch_oper = BTA_HL_DCH_OP_REMOTE_RECONNECT;
- p_dcb->sec_mask = (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
- p_dcb->peer_mdep_id = 0xFF;
- p_dcb->local_mdep_id = p_mdl_cfg->local_mdep_id;
- p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
- p_dcb->local_cfg = BTA_HL_DCH_CFG_UNKNOWN;
- p_dcb->mdl_id = p_reconnect_ind->mdl_id;
- p_dcb->mdl_cfg_idx_included = true;
- p_dcb->mdl_cfg_idx = mdl_cfg_idx;
- p_dcb->dch_mode = p_mdl_cfg->dch_mode;
- bta_hl_find_rxtx_apdu_size(app_idx, mdep_cfg_idx,
- &p_dcb->max_rx_apdu_size,
- &p_dcb->max_tx_apdu_size);
- bta_hl_set_dch_chan_cfg(app_idx, mcl_idx, mdl_idx, p_data);
- } else {
- rsp_code = MCA_RSP_BAD_MDL;
- }
- } else {
- rsp_code = MCA_RSP_BAD_MDL;
- }
- } else {
- rsp_code = MCA_RSP_BAD_MDL;
- }
-
- if (MCA_ReconnectMdlRsp((tMCA_CL)p_mcb->mcl_handle, p_dcb->local_mdep_id,
- p_dcb->mdl_id, rsp_code,
- &p_dcb->chnl_cfg) != MCA_SUCCESS) {
- MCA_Abort((tMCA_CL)p_mcb->mcl_handle);
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT,
- p_data);
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_dch_mca_reconnect_cfm
- *
- * Description Action routine for processing the reconenct confirmation
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_dch_mca_reconnect_cfm(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
- tMCA_RSP_EVT* p_reconnect_cfm = &p_data->mca_evt.mca_data.reconnect_cfm;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_dch_mca_reconnect_cfm");
-#endif
- if (p_dcb->abort_oper & BTA_HL_ABORT_PENDING_MASK) {
- p_dcb->abort_oper &= ~BTA_HL_ABORT_PENDING_MASK;
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_ABORT_EVT,
- p_data);
- return;
- }
-
- if (p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_RECONNECT) {
- if (p_reconnect_cfm->rsp_code == MCA_RSP_SUCCESS) {
- bta_hl_set_dch_chan_cfg(app_idx, mcl_idx, mdl_idx, p_data);
-
- if (MCA_DataChnlCfg((tMCA_CL)p_mcb->mcl_handle, &p_dcb->chnl_cfg) !=
- MCA_SUCCESS) {
- /* should be able to abort so no checking of the return code */
- MCA_Abort((tMCA_CL)p_mcb->mcl_handle);
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
- BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
- }
- } else {
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
- BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
- }
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_dch_mca_reconnect
- *
- * Description Action routine for processing the reconnect request
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_dch_mca_reconnect(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
- tBTA_HL_DATA* p_data) {
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
- tMCA_CHNL_CFG* p_chnl_cfg = NULL;
- uint8_t sdp_idx;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_dch_mca_reconnect");
-#endif
- if (bta_hl_find_sdp_idx_using_ctrl_psm(&p_mcb->sdp, p_mcb->ctrl_psm,
- &sdp_idx)) {
- p_mcb->data_psm = p_mcb->sdp.sdp_rec[sdp_idx].data_psm;
- if (MCA_ReconnectMdl((tMCA_CL)p_mcb->mcl_handle, p_dcb->local_mdep_id,
- p_mcb->data_psm, p_dcb->mdl_id,
- p_chnl_cfg) != MCA_SUCCESS) {
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
- BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
- }
- } else {
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT,
- p_data);
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_dch_create_rsp
- *
- * Description Action routine for processing BTA_HL_API_DCH_CREATE_RSP_EVT
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_dch_create_rsp(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
- tBTA_HL_DATA* p_data) {
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
- tBTA_HL_API_DCH_CREATE_RSP* p_create_rsp = &p_data->api_dch_create_rsp;
- uint8_t mca_rsp_code = MCA_RSP_SUCCESS;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_dch_create_rsp");
-#endif
- if (p_create_rsp->rsp_code == BTA_HL_DCH_CREATE_RSP_SUCCESS) {
- p_dcb->dch_oper = BTA_HL_DCH_OP_REMOTE_OPEN;
- p_dcb->local_cfg = p_create_rsp->cfg_rsp;
-
- bta_hl_set_dch_chan_cfg(app_idx, mcl_idx, mdl_idx, p_data);
- } else {
- mca_rsp_code = MCA_RSP_CFG_REJ;
- }
-
- if (MCA_CreateMdlRsp((tMCA_CL)p_mcb->mcl_handle, p_dcb->local_mdep_id,
- p_dcb->mdl_id, p_dcb->local_cfg, mca_rsp_code,
- &p_dcb->chnl_cfg) != MCA_SUCCESS) {
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT,
- p_data);
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_dch_mca_create_ind
- *
- * Description Action routine for processing
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_dch_mca_create_ind(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
- tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
- tMCA_CREATE_IND* p_create_ind = &p_data->mca_evt.mca_data.create_ind;
- uint8_t mdep_cfg_idx;
- uint8_t cfg_rsp;
- uint8_t rsp_code = MCA_RSP_SUCCESS;
- bool send_create_ind_evt = false;
- tBTA_HL evt_data;
- tBTA_HL_ECHO_CFG* p_echo_cfg;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_dch_mca_create_ind");
-#endif
-
- if (bta_hl_find_mdep_cfg_idx(app_idx, p_create_ind->dep_id, &mdep_cfg_idx)) {
- if (p_create_ind->dep_id == BTA_HL_ECHO_TEST_MDEP_ID) {
- if (bta_hl_find_echo_cfg_rsp(app_idx, mcl_idx, mdep_cfg_idx,
- p_create_ind->cfg, &cfg_rsp)) {
- p_dcb->in_use = true;
- p_dcb->dch_oper = BTA_HL_DCH_OP_REMOTE_OPEN;
- p_dcb->local_mdep_id = p_create_ind->dep_id;
- p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
- p_dcb->local_cfg = cfg_rsp;
- p_dcb->remote_cfg = p_create_ind->cfg;
- p_dcb->mdl_id = p_create_ind->mdl_id;
- p_dcb->mdl_cfg_idx_included = false;
- p_echo_cfg = BTA_HL_GET_ECHO_CFG_PTR(app_idx);
- p_dcb->max_rx_apdu_size = p_echo_cfg->max_rx_apdu_size;
- p_dcb->max_tx_apdu_size = p_echo_cfg->max_tx_apdu_size;
-
- bta_hl_set_dch_chan_cfg(app_idx, mcl_idx, mdl_idx, p_data);
- } else {
- rsp_code = MCA_RSP_CFG_REJ;
- }
- } else
-
- {
- p_dcb->in_use = true;
- p_dcb->dch_oper = BTA_HL_DCH_OP_REMOTE_CREATE;
- p_dcb->local_mdep_id = p_create_ind->dep_id;
- p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
- p_dcb->local_cfg = BTA_HL_DCH_CFG_UNKNOWN;
- p_dcb->remote_cfg = p_create_ind->cfg;
- p_dcb->mdl_id = p_create_ind->mdl_id;
- p_dcb->mdl_cfg_idx_included = false;
- bta_hl_find_rxtx_apdu_size(app_idx, mdep_cfg_idx,
- &p_dcb->max_rx_apdu_size,
- &p_dcb->max_tx_apdu_size);
- send_create_ind_evt = true;
- }
- } else {
- rsp_code = MCA_RSP_BAD_MDEP;
- }
-
- if (send_create_ind_evt) {
- evt_data.dch_create_ind.mcl_handle = p_mcb->mcl_handle;
- evt_data.dch_create_ind.app_handle = p_acb->app_handle;
- evt_data.dch_create_ind.local_mdep_id = p_dcb->local_mdep_id;
- evt_data.dch_create_ind.mdl_id = p_dcb->mdl_id;
- evt_data.dch_create_ind.cfg = p_dcb->remote_cfg;
- evt_data.dch_create_ind.bd_addr = p_mcb->bd_addr;
- p_acb->p_cback(BTA_HL_DCH_CREATE_IND_EVT, (tBTA_HL*)&evt_data);
- } else {
- if (MCA_CreateMdlRsp((tMCA_CL)p_mcb->mcl_handle, p_dcb->local_mdep_id,
- p_dcb->mdl_id, p_dcb->local_cfg, rsp_code,
- &p_dcb->chnl_cfg) != MCA_SUCCESS) {
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
- BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
- } else {
- if (p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID) {
- p_mcb->echo_test = true;
- p_dcb->echo_oper = BTA_HL_ECHO_OP_OPEN_IND;
- }
- }
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_dch_mca_create_cfm
- *
- * Description Action routine for processing
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_dch_mca_create_cfm(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
- tMCA_CREATE_CFM* p_create_cfm = &p_data->mca_evt.mca_data.create_cfm;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_dch_mca_create_cfm");
-#endif
-
- if (p_dcb->abort_oper & BTA_HL_ABORT_PENDING_MASK) {
- p_dcb->abort_oper &= ~BTA_HL_ABORT_PENDING_MASK;
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_ABORT_EVT,
- p_data);
- return;
- }
-
- if (p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_OPEN) {
- if (p_create_cfm->rsp_code == MCA_RSP_SUCCESS) {
- if (bta_hl_validate_cfg(app_idx, mcl_idx, mdl_idx, p_create_cfm->cfg)) {
- bta_hl_set_dch_chan_cfg(app_idx, mcl_idx, mdl_idx, p_data);
-
- if (MCA_DataChnlCfg((tMCA_CL)p_mcb->mcl_handle, &p_dcb->chnl_cfg) !=
- MCA_SUCCESS) {
- /* this should not happen */
- APPL_TRACE_ERROR("Unable to create data channel");
- MCA_Abort((tMCA_CL)p_mcb->mcl_handle);
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
- BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
- } else {
- if (p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID) {
- p_dcb->echo_oper = BTA_HL_ECHO_OP_DCH_OPEN_CFM;
- }
- }
- } else {
- MCA_Abort((tMCA_CL)p_mcb->mcl_handle);
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
- BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
- }
- } else {
- APPL_TRACE_ERROR("MCA Create- failed");
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
- BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
- }
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_dch_mca_create
- *
- * Description Action routine for processing the MDL create request
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_dch_mca_create(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
- tBTA_HL_DATA* p_data) {
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
- tMCA_RESULT result;
- uint8_t sdp_idx;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_dch_mca_create");
-#endif
-
- if (bta_hl_find_sdp_idx_using_ctrl_psm(&p_mcb->sdp, p_mcb->ctrl_psm,
- &sdp_idx) &&
- bta_hl_validate_peer_cfg(app_idx, mcl_idx, mdl_idx, p_dcb->peer_mdep_id,
- p_dcb->peer_mdep_role, sdp_idx)) {
- p_mcb->data_psm = p_mcb->sdp.sdp_rec[sdp_idx].data_psm;
- result = MCA_CreateMdl((tMCA_CL)p_mcb->mcl_handle, p_dcb->local_mdep_id,
- p_mcb->data_psm, p_dcb->mdl_id, p_dcb->peer_mdep_id,
- p_dcb->local_cfg, NULL);
- if (result != MCA_SUCCESS) {
- APPL_TRACE_ERROR("MCA_CreateMdl FAIL mca_result=%d", result);
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
- BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
- }
- } else {
- APPL_TRACE_ERROR("MCA Create- SDP idx or peer MDEP cfg not found");
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT,
- p_data);
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_dch_sdp_fail
- *
- * Description Action routine for processing the SDP failed event
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_dch_sdp_fail(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
- tBTA_HL_DATA* p_data) {
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_dch_sdp_fail");
-#endif
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT,
- p_data);
-}
-
-/******************************************************************************
- *
- * Function bta_hl_sdp_cback
- *
- * Description This is the SDP callback function used by HL.
- * This function will be executed by SDP when the service
- * search is completed. If the search is successful, it
- * finds the first record in the database that matches the
- * UUID of the search. Then retrieves the scn from the
- * record.
- *
- * Returns void.
- *
- *****************************************************************************/
-static void bta_hl_sdp_cback(uint8_t sdp_oper, uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, uint16_t status) {
- tBTA_HL_MCL_CB* p_cb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- tBTA_HL_SDP_REC* p_hdp_rec;
- tBTA_HL_CCH_SDP* p_cch_buf;
- tBTA_HL_DCH_SDP* p_dch_buf;
- tSDP_DISC_REC* p_rec = NULL;
- tSDP_PROTOCOL_ELEM pe;
- tSDP_DISC_ATTR* p_attr;
- uint8_t i, rec_cnt;
- tBTA_HL_SUP_FEATURE_LIST_ELEM sup_feature;
- bool sdp_parsing_ok = false, result = false;
- uint16_t event;
- tBTA_HL_MDL_CB* p_dcb;
- uint16_t service_uuid;
- uint16_t name_len;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG(
- "bta_hl_sdp_cback status:%d sdp_oper=%d app_idx=%d, mcl_idx=%d, "
- "mdl_idx=%d",
- status, sdp_oper, app_idx, mcl_idx, mdl_idx);
-#endif
-
- rec_cnt = 0;
- service_uuid = bta_hl_get_service_uuids(sdp_oper, app_idx, mcl_idx, mdl_idx);
-
- if (status == SDP_SUCCESS || status == SDP_DB_FULL) {
- memset(&p_cb->sdp, 0, sizeof(tBTA_HL_SDP));
- do {
- if (bta_hl_find_service_in_db(app_idx, mcl_idx, service_uuid, &p_rec)) {
- p_hdp_rec = &p_cb->sdp.sdp_rec[rec_cnt];
- p_cb->sdp.num_recs = rec_cnt + 1;
- } else {
- break;
- }
-
- if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_L2CAP, &pe)) {
- p_hdp_rec->ctrl_psm = (uint16_t)pe.params[0];
- } else {
- APPL_TRACE_WARNING("Control PSM not found");
- break;
- }
- if (SDP_FindAddProtoListsElemInRec(p_rec, UUID_PROTOCOL_L2CAP, &pe)) {
- p_hdp_rec->data_psm = (uint16_t)pe.params[0];
- } else {
- APPL_TRACE_WARNING("Data PSM not found");
- break;
- }
-
- p_hdp_rec->srv_name[0] = '\0';
- p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME);
- if (p_attr != NULL) {
- if (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) < BT_MAX_SERVICE_NAME_LEN)
- name_len = (uint16_t)SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
- else
- name_len = BT_MAX_SERVICE_NAME_LEN;
- memcpy(p_hdp_rec->srv_name, p_attr->attr_value.v.array, name_len);
- }
-
- p_hdp_rec->srv_desp[0] = '\0';
- p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_DESCRIPTION);
- if (p_attr != NULL) {
- if (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) < BT_MAX_SERVICE_NAME_LEN)
- name_len = (uint16_t)SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
- else
- name_len = BT_MAX_SERVICE_NAME_LEN;
- memcpy(p_hdp_rec->srv_desp, p_attr->attr_value.v.array, name_len);
- }
-
- p_hdp_rec->provider_name[0] = '\0';
- p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_PROVIDER_NAME);
- if (p_attr != NULL) {
- if (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) < BT_MAX_SERVICE_NAME_LEN)
- name_len = (uint16_t)SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
- else
- name_len = BT_MAX_SERVICE_NAME_LEN;
- memcpy(p_hdp_rec->provider_name, p_attr->attr_value.v.array, name_len);
- }
-
- p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HDP_MCAP_SUP_PROC);
- if (p_attr != NULL) {
- p_hdp_rec->mcap_sup_proc = p_attr->attr_value.v.u8;
- } else {
- APPL_TRACE_WARNING("MCAP SUP PROC not found");
- break;
- }
-
- p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HDP_SUP_FEAT_LIST);
- if (p_attr != NULL) {
- if (bta_hl_fill_sup_feature_list(p_attr, &sup_feature)) {
- p_hdp_rec->num_mdeps = (uint8_t)sup_feature.num_elems;
- APPL_TRACE_WARNING("bta_hl_sdp_cback num_mdeps %d",
- sup_feature.num_elems);
- for (i = 0; i < sup_feature.num_elems; i++) {
- p_hdp_rec->mdep_cfg[i].data_type =
- sup_feature.list_elem[i].data_type;
- p_hdp_rec->mdep_cfg[i].mdep_id = sup_feature.list_elem[i].mdep_id;
- p_hdp_rec->mdep_cfg[i].mdep_role =
- sup_feature.list_elem[i].mdep_role;
- /* Check MDEP Description pointer to prevent crash due to null
- * pointer */
- if (sup_feature.list_elem[i].p_mdep_desp != NULL) {
- strlcpy(p_hdp_rec->mdep_cfg[i].mdep_desp,
- sup_feature.list_elem[i].p_mdep_desp,
- BTA_HL_MDEP_DESP_LEN);
- } else {
- APPL_TRACE_ERROR(
- "bta_hl_sdp_cback Incorrect Mdep[%d] Description (Null ptr)",
- i);
- }
- }
-
- sdp_parsing_ok = true;
- } else {
- APPL_TRACE_WARNING("HDP supported feature list fill failed");
- break;
- }
- } else {
- APPL_TRACE_WARNING("HDP supported feature list not found");
- break;
- }
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("record=%d ctrl_psm=%0x data_psm=%x", rec_cnt + 1,
- p_hdp_rec->ctrl_psm, p_hdp_rec->data_psm);
- APPL_TRACE_DEBUG("srv_name=[%s]", (p_hdp_rec->srv_name[0] != '\0')
- ? p_hdp_rec->srv_name
- : "NULL");
- APPL_TRACE_DEBUG("srv_desp=[%s]", (p_hdp_rec->srv_desp[0] != '\0')
- ? p_hdp_rec->srv_desp
- : "NULL");
- for (i = 0; i < sup_feature.num_elems; i++) {
- APPL_TRACE_DEBUG(
- "index=0x%02x mdep_id=0x%04x data type=0x%04x mdep role=%s(0x%02x)",
- (i + 1), p_hdp_rec->mdep_cfg[i].mdep_id,
- p_hdp_rec->mdep_cfg[i].data_type,
- (p_hdp_rec->mdep_cfg[i].mdep_role == BTA_HL_MDEP_ROLE_SOURCE)
- ? "Src"
- : "Snk",
- p_hdp_rec->mdep_cfg[i].mdep_role);
- }
- APPL_TRACE_DEBUG("provider_name=[%s]",
- (p_hdp_rec->provider_name[0] != '\0')
- ? p_hdp_rec->provider_name
- : "NULL");
- APPL_TRACE_DEBUG("found MCAP sup procedure=%d",
- p_cb->sdp.sdp_rec[rec_cnt].mcap_sup_proc);
-#endif
- rec_cnt++;
- if (rec_cnt >= BTA_HL_NUM_SDP_RECS) {
- APPL_TRACE_WARNING("No more spaces for SDP recs max_rec_cnt=%d",
- BTA_HL_NUM_SDP_RECS);
- break;
- }
-
- } while (true);
- }
-
- osi_free_and_reset((void**)&p_cb->p_db);
-
- if ((status == SDP_SUCCESS || status == SDP_DB_FULL) && p_cb->sdp.num_recs &&
- sdp_parsing_ok) {
- result = true;
- } else {
- APPL_TRACE_WARNING(
- "SDP Failed sdp_status=%d num_recs=%d sdp_parsing_ok=%d ", status,
- p_cb->sdp.num_recs, sdp_parsing_ok);
- }
-
- p_cb->sdp_oper = BTA_HL_SDP_OP_NONE;
-
- switch (sdp_oper) {
- case BTA_HL_SDP_OP_CCH_INIT:
- case BTA_HL_SDP_OP_SDP_QUERY_NEW:
- case BTA_HL_SDP_OP_SDP_QUERY_CURRENT:
-
- /* send result in event back to BTA */
- p_cch_buf = (tBTA_HL_CCH_SDP*)osi_malloc(sizeof(tBTA_HL_CCH_SDP));
- if (result) {
- if (sdp_oper == BTA_HL_SDP_OP_CCH_INIT) {
- event = BTA_HL_CCH_SDP_OK_EVT;
- if (p_cb->close_pending) event = BTA_HL_CCH_SDP_FAIL_EVT;
- } else {
- event = BTA_HL_SDP_QUERY_OK_EVT;
- }
- } else {
- if (sdp_oper == BTA_HL_SDP_OP_CCH_INIT)
- event = BTA_HL_CCH_SDP_FAIL_EVT;
- else
- event = BTA_HL_SDP_QUERY_FAIL_EVT;
- }
- p_cch_buf->hdr.event = event;
-
- p_cch_buf->app_idx = app_idx;
- p_cch_buf->mcl_idx = mcl_idx;
- p_cch_buf->release_mcl_cb = false;
- if (sdp_oper == BTA_HL_SDP_OP_SDP_QUERY_NEW)
- p_cch_buf->release_mcl_cb = true;
-
- bta_sys_sendmsg(p_cch_buf);
- break;
- case BTA_HL_SDP_OP_DCH_OPEN_INIT:
- case BTA_HL_SDP_OP_DCH_RECONNECT_INIT:
- p_dch_buf = (tBTA_HL_DCH_SDP*)osi_malloc(sizeof(tBTA_HL_DCH_SDP));
- p_dch_buf->hdr.event = BTA_HL_DCH_SDP_FAIL_EVT;
- p_dch_buf->app_idx = app_idx;
- p_dch_buf->mcl_idx = mcl_idx;
- p_dch_buf->mdl_idx = mdl_idx;
- p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
- if (p_dcb->abort_oper & BTA_HL_ABORT_PENDING_MASK) {
- p_dcb->abort_oper &= ~BTA_HL_ABORT_PENDING_MASK;
- result = false;
- }
- if (result) {
- if (sdp_oper == BTA_HL_SDP_OP_DCH_OPEN_INIT) {
- if (p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID) {
- p_dch_buf->hdr.event = BTA_HL_DCH_ECHO_TEST_EVT;
- } else {
- p_dch_buf->hdr.event = BTA_HL_DCH_OPEN_EVT;
- }
- } else {
- p_dch_buf->hdr.event = BTA_HL_DCH_RECONNECT_EVT;
- }
- }
- bta_sys_sendmsg(p_dch_buf);
- break;
- default:
- break;
- }
-}
-
-/******************************************************************************
- *
- * Function bta_hl_sdp_cback0
- *
- * Description This is the SDP callback function used by index = 0
- *
- * Returns void.
- *
- *****************************************************************************/
-static void bta_hl_sdp_cback0(uint16_t status) {
- bta_hl_sdp_cback(bta_hl_cb.scb[0].sdp_oper, bta_hl_cb.scb[0].app_idx,
- bta_hl_cb.scb[0].mcl_idx, bta_hl_cb.scb[0].mdl_idx, status);
- bta_hl_deallocate_spd_cback(0);
-}
-
-/******************************************************************************
- *
- * Function bta_hl_sdp_cback1
- *
- * Description This is the SDP callback function used by index = 1
- *
- * Parameters status - status of the SDP callabck
- *
- * Returns void.
- *
- *****************************************************************************/
-static void bta_hl_sdp_cback1(uint16_t status) {
- bta_hl_sdp_cback(bta_hl_cb.scb[1].sdp_oper, bta_hl_cb.scb[1].app_idx,
- bta_hl_cb.scb[1].mcl_idx, bta_hl_cb.scb[1].mdl_idx, status);
- bta_hl_deallocate_spd_cback(1);
-}
-
-/******************************************************************************
- *
- * Function bta_hl_sdp_cback2
- *
- * Description This is the SDP callback function used by index = 2
- *
- * Returns void.
- *
- *****************************************************************************/
-static void bta_hl_sdp_cback2(uint16_t status) {
- bta_hl_sdp_cback(bta_hl_cb.scb[2].sdp_oper, bta_hl_cb.scb[2].app_idx,
- bta_hl_cb.scb[2].mcl_idx, bta_hl_cb.scb[2].mdl_idx, status);
- bta_hl_deallocate_spd_cback(2);
-}
-
-/******************************************************************************
- *
- * Function bta_hl_sdp_cback3
- *
- * Description This is the SDP callback function used by index = 3
- *
- * Returns void.
- *
- *****************************************************************************/
-static void bta_hl_sdp_cback3(uint16_t status) {
- bta_hl_sdp_cback(bta_hl_cb.scb[3].sdp_oper, bta_hl_cb.scb[3].app_idx,
- bta_hl_cb.scb[3].mcl_idx, bta_hl_cb.scb[3].mdl_idx, status);
- bta_hl_deallocate_spd_cback(3);
-}
-
-/******************************************************************************
- *
- * Function bta_hl_sdp_cback4
- *
- * Description This is the SDP callback function used by index = 4
- *
- * Parameters status - status of the SDP callabck
- *
- * Returns void.
- *
- *****************************************************************************/
-static void bta_hl_sdp_cback4(uint16_t status) {
- bta_hl_sdp_cback(bta_hl_cb.scb[4].sdp_oper, bta_hl_cb.scb[4].app_idx,
- bta_hl_cb.scb[4].mcl_idx, bta_hl_cb.scb[4].mdl_idx, status);
- bta_hl_deallocate_spd_cback(4);
-}
-
-/******************************************************************************
- *
- * Function bta_hl_sdp_cback5
- *
- * Description This is the SDP callback function used by index = 5
- *
- * Parameters status - status of the SDP callabck
- *
- * Returns void.
- *
- *****************************************************************************/
-static void bta_hl_sdp_cback5(uint16_t status) {
- bta_hl_sdp_cback(bta_hl_cb.scb[5].sdp_oper, bta_hl_cb.scb[5].app_idx,
- bta_hl_cb.scb[5].mcl_idx, bta_hl_cb.scb[5].mdl_idx, status);
- bta_hl_deallocate_spd_cback(5);
-}
-
-/******************************************************************************
- *
- * Function bta_hl_sdp_cback6
- *
- * Description This is the SDP callback function used by index = 6
- *
- * Returns void.
- *
- *****************************************************************************/
-static void bta_hl_sdp_cback6(uint16_t status) {
- bta_hl_sdp_cback(bta_hl_cb.scb[6].sdp_oper, bta_hl_cb.scb[6].app_idx,
- bta_hl_cb.scb[6].mcl_idx, bta_hl_cb.scb[6].mdl_idx, status);
- bta_hl_deallocate_spd_cback(6);
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_deallocate_spd_cback
- *
- * Description Deallocate a SDP control block
- *
- * Returns bool - true found
- * false not found
- *
- ******************************************************************************/
-void bta_hl_deallocate_spd_cback(uint8_t sdp_cback_idx) {
- tBTA_HL_SDP_CB* p_spd_cb = &bta_hl_cb.scb[sdp_cback_idx];
-
- memset(p_spd_cb, 0, sizeof(tBTA_HL_SDP_CB));
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_deallocate_spd_cback index=%d", sdp_cback_idx);
-#endif
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_allocate_spd_cback
- *
- * Description Finds a not in used SDP control block index
- *
- *
- * Returns bool - true found
- * false not found
- *
- ******************************************************************************/
-tSDP_DISC_CMPL_CB* bta_hl_allocate_spd_cback(tBTA_HL_SDP_OPER sdp_oper,
- uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx,
- uint8_t* p_sdp_cback_idx) {
- uint8_t i;
- tSDP_DISC_CMPL_CB* p_cbcak = NULL;
-
- for (i = 0; i < BTA_HL_NUM_SDP_CBACKS; i++) {
- if (!bta_hl_cb.scb[i].in_use) {
- p_cbcak = bta_hl_sdp_cback_arr[i];
- bta_hl_cb.scb[i].in_use = true;
- bta_hl_cb.scb[i].sdp_oper = sdp_oper;
- bta_hl_cb.scb[i].app_idx = app_idx;
- bta_hl_cb.scb[i].mcl_idx = mcl_idx;
- bta_hl_cb.scb[i].mdl_idx = mdl_idx;
- *p_sdp_cback_idx = i;
- break;
- }
- }
-
- if (i == BTA_HL_NUM_SDP_CBACKS) {
- APPL_TRACE_WARNING("No scb is available to allocate")
- } else {
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_allocate_spd_cback cback_idx=%d ", i);
- APPL_TRACE_DEBUG("sdp_oper=%d, app_idx=%d, mcl_idx=%d, mdl_idx=%d",
- bta_hl_cb.scb[i].sdp_oper, bta_hl_cb.scb[i].app_idx,
- bta_hl_cb.scb[i].mcl_idx, bta_hl_cb.scb[i].mdl_idx);
-#endif
- }
- return p_cbcak;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_init_sdp
- *
- * Description Action routine for processing the SDP initiattion request
- *
- * Returns void
- *
- ******************************************************************************/
-tBTA_HL_STATUS bta_hl_init_sdp(tBTA_HL_SDP_OPER sdp_oper, uint8_t app_idx,
- uint8_t mcl_idx, uint8_t mdl_idx) {
- tBTA_HL_MCL_CB* p_cb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- uint16_t attr_list[BTA_HL_NUM_SRCH_ATTR];
- uint16_t num_attrs = BTA_HL_NUM_SRCH_ATTR;
- tBTA_HL_STATUS status;
- uint8_t sdp_cback_idx;
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG(
- "bta_hl_init_sdp sdp_oper=%d app_idx=%d mcl_idx=%d, mdl_idx=%d", sdp_oper,
- app_idx, mcl_idx, mdl_idx);
-#endif
- p_cb->sdp_cback = bta_hl_allocate_spd_cback(sdp_oper, app_idx, mcl_idx,
- mdl_idx, &sdp_cback_idx);
- if (p_cb->sdp_cback != NULL) {
- if (p_cb->p_db == NULL)
- (p_cb->p_db = (tSDP_DISCOVERY_DB*)osi_malloc(BTA_HL_DISC_SIZE));
- attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
- attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
- attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
- attr_list[3] = ATTR_ID_ADDITION_PROTO_DESC_LISTS;
- attr_list[4] = ATTR_ID_SERVICE_NAME;
- attr_list[5] = ATTR_ID_SERVICE_DESCRIPTION;
- attr_list[6] = ATTR_ID_PROVIDER_NAME;
- attr_list[7] = ATTR_ID_HDP_SUP_FEAT_LIST;
- attr_list[8] = ATTR_ID_HDP_DATA_EXCH_SPEC;
- attr_list[9] = ATTR_ID_HDP_MCAP_SUP_PROC;
-
- Uuid uuid_list = Uuid::From16Bit(UUID_SERVCLASS_HDP_PROFILE);
- SDP_InitDiscoveryDb(p_cb->p_db, BTA_HL_DISC_SIZE, 1, &uuid_list, num_attrs,
- attr_list);
-
- if (!SDP_ServiceSearchAttributeRequest(p_cb->bd_addr, p_cb->p_db,
- p_cb->sdp_cback)) {
- status = BTA_HL_STATUS_FAIL;
- } else {
- status = BTA_HL_STATUS_OK;
- }
- } else {
- status = BTA_HL_STATUS_SDP_NO_RESOURCE;
- }
-
- if (status != BTA_HL_STATUS_OK) {
- osi_free_and_reset((void**)&p_cb->p_db);
- if (status != BTA_HL_STATUS_SDP_NO_RESOURCE)
- bta_hl_deallocate_spd_cback(sdp_cback_idx);
- }
-
- return status;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_cch_sdp_init
- *
- * Description Action routine for processing the CCH SDP init event
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_cch_sdp_init(uint8_t app_idx, uint8_t mcl_idx,
- tBTA_HL_DATA* p_data) {
- tBTA_HL_MCL_CB* p_cb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_cch_init_sdp");
-#endif
- if (p_cb->sdp_oper == BTA_HL_SDP_OP_NONE) {
- p_cb->app_id = p_data->api_cch_open.app_id;
- p_cb->sdp_oper = BTA_HL_SDP_OP_CCH_INIT;
-
- if (bta_hl_init_sdp(p_cb->sdp_oper, app_idx, mcl_idx, 0xFF) !=
- BTA_HL_STATUS_OK) {
- p_cb->sdp_oper = BTA_HL_SDP_OP_NONE;
- bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_SDP_FAIL_EVT, p_data);
- }
- } else {
- APPL_TRACE_ERROR("SDP in use");
- bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_SDP_FAIL_EVT, p_data);
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_cch_mca_open
- *
- * Description Action routine for processing the CCH open request
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_cch_mca_open(uint8_t app_idx, uint8_t mcl_idx,
- tBTA_HL_DATA* p_data) {
- tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- uint8_t sdp_idx;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_cch_mca_open");
-#endif
-
- if (bta_hl_find_sdp_idx_using_ctrl_psm(&p_mcb->sdp, p_mcb->req_ctrl_psm,
- &sdp_idx)) {
- p_mcb->ctrl_psm = p_mcb->sdp.sdp_rec[sdp_idx].ctrl_psm;
- p_mcb->data_psm = p_mcb->sdp.sdp_rec[sdp_idx].data_psm;
- if (MCA_ConnectReq((tMCA_HANDLE)p_acb->app_handle, p_mcb->bd_addr,
- p_mcb->ctrl_psm, p_mcb->sec_mask) != MCA_SUCCESS) {
- bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_CLOSE_CMPL_EVT,
- p_data);
- }
- } else {
- bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_CLOSE_CMPL_EVT, p_data);
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_cch_mca_close
- *
- * Description Action routine for processing the CCH close request
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_cch_mca_close(uint8_t app_idx, uint8_t mcl_idx,
- tBTA_HL_DATA* p_data) {
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_cch_mca_close mcl_handle=%d", p_mcb->mcl_handle);
-#endif
- if (p_mcb->sdp_oper != BTA_HL_SDP_OP_CCH_INIT) {
- if (p_mcb->mcl_handle) {
- if (MCA_DisconnectReq((tMCA_HANDLE)p_mcb->mcl_handle) != MCA_SUCCESS) {
- bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_CLOSE_CMPL_EVT,
- p_data);
- }
- } else {
- p_mcb->close_pending = true;
- APPL_TRACE_DEBUG(
- "No valid mcl_handle to stop the CCH setup now so wait until CCH is "
- "up then close it");
- }
- } else {
- p_mcb->close_pending = true;
- APPL_TRACE_DEBUG(
- "can not stop the CCH setup becasue SDP is in progress so wait until "
- "it is done");
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_cch_close_cmpl
- *
- * Description Action routine for processing the CCH close complete event
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_cch_close_cmpl(uint8_t app_idx, uint8_t mcl_idx,
- tBTA_HL_DATA* p_data) {
- tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
-
- tBTA_HL evt_data;
- tBTA_HL_EVT event;
- bool send_evt = true;
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_cch_close_cmpl");
-#endif
- bta_sys_conn_close(BTA_ID_HL, p_acb->app_id, p_mcb->bd_addr);
-
- if (p_mcb->cch_oper == BTA_HL_CCH_OP_LOCAL_CLOSE &&
- p_mcb->force_close_local_cch_opening) {
- p_mcb->cch_oper = BTA_HL_CCH_OP_LOCAL_OPEN;
- APPL_TRACE_DEBUG(
- "change cch_oper from BTA_HL_CCH_OP_LOCAL_CLOSE to "
- "BTA_HL_CCH_OP_LOCAL_OPEN");
- }
-
- switch (p_mcb->cch_oper) {
- case BTA_HL_CCH_OP_LOCAL_OPEN:
- bta_hl_build_cch_open_cfm(&evt_data, p_mcb->app_id, p_acb->app_handle,
- p_mcb->mcl_handle, p_mcb->bd_addr,
- BTA_HL_STATUS_FAIL);
- event = BTA_HL_CCH_OPEN_CFM_EVT;
- break;
- case BTA_HL_CCH_OP_LOCAL_CLOSE:
- bta_hl_build_cch_close_cfm(&evt_data, p_acb->app_handle,
- p_mcb->mcl_handle, BTA_HL_STATUS_OK);
- event = BTA_HL_CCH_CLOSE_CFM_EVT;
- break;
- case BTA_HL_CCH_OP_REMOTE_CLOSE:
- bta_hl_build_cch_close_ind(&evt_data, p_acb->app_handle,
- p_mcb->mcl_handle, p_mcb->intentional_close);
- event = BTA_HL_CCH_CLOSE_IND_EVT;
- break;
- default:
- send_evt = false;
- break;
- }
-
- memset(p_mcb, 0, sizeof(tBTA_HL_MCL_CB));
-
- if (send_evt) p_acb->p_cback(event, (tBTA_HL*)&evt_data);
-
- bta_hl_check_deregistration(app_idx, p_data);
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_cch_mca_disconnect
- *
- * Description Action routine for processing the CCH disconnect indication
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_cch_mca_disconnect(uint8_t app_idx, uint8_t mcl_idx,
- tBTA_HL_DATA* p_data) {
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- tBTA_HL_MDL_CB* p_dcb;
- uint8_t i;
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_cch_mca_disconnect");
-#endif
-
- p_mcb->intentional_close = false;
- if (p_data->mca_evt.mca_data.disconnect_ind.reason == L2CAP_DISC_OK) {
- p_mcb->intentional_close = true;
- }
-
- for (i = 0; i < BTA_HL_NUM_MDLS_PER_MCL; i++) {
- p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, i);
- if (p_dcb->in_use && (p_dcb->dch_state != BTA_HL_DCH_IDLE_ST)) {
- if (p_mcb->cch_oper == BTA_HL_CCH_OP_LOCAL_CLOSE) {
- bta_hl_dch_sm_execute(app_idx, mcl_idx, i, BTA_HL_DCH_CLOSE_CMPL_EVT,
- p_data);
- } else {
- bta_hl_dch_sm_execute(app_idx, mcl_idx, i, BTA_HL_MCA_CLOSE_IND_EVT,
- p_data);
- }
- }
- }
- bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_CLOSE_CMPL_EVT, p_data);
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_cch_mca_disc_open
- *
- * Description Action routine for disconnect the just opened Control
- * channel
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_cch_mca_disc_open(uint8_t app_idx, uint8_t mcl_idx,
- tBTA_HL_DATA* p_data) {
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_cch_mca_disc_open mcl_handle=0x%x close_pending=%d",
- p_data->mca_evt.mcl_handle, p_mcb->close_pending);
-#endif
-
- p_mcb->close_pending = false;
- p_mcb->mcl_handle = p_data->mca_evt.mcl_handle;
- bta_hl_cch_mca_close(app_idx, mcl_idx, p_data);
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_cch_mca_rsp_tout
- *
- * Description Action routine for processing the MCAP response timeout
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_cch_mca_rsp_tout(uint8_t app_idx, uint8_t mcl_idx,
- tBTA_HL_DATA* p_data) {
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_cch_mca_rsp_tout");
-#endif
-
- p_mcb->rsp_tout = true;
-
- bta_hl_check_cch_close(app_idx, mcl_idx, p_data, true);
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_cch_mca_connect
- *
- * Description Action routine for processing the CCH connect indication
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_cch_mca_connect(uint8_t app_idx, uint8_t mcl_idx,
- tBTA_HL_DATA* p_data) {
- tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- tBTA_HL evt_data;
- tBTA_HL_EVT event;
- bool send_event = true;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_cch_mca_connect mcl_handle=%d ",
- p_data->mca_evt.mcl_handle);
-#endif
-
- p_mcb->mcl_handle = p_data->mca_evt.mcl_handle;
- p_mcb->bd_addr = p_data->mca_evt.mca_data.connect_ind.bd_addr;
- p_mcb->cch_mtu = p_data->mca_evt.mca_data.connect_ind.mtu;
-
- bta_sys_conn_open(BTA_ID_HL, p_acb->app_id, p_mcb->bd_addr);
- switch (p_mcb->cch_oper) {
- case BTA_HL_CCH_OP_LOCAL_OPEN:
- bta_hl_build_cch_open_cfm(&evt_data, p_mcb->app_id, p_acb->app_handle,
- p_mcb->mcl_handle, p_mcb->bd_addr,
- BTA_HL_STATUS_OK);
- event = BTA_HL_CCH_OPEN_CFM_EVT;
- break;
- case BTA_HL_CCH_OP_REMOTE_OPEN:
- bta_hl_build_cch_open_ind(&evt_data, p_acb->app_handle, p_mcb->mcl_handle,
- p_mcb->bd_addr);
- event = BTA_HL_CCH_OPEN_IND_EVT;
- break;
- default:
- send_event = false;
- break;
- }
-
- p_mcb->cch_oper = BTA_HL_CCH_OP_NONE;
- if (send_event) p_acb->p_cback(event, (tBTA_HL*)&evt_data);
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_mcap_ctrl_cback
- *
- * Description MCAP control callback function for HL.
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_mcap_ctrl_cback(tMCA_HANDLE handle, tMCA_CL mcl, uint8_t event,
- tMCA_CTRL* p_data) {
- bool send_event = true;
- uint16_t mca_event;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_EVENT("bta_hl_mcap_ctrl_cback event[%s]",
- bta_hl_mcap_evt_code(event));
-#endif
-
- switch (event) {
- case MCA_CREATE_IND_EVT:
- mca_event = (uint16_t)BTA_HL_MCA_CREATE_IND_EVT;
- break;
- case MCA_CREATE_CFM_EVT:
- mca_event = (uint16_t)BTA_HL_MCA_CREATE_CFM_EVT;
- break;
- case MCA_RECONNECT_IND_EVT:
- mca_event = (uint16_t)BTA_HL_MCA_RECONNECT_IND_EVT;
- break;
- case MCA_RECONNECT_CFM_EVT:
- mca_event = (uint16_t)BTA_HL_MCA_RECONNECT_CFM_EVT;
- break;
- case MCA_ABORT_IND_EVT:
- mca_event = (uint16_t)BTA_HL_MCA_ABORT_IND_EVT;
- break;
- case MCA_ABORT_CFM_EVT:
- mca_event = (uint16_t)BTA_HL_MCA_ABORT_CFM_EVT;
- break;
- case MCA_DELETE_IND_EVT:
- mca_event = (uint16_t)BTA_HL_MCA_DELETE_IND_EVT;
- break;
- case MCA_DELETE_CFM_EVT:
- mca_event = (uint16_t)BTA_HL_MCA_DELETE_CFM_EVT;
- break;
- case MCA_CONNECT_IND_EVT:
- mca_event = (uint16_t)BTA_HL_MCA_CONNECT_IND_EVT;
- break;
- case MCA_DISCONNECT_IND_EVT:
- mca_event = (uint16_t)BTA_HL_MCA_DISCONNECT_IND_EVT;
- break;
- case MCA_OPEN_IND_EVT:
- mca_event = (uint16_t)BTA_HL_MCA_OPEN_IND_EVT;
- break;
- case MCA_OPEN_CFM_EVT:
- mca_event = (uint16_t)BTA_HL_MCA_OPEN_CFM_EVT;
- break;
- case MCA_CLOSE_IND_EVT:
- mca_event = (uint16_t)BTA_HL_MCA_CLOSE_IND_EVT;
- break;
- case MCA_CLOSE_CFM_EVT:
- mca_event = (uint16_t)BTA_HL_MCA_CLOSE_CFM_EVT;
- break;
- case MCA_CONG_CHG_EVT:
- mca_event = (uint16_t)BTA_HL_MCA_CONG_CHG_EVT;
- break;
- case MCA_RSP_TOUT_IND_EVT:
- mca_event = (uint16_t)BTA_HL_MCA_RSP_TOUT_IND_EVT;
- break;
- case MCA_ERROR_RSP_EVT:
-
- default:
- send_event = false;
- break;
- }
-
- if (send_event) {
- tBTA_HL_MCA_EVT* p_msg =
- (tBTA_HL_MCA_EVT*)osi_malloc(sizeof(tBTA_HL_MCA_EVT));
- p_msg->hdr.event = mca_event;
- p_msg->app_handle = (tBTA_HL_APP_HANDLE)handle;
- p_msg->mcl_handle = (tBTA_HL_MCL_HANDLE)mcl;
- memcpy(&p_msg->mca_data, p_data, sizeof(tMCA_CTRL));
- bta_sys_sendmsg(p_msg);
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_mcap_data_cback
- *
- * Description MCAP data callback function for HL.
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_mcap_data_cback(tMCA_DL mdl, BT_HDR* p_pkt) {
- uint8_t app_idx, mcl_idx, mdl_idx;
- if (bta_hl_find_mdl_idx_using_handle((tBTA_HL_MDL_HANDLE)mdl, &app_idx,
- &mcl_idx, &mdl_idx)) {
- tBTA_HL_MCA_RCV_DATA_EVT* p_msg =
- (tBTA_HL_MCA_RCV_DATA_EVT*)osi_malloc(sizeof(tBTA_HL_MCA_RCV_DATA_EVT));
- p_msg->hdr.event = BTA_HL_MCA_RCV_DATA_EVT;
- p_msg->app_idx = app_idx;
- p_msg->mcl_idx = mcl_idx;
- p_msg->mdl_idx = mdl_idx;
- p_msg->p_pkt = p_pkt;
- bta_sys_sendmsg(p_msg);
- }
-}
-
-/*****************************************************************************
- * Debug Functions
- ****************************************************************************/
-#if (BTA_HL_DEBUG == TRUE)
-
-#define CASE_RETURN_STR(const) \
- case const: \
- return #const;
-
-/*******************************************************************************
- *
- * Function bta_hl_mcap_evt_code
- *
- * Description get the MCAP event string pointer
- *
- * Returns char * - event string pointer
- *
- ******************************************************************************/
-static const char* bta_hl_mcap_evt_code(uint8_t evt_code) {
- switch (evt_code) {
- CASE_RETURN_STR(MCA_ERROR_RSP_EVT)
- CASE_RETURN_STR(MCA_CREATE_IND_EVT)
- CASE_RETURN_STR(MCA_CREATE_CFM_EVT)
- CASE_RETURN_STR(MCA_RECONNECT_IND_EVT)
- CASE_RETURN_STR(MCA_RECONNECT_CFM_EVT)
- CASE_RETURN_STR(MCA_ABORT_IND_EVT)
- CASE_RETURN_STR(MCA_ABORT_CFM_EVT)
- CASE_RETURN_STR(MCA_DELETE_IND_EVT)
- CASE_RETURN_STR(MCA_DELETE_CFM_EVT)
- CASE_RETURN_STR(MCA_CONNECT_IND_EVT)
- CASE_RETURN_STR(MCA_DISCONNECT_IND_EVT)
- CASE_RETURN_STR(MCA_OPEN_IND_EVT)
- CASE_RETURN_STR(MCA_OPEN_CFM_EVT)
- CASE_RETURN_STR(MCA_CLOSE_IND_EVT)
- CASE_RETURN_STR(MCA_CLOSE_CFM_EVT)
- CASE_RETURN_STR(MCA_CONG_CHG_EVT)
- CASE_RETURN_STR(MCA_RSP_TOUT_IND_EVT)
- default:
- return "Unknown MCAP event code";
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_cback_evt_code
- *
- * Description get the HDP event string pointer
- *
- * Returns char * - event string pointer
- *
- ******************************************************************************/
-static const char* bta_hl_cback_evt_code(uint8_t evt_code) {
- switch (evt_code) {
- CASE_RETURN_STR(BTA_HL_CCH_OPEN_IND_EVT)
- CASE_RETURN_STR(BTA_HL_CCH_OPEN_CFM_EVT)
- CASE_RETURN_STR(BTA_HL_CCH_CLOSE_IND_EVT)
- CASE_RETURN_STR(BTA_HL_CCH_CLOSE_CFM_EVT)
- CASE_RETURN_STR(BTA_HL_DCH_OPEN_IND_EVT)
- CASE_RETURN_STR(BTA_HL_DCH_OPEN_CFM_EVT)
- CASE_RETURN_STR(BTA_HL_DCH_CLOSE_IND_EVT)
- CASE_RETURN_STR(BTA_HL_DCH_CLOSE_CFM_EVT)
- CASE_RETURN_STR(BTA_HL_DCH_RCV_DATA_IND_EVT)
- CASE_RETURN_STR(BTA_HL_REGISTER_CFM_EVT)
- CASE_RETURN_STR(BTA_HL_DEREGISTER_CFM_EVT)
- CASE_RETURN_STR(BTA_HL_DCH_RECONNECT_CFM_EVT)
- CASE_RETURN_STR(BTA_HL_DCH_RECONNECT_IND_EVT)
- CASE_RETURN_STR(BTA_HL_DCH_ECHO_TEST_CFM_EVT)
- CASE_RETURN_STR(BTA_HL_SDP_QUERY_CFM_EVT)
- CASE_RETURN_STR(BTA_HL_CONG_CHG_IND_EVT)
- CASE_RETURN_STR(BTA_HL_DCH_CREATE_IND_EVT)
- CASE_RETURN_STR(BTA_HL_DELETE_MDL_IND_EVT)
- CASE_RETURN_STR(BTA_HL_DELETE_MDL_CFM_EVT)
- CASE_RETURN_STR(BTA_HL_DCH_ABORT_IND_EVT)
- CASE_RETURN_STR(BTA_HL_DCH_ABORT_CFM_EVT)
- default:
- return "Unknown HDP event code";
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_dch_oper_code
- *
- * Description Get the DCH operation string
- *
- * Returns char * - DCH operation string pointer
- *
- ******************************************************************************/
-static const char* bta_hl_dch_oper_code(tBTA_HL_DCH_OPER oper_code) {
- switch (oper_code) {
- CASE_RETURN_STR(BTA_HL_DCH_OP_NONE)
- CASE_RETURN_STR(BTA_HL_DCH_OP_REMOTE_CREATE)
- CASE_RETURN_STR(BTA_HL_DCH_OP_LOCAL_OPEN)
- CASE_RETURN_STR(BTA_HL_DCH_OP_REMOTE_OPEN)
- CASE_RETURN_STR(BTA_HL_DCH_OP_LOCAL_CLOSE)
- CASE_RETURN_STR(BTA_HL_DCH_OP_REMOTE_CLOSE)
- CASE_RETURN_STR(BTA_HL_DCH_OP_LOCAL_DELETE)
- CASE_RETURN_STR(BTA_HL_DCH_OP_REMOTE_DELETE)
- CASE_RETURN_STR(BTA_HL_DCH_OP_LOCAL_RECONNECT)
- CASE_RETURN_STR(BTA_HL_DCH_OP_REMOTE_RECONNECT)
- CASE_RETURN_STR(BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST)
- CASE_RETURN_STR(BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT)
- default:
- return "Unknown DCH oper code";
- }
-}
-
-#endif /* Debug Functions */
-#endif /* HL_INCLUDED */
diff --git a/bta/hl/bta_hl_api.cc b/bta/hl/bta_hl_api.cc
deleted file mode 100644
index fa82245..0000000
--- a/bta/hl/bta_hl_api.cc
+++ /dev/null
@@ -1,489 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2009-2012 Broadcom 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.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- * This is the implementation of the API for the HeaLth device profile (HL)
- * subsystem of BTA, Broadcom Corp's Bluetooth application layer for mobile
- * phones.
- *
- ******************************************************************************/
-
-#include <string.h>
-
-#include "bt_target.h"
-#if (HL_INCLUDED == TRUE)
-
-#include "bt_common.h"
-#include "bta_hl_api.h"
-#include "bta_hl_int.h"
-
-/*****************************************************************************
- * Constants
- ****************************************************************************/
-
-static const tBTA_SYS_REG bta_hl_reg = {bta_hl_hdl_event, BTA_HlDisable};
-
-/*******************************************************************************
- *
- * Function BTA_HlEnable
- *
- * Description Enable the HL subsystems. This function must be
- * called before any other functions in the HL API are called.
- * When the enable operation is completed the callback function
- * will be called with an BTA_HL_CTRL_ENABLE_CFM_EVT event.
- *
- * Parameters p_cback - HL event call back function
- *
- * Returns void
- *
- ******************************************************************************/
-void BTA_HlEnable(tBTA_HL_CTRL_CBACK* p_ctrl_cback) {
- tBTA_HL_API_ENABLE* p_buf =
- (tBTA_HL_API_ENABLE*)osi_malloc(sizeof(tBTA_HL_API_ENABLE));
-
- /* register with BTA system manager */
- bta_sys_register(BTA_ID_HL, &bta_hl_reg);
-
- p_buf->hdr.event = BTA_HL_API_ENABLE_EVT;
- p_buf->p_cback = p_ctrl_cback;
-
- bta_sys_sendmsg(p_buf);
-}
-
-/*******************************************************************************
- *
- * Function BTA_HlDisable
- *
- * Description Disable the HL subsystem.
- *
- * Returns void
- *
- ******************************************************************************/
-void BTA_HlDisable(void) {
- BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
-
- bta_sys_deregister(BTA_ID_HL);
- p_buf->event = BTA_HL_API_DISABLE_EVT;
-
- bta_sys_sendmsg(p_buf);
-}
-
-/*******************************************************************************
- *
- * Function BTA_HlUpdate
- *
- * Description Register an HDP application
- *
- * Parameters app_id - Application ID
- * p_reg_param - non-platform related parameters for the
- * HDP application
- * p_cback - HL event callback fucntion
- *
- * Returns void
- *
- ******************************************************************************/
-void BTA_HlUpdate(uint8_t app_id, tBTA_HL_REG_PARAM* p_reg_param,
- bool is_register, tBTA_HL_CBACK* p_cback) {
- tBTA_HL_API_UPDATE* p_buf =
- (tBTA_HL_API_UPDATE*)osi_malloc(sizeof(tBTA_HL_API_UPDATE));
-
- APPL_TRACE_DEBUG("%s", __func__);
-
- p_buf->hdr.event = BTA_HL_API_UPDATE_EVT;
- p_buf->app_id = app_id;
- p_buf->is_register = is_register;
-
- if (is_register) {
- p_buf->sec_mask =
- (p_reg_param->sec_mask | BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
- p_buf->p_cback = p_cback;
- if (p_reg_param->p_srv_name)
- strlcpy(p_buf->srv_name, p_reg_param->p_srv_name, BTA_SERVICE_NAME_LEN);
- else
- p_buf->srv_name[0] = 0;
-
- if (p_reg_param->p_srv_desp)
- strlcpy(p_buf->srv_desp, p_reg_param->p_srv_desp, BTA_SERVICE_DESP_LEN);
- else
- p_buf->srv_desp[0] = 0;
-
- if (p_reg_param->p_provider_name)
- strlcpy(p_buf->provider_name, p_reg_param->p_provider_name,
- BTA_PROVIDER_NAME_LEN);
- else
- p_buf->provider_name[0] = 0;
- }
-
- bta_sys_sendmsg(p_buf);
-}
-
-/*******************************************************************************
- *
- * Function BTA_HlRegister
- *
- * Description Register an HDP application
- *
- * Parameters app_id - Application ID
- * p_reg_param - non-platform related parameters for the
- * HDP application
- * p_cback - HL event callback fucntion
- *
- * Returns void
- *
- ******************************************************************************/
-void BTA_HlRegister(uint8_t app_id, tBTA_HL_REG_PARAM* p_reg_param,
- tBTA_HL_CBACK* p_cback) {
- tBTA_HL_API_REGISTER* p_buf =
- (tBTA_HL_API_REGISTER*)osi_malloc(sizeof(tBTA_HL_API_REGISTER));
-
- p_buf->hdr.event = BTA_HL_API_REGISTER_EVT;
- p_buf->app_id = app_id;
- p_buf->sec_mask =
- (p_reg_param->sec_mask | BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
- p_buf->p_cback = p_cback;
-
- if (p_reg_param->p_srv_name)
- strlcpy(p_buf->srv_name, p_reg_param->p_srv_name, BTA_SERVICE_NAME_LEN);
- else
- p_buf->srv_name[0] = 0;
-
- if (p_reg_param->p_srv_desp)
- strlcpy(p_buf->srv_desp, p_reg_param->p_srv_desp, BTA_SERVICE_DESP_LEN);
- else
- p_buf->srv_desp[0] = 0;
-
- if (p_reg_param->p_provider_name)
- strlcpy(p_buf->provider_name, p_reg_param->p_provider_name,
- BTA_PROVIDER_NAME_LEN);
- else
- p_buf->provider_name[0] = 0;
-
- bta_sys_sendmsg(p_buf);
-}
-
-/*******************************************************************************
- *
- * Function BTA_HlDeregister
- *
- * Description Deregister an HDP application
- *
- * Parameters app_handle - Application handle
- *
- * Returns void
- *
- ******************************************************************************/
-void BTA_HlDeregister(uint8_t app_id, tBTA_HL_APP_HANDLE app_handle) {
- tBTA_HL_API_DEREGISTER* p_buf =
- (tBTA_HL_API_DEREGISTER*)osi_malloc(sizeof(tBTA_HL_API_DEREGISTER));
-
- p_buf->hdr.event = BTA_HL_API_DEREGISTER_EVT;
- p_buf->app_id = app_id;
- p_buf->app_handle = app_handle;
-
- bta_sys_sendmsg(p_buf);
-}
-
-/*******************************************************************************
- *
- * Function BTA_HlCchOpen
- *
- * Description Open a Control channel connection with the specified BD
- * address
- *
- * Parameters app_handle - Application Handle
- * p_open_param - parameters for opening a control channel
- *
- * Returns void
- *
- * Note: The control PSM value is used to select which
- * HDP insatnce should be used in case the peer device support
- * multiple HDP instances. Also, if the control PSM value is
- * zero then the first HDP instance is used for the control
- * channel setup
- ******************************************************************************/
-void BTA_HlCchOpen(uint8_t app_id, tBTA_HL_APP_HANDLE app_handle,
- tBTA_HL_CCH_OPEN_PARAM* p_open_param) {
- tBTA_HL_API_CCH_OPEN* p_buf =
- (tBTA_HL_API_CCH_OPEN*)osi_malloc(sizeof(tBTA_HL_API_CCH_OPEN));
-
- p_buf->hdr.event = BTA_HL_API_CCH_OPEN_EVT;
- p_buf->app_id = app_id;
- p_buf->app_handle = app_handle;
- p_buf->sec_mask =
- (p_open_param->sec_mask | BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
- p_buf->bd_addr = p_open_param->bd_addr;
- p_buf->ctrl_psm = p_open_param->ctrl_psm;
-
- bta_sys_sendmsg(p_buf);
-}
-
-/*******************************************************************************
- *
- * Function BTA_HlCchClose
- *
- * Description Close a Control channel connection with the specified MCL
- * handle
- *
- * Parameters mcl_handle - MCL handle
- *
- * Returns void
- *
- ******************************************************************************/
-void BTA_HlCchClose(tBTA_HL_MCL_HANDLE mcl_handle) {
- tBTA_HL_API_CCH_CLOSE* p_buf =
- (tBTA_HL_API_CCH_CLOSE*)osi_malloc(sizeof(tBTA_HL_API_CCH_CLOSE));
-
- p_buf->hdr.event = BTA_HL_API_CCH_CLOSE_EVT;
- p_buf->mcl_handle = mcl_handle;
-
- bta_sys_sendmsg(p_buf);
-}
-
-/*******************************************************************************
- *
- * Function BTA_HlDchOpen
- *
- * Description Open a data channel connection with the specified DCH
- * parameters
- *
- * Parameters mcl_handle - MCL handle
- * p_open_param - parameters for opening a data channel
- *
- * Returns void
- *
- ******************************************************************************/
-void BTA_HlDchOpen(tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_DCH_OPEN_PARAM* p_open_param) {
- tBTA_HL_API_DCH_OPEN* p_buf =
- (tBTA_HL_API_DCH_OPEN*)osi_malloc(sizeof(tBTA_HL_API_DCH_OPEN));
-
- p_buf->hdr.event = BTA_HL_API_DCH_OPEN_EVT;
- p_buf->mcl_handle = mcl_handle;
- p_buf->ctrl_psm = p_open_param->ctrl_psm;
- p_buf->local_mdep_id = p_open_param->local_mdep_id;
- p_buf->peer_mdep_id = p_open_param->peer_mdep_id;
- p_buf->local_cfg = p_open_param->local_cfg;
- p_buf->sec_mask =
- (p_open_param->sec_mask | BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
-
- bta_sys_sendmsg(p_buf);
-}
-
-/*******************************************************************************
- *
- * Function BTA_HlDchReconnect
- *
- * Description Reconnect a data channel with the specified MDL_ID
- *
- * Parameters mcl_handle - MCL handle
-*8 p_recon_param - parameters for reconnecting a data channel
- *
- * Returns void
- *
- ******************************************************************************/
-void BTA_HlDchReconnect(tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_DCH_RECONNECT_PARAM* p_recon_param) {
- tBTA_HL_API_DCH_RECONNECT* p_buf =
- (tBTA_HL_API_DCH_RECONNECT*)osi_malloc(sizeof(tBTA_HL_API_DCH_RECONNECT));
-
- p_buf->hdr.event = BTA_HL_API_DCH_RECONNECT_EVT;
- p_buf->mcl_handle = mcl_handle;
- p_buf->ctrl_psm = p_recon_param->ctrl_psm;
- p_buf->mdl_id = p_recon_param->mdl_id;
-
- bta_sys_sendmsg(p_buf);
-}
-
-/*******************************************************************************
- *
- * Function BTA_HlDchClose
- *
- * Description Close a data channel with the specified MDL handle
- *
- * Parameters mdl_handle - MDL handle
- *
- * Returns void
- *
- ******************************************************************************/
-void BTA_HlDchClose(tBTA_HL_MDL_HANDLE mdl_handle) {
- tBTA_HL_API_DCH_CLOSE* p_buf =
- (tBTA_HL_API_DCH_CLOSE*)osi_malloc(sizeof(tBTA_HL_API_DCH_CLOSE));
-
- p_buf->hdr.event = BTA_HL_API_DCH_CLOSE_EVT;
- p_buf->mdl_handle = mdl_handle;
-
- bta_sys_sendmsg(p_buf);
-}
-
-/*******************************************************************************
- *
- * Function BTA_HlDchAbort
- *
- * Description Abort the current data channel setup with the specified MCL
- * handle
- *
- * Parameters mcl_handle - MCL handle
- *
- *
- * Returns void
- *
- ******************************************************************************/
-void BTA_HlDchAbort(tBTA_HL_MCL_HANDLE mcl_handle) {
- tBTA_HL_API_DCH_ABORT* p_buf =
- (tBTA_HL_API_DCH_ABORT*)osi_malloc(sizeof(tBTA_HL_API_DCH_ABORT));
-
- p_buf->hdr.event = BTA_HL_API_DCH_ABORT_EVT;
- p_buf->mcl_handle = mcl_handle;
-
- bta_sys_sendmsg(p_buf);
-}
-
-/*******************************************************************************
- *
- * Function BTA_HlSendData
- *
- * Description Send an APDU to the peer device
- *
- * Parameters mdl_handle - MDL handle
- * pkt_size - size of the data packet to be sent
- *
- * Returns void
- *
- ******************************************************************************/
-void BTA_HlSendData(tBTA_HL_MDL_HANDLE mdl_handle, uint16_t pkt_size) {
- tBTA_HL_API_SEND_DATA* p_buf =
- (tBTA_HL_API_SEND_DATA*)osi_malloc(sizeof(tBTA_HL_API_SEND_DATA));
-
- p_buf->hdr.event = BTA_HL_API_SEND_DATA_EVT;
- p_buf->mdl_handle = mdl_handle;
- p_buf->pkt_size = pkt_size;
-
- bta_sys_sendmsg(p_buf);
-}
-
-/*******************************************************************************
- *
- * Function BTA_HlDeleteMdl
- *
- * Description Delete the specified MDL_ID within the specified MCL handle
- *
- * Parameters mcl_handle - MCL handle
- * mdl_id - MDL ID
- *
- * Returns void
- *
- * note: If mdl_id = 0xFFFF then this means to delete all MDLs
- * and this value can only be used with DeleteMdl request
- * only not other requests
- *
- ******************************************************************************/
-void BTA_HlDeleteMdl(tBTA_HL_MCL_HANDLE mcl_handle, tBTA_HL_MDL_ID mdl_id) {
- tBTA_HL_API_DELETE_MDL* p_buf =
- (tBTA_HL_API_DELETE_MDL*)osi_malloc(sizeof(tBTA_HL_API_DELETE_MDL));
-
- p_buf->hdr.event = BTA_HL_API_DELETE_MDL_EVT;
- p_buf->mcl_handle = mcl_handle;
- p_buf->mdl_id = mdl_id;
-
- bta_sys_sendmsg(p_buf);
-}
-
-/*******************************************************************************
- *
- * Function BTA_HlDchEchoTest
- *
- * Description Initiate an echo test with the specified MCL handle
- *
- * Parameters mcl_handle - MCL handle
-*8 p_echo_test_param - parameters for echo testing
- *
- * Returns void
- *
- ******************************************************************************/
-void BTA_HlDchEchoTest(tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_DCH_ECHO_TEST_PARAM* p_echo_test_param) {
- tBTA_HL_API_DCH_ECHO_TEST* p_buf =
- (tBTA_HL_API_DCH_ECHO_TEST*)osi_malloc(sizeof(tBTA_HL_API_DCH_ECHO_TEST));
-
- p_buf->hdr.event = BTA_HL_API_DCH_ECHO_TEST_EVT;
- p_buf->mcl_handle = mcl_handle;
- p_buf->ctrl_psm = p_echo_test_param->ctrl_psm;
- p_buf->local_cfg = p_echo_test_param->local_cfg;
- p_buf->pkt_size = p_echo_test_param->pkt_size;
-
- bta_sys_sendmsg(p_buf);
-}
-
-/*******************************************************************************
- *
- * Function BTA_HlSdpQuery
- *
- * Description SDP query request for the specified BD address
- *
- * Parameters app_handle - application handle
- * bd_addr - BD address
- *
- * Returns void
- *
- ******************************************************************************/
-void BTA_HlSdpQuery(uint8_t app_id, tBTA_HL_APP_HANDLE app_handle,
- const RawAddress& bd_addr) {
- tBTA_HL_API_SDP_QUERY* p_buf =
- (tBTA_HL_API_SDP_QUERY*)osi_malloc(sizeof(tBTA_HL_API_SDP_QUERY));
-
- p_buf->hdr.event = BTA_HL_API_SDP_QUERY_EVT;
- p_buf->app_id = app_id;
- p_buf->app_handle = app_handle;
- p_buf->bd_addr = bd_addr;
-
- bta_sys_sendmsg(p_buf);
-}
-
-/*******************************************************************************
- *
- * Function BTA_HlDchCreateMdlRsp
- *
- * Description Set the Response and configuration values for the Create MDL
- * request
- *
- * Parameters mcl_handle - MCL handle
- * p_rsp_param - parameters specified whether the request
- * should be accepted or not and if it should be
- * accepted, then it also specified the
- * configuration response value
- *
- * Returns void
- *
- ******************************************************************************/
-void BTA_HlDchCreateRsp(tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_DCH_CREATE_RSP_PARAM* p_rsp_param) {
- tBTA_HL_API_DCH_CREATE_RSP* p_buf = (tBTA_HL_API_DCH_CREATE_RSP*)osi_malloc(
- sizeof(tBTA_HL_API_DCH_CREATE_RSP));
-
- p_buf->hdr.event = BTA_HL_API_DCH_CREATE_RSP_EVT;
- p_buf->mcl_handle = mcl_handle;
- p_buf->mdl_id = p_rsp_param->mdl_id;
- p_buf->local_mdep_id = p_rsp_param->local_mdep_id;
- p_buf->rsp_code = p_rsp_param->rsp_code;
- p_buf->cfg_rsp = p_rsp_param->cfg_rsp;
-
- bta_sys_sendmsg(p_buf);
-}
-
-#endif /* HL_INCLUDED */
diff --git a/bta/hl/bta_hl_ci.cc b/bta/hl/bta_hl_ci.cc
deleted file mode 100644
index e48c74b..0000000
--- a/bta/hl/bta_hl_ci.cc
+++ /dev/null
@@ -1,162 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2009-2012 Broadcom 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.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- * This is the implementation file for the HeaLth device profile (HL)
- * subsystem call-in functions.
- *
- ******************************************************************************/
-
-#include <stddef.h>
-
-#include "bta_api.h"
-#include "bta_hl_api.h"
-#include "bta_hl_ci.h"
-#include "bta_hl_co.h"
-#include "bta_hl_int.h"
-#include "bta_sys.h"
-#include "btm_api.h"
-
-/*******************************************************************************
- *
- * Function bta_hl_ci_get_tx_data
- *
- * Description This function is called in response to the
- * bta_hl_co_get_tx_data call-out function.
- *
- * Parameters mdl_handle -MDL handle
- * status - BTA_MA_STATUS_OK if operation is successful
- * BTA_MA_STATUS_FAIL if any errors have occurred.
- * evt - evt from the call-out function
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_ci_get_tx_data(tBTA_HL_MDL_HANDLE mdl_handle, tBTA_HL_STATUS status,
- uint16_t evt) {
- tBTA_HL_CI_GET_PUT_DATA* p_evt =
- (tBTA_HL_CI_GET_PUT_DATA*)osi_malloc(sizeof(tBTA_HL_CI_GET_PUT_DATA));
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("%s mdl_handle=%d status=%d evt=%d\n", __func__, mdl_handle,
- status, evt);
-#endif
-
- p_evt->hdr.event = evt;
- p_evt->mdl_handle = mdl_handle;
- p_evt->status = status;
-
- bta_sys_sendmsg(p_evt);
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_ci_put_rx_data
- *
- * Description This function is called in response to the
- * bta_hl_co_put_rx_data call-out function.
- *
- * Parameters mdl_handle -MDL handle
- * status - BTA_MA_STATUS_OK if operation is successful
- * BTA_MA_STATUS_FAIL if any errors have occurred.
- * evt - evt from the call-out function
- *
- * Returns void
- *
- ******************************************************************************/
-extern void bta_hl_ci_put_rx_data(tBTA_HL_MDL_HANDLE mdl_handle,
- tBTA_HL_STATUS status, uint16_t evt) {
- tBTA_HL_CI_GET_PUT_DATA* p_evt =
- (tBTA_HL_CI_GET_PUT_DATA*)osi_malloc(sizeof(tBTA_HL_CI_GET_PUT_DATA));
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("%s mdl_handle=%d status=%d evt=%d\n", __func__, mdl_handle,
- status, evt);
-#endif
-
- p_evt->hdr.event = evt;
- p_evt->mdl_handle = mdl_handle;
- p_evt->status = status;
-
- bta_sys_sendmsg(p_evt);
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_ci_get_echo_data
- *
- * Description This function is called in response to the
- * bta_hl_co_get_echo_data call-out function.
- *
- * Parameters mcl_handle -MCL handle
- * status - BTA_MA_STATUS_OK if operation is successful
- * BTA_MA_STATUS_FAIL if any errors have occurred.
- * evt - evt from the call-out function
- *
- * Returns void
- *
- ******************************************************************************/
-extern void bta_hl_ci_get_echo_data(tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_STATUS status, uint16_t evt) {
- tBTA_HL_CI_ECHO_DATA* p_evt =
- (tBTA_HL_CI_ECHO_DATA*)osi_malloc(sizeof(tBTA_HL_CI_ECHO_DATA));
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("%s mcl_handle=%d status=%d evt=%d\n", __func__, mcl_handle,
- status, evt);
-#endif
-
- p_evt->hdr.event = evt;
- p_evt->mcl_handle = mcl_handle;
- p_evt->status = status;
-
- bta_sys_sendmsg(p_evt);
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_ci_put_echo_data
- *
- * Description This function is called in response to the
- * bta_hl_co_put_echo_data call-out function.
- *
- * Parameters mcl_handle -MCL handle
- * status - BTA_MA_STATUS_OK if operation is successful
- * BTA_MA_STATUS_FAIL if any errors have occurred.
- * evt - evt from the call-out function
- *
- * Returns void
- *
- ******************************************************************************/
-extern void bta_hl_ci_put_echo_data(tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_STATUS status, uint16_t evt) {
- tBTA_HL_CI_ECHO_DATA* p_evt =
- (tBTA_HL_CI_ECHO_DATA*)osi_malloc(sizeof(tBTA_HL_CI_ECHO_DATA));
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("%s mcl_handle=%d status=%d evt=%d\n", __func__, mcl_handle,
- status, evt);
-#endif
-
- p_evt->hdr.event = evt;
- p_evt->mcl_handle = mcl_handle;
- p_evt->status = status;
-
- bta_sys_sendmsg(p_evt);
-}
diff --git a/bta/hl/bta_hl_int.h b/bta/hl/bta_hl_int.h
deleted file mode 100644
index c6dce11..0000000
--- a/bta/hl/bta_hl_int.h
+++ /dev/null
@@ -1,856 +0,0 @@
-/******************************************************************************
- *
- * Copyright 1998-2012 Broadcom 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.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- * This is the private file for the message access equipment (MSE)
- * subsystem.
- *
- ******************************************************************************/
-#ifndef BTA_HL_INT_H
-#define BTA_HL_INT_H
-
-#include "bt_target.h"
-#include "bta_hl_api.h"
-#include "bta_hl_co.h"
-#include "bta_sys.h"
-#include "l2cdefs.h"
-
-typedef uint16_t(tBTA_HL_ALLOCATE_PSM)(void);
-
-/*****************************************************************************
- * Constants and data types
- ****************************************************************************/
-
-#ifndef BTA_HL_DISC_SIZE
-#define BTA_HL_DISC_SIZE 1600
-#endif
-#define BTA_HL_NUM_SRCH_ATTR 10
-#define BTA_HL_MIN_SDP_MDEP_LEN 7
-
-/* L2CAP defualt parameters */
-#define BTA_HL_L2C_TX_WIN_SIZE 10
-#define BTA_HL_L2C_MAX_TRANSMIT 32
-#define BTA_HL_L2C_RTRANS_TOUT 2000
-#define BTA_HL_L2C_MON_TOUT 12000
-#define BTA_HL_L2C_MPS 1017
-
-/* L2CAP FCS setting*/
-#define BTA_HL_MCA_USE_FCS MCA_FCS_USE
-#define BTA_HL_MCA_NO_FCS MCA_FCS_BYPASS
-#define BTA_HL_L2C_USE_FCS 1
-#define BTA_HL_L2C_NO_FCS 0
-#define BTA_HL_DEFAULT_SOURCE_FCS BTA_HL_L2C_USE_FCS
-#define BTA_HL_MCA_FCS_USE_MASK MCA_FCS_USE_MASK
-
-/* SDP Operations */
-#define BTA_HL_SDP_OP_NONE 0
-#define BTA_HL_SDP_OP_CCH_INIT 1
-#define BTA_HL_SDP_OP_DCH_OPEN_INIT 2
-#define BTA_HL_SDP_OP_DCH_RECONNECT_INIT 3
-#define BTA_HL_SDP_OP_SDP_QUERY_NEW 4
-#define BTA_HL_SDP_OP_SDP_QUERY_CURRENT 5
-
-typedef uint8_t tBTA_HL_SDP_OPER;
-
-/* CCH Operations */
-#define BTA_HL_CCH_OP_NONE 0
-#define BTA_HL_CCH_OP_LOCAL_OPEN 1
-#define BTA_HL_CCH_OP_REMOTE_OPEN 2
-#define BTA_HL_CCH_OP_LOCAL_CLOSE 3
-#define BTA_HL_CCH_OP_REMOTE_CLOSE 4
-
-typedef uint8_t tBTA_HL_CCH_OPER;
-
-/* Pending DCH close operations when closing a CCH */
-#define BTA_HL_CCH_CLOSE_OP_DCH_NONE 0
-#define BTA_HL_CCH_CLOSE_OP_DCH_ABORT 1
-#define BTA_HL_CCH_CLOSE_OP_DCH_CLOSE 2
-typedef uint8_t tBTA_HL_CCH_CLOSE_DCH_OPER;
-
-/* DCH Operations */
-#define BTA_HL_DCH_OP_NONE 0
-#define BTA_HL_DCH_OP_REMOTE_CREATE 1
-#define BTA_HL_DCH_OP_LOCAL_OPEN 2
-#define BTA_HL_DCH_OP_REMOTE_OPEN 3
-#define BTA_HL_DCH_OP_LOCAL_CLOSE 4
-#define BTA_HL_DCH_OP_REMOTE_CLOSE 5
-#define BTA_HL_DCH_OP_LOCAL_DELETE 6
-#define BTA_HL_DCH_OP_REMOTE_DELETE 7
-#define BTA_HL_DCH_OP_LOCAL_RECONNECT 8
-#define BTA_HL_DCH_OP_REMOTE_RECONNECT 9
-#define BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST 10
-#define BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT 11
-
-typedef uint8_t tBTA_HL_DCH_OPER;
-
-/* Echo test Operations */
-#define BTA_HL_ECHO_OP_NONE 0
-#define BTA_HL_ECHO_OP_CI_GET_ECHO_DATA 1
-#define BTA_HL_ECHO_OP_SDP_INIT 2
-#define BTA_HL_ECHO_OP_MDL_CREATE_CFM 3
-#define BTA_HL_ECHO_OP_DCH_OPEN_CFM 4
-#define BTA_HL_ECHO_OP_LOOP_BACK 5
-#define BTA_HL_ECHO_OP_CI_PUT_ECHO_DATA 6
-#define BTA_HL_ECHO_OP_DCH_CLOSE_CFM 7
-#define BTA_HL_ECHO_OP_OPEN_IND 8
-#define BTA_HL_ECHO_OP_ECHO_PKT 9
-
-typedef uint8_t tBTA_HL_ECHO_OPER;
-
-/* abort status mask for abort_oper */
-
-#define BTA_HL_ABORT_NONE_MASK 0x00
-#define BTA_HL_ABORT_PENDING_MASK 0x01
-#define BTA_HL_ABORT_LOCAL_MASK 0x10
-#define BTA_HL_ABORT_REMOTE_MASK 0x20
-#define BTA_HL_ABORT_CCH_CLOSE_MASK 0x40
-
-/* call out mask for cout_oper */
-#define BTA_HL_CO_NONE_MASK 0x00
-#define BTA_HL_CO_GET_TX_DATA_MASK 0x01
-#define BTA_HL_CO_PUT_RX_DATA_MASK 0x02
-#define BTA_HL_CO_GET_ECHO_DATA_MASK 0x04
-#define BTA_HL_CO_PUT_ECHO_DATA_MASK 0x08
-
-typedef struct {
- uint16_t mtu;
- uint8_t fcs; /* '0' No FCS, otherwise '1' */
-} tBTA_HL_L2CAP_CFG_INFO;
-
-/* State Machine Events */
-enum {
- /* these events are handled by the state machine */
- BTA_HL_CCH_OPEN_EVT = BTA_SYS_EVT_START(BTA_ID_HL),
- BTA_HL_CCH_SDP_OK_EVT,
- BTA_HL_CCH_SDP_FAIL_EVT,
- BTA_HL_MCA_CONNECT_IND_EVT,
- BTA_HL_MCA_DISCONNECT_IND_EVT,
- BTA_HL_CCH_CLOSE_EVT,
- BTA_HL_CCH_CLOSE_CMPL_EVT,
- BTA_HL_MCA_RSP_TOUT_IND_EVT,
- /* DCH EVENT */
- BTA_HL_DCH_SDP_INIT_EVT,
- BTA_HL_DCH_OPEN_EVT,
- BTA_HL_MCA_CREATE_IND_EVT,
- BTA_HL_MCA_CREATE_CFM_EVT,
- BTA_HL_MCA_OPEN_IND_EVT,
-
- BTA_HL_MCA_OPEN_CFM_EVT,
- BTA_HL_DCH_CLOSE_EVT,
- BTA_HL_MCA_CLOSE_IND_EVT,
- BTA_HL_MCA_CLOSE_CFM_EVT,
- BTA_HL_API_SEND_DATA_EVT,
-
- BTA_HL_MCA_RCV_DATA_EVT,
- BTA_HL_DCH_CLOSE_CMPL_EVT,
- BTA_HL_DCH_RECONNECT_EVT,
- BTA_HL_DCH_SDP_FAIL_EVT,
- BTA_HL_MCA_RECONNECT_IND_EVT,
-
- BTA_HL_MCA_RECONNECT_CFM_EVT,
- BTA_HL_DCH_CLOSE_ECHO_TEST_EVT,
- BTA_HL_API_DCH_CREATE_RSP_EVT,
- BTA_HL_DCH_ABORT_EVT,
- BTA_HL_MCA_ABORT_IND_EVT,
-
- BTA_HL_MCA_ABORT_CFM_EVT,
- BTA_HL_MCA_CONG_CHG_EVT,
- BTA_HL_CI_GET_TX_DATA_EVT,
- BTA_HL_CI_PUT_RX_DATA_EVT,
- BTA_HL_CI_GET_ECHO_DATA_EVT,
- BTA_HL_DCH_ECHO_TEST_EVT,
- BTA_HL_CI_PUT_ECHO_DATA_EVT,
-
- /* these events are handled outside the state machine */
- BTA_HL_API_ENABLE_EVT,
- BTA_HL_API_DISABLE_EVT,
- BTA_HL_API_UPDATE_EVT,
- BTA_HL_API_REGISTER_EVT,
- BTA_HL_API_DEREGISTER_EVT,
- BTA_HL_API_CCH_OPEN_EVT,
- BTA_HL_API_CCH_CLOSE_EVT,
- BTA_HL_API_DCH_OPEN_EVT,
- BTA_HL_API_DCH_RECONNECT_EVT,
- BTA_HL_API_DCH_CLOSE_EVT,
- BTA_HL_API_DELETE_MDL_EVT,
- BTA_HL_API_DCH_ABORT_EVT,
-
- BTA_HL_API_DCH_ECHO_TEST_EVT,
- BTA_HL_API_SDP_QUERY_EVT,
- BTA_HL_SDP_QUERY_OK_EVT,
- BTA_HL_SDP_QUERY_FAIL_EVT,
- BTA_HL_MCA_DELETE_IND_EVT,
- BTA_HL_MCA_DELETE_CFM_EVT
-};
-typedef uint16_t tBTA_HL_INT_EVT;
-
-#define BTA_HL_DCH_EVT_MIN BTA_HL_DCH_SDP_INIT_EVT
-#define BTA_HL_DCH_EVT_MAX 0xFFFF
-
-/* state machine states */
-enum {
- BTA_HL_CCH_IDLE_ST = 0, /* Idle */
- BTA_HL_CCH_OPENING_ST, /* Opening a connection*/
- BTA_HL_CCH_OPEN_ST, /* Connection is open */
- BTA_HL_CCH_CLOSING_ST /* Closing is in progress */
-};
-typedef uint8_t tBTA_HL_CCH_STATE;
-
-enum {
- BTA_HL_DCH_IDLE_ST = 0, /* Idle */
- BTA_HL_DCH_OPENING_ST, /* Opening a connection*/
- BTA_HL_DCH_OPEN_ST, /* Connection is open */
- BTA_HL_DCH_CLOSING_ST /* Closing is in progress */
-};
-typedef uint8_t tBTA_HL_DCH_STATE;
-
-typedef struct {
- BT_HDR hdr;
- tBTA_HL_CTRL_CBACK* p_cback; /* pointer to control callback function */
-} tBTA_HL_API_ENABLE;
-
-typedef struct {
- BT_HDR hdr;
- uint8_t app_id;
- bool is_register; /* Update HL application due to register or deregister */
- tBTA_HL_CBACK* p_cback; /* pointer to application callback function */
- tBTA_HL_DEVICE_TYPE dev_type; /* sink, source or dual roles */
- tBTA_SEC sec_mask; /* security mask for accepting conenction*/
- char srv_name[BTA_SERVICE_NAME_LEN +
- 1]; /* service name to be used in the SDP; null terminated*/
- char srv_desp[BTA_SERVICE_DESP_LEN + 1]; /* service description to be used in
- the SDP; null terminated */
- char provider_name[BTA_PROVIDER_NAME_LEN + 1]; /* provide name to be used in
- the SDP; null terminated */
-
-} tBTA_HL_API_UPDATE;
-
-typedef struct {
- BT_HDR hdr;
- uint8_t app_id;
- tBTA_HL_CBACK* p_cback; /* pointer to application callback function */
- tBTA_HL_DEVICE_TYPE dev_type; /* sink, source or dual roles */
- tBTA_SEC sec_mask; /* security mask for accepting conenction*/
- char srv_name[BTA_SERVICE_NAME_LEN +
- 1]; /* service name to be used in the SDP; null terminated*/
- char srv_desp[BTA_SERVICE_DESP_LEN + 1]; /* service description to be used in
- the SDP; null terminated */
- char provider_name[BTA_PROVIDER_NAME_LEN + 1]; /* provide name to be used in
- the SDP; null terminated */
-} tBTA_HL_API_REGISTER;
-
-typedef struct {
- BT_HDR hdr;
- uint8_t app_id;
- tBTA_HL_CBACK* p_cback; /* pointer to application callback function */
- tBTA_HL_APP_HANDLE app_handle;
-} tBTA_HL_API_DEREGISTER;
-
-typedef struct {
- BT_HDR hdr;
- uint8_t app_id;
- tBTA_HL_APP_HANDLE app_handle;
- uint16_t ctrl_psm;
- RawAddress bd_addr; /* Address of peer device */
- tBTA_SEC sec_mask; /* security mask for initiating connection*/
-} tBTA_HL_API_CCH_OPEN;
-
-typedef struct {
- BT_HDR hdr;
- tBTA_HL_MCL_HANDLE mcl_handle;
-} tBTA_HL_API_CCH_CLOSE;
-
-typedef struct {
- BT_HDR hdr;
- tBTA_HL_MCL_HANDLE mcl_handle;
- uint16_t ctrl_psm;
- tBTA_HL_MDEP_ID local_mdep_id; /* local MDEP ID */
- tBTA_HL_MDEP_ID peer_mdep_id; /* peer mdep id */
- tBTA_HL_DCH_CFG local_cfg;
- tBTA_SEC sec_mask; /* security mask for initiating connection*/
-} tBTA_HL_API_DCH_OPEN;
-
-typedef struct {
- BT_HDR hdr;
-
- tBTA_HL_MCL_HANDLE mcl_handle;
- uint16_t ctrl_psm;
- tBTA_HL_MDL_ID mdl_id;
-} tBTA_HL_API_DCH_RECONNECT;
-
-typedef struct {
- BT_HDR hdr;
- tBTA_HL_MDL_HANDLE mdl_handle;
-} tBTA_HL_API_DCH_CLOSE;
-
-typedef struct {
- BT_HDR hdr;
- tBTA_HL_MCL_HANDLE mcl_handle;
- tBTA_HL_MDL_ID mdl_id;
-} tBTA_HL_API_DELETE_MDL;
-
-typedef struct {
- BT_HDR hdr;
- tBTA_HL_MCL_HANDLE mcl_handle;
-} tBTA_HL_API_DCH_ABORT;
-
-typedef struct {
- BT_HDR hdr;
- tBTA_HL_MDL_HANDLE mdl_handle;
- uint16_t pkt_size;
-} tBTA_HL_API_SEND_DATA;
-
-typedef struct {
- BT_HDR hdr;
- tBTA_HL_MCL_HANDLE mcl_handle;
- uint16_t ctrl_psm;
- uint16_t pkt_size;
- tBTA_HL_DCH_CFG local_cfg;
-} tBTA_HL_API_DCH_ECHO_TEST;
-
-typedef struct {
- BT_HDR hdr;
- uint8_t app_idx;
- uint8_t mcl_idx;
- bool release_mcl_cb;
-} tBTA_HL_CCH_SDP;
-
-/* MCA callback event parameters. */
-typedef struct {
- BT_HDR hdr;
- tBTA_HL_APP_HANDLE app_handle;
- tBTA_HL_MCL_HANDLE mcl_handle;
- tMCA_CTRL mca_data;
-} tBTA_HL_MCA_EVT;
-
-/* MCA callback event parameters. */
-typedef struct {
- BT_HDR hdr;
- uint8_t app_idx;
- uint8_t mcl_idx;
- uint8_t mdl_idx;
- BT_HDR* p_pkt;
-} tBTA_HL_MCA_RCV_DATA_EVT;
-
-typedef struct {
- BT_HDR hdr;
- uint8_t app_idx;
- uint8_t mcl_idx;
- uint8_t mdl_idx;
-} tBTA_HL_DCH_SDP;
-
-typedef struct {
- BT_HDR hdr;
- tBTA_HL_APP_HANDLE app_handle;
- uint8_t app_id;
- RawAddress bd_addr; /* Address of peer device */
-} tBTA_HL_API_SDP_QUERY;
-
-typedef struct {
- BT_HDR hdr;
- tBTA_HL_MCL_HANDLE mcl_handle;
- tBTA_HL_MDL_ID mdl_id;
- tBTA_HL_MDEP_ID local_mdep_id;
- tBTA_HL_DCH_CREATE_RSP rsp_code;
- tBTA_HL_DCH_CFG cfg_rsp;
-} tBTA_HL_API_DCH_CREATE_RSP;
-
-typedef struct {
- BT_HDR hdr;
- tBTA_HL_MDL_HANDLE mdl_handle;
- tBTA_HL_STATUS status;
-} tBTA_HL_CI_GET_PUT_DATA;
-
-typedef struct {
- BT_HDR hdr;
- tBTA_HL_MCL_HANDLE mcl_handle;
- tBTA_HL_STATUS status;
-} tBTA_HL_CI_ECHO_DATA;
-
-/* union of all state machine event data types */
-typedef union {
- BT_HDR hdr;
- tBTA_HL_API_ENABLE api_enable; /* data for BTA_MSE_API_ENABLE_EVT */
- tBTA_HL_API_UPDATE api_update;
- tBTA_HL_API_REGISTER api_reg;
- tBTA_HL_API_DEREGISTER api_dereg;
- tBTA_HL_API_CCH_OPEN api_cch_open;
- tBTA_HL_API_CCH_CLOSE api_cch_close;
- tBTA_HL_API_DCH_CREATE_RSP api_dch_create_rsp;
- tBTA_HL_API_DCH_OPEN api_dch_open;
- tBTA_HL_API_DCH_RECONNECT api_dch_reconnect;
- tBTA_HL_API_DCH_CLOSE api_dch_close;
- tBTA_HL_API_DELETE_MDL api_delete_mdl;
- tBTA_HL_API_DCH_ABORT api_dch_abort;
- tBTA_HL_API_SEND_DATA api_send_data;
- tBTA_HL_API_DCH_ECHO_TEST api_dch_echo_test;
- tBTA_HL_API_SDP_QUERY api_sdp_query;
-
- tBTA_HL_CCH_SDP cch_sdp;
- tBTA_HL_MCA_EVT mca_evt;
- tBTA_HL_MCA_RCV_DATA_EVT mca_rcv_data_evt;
- tBTA_HL_DCH_SDP dch_sdp; /* for DCH_OPEN_EVT and DCH_RECONNECT_EVT */
- tBTA_HL_CI_GET_PUT_DATA ci_get_put_data;
- tBTA_HL_CI_ECHO_DATA ci_get_put_echo_data;
-} tBTA_HL_DATA;
-
-typedef struct {
- bool in_use;
- uint16_t mdl_id;
- tBTA_HL_MDL_HANDLE mdl_handle;
- tBTA_HL_DCH_OPER dch_oper;
- bool intentional_close;
- tBTA_HL_DCH_STATE dch_state;
- uint8_t abort_oper;
- uint16_t req_data_psm;
- uint16_t max_rx_apdu_size;
- uint16_t max_tx_apdu_size;
- BT_HDR* p_tx_pkt;
- BT_HDR* p_rx_pkt;
- tBTA_HL_MDEP_ID local_mdep_id;
- uint8_t local_mdep_cfg_idx;
- tBTA_HL_DCH_CFG local_cfg;
- tBTA_HL_DCH_CFG remote_cfg;
- tBTA_HL_MDEP_ID peer_mdep_id;
- uint16_t peer_data_type;
- tBTA_HL_MDEP_ROLE peer_mdep_role;
- tBTA_HL_DCH_MODE dch_mode;
- tBTA_SEC sec_mask;
- bool is_the_first_reliable;
- bool delete_mdl;
- uint16_t mtu;
- tMCA_CHNL_CFG chnl_cfg;
- bool mdl_cfg_idx_included;
- uint8_t mdl_cfg_idx;
- uint8_t echo_oper;
- bool cong;
- bool close_pending;
- uint8_t cout_oper;
- BT_HDR* p_echo_tx_pkt;
- BT_HDR* p_echo_rx_pkt;
- tBTA_HL_STATUS ci_put_echo_data_status;
-} tBTA_HL_MDL_CB;
-
-typedef struct {
- tBTA_HL_MDL_CB mdl[BTA_HL_NUM_MDLS_PER_MCL];
- tBTA_HL_DELETE_MDL delete_mdl;
- bool in_use;
- tBTA_HL_CCH_STATE cch_state;
- uint16_t req_ctrl_psm;
- uint16_t ctrl_psm;
- uint16_t data_psm;
- RawAddress bd_addr;
- uint16_t cch_mtu;
- uint16_t sec_mask;
- tBTA_HL_MCL_HANDLE mcl_handle;
- tSDP_DISCOVERY_DB* p_db; /* pointer to discovery database */
- tSDP_DISC_CMPL_CB* sdp_cback;
- tBTA_HL_SDP_OPER sdp_oper;
- bool close_pending;
- uint8_t sdp_mdl_idx;
- tBTA_HL_SDP sdp;
- uint8_t cch_oper;
- uint8_t force_close_local_cch_opening;
- bool intentional_close;
- bool rsp_tout;
- uint8_t timer_oper;
- bool echo_test;
- uint8_t echo_mdl_idx;
- uint8_t cch_close_dch_oper;
- uint8_t app_id;
-} tBTA_HL_MCL_CB;
-
-typedef struct {
- tBTA_HL_MCL_CB mcb[BTA_HL_NUM_MCLS]; /* application Control Blocks */
- tBTA_HL_CBACK* p_cback; /* pointer to control callback function */
- bool in_use; /* this CB is in use*/
- bool deregistering;
- uint8_t app_id;
- uint32_t sdp_handle; /* SDP record handle */
- tBTA_HL_SUP_FEATURE sup_feature;
- tBTA_HL_MDL_CFG mdl_cfg[BTA_HL_NUM_MDL_CFGS];
- tBTA_HL_DEVICE_TYPE dev_type;
- tBTA_HL_APP_HANDLE app_handle;
- uint16_t ctrl_psm; /* L2CAP PSM for the MCAP control channel */
- uint16_t data_psm; /* L2CAP PSM for the MCAP data channel */
- uint16_t sec_mask; /* Security mask for BTM_SetSecurityLevel() */
-
- char srv_name[BTA_SERVICE_NAME_LEN +
- 1]; /* service name to be used in the SDP; null terminated*/
- char srv_desp[BTA_SERVICE_DESP_LEN + 1]; /* service description to be used in
- the SDP; null terminated */
- char provider_name[BTA_PROVIDER_NAME_LEN + 1]; /* provide name to be used in
- the SDP; null terminated */
-
- tMCA_CTRL_CBACK* p_mcap_cback; /* pointer to MCAP callback function */
- tMCA_DATA_CBACK* p_data_cback;
-} tBTA_HL_APP_CB;
-
-typedef struct {
- bool in_use;
- tBTA_HL_SDP_OPER sdp_oper;
- uint8_t app_idx;
- uint8_t mcl_idx;
- uint8_t mdl_idx;
-} tBTA_HL_SDP_CB;
-
-typedef struct {
- bool in_use;
- uint8_t app_idx;
- uint8_t mcl_idx;
-} tBTA_HL_TIMER_CB;
-
-typedef struct {
- tBTA_HL_APP_CB acb[BTA_HL_NUM_APPS]; /* HL Control Blocks */
- tBTA_HL_CTRL_CBACK* p_ctrl_cback; /* pointer to control callback function */
- bool enable;
- bool disabling;
-
- tBTA_HL_SDP_CB scb[BTA_HL_NUM_SDP_CBACKS];
- tBTA_HL_TIMER_CB tcb[BTA_HL_NUM_TIMERS];
- bool enable_random_psm;
- tBTA_HL_ALLOCATE_PSM* p_alloc_psm;
-} tBTA_HL_CB;
-
-/******************************************************************************
- * Configuration Definitions
- ******************************************************************************/
-/* Configuration structure */
-
-/*****************************************************************************
- * Global data
- ****************************************************************************/
-
-/* HL control block */
-extern tBTA_HL_CB bta_hl_cb;
-
-#define BTA_HL_GET_CB_PTR() &(bta_hl_cb)
-#define BTA_HL_GET_APP_CB_PTR(app_idx) &(bta_hl_cb.acb[(app_idx)])
-#define BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx) \
- &(bta_hl_cb.acb[(app_idx)].mcb[(mcl_idx)])
-#define BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx) \
- &(bta_hl_cb.acb[(app_idx)].mcb[(mcl_idx)].mdl[(mdl_idx)])
-#define BTA_HL_GET_MDL_CFG_PTR(app_idx, item_idx) \
- &(bta_hl_cb.acb[(app_idx)].mdl_cfg[(item_idx)])
-#define BTA_HL_GET_ECHO_CFG_PTR(app_idx) \
- &(bta_hl_cb.acb[(app_idx)].sup_feature.echo_cfg)
-#define BTA_HL_GET_MDEP_CFG_PTR(app_idx, mdep_cfg_idx) \
- &(bta_hl_cb.acb[(app_idx)].sup_feature.mdep[(mdep_cfg_idx)].mdep_cfg)
-#define BTA_HL_GET_DATA_CFG_PTR(app_idx, mdep_cfg_idx, data_cfg_idx) \
- &(bta_hl_cb.acb[(app_idx)] \
- .sup_feature.mdep[(mdep_cfg_idx)] \
- .mdep_cfg.data_cfg[(data_cfg_idx)])
-#define BTA_HL_GET_BUF_PTR(p_pkt) \
- ((uint8_t*)((uint8_t*)((p_pkt) + 1) + (p_pkt)->offset))
-
-/*****************************************************************************
- * Function prototypes
- ****************************************************************************/
-/* main */
-extern bool bta_hl_hdl_event(BT_HDR* p_msg);
-/* sdp */
-extern bool bta_hl_fill_sup_feature_list(const tSDP_DISC_ATTR* p_attr,
- tBTA_HL_SUP_FEATURE_LIST_ELEM* p_list);
-extern tBTA_HL_STATUS bta_hl_sdp_update(uint8_t app_id);
-extern tBTA_HL_STATUS bta_hl_sdp_register(uint8_t app_idx);
-extern tSDP_DISC_REC* bta_hl_find_sink_or_src_srv_class_in_db(
- const tSDP_DISCOVERY_DB* p_db, const tSDP_DISC_REC* p_start_rec);
-
-/* action routines */
-extern void bta_hl_dch_ci_get_tx_data(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-extern void bta_hl_dch_ci_put_rx_data(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-extern void bta_hl_dch_ci_get_echo_data(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-
-extern void bta_hl_dch_echo_test(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-extern void bta_hl_dch_ci_put_echo_data(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-extern void bta_hl_dch_send_data(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-extern void bta_hl_dch_sdp_fail(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-extern void bta_hl_dch_mca_cong_change(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-extern void bta_hl_dch_mca_reconnect_ind(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-extern void bta_hl_dch_mca_reconnect_cfm(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-extern void bta_hl_dch_mca_reconnect(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-extern void bta_hl_dch_sdp_init(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-extern void bta_hl_dch_close_echo_test(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-extern void bta_hl_dch_create_rsp(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-extern void bta_hl_dch_mca_rcv_data(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-extern void bta_hl_dch_close_cmpl(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-extern void bta_hl_dch_mca_close_cfm(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-extern void bta_hl_dch_mca_close_ind(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-extern void bta_hl_dch_mca_close(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-extern void bta_hl_dch_mca_delete_ind(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-
-extern void bta_hl_dch_mca_delete_cfm(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-extern void bta_hl_dch_mca_delete(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-extern void bta_hl_dch_mca_abort_ind(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-extern void bta_hl_dch_mca_abort_cfm(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-extern void bta_hl_dch_mca_abort(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-extern void bta_hl_dch_mca_open_ind(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-extern void bta_hl_dch_mca_open_cfm(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-extern void bta_hl_dch_mca_create_ind(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-extern void bta_hl_dch_mca_create_cfm(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-extern void bta_hl_dch_mca_create(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-extern void bta_hl_deallocate_spd_cback(uint8_t sdp_cback_idx);
-extern tSDP_DISC_CMPL_CB* bta_hl_allocate_spd_cback(tBTA_HL_SDP_OPER sdp_oper,
- uint8_t app_idx,
- uint8_t mcl_idx,
- uint8_t mdl_idx,
- uint8_t* p_sdp_cback_idx);
-extern tBTA_HL_STATUS bta_hl_init_sdp(tBTA_HL_SDP_OPER sdp_oper,
- uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx);
-extern void bta_hl_cch_sdp_init(uint8_t app_idx, uint8_t mcl_idx,
- tBTA_HL_DATA* p_data);
-extern void bta_hl_cch_mca_open(uint8_t app_idx, uint8_t mcl_idx,
- tBTA_HL_DATA* p_data);
-extern void bta_hl_cch_mca_close(uint8_t app_idx, uint8_t mcl_idx,
- tBTA_HL_DATA* p_data);
-extern void bta_hl_cch_close_cmpl(uint8_t app_idx, uint8_t mcl_idx,
- tBTA_HL_DATA* p_data);
-extern void bta_hl_cch_mca_disconnect(uint8_t app_idx, uint8_t mcl_idx,
- tBTA_HL_DATA* p_data);
-extern void bta_hl_cch_mca_disc_open(uint8_t app_idx, uint8_t mcl_idx,
- tBTA_HL_DATA* p_data);
-extern void bta_hl_cch_mca_rsp_tout(uint8_t app_idx, uint8_t mcl_idx,
- tBTA_HL_DATA* p_data);
-extern void bta_hl_cch_mca_connect(uint8_t app_idx, uint8_t mcl_idx,
- tBTA_HL_DATA* p_data);
-
-/* State machine drivers */
-extern void bta_hl_cch_sm_execute(uint8_t inst_idx, uint8_t mcl_idx,
- uint16_t event, tBTA_HL_DATA* p_data);
-extern void bta_hl_dch_sm_execute(uint8_t inst_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, uint16_t event,
- tBTA_HL_DATA* p_data);
-/* MCAP callback functions */
-extern void bta_hl_mcap_ctrl_cback(tMCA_HANDLE handle, tMCA_CL mcl,
- uint8_t event, tMCA_CTRL* p_data);
-
-extern void bta_hl_mcap_data_cback(tMCA_DL mdl, BT_HDR* p_pkt);
-
-/* utility functions */
-extern bool bta_hl_set_ctrl_psm_for_dch(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, uint16_t ctrl_psm);
-extern bool bta_hl_find_sdp_idx_using_ctrl_psm(tBTA_HL_SDP* p_sdp,
- uint16_t ctrl_psm,
- uint8_t* p_sdp_idx);
-extern uint16_t bta_hl_set_user_tx_buf_size(uint16_t max_tx_size);
-extern uint16_t bta_hl_set_user_rx_buf_size(uint16_t mtu);
-extern uint8_t bta_hl_set_tx_win_size(uint16_t mtu, uint16_t mps);
-extern uint16_t bta_hl_set_mps(uint16_t mtu);
-extern void bta_hl_clean_mdl_cb(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx);
-extern BT_HDR* bta_hl_get_buf(uint16_t data_size, bool fcs_use);
-extern bool bta_hl_find_service_in_db(uint8_t app_idx, uint8_t mcl_idx,
- uint16_t service_uuid,
- tSDP_DISC_REC** pp_rec);
-extern uint16_t bta_hl_get_service_uuids(uint8_t sdp_oper, uint8_t app_idx,
- uint8_t mcl_idx, uint8_t mdl_idx);
-extern bool bta_hl_find_echo_cfg_rsp(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdep_idx, uint8_t cfg,
- uint8_t* p_cfg_rsp);
-extern bool bta_hl_validate_cfg(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, uint8_t cfg);
-extern bool bta_hl_find_cch_cb_indexes(tBTA_HL_DATA* p_msg, uint8_t* p_app_idx,
- uint8_t* p_mcl_idx);
-extern bool bta_hl_find_dch_cb_indexes(tBTA_HL_DATA* p_msg, uint8_t* p_app_idx,
- uint8_t* p_mcl_idx, uint8_t* p_mdl_idx);
-extern uint16_t bta_hl_allocate_mdl_id(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx);
-extern bool bta_hl_find_mdl_idx_using_handle(tBTA_HL_MDL_HANDLE mdl_handle,
- uint8_t* p_app_idx,
- uint8_t* p_mcl_idx,
- uint8_t* p_mdl_idx);
-extern bool bta_hl_find_mdl_idx(uint8_t app_idx, uint8_t mcl_idx,
- uint16_t mdl_id, uint8_t* p_mdl_idx);
-extern bool bta_hl_find_an_active_mdl_idx(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t* p_mdl_idx);
-extern bool bta_hl_find_dch_setup_mdl_idx(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t* p_mdl_idx);
-extern bool bta_hl_find_an_in_use_mcl_idx(uint8_t app_idx, uint8_t* p_mcl_idx);
-extern bool bta_hl_find_an_in_use_app_idx(uint8_t* p_app_idx);
-extern bool bta_hl_find_app_idx(uint8_t app_id, uint8_t* p_app_idx);
-extern bool bta_hl_find_app_idx_using_handle(tBTA_HL_APP_HANDLE app_handle,
- uint8_t* p_app_idx);
-extern bool bta_hl_find_mcl_idx_using_handle(tBTA_HL_MCL_HANDLE mcl_handle,
- uint8_t* p_app_idx,
- uint8_t* p_mcl_idx);
-extern bool bta_hl_find_mcl_idx(uint8_t app_idx, const RawAddress& p_bd_addr,
- uint8_t* p_mcl_idx);
-extern bool bta_hl_is_the_first_reliable_existed(uint8_t app_idx,
- uint8_t mcl_idx);
-extern bool bta_hl_find_non_active_mdl_cfg(uint8_t app_idx,
- uint8_t start_mdl_cfg_idx,
- uint8_t* p_mdl_cfg_idx);
-extern bool bta_hl_find_avail_mdl_cfg_idx(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t* p_mdl_cfg_idx);
-extern bool bta_hl_find_mdl_cfg_idx(uint8_t app_idx, uint8_t mcl_idx,
- tBTA_HL_MDL_ID mdl_id,
- uint8_t* p_mdl_cfg_idx);
-extern bool bta_hl_get_cur_time(uint8_t app_idx, uint8_t* p_cur_time);
-extern void bta_hl_sort_cfg_time_idx(uint8_t app_idx, uint8_t* a, uint8_t n);
-extern void bta_hl_compact_mdl_cfg_time(uint8_t app_idx, uint8_t mdep_id);
-extern bool bta_hl_is_mdl_exsit_in_mcl(uint8_t app_idx,
- const RawAddress& bd_addr,
- tBTA_HL_MDL_ID mdl_id);
-extern bool bta_hl_delete_mdl_cfg(uint8_t app_idx, const RawAddress& bd_addr,
- tBTA_HL_MDL_ID mdl_id);
-extern bool bta_hl_is_mdl_value_valid(tBTA_HL_MDL_ID mdl_id);
-extern bool bta_hl_find_mdep_cfg_idx(uint8_t app_idx,
- tBTA_HL_MDEP_ID local_mdep_id,
- uint8_t* p_mdep_cfg_idx);
-extern void bta_hl_find_rxtx_apdu_size(uint8_t app_idx, uint8_t mdep_cfg_idx,
- uint16_t* p_rx_apu_size,
- uint16_t* p_tx_apu_size);
-extern bool bta_hl_validate_peer_cfg(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx,
- tBTA_HL_MDEP_ID peer_mdep_id,
- tBTA_HL_MDEP_ROLE peer_mdep_role,
- uint8_t sdp_idx);
-extern tBTA_HL_STATUS bta_hl_chk_local_cfg(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdep_cfg_idx,
- tBTA_HL_DCH_CFG local_cfg);
-
-extern bool bta_hl_validate_reconnect_params(
- uint8_t app_idx, uint8_t mcl_idx, tBTA_HL_API_DCH_RECONNECT* p_reconnect,
- uint8_t* p_mdep_cfg_idx, uint8_t* p_mdl_cfg_idx);
-extern bool bta_hl_find_avail_mcl_idx(uint8_t app_idx, uint8_t* p_mcl_idx);
-extern bool bta_hl_find_avail_mdl_idx(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t* p_mdl_idx);
-extern bool bta_hl_is_a_duplicate_id(uint8_t app_id);
-extern bool bta_hl_find_avail_app_idx(uint8_t* p_idx);
-extern tBTA_HL_STATUS bta_hl_app_update(uint8_t app_id, bool is_register);
-extern tBTA_HL_STATUS bta_hl_app_registration(uint8_t app_idx);
-extern void bta_hl_discard_data(uint16_t event, tBTA_HL_DATA* p_data);
-extern void bta_hl_save_mdl_cfg(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx);
-extern void bta_hl_set_dch_chan_cfg(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx, tBTA_HL_DATA* p_data);
-extern bool bta_hl_get_l2cap_cfg(tBTA_HL_MDL_HANDLE mdl_hnd,
- tBTA_HL_L2CAP_CFG_INFO* p_cfg);
-extern bool bta_hl_validate_chan_cfg(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx);
-extern bool bta_hl_is_cong_on(uint8_t app_id, const RawAddress& bd_addr,
- tBTA_HL_MDL_ID mdl_id);
-extern void bta_hl_check_cch_close(uint8_t app_idx, uint8_t mcl_idx,
- tBTA_HL_DATA* p_data, bool check_dch_setup);
-extern void bta_hl_clean_app(uint8_t app_idx);
-extern void bta_hl_check_deregistration(uint8_t app_idx, tBTA_HL_DATA* p_data);
-extern void bta_hl_check_disable(tBTA_HL_DATA* p_data);
-extern void bta_hl_build_abort_ind(tBTA_HL* p_evt_data,
- tBTA_HL_APP_HANDLE app_handle,
- tBTA_HL_MCL_HANDLE mcl_handle);
-extern void bta_hl_build_abort_cfm(tBTA_HL* p_evt_data,
- tBTA_HL_APP_HANDLE app_handle,
- tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_STATUS status);
-extern void bta_hl_build_dch_close_cfm(tBTA_HL* p_evt_data,
- tBTA_HL_APP_HANDLE app_handle,
- tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_MDL_HANDLE mdl_handle,
- tBTA_HL_STATUS status);
-extern void bta_hl_build_dch_close_ind(tBTA_HL* p_evt_data,
- tBTA_HL_APP_HANDLE app_handle,
- tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_MDL_HANDLE mdl_handle,
- bool intentional);
-extern void bta_hl_build_send_data_cfm(tBTA_HL* p_evt_data,
- tBTA_HL_APP_HANDLE app_handle,
- tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_MDL_HANDLE mdl_handle,
- tBTA_HL_STATUS status);
-extern void bta_hl_build_rcv_data_ind(tBTA_HL* p_evt_data,
- tBTA_HL_APP_HANDLE app_handle,
- tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_MDL_HANDLE mdl_handle);
-extern void bta_hl_build_cch_open_cfm(tBTA_HL* p_evt_data, uint8_t app_id,
- tBTA_HL_APP_HANDLE app_handle,
- tBTA_HL_MCL_HANDLE mcl_handle,
- const RawAddress& bd_addr,
- tBTA_HL_STATUS status);
-extern void bta_hl_build_cch_open_ind(tBTA_HL* p_evt_data,
- tBTA_HL_APP_HANDLE app_handle,
- tBTA_HL_MCL_HANDLE mcl_handle,
- const RawAddress& bd_addr);
-extern void bta_hl_build_cch_close_cfm(tBTA_HL* p_evt_data,
- tBTA_HL_APP_HANDLE app_handle,
- tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_STATUS status);
-extern void bta_hl_build_cch_close_ind(tBTA_HL* p_evt_data,
- tBTA_HL_APP_HANDLE app_handle,
- tBTA_HL_MCL_HANDLE mcl_handle,
- bool intentional);
-
-extern void bta_hl_build_dch_open_cfm(
- tBTA_HL* p_evt_data, tBTA_HL_APP_HANDLE app_handle,
- tBTA_HL_MCL_HANDLE mcl_handle, tBTA_HL_MDL_HANDLE mdl_handle,
- tBTA_HL_MDEP_ID local_mdep_id, tBTA_HL_MDL_ID mdl_id,
- tBTA_HL_DCH_MODE dch_mode, bool first_reliable, uint16_t mtu,
- tBTA_HL_STATUS status);
-
-extern void bta_hl_build_delete_mdl_cfm(tBTA_HL* p_evt_data,
- tBTA_HL_APP_HANDLE app_handle,
- tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_MDL_ID mdl_id,
- tBTA_HL_STATUS status);
-extern void bta_hl_build_echo_test_cfm(tBTA_HL* p_evt_data,
- tBTA_HL_APP_HANDLE app_handle,
- tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_STATUS status);
-extern void bta_hl_build_sdp_query_cfm(tBTA_HL* p_evt_data, uint8_t app_id,
- tBTA_HL_APP_HANDLE app_handle,
- const RawAddress& bd_addr,
- tBTA_HL_SDP* p_sdp,
- tBTA_HL_STATUS status);
-
-#if (BTA_HL_DEBUG == TRUE)
-extern const char* bta_hl_status_code(tBTA_HL_STATUS status);
-extern const char* bta_hl_evt_code(tBTA_HL_INT_EVT evt_code);
-#endif
-
-#endif /* BTA_MSE_INT_H */
diff --git a/bta/hl/bta_hl_main.cc b/bta/hl/bta_hl_main.cc
index c224a76..597c5d3 100644
--- a/bta/hl/bta_hl_main.cc
+++ b/bta/hl/bta_hl_main.cc
@@ -678,11 +678,11 @@
p_acb->sec_mask = p_data->api_reg.sec_mask;
p_acb->dev_type = p_data->api_reg.dev_type;
strlcpy(p_acb->srv_name, p_data->api_reg.srv_name,
- BTA_SERVICE_NAME_LEN);
+ sizeof(p_acb->srv_name));
strlcpy(p_acb->srv_desp, p_data->api_reg.srv_desp,
- BTA_SERVICE_DESP_LEN);
+ sizeof(p_acb->srv_desp));
strlcpy(p_acb->provider_name, p_data->api_reg.provider_name,
- BTA_PROVIDER_NAME_LEN);
+ sizeof(p_acb->provider_name));
bta_hl_cb.p_alloc_psm = L2CA_AllocatePSM;
p_acb->ctrl_psm = bta_hl_cb.p_alloc_psm();
p_acb->data_psm = bta_hl_cb.p_alloc_psm();
diff --git a/bta/hl/bta_hl_sdp.cc b/bta/hl/bta_hl_sdp.cc
deleted file mode 100644
index 0a357f0..0000000
--- a/bta/hl/bta_hl_sdp.cc
+++ /dev/null
@@ -1,572 +0,0 @@
-/******************************************************************************
- *
- * Copyright 1998-2012 Broadcom 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.
- *
- ******************************************************************************/
-
-#include <string.h>
-
-#include "bt_target.h"
-#if (HL_INCLUDED == TRUE)
-
-#include "bta_hl_int.h"
-#include "osi/include/osi.h"
-#include "sdp_api.h"
-#include "utl.h"
-
-/*******************************************************************************
- *
- * Function bta_hl_fill_sup_feature_list
- *
- * Description Fill the supported features from teh SDP record
- *
- * Returns true if found, false if not
- * If found, the passed protocol list element is filled in.
- *
- ******************************************************************************/
-bool bta_hl_fill_sup_feature_list(const tSDP_DISC_ATTR* p_attr,
- tBTA_HL_SUP_FEATURE_LIST_ELEM* p_list) {
- tSDP_DISC_ATTR* p_sattr;
- uint8_t item_cnt;
- uint8_t list_cnt = 0;
- bool status = true;
-
- for (p_attr = p_attr->attr_value.v.p_sub_attr; p_attr;
- p_attr = p_attr->p_next_attr) {
- /* mdep sequence */
- if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE) {
- return (false);
- }
-
- 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 each mdep list */
-
- p_list->list_elem[list_cnt].p_mdep_desp = NULL;
- switch (item_cnt) {
- case 0:
- p_list->list_elem[list_cnt].mdep_id = p_sattr->attr_value.v.u8;
- break;
- case 1:
- p_list->list_elem[list_cnt].data_type = p_sattr->attr_value.v.u16;
- break;
- case 2:
- p_list->list_elem[list_cnt].mdep_role =
- (tBTA_HL_MDEP_ROLE)p_sattr->attr_value.v.u8;
- break;
- case 3:
- p_list->list_elem[list_cnt].p_mdep_desp =
- (char*)p_sattr->attr_value.v.array;
- break;
- }
-
- item_cnt++;
- }
- list_cnt++;
- }
- p_list->num_elems = list_cnt;
- return (status);
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_compose_supported_feature_list
- *
- * Description This function is called to compose a data sequence from
- * the supported feature element list struct pointer
- *
- * Returns the length of the data sequence
- *
- ******************************************************************************/
-int bta_hl_compose_supported_feature_list(
- uint8_t* p, uint16_t num_elem,
- const tBTA_HL_SUP_FEATURE_ELEM* p_elem_list) {
- uint16_t xx, str_len, seq_len;
- uint8_t* p_head = p;
-
- for (xx = 0; xx < num_elem; xx++, p_elem_list++) {
- UINT8_TO_BE_STREAM(p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
- seq_len = 7;
- str_len = 0;
- if (p_elem_list->p_mdep_desp) {
- str_len = strlen(p_elem_list->p_mdep_desp) + 1;
- seq_len += str_len + 2; /* todo add a # symbol for 2 */
- }
-
- *p++ = (uint8_t)seq_len;
-
- UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE);
- UINT8_TO_BE_STREAM(p, p_elem_list->mdep_id);
- UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
- UINT16_TO_BE_STREAM(p, p_elem_list->data_type);
- UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE);
- UINT8_TO_BE_STREAM(p, p_elem_list->mdep_role);
-
- if (str_len) {
- UINT8_TO_BE_STREAM(p, (TEXT_STR_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
- UINT8_TO_BE_STREAM(p, str_len);
- ARRAY_TO_BE_STREAM(p, p_elem_list->p_mdep_desp, str_len);
- }
- }
-
- return (p - p_head);
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_add_sup_feature_list
- *
- * Description This function is called to add a protocol descriptor list to
- * a record. This would be through the SDP database maintenance
- * API. If the protocol list already exists in the record, it
- * is replaced with the new list.
- *
- * Returns true if added OK, else false
- *
- ******************************************************************************/
-bool bta_hl_add_sup_feature_list(uint32_t handle, uint16_t num_elem,
- const tBTA_HL_SUP_FEATURE_ELEM* p_elem_list) {
- int offset;
- bool result;
- uint8_t* p_buf = (uint8_t*)osi_malloc(BTA_HL_SUP_FEATURE_SDP_BUF_SIZE);
-
- offset = bta_hl_compose_supported_feature_list(p_buf, num_elem, p_elem_list);
- result = SDP_AddAttribute(handle, ATTR_ID_HDP_SUP_FEAT_LIST,
- DATA_ELE_SEQ_DESC_TYPE, (uint32_t)offset, p_buf);
- osi_free(p_buf);
-
- return result;
-}
-
-/*****************************************************************************
- *
- * Function: bta_hl_sdp_update
- *
- * Purpose: Register an HDP application with SDP
- *
- * Parameters:
- *
- * Returns: void
- *
- ****************************************************************************/
-tBTA_HL_STATUS bta_hl_sdp_update(UNUSED_ATTR uint8_t app_id) {
- uint16_t svc_class_id_list[BTA_HL_NUM_SVC_ELEMS];
- tSDP_PROTOCOL_ELEM proto_elem_list[BTA_HL_NUM_PROTO_ELEMS];
- tSDP_PROTO_LIST_ELEM add_proto_list;
- tBTA_HL_SUP_FEATURE_LIST_ELEM sup_feature_list;
- uint16_t browse_list[] = {UUID_SERVCLASS_PUBLIC_BROWSE_GROUP};
- uint8_t i, j, cnt, mdep_id, mdep_role;
- uint8_t data_exchange_spec = BTA_HL_SDP_IEEE_11073_20601;
- uint8_t mcap_sup_proc = BTA_HL_MCAP_SUP_PROC_MASK;
- uint16_t profile_uuid = UUID_SERVCLASS_HDP_PROFILE;
- uint16_t version = BTA_HL_VERSION;
- uint8_t num_services = 1;
- tBTA_HL_APP_CB* p_cb = BTA_HL_GET_APP_CB_PTR(0);
- bool result = true;
- tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
-
- if ((p_cb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SOURCE) &&
- (!p_cb->sup_feature.advertize_source_sdp)) {
- return BTA_HL_STATUS_OK;
- }
-
- num_services = 1;
- svc_class_id_list[0] = UUID_SERVCLASS_HDP_SOURCE;
- if (p_cb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SINK) {
- svc_class_id_list[0] = UUID_SERVCLASS_HDP_SINK;
- } else {
- if (p_cb->sup_feature.app_role_mask != BTA_HL_MDEP_ROLE_MASK_SOURCE) {
- /* dual role */
- num_services = 2;
- svc_class_id_list[1] = UUID_SERVCLASS_HDP_SINK;
- }
- }
- result &= SDP_AddServiceClassIdList(p_cb->sdp_handle, num_services,
- svc_class_id_list);
-
- if (result) {
- /* add the protocol element sequence */
- proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
- proto_elem_list[0].num_params = 1;
- proto_elem_list[0].params[0] = p_cb->ctrl_psm;
- proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_MCAP_CTRL;
- proto_elem_list[1].num_params = 1;
- proto_elem_list[1].params[0] = version;
- result &= SDP_AddProtocolList(p_cb->sdp_handle, BTA_HL_NUM_PROTO_ELEMS,
- proto_elem_list);
-
- result &=
- SDP_AddProfileDescriptorList(p_cb->sdp_handle, profile_uuid, version);
- }
-
- if (result) {
- add_proto_list.num_elems = BTA_HL_NUM_ADD_PROTO_ELEMS;
- add_proto_list.list_elem[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
- add_proto_list.list_elem[0].num_params = 1;
- add_proto_list.list_elem[0].params[0] = p_cb->data_psm;
- add_proto_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_MCAP_DATA;
- add_proto_list.list_elem[1].num_params = 0;
- result &= SDP_AddAdditionProtoLists(
- p_cb->sdp_handle, BTA_HL_NUM_ADD_PROTO_LISTS, &add_proto_list);
- }
-
- if (result) {
- if (p_cb->srv_name[0]) {
- result &= SDP_AddAttribute(
- p_cb->sdp_handle, (uint16_t)ATTR_ID_SERVICE_NAME,
- (uint8_t)TEXT_STR_DESC_TYPE, (uint32_t)(strlen(p_cb->srv_name) + 1),
- (uint8_t*)p_cb->srv_name);
- } /* end of setting optional service name */
- }
-
- if (result) {
- if (p_cb->srv_desp[0]) {
- result &= SDP_AddAttribute(
- p_cb->sdp_handle, (uint16_t)ATTR_ID_SERVICE_DESCRIPTION,
- (uint8_t)TEXT_STR_DESC_TYPE, (uint32_t)(strlen(p_cb->srv_desp) + 1),
- (uint8_t*)p_cb->srv_desp);
-
- } /* end of setting optional service description */
- }
-
- if (result) {
- if (p_cb->provider_name[0]) {
- result &=
- SDP_AddAttribute(p_cb->sdp_handle, (uint16_t)ATTR_ID_PROVIDER_NAME,
- (uint8_t)TEXT_STR_DESC_TYPE,
- (uint32_t)(strlen(p_cb->provider_name) + 1),
- (uint8_t*)p_cb->provider_name);
- } /* end of setting optional provider name */
- }
-
- /* add supported feture list */
-
- if (result) {
- cnt = 0;
- for (i = 1; i < BTA_HL_NUM_MDEPS; i++) {
- if (p_cb->sup_feature.mdep[i].mdep_id) {
- mdep_id = (uint8_t)p_cb->sup_feature.mdep[i].mdep_id;
- mdep_role = (uint8_t)p_cb->sup_feature.mdep[i].mdep_cfg.mdep_role;
-
- APPL_TRACE_DEBUG(
- "num_of_mdep_data_types %d ",
- p_cb->sup_feature.mdep[i].mdep_cfg.num_of_mdep_data_types);
- for (j = 0;
- j < p_cb->sup_feature.mdep[i].mdep_cfg.num_of_mdep_data_types;
- j++) {
- sup_feature_list.list_elem[cnt].mdep_id = mdep_id;
- sup_feature_list.list_elem[cnt].mdep_role = mdep_role;
- sup_feature_list.list_elem[cnt].data_type =
- p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].data_type;
- if (p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].desp[0] != '\0') {
- sup_feature_list.list_elem[cnt].p_mdep_desp =
- p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].desp;
- } else {
- sup_feature_list.list_elem[cnt].p_mdep_desp = NULL;
- }
-
- cnt++;
- if (cnt == BTA_HL_NUM_SUP_FEATURE_ELEMS) {
- result = false;
- break;
- }
- }
- }
- }
- sup_feature_list.num_elems = cnt;
- result &= bta_hl_add_sup_feature_list(p_cb->sdp_handle,
- sup_feature_list.num_elems,
- sup_feature_list.list_elem);
- }
- if (result) {
- result &= SDP_AddAttribute(p_cb->sdp_handle, ATTR_ID_HDP_DATA_EXCH_SPEC,
- UINT_DESC_TYPE, (uint32_t)1,
- (uint8_t*)&data_exchange_spec);
- }
-
- if (result) {
- result &=
- SDP_AddAttribute(p_cb->sdp_handle, ATTR_ID_HDP_MCAP_SUP_PROC,
- UINT_DESC_TYPE, (uint32_t)1, (uint8_t*)&mcap_sup_proc);
- }
-
- if (result) {
- result &= SDP_AddUuidSequence(p_cb->sdp_handle, ATTR_ID_BROWSE_GROUP_LIST,
- 1, browse_list);
- }
-
- if (result) {
- for (i = 0; i < num_services; i++) {
- bta_sys_add_uuid(svc_class_id_list[i]);
- APPL_TRACE_DEBUG("dbg bta_sys_add_uuid i=%d uuid=0x%x", i,
- svc_class_id_list[i]); // todo
- }
- } else {
- if (p_cb->sdp_handle) {
- SDP_DeleteRecord(p_cb->sdp_handle);
- p_cb->sdp_handle = 0;
- }
- status = BTA_HL_STATUS_SDP_FAIL;
- }
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_sdp_update status=%s", bta_hl_status_code(status));
-#endif
- return status;
-}
-
-/*****************************************************************************
- *
- * Function: bta_hl_sdp_register
- *
- * Purpose: Register an HDP application with SDP
- *
- * Parameters: p_cb - Pointer to MA instance control block
- * p_service_name - MA server name
- * inst_id - MAS instance ID
- * msg_type - Supported message type(s)
- *
- *
- * Returns: void
- *
- ****************************************************************************/
-tBTA_HL_STATUS bta_hl_sdp_register(uint8_t app_idx) {
- uint16_t svc_class_id_list[BTA_HL_NUM_SVC_ELEMS];
- tSDP_PROTOCOL_ELEM proto_elem_list[BTA_HL_NUM_PROTO_ELEMS];
- tSDP_PROTO_LIST_ELEM add_proto_list;
- tBTA_HL_SUP_FEATURE_LIST_ELEM sup_feature_list;
- uint16_t browse_list[] = {UUID_SERVCLASS_PUBLIC_BROWSE_GROUP};
- uint8_t i, j, cnt, mdep_id, mdep_role;
- uint8_t data_exchange_spec = BTA_HL_SDP_IEEE_11073_20601;
- uint8_t mcap_sup_proc = BTA_HL_MCAP_SUP_PROC_MASK;
- uint16_t profile_uuid = UUID_SERVCLASS_HDP_PROFILE;
- uint16_t version = BTA_HL_VERSION;
- uint8_t num_services = 1;
- tBTA_HL_APP_CB* p_cb = BTA_HL_GET_APP_CB_PTR(app_idx);
- bool result = true;
- tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_sdp_register app_idx=%d", app_idx);
-#endif
-
- if ((p_cb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SOURCE) &&
- (!p_cb->sup_feature.advertize_source_sdp)) {
- return BTA_HL_STATUS_OK;
- }
-
- p_cb->sdp_handle = SDP_CreateRecord();
- if (p_cb->sdp_handle == 0) {
- return BTA_HL_STATUS_SDP_NO_RESOURCE;
- }
-
- num_services = 1;
- svc_class_id_list[0] = UUID_SERVCLASS_HDP_SOURCE;
- if (p_cb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SINK) {
- svc_class_id_list[0] = UUID_SERVCLASS_HDP_SINK;
- } else {
- if (p_cb->sup_feature.app_role_mask != BTA_HL_MDEP_ROLE_MASK_SOURCE) {
- /* dual role */
- num_services = 2;
- svc_class_id_list[1] = UUID_SERVCLASS_HDP_SINK;
- }
- }
- result &= SDP_AddServiceClassIdList(p_cb->sdp_handle, num_services,
- svc_class_id_list);
-
- if (result) {
- /* add the protocol element sequence */
- proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
- proto_elem_list[0].num_params = 1;
- proto_elem_list[0].params[0] = p_cb->ctrl_psm;
- proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_MCAP_CTRL;
- proto_elem_list[1].num_params = 1;
- proto_elem_list[1].params[0] = version;
- result &= SDP_AddProtocolList(p_cb->sdp_handle, BTA_HL_NUM_PROTO_ELEMS,
- proto_elem_list);
-
- result &=
- SDP_AddProfileDescriptorList(p_cb->sdp_handle, profile_uuid, version);
- }
-
- if (result) {
- add_proto_list.num_elems = BTA_HL_NUM_ADD_PROTO_ELEMS;
- add_proto_list.list_elem[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
- add_proto_list.list_elem[0].num_params = 1;
- add_proto_list.list_elem[0].params[0] = p_cb->data_psm;
- add_proto_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_MCAP_DATA;
- add_proto_list.list_elem[1].num_params = 0;
- result &= SDP_AddAdditionProtoLists(
- p_cb->sdp_handle, BTA_HL_NUM_ADD_PROTO_LISTS, &add_proto_list);
- }
-
- if (result) {
- if (p_cb->srv_name[0]) {
- result &= SDP_AddAttribute(
- p_cb->sdp_handle, (uint16_t)ATTR_ID_SERVICE_NAME,
- (uint8_t)TEXT_STR_DESC_TYPE, (uint32_t)(strlen(p_cb->srv_name) + 1),
- (uint8_t*)p_cb->srv_name);
- } /* end of setting optional service name */
- }
-
- if (result) {
- if (p_cb->srv_desp[0]) {
- result &= SDP_AddAttribute(
- p_cb->sdp_handle, (uint16_t)ATTR_ID_SERVICE_DESCRIPTION,
- (uint8_t)TEXT_STR_DESC_TYPE, (uint32_t)(strlen(p_cb->srv_desp) + 1),
- (uint8_t*)p_cb->srv_desp);
-
- } /* end of setting optional service description */
- }
-
- if (result) {
- if (p_cb->provider_name[0]) {
- result &=
- SDP_AddAttribute(p_cb->sdp_handle, (uint16_t)ATTR_ID_PROVIDER_NAME,
- (uint8_t)TEXT_STR_DESC_TYPE,
- (uint32_t)(strlen(p_cb->provider_name) + 1),
- (uint8_t*)p_cb->provider_name);
- } /* end of setting optional provider name */
- }
-
- /* add supported feture list */
-
- if (result) {
- cnt = 0;
- for (i = 1; i <= p_cb->sup_feature.num_of_mdeps; i++) {
- mdep_id = (uint8_t)p_cb->sup_feature.mdep[i].mdep_id;
- mdep_role = (uint8_t)p_cb->sup_feature.mdep[i].mdep_cfg.mdep_role;
-
- for (j = 0; j < p_cb->sup_feature.mdep[i].mdep_cfg.num_of_mdep_data_types;
- j++) {
- sup_feature_list.list_elem[cnt].mdep_id = mdep_id;
- sup_feature_list.list_elem[cnt].mdep_role = mdep_role;
- sup_feature_list.list_elem[cnt].data_type =
- p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].data_type;
- if (p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].desp[0] != '\0') {
- sup_feature_list.list_elem[cnt].p_mdep_desp =
- p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].desp;
- } else {
- sup_feature_list.list_elem[cnt].p_mdep_desp = NULL;
- }
-
- cnt++;
- if (cnt == BTA_HL_NUM_SUP_FEATURE_ELEMS) {
- result = false;
- break;
- }
- }
- }
- sup_feature_list.num_elems = cnt;
- result &= bta_hl_add_sup_feature_list(p_cb->sdp_handle,
- sup_feature_list.num_elems,
- sup_feature_list.list_elem);
- }
- if (result) {
- result &= SDP_AddAttribute(p_cb->sdp_handle, ATTR_ID_HDP_DATA_EXCH_SPEC,
- UINT_DESC_TYPE, (uint32_t)1,
- (uint8_t*)&data_exchange_spec);
- }
-
- if (result) {
- result &=
- SDP_AddAttribute(p_cb->sdp_handle, ATTR_ID_HDP_MCAP_SUP_PROC,
- UINT_DESC_TYPE, (uint32_t)1, (uint8_t*)&mcap_sup_proc);
- }
-
- if (result) {
- result &= SDP_AddUuidSequence(p_cb->sdp_handle, ATTR_ID_BROWSE_GROUP_LIST,
- 1, browse_list);
- }
-
- if (result) {
- for (i = 0; i < num_services; i++) {
- bta_sys_add_uuid(svc_class_id_list[i]);
- APPL_TRACE_DEBUG("dbg bta_sys_add_uuid i=%d uuid=0x%x", i,
- svc_class_id_list[i]); // todo
- }
- } else {
- if (p_cb->sdp_handle) {
- SDP_DeleteRecord(p_cb->sdp_handle);
- p_cb->sdp_handle = 0;
- }
- status = BTA_HL_STATUS_SDP_FAIL;
- }
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_sdp_register status=%s", bta_hl_status_code(status));
-#endif
- return status;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_find_sink_or_src_srv_class_in_db
- *
- * Description This function queries an SDP database for either a HDP Sink
- * or Source service class ID.
- * If the p_start_rec pointer is NULL, it looks from the
- * beginning of the database, else it continues from the next
- * record after p_start_rec.
- *
- * Returns Pointer to record containing service class, or NULL
- *
- ******************************************************************************/
-tSDP_DISC_REC* bta_hl_find_sink_or_src_srv_class_in_db(
- const tSDP_DISCOVERY_DB* p_db, const tSDP_DISC_REC* p_start_rec) {
- tSDP_DISC_REC* p_rec;
- tSDP_DISC_ATTR *p_attr, *p_sattr;
-
- /* Must have a valid database */
- if (p_db == NULL) return (NULL);
-
- if (!p_start_rec) {
- p_rec = p_db->p_first_rec;
- } else {
- p_rec = p_start_rec->p_next_rec;
- }
-
- while (p_rec) {
- p_attr = p_rec->p_first_attr;
- while (p_attr) {
- if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) &&
- (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) ==
- DATA_ELE_SEQ_DESC_TYPE)) {
- for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr;
- p_sattr = p_sattr->p_next_attr) {
- if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) &&
- (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) &&
- ((p_sattr->attr_value.v.u16 == UUID_SERVCLASS_HDP_SINK) ||
- (p_sattr->attr_value.v.u16 == UUID_SERVCLASS_HDP_SOURCE))) {
- return (p_rec);
- }
- }
- break;
- }
-
- p_attr = p_attr->p_next_attr;
- }
-
- p_rec = p_rec->p_next_rec;
- }
-/* If here, no matching UUID found */
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_find_sink_or_src_srv_class_in_db failed");
-#endif
-
- return (NULL);
-}
-#endif /* HL_INCLUDED */
diff --git a/bta/hl/bta_hl_utils.cc b/bta/hl/bta_hl_utils.cc
deleted file mode 100644
index 0aa93b3..0000000
--- a/bta/hl/bta_hl_utils.cc
+++ /dev/null
@@ -1,3083 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2003-2012 Broadcom 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.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- * This file implements utility functions for the HeaLth device profile
- * (HL).
- *
- ******************************************************************************/
-
-#include <stdio.h>
-#include <string.h>
-
-#include "bt_target.h"
-#if (HL_INCLUDED == TRUE)
-
-#include "bt_common.h"
-#include "bta_hl_co.h"
-#include "bta_hl_int.h"
-#include "mca_api.h"
-#include "mca_defs.h"
-#include "osi/include/osi.h"
-#include "utl.h"
-
-/*******************************************************************************
- *
- * Function bta_hl_set_ctrl_psm_for_dch
- *
- * Description This function set the control PSM for the DCH setup
- *
- * Returns bool - true - control PSM setting is successful
- ******************************************************************************/
-bool bta_hl_set_ctrl_psm_for_dch(uint8_t app_idx, uint8_t mcl_idx,
- UNUSED_ATTR uint8_t mdl_idx,
- uint16_t ctrl_psm) {
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- bool success = true, update_ctrl_psm = false;
-
- if (p_mcb->sdp.num_recs) {
- if (p_mcb->ctrl_psm != ctrl_psm) {
- /* can not use a different ctrl PSM than the current one*/
- success = false;
- }
- } else {
- /* No SDP info control i.e. channel was opened by the peer */
- update_ctrl_psm = true;
- }
-
- if (success && update_ctrl_psm) {
- p_mcb->ctrl_psm = ctrl_psm;
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- if (!success) {
- APPL_TRACE_DEBUG(
- "bta_hl_set_ctrl_psm_for_dch num_recs=%d success=%d update_ctrl_psm=%d "
- "ctrl_psm=0x%x ",
- p_mcb->sdp.num_recs, success, update_ctrl_psm, ctrl_psm);
- }
-#endif
-
- return success;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_find_sdp_idx_using_ctrl_psm
- *
- * Description
- *
- * Returns true if found
- *
- ******************************************************************************/
-bool bta_hl_find_sdp_idx_using_ctrl_psm(tBTA_HL_SDP* p_sdp, uint16_t ctrl_psm,
- uint8_t* p_sdp_idx) {
- bool found = false;
- tBTA_HL_SDP_REC* p_rec;
- uint8_t i;
-
- if (ctrl_psm != 0) {
- for (i = 0; i < p_sdp->num_recs; i++) {
- p_rec = &p_sdp->sdp_rec[i];
- if (p_rec->ctrl_psm == ctrl_psm) {
- *p_sdp_idx = i;
- found = true;
- break;
- }
- }
- } else {
- *p_sdp_idx = 0;
- found = true;
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- if (!found) {
- APPL_TRACE_DEBUG(
- "bta_hl_find_sdp_idx_using_ctrl_psm found=%d sdp_idx=%d ctrl_psm=0x%x ",
- found, *p_sdp_idx, ctrl_psm);
- }
-#endif
- return found;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_set_user_tx_buf_size
- *
- * Description This function sets the user tx buffer size
- *
- * Returns uint16_t buf_size
- *
- ******************************************************************************/
-
-uint16_t bta_hl_set_user_tx_buf_size(uint16_t max_tx_size) {
- if (max_tx_size > BT_DEFAULT_BUFFER_SIZE) return BTA_HL_LRG_DATA_BUF_SIZE;
- return L2CAP_INVALID_ERM_BUF_SIZE;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_set_user_rx_buf_size
- *
- * Description This function sets the user rx buffer size
- *
- * Returns uint16_t buf_size
- *
- ******************************************************************************/
-
-uint16_t bta_hl_set_user_rx_buf_size(uint16_t mtu) {
- if (mtu > BT_DEFAULT_BUFFER_SIZE) return BTA_HL_LRG_DATA_BUF_SIZE;
- return L2CAP_INVALID_ERM_BUF_SIZE;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_set_tx_win_size
- *
- * Description This function sets the tx window size
- *
- * Returns uint8_t tx_win_size
- *
- ******************************************************************************/
-uint8_t bta_hl_set_tx_win_size(uint16_t mtu, uint16_t mps) {
- uint8_t tx_win_size;
-
- if (mtu <= mps) {
- tx_win_size = 1;
- } else {
- if (mps > 0) {
- tx_win_size = (mtu / mps) + 1;
- } else {
- APPL_TRACE_ERROR("The MPS is zero");
- tx_win_size = 10;
- }
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_set_tx_win_size win_size=%d mtu=%d mps=%d",
- tx_win_size, mtu, mps);
-#endif
- return tx_win_size;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_set_mps
- *
- * Description This function sets the MPS
- *
- * Returns uint16_t MPS
- *
- ******************************************************************************/
-uint16_t bta_hl_set_mps(uint16_t mtu) {
- uint16_t mps;
- if (mtu > BTA_HL_L2C_MPS) {
- mps = BTA_HL_L2C_MPS;
- } else {
- mps = mtu;
- }
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_set_mps mps=%d mtu=%d", mps, mtu);
-#endif
- return mps;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_clean_mdl_cb
- *
- * Description This function clean up the specified MDL control block
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_clean_mdl_cb(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx) {
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_clean_mdl_cb app_idx=%d mcl_idx=%d mdl_idx=%d",
- app_idx, mcl_idx, mdl_idx);
-#endif
- osi_free_and_reset((void**)&p_dcb->p_tx_pkt);
- osi_free_and_reset((void**)&p_dcb->p_rx_pkt);
- osi_free_and_reset((void**)&p_dcb->p_echo_tx_pkt);
- osi_free_and_reset((void**)&p_dcb->p_echo_rx_pkt);
-
- memset((void*)p_dcb, 0, sizeof(tBTA_HL_MDL_CB));
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_get_buf
- *
- * Description This function allocate a buffer based on the specified data size
- *
- * Returns BT_HDR *.
- *
- ******************************************************************************/
-BT_HDR* bta_hl_get_buf(uint16_t data_size, bool fcs_use) {
- size_t size = data_size + L2CAP_MIN_OFFSET + BT_HDR_SIZE + L2CAP_FCS_LEN +
- L2CAP_EXT_CONTROL_OVERHEAD;
-
- if (fcs_use) size += L2CAP_FCS_LEN;
-
- BT_HDR* p_new = (BT_HDR*)osi_malloc(size);
- p_new->len = data_size;
- p_new->offset = L2CAP_MIN_OFFSET;
-
- return p_new;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_find_service_in_db
- *
- * Description This function check the specified service class(es) can be find
- * in the received SDP database
- *
- * Returns bool true - found
- * false - not found
- *
- ******************************************************************************/
-bool bta_hl_find_service_in_db(uint8_t app_idx, uint8_t mcl_idx,
- uint16_t service_uuid, tSDP_DISC_REC** pp_rec) {
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- bool found = true;
-
- switch (service_uuid) {
- case UUID_SERVCLASS_HDP_SINK:
- case UUID_SERVCLASS_HDP_SOURCE:
- *pp_rec = SDP_FindServiceInDb(p_mcb->p_db, service_uuid, *pp_rec);
- if (*pp_rec == NULL) {
- found = false;
- }
- break;
- default:
- *pp_rec = bta_hl_find_sink_or_src_srv_class_in_db(p_mcb->p_db, *pp_rec);
- if (*pp_rec == NULL) {
- found = false;
- }
- break;
- }
- return found;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_get_service_uuids
- *
- *
- * Description This function finds the service class(es) for both CCH and DCH
- * operations
- *
- * Returns uint16_t - service_id
- * if service_uuid = 0xFFFF then it means service uuid
- * can be either Sink or Source
- *
- ******************************************************************************/
-uint16_t bta_hl_get_service_uuids(uint8_t sdp_oper, uint8_t app_idx,
- uint8_t mcl_idx, uint8_t mdl_idx) {
- tBTA_HL_MDL_CB* p_dcb;
- uint16_t service_uuid = 0xFFFF; /* both Sink and Source */
-
- switch (sdp_oper) {
- case BTA_HL_SDP_OP_DCH_OPEN_INIT:
- case BTA_HL_SDP_OP_DCH_RECONNECT_INIT:
- p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
- if (p_dcb->local_mdep_id != BTA_HL_ECHO_TEST_MDEP_ID) {
- if (p_dcb->peer_mdep_role == BTA_HL_MDEP_ROLE_SINK) {
- service_uuid = UUID_SERVCLASS_HDP_SINK;
- } else {
- service_uuid = UUID_SERVCLASS_HDP_SOURCE;
- }
- }
- break;
- case BTA_HL_SDP_OP_CCH_INIT:
- default:
- /* use default that is both Sink and Source */
- break;
- }
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_get_service_uuids service_uuid=0x%x", service_uuid);
-#endif
- return service_uuid;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_find_echo_cfg_rsp
- *
- *
- * Description This function finds the configuration response for the echo test
- *
- * Returns bool - true found
- * false not found
- *
- ******************************************************************************/
-bool bta_hl_find_echo_cfg_rsp(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdep_idx, uint8_t cfg,
- uint8_t* p_cfg_rsp) {
- tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
- tBTA_HL_MDEP* p_mdep = &p_acb->sup_feature.mdep[mdep_idx];
- bool status = true;
-
- if (p_mdep->mdep_id == BTA_HL_ECHO_TEST_MDEP_ID) {
- if ((cfg == BTA_HL_DCH_CFG_RELIABLE) || (cfg == BTA_HL_DCH_CFG_STREAMING)) {
- *p_cfg_rsp = cfg;
- } else if (cfg == BTA_HL_DCH_CFG_NO_PREF) {
- *p_cfg_rsp = BTA_HL_DEFAULT_ECHO_TEST_SRC_DCH_CFG;
- } else {
- status = false;
- APPL_TRACE_ERROR("Inavlid echo cfg value");
- }
- return status;
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- if (!status) {
- APPL_TRACE_DEBUG(
- "bta_hl_find_echo_cfg_rsp status=failed app_idx=%d mcl_idx=%d "
- "mdep_idx=%d cfg=%d",
- app_idx, mcl_idx, mdep_idx, cfg);
- }
-#endif
-
- return status;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_validate_dch_cfg
- *
- * Description This function validate the DCH configuration
- *
- * Returns bool - true cfg is valid
- * false not valid
- *
- ******************************************************************************/
-bool bta_hl_validate_cfg(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
- uint8_t cfg) {
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
- bool is_valid = false;
-
- if (!bta_hl_is_the_first_reliable_existed(app_idx, mcl_idx) &&
- (cfg != BTA_HL_DCH_CFG_RELIABLE)) {
- APPL_TRACE_ERROR("the first DCH should be a reliable channel");
- return is_valid;
- }
-
- switch (p_dcb->local_cfg) {
- case BTA_HL_DCH_CFG_NO_PREF:
-
- if ((cfg == BTA_HL_DCH_CFG_RELIABLE) ||
- (cfg == BTA_HL_DCH_CFG_STREAMING)) {
- is_valid = true;
- }
- break;
- case BTA_HL_DCH_CFG_RELIABLE:
- case BTA_HL_DCH_CFG_STREAMING:
- if (p_dcb->local_cfg == cfg) {
- is_valid = true;
- }
- break;
- default:
- break;
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- if (!is_valid) {
- APPL_TRACE_DEBUG("bta_hl_validate_dch_open_cfg is_valid=%d, cfg=%d",
- is_valid, cfg);
- }
-#endif
- return is_valid;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_find_cch_cb_indexes
- *
- * Description This function finds the indexes needed for the CCH state machine
- *
- * Returns bool - true found
- * false not found
- *
- ******************************************************************************/
-bool bta_hl_find_cch_cb_indexes(tBTA_HL_DATA* p_msg, uint8_t* p_app_idx,
- uint8_t* p_mcl_idx) {
- bool found = false;
- tBTA_HL_MCL_CB* p_mcb;
- uint8_t app_idx = 0, mcl_idx = 0;
-
- switch (p_msg->hdr.event) {
- case BTA_HL_CCH_SDP_OK_EVT:
- case BTA_HL_CCH_SDP_FAIL_EVT:
- app_idx = p_msg->cch_sdp.app_idx;
- mcl_idx = p_msg->cch_sdp.mcl_idx;
- found = true;
- break;
-
- case BTA_HL_MCA_CONNECT_IND_EVT:
-
- if (bta_hl_find_app_idx_using_handle(p_msg->mca_evt.app_handle,
- &app_idx)) {
- if (bta_hl_find_mcl_idx(app_idx,
- p_msg->mca_evt.mca_data.connect_ind.bd_addr,
- &mcl_idx)) {
- /* local initiated */
- found = true;
- } else if (!bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle,
- &app_idx, &mcl_idx) &&
- bta_hl_find_avail_mcl_idx(app_idx, &mcl_idx)) {
- /* remote initiated */
- p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- p_mcb->in_use = true;
- p_mcb->cch_oper = BTA_HL_CCH_OP_REMOTE_OPEN;
- found = true;
- }
- }
- break;
-
- case BTA_HL_MCA_DISCONNECT_IND_EVT:
-
- if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx,
- &mcl_idx)) {
- found = true;
- } else if (bta_hl_find_app_idx_using_handle(p_msg->mca_evt.app_handle,
- &app_idx) &&
- bta_hl_find_mcl_idx(
- app_idx, p_msg->mca_evt.mca_data.disconnect_ind.bd_addr,
- &mcl_idx)) {
- found = true;
- }
-
- if (found) {
- p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- if ((p_mcb->cch_oper != BTA_HL_CCH_OP_LOCAL_CLOSE) &&
- (p_mcb->cch_oper != BTA_HL_CCH_OP_LOCAL_OPEN)) {
- p_mcb->cch_oper = BTA_HL_CCH_OP_REMOTE_CLOSE;
- }
- }
- break;
-
- case BTA_HL_MCA_RSP_TOUT_IND_EVT:
-
- if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx,
- &mcl_idx)) {
- found = true;
- }
-
- if (found) {
- p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- if ((p_mcb->cch_oper != BTA_HL_CCH_OP_REMOTE_CLOSE) &&
- (p_mcb->cch_oper != BTA_HL_CCH_OP_LOCAL_OPEN)) {
- p_mcb->cch_oper = BTA_HL_CCH_OP_LOCAL_CLOSE;
- }
- }
- break;
- default:
- break;
- }
-
- if (found) {
- *p_app_idx = app_idx;
- *p_mcl_idx = mcl_idx;
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- if (!found) {
- APPL_TRACE_DEBUG(
- "bta_hl_find_cch_cb_indexes event=%s found=%d app_idx=%d mcl_idx=%d",
- bta_hl_evt_code(p_msg->hdr.event), found, app_idx, mcl_idx);
- }
-#endif
-
- return found;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_find_dch_cb_indexes
- *
- * Description This function finds the indexes needed for the DCH state machine
- *
- * Returns bool - true found
- * false not found
- *
- ******************************************************************************/
-bool bta_hl_find_dch_cb_indexes(tBTA_HL_DATA* p_msg, uint8_t* p_app_idx,
- uint8_t* p_mcl_idx, uint8_t* p_mdl_idx) {
- bool found = false;
- tBTA_HL_MCL_CB* p_mcb;
- uint8_t app_idx = 0, mcl_idx = 0, mdl_idx = 0;
-
- switch (p_msg->hdr.event) {
- case BTA_HL_MCA_CREATE_CFM_EVT:
- if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx,
- &mcl_idx) &&
- bta_hl_find_mdl_idx(app_idx, mcl_idx,
- p_msg->mca_evt.mca_data.create_cfm.mdl_id,
- &mdl_idx)) {
- found = true;
- }
- break;
-
- case BTA_HL_MCA_CREATE_IND_EVT:
- case BTA_HL_MCA_RECONNECT_IND_EVT:
- if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx,
- &mcl_idx) &&
- bta_hl_find_avail_mdl_idx(app_idx, mcl_idx, &mdl_idx)) {
- found = true;
- }
- break;
-
- case BTA_HL_MCA_OPEN_CFM_EVT:
- if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx,
- &mcl_idx) &&
- bta_hl_find_mdl_idx(app_idx, mcl_idx,
- p_msg->mca_evt.mca_data.open_cfm.mdl_id,
- &mdl_idx)) {
- found = true;
- }
- break;
-
- case BTA_HL_MCA_OPEN_IND_EVT:
- if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx,
- &mcl_idx) &&
- bta_hl_find_mdl_idx(app_idx, mcl_idx,
- p_msg->mca_evt.mca_data.open_ind.mdl_id,
- &mdl_idx)) {
- found = true;
- }
- break;
-
- case BTA_HL_MCA_CLOSE_CFM_EVT:
-
- if (bta_hl_find_mdl_idx_using_handle(
- (tBTA_HL_MDL_HANDLE)p_msg->mca_evt.mca_data.close_cfm.mdl,
- &app_idx, &mcl_idx, &mdl_idx)) {
- found = true;
- }
- break;
- case BTA_HL_MCA_CLOSE_IND_EVT:
-
- if (bta_hl_find_mdl_idx_using_handle(
- (tBTA_HL_MDL_HANDLE)p_msg->mca_evt.mca_data.close_ind.mdl,
- &app_idx, &mcl_idx, &mdl_idx)) {
- found = true;
- }
- break;
- case BTA_HL_API_SEND_DATA_EVT:
-
- if (bta_hl_find_mdl_idx_using_handle(p_msg->api_send_data.mdl_handle,
- &app_idx, &mcl_idx, &mdl_idx)) {
- found = true;
- }
-
- break;
-
- case BTA_HL_MCA_CONG_CHG_EVT:
-
- if (bta_hl_find_mdl_idx_using_handle(
- (tBTA_HL_MDL_HANDLE)p_msg->mca_evt.mca_data.cong_chg.mdl,
- &app_idx, &mcl_idx, &mdl_idx)) {
- found = true;
- }
-
- break;
-
- case BTA_HL_MCA_RCV_DATA_EVT:
- app_idx = p_msg->mca_rcv_data_evt.app_idx;
- mcl_idx = p_msg->mca_rcv_data_evt.mcl_idx;
- mdl_idx = p_msg->mca_rcv_data_evt.mdl_idx;
- found = true;
- break;
- case BTA_HL_DCH_RECONNECT_EVT:
- case BTA_HL_DCH_OPEN_EVT:
- case BTA_HL_DCH_ECHO_TEST_EVT:
- case BTA_HL_DCH_SDP_FAIL_EVT:
- app_idx = p_msg->dch_sdp.app_idx;
- mcl_idx = p_msg->dch_sdp.mcl_idx;
- mdl_idx = p_msg->dch_sdp.mdl_idx;
- found = true;
- break;
- case BTA_HL_MCA_RECONNECT_CFM_EVT:
- if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx,
- &mcl_idx) &&
- bta_hl_find_mdl_idx(app_idx, mcl_idx,
- p_msg->mca_evt.mca_data.reconnect_cfm.mdl_id,
- &mdl_idx)) {
- found = true;
- }
- break;
-
- case BTA_HL_API_DCH_CREATE_RSP_EVT:
- if (bta_hl_find_mcl_idx_using_handle(p_msg->api_dch_create_rsp.mcl_handle,
- &app_idx, &mcl_idx) &&
- bta_hl_find_mdl_idx(app_idx, mcl_idx,
- p_msg->api_dch_create_rsp.mdl_id, &mdl_idx)) {
- found = true;
- }
- break;
- case BTA_HL_MCA_ABORT_IND_EVT:
- if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx,
- &mcl_idx) &&
- bta_hl_find_mdl_idx(app_idx, mcl_idx,
- p_msg->mca_evt.mca_data.abort_ind.mdl_id,
- &mdl_idx)) {
- found = true;
- }
- break;
- case BTA_HL_MCA_ABORT_CFM_EVT:
- if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx,
- &mcl_idx) &&
- bta_hl_find_mdl_idx(app_idx, mcl_idx,
- p_msg->mca_evt.mca_data.abort_cfm.mdl_id,
- &mdl_idx)) {
- found = true;
- }
- break;
- case BTA_HL_CI_GET_TX_DATA_EVT:
- case BTA_HL_CI_PUT_RX_DATA_EVT:
- if (bta_hl_find_mdl_idx_using_handle(p_msg->ci_get_put_data.mdl_handle,
- &app_idx, &mcl_idx, &mdl_idx)) {
- found = true;
- }
- break;
- case BTA_HL_CI_GET_ECHO_DATA_EVT:
- case BTA_HL_CI_PUT_ECHO_DATA_EVT:
- if (bta_hl_find_mcl_idx_using_handle(
- p_msg->ci_get_put_echo_data.mcl_handle, &app_idx, &mcl_idx)) {
- p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- mdl_idx = p_mcb->echo_mdl_idx;
- found = true;
- }
- break;
-
- default:
- break;
- }
-
- if (found) {
- *p_app_idx = app_idx;
- *p_mcl_idx = mcl_idx;
- *p_mdl_idx = mdl_idx;
- }
-#if (BTA_HL_DEBUG == TRUE)
- if (!found) {
- APPL_TRACE_DEBUG(
- "bta_hl_find_dch_cb_indexes event=%s found=%d app_idx=%d mcl_idx=%d "
- "mdl_idx=%d",
- bta_hl_evt_code(p_msg->hdr.event), found, *p_app_idx, *p_mcl_idx,
- *p_mdl_idx);
- }
-#endif
-
- return found;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_allocate_mdl_id
- *
- * Description This function allocates a MDL ID
- *
- * Returns uint16_t - MDL ID
- *
- ******************************************************************************/
-uint16_t bta_hl_allocate_mdl_id(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx) {
- uint16_t mdl_id = 0;
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- bool duplicate_id;
- uint8_t i, mdl_cfg_idx;
-
- do {
- duplicate_id = false;
- mdl_id = ((mdl_id + 1) & 0xFEFF);
- /* check mdl_ids that are used for the current conenctions */
- for (i = 0; i < BTA_HL_NUM_MDLS_PER_MCL; i++) {
- if (p_mcb->mdl[i].in_use && (i != mdl_idx) &&
- (p_mcb->mdl[i].mdl_id == mdl_id)) {
- duplicate_id = true;
- break;
- }
- }
-
- if (duplicate_id) {
- /* start from the beginning to get another MDL value*/
- continue;
- } else {
- /* check mdl_ids that are stored in the persistent memory */
- if (bta_hl_find_mdl_cfg_idx(app_idx, mcl_idx, mdl_id, &mdl_cfg_idx)) {
- duplicate_id = true;
- } else {
- /* found a new MDL value */
- break;
- }
- }
-
- } while (true);
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_allocate_mdl OK mdl_id=%d", mdl_id);
-#endif
- return mdl_id;
-}
-/*******************************************************************************
- *
- * Function bta_hl_find_mdl_idx
- *
- * Description This function finds the MDL index based on mdl_id
- *
- * Returns bool true-found
- *
- ******************************************************************************/
-bool bta_hl_find_mdl_idx(uint8_t app_idx, uint8_t mcl_idx, uint16_t mdl_id,
- uint8_t* p_mdl_idx) {
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- bool found = false;
- uint8_t i;
-
- for (i = 0; i < BTA_HL_NUM_MDLS_PER_MCL; i++) {
- if (p_mcb->mdl[i].in_use && (mdl_id != 0) &&
- (p_mcb->mdl[i].mdl_id == mdl_id)) {
- found = true;
- *p_mdl_idx = i;
- break;
- }
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- if (!found) {
- APPL_TRACE_DEBUG("bta_hl_find_mdl_idx found=%d mdl_id=%d mdl_idx=%d ",
- found, mdl_id, i);
- }
-#endif
-
- return found;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_find_an_active_mdl_idx
- *
- * Description This function finds an active MDL
- *
- * Returns bool true-found
- *
- ******************************************************************************/
-bool bta_hl_find_an_active_mdl_idx(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t* p_mdl_idx) {
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- bool found = false;
- uint8_t i;
-
- for (i = 0; i < BTA_HL_NUM_MDLS_PER_MCL; i++) {
- if (p_mcb->mdl[i].in_use &&
- (p_mcb->mdl[i].dch_state == BTA_HL_DCH_OPEN_ST)) {
- found = true;
- *p_mdl_idx = i;
- break;
- }
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- if (found) {
- APPL_TRACE_DEBUG(
- "bta_hl_find_an_opened_mdl_idx found=%d app_idx=%d mcl_idx=%d "
- "mdl_idx=%d",
- found, app_idx, mcl_idx, i);
- }
-#endif
-
- return found;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_find_dch_setup_mdl_idx
- *
- * Description This function finds a MDL which in the DCH setup state
- *
- * Returns bool true-found
- *
- ******************************************************************************/
-bool bta_hl_find_dch_setup_mdl_idx(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t* p_mdl_idx) {
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- bool found = false;
- uint8_t i;
-
- for (i = 0; i < BTA_HL_NUM_MDLS_PER_MCL; i++) {
- if (p_mcb->mdl[i].in_use &&
- (p_mcb->mdl[i].dch_state == BTA_HL_DCH_OPENING_ST)) {
- found = true;
- *p_mdl_idx = i;
- break;
- }
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- if (found) {
- APPL_TRACE_DEBUG(
- "bta_hl_find_dch_setup_mdl_idx found=%d app_idx=%d mcl_idx=%d "
- "mdl_idx=%d",
- found, app_idx, mcl_idx, i);
- }
-#endif
-
- return found;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_find_an_in_use_mcl_idx
- *
- * Description This function finds an in-use MCL control block index
- *
- * Returns bool true-found
- *
- ******************************************************************************/
-bool bta_hl_find_an_in_use_mcl_idx(uint8_t app_idx, uint8_t* p_mcl_idx) {
- tBTA_HL_MCL_CB* p_mcb;
- bool found = false;
- uint8_t i;
-
- for (i = 0; i < BTA_HL_NUM_MCLS; i++) {
- p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, i);
- if (p_mcb->in_use && (p_mcb->cch_state != BTA_HL_CCH_IDLE_ST)) {
- found = true;
- *p_mcl_idx = i;
- break;
- }
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- if (found) {
- APPL_TRACE_DEBUG(
- "bta_hl_find_an_in_use_mcl_idx found=%d app_idx=%d mcl_idx=%d ", found,
- app_idx, i);
- }
-#endif
-
- return found;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_find_an_in_use_app_idx
- *
- * Description This function finds an in-use application control block index
- *
- * Returns bool true-found
- *
- ******************************************************************************/
-bool bta_hl_find_an_in_use_app_idx(uint8_t* p_app_idx) {
- tBTA_HL_APP_CB* p_acb;
- bool found = false;
- uint8_t i;
-
- for (i = 0; i < BTA_HL_NUM_APPS; i++) {
- p_acb = BTA_HL_GET_APP_CB_PTR(i);
- if (p_acb->in_use) {
- found = true;
- *p_app_idx = i;
- break;
- }
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- if (found) {
- APPL_TRACE_DEBUG("bta_hl_find_an_in_use_app_idx found=%d app_idx=%d ",
- found, i);
- }
-#endif
-
- return found;
-}
-/*******************************************************************************
- *
- * Function bta_hl_find_app_idx
- *
- * Description This function finds the application control block index based on
- * the application ID
- *
- * Returns bool true-found
- *
- ******************************************************************************/
-bool bta_hl_find_app_idx(uint8_t app_id, uint8_t* p_app_idx) {
- bool found = false;
- uint8_t i;
-
- for (i = 0; i < BTA_HL_NUM_APPS; i++) {
- if (bta_hl_cb.acb[i].in_use && (bta_hl_cb.acb[i].app_id == app_id)) {
- found = true;
- *p_app_idx = i;
- break;
- }
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_find_app_idx found=%d app_id=%d idx=%d ", found,
- app_id, i);
-#endif
-
- return found;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_find_app_idx_using_handle
- *
- * Description This function finds the application control block index based on
- * the application handle
- *
- * Returns bool true-found
- *
- ******************************************************************************/
-bool bta_hl_find_app_idx_using_handle(tBTA_HL_APP_HANDLE app_handle,
- uint8_t* p_app_idx) {
- bool found = false;
- uint8_t i;
-
- for (i = 0; i < BTA_HL_NUM_APPS; i++) {
- if (bta_hl_cb.acb[i].in_use &&
- (bta_hl_cb.acb[i].app_handle == app_handle)) {
- found = true;
- *p_app_idx = i;
- break;
- }
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- if (!found) {
- APPL_TRACE_DEBUG(
- "bta_hl_find_app_idx_using_mca_handle status=%d handle=%d app_idx=%d ",
- found, app_handle, i);
- }
-#endif
-
- return found;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_find_mcl_idx_using_handle
- *
- * Description This function finds the MCL control block index based on
- * the MCL handle
- *
- * Returns bool true-found
- *
- ******************************************************************************/
-bool bta_hl_find_mcl_idx_using_handle(tBTA_HL_MCL_HANDLE mcl_handle,
- uint8_t* p_app_idx, uint8_t* p_mcl_idx) {
- tBTA_HL_APP_CB* p_acb;
- bool found = false;
- uint8_t i = 0, j = 0;
-
- for (i = 0; i < BTA_HL_NUM_APPS; i++) {
- p_acb = BTA_HL_GET_APP_CB_PTR(i);
- if (p_acb->in_use) {
- for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
- if (p_acb->mcb[j].mcl_handle == mcl_handle) {
- found = true;
- *p_app_idx = i;
- *p_mcl_idx = j;
- break;
- }
- }
- }
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- if (!found) {
- APPL_TRACE_DEBUG(
- "bta_hl_find_mcl_idx_using_handle found=%d app_idx=%d mcl_idx=%d",
- found, i, j);
- }
-#endif
- return found;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_find_mcl_idx
- *
- * Description This function finds the MCL control block index based on
- * the peer BD address
- *
- * Returns bool true-found
- *
- ******************************************************************************/
-bool bta_hl_find_mcl_idx(uint8_t app_idx, const RawAddress& p_bd_addr,
- uint8_t* p_mcl_idx) {
- bool found = false;
- uint8_t i;
-
- for (i = 0; i < BTA_HL_NUM_MCLS; i++) {
- if (bta_hl_cb.acb[app_idx].mcb[i].in_use &&
- bta_hl_cb.acb[app_idx].mcb[i].bd_addr == p_bd_addr) {
- found = true;
- *p_mcl_idx = i;
- break;
- }
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- if (!found) {
- APPL_TRACE_DEBUG("bta_hl_find_mcl_idx found=%d idx=%d", found, i);
- }
-#endif
- return found;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_find_mdl_idx_using_handle
- *
- * Description This function finds the MDL control block index based on
- * the MDL handle
- *
- * Returns bool true-found
- *
- ******************************************************************************/
-bool bta_hl_find_mdl_idx_using_handle(tBTA_HL_MDL_HANDLE mdl_handle,
- uint8_t* p_app_idx, uint8_t* p_mcl_idx,
- uint8_t* p_mdl_idx) {
- tBTA_HL_APP_CB* p_acb;
- tBTA_HL_MCL_CB* p_mcb;
- tBTA_HL_MDL_CB* p_dcb;
- bool found = false;
- uint8_t i, j, k;
-
- for (i = 0; i < BTA_HL_NUM_APPS; i++) {
- p_acb = BTA_HL_GET_APP_CB_PTR(i);
- if (p_acb->in_use) {
- for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
- p_mcb = BTA_HL_GET_MCL_CB_PTR(i, j);
- if (p_mcb->in_use) {
- for (k = 0; k < BTA_HL_NUM_MDLS_PER_MCL; k++) {
- p_dcb = BTA_HL_GET_MDL_CB_PTR(i, j, k);
- if (p_dcb->in_use) {
- if (p_dcb->mdl_handle == mdl_handle) {
- found = true;
- *p_app_idx = i;
- *p_mcl_idx = j;
- *p_mdl_idx = k;
- break;
- }
- }
- }
- }
- }
- }
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- if (!found) {
- APPL_TRACE_DEBUG(
- "bta_hl_find_mdl_idx_using_handle found=%d mdl_handle=%d ", found,
- mdl_handle);
- }
-#endif
- return found;
-}
-/*******************************************************************************
- *
- * Function bta_hl_is_the_first_reliable_existed
- *
- * Description This function checks whether the first reliable DCH channel
- * has been setup on the MCL or not
- *
- * Returns bool - true exist
- * false does not exist
- *
- ******************************************************************************/
-bool bta_hl_is_the_first_reliable_existed(uint8_t app_idx, uint8_t mcl_idx) {
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- bool is_existed = false;
- uint8_t i;
-
- for (i = 0; i < BTA_HL_NUM_MDLS_PER_MCL; i++) {
- if (p_mcb->mdl[i].in_use && p_mcb->mdl[i].is_the_first_reliable) {
- is_existed = true;
- break;
- }
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_is_the_first_reliable_existed is_existed=%d ",
- is_existed);
-#endif
- return is_existed;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_find_non_active_mdl_cfg
- *
- * Description This function finds a valid MDL configiration index and this
- * MDL ID is not active
- *
- * Returns bool - true found
- * false not found
- *
- ******************************************************************************/
-bool bta_hl_find_non_active_mdl_cfg(uint8_t app_idx, uint8_t start_mdl_cfg_idx,
- uint8_t* p_mdl_cfg_idx) {
- tBTA_HL_MCL_CB* p_mcb;
- tBTA_HL_MDL_CB* p_dcb;
- tBTA_HL_MDL_CFG* p_mdl;
- bool mdl_in_use;
- bool found = false;
- uint8_t i, j, k;
-
- for (i = start_mdl_cfg_idx; i < BTA_HL_NUM_MDL_CFGS; i++) {
- mdl_in_use = false;
- p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
- for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
- p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, j);
- if (p_mcb->in_use && p_mdl->peer_bd_addr == p_mcb->bd_addr) {
- for (k = 0; k < BTA_HL_NUM_MDLS_PER_MCL; k++) {
- p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, j, k);
-
- if (p_dcb->in_use && p_mdl->mdl_id == p_dcb->mdl_id) {
- mdl_in_use = true;
- break;
- }
- }
- }
-
- if (mdl_in_use) {
- break;
- }
- }
-
- if (!mdl_in_use) {
- *p_mdl_cfg_idx = i;
- found = true;
- break;
- }
- }
-
- return found;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_find_mdl_cfg_idx
- *
- * Description This function finds an available MDL configuration index
- *
- * Returns bool - true found
- * false not found
- *
- ******************************************************************************/
-bool bta_hl_find_avail_mdl_cfg_idx(uint8_t app_idx, UNUSED_ATTR uint8_t mcl_idx,
- uint8_t* p_mdl_cfg_idx) {
- tBTA_HL_MDL_CFG *p_mdl, *p_mdl1, *p_mdl2;
- uint8_t i;
- bool found = false;
- uint8_t first_mdl_cfg_idx, second_mdl_cfg_idx, older_mdl_cfg_idx;
- bool done;
-
- for (i = 0; i < BTA_HL_NUM_MDL_CFGS; i++) {
- p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
- if (!p_mdl->active) {
- /* found an unused space to store mdl cfg*/
- found = true;
- *p_mdl_cfg_idx = i;
- break;
- }
- }
-
- if (!found) {
- /* all available mdl cfg spaces are in use so we need to find the mdl cfg
- which is
- not currently in use and has the the oldest time stamp to remove*/
-
- found = true;
- if (bta_hl_find_non_active_mdl_cfg(app_idx, 0, &first_mdl_cfg_idx)) {
- if (bta_hl_find_non_active_mdl_cfg(
- app_idx, (uint8_t)(first_mdl_cfg_idx + 1), &second_mdl_cfg_idx)) {
- done = false;
- while (!done) {
- p_mdl1 = BTA_HL_GET_MDL_CFG_PTR(app_idx, first_mdl_cfg_idx);
- p_mdl2 = BTA_HL_GET_MDL_CFG_PTR(app_idx, second_mdl_cfg_idx);
-
- if (p_mdl1->time < p_mdl2->time) {
- older_mdl_cfg_idx = first_mdl_cfg_idx;
- } else {
- older_mdl_cfg_idx = second_mdl_cfg_idx;
- }
-
- if (bta_hl_find_non_active_mdl_cfg(app_idx,
- (uint8_t)(second_mdl_cfg_idx + 1),
- &second_mdl_cfg_idx)) {
- first_mdl_cfg_idx = older_mdl_cfg_idx;
- } else {
- done = true;
- }
- }
-
- *p_mdl_cfg_idx = older_mdl_cfg_idx;
-
- } else {
- *p_mdl_cfg_idx = first_mdl_cfg_idx;
- }
-
- } else {
- found = false;
- }
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- if (!found) {
- APPL_TRACE_DEBUG("bta_hl_find_avail_mdl_cfg_idx found=%d mdl_cfg_idx=%d ",
- found, *p_mdl_cfg_idx);
- }
-#endif
-
- return found;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_find_mdl_cfg_idx
- *
- * Description This function finds the MDL configuration index based on
- * the MDL ID
- *
- * Returns bool - true found
- * false not found
- *
- ******************************************************************************/
-bool bta_hl_find_mdl_cfg_idx(uint8_t app_idx, uint8_t mcl_idx,
- tBTA_HL_MDL_ID mdl_id, uint8_t* p_mdl_cfg_idx) {
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- tBTA_HL_MDL_CFG* p_mdl;
- uint8_t i;
- bool found = false;
-
- *p_mdl_cfg_idx = 0;
- for (i = 0; i < BTA_HL_NUM_MDL_CFGS; i++) {
- p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
- if (p_mdl->active)
- APPL_TRACE_DEBUG("bta_hl_find_mdl_cfg_idx: mdl_id =%d, p_mdl->mdl_id=%d",
- mdl_id, p_mdl->mdl_id);
- if (p_mdl->active && p_mcb->bd_addr == p_mdl->peer_bd_addr &&
- (p_mdl->mdl_id == mdl_id)) {
- found = true;
- *p_mdl_cfg_idx = i;
- break;
- }
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- if (!found) {
- APPL_TRACE_DEBUG("bta_hl_find_mdl_cfg_idx found=%d mdl_cfg_idx=%d ", found,
- i);
- }
-#endif
-
- return found;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_get_cur_time
- *
- * Description This function get the cuurent time value
- *
- * Returns bool - true found
- * false not found
- *
- ******************************************************************************/
-bool bta_hl_get_cur_time(uint8_t app_idx, uint8_t* p_cur_time) {
- tBTA_HL_MDL_CFG* p_mdl;
- uint8_t i, j, time_latest, time;
- bool found = false, result = true;
-
- for (i = 0; i < BTA_HL_NUM_MDL_CFGS; i++) {
- p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
- if (p_mdl->active) {
- found = true;
- time_latest = p_mdl->time;
- for (j = (i + 1); j < BTA_HL_NUM_MDL_CFGS; j++) {
- p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, j);
- if (p_mdl->active) {
- time = p_mdl->time;
- if (time > time_latest) {
- time_latest = time;
- }
- }
- }
- break;
- }
- }
-
- if (found) {
- if (time_latest < BTA_HL_MAX_TIME) {
- *p_cur_time = time_latest + 1;
- } else {
- /* need to wrap around */
- result = false;
- }
- } else {
- *p_cur_time = BTA_HL_MIN_TIME;
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- if (!result) {
- APPL_TRACE_DEBUG("bta_hl_get_cur_time result=%s cur_time=%d",
- (result ? "OK" : "FAIL"), *p_cur_time);
- }
-#endif
-
- return result;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_sort_cfg_time_idx
- *
- * Description This function sort the mdl configuration idx stored in array a
- * based on decending time value
- *
- * Returns bool - true found
- * false not found
- *
- ******************************************************************************/
-void bta_hl_sort_cfg_time_idx(uint8_t app_idx, uint8_t* a, uint8_t n) {
- tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
- uint8_t temp_time, temp_idx;
- int16_t i, j;
- for (i = 1; i < n; ++i) {
- temp_idx = a[i];
- temp_time = p_acb->mdl_cfg[temp_idx].time;
- j = i - 1;
- while ((j >= 0) && (temp_time < p_acb->mdl_cfg[a[j]].time)) {
- a[j + 1] = a[j];
- --j;
- }
- a[j + 1] = temp_idx;
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_compact_mdl_cfg_time
- *
- * Description This function finds the MDL configuration index based on
- * the MDL ID
- *
- * Returns bool - true found
- * false not found
- *
- ******************************************************************************/
-void bta_hl_compact_mdl_cfg_time(uint8_t app_idx, uint8_t mdep_id) {
- tBTA_HL_MDL_CFG* p_mdl;
- uint8_t i, time_min, cnt = 0;
- uint8_t s_arr[BTA_HL_NUM_MDL_CFGS];
-
- for (i = 0; i < BTA_HL_NUM_MDL_CFGS; i++) {
- p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
- if (p_mdl->active) {
- s_arr[cnt] = i;
- cnt++;
- }
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_compact_mdl_cfg_time cnt=%d ", cnt);
-#endif
-
- if (cnt) {
- bta_hl_sort_cfg_time_idx(app_idx, s_arr, cnt);
- time_min = BTA_HL_MIN_TIME;
- for (i = 0; i < cnt; i++) {
- p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, s_arr[i]);
- p_mdl->time = time_min + i;
- bta_hl_co_save_mdl(mdep_id, s_arr[i], p_mdl);
- }
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_is_mdl_exsit_in_mcl
- *
- * Description This function checks whether the MDL ID
- * has already existed in teh MCL or not
- *
- * Returns bool - true exist
- * false does not exist
- *
- ******************************************************************************/
-bool bta_hl_is_mdl_exsit_in_mcl(uint8_t app_idx, const RawAddress& bd_addr,
- tBTA_HL_MDL_ID mdl_id) {
- tBTA_HL_MDL_CFG* p_mdl;
- bool found = false;
- uint8_t i;
-
- for (i = 0; i < BTA_HL_NUM_MDL_CFGS; i++) {
- p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
- if (p_mdl->active && p_mdl->peer_bd_addr == bd_addr) {
- if (mdl_id != BTA_HL_DELETE_ALL_MDL_IDS) {
- if (p_mdl->mdl_id == mdl_id) {
- found = true;
- break;
- }
- } else {
- found = true;
- break;
- }
- }
- }
-
- return found;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_delete_mdl_cfg
- *
- * Description This function delete the specified MDL ID
- *
- * Returns bool - true Success
- * false Failed
- *
- ******************************************************************************/
-bool bta_hl_delete_mdl_cfg(uint8_t app_idx, const RawAddress& bd_addr,
- tBTA_HL_MDL_ID mdl_id) {
- tBTA_HL_MDL_CFG* p_mdl;
- bool success = false;
- uint8_t i;
-
- for (i = 0; i < BTA_HL_NUM_MDL_CFGS; i++) {
- p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
- if (p_mdl->active && p_mdl->peer_bd_addr == bd_addr) {
- if (mdl_id != BTA_HL_DELETE_ALL_MDL_IDS) {
- if (p_mdl->mdl_id == mdl_id) {
- bta_hl_co_delete_mdl(p_mdl->local_mdep_id, i);
- memset(p_mdl, 0, sizeof(tBTA_HL_MDL_CFG));
- success = true;
- break;
- }
- } else {
- bta_hl_co_delete_mdl(p_mdl->local_mdep_id, i);
- memset(p_mdl, 0, sizeof(tBTA_HL_MDL_CFG));
- success = true;
- }
- }
- }
-
- return success;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_is_mdl_value_valid
- *
- *
- * Description This function checks the specified MDL ID is in valid range.
- *
- * Returns bool - true Success
- * false Failed
- *
- * note: mdl_id range 0x0000 reserved,
- * 0x0001-oxFEFF dynamic range,
- * 0xFF00-0xFFFE reserved,
- * 0xFFFF indicates all MDLs (for delete operation only)
- *
- ******************************************************************************/
-bool bta_hl_is_mdl_value_valid(tBTA_HL_MDL_ID mdl_id) {
- bool status = true;
-
- if (mdl_id != BTA_HL_DELETE_ALL_MDL_IDS) {
- if (mdl_id != 0) {
- if (mdl_id > BTA_HL_MAX_MDL_VAL) {
- status = false;
- }
- } else {
- status = false;
- }
- }
-
- return status;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_find_mdep_cfg_idx
- *
- * Description This function finds the MDEP configuration index based
- * on the local MDEP ID
- *
- * Returns bool - true found
- * false not found
- *
- ******************************************************************************/
-bool bta_hl_find_mdep_cfg_idx(uint8_t app_idx, tBTA_HL_MDEP_ID local_mdep_id,
- uint8_t* p_mdep_cfg_idx) {
- tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
- tBTA_HL_SUP_FEATURE* p_sup_feature = &p_acb->sup_feature;
- bool found = false;
- uint8_t i;
-
- for (i = 0; i < p_sup_feature->num_of_mdeps; i++) {
- if (p_sup_feature->mdep[i].mdep_id == local_mdep_id) {
- found = true;
- *p_mdep_cfg_idx = i;
- break;
- }
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- if (!found) {
- APPL_TRACE_DEBUG(
- "bta_hl_find_mdep_cfg_idx found=%d mdep_idx=%d local_mdep_id=%d ",
- found, i, local_mdep_id);
- }
-#endif
- return found;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_find_rxtx_apdu_size
- *
- * Description This function finds the maximum APDU rx and tx sizes based on
- * the MDEP configuration data
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_find_rxtx_apdu_size(uint8_t app_idx, uint8_t mdep_cfg_idx,
- uint16_t* p_rx_apu_size,
- uint16_t* p_tx_apu_size) {
- tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
- tBTA_HL_MDEP_CFG* p_mdep_cfg;
- uint8_t i;
- uint16_t max_rx_apdu_size = 0, max_tx_apdu_size = 0;
-
- p_mdep_cfg = &p_acb->sup_feature.mdep[mdep_cfg_idx].mdep_cfg;
-
- for (i = 0; i < p_mdep_cfg->num_of_mdep_data_types; i++) {
- if (max_rx_apdu_size < p_mdep_cfg->data_cfg[i].max_rx_apdu_size) {
- max_rx_apdu_size = p_mdep_cfg->data_cfg[i].max_rx_apdu_size;
- }
-
- if (max_tx_apdu_size < p_mdep_cfg->data_cfg[i].max_tx_apdu_size) {
- max_tx_apdu_size = p_mdep_cfg->data_cfg[i].max_tx_apdu_size;
- }
- }
-
- *p_rx_apu_size = max_rx_apdu_size;
- *p_tx_apu_size = max_tx_apdu_size;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG(
- "bta_hl_find_rxtx_apdu_size max_rx_apdu_size=%d max_tx_apdu_size=%d ",
- max_rx_apdu_size, max_tx_apdu_size);
-#endif
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_validate_peer_cfg
- *
- * Description This function validates the peer DCH configuration
- *
- * Returns bool - true validation is successful
- * false validation failed
- *
- ******************************************************************************/
-bool bta_hl_validate_peer_cfg(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
- tBTA_HL_MDEP_ID peer_mdep_id,
- tBTA_HL_MDEP_ROLE peer_mdep_role,
- uint8_t sdp_idx) {
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
- tBTA_HL_SDP_REC* p_rec;
- bool peer_found = false;
- uint8_t i;
-
- APPL_TRACE_DEBUG("bta_hl_validate_peer_cfg sdp_idx=%d app_idx %d", sdp_idx,
- app_idx);
-
- if (p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID) {
- return true;
- }
-
- p_rec = &p_mcb->sdp.sdp_rec[sdp_idx];
- for (i = 0; i < p_rec->num_mdeps; i++) {
- APPL_TRACE_DEBUG("mdep_id %d peer_mdep_id %d", p_rec->mdep_cfg[i].mdep_id,
- peer_mdep_id);
- APPL_TRACE_DEBUG("mdep_role %d peer_mdep_role %d",
- p_rec->mdep_cfg[i].mdep_role, peer_mdep_role)
- if ((p_rec->mdep_cfg[i].mdep_id == peer_mdep_id) &&
- (p_rec->mdep_cfg[i].mdep_role == peer_mdep_role)) {
- peer_found = true;
-
- break;
- }
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- if (!peer_found) {
- APPL_TRACE_DEBUG("bta_hl_validate_peer_cfg failed num_mdeps=%d",
- p_rec->num_mdeps);
- }
-#endif
- return peer_found;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_chk_local_cfg
- *
- * Description This function check whether the local DCH configuration is OK.
- *
- * Returns tBTA_HL_STATUS - OK - local DCH configuration is OK
- * NO_FIRST_RELIABLE - the streaming DCH
- * configuration is not OK and
- * it needs to use reliable
- * DCH configuration
- *
- ******************************************************************************/
-tBTA_HL_STATUS bta_hl_chk_local_cfg(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdep_cfg_idx,
- tBTA_HL_DCH_CFG local_cfg) {
- tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
- tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
-
- if (mdep_cfg_idx &&
- (p_acb->sup_feature.mdep[mdep_cfg_idx].mdep_cfg.mdep_role ==
- BTA_HL_MDEP_ROLE_SOURCE) &&
- (!bta_hl_is_the_first_reliable_existed(app_idx, mcl_idx)) &&
- (local_cfg != BTA_HL_DCH_CFG_RELIABLE)) {
- status = BTA_HL_STATUS_NO_FIRST_RELIABLE;
- APPL_TRACE_ERROR("BTA_HL_STATUS_INVALID_DCH_CFG");
- }
-
- return status;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_validate_reconnect_params
- *
- * Description This function validates the reconnect parameters
- *
- * Returns bool - true validation is successful
- * false validation failed
- ******************************************************************************/
-bool bta_hl_validate_reconnect_params(uint8_t app_idx, uint8_t mcl_idx,
- tBTA_HL_API_DCH_RECONNECT* p_reconnect,
- uint8_t* p_mdep_cfg_idx,
- uint8_t* p_mdl_cfg_idx) {
- tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
- tBTA_HL_SUP_FEATURE* p_sup_feature = &p_acb->sup_feature;
- uint8_t num_mdeps;
- uint8_t mdl_cfg_idx;
- bool local_mdep_id_found = false;
- bool mdl_cfg_found = false;
- bool status = false;
- uint8_t i, in_use_mdl_idx = 0;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_validate_reconnect_params mdl_id=%d app_idx=%d",
- p_reconnect->mdl_id, app_idx);
-#endif
- if (bta_hl_find_mdl_cfg_idx(app_idx, mcl_idx, p_reconnect->mdl_id,
- &mdl_cfg_idx)) {
- mdl_cfg_found = true;
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- if (!mdl_cfg_found) {
- APPL_TRACE_DEBUG("mdl_cfg_found not found");
- }
-#endif
-
- if (mdl_cfg_found) {
- num_mdeps = p_sup_feature->num_of_mdeps;
- for (i = 0; i < num_mdeps; i++) {
- if (p_sup_feature->mdep[i].mdep_id ==
- p_acb->mdl_cfg[mdl_cfg_idx].local_mdep_id) {
- local_mdep_id_found = true;
- *p_mdep_cfg_idx = i;
- *p_mdl_cfg_idx = mdl_cfg_idx;
- break;
- }
- }
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- if (!local_mdep_id_found) {
- APPL_TRACE_DEBUG("local_mdep_id not found");
- }
-#endif
-
- if (local_mdep_id_found) {
- if (!bta_hl_find_mdl_idx(app_idx, mcl_idx, p_reconnect->mdl_id,
- &in_use_mdl_idx)) {
- status = true;
- } else {
- APPL_TRACE_ERROR("mdl_id=%d is curreltly in use", p_reconnect->mdl_id);
- }
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- if (!status) {
- APPL_TRACE_DEBUG(
- "Reconnect validation failed local_mdep_id found=%d mdl_cfg_idx "
- "found=%d in_use_mdl_idx=%d ",
- local_mdep_id_found, mdl_cfg_found, in_use_mdl_idx);
- }
-#endif
- return status;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_find_avail_mcl_idx
- *
- * Returns bool - true found
- * false not found
- *
- ******************************************************************************/
-bool bta_hl_find_avail_mcl_idx(uint8_t app_idx, uint8_t* p_mcl_idx) {
- bool found = false;
- uint8_t i;
-
- for (i = 0; i < BTA_HL_NUM_MCLS; i++) {
- if (!bta_hl_cb.acb[app_idx].mcb[i].in_use) {
- found = true;
- *p_mcl_idx = i;
- break;
- }
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- if (!found) {
- APPL_TRACE_DEBUG("bta_hl_find_avail_mcl_idx found=%d idx=%d", found, i);
- }
-#endif
- return found;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_find_avail_mdl_idx
- *
- * Description This function finds an available MDL control block index
- *
- * Returns bool - true found
- * false not found
- *
- ******************************************************************************/
-bool bta_hl_find_avail_mdl_idx(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t* p_mdl_idx) {
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- bool found = false;
- uint8_t i;
-
- for (i = 0; i < BTA_HL_NUM_MDLS_PER_MCL; i++) {
- if (!p_mcb->mdl[i].in_use) {
- memset((void*)&p_mcb->mdl[i], 0, sizeof(tBTA_HL_MDL_CB));
- found = true;
- *p_mdl_idx = i;
- break;
- }
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- if (!found) {
- APPL_TRACE_DEBUG("bta_hl_find_avail_mdl_idx found=%d idx=%d", found, i);
- }
-#endif
- return found;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_is_a_duplicate_id
- *
- * Description This function finds the application has been used or not
- *
- * Returns bool - true the app_id is a duplicate ID
- * false not a duplicate ID
- ******************************************************************************/
-bool bta_hl_is_a_duplicate_id(uint8_t app_id) {
- bool is_duplicate = false;
- uint8_t i;
-
- for (i = 0; i < BTA_HL_NUM_APPS; i++) {
- if (bta_hl_cb.acb[i].in_use && (bta_hl_cb.acb[i].app_id == app_id)) {
- is_duplicate = true;
-
- break;
- }
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- if (is_duplicate) {
- APPL_TRACE_DEBUG("bta_hl_is_a_duplicate_id app_id=%d is_duplicate=%d",
- app_id, is_duplicate);
- }
-#endif
-
- return is_duplicate;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_find_avail_app_idx
- *
- * Description This function finds an available application control block index
- *
- * Returns bool - true found
- * false not found
- *
- ******************************************************************************/
-bool bta_hl_find_avail_app_idx(uint8_t* p_idx) {
- bool found = false;
- uint8_t i;
-
- for (i = 0; i < BTA_HL_NUM_APPS; i++) {
- if (!bta_hl_cb.acb[i].in_use) {
- found = true;
- *p_idx = i;
- break;
- }
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- if (!found) {
- APPL_TRACE_DEBUG("bta_hl_find_avail_app_idx found=%d app_idx=%d", found, i);
- }
-#endif
- return found;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_app_update
- *
- * Description This function registers an HDP application MCAP and DP
- *
- * Returns tBTA_HL_STATUS -registration status
- *
- ******************************************************************************/
-tBTA_HL_STATUS bta_hl_app_update(uint8_t app_id, bool is_register) {
- tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
- tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(0);
- tMCA_CS mca_cs;
- uint8_t i, mdep_idx, num_of_mdeps;
- uint8_t mdep_counter = 0;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_app_update app_id=%d", app_id);
-#endif
-
- if (is_register) {
- if ((status == BTA_HL_STATUS_OK) &&
- bta_hl_co_get_num_of_mdep(app_id, &num_of_mdeps)) {
- for (i = 0; i < num_of_mdeps; i++) {
- mca_cs.type = MCA_TDEP_DATA;
- mca_cs.max_mdl = BTA_HL_NUM_MDLS_PER_MDEP;
- mca_cs.p_data_cback = bta_hl_mcap_data_cback;
- /* Find the first available mdep index, and create a MDL Endpoint */
- // make a function later if needed
- for (mdep_idx = 1; mdep_idx < BTA_HL_NUM_MDEPS; mdep_idx++) {
- if (p_acb->sup_feature.mdep[mdep_idx].mdep_id == 0) {
- break; /* We found an available index */
- } else {
- mdep_counter++;
- }
- }
- /* If no available MDEPs, return error */
- if (mdep_idx == BTA_HL_NUM_MDEPS) {
- APPL_TRACE_ERROR("bta_hl_app_update: Out of MDEP IDs");
- status = BTA_HL_STATUS_MCAP_REG_FAIL;
- break;
- }
- if (MCA_CreateDep((tMCA_HANDLE)p_acb->app_handle,
- &(p_acb->sup_feature.mdep[mdep_idx].mdep_id),
- &mca_cs) == MCA_SUCCESS) {
- if (bta_hl_co_get_mdep_config(
- app_id, mdep_idx, mdep_counter,
- p_acb->sup_feature.mdep[mdep_idx].mdep_id,
- &p_acb->sup_feature.mdep[mdep_idx].mdep_cfg)) {
- p_acb->sup_feature.mdep[mdep_idx].ori_app_id = app_id;
- APPL_TRACE_DEBUG("mdep idx %d id %d ori_app_id %d num data type %d",
- mdep_idx,
- p_acb->sup_feature.mdep[mdep_idx].mdep_id,
- p_acb->sup_feature.mdep[mdep_idx].ori_app_id,
- p_acb->sup_feature.mdep[mdep_idx]
- .mdep_cfg.num_of_mdep_data_types);
- if (p_acb->sup_feature.mdep[mdep_idx].mdep_cfg.mdep_role ==
- BTA_HL_MDEP_ROLE_SOURCE) {
- p_acb->sup_feature.app_role_mask |= BTA_HL_MDEP_ROLE_MASK_SOURCE;
- } else if (p_acb->sup_feature.mdep[mdep_idx].mdep_cfg.mdep_role ==
- BTA_HL_MDEP_ROLE_SINK) {
- p_acb->sup_feature.app_role_mask |= BTA_HL_MDEP_ROLE_MASK_SINK;
- } else {
- APPL_TRACE_ERROR(
- "bta_hl_app_registration: Invalid Role %d",
- p_acb->sup_feature.mdep[mdep_idx].mdep_cfg.mdep_role);
- status = BTA_HL_STATUS_MDEP_CO_FAIL;
- break;
- }
- } else {
- APPL_TRACE_ERROR("bta_hl_app_registration: Cfg callout failed");
- status = BTA_HL_STATUS_MDEP_CO_FAIL;
- break;
- }
- } else {
- APPL_TRACE_ERROR("bta_hl_app_registration: MCA_CreateDep failed");
- status = BTA_HL_STATUS_MCAP_REG_FAIL;
- break;
- }
- }
- p_acb->sup_feature.num_of_mdeps += num_of_mdeps;
- APPL_TRACE_DEBUG("num_of_mdeps %d", p_acb->sup_feature.num_of_mdeps);
-
- if ((status == BTA_HL_STATUS_OK) &&
- (p_acb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SOURCE)) {
- p_acb->sup_feature.advertize_source_sdp =
- bta_hl_co_advrtise_source_sdp(app_id);
- }
-
- if ((status == BTA_HL_STATUS_OK) &&
- (!bta_hl_co_get_echo_config(app_id, &p_acb->sup_feature.echo_cfg))) {
- status = BTA_HL_STATUS_ECHO_CO_FAIL;
- }
-
- if ((status == BTA_HL_STATUS_OK) &&
- (!bta_hl_co_load_mdl_config(app_id, BTA_HL_NUM_MDL_CFGS,
- &p_acb->mdl_cfg[0]))) {
- status = BTA_HL_STATUS_MDL_CFG_CO_FAIL;
- }
- } else {
- status = BTA_HL_STATUS_MDEP_CO_FAIL;
- }
- } else {
- for (i = 1; i < BTA_HL_NUM_MDEPS; i++) {
- if (p_acb->sup_feature.mdep[i].ori_app_id == app_id) {
- APPL_TRACE_DEBUG("Found index %", i);
-
- if (MCA_DeleteDep((tMCA_HANDLE)p_acb->app_handle,
- (p_acb->sup_feature.mdep[i].mdep_id)) !=
- MCA_SUCCESS) {
- APPL_TRACE_ERROR("Error deregistering");
- status = BTA_HL_STATUS_MCAP_REG_FAIL;
- return status;
- }
- memset(&p_acb->sup_feature.mdep[i], 0, sizeof(tBTA_HL_MDEP));
- }
- }
- }
-
- if (status == BTA_HL_STATUS_OK) {
- /* Register/Update MDEP(s) in SDP Record */
- status = bta_hl_sdp_update(app_id);
- }
- /* else do cleanup */
-
- return status;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_app_registration
- *
- * Description This function registers an HDP application MCAP and DP
- *
- * Returns tBTA_HL_STATUS -registration status
- *
- ******************************************************************************/
-tBTA_HL_STATUS bta_hl_app_registration(uint8_t app_idx) {
- tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
- tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
- tMCA_REG reg;
- tMCA_CS mca_cs;
- uint8_t i, num_of_mdeps;
- uint8_t mdep_counter = 0;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_app_registration app_idx=%d", app_idx);
-#endif
-
- reg.ctrl_psm = p_acb->ctrl_psm;
- reg.data_psm = p_acb->data_psm;
- reg.sec_mask = p_acb->sec_mask;
- reg.rsp_tout = BTA_HL_MCAP_RSP_TOUT;
-
- p_acb->app_handle =
- (tBTA_HL_APP_HANDLE)MCA_Register(®, bta_hl_mcap_ctrl_cback);
- if (p_acb->app_handle != 0) {
- mca_cs.type = MCA_TDEP_ECHO;
- mca_cs.max_mdl = BTA_HL_NUM_MDLS_PER_MDEP;
- mca_cs.p_data_cback = bta_hl_mcap_data_cback;
-
- if (MCA_CreateDep((tMCA_HANDLE)p_acb->app_handle,
- &(p_acb->sup_feature.mdep[0].mdep_id),
- &mca_cs) == MCA_SUCCESS) {
- if (p_acb->sup_feature.mdep[0].mdep_id != BTA_HL_ECHO_TEST_MDEP_ID) {
- status = BTA_HL_STATUS_MCAP_REG_FAIL;
- APPL_TRACE_ERROR("BAD MDEP ID for echo test mdep_id=%d",
- p_acb->sup_feature.mdep[0].mdep_id);
- }
- } else {
- status = BTA_HL_STATUS_MCAP_REG_FAIL;
- APPL_TRACE_ERROR("MCA_CreateDep for echo test(mdep_id=0) failed");
- }
-
- if ((status == BTA_HL_STATUS_OK) &&
- bta_hl_co_get_num_of_mdep(p_acb->app_id, &num_of_mdeps)) {
- p_acb->sup_feature.num_of_mdeps = num_of_mdeps + 1;
-
- for (i = 1; i < p_acb->sup_feature.num_of_mdeps; i++) {
- mca_cs.type = MCA_TDEP_DATA;
- mca_cs.max_mdl = BTA_HL_NUM_MDLS_PER_MDEP;
- mca_cs.p_data_cback = bta_hl_mcap_data_cback;
-
- if (MCA_CreateDep((tMCA_HANDLE)p_acb->app_handle,
- &(p_acb->sup_feature.mdep[i].mdep_id),
- &mca_cs) == MCA_SUCCESS) {
- if (bta_hl_co_get_mdep_config(p_acb->app_id, i, mdep_counter,
- p_acb->sup_feature.mdep[i].mdep_id,
- &p_acb->sup_feature.mdep[i].mdep_cfg)) {
- if (p_acb->sup_feature.mdep[i].mdep_cfg.mdep_role ==
- BTA_HL_MDEP_ROLE_SOURCE) {
- p_acb->sup_feature.app_role_mask |= BTA_HL_MDEP_ROLE_MASK_SOURCE;
- } else if (p_acb->sup_feature.mdep[i].mdep_cfg.mdep_role ==
- BTA_HL_MDEP_ROLE_SINK) {
- p_acb->sup_feature.app_role_mask |= BTA_HL_MDEP_ROLE_MASK_SINK;
- } else {
- status = BTA_HL_STATUS_MDEP_CO_FAIL;
- break;
- }
- p_acb->sup_feature.mdep[i].ori_app_id = p_acb->app_id;
- APPL_TRACE_DEBUG("index %d ori_app_id %d", i,
- p_acb->sup_feature.mdep[i].ori_app_id);
- } else {
- status = BTA_HL_STATUS_MDEP_CO_FAIL;
- break;
- }
- } else {
- status = BTA_HL_STATUS_MCAP_REG_FAIL;
- break;
- }
- }
-
- if ((status == BTA_HL_STATUS_OK) &&
- (p_acb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SOURCE)) {
- /* this is a source only applciation */
- p_acb->sup_feature.advertize_source_sdp =
- bta_hl_co_advrtise_source_sdp(p_acb->app_id);
- }
-
- if ((status == BTA_HL_STATUS_OK) &&
- (!bta_hl_co_get_echo_config(p_acb->app_id,
- &p_acb->sup_feature.echo_cfg))) {
- status = BTA_HL_STATUS_ECHO_CO_FAIL;
- }
-
- if ((status == BTA_HL_STATUS_OK) &&
- (!bta_hl_co_load_mdl_config(p_acb->app_id, BTA_HL_NUM_MDL_CFGS,
- &p_acb->mdl_cfg[0]))) {
- status = BTA_HL_STATUS_MDL_CFG_CO_FAIL;
- }
- } else {
- status = BTA_HL_STATUS_MDEP_CO_FAIL;
- }
- } else {
- status = BTA_HL_STATUS_MCAP_REG_FAIL;
- }
-
- if (status == BTA_HL_STATUS_OK) {
- status = bta_hl_sdp_register(app_idx);
- }
-
- return status;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_discard_data
- *
- * Description This function discard an HDP event
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_discard_data(uint16_t event, tBTA_HL_DATA* p_data) {
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_ERROR("BTA HL Discard event=%s", bta_hl_evt_code(event));
-
-#endif
-
- switch (event) {
- case BTA_HL_API_SEND_DATA_EVT:
- break;
-
- case BTA_HL_MCA_RCV_DATA_EVT:
- osi_free_and_reset((void**)&p_data->mca_rcv_data_evt.p_pkt);
- break;
-
- default:
- /*Nothing to free*/
- break;
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_save_mdl_cfg
- *
- * Description This function saves the MDL configuration
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_save_mdl_cfg(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx) {
- tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
- uint8_t mdl_cfg_idx;
- tBTA_HL_MDL_ID mdl_id;
- bool found = true;
- tBTA_HL_MDL_CFG mdl_cfg;
- tBTA_HL_MDEP* p_mdep_cfg;
- tBTA_HL_L2CAP_CFG_INFO l2cap_cfg;
- uint8_t time_val = 0;
- mdl_id = p_dcb->mdl_id;
- if (!bta_hl_find_mdl_cfg_idx(app_idx, mcl_idx, mdl_id, &mdl_cfg_idx)) {
- if (!bta_hl_find_avail_mdl_cfg_idx(app_idx, mcl_idx, &mdl_cfg_idx)) {
- APPL_TRACE_ERROR("No space to save the MDL config");
- found = false; /*no space available*/
- }
- }
-
- if (found) {
- bta_hl_get_l2cap_cfg(p_dcb->mdl_handle, &l2cap_cfg);
- if (!bta_hl_get_cur_time(app_idx, &time_val)) {
- bta_hl_compact_mdl_cfg_time(app_idx, p_dcb->local_mdep_id);
- bta_hl_get_cur_time(app_idx, &time_val);
- }
- mdl_cfg.active = true;
- mdl_cfg.time = time_val;
- mdl_cfg.mdl_id = p_dcb->mdl_id;
- mdl_cfg.dch_mode = p_dcb->dch_mode;
- mdl_cfg.mtu = l2cap_cfg.mtu;
- mdl_cfg.fcs = l2cap_cfg.fcs;
-
- mdl_cfg.peer_bd_addr = p_mcb->bd_addr;
- mdl_cfg.local_mdep_id = p_dcb->local_mdep_id;
- p_mdep_cfg = &p_acb->sup_feature.mdep[p_dcb->local_mdep_cfg_idx];
- mdl_cfg.local_mdep_role = p_mdep_cfg->mdep_cfg.mdep_role;
- memcpy(&p_acb->mdl_cfg[mdl_cfg_idx], &mdl_cfg, sizeof(tBTA_HL_MDL_CFG));
- bta_hl_co_save_mdl(mdl_cfg.local_mdep_id, mdl_cfg_idx, &mdl_cfg);
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- if (found) {
- if (p_dcb->mtu != l2cap_cfg.mtu) {
- APPL_TRACE_WARNING(
- "MCAP and L2CAP peer mtu size out of sync from MCAP mtu=%d from "
- "l2cap mtu=%d",
- p_dcb->mtu, l2cap_cfg.mtu);
- }
- APPL_TRACE_DEBUG("bta_hl_save_mdl_cfg saved=%d", found);
- APPL_TRACE_DEBUG("Saved. L2cap cfg mdl_id=%d mtu=%d fcs=%d dch_mode=%d",
- mdl_cfg.mdl_id, mdl_cfg.mtu, mdl_cfg.fcs,
- mdl_cfg.dch_mode);
- }
-#endif
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_set_dch_chan_cfg
- *
- * Description This function setups the L2CAP DCH channel configuration
- *
- * Returns void
- ******************************************************************************/
-void bta_hl_set_dch_chan_cfg(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
- tBTA_HL_DATA* p_data) {
- tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
- uint8_t l2cap_mode = L2CAP_FCR_ERTM_MODE;
- tBTA_HL_SUP_FEATURE* p_sup_feature = &p_acb->sup_feature;
- uint8_t local_mdep_cfg_idx = p_dcb->local_mdep_cfg_idx;
-
- switch (p_dcb->dch_oper) {
- case BTA_HL_DCH_OP_LOCAL_RECONNECT:
- case BTA_HL_DCH_OP_REMOTE_RECONNECT:
- if (p_dcb->dch_mode == BTA_HL_DCH_MODE_STREAMING)
- l2cap_mode = L2CAP_FCR_STREAM_MODE;
- break;
- case BTA_HL_DCH_OP_LOCAL_OPEN:
- if (p_data->mca_evt.mca_data.create_cfm.cfg == BTA_HL_DCH_CFG_STREAMING)
- l2cap_mode = L2CAP_FCR_STREAM_MODE;
- break;
- case BTA_HL_DCH_OP_REMOTE_OPEN:
- if (p_dcb->local_cfg == BTA_HL_DCH_CFG_STREAMING)
- l2cap_mode = L2CAP_FCR_STREAM_MODE;
- break;
- default:
- APPL_TRACE_ERROR("Invalid dch oper=%d for set dch chan cfg",
- p_dcb->dch_oper);
- break;
- }
- p_dcb->chnl_cfg.fcr_opt.mode = l2cap_mode;
- p_dcb->chnl_cfg.fcr_opt.mps = bta_hl_set_mps(p_dcb->max_rx_apdu_size);
- p_dcb->chnl_cfg.fcr_opt.tx_win_sz = bta_hl_set_tx_win_size(
- p_dcb->max_rx_apdu_size, p_dcb->chnl_cfg.fcr_opt.mps);
- p_dcb->chnl_cfg.fcr_opt.max_transmit = BTA_HL_L2C_MAX_TRANSMIT;
- p_dcb->chnl_cfg.fcr_opt.rtrans_tout = BTA_HL_L2C_RTRANS_TOUT;
- p_dcb->chnl_cfg.fcr_opt.mon_tout = BTA_HL_L2C_MON_TOUT;
-
- p_dcb->chnl_cfg.user_rx_buf_size =
- bta_hl_set_user_rx_buf_size(p_dcb->max_rx_apdu_size);
- p_dcb->chnl_cfg.user_tx_buf_size =
- bta_hl_set_user_tx_buf_size(p_dcb->max_tx_apdu_size);
- p_dcb->chnl_cfg.fcr_rx_buf_size = L2CAP_INVALID_ERM_BUF_SIZE;
- p_dcb->chnl_cfg.fcr_tx_buf_size = L2CAP_INVALID_ERM_BUF_SIZE;
- p_dcb->chnl_cfg.data_mtu = p_dcb->max_rx_apdu_size;
-
- p_dcb->chnl_cfg.fcs = BTA_HL_MCA_NO_FCS;
- if (local_mdep_cfg_idx != BTA_HL_ECHO_TEST_MDEP_CFG_IDX) {
- if (p_sup_feature->mdep[local_mdep_cfg_idx].mdep_cfg.mdep_role ==
- BTA_HL_MDEP_ROLE_SOURCE) {
- p_dcb->chnl_cfg.fcs = BTA_HL_DEFAULT_SOURCE_FCS;
- }
- } else {
- p_dcb->chnl_cfg.fcs = BTA_HL_MCA_USE_FCS;
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("L2CAP Params l2cap_mode[3-ERTM 4-STREAM]=%d", l2cap_mode);
- APPL_TRACE_DEBUG("Use FCS =%s mtu=%d",
- ((p_dcb->chnl_cfg.fcs & 1) ? "YES" : "NO"),
- p_dcb->chnl_cfg.data_mtu);
- APPL_TRACE_DEBUG(
- "tx_win_sz=%d, max_transmit=%d, rtrans_tout=%d, mon_tout=%d, mps=%d",
- p_dcb->chnl_cfg.fcr_opt.tx_win_sz, p_dcb->chnl_cfg.fcr_opt.max_transmit,
- p_dcb->chnl_cfg.fcr_opt.rtrans_tout, p_dcb->chnl_cfg.fcr_opt.mon_tout,
- p_dcb->chnl_cfg.fcr_opt.mps);
-
- APPL_TRACE_DEBUG(
- "USER rx_buf_size=%d, tx_buf_size=%d, FCR rx_buf_size=%d, tx_buf_size=%d",
- p_dcb->chnl_cfg.user_rx_buf_size, p_dcb->chnl_cfg.user_tx_buf_size,
- p_dcb->chnl_cfg.fcr_rx_buf_size, p_dcb->chnl_cfg.fcr_tx_buf_size);
-
-#endif
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_get_l2cap_cfg
- *
- * Description This function get the current L2CAP channel configuration
- *
- * Returns bool - true - operation is successful
- ******************************************************************************/
-bool bta_hl_get_l2cap_cfg(tBTA_HL_MDL_HANDLE mdl_hnd,
- tBTA_HL_L2CAP_CFG_INFO* p_cfg) {
- bool success = false;
- uint16_t lcid;
- tL2CAP_CFG_INFO* p_our_cfg;
- tL2CAP_CH_CFG_BITS our_cfg_bits;
- tL2CAP_CFG_INFO* p_peer_cfg;
- tL2CAP_CH_CFG_BITS peer_cfg_bits;
-
- lcid = MCA_GetL2CapChannel((tMCA_DL)mdl_hnd);
- if (lcid && L2CA_GetCurrentConfig(lcid, &p_our_cfg, &our_cfg_bits,
- &p_peer_cfg, &peer_cfg_bits)) {
- p_cfg->fcs = BTA_HL_MCA_NO_FCS;
- if (our_cfg_bits & L2CAP_CH_CFG_MASK_FCS) {
- p_cfg->fcs |= p_our_cfg->fcs;
- } else {
- p_cfg->fcs = BTA_HL_MCA_USE_FCS;
- }
-
- if (p_cfg->fcs != BTA_HL_MCA_USE_FCS) {
- if (peer_cfg_bits & L2CAP_CH_CFG_MASK_FCS) {
- p_cfg->fcs |= p_peer_cfg->fcs;
- } else {
- p_cfg->fcs = BTA_HL_MCA_USE_FCS;
- }
- }
-
- p_cfg->mtu = 0;
- if (peer_cfg_bits & L2CAP_CH_CFG_MASK_MTU) {
- p_cfg->mtu = p_peer_cfg->mtu;
- } else {
- p_cfg->mtu = L2CAP_DEFAULT_MTU;
- }
- success = true;
- } else {
- p_cfg->mtu = L2CAP_DEFAULT_MTU;
- p_cfg->fcs = BTA_HL_L2C_NO_FCS;
- }
-
-#if (BTA_HL_DEBUG == TRUE)
- if (!success) {
- APPL_TRACE_DEBUG("bta_hl_get_l2cap_cfg success=%d mdl=%d lcid=%d", success,
- mdl_hnd, lcid);
- APPL_TRACE_DEBUG("l2cap mtu=%d fcs=%d", p_cfg->mtu, p_cfg->fcs);
- }
-#endif
-
- return success;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_validate_chan_cfg
- *
- * Description This function validates the L2CAP channel configuration
- *
- * Returns bool - true - validation is successful
- ******************************************************************************/
-bool bta_hl_validate_chan_cfg(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t mdl_idx) {
- tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
- tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
- bool success = false;
- uint8_t mdl_cfg_idx = 0;
- tBTA_HL_L2CAP_CFG_INFO l2cap_cfg;
- bool get_l2cap_result, get_mdl_result;
-
- get_l2cap_result = bta_hl_get_l2cap_cfg(p_dcb->mdl_handle, &l2cap_cfg);
- get_mdl_result =
- bta_hl_find_mdl_cfg_idx(app_idx, mcl_idx, p_dcb->mdl_id, &mdl_cfg_idx);
-
- if (get_l2cap_result && get_mdl_result) {
- if ((p_acb->mdl_cfg[mdl_cfg_idx].mtu <= l2cap_cfg.mtu) &&
- (p_acb->mdl_cfg[mdl_cfg_idx].fcs == l2cap_cfg.fcs) &&
- (p_acb->mdl_cfg[mdl_cfg_idx].dch_mode == p_dcb->dch_mode)) {
- success = true;
- }
- }
-
-#if (BTA_HL_DEBUG == TRUE)
-
- if (p_dcb->mtu != l2cap_cfg.mtu) {
- APPL_TRACE_WARNING(
- "MCAP and L2CAP peer mtu size out of sync from MCAP mtu=%d from l2cap "
- "mtu=%d",
- p_dcb->mtu, l2cap_cfg.mtu);
- }
-
- if (!success) {
- APPL_TRACE_DEBUG(
- "bta_hl_validate_chan_cfg success=%d app_idx=%d mcl_idx=%d mdl_idx=%d",
- success, app_idx, mcl_idx, mdl_idx);
- APPL_TRACE_DEBUG("Cur. L2cap cfg mtu=%d fcs=%d dch_mode=%d", l2cap_cfg.mtu,
- l2cap_cfg.fcs, p_dcb->dch_mode);
- APPL_TRACE_DEBUG("From saved: L2cap cfg mtu=%d fcs=%d dch_mode=%d",
- p_acb->mdl_cfg[mdl_cfg_idx].mtu,
- p_acb->mdl_cfg[mdl_cfg_idx].fcs,
- p_acb->mdl_cfg[mdl_cfg_idx].dch_mode);
- }
-#endif
-
- return success;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_is_cong_on
- *
- * Description This function checks whether the congestion condition is on.
- *
- * Returns bool - true DCH is congested
- * false not congested
- *
- ******************************************************************************/
-bool bta_hl_is_cong_on(uint8_t app_id, const RawAddress& bd_addr,
- tBTA_HL_MDL_ID mdl_id)
-
-{
- tBTA_HL_MDL_CB* p_dcb;
- uint8_t app_idx = 0, mcl_idx, mdl_idx;
- bool cong_status = true;
-
- if (bta_hl_find_app_idx(app_id, &app_idx)) {
- if (bta_hl_find_mcl_idx(app_idx, bd_addr, &mcl_idx)) {
- if (bta_hl_find_mdl_idx(app_idx, mcl_idx, mdl_id, &mdl_idx)) {
- p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
- cong_status = p_dcb->cong;
- }
- }
- }
-
- return cong_status;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_check_cch_close
- *
- * Description This function checks whether there is a pending CCH close
- * request or not
- *
- * Returns void
- ******************************************************************************/
-void bta_hl_check_cch_close(uint8_t app_idx, uint8_t mcl_idx,
- tBTA_HL_DATA* p_data, bool check_dch_setup) {
- tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- tBTA_HL_MDL_CB* p_dcb;
- uint8_t mdl_idx;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_check_cch_close cch_close_dch_oper=%d",
- p_mcb->cch_close_dch_oper);
-#endif
-
- if (p_mcb->cch_oper == BTA_HL_CCH_OP_LOCAL_CLOSE) {
- if (check_dch_setup &&
- bta_hl_find_dch_setup_mdl_idx(app_idx, mcl_idx, &mdl_idx)) {
- p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
- if (!p_mcb->rsp_tout) {
- p_mcb->cch_close_dch_oper = BTA_HL_CCH_CLOSE_OP_DCH_ABORT;
-
- if (!p_dcb->abort_oper) {
- p_dcb->abort_oper |= BTA_HL_ABORT_CCH_CLOSE_MASK;
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_ABORT_EVT,
- p_data);
- }
- } else {
- p_mcb->cch_close_dch_oper = BTA_HL_CCH_CLOSE_OP_DCH_CLOSE;
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
- BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
- }
- } else if (bta_hl_find_an_active_mdl_idx(app_idx, mcl_idx, &mdl_idx)) {
- p_mcb->cch_close_dch_oper = BTA_HL_CCH_CLOSE_OP_DCH_CLOSE;
- bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_EVT,
- p_data);
- } else {
- p_mcb->cch_close_dch_oper = BTA_HL_CCH_CLOSE_OP_DCH_NONE;
- bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_CLOSE_EVT, p_data);
- }
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_clean_app
- *
- * Description Cleans up the HDP application resources and control block
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_clean_app(uint8_t app_idx) {
- tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
- int i, num_act_apps = 0;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_clean_app");
-#endif
- MCA_Deregister((tMCA_HANDLE)p_acb->app_handle);
-
- if (p_acb->sdp_handle) SDP_DeleteRecord(p_acb->sdp_handle);
-
- memset((void*)p_acb, 0, sizeof(tBTA_HL_APP_CB));
-
- /* check any application is still active */
- for (i = 0; i < BTA_HL_NUM_APPS; i++) {
- p_acb = BTA_HL_GET_APP_CB_PTR(i);
- if (p_acb->in_use) num_act_apps++;
- }
-
- if (!num_act_apps) {
- bta_sys_remove_uuid(UUID_SERVCLASS_HDP_PROFILE);
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_check_deregistration
- *
- * Description This function checks whether there is a pending deregistration
- * request or not
- *
- * Returns void
- ******************************************************************************/
-void bta_hl_check_deregistration(uint8_t app_idx, tBTA_HL_DATA* p_data) {
- tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
- tBTA_HL_MCL_CB* p_mcb;
- uint8_t mcl_idx;
- tBTA_HL evt_data;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_check_deregistration");
-#endif
-
- if (p_acb->deregistering) {
- if (bta_hl_find_an_in_use_mcl_idx(app_idx, &mcl_idx)) {
- p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
- if (p_mcb->cch_oper != BTA_HL_CCH_OP_LOCAL_CLOSE) {
- if (p_mcb->cch_state == BTA_HL_CCH_OPENING_ST)
- p_mcb->force_close_local_cch_opening = true;
- p_mcb->cch_oper = BTA_HL_CCH_OP_LOCAL_CLOSE;
- APPL_TRACE_DEBUG("p_mcb->force_close_local_cch_opening=%d",
- p_mcb->force_close_local_cch_opening);
- bta_hl_check_cch_close(app_idx, mcl_idx, p_data, true);
- }
- } else {
- /* all cchs are closed */
- evt_data.dereg_cfm.app_handle = p_acb->app_handle;
- evt_data.dereg_cfm.app_id = p_data->api_dereg.app_id;
- evt_data.dereg_cfm.status = BTA_HL_STATUS_OK;
- p_acb->p_cback(BTA_HL_DEREGISTER_CFM_EVT, (tBTA_HL*)&evt_data);
- bta_hl_clean_app(app_idx);
- bta_hl_check_disable(p_data);
- }
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_check_disable
- *
- * Description This function checks whether there is a pending disable
- * request or not
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_check_disable(tBTA_HL_DATA* p_data) {
- tBTA_HL_CB* p_cb = &bta_hl_cb;
- tBTA_HL_APP_CB* p_acb;
- uint8_t app_idx;
- tBTA_HL_CTRL evt_data;
-
-#if (BTA_HL_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hl_check_disable");
-#endif
-
- if (bta_hl_cb.disabling) {
- if (bta_hl_find_an_in_use_app_idx(&app_idx)) {
- p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
- if (!p_acb->deregistering) {
- p_acb->deregistering = true;
- bta_hl_check_deregistration(app_idx, p_data);
- }
- } else {
- /* all apps are deregistered */
- bta_sys_deregister(BTA_ID_HL);
- evt_data.disable_cfm.status = BTA_HL_STATUS_OK;
- if (p_cb->p_ctrl_cback)
- p_cb->p_ctrl_cback(BTA_HL_CTRL_DISABLE_CFM_EVT,
- (tBTA_HL_CTRL*)&evt_data);
- memset((void*)p_cb, 0, sizeof(tBTA_HL_CB));
- }
- }
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_build_abort_cfm
- *
- * Description This function builds the abort confirmation event data
- *
- * Returns None
- *
- ******************************************************************************/
-void bta_hl_build_abort_cfm(tBTA_HL* p_evt_data, tBTA_HL_APP_HANDLE app_handle,
- tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_STATUS status) {
- p_evt_data->dch_abort_cfm.status = status;
- p_evt_data->dch_abort_cfm.mcl_handle = mcl_handle;
- p_evt_data->dch_abort_cfm.app_handle = app_handle;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_build_abort_ind
- *
- * Description This function builds the abort indication event data
- *
- * Returns None
- *
- ******************************************************************************/
-void bta_hl_build_abort_ind(tBTA_HL* p_evt_data, tBTA_HL_APP_HANDLE app_handle,
- tBTA_HL_MCL_HANDLE mcl_handle) {
- p_evt_data->dch_abort_ind.mcl_handle = mcl_handle;
- p_evt_data->dch_abort_ind.app_handle = app_handle;
-}
-/*******************************************************************************
- *
- * Function bta_hl_build_close_cfm
- *
- * Description This function builds the close confirmation event data
- *
- * Returns None
- *
- ******************************************************************************/
-void bta_hl_build_dch_close_cfm(tBTA_HL* p_evt_data,
- tBTA_HL_APP_HANDLE app_handle,
- tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_MDL_HANDLE mdl_handle,
- tBTA_HL_STATUS status) {
- p_evt_data->dch_close_cfm.status = status;
- p_evt_data->dch_close_cfm.mdl_handle = mdl_handle;
- p_evt_data->dch_close_cfm.mcl_handle = mcl_handle;
- p_evt_data->dch_close_cfm.app_handle = app_handle;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_build_dch_close_ind
- *
- * Description This function builds the close indication event data
- *
- * Returns None
- *
- ******************************************************************************/
-void bta_hl_build_dch_close_ind(tBTA_HL* p_evt_data,
- tBTA_HL_APP_HANDLE app_handle,
- tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_MDL_HANDLE mdl_handle,
- bool intentional) {
- p_evt_data->dch_close_ind.mdl_handle = mdl_handle;
- p_evt_data->dch_close_ind.mcl_handle = mcl_handle;
- p_evt_data->dch_close_ind.app_handle = app_handle;
- p_evt_data->dch_close_ind.intentional = intentional;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_build_send_data_cfm
- *
- * Description This function builds the send data confirmation event data
- *
- * Returns None
- *
- ******************************************************************************/
-void bta_hl_build_send_data_cfm(tBTA_HL* p_evt_data,
- tBTA_HL_APP_HANDLE app_handle,
- tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_MDL_HANDLE mdl_handle,
- tBTA_HL_STATUS status) {
- p_evt_data->dch_send_data_cfm.mdl_handle = mdl_handle;
- p_evt_data->dch_send_data_cfm.mcl_handle = mcl_handle;
- p_evt_data->dch_send_data_cfm.app_handle = app_handle;
- p_evt_data->dch_send_data_cfm.status = status;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_build_rcv_data_ind
- *
- * Description This function builds the received data indication event data
- *
- * Returns None
- *
- ******************************************************************************/
-void bta_hl_build_rcv_data_ind(tBTA_HL* p_evt_data,
- tBTA_HL_APP_HANDLE app_handle,
- tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_MDL_HANDLE mdl_handle) {
- p_evt_data->dch_rcv_data_ind.mdl_handle = mdl_handle;
- p_evt_data->dch_rcv_data_ind.mcl_handle = mcl_handle;
- p_evt_data->dch_rcv_data_ind.app_handle = app_handle;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_build_cch_open_cfm
- *
- * Description This function builds the CCH open confirmation event data
- *
- * Returns None
- *
- ******************************************************************************/
-void bta_hl_build_cch_open_cfm(tBTA_HL* p_evt_data, uint8_t app_id,
- tBTA_HL_APP_HANDLE app_handle,
- tBTA_HL_MCL_HANDLE mcl_handle,
- const RawAddress& bd_addr,
- tBTA_HL_STATUS status) {
- p_evt_data->cch_open_cfm.app_id = app_id;
- p_evt_data->cch_open_cfm.app_handle = app_handle;
- p_evt_data->cch_open_cfm.mcl_handle = mcl_handle;
- p_evt_data->cch_open_cfm.bd_addr = bd_addr;
- p_evt_data->cch_open_cfm.status = status;
- APPL_TRACE_DEBUG("bta_hl_build_cch_open_cfm: status=%d", status);
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_build_cch_open_ind
- *
- * Description This function builds the CCH open indication event data
- *
- * Returns None
- *
- ******************************************************************************/
-void bta_hl_build_cch_open_ind(tBTA_HL* p_evt_data,
- tBTA_HL_APP_HANDLE app_handle,
- tBTA_HL_MCL_HANDLE mcl_handle,
- const RawAddress& bd_addr) {
- p_evt_data->cch_open_ind.app_handle = app_handle;
- p_evt_data->cch_open_ind.mcl_handle = mcl_handle;
- p_evt_data->cch_open_ind.bd_addr = bd_addr;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_build_cch_close_cfm
- *
- * Description This function builds the CCH close confirmation event data
- *
- * Returns None
- *
- ******************************************************************************/
-void bta_hl_build_cch_close_cfm(tBTA_HL* p_evt_data,
- tBTA_HL_APP_HANDLE app_handle,
- tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_STATUS status) {
- p_evt_data->cch_close_cfm.mcl_handle = mcl_handle;
- p_evt_data->cch_close_cfm.app_handle = app_handle;
- p_evt_data->cch_close_cfm.status = status;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_build_cch_close_ind
- *
- * Description This function builds the CCH colse indication event data
- *
- * Returns None
- *
- ******************************************************************************/
-void bta_hl_build_cch_close_ind(tBTA_HL* p_evt_data,
- tBTA_HL_APP_HANDLE app_handle,
- tBTA_HL_MCL_HANDLE mcl_handle,
- bool intentional) {
- p_evt_data->cch_close_ind.mcl_handle = mcl_handle;
- p_evt_data->cch_close_ind.app_handle = app_handle;
- p_evt_data->cch_close_ind.intentional = intentional;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_build_dch_open_cfm
- *
- * Description This function builds the DCH open confirmation event data
- *
- * Returns None
- *
- ******************************************************************************/
-void bta_hl_build_dch_open_cfm(tBTA_HL* p_evt_data,
- tBTA_HL_APP_HANDLE app_handle,
- tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_MDL_HANDLE mdl_handle,
- tBTA_HL_MDEP_ID local_mdep_id,
- tBTA_HL_MDL_ID mdl_id, tBTA_HL_DCH_MODE dch_mode,
- bool first_reliable, uint16_t mtu,
- tBTA_HL_STATUS status)
-
-{
- p_evt_data->dch_open_cfm.mdl_handle = mdl_handle;
- p_evt_data->dch_open_cfm.mcl_handle = mcl_handle;
- p_evt_data->dch_open_cfm.app_handle = app_handle;
- p_evt_data->dch_open_cfm.local_mdep_id = local_mdep_id;
- p_evt_data->dch_open_cfm.mdl_id = mdl_id;
- p_evt_data->dch_open_cfm.dch_mode = dch_mode;
- p_evt_data->dch_open_cfm.first_reliable = first_reliable;
- p_evt_data->dch_open_cfm.mtu = mtu;
- p_evt_data->dch_open_cfm.status = status;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_build_sdp_query_cfm
- *
- * Description This function builds the SDP query indication event data
- *
- * Returns None
- *
- ******************************************************************************/
-void bta_hl_build_sdp_query_cfm(tBTA_HL* p_evt_data, uint8_t app_id,
- tBTA_HL_APP_HANDLE app_handle,
- const RawAddress& bd_addr, tBTA_HL_SDP* p_sdp,
- tBTA_HL_STATUS status)
-
-{
- APPL_TRACE_DEBUG("bta_hl_build_sdp_query_cfm: app_id = %d, app_handle=%d",
- app_id, app_handle);
- p_evt_data->sdp_query_cfm.app_id = app_id;
- p_evt_data->sdp_query_cfm.app_handle = app_handle;
- p_evt_data->sdp_query_cfm.bd_addr = bd_addr;
- p_evt_data->sdp_query_cfm.p_sdp = p_sdp;
- p_evt_data->sdp_query_cfm.status = status;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_build_delete_mdl_cfm
- *
- * Description This function builds the delete MDL confirmation event data
- *
- * Returns None
- *
- ******************************************************************************/
-void bta_hl_build_delete_mdl_cfm(tBTA_HL* p_evt_data,
- tBTA_HL_APP_HANDLE app_handle,
- tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_MDL_ID mdl_id, tBTA_HL_STATUS status)
-
-{
- p_evt_data->delete_mdl_cfm.mcl_handle = mcl_handle;
- p_evt_data->delete_mdl_cfm.app_handle = app_handle;
- p_evt_data->delete_mdl_cfm.mdl_id = mdl_id;
- p_evt_data->delete_mdl_cfm.status = status;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_build_echo_test_cfm
- *
- * Description This function builds the echo test confirmation event data
- *
- * Returns None
- *
- ******************************************************************************/
-void bta_hl_build_echo_test_cfm(tBTA_HL* p_evt_data,
- tBTA_HL_APP_HANDLE app_handle,
- tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_STATUS status) {
- p_evt_data->echo_test_cfm.mcl_handle = mcl_handle;
- p_evt_data->echo_test_cfm.app_handle = app_handle;
- p_evt_data->echo_test_cfm.status = status;
-}
-
-/*****************************************************************************
- * Debug Functions
- ****************************************************************************/
-#if (BTA_HL_DEBUG == TRUE)
-
-/*******************************************************************************
- *
- * Function bta_hl_status_code
- *
- * Description get the status string pointer
- *
- * Returns char * - status string pointer
- *
- ******************************************************************************/
-const char* bta_hl_status_code(tBTA_HL_STATUS status) {
- switch (status) {
- case BTA_HL_STATUS_OK:
- return "BTA_HL_STATUS_OK";
- case BTA_HL_STATUS_FAIL:
- return "BTA_HL_STATUS_FAIL";
- case BTA_HL_STATUS_ABORTED:
- return "BTA_HL_STATUS_ABORTED";
- case BTA_HL_STATUS_NO_RESOURCE:
- return "BTA_HL_STATUS_NO_RESOURCE";
- case BTA_HL_STATUS_LAST_ITEM:
- return "BTA_HL_STATUS_LAST_ITEM";
- case BTA_HL_STATUS_DUPLICATE_APP_ID:
- return "BTA_HL_STATUS_DUPLICATE_APP_ID";
- case BTA_HL_STATUS_INVALID_APP_HANDLE:
- return "BTA_HL_STATUS_INVALID_APP_HANDLE";
- case BTA_HL_STATUS_INVALID_MCL_HANDLE:
- return "BTA_HL_STATUS_INVALID_MCL_HANDLE";
- case BTA_HL_STATUS_MCAP_REG_FAIL:
- return "BTA_HL_STATUS_MCAP_REG_FAIL";
- case BTA_HL_STATUS_MDEP_CO_FAIL:
- return "BTA_HL_STATUS_MDEP_CO_FAIL";
- case BTA_HL_STATUS_ECHO_CO_FAIL:
- return "BTA_HL_STATUS_ECHO_CO_FAIL";
- case BTA_HL_STATUS_MDL_CFG_CO_FAIL:
- return "BTA_HL_STATUS_MDL_CFG_CO_FAIL";
- case BTA_HL_STATUS_SDP_NO_RESOURCE:
- return "BTA_HL_STATUS_SDP_NO_RESOURCE";
- case BTA_HL_STATUS_SDP_FAIL:
- return "BTA_HL_STATUS_SDP_FAIL";
- case BTA_HL_STATUS_NO_CCH:
- return "BTA_HL_STATUS_NO_CCH";
- case BTA_HL_STATUS_NO_MCL:
- return "BTA_HL_STATUS_NO_MCL";
-
- case BTA_HL_STATUS_NO_FIRST_RELIABLE:
- return "BTA_HL_STATUS_NO_FIRST_RELIABLE";
- case BTA_HL_STATUS_INVALID_DCH_CFG:
- return "BTA_HL_STATUS_INVALID_DCH_CFG";
- case BTA_HL_STATUS_INVALID_BD_ADDR:
- return "BTA_HL_STATUS_INVALID_BD_ADDR";
- case BTA_HL_STATUS_INVALID_RECONNECT_CFG:
- return "BTA_HL_STATUS_INVALID_RECONNECT_CFG";
- case BTA_HL_STATUS_ECHO_TEST_BUSY:
- return "BTA_HL_STATUS_ECHO_TEST_BUSY";
- case BTA_HL_STATUS_INVALID_LOCAL_MDEP_ID:
- return "BTA_HL_STATUS_INVALID_LOCAL_MDEP_ID";
- case BTA_HL_STATUS_INVALID_MDL_ID:
- return "BTA_HL_STATUS_INVALID_MDL_ID";
- case BTA_HL_STATUS_NO_MDL_ID_FOUND:
- return "BTA_HL_STATUS_NO_MDL_ID_FOUND";
- case BTA_HL_STATUS_DCH_BUSY:
- return "BTA_HL_STATUS_DCH_BUSY";
- default:
- return "Unknown status code";
- }
-}
-/*******************************************************************************
- *
- * Function bta_hl_evt_code
- *
- * Description Maps HL event code to the corresponding event string
- *
- * Returns string pointer for the associated event name
- *
- ******************************************************************************/
-const char* bta_hl_evt_code(tBTA_HL_INT_EVT evt_code) {
- switch (evt_code) {
- case BTA_HL_CCH_OPEN_EVT:
- return "BTA_HL_CCH_OPEN_EVT";
- case BTA_HL_CCH_SDP_OK_EVT:
- return "BTA_HL_CCH_SDP_OK_EVT";
- case BTA_HL_CCH_SDP_FAIL_EVT:
- return "BTA_HL_CCH_SDP_FAIL_EVT";
- case BTA_HL_MCA_CONNECT_IND_EVT:
- return "BTA_HL_MCA_CONNECT_IND_EVT";
- case BTA_HL_MCA_DISCONNECT_IND_EVT:
- return "BTA_HL_MCA_DISCONNECT_IND_EVT";
-
- case BTA_HL_CCH_CLOSE_EVT:
- return "BTA_HL_CCH_CLOSE_EVT";
- case BTA_HL_CCH_CLOSE_CMPL_EVT:
- return "BTA_HL_CCH_CLOSE_CMPL_EVT";
- case BTA_HL_DCH_OPEN_EVT:
- return "BTA_HL_DCH_OPEN_EVT";
- case BTA_HL_MCA_CREATE_IND_EVT:
- return "BTA_HL_MCA_CREATE_IND_EVT";
- case BTA_HL_MCA_CREATE_CFM_EVT:
- return "BTA_HL_MCA_CREATE_CFM_EVT";
- case BTA_HL_MCA_OPEN_IND_EVT:
- return "BTA_HL_MCA_OPEN_IND_EVT";
- case BTA_HL_MCA_OPEN_CFM_EVT:
- return "BTA_HL_MCA_OPEN_CFM_EVT";
- case BTA_HL_DCH_CLOSE_EVT:
- return "BTA_HL_DCH_CLOSE_EVT";
- case BTA_HL_MCA_CLOSE_IND_EVT:
- return "BTA_HL_MCA_CLOSE_IND_EVT";
- case BTA_HL_MCA_CLOSE_CFM_EVT:
- return "BTA_HL_MCA_CLOSE_CFM_EVT";
- case BTA_HL_API_SEND_DATA_EVT:
- return "BTA_HL_API_SEND_DATA_EVT";
- case BTA_HL_MCA_RCV_DATA_EVT:
- return "BTA_HL_MCA_RCV_DATA_EVT";
- case BTA_HL_DCH_CLOSE_CMPL_EVT:
- return "BTA_HL_DCH_CLOSE_CMPL_EVT";
-
- case BTA_HL_API_ENABLE_EVT:
- return "BTA_HL_API_ENABLE_EVT";
- case BTA_HL_API_DISABLE_EVT:
- return "BTA_HL_API_DISABLE_EVT";
- case BTA_HL_API_UPDATE_EVT:
- return "BTA_HL_API_UPDATE_EVT";
- case BTA_HL_API_REGISTER_EVT:
- return "BTA_HL_API_REGISTER_EVT";
- case BTA_HL_API_DEREGISTER_EVT:
- return "BTA_HL_API_DEREGISTER_EVT";
-
- case BTA_HL_API_CCH_OPEN_EVT:
- return "BTA_HL_API_CCH_OPEN_EVT";
-
- case BTA_HL_API_CCH_CLOSE_EVT:
- return "BTA_HL_API_CCH_CLOSE_EVT";
- case BTA_HL_API_DCH_OPEN_EVT:
- return "BTA_HL_API_DCH_OPEN_EVT";
-
- case BTA_HL_API_DCH_RECONNECT_EVT:
- return "BTA_HL_API_DCH_RECONNECT_EVT";
- case BTA_HL_API_DCH_CLOSE_EVT:
- return "BTA_HL_API_DCH_CLOSE_EVT";
- case BTA_HL_API_DELETE_MDL_EVT:
- return "BTA_HL_API_DELETE_MDL_EVT";
- case BTA_HL_API_DCH_ABORT_EVT:
- return "BTA_HL_API_DCH_ABORT_EVT";
-
- case BTA_HL_DCH_RECONNECT_EVT:
- return "BTA_HL_DCH_RECONNECT_EVT";
- case BTA_HL_DCH_SDP_INIT_EVT:
- return "BTA_HL_DCH_SDP_INIT_EVT";
- case BTA_HL_DCH_SDP_FAIL_EVT:
- return "BTA_HL_DCH_SDP_FAIL_EVT";
- case BTA_HL_API_DCH_ECHO_TEST_EVT:
- return "BTA_HL_API_DCH_ECHO_TEST_EVT";
- case BTA_HL_DCH_CLOSE_ECHO_TEST_EVT:
- return "BTA_HL_DCH_CLOSE_ECHO_TEST_EVT";
- case BTA_HL_MCA_RECONNECT_IND_EVT:
- return "BTA_HL_MCA_RECONNECT_IND_EVT";
- case BTA_HL_MCA_RECONNECT_CFM_EVT:
- return "BTA_HL_MCA_RECONNECT_CFM_EVT";
- case BTA_HL_API_DCH_CREATE_RSP_EVT:
- return "BTA_HL_API_DCH_CREATE_RSP_EVT";
- case BTA_HL_DCH_ABORT_EVT:
- return "BTA_HL_DCH_ABORT_EVT";
- case BTA_HL_MCA_ABORT_IND_EVT:
- return "BTA_HL_MCA_ABORT_IND_EVT";
- case BTA_HL_MCA_ABORT_CFM_EVT:
- return "BTA_HL_MCA_ABORT_CFM_EVT";
- case BTA_HL_MCA_DELETE_IND_EVT:
- return "BTA_HL_MCA_DELETE_IND_EVT";
- case BTA_HL_MCA_DELETE_CFM_EVT:
- return "BTA_HL_MCA_DELETE_CFM_EVT";
- case BTA_HL_MCA_CONG_CHG_EVT:
- return "BTA_HL_MCA_CONG_CHG_EVT";
- case BTA_HL_CI_GET_TX_DATA_EVT:
- return "BTA_HL_CI_GET_TX_DATA_EVT";
- case BTA_HL_CI_PUT_RX_DATA_EVT:
- return "BTA_HL_CI_PUT_RX_DATA_EVT";
- case BTA_HL_CI_GET_ECHO_DATA_EVT:
- return "BTA_HL_CI_GET_ECHO_DATA_EVT";
- case BTA_HL_DCH_ECHO_TEST_EVT:
- return "BTA_HL_DCH_ECHO_TEST_EVT";
- case BTA_HL_CI_PUT_ECHO_DATA_EVT:
- return "BTA_HL_CI_PUT_ECHO_DATA_EVT";
- case BTA_HL_API_SDP_QUERY_EVT:
- return "BTA_HL_API_SDP_QUERY_EVT";
- case BTA_HL_SDP_QUERY_OK_EVT:
- return "BTA_HL_SDP_QUERY_OK_EVT";
- case BTA_HL_SDP_QUERY_FAIL_EVT:
- return "BTA_HL_SDP_QUERY_FAIL_EVT";
- case BTA_HL_MCA_RSP_TOUT_IND_EVT:
- return "BTA_HL_MCA_RSP_TOUT_IND_EVT";
-
- default:
- return "Unknown HL event code";
- }
-}
-
-#endif /* Debug Functions */
-#endif // HL_INCLUDED
diff --git a/bta/include/bta_ag_api.h b/bta/include/bta_ag_api.h
index b968ae6..c5d4f36 100644
--- a/bta/include/bta_ag_api.h
+++ b/bta/include/bta_ag_api.h
@@ -264,6 +264,12 @@
#define BTA_AG_BTRH_READ 3 /* Read the current value */
#define BTA_AG_BTRH_NO_RESP 4 /* Not in RH States (reply to read) */
+/* clip type constants */
+#define BTA_AG_CLIP_TYPE_MIN 128
+#define BTA_AG_CLIP_TYPE_MAX 175
+#define BTA_AG_CLIP_TYPE_DEFAULT 129
+#define BTA_AG_CLIP_TYPE_VOIP 255
+
/* ASCII character string of arguments to the AT command or result */
#ifndef BTA_AG_AT_MAX_LEN
#define BTA_AG_AT_MAX_LEN 256
diff --git a/bta/include/bta_api.h b/bta/include/bta_api.h
index 9d4693e..d58f183 100644
--- a/bta/include/bta_api.h
+++ b/bta/include/bta_api.h
@@ -50,11 +50,9 @@
* Service ID
*
* NOTES: When you add a new Service ID for BTA AND require to change the value
- * of BTA_MAX_SERVICE_ID,
- * make sure that the correct security ID of the new service from
- * Security service definitions (btm_api.h)
- * should be added to bta_service_id_to_btm_srv_id_lkup_tbl table in
- * bta_dm_act.c.
+ * of BTA_MAX_SERVICE_ID, make sure that the correct security ID of the new
+ * service from Security service definitions (btm_api.h) should be added to
+ * bta_service_id_to_btm_srv_id_lkup_tbl table in bta_dm_act.cc
*/
#define BTA_RES_SERVICE_ID 0 /* Reserved */
@@ -485,9 +483,9 @@
typedef uint8_t tBTA_DM_BLE_LOCAL_KEY_MASK;
typedef struct {
- BT_OCTET16 ir;
- BT_OCTET16 irk;
- BT_OCTET16 dhk;
+ Octet16 ir;
+ Octet16 irk;
+ Octet16 dhk;
} tBTA_BLE_LOCAL_ID_KEYS;
#define BTA_DM_SEC_GRANTED BTA_SUCCESS
@@ -512,7 +510,7 @@
RawAddress bd_addr; /* BD address peer device. */
BD_NAME bd_name; /* Name of peer device. */
bool key_present; /* Valid link key value in key element */
- LINK_KEY key; /* Link key associated with peer device. */
+ LinkKey key; /* Link key associated with peer device. */
uint8_t key_type; /* The type of Link Key */
bool success; /* true of authentication succeeded, false if failed. */
uint8_t fail_reason; /* The HCI reason/error code for when success=false */
@@ -689,7 +687,7 @@
tBTA_DM_BLE_SEC_REQ ble_req; /* BLE SMP related request */
tBTA_DM_BLE_KEY ble_key; /* BLE SMP keys used when pairing */
tBTA_BLE_LOCAL_ID_KEYS ble_id_keys; /* IR event */
- BT_OCTET16 ble_er; /* ER event data */
+ Octet16 ble_er; /* ER event data */
} tBTA_DM_SEC;
/* Security callback */
@@ -877,7 +875,7 @@
#ifndef BTA_DM_PM_PARK_IDX
#define BTA_DM_PM_PARK_IDX \
- 5 /* the actual index to bta_dm_pm_md[] for PARK mode */
+ 6 /* the actual index to bta_dm_pm_md[] for PARK mode */
#endif
#ifndef BTA_DM_PM_SNIFF_A2DP_IDX
@@ -968,6 +966,13 @@
#define BTA_DM_PM_SNIFF5_TIMEOUT 0
#endif
+#ifndef BTA_DM_PM_SNIFF6_MAX
+#define BTA_DM_PM_SNIFF6_MAX 18
+#define BTA_DM_PM_SNIFF6_MIN 14
+#define BTA_DM_PM_SNIFF6_ATTEMPT 1
+#define BTA_DM_PM_SNIFF6_TIMEOUT 0
+#endif
+
#ifndef BTA_DM_PM_PARK_MAX
#define BTA_DM_PM_PARK_MAX 800
#define BTA_DM_PM_PARK_MIN 400
@@ -1282,9 +1287,10 @@
*
******************************************************************************/
extern void BTA_DmAddDevice(const RawAddress& bd_addr, DEV_CLASS dev_class,
- LINK_KEY link_key, tBTA_SERVICE_MASK trusted_mask,
- bool is_trusted, uint8_t key_type,
- tBTA_IO_CAP io_cap, uint8_t pin_length);
+ const LinkKey& link_key,
+ tBTA_SERVICE_MASK trusted_mask, bool is_trusted,
+ uint8_t key_type, tBTA_IO_CAP io_cap,
+ uint8_t pin_length);
/*******************************************************************************
*
@@ -1376,11 +1382,6 @@
extern void BTA_DmBleSecurityGrant(const RawAddress& bd_addr,
tBTA_DM_BLE_SEC_GRANT res);
-/**
- * Set BLE connectable mode to auto connect
- */
-extern void BTA_DmBleStartAutoConn();
-
/*******************************************************************************
*
* Function BTA_DmBlePasskeyReply
diff --git a/bta/include/bta_av_api.h b/bta/include/bta_av_api.h
index 4c0539e..418f012 100644
--- a/bta/include/bta_av_api.h
+++ b/bta/include/bta_av_api.h
@@ -96,11 +96,6 @@
#define BTA_AV_NUM_STRS 6
#endif
-#ifndef BTA_AV_MAX_A2DP_MTU
-/*#define BTA_AV_MAX_A2DP_MTU 668 //224 (DM5) * 3 - 4(L2CAP header) */
-#define BTA_AV_MAX_A2DP_MTU 1008
-#endif
-
/* operation id list for BTA_AvRemoteCmd */
typedef uint8_t tBTA_AV_RC;
diff --git a/bta/include/bta_closure_api.h b/bta/include/bta_closure_api.h
deleted file mode 100644
index c57f07f..0000000
--- a/bta/include/bta_closure_api.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2016 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.
- *
- ******************************************************************************/
-
-#ifndef BTA_CLOSURE_API_H
-#define BTA_CLOSURE_API_H
-
-#include <base/bind.h>
-#include <base/callback_forward.h>
-#include <base/location.h>
-
-#include <hardware/bluetooth.h>
-
-/*
- * This method post a closure for execution on bta thread. Please see
- * documentation at
- * https://www.chromium.org/developers/coding-style/important-abstractions-and-data-structures
- * for how to handle dynamic memory ownership/smart pointers with base::Owned(),
- * base::Passed(), base::ConstRef() and others.
- */
-bt_status_t do_in_bta_thread(const tracked_objects::Location& from_here,
- const base::Closure& task);
-bt_status_t do_in_bta_thread_once(const tracked_objects::Location& from_here,
- base::OnceClosure task);
-
-#endif /* BTA_CLOSURE_API_H */
diff --git a/bta/include/bta_dm_ci.h b/bta/include/bta_dm_ci.h
index dbbace6..a89854a 100644
--- a/bta/include/bta_dm_ci.h
+++ b/bta/include/bta_dm_ci.h
@@ -55,7 +55,7 @@
*
******************************************************************************/
extern void bta_dm_ci_rmt_oob(bool accept, const RawAddress& bd_addr,
- BT_OCTET16 c, BT_OCTET16 r);
+ const Octet16& c, const Octet16& r);
/*******************************************************************************
*
* Function bta_dm_sco_ci_data_ready
diff --git a/bta/include/bta_dm_co.h b/bta/include/bta_dm_co.h
index ddb9d22..4561cbf 100644
--- a/bta/include/bta_dm_co.h
+++ b/bta/include/bta_dm_co.h
@@ -105,7 +105,7 @@
* Returns void.
*
******************************************************************************/
-extern void bta_dm_co_loc_oob(bool valid, BT_OCTET16 c, BT_OCTET16 r);
+extern void bta_dm_co_loc_oob(bool valid, const Octet16& c, const Octet16& r);
/*******************************************************************************
*
@@ -207,7 +207,7 @@
*
******************************************************************************/
extern void bta_dm_co_ble_load_local_keys(
- tBTA_DM_BLE_LOCAL_KEY_MASK* p_key_mask, BT_OCTET16 er,
+ tBTA_DM_BLE_LOCAL_KEY_MASK* p_key_mask, Octet16* p_er,
tBTA_BLE_LOCAL_ID_KEYS* p_id_keys);
#endif /* BTA_DM_CO_H */
diff --git a/bta/include/bta_gatt_api.h b/bta/include/bta_gatt_api.h
index 4dcc76a..9176501 100644
--- a/bta/include/bta_gatt_api.h
+++ b/bta/include/bta_gatt_api.h
@@ -25,6 +25,7 @@
#ifndef BTA_GATT_API_H
#define BTA_GATT_API_H
+#include "bta/gatt/database.h"
#include "bta_api.h"
#include "gatt_api.h"
@@ -53,6 +54,7 @@
#define BTA_GATTC_CLOSE_EVT 5 /* GATTC close request status event */
#define BTA_GATTC_SEARCH_CMPL_EVT 6 /* GATT discovery complete event */
#define BTA_GATTC_SEARCH_RES_EVT 7 /* GATT discovery result event */
+#define BTA_GATTC_SRVC_DISC_DONE_EVT 8 /* GATT service discovery done event */
#define BTA_GATTC_NOTIF_EVT 10 /* GATT attribute notification event */
#define BTA_GATTC_EXEC_EVT 12 /* execute write complete event */
#define BTA_GATTC_ACL_EVT 13 /* ACL up event */
@@ -97,25 +99,6 @@
uint16_t handles[BTA_GATTC_MULTI_MAX];
} tBTA_GATTC_MULTI;
-enum {
- BTA_GATTC_ATTR_TYPE_INCL_SRVC,
- BTA_GATTC_ATTR_TYPE_CHAR,
- BTA_GATTC_ATTR_TYPE_CHAR_DESCR,
- BTA_GATTC_ATTR_TYPE_SRVC
-};
-typedef uint8_t tBTA_GATTC_ATTR_TYPE;
-
-typedef struct {
- bluetooth::Uuid uuid;
- uint16_t s_handle;
- uint16_t e_handle; /* used for service only */
- uint8_t attr_type;
- uint8_t id;
- uint8_t prop; /* used when attribute type is characteristic */
- bool is_primary; /* used when attribute type is service */
- uint16_t incl_srvc_handle; /* used when attribute type is included service */
-} tBTA_GATTC_NV_ATTR;
-
/* callback data structure */
typedef struct {
tGATT_STATUS status;
@@ -374,41 +357,6 @@
/* Server callback function */
typedef void(tBTA_GATTS_CBACK)(tBTA_GATTS_EVT event, tBTA_GATTS* p_data);
-struct tBTA_GATTC_CHARACTERISTIC;
-struct tBTA_GATTC_DESCRIPTOR;
-struct tBTA_GATTC_INCLUDED_SVC;
-
-struct tBTA_GATTC_SERVICE {
- bluetooth::Uuid uuid;
- bool is_primary;
- uint16_t handle;
- uint16_t s_handle;
- uint16_t e_handle;
- std::vector<tBTA_GATTC_CHARACTERISTIC> characteristics;
- std::vector<tBTA_GATTC_INCLUDED_SVC> included_svc;
-};
-
-struct tBTA_GATTC_CHARACTERISTIC {
- bluetooth::Uuid uuid;
- // this is used only during discovery, and not persisted in cache
- uint16_t declaration_handle;
- uint16_t value_handle;
- tGATT_CHAR_PROP properties;
- std::vector<tBTA_GATTC_DESCRIPTOR> descriptors;
-};
-
-struct tBTA_GATTC_DESCRIPTOR {
- bluetooth::Uuid uuid;
- uint16_t handle;
-};
-
-struct tBTA_GATTC_INCLUDED_SVC {
- bluetooth::Uuid uuid;
- uint16_t handle;
- tBTA_GATTC_SERVICE* owning_service; /* owning service*/
- tBTA_GATTC_SERVICE* included_service;
-};
-
/*****************************************************************************
* External Function Declarations
****************************************************************************/
@@ -529,7 +477,7 @@
* PTS tests.
*/
extern void BTA_GATTC_DiscoverServiceByUuid(uint16_t conn_id,
- const bluetooth::Uuid& p_srvc_uuid);
+ const bluetooth::Uuid& srvc_uuid);
/*******************************************************************************
*
@@ -540,10 +488,10 @@
*
* Parameters conn_id: connection ID which identify the server.
*
- * Returns returns list of tBTA_GATTC_SERVICE or NULL.
+ * Returns returns list of gatt::Service or NULL.
*
******************************************************************************/
-extern const std::vector<tBTA_GATTC_SERVICE>* BTA_GATTC_GetServices(
+extern const std::vector<gatt::Service>* BTA_GATTC_GetServices(
uint16_t conn_id);
/*******************************************************************************
@@ -556,11 +504,11 @@
* Parameters conn_id: connection ID which identify the server.
* handle: characteristic handle
*
- * Returns returns pointer to tBTA_GATTC_CHARACTERISTIC or NULL.
+ * Returns returns pointer to gatt::Characteristic or NULL.
*
******************************************************************************/
-extern const tBTA_GATTC_CHARACTERISTIC* BTA_GATTC_GetCharacteristic(
- uint16_t conn_id, uint16_t handle);
+extern const gatt::Characteristic* BTA_GATTC_GetCharacteristic(uint16_t conn_id,
+ uint16_t handle);
/*******************************************************************************
*
@@ -572,21 +520,21 @@
* Parameters conn_id: connection ID which identify the server.
* handle: descriptor handle
*
- * Returns returns pointer to tBTA_GATTC_DESCRIPTOR or NULL.
+ * Returns returns pointer to gatt::Descriptor or NULL.
*
******************************************************************************/
-extern const tBTA_GATTC_DESCRIPTOR* BTA_GATTC_GetDescriptor(uint16_t conn_id,
- uint16_t handle);
+extern const gatt::Descriptor* BTA_GATTC_GetDescriptor(uint16_t conn_id,
+ uint16_t handle);
/* Return characteristic that owns descriptor with handle equal to |handle|, or
* NULL */
-extern const tBTA_GATTC_CHARACTERISTIC* BTA_GATTC_GetOwningCharacteristic(
+extern const gatt::Characteristic* BTA_GATTC_GetOwningCharacteristic(
uint16_t conn_id, uint16_t handle);
/* Return service that owns descriptor or characteristic with handle equal to
* |handle|, or NULL */
-extern const tBTA_GATTC_SERVICE* BTA_GATTC_GetOwningService(uint16_t conn_id,
- uint16_t handle);
+extern const gatt::Service* BTA_GATTC_GetOwningService(uint16_t conn_id,
+ uint16_t handle);
/*******************************************************************************
*
diff --git a/bta/include/bta_hearing_aid_api.h b/bta/include/bta_hearing_aid_api.h
index 6595060..9026262 100644
--- a/bta/include/bta_hearing_aid_api.h
+++ b/bta/include/bta_hearing_aid_api.h
@@ -20,18 +20,177 @@
#include <base/callback_forward.h>
#include <hardware/bt_hearing_aid.h>
+#include <deque>
#include <future>
+#include <vector>
+
+constexpr uint16_t HEARINGAID_MAX_NUM_UUIDS = 1;
constexpr uint16_t HA_INTERVAL_10_MS = 10;
constexpr uint16_t HA_INTERVAL_20_MS = 20;
+// Masks for checking capability support
+constexpr uint8_t CAPABILITY_SIDE = 0x01;
+constexpr uint8_t CAPABILITY_BINAURAL = 0x02;
+constexpr uint8_t CAPABILITY_RESERVED = 0xFC;
+
/** Implementations of HearingAid will also implement this interface */
class HearingAidAudioReceiver {
public:
virtual ~HearingAidAudioReceiver() = default;
virtual void OnAudioDataReady(const std::vector<uint8_t>& data) = 0;
- virtual void OnAudioSuspend(std::promise<void> do_suspend_promise);
- virtual void OnAudioResume(std::promise<void> do_resume_promise);
+ virtual void OnAudioSuspend(std::promise<void> do_suspend_promise) = 0;
+ virtual void OnAudioResume(std::promise<void> do_resume_promise) = 0;
+};
+
+// Number of rssi reads to attempt when requested
+constexpr int READ_RSSI_NUM_TRIES = 10;
+constexpr int PERIOD_TO_READ_RSSI_IN_INTERVALS = 5;
+// Depth of RSSI History in DumpSys
+constexpr int MAX_RSSI_HISTORY = 15;
+
+struct rssi_log {
+ struct timespec timestamp;
+ std::vector<int8_t> rssi;
+};
+
+struct AudioStats {
+ size_t packet_flush_count;
+ size_t packet_send_count;
+ size_t frame_flush_count;
+ size_t frame_send_count;
+ std::deque<rssi_log> rssi_history;
+
+ AudioStats() { Reset(); }
+
+ void Reset() {
+ packet_flush_count = 0;
+ packet_send_count = 0;
+ frame_flush_count = 0;
+ frame_send_count = 0;
+ }
+};
+
+/** Possible states for the Connection Update status */
+typedef enum {
+ NONE, // Not Connected
+ AWAITING, // Waiting for start the Connection Update operation
+ STARTED, // Connection Update has started
+ COMPLETED // Connection Update is completed successfully
+} connection_update_status_t;
+
+struct HearingDevice {
+ RawAddress address;
+ /* This is true only during first connection to profile, until we store the
+ * device */
+ bool first_connection;
+ bool service_changed_rcvd;
+
+ /* we are making active attempt to connect to this device, 'direct connect'.
+ * This is true only during initial phase of first connection. */
+ bool connecting_actively;
+
+ /* For two hearing aids, you must update their parameters one after another,
+ * not simulteanously, to ensure start of connection events for both devices
+ * are far from each other. This status tracks whether this device is waiting
+ * for update of parameters, that should happen after "LE Connection Update
+ * Complete" event
+ */
+ connection_update_status_t connection_update_status;
+ uint16_t requested_connection_interval;
+
+ /* if true, we are connected, L2CAP socket is open, we can stream audio.
+ However, the actual audio stream also depends on whether the
+ Audio Service has resumed.
+ */
+ bool accepting_audio;
+
+ uint16_t conn_id;
+ uint16_t gap_handle;
+ uint16_t audio_control_point_handle;
+ uint16_t audio_status_handle;
+ uint16_t audio_status_ccc_handle;
+ uint16_t service_changed_ccc_handle;
+ uint16_t volume_handle;
+ uint16_t read_psm_handle;
+
+ uint8_t capabilities;
+ uint64_t hi_sync_id;
+ uint16_t render_delay;
+ uint16_t preparation_delay;
+ uint16_t codecs;
+
+ AudioStats audio_stats;
+ /* Keep tracks of whether the "Start Cmd" has been send to this device. When
+ the "Stop Cmd" is send or when this device disconnects, then this flag is
+ cleared. Please note that the "Start Cmd" is not send during device
+ connection in the case when the audio is suspended. */
+ bool playback_started;
+ /* This tracks whether the last command to Hearing Aids device is
+ * ACKnowledged. */
+ bool command_acked;
+
+ /* When read_rssi_count is > 0, then read the rssi. The interval between rssi
+ reads is tracked by num_intervals_since_last_rssi_read. */
+ int read_rssi_count;
+ int num_intervals_since_last_rssi_read;
+
+ HearingDevice(const RawAddress& address, uint8_t capabilities,
+ uint16_t codecs, uint16_t audio_control_point_handle,
+ uint16_t audio_status_handle, uint16_t audio_status_ccc_handle,
+ uint16_t service_changed_ccc_handle, uint16_t volume_handle,
+ uint16_t read_psm_handle, uint64_t hiSyncId,
+ uint16_t render_delay, uint16_t preparation_delay)
+ : address(address),
+ first_connection(false),
+ service_changed_rcvd(false),
+ connecting_actively(false),
+ connection_update_status(NONE),
+ accepting_audio(false),
+ conn_id(0),
+ gap_handle(0),
+ audio_control_point_handle(audio_control_point_handle),
+ audio_status_handle(audio_status_handle),
+ audio_status_ccc_handle(audio_status_ccc_handle),
+ service_changed_ccc_handle(service_changed_ccc_handle),
+ volume_handle(volume_handle),
+ read_psm_handle(read_psm_handle),
+ capabilities(capabilities),
+ hi_sync_id(hiSyncId),
+ render_delay(render_delay),
+ preparation_delay(preparation_delay),
+ codecs(codecs),
+ playback_started(false),
+ command_acked(false),
+ read_rssi_count(0) {}
+
+ HearingDevice(const RawAddress& address, bool first_connection)
+ : address(address),
+ first_connection(first_connection),
+ service_changed_rcvd(false),
+ connecting_actively(first_connection),
+ connection_update_status(NONE),
+ accepting_audio(false),
+ conn_id(0),
+ gap_handle(0),
+ audio_status_handle(0),
+ audio_status_ccc_handle(0),
+ service_changed_ccc_handle(0),
+ read_psm_handle(0),
+ capabilities(0),
+ hi_sync_id(0),
+ render_delay(0),
+ preparation_delay(0),
+ codecs(0),
+ playback_started(false),
+ command_acked(false),
+ read_rssi_count(0) {}
+
+ HearingDevice() : HearingDevice(RawAddress::kEmpty, false) {}
+
+ /* return true if this device represents left Hearing Aid. Returned value is
+ * valid only after capabilities are discovered */
+ bool isLeft() const { return !(capabilities & CAPABILITY_SIDE); }
};
class HearingAid {
@@ -41,15 +200,11 @@
static void Initialize(bluetooth::hearing_aid::HearingAidCallbacks* callbacks,
base::Closure initCb);
static void CleanUp();
- static bool IsInitialized();
+ static bool IsHearingAidRunning();
static HearingAid* Get();
static void DebugDump(int fd);
- static void AddFromStorage(const RawAddress& address, uint16_t psm,
- uint8_t capabilities, uint16_t codec,
- uint16_t audioControlPointHandle,
- uint16_t volumeHandle, uint64_t hiSyncId,
- uint16_t render_delay, uint16_t preparation_delay,
+ static void AddFromStorage(const HearingDevice& dev_info,
uint16_t is_white_listed);
static int GetDeviceCount();
@@ -57,7 +212,6 @@
virtual void Connect(const RawAddress& address) = 0;
virtual void Disconnect(const RawAddress& address) = 0;
virtual void AddToWhiteList(const RawAddress& address) = 0;
- virtual void RemoveFromWhiteList(const RawAddress& address) = 0;
virtual void SetVolume(int8_t volume) = 0;
};
@@ -87,7 +241,8 @@
class HearingAidAudioSource {
public:
static void Start(const CodecConfiguration& codecConfiguration,
- HearingAidAudioReceiver* audioReceiver);
+ HearingAidAudioReceiver* audioReceiver,
+ uint16_t remote_delay_ms);
static void Stop();
static void Initialize();
static void CleanUp();
diff --git a/bta/include/bta_hh_co.h b/bta/include/bta_hh_co.h
index da884bc..44e5a9f 100644
--- a/bta/include/bta_hh_co.h
+++ b/bta/include/bta_hh_co.h
@@ -77,6 +77,31 @@
******************************************************************************/
extern void bta_hh_co_close(uint8_t dev_handle, uint8_t app_id);
+/*******************************************************************************
+ *
+ * Function bta_hh_co_set_rpt_rsp
+ *
+ * Description This callout function is executed by HH when Set Report
+ * Response is received on Control Channel.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+extern void bta_hh_co_set_rpt_rsp(uint8_t dev_handle, uint8_t status);
+
+/*******************************************************************************
+ *
+ * Function bta_hh_co_get_rpt_rsp
+ *
+ * Description This callout function is executed by HH when Get Report
+ * Response is received on Control Channel.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+extern void bta_hh_co_get_rpt_rsp(uint8_t dev_handle, uint8_t status,
+ uint8_t* p_rpt, uint16_t len);
+
#if (BTA_HH_LE_INCLUDED == TRUE)
/*******************************************************************************
*
diff --git a/bta/include/bta_hl_api.h b/bta/include/bta_hl_api.h
deleted file mode 100644
index 12532d7..0000000
--- a/bta/include/bta_hl_api.h
+++ /dev/null
@@ -1,824 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2009-2012 Broadcom 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.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- * This is the public interface file for the HeaLth device profile (HL)
- * subsystem of BTA, Broadcom's Bluetooth application layer for mobile
- * phones.
- *
- ******************************************************************************/
-#ifndef BTA_HL_API_H
-#define BTA_HL_API_H
-
-#include "bta_api.h"
-#include "btm_api.h"
-#include "mca_api.h"
-
-/*****************************************************************************
- * Constants and data types
- ****************************************************************************/
-/* Extra Debug Code */
-#ifndef BTA_HL_DEBUG
-#define BTA_HL_DEBUG TRUE
-#endif
-
-#ifndef BTA_HL_NUM_APPS
-#define BTA_HL_NUM_APPS 12
-#endif
-
-#ifndef BTA_HL_NUM_MDEPS
-#define BTA_HL_NUM_MDEPS 13
-#endif
-
-#ifndef BTA_HL_NUM_MCLS
-#define BTA_HL_NUM_MCLS 7
-#endif
-
-#ifndef BTA_HL_NUM_MDLS_PER_MDEP
-#define BTA_HL_NUM_MDLS_PER_MDEP 4
-#endif
-
-#ifndef BTA_HL_NUM_MDLS_PER_MCL
-#define BTA_HL_NUM_MDLS_PER_MCL 10
-#endif
-
-#ifndef BTA_HL_NUM_DATA_TYPES
-#define BTA_HL_NUM_DATA_TYPES \
- 5 /* maximum number of data types can be supported \
- per MDEP ID */
-#endif
-
-#define BTA_HL_MCAP_RSP_TOUT 2 /* 2 seconds */
-
-#ifndef BTA_HL_CCH_NUM_FILTER_ELEMS
-#define BTA_HL_CCH_NUM_FILTER_ELEMS 3
-#endif
-
-#ifndef BTA_HL_NUM_SDP_CBACKS
-#define BTA_HL_NUM_SDP_CBACKS 7
-#endif
-
-#ifndef BTA_HL_NUM_SDP_RECS
-#define BTA_HL_NUM_SDP_RECS 5
-#endif
-
-#ifndef BTA_HL_NUM_SDP_MDEPS
-#define BTA_HL_NUM_SDP_MDEPS 12
-#endif
-
-#ifndef BTA_HL_NUM_SVC_ELEMS
-#define BTA_HL_NUM_SVC_ELEMS 2
-#endif
-
-#ifndef BTA_HL_NUM_PROTO_ELEMS
-#define BTA_HL_NUM_PROTO_ELEMS 2
-#endif
-
-#define BTA_HL_VERSION 0x0101
-#define BTA_HL_NUM_ADD_PROTO_LISTS 1
-#define BTA_HL_NUM_ADD_PROTO_ELEMS 2
-#define BTA_HL_MDEP_SEQ_SIZE 20
-#define BTA_HL_VAL_ARRY_SIZE 320
-
-#ifndef BTA_HL_NUM_MDL_CFGS
-#define BTA_HL_NUM_MDL_CFGS \
- 16 /* numer of MDL cfg saved in the persistent memory*/
-#endif
-
-#define BTA_HL_NUM_TIMERS 7
-
-#define BTA_HL_CCH_RSP_TOUT 2000
-#define BTA_HL_MAX_TIME 255
-#define BTA_HL_MIN_TIME 1
-#define BTA_HL_INVALID_APP_HANDLE 0xFF
-#define BTA_HL_INVALID_MCL_HANDLE 0xFF
-#define BTA_HL_INVALID_MDL_HANDLE 0xFFFF
-
-#define BTA_HL_STATUS_OK 0
-#define BTA_HL_STATUS_FAIL 1 /* Used to pass all other errors */
-#define BTA_HL_STATUS_ABORTED 2
-#define BTA_HL_STATUS_NO_RESOURCE 3
-#define BTA_HL_STATUS_LAST_ITEM 4
-#define BTA_HL_STATUS_DUPLICATE_APP_ID 5
-#define BTA_HL_STATUS_INVALID_APP_HANDLE 6
-#define BTA_HL_STATUS_INVALID_MCL_HANDLE 7
-#define BTA_HL_STATUS_MCAP_REG_FAIL 8
-#define BTA_HL_STATUS_MDEP_CO_FAIL 9
-#define BTA_HL_STATUS_ECHO_CO_FAIL 10
-#define BTA_HL_STATUS_MDL_CFG_CO_FAIL 11
-#define BTA_HL_STATUS_SDP_NO_RESOURCE 12
-#define BTA_HL_STATUS_SDP_FAIL 13
-#define BTA_HL_STATUS_NO_CCH 14
-#define BTA_HL_STATUS_NO_MCL 15
-
-#define BTA_HL_STATUS_NO_FIRST_RELIABLE 17
-#define BTA_HL_STATUS_INVALID_DCH_CFG 18
-#define BTA_HL_STATUS_INVALID_MDL_HANDLE 19
-#define BTA_HL_STATUS_INVALID_BD_ADDR 20
-#define BTA_HL_STATUS_INVALID_RECONNECT_CFG 21
-#define BTA_HL_STATUS_ECHO_TEST_BUSY 22
-#define BTA_HL_STATUS_INVALID_LOCAL_MDEP_ID 23
-#define BTA_HL_STATUS_INVALID_MDL_ID 24
-#define BTA_HL_STATUS_NO_MDL_ID_FOUND 25
-#define BTA_HL_STATUS_DCH_BUSY 26 /* DCH is congested*/
-#define BTA_HL_STATUS_INVALID_CTRL_PSM 27
-#define BTA_HL_STATUS_DUPLICATE_CCH_OPEN 28
-
-typedef uint8_t tBTA_HL_STATUS;
-typedef tMCA_HANDLE tBTA_HL_APP_HANDLE;
-typedef tMCA_CL tBTA_HL_MCL_HANDLE;
-typedef tMCA_DL tBTA_HL_MDL_HANDLE;
-enum {
- BTA_HL_DEVICE_TYPE_SINK,
- BTA_HL_DEVICE_TYPE_SOURCE,
- BTA_HL_DEVICE_TYPE_DUAL
-};
-
-typedef uint8_t tBTA_HL_DEVICE_TYPE;
-
-#define BTA_HL_SDP_IEEE_11073_20601 0x01
-
-#define BTA_HL_MCAP_SUP_RECONNECT_MASK_INIT 2 /* 0x02 */
-#define BTA_HL_MCAP_SUP_RECONNECT_MASK_ACCEPT 4 /* 0x04 */
-#define BTA_HL_MCAP_SUP_CSP_MASK_SYNC_SLAVE 0 /* 0x08 */
-#define BTA_HL_MCAP_SUP_CSP_MASK_SYNC_MASTER 0 /* 0x10 */
-
-#define BTA_HL_MCAP_SUP_PROC_MASK \
- (BTA_HL_MCAP_SUP_RECONNECT_MASK_INIT | \
- BTA_HL_MCAP_SUP_RECONNECT_MASK_ACCEPT | \
- BTA_HL_MCAP_SUP_CSP_MASK_SYNC_SLAVE | BTA_HL_MCAP_SUP_CSP_MASK_SYNC_MASTER)
-#define BTA_HL_MDEP_ROLE_SOURCE 0x00
-#define BTA_HL_MDEP_ROLE_SINK 0x01
-
-typedef uint8_t tBTA_HL_MDEP_ROLE;
-
-#define BTA_HL_MDEP_ROLE_MASK_SOURCE 0x01 /* bit mask */
-#define BTA_HL_MDEP_ROLE_MASK_SINK 0x02
-typedef uint8_t tBTA_HL_MDEP_ROLE_MASK;
-
-#define BTA_HL_ECHO_TEST_MDEP_ID 0
-#define BTA_HL_ECHO_TEST_MDEP_CFG_IDX 0
-
-#define BTA_HL_INVALID_MDEP_ID 0xFF
-typedef tMCA_DEP tBTA_HL_MDEP_ID; /* 0 is for echo test,
- 0x01-0x7F availave for use,
- 0x80-0xFF reserved*/
-
-#define BTA_HL_DELETE_ALL_MDL_IDS 0xFFFF
-#define BTA_HL_MAX_MDL_VAL 0xFEFF
-typedef uint16_t tBTA_HL_MDL_ID; /* 0x0000 reserved,
- 0x0001-0xFEFF dynamic range,
- 0xFF00-0xFFFE reserved,
- 0xFFFF indicates all MDLs*/
-
-#define BTA_HL_MDEP_DESP_LEN 35
-
-#define BTA_HL_DCH_MODE_RELIABLE 0
-#define BTA_HL_DCH_MODE_STREAMING 1
-
-typedef uint8_t tBTA_HL_DCH_MODE;
-
-#define BTA_HL_DCH_CFG_NO_PREF 0
-#define BTA_HL_DCH_CFG_RELIABLE 1
-#define BTA_HL_DCH_CFG_STREAMING 2
-#define BTA_HL_DCH_CFG_UNKNOWN 0xFF
-
-typedef uint8_t tBTA_HL_DCH_CFG;
-
-/* The Default DCH CFG for the echo test when the device is a Source */
-#define BTA_HL_DEFAULT_ECHO_TEST_SRC_DCH_CFG BTA_HL_DCH_CFG_RELIABLE
-
-#define BTA_HL_DCH_CREATE_RSP_SUCCESS 0
-#define BTA_HL_DCH_CREATE_RSP_CFG_REJ 1
-
-typedef uint8_t tBTA_HL_DCH_CREATE_RSP;
-
-#define BTA_HL_MCAP_SUP_PROC_RECONNECT_INIT 0x02
-#define BTA_HL_MCAP_SUP_PROC_RECONNECT_APT 0x04
-#define BTA_HL_MCAP_SUP_PROC_CSP_SLAVE 0x08
-#define BTA_HL_MCAP_SUP_PROC_CSP_MASTER 0x10
-
-typedef uint8_t tBTA_HL_SUP_PROC_MASK;
-
-typedef struct {
- uint16_t max_rx_apdu_size; /* local rcv MTU */
- uint16_t max_tx_apdu_size; /* maximum TX APDU size*/
-} tBTA_HL_ECHO_CFG;
-
-typedef struct {
- uint16_t data_type;
- uint16_t max_rx_apdu_size; /* local rcv MTU */
- uint16_t max_tx_apdu_size; /* maximum TX APDU size*/
- char desp[BTA_HL_MDEP_DESP_LEN + 1];
-} tBTA_HL_MDEP_DATA_TYPE_CFG;
-
-typedef struct {
- tBTA_HL_MDEP_ROLE mdep_role;
- uint8_t num_of_mdep_data_types;
- tBTA_HL_MDEP_DATA_TYPE_CFG data_cfg[BTA_HL_NUM_DATA_TYPES];
-} tBTA_HL_MDEP_CFG;
-
-typedef struct {
- tBTA_HL_MDEP_ID mdep_id; /* MDEP ID 0x01-0x7F */
- tBTA_HL_MDEP_CFG mdep_cfg;
- uint8_t ori_app_id;
-} tBTA_HL_MDEP;
-
-typedef struct {
- tBTA_HL_MDEP mdep[BTA_HL_NUM_MDEPS];
- tBTA_HL_ECHO_CFG echo_cfg;
- tBTA_HL_MDEP_ROLE_MASK app_role_mask;
- bool advertize_source_sdp;
- uint8_t num_of_mdeps;
-} tBTA_HL_SUP_FEATURE;
-
-typedef struct {
- bool delete_req_pending;
- tBTA_HL_MDL_ID mdl_id;
- tBTA_HL_MCL_HANDLE mcl_handle;
-} tBTA_HL_DELETE_MDL;
-
-typedef struct {
- uint8_t time;
- uint16_t mtu;
- tBTA_HL_MDL_ID mdl_id;
- tBTA_HL_MDEP_ID local_mdep_id;
- tBTA_HL_MDEP_ROLE local_mdep_role;
- bool active; /* true if this item is in use */
- tBTA_HL_DCH_MODE dch_mode;
- uint8_t fcs;
- RawAddress peer_bd_addr;
-} tBTA_HL_MDL_CFG;
-
-/* Maximum number of supported feature list items (list_elem in
- * tSDP_SUP_FEATURE_ELEM) */
-#define BTA_HL_NUM_SUP_FEATURE_ELEMS 13
-#define BTA_HL_SUP_FEATURE_SDP_BUF_SIZE 512
-/* This structure is used to add supported feature lists and find supported
- * feature elements */
-typedef struct {
- uint8_t mdep_id;
- uint16_t data_type;
- tBTA_HL_MDEP_ROLE mdep_role;
- char* p_mdep_desp;
-} tBTA_HL_SUP_FEATURE_ELEM;
-
-typedef struct {
- uint16_t num_elems;
- tBTA_HL_SUP_FEATURE_ELEM list_elem[BTA_HL_NUM_SUP_FEATURE_ELEMS];
-} tBTA_HL_SUP_FEATURE_LIST_ELEM;
-
-typedef struct {
- tBTA_HL_DEVICE_TYPE dev_type; /* sink, source or dual roles */
- tBTA_SEC sec_mask; /* security mask for accepting conenction*/
- const char*
- p_srv_name; /* service name to be used in the SDP; null terminated*/
- const char* p_srv_desp; /* service description to be used in the SDP; null
- terminated */
- const char*
- p_provider_name; /* provide name to be used in the SDP; null terminated */
-} tBTA_HL_REG_PARAM;
-
-typedef struct {
- uint16_t ctrl_psm;
- RawAddress bd_addr; /* Address of peer device */
- tBTA_SEC sec_mask; /* security mask for initiating connection*/
-} tBTA_HL_CCH_OPEN_PARAM;
-
-typedef struct {
- uint16_t ctrl_psm;
- tBTA_HL_MDEP_ID local_mdep_id; /* local MDEP ID */
- tBTA_HL_MDEP_ID peer_mdep_id; /* peer mdep id */
- tBTA_HL_DCH_CFG local_cfg;
- tBTA_SEC sec_mask; /* security mask for initiating connection*/
-} tBTA_HL_DCH_OPEN_PARAM;
-
-typedef struct {
- uint16_t ctrl_psm;
- tBTA_HL_MDL_ID mdl_id;
-} tBTA_HL_DCH_RECONNECT_PARAM;
-
-typedef struct {
- uint16_t ctrl_psm;
- uint16_t pkt_size;
- tBTA_HL_DCH_CFG local_cfg;
-} tBTA_HL_DCH_ECHO_TEST_PARAM;
-
-typedef struct {
- uint16_t buf_size;
- uint8_t p_buf; /* buffer pointer */
-} tBTA_HL_DCH_BUF_INFO;
-
-typedef struct {
- tBTA_HL_MDEP_ID local_mdep_id; /* local MDEP ID */
- tBTA_HL_MDL_ID mdl_id;
- tBTA_HL_DCH_CREATE_RSP rsp_code;
- tBTA_HL_DCH_CFG cfg_rsp;
-} tBTA_HL_DCH_CREATE_RSP_PARAM;
-
-typedef struct {
- uint16_t data_type;
- uint8_t mdep_id;
- tBTA_HL_MDEP_ROLE mdep_role;
- char mdep_desp[BTA_HL_MDEP_DESP_LEN + 1];
-} tBTA_HL_SDP_MDEP_CFG;
-
-typedef struct {
- uint16_t ctrl_psm;
- uint16_t data_psm;
- uint8_t mcap_sup_proc;
- uint8_t num_mdeps; /* number of mdep elements from SDP*/
- char srv_name[BTA_SERVICE_NAME_LEN + 1];
- char srv_desp[BTA_SERVICE_DESP_LEN + 1];
- char provider_name[BTA_PROVIDER_NAME_LEN + 1];
- tBTA_HL_SDP_MDEP_CFG mdep_cfg[BTA_HL_NUM_SDP_MDEPS];
-} tBTA_HL_SDP_REC;
-
-typedef struct {
- uint8_t num_recs;
- tBTA_HL_SDP_REC sdp_rec[BTA_HL_NUM_SDP_RECS];
-} tBTA_HL_SDP;
-
-/* HL control callback function events */
-enum { BTA_HL_CTRL_ENABLE_CFM_EVT = 0, BTA_HL_CTRL_DISABLE_CFM_EVT };
-typedef uint8_t tBTA_HL_CTRL_EVT;
-/* Structure associated with BTA_HL_ENABLE_EVT
- BTA_HL_DISABLE_EVT */
-
-typedef struct { tBTA_HL_STATUS status; } tBTA_HL_CTRL_ENABLE_DISABLE;
-
-typedef union {
- tBTA_HL_CTRL_ENABLE_DISABLE enable_cfm;
- tBTA_HL_CTRL_ENABLE_DISABLE disable_cfm;
-} tBTA_HL_CTRL;
-
-/* HL instance callback function events */
-enum {
- BTA_HL_REGISTER_CFM_EVT = 0,
- BTA_HL_DEREGISTER_CFM_EVT,
- BTA_HL_CCH_OPEN_IND_EVT,
- BTA_HL_CCH_OPEN_CFM_EVT,
- BTA_HL_CCH_CLOSE_IND_EVT,
- BTA_HL_CCH_CLOSE_CFM_EVT,
- BTA_HL_DCH_CREATE_IND_EVT,
- BTA_HL_DCH_OPEN_IND_EVT,
- BTA_HL_DCH_OPEN_CFM_EVT,
- BTA_HL_DCH_CLOSE_IND_EVT,
- BTA_HL_DCH_CLOSE_CFM_EVT,
- BTA_HL_DCH_RECONNECT_IND_EVT,
- BTA_HL_DCH_RECONNECT_CFM_EVT,
-
- BTA_HL_DCH_ABORT_IND_EVT,
- BTA_HL_DCH_ABORT_CFM_EVT,
- BTA_HL_DELETE_MDL_IND_EVT,
- BTA_HL_DELETE_MDL_CFM_EVT,
- BTA_HL_DCH_SEND_DATA_CFM_EVT,
- BTA_HL_DCH_RCV_DATA_IND_EVT,
- BTA_HL_CONG_CHG_IND_EVT,
- BTA_HL_DCH_ECHO_TEST_CFM_EVT,
- BTA_HL_SDP_QUERY_CFM_EVT,
- BTA_HL_SDP_INFO_IND_EVT
-};
-typedef uint8_t tBTA_HL_EVT;
-
-typedef struct {
- tBTA_HL_STATUS status; /* start status */
- uint8_t app_id;
- tBTA_HL_APP_HANDLE app_handle;
-} tBTA_HL_REGISTER_CFM;
-
-typedef struct {
- tBTA_HL_STATUS status; /* start status */
- uint8_t app_id;
- tBTA_HL_APP_HANDLE app_handle;
-} tBTA_HL_DEREGISTER_CFM;
-
-typedef struct {
- bool intentional;
- tBTA_HL_MCL_HANDLE mcl_handle;
- tBTA_HL_APP_HANDLE app_handle;
-} tBTA_HL_CCH_CLOSE_IND;
-
-typedef struct {
- tBTA_HL_MCL_HANDLE mcl_handle;
- tBTA_HL_APP_HANDLE app_handle;
-} tBTA_HL_MCL_IND;
-
-typedef struct {
- tBTA_HL_STATUS status; /* connection status */
- tBTA_HL_MCL_HANDLE mcl_handle;
- tBTA_HL_APP_HANDLE app_handle;
-} tBTA_HL_MCL_CFM;
-
-typedef struct {
- tBTA_HL_MCL_HANDLE mcl_handle;
- tBTA_HL_APP_HANDLE app_handle;
- RawAddress bd_addr; /* address of peer device */
-} tBTA_HL_CCH_OPEN_IND;
-
-typedef struct {
- tBTA_HL_STATUS status; /* connection status */
- uint8_t app_id;
- tBTA_HL_MCL_HANDLE mcl_handle;
- tBTA_HL_APP_HANDLE app_handle;
- RawAddress bd_addr; /* address of peer device */
-} tBTA_HL_CCH_OPEN_CFM;
-
-typedef struct {
- tBTA_HL_MCL_HANDLE mcl_handle;
- tBTA_HL_APP_HANDLE app_handle;
- tBTA_HL_MDEP_ID local_mdep_id;
- tBTA_HL_MDL_ID mdl_id; /* MCAP data link ID for this
- data channel conenction */
- tBTA_HL_DCH_CFG cfg; /* dch cfg requested by the peer device */
- RawAddress bd_addr; /* address of peer device */
-
-} tBTA_HL_DCH_CREATE_IND;
-
-typedef struct {
- tBTA_HL_MDL_HANDLE mdl_handle;
- tBTA_HL_MCL_HANDLE mcl_handle;
- tBTA_HL_APP_HANDLE app_handle;
- tBTA_HL_MDEP_ID local_mdep_id;
- tBTA_HL_MDL_ID mdl_id; /* MCAP data link ID for this
- data channel conenction */
- tBTA_HL_DCH_MODE dch_mode; /* data channel mode - reliable or streaming*/
-
- bool first_reliable; /* whether this is the first reliable data channel */
- uint16_t mtu;
-} tBTA_HL_DCH_OPEN_IND;
-
-typedef struct {
- tBTA_HL_STATUS status; /* connection status */
- tBTA_HL_MDL_HANDLE mdl_handle;
- tBTA_HL_MCL_HANDLE mcl_handle;
- tBTA_HL_APP_HANDLE app_handle;
- tBTA_HL_MDEP_ID local_mdep_id;
- tBTA_HL_MDL_ID mdl_id; /* MCAP data link ID for this
- data channel conenction */
- tBTA_HL_DCH_MODE dch_mode; /* data channel mode - reliable or streaming*/
- bool first_reliable; /* whether this is the first reliable data channel */
- uint16_t mtu;
-} tBTA_HL_DCH_OPEN_CFM;
-
-typedef struct {
- bool intentional;
- tBTA_HL_MDL_HANDLE mdl_handle;
- tBTA_HL_MCL_HANDLE mcl_handle;
- tBTA_HL_APP_HANDLE app_handle;
-} tBTA_HL_DCH_CLOSE_IND;
-
-typedef struct {
- tBTA_HL_MDL_HANDLE mdl_handle;
- tBTA_HL_MCL_HANDLE mcl_handle;
- tBTA_HL_APP_HANDLE app_handle;
-} tBTA_HL_MDL_IND;
-
-typedef struct {
- tBTA_HL_STATUS status;
- tBTA_HL_MDL_HANDLE mdl_handle;
- tBTA_HL_MCL_HANDLE mcl_handle;
- tBTA_HL_APP_HANDLE app_handle;
-} tBTA_HL_MDL_CFM;
-
-typedef struct {
- tBTA_HL_MCL_HANDLE mcl_handle;
- tBTA_HL_APP_HANDLE app_handle;
- tBTA_HL_MDL_ID mdl_id;
-} tBTA_HL_DELETE_MDL_IND;
-
-typedef struct {
- tBTA_HL_STATUS status;
- tBTA_HL_MCL_HANDLE mcl_handle;
- tBTA_HL_APP_HANDLE app_handle;
- tBTA_HL_MDL_ID mdl_id;
-} tBTA_HL_DELETE_MDL_CFM;
-
-typedef struct {
- tBTA_HL_MDL_HANDLE mdl_handle;
- tBTA_HL_MCL_HANDLE mcl_handle;
- tBTA_HL_APP_HANDLE app_handle;
- bool cong;
-} tBTA_HL_DCH_CONG_IND;
-
-typedef struct {
- tBTA_HL_APP_HANDLE app_handle;
- uint16_t ctrl_psm;
- uint16_t data_psm;
- uint8_t data_x_spec;
- uint8_t mcap_sup_procs;
-} tBTA_HL_SDP_INFO_IND;
-
-typedef struct {
- tBTA_HL_STATUS status;
- uint8_t app_id;
- tBTA_HL_APP_HANDLE app_handle;
- RawAddress bd_addr;
- tBTA_HL_SDP* p_sdp;
-} tBTA_HL_SDP_QUERY_CFM;
-
-typedef union {
- tBTA_HL_REGISTER_CFM reg_cfm;
- tBTA_HL_DEREGISTER_CFM dereg_cfm;
- tBTA_HL_CCH_OPEN_IND cch_open_ind;
- tBTA_HL_CCH_OPEN_CFM cch_open_cfm;
- tBTA_HL_CCH_CLOSE_IND cch_close_ind;
- tBTA_HL_MCL_CFM cch_close_cfm;
- tBTA_HL_DCH_CREATE_IND dch_create_ind;
- tBTA_HL_DCH_OPEN_IND dch_open_ind;
- tBTA_HL_DCH_OPEN_CFM dch_open_cfm;
- tBTA_HL_DCH_CLOSE_IND dch_close_ind;
- tBTA_HL_MDL_CFM dch_close_cfm;
- tBTA_HL_DCH_OPEN_IND dch_reconnect_ind;
- tBTA_HL_DCH_OPEN_CFM dch_reconnect_cfm;
- tBTA_HL_MCL_IND dch_abort_ind;
- tBTA_HL_MCL_CFM dch_abort_cfm;
- tBTA_HL_DELETE_MDL_IND delete_mdl_ind;
- tBTA_HL_DELETE_MDL_CFM delete_mdl_cfm;
- tBTA_HL_MDL_CFM dch_send_data_cfm;
- tBTA_HL_MDL_IND dch_rcv_data_ind;
- tBTA_HL_DCH_CONG_IND dch_cong_ind;
- tBTA_HL_MCL_CFM echo_test_cfm;
- tBTA_HL_SDP_QUERY_CFM sdp_query_cfm;
- tBTA_HL_SDP_INFO_IND sdp_info_ind;
-
-} tBTA_HL;
-
-/* HL callback functions */
-typedef void tBTA_HL_CTRL_CBACK(tBTA_HL_CTRL_EVT event, tBTA_HL_CTRL* p_data);
-typedef void tBTA_HL_CBACK(tBTA_HL_EVT event, tBTA_HL* p_data);
-
-/*****************************************************************************
- * External Function Declarations
- ****************************************************************************/
-
-/**************************
- * API Functions
- **************************/
-
-/*******************************************************************************
- *
- * Function BTA_HlEnable
- *
- * Description Enable the HL subsystems. This function must be
- * called before any other functions in the HL API are called.
- * When the enable operation is completed the callback function
- * will be called with an BTA_HL_CTRL_ENABLE_CFM_EVT event.
- *
- * Parameters p_cback - HL event call back function
- *
- * Returns void
- *
- ******************************************************************************/
-extern void BTA_HlEnable(tBTA_HL_CTRL_CBACK* p_ctrl_cback);
-/*******************************************************************************
- *
- * Function BTA_HlDisable
- *
- * Description Disable the HL subsystem.
- *
- * Returns void
- *
- ******************************************************************************/
-extern void BTA_HlDisable(void);
-
-/*******************************************************************************
- *
- * Function BTA_HlUpdate
- *
- * Description Register an HDP application
- *
- * Parameters app_id - Application ID
- * p_reg_param - non-platform related parameters for the
- * HDP application
- * p_cback - HL event callback fucntion
- *
- * Returns void
- *
- ******************************************************************************/
-extern void BTA_HlUpdate(uint8_t app_id, tBTA_HL_REG_PARAM* p_reg_param,
- bool is_register, tBTA_HL_CBACK* p_cback);
-
-/*******************************************************************************
- *
- * Function BTA_HlRegister
- *
- * Description Register a HDP application
- *
- *
- * Parameters app_id - hdp application ID
- * p_reg_param - non-platform related parameters for the
- * HDP application
- * p_cback - HL event callback fucntion
- *
- * Returns void
- *
- ******************************************************************************/
-extern void BTA_HlRegister(uint8_t app_id, tBTA_HL_REG_PARAM* p_reg_param,
- tBTA_HL_CBACK* p_cback);
-
-/*******************************************************************************
- *
- * Function BTA_HlDeregister
- *
- * Description Deregister an HDP application
- *
- * Parameters app_handle - Application handle
- *
- * Returns void
- *
- ******************************************************************************/
-extern void BTA_HlDeregister(uint8_t app_id, tBTA_HL_APP_HANDLE app_handle);
-
-/*******************************************************************************
- *
- * Function BTA_HlCchOpen
- *
- * Description Open a Control channel connection with the specified BD
- * address and the control PSM value is used to select which
- * HDP insatnce should be used in case the peer device support
- * multiple HDP instances.
- *
- *
- * Parameters app_handle - Application Handle
- * p_open_param - parameters for opening a control channel
- *
- * Returns void
- *
- * Note: If the control PSM value is zero then the first HDP
- * instance is used for the control channel setup
- ******************************************************************************/
-extern void BTA_HlCchOpen(uint8_t app_id, tBTA_HL_APP_HANDLE app_handle,
- tBTA_HL_CCH_OPEN_PARAM* p_open_param);
-
-/*******************************************************************************
- *
- * Function BTA_HlCchClose
- *
- * Description Close a Control channel connection with the specified MCL
- * handle
- *
- * Parameters mcl_handle - MCL handle
- *
- * Returns void
- *
- ******************************************************************************/
-extern void BTA_HlCchClose(tBTA_HL_MCL_HANDLE mcl_handle);
-
-/*******************************************************************************
- *
- * Function BTA_HlDchOpen
- *
- * Description Open a data channel connection with the specified DCH
- * parameters
- *
- * Parameters mcl_handle - MCL handle
- * p_open_param - parameters for opening a data channel
- *
- * Returns void
- *
- ******************************************************************************/
-extern void BTA_HlDchOpen(tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_DCH_OPEN_PARAM* p_open_param);
-/*******************************************************************************
- *
- * Function BTA_HlDchReconnect
- *
- * Description Reconnect a data channel with the specified MDL_ID
- *
- * Parameters mcl_handle - MCL handle
-*8 p_recon_param - parameters for reconnecting a data channel
- *
- * Returns void
- *
- ******************************************************************************/
-extern void BTA_HlDchReconnect(tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_DCH_RECONNECT_PARAM* p_recon_param);
-/*******************************************************************************
- *
- * Function BTA_HlDchClose
- *
- * Description Close a data channel with the specified MDL handle
- *
- * Parameters mdl_handle - MDL handle
- *
- * Returns void
- *
- ******************************************************************************/
-extern void BTA_HlDchClose(tBTA_HL_MDL_HANDLE mdl_handle);
-
-/*******************************************************************************
- *
- * Function BTA_HlDchAbort
- *
- * Description Abort the current data channel setup with the specified MCL
- * handle
- *
- * Parameters mcl_handle - MCL handle
- *
- *
- * Returns void
- *
- ******************************************************************************/
-extern void BTA_HlDchAbort(tBTA_HL_MCL_HANDLE mcl_handle);
-
-/*******************************************************************************
- *
- * Function BTA_HlSendData
- *
- * Description Send an APDU to the peer device
- *
- * Parameters mdl_handle - MDL handle
- * pkt_size - size of the data packet to be sent
- *
- * Returns void
- *
- ******************************************************************************/
-extern void BTA_HlSendData(tBTA_HL_MDL_HANDLE mdl_handle, uint16_t pkt_size);
-
-/*******************************************************************************
- *
- * Function BTA_HlDeleteMdl
- *
- * Description Delete the specified MDL_ID within the specified MCL handle
- *
- * Parameters mcl_handle - MCL handle
- * mdl_id - MDL ID
- *
- * Returns void
- *
- * note: If mdl_id = 0xFFFF then this means to delete all MDLs
- * and this value can only be used with DeleteMdl request
- * only not other requests
- *
- ******************************************************************************/
-extern void BTA_HlDeleteMdl(tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_MDL_ID mdl_id);
-
-/*******************************************************************************
- *
- * Function BTA_HlDchEchoTest
- *
- * Description Initiate an echo test with the specified MCL handle
- *
- * Parameters mcl_handle - MCL handle
-*8 p_echo_test_param - parameters for echo testing
- *
- * Returns void
- *
- ******************************************************************************/
-extern void BTA_HlDchEchoTest(tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_DCH_ECHO_TEST_PARAM* p_echo_test_param);
-
-/*******************************************************************************
- *
- * Function BTA_HlSdpQuery
- *
- * Description SDP query request for the specified BD address
- *
- * Parameters app_id
- app_handle - application handle
- * bd_addr - BD address
- *
- * Returns void
- *
- ******************************************************************************/
-extern void BTA_HlSdpQuery(uint8_t app_id, tBTA_HL_APP_HANDLE app_handle,
- const RawAddress& bd_addr);
-
-/*******************************************************************************
- *
- * Function BTA_HlDchCreateMdlRsp
- *
- * Description Set the Response and configuration values for the Create MDL
- * request
- *
- * Parameters mcl_handle - MCL handle
- * p_rsp_param - parameters specified whether the request
- * should be accepted or not and if it should be
- * accepted then it also specified the
- * configuration response value
- *
- * Returns void
- *
- ******************************************************************************/
-extern void BTA_HlDchCreateRsp(tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_DCH_CREATE_RSP_PARAM* p_rsp_param);
-
-#endif /* BTA_HL_API_H */
diff --git a/bta/include/bta_hl_ci.h b/bta/include/bta_hl_ci.h
deleted file mode 100644
index 73a7cd4..0000000
--- a/bta/include/bta_hl_ci.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2009-2012 Broadcom 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.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- * This is the interface file for the HL (HeaLth device profile) subsystem
- * call-in functions.
- *
- ******************************************************************************/
-#ifndef BTA_HL_CI_H
-#define BTA_HL_CI_H
-
-#include "bta_api.h"
-#include "bta_hl_api.h"
-
-/*****************************************************************************
- * Constants and Data Types
- ****************************************************************************/
-/**************************
- * Common Definitions
- **************************/
-/* Read Ready Event */
-/*****************************************************************************
- * Function Declarations
- ****************************************************************************/
-/**************************
- * Common Functions
- **************************/
-/*******************************************************************************
- *
- * Function bta_hl_ci_get_tx_data
- *
- * Description This function is called in response to the
- * bta_hl_co_get_tx_data call-out function.
- *
- * Parameters mdl_handle -MDL handle
- * status - BTA_MA_STATUS_OK if operation is successful
- * BTA_MA_STATUS_FAIL if any errors have occurred.
- * evt - evt from the call-out function
- *
- * Returns void
- *
- ******************************************************************************/
-extern void bta_hl_ci_get_tx_data(tBTA_HL_MDL_HANDLE mdl_handle,
- tBTA_HL_STATUS status, uint16_t evt);
-
-/*******************************************************************************
- *
- * Function bta_hl_ci_put_rx_data
- *
- * Description This function is called in response to the
- * bta_hl_co_put_rx_data call-out function.
- *
- * Parameters mdl_handle -MDL handle
- * status - BTA_MA_STATUS_OK if operation is successful
- * BTA_MA_STATUS_FAIL if any errors have occurred.
- * evt - evt from the call-out function
- *
- * Returns void
- *
- ******************************************************************************/
-extern void bta_hl_ci_put_rx_data(tBTA_HL_MDL_HANDLE mdl_handle,
- tBTA_HL_STATUS status, uint16_t evt);
-
-/*******************************************************************************
- *
- * Function bta_hl_ci_get_echo_data
- *
- * Description This function is called in response to the
- * bta_hl_co_get_echo_data call-out function.
- *
- * Parameters mcl_handle -MCL handle
- * status - BTA_MA_STATUS_OK if operation is successful
- * BTA_MA_STATUS_FAIL if any errors have occurred.
- * evt - evt from the call-out function
- *
- * Returns void
- *
- ******************************************************************************/
-extern void bta_hl_ci_get_echo_data(tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_STATUS status, uint16_t evt);
-
-/*******************************************************************************
- *
- * Function bta_hl_ci_put_echo_data
- *
- * Description This function is called in response to the
- * bta_hl_co_put_echo_data call-out function.
- *
- * Parameters mcl_handle -MCL handle
- * status - BTA_MA_STATUS_OK if operation is successful
- * BTA_MA_STATUS_FAIL if any errors have occurred.
- * evt - evt from the call-out function
- *
- * Returns void
- *
- ******************************************************************************/
-extern void bta_hl_ci_put_echo_data(tBTA_HL_MCL_HANDLE mcl_handle,
- tBTA_HL_STATUS status, uint16_t evt);
-
-#endif /* BTA_HL_CI_H */
diff --git a/bta/include/bta_hl_co.h b/bta/include/bta_hl_co.h
deleted file mode 100644
index 9a36911..0000000
--- a/bta/include/bta_hl_co.h
+++ /dev/null
@@ -1,240 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2009-2012 Broadcom 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.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- * This is the interface file for the HL (HeaLth device profile) subsystem
- * call-out functions.
- *
- ******************************************************************************/
-#ifndef BTA_HL_CO_H
-#define BTA_HL_CO_H
-
-#include "bta_api.h"
-#include "bta_hl_api.h"
-
-/*****************************************************************************
- * Constants and Data Types
- ****************************************************************************/
-/**************************
- * Common Definitions
- **************************/
-
-/*******************************************************************************
- *
- * Function bta_hl_co_get_num_of_mdep
- *
- * Description This function is called to get the number of MDEPs for this
- * application ID
- *
- * Parameters app_id - application ID
- * p_num_of_mdep (output) - number of MDEP configurations
- * supported
- * by the application
- *
- * Returns Bloolean - true success
- *
- ******************************************************************************/
-extern bool bta_hl_co_get_num_of_mdep(uint8_t app_id, uint8_t* p_num_of_mdep);
-/*******************************************************************************
- *
- * Function bta_hl_co_advrtise_source_sdp
- *
- * Description This function is called to find out whether the SOURCE MDEP
- * configuration information should be advertize in the SDP or
- * not
- *
- * Parameters app_id - application ID
- *
- * Returns Bloolean - true advertise the SOURCE MDEP configuration
- * information
- *
- ******************************************************************************/
-extern bool bta_hl_co_advrtise_source_sdp(uint8_t app_id);
-/*******************************************************************************
- *
- * Function bta_hl_co_get_mdep_config
- *
- * Description This function is called to get the supported feature
- * configuration for the specified mdep index and it also
- * assigns
- * the MDEP ID for the specified mdep index
- *
- * Parameters app_id - HDP application ID
- * mdep_idx - the mdep index
- * mdep_counter - mdep_counter
- * mdep_id - the assigned MDEP ID for the specified medp_idx
- * p_mdl_cfg (output) - pointer to the MDEP configuration
- *
- *
- * Returns Bloolean - true success
- ******************************************************************************/
-extern bool bta_hl_co_get_mdep_config(uint8_t app_id, uint8_t mdep_idx,
- uint8_t mdep_counter,
- tBTA_HL_MDEP_ID mdep_id,
- tBTA_HL_MDEP_CFG* p_mdep_cfg);
-
-/*******************************************************************************
- *
- * Function bta_hl_co_get_echo_config
- *
- * Description This function is called to get the echo test
- * maximum APDU size configuration
- *
- * Parameters app_id - HDP application ID
- * p_echo_cfg (output) - pointer to the Echo test maximum APDU
- * size configuration
- *
- * Returns Bloolean - true success
- ******************************************************************************/
-extern bool bta_hl_co_get_echo_config(uint8_t app_id,
- tBTA_HL_ECHO_CFG* p_echo_cfg);
-
-/*******************************************************************************
- *
- * Function bta_hl_co_save_mdl
- *
- * Description This function is called to save a MDL configuration item in
- * persistent storage
- *
- * Parameters app_id - HDP application ID
- * item_idx - the MDL configuration storage index
- * p_mdl_cfg - pointer to the MDL configuration data
- *
- * Returns void
- *
- ******************************************************************************/
-extern void bta_hl_co_save_mdl(uint8_t app_id, uint8_t item_idx,
- tBTA_HL_MDL_CFG* p_mdl_cfg);
-/*******************************************************************************
- *
- * Function bta_hl_co_delete_mdl
- *
- * Description This function is called to delete a MDL configuration item in
- * persistent storage
- *
- * Parameters app_id - HDP application ID
- * item_idx - the MDL configuration storage index
- *
- * Returns void
- *
- ******************************************************************************/
-extern void bta_hl_co_delete_mdl(uint8_t app_id, uint8_t item_idx);
-/*******************************************************************************
- *
- * Function bta_hl_co_get_mdl_config
- *
- * Description This function is called to get the MDL configuration
- * from teh persistent memory. This function shall only be
-*called
-*8 once after the device is powered up
- *
- * Parameters app_id - HDP application ID
- * buffer_size - the unit of the buffer size is
-*sizeof(tBTA_HL_MDL_CFG)
- * p_mdl_buf - Point to the starting location of the buffer
- *
- * Returns bool
- *
- *
- ******************************************************************************/
-extern bool bta_hl_co_load_mdl_config(uint8_t app_id, uint8_t buffer_size,
- tBTA_HL_MDL_CFG* p_mdl_buf);
-
-/*******************************************************************************
- *
- * Function bta_hl_co_get_tx_data
- *
- * Description Get the data to be sent
- *
- * Parameters app_id - HDP application ID
- * mdl_handle - MDL handle
- * buf_size - the size of the buffer
- * p_buf - the buffer pointer
- * evt - the evt to be passed back to the HL in the
- * bta_hl_ci_get_tx_data call-in function
- *
- * Returns Void
- *
- ******************************************************************************/
-extern void bta_hl_co_get_tx_data(uint8_t app_id, tBTA_HL_MDL_HANDLE mdl_handle,
- uint16_t buf_size, uint8_t* p_buf,
- uint16_t evt);
-
-/*******************************************************************************
- *
- * Function bta_hl_co_put_rx_data
- *
- * Description Put the received data
- *
- * Parameters app_id - HDP application ID
- * mdl_handle - MDL handle
- * data_size - the size of the data
- * p_data - the data pointer
- * evt - the evt to be passed back to the HL in the
- * bta_hl_ci_put_rx_data call-in function
- *
- * Returns Void
- *
- ******************************************************************************/
-extern void bta_hl_co_put_rx_data(uint8_t app_id, tBTA_HL_MDL_HANDLE mdl_handle,
- uint16_t data_size, uint8_t* p_data,
- uint16_t evt);
-/*******************************************************************************
- *
- * Function bta_hl_co_get_tx_data
- *
- * Description Get the Echo data to be sent
- *
- * Parameters app_id - HDP application ID
- * mcl_handle - MCL handle
- * buf_size - the size of the buffer
- * p_buf - the buffer pointer
- * evt - the evt to be passed back to the HL in the
- * bta_hl_ci_get_tx_data call-in function
- *
- * Returns Void
- *
- ******************************************************************************/
-extern void bta_hl_co_get_echo_data(uint8_t app_id,
- tBTA_HL_MCL_HANDLE mcl_handle,
- uint16_t buf_size, uint8_t* p_buf,
- uint16_t evt);
-
-/*******************************************************************************
- *
- * Function bta_hl_co_put_echo_data
- *
- * Description Put the received loopback echo data
- *
- * Parameters app_id - HDP application ID
- * mcl_handle - MCL handle
- * data_size - the size of the data
- * p_data - the data pointer
- * evt - the evt to be passed back to the HL in the
- * bta_hl_ci_put_echo_data call-in function
- *
- * Returns Void
- *
- ******************************************************************************/
-extern void bta_hl_co_put_echo_data(uint8_t app_id,
- tBTA_HL_MCL_HANDLE mcl_handle,
- uint16_t data_size, uint8_t* p_data,
- uint16_t evt);
-
-#endif /* BTA_HL_CO_H */
diff --git a/bta/jv/bta_jv_act.cc b/bta/jv/bta_jv_act.cc
index 69fa3f2..462ee9d 100644
--- a/bta/jv/bta_jv_act.cc
+++ b/bta/jv/bta_jv_act.cc
@@ -194,9 +194,7 @@
}
}
if (p_cb == NULL) {
- LOG(ERROR) << __func__ << "port_handle=" << port_handle
- << " ctrl block exceeds limit:" << port_handle,
- BTA_JV_MAX_RFC_CONN;
+ LOG(ERROR) << __func__ << "port_handle=" << port_handle << " ctrl block exceeds limit:" << BTA_JV_MAX_RFC_CONN;
}
return p_cb;
}
@@ -480,7 +478,7 @@
static tBTA_JV_PM_CB* bta_jv_alloc_set_pm_profile_cb(uint32_t jv_handle,
tBTA_JV_PM_ID app_id) {
bool bRfcHandle = (jv_handle & BTA_JV_RFCOMM_MASK) != 0;
- RawAddress peer_bd_addr;
+ RawAddress peer_bd_addr = RawAddress::kEmpty;
int i, j;
tBTA_JV_PM_CB** pp_cb;
@@ -494,8 +492,9 @@
pp_cb = &bta_jv_cb.port_cb[j].p_pm_cb;
if (PORT_SUCCESS !=
PORT_CheckConnection(bta_jv_cb.port_cb[j].port_handle,
- peer_bd_addr, NULL))
+ &peer_bd_addr, NULL)) {
i = BTA_JV_PM_MAX_NUM;
+ }
break;
}
}
@@ -604,7 +603,7 @@
}
/** Disables the BT device manager free the resources used by java */
-void bta_jv_disable() { LOG(ERROR) << __func__; }
+void bta_jv_disable() { LOG(INFO) << __func__; }
/**
* We keep a list of PSM's that have been freed from JAVA, for reuse.
@@ -788,7 +787,7 @@
}
/* init the database/set up the filter */
- VLOG(2) << __func__ << ": call SDP_InitDiscoveryDb, num_uuid=", num_uuid;
+ VLOG(2) << __func__ << ": call SDP_InitDiscoveryDb, num_uuid=" << num_uuid;
SDP_InitDiscoveryDb(p_bta_jv_cfg->p_sdp_db, p_bta_jv_cfg->sdp_db_size,
num_uuid, uuid_list, 0, NULL);
@@ -1254,7 +1253,7 @@
tBTA_JV_RFC_CB* p_cb = bta_jv_rfc_port_to_cb(port_handle);
tBTA_JV_PCB* p_pcb = bta_jv_rfc_port_to_pcb(port_handle);
tBTA_JV evt_data;
- RawAddress rem_bda;
+ RawAddress rem_bda = RawAddress::kEmpty;
uint16_t lcid;
tBTA_JV_RFCOMM_CBACK* p_cback; /* the callback function */
@@ -1264,7 +1263,7 @@
VLOG(2) << __func__ << ": code=" << code << ", port_handle=" << port_handle
<< ", handle=" << p_cb->handle;
- PORT_CheckConnection(port_handle, rem_bda, &lcid);
+ PORT_CheckConnection(port_handle, &rem_bda, &lcid);
if (code == PORT_SUCCESS) {
evt_data.rfc_open.handle = p_cb->handle;
@@ -1451,7 +1450,7 @@
tBTA_JV_PCB* p_pcb = bta_jv_rfc_port_to_pcb(port_handle);
tBTA_JV_RFC_CB* p_cb = bta_jv_rfc_port_to_cb(port_handle);
tBTA_JV evt_data;
- RawAddress rem_bda;
+ RawAddress rem_bda = RawAddress::kEmpty;
uint16_t lcid;
VLOG(2) << __func__ << ": code=" << code << ", port_handle=" << port_handle;
if (NULL == p_cb || NULL == p_cb->p_cback) {
@@ -1465,9 +1464,13 @@
<< ", handle=" << loghex(p_cb->handle) << ", p_pcb" << p_pcb
<< ", user=" << p_pcb->rfcomm_slot_id;
- PORT_CheckConnection(port_handle, rem_bda, &lcid);
+ int status = PORT_CheckConnection(port_handle, &rem_bda, &lcid);
int failed = true;
if (code == PORT_SUCCESS) {
+ if (status != PORT_SUCCESS) {
+ LOG(ERROR) << __func__ << ": PORT_CheckConnection returned " << status
+ << ", although port is supposed to be connected";
+ }
evt_data.rfc_srv_open.handle = p_pcb->handle;
evt_data.rfc_srv_open.status = BTA_JV_SUCCESS;
evt_data.rfc_srv_open.rem_bda = rem_bda;
@@ -1521,7 +1524,11 @@
tBTA_JV_RFC_CB* p_cb = bta_jv_rfc_port_to_cb(port_handle);
tBTA_JV evt_data;
- if (NULL == p_cb || NULL == p_cb->p_cback) return;
+ if (NULL == p_cb || NULL == p_cb->p_cback) {
+ LOG(ERROR) << __func__ << ": p_cb=" << p_cb
+ << ", p_cb->p_cback=" << (p_cb ? p_cb->p_cback : 0);
+ return;
+ }
VLOG(2) << __func__ << ": code=" << loghex(code)
<< ", port_handle=" << port_handle << ", handle=" << p_cb->handle;
@@ -2110,11 +2117,12 @@
if (tc) {
// try to find an open socked for that addr and channel
t = fcclient_find_by_addr(tc->clients, &bd_addr);
- if (!t) {
- // no socket -> drop it
- return;
- }
}
+ if (!t) {
+ // no socket -> drop it
+ return;
+ }
+
sock_cback = t->p_cback;
sock_id = t->l2cap_socket_id;
@@ -2157,13 +2165,17 @@
// it could have been deleted/moved from under us, so re-find it */
t = fcclient_find_by_id(id);
if (t) {
- if (evt.l2c_cl_init.status == BTA_JV_SUCCESS)
+ if (evt.l2c_cl_init.status == BTA_JV_SUCCESS) {
call_init_f = !t->init_called;
- else
+ } else {
fcclient_free(t);
+ t = NULL;
+ }
}
if (call_init_f) p_cback(BTA_JV_L2CAP_CL_INIT_EVT, &evt, l2cap_socket_id);
- t->init_called = true;
+ if (t) {
+ t->init_called = true;
+ }
}
/* stops an LE L2CAP server */
diff --git a/bta/jv/bta_jv_api.cc b/bta/jv/bta_jv_api.cc
index 74818b6..6702e0d 100644
--- a/bta/jv/bta_jv_api.cc
+++ b/bta/jv/bta_jv_api.cc
@@ -29,13 +29,13 @@
#include "bt_common.h"
#include "bta_api.h"
-#include "bta_closure_api.h"
#include "bta_jv_api.h"
#include "bta_jv_int.h"
#include "bta_sys.h"
#include "gap_api.h"
#include "port_api.h"
#include "sdp_api.h"
+#include "stack/include/btu.h"
#include "utl.h"
using base::Bind;
@@ -75,7 +75,7 @@
bta_jv_enabled = true;
- do_in_bta_thread(FROM_HERE, Bind(&bta_jv_enable, p_cback));
+ do_in_main_thread(FROM_HERE, Bind(&bta_jv_enable, p_cback));
return BTA_JV_SUCCESS;
}
@@ -85,7 +85,7 @@
bta_jv_enabled = false;
- do_in_bta_thread(FROM_HERE, Bind(&bta_jv_disable));
+ do_in_main_thread(FROM_HERE, Bind(&bta_jv_disable));
}
/*******************************************************************************
@@ -140,8 +140,8 @@
CHECK(false) << "Invalid conn_type=" << conn_type;
}
- do_in_bta_thread(FROM_HERE,
- Bind(&bta_jv_get_channel_id, conn_type, channel, id, id));
+ do_in_main_thread(FROM_HERE,
+ Bind(&bta_jv_get_channel_id, conn_type, channel, id, id));
}
/*******************************************************************************
@@ -161,7 +161,7 @@
tBTA_JV_STATUS BTA_JvFreeChannel(uint16_t channel, int conn_type) {
VLOG(2) << __func__;
- do_in_bta_thread(FROM_HERE, Bind(&bta_jv_free_scn, conn_type, channel));
+ do_in_main_thread(FROM_HERE, Bind(&bta_jv_free_scn, conn_type, channel));
return BTA_JV_SUCCESS;
}
@@ -186,9 +186,9 @@
Uuid* uuid_list_copy = new Uuid[num_uuid];
memcpy(uuid_list_copy, p_uuid_list, num_uuid * sizeof(Uuid));
- do_in_bta_thread(FROM_HERE,
- Bind(&bta_jv_start_discovery, bd_addr, num_uuid,
- base::Owned(uuid_list_copy), rfcomm_slot_id));
+ do_in_main_thread(FROM_HERE,
+ Bind(&bta_jv_start_discovery, bd_addr, num_uuid,
+ base::Owned(uuid_list_copy), rfcomm_slot_id));
return BTA_JV_SUCCESS;
}
@@ -207,7 +207,7 @@
tBTA_JV_STATUS BTA_JvCreateRecordByUser(uint32_t rfcomm_slot_id) {
VLOG(2) << __func__;
- do_in_bta_thread(FROM_HERE, Bind(&bta_jv_create_record, rfcomm_slot_id));
+ do_in_main_thread(FROM_HERE, Bind(&bta_jv_create_record, rfcomm_slot_id));
return BTA_JV_SUCCESS;
}
@@ -224,7 +224,7 @@
tBTA_JV_STATUS BTA_JvDeleteRecord(uint32_t handle) {
VLOG(2) << __func__;
- do_in_bta_thread(FROM_HERE, Bind(&bta_jv_delete_record, handle));
+ do_in_main_thread(FROM_HERE, Bind(&bta_jv_delete_record, handle));
return BTA_JV_SUCCESS;
}
@@ -245,8 +245,8 @@
uint32_t l2cap_socket_id) {
VLOG(2) << __func__;
CHECK(p_cback);
- do_in_bta_thread(FROM_HERE, Bind(&bta_jv_l2cap_connect_le, remote_chan,
- peer_bd_addr, p_cback, l2cap_socket_id));
+ do_in_main_thread(FROM_HERE, Bind(&bta_jv_l2cap_connect_le, remote_chan,
+ peer_bd_addr, p_cback, l2cap_socket_id));
}
/*******************************************************************************
@@ -271,10 +271,10 @@
VLOG(2) << __func__;
CHECK(p_cback);
- do_in_bta_thread(FROM_HERE,
- Bind(&bta_jv_l2cap_connect, conn_type, sec_mask, role,
- remote_psm, rx_mtu, peer_bd_addr, base::Passed(&cfg),
- base::Passed(&ertm_info), p_cback, l2cap_socket_id));
+ do_in_main_thread(FROM_HERE,
+ Bind(&bta_jv_l2cap_connect, conn_type, sec_mask, role,
+ remote_psm, rx_mtu, peer_bd_addr, base::Passed(&cfg),
+ base::Passed(&ertm_info), p_cback, l2cap_socket_id));
}
/*******************************************************************************
@@ -293,7 +293,7 @@
if (handle >= BTA_JV_MAX_L2C_CONN || !bta_jv_cb.l2c_cb[handle].p_cback)
return BTA_JV_FAILURE;
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE, Bind(&bta_jv_l2cap_close, handle, &bta_jv_cb.l2c_cb[handle]));
return BTA_JV_SUCCESS;
}
@@ -312,7 +312,7 @@
tBTA_JV_STATUS BTA_JvL2capCloseLE(uint32_t handle) {
VLOG(2) << __func__;
- do_in_bta_thread(FROM_HERE, Bind(&bta_jv_l2cap_close_fixed, handle));
+ do_in_main_thread(FROM_HERE, Bind(&bta_jv_l2cap_close_fixed, handle));
return BTA_JV_SUCCESS;
}
@@ -339,10 +339,10 @@
VLOG(2) << __func__;
CHECK(p_cback);
- do_in_bta_thread(FROM_HERE,
- Bind(&bta_jv_l2cap_start_server, conn_type, sec_mask, role,
- local_psm, rx_mtu, base::Passed(&cfg),
- base::Passed(&ertm_info), p_cback, l2cap_socket_id));
+ do_in_main_thread(FROM_HERE,
+ Bind(&bta_jv_l2cap_start_server, conn_type, sec_mask, role,
+ local_psm, rx_mtu, base::Passed(&cfg),
+ base::Passed(&ertm_info), p_cback, l2cap_socket_id));
}
/*******************************************************************************
@@ -363,8 +363,8 @@
uint32_t l2cap_socket_id) {
VLOG(2) << __func__;
CHECK(p_cback);
- do_in_bta_thread(FROM_HERE, Bind(&bta_jv_l2cap_start_server_le, local_chan,
- p_cback, l2cap_socket_id));
+ do_in_main_thread(FROM_HERE, Bind(&bta_jv_l2cap_start_server_le, local_chan,
+ p_cback, l2cap_socket_id));
}
/*******************************************************************************
@@ -382,8 +382,8 @@
uint32_t l2cap_socket_id) {
VLOG(2) << __func__;
- do_in_bta_thread(FROM_HERE,
- Bind(&bta_jv_l2cap_stop_server, local_psm, l2cap_socket_id));
+ do_in_main_thread(
+ FROM_HERE, Bind(&bta_jv_l2cap_stop_server, local_psm, l2cap_socket_id));
return BTA_JV_SUCCESS;
}
@@ -402,7 +402,7 @@
uint32_t l2cap_socket_id) {
VLOG(2) << __func__;
- do_in_bta_thread(FROM_HERE, Bind(&bta_jv_l2cap_stop_server_le, local_chan));
+ do_in_main_thread(FROM_HERE, Bind(&bta_jv_l2cap_stop_server_le, local_chan));
return BTA_JV_SUCCESS;
}
@@ -491,8 +491,8 @@
return BTA_JV_FAILURE;
}
- do_in_bta_thread(FROM_HERE, Bind(&bta_jv_l2cap_write, handle, req_id, msg,
- user_id, &bta_jv_cb.l2c_cb[handle]));
+ do_in_main_thread(FROM_HERE, Bind(&bta_jv_l2cap_write, handle, req_id, msg,
+ user_id, &bta_jv_cb.l2c_cb[handle]));
return BTA_JV_SUCCESS;
}
@@ -512,8 +512,8 @@
BT_HDR* msg, uint32_t user_id) {
VLOG(2) << __func__;
- do_in_bta_thread(FROM_HERE, Bind(&bta_jv_l2cap_write_fixed, channel, addr,
- req_id, msg, user_id, p_cback));
+ do_in_main_thread(FROM_HERE, Bind(&bta_jv_l2cap_write_fixed, channel, addr,
+ req_id, msg, user_id, p_cback));
}
/*******************************************************************************
@@ -541,9 +541,9 @@
if (!p_cback) return BTA_JV_FAILURE; /* Nothing to do */
- do_in_bta_thread(FROM_HERE,
- Bind(&bta_jv_rfcomm_connect, sec_mask, role, remote_scn,
- peer_bd_addr, p_cback, rfcomm_slot_id));
+ do_in_main_thread(FROM_HERE,
+ Bind(&bta_jv_rfcomm_connect, sec_mask, role, remote_scn,
+ peer_bd_addr, p_cback, rfcomm_slot_id));
return BTA_JV_SUCCESS;
}
@@ -567,8 +567,8 @@
si >= BTA_JV_MAX_RFC_SR_SESSION || !bta_jv_cb.rfc_cb[hi].rfc_hdl[si])
return BTA_JV_FAILURE;
- do_in_bta_thread(FROM_HERE,
- Bind(&bta_jv_rfcomm_close, handle, rfcomm_slot_id));
+ do_in_main_thread(FROM_HERE,
+ Bind(&bta_jv_rfcomm_close, handle, rfcomm_slot_id));
return BTA_JV_SUCCESS;
}
@@ -602,9 +602,9 @@
max_session = BTA_JV_MAX_RFC_SR_SESSION;
}
- do_in_bta_thread(FROM_HERE,
- Bind(&bta_jv_rfcomm_start_server, sec_mask, role, local_scn,
- max_session, p_cback, rfcomm_slot_id));
+ do_in_main_thread(FROM_HERE,
+ Bind(&bta_jv_rfcomm_start_server, sec_mask, role, local_scn,
+ max_session, p_cback, rfcomm_slot_id));
return BTA_JV_SUCCESS;
}
@@ -623,8 +623,8 @@
uint32_t rfcomm_slot_id) {
VLOG(2) << __func__;
- do_in_bta_thread(FROM_HERE,
- Bind(&bta_jv_rfcomm_stop_server, handle, rfcomm_slot_id));
+ do_in_main_thread(FROM_HERE,
+ Bind(&bta_jv_rfcomm_stop_server, handle, rfcomm_slot_id));
return BTA_JV_SUCCESS;
}
@@ -675,8 +675,8 @@
VLOG(2) << "write ok";
tBTA_JV_RFC_CB* p_cb = &bta_jv_cb.rfc_cb[hi];
- do_in_bta_thread(FROM_HERE, Bind(&bta_jv_rfcomm_write, handle, req_id, p_cb,
- &bta_jv_cb.port_cb[p_cb->rfc_hdl[si] - 1]));
+ do_in_main_thread(FROM_HERE, Bind(&bta_jv_rfcomm_write, handle, req_id, p_cb,
+ &bta_jv_cb.port_cb[p_cb->rfc_hdl[si] - 1]));
return BTA_JV_SUCCESS;
}
@@ -707,7 +707,7 @@
tBTA_JV_CONN_STATE init_st) {
VLOG(2) << __func__ << " handle=" << loghex(handle) << ", app_id:" << app_id;
- do_in_bta_thread(FROM_HERE,
- Bind(&bta_jv_set_pm_profile, handle, app_id, init_st));
+ do_in_main_thread(FROM_HERE,
+ Bind(&bta_jv_set_pm_profile, handle, app_id, init_st));
return BTA_JV_SUCCESS;
}
diff --git a/bta/pan/bta_pan_act.cc b/bta/pan/bta_pan_act.cc
index 04c06d0..548d6fd 100644
--- a/bta/pan/bta_pan_act.cc
+++ b/bta/pan/bta_pan_act.cc
@@ -28,7 +28,7 @@
#include <string.h>
-#include <cutils/log.h>
+#include <log/log.h>
#include "bt_common.h"
#include "bta_api.h"
diff --git a/bta/sys/bta_sys.h b/bta/sys/bta_sys.h
index a72f34b..29e9a3f 100644
--- a/bta/sys/bta_sys.h
+++ b/bta/sys/bta_sys.h
@@ -31,8 +31,6 @@
#include <base/logging.h>
#include <base/threading/thread.h>
-#include "bta/include/bta_closure_api.h"
-
/*****************************************************************************
* Constants and data types
****************************************************************************/
@@ -224,7 +222,7 @@
extern bool bta_sys_is_register(uint8_t id);
extern uint16_t bta_sys_get_sys_features(void);
extern void bta_sys_sendmsg(void* p_msg);
-extern void bta_sys_start_timer(alarm_t* alarm, period_ms_t interval,
+extern void bta_sys_start_timer(alarm_t* alarm, uint64_t interval_ms,
uint16_t event, uint16_t layer_specific);
extern void bta_sys_disable(tBTA_SYS_HW_MODULE module);
diff --git a/bta/sys/bta_sys_main.cc b/bta/sys/bta_sys_main.cc
index dda3977..1036e74 100644
--- a/bta/sys/bta_sys_main.cc
+++ b/bta/sys/bta_sys_main.cc
@@ -26,8 +26,6 @@
#include <base/bind.h>
#include <base/logging.h>
-#include <base/threading/thread.h>
-#include <pthread.h>
#include <string.h>
#include "bt_common.h"
@@ -40,7 +38,6 @@
#include "osi/include/fixed_queue.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)
@@ -50,8 +47,6 @@
/* system manager control block definition */
tBTA_SYS_CB bta_sys_cb;
-extern thread_t* bt_workqueue_thread;
-
/* trace level */
/* TODO Hard-coded trace levels - Needs to be configurable */
uint8_t appl_trace_level = BT_TRACE_LEVEL_WARNING; // APPL_INITIAL_TRACE_LEVEL;
@@ -530,77 +525,11 @@
*
******************************************************************************/
void bta_sys_sendmsg(void* p_msg) {
- base::MessageLoop* bta_message_loop = get_message_loop();
-
- if (!bta_message_loop || !bta_message_loop->task_runner().get()) {
- APPL_TRACE_ERROR("%s: MessageLooper not initialized", __func__);
- return;
+ if (do_in_main_thread(
+ FROM_HERE, base::Bind(&bta_sys_event, static_cast<BT_HDR*>(p_msg))) !=
+ BT_STATUS_SUCCESS) {
+ LOG(ERROR) << __func__ << ": do_in_main_thread failed";
}
-
- bta_message_loop->task_runner()->PostTask(
- FROM_HERE, base::Bind(&bta_sys_event, static_cast<BT_HDR*>(p_msg)));
-}
-
-/*******************************************************************************
- *
- * Function do_in_bta_thread
- *
- * Description Post a closure to be ran in the bta thread
- *
- * Returns BT_STATUS_SUCCESS on success
- *
- ******************************************************************************/
-bt_status_t do_in_bta_thread(const tracked_objects::Location& from_here,
- const base::Closure& task) {
- base::MessageLoop* bta_message_loop = get_message_loop();
- if (!bta_message_loop) {
- APPL_TRACE_ERROR("%s: MessageLooper not initialized", __func__);
- return BT_STATUS_FAIL;
- }
-
- scoped_refptr<base::SingleThreadTaskRunner> task_runner =
- bta_message_loop->task_runner();
- if (!task_runner.get()) {
- APPL_TRACE_ERROR("%s: task runner is dead", __func__);
- return BT_STATUS_FAIL;
- }
-
- if (!task_runner->PostTask(from_here, task)) {
- APPL_TRACE_ERROR("%s: Post task to task runner failed!", __func__);
- return BT_STATUS_FAIL;
- }
- return BT_STATUS_SUCCESS;
-}
-
-/*******************************************************************************
- *
- * Function do_in_bta_thread_once
- *
- * Description Post a closure to be ran in the bta thread once
- *
- * Returns BT_STATUS_SUCCESS on success
- *
- ******************************************************************************/
-bt_status_t do_in_bta_thread_once(const tracked_objects::Location& from_here,
- base::OnceClosure task) {
- base::MessageLoop* bta_message_loop = get_message_loop();
- if (!bta_message_loop) {
- APPL_TRACE_ERROR("%s: MessageLooper not initialized", __func__);
- return BT_STATUS_FAIL;
- }
-
- scoped_refptr<base::SingleThreadTaskRunner> task_runner =
- bta_message_loop->task_runner();
- if (!task_runner.get()) {
- APPL_TRACE_ERROR("%s: task runner is dead", __func__);
- return BT_STATUS_FAIL;
- }
-
- if (!task_runner->PostTask(from_here, std::move(task))) {
- APPL_TRACE_ERROR("%s: Post task to task runner failed!", __func__);
- return BT_STATUS_FAIL;
- }
- return BT_STATUS_SUCCESS;
}
/*******************************************************************************
@@ -613,14 +542,14 @@
* Returns void
*
******************************************************************************/
-void bta_sys_start_timer(alarm_t* alarm, period_ms_t interval, uint16_t event,
+void bta_sys_start_timer(alarm_t* alarm, uint64_t interval_ms, uint16_t event,
uint16_t layer_specific) {
BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
p_buf->event = event;
p_buf->layer_specific = layer_specific;
- alarm_set_on_mloop(alarm, interval, bta_sys_sendmsg, p_buf);
+ alarm_set_on_mloop(alarm, interval_ms, bta_sys_sendmsg, p_buf);
}
/*******************************************************************************
diff --git a/bta/test/bta_hf_client_test.cc b/bta/test/bta_hf_client_test.cc
index 107a2e5..9b9ade2 100644
--- a/bta/test/bta_hf_client_test.cc
+++ b/bta/test/bta_hf_client_test.cc
@@ -25,7 +25,7 @@
class MessageLoop;
} // namespace base
-base::MessageLoop* get_message_loop() { return NULL; }
+base::MessageLoop* get_main_message_loop() { return NULL; }
namespace {
const RawAddress bdaddr1({0x11, 0x22, 0x33, 0x44, 0x55, 0x66});
diff --git a/bta/test/gatt/database_builder_sample_device_test.cc b/bta/test/gatt/database_builder_sample_device_test.cc
new file mode 100644
index 0000000..bd4dabc
--- /dev/null
+++ b/bta/test/gatt/database_builder_sample_device_test.cc
@@ -0,0 +1,286 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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 <gtest/gtest.h>
+
+#include <base/logging.h>
+#include <utility>
+
+#include "gatt/database_builder.h"
+
+using bluetooth::Uuid;
+
+namespace gatt {
+
+namespace {
+/* EXPECT_EQ doesn't work well with static constexpr fields, need a variable
+ * with address */
+constexpr std::pair<uint16_t, uint16_t> EXPLORE_END =
+ DatabaseBuilder::EXPLORE_END;
+
+/* make_pair doesn't work well with EXPECT_EQ, have own helper instead */
+inline std::pair<uint16_t, uint16_t> make_pair_u16(uint16_t first,
+ uint16_t second) {
+ return std::make_pair(first, second);
+}
+
+// clang-format off
+Uuid SERVICE_1_UUID = Uuid::FromString("00001800-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_2_UUID = Uuid::FromString("00001801-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_3_UUID = Uuid::FromString("0000180f-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_4_UUID = Uuid::FromString("0000fef5-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_5_UUID = Uuid::FromString("0000180a-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_6_UUID = Uuid::FromString("0000fe55-0000-1000-8000-00805f9b34fb");
+
+Uuid SERVICE_1_CHAR_1_UUID = Uuid::FromString("00002a00-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_1_CHAR_2_UUID = Uuid::FromString("00002a01-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_1_CHAR_3_UUID = Uuid::FromString("00002a04-0000-1000-8000-00805f9b34fb");
+
+Uuid SERVICE_3_CHAR_1_UUID = Uuid::FromString("00002a19-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_3_CHAR_1_DESC_1_UUID = Uuid::FromString("00002902-0000-1000-8000-00805f9b34fb");
+
+Uuid SERVICE_4_CHAR_1_UUID = Uuid::FromString("8082caa8-41a6-4021-91c6-56f9b954cc34");
+Uuid SERVICE_4_CHAR_2_UUID = Uuid::FromString("724249f0-5ec3-4b5f-8804-42345af08651");
+Uuid SERVICE_4_CHAR_3_UUID = Uuid::FromString("6c53db25-47a1-45fe-a022-7c92fb334fd4");
+Uuid SERVICE_4_CHAR_4_UUID = Uuid::FromString("9d84b9a3-000c-49d8-9183-855b673fda31");
+Uuid SERVICE_4_CHAR_5_UUID = Uuid::FromString("457871e8-d516-4ca1-9116-57d0b17b9cb2");
+Uuid SERVICE_4_CHAR_6_UUID = Uuid::FromString("5f78df94-798c-46f5-990a-b3eb6a065c88");
+Uuid SERVICE_4_CHAR_6_DESC_1_UUID = Uuid::FromString("00002902-0000-1000-8000-00805f9b34fb");
+
+Uuid SERVICE_5_CHAR_1_UUID = Uuid::FromString("00002a29-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_5_CHAR_2_UUID = Uuid::FromString("00002a24-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_5_CHAR_3_UUID = Uuid::FromString("00002a25-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_5_CHAR_4_UUID = Uuid::FromString("00002a27-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_5_CHAR_5_UUID = Uuid::FromString("00002a26-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_5_CHAR_6_UUID = Uuid::FromString("00002a28-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_5_CHAR_7_UUID = Uuid::FromString("00002a50-0000-1000-8000-00805f9b34fb");
+
+Uuid SERVICE_6_CHAR_1_UUID = Uuid::FromString("00000001-1000-1000-8000-00805f9b34fb");
+Uuid SERVICE_6_CHAR_1_DESC_1_UUID = Uuid::FromString("00002902-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_6_CHAR_2_UUID = Uuid::FromString("00000002-1000-1000-8000-00805f9b34fb");
+Uuid SERVICE_6_CHAR_3_UUID = Uuid::FromString("00000003-1000-1000-8000-00805f9b34fb");
+// clang-format on
+
+} // namespace
+
+// clang-format off
+/* Content of sample database, comes from Daydream controller:
+Service: handle=0x0001, end_handle=0x0007, uuid=00001800-0000-1000-8000-00805f9b34fb
+ Characteristic: declaration_handle=0x0002, value_handle=0x0003, uuid=00002a00-0000-1000-8000-00805f9b34fb, prop=0x02
+ Characteristic: declaration_handle=0x0004, value_handle=0x0005, uuid=00002a01-0000-1000-8000-00805f9b34fb, prop=0x02
+ Characteristic: declaration_handle=0x0006, value_handle=0x0007, uuid=00002a04-0000-1000-8000-00805f9b34fb, prop=0x02
+Service: handle=0x0008, end_handle=0x0008, uuid=00001801-0000-1000-8000-00805f9b34fb
+Service: handle=0x0009, end_handle=0x000c, uuid=0000180f-0000-1000-8000-00805f9b34fb
+ Characteristic: declaration_handle=0x000a, value_handle=0x000b, uuid=00002a19-0000-1000-8000-00805f9b34fb, prop=0x12
+ Descriptor: handle=0x000c, uuid=00002902-0000-1000-8000-00805f9b34fb
+Service: handle=0x000d, end_handle=0x001a, uuid=0000fef5-0000-1000-8000-00805f9b34fb
+ Characteristic: declaration_handle=0x000e, value_handle=0x000f, uuid=8082caa8-41a6-4021-91c6-56f9b954cc34, prop=0x0a
+ Characteristic: declaration_handle=0x0010, value_handle=0x0011, uuid=724249f0-5ec3-4b5f-8804-42345af08651, prop=0x0a
+ Characteristic: declaration_handle=0x0012, value_handle=0x0013, uuid=6c53db25-47a1-45fe-a022-7c92fb334fd4, prop=0x02
+ Characteristic: declaration_handle=0x0014, value_handle=0x0015, uuid=9d84b9a3-000c-49d8-9183-855b673fda31, prop=0x0a
+ Characteristic: declaration_handle=0x0016, value_handle=0x0017, uuid=457871e8-d516-4ca1-9116-57d0b17b9cb2, prop=0x0e
+ Characteristic: declaration_handle=0x0018, value_handle=0x0019, uuid=5f78df94-798c-46f5-990a-b3eb6a065c88, prop=0x12
+ Descriptor: handle=0x001a, uuid=00002902-0000-1000-8000-00805f9b34fb
+Service: handle=0x001b, end_handle=0x0029, uuid=0000180a-0000-1000-8000-00805f9b34fb
+ Characteristic: declaration_handle=0x001c, value_handle=0x001d, uuid=00002a29-0000-1000-8000-00805f9b34fb, prop=0x02
+ Characteristic: declaration_handle=0x001e, value_handle=0x001f, uuid=00002a24-0000-1000-8000-00805f9b34fb, prop=0x02
+ Characteristic: declaration_handle=0x0020, value_handle=0x0021, uuid=00002a25-0000-1000-8000-00805f9b34fb, prop=0x02
+ Characteristic: declaration_handle=0x0022, value_handle=0x0023, uuid=00002a27-0000-1000-8000-00805f9b34fb, prop=0x02
+ Characteristic: declaration_handle=0x0024, value_handle=0x0025, uuid=00002a26-0000-1000-8000-00805f9b34fb, prop=0x02
+ Characteristic: declaration_handle=0x0026, value_handle=0x0027, uuid=00002a28-0000-1000-8000-00805f9b34fb, prop=0x02
+ Characteristic: declaration_handle=0x0028, value_handle=0x0029, uuid=00002a50-0000-1000-8000-00805f9b34fb, prop=0x02
+Service: handle=0x002a, end_handle=0x0031, uuid=0000fe55-0000-1000-8000-00805f9b34fb
+ Characteristic: declaration_handle=0x002b, value_handle=0x002c, uuid=00000001-1000-1000-8000-00805f9b34fb, prop=0x10
+ Descriptor: handle=0x002d, uuid=00002902-0000-1000-8000-00805f9b34fb
+ Characteristic: declaration_handle=0x002e, value_handle=0x002f, uuid=00000002-1000-1000-8000-00805f9b34fb, prop=0x08
+ Characteristic: declaration_handle=0x0030, value_handle=0x0031, uuid=00000003-1000-1000-8000-00805f9b34fb, prop=0x02
+*/
+// clang-format on
+
+/* This test verifies that DatabaseBuilder will properly discover database
+ * content from a remote device. It also verify that after the discovery is
+ * done, returned database is equal to the discovered one */
+TEST(DatabaseBuilderSampleDeviceTest, DoDiscovery) {
+ DatabaseBuilder builder;
+
+ EXPECT_FALSE(builder.InProgress());
+
+ // At start of discovery, builder will receive All services in order from
+ // lower layers.
+ builder.AddService(0x0001, 0x0007, SERVICE_1_UUID, true);
+
+ // The moment we receive first service, we are in progress
+ // TODO: we should be able to set InProgress state once we sent GATT request,
+ // not when it's back and parsed
+ EXPECT_TRUE(builder.InProgress());
+
+ builder.AddService(0x0008, 0x0008, SERVICE_2_UUID, true);
+ builder.AddService(0x0009, 0x000c, SERVICE_3_UUID, true);
+ builder.AddService(0x000d, 0x001a, SERVICE_4_UUID, true);
+ builder.AddService(0x001b, 0x0029, SERVICE_5_UUID, true);
+ builder.AddService(0x002a, 0x0031, SERVICE_6_UUID, true);
+
+ // At this moment, all services are received, stack will grab them one and one
+ // to discover their content.
+ EXPECT_TRUE(builder.StartNextServiceExploration());
+
+ // Grabbing first service, to start Included Service and Characteristic
+ // discovery
+ EXPECT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x0001, 0x0007));
+
+ builder.AddCharacteristic(0x0002, 0x0003, SERVICE_1_CHAR_1_UUID, 0x02);
+ builder.AddCharacteristic(0x0004, 0x0005, SERVICE_1_CHAR_2_UUID, 0x02);
+ builder.AddCharacteristic(0x0006, 0x0007, SERVICE_1_CHAR_3_UUID, 0x02);
+
+ // All characteristics were discovered, stack will try to look for
+ // descriptors. Since there is no space for descriptors, builder should return
+ // nothing more to discover
+ EXPECT_EQ(builder.NextDescriptorRangeToExplore(), EXPLORE_END);
+
+ // Service with handles 0x0008, 0x0008 is skipped for exploration - we know
+ // it's empty.
+ EXPECT_TRUE(builder.StartNextServiceExploration());
+ EXPECT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x0009, 0x000c));
+
+ builder.AddCharacteristic(0x000a, 0x000b, SERVICE_3_CHAR_1_UUID, 0x12);
+
+ EXPECT_EQ(builder.NextDescriptorRangeToExplore(),
+ make_pair_u16(0x000c, 0x000c));
+
+ builder.AddDescriptor(0x000c, SERVICE_3_CHAR_1_DESC_1_UUID);
+
+ // All descriptors were explored
+ EXPECT_EQ(builder.NextDescriptorRangeToExplore(), EXPLORE_END);
+
+ EXPECT_TRUE(builder.StartNextServiceExploration());
+ EXPECT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x000d, 0x001a));
+
+ builder.AddCharacteristic(0x000e, 0x000f, SERVICE_4_CHAR_1_UUID, 0x0a);
+ builder.AddCharacteristic(0x0010, 0x0011, SERVICE_4_CHAR_2_UUID, 0x0a);
+ builder.AddCharacteristic(0x0012, 0x0013, SERVICE_4_CHAR_3_UUID, 0x02);
+ builder.AddCharacteristic(0x0014, 0x0015, SERVICE_4_CHAR_4_UUID, 0x0a);
+ builder.AddCharacteristic(0x0016, 0x0017, SERVICE_4_CHAR_5_UUID, 0x0e);
+ builder.AddCharacteristic(0x0018, 0x0019, SERVICE_4_CHAR_6_UUID, 0x12);
+
+ // Just last Characteristic have space for descriptor
+ EXPECT_EQ(builder.NextDescriptorRangeToExplore(),
+ make_pair_u16(0x001a, 0x001a));
+
+ builder.AddDescriptor(0x001a, SERVICE_4_CHAR_6_DESC_1_UUID);
+
+ // All descriptors were explored
+ EXPECT_EQ(builder.NextDescriptorRangeToExplore(), EXPLORE_END);
+
+ EXPECT_TRUE(builder.StartNextServiceExploration());
+ EXPECT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x001b, 0x0029));
+
+ builder.AddCharacteristic(0x001c, 0x001d, SERVICE_5_CHAR_1_UUID, 0x02);
+ builder.AddCharacteristic(0x001e, 0x001f, SERVICE_5_CHAR_2_UUID, 0x02);
+ builder.AddCharacteristic(0x0020, 0x0021, SERVICE_5_CHAR_3_UUID, 0x02);
+ builder.AddCharacteristic(0x0022, 0x0023, SERVICE_5_CHAR_4_UUID, 0x02);
+ builder.AddCharacteristic(0x0024, 0x0025, SERVICE_5_CHAR_5_UUID, 0x02);
+ builder.AddCharacteristic(0x0026, 0x0027, SERVICE_5_CHAR_6_UUID, 0x02);
+ builder.AddCharacteristic(0x0028, 0x0029, SERVICE_5_CHAR_7_UUID, 0x02);
+
+ // No space for descriptors
+ EXPECT_EQ(builder.NextDescriptorRangeToExplore(), EXPLORE_END);
+
+ EXPECT_TRUE(builder.StartNextServiceExploration());
+ EXPECT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x002a, 0x0031));
+
+ builder.AddCharacteristic(0x002b, 0x002c, SERVICE_6_CHAR_1_UUID, 0x10);
+ builder.AddCharacteristic(0x002e, 0x002f, SERVICE_6_CHAR_2_UUID, 0x08);
+ builder.AddCharacteristic(0x0030, 0x0031, SERVICE_6_CHAR_3_UUID, 0x02);
+
+ // Just one Characteristic have space for descriptor
+ EXPECT_EQ(builder.NextDescriptorRangeToExplore(),
+ make_pair_u16(0x002d, 0x002d));
+
+ builder.AddDescriptor(0x002d, SERVICE_6_CHAR_1_DESC_1_UUID);
+
+ // All descriptors were explored
+ EXPECT_EQ(builder.NextDescriptorRangeToExplore(), EXPLORE_END);
+
+ EXPECT_FALSE(builder.StartNextServiceExploration());
+
+ EXPECT_TRUE(builder.InProgress());
+ Database result = builder.Build();
+ EXPECT_FALSE(builder.InProgress());
+
+ // verify that the returned database matches what was discovered
+ EXPECT_EQ(result.Services()[0].handle, 0x0001);
+ EXPECT_EQ(result.Services()[0].uuid, SERVICE_1_UUID);
+ EXPECT_EQ(result.Services()[1].uuid, SERVICE_2_UUID);
+ EXPECT_EQ(result.Services()[2].uuid, SERVICE_3_UUID);
+ EXPECT_EQ(result.Services()[3].uuid, SERVICE_4_UUID);
+ EXPECT_EQ(result.Services()[4].uuid, SERVICE_5_UUID);
+ EXPECT_EQ(result.Services()[5].uuid, SERVICE_6_UUID);
+
+ EXPECT_EQ(result.Services()[0].characteristics[0].uuid,
+ SERVICE_1_CHAR_1_UUID);
+ EXPECT_EQ(result.Services()[0].characteristics[1].uuid,
+ SERVICE_1_CHAR_2_UUID);
+ EXPECT_EQ(result.Services()[0].characteristics[2].uuid,
+ SERVICE_1_CHAR_3_UUID);
+
+ EXPECT_EQ(result.Services()[2].characteristics[0].uuid,
+ SERVICE_3_CHAR_1_UUID);
+ EXPECT_EQ(result.Services()[2].characteristics[0].descriptors[0].uuid,
+ SERVICE_3_CHAR_1_DESC_1_UUID);
+
+ EXPECT_EQ(result.Services()[3].characteristics[0].uuid,
+ SERVICE_4_CHAR_1_UUID);
+ EXPECT_EQ(result.Services()[3].characteristics[1].uuid,
+ SERVICE_4_CHAR_2_UUID);
+ EXPECT_EQ(result.Services()[3].characteristics[2].uuid,
+ SERVICE_4_CHAR_3_UUID);
+ EXPECT_EQ(result.Services()[3].characteristics[3].uuid,
+ SERVICE_4_CHAR_4_UUID);
+ EXPECT_EQ(result.Services()[3].characteristics[4].uuid,
+ SERVICE_4_CHAR_5_UUID);
+ EXPECT_EQ(result.Services()[3].characteristics[5].uuid,
+ SERVICE_4_CHAR_6_UUID);
+ EXPECT_EQ(result.Services()[3].characteristics[5].descriptors[0].uuid,
+ SERVICE_4_CHAR_6_DESC_1_UUID);
+
+ EXPECT_EQ(result.Services()[4].characteristics[0].uuid,
+ SERVICE_5_CHAR_1_UUID);
+ EXPECT_EQ(result.Services()[4].characteristics[1].uuid,
+ SERVICE_5_CHAR_2_UUID);
+ EXPECT_EQ(result.Services()[4].characteristics[2].uuid,
+ SERVICE_5_CHAR_3_UUID);
+ EXPECT_EQ(result.Services()[4].characteristics[3].uuid,
+ SERVICE_5_CHAR_4_UUID);
+ EXPECT_EQ(result.Services()[4].characteristics[4].uuid,
+ SERVICE_5_CHAR_5_UUID);
+ EXPECT_EQ(result.Services()[4].characteristics[5].uuid,
+ SERVICE_5_CHAR_6_UUID);
+ EXPECT_EQ(result.Services()[4].characteristics[6].uuid,
+ SERVICE_5_CHAR_7_UUID);
+
+ EXPECT_EQ(result.Services()[5].characteristics[0].uuid,
+ SERVICE_6_CHAR_1_UUID);
+ EXPECT_EQ(result.Services()[5].characteristics[0].descriptors[0].uuid,
+ SERVICE_6_CHAR_1_DESC_1_UUID);
+ EXPECT_EQ(result.Services()[5].characteristics[1].uuid,
+ SERVICE_6_CHAR_2_UUID);
+ EXPECT_EQ(result.Services()[5].characteristics[2].uuid,
+ SERVICE_6_CHAR_3_UUID);
+}
+
+} // namespace gatt
\ No newline at end of file
diff --git a/bta/test/gatt/database_builder_test.cc b/bta/test/gatt/database_builder_test.cc
new file mode 100644
index 0000000..fcafb49
--- /dev/null
+++ b/bta/test/gatt/database_builder_test.cc
@@ -0,0 +1,165 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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 <gtest/gtest.h>
+
+#include <base/logging.h>
+#include <utility>
+
+#include "gatt/database_builder.h"
+
+using bluetooth::Uuid;
+
+namespace gatt {
+
+namespace {
+/* make_pair doesn't work well with EXPECT_EQ, have own helper instead */
+inline std::pair<uint16_t, uint16_t> make_pair_u16(uint16_t first,
+ uint16_t second) {
+ return std::make_pair(first, second);
+}
+
+Uuid SERVICE_1_UUID = Uuid::FromString("00001800-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_2_UUID = Uuid::FromString("00001801-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_3_UUID = Uuid::FromString("0000180f-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_4_UUID = Uuid::FromString("0000fef5-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_5_UUID = Uuid::FromString("0000180a-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_1_CHAR_1_UUID =
+ Uuid::FromString("00002a00-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_1_CHAR_1_DESC_1_UUID =
+ Uuid::FromString("00002902-0000-1000-8000-00805f9b34fb");
+
+} // namespace
+
+/* Verify adding empty service works ok */
+TEST(DatabaseBuilderTest, EmptyServiceAddTest) {
+ DatabaseBuilder builder;
+
+ EXPECT_FALSE(builder.InProgress());
+
+ // Simple database, just one empty
+ builder.AddService(0x0001, 0x0001, SERVICE_1_UUID, true);
+ EXPECT_FALSE(builder.StartNextServiceExploration());
+
+ Database result = builder.Build();
+
+ // verify that the returned database matches what was discovered
+ EXPECT_EQ(result.Services()[0].handle, 0x0001);
+ EXPECT_EQ(result.Services()[0].end_handle, 0x0001);
+ EXPECT_EQ(result.Services()[0].is_primary, true);
+ EXPECT_EQ(result.Services()[0].uuid, SERVICE_1_UUID);
+}
+
+/* Verify adding service, characteristic and descriptor work */
+TEST(DatabaseBuilderTest, DescriptorAddTest) {
+ DatabaseBuilder builder;
+
+ EXPECT_FALSE(builder.InProgress());
+
+ // Simple database, just one empty
+ builder.AddService(0x0001, 0x000f, SERVICE_1_UUID, true);
+ builder.AddCharacteristic(0x0002, 0x0003, SERVICE_1_CHAR_1_UUID, 0x02);
+ builder.AddDescriptor(0x0004, SERVICE_1_CHAR_1_DESC_1_UUID);
+
+ Database result = builder.Build();
+
+ // verify that the returned database matches what was discovered
+ EXPECT_EQ(result.Services()[0].handle, 0x0001);
+ EXPECT_EQ(result.Services()[0].end_handle, 0x000f);
+ EXPECT_EQ(result.Services()[0].is_primary, true);
+ EXPECT_EQ(result.Services()[0].uuid, SERVICE_1_UUID);
+
+ EXPECT_EQ(result.Services()[0].characteristics[0].uuid,
+ SERVICE_1_CHAR_1_UUID);
+ EXPECT_EQ(result.Services()[0].characteristics[0].declaration_handle, 0x0002);
+ EXPECT_EQ(result.Services()[0].characteristics[0].value_handle, 0x0003);
+ EXPECT_EQ(result.Services()[0].characteristics[0].properties, 0x02);
+
+ EXPECT_EQ(result.Services()[0].characteristics[0].descriptors[0].uuid,
+ SERVICE_1_CHAR_1_DESC_1_UUID);
+ EXPECT_EQ(result.Services()[0].characteristics[0].descriptors[0].handle,
+ 0x0004);
+}
+
+/* This test verifies that DatabaseBuilder properly handle discovery of
+ * secondary service, that is added to the discovery queue from included service
+ * definition. Such service might come out of order. */
+TEST(DatabaseBuilderTest, SecondaryServiceOutOfOrderTest) {
+ DatabaseBuilder builder;
+
+ EXPECT_FALSE(builder.InProgress());
+
+ // At start of discovery, builder will receive All services in order from
+ // lower layers.
+ builder.AddService(0x0001, 0x000f, SERVICE_1_UUID, true);
+ builder.AddService(0x0030, 0x003f, SERVICE_3_UUID, true);
+ builder.AddService(0x0050, 0x005f, SERVICE_5_UUID, true);
+
+ // First service skipped, no place for handles
+ EXPECT_TRUE(builder.StartNextServiceExploration());
+ EXPECT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x0001, 0x000f));
+
+ // For this test, content of first service is irrevelant
+
+ EXPECT_TRUE(builder.StartNextServiceExploration());
+ // Grabbing first service, to start Included Service and Characteristic
+ // discovery
+ EXPECT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x0030, 0x003f));
+
+ builder.AddIncludedService(0x0031, SERVICE_4_UUID, 0x0040, 0x004f);
+ builder.AddIncludedService(0x0032, SERVICE_2_UUID, 0x0020, 0x002f);
+
+ /* Secondary service exploration */
+ EXPECT_TRUE(builder.StartNextServiceExploration());
+ EXPECT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x0020, 0x002f));
+
+ /* Secondary service exploration */
+ EXPECT_TRUE(builder.StartNextServiceExploration());
+ EXPECT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x0040, 0x004f));
+
+ /* Back to primary service exploration */
+ EXPECT_TRUE(builder.StartNextServiceExploration());
+ EXPECT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x0050, 0x005f));
+
+ Database result = builder.Build();
+
+ // verify that the returned database matches what was discovered
+ EXPECT_EQ(result.Services()[0].handle, 0x0001);
+ EXPECT_EQ(result.Services()[0].is_primary, true);
+ EXPECT_EQ(result.Services()[0].uuid, SERVICE_1_UUID);
+
+ EXPECT_EQ(result.Services()[1].handle, 0x0020);
+ EXPECT_EQ(result.Services()[1].end_handle, 0x002f);
+ EXPECT_EQ(result.Services()[1].uuid, SERVICE_2_UUID);
+ EXPECT_EQ(result.Services()[1].is_primary, false);
+
+ EXPECT_EQ(result.Services()[2].handle, 0x0030);
+ EXPECT_EQ(result.Services()[2].end_handle, 0x003f);
+ EXPECT_EQ(result.Services()[2].uuid, SERVICE_3_UUID);
+ EXPECT_EQ(result.Services()[2].is_primary, true);
+
+ EXPECT_EQ(result.Services()[3].handle, 0x0040);
+ EXPECT_EQ(result.Services()[3].uuid, SERVICE_4_UUID);
+ EXPECT_EQ(result.Services()[3].is_primary, false);
+
+ EXPECT_EQ(result.Services()[4].handle, 0x0050);
+ EXPECT_EQ(result.Services()[4].uuid, SERVICE_5_UUID);
+ EXPECT_EQ(result.Services()[4].is_primary, true);
+}
+
+} // namespace gatt
\ No newline at end of file
diff --git a/bta/test/gatt/database_test.cc b/bta/test/gatt/database_test.cc
new file mode 100644
index 0000000..78250ec
--- /dev/null
+++ b/bta/test/gatt/database_test.cc
@@ -0,0 +1,207 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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 <gtest/gtest.h>
+
+#include <base/logging.h>
+#include <base/strings/string_number_conversions.h>
+#include "gatt/database.h"
+#include "gatt/database_builder.h"
+#include "stack/include/gattdefs.h"
+
+using bluetooth::Uuid;
+
+namespace gatt {
+
+namespace {
+const Uuid PRIMARY_SERVICE = Uuid::From16Bit(GATT_UUID_PRI_SERVICE);
+const Uuid SECONDARY_SERVICE = Uuid::From16Bit(GATT_UUID_SEC_SERVICE);
+const Uuid INCLUDE = Uuid::From16Bit(GATT_UUID_INCLUDE_SERVICE);
+const Uuid CHARACTERISTIC = Uuid::From16Bit(GATT_UUID_CHAR_DECLARE);
+
+Uuid SERVICE_1_UUID = Uuid::FromString("1800");
+Uuid SERVICE_2_UUID = Uuid::FromString("1801");
+Uuid SERVICE_1_CHAR_1_UUID = Uuid::FromString("2a00");
+Uuid SERVICE_1_CHAR_1_DESC_1_UUID = Uuid::FromString("2902");
+} // namespace
+
+/* This test makes sure that each possible GATT cache element is properly
+ * serialized into StoredAttribute */
+TEST(GattDatabaseTest, serialize_deserialize_binary_test) {
+ DatabaseBuilder builder;
+ builder.AddService(0x0001, 0x000f, SERVICE_1_UUID, true);
+ builder.AddService(0x0010, 0x001f, SERVICE_2_UUID, false);
+ builder.AddIncludedService(0x0002, SERVICE_2_UUID, 0x0010, 0x001f);
+ builder.AddCharacteristic(0x0003, 0x0004, SERVICE_1_CHAR_1_UUID, 0x02);
+ builder.AddDescriptor(0x0005, SERVICE_1_CHAR_1_DESC_1_UUID);
+
+ Database db = builder.Build();
+ std::vector<StoredAttribute> serialized = db.Serialize();
+
+ // Primary Service
+ EXPECT_EQ(serialized[0].handle, 0x0001);
+ EXPECT_EQ(serialized[0].type, PRIMARY_SERVICE);
+ EXPECT_EQ(serialized[0].value.service.uuid, SERVICE_1_UUID);
+ EXPECT_EQ(serialized[0].value.service.end_handle, 0x000f);
+
+ // Secondary Service
+ EXPECT_EQ(serialized[1].handle, 0x0010);
+ EXPECT_EQ(serialized[1].type, SECONDARY_SERVICE);
+ EXPECT_EQ(serialized[1].value.service.uuid, SERVICE_2_UUID);
+ EXPECT_EQ(serialized[1].value.service.end_handle, 0x001f);
+
+ // Included Service
+ EXPECT_EQ(serialized[2].handle, 0x0002);
+ EXPECT_EQ(serialized[2].type, INCLUDE);
+ EXPECT_EQ(serialized[2].value.included_service.handle, 0x0010);
+ EXPECT_EQ(serialized[2].value.included_service.end_handle, 0x001f);
+ EXPECT_EQ(serialized[2].value.included_service.uuid, SERVICE_2_UUID);
+
+ // Characteristic
+ EXPECT_EQ(serialized[3].handle, 0x0003);
+ EXPECT_EQ(serialized[3].type, CHARACTERISTIC);
+ EXPECT_EQ(serialized[3].value.characteristic.properties, 0x02);
+ EXPECT_EQ(serialized[3].value.characteristic.value_handle, 0x0004);
+ EXPECT_EQ(serialized[3].value.characteristic.uuid, SERVICE_1_CHAR_1_UUID);
+
+ // Descriptor
+ EXPECT_EQ(serialized[4].handle, 0x0005);
+ EXPECT_EQ(serialized[4].type, SERVICE_1_CHAR_1_DESC_1_UUID);
+}
+
+/* This test makes sure that Service represented in StoredAttribute have proper
+ * binary format. */
+TEST(GattCacheTest, stored_attribute_to_binary_service_test) {
+ StoredAttribute attr;
+
+ /* make sure padding at end of union is cleared */
+ memset(&attr, 0, sizeof(attr));
+
+ attr = {
+ .handle = 0x0001,
+ .type = PRIMARY_SERVICE,
+ .value = {.service = {.uuid = Uuid::FromString("1800"),
+ .end_handle = 0x001c}},
+ };
+
+ constexpr size_t len = sizeof(StoredAttribute);
+ // clang-format off
+ uint8_t binary_form[len] = {
+ /*handle */ 0x01, 0x00,
+ /* type*/ 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB,
+ /* service uuid */ 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB,
+ /* end handle */ 0x1C, 0x00,
+ /* cleared padding at end of union*/ 0x00, 0x00};
+ // clang-format on
+
+ // useful for debugging:
+ // LOG(ERROR) << " " << base::HexEncode(&attr, len);
+ EXPECT_EQ(memcmp(binary_form, &attr, len), 0);
+}
+
+/* This test makes sure that Service represented in StoredAttribute have proper
+ * binary format. */
+TEST(GattCacheTest, stored_attribute_to_binary_included_service_test) {
+ StoredAttribute attr;
+
+ /* make sure padding at end of union is cleared */
+ memset(&attr, 0, sizeof(attr));
+
+ attr = {
+ .handle = 0x0001,
+ .type = INCLUDE,
+ .value = {.included_service =
+ {
+ .handle = 0x0010,
+ .end_handle = 0x001f,
+ .uuid = Uuid::FromString("1801"),
+ }},
+ };
+
+ constexpr size_t len = sizeof(StoredAttribute);
+ // clang-format off
+ uint8_t binary_form[len] = {
+ /*handle */ 0x01, 0x00,
+ /* type*/ 0x00, 0x00, 0x28, 0x02, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB,
+ /* handle */ 0x10, 0x00,
+ /* end handle */ 0x1f, 0x00,
+ /* service uuid */ 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
+ // clang-format on
+
+ // useful for debugging:
+ // LOG(ERROR) << " " << base::HexEncode(&attr, len);
+ EXPECT_EQ(memcmp(binary_form, &attr, len), 0);
+}
+
+/* This test makes sure that Characteristic represented in StoredAttribute have
+ * proper binary format. */
+TEST(GattCacheTest, stored_attribute_to_binary_characteristic_test) {
+ StoredAttribute attr;
+
+ /* make sure padding at end of union is cleared */
+ memset(&attr, 0, sizeof(attr));
+
+ attr = {
+ .handle = 0x0002,
+ .type = CHARACTERISTIC,
+ .value = {.characteristic = {.properties = 0x02,
+ .value_handle = 0x0003,
+ .uuid = Uuid::FromString("2a00")}},
+ };
+
+ constexpr size_t len = sizeof(StoredAttribute);
+ // clang-format off
+ uint8_t binary_form[len] = {
+ /*handle */ 0x02, 0x00,
+ /* type */ 0x00, 0x00, 0x28, 0x03, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB,
+ /* properties */ 0x02,
+ /* after properties there is one byte padding. This might cause troube
+ on other platforms, investigate if it's ever a problem */ 0x00,
+ /* value handle */ 0x03, 0x00,
+ /* uuid */ 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
+ // clang-format on
+
+ // useful for debugging:
+ // LOG(ERROR) << " " << base::HexEncode(&attr, len);
+ EXPECT_EQ(memcmp(binary_form, &attr, len), 0);
+}
+
+/* This test makes sure that Descriptor represented in StoredAttribute have
+ * proper binary format. */
+TEST(GattCacheTest, stored_attribute_to_binary_descriptor_test) {
+ StoredAttribute attr;
+
+ /* make sure padding at end of union is cleared */
+ memset(&attr, 0, sizeof(attr));
+
+ attr = {.handle = 0x0003, .type = Uuid::FromString("2902"), .value = {}};
+
+ constexpr size_t len = sizeof(StoredAttribute);
+ // clang-format off
+ uint8_t binary_form[len] = {
+ /*handle */ 0x03, 0x00,
+ /* type */ 0x00, 0x00, 0x29, 0x02, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB,
+ /* clear padding */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ // clang-format on
+
+ // useful for debugging:
+ // LOG(ERROR) << " " << base::HexEncode(&attr, len);
+ EXPECT_EQ(memcmp(binary_form, &attr, len), 0);
+}
+} // namespace gatt
\ No newline at end of file
diff --git a/bta/test/gatt_cache_file_test.cc b/bta/test/gatt_cache_file_test.cc
deleted file mode 100644
index 3ea8902..0000000
--- a/bta/test/gatt_cache_file_test.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2018 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 <gtest/gtest.h>
-
-#include <base/logging.h>
-#include <base/strings/string_number_conversions.h>
-#include "bta/include/bta_gatt_api.h"
-
-using bluetooth::Uuid;
-
-/* This test makes sure that v3 cache element is properly encoded into file*/
-TEST(GattCacheTest, nv_attr_to_binary_test) {
- tBTA_GATTC_NV_ATTR attr{
- .uuid = Uuid::FromString("1800"),
- .s_handle = 0x0001,
- .e_handle = 0xFFFF,
- .attr_type = 0x01,
- .id = 0x02,
- .prop = 0x03,
- .is_primary = false,
- .incl_srvc_handle = 0x4543,
- };
-
- constexpr size_t len = sizeof(tBTA_GATTC_NV_ATTR);
- uint8_t binary_form[len] = {0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x10,
- 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B,
- 0x34, 0xFB, 0x01, 0x00, 0xFF, 0xFF, 0x01,
- 0x02, 0x03, 0x00, 0x43, 0x45};
-
- // USEFUL for debugging:
- // LOG(ERROR) << " " << base::HexEncode(binary_form, len);
- EXPECT_EQ(memcmp(binary_form, &attr, len), 0);
-}
diff --git a/btcore/AndroidTest.xml b/btcore/AndroidTest.xml
deleted file mode 100644
index 27cd569..0000000
--- a/btcore/AndroidTest.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2017 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.
--->
-<configuration description="Config for net_test_btcore">
- <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
- <option name="cleanup" value="true" />
- <option name="push" value="net_test_btcore->/data/local/tmp/net_test_btcore" />
- </target_preparer>
- <option name="test-suite-tag" value="apct" />
- <test class="com.android.tradefed.testtype.GTest" >
- <option name="native-test-device-path" value="/data/local/tmp" />
- <option name="module-name" value="net_test_btcore" />
- </test>
-</configuration>
\ No newline at end of file
diff --git a/btcore/include/module.h b/btcore/include/module.h
index 949d147..ca1d8b4 100644
--- a/btcore/include/module.h
+++ b/btcore/include/module.h
@@ -20,6 +20,7 @@
#include <stdbool.h>
+#include "common/message_loop_thread.h"
#include "osi/include/future.h"
#include "osi/include/thread.h"
@@ -63,6 +64,6 @@
// has finished, |callback| is called within the context of |callback_thread|
// with |FUTURE_SUCCESS| or |FUTURE_FAIL| depending on whether startup succeeded
// or not.
-void module_start_up_callbacked_wrapper(const module_t* module,
- thread_t* callback_thread,
- thread_fn callback);
+void module_start_up_callbacked_wrapper(
+ const module_t* module,
+ bluetooth::common::MessageLoopThread* callback_thread, thread_fn callback);
diff --git a/btcore/src/module.cc b/btcore/src/module.cc
index 88d4f80..d226006 100644
--- a/btcore/src/module.cc
+++ b/btcore/src/module.cc
@@ -26,10 +26,13 @@
#include <unordered_map>
#include "btcore/include/module.h"
+#include "common/message_loop_thread.h"
#include "osi/include/allocator.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
+using bluetooth::common::MessageLoopThread;
+
typedef enum {
MODULE_STATE_NONE = 0,
MODULE_STATE_INITIALIZED = 1,
@@ -159,55 +162,45 @@
// TODO(zachoverflow): remove when everything modulized
// Temporary callback-wrapper-related code
-
-typedef struct {
+class CallbackWrapper {
+ public:
+ explicit CallbackWrapper(const module_t* module,
+ MessageLoopThread* callback_thread,
+ thread_fn callback)
+ : module(module),
+ lifecycle_thread("bt_module_lifecycle_thread"),
+ callback_thread(callback_thread),
+ callback(callback),
+ success(false) {}
const module_t* module;
- thread_t* lifecycle_thread;
- thread_t* callback_thread; // we don't own this thread
+ MessageLoopThread lifecycle_thread;
+ // we don't own this thread
+ MessageLoopThread* callback_thread;
thread_fn callback;
bool success;
-} callbacked_wrapper_t;
+};
-static void run_wrapped_start_up(void* context);
-static void post_result_to_callback(void* context);
+static void post_result_to_callback(std::shared_ptr<CallbackWrapper> wrapper) {
+ CHECK(wrapper);
+ wrapper->lifecycle_thread.ShutDown();
+ wrapper->callback(wrapper->success ? FUTURE_SUCCESS : FUTURE_FAIL);
+}
+
+static void run_wrapped_start_up(std::shared_ptr<CallbackWrapper> wrapper) {
+ CHECK(wrapper);
+ wrapper->success = module_start_up(wrapper->module);
+ // Post the result back to the callback
+ wrapper->callback_thread->DoInThread(
+ FROM_HERE, base::BindOnce(post_result_to_callback, wrapper));
+}
void module_start_up_callbacked_wrapper(const module_t* module,
- thread_t* callback_thread,
+ MessageLoopThread* callback_thread,
thread_fn callback) {
- callbacked_wrapper_t* wrapper =
- (callbacked_wrapper_t*)osi_calloc(sizeof(callbacked_wrapper_t));
-
- wrapper->module = module;
- wrapper->lifecycle_thread = thread_new("module_wrapper");
- wrapper->callback_thread = callback_thread;
- wrapper->callback = callback;
-
+ std::shared_ptr<CallbackWrapper> wrapper =
+ std::make_shared<CallbackWrapper>(module, callback_thread, callback);
+ wrapper->lifecycle_thread.StartUp();
// Run the actual module start up
- thread_post(wrapper->lifecycle_thread, run_wrapped_start_up, wrapper);
-}
-
-static void run_wrapped_start_up(void* context) {
- CHECK(context);
-
- callbacked_wrapper_t* wrapper = (callbacked_wrapper_t*)context;
- wrapper->success = module_start_up(wrapper->module);
-
- // Post the result back to the callback
- thread_post(wrapper->callback_thread, post_result_to_callback, wrapper);
-}
-
-static void post_result_to_callback(void* context) {
- CHECK(context);
-
- callbacked_wrapper_t* wrapper = (callbacked_wrapper_t*)context;
-
- // Save the values we need for callback
- void* result = wrapper->success ? FUTURE_SUCCESS : FUTURE_FAIL;
- thread_fn callback = wrapper->callback;
-
- // Clean up the resources we used
- thread_free(wrapper->lifecycle_thread);
- osi_free(wrapper);
-
- callback(result);
+ wrapper->lifecycle_thread.DoInThread(
+ FROM_HERE, base::BindOnce(run_wrapped_start_up, wrapper));
}
diff --git a/btif/Android.bp b/btif/Android.bp
index 0bbc241..1f781c9 100644
--- a/btif/Android.bp
+++ b/btif/Android.bp
@@ -39,7 +39,6 @@
"co/bta_dm_co.cc",
"co/bta_av_co.cc",
"co/bta_hh_co.cc",
- "co/bta_hl_co.cc",
"co/bta_pan_co.cc",
"co/bta_gatts_co.cc",
// HAL layer
@@ -54,6 +53,7 @@
"src/btif_avrcp_audio_track.cc",
"src/btif_ble_advertiser.cc",
"src/btif_ble_scanner.cc",
+ "src/btif_bqr.cc",
"src/btif_config.cc",
"src/btif_config_transcode.cc",
"src/btif_core.cc",
@@ -71,7 +71,6 @@
"src/btif_hf_client.cc",
"src/btif_hh.cc",
"src/btif_hd.cc",
- "src/btif_hl.cc",
"src/btif_mce.cc",
"src/btif_pan.cc",
"src/btif_profile_queue.cc",
@@ -93,21 +92,28 @@
shared_libs: [
"libaudioclient",
"libcutils",
+ "libfmq",
"liblog",
"libz",
"libtinyxml2",
"android.hardware.bluetooth.a2dp@1.0",
+ "android.hardware.bluetooth.audio@2.0",
"libhidlbase",
"libhidltransport",
"libhwbinder",
"libutils",
+ "libcrypto",
],
whole_static_libs: [
"avrcp-target-service",
"libaudio-a2dp-hw-utils",
"lib-bt-packets",
+ "libbt-audio-hal-interface",
],
- cflags: ["-DBUILDCFG"],
+ cflags: [
+ "-DBUILDCFG",
+ "-Wno-implicit-fallthrough",
+ ],
}
@@ -116,23 +122,30 @@
cc_test {
name: "net_test_btif",
defaults: ["fluoride_defaults"],
+ test_suites: ["device-tests"],
include_dirs: btifCommonIncludes,
srcs: ["test/btif_storage_test.cc"],
header_libs: ["libbluetooth_headers"],
shared_libs: [
"libaudioclient",
"android.hardware.bluetooth.a2dp@1.0",
+ "android.hardware.bluetooth.audio@2.0",
+ "libfmq",
"libhidlbase",
+ "libhidltransport",
"liblog",
"libprotobuf-cpp-lite",
"libcutils",
+ "libprocessgroup",
"libutils",
- "libstatslog",
+ "libcrypto",
],
static_libs: [
"libbt-bta",
"libbtcore",
+ "libbt-common",
"libbt-stack",
+ "libbt-sbc-decoder",
"libbt-sbc-encoder",
"libbt-utils",
"libFraunhoferAAC",
@@ -156,32 +169,11 @@
cc_test {
name: "net_test_btif_profile_queue",
defaults: ["fluoride_defaults"],
+ test_suites: ["device-tests"],
include_dirs: btifCommonIncludes,
srcs: [
- "src/btif_profile_queue.cc",
- "test/btif_profile_queue_test.cc"
- ],
- header_libs: ["libbluetooth_headers"],
- shared_libs: [
- "liblog",
- "libcutils",
- ],
- static_libs: [
- "libbluetooth-types",
- "libosi",
- ],
- cflags: ["-DBUILDCFG"],
-}
-
-// btif state machine unit tests for target
-// ========================================================
-cc_test {
- name: "net_test_btif_state_machine",
- defaults: ["fluoride_defaults"],
- include_dirs: btifCommonIncludes,
- host_supported: true,
- srcs: [
- "test/btif_state_machine_test.cc"
+ "src/btif_profile_queue.cc",
+ "test/btif_profile_queue_test.cc",
],
header_libs: ["libbluetooth_headers"],
shared_libs: [
diff --git a/btif/BUILD.gn b/btif/BUILD.gn
index de50a97..5e78d7d 100644
--- a/btif/BUILD.gn
+++ b/btif/BUILD.gn
@@ -17,14 +17,18 @@
static_library("btif") {
sources = [
"//audio_a2dp_hw/src/audio_a2dp_hw_utils.cc",
+ "//audio_hearing_aid_hw/src/audio_hearing_aid_hw_utils.cc",
"src/btif_a2dp.cc",
+ "src/btif_a2dp_audio_interface_linux.cc",
"src/btif_a2dp_control.cc",
"src/btif_a2dp_sink.cc",
"src/btif_a2dp_source.cc",
"src/btif_av.cc",
+ "avrcp/avrcp_service.cc",
#TODO(jpawlowski): heavily depends on Android,
# "src/btif_avrcp_audio_track.cc",
+ "src/btif_avrcp_audio_track_linux.cc",
"src/btif_ble_advertiser.cc",
"src/btif_ble_scanner.cc",
"src/btif_config.cc",
@@ -44,7 +48,6 @@
"src/btif_hf_client.cc",
"src/btif_hh.cc",
"src/btif_hd.cc",
- "src/btif_hl.cc",
"src/btif_mce.cc",
"src/btif_pan.cc",
"src/btif_profile_queue.cc",
@@ -66,11 +69,9 @@
# BTIF callouts
sources += [
- "co/bta_ag_co.cc",
"co/bta_dm_co.cc",
"co/bta_av_co.cc",
"co/bta_hh_co.cc",
- "co/bta_hl_co.cc",
"co/bta_pan_co.cc",
"co/bta_gatts_co.cc",
]
@@ -78,7 +79,9 @@
include_dirs = [
"include",
"//",
+ "//linux_include",
"//audio_a2dp_hw/include",
+ "//audio_hearing_aid_hw/include",
"//bta/include",
"//bta/sys",
"//btcore/include",
@@ -88,15 +91,19 @@
"//hci/include",
"//stack/a2dp",
"//stack/btm",
+ "//stack/l2cap",
"//stack/include",
"//third_party/tinyxml2",
"//internal_include",
"//udrv/include",
"//utils/include",
"//vnd/include",
+ "//profile/avrcp",
]
deps = [
- "//third_party/libchrome:base"
+ "//common",
+ "//third_party/libchrome:base",
+ "//profile/avrcp:profile_avrcp"
]
}
diff --git a/btif/avrcp/avrcp_service.cc b/btif/avrcp/avrcp_service.cc
index 5a058f4..1308461 100644
--- a/btif/avrcp/avrcp_service.cc
+++ b/btif/avrcp/avrcp_service.cc
@@ -23,10 +23,10 @@
#include <mutex>
#include <sstream>
-#include "bta_closure_api.h"
#include "btif_av.h"
#include "btif_common.h"
#include "device.h"
+#include "stack/include/btu.h"
namespace bluetooth {
namespace avrcp {
@@ -52,6 +52,10 @@
class A2dpInterfaceImpl : public A2dpInterface {
RawAddress active_peer() override { return btif_av_source_active_peer(); }
+
+ bool is_peer_in_silence_mode(const RawAddress& peer_address) override {
+ return btif_av_is_peer_silenced(peer_address);
+ }
} a2dp_interface_;
class AvrcpInterfaceImpl : public AvrcpInterface {
@@ -141,7 +145,7 @@
void GetSongInfo(SongInfoCallback info_cb) override {
auto cb_lambda = [](SongInfoCallback cb, SongInfo data) {
- do_in_bta_thread(FROM_HERE, base::Bind(cb, data));
+ do_in_main_thread(FROM_HERE, base::Bind(cb, data));
};
auto bound_cb = base::Bind(cb_lambda, info_cb);
@@ -152,7 +156,7 @@
void GetPlayStatus(PlayStatusCallback status_cb) override {
auto cb_lambda = [](PlayStatusCallback cb, PlayStatus status) {
- do_in_bta_thread(FROM_HERE, base::Bind(cb, status));
+ do_in_main_thread(FROM_HERE, base::Bind(cb, status));
};
auto bound_cb = base::Bind(cb_lambda, status_cb);
@@ -164,8 +168,8 @@
void GetNowPlayingList(NowPlayingCallback now_playing_cb) override {
auto cb_lambda = [](NowPlayingCallback cb, std::string curr_media_id,
std::vector<SongInfo> song_list) {
- do_in_bta_thread(FROM_HERE,
- base::Bind(cb, curr_media_id, std::move(song_list)));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(cb, curr_media_id, std::move(song_list)));
};
auto bound_cb = base::Bind(cb_lambda, now_playing_cb);
@@ -177,8 +181,8 @@
void GetMediaPlayerList(MediaListCallback list_cb) override {
auto cb_lambda = [](MediaListCallback cb, uint16_t curr_player,
std::vector<MediaPlayerInfo> player_list) {
- do_in_bta_thread(FROM_HERE,
- base::Bind(cb, curr_player, std::move(player_list)));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(cb, curr_player, std::move(player_list)));
};
auto bound_cb = base::Bind(cb_lambda, list_cb);
@@ -191,7 +195,7 @@
FolderItemsCallback folder_cb) override {
auto cb_lambda = [](FolderItemsCallback cb,
std::vector<ListItem> item_list) {
- do_in_bta_thread(FROM_HERE, base::Bind(cb, std::move(item_list)));
+ do_in_main_thread(FROM_HERE, base::Bind(cb, std::move(item_list)));
};
auto bound_cb = base::Bind(cb_lambda, folder_cb);
@@ -205,7 +209,7 @@
SetBrowsedPlayerCallback browse_cb) override {
auto cb_lambda = [](SetBrowsedPlayerCallback cb, bool success,
std::string root_id, uint32_t num_items) {
- do_in_bta_thread(FROM_HERE, base::Bind(cb, success, root_id, num_items));
+ do_in_main_thread(FROM_HERE, base::Bind(cb, success, root_id, num_items));
};
auto bound_cb = base::Bind(cb_lambda, browse_cb);
@@ -254,7 +258,7 @@
void DeviceConnected(const RawAddress& bdaddr, VolumeChangedCb cb) override {
auto cb_lambda = [](VolumeChangedCb cb, int8_t volume) {
- do_in_bta_thread(FROM_HERE, base::Bind(cb, volume));
+ do_in_main_thread(FROM_HERE, base::Bind(cb, volume));
};
auto bound_cb = base::Bind(cb_lambda, cb);
@@ -348,9 +352,8 @@
// device update happens on the main thread.
for (const auto& device :
instance_->connection_handler_->GetListOfDevices()) {
- do_in_bta_thread(FROM_HERE,
- base::Bind(&Device::SendMediaUpdate, device.get()->Get(),
- track_changed, play_state, queue));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(&Device::SendMediaUpdate, device.get()->Get(), track_changed, play_state, queue));
}
}
@@ -364,9 +367,8 @@
// Ensure that the update is posted to the correct thread
for (const auto& device :
instance_->connection_handler_->GetListOfDevices()) {
- do_in_bta_thread(FROM_HERE,
- base::Bind(&Device::SendFolderUpdate, device.get()->Get(),
- available_players, addressed_players, uids));
+ do_in_main_thread(FROM_HERE, base::Bind(&Device::SendFolderUpdate, device.get()->Get(), available_players,
+ addressed_players, uids));
}
}
@@ -401,17 +403,17 @@
jni_message_loop_ = get_jni_message_loop();
}
- do_in_bta_thread(FROM_HERE,
- base::Bind(&AvrcpService::Init, base::Unretained(instance_),
- media_interface, volume_interface));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(&AvrcpService::Init, base::Unretained(instance_),
+ media_interface, volume_interface));
}
bool AvrcpService::ServiceInterfaceImpl::ConnectDevice(
const RawAddress& bdaddr) {
std::lock_guard<std::mutex> lock(service_interface_lock_);
CHECK(instance_ != nullptr);
- do_in_bta_thread(FROM_HERE, base::Bind(&AvrcpService::ConnectDevice,
- base::Unretained(instance_), bdaddr));
+ do_in_main_thread(FROM_HERE, base::Bind(&AvrcpService::ConnectDevice,
+ base::Unretained(instance_), bdaddr));
return true;
}
@@ -419,8 +421,8 @@
const RawAddress& bdaddr) {
std::lock_guard<std::mutex> lock(service_interface_lock_);
CHECK(instance_ != nullptr);
- do_in_bta_thread(FROM_HERE, base::Bind(&AvrcpService::DisconnectDevice,
- base::Unretained(instance_), bdaddr));
+ do_in_main_thread(FROM_HERE, base::Bind(&AvrcpService::DisconnectDevice,
+ base::Unretained(instance_), bdaddr));
return true;
}
@@ -435,8 +437,8 @@
jni_message_loop_ = nullptr;
}
- do_in_bta_thread(FROM_HERE,
- base::Bind(&AvrcpService::Cleanup, base::Owned(instance_)));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(&AvrcpService::Cleanup, base::Owned(instance_)));
// Setting instance to nullptr here is fine since it will be deleted on the
// other thread.
@@ -456,11 +458,15 @@
device_list.size());
std::stringstream stream;
- for (auto device : device_list) {
- stream << *device << std::endl;
+ {
+ ScopedIndent indent(stream);
+ for (const auto& device : device_list) {
+ stream << *device << std::endl;
+ }
}
+
dprintf(fd, "%s", stream.str().c_str());
}
} // namespace avrcp
-} // namespace bluetooth
\ No newline at end of file
+} // namespace bluetooth
diff --git a/btif/avrcp/avrcp_service.h b/btif/avrcp/avrcp_service.h
index d26b200..e19899d 100644
--- a/btif/avrcp/avrcp_service.h
+++ b/btif/avrcp/avrcp_service.h
@@ -19,9 +19,9 @@
#include <map>
#include <memory>
-#include "avrcp.h"
-#include "connection_handler.h"
+#include "hardware/avrcp/avrcp.h"
#include "osi/include/properties.h"
+#include "profile/avrcp/connection_handler.h"
#include "raw_address.h"
namespace bluetooth {
diff --git a/btif/co/bta_av_co.cc b/btif/co/bta_av_co.cc
index 6147744..9f17d4a 100644
--- a/btif/co/bta_av_co.cc
+++ b/btif/co/bta_av_co.cc
@@ -179,6 +179,14 @@
void Init(const std::vector<btav_a2dp_codec_config_t>& codec_priorities);
/**
+ * Checks whether a codec is supported.
+ *
+ * @param codec_index the index of the codec to check
+ * @return true if the codec is supported, otherwise false
+ */
+ bool IsSupportedCodec(btav_a2dp_codec_index_t codec_index);
+
+ /**
* Get the current codec configuration for the active peer.
*
* @return the current codec configuration if found, otherwise nullptr
@@ -769,6 +777,14 @@
}
}
+bool BtaAvCo::IsSupportedCodec(btav_a2dp_codec_index_t codec_index) {
+ // All peer state is initialized with the same local codec config,
+ // hence we check only the first peer.
+ A2dpCodecs* codecs = peers_[0].GetCodecs();
+ CHECK(codecs != nullptr);
+ return codecs->isSupportedCodec(codec_index);
+}
+
A2dpCodecConfig* BtaAvCo::GetActivePeerCurrentCodec() {
std::lock_guard<std::recursive_mutex> lock(codec_lock_);
@@ -1626,16 +1642,32 @@
// Nothing to do (for now)
return true;
}
+
void BtaAvCo::DebugDump(int fd) {
std::lock_guard<std::recursive_mutex> lock(codec_lock_);
- dprintf(fd, "\nA2DP Codecs and Peers State:\n");
+ //
+ // Active peer codec-specific stats
+ //
+ if (active_peer_ != nullptr) {
+ A2dpCodecs* a2dp_codecs = active_peer_->GetCodecs();
+ if (a2dp_codecs != nullptr) {
+ a2dp_codecs->debug_codec_dump(fd);
+ }
+ }
+
+ if (appl_trace_level < BT_TRACE_LEVEL_DEBUG) return;
+
+ dprintf(fd, "\nA2DP Peers State:\n");
dprintf(fd, " Active peer: %s\n",
(active_peer_ != nullptr) ? active_peer_->addr.ToString().c_str()
: "null");
for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peers_); i++) {
const BtaAvCoPeer& peer = peers_[i];
+ if (peer.addr.IsEmpty()) {
+ continue;
+ }
dprintf(fd, " Peer: %s\n", peer.addr.ToString().c_str());
dprintf(fd, " Number of sinks: %u\n", peer.num_sinks);
dprintf(fd, " Number of sources: %u\n", peer.num_sources);
@@ -1652,16 +1684,6 @@
dprintf(fd, " UUID to connect: 0x%x\n", peer.uuid_to_connect);
dprintf(fd, " BTA AV handle: %u\n", peer.BtaAvHandle());
}
-
- //
- // Active peer codec-specific stats
- //
- if (active_peer_ != nullptr) {
- A2dpCodecs* a2dp_codecs = active_peer_->GetCodecs();
- if (a2dp_codecs != nullptr) {
- a2dp_codecs->debug_codec_dump(fd);
- }
- }
}
bool BtaAvCo::ContentProtectIsScmst(const uint8_t* p_protect_info) {
@@ -2020,6 +2042,10 @@
bta_av_co_cb.Init(codec_priorities);
}
+bool bta_av_co_is_supported_codec(btav_a2dp_codec_index_t codec_index) {
+ return bta_av_co_cb.IsSupportedCodec(codec_index);
+}
+
A2dpCodecConfig* bta_av_get_a2dp_current_codec(void) {
return bta_av_co_cb.GetActivePeerCurrentCodec();
}
diff --git a/btif/co/bta_dm_co.cc b/btif/co/bta_dm_co.cc
index dfd512b..200ce55 100644
--- a/btif/co/bta_dm_co.cc
+++ b/btif/co/bta_dm_co.cc
@@ -25,12 +25,17 @@
#include "bta_sys.h"
#include "bte_appl.h"
#include "btif_dm.h"
+#include "btif_storage.h"
#include "osi/include/osi.h"
+// tBTE_APPL_CFG.ble_io_cap is set to BTM_IO_CAP_UNKNOWN at structure
+// initialization since btif_storage isn't ready yet for data to be fetched.
+// This value is initialized properly during first use by fetching properly
+// from btif_storage.
tBTE_APPL_CFG bte_appl_cfg = {
BTA_LE_AUTH_REQ_SC_MITM_BOND, // Authentication requirements
- BTM_LOCAL_IO_CAPS_BLE, BTM_BLE_INITIATOR_KEY_SIZE,
- BTM_BLE_RESPONDER_KEY_SIZE, BTM_BLE_MAX_KEY_SIZE};
+ BTM_IO_CAP_UNKNOWN, BTM_BLE_INITIATOR_KEY_SIZE, BTM_BLE_RESPONDER_KEY_SIZE,
+ BTM_BLE_MAX_KEY_SIZE};
/*******************************************************************************
*
@@ -132,7 +137,7 @@
* Returns void.
*
******************************************************************************/
-void bta_dm_co_loc_oob(bool valid, BT_OCTET16 c, BT_OCTET16 r) {
+void bta_dm_co_loc_oob(bool valid, const Octet16& c, const Octet16& r) {
BTIF_TRACE_DEBUG("bta_dm_co_loc_oob, valid = %d", valid);
#ifdef BTIF_DM_OOB_TEST
btif_dm_proc_loc_oob(valid, c, r);
@@ -153,16 +158,16 @@
*
******************************************************************************/
void bta_dm_co_rmt_oob(const RawAddress& bd_addr) {
- BT_OCTET16 p_c;
- BT_OCTET16 p_r;
+ Octet16 c;
+ Octet16 r;
bool result = false;
#ifdef BTIF_DM_OOB_TEST
- result = btif_dm_proc_rmt_oob(bd_addr, p_c, p_r);
+ result = btif_dm_proc_rmt_oob(bd_addr, &c, &r);
#endif
BTIF_TRACE_DEBUG("bta_dm_co_rmt_oob: result=%d", result);
- bta_dm_ci_rmt_oob(result, bd_addr, p_c, p_r);
+ bta_dm_ci_rmt_oob(result, bd_addr, c, r);
}
/*******************************************************************************
@@ -207,13 +212,13 @@
*
******************************************************************************/
void bta_dm_co_ble_load_local_keys(tBTA_DM_BLE_LOCAL_KEY_MASK* p_key_mask,
- BT_OCTET16 er,
+ Octet16* p_er,
tBTA_BLE_LOCAL_ID_KEYS* p_id_keys) {
BTIF_TRACE_DEBUG("##################################");
BTIF_TRACE_DEBUG(
"bta_dm_co_ble_load_local_keys: Load local keys if any are persisted");
BTIF_TRACE_DEBUG("##################################");
- btif_dm_get_ble_local_keys(p_key_mask, er, p_id_keys);
+ btif_dm_get_ble_local_keys(p_key_mask, p_er, p_id_keys);
}
/*******************************************************************************
@@ -241,6 +246,8 @@
tBTA_LE_AUTH_REQ* p_auth_req, uint8_t* p_max_key_size,
tBTA_LE_KEY_TYPE* p_init_key,
tBTA_LE_KEY_TYPE* p_resp_key) {
+ bte_appl_cfg.ble_io_cap = btif_storage_get_local_io_caps_ble();
+
/* Retrieve the properties from file system if possible */
tBTE_APPL_CFG nv_config;
if (btif_dm_get_smp_config(&nv_config)) bte_appl_cfg = nv_config;
diff --git a/btif/co/bta_hh_co.cc b/btif/co/bta_hh_co.cc
index 2f507f9..5a7cad8 100644
--- a/btif/co/bta_hh_co.cc
+++ b/btif/co/bta_hh_co.cc
@@ -42,6 +42,9 @@
#define BTA_HH_NV_LOAD_MAX 16
static tBTA_HH_RPT_CACHE_ENTRY sReportCache[BTA_HH_NV_LOAD_MAX];
#endif
+#define GET_RPT_RSP_OFFSET 9
+#define THREAD_NORMAL_PRIORITY 0
+#define BT_HH_THREAD "bt_hh_thread"
void uhid_set_non_blocking(int fd) {
int opts = fcntl(fd, F_GETFL);
@@ -128,8 +131,8 @@
btif_hh_setreport(p_dev, BTHH_OUTPUT_REPORT, ev.u.output.size,
ev.u.output.data);
else
- btif_hh_setreport(p_dev, BTHH_INPUT_REPORT, ev.u.output.size,
- ev.u.output.data);
+ APPL_TRACE_ERROR("%s: UHID_OUTPUT: Invalid report type = %d", __func__,
+ ev.u.output.rtype);
break;
case UHID_OUTPUT_EV:
if (ret < (ssize_t)(sizeof(ev.type) + sizeof(ev.u.output_ev))) {
@@ -141,10 +144,24 @@
APPL_TRACE_DEBUG("UHID_OUTPUT_EV from uhid-dev\n");
break;
case UHID_FEATURE:
- APPL_TRACE_DEBUG("UHID_FEATURE from uhid-dev\n");
- break;
- case UHID_FEATURE_ANSWER:
- APPL_TRACE_DEBUG("UHID_FEATURE_ANSWER from uhid-dev\n");
+ if (ret < (ssize_t)(sizeof(ev.type) + sizeof(ev.u.feature))) {
+ APPL_TRACE_ERROR(
+ "%s: UHID_FEATURE: Invalid size read from uhid-dev: %zd < %zu",
+ __func__, ret, sizeof(ev.type) + sizeof(ev.u.feature));
+ return -EFAULT;
+ }
+ APPL_TRACE_DEBUG("UHID_FEATURE: Report type = %d", ev.u.feature.rtype);
+ p_dev->get_rpt_snt++;
+ if (p_dev->get_rpt_id_queue) {
+ uint32_t* get_rpt_id = (uint32_t*)osi_malloc(sizeof(uint32_t));
+ *get_rpt_id = ev.u.feature.id;
+ fixed_queue_enqueue(p_dev->get_rpt_id_queue, (void*)get_rpt_id);
+ }
+ if (ev.u.feature.rtype == UHID_FEATURE_REPORT)
+ btif_hh_getreport(p_dev, BTHH_FEATURE_REPORT, ev.u.feature.rnum, 0);
+ else
+ APPL_TRACE_ERROR("%s: UHID_FEATURE: Invalid report type = %d", __func__,
+ ev.u.feature.rtype);
break;
default:
@@ -193,6 +210,17 @@
APPL_TRACE_DEBUG("%s: Thread created fd = %d", __func__, p_dev->fd);
struct pollfd pfds[1];
+ // This thread is created by bt_main_thread with RT priority. Lower the thread
+ // priority here since the tasks in this thread is not timing critical.
+ struct sched_param sched_params;
+ sched_params.sched_priority = THREAD_NORMAL_PRIORITY;
+ if (sched_setscheduler(gettid(), SCHED_OTHER, &sched_params)) {
+ APPL_TRACE_ERROR("%s: Failed to set thread priority to normal", __func__);
+ p_dev->hh_poll_thread_id = -1;
+ return 0;
+ }
+ pthread_setname_np(pthread_self(), BT_HH_THREAD);
+
pfds[0].fd = p_dev->fd;
pfds[0].events = POLLIN;
@@ -278,16 +306,10 @@
p_dev->dev_handle == dev_handle) {
// We found a device with the same handle. Must be a device reconnected.
APPL_TRACE_WARNING(
- "%s: Found an existing device with the same handle "
- "dev_status = %d",
- __func__, p_dev->dev_status);
- APPL_TRACE_WARNING("%s: bd_addr = [%02X:%02X:%02X:%02X:%02X:]",
- __func__, p_dev->bd_addr.address[0],
- p_dev->bd_addr.address[1], p_dev->bd_addr.address[2],
- p_dev->bd_addr.address[3], p_dev->bd_addr.address[4]);
- APPL_TRACE_WARNING(
- "%s: attr_mask = 0x%04x, sub_class = 0x%02x, app_id = %d",
- __func__, p_dev->attr_mask, p_dev->sub_class, p_dev->app_id);
+ "%s: Found an existing device with the same handle dev_status=%d, "
+ "address=%s, attr_mask=0x%04x, sub_class=0x%02x, app_id=%d",
+ __func__, p_dev->dev_status, p_dev->bd_addr.ToString().c_str(),
+ p_dev->attr_mask, p_dev->sub_class, p_dev->app_id);
if (p_dev->fd < 0) {
p_dev->fd = open(dev_path, O_RDWR | O_CLOEXEC);
@@ -343,6 +365,9 @@
}
p_dev->dev_status = BTHH_CONN_STATE_CONNECTED;
+ p_dev->get_rpt_id_queue = fixed_queue_new(SIZE_MAX);
+ CHECK(p_dev->get_rpt_id_queue);
+
APPL_TRACE_DEBUG("%s: Return device status %d", __func__, p_dev->dev_status);
}
@@ -372,6 +397,9 @@
for (i = 0; i < BTIF_HH_MAX_HID; i++) {
p_dev = &btif_hh_cb.devices[i];
+ fixed_queue_flush(p_dev->get_rpt_id_queue, osi_free);
+ fixed_queue_free(p_dev->get_rpt_id_queue, NULL);
+ p_dev->get_rpt_id_queue = NULL;
if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN &&
p_dev->dev_handle == dev_handle) {
APPL_TRACE_WARNING(
@@ -499,6 +527,71 @@
}
}
+/*******************************************************************************
+ *
+ * Function bta_hh_co_set_rpt_rsp
+ *
+ * Description This callout function is executed by HH when Set Report
+ * Response is received on Control Channel.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void bta_hh_co_set_rpt_rsp(uint8_t dev_handle, uint8_t status) {
+ APPL_TRACE_ERROR("%s: Error: UHID_SET_REPORT_REPLY not supported", __func__);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_co_get_rpt_rsp
+ *
+ * Description This callout function is executed by HH when Get Report
+ * Response is received on Control Channel.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void bta_hh_co_get_rpt_rsp(uint8_t dev_handle, uint8_t status, uint8_t* p_rpt,
+ uint16_t len) {
+ struct uhid_event ev;
+ btif_hh_device_t* p_dev;
+
+ APPL_TRACE_VERBOSE("%s: dev_handle = %d", __func__, dev_handle);
+
+ p_dev = btif_hh_find_connected_dev_by_handle(dev_handle);
+ if (p_dev == NULL) {
+ APPL_TRACE_WARNING("%s: Error: unknown HID device handle %d", __func__,
+ dev_handle);
+ return;
+ }
+
+ if (!p_dev->get_rpt_id_queue) {
+ APPL_TRACE_WARNING("%s: Error: missing UHID_GET_REPORT id queue", __func__);
+ return;
+ }
+
+ // Send the HID report to the kernel.
+ if (p_dev->fd >= 0 && p_dev->get_rpt_snt--) {
+ uint32_t* get_rpt_id =
+ (uint32_t*)fixed_queue_dequeue(p_dev->get_rpt_id_queue);
+ memset(&ev, 0, sizeof(ev));
+ ev.type = UHID_FEATURE_ANSWER;
+ ev.u.feature_answer.id = *get_rpt_id;
+ ev.u.feature_answer.err = status;
+ ev.u.feature_answer.size = len;
+ osi_free(get_rpt_id);
+ if (len > 0) {
+ if (len > UHID_DATA_MAX) {
+ APPL_TRACE_WARNING("%s: Report size greater than allowed size",
+ __func__);
+ return;
+ }
+ memcpy(ev.u.feature_answer.data, p_rpt + GET_RPT_RSP_OFFSET, len);
+ uhid_write(p_dev->fd, &ev);
+ }
+ }
+}
+
#if (BTA_HH_LE_INCLUDED == TRUE)
/*******************************************************************************
*
diff --git a/btif/co/bta_hl_co.cc b/btif/co/bta_hl_co.cc
deleted file mode 100644
index c818351..0000000
--- a/btif/co/bta_hl_co.cc
+++ /dev/null
@@ -1,415 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2009-2012 Broadcom 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.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- * This is the implementation file for the HeaLth device profile (HL)
- * subsystem call-out functions.
- *
- ******************************************************************************/
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <time.h>
-
-#include "bta_api.h"
-#include "bta_hl_api.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"
-#include "osi/include/osi.h"
-
-/*****************************************************************************
- * Constants and Data Types
- ****************************************************************************/
-/**************************
- * Common Definitions
- **************************/
-
-/*******************************************************************************
- *
- * Function bta_hl_co_get_num_of_mdep
- *
- * Description This function is called to get the number of MDEPs for this
- * application ID
- *
- * Parameters app_id - application ID
- * p_num_of_mdep (output) - number of MDEP configurations
- * supported by the application
- *
- * Returns true on success
- *
- ******************************************************************************/
-bool bta_hl_co_get_num_of_mdep(uint8_t app_id, uint8_t* p_num_of_mdep) {
- uint8_t app_idx;
- bool success = false;
-
- if (btif_hl_find_app_idx(app_id, &app_idx)) {
- *p_num_of_mdep = p_btif_hl_cb->acb[app_idx].sup_feature.num_of_mdeps;
- success = true;
- }
-
- BTIF_TRACE_DEBUG("%s success=%d num_mdeps=%d", __func__, success,
- *p_num_of_mdep);
- return success;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_co_advrtise_source_sdp
- *
- * Description This function is called to find out whether the SOURCE MDEP
- * configuration information should be advertise in the SDP or
- * not.
- *
- * Parameters app_id - application ID
- *
- * Returns true when advertise the SOURCE MDEP configuration
- * information
- *
- ******************************************************************************/
-bool bta_hl_co_advrtise_source_sdp(uint8_t app_id) {
- bool advertize_source_sdp = false;
- uint8_t app_idx;
-
- if (btif_hl_find_app_idx(app_id, &app_idx)) {
- advertize_source_sdp =
- p_btif_hl_cb->acb[app_idx].sup_feature.advertize_source_sdp;
- }
-
- BTIF_TRACE_DEBUG("%s advertize_flag=%d", __func__, advertize_source_sdp);
-
- return advertize_source_sdp;
-}
-/*******************************************************************************
- *
- * Function bta_hl_co_get_mdep_config
- *
- * Description This function is called to get the supported feature
- * configuration for the specified mdep index and it also
- * assigns the MDEP ID for the specified mdep index
- *
- * Parameters app_id - HDP application ID
- * mdep_idx - the mdep index
- * mdep_counter - number of mdeps
- * mdep_id - the assigned MDEP ID for the specified medp_idx
- * p_mdl_cfg (output) - pointer to the MDEP configuration
- *
- *
- * Returns Bloolean - true success
- ******************************************************************************/
-bool bta_hl_co_get_mdep_config(uint8_t app_id, uint8_t mdep_idx,
- uint8_t mdep_counter, tBTA_HL_MDEP_ID mdep_id,
- tBTA_HL_MDEP_CFG* p_mdep_cfg) {
- uint8_t idx;
- uint8_t app_idx;
- bool success = false;
-
- BTIF_TRACE_DEBUG("%s app_id=%d mdep_idx=%d mdep_id=%d mdep_counter=%d",
- __func__, app_id, mdep_idx, mdep_id, mdep_counter);
-
- if (btif_hl_find_app_idx(app_id, &app_idx)) {
- idx = mdep_idx - mdep_counter - 1;
- p_btif_hl_cb->acb[app_idx].sup_feature.mdep[idx].mdep_id = mdep_id;
- memcpy(p_mdep_cfg,
- &p_btif_hl_cb->acb[app_idx].sup_feature.mdep[idx].mdep_cfg,
- sizeof(tBTA_HL_MDEP_CFG));
-
- success = true;
- }
-
- BTIF_TRACE_DEBUG("%s success=%d mdep_idx=%d mdep_id=%d", __func__, success,
- mdep_idx, mdep_id);
-
- return success;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_co_get_echo_config
- *
- * Description This function is called to get the echo test
- * maximum APDU size configurations
- *
- * Parameters app_id - HDP application ID
- * p_echo_cfg (output) - pointer to the Echo test maximum APDU
- * size configuration
- *
- * Returns Bloolean - true success
- ******************************************************************************/
-bool bta_hl_co_get_echo_config(uint8_t app_id, tBTA_HL_ECHO_CFG* p_echo_cfg) {
- uint8_t app_idx;
- bool success = false;
- btif_hl_app_cb_t* p_acb;
- tBTA_HL_SUP_FEATURE* p_sup;
-
- BTIF_TRACE_DEBUG("%s app_id=%d", __func__, app_id);
-
- if (btif_hl_find_app_idx(app_id, &app_idx)) {
- p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
- p_sup = &p_acb->sup_feature;
- p_echo_cfg->max_rx_apdu_size = p_sup->echo_cfg.max_rx_apdu_size;
- p_echo_cfg->max_tx_apdu_size = p_sup->echo_cfg.max_tx_apdu_size;
- success = true;
- }
-
- BTIF_TRACE_DEBUG("%s success=%d max tx_size=%d rx_size=%d", __func__, success,
- p_echo_cfg->max_tx_apdu_size, p_echo_cfg->max_rx_apdu_size);
-
- return success;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_co_save_mdl
- *
- * Description This function is called to save a MDL configuration item in
- * persistent storage
- *
- * Parameters app_id - HDP application ID
- * item_idx - the MDL configuration storage index
- * p_mdl_cfg - pointer to the MDL configuration data
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_co_save_mdl(uint8_t mdep_id, uint8_t item_idx,
- tBTA_HL_MDL_CFG* p_mdl_cfg) {
- BTIF_TRACE_DEBUG("%s mdep_id =%d, item_idx=%d active=%d mdl_id=%d time=%d",
- __func__, mdep_id, item_idx, p_mdl_cfg->active,
- p_mdl_cfg->mdl_id, p_mdl_cfg->time);
-
- btif_hl_save_mdl_cfg(mdep_id, item_idx, p_mdl_cfg);
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_co_delete_mdl
- *
- * Description This function is called to delete a MDL configuration item in
- * persistent storage
- *
- * Parameters app_id - HDP application ID
- * item_idx - the MDL configuration storage index
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hl_co_delete_mdl(uint8_t mdep_id, uint8_t item_idx) {
- BTIF_TRACE_DEBUG("%s mdep_id=%d, item_idx=%d", __func__, mdep_id, item_idx);
-
- btif_hl_delete_mdl_cfg(mdep_id, item_idx);
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_co_get_mdl_config
- *
- * Description This function is called to get the MDL configuration
- * from the persistent memory. This function shall only be
- * called once after the device is powered up
- *
- * Parameters app_id - HDP application ID
- * buffer_size - the unit of the buffer size is
- * sizeof(tBTA_HL_MDL_CFG)
- * p_mdl_buf - Point to the starting location of the buffer
- *
- * Returns bool
- *
- *
- ******************************************************************************/
-bool bta_hl_co_load_mdl_config(uint8_t app_id, uint8_t buffer_size,
- tBTA_HL_MDL_CFG* p_mdl_buf) {
- bool result = true;
- uint8_t i;
- tBTA_HL_MDL_CFG* p;
-
- BTIF_TRACE_DEBUG("%s app_id=%d, num_items=%d", __func__, app_id, buffer_size);
-
- if (buffer_size > BTA_HL_NUM_MDL_CFGS) {
- result = false;
- return result;
- }
- result = btif_hl_load_mdl_config(app_id, buffer_size, p_mdl_buf);
-
- if (result) {
- for (i = 0, p = p_mdl_buf; i < buffer_size; i++, p++) {
- if (p->active) {
- BTIF_TRACE_DEBUG(
- "i=%d mdl_id=0x%x dch_mode=%d local mdep_role=%d mdep_id=%d mtu=%d",
- i, p->mdl_id, p->dch_mode, p->local_mdep_role, p->local_mdep_role,
- p->mtu);
- }
- }
- }
-
- BTIF_TRACE_DEBUG("%s success=%d num_items=%d", __func__, result, buffer_size);
-
- return result;
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_co_get_tx_data
- *
- * Description Get the data to be sent
- *
- * Parameters app_id - HDP application ID
- * mdl_handle - MDL handle
- * buf_size - the size of the buffer
- * p_buf - the buffer pointer
- * evt - the evt to be passed back to the HL in the
- * bta_hl_ci_get_tx_data call-in function
- *
- * Returns Void
- *
- ******************************************************************************/
-void bta_hl_co_get_tx_data(uint8_t app_id, tBTA_HL_MDL_HANDLE mdl_handle,
- uint16_t buf_size, uint8_t* p_buf, uint16_t evt) {
- uint8_t app_idx, mcl_idx, mdl_idx;
- btif_hl_mdl_cb_t* p_dcb;
- tBTA_HL_STATUS status = BTA_HL_STATUS_FAIL;
-
- BTIF_TRACE_DEBUG("%s app_id=%d mdl_handle=0x%x buf_size=%d", __func__, app_id,
- mdl_handle, buf_size);
-
- if (btif_hl_find_mdl_idx_using_handle(mdl_handle, &app_idx, &mcl_idx,
- &mdl_idx)) {
- p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
-
- if ((p_dcb->tx_size <= buf_size) && p_dcb->p_tx_pkt) {
- memcpy(p_buf, p_dcb->p_tx_pkt, p_dcb->tx_size);
- osi_free_and_reset((void**)&p_dcb->p_tx_pkt);
- p_dcb->tx_size = 0;
- status = BTA_HL_STATUS_OK;
- }
- }
-
- bta_hl_ci_get_tx_data(mdl_handle, status, evt);
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_co_put_rx_data
- *
- * Description Put the received data
- *
- * Parameters app_id - HDP application ID
- * mdl_handle - MDL handle
- * data_size - the size of the data
- * p_data - the data pointer
- * evt - the evt to be passed back to the HL in the
- * bta_hl_ci_put_rx_data call-in function
- *
- * Returns Void
- *
- ******************************************************************************/
-void bta_hl_co_put_rx_data(uint8_t app_id, tBTA_HL_MDL_HANDLE mdl_handle,
- uint16_t data_size, uint8_t* p_data, uint16_t evt) {
- uint8_t app_idx, mcl_idx, mdl_idx;
- btif_hl_mdl_cb_t* p_dcb;
- tBTA_HL_STATUS status = BTA_HL_STATUS_FAIL;
- BTIF_TRACE_DEBUG("%s app_id=%d mdl_handle=0x%x data_size=%d", __func__,
- app_id, mdl_handle, data_size);
-
- if (btif_hl_find_mdl_idx_using_handle(mdl_handle, &app_idx, &mcl_idx,
- &mdl_idx)) {
- p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
-
- p_dcb->p_rx_pkt = (uint8_t*)osi_malloc(data_size);
- memcpy(p_dcb->p_rx_pkt, p_data, data_size);
- if (p_dcb->p_scb) {
- BTIF_TRACE_DEBUG("app_idx=%d mcl_idx=0x%x mdl_idx=0x%x data_size=%d",
- app_idx, mcl_idx, mdl_idx, data_size);
- ssize_t r;
- OSI_NO_INTR(
- r = send(p_dcb->p_scb->socket_id[1], p_dcb->p_rx_pkt, data_size, 0));
- if (r == data_size) {
- BTIF_TRACE_DEBUG("socket send success data_size=%d", data_size);
- status = BTA_HL_STATUS_OK;
- } else {
- BTIF_TRACE_ERROR("socket send failed r=%d data_size=%d", r, data_size);
- }
- }
- osi_free_and_reset((void**)&p_dcb->p_rx_pkt);
- }
-
- bta_hl_ci_put_rx_data(mdl_handle, status, evt);
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_co_get_tx_data
- *
- * Description Get the Echo data to be sent
- *
- * Parameters app_id - HDP application ID
- * mcl_handle - MCL handle
- * buf_size - the size of the buffer
- * p_buf - the buffer pointer
- * evt - the evt to be passed back to the HL in the
- * bta_hl_ci_get_tx_data call-in function
- *
- * Returns Void
- *
- ******************************************************************************/
-void bta_hl_co_get_echo_data(UNUSED_ATTR uint8_t app_id,
- tBTA_HL_MCL_HANDLE mcl_handle,
- UNUSED_ATTR uint16_t buf_size,
- UNUSED_ATTR uint8_t* p_buf, uint16_t evt) {
- tBTA_HL_STATUS status = BTA_HL_STATUS_FAIL;
-
- BTIF_TRACE_ERROR("%s not supported", __func__);
- bta_hl_ci_get_echo_data(mcl_handle, status, evt);
-}
-
-/*******************************************************************************
- *
- * Function bta_hl_co_put_echo_data
- *
- * Description Put the received loopback echo data
- *
- * Parameters app_id - HDP application ID
- * mcl_handle - MCL handle
- * data_size - the size of the data
- * p_data - the data pointer
- * evt - the evt to be passed back to the HL in the
- * bta_hl_ci_put_echo_data call-in function
- *
- * Returns Void
- *
- ******************************************************************************/
-void bta_hl_co_put_echo_data(UNUSED_ATTR uint8_t app_id,
- tBTA_HL_MCL_HANDLE mcl_handle,
- UNUSED_ATTR uint16_t data_size,
- UNUSED_ATTR uint8_t* p_data, uint16_t evt) {
- tBTA_HL_STATUS status = BTA_HL_STATUS_FAIL;
-
- BTIF_TRACE_ERROR("%s not supported", __func__);
- bta_hl_ci_put_echo_data(mcl_handle, status, evt);
-}
diff --git a/btif/include/btif_a2dp.h b/btif/include/btif_a2dp.h
index 7b7b2ca..49e4f9c 100644
--- a/btif/include/btif_a2dp.h
+++ b/btif/include/btif_a2dp.h
@@ -31,11 +31,8 @@
// streaming.
// |peer_addr| is the peer address.
// |p_av_start| is the data associated with the request - see |tBTA_AV_START|.
-// |pending_start| should be set to true if the BTIF state machine is in
-// 'pending start' state.
// Returns true if an ACK for the local command was sent, otherwise false.
-bool btif_a2dp_on_started(const RawAddress& peer_addr,
- tBTA_AV_START* p_av_start, bool pending_start);
+bool btif_a2dp_on_started(const RawAddress& peer_addr, tBTA_AV_START* p_av_start);
// Process 'stop' request from the BTIF state machine to stop A2DP streaming.
// |p_av_suspend| is the data associated with the request - see
diff --git a/btif/include/btif_a2dp_sink.h b/btif/include/btif_a2dp_sink.h
index 25e65f4..0a9038c 100644
--- a/btif/include/btif_a2dp_sink.h
+++ b/btif/include/btif_a2dp_sink.h
@@ -22,6 +22,7 @@
#include <inttypes.h>
#include <stdbool.h>
+#include <future>
#include "bt_types.h"
#include "bta_av_api.h"
@@ -52,7 +53,8 @@
// Start the A2DP Sink session.
// This function should be called by the BTIF state machine after
// btif_a2dp_sink_startup() to start the streaming session for |peer_address|.
-bool btif_a2dp_sink_start_session(const RawAddress& peer_address);
+bool btif_a2dp_sink_start_session(const RawAddress& peer_address,
+ std::promise<void> peer_ready_promise);
// Restart the A2DP Sink session.
// This function should be called by the BTIF state machine after
@@ -62,7 +64,8 @@
// |new_peer_address| is the peer address of the new session. This address
// cannot be empty.
bool btif_a2dp_sink_restart_session(const RawAddress& old_peer_address,
- const RawAddress& new_peer_address);
+ const RawAddress& new_peer_address,
+ std::promise<void> peer_ready_promise);
// End the A2DP Sink session.
// This function should be called by the BTIF state machine to end the
@@ -85,6 +88,9 @@
// Get the audio channel count for the A2DP Sink module.
tA2DP_CHANNEL_COUNT btif_a2dp_sink_get_channel_count(void);
+// Get the audio bits per sample for the A2DP Sink module.
+tA2DP_BITS_PER_SAMPLE btif_a2dp_sink_get_bits_per_sample(void);
+
// Update the decoder for the A2DP Sink module.
// |p_codec_info| contains the new codec information.
void btif_a2dp_sink_update_decoder(const uint8_t* p_codec_info);
diff --git a/btif/include/btif_a2dp_source.h b/btif/include/btif_a2dp_source.h
index bb96e1a..0649012 100644
--- a/btif/include/btif_a2dp_source.h
+++ b/btif/include/btif_a2dp_source.h
@@ -21,6 +21,7 @@
#define BTIF_A2DP_SOURCE_H
#include <stdbool.h>
+#include <future>
#include "bta_av_api.h"
@@ -37,7 +38,8 @@
// Start the A2DP Source session.
// This function should be called by the BTIF state machine after
// btif_a2dp_source_startup() to start the streaming session for |peer_address|.
-bool btif_a2dp_source_start_session(const RawAddress& peer_address);
+bool btif_a2dp_source_start_session(const RawAddress& peer_address,
+ std::promise<void> peer_ready_promise);
// Restart the A2DP Source session.
// This function should be called by the BTIF state machine after
@@ -47,7 +49,8 @@
// |new_peer_address| is the peer address of the new session. This address
// cannot be empty.
bool btif_a2dp_source_restart_session(const RawAddress& old_peer_address,
- const RawAddress& new_peer_address);
+ const RawAddress& new_peer_address,
+ std::promise<void> peer_ready_promise);
// End the A2DP Source session.
// This function should be called by the BTIF state machine to end the
diff --git a/btif/include/btif_av.h b/btif/include/btif_av.h
index 486c2af..e42f056 100644
--- a/btif/include/btif_av.h
+++ b/btif/include/btif_av.h
@@ -92,27 +92,6 @@
void btif_av_clear_remote_suspend_flag(void);
/**
- * Process AVRCP Open event.
- *
- * @param peer_address the peer address
- */
-void btif_av_avrcp_event_open(const RawAddress& peer_address);
-
-/**
- * Process AVRCP Close event.
- *
- * @param peer_address the peer address
- */
-void btif_av_avrcp_event_close(const RawAddress& peer_address);
-
-/**
- * Process AVRCP Remote Play event.
- *
- * @param peer_address the peer address
- */
-void btif_av_avrcp_event_remote_play(const RawAddress& peer_address);
-
-/**
* Check whether the connected A2DP peer supports EDR.
*
* The value can be provided only if the remote peer is connected.
@@ -207,4 +186,13 @@
* @param none
*/
bool btif_av_is_a2dp_offload_enabled(void);
+
+/**
+ * Check whether peer device is silenced
+ *
+ * @param peer_address to check
+ *
+ */
+bool btif_av_is_peer_silenced(const RawAddress& peer_address);
+
#endif /* BTIF_AV_H */
diff --git a/btif/include/btif_av_co.h b/btif/include/btif_av_co.h
index df7454f..93d6d7e 100644
--- a/btif/include/btif_av_co.h
+++ b/btif/include/btif_av_co.h
@@ -65,6 +65,10 @@
void bta_av_co_init(
const std::vector<btav_a2dp_codec_config_t>& codec_priorities);
+// Checks whether the codec for |codec_index| is supported.
+// Returns true if the codec is supported, otherwise false.
+bool bta_av_co_is_supported_codec(btav_a2dp_codec_index_t codec_index);
+
// Gets the current A2DP codec for the active peer.
// Returns a pointer to the current |A2dpCodecConfig| if valid, otherwise
// nullptr.
diff --git a/btif/include/btif_avrcp_audio_track.h b/btif/include/btif_avrcp_audio_track.h
index 720fe60..20b21ff 100644
--- a/btif/include/btif_avrcp_audio_track.h
+++ b/btif/include/btif_avrcp_audio_track.h
@@ -35,7 +35,8 @@
* should eventually be
* deleted using BtifAvrcpAudioTrackDelete (see below).
*/
-void* BtifAvrcpAudioTrackCreate(int trackFreq, int channelType);
+void* BtifAvrcpAudioTrackCreate(int trackFreq, int bits_per_sample,
+ int channelType);
/**
* Starts the audio track.
diff --git a/btif/include/btif_bqr.h b/btif/include/btif_bqr.h
new file mode 100644
index 0000000..4407b0d
--- /dev/null
+++ b/btif/include/btif_bqr.h
@@ -0,0 +1,268 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#ifndef BTIF_BQR_H_
+#define BTIF_BQR_H_
+
+#include "btm_api_types.h"
+#include "common/leaky_bonded_queue.h"
+
+namespace bluetooth {
+namespace bqr {
+
+// Bluetooth Quality Report (BQR)
+//
+// It is a feature to start the mechanism in the Bluetooth controller to report
+// Bluetooth Quality event to the host and there are four options could be
+// enabled:
+// [Quality Monitoring Mode]
+// The controller shall periodically send Bluetooth Quality Report sub-event
+// to the host.
+//
+// [Approaching LSTO]
+// Once no packets are received from the connected Bluetooth device for a
+// duration longer than the half of LSTO (Link Supervision TimeOut) value,
+// the controller shall report Approaching LSTO event to the host.
+//
+// [A2DP Audio Choppy]
+// When the controller detects the factors which will cause audio choppy,
+// the controller shall report A2DP Audio Choppy event to the host.
+//
+// [(e)SCO Voice Choppy]
+// When the controller detects the factors which will cause voice choppy,
+// the controller shall report (e)SCO Voice Choppy event to the host.
+
+// Bit masks for the selected quality event reporting.
+static constexpr uint32_t kQualityEventMaskAllOff = 0;
+static constexpr uint32_t kQualityEventMaskMonitorMode = 0x00000001;
+static constexpr uint32_t kQualityEventMaskApproachLsto = 0x00000002;
+static constexpr uint32_t kQualityEventMaskA2dpAudioChoppy = 0x00000004;
+static constexpr uint32_t kQualityEventMaskScoVoiceChoppy = 0x00000008;
+static constexpr uint32_t kQualityEventMaskAll =
+ kQualityEventMaskMonitorMode | kQualityEventMaskApproachLsto |
+ kQualityEventMaskA2dpAudioChoppy | kQualityEventMaskScoVoiceChoppy;
+// Define the minimum time interval (in ms) of quality event reporting for the
+// selected quality event(s). Controller Firmware should not report the next
+// event within the defined time interval.
+static constexpr uint16_t kMinReportIntervalNoLimit = 0;
+static constexpr uint16_t kMinReportIntervalMaxMs = 0xFFFF;
+// Total length of all BQR parameters except Vendor Specific Parameters.
+static constexpr uint8_t kBqrParamTotalLen = 48;
+// Warning criteria of the RSSI value.
+static constexpr int8_t kCriWarnRssi = -80;
+// Warning criteria of the unused AFH channel count.
+static constexpr uint8_t kCriWarnUnusedCh = 55;
+// The queue size of recording the BQR events.
+static constexpr uint8_t kBqrEventQueueSize = 25;
+// The Property of BQR event mask configuration.
+static constexpr const char* kpPropertyEventMask =
+ "persist.bluetooth.bqr.event_mask";
+// The Property of BQR minimum report interval configuration.
+static constexpr const char* kpPropertyMinReportIntervalMs =
+ "persist.bluetooth.bqr.min_interval_ms";
+
+// Action definition
+//
+// Action to Add, Delete or Clear the reporting of quality event(s).
+// Delete will clear specific quality event(s) reporting. Clear will clear all
+// quality events reporting.
+enum BqrReportAction : uint8_t {
+ REPORT_ACTION_ADD = 0x00,
+ REPORT_ACTION_DELETE = 0x01,
+ REPORT_ACTION_CLEAR = 0x02
+};
+
+// Report ID definition
+enum BqrQualityReportId : uint8_t {
+ QUALITY_REPORT_ID_MONITOR_MODE = 0x01,
+ QUALITY_REPORT_ID_APPROACH_LSTO = 0x02,
+ QUALITY_REPORT_ID_A2DP_AUDIO_CHOPPY = 0x03,
+ QUALITY_REPORT_ID_SCO_VOICE_CHOPPY = 0x04
+};
+
+// Packet Type definition
+enum BqrPacketType : uint8_t {
+ PACKET_TYPE_ID = 0x01,
+ PACKET_TYPE_NULL,
+ PACKET_TYPE_POLL,
+ PACKET_TYPE_FHS,
+ PACKET_TYPE_HV1,
+ PACKET_TYPE_HV2,
+ PACKET_TYPE_HV3,
+ PACKET_TYPE_DV,
+ PACKET_TYPE_EV3,
+ PACKET_TYPE_EV4,
+ PACKET_TYPE_EV5,
+ PACKET_TYPE_2EV3,
+ PACKET_TYPE_2EV5,
+ PACKET_TYPE_3EV3,
+ PACKET_TYPE_3EV5,
+ PACKET_TYPE_DM1,
+ PACKET_TYPE_DH1,
+ PACKET_TYPE_DM3,
+ PACKET_TYPE_DH3,
+ PACKET_TYPE_DM5,
+ PACKET_TYPE_DH5,
+ PACKET_TYPE_AUX1,
+ PACKET_TYPE_2DH1,
+ PACKET_TYPE_2DH3,
+ PACKET_TYPE_2DH5,
+ PACKET_TYPE_3DH1,
+ PACKET_TYPE_3DH3,
+ PACKET_TYPE_3DH5
+};
+
+// Configuration Parameters
+typedef struct {
+ BqrReportAction report_action;
+ uint32_t quality_event_mask;
+ uint16_t minimum_report_interval_ms;
+} BqrConfiguration;
+
+// BQR sub-event of Vendor Specific Event
+class BqrVseSubEvt {
+ public:
+ // Parse the Bluetooth Quality Report VSE sub-event.
+ //
+ // @param length Total length of all parameters contained in the sub-event.
+ // @param p_param_buf A pointer to the parameters contained in the sub-event.
+ // @return false If the parameter total length is abnormal.
+ // true If all parameters are parsed successfully.
+ bool ParseBqrEvt(uint8_t length, uint8_t* p_param_buf);
+
+ // Get a string representation of the Bluetooth Quality event.
+ //
+ // @return a string representation of the Bluetooth Quality event.
+ std::string ToString() const;
+
+ friend std::ostream& operator<<(std::ostream& os, const BqrVseSubEvt& a) {
+ return os << a.ToString();
+ }
+
+ virtual ~BqrVseSubEvt() = default;
+
+ // Quality report ID.
+ uint8_t quality_report_id_ = 0;
+ // Packet type of the connection.
+ uint8_t packet_types_ = 0;
+ // Connection handle of the connection.
+ uint16_t connection_handle_ = 0;
+ // Performing Role for the connection.
+ uint8_t connection_role_ = 0;
+ // Current Transmit Power Level for the connection. This value is the same as
+ // the controller's response to the HCI_Read_Transmit_Power_Level HCI command.
+ uint8_t tx_power_level_ = 0;
+ // Received Signal Strength Indication (RSSI) value for the connection. This
+ // value is an absolute receiver signal strength value.
+ int8_t rssi_ = 0;
+ // Signal-to-Noise Ratio (SNR) value for the connection. It is the average
+ // SNR of all the channels used by the link currently.
+ uint8_t snr_ = 0;
+ // Indicates the number of unused channels in AFH_channel_map.
+ uint8_t unused_afh_channel_count_ = 0;
+ // Indicates the number of the channels which are interfered and quality is
+ // bad but are still selected for AFH.
+ uint8_t afh_select_unideal_channel_count_ = 0;
+ // Current Link Supervision Timeout Setting.
+ // Unit: N * 0.3125 ms (1 Bluetooth Clock)
+ uint16_t lsto_ = 0;
+ // Piconet Clock for the specified Connection_Handle. This value is the same
+ // as the controller's response to HCI_Read_Clock HCI command with the
+ // parameter "Which_Clock" of 0x01 (Piconet Clock).
+ // Unit: N * 0.3125 ms (1 Bluetooth Clock)
+ uint32_t connection_piconet_clock_ = 0;
+ // The count of retransmission.
+ uint32_t retransmission_count_ = 0;
+ // The count of no RX.
+ uint32_t no_rx_count_ = 0;
+ // The count of NAK (Negative Acknowledge).
+ uint32_t nak_count_ = 0;
+ // Timestamp of last TX ACK.
+ // Unit: N * 0.3125 ms (1 Bluetooth Clock)
+ uint32_t last_tx_ack_timestamp_ = 0;
+ // The count of Flow-off (STOP).
+ uint32_t flow_off_count_ = 0;
+ // Timestamp of last Flow-on (GO).
+ // Unit: N * 0.3125 ms (1 Bluetooth Clock)
+ uint32_t last_flow_on_timestamp_ = 0;
+ // Buffer overflow count (how many bytes of TX data are dropped) since the
+ // last event.
+ uint32_t buffer_overflow_bytes_ = 0;
+ // Buffer underflow count (in byte).
+ uint32_t buffer_underflow_bytes_ = 0;
+ // Local wall clock timestamp of receiving BQR VSE sub-event
+ std::tm tm_timestamp_ = {};
+};
+
+// Get a string representation of the Quality Report ID.
+//
+// @param quality_report_id The quality report ID to convert.
+// @return a string representation of the Quality Report ID.
+std::string QualityReportIdToString(uint8_t quality_report_id);
+
+// Get a string representation of the Packet Type.
+//
+// @param packet_type The packet type to convert.
+// @return a string representation of the Packet Type.
+std::string PacketTypeToString(uint8_t packet_type);
+
+// Enable/Disable Bluetooth Quality Report mechanism.
+//
+// Which Quality event will be enabled is according to the setting of the
+// property "persist.bluetooth.bqr.event_mask".
+// And the minimum time interval of quality event reporting depends on the
+// setting of property "persist.bluetooth.bqr.min_interval_ms".
+//
+// @param is_enable True/False to enable/disable Bluetooth Quality Report
+// mechanism in the Bluetooth controller.
+void EnableBtQualityReport(bool is_enable);
+
+// Dump Bluetooth Quality Report information.
+//
+// @param fd The file descriptor to use for dumping information.
+void DebugDump(int fd);
+
+// Configure Bluetooth Quality Report setting to the Bluetooth controller.
+//
+// @param bqr_config The struct of configuration parameters.
+void ConfigureBqr(const BqrConfiguration& bqr_config);
+
+// Invoked on completion of Bluetooth Quality Report configuration. Then it will
+// Register/Unregister for receiving VSE - Bluetooth Quality Report sub event.
+//
+// @param current_evt_mask Indicates current quality event bit mask setting in
+// the Bluetooth controller.
+void ConfigureBqrCmpl(uint32_t current_evt_mask);
+
+// Callback invoked on completion of vendor specific Bluetooth Quality Report
+// command.
+//
+// @param p_vsc_cmpl_params A pointer to the parameters contained in the vendor
+// specific command complete event.
+void BqrVscCompleteCallback(tBTM_VSC_CMPL* p_vsc_cmpl_params);
+
+// Record a new incoming Bluetooth Quality Report in quality event queue.
+//
+// @param len Lengths of the quality report sent from the Bluetooth
+// controller.
+// @param p_quality_report A pointer to the quality report which is sent from
+// the Bluetooth controller via Vendor Specific Event.
+void AddBqrEventToQueue(uint8_t length, uint8_t* p_stream);
+
+} // namespace bqr
+} // namespace bluetooth
+
+#endif // BTIF_BQR_H_
diff --git a/btif/include/btif_common.h b/btif/include/btif_common.h
index af0beb0..39034c3 100644
--- a/btif/include/btif_common.h
+++ b/btif/include/btif_common.h
@@ -23,8 +23,8 @@
#include <stdlib.h>
#include <base/bind.h>
+#include <base/location.h>
#include <base/message_loop/message_loop.h>
-#include <base/tracked_objects.h>
#include <hardware/bluetooth.h>
#include "bt_types.h"
@@ -174,9 +174,9 @@
* Functions
******************************************************************************/
-extern bt_status_t do_in_jni_thread(const base::Closure& task);
-extern bt_status_t do_in_jni_thread(const tracked_objects::Location& from_here,
- const base::Closure& task);
+extern bt_status_t do_in_jni_thread(base::OnceClosure task);
+extern bt_status_t do_in_jni_thread(const base::Location& from_here,
+ base::OnceClosure task);
extern bool is_on_jni_thread();
extern base::MessageLoop* get_jni_message_loop();
/**
@@ -184,11 +184,11 @@
* thread
*/
template <typename R, typename... Args>
-base::Callback<R(Args...)> jni_thread_wrapper(
- const tracked_objects::Location& from_here, base::Callback<R(Args...)> cb) {
+base::Callback<R(Args...)> jni_thread_wrapper(const base::Location& from_here,
+ base::Callback<R(Args...)> cb) {
return base::Bind(
- [](const tracked_objects::Location& from_here,
- base::Callback<R(Args...)> cb, Args... args) {
+ [](const base::Location& from_here, base::Callback<R(Args...)> cb,
+ Args... args) {
do_in_jni_thread(from_here,
base::Bind(cb, std::forward<Args>(args)...));
},
diff --git a/btif/include/btif_dm.h b/btif/include/btif_dm.h
index 6105ab5..a9cb228 100644
--- a/btif/include/btif_dm.h
+++ b/btif/include/btif_dm.h
@@ -61,9 +61,9 @@
tBTA_LE_AUTH_REQ* p_auth_req);
#ifdef BTIF_DM_OOB_TEST
void btif_dm_load_local_oob(void);
-void btif_dm_proc_loc_oob(bool valid, BT_OCTET16 c, BT_OCTET16 r);
-bool btif_dm_proc_rmt_oob(const RawAddress& bd_addr, BT_OCTET16 p_c,
- BT_OCTET16 p_r);
+void btif_dm_proc_loc_oob(bool valid, const Octet16& c, const Octet16& r);
+bool btif_dm_proc_rmt_oob(const RawAddress& bd_addr, Octet16* p_c,
+ Octet16* p_r);
#endif /* BTIF_DM_OOB_TEST */
/*callout for reading SMP properties from Text file*/
@@ -98,7 +98,7 @@
void btif_dm_load_ble_local_keys(void);
void btif_dm_get_ble_local_keys(tBTA_DM_BLE_LOCAL_KEY_MASK* p_key_mask,
- BT_OCTET16 er,
+ Octet16* p_er,
tBTA_BLE_LOCAL_ID_KEYS* p_id_keys);
void btif_dm_save_ble_bonding_keys(void);
void btif_dm_remove_ble_bonding_keys(void);
diff --git a/btif/include/btif_hh.h b/btif/include/btif_hh.h
index 2364544..b71d347 100644
--- a/btif/include/btif_hh.h
+++ b/btif/include/btif_hh.h
@@ -25,6 +25,7 @@
#include <stdint.h>
#include "bta_hh_api.h"
#include "btu.h"
+#include "osi/include/fixed_queue.h"
/*******************************************************************************
* Constants & Macros
@@ -67,6 +68,8 @@
pthread_t hh_poll_thread_id;
uint8_t hh_keep_polling;
alarm_t* vup_timer;
+ fixed_queue_t* get_rpt_id_queue;
+ uint8_t get_rpt_snt;
bool local_vup; // Indicated locally initiated VUP
} btif_hh_device_t;
@@ -106,6 +109,9 @@
extern void btif_hh_setreport(btif_hh_device_t* p_dev,
bthh_report_type_t r_type, uint16_t size,
uint8_t* report);
+extern void btif_hh_getreport(btif_hh_device_t* p_dev,
+ bthh_report_type_t r_type, uint8_t reportId,
+ uint16_t bufferSize);
extern void btif_hh_service_registration(bool enable);
#endif
diff --git a/btif/include/btif_hl.h b/btif/include/btif_hl.h
deleted file mode 100644
index 69a99b5..0000000
--- a/btif/include/btif_hl.h
+++ /dev/null
@@ -1,315 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2009-2012 Broadcom 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.
- *
- ******************************************************************************/
-
-#ifndef BTIF_HL_H
-#define BTIF_HL_H
-
-#include <hardware/bluetooth.h>
-
-#include "bt_common.h"
-#include "bta_hl_api.h"
-#include "osi/include/alarm.h"
-
-/*******************************************************************************
- * Constants & Macros
- ******************************************************************************/
-
-#define BTIF_HL_DATA_TYPE_NONE 0x0000
-#define BTIF_HL_DATA_TYPE_PULSE_OXIMETER 0x1004 /* from BT assigned number */
-#define BTIF_HL_DATA_TYPE_BLOOD_PRESSURE_MON 0x1007
-#define BTIF_HL_DATA_TYPE_BODY_THERMOMETER 0x1008
-#define BTIF_HL_DATA_TYPE_BODY_WEIGHT_SCALE 0x100F
-#define BTIF_HL_DATA_TYPE_GLUCOSE_METER 0x1011
-#define BTIF_HL_DATA_TYPE_STEP_COUNTER 0x1068
-#define BTIF_HL_DATA_TYPE_BCA 0x1014
-#define BTIF_HL_DATA_TYPE_PEAK_FLOW 0x1015
-#define BTIF_HL_DATA_TYPE_CARDIO 0x1029
-#define BTIF_HL_DATA_TYPE_ACTIVITY_HUB 0x1047
-#define BTIF_HL_DATA_TYPE_AMM 0x1048
-
-#define BTIF_HL_CCH_NUM_FILTER_ELEMS 3
-#define BTIF_HL_APPLICATION_NAME_LEN 512
-
-/*******************************************************************************
- * Type definitions and return values
- ******************************************************************************/
-
-typedef enum {
- BTIF_HL_SOC_STATE_IDLE,
- BTIF_HL_SOC_STATE_W4_ADD,
- BTIF_HL_SOC_STATE_W4_CONN,
- BTIF_HL_SOC_STATE_W4_READ,
- BTIF_HL_SOC_STATE_W4_REL
-} btif_hl_soc_state_t;
-
-typedef enum {
- BTIF_HL_STATE_DISABLED,
- BTIF_HL_STATE_DISABLING,
- BTIF_HL_STATE_ENABLED,
- BTIF_HL_STATE_ENABLING,
-} btif_hl_state_t;
-
-typedef enum {
- BTIF_HL_CCH_OP_NONE,
- BTIF_HL_CCH_OP_MDEP_FILTERING,
- BTIF_HL_CCH_OP_MATCHED_CTRL_PSM,
- BTIF_HL_CCH_OP_DCH_OPEN,
- BTIF_HL_CCH_OP_DCH_RECONNECT,
- BTIF_HL_CCH_OP_DCH_ECHO_TEST
-} btif_hl_cch_op_t;
-
-typedef enum {
- BTIF_HL_PEND_DCH_OP_NONE,
- BTIF_HL_PEND_DCH_OP_DELETE_MDL,
- BTIF_HL_PEND_DCH_OP_OPEN,
- BTIF_HL_PEND_DCH_OP_RECONNECT
-} btif_hl_pend_dch_op_t;
-
-typedef enum { BTIF_HL_DCH_OP_NONE, BTIF_HL_DCH_OP_DISC } btif_hl_dch_op_t;
-
-typedef enum {
- BTIF_HL_CHAN_CB_STATE_NONE,
- BTIF_HL_CHAN_CB_STATE_CONNECTING_PENDING,
- BTIF_HL_CHAN_CB_STATE_CONNECTED_PENDING,
-
- BTIF_HL_CHAN_CB_STATE_DISCONNECTING_PENDING,
- BTIF_HL_CHAN_CB_STATE_DISCONNECTED_PENDING,
- BTIF_HL_CHAN_CB_STATE_DESTROYED_PENDING,
-} btif_hl_chan_cb_state_t;
-
-enum {
- BTIF_HL_SEND_CONNECTED_CB,
- BTIF_HL_SEND_DISCONNECTED_CB,
- BTIF_HL_REG_APP,
- BTIF_HL_UNREG_APP,
- BTIF_HL_UPDATE_MDL,
-};
-
-typedef struct {
- uint8_t mdep_cfg_idx;
- int data_type;
- tBTA_HL_MDEP_ID peer_mdep_id;
-} btif_hl_extra_mdl_cfg_t;
-
-typedef struct {
- tBTA_HL_MDL_CFG base;
- btif_hl_extra_mdl_cfg_t extra;
-} btif_hl_mdl_cfg_t;
-
-typedef struct {
- bool active;
- uint8_t app_idx;
-} btif_hl_app_data_t;
-
-typedef struct {
- int channel_id;
- RawAddress bd_addr;
- uint8_t mdep_cfg_idx;
- int max_s;
- int socket_id[2];
- uint8_t app_idx;
- uint8_t mcl_idx;
- uint8_t mdl_idx;
- btif_hl_soc_state_t state;
-} btif_hl_soc_cb_t;
-
-typedef struct {
- uint16_t data_type;
- uint16_t max_tx_apdu_size;
- uint16_t max_rx_apdu_size;
-} btif_hl_data_type_cfg_t;
-
-typedef struct {
- uint16_t data_type;
- tBTA_HL_MDEP_ROLE peer_mdep_role;
-} btif_hl_filter_elem_t;
-
-typedef struct {
- uint8_t num_elems;
- btif_hl_filter_elem_t elem[BTIF_HL_CCH_NUM_FILTER_ELEMS];
-} btif_hl_cch_filter_t;
-
-typedef struct {
- bool in_use;
- uint16_t mdl_id;
- tBTA_HL_MDL_HANDLE mdl_handle;
- btif_hl_dch_op_t dch_oper;
- tBTA_HL_MDEP_ID local_mdep_id;
- uint8_t local_mdep_cfg_idx;
- tBTA_HL_DCH_CFG local_cfg;
- tBTA_HL_MDEP_ID peer_mdep_id;
- uint16_t peer_data_type;
- tBTA_HL_MDEP_ROLE peer_mdep_role;
- tBTA_HL_DCH_MODE dch_mode;
- tBTA_SEC sec_mask;
- bool is_the_first_reliable;
- bool delete_mdl;
- uint16_t mtu;
- tMCA_CHNL_CFG chnl_cfg;
- uint16_t tx_size;
- uint8_t* p_tx_pkt;
- uint8_t* p_rx_pkt;
- bool cong;
- btif_hl_soc_cb_t* p_scb;
- int channel_id;
-} btif_hl_mdl_cb_t;
-
-typedef struct {
- int channel_id;
- int mdep_cfg_idx;
- bool in_use;
- btif_hl_chan_cb_state_t cb_state;
- btif_hl_pend_dch_op_t op;
- RawAddress bd_addr;
- bool abort_pending;
-} btif_hl_pending_chan_cb_t;
-
-typedef struct {
- btif_hl_mdl_cb_t mdl[BTA_HL_NUM_MDLS_PER_MCL];
- bool in_use;
- bool is_connected;
- uint16_t req_ctrl_psm;
- uint16_t ctrl_psm;
- uint16_t data_psm;
- RawAddress bd_addr;
- uint16_t cch_mtu;
- tBTA_SEC sec_mask;
- tBTA_HL_MCL_HANDLE mcl_handle;
- btif_hl_pending_chan_cb_t pcb;
- bool valid_sdp_idx;
- uint8_t sdp_idx;
- tBTA_HL_SDP sdp;
- btif_hl_cch_op_t cch_oper;
- alarm_t* cch_timer;
-} btif_hl_mcl_cb_t;
-
-typedef struct {
- bool active;
- uint16_t mdl_id;
- uint8_t mdep_cfg_idx;
- RawAddress bd_addr;
- int channel_id;
-} btif_hl_delete_mdl_t;
-
-typedef struct {
- btif_hl_mcl_cb_t mcb[BTA_HL_NUM_MCLS]; /* application Control Blocks */
- bool in_use; /* this CB is in use*/
- bool reg_pending;
- uint8_t app_id;
-
- tBTA_HL_SUP_FEATURE sup_feature;
- tBTA_HL_DCH_CFG channel_type[BTA_HL_NUM_MDEPS];
- tBTA_HL_SDP_INFO_IND sdp_info_ind;
- btif_hl_cch_filter_t filter;
-
- btif_hl_mdl_cfg_t mdl_cfg[BTA_HL_NUM_MDL_CFGS];
- int mdl_cfg_channel_id[BTA_HL_NUM_MDL_CFGS];
-
- btif_hl_delete_mdl_t delete_mdl;
- tBTA_HL_DEVICE_TYPE dev_type;
- tBTA_HL_APP_HANDLE app_handle;
- uint16_t sec_mask; /* Security mask for BTM_SetSecurityLevel() */
- char srv_name[BTA_SERVICE_NAME_LEN +
- 1]; /* service name to be used in the SDP; null terminated*/
- char srv_desp[BTA_SERVICE_DESP_LEN + 1]; /* service description to be used in
- the SDP; null terminated */
- char provider_name[BTA_PROVIDER_NAME_LEN + 1]; /* provide name to be used in
- the SDP; null terminated */
- char
- application_name[BTIF_HL_APPLICATION_NAME_LEN + 1]; /* applicaiton name */
-} btif_hl_app_cb_t;
-
-typedef struct {
- bool in_use;
- uint8_t app_idx;
-} btif_hl_pending_reg_cb_t;
-
-/* BTIF-HL control block */
-typedef struct {
- btif_hl_app_cb_t acb[BTA_HL_NUM_APPS]; /* HL Control Blocks */
- tBTA_HL_CTRL_CBACK* p_ctrl_cback; /* pointer to control callback function */
- uint8_t next_app_id;
- uint16_t next_channel_id;
- btif_hl_state_t state;
-} btif_hl_cb_t;
-
-typedef uint8_t btif_hl_evt_t;
-
-typedef struct {
- int app_id;
- RawAddress bd_addr;
- int mdep_cfg_index;
- int channel_id;
- btif_hl_chan_cb_state_t cb_state;
- int fd;
-} btif_hl_send_chan_state_cb_t;
-
-typedef struct { uint8_t app_idx; } btif_hl_reg_t;
-
-typedef btif_hl_reg_t btif_hl_unreg_t;
-typedef btif_hl_reg_t btif_hl_update_mdl_t;
-
-typedef union {
- btif_hl_send_chan_state_cb_t chan_cb;
- btif_hl_reg_t reg;
- btif_hl_unreg_t unreg;
- btif_hl_update_mdl_t update_mdl;
-} btif_hl_evt_cb_t;
-
-/*******************************************************************************
- * Functions
- ******************************************************************************/
-
-#define BTIF_HL_GET_CB_PTR() &(btif_hl_cb)
-#define BTIF_HL_GET_APP_CB_PTR(app_idx) &(btif_hl_cb.acb[(app_idx)])
-#define BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx) \
- &(btif_hl_cb.acb[(app_idx)].mcb[(mcl_idx)])
-#define BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx) \
- &(btif_hl_cb.acb[(app_idx)].mcb[(mcl_idx)].mdl[mdl_idx])
-#define BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx) \
- &(btif_hl_cb.acb[app_idx].mcb[mcl_idx].pcb)
-#define BTIF_HL_GET_MDL_CFG_PTR(app_idx, item_idx) \
- &(btif_hl_cb.acb[(app_idx)].mdl_cfg[(item_idx)])
-#define BTIF_HL_GET_MDL_CFG_CHANNEL_ID_PTR(app_idx, item_idx) \
- &(btif_hl_cb.acb[(app_idx)].mdl_cfg_channel_id[(item_idx)])
-
-extern btif_hl_cb_t btif_hl_cb;
-extern btif_hl_cb_t* p_btif_hl_cb;
-
-extern bool btif_hl_find_mcl_idx(uint8_t app_idx, const RawAddress& p_bd_addr,
- uint8_t* p_mcl_idx);
-extern bool btif_hl_find_app_idx(uint8_t app_id, uint8_t* p_app_idx);
-extern bool btif_hl_find_avail_mcl_idx(uint8_t app_idx, uint8_t* p_mcl_idx);
-extern bool btif_hl_find_avail_mdl_idx(uint8_t app_idx, uint8_t mcl_idx,
- uint8_t* p_mdl_idx);
-extern bool btif_hl_find_mcl_idx_using_handle(tBTA_HL_MCL_HANDLE mcl_handle,
- uint8_t* p_app_idx,
- uint8_t* p_mcl_idx);
-extern bool btif_hl_save_mdl_cfg(uint8_t app_id, uint8_t item_idx,
- tBTA_HL_MDL_CFG* p_mdl_cfg);
-extern bool btif_hl_delete_mdl_cfg(uint8_t app_id, uint8_t item_idx);
-extern bool btif_hl_find_mdl_idx_using_handle(tBTA_HL_MDL_HANDLE mdl_handle,
- uint8_t* p_app_idx,
- uint8_t* p_mcl_idx,
- uint8_t* p_mdl_idx);
-extern void btif_hl_abort_pending_chan_setup(uint8_t app_idx, uint8_t mcl_idx);
-extern bool btif_hl_proc_pending_op(uint8_t app_idx, uint8_t mcl_idx);
-extern bool btif_hl_load_mdl_config(uint8_t app_id, uint8_t buffer_size,
- tBTA_HL_MDL_CFG* p_mdl_buf);
-
-#endif
diff --git a/btif/include/btif_state_machine.h b/btif/include/btif_state_machine.h
deleted file mode 100644
index 49b1583..0000000
--- a/btif/include/btif_state_machine.h
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#ifndef BTIF_STATE_MACHINE_H
-#define BTIF_STATE_MACHINE_H
-
-#include <map>
-#include <utility>
-
-#include <base/logging.h>
-
-/**
- * State machine used by BTIF components.
- */
-class BtifStateMachine {
- public:
- enum { kStateInvalid = -1 };
-
- /**
- * A class to represent the state in the State Machine.
- */
- class State {
- friend class BtifStateMachine;
-
- public:
- /**
- * Constructor.
- *
- * @param sm the State Machine to use
- * @param state_id the unique State ID. It should be a non-negative number.
- */
- State(BtifStateMachine& sm, int state_id) : sm_(sm), state_id_(state_id) {}
-
- virtual ~State() = default;
-
- /**
- * Process an event.
- * TODO: The arguments are wrong - used for backward compatibility.
- * Will be replaced later.
- *
- * @param event the event type
- * @param p_data the event data
- * @return true if the processing was completed, otherwise false
- */
- virtual bool ProcessEvent(uint32_t event, void* p_data) = 0;
-
- /**
- * Get the State ID.
- *
- * @return the State ID
- */
- int StateId() const { return state_id_; }
-
- protected:
- /**
- * Called when a state is entered.
- */
- virtual void OnEnter() {}
-
- /**
- * Called when a state is exited.
- */
- virtual void OnExit() {}
-
- /**
- * Transition the State Machine to a new state.
- *
- * @param dest_state_id the state ID to transition to. It must be one
- * of the unique state IDs when the corresponding state was created.
- */
- void TransitionTo(int dest_state_id) { sm_.TransitionTo(dest_state_id); }
-
- /**
- * Transition the State Machine to a new state.
- *
- * @param dest_state the state to transition to. It cannot be nullptr.
- */
- void TransitionTo(BtifStateMachine::State* dest_state) {
- sm_.TransitionTo(dest_state);
- }
-
- private:
- BtifStateMachine& sm_;
- int state_id_;
- };
-
- BtifStateMachine()
- : initial_state_(nullptr),
- previous_state_(nullptr),
- current_state_(nullptr) {}
- ~BtifStateMachine() {
- for (auto& kv : states_) delete kv.second;
- }
-
- /**
- * Start the State Machine operation.
- */
- void Start() { TransitionTo(initial_state_); }
-
- /**
- * Quit the State Machine operation.
- */
- void Quit() { previous_state_ = current_state_ = nullptr; }
-
- /**
- * Get the current State ID.
- *
- * @return the current State ID
- */
- int StateId() const {
- if (current_state_ != nullptr) {
- return current_state_->StateId();
- }
- return kStateInvalid;
- }
-
- /**
- * Get the previous current State ID.
- *
- * @return the previous State ID
- */
- int PreviousStateId() const {
- if (previous_state_ != nullptr) {
- return previous_state_->StateId();
- }
- return kStateInvalid;
- }
-
- /**
- * Process an event.
- * TODO: The arguments are wrong - used for backward compatibility.
- * Will be replaced later.
- *
- * @param event the event type
- * @param p_data the event data
- * @return true if the processing was completed, otherwise false
- */
- bool ProcessEvent(uint32_t event, void* p_data) {
- if (current_state_ == nullptr) return false;
- return current_state_->ProcessEvent(event, p_data);
- }
-
- /**
- * Transition the State Machine to a new state.
- *
- * @param dest_state_id the state ID to transition to. It must be one
- * of the unique state IDs when the corresponding state was created.
- */
- void TransitionTo(int dest_state_id) {
- auto it = states_.find(dest_state_id);
-
- CHECK(it != states_.end()) << "Unknown State ID: " << dest_state_id;
- State* dest_state = it->second;
- TransitionTo(dest_state);
- }
-
- /**
- * Transition the State Machine to a new state.
- *
- * @param dest_state the state to transition to. It cannot be nullptr.
- */
- void TransitionTo(BtifStateMachine::State* dest_state) {
- if (current_state_ != nullptr) {
- current_state_->OnExit();
- }
- previous_state_ = current_state_;
- current_state_ = dest_state;
- current_state_->OnEnter();
- }
-
- /**
- * Add a state to the State Machine.
- * The state machine takes ownership on the state - i.e., the state will
- * be deleted by the State Machine itself.
- *
- * @param state the state to add
- */
- void AddState(State* state) {
- states_.insert(std::make_pair(state->StateId(), state));
- }
-
- /**
- * Set the initial state of the State Machine.
- *
- * @param initial_state the initial state
- */
- void SetInitialState(State* initial_state) { initial_state_ = initial_state; }
-
- private:
- State* initial_state_;
- State* previous_state_;
- State* current_state_;
- std::map<int, State*> states_;
-};
-
-#endif // BTIF_STATE_MACHINE_H
diff --git a/btif/include/btif_storage.h b/btif/include/btif_storage.h
index 07d29c8..1c1163d 100644
--- a/btif/include/btif_storage.h
+++ b/btif/include/btif_storage.h
@@ -99,6 +99,32 @@
/*******************************************************************************
*
+ * Function btif_storage_get_io_caps
+ *
+ * Description BTIF storage API - Fetches the local Input/Output
+ * capabilities of the device.
+ *
+ * Returns Returns local IO Capability of device. If not stored,
+ * returns BTM_LOCAL_IO_CAPS.
+ *
+ ******************************************************************************/
+uint8_t btif_storage_get_local_io_caps();
+
+/*******************************************************************************
+ *
+ * Function btif_storage_get_io_caps_ble
+ *
+ * Description BTIF storage API - Fetches the local Input/Output
+ * capabilities of the BLE device.
+ *
+ * Returns Returns local IO Capability of BLE device. If not stored,
+ * returns BTM_LOCAL_IO_CAPS_BLE.
+ *
+ ******************************************************************************/
+uint8_t btif_storage_get_local_io_caps_ble();
+
+/*******************************************************************************
+ *
* Function btif_storage_add_remote_device
*
* Description BTIF storage API - Adds a newly discovered device to
@@ -125,7 +151,7 @@
*
******************************************************************************/
bt_status_t btif_storage_add_bonded_device(RawAddress* remote_bd_addr,
- LINK_KEY link_key, uint8_t key_type,
+ LinkKey link_key, uint8_t key_type,
uint8_t pin_length);
/*******************************************************************************
@@ -201,11 +227,14 @@
/** Deletes the bonded hearing aid device info from NVRAM */
void btif_storage_remove_hearing_aid(const RawAddress& address);
-/** Add the hearing aid device to white list */
-void btif_storage_add_hearing_aid_to_white_list(const RawAddress& address);
+/** Set/Unset the hearing aid device HEARING_AID_IS_WHITE_LISTED flag. */
+void btif_storage_set_hearing_aid_white_list(const RawAddress& address,
+ bool add_to_whitelist);
-/** Remove the hearing aid device from white list */
-void btif_storage_remove_hearing_aid_white_list(const RawAddress& address);
+/** Get the hearing aid device properties. */
+bool btif_storage_get_hearing_aid_prop(
+ const RawAddress& address, uint8_t* capabilities, uint64_t* hi_sync_id,
+ uint16_t* render_delay, uint16_t* preparation_delay, uint16_t* codecs);
/*******************************************************************************
*
@@ -220,6 +249,8 @@
******************************************************************************/
bool btif_storage_is_restricted_device(const RawAddress* remote_bd_addr);
+int btif_storage_get_num_bonded_devices(void);
+
bt_status_t btif_storage_add_ble_bonding_key(RawAddress* remote_bd_addr,
const uint8_t* key,
uint8_t key_type,
@@ -229,13 +260,13 @@
uint8_t* key_value,
int key_length);
-bt_status_t btif_storage_add_ble_local_key(char* key, uint8_t key_type,
- uint8_t key_length);
+bt_status_t btif_storage_add_ble_local_key(const Octet16& key,
+ uint8_t key_type);
bt_status_t btif_storage_remove_ble_bonding_keys(
const RawAddress* remote_bd_addr);
bt_status_t btif_storage_remove_ble_local_keys(void);
-bt_status_t btif_storage_get_ble_local_key(uint8_t key_type, char* key_value,
- int key_len);
+bt_status_t btif_storage_get_ble_local_key(uint8_t key_type,
+ Octet16* key_value);
bt_status_t btif_storage_get_remote_addr_type(const RawAddress* remote_bd_addr,
int* addr_type);
diff --git a/btif/src/bluetooth.cc b/btif/src/bluetooth.cc
index 6e86ce7..1faca2d 100644
--- a/btif/src/bluetooth.cc
+++ b/btif/src/bluetooth.cc
@@ -40,20 +40,20 @@
#include <hardware/bt_hearing_aid.h>
#include <hardware/bt_hf_client.h>
#include <hardware/bt_hh.h>
-#include <hardware/bt_hl.h>
#include <hardware/bt_mce.h>
#include <hardware/bt_pan.h>
#include <hardware/bt_rc.h>
#include <hardware/bt_sdp.h>
#include <hardware/bt_sock.h>
-#include "avrcp_service.h"
#include "bt_utils.h"
#include "bta/include/bta_hearing_aid_api.h"
#include "bta/include/bta_hf_client_api.h"
+#include "btif/avrcp/avrcp_service.h"
#include "btif_a2dp.h"
#include "btif_api.h"
#include "btif_av.h"
+#include "btif_bqr.h"
#include "btif_config.h"
#include "btif_debug.h"
#include "btif_debug_btsnoop.h"
@@ -62,18 +62,17 @@
#include "btif_storage.h"
#include "btsnoop.h"
#include "btsnoop_mem.h"
+#include "common/address_obfuscator.h"
+#include "common/metrics.h"
#include "device/include/interop.h"
#include "osi/include/alarm.h"
#include "osi/include/allocation_tracker.h"
#include "osi/include/log.h"
-#include "osi/include/metrics.h"
#include "osi/include/osi.h"
#include "osi/include/wakelock.h"
+#include "stack/gatt/connection_manager.h"
#include "stack_manager.h"
-/* Test interface includes */
-#include "mca_api.h"
-
using bluetooth::hearing_aid::HearingAidInterface;
/*******************************************************************************
@@ -100,8 +99,6 @@
extern const bthh_interface_t* btif_hh_get_interface();
/* hid device profile */
extern const bthd_interface_t* btif_hd_get_interface();
-/* health device profile */
-extern const bthl_interface_t* btif_hl_get_interface();
/*pan*/
extern const btpan_interface_t* btif_pan_get_interface();
/*map client*/
@@ -117,9 +114,6 @@
/*Hearing Aid client*/
extern HearingAidInterface* btif_hearing_aid_get_interface();
-/* List all test interface here */
-extern const btmcap_test_interface_t* stack_mcap_get_interface();
-
/*******************************************************************************
* Functions
******************************************************************************/
@@ -323,13 +317,15 @@
osi_allocator_debug_dump(fd);
alarm_debug_dump(fd);
HearingAid::DebugDump(fd);
+ connection_manager::dump(fd);
+ bluetooth::bqr::DebugDump(fd);
#if (BTSNOOP_MEM == TRUE)
btif_debug_btsnoop_dump(fd);
#endif
}
static void dumpMetrics(std::string* output) {
- system_bt_osi::BluetoothMetricsLogger::GetInstance()->WriteString(output);
+ bluetooth::common::BluetoothMetricsLogger::GetInstance()->WriteString(output);
}
static const void* get_profile_interface(const char* profile_id) {
@@ -363,9 +359,6 @@
if (is_profile(profile_id, BT_PROFILE_HIDDEV_ID))
return btif_hd_get_interface();
- if (is_profile(profile_id, BT_PROFILE_HEALTH_ID))
- return btif_hl_get_interface();
-
if (is_profile(profile_id, BT_PROFILE_SDP_CLIENT_ID))
return btif_sdp_get_interface();
@@ -378,9 +371,6 @@
if (is_profile(profile_id, BT_PROFILE_AV_RC_CTRL_ID))
return btif_rc_ctrl_get_interface();
- if (is_profile(profile_id, BT_TEST_INTERFACE_MCAP_ID))
- return stack_mcap_get_interface();
-
if (is_profile(profile_id, BT_PROFILE_HEARING_AID_ID))
return btif_hearing_aid_get_interface();
return NULL;
@@ -451,6 +441,11 @@
return bluetooth::avrcp::AvrcpService::GetServiceInterface();
}
+static std::string obfuscate_address(const RawAddress& address) {
+ return bluetooth::common::AddressObfuscator::GetInstance()->Obfuscate(
+ address);
+}
+
EXPORT_SYMBOL bt_interface_t bluetoothInterface = {
sizeof(bluetoothInterface),
init,
@@ -486,4 +481,5 @@
interop_database_clear,
interop_database_add,
get_avrcp_service,
+ obfuscate_address,
};
diff --git a/btif/src/btif_a2dp.cc b/btif/src/btif_a2dp.cc
index 86485d4..e2d6132 100644
--- a/btif/src/btif_a2dp.cc
+++ b/btif/src/btif_a2dp.cc
@@ -22,6 +22,7 @@
#include <stdbool.h>
#include "audio_a2dp_hw/include/audio_a2dp_hw.h"
+#include "audio_hal_interface/a2dp_encoding.h"
#include "bt_common.h"
#include "bta_av_api.h"
#include "btif_a2dp.h"
@@ -45,69 +46,65 @@
}
}
-bool btif_a2dp_on_started(const RawAddress& peer_addr,
- tBTA_AV_START* p_av_start, bool pending_start) {
- bool ack = false;
-
- LOG_INFO(LOG_TAG,
- "%s: ## ON A2DP STARTED ## peer %s pending_start:%s p_av_start:%p",
- __func__, peer_addr.ToString().c_str(),
- logbool(pending_start).c_str(), p_av_start);
+bool btif_a2dp_on_started(const RawAddress& peer_addr, tBTA_AV_START* p_av_start) {
+ LOG(INFO) << __func__ << ": ## ON A2DP STARTED ## peer " << peer_addr << " p_av_start:" << p_av_start;
if (p_av_start == NULL) {
- /* ack back a local start request */
-
- if (!btif_av_is_a2dp_offload_enabled()) {
- btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
- return true;
- } else if (bluetooth::headset::IsCallIdle()) {
- btif_av_stream_start_offload();
+ tA2DP_CTRL_ACK status = A2DP_CTRL_ACK_SUCCESS;
+ if (!bluetooth::headset::IsCallIdle()) {
+ LOG(ERROR) << __func__ << ": peer " << peer_addr << " call in progress, do not start A2DP stream";
+ status = A2DP_CTRL_ACK_INCALL_FAILURE;
+ }
+ /* just ack back a local start request, do not start the media encoder since
+ * this is not for BTA_AV_START_EVT. */
+ if (bluetooth::audio::a2dp::is_hal_2_0_enabled()) {
+ bluetooth::audio::a2dp::ack_stream_started(status);
+ } else if (btif_av_is_a2dp_offload_enabled()) {
+ btif_a2dp_audio_on_started(status);
} else {
- LOG_ERROR(LOG_TAG, "%s: peer %s call in progress, do not start offload",
- __func__, peer_addr.ToString().c_str());
- btif_a2dp_audio_on_started(A2DP_CTRL_ACK_INCALL_FAILURE);
+ btif_a2dp_command_ack(status);
}
return true;
}
- LOG_INFO(LOG_TAG,
- "%s: peer %s pending_start:%s status:%d suspending:%s initiator:%s",
- __func__, peer_addr.ToString().c_str(),
- logbool(pending_start).c_str(), p_av_start->status,
- logbool(p_av_start->suspending).c_str(),
- logbool(p_av_start->initiator).c_str());
+ LOG(INFO) << __func__ << ": peer " << peer_addr << " status:" << +p_av_start->status
+ << " suspending:" << logbool(p_av_start->suspending) << " initiator:" << logbool(p_av_start->initiator);
if (p_av_start->status == BTA_AV_SUCCESS) {
- if (!p_av_start->suspending) {
- if (p_av_start->initiator) {
- if (pending_start) {
- if (btif_av_is_a2dp_offload_enabled()) {
- btif_av_stream_start_offload();
- } else {
- btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
- }
- ack = true;
- }
- } else {
- // We were started remotely
- if (btif_av_is_a2dp_offload_enabled()) {
- btif_av_stream_start_offload();
- }
- }
-
- /* media task is autostarted upon a2dp audiopath connection */
+ if (p_av_start->suspending) {
+ LOG(WARNING) << __func__ << ": peer " << peer_addr << " A2DP is suspending and ignores the started event";
+ return false;
}
- } else if (pending_start) {
- LOG_ERROR(LOG_TAG, "%s: peer %s A2DP start request failed: status = %d",
- __func__, peer_addr.ToString().c_str(), p_av_start->status);
if (btif_av_is_a2dp_offload_enabled()) {
+ btif_av_stream_start_offload();
+ } else if (bluetooth::audio::a2dp::is_hal_2_0_enabled()) {
+ if (btif_av_get_peer_sep() == AVDT_TSEP_SNK) {
+ /* Start the media encoder to do the SW audio stream */
+ btif_a2dp_source_start_audio_req();
+ }
+ if (p_av_start->initiator) {
+ bluetooth::audio::a2dp::ack_stream_started(A2DP_CTRL_ACK_SUCCESS);
+ return true;
+ }
+ } else {
+ if (p_av_start->initiator) {
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+ return true;
+ }
+ /* media task is auto-started upon UIPC connection of a2dp audiopath */
+ }
+ } else if (p_av_start->initiator) {
+ LOG(ERROR) << __func__ << ": peer " << peer_addr << " A2DP start request failed: status = " << +p_av_start->status;
+ if (bluetooth::audio::a2dp::is_hal_2_0_enabled()) {
+ bluetooth::audio::a2dp::ack_stream_started(A2DP_CTRL_ACK_FAILURE);
+ } else if (btif_av_is_a2dp_offload_enabled()) {
btif_a2dp_audio_on_started(p_av_start->status);
} else {
btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
}
- ack = true;
+ return true;
}
- return ack;
+ return false;
}
void btif_a2dp_on_stopped(tBTA_AV_SUSPEND* p_av_suspend) {
@@ -118,7 +115,8 @@
btif_a2dp_sink_on_stopped(p_av_suspend);
return;
}
- if (!btif_av_is_a2dp_offload_enabled()) {
+ if (bluetooth::audio::a2dp::is_hal_2_0_enabled() ||
+ !btif_av_is_a2dp_offload_enabled()) {
btif_a2dp_source_on_stopped(p_av_suspend);
} else if (p_av_suspend != NULL) {
btif_a2dp_audio_on_stopped(p_av_suspend->status);
@@ -128,13 +126,14 @@
void btif_a2dp_on_suspended(tBTA_AV_SUSPEND* p_av_suspend) {
LOG_INFO(LOG_TAG, "%s: ## ON A2DP SUSPENDED ## p_av_suspend=%p", __func__,
p_av_suspend);
- if (!btif_av_is_a2dp_offload_enabled()) {
- if (btif_av_get_peer_sep() == AVDT_TSEP_SRC) {
- btif_a2dp_sink_on_suspended(p_av_suspend);
- } else {
- btif_a2dp_source_on_suspended(p_av_suspend);
- }
- } else {
+ if (btif_av_get_peer_sep() == AVDT_TSEP_SRC) {
+ btif_a2dp_sink_on_suspended(p_av_suspend);
+ return;
+ }
+ if (bluetooth::audio::a2dp::is_hal_2_0_enabled() ||
+ !btif_av_is_a2dp_offload_enabled()) {
+ btif_a2dp_source_on_suspended(p_av_suspend);
+ } else if (p_av_suspend != NULL) {
btif_a2dp_audio_on_suspended(p_av_suspend->status);
}
}
@@ -161,7 +160,6 @@
break;
}
if (btif_av_is_a2dp_offload_enabled()) {
- btif_a2dp_audio_on_started(status);
if (ack != BTA_AV_SUCCESS && btif_av_stream_started_ready()) {
// Offload request will return with failure from btif_av sm if
// suspend is triggered for remote start. Disconnect only if SoC
@@ -170,8 +168,12 @@
peer_addr.ToString().c_str());
btif_av_src_disconnect_sink(peer_addr);
}
+ }
+ if (bluetooth::audio::a2dp::is_hal_2_0_enabled()) {
+ bluetooth::audio::a2dp::ack_stream_started(ack);
} else {
btif_a2dp_command_ack(ack);
+ btif_a2dp_audio_on_started(status);
}
}
diff --git a/btif/src/btif_a2dp_audio_interface.cc b/btif/src/btif_a2dp_audio_interface.cc
index 7343bbe..026baa1 100644
--- a/btif/src/btif_a2dp_audio_interface.cc
+++ b/btif/src/btif_a2dp_audio_interface.cc
@@ -40,11 +40,13 @@
#include "btif_av.h"
#include "btif_av_co.h"
#include "btif_hf.h"
-#include "osi/include/metrics.h"
+#include "common/metrics.h"
+#include "common/time_util.h"
#include "osi/include/osi.h"
+#include "stack/include/btu.h"
-using system_bt_osi::A2dpSessionMetrics;
-using system_bt_osi::BluetoothMetricsLogger;
+using bluetooth::common::A2dpSessionMetrics;
+using bluetooth::common::BluetoothMetricsLogger;
using android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioOffload;
using android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioHost;
@@ -107,11 +109,11 @@
}
void LogAudioStart() {
std::lock_guard<std::recursive_mutex> lock(lock_);
- audio_start_time_ms_ = time_get_os_boottime_ms();
+ audio_start_time_ms_ = bluetooth::common::time_get_os_boottime_ms();
}
void LogAudioStop() {
std::lock_guard<std::recursive_mutex> lock(lock_);
- audio_stop_time_ms_ = time_get_os_boottime_ms();
+ audio_stop_time_ms_ = bluetooth::common::time_get_os_boottime_ms();
}
void LogAudioStopMetricsAndReset() {
std::lock_guard<std::recursive_mutex> lock(lock_);
@@ -135,15 +137,15 @@
class BluetoothAudioHost : public IBluetoothAudioHost {
public:
- Return<void> startStream() {
+ Return<void> startStream() override {
btif_a2dp_audio_send_start_req();
return Void();
}
- Return<void> suspendStream() {
+ Return<void> suspendStream() override {
btif_a2dp_audio_send_suspend_req();
return Void();
}
- Return<void> stopStream() {
+ Return<void> stopStream() override {
btif_a2dp_audio_send_stop_req();
return Void();
}
@@ -158,13 +160,13 @@
class BluetoothAudioDeathRecipient : public hidl_death_recipient {
public:
- virtual void serviceDied(
+ void serviceDied(
uint64_t /*cookie*/,
- const wp<::android::hidl::base::V1_0::IBase>& /*who*/) {
+ const wp<::android::hidl::base::V1_0::IBase>& /*who*/) override {
LOG_ERROR(LOG_TAG, "%s", __func__);
// Restart the session on the correct thread
- do_in_bta_thread(FROM_HERE,
- base::Bind(&btif_a2dp_audio_interface_restart_session));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(&btif_a2dp_audio_interface_restart_session));
}
};
sp<BluetoothAudioDeathRecipient> bluetoothAudioDeathRecipient =
@@ -299,7 +301,7 @@
void btif_a2dp_audio_interface_start_session() {
LOG_INFO(LOG_TAG, "%s", __func__);
BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
- system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
+ bluetooth::common::CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
a2dp_offload_audio_stats.Reset();
btif_a2dp_audio_interface_init();
CHECK(btAudio != nullptr);
@@ -313,7 +315,7 @@
LOG_INFO(LOG_TAG, "%s", __func__);
a2dp_offload_audio_stats.LogAudioStopMetricsAndReset();
BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
- system_bt_osi::DISCONNECT_REASON_UNKNOWN, 0);
+ bluetooth::common::DISCONNECT_REASON_UNKNOWN, 0);
a2dp_offload_audio_stats.Reset();
if (btAudio == nullptr) return;
auto ret = btAudio->endSession();
@@ -339,6 +341,9 @@
LOG_INFO(LOG_TAG, "%s: status = %d", __func__, status);
if (btAudio != nullptr) {
if (a2dp_cmd_pending == A2DP_CTRL_CMD_START) {
+ if (status != A2DP_CTRL_ACK_PENDING) {
+ a2dp_cmd_pending = A2DP_CTRL_CMD_NONE;
+ }
LOG_INFO(LOG_TAG, "%s: calling method onStarted", __func__);
auto hal_status = mapToStatus(status);
btAudio->streamStarted(hal_status);
@@ -353,6 +358,9 @@
LOG_INFO(LOG_TAG, "%s: status = %d", __func__, status);
if (btAudio != nullptr) {
if (a2dp_cmd_pending == A2DP_CTRL_CMD_SUSPEND) {
+ if (status != A2DP_CTRL_ACK_PENDING) {
+ a2dp_cmd_pending = A2DP_CTRL_CMD_NONE;
+ }
LOG_INFO(LOG_TAG, "calling method onSuspended");
auto hal_status = mapToStatus(status);
btAudio->streamSuspended(hal_status);
@@ -366,6 +374,7 @@
void btif_a2dp_audio_on_stopped(tBTA_AV_STATUS status) {
LOG_INFO(LOG_TAG, "%s: status = %d", __func__, status);
if (btAudio != nullptr && a2dp_cmd_pending == A2DP_CTRL_CMD_START) {
+ a2dp_cmd_pending = A2DP_CTRL_CMD_NONE;
LOG_INFO(LOG_TAG, "%s: Remote disconnected when start under progress",
__func__);
btAudio->streamStarted(mapToStatus(A2DP_CTRL_ACK_DISCONNECT_IN_PROGRESS));
@@ -418,7 +427,6 @@
uint8_t btif_a2dp_audio_process_request(uint8_t cmd) {
LOG_INFO(LOG_TAG, "%s: cmd: %s", __func__,
audio_a2dp_hw_dump_ctrl_event((tA2DP_CTRL_CMD)cmd));
- a2dp_cmd_pending = cmd;
uint8_t status;
switch (cmd) {
case A2DP_CTRL_CMD_START:
@@ -461,7 +469,7 @@
APPL_TRACE_WARNING("%s: A2DP command %s while AV stream is not ready",
__func__,
audio_a2dp_hw_dump_ctrl_event((tA2DP_CTRL_CMD)cmd));
- return A2DP_CTRL_ACK_FAILURE;
+ status = A2DP_CTRL_ACK_FAILURE;
break;
case A2DP_CTRL_CMD_STOP:
@@ -472,7 +480,7 @@
break;
}
btif_av_stream_stop(RawAddress::kEmpty);
- return A2DP_CTRL_ACK_SUCCESS;
+ status = A2DP_CTRL_ACK_SUCCESS;
break;
case A2DP_CTRL_CMD_SUSPEND:
@@ -502,5 +510,10 @@
}
LOG_INFO(LOG_TAG, "a2dp-ctrl-cmd : %s DONE returning status %d",
audio_a2dp_hw_dump_ctrl_event((tA2DP_CTRL_CMD)cmd), status);
+ if (status == A2DP_CTRL_ACK_PENDING) {
+ a2dp_cmd_pending = cmd;
+ } else {
+ a2dp_cmd_pending = A2DP_CTRL_CMD_NONE;
+ }
return status;
}
diff --git a/btif/src/btif_a2dp_audio_interface_linux.cc b/btif/src/btif_a2dp_audio_interface_linux.cc
new file mode 100644
index 0000000..b5a0e19
--- /dev/null
+++ b/btif/src/btif_a2dp_audio_interface_linux.cc
@@ -0,0 +1,37 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2018 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 "btif_a2dp_audio_interface.h"
+
+#include <base/logging.h>
+
+void btif_a2dp_audio_on_started(tBTA_AV_STATUS status) {
+ LOG(FATAL) << "Unimplemented yet";
+}
+void btif_a2dp_audio_on_stopped(tBTA_AV_STATUS status) {
+ LOG(FATAL) << "Unimplemented yet";
+}
+void btif_a2dp_audio_on_suspended(tBTA_AV_STATUS status) {
+ LOG(FATAL) << "Unimplemented yet";
+}
+void btif_a2dp_audio_interface_start_session(void) {
+ LOG(FATAL) << "Unimplemented yet";
+}
+void btif_a2dp_audio_interface_end_session(void) {
+ LOG(FATAL) << "Unimplemented yet";
+}
diff --git a/btif/src/btif_a2dp_control.cc b/btif/src/btif_a2dp_control.cc
index fb62480..26b7f02 100644
--- a/btif/src/btif_a2dp_control.cc
+++ b/btif/src/btif_a2dp_control.cc
@@ -48,7 +48,7 @@
/* We can have max one command pending */
static tA2DP_CTRL_CMD a2dp_cmd_pending = A2DP_CTRL_CMD_NONE;
-std::unique_ptr<tUIPC_STATE> a2dp_uipc;
+std::unique_ptr<tUIPC_STATE> a2dp_uipc = nullptr;
void btif_a2dp_control_init(void) {
a2dp_uipc = UIPC_Init();
@@ -57,7 +57,9 @@
void btif_a2dp_control_cleanup(void) {
/* This calls blocks until UIPC is fully closed */
- UIPC_Close(*a2dp_uipc, UIPC_CH_ID_ALL);
+ if (a2dp_uipc != nullptr) {
+ UIPC_Close(*a2dp_uipc, UIPC_CH_ID_ALL);
+ }
}
static void btif_a2dp_recv_ctrl_data(void) {
@@ -419,7 +421,9 @@
a2dp_cmd_pending = A2DP_CTRL_CMD_NONE;
/* Acknowledge start request */
- UIPC_Send(*a2dp_uipc, UIPC_CH_ID_AV_CTRL, 0, &ack, sizeof(ack));
+ if (a2dp_uipc != nullptr) {
+ UIPC_Send(*a2dp_uipc, UIPC_CH_ID_AV_CTRL, 0, &ack, sizeof(ack));
+ }
}
void btif_a2dp_control_log_bytes_read(uint32_t bytes_read) {
diff --git a/btif/src/btif_a2dp_sink.cc b/btif/src/btif_a2dp_sink.cc
index c17b33a..bb1bc49 100644
--- a/btif/src/btif_a2dp_sink.cc
+++ b/btif/src/btif_a2dp_sink.cc
@@ -20,8 +20,12 @@
#define LOG_TAG "bt_btif_a2dp_sink"
#include <atomic>
+#include <cstdio>
#include <cstring>
#include <mutex>
+#include <string>
+
+#include <base/bind.h>
#include "bt_common.h"
#include "btif_a2dp.h"
@@ -30,11 +34,12 @@
#include "btif_av_co.h"
#include "btif_avrcp_audio_track.h"
#include "btif_util.h"
+#include "common/message_loop_thread.h"
#include "osi/include/fixed_queue.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
-#include "osi/include/thread.h"
+using bluetooth::common::MessageLoopThread;
using LockGuard = std::lock_guard<std::mutex>;
/**
@@ -73,47 +78,77 @@
} tBTIF_MEDIA_SINK_FOCUS_UPDATE;
/* BTIF A2DP Sink control block */
-typedef struct {
- thread_t* worker_thread;
- fixed_queue_t* cmd_msg_queue;
+class BtifA2dpSinkControlBlock {
+ public:
+ explicit BtifA2dpSinkControlBlock(const std::string& thread_name)
+ : worker_thread(thread_name),
+ rx_audio_queue(nullptr),
+ rx_flush(false),
+ decode_alarm(nullptr),
+ sample_rate(0),
+ channel_count(0),
+ rx_focus_state(BTIF_A2DP_SINK_FOCUS_NOT_GRANTED),
+ audio_track(nullptr),
+ decoder_interface(nullptr) {}
+
+ void Reset() {
+ if (audio_track != nullptr) {
+ BtifAvrcpAudioTrackStop(audio_track);
+ BtifAvrcpAudioTrackDelete(audio_track);
+ }
+ audio_track = nullptr;
+ fixed_queue_free(rx_audio_queue, nullptr);
+ rx_audio_queue = nullptr;
+ alarm_free(decode_alarm);
+ decode_alarm = nullptr;
+ rx_flush = false;
+ rx_focus_state = BTIF_A2DP_SINK_FOCUS_NOT_GRANTED;
+ sample_rate = 0;
+ channel_count = 0;
+ decoder_interface = nullptr;
+ }
+
+ MessageLoopThread worker_thread;
fixed_queue_t* rx_audio_queue;
bool rx_flush; /* discards any incoming data when true */
alarm_t* decode_alarm;
tA2DP_SAMPLE_RATE sample_rate;
+ tA2DP_BITS_PER_SAMPLE bits_per_sample;
tA2DP_CHANNEL_COUNT channel_count;
btif_a2dp_sink_focus_state_t rx_focus_state; /* audio focus state */
void* audio_track;
const tA2DP_DECODER_INTERFACE* decoder_interface;
-} tBTIF_A2DP_SINK_CB;
+};
// Mutex for below data structures.
static std::mutex g_mutex;
-static tBTIF_A2DP_SINK_CB btif_a2dp_sink_cb;
+static BtifA2dpSinkControlBlock btif_a2dp_sink_cb("bt_a2dp_sink_worker_thread");
static std::atomic<int> btif_a2dp_sink_state{BTIF_A2DP_SINK_STATE_OFF};
-static void btif_a2dp_sink_init_delayed(void* context);
-static void btif_a2dp_sink_startup_delayed(void* context);
-static void btif_a2dp_sink_start_session_delayed(void* context);
-static void btif_a2dp_sink_end_session_delayed(void* context);
-static void btif_a2dp_sink_shutdown_delayed(void* context);
-static void btif_a2dp_sink_cleanup_delayed(void* context);
-static void btif_a2dp_sink_command_ready(fixed_queue_t* queue, void* context);
-static void btif_a2dp_sink_audio_handle_stop_decoding(void);
+static void btif_a2dp_sink_init_delayed();
+static void btif_a2dp_sink_startup_delayed();
+static void btif_a2dp_sink_start_session_delayed(
+ std::promise<void> peer_ready_promise);
+static void btif_a2dp_sink_end_session_delayed();
+static void btif_a2dp_sink_shutdown_delayed();
+static void btif_a2dp_sink_cleanup_delayed();
+static void btif_a2dp_sink_command_ready(BT_HDR* p_msg);
+static void btif_a2dp_sink_audio_handle_stop_decoding();
static void btif_decode_alarm_cb(void* context);
-static void btif_a2dp_sink_audio_handle_start_decoding(void);
-static void btif_a2dp_sink_avk_handle_timer(UNUSED_ATTR void* context);
-static void btif_a2dp_sink_audio_rx_flush_req(void);
+static void btif_a2dp_sink_audio_handle_start_decoding();
+static void btif_a2dp_sink_avk_handle_timer();
+static void btif_a2dp_sink_audio_rx_flush_req();
/* Handle incoming media packets A2DP SINK streaming */
static void btif_a2dp_sink_handle_inc_media(BT_HDR* p_msg);
static void btif_a2dp_sink_decoder_update_event(
tBTIF_MEDIA_SINK_DECODER_UPDATE* p_buf);
-static void btif_a2dp_sink_clear_track_event(void);
+static void btif_a2dp_sink_clear_track_event();
static void btif_a2dp_sink_set_focus_state_event(
btif_a2dp_sink_focus_state_t state);
-static void btif_a2dp_sink_audio_rx_flush_event(void);
-static void btif_a2dp_sink_clear_track_event_req(void);
+static void btif_a2dp_sink_audio_rx_flush_event();
+static void btif_a2dp_sink_clear_track_event_req();
UNUSED_ATTR static const char* dump_media_event(uint16_t event) {
switch (event) {
@@ -127,7 +162,7 @@
return "UNKNOWN A2DP SINK EVENT";
}
-bool btif_a2dp_sink_init(void) {
+bool btif_a2dp_sink_init() {
LOG_INFO(LOG_TAG, "%s", __func__);
LockGuard lock(g_mutex);
@@ -136,72 +171,75 @@
return false;
}
- memset(&btif_a2dp_sink_cb, 0, sizeof(btif_a2dp_sink_cb));
+ btif_a2dp_sink_cb.Reset();
btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_STARTING_UP;
/* Start A2DP Sink media task */
- btif_a2dp_sink_cb.worker_thread = thread_new("btif_a2dp_sink_worker_thread");
- if (btif_a2dp_sink_cb.worker_thread == NULL) {
+ btif_a2dp_sink_cb.worker_thread.StartUp();
+ if (!btif_a2dp_sink_cb.worker_thread.IsRunning()) {
LOG_ERROR(LOG_TAG, "%s: unable to start up media thread", __func__);
btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_OFF;
return false;
}
- btif_a2dp_sink_cb.rx_focus_state = BTIF_A2DP_SINK_FOCUS_NOT_GRANTED;
- btif_a2dp_sink_cb.audio_track = NULL;
btif_a2dp_sink_cb.rx_audio_queue = fixed_queue_new(SIZE_MAX);
- btif_a2dp_sink_cb.cmd_msg_queue = fixed_queue_new(SIZE_MAX);
- fixed_queue_register_dequeue(
- btif_a2dp_sink_cb.cmd_msg_queue,
- thread_get_reactor(btif_a2dp_sink_cb.worker_thread),
- btif_a2dp_sink_command_ready, NULL);
-
/* Schedule the rest of the operations */
- thread_post(btif_a2dp_sink_cb.worker_thread, btif_a2dp_sink_init_delayed,
- NULL);
-
+ if (!btif_a2dp_sink_cb.worker_thread.EnableRealTimeScheduling()) {
+ LOG(FATAL) << __func__
+ << ": Failed to increase A2DP decoder thread priority";
+ }
+ btif_a2dp_sink_cb.worker_thread.DoInThread(
+ FROM_HERE, base::BindOnce(btif_a2dp_sink_init_delayed));
return true;
}
-static void btif_a2dp_sink_init_delayed(UNUSED_ATTR void* context) {
+static void btif_a2dp_sink_init_delayed() {
LOG_INFO(LOG_TAG, "%s", __func__);
- raise_priority_a2dp(TASK_HIGH_MEDIA);
btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_RUNNING;
}
-bool btif_a2dp_sink_startup(void) {
+bool btif_a2dp_sink_startup() {
LOG_INFO(LOG_TAG, "%s", __func__);
- thread_post(btif_a2dp_sink_cb.worker_thread, btif_a2dp_sink_startup_delayed,
- NULL);
+ btif_a2dp_sink_cb.worker_thread.DoInThread(
+ FROM_HERE, base::BindOnce(btif_a2dp_sink_startup_delayed));
return true;
}
-static void btif_a2dp_sink_startup_delayed(UNUSED_ATTR void* context) {
+static void btif_a2dp_sink_startup_delayed() {
LOG_INFO(LOG_TAG, "%s", __func__);
LockGuard lock(g_mutex);
// Nothing to do
}
-bool btif_a2dp_sink_start_session(const RawAddress& peer_address) {
- LOG_INFO(LOG_TAG, "%s: peer_address=%s", __func__,
- peer_address.ToString().c_str());
- thread_post(btif_a2dp_sink_cb.worker_thread,
- btif_a2dp_sink_start_session_delayed, NULL);
- return true;
+bool btif_a2dp_sink_start_session(const RawAddress& peer_address,
+ std::promise<void> peer_ready_promise) {
+ LOG(INFO) << __func__ << ": peer_address=" << peer_address;
+ if (btif_a2dp_sink_cb.worker_thread.DoInThread(
+ FROM_HERE, base::BindOnce(btif_a2dp_sink_start_session_delayed,
+ std::move(peer_ready_promise)))) {
+ return true;
+ } else {
+ // cannot set promise but triggers crash
+ LOG(FATAL) << __func__ << ": peer_address=" << peer_address
+ << " fails to context switch";
+ return false;
+ }
}
-static void btif_a2dp_sink_start_session_delayed(UNUSED_ATTR void* context) {
- LOG_INFO(LOG_TAG, "%s", __func__);
+static void btif_a2dp_sink_start_session_delayed(
+ std::promise<void> peer_ready_promise) {
+ LOG(INFO) << __func__;
LockGuard lock(g_mutex);
+ peer_ready_promise.set_value();
// Nothing to do
}
bool btif_a2dp_sink_restart_session(const RawAddress& old_peer_address,
- const RawAddress& new_peer_address) {
- LOG_INFO(LOG_TAG, "%s: old_peer_address=%s new_peer_address=%s", __func__,
- old_peer_address.ToString().c_str(),
- new_peer_address.ToString().c_str());
+ const RawAddress& new_peer_address,
+ std::promise<void> peer_ready_promise) {
+ LOG(INFO) << __func__ << ": old_peer_address=" << old_peer_address
+ << " new_peer_address=" << new_peer_address;
CHECK(!new_peer_address.IsEmpty());
@@ -210,15 +248,17 @@
}
if (!bta_av_co_set_active_peer(new_peer_address)) {
- LOG_ERROR(LOG_TAG, "%s: Cannot stream audio: cannot set active peer to %s",
- __func__, new_peer_address.ToString().c_str());
+ LOG(ERROR) << __func__
+ << ": Cannot stream audio: cannot set active peer to "
+ << new_peer_address;
+ peer_ready_promise.set_value();
return false;
}
if (old_peer_address.IsEmpty()) {
btif_a2dp_sink_startup();
}
- btif_a2dp_sink_start_session(new_peer_address);
+ btif_a2dp_sink_start_session(new_peer_address, std::move(peer_ready_promise));
return true;
}
@@ -226,35 +266,33 @@
bool btif_a2dp_sink_end_session(const RawAddress& peer_address) {
LOG_INFO(LOG_TAG, "%s: peer_address=%s", __func__,
peer_address.ToString().c_str());
- thread_post(btif_a2dp_sink_cb.worker_thread,
- btif_a2dp_sink_end_session_delayed, NULL);
+ btif_a2dp_sink_cb.worker_thread.DoInThread(
+ FROM_HERE, base::BindOnce(btif_a2dp_sink_end_session_delayed));
return true;
}
-static void btif_a2dp_sink_end_session_delayed(UNUSED_ATTR void* context) {
+static void btif_a2dp_sink_end_session_delayed() {
LOG_INFO(LOG_TAG, "%s", __func__);
LockGuard lock(g_mutex);
// Nothing to do
}
-void btif_a2dp_sink_shutdown(void) {
+void btif_a2dp_sink_shutdown() {
LOG_INFO(LOG_TAG, "%s", __func__);
- thread_post(btif_a2dp_sink_cb.worker_thread, btif_a2dp_sink_shutdown_delayed,
- NULL);
+ btif_a2dp_sink_cb.worker_thread.DoInThread(
+ FROM_HERE, base::BindOnce(btif_a2dp_sink_shutdown_delayed));
}
-static void btif_a2dp_sink_shutdown_delayed(UNUSED_ATTR void* context) {
+static void btif_a2dp_sink_shutdown_delayed() {
LOG_INFO(LOG_TAG, "%s", __func__);
LockGuard lock(g_mutex);
// Nothing to do
}
-void btif_a2dp_sink_cleanup(void) {
+void btif_a2dp_sink_cleanup() {
LOG_INFO(LOG_TAG, "%s", __func__);
alarm_t* decode_alarm;
- fixed_queue_t* cmd_msg_queue;
- thread_t* worker_thread;
// Make sure the sink is shutdown
btif_a2dp_sink_shutdown();
@@ -269,47 +307,43 @@
btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_SHUTTING_DOWN;
decode_alarm = btif_a2dp_sink_cb.decode_alarm;
- btif_a2dp_sink_cb.decode_alarm = NULL;
-
- cmd_msg_queue = btif_a2dp_sink_cb.cmd_msg_queue;
- btif_a2dp_sink_cb.cmd_msg_queue = NULL;
-
- worker_thread = btif_a2dp_sink_cb.worker_thread;
- btif_a2dp_sink_cb.worker_thread = NULL;
+ btif_a2dp_sink_cb.decode_alarm = nullptr;
}
// Stop the timer
alarm_free(decode_alarm);
// Exit the thread
- fixed_queue_free(cmd_msg_queue, NULL);
- thread_post(worker_thread, btif_a2dp_sink_cleanup_delayed, NULL);
- thread_free(worker_thread);
+ btif_a2dp_sink_cb.worker_thread.DoInThread(
+ FROM_HERE, base::BindOnce(btif_a2dp_sink_cleanup_delayed));
+ btif_a2dp_sink_cb.worker_thread.ShutDown();
}
-static void btif_a2dp_sink_cleanup_delayed(UNUSED_ATTR void* context) {
+static void btif_a2dp_sink_cleanup_delayed() {
LOG_INFO(LOG_TAG, "%s", __func__);
LockGuard lock(g_mutex);
- fixed_queue_free(btif_a2dp_sink_cb.rx_audio_queue, NULL);
- btif_a2dp_sink_cb.rx_audio_queue = NULL;
+ fixed_queue_free(btif_a2dp_sink_cb.rx_audio_queue, nullptr);
+ btif_a2dp_sink_cb.rx_audio_queue = nullptr;
btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_OFF;
}
-tA2DP_SAMPLE_RATE btif_a2dp_sink_get_sample_rate(void) {
+tA2DP_SAMPLE_RATE btif_a2dp_sink_get_sample_rate() {
LockGuard lock(g_mutex);
return btif_a2dp_sink_cb.sample_rate;
}
-tA2DP_CHANNEL_COUNT btif_a2dp_sink_get_channel_count(void) {
+tA2DP_BITS_PER_SAMPLE btif_a2dp_sink_get_bits_per_sample() {
+ LockGuard lock(g_mutex);
+ return btif_a2dp_sink_cb.bits_per_sample;
+}
+
+tA2DP_CHANNEL_COUNT btif_a2dp_sink_get_channel_count() {
LockGuard lock(g_mutex);
return btif_a2dp_sink_cb.channel_count;
}
-static void btif_a2dp_sink_command_ready(fixed_queue_t* queue,
- UNUSED_ATTR void* context) {
- BT_HDR* p_msg = (BT_HDR*)fixed_queue_dequeue(queue);
-
+static void btif_a2dp_sink_command_ready(BT_HDR* p_msg) {
LOG_VERBOSE(LOG_TAG, "%s: event %d %s", __func__, p_msg->event,
dump_media_event(p_msg->event));
@@ -352,10 +386,11 @@
memcpy(p_buf->codec_info, p_codec_info, AVDT_CODEC_SIZE);
p_buf->hdr.event = BTIF_MEDIA_SINK_DECODER_UPDATE;
- fixed_queue_enqueue(btif_a2dp_sink_cb.cmd_msg_queue, p_buf);
+ btif_a2dp_sink_cb.worker_thread.DoInThread(
+ FROM_HERE, base::BindOnce(btif_a2dp_sink_command_ready, (BT_HDR*)p_buf));
}
-void btif_a2dp_sink_on_idle(void) {
+void btif_a2dp_sink_on_idle() {
LOG_INFO(LOG_TAG, "%s", __func__);
if (btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_OFF) return;
btif_a2dp_sink_audio_handle_stop_decoding();
@@ -374,7 +409,7 @@
btif_a2dp_sink_audio_handle_stop_decoding();
}
-static void btif_a2dp_sink_audio_handle_stop_decoding(void) {
+static void btif_a2dp_sink_audio_handle_stop_decoding() {
LOG_INFO(LOG_TAG, "%s", __func__);
alarm_t* old_alarm;
{
@@ -382,7 +417,7 @@
btif_a2dp_sink_cb.rx_flush = true;
btif_a2dp_sink_audio_rx_flush_req();
old_alarm = btif_a2dp_sink_cb.decode_alarm;
- btif_a2dp_sink_cb.decode_alarm = NULL;
+ btif_a2dp_sink_cb.decode_alarm = nullptr;
}
// Drop the lock here, btif_decode_alarm_cb may in the process of being called
@@ -401,13 +436,11 @@
static void btif_decode_alarm_cb(UNUSED_ATTR void* context) {
LockGuard lock(g_mutex);
- if (btif_a2dp_sink_cb.worker_thread != NULL) {
- thread_post(btif_a2dp_sink_cb.worker_thread,
- btif_a2dp_sink_avk_handle_timer, NULL);
- }
+ btif_a2dp_sink_cb.worker_thread.DoInThread(
+ FROM_HERE, base::BindOnce(btif_a2dp_sink_avk_handle_timer));
}
-static void btif_a2dp_sink_clear_track_event(void) {
+static void btif_a2dp_sink_clear_track_event() {
LOG_INFO(LOG_TAG, "%s", __func__);
LockGuard lock(g_mutex);
@@ -415,13 +448,13 @@
BtifAvrcpAudioTrackStop(btif_a2dp_sink_cb.audio_track);
BtifAvrcpAudioTrackDelete(btif_a2dp_sink_cb.audio_track);
#endif
- btif_a2dp_sink_cb.audio_track = NULL;
+ btif_a2dp_sink_cb.audio_track = nullptr;
}
// Must be called while locked.
-static void btif_a2dp_sink_audio_handle_start_decoding(void) {
+static void btif_a2dp_sink_audio_handle_start_decoding() {
LOG_INFO(LOG_TAG, "%s", __func__);
- if (btif_a2dp_sink_cb.decode_alarm != NULL)
+ if (btif_a2dp_sink_cb.decode_alarm != nullptr)
return; // Already started decoding
#ifndef OS_GENERIC
@@ -429,12 +462,12 @@
#endif
btif_a2dp_sink_cb.decode_alarm = alarm_new_periodic("btif.a2dp_sink_decode");
- if (btif_a2dp_sink_cb.decode_alarm == NULL) {
+ if (btif_a2dp_sink_cb.decode_alarm == nullptr) {
LOG_ERROR(LOG_TAG, "%s: unable to allocate decode alarm", __func__);
return;
}
alarm_set(btif_a2dp_sink_cb.decode_alarm, BTIF_SINK_MEDIA_TIME_TICK_MS,
- btif_decode_alarm_cb, NULL);
+ btif_decode_alarm_cb, nullptr);
}
static void btif_a2dp_sink_on_decode_complete(uint8_t* data, uint32_t len) {
@@ -452,13 +485,13 @@
return;
}
- CHECK(btif_a2dp_sink_cb.decoder_interface);
+ CHECK(btif_a2dp_sink_cb.decoder_interface != nullptr);
if (!btif_a2dp_sink_cb.decoder_interface->decode_packet(p_msg)) {
LOG_ERROR(LOG_TAG, "%s: decoding failed", __func__);
}
}
-static void btif_a2dp_sink_avk_handle_timer(UNUSED_ATTR void* context) {
+static void btif_a2dp_sink_avk_handle_timer() {
LockGuard lock(g_mutex);
BT_HDR* p_msg;
@@ -503,7 +536,7 @@
btif_a2dp_sink_cb.rx_flush = enable;
}
-static void btif_a2dp_sink_audio_rx_flush_event(void) {
+static void btif_a2dp_sink_audio_rx_flush_event() {
LOG_INFO(LOG_TAG, "%s", __func__);
LockGuard lock(g_mutex);
// Flush all received encoded audio buffers
@@ -524,6 +557,11 @@
LOG_ERROR(LOG_TAG, "%s: cannot get the track frequency", __func__);
return;
}
+ int bits_per_sample = A2DP_GetTrackBitsPerSample(p_buf->codec_info);
+ if (bits_per_sample == -1) {
+ LOG_ERROR(LOG_TAG, "%s: cannot get the bits per sample", __func__);
+ return;
+ }
int channel_count = A2DP_GetTrackChannelCount(p_buf->codec_info);
if (channel_count == -1) {
LOG_ERROR(LOG_TAG, "%s: cannot get the channel count", __func__);
@@ -535,13 +573,14 @@
return;
}
btif_a2dp_sink_cb.sample_rate = sample_rate;
+ btif_a2dp_sink_cb.bits_per_sample = bits_per_sample;
btif_a2dp_sink_cb.channel_count = channel_count;
btif_a2dp_sink_cb.rx_flush = false;
APPL_TRACE_DEBUG("%s: reset to Sink role", __func__);
btif_a2dp_sink_cb.decoder_interface = bta_av_co_get_decoder_interface();
- if (btif_a2dp_sink_cb.decoder_interface == NULL) {
+ if (btif_a2dp_sink_cb.decoder_interface == nullptr) {
LOG_ERROR(LOG_TAG, "%s: cannot stream audio: no source decoder interface",
__func__);
return;
@@ -556,11 +595,11 @@
APPL_TRACE_DEBUG("%s: create audio track", __func__);
btif_a2dp_sink_cb.audio_track =
#ifndef OS_GENERIC
- BtifAvrcpAudioTrackCreate(sample_rate, channel_type);
+ BtifAvrcpAudioTrackCreate(sample_rate, bits_per_sample, channel_type);
#else
NULL;
#endif
- if (btif_a2dp_sink_cb.audio_track == NULL) {
+ if (btif_a2dp_sink_cb.audio_track == nullptr) {
LOG_ERROR(LOG_TAG, "%s: track creation failed", __func__);
return;
}
@@ -595,7 +634,7 @@
return fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue);
}
-void btif_a2dp_sink_audio_rx_flush_req(void) {
+void btif_a2dp_sink_audio_rx_flush_req() {
LOG_INFO(LOG_TAG, "%s", __func__);
if (fixed_queue_is_empty(btif_a2dp_sink_cb.rx_audio_queue)) {
/* Queue is already empty */
@@ -604,7 +643,8 @@
BT_HDR* p_buf = reinterpret_cast<BT_HDR*>(osi_malloc(sizeof(BT_HDR)));
p_buf->event = BTIF_MEDIA_SINK_AUDIO_RX_FLUSH;
- fixed_queue_enqueue(btif_a2dp_sink_cb.cmd_msg_queue, p_buf);
+ btif_a2dp_sink_cb.worker_thread.DoInThread(
+ FROM_HERE, base::BindOnce(btif_a2dp_sink_command_ready, p_buf));
}
void btif_a2dp_sink_debug_dump(UNUSED_ATTR int fd) {
@@ -618,7 +658,8 @@
osi_malloc(sizeof(tBTIF_MEDIA_SINK_FOCUS_UPDATE)));
p_buf->focus_state = state;
p_buf->hdr.event = BTIF_MEDIA_SINK_SET_FOCUS_STATE;
- fixed_queue_enqueue(btif_a2dp_sink_cb.cmd_msg_queue, p_buf);
+ btif_a2dp_sink_cb.worker_thread.DoInThread(
+ FROM_HERE, base::BindOnce(btif_a2dp_sink_command_ready, (BT_HDR*)p_buf));
}
static void btif_a2dp_sink_set_focus_state_event(
@@ -646,10 +687,11 @@
#endif
}
-static void btif_a2dp_sink_clear_track_event_req(void) {
+static void btif_a2dp_sink_clear_track_event_req() {
LOG_INFO(LOG_TAG, "%s", __func__);
BT_HDR* p_buf = reinterpret_cast<BT_HDR*>(osi_malloc(sizeof(BT_HDR)));
p_buf->event = BTIF_MEDIA_SINK_CLEAR_TRACK;
- fixed_queue_enqueue(btif_a2dp_sink_cb.cmd_msg_queue, p_buf);
+ btif_a2dp_sink_cb.worker_thread.DoInThread(
+ FROM_HERE, base::BindOnce(btif_a2dp_sink_command_ready, p_buf));
}
diff --git a/btif/src/btif_a2dp_source.cc b/btif/src/btif_a2dp_source.cc
index 78e5a4e..9951ce1 100644
--- a/btif/src/btif_a2dp_source.cc
+++ b/btif/src/btif_a2dp_source.cc
@@ -30,6 +30,7 @@
#include <algorithm>
#include "audio_a2dp_hw/include/audio_a2dp_hw.h"
+#include "audio_hal_interface/a2dp_encoding.h"
#include "bt_common.h"
#include "bta_av_ci.h"
#include "btif_a2dp.h"
@@ -39,19 +40,19 @@
#include "btif_av.h"
#include "btif_av_co.h"
#include "btif_util.h"
+#include "common/message_loop_thread.h"
+#include "common/metrics.h"
+#include "common/repeating_timer.h"
+#include "common/time_util.h"
#include "osi/include/fixed_queue.h"
#include "osi/include/log.h"
-#include "osi/include/metrics.h"
#include "osi/include/osi.h"
-#include "osi/include/thread.h"
-#include "osi/include/time.h"
+#include "osi/include/wakelock.h"
#include "uipc.h"
-#include <condition_variable>
-#include <mutex>
-
-using system_bt_osi::BluetoothMetricsLogger;
-using system_bt_osi::A2dpSessionMetrics;
+using bluetooth::common::A2dpSessionMetrics;
+using bluetooth::common::BluetoothMetricsLogger;
+using bluetooth::common::RepeatingTimer;
extern std::unique_ptr<tUIPC_STATE> a2dp_uipc;
@@ -165,95 +166,6 @@
int codec_index = -1;
};
-class BtWorkerThread {
- public:
- BtWorkerThread(const std::string& thread_name)
- : thread_name_(thread_name),
- message_loop_(nullptr),
- run_loop_(nullptr),
- message_loop_thread_(nullptr),
- started_(false) {}
-
- void StartUp() {
- if (message_loop_thread_ != nullptr) {
- return; // Already started up
- }
- message_loop_thread_ = thread_new(thread_name_.c_str());
- CHECK(message_loop_thread_ != nullptr);
- started_ = false;
- thread_post(message_loop_thread_, &BtWorkerThread::RunThread, this);
- {
- // Block until run_loop_ is allocated and ready to run
- std::unique_lock<std::mutex> start_lock(start_up_mutex_);
- while (!started_) {
- start_up_cv_.wait(start_lock);
- }
- }
- }
-
- bool DoInThread(const tracked_objects::Location& from_here,
- const base::Closure& task) {
- if ((message_loop_ == nullptr) || !message_loop_->task_runner().get()) {
- LOG_ERROR(
- LOG_TAG,
- "%s: Dropping message for thread %s: message loop is not initialized",
- __func__, thread_name_.c_str());
- return false;
- }
- if (!message_loop_->task_runner()->PostTask(from_here, task)) {
- LOG_ERROR(LOG_TAG,
- "%s: Posting task to message loop for thread %s failed",
- __func__, thread_name_.c_str());
- return false;
- }
- return true;
- }
-
- void ShutDown() {
- if ((run_loop_ != nullptr) && (message_loop_ != nullptr)) {
- message_loop_->task_runner()->PostTask(FROM_HERE,
- run_loop_->QuitClosure());
- }
- thread_free(message_loop_thread_);
- message_loop_thread_ = nullptr;
- }
-
- private:
- static void RunThread(void* context) {
- auto wt = static_cast<BtWorkerThread*>(context);
- wt->Run();
- }
-
- void Run() {
- LOG_INFO(LOG_TAG, "%s: message loop for thread %s started", __func__,
- thread_name_.c_str());
- message_loop_ = new base::MessageLoop();
- run_loop_ = new base::RunLoop();
- {
- std::unique_lock<std::mutex> start_lock(start_up_mutex_);
- started_ = true;
- start_up_cv_.notify_all();
- }
- // Blocking util ShutDown() is called
- run_loop_->Run();
- delete message_loop_;
- message_loop_ = nullptr;
- delete run_loop_;
- run_loop_ = nullptr;
- LOG_INFO(LOG_TAG, "%s: message loop for thread %s finished", __func__,
- thread_name_.c_str());
- }
-
- std::string thread_name_;
- base::MessageLoop* message_loop_;
- base::RunLoop* run_loop_;
- thread_t* message_loop_thread_;
- // For start-up
- bool started_;
- std::mutex start_up_mutex_;
- std::condition_variable start_up_cv_;
-};
-
class BtifA2dpSource {
public:
enum RunState {
@@ -266,7 +178,6 @@
BtifA2dpSource()
: tx_audio_queue(nullptr),
tx_flush(false),
- media_alarm(nullptr),
encoder_interface(nullptr),
encoder_interval_ms(0),
state_(kStateOff) {}
@@ -275,8 +186,8 @@
fixed_queue_free(tx_audio_queue, nullptr);
tx_audio_queue = nullptr;
tx_flush = false;
- alarm_free(media_alarm);
- media_alarm = nullptr;
+ media_alarm.CancelAndWait();
+ wakelock_release();
encoder_interface = nullptr;
encoder_interval_ms = 0;
stats.Reset();
@@ -302,9 +213,9 @@
fixed_queue_t* tx_audio_queue;
bool tx_flush; /* Discards any outgoing data when true */
- alarm_t* media_alarm;
+ RepeatingTimer media_alarm;
const tA2DP_ENCODER_INTERFACE* encoder_interface;
- period_ms_t encoder_interval_ms; /* Local copy of the encoder interval */
+ uint64_t encoder_interval_ms; /* Local copy of the encoder interval */
BtifMediaStats stats;
BtifMediaStats accumulated_stats;
@@ -312,13 +223,14 @@
BtifA2dpSource::RunState state_;
};
-static BtWorkerThread btif_a2dp_source_thread("btif_a2dp_source_thread");
+static bluetooth::common::MessageLoopThread btif_a2dp_source_thread(
+ "bt_a2dp_source_worker_thread");
static BtifA2dpSource btif_a2dp_source_cb;
static void btif_a2dp_source_init_delayed(void);
static void btif_a2dp_source_startup_delayed(void);
static void btif_a2dp_source_start_session_delayed(
- const RawAddress& peer_address);
+ const RawAddress& peer_address, std::promise<void> start_session_promise);
static void btif_a2dp_source_end_session_delayed(
const RawAddress& peer_address);
static void btif_a2dp_source_shutdown_delayed(void);
@@ -338,7 +250,6 @@
static void btif_a2dp_source_audio_feeding_update_event(
const btav_a2dp_codec_config_t& codec_audio_config);
static bool btif_a2dp_source_audio_tx_flush_req(void);
-static void btif_a2dp_source_alarm_cb(void* context);
static void btif_a2dp_source_audio_handle_timer(void);
static uint32_t btif_a2dp_source_read_callback(uint8_t* p_buf, uint32_t len);
static bool btif_a2dp_source_enqueue_callback(BT_HDR* p_buf, size_t frames_n,
@@ -439,52 +350,72 @@
return true;
}
-static void btif_a2dp_source_startup_delayed(void) {
+static void btif_a2dp_source_startup_delayed() {
LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
btif_a2dp_source_cb.StateStr().c_str());
-
- raise_priority_a2dp(TASK_HIGH_MEDIA);
- btif_a2dp_control_init();
+ if (!btif_a2dp_source_thread.EnableRealTimeScheduling()) {
+ LOG(FATAL) << __func__ << ": unable to enable real time scheduling";
+ }
+ if (!bluetooth::audio::a2dp::init(&btif_a2dp_source_thread)) {
+ if (btif_av_is_a2dp_offload_enabled()) {
+ LOG(WARNING) << __func__ << ": Using BluetoothA2dp HAL";
+ } else {
+ LOG(WARNING) << __func__ << ": Using legacy HAL";
+ btif_a2dp_control_init();
+ }
+ }
btif_a2dp_source_cb.SetState(BtifA2dpSource::kStateRunning);
}
-bool btif_a2dp_source_start_session(const RawAddress& peer_address) {
- LOG_INFO(LOG_TAG, "%s: peer_address=%s state=%s", __func__,
- peer_address.ToString().c_str(),
- btif_a2dp_source_cb.StateStr().c_str());
+bool btif_a2dp_source_start_session(const RawAddress& peer_address,
+ std::promise<void> peer_ready_promise) {
+ LOG(INFO) << __func__ << ": peer_address=" << peer_address
+ << " state=" << btif_a2dp_source_cb.StateStr();
btif_a2dp_source_setup_codec(peer_address);
- btif_a2dp_source_thread.DoInThread(
- FROM_HERE,
- base::Bind(&btif_a2dp_source_start_session_delayed, peer_address));
- return true;
+ if (btif_a2dp_source_thread.DoInThread(
+ FROM_HERE,
+ base::BindOnce(&btif_a2dp_source_start_session_delayed, peer_address,
+ std::move(peer_ready_promise)))) {
+ return true;
+ } else {
+ // cannot set promise but triggers crash
+ LOG(FATAL) << __func__ << ": peer_address=" << peer_address
+ << " state=" << btif_a2dp_source_cb.StateStr()
+ << " fails to context switch";
+ return false;
+ }
}
static void btif_a2dp_source_start_session_delayed(
- const RawAddress& peer_address) {
- LOG_INFO(LOG_TAG, "%s: peer_address=%s state=%s", __func__,
- peer_address.ToString().c_str(),
- btif_a2dp_source_cb.StateStr().c_str());
+ const RawAddress& peer_address, std::promise<void> peer_ready_promise) {
+ LOG(INFO) << __func__ << ": peer_address=" << peer_address
+ << " state=" << btif_a2dp_source_cb.StateStr();
if (btif_a2dp_source_cb.State() != BtifA2dpSource::kStateRunning) {
- LOG_ERROR(LOG_TAG, "%s: A2DP Source media task is not running", __func__);
+ LOG(ERROR) << __func__ << ": A2DP Source media task is not running";
+ peer_ready_promise.set_value();
return;
}
- if (btif_av_is_a2dp_offload_enabled()) {
+ if (bluetooth::audio::a2dp::is_hal_2_0_enabled()) {
+ bluetooth::audio::a2dp::start_session();
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ bluetooth::common::CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
+ } else if (btif_av_is_a2dp_offload_enabled()) {
btif_a2dp_audio_interface_start_session();
} else {
BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
- system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
+ bluetooth::common::CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
}
+ peer_ready_promise.set_value();
}
bool btif_a2dp_source_restart_session(const RawAddress& old_peer_address,
- const RawAddress& new_peer_address) {
- bool is_streaming = alarm_is_scheduled(btif_a2dp_source_cb.media_alarm);
- LOG_INFO(LOG_TAG,
- "%s: old_peer_address=%s new_peer_address=%s is_streaming=%s "
- "state=%s",
- __func__, old_peer_address.ToString().c_str(),
- new_peer_address.ToString().c_str(), logbool(is_streaming).c_str(),
- btif_a2dp_source_cb.StateStr().c_str());
+ const RawAddress& new_peer_address,
+ std::promise<void> peer_ready_promise) {
+ bool is_streaming = btif_a2dp_source_cb.media_alarm.IsScheduled();
+ LOG(INFO) << __func__ << ": old_peer_address=" << old_peer_address
+ << " new_peer_address=" << new_peer_address
+ << " is_streaming=" << logbool(is_streaming)
+ << " state=" << btif_a2dp_source_cb.StateStr();
CHECK(!new_peer_address.IsEmpty());
@@ -503,7 +434,8 @@
// Start the session.
// If audio was streaming before, start audio streaming as well.
- btif_a2dp_source_start_session(new_peer_address);
+ btif_a2dp_source_start_session(new_peer_address,
+ std::move(peer_ready_promise));
if (is_streaming) {
btif_a2dp_source_start_audio_req();
}
@@ -525,18 +457,21 @@
LOG_INFO(LOG_TAG, "%s: peer_address=%s state=%s", __func__,
peer_address.ToString().c_str(),
btif_a2dp_source_cb.StateStr().c_str());
- if (!btif_av_is_a2dp_offload_enabled()) {
- BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
- system_bt_osi::DISCONNECT_REASON_UNKNOWN, 0);
- }
if ((btif_a2dp_source_cb.State() == BtifA2dpSource::kStateRunning) ||
(btif_a2dp_source_cb.State() == BtifA2dpSource::kStateShuttingDown)) {
btif_av_stream_stop(peer_address);
} else {
LOG_ERROR(LOG_TAG, "%s: A2DP Source media task is not running", __func__);
}
- if (btif_av_is_a2dp_offload_enabled()) {
+ if (bluetooth::audio::a2dp::is_hal_2_0_enabled()) {
+ bluetooth::audio::a2dp::end_session();
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
+ bluetooth::common::DISCONNECT_REASON_UNKNOWN, 0);
+ } else if (btif_av_is_a2dp_offload_enabled()) {
btif_a2dp_audio_interface_end_session();
+ } else {
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
+ bluetooth::common::DISCONNECT_REASON_UNKNOWN, 0);
}
}
@@ -561,12 +496,16 @@
btif_a2dp_source_cb.StateStr().c_str());
// Stop the timer
- alarm_free(btif_a2dp_source_cb.media_alarm);
- btif_a2dp_source_cb.media_alarm = nullptr;
+ btif_a2dp_source_cb.media_alarm.CancelAndWait();
+ wakelock_release();
- btif_a2dp_control_cleanup();
- if (btif_av_is_a2dp_offload_enabled())
+ if (bluetooth::audio::a2dp::is_hal_2_0_enabled()) {
+ bluetooth::audio::a2dp::cleanup();
+ } else if (btif_av_is_a2dp_offload_enabled()) {
btif_a2dp_audio_interface_end_session();
+ } else {
+ btif_a2dp_control_cleanup();
+ }
fixed_queue_free(btif_a2dp_source_cb.tx_audio_queue, nullptr);
btif_a2dp_source_cb.tx_audio_queue = nullptr;
@@ -602,7 +541,7 @@
}
bool btif_a2dp_source_is_streaming(void) {
- return alarm_is_scheduled(btif_a2dp_source_cb.media_alarm);
+ return btif_a2dp_source_cb.media_alarm.IsScheduled();
}
static void btif_a2dp_source_setup_codec(const RawAddress& peer_address) {
@@ -655,6 +594,10 @@
// Save a local copy of the encoder_interval_ms
btif_a2dp_source_cb.encoder_interval_ms =
btif_a2dp_source_cb.encoder_interface->get_encoder_interval_ms();
+
+ if (bluetooth::audio::a2dp::is_hal_2_0_enabled()) {
+ bluetooth::audio::a2dp::setup_codec();
+ }
}
void btif_a2dp_source_start_audio_req(void) {
@@ -737,12 +680,19 @@
if (p_av_suspend->initiator) {
LOG_WARN(LOG_TAG, "%s: A2DP stop request failed: status=%d", __func__,
p_av_suspend->status);
- btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
+ if (bluetooth::audio::a2dp::is_hal_2_0_enabled()) {
+ bluetooth::audio::a2dp::ack_stream_suspended(A2DP_CTRL_ACK_FAILURE);
+ } else {
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
+ }
}
return;
}
}
-
+ if (btif_av_is_a2dp_offload_enabled()) {
+ bluetooth::audio::a2dp::ack_stream_suspended(A2DP_CTRL_ACK_SUCCESS);
+ return;
+ }
/* ensure tx frames are immediately suspended */
btif_a2dp_source_cb.tx_flush = true;
@@ -764,10 +714,17 @@
if (p_av_suspend->initiator) {
LOG_WARN(LOG_TAG, "%s: A2DP suspend request failed: status=%d", __func__,
p_av_suspend->status);
- btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
+ if (bluetooth::audio::a2dp::is_hal_2_0_enabled()) {
+ bluetooth::audio::a2dp::ack_stream_suspended(A2DP_CTRL_ACK_FAILURE);
+ } else {
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
+ }
}
}
-
+ if (btif_av_is_a2dp_offload_enabled()) {
+ bluetooth::audio::a2dp::ack_stream_suspended(A2DP_CTRL_ACK_SUCCESS);
+ return;
+ }
/* once stream is fully stopped we will ack back */
/* ensure tx frames are immediately flushed */
@@ -787,7 +744,7 @@
static void btif_a2dp_source_audio_tx_start_event(void) {
LOG_INFO(LOG_TAG, "%s: media_alarm is %srunning, streaming %s state=%s",
__func__,
- alarm_is_scheduled(btif_a2dp_source_cb.media_alarm) ? "" : "not ",
+ btif_a2dp_source_cb.media_alarm.IsScheduled() ? "" : "not ",
btif_a2dp_source_is_streaming() ? "true" : "false",
btif_a2dp_source_cb.StateStr().c_str());
@@ -800,22 +757,20 @@
APPL_TRACE_EVENT(
"%s: starting timer %" PRIu64 " ms", __func__,
btif_a2dp_source_cb.encoder_interface->get_encoder_interval_ms());
- alarm_free(btif_a2dp_source_cb.media_alarm);
- btif_a2dp_source_cb.media_alarm =
- alarm_new_periodic("btif.a2dp_source_media_alarm");
- if (btif_a2dp_source_cb.media_alarm == nullptr) {
- LOG_ERROR(LOG_TAG, "%s: unable to allocate media alarm", __func__);
- return;
- }
- alarm_set(btif_a2dp_source_cb.media_alarm,
- btif_a2dp_source_cb.encoder_interface->get_encoder_interval_ms(),
- btif_a2dp_source_alarm_cb, nullptr);
+ wakelock_acquire();
+ btif_a2dp_source_cb.media_alarm.SchedulePeriodic(
+ btif_a2dp_source_thread.GetWeakPtr(), FROM_HERE,
+ base::Bind(&btif_a2dp_source_audio_handle_timer),
+ base::TimeDelta::FromMilliseconds(
+ btif_a2dp_source_cb.encoder_interface->get_encoder_interval_ms()));
btif_a2dp_source_cb.stats.Reset();
- // Assign session_start_us to 1 when time_get_os_boottime_us() is 0 to
- // indicate btif_a2dp_source_start_audio_req() has been called
- btif_a2dp_source_cb.stats.session_start_us = time_get_os_boottime_us();
+ // Assign session_start_us to 1 when
+ // bluetooth::common::time_get_os_boottime_us() is 0 to indicate
+ // btif_a2dp_source_start_audio_req() has been called
+ btif_a2dp_source_cb.stats.session_start_us =
+ bluetooth::common::time_get_os_boottime_us();
if (btif_a2dp_source_cb.stats.session_start_us == 0) {
btif_a2dp_source_cb.stats.session_start_us = 1;
}
@@ -829,13 +784,14 @@
static void btif_a2dp_source_audio_tx_stop_event(void) {
LOG_INFO(LOG_TAG, "%s: media_alarm is %srunning, streaming %s state=%s",
__func__,
- alarm_is_scheduled(btif_a2dp_source_cb.media_alarm) ? "" : "not ",
+ btif_a2dp_source_cb.media_alarm.IsScheduled() ? "" : "not ",
btif_a2dp_source_is_streaming() ? "true" : "false",
btif_a2dp_source_cb.StateStr().c_str());
if (btif_av_is_a2dp_offload_enabled()) return;
- btif_a2dp_source_cb.stats.session_end_us = time_get_os_boottime_us();
+ btif_a2dp_source_cb.stats.session_end_us =
+ bluetooth::common::time_get_os_boottime_us();
btif_a2dp_source_update_metrics();
btif_a2dp_source_accumulate_stats(&btif_a2dp_source_cb.stats,
&btif_a2dp_source_cb.accumulated_stats);
@@ -844,29 +800,38 @@
uint16_t event;
// Keep track of audio data still left in the pipe
- btif_a2dp_control_log_bytes_read(
- UIPC_Read(*a2dp_uipc, UIPC_CH_ID_AV_AUDIO, &event, p_buf, sizeof(p_buf)));
+ if (bluetooth::audio::a2dp::is_hal_2_0_enabled()) {
+ btif_a2dp_control_log_bytes_read(
+ bluetooth::audio::a2dp::read(p_buf, sizeof(p_buf)));
+ } else if (a2dp_uipc != nullptr) {
+ btif_a2dp_control_log_bytes_read(UIPC_Read(*a2dp_uipc, UIPC_CH_ID_AV_AUDIO,
+ &event, p_buf, sizeof(p_buf)));
+ }
/* Stop the timer first */
- alarm_free(btif_a2dp_source_cb.media_alarm);
- btif_a2dp_source_cb.media_alarm = nullptr;
+ btif_a2dp_source_cb.media_alarm.CancelAndWait();
+ wakelock_release();
- UIPC_Close(*a2dp_uipc, UIPC_CH_ID_AV_AUDIO);
+ if (bluetooth::audio::a2dp::is_hal_2_0_enabled()) {
+ bluetooth::audio::a2dp::ack_stream_suspended(A2DP_CTRL_ACK_SUCCESS);
+ } else if (a2dp_uipc != nullptr) {
+ UIPC_Close(*a2dp_uipc, UIPC_CH_ID_AV_AUDIO);
- /*
- * Try to send acknowldegment once the media stream is
- * stopped. This will make sure that the A2DP HAL layer is
- * un-blocked on wait for acknowledgment for the sent command.
- * This resolves a corner cases AVDTP SUSPEND collision
- * when the DUT and the remote device issue SUSPEND simultaneously
- * and due to the processing of the SUSPEND request from the remote,
- * the media path is torn down. If the A2DP HAL happens to wait
- * for ACK for the initiated SUSPEND, it would never receive it casuing
- * a block/wait. Due to this acknowledgement, the A2DP HAL is guranteed
- * to get the ACK for any pending command in such cases.
- */
+ /*
+ * Try to send acknowldegment once the media stream is
+ * stopped. This will make sure that the A2DP HAL layer is
+ * un-blocked on wait for acknowledgment for the sent command.
+ * This resolves a corner cases AVDTP SUSPEND collision
+ * when the DUT and the remote device issue SUSPEND simultaneously
+ * and due to the processing of the SUSPEND request from the remote,
+ * the media path is torn down. If the A2DP HAL happens to wait
+ * for ACK for the initiated SUSPEND, it would never receive it casuing
+ * a block/wait. Due to this acknowledgement, the A2DP HAL is guranteed
+ * to get the ACK for any pending command in such cases.
+ */
- btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+ }
/* audio engine stopped, reset tx suspended flag */
btif_a2dp_source_cb.tx_flush = false;
@@ -876,18 +841,13 @@
btif_a2dp_source_cb.encoder_interface->feeding_reset();
}
-static void btif_a2dp_source_alarm_cb(UNUSED_ATTR void* context) {
- btif_a2dp_source_thread.DoInThread(
- FROM_HERE, base::Bind(&btif_a2dp_source_audio_handle_timer));
-}
-
static void btif_a2dp_source_audio_handle_timer(void) {
if (btif_av_is_a2dp_offload_enabled()) return;
- uint64_t timestamp_us = time_get_os_boottime_us();
+ uint64_t timestamp_us = bluetooth::common::time_get_os_boottime_us();
log_tstamps_us("A2DP Source tx timer", timestamp_us);
- if (!alarm_is_scheduled(btif_a2dp_source_cb.media_alarm)) {
+ if (!btif_a2dp_source_cb.media_alarm.IsScheduled()) {
LOG_ERROR(LOG_TAG, "%s: ERROR Media task Scheduled after Suspend",
__func__);
return;
@@ -912,8 +872,13 @@
static uint32_t btif_a2dp_source_read_callback(uint8_t* p_buf, uint32_t len) {
uint16_t event;
- uint32_t bytes_read =
- UIPC_Read(*a2dp_uipc, UIPC_CH_ID_AV_AUDIO, &event, p_buf, len);
+ uint32_t bytes_read = 0;
+
+ if (bluetooth::audio::a2dp::is_hal_2_0_enabled()) {
+ bytes_read = bluetooth::audio::a2dp::read(p_buf, len);
+ } else if (a2dp_uipc != nullptr) {
+ bytes_read = UIPC_Read(*a2dp_uipc, UIPC_CH_ID_AV_AUDIO, &event, p_buf, len);
+ }
if (bytes_read < len) {
LOG_WARN(LOG_TAG, "%s: UNDERFLOW: ONLY READ %d BYTES OUT OF %d", __func__,
@@ -922,7 +887,10 @@
(len - bytes_read);
btif_a2dp_source_cb.stats.media_read_total_underflow_count++;
btif_a2dp_source_cb.stats.media_read_last_underflow_us =
- time_get_os_boottime_us();
+ bluetooth::common::time_get_os_boottime_us();
+ bluetooth::common::LogA2dpAudioUnderrunEvent(
+ btif_av_source_active_peer(), btif_a2dp_source_cb.encoder_interval_ms,
+ len - bytes_read);
}
return bytes_read;
@@ -930,11 +898,11 @@
static bool btif_a2dp_source_enqueue_callback(BT_HDR* p_buf, size_t frames_n,
uint32_t bytes_read) {
- uint64_t now_us = time_get_os_boottime_us();
+ uint64_t now_us = bluetooth::common::time_get_os_boottime_us();
btif_a2dp_control_log_bytes_read(bytes_read);
/* Check if timer was stopped (media task stopped) */
- if (!alarm_is_scheduled(btif_a2dp_source_cb.media_alarm)) {
+ if (!btif_a2dp_source_cb.media_alarm.IsScheduled()) {
osi_free(p_buf);
return false;
}
@@ -968,10 +936,23 @@
size_t drop_n = fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue);
btif_a2dp_source_cb.stats.tx_queue_max_dropped_messages = std::max(
drop_n, btif_a2dp_source_cb.stats.tx_queue_max_dropped_messages);
+ int num_dropped_encoded_bytes = 0;
+ int num_dropped_encoded_frames = 0;
while (fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue)) {
btif_a2dp_source_cb.stats.tx_queue_total_dropped_messages++;
- osi_free(fixed_queue_try_dequeue(btif_a2dp_source_cb.tx_audio_queue));
+ void* p_data =
+ fixed_queue_try_dequeue(btif_a2dp_source_cb.tx_audio_queue);
+ if (p_data != nullptr) {
+ auto p_dropped_buf = static_cast<BT_HDR*>(p_data);
+ num_dropped_encoded_bytes += p_dropped_buf->len;
+ num_dropped_encoded_frames += p_dropped_buf->layer_specific;
+ osi_free(p_data);
+ }
}
+ bluetooth::common::LogA2dpAudioOverrunEvent(
+ btif_av_source_active_peer(), drop_n,
+ btif_a2dp_source_cb.encoder_interval_ms, num_dropped_encoded_frames,
+ num_dropped_encoded_bytes);
// Request additional debug info if we had to flush buffers
RawAddress peer_bda = btif_av_source_active_peer();
@@ -1022,10 +1003,12 @@
btif_a2dp_source_cb.stats.tx_queue_total_flushed_messages +=
fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue);
btif_a2dp_source_cb.stats.tx_queue_last_flushed_us =
- time_get_os_boottime_us();
+ bluetooth::common::time_get_os_boottime_us();
fixed_queue_flush(btif_a2dp_source_cb.tx_audio_queue, osi_free);
- UIPC_Ioctl(*a2dp_uipc, UIPC_CH_ID_AV_AUDIO, UIPC_REQ_RX_FLUSH, nullptr);
+ if (!bluetooth::audio::a2dp::is_hal_2_0_enabled() && a2dp_uipc != nullptr) {
+ UIPC_Ioctl(*a2dp_uipc, UIPC_CH_ID_AV_AUDIO, UIPC_REQ_RX_FLUSH, nullptr);
+ }
}
static bool btif_a2dp_source_audio_tx_flush_req(void) {
@@ -1038,7 +1021,7 @@
}
BT_HDR* btif_a2dp_source_audio_readbuf(void) {
- uint64_t now_us = time_get_os_boottime_us();
+ uint64_t now_us = bluetooth::common::time_get_os_boottime_us();
BT_HDR* p_buf =
(BT_HDR*)fixed_queue_try_dequeue(btif_a2dp_source_cb.tx_audio_queue);
@@ -1105,7 +1088,7 @@
void btif_a2dp_source_debug_dump(int fd) {
btif_a2dp_source_accumulate_stats(&btif_a2dp_source_cb.stats,
&btif_a2dp_source_cb.accumulated_stats);
- uint64_t now_us = time_get_os_boottime_us();
+ uint64_t now_us = bluetooth::common::time_get_os_boottime_us();
BtifMediaStats* accumulated_stats = &btif_a2dp_source_cb.accumulated_stats;
SchedulingStats* enqueue_stats = &accumulated_stats->tx_queue_enqueue_stats;
SchedulingStats* dequeue_stats = &accumulated_stats->tx_queue_dequeue_stats;
@@ -1277,7 +1260,7 @@
// mark the metric duration as invalid (-1) in this case
if (stats.session_start_us != 0) {
int64_t session_end_us = stats.session_end_us == 0
- ? time_get_os_boottime_us()
+ ? bluetooth::common::time_get_os_boottime_us()
: stats.session_end_us;
if (static_cast<uint64_t>(session_end_us) > stats.session_start_us) {
metrics.audio_duration_ms =
@@ -1326,6 +1309,9 @@
result->status);
return;
}
+ bluetooth::common::LogReadRssiResult(
+ result->rem_bda, bluetooth::common::kUnknownConnectionHandle,
+ result->hci_status, result->rssi);
LOG_WARN(LOG_TAG, "%s: device: %s, rssi: %d", __func__,
result->rem_bda.ToString().c_str(), result->rssi);
@@ -1345,6 +1331,9 @@
__func__, result->status);
return;
}
+ bluetooth::common::LogReadFailedContactCounterResult(
+ result->rem_bda, bluetooth::common::kUnknownConnectionHandle,
+ result->hci_status, result->failed_contact_counter);
LOG_WARN(LOG_TAG, "%s: device: %s, Failed Contact Counter: %u", __func__,
result->rem_bda.ToString().c_str(), result->failed_contact_counter);
@@ -1381,6 +1370,9 @@
result->status);
return;
}
+ bluetooth::common::LogReadTxPowerLevelResult(
+ result->rem_bda, bluetooth::common::kUnknownConnectionHandle,
+ result->hci_status, result->tx_power);
LOG_WARN(LOG_TAG, "%s: device: %s, Tx Power: %d", __func__,
result->rem_bda.ToString().c_str(), result->tx_power);
diff --git a/btif/src/btif_av.cc b/btif/src/btif_av.cc
index 8d416c1..24e32ec 100644
--- a/btif/src/btif_av.cc
+++ b/btif/src/btif_av.cc
@@ -31,10 +31,10 @@
#include <hardware/bt_rc.h>
#include "audio_a2dp_hw/include/audio_a2dp_hw.h"
+#include "audio_hal_interface/a2dp_encoding.h"
#include "bt_common.h"
#include "bt_utils.h"
#include "bta/include/bta_api.h"
-#include "bta/include/bta_closure_api.h"
#include "btif/include/btif_a2dp_source.h"
#include "btif_a2dp.h"
#include "btif_a2dp_audio_interface.h"
@@ -43,9 +43,9 @@
#include "btif_av_co.h"
#include "btif_profile_queue.h"
#include "btif_rc.h"
-#include "btif_state_machine.h"
#include "btif_util.h"
#include "btu.h"
+#include "common/state_machine.h"
#include "osi/include/allocator.h"
#include "osi/include/osi.h"
#include "osi/include/properties.h"
@@ -115,7 +115,7 @@
// different than Open state. Suspend flags are needed however to prevent
// media task from trying to restart stream during remote Suspend or while
// we are in the process of a local Suspend.
-class BtifAvStateMachine : public BtifStateMachine {
+class BtifAvStateMachine : public bluetooth::common::StateMachine {
public:
enum {
kStateIdle, // AVDTP disconnected
@@ -219,7 +219,7 @@
kFlagPendingStart = 0x4,
kFlagPendingStop = 0x8,
};
- static constexpr period_ms_t kTimeoutAvOpenOnRcMs = 2 * 1000; // 2s
+ static constexpr uint64_t kTimeoutAvOpenOnRcMs = 2 * 1000; // 2s
BtifAvPeer(const RawAddress& peer_address, uint8_t peer_sep,
tBTA_AV_HNDL bta_handle, uint8_t peer_id);
@@ -277,6 +277,9 @@
bool IsConnected() const;
bool IsStreaming() const;
+ bool IsInSilenceMode() const { return is_silenced_; };
+
+ void SetSilence(bool silence) { is_silenced_ = silence; };
/**
* Check whether any of the flags specified by the bitlags mask is set.
@@ -325,6 +328,7 @@
tBTA_AV_EDR edr_;
uint8_t flags_;
bool self_initiated_connection_;
+ bool is_silenced_;
};
class BtifAvSource {
@@ -386,38 +390,93 @@
const RawAddress& ActivePeer() const { return active_peer_; }
/**
+ * Check whether peer is silenced
+ *
+ * @param peer_address the peer to check
+ * @return true on silence mode enabled, otherwise false
+ */
+ bool IsPeerSilenced(const RawAddress& peer_address) {
+ if (peer_address.IsEmpty()) {
+ return false;
+ }
+ BtifAvPeer* peer = FindPeer(peer_address);
+ if (peer == nullptr) {
+ BTIF_TRACE_WARNING("%s: peer is null", __func__);
+ return false;
+ }
+ if (!peer->IsConnected()) {
+ BTIF_TRACE_WARNING("%s: peer is not connected", __func__);
+ return false;
+ }
+ return peer->IsInSilenceMode();
+ }
+
+ /**
+ * Set peer silence mode
+ *
+ * @param peer_address the peer to set
+ * @param silence true on enable silence mode, false on disable
+ * @return true on success, otherwise false
+ */
+ bool SetSilencePeer(const RawAddress& peer_address, const bool silence) {
+ if (peer_address.IsEmpty()) {
+ return false;
+ }
+ LOG_INFO(LOG_TAG, "%s: peer: %s", __PRETTY_FUNCTION__,
+ peer_address.ToString().c_str());
+ BtifAvPeer* peer = FindPeer(peer_address);
+ if (peer == nullptr) {
+ BTIF_TRACE_WARNING("%s: peer is null", __func__);
+ return false;
+ }
+ if (!peer->IsConnected()) {
+ BTIF_TRACE_WARNING("%s: peer is not connected", __func__);
+ return false;
+ }
+ peer->SetSilence(silence);
+ return true;
+ }
+
+ /**
* Set the active peer.
*
* @param peer_address the active peer address or RawAddress::kEmpty to
* reset the active peer
* @return true on success, otherwise false
*/
- bool SetActivePeer(const RawAddress& peer_address) {
- LOG_INFO(LOG_TAG, "%s: peer: %s", __PRETTY_FUNCTION__,
- peer_address.ToString().c_str());
+ bool SetActivePeer(const RawAddress& peer_address,
+ std::promise<void> peer_ready_promise) {
+ LOG(INFO) << __PRETTY_FUNCTION__ << ": peer: " << peer_address;
- if (active_peer_ == peer_address) return true; // Nothing has changed
+ if (active_peer_ == peer_address) {
+ peer_ready_promise.set_value();
+ return true; // Nothing has changed
+ }
if (peer_address.IsEmpty()) {
BTIF_TRACE_EVENT("%s: peer address is empty, shutdown the Audio source",
__func__);
if (!bta_av_co_set_active_peer(peer_address)) {
- BTIF_TRACE_WARNING("%s: unable to set active peer to empty in BtaAvCo",
- __func__);
+ LOG(WARNING) << __func__
+ << ": unable to set active peer to empty in BtaAvCo";
}
btif_a2dp_source_end_session(active_peer_);
btif_a2dp_source_shutdown();
active_peer_ = peer_address;
+ peer_ready_promise.set_value();
return true;
}
BtifAvPeer* peer = FindPeer(peer_address);
if (peer != nullptr && !peer->IsConnected()) {
- BTIF_TRACE_ERROR("%s: Error setting %s as active Source peer", __func__,
- peer->PeerAddress().ToString().c_str());
+ LOG(ERROR) << __func__ << ": Error setting " << peer->PeerAddress()
+ << " as active Source peer";
+ peer_ready_promise.set_value();
return false;
}
- if (!btif_a2dp_source_restart_session(active_peer_, peer_address)) {
+ if (!btif_a2dp_source_restart_session(active_peer_, peer_address,
+ std::move(peer_ready_promise))) {
+ // cannot set promise but need to be handled within restart_session
return false;
}
active_peer_ = peer_address;
@@ -432,7 +491,8 @@
*/
void UpdateCodecConfig(
const RawAddress& peer_address,
- const std::vector<btav_a2dp_codec_config_t>& codec_preferences) {
+ const std::vector<btav_a2dp_codec_config_t>& codec_preferences,
+ std::promise<void> peer_ready_promise) {
// Restart the session if the codec for the active peer is updated
bool restart_session =
((active_peer_ == peer_address) && !active_peer_.IsEmpty());
@@ -446,7 +506,10 @@
btif_a2dp_source_encoder_user_config_update_req(peer_address, cp);
}
if (restart_session) {
- btif_a2dp_source_start_session(active_peer_);
+ btif_a2dp_source_start_session(active_peer_,
+ std::move(peer_ready_promise));
+ } else {
+ peer_ready_promise.set_value();
}
}
@@ -464,6 +527,7 @@
bool a2dp_offload_enabled_;
int max_connected_peers_;
std::map<RawAddress, BtifAvPeer*> peers_;
+ std::set<RawAddress> silenced_peers_;
RawAddress active_peer_;
std::map<uint8_t, tBTA_AV_HNDL> peer_id2bta_handle_;
};
@@ -529,32 +593,39 @@
* reset the active peer
* @return true on success, otherwise false
*/
- bool SetActivePeer(const RawAddress& peer_address) {
- LOG_INFO(LOG_TAG, "%s: peer: %s", __PRETTY_FUNCTION__,
- peer_address.ToString().c_str());
+ bool SetActivePeer(const RawAddress& peer_address,
+ std::promise<void> peer_ready_promise) {
+ LOG(INFO) << __PRETTY_FUNCTION__ << ": peer: " << peer_address;
- if (active_peer_ == peer_address) return true; // Nothing has changed
+ if (active_peer_ == peer_address) {
+ peer_ready_promise.set_value();
+ return true; // Nothing has changed
+ }
if (peer_address.IsEmpty()) {
BTIF_TRACE_EVENT("%s: peer address is empty, shutdown the Audio sink",
__func__);
if (!bta_av_co_set_active_peer(peer_address)) {
- BTIF_TRACE_WARNING("%s: unable to set active peer to empty in BtaAvCo",
- __func__);
+ LOG(WARNING) << __func__
+ << ": unable to set active peer to empty in BtaAvCo";
}
btif_a2dp_sink_end_session(active_peer_);
btif_a2dp_sink_shutdown();
active_peer_ = peer_address;
+ peer_ready_promise.set_value();
return true;
}
BtifAvPeer* peer = FindPeer(peer_address);
if (peer != nullptr && !peer->IsConnected()) {
- BTIF_TRACE_ERROR("%s: Error setting %s as active Sink peer", __func__,
- peer->PeerAddress().ToString().c_str());
+ LOG(ERROR) << __func__ << ": Error setting " << peer->PeerAddress()
+ << " as active Sink peer";
+ peer_ready_promise.set_value();
return false;
}
- if (!btif_a2dp_sink_restart_session(active_peer_, peer_address)) {
+ if (!btif_a2dp_sink_restart_session(active_peer_, peer_address,
+ std::move(peer_ready_promise))) {
+ // cannot set promise but need to be handled within restart_session
return false;
}
active_peer_ = peer_address;
@@ -830,6 +901,7 @@
bt_status_t BtifAvPeer::Init() {
alarm_free(av_open_on_rc_timer_);
av_open_on_rc_timer_ = alarm_new("btif_av_peer.av_open_on_rc_timer");
+ is_silenced_ = false;
state_machine_.Start();
return BT_STATUS_SUCCESS;
@@ -908,11 +980,13 @@
btif_queue_cleanup(UUID_SERVCLASS_AUDIO_SOURCE);
- do_in_bta_thread(
+ std::promise<void> peer_ready_promise;
+ do_in_main_thread(
FROM_HERE,
- base::Bind(base::IgnoreResult(&BtifAvSource::SetActivePeer),
- base::Unretained(&btif_av_source), RawAddress::kEmpty));
- do_in_bta_thread(FROM_HERE, base::Bind(&btif_a2dp_source_cleanup));
+ base::BindOnce(base::IgnoreResult(&BtifAvSource::SetActivePeer),
+ base::Unretained(&btif_av_source), RawAddress::kEmpty,
+ std::move(peer_ready_promise)));
+ do_in_main_thread(FROM_HERE, base::Bind(&btif_a2dp_source_cleanup));
btif_disable_service(BTA_A2DP_SOURCE_SERVICE_ID);
CleanupAllPeers();
@@ -1093,11 +1167,13 @@
btif_queue_cleanup(UUID_SERVCLASS_AUDIO_SINK);
- do_in_bta_thread(
+ std::promise<void> peer_ready_promise;
+ do_in_main_thread(
FROM_HERE,
- base::Bind(base::IgnoreResult(&BtifAvSink::SetActivePeer),
- base::Unretained(&btif_av_sink), RawAddress::kEmpty));
- do_in_bta_thread(FROM_HERE, base::Bind(&btif_a2dp_sink_cleanup));
+ base::BindOnce(base::IgnoreResult(&BtifAvSink::SetActivePeer),
+ base::Unretained(&btif_av_sink), RawAddress::kEmpty,
+ std::move(peer_ready_promise)));
+ do_in_main_thread(FROM_HERE, base::Bind(&btif_a2dp_sink_cleanup));
btif_disable_service(BTA_A2DP_SINK_SERVICE_ID);
CleanupAllPeers();
@@ -1168,6 +1244,9 @@
peer = new BtifAvPeer(peer_address, AVDT_TSEP_SRC, bta_handle, peer_id);
peers_.insert(std::make_pair(peer_address, peer));
peer->Init();
+ if (active_peer_.IsEmpty()) {
+ active_peer_ = peer_address;
+ }
return peer;
}
@@ -1266,20 +1345,23 @@
// Reset the active peer if this was the active peer and
// the Idle state was reentered
if (peer_.IsActivePeer() && peer_.CanBeDeleted()) {
+ std::promise<void> peer_ready_promise;
if (peer_.IsSink()) {
- btif_av_source.SetActivePeer(RawAddress::kEmpty);
+ btif_av_source.SetActivePeer(RawAddress::kEmpty,
+ std::move(peer_ready_promise));
} else if (peer_.IsSource()) {
- btif_av_sink.SetActivePeer(RawAddress::kEmpty);
+ btif_av_sink.SetActivePeer(RawAddress::kEmpty,
+ std::move(peer_ready_promise));
}
}
// Delete peers that are re-entering the Idle state
if (peer_.IsSink()) {
- do_in_bta_thread(FROM_HERE, base::Bind(&BtifAvSource::DeleteIdlePeers,
- base::Unretained(&btif_av_source)));
+ do_in_main_thread(FROM_HERE, base::Bind(&BtifAvSource::DeleteIdlePeers,
+ base::Unretained(&btif_av_source)));
} else if (peer_.IsSource()) {
- do_in_bta_thread(FROM_HERE, base::Bind(&BtifAvSink::DeleteIdlePeers,
- base::Unretained(&btif_av_sink)));
+ do_in_main_thread(FROM_HERE, base::Bind(&BtifAvSink::DeleteIdlePeers,
+ base::Unretained(&btif_av_sink)));
}
}
@@ -1694,7 +1776,9 @@
// For A2DP Source, the setting of the Active device is done by the
// ActiveDeviceManager in Java.
if (peer_.IsSource() && btif_av_sink.ActivePeer().IsEmpty()) {
- if (!btif_av_sink.SetActivePeer(peer_.PeerAddress())) {
+ std::promise<void> peer_ready_promise;
+ if (!btif_av_sink.SetActivePeer(peer_.PeerAddress(),
+ std::move(peer_ready_promise))) {
BTIF_TRACE_ERROR("%s: Error setting %s as active Source peer", __func__,
peer_.PeerAddress().ToString().c_str());
}
@@ -1759,17 +1843,13 @@
bool should_suspend = false;
if (peer_.IsSink() && !peer_.CheckFlags(BtifAvPeer::kFlagPendingStart |
BtifAvPeer::kFlagRemoteSuspend)) {
- BTIF_TRACE_WARNING("%s: Peer %s : trigger Suspend as remote initiated",
- __PRETTY_FUNCTION__,
- peer_.PeerAddress().ToString().c_str());
+ LOG(WARNING) << __PRETTY_FUNCTION__ << ": Peer " << peer_.PeerAddress()
+ << " : trigger Suspend as remote initiated";
should_suspend = true;
}
- // If peer is A2DP Source, we do not want to ACK commands on UIPC
- if (peer_.IsSink() &&
- btif_a2dp_on_started(
- peer_.PeerAddress(), &p_av->start,
- peer_.CheckFlags(BtifAvPeer::kFlagPendingStart))) {
+ // If peer is A2DP Source, do ACK commands to audio HAL and start media task
+ if (peer_.IsSink() && btif_a2dp_on_started(peer_.PeerAddress(), &p_av->start)) {
// Only clear pending flag after acknowledgement
peer_.ClearFlags(BtifAvPeer::kFlagPendingStart);
}
@@ -1782,12 +1862,6 @@
btif_a2dp_sink_set_rx_flush(false);
}
- // Change state to Started, send acknowledgement if start is pending
- if (peer_.IsSink() && peer_.CheckFlags(BtifAvPeer::kFlagPendingStart)) {
- btif_a2dp_on_started(peer_.PeerAddress(), nullptr, true);
- // Pending start flag will be cleared when exit current state
- }
-
if (should_suspend) {
btif_av_source_dispatch_sm_event(peer_.PeerAddress(),
BTIF_AV_SUSPEND_STREAM_REQ_EVT);
@@ -1921,8 +1995,7 @@
BtifAvEvent::EventName(event).c_str(),
peer_.FlagsToString().c_str());
// We were started remotely, just ACK back the local request
- if (peer_.IsSink())
- btif_a2dp_on_started(peer_.PeerAddress(), nullptr, true);
+ if (peer_.IsSink()) btif_a2dp_on_started(peer_.PeerAddress(), nullptr);
break;
// FIXME -- use suspend = true always to work around issue with BTA AV
@@ -2476,16 +2549,16 @@
BtifAvEvent btif_av_event(event, p_data, sizeof(tBTA_AV));
BTIF_TRACE_EVENT("%s: event=%s", __func__, btif_av_event.ToString().c_str());
- do_in_bta_thread(FROM_HERE,
- base::Bind(&btif_av_handle_bta_av_event,
- AVDT_TSEP_SNK /* peer_sep */, btif_av_event));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(&btif_av_handle_bta_av_event,
+ AVDT_TSEP_SNK /* peer_sep */, btif_av_event));
}
static void bta_av_sink_callback(tBTA_AV_EVT event, tBTA_AV* p_data) {
BtifAvEvent btif_av_event(event, p_data, sizeof(tBTA_AV));
- do_in_bta_thread(FROM_HERE,
- base::Bind(&btif_av_handle_bta_av_event,
- AVDT_TSEP_SRC /* peer_sep */, btif_av_event));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(&btif_av_handle_bta_av_event,
+ AVDT_TSEP_SRC /* peer_sep */, btif_av_event));
}
// TODO: All processing should be done on the JNI thread
@@ -2527,10 +2600,11 @@
config_req.peer_address = p_data->avk_config.bd_addr;
BtifAvEvent btif_av_event(BTIF_AV_SINK_CONFIG_REQ_EVT, &config_req,
sizeof(config_req));
- do_in_bta_thread(FROM_HERE, base::Bind(&btif_av_handle_event,
- AVDT_TSEP_SRC, // peer_sep
- config_req.peer_address,
- kBtaHandleUnknown, btif_av_event));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(&btif_av_handle_event,
+ AVDT_TSEP_SRC, // peer_sep
+ config_req.peer_address, kBtaHandleUnknown,
+ btif_av_event));
break;
}
default:
@@ -2586,22 +2660,35 @@
return BT_STATUS_SUCCESS;
}
+static void set_source_silence_peer_int(const RawAddress& peer_address,
+ bool silence) {
+ BTIF_TRACE_EVENT("%s: peer_address=%s, silence=%s", __func__,
+ peer_address.ToString().c_str(), silence ? "true" : "false");
+ if (!btif_av_source.SetSilencePeer(peer_address, silence)) {
+ BTIF_TRACE_ERROR("%s: Error setting silence state to %s", __func__,
+ peer_address.ToString().c_str());
+ }
+}
+
// Set the active peer
static void set_active_peer_int(uint8_t peer_sep,
- const RawAddress& peer_address) {
+ const RawAddress& peer_address,
+ std::promise<void> peer_ready_promise) {
BTIF_TRACE_EVENT("%s: peer_sep=%s (%d) peer_address=%s", __func__,
(peer_sep == AVDT_TSEP_SRC) ? "Source" : "Sink", peer_sep,
peer_address.ToString().c_str());
BtifAvPeer* peer = nullptr;
if (peer_sep == AVDT_TSEP_SNK) {
- if (!btif_av_source.SetActivePeer(peer_address)) {
+ if (!btif_av_source.SetActivePeer(peer_address,
+ std::move(peer_ready_promise))) {
BTIF_TRACE_ERROR("%s: Error setting %s as active Sink peer", __func__,
peer_address.ToString().c_str());
}
return;
}
if (peer_sep == AVDT_TSEP_SRC) {
- if (!btif_av_sink.SetActivePeer(peer_address)) {
+ if (!btif_av_sink.SetActivePeer(peer_address,
+ std::move(peer_ready_promise))) {
BTIF_TRACE_ERROR("%s: Error setting %s as active Source peer", __func__,
peer_address.ToString().c_str());
}
@@ -2612,6 +2699,7 @@
(peer_sep == AVDT_TSEP_SRC) ? "Source" : "Sink",
peer_address.ToString().c_str(),
(peer == nullptr) ? "found" : "connected");
+ peer_ready_promise.set_value();
}
static bt_status_t src_connect_sink(const RawAddress& peer_address) {
@@ -2650,7 +2738,7 @@
BtifAvEvent btif_av_event(BTIF_AV_DISCONNECT_REQ_EVT, &peer_address,
sizeof(peer_address));
- return do_in_bta_thread(
+ return do_in_main_thread(
FROM_HERE, base::Bind(&btif_av_handle_event,
AVDT_TSEP_SNK, // peer_sep
peer_address, kBtaHandleUnknown, btif_av_event));
@@ -2666,23 +2754,44 @@
BtifAvEvent btif_av_event(BTIF_AV_DISCONNECT_REQ_EVT, &peer_address,
sizeof(peer_address));
- return do_in_bta_thread(
+ return do_in_main_thread(
FROM_HERE, base::Bind(&btif_av_handle_event,
AVDT_TSEP_SRC, // peer_sep
peer_address, kBtaHandleUnknown, btif_av_event));
}
+static bt_status_t src_set_silence_sink(const RawAddress& peer_address,
+ bool silence) {
+ BTIF_TRACE_EVENT("%s: Peer %s", __func__, peer_address.ToString().c_str());
+ if (!btif_av_source.Enabled()) {
+ BTIF_TRACE_WARNING("%s: BTIF AV Source is not enabled", __func__);
+ return BT_STATUS_NOT_READY;
+ }
+
+ return do_in_main_thread(FROM_HERE, base::Bind(&set_source_silence_peer_int,
+ peer_address, silence));
+}
+
static bt_status_t src_set_active_sink(const RawAddress& peer_address) {
BTIF_TRACE_EVENT("%s: Peer %s", __func__, peer_address.ToString().c_str());
if (!btif_av_source.Enabled()) {
- BTIF_TRACE_WARNING("%s: BTIF AV Source is not enabled", __func__);
+ LOG(WARNING) << __func__ << ": BTIF AV Source is not enabled";
return BT_STATUS_NOT_READY;
}
- return do_in_bta_thread(FROM_HERE, base::Bind(&set_active_peer_int,
- AVDT_TSEP_SNK, // peer_sep
- peer_address));
+ std::promise<void> peer_ready_promise;
+ std::future<void> peer_ready_future = peer_ready_promise.get_future();
+ bt_status_t status = do_in_main_thread(
+ FROM_HERE, base::BindOnce(&set_active_peer_int,
+ AVDT_TSEP_SNK, // peer_sep
+ peer_address, std::move(peer_ready_promise)));
+ if (status == BT_STATUS_SUCCESS) {
+ peer_ready_future.wait();
+ } else {
+ LOG(WARNING) << __func__ << ": BTIF AV Source fails to change peer";
+ }
+ return status;
}
static bt_status_t codec_config_src(
@@ -2691,26 +2800,35 @@
BTIF_TRACE_EVENT("%s", __func__);
if (!btif_av_source.Enabled()) {
- BTIF_TRACE_WARNING("%s: BTIF AV Source is not enabled", __func__);
+ LOG(WARNING) << __func__ << ": BTIF AV Source is not enabled";
return BT_STATUS_NOT_READY;
}
- return do_in_bta_thread(
- FROM_HERE, base::Bind(&BtifAvSource::UpdateCodecConfig,
- base::Unretained(&btif_av_source), peer_address,
- codec_preferences));
+ std::promise<void> peer_ready_promise;
+ std::future<void> peer_ready_future = peer_ready_promise.get_future();
+ bt_status_t status = do_in_main_thread(
+ FROM_HERE,
+ base::BindOnce(&BtifAvSource::UpdateCodecConfig,
+ base::Unretained(&btif_av_source), peer_address,
+ codec_preferences, std::move(peer_ready_promise)));
+ if (status == BT_STATUS_SUCCESS) {
+ peer_ready_future.wait();
+ } else {
+ LOG(WARNING) << __func__ << ": BTIF AV Source fails to config codec";
+ }
+ return status;
}
static void cleanup_src(void) {
BTIF_TRACE_EVENT("%s", __func__);
- do_in_bta_thread(FROM_HERE, base::Bind(&BtifAvSource::Cleanup,
- base::Unretained(&btif_av_source)));
+ do_in_main_thread(FROM_HERE, base::Bind(&BtifAvSource::Cleanup,
+ base::Unretained(&btif_av_source)));
}
static void cleanup_sink(void) {
BTIF_TRACE_EVENT("%s", __func__);
- do_in_bta_thread(FROM_HERE, base::Bind(&BtifAvSink::Cleanup,
- base::Unretained(&btif_av_sink)));
+ do_in_main_thread(FROM_HERE, base::Bind(&BtifAvSink::Cleanup,
+ base::Unretained(&btif_av_sink)));
}
static const btav_source_interface_t bt_av_src_interface = {
@@ -2718,6 +2836,7 @@
init_src,
src_connect_sink,
src_disconnect_sink,
+ src_set_silence_sink,
src_set_active_sink,
codec_config_src,
cleanup_src,
@@ -2838,10 +2957,10 @@
peer_address.ToString().c_str(),
btif_av_event.ToString().c_str());
- do_in_bta_thread(FROM_HERE,
- base::Bind(&btif_av_handle_event,
- AVDT_TSEP_SNK, // peer_sep
- peer_address, kBtaHandleUnknown, btif_av_event));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(&btif_av_handle_event,
+ AVDT_TSEP_SNK, // peer_sep
+ peer_address, kBtaHandleUnknown, btif_av_event));
}
static void btif_av_sink_dispatch_sm_event(const RawAddress& peer_address,
@@ -2851,10 +2970,10 @@
peer_address.ToString().c_str(),
btif_av_event.ToString().c_str());
- do_in_bta_thread(FROM_HERE,
- base::Bind(&btif_av_handle_event,
- AVDT_TSEP_SRC, // peer_sep
- peer_address, kBtaHandleUnknown, btif_av_event));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(&btif_av_handle_event,
+ AVDT_TSEP_SRC, // peer_sep
+ peer_address, kBtaHandleUnknown, btif_av_event));
}
bt_status_t btif_av_source_execute_service(bool enable) {
@@ -2968,49 +3087,6 @@
peer->ClearFlags(BtifAvPeer::kFlagRemoteSuspend);
}
-void btif_av_avrcp_event_open(const RawAddress& peer_address) {
- // TODO: We need a better demultipexing mechanism whether the remote device
- // is an A2DP Source or a Sink.
- if (btif_av_source.Enabled()) {
- BtifAvPeer* peer =
- btif_av_source.FindOrCreatePeer(peer_address, kBtaHandleUnknown);
- if (peer != nullptr) {
- btif_av_source_dispatch_sm_event(peer_address, BTIF_AV_AVRCP_OPEN_EVT);
- return;
- }
- } else if (btif_av_sink.Enabled()) {
- BtifAvPeer* peer =
- btif_av_sink.FindOrCreatePeer(peer_address, kBtaHandleUnknown);
- if (peer != nullptr) {
- btif_av_sink_dispatch_sm_event(peer_address, BTIF_AV_AVRCP_OPEN_EVT);
- return;
- }
- }
- BTIF_TRACE_ERROR("%s: event ignored: cannot find or create peer state for %s",
- __func__, peer_address.ToString().c_str());
-}
-
-void btif_av_avrcp_event_close(const RawAddress& peer_address) {
- // TODO: We need a better demultipexing mechanism whether the remote device
- // is an A2DP Source or a Sink.
- if (btif_av_source.Enabled()) {
- btif_av_source_dispatch_sm_event(peer_address, BTIF_AV_AVRCP_CLOSE_EVT);
- } else if (btif_av_sink.Enabled()) {
- btif_av_sink_dispatch_sm_event(peer_address, BTIF_AV_AVRCP_CLOSE_EVT);
- }
-}
-
-void btif_av_avrcp_event_remote_play(const RawAddress& peer_address) {
- // TODO: We need a better demultipexing mechanism whether the remote device
- // is an A2DP Source or a Sink.
- if (btif_av_source.Enabled()) {
- btif_av_source_dispatch_sm_event(peer_address,
- BTIF_AV_AVRCP_REMOTE_PLAY_EVT);
- } else if (btif_av_sink.Enabled()) {
- btif_av_sink_dispatch_sm_event(peer_address, BTIF_AV_AVRCP_REMOTE_PLAY_EVT);
- }
-}
-
bool btif_av_is_peer_edr(const RawAddress& peer_address) {
BtifAvPeer* peer = btif_av_find_peer(peer_address);
if (peer == nullptr) {
@@ -3133,6 +3209,7 @@
void btif_av_set_audio_delay(uint16_t delay) {
btif_a2dp_control_set_audio_delay(delay);
+ bluetooth::audio::a2dp::set_remote_delay(delay);
}
void btif_av_reset_audio_delay(void) { btif_a2dp_control_reset_audio_delay(); }
@@ -3140,3 +3217,7 @@
bool btif_av_is_a2dp_offload_enabled() {
return btif_av_source.A2dpOffloadEnabled();
}
+
+bool btif_av_is_peer_silenced(const RawAddress& peer_address) {
+ return btif_av_source.IsPeerSilenced(peer_address);
+}
diff --git a/btif/src/btif_avrcp_audio_track.cc b/btif/src/btif_avrcp_audio_track.cc
index 76da406..4f3cd35 100644
--- a/btif/src/btif_avrcp_audio_track.cc
+++ b/btif/src/btif_avrcp_audio_track.cc
@@ -35,11 +35,26 @@
char outputFilename[50] = "/data/misc/bluedroid/output_sample.pcm";
#endif
-void* BtifAvrcpAudioTrackCreate(int trackFreq, int channelType) {
- LOG_VERBOSE(LOG_TAG, "%s Track.cpp: btCreateTrack freq %d channel %d ",
- __func__, trackFreq, channelType);
+void* BtifAvrcpAudioTrackCreate(int trackFreq, int bits_per_sample,
+ int channelType) {
+ audio_format_t format;
+ switch (bits_per_sample) {
+ default:
+ case 16:
+ format = AUDIO_FORMAT_PCM_16_BIT;
+ break;
+ case 24:
+ format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
+ break;
+ case 32:
+ format = AUDIO_FORMAT_PCM_32_BIT;
+ break;
+ }
+ LOG_VERBOSE(LOG_TAG,
+ "%s Track.cpp: btCreateTrack freq %d format 0x%x channel %d ",
+ __func__, trackFreq, format, channelType);
sp<android::AudioTrack> track = new android::AudioTrack(
- AUDIO_STREAM_MUSIC, trackFreq, AUDIO_FORMAT_PCM_16_BIT, channelType,
+ AUDIO_STREAM_MUSIC, trackFreq, format, channelType,
(size_t)0 /*frameCount*/, (audio_output_flags_t)AUDIO_OUTPUT_FLAG_FAST,
NULL /*callback_t*/, NULL /*void* user*/, 0 /*notificationFrames*/,
AUDIO_SESSION_ALLOCATE, android::AudioTrack::TRANSFER_SYNC);
diff --git a/btif/src/btif_avrcp_audio_track_linux.cc b/btif/src/btif_avrcp_audio_track_linux.cc
new file mode 100644
index 0000000..ea35212
--- /dev/null
+++ b/btif/src/btif_avrcp_audio_track_linux.cc
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2018 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 "btif_avrcp_audio_track.h"
+
+void* BtifAvrcpAudioTrackCreate(int trackFreq, int bits_per_sample,
+ int channelType) {
+ return nullptr;
+}
+
+void BtifAvrcpAudioTrackStart(void* handle) {}
+
+void BtifAvrcpAudioTrackStop(void* handle) {}
+
+void BtifAvrcpAudioTrackDelete(void* handle) {}
+
+void BtifAvrcpAudioTrackPause(void* handle) {}
+
+void BtifAvrcpSetAudioTrackGain(void* handle, float gain) {}
+
+int BtifAvrcpAudioTrackWriteData(void* handle, void* audioBuffer,
+ int bufferlen) {
+ return 0;
+}
diff --git a/btif/src/btif_ble_advertiser.cc b/btif/src/btif_ble_advertiser.cc
index e24bcde..d1923bd 100644
--- a/btif/src/btif_ble_advertiser.cc
+++ b/btif/src/btif_ble_advertiser.cc
@@ -25,8 +25,8 @@
#include <vector>
#include "ble_advertiser.h"
-#include "bta_closure_api.h"
#include "btif_common.h"
+#include "stack/include/btu.h"
using base::Bind;
using base::Owned;
@@ -40,7 +40,7 @@
explicit OwnedArrayWrapper(T* o) : ptr_(o) {}
~OwnedArrayWrapper() { delete[] ptr_; }
T* get() const { return ptr_; }
- OwnedArrayWrapper(OwnedArrayWrapper&& other) {
+ OwnedArrayWrapper(OwnedArrayWrapper&& other) noexcept {
ptr_ = other.ptr_;
other.ptr_ = NULL;
}
@@ -83,7 +83,7 @@
}
class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface {
- ~BleAdvertiserInterfaceImpl(){};
+ ~BleAdvertiserInterfaceImpl() override{};
void RegisterAdvertiserCb(IdStatusCallback cb, uint8_t advertiser_id,
uint8_t status) {
@@ -93,7 +93,7 @@
}
void RegisterAdvertiser(IdStatusCallback cb) override {
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE, Bind(&BleAdvertisingManager::RegisterAdvertiser,
BleAdvertisingManager::Get(),
Bind(&BleAdvertiserInterfaceImpl::RegisterAdvertiserCb,
@@ -101,7 +101,7 @@
}
void Unregister(uint8_t advertiser_id) override {
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE,
Bind(
[](uint8_t advertiser_id) {
@@ -116,10 +116,10 @@
void GetOwnAddress(uint8_t advertiser_id, GetAddressCallback cb) override {
if (!BleAdvertisingManager::IsInitialized()) return;
- do_in_bta_thread(FROM_HERE,
- Bind(&BleAdvertisingManager::GetOwnAddress,
- BleAdvertisingManager::Get(), advertiser_id,
- jni_thread_wrapper(FROM_HERE, cb)));
+ do_in_main_thread(FROM_HERE,
+ Bind(&BleAdvertisingManager::GetOwnAddress,
+ BleAdvertisingManager::Get(), advertiser_id,
+ jni_thread_wrapper(FROM_HERE, cb)));
}
void SetParameters(uint8_t advertiser_id, AdvertiseParameters params,
@@ -130,16 +130,16 @@
tBTM_BLE_ADV_PARAMS* p_params = new tBTM_BLE_ADV_PARAMS;
parseParams(p_params, params);
- do_in_bta_thread(FROM_HERE, Bind(&BleAdvertisingManager::SetParameters,
- BleAdvertisingManager::Get(),
- advertiser_id, base::Owned(p_params),
- jni_thread_wrapper(FROM_HERE, cb)));
+ do_in_main_thread(FROM_HERE, Bind(&BleAdvertisingManager::SetParameters,
+ BleAdvertisingManager::Get(),
+ advertiser_id, base::Owned(p_params),
+ jni_thread_wrapper(FROM_HERE, cb)));
}
void SetData(int advertiser_id, bool set_scan_rsp, vector<uint8_t> data,
StatusCallback cb) override {
if (!BleAdvertisingManager::IsInitialized()) return;
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE,
Bind(&BleAdvertisingManager::SetData, BleAdvertisingManager::Get(),
advertiser_id, set_scan_rsp, std::move(data),
@@ -153,7 +153,7 @@
<< " ,enable: " << enable;
if (!BleAdvertisingManager::IsInitialized()) return;
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE,
Bind(&BleAdvertisingManager::Enable, BleAdvertisingManager::Get(),
advertiser_id, enable, jni_thread_wrapper(FROM_HERE, cb), duration,
@@ -171,7 +171,7 @@
tBTM_BLE_ADV_PARAMS* p_params = new tBTM_BLE_ADV_PARAMS;
parseParams(p_params, params);
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE,
Bind(&BleAdvertisingManager::StartAdvertising,
BleAdvertisingManager::Get(), advertiser_id,
@@ -197,7 +197,7 @@
tBLE_PERIODIC_ADV_PARAMS* p_periodic_params = new tBLE_PERIODIC_ADV_PARAMS;
parsePeriodicParams(p_periodic_params, periodic_params);
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE,
Bind(&BleAdvertisingManager::StartAdvertisingSet,
BleAdvertisingManager::Get(), jni_thread_wrapper(FROM_HERE, cb),
@@ -216,7 +216,7 @@
tBLE_PERIODIC_ADV_PARAMS* p_periodic_params = new tBLE_PERIODIC_ADV_PARAMS;
parsePeriodicParams(p_periodic_params, periodic_params);
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE,
Bind(&BleAdvertisingManager::SetPeriodicAdvertisingParameters,
BleAdvertisingManager::Get(), advertiser_id,
@@ -229,10 +229,10 @@
VLOG(1) << __func__ << " advertiser_id: " << +advertiser_id;
if (!BleAdvertisingManager::IsInitialized()) return;
- do_in_bta_thread(FROM_HERE,
- Bind(&BleAdvertisingManager::SetPeriodicAdvertisingData,
- BleAdvertisingManager::Get(), advertiser_id,
- std::move(data), jni_thread_wrapper(FROM_HERE, cb)));
+ do_in_main_thread(FROM_HERE,
+ Bind(&BleAdvertisingManager::SetPeriodicAdvertisingData,
+ BleAdvertisingManager::Get(), advertiser_id,
+ std::move(data), jni_thread_wrapper(FROM_HERE, cb)));
}
void SetPeriodicAdvertisingEnable(int advertiser_id, bool enable,
@@ -241,10 +241,10 @@
<< " ,enable: " << enable;
if (!BleAdvertisingManager::IsInitialized()) return;
- do_in_bta_thread(FROM_HERE,
- Bind(&BleAdvertisingManager::SetPeriodicAdvertisingEnable,
- BleAdvertisingManager::Get(), advertiser_id, enable,
- jni_thread_wrapper(FROM_HERE, cb)));
+ do_in_main_thread(FROM_HERE,
+ Bind(&BleAdvertisingManager::SetPeriodicAdvertisingEnable,
+ BleAdvertisingManager::Get(), advertiser_id, enable,
+ jni_thread_wrapper(FROM_HERE, cb)));
}
};
diff --git a/btif/src/btif_ble_scanner.cc b/btif/src/btif_ble_scanner.cc
index 2587c8d..b314993 100644
--- a/btif/src/btif_ble_scanner.cc
+++ b/btif/src/btif_ble_scanner.cc
@@ -35,7 +35,6 @@
#include "advertise_data_parser.h"
#include "bta_api.h"
-#include "bta_closure_api.h"
#include "bta_gatt_api.h"
#include "btif_config.h"
#include "btif_dm.h"
@@ -43,6 +42,7 @@
#include "btif_gatt_util.h"
#include "btif_storage.h"
#include "osi/include/log.h"
+#include "stack/include/btu.h"
#include "vendor_api.h"
using base::Bind;
@@ -70,7 +70,7 @@
std::queue<RawAddress> remote_bdaddr_cache_ordered;
const size_t remote_bdaddr_cache_max_size = 1024;
-void btif_gattc_add_remote_bdaddr(const RawAddress& p_bda, uint8_t addr_type) {
+void btif_address_cache_add(const RawAddress& p_bda, uint8_t addr_type) {
// Remove the oldest entries
while (remote_bdaddr_cache.size() >= remote_bdaddr_cache_max_size) {
const RawAddress& raw_address = remote_bdaddr_cache_ordered.front();
@@ -81,11 +81,11 @@
remote_bdaddr_cache_ordered.push(p_bda);
}
-bool btif_gattc_find_bdaddr(const RawAddress& p_bda) {
+bool btif_address_cache_find(const RawAddress& p_bda) {
return (remote_bdaddr_cache.find(p_bda) != remote_bdaddr_cache.end());
}
-void btif_gattc_init_dev_cb(void) {
+void btif_address_cache_init(void) {
remote_bdaddr_cache.clear();
remote_bdaddr_cache_ordered = {};
}
@@ -121,8 +121,8 @@
}
if ((addr_type != BLE_ADDR_RANDOM) || (p_eir_remote_name)) {
- if (!btif_gattc_find_bdaddr(bd_addr)) {
- btif_gattc_add_remote_bdaddr(bd_addr, addr_type);
+ if (!btif_address_cache_find(bd_addr)) {
+ btif_address_cache_add(bd_addr, addr_type);
if (p_eir_remote_name) {
if (remote_name_len > BD_NAME_LEN + 1 ||
@@ -203,34 +203,34 @@
void bta_cback(tBTA_GATTC_EVT, tBTA_GATTC*) {}
class BleScannerInterfaceImpl : public BleScannerInterface {
- ~BleScannerInterfaceImpl(){};
+ ~BleScannerInterfaceImpl() override{};
void RegisterScanner(RegisterCallback cb) override {
- do_in_bta_thread(FROM_HERE,
- Bind(
- [](RegisterCallback cb) {
- BTA_GATTC_AppRegister(
- bta_cback,
- jni_thread_wrapper(FROM_HERE, std::move(cb)));
- },
- std::move(cb)));
+ do_in_main_thread(FROM_HERE,
+ Bind(
+ [](RegisterCallback cb) {
+ BTA_GATTC_AppRegister(
+ bta_cback,
+ jni_thread_wrapper(FROM_HERE, std::move(cb)));
+ },
+ std::move(cb)));
}
void Unregister(int scanner_id) override {
- do_in_bta_thread(FROM_HERE, Bind(&BTA_GATTC_AppDeregister, scanner_id));
+ do_in_main_thread(FROM_HERE, Bind(&BTA_GATTC_AppDeregister, scanner_id));
}
void Scan(bool start) override {
do_in_jni_thread(Bind(
[](bool start) {
if (!start) {
- do_in_bta_thread(FROM_HERE,
- Bind(&BTA_DmBleObserve, false, 0, nullptr));
+ do_in_main_thread(FROM_HERE,
+ Bind(&BTA_DmBleObserve, false, 0, nullptr));
return;
}
- btif_gattc_init_dev_cb();
- do_in_bta_thread(
+ btif_address_cache_init();
+ do_in_main_thread(
FROM_HERE, Bind(&BTA_DmBleObserve, true, 0, bta_scan_results_cb));
},
start));
@@ -243,22 +243,22 @@
BTIF_TRACE_DEBUG("%s", __func__);
if (filt_param && filt_param->dely_mode == 1) {
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE, base::Bind(BTM_BleTrackAdvertiser, bta_track_adv_event_cb,
client_if));
}
- do_in_bta_thread(FROM_HERE,
- base::Bind(&BTM_BleAdvFilterParamSetup, action, filt_index,
- base::Passed(&filt_param),
- jni_thread_wrapper(FROM_HERE, std::move(cb))));
+ do_in_main_thread(
+ FROM_HERE, base::Bind(&BTM_BleAdvFilterParamSetup, action, filt_index,
+ base::Passed(&filt_param),
+ jni_thread_wrapper(FROM_HERE, std::move(cb))));
}
void ScanFilterAdd(int filter_index, std::vector<ApcfCommand> filters,
FilterConfigCallback cb) override {
BTIF_TRACE_DEBUG("%s: %d", __func__, filter_index);
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE,
base::Bind(
&BTM_LE_PF_set, filter_index, std::move(filters),
@@ -270,24 +270,24 @@
void ScanFilterClear(int filter_index, FilterConfigCallback cb) override {
BTIF_TRACE_DEBUG("%s: filter_index: %d", __func__, filter_index);
- do_in_bta_thread(FROM_HERE,
- base::Bind(&BTM_LE_PF_clear, filter_index,
- jni_thread_wrapper(
- FROM_HERE, Bind(cb, BTM_BLE_PF_TYPE_ALL))));
+ do_in_main_thread(
+ FROM_HERE, base::Bind(&BTM_LE_PF_clear, filter_index,
+ jni_thread_wrapper(
+ FROM_HERE, Bind(cb, BTM_BLE_PF_TYPE_ALL))));
}
void ScanFilterEnable(bool enable, EnableCallback cb) override {
BTIF_TRACE_DEBUG("%s: enable: %d", __func__, enable);
uint8_t action = enable ? 1 : 0;
- do_in_bta_thread(FROM_HERE,
- base::Bind(&BTM_BleEnableDisableFilterFeature, action,
- jni_thread_wrapper(FROM_HERE, std::move(cb))));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(&BTM_BleEnableDisableFilterFeature, action,
+ jni_thread_wrapper(FROM_HERE, std::move(cb))));
}
void SetScanParameters(int scan_interval, int scan_window,
Callback cb) override {
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE, base::Bind(&BTM_BleSetScanParams, scan_interval, scan_window,
BTM_BLE_SCAN_MODE_ACTI,
jni_thread_wrapper(FROM_HERE, std::move(cb))));
@@ -297,7 +297,7 @@
int batch_scan_trunc_max,
int batch_scan_notify_threshold,
Callback cb) override {
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE,
base::Bind(&BTM_BleSetStorageConfig, (uint8_t)batch_scan_full_max,
(uint8_t)batch_scan_trunc_max,
@@ -308,21 +308,21 @@
void BatchscanEnable(int scan_mode, int scan_interval, int scan_window,
int addr_type, int discard_rule, Callback cb) override {
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE, base::Bind(&BTM_BleEnableBatchScan, scan_mode, scan_interval,
scan_window, discard_rule, addr_type,
jni_thread_wrapper(FROM_HERE, cb)));
}
void BatchscanDisable(Callback cb) override {
- do_in_bta_thread(FROM_HERE, base::Bind(&BTM_BleDisableBatchScan,
- jni_thread_wrapper(FROM_HERE, cb)));
+ do_in_main_thread(FROM_HERE, base::Bind(&BTM_BleDisableBatchScan,
+ jni_thread_wrapper(FROM_HERE, cb)));
}
void BatchscanReadReports(int client_if, int scan_mode) override {
- do_in_bta_thread(FROM_HERE,
- base::Bind(&BTM_BleReadScanReports, (uint8_t)scan_mode,
- Bind(bta_batch_scan_reports_cb, client_if)));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(&BTM_BleReadScanReports, (uint8_t)scan_mode,
+ Bind(bta_batch_scan_reports_cb, client_if)));
}
void StartSync(uint8_t sid, RawAddress address, uint16_t skip,
diff --git a/btif/src/btif_bqr.cc b/btif/src/btif_bqr.cc
new file mode 100644
index 0000000..17253c5
--- /dev/null
+++ b/btif/src/btif_bqr.cc
@@ -0,0 +1,326 @@
+/*
+ * Copyright 2019 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 <statslog.h>
+
+#include "btif_bqr.h"
+#include "btif_dm.h"
+#include "common/leaky_bonded_queue.h"
+#include "osi/include/properties.h"
+#include "stack/btm/btm_int.h"
+
+namespace bluetooth {
+namespace bqr {
+
+using bluetooth::common::LeakyBondedQueue;
+using std::chrono::system_clock;
+
+// The instance of BQR event queue
+static std::unique_ptr<LeakyBondedQueue<BqrVseSubEvt>> kpBqrEventQueue(
+ new LeakyBondedQueue<BqrVseSubEvt>(kBqrEventQueueSize));
+
+bool BqrVseSubEvt::ParseBqrEvt(uint8_t length, uint8_t* p_param_buf) {
+ if (length < kBqrParamTotalLen) {
+ LOG(FATAL) << __func__
+ << ": Parameter total length: " << std::to_string(length)
+ << " is abnormal. It shall be not shorter than: "
+ << std::to_string(kBqrParamTotalLen);
+ return false;
+ }
+
+ STREAM_TO_UINT8(quality_report_id_, p_param_buf);
+ STREAM_TO_UINT8(packet_types_, p_param_buf);
+ STREAM_TO_UINT16(connection_handle_, p_param_buf);
+ STREAM_TO_UINT8(connection_role_, p_param_buf);
+ STREAM_TO_UINT8(tx_power_level_, p_param_buf);
+ STREAM_TO_INT8(rssi_, p_param_buf);
+ STREAM_TO_UINT8(snr_, p_param_buf);
+ STREAM_TO_UINT8(unused_afh_channel_count_, p_param_buf);
+ STREAM_TO_UINT8(afh_select_unideal_channel_count_, p_param_buf);
+ STREAM_TO_UINT16(lsto_, p_param_buf);
+ STREAM_TO_UINT32(connection_piconet_clock_, p_param_buf);
+ STREAM_TO_UINT32(retransmission_count_, p_param_buf);
+ STREAM_TO_UINT32(no_rx_count_, p_param_buf);
+ STREAM_TO_UINT32(nak_count_, p_param_buf);
+ STREAM_TO_UINT32(last_tx_ack_timestamp_, p_param_buf);
+ STREAM_TO_UINT32(flow_off_count_, p_param_buf);
+ STREAM_TO_UINT32(last_flow_on_timestamp_, p_param_buf);
+ STREAM_TO_UINT32(buffer_overflow_bytes_, p_param_buf);
+ STREAM_TO_UINT32(buffer_underflow_bytes_, p_param_buf);
+
+ const auto now = system_clock::to_time_t(system_clock::now());
+ localtime_r(&now, &tm_timestamp_);
+
+ return true;
+}
+
+std::string BqrVseSubEvt::ToString() const {
+ std::stringstream ss_return_string;
+ ss_return_string << QualityReportIdToString(quality_report_id_)
+ << ", Handle: " << loghex(connection_handle_) << ", "
+ << PacketTypeToString(packet_types_) << ", "
+ << ((connection_role_ == 0) ? "Master" : "Slave ")
+ << ", PwLv: " << loghex(tx_power_level_)
+ << ", RSSI: " << std::to_string(rssi_)
+ << ", SNR: " << std::to_string(snr_) << ", UnusedCh: "
+ << std::to_string(unused_afh_channel_count_)
+ << ", UnidealCh: "
+ << std::to_string(afh_select_unideal_channel_count_)
+ << ", ReTx: " << std::to_string(retransmission_count_)
+ << ", NoRX: " << std::to_string(no_rx_count_)
+ << ", NAK: " << std::to_string(nak_count_)
+ << ", FlowOff: " << std::to_string(flow_off_count_)
+ << ", OverFlow: " << std::to_string(buffer_overflow_bytes_)
+ << ", UndFlow: " << std::to_string(buffer_underflow_bytes_);
+ return ss_return_string.str();
+}
+
+std::string QualityReportIdToString(uint8_t quality_report_id) {
+ switch (quality_report_id) {
+ case QUALITY_REPORT_ID_MONITOR_MODE:
+ return "Monitoring ";
+ case QUALITY_REPORT_ID_APPROACH_LSTO:
+ return "Appro LSTO ";
+ case QUALITY_REPORT_ID_A2DP_AUDIO_CHOPPY:
+ return "A2DP Choppy";
+ case QUALITY_REPORT_ID_SCO_VOICE_CHOPPY:
+ return "SCO Choppy ";
+ default:
+ return "Invalid ";
+ }
+}
+
+std::string PacketTypeToString(uint8_t packet_type) {
+ switch (packet_type) {
+ case PACKET_TYPE_ID:
+ return "ID";
+ case PACKET_TYPE_NULL:
+ return "NULL";
+ case PACKET_TYPE_POLL:
+ return "POLL";
+ case PACKET_TYPE_FHS:
+ return "FHS";
+ case PACKET_TYPE_HV1:
+ return "HV1";
+ case PACKET_TYPE_HV2:
+ return "HV2";
+ case PACKET_TYPE_HV3:
+ return "HV3";
+ case PACKET_TYPE_DV:
+ return "DV";
+ case PACKET_TYPE_EV3:
+ return "EV3";
+ case PACKET_TYPE_EV4:
+ return "EV4";
+ case PACKET_TYPE_EV5:
+ return "EV5";
+ case PACKET_TYPE_2EV3:
+ return "2EV3";
+ case PACKET_TYPE_2EV5:
+ return "2EV5";
+ case PACKET_TYPE_3EV3:
+ return "3EV3";
+ case PACKET_TYPE_3EV5:
+ return "3EV5";
+ case PACKET_TYPE_DM1:
+ return "DM1";
+ case PACKET_TYPE_DH1:
+ return "DH1";
+ case PACKET_TYPE_DM3:
+ return "DM3";
+ case PACKET_TYPE_DH3:
+ return "DH3";
+ case PACKET_TYPE_DM5:
+ return "DM5";
+ case PACKET_TYPE_DH5:
+ return "DH5";
+ case PACKET_TYPE_AUX1:
+ return "AUX1";
+ case PACKET_TYPE_2DH1:
+ return "2DH1";
+ case PACKET_TYPE_2DH3:
+ return "2DH3";
+ case PACKET_TYPE_2DH5:
+ return "2DH5";
+ case PACKET_TYPE_3DH1:
+ return "3DH1";
+ case PACKET_TYPE_3DH3:
+ return "3DH3";
+ case PACKET_TYPE_3DH5:
+ return "3DH5";
+ default:
+ return "UnKnown ";
+ }
+}
+
+void AddBqrEventToQueue(uint8_t length, uint8_t* p_stream) {
+ std::unique_ptr<BqrVseSubEvt> p_bqr_event = std::make_unique<BqrVseSubEvt>();
+ if (!p_bqr_event->ParseBqrEvt(length, p_stream)) {
+ LOG(WARNING) << __func__ << ": Fail to parse BQR sub event.";
+ return;
+ }
+
+ LOG(WARNING) << *p_bqr_event;
+ int ret = android::util::stats_write(
+ android::util::BLUETOOTH_QUALITY_REPORT_REPORTED,
+ p_bqr_event->quality_report_id_, p_bqr_event->packet_types_,
+ p_bqr_event->connection_handle_, p_bqr_event->connection_role_,
+ p_bqr_event->tx_power_level_, p_bqr_event->rssi_, p_bqr_event->snr_,
+ p_bqr_event->unused_afh_channel_count_,
+ p_bqr_event->afh_select_unideal_channel_count_, p_bqr_event->lsto_,
+ p_bqr_event->connection_piconet_clock_,
+ p_bqr_event->retransmission_count_, p_bqr_event->no_rx_count_,
+ p_bqr_event->nak_count_, p_bqr_event->last_tx_ack_timestamp_,
+ p_bqr_event->flow_off_count_, p_bqr_event->last_flow_on_timestamp_,
+ p_bqr_event->buffer_overflow_bytes_,
+ p_bqr_event->buffer_underflow_bytes_);
+ if (ret < 0) {
+ LOG(WARNING) << __func__ << ": failed to log BQR event to statsd, error "
+ << ret;
+ }
+ kpBqrEventQueue->Enqueue(p_bqr_event.release());
+}
+
+void ConfigureBqrCmpl(uint32_t current_evt_mask) {
+ LOG(INFO) << __func__ << ": current_evt_mask: " << loghex(current_evt_mask);
+ // (Un)Register for VSE of Bluetooth Quality Report sub event
+ tBTM_STATUS btm_status = BTM_BT_Quality_Report_VSE_Register(
+ current_evt_mask > kQualityEventMaskAllOff, AddBqrEventToQueue);
+
+ if (btm_status != BTM_SUCCESS) {
+ LOG(ERROR) << __func__ << ": Fail to (un)register VSE of BQR sub event."
+ << " status: " << btm_status;
+ }
+}
+
+void EnableBtQualityReport(bool is_enable) {
+ LOG(INFO) << __func__ << ": is_enable: " << logbool(is_enable);
+
+ char bqr_prop_evtmask[PROPERTY_VALUE_MAX] = {0};
+ char bqr_prop_interval_ms[PROPERTY_VALUE_MAX] = {0};
+ osi_property_get(kpPropertyEventMask, bqr_prop_evtmask, "");
+ osi_property_get(kpPropertyMinReportIntervalMs, bqr_prop_interval_ms, "");
+
+ if (strlen(bqr_prop_evtmask) == 0 || strlen(bqr_prop_interval_ms) == 0) {
+ LOG(WARNING) << __func__ << ": Bluetooth Quality Report is disabled."
+ << " bqr_prop_evtmask: " << bqr_prop_evtmask
+ << ", bqr_prop_interval_ms: " << bqr_prop_interval_ms;
+ return;
+ }
+
+ BqrConfiguration bqr_config = {};
+
+ if (is_enable) {
+ bqr_config.report_action = REPORT_ACTION_ADD;
+ bqr_config.quality_event_mask =
+ static_cast<uint32_t>(atoi(bqr_prop_evtmask));
+ bqr_config.minimum_report_interval_ms =
+ static_cast<uint16_t>(atoi(bqr_prop_interval_ms));
+ } else {
+ bqr_config.report_action = REPORT_ACTION_CLEAR;
+ bqr_config.quality_event_mask = kQualityEventMaskAllOff;
+ bqr_config.minimum_report_interval_ms = kMinReportIntervalNoLimit;
+ }
+
+ LOG(INFO) << __func__
+ << ": Event Mask: " << loghex(bqr_config.quality_event_mask)
+ << ", Interval: " << bqr_config.minimum_report_interval_ms;
+ ConfigureBqr(bqr_config);
+}
+
+void BqrVscCompleteCallback(tBTM_VSC_CMPL* p_vsc_cmpl_params) {
+ if (p_vsc_cmpl_params->param_len < 1) {
+ LOG(ERROR) << __func__ << ": The length of returned parameters is less than 1";
+ return;
+ }
+
+ uint8_t* p_event_param_buf = p_vsc_cmpl_params->p_param_buf;
+ uint8_t status = 0xff;
+ // [Return Parameter] | [Size] | [Purpose]
+ // Status | 1 octet | Command complete status
+ // Current_Quality_Event_Mask | 4 octets | Indicates current bit mask setting
+ STREAM_TO_UINT8(status, p_event_param_buf);
+ if (status != HCI_SUCCESS) {
+ LOG(ERROR) << __func__ << ": Fail to configure BQR. status: " << loghex(status);
+ return;
+ }
+
+ if (p_vsc_cmpl_params->param_len != 5) {
+ LOG(FATAL) << __func__
+ << ": The length of returned parameters is not equal to 5: "
+ << std::to_string(p_vsc_cmpl_params->param_len);
+ return;
+ }
+
+ uint32_t current_quality_event_mask = kQualityEventMaskAllOff;
+ STREAM_TO_UINT32(current_quality_event_mask, p_event_param_buf);
+
+ LOG(INFO) << __func__
+ << ", current event mask: " << loghex(current_quality_event_mask);
+ ConfigureBqrCmpl(current_quality_event_mask);
+}
+
+void ConfigureBqr(const BqrConfiguration& bqr_config) {
+ if (bqr_config.report_action > REPORT_ACTION_CLEAR ||
+ bqr_config.quality_event_mask > kQualityEventMaskAll ||
+ bqr_config.minimum_report_interval_ms > kMinReportIntervalMaxMs) {
+ LOG(FATAL) << __func__ << ": Invalid Parameter"
+ << ", Action: " << bqr_config.report_action
+ << ", Mask: " << loghex(bqr_config.quality_event_mask)
+ << ", Interval: " << bqr_config.minimum_report_interval_ms;
+ return;
+ }
+
+ LOG(INFO) << __func__ << ": Action: " << bqr_config.report_action
+ << ", Mask: " << loghex(bqr_config.quality_event_mask)
+ << ", Interval: " << bqr_config.minimum_report_interval_ms;
+
+ uint8_t param[sizeof(BqrConfiguration)];
+ uint8_t* p_param = param;
+ UINT8_TO_STREAM(p_param, bqr_config.report_action);
+ UINT32_TO_STREAM(p_param, bqr_config.quality_event_mask);
+ UINT16_TO_STREAM(p_param, bqr_config.minimum_report_interval_ms);
+
+ BTM_VendorSpecificCommand(HCI_CONTROLLER_BQR_OPCODE_OCF, p_param - param,
+ param, BqrVscCompleteCallback);
+}
+
+void DebugDump(int fd) {
+ dprintf(fd, "\nBT Quality Report Events: \n");
+
+ if (kpBqrEventQueue->Empty()) {
+ dprintf(fd, "Event queue is empty.\n");
+ return;
+ }
+
+ while (!kpBqrEventQueue->Empty()) {
+ std::unique_ptr<BqrVseSubEvt> p_event(kpBqrEventQueue->Dequeue());
+
+ bool warning = (p_event->rssi_ < kCriWarnRssi ||
+ p_event->unused_afh_channel_count_ > kCriWarnUnusedCh);
+
+ std::stringstream ss_timestamp;
+ ss_timestamp << std::put_time(&p_event->tm_timestamp_, "%m-%d %H:%M:%S");
+
+ dprintf(fd, "%c %s %s\n", warning ? '*' : ' ', ss_timestamp.str().c_str(),
+ p_event->ToString().c_str());
+ }
+
+ dprintf(fd, "\n");
+}
+
+} // namespace bqr
+} // namespace bluetooth
diff --git a/btif/src/btif_config.cc b/btif/src/btif_config.cc
index 3155dc6..c017c0f 100644
--- a/btif/src/btif_config.cc
+++ b/btif/src/btif_config.cc
@@ -22,6 +22,7 @@
#include <base/logging.h>
#include <ctype.h>
+#include <openssl/rand.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
@@ -36,6 +37,7 @@
#include "btif_common.h"
#include "btif_config_transcode.h"
#include "btif_util.h"
+#include "common/address_obfuscator.h"
#include "osi/include/alarm.h"
#include "osi/include/allocator.h"
#include "osi/include/compat.h"
@@ -52,6 +54,10 @@
#define TIME_STRING_LENGTH sizeof("YYYY-MM-DD HH:MM:SS")
static const char* TIME_STRING_FORMAT = "%Y-%m-%d %H:%M:%S";
+#define BT_CONFIG_METRICS_SECTION "Metrics"
+#define BT_CONFIG_METRICS_SALT_256BIT "Salt256Bit"
+using bluetooth::common::AddressObfuscator;
+
// 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";
@@ -63,7 +69,7 @@
static const char* CONFIG_LEGACY_FILE_PATH =
"/data/misc/bluedroid/bt_config.xml";
#endif // defined(OS_GENERIC)
-static const period_ms_t CONFIG_SETTLE_PERIOD_MS = 3000;
+static const uint64_t CONFIG_SETTLE_PERIOD_MS = 3000;
static void timer_config_save_cb(void* data);
static void btif_config_write(uint16_t event, char* p_param);
@@ -114,14 +120,48 @@
return true;
}
-static std::mutex config_lock; // protects operations on |config|.
+/**
+ * Read metrics salt from config file, if salt is invalid or does not exist,
+ * generate new one and save it to config
+ */
+static void read_or_set_metrics_salt() {
+ AddressObfuscator::Octet32 metrics_salt = {};
+ size_t metrics_salt_length = metrics_salt.size();
+ if (!btif_config_get_bin(BT_CONFIG_METRICS_SECTION,
+ BT_CONFIG_METRICS_SALT_256BIT, metrics_salt.data(),
+ &metrics_salt_length)) {
+ LOG(WARNING) << __func__ << ": Failed to read metrics salt from config";
+ // Invalidate salt
+ metrics_salt.fill(0);
+ }
+ if (metrics_salt_length != metrics_salt.size()) {
+ LOG(ERROR) << __func__ << ": Metrics salt length incorrect, "
+ << metrics_salt_length << " instead of " << metrics_salt.size();
+ // Invalidate salt
+ metrics_salt.fill(0);
+ }
+ if (!AddressObfuscator::IsSaltValid(metrics_salt)) {
+ LOG(INFO) << __func__ << ": Metrics salt is not invalid, creating new one";
+ if (RAND_bytes(metrics_salt.data(), metrics_salt.size()) != 1) {
+ LOG(FATAL) << __func__ << "Failed to generate salt for metrics";
+ }
+ if (!btif_config_set_bin(BT_CONFIG_METRICS_SECTION,
+ BT_CONFIG_METRICS_SALT_256BIT, metrics_salt.data(),
+ metrics_salt.size())) {
+ LOG(FATAL) << __func__ << "Failed to write metrics salt to config";
+ }
+ }
+ AddressObfuscator::GetInstance()->Initialize(metrics_salt);
+}
+
+static std::recursive_mutex config_lock; // protects operations on |config|.
static std::unique_ptr<config_t> config;
static alarm_t* config_timer;
// Module lifecycle functions
static future_t* init(void) {
- std::unique_lock<std::mutex> lock(config_lock);
+ std::unique_lock<std::recursive_mutex> lock(config_lock);
if (is_factory_reset()) delete_config_files();
@@ -175,6 +215,9 @@
btif_config_time_created);
}
+ // Read or set metrics 256 bit hashing salt
+ read_or_set_metrics_salt();
+
// TODO(sharvil): use a non-wake alarm for this once we have
// API support for it. There's no need to wake the system to
// write back to disk.
@@ -219,7 +262,7 @@
alarm_free(config_timer);
config_timer = NULL;
- std::unique_lock<std::mutex> lock(config_lock);
+ std::unique_lock<std::recursive_mutex> lock(config_lock);
config.reset();
return future_new_immediate(FUTURE_SUCCESS);
}
@@ -234,14 +277,14 @@
CHECK(config != NULL);
CHECK(section != NULL);
- std::unique_lock<std::mutex> lock(config_lock);
+ std::unique_lock<std::recursive_mutex> lock(config_lock);
return config_has_section(*config, section);
}
bool btif_config_exist(const std::string& section, const std::string& key) {
CHECK(config != NULL);
- std::unique_lock<std::mutex> lock(config_lock);
+ std::unique_lock<std::recursive_mutex> lock(config_lock);
return config_has_key(*config, section, key);
}
@@ -250,7 +293,7 @@
CHECK(config != NULL);
CHECK(value != NULL);
- std::unique_lock<std::mutex> lock(config_lock);
+ std::unique_lock<std::recursive_mutex> lock(config_lock);
bool ret = config_has_key(*config, section, key);
if (ret) *value = config_get_int(*config, section, key, *value);
@@ -261,7 +304,7 @@
int value) {
CHECK(config != NULL);
- std::unique_lock<std::mutex> lock(config_lock);
+ std::unique_lock<std::recursive_mutex> lock(config_lock);
config_set_int(config.get(), section, key, value);
return true;
@@ -272,7 +315,7 @@
CHECK(config != NULL);
CHECK(value != NULL);
- std::unique_lock<std::mutex> lock(config_lock);
+ std::unique_lock<std::recursive_mutex> lock(config_lock);
bool ret = config_has_key(*config, section, key);
if (ret) *value = config_get_uint64(*config, section, key, *value);
@@ -283,7 +326,7 @@
uint64_t value) {
CHECK(config != NULL);
- std::unique_lock<std::mutex> lock(config_lock);
+ std::unique_lock<std::recursive_mutex> lock(config_lock);
config_set_uint64(config.get(), section, key, value);
return true;
@@ -296,7 +339,7 @@
CHECK(size_bytes != NULL);
{
- std::unique_lock<std::mutex> lock(config_lock);
+ std::unique_lock<std::recursive_mutex> lock(config_lock);
const std::string* stored_value =
config_get_string(*config, section, key, NULL);
if (!stored_value) return false;
@@ -311,7 +354,7 @@
const std::string& value) {
CHECK(config != NULL);
- std::unique_lock<std::mutex> lock(config_lock);
+ std::unique_lock<std::recursive_mutex> lock(config_lock);
config_set_string(config.get(), section, key, value);
return true;
}
@@ -322,16 +365,26 @@
CHECK(value != NULL);
CHECK(length != NULL);
- std::unique_lock<std::mutex> lock(config_lock);
+ std::unique_lock<std::recursive_mutex> lock(config_lock);
const std::string* value_str = config_get_string(*config, section, key, NULL);
- if (!value_str) return false;
+ if (!value_str) {
+ VLOG(1) << __func__ << ": cannot find string for section " << section
+ << ", key " << key;
+ return false;
+ }
size_t value_len = value_str->length();
- if ((value_len % 2) != 0 || *length < (value_len / 2)) return false;
+ if ((value_len % 2) != 0 || *length < (value_len / 2)) {
+ LOG(WARNING) << ": value size not divisible by 2, size is " << value_len;
+ return false;
+ }
for (size_t i = 0; i < value_len; ++i)
- if (!isxdigit(value_str->c_str()[i])) return false;
+ if (!isxdigit(value_str->c_str()[i])) {
+ LOG(WARNING) << ": value is not hex digit";
+ return false;
+ }
const char* ptr = value_str->c_str();
for (*length = 0; *ptr; ptr += 2, *length += 1)
@@ -344,7 +397,7 @@
const std::string& key) {
CHECK(config != NULL);
- std::unique_lock<std::mutex> lock(config_lock);
+ std::unique_lock<std::recursive_mutex> lock(config_lock);
const std::string* value_str = config_get_string(*config, section, key, NULL);
if (!value_str) return 0;
@@ -368,7 +421,7 @@
}
{
- std::unique_lock<std::mutex> lock(config_lock);
+ std::unique_lock<std::recursive_mutex> lock(config_lock);
config_set_string(config.get(), section, key, str);
}
@@ -381,7 +434,7 @@
bool btif_config_remove(const std::string& section, const std::string& key) {
CHECK(config != NULL);
- std::unique_lock<std::mutex> lock(config_lock);
+ std::unique_lock<std::recursive_mutex> lock(config_lock);
return config_remove_key(config.get(), section, key);
}
@@ -406,7 +459,7 @@
alarm_cancel(config_timer);
- std::unique_lock<std::mutex> lock(config_lock);
+ std::unique_lock<std::recursive_mutex> lock(config_lock);
config = config_new_empty();
@@ -427,7 +480,7 @@
CHECK(config != NULL);
CHECK(config_timer != NULL);
- std::unique_lock<std::mutex> lock(config_lock);
+ std::unique_lock<std::recursive_mutex> lock(config_lock);
rename(CONFIG_FILE_PATH, CONFIG_BACKUP_PATH);
std::unique_ptr<config_t> config_paired = config_new_clone(*config);
btif_config_remove_unpaired(config_paired.get());
diff --git a/btif/src/btif_core.cc b/btif/src/btif_core.cc
index 582ae47..aa77979 100644
--- a/btif/src/btif_core.cc
+++ b/btif/src/btif_core.cc
@@ -46,7 +46,6 @@
#include "bt_common.h"
#include "bt_utils.h"
#include "bta_api.h"
-#include "bta_closure_api.h"
#include "bte.h"
#include "btif_api.h"
#include "btif_av.h"
@@ -58,17 +57,18 @@
#include "btif_uid.h"
#include "btif_util.h"
#include "btu.h"
+#include "common/message_loop_thread.h"
#include "device/include/controller.h"
#include "osi/include/fixed_queue.h"
#include "osi/include/future.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
#include "osi/include/properties.h"
-#include "osi/include/thread.h"
#include "stack_manager.h"
using base::PlatformThread;
using bluetooth::Uuid;
+using bluetooth::common::MessageLoopThread;
/*******************************************************************************
* Constants & Macros
@@ -128,12 +128,9 @@
*/
static uint8_t btif_dut_mode = 0;
-static thread_t* bt_jni_workqueue_thread;
-static const char* BT_JNI_WORKQUEUE_NAME = "bt_jni_workqueue";
-static uid_set_t* uid_set = NULL;
-base::MessageLoop* message_loop_ = NULL;
-base::RunLoop* jni_run_loop = NULL;
-static base::PlatformThreadId btif_thread_id_ = -1;
+static MessageLoopThread jni_thread("bt_jni_thread");
+static base::AtExitManager* exit_manager;
+static uid_set_t* uid_set;
/*******************************************************************************
* Static functions
@@ -223,36 +220,24 @@
* This function posts a task into the btif message loop, that executes it in
* the JNI message loop.
**/
-bt_status_t do_in_jni_thread(const tracked_objects::Location& from_here,
- const base::Closure& task) {
- if (!message_loop_) {
- BTIF_TRACE_WARNING("%s: Dropped message, message_loop not initialized yet!",
- __func__);
+bt_status_t do_in_jni_thread(const base::Location& from_here,
+ base::OnceClosure task) {
+ if (!jni_thread.DoInThread(from_here, std::move(task))) {
+ LOG(ERROR) << __func__ << ": Post task to task runner failed!";
return BT_STATUS_FAIL;
}
-
- scoped_refptr<base::SingleThreadTaskRunner> task_runner =
- message_loop_->task_runner();
- if (!task_runner.get()) {
- BTIF_TRACE_WARNING("%s: task runner is dead", __func__);
- return BT_STATUS_FAIL;
- }
-
- if (task_runner->PostTask(from_here, task)) return BT_STATUS_SUCCESS;
-
- BTIF_TRACE_ERROR("%s: Post task to task runner failed!", __func__);
- return BT_STATUS_FAIL;
+ return BT_STATUS_SUCCESS;
}
-bt_status_t do_in_jni_thread(const base::Closure& task) {
- return do_in_jni_thread(FROM_HERE, task);
+bt_status_t do_in_jni_thread(base::OnceClosure task) {
+ return do_in_jni_thread(FROM_HERE, std::move(task));
}
bool is_on_jni_thread() {
- return btif_thread_id_ == PlatformThread::CurrentId();
+ return jni_thread.GetThreadId() == PlatformThread::CurrentId();
}
-base::MessageLoop* get_jni_message_loop() { return message_loop_; }
+base::MessageLoop* get_jni_message_loop() { return jni_thread.message_loop(); }
/*******************************************************************************
*
@@ -260,11 +245,11 @@
*
* Description checks if BTIF is currently in DUT mode
*
- * Returns 1 if test mode, otherwize 0
+ * Returns true if test mode, otherwise false
*
******************************************************************************/
-uint8_t btif_is_dut_mode(void) { return (btif_dut_mode == 1); }
+bool btif_is_dut_mode() { return btif_dut_mode == 1; }
/*******************************************************************************
*
@@ -327,38 +312,6 @@
do_in_jni_thread(base::Bind(&bt_jni_msg_ready, p_msg));
}
-void btif_thread_post(thread_fn func, void* context) {
- do_in_jni_thread(base::Bind(func, context));
-}
-
-void run_message_loop(UNUSED_ATTR void* context) {
- LOG_INFO(LOG_TAG, "%s entered", __func__);
- btif_thread_id_ = PlatformThread::CurrentId();
-
- // TODO(jpawlowski): exit_manager should be defined in main(), but there is no
- // main method.
- // It is therefore defined in bt_jni_workqueue_thread, and will be deleted
- // when we free it.
- base::AtExitManager exit_manager;
-
- message_loop_ = new base::MessageLoop(base::MessageLoop::Type::TYPE_DEFAULT);
-
- // Associate this workqueue thread with JNI.
- message_loop_->task_runner()->PostTask(FROM_HERE,
- base::Bind(&btif_jni_associate));
-
- jni_run_loop = new base::RunLoop();
- jni_run_loop->Run();
-
- delete message_loop_;
- message_loop_ = NULL;
-
- delete jni_run_loop;
- jni_run_loop = NULL;
-
- btif_thread_id_ = -1;
- LOG_INFO(LOG_TAG, "%s finished", __func__);
-}
/*******************************************************************************
*
* Function btif_init_bluetooth
@@ -370,27 +323,12 @@
******************************************************************************/
bt_status_t btif_init_bluetooth() {
LOG_INFO(LOG_TAG, "%s entered", __func__);
-
+ exit_manager = new base::AtExitManager();
bte_main_boot_entry();
-
- bt_jni_workqueue_thread = thread_new(BT_JNI_WORKQUEUE_NAME);
- if (bt_jni_workqueue_thread == NULL) {
- LOG_ERROR(LOG_TAG, "%s Unable to create thread %s", __func__,
- BT_JNI_WORKQUEUE_NAME);
- goto error_exit;
- }
-
- thread_post(bt_jni_workqueue_thread, run_message_loop, nullptr);
-
+ jni_thread.StartUp();
+ jni_thread.DoInThread(FROM_HERE, base::Bind(btif_jni_associate));
LOG_INFO(LOG_TAG, "%s finished", __func__);
return BT_STATUS_SUCCESS;
-
-error_exit:;
- thread_free(bt_jni_workqueue_thread);
-
- bt_jni_workqueue_thread = NULL;
-
- return BT_STATUS_FAIL;
}
/*******************************************************************************
@@ -475,10 +413,10 @@
* Returns void
*
******************************************************************************/
-bt_status_t btif_disable_bluetooth(void) {
+bt_status_t btif_disable_bluetooth() {
LOG_INFO(LOG_TAG, "%s entered", __func__);
- do_in_bta_thread(FROM_HERE, base::Bind(&btm_ble_multi_adv_cleanup));
+ do_in_main_thread(FROM_HERE, base::Bind(&btm_ble_multi_adv_cleanup));
// TODO(jpawlowski): this should do whole BTA_VendorCleanup(), but it would
// kill the stack now.
@@ -505,7 +443,7 @@
*
******************************************************************************/
-void btif_disable_bluetooth_evt(void) {
+void btif_disable_bluetooth_evt() {
LOG_INFO(LOG_TAG, "%s entered", __func__);
bte_main_disable();
@@ -526,29 +464,18 @@
*
******************************************************************************/
-bt_status_t btif_cleanup_bluetooth(void) {
+bt_status_t btif_cleanup_bluetooth() {
LOG_INFO(LOG_TAG, "%s entered", __func__);
-
- do_in_bta_thread(FROM_HERE, base::Bind(&BTA_VendorCleanup));
-
+ do_in_main_thread(FROM_HERE, base::Bind(&BTA_VendorCleanup));
btif_dm_cleanup();
- btif_jni_disassociate();
+ jni_thread.DoInThread(FROM_HERE, base::BindOnce(btif_jni_disassociate));
btif_queue_release();
-
- if (jni_run_loop && message_loop_) {
- message_loop_->task_runner()->PostTask(FROM_HERE,
- jni_run_loop->QuitClosure());
- }
-
- thread_free(bt_jni_workqueue_thread);
- bt_jni_workqueue_thread = NULL;
-
+ jni_thread.ShutDown();
bte_main_cleanup();
-
+ delete exit_manager;
+ exit_manager = nullptr;
btif_dut_mode = 0;
-
LOG_INFO(LOG_TAG, "%s finished", __func__);
-
return BT_STATUS_SUCCESS;
}
@@ -620,7 +547,8 @@
****************************************************************************/
static bt_status_t btif_in_get_adapter_properties(void) {
- bt_property_t properties[6];
+ const static uint32_t NUM_ADAPTER_PROPERTIES = 8;
+ bt_property_t properties[NUM_ADAPTER_PROPERTIES];
uint32_t num_props = 0;
RawAddress addr;
@@ -630,6 +558,8 @@
RawAddress bonded_devices[BTM_SEC_MAX_DEVICE_RECORDS];
Uuid local_uuids[BT_MAX_NUM_UUIDS];
bt_status_t status;
+ bt_io_cap_t local_bt_io_cap;
+ bt_io_cap_t local_bt_io_cap_ble;
/* RawAddress */
BTIF_STORAGE_FILL_PROPERTY(&properties[num_props], BT_PROPERTY_BDADDR,
@@ -674,6 +604,18 @@
btif_storage_get_adapter_property(&properties[num_props]);
num_props++;
+ /* LOCAL IO Capabilities */
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_props], BT_PROPERTY_LOCAL_IO_CAPS,
+ sizeof(bt_io_cap_t), &local_bt_io_cap);
+ btif_storage_get_adapter_property(&properties[num_props]);
+ num_props++;
+
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_props],
+ BT_PROPERTY_LOCAL_IO_CAPS_BLE, sizeof(bt_io_cap_t),
+ &local_bt_io_cap_ble);
+ btif_storage_get_adapter_property(&properties[num_props]);
+ num_props++;
+
HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, BT_STATUS_SUCCESS, num_props,
properties);
@@ -1024,6 +966,13 @@
* BTA events */
status = BT_STATUS_FAIL;
break;
+ case BT_PROPERTY_LOCAL_IO_CAPS:
+ case BT_PROPERTY_LOCAL_IO_CAPS_BLE: {
+ // Changing IO Capability of stack at run-time is not currently supported.
+ // This call changes the stored value which will affect the stack next
+ // time it starts up.
+ storage_req_id = BTIF_CORE_STORAGE_ADAPTER_WRITE;
+ } break;
default:
BTIF_TRACE_ERROR("btif_get_adapter_property : invalid type %d",
property->type);
diff --git a/btif/src/btif_debug_btsnoop.cc b/btif/src/btif_debug_btsnoop.cc
index 1dcb835..45fcade 100644
--- a/btif/src/btif_debug_btsnoop.cc
+++ b/btif/src/btif_debug_btsnoop.cc
@@ -27,7 +27,6 @@
#include "hci/include/btsnoop_mem.h"
#include "internal_include/bt_target.h"
#include "osi/include/ringbuffer.h"
-#include "osi/include/time.h"
#define REDUCE_HCI_TYPE_TO_SIGNIFICANT_BITS(type) ((type) >> 8)
@@ -123,9 +122,9 @@
case BT_EVT_TO_LM_HCI_SCO:
case BT_EVT_TO_BTU_HCI_SCO:
- // We're not logging SCO packets at this time since they are not currently
- // used.
- // FALLTHROUGH
+ // We're not logging SCO packets at this time since they are not currently
+ // used.
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
default:
return 0;
}
diff --git a/btif/src/btif_debug_conn.cc b/btif/src/btif_debug_conn.cc
index 6b4d96f..dc36c45 100644
--- a/btif/src/btif_debug_conn.cc
+++ b/btif/src/btif_debug_conn.cc
@@ -21,7 +21,7 @@
#include <time.h>
#include "btif/include/btif_debug_conn.h"
-#include "osi/include/time.h"
+#include "common/time_util.h"
#define NUM_CONNECTION_EVENTS 16
#define TEMP_BUFFER_SIZE 30
@@ -69,7 +69,7 @@
next_event();
conn_event_t* evt = &connection_events[current_event];
- evt->ts = time_gettimeofday_us();
+ evt->ts = bluetooth::common::time_gettimeofday_us();
evt->state = state;
evt->disconnect_reason = disconnect_reason;
evt->bda = bda;
diff --git a/btif/src/btif_dm.cc b/btif/src/btif_dm.cc
index dd9b813..683834a 100644
--- a/btif/src/btif_dm.cc
+++ b/btif/src/btif_dm.cc
@@ -47,10 +47,10 @@
#include "advertise_data_parser.h"
#include "bt_common.h"
-#include "bta_closure_api.h"
#include "bta_gatt_api.h"
#include "btif_api.h"
#include "btif_av.h"
+#include "btif_bqr.h"
#include "btif_config.h"
#include "btif_dm.h"
#include "btif_hd.h"
@@ -60,12 +60,12 @@
#include "btif_storage.h"
#include "btif_util.h"
#include "btu.h"
+#include "common/metrics.h"
#include "device/include/controller.h"
#include "device/include/interop.h"
#include "internal_include/stack_config.h"
#include "osi/include/allocator.h"
#include "osi/include/log.h"
-#include "osi/include/metrics.h"
#include "osi/include/osi.h"
#include "osi/include/properties.h"
#include "stack/btm/btm_int.h"
@@ -97,8 +97,9 @@
#define BTIF_DM_MAX_SDP_ATTEMPTS_AFTER_PAIRING 2
#define NUM_TIMEOUT_RETRIES 5
-
+#ifndef PROPERTY_PRODUCT_MODEL
#define PROPERTY_PRODUCT_MODEL "ro.product.model"
+#endif
#define DEFAULT_LOCAL_NAME_MAX 31
#if (DEFAULT_LOCAL_NAME_MAX > BTM_MAX_LOC_BD_NAME_LEN)
#error "default btif local name size exceeds stack supported length"
@@ -125,15 +126,17 @@
btif_dm_ble_cb_t ble;
} btif_dm_pairing_cb_t;
+// TODO(jpawlowski): unify ?
+// btif_dm_local_key_id_t == tBTM_BLE_LOCAL_ID_KEYS == tBTA_BLE_LOCAL_ID_KEYS
typedef struct {
- uint8_t ir[BT_OCTET16_LEN];
- uint8_t irk[BT_OCTET16_LEN];
- uint8_t dhk[BT_OCTET16_LEN];
+ Octet16 ir;
+ Octet16 irk;
+ Octet16 dhk;
} btif_dm_local_key_id_t;
typedef struct {
bool is_er_rcvd;
- uint8_t er[BT_OCTET16_LEN];
+ Octet16 er;
bool is_id_keys_rcvd;
btif_dm_local_key_id_t id_keys; /* ID kyes */
@@ -1153,7 +1156,7 @@
btif_dm_cb_create_bond(bd_addr, BTA_TRANSPORT_UNKNOWN);
return;
}
- /* Fall-through */
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case HCI_ERR_CONNECTION_TOUT:
status = BT_STATUS_RMT_DEV_DOWN;
break;
@@ -1336,7 +1339,7 @@
} break;
case BTA_DM_INQ_CMPL_EVT: {
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE,
base::Bind(&BTM_BleAdvFilterParamSetup, BTM_BLE_SCAN_COND_DELETE, 0,
nullptr, base::Bind(&bte_scan_filt_param_cfg_evt, 0)));
@@ -1358,7 +1361,7 @@
if (!btif_dm_inquiry_in_progress) {
btgatt_filt_param_setup_t adv_filt_param;
memset(&adv_filt_param, 0, sizeof(btgatt_filt_param_setup_t));
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE,
base::Bind(&BTM_BleAdvFilterParamSetup, BTM_BLE_SCAN_COND_DELETE, 0,
nullptr, base::Bind(&bte_scan_filt_param_cfg_evt, 0)));
@@ -1604,7 +1607,7 @@
** and bonded_devices_info_cb
*/
btif_storage_load_bonded_devices();
-
+ bluetooth::bqr::EnableBtQualityReport(true);
btif_enable_bluetooth_evt(p_data->enable.status);
} break;
@@ -1618,6 +1621,7 @@
btif_in_execute_service_request(i, false);
}
}
+ bluetooth::bqr::EnableBtQualityReport(false);
btif_disable_bluetooth_evt();
break;
@@ -1796,25 +1800,22 @@
case BTA_DM_BLE_LOCAL_IR_EVT:
BTIF_TRACE_DEBUG("BTA_DM_BLE_LOCAL_IR_EVT. ");
ble_local_key_cb.is_id_keys_rcvd = true;
- memcpy(&ble_local_key_cb.id_keys.irk[0], &p_data->ble_id_keys.irk[0],
- sizeof(BT_OCTET16));
- memcpy(&ble_local_key_cb.id_keys.ir[0], &p_data->ble_id_keys.ir[0],
- sizeof(BT_OCTET16));
- memcpy(&ble_local_key_cb.id_keys.dhk[0], &p_data->ble_id_keys.dhk[0],
- sizeof(BT_OCTET16));
- btif_storage_add_ble_local_key((char*)&ble_local_key_cb.id_keys.irk[0],
- BTIF_DM_LE_LOCAL_KEY_IRK, BT_OCTET16_LEN);
- btif_storage_add_ble_local_key((char*)&ble_local_key_cb.id_keys.ir[0],
- BTIF_DM_LE_LOCAL_KEY_IR, BT_OCTET16_LEN);
- btif_storage_add_ble_local_key((char*)&ble_local_key_cb.id_keys.dhk[0],
- BTIF_DM_LE_LOCAL_KEY_DHK, BT_OCTET16_LEN);
+ ble_local_key_cb.id_keys.irk = p_data->ble_id_keys.irk;
+ ble_local_key_cb.id_keys.ir = p_data->ble_id_keys.ir;
+ ble_local_key_cb.id_keys.dhk = p_data->ble_id_keys.dhk;
+ btif_storage_add_ble_local_key(ble_local_key_cb.id_keys.irk,
+ BTIF_DM_LE_LOCAL_KEY_IRK);
+ btif_storage_add_ble_local_key(ble_local_key_cb.id_keys.ir,
+ BTIF_DM_LE_LOCAL_KEY_IR);
+ btif_storage_add_ble_local_key(ble_local_key_cb.id_keys.dhk,
+ BTIF_DM_LE_LOCAL_KEY_DHK);
break;
case BTA_DM_BLE_LOCAL_ER_EVT:
BTIF_TRACE_DEBUG("BTA_DM_BLE_LOCAL_ER_EVT. ");
ble_local_key_cb.is_er_rcvd = true;
- memcpy(&ble_local_key_cb.er[0], &p_data->ble_er[0], sizeof(BT_OCTET16));
- btif_storage_add_ble_local_key((char*)&ble_local_key_cb.er[0],
- BTIF_DM_LE_LOCAL_KEY_ER, BT_OCTET16_LEN);
+ ble_local_key_cb.er = p_data->ble_er;
+ btif_storage_add_ble_local_key(ble_local_key_cb.er,
+ BTIF_DM_LE_LOCAL_KEY_ER);
break;
case BTA_DM_BLE_AUTH_CMPL_EVT:
@@ -2138,7 +2139,7 @@
BTIF_TRACE_EVENT("%s", __func__);
/* Cleanup anything remaining on index 0 */
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE,
base::Bind(&BTM_BleAdvFilterParamSetup, BTM_BLE_SCAN_COND_DELETE, 0,
nullptr, base::Bind(&bte_scan_filt_param_cfg_evt, 0)));
@@ -2151,7 +2152,7 @@
adv_filt_param->list_logic_type = BTA_DM_BLE_PF_LIST_LOGIC_OR;
adv_filt_param->rssi_low_thres = LOWEST_RSSI_VALUE;
adv_filt_param->rssi_high_thres = LOWEST_RSSI_VALUE;
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE, base::Bind(&BTM_BleAdvFilterParamSetup, BTM_BLE_SCAN_COND_ADD,
0, base::Passed(&adv_filt_param),
base::Bind(&bte_scan_filt_param_cfg_evt, 0)));
@@ -2444,6 +2445,20 @@
prop->len = sizeof(DEV_CLASS);
} break;
+ // While fetching IO_CAP* values for the local device, we maintain backward
+ // compatibility by using the value from #define macros BTM_LOCAL_IO_CAPS,
+ // BTM_LOCAL_IO_CAPS_BLE if the values have never been explicitly set.
+
+ case BT_PROPERTY_LOCAL_IO_CAPS: {
+ *(bt_io_cap_t*)prop->val = (bt_io_cap_t)BTM_LOCAL_IO_CAPS;
+ prop->len = sizeof(bt_io_cap_t);
+ } break;
+
+ case BT_PROPERTY_LOCAL_IO_CAPS_BLE: {
+ *(bt_io_cap_t*)prop->val = (bt_io_cap_t)BTM_LOCAL_IO_CAPS_BLE;
+ prop->len = sizeof(bt_io_cap_t);
+ } break;
+
default:
prop->len = 0;
return BT_STATUS_FAIL;
@@ -2640,7 +2655,7 @@
}
}
-void btif_dm_proc_loc_oob(bool valid, BT_OCTET16 c, BT_OCTET16 r) {
+void btif_dm_proc_loc_oob(bool valid, const Octet16& c, const Octet16& r) {
FILE* fp;
const char* path_a = "/data/misc/bluedroid/LOCAL/a.key";
const char* path_b = "/data/misc/bluedroid/LOCAL/b.key";
@@ -2649,8 +2664,8 @@
BTIF_TRACE_DEBUG("%s: valid=%d", __func__, valid);
if (is_empty_128bit(oob_cb.oob_data.c192) && valid) {
BTIF_TRACE_DEBUG("save local OOB data in memory");
- memcpy(oob_cb.oob_data.c192, c, BT_OCTET16_LEN);
- memcpy(oob_cb.oob_data.r192, r, BT_OCTET16_LEN);
+ memcpy(oob_cb.oob_data.c192, c.data(), OCTET16_LEN);
+ memcpy(oob_cb.oob_data.r192, r.data(), OCTET16_LEN);
osi_property_get("service.brcm.bt.oob", prop_oob, "3");
BTIF_TRACE_DEBUG("%s: prop_oob = %s", __func__, prop_oob);
if (prop_oob[0] == '1')
@@ -2665,8 +2680,8 @@
} else {
BTIF_TRACE_DEBUG("%s: save local OOB data into file %s", __func__,
path);
- fwrite(c, 1, BT_OCTET16_LEN, fp);
- fwrite(r, 1, BT_OCTET16_LEN, fp);
+ fwrite(c.data(), 1, OCTET16_LEN, fp);
+ fwrite(r.data(), 1, OCTET16_LEN, fp);
fclose(fp);
}
}
@@ -2736,8 +2751,8 @@
return true;
}
-bool btif_dm_proc_rmt_oob(const RawAddress& bd_addr, BT_OCTET16 p_c,
- BT_OCTET16 p_r) {
+bool btif_dm_proc_rmt_oob(const RawAddress& bd_addr, Octet16* p_c,
+ Octet16* p_r) {
const char* path_a = "/data/misc/bluedroid/LOCAL/a.key";
const char* path_b = "/data/misc/bluedroid/LOCAL/b.key";
const char* path = NULL;
@@ -2760,8 +2775,8 @@
}
BTIF_TRACE_DEBUG("%s: read OOB data from %s", __func__, path);
- fread(p_c, 1, BT_OCTET16_LEN, fp);
- fread(p_r, 1, BT_OCTET16_LEN, fp);
+ fread(p_c->data(), 1, OCTET16_LEN, fp);
+ fread(p_r->data(), 1, OCTET16_LEN, fp);
fclose(fp);
RawAddress bt_bd_addr = bd_addr;
@@ -2836,7 +2851,6 @@
state = BT_BOND_STATE_NONE;
} else {
btif_dm_save_ble_bonding_keys();
- BTA_GATTC_Refresh(bd_addr);
btif_dm_get_remote_services_by_transport(&bd_addr, GATT_TRANSPORT_LE);
}
} else {
@@ -2845,10 +2859,23 @@
case BTA_DM_AUTH_SMP_PAIR_AUTH_FAIL:
case BTA_DM_AUTH_SMP_CONFIRM_VALUE_FAIL:
case BTA_DM_AUTH_SMP_UNKNOWN_ERR:
- case BTA_DM_AUTH_SMP_CONN_TOUT:
btif_dm_remove_ble_bonding_keys();
status = BT_STATUS_AUTH_FAILURE;
break;
+
+ case BTA_DM_AUTH_SMP_CONN_TOUT: {
+ if (btm_sec_is_a_bonded_dev(bd_addr)) {
+ LOG(INFO) << __func__ << " Bonded device addr=" << bd_addr
+ << " timed out - will not remove the keys";
+ // Don't send state change to upper layers - otherwise Java think we
+ // unbonded, and will disconnect HID profile.
+ return;
+ }
+
+ btif_dm_remove_ble_bonding_keys();
+ status = BT_STATUS_AUTH_FAILURE;
+ break;
+ }
case BTA_DM_AUTH_SMP_PAIR_NOT_SUPPORT:
status = BT_STATUS_AUTH_REJECTED;
break;
@@ -2864,41 +2891,37 @@
void btif_dm_load_ble_local_keys(void) {
memset(&ble_local_key_cb, 0, sizeof(btif_dm_local_key_cb_t));
- if (btif_storage_get_ble_local_key(BTIF_DM_LE_LOCAL_KEY_ER,
- (char*)&ble_local_key_cb.er[0],
- BT_OCTET16_LEN) == BT_STATUS_SUCCESS) {
+ if (btif_storage_get_ble_local_key(
+ BTIF_DM_LE_LOCAL_KEY_ER, &ble_local_key_cb.er) == BT_STATUS_SUCCESS) {
ble_local_key_cb.is_er_rcvd = true;
BTIF_TRACE_DEBUG("%s BLE ER key loaded", __func__);
}
if ((btif_storage_get_ble_local_key(BTIF_DM_LE_LOCAL_KEY_IR,
- (char*)&ble_local_key_cb.id_keys.ir[0],
- BT_OCTET16_LEN) == BT_STATUS_SUCCESS) &&
+ &ble_local_key_cb.id_keys.ir) ==
+ BT_STATUS_SUCCESS) &&
(btif_storage_get_ble_local_key(BTIF_DM_LE_LOCAL_KEY_IRK,
- (char*)&ble_local_key_cb.id_keys.irk[0],
- BT_OCTET16_LEN) == BT_STATUS_SUCCESS) &&
+ &ble_local_key_cb.id_keys.irk) ==
+ BT_STATUS_SUCCESS) &&
(btif_storage_get_ble_local_key(BTIF_DM_LE_LOCAL_KEY_DHK,
- (char*)&ble_local_key_cb.id_keys.dhk[0],
- BT_OCTET16_LEN) == BT_STATUS_SUCCESS)) {
+ &ble_local_key_cb.id_keys.dhk) ==
+ BT_STATUS_SUCCESS)) {
ble_local_key_cb.is_id_keys_rcvd = true;
BTIF_TRACE_DEBUG("%s BLE ID keys loaded", __func__);
}
}
void btif_dm_get_ble_local_keys(tBTA_DM_BLE_LOCAL_KEY_MASK* p_key_mask,
- BT_OCTET16 er,
+ Octet16* p_er,
tBTA_BLE_LOCAL_ID_KEYS* p_id_keys) {
if (ble_local_key_cb.is_er_rcvd) {
- memcpy(&er[0], &ble_local_key_cb.er[0], sizeof(BT_OCTET16));
+ *p_er = ble_local_key_cb.er;
*p_key_mask |= BTA_BLE_LOCAL_KEY_TYPE_ER;
}
if (ble_local_key_cb.is_id_keys_rcvd) {
- memcpy(&p_id_keys->ir[0], &ble_local_key_cb.id_keys.ir[0],
- sizeof(BT_OCTET16));
- memcpy(&p_id_keys->irk[0], &ble_local_key_cb.id_keys.irk[0],
- sizeof(BT_OCTET16));
- memcpy(&p_id_keys->dhk[0], &ble_local_key_cb.id_keys.dhk[0],
- sizeof(BT_OCTET16));
+ p_id_keys->ir = ble_local_key_cb.id_keys.ir;
+ p_id_keys->irk = ble_local_key_cb.id_keys.irk;
+ p_id_keys->dhk = ble_local_key_cb.id_keys.dhk;
*p_key_mask |= BTA_BLE_LOCAL_KEY_TYPE_ID;
}
BTIF_TRACE_DEBUG("%s *p_key_mask=0x%02x", __func__, *p_key_mask);
@@ -3222,26 +3245,26 @@
int type;
btif_get_device_type(bd_addr, &type);
- system_bt_osi::device_type_t device_type;
+ bluetooth::common::device_type_t device_type;
switch (type) {
case BT_DEVICE_TYPE_BREDR:
- device_type = system_bt_osi::DEVICE_TYPE_BREDR;
+ device_type = bluetooth::common::DEVICE_TYPE_BREDR;
break;
case BT_DEVICE_TYPE_BLE:
- device_type = system_bt_osi::DEVICE_TYPE_LE;
+ device_type = bluetooth::common::DEVICE_TYPE_LE;
break;
case BT_DEVICE_TYPE_DUMO:
- device_type = system_bt_osi::DEVICE_TYPE_DUMO;
+ device_type = bluetooth::common::DEVICE_TYPE_DUMO;
break;
default:
- device_type = system_bt_osi::DEVICE_TYPE_UNKNOWN;
+ device_type = bluetooth::common::DEVICE_TYPE_UNKNOWN;
break;
}
uint32_t cod = get_cod(&bd_addr);
uint64_t ts =
event->timestamp.tv_sec * 1000 + event->timestamp.tv_nsec / 1000000;
- system_bt_osi::BluetoothMetricsLogger::GetInstance()->LogPairEvent(
+ bluetooth::common::BluetoothMetricsLogger::GetInstance()->LogPairEvent(
0, ts, cod, device_type);
}
diff --git a/btif/src/btif_gatt_client.cc b/btif/src/btif_gatt_client.cc
index 0e06bbb..14433d3 100644
--- a/btif/src/btif_gatt_client.cc
+++ b/btif/src/btif_gatt_client.cc
@@ -41,7 +41,6 @@
#include <hardware/bt_gatt.h>
#include "bta_api.h"
-#include "bta_closure_api.h"
#include "bta_gatt_api.h"
#include "btif_config.h"
#include "btif_dm.h"
@@ -49,6 +48,7 @@
#include "btif_gatt_util.h"
#include "btif_storage.h"
#include "osi/include/log.h"
+#include "stack/include/btu.h"
#include "vendor_api.h"
using base::Bind;
@@ -163,6 +163,9 @@
/* Ignore for now */
break;
+ case BTA_GATTC_SEARCH_RES_EVT:
+ break;
+
case BTA_GATTC_CANCEL_OPEN_EVT:
break;
@@ -276,7 +279,6 @@
return;
}
}
- BTA_DmBleStartAutoConn();
}
// Determine transport
@@ -562,8 +564,8 @@
uint8_t tx_phy, uint8_t rx_phy,
uint16_t phy_options) {
CHECK_BTGATT_INIT();
- do_in_bta_thread(FROM_HERE,
- Bind(&BTM_BleSetPhy, bd_addr, tx_phy, rx_phy, phy_options));
+ do_in_main_thread(FROM_HERE,
+ Bind(&BTM_BleSetPhy, bd_addr, tx_phy, rx_phy, phy_options));
return BT_STATUS_SUCCESS;
}
@@ -571,8 +573,8 @@
const RawAddress& bd_addr,
base::Callback<void(uint8_t tx_phy, uint8_t rx_phy, uint8_t status)> cb) {
CHECK_BTGATT_INIT();
- do_in_bta_thread(FROM_HERE, Bind(&BTM_BleReadPhy, bd_addr,
- jni_thread_wrapper(FROM_HERE, cb)));
+ do_in_main_thread(FROM_HERE, Bind(&BTM_BleReadPhy, bd_addr,
+ jni_thread_wrapper(FROM_HERE, cb)));
return BT_STATUS_SUCCESS;
}
diff --git a/btif/src/btif_gatt_server.cc b/btif/src/btif_gatt_server.cc
index b7fdc8c..6dc5eb7 100644
--- a/btif/src/btif_gatt_server.cc
+++ b/btif/src/btif_gatt_server.cc
@@ -40,7 +40,6 @@
#include "bt_common.h"
#include "bta_api.h"
-#include "bta_closure_api.h"
#include "bta_gatt_api.h"
#include "btif_config.h"
#include "btif_dm.h"
@@ -48,6 +47,7 @@
#include "btif_gatt_util.h"
#include "btif_storage.h"
#include "osi/include/log.h"
+#include "stack/include/btu.h"
using base::Bind;
using base::Owned;
@@ -291,9 +291,6 @@
BTA_DmAddBleDevice(address, addr_type, device_type);
}
- // Mark background connections
- if (!is_direct) BTA_DmBleStartAutoConn();
-
// Determine transport
if (transport_param != GATT_TRANSPORT_AUTO) {
transport = transport_param;
@@ -425,8 +422,8 @@
uint8_t tx_phy, uint8_t rx_phy,
uint16_t phy_options) {
CHECK_BTGATT_INIT();
- do_in_bta_thread(FROM_HERE,
- Bind(&BTM_BleSetPhy, bd_addr, tx_phy, rx_phy, phy_options));
+ do_in_main_thread(FROM_HERE,
+ Bind(&BTM_BleSetPhy, bd_addr, tx_phy, rx_phy, phy_options));
return BT_STATUS_SUCCESS;
}
@@ -434,8 +431,8 @@
const RawAddress& bd_addr,
base::Callback<void(uint8_t tx_phy, uint8_t rx_phy, uint8_t status)> cb) {
CHECK_BTGATT_INIT();
- do_in_bta_thread(FROM_HERE, Bind(&BTM_BleReadPhy, bd_addr,
- jni_thread_wrapper(FROM_HERE, cb)));
+ do_in_main_thread(FROM_HERE, Bind(&BTM_BleReadPhy, bd_addr,
+ jni_thread_wrapper(FROM_HERE, cb)));
return BT_STATUS_SUCCESS;
}
diff --git a/btif/src/btif_gatt_test.cc b/btif/src/btif_gatt_test.cc
index 1297d50..1c0af35 100644
--- a/btif/src/btif_gatt_test.cc
+++ b/btif/src/btif_gatt_test.cc
@@ -219,24 +219,18 @@
case 0x04: /* Discover */
{
- tGATT_DISC_PARAM param;
- memset(¶m, 0, sizeof(tGATT_DISC_PARAM));
-
if (params->u1 >= GATT_DISC_MAX) {
LOG_ERROR(LOG_TAG, "%s: DISCOVER - Invalid type (%d)!", __func__,
params->u1);
return (bt_status_t)0;
}
- param.s_handle = params->u2;
- param.e_handle = params->u3;
- param.service = *params->uuid1;
-
LOG_DEBUG(LOG_TAG,
"%s: DISCOVER (%s), conn_id=%d, uuid=%s, handles=0x%04x-0x%04x",
__func__, disc_name[params->u1], test_cb.conn_id,
- param.service.ToString().c_str(), params->u2, params->u3);
- GATTC_Discover(test_cb.conn_id, params->u1, ¶m);
+ params->uuid1->ToString().c_str(), params->u2, params->u3);
+ GATTC_Discover(test_cb.conn_id, params->u1, params->u2, params->u3,
+ *params->uuid1);
break;
}
diff --git a/btif/src/btif_hd.cc b/btif/src/btif_hd.cc
index 6d83167..d580a19 100644
--- a/btif/src/btif_hd.cc
+++ b/btif/src/btif_hd.cc
@@ -201,10 +201,8 @@
case BTA_HD_OPEN_EVT: {
RawAddress* addr = (RawAddress*)&p_data->conn.bda;
- BTIF_TRACE_WARNING(
- "BTA_HD_OPEN_EVT, address (%02x:%02x:%02x:%02x:%02x:%02x)",
- addr->address[0], addr->address[1], addr->address[2],
- addr->address[3], addr->address[4], addr->address[5]);
+ BTIF_TRACE_WARNING("BTA_HD_OPEN_EVT, address=%s",
+ addr->ToString().c_str());
/* Check if the connection is from hid host and not hid device */
if (check_cod_hid(addr)) {
/* Incoming connection from hid device, reject it */
diff --git a/btif/src/btif_hearing_aid.cc b/btif/src/btif_hearing_aid.cc
index 74db790..52cce27 100644
--- a/btif/src/btif_hearing_aid.cc
+++ b/btif/src/btif_hearing_aid.cc
@@ -18,10 +18,10 @@
/* Hearing Aid Profile Interface */
-#include "bta_closure_api.h"
#include "bta_hearing_aid_api.h"
#include "btif_common.h"
#include "btif_storage.h"
+#include "stack/include/btu.h"
#include <base/bind.h>
#include <base/location.h>
@@ -37,11 +37,12 @@
// template specialization
template <>
-base::Callback<void()> jni_thread_wrapper(
- const tracked_objects::Location& from_here, base::Callback<void()> cb) {
+base::Callback<void()> jni_thread_wrapper(const base::Location& from_here,
+ base::Callback<void()> cb) {
return base::Bind(
- [](const tracked_objects::Location& from_here,
- base::Callback<void()> cb) { do_in_jni_thread(from_here, cb); },
+ [](const base::Location& from_here, base::Callback<void()> cb) {
+ do_in_jni_thread(from_here, cb);
+ },
from_here, std::move(cb));
}
@@ -52,12 +53,12 @@
class HearingAidInterfaceImpl
: public bluetooth::hearing_aid::HearingAidInterface,
public HearingAidCallbacks {
- ~HearingAidInterfaceImpl() = default;
+ ~HearingAidInterfaceImpl() override = default;
- void Init(HearingAidCallbacks* callbacks) {
+ void Init(HearingAidCallbacks* callbacks) override {
DVLOG(2) << __func__;
this->callbacks = callbacks;
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE,
Bind(&HearingAid::Initialize, this,
jni_thread_wrapper(FROM_HERE,
@@ -83,56 +84,49 @@
void Connect(const RawAddress& address) override {
DVLOG(2) << __func__ << " address: " << address;
- do_in_bta_thread(FROM_HERE, Bind(&HearingAid::Connect,
- Unretained(HearingAid::Get()), address));
+ do_in_main_thread(FROM_HERE, Bind(&HearingAid::Connect,
+ Unretained(HearingAid::Get()), address));
}
void Disconnect(const RawAddress& address) override {
DVLOG(2) << __func__ << " address: " << address;
- do_in_bta_thread(FROM_HERE, Bind(&HearingAid::Disconnect,
- Unretained(HearingAid::Get()), address));
- do_in_jni_thread(
- FROM_HERE, Bind(&btif_storage_remove_hearing_aid_white_list, address));
+ do_in_main_thread(FROM_HERE, Bind(&HearingAid::Disconnect,
+ Unretained(HearingAid::Get()), address));
+ do_in_jni_thread(FROM_HERE, Bind(&btif_storage_set_hearing_aid_white_list,
+ address, false));
}
void AddToWhiteList(const RawAddress& address) override {
- DVLOG(2) << __func__ << " address: " << address;
- do_in_bta_thread(FROM_HERE, Bind(&HearingAid::AddToWhiteList,
- Unretained(HearingAid::Get()), address));
- do_in_jni_thread(
- FROM_HERE, Bind(&btif_storage_add_hearing_aid_to_white_list, address));
- }
-
- void RemoveFromWhiteList(const RawAddress& address) override {
- DVLOG(2) << __func__ << " address: " << address;
- do_in_bta_thread(FROM_HERE, Bind(&HearingAid::RemoveFromWhiteList,
- Unretained(HearingAid::Get()), address));
- do_in_jni_thread(
- FROM_HERE, Bind(&btif_storage_remove_hearing_aid_white_list, address));
+ VLOG(2) << __func__ << " address: " << address;
+ do_in_main_thread(FROM_HERE, Bind(&HearingAid::AddToWhiteList,
+ Unretained(HearingAid::Get()), address));
+ do_in_jni_thread(FROM_HERE, Bind(&btif_storage_set_hearing_aid_white_list,
+ address, true));
}
void SetVolume(int8_t volume) override {
DVLOG(2) << __func__ << " volume: " << +volume;
- do_in_bta_thread(FROM_HERE, Bind(&HearingAid::SetVolume,
- Unretained(HearingAid::Get()), volume));
+ do_in_main_thread(FROM_HERE, Bind(&HearingAid::SetVolume,
+ Unretained(HearingAid::Get()), volume));
}
void RemoveDevice(const RawAddress& address) override {
DVLOG(2) << __func__ << " address: " << address;
// RemoveDevice can be called on devices that don't have HA enabled
- if (HearingAid::IsInitialized()) {
- do_in_bta_thread(FROM_HERE, Bind(&HearingAid::Disconnect,
- Unretained(HearingAid::Get()), address));
+ if (HearingAid::IsHearingAidRunning()) {
+ do_in_main_thread(FROM_HERE,
+ Bind(&HearingAid::Disconnect,
+ Unretained(HearingAid::Get()), address));
}
do_in_jni_thread(FROM_HERE,
Bind(&btif_storage_remove_hearing_aid, address));
}
- void Cleanup(void) {
+ void Cleanup(void) override {
DVLOG(2) << __func__;
- do_in_bta_thread(FROM_HERE, Bind(&HearingAid::CleanUp));
+ do_in_main_thread(FROM_HERE, Bind(&HearingAid::CleanUp));
}
private:
diff --git a/btif/src/btif_hf.cc b/btif/src/btif_hf.cc
index 24656c2..e0e9515 100644
--- a/btif/src/btif_hf.cc
+++ b/btif/src/btif_hf.cc
@@ -36,6 +36,7 @@
#include <hardware/bluetooth_headset_callbacks.h>
#include <hardware/bluetooth_headset_interface.h>
#include <hardware/bt_hf.h>
+#include <log/log.h>
#include "bta/include/utl.h"
#include "bta_ag_api.h"
@@ -43,7 +44,7 @@
#include "btif_hf.h"
#include "btif_profile_queue.h"
#include "btif_util.h"
-#include "osi/include/metrics.h"
+#include "common/metrics.h"
namespace bluetooth {
namespace headset {
@@ -118,16 +119,6 @@
static btif_hf_cb_t btif_hf_cb[BTA_AG_MAX_NUM_CLIENTS];
-/* By default, even though codec negotiation is enabled, we will not use WBS as
- * the default
- * codec unless this variable is set to true.
- */
-#ifndef BTIF_HF_WBS_PREFERRED
-#define BTIF_HF_WBS_PREFERRED false
-#endif
-
-static bool btif_conf_hf_force_wbs = BTIF_HF_WBS_PREFERRED;
-
static const char* dump_hf_call_state(bthf_call_state_t call_state) {
switch (call_state) {
CASE_RETURN_STR(BTHF_CALL_STATE_IDLE)
@@ -341,7 +332,7 @@
btif_hf_cb[idx].state = BTHF_CONNECTION_STATE_CONNECTED;
btif_hf_cb[idx].peer_feat = 0;
clear_phone_state_multihf(&btif_hf_cb[idx]);
- system_bt_osi::BluetoothMetricsLogger::GetInstance()
+ bluetooth::common::BluetoothMetricsLogger::GetInstance()
->LogHeadsetProfileRfcConnection(p_data->open.service_id);
bt_hf_callbacks->ConnectionStateCallback(
btif_hf_cb[idx].state, &btif_hf_cb[idx].connected_bda);
@@ -511,7 +502,7 @@
we should set the BTA AG Codec to mSBC. This would trigger a +BCS to mSBC
at the time
of SCO connection establishment */
- if ((btif_conf_hf_force_wbs) && (p_data->val.num & BTA_AG_CODEC_MSBC)) {
+ if (p_data->val.num & BTA_AG_CODEC_MSBC) {
BTIF_TRACE_EVENT("%s: btif_hf override-Preferred Codec to MSBC",
__func__);
BTA_AgSetCodec(btif_hf_cb[idx].handle, BTA_AG_CODEC_MSBC);
@@ -709,7 +700,7 @@
bt_status_t PhoneStateChange(int num_active, int num_held,
bthf_call_state_t call_setup_state,
const char* number, bthf_call_addrtype_t type,
- RawAddress* bd_addr) override;
+ const char* name, RawAddress* bd_addr) override;
void Cleanup() override;
bt_status_t SetScoAllowed(bool value) override;
@@ -1052,7 +1043,8 @@
bt_status_t HeadsetInterface::PhoneStateChange(
int num_active, int num_held, bthf_call_state_t call_setup_state,
- const char* number, bthf_call_addrtype_t type, RawAddress* bd_addr) {
+ const char* number, bthf_call_addrtype_t type, const char* name,
+ RawAddress* bd_addr) {
CHECK_BTHF_INIT();
if (!bd_addr) {
BTIF_TRACE_WARNING("%s: bd_addr is null", __func__);
@@ -1184,22 +1176,53 @@
}
}
if (number) {
- int xx = 0;
- if ((type == BTHF_CALL_ADDRTYPE_INTERNATIONAL) && (*number != '+'))
- xx = snprintf(ag_res.str, sizeof(ag_res.str), "\"+%s\"", number);
- else
- xx = snprintf(ag_res.str, sizeof(ag_res.str), "\"%s\"", number);
- ag_res.num = type;
- // 5 = [,][3_digit_type][null_terminator]
- if (xx > static_cast<int>(sizeof(ag_res.str) - 5)) {
- android_errorWriteLog(0x534e4554, "79431031");
- xx = sizeof(ag_res.str) - 5;
- // Null terminating the string
- memset(&ag_res.str[xx], 0, 5);
+ std::ostringstream call_number_stream;
+ if ((type == BTHF_CALL_ADDRTYPE_INTERNATIONAL) && (*number != '+')) {
+ call_number_stream << "\"+";
+ } else {
+ call_number_stream << "\"";
}
- if (res == BTA_AG_CALL_WAIT_RES)
- snprintf(&ag_res.str[xx], sizeof(ag_res.str) - xx, ",%d", type);
+ std::string name_str;
+ if (name) {
+ name_str.append(name);
+ }
+ std::string number_str(number);
+ // 13 = ["][+]["][,][3_digit_type][,,,]["]["][null_terminator]
+ int overflow_size =
+ 13 + static_cast<int>(number_str.length() + name_str.length()) -
+ static_cast<int>(sizeof(ag_res.str));
+ if (overflow_size > 0) {
+ android_errorWriteLog(0x534e4554, "79431031");
+ int extra_overflow_size =
+ overflow_size - static_cast<int>(name_str.length());
+ if (extra_overflow_size > 0) {
+ number_str.resize(number_str.length() - extra_overflow_size);
+ name_str.clear();
+ } else {
+ name_str.resize(name_str.length() - overflow_size);
+ }
+ }
+ call_number_stream << number_str << "\"";
+
+ // Store caller id string and append type info.
+ // Make sure type info is valid, otherwise add 129 as default type
+ ag_res.num = static_cast<uint16_t>(type);
+ if ((ag_res.num < BTA_AG_CLIP_TYPE_MIN) ||
+ (ag_res.num > BTA_AG_CLIP_TYPE_MAX)) {
+ if (ag_res.num != BTA_AG_CLIP_TYPE_VOIP) {
+ ag_res.num = BTA_AG_CLIP_TYPE_DEFAULT;
+ }
+ }
+
+ if (res == BTA_AG_CALL_WAIT_RES || name_str.empty()) {
+ call_number_stream << "," << std::to_string(ag_res.num);
+ } else {
+ call_number_stream << "," << std::to_string(ag_res.num) << ",,,\""
+ << name_str << "\"";
+ }
+ snprintf(ag_res.str, sizeof(ag_res.str), "%s",
+ call_number_stream.str().c_str());
}
break;
case BTHF_CALL_STATE_DIALING:
diff --git a/btif/src/btif_hh.cc b/btif/src/btif_hh.cc
index c5a9021..650923a 100644
--- a/btif/src/btif_hh.cc
+++ b/btif/src/btif_hh.cc
@@ -543,6 +543,14 @@
p_dev->local_vup = true;
BTA_HhSendCtrl(p_dev->dev_handle, BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG);
return BT_STATUS_SUCCESS;
+ } else if ((p_dev != NULL) &&
+ (p_dev->dev_status == BTHH_CONN_STATE_CONNECTED)) {
+ BTIF_TRACE_ERROR("%s: Virtual unplug not suported, disconnecting device");
+ /* start the timer */
+ btif_hh_start_vup_timer(bd_addr);
+ p_dev->local_vup = true;
+ BTA_HhClose(p_dev->dev_handle);
+ return BT_STATUS_SUCCESS;
} else {
BTIF_TRACE_ERROR("%s: Error, device %s not opened, status = %d", __func__,
bd_addr->ToString().c_str(), btif_hh_cb.status);
@@ -682,6 +690,21 @@
}
}
+/*******************************************************************************
+ *
+ *
+ * Function btif_hh_getreport
+ *
+ * Description getreport initiated from the BTIF thread context
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_hh_getreport(btif_hh_device_t* p_dev, bthh_report_type_t r_type,
+ uint8_t reportId, uint16_t bufferSize) {
+ BTA_HhGetReport(p_dev->dev_handle, r_type, reportId, bufferSize);
+}
+
/*****************************************************************************
* Section name (Group of functions)
****************************************************************************/
diff --git a/btif/src/btif_pan.cc b/btif/src/btif_pan.cc
index 9828c4b..fe10b49 100644
--- a/btif/src/btif_pan.cc
+++ b/btif/src/btif_pan.cc
@@ -54,7 +54,6 @@
#include "bt_common.h"
#include "bta_api.h"
-#include "bta_closure_api.h"
#include "bta_pan_api.h"
#include "btif_common.h"
#include "btif_pan_internal.h"
@@ -65,6 +64,7 @@
#include "device/include/controller.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
+#include "stack/include/btu.h"
#define FORWARD_IGNORE 1
#define FORWARD_SUCCESS 0
@@ -369,8 +369,8 @@
btpan_cb.flow = enable;
if (enable) {
btsock_thread_add_fd(pan_pth, btpan_cb.tap_fd, 0, SOCK_THREAD_FD_RD, 0);
- do_in_bta_thread(FROM_HERE,
- base::Bind(btu_exec_tap_fd_read, btpan_cb.tap_fd));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(btu_exec_tap_fd_read, btpan_cb.tap_fd));
}
}
@@ -773,6 +773,6 @@
btpan_tap_close(fd);
btif_pan_close_all_conns();
} else if (flags & SOCK_THREAD_FD_RD) {
- do_in_bta_thread(FROM_HERE, base::Bind(btu_exec_tap_fd_read, fd));
+ do_in_main_thread(FROM_HERE, base::Bind(btu_exec_tap_fd_read, fd));
}
}
diff --git a/btif/src/btif_profile_queue.cc b/btif/src/btif_profile_queue.cc
index 10acade..41275f1 100644
--- a/btif/src/btif_profile_queue.cc
+++ b/btif/src/btif_profile_queue.cc
@@ -29,6 +29,7 @@
#include "btif_profile_queue.h"
#include <base/bind.h>
+#include <base/callback.h>
#include <base/logging.h>
#include <base/strings/stringprintf.h>
#include <string.h>
@@ -210,7 +211,6 @@
LOG_INFO(LOG_TAG, "%s", __func__);
if (do_in_jni_thread(FROM_HERE, base::Bind(&queue_int_release)) !=
BT_STATUS_SUCCESS) {
- // Scheduling failed - the thread to schedule on is probably dead
- queue_int_release();
+ LOG(FATAL) << __func__ << ": Failed to schedule on JNI thread";
}
}
diff --git a/btif/src/btif_rc.cc b/btif/src/btif_rc.cc
index c226b5f..9919a7b 100644
--- a/btif/src/btif_rc.cc
+++ b/btif/src/btif_rc.cc
@@ -216,7 +216,7 @@
rc_device_t device;
-static void sleep_ms(period_ms_t timeout_ms);
+static void sleep_ms(uint64_t timeout_ms);
/* Response status code - Unknown Error - this is changed to "reserved" */
#define BTIF_STS_GEN_ERROR 0x06
@@ -272,7 +272,6 @@
uint8_t label,
btif_rc_device_cb_t* p_dev);
static void rc_ctrl_procedure_complete(btif_rc_device_cb_t* p_dev);
-static void rc_stop_play_status_timer(btif_rc_device_cb_t* p_dev);
static void register_for_event_notification(btif_rc_supported_event_t* p_event,
btif_rc_device_cb_t* p_dev);
static void handle_get_capability_response(tBTA_AV_META_MSG* pmeta_msg,
@@ -338,7 +337,6 @@
uint8_t label,
btif_rc_device_cb_t* p_dev);
-static void rc_start_play_status_timer(btif_rc_device_cb_t* p_dev);
static bool absolute_volume_disabled(void);
/*****************************************************************************
@@ -466,11 +464,12 @@
rc_features |= BTRC_FEAT_ABSOLUTE_VOLUME;
}
- if ((p_dev->rc_features & BTA_AV_FEAT_METADATA) &&
- (p_dev->rc_features & BTA_AV_FEAT_VENDOR) &&
- (p_dev->rc_features_processed != true)) {
+ if (p_dev->rc_features & BTA_AV_FEAT_METADATA) {
rc_features |= BTRC_FEAT_METADATA;
+ }
+ if ((p_dev->rc_features & BTA_AV_FEAT_VENDOR) &&
+ (p_dev->rc_features_processed != true)) {
/* Mark rc features processed to avoid repeating
* the AVRCP procedure every time on receiving this
* update.
@@ -687,7 +686,6 @@
memset(&p_dev->rc_app_settings, 0, sizeof(btif_rc_player_app_settings_t));
p_dev->rc_features_processed = false;
p_dev->rc_procedure_complete = false;
- rc_stop_play_status_timer(p_dev);
/* Check and clear the notification event list */
if (p_dev->rc_supported_event_list != NULL) {
list_clear(p_dev->rc_supported_event_list);
@@ -1367,8 +1365,6 @@
static uint8_t fill_attribute_id_array(
uint8_t cmd_attribute_number, btrc_media_attr_t* cmd_attribute_id_array,
size_t out_array_size, btrc_media_attr_t* out_attribute_id_array) {
- /* Reset attribute array */
- memset(out_attribute_id_array, 0, out_array_size);
/* Default case for cmd_attribute_number == 0xFF, No attribute */
uint8_t out_attribute_number = 0;
if (cmd_attribute_number == 0) {
@@ -1440,7 +1436,7 @@
AVRC_STS_BAD_CMD, pavrc_cmd->cmd.opcode);
} break;
case AVRC_PDU_GET_ELEMENT_ATTR: {
- btrc_media_attr_t element_attrs[BTRC_MAX_ELEM_ATTR_SIZE];
+ btrc_media_attr_t element_attrs[BTRC_MAX_ELEM_ATTR_SIZE] = {};
uint8_t num_attr = fill_attribute_id_array(
pavrc_cmd->get_elem_attrs.num_attr,
(btrc_media_attr_t*)pavrc_cmd->get_elem_attrs.attrs,
@@ -1487,7 +1483,7 @@
} break;
case AVRC_PDU_GET_FOLDER_ITEMS: {
- uint32_t attr_ids[BTRC_MAX_ELEM_ATTR_SIZE];
+ uint32_t attr_ids[BTRC_MAX_ELEM_ATTR_SIZE] = {0};
uint8_t num_attr;
num_attr = pavrc_cmd->get_items.attr_count;
@@ -1578,7 +1574,7 @@
} break;
case AVRC_PDU_GET_ITEM_ATTRIBUTES: {
- btrc_media_attr_t item_attrs[BTRC_MAX_ELEM_ATTR_SIZE];
+ btrc_media_attr_t item_attrs[BTRC_MAX_ELEM_ATTR_SIZE] = {};
uint8_t num_attr = fill_attribute_id_array(
pavrc_cmd->get_attrs.attr_count,
(btrc_media_attr_t*)pavrc_cmd->get_attrs.p_attr_list,
@@ -2047,7 +2043,7 @@
} break;
case AVRC_ITEM_MEDIA: {
- tAVRC_ATTR_ENTRY attr_vals[BTRC_MAX_ELEM_ATTR_SIZE];
+ tAVRC_ATTR_ENTRY attr_vals[BTRC_MAX_ELEM_ATTR_SIZE] = {};
memcpy(item.u.media.uid, cur_item->media.uid, sizeof(tAVRC_UID));
item.u.media.type = cur_item->media.type;
@@ -2926,77 +2922,6 @@
/***************************************************************************
*
- * Function btif_rc_play_status_timeout_handler
- *
- * Description RC play status timeout handler (Runs in BTIF context).
- * Returns None
- *
- **************************************************************************/
-static void btif_rc_play_status_timeout_handler(UNUSED_ATTR uint16_t event,
- char* p_data) {
- btif_rc_handle_t* rc_handle = (btif_rc_handle_t*)p_data;
- btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_handle(rc_handle->handle);
- if (p_dev == NULL) {
- BTIF_TRACE_ERROR("%s timeout handler but no device found for handle %d",
- __func__, rc_handle->handle);
- return;
- }
- get_play_status_cmd(p_dev);
- rc_start_play_status_timer(p_dev);
-}
-
-/***************************************************************************
- *
- * Function btif_rc_play_status_timer_timeout
- *
- * Description RC play status timeout callback.
- * This is called from BTU context and switches to BTIF
- * context to handle the timeout events
- * Returns None
- *
- **************************************************************************/
-static void btif_rc_play_status_timer_timeout(void* data) {
- btif_rc_handle_t rc_handle;
- rc_handle.handle = PTR_TO_UINT(data);
- BTIF_TRACE_DEBUG("%s called with handle: %d", __func__, rc_handle);
- btif_transfer_context(btif_rc_play_status_timeout_handler, 0,
- (char*)(&rc_handle), sizeof(btif_rc_handle_t), NULL);
-}
-
-/***************************************************************************
- *
- * Function rc_start_play_status_timer
- *
- * Description Helper function to start the timer to fetch play status.
- * Returns None
- *
- **************************************************************************/
-static void rc_start_play_status_timer(btif_rc_device_cb_t* p_dev) {
- /* Start the Play status timer only if it is not started */
- if (!alarm_is_scheduled(p_dev->rc_play_status_timer)) {
- if (p_dev->rc_play_status_timer == NULL) {
- p_dev->rc_play_status_timer = alarm_new("p_dev->rc_play_status_timer");
- }
- alarm_set_on_mloop(
- p_dev->rc_play_status_timer, BTIF_TIMEOUT_RC_INTERIM_RSP_MS,
- btif_rc_play_status_timer_timeout, UINT_TO_PTR(p_dev->rc_handle));
- }
-}
-
-/***************************************************************************
- *
- * Function rc_stop_play_status_timer
- *
- * Description Helper function to stop the play status timer.
- * Returns None
- *
- **************************************************************************/
-void rc_stop_play_status_timer(btif_rc_device_cb_t* p_dev) {
- alarm_cancel(p_dev->rc_play_status_timer);
-}
-
-/***************************************************************************
- *
* Function register_for_event_notification
*
* Description Helper function registering notification events
@@ -3013,9 +2938,12 @@
BTIF_TRACE_ERROR("%s: no more transaction labels: %d", __func__, status);
return;
}
-
- status = register_notification_cmd(p_transaction->lbl, p_event->event_id, 0,
- p_dev);
+ // interval is only valid for AVRC_EVT_PLAY_POS_CHANGED
+ uint32_t interval = 0;
+ if (p_event->event_id == AVRC_EVT_PLAY_POS_CHANGED) {
+ interval = 2000;
+ }
+ status = register_notification_cmd(p_transaction->lbl, p_event->event_id, interval, p_dev);
if (status != BT_STATUS_SUCCESS) {
BTIF_TRACE_ERROR("%s: Error in Notification registration: %d", __func__,
status);
@@ -3123,7 +3051,9 @@
/* Skip registering for Play position change notification */
if ((p_rsp->param.event_id[xx] == AVRC_EVT_PLAY_STATUS_CHANGE) ||
(p_rsp->param.event_id[xx] == AVRC_EVT_TRACK_CHANGE) ||
+ (p_rsp->param.event_id[xx] == AVRC_EVT_PLAY_POS_CHANGED) ||
(p_rsp->param.event_id[xx] == AVRC_EVT_APP_SETTING_CHANGE) ||
+ (p_rsp->param.event_id[xx] == AVRC_EVT_NOW_PLAYING_CHANGE) ||
(p_rsp->param.event_id[xx] == AVRC_EVT_ADDR_PLAYER_CHANGE) ||
(p_rsp->param.event_id[xx] == AVRC_EVT_UIDS_CHANGE)) {
p_event = (btif_rc_supported_event_t*)osi_malloc(
@@ -3133,6 +3063,15 @@
list_append(p_dev->rc_supported_event_list, p_event);
}
}
+
+ // On occasion a remote device can intermittently send a poorly configured
+ // packet with 0 capabilities. This check ensures the stack does not crash.
+ // Typically the remote device will send a proper packet in the future and
+ // continue operation.
+ if (list_is_empty(p_dev->rc_supported_event_list)) {
+ return;
+ }
+
p_event =
(btif_rc_supported_event_t*)list_front(p_dev->rc_supported_event_list);
if (p_event != NULL) {
@@ -3200,14 +3139,7 @@
BTIF_TRACE_DEBUG("%s: Interim response: 0x%2X ", __func__, p_rsp->event_id);
switch (p_rsp->event_id) {
case AVRC_EVT_PLAY_STATUS_CHANGE:
- /* Start timer to get play status periodically
- * if the play state is playing.
- */
- if (p_rsp->param.play_status == AVRC_PLAYSTATE_PLAYING ||
- p_rsp->param.play_status == AVRC_PLAYSTATE_REV_SEEK ||
- p_rsp->param.play_status == AVRC_PLAYSTATE_FWD_SEEK) {
- rc_start_play_status_timer(p_dev);
- }
+ get_play_status_cmd(p_dev);
do_in_jni_thread(
FROM_HERE,
base::Bind(bt_rc_ctrl_callbacks->play_status_changed_cb,
@@ -3224,6 +3156,7 @@
* Attributes will be fetched after the AVRCP procedure
*/
BE_STREAM_TO_UINT64(p_dev->rc_playing_uid, p_data);
+ get_play_status_cmd(p_dev);
}
break;
@@ -3231,6 +3164,10 @@
break;
case AVRC_EVT_NOW_PLAYING_CHANGE:
+ do_in_jni_thread(
+ FROM_HERE,
+ base::Bind(bt_rc_ctrl_callbacks->now_playing_contents_changed_cb,
+ p_dev->rc_addr));
break;
case AVRC_EVT_AVAL_PLAYERS_CHANGE:
@@ -3238,16 +3175,21 @@
case AVRC_EVT_ADDR_PLAYER_CHANGE:
do_in_jni_thread(
- FROM_HERE, base::Bind(bt_rc_ctrl_callbacks->set_addressed_player_cb,
- p_dev->rc_addr, BTRC_STS_ADDR_PLAY_CHGD));
+ FROM_HERE,
+ base::Bind(bt_rc_ctrl_callbacks->addressed_player_changed_cb,
+ p_dev->rc_addr, p_rsp->param.addr_player.player_id));
break;
+ case AVRC_EVT_PLAY_POS_CHANGED:
+ do_in_jni_thread(FROM_HERE, base::Bind(bt_rc_ctrl_callbacks->play_position_changed_cb, p_dev->rc_addr, 0,
+ p_rsp->param.play_pos));
+
+ break;
case AVRC_EVT_UIDS_CHANGE:
break;
case AVRC_EVT_TRACK_REACHED_END:
case AVRC_EVT_TRACK_REACHED_START:
- case AVRC_EVT_PLAY_POS_CHANGED:
case AVRC_EVT_BATTERY_STATUS_CHANGE:
case AVRC_EVT_SYSTEM_STATUS_CHANGE:
default:
@@ -3310,11 +3252,8 @@
* if the play state is playing.
*/
if (p_rsp->param.play_status == AVRC_PLAYSTATE_PLAYING) {
- rc_start_play_status_timer(p_dev);
get_element_attribute_cmd(AVRC_MAX_NUM_MEDIA_ATTR_ID, attr_list,
p_dev);
- } else {
- rc_stop_play_status_timer(p_dev);
}
do_in_jni_thread(
FROM_HERE,
@@ -3357,12 +3296,15 @@
case AVRC_EVT_ADDR_PLAYER_CHANGE:
break;
+ case AVRC_EVT_PLAY_POS_CHANGED:
+ // handle on interim
+ break;
+
case AVRC_EVT_UIDS_CHANGE:
break;
case AVRC_EVT_TRACK_REACHED_END:
case AVRC_EVT_TRACK_REACHED_START:
- case AVRC_EVT_PLAY_POS_CHANGED:
case AVRC_EVT_BATTERY_STATUS_CHANGE:
case AVRC_EVT_SYSTEM_STATUS_CHANGE:
default:
@@ -5417,7 +5359,7 @@
*
* Returns void
******************************************************************************/
-static void sleep_ms(period_ms_t timeout_ms) {
+static void sleep_ms(uint64_t timeout_ms) {
struct timespec delay;
delay.tv_sec = timeout_ms / 1000;
delay.tv_nsec = 1000 * 1000 * (timeout_ms % 1000);
diff --git a/btif/src/btif_sdp_server.cc b/btif/src/btif_sdp_server.cc
index 4738da4..ef1b02f 100644
--- a/btif/src/btif_sdp_server.cc
+++ b/btif/src/btif_sdp_server.cc
@@ -28,6 +28,7 @@
#define LOG_TAG "bt_btif_sdp_server"
+#include <log/log.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
@@ -71,6 +72,7 @@
*****************************************************************************/
static int add_maps_sdp(const bluetooth_sdp_mas_record* rec);
static int add_mapc_sdp(const bluetooth_sdp_mns_record* rec);
+static int add_pbapc_sdp(const bluetooth_sdp_pce_record* rec);
static int add_pbaps_sdp(const bluetooth_sdp_pse_record* rec);
static int add_opps_sdp(const bluetooth_sdp_ops_record* rec);
static int add_saps_sdp(const bluetooth_sdp_sap_record* rec);
@@ -338,7 +340,8 @@
handle = add_saps_sdp(&record->sap);
break;
case SDP_TYPE_PBAP_PCE:
- // break; not yet supported
+ handle = add_pbapc_sdp(&record->pce);
+ break;
default:
BTIF_TRACE_DEBUG("Record type %d is not supported", record->hdr.type);
break;
@@ -532,6 +535,49 @@
return sdp_handle;
}
+/* Create a PBAP Client SDP record based on information stored in a
+ * bluetooth_sdp_pce_record */
+static int add_pbapc_sdp(const bluetooth_sdp_pce_record* rec) {
+ uint16_t service = UUID_SERVCLASS_PBAP_PCE;
+ uint16_t browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ bool status = true;
+ uint32_t sdp_handle = 0;
+
+ APPL_TRACE_DEBUG("%s(): service name %s", __func__, rec->hdr.service_name);
+ sdp_handle = SDP_CreateRecord();
+ if (sdp_handle == 0) {
+ APPL_TRACE_ERROR("%s(): Unable to register PBAP Client Service", __func__);
+ return sdp_handle;
+ }
+
+ status &= SDP_AddServiceClassIdList(sdp_handle, 1, &service);
+
+ /* Add a name entry */
+ status &= SDP_AddAttribute(sdp_handle, (uint16_t)ATTR_ID_SERVICE_NAME,
+ (uint8_t)TEXT_STR_DESC_TYPE,
+ (uint32_t)(rec->hdr.service_name_length + 1),
+ (uint8_t*)rec->hdr.service_name);
+
+ /* Add in the Bluetooth Profile Descriptor List */
+ status &= SDP_AddProfileDescriptorList(sdp_handle, service,
+ rec->hdr.profile_version);
+
+ /* Make the service browseable */
+ status &=
+ SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
+
+ if (!status) {
+ SDP_DeleteRecord(sdp_handle);
+ sdp_handle = 0;
+ APPL_TRACE_ERROR("%s() FAILED", __func__);
+ return sdp_handle;
+ }
+ bta_sys_add_uuid(service); /* UUID_SERVCLASS_PBAP_PCE */
+ APPL_TRACE_DEBUG("%s(): SDP Registered (handle 0x%08x)", __func__,
+ sdp_handle);
+ return sdp_handle;
+}
+
/* Create a PBAP Server SDP record based on information stored in a
* bluetooth_sdp_pse_record */
static int add_pbaps_sdp(const bluetooth_sdp_pse_record* rec) {
diff --git a/btif/src/btif_sock.cc b/btif/src/btif_sock.cc
index 90121b1..0c4f6f6 100644
--- a/btif/src/btif_sock.cc
+++ b/btif/src/btif_sock.cc
@@ -22,6 +22,7 @@
#include <base/logging.h>
+#include <frameworks/base/core/proto/android/bluetooth/enums.pb.h>
#include <hardware/bluetooth.h>
#include <hardware/bt_sock.h>
@@ -34,6 +35,7 @@
#include "btif_sock_thread.h"
#include "btif_uid.h"
#include "btif_util.h"
+#include "common/metrics.h"
#include "device/include/controller.h"
#include "osi/include/thread.h"
@@ -138,6 +140,11 @@
bt_status_t status = BT_STATUS_FAIL;
int original_channel = channel;
+ bluetooth::common::LogSocketConnectionState(
+ RawAddress::kEmpty, 0, type,
+ android::bluetooth::SocketConnectionstateEnum::
+ SOCKET_CONNECTION_STATE_LISTENING,
+ 0, 0, app_uid, channel, android::bluetooth::SOCKET_ROLE_LISTEN);
switch (type) {
case BTSOCK_RFCOMM:
status = btsock_rfc_listen(service_name, service_uuid, channel, sock_fd,
@@ -174,6 +181,13 @@
status = BT_STATUS_UNSUPPORTED;
break;
}
+ if (status != BT_STATUS_SUCCESS) {
+ bluetooth::common::LogSocketConnectionState(
+ RawAddress::kEmpty, 0, type,
+ android::bluetooth::SocketConnectionstateEnum::
+ SOCKET_CONNECTION_STATE_DISCONNECTED,
+ 0, 0, app_uid, channel, android::bluetooth::SOCKET_ROLE_LISTEN);
+ }
return status;
}
@@ -186,6 +200,11 @@
*sock_fd = INVALID_FD;
bt_status_t status = BT_STATUS_FAIL;
+ bluetooth::common::LogSocketConnectionState(
+ *bd_addr, 0, type,
+ android::bluetooth::SocketConnectionstateEnum::
+ SOCKET_CONNECTION_STATE_CONNECTING,
+ 0, 0, app_uid, channel, android::bluetooth::SOCKET_ROLE_CONNECTION);
switch (type) {
case BTSOCK_RFCOMM:
status =
@@ -213,6 +232,13 @@
status = BT_STATUS_UNSUPPORTED;
break;
}
+ if (status != BT_STATUS_SUCCESS) {
+ bluetooth::common::LogSocketConnectionState(
+ *bd_addr, 0, type,
+ android::bluetooth::SocketConnectionstateEnum::
+ SOCKET_CONNECTION_STATE_DISCONNECTED,
+ 0, 0, app_uid, channel, android::bluetooth::SOCKET_ROLE_CONNECTION);
+ }
return status;
}
@@ -237,7 +263,8 @@
btsock_l2cap_signaled(fd, flags, user_id);
break;
default:
- CHECK(false && "Invalid socket type");
+ LOG(FATAL) << "Invalid socket type! type=" << type << " fd=" << fd
+ << " flags=" << flags << " user_id=" << user_id;
break;
}
}
diff --git a/btif/src/btif_sock_l2cap.cc b/btif/src/btif_sock_l2cap.cc
index 43f2372..1f85c73 100644
--- a/btif/src/btif_sock_l2cap.cc
+++ b/btif/src/btif_sock_l2cap.cc
@@ -28,6 +28,7 @@
#include <mutex>
+#include <frameworks/base/core/proto/android/bluetooth/enums.pb.h>
#include <hardware/bt_sock.h>
#include "osi/include/allocator.h"
@@ -46,6 +47,7 @@
#include "btm_api.h"
#include "btm_int.h"
#include "btu.h"
+#include "common/metrics.h"
#include "hcimsgs.h"
#include "l2c_api.h"
#include "l2c_int.h"
@@ -84,6 +86,10 @@
bool is_le_coc; // is le connection oriented channel?
uint16_t rx_mtu;
uint16_t tx_mtu;
+ // Cumulative number of bytes transmitted on this socket
+ int64_t tx_bytes;
+ // Cumulative number of bytes received on this socket
+ int64_t rx_bytes;
} l2cap_socket;
static void btsock_l2cap_server_listen(l2cap_socket* sock);
@@ -215,6 +221,14 @@
if (!t) /* prever double-frees */
return;
+ // Whenever a socket is freed, the connection must be dropped
+ bluetooth::common::LogSocketConnectionState(
+ sock->addr, sock->id, sock->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
+ android::bluetooth::SOCKET_CONNECTION_STATE_DISCONNECTED, sock->tx_bytes,
+ sock->rx_bytes, sock->app_uid, sock->channel,
+ sock->server ? android::bluetooth::SOCKET_ROLE_LISTEN
+ : android::bluetooth::SOCKET_ROLE_CONNECTION);
+
if (sock->next) sock->next->prev = sock->prev;
if (sock->prev)
@@ -309,6 +323,8 @@
sock->prev = NULL;
if (socks) socks->prev = sock;
sock->id = (socks ? socks->id : 0) + 1;
+ sock->tx_bytes = 0;
+ sock->rx_bytes = 0;
socks = sock;
/* paranoia cap on: verify no ID duplicates due to overflow and fix as needed
*/
@@ -396,6 +412,14 @@
DVLOG(2) << __func__ << ": sock->handle: " << sock->handle
<< ", id: " << sock->id;
+ bluetooth::common::LogSocketConnectionState(
+ sock->addr, sock->id, sock->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
+ android::bluetooth::SocketConnectionstateEnum::
+ SOCKET_CONNECTION_STATE_LISTENING,
+ 0, 0, sock->app_uid, sock->channel,
+ sock->server ? android::bluetooth::SOCKET_ROLE_LISTEN
+ : android::bluetooth::SOCKET_ROLE_CONNECTION);
+
if (!sock->server_psm_sent) {
if (!send_app_psm_or_chan_l(sock)) {
// closed
@@ -448,6 +472,14 @@
accept_rs->id = sock->id;
sock->id = new_listen_id;
+ bluetooth::common::LogSocketConnectionState(
+ accept_rs->addr, accept_rs->id,
+ accept_rs->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
+ android::bluetooth::SOCKET_CONNECTION_STATE_CONNECTED, 0, 0,
+ accept_rs->app_uid, accept_rs->channel,
+ accept_rs->server ? android::bluetooth::SOCKET_ROLE_LISTEN
+ : android::bluetooth::SOCKET_ROLE_CONNECTION);
+
// start monitor the socket
btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP,
SOCK_THREAD_FD_EXCEPTION, sock->id);
@@ -489,6 +521,14 @@
*(p_open->p_p_cback) = (void*)btsock_l2cap_cbk;
*(p_open->p_user_data) = UINT_TO_PTR(accept_rs->id);
+ bluetooth::common::LogSocketConnectionState(
+ accept_rs->addr, accept_rs->id,
+ accept_rs->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
+ android::bluetooth::SOCKET_CONNECTION_STATE_CONNECTED, 0, 0,
+ accept_rs->app_uid, accept_rs->channel,
+ accept_rs->server ? android::bluetooth::SOCKET_ROLE_LISTEN
+ : android::bluetooth::SOCKET_ROLE_CONNECTION);
+
// start monitor the socket
btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP,
SOCK_THREAD_FD_EXCEPTION, sock->id);
@@ -518,6 +558,13 @@
return;
}
+ bluetooth::common::LogSocketConnectionState(
+ sock->addr, sock->id, sock->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
+ android::bluetooth::SOCKET_CONNECTION_STATE_CONNECTED, 0, 0,
+ sock->app_uid, sock->channel,
+ sock->server ? android::bluetooth::SOCKET_ROLE_LISTEN
+ : android::bluetooth::SOCKET_ROLE_CONNECTION);
+
// start monitoring the socketpair to get call back when app writing data
DVLOG(2) << " connect signal sent, slot id: " << sock->id
<< ", chan: " << sock->channel << ", server: " << sock->server;
@@ -542,6 +589,13 @@
return;
}
+ bluetooth::common::LogSocketConnectionState(
+ sock->addr, sock->id, sock->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
+ android::bluetooth::SOCKET_CONNECTION_STATE_CONNECTED, 0, 0,
+ sock->app_uid, sock->channel,
+ sock->server ? android::bluetooth::SOCKET_ROLE_LISTEN
+ : android::bluetooth::SOCKET_ROLE_CONNECTION);
+
// start monitoring the socketpair to get call back when app writing data
DVLOG(2) << " connect signal sent, slot id: " << sock->id
<< ", chan: " << sock->channel << ", server: " << sock->server;
@@ -564,17 +618,20 @@
sock->tx_mtu = le_open->tx_mtu;
if (sock->fixed_chan && le_open->status == BTA_JV_SUCCESS) {
- if (!sock->server)
+ if (!sock->server) {
on_cl_l2cap_le_connect_l(le_open, sock);
- else
+ } else {
on_srv_l2cap_le_connect_l(le_open, sock);
+ }
} else if (!sock->fixed_chan && psm_open->status == BTA_JV_SUCCESS) {
- if (!sock->server)
+ if (!sock->server) {
on_cl_l2cap_psm_connect_l(psm_open, sock);
- else
+ } else {
on_srv_l2cap_psm_connect_l(psm_open, sock);
- } else
+ }
+ } else {
btsock_l2cap_free_l(sock);
+ }
}
static void on_l2cap_close(tBTA_JV_L2CAP_CLOSE* p_close, uint32_t id) {
@@ -584,6 +641,13 @@
sock = btsock_l2cap_find_by_id_l(id);
if (!sock) return;
+ bluetooth::common::LogSocketConnectionState(
+ sock->addr, sock->id, sock->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
+ android::bluetooth::SOCKET_CONNECTION_STATE_DISCONNECTING, 0, 0,
+ sock->app_uid, sock->channel,
+ sock->server ? android::bluetooth::SOCKET_ROLE_LISTEN
+ : android::bluetooth::SOCKET_ROLE_CONNECTION);
+
DVLOG(2) << __func__ << ": slot id: " << sock->id << ", fd: " << sock->our_fd
<< (sock->fixed_chan ? ", fixed_chan:" : ", PSM: ") << sock->channel
<< ", server:" << sock->server;
@@ -624,6 +688,7 @@
sock->id);
}
+ sock->tx_bytes += len;
uid_set_add_tx(uid_set, app_uid, len);
}
@@ -677,6 +742,7 @@
}
}
+ sock->rx_bytes += bytes_read;
uid_set_add_rx(uid_set, app_uid, bytes_read);
}
diff --git a/btif/src/btif_sock_rfc.cc b/btif/src/btif_sock_rfc.cc
index 4b490a0..3c9e26e 100644
--- a/btif/src/btif_sock_rfc.cc
+++ b/btif/src/btif_sock_rfc.cc
@@ -30,6 +30,7 @@
#include <mutex>
+#include <frameworks/base/core/proto/android/bluetooth/enums.pb.h>
#include <hardware/bluetooth.h>
#include <hardware/bt_sock.h>
@@ -47,6 +48,7 @@
#include "btm_api.h"
#include "btm_int.h"
#include "btu.h"
+#include "common/metrics.h"
#include "hcimsgs.h"
#include "osi/include/compat.h"
#include "osi/include/list.h"
@@ -97,6 +99,10 @@
int rfc_port_handle;
int role;
list_t* incoming_queue;
+ // Cumulative number of bytes transmitted on this socket
+ int64_t tx_bytes;
+ // Cumulative number of bytes received on this socket
+ int64_t rx_bytes;
} rfc_slot_t;
static rfc_slot_t rfc_slots[MAX_RFC_CHANNEL];
@@ -225,11 +231,15 @@
} else {
memset(slot->service_name, 0, sizeof(slot->service_name));
}
- if (addr) slot->addr = *addr;
-
+ if (addr) {
+ slot->addr = *addr;
+ } else {
+ slot->addr = RawAddress::kEmpty;
+ }
slot->id = rfc_slot_id;
slot->f.server = server;
-
+ slot->tx_bytes = 0;
+ slot->rx_bytes = 0;
return slot;
}
@@ -411,6 +421,12 @@
if (slot->fd != INVALID_FD) {
shutdown(slot->fd, SHUT_RDWR);
close(slot->fd);
+ bluetooth::common::LogSocketConnectionState(
+ slot->addr, slot->id, BTSOCK_RFCOMM,
+ android::bluetooth::SOCKET_CONNECTION_STATE_DISCONNECTED,
+ slot->tx_bytes, slot->rx_bytes, slot->app_uid, slot->scn,
+ slot->f.server ? android::bluetooth::SOCKET_ROLE_LISTEN
+ : android::bluetooth::SOCKET_ROLE_CONNECTION);
slot->fd = INVALID_FD;
}
@@ -436,6 +452,8 @@
memset(&slot->f, 0, sizeof(slot->f));
slot->id = 0;
slot->scn_notified = false;
+ slot->tx_bytes = 0;
+ slot->rx_bytes = 0;
}
static bool send_app_scn(rfc_slot_t* slot) {
@@ -484,6 +502,13 @@
if (p_start->status == BTA_JV_SUCCESS) {
slot->rfc_handle = p_start->handle;
+ bluetooth::common::LogSocketConnectionState(
+ slot->addr, slot->id, BTSOCK_RFCOMM,
+ android::bluetooth::SocketConnectionstateEnum::
+ SOCKET_CONNECTION_STATE_LISTENING,
+ 0, 0, slot->app_uid, slot->scn,
+ slot->f.server ? android::bluetooth::SOCKET_ROLE_LISTEN
+ : android::bluetooth::SOCKET_ROLE_CONNECTION);
} else {
cleanup_rfc_slot(slot);
}
@@ -500,6 +525,13 @@
srv_rs, &p_open->rem_bda, p_open->handle, p_open->new_listen_handle);
if (!accept_rs) return 0;
+ bluetooth::common::LogSocketConnectionState(
+ accept_rs->addr, accept_rs->id, BTSOCK_RFCOMM,
+ android::bluetooth::SOCKET_CONNECTION_STATE_CONNECTED, 0, 0,
+ accept_rs->app_uid, accept_rs->scn,
+ accept_rs->f.server ? android::bluetooth::SOCKET_ROLE_LISTEN
+ : android::bluetooth::SOCKET_ROLE_CONNECTION);
+
// Start monitoring the socket.
btsock_thread_add_fd(pth, srv_rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_EXCEPTION,
srv_rs->id);
@@ -525,6 +557,13 @@
slot->rfc_port_handle = BTA_JvRfcommGetPortHdl(p_open->handle);
slot->addr = p_open->rem_bda;
+ bluetooth::common::LogSocketConnectionState(
+ slot->addr, slot->id, BTSOCK_RFCOMM,
+ android::bluetooth::SOCKET_CONNECTION_STATE_CONNECTED, 0, 0,
+ slot->app_uid, slot->scn,
+ slot->f.server ? android::bluetooth::SOCKET_ROLE_LISTEN
+ : android::bluetooth::SOCKET_ROLE_CONNECTION);
+
if (send_app_connect_signal(slot->fd, &slot->addr, slot->scn, 0, -1)) {
slot->f.connected = true;
} else {
@@ -539,7 +578,15 @@
// rfc_handle already closed when receiving rfcomm close event from stack.
rfc_slot_t* slot = find_rfc_slot_by_id(id);
- if (slot) cleanup_rfc_slot(slot);
+ if (slot) {
+ bluetooth::common::LogSocketConnectionState(
+ slot->addr, slot->id, BTSOCK_RFCOMM,
+ android::bluetooth::SOCKET_CONNECTION_STATE_DISCONNECTING, 0, 0,
+ slot->app_uid, slot->scn,
+ slot->f.server ? android::bluetooth::SOCKET_ROLE_LISTEN
+ : android::bluetooth::SOCKET_ROLE_CONNECTION);
+ cleanup_rfc_slot(slot);
+ }
}
static void on_rfc_write_done(tBTA_JV_RFCOMM_WRITE* p, uint32_t id) {
@@ -559,6 +606,7 @@
btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD,
slot->id);
}
+ slot->tx_bytes += p->len;
}
uid_set_add_tx(uid_set, app_uid, p->len);
@@ -877,6 +925,7 @@
list_append(slot->incoming_queue, p_buf);
}
+ slot->rx_bytes += bytes_rx;
uid_set_add_rx(uid_set, app_uid, bytes_rx);
return ret; // Return 0 to disable data flow.
diff --git a/btif/src/btif_storage.cc b/btif/src/btif_storage.cc
index ef2e191..b6ffcda 100644
--- a/btif/src/btif_storage.cc
+++ b/btif/src/btif_storage.cc
@@ -41,7 +41,6 @@
#include <time.h>
#include "bt_common.h"
-#include "bta_closure_api.h"
#include "bta_hd_api.h"
#include "bta_hearing_aid_api.h"
#include "bta_hh_api.h"
@@ -83,6 +82,8 @@
#define BTIF_STORAGE_PATH_REMOTE_HIDINFO "HidInfo"
#define BTIF_STORAGE_KEY_ADAPTER_NAME "Name"
#define BTIF_STORAGE_KEY_ADAPTER_SCANMODE "ScanMode"
+#define BTIF_STORAGE_KEY_LOCAL_IO_CAPS "LocalIOCaps"
+#define BTIF_STORAGE_KEY_LOCAL_IO_CAPS_BLE "LocalIOCapsBLE"
#define BTIF_STORAGE_KEY_ADAPTER_DISC_TIMEOUT "DiscoveryTimeout"
/* This is a local property to add a device found */
@@ -225,6 +226,14 @@
btif_config_set_int("Adapter", BTIF_STORAGE_KEY_ADAPTER_SCANMODE,
*(int*)prop->val);
break;
+ case BT_PROPERTY_LOCAL_IO_CAPS:
+ btif_config_set_int("Adapter", BTIF_STORAGE_KEY_LOCAL_IO_CAPS,
+ *(int*)prop->val);
+ break;
+ case BT_PROPERTY_LOCAL_IO_CAPS_BLE:
+ btif_config_set_int("Adapter", BTIF_STORAGE_KEY_LOCAL_IO_CAPS_BLE,
+ *(int*)prop->val);
+ break;
case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT:
btif_config_set_int("Adapter", BTIF_STORAGE_KEY_ADAPTER_DISC_TIMEOUT,
*(int*)prop->val);
@@ -326,6 +335,18 @@
ret = btif_config_get_int("Adapter", BTIF_STORAGE_KEY_ADAPTER_SCANMODE,
(int*)prop->val);
break;
+
+ case BT_PROPERTY_LOCAL_IO_CAPS:
+ if (prop->len >= (int)sizeof(int))
+ ret = btif_config_get_int("Adapter", BTIF_STORAGE_KEY_LOCAL_IO_CAPS,
+ (int*)prop->val);
+ break;
+ case BT_PROPERTY_LOCAL_IO_CAPS_BLE:
+ if (prop->len >= (int)sizeof(int))
+ ret = btif_config_get_int("Adapter", BTIF_STORAGE_KEY_LOCAL_IO_CAPS_BLE,
+ (int*)prop->val);
+ break;
+
case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT:
if (prop->len >= (int)sizeof(int))
ret = btif_config_get_int(
@@ -394,9 +415,9 @@
static bt_status_t btif_in_fetch_bonded_device(const std::string& bdstr) {
bool bt_linkkey_file_found = false;
- LINK_KEY link_key;
- size_t size = sizeof(link_key);
- if (btif_config_get_bin(bdstr, "LinkKey", (uint8_t*)link_key, &size)) {
+ LinkKey link_key;
+ size_t size = link_key.size();
+ if (btif_config_get_bin(bdstr, "LinkKey", link_key.data(), &size)) {
int linkkey_type;
if (btif_config_get_int(bdstr, "LinkKeyType", &linkkey_type)) {
bt_linkkey_file_found = true;
@@ -438,9 +459,9 @@
if (!RawAddress::IsValidAddress(name)) continue;
BTIF_TRACE_DEBUG("Remote device:%s", name.c_str());
- LINK_KEY link_key;
+ LinkKey link_key;
size_t size = sizeof(link_key);
- if (btif_config_get_bin(name, "LinkKey", link_key, &size)) {
+ if (btif_config_get_bin(name, "LinkKey", link_key.data(), &size)) {
int linkkey_type;
if (btif_config_get_int(name, "LinkKeyType", &linkkey_type)) {
RawAddress bd_addr;
@@ -466,8 +487,7 @@
bt_linkkey_file_found = false;
}
}
- if (!btif_in_fetch_bonded_ble_device(name.c_str(), add, p_bonded_devices) &&
- !bt_linkkey_file_found) {
+ if (!btif_in_fetch_bonded_ble_device(name, add, p_bonded_devices) && !bt_linkkey_file_found) {
BTIF_TRACE_DEBUG("Remote device:%s, no link key or ble key found",
name.c_str());
}
@@ -545,6 +565,57 @@
return num_uuids;
}
+/**
+ * Helper function for fetching a local Input/Output capability property. If not
+ * set, it returns the default value.
+ */
+static uint8_t btif_storage_get_io_cap_property(bt_property_type_t type,
+ uint8_t default_value) {
+ char buf[sizeof(int)];
+
+ bt_property_t property;
+ property.type = type;
+ property.val = (void*)buf;
+ property.len = sizeof(int);
+
+ bt_status_t ret = btif_storage_get_adapter_property(&property);
+
+ return (ret == BT_STATUS_SUCCESS) ? (uint8_t)(*(int*)property.val)
+ : default_value;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_storage_get_io_caps
+ *
+ * Description BTIF storage API - Fetches the local Input/Output
+ * capabilities of the device.
+ *
+ * Returns Returns local IO Capability of device. If not stored,
+ * returns BTM_LOCAL_IO_CAPS.
+ *
+ ******************************************************************************/
+uint8_t btif_storage_get_local_io_caps() {
+ return btif_storage_get_io_cap_property(BT_PROPERTY_LOCAL_IO_CAPS,
+ BTM_LOCAL_IO_CAPS);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_storage_get_io_caps_ble
+ *
+ * Description BTIF storage API - Fetches the local Input/Output
+ * capabilities of the BLE device.
+ *
+ * Returns Returns local IO Capability of BLE device. If not stored,
+ * returns BTM_LOCAL_IO_CAPS_BLE.
+ *
+ ******************************************************************************/
+uint8_t btif_storage_get_local_io_caps_ble() {
+ return btif_storage_get_io_cap_property(BT_PROPERTY_LOCAL_IO_CAPS_BLE,
+ BTM_LOCAL_IO_CAPS_BLE);
+}
+
/*******************************************************************************
*
* Function btif_storage_get_adapter_property
@@ -611,6 +682,7 @@
Uuid::From16Bit(UUID_SERVCLASS_AG_HANDSFREE);
num_uuids++;
}
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
/* intentional fall through: Send both BFP & HSP UUIDs if HFP is
* enabled */
case BTA_HSP_SERVICE_ID: {
@@ -745,12 +817,13 @@
******************************************************************************/
bt_status_t btif_storage_add_bonded_device(RawAddress* remote_bd_addr,
- LINK_KEY link_key, uint8_t key_type,
+ LinkKey link_key, uint8_t key_type,
uint8_t pin_length) {
std::string bdstr = remote_bd_addr->ToString();
int ret = btif_config_set_int(bdstr, "LinkKeyType", (int)key_type);
ret &= btif_config_set_int(bdstr, "PinLength", (int)pin_length);
- ret &= btif_config_set_bin(bdstr, "LinkKey", link_key, sizeof(LINK_KEY));
+ ret &=
+ btif_config_set_bin(bdstr, "LinkKey", link_key.data(), link_key.size());
if (is_restricted_mode()) {
BTIF_TRACE_WARNING("%s: '%s' pairing will be removed if unrestricted",
@@ -1096,8 +1169,8 @@
* BT_STATUS_FAIL otherwise
*
******************************************************************************/
-bt_status_t btif_storage_add_ble_local_key(char* key, uint8_t key_type,
- uint8_t key_length) {
+bt_status_t btif_storage_add_ble_local_key(const Octet16& key,
+ uint8_t key_type) {
const char* name;
switch (key_type) {
case BTIF_DM_LE_LOCAL_KEY_IR:
@@ -1115,24 +1188,17 @@
default:
return BT_STATUS_FAIL;
}
- int ret =
- btif_config_set_bin("Adapter", name, (const uint8_t*)key, key_length);
+ int ret = btif_config_set_bin("Adapter", name, key.data(), key.size());
btif_config_save();
return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
}
-/*******************************************************************************
- *
- * Function btif_storage_get_ble_local_key
- *
- * Description
- *
- * Returns BT_STATUS_SUCCESS if the fetch was successful,
- * BT_STATUS_FAIL otherwise
- *
- ******************************************************************************/
-bt_status_t btif_storage_get_ble_local_key(uint8_t key_type, char* key_value,
- int key_length) {
+/** Stores local key of |key_type| into |key_value|
+ * Returns BT_STATUS_SUCCESS if the fetch was successful, BT_STATUS_FAIL
+ * otherwise
+ */
+bt_status_t btif_storage_get_ble_local_key(uint8_t key_type,
+ Octet16* key_value) {
const char* name;
switch (key_type) {
case BTIF_DM_LE_LOCAL_KEY_IR:
@@ -1150,8 +1216,8 @@
default:
return BT_STATUS_FAIL;
}
- size_t length = key_length;
- int ret = btif_config_get_bin("Adapter", name, (uint8_t*)key_value, &length);
+ size_t length = key_value->size();
+ int ret = btif_config_get_bin("Adapter", name, key_value->data(), &length);
return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
}
@@ -1399,48 +1465,55 @@
return BT_STATUS_SUCCESS;
}
-constexpr char HEARING_AID_PSM[] = "HearingAidPsm";
+constexpr char HEARING_AID_READ_PSM_HANDLE[] = "HearingAidReadPsmHandle";
constexpr char HEARING_AID_CAPABILITIES[] = "HearingAidCapabilities";
constexpr char HEARING_AID_CODECS[] = "HearingAidCodecs";
constexpr char HEARING_AID_AUDIO_CONTROL_POINT[] =
"HearingAidAudioControlPoint";
constexpr char HEARING_AID_VOLUME_HANDLE[] = "HearingAidVolumeHandle";
+constexpr char HEARING_AID_AUDIO_STATUS_HANDLE[] =
+ "HearingAidAudioStatusHandle";
+constexpr char HEARING_AID_AUDIO_STATUS_CCC_HANDLE[] =
+ "HearingAidAudioStatusCccHandle";
+constexpr char HEARING_AID_SERVICE_CHANGED_CCC_HANDLE[] =
+ "HearingAidServiceChangedCccHandle";
constexpr char HEARING_AID_SYNC_ID[] = "HearingAidSyncId";
constexpr char HEARING_AID_RENDER_DELAY[] = "HearingAidRenderDelay";
constexpr char HEARING_AID_PREPARATION_DELAY[] = "HearingAidPreparationDelay";
constexpr char HEARING_AID_IS_WHITE_LISTED[] = "HearingAidIsWhiteListed";
-void btif_storage_add_hearing_aid(const RawAddress& address, uint16_t psm,
- uint8_t capabilities, uint16_t codecs,
- uint16_t audio_control_point_handle,
- uint16_t volume_handle, uint64_t hi_sync_id,
- uint16_t render_delay,
- uint16_t preparation_delay) {
+void btif_storage_add_hearing_aid(const HearingDevice& dev_info) {
do_in_jni_thread(
FROM_HERE,
Bind(
- [](const RawAddress& address, uint16_t psm, uint8_t capabilities,
- uint16_t codecs, uint16_t audio_control_point_handle,
- uint16_t volume_handle, uint64_t hi_sync_id, uint16_t render_delay,
- uint16_t preparation_delay) {
- std::string bdstr = address.ToString();
+ [](const HearingDevice& dev_info) {
+ std::string bdstr = dev_info.address.ToString();
VLOG(2) << "saving hearing aid device: " << bdstr;
- btif_config_set_int(bdstr, HEARING_AID_PSM, psm);
- btif_config_set_int(bdstr, HEARING_AID_CAPABILITIES, capabilities);
- btif_config_set_int(bdstr, HEARING_AID_CODECS, codecs);
+ btif_config_set_int(bdstr, HEARING_AID_SERVICE_CHANGED_CCC_HANDLE,
+ dev_info.service_changed_ccc_handle);
+ btif_config_set_int(bdstr, HEARING_AID_READ_PSM_HANDLE,
+ dev_info.read_psm_handle);
+ btif_config_set_int(bdstr, HEARING_AID_CAPABILITIES,
+ dev_info.capabilities);
+ btif_config_set_int(bdstr, HEARING_AID_CODECS, dev_info.codecs);
btif_config_set_int(bdstr, HEARING_AID_AUDIO_CONTROL_POINT,
- audio_control_point_handle);
+ dev_info.audio_control_point_handle);
btif_config_set_int(bdstr, HEARING_AID_VOLUME_HANDLE,
- volume_handle);
- btif_config_set_uint64(bdstr, HEARING_AID_SYNC_ID, hi_sync_id);
- btif_config_set_int(bdstr, HEARING_AID_RENDER_DELAY, render_delay);
+ dev_info.volume_handle);
+ btif_config_set_int(bdstr, HEARING_AID_AUDIO_STATUS_HANDLE,
+ dev_info.audio_status_handle);
+ btif_config_set_int(bdstr, HEARING_AID_AUDIO_STATUS_CCC_HANDLE,
+ dev_info.audio_status_ccc_handle);
+ btif_config_set_uint64(bdstr, HEARING_AID_SYNC_ID,
+ dev_info.hi_sync_id);
+ btif_config_set_int(bdstr, HEARING_AID_RENDER_DELAY,
+ dev_info.render_delay);
btif_config_set_int(bdstr, HEARING_AID_PREPARATION_DELAY,
- preparation_delay);
+ dev_info.preparation_delay);
btif_config_set_int(bdstr, HEARING_AID_IS_WHITE_LISTED, true);
btif_config_save();
},
- address, psm, capabilities, codecs, audio_control_point_handle,
- volume_handle, hi_sync_id, render_delay, preparation_delay));
+ dev_info));
}
/** Loads information about bonded hearing aid devices */
@@ -1451,19 +1524,35 @@
const std::string& name = section.name;
if (!RawAddress::IsValidAddress(name)) continue;
+ int size = STORAGE_UUID_STRING_SIZE * HEARINGAID_MAX_NUM_UUIDS;
+ char uuid_str[size];
+ bool isHearingaidDevice = false;
+ if (btif_config_get_str(name, BTIF_STORAGE_PATH_REMOTE_SERVICE, uuid_str,
+ &size)) {
+ Uuid p_uuid[HEARINGAID_MAX_NUM_UUIDS];
+ size_t num_uuids =
+ btif_split_uuids_string(uuid_str, p_uuid, HEARINGAID_MAX_NUM_UUIDS);
+ for (size_t i = 0; i < num_uuids; i++) {
+ if (p_uuid[i] == Uuid::FromString("FDF0")) {
+ isHearingaidDevice = true;
+ break;
+ }
+ }
+ }
+ if (!isHearingaidDevice) {
+ continue;
+ }
+
BTIF_TRACE_DEBUG("Remote device:%s", name.c_str());
- int value;
- if (!btif_config_get_int(name, HEARING_AID_PSM, &value)) continue;
- uint16_t psm = value;
-
- if (btif_in_fetch_bonded_device(name.c_str()) != BT_STATUS_SUCCESS) {
+ if (btif_in_fetch_bonded_device(name) != BT_STATUS_SUCCESS) {
RawAddress bd_addr;
RawAddress::FromString(name, bd_addr);
btif_storage_remove_hearing_aid(bd_addr);
continue;
}
+ int value;
uint8_t capabilities = 0;
if (btif_config_get_int(name, HEARING_AID_CAPABILITIES, &value))
capabilities = value;
@@ -1475,10 +1564,27 @@
if (btif_config_get_int(name, HEARING_AID_AUDIO_CONTROL_POINT, &value))
audio_control_point_handle = value;
+ uint16_t audio_status_handle = 0;
+ if (btif_config_get_int(name, HEARING_AID_AUDIO_STATUS_HANDLE, &value))
+ audio_status_handle = value;
+
+ uint16_t audio_status_ccc_handle = 0;
+ if (btif_config_get_int(name, HEARING_AID_AUDIO_STATUS_CCC_HANDLE, &value))
+ audio_status_ccc_handle = value;
+
+ uint16_t service_changed_ccc_handle = 0;
+ if (btif_config_get_int(name, HEARING_AID_SERVICE_CHANGED_CCC_HANDLE,
+ &value))
+ service_changed_ccc_handle = value;
+
uint16_t volume_handle = 0;
if (btif_config_get_int(name, HEARING_AID_VOLUME_HANDLE, &value))
volume_handle = value;
+ uint16_t read_psm_handle = 0;
+ if (btif_config_get_int(name, HEARING_AID_READ_PSM_HANDLE, &value))
+ read_psm_handle = value;
+
uint64_t lvalue;
uint64_t hi_sync_id = 0;
if (btif_config_get_uint64(name, HEARING_AID_SYNC_ID, &lvalue))
@@ -1498,41 +1604,86 @@
RawAddress bd_addr;
RawAddress::FromString(name, bd_addr);
+
// add extracted information to BTA Hearing Aid
- do_in_bta_thread(
+ do_in_main_thread(
FROM_HERE,
- Bind(&HearingAid::AddFromStorage, bd_addr, psm, capabilities, codecs,
- audio_control_point_handle, volume_handle, hi_sync_id,
- render_delay, preparation_delay, is_white_listed));
+ Bind(&HearingAid::AddFromStorage,
+ HearingDevice(bd_addr, capabilities, codecs,
+ audio_control_point_handle, audio_status_handle,
+ audio_status_ccc_handle, service_changed_ccc_handle,
+ volume_handle, read_psm_handle, hi_sync_id,
+ render_delay, preparation_delay),
+ is_white_listed));
}
}
/** Deletes the bonded hearing aid device info from NVRAM */
void btif_storage_remove_hearing_aid(const RawAddress& address) {
std::string addrstr = address.ToString();
-
- btif_config_remove(addrstr, HEARING_AID_PSM);
+ btif_config_remove(addrstr, HEARING_AID_READ_PSM_HANDLE);
btif_config_remove(addrstr, HEARING_AID_CAPABILITIES);
btif_config_remove(addrstr, HEARING_AID_CODECS);
btif_config_remove(addrstr, HEARING_AID_AUDIO_CONTROL_POINT);
btif_config_remove(addrstr, HEARING_AID_VOLUME_HANDLE);
+ btif_config_remove(addrstr, HEARING_AID_AUDIO_STATUS_HANDLE);
+ btif_config_remove(addrstr, HEARING_AID_AUDIO_STATUS_CCC_HANDLE);
+ btif_config_remove(addrstr, HEARING_AID_SERVICE_CHANGED_CCC_HANDLE);
btif_config_remove(addrstr, HEARING_AID_SYNC_ID);
+ btif_config_remove(addrstr, HEARING_AID_RENDER_DELAY);
+ btif_config_remove(addrstr, HEARING_AID_PREPARATION_DELAY);
btif_config_remove(addrstr, HEARING_AID_IS_WHITE_LISTED);
btif_config_save();
}
-/** Add the hearing aid device to white list */
-void btif_storage_add_hearing_aid_to_white_list(const RawAddress& address) {
+/** Set/Unset the hearing aid device HEARING_AID_IS_WHITE_LISTED flag. */
+void btif_storage_set_hearing_aid_white_list(const RawAddress& address,
+ bool add_to_whitelist) {
std::string addrstr = address.ToString();
- btif_config_set_int(addrstr, HEARING_AID_IS_WHITE_LISTED, true);
+ btif_config_set_int(addrstr, HEARING_AID_IS_WHITE_LISTED, add_to_whitelist);
+ btif_config_save();
}
-/** Remove the hearing aid device from white list */
-void btif_storage_remove_hearing_aid_white_list(const RawAddress& address) {
+/** Get the hearing aid device properties. */
+bool btif_storage_get_hearing_aid_prop(
+ const RawAddress& address, uint8_t* capabilities, uint64_t* hi_sync_id,
+ uint16_t* render_delay, uint16_t* preparation_delay, uint16_t* codecs) {
std::string addrstr = address.ToString();
- btif_config_set_int(addrstr, HEARING_AID_IS_WHITE_LISTED, false);
+ int value;
+ if (btif_config_get_int(addrstr, HEARING_AID_CAPABILITIES, &value)) {
+ *capabilities = value;
+ } else {
+ return false;
+ }
+
+ if (btif_config_get_int(addrstr, HEARING_AID_CODECS, &value)) {
+ *codecs = value;
+ } else {
+ return false;
+ }
+
+ if (btif_config_get_int(addrstr, HEARING_AID_RENDER_DELAY, &value)) {
+ *render_delay = value;
+ } else {
+ return false;
+ }
+
+ if (btif_config_get_int(addrstr, HEARING_AID_PREPARATION_DELAY, &value)) {
+ *preparation_delay = value;
+ } else {
+ return false;
+ }
+
+ uint64_t lvalue;
+ if (btif_config_get_uint64(addrstr, HEARING_AID_SYNC_ID, &lvalue)) {
+ *hi_sync_id = lvalue;
+ } else {
+ return false;
+ }
+
+ return true;
}
/*******************************************************************************
@@ -1550,6 +1701,12 @@
return btif_config_exist(remote_bd_addr->ToString(), "Restricted");
}
+int btif_storage_get_num_bonded_devices(void) {
+ btif_bonded_devices_t bonded_devices;
+ btif_in_fetch_bonded_devices(&bonded_devices, 0);
+ return bonded_devices.num_devices;
+}
+
/*******************************************************************************
* Function btif_storage_load_hidd
*
diff --git a/btif/src/stack_manager.cc b/btif/src/stack_manager.cc
index e37db87..60c2c0c 100644
--- a/btif/src/stack_manager.cc
+++ b/btif/src/stack_manager.cc
@@ -26,18 +26,20 @@
#include "btcore/include/osi_module.h"
#include "btif_api.h"
#include "btif_common.h"
+#include "common/message_loop_thread.h"
#include "device/include/controller.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
#include "osi/include/semaphore.h"
-#include "osi/include/thread.h"
// Temp includes
#include "bt_utils.h"
#include "btif_config.h"
#include "btif_profile_queue.h"
-static thread_t* management_thread;
+using bluetooth::common::MessageLoopThread;
+
+static MessageLoopThread management_thread("bt_stack_manager_thread");
// If initialized, any of the bluetooth API functions can be called.
// (e.g. turning logging on and off, enabling/disabling the stack, etc)
@@ -56,40 +58,44 @@
// Unvetted includes/imports, etc which should be removed or vetted in the
// future
static future_t* hack_future;
-void btif_thread_post(thread_fn func, void* context);
// End unvetted section
// Interface functions
-static void init_stack(void) {
+static void init_stack() {
// This is a synchronous process. Post it to the thread though, so
// state modification only happens there. Using the thread to perform
// all stack operations ensures that the operations are done serially
// and do not overlap.
semaphore_t* semaphore = semaphore_new(0);
- thread_post(management_thread, event_init_stack, semaphore);
+ management_thread.DoInThread(FROM_HERE,
+ base::Bind(event_init_stack, semaphore));
semaphore_wait(semaphore);
semaphore_free(semaphore);
}
-static void start_up_stack_async(void) {
- thread_post(management_thread, event_start_up_stack, NULL);
+static void start_up_stack_async() {
+ management_thread.DoInThread(FROM_HERE,
+ base::Bind(event_start_up_stack, nullptr));
}
-static void shut_down_stack_async(void) {
- thread_post(management_thread, event_shut_down_stack, NULL);
+static void shut_down_stack_async() {
+ management_thread.DoInThread(FROM_HERE,
+ base::Bind(event_shut_down_stack, nullptr));
}
-static void clean_up_stack(void) {
+static void clean_up_stack() {
// This is a synchronous process. Post it to the thread though, so
// state modification only happens there.
semaphore_t* semaphore = semaphore_new(0);
- thread_post(management_thread, event_clean_up_stack, semaphore);
+ management_thread.DoInThread(FROM_HERE,
+ base::Bind(event_clean_up_stack, semaphore));
semaphore_wait(semaphore);
semaphore_free(semaphore);
+ management_thread.ShutDown();
}
-static bool get_stack_is_running(void) { return stack_is_running; }
+static bool get_stack_is_running() { return stack_is_running; }
// Internal functions
@@ -119,12 +125,12 @@
if (semaphore) semaphore_post(semaphore);
}
-static void ensure_stack_is_initialized(void) {
+static void ensure_stack_is_initialized() {
if (!stack_is_initialized) {
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);
+ event_init_stack(nullptr);
}
}
@@ -148,13 +154,13 @@
if (future_await(local_hack_future) != FUTURE_SUCCESS) {
LOG_ERROR(LOG_TAG, "%s failed to start up the stack", __func__);
stack_is_running = true; // So stack shutdown actually happens
- event_shut_down_stack(NULL);
+ event_shut_down_stack(nullptr);
return;
}
stack_is_running = true;
LOG_INFO(LOG_TAG, "%s finished", __func__);
- btif_thread_post(event_signal_stack_up, NULL);
+ do_in_jni_thread(FROM_HERE, base::Bind(event_signal_stack_up, nullptr));
}
// Synchronous function to shut down the stack
@@ -178,17 +184,17 @@
// state
hack_future = future_new();
- btif_thread_post(event_signal_stack_down, NULL);
+ do_in_jni_thread(FROM_HERE, base::Bind(event_signal_stack_down, nullptr));
future_await(hack_future);
LOG_INFO(LOG_TAG, "%s finished", __func__);
}
-static void ensure_stack_is_not_running(void) {
+static void ensure_stack_is_not_running() {
if (stack_is_running) {
LOG_WARN(LOG_TAG,
"%s found the stack was still running. Bringing it down now.",
__func__);
- event_shut_down_stack(NULL);
+ event_shut_down_stack(nullptr);
}
}
@@ -228,19 +234,18 @@
future_ready(stack_manager_get_hack_future(), FUTURE_SUCCESS);
}
-static void ensure_manager_initialized(void) {
- if (management_thread) return;
+static void ensure_manager_initialized() {
+ if (management_thread.IsRunning()) return;
- management_thread = thread_new("stack_manager");
- if (!management_thread) {
- LOG_ERROR(LOG_TAG, "%s unable to create stack management thread", __func__);
+ management_thread.StartUp();
+ if (!management_thread.IsRunning()) {
+ LOG_ERROR(LOG_TAG, "%s unable to start stack management thread", __func__);
return;
}
}
static const stack_manager_t interface = {init_stack, start_up_stack_async,
shut_down_stack_async, clean_up_stack,
-
get_stack_is_running};
const stack_manager_t* stack_manager_get_interface() {
diff --git a/btif/test/btif_profile_queue_test.cc b/btif/test/btif_profile_queue_test.cc
index f7bce86..486959b 100644
--- a/btif/test/btif_profile_queue_test.cc
+++ b/btif/test/btif_profile_queue_test.cc
@@ -15,12 +15,14 @@
* limitations under the License.
*
******************************************************************************/
+#include "btif/include/btif_profile_queue.h"
+
#include <gtest/gtest.h>
#include <base/bind.h>
+#include <base/callback.h>
+#include <base/location.h>
-#include "base/location.h"
-#include "btif/include/btif_profile_queue.h"
#include "stack_manager.h"
#include "types/raw_address.h"
@@ -33,9 +35,9 @@
static stack_manager_t sStackManager = {nullptr, nullptr, nullptr, nullptr,
get_stack_is_running};
const stack_manager_t* stack_manager_get_interface() { return &sStackManager; }
-bt_status_t do_in_jni_thread(const tracked_objects::Location& from_here,
- const base::Closure& task) {
- task.Run();
+bt_status_t do_in_jni_thread(const base::Location& from_here,
+ base::OnceClosure task) {
+ std::move(task).Run();
return BT_STATUS_SUCCESS;
}
bool is_on_jni_thread() { return true; }
diff --git a/btif/test/btif_state_machine_test.cc b/btif/test/btif_state_machine_test.cc
deleted file mode 100644
index d413a4a..0000000
--- a/btif/test/btif_state_machine_test.cc
+++ /dev/null
@@ -1,261 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2017 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 <gtest/gtest.h>
-
-#include "btif/include/btif_state_machine.h"
-
-namespace {
-static constexpr uint32_t kInvalidEvent = 0xffffffff;
-static constexpr uint32_t kEventZero = 0;
-static constexpr uint32_t kEventOne = 1;
-static constexpr uint32_t kEventTwo = 2;
-
-static char dataZero = 0;
-static char dataOne = 1;
-static char dataTwo = 2;
-} // namespace
-
-class BtifStateMachineImpl : public BtifStateMachine {
- public:
- enum {
- kStateZero,
- kStateOne,
- kStateTwo,
- };
-
- class StateZero : public State {
- public:
- StateZero(BtifStateMachine& sm)
- : State(sm, kStateZero),
- on_enter_(false),
- on_exit_(false),
- event_(kInvalidEvent),
- data_(nullptr) {}
- void OnEnter() override {
- on_enter_ = true;
- on_exit_ = false;
- }
- void OnExit() override {
- on_exit_ = true;
- on_enter_ = false;
- }
- bool ProcessEvent(uint32_t event, void* p_data) override {
- event_ = event;
- data_ = p_data;
- TransitionTo(kStateOne);
- return true;
- }
-
- bool on_enter_;
- bool on_exit_;
- uint32_t event_;
- void* data_;
- };
-
- class StateOne : public State {
- public:
- StateOne(BtifStateMachine& sm)
- : State(sm, kStateOne),
- on_enter_(false),
- on_exit_(false),
- event_(kInvalidEvent),
- data_(nullptr) {}
- void OnEnter() override {
- on_enter_ = true;
- on_exit_ = false;
- }
- void OnExit() override {
- on_exit_ = true;
- on_enter_ = false;
- }
- bool ProcessEvent(uint32_t event, void* p_data) override {
- event_ = event;
- data_ = p_data;
- TransitionTo(kStateTwo);
- return true;
- }
-
- bool on_enter_;
- bool on_exit_;
- uint32_t event_;
- void* data_;
- };
-
- class StateTwo : public State {
- public:
- StateTwo(BtifStateMachine& sm)
- : State(sm, kStateTwo),
- on_enter_(false),
- on_exit_(false),
- event_(kInvalidEvent),
- data_(nullptr) {}
- void OnEnter() override {
- on_enter_ = true;
- on_exit_ = false;
- }
- void OnExit() override {
- on_exit_ = true;
- on_enter_ = false;
- }
- bool ProcessEvent(uint32_t event, void* p_data) override {
- event_ = event;
- data_ = p_data;
- TransitionTo(kStateZero);
- return true;
- }
-
- bool on_enter_;
- bool on_exit_;
- uint32_t event_;
- void* data_;
- };
-
- BtifStateMachineImpl() {
- state_zero_ = new StateZero(*this);
- state_one_ = new StateOne(*this);
- state_two_ = new StateTwo(*this);
-
- AddState(state_zero_);
- AddState(state_one_);
- AddState(state_two_);
- SetInitialState(state_zero_);
- }
-
- StateZero* state_zero_;
- StateOne* state_one_;
- StateTwo* state_two_;
-};
-
-class BtifStateMachineTest : public ::testing::Test {
- protected:
- BtifStateMachineTest() {}
-
- void SetUp() override { sm_.Start(); }
-
- void TearDown() override { sm_.Quit(); }
-
- BtifStateMachineImpl sm_;
-};
-
-TEST_F(BtifStateMachineTest, test_initial_state) {
- ASSERT_EQ(sm_.kStateZero, sm_.StateId());
- ASSERT_EQ(sm_.kStateInvalid, sm_.PreviousStateId());
-}
-
-TEST_F(BtifStateMachineTest, test_invalid_state) {
- sm_.Quit();
- ASSERT_EQ(sm_.kStateInvalid, sm_.StateId());
- ASSERT_EQ(sm_.kStateInvalid, sm_.PreviousStateId());
- sm_.Start();
- ASSERT_EQ(sm_.kStateZero, sm_.StateId());
- ASSERT_EQ(sm_.kStateInvalid, sm_.PreviousStateId());
-}
-
-TEST_F(BtifStateMachineTest, test_transition_to) {
- // Initial state: StateZero
- ASSERT_EQ(sm_.kStateZero, sm_.StateId());
- ASSERT_EQ(sm_.kStateInvalid, sm_.PreviousStateId());
- ASSERT_TRUE(sm_.state_zero_->on_enter_);
- ASSERT_FALSE(sm_.state_zero_->on_exit_);
-
- // Transition to StateOne
- ASSERT_FALSE(sm_.state_one_->on_enter_);
- ASSERT_FALSE(sm_.state_one_->on_exit_);
- sm_.TransitionTo(sm_.kStateOne);
- ASSERT_EQ(sm_.kStateOne, sm_.StateId());
- ASSERT_EQ(sm_.kStateZero, sm_.PreviousStateId());
- ASSERT_TRUE(sm_.state_zero_->on_exit_);
- ASSERT_TRUE(sm_.state_one_->on_enter_);
- ASSERT_FALSE(sm_.state_one_->on_exit_);
-
- // Transition to StateTwo
- ASSERT_FALSE(sm_.state_two_->on_enter_);
- ASSERT_FALSE(sm_.state_two_->on_exit_);
- sm_.TransitionTo(sm_.kStateTwo);
- ASSERT_EQ(sm_.kStateTwo, sm_.StateId());
- ASSERT_EQ(sm_.kStateOne, sm_.PreviousStateId());
- ASSERT_TRUE(sm_.state_one_->on_exit_);
- ASSERT_TRUE(sm_.state_two_->on_enter_);
- ASSERT_FALSE(sm_.state_two_->on_exit_);
-}
-
-TEST_F(BtifStateMachineTest, test_process_event) {
- // Initial state: StateZero
- ASSERT_EQ(sm_.kStateZero, sm_.StateId());
- ASSERT_EQ(sm_.kStateInvalid, sm_.PreviousStateId());
- ASSERT_TRUE(sm_.state_zero_->on_enter_);
- ASSERT_FALSE(sm_.state_zero_->on_exit_);
- ASSERT_EQ(sm_.state_zero_->event_, kInvalidEvent);
- ASSERT_EQ(sm_.state_zero_->data_, nullptr);
-
- // Process an event and transition to StateOne
- ASSERT_FALSE(sm_.state_one_->on_enter_);
- ASSERT_FALSE(sm_.state_one_->on_exit_);
- ASSERT_EQ(sm_.state_one_->event_, kInvalidEvent);
- ASSERT_EQ(sm_.state_one_->data_, nullptr);
- ASSERT_TRUE(sm_.ProcessEvent(kEventZero, &dataZero));
- ASSERT_EQ(sm_.kStateOne, sm_.StateId());
- ASSERT_EQ(sm_.kStateZero, sm_.PreviousStateId());
- // Check StateZero
- ASSERT_EQ(sm_.state_zero_->event_, kEventZero);
- ASSERT_EQ(sm_.state_zero_->data_, &dataZero);
- ASSERT_TRUE(sm_.state_zero_->on_exit_);
- // Check StateOne
- ASSERT_TRUE(sm_.state_one_->on_enter_);
- ASSERT_FALSE(sm_.state_one_->on_exit_);
- ASSERT_EQ(sm_.state_one_->event_, kInvalidEvent);
- ASSERT_EQ(sm_.state_one_->data_, nullptr);
-
- // Process an event and transition to StateTwo
- ASSERT_FALSE(sm_.state_two_->on_enter_);
- ASSERT_FALSE(sm_.state_two_->on_exit_);
- ASSERT_EQ(sm_.state_two_->event_, kInvalidEvent);
- ASSERT_EQ(sm_.state_two_->data_, nullptr);
- ASSERT_TRUE(sm_.ProcessEvent(kEventOne, &dataOne));
- ASSERT_EQ(sm_.kStateTwo, sm_.StateId());
- ASSERT_EQ(sm_.kStateOne, sm_.PreviousStateId());
- // Check StateOne
- ASSERT_EQ(sm_.state_one_->event_, kEventOne);
- ASSERT_EQ(sm_.state_one_->data_, &dataOne);
- ASSERT_TRUE(sm_.state_one_->on_exit_);
- // Check StateTwo
- ASSERT_TRUE(sm_.state_two_->on_enter_);
- ASSERT_FALSE(sm_.state_two_->on_exit_);
- ASSERT_EQ(sm_.state_two_->event_, kInvalidEvent);
- ASSERT_EQ(sm_.state_two_->data_, nullptr);
-
- // Process an event and transition to StateZero
- // NOTE: StateZero was exited before and has local state
- ASSERT_FALSE(sm_.state_zero_->on_enter_);
- ASSERT_TRUE(sm_.state_zero_->on_exit_); // NOTE: already exited before
- ASSERT_EQ(sm_.state_zero_->event_, kEventZero); // NOTE: state from before
- ASSERT_EQ(sm_.state_zero_->data_, &dataZero); // NOTE: state from before
- ASSERT_TRUE(sm_.ProcessEvent(kEventTwo, &dataTwo));
- ASSERT_EQ(sm_.kStateZero, sm_.StateId());
- ASSERT_EQ(sm_.kStateTwo, sm_.PreviousStateId());
- // Check StateTwo
- ASSERT_EQ(sm_.state_two_->event_, kEventTwo);
- ASSERT_EQ(sm_.state_two_->data_, &dataTwo);
- ASSERT_TRUE(sm_.state_two_->on_exit_);
- // Check StateZero
- ASSERT_TRUE(sm_.state_zero_->on_enter_);
- ASSERT_FALSE(sm_.state_zero_->on_exit_);
- ASSERT_EQ(sm_.state_zero_->event_, kEventZero); // NOTE: state from before
- ASSERT_EQ(sm_.state_zero_->data_, &dataZero); // NOTE: state from before
-}
diff --git a/build/Android.bp b/build/Android.bp
index b8abb0f..768d6ec 100644
--- a/build/Android.bp
+++ b/build/Android.bp
@@ -55,9 +55,61 @@
fluoride_defaults {
name: "fluoride_defaults",
+ target: {
+ android: {
+ test_config_template: ":BluetoothTestConfigTemplate",
+ },
+ },
defaults: ["fluoride_types_defaults"],
header_libs: ["libbluetooth_headers"],
+ shared_libs: ["libstatslog"],
static_libs: [
"libbluetooth-types",
+ "libbt-platform-protos-lite",
],
+ cpp_std: "c++17",
+ sanitize: {
+ misc_undefined: ["bounds"],
+ },
+}
+
+// Enables code coverage for a set of source files. Must be combined with
+// "clang_coverage_bin" in order to work. See //test/gen_coverage.py for more information
+// on generating code coverage.
+cc_defaults {
+ name: "clang_file_coverage",
+ target: {
+ host: {
+ clang_cflags: [
+ "-fprofile-instr-generate",
+ "-fcoverage-mapping",
+
+ // New pass manager does not work with -fprofile-instr-generate yet.
+ // http://b/131132095
+ "-fno-experimental-new-pass-manager",
+ ],
+ },
+ },
+}
+
+// Enabled code coverage on a binary. These flags allow libraries that were
+// compiled with "clang_file_coverage" to be properly linked together in
+// order to create a binary that will create a profraw file when ran. Note
+// these flags themselves don't enable code coverage for the source files
+// compiled in the binary. See //test/gen_coverage.py for more information
+// on generating code coverage.
+cc_defaults {
+ name: "clang_coverage_bin",
+ target: {
+ host: {
+ ldflags: [
+ "-fprofile-instr-generate",
+ "-fcoverage-mapping",
+
+ // New pass manager does not work with -fprofile-instr-generate yet.
+ // http://b/131132095
+ "-fno-experimental-new-pass-manager",
+ ],
+ },
+ },
}
diff --git a/build/BUILD.gn b/build/BUILD.gn
index f09a274..922a3f6 100644
--- a/build/BUILD.gn
+++ b/build/BUILD.gn
@@ -59,6 +59,8 @@
# 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",
+
+ "FALLTHROUGH_INTENDED",
]
}
diff --git a/build/secondary/third_party/aac/BUILD.gn b/build/secondary/third_party/aac/BUILD.gn
index d9e79a7..18fcf93 100644
--- a/build/secondary/third_party/aac/BUILD.gn
+++ b/build/secondary/third_party/aac/BUILD.gn
@@ -18,11 +18,15 @@
include_dirs = [
"libAACdec/include",
"libAACenc/include",
+ "libArithCoding/include",
+ "libDRCdec/include",
"libPCMutils/include",
"libFDK/include",
"libSYS/include",
"libMpegTPDec/include",
"libMpegTPEnc/include",
+ "libSACenc/include",
+ "libSACdec/include",
"libSBRdec/include",
"libSBRenc/include",
]
@@ -31,17 +35,13 @@
#TODO(jpawlowski): this files are not build right now, but might be useful when
# arm platform linux compilation is in use:
# "libAACdec/src/arm/block_arm.cpp",
-# "libFDK/src/arm/autocorr2nd.cpp",
# "libFDK/src/arm/dct_arm.cpp",
# "libFDK/src/arm/fft_rad2_arm.cpp",
-# "libFDK/src/arm/qmf_arm.cpp",
# "libFDK/src/arm/scale_arm.cpp",
-# "libSBRdec/src/arm/env_calc_arm.cpp",
# "libSBRdec/src/arm/lpp_tran_arm.cpp",
-# "libSYS/src/mips/genericStds_mips.cpp",
# "libFDK/src/mips/fft_rad2_mips.cpp",
# "libFDK/src/mips/mips_fft_twiddles.cpp",
-# "libFDK/src/mips/scale.cpp",
+# "libFDK/src/mips/scale_mips.cpp",
static_library("libFraunhoferAAC") {
sources = [
@@ -59,12 +59,20 @@
"libAACdec/src/channel.cpp",
"libAACdec/src/channelinfo.cpp",
"libAACdec/src/conceal.cpp",
+ "libAACdec/src/FDK_delay.cpp",
"libAACdec/src/ldfiltbank.cpp",
"libAACdec/src/pulsedata.cpp",
"libAACdec/src/rvlcbit.cpp",
"libAACdec/src/rvlcconceal.cpp",
"libAACdec/src/rvlc.cpp",
"libAACdec/src/stereo.cpp",
+ "libAACdec/src/usacdec_ace_d4t64.cpp",
+ "libAACdec/src/usacdec_acelp.cpp",
+ "libAACdec/src/usacdec_ace_ltp.cpp",
+ "libAACdec/src/usacdec_fac.cpp",
+ "libAACdec/src/usacdec_lpc.cpp",
+ "libAACdec/src/usacdec_lpd.cpp",
+ "libAACdec/src/usacdec_rom.cpp",
"libAACenc/src/aacenc.cpp",
"libAACenc/src/aacenc_lib.cpp",
"libAACenc/src/aacenc_pns.cpp",
@@ -85,6 +93,7 @@
"libAACenc/src/line_pe.cpp",
"libAACenc/src/metadata_compressor.cpp",
"libAACenc/src/metadata_main.cpp",
+ "libAACenc/src/mps_main.cpp",
"libAACenc/src/ms_stereo.cpp",
"libAACenc/src/noisedet.cpp",
"libAACenc/src/pnsparam.cpp",
@@ -97,18 +106,34 @@
"libAACenc/src/spreading.cpp",
"libAACenc/src/tonality.cpp",
"libAACenc/src/transform.cpp",
+ "libArithCoding/src/ac_arith_coder.cpp",
+ "libDRCdec/src/drcDec_gainDecoder.cpp",
+ "libDRCdec/src/drcDec_reader.cpp",
+ "libDRCdec/src/drcDec_rom.cpp",
+ "libDRCdec/src/drcDec_selectionProcess.cpp",
+ "libDRCdec/src/drcDec_tools.cpp",
+ "libDRCdec/src/drcGainDec_init.cpp",
+ "libDRCdec/src/drcGainDec_preprocess.cpp",
+ "libDRCdec/src/drcGainDec_process.cpp",
+ "libDRCdec/src/FDK_drcDecLib.cpp",
"libFDK/src/autocorr2nd.cpp",
"libFDK/src/dct.cpp",
"libFDK/src/FDK_bitbuffer.cpp",
"libFDK/src/FDK_core.cpp",
"libFDK/src/FDK_crc.cpp",
+ "libFDK/src/FDK_decorrelate.cpp",
"libFDK/src/FDK_hybrid.cpp",
+ "libFDK/src/FDK_lpc.cpp",
+ "libFDK/src/FDK_matrixCalloc.cpp",
+ "libFDK/src/FDK_qmf_domain.cpp",
"libFDK/src/FDK_tools_rom.cpp",
"libFDK/src/FDK_trigFcts.cpp",
"libFDK/src/fft.cpp",
"libFDK/src/fft_rad2.cpp",
"libFDK/src/fixpoint_math.cpp",
+ "libFDK/src/huff_nodes.cpp",
"libFDK/src/mdct.cpp",
+ "libFDK/src/nlc_dec.cpp",
"libFDK/src/qmf.cpp",
"libFDK/src/scale.cpp",
"libMpegTPDec/src/tpdec_adif.cpp",
@@ -123,15 +148,45 @@
"libMpegTPEnc/src/tpenc_latm.cpp",
"libMpegTPEnc/src/tpenc_lib.cpp",
"libPCMutils/src/limiter.cpp",
- "libPCMutils/src/pcmutils_lib.cpp",
+ "libPCMutils/src/pcmdmx_lib.cpp",
+ "libPCMutils/src/pcm_utils.cpp",
+ "libSACdec/src/sac_bitdec.cpp",
+ "libSACdec/src/sac_calcM1andM2.cpp",
+ "libSACdec/src/sac_dec_conceal.cpp",
+ "libSACdec/src/sac_dec.cpp",
+ "libSACdec/src/sac_dec_lib.cpp",
+ "libSACdec/src/sac_process.cpp",
+ "libSACdec/src/sac_qmf.cpp",
+ "libSACdec/src/sac_reshapeBBEnv.cpp",
+ "libSACdec/src/sac_rom.cpp",
+ "libSACdec/src/sac_smoothing.cpp",
+ "libSACdec/src/sac_stp.cpp",
+ "libSACdec/src/sac_tsd.cpp",
+ "libSACenc/src/sacenc_bitstream.cpp",
+ "libSACenc/src/sacenc_delay.cpp",
+ "libSACenc/src/sacenc_dmx_tdom_enh.cpp",
+ "libSACenc/src/sacenc_filter.cpp",
+ "libSACenc/src/sacenc_framewindowing.cpp",
+ "libSACenc/src/sacenc_huff_tab.cpp",
+ "libSACenc/src/sacenc_lib.cpp",
+ "libSACenc/src/sacenc_nlc_enc.cpp",
+ "libSACenc/src/sacenc_onsetdetect.cpp",
+ "libSACenc/src/sacenc_paramextract.cpp",
+ "libSACenc/src/sacenc_staticgain.cpp",
+ "libSACenc/src/sacenc_tree.cpp",
+ "libSACenc/src/sacenc_vectorfunctions.cpp",
"libSBRdec/src/env_calc.cpp",
"libSBRdec/src/env_dec.cpp",
"libSBRdec/src/env_extr.cpp",
+ "libSBRdec/src/hbe.cpp",
+ "libSBRdec/src/HFgen_preFlat.cpp",
"libSBRdec/src/huff_dec.cpp",
"libSBRdec/src/lpp_tran.cpp",
"libSBRdec/src/psbitdec.cpp",
"libSBRdec/src/psdec.cpp",
- "libSBRdec/src/psdec_hybrid.cpp",
+ "libSBRdec/src/psdec_drm.cpp",
+ "libSBRdec/src/psdecrom_drm.cpp",
+ "libSBRdec/src/pvc_dec.cpp",
"libSBRdec/src/sbr_crc.cpp",
"libSBRdec/src/sbr_deb.cpp",
"libSBRdec/src/sbr_dec.cpp",
@@ -154,20 +209,13 @@
"libSBRenc/src/resampler.cpp",
"libSBRenc/src/sbrenc_freq_sca.cpp",
"libSBRenc/src/sbr_encoder.cpp",
+ "libSBRenc/src/sbrenc_ram.cpp",
+ "libSBRenc/src/sbrenc_rom.cpp",
"libSBRenc/src/sbr_misc.cpp",
- "libSBRenc/src/sbr_ram.cpp",
- "libSBRenc/src/sbr_rom.cpp",
"libSBRenc/src/ton_corr.cpp",
"libSBRenc/src/tran_det.cpp",
- "libSYS/src/cmdl_parser.cpp",
- "libSYS/src/conv_string.cpp",
"libSYS/src/genericStds.cpp",
- "libSYS/src/linux/audio_linux.cpp",
- "libSYS/src/linux/coresup_linux.cpp",
- "libSYS/src/linux/FDK_stackload_linux.cpp",
- "libSYS/src/linux/genericStds_linux.cpp",
- "libSYS/src/linux/uart_linux.cpp",
- "libSYS/src/wav_file.cpp",
+ "libSYS/src/syslib_channelMapDescr.cpp",
]
public_configs = [ ":libFraunhoferAAC_config" ]
diff --git a/build/secondary/third_party/libchrome/BUILD.gn b/build/secondary/third_party/libchrome/BUILD.gn
index c84b293..1b0d2f0 100644
--- a/build/secondary/third_party/libchrome/BUILD.gn
+++ b/build/secondary/third_party/libchrome/BUILD.gn
@@ -24,13 +24,14 @@
"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/activity_tracker.cc",
"base/debug/alias.cc",
+ "base/debug/dump_without_crashing.cc",
"base/debug/debugger.cc",
"base/debug/debugger_posix.cc",
"base/debug/stack_trace.cc",
@@ -38,6 +39,7 @@
"base/debug/task_annotator.cc",
"base/environment.cc",
"base/files/file.cc",
+ "base/files/file_descriptor_watcher_posix.cc",
"base/files/file_enumerator.cc",
"base/files/file_enumerator_posix.cc",
"base/files/file_path.cc",
@@ -58,30 +60,34 @@
"base/json/json_string_value_serializer.cc",
"base/json/json_writer.cc",
"base/json/string_escape.cc",
- "base/lazy_instance.cc",
+ "base/lazy_instance_helpers.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_current.cc",
"base/message_loop/message_loop_task_runner.cc",
"base/message_loop/message_pump.cc",
"base/message_loop/message_pump_default.cc",
+ "base/message_loop/message_pump_libevent.cc",
+ "base/message_loop/watchable_io_message_pump_posix.cc",
# we don't want any glib dependencies.
# "base/message_loop/message_pump_glib.cc",
- "base/message_loop/message_pump_libevent.cc",
"base/metrics/bucket_ranges.cc",
+ "base/metrics/dummy_histogram.cc",
"base/metrics/field_trial.cc",
- "base/metrics/metrics_hashes.cc",
- "base/metrics/histogram_base.cc",
+ "base/metrics/field_trial_param_associator.cc",
"base/metrics/histogram.cc",
+ "base/metrics/histogram_base.cc",
+ "base/metrics/histogram_functions.cc",
"base/metrics/histogram_samples.cc",
"base/metrics/histogram_snapshot_manager.cc",
+ "base/metrics/metrics_hashes.cc",
"base/metrics/persistent_histogram_allocator.cc",
"base/metrics/persistent_memory_allocator.cc",
"base/metrics/persistent_sample_map.cc",
@@ -89,33 +95,37 @@
"base/metrics/sample_vector.cc",
"base/metrics/sparse_histogram.cc",
"base/metrics/statistics_recorder.cc",
+ "base/native_library.cc",
+ "base/observer_list_threadsafe.cc",
+ "base/path_service.cc",
"base/pending_task.cc",
"base/pickle.cc",
"base/posix/file_descriptor_shuffle.cc",
+ "base/posix/global_descriptors.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/memory.cc",
+ "base/process/process_handle.cc",
"base/process/process_handle_linux.cc",
"base/process/process_handle_posix.cc",
+ "base/process/process_info_linux.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/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/sequence_token.cc",
+ "base/sha1.cc",
"base/strings/pattern.cc",
"base/strings/safe_sprintf.cc",
"base/strings/string16.cc",
@@ -128,11 +138,10 @@
"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/atomic_flag.cc",
"base/synchronization/condition_variable_posix.cc",
"base/synchronization/lock.cc",
"base/synchronization/lock_impl_posix.cc",
- "base/synchronization/read_write_lock_posix.cc",
"base/synchronization/waitable_event_posix.cc",
"base/sync_socket_posix.cc",
"base/sys_info.cc",
@@ -148,64 +157,43 @@
"base/task_runner.cc",
"base/third_party/icu/icu_utf.cc",
"base/third_party/nspr/prtime.cc",
- "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/scoped_blocking_call.cc",
+ "base/threading/sequence_local_storage_map.cc",
+ "base/threading/sequence_local_storage_slot.cc",
"base/threading/sequenced_task_runner_handle.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/threading/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/heap_profiler_allocation_context.cc",
- "base/trace_event/heap_profiler_allocation_context_tracker.cc",
- "base/trace_event/heap_profiler_stack_frame_deduplicator.cc",
- "base/trace_event/heap_profiler_type_name_deduplicator.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/memory_infra_background_whitelist.cc",
- "base/trace_event/process_memory_dump.cc",
- "base/trace_event/process_memory_maps.cc",
- "base/trace_event/process_memory_totals.cc",
- "base/trace_event/trace_buffer.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_memory_overhead.cc",
- "base/trace_event/trace_event_synthetic_delay.cc",
- "base/trace_event/trace_log.cc",
- "base/trace_event/trace_log_constants.cc",
- "base/trace_event/trace_sampling_thread.cc",
- "base/tracked_objects.cc",
- "base/tracking_info.cc",
+ "base/time/time_conversion_posix.cc",
+ "base/time/time_exploded_posix.cc",
+ "base/time/time_now_posix.cc",
+ "base/time/time_override.cc",
+ "base/timer/elapsed_timer.cc",
+ "base/timer/timer.cc",
+ "base/unguessable_token.cc",
+ "base/value_iterators.cc",
"base/values.cc",
+ "base/version.cc",
"base/vlog.cc",
"dbus/bus.cc",
"dbus/dbus_statistics.cc",
"dbus/exported_object.cc",
- "dbus/file_descriptor.cc",
"dbus/message.cc",
"dbus/object_manager.cc",
"dbus/object_path.cc",
diff --git a/common/Android.bp b/common/Android.bp
new file mode 100644
index 0000000..587b197
--- /dev/null
+++ b/common/Android.bp
@@ -0,0 +1,126 @@
+cc_library_static {
+ name: "libbt-common",
+ defaults: [
+ "fluoride_defaults",
+ "clang_file_coverage",
+ ],
+ host_supported: true,
+ include_dirs: [
+ "system/bt",
+ "system/bt/stack/include",
+ ],
+ srcs: [
+ "address_obfuscator.cc",
+ "message_loop_thread.cc",
+ "metrics.cc",
+ "once_timer.cc",
+ "repeating_timer.cc",
+ "time_util.cc",
+ ],
+ shared_libs: [
+ "libcrypto",
+ ],
+ static_libs: [
+ "libbt-protos-lite",
+ ],
+}
+
+cc_test {
+ name: "bluetooth_test_common",
+ test_suites: ["device-tests"],
+ defaults: [
+ "fluoride_defaults",
+ "clang_coverage_bin",
+ ],
+ host_supported: true,
+ include_dirs: [
+ "system/bt",
+ "system/bt/stack/include",
+ ],
+ srcs: [
+ "address_obfuscator_unittest.cc",
+ "leaky_bonded_queue_unittest.cc",
+ "message_loop_thread_unittest.cc",
+ "metrics_unittest.cc",
+ "once_timer_unittest.cc",
+ "repeating_timer_unittest.cc",
+ "state_machine_unittest.cc",
+ "time_util_unittest.cc",
+ "id_generator_unittest.cc",
+ ],
+ shared_libs: [
+ "libprotobuf-cpp-lite",
+ "libcrypto",
+ ],
+ static_libs: [
+ "libgmock",
+ "libbt-common",
+ "libbt-protos-lite",
+ ],
+ sanitize: {
+ cfi: false,
+ },
+}
+
+cc_test {
+ name: "net_test_performance",
+ defaults: ["fluoride_defaults"],
+ test_suites: ["device-tests"],
+ include_dirs: ["system/bt"],
+ host_supported: true,
+ srcs: [
+ "test/thread_performance_test.cc",
+ ],
+ shared_libs: [
+ "liblog",
+ ],
+ static_libs: [
+ "libgmock",
+ "libosi",
+ "libbt-common",
+ ],
+}
+
+cc_benchmark {
+ name: "bluetooth_benchmark_thread_performance",
+ defaults: [
+ "fluoride_defaults",
+ ],
+ host_supported: true,
+ include_dirs: ["system/bt"],
+ srcs: [
+ "benchmark/thread_performance_benchmark.cc",
+ ],
+ shared_libs: [
+ "libcrypto",
+ "liblog",
+ ],
+ static_libs: [
+ "libosi",
+ "libbt-common",
+ ],
+}
+
+cc_benchmark {
+ name: "bluetooth_benchmark_timer_performance",
+ defaults: [
+ "fluoride_defaults",
+ ],
+ host_supported: false,
+ include_dirs: ["system/bt"],
+ srcs: [
+ "benchmark/timer_performance_benchmark.cc",
+ ],
+ shared_libs: [
+ "liblog",
+ "libcrypto",
+ "libprotobuf-cpp-lite",
+ "libcrypto",
+ "libcutils",
+ ],
+ static_libs: [
+ "libosi",
+ "libbt-common",
+ "libbt-protos-lite",
+ ],
+}
diff --git a/common/BUILD.gn b/common/BUILD.gn
new file mode 100644
index 0000000..76d70f8
--- /dev/null
+++ b/common/BUILD.gn
@@ -0,0 +1,62 @@
+#
+# Copyright 2018 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.
+#
+
+static_library("common") {
+ sources = [
+ "message_loop_thread.cc",
+ "metrics_linux.cc",
+ "time_util.cc",
+ "timer.cc",
+ ]
+
+ include_dirs = [
+ "//",
+ "//stack/include",
+ "//linux_include",
+ "//internal_include",
+ ]
+
+ deps = [
+ "//third_party/libchrome:base",
+ ]
+}
+
+executable("bt_test_common") {
+ testonly = true
+ sources = [
+ "leaky_bonded_queue_unittest.cc",
+ "state_machine_unittest.cc",
+ "time_util_unittest.cc",
+ "timer_unittest.cc"
+ ]
+
+ include_dirs = [
+ "//",
+ "//common",
+ ]
+
+ deps = [
+ "//common",
+ "//third_party/googletest:gtest_main",
+ "//third_party/googletest:gmock_main",
+ "//third_party/libchrome:base",
+ ]
+
+ libs = [
+ "-lpthread",
+ "-lrt",
+ ]
+}
diff --git a/common/address_obfuscator.cc b/common/address_obfuscator.cc
new file mode 100644
index 0000000..5c30288
--- /dev/null
+++ b/common/address_obfuscator.cc
@@ -0,0 +1,59 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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 "address_obfuscator.h"
+
+#include <algorithm>
+
+#include <base/logging.h>
+#include <openssl/hmac.h>
+
+#include "bt_trace.h"
+
+namespace bluetooth {
+namespace common {
+
+bool AddressObfuscator::IsSaltValid(const Octet32& salt_256bit) {
+ return !std::all_of(salt_256bit.begin(), salt_256bit.end(),
+ [](uint8_t i) { return i == 0; });
+}
+
+void AddressObfuscator::Initialize(const Octet32& salt_256bit) {
+ std::lock_guard<std::recursive_mutex> lock(instance_mutex_);
+ salt_256bit_ = salt_256bit;
+}
+
+bool AddressObfuscator::IsInitialized() {
+ std::lock_guard<std::recursive_mutex> lock(instance_mutex_);
+ return IsSaltValid(salt_256bit_);
+}
+
+std::string AddressObfuscator::Obfuscate(const RawAddress& address) {
+ std::lock_guard<std::recursive_mutex> lock(instance_mutex_);
+ CHECK(IsInitialized());
+ std::array<uint8_t, EVP_MAX_MD_SIZE> result = {};
+ unsigned int out_len = 0;
+ CHECK(::HMAC(EVP_sha256(), salt_256bit_.data(), salt_256bit_.size(),
+ address.address, address.kLength, result.data(),
+ &out_len) != nullptr);
+ CHECK_EQ(out_len, static_cast<unsigned int>(kOctet32Length));
+ return std::string(reinterpret_cast<const char*>(result.data()), out_len);
+}
+
+} // namespace common
+} // namespace bluetooth
\ No newline at end of file
diff --git a/common/address_obfuscator.h b/common/address_obfuscator.h
new file mode 100644
index 0000000..b8e7dc2
--- /dev/null
+++ b/common/address_obfuscator.h
@@ -0,0 +1,76 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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 <mutex>
+#include <string>
+
+#include "raw_address.h"
+
+namespace bluetooth {
+namespace common {
+
+class AddressObfuscator {
+ public:
+ static constexpr unsigned int kOctet32Length = 32;
+ using Octet32 = std::array<uint8_t, kOctet32Length>;
+ static AddressObfuscator* GetInstance() {
+ static auto instance = new AddressObfuscator();
+ return instance;
+ }
+
+ /**
+ * Return true if the input salt is valid
+ * Criteria:
+ * - Salt must be non-zero
+ *
+ * @param salt_256bit
+ * @return true if the salt is valid
+ */
+ static bool IsSaltValid(const Octet32& salt_256bit);
+
+ /**
+ * Initialize this obfuscator with necessary parameters
+ *
+ * @param salt_256bit a 256 bit salt used to hash the fixed length address
+ */
+ void Initialize(const Octet32& salt_256bit);
+
+ /**
+ * Return true if Initialize() was called earlier
+ */
+ bool IsInitialized();
+
+ /**
+ * Obfuscate Bluetooth MAC address into an anonymous ID string
+ *
+ * @param address Bluetooth MAC address to be obfuscated
+ * @return the obfuscated MAC address in 256 bit
+ */
+ std::string Obfuscate(const RawAddress& address);
+
+ private:
+ AddressObfuscator() : salt_256bit_({0}) {}
+ Octet32 salt_256bit_;
+ std::recursive_mutex instance_mutex_;
+};
+
+} // namespace common
+} // namespace bluetooth
\ No newline at end of file
diff --git a/common/address_obfuscator_unittest.cc b/common/address_obfuscator_unittest.cc
new file mode 100644
index 0000000..d10446f
--- /dev/null
+++ b/common/address_obfuscator_unittest.cc
@@ -0,0 +1,120 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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 "address_obfuscator.h"
+
+#include <gtest/gtest.h>
+
+using bluetooth::common::AddressObfuscator;
+
+constexpr AddressObfuscator::Octet32 kEmptyKey = {0};
+
+constexpr AddressObfuscator::Octet32 kTestKey1 = {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+};
+static RawAddress kTestData1 = {{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}};
+constexpr AddressObfuscator::Octet32 kTestResultRaw1 = {
+ 0x9b, 0x52, 0xb9, 0xb9, 0xb9, 0x34, 0x80, 0x1d, 0x98, 0x0b, 0x10,
+ 0xbe, 0x45, 0xa2, 0x6d, 0xaa, 0x99, 0xc3, 0x04, 0x10, 0x08, 0x03,
+ 0xb7, 0xb4, 0xa9, 0xde, 0xcf, 0x89, 0xe1, 0x5d, 0xd4, 0xaa};
+static std::string kTestResult1(
+ reinterpret_cast<const char*>(kTestResultRaw1.data()),
+ kTestResultRaw1.size());
+
+constexpr AddressObfuscator::Octet32 kTestKey2 = {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+ 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20};
+
+static RawAddress kTestData2_1 = {{0x9e, 0xf5, 0x3d, 0x6c, 0x2e, 0x33}};
+constexpr AddressObfuscator::Octet32 kTestResultRaw2_1 = {
+ 0xb4, 0xe2, 0xfc, 0xb9, 0x59, 0x0d, 0x1f, 0xcf, 0x68, 0x80, 0xb2,
+ 0x3d, 0x08, 0x55, 0x4e, 0x64, 0xf5, 0x3b, 0x33, 0x0d, 0xb6, 0x31,
+ 0x9a, 0xbc, 0x4e, 0xce, 0x61, 0xbd, 0x46, 0x66, 0x45, 0x94};
+static std::string kTestResult2_1(
+ reinterpret_cast<const char*>(kTestResultRaw2_1.data()),
+ kTestResultRaw2_1.size());
+
+static RawAddress kTestData2_2 = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
+constexpr AddressObfuscator::Octet32 kTestResultRaw2_2 = {
+ 0xd4, 0xd8, 0x23, 0xc0, 0x24, 0xba, 0xde, 0xe3, 0x1c, 0xad, 0x84,
+ 0x8b, 0x3d, 0xc6, 0xda, 0x93, 0x88, 0xb2, 0x5c, 0x60, 0x13, 0xe5,
+ 0xe2, 0x3e, 0x75, 0x5f, 0xd7, 0x15, 0x56, 0xf7, 0xaf, 0x27};
+static std::string kTestResult2_2(
+ reinterpret_cast<const char*>(kTestResultRaw2_2.data()),
+ kTestResultRaw2_2.size());
+
+static RawAddress kTestData2_3 = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
+constexpr AddressObfuscator::Octet32 kTestResultRaw2_3 = {
+ 0x6f, 0x7c, 0x3d, 0x23, 0xcc, 0x7a, 0xf2, 0x68, 0xee, 0xe8, 0x6c,
+ 0x0f, 0xb5, 0xe0, 0x0c, 0x88, 0xf6, 0x38, 0x71, 0x44, 0x88, 0x09,
+ 0x45, 0x0a, 0xa2, 0xd7, 0xf6, 0x70, 0xba, 0x8c, 0xe9, 0x79};
+static std::string kTestResult2_3(
+ reinterpret_cast<const char*>(kTestResultRaw2_3.data()),
+ kTestResultRaw2_3.size());
+
+TEST(AddressObfuscatorTest, test_invalid_key) {
+ EXPECT_FALSE(AddressObfuscator::IsSaltValid(kEmptyKey));
+}
+
+TEST(AddressObfuscatorTest, test_valid_key) {
+ EXPECT_TRUE(AddressObfuscator::IsSaltValid(kTestKey1));
+}
+
+TEST(AddressObfuscatorTest, test_initialize_negative) {
+ AddressObfuscator::GetInstance()->Initialize(kEmptyKey);
+ EXPECT_FALSE(AddressObfuscator::GetInstance()->IsInitialized());
+}
+
+TEST(AddressObfuscatorTest, test_initialize_positive) {
+ AddressObfuscator::GetInstance()->Initialize(kTestKey1);
+ EXPECT_TRUE(AddressObfuscator::GetInstance()->IsInitialized());
+}
+
+TEST(AddressObfuscatorTest, test_obfuscate_address_key1) {
+ AddressObfuscator::GetInstance()->Initialize(kTestKey1);
+ std::string result = AddressObfuscator::GetInstance()->Obfuscate(kTestData1);
+ EXPECT_EQ(result.size(), AddressObfuscator::kOctet32Length);
+ EXPECT_EQ(result, kTestResult1);
+}
+
+TEST(AddressObfuscatorTest, test_obfuscate_address_key2) {
+ AddressObfuscator::GetInstance()->Initialize(kTestKey2);
+ std::string result =
+ AddressObfuscator::GetInstance()->Obfuscate(kTestData2_1);
+ EXPECT_EQ(result.size(), AddressObfuscator::kOctet32Length);
+ EXPECT_EQ(result, kTestResult2_1);
+}
+
+TEST(AddressObfuscatorTest, test_obfuscate_address_key2_empty_adddress) {
+ AddressObfuscator::GetInstance()->Initialize(kTestKey2);
+ std::string result =
+ AddressObfuscator::GetInstance()->Obfuscate(kTestData2_2);
+ EXPECT_EQ(result.size(), AddressObfuscator::kOctet32Length);
+ EXPECT_EQ(result, kTestResult2_2);
+}
+
+TEST(AddressObfuscatorTest, test_obfuscate_address_key2_max_address) {
+ AddressObfuscator::GetInstance()->Initialize(kTestKey2);
+ std::string result =
+ AddressObfuscator::GetInstance()->Obfuscate(kTestData2_3);
+ EXPECT_EQ(result.size(), AddressObfuscator::kOctet32Length);
+ EXPECT_EQ(result, kTestResult2_3);
+}
\ No newline at end of file
diff --git a/common/benchmark/thread_performance_benchmark.cc b/common/benchmark/thread_performance_benchmark.cc
new file mode 100644
index 0000000..74f157f
--- /dev/null
+++ b/common/benchmark/thread_performance_benchmark.cc
@@ -0,0 +1,432 @@
+/*
+ * Copyright 2018 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/bind.h>
+#include <base/logging.h>
+#include <base/run_loop.h>
+#include <base/threading/thread.h>
+#include <benchmark/benchmark.h>
+#include <future>
+#include <memory>
+#include <thread>
+
+#include "common/message_loop_thread.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/thread.h"
+
+using ::benchmark::State;
+using bluetooth::common::MessageLoopThread;
+
+#define NUM_MESSAGES_TO_SEND 100000
+
+volatile static int g_counter = 0;
+static std::unique_ptr<std::promise<void>> g_counter_promise = nullptr;
+
+void pthread_callback_batch(void* context) {
+ auto queue = static_cast<fixed_queue_t*>(context);
+ CHECK_NE(queue, nullptr);
+ fixed_queue_dequeue(queue);
+ g_counter++;
+ if (g_counter >= NUM_MESSAGES_TO_SEND) {
+ g_counter_promise->set_value();
+ }
+}
+
+void callback_sequential(void* context) { g_counter_promise->set_value(); }
+
+void callback_sequential_queue(fixed_queue_t* queue, void* context) {
+ CHECK_NE(queue, nullptr);
+ fixed_queue_dequeue(queue);
+ g_counter_promise->set_value();
+}
+
+void callback_batch(fixed_queue_t* queue, void* data) {
+ CHECK_NE(queue, nullptr);
+ fixed_queue_dequeue(queue);
+ g_counter++;
+ if (g_counter >= NUM_MESSAGES_TO_SEND) {
+ g_counter_promise->set_value();
+ }
+}
+
+class BM_ThreadPerformance : public ::benchmark::Fixture {
+ protected:
+ void SetUp(State& st) override {
+ benchmark::Fixture::SetUp(st);
+ set_up_promise_ = std::make_unique<std::promise<void>>();
+ g_counter = 0;
+ bt_msg_queue_ = fixed_queue_new(SIZE_MAX);
+ }
+ void TearDown(State& st) override {
+ fixed_queue_free(bt_msg_queue_, nullptr);
+ bt_msg_queue_ = nullptr;
+ set_up_promise_.reset(nullptr);
+ g_counter_promise.reset(nullptr);
+ benchmark::Fixture::TearDown(st);
+ }
+ fixed_queue_t* bt_msg_queue_ = nullptr;
+ std::unique_ptr<std::promise<void>> set_up_promise_;
+};
+
+class BM_MessageLoop : public BM_ThreadPerformance {
+ public:
+ static void RunThread(void* context) {
+ auto test = static_cast<BM_MessageLoop*>(context);
+ test->RunMessageLoop();
+ }
+ static void* RunPThread(void* context) {
+ auto test = static_cast<BM_MessageLoop*>(context);
+ test->RunMessageLoop();
+ return nullptr;
+ }
+ void RunMessageLoop() {
+ message_loop_ = new base::MessageLoop();
+ run_loop_ = new base::RunLoop();
+ message_loop_->task_runner()->PostTask(
+ FROM_HERE, base::BindOnce(&std::promise<void>::set_value,
+ base::Unretained(set_up_promise_.get())));
+ run_loop_->Run();
+ delete message_loop_;
+ message_loop_ = nullptr;
+ delete run_loop_;
+ run_loop_ = nullptr;
+ }
+
+ protected:
+ base::MessageLoop* message_loop_ = nullptr;
+ base::RunLoop* run_loop_ = nullptr;
+};
+
+class BM_MessageLoopOsiThread : public BM_MessageLoop {
+ protected:
+ void SetUp(State& st) override {
+ BM_MessageLoop::SetUp(st);
+ std::future<void> set_up_future = set_up_promise_->get_future();
+ thread_ = thread_new("BM_MessageLoopOnOsiThread thread");
+ thread_post(thread_, &BM_MessageLoop::RunThread, this);
+ set_up_future.wait();
+ }
+
+ void TearDown(State& st) override {
+ message_loop_->task_runner()->PostTask(FROM_HERE,
+ run_loop_->QuitWhenIdleClosure());
+ thread_free(thread_);
+ thread_ = nullptr;
+ BM_MessageLoop::TearDown(st);
+ }
+
+ thread_t* thread_ = nullptr;
+};
+
+BENCHMARK_F(BM_MessageLoopOsiThread, batch_enque_dequeue)(State& state) {
+ for (auto _ : state) {
+ g_counter = 0;
+ g_counter_promise = std::make_unique<std::promise<void>>();
+ std::future<void> counter_future = g_counter_promise->get_future();
+ for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
+ fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
+ message_loop_->task_runner()->PostTask(
+ FROM_HERE, base::BindOnce(&callback_batch, bt_msg_queue_, nullptr));
+ }
+ counter_future.wait();
+ }
+};
+
+BENCHMARK_F(BM_MessageLoopOsiThread, sequential_execution)(State& state) {
+ for (auto _ : state) {
+ for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
+ g_counter_promise = std::make_unique<std::promise<void>>();
+ std::future<void> counter_future = g_counter_promise->get_future();
+ message_loop_->task_runner()->PostTask(
+ FROM_HERE, base::BindOnce(&callback_sequential, nullptr));
+ counter_future.wait();
+ }
+ }
+};
+
+class BM_MessageLoopStlThread : public BM_MessageLoop {
+ protected:
+ void SetUp(State& st) override {
+ BM_MessageLoop::SetUp(st);
+ std::future<void> set_up_future = set_up_promise_->get_future();
+ thread_ = new std::thread(&BM_MessageLoop::RunThread, this);
+ set_up_future.wait();
+ }
+
+ void TearDown(State& st) override {
+ message_loop_->task_runner()->PostTask(FROM_HERE,
+ run_loop_->QuitWhenIdleClosure());
+ thread_->join();
+ delete thread_;
+ thread_ = nullptr;
+ BM_MessageLoop::TearDown(st);
+ }
+
+ std::thread* thread_ = nullptr;
+};
+
+BENCHMARK_F(BM_MessageLoopStlThread, batch_enque_dequeue)(State& state) {
+ for (auto _ : state) {
+ g_counter = 0;
+ g_counter_promise = std::make_unique<std::promise<void>>();
+ std::future<void> counter_future = g_counter_promise->get_future();
+ for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
+ fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
+ message_loop_->task_runner()->PostTask(
+ FROM_HERE, base::BindOnce(&callback_batch, bt_msg_queue_, nullptr));
+ }
+ counter_future.wait();
+ }
+};
+
+BENCHMARK_F(BM_MessageLoopStlThread, sequential_execution)(State& state) {
+ for (auto _ : state) {
+ for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
+ g_counter_promise = std::make_unique<std::promise<void>>();
+ std::future<void> counter_future = g_counter_promise->get_future();
+ message_loop_->task_runner()->PostTask(
+ FROM_HERE, base::BindOnce(&callback_sequential, nullptr));
+ counter_future.wait();
+ }
+ }
+};
+
+class BM_MessageLoopPosixThread : public BM_MessageLoop {
+ protected:
+ void SetUp(State& st) override {
+ BM_MessageLoop::SetUp(st);
+ std::future<void> set_up_future = set_up_promise_->get_future();
+ pthread_create(&thread_, nullptr, &BM_MessageLoop::RunPThread, (void*)this);
+ set_up_future.wait();
+ }
+
+ void TearDown(State& st) override {
+ message_loop_->task_runner()->PostTask(FROM_HERE,
+ run_loop_->QuitWhenIdleClosure());
+ pthread_join(thread_, nullptr);
+ BM_MessageLoop::TearDown(st);
+ }
+
+ pthread_t thread_ = -1;
+};
+
+BENCHMARK_F(BM_MessageLoopPosixThread, batch_enque_dequeue)(State& state) {
+ for (auto _ : state) {
+ g_counter = 0;
+ g_counter_promise = std::make_unique<std::promise<void>>();
+ std::future<void> counter_future = g_counter_promise->get_future();
+ for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
+ fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
+ message_loop_->task_runner()->PostTask(
+ FROM_HERE, base::BindOnce(&callback_batch, bt_msg_queue_, nullptr));
+ }
+ counter_future.wait();
+ }
+};
+
+BENCHMARK_F(BM_MessageLoopPosixThread, sequential_execution)(State& state) {
+ for (auto _ : state) {
+ for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
+ g_counter_promise = std::make_unique<std::promise<void>>();
+ std::future<void> counter_future = g_counter_promise->get_future();
+ message_loop_->task_runner()->PostTask(
+ FROM_HERE, base::BindOnce(&callback_sequential, nullptr));
+ counter_future.wait();
+ }
+ }
+};
+
+class BM_OsiReactorThread : public BM_ThreadPerformance {
+ protected:
+ void SetUp(State& st) override {
+ BM_ThreadPerformance::SetUp(st);
+ thread_ = thread_new("BM_OsiReactorThread thread");
+ }
+
+ void TearDown(State& st) override {
+ thread_free(thread_);
+ thread_ = nullptr;
+ BM_ThreadPerformance::TearDown(st);
+ }
+
+ thread_t* thread_ = nullptr;
+};
+
+BENCHMARK_F(BM_OsiReactorThread, batch_enque_dequeue_using_thread_post)
+(State& state) {
+ for (auto _ : state) {
+ g_counter = 0;
+ g_counter_promise = std::make_unique<std::promise<void>>();
+ std::future<void> counter_future = g_counter_promise->get_future();
+ for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
+ fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
+ thread_post(thread_, pthread_callback_batch, bt_msg_queue_);
+ }
+ counter_future.wait();
+ }
+};
+
+BENCHMARK_F(BM_OsiReactorThread, sequential_execution_using_thread_post)
+(State& state) {
+ for (auto _ : state) {
+ for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
+ g_counter_promise = std::make_unique<std::promise<void>>();
+ std::future<void> counter_future = g_counter_promise->get_future();
+ thread_post(thread_, callback_sequential, nullptr);
+ counter_future.wait();
+ }
+ }
+};
+
+BENCHMARK_F(BM_OsiReactorThread, batch_enque_dequeue_using_reactor)
+(State& state) {
+ fixed_queue_register_dequeue(bt_msg_queue_, thread_get_reactor(thread_),
+ callback_batch, nullptr);
+ for (auto _ : state) {
+ g_counter = 0;
+ g_counter_promise = std::make_unique<std::promise<void>>();
+ std::future<void> counter_future = g_counter_promise->get_future();
+ for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
+ fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
+ }
+ counter_future.wait();
+ }
+};
+
+BENCHMARK_F(BM_OsiReactorThread, sequential_execution_using_reactor)
+(State& state) {
+ fixed_queue_register_dequeue(bt_msg_queue_, thread_get_reactor(thread_),
+ callback_sequential_queue, nullptr);
+ for (auto _ : state) {
+ for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
+ g_counter_promise = std::make_unique<std::promise<void>>();
+ std::future<void> counter_future = g_counter_promise->get_future();
+ fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
+ counter_future.wait();
+ }
+ }
+};
+
+class BM_MessageLooopThread : public BM_ThreadPerformance {
+ protected:
+ void SetUp(State& st) override {
+ BM_ThreadPerformance::SetUp(st);
+ std::future<void> set_up_future = set_up_promise_->get_future();
+ message_loop_thread_ =
+ new MessageLoopThread("BM_MessageLooopThread thread");
+ message_loop_thread_->StartUp();
+ message_loop_thread_->DoInThread(
+ FROM_HERE, base::BindOnce(&std::promise<void>::set_value,
+ base::Unretained(set_up_promise_.get())));
+ set_up_future.wait();
+ }
+
+ void TearDown(State& st) override {
+ message_loop_thread_->ShutDown();
+ delete message_loop_thread_;
+ message_loop_thread_ = nullptr;
+ BM_ThreadPerformance::TearDown(st);
+ }
+
+ MessageLoopThread* message_loop_thread_ = nullptr;
+};
+
+BENCHMARK_F(BM_MessageLooopThread, batch_enque_dequeue)(State& state) {
+ for (auto _ : state) {
+ g_counter = 0;
+ g_counter_promise = std::make_unique<std::promise<void>>();
+ std::future<void> counter_future = g_counter_promise->get_future();
+ for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
+ fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
+ message_loop_thread_->DoInThread(
+ FROM_HERE, base::BindOnce(&callback_batch, bt_msg_queue_, nullptr));
+ }
+ counter_future.wait();
+ }
+};
+
+BENCHMARK_F(BM_MessageLooopThread, sequential_execution)(State& state) {
+ for (auto _ : state) {
+ for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
+ g_counter_promise = std::make_unique<std::promise<void>>();
+ std::future<void> counter_future = g_counter_promise->get_future();
+ message_loop_thread_->DoInThread(
+ FROM_HERE, base::BindOnce(&callback_sequential, nullptr));
+ counter_future.wait();
+ }
+ }
+};
+
+class BM_LibChromeThread : public BM_ThreadPerformance {
+ protected:
+ void SetUp(State& st) override {
+ BM_ThreadPerformance::SetUp(st);
+ std::future<void> set_up_future = set_up_promise_->get_future();
+ thread_ = new base::Thread("BM_LibChromeThread thread");
+ thread_->Start();
+ thread_->task_runner()->PostTask(
+ FROM_HERE, base::BindOnce(&std::promise<void>::set_value,
+ base::Unretained(set_up_promise_.get())));
+ set_up_future.wait();
+ }
+
+ void TearDown(State& st) override {
+ thread_->Stop();
+ delete thread_;
+ thread_ = nullptr;
+ BM_ThreadPerformance::TearDown(st);
+ }
+
+ base::Thread* thread_ = nullptr;
+};
+
+BENCHMARK_F(BM_LibChromeThread, batch_enque_dequeue)(State& state) {
+ for (auto _ : state) {
+ g_counter = 0;
+ g_counter_promise = std::make_unique<std::promise<void>>();
+ std::future<void> counter_future = g_counter_promise->get_future();
+ for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
+ fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
+ thread_->task_runner()->PostTask(
+ FROM_HERE, base::BindOnce(&callback_batch, bt_msg_queue_, nullptr));
+ }
+ counter_future.wait();
+ }
+};
+
+BENCHMARK_F(BM_LibChromeThread, sequential_execution)(State& state) {
+ for (auto _ : state) {
+ for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
+ g_counter_promise = std::make_unique<std::promise<void>>();
+ std::future<void> counter_future = g_counter_promise->get_future();
+ thread_->task_runner()->PostTask(
+ FROM_HERE, base::BindOnce(&callback_sequential, nullptr));
+ counter_future.wait();
+ }
+ }
+};
+
+int main(int argc, char** argv) {
+ // Disable LOG() output from libchrome
+ logging::LoggingSettings log_settings;
+ log_settings.logging_dest = logging::LoggingDestination::LOG_NONE;
+ CHECK(logging::InitLogging(log_settings)) << "Failed to set up logging";
+ ::benchmark::Initialize(&argc, argv);
+ if (::benchmark::ReportUnrecognizedArguments(argc, argv)) {
+ return 1;
+ }
+ ::benchmark::RunSpecifiedBenchmarks();
+}
diff --git a/common/benchmark/timer_performance_benchmark.cc b/common/benchmark/timer_performance_benchmark.cc
new file mode 100644
index 0000000..deaaad8
--- /dev/null
+++ b/common/benchmark/timer_performance_benchmark.cc
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2018 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/bind.h>
+#include <base/run_loop.h>
+#include <base/threading/thread.h>
+#include <benchmark/benchmark.h>
+#include <future>
+
+#include "common/message_loop_thread.h"
+#include "common/once_timer.h"
+#include "common/repeating_timer.h"
+#include "common/time_util.h"
+#include "osi/include/alarm.h"
+
+using ::benchmark::State;
+using bluetooth::common::MessageLoopThread;
+using bluetooth::common::OnceTimer;
+using bluetooth::common::RepeatingTimer;
+using bluetooth::common::time_get_os_boottime_us;
+
+// fake get_main_message_loop implementation for alarm
+base::MessageLoop* get_main_message_loop() { return nullptr; }
+
+namespace {
+std::unordered_map<int, int> g_map;
+std::shared_ptr<std::promise<void>> g_promise;
+uint64_t g_start_time;
+int g_scheduled_tasks;
+int g_task_length;
+int g_task_interval;
+int g_task_counter;
+
+void TimerFire(void*) { g_promise->set_value(); }
+
+void AlarmSleepAndCountDelayedTime(void*) {
+ auto end_time_us = time_get_os_boottime_us();
+ auto time_after_start_ms = (end_time_us - g_start_time) / 1000;
+ g_task_counter++;
+ g_map[time_after_start_ms - g_task_counter * g_task_interval]++;
+ std::this_thread::sleep_for(std::chrono::milliseconds(g_task_length));
+ if (g_task_counter >= g_scheduled_tasks) {
+ g_promise->set_value();
+ }
+}
+
+} // namespace
+
+class BM_OsiAlarmTimer : public ::benchmark::Fixture {
+ protected:
+ void SetUp(State& st) override {
+ ::benchmark::Fixture::SetUp(st);
+ alarm_ = alarm_new("osi_alarm_timer_test");
+ g_promise = std::make_shared<std::promise<void>>();
+ }
+
+ void TearDown(State& st) override {
+ g_promise = nullptr;
+ alarm_free(alarm_);
+ ::benchmark::Fixture::TearDown(st);
+ }
+
+ alarm_t* alarm_ = nullptr;
+};
+
+BENCHMARK_DEFINE_F(BM_OsiAlarmTimer, timer_performance_ms)(State& state) {
+ auto milliseconds = static_cast<int>(state.range(0));
+ for (auto _ : state) {
+ auto start_time_point = time_get_os_boottime_us();
+ alarm_set(alarm_, milliseconds, &TimerFire, nullptr);
+ g_promise->get_future().get();
+ auto end_time_point = time_get_os_boottime_us();
+ auto duration = end_time_point - start_time_point;
+ state.SetIterationTime(duration * 1e-6);
+ }
+};
+
+BENCHMARK_REGISTER_F(BM_OsiAlarmTimer, timer_performance_ms)
+ ->Arg(1)
+ ->Arg(5)
+ ->Arg(10)
+ ->Arg(20)
+ ->Arg(100)
+ ->Arg(1000)
+ ->Arg(2000)
+ ->Iterations(1)
+ ->UseManualTime();
+
+class BM_AlarmTaskTimer : public ::benchmark::Fixture {
+ protected:
+ void SetUp(State& st) override {
+ ::benchmark::Fixture::SetUp(st);
+ message_loop_thread_ = new MessageLoopThread("timer_benchmark");
+ message_loop_thread_->StartUp();
+ message_loop_thread_->EnableRealTimeScheduling();
+ once_timer_ = new OnceTimer();
+ repeating_timer_ = new RepeatingTimer();
+ g_promise = std::make_shared<std::promise<void>>();
+ }
+
+ void TearDown(State& st) override {
+ g_promise = nullptr;
+ delete once_timer_;
+ once_timer_ = nullptr;
+ delete repeating_timer_;
+ repeating_timer_ = nullptr;
+ message_loop_thread_->ShutDown();
+ delete message_loop_thread_;
+ message_loop_thread_ = nullptr;
+ ::benchmark::Fixture::TearDown(st);
+ }
+
+ MessageLoopThread* message_loop_thread_;
+ OnceTimer* once_timer_;
+ RepeatingTimer* repeating_timer_;
+};
+
+BENCHMARK_DEFINE_F(BM_AlarmTaskTimer, timer_performance_ms)(State& state) {
+ auto milliseconds = static_cast<int>(state.range(0));
+ for (auto _ : state) {
+ auto start_time_point = time_get_os_boottime_us();
+ once_timer_->Schedule(message_loop_thread_->GetWeakPtr(), FROM_HERE,
+ base::BindOnce(&TimerFire, nullptr),
+ base::TimeDelta::FromMilliseconds(milliseconds));
+ g_promise->get_future().get();
+ once_timer_->Cancel();
+ auto end_time_point = time_get_os_boottime_us();
+ auto duration = end_time_point - start_time_point;
+ state.SetIterationTime(duration * 1e-6);
+ }
+};
+
+BENCHMARK_REGISTER_F(BM_AlarmTaskTimer, timer_performance_ms)
+ ->Arg(1)
+ ->Arg(5)
+ ->Arg(10)
+ ->Arg(20)
+ ->Arg(100)
+ ->Arg(1000)
+ ->Arg(2000)
+ ->Iterations(1)
+ ->UseManualTime();
+
+class BM_OsiPeriodicAlarmTimer : public ::benchmark::Fixture {
+ protected:
+ void SetUp(State& st) override {
+ ::benchmark::Fixture::SetUp(st);
+ alarm_ = alarm_new_periodic("osi_alarm_timer_test");
+ g_map.clear();
+ g_promise = std::make_shared<std::promise<void>>();
+ g_scheduled_tasks = 0;
+ g_task_length = 0;
+ g_task_interval = 0;
+ g_task_counter = 0;
+ }
+
+ void TearDown(State& st) override {
+ g_promise = nullptr;
+ alarm_free(alarm_);
+ ::benchmark::Fixture::TearDown(st);
+ }
+
+ alarm_t* alarm_ = nullptr;
+};
+
+BENCHMARK_DEFINE_F(BM_OsiPeriodicAlarmTimer, periodic_accuracy)(State& state) {
+ for (auto _ : state) {
+ g_scheduled_tasks = state.range(0);
+ g_task_length = state.range(1);
+ g_task_interval = state.range(2);
+ g_start_time = time_get_os_boottime_us();
+ alarm_set(alarm_, g_task_interval, &AlarmSleepAndCountDelayedTime, nullptr);
+ g_promise->get_future().get();
+ alarm_cancel(alarm_);
+ }
+ for (const auto& delay : g_map) {
+ state.counters[std::to_string(delay.first)] = delay.second;
+ }
+};
+
+BENCHMARK_REGISTER_F(BM_OsiPeriodicAlarmTimer, periodic_accuracy)
+ ->Args({2000, 1, 5})
+ ->Args({2000, 3, 5})
+ ->Args({2000, 1, 7})
+ ->Args({2000, 3, 7})
+ ->Args({2000, 1, 20})
+ ->Args({2000, 5, 20})
+ ->Args({2000, 10, 20})
+ ->Args({2000, 15, 20})
+ ->Iterations(1)
+ ->UseRealTime();
+
+class BM_AlarmTaskPeriodicTimer : public ::benchmark::Fixture {
+ protected:
+ void SetUp(State& st) override {
+ ::benchmark::Fixture::SetUp(st);
+ message_loop_thread_ = new MessageLoopThread("timer_benchmark");
+ message_loop_thread_->StartUp();
+ message_loop_thread_->EnableRealTimeScheduling();
+ once_timer_ = new OnceTimer();
+ repeating_timer_ = new RepeatingTimer();
+ g_map.clear();
+ g_promise = std::make_shared<std::promise<void>>();
+ g_scheduled_tasks = 0;
+ g_task_length = 0;
+ g_task_interval = 0;
+ g_task_counter = 0;
+ }
+
+ void TearDown(State& st) override {
+ g_promise = nullptr;
+ delete once_timer_;
+ once_timer_ = nullptr;
+ delete repeating_timer_;
+ repeating_timer_ = nullptr;
+ message_loop_thread_->ShutDown();
+ delete message_loop_thread_;
+ message_loop_thread_ = nullptr;
+ ::benchmark::Fixture::TearDown(st);
+ }
+
+ MessageLoopThread* message_loop_thread_;
+ OnceTimer* once_timer_;
+ RepeatingTimer* repeating_timer_;
+};
+
+BENCHMARK_DEFINE_F(BM_AlarmTaskPeriodicTimer, periodic_accuracy)
+(State& state) {
+ for (auto _ : state) {
+ g_scheduled_tasks = state.range(0);
+ g_task_length = state.range(1);
+ g_task_interval = state.range(2);
+ g_start_time = time_get_os_boottime_us();
+ repeating_timer_->SchedulePeriodic(
+ message_loop_thread_->GetWeakPtr(), FROM_HERE,
+ base::BindRepeating(&AlarmSleepAndCountDelayedTime, nullptr),
+ base::TimeDelta::FromMilliseconds(g_task_interval));
+ g_promise->get_future().get();
+ repeating_timer_->Cancel();
+ }
+ for (const auto& delay : g_map) {
+ state.counters[std::to_string(delay.first)] = delay.second;
+ }
+};
+
+BENCHMARK_REGISTER_F(BM_AlarmTaskPeriodicTimer, periodic_accuracy)
+ ->Args({2000, 1, 5})
+ ->Args({2000, 3, 5})
+ ->Args({2000, 1, 7})
+ ->Args({2000, 3, 7})
+ ->Args({2000, 1, 20})
+ ->Args({2000, 5, 20})
+ ->Args({2000, 10, 20})
+ ->Args({2000, 15, 20})
+ ->Iterations(1)
+ ->UseRealTime();
+
+int main(int argc, char** argv) {
+ // Disable LOG() output from libchrome
+ logging::LoggingSettings log_settings;
+ log_settings.logging_dest = logging::LoggingDestination::LOG_NONE;
+ CHECK(logging::InitLogging(log_settings)) << "Failed to set up logging";
+ ::benchmark::Initialize(&argc, argv);
+ if (::benchmark::ReportUnrecognizedArguments(argc, argv)) {
+ return 1;
+ }
+ ::benchmark::RunSpecifiedBenchmarks();
+}
diff --git a/common/id_generator.h b/common/id_generator.h
new file mode 100644
index 0000000..202d645
--- /dev/null
+++ b/common/id_generator.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2019 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 <array>
+
+/* Helper class generating N unique ids, from 0 to N-1 */
+template <std::size_t N>
+class IdGenerator {
+ public:
+ static int ALL_USED;
+
+ IdGenerator() : in_use_{} {}
+
+ /* Returns next free id, or ALL_USED if no ids left */
+ int GetNext() {
+ for (std::size_t i = 0; i < N; i++) {
+ if (!in_use_[i]) {
+ in_use_[i] = true;
+ return i;
+ }
+ }
+ return ALL_USED;
+ }
+
+ /* Release given ID */
+ void Release(int id) { in_use_[id] = false; }
+
+ private:
+ std::array<bool, N> in_use_;
+};
+
+template <std::size_t N>
+int IdGenerator<N>::ALL_USED = -1;
\ No newline at end of file
diff --git a/common/id_generator_unittest.cc b/common/id_generator_unittest.cc
new file mode 100644
index 0000000..d56ee19
--- /dev/null
+++ b/common/id_generator_unittest.cc
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 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 "common/id_generator.h"
+
+#include <gtest/gtest.h>
+
+TEST(IdGeneratorTest, sanity_test) {
+ IdGenerator<5> generator;
+ ASSERT_EQ(0, generator.GetNext());
+ ASSERT_EQ(1, generator.GetNext());
+ ASSERT_EQ(2, generator.GetNext());
+ ASSERT_EQ(3, generator.GetNext());
+ ASSERT_EQ(4, generator.GetNext());
+ ASSERT_EQ(generator.ALL_USED, generator.GetNext());
+
+ generator.Release(3);
+ ASSERT_EQ(3, generator.GetNext());
+
+ generator.Release(0);
+ generator.Release(2);
+ ASSERT_EQ(0, generator.GetNext());
+ ASSERT_EQ(2, generator.GetNext());
+}
\ No newline at end of file
diff --git a/common/leaky_bonded_queue.h b/common/leaky_bonded_queue.h
new file mode 100644
index 0000000..087b192
--- /dev/null
+++ b/common/leaky_bonded_queue.h
@@ -0,0 +1,162 @@
+/******************************************************************************
+ *
+ * Copyright 2016 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 <mutex>
+#include <queue>
+
+namespace bluetooth {
+
+namespace common {
+
+/*
+ * LeakyBondedQueue<T>
+ *
+ * - LeakyLondedQueue<T> is a fixed size queue that leaks oldest item when
+ * reaching its capacity. This is useful in creating memory bonded data
+ * structure where freshness is more important than full coverage.
+ * - The queue is protected by a simple mutex and is thread-safe, although
+ * improvements could be made to lock enqueue and dequeue separately, it
+ * is not implemented at this moment due to lack of demand
+ * - The queue uses unique_ptr to automatically free its content when it is
+ * destructed. It is the user's responsibility to implement T's destructor
+ * correctly.
+ *
+ */
+template <class T>
+class LeakyBondedQueue {
+ public:
+ LeakyBondedQueue(size_t capacity);
+ /* Default destructor
+ *
+ * Call Clear() and free the queue structure itself
+ */
+ ~LeakyBondedQueue();
+ /*
+ * Add item NEW_ITEM to the underlining queue. If the queue is full, pop
+ * the oldest item
+ */
+ void Enqueue(T* new_item);
+ /*
+ * Add item NEW_ITEM to the underlining queue. If the queue is full, dequeue
+ * the oldest item and returns it to the caller. Return nullptr otherwise.
+ */
+ T* EnqueueWithPop(T* new_item);
+ /*
+ * Dequeues the oldest item from the queue. Return nullptr if queue is empty
+ */
+ T* Dequeue();
+ /*
+ * Returns the length of queue
+ */
+ size_t Length();
+ /*
+ * Returns the defined capacity of the queue
+ */
+ size_t Capacity();
+ /*
+ * Returns whether the queue is empty
+ */
+ bool Empty();
+ /*
+ * Pops all items from the queue
+ */
+ void Clear();
+
+ private:
+ // Put item in unique_ptr so that they get freed automatically when poped or
+ // when queue_ is freed
+ std::queue<std::unique_ptr<T>> queue_;
+ std::mutex lock_;
+ size_t capacity_;
+};
+
+/*
+ * Definitions must be in the header for template classes
+ */
+
+template <class T>
+LeakyBondedQueue<T>::LeakyBondedQueue(size_t capacity) {
+ capacity_ = capacity;
+}
+
+template <class T>
+LeakyBondedQueue<T>::~LeakyBondedQueue() {}
+
+template <class T>
+void LeakyBondedQueue<T>::Enqueue(T* new_item) {
+ std::lock_guard<std::mutex> lock(lock_);
+ if ((queue_.size() + 1) > capacity_) {
+ queue_.pop();
+ }
+ std::unique_ptr<T> item_ptr(new_item);
+ queue_.push(std::move(item_ptr));
+}
+
+template <class T>
+T* LeakyBondedQueue<T>::EnqueueWithPop(T* new_item) {
+ std::lock_guard<std::mutex> lock(lock_);
+ T* old_item = nullptr;
+ if ((queue_.size() + 1) > capacity_) {
+ std::unique_ptr<T> item = std::move(queue_.front());
+ queue_.pop();
+ old_item = item.release();
+ }
+ std::unique_ptr<T> item_ptr(new_item);
+ queue_.push(std::move(item_ptr));
+ return old_item;
+}
+
+template <class T>
+T* LeakyBondedQueue<T>::Dequeue() {
+ std::lock_guard<std::mutex> lock(lock_);
+ std::unique_ptr<T> item = std::move(queue_.front());
+ queue_.pop();
+ return item.release();
+}
+
+template <class T>
+void LeakyBondedQueue<T>::Clear() {
+ std::lock_guard<std::mutex> lock(lock_);
+ while (!queue_.empty()) {
+ // unique_ptr does not need to be freed
+ queue_.pop();
+ }
+}
+
+template <class T>
+size_t LeakyBondedQueue<T>::Length() {
+ std::lock_guard<std::mutex> lock(lock_);
+ return queue_.size();
+}
+
+template <class T>
+size_t LeakyBondedQueue<T>::Capacity() {
+ return capacity_;
+}
+
+template <class T>
+bool LeakyBondedQueue<T>::Empty() {
+ std::lock_guard<std::mutex> lock(lock_);
+ return queue_.empty();
+}
+
+} // namespace common
+
+} // namespace bluetooth
diff --git a/common/leaky_bonded_queue_unittest.cc b/common/leaky_bonded_queue_unittest.cc
new file mode 100644
index 0000000..b2ff35b
--- /dev/null
+++ b/common/leaky_bonded_queue_unittest.cc
@@ -0,0 +1,242 @@
+/******************************************************************************
+ *
+ * Copyright 2016 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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <base/logging.h>
+
+#include "common/leaky_bonded_queue.h"
+
+namespace testing {
+
+using bluetooth::common::LeakyBondedQueue;
+
+#define ITEM_EQ(a, b) \
+ do { \
+ EXPECT_EQ(a, b); \
+ EXPECT_EQ((a)->index, (b)->index); \
+ } while (0)
+
+class Item {
+ public:
+ Item(int i) { index = i; }
+ virtual ~Item() {}
+ int index;
+};
+
+class MockItem : public Item {
+ public:
+ MockItem(int i) : Item(i) {}
+ ~MockItem() override { Destruct(); }
+ MOCK_METHOD0(Destruct, void());
+};
+
+TEST(LeakyBondedQueueTest, TestEnqueueDequeue) {
+ MockItem* item1 = new MockItem(1);
+ MockItem* item2 = new MockItem(2);
+ MockItem* item3 = new MockItem(3);
+ MockItem* item4 = new MockItem(4);
+ LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(3);
+ EXPECT_EQ(queue->Capacity(), static_cast<size_t>(3));
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
+ queue->Enqueue(item1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
+ queue->Enqueue(item2);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ queue->Enqueue(item3);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(3));
+ EXPECT_CALL(*item1, Destruct()).Times(1);
+ queue->Enqueue(item4);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(3));
+ MockItem* item2_2 = queue->Dequeue();
+ MockItem* item3_3 = queue->Dequeue();
+ MockItem* item4_4 = queue->Dequeue();
+ EXPECT_THAT(item2_2, NotNull());
+ ITEM_EQ(item2_2, item2);
+ EXPECT_THAT(item3_3, NotNull());
+ ITEM_EQ(item3_3, item3);
+ EXPECT_THAT(item4_4, NotNull());
+ ITEM_EQ(item4_4, item4);
+ LOG(INFO) << "All done release items";
+ EXPECT_CALL(*item2_2, Destruct()).Times(1);
+ delete item2_2;
+ EXPECT_CALL(*item3_3, Destruct()).Times(1);
+ delete item3_3;
+ EXPECT_CALL(*item4_4, Destruct()).Times(1);
+ delete item4_4;
+ delete queue;
+}
+
+TEST(LeakyBondedQueueTest, TestEnqueueDequeue2) {
+ MockItem* item1 = new MockItem(1);
+ MockItem* item2 = new MockItem(2);
+ MockItem* item3 = new MockItem(3);
+ MockItem* item4 = new MockItem(4);
+ LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(2);
+ EXPECT_EQ(queue->Capacity(), static_cast<size_t>(2));
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
+ queue->Enqueue(item1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
+ MockItem* item1_1 = queue->Dequeue();
+ ITEM_EQ(item1, item1_1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
+ queue->Enqueue(item2);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
+ queue->Enqueue(item3);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ EXPECT_CALL(*item2, Destruct()).Times(1);
+ queue->Enqueue(item4);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ EXPECT_CALL(*item3, Destruct()).Times(1);
+ queue->Enqueue(item1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ MockItem* item4_4_4 = queue->Dequeue();
+ MockItem* item1_1_1 = queue->Dequeue();
+ ITEM_EQ(item4_4_4, item4);
+ ITEM_EQ(item1_1_1, item1);
+ EXPECT_CALL(*item1_1_1, Destruct()).Times(1);
+ delete item1_1_1;
+ EXPECT_CALL(*item4_4_4, Destruct()).Times(1);
+ delete item4_4_4;
+ delete queue;
+}
+
+TEST(LeakyBondedQueueTest, TestEnqueuePop) {
+ MockItem* item1 = new MockItem(1);
+ MockItem* item2 = new MockItem(2);
+ MockItem* item3 = new MockItem(3);
+ MockItem* item4 = new MockItem(4);
+ LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(2);
+ EXPECT_EQ(queue->Capacity(), static_cast<size_t>(2));
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
+ queue->Enqueue(item1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
+ MockItem* item1_1 = queue->Dequeue();
+ ITEM_EQ(item1, item1_1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
+ queue->Enqueue(item2);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
+ queue->Enqueue(item3);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ MockItem* item2_2 = queue->EnqueueWithPop(item4);
+ EXPECT_THAT(item2_2, NotNull());
+ ITEM_EQ(item2_2, item2);
+ EXPECT_CALL(*item2, Destruct()).Times(1);
+ delete item2_2;
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ MockItem* item3_3 = queue->EnqueueWithPop(item1);
+ EXPECT_THAT(item3_3, NotNull());
+ ITEM_EQ(item3_3, item3);
+ EXPECT_CALL(*item3, Destruct()).Times(1);
+ delete item3_3;
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ MockItem* item4_4_4 = queue->Dequeue();
+ MockItem* item1_1_1 = queue->Dequeue();
+ ITEM_EQ(item4_4_4, item4);
+ ITEM_EQ(item1_1_1, item1);
+ EXPECT_CALL(*item1_1_1, Destruct()).Times(1);
+ delete item1_1_1;
+ EXPECT_CALL(*item4_4_4, Destruct()).Times(1);
+ delete item4_4_4;
+ delete queue;
+}
+
+TEST(LeakyBondedQueueTest, TestQueueClear) {
+ MockItem* item1 = new MockItem(1);
+ MockItem* item2 = new MockItem(2);
+ MockItem* item3 = new MockItem(3);
+ MockItem* item4 = new MockItem(4);
+ LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(2);
+ EXPECT_EQ(queue->Capacity(), static_cast<size_t>(2));
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
+ queue->Enqueue(item1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
+ MockItem* item1_1 = queue->Dequeue();
+ ITEM_EQ(item1, item1_1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
+ queue->Enqueue(item2);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
+ queue->Enqueue(item3);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ EXPECT_CALL(*item2, Destruct()).Times(1);
+ queue->Enqueue(item4);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ EXPECT_CALL(*item3, Destruct()).Times(1);
+ queue->Enqueue(item1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ EXPECT_CALL(*item1, Destruct()).Times(1);
+ EXPECT_CALL(*item4, Destruct()).Times(1);
+ queue->Clear();
+ delete queue;
+}
+
+TEST(LeakyBondedQueueTest, TestQueueFree) {
+ MockItem* item1 = new MockItem(1);
+ MockItem* item2 = new MockItem(2);
+ MockItem* item3 = new MockItem(3);
+ MockItem* item4 = new MockItem(4);
+ LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(2);
+ EXPECT_EQ(queue->Capacity(), static_cast<size_t>(2));
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
+ queue->Enqueue(item1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
+ MockItem* item1_1 = queue->Dequeue();
+ ITEM_EQ(item1, item1_1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
+ queue->Enqueue(item2);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
+ queue->Enqueue(item3);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ EXPECT_CALL(*item2, Destruct()).Times(1);
+ queue->Enqueue(item4);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ EXPECT_CALL(*item3, Destruct()).Times(1);
+ queue->Enqueue(item1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ EXPECT_CALL(*item1, Destruct()).Times(1);
+ EXPECT_CALL(*item4, Destruct()).Times(1);
+ delete queue;
+}
+
+TEST(LeakyBondedQueueTest, TestPushNull) {
+ MockItem* item1 = nullptr;
+ LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(2);
+ queue->Enqueue(item1);
+ MockItem* item1_1 = queue->Dequeue();
+ EXPECT_THAT(item1_1, IsNull());
+}
+
+TEST(LeakyBondedQueueTest, TestPushNullOverflowQueue) {
+ MockItem* item1 = nullptr;
+ MockItem* item2 = nullptr;
+ LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(1);
+ queue->Enqueue(item1);
+ queue->Enqueue(item2);
+ MockItem* item2_2 = queue->Dequeue();
+ EXPECT_THAT(item2_2, IsNull());
+}
+
+TEST(LeakyBondedQueueTest, TestPushNullDeleteQueue) {
+ MockItem* item1 = nullptr;
+ MockItem* item2 = nullptr;
+ LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(2);
+ queue->Enqueue(item1);
+ queue->Enqueue(item2);
+ delete queue;
+}
+} // namespace testing
diff --git a/common/message_loop_thread.cc b/common/message_loop_thread.cc
new file mode 100644
index 0000000..e2c2e2d
--- /dev/null
+++ b/common/message_loop_thread.cc
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2018 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 "message_loop_thread.h"
+
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <thread>
+
+#include <base/strings/stringprintf.h>
+
+namespace bluetooth {
+
+namespace common {
+
+static constexpr int kRealTimeFifoSchedulingPriority = 1;
+
+MessageLoopThread::MessageLoopThread(const std::string& thread_name)
+ : thread_name_(thread_name),
+ message_loop_(nullptr),
+ run_loop_(nullptr),
+ thread_(nullptr),
+ thread_id_(-1),
+ linux_tid_(-1),
+ weak_ptr_factory_(this),
+ shutting_down_(false) {}
+
+MessageLoopThread::~MessageLoopThread() { ShutDown(); }
+
+void MessageLoopThread::StartUp() {
+ std::promise<void> start_up_promise;
+ std::future<void> start_up_future = start_up_promise.get_future();
+ {
+ std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
+ if (thread_ != nullptr) {
+ LOG(WARNING) << __func__ << ": thread " << *this << " is already started";
+
+ return;
+ }
+ thread_ = new std::thread(&MessageLoopThread::RunThread, this,
+ std::move(start_up_promise));
+ }
+ start_up_future.wait();
+}
+
+bool MessageLoopThread::DoInThread(const base::Location& from_here,
+ base::OnceClosure task) {
+ return DoInThreadDelayed(from_here, std::move(task), base::TimeDelta());
+}
+
+bool MessageLoopThread::DoInThreadDelayed(const base::Location& from_here,
+ base::OnceClosure task,
+ const base::TimeDelta& delay) {
+ std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
+ if (message_loop_ == nullptr) {
+ LOG(ERROR) << __func__ << ": message loop is null for thread " << *this
+ << ", from " << from_here.ToString();
+ return false;
+ }
+ if (!message_loop_->task_runner()->PostDelayedTask(from_here, std::move(task),
+ delay)) {
+ LOG(ERROR) << __func__
+ << ": failed to post task to message loop for thread " << *this
+ << ", from " << from_here.ToString();
+ return false;
+ }
+ return true;
+}
+
+void MessageLoopThread::ShutDown() {
+ {
+ std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
+ if (thread_ == nullptr) {
+ LOG(INFO) << __func__ << ": thread " << *this << " is already stopped";
+ return;
+ }
+ if (message_loop_ == nullptr) {
+ LOG(INFO) << __func__ << ": message_loop_ is null. Already stopping";
+ return;
+ }
+ if (shutting_down_) {
+ LOG(INFO) << __func__ << ": waiting for thread to join";
+ return;
+ }
+ shutting_down_ = true;
+ CHECK_NE(thread_id_, base::PlatformThread::CurrentId())
+ << __func__ << " should not be called on the thread itself. "
+ << "Otherwise, deadlock may happen.";
+ if (!message_loop_->task_runner()->PostTask(
+ FROM_HERE, run_loop_->QuitWhenIdleClosure())) {
+ LOG(FATAL) << __func__
+ << ": failed to post task to message loop for thread "
+ << *this;
+ }
+ }
+ thread_->join();
+ {
+ std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
+ delete thread_;
+ thread_ = nullptr;
+ shutting_down_ = false;
+ }
+}
+
+base::PlatformThreadId MessageLoopThread::GetThreadId() const {
+ std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
+ return thread_id_;
+}
+
+std::string MessageLoopThread::GetName() const {
+ return thread_name_;
+}
+
+std::string MessageLoopThread::ToString() const {
+ std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
+ return base::StringPrintf("%s(%d)", thread_name_.c_str(), thread_id_);
+}
+
+bool MessageLoopThread::IsRunning() const {
+ std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
+ return message_loop_ != nullptr;
+}
+
+// Non API method, should not be protected by API mutex
+void MessageLoopThread::RunThread(MessageLoopThread* thread,
+ std::promise<void> start_up_promise) {
+ thread->Run(std::move(start_up_promise));
+}
+
+base::MessageLoop* MessageLoopThread::message_loop() const {
+ std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
+ return message_loop_;
+}
+
+bool MessageLoopThread::EnableRealTimeScheduling() {
+ std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
+ if (!IsRunning()) {
+ LOG(ERROR) << __func__ << ": thread " << *this << " is not running";
+ return false;
+ }
+ struct sched_param rt_params = {.sched_priority =
+ kRealTimeFifoSchedulingPriority};
+ int rc = sched_setscheduler(linux_tid_, SCHED_FIFO, &rt_params);
+ if (rc != 0) {
+ LOG(ERROR) << __func__ << ": unable to set SCHED_FIFO priority "
+ << kRealTimeFifoSchedulingPriority << " for linux_tid "
+ << std::to_string(linux_tid_) << ", thread " << *this
+ << ", error: " << strerror(errno);
+ return false;
+ }
+ return true;
+}
+
+base::WeakPtr<MessageLoopThread> MessageLoopThread::GetWeakPtr() {
+ std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
+ return weak_ptr_factory_.GetWeakPtr();
+}
+
+void MessageLoopThread::Run(std::promise<void> start_up_promise) {
+ {
+ std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
+ LOG(INFO) << __func__ << ": message loop starting for thread "
+ << thread_name_;
+ base::PlatformThread::SetName(thread_name_);
+ message_loop_ = new base::MessageLoop();
+ run_loop_ = new base::RunLoop();
+ thread_id_ = base::PlatformThread::CurrentId();
+ linux_tid_ = static_cast<pid_t>(syscall(SYS_gettid));
+ start_up_promise.set_value();
+ }
+
+ // Blocking until ShutDown() is called
+ run_loop_->Run();
+
+ {
+ std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
+ thread_id_ = -1;
+ linux_tid_ = -1;
+ delete message_loop_;
+ message_loop_ = nullptr;
+ delete run_loop_;
+ run_loop_ = nullptr;
+ LOG(INFO) << __func__ << ": message loop finished for thread "
+ << thread_name_;
+ }
+}
+
+} // namespace common
+
+} // namespace bluetooth
diff --git a/common/message_loop_thread.h b/common/message_loop_thread.h
new file mode 100644
index 0000000..3984a9b
--- /dev/null
+++ b/common/message_loop_thread.h
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2018 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 <unistd.h>
+#include <future>
+#include <memory>
+#include <string>
+#include <thread>
+
+#include <base/bind.h>
+#include <base/location.h>
+#include <base/message_loop/message_loop.h>
+#include <base/run_loop.h>
+#include <base/threading/platform_thread.h>
+
+namespace bluetooth {
+
+namespace common {
+
+/**
+ * An interface to various thread related functionality
+ */
+class MessageLoopThread final {
+ public:
+ /**
+ * Create a message loop thread with name. Thread won't be running until
+ * StartUp is called.
+ *
+ * @param thread_name name of this worker thread
+ */
+ explicit MessageLoopThread(const std::string& thread_name);
+
+ /**
+ * Destroys the message loop thread automatically when it goes out of scope
+ */
+ ~MessageLoopThread();
+
+ /**
+ * Start the underlying thread. Blocks until all thread infrastructure is
+ * setup. IsRunning() and DoInThread() should return true after this call.
+ * Blocks until the thread is successfully started.
+ *
+ * Repeated call to this method will only start this thread once
+ */
+ void StartUp();
+
+ /**
+ * Post a task to run on this thread
+ *
+ * @param from_here location where this task is originated
+ * @param task task created through base::Bind()
+ * @return true if task is successfully scheduled, false if task cannot be
+ * scheduled
+ */
+ bool DoInThread(const base::Location& from_here, base::OnceClosure task);
+
+ /**
+ * Shutdown the current thread as if it is never started. IsRunning() and
+ * DoInThread() will return false after this call. Blocks until the thread is
+ * joined and freed. This thread can be re-started again using StartUp()
+ *
+ * Repeated call to this method will only stop this thread once
+ *
+ * NOTE: Should never be called on the thread itself to avoid deadlock
+ */
+ void ShutDown();
+
+ /**
+ * Get the current thread ID returned by PlatformThread::CurrentId()
+ *
+ * On Android platform, this value should be the same as the tid logged by
+ * logcat, which is returned by gettid(). On other platform, this thread id
+ * may have different meanings. Therefore, this ID is only good for logging
+ * and thread comparison purpose
+ *
+ * @return this thread's ID
+ */
+ base::PlatformThreadId GetThreadId() const;
+
+ /**
+ * Get this thread's name set in constructor
+ *
+ * @return this thread's name set in constructor
+ */
+ std::string GetName() const;
+
+ /**
+ * Get a string representation of this thread
+ *
+ * @return a string representation of this thread
+ */
+ std::string ToString() const;
+
+ /**
+ * Check if this thread is running
+ *
+ * @return true iff this thread is running and is able to do task
+ */
+ bool IsRunning() const;
+
+ /**
+ * Attempt to make scheduling for this thread real time
+ *
+ * @return true on success, false otherwise
+ */
+ bool EnableRealTimeScheduling();
+
+ /**
+ * Return the weak pointer to this object. This can be useful when posting
+ * delayed tasks to this MessageLoopThread using Timer.
+ */
+ base::WeakPtr<MessageLoopThread> GetWeakPtr();
+
+ /**
+ * Return the message loop for this thread. Accessing raw message loop is not
+ * recommended as message loop can be freed internally.
+ *
+ * @return message loop associated with this thread, nullptr if thread is not
+ * running
+ */
+ base::MessageLoop* message_loop() const;
+
+ private:
+ /**
+ * Static method to run the thread
+ *
+ * This is used instead of a C++ lambda because of the use of std::shared_ptr
+ *
+ * @param context needs to be a pointer to an instance of MessageLoopThread
+ * @param start_up_promise a std::promise that is used to notify calling
+ * thread the completion of message loop start-up
+ */
+ static void RunThread(MessageLoopThread* context,
+ std::promise<void> start_up_promise);
+
+ /**
+ * Post a task to run on this thread after a specified delay. If the task
+ * needs to be cancelable before it's run, use base::CancelableClosure type
+ * for task closure. For example:
+ * <code>
+ * base::CancelableClosure cancelable_task;
+ * cancelable_task.Reset(base::Bind(...)); // bind the task
+ * same_thread->DoInThreadDelayed(FROM_HERE,
+ * cancelable_task.callback(), delay);
+ * ...
+ * // Cancel the task closure
+ * same_thread->DoInThread(FROM_HERE,
+ * base::Bind(&base::CancelableClosure::Cancel,
+ * base::Unretained(&cancelable_task)));
+ * </code>
+ *
+ * Warning: base::CancelableClosure objects must be created on, posted to,
+ * cancelled on, and destroyed on the same thread.
+ *
+ * @param from_here location where this task is originated
+ * @param task task created through base::Bind()
+ * @param delay delay for the task to be executed
+ * @return true if task is successfully scheduled, false if task cannot be
+ * scheduled
+ */
+ bool DoInThreadDelayed(const base::Location& from_here,
+ base::OnceClosure task, const base::TimeDelta& delay);
+
+ friend class RepeatingTimer; // allow Timer to use DoInThreadDelayed()
+ friend class OnceTimer; // allow OnceTimer to use DoInThreadDelayed()
+
+ /**
+ * Actual method to run the thread, blocking until ShutDown() is called
+ *
+ * @param start_up_promise a std::promise that is used to notify calling
+ * thread the completion of message loop start-up
+ */
+ void Run(std::promise<void> start_up_promise);
+
+ mutable std::recursive_mutex api_mutex_;
+ const std::string thread_name_;
+ base::MessageLoop* message_loop_;
+ base::RunLoop* run_loop_;
+ std::thread* thread_;
+ base::PlatformThreadId thread_id_;
+ // Linux specific abstractions
+ pid_t linux_tid_;
+ base::WeakPtrFactory<MessageLoopThread> weak_ptr_factory_;
+ bool shutting_down_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessageLoopThread);
+};
+
+inline std::ostream& operator<<(std::ostream& os,
+ const bluetooth::common::MessageLoopThread& a) {
+ os << a.ToString();
+ return os;
+}
+
+} // namespace common
+
+} // namespace bluetooth
diff --git a/common/message_loop_thread_unittest.cc b/common/message_loop_thread_unittest.cc
new file mode 100644
index 0000000..0e8f0a4
--- /dev/null
+++ b/common/message_loop_thread_unittest.cc
@@ -0,0 +1,330 @@
+/*
+ * Copyright 2018 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 "message_loop_thread.h"
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+
+#include <gtest/gtest.h>
+
+#include <base/bind.h>
+#include <base/threading/platform_thread.h>
+#include <sys/capability.h>
+#include <syscall.h>
+
+using bluetooth::common::MessageLoopThread;
+
+/**
+ * Unit tests to verify MessageLoopThread. Must have CAP_SYS_NICE capability.
+ */
+class MessageLoopThreadTest : public ::testing::Test {
+ public:
+ void ShouldNotHappen() { FAIL() << "Should not happen"; }
+
+ void GetThreadId(std::promise<base::PlatformThreadId> thread_id_promise) {
+ thread_id_promise.set_value(base::PlatformThread::CurrentId());
+ }
+
+ void GetLinuxTid(std::promise<pid_t> tid_promise) {
+ tid_promise.set_value(static_cast<pid_t>(syscall(SYS_gettid)));
+ }
+
+ void GetName(std::promise<std::string> name_promise) {
+ char my_name[256];
+ pthread_getname_np(pthread_self(), my_name, sizeof(my_name));
+ name_promise.set_value(my_name);
+ }
+
+ void GetSchedulingPolicyAndPriority(int* scheduling_policy,
+ int* schedule_priority,
+ std::promise<void> execution_promise) {
+ *scheduling_policy = sched_getscheduler(0);
+ struct sched_param param = {};
+ ASSERT_EQ(sched_getparam(0, ¶m), 0);
+ *schedule_priority = param.sched_priority;
+ execution_promise.set_value();
+ }
+
+ void SleepAndGetName(std::promise<std::string> name_promise, int sleep_ms) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(sleep_ms));
+ GetName(std::move(name_promise));
+ }
+
+ protected:
+ static bool CanSetCurrentThreadPriority() {
+ struct __user_cap_header_struct linux_user_header = {
+ .version = _LINUX_CAPABILITY_VERSION_3};
+ struct __user_cap_data_struct linux_user_data = {};
+ if (capget(&linux_user_header, &linux_user_data) != 0) {
+ LOG(ERROR) << "Failed to get capability for current thread, error: "
+ << strerror(errno);
+ // Log record in XML
+ RecordProperty("MessageLoopThreadTestCannotGetCapabilityReason",
+ strerror(errno));
+ return false;
+ }
+ return ((linux_user_data.permitted >> CAP_SYS_NICE) & 0x1) != 0;
+ }
+};
+
+TEST_F(MessageLoopThreadTest, get_weak_ptr) {
+ base::WeakPtr<MessageLoopThread> message_loop_thread_ptr;
+ {
+ MessageLoopThread message_loop_thread("test_thread");
+ message_loop_thread_ptr = message_loop_thread.GetWeakPtr();
+ ASSERT_NE(message_loop_thread_ptr, nullptr);
+ }
+ ASSERT_EQ(message_loop_thread_ptr, nullptr);
+}
+
+TEST_F(MessageLoopThreadTest, test_running_thread) {
+ MessageLoopThread message_loop_thread("test_thread");
+ message_loop_thread.StartUp();
+ ASSERT_GE(message_loop_thread.GetThreadId(), 0);
+ ASSERT_TRUE(message_loop_thread.IsRunning());
+ message_loop_thread.ShutDown();
+ ASSERT_LT(message_loop_thread.GetThreadId(), 0);
+ ASSERT_FALSE(message_loop_thread.IsRunning());
+}
+
+TEST_F(MessageLoopThreadTest, test_not_self) {
+ MessageLoopThread message_loop_thread("test_thread");
+ message_loop_thread.StartUp();
+ ASSERT_GE(message_loop_thread.GetThreadId(), 0);
+ ASSERT_NE(message_loop_thread.GetThreadId(),
+ base::PlatformThread::CurrentId());
+}
+
+TEST_F(MessageLoopThreadTest, test_shutdown_without_start) {
+ MessageLoopThread message_loop_thread("test_thread");
+ message_loop_thread.ShutDown();
+ ASSERT_LT(message_loop_thread.GetThreadId(), 0);
+}
+
+TEST_F(MessageLoopThreadTest, test_do_in_thread_before_start) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ ASSERT_FALSE(message_loop_thread.DoInThread(
+ FROM_HERE, base::Bind(&MessageLoopThreadTest::ShouldNotHappen,
+ base::Unretained(this))));
+}
+
+TEST_F(MessageLoopThreadTest, test_do_in_thread_after_shutdown) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ message_loop_thread.StartUp();
+ message_loop_thread.ShutDown();
+ ASSERT_FALSE(message_loop_thread.DoInThread(
+ FROM_HERE, base::Bind(&MessageLoopThreadTest::ShouldNotHappen,
+ base::Unretained(this))));
+}
+
+TEST_F(MessageLoopThreadTest, test_name) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ message_loop_thread.StartUp();
+ ASSERT_GE(message_loop_thread.GetThreadId(), 0);
+ std::promise<std::string> name_promise;
+ std::future<std::string> name_future = name_promise.get_future();
+ message_loop_thread.DoInThread(
+ FROM_HERE,
+ base::BindOnce(&MessageLoopThreadTest::GetName, base::Unretained(this),
+ std::move(name_promise)));
+ std::string my_name = name_future.get();
+ ASSERT_EQ(name, my_name);
+ ASSERT_EQ(name, message_loop_thread.GetName());
+}
+
+TEST_F(MessageLoopThreadTest, test_thread_id) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ message_loop_thread.StartUp();
+ base::PlatformThreadId thread_id = message_loop_thread.GetThreadId();
+ ASSERT_GE(thread_id, 0);
+ std::promise<base::PlatformThreadId> thread_id_promise;
+ std::future<base::PlatformThreadId> thread_id_future =
+ thread_id_promise.get_future();
+ message_loop_thread.DoInThread(
+ FROM_HERE,
+ base::BindOnce(&MessageLoopThreadTest::GetThreadId,
+ base::Unretained(this), std::move(thread_id_promise)));
+ base::PlatformThreadId my_thread_id = thread_id_future.get();
+ ASSERT_EQ(thread_id, my_thread_id);
+}
+
+TEST_F(MessageLoopThreadTest, test_set_realtime_priority_fail_before_start) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ ASSERT_FALSE(message_loop_thread.EnableRealTimeScheduling());
+}
+
+TEST_F(MessageLoopThreadTest, test_set_realtime_priority_success) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ message_loop_thread.StartUp();
+ bool ret = message_loop_thread.EnableRealTimeScheduling();
+ if (!ret) {
+ if (CanSetCurrentThreadPriority()) {
+ FAIL() << "Cannot set real time priority even though we have permission";
+ } else {
+ LOG(WARNING) << "Allowing EnableRealTimeScheduling to fail because we"
+ " don't have CAP_SYS_NICE capability";
+ // Log record in XML
+ RecordProperty("MessageLoopThreadTestConditionalSuccess",
+ "Mark test as success even though EnableRealTimeScheduling"
+ " failed because we don't have CAP_SYS_NICE capability");
+ // Quit early since further verification is no longer needed
+ return;
+ }
+ }
+ std::promise<void> execution_promise;
+ std::future<void> execution_future = execution_promise.get_future();
+ int scheduling_policy = -1;
+ int scheduling_priority = -1;
+ message_loop_thread.DoInThread(
+ FROM_HERE,
+ base::BindOnce(&MessageLoopThreadTest::GetSchedulingPolicyAndPriority,
+ base::Unretained(this), &scheduling_policy,
+ &scheduling_priority, std::move(execution_promise)));
+ execution_future.wait();
+ ASSERT_EQ(scheduling_policy, SCHED_FIFO);
+ // Internal implementation verified here
+ ASSERT_EQ(scheduling_priority, 1);
+ std::promise<pid_t> tid_promise;
+ std::future<pid_t> tid_future = tid_promise.get_future();
+ message_loop_thread.DoInThread(
+ FROM_HERE,
+ base::BindOnce(&MessageLoopThreadTest::GetLinuxTid,
+ base::Unretained(this), std::move(tid_promise)));
+ pid_t linux_tid = tid_future.get();
+ ASSERT_GT(linux_tid, 0);
+ ASSERT_EQ(sched_getscheduler(linux_tid), SCHED_FIFO);
+ struct sched_param param = {};
+ ASSERT_EQ(sched_getparam(linux_tid, ¶m), 0);
+ // Internal implementation verified here
+ ASSERT_EQ(param.sched_priority, 1);
+}
+
+TEST_F(MessageLoopThreadTest, test_message_loop_null_before_start) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ ASSERT_EQ(message_loop_thread.message_loop(), nullptr);
+}
+
+TEST_F(MessageLoopThreadTest, test_message_loop_not_null_start) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ message_loop_thread.StartUp();
+ ASSERT_NE(message_loop_thread.message_loop(), nullptr);
+}
+
+TEST_F(MessageLoopThreadTest, test_message_loop_null_after_stop) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ message_loop_thread.StartUp();
+ ASSERT_NE(message_loop_thread.message_loop(), nullptr);
+ message_loop_thread.ShutDown();
+ ASSERT_EQ(message_loop_thread.message_loop(), nullptr);
+}
+
+TEST_F(MessageLoopThreadTest, test_to_string_method) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ std::string thread_string_before_start = message_loop_thread.ToString();
+ ASSERT_FALSE(thread_string_before_start.empty());
+ LOG(INFO) << "Before start: " << message_loop_thread;
+ message_loop_thread.StartUp();
+ std::string thread_string_running = message_loop_thread.ToString();
+ ASSERT_FALSE(thread_string_running.empty());
+ LOG(INFO) << "Running: " << message_loop_thread;
+ // String representation should look different when thread is not running
+ ASSERT_STRNE(thread_string_running.c_str(),
+ thread_string_before_start.c_str());
+ message_loop_thread.ShutDown();
+ std::string thread_string_after_shutdown = message_loop_thread.ToString();
+ LOG(INFO) << "After shutdown: " << message_loop_thread;
+ // String representation should look the same when thread is not running
+ ASSERT_STREQ(thread_string_after_shutdown.c_str(),
+ thread_string_before_start.c_str());
+}
+
+// Verify the message loop thread will shutdown after callback finishes
+TEST_F(MessageLoopThreadTest, shut_down_while_in_callback) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ message_loop_thread.StartUp();
+ std::promise<std::string> name_promise;
+ std::future<std::string> name_future = name_promise.get_future();
+ uint32_t delay_ms = 5;
+ message_loop_thread.DoInThread(
+ FROM_HERE, base::BindOnce(&MessageLoopThreadTest::SleepAndGetName,
+ base::Unretained(this), std::move(name_promise),
+ delay_ms));
+ message_loop_thread.ShutDown();
+ std::string my_name = name_future.get();
+ ASSERT_EQ(name, my_name);
+}
+
+// Verify the message loop thread will shutdown after callback finishes
+TEST_F(MessageLoopThreadTest, shut_down_while_in_callback_check_lock) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ message_loop_thread.StartUp();
+ message_loop_thread.DoInThread(
+ FROM_HERE,
+ base::BindOnce([](MessageLoopThread* thread) { thread->IsRunning(); },
+ &message_loop_thread));
+ message_loop_thread.ShutDown();
+}
+
+// Verify multiple threads try shutdown, no deadlock/crash
+TEST_F(MessageLoopThreadTest, shut_down_multi_thread) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ message_loop_thread.StartUp();
+ auto thread = std::thread(&MessageLoopThread::ShutDown, &message_loop_thread);
+ message_loop_thread.ShutDown();
+ thread.join();
+}
+
+// Verify multiple threads try startup, no deadlock/crash
+TEST_F(MessageLoopThreadTest, start_up_multi_thread) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ message_loop_thread.StartUp();
+ auto thread = std::thread(&MessageLoopThread::StartUp, &message_loop_thread);
+ thread.join();
+}
+
+// Verify multiple threads try startup/shutdown, no deadlock/crash
+TEST_F(MessageLoopThreadTest, start_up_shut_down_multi_thread) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ message_loop_thread.StartUp();
+ auto thread = std::thread(&MessageLoopThread::ShutDown, &message_loop_thread);
+ thread.join();
+}
+
+// Verify multiple threads try shutdown/startup, no deadlock/crash
+TEST_F(MessageLoopThreadTest, shut_down_start_up_multi_thread) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ message_loop_thread.StartUp();
+ message_loop_thread.ShutDown();
+ auto thread = std::thread(&MessageLoopThread::StartUp, &message_loop_thread);
+ thread.join();
+}
diff --git a/common/metrics.cc b/common/metrics.cc
new file mode 100644
index 0000000..4550eeb
--- /dev/null
+++ b/common/metrics.cc
@@ -0,0 +1,858 @@
+/******************************************************************************
+ *
+ * Copyright 2016 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 <unistd.h>
+#include <algorithm>
+#include <array>
+#include <cerrno>
+#include <chrono>
+#include <cstdint>
+#include <cstring>
+#include <memory>
+#include <mutex>
+
+#include <base/base64.h>
+#include <base/logging.h>
+#include <include/hardware/bt_av.h>
+#include <statslog.h>
+
+#include "bluetooth/metrics/bluetooth.pb.h"
+#include "osi/include/osi.h"
+#include "stack/include/btm_api_types.h"
+
+#include "address_obfuscator.h"
+#include "leaky_bonded_queue.h"
+#include "metrics.h"
+#include "time_util.h"
+
+namespace bluetooth {
+
+namespace common {
+
+using bluetooth::metrics::BluetoothMetricsProto::A2DPSession;
+using bluetooth::metrics::BluetoothMetricsProto::A2dpSourceCodec;
+using bluetooth::metrics::BluetoothMetricsProto::BluetoothLog;
+using bluetooth::metrics::BluetoothMetricsProto::BluetoothSession;
+using bluetooth::metrics::BluetoothMetricsProto::
+ BluetoothSession_ConnectionTechnologyType;
+using bluetooth::metrics::BluetoothMetricsProto::
+ BluetoothSession_DisconnectReasonType;
+using bluetooth::metrics::BluetoothMetricsProto::DeviceInfo;
+using bluetooth::metrics::BluetoothMetricsProto::DeviceInfo_DeviceType;
+using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileConnectionStats;
+using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileType;
+using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileType_ARRAYSIZE;
+using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileType_IsValid;
+using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileType_MAX;
+using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileType_MIN;
+using bluetooth::metrics::BluetoothMetricsProto::PairEvent;
+using bluetooth::metrics::BluetoothMetricsProto::ScanEvent;
+using bluetooth::metrics::BluetoothMetricsProto::ScanEvent_ScanEventType;
+using bluetooth::metrics::BluetoothMetricsProto::ScanEvent_ScanTechnologyType;
+using bluetooth::metrics::BluetoothMetricsProto::WakeEvent;
+using bluetooth::metrics::BluetoothMetricsProto::WakeEvent_WakeEventType;
+
+static float combine_averages(float avg_a, int64_t ct_a, float avg_b,
+ int64_t ct_b) {
+ if (ct_a > 0 && ct_b > 0) {
+ return (avg_a * ct_a + avg_b * ct_b) / (ct_a + ct_b);
+ } else if (ct_b > 0) {
+ return avg_b;
+ } else {
+ return avg_a;
+ }
+}
+
+static int32_t combine_averages(int32_t avg_a, int64_t ct_a, int32_t avg_b,
+ int64_t ct_b) {
+ if (ct_a > 0 && ct_b > 0) {
+ return (avg_a * ct_a + avg_b * ct_b) / (ct_a + ct_b);
+ } else if (ct_b > 0) {
+ return avg_b;
+ } else {
+ return avg_a;
+ }
+}
+
+void A2dpSessionMetrics::Update(const A2dpSessionMetrics& metrics) {
+ if (metrics.audio_duration_ms >= 0) {
+ audio_duration_ms = std::max(static_cast<int64_t>(0), audio_duration_ms);
+ audio_duration_ms += metrics.audio_duration_ms;
+ }
+ if (metrics.media_timer_min_ms >= 0) {
+ if (media_timer_min_ms < 0) {
+ media_timer_min_ms = metrics.media_timer_min_ms;
+ } else {
+ media_timer_min_ms =
+ std::min(media_timer_min_ms, metrics.media_timer_min_ms);
+ }
+ }
+ if (metrics.media_timer_max_ms >= 0) {
+ media_timer_max_ms =
+ std::max(media_timer_max_ms, metrics.media_timer_max_ms);
+ }
+ if (metrics.media_timer_avg_ms >= 0 && metrics.total_scheduling_count >= 0) {
+ if (media_timer_avg_ms < 0 || total_scheduling_count < 0) {
+ media_timer_avg_ms = metrics.media_timer_avg_ms;
+ total_scheduling_count = metrics.total_scheduling_count;
+ } else {
+ media_timer_avg_ms = combine_averages(
+ media_timer_avg_ms, total_scheduling_count,
+ metrics.media_timer_avg_ms, metrics.total_scheduling_count);
+ total_scheduling_count += metrics.total_scheduling_count;
+ }
+ }
+ if (metrics.buffer_overruns_max_count >= 0) {
+ buffer_overruns_max_count =
+ std::max(buffer_overruns_max_count, metrics.buffer_overruns_max_count);
+ }
+ if (metrics.buffer_overruns_total >= 0) {
+ buffer_overruns_total =
+ std::max(static_cast<int32_t>(0), buffer_overruns_total);
+ buffer_overruns_total += metrics.buffer_overruns_total;
+ }
+ if (metrics.buffer_underruns_average >= 0 &&
+ metrics.buffer_underruns_count >= 0) {
+ if (buffer_underruns_average < 0 || buffer_underruns_count < 0) {
+ buffer_underruns_average = metrics.buffer_underruns_average;
+ buffer_underruns_count = metrics.buffer_underruns_count;
+ } else {
+ buffer_underruns_average = combine_averages(
+ buffer_underruns_average, buffer_underruns_count,
+ metrics.buffer_underruns_average, metrics.buffer_underruns_count);
+ buffer_underruns_count += metrics.buffer_underruns_count;
+ }
+ }
+ if (codec_index < 0) {
+ codec_index = metrics.codec_index;
+ }
+ if (!is_a2dp_offload) {
+ is_a2dp_offload = metrics.is_a2dp_offload;
+ }
+}
+
+bool A2dpSessionMetrics::operator==(const A2dpSessionMetrics& rhs) const {
+ return audio_duration_ms == rhs.audio_duration_ms &&
+ media_timer_min_ms == rhs.media_timer_min_ms &&
+ media_timer_max_ms == rhs.media_timer_max_ms &&
+ media_timer_avg_ms == rhs.media_timer_avg_ms &&
+ total_scheduling_count == rhs.total_scheduling_count &&
+ buffer_overruns_max_count == rhs.buffer_overruns_max_count &&
+ buffer_overruns_total == rhs.buffer_overruns_total &&
+ buffer_underruns_average == rhs.buffer_underruns_average &&
+ buffer_underruns_count == rhs.buffer_underruns_count &&
+ codec_index == rhs.codec_index &&
+ is_a2dp_offload == rhs.is_a2dp_offload;
+}
+
+static DeviceInfo_DeviceType get_device_type(device_type_t type) {
+ switch (type) {
+ case DEVICE_TYPE_BREDR:
+ return DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR;
+ case DEVICE_TYPE_LE:
+ return DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_LE;
+ case DEVICE_TYPE_DUMO:
+ return DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_DUMO;
+ case DEVICE_TYPE_UNKNOWN:
+ default:
+ return DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_UNKNOWN;
+ }
+}
+
+static BluetoothSession_ConnectionTechnologyType get_connection_tech_type(
+ connection_tech_t type) {
+ switch (type) {
+ case CONNECTION_TECHNOLOGY_TYPE_LE:
+ return BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_LE;
+ case CONNECTION_TECHNOLOGY_TYPE_BREDR:
+ return BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR;
+ case CONNECTION_TECHNOLOGY_TYPE_UNKNOWN:
+ default:
+ return BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_UNKNOWN;
+ }
+}
+
+static ScanEvent_ScanTechnologyType get_scan_tech_type(scan_tech_t type) {
+ switch (type) {
+ case SCAN_TECH_TYPE_LE:
+ return ScanEvent_ScanTechnologyType::
+ ScanEvent_ScanTechnologyType_SCAN_TECH_TYPE_LE;
+ case SCAN_TECH_TYPE_BREDR:
+ return ScanEvent_ScanTechnologyType::
+ ScanEvent_ScanTechnologyType_SCAN_TECH_TYPE_BREDR;
+ case SCAN_TECH_TYPE_BOTH:
+ return ScanEvent_ScanTechnologyType::
+ ScanEvent_ScanTechnologyType_SCAN_TECH_TYPE_BOTH;
+ case SCAN_TYPE_UNKNOWN:
+ default:
+ return ScanEvent_ScanTechnologyType::
+ ScanEvent_ScanTechnologyType_SCAN_TYPE_UNKNOWN;
+ }
+}
+
+static WakeEvent_WakeEventType get_wake_event_type(wake_event_type_t type) {
+ switch (type) {
+ case WAKE_EVENT_ACQUIRED:
+ return WakeEvent_WakeEventType::WakeEvent_WakeEventType_ACQUIRED;
+ case WAKE_EVENT_RELEASED:
+ return WakeEvent_WakeEventType::WakeEvent_WakeEventType_RELEASED;
+ case WAKE_EVENT_UNKNOWN:
+ default:
+ return WakeEvent_WakeEventType::WakeEvent_WakeEventType_UNKNOWN;
+ }
+}
+
+static BluetoothSession_DisconnectReasonType get_disconnect_reason_type(
+ disconnect_reason_t type) {
+ switch (type) {
+ case DISCONNECT_REASON_METRICS_DUMP:
+ return BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_METRICS_DUMP;
+ case DISCONNECT_REASON_NEXT_START_WITHOUT_END_PREVIOUS:
+ return BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_NEXT_START_WITHOUT_END_PREVIOUS;
+ case DISCONNECT_REASON_UNKNOWN:
+ default:
+ return BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_UNKNOWN;
+ }
+}
+
+static A2dpSourceCodec get_a2dp_source_codec(int64_t codec_index) {
+ switch (codec_index) {
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
+ return A2dpSourceCodec::A2DP_SOURCE_CODEC_SBC;
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
+ return A2dpSourceCodec::A2DP_SOURCE_CODEC_AAC;
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
+ return A2dpSourceCodec::A2DP_SOURCE_CODEC_APTX;
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD:
+ return A2dpSourceCodec::A2DP_SOURCE_CODEC_APTX_HD;
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC:
+ return A2dpSourceCodec::A2DP_SOURCE_CODEC_LDAC;
+ default:
+ return A2dpSourceCodec::A2DP_SOURCE_CODEC_UNKNOWN;
+ }
+}
+
+struct BluetoothMetricsLogger::impl {
+ impl(size_t max_bluetooth_session, size_t max_pair_event,
+ size_t max_wake_event, size_t max_scan_event)
+ : bt_session_queue_(
+ new LeakyBondedQueue<BluetoothSession>(max_bluetooth_session)),
+ pair_event_queue_(new LeakyBondedQueue<PairEvent>(max_pair_event)),
+ wake_event_queue_(new LeakyBondedQueue<WakeEvent>(max_wake_event)),
+ scan_event_queue_(new LeakyBondedQueue<ScanEvent>(max_scan_event)) {
+ bluetooth_log_ = BluetoothLog::default_instance().New();
+ headset_profile_connection_counts_.fill(0);
+ bluetooth_session_ = nullptr;
+ bluetooth_session_start_time_ms_ = 0;
+ a2dp_session_metrics_ = A2dpSessionMetrics();
+ }
+
+ /* Bluetooth log lock protected */
+ BluetoothLog* bluetooth_log_;
+ std::array<int, HeadsetProfileType_ARRAYSIZE>
+ headset_profile_connection_counts_;
+ std::recursive_mutex bluetooth_log_lock_;
+ /* End Bluetooth log lock protected */
+ /* Bluetooth session lock protected */
+ BluetoothSession* bluetooth_session_;
+ uint64_t bluetooth_session_start_time_ms_;
+ A2dpSessionMetrics a2dp_session_metrics_;
+ std::recursive_mutex bluetooth_session_lock_;
+ /* End bluetooth session lock protected */
+ std::unique_ptr<LeakyBondedQueue<BluetoothSession>> bt_session_queue_;
+ std::unique_ptr<LeakyBondedQueue<PairEvent>> pair_event_queue_;
+ std::unique_ptr<LeakyBondedQueue<WakeEvent>> wake_event_queue_;
+ std::unique_ptr<LeakyBondedQueue<ScanEvent>> scan_event_queue_;
+};
+
+BluetoothMetricsLogger::BluetoothMetricsLogger()
+ : pimpl_(new impl(kMaxNumBluetoothSession, kMaxNumPairEvent,
+ kMaxNumWakeEvent, kMaxNumScanEvent)) {}
+
+void BluetoothMetricsLogger::LogPairEvent(uint32_t disconnect_reason,
+ uint64_t timestamp_ms,
+ uint32_t device_class,
+ device_type_t device_type) {
+ PairEvent* event = new PairEvent();
+ DeviceInfo* info = event->mutable_device_paired_with();
+ info->set_device_class(device_class);
+ info->set_device_type(get_device_type(device_type));
+ event->set_disconnect_reason(disconnect_reason);
+ event->set_event_time_millis(timestamp_ms);
+ pimpl_->pair_event_queue_->Enqueue(event);
+ {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
+ pimpl_->bluetooth_log_->set_num_pair_event(
+ pimpl_->bluetooth_log_->num_pair_event() + 1);
+ }
+}
+
+void BluetoothMetricsLogger::LogWakeEvent(wake_event_type_t type,
+ const std::string& requestor,
+ const std::string& name,
+ uint64_t timestamp_ms) {
+ WakeEvent* event = new WakeEvent();
+ event->set_wake_event_type(get_wake_event_type(type));
+ event->set_requestor(requestor);
+ event->set_name(name);
+ event->set_event_time_millis(timestamp_ms);
+ pimpl_->wake_event_queue_->Enqueue(event);
+ {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
+ pimpl_->bluetooth_log_->set_num_wake_event(
+ pimpl_->bluetooth_log_->num_wake_event() + 1);
+ }
+}
+
+void BluetoothMetricsLogger::LogScanEvent(bool start,
+ const std::string& initator,
+ scan_tech_t type, uint32_t results,
+ uint64_t timestamp_ms) {
+ ScanEvent* event = new ScanEvent();
+ if (start) {
+ event->set_scan_event_type(ScanEvent::SCAN_EVENT_START);
+ } else {
+ event->set_scan_event_type(ScanEvent::SCAN_EVENT_STOP);
+ }
+ event->set_initiator(initator);
+ event->set_scan_technology_type(get_scan_tech_type(type));
+ event->set_number_results(results);
+ event->set_event_time_millis(timestamp_ms);
+ pimpl_->scan_event_queue_->Enqueue(event);
+ {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
+ pimpl_->bluetooth_log_->set_num_scan_event(
+ pimpl_->bluetooth_log_->num_scan_event() + 1);
+ }
+}
+
+void BluetoothMetricsLogger::LogBluetoothSessionStart(
+ connection_tech_t connection_tech_type, uint64_t timestamp_ms) {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
+ if (pimpl_->bluetooth_session_ != nullptr) {
+ LogBluetoothSessionEnd(DISCONNECT_REASON_NEXT_START_WITHOUT_END_PREVIOUS,
+ 0);
+ }
+ if (timestamp_ms == 0) {
+ timestamp_ms = bluetooth::common::time_get_os_boottime_ms();
+ }
+ pimpl_->bluetooth_session_start_time_ms_ = timestamp_ms;
+ pimpl_->bluetooth_session_ = new BluetoothSession();
+ pimpl_->bluetooth_session_->set_connection_technology_type(
+ get_connection_tech_type(connection_tech_type));
+}
+
+void BluetoothMetricsLogger::LogBluetoothSessionEnd(
+ disconnect_reason_t disconnect_reason, uint64_t timestamp_ms) {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
+ if (pimpl_->bluetooth_session_ == nullptr) {
+ return;
+ }
+ if (timestamp_ms == 0) {
+ timestamp_ms = bluetooth::common::time_get_os_boottime_ms();
+ }
+ int64_t session_duration_sec =
+ (timestamp_ms - pimpl_->bluetooth_session_start_time_ms_) / 1000;
+ pimpl_->bluetooth_session_->set_session_duration_sec(session_duration_sec);
+ pimpl_->bluetooth_session_->set_disconnect_reason_type(
+ get_disconnect_reason_type(disconnect_reason));
+ pimpl_->bt_session_queue_->Enqueue(pimpl_->bluetooth_session_);
+ pimpl_->bluetooth_session_ = nullptr;
+ pimpl_->a2dp_session_metrics_ = A2dpSessionMetrics();
+ {
+ std::lock_guard<std::recursive_mutex> log_lock(pimpl_->bluetooth_log_lock_);
+ pimpl_->bluetooth_log_->set_num_bluetooth_session(
+ pimpl_->bluetooth_log_->num_bluetooth_session() + 1);
+ }
+}
+
+void BluetoothMetricsLogger::LogBluetoothSessionDeviceInfo(
+ uint32_t device_class, device_type_t device_type) {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
+ if (pimpl_->bluetooth_session_ == nullptr) {
+ LogBluetoothSessionStart(CONNECTION_TECHNOLOGY_TYPE_UNKNOWN, 0);
+ }
+ DeviceInfo* info = pimpl_->bluetooth_session_->mutable_device_connected_to();
+ info->set_device_class(device_class);
+ info->set_device_type(DeviceInfo::DEVICE_TYPE_BREDR);
+}
+
+void BluetoothMetricsLogger::LogA2dpSession(
+ const A2dpSessionMetrics& a2dp_session_metrics) {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
+ if (pimpl_->bluetooth_session_ == nullptr) {
+ // When no bluetooth session exist, create one on system's behalf
+ // Set connection type: for A2DP it is always BR/EDR
+ LogBluetoothSessionStart(CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
+ LogBluetoothSessionDeviceInfo(BTM_COD_MAJOR_AUDIO, DEVICE_TYPE_BREDR);
+ }
+ // Accumulate metrics
+ pimpl_->a2dp_session_metrics_.Update(a2dp_session_metrics);
+ // Get or allocate new A2DP session object
+ A2DPSession* a2dp_session =
+ pimpl_->bluetooth_session_->mutable_a2dp_session();
+ a2dp_session->set_audio_duration_millis(
+ pimpl_->a2dp_session_metrics_.audio_duration_ms);
+ a2dp_session->set_media_timer_min_millis(
+ pimpl_->a2dp_session_metrics_.media_timer_min_ms);
+ a2dp_session->set_media_timer_max_millis(
+ pimpl_->a2dp_session_metrics_.media_timer_max_ms);
+ a2dp_session->set_media_timer_avg_millis(
+ pimpl_->a2dp_session_metrics_.media_timer_avg_ms);
+ a2dp_session->set_buffer_overruns_max_count(
+ pimpl_->a2dp_session_metrics_.buffer_overruns_max_count);
+ a2dp_session->set_buffer_overruns_total(
+ pimpl_->a2dp_session_metrics_.buffer_overruns_total);
+ a2dp_session->set_buffer_underruns_average(
+ pimpl_->a2dp_session_metrics_.buffer_underruns_average);
+ a2dp_session->set_buffer_underruns_count(
+ pimpl_->a2dp_session_metrics_.buffer_underruns_count);
+ a2dp_session->set_source_codec(
+ get_a2dp_source_codec(pimpl_->a2dp_session_metrics_.codec_index));
+ a2dp_session->set_is_a2dp_offload(
+ pimpl_->a2dp_session_metrics_.is_a2dp_offload);
+}
+
+void BluetoothMetricsLogger::LogHeadsetProfileRfcConnection(
+ tBTA_SERVICE_ID service_id) {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
+ switch (service_id) {
+ case BTA_HSP_SERVICE_ID:
+ pimpl_->headset_profile_connection_counts_[HeadsetProfileType::HSP]++;
+ break;
+ case BTA_HFP_SERVICE_ID:
+ pimpl_->headset_profile_connection_counts_[HeadsetProfileType::HFP]++;
+ break;
+ default:
+ pimpl_->headset_profile_connection_counts_
+ [HeadsetProfileType::HEADSET_PROFILE_UNKNOWN]++;
+ break;
+ }
+ return;
+}
+
+void BluetoothMetricsLogger::WriteString(std::string* serialized) {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
+ LOG(INFO) << __func__ << ": building metrics";
+ Build();
+ LOG(INFO) << __func__ << ": serializing metrics";
+ if (!pimpl_->bluetooth_log_->SerializeToString(serialized)) {
+ LOG(ERROR) << __func__ << ": error serializing metrics";
+ }
+ // Always clean up log objects
+ pimpl_->bluetooth_log_->Clear();
+}
+
+void BluetoothMetricsLogger::WriteBase64String(std::string* serialized) {
+ this->WriteString(serialized);
+ base::Base64Encode(*serialized, serialized);
+}
+
+void BluetoothMetricsLogger::WriteBase64(int fd) {
+ std::string protoBase64;
+ this->WriteBase64String(&protoBase64);
+ ssize_t ret;
+ OSI_NO_INTR(ret = write(fd, protoBase64.c_str(), protoBase64.size()));
+ if (ret == -1) {
+ LOG(ERROR) << __func__
+ << ": error writing to dumpsys fd: " << strerror(errno) << " ("
+ << std::to_string(errno) << ")";
+ }
+}
+
+void BluetoothMetricsLogger::CutoffSession() {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
+ if (pimpl_->bluetooth_session_ != nullptr) {
+ BluetoothSession* new_bt_session =
+ new BluetoothSession(*pimpl_->bluetooth_session_);
+ new_bt_session->clear_a2dp_session();
+ new_bt_session->clear_rfcomm_session();
+ LogBluetoothSessionEnd(DISCONNECT_REASON_METRICS_DUMP, 0);
+ pimpl_->bluetooth_session_ = new_bt_session;
+ pimpl_->bluetooth_session_start_time_ms_ =
+ bluetooth::common::time_get_os_boottime_ms();
+ pimpl_->a2dp_session_metrics_ = A2dpSessionMetrics();
+ }
+}
+
+void BluetoothMetricsLogger::Build() {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
+ CutoffSession();
+ BluetoothLog* bluetooth_log = pimpl_->bluetooth_log_;
+ while (!pimpl_->bt_session_queue_->Empty() &&
+ static_cast<size_t>(bluetooth_log->session_size()) <=
+ pimpl_->bt_session_queue_->Capacity()) {
+ bluetooth_log->mutable_session()->AddAllocated(
+ pimpl_->bt_session_queue_->Dequeue());
+ }
+ while (!pimpl_->pair_event_queue_->Empty() &&
+ static_cast<size_t>(bluetooth_log->pair_event_size()) <=
+ pimpl_->pair_event_queue_->Capacity()) {
+ bluetooth_log->mutable_pair_event()->AddAllocated(
+ pimpl_->pair_event_queue_->Dequeue());
+ }
+ while (!pimpl_->scan_event_queue_->Empty() &&
+ static_cast<size_t>(bluetooth_log->scan_event_size()) <=
+ pimpl_->scan_event_queue_->Capacity()) {
+ bluetooth_log->mutable_scan_event()->AddAllocated(
+ pimpl_->scan_event_queue_->Dequeue());
+ }
+ while (!pimpl_->wake_event_queue_->Empty() &&
+ static_cast<size_t>(bluetooth_log->wake_event_size()) <=
+ pimpl_->wake_event_queue_->Capacity()) {
+ bluetooth_log->mutable_wake_event()->AddAllocated(
+ pimpl_->wake_event_queue_->Dequeue());
+ }
+ while (!pimpl_->bt_session_queue_->Empty() &&
+ static_cast<size_t>(bluetooth_log->wake_event_size()) <=
+ pimpl_->wake_event_queue_->Capacity()) {
+ bluetooth_log->mutable_wake_event()->AddAllocated(
+ pimpl_->wake_event_queue_->Dequeue());
+ }
+ for (size_t i = 0; i < HeadsetProfileType_ARRAYSIZE; ++i) {
+ int num_times_connected = pimpl_->headset_profile_connection_counts_[i];
+ if (HeadsetProfileType_IsValid(i) && num_times_connected > 0) {
+ HeadsetProfileConnectionStats* headset_profile_connection_stats =
+ bluetooth_log->add_headset_profile_connection_stats();
+ // Able to static_cast because HeadsetProfileType_IsValid(i) is true
+ headset_profile_connection_stats->set_headset_profile_type(
+ static_cast<HeadsetProfileType>(i));
+ headset_profile_connection_stats->set_num_times_connected(
+ num_times_connected);
+ }
+ }
+ pimpl_->headset_profile_connection_counts_.fill(0);
+}
+
+void BluetoothMetricsLogger::ResetSession() {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
+ if (pimpl_->bluetooth_session_ != nullptr) {
+ delete pimpl_->bluetooth_session_;
+ pimpl_->bluetooth_session_ = nullptr;
+ }
+ pimpl_->bluetooth_session_start_time_ms_ = 0;
+ pimpl_->a2dp_session_metrics_ = A2dpSessionMetrics();
+}
+
+void BluetoothMetricsLogger::ResetLog() {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
+ pimpl_->bluetooth_log_->Clear();
+}
+
+void BluetoothMetricsLogger::Reset() {
+ ResetSession();
+ ResetLog();
+ pimpl_->bt_session_queue_->Clear();
+ pimpl_->pair_event_queue_->Clear();
+ pimpl_->wake_event_queue_->Clear();
+ pimpl_->scan_event_queue_->Clear();
+}
+
+void LogLinkLayerConnectionEvent(const RawAddress* address,
+ uint32_t connection_handle,
+ android::bluetooth::DirectionEnum direction,
+ uint16_t link_type, uint32_t hci_cmd,
+ uint16_t hci_event, uint16_t hci_ble_event,
+ uint16_t cmd_status, uint16_t reason_code) {
+ std::string obfuscated_id;
+ if (address != nullptr) {
+ obfuscated_id = AddressObfuscator::GetInstance()->Obfuscate(*address);
+ }
+ // nullptr and size 0 represent missing value for obfuscated_id
+ android::util::BytesField bytes_field(
+ address != nullptr ? obfuscated_id.c_str() : nullptr,
+ address != nullptr ? obfuscated_id.size() : 0);
+ int ret = android::util::stats_write(
+ android::util::BLUETOOTH_LINK_LAYER_CONNECTION_EVENT, bytes_field,
+ connection_handle, direction, link_type, hci_cmd, hci_event,
+ hci_ble_event, cmd_status, reason_code);
+ if (ret < 0) {
+ LOG(WARNING) << __func__ << ": failed to log status " << loghex(cmd_status)
+ << ", reason " << loghex(reason_code) << " from cmd "
+ << loghex(hci_cmd) << ", event " << loghex(hci_event)
+ << ", ble_event " << loghex(hci_ble_event) << " for "
+ << address << ", handle " << connection_handle << ", type "
+ << loghex(link_type) << ", error " << ret;
+ }
+}
+
+void LogHciTimeoutEvent(uint32_t hci_cmd) {
+ int ret =
+ android::util::stats_write(android::util::BLUETOOTH_HCI_TIMEOUT_REPORTED,
+ static_cast<int64_t>(hci_cmd));
+ if (ret < 0) {
+ LOG(WARNING) << __func__ << ": failed for opcode " << loghex(hci_cmd)
+ << ", error " << ret;
+ }
+}
+
+void LogRemoteVersionInfo(uint16_t handle, uint8_t status, uint8_t version,
+ uint16_t manufacturer_name, uint16_t subversion) {
+ int ret = android::util::stats_write(
+ android::util::BLUETOOTH_REMOTE_VERSION_INFO_REPORTED, handle, status,
+ version, manufacturer_name, subversion);
+ if (ret < 0) {
+ LOG(WARNING) << __func__ << ": failed for handle " << handle << ", status "
+ << loghex(status) << ", version " << loghex(version)
+ << ", manufacturer_name " << loghex(manufacturer_name)
+ << ", subversion " << loghex(subversion) << ", error " << ret;
+ }
+}
+
+void LogA2dpAudioUnderrunEvent(const RawAddress& address,
+ uint64_t encoding_interval_millis,
+ int num_missing_pcm_bytes) {
+ std::string obfuscated_id;
+ if (!address.IsEmpty()) {
+ obfuscated_id = AddressObfuscator::GetInstance()->Obfuscate(address);
+ }
+ // nullptr and size 0 represent missing value for obfuscated_id
+ android::util::BytesField bytes_field(
+ address.IsEmpty() ? nullptr : obfuscated_id.c_str(),
+ address.IsEmpty() ? 0 : obfuscated_id.size());
+ int64_t encoding_interval_nanos = encoding_interval_millis * 1000000;
+ int ret = android::util::stats_write(
+ android::util::BLUETOOTH_A2DP_AUDIO_UNDERRUN_REPORTED, bytes_field,
+ encoding_interval_nanos, num_missing_pcm_bytes);
+ if (ret < 0) {
+ LOG(WARNING) << __func__ << ": failed for " << address
+ << ", encoding_interval_nanos " << encoding_interval_nanos
+ << ", num_missing_pcm_bytes " << num_missing_pcm_bytes
+ << ", error " << ret;
+ }
+}
+
+void LogA2dpAudioOverrunEvent(const RawAddress& address,
+ uint64_t encoding_interval_millis,
+ int num_dropped_buffers,
+ int num_dropped_encoded_frames,
+ int num_dropped_encoded_bytes) {
+ std::string obfuscated_id;
+ if (!address.IsEmpty()) {
+ obfuscated_id = AddressObfuscator::GetInstance()->Obfuscate(address);
+ }
+ // nullptr and size 0 represent missing value for obfuscated_id
+ android::util::BytesField bytes_field(
+ address.IsEmpty() ? nullptr : obfuscated_id.c_str(),
+ address.IsEmpty() ? 0 : obfuscated_id.size());
+ int64_t encoding_interval_nanos = encoding_interval_millis * 1000000;
+ int ret = android::util::stats_write(
+ android::util::BLUETOOTH_A2DP_AUDIO_OVERRUN_REPORTED, bytes_field,
+ encoding_interval_nanos, num_dropped_buffers, num_dropped_encoded_frames,
+ num_dropped_encoded_bytes);
+ if (ret < 0) {
+ LOG(WARNING) << __func__ << ": failed to log for " << address
+ << ", encoding_interval_nanos " << encoding_interval_nanos
+ << ", num_dropped_buffers " << num_dropped_buffers
+ << ", num_dropped_encoded_frames "
+ << num_dropped_encoded_frames << ", num_dropped_encoded_bytes "
+ << num_dropped_encoded_bytes << ", error " << ret;
+ }
+}
+
+void LogReadRssiResult(const RawAddress& address, uint16_t handle,
+ uint32_t cmd_status, int8_t rssi) {
+ std::string obfuscated_id;
+ if (!address.IsEmpty()) {
+ obfuscated_id = AddressObfuscator::GetInstance()->Obfuscate(address);
+ }
+ // nullptr and size 0 represent missing value for obfuscated_id
+ android::util::BytesField bytes_field(
+ address.IsEmpty() ? nullptr : obfuscated_id.c_str(),
+ address.IsEmpty() ? 0 : obfuscated_id.size());
+ int ret =
+ android::util::stats_write(android::util::BLUETOOTH_DEVICE_RSSI_REPORTED,
+ bytes_field, handle, cmd_status, rssi);
+ if (ret < 0) {
+ LOG(WARNING) << __func__ << ": failed for " << address << ", handle "
+ << handle << ", status " << loghex(cmd_status) << ", rssi "
+ << rssi << " dBm, error " << ret;
+ }
+}
+
+void LogReadFailedContactCounterResult(const RawAddress& address,
+ uint16_t handle, uint32_t cmd_status,
+ int32_t failed_contact_counter) {
+ std::string obfuscated_id;
+ if (!address.IsEmpty()) {
+ obfuscated_id = AddressObfuscator::GetInstance()->Obfuscate(address);
+ }
+ // nullptr and size 0 represent missing value for obfuscated_id
+ android::util::BytesField bytes_field(
+ address.IsEmpty() ? nullptr : obfuscated_id.c_str(),
+ address.IsEmpty() ? 0 : obfuscated_id.size());
+ int ret = android::util::stats_write(
+ android::util::BLUETOOTH_DEVICE_FAILED_CONTACT_COUNTER_REPORTED,
+ bytes_field, handle, cmd_status, failed_contact_counter);
+ if (ret < 0) {
+ LOG(WARNING) << __func__ << ": failed for " << address << ", handle "
+ << handle << ", status " << loghex(cmd_status)
+ << ", failed_contact_counter " << failed_contact_counter
+ << " packets, error " << ret;
+ }
+}
+
+void LogReadTxPowerLevelResult(const RawAddress& address, uint16_t handle,
+ uint32_t cmd_status,
+ int32_t transmit_power_level) {
+ std::string obfuscated_id;
+ if (!address.IsEmpty()) {
+ obfuscated_id = AddressObfuscator::GetInstance()->Obfuscate(address);
+ }
+ // nullptr and size 0 represent missing value for obfuscated_id
+ android::util::BytesField bytes_field(
+ address.IsEmpty() ? nullptr : obfuscated_id.c_str(),
+ address.IsEmpty() ? 0 : obfuscated_id.size());
+ int ret = android::util::stats_write(
+ android::util::BLUETOOTH_DEVICE_TX_POWER_LEVEL_REPORTED, bytes_field,
+ handle, cmd_status, transmit_power_level);
+ if (ret < 0) {
+ LOG(WARNING) << __func__ << ": failed for " << address << ", handle "
+ << handle << ", status " << loghex(cmd_status)
+ << ", transmit_power_level " << transmit_power_level
+ << " packets, error " << ret;
+ }
+}
+
+void LogSmpPairingEvent(const RawAddress& address, uint8_t smp_cmd,
+ android::bluetooth::DirectionEnum direction,
+ uint8_t smp_fail_reason) {
+ std::string obfuscated_id;
+ if (!address.IsEmpty()) {
+ obfuscated_id = AddressObfuscator::GetInstance()->Obfuscate(address);
+ }
+ // nullptr and size 0 represent missing value for obfuscated_id
+ android::util::BytesField obfuscated_id_field(
+ address.IsEmpty() ? nullptr : obfuscated_id.c_str(),
+ address.IsEmpty() ? 0 : obfuscated_id.size());
+ int ret = android::util::stats_write(
+ android::util::BLUETOOTH_SMP_PAIRING_EVENT_REPORTED, obfuscated_id_field,
+ smp_cmd, direction, smp_fail_reason);
+ if (ret < 0) {
+ LOG(WARNING) << __func__ << ": failed for " << address << ", smp_cmd "
+ << loghex(smp_cmd) << ", direction " << direction
+ << ", smp_fail_reason " << loghex(smp_fail_reason)
+ << ", error " << ret;
+ }
+}
+
+void LogClassicPairingEvent(const RawAddress& address, uint16_t handle, uint32_t hci_cmd, uint16_t hci_event,
+ uint16_t cmd_status, uint16_t reason_code, int64_t event_value) {
+ std::string obfuscated_id;
+ if (!address.IsEmpty()) {
+ obfuscated_id = AddressObfuscator::GetInstance()->Obfuscate(address);
+ }
+ // nullptr and size 0 represent missing value for obfuscated_id
+ android::util::BytesField obfuscated_id_field(
+ address.IsEmpty() ? nullptr : obfuscated_id.c_str(),
+ address.IsEmpty() ? 0 : obfuscated_id.size());
+ int ret = android::util::stats_write(android::util::BLUETOOTH_CLASSIC_PAIRING_EVENT_REPORTED, obfuscated_id_field,
+ handle, hci_cmd, hci_event, cmd_status, reason_code, event_value);
+ if (ret < 0) {
+ LOG(WARNING) << __func__ << ": failed for " << address << ", handle " << handle << ", hci_cmd " << loghex(hci_cmd)
+ << ", hci_event " << loghex(hci_event) << ", cmd_status " << loghex(cmd_status) << ", reason "
+ << loghex(reason_code) << ", event_value " << event_value << ", error " << ret;
+ }
+}
+
+void LogSdpAttribute(const RawAddress& address, uint16_t protocol_uuid,
+ uint16_t attribute_id, size_t attribute_size,
+ const char* attribute_value) {
+ std::string obfuscated_id;
+ if (!address.IsEmpty()) {
+ obfuscated_id = AddressObfuscator::GetInstance()->Obfuscate(address);
+ }
+ // nullptr and size 0 represent missing value for obfuscated_id
+ android::util::BytesField obfuscated_id_field(
+ address.IsEmpty() ? nullptr : obfuscated_id.c_str(),
+ address.IsEmpty() ? 0 : obfuscated_id.size());
+ android::util::BytesField attribute_field(attribute_value, attribute_size);
+ int ret = android::util::stats_write(
+ android::util::BLUETOOTH_SDP_ATTRIBUTE_REPORTED, obfuscated_id_field,
+ protocol_uuid, attribute_id, attribute_field);
+ if (ret < 0) {
+ LOG(WARNING) << __func__ << ": failed for " << address << ", protocol_uuid "
+ << loghex(protocol_uuid) << ", attribute_id "
+ << loghex(attribute_id) << ", error " << ret;
+ }
+}
+
+void LogSocketConnectionState(
+ const RawAddress& address, int port, int type,
+ android::bluetooth::SocketConnectionstateEnum connection_state,
+ int64_t tx_bytes, int64_t rx_bytes, int uid, int server_port,
+ android::bluetooth::SocketRoleEnum socket_role) {
+ std::string obfuscated_id;
+ if (!address.IsEmpty()) {
+ obfuscated_id = AddressObfuscator::GetInstance()->Obfuscate(address);
+ }
+ // nullptr and size 0 represent missing value for obfuscated_id
+ android::util::BytesField obfuscated_id_field(
+ address.IsEmpty() ? nullptr : obfuscated_id.c_str(),
+ address.IsEmpty() ? 0 : obfuscated_id.size());
+ int ret = android::util::stats_write(
+ android::util::BLUETOOTH_SOCKET_CONNECTION_STATE_CHANGED,
+ obfuscated_id_field, port, type, connection_state, tx_bytes, rx_bytes,
+ uid, server_port, socket_role);
+ if (ret < 0) {
+ LOG(WARNING) << __func__ << ": failed for " << address << ", port " << port
+ << ", type " << type << ", state " << connection_state
+ << ", tx_bytes " << tx_bytes << ", rx_bytes " << rx_bytes
+ << ", uid " << uid << ", server_port " << server_port
+ << ", socket_role " << socket_role << ", error " << ret;
+ }
+}
+
+void LogManufacturerInfo(const RawAddress& address,
+ android::bluetooth::DeviceInfoSrcEnum source_type,
+ const std::string& source_name,
+ const std::string& manufacturer,
+ const std::string& model,
+ const std::string& hardware_version,
+ const std::string& software_version) {
+ std::string obfuscated_id;
+ if (!address.IsEmpty()) {
+ obfuscated_id = AddressObfuscator::GetInstance()->Obfuscate(address);
+ }
+ // nullptr and size 0 represent missing value for obfuscated_id
+ android::util::BytesField obfuscated_id_field(
+ address.IsEmpty() ? nullptr : obfuscated_id.c_str(),
+ address.IsEmpty() ? 0 : obfuscated_id.size());
+ int ret = android::util::stats_write(
+ android::util::BLUETOOTH_DEVICE_INFO_REPORTED, obfuscated_id_field,
+ source_type, source_name.c_str(), manufacturer.c_str(), model.c_str(),
+ hardware_version.c_str(), software_version.c_str());
+ if (ret < 0) {
+ LOG(WARNING) << __func__ << ": failed for " << address << ", source_type "
+ << source_type << ", source_name " << source_name
+ << ", manufacturer " << manufacturer << ", model " << model
+ << ", hardware_version " << hardware_version
+ << ", software_version " << software_version << ", error "
+ << ret;
+ }
+}
+
+} // namespace common
+
+} // namespace bluetooth
diff --git a/common/metrics.h b/common/metrics.h
new file mode 100644
index 0000000..8d83cac
--- /dev/null
+++ b/common/metrics.h
@@ -0,0 +1,484 @@
+/******************************************************************************
+ *
+ * Copyright 2016 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 <android/bluetooth/hci/enums.pb.h>
+#include <bta/include/bta_api.h>
+#include <frameworks/base/core/proto/android/bluetooth/enums.pb.h>
+#include <stdint.h>
+#include <memory>
+#include <string>
+
+namespace bluetooth {
+
+namespace common {
+
+// Typedefs to hide protobuf definition to the rest of stack
+
+typedef enum {
+ DEVICE_TYPE_UNKNOWN,
+ DEVICE_TYPE_BREDR,
+ DEVICE_TYPE_LE,
+ DEVICE_TYPE_DUMO,
+} device_type_t;
+
+typedef enum {
+ WAKE_EVENT_UNKNOWN,
+ WAKE_EVENT_ACQUIRED,
+ WAKE_EVENT_RELEASED,
+} wake_event_type_t;
+
+typedef enum {
+ SCAN_TYPE_UNKNOWN,
+ SCAN_TECH_TYPE_LE,
+ SCAN_TECH_TYPE_BREDR,
+ SCAN_TECH_TYPE_BOTH,
+} scan_tech_t;
+
+typedef enum {
+ CONNECTION_TECHNOLOGY_TYPE_UNKNOWN,
+ CONNECTION_TECHNOLOGY_TYPE_LE,
+ CONNECTION_TECHNOLOGY_TYPE_BREDR,
+} connection_tech_t;
+
+typedef enum {
+ DISCONNECT_REASON_UNKNOWN,
+ DISCONNECT_REASON_METRICS_DUMP,
+ DISCONNECT_REASON_NEXT_START_WITHOUT_END_PREVIOUS,
+} disconnect_reason_t;
+
+/* Values of A2DP metrics that we care about
+ *
+ * audio_duration_ms : sum of audio duration (in milliseconds).
+ * device_class: device class of the paired device.
+ * media_timer_min_ms : minimum scheduled time (in milliseconds)
+ * of the media timer.
+ * media_timer_max_ms: maximum scheduled time (in milliseconds)
+ * of the media timer.
+ * media_timer_avg_ms: average scheduled time (in milliseconds)
+ * of the media timer.
+ * buffer_overruns_max_count: TODO - not clear what this is.
+ * buffer_overruns_total : number of times the media buffer with
+ * audio data has overrun
+ * buffer_underruns_average: TODO - not clear what this is.
+ * buffer_underruns_count: number of times there was no enough
+ * audio data to add to the media buffer.
+ * NOTE: Negative values are invalid
+ */
+class A2dpSessionMetrics {
+ public:
+ A2dpSessionMetrics() {}
+
+ /*
+ * Update the metrics value in the current metrics object using the metrics
+ * objects supplied
+ */
+ void Update(const A2dpSessionMetrics& metrics);
+
+ /*
+ * Compare whether two metrics objects are equal
+ */
+ bool operator==(const A2dpSessionMetrics& rhs) const;
+
+ /*
+ * Initialize all values to -1 which is invalid in order to make a distinction
+ * between 0 and invalid values
+ */
+ int64_t audio_duration_ms = -1;
+ int32_t media_timer_min_ms = -1;
+ int32_t media_timer_max_ms = -1;
+ int32_t media_timer_avg_ms = -1;
+ int64_t total_scheduling_count = -1;
+ int32_t buffer_overruns_max_count = -1;
+ int32_t buffer_overruns_total = -1;
+ float buffer_underruns_average = -1;
+ int32_t buffer_underruns_count = -1;
+ int64_t codec_index = -1;
+ bool is_a2dp_offload = false;
+};
+
+class BluetoothMetricsLogger {
+ public:
+ static BluetoothMetricsLogger* GetInstance() {
+ static BluetoothMetricsLogger* instance = new BluetoothMetricsLogger();
+ return instance;
+ }
+
+ /*
+ * Record a pairing event
+ *
+ * Parameters:
+ * timestamp_ms: Unix epoch time in milliseconds
+ * device_class: class of remote device
+ * device_type: type of remote device
+ * disconnect_reason: HCI reason for pairing disconnection.
+ * See: stack/include/hcidefs.h
+ */
+ void LogPairEvent(uint32_t disconnect_reason, uint64_t timestamp_ms,
+ uint32_t device_class, device_type_t device_type);
+
+ /*
+ * Record a wake event
+ *
+ * Parameters:
+ * timestamp_ms: Unix epoch time in milliseconds
+ * type: whether it was acquired or released
+ * requestor: if provided is the service requesting the wake lock
+ * name: the name of the wake lock held
+ */
+ void LogWakeEvent(wake_event_type_t type, const std::string& requestor,
+ const std::string& name, uint64_t timestamp_ms);
+
+ /*
+ * Record a scan event
+ *
+ * Parameters
+ * timestamp_ms : Unix epoch time in milliseconds
+ * start : true if this is the beginning of the scan
+ * initiator: a unique ID identifying the app starting the scan
+ * type: whether the scan reports BR/EDR, LE, or both.
+ * results: number of results to be reported.
+ */
+ void LogScanEvent(bool start, const std::string& initator, scan_tech_t type,
+ uint32_t results, uint64_t timestamp_ms);
+
+ /*
+ * Start logging a Bluetooth session
+ *
+ * A Bluetooth session is defined a a connection between this device and
+ * another remote device which may include multiple profiles and protocols
+ *
+ * Only one Bluetooth session can exist at one time. Calling this method twice
+ * without LogBluetoothSessionEnd will result in logging a premature end of
+ * current Bluetooth session
+ *
+ * Parameters:
+ * connection_tech_type : type of connection technology
+ * timestamp_ms : the timestamp for session start, 0 means now
+ *
+ */
+ void LogBluetoothSessionStart(connection_tech_t connection_tech_type,
+ uint64_t timestamp_ms);
+
+ /*
+ * Stop logging a Bluetooth session and pushes it to the log queue
+ *
+ * If no Bluetooth session exist, this method exits immediately
+ *
+ * Parameters:
+ * disconnect_reason : A string representation of disconnect reason
+ * timestamp_ms : the timestamp of session end, 0 means now
+ *
+ */
+ void LogBluetoothSessionEnd(disconnect_reason_t disconnect_reason,
+ uint64_t timestamp_ms);
+
+ /*
+ * Log information about remote device in a current Bluetooth session
+ *
+ * If a Bluetooth session does not exist, create one with default parameter
+ * and timestamp now
+ *
+ * Parameters:
+ * device_class : device_class defined in btm_api_types.h
+ * device_type : type of remote device
+ */
+ void LogBluetoothSessionDeviceInfo(uint32_t device_class,
+ device_type_t device_type);
+
+ /*
+ * Log A2DP Audio Session Information
+ *
+ * - Repeated calls to this method will override previous metrics if in the
+ * same Bluetooth connection
+ * - If a Bluetooth session does not exist, create one with default parameter
+ * and timestamp now
+ *
+ * Parameters:
+ * a2dp_session_metrics - pointer to struct holding a2dp stats
+ *
+ */
+ void LogA2dpSession(const A2dpSessionMetrics& a2dp_session_metrics);
+
+ /**
+ * Log Headset profile RFCOMM connection event
+ *
+ * @param service_id the BTA service ID for this headset connection
+ */
+ void LogHeadsetProfileRfcConnection(tBTA_SERVICE_ID service_id);
+
+ /*
+ * Writes the metrics, in base64 protobuf format, into the descriptor FD,
+ * metrics events are always cleared after dump
+ */
+ void WriteBase64(int fd);
+ void WriteBase64String(std::string* serialized);
+ void WriteString(std::string* serialized);
+
+ /*
+ * Reset the metrics logger by cleaning up its staging queues and existing
+ * protobuf objects.
+ */
+ void Reset();
+
+ /*
+ * Maximum number of log entries for each session or event
+ */
+ static const size_t kMaxNumBluetoothSession = 50;
+ static const size_t kMaxNumPairEvent = 50;
+ static const size_t kMaxNumWakeEvent = 1000;
+ static const size_t kMaxNumScanEvent = 50;
+
+ private:
+ BluetoothMetricsLogger();
+
+ /*
+ * When a Bluetooth session is on and the user initiates a metrics dump, we
+ * need to be able to upload whatever we have first. This method breaks the
+ * ongoing Bluetooth session into two sessions with the previous one labeled
+ * as "METRICS_DUMP" for the disconnect reason.
+ */
+ void CutoffSession();
+
+ /*
+ * Build the internal metrics object using information gathered
+ */
+ void Build();
+
+ /*
+ * Reset objects related to current Bluetooth session
+ */
+ void ResetSession();
+
+ /*
+ * Reset the underlining BluetoothLog object
+ */
+ void ResetLog();
+
+ /*
+ * PIMPL style implementation to hide internal dependencies
+ */
+ struct impl;
+ std::unique_ptr<impl> const pimpl_;
+};
+
+/**
+ * Unknown connection handle for metrics purpose
+ */
+static const uint32_t kUnknownConnectionHandle = 0xFFFF;
+
+/**
+ * Log link layer connection event
+ *
+ * @param address Stack wide consistent Bluetooth address of this event,
+ * nullptr if unknown
+ * @param connection_handle connection handle of this event,
+ * {@link kUnknownConnectionHandle} if unknown
+ * @param direction direction of this connection
+ * @param link_type type of the link
+ * @param hci_cmd HCI command opecode associated with this event, if any
+ * @param hci_event HCI event code associated with this event, if any
+ * @param hci_ble_event HCI BLE event code associated with this event, if any
+ * @param cmd_status Command status associated with this event, if any
+ * @param reason_code Reason code associated with this event, if any
+ */
+void LogLinkLayerConnectionEvent(const RawAddress* address,
+ uint32_t connection_handle,
+ android::bluetooth::DirectionEnum direction,
+ uint16_t link_type, uint32_t hci_cmd,
+ uint16_t hci_event, uint16_t hci_ble_event,
+ uint16_t cmd_status, uint16_t reason_code);
+
+/**
+ * Logs when Bluetooth controller failed to reply with command status within
+ * a timeout period after receiving an HCI command from the host
+ *
+ * @param hci_cmd opcode of HCI command that caused this timeout
+ */
+void LogHciTimeoutEvent(uint32_t hci_cmd);
+
+/**
+ * Logs when we receive Bluetooth Read Remote Version Information Complete
+ * Event from the remote device, as documented by the Bluetooth Core HCI
+ * specification
+ *
+ * Reference: 5.0 Core Specification, Vol 2, Part E, Page 1118
+ *
+ * @param handle handle of associated ACL connection
+ * @param status HCI command status of this event
+ * @param version version code from read remote version complete event
+ * @param manufacturer_name manufacturer code from read remote version complete
+ * event
+ * @param subversion subversion code from read remote version complete event
+ */
+void LogRemoteVersionInfo(uint16_t handle, uint8_t status, uint8_t version,
+ uint16_t manufacturer_name, uint16_t subversion);
+
+/**
+ * Log A2DP audio buffer underrun event
+ *
+ * @param address A2DP device associated with this event
+ * @param encoding_interval_millis encoding interval in milliseconds
+ * @param num_missing_pcm_bytes number of PCM bytes that cannot be read from
+ * the source
+ */
+void LogA2dpAudioUnderrunEvent(const RawAddress& address,
+ uint64_t encoding_interval_millis,
+ int num_missing_pcm_bytes);
+
+/**
+ * Log A2DP audio buffer overrun event
+ *
+ * @param address A2DP device associated with this event
+ * @param encoding_interval_millis encoding interval in milliseconds
+ * @param num_dropped_buffers number of encoded buffers dropped from Tx queue
+ * @param num_dropped_encoded_frames number of encoded frames dropped from Tx
+ * queue
+ * @param num_dropped_encoded_bytes number of encoded bytes dropped from Tx
+ * queue
+ */
+void LogA2dpAudioOverrunEvent(const RawAddress& address,
+ uint64_t encoding_interval_millis,
+ int num_dropped_buffers,
+ int num_dropped_encoded_frames,
+ int num_dropped_encoded_bytes);
+
+/**
+ * Log read RSSI result
+ *
+ * @param address device associated with this event
+ * @param handle connection handle of this event,
+ * {@link kUnknownConnectionHandle} if unknown
+ * @param cmd_status command status from read RSSI command
+ * @param rssi rssi value in dBm
+ */
+void LogReadRssiResult(const RawAddress& address, uint16_t handle,
+ uint32_t cmd_status, int8_t rssi);
+
+/**
+ * Log failed contact counter report
+ *
+ * @param address device associated with this event
+ * @param handle connection handle of this event,
+ * {@link kUnknownConnectionHandle} if unknown
+ * @param cmd_status command status from read failed contact counter command
+ * @param failed_contact_counter Number of consecutive failed contacts for a
+ * connection corresponding to the Handle
+ */
+void LogReadFailedContactCounterResult(const RawAddress& address,
+ uint16_t handle, uint32_t cmd_status,
+ int32_t failed_contact_counter);
+
+/**
+ * Log transmit power level for a particular device after read
+ *
+ * @param address device associated with this event
+ * @param handle connection handle of this event,
+ * {@link kUnknownConnectionHandle} if unknown
+ * @param cmd_status command status from read failed contact counter command
+ * @param transmit_power_level transmit power level for connection to this
+ * device
+ */
+void LogReadTxPowerLevelResult(const RawAddress& address, uint16_t handle,
+ uint32_t cmd_status,
+ int32_t transmit_power_level);
+
+/**
+ * Logs when there is an event related to Bluetooth Security Manager Protocol
+ *
+ * @param address address of associated device
+ * @param smp_cmd SMP command code associated with this event
+ * @param direction direction of this SMP command
+ * @param smp_fail_reason SMP pairing failure reason code from SMP spec
+ */
+void LogSmpPairingEvent(const RawAddress& address, uint8_t smp_cmd,
+ android::bluetooth::DirectionEnum direction,
+ uint8_t smp_fail_reason);
+
+/**
+ * Logs there is an event related Bluetooth classic pairing
+ *
+ * @param address address of associated device
+ * @param handle connection handle of this event,
+ * {@link kUnknownConnectionHandle} if unknown
+ * @param hci_cmd HCI command associated with this event
+ * @param hci_event HCI event associated with this event
+ * @param cmd_status Command status associated with this event
+ * @param reason_code Reason code associated with this event
+ * @param event_value A status value related to this specific event
+ */
+void LogClassicPairingEvent(const RawAddress& address, uint16_t handle, uint32_t hci_cmd, uint16_t hci_event,
+ uint16_t cmd_status, uint16_t reason_code, int64_t event_value);
+
+/**
+ * Logs when certain Bluetooth SDP attributes are discovered
+ *
+ * @param address address of associated device
+ * @param protocol_uuid 16 bit protocol UUID from Bluetooth Assigned Numbers
+ * @param attribute_id 16 bit attribute ID from Bluetooth Assigned Numbers
+ * @param attribute_size size of this attribute
+ * @param attribute_value pointer to the attribute data, must be larger than
+ * attribute_size
+ */
+void LogSdpAttribute(const RawAddress& address, uint16_t protocol_uuid,
+ uint16_t attribute_id, size_t attribute_size,
+ const char* attribute_value);
+
+/**
+ * Logs when there is a change in Bluetooth socket connection state
+ *
+ * @param address address of associated device, empty if this is a server port
+ * @param port port of this socket connection
+ * @param type type of socket
+ * @param connection_state socket connection state
+ * @param tx_bytes number of bytes transmitted
+ * @param rx_bytes number of bytes received
+ * @param server_port server port of this socket, if any. When both
+ * |server_port| and |port| fields are populated, |port| must be spawned
+ * by |server_port|
+ * @param socket_role role of this socket, server or connection
+ * @param uid socket owner's uid
+ */
+void LogSocketConnectionState(
+ const RawAddress& address, int port, int type,
+ android::bluetooth::SocketConnectionstateEnum connection_state,
+ int64_t tx_bytes, int64_t rx_bytes, int uid, int server_port,
+ android::bluetooth::SocketRoleEnum socket_role);
+
+/**
+ * Logs when a Bluetooth device's manufacturer information is learnt
+ *
+ * @param address address of associated device
+ * @param source_type where is this device info obtained from
+ * @param source_name name of the data source, internal or external
+ * @param manufacturer name of the manufacturer of this device
+ * @param model model of this device
+ * @param hardware_version hardware version of this device
+ * @param software_version software version of this device
+ */
+void LogManufacturerInfo(const RawAddress& address,
+ android::bluetooth::DeviceInfoSrcEnum source_type,
+ const std::string& source_name,
+ const std::string& manufacturer,
+ const std::string& model,
+ const std::string& hardware_version,
+ const std::string& software_version);
+} // namespace common
+
+} // namespace bluetooth
diff --git a/common/metrics_linux.cc b/common/metrics_linux.cc
new file mode 100644
index 0000000..bf16960
--- /dev/null
+++ b/common/metrics_linux.cc
@@ -0,0 +1,93 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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 "metrics.h"
+
+#include <base/logging.h>
+
+#include "leaky_bonded_queue.h"
+
+namespace bluetooth {
+
+namespace common {
+
+void A2dpSessionMetrics::Update(const A2dpSessionMetrics& metrics) {}
+
+bool A2dpSessionMetrics::operator==(const A2dpSessionMetrics& rhs) const {
+ LOG(FATAL) << "UNIMPLEMENTED";
+ return 0;
+}
+
+struct BluetoothMetricsLogger::impl {
+ impl(size_t max_bluetooth_session, size_t max_pair_event,
+ size_t max_wake_event, size_t max_scan_event) {}
+};
+
+BluetoothMetricsLogger::BluetoothMetricsLogger()
+ : pimpl_(new impl(kMaxNumBluetoothSession, kMaxNumPairEvent,
+ kMaxNumWakeEvent, kMaxNumScanEvent)) {}
+
+void BluetoothMetricsLogger::LogPairEvent(uint32_t disconnect_reason,
+ uint64_t timestamp_ms,
+ uint32_t device_class,
+ device_type_t device_type) {}
+
+void BluetoothMetricsLogger::LogWakeEvent(wake_event_type_t type,
+ const std::string& requestor,
+ const std::string& name,
+ uint64_t timestamp_ms) {}
+
+void BluetoothMetricsLogger::LogScanEvent(bool start,
+ const std::string& initator,
+ scan_tech_t type, uint32_t results,
+ uint64_t timestamp_ms) {}
+
+void BluetoothMetricsLogger::LogBluetoothSessionStart(
+ connection_tech_t connection_tech_type, uint64_t timestamp_ms) {}
+
+void BluetoothMetricsLogger::LogBluetoothSessionEnd(
+ disconnect_reason_t disconnect_reason, uint64_t timestamp_ms) {}
+
+void BluetoothMetricsLogger::LogBluetoothSessionDeviceInfo(
+ uint32_t device_class, device_type_t device_type) {}
+
+void BluetoothMetricsLogger::LogA2dpSession(
+ const A2dpSessionMetrics& a2dp_session_metrics) {}
+
+void BluetoothMetricsLogger::LogHeadsetProfileRfcConnection(
+ tBTA_SERVICE_ID service_id) {}
+
+void BluetoothMetricsLogger::WriteString(std::string* serialized) {}
+
+void BluetoothMetricsLogger::WriteBase64String(std::string* serialized) {}
+
+void BluetoothMetricsLogger::WriteBase64(int fd) {}
+
+void BluetoothMetricsLogger::CutoffSession() {}
+
+void BluetoothMetricsLogger::Build() {}
+
+void BluetoothMetricsLogger::ResetSession() {}
+
+void BluetoothMetricsLogger::ResetLog() {}
+
+void BluetoothMetricsLogger::Reset() {}
+
+} // namespace common
+
+} // namespace bluetooth
diff --git a/common/metrics_unittest.cc b/common/metrics_unittest.cc
new file mode 100644
index 0000000..a46c896
--- /dev/null
+++ b/common/metrics_unittest.cc
@@ -0,0 +1,1008 @@
+/******************************************************************************
+ *
+ * Copyright 2016 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 <chrono>
+#include <cstdint>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <base/logging.h>
+#include <include/hardware/bt_av.h>
+
+#include "bluetooth/metrics/bluetooth.pb.h"
+#include "common/metrics.h"
+#include "common/time_util.h"
+
+#define BTM_COD_MAJOR_AUDIO_TEST 0x04
+
+namespace testing {
+
+using bluetooth::common::A2dpSessionMetrics;
+using bluetooth::common::BluetoothMetricsLogger;
+using bluetooth::metrics::BluetoothMetricsProto::A2DPSession;
+using bluetooth::metrics::BluetoothMetricsProto::A2dpSourceCodec;
+using bluetooth::metrics::BluetoothMetricsProto::BluetoothLog;
+using bluetooth::metrics::BluetoothMetricsProto::BluetoothSession;
+using bluetooth::metrics::BluetoothMetricsProto::
+ BluetoothSession_ConnectionTechnologyType;
+using bluetooth::metrics::BluetoothMetricsProto::
+ BluetoothSession_DisconnectReasonType;
+using bluetooth::metrics::BluetoothMetricsProto::DeviceInfo;
+using bluetooth::metrics::BluetoothMetricsProto::DeviceInfo_DeviceType;
+using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileConnectionStats;
+using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileType;
+using bluetooth::metrics::BluetoothMetricsProto::PairEvent;
+using bluetooth::metrics::BluetoothMetricsProto::RFCommSession;
+using bluetooth::metrics::BluetoothMetricsProto::ScanEvent;
+using bluetooth::metrics::BluetoothMetricsProto::ScanEvent_ScanEventType;
+using bluetooth::metrics::BluetoothMetricsProto::ScanEvent_ScanTechnologyType;
+using bluetooth::metrics::BluetoothMetricsProto::WakeEvent;
+using bluetooth::metrics::BluetoothMetricsProto::WakeEvent_WakeEventType;
+
+namespace {
+const size_t kMaxEventGenerationLimit = 5000;
+}
+
+static void sleep_ms(int64_t t) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(t));
+}
+
+DeviceInfo* MakeDeviceInfo(int32_t device_class,
+ DeviceInfo_DeviceType device_type) {
+ DeviceInfo* info = new DeviceInfo();
+ info->set_device_class(device_class);
+ info->set_device_type(device_type);
+ return info;
+}
+
+PairEvent* MakePairEvent(int32_t disconnect_reason, int64_t timestamp_ms,
+ DeviceInfo* device_info) {
+ PairEvent* event = new PairEvent();
+ event->set_disconnect_reason(disconnect_reason);
+ event->set_event_time_millis(timestamp_ms);
+ if (device_info) event->set_allocated_device_paired_with(device_info);
+ return event;
+}
+
+WakeEvent* MakeWakeEvent(WakeEvent_WakeEventType event_type,
+ const std::string& requestor, const std::string& name,
+ int64_t timestamp_ms) {
+ WakeEvent* event = new WakeEvent();
+ event->set_wake_event_type(event_type);
+ event->set_requestor(requestor);
+ event->set_name(name);
+ event->set_event_time_millis(timestamp_ms);
+ return event;
+}
+
+ScanEvent* MakeScanEvent(ScanEvent_ScanEventType event_type,
+ const std::string& initiator,
+ ScanEvent_ScanTechnologyType tech_type,
+ int32_t num_results, int64_t timestamp_ms) {
+ ScanEvent* event = new ScanEvent();
+ event->set_scan_event_type(event_type);
+ event->set_initiator(initiator);
+ event->set_scan_technology_type(tech_type);
+ event->set_number_results(num_results);
+ event->set_event_time_millis(timestamp_ms);
+ return event;
+}
+
+A2DPSession* MakeA2DPSession(const A2dpSessionMetrics& metrics,
+ A2dpSourceCodec source_codec) {
+ A2DPSession* session = new A2DPSession();
+ session->set_media_timer_min_millis(metrics.media_timer_min_ms);
+ session->set_media_timer_max_millis(metrics.media_timer_max_ms);
+ session->set_media_timer_avg_millis(metrics.media_timer_avg_ms);
+ session->set_buffer_overruns_max_count(metrics.buffer_overruns_max_count);
+ session->set_buffer_overruns_total(metrics.buffer_overruns_total);
+ session->set_buffer_underruns_average(metrics.buffer_underruns_average);
+ session->set_buffer_underruns_count(metrics.buffer_underruns_count);
+ session->set_audio_duration_millis(metrics.audio_duration_ms);
+ session->set_source_codec(source_codec);
+ session->set_is_a2dp_offload(metrics.is_a2dp_offload);
+ return session;
+}
+
+BluetoothSession* MakeBluetoothSession(
+ int64_t session_duration_sec,
+ BluetoothSession_ConnectionTechnologyType conn_type,
+ BluetoothSession_DisconnectReasonType disconnect_reason,
+ DeviceInfo* device_info, RFCommSession* rfcomm_session,
+ A2DPSession* a2dp_session) {
+ BluetoothSession* session = new BluetoothSession();
+ if (a2dp_session) session->set_allocated_a2dp_session(a2dp_session);
+ if (rfcomm_session) session->set_allocated_rfcomm_session(rfcomm_session);
+ if (device_info) session->set_allocated_device_connected_to(device_info);
+ session->set_session_duration_sec(session_duration_sec);
+ session->set_connection_technology_type(conn_type);
+ session->set_disconnect_reason_type(disconnect_reason);
+ return session;
+}
+
+BluetoothLog* MakeBluetoothLog(std::vector<BluetoothSession*> bt_sessions,
+ std::vector<PairEvent*> pair_events,
+ std::vector<WakeEvent*> wake_events,
+ std::vector<ScanEvent*> scan_events) {
+ BluetoothLog* bt_log = new BluetoothLog();
+ for (BluetoothSession* session : bt_sessions) {
+ bt_log->mutable_session()->AddAllocated(session);
+ }
+ bt_sessions.clear();
+ for (PairEvent* event : pair_events) {
+ bt_log->mutable_pair_event()->AddAllocated(event);
+ }
+ pair_events.clear();
+ for (WakeEvent* event : wake_events) {
+ bt_log->mutable_wake_event()->AddAllocated(event);
+ }
+ wake_events.clear();
+ for (ScanEvent* event : scan_events) {
+ bt_log->mutable_scan_event()->AddAllocated(event);
+ }
+ scan_events.clear();
+ return bt_log;
+}
+
+void GenerateWakeEvents(size_t start, size_t end,
+ std::vector<WakeEvent*>* wake_events) {
+ for (size_t i = start; i < end; ++i) {
+ wake_events->push_back(MakeWakeEvent(
+ i % 2 == 0 ? WakeEvent_WakeEventType::WakeEvent_WakeEventType_ACQUIRED
+ : WakeEvent_WakeEventType::WakeEvent_WakeEventType_RELEASED,
+ "TEST_REQ", "TEST_NAME", i));
+ }
+}
+
+#define COMPARE_A2DP_METRICS(a, b) \
+ do { \
+ EXPECT_EQ((a).audio_duration_ms, (b).audio_duration_ms); \
+ EXPECT_EQ((a).media_timer_min_ms, (b).media_timer_min_ms); \
+ EXPECT_EQ((a).media_timer_max_ms, (b).media_timer_max_ms); \
+ EXPECT_EQ((a).media_timer_avg_ms, (b).media_timer_avg_ms); \
+ EXPECT_EQ((a).total_scheduling_count, (b).total_scheduling_count); \
+ EXPECT_EQ((a).buffer_overruns_max_count, (b).buffer_overruns_max_count); \
+ EXPECT_EQ((a).buffer_overruns_total, (b).buffer_overruns_total); \
+ EXPECT_THAT((a).buffer_underruns_average, \
+ FloatNear((b).buffer_underruns_average, 0.01)); \
+ (a).buffer_underruns_average = (b).buffer_underruns_average; \
+ EXPECT_EQ((a).buffer_underruns_count, (b).buffer_underruns_count); \
+ EXPECT_EQ((a).codec_index, (b).codec_index); \
+ EXPECT_EQ((a).is_a2dp_offload, (b).is_a2dp_offload); \
+ } while (0)
+
+/*
+ * metrics_sum = metrics1 + metrics2
+ */
+TEST(BluetoothA2DPSessionMetricsTest, TestUpdateNormal) {
+ A2dpSessionMetrics metrics1;
+ A2dpSessionMetrics metrics2;
+ A2dpSessionMetrics metrics_sum;
+ metrics1.audio_duration_ms = 10;
+ metrics2.audio_duration_ms = 25;
+ metrics_sum.audio_duration_ms = 35;
+ metrics1.media_timer_min_ms = 10;
+ metrics2.media_timer_min_ms = 25;
+ metrics_sum.media_timer_min_ms = 10;
+ metrics1.media_timer_max_ms = 100;
+ metrics2.media_timer_max_ms = 200;
+ metrics_sum.media_timer_max_ms = 200;
+ metrics1.media_timer_avg_ms = 50;
+ metrics1.total_scheduling_count = 50;
+ metrics2.media_timer_avg_ms = 100;
+ metrics2.total_scheduling_count = 50;
+ metrics_sum.media_timer_avg_ms = 75;
+ metrics_sum.total_scheduling_count = 100;
+ metrics1.buffer_overruns_max_count = 70;
+ metrics2.buffer_overruns_max_count = 80;
+ metrics_sum.buffer_overruns_max_count = 80;
+ metrics1.buffer_underruns_average = 80;
+ metrics1.buffer_underruns_count = 1200;
+ metrics2.buffer_underruns_average = 130;
+ metrics2.buffer_underruns_count = 2400;
+ metrics_sum.buffer_underruns_average = 113.33333333;
+ metrics_sum.buffer_underruns_count = 3600;
+ metrics1.codec_index = -1;
+ metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
+ metrics_sum.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
+ metrics1.is_a2dp_offload = false;
+ metrics2.is_a2dp_offload = true;
+ metrics_sum.is_a2dp_offload = true;
+ metrics1.Update(metrics2);
+ COMPARE_A2DP_METRICS(metrics1, metrics_sum);
+ EXPECT_TRUE(metrics1 == metrics_sum);
+ EXPECT_EQ(metrics1, metrics_sum);
+}
+
+TEST(BluetoothA2DPSessionMetricsTest, TestUpdateNew) {
+ A2dpSessionMetrics metrics1;
+ A2dpSessionMetrics metrics2;
+ A2dpSessionMetrics metrics_sum;
+ metrics2.audio_duration_ms = 25;
+ metrics_sum.audio_duration_ms = 25;
+ metrics2.media_timer_min_ms = 25;
+ metrics_sum.media_timer_min_ms = 25;
+ metrics2.media_timer_max_ms = 200;
+ metrics_sum.media_timer_max_ms = 200;
+ metrics2.media_timer_avg_ms = 100;
+ metrics2.total_scheduling_count = 50;
+ metrics_sum.media_timer_avg_ms = 100;
+ metrics_sum.total_scheduling_count = 50;
+ metrics2.buffer_overruns_max_count = 80;
+ metrics_sum.buffer_overruns_max_count = 80;
+ metrics2.buffer_underruns_average = 130;
+ metrics2.buffer_underruns_count = 2400;
+ metrics_sum.buffer_underruns_average = 130;
+ metrics_sum.buffer_underruns_count = 2400;
+ metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_APTX;
+ metrics_sum.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_APTX;
+ metrics2.is_a2dp_offload = true;
+ metrics_sum.is_a2dp_offload = true;
+ metrics1.Update(metrics2);
+ COMPARE_A2DP_METRICS(metrics1, metrics_sum);
+ EXPECT_TRUE(metrics1 == metrics_sum);
+ EXPECT_EQ(metrics1, metrics_sum);
+}
+
+TEST(BluetoothA2DPSessionMetricsTest, TestNullUpdate) {
+ A2dpSessionMetrics metrics1;
+ A2dpSessionMetrics metrics2;
+ A2dpSessionMetrics metrics_sum;
+ metrics2.audio_duration_ms = 25;
+ metrics_sum.audio_duration_ms = 25;
+ metrics2.media_timer_min_ms = 25;
+ metrics_sum.media_timer_min_ms = 25;
+ metrics2.media_timer_max_ms = 200;
+ metrics_sum.media_timer_max_ms = 200;
+ metrics2.media_timer_avg_ms = 100;
+ metrics2.total_scheduling_count = 50;
+ metrics_sum.media_timer_avg_ms = 100;
+ metrics_sum.total_scheduling_count = 50;
+ metrics2.buffer_overruns_max_count = 80;
+ metrics_sum.buffer_overruns_max_count = 80;
+ metrics2.buffer_underruns_average = 130;
+ metrics2.buffer_underruns_count = 2400;
+ metrics_sum.buffer_underruns_average = 130;
+ metrics_sum.buffer_underruns_count = 2400;
+ metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD;
+ metrics_sum.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD;
+ metrics2.is_a2dp_offload = true;
+ metrics_sum.is_a2dp_offload = true;
+ metrics2.Update(metrics1);
+ COMPARE_A2DP_METRICS(metrics2, metrics_sum);
+ EXPECT_TRUE(metrics2 == metrics_sum);
+ EXPECT_EQ(metrics2, metrics_sum);
+}
+
+TEST(BluetoothA2DPSessionMetricsTest, TestPartialUpdate) {
+ A2dpSessionMetrics metrics1;
+ A2dpSessionMetrics metrics2;
+ A2dpSessionMetrics metrics_sum;
+ metrics1.audio_duration_ms = 10;
+ metrics2.audio_duration_ms = 25;
+ metrics_sum.audio_duration_ms = 35;
+ metrics1.media_timer_min_ms = 10;
+ metrics_sum.media_timer_min_ms = 10;
+ metrics1.media_timer_max_ms = 100;
+ metrics_sum.media_timer_max_ms = 100;
+ metrics1.media_timer_avg_ms = 50;
+ metrics1.total_scheduling_count = 50;
+ metrics2.media_timer_avg_ms = 100;
+ metrics_sum.media_timer_avg_ms = 50;
+ metrics_sum.total_scheduling_count = 50;
+ metrics1.buffer_overruns_max_count = 70;
+ metrics_sum.buffer_overruns_max_count = 70;
+ metrics1.buffer_underruns_average = 80;
+ metrics1.buffer_underruns_count = 1200;
+ metrics2.buffer_underruns_count = 2400;
+ metrics_sum.buffer_underruns_average = 80;
+ metrics_sum.buffer_underruns_count = 1200;
+ metrics1.Update(metrics2);
+ COMPARE_A2DP_METRICS(metrics1, metrics_sum);
+ EXPECT_TRUE(metrics1 == metrics_sum);
+ EXPECT_EQ(metrics1, metrics_sum);
+}
+
+class BluetoothMetricsLoggerTest : public Test {
+ protected:
+ // Use to hold test protos
+ std::vector<PairEvent*> pair_events_;
+ std::vector<WakeEvent*> wake_events_;
+ std::vector<ScanEvent*> scan_events_;
+ std::vector<BluetoothSession*> bt_sessions_;
+ int64_t num_pair_event_ = 0;
+ int64_t num_wake_event_ = 0;
+ int64_t num_scan_event_ = 0;
+ int64_t num_bt_session_ = 0;
+ BluetoothLog* bt_log_;
+ std::string bt_log_str_;
+ std::string bt_log_ascii_str_;
+
+ void UpdateLog() {
+ for (BluetoothSession* session : bt_sessions_) {
+ bt_log_->mutable_session()->AddAllocated(session);
+ }
+ if (num_bt_session_ > 0) {
+ bt_log_->set_num_bluetooth_session(num_bt_session_);
+ } else if (bt_sessions_.size() > 0) {
+ bt_log_->set_num_bluetooth_session(bt_sessions_.size());
+ }
+ bt_sessions_.clear();
+ for (PairEvent* event : pair_events_) {
+ bt_log_->mutable_pair_event()->AddAllocated(event);
+ }
+ if (num_pair_event_ > 0) {
+ bt_log_->set_num_pair_event(num_pair_event_);
+ } else if (pair_events_.size() > 0) {
+ bt_log_->set_num_pair_event(pair_events_.size());
+ }
+ pair_events_.clear();
+ for (WakeEvent* event : wake_events_) {
+ bt_log_->mutable_wake_event()->AddAllocated(event);
+ }
+ if (num_wake_event_ > 0) {
+ bt_log_->set_num_wake_event(num_wake_event_);
+ } else if (wake_events_.size() > 0) {
+ bt_log_->set_num_wake_event(wake_events_.size());
+ }
+ wake_events_.clear();
+ for (ScanEvent* event : scan_events_) {
+ bt_log_->mutable_scan_event()->AddAllocated(event);
+ }
+ if (num_scan_event_ > 0) {
+ bt_log_->set_num_scan_event(num_scan_event_);
+ } else if (scan_events_.size() > 0) {
+ bt_log_->set_num_scan_event(scan_events_.size());
+ }
+ scan_events_.clear();
+ bt_log_->SerializeToString(&bt_log_str_);
+ }
+
+ void ClearLog() {
+ for (BluetoothSession* session : bt_sessions_) {
+ session->Clear();
+ delete session;
+ }
+ bt_sessions_.clear();
+ for (PairEvent* event : pair_events_) {
+ event->Clear();
+ delete event;
+ }
+ pair_events_.clear();
+ for (WakeEvent* event : wake_events_) {
+ event->Clear();
+ delete event;
+ }
+ wake_events_.clear();
+ for (ScanEvent* event : scan_events_) {
+ event->Clear();
+ delete event;
+ }
+ scan_events_.clear();
+ bt_log_->Clear();
+ }
+
+ void SetUp() override {
+ bt_log_ = new BluetoothLog();
+ // Clear existing metrics entries, if any
+ BluetoothMetricsLogger::GetInstance()->Reset();
+ }
+ void TearDown() override {
+ // Clear remaining metrics entries, if any
+ BluetoothMetricsLogger::GetInstance()->Reset();
+ ClearLog();
+ delete bt_log_;
+ }
+
+ public:
+};
+
+TEST_F(BluetoothMetricsLoggerTest, PairEventTest) {
+ pair_events_.push_back(MakePairEvent(
+ 35, 12345,
+ MakeDeviceInfo(
+ 42, DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR)));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogPairEvent(
+ 35, 12345, 42, bluetooth::common::DEVICE_TYPE_BREDR);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+TEST_F(BluetoothMetricsLoggerTest, WakeEventTest) {
+ wake_events_.push_back(
+ MakeWakeEvent(WakeEvent_WakeEventType::WakeEvent_WakeEventType_ACQUIRED,
+ "TEST_REQ", "TEST_NAME", 12345));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogWakeEvent(
+ bluetooth::common::WAKE_EVENT_ACQUIRED, "TEST_REQ", "TEST_NAME", 12345);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+TEST_F(BluetoothMetricsLoggerTest, WakeEventOverrunTest) {
+ GenerateWakeEvents(
+ kMaxEventGenerationLimit - BluetoothMetricsLogger::kMaxNumWakeEvent,
+ kMaxEventGenerationLimit, &wake_events_);
+ num_wake_event_ = kMaxEventGenerationLimit;
+ UpdateLog();
+ for (size_t i = 0; i < kMaxEventGenerationLimit; ++i) {
+ BluetoothMetricsLogger::GetInstance()->LogWakeEvent(
+ i % 2 == 0 ? bluetooth::common::WAKE_EVENT_ACQUIRED
+ : bluetooth::common::WAKE_EVENT_RELEASED,
+ "TEST_REQ", "TEST_NAME", i);
+ }
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+TEST_F(BluetoothMetricsLoggerTest, ScanEventTest) {
+ scan_events_.push_back(MakeScanEvent(
+ ScanEvent_ScanEventType::ScanEvent_ScanEventType_SCAN_EVENT_STOP,
+ "TEST_INITIATOR",
+ ScanEvent_ScanTechnologyType::
+ ScanEvent_ScanTechnologyType_SCAN_TECH_TYPE_BREDR,
+ 42, 123456));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogScanEvent(
+ false, "TEST_INITIATOR", bluetooth::common::SCAN_TECH_TYPE_BREDR, 42,
+ 123456);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+TEST_F(BluetoothMetricsLoggerTest, BluetoothSessionTest) {
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 10,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_LE,
+ BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_UNKNOWN,
+ nullptr, nullptr, nullptr));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ bluetooth::common::CONNECTION_TECHNOLOGY_TYPE_LE, 123456);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
+ bluetooth::common::DISCONNECT_REASON_UNKNOWN, 133456);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+TEST_F(BluetoothMetricsLoggerTest, BluetoothSessionDumpBeforeEndTest) {
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 1,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_LE,
+ BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_METRICS_DUMP,
+ nullptr, nullptr, nullptr));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ bluetooth::common::CONNECTION_TECHNOLOGY_TYPE_LE,
+ bluetooth::common::time_get_os_boottime_ms());
+ sleep_ms(1000);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+TEST_F(BluetoothMetricsLoggerTest, BluetoothSessionStartBeforeEndTest) {
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 1,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_UNKNOWN,
+ BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_NEXT_START_WITHOUT_END_PREVIOUS,
+ nullptr, nullptr, nullptr));
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 2,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_LE,
+ BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_METRICS_DUMP,
+ nullptr, nullptr, nullptr));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ bluetooth::common::CONNECTION_TECHNOLOGY_TYPE_UNKNOWN, 0);
+ sleep_ms(1000);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ bluetooth::common::CONNECTION_TECHNOLOGY_TYPE_LE, 0);
+ sleep_ms(2000);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+/*
+ * Test Case: A2DPSessionTwoUpdatesTest
+ *
+ * 1. Create Instance
+ * 2. LogBluetoothSessionStart
+ * 3. LogBluetoothSessionDeviceInfo
+ * 4. LogA2dpSession
+ * 5. LogA2dpSession
+ * 6. LogBluetoothSessionEnd
+ * 7. WriteString
+ *
+ */
+TEST_F(BluetoothMetricsLoggerTest, A2DPSessionTwoUpdatesTest) {
+ /* Same metrics from BluetoothA2DPSessionMetricsTest.TestUpdateNormal */
+ A2dpSessionMetrics metrics1;
+ A2dpSessionMetrics metrics2;
+ A2dpSessionMetrics metrics_sum;
+ metrics1.audio_duration_ms = 10;
+ metrics2.audio_duration_ms = 25;
+ metrics_sum.audio_duration_ms = 35;
+ metrics1.media_timer_min_ms = 10;
+ metrics2.media_timer_min_ms = 25;
+ metrics_sum.media_timer_min_ms = 10;
+ metrics1.media_timer_max_ms = 100;
+ metrics2.media_timer_max_ms = 200;
+ metrics_sum.media_timer_max_ms = 200;
+ metrics1.media_timer_avg_ms = 50;
+ metrics1.total_scheduling_count = 50;
+ metrics2.media_timer_avg_ms = 100;
+ metrics2.total_scheduling_count = 50;
+ metrics_sum.media_timer_avg_ms = 75;
+ metrics_sum.total_scheduling_count = 100;
+ metrics1.buffer_overruns_max_count = 70;
+ metrics2.buffer_overruns_max_count = 80;
+ metrics_sum.buffer_overruns_max_count = 80;
+ metrics1.buffer_underruns_average = 80;
+ metrics1.buffer_underruns_count = 1200;
+ metrics2.buffer_underruns_average = 130;
+ metrics2.buffer_underruns_count = 2400;
+ metrics_sum.buffer_underruns_average = 113.33333333;
+ metrics_sum.buffer_underruns_count = 3600;
+ metrics1.codec_index = -1;
+ metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
+ metrics_sum.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
+ metrics1.is_a2dp_offload = false;
+ metrics2.is_a2dp_offload = true;
+ metrics_sum.is_a2dp_offload = true;
+ DeviceInfo* info = MakeDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST,
+ DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
+ A2DPSession* session =
+ MakeA2DPSession(metrics_sum, A2dpSourceCodec::A2DP_SOURCE_CODEC_AAC);
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 10,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
+ BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_UNKNOWN,
+ info, nullptr, session));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ bluetooth::common::CONNECTION_TECHNOLOGY_TYPE_BREDR, 123456);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST, bluetooth::common::DEVICE_TYPE_BREDR);
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics1);
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics2);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
+ bluetooth::common::DISCONNECT_REASON_UNKNOWN, 133456);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+/*
+ * Test Case: A2DPSessionTwoUpdatesSeparatedbyDumpTest
+ *
+ * 1. Create Instance
+ * 2. LogBluetoothSessionStart
+ * 3. LogBluetoothSessionDeviceInfo
+ * 4. LogA2dpSession
+ * 5. WriteString
+ * 6. LogA2dpSession
+ * 7. LogBluetoothSessionEnd
+ * 8. WriteString
+ *
+ */
+TEST_F(BluetoothMetricsLoggerTest, A2DPSessionTwoUpdatesSeparatedbyDumpTest) {
+ /* Same metrics from BluetoothA2DPSessionMetricsTest.TestUpdateNormal */
+ A2dpSessionMetrics metrics1;
+ A2dpSessionMetrics metrics2;
+ metrics1.audio_duration_ms = 10;
+ metrics2.audio_duration_ms = 25;
+ metrics1.media_timer_min_ms = 10;
+ metrics2.media_timer_min_ms = 25;
+ metrics1.media_timer_max_ms = 100;
+ metrics2.media_timer_max_ms = 200;
+ metrics1.media_timer_avg_ms = 50;
+ metrics1.total_scheduling_count = 50;
+ metrics2.media_timer_avg_ms = 100;
+ metrics2.total_scheduling_count = 50;
+ metrics1.buffer_overruns_max_count = 70;
+ metrics2.buffer_overruns_max_count = 80;
+ metrics1.buffer_underruns_average = 80;
+ metrics1.buffer_underruns_count = 1200;
+ metrics2.buffer_underruns_average = 130;
+ metrics2.buffer_underruns_count = 2400;
+ metrics1.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_SBC;
+ metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
+ DeviceInfo* info = MakeDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST,
+ DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
+ A2DPSession* session =
+ MakeA2DPSession(metrics1, A2dpSourceCodec::A2DP_SOURCE_CODEC_SBC);
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 1,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
+ BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_METRICS_DUMP,
+ info, nullptr, session));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ bluetooth::common::CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST, bluetooth::common::DEVICE_TYPE_BREDR);
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics1);
+ sleep_ms(1000);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+ ClearLog();
+ info = MakeDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST,
+ DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
+ session = MakeA2DPSession(metrics2, A2dpSourceCodec::A2DP_SOURCE_CODEC_AAC);
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 1,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
+ BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_UNKNOWN,
+ info, nullptr, session));
+ UpdateLog();
+ sleep_ms(1000);
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics2);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
+ bluetooth::common::DISCONNECT_REASON_UNKNOWN, 0);
+ msg_str.clear();
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+/*
+ * Test Case: A2DPSessionTwoUpdatesSeparatedbyEndTest
+ *
+ * 1. Create Instance
+ * 2. LogBluetoothSessionStart
+ * 3. LogA2dpSession
+ * 4. LogBluetoothSessionEnd
+ * 5. LogBluetoothSessionStart
+ * 6. LogA2dpSession
+ * 7. LogBluetoothSessionEnd
+ * 8. WriteString
+ *
+ */
+TEST_F(BluetoothMetricsLoggerTest, A2DPSessionTwoUpdatesSeparatedbyEndTest) {
+ /* Same metrics from BluetoothA2DPSessionMetricsTest.TestUpdateNormal */
+ A2dpSessionMetrics metrics1;
+ metrics1.audio_duration_ms = 10;
+ metrics1.media_timer_min_ms = 10;
+ metrics1.media_timer_max_ms = 100;
+ metrics1.media_timer_avg_ms = 50;
+ metrics1.total_scheduling_count = 50;
+ metrics1.buffer_overruns_max_count = 70;
+ metrics1.buffer_underruns_average = 80;
+ metrics1.buffer_underruns_count = 1200;
+ metrics1.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_SBC;
+ DeviceInfo* info = MakeDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST,
+ DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
+ A2DPSession* session =
+ MakeA2DPSession(metrics1, A2dpSourceCodec::A2DP_SOURCE_CODEC_SBC);
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 1,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
+ BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_UNKNOWN,
+ info, nullptr, session));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ bluetooth::common::CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST, bluetooth::common::DEVICE_TYPE_BREDR);
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics1);
+ sleep_ms(1000);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
+ bluetooth::common::DISCONNECT_REASON_UNKNOWN, 0);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+ ClearLog();
+ A2dpSessionMetrics metrics2;
+ metrics2.audio_duration_ms = 25;
+ metrics2.media_timer_min_ms = 25;
+ metrics2.media_timer_max_ms = 200;
+ metrics2.media_timer_avg_ms = 100;
+ metrics2.total_scheduling_count = 50;
+ metrics2.buffer_overruns_max_count = 80;
+ metrics2.buffer_underruns_average = 130;
+ metrics2.buffer_underruns_count = 2400;
+ metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
+ session = MakeA2DPSession(metrics2, A2dpSourceCodec::A2DP_SOURCE_CODEC_AAC);
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 1,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
+ BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_UNKNOWN,
+ nullptr, nullptr, session));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ bluetooth::common::CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
+ sleep_ms(1000);
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics2);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
+ bluetooth::common::DISCONNECT_REASON_UNKNOWN, 0);
+ msg_str.clear();
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+/*
+ * Test Case 1: A2DPSessionOnlyTest
+ *
+ * 1. Create Instance
+ * 4. LogA2dpSession
+ * 5. WriteString
+ * 6. LogA2dpSession
+ * 8. WriteString
+ *
+ */
+TEST_F(BluetoothMetricsLoggerTest, A2DPSessionOnlyTest) {
+ /* Same metrics from BluetoothA2DPSessionMetricsTest.TestUpdateNormal */
+ A2dpSessionMetrics metrics1;
+ A2dpSessionMetrics metrics2;
+ A2dpSessionMetrics metrics_sum;
+ metrics1.audio_duration_ms = 10;
+ metrics2.audio_duration_ms = 25;
+ metrics_sum.audio_duration_ms = 35;
+ metrics1.media_timer_min_ms = 10;
+ metrics2.media_timer_min_ms = 25;
+ metrics_sum.media_timer_min_ms = 10;
+ metrics1.media_timer_max_ms = 100;
+ metrics2.media_timer_max_ms = 200;
+ metrics_sum.media_timer_max_ms = 200;
+ metrics1.media_timer_avg_ms = 50;
+ metrics1.total_scheduling_count = 50;
+ metrics2.media_timer_avg_ms = 100;
+ metrics2.total_scheduling_count = 50;
+ metrics_sum.media_timer_avg_ms = 75;
+ metrics_sum.total_scheduling_count = 100;
+ metrics1.buffer_overruns_max_count = 70;
+ metrics2.buffer_overruns_max_count = 80;
+ metrics_sum.buffer_overruns_max_count = 80;
+ metrics1.buffer_underruns_average = 80;
+ metrics1.buffer_underruns_count = 1200;
+ metrics2.buffer_underruns_average = 130;
+ metrics2.buffer_underruns_count = 2400;
+ metrics_sum.buffer_underruns_average = 113.33333333;
+ metrics_sum.buffer_underruns_count = 3600;
+ metrics1.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_SBC;
+ metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
+ metrics_sum.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_SBC;
+ DeviceInfo* info = MakeDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST,
+ DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
+ A2DPSession* session =
+ MakeA2DPSession(metrics_sum, A2dpSourceCodec::A2DP_SOURCE_CODEC_SBC);
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 1,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
+ BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_METRICS_DUMP,
+ info, nullptr, session));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics1);
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics2);
+ sleep_ms(1000);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+/*
+ * Test Case: A2DPSessionDumpBeforeTwoUpdatesTest
+ *
+ * 1. Create Instance
+ * 2. LogBluetoothSessionStart
+ * 3. LogBluetoothSessionDeviceInfo
+ * 5. WriteString
+ * 6. LogA2dpSession
+ * 7. LogA2dpSession
+ * 8. LogBluetoothSessionEnd
+ * 9. WriteString
+ *
+ */
+TEST_F(BluetoothMetricsLoggerTest, A2DPSessionDumpBeforeTwoUpdatesTest) {
+ /* Same metrics from BluetoothA2DPSessionMetricsTest.TestUpdateNormal */
+ A2dpSessionMetrics metrics1;
+ A2dpSessionMetrics metrics2;
+ A2dpSessionMetrics metrics_sum;
+ metrics1.audio_duration_ms = 10;
+ metrics2.audio_duration_ms = 25;
+ metrics_sum.audio_duration_ms = 35;
+ metrics1.media_timer_min_ms = 10;
+ metrics2.media_timer_min_ms = 25;
+ metrics_sum.media_timer_min_ms = 10;
+ metrics1.media_timer_max_ms = 100;
+ metrics2.media_timer_max_ms = 200;
+ metrics_sum.media_timer_max_ms = 200;
+ metrics1.media_timer_avg_ms = 50;
+ metrics1.total_scheduling_count = 50;
+ metrics2.media_timer_avg_ms = 100;
+ metrics2.total_scheduling_count = 50;
+ metrics_sum.media_timer_avg_ms = 75;
+ metrics_sum.total_scheduling_count = 100;
+ metrics1.buffer_overruns_max_count = 70;
+ metrics2.buffer_overruns_max_count = 80;
+ metrics_sum.buffer_overruns_max_count = 80;
+ metrics1.buffer_underruns_average = 80;
+ metrics1.buffer_underruns_count = 1200;
+ metrics2.buffer_underruns_average = 130;
+ metrics2.buffer_underruns_count = 2400;
+ metrics_sum.buffer_underruns_average = 113.33333333;
+ metrics_sum.buffer_underruns_count = 3600;
+ metrics1.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_SBC;
+ metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
+ metrics_sum.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_SBC;
+ DeviceInfo* info = MakeDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST,
+ DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 1,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
+ BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_METRICS_DUMP,
+ info, nullptr, nullptr));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ bluetooth::common::CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST, bluetooth::common::DEVICE_TYPE_BREDR);
+ sleep_ms(1000);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+ ClearLog();
+ info = MakeDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST,
+ DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
+ A2DPSession* session =
+ MakeA2DPSession(metrics_sum, A2dpSourceCodec::A2DP_SOURCE_CODEC_SBC);
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 1,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
+ BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_UNKNOWN,
+ info, nullptr, session));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics1);
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics2);
+ sleep_ms(1000);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
+ bluetooth::common::DISCONNECT_REASON_UNKNOWN, 0);
+ msg_str.clear();
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+TEST_F(BluetoothMetricsLoggerTest, LogHeadsetProfileRfcConnectionTest) {
+ BluetoothMetricsLogger::GetInstance()->LogHeadsetProfileRfcConnection(
+ BTA_HSP_SERVICE_ID);
+ BluetoothMetricsLogger::GetInstance()->LogHeadsetProfileRfcConnection(
+ BTA_HFP_SERVICE_ID);
+ BluetoothMetricsLogger::GetInstance()->LogHeadsetProfileRfcConnection(
+ BTA_HFP_SERVICE_ID);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
+ BluetoothLog* metrics = BluetoothLog::default_instance().New();
+ metrics->ParseFromString(msg_str);
+ EXPECT_EQ(metrics->headset_profile_connection_stats_size(), 2);
+ bool hfp_correct = false;
+ bool hsp_correct = false;
+ for (const HeadsetProfileConnectionStats& headset_profile_connection_stats :
+ metrics->headset_profile_connection_stats()) {
+ switch (headset_profile_connection_stats.headset_profile_type()) {
+ case HeadsetProfileType::HFP:
+ EXPECT_EQ(headset_profile_connection_stats.num_times_connected(), 2);
+ hfp_correct = true;
+ break;
+ case HeadsetProfileType::HSP:
+ EXPECT_EQ(headset_profile_connection_stats.num_times_connected(), 1);
+ hsp_correct = true;
+ break;
+ default:
+ FAIL();
+ }
+ }
+ EXPECT_TRUE(hfp_correct);
+ EXPECT_TRUE(hsp_correct);
+ metrics->clear_headset_profile_connection_stats();
+ EXPECT_EQ(metrics->headset_profile_connection_stats_size(), 0);
+ msg_str.clear();
+ // Verify that dump after clean up result in an empty list
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
+ metrics->ParseFromString(msg_str);
+ EXPECT_EQ(metrics->headset_profile_connection_stats_size(), 0);
+ delete metrics;
+}
+
+TEST_F(BluetoothMetricsLoggerTest, LogHeadsetProfileRfcConnectionErrorTest) {
+ BluetoothMetricsLogger::GetInstance()->LogHeadsetProfileRfcConnection(
+ BTA_HSP_SERVICE_ID);
+ BluetoothMetricsLogger::GetInstance()->LogHeadsetProfileRfcConnection(
+ BTA_HFP_SERVICE_ID);
+ BluetoothMetricsLogger::GetInstance()->LogHeadsetProfileRfcConnection(
+ BTA_BIP_SERVICE_ID);
+ BluetoothMetricsLogger::GetInstance()->LogHeadsetProfileRfcConnection(
+ BTA_HSP_SERVICE_ID);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
+ BluetoothLog* metrics = BluetoothLog::default_instance().New();
+ metrics->ParseFromString(msg_str);
+ EXPECT_EQ(metrics->headset_profile_connection_stats_size(), 3);
+ bool hfp_correct = false;
+ bool hsp_correct = false;
+ bool unknown_correct = false;
+ for (const HeadsetProfileConnectionStats& headset_profile_connection_stats :
+ metrics->headset_profile_connection_stats()) {
+ switch (headset_profile_connection_stats.headset_profile_type()) {
+ case HeadsetProfileType::HFP:
+ EXPECT_EQ(headset_profile_connection_stats.num_times_connected(), 1);
+ hfp_correct = true;
+ break;
+ case HeadsetProfileType::HSP:
+ EXPECT_EQ(headset_profile_connection_stats.num_times_connected(), 2);
+ hsp_correct = true;
+ break;
+ default:
+ EXPECT_EQ(headset_profile_connection_stats.num_times_connected(), 1);
+ unknown_correct = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(hfp_correct);
+ EXPECT_TRUE(hsp_correct);
+ EXPECT_TRUE(unknown_correct);
+ metrics->clear_headset_profile_connection_stats();
+ EXPECT_EQ(metrics->headset_profile_connection_stats_size(), 0);
+ // Verify that dump after clean up result in an empty list
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
+ metrics->ParseFromString(msg_str);
+ EXPECT_EQ(metrics->headset_profile_connection_stats_size(), 0);
+ delete metrics;
+}
+} // namespace testing
diff --git a/common/once_timer.cc b/common/once_timer.cc
new file mode 100644
index 0000000..413dc44
--- /dev/null
+++ b/common/once_timer.cc
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2018 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 "once_timer.h"
+
+#include "message_loop_thread.h"
+#include "time_util.h"
+
+namespace bluetooth {
+
+namespace common {
+
+// This runs on user thread
+OnceTimer::~OnceTimer() {
+ std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
+ if (message_loop_thread_ != nullptr && message_loop_thread_->IsRunning()) {
+ CancelAndWait();
+ }
+}
+
+// This runs on user thread
+bool OnceTimer::Schedule(const base::WeakPtr<MessageLoopThread>& thread,
+ const base::Location& from_here,
+ base::OnceClosure task, base::TimeDelta delay) {
+ uint64_t time_now_us = time_get_os_boottime_us();
+ uint64_t time_next_task_us = time_now_us + delay.InMicroseconds();
+ std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
+ if (thread == nullptr) {
+ LOG(ERROR) << __func__ << ": thread must be non-null";
+ return false;
+ }
+ CancelAndWait();
+ task_ = std::move(task);
+ task_wrapper_.Reset(
+ base::BindOnce(&OnceTimer::RunTask, base::Unretained(this)));
+ message_loop_thread_ = thread;
+ delay_ = delay;
+ uint64_t time_until_next_us = time_next_task_us - time_get_os_boottime_us();
+ if (!thread->DoInThreadDelayed(
+ from_here, task_wrapper_.callback(),
+ base::TimeDelta::FromMicroseconds(time_until_next_us))) {
+ LOG(ERROR) << __func__
+ << ": failed to post task to message loop for thread " << *thread
+ << ", from " << from_here.ToString();
+ task_wrapper_.Cancel();
+ message_loop_thread_ = nullptr;
+ delay_ = {};
+ return false;
+ }
+ return true;
+}
+
+// This runs on user thread
+void OnceTimer::Cancel() {
+ std::promise<void> promise;
+ CancelHelper(std::move(promise));
+}
+
+// This runs on user thread
+void OnceTimer::CancelAndWait() {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ CancelHelper(std::move(promise));
+ future.wait();
+}
+
+// This runs on user thread
+void OnceTimer::CancelHelper(std::promise<void> promise) {
+ std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
+ MessageLoopThread* scheduled_thread = message_loop_thread_.get();
+ if (scheduled_thread == nullptr) {
+ promise.set_value();
+ return;
+ }
+ if (scheduled_thread->GetThreadId() == base::PlatformThread::CurrentId()) {
+ CancelClosure(std::move(promise));
+ return;
+ }
+ scheduled_thread->DoInThread(
+ FROM_HERE, base::BindOnce(&OnceTimer::CancelClosure,
+ base::Unretained(this), std::move(promise)));
+}
+
+// This runs on message loop thread
+void OnceTimer::CancelClosure(std::promise<void> promise) {
+ message_loop_thread_ = nullptr;
+ task_wrapper_.Cancel();
+ std::move(task_);
+ delay_ = base::TimeDelta();
+ promise.set_value();
+}
+
+// This runs on user thread
+bool OnceTimer::IsScheduled() const {
+ std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
+ return message_loop_thread_ != nullptr && message_loop_thread_->IsRunning();
+}
+
+// This runs on message loop thread
+void OnceTimer::RunTask() {
+ if (message_loop_thread_ == nullptr || !message_loop_thread_->IsRunning()) {
+ LOG(ERROR) << __func__
+ << ": message_loop_thread_ is null or is not running";
+ return;
+ }
+ CHECK_EQ(message_loop_thread_->GetThreadId(),
+ base::PlatformThread::CurrentId())
+ << ": task must run on message loop thread";
+
+ task_wrapper_.Cancel();
+ std::move(task_).Run();
+ message_loop_thread_ = nullptr;
+}
+
+} // namespace common
+
+} // namespace bluetooth
diff --git a/common/once_timer.h b/common/once_timer.h
new file mode 100644
index 0000000..9968be5
--- /dev/null
+++ b/common/once_timer.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2018 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 <base/bind.h>
+#include <base/cancelable_callback.h>
+#include <base/location.h>
+#include <future>
+
+namespace bluetooth {
+
+namespace common {
+
+class MessageLoopThread;
+
+/**
+ * An alarm clock that posts a delayed task to a specified MessageLoopThread
+ * once.
+ *
+ * Warning: MessageLoopThread must be running when any task is scheduled or
+ * being executed
+ */
+class OnceTimer final {
+ public:
+ OnceTimer() {}
+ ~OnceTimer();
+
+ /**
+ * Schedule a delayed task to the MessageLoopThread. Only one task can be
+ * scheduled at a time. If another task is scheduled, it will cancel the
+ * previous task synchronously and schedule the new task; this blocks until
+ * the previous task is cancelled.
+ *
+ * @param thread thread to run the task
+ * @param from_here location where this task is originated
+ * @param task task created through base::Bind()
+ * @param delay delay for the task to be executed
+ * @return true iff task is scheduled successfully
+ */
+ bool Schedule(const base::WeakPtr<MessageLoopThread>& thread,
+ const base::Location& from_here, base::OnceClosure task,
+ base::TimeDelta delay);
+
+ /**
+ * Post an event which cancels the current task asynchronously
+ */
+ void Cancel();
+
+ /**
+ * Post an event which cancels the current task and wait for the cancellation
+ * to be completed
+ */
+ void CancelAndWait();
+
+ /**
+ * Returns true when there is a pending task scheduled on a running thread,
+ * otherwise false.
+ */
+ bool IsScheduled() const;
+
+ private:
+ base::WeakPtr<MessageLoopThread> message_loop_thread_;
+ base::CancelableOnceClosure task_wrapper_;
+ base::OnceClosure task_;
+ base::TimeDelta delay_;
+ mutable std::recursive_mutex api_mutex_;
+ void CancelHelper(std::promise<void> promise);
+ void CancelClosure(std::promise<void> promise);
+
+ void RunTask();
+
+ DISALLOW_COPY_AND_ASSIGN(OnceTimer);
+};
+
+} // namespace common
+
+} // namespace bluetooth
diff --git a/common/once_timer_unittest.cc b/common/once_timer_unittest.cc
new file mode 100644
index 0000000..d0fa238
--- /dev/null
+++ b/common/once_timer_unittest.cc
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2018 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/bind.h>
+#include <base/bind_helpers.h>
+#include <base/logging.h>
+#include <gtest/gtest.h>
+#include <future>
+
+#include "message_loop_thread.h"
+#include "once_timer.h"
+
+using bluetooth::common::MessageLoopThread;
+using bluetooth::common::OnceTimer;
+
+// Allowed error between the expected and actual delay for DoInThreadDelayed().
+constexpr uint32_t delay_error_ms = 3;
+
+/**
+ * Unit tests to verify Task Scheduler.
+ */
+class OnceTimerTest : public ::testing::Test {
+ public:
+ void ShouldNotHappen() { FAIL() << "Should not happen"; }
+
+ void IncreaseTaskCounter(int scheduled_tasks, std::promise<void>* promise) {
+ counter_++;
+ if (counter_ == scheduled_tasks) {
+ promise->set_value();
+ }
+ }
+
+ void GetName(std::string* name, std::promise<void>* promise) {
+ char my_name[256];
+ pthread_getname_np(pthread_self(), my_name, sizeof(my_name));
+ name->append(my_name);
+ promise->set_value();
+ }
+
+ void SleepAndIncreaseCounter(std::promise<void>* promise, int sleep_ms) {
+ promise->set_value();
+ std::this_thread::sleep_for(std::chrono::milliseconds(sleep_ms));
+ counter_++;
+ }
+
+ void CancelTimerAndWait() { timer_->CancelAndWait(); }
+
+ protected:
+ void SetUp() override {
+ ::testing::Test::SetUp();
+ counter_ = 0;
+ timer_ = new OnceTimer();
+ promise_ = new std::promise<void>();
+ }
+
+ void TearDown() override {
+ if (promise_ != nullptr) {
+ delete promise_;
+ promise_ = nullptr;
+ }
+ if (timer_ != nullptr) {
+ delete timer_;
+ timer_ = nullptr;
+ }
+ }
+
+ int counter_;
+ OnceTimer* timer_;
+ std::promise<void>* promise_;
+};
+
+TEST_F(OnceTimerTest, initial_is_not_scheduled) {
+ ASSERT_FALSE(timer_->IsScheduled());
+}
+
+TEST_F(OnceTimerTest, schedule_task) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ message_loop_thread.StartUp();
+ auto future = promise_->get_future();
+ std::string my_name;
+ uint32_t delay_ms = 5;
+
+ timer_->Schedule(message_loop_thread.GetWeakPtr(), FROM_HERE,
+ base::BindOnce(&OnceTimerTest::GetName,
+ base::Unretained(this), &my_name, promise_),
+ base::TimeDelta::FromMilliseconds(delay_ms));
+ EXPECT_TRUE(timer_->IsScheduled());
+ future.get();
+ ASSERT_EQ(name, my_name);
+ std::this_thread::sleep_for(std::chrono::milliseconds(delay_error_ms));
+ EXPECT_FALSE(timer_->IsScheduled());
+}
+
+TEST_F(OnceTimerTest, cancel_without_scheduling) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ message_loop_thread.StartUp();
+
+ EXPECT_FALSE(timer_->IsScheduled());
+ timer_->CancelAndWait();
+ EXPECT_FALSE(timer_->IsScheduled());
+}
+
+TEST_F(OnceTimerTest, cancel_in_callback_no_deadlock) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ message_loop_thread.StartUp();
+ uint32_t delay_ms = 5;
+
+ timer_->Schedule(message_loop_thread.GetWeakPtr(), FROM_HERE,
+ base::BindOnce(&OnceTimerTest::CancelTimerAndWait,
+ base::Unretained(this)),
+ base::TimeDelta::FromMilliseconds(delay_ms));
+}
+
+TEST_F(OnceTimerTest, cancel_single_task) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ message_loop_thread.StartUp();
+ uint32_t delay_ms = 100000000;
+ timer_->Schedule(
+ message_loop_thread.GetWeakPtr(), FROM_HERE,
+ base::BindOnce(&OnceTimerTest::ShouldNotHappen, base::Unretained(this)),
+ base::TimeDelta::FromMilliseconds(delay_ms));
+ std::this_thread::sleep_for(std::chrono::milliseconds(delay_error_ms));
+ timer_->CancelAndWait();
+}
+
+TEST_F(OnceTimerTest, message_loop_thread_down_cancel_task) {
+ std::string name = "test_thread";
+ {
+ MessageLoopThread message_loop_thread(name);
+ message_loop_thread.StartUp();
+ uint32_t delay_ms = 100000000;
+ timer_->Schedule(
+ message_loop_thread.GetWeakPtr(), FROM_HERE,
+ base::BindOnce(&OnceTimerTest::ShouldNotHappen, base::Unretained(this)),
+ base::TimeDelta::FromMilliseconds(delay_ms));
+ std::this_thread::sleep_for(std::chrono::milliseconds(delay_error_ms));
+ }
+}
+
+// Verify that if a task is being executed, then cancelling it is no-op
+TEST_F(OnceTimerTest, cancel_current_task_no_effect) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ message_loop_thread.StartUp();
+ auto future = promise_->get_future();
+ uint32_t delay_ms = 5;
+
+ timer_->Schedule(message_loop_thread.GetWeakPtr(), FROM_HERE,
+ base::BindOnce(&OnceTimerTest::SleepAndIncreaseCounter,
+ base::Unretained(this), promise_, delay_ms),
+ base::TimeDelta::FromMilliseconds(delay_ms));
+ EXPECT_TRUE(timer_->IsScheduled());
+ future.get();
+ timer_->CancelAndWait();
+ ASSERT_EQ(counter_, 1);
+ EXPECT_FALSE(timer_->IsScheduled());
+}
+
+TEST_F(OnceTimerTest, reschedule_task_dont_invoke_new_task_early) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ message_loop_thread.StartUp();
+ uint32_t delay_ms = 5;
+ timer_->Schedule(message_loop_thread.GetWeakPtr(), FROM_HERE,
+ base::DoNothing(),
+ base::TimeDelta::FromMilliseconds(delay_ms));
+ std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms - 2));
+ timer_->Schedule(
+ message_loop_thread.GetWeakPtr(), FROM_HERE,
+ base::BindOnce(&OnceTimerTest::ShouldNotHappen, base::Unretained(this)),
+ base::TimeDelta::FromMilliseconds(delay_ms + 1000));
+ std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
+}
+
+TEST_F(OnceTimerTest, reschedule_task_when_firing_dont_invoke_new_task_early) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ message_loop_thread.StartUp();
+ uint32_t delay_ms = 5;
+ timer_->Schedule(message_loop_thread.GetWeakPtr(), FROM_HERE,
+ base::DoNothing(),
+ base::TimeDelta::FromMilliseconds(delay_ms));
+ std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
+ timer_->Schedule(
+ message_loop_thread.GetWeakPtr(), FROM_HERE,
+ base::BindOnce(&OnceTimerTest::ShouldNotHappen, base::Unretained(this)),
+ base::TimeDelta::FromMilliseconds(delay_ms + 1000));
+ std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
+}
+
+TEST_F(OnceTimerTest, reschedule_task_when_firing_must_schedule_new_task) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ message_loop_thread.StartUp();
+ uint32_t delay_ms = 5;
+ std::string my_name;
+ auto future = promise_->get_future();
+ timer_->Schedule(message_loop_thread.GetWeakPtr(), FROM_HERE,
+ base::DoNothing(),
+ base::TimeDelta::FromMilliseconds(delay_ms));
+ std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
+ timer_->Schedule(message_loop_thread.GetWeakPtr(), FROM_HERE,
+ base::BindOnce(&OnceTimerTest::GetName,
+ base::Unretained(this), &my_name, promise_),
+ base::TimeDelta::FromMilliseconds(delay_ms));
+ future.get();
+ ASSERT_EQ(name, my_name);
+}
diff --git a/common/repeating_timer.cc b/common/repeating_timer.cc
new file mode 100644
index 0000000..e34dabc
--- /dev/null
+++ b/common/repeating_timer.cc
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2018 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 "repeating_timer.h"
+
+#include "message_loop_thread.h"
+#include "time_util.h"
+
+namespace bluetooth {
+
+namespace common {
+
+constexpr base::TimeDelta kMinimumPeriod = base::TimeDelta::FromMicroseconds(1);
+
+// This runs on user thread
+RepeatingTimer::~RepeatingTimer() {
+ std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
+ if (message_loop_thread_ != nullptr && message_loop_thread_->IsRunning()) {
+ CancelAndWait();
+ }
+}
+
+// This runs on user thread
+bool RepeatingTimer::SchedulePeriodic(
+ const base::WeakPtr<MessageLoopThread>& thread,
+ const base::Location& from_here, base::Closure task,
+ base::TimeDelta period) {
+ if (period < kMinimumPeriod) {
+ LOG(ERROR) << __func__ << ": period must be at least " << kMinimumPeriod;
+ return false;
+ }
+
+ uint64_t time_now_us = time_get_os_boottime_us();
+ uint64_t time_next_task_us = time_now_us + period.InMicroseconds();
+ std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
+ if (thread == nullptr) {
+ LOG(ERROR) << __func__ << ": thread must be non-null";
+ return false;
+ }
+ CancelAndWait();
+ expected_time_next_task_us_ = time_next_task_us;
+ task_ = std::move(task);
+ task_wrapper_.Reset(
+ base::Bind(&RepeatingTimer::RunTask, base::Unretained(this)));
+ message_loop_thread_ = thread;
+ period_ = period;
+ uint64_t time_until_next_us = time_next_task_us - time_get_os_boottime_us();
+ if (!thread->DoInThreadDelayed(
+ from_here, task_wrapper_.callback(),
+ base::TimeDelta::FromMicroseconds(time_until_next_us))) {
+ LOG(ERROR) << __func__
+ << ": failed to post task to message loop for thread " << *thread
+ << ", from " << from_here.ToString();
+ expected_time_next_task_us_ = 0;
+ task_wrapper_.Cancel();
+ message_loop_thread_ = nullptr;
+ period_ = {};
+ return false;
+ }
+ return true;
+}
+
+// This runs on user thread
+void RepeatingTimer::Cancel() {
+ std::promise<void> promise;
+ CancelHelper(std::move(promise));
+}
+
+// This runs on user thread
+void RepeatingTimer::CancelAndWait() {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ CancelHelper(std::move(promise));
+ future.wait();
+}
+
+// This runs on user thread
+void RepeatingTimer::CancelHelper(std::promise<void> promise) {
+ std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
+ MessageLoopThread* scheduled_thread = message_loop_thread_.get();
+ if (scheduled_thread == nullptr) {
+ promise.set_value();
+ return;
+ }
+ if (scheduled_thread->GetThreadId() == base::PlatformThread::CurrentId()) {
+ CancelClosure(std::move(promise));
+ return;
+ }
+ scheduled_thread->DoInThread(
+ FROM_HERE, base::BindOnce(&RepeatingTimer::CancelClosure,
+ base::Unretained(this), std::move(promise)));
+}
+
+// This runs on message loop thread
+void RepeatingTimer::CancelClosure(std::promise<void> promise) {
+ message_loop_thread_ = nullptr;
+ task_wrapper_.Cancel();
+ task_ = {};
+ period_ = base::TimeDelta();
+ expected_time_next_task_us_ = 0;
+ promise.set_value();
+}
+
+// This runs on user thread
+bool RepeatingTimer::IsScheduled() const {
+ std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
+ return message_loop_thread_ != nullptr && message_loop_thread_->IsRunning();
+}
+
+// This runs on message loop thread
+void RepeatingTimer::RunTask() {
+ if (message_loop_thread_ == nullptr || !message_loop_thread_->IsRunning()) {
+ LOG(ERROR) << __func__
+ << ": message_loop_thread_ is null or is not running";
+ return;
+ }
+ CHECK_EQ(message_loop_thread_->GetThreadId(),
+ base::PlatformThread::CurrentId())
+ << ": task must run on message loop thread";
+
+ int64_t period_us = period_.InMicroseconds();
+ expected_time_next_task_us_ += period_us;
+ uint64_t time_now_us = time_get_os_boottime_us();
+ int64_t remaining_time_us = expected_time_next_task_us_ - time_now_us;
+ if (remaining_time_us < 0) {
+ // if remaining_time_us is negative, schedule the task to the nearest
+ // multiple of period
+ remaining_time_us = (remaining_time_us % period_us + period_us) % period_us;
+ }
+ message_loop_thread_->DoInThreadDelayed(
+ FROM_HERE, task_wrapper_.callback(),
+ base::TimeDelta::FromMicroseconds(remaining_time_us));
+
+ uint64_t time_before_task_us = time_get_os_boottime_us();
+ task_.Run();
+ uint64_t time_after_task_us = time_get_os_boottime_us();
+ auto task_time_us =
+ static_cast<int64_t>(time_after_task_us - time_before_task_us);
+ if (task_time_us > period_.InMicroseconds()) {
+ LOG(ERROR) << __func__ << ": Periodic task execution took " << task_time_us
+ << " microseconds, longer than interval "
+ << period_.InMicroseconds() << " microseconds";
+ }
+}
+
+} // namespace common
+
+} // namespace bluetooth
diff --git a/common/repeating_timer.h b/common/repeating_timer.h
new file mode 100644
index 0000000..b4c5108
--- /dev/null
+++ b/common/repeating_timer.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2018 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 <base/bind.h>
+#include <base/cancelable_callback.h>
+#include <base/location.h>
+#include <future>
+
+namespace bluetooth {
+
+namespace common {
+
+class MessageLoopThread;
+
+/**
+ * An alarm clock that posts a delayed task to a specified MessageLoopThread
+ * periodically.
+ *
+ * Warning: MessageLoopThread must be running when any task is scheduled or
+ * being executed
+ */
+class RepeatingTimer final {
+ public:
+ RepeatingTimer() : expected_time_next_task_us_(0) {}
+ ~RepeatingTimer();
+
+ /**
+ * Schedule a delayed periodic task to the MessageLoopThread. Only one task
+ * can be scheduled at a time. If another task is scheduled, it will cancel
+ * the previous task synchronously and schedule the new periodic task; this
+ * blocks until the previous task is cancelled.
+ *
+ * @param thread thread to run the task
+ * @param from_here location where this task is originated
+ * @param task task created through base::Bind()
+ * @param period period for the task to be executed
+ * @return true iff task is scheduled successfully
+ */
+ bool SchedulePeriodic(const base::WeakPtr<MessageLoopThread>& thread,
+ const base::Location& from_here,
+ base::RepeatingClosure task, base::TimeDelta period);
+
+ /**
+ * Post an event which cancels the current task asynchronously
+ */
+ void Cancel();
+
+ /**
+ * Post an event which cancels the current task and wait for the cancellation
+ * to be completed
+ */
+ void CancelAndWait();
+
+ /**
+ * Returns true when there is a pending task scheduled on a running thread,
+ * otherwise false.
+ */
+ bool IsScheduled() const;
+
+ private:
+ base::WeakPtr<MessageLoopThread> message_loop_thread_;
+ base::CancelableClosure task_wrapper_;
+ base::RepeatingClosure task_;
+ base::TimeDelta period_;
+ uint64_t expected_time_next_task_us_; // Using clock boot time in time_util.h
+ mutable std::recursive_mutex api_mutex_;
+ void CancelHelper(std::promise<void> promise);
+ void CancelClosure(std::promise<void> promise);
+
+ void RunTask();
+
+ DISALLOW_COPY_AND_ASSIGN(RepeatingTimer);
+};
+
+} // namespace common
+
+} // namespace bluetooth
diff --git a/common/repeating_timer_unittest.cc b/common/repeating_timer_unittest.cc
new file mode 100644
index 0000000..20d8d67
--- /dev/null
+++ b/common/repeating_timer_unittest.cc
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2018 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/bind.h>
+#include <base/bind_helpers.h>
+#include <base/logging.h>
+#include <gtest/gtest.h>
+#include <future>
+
+#include "message_loop_thread.h"
+#include "repeating_timer.h"
+
+using bluetooth::common::MessageLoopThread;
+using bluetooth::common::RepeatingTimer;
+
+// Allowed error between the expected and actual delay for DoInThreadDelayed().
+constexpr uint32_t delay_error_ms = 3;
+
+/**
+ * Unit tests to verify Task Scheduler.
+ */
+class RepeatingTimerTest : public ::testing::Test {
+ public:
+ void ShouldNotHappen() { FAIL() << "Should not happen"; }
+
+ void IncreaseTaskCounter(int scheduled_tasks, std::promise<void>* promise) {
+ counter_++;
+ if (counter_ == scheduled_tasks) {
+ promise->set_value();
+ }
+ }
+
+ void GetName(std::string* name, std::promise<void>* promise) {
+ char my_name[256];
+ pthread_getname_np(pthread_self(), my_name, sizeof(my_name));
+ name->append(my_name);
+ promise->set_value();
+ }
+
+ void SleepAndIncreaseCounter(std::promise<void>* promise, int sleep_ms) {
+ promise->set_value();
+ std::this_thread::sleep_for(std::chrono::milliseconds(sleep_ms));
+ counter_++;
+ }
+
+ void VerifyDelayTimeAndSleep(std::chrono::steady_clock::time_point start_time,
+ int interval_ms, int scheduled_tasks,
+ int task_length_ms,
+ std::promise<void>* promise) {
+ auto end_time = std::chrono::steady_clock::now();
+ auto actual_delay = std::chrono::duration_cast<std::chrono::milliseconds>(
+ end_time - start_time);
+ counter_++;
+ int64_t scheduled_delay_ms = interval_ms * counter_;
+ if (counter_ == scheduled_tasks) {
+ promise->set_value();
+ }
+ ASSERT_NEAR(scheduled_delay_ms, actual_delay.count(), delay_error_ms);
+ std::this_thread::sleep_for(std::chrono::milliseconds(task_length_ms));
+ }
+
+ void VerifyMultipleDelayedTasks(int scheduled_tasks, int task_length_ms,
+ int interval_between_tasks_ms) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ message_loop_thread.StartUp();
+ message_loop_thread.EnableRealTimeScheduling();
+ auto future = promise_->get_future();
+ auto start_time = std::chrono::steady_clock::now();
+ timer_->SchedulePeriodic(
+ message_loop_thread.GetWeakPtr(), FROM_HERE,
+ base::BindRepeating(&RepeatingTimerTest::VerifyDelayTimeAndSleep,
+ base::Unretained(this), start_time,
+ interval_between_tasks_ms, scheduled_tasks,
+ task_length_ms, promise_),
+ base::TimeDelta::FromMilliseconds(interval_between_tasks_ms));
+ future.get();
+ timer_->CancelAndWait();
+ }
+
+ void CancelRepeatingTimerAndWait() { timer_->CancelAndWait(); }
+
+ protected:
+ void SetUp() override {
+ ::testing::Test::SetUp();
+ counter_ = 0;
+ timer_ = new RepeatingTimer();
+ promise_ = new std::promise<void>();
+ }
+
+ void TearDown() override {
+ if (promise_ != nullptr) {
+ delete promise_;
+ promise_ = nullptr;
+ }
+ if (timer_ != nullptr) {
+ delete timer_;
+ timer_ = nullptr;
+ }
+ }
+
+ int counter_;
+ RepeatingTimer* timer_;
+ std::promise<void>* promise_;
+};
+
+TEST_F(RepeatingTimerTest, initial_is_not_scheduled) {
+ ASSERT_FALSE(timer_->IsScheduled());
+}
+
+TEST_F(RepeatingTimerTest, cancel_without_scheduling) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ message_loop_thread.StartUp();
+
+ EXPECT_FALSE(timer_->IsScheduled());
+ timer_->CancelAndWait();
+ EXPECT_FALSE(timer_->IsScheduled());
+}
+
+TEST_F(RepeatingTimerTest, periodic_run) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ message_loop_thread.StartUp();
+ auto future = promise_->get_future();
+ uint32_t delay_ms = 5;
+ int num_tasks = 200;
+
+ timer_->SchedulePeriodic(
+ message_loop_thread.GetWeakPtr(), FROM_HERE,
+ base::BindRepeating(&RepeatingTimerTest::IncreaseTaskCounter,
+ base::Unretained(this), num_tasks, promise_),
+ base::TimeDelta::FromMilliseconds(delay_ms));
+ future.get();
+ ASSERT_GE(counter_, num_tasks);
+ timer_->CancelAndWait();
+}
+
+TEST_F(RepeatingTimerTest, schedule_periodic_task_zero_interval) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ message_loop_thread.StartUp();
+ uint32_t interval_ms = 0;
+
+ ASSERT_FALSE(timer_->SchedulePeriodic(
+ message_loop_thread.GetWeakPtr(), FROM_HERE,
+ base::BindRepeating(&RepeatingTimerTest::ShouldNotHappen,
+ base::Unretained(this)),
+ base::TimeDelta::FromMilliseconds(interval_ms)));
+ std::this_thread::sleep_for(std::chrono::milliseconds(delay_error_ms));
+}
+
+// Verify that deleting the timer without cancelling it will cancel the task
+TEST_F(RepeatingTimerTest, periodic_delete_without_cancel) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ message_loop_thread.StartUp();
+ uint32_t delay_ms = 5;
+ timer_->SchedulePeriodic(
+ message_loop_thread.GetWeakPtr(), FROM_HERE,
+ base::BindRepeating(&RepeatingTimerTest::ShouldNotHappen,
+ base::Unretained(this)),
+ base::TimeDelta::FromMilliseconds(delay_ms));
+ delete timer_;
+ timer_ = nullptr;
+ std::this_thread::sleep_for(std::chrono::milliseconds(delay_error_ms));
+}
+
+TEST_F(RepeatingTimerTest, cancel_single_task_near_fire_no_race_condition) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ message_loop_thread.StartUp();
+ uint32_t delay_ms = 5;
+ timer_->SchedulePeriodic(message_loop_thread.GetWeakPtr(), FROM_HERE,
+ base::DoNothing(),
+ base::TimeDelta::FromMilliseconds(delay_ms));
+ std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
+ timer_->CancelAndWait();
+}
+
+TEST_F(RepeatingTimerTest, cancel_periodic_task) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ message_loop_thread.StartUp();
+ uint32_t delay_ms = 5;
+ int num_tasks = 5;
+ auto future = promise_->get_future();
+
+ timer_->SchedulePeriodic(
+ message_loop_thread.GetWeakPtr(), FROM_HERE,
+ base::BindRepeating(&RepeatingTimerTest::IncreaseTaskCounter,
+ base::Unretained(this), num_tasks, promise_),
+ base::TimeDelta::FromMilliseconds(delay_ms));
+ future.wait();
+ timer_->CancelAndWait();
+ std::this_thread::sleep_for(
+ std::chrono::milliseconds(delay_ms + delay_error_ms));
+ int counter = counter_;
+ std::this_thread::sleep_for(
+ std::chrono::milliseconds(delay_ms + delay_error_ms));
+ ASSERT_EQ(counter, counter_);
+}
+
+// Schedule 10 short periodic tasks with interval 1 ms between each; verify the
+// functionality
+TEST_F(RepeatingTimerTest, schedule_multiple_delayed_tasks) {
+ VerifyMultipleDelayedTasks(10, 0, 1);
+}
+
+// Schedule 10 periodic tasks with interval 2 ms between each and each takes 1
+// ms; verify the functionality
+TEST_F(RepeatingTimerTest, schedule_multiple_delayed_slow_tasks) {
+ VerifyMultipleDelayedTasks(10, 1, 2);
+}
+
+TEST_F(RepeatingTimerTest,
+ message_loop_thread_down_cancel_scheduled_periodic_task) {
+ std::string name = "test_thread";
+ MessageLoopThread message_loop_thread(name);
+ message_loop_thread.StartUp();
+ std::string my_name;
+ auto future = promise_->get_future();
+ uint32_t delay_ms = 5;
+ int num_tasks = 5;
+
+ timer_->SchedulePeriodic(
+ message_loop_thread.GetWeakPtr(), FROM_HERE,
+ base::BindRepeating(&RepeatingTimerTest::IncreaseTaskCounter,
+ base::Unretained(this), num_tasks, promise_),
+ base::TimeDelta::FromMilliseconds(delay_ms));
+ future.wait();
+ message_loop_thread.ShutDown();
+ std::this_thread::sleep_for(
+ std::chrono::milliseconds(delay_ms + delay_error_ms));
+ int counter = counter_;
+ std::this_thread::sleep_for(
+ std::chrono::milliseconds(delay_ms + delay_error_ms));
+ ASSERT_EQ(counter, counter_);
+}
diff --git a/common/scoped_scs_exit.h b/common/scoped_scs_exit.h
new file mode 100644
index 0000000..ad4a8d6
--- /dev/null
+++ b/common/scoped_scs_exit.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2018 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
+
+// Prevent x18 (shadow call stack address) from being clobbered by functions
+// called by a function that declares a variable of this type by temporarily
+// storing the value on the stack. This is used only when calling out to certain
+// vendor libraries.
+struct ScopedSCSExit {
+#ifdef __aarch64__
+ void* scs;
+
+ __attribute__((always_inline, no_sanitize("shadow-call-stack"))) ScopedSCSExit() {
+ __asm__ __volatile__("str x18, [%0]" ::"r"(&scs));
+ }
+
+ __attribute__((always_inline, no_sanitize("shadow-call-stack"))) ~ScopedSCSExit() {
+ __asm__ __volatile__("ldr x18, [%0]; str xzr, [%0]" ::"r"(&scs));
+ }
+#else
+ // Silence unused variable warnings in non-SCS builds.
+ __attribute__((no_sanitize("shadow-call-stack"))) ScopedSCSExit() {}
+ __attribute__((no_sanitize("shadow-call-stack"))) ~ScopedSCSExit() {}
+#endif
+};
diff --git a/common/state_machine.h b/common/state_machine.h
new file mode 100644
index 0000000..62d92d2
--- /dev/null
+++ b/common/state_machine.h
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2018 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 <map>
+#include <utility>
+
+#include <base/logging.h>
+
+namespace bluetooth {
+
+namespace common {
+
+/**
+ * State machine used by Bluetooth native stack.
+ */
+class StateMachine {
+ public:
+ enum { kStateInvalid = -1 };
+
+ /**
+ * A class to represent the state in the State Machine.
+ */
+ class State {
+ friend class StateMachine;
+
+ public:
+ /**
+ * Constructor.
+ *
+ * @param sm the State Machine to use
+ * @param state_id the unique State ID. It should be a non-negative number.
+ */
+ State(StateMachine& sm, int state_id) : sm_(sm), state_id_(state_id) {}
+
+ virtual ~State() = default;
+
+ /**
+ * Process an event.
+ * TODO: The arguments are wrong - used for backward compatibility.
+ * Will be replaced later.
+ *
+ * @param event the event type
+ * @param p_data the event data
+ * @return true if the processing was completed, otherwise false
+ */
+ virtual bool ProcessEvent(uint32_t event, void* p_data) = 0;
+
+ /**
+ * Get the State ID.
+ *
+ * @return the State ID
+ */
+ int StateId() const { return state_id_; }
+
+ protected:
+ /**
+ * Called when a state is entered.
+ */
+ virtual void OnEnter() {}
+
+ /**
+ * Called when a state is exited.
+ */
+ virtual void OnExit() {}
+
+ /**
+ * Transition the State Machine to a new state.
+ *
+ * @param dest_state_id the state ID to transition to. It must be one
+ * of the unique state IDs when the corresponding state was created.
+ */
+ void TransitionTo(int dest_state_id) { sm_.TransitionTo(dest_state_id); }
+
+ /**
+ * Transition the State Machine to a new state.
+ *
+ * @param dest_state the state to transition to. It cannot be nullptr.
+ */
+ void TransitionTo(StateMachine::State* dest_state) {
+ sm_.TransitionTo(dest_state);
+ }
+
+ private:
+ StateMachine& sm_;
+ int state_id_;
+ };
+
+ StateMachine()
+ : initial_state_(nullptr),
+ previous_state_(nullptr),
+ current_state_(nullptr) {}
+ ~StateMachine() {
+ for (auto& kv : states_) delete kv.second;
+ }
+
+ /**
+ * Start the State Machine operation.
+ */
+ void Start() { TransitionTo(initial_state_); }
+
+ /**
+ * Quit the State Machine operation.
+ */
+ void Quit() { previous_state_ = current_state_ = nullptr; }
+
+ /**
+ * Get the current State ID.
+ *
+ * @return the current State ID
+ */
+ int StateId() const {
+ if (current_state_ != nullptr) {
+ return current_state_->StateId();
+ }
+ return kStateInvalid;
+ }
+
+ /**
+ * Get the previous current State ID.
+ *
+ * @return the previous State ID
+ */
+ int PreviousStateId() const {
+ if (previous_state_ != nullptr) {
+ return previous_state_->StateId();
+ }
+ return kStateInvalid;
+ }
+
+ /**
+ * Process an event.
+ * TODO: The arguments are wrong - used for backward compatibility.
+ * Will be replaced later.
+ *
+ * @param event the event type
+ * @param p_data the event data
+ * @return true if the processing was completed, otherwise false
+ */
+ bool ProcessEvent(uint32_t event, void* p_data) {
+ if (current_state_ == nullptr) return false;
+ return current_state_->ProcessEvent(event, p_data);
+ }
+
+ /**
+ * Transition the State Machine to a new state.
+ *
+ * @param dest_state_id the state ID to transition to. It must be one
+ * of the unique state IDs when the corresponding state was created.
+ */
+ void TransitionTo(int dest_state_id) {
+ auto it = states_.find(dest_state_id);
+
+ CHECK(it != states_.end()) << "Unknown State ID: " << dest_state_id;
+ State* dest_state = it->second;
+ TransitionTo(dest_state);
+ }
+
+ /**
+ * Transition the State Machine to a new state.
+ *
+ * @param dest_state the state to transition to. It cannot be nullptr.
+ */
+ void TransitionTo(StateMachine::State* dest_state) {
+ if (current_state_ != nullptr) {
+ current_state_->OnExit();
+ }
+ previous_state_ = current_state_;
+ current_state_ = dest_state;
+ current_state_->OnEnter();
+ }
+
+ /**
+ * Add a state to the State Machine.
+ * The state machine takes ownership on the state - i.e., the state will
+ * be deleted by the State Machine itself.
+ *
+ * @param state the state to add
+ */
+ void AddState(State* state) {
+ states_.insert(std::make_pair(state->StateId(), state));
+ }
+
+ /**
+ * Set the initial state of the State Machine.
+ *
+ * @param initial_state the initial state
+ */
+ void SetInitialState(State* initial_state) { initial_state_ = initial_state; }
+
+ private:
+ State* initial_state_;
+ State* previous_state_;
+ State* current_state_;
+ std::map<int, State*> states_;
+};
+
+} // namespace common
+
+} // namespace bluetooth
diff --git a/common/state_machine_unittest.cc b/common/state_machine_unittest.cc
new file mode 100644
index 0000000..896e983
--- /dev/null
+++ b/common/state_machine_unittest.cc
@@ -0,0 +1,263 @@
+/******************************************************************************
+ *
+ * Copyright 2017 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 <gtest/gtest.h>
+
+#include "common/state_machine.h"
+
+using bluetooth::common::StateMachine;
+
+namespace {
+static constexpr uint32_t kInvalidEvent = 0xffffffff;
+static constexpr uint32_t kEventZero = 0;
+static constexpr uint32_t kEventOne = 1;
+static constexpr uint32_t kEventTwo = 2;
+
+static char dataZero = 0;
+static char dataOne = 1;
+static char dataTwo = 2;
+} // namespace
+
+class StateMachineImpl : public StateMachine {
+ public:
+ enum {
+ kStateZero,
+ kStateOne,
+ kStateTwo,
+ };
+
+ class StateZero : public State {
+ public:
+ StateZero(StateMachine& sm)
+ : State(sm, kStateZero),
+ on_enter_(false),
+ on_exit_(false),
+ event_(kInvalidEvent),
+ data_(nullptr) {}
+ void OnEnter() override {
+ on_enter_ = true;
+ on_exit_ = false;
+ }
+ void OnExit() override {
+ on_exit_ = true;
+ on_enter_ = false;
+ }
+ bool ProcessEvent(uint32_t event, void* p_data) override {
+ event_ = event;
+ data_ = p_data;
+ TransitionTo(kStateOne);
+ return true;
+ }
+
+ bool on_enter_;
+ bool on_exit_;
+ uint32_t event_;
+ void* data_;
+ };
+
+ class StateOne : public State {
+ public:
+ StateOne(StateMachine& sm)
+ : State(sm, kStateOne),
+ on_enter_(false),
+ on_exit_(false),
+ event_(kInvalidEvent),
+ data_(nullptr) {}
+ void OnEnter() override {
+ on_enter_ = true;
+ on_exit_ = false;
+ }
+ void OnExit() override {
+ on_exit_ = true;
+ on_enter_ = false;
+ }
+ bool ProcessEvent(uint32_t event, void* p_data) override {
+ event_ = event;
+ data_ = p_data;
+ TransitionTo(kStateTwo);
+ return true;
+ }
+
+ bool on_enter_;
+ bool on_exit_;
+ uint32_t event_;
+ void* data_;
+ };
+
+ class StateTwo : public State {
+ public:
+ StateTwo(StateMachine& sm)
+ : State(sm, kStateTwo),
+ on_enter_(false),
+ on_exit_(false),
+ event_(kInvalidEvent),
+ data_(nullptr) {}
+ void OnEnter() override {
+ on_enter_ = true;
+ on_exit_ = false;
+ }
+ void OnExit() override {
+ on_exit_ = true;
+ on_enter_ = false;
+ }
+ bool ProcessEvent(uint32_t event, void* p_data) override {
+ event_ = event;
+ data_ = p_data;
+ TransitionTo(kStateZero);
+ return true;
+ }
+
+ bool on_enter_;
+ bool on_exit_;
+ uint32_t event_;
+ void* data_;
+ };
+
+ StateMachineImpl() {
+ state_zero_ = new StateZero(*this);
+ state_one_ = new StateOne(*this);
+ state_two_ = new StateTwo(*this);
+
+ AddState(state_zero_);
+ AddState(state_one_);
+ AddState(state_two_);
+ SetInitialState(state_zero_);
+ }
+
+ StateZero* state_zero_;
+ StateOne* state_one_;
+ StateTwo* state_two_;
+};
+
+class StateMachineTest : public ::testing::Test {
+ protected:
+ StateMachineTest() {}
+
+ void SetUp() override { sm_.Start(); }
+
+ void TearDown() override { sm_.Quit(); }
+
+ StateMachineImpl sm_;
+};
+
+TEST_F(StateMachineTest, test_initial_state) {
+ ASSERT_EQ(sm_.kStateZero, sm_.StateId());
+ ASSERT_EQ(sm_.kStateInvalid, sm_.PreviousStateId());
+}
+
+TEST_F(StateMachineTest, test_invalid_state) {
+ sm_.Quit();
+ ASSERT_EQ(sm_.kStateInvalid, sm_.StateId());
+ ASSERT_EQ(sm_.kStateInvalid, sm_.PreviousStateId());
+ sm_.Start();
+ ASSERT_EQ(sm_.kStateZero, sm_.StateId());
+ ASSERT_EQ(sm_.kStateInvalid, sm_.PreviousStateId());
+}
+
+TEST_F(StateMachineTest, test_transition_to) {
+ // Initial state: StateZero
+ ASSERT_EQ(sm_.kStateZero, sm_.StateId());
+ ASSERT_EQ(sm_.kStateInvalid, sm_.PreviousStateId());
+ ASSERT_TRUE(sm_.state_zero_->on_enter_);
+ ASSERT_FALSE(sm_.state_zero_->on_exit_);
+
+ // Transition to StateOne
+ ASSERT_FALSE(sm_.state_one_->on_enter_);
+ ASSERT_FALSE(sm_.state_one_->on_exit_);
+ sm_.TransitionTo(sm_.kStateOne);
+ ASSERT_EQ(sm_.kStateOne, sm_.StateId());
+ ASSERT_EQ(sm_.kStateZero, sm_.PreviousStateId());
+ ASSERT_TRUE(sm_.state_zero_->on_exit_);
+ ASSERT_TRUE(sm_.state_one_->on_enter_);
+ ASSERT_FALSE(sm_.state_one_->on_exit_);
+
+ // Transition to StateTwo
+ ASSERT_FALSE(sm_.state_two_->on_enter_);
+ ASSERT_FALSE(sm_.state_two_->on_exit_);
+ sm_.TransitionTo(sm_.kStateTwo);
+ ASSERT_EQ(sm_.kStateTwo, sm_.StateId());
+ ASSERT_EQ(sm_.kStateOne, sm_.PreviousStateId());
+ ASSERT_TRUE(sm_.state_one_->on_exit_);
+ ASSERT_TRUE(sm_.state_two_->on_enter_);
+ ASSERT_FALSE(sm_.state_two_->on_exit_);
+}
+
+TEST_F(StateMachineTest, test_process_event) {
+ // Initial state: StateZero
+ ASSERT_EQ(sm_.kStateZero, sm_.StateId());
+ ASSERT_EQ(sm_.kStateInvalid, sm_.PreviousStateId());
+ ASSERT_TRUE(sm_.state_zero_->on_enter_);
+ ASSERT_FALSE(sm_.state_zero_->on_exit_);
+ ASSERT_EQ(sm_.state_zero_->event_, kInvalidEvent);
+ ASSERT_EQ(sm_.state_zero_->data_, nullptr);
+
+ // Process an event and transition to StateOne
+ ASSERT_FALSE(sm_.state_one_->on_enter_);
+ ASSERT_FALSE(sm_.state_one_->on_exit_);
+ ASSERT_EQ(sm_.state_one_->event_, kInvalidEvent);
+ ASSERT_EQ(sm_.state_one_->data_, nullptr);
+ ASSERT_TRUE(sm_.ProcessEvent(kEventZero, &dataZero));
+ ASSERT_EQ(sm_.kStateOne, sm_.StateId());
+ ASSERT_EQ(sm_.kStateZero, sm_.PreviousStateId());
+ // Check StateZero
+ ASSERT_EQ(sm_.state_zero_->event_, kEventZero);
+ ASSERT_EQ(sm_.state_zero_->data_, &dataZero);
+ ASSERT_TRUE(sm_.state_zero_->on_exit_);
+ // Check StateOne
+ ASSERT_TRUE(sm_.state_one_->on_enter_);
+ ASSERT_FALSE(sm_.state_one_->on_exit_);
+ ASSERT_EQ(sm_.state_one_->event_, kInvalidEvent);
+ ASSERT_EQ(sm_.state_one_->data_, nullptr);
+
+ // Process an event and transition to StateTwo
+ ASSERT_FALSE(sm_.state_two_->on_enter_);
+ ASSERT_FALSE(sm_.state_two_->on_exit_);
+ ASSERT_EQ(sm_.state_two_->event_, kInvalidEvent);
+ ASSERT_EQ(sm_.state_two_->data_, nullptr);
+ ASSERT_TRUE(sm_.ProcessEvent(kEventOne, &dataOne));
+ ASSERT_EQ(sm_.kStateTwo, sm_.StateId());
+ ASSERT_EQ(sm_.kStateOne, sm_.PreviousStateId());
+ // Check StateOne
+ ASSERT_EQ(sm_.state_one_->event_, kEventOne);
+ ASSERT_EQ(sm_.state_one_->data_, &dataOne);
+ ASSERT_TRUE(sm_.state_one_->on_exit_);
+ // Check StateTwo
+ ASSERT_TRUE(sm_.state_two_->on_enter_);
+ ASSERT_FALSE(sm_.state_two_->on_exit_);
+ ASSERT_EQ(sm_.state_two_->event_, kInvalidEvent);
+ ASSERT_EQ(sm_.state_two_->data_, nullptr);
+
+ // Process an event and transition to StateZero
+ // NOTE: StateZero was exited before and has local state
+ ASSERT_FALSE(sm_.state_zero_->on_enter_);
+ ASSERT_TRUE(sm_.state_zero_->on_exit_); // NOTE: already exited before
+ ASSERT_EQ(sm_.state_zero_->event_, kEventZero); // NOTE: state from before
+ ASSERT_EQ(sm_.state_zero_->data_, &dataZero); // NOTE: state from before
+ ASSERT_TRUE(sm_.ProcessEvent(kEventTwo, &dataTwo));
+ ASSERT_EQ(sm_.kStateZero, sm_.StateId());
+ ASSERT_EQ(sm_.kStateTwo, sm_.PreviousStateId());
+ // Check StateTwo
+ ASSERT_EQ(sm_.state_two_->event_, kEventTwo);
+ ASSERT_EQ(sm_.state_two_->data_, &dataTwo);
+ ASSERT_TRUE(sm_.state_two_->on_exit_);
+ // Check StateZero
+ ASSERT_TRUE(sm_.state_zero_->on_enter_);
+ ASSERT_FALSE(sm_.state_zero_->on_exit_);
+ ASSERT_EQ(sm_.state_zero_->event_, kEventZero); // NOTE: state from before
+ ASSERT_EQ(sm_.state_zero_->data_, &dataZero); // NOTE: state from before
+}
diff --git a/common/test/thread_performance_test.cc b/common/test/thread_performance_test.cc
new file mode 100644
index 0000000..4c38fed
--- /dev/null
+++ b/common/test/thread_performance_test.cc
@@ -0,0 +1,369 @@
+/*
+ * Copyright 2018 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/bind.h>
+#include <base/logging.h>
+#include <base/run_loop.h>
+#include <base/threading/thread.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <unistd.h>
+#include <chrono>
+#include <future>
+#include <iostream>
+#include <thread>
+
+#include "common/message_loop_thread.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/thread.h"
+
+using bluetooth::common::MessageLoopThread;
+
+#define NUM_MESSAGES_TO_SEND 100000
+
+volatile static int g_counter = 0;
+static std::unique_ptr<std::promise<void>> g_counter_promise = nullptr;
+
+void callback_batch(fixed_queue_t* queue, void* data) {
+ if (queue != nullptr) {
+ fixed_queue_dequeue(queue);
+ }
+ g_counter++;
+ if (g_counter >= NUM_MESSAGES_TO_SEND) {
+ g_counter_promise->set_value();
+ }
+}
+
+class PerformanceTest : public testing::Test {
+ protected:
+ void SetUp() override {
+ set_up_promise_ = std::make_unique<std::promise<void>>();
+ g_counter = 0;
+ bt_msg_queue_ = fixed_queue_new(SIZE_MAX);
+ }
+ void TearDown() override {
+ fixed_queue_free(bt_msg_queue_, nullptr);
+ bt_msg_queue_ = nullptr;
+ set_up_promise_.reset(nullptr);
+ g_counter_promise.reset(nullptr);
+ }
+ fixed_queue_t* bt_msg_queue_ = nullptr;
+ std::unique_ptr<std::promise<void>> set_up_promise_ = nullptr;
+};
+
+class MessageLoopPerformanceTest : public PerformanceTest {
+ public:
+ static void RunThread(void* context) {
+ auto test = static_cast<MessageLoopPerformanceTest*>(context);
+ test->RunMessageLoop();
+ }
+ static void* RunPThread(void* context) {
+ auto test = static_cast<MessageLoopPerformanceTest*>(context);
+ test->RunMessageLoop();
+ return nullptr;
+ }
+ void RunMessageLoop() {
+ message_loop_ = new base::MessageLoop();
+ run_loop_ = new base::RunLoop();
+ message_loop_->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&std::promise<void>::set_value,
+ base::Unretained(set_up_promise_.get())));
+ run_loop_->Run();
+ delete message_loop_;
+ message_loop_ = nullptr;
+ delete run_loop_;
+ run_loop_ = nullptr;
+ }
+
+ protected:
+ base::MessageLoop* message_loop_ = nullptr;
+ base::RunLoop* run_loop_ = nullptr;
+};
+
+class OsiThreadMessageLoopPerformanceTest : public MessageLoopPerformanceTest {
+ protected:
+ void SetUp() override {
+ MessageLoopPerformanceTest::SetUp();
+ std::future<void> set_up_future = set_up_promise_->get_future();
+ thread_ = thread_new("OsiThreadMessageLoopPerformanceTest thread");
+ thread_post(thread_, &MessageLoopPerformanceTest::RunThread, this);
+ set_up_future.wait();
+ }
+
+ void TearDown() override {
+ message_loop_->task_runner()->PostTask(FROM_HERE,
+ run_loop_->QuitWhenIdleClosure());
+ thread_free(thread_);
+ thread_ = nullptr;
+ MessageLoopPerformanceTest::TearDown();
+ }
+
+ thread_t* thread_ = nullptr;
+};
+
+TEST_F(OsiThreadMessageLoopPerformanceTest, message_loop_speed_test) {
+ g_counter = 0;
+ g_counter_promise = std::make_unique<std::promise<void>>();
+ std::future<void> counter_future = g_counter_promise->get_future();
+ std::chrono::steady_clock::time_point start_time =
+ std::chrono::steady_clock::now();
+
+ for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
+ fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
+ message_loop_->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&callback_batch, bt_msg_queue_, nullptr));
+ }
+ counter_future.wait();
+
+ std::chrono::steady_clock::time_point end_time =
+ std::chrono::steady_clock::now();
+ std::chrono::milliseconds duration =
+ std::chrono::duration_cast<std::chrono::milliseconds>(end_time -
+ start_time);
+
+ LOG(INFO) << "OsiThreadMessageLoopPerformanceTest, " << duration.count()
+ << " ms, " << NUM_MESSAGES_TO_SEND << " messages";
+}
+
+class StlThreadMessageLoopPerformanceTest : public MessageLoopPerformanceTest {
+ protected:
+ void SetUp() override {
+ MessageLoopPerformanceTest::SetUp();
+ std::future<void> set_up_future = set_up_promise_->get_future();
+ thread_ = new std::thread(&MessageLoopPerformanceTest::RunThread, this);
+ set_up_future.wait();
+ }
+
+ void TearDown() override {
+ message_loop_->task_runner()->PostTask(FROM_HERE,
+ run_loop_->QuitWhenIdleClosure());
+ thread_->join();
+ delete thread_;
+ thread_ = nullptr;
+ MessageLoopPerformanceTest::TearDown();
+ }
+
+ std::thread* thread_ = nullptr;
+};
+
+TEST_F(StlThreadMessageLoopPerformanceTest, stl_thread_speed_test) {
+ g_counter = 0;
+ g_counter_promise = std::make_unique<std::promise<void>>();
+ std::future<void> counter_future = g_counter_promise->get_future();
+ std::chrono::steady_clock::time_point start_time =
+ std::chrono::steady_clock::now();
+
+ for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
+ fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
+ message_loop_->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&callback_batch, bt_msg_queue_, nullptr));
+ }
+ counter_future.wait();
+
+ std::chrono::steady_clock::time_point end_time =
+ std::chrono::steady_clock::now();
+ std::chrono::milliseconds duration =
+ std::chrono::duration_cast<std::chrono::milliseconds>(end_time -
+ start_time);
+
+ LOG(INFO) << "StlThreadMessageLoopPerformanceTest, " << duration.count()
+ << " ms, " << NUM_MESSAGES_TO_SEND << " messages";
+}
+
+class PosixThreadMessageLoopPerformanceTest
+ : public MessageLoopPerformanceTest {
+ protected:
+ void SetUp() override {
+ MessageLoopPerformanceTest::SetUp();
+ std::future<void> set_up_future = set_up_promise_->get_future();
+ pthread_create(&thread_, nullptr, &MessageLoopPerformanceTest::RunPThread,
+ (void*)this);
+ set_up_future.wait();
+ }
+
+ void TearDown() override {
+ message_loop_->task_runner()->PostTask(FROM_HERE,
+ run_loop_->QuitWhenIdleClosure());
+ pthread_join(thread_, nullptr);
+ MessageLoopPerformanceTest::TearDown();
+ }
+
+ pthread_t thread_ = -1;
+};
+
+TEST_F(PosixThreadMessageLoopPerformanceTest, stl_thread_speed_test) {
+ g_counter = 0;
+ g_counter_promise = std::make_unique<std::promise<void>>();
+ std::future<void> counter_future = g_counter_promise->get_future();
+
+ std::chrono::steady_clock::time_point start_time =
+ std::chrono::steady_clock::now();
+
+ for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
+ fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
+ message_loop_->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&callback_batch, bt_msg_queue_, nullptr));
+ }
+ counter_future.wait();
+
+ std::chrono::steady_clock::time_point end_time =
+ std::chrono::steady_clock::now();
+ std::chrono::milliseconds duration =
+ std::chrono::duration_cast<std::chrono::milliseconds>(end_time -
+ start_time);
+
+ LOG(INFO) << "PosixThreadMessageLoopPerformanceTest, " << duration.count()
+ << " ms, " << NUM_MESSAGES_TO_SEND << " messages";
+}
+
+class ReactorPerformanceTest : public PerformanceTest {
+ protected:
+ void SetUp() override {
+ PerformanceTest::SetUp();
+ thread_ = thread_new("ReactorPerformanceTest thread");
+ }
+
+ void TearDown() override {
+ thread_free(thread_);
+ thread_ = nullptr;
+ PerformanceTest::TearDown();
+ }
+
+ thread_t* thread_ = nullptr;
+};
+
+TEST_F(ReactorPerformanceTest, reactor_thread_speed_test) {
+ g_counter = 0;
+ g_counter_promise = std::make_unique<std::promise<void>>();
+ std::future<void> counter_future = g_counter_promise->get_future();
+ fixed_queue_register_dequeue(bt_msg_queue_, thread_get_reactor(thread_),
+ callback_batch, nullptr);
+
+ std::chrono::steady_clock::time_point start_time =
+ std::chrono::steady_clock::now();
+
+ for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
+ fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
+ }
+ counter_future.wait();
+
+ std::chrono::steady_clock::time_point end_time =
+ std::chrono::steady_clock::now();
+ std::chrono::milliseconds duration =
+ std::chrono::duration_cast<std::chrono::milliseconds>(end_time -
+ start_time);
+ fixed_queue_unregister_dequeue(bt_msg_queue_);
+
+ LOG(INFO) << "ReactorPerformanceTest, " << duration.count() << " ms, "
+ << NUM_MESSAGES_TO_SEND << " messages";
+}
+
+class WorkerThreadPerformanceTest : public PerformanceTest {
+ protected:
+ void SetUp() override {
+ PerformanceTest::SetUp();
+ std::future<void> set_up_future = set_up_promise_->get_future();
+ worker_thread_ =
+ new MessageLoopThread("WorkerThreadPerformanceTest thread");
+ worker_thread_->StartUp();
+ worker_thread_->DoInThread(
+ FROM_HERE, base::Bind(&std::promise<void>::set_value,
+ base::Unretained(set_up_promise_.get())));
+ set_up_future.wait();
+ }
+
+ void TearDown() override {
+ worker_thread_->ShutDown();
+ delete worker_thread_;
+ worker_thread_ = nullptr;
+ PerformanceTest::TearDown();
+ }
+
+ MessageLoopThread* worker_thread_ = nullptr;
+};
+
+TEST_F(WorkerThreadPerformanceTest, worker_thread_speed_test) {
+ g_counter = 0;
+ g_counter_promise = std::make_unique<std::promise<void>>();
+ std::future<void> counter_future = g_counter_promise->get_future();
+
+ std::chrono::steady_clock::time_point start_time =
+ std::chrono::steady_clock::now();
+
+ for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
+ fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
+ worker_thread_->DoInThread(
+ FROM_HERE, base::Bind(&callback_batch, bt_msg_queue_, nullptr));
+ }
+ counter_future.wait();
+
+ std::chrono::steady_clock::time_point end_time =
+ std::chrono::steady_clock::now();
+ std::chrono::milliseconds duration =
+ std::chrono::duration_cast<std::chrono::milliseconds>(end_time -
+ start_time);
+
+ LOG(INFO) << "WorkerThreadPerformanceTest, " << duration.count() << " ms, "
+ << NUM_MESSAGES_TO_SEND << " messages";
+}
+
+class LibChromeThreadPerformanceTest : public PerformanceTest {
+ protected:
+ void SetUp() override {
+ PerformanceTest::SetUp();
+ std::future<void> set_up_future = set_up_promise_->get_future();
+ thread_ = new base::Thread("LibChromeThreadPerformanceTest thread");
+ thread_->Start();
+ thread_->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&std::promise<void>::set_value,
+ base::Unretained(set_up_promise_.get())));
+ set_up_future.wait();
+ }
+
+ void TearDown() override {
+ thread_->Stop();
+ delete thread_;
+ thread_ = nullptr;
+ PerformanceTest::TearDown();
+ }
+
+ base::Thread* thread_ = nullptr;
+};
+
+TEST_F(LibChromeThreadPerformanceTest, worker_thread_speed_test) {
+ g_counter = 0;
+ g_counter_promise = std::make_unique<std::promise<void>>();
+ std::future<void> counter_future = g_counter_promise->get_future();
+
+ std::chrono::steady_clock::time_point start_time =
+ std::chrono::steady_clock::now();
+
+ for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
+ fixed_queue_enqueue(bt_msg_queue_, (void*)&g_counter);
+ thread_->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&callback_batch, bt_msg_queue_, nullptr));
+ }
+ counter_future.wait();
+
+ std::chrono::steady_clock::time_point end_time =
+ std::chrono::steady_clock::now();
+ std::chrono::milliseconds duration =
+ std::chrono::duration_cast<std::chrono::milliseconds>(end_time -
+ start_time);
+
+ LOG(INFO) << "LibChromeThreadPerformanceTest, " << duration.count() << " ms, "
+ << NUM_MESSAGES_TO_SEND << " messages";
+}
diff --git a/common/time_util.cc b/common/time_util.cc
new file mode 100644
index 0000000..273be18
--- /dev/null
+++ b/common/time_util.cc
@@ -0,0 +1,47 @@
+/******************************************************************************
+ *
+ * Copyright 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 <sys/time.h>
+#include <time.h>
+
+#include "common/time_util.h"
+
+namespace bluetooth {
+
+namespace common {
+
+uint64_t time_get_os_boottime_ms() { return time_get_os_boottime_us() / 1000; }
+
+uint64_t time_get_os_boottime_us() {
+ struct timespec ts_now = {};
+ clock_gettime(CLOCK_BOOTTIME, &ts_now);
+
+ return ((uint64_t)ts_now.tv_sec * 1000000L) +
+ ((uint64_t)ts_now.tv_nsec / 1000);
+}
+
+uint64_t time_gettimeofday_us() {
+ struct timeval tv = {};
+ gettimeofday(&tv, nullptr);
+ return static_cast<uint64_t>(tv.tv_sec) * 1000000ULL +
+ static_cast<uint64_t>(tv.tv_usec);
+}
+
+} // namespace common
+
+} // namespace bluetooth
\ No newline at end of file
diff --git a/common/time_util.h b/common/time_util.h
new file mode 100644
index 0000000..70a64d2
--- /dev/null
+++ b/common/time_util.h
@@ -0,0 +1,38 @@
+/******************************************************************************
+ *
+ * Copyright 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 <cstdint>
+
+namespace bluetooth {
+
+namespace common {
+
+// Get the OS boot time in milliseconds.
+uint64_t time_get_os_boottime_ms();
+
+// Get the OS boot time in microseconds.
+uint64_t time_get_os_boottime_us();
+
+// Get the current wall clock time in microseconds.
+uint64_t time_gettimeofday_us();
+
+} // namespace common
+
+} // namespace bluetooth
diff --git a/common/time_util_unittest.cc b/common/time_util_unittest.cc
new file mode 100644
index 0000000..77e205d
--- /dev/null
+++ b/common/time_util_unittest.cc
@@ -0,0 +1,146 @@
+/******************************************************************************
+ *
+ * Copyright 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 <gtest/gtest.h>
+
+#include "common/time_util.h"
+
+// Generous upper bound: 10 seconds
+static const uint32_t TEST_TIME_DELTA_UPPER_BOUND_MS = 10 * 1000;
+
+//
+// Test that the return value of bluetooth::common::time_get_os_boottime_ms() is
+// not zero.
+//
+TEST(TimeTest, test_time_get_os_boottime_ms_not_zero) {
+ uint64_t t1 = bluetooth::common::time_get_os_boottime_ms();
+ ASSERT_GT(t1, uint64_t(0));
+}
+
+//
+// Test that the return value of bluetooth::common::time_get_os_boottime_us() is
+// not zero.
+//
+TEST(TimeTest, test_time_get_os_boottime_us_not_zero) {
+ uint64_t t1 = bluetooth::common::time_get_os_boottime_us();
+ ASSERT_GT(t1, uint64_t(0));
+}
+
+//
+// Test that the return value of bluetooth::common::time_get_os_boottime_ms()
+// is monotonically increasing within reasonable boundries.
+//
+TEST(TimeTest, test_time_get_os_boottime_ms_increases_upper_bound) {
+ uint64_t t1 = bluetooth::common::time_get_os_boottime_ms();
+ uint64_t t2 = bluetooth::common::time_get_os_boottime_ms();
+ ASSERT_TRUE((t2 - t1) < TEST_TIME_DELTA_UPPER_BOUND_MS);
+}
+
+//
+// Test that the return value of bluetooth::common::time_get_os_boottime_us()
+// is monotonically increasing within reasonable boundries.
+//
+TEST(TimeTest, test_time_get_os_boottime_us_increases_upper_bound) {
+ uint64_t t1 = bluetooth::common::time_get_os_boottime_us();
+ uint64_t t2 = bluetooth::common::time_get_os_boottime_us();
+ ASSERT_TRUE((t2 - t1) < TEST_TIME_DELTA_UPPER_BOUND_MS * 1000);
+}
+
+//
+// Test that the return value of bluetooth::common::time_get_os_boottime_ms()
+// is increasing.
+//
+TEST(TimeTest, test_time_get_os_boottime_ms_increases_lower_bound) {
+ static const uint32_t TEST_TIME_SLEEP_MS = 100;
+ struct timespec delay = {};
+
+ delay.tv_sec = TEST_TIME_SLEEP_MS / 1000;
+ delay.tv_nsec = 1000 * 1000 * (TEST_TIME_SLEEP_MS % 1000);
+
+ // Take two timestamps with sleep in-between
+ uint64_t t1 = bluetooth::common::time_get_os_boottime_ms();
+ int err = nanosleep(&delay, &delay);
+ uint64_t t2 = bluetooth::common::time_get_os_boottime_ms();
+
+ ASSERT_EQ(err, 0);
+ ASSERT_TRUE((t2 - t1) >= TEST_TIME_SLEEP_MS);
+ ASSERT_TRUE((t2 - t1) < TEST_TIME_DELTA_UPPER_BOUND_MS);
+}
+
+//
+// Test that the return value of bluetooth::common::time_get_os_boottime_us()
+// is increasing.
+//
+TEST(TimeTest, test_time_get_os_boottime_us_increases_lower_bound) {
+ static const uint64_t TEST_TIME_SLEEP_US = 100 * 1000;
+ struct timespec delay = {};
+
+ delay.tv_sec = TEST_TIME_SLEEP_US / (1000 * 1000);
+ delay.tv_nsec = 1000 * (TEST_TIME_SLEEP_US % (1000 * 1000));
+
+ // Take two timestamps with sleep in-between
+ uint64_t t1 = bluetooth::common::time_get_os_boottime_us();
+ int err = nanosleep(&delay, &delay);
+ uint64_t t2 = bluetooth::common::time_get_os_boottime_us();
+
+ ASSERT_EQ(err, 0);
+ ASSERT_GT(t2, t1);
+ ASSERT_TRUE((t2 - t1) >= TEST_TIME_SLEEP_US);
+ ASSERT_TRUE((t2 - t1) < TEST_TIME_DELTA_UPPER_BOUND_MS * 1000);
+}
+
+//
+// Test that the return value of bluetooth::common::time_gettimeofday_us() is
+// not zero.
+//
+TEST(TimeTest, test_time_gettimeofday_us_not_zero) {
+ uint64_t t1 = bluetooth::common::time_gettimeofday_us();
+ ASSERT_GT(t1, uint64_t(0));
+}
+
+//
+// Test that the return value of bluetooth::common::time_gettimeofday_us()
+// is monotonically increasing within reasonable boundaries.
+//
+TEST(TimeTest, test_time_gettimeofday_us_increases_upper_bound) {
+ uint64_t t1 = bluetooth::common::time_gettimeofday_us();
+ uint64_t t2 = bluetooth::common::time_gettimeofday_us();
+ ASSERT_TRUE((t2 - t1) < TEST_TIME_DELTA_UPPER_BOUND_MS * 1000);
+}
+
+//
+// Test that the return value of bluetooth::common::time_gettimeofday_us()
+// is increasing.
+//
+TEST(TimeTest, test_time_gettimeofday_us_increases_lower_bound) {
+ static const uint64_t TEST_TIME_SLEEP_US = 100 * 1000;
+ struct timespec delay = {};
+
+ delay.tv_sec = TEST_TIME_SLEEP_US / (1000 * 1000);
+ delay.tv_nsec = 1000 * (TEST_TIME_SLEEP_US % (1000 * 1000));
+
+ // Take two timestamps with sleep in-between
+ uint64_t t1 = bluetooth::common::time_gettimeofday_us();
+ int err = nanosleep(&delay, &delay);
+ uint64_t t2 = bluetooth::common::time_gettimeofday_us();
+
+ ASSERT_EQ(err, 0);
+ ASSERT_GT(t2, t1);
+ ASSERT_TRUE((t2 - t1) >= TEST_TIME_SLEEP_US);
+ ASSERT_TRUE((t2 - t1) < TEST_TIME_DELTA_UPPER_BOUND_MS * 1000);
+}
diff --git a/common/utils.h b/common/utils.h
new file mode 100644
index 0000000..26e8f23
--- /dev/null
+++ b/common/utils.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2019 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
+
+// A macro to re-try a syscall when it receives EINTR
+#ifndef RUN_NO_INTR
+#define RUN_NO_INTR(fn) \
+ do { \
+ } while ((fn) == -1 && errno == EINTR)
+#endif
+
+// A macro to disallow the copy constructor and operator= functions
+#ifndef DISALLOW_COPY_AND_ASSIGN
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ TypeName(const TypeName&) = delete; \
+ void operator=(const TypeName&) = delete
+#endif
diff --git a/conf/Android.bp b/conf/Android.bp
new file mode 100644
index 0000000..ecf4922
--- /dev/null
+++ b/conf/Android.bp
@@ -0,0 +1,15 @@
+// Bluetooth bt_stack.conf config file
+// ========================================================
+prebuilt_etc {
+ name: "bt_stack.conf",
+ src: "bt_stack.conf",
+ sub_dir: "bluetooth",
+}
+
+// Bluetooth bt_did.conf config file
+// ========================================================
+prebuilt_etc {
+ name: "bt_did.conf",
+ src: "bt_did.conf",
+ sub_dir: "bluetooth",
+}
diff --git a/conf/Android.mk b/conf/Android.mk
deleted file mode 100644
index 6f5037c..0000000
--- a/conf/Android.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-# Cannot convert to Android.bp as resource copying has not
-# yet implemented for soong as of 12/16/2016
-LOCAL_PATH := $(call my-dir)
-
-# Bluetooth bt_stack.conf config file
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := bt_stack.conf
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/bluetooth
-LOCAL_MODULE_TAGS := optional
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-# Bluetooth bt_did.conf config file
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := bt_did.conf
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/bluetooth
-LOCAL_MODULE_TAGS := optional
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
diff --git a/device/AndroidTest.xml b/device/AndroidTest.xml
deleted file mode 100644
index 0960fb4..0000000
--- a/device/AndroidTest.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2017 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.
--->
-<configuration description="Config for net_test_device">
- <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
- <option name="cleanup" value="true" />
- <option name="push" value="net_test_device->/data/local/tmp/net_test_device" />
- </target_preparer>
- <option name="test-suite-tag" value="apct" />
- <test class="com.android.tradefed.testtype.GTest" >
- <option name="native-test-device-path" value="/data/local/tmp" />
- <option name="module-name" value="net_test_device" />
- </test>
-</configuration>
\ No newline at end of file
diff --git a/device/include/interop_database.h b/device/include/interop_database.h
index ad1bb5a..1fa2a4d 100644
--- a/device/include/interop_database.h
+++ b/device/include/interop_database.h
@@ -137,6 +137,12 @@
// Jeep Uconnect
{{{0x00, 0x54, 0xaf, 0, 0, 0}}, 3, INTEROP_DISABLE_ROLE_SWITCH},
+
+ // deepblue2 - cannot change smoothly the volume: b/37834035
+ {{{0x0c, 0xa6, 0x94, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+
+ // AirPods 2 - unacceptably loud volume
+ {{{0x94, 0x16, 0x25, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
};
typedef struct {
diff --git a/device/src/controller.cc b/device/src/controller.cc
index 02a3998..34c8afd 100644
--- a/device/src/controller.cc
+++ b/device/src/controller.cc
@@ -30,8 +30,15 @@
#include "osi/include/future.h"
#include "stack/include/btm_ble_api.h"
-const bt_event_mask_t BLE_EVENT_MASK = {
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1E, 0x7f}};
+const bt_event_mask_t BLE_EVENT_MASK = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+#if (BLE_PRIVACY_SPT == TRUE)
+ 0x1E,
+#else
+ /* Disable "LE Enhanced Connection
+ Complete" when privacy is off */
+ 0x1C,
+#endif
+ 0x7f}};
const bt_event_mask_t CLASSIC_EVENT_MASK = {HCI_DUMO_EVENT_MASK_EXT};
diff --git a/doc/power_management.md b/doc/power_management.md
index 2b90130..6803257 100644
--- a/doc/power_management.md
+++ b/doc/power_management.md
@@ -62,12 +62,12 @@
action that `bta_dm_pm_set_mode` will take, the connection will be removed
from `bta_dm_conn_srvcs` and no longer be considered for power management
decisions.
- - `BTA_DM_PM_SNIFF` through `BTA_DM_PM_SNIFF4` are special, in that each
+ - `BTA_DM_PM_SNIFF` through `BTA_DM_PM_SNIFF6` are special, in that each
level specifies a set of parameters for the SNIFF mode which relate to the
min and max intervals, the number of attempts and the timeout. The overall
action is still the same, however -- SNIFF mode is attempted. There are
definitions available up to SNIFF7, but actual SSR values are only defined
- up to SNIFF4. Params are defined in `bta_dm_ssr_spec`.
+ up to SNIFF6. Params are defined in `bta_dm_ssr_spec`.
- `BTA_DM_PM_ACTIVE` is full-on power.
- `BTA_DM_PM_RETRY` has the same effect as `BTA_DM_PM_NO_ACTION`, except a
timeout is possible to be set, which effectively allows a power operation to
diff --git a/doc/pts_guide.md b/doc/pts_guide.md
new file mode 100644
index 0000000..1e13b9d
--- /dev/null
+++ b/doc/pts_guide.md
@@ -0,0 +1,43 @@
+# Fluoride Bluetooth Profile Tuning Suite (PTS) Test Mode
+
+This document provides commands to enable PTS test mode for Fluoride stack. We
+need special handling for some test cases as they are not applicable for the
+Fluoride stack.
+
+## PTS Test Mode system property
+
+Profile services in packages/apps/Bluetooth uses system property
+`persist.bluetooth.pts` to check if the PTS test mode is enabled. To enable it:
+
+```sh
+adb shell setprop persist.bluetooth.pts true
+```
+
+To disable it:
+
+```sh
+adb shell setprop persist.bluetooth.pts false
+```
+
+### Current use case
+
+- In `newavrcp`, we send active player update to remote device only in PTS test
+ mode (AVRCP/TG/MPS/BV-05-C AVRCP/TG/MPS/BV-07-C).
+
+## PTS Helpers in stack config
+
+Native stack also requires some special handling, and the config is stored in
+`conf/bt_stack.conf`. To enable a flag, uncomment the corresponding line and
+push the config file to `/etc/bluetooth/` in IUT.
+
+### Current use case
+
+- `PTS_SecurePairOnly` enables secure connections only mode.
+- `PTS_DisableConnUpdates` disables LE Connection updates.
+- `PTS_DisableSDPOnLEPair` disables BR/EDR discovery after LE pairing to avoid
+ cross key derivation errors.
+- `PTS_SmpOptions` sets SMP Pair options (formatted as hex bytes) `auth, io,
+ ikey, rkey, ksize`.
+- `PTS_AvrcpTest` enables AVRCP test mode. The UID is set to 0xffffffffffffffff
+ in `TrackChangedNotificationResponse` (AVRCP/TG/NFY/BV-04-C).
+- `PTS_SmpFailureCase` enables handling for various SMP failure cases.
diff --git a/doc/supported_features.md b/doc/supported_features.md
index 60580e2..6063d91 100644
--- a/doc/supported_features.md
+++ b/doc/supported_features.md
@@ -15,6 +15,5 @@
AVDTP | 1.2 | Source, Initiator, Acceptor
BNEP | 1.0 |
GAVDP | 1.2 | Initiator, Acceptor
-MCAP | 1.0 | Sink
RFCOMM | 1.2 |
SPP | 1.2 | A, B
diff --git a/embdrv/g722/Android.bp b/embdrv/g722/Android.bp
index cc635d8..fbac145 100644
--- a/embdrv/g722/Android.bp
+++ b/embdrv/g722/Android.bp
@@ -1,12 +1,11 @@
-
cc_library_static {
name: "libg722codec",
defaults: ["fluoride_defaults"],
cflags: [
- "-DG722_SUPPORT_MALLOC"
+ "-DG722_SUPPORT_MALLOC",
],
srcs: [
"g722_decode.cc",
"g722_encode.cc",
],
-}
\ No newline at end of file
+}
diff --git a/embdrv/g722/BUILD.gn b/embdrv/g722/BUILD.gn
new file mode 100644
index 0000000..083e80b
--- /dev/null
+++ b/embdrv/g722/BUILD.gn
@@ -0,0 +1,22 @@
+#
+# Copyright 2018 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("g722") {
+ sources = [
+ "g722_decode.cc",
+ "g722_encode.cc",
+ ]
+}
diff --git a/gd/.clang-format b/gd/.clang-format
new file mode 100644
index 0000000..1f1f586
--- /dev/null
+++ b/gd/.clang-format
@@ -0,0 +1,28 @@
+#
+# Copyright 2016 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.
+#
+
+#
+# Below are some minor deviations from the default Google style to
+# accommodate for handling of the large legacy code base.
+#
+
+BasedOnStyle: Google
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+ColumnLimit: 120
+AllowShortFunctionsOnASingleLine: Empty
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+BreakConstructorInitializers: BeforeColon
diff --git a/gd/.gitignore b/gd/.gitignore
new file mode 100644
index 0000000..106fe1e
--- /dev/null
+++ b/gd/.gitignore
@@ -0,0 +1,2 @@
+**/default.profraw
+**/__pycache__/
diff --git a/gd/Android.bp b/gd/Android.bp
new file mode 100644
index 0000000..64c9291
--- /dev/null
+++ b/gd/Android.bp
@@ -0,0 +1,443 @@
+cc_defaults {
+ name: "gd_defaults",
+ target: {
+ android: {
+ test_config_template: "AndroidTestTemplate.xml",
+ cflags: [
+ "-DOS_ANDROID",
+ "-DOS_LINUX_GENERIC",
+ ],
+ shared_libs: [
+ "liblog",
+ ],
+ },
+ host: {
+ cflags: [
+ "-DOS_LINUX",
+ "-DOS_LINUX_GENERIC",
+ ],
+ },
+ darwin: {
+ enabled: false,
+ },
+ },
+ cpp_std: "c++17",
+ cflags: [
+ "-DEXPORT_SYMBOL=__attribute__((visibility(\"default\")))",
+ "-fvisibility=hidden",
+ "-DLOG_NDEBUG=1",
+ "-DGOOGLE_PROTOBUF_NO_RTTI",
+ "-Wno-unused-parameter",
+ "-Wno-implicit-fallthrough",
+ "-Wno-unused-result",
+ ],
+ conlyflags: [
+ "-std=c99",
+ ],
+ sanitize: {
+ misc_undefined: ["bounds"],
+ },
+}
+
+// Enables code coverage for a set of source files. Must be combined with
+// "clang_coverage_bin" in order to work. See //test/gen_coverage.py for more information
+// on generating code coverage.
+cc_defaults {
+ name: "gd_clang_file_coverage",
+ target: {
+ host: {
+ clang_cflags: [
+ "-fprofile-instr-generate",
+ "-fcoverage-mapping",
+
+ // New pass manager does not work with -fprofile-instr-generate yet.
+ // http://b/131132095
+ "-fno-experimental-new-pass-manager",
+ ],
+ },
+ },
+}
+
+// Enabled code coverage on a binary. These flags allow libraries that were
+// compiled with "clang_file_coverage" to be properly linked together in
+// order to create a binary that will create a profraw file when ran. Note
+// these flags themselves don't enable code coverage for the source files
+// compiled in the binary. See //test/gen_coverage.py for more information
+// on generating code coverage.
+cc_defaults {
+ name: "gd_clang_coverage_bin",
+ target: {
+ host: {
+ ldflags: [
+ "-fprofile-instr-generate",
+ "-fcoverage-mapping",
+
+ // New pass manager does not work with -fprofile-instr-generate yet.
+ // http://b/131132095
+ "-fno-experimental-new-pass-manager",
+ ],
+ },
+ },
+}
+
+cc_library {
+ name: "libbluetooth_gd",
+ defaults: [
+ "gd_defaults",
+ "gd_clang_file_coverage",
+ ],
+ host_supported: true,
+ target: {
+ linux: {
+ srcs: [
+ ":BluetoothOsSources_linux_generic",
+ ],
+ },
+ host: {
+ srcs: [
+ ":BluetoothHalSources_hci_rootcanal",
+ ],
+ },
+ android: {
+ srcs: [
+ ":BluetoothHalSources_hci_android_hidl",
+ ],
+ shared_libs: [
+ "android.hardware.bluetooth@1.0",
+ "libhwbinder",
+ "libhidlbase",
+ "libhidltransport",
+ "libutils",
+ ],
+ },
+ },
+ srcs: [
+ "stack_manager.cc",
+ "module.cc",
+ ":BluetoothCommonSources",
+ ":BluetoothCryptoToolboxSources",
+ ":BluetoothHalSources",
+ ":BluetoothHciSources",
+ ":BluetoothPacketSources",
+ ":BluetoothSmpSources",
+ ],
+ generated_headers: [
+ "BluetoothGeneratedPackets_h",
+ ],
+}
+
+cc_binary {
+ name: "stack_with_facade",
+ defaults: [
+ "gd_defaults",
+ ],
+ host_supported: true,
+ srcs: [
+ "facade/facade_main.cc",
+ "facade/grpc_root_server.cc",
+ "grpc/grpc_module.cc",
+ ":BluetoothFacade_hci_hal",
+ ],
+ generated_headers: [
+ "BluetoothGeneratedPackets_h",
+ "BluetoothFacadeGeneratedStub_h",
+ ],
+ generated_sources: [
+ "BluetoothFacadeGeneratedStub_cc",
+ ],
+ static_libs: [
+ "libbluetooth_gd",
+ ],
+ shared_libs: [
+ "libgrpc++_unsecure",
+ "libprotobuf-cpp-full",
+ ],
+ target: {
+ android: {
+ shared_libs: [
+ "android.hardware.bluetooth@1.0",
+ "libhwbinder",
+ "libhidlbase",
+ "libhidltransport",
+ "libutils",
+ ],
+ },
+ },
+ sanitize: {
+ address: true,
+ },
+}
+
+cc_binary {
+ name: "bluetooth_cert_stack",
+ defaults: [
+ "gd_defaults",
+ ],
+ host_supported: true,
+ srcs: [
+ "cert/cert_main.cc",
+ "cert/grpc_root_server.cc",
+ "grpc/grpc_module.cc",
+ ":BluetoothCertSource_hci_hal",
+ ],
+ generated_headers: [
+ "BluetoothGeneratedPackets_h",
+ "BluetoothCertStackGeneratedStub_h",
+ ],
+ generated_sources: [
+ "BluetoothCertStackGeneratedStub_cc",
+ ],
+ static_libs: [
+ "libbluetooth_gd",
+ ],
+ shared_libs: [
+ "libgrpc++_unsecure",
+ "libprotobuf-cpp-full",
+ ],
+ target: {
+ android: {
+ shared_libs: [
+ "android.hardware.bluetooth@1.0",
+ "libhwbinder",
+ "libhidlbase",
+ "libhidltransport",
+ "libutils",
+ ],
+ },
+ },
+ sanitize: {
+ address: true,
+ },
+}
+
+cc_test {
+ name: "bluetooth_test_gd",
+ test_suites: ["device-tests"],
+ defaults: [
+ "gd_defaults",
+ "gd_clang_coverage_bin",
+ ],
+ host_supported: true,
+ target: {
+ linux: {
+ srcs: [
+ ":BluetoothOsTestSources_linux_generic",
+ ],
+ },
+ host: {
+ srcs: [
+ ":BluetoothHalTestSources_hci_rootcanal",
+ ],
+ },
+ android: {
+ srcs: [
+ ":BluetoothHalTestSources_hci_android_hidl",
+ ],
+ shared_libs: [
+ "android.hardware.bluetooth@1.0",
+ "libhwbinder",
+ "libhidlbase",
+ "libhidltransport",
+ "libutils",
+ ],
+ },
+ },
+ srcs: [
+ "module_unittest.cc",
+ ":BluetoothCommonTestSources",
+ ":BluetoothCryptoToolboxTestSources",
+ ":BluetoothHciTestSources",
+ ":BluetoothL2capTestSources",
+ ":BluetoothPacketTestSources",
+ ":BluetoothSmpTestSources",
+ ],
+ generated_headers: [
+ "BluetoothGeneratedPackets_h",
+ ],
+ static_libs: [
+ "libbluetooth_gd",
+ ],
+ sanitize: {
+ address: true,
+ },
+}
+
+cc_test {
+ name: "bluetooth_packet_parser_test",
+ test_suites: ["device-tests"],
+ defaults: [
+ "gd_defaults",
+ "gd_clang_coverage_bin",
+ ],
+ host_supported: true,
+ srcs: [
+ ":BluetoothPacketSources",
+ ":BluetoothPacketParserTestPacketTestSources",
+ ],
+ generated_headers: [
+ "BluetoothPacketParserTestPacketPdlGen_h",
+ ],
+ sanitize: {
+ address: true,
+ cfi: true,
+ },
+}
+
+cc_benchmark {
+ name: "bluetooth_benchmark_gd",
+ defaults: ["gd_defaults"],
+ host_supported: true,
+ srcs: [
+ "benchmark.cc",
+ ":BluetoothOsBenchmarkSources",
+ ],
+ static_libs: [
+ "libbluetooth_gd",
+ ],
+}
+
+genrule {
+ name: "BluetoothGeneratedPackets_h",
+ tools: [
+ "bluetooth_packetgen",
+ ],
+ cmd: "$(location bluetooth_packetgen) --include=system/bt/gd --out=$(genDir) $(in)",
+ srcs: [
+ "hci/hci_packets.pdl",
+ "l2cap/l2cap_packets.pdl",
+ ],
+ out: [
+ "hci/hci_packets.h",
+ "l2cap/l2cap_packets.h",
+ ],
+}
+
+filegroup {
+ name: "BluetoothFacadeProto",
+ srcs: [
+ "facade/common.proto",
+ "facade/rootservice.proto",
+ "hal/facade.proto",
+ ],
+}
+
+genrule {
+ name: "BluetoothFacadeGeneratedStub_h",
+ tools: [
+ "aprotoc",
+ "protoc-gen-grpc-cpp-plugin",
+ ],
+ cmd: "$(location aprotoc) -Isystem/bt/gd -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+ srcs: [
+ ":BluetoothFacadeProto",
+ ],
+ out: [
+ "facade/common.grpc.pb.h",
+ "facade/common.pb.h",
+ "facade/rootservice.grpc.pb.h",
+ "facade/rootservice.pb.h",
+ "hal/facade.grpc.pb.h",
+ "hal/facade.pb.h",
+ ],
+}
+
+genrule {
+ name: "BluetoothFacadeGeneratedStub_cc",
+ tools: [
+ "aprotoc",
+ "protoc-gen-grpc-cpp-plugin",
+ ],
+ cmd: "$(location aprotoc) -Isystem/bt/gd -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+ srcs: [
+ ":BluetoothFacadeProto",
+ ],
+ out: [
+ "facade/common.grpc.pb.cc",
+ "facade/common.pb.cc",
+ "facade/rootservice.grpc.pb.cc",
+ "facade/rootservice.pb.cc",
+ "hal/facade.grpc.pb.cc",
+ "hal/facade.pb.cc",
+ ],
+}
+
+genrule {
+ name: "BluetoothFacadeAndCertGeneratedStub_py",
+ tools: [
+ "aprotoc",
+ "protoc-gen-grpc-python-plugin",
+ ],
+ cmd: "$(location aprotoc) -Isystem/bt/gd -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-python-plugin) $(in) --grpc_out=$(genDir) --python_out=$(genDir); " +
+ "touch $(genDir)/facade/__init__.py; " +
+ "touch $(genDir)/hal/__init__.py; " +
+ "touch $(genDir)/hal/cert/__init__.py; ",
+ srcs: [
+ ":BluetoothFacadeProto",
+ ":BluetoothCertStackProto",
+ ],
+ out: [
+ "cert/rootservice_pb2_grpc.py",
+ "cert/rootservice_pb2.py",
+ "facade/__init__.py",
+ "facade/common_pb2_grpc.py",
+ "facade/common_pb2.py",
+ "facade/rootservice_pb2_grpc.py",
+ "facade/rootservice_pb2.py",
+ "hal/__init__.py",
+ "hal/facade_pb2_grpc.py",
+ "hal/facade_pb2.py",
+ "hal/cert/__init__.py",
+ "hal/cert/api_pb2_grpc.py",
+ "hal/cert/api_pb2.py",
+ ],
+}
+
+filegroup {
+ name: "BluetoothCertStackProto",
+ srcs: [
+ "cert/rootservice.proto",
+ "hal/cert/api.proto",
+ ],
+}
+
+genrule {
+ name: "BluetoothCertStackGeneratedStub_h",
+ tools: [
+ "aprotoc",
+ "protoc-gen-grpc-cpp-plugin",
+ ],
+ cmd: "$(location aprotoc) -Isystem/bt/gd -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+ srcs: [
+ ":BluetoothCertStackProto",
+ ":BluetoothFacadeProto", // we need to use facade/common.proto
+ ],
+ out: [
+ "cert/rootservice.grpc.pb.h",
+ "cert/rootservice.pb.h",
+ "facade/common.grpc.pb.h",
+ "facade/common.pb.h",
+ "hal/cert/api.grpc.pb.h",
+ "hal/cert/api.pb.h",
+ ],
+}
+
+genrule {
+ name: "BluetoothCertStackGeneratedStub_cc",
+ tools: [
+ "aprotoc",
+ "protoc-gen-grpc-cpp-plugin",
+ ],
+ cmd: "$(location aprotoc) -Isystem/bt/gd -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+ srcs: [
+ ":BluetoothCertStackProto",
+ ":BluetoothFacadeProto", // we need to use facade/common.proto
+ ],
+ out: [
+ "cert/rootservice.grpc.pb.cc",
+ "cert/rootservice.pb.cc",
+ "facade/common.grpc.pb.cc",
+ "facade/common.pb.cc",
+ "hal/cert/api.grpc.pb.cc",
+ "hal/cert/api.pb.cc",
+ ],
+}
diff --git a/gd/AndroidTestTemplate.xml b/gd/AndroidTestTemplate.xml
new file mode 100644
index 0000000..601be93
--- /dev/null
+++ b/gd/AndroidTestTemplate.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2018 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.
+-->
+<configuration description="Runs {MODULE}.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="{MODULE}->/data/local/tmp/{MODULE}" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="settings put global ble_scan_always_enabled 0" />
+ <option name="run-command" value="svc bluetooth disable" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.FolderSaver">
+ <option name="device-path" value="/data/vendor/ssrdump" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="{MODULE}" />
+ <option name="run-test-as" value="0" />
+ </test>
+</configuration>
diff --git a/gd/TEST_MAPPING b/gd/TEST_MAPPING
new file mode 100644
index 0000000..f0ddeaf
--- /dev/null
+++ b/gd/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit" : [
+ {
+ "name" : "bluetooth_test_gd",
+ "host" : true
+ },
+ {
+ "name" : "bluetooth_packet_parser_test",
+ "host" : true
+ }
+ ]
+}
diff --git a/gd/benchmark.cc b/gd/benchmark.cc
new file mode 100644
index 0000000..2b11c89
--- /dev/null
+++ b/gd/benchmark.cc
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2019 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 <benchmark/benchmark.h>
+
+int main(int argc, char** argv) {
+ ::benchmark::Initialize(&argc, argv);
+ if (::benchmark::ReportUnrecognizedArguments(argc, argv)) {
+ return 1;
+ }
+ ::benchmark::RunSpecifiedBenchmarks();
+}
diff --git a/gd/cert/cert_main.cc b/gd/cert/cert_main.cc
new file mode 100644
index 0000000..623a45c
--- /dev/null
+++ b/gd/cert/cert_main.cc
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2019 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 "stack_manager.h"
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <csignal>
+#include <cstring>
+#include <string>
+#include <thread>
+
+#include "cert/grpc_root_server.h"
+#include "grpc/grpc_module.h"
+#include "hal/cert/cert.h"
+#include "hal/hci_hal.h"
+#include "hal/hci_hal_host_rootcanal.h"
+#include "hal/snoop_logger.h"
+
+using ::bluetooth::Module;
+using ::bluetooth::ModuleList;
+using ::bluetooth::StackManager;
+using ::bluetooth::grpc::GrpcModule;
+using ::bluetooth::os::Thread;
+
+namespace {
+::bluetooth::cert::GrpcRootServer grpc_root_server;
+
+void interrupt_handler(int) {
+ grpc_root_server.StopServer();
+}
+} // namespace
+
+int main(int argc, const char** argv) {
+ int root_server_port = 8897;
+ int grpc_port = 8899;
+
+ const std::string arg_grpc_root_server_port = "--root-server-port=";
+ const std::string arg_grpc_server_port = "--grpc-port=";
+ const std::string arg_rootcanal_port = "--rootcanal-port=";
+ const std::string arg_btsnoop_path = "--btsnoop=";
+ std::string btsnoop_path;
+ const std::string arg_tester_signal_socket = "--tester-signal-socket=";
+ std::string tester_signal_path;
+ for (int i = 1; i < argc; i++) {
+ std::string arg = argv[i];
+ if (arg.find(arg_grpc_root_server_port) == 0) {
+ auto port_number = arg.substr(arg_grpc_root_server_port.size());
+ root_server_port = std::stoi(port_number);
+ }
+ if (arg.find(arg_grpc_server_port) == 0) {
+ auto port_number = arg.substr(arg_grpc_server_port.size());
+ grpc_port = std::stoi(port_number);
+ }
+ if (arg.find(arg_rootcanal_port) == 0) {
+ auto port_number = arg.substr(arg_rootcanal_port.size());
+ ::bluetooth::hal::HciHalHostRootcanalConfig::Get()->SetPort(std::stoi(port_number));
+ }
+ if (arg.find(arg_btsnoop_path) == 0) {
+ btsnoop_path = arg.substr(arg_btsnoop_path.size());
+ ::bluetooth::hal::SnoopLogger::SetFilePath(btsnoop_path);
+ }
+ if (arg.find(arg_tester_signal_socket) == 0) {
+ tester_signal_path = arg.substr(arg_tester_signal_socket.size());
+ }
+ }
+
+ signal(SIGINT, interrupt_handler);
+ grpc_root_server.StartServer("0.0.0.0", root_server_port, grpc_port);
+ int tester_signal_socket = socket(AF_UNIX, SOCK_STREAM, 0);
+ struct sockaddr_un addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, tester_signal_path.c_str(), tester_signal_path.size() + 1);
+ connect(tester_signal_socket, (sockaddr*)&addr, sizeof(addr));
+ close(tester_signal_socket);
+ auto wait_thread = std::thread([] { grpc_root_server.RunGrpcLoop(); });
+ wait_thread.join();
+
+ return 0;
+}
diff --git a/gd/cert/cert_testcases b/gd/cert/cert_testcases
new file mode 100644
index 0000000..777be8e
--- /dev/null
+++ b/gd/cert/cert_testcases
@@ -0,0 +1 @@
+SimpleHalTest
diff --git a/gd/cert/event_stream.py b/gd/cert/event_stream.py
new file mode 100644
index 0000000..0342131
--- /dev/null
+++ b/gd/cert/event_stream.py
@@ -0,0 +1,115 @@
+#!/usr/bin/env python3
+#
+# Copyright 2019 - 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.
+
+from acts import asserts
+
+from facade import common_pb2
+from datetime import datetime
+from datetime import timedelta
+from grpc import RpcError
+from grpc import StatusCode
+
+class EventStream(object):
+
+ event_buffer = []
+
+ def __init__(self, stream_stub_fn):
+ self.stream_stub_fn = stream_stub_fn
+
+ def clear_event_buffer(self):
+ self.event_buffer.clear()
+
+ def subscribe(self):
+ return self.stream_stub_fn(
+ common_pb2.EventStreamRequest(
+ subscription_mode=common_pb2.SUBSCRIBE,
+ fetch_mode=common_pb2.NONE
+ )
+ )
+
+ def unsubscribe(self):
+ return self.stream_stub_fn(
+ common_pb2.EventStreamRequest(
+ subscription_mode=common_pb2.UNSUBSCRIBE,
+ fetch_mode=common_pb2.NONE
+ )
+ )
+
+ def assert_none(self):
+ response = self.stream_stub_fn(
+ common_pb2.EventStreamRequest(
+ subscription_mode=common_pb2.NONE,
+ fetch_mode=common_pb2.ALL_CURRENT
+ )
+ )
+
+ try:
+ for event in response:
+ self.event_buffer.append(event)
+ except RpcError:
+ pass
+
+ if len(self.event_buffer) != 0:
+ asserts.fail("event_buffer is not empty \n%s" % self.event_buffer)
+
+ def assert_none_matching(self, match_fn):
+ response = self.stream_stub_fn(
+ common_pb2.EventStreamRequest(
+ subscription_mode=common_pb2.NONE,
+ fetch_mode=common_pb2.ALL_CURRENT
+ )
+ )
+
+ try:
+ for event in response:
+ self.event_buffer.append(event)
+ except RpcError:
+ pass
+
+ for event in self.event_buffer:
+ if match_fn(event):
+ asserts.fail("event %s occurs" % event)
+
+ def assert_event_occurs(self, match_fn, timeout=timedelta(seconds=3)):
+ expiration_time = datetime.now() + timeout
+
+ while len(self.event_buffer):
+ element = self.event_buffer.pop(0)
+ if match_fn(element):
+ return
+
+ while (True):
+ if datetime.now() > expiration_time:
+ asserts.fail("timeout of %s exceeded" % str(timeout))
+
+ response = self.stream_stub_fn(
+ common_pb2.EventStreamRequest(
+ subscription_mode=common_pb2.NONE,
+ fetch_mode=common_pb2.AT_LEAST_ONE,
+ timeout_ms = int((expiration_time - datetime.now()).total_seconds() * 1000)
+ )
+ )
+
+ try:
+ for event in response:
+ if (match_fn(event)):
+ for remain_event in response:
+ self.event_buffer.append(remain_event)
+ return
+ except RpcError:
+ if response.code() == StatusCode.DEADLINE_EXCEEDED:
+ continue
+ raise
diff --git a/gd/cert/gd_base_test.py b/gd/cert/gd_base_test.py
new file mode 100644
index 0000000..af4becb
--- /dev/null
+++ b/gd/cert/gd_base_test.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python3
+#
+# Copyright 2019 - 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.
+
+from acts.base_test import BaseTestClass
+
+import importlib
+import logging
+import os
+import signal
+import sys
+import subprocess
+
+ANDROID_BUILD_TOP = os.environ.get('ANDROID_BUILD_TOP')
+
+sys.path.append(ANDROID_BUILD_TOP + '/out/soong/.intermediates/system/bt/gd/BluetoothFacadeAndCertGeneratedStub_py/gen')
+
+ANDROID_HOST_OUT = os.environ.get('ANDROID_HOST_OUT')
+ROOTCANAL = ANDROID_HOST_OUT + "/nativetest64/root-canal/root-canal"
+
+class GdBaseTestClass(BaseTestClass):
+ def __init__(self, configs):
+ BaseTestClass.__init__(self, configs)
+
+ log_path_base = configs.get('log_path', '/tmp/logs')
+ rootcanal_logpath = os.path.join(log_path_base, 'rootcanal_logs.txt')
+ self.rootcanal_logs = open(rootcanal_logpath, 'w')
+
+ rootcanal_config = configs["testbed_configs"]['rootcanal']
+ rootcanal_hci_port = str(rootcanal_config.get("hci_port", "6402"))
+ self.rootcanal_process = subprocess.Popen(
+ [
+ ROOTCANAL,
+ str(rootcanal_config.get("test_port", "6401")),
+ rootcanal_hci_port,
+ str(rootcanal_config.get("link_layer_port", "6403"))
+ ],
+ cwd=ANDROID_BUILD_TOP,
+ env=os.environ.copy(),
+ stdout=self.rootcanal_logs,
+ stderr=self.rootcanal_logs
+ )
+
+ gd_devices = self.testbed_configs.get("GdDevice")
+ for gd_device in gd_devices:
+ gd_device["rootcanal_port"] = rootcanal_hci_port
+ gd_cert_devices = self.testbed_configs.get("GdCertDevice")
+ for gd_cert_device in gd_cert_devices:
+ gd_cert_device["rootcanal_port"] = rootcanal_hci_port
+
+ self.register_controller(
+ importlib.import_module('cert.gd_device'),
+ builtin=True)
+ self.register_controller(
+ importlib.import_module('cert.gd_cert_device'),
+ builtin=True)
+
+ def teardown_class(self):
+ self.unregister_controllers()
+ self.rootcanal_process.send_signal(signal.SIGINT)
+ rootcanal_return_code = self.rootcanal_process.wait()
+ self.rootcanal_logs.close()
+ if rootcanal_return_code != 0 and rootcanal_return_code != -signal.SIGINT:
+ logging.error("rootcanal stopped with code: %d" %
+ rootcanal_return_code)
+ return False
diff --git a/gd/cert/gd_cert_device.py b/gd/cert/gd_cert_device.py
new file mode 100644
index 0000000..7a35bd4
--- /dev/null
+++ b/gd/cert/gd_cert_device.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python3
+#
+# Copyright 2019 - 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.
+
+from gd_device_base import GdDeviceBase
+from gd_device_base import replace_vars
+
+from cert import rootservice_pb2_grpc as cert_rootservice_pb2_grpc
+from hal.cert import api_pb2_grpc as hal_cert_pb2_grpc
+
+ACTS_CONTROLLER_CONFIG_NAME = "GdCertDevice"
+ACTS_CONTROLLER_REFERENCE_NAME = "gd_cert_devices"
+
+def create(configs):
+ if not configs:
+ raise GdDeviceConfigError("Configuration is empty")
+ elif not isinstance(configs, list):
+ raise GdDeviceConfigError("Configuration should be a list")
+ return get_instances_with_configs(configs)
+
+
+def destroy(devices):
+ for device in devices:
+ try:
+ device.clean_up()
+ except:
+ device.log.exception("Failed to clean up properly.")
+
+
+def get_info(devices):
+ return []
+
+
+def get_instances_with_configs(configs):
+ print(configs)
+ devices = []
+ for config in configs:
+ resolved_cmd = []
+ for entry in config["cmd"]:
+ resolved_cmd.append(replace_vars(entry, config))
+ devices.append(GdCertDevice(config["grpc_port"], config["grpc_root_server_port"], resolved_cmd, config["label"]))
+ return devices
+
+class GdCertDevice(GdDeviceBase):
+ def __init__(self, grpc_port, grpc_root_server_port, cmd, label):
+ super().__init__(grpc_port, grpc_root_server_port, cmd, label, ACTS_CONTROLLER_CONFIG_NAME)
+ self.rootservice = cert_rootservice_pb2_grpc.RootCertStub(self.grpc_root_server_channel)
+ self.hal = hal_cert_pb2_grpc.HciHalCertStub(self.grpc_channel)
+
diff --git a/gd/cert/gd_device.py b/gd/cert/gd_device.py
new file mode 100644
index 0000000..a306d20
--- /dev/null
+++ b/gd/cert/gd_device.py
@@ -0,0 +1,64 @@
+#!/usr/bin/env python3
+#
+# Copyright 2019 - 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.
+
+from gd_device_base import GdDeviceBase
+from gd_device_base import replace_vars
+
+from cert.event_stream import EventStream
+from facade import rootservice_pb2_grpc as facade_rootservice_pb2_grpc
+from hal import facade_pb2_grpc as hal_facade_pb2_grpc
+
+ACTS_CONTROLLER_CONFIG_NAME = "GdDevice"
+ACTS_CONTROLLER_REFERENCE_NAME = "gd_devices"
+
+def create(configs):
+ if not configs:
+ raise GdDeviceConfigError("Configuration is empty")
+ elif not isinstance(configs, list):
+ raise GdDeviceConfigError("Configuration should be a list")
+ return get_instances_with_configs(configs)
+
+
+def destroy(devices):
+ for device in devices:
+ try:
+ device.clean_up()
+ except:
+ device.log.exception("Failed to clean up properly.")
+
+
+def get_info(devices):
+ return []
+
+
+def get_instances_with_configs(configs):
+ print(configs)
+ devices = []
+ for config in configs:
+ resolved_cmd = []
+ for entry in config["cmd"]:
+ resolved_cmd.append(replace_vars(entry, config))
+ devices.append(GdDevice(config["grpc_port"], config["grpc_root_server_port"], resolved_cmd, config["label"]))
+ return devices
+
+class GdDevice(GdDeviceBase):
+ def __init__(self, grpc_port, grpc_root_server_port, cmd, label):
+ super().__init__(grpc_port, grpc_root_server_port, cmd, label, ACTS_CONTROLLER_CONFIG_NAME)
+ self.rootservice = facade_rootservice_pb2_grpc.RootFacadeStub(self.grpc_root_server_channel)
+ self.hal = hal_facade_pb2_grpc.HciHalFacadeStub(self.grpc_channel)
+ self.hal.hci_event_stream = EventStream(self.hal.FetchHciEvent)
+ self.hal.hci_acl_stream = EventStream(self.hal.FetchHciAcl)
+ self.hal.hci_sco_stream = EventStream(self.hal.FetchHciSco)
diff --git a/gd/cert/gd_device_base.py b/gd/cert/gd_device_base.py
new file mode 100644
index 0000000..938db1a
--- /dev/null
+++ b/gd/cert/gd_device_base.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python3
+#
+# Copyright 2019 - 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.
+
+import logging
+import os
+from builtins import open
+import signal
+import socket
+import subprocess
+import time
+
+from acts import error
+from acts import tracelogger
+
+import grpc
+
+ANDROID_BUILD_TOP = os.environ.get('ANDROID_BUILD_TOP')
+ANDROID_HOST_OUT = os.environ.get('ANDROID_HOST_OUT')
+
+def replace_vars(string, config):
+ return string.replace("$ANDROID_HOST_OUT", ANDROID_HOST_OUT) \
+ .replace("$(grpc_port)", config.get("grpc_port")) \
+ .replace("$(grpc_root_server_port)", config.get("grpc_root_server_port")) \
+ .replace("$(rootcanal_port)", config.get("rootcanal_port"))
+
+class GdDeviceBase:
+ def __init__(self, grpc_port, grpc_root_server_port, cmd, label, type_identifier):
+ self.label = label if label is not None else grpc_port
+ # logging.log_path only exists when this is used in an ACTS test run.
+ log_path_base = getattr(logging, 'log_path', '/tmp/logs')
+ self.log = tracelogger.TraceLogger(
+ GdDeviceBaseLoggerAdapter(logging.getLogger(), {
+ 'device': label,
+ 'type_identifier' : type_identifier
+ }))
+
+ backing_process_logpath = os.path.join(
+ log_path_base, '%s_%s_backing_logs.txt' % (type_identifier, label))
+ self.backing_process_logs = open(backing_process_logpath, 'w')
+
+ btsnoop_path = os.path.join(log_path_base, '%s_btsnoop_hci.log' % label)
+ cmd.append("--btsnoop=" + btsnoop_path)
+
+ tester_signal_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ socket_address = os.path.join(
+ log_path_base, '%s_socket' % type_identifier)
+ tester_signal_socket.bind(socket_address)
+ tester_signal_socket.listen(1)
+
+ cmd.append("--tester-signal-socket=" + socket_address)
+
+ self.backing_process = subprocess.Popen(
+ cmd,
+ cwd=ANDROID_BUILD_TOP,
+ env=os.environ.copy(),
+ stdout=self.backing_process_logs,
+ stderr=self.backing_process_logs)
+ tester_signal_socket.accept()
+ tester_signal_socket.close()
+
+ self.grpc_root_server_channel = grpc.insecure_channel("localhost:" + grpc_root_server_port)
+ self.grpc_port = int(grpc_port)
+ self.grpc_channel = grpc.insecure_channel("localhost:" + grpc_port)
+
+ def clean_up(self):
+ self.grpc_channel.close()
+ self.grpc_root_server_channel.close()
+ self.backing_process.send_signal(signal.SIGINT)
+ backing_process_return_code = self.backing_process.wait()
+ self.backing_process_logs.close()
+ if backing_process_return_code != 0:
+ logging.error("backing process stopped with code: %d" %
+ backing_process_return_code)
+ return False
+
+
+class GdDeviceBaseLoggerAdapter(logging.LoggerAdapter):
+ def process(self, msg, kwargs):
+ msg = "[%s|%s] %s" % (self.extra["type_identifier"], self.extra["device"], msg)
+ return (msg, kwargs)
+
+class GdDeviceConfigError(Exception):
+ """Raised when GdDevice configs are malformatted."""
+
+
+class GdDeviceError(error.ActsError):
+ """Raised when there is an error in GdDevice."""
+
diff --git a/gd/cert/grpc_root_server.cc b/gd/cert/grpc_root_server.cc
new file mode 100644
index 0000000..fdbf85a
--- /dev/null
+++ b/gd/cert/grpc_root_server.cc
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2019 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 "cert/grpc_root_server.h"
+
+#include <string>
+
+#include "cert/rootservice.grpc.pb.h"
+#include "grpc/grpc_module.h"
+#include "hal/cert/cert.h"
+#include "os/log.h"
+#include "os/thread.h"
+#include "stack_manager.h"
+
+namespace bluetooth {
+namespace cert {
+
+using ::bluetooth::grpc::GrpcModule;
+using ::bluetooth::os::Thread;
+
+namespace {
+class RootCertService : public ::bluetooth::cert::RootCert::Service {
+ public:
+ RootCertService(int grpc_port) : grpc_port_(grpc_port) {}
+
+ ::grpc::Status StartStack(::grpc::ServerContext* context, const ::bluetooth::cert::StartStackRequest* request,
+ ::bluetooth::cert::StartStackResponse* response) override {
+ if (is_running_) {
+ return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "stack is running");
+ }
+
+ ModuleList modules;
+ modules.add<::bluetooth::grpc::GrpcModule>();
+
+ BluetoothModule module_to_test = request->module_to_test();
+ switch (module_to_test) {
+ case BluetoothModule::HAL:
+ modules.add<::bluetooth::hal::cert::HalCertModule>();
+ break;
+ default:
+ return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "invalid module under test");
+ }
+
+ stack_thread_ = new Thread("stack_thread", Thread::Priority::NORMAL);
+ stack_manager_.StartUp(&modules, stack_thread_);
+
+ GrpcModule* grpc_module = stack_manager_.GetInstance<GrpcModule>();
+ grpc_module->StartServer("0.0.0.0", grpc_port_);
+
+ grpc_loop_thread_ = new std::thread([grpc_module] { grpc_module->RunGrpcLoop(); });
+ is_running_ = true;
+
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status StopStack(::grpc::ServerContext* context, const ::bluetooth::cert::StopStackRequest* request,
+ ::bluetooth::cert::StopStackResponse* response) override {
+ if (!is_running_) {
+ return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "stack is not running");
+ }
+
+ stack_manager_.GetInstance<GrpcModule>()->StopServer();
+ grpc_loop_thread_->join();
+
+ stack_manager_.ShutDown();
+ delete stack_thread_;
+ is_running_ = false;
+ return ::grpc::Status::OK;
+ }
+
+ private:
+ Thread* stack_thread_ = nullptr;
+ bool is_running_ = false;
+ std::thread* grpc_loop_thread_ = nullptr;
+ StackManager stack_manager_;
+ int grpc_port_ = 8898;
+};
+
+RootCertService* root_cert_service;
+} // namespace
+
+void GrpcRootServer::StartServer(const std::string& address, int grpc_root_server_port, int grpc_port) {
+ ASSERT(!started_);
+ started_ = true;
+
+ std::string listening_port = address + ":" + std::to_string(grpc_root_server_port);
+ ::grpc::ServerBuilder builder;
+ root_cert_service = new RootCertService(grpc_port);
+ builder.RegisterService(root_cert_service);
+ builder.AddListeningPort(listening_port, ::grpc::InsecureServerCredentials());
+ server_ = builder.BuildAndStart();
+
+ ASSERT(server_ != nullptr);
+}
+
+void GrpcRootServer::StopServer() {
+ ASSERT(started_);
+ server_->Shutdown();
+ started_ = false;
+ server_.reset();
+ delete root_cert_service;
+}
+
+void GrpcRootServer::RunGrpcLoop() {
+ ASSERT(started_);
+ server_->Wait();
+}
+
+} // namespace cert
+} // namespace bluetooth
diff --git a/gd/cert/grpc_root_server.h b/gd/cert/grpc_root_server.h
new file mode 100644
index 0000000..2ebfe79
--- /dev/null
+++ b/gd/cert/grpc_root_server.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2019 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 <memory>
+#include <string>
+
+#include <grpc++/grpc++.h>
+
+namespace bluetooth {
+namespace cert {
+
+class GrpcRootServer {
+ public:
+ void StartServer(const std::string& address, int grpc_root_server_port, int grpc_port);
+
+ void StopServer();
+
+ void RunGrpcLoop();
+
+ private:
+ bool started_ = false;
+ std::unique_ptr<::grpc::Server> server_ = nullptr;
+};
+
+} // namespace cert
+} // namespace bluetooth
diff --git a/gd/cert/host_only_config.json b/gd/cert/host_only_config.json
new file mode 100644
index 0000000..052685a
--- /dev/null
+++ b/gd/cert/host_only_config.json
@@ -0,0 +1,46 @@
+{ "_description": "Bluetooth cert testing",
+ "testbed":
+ [
+ {
+ "_description": "Host only cert testbed",
+ "name": "HostOnlyCert",
+ "rootcanal":
+ {
+ "test_port": 6401,
+ "hci_port": 6402,
+ "link_layer_port": 6403
+ },
+ "GdDevice":
+ [
+ {
+ "grpc_port": "8899",
+ "grpc_root_server_port": "8897",
+ "label": "stack_under_test",
+ "cmd":
+ [
+ "$ANDROID_HOST_OUT/bin/stack_with_facade",
+ "--grpc-port=$(grpc_port)",
+ "--root-server-port=$(grpc_root_server_port)",
+ "--rootcanal-port=$(rootcanal_port)"
+ ]
+ }
+ ],
+ "GdCertDevice":
+ [
+ {
+ "grpc_port": "8898",
+ "grpc_root_server_port": "8896",
+ "label": "cert_stack",
+ "cmd":
+ [
+ "$ANDROID_HOST_OUT/bin/bluetooth_cert_stack",
+ "--grpc-port=$(grpc_port)",
+ "--root-server-port=$(grpc_root_server_port)",
+ "--rootcanal-port=$(rootcanal_port)"
+ ]
+ }
+ ]
+ }
+ ],
+ "logpath": "/tmp/logs"
+}
diff --git a/gd/cert/rootservice.proto b/gd/cert/rootservice.proto
new file mode 100644
index 0000000..02bd078
--- /dev/null
+++ b/gd/cert/rootservice.proto
@@ -0,0 +1,25 @@
+syntax = "proto3";
+
+package bluetooth.cert;
+
+service RootCert {
+ rpc StartStack(StartStackRequest) returns (StartStackResponse) {}
+ rpc StopStack(StopStackRequest) returns (StopStackResponse) {}
+}
+
+enum BluetoothModule {
+ HAL = 0;
+ HCI = 1;
+ L2CAP = 2;
+ SECURITY = 3;
+}
+
+message StartStackRequest {
+ BluetoothModule module_to_test = 1;
+}
+
+message StartStackResponse {}
+
+message StopStackRequest {}
+
+message StopStackResponse {}
diff --git a/gd/cert/run_cert.sh b/gd/cert/run_cert.sh
new file mode 100755
index 0000000..81fe91e
--- /dev/null
+++ b/gd/cert/run_cert.sh
@@ -0,0 +1,3 @@
+#! /bin/bash
+
+act.py -c $ANDROID_BUILD_TOP/system/bt/gd/cert/host_only_config.json -tf $ANDROID_BUILD_TOP/system/bt/gd/cert/cert_testcases -tp $ANDROID_BUILD_TOP/system/bt/gd
diff --git a/gd/cert/set_up_acts.sh b/gd/cert/set_up_acts.sh
new file mode 100755
index 0000000..2d3ad3a
--- /dev/null
+++ b/gd/cert/set_up_acts.sh
@@ -0,0 +1,6 @@
+#! /bin/bash
+
+# for more info, see go/acts
+
+cd $ANDROID_BUILD_TOP/tools/test/connectivity/acts/framework/
+sudo python3 setup.py develop
diff --git a/gd/common/Android.bp b/gd/common/Android.bp
new file mode 100644
index 0000000..e9e0b25
--- /dev/null
+++ b/gd/common/Android.bp
@@ -0,0 +1,17 @@
+filegroup {
+ name: "BluetoothCommonSources",
+ srcs: [
+ "address.cc",
+ "class_of_device.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothCommonTestSources",
+ srcs: [
+ "address_unittest.cc",
+ "blocking_queue_unittest.cc",
+ "class_of_device_unittest.cc",
+ "bidi_queue_unittest.cc",
+ ],
+}
diff --git a/gd/common/address.cc b/gd/common/address.cc
new file mode 100644
index 0000000..cd8101a
--- /dev/null
+++ b/gd/common/address.cc
@@ -0,0 +1,92 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 "address.h"
+
+#include <stdint.h>
+#include <algorithm>
+#include <sstream>
+#include <vector>
+
+namespace bluetooth {
+namespace common {
+
+static_assert(sizeof(Address) == 6, "Address must be 6 bytes long!");
+
+const Address Address::kAny{{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}};
+const Address Address::kEmpty{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
+
+Address::Address(const uint8_t (&addr)[6]) {
+ std::copy(addr, addr + kLength, address);
+};
+
+std::string Address::ToString() const {
+ char buffer[] = "00:00:00:00:00:00";
+ std::snprintf(&buffer[0], sizeof(buffer),
+ "%02x:%02x:%02x:%02x:%02x:%02x", address[5], address[4], address[3], address[2], address[1], address[0]);
+ std::string str(buffer);
+ return str;
+}
+
+bool Address::FromString(const std::string& from, Address& to) {
+ Address new_addr;
+ if (from.length() != 17) {
+ return false;
+ }
+
+ std::istringstream stream(from);
+ std::string token;
+ int index = 0;
+ while (getline(stream, token, ':')) {
+ if (index >= 6) {
+ return false;
+ }
+
+ if (token.length() != 2) {
+ return false;
+ }
+
+ char* temp = nullptr;
+ new_addr.address[5 - index] = strtol(token.c_str(), &temp, 16);
+ if (*temp != '\0') {
+ return false;
+ }
+
+ index++;
+ }
+
+ if (index != 6) {
+ return false;
+ }
+
+ to = new_addr;
+ return true;
+}
+
+size_t Address::FromOctets(const uint8_t* from) {
+ std::copy(from, from + kLength, address);
+ return kLength;
+};
+
+bool Address::IsValidAddress(const std::string& address) {
+ Address tmp;
+ return Address::FromString(address, tmp);
+}
+
+} // namespace common
+} // namespace bluetooth
diff --git a/gd/common/address.h b/gd/common/address.h
new file mode 100644
index 0000000..0036a59
--- /dev/null
+++ b/gd/common/address.h
@@ -0,0 +1,81 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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>
+
+namespace bluetooth {
+namespace common {
+
+class Address final {
+ public:
+ static constexpr unsigned int kLength = 6;
+
+ uint8_t address[kLength];
+
+ Address() = default;
+ Address(const uint8_t (&addr)[6]);
+
+ bool operator<(const Address& rhs) const {
+ return (std::memcmp(address, rhs.address, sizeof(address)) < 0);
+ }
+ bool operator==(const Address& rhs) const {
+ return (std::memcmp(address, rhs.address, sizeof(address)) == 0);
+ }
+ bool operator>(const Address& rhs) const {
+ return (rhs < *this);
+ }
+ bool operator<=(const Address& rhs) const {
+ return !(*this > rhs);
+ }
+ bool operator>=(const Address& rhs) const {
+ return !(*this < rhs);
+ }
+ bool operator!=(const Address& rhs) const {
+ return !(*this == rhs);
+ }
+
+ bool IsEmpty() const {
+ return *this == kEmpty;
+ }
+
+ std::string ToString() const;
+
+ // Converts |string| to Address and places it in |to|. If |from| does
+ // not represent a Bluetooth address, |to| is not modified and this function
+ // returns false. Otherwise, it returns true.
+ static bool FromString(const std::string& from, Address& to);
+
+ // Copies |from| raw Bluetooth address octets to the local object.
+ // Returns the number of copied octets - should be always Address::kLength
+ size_t FromOctets(const uint8_t* from);
+
+ static bool IsValidAddress(const std::string& address);
+
+ static const Address kEmpty; // 00:00:00:00:00:00
+ static const Address kAny; // FF:FF:FF:FF:FF:FF
+};
+
+inline std::ostream& operator<<(std::ostream& os, const Address& a) {
+ os << a.ToString();
+ return os;
+}
+
+} // namespace common
+} // namespace bluetooth
diff --git a/gd/common/address_unittest.cc b/gd/common/address_unittest.cc
new file mode 100644
index 0000000..cdecce3
--- /dev/null
+++ b/gd/common/address_unittest.cc
@@ -0,0 +1,199 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 <gtest/gtest.h>
+
+#include "common/address.h"
+
+using bluetooth::common::Address;
+
+static const char* test_addr = "bc:9a:78:56:34:12";
+static const char* test_addr2 = "21:43:65:87:a9:cb";
+
+TEST(AddressUnittest, test_constructor_array) {
+ Address bdaddr({0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc});
+
+ ASSERT_EQ(0x12, bdaddr.address[0]);
+ ASSERT_EQ(0x34, bdaddr.address[1]);
+ ASSERT_EQ(0x56, bdaddr.address[2]);
+ ASSERT_EQ(0x78, bdaddr.address[3]);
+ ASSERT_EQ(0x9A, bdaddr.address[4]);
+ ASSERT_EQ(0xBC, bdaddr.address[5]);
+
+ std::string ret = bdaddr.ToString();
+
+ ASSERT_STREQ(test_addr, ret.c_str());
+}
+
+TEST(AddressUnittest, test_is_empty) {
+ Address empty;
+ Address::FromString("00:00:00:00:00:00", empty);
+ ASSERT_TRUE(empty.IsEmpty());
+
+ Address not_empty;
+ Address::FromString("00:00:00:00:00:01", not_empty);
+ ASSERT_FALSE(not_empty.IsEmpty());
+}
+
+TEST(AddressUnittest, test_to_from_str) {
+ Address bdaddr;
+ Address::FromString(test_addr, bdaddr);
+
+ ASSERT_EQ(0x12, bdaddr.address[0]);
+ ASSERT_EQ(0x34, bdaddr.address[1]);
+ ASSERT_EQ(0x56, bdaddr.address[2]);
+ ASSERT_EQ(0x78, bdaddr.address[3]);
+ ASSERT_EQ(0x9A, bdaddr.address[4]);
+ ASSERT_EQ(0xBC, bdaddr.address[5]);
+
+ std::string ret = bdaddr.ToString();
+
+ ASSERT_STREQ(test_addr, ret.c_str());
+}
+
+TEST(AddressUnittest, test_from_octets) {
+ static const uint8_t test_addr_array[] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc};
+
+ Address bdaddr;
+ size_t expected_result = Address::kLength;
+ ASSERT_EQ(expected_result, bdaddr.FromOctets(test_addr_array));
+
+ ASSERT_EQ(0x12, bdaddr.address[0]);
+ ASSERT_EQ(0x34, bdaddr.address[1]);
+ ASSERT_EQ(0x56, bdaddr.address[2]);
+ ASSERT_EQ(0x78, bdaddr.address[3]);
+ ASSERT_EQ(0x9A, bdaddr.address[4]);
+ ASSERT_EQ(0xBC, bdaddr.address[5]);
+
+ std::string ret = bdaddr.ToString();
+
+ ASSERT_STREQ(test_addr, ret.c_str());
+}
+
+TEST(AddressTest, test_equals) {
+ Address bdaddr1;
+ Address bdaddr2;
+ Address bdaddr3;
+ Address::FromString(test_addr, bdaddr1);
+ Address::FromString(test_addr, bdaddr2);
+ EXPECT_TRUE(bdaddr1 == bdaddr2);
+ EXPECT_FALSE(bdaddr1 != bdaddr2);
+ EXPECT_TRUE(bdaddr1 == bdaddr1);
+ EXPECT_FALSE(bdaddr1 != bdaddr1);
+
+ Address::FromString(test_addr2, bdaddr3);
+ EXPECT_FALSE(bdaddr2 == bdaddr3);
+ EXPECT_TRUE(bdaddr2 != bdaddr3);
+}
+
+TEST(AddressTest, test_less_than) {
+ Address bdaddr1;
+ Address bdaddr2;
+ Address bdaddr3;
+ Address::FromString(test_addr, bdaddr1);
+ Address::FromString(test_addr, bdaddr2);
+ EXPECT_FALSE(bdaddr1 < bdaddr2);
+ EXPECT_FALSE(bdaddr1 < bdaddr1);
+
+ Address::FromString(test_addr2, bdaddr3);
+ EXPECT_TRUE(bdaddr2 < bdaddr3);
+ EXPECT_FALSE(bdaddr3 < bdaddr2);
+}
+
+TEST(AddressTest, test_more_than) {
+ Address bdaddr1;
+ Address bdaddr2;
+ Address bdaddr3;
+ Address::FromString(test_addr, bdaddr1);
+ Address::FromString(test_addr, bdaddr2);
+ EXPECT_FALSE(bdaddr1 > bdaddr2);
+ EXPECT_FALSE(bdaddr1 > bdaddr1);
+
+ Address::FromString(test_addr2, bdaddr3);
+ EXPECT_FALSE(bdaddr2 > bdaddr3);
+ EXPECT_TRUE(bdaddr3 > bdaddr2);
+}
+
+TEST(AddressTest, test_less_than_or_equal) {
+ Address bdaddr1;
+ Address bdaddr2;
+ Address bdaddr3;
+ Address::FromString(test_addr, bdaddr1);
+ Address::FromString(test_addr, bdaddr2);
+ EXPECT_TRUE(bdaddr1 <= bdaddr2);
+ EXPECT_TRUE(bdaddr1 <= bdaddr1);
+
+ Address::FromString(test_addr2, bdaddr3);
+ EXPECT_TRUE(bdaddr2 <= bdaddr3);
+ EXPECT_FALSE(bdaddr3 <= bdaddr2);
+}
+
+TEST(AddressTest, test_more_than_or_equal) {
+ Address bdaddr1;
+ Address bdaddr2;
+ Address bdaddr3;
+ Address::FromString(test_addr, bdaddr1);
+ Address::FromString(test_addr, bdaddr2);
+ EXPECT_TRUE(bdaddr1 >= bdaddr2);
+ EXPECT_TRUE(bdaddr1 >= bdaddr1);
+
+ Address::FromString(test_addr2, bdaddr3);
+ EXPECT_FALSE(bdaddr2 >= bdaddr3);
+ EXPECT_TRUE(bdaddr3 >= bdaddr2);
+}
+
+TEST(AddressTest, test_copy) {
+ Address bdaddr1;
+ Address bdaddr2;
+ Address::FromString(test_addr, bdaddr1);
+ bdaddr2 = bdaddr1;
+
+ EXPECT_TRUE(bdaddr1 == bdaddr2);
+}
+
+TEST(AddressTest, IsValidAddress) {
+ EXPECT_FALSE(Address::IsValidAddress(""));
+ EXPECT_FALSE(Address::IsValidAddress("000000000000"));
+ EXPECT_FALSE(Address::IsValidAddress("00:00:00:00:0000"));
+ EXPECT_FALSE(Address::IsValidAddress("00:00:00:00:00:0"));
+ EXPECT_FALSE(Address::IsValidAddress("00:00:00:00:00:0;"));
+ EXPECT_TRUE(Address::IsValidAddress("00:00:00:00:00:00"));
+ EXPECT_TRUE(Address::IsValidAddress("AB:cd:00:00:00:00"));
+ EXPECT_FALSE(Address::IsValidAddress("aB:cD:eF:Gh:iJ:Kl"));
+}
+
+TEST(AddressTest, BdAddrFromString) {
+ Address addr;
+ memset(&addr, 0, sizeof(addr));
+
+ EXPECT_TRUE(Address::FromString("00:00:00:00:00:00", addr));
+ const Address result0 = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
+ EXPECT_EQ(0, memcmp(&addr, &result0, sizeof(addr)));
+
+ EXPECT_TRUE(Address::FromString("ab:01:4C:d5:21:9f", addr));
+ const Address result1 = {{0x9f, 0x21, 0xd5, 0x4c, 0x01, 0xab}};
+ EXPECT_EQ(0, memcmp(&addr, &result1, sizeof(addr)));
+}
+
+TEST(AddressTest, BdAddrFromStringToStringEquivalent) {
+ std::string address = "c1:c2:c3:d1:d2:d3";
+ Address addr;
+
+ EXPECT_TRUE(Address::FromString(address, addr));
+ EXPECT_EQ(addr.ToString(), address);
+}
diff --git a/gd/common/bidi_queue.h b/gd/common/bidi_queue.h
new file mode 100644
index 0000000..17baa60
--- /dev/null
+++ b/gd/common/bidi_queue.h
@@ -0,0 +1,89 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 "os/queue.h"
+
+namespace bluetooth {
+namespace common {
+
+template <typename TENQUEUE, typename TDEQUEUE>
+class BidiQueueEnd
+ : public ::bluetooth::os::IQueueEnqueue<TENQUEUE>,
+ public ::bluetooth::os::IQueueDequeue<TDEQUEUE> {
+ public:
+ using EnqueueCallback = std::function<std::unique_ptr<TENQUEUE>()>;
+ using DequeueCallback = std::function<void()>;
+
+ BidiQueueEnd(::bluetooth::os::IQueueEnqueue<TENQUEUE>* tx, ::bluetooth::os::IQueueDequeue<TDEQUEUE>* rx)
+ : tx_(tx), rx_(rx) {
+ }
+
+ void RegisterEnqueue(::bluetooth::os::Handler* handler, EnqueueCallback callback) override {
+ tx_->RegisterEnqueue(handler, callback);
+ }
+
+ void UnregisterEnqueue() override {
+ tx_->UnregisterEnqueue();
+ }
+
+ void RegisterDequeue(::bluetooth::os::Handler* handler, DequeueCallback callback) override {
+ rx_->RegisterDequeue(handler, callback);
+ }
+
+ void UnregisterDequeue() override {
+ rx_->UnregisterDequeue();
+ }
+
+ std::unique_ptr<TDEQUEUE> TryDequeue() override {
+ return rx_->TryDequeue();
+ }
+
+ private:
+ ::bluetooth::os::IQueueEnqueue<TENQUEUE>* tx_;
+ ::bluetooth::os::IQueueDequeue<TDEQUEUE>* rx_;
+};
+
+template <typename TUP, typename TDOWN>
+class BidiQueue {
+ public:
+ explicit BidiQueue(size_t capacity)
+ : up_queue_(capacity),
+ down_queue_(capacity),
+ up_end_(&down_queue_, &up_queue_),
+ down_end_(&up_queue_, &down_queue_) {
+ }
+
+ BidiQueueEnd<TDOWN, TUP>* GetUpEnd() {
+ return &up_end_;
+ }
+
+ BidiQueueEnd<TUP, TDOWN>* GetDownEnd() {
+ return &down_end_;
+ }
+
+ private:
+ ::bluetooth::os::Queue<TUP> up_queue_;
+ ::bluetooth::os::Queue<TDOWN> down_queue_;
+ BidiQueueEnd<TDOWN, TUP> up_end_;
+ BidiQueueEnd<TUP, TDOWN> down_end_;
+};
+
+} // namespace common
+} // namespace bluetooth
diff --git a/gd/common/bidi_queue_unittest.cc b/gd/common/bidi_queue_unittest.cc
new file mode 100644
index 0000000..0bad92d
--- /dev/null
+++ b/gd/common/bidi_queue_unittest.cc
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2019 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 "common/bidi_queue.h"
+
+#include <future>
+
+#include "gtest/gtest.h"
+#include "os/thread.h"
+#include "os/handler.h"
+
+using ::bluetooth::os::Thread;
+using ::bluetooth::os::Handler;
+
+namespace bluetooth {
+namespace common {
+namespace {
+
+class BidiQueueTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ up_thread_ = new Thread("up_thread", Thread::Priority::NORMAL);
+ up_handler_ = new Handler(up_thread_);
+ down_thread_ = new Thread("down_thread", Thread::Priority::NORMAL);
+ down_handler_ = new Handler(down_thread_);
+ }
+
+ void TearDown() override {
+ delete up_handler_;
+ delete up_thread_;
+ delete down_handler_;
+ delete down_thread_;
+ }
+
+ Thread* up_thread_;
+ Handler* up_handler_;
+ Thread* down_thread_;
+ Handler* down_handler_;
+};
+
+class A {
+};
+
+class B {
+};
+
+template <typename TA, typename TB>
+class TestBidiQueueEnd {
+ public:
+ explicit TestBidiQueueEnd(BidiQueueEnd<TA, TB>* end, Handler* handler)
+ : handler_(handler), end_(end) {}
+
+ ~TestBidiQueueEnd() {
+ }
+
+ std::promise<void>* Send(TA* value) {
+ std::promise<void>* promise = new std::promise<void>();
+ handler_->Post([this, value, promise] {
+ end_->RegisterEnqueue(handler_, [this, value, promise]() -> std::unique_ptr<TA> {
+ end_->UnregisterEnqueue();
+ promise->set_value();
+ return std::unique_ptr<TA>(value);
+ });
+ });
+
+ return promise;
+ }
+
+ std::promise<TB*>* Receive() {
+ std::promise<TB*>* promise = new std::promise<TB*>();
+ handler_->Post([this, promise] {
+ end_->RegisterDequeue(handler_, [this, promise] {
+ end_->UnregisterDequeue();
+ promise->set_value(end_->TryDequeue().get());
+ });
+ });
+
+ return promise;
+ }
+
+ private:
+ Handler* handler_;
+ BidiQueueEnd<TA, TB>* end_;
+};
+
+TEST_F(BidiQueueTest, simple_test) {
+ BidiQueue<A, B> queue(100);
+ TestBidiQueueEnd<B, A> test_up(queue.GetUpEnd(), up_handler_);
+ TestBidiQueueEnd<A, B> test_down(queue.GetDownEnd(), down_handler_);
+
+ auto sending_b = new B();
+ auto promise_sending_b = test_up.Send(sending_b);
+ promise_sending_b->get_future().wait();
+ auto promise_receive_b = test_down.Receive();
+ EXPECT_EQ(promise_receive_b->get_future().get(), sending_b);
+ delete promise_receive_b;
+ delete promise_sending_b;
+
+ auto sending_a = new A();
+ auto promise_sending_a = test_down.Send(sending_a);
+ promise_sending_a->get_future().wait();
+ auto promise_receive_a = test_up.Receive();
+ EXPECT_EQ(promise_receive_a->get_future().get(), sending_a);
+ delete promise_receive_a;
+ delete promise_sending_a;
+}
+
+} // namespace
+} // namespace os
+} // namespace bluetooth
diff --git a/gd/common/blocking_queue.h b/gd/common/blocking_queue.h
new file mode 100644
index 0000000..8d006d5
--- /dev/null
+++ b/gd/common/blocking_queue.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2019 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 <chrono>
+#include <condition_variable>
+#include <mutex>
+#include <queue>
+
+namespace bluetooth {
+namespace common {
+
+template <typename T>
+class BlockingQueue {
+ public:
+ void push(T data) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ queue_.push(std::move(data));
+ if (queue_.size() == 1) {
+ not_empty_.notify_all();
+ }
+ };
+
+ T take() {
+ std::unique_lock<std::mutex> lock(mutex_);
+ while (queue_.empty()) {
+ not_empty_.wait(lock);
+ }
+ T data = queue_.front();
+ queue_.pop();
+ return data;
+ };
+
+ bool take_for(std::chrono::milliseconds time, T& data) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ while (queue_.empty()) {
+ if (not_empty_.wait_for(lock, time) == std::cv_status::timeout) {
+ return false;
+ }
+ }
+ data = queue_.front();
+ queue_.pop();
+
+ return true;
+ }
+
+ bool empty() const {
+ std::unique_lock<std::mutex> lock(mutex_);
+ return queue_.empty();
+ };
+
+ void clear() {
+ std::unique_lock<std::mutex> lock(mutex_);
+ std::queue<T> empty;
+ std::swap(queue_, empty);
+ };
+
+ private:
+ std::queue<T> queue_;
+ mutable std::mutex mutex_;
+ std::condition_variable not_empty_;
+};
+
+} // namespace common
+} // namespace bluetooth
diff --git a/gd/common/blocking_queue_unittest.cc b/gd/common/blocking_queue_unittest.cc
new file mode 100644
index 0000000..da1d9c6
--- /dev/null
+++ b/gd/common/blocking_queue_unittest.cc
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2019 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 "common/blocking_queue.h"
+
+#include <thread>
+
+#include <gtest/gtest.h>
+
+namespace bluetooth {
+namespace common {
+namespace {
+class BlockingQueueTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ EXPECT_TRUE(queue_.empty());
+ }
+
+ // Postcondition for each test case: clear the blocking queue
+ void TearDown() override {
+ EXPECT_TRUE(queue_.empty());
+ }
+
+ BlockingQueue<int> queue_;
+};
+
+TEST_F(BlockingQueueTest, initial_empty) {
+ EXPECT_TRUE(queue_.empty());
+}
+
+TEST_F(BlockingQueueTest, same_thread_push_and_pop) {
+ int data = 1;
+ queue_.push(data);
+ EXPECT_FALSE(queue_.empty());
+ EXPECT_EQ(queue_.take(), data);
+ EXPECT_TRUE(queue_.empty());
+}
+
+TEST_F(BlockingQueueTest, same_thread_push_and_pop_sequential) {
+ for (int data = 0; data < 10; data++) {
+ queue_.push(data);
+ EXPECT_FALSE(queue_.empty());
+ EXPECT_EQ(queue_.take(), data);
+ EXPECT_TRUE(queue_.empty());
+ }
+}
+
+TEST_F(BlockingQueueTest, same_thread_push_and_pop_batch) {
+ for (int data = 0; data < 10; data++) {
+ queue_.push(data);
+ }
+ EXPECT_FALSE(queue_.empty());
+ for (int data = 0; data < 10; data++) {
+ EXPECT_EQ(queue_.take(), data);
+ }
+ EXPECT_TRUE(queue_.empty());
+}
+
+TEST_F(BlockingQueueTest, clear_queue) {
+ for (int data = 0; data < 10; data++) {
+ queue_.push(data);
+ }
+ EXPECT_FALSE(queue_.empty());
+ queue_.clear();
+ EXPECT_TRUE(queue_.empty());
+}
+
+TEST_F(BlockingQueueTest, wait_for_non_empty) {
+ int data = 1;
+ std::thread waiter_thread([this, data] { EXPECT_EQ(queue_.take(), data); });
+ queue_.push(data);
+ waiter_thread.join();
+ EXPECT_TRUE(queue_.empty());
+}
+
+TEST_F(BlockingQueueTest, wait_for_non_empty_batch) {
+ std::thread waiter_thread([this] {
+ for (int data = 0; data < 10; data++) {
+ EXPECT_EQ(queue_.take(), data);
+ }
+ });
+ for (int data = 0; data < 10; data++) {
+ queue_.push(data);
+ }
+ waiter_thread.join();
+ EXPECT_TRUE(queue_.empty());
+}
+
+class VectorBlockingQueueTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ EXPECT_TRUE(queue_.empty());
+ }
+
+ // Postcondition for each test case: clear the blocking queue
+ void TearDown() override {
+ EXPECT_TRUE(queue_.empty());
+ }
+
+ BlockingQueue<std::vector<uint8_t>> queue_;
+};
+
+TEST_F(VectorBlockingQueueTest, same_thread_push_and_pop) {
+ std::vector<uint8_t> data = {1, 2, 3, 4, 5, 6};
+ queue_.push(data);
+ EXPECT_FALSE(queue_.empty());
+ EXPECT_EQ(queue_.take(), data);
+ EXPECT_TRUE(queue_.empty());
+}
+
+} // namespace
+} // namespace common
+} // namespace bluetooth
diff --git a/gd/common/class_of_device.cc b/gd/common/class_of_device.cc
new file mode 100644
index 0000000..8d7ff68
--- /dev/null
+++ b/gd/common/class_of_device.cc
@@ -0,0 +1,98 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 "class_of_device.h"
+
+#include <stdint.h>
+#include <algorithm>
+#include <sstream>
+#include <vector>
+
+#include "os/log.h"
+
+namespace bluetooth {
+namespace common {
+
+static_assert(sizeof(ClassOfDevice) == ClassOfDevice::kLength, "ClassOfDevice must be 3 bytes long!");
+
+ClassOfDevice::ClassOfDevice(const uint8_t (&class_of_device)[kLength]) {
+ std::copy(class_of_device, class_of_device + kLength, cod);
+};
+
+std::string ClassOfDevice::ToString() const {
+ char buffer[] = "000-0-00";
+ std::snprintf(&buffer[0], sizeof(buffer),
+ "%03x-%01x-%02x", (static_cast<uint16_t>(cod[2]) << 4) | cod[1] >> 4, cod[1] & 0x0f, cod[0]);
+ std::string str(buffer);
+ return str;
+
+}
+
+bool ClassOfDevice::FromString(const std::string& from, ClassOfDevice& to) {
+ ClassOfDevice new_cod;
+ if (from.length() != 8) return false;
+
+ std::istringstream stream(from);
+ std::string token;
+ int index = 0;
+ uint16_t values[3];
+
+ while (getline(stream, token, '-')) {
+ if (index >= 3) {
+ return false;
+ }
+
+ if (index == 0 && token.length() != 3) {
+ return false;
+ } else if (index == 1 && token.length() != 1) {
+ return false;
+ } else if (index == 2 && token.length() != 2) {
+ return false;
+ }
+ char* temp = nullptr;
+ values[index] = strtol(token.c_str(), &temp, 16);
+ if (*temp != '\0') {
+ return false;
+ }
+
+ index++;
+ }
+
+ if (index != 3) {
+ return false;
+ }
+
+ new_cod.cod[0] = values[2];
+ new_cod.cod[1] = values[1] | ((values[0] & 0xf) << 4);
+ new_cod.cod[2] = values[0] >> 4;
+
+ to = new_cod;
+ return true;
+}
+
+size_t ClassOfDevice::FromOctets(const uint8_t* from) {
+ std::copy(from, from + kLength, cod);
+ return kLength;
+};
+
+bool ClassOfDevice::IsValid(const std::string& cod) {
+ ClassOfDevice tmp;
+ return ClassOfDevice::FromString(cod, tmp);
+}
+} // namespace common
+} // namespace bluetooth
diff --git a/gd/common/class_of_device.h b/gd/common/class_of_device.h
new file mode 100644
index 0000000..983f128
--- /dev/null
+++ b/gd/common/class_of_device.h
@@ -0,0 +1,59 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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>
+
+namespace bluetooth {
+namespace common {
+
+class ClassOfDevice final {
+ public:
+ static constexpr unsigned int kLength = 3;
+
+ uint8_t cod[kLength];
+
+ ClassOfDevice() = default;
+ ClassOfDevice(const uint8_t (&class_of_device)[kLength]);
+
+ bool operator==(const ClassOfDevice& rhs) const {
+ return (std::memcmp(cod, rhs.cod, sizeof(cod)) == 0);
+ }
+
+ std::string ToString() const;
+
+ // Converts |string| to ClassOfDevice and places it in |to|. If |from| does
+ // not represent a Class of Device, |to| is not modified and this function
+ // returns false. Otherwise, it returns true.
+ static bool FromString(const std::string& from, ClassOfDevice& to);
+
+ // Copies |from| raw Class of Device octets to the local object.
+ // Returns the number of copied octets (always ClassOfDevice::kLength)
+ size_t FromOctets(const uint8_t* from);
+
+ static bool IsValid(const std::string& class_of_device);
+};
+
+inline std::ostream& operator<<(std::ostream& os, const ClassOfDevice& c) {
+ os << c.ToString();
+ return os;
+}
+
+} // namespace common
+} // namespace bluetooth
diff --git a/gd/common/class_of_device_unittest.cc b/gd/common/class_of_device_unittest.cc
new file mode 100644
index 0000000..abd4a59
--- /dev/null
+++ b/gd/common/class_of_device_unittest.cc
@@ -0,0 +1,98 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 <gtest/gtest.h>
+
+#include "common/class_of_device.h"
+
+using bluetooth::common::ClassOfDevice;
+
+static const char* test_class = "efc-d-ab";
+static const uint8_t test_bytes[]{0xab, 0xcd, 0xef};
+
+TEST(ClassOfDeviceUnittest, test_constructor_array) {
+ ClassOfDevice cod(test_bytes);
+
+ ASSERT_EQ(test_bytes[0], cod.cod[0]);
+ ASSERT_EQ(test_bytes[1], cod.cod[1]);
+ ASSERT_EQ(test_bytes[2], cod.cod[2]);
+
+ std::string ret = cod.ToString();
+
+ ASSERT_STREQ(test_class, ret.c_str());
+}
+
+TEST(ClassOfDeviceUnittest, test_to_from_str) {
+ ClassOfDevice cod;
+ ClassOfDevice::FromString(test_class, cod);
+
+ ASSERT_EQ(test_bytes[0], cod.cod[0]);
+ ASSERT_EQ(test_bytes[1], cod.cod[1]);
+ ASSERT_EQ(test_bytes[2], cod.cod[2]);
+
+ std::string ret = cod.ToString();
+
+ ASSERT_STREQ(test_class, ret.c_str());
+}
+
+TEST(ClassOfDeviceUnittest, test_from_octets) {
+ ClassOfDevice cod;
+ size_t expected_result = ClassOfDevice::kLength;
+ ASSERT_EQ(expected_result, cod.FromOctets(test_bytes));
+
+ ASSERT_EQ(test_bytes[0], cod.cod[0]);
+ ASSERT_EQ(test_bytes[1], cod.cod[1]);
+ ASSERT_EQ(test_bytes[2], cod.cod[2]);
+
+ std::string ret = cod.ToString();
+
+ ASSERT_STREQ(test_class, ret.c_str());
+}
+
+TEST(ClassOfDeviceTest, test_copy) {
+ ClassOfDevice cod1;
+ ClassOfDevice cod2;
+ ClassOfDevice::FromString(test_class, cod1);
+ cod2 = cod1;
+
+ ASSERT_EQ(cod1.cod[0], cod2.cod[0]);
+ ASSERT_EQ(cod1.cod[1], cod2.cod[1]);
+ ASSERT_EQ(cod1.cod[2], cod2.cod[2]);
+}
+
+TEST(ClassOfDeviceTest, IsValid) {
+ EXPECT_FALSE(ClassOfDevice::IsValid(""));
+ EXPECT_FALSE(ClassOfDevice::IsValid("000000"));
+ EXPECT_FALSE(ClassOfDevice::IsValid("00-00-00"));
+ EXPECT_FALSE(ClassOfDevice::IsValid("000-0-0"));
+ EXPECT_TRUE(ClassOfDevice::IsValid("000-0-00"));
+ EXPECT_TRUE(ClassOfDevice::IsValid("ABc-d-00"));
+ EXPECT_TRUE(ClassOfDevice::IsValid("aBc-D-eF"));
+}
+
+TEST(ClassOfDeviceTest, classOfDeviceFromString) {
+ ClassOfDevice cod;
+
+ EXPECT_TRUE(ClassOfDevice::FromString("000-0-00", cod));
+ const ClassOfDevice result0 = {{0x00, 0x00, 0x00}};
+ EXPECT_EQ(0, memcmp(&cod, &result0, sizeof(cod)));
+
+ EXPECT_TRUE(ClassOfDevice::FromString("ab2-1-4C", cod));
+ const ClassOfDevice result1 = {{0x4c, 0x21, 0xab}};
+ EXPECT_EQ(0, memcmp(&cod, &result1, sizeof(cod)));
+}
diff --git a/gd/crypto_toolbox/Android.bp b/gd/crypto_toolbox/Android.bp
new file mode 100644
index 0000000..fd2e6ed
--- /dev/null
+++ b/gd/crypto_toolbox/Android.bp
@@ -0,0 +1,15 @@
+filegroup {
+ name: "BluetoothCryptoToolboxSources",
+ srcs: [
+ "aes.cc",
+ "aes_cmac.cc",
+ "crypto_toolbox.cc",
+ ]
+}
+
+filegroup {
+ name: "BluetoothCryptoToolboxTestSources",
+ srcs: [
+ "crypto_toolbox_test.cc",
+ ]
+}
\ No newline at end of file
diff --git a/gd/crypto_toolbox/aes.cc b/gd/crypto_toolbox/aes.cc
new file mode 100644
index 0000000..f53894e
--- /dev/null
+++ b/gd/crypto_toolbox/aes.cc
@@ -0,0 +1,950 @@
+/*
+ ---------------------------------------------------------------------------
+ Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.
+
+ LICENSE TERMS
+
+ The redistribution and use of this software (with or without changes)
+ is allowed without the payment of fees or royalties provided that:
+
+ 1. source code distributions include the above copyright notice, this
+ list of conditions and the following disclaimer;
+
+ 2. binary distributions include the above copyright notice, this list
+ of conditions and the following disclaimer in their documentation;
+
+ 3. the name of the copyright holder is not used to endorse products
+ built using this software without specific written permission.
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness
+ and/or fitness for purpose.
+ ---------------------------------------------------------------------------
+ Issue 09/09/2006
+
+ This is an AES implementation that uses only 8-bit byte operations on the
+ cipher state (there are options to use 32-bit types if available).
+
+ The combination of mix columns and byte substitution used here is based on
+ that developed by Karl Malbrain. His contribution is acknowledged.
+ */
+
+/* define if you have a fast memcpy function on your system */
+#if 1
+#define HAVE_MEMCPY
+#include <string.h>
+#if 0
+#if defined(_MSC_VER)
+#include <intrin.h>
+#pragma intrinsic(memcpy)
+#endif
+#endif
+#endif
+
+#include <stdint.h>
+#include <stdlib.h>
+
+/* define if you have fast 32-bit types on your system */
+#if 1
+#define HAVE_UINT_32T
+#endif
+
+/* define if you don't want any tables */
+#if 1
+#define USE_TABLES
+#endif
+
+/* On Intel Core 2 duo VERSION_1 is faster */
+
+/* alternative versions (test for performance on your system) */
+#if 1
+#define VERSION_1
+#endif
+
+#include "aes.h"
+
+#if defined(HAVE_UINT_32T)
+typedef uint32_t uint_32t;
+#endif
+
+/* functions for finite field multiplication in the AES Galois field */
+
+#define WPOLY 0x011b
+#define BPOLY 0x1b
+#define DPOLY 0x008d
+
+#define f1(x) (x)
+#define f2(x) (((x) << 1) ^ ((((x) >> 7) & 1) * WPOLY))
+#define f4(x) \
+ (((x) << 2) ^ ((((x) >> 6) & 1) * WPOLY) ^ ((((x) >> 6) & 2) * WPOLY))
+#define f8(x) \
+ (((x) << 3) ^ ((((x) >> 5) & 1) * WPOLY) ^ ((((x) >> 5) & 2) * WPOLY) ^ \
+ ((((x) >> 5) & 4) * WPOLY))
+#define d2(x) (((x) >> 1) ^ ((x)&1 ? DPOLY : 0))
+
+#define f3(x) (f2(x) ^ (x))
+#define f9(x) (f8(x) ^ (x))
+#define fb(x) (f8(x) ^ f2(x) ^ (x))
+#define fd(x) (f8(x) ^ f4(x) ^ (x))
+#define fe(x) (f8(x) ^ f4(x) ^ f2(x))
+
+#if defined(USE_TABLES)
+
+#define sb_data(w) \
+ { /* S Box data values */ \
+ w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5), \
+ w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), \
+ w(0x76), w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), \
+ w(0x47), w(0xf0), w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), \
+ w(0xa4), w(0x72), w(0xc0), w(0xb7), w(0xfd), w(0x93), w(0x26), \
+ w(0x36), w(0x3f), w(0xf7), w(0xcc), w(0x34), w(0xa5), w(0xe5), \
+ w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15), w(0x04), w(0xc7), \
+ w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a), w(0x07), \
+ w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75), \
+ w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), \
+ w(0xa0), w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), \
+ w(0x2f), w(0x84), w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), \
+ w(0xfc), w(0xb1), w(0x5b), w(0x6a), w(0xcb), w(0xbe), w(0x39), \
+ w(0x4a), w(0x4c), w(0x58), w(0xcf), w(0xd0), w(0xef), w(0xaa), \
+ w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85), w(0x45), w(0xf9), \
+ w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8), w(0x51), \
+ w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5), \
+ w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), \
+ w(0xd2), w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), \
+ w(0x44), w(0x17), w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), \
+ w(0x5d), w(0x19), w(0x73), w(0x60), w(0x81), w(0x4f), w(0xdc), \
+ w(0x22), w(0x2a), w(0x90), w(0x88), w(0x46), w(0xee), w(0xb8), \
+ w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb), w(0xe0), w(0x32), \
+ w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c), w(0xc2), \
+ w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79), \
+ w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), \
+ w(0xa9), w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), \
+ w(0xae), w(0x08), w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), \
+ w(0xa6), w(0xb4), w(0xc6), w(0xe8), w(0xdd), w(0x74), w(0x1f), \
+ w(0x4b), w(0xbd), w(0x8b), w(0x8a), w(0x70), w(0x3e), w(0xb5), \
+ w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e), w(0x61), w(0x35), \
+ w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e), w(0xe1), \
+ w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94), \
+ w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), \
+ w(0xdf), w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), \
+ w(0x42), w(0x68), w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), \
+ w(0x54), w(0xbb), w(0x16) \
+ }
+
+#define isb_data(w) \
+ { /* inverse S Box data values */ \
+ w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38), \
+ w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), \
+ w(0xfb), w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), \
+ w(0xff), w(0x87), w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), \
+ w(0xde), w(0xe9), w(0xcb), w(0x54), w(0x7b), w(0x94), w(0x32), \
+ w(0xa6), w(0xc2), w(0x23), w(0x3d), w(0xee), w(0x4c), w(0x95), \
+ w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e), w(0x08), w(0x2e), \
+ w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2), w(0x76), \
+ w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25), \
+ w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), \
+ w(0x16), w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), \
+ w(0xb6), w(0x92), w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), \
+ w(0xed), w(0xb9), w(0xda), w(0x5e), w(0x15), w(0x46), w(0x57), \
+ w(0xa7), w(0x8d), w(0x9d), w(0x84), w(0x90), w(0xd8), w(0xab), \
+ w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a), w(0xf7), w(0xe4), \
+ w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06), w(0xd0), \
+ w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02), \
+ w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), \
+ w(0x6b), w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), \
+ w(0xdc), w(0xea), w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), \
+ w(0xb4), w(0xe6), w(0x73), w(0x96), w(0xac), w(0x74), w(0x22), \
+ w(0xe7), w(0xad), w(0x35), w(0x85), w(0xe2), w(0xf9), w(0x37), \
+ w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e), w(0x47), w(0xf1), \
+ w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89), w(0x6f), \
+ w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b), \
+ w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), \
+ w(0x20), w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), \
+ w(0x5a), w(0xf4), w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), \
+ w(0x07), w(0xc7), w(0x31), w(0xb1), w(0x12), w(0x10), w(0x59), \
+ w(0x27), w(0x80), w(0xec), w(0x5f), w(0x60), w(0x51), w(0x7f), \
+ w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d), w(0x2d), w(0xe5), \
+ w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef), w(0xa0), \
+ w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0), \
+ w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), \
+ w(0x61), w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), \
+ w(0xd6), w(0x26), w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), \
+ w(0x21), w(0x0c), w(0x7d) \
+ }
+
+#define mm_data(w) \
+ { /* basic data for forming finite field tables */ \
+ w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07), \
+ w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), \
+ w(0x0f), w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), \
+ w(0x16), w(0x17), w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), \
+ w(0x1d), w(0x1e), w(0x1f), w(0x20), w(0x21), w(0x22), w(0x23), \
+ w(0x24), w(0x25), w(0x26), w(0x27), w(0x28), w(0x29), w(0x2a), \
+ w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f), w(0x30), w(0x31), \
+ w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37), w(0x38), \
+ w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f), \
+ w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), \
+ w(0x47), w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), \
+ w(0x4e), w(0x4f), w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), \
+ w(0x55), w(0x56), w(0x57), w(0x58), w(0x59), w(0x5a), w(0x5b), \
+ w(0x5c), w(0x5d), w(0x5e), w(0x5f), w(0x60), w(0x61), w(0x62), \
+ w(0x63), w(0x64), w(0x65), w(0x66), w(0x67), w(0x68), w(0x69), \
+ w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f), w(0x70), \
+ w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77), \
+ w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), \
+ w(0x7f), w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), \
+ w(0x86), w(0x87), w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), \
+ w(0x8d), w(0x8e), w(0x8f), w(0x90), w(0x91), w(0x92), w(0x93), \
+ w(0x94), w(0x95), w(0x96), w(0x97), w(0x98), w(0x99), w(0x9a), \
+ w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f), w(0xa0), w(0xa1), \
+ w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7), w(0xa8), \
+ w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf), \
+ w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), \
+ w(0xb7), w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), \
+ w(0xbe), w(0xbf), w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), \
+ w(0xc5), w(0xc6), w(0xc7), w(0xc8), w(0xc9), w(0xca), w(0xcb), \
+ w(0xcc), w(0xcd), w(0xce), w(0xcf), w(0xd0), w(0xd1), w(0xd2), \
+ w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7), w(0xd8), w(0xd9), \
+ w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf), w(0xe0), \
+ w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7), \
+ w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), \
+ w(0xef), w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), \
+ w(0xf6), w(0xf7), w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), \
+ w(0xfd), w(0xfe), w(0xff) \
+ }
+
+static const uint_8t sbox[256] = sb_data(f1);
+static const uint_8t isbox[256] = isb_data(f1);
+
+static const uint_8t gfm2_sbox[256] = sb_data(f2);
+static const uint_8t gfm3_sbox[256] = sb_data(f3);
+
+static const uint_8t gfmul_9[256] = mm_data(f9);
+static const uint_8t gfmul_b[256] = mm_data(fb);
+static const uint_8t gfmul_d[256] = mm_data(fd);
+static const uint_8t gfmul_e[256] = mm_data(fe);
+
+#define s_box(x) sbox[(x)]
+#define is_box(x) isbox[(x)]
+#define gfm2_sb(x) gfm2_sbox[(x)]
+#define gfm3_sb(x) gfm3_sbox[(x)]
+#define gfm_9(x) gfmul_9[(x)]
+#define gfm_b(x) gfmul_b[(x)]
+#define gfm_d(x) gfmul_d[(x)]
+#define gfm_e(x) gfmul_e[(x)]
+
+#else
+
+/* this is the high bit of x right shifted by 1 */
+/* position. Since the starting polynomial has */
+/* 9 bits (0x11b), this right shift keeps the */
+/* values of all top bits within a byte */
+
+static uint_8t hibit(const uint_8t x) {
+ uint_8t r = (uint_8t)((x >> 1) | (x >> 2));
+
+ r |= (r >> 2);
+ r |= (r >> 4);
+ return (r + 1) >> 1;
+}
+
+/* return the inverse of the finite field element x */
+
+static uint_8t gf_inv(const uint_8t x) {
+ uint_8t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0;
+
+ if (x < 2) return x;
+
+ for (;;) {
+ if (n1)
+ while (n2 >= n1) /* divide polynomial p2 by p1 */
+ {
+ n2 /= n1; /* shift smaller polynomial left */
+ p2 ^= (p1 * n2) & 0xff; /* and remove from larger one */
+ v2 ^= (v1 * n2); /* shift accumulated value and */
+ n2 = hibit(p2); /* add into result */
+ }
+ else
+ return v1;
+
+ if (n2) /* repeat with values swapped */
+ while (n1 >= n2) {
+ n1 /= n2;
+ p1 ^= p2 * n1;
+ v1 ^= v2 * n1;
+ n1 = hibit(p1);
+ }
+ else
+ return v2;
+ }
+}
+
+/* The forward and inverse affine transformations used in the S-box */
+uint_8t fwd_affine(const uint_8t x) {
+#if defined(HAVE_UINT_32T)
+ uint_32t w = x;
+ w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4);
+ return 0x63 ^ ((w ^ (w >> 8)) & 0xff);
+#else
+ return 0x63 ^ x ^ (x << 1) ^ (x << 2) ^ (x << 3) ^ (x << 4) ^ (x >> 7) ^
+ (x >> 6) ^ (x >> 5) ^ (x >> 4);
+#endif
+}
+
+uint_8t inv_affine(const uint_8t x) {
+#if defined(HAVE_UINT_32T)
+ uint_32t w = x;
+ w = (w << 1) ^ (w << 3) ^ (w << 6);
+ return 0x05 ^ ((w ^ (w >> 8)) & 0xff);
+#else
+ return 0x05 ^ (x << 1) ^ (x << 3) ^ (x << 6) ^ (x >> 7) ^ (x >> 5) ^ (x >> 2);
+#endif
+}
+
+#define s_box(x) fwd_affine(gf_inv(x))
+#define is_box(x) gf_inv(inv_affine(x))
+#define gfm2_sb(x) f2(s_box(x))
+#define gfm3_sb(x) f3(s_box(x))
+#define gfm_9(x) f9(x)
+#define gfm_b(x) fb(x)
+#define gfm_d(x) fd(x)
+#define gfm_e(x) fe(x)
+
+#endif
+
+#if defined(HAVE_MEMCPY)
+#define block_copy_nn(d, s, l) memcpy(d, s, l)
+#define block_copy(d, s) memcpy(d, s, N_BLOCK)
+#else
+#define block_copy_nn(d, s, l) copy_block_nn(d, s, l)
+#define block_copy(d, s) copy_block(d, s)
+#endif
+
+#if !defined(HAVE_MEMCPY)
+static void copy_block(void* d, const void* s) {
+#if defined(HAVE_UINT_32T)
+ ((uint_32t*)d)[0] = ((uint_32t*)s)[0];
+ ((uint_32t*)d)[1] = ((uint_32t*)s)[1];
+ ((uint_32t*)d)[2] = ((uint_32t*)s)[2];
+ ((uint_32t*)d)[3] = ((uint_32t*)s)[3];
+#else
+ ((uint_8t*)d)[0] = ((uint_8t*)s)[0];
+ ((uint_8t*)d)[1] = ((uint_8t*)s)[1];
+ ((uint_8t*)d)[2] = ((uint_8t*)s)[2];
+ ((uint_8t*)d)[3] = ((uint_8t*)s)[3];
+ ((uint_8t*)d)[4] = ((uint_8t*)s)[4];
+ ((uint_8t*)d)[5] = ((uint_8t*)s)[5];
+ ((uint_8t*)d)[6] = ((uint_8t*)s)[6];
+ ((uint_8t*)d)[7] = ((uint_8t*)s)[7];
+ ((uint_8t*)d)[8] = ((uint_8t*)s)[8];
+ ((uint_8t*)d)[9] = ((uint_8t*)s)[9];
+ ((uint_8t*)d)[10] = ((uint_8t*)s)[10];
+ ((uint_8t*)d)[11] = ((uint_8t*)s)[11];
+ ((uint_8t*)d)[12] = ((uint_8t*)s)[12];
+ ((uint_8t*)d)[13] = ((uint_8t*)s)[13];
+ ((uint_8t*)d)[14] = ((uint_8t*)s)[14];
+ ((uint_8t*)d)[15] = ((uint_8t*)s)[15];
+#endif
+}
+
+static void copy_block_nn(void* d, const void* s, uint_8t nn) {
+ while (nn--) *((uint_8t*)d)++ = *((uint_8t*)s)++;
+}
+#endif
+
+static void xor_block(void* d, const void* s) {
+#if defined(HAVE_UINT_32T)
+ ((uint_32t*)d)[0] ^= ((uint_32t*)s)[0];
+ ((uint_32t*)d)[1] ^= ((uint_32t*)s)[1];
+ ((uint_32t*)d)[2] ^= ((uint_32t*)s)[2];
+ ((uint_32t*)d)[3] ^= ((uint_32t*)s)[3];
+#else
+ ((uint_8t*)d)[0] ^= ((uint_8t*)s)[0];
+ ((uint_8t*)d)[1] ^= ((uint_8t*)s)[1];
+ ((uint_8t*)d)[2] ^= ((uint_8t*)s)[2];
+ ((uint_8t*)d)[3] ^= ((uint_8t*)s)[3];
+ ((uint_8t*)d)[4] ^= ((uint_8t*)s)[4];
+ ((uint_8t*)d)[5] ^= ((uint_8t*)s)[5];
+ ((uint_8t*)d)[6] ^= ((uint_8t*)s)[6];
+ ((uint_8t*)d)[7] ^= ((uint_8t*)s)[7];
+ ((uint_8t*)d)[8] ^= ((uint_8t*)s)[8];
+ ((uint_8t*)d)[9] ^= ((uint_8t*)s)[9];
+ ((uint_8t*)d)[10] ^= ((uint_8t*)s)[10];
+ ((uint_8t*)d)[11] ^= ((uint_8t*)s)[11];
+ ((uint_8t*)d)[12] ^= ((uint_8t*)s)[12];
+ ((uint_8t*)d)[13] ^= ((uint_8t*)s)[13];
+ ((uint_8t*)d)[14] ^= ((uint_8t*)s)[14];
+ ((uint_8t*)d)[15] ^= ((uint_8t*)s)[15];
+#endif
+}
+
+static void copy_and_key(void* d, const void* s, const void* k) {
+#if defined(HAVE_UINT_32T)
+ ((uint_32t*)d)[0] = ((uint_32t*)s)[0] ^ ((uint_32t*)k)[0];
+ ((uint_32t*)d)[1] = ((uint_32t*)s)[1] ^ ((uint_32t*)k)[1];
+ ((uint_32t*)d)[2] = ((uint_32t*)s)[2] ^ ((uint_32t*)k)[2];
+ ((uint_32t*)d)[3] = ((uint_32t*)s)[3] ^ ((uint_32t*)k)[3];
+#elif 1
+ ((uint_8t*)d)[0] = ((uint_8t*)s)[0] ^ ((uint_8t*)k)[0];
+ ((uint_8t*)d)[1] = ((uint_8t*)s)[1] ^ ((uint_8t*)k)[1];
+ ((uint_8t*)d)[2] = ((uint_8t*)s)[2] ^ ((uint_8t*)k)[2];
+ ((uint_8t*)d)[3] = ((uint_8t*)s)[3] ^ ((uint_8t*)k)[3];
+ ((uint_8t*)d)[4] = ((uint_8t*)s)[4] ^ ((uint_8t*)k)[4];
+ ((uint_8t*)d)[5] = ((uint_8t*)s)[5] ^ ((uint_8t*)k)[5];
+ ((uint_8t*)d)[6] = ((uint_8t*)s)[6] ^ ((uint_8t*)k)[6];
+ ((uint_8t*)d)[7] = ((uint_8t*)s)[7] ^ ((uint_8t*)k)[7];
+ ((uint_8t*)d)[8] = ((uint_8t*)s)[8] ^ ((uint_8t*)k)[8];
+ ((uint_8t*)d)[9] = ((uint_8t*)s)[9] ^ ((uint_8t*)k)[9];
+ ((uint_8t*)d)[10] = ((uint_8t*)s)[10] ^ ((uint_8t*)k)[10];
+ ((uint_8t*)d)[11] = ((uint_8t*)s)[11] ^ ((uint_8t*)k)[11];
+ ((uint_8t*)d)[12] = ((uint_8t*)s)[12] ^ ((uint_8t*)k)[12];
+ ((uint_8t*)d)[13] = ((uint_8t*)s)[13] ^ ((uint_8t*)k)[13];
+ ((uint_8t*)d)[14] = ((uint_8t*)s)[14] ^ ((uint_8t*)k)[14];
+ ((uint_8t*)d)[15] = ((uint_8t*)s)[15] ^ ((uint_8t*)k)[15];
+#else
+ block_copy(d, s);
+ xor_block(d, k);
+#endif
+}
+
+static void add_round_key(uint_8t d[N_BLOCK], const uint_8t k[N_BLOCK]) {
+ xor_block(d, k);
+}
+
+static void shift_sub_rows(uint_8t st[N_BLOCK]) {
+ uint_8t tt;
+
+ st[0] = s_box(st[0]);
+ st[4] = s_box(st[4]);
+ st[8] = s_box(st[8]);
+ st[12] = s_box(st[12]);
+
+ tt = st[1];
+ st[1] = s_box(st[5]);
+ st[5] = s_box(st[9]);
+ st[9] = s_box(st[13]);
+ st[13] = s_box(tt);
+
+ tt = st[2];
+ st[2] = s_box(st[10]);
+ st[10] = s_box(tt);
+ tt = st[6];
+ st[6] = s_box(st[14]);
+ st[14] = s_box(tt);
+
+ tt = st[15];
+ st[15] = s_box(st[11]);
+ st[11] = s_box(st[7]);
+ st[7] = s_box(st[3]);
+ st[3] = s_box(tt);
+}
+
+static void inv_shift_sub_rows(uint_8t st[N_BLOCK]) {
+ uint_8t tt;
+
+ st[0] = is_box(st[0]);
+ st[4] = is_box(st[4]);
+ st[8] = is_box(st[8]);
+ st[12] = is_box(st[12]);
+
+ tt = st[13];
+ st[13] = is_box(st[9]);
+ st[9] = is_box(st[5]);
+ st[5] = is_box(st[1]);
+ st[1] = is_box(tt);
+
+ tt = st[2];
+ st[2] = is_box(st[10]);
+ st[10] = is_box(tt);
+ tt = st[6];
+ st[6] = is_box(st[14]);
+ st[14] = is_box(tt);
+
+ tt = st[3];
+ st[3] = is_box(st[7]);
+ st[7] = is_box(st[11]);
+ st[11] = is_box(st[15]);
+ st[15] = is_box(tt);
+}
+
+#if defined(VERSION_1)
+static void mix_sub_columns(uint_8t dt[N_BLOCK]) {
+ uint_8t st[N_BLOCK];
+ block_copy(st, dt);
+#else
+static void mix_sub_columns(uint_8t dt[N_BLOCK], uint_8t st[N_BLOCK]) {
+#endif
+ dt[0] = gfm2_sb(st[0]) ^ gfm3_sb(st[5]) ^ s_box(st[10]) ^ s_box(st[15]);
+ dt[1] = s_box(st[0]) ^ gfm2_sb(st[5]) ^ gfm3_sb(st[10]) ^ s_box(st[15]);
+ dt[2] = s_box(st[0]) ^ s_box(st[5]) ^ gfm2_sb(st[10]) ^ gfm3_sb(st[15]);
+ dt[3] = gfm3_sb(st[0]) ^ s_box(st[5]) ^ s_box(st[10]) ^ gfm2_sb(st[15]);
+
+ dt[4] = gfm2_sb(st[4]) ^ gfm3_sb(st[9]) ^ s_box(st[14]) ^ s_box(st[3]);
+ dt[5] = s_box(st[4]) ^ gfm2_sb(st[9]) ^ gfm3_sb(st[14]) ^ s_box(st[3]);
+ dt[6] = s_box(st[4]) ^ s_box(st[9]) ^ gfm2_sb(st[14]) ^ gfm3_sb(st[3]);
+ dt[7] = gfm3_sb(st[4]) ^ s_box(st[9]) ^ s_box(st[14]) ^ gfm2_sb(st[3]);
+
+ dt[8] = gfm2_sb(st[8]) ^ gfm3_sb(st[13]) ^ s_box(st[2]) ^ s_box(st[7]);
+ dt[9] = s_box(st[8]) ^ gfm2_sb(st[13]) ^ gfm3_sb(st[2]) ^ s_box(st[7]);
+ dt[10] = s_box(st[8]) ^ s_box(st[13]) ^ gfm2_sb(st[2]) ^ gfm3_sb(st[7]);
+ dt[11] = gfm3_sb(st[8]) ^ s_box(st[13]) ^ s_box(st[2]) ^ gfm2_sb(st[7]);
+
+ dt[12] = gfm2_sb(st[12]) ^ gfm3_sb(st[1]) ^ s_box(st[6]) ^ s_box(st[11]);
+ dt[13] = s_box(st[12]) ^ gfm2_sb(st[1]) ^ gfm3_sb(st[6]) ^ s_box(st[11]);
+ dt[14] = s_box(st[12]) ^ s_box(st[1]) ^ gfm2_sb(st[6]) ^ gfm3_sb(st[11]);
+ dt[15] = gfm3_sb(st[12]) ^ s_box(st[1]) ^ s_box(st[6]) ^ gfm2_sb(st[11]);
+}
+
+#if defined(VERSION_1)
+static void inv_mix_sub_columns(uint_8t dt[N_BLOCK]) {
+ uint_8t st[N_BLOCK];
+ block_copy(st, dt);
+#else
+static void inv_mix_sub_columns(uint_8t dt[N_BLOCK], uint_8t st[N_BLOCK]) {
+#endif
+ dt[0] = is_box(gfm_e(st[0]) ^ gfm_b(st[1]) ^ gfm_d(st[2]) ^ gfm_9(st[3]));
+ dt[5] = is_box(gfm_9(st[0]) ^ gfm_e(st[1]) ^ gfm_b(st[2]) ^ gfm_d(st[3]));
+ dt[10] = is_box(gfm_d(st[0]) ^ gfm_9(st[1]) ^ gfm_e(st[2]) ^ gfm_b(st[3]));
+ dt[15] = is_box(gfm_b(st[0]) ^ gfm_d(st[1]) ^ gfm_9(st[2]) ^ gfm_e(st[3]));
+
+ dt[4] = is_box(gfm_e(st[4]) ^ gfm_b(st[5]) ^ gfm_d(st[6]) ^ gfm_9(st[7]));
+ dt[9] = is_box(gfm_9(st[4]) ^ gfm_e(st[5]) ^ gfm_b(st[6]) ^ gfm_d(st[7]));
+ dt[14] = is_box(gfm_d(st[4]) ^ gfm_9(st[5]) ^ gfm_e(st[6]) ^ gfm_b(st[7]));
+ dt[3] = is_box(gfm_b(st[4]) ^ gfm_d(st[5]) ^ gfm_9(st[6]) ^ gfm_e(st[7]));
+
+ dt[8] = is_box(gfm_e(st[8]) ^ gfm_b(st[9]) ^ gfm_d(st[10]) ^ gfm_9(st[11]));
+ dt[13] = is_box(gfm_9(st[8]) ^ gfm_e(st[9]) ^ gfm_b(st[10]) ^ gfm_d(st[11]));
+ dt[2] = is_box(gfm_d(st[8]) ^ gfm_9(st[9]) ^ gfm_e(st[10]) ^ gfm_b(st[11]));
+ dt[7] = is_box(gfm_b(st[8]) ^ gfm_d(st[9]) ^ gfm_9(st[10]) ^ gfm_e(st[11]));
+
+ dt[12] =
+ is_box(gfm_e(st[12]) ^ gfm_b(st[13]) ^ gfm_d(st[14]) ^ gfm_9(st[15]));
+ dt[1] = is_box(gfm_9(st[12]) ^ gfm_e(st[13]) ^ gfm_b(st[14]) ^ gfm_d(st[15]));
+ dt[6] = is_box(gfm_d(st[12]) ^ gfm_9(st[13]) ^ gfm_e(st[14]) ^ gfm_b(st[15]));
+ dt[11] =
+ is_box(gfm_b(st[12]) ^ gfm_d(st[13]) ^ gfm_9(st[14]) ^ gfm_e(st[15]));
+}
+
+#if defined(AES_ENC_PREKEYED) || defined(AES_DEC_PREKEYED)
+
+/* Set the cipher key for the pre-keyed version */
+/* NOTE: If the length_type used for the key length is an
+ unsigned 8-bit character, a key length of 256 bits must
+ be entered as a length in bytes (valid inputs are hence
+ 128, 192, 16, 24 and 32).
+*/
+
+return_type aes_set_key(const unsigned char key[], length_type keylen,
+ aes_context ctx[1]) {
+ uint_8t cc, rc, hi;
+
+ switch (keylen) {
+ case 16:
+ case 128: /* length in bits (128 = 8*16) */
+ keylen = 16;
+ break;
+ case 24:
+ case 192: /* length in bits (192 = 8*24) */
+ keylen = 24;
+ break;
+ case 32:
+ /* case 256: length in bits (256 = 8*32) */
+ keylen = 32;
+ break;
+ default:
+ ctx->rnd = 0;
+ return (return_type)-1;
+ }
+ block_copy_nn(ctx->ksch, key, keylen);
+ hi = (keylen + 28) << 2;
+ ctx->rnd = (hi >> 4) - 1;
+ for (cc = keylen, rc = 1; cc < hi; cc += 4) {
+ uint_8t tt, t0, t1, t2, t3;
+
+ t0 = ctx->ksch[cc - 4];
+ t1 = ctx->ksch[cc - 3];
+ t2 = ctx->ksch[cc - 2];
+ t3 = ctx->ksch[cc - 1];
+ if (cc % keylen == 0) {
+ tt = t0;
+ t0 = s_box(t1) ^ rc;
+ t1 = s_box(t2);
+ t2 = s_box(t3);
+ t3 = s_box(tt);
+ rc = f2(rc);
+ } else if (keylen > 24 && cc % keylen == 16) {
+ t0 = s_box(t0);
+ t1 = s_box(t1);
+ t2 = s_box(t2);
+ t3 = s_box(t3);
+ }
+ tt = cc - keylen;
+ ctx->ksch[cc + 0] = ctx->ksch[tt + 0] ^ t0;
+ ctx->ksch[cc + 1] = ctx->ksch[tt + 1] ^ t1;
+ ctx->ksch[cc + 2] = ctx->ksch[tt + 2] ^ t2;
+ ctx->ksch[cc + 3] = ctx->ksch[tt + 3] ^ t3;
+ }
+ return 0;
+}
+
+#endif
+
+#if defined(AES_ENC_PREKEYED)
+
+/* Encrypt a single block of 16 bytes */
+
+return_type aes_encrypt(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK], const aes_context ctx[1]) {
+ if (ctx->rnd) {
+ uint_8t s1[N_BLOCK], r;
+ copy_and_key(s1, in, ctx->ksch);
+
+ for (r = 1; r < ctx->rnd; ++r)
+#if defined(VERSION_1)
+ {
+ mix_sub_columns(s1);
+ add_round_key(s1, ctx->ksch + r * N_BLOCK);
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ mix_sub_columns(s2, s1);
+ copy_and_key(s1, s2, ctx->ksch + r * N_BLOCK);
+ }
+#endif
+ shift_sub_rows(s1);
+ copy_and_key(out, s1, ctx->ksch + r * N_BLOCK);
+ } else
+ return (return_type)-1;
+ return 0;
+}
+
+/* CBC encrypt a number of blocks (input and return an IV) */
+
+return_type aes_cbc_encrypt(const unsigned char* in, unsigned char* out,
+ int n_block, unsigned char iv[N_BLOCK],
+ const aes_context ctx[1]) {
+ while (n_block--) {
+ xor_block(iv, in);
+ if (aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE;
+ memcpy(out, iv, N_BLOCK);
+ in += N_BLOCK;
+ out += N_BLOCK;
+ }
+ return EXIT_SUCCESS;
+}
+
+#endif
+
+#if defined(AES_DEC_PREKEYED)
+
+/* Decrypt a single block of 16 bytes */
+
+return_type aes_decrypt(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK], const aes_context ctx[1]) {
+ if (ctx->rnd) {
+ uint_8t s1[N_BLOCK], r;
+ copy_and_key(s1, in, ctx->ksch + ctx->rnd * N_BLOCK);
+ inv_shift_sub_rows(s1);
+
+ for (r = ctx->rnd; --r;)
+#if defined(VERSION_1)
+ {
+ add_round_key(s1, ctx->ksch + r * N_BLOCK);
+ inv_mix_sub_columns(s1);
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ copy_and_key(s2, s1, ctx->ksch + r * N_BLOCK);
+ inv_mix_sub_columns(s1, s2);
+ }
+#endif
+ copy_and_key(out, s1, ctx->ksch);
+ } else
+ return (return_type)-1;
+ return 0;
+}
+
+/* CBC decrypt a number of blocks (input and return an IV) */
+
+return_type aes_cbc_decrypt(const unsigned char* in, unsigned char* out,
+ int n_block, unsigned char iv[N_BLOCK],
+ const aes_context ctx[1]) {
+ while (n_block--) {
+ uint_8t tmp[N_BLOCK];
+
+ memcpy(tmp, in, N_BLOCK);
+ if (aes_decrypt(in, out, ctx) != EXIT_SUCCESS) return EXIT_FAILURE;
+ xor_block(out, iv);
+ memcpy(iv, tmp, N_BLOCK);
+ in += N_BLOCK;
+ out += N_BLOCK;
+ }
+ return EXIT_SUCCESS;
+}
+
+#endif
+
+#if defined(AES_ENC_128_OTFK)
+
+/* The 'on the fly' encryption key update for for 128 bit keys */
+
+static void update_encrypt_key_128(uint_8t k[N_BLOCK], uint_8t* rc) {
+ uint_8t cc;
+
+ k[0] ^= s_box(k[13]) ^ *rc;
+ k[1] ^= s_box(k[14]);
+ k[2] ^= s_box(k[15]);
+ k[3] ^= s_box(k[12]);
+ *rc = f2(*rc);
+
+ for (cc = 4; cc < 16; cc += 4) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+}
+
+/* Encrypt a single block of 16 bytes with 'on the fly' 128 bit keying */
+
+void aes_encrypt_128(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[N_BLOCK],
+ unsigned char o_key[N_BLOCK]) {
+ uint_8t s1[N_BLOCK], r, rc = 1;
+
+ if (o_key != key) block_copy(o_key, key);
+ copy_and_key(s1, in, o_key);
+
+ for (r = 1; r < 10; ++r)
+#if defined(VERSION_1)
+ {
+ mix_sub_columns(s1);
+ update_encrypt_key_128(o_key, &rc);
+ add_round_key(s1, o_key);
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ mix_sub_columns(s2, s1);
+ update_encrypt_key_128(o_key, &rc);
+ copy_and_key(s1, s2, o_key);
+ }
+#endif
+
+ shift_sub_rows(s1);
+ update_encrypt_key_128(o_key, &rc);
+ copy_and_key(out, s1, o_key);
+}
+
+#endif
+
+#if defined(AES_DEC_128_OTFK)
+
+/* The 'on the fly' decryption key update for for 128 bit keys */
+
+static void update_decrypt_key_128(uint_8t k[N_BLOCK], uint_8t* rc) {
+ uint_8t cc;
+
+ for (cc = 12; cc > 0; cc -= 4) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+ *rc = d2(*rc);
+ k[0] ^= s_box(k[13]) ^ *rc;
+ k[1] ^= s_box(k[14]);
+ k[2] ^= s_box(k[15]);
+ k[3] ^= s_box(k[12]);
+}
+
+/* Decrypt a single block of 16 bytes with 'on the fly' 128 bit keying */
+
+void aes_decrypt_128(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[N_BLOCK],
+ unsigned char o_key[N_BLOCK]) {
+ uint_8t s1[N_BLOCK], r, rc = 0x6c;
+ if (o_key != key) block_copy(o_key, key);
+
+ copy_and_key(s1, in, o_key);
+ inv_shift_sub_rows(s1);
+
+ for (r = 10; --r;)
+#if defined(VERSION_1)
+ {
+ update_decrypt_key_128(o_key, &rc);
+ add_round_key(s1, o_key);
+ inv_mix_sub_columns(s1);
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ update_decrypt_key_128(o_key, &rc);
+ copy_and_key(s2, s1, o_key);
+ inv_mix_sub_columns(s1, s2);
+ }
+#endif
+ update_decrypt_key_128(o_key, &rc);
+ copy_and_key(out, s1, o_key);
+}
+
+#endif
+
+#if defined(AES_ENC_256_OTFK)
+
+/* The 'on the fly' encryption key update for for 256 bit keys */
+
+static void update_encrypt_key_256(uint_8t k[2 * N_BLOCK], uint_8t* rc) {
+ uint_8t cc;
+
+ k[0] ^= s_box(k[29]) ^ *rc;
+ k[1] ^= s_box(k[30]);
+ k[2] ^= s_box(k[31]);
+ k[3] ^= s_box(k[28]);
+ *rc = f2(*rc);
+
+ for (cc = 4; cc < 16; cc += 4) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+
+ k[16] ^= s_box(k[12]);
+ k[17] ^= s_box(k[13]);
+ k[18] ^= s_box(k[14]);
+ k[19] ^= s_box(k[15]);
+
+ for (cc = 20; cc < 32; cc += 4) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+}
+
+/* Encrypt a single block of 16 bytes with 'on the fly' 256 bit keying */
+
+void aes_encrypt_256(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[2 * N_BLOCK],
+ unsigned char o_key[2 * N_BLOCK]) {
+ uint_8t s1[N_BLOCK], r, rc = 1;
+ if (o_key != key) {
+ block_copy(o_key, key);
+ block_copy(o_key + 16, key + 16);
+ }
+ copy_and_key(s1, in, o_key);
+
+ for (r = 1; r < 14; ++r)
+#if defined(VERSION_1)
+ {
+ mix_sub_columns(s1);
+ if (r & 1)
+ add_round_key(s1, o_key + 16);
+ else {
+ update_encrypt_key_256(o_key, &rc);
+ add_round_key(s1, o_key);
+ }
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ mix_sub_columns(s2, s1);
+ if (r & 1)
+ copy_and_key(s1, s2, o_key + 16);
+ else {
+ update_encrypt_key_256(o_key, &rc);
+ copy_and_key(s1, s2, o_key);
+ }
+ }
+#endif
+
+ shift_sub_rows(s1);
+ update_encrypt_key_256(o_key, &rc);
+ copy_and_key(out, s1, o_key);
+}
+
+#endif
+
+#if defined(AES_DEC_256_OTFK)
+
+/* The 'on the fly' encryption key update for for 256 bit keys */
+
+static void update_decrypt_key_256(uint_8t k[2 * N_BLOCK], uint_8t* rc) {
+ uint_8t cc;
+
+ for (cc = 28; cc > 16; cc -= 4) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+
+ k[16] ^= s_box(k[12]);
+ k[17] ^= s_box(k[13]);
+ k[18] ^= s_box(k[14]);
+ k[19] ^= s_box(k[15]);
+
+ for (cc = 12; cc > 0; cc -= 4) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+
+ *rc = d2(*rc);
+ k[0] ^= s_box(k[29]) ^ *rc;
+ k[1] ^= s_box(k[30]);
+ k[2] ^= s_box(k[31]);
+ k[3] ^= s_box(k[28]);
+}
+
+/* Decrypt a single block of 16 bytes with 'on the fly'
+ 256 bit keying
+*/
+void aes_decrypt_256(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[2 * N_BLOCK],
+ unsigned char o_key[2 * N_BLOCK]) {
+ uint_8t s1[N_BLOCK], r, rc = 0x80;
+
+ if (o_key != key) {
+ block_copy(o_key, key);
+ block_copy(o_key + 16, key + 16);
+ }
+
+ copy_and_key(s1, in, o_key);
+ inv_shift_sub_rows(s1);
+
+ for (r = 14; --r;)
+#if defined(VERSION_1)
+ {
+ if ((r & 1)) {
+ update_decrypt_key_256(o_key, &rc);
+ add_round_key(s1, o_key + 16);
+ } else
+ add_round_key(s1, o_key);
+ inv_mix_sub_columns(s1);
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ if ((r & 1)) {
+ update_decrypt_key_256(o_key, &rc);
+ copy_and_key(s2, s1, o_key + 16);
+ } else
+ copy_and_key(s2, s1, o_key);
+ inv_mix_sub_columns(s1, s2);
+ }
+#endif
+ copy_and_key(out, s1, o_key);
+}
+
+#endif
diff --git a/stack/smp/aes.h b/gd/crypto_toolbox/aes.h
similarity index 100%
copy from stack/smp/aes.h
copy to gd/crypto_toolbox/aes.h
diff --git a/gd/crypto_toolbox/aes_cmac.cc b/gd/crypto_toolbox/aes_cmac.cc
new file mode 100644
index 0000000..a58a5af
--- /dev/null
+++ b/gd/crypto_toolbox/aes_cmac.cc
@@ -0,0 +1,202 @@
+/******************************************************************************
+ *
+ * Copyright 2008-2012 Broadcom 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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the implementation of the AES128 and AES CMAC algorithm.
+ *
+ ******************************************************************************/
+
+#include "crypto_toolbox/aes.h"
+#include "crypto_toolbox/crypto_toolbox.h"
+
+namespace bluetooth {
+namespace crypto_toolbox {
+
+namespace {
+
+typedef struct {
+ uint8_t* text;
+ uint16_t len;
+ uint16_t round;
+} tCMAC_CB;
+
+thread_local tCMAC_CB cmac_cb;
+
+/* Rb for AES-128 as block cipher, LSB as [0] */
+Octet16 const_Rb{0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+/** utility function to do an biteise exclusive-OR of two bit strings of the
+ * length of OCTET16_LEN. Result is stored in first argument.
+ */
+static void xor_128(Octet16* a, const Octet16& b) {
+ // CHECK(a);
+ uint8_t i, *aa = a->data();
+ const uint8_t* bb = b.data();
+
+ for (i = 0; i < OCTET16_LEN; i++) {
+ aa[i] = aa[i] ^ bb[i];
+ }
+}
+} // namespace
+
+/* This function computes AES_128(key, message) */
+Octet16 aes_128(const Octet16& key, const Octet16& message) {
+ Octet16 key_reversed;
+ Octet16 message_reversed;
+ Octet16 output;
+
+ std::reverse_copy(key.begin(), key.end(), key_reversed.begin());
+ std::reverse_copy(message.begin(), message.end(), message_reversed.begin());
+
+ aes_context ctx;
+ aes_set_key(key_reversed.data(), key_reversed.size(), &ctx);
+ aes_encrypt(message_reversed.data(), output.data(), &ctx);
+
+ std::reverse(output.begin(), output.end());
+ return output;
+}
+
+/** utility function to padding the given text to be a 128 bits data. The
+ * parameter dest is input and output parameter, it must point to a
+ * OCTET16_LEN memory space; where include length bytes valid data. */
+static void padding(Octet16* dest, uint8_t length) {
+ uint8_t i, *p = dest->data();
+ /* original last block */
+ for (i = length; i < OCTET16_LEN; i++) p[OCTET16_LEN - i - 1] = (i == length) ? 0x80 : 0;
+}
+
+/** utility function to left shift one bit for a 128 bits value. */
+static void leftshift_onebit(uint8_t* input, uint8_t* output) {
+ uint8_t i, overflow = 0, next_overflow = 0;
+ /* input[0] is LSB */
+ for (i = 0; i < OCTET16_LEN; i++) {
+ next_overflow = (input[i] & 0x80) ? 1 : 0;
+ output[i] = (input[i] << 1) | overflow;
+ overflow = next_overflow;
+ }
+ return;
+}
+
+/** This function is the calculation of block cipher using AES-128. */
+static Octet16 cmac_aes_k_calculate(const Octet16& key) {
+ Octet16 output;
+ Octet16 x{0}; // zero initialized
+
+ uint8_t i = 1;
+ while (i <= cmac_cb.round) {
+ /* Mi' := Mi (+) X */
+ xor_128((Octet16*)&cmac_cb.text[(cmac_cb.round - i) * OCTET16_LEN], x);
+
+ output = aes_128(key, &cmac_cb.text[(cmac_cb.round - i) * OCTET16_LEN], OCTET16_LEN);
+ x = output;
+ i++;
+ }
+
+ return output;
+}
+
+/** This function proceeed to prepare the last block of message Mn depending on
+ * the size of the message.
+ */
+static void cmac_prepare_last_block(const Octet16& k1, const Octet16& k2) {
+ // uint8_t x[16] = {0};
+ bool flag;
+
+ /* last block is a complete block set flag to 1 */
+ flag = ((cmac_cb.len % OCTET16_LEN) == 0 && cmac_cb.len != 0) ? true : false;
+
+ if (flag) { /* last block is complete block */
+ xor_128((Octet16*)&cmac_cb.text[0], k1);
+ } else /* padding then xor with k2 */
+ {
+ padding((Octet16*)&cmac_cb.text[0], (uint8_t)(cmac_cb.len % 16));
+
+ xor_128((Octet16*)&cmac_cb.text[0], k2);
+ }
+}
+
+/** This is the function to generate the two subkeys.
+ * |key| is CMAC key, expect SRK when used by SMP.
+ */
+static void cmac_generate_subkey(const Octet16& key) {
+ Octet16 zero{};
+ Octet16 p = aes_128(key, zero.data(), OCTET16_LEN);
+
+ Octet16 k1, k2;
+ uint8_t* pp = p.data();
+
+ /* If MSB(L) = 0, then K1 = L << 1 */
+ if ((pp[OCTET16_LEN - 1] & 0x80) != 0) {
+ /* Else K1 = ( L << 1 ) (+) Rb */
+ leftshift_onebit(pp, k1.data());
+ xor_128(&k1, const_Rb);
+ } else {
+ leftshift_onebit(pp, k1.data());
+ }
+
+ if ((k1[OCTET16_LEN - 1] & 0x80) != 0) {
+ /* K2 = (K1 << 1) (+) Rb */
+ leftshift_onebit(k1.data(), k2.data());
+ xor_128(&k2, const_Rb);
+ } else {
+ /* If MSB(K1) = 0, then K2 = K1 << 1 */
+ leftshift_onebit(k1.data(), k2.data());
+ }
+
+ cmac_prepare_last_block(k1, k2);
+}
+
+/** key - CMAC key in little endian order
+ * input - text to be signed in little endian byte order.
+ * length - length of the input in byte.
+ */
+Octet16 aes_cmac(const Octet16& key, const uint8_t* input, uint16_t length) {
+ uint16_t len, diff;
+ /* n is number of rounds */
+ uint16_t n = (length + OCTET16_LEN - 1) / OCTET16_LEN;
+
+ if (n == 0) n = 1;
+ len = n * OCTET16_LEN;
+
+ /* allocate a memory space of multiple of 16 bytes to hold text */
+ cmac_cb.text = (uint8_t*)alloca(len);
+ cmac_cb.round = n;
+ diff = len - length;
+
+ if (input != NULL && length > 0) {
+ memcpy(&cmac_cb.text[diff], input, (int)length);
+ cmac_cb.len = length;
+ } else {
+ cmac_cb.len = 0;
+ }
+
+ /* prepare calculation for subkey s and last block of data */
+ cmac_generate_subkey(key);
+ /* start calculation */
+ Octet16 signature = cmac_aes_k_calculate(key);
+
+ /* clean up */
+ memset(&cmac_cb, 0, sizeof(tCMAC_CB));
+ // cmac_cb.text is auto-freed by alloca
+
+ return signature;
+}
+
+} // namespace crypto_toolbox
+} // namespace bluetooth
diff --git a/gd/crypto_toolbox/crypto_toolbox.cc b/gd/crypto_toolbox/crypto_toolbox.cc
new file mode 100644
index 0000000..1b2c06d
--- /dev/null
+++ b/gd/crypto_toolbox/crypto_toolbox.cc
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2018 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 "crypto_toolbox/crypto_toolbox.h"
+#include "crypto_toolbox/aes.h"
+
+#include <endian.h>
+#include <algorithm>
+
+namespace bluetooth {
+namespace crypto_toolbox {
+
+constexpr int OCTET32_LEN = 32;
+
+Octet16 h6(const Octet16& w, std::array<uint8_t, 4> keyid) {
+ return aes_cmac(w, keyid.data(), keyid.size());
+}
+
+Octet16 h7(const Octet16& salt, const Octet16& w) {
+ return aes_cmac(salt, w.data(), w.size());
+}
+
+Octet16 f4(uint8_t* u, uint8_t* v, const Octet16& x, uint8_t z) {
+ constexpr size_t msg_len = OCTET32_LEN /* U size */ + OCTET32_LEN /* V size */ + 1 /* Z size */;
+
+ // DVLOG(2) << "U=" << HexEncode(u, OCTET32_LEN) << ", V=" << HexEncode(v, OCTET32_LEN)
+ // << ", X=" << HexEncode(x.data(), x.size()) << ", Z=" << std::hex << +z;
+
+ std::array<uint8_t, msg_len> msg;
+ auto it = msg.begin();
+ it = std::copy(&z, &z + 1, it);
+ it = std::copy(v, v + OCTET32_LEN, it);
+ it = std::copy(u, u + OCTET32_LEN, it);
+ return aes_cmac(x, msg.data(), msg.size());
+}
+
+/** helper for f5 */
+static Octet16 calculate_mac_key_or_ltk(const Octet16& t, uint8_t counter, uint8_t* key_id, const Octet16& n1,
+ const Octet16& n2, uint8_t* a1, uint8_t* a2, uint8_t* length) {
+ constexpr size_t msg_len = 1 /* Counter size */ + 4 /* keyID size */ + OCTET16_LEN /* N1 size */ +
+ OCTET16_LEN /* N2 size */ + 7 /* A1 size*/ + 7 /* A2 size*/ + 2 /* Length size */;
+
+ std::array<uint8_t, msg_len> msg;
+ auto it = msg.begin();
+ it = std::copy(length, length + 2, it);
+ it = std::copy(a2, a2 + 7, it);
+ it = std::copy(a1, a1 + 7, it);
+ it = std::copy(n2.begin(), n2.end(), it);
+ it = std::copy(n1.begin(), n1.end(), it);
+ it = std::copy(key_id, key_id + 4, it);
+ it = std::copy(&counter, &counter + 1, it);
+
+ return aes_cmac(t, msg.data(), msg.size());
+}
+
+void f5(uint8_t* w, const Octet16& n1, const Octet16& n2, uint8_t* a1, uint8_t* a2, Octet16* mac_key, Octet16* ltk) {
+ // DVLOG(2) << __func__ << "W=" << HexEncode(w, OCTET32_LEN) << ", N1=" << HexEncode(n1.data(), n1.size())
+ // << ", N2=" << HexEncode(n2.data(), n2.size()) << ", A1=" << HexEncode(a1, 7) << ", A2=" << HexEncode(a2,
+ // 7);
+
+ const Octet16 salt{0xBE, 0x83, 0x60, 0x5A, 0xDB, 0x0B, 0x37, 0x60, 0x38, 0xA5, 0xF5, 0xAA, 0x91, 0x83, 0x88, 0x6C};
+ Octet16 t = aes_cmac(salt, w, OCTET32_LEN);
+
+ // DVLOG(2) << "T=" << HexEncode(t.data(), t.size());
+
+ uint8_t key_id[4] = {0x65, 0x6c, 0x74, 0x62}; /* 0x62746c65 */
+ uint8_t length[2] = {0x00, 0x01}; /* 0x0100 */
+
+ *mac_key = calculate_mac_key_or_ltk(t, 0, key_id, n1, n2, a1, a2, length);
+
+ *ltk = calculate_mac_key_or_ltk(t, 1, key_id, n1, n2, a1, a2, length);
+
+ // DVLOG(2) << "mac_key=" << HexEncode(mac_key->data(), mac_key->size());
+ // DVLOG(2) << "ltk=" << HexEncode(ltk->data(), ltk->size());
+}
+
+Octet16 f6(const Octet16& w, const Octet16& n1, const Octet16& n2, const Octet16& r, uint8_t* iocap, uint8_t* a1,
+ uint8_t* a2) {
+ const uint8_t msg_len = OCTET16_LEN /* N1 size */ + OCTET16_LEN /* N2 size */ + OCTET16_LEN /* R size */ +
+ 3 /* IOcap size */ + 7 /* A1 size*/ + 7 /* A2 size*/;
+
+ // DVLOG(2) << __func__ << "W=" << HexEncode(w.data(), w.size()) << ", N1=" << HexEncode(n1.data(), n1.size())
+ // << ", N2=" << HexEncode(n2.data(), n2.size()) << ", R=" << HexEncode(r.data(), r.size())
+ // << ", IOcap=" << HexEncode(iocap, 3) << ", A1=" << HexEncode(a1, 7) << ", A2=" << HexEncode(a2, 7);
+
+ std::array<uint8_t, msg_len> msg;
+ auto it = msg.begin();
+ it = std::copy(a2, a2 + 7, it);
+ it = std::copy(a1, a1 + 7, it);
+ it = std::copy(iocap, iocap + 3, it);
+ it = std::copy(r.begin(), r.end(), it);
+ it = std::copy(n2.begin(), n2.end(), it);
+ it = std::copy(n1.begin(), n1.end(), it);
+
+ return aes_cmac(w, msg.data(), msg.size());
+}
+
+uint32_t g2(uint8_t* u, uint8_t* v, const Octet16& x, const Octet16& y) {
+ constexpr size_t msg_len = OCTET32_LEN /* U size */ + OCTET32_LEN /* V size */
+ + OCTET16_LEN /* Y size */;
+
+ // DVLOG(2) << __func__ << "U=" << HexEncode(u, OCTET32_LEN) << ", V=" << HexEncode(v, OCTET32_LEN)
+ // << ", X=" << HexEncode(x.data(), x.size()) << ", Y=" << HexEncode(y.data(), y.size());
+
+ std::array<uint8_t, msg_len> msg;
+ auto it = msg.begin();
+ it = std::copy(y.begin(), y.end(), it);
+ it = std::copy(v, v + OCTET32_LEN, it);
+ it = std::copy(u, u + OCTET32_LEN, it);
+
+ Octet16 cmac = aes_cmac(x, msg.data(), msg.size());
+
+ /* vres = cmac mod 2**32 mod 10**6 */
+ return le32toh(*(uint32_t*)cmac.data()) % 1000000;
+}
+
+Octet16 ltk_to_link_key(const Octet16& ltk, bool use_h7) {
+ Octet16 ilk; /* intermidiate link key */
+ if (use_h7) {
+ constexpr Octet16 salt{0x31, 0x70, 0x6D, 0x74, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ ilk = h7(salt, ltk);
+ } else {
+ /* "tmp1" mapping to extended ASCII, little endian*/
+ constexpr std::array<uint8_t, 4> keyID_tmp1 = {0x31, 0x70, 0x6D, 0x74};
+ ilk = h6(ltk, keyID_tmp1);
+ }
+
+ /* "lebr" mapping to extended ASCII, little endian */
+ constexpr std::array<uint8_t, 4> keyID_lebr = {0x72, 0x62, 0x65, 0x6c};
+ return h6(ilk, keyID_lebr);
+}
+
+Octet16 link_key_to_ltk(const Octet16& link_key, bool use_h7) {
+ Octet16 iltk; /* intermidiate long term key */
+ if (use_h7) {
+ constexpr Octet16 salt{0x32, 0x70, 0x6D, 0x74, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ iltk = h7(salt, link_key);
+ } else {
+ /* "tmp2" mapping to extended ASCII, little endian */
+ constexpr std::array<uint8_t, 4> keyID_tmp2 = {0x32, 0x70, 0x6D, 0x74};
+ iltk = h6(link_key, keyID_tmp2);
+ }
+
+ /* "brle" mapping to extended ASCII, little endian */
+ constexpr std::array<uint8_t, 4> keyID_brle = {0x65, 0x6c, 0x72, 0x62};
+ return h6(iltk, keyID_brle);
+}
+
+} // namespace crypto_toolbox
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/crypto_toolbox/crypto_toolbox.h b/gd/crypto_toolbox/crypto_toolbox.h
new file mode 100644
index 0000000..899c958
--- /dev/null
+++ b/gd/crypto_toolbox/crypto_toolbox.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 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 <array>
+
+namespace bluetooth {
+namespace crypto_toolbox {
+
+constexpr int OCTET16_LEN = 16;
+using Octet16 = std::array<uint8_t, OCTET16_LEN>;
+
+extern Octet16 aes_128(const Octet16& key, const Octet16& message);
+extern Octet16 aes_cmac(const Octet16& key, const uint8_t* message, uint16_t length);
+extern Octet16 f4(uint8_t* u, uint8_t* v, const Octet16& x, uint8_t z);
+extern void f5(uint8_t* w, const Octet16& n1, const Octet16& n2, uint8_t* a1, uint8_t* a2, Octet16* mac_key,
+ Octet16* ltk);
+extern Octet16 f6(const Octet16& w, const Octet16& n1, const Octet16& n2, const Octet16& r, uint8_t* iocap, uint8_t* a1,
+ uint8_t* a2);
+extern Octet16 h6(const Octet16& w, std::array<uint8_t, 4> keyid);
+extern Octet16 h7(const Octet16& salt, const Octet16& w);
+extern uint32_t g2(uint8_t* u, uint8_t* v, const Octet16& x, const Octet16& y);
+extern Octet16 ltk_to_link_key(const Octet16& ltk, bool use_h7);
+extern Octet16 link_key_to_ltk(const Octet16& link_key, bool use_h7);
+
+/* This function computes AES_128(key, message). |key| must be 128bit.
+ * |message| can be at most 16 bytes long, it's length in bytes is given in
+ * |length| */
+inline Octet16 aes_128(const Octet16& key, const uint8_t* message, const uint8_t length) {
+ // CHECK(length <= OCTET16_LEN) << "you tried aes_128 more than 16 bytes!";
+ Octet16 msg{0};
+ std::copy(message, message + length, msg.begin());
+ return aes_128(key, msg);
+}
+
+// |tlen| - lenth of mac desired
+// |p_signature| - data pointer to where signed data to be stored, tlen long.
+inline void aes_cmac(const Octet16& key, const uint8_t* message, uint16_t length, uint16_t tlen, uint8_t* p_signature) {
+ Octet16 signature = aes_cmac(key, message, length);
+
+ uint8_t* p_mac = signature.data() + (OCTET16_LEN - tlen);
+ memcpy(p_signature, p_mac, tlen);
+}
+
+inline Octet16 aes_cmac(const Octet16& key, const Octet16& message) {
+ return aes_cmac(key, message.data(), message.size());
+}
+
+} // namespace crypto_toolbox
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/crypto_toolbox/crypto_toolbox_test.cc b/gd/crypto_toolbox/crypto_toolbox_test.cc
new file mode 100644
index 0000000..b5674c1
--- /dev/null
+++ b/gd/crypto_toolbox/crypto_toolbox_test.cc
@@ -0,0 +1,355 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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 <gtest/gtest.h>
+
+#include "crypto_toolbox/aes.h"
+#include "crypto_toolbox/crypto_toolbox.h"
+
+#include <vector>
+
+namespace bluetooth {
+namespace crypto_toolbox {
+
+// BT Spec 5.0 | Vol 3, Part H D.1
+TEST(CryptoToolboxTest, bt_spec_test_d_1_test) {
+ uint8_t k[] = {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
+
+ uint8_t m[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+ uint8_t aes_cmac_k_m[] = {0x7d, 0xf7, 0x6b, 0x0c, 0x1a, 0xb8, 0x99, 0xb3,
+ 0x3e, 0x42, 0xf0, 0x47, 0xb9, 0x1b, 0x54, 0x6f};
+
+ uint8_t output[16];
+ aes_context ctx;
+ aes_set_key(k, sizeof(k), &ctx);
+ aes_encrypt(m, output, &ctx); /* outputs in byte 48 to byte 63 */
+
+ EXPECT_TRUE(memcmp(output, aes_cmac_k_m, OCTET16_LEN) == 0);
+
+ // useful for debugging
+ // LOG(INFO) << "k " << base::HexEncode(k, OCTET16_LEN);
+ // LOG(INFO) << "m " << base::HexEncode(m, sizeof(m));
+ // LOG(INFO) << "output " << base::HexEncode(output, OCTET16_LEN);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.1.1
+TEST(CryptoToolboxTest, bt_spec_example_d_1_1_test) {
+ Octet16 k{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
+
+ Octet16 aes_cmac_k_m{0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(k), std::end(k));
+ std::reverse(std::begin(aes_cmac_k_m), std::end(aes_cmac_k_m));
+
+ Octet16 output = aes_cmac(k, nullptr /* empty message */, 0);
+
+ EXPECT_EQ(output, aes_cmac_k_m);
+
+ // useful for debugging
+ // LOG(INFO) << "k " << base::HexEncode(k.data(), k.size());
+ // LOG(INFO) << "aes_cmac(k,nullptr) "
+ // << base::HexEncode(output.data(), output.size());
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.1.2
+TEST(CryptoToolboxTest, bt_spec_example_d_1_2_test) {
+ Octet16 k{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
+
+ Octet16 m = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a};
+
+ Octet16 aes_cmac_k_m{0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(k), std::end(k));
+ std::reverse(std::begin(m), std::end(m));
+ std::reverse(std::begin(aes_cmac_k_m), std::end(aes_cmac_k_m));
+
+ Octet16 output = aes_cmac(k, m);
+
+ EXPECT_EQ(output, aes_cmac_k_m);
+
+ // useful for debugging
+ // LOG(INFO) << "k " << base::HexEncode(k.data(), k.size());
+ // LOG(INFO) << "m " << base::HexEncode(m, sizeof(m));
+ // LOG(INFO) << "aes_cmac(k,m) "
+ // << base::HexEncode(output.data(), output.size());
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.1.3
+TEST(CryptoToolboxTest, bt_spec_example_d_1_3_test) {
+ Octet16 k{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
+
+ uint8_t m[] = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93,
+ 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac,
+ 0x45, 0xaf, 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11};
+
+ Octet16 aes_cmac_k_m{0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30, 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(k), std::end(k));
+ std::reverse(std::begin(m), std::end(m));
+ std::reverse(std::begin(aes_cmac_k_m), std::end(aes_cmac_k_m));
+
+ Octet16 output = aes_cmac(k, m, sizeof(m));
+ EXPECT_EQ(output, aes_cmac_k_m);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.1.4
+TEST(CryptoToolboxTest, bt_spec_example_d_1_4_test) {
+ Octet16 k{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
+
+ uint8_t m[] = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10};
+
+ Octet16 aes_cmac_k_m{0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(k), std::end(k));
+ std::reverse(std::begin(m), std::end(m));
+ std::reverse(std::begin(aes_cmac_k_m), std::end(aes_cmac_k_m));
+
+ Octet16 output = aes_cmac(k, m, sizeof(m));
+
+ EXPECT_EQ(output, aes_cmac_k_m);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.2
+TEST(CryptoToolboxTest, bt_spec_example_d_2_test) {
+ std::vector<uint8_t> u{0x20, 0xb0, 0x03, 0xd2, 0xf2, 0x97, 0xbe, 0x2c, 0x5e, 0x2c, 0x83,
+ 0xa7, 0xe9, 0xf9, 0xa5, 0xb9, 0xef, 0xf4, 0x91, 0x11, 0xac, 0xf4,
+ 0xfd, 0xdb, 0xcc, 0x03, 0x01, 0x48, 0x0e, 0x35, 0x9d, 0xe6};
+ std::vector<uint8_t> v{0x55, 0x18, 0x8b, 0x3d, 0x32, 0xf6, 0xbb, 0x9a, 0x90, 0x0a, 0xfc,
+ 0xfb, 0xee, 0xd4, 0xe7, 0x2a, 0x59, 0xcb, 0x9a, 0xc2, 0xf1, 0x9d,
+ 0x7c, 0xfb, 0x6b, 0x4f, 0xdd, 0x49, 0xf4, 0x7f, 0xc5, 0xfd};
+ Octet16 x{0xd5, 0xcb, 0x84, 0x54, 0xd1, 0x77, 0x73, 0x3e, 0xff, 0xff, 0xb2, 0xec, 0x71, 0x2b, 0xae, 0xab};
+ uint8_t z = 0x00;
+
+ Octet16 aes_cmac_k_m{0xf2, 0xc9, 0x16, 0xf1, 0x07, 0xa9, 0xbd, 0x1c, 0xf1, 0xed, 0xa1, 0xbe, 0xa9, 0x74, 0x87, 0x2d};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(u), std::end(u));
+ std::reverse(std::begin(v), std::end(v));
+ std::reverse(std::begin(x), std::end(x));
+ std::reverse(std::begin(aes_cmac_k_m), std::end(aes_cmac_k_m));
+
+ Octet16 output = f4(u.data(), v.data(), x, z);
+
+ EXPECT_EQ(output, aes_cmac_k_m);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.3
+TEST(CryptoToolboxTest, bt_spec_example_d_3_test) {
+ std::array<uint8_t, 32> dhkey_w{0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, 0x34, 0x10, 0x10,
+ 0xa6, 0x0a, 0x39, 0x7d, 0x9b, 0x99, 0x79, 0x6b, 0x13, 0xb4, 0xf8,
+ 0x66, 0xf1, 0x86, 0x8d, 0x34, 0xf3, 0x73, 0xbf, 0xa6, 0x98};
+ Octet16 n1{0xd5, 0xcb, 0x84, 0x54, 0xd1, 0x77, 0x73, 0x3e, 0xff, 0xff, 0xb2, 0xec, 0x71, 0x2b, 0xae, 0xab};
+ Octet16 n2{0xa6, 0xe8, 0xe7, 0xcc, 0x25, 0xa7, 0x5f, 0x6e, 0x21, 0x65, 0x83, 0xf7, 0xff, 0x3d, 0xc4, 0xcf};
+ std::array<uint8_t, 7> a1{0x00, 0x56, 0x12, 0x37, 0x37, 0xbf, 0xce};
+ std::array<uint8_t, 7> a2{0x00, 0xa7, 0x13, 0x70, 0x2d, 0xcf, 0xc1};
+
+ Octet16 expected_ltk{0x69, 0x86, 0x79, 0x11, 0x69, 0xd7, 0xcd, 0x23, 0x98, 0x05, 0x22, 0xb5, 0x94, 0x75, 0x0a, 0x38};
+ Octet16 expected_mac_key{0x29, 0x65, 0xf1, 0x76, 0xa1, 0x08, 0x4a, 0x02,
+ 0xfd, 0x3f, 0x6a, 0x20, 0xce, 0x63, 0x6e, 0x20};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(dhkey_w), std::end(dhkey_w));
+ std::reverse(std::begin(n1), std::end(n1));
+ std::reverse(std::begin(n2), std::end(n2));
+ std::reverse(std::begin(a1), std::end(a1));
+ std::reverse(std::begin(a2), std::end(a2));
+ std::reverse(std::begin(expected_ltk), std::end(expected_ltk));
+ std::reverse(std::begin(expected_mac_key), std::end(expected_mac_key));
+
+ Octet16 mac_key, ltk;
+ f5(dhkey_w.data(), n1, n2, a1.data(), a2.data(), &mac_key, <k);
+
+ EXPECT_EQ(mac_key, expected_mac_key);
+ EXPECT_EQ(ltk, expected_ltk);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.4
+TEST(CryptoToolboxTest, bt_spec_example_d_4_test) {
+ Octet16 n1{0xd5, 0xcb, 0x84, 0x54, 0xd1, 0x77, 0x73, 0x3e, 0xff, 0xff, 0xb2, 0xec, 0x71, 0x2b, 0xae, 0xab};
+ Octet16 n2{0xa6, 0xe8, 0xe7, 0xcc, 0x25, 0xa7, 0x5f, 0x6e, 0x21, 0x65, 0x83, 0xf7, 0xff, 0x3d, 0xc4, 0xcf};
+ Octet16 r{0x12, 0xa3, 0x34, 0x3b, 0xb4, 0x53, 0xbb, 0x54, 0x08, 0xda, 0x42, 0xd2, 0x0c, 0x2d, 0x0f, 0xc8};
+ std::vector<uint8_t> IOcap{0x01, 0x01, 0x02};
+ std::vector<uint8_t> a1{0x00, 0x56, 0x12, 0x37, 0x37, 0xbf, 0xce};
+ std::vector<uint8_t> a2{0x00, 0xa7, 0x13, 0x70, 0x2d, 0xcf, 0xc1};
+
+ Octet16 MacKey{0x29, 0x65, 0xf1, 0x76, 0xa1, 0x08, 0x4a, 0x02, 0xfd, 0x3f, 0x6a, 0x20, 0xce, 0x63, 0x6e, 0x20};
+
+ Octet16 expected_aes_cmac{0xe3, 0xc4, 0x73, 0x98, 0x9c, 0xd0, 0xe8, 0xc5,
+ 0xd2, 0x6c, 0x0b, 0x09, 0xda, 0x95, 0x8f, 0x61};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(n1), std::end(n1));
+ std::reverse(std::begin(n2), std::end(n2));
+ std::reverse(std::begin(r), std::end(r));
+ std::reverse(std::begin(IOcap), std::end(IOcap));
+ std::reverse(std::begin(a1), std::end(a1));
+ std::reverse(std::begin(a2), std::end(a2));
+ std::reverse(std::begin(MacKey), std::end(MacKey));
+ std::reverse(std::begin(expected_aes_cmac), std::end(expected_aes_cmac));
+
+ Octet16 aes_cmac = f6(MacKey, n1, n2, r, IOcap.data(), a1.data(), a2.data());
+
+ EXPECT_EQ(aes_cmac, expected_aes_cmac);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.5
+TEST(CryptoToolboxTest, bt_spec_example_d_5_test) {
+ std::array<uint8_t, 32> u{0x20, 0xb0, 0x03, 0xd2, 0xf2, 0x97, 0xbe, 0x2c, 0x5e, 0x2c, 0x83,
+ 0xa7, 0xe9, 0xf9, 0xa5, 0xb9, 0xef, 0xf4, 0x91, 0x11, 0xac, 0xf4,
+ 0xfd, 0xdb, 0xcc, 0x03, 0x01, 0x48, 0x0e, 0x35, 0x9d, 0xe6};
+ std::array<uint8_t, 32> v{0x55, 0x18, 0x8b, 0x3d, 0x32, 0xf6, 0xbb, 0x9a, 0x90, 0x0a, 0xfc,
+ 0xfb, 0xee, 0xd4, 0xe7, 0x2a, 0x59, 0xcb, 0x9a, 0xc2, 0xf1, 0x9d,
+ 0x7c, 0xfb, 0x6b, 0x4f, 0xdd, 0x49, 0xf4, 0x7f, 0xc5, 0xfd};
+
+ Octet16 x{0xd5, 0xcb, 0x84, 0x54, 0xd1, 0x77, 0x73, 0x3e, 0xff, 0xff, 0xb2, 0xec, 0x71, 0x2b, 0xae, 0xab};
+ Octet16 y{0xa6, 0xe8, 0xe7, 0xcc, 0x25, 0xa7, 0x5f, 0x6e, 0x21, 0x65, 0x83, 0xf7, 0xff, 0x3d, 0xc4, 0xcf};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(u), std::end(u));
+ std::reverse(std::begin(v), std::end(v));
+ std::reverse(std::begin(x), std::end(x));
+ std::reverse(std::begin(y), std::end(y));
+
+ uint32_t val = g2(u.data(), v.data(), x, y);
+
+ /* the returned value is already mod 1000000, so do mod on the test result
+ * value too */
+ EXPECT_EQ(val, 0x2f9ed5baU % 1000000);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.6
+TEST(CryptoToolboxTest, bt_spec_example_d_6_test) {
+ Octet16 key{0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b};
+ std::array<uint8_t, 4> keyID{0x6c, 0x65, 0x62, 0x72};
+ Octet16 expected_aes_cmac{0x2d, 0x9a, 0xe1, 0x02, 0xe7, 0x6d, 0xc9, 0x1c,
+ 0xe8, 0xd3, 0xa9, 0xe2, 0x80, 0xb1, 0x63, 0x99};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(key), std::end(key));
+ std::reverse(std::begin(keyID), std::end(keyID));
+ std::reverse(std::begin(expected_aes_cmac), std::end(expected_aes_cmac));
+
+ Octet16 aes_cmac = h6(key, keyID);
+ EXPECT_EQ(aes_cmac, expected_aes_cmac);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.7
+TEST(CryptoToolboxTest, bt_spec_example_d_7_test) {
+ Octet16 IRK{0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b};
+ Octet16 prand{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x81, 0x94};
+ Octet16 expected_aes_128{0x15, 0x9d, 0x5f, 0xb7, 0x2e, 0xbe, 0x23, 0x11,
+ 0xa4, 0x8c, 0x1b, 0xdc, 0xc4, 0x0d, 0xfb, 0xaa};
+ std::array<uint8_t, 3> expected_ah{0x0d, 0xfb, 0xaa};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(IRK), std::end(IRK));
+ std::reverse(std::begin(prand), std::end(prand));
+ std::reverse(std::begin(expected_aes_128), std::end(expected_aes_128));
+ std::reverse(std::begin(expected_ah), std::end(expected_ah));
+
+ Octet16 result = aes_128(IRK, prand.data(), 3);
+ EXPECT_EQ(expected_aes_128, result);
+
+ // little/big endian 24 bits
+ EXPECT_EQ(result[0], expected_ah[0]);
+ EXPECT_EQ(result[1], expected_ah[1]);
+ EXPECT_EQ(result[2], expected_ah[2]);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.8
+TEST(CryptoToolboxTest, bt_spec_example_d_8_test) {
+ Octet16 Key{0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b};
+ Octet16 SALT{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x6D, 0x70, 0x31};
+ Octet16 expected_aes_cmac{0xfb, 0x17, 0x35, 0x97, 0xc6, 0xa3, 0xc0, 0xec,
+ 0xd2, 0x99, 0x8c, 0x2a, 0x75, 0xa5, 0x70, 0x11};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(Key), std::end(Key));
+ std::reverse(std::begin(SALT), std::end(SALT));
+ std::reverse(std::begin(expected_aes_cmac), std::end(expected_aes_cmac));
+
+ Octet16 aes_cmac = h7(SALT, Key);
+ EXPECT_EQ(expected_aes_cmac, aes_cmac);
+}
+
+extern Octet16 smp_calculate_ltk_to_link_key(const Octet16& ltk, bool use_h7);
+
+// BT Spec 5.0 | Vol 3, Part H D.9
+TEST(CryptoToolboxTest, bt_spec_example_d_9_test) {
+ Octet16 LTK{0x36, 0x8d, 0xf9, 0xbc, 0xe3, 0x26, 0x4b, 0x58, 0xbd, 0x06, 0x6c, 0x33, 0x33, 0x4f, 0xbf, 0x64};
+ Octet16 expected_link_key{0x28, 0x7a, 0xd3, 0x79, 0xdc, 0xa4, 0x02, 0x53,
+ 0x0a, 0x39, 0xf1, 0xf4, 0x30, 0x47, 0xb8, 0x35};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(LTK), std::end(LTK));
+ std::reverse(std::begin(expected_link_key), std::end(expected_link_key));
+
+ Octet16 link_key = ltk_to_link_key(LTK, true);
+ EXPECT_EQ(expected_link_key, link_key);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.10
+TEST(CryptoToolboxTest, bt_spec_example_d_10_test) {
+ Octet16 LTK{0x36, 0x8d, 0xf9, 0xbc, 0xe3, 0x26, 0x4b, 0x58, 0xbd, 0x06, 0x6c, 0x33, 0x33, 0x4f, 0xbf, 0x64};
+ Octet16 expected_link_key{0xbc, 0x1c, 0xa4, 0xef, 0x63, 0x3f, 0xc1, 0xbd,
+ 0x0d, 0x82, 0x30, 0xaf, 0xee, 0x38, 0x8f, 0xb0};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(LTK), std::end(LTK));
+ std::reverse(std::begin(expected_link_key), std::end(expected_link_key));
+
+ Octet16 link_key = ltk_to_link_key(LTK, false);
+ EXPECT_EQ(expected_link_key, link_key);
+}
+
+// // BT Spec 5.0 | Vol 3, Part H D.11
+TEST(CryptoToolboxTest, bt_spec_example_d_11_test) {
+ Octet16 link_key{0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00};
+ Octet16 expected_ltk{0xe8, 0x5e, 0x09, 0xeb, 0x5e, 0xcc, 0xb3, 0xe2, 0x69, 0x41, 0x8a, 0x13, 0x32, 0x11, 0xbc, 0x79};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(link_key), std::end(link_key));
+ std::reverse(std::begin(expected_ltk), std::end(expected_ltk));
+
+ Octet16 ltk = link_key_to_ltk(link_key, true);
+ EXPECT_EQ(expected_ltk, ltk);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.12
+TEST(CryptoToolboxTest, bt_spec_example_d_12_test) {
+ Octet16 link_key{0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00};
+ Octet16 expected_ltk{0xa8, 0x13, 0xfb, 0x72, 0xf1, 0xa3, 0xdf, 0xa1, 0x8a, 0x2c, 0x9a, 0x43, 0xf1, 0x0d, 0x0a, 0x30};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(link_key), std::end(link_key));
+ std::reverse(std::begin(expected_ltk), std::end(expected_ltk));
+
+ Octet16 ltk = link_key_to_ltk(link_key, false);
+ EXPECT_EQ(expected_ltk, ltk);
+}
+
+} // namespace crypto_toolbox
+} // namespace bluetooth
diff --git a/gd/facade/common.proto b/gd/facade/common.proto
new file mode 100644
index 0000000..1c4a764
--- /dev/null
+++ b/gd/facade/common.proto
@@ -0,0 +1,21 @@
+syntax = "proto3";
+
+package bluetooth.facade;
+
+enum EventSubscriptionMode {
+ UNCHANGED = 0;
+ SUBSCRIBE = 1;
+ UNSUBSCRIBE = 2;
+}
+
+enum EventFetchMode {
+ NONE = 0;
+ ALL_CURRENT = 1;
+ AT_LEAST_ONE = 2;
+}
+
+message EventStreamRequest {
+ EventSubscriptionMode subscription_mode = 1;
+ EventFetchMode fetch_mode = 2;
+ uint32 timeout_ms = 3;
+}
diff --git a/gd/facade/facade_main.cc b/gd/facade/facade_main.cc
new file mode 100644
index 0000000..4236923
--- /dev/null
+++ b/gd/facade/facade_main.cc
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2019 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 "stack_manager.h"
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <csignal>
+#include <cstring>
+#include <string>
+#include <thread>
+
+#include "facade/grpc_root_server.h"
+#include "grpc/grpc_module.h"
+#include "hal/hci_hal.h"
+#include "hal/hci_hal_host_rootcanal.h"
+#include "hal/snoop_logger.h"
+
+using ::bluetooth::hal::HciHalHostRootcanalConfig;
+using ::bluetooth::StackManager;
+using ::bluetooth::grpc::GrpcModule;
+using ::bluetooth::ModuleList;
+using ::bluetooth::os::Thread;
+
+namespace {
+::bluetooth::facade::GrpcRootServer grpc_root_server;
+
+void interrupt_handler(int) {
+ grpc_root_server.StopServer();
+}
+} // namespace
+
+// The entry point for the binary with libbluetooth + facades
+int main(int argc, const char** argv) {
+ int root_server_port = 8897;
+ int grpc_port = 8899;
+
+ const std::string arg_grpc_root_server_port = "--root-server-port=";
+ const std::string arg_grpc_server_port = "--grpc-port=";
+ const std::string arg_rootcanal_port = "--rootcanal-port=";
+ const std::string arg_btsnoop_path = "--btsnoop=";
+ std::string btsnoop_path;
+ const std::string arg_tester_signal_socket = "--tester-signal-socket=";
+ std::string tester_signal_path;
+ for (int i = 1; i < argc; i++) {
+ std::string arg = argv[i];
+ if (arg.find(arg_grpc_root_server_port) == 0) {
+ auto port_number = arg.substr(arg_grpc_root_server_port.size());
+ root_server_port = std::stoi(port_number);
+ }
+ if (arg.find(arg_grpc_server_port) == 0) {
+ auto port_number = arg.substr(arg_grpc_server_port.size());
+ grpc_port = std::stoi(port_number);
+ }
+ if (arg.find(arg_rootcanal_port) == 0) {
+ auto port_number = arg.substr(arg_rootcanal_port.size());
+ HciHalHostRootcanalConfig::Get()->SetPort(std::stoi(port_number));
+ }
+ if (arg.find(arg_btsnoop_path) == 0) {
+ btsnoop_path = arg.substr(arg_btsnoop_path.size());
+ ::bluetooth::hal::SnoopLogger::SetFilePath(btsnoop_path);
+ }
+ if (arg.find(arg_tester_signal_socket) == 0) {
+ tester_signal_path = arg.substr(arg_tester_signal_socket.size());
+ }
+ }
+
+ signal(SIGINT, interrupt_handler);
+ grpc_root_server.StartServer("0.0.0.0", root_server_port, grpc_port);
+ int tester_signal_socket = socket(AF_UNIX, SOCK_STREAM, 0);
+ struct sockaddr_un addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, tester_signal_path.c_str(), tester_signal_path.size() + 1);
+ connect(tester_signal_socket, (sockaddr*)&addr, sizeof(addr));
+ close(tester_signal_socket);
+ auto wait_thread = std::thread([] { grpc_root_server.RunGrpcLoop(); });
+ wait_thread.join();
+
+ return 0;
+}
diff --git a/gd/facade/grpc_root_server.cc b/gd/facade/grpc_root_server.cc
new file mode 100644
index 0000000..e03cded
--- /dev/null
+++ b/gd/facade/grpc_root_server.cc
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2019 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 "facade/grpc_root_server.h"
+
+#include <string>
+
+#include "facade/rootservice.grpc.pb.h"
+#include "grpc/grpc_module.h"
+#include "hal/facade.h"
+#include "os/log.h"
+#include "os/thread.h"
+#include "stack_manager.h"
+
+namespace bluetooth {
+namespace facade {
+
+using ::bluetooth::grpc::GrpcModule;
+using ::bluetooth::os::Thread;
+
+namespace {
+class RootFacadeService : public ::bluetooth::facade::RootFacade::Service {
+ public:
+ RootFacadeService(int grpc_port) : grpc_port_(grpc_port) {}
+
+ ::grpc::Status StartStack(::grpc::ServerContext* context, const ::bluetooth::facade::StartStackRequest* request,
+ ::bluetooth::facade::StartStackResponse* response) override {
+ if (is_running_) {
+ return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "stack is running");
+ }
+
+ ModuleList modules;
+ modules.add<::bluetooth::grpc::GrpcModule>();
+
+ BluetoothModule module_under_test = request->module_under_test();
+ switch (module_under_test) {
+ case BluetoothModule::HAL:
+ modules.add<::bluetooth::hal::HciHalFacadeModule>();
+ break;
+ default:
+ return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "invalid module under test");
+ }
+
+ stack_thread_ = new Thread("stack_thread", Thread::Priority::NORMAL);
+ stack_manager_.StartUp(&modules, stack_thread_);
+
+ GrpcModule* grpc_module = stack_manager_.GetInstance<GrpcModule>();
+ grpc_module->StartServer("0.0.0.0", grpc_port_);
+
+ grpc_loop_thread_ = new std::thread([grpc_module] { grpc_module->RunGrpcLoop(); });
+ is_running_ = true;
+
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status StopStack(::grpc::ServerContext* context, const ::bluetooth::facade::StopStackRequest* request,
+ ::bluetooth::facade::StopStackResponse* response) override {
+ if (!is_running_) {
+ return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "stack is not running");
+ }
+
+ stack_manager_.GetInstance<GrpcModule>()->StopServer();
+ grpc_loop_thread_->join();
+
+ stack_manager_.ShutDown();
+ delete stack_thread_;
+ is_running_ = false;
+ return ::grpc::Status::OK;
+ }
+
+ private:
+ Thread* stack_thread_ = nullptr;
+ bool is_running_ = false;
+ std::thread* grpc_loop_thread_ = nullptr;
+ StackManager stack_manager_;
+ int grpc_port_ = 8898;
+};
+
+RootFacadeService* root_facade_service;
+} // namespace
+
+void GrpcRootServer::StartServer(const std::string& address, int grpc_root_server_port, int grpc_port) {
+ ASSERT(!started_);
+ started_ = true;
+
+ std::string listening_port = address + ":" + std::to_string(grpc_root_server_port);
+ ::grpc::ServerBuilder builder;
+ root_facade_service = new RootFacadeService(grpc_port);
+ builder.RegisterService(root_facade_service);
+ builder.AddListeningPort(listening_port, ::grpc::InsecureServerCredentials());
+ server_ = builder.BuildAndStart();
+
+ ASSERT(server_ != nullptr);
+}
+
+void GrpcRootServer::StopServer() {
+ ASSERT(started_);
+ server_->Shutdown();
+ started_ = false;
+ server_.reset();
+ delete root_facade_service;
+}
+
+void GrpcRootServer::RunGrpcLoop() {
+ ASSERT(started_);
+ server_->Wait();
+}
+
+} // namespace facade
+} // namespace bluetooth
diff --git a/gd/facade/grpc_root_server.h b/gd/facade/grpc_root_server.h
new file mode 100644
index 0000000..9deba35
--- /dev/null
+++ b/gd/facade/grpc_root_server.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2019 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 <memory>
+#include <string>
+
+#include <grpc++/grpc++.h>
+
+namespace bluetooth {
+namespace facade {
+
+class GrpcRootServer {
+ public:
+ void StartServer(const std::string& address, int grpc_root_server_port, int grpc_port);
+
+ void StopServer();
+
+ void RunGrpcLoop();
+
+ private:
+ bool started_ = false;
+ std::unique_ptr<::grpc::Server> server_ = nullptr;
+};
+
+} // namespace facade
+} // namespace bluetooth
diff --git a/gd/facade/rootservice.proto b/gd/facade/rootservice.proto
new file mode 100644
index 0000000..7bf45ca
--- /dev/null
+++ b/gd/facade/rootservice.proto
@@ -0,0 +1,25 @@
+syntax = "proto3";
+
+package bluetooth.facade;
+
+service RootFacade {
+ rpc StartStack(StartStackRequest) returns (StartStackResponse) {}
+ rpc StopStack(StopStackRequest) returns (StopStackResponse) {}
+}
+
+enum BluetoothModule {
+ HAL = 0;
+ HCI = 1;
+ L2CAP = 2;
+ SECURITY = 3;
+}
+
+message StartStackRequest {
+ BluetoothModule module_under_test = 1;
+}
+
+message StartStackResponse {}
+
+message StopStackRequest {}
+
+message StopStackResponse {}
diff --git a/gd/grpc/async_grpc.h b/gd/grpc/async_grpc.h
new file mode 100644
index 0000000..7cde95d
--- /dev/null
+++ b/gd/grpc/async_grpc.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2019 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 <future>
+#include <memory>
+#include <mutex>
+
+#include <grpc++/grpc++.h>
+
+#include "os/log.h"
+
+namespace bluetooth {
+namespace grpc {
+
+// To be passed to gRPC async invocations as tag.
+// Function is called when the CompletionQueue.Next() returns this tag.
+// Then, user needs to delete this object.
+using GrpcAsyncEventCallback = std::function<void(bool)>;
+
+template <typename REQ, typename RES>
+class GrpcAsyncServerStreamingHandler {
+ public:
+ virtual ~GrpcAsyncServerStreamingHandler() = default;
+
+ // Implementation for requesting the next specific type RPC, using provided parameters.
+ virtual void OnReadyForNextRequest(::grpc::ServerContext*, REQ* req, ::grpc::ServerAsyncWriter<RES>* res,
+ ::grpc::CompletionQueue* new_call_cq,
+ ::grpc::ServerCompletionQueue* notification_cq, void* tag) = 0;
+
+ virtual void OnRpcRequestReceived(REQ req) = 0;
+
+ virtual void OnRpcRequestFailed() {}
+
+ virtual void OnRpcFinished() {}
+
+ virtual void OnWriteSuccess() {}
+};
+
+// Provides API to upper layer users to control (request, write, finish) a server-streaming asynchronous RPC.
+// When each API is done, callback will be sent to the given GrpcAsyncServerStreamingHandler.
+// Each control box can take one active RPC at one time.
+
+// TODO: problems with this control box:
+// 1. RequestNewRpc is async, but Write and Stop is blocking users. Do we want to do this?
+// 2. Callback to user is done in the gRPC thread. Let's create a pool thread to give it to user?
+// 3. Currently it uses promise to synchronize between events. If we use os/handler it should be easier.
+template <typename REQ, typename RES>
+class GrpcAsyncServerStreamingControlBox {
+ public:
+ GrpcAsyncServerStreamingControlBox(GrpcAsyncServerStreamingHandler<REQ, RES>* async_handler,
+ ::grpc::ServerCompletionQueue* cq)
+ : async_handler_(async_handler), cq_(cq) {}
+
+ void RequestNewRpc() {
+ ASSERT(my_state_ == MyState::IDLE);
+ context_ = std::make_unique<::grpc::ServerContext>();
+ req_ = std::make_unique<REQ>();
+ res_ = std::make_unique<::grpc::ServerAsyncWriter<RES>>(context_.get());
+ request_done_ = std::make_unique<GrpcAsyncEventCallback>([this](bool ok) { this->RequestDone(ok); });
+ async_handler_->OnReadyForNextRequest(context_.get(), req_.get(), res_.get(), cq_, cq_, request_done_.get());
+ my_state_ = MyState::REQUESTING;
+ }
+
+ void Write(const RES& res) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ if (my_state_ == MyState::IDLE || my_state_ == MyState::REQUESTING) {
+ LOG_INFO("stream already stopped");
+ return;
+ }
+ ASSERT(my_state_ == MyState::OPEN);
+ write_done_ = std::make_unique<GrpcAsyncEventCallback>([this](bool ok) { this->WriteDone(ok); });
+ my_state_ = MyState::WRITING;
+ res_->Write(res, write_done_.get());
+ promise_ = new std::promise<void>();
+ auto future = promise_->get_future();
+ future.wait();
+ }
+
+ void StopStreaming() {
+ std::unique_lock<std::mutex> lock(mutex_);
+ ASSERT(my_state_ == MyState::OPEN);
+ rpc_finish_ = std::make_unique<GrpcAsyncEventCallback>([this](bool ok) { this->RpcFinish(ok); });
+ my_state_ = MyState::FINISHING;
+ res_->Finish(::grpc::Status::OK, rpc_finish_.get());
+ promise_ = new std::promise<void>();
+ auto future = promise_->get_future();
+ future.wait();
+ }
+
+ private:
+ void RequestDone(bool ok) {
+ ASSERT(my_state_ == MyState::REQUESTING);
+ if (ok) {
+ async_handler_->OnRpcRequestReceived(*req_);
+ my_state_ = MyState::OPEN;
+ } else {
+ clean_up();
+ async_handler_->OnRpcRequestFailed();
+ my_state_ = MyState::IDLE;
+ }
+ }
+
+ void WriteDone(bool ok) {
+ ASSERT(my_state_ == MyState::WRITING);
+ if (ok) {
+ my_state_ = MyState::OPEN;
+ async_handler_->OnWriteSuccess();
+ } else {
+ clean_up();
+ my_state_ = MyState::IDLE;
+ async_handler_->OnRpcFinished();
+ }
+ promise_->set_value();
+ }
+
+ void RpcFinish(bool ok) {
+ ASSERT(ok);
+ ASSERT(my_state_ == MyState::FINISHING);
+ clean_up();
+ my_state_ = MyState::IDLE;
+ async_handler_->OnRpcFinished();
+ promise_->set_value();
+ }
+
+ void clean_up() {
+ context_ = nullptr;
+ req_ = nullptr;
+ res_ = nullptr;
+ }
+
+ mutable std::mutex mutex_;
+ std::promise<void>* promise_ = nullptr;
+
+ GrpcAsyncServerStreamingHandler<REQ, RES>* async_handler_;
+ ::grpc::ServerCompletionQueue* cq_;
+
+ std::unique_ptr<::grpc::ServerContext> context_ = nullptr;
+ std::unique_ptr<REQ> req_ = nullptr;
+ std::unique_ptr<::grpc::ServerAsyncWriter<RES>> res_ = nullptr;
+
+ std::unique_ptr<GrpcAsyncEventCallback> request_done_ = nullptr;
+ std::unique_ptr<GrpcAsyncEventCallback> write_done_ = nullptr;
+ std::unique_ptr<GrpcAsyncEventCallback> rpc_finish_ = nullptr;
+
+ enum class MyState { IDLE, REQUESTING, OPEN, WRITING, FINISHING } my_state_ = MyState::IDLE;
+};
+
+} // namespace grpc
+} // namespace bluetooth
diff --git a/gd/grpc/grpc_event_stream.h b/gd/grpc/grpc_event_stream.h
new file mode 100644
index 0000000..3b313f3
--- /dev/null
+++ b/gd/grpc/grpc_event_stream.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2019 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 <grpc++/grpc++.h>
+
+#include <chrono>
+
+#include "common/blocking_queue.h"
+#include "facade/common.pb.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace grpc {
+
+template <typename RES, typename EVENT>
+class GrpcEventStreamCallback {
+ public:
+ virtual ~GrpcEventStreamCallback() = default;
+ virtual void OnSubscribe() {}
+ virtual void OnUnsubscribe() {}
+ virtual void OnWriteResponse(RES* response, const EVENT& event) = 0;
+};
+
+template <typename RES, typename EVENT>
+class GrpcEventStream {
+ public:
+ explicit GrpcEventStream(GrpcEventStreamCallback<RES, EVENT>* callback) : callback_(callback) {}
+
+ void OnIncomingEvent(const EVENT& event) {
+ if (subscribed_) {
+ event_queue_.push(event);
+ }
+ }
+
+ ::grpc::Status HandleRequest(::grpc::ServerContext* context, const ::bluetooth::facade::EventStreamRequest* request,
+ ::grpc::ServerWriter<RES>* writer) {
+ ::bluetooth::facade::EventSubscriptionMode subscription_mode = request->subscription_mode();
+ ::bluetooth::facade::EventFetchMode fetch_mode = request->fetch_mode();
+ uint32_t timeout_ms = request->timeout_ms();
+ if (timeout_ms == 0) {
+ timeout_ms = 3000;
+ }
+
+ if (subscription_mode == ::bluetooth::facade::SUBSCRIBE) {
+ event_queue_.clear();
+ callback_->OnSubscribe();
+ subscribed_ = true;
+ }
+
+ if (fetch_mode == ::bluetooth::facade::AT_LEAST_ONE) {
+ RES response;
+ EVENT event;
+ if (!event_queue_.take_for(std::chrono::milliseconds(timeout_ms), event)) {
+ return ::grpc::Status(::grpc::StatusCode::DEADLINE_EXCEEDED, "timeout exceeded");
+ }
+ callback_->OnWriteResponse(&response, event);
+ writer->Write(response);
+ }
+
+ // fetch all current remaining items and append to AT_LEAST_ONE query if present
+ if (fetch_mode == ::bluetooth::facade::ALL_CURRENT || fetch_mode == ::bluetooth::facade::AT_LEAST_ONE) {
+ while (!event_queue_.empty()) {
+ RES response;
+ EVENT event = event_queue_.take();
+ callback_->OnWriteResponse(&response, event);
+ writer->Write(response);
+ }
+ }
+
+ if (subscription_mode == ::bluetooth::facade::UNSUBSCRIBE) {
+ subscribed_ = false;
+ event_queue_.clear();
+ callback_->OnUnsubscribe();
+ }
+
+ return ::grpc::Status::OK;
+ }
+
+ private:
+ common::BlockingQueue<EVENT> event_queue_;
+ GrpcEventStreamCallback<RES, EVENT>* callback_;
+ bool subscribed_ = false;
+};
+
+} // namespace grpc
+} // namespace bluetooth
diff --git a/gd/grpc/grpc_module.cc b/gd/grpc/grpc_module.cc
new file mode 100644
index 0000000..5f4c862
--- /dev/null
+++ b/gd/grpc/grpc_module.cc
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2019 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 "grpc/grpc_module.h"
+
+#include "os/log.h"
+#include "grpc/async_grpc.h"
+
+using ::grpc::Server;
+using ::grpc::ServerBuilder;
+
+namespace bluetooth {
+namespace grpc {
+
+void GrpcModule::ListDependencies(ModuleList* list) {
+}
+
+void GrpcModule::Start() {
+ ASSERT(!started_);
+}
+
+void GrpcModule::Stop() {
+ ASSERT(!started_);
+}
+
+void GrpcModule::StartServer(const std::string& address, int port) {
+ ASSERT(!started_);
+ started_ = true;
+
+ std::string listening_port = address + ":" + std::to_string(port);
+ ServerBuilder builder;
+
+ for (const auto& facade : facades_) {
+ builder.RegisterService(facade->GetService());
+ }
+
+ builder.AddListeningPort(listening_port, ::grpc::InsecureServerCredentials());
+ completion_queue_ = builder.AddCompletionQueue();
+ server_ = builder.BuildAndStart();
+ ASSERT(server_ != nullptr);
+
+ for (const auto& facade : facades_) {
+ facade->OnServerStarted(completion_queue_.get());
+ }
+}
+
+void GrpcModule::StopServer() {
+ ASSERT(started_);
+
+ server_->Shutdown();
+ completion_queue_->Shutdown();
+
+ for (const auto& facade : facades_) {
+ facade->OnServerStopped();
+ }
+
+ started_ = false;
+}
+
+void GrpcModule::Register(GrpcFacadeModule* facade) {
+ ASSERT(!started_);
+
+ facades_.push_back(facade);
+}
+
+void GrpcModule::Unregister(GrpcFacadeModule* facade) {
+ ASSERT(!started_);
+
+ for (auto it = facades_.begin(); it != facades_.end(); it++) {
+ if (*it == facade) {
+ facades_.erase(it);
+ return;
+ }
+ }
+
+ ASSERT(false);
+}
+
+void GrpcModule::RunGrpcLoop() {
+ void* tag;
+ bool ok;
+ while (true) {
+ if (!completion_queue_->Next(&tag, &ok)) {
+ LOG_INFO("gRPC is shutdown");
+ break;
+ }
+ auto* data = static_cast<GrpcAsyncEventCallback*>(tag);
+ (*data)(ok);
+ }
+}
+
+const ::bluetooth::ModuleFactory GrpcModule::Factory = ::bluetooth::ModuleFactory([]() {
+ return new GrpcModule();
+});
+
+
+void GrpcFacadeModule::ListDependencies(ModuleList* list) {
+ list->add<GrpcModule>();
+}
+
+void GrpcFacadeModule::Start() {
+ GetDependency<GrpcModule>()->Register(this);
+}
+
+void GrpcFacadeModule::Stop() {
+ GetDependency<GrpcModule>()->Unregister(this);
+}
+
+} // namespace grpc
+} // namespace bluetooth
diff --git a/gd/grpc/grpc_module.h b/gd/grpc/grpc_module.h
new file mode 100644
index 0000000..4730b06
--- /dev/null
+++ b/gd/grpc/grpc_module.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2019 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 <vector>
+
+#include <grpc++/grpc++.h>
+#include <module.h>
+
+namespace bluetooth {
+namespace grpc {
+
+class GrpcFacadeModule;
+
+class GrpcModule : public ::bluetooth::Module {
+ public:
+ static const ModuleFactory Factory;
+
+ void StartServer(const std::string& address, int port);
+
+ void StopServer();
+
+ void Register(GrpcFacadeModule* facade);
+
+ void Unregister(GrpcFacadeModule* facade);
+
+ // Blocks for incoming gRPC requests
+ void RunGrpcLoop();
+
+ protected:
+ void ListDependencies(ModuleList* list) override;
+
+ void Start() override;
+
+ void Stop() override;
+
+ private:
+ bool started_;
+ std::unique_ptr<::grpc::Server> server_ = nullptr;
+ std::unique_ptr<::grpc::ServerCompletionQueue> completion_queue_ = nullptr;
+ std::vector<GrpcFacadeModule*> facades_;
+};
+
+class GrpcFacadeModule : public ::bluetooth::Module {
+ friend GrpcModule;
+ protected:
+ void ListDependencies(ModuleList* list) override;
+
+ void Start() override;
+
+ void Stop() override;
+
+ virtual ::grpc::Service* GetService() const = 0;
+
+ virtual void OnServerStarted(::grpc::ServerCompletionQueue* cq) {}
+
+ virtual void OnServerStopped() {}
+};
+
+} // namespace grpc
+} // namespace bluetooth
diff --git a/gd/hal/Android.bp b/gd/hal/Android.bp
new file mode 100644
index 0000000..4c9fa2a
--- /dev/null
+++ b/gd/hal/Android.bp
@@ -0,0 +1,48 @@
+filegroup {
+ name: "BluetoothHalSources",
+ srcs: [
+ "snoop_logger.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothHalSources_hci_rootcanal",
+ srcs: [
+ "hci_hal_host_rootcanal.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothHalSources_hci_android_hidl",
+ srcs: [
+ "hci_hal_android_hidl.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothHalTestSources_hci_rootcanal",
+ srcs: [
+ "hci_hal_host_rootcanal_test.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothHalTestSources_hci_android_hidl",
+ srcs: [
+ "hci_hal_android_hidl_test.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothFacade_hci_hal",
+ srcs: [
+ "facade.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothCertSource_hci_hal",
+ srcs: [
+ "cert/cert.cc",
+ ],
+}
diff --git a/gd/hal/cert/api.proto b/gd/hal/cert/api.proto
new file mode 100644
index 0000000..6071dd1
--- /dev/null
+++ b/gd/hal/cert/api.proto
@@ -0,0 +1,38 @@
+syntax = "proto3";
+
+package bluetooth.hal.cert;
+
+import "google/protobuf/empty.proto";
+import "facade/common.proto";
+
+service HciHalCert {
+ rpc SendHciResetCommand(google.protobuf.Empty) returns (google.protobuf.Empty) {}
+ rpc SetScanMode(ScanModeSettings) returns (google.protobuf.Empty) {}
+ rpc SendHciCommand(HciCommandPacket) returns (google.protobuf.Empty) {}
+ rpc SendHciAcl(HciAclPacket) returns (google.protobuf.Empty) {}
+ rpc SendHciSco(HciScoPacket) returns (google.protobuf.Empty) {}
+
+ rpc FetchHciEvent(bluetooth.facade.EventStreamRequest) returns (stream HciEventPacket) {}
+ rpc FetchHciAcl(bluetooth.facade.EventStreamRequest) returns (stream HciAclPacket) {}
+ rpc FetchHciSco(bluetooth.facade.EventStreamRequest) returns (stream HciScoPacket) {}
+}
+
+message ScanModeSettings {
+ uint32 mode = 1;
+}
+
+message HciEventPacket {
+ bytes payload = 1;
+}
+
+message HciCommandPacket {
+ bytes payload = 1;
+}
+
+message HciAclPacket {
+ bytes payload = 1;
+}
+
+message HciScoPacket {
+ bytes payload = 1;
+}
diff --git a/gd/hal/cert/cert.cc b/gd/hal/cert/cert.cc
new file mode 100644
index 0000000..d637f13
--- /dev/null
+++ b/gd/hal/cert/cert.cc
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2019 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 "hal/cert/cert.h"
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+
+#include "common/blocking_queue.h"
+#include "grpc/grpc_event_stream.h"
+#include "hal/cert/api.grpc.pb.h"
+#include "hal/hci_hal.h"
+#include "hci/hci_packets.h"
+
+namespace bluetooth {
+namespace hal {
+namespace cert {
+
+class HciHalCertService : public HciHalCert::Service, public ::bluetooth::hal::HciHalCallbacks {
+ public:
+ HciHalCertService(HciHal* hal)
+ : hal_(hal), hci_event_stream_(&hci_event_stream_callback_), hci_acl_stream_(&hci_acl_stream_callback_),
+ hci_sco_stream_(&hci_sco_stream_callback_) {
+ hal->registerIncomingPacketCallback(this);
+ }
+
+ ::grpc::Status SendHciResetCommand(::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
+ ::google::protobuf::Empty* response) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ can_send_hci_command_ = false;
+ auto packet = hci::ResetBuilder::Create();
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ hci::BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+ hal_->sendHciCommand(*packet_bytes);
+ std::this_thread::sleep_for(std::chrono::milliseconds(300));
+ while (!can_send_hci_command_) {
+ cv_.wait(lock);
+ }
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SetScanMode(::grpc::ServerContext* context, const ScanModeSettings* request,
+ ::google::protobuf::Empty* response) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ can_send_hci_command_ = false;
+ unsigned int mode = request->mode();
+ hci::ScanEnable scan_enable;
+ switch (mode) {
+ case 0x00:
+ scan_enable = hci::ScanEnable::NO_SCANS;
+ break;
+ case 0x01:
+ scan_enable = hci::ScanEnable::INQUIRY_SCAN_ONLY;
+ break;
+ case 0x02:
+ scan_enable = hci::ScanEnable::PAGE_SCAN_ONLY;
+ break;
+ case 0x03:
+ scan_enable = hci::ScanEnable::INQUIRY_AND_PAGE_SCAN;
+ break;
+ }
+
+ auto packet = hci::WriteScanEnableBuilder::Create(scan_enable);
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ hci::BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+ hal_->sendHciCommand(*packet_bytes);
+
+ while (!can_send_hci_command_) {
+ cv_.wait(lock);
+ }
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SendHciCommand(::grpc::ServerContext* context, const ::bluetooth::hal::cert::HciCommandPacket* request,
+ ::google::protobuf::Empty* response) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ can_send_hci_command_ = false;
+ std::string req_string = request->payload();
+ hal_->sendHciCommand(std::vector<uint8_t>(req_string.begin(), req_string.end()));
+ while (!can_send_hci_command_) {
+ cv_.wait(lock);
+ }
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SendHciAcl(::grpc::ServerContext* context, const ::bluetooth::hal::cert::HciAclPacket* request,
+ ::google::protobuf::Empty* response) override {
+ std::string req_string = request->payload();
+ hal_->sendAclData(std::vector<uint8_t>(req_string.begin(), req_string.end()));
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SendHciSco(::grpc::ServerContext* context, const ::bluetooth::hal::cert::HciScoPacket* request,
+ ::google::protobuf::Empty* response) override {
+ std::string req_string = request->payload();
+ hal_->sendScoData(std::vector<uint8_t>(req_string.begin(), req_string.end()));
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status FetchHciEvent(::grpc::ServerContext* context, const ::bluetooth::facade::EventStreamRequest* request,
+ ::grpc::ServerWriter<HciEventPacket>* writer) override {
+ return hci_event_stream_.HandleRequest(context, request, writer);
+ };
+
+ ::grpc::Status FetchHciAcl(::grpc::ServerContext* context, const ::bluetooth::facade::EventStreamRequest* request,
+ ::grpc::ServerWriter<HciAclPacket>* writer) override {
+ return hci_acl_stream_.HandleRequest(context, request, writer);
+ };
+
+ ::grpc::Status FetchHciSco(::grpc::ServerContext* context, const ::bluetooth::facade::EventStreamRequest* request,
+ ::grpc::ServerWriter<HciScoPacket>* writer) override {
+ return hci_sco_stream_.HandleRequest(context, request, writer);
+ };
+
+ void hciEventReceived(bluetooth::hal::HciPacket event) override {
+ std::string response_str = std::string(event.begin(), event.end());
+ hci_event_stream_.OnIncomingEvent(event);
+ can_send_hci_command_ = true;
+ cv_.notify_one();
+ }
+
+ void aclDataReceived(bluetooth::hal::HciPacket data) override {
+ hci_acl_stream_.OnIncomingEvent(data);
+ }
+
+ void scoDataReceived(bluetooth::hal::HciPacket data) override {
+ hci_sco_stream_.OnIncomingEvent(data);
+ }
+
+ private:
+ HciHal* hal_;
+ bool can_send_hci_command_ = true;
+ mutable std::mutex mutex_;
+ std::condition_variable cv_;
+
+ class HciEventStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<HciEventPacket, HciPacket> {
+ public:
+ void OnWriteResponse(HciEventPacket* response, const HciPacket& event) override {
+ std::string response_str = std::string(event.begin(), event.end());
+ response->set_payload(std::string(event.begin(), event.end()));
+ }
+ } hci_event_stream_callback_;
+ ::bluetooth::grpc::GrpcEventStream<HciEventPacket, HciPacket> hci_event_stream_;
+
+ class HciAclStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<HciAclPacket, HciPacket> {
+ public:
+ void OnWriteResponse(HciAclPacket* response, const HciPacket& event) override {
+ response->set_payload(std::string(event.begin(), event.end()));
+ }
+ } hci_acl_stream_callback_;
+ ::bluetooth::grpc::GrpcEventStream<HciAclPacket, HciPacket> hci_acl_stream_;
+
+ class HciScoStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<HciScoPacket, HciPacket> {
+ public:
+ void OnWriteResponse(HciScoPacket* response, const HciPacket& event) override {
+ response->set_payload(std::string(event.begin(), event.end()));
+ }
+ } hci_sco_stream_callback_;
+ ::bluetooth::grpc::GrpcEventStream<HciScoPacket, HciPacket> hci_sco_stream_;
+};
+
+void HalCertModule::ListDependencies(ModuleList* list) {
+ ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
+ list->add<HciHal>();
+}
+
+void HalCertModule::Start() {
+ ::bluetooth::grpc::GrpcFacadeModule::Start();
+ service_ = new HciHalCertService(GetDependency<HciHal>());
+}
+
+void HalCertModule::Stop() {
+ delete service_;
+ ::bluetooth::grpc::GrpcFacadeModule::Stop();
+}
+
+::grpc::Service* HalCertModule::GetService() const {
+ return service_;
+}
+
+const ModuleFactory HalCertModule::Factory = ::bluetooth::ModuleFactory([]() {
+ return new HalCertModule();
+});
+
+} // namespace cert
+} // namespace hal
+} // namespace bluetooth
diff --git a/gd/hal/cert/cert.h b/gd/hal/cert/cert.h
new file mode 100644
index 0000000..7dba43d
--- /dev/null
+++ b/gd/hal/cert/cert.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019 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 <grpc++/grpc++.h>
+
+#include "grpc/grpc_module.h"
+
+namespace bluetooth {
+namespace hal {
+namespace cert {
+
+class HciHalCertService;
+
+class HalCertModule : public ::bluetooth::grpc::GrpcFacadeModule {
+ public:
+ static const ModuleFactory Factory;
+
+ void ListDependencies(ModuleList* list) override;
+
+ void Start() override;
+ void Stop() override;
+
+ ::grpc::Service* GetService() const override;
+
+ private:
+ HciHalCertService* service_;
+};
+
+} // namespace cert
+} // namespace hal
+} // namespace bluetooth
diff --git a/gd/hal/cert/simple_hal_test.py b/gd/hal/cert/simple_hal_test.py
new file mode 100644
index 0000000..e7b7bab
--- /dev/null
+++ b/gd/hal/cert/simple_hal_test.py
@@ -0,0 +1,103 @@
+#!/usr/bin/env python3
+#
+# Copyright 2019 - 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.
+
+from __future__ import print_function
+
+import os
+import sys
+sys.path.append(os.environ['ANDROID_BUILD_TOP'] + '/system/bt/gd')
+
+from cert.gd_base_test import GdBaseTestClass
+from cert.event_stream import EventStream
+from cert import rootservice_pb2 as cert_rootservice_pb2
+from facade import common_pb2
+from google.protobuf import empty_pb2
+from facade import rootservice_pb2 as facade_rootservice_pb2
+from hal.cert import api_pb2 as hal_cert_pb2
+from hal import facade_pb2 as hal_facade_pb2
+
+class SimpleHalTest(GdBaseTestClass):
+
+ def setup_test(self):
+ self.device_under_test = self.gd_devices[0]
+ self.cert_device = self.gd_cert_devices[0]
+
+ self.device_under_test.rootservice.StartStack(
+ facade_rootservice_pb2.StartStackRequest(
+ module_under_test=facade_rootservice_pb2.BluetoothModule.Value('HAL'),
+ )
+ )
+ self.cert_device.rootservice.StartStack(
+ cert_rootservice_pb2.StartStackRequest(
+ module_to_test=cert_rootservice_pb2.BluetoothModule.Value('HAL'),
+ )
+ )
+
+ self.device_under_test.hal.SendHciResetCommand(empty_pb2.Empty())
+ self.cert_device.hal.SendHciResetCommand(empty_pb2.Empty())
+
+ def teardown_test(self):
+ self.device_under_test.rootservice.StopStack(
+ facade_rootservice_pb2.StopStackRequest()
+ )
+ self.cert_device.rootservice.StopStack(
+ cert_rootservice_pb2.StopStackRequest()
+ )
+
+ def test_none_event(self):
+ self.device_under_test.hal.hci_event_stream.clear_event_buffer()
+
+ self.device_under_test.hal.hci_event_stream.subscribe()
+ self.device_under_test.hal.hci_event_stream.assert_none()
+ self.device_under_test.hal.hci_event_stream.unsubscribe()
+
+ def test_example(self):
+ response = self.device_under_test.hal.SetLoopbackMode(
+ hal_facade_pb2.LoopbackModeSettings(enable=True)
+ )
+
+ def test_fetch_hci_event(self):
+ self.device_under_test.hal.SetLoopbackMode(
+ hal_facade_pb2.LoopbackModeSettings(enable=True)
+ )
+
+ self.device_under_test.hal.hci_event_stream.subscribe()
+
+ self.device_under_test.hal.SendHciCommand(
+ hal_facade_pb2.HciCommandPacket(
+ payload=b'\x01\x04\x053\x8b\x9e0\x01'
+ )
+ )
+
+ self.device_under_test.hal.hci_event_stream.assert_event_occurs(
+ lambda packet: packet.payload == b'\x19\x08\x01\x04\x053\x8b\x9e0\x01'
+ )
+ self.device_under_test.hal.hci_event_stream.unsubscribe()
+
+ def test_inquiry_from_dut(self):
+ self.device_under_test.hal.hci_event_stream.subscribe()
+
+ self.cert_device.hal.SetScanMode(
+ hal_cert_pb2.ScanModeSettings(mode=3)
+ )
+ self.device_under_test.hal.SetInquiry(
+ hal_facade_pb2.InquirySettings(length=0x30, num_responses=0xff)
+ )
+ self.device_under_test.hal.hci_event_stream.assert_event_occurs(
+ lambda packet: b'\x02\x0f' in packet.payload
+ # Expecting an HCI Event (code 0x02, length 0x0f)
+ )
+ self.device_under_test.hal.hci_event_stream.unsubscribe()
diff --git a/gd/hal/facade.cc b/gd/hal/facade.cc
new file mode 100644
index 0000000..1072d59
--- /dev/null
+++ b/gd/hal/facade.cc
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2019 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 "hal/facade.h"
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+
+#include "common/blocking_queue.h"
+#include "grpc/grpc_event_stream.h"
+#include "hal/facade.grpc.pb.h"
+#include "hal/hci_hal.h"
+#include "hci/hci_packets.h"
+
+using ::grpc::ServerAsyncResponseWriter;
+using ::grpc::ServerAsyncWriter;
+using ::grpc::ServerContext;
+
+using ::bluetooth::facade::EventStreamRequest;
+
+namespace bluetooth {
+namespace hal {
+
+class HciHalFacadeService
+ : public HciHalFacade::Service,
+ public ::bluetooth::hal::HciHalCallbacks {
+ public:
+ HciHalFacadeService(HciHal* hal)
+ : hal_(hal), hci_event_stream_(&hci_event_stream_callback_), hci_acl_stream_(&hci_acl_stream_callback_),
+ hci_sco_stream_(&hci_sco_stream_callback_) {
+ hal->registerIncomingPacketCallback(this);
+ }
+
+ ::grpc::Status SendHciResetCommand(::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
+ ::google::protobuf::Empty* response) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ can_send_hci_command_ = false;
+ auto packet = hci::ResetBuilder::Create();
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ hci::BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+ hal_->sendHciCommand(*packet_bytes);
+ while (!can_send_hci_command_) {
+ cv_.wait(lock);
+ }
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SetLoopbackMode(::grpc::ServerContext* context,
+ const ::bluetooth::hal::LoopbackModeSettings* request,
+ ::google::protobuf::Empty* response) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ can_send_hci_command_ = false;
+ bool enable = request->enable();
+ auto packet = hci::WriteLoopbackModeBuilder::Create(enable ? hci::LoopbackMode::ENABLE_LOCAL
+ : hci::LoopbackMode::NO_LOOPBACK);
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ hci::BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+ hal_->sendHciCommand(*packet_bytes);
+ while (!can_send_hci_command_) {
+ cv_.wait(lock);
+ }
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SetInquiry(::grpc::ServerContext* context, const ::bluetooth::hal::InquirySettings* request,
+ ::google::protobuf::Empty* response) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ can_send_hci_command_ = false;
+ auto packet = hci::InquiryBuilder::Create(0x33 /* LAP=0x9e8b33 */, static_cast<uint8_t>(request->length()),
+ static_cast<uint8_t>(request->num_responses()));
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ hci::BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+ hal_->sendHciCommand(*packet_bytes);
+ while (!can_send_hci_command_) {
+ cv_.wait(lock);
+ }
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SendHciCommand(::grpc::ServerContext* context, const ::bluetooth::hal::HciCommandPacket* request,
+ ::google::protobuf::Empty* response) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ can_send_hci_command_ = false;
+ std::string req_string = request->payload();
+ hal_->sendHciCommand(std::vector<uint8_t>(req_string.begin(), req_string.end()));
+ while (!can_send_hci_command_) {
+ cv_.wait(lock);
+ }
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SendHciAcl(::grpc::ServerContext* context, const ::bluetooth::hal::HciAclPacket* request,
+ ::google::protobuf::Empty* response) override {
+ std::string req_string = request->payload();
+ hal_->sendAclData(std::vector<uint8_t>(req_string.begin(), req_string.end()));
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SendHciSco(::grpc::ServerContext* context, const ::bluetooth::hal::HciScoPacket* request,
+ ::google::protobuf::Empty* response) override {
+ std::string req_string = request->payload();
+ hal_->sendScoData(std::vector<uint8_t>(req_string.begin(), req_string.end()));
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status FetchHciEvent(::grpc::ServerContext* context, const EventStreamRequest* request,
+ ::grpc::ServerWriter<HciEventPacket>* writer) override {
+ return hci_event_stream_.HandleRequest(context, request, writer);
+ };
+
+ ::grpc::Status FetchHciAcl(::grpc::ServerContext* context, const EventStreamRequest* request,
+ ::grpc::ServerWriter<HciAclPacket>* writer) override {
+ return hci_acl_stream_.HandleRequest(context, request, writer);
+ };
+
+ ::grpc::Status FetchHciSco(::grpc::ServerContext* context, const EventStreamRequest* request,
+ ::grpc::ServerWriter<HciScoPacket>* writer) override {
+ return hci_sco_stream_.HandleRequest(context, request, writer);
+ };
+
+ void hciEventReceived(bluetooth::hal::HciPacket event) override {
+ std::string response_str = std::string(event.begin(), event.end());
+ hci_event_stream_.OnIncomingEvent(event);
+ can_send_hci_command_ = true;
+ cv_.notify_one();
+ }
+
+ void aclDataReceived(bluetooth::hal::HciPacket data) override {
+ hci_acl_stream_.OnIncomingEvent(data);
+ }
+
+ void scoDataReceived(bluetooth::hal::HciPacket data) override {
+ hci_sco_stream_.OnIncomingEvent(data);
+ }
+
+ private:
+ HciHal* hal_;
+ bool can_send_hci_command_ = true;
+ mutable std::mutex mutex_;
+ std::condition_variable cv_;
+
+ class HciEventStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<HciEventPacket, HciPacket> {
+ public:
+ void OnWriteResponse(HciEventPacket* response, const HciPacket& event) override {
+ std::string response_str = std::string(event.begin(), event.end());
+ response->set_payload(std::string(event.begin(), event.end()));
+ }
+ } hci_event_stream_callback_;
+ ::bluetooth::grpc::GrpcEventStream<HciEventPacket, HciPacket> hci_event_stream_;
+
+ class HciAclStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<HciAclPacket, HciPacket> {
+ public:
+ void OnWriteResponse(HciAclPacket* response, const HciPacket& event) override {
+ response->set_payload(std::string(event.begin(), event.end()));
+ }
+ } hci_acl_stream_callback_;
+ ::bluetooth::grpc::GrpcEventStream<HciAclPacket, HciPacket> hci_acl_stream_;
+
+ class HciScoStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<HciScoPacket, HciPacket> {
+ public:
+ void OnWriteResponse(HciScoPacket* response, const HciPacket& event) override {
+ response->set_payload(std::string(event.begin(), event.end()));
+ }
+ } hci_sco_stream_callback_;
+ ::bluetooth::grpc::GrpcEventStream<HciScoPacket, HciPacket> hci_sco_stream_;
+};
+
+void HciHalFacadeModule::ListDependencies(ModuleList* list) {
+ ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
+ list->add<HciHal>();
+}
+
+void HciHalFacadeModule::Start() {
+ ::bluetooth::grpc::GrpcFacadeModule::Start();
+ service_ = new HciHalFacadeService(GetDependency<HciHal>());
+}
+
+void HciHalFacadeModule::Stop() {
+ delete service_;
+ ::bluetooth::grpc::GrpcFacadeModule::Stop();
+}
+
+::grpc::Service* HciHalFacadeModule::GetService() const {
+ return service_;
+}
+
+const ModuleFactory HciHalFacadeModule::Factory = ::bluetooth::ModuleFactory([]() {
+ return new HciHalFacadeModule();
+});
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/gd/hal/facade.h b/gd/hal/facade.h
new file mode 100644
index 0000000..fa28d10
--- /dev/null
+++ b/gd/hal/facade.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2019 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 <list>
+#include <mutex>
+
+#include <grpc++/grpc++.h>
+
+#include "grpc/grpc_module.h"
+#include "hal/hci_hal.h"
+
+namespace bluetooth {
+namespace hal {
+
+class HciHalFacadeService;
+
+class HciHalFacadeModule : public ::bluetooth::grpc::GrpcFacadeModule {
+ public:
+ static const ModuleFactory Factory;
+
+ void ListDependencies(ModuleList* list) override;
+
+ void Start() override;
+ void Stop() override;
+
+ ::grpc::Service* GetService() const override;
+
+ private:
+ HciHalFacadeService* service_;
+};
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/gd/hal/facade.proto b/gd/hal/facade.proto
new file mode 100644
index 0000000..45919fe
--- /dev/null
+++ b/gd/hal/facade.proto
@@ -0,0 +1,48 @@
+syntax = "proto3";
+
+package bluetooth.hal;
+
+import "google/protobuf/empty.proto";
+import "facade/common.proto";
+
+service HciHalFacade {
+ rpc SendHciResetCommand(google.protobuf.Empty) returns (google.protobuf.Empty) {}
+ rpc SetLoopbackMode(LoopbackModeSettings) returns (google.protobuf.Empty) {}
+ rpc SetInquiry(InquirySettings) returns (google.protobuf.Empty) {}
+ rpc SendHciCommand(HciCommandPacket) returns (google.protobuf.Empty) {}
+ rpc SendHciAcl(HciAclPacket) returns (google.protobuf.Empty) {}
+ rpc SendHciSco(HciScoPacket) returns (google.protobuf.Empty) {}
+
+ rpc FetchHciEvent(bluetooth.facade.EventStreamRequest) returns (stream HciEventPacket) {}
+ rpc FetchHciAcl(bluetooth.facade.EventStreamRequest) returns (stream HciAclPacket) {}
+ rpc FetchHciSco(bluetooth.facade.EventStreamRequest) returns (stream HciScoPacket) {}
+}
+
+message LoopbackModeSettings {
+ bool enable = 1;
+}
+
+message ScanModeSettings {
+ uint32 mode = 1;
+}
+
+message InquirySettings {
+ uint32 length = 1;
+ uint32 num_responses = 2;
+}
+
+message HciEventPacket {
+ bytes payload = 1;
+}
+
+message HciCommandPacket {
+ bytes payload = 1;
+}
+
+message HciAclPacket {
+ bytes payload = 1;
+}
+
+message HciScoPacket {
+ bytes payload = 1;
+}
diff --git a/gd/hal/hci_hal.h b/gd/hal/hci_hal.h
new file mode 100644
index 0000000..88c0d9e
--- /dev/null
+++ b/gd/hal/hci_hal.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2019 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 <vector>
+
+#include "module.h"
+
+namespace bluetooth {
+namespace hal {
+
+using HciPacket = std::vector<uint8_t>;
+
+enum class Status : int32_t { SUCCESS, TRANSPORT_ERROR, INITIALIZATION_ERROR, UNKNOWN };
+
+// Mirrors hardware/interfaces/bluetooth/1.0/IBluetoothHciCallbacks.hal in Android, but moved initializationComplete
+// callback to BluetoothInitializationCompleteCallback
+
+// The interface from the Bluetooth Controller to the stack
+class HciHalCallbacks {
+ public:
+ virtual ~HciHalCallbacks() = default;
+
+ // This function is invoked when an HCI event is received from the
+ // Bluetooth controller to be forwarded to the Bluetooth stack
+ // @param event is the HCI event to be sent to the Bluetooth stack
+ virtual void hciEventReceived(HciPacket event) = 0;
+
+ // Send an ACL data packet form the controller to the host
+ // @param data the ACL HCI packet to be passed to the host stack
+ virtual void aclDataReceived(HciPacket data) = 0;
+
+ // Send a SCO data packet form the controller to the host
+ // @param data the SCO HCI packet to be passed to the host stack
+ virtual void scoDataReceived(HciPacket data) = 0;
+};
+
+// Mirrors hardware/interfaces/bluetooth/1.0/IBluetoothHci.hal in Android
+// The Host Controller Interface (HCI) is the layer defined by the Bluetooth
+// specification between the software that runs on the host and the Bluetooth
+// controller chip. This boundary is the natural choice for a Hardware
+// Abstraction Layer (HAL). Dealing only in HCI packets and events simplifies
+// the stack and abstracts away power management, initialization, and other
+// implementation-specific details related to the hardware.
+class HciHal : public ::bluetooth::Module {
+ public:
+ static const ModuleFactory Factory;
+
+ virtual ~HciHal() = default;
+
+ // Register the callback for incoming packets. All incoming packets are dropped before
+ // this callback is registered. Callback can only be registered once, but will be reset
+ // after close().
+ //
+ // Call this function before initialize() to guarantee all incoming packets are received.
+ //
+ // @param callback implements BluetoothHciHalCallbacks which will
+ // receive callbacks when incoming HCI packets are received
+ // from the controller to be sent to the host.
+ virtual void registerIncomingPacketCallback(HciHalCallbacks* callback) = 0;
+
+ // Send an HCI command (as specified in the Bluetooth Specification
+ // V4.2, Vol 2, Part 5, Section 5.4.1) to the Bluetooth controller.
+ // Commands must be executed in order.
+ virtual void sendHciCommand(HciPacket command) = 0;
+
+ // Send an HCI ACL data packet (as specified in the Bluetooth Specification
+ // V4.2, Vol 2, Part 5, Section 5.4.2) to the Bluetooth controller.
+ // Packets must be processed in order.
+ virtual void sendAclData(HciPacket data) = 0;
+
+ // Send an SCO data packet (as specified in the Bluetooth Specification
+ // V4.2, Vol 2, Part 5, Section 5.4.3) to the Bluetooth controller.
+ // Packets must be processed in order.
+ virtual void sendScoData(HciPacket data) = 0;
+};
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/gd/hal/hci_hal_android_hidl.cc b/gd/hal/hci_hal_android_hidl.cc
new file mode 100644
index 0000000..8935837
--- /dev/null
+++ b/gd/hal/hci_hal_android_hidl.cc
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2019 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 "hal/hci_hal.h"
+
+#include <stdlib.h>
+#include <vector>
+#include <future>
+
+#include <android/hardware/bluetooth/1.0/IBluetoothHci.h>
+#include <android/hardware/bluetooth/1.0/IBluetoothHciCallbacks.h>
+#include <android/hardware/bluetooth/1.0/types.h>
+
+#include "hal/snoop_logger.h"
+#include "os/log.h"
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::bluetooth::V1_0::IBluetoothHci;
+using ::android::hardware::bluetooth::V1_0::IBluetoothHciCallbacks;
+using HidlStatus = ::android::hardware::bluetooth::V1_0::Status;
+
+namespace bluetooth {
+namespace hal {
+namespace {
+
+class HciDeathRecipient : public ::android::hardware::hidl_death_recipient {
+ public:
+ virtual void serviceDied(uint64_t /*cookie*/, const android::wp<::android::hidl::base::V1_0::IBase>& /*who*/) {
+ LOG_ERROR("Bluetooth HAL service died!");
+ abort();
+ }
+};
+
+android::sp<HciDeathRecipient> hci_death_recipient_ = new HciDeathRecipient();
+
+class InternalHciCallbacks : public IBluetoothHciCallbacks {
+ public:
+ InternalHciCallbacks(SnoopLogger* btsnoop_logger)
+ : btsnoop_logger_(btsnoop_logger) {
+ init_promise_ = new std::promise<void>();
+ }
+
+ void SetCallback(HciHalCallbacks* callback) {
+ ASSERT(callback_ == nullptr && callback != nullptr);
+ callback_ = callback;
+ }
+
+ void ResetCallback() {
+ callback_ = nullptr;
+ }
+
+ std::promise<void>* GetInitPromise() {
+ return init_promise_;
+ }
+
+ Return<void> initializationComplete(HidlStatus status) {
+ ASSERT(status == HidlStatus::SUCCESS);
+ init_promise_->set_value();
+ return Void();
+ }
+
+ Return<void> hciEventReceived(const hidl_vec<uint8_t>& event) {
+ std::vector<uint8_t> received_hci_packet(event.begin(), event.end());
+ btsnoop_logger_->capture(received_hci_packet, SnoopLogger::Direction::INCOMING,
+ SnoopLogger::PacketType::EVT);
+ if (callback_ != nullptr) {
+ callback_->hciEventReceived(std::move(received_hci_packet));
+ }
+ return Void();
+ }
+
+ Return<void> aclDataReceived(const hidl_vec<uint8_t>& data) {
+ std::vector<uint8_t> received_hci_packet(data.begin(), data.end());
+ btsnoop_logger_->capture(received_hci_packet, SnoopLogger::Direction::INCOMING,
+ SnoopLogger::PacketType::ACL);
+ if (callback_ != nullptr) {
+ callback_->aclDataReceived(std::move(received_hci_packet));
+ }
+ return Void();
+ }
+
+ Return<void> scoDataReceived(const hidl_vec<uint8_t>& data) {
+ std::vector<uint8_t> received_hci_packet(data.begin(), data.end());
+ btsnoop_logger_->capture(received_hci_packet, SnoopLogger::Direction::INCOMING,
+ SnoopLogger::PacketType::SCO);
+ if (callback_ != nullptr) {
+ callback_->scoDataReceived(std::move(received_hci_packet));
+ }
+ return Void();
+ }
+
+ private:
+ std::promise<void>* init_promise_ = nullptr;
+ HciHalCallbacks* callback_ = nullptr;
+ SnoopLogger* btsnoop_logger_ = nullptr;
+};
+
+} // namespace
+
+const std::string SnoopLogger::DefaultFilePath = "/data/misc/bluetooth/logs/btsnoop_hci.log";
+
+class HciHalHidl : public HciHal {
+ public:
+ void registerIncomingPacketCallback(HciHalCallbacks* callback) override {
+ callbacks_->SetCallback(callback);
+ }
+
+ void sendHciCommand(HciPacket command) override {
+ btsnoop_logger_->capture(command, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::CMD);
+ bt_hci_->sendHciCommand(command);
+ }
+
+ void sendAclData(HciPacket packet) override {
+ btsnoop_logger_->capture(packet, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::ACL);
+ bt_hci_->sendAclData(packet);
+ }
+
+ void sendScoData(HciPacket packet) override {
+ btsnoop_logger_->capture(packet, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::SCO);
+ bt_hci_->sendScoData(packet);
+ }
+
+ protected:
+ void ListDependencies(ModuleList* list) override {
+ list->add<SnoopLogger>();
+ }
+
+ void Start() override {
+ btsnoop_logger_ = GetDependency<SnoopLogger>();
+ bt_hci_ = IBluetoothHci::getService();
+ ASSERT(bt_hci_ != nullptr);
+ auto death_link = bt_hci_->linkToDeath(hci_death_recipient_, 0);
+ ASSERT_LOG(death_link.isOk(), "Unable to set the death recipient for the Bluetooth HAL");
+ // Block allows allocation of a variable that might be bypassed by goto.
+ {
+ callbacks_ = new InternalHciCallbacks(btsnoop_logger_);
+ bt_hci_->initialize(callbacks_);
+ // Don't timeout here, time out at a higher layer
+ callbacks_->GetInitPromise()->get_future().wait();
+ }
+ }
+
+ void Stop() override {
+ ASSERT(bt_hci_ != nullptr);
+ auto death_unlink = bt_hci_->unlinkToDeath(hci_death_recipient_);
+ if (!death_unlink.isOk()) {
+ LOG_ERROR("Error unlinking death recipient from the Bluetooth HAL");
+ }
+ bt_hci_->close();
+ callbacks_->ResetCallback();
+ bt_hci_ = nullptr;
+ }
+
+ private:
+ android::sp<InternalHciCallbacks> callbacks_;
+ android::sp<IBluetoothHci> bt_hci_;
+ SnoopLogger* btsnoop_logger_;
+};
+
+const ModuleFactory HciHal::Factory = ModuleFactory([]() {
+ return new HciHalHidl();
+});
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/gd/hal/hci_hal_android_hidl_test.cc b/gd/hal/hci_hal_android_hidl_test.cc
new file mode 100644
index 0000000..5b8b68d
--- /dev/null
+++ b/gd/hal/hci_hal_android_hidl_test.cc
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 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 "hal/hci_hal.h"
+
+#include <chrono>
+#include <future>
+
+#include <gtest/gtest.h>
+
+#include "os/thread.h"
+
+using ::bluetooth::os::Thread;
+
+namespace bluetooth {
+namespace hal {
+namespace {
+
+class HciHalHidlTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ thread_ = new Thread("test_thread", Thread::Priority::NORMAL);
+ }
+
+ void TearDown() override {
+ delete thread_;
+ }
+
+ ModuleRegistry fake_registry_;
+ Thread* thread_;
+};
+
+TEST_F(HciHalHidlTest, init_and_close) {
+ fake_registry_.Start<HciHal>(thread_);
+ fake_registry_.StopAll();
+}
+} // namespace
+} // namespace hal
+} // namespace bluetooth
diff --git a/gd/hal/hci_hal_host_rootcanal.cc b/gd/hal/hci_hal_host_rootcanal.cc
new file mode 100644
index 0000000..3279bd5
--- /dev/null
+++ b/gd/hal/hci_hal_host_rootcanal.cc
@@ -0,0 +1,269 @@
+/*
+ * Copyright 2019 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 "hal/hci_hal_host_rootcanal.h"
+#include "hal/hci_hal.h"
+
+#include <netdb.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <csignal>
+#include <mutex>
+#include <queue>
+
+#include "hal/snoop_logger.h"
+#include "os/log.h"
+#include "os/reactor.h"
+#include "os/thread.h"
+
+namespace {
+constexpr int INVALID_FD = -1;
+
+constexpr uint8_t kH4Command = 0x01;
+constexpr uint8_t kH4Acl = 0x02;
+constexpr uint8_t kH4Sco = 0x03;
+constexpr uint8_t kH4Event = 0x04;
+
+constexpr uint8_t kH4HeaderSize = 1;
+constexpr uint8_t kHciAclHeaderSize = 4;
+constexpr uint8_t kHciScoHeaderSize = 3;
+constexpr uint8_t kHciEvtHeaderSize = 2;
+constexpr int kBufSize = 1024;
+
+int ConnectToRootCanal(const std::string& server, int port) {
+ int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (socket_fd < 1) {
+ LOG_ERROR("can't create socket: %s", strerror(errno));
+ return INVALID_FD;
+ }
+
+ struct hostent* host;
+ host = gethostbyname(server.c_str());
+ if (host == nullptr) {
+ LOG_ERROR("can't get server name");
+ return INVALID_FD;
+ }
+
+ struct sockaddr_in serv_addr;
+ memset((void*)&serv_addr, 0, sizeof(serv_addr));
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_addr.s_addr = INADDR_ANY;
+ serv_addr.sin_port = htons(port);
+
+ int result = connect(socket_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
+ if (result < 0) {
+ LOG_ERROR("can't connect: %s", strerror(errno));
+ return INVALID_FD;
+ }
+
+ timeval socket_timeout{
+ .tv_sec = 3,
+ .tv_usec = 0,
+ };
+ int ret = setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, &socket_timeout, sizeof(socket_timeout));
+ if (ret == -1) {
+ LOG_ERROR("can't control socket fd: %s", strerror(errno));
+ return INVALID_FD;
+ }
+ return socket_fd;
+}
+} // namespace
+
+namespace bluetooth {
+namespace hal {
+
+const std::string SnoopLogger::DefaultFilePath = "/tmp/btsnoop_hci.log";
+
+class HciHalHostRootcanal : public HciHal {
+ public:
+ void registerIncomingPacketCallback(HciHalCallbacks* callback) override {
+ std::lock_guard<std::mutex> lock(mutex_);
+ ASSERT(incoming_packet_callback_ == nullptr && callback != nullptr);
+ incoming_packet_callback_ = callback;
+ }
+
+ void sendHciCommand(HciPacket command) override {
+ std::lock_guard<std::mutex> lock(mutex_);
+ ASSERT(sock_fd_ != INVALID_FD);
+ std::vector<uint8_t> packet = std::move(command);
+ btsnoop_logger_->capture(packet, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::CMD);
+ packet.insert(packet.cbegin(), kH4Command);
+ write_to_rootcanal_fd(packet);
+ }
+
+ void sendAclData(HciPacket data) override {
+ std::lock_guard<std::mutex> lock(mutex_);
+ ASSERT(sock_fd_ != INVALID_FD);
+ std::vector<uint8_t> packet = std::move(data);
+ btsnoop_logger_->capture(packet, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::ACL);
+ packet.insert(packet.cbegin(), kH4Acl);
+ write_to_rootcanal_fd(packet);
+ }
+
+ void sendScoData(HciPacket data) override {
+ std::lock_guard<std::mutex> lock(mutex_);
+ ASSERT(sock_fd_ != INVALID_FD);
+ std::vector<uint8_t> packet = std::move(data);
+ btsnoop_logger_->capture(packet, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::SCO);
+ packet.insert(packet.cbegin(), kH4Sco);
+ write_to_rootcanal_fd(packet);
+ }
+
+ protected:
+ void ListDependencies(ModuleList* list) override {
+ list->add<SnoopLogger>();
+ }
+
+ void Start() override {
+ std::lock_guard<std::mutex> lock(mutex_);
+ ASSERT(sock_fd_ == INVALID_FD);
+ sock_fd_ = ConnectToRootCanal(config_->GetServerAddress(), config_->GetPort());
+ ASSERT(sock_fd_ != INVALID_FD);
+ reactable_ =
+ hci_incoming_thread_.GetReactor()->Register(sock_fd_, [this]() { this->incoming_packet_received(); }, nullptr);
+ btsnoop_logger_ = GetDependency<SnoopLogger>();
+ LOG_INFO("Rootcanal HAL opened successfully");
+ }
+
+ void Stop() override {
+ std::lock_guard<std::mutex> lock(mutex_);
+ if (reactable_ != nullptr) {
+ hci_incoming_thread_.GetReactor()->Unregister(reactable_);
+ ASSERT(sock_fd_ != INVALID_FD);
+ }
+ reactable_ = nullptr;
+ incoming_packet_callback_ = nullptr;
+ ::close(sock_fd_);
+ sock_fd_ = INVALID_FD;
+ LOG_INFO("Rootcanal HAL is closed");
+ }
+
+ private:
+ std::mutex mutex_;
+ HciHalHostRootcanalConfig* config_ = HciHalHostRootcanalConfig::Get();
+ HciHalCallbacks* incoming_packet_callback_ = nullptr;
+ int sock_fd_ = INVALID_FD;
+ bluetooth::os::Thread hci_incoming_thread_ =
+ bluetooth::os::Thread("hci_incoming_thread", bluetooth::os::Thread::Priority::NORMAL);
+ bluetooth::os::Reactor::Reactable* reactable_ = nullptr;
+ std::queue<std::vector<uint8_t>> hci_outgoing_queue_;
+ SnoopLogger* btsnoop_logger_;
+
+ void write_to_rootcanal_fd(HciPacket packet) {
+ // TODO: replace this with new queue when it's ready
+ hci_outgoing_queue_.emplace(packet);
+ if (hci_outgoing_queue_.size() == 1) {
+ hci_incoming_thread_.GetReactor()->ModifyRegistration(
+ reactable_, [this] { this->incoming_packet_received(); },
+ [this] {
+ std::lock_guard<std::mutex> lock(this->mutex_);
+ auto packet_to_send = this->hci_outgoing_queue_.front();
+ auto bytes_written = write(this->sock_fd_, (void*)packet_to_send.data(), packet_to_send.size());
+ this->hci_outgoing_queue_.pop();
+ if (bytes_written == -1) {
+ abort();
+ }
+ if (hci_outgoing_queue_.empty()) {
+ this->hci_incoming_thread_.GetReactor()->ModifyRegistration(
+ this->reactable_, [this] { this->incoming_packet_received(); }, nullptr);
+ }
+ });
+ }
+ }
+
+ void incoming_packet_received() {
+ ASSERT(incoming_packet_callback_ != nullptr);
+
+ uint8_t buf[kBufSize] = {};
+
+ ssize_t received_size;
+ RUN_NO_INTR(received_size = recv(sock_fd_, buf, kH4HeaderSize, 0));
+ ASSERT_LOG(received_size != -1, "Can't receive from socket: %s", strerror(errno));
+ if (received_size == 0) {
+ LOG_WARN("Can't read H4 header.");
+ raise(SIGINT);
+ return;
+ }
+
+ if (buf[0] == kH4Event) {
+ RUN_NO_INTR(received_size = recv(sock_fd_, buf + kH4HeaderSize, kHciEvtHeaderSize, 0));
+ ASSERT_LOG(received_size != -1, "Can't receive from socket: %s", strerror(errno));
+ ASSERT_LOG(received_size == kHciEvtHeaderSize, "malformed HCI event header received");
+
+ uint8_t hci_evt_parameter_total_length = buf[2];
+ ssize_t payload_size;
+ RUN_NO_INTR(payload_size =
+ recv(sock_fd_, buf + kH4HeaderSize + kHciEvtHeaderSize, hci_evt_parameter_total_length, 0));
+ ASSERT_LOG(payload_size != -1, "Can't receive from socket: %s", strerror(errno));
+ ASSERT_LOG(payload_size == hci_evt_parameter_total_length,
+ "malformed HCI event total parameter size received: %zu != %d", payload_size,
+ hci_evt_parameter_total_length);
+
+ HciPacket receivedHciPacket;
+ receivedHciPacket.assign(buf + kH4HeaderSize, buf + kH4HeaderSize + kHciEvtHeaderSize + payload_size);
+ btsnoop_logger_->capture(receivedHciPacket, SnoopLogger::Direction::INCOMING,
+ SnoopLogger::PacketType::EVT);
+ incoming_packet_callback_->hciEventReceived(receivedHciPacket);
+ }
+
+ if (buf[0] == kH4Acl) {
+ RUN_NO_INTR(received_size = recv(sock_fd_, buf + kH4HeaderSize, kHciAclHeaderSize, 0));
+ ASSERT_LOG(received_size != -1, "Can't receive from socket: %s", strerror(errno));
+ ASSERT_LOG(received_size == kHciAclHeaderSize, "malformed ACL header received");
+
+ uint16_t hci_acl_data_total_length = buf[4] * 256 + buf[3];
+ int payload_size;
+ RUN_NO_INTR(payload_size = recv(sock_fd_, buf + kH4HeaderSize + kHciAclHeaderSize, hci_acl_data_total_length, 0));
+ ASSERT_LOG(payload_size != -1, "Can't receive from socket: %s", strerror(errno));
+ ASSERT_LOG(payload_size == hci_acl_data_total_length, "malformed ACL length received: %d != %d", payload_size,
+ hci_acl_data_total_length);
+ ASSERT_LOG(hci_acl_data_total_length <= kBufSize - kH4HeaderSize - kHciAclHeaderSize, "packet too long");
+
+ HciPacket receivedHciPacket;
+ receivedHciPacket.assign(buf + kH4HeaderSize, buf + kH4HeaderSize + kHciAclHeaderSize + payload_size);
+ btsnoop_logger_->capture(receivedHciPacket, SnoopLogger::Direction::INCOMING,
+ SnoopLogger::PacketType::ACL);
+ incoming_packet_callback_->aclDataReceived(receivedHciPacket);
+ }
+
+ if (buf[0] == kH4Sco) {
+ RUN_NO_INTR(received_size = recv(sock_fd_, buf + kH4HeaderSize, kHciScoHeaderSize, 0));
+ ASSERT_LOG(received_size != -1, "Can't receive from socket: %s", strerror(errno));
+ ASSERT_LOG(received_size == kHciScoHeaderSize, "malformed SCO header received");
+
+ uint8_t hci_sco_data_total_length = buf[3];
+ int payload_size;
+ RUN_NO_INTR(payload_size = recv(sock_fd_, buf + kH4HeaderSize + kHciScoHeaderSize, hci_sco_data_total_length, 0));
+ ASSERT_LOG(payload_size != -1, "Can't receive from socket: %s", strerror(errno));
+ ASSERT_LOG(payload_size == hci_sco_data_total_length, "malformed SCO packet received: size mismatch");
+
+ HciPacket receivedHciPacket;
+ receivedHciPacket.assign(buf + kH4HeaderSize, buf + kH4HeaderSize + kHciScoHeaderSize + payload_size);
+ btsnoop_logger_->capture(receivedHciPacket, SnoopLogger::Direction::INCOMING,
+ SnoopLogger::PacketType::SCO);
+ incoming_packet_callback_->scoDataReceived(receivedHciPacket);
+ }
+ memset(buf, 0, kBufSize);
+ }
+};
+
+const ModuleFactory HciHal::Factory = ModuleFactory([]() {
+ return new HciHalHostRootcanal();
+});
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/gd/hal/hci_hal_host_rootcanal.h b/gd/hal/hci_hal_host_rootcanal.h
new file mode 100644
index 0000000..9b73b15
--- /dev/null
+++ b/gd/hal/hci_hal_host_rootcanal.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2019 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>
+
+namespace bluetooth {
+namespace hal {
+
+// Singleton object to store runtime configuration for rootcanal
+class HciHalHostRootcanalConfig {
+ public:
+ static HciHalHostRootcanalConfig* Get() {
+ static HciHalHostRootcanalConfig instance;
+ return &instance;
+ }
+
+ // Get the listening TCP port for rootcanal HCI socket
+ uint16_t GetPort() {
+ return port_;
+ }
+
+ // Set the listening TCP port for rootcanal HCI socket
+ void SetPort(uint16_t port) {
+ port_ = port;
+ }
+
+ // Get the server address for rootcanal HCI socket
+ std::string GetServerAddress() {
+ return server_address_;
+ }
+
+ // Set the server address for rootcanal HCI socket
+ void SetServerAddress(const std::string& address) {
+ server_address_ = address;
+ }
+
+ private:
+ HciHalHostRootcanalConfig() = default;
+ uint16_t port_ = 6402; // Default server TCP port
+ std::string server_address_ = "127.0.0.1"; // Default server address
+};
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/gd/hal/hci_hal_host_rootcanal_test.cc b/gd/hal/hci_hal_host_rootcanal_test.cc
new file mode 100644
index 0000000..ae98737
--- /dev/null
+++ b/gd/hal/hci_hal_host_rootcanal_test.cc
@@ -0,0 +1,381 @@
+/*
+ * Copyright 2019 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 "hal/hci_hal_host_rootcanal.h"
+#include "hal/hci_hal.h"
+
+#include <fcntl.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <cstring>
+#include <queue>
+#include <thread>
+#include <utility>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "os/log.h"
+#include "os/thread.h"
+#include "os/utils.h"
+
+using ::bluetooth::os::Thread;
+
+namespace bluetooth {
+namespace hal {
+namespace {
+
+uint16_t kTestPort = 6537;
+
+constexpr uint8_t kH4Command = 0x01;
+constexpr uint8_t kH4Acl = 0x02;
+constexpr uint8_t kH4Sco = 0x03;
+constexpr uint8_t kH4Event = 0x04;
+
+using H4Packet = std::vector<uint8_t>;
+
+std::queue<std::pair<uint8_t, HciPacket>> incoming_packets_queue_;
+
+class TestHciHalCallbacks : public HciHalCallbacks {
+ public:
+ void hciEventReceived(HciPacket packet) override {
+ incoming_packets_queue_.emplace(kH4Event, packet);
+ }
+
+ void aclDataReceived(HciPacket packet) override {
+ incoming_packets_queue_.emplace(kH4Acl, packet);
+ }
+
+ void scoDataReceived(HciPacket packet) override {
+ incoming_packets_queue_.emplace(kH4Sco, packet);
+ }
+};
+
+// An implementation of rootcanal desktop HCI server which listens on localhost:kListeningPort
+class FakeRootcanalDesktopHciServer {
+ public:
+ FakeRootcanalDesktopHciServer() {
+ struct sockaddr_in listen_address;
+ socklen_t sockaddr_in_size = sizeof(struct sockaddr_in);
+ memset(&listen_address, 0, sockaddr_in_size);
+
+ RUN_NO_INTR(listen_fd_ = socket(AF_INET, SOCK_STREAM, 0));
+ if (listen_fd_ < 0) {
+ LOG_WARN("Error creating socket for test channel.");
+ return;
+ }
+
+ listen_address.sin_family = AF_INET;
+ listen_address.sin_port = htons(HciHalHostRootcanalConfig::Get()->GetPort());
+ listen_address.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ if (bind(listen_fd_, reinterpret_cast<sockaddr*>(&listen_address), sockaddr_in_size) < 0) {
+ LOG_WARN("Error binding test channel listener socket to address.");
+ close(listen_fd_);
+ return;
+ }
+
+ if (listen(listen_fd_, 1) < 0) {
+ LOG_WARN("Error listening for test channel.");
+ close(listen_fd_);
+ return;
+ }
+ }
+
+ ~FakeRootcanalDesktopHciServer() {
+ close(listen_fd_);
+ }
+
+ int Accept() {
+ int accept_fd;
+
+ RUN_NO_INTR(accept_fd = accept(listen_fd_, nullptr, nullptr));
+
+ int flags = fcntl(accept_fd, F_GETFL, NULL);
+ int ret = fcntl(accept_fd, F_SETFL, flags | O_NONBLOCK);
+ if (ret == -1) {
+ LOG_ERROR("Can't fcntl");
+ return -1;
+ }
+
+ if (accept_fd < 0) {
+ LOG_WARN("Error accepting test channel connection errno=%d (%s).", errno, strerror(errno));
+
+ if (errno != EAGAIN && errno != EWOULDBLOCK) {
+ LOG_ERROR("Closing listen_fd_ (won't try again).");
+ close(listen_fd_);
+ return -1;
+ }
+ }
+
+ return accept_fd;
+ }
+
+ private:
+ int listen_fd_ = -1;
+};
+
+class HciHalRootcanalTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ thread_ = new Thread("test_thread", Thread::Priority::NORMAL);
+
+ HciHalHostRootcanalConfig::Get()->SetPort(kTestPort);
+ fake_server_ = new FakeRootcanalDesktopHciServer;
+ hal_ = fake_registry_.Start<HciHal>(thread_);
+ hal_->registerIncomingPacketCallback(&callbacks_);
+ fake_server_socket_ = fake_server_->Accept(); // accept() after client is connected to avoid blocking
+ std::queue<std::pair<uint8_t, HciPacket>> empty;
+ std::swap(incoming_packets_queue_, empty);
+ }
+
+ void TearDown() override {
+ fake_registry_.StopAll();
+ close(fake_server_socket_);
+ delete fake_server_;
+ delete thread_;
+ }
+
+ void SetFakeServerSocketToBlocking() {
+ int flags = fcntl(fake_server_socket_, F_GETFL, NULL);
+ int ret = fcntl(fake_server_socket_, F_SETFL, flags & ~O_NONBLOCK);
+ EXPECT_NE(ret, -1) << "Can't set accept fd to blocking";
+ }
+
+ FakeRootcanalDesktopHciServer* fake_server_ = nullptr;
+ HciHal* hal_ = nullptr;
+ ModuleRegistry fake_registry_;
+ TestHciHalCallbacks callbacks_;
+ int fake_server_socket_ = -1;
+ Thread* thread_;
+};
+
+void check_packet_equal(std::pair<uint8_t, HciPacket> hci_packet1_type_data_pair, H4Packet h4_packet2) {
+ auto packet1_hci_size = hci_packet1_type_data_pair.second.size();
+ EXPECT_EQ(packet1_hci_size + 1, h4_packet2.size());
+ EXPECT_EQ(hci_packet1_type_data_pair.first, h4_packet2[0]);
+ EXPECT_EQ(memcmp(hci_packet1_type_data_pair.second.data(), h4_packet2.data() + 1, packet1_hci_size), 0);
+}
+
+HciPacket make_sample_hci_cmd_pkt(uint8_t parameter_total_length) {
+ HciPacket pkt;
+ pkt.assign(2 + 1 + parameter_total_length, 0x01);
+ pkt[2] = parameter_total_length;
+ return pkt;
+}
+
+HciPacket make_sample_hci_acl_pkt(uint8_t payload_size) {
+ HciPacket pkt;
+ pkt.assign(2 + 2 + payload_size, 0x01);
+ pkt[2] = payload_size;
+ return pkt;
+}
+
+HciPacket make_sample_hci_sco_pkt(uint8_t payload_size) {
+ HciPacket pkt;
+ pkt.assign(3 + payload_size, 0x01);
+ pkt[2] = payload_size;
+ return pkt;
+}
+
+H4Packet make_sample_h4_evt_pkt(uint8_t parameter_total_length) {
+ H4Packet pkt;
+ pkt.assign(1 + 1 + 1 + parameter_total_length, 0x01);
+ pkt[0] = kH4Event;
+ pkt[2] = parameter_total_length;
+ return pkt;
+}
+
+HciPacket make_sample_h4_acl_pkt(uint8_t payload_size) {
+ HciPacket pkt;
+ pkt.assign(1 + 2 + 2 + payload_size, 0x01);
+ pkt[0] = kH4Acl;
+ pkt[3] = payload_size;
+ pkt[4] = 0;
+ return pkt;
+}
+
+HciPacket make_sample_h4_sco_pkt(uint8_t payload_size) {
+ HciPacket pkt;
+ pkt.assign(1 + 3 + payload_size, 0x01);
+ pkt[0] = kH4Sco;
+ pkt[3] = payload_size;
+ return pkt;
+}
+
+TEST_F(HciHalRootcanalTest, init_and_close) {}
+
+TEST_F(HciHalRootcanalTest, receive_hci_evt) {
+ H4Packet incoming_packet = make_sample_h4_evt_pkt(3);
+ write(fake_server_socket_, incoming_packet.data(), incoming_packet.size());
+ while (incoming_packets_queue_.size() != 1) {
+ }
+ auto packet = incoming_packets_queue_.front();
+ incoming_packets_queue_.pop();
+ check_packet_equal(packet, incoming_packet);
+}
+
+TEST_F(HciHalRootcanalTest, receive_hci_acl) {
+ H4Packet incoming_packet = make_sample_h4_acl_pkt(3);
+ write(fake_server_socket_, incoming_packet.data(), incoming_packet.size());
+ while (incoming_packets_queue_.size() != 1) {
+ }
+ auto packet = incoming_packets_queue_.front();
+ incoming_packets_queue_.pop();
+ check_packet_equal(packet, incoming_packet);
+}
+
+TEST_F(HciHalRootcanalTest, receive_hci_sco) {
+ H4Packet incoming_packet = make_sample_h4_sco_pkt(3);
+ write(fake_server_socket_, incoming_packet.data(), incoming_packet.size());
+ while (incoming_packets_queue_.size() != 1) {
+ }
+ auto packet = incoming_packets_queue_.front();
+ incoming_packets_queue_.pop();
+ check_packet_equal(packet, incoming_packet);
+}
+
+TEST_F(HciHalRootcanalTest, receive_two_hci_evts) {
+ H4Packet incoming_packet = make_sample_h4_evt_pkt(3);
+ H4Packet incoming_packet2 = make_sample_h4_evt_pkt(5);
+ write(fake_server_socket_, incoming_packet.data(), incoming_packet.size());
+ write(fake_server_socket_, incoming_packet2.data(), incoming_packet2.size());
+ while (incoming_packets_queue_.size() != 2) {
+ }
+ auto packet = incoming_packets_queue_.front();
+ incoming_packets_queue_.pop();
+ check_packet_equal(packet, incoming_packet);
+ packet = incoming_packets_queue_.front();
+ incoming_packets_queue_.pop();
+ check_packet_equal(packet, incoming_packet2);
+}
+
+TEST_F(HciHalRootcanalTest, receive_evt_and_acl) {
+ H4Packet incoming_packet = make_sample_h4_evt_pkt(3);
+ H4Packet incoming_packet2 = make_sample_h4_acl_pkt(5);
+ write(fake_server_socket_, incoming_packet.data(), incoming_packet.size());
+ write(fake_server_socket_, incoming_packet2.data(), incoming_packet2.size());
+ while (incoming_packets_queue_.size() != 2) {
+ }
+ auto packet = incoming_packets_queue_.front();
+ incoming_packets_queue_.pop();
+ check_packet_equal(packet, incoming_packet);
+ packet = incoming_packets_queue_.front();
+ incoming_packets_queue_.pop();
+ check_packet_equal(packet, incoming_packet2);
+}
+
+TEST_F(HciHalRootcanalTest, receive_multiple_acl_batch) {
+ H4Packet incoming_packet = make_sample_h4_acl_pkt(5);
+ int num_packets = 1000;
+ for (int i = 0; i < num_packets; i++) {
+ write(fake_server_socket_, incoming_packet.data(), incoming_packet.size());
+ }
+ while (incoming_packets_queue_.size() != num_packets) {
+ }
+ for (int i = 0; i < num_packets; i++) {
+ auto packet = incoming_packets_queue_.front();
+ incoming_packets_queue_.pop();
+ check_packet_equal(packet, incoming_packet);
+ }
+}
+
+TEST_F(HciHalRootcanalTest, receive_multiple_acl_sequential) {
+ H4Packet incoming_packet = make_sample_h4_acl_pkt(5);
+ int num_packets = 1000;
+ for (int i = 0; i < num_packets; i++) {
+ write(fake_server_socket_, incoming_packet.data(), incoming_packet.size());
+ while (incoming_packets_queue_.empty()) {
+ }
+ auto packet = incoming_packets_queue_.front();
+ incoming_packets_queue_.pop();
+ check_packet_equal(packet, incoming_packet);
+ }
+}
+
+TEST_F(HciHalRootcanalTest, send_hci_cmd) {
+ uint8_t hci_cmd_param_size = 2;
+ HciPacket hci_data = make_sample_hci_cmd_pkt(hci_cmd_param_size);
+ hal_->sendHciCommand(hci_data);
+ H4Packet read_buf(1 + 2 + 1 + hci_cmd_param_size);
+ SetFakeServerSocketToBlocking();
+ auto size_read = read(fake_server_socket_, read_buf.data(), read_buf.size());
+
+ EXPECT_EQ(size_read, 1 + hci_data.size());
+ check_packet_equal({kH4Command, hci_data}, read_buf);
+}
+
+TEST_F(HciHalRootcanalTest, send_acl) {
+ uint8_t acl_payload_size = 200;
+ HciPacket acl_packet = make_sample_hci_acl_pkt(acl_payload_size);
+ hal_->sendAclData(acl_packet);
+ H4Packet read_buf(1 + 2 + 2 + acl_payload_size);
+ SetFakeServerSocketToBlocking();
+ auto size_read = read(fake_server_socket_, read_buf.data(), read_buf.size());
+
+ EXPECT_EQ(size_read, 1 + acl_packet.size());
+ check_packet_equal({kH4Acl, acl_packet}, read_buf);
+}
+
+TEST_F(HciHalRootcanalTest, send_sco) {
+ uint8_t sco_payload_size = 200;
+ HciPacket sco_packet = make_sample_hci_sco_pkt(sco_payload_size);
+ hal_->sendScoData(sco_packet);
+ H4Packet read_buf(1 + 3 + sco_payload_size);
+ SetFakeServerSocketToBlocking();
+ auto size_read = read(fake_server_socket_, read_buf.data(), read_buf.size());
+
+ EXPECT_EQ(size_read, 1 + sco_packet.size());
+ check_packet_equal({kH4Sco, sco_packet}, read_buf);
+}
+
+TEST_F(HciHalRootcanalTest, send_multiple_acl_batch) {
+ uint8_t acl_payload_size = 200;
+ int num_packets = 1000;
+ HciPacket acl_packet = make_sample_hci_acl_pkt(acl_payload_size);
+ for (int i = 0; i < num_packets; i++) {
+ hal_->sendAclData(acl_packet);
+ }
+ H4Packet read_buf(1 + 2 + 2 + acl_payload_size);
+ SetFakeServerSocketToBlocking();
+ for (int i = 0; i < num_packets; i++) {
+ auto size_read = read(fake_server_socket_, read_buf.data(), read_buf.size());
+ EXPECT_EQ(size_read, 1 + acl_packet.size());
+ check_packet_equal({kH4Acl, acl_packet}, read_buf);
+ }
+}
+
+TEST_F(HciHalRootcanalTest, send_multiple_acl_sequential) {
+ uint8_t acl_payload_size = 200;
+ int num_packets = 1000;
+ HciPacket acl_packet = make_sample_hci_acl_pkt(acl_payload_size);
+ SetFakeServerSocketToBlocking();
+ for (int i = 0; i < num_packets; i++) {
+ hal_->sendAclData(acl_packet);
+ H4Packet read_buf(1 + 2 + 2 + acl_payload_size);
+ auto size_read = read(fake_server_socket_, read_buf.data(), read_buf.size());
+ EXPECT_EQ(size_read, 1 + acl_packet.size());
+ check_packet_equal({kH4Acl, acl_packet}, read_buf);
+ }
+}
+
+} // namespace
+} // namespace hal
+} // namespace bluetooth
diff --git a/gd/hal/snoop_logger.cc b/gd/hal/snoop_logger.cc
new file mode 100644
index 0000000..874fb31
--- /dev/null
+++ b/gd/hal/snoop_logger.cc
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2019 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 "hal/snoop_logger.h"
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <bitset>
+#include <chrono>
+
+#include "os/log.h"
+
+namespace bluetooth {
+namespace hal {
+
+namespace {
+typedef struct {
+ uint32_t length_original;
+ uint32_t length_captured;
+ uint32_t flags;
+ uint32_t dropped_packets;
+ uint64_t timestamp;
+ uint8_t type;
+} __attribute__((__packed__)) btsnoop_packet_header_t;
+
+typedef struct {
+ uint8_t identification_pattern[8];
+ uint32_t version_number;
+ uint32_t datalink_type;
+} __attribute__((__packed__)) btsnoop_file_header_t;
+
+constexpr uint64_t BTSNOOP_EPOCH_DELTA = 0x00dcddb30f2f8000ULL;
+
+constexpr uint32_t kBytesToTest = 0x12345678;
+constexpr uint8_t kFirstByte = (const uint8_t&)kBytesToTest;
+constexpr bool isLittleEndian = kFirstByte == 0x78;
+constexpr bool isBigEndian = kFirstByte == 0x12;
+static_assert(isLittleEndian || isBigEndian && isLittleEndian != isBigEndian);
+
+constexpr uint32_t BTSNOOP_VERSION_NUMBER = isLittleEndian ? 0x01000000 : 1;
+constexpr uint32_t BTSNOOP_DATALINK_TYPE =
+ isLittleEndian ? 0xea030000 : 0x03ea; // Datalink Type code for HCI UART (H4) is 1002
+uint64_t htonll(uint64_t ll) {
+ if constexpr (isLittleEndian) {
+ return static_cast<uint64_t>(htonl(ll & 0xffffffff)) << 32 | htonl(ll >> 32);
+ } else {
+ return ll;
+ }
+}
+
+constexpr btsnoop_file_header_t BTSNOOP_FILE_HEADER = {
+ .identification_pattern = {'b', 't', 's', 'n', 'o', 'o', 'p', 0x00},
+ .version_number = BTSNOOP_VERSION_NUMBER,
+ .datalink_type = BTSNOOP_DATALINK_TYPE};
+} // namespace
+
+SnoopLogger::SnoopLogger() {
+ bool file_exists;
+ {
+ std::ifstream btsnoop_istream(file_path);
+ file_exists = btsnoop_istream.is_open();
+ }
+ btsnoop_ostream_.open(file_path, std::ios::binary | std::ios::app | std::ios::out);
+ if (!file_exists) {
+ LOG_INFO("Creating new BTSNOOP");
+ btsnoop_ostream_.write(reinterpret_cast<const char*>(&BTSNOOP_FILE_HEADER), sizeof(btsnoop_file_header_t));
+ } else {
+ LOG_INFO("Appending to old BTSNOOP");
+ }
+}
+
+void SnoopLogger::SetFilePath(const std::string& filename) {
+ file_path = filename;
+}
+
+void SnoopLogger::capture(const HciPacket& packet, Direction direction, PacketType type) {
+ uint64_t timestamp_us =
+ std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch())
+ .count();
+ std::lock_guard<std::mutex> lock(file_mutex_);
+ std::bitset<32> flags = 0;
+ switch (type) {
+ case PacketType::CMD:
+ flags.set(0, false);
+ flags.set(1, true);
+ break;
+ case PacketType::ACL:
+ flags.set(0, direction == Direction::INCOMING);
+ flags.set(1, false);
+ break;
+ case PacketType::SCO:
+ flags.set(0, direction == Direction::INCOMING);
+ flags.set(1, false);
+ break;
+ case PacketType::EVT:
+ flags.set(0, true);
+ flags.set(1, true);
+ break;
+ }
+ uint32_t length = packet.size() + /* type byte */ 1;
+ btsnoop_packet_header_t header = {.length_original = htonl(length),
+ .length_captured = htonl(length),
+ .flags = htonl(static_cast<uint32_t>(flags.to_ulong())),
+ .dropped_packets = 0,
+ .timestamp = htonll(timestamp_us + BTSNOOP_EPOCH_DELTA),
+ .type = static_cast<uint8_t>(type)};
+ btsnoop_ostream_.write(reinterpret_cast<const char*>(&header), sizeof(btsnoop_packet_header_t));
+ btsnoop_ostream_.write(reinterpret_cast<const char*>(packet.data()), packet.size());
+}
+
+void SnoopLogger::ListDependencies(ModuleList* list) {
+ // We have no dependencies
+}
+
+void SnoopLogger::Start() {}
+
+void SnoopLogger::Stop() {}
+
+std::string SnoopLogger::file_path = SnoopLogger::DefaultFilePath;
+
+const ModuleFactory SnoopLogger::Factory = ModuleFactory([]() {
+ return new SnoopLogger();
+});
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/gd/hal/snoop_logger.h b/gd/hal/snoop_logger.h
new file mode 100644
index 0000000..4e0b90d
--- /dev/null
+++ b/gd/hal/snoop_logger.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2019 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 <fstream>
+#include <iostream>
+#include <mutex>
+#include <string>
+
+#include "hal/hci_hal.h"
+#include "module.h"
+
+namespace bluetooth {
+namespace hal {
+
+class SnoopLogger : public ::bluetooth::Module {
+ public:
+ static const ModuleFactory Factory;
+
+ // Each transport using SnoopLogger should define its own DefaultFilepath
+ static const std::string DefaultFilePath;
+ // Set File Path before module is started to ensure all packets are written to the right file
+ static void SetFilePath(const std::string& filename);
+
+ enum class PacketType {
+ CMD = 1,
+ ACL = 2,
+ SCO = 3,
+ EVT = 4,
+ };
+
+ enum class Direction {
+ INCOMING,
+ OUTGOING,
+ };
+
+ void capture(const HciPacket& packet, Direction direction, PacketType type);
+
+ protected:
+ void ListDependencies(ModuleList* list) override;
+ void Start() override;
+ void Stop() override;
+
+ private:
+ SnoopLogger();
+ static std::string file_path;
+ std::ofstream btsnoop_ostream_;
+ std::mutex file_mutex_;
+};
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/gd/hci/Android.bp b/gd/hci/Android.bp
new file mode 100644
index 0000000..69589ca
--- /dev/null
+++ b/gd/hci/Android.bp
@@ -0,0 +1,14 @@
+filegroup {
+ name: "BluetoothHciSources",
+ srcs: [
+ "hci_layer.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothHciTestSources",
+ srcs: [
+ "acl_builder_test.cc",
+ "hci_layer_test.cc",
+ ],
+}
diff --git a/gd/hci/acl_builder_test.cc b/gd/hci/acl_builder_test.cc
new file mode 100644
index 0000000..7fc59c6
--- /dev/null
+++ b/gd/hci/acl_builder_test.cc
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2018 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 "hci/hci_packets.h"
+
+#include <gtest/gtest.h>
+#include <memory>
+
+#include "os/log.h"
+#include "packet/bit_inserter.h"
+#include "packet/raw_builder.h"
+
+using bluetooth::packet::BitInserter;
+using bluetooth::packet::RawBuilder;
+using std::vector;
+
+namespace {
+vector<uint8_t> information_request = {
+ 0xfe, 0x2e, 0x0a, 0x00, 0x06, 0x00, 0x01, 0x00, 0x0a, 0x02, 0x02, 0x00, 0x02, 0x00,
+};
+// 0x00, 0x01, 0x02, 0x03, ...
+vector<uint8_t> counting_bytes;
+// 0xFF, 0xFE, 0xFD, 0xFC, ...
+vector<uint8_t> counting_down_bytes;
+const size_t count_size = 0x8;
+
+} // namespace
+
+namespace bluetooth {
+namespace hci {
+
+class AclBuilderTest : public ::testing::Test {
+ public:
+ AclBuilderTest() {
+ counting_bytes.reserve(count_size);
+ counting_down_bytes.reserve(count_size);
+ for (size_t i = 0; i < count_size; i++) {
+ counting_bytes.push_back(i);
+ counting_down_bytes.push_back(~i);
+ }
+ }
+ ~AclBuilderTest() = default;
+};
+
+TEST(AclBuilderTest, buildAclCount) {
+ uint16_t handle = 0x0314;
+ PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE;
+ BroadcastFlag broadcast_flag = BroadcastFlag::ACTIVE_SLAVE_BROADCAST;
+
+ std::unique_ptr<RawBuilder> count_payload = std::make_unique<RawBuilder>();
+ count_payload->AddOctets(counting_bytes);
+ ASSERT_EQ(counting_bytes.size(), count_payload->size());
+
+ std::unique_ptr<AclPacketBuilder> count_packet =
+ AclPacketBuilder::Create(handle, packet_boundary_flag, broadcast_flag, std::move(count_payload));
+
+ ASSERT_EQ(counting_bytes.size() + 4, count_packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> count_packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*count_packet_bytes);
+ count_packet->Serialize(it);
+
+ PacketView<true> count_packet_bytes_view(count_packet_bytes);
+ AclPacketView count_packet_view = AclPacketView::Create(count_packet_bytes_view);
+ ASSERT_TRUE(count_packet_view.IsValid());
+
+ ASSERT_EQ(handle, count_packet_view.GetHandle());
+ ASSERT_EQ(packet_boundary_flag, count_packet_view.GetPacketBoundaryFlag());
+ ASSERT_EQ(broadcast_flag, count_packet_view.GetBroadcastFlag());
+ PacketView<true> count_view = count_packet_view.GetPayload();
+
+ ASSERT_EQ(count_view.size(), counting_bytes.size());
+ for (size_t i = 0; i < count_view.size(); i++) {
+ ASSERT_EQ(count_view[i], counting_bytes[i]);
+ }
+}
+
+TEST(AclBuilderTest, buildAclCountInverted) {
+ uint16_t handle = 0x0304;
+ PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::CONTINUING_FRAGMENT;
+ BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT;
+
+ std::unique_ptr<RawBuilder> counting_down_bytes_payload = std::make_unique<RawBuilder>();
+ counting_down_bytes_payload->AddOctets(counting_down_bytes);
+ ASSERT_EQ(counting_down_bytes.size(), counting_down_bytes_payload->size());
+
+ std::unique_ptr<AclPacketBuilder> counting_down_bytes_packet =
+ AclPacketBuilder::Create(handle, packet_boundary_flag, broadcast_flag, std::move(counting_down_bytes_payload));
+
+ ASSERT_EQ(counting_down_bytes.size() + 4, counting_down_bytes_packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> counting_down_bytes_packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*counting_down_bytes_packet_bytes);
+ counting_down_bytes_packet->Serialize(it);
+ PacketView<true> counting_down_bytes_packet_bytes_view(counting_down_bytes_packet_bytes);
+ AclPacketView counting_down_bytes_packet_view = AclPacketView::Create(counting_down_bytes_packet_bytes_view);
+ ASSERT_TRUE(counting_down_bytes_packet_view.IsValid());
+
+ ASSERT_EQ(handle, counting_down_bytes_packet_view.GetHandle());
+ ASSERT_EQ(packet_boundary_flag, counting_down_bytes_packet_view.GetPacketBoundaryFlag());
+ ASSERT_EQ(broadcast_flag, counting_down_bytes_packet_view.GetBroadcastFlag());
+ PacketView<true> counting_down_bytes_view = counting_down_bytes_packet_view.GetPayload();
+
+ ASSERT_EQ(counting_down_bytes_view.size(), counting_down_bytes.size());
+ for (size_t i = 0; i < counting_down_bytes_view.size(); i++) {
+ ASSERT_EQ(counting_down_bytes_view[i], counting_down_bytes[i]);
+ }
+}
+
+TEST(AclBuilderTest, buildInformationRequest) {
+ uint16_t handle = 0x0efe;
+ PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE;
+ BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT;
+
+ std::vector<uint8_t> payload_bytes(information_request.begin() + 4, information_request.end());
+ std::unique_ptr<RawBuilder> payload = std::make_unique<RawBuilder>();
+ payload->AddOctets(payload_bytes);
+ ASSERT_EQ(payload_bytes.size(), payload->size());
+
+ std::unique_ptr<AclPacketBuilder> packet =
+ AclPacketBuilder::Create(handle, packet_boundary_flag, broadcast_flag, std::move(payload));
+
+ ASSERT_EQ(information_request.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+ PacketView<true> packet_bytes_view(packet_bytes);
+ AclPacketView packet_view = AclPacketView::Create(packet_bytes_view);
+ ASSERT_TRUE(packet_view.IsValid());
+
+ ASSERT_EQ(packet_bytes->size(), information_request.size());
+ for (size_t i = 0; i < packet_bytes->size(); i++) {
+ ASSERT_EQ((*packet_bytes)[i], information_request[i]);
+ }
+
+ ASSERT_EQ(handle, packet_view.GetHandle());
+ ASSERT_EQ(packet_boundary_flag, packet_view.GetPacketBoundaryFlag());
+ ASSERT_EQ(broadcast_flag, packet_view.GetBroadcastFlag());
+ PacketView<true> payload_view = packet_view.GetPayload();
+
+ ASSERT_EQ(payload_view.size(), payload_bytes.size());
+ for (size_t i = 0; i < payload_view.size(); i++) {
+ ASSERT_EQ(payload_view[i], payload_bytes[i]);
+ }
+
+ ASSERT_EQ(packet_view.size(), information_request.size());
+ for (size_t i = 0; i < packet_view.size(); i++) {
+ ASSERT_EQ(packet_view[i], information_request[i]);
+ }
+}
+
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/hci_layer.cc b/gd/hci/hci_layer.cc
new file mode 100644
index 0000000..95a373f
--- /dev/null
+++ b/gd/hci/hci_layer.cc
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2019 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 "hci/hci_layer.h"
+
+#include "packet/packet_builder.h"
+
+namespace {
+using bluetooth::hci::CommandCompleteView;
+using bluetooth::hci::CommandPacketBuilder;
+using bluetooth::hci::CommandStatusView;
+using bluetooth::hci::EventPacketView;
+using bluetooth::os::Handler;
+
+class EventHandler {
+ public:
+ EventHandler() : event_handler(), handler(nullptr) {}
+ EventHandler(std::function<void(EventPacketView)> on_event, Handler* on_event_handler)
+ : event_handler(on_event), handler(on_event_handler) {}
+ std::function<void(EventPacketView)> event_handler;
+ Handler* handler;
+};
+
+class CommandQueueEntry {
+ public:
+ CommandQueueEntry(std::unique_ptr<CommandPacketBuilder> command_packet,
+ std::function<void(CommandStatusView)> on_status_function,
+ std::function<void(CommandCompleteView)> on_complete_function, Handler* handler)
+ : command(std::move(command_packet)), on_status(on_status_function), on_complete(on_complete_function),
+ caller_handler(handler) {}
+
+ std::unique_ptr<CommandPacketBuilder> command;
+ std::function<void(CommandStatusView)> on_status;
+ std::function<void(CommandCompleteView)> on_complete;
+ Handler* caller_handler;
+};
+} // namespace
+
+namespace bluetooth {
+namespace hci {
+
+using common::Address;
+using common::BidiQueue;
+using common::BidiQueueEnd;
+using os::Handler;
+
+struct HciLayer::impl : public hal::HciHalCallbacks {
+ impl(HciLayer& module) : hal_(nullptr), module_(module) {}
+
+ void Start(hal::HciHal* hal) {
+ hal_ = hal;
+
+ send_acl_ = [this](std::unique_ptr<hci::BasePacketBuilder> packet) {
+ std::vector<uint8_t> bytes;
+ BitInserter bi(bytes);
+ packet->Serialize(bi);
+ hal_->sendAclData(bytes);
+ };
+ send_sco_ = [this](std::unique_ptr<hci::BasePacketBuilder> packet) {
+ std::vector<uint8_t> bytes;
+ BitInserter bi(bytes);
+ packet->Serialize(bi);
+ hal_->sendScoData(bytes);
+ };
+ auto queue_end = acl_queue_.GetDownEnd();
+ Handler* handler = module_.GetHandler();
+ queue_end->RegisterDequeue(handler, [queue_end, this]() { send_acl_(queue_end->TryDequeue()); });
+ RegisterEventHandler(EventCode::COMMAND_COMPLETE, [this](EventPacketView event) { CommandCompleteCallback(event); },
+ handler);
+ RegisterEventHandler(EventCode::COMMAND_STATUS, [this](EventPacketView event) { CommandStatusCallback(event); },
+ handler);
+ hal_->registerIncomingPacketCallback(this);
+ }
+
+ void Stop() {
+ acl_queue_.GetDownEnd()->UnregisterDequeue();
+ hal_ = nullptr;
+ }
+
+ void CommandStatusCallback(EventPacketView event) {
+ CommandStatusView status_view = CommandStatusView::Create(event);
+ ASSERT(status_view.IsValid());
+ if (command_queue_.size() == 0) {
+ ASSERT_LOG(status_view.GetCommandOpCode() == OpCode::NONE, "Unexpected status event with OpCode 0x%02hx",
+ status_view.GetCommandOpCode());
+ return;
+ }
+ // TODO: Check whether this is the CommandOpCode we're looking for.
+ auto caller_handler = command_queue_.front().caller_handler;
+ auto on_status = command_queue_.front().on_status;
+ caller_handler->Post([on_status, status_view]() { on_status(status_view); });
+ command_queue_.pop();
+ }
+
+ void CommandCompleteCallback(EventPacketView event) {
+ CommandCompleteView complete_view = CommandCompleteView::Create(event);
+ ASSERT(complete_view.IsValid());
+ if (command_queue_.size() == 0) {
+ ASSERT_LOG(complete_view.GetCommandOpCode() == OpCode::NONE,
+ "Unexpected command complete event with OpCode 0x%02hx", complete_view.GetCommandOpCode());
+ return;
+ }
+ // TODO: Check whether this is the CommandOpCode we're looking for.
+ auto caller_handler = command_queue_.front().caller_handler;
+ auto on_complete = command_queue_.front().on_complete;
+ caller_handler->Post([on_complete, complete_view]() { on_complete(complete_view); });
+ command_queue_.pop();
+ }
+
+ void hciEventReceived(hal::HciPacket event_bytes) override {
+ auto packet = packet::PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>(event_bytes));
+ EventPacketView event = EventPacketView::Create(packet);
+ ASSERT(event.IsValid());
+ EventCode event_code = event.GetEventCode();
+
+ Handler* hci_handler = module_.GetHandler();
+ hci_handler->Post([this, event, event_code]() {
+ ASSERT_LOG(event_handlers_.find(event_code) != event_handlers_.end(), "Unhandled event of type 0x%02hhx",
+ event.GetEventCode());
+ auto& registered_handler = event_handlers_[event_code].event_handler;
+ event_handlers_[event_code].handler->Post([event, registered_handler]() { registered_handler(event); });
+ });
+ // TODO: Credits
+ }
+
+ void aclDataReceived(hal::HciPacket data_bytes) override {
+ module_.GetHandler()->Post([this, data_bytes]() {
+ auto queue_end = acl_queue_.GetDownEnd();
+ Handler* hci_handler = module_.GetHandler();
+ queue_end->RegisterEnqueue(hci_handler, [queue_end, data_bytes]() {
+ auto packet = packet::PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>(data_bytes));
+ AclPacketView acl2 = AclPacketView::Create(packet);
+ queue_end->UnregisterEnqueue();
+ return std::make_unique<AclPacketView>(acl2);
+ });
+ });
+ }
+
+ void scoDataReceived(hal::HciPacket data_bytes) override {
+ auto packet = packet::PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>(data_bytes));
+ ScoPacketView sco = ScoPacketView::Create(packet);
+ }
+
+ void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command, std::function<void(CommandStatusView)> on_status,
+ std::function<void(CommandCompleteView)> on_complete, Handler* handler) {
+ command_queue_.emplace(std::move(command), on_status, on_complete, handler);
+
+ if (command_queue_.size() == 1) {
+ std::vector<uint8_t> bytes;
+ BitInserter bi(bytes);
+ command_queue_.front().command->Serialize(bi);
+ hal_->sendHciCommand(bytes);
+ }
+ }
+
+ BidiQueueEnd<AclPacketBuilder, AclPacketView>* GetAclQueueEnd() {
+ return acl_queue_.GetUpEnd();
+ }
+
+ void RegisterEventHandler(EventCode event_code, std::function<void(EventPacketView)> event_handler,
+ Handler* handler) {
+ ASSERT_LOG(event_handlers_.count(event_code) == 0, "Can not register a second handler for event_code %02hhx",
+ event_code);
+ EventHandler to_save(event_handler, handler);
+ event_handlers_[event_code] = to_save;
+ }
+
+ void UnregisterEventHandler(EventCode event_code) {
+ event_handlers_.erase(event_code);
+ }
+
+ // The HAL
+ hal::HciHal* hal_;
+
+ // A reference to the HciLayer module
+ HciLayer& module_;
+
+ // Conversion functions for sending bytes from Builders
+ std::function<void(std::unique_ptr<hci::BasePacketBuilder>)> send_acl_;
+ std::function<void(std::unique_ptr<hci::BasePacketBuilder>)> send_sco_;
+
+ // Command Handling
+ std::queue<CommandQueueEntry> command_queue_;
+
+ std::map<EventCode, EventHandler> event_handlers_;
+ OpCode waiting_command_;
+
+ // Acl packets
+ BidiQueue<AclPacketView, AclPacketBuilder> acl_queue_{3 /* TODO: Set queue depth */};
+};
+
+HciLayer::HciLayer() : impl_(std::make_unique<impl>(*this)) {}
+
+HciLayer::~HciLayer() {
+ impl_.reset();
+}
+
+void HciLayer::EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
+ std::function<void(CommandStatusView)> on_status,
+ std::function<void(CommandCompleteView)> on_complete, Handler* handler) {
+ impl_->EnqueueCommand(std::move(command), on_status, on_complete, handler);
+}
+
+common::BidiQueueEnd<AclPacketBuilder, AclPacketView>* HciLayer::GetAclQueueEnd() {
+ return impl_->GetAclQueueEnd();
+}
+
+void HciLayer::RegisterEventHandler(EventCode event_code, std::function<void(EventPacketView)> event_handler,
+ Handler* handler) {
+ impl_->RegisterEventHandler(event_code, event_handler, handler);
+}
+
+void HciLayer::UnregisterEventHandler(EventCode event_code) {
+ impl_->UnregisterEventHandler(event_code);
+}
+
+const ModuleFactory HciLayer::Factory = ModuleFactory([]() { return new HciLayer(); });
+
+void HciLayer::ListDependencies(ModuleList* list) {
+ list->add<hal::HciHal>();
+}
+
+void HciLayer::Start() {
+ impl_->Start(GetDependency<hal::HciHal>());
+}
+
+void HciLayer::Stop() {
+ impl_->Stop();
+}
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/hci_layer.h b/gd/hci/hci_layer.h
new file mode 100644
index 0000000..a841a0d
--- /dev/null
+++ b/gd/hci/hci_layer.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2019 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 <map>
+
+#include "common/address.h"
+#include "common/bidi_queue.h"
+#include "common/class_of_device.h"
+#include "hal/hci_hal.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "os/utils.h"
+
+namespace bluetooth {
+namespace hci {
+
+class HciLayer : public Module {
+ public:
+ HciLayer();
+ virtual ~HciLayer();
+ DISALLOW_COPY_AND_ASSIGN(HciLayer);
+
+ virtual void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
+ std::function<void(CommandStatusView)> on_status,
+ std::function<void(CommandCompleteView)> on_complete, os::Handler* handler);
+
+ virtual common::BidiQueueEnd<AclPacketBuilder, AclPacketView>* GetAclQueueEnd();
+
+ virtual void RegisterEventHandler(EventCode event_code, std::function<void(EventPacketView)> event_handler,
+ os::Handler* handler);
+
+ virtual void UnregisterEventHandler(EventCode event_code);
+
+ static const ModuleFactory Factory;
+
+ void ListDependencies(ModuleList* list) override;
+
+ void Start() override;
+
+ void Stop() override;
+
+ private:
+ struct impl;
+ std::unique_ptr<impl> impl_;
+};
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/hci_layer_test.cc b/gd/hci/hci_layer_test.cc
new file mode 100644
index 0000000..aba2f22
--- /dev/null
+++ b/gd/hci/hci_layer_test.cc
@@ -0,0 +1,291 @@
+/*
+ * Copyright 2019 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 "hci/hci_layer.h"
+
+#include <gtest/gtest.h>
+#include <list>
+#include <memory>
+
+#include "hal/hci_hal.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "os/log.h"
+#include "os/thread.h"
+#include "packet/bit_inserter.h"
+#include "packet/raw_builder.h"
+
+using bluetooth::os::Thread;
+using bluetooth::packet::BitInserter;
+using bluetooth::packet::RawBuilder;
+using std::vector;
+
+namespace {
+vector<uint8_t> information_request = {
+ 0xfe, 0x2e, 0x0a, 0x00, 0x06, 0x00, 0x01, 0x00, 0x0a, 0x02, 0x02, 0x00, 0x02, 0x00,
+};
+// 0x00, 0x01, 0x02, 0x03, ...
+vector<uint8_t> counting_bytes;
+// 0xFF, 0xFE, 0xFD, 0xFC, ...
+vector<uint8_t> counting_down_bytes;
+const size_t count_size = 0x8;
+
+} // namespace
+
+namespace bluetooth {
+namespace hci {
+
+class TestHciHal : public hal::HciHal {
+ public:
+ TestHciHal() : hal::HciHal() {}
+
+ virtual void registerIncomingPacketCallback(hal::HciHalCallbacks* callback) {
+ callbacks = callback;
+ }
+
+ virtual void sendHciCommand(hal::HciPacket command) {
+ outgoing_commands_.push_back(std::move(command));
+ }
+
+ virtual void sendAclData(hal::HciPacket data) {
+ outgoing_acl_.push_front(std::move(data));
+ }
+
+ virtual void sendScoData(hal::HciPacket data) {
+ outgoing_sco_.push_front(std::move(data));
+ }
+
+ hal::HciHalCallbacks* callbacks = nullptr;
+
+ PacketView<kLittleEndian> GetPacketView(hal::HciPacket data) {
+ auto shared = std::make_shared<std::vector<uint8_t>>(data);
+ return PacketView<kLittleEndian>(shared);
+ }
+
+ PacketView<kLittleEndian> GetSentCommand() {
+ while (outgoing_commands_.size() == 0)
+ ;
+ auto packetview = GetPacketView(std::move(outgoing_commands_.front()));
+ outgoing_commands_.pop_front();
+ return packetview;
+ }
+
+ PacketView<kLittleEndian> GetSentAcl() {
+ while (outgoing_acl_.size() == 0)
+ ;
+ auto packetview = GetPacketView(std::move(outgoing_acl_.front()));
+ outgoing_acl_.pop_front();
+ return packetview;
+ }
+
+ void Start() {}
+
+ void Stop() {}
+
+ void ListDependencies(ModuleList*) {}
+
+ static const ModuleFactory Factory;
+
+ private:
+ std::list<hal::HciPacket> outgoing_commands_;
+ std::list<hal::HciPacket> outgoing_acl_;
+ std::list<hal::HciPacket> outgoing_sco_;
+};
+
+const ModuleFactory TestHciHal::Factory = ModuleFactory([]() { return new TestHciHal(); });
+
+class DependsOnHci : public Module {
+ public:
+ DependsOnHci() : Module() {}
+
+ void SendHciCommand(std::unique_ptr<CommandPacketBuilder> command) {
+ hci_->EnqueueCommand(std::move(command), [this](CommandStatusView status) { incoming_events_.push_back(status); },
+ [this](CommandCompleteView complete) { incoming_events_.push_back(complete); }, GetHandler());
+ }
+
+ void SendAclData(std::unique_ptr<AclPacketBuilder> acl) {
+ AclPacketBuilder* raw_acl_pointer = acl.release();
+ auto queue_end = hci_->GetAclQueueEnd();
+ queue_end->RegisterEnqueue(GetHandler(), [queue_end, raw_acl_pointer]() -> std::unique_ptr<AclPacketBuilder> {
+ queue_end->UnregisterEnqueue();
+ return std::unique_ptr<AclPacketBuilder>(raw_acl_pointer);
+ });
+ }
+
+ EventPacketView GetReceivedEvent() {
+ while (incoming_events_.size() == 0)
+ ;
+ EventPacketView packetview = incoming_events_.front();
+ incoming_events_.pop_front();
+ return packetview;
+ }
+
+ AclPacketView GetReceivedAcl() {
+ auto queue_end = hci_->GetAclQueueEnd();
+ std::unique_ptr<AclPacketView> incoming_acl_ptr;
+ while (incoming_acl_ptr == nullptr) {
+ incoming_acl_ptr = queue_end->TryDequeue();
+ }
+ AclPacketView packetview = *incoming_acl_ptr;
+ return packetview;
+ }
+
+ void Start() {
+ hci_ = GetDependency<HciLayer>();
+ hci_->RegisterEventHandler(EventCode::CONNECTION_COMPLETE,
+ [this](EventPacketView event) { incoming_events_.push_back(event); }, GetHandler());
+ }
+
+ void Stop() {}
+
+ void ListDependencies(ModuleList* list) {
+ list->add<HciLayer>();
+ }
+
+ static const ModuleFactory Factory;
+
+ private:
+ HciLayer* hci_ = nullptr;
+ std::list<EventPacketView> incoming_events_;
+};
+
+const ModuleFactory DependsOnHci::Factory = ModuleFactory([]() { return new DependsOnHci(); });
+
+class HciTest : public ::testing::Test {
+ public:
+ void SetUp() override {
+ counting_bytes.reserve(count_size);
+ counting_down_bytes.reserve(count_size);
+ for (size_t i = 0; i < count_size; i++) {
+ counting_bytes.push_back(i);
+ counting_down_bytes.push_back(~i);
+ }
+ hal = new TestHciHal();
+ fake_registry_.InjectTestModule(&hal::HciHal::Factory, hal);
+ fake_registry_.Start<DependsOnHci>(&fake_registry_.GetTestThread());
+ hci = static_cast<HciLayer*>(fake_registry_.GetModuleUnderTest(&HciLayer::Factory));
+ upper = static_cast<DependsOnHci*>(fake_registry_.GetModuleUnderTest(&DependsOnHci::Factory));
+ ASSERT(fake_registry_.IsStarted<HciLayer>());
+ }
+
+ void TearDown() override {
+ fake_registry_.StopAll();
+ }
+
+ std::vector<uint8_t> GetPacketBytes(std::unique_ptr<packet::BasePacketBuilder> packet) {
+ std::vector<uint8_t> bytes;
+ BitInserter i(bytes);
+ bytes.reserve(packet->size());
+ packet->Serialize(i);
+ return bytes;
+ }
+
+ DependsOnHci* upper = nullptr;
+ TestHciHal* hal = nullptr;
+ HciLayer* hci = nullptr;
+ TestModuleRegistry fake_registry_;
+};
+
+TEST_F(HciTest, initAndClose) {}
+
+TEST_F(HciTest, createConnectionTest) {
+ // Send CreateConnection to the controller
+ common::Address bd_addr;
+ ASSERT_TRUE(common::Address::FromString("A1:A2:A3:A4:A5:A6", bd_addr));
+ uint16_t packet_type = 0x1234;
+ PageScanRepetitionMode page_scan_repetition_mode = PageScanRepetitionMode::R0;
+ uint16_t clock_offset = 0x3456;
+ ClockOffsetValid clock_offset_valid = ClockOffsetValid::VALID;
+ CreateConnectionRoleSwitch allow_role_switch = CreateConnectionRoleSwitch::ALLOW_ROLE_SWITCH;
+ upper->SendHciCommand(CreateConnectionBuilder::Create(bd_addr, packet_type, page_scan_repetition_mode, clock_offset,
+ clock_offset_valid, allow_role_switch));
+
+ // Check the command
+ auto sent_command = hal->GetSentCommand();
+ ASSERT_LT(0, sent_command.size());
+ CreateConnectionView view =
+ CreateConnectionView::Create(ConnectionManagementCommandView::Create(CommandPacketView::Create(sent_command)));
+ ASSERT_TRUE(view.IsValid());
+ ASSERT_EQ(bd_addr, view.GetBdAddr());
+ ASSERT_EQ(packet_type, view.GetPacketType());
+ ASSERT_EQ(page_scan_repetition_mode, view.GetPageScanRepetitionMode());
+ ASSERT_EQ(clock_offset, view.GetClockOffset());
+ ASSERT_EQ(clock_offset_valid, view.GetClockOffsetValid());
+ ASSERT_EQ(allow_role_switch, view.GetAllowRoleSwitch());
+
+ // Send a ConnectionComplete to the host
+ ErrorCode status = ErrorCode::SUCCESS;
+ uint16_t handle = 0x123;
+ LinkType link_type = LinkType::ACL;
+ Enable encryption_enabled = Enable::DISABLED;
+ hal->callbacks->hciEventReceived(GetPacketBytes(CreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 1)));
+
+ // Verify the event
+ auto event = upper->GetReceivedEvent();
+ ASSERT_TRUE(event.IsValid());
+ ASSERT_EQ(EventCode::COMMAND_STATUS, event.GetEventCode());
+
+ hal->callbacks->hciEventReceived(
+ GetPacketBytes(ConnectionCompleteBuilder::Create(status, handle, bd_addr, link_type, encryption_enabled)));
+
+ // Verify the event
+ event = upper->GetReceivedEvent();
+ ASSERT_TRUE(event.IsValid());
+ ASSERT_EQ(EventCode::CONNECTION_COMPLETE, event.GetEventCode());
+ ConnectionCompleteView connection_complete_view = ConnectionCompleteView::Create(event);
+ ASSERT_TRUE(connection_complete_view.IsValid());
+ ASSERT_EQ(status, connection_complete_view.GetStatus());
+ ASSERT_EQ(handle, connection_complete_view.GetConnectionHandle());
+ ASSERT_EQ(link_type, connection_complete_view.GetLinkType());
+ ASSERT_EQ(encryption_enabled, connection_complete_view.GetEncryptionEnabled());
+
+ // Send an ACL packet from the remote
+ PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::COMPLETE_PDU;
+ BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT;
+ auto acl_payload = std::make_unique<RawBuilder>();
+ acl_payload->AddAddress(bd_addr);
+ acl_payload->AddOctets2(handle);
+ hal->callbacks->aclDataReceived(
+ GetPacketBytes(AclPacketBuilder::Create(handle, packet_boundary_flag, broadcast_flag, std::move(acl_payload))));
+
+ // Verify the ACL packet
+ auto acl_view = upper->GetReceivedAcl();
+ ASSERT_TRUE(acl_view.IsValid());
+ ASSERT_EQ(sizeof(bd_addr) + sizeof(handle), acl_view.GetPayload().size());
+ auto itr = acl_view.GetPayload().begin();
+ ASSERT_EQ(bd_addr, itr.extract<Address>());
+ ASSERT_EQ(handle, itr.extract<uint16_t>());
+
+ // Send an ACL packet from DependsOnHci
+ PacketBoundaryFlag packet_boundary_flag2 = PacketBoundaryFlag::COMPLETE_PDU;
+ BroadcastFlag broadcast_flag2 = BroadcastFlag::POINT_TO_POINT;
+ auto acl_payload2 = std::make_unique<RawBuilder>();
+ acl_payload2->AddOctets2(handle);
+ acl_payload2->AddAddress(bd_addr);
+ upper->SendAclData(AclPacketBuilder::Create(handle, packet_boundary_flag2, broadcast_flag2, std::move(acl_payload2)));
+
+ // Verify the ACL packet
+ auto sent_acl = hal->GetSentAcl();
+ ASSERT_LT(0, sent_acl.size());
+ AclPacketView sent_acl_view = AclPacketView::Create(sent_acl);
+ ASSERT_TRUE(sent_acl_view.IsValid());
+ ASSERT_EQ(sizeof(bd_addr) + sizeof(handle), sent_acl_view.GetPayload().size());
+ auto sent_itr = sent_acl_view.GetPayload().begin();
+ ASSERT_EQ(handle, sent_itr.extract<uint16_t>());
+ ASSERT_EQ(bd_addr, sent_itr.extract<Address>());
+}
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/hci_packets.pdl b/gd/hci/hci_packets.pdl
new file mode 100644
index 0000000..6d57c95
--- /dev/null
+++ b/gd/hci/hci_packets.pdl
@@ -0,0 +1,2545 @@
+little_endian_packets
+
+custom_field Address : 48 "common/"
+custom_field ClassOfDevice : 24 "common/"
+
+enum Enable : 8 {
+ DISABLED = 0x00,
+ ENABLED = 0x01,
+}
+
+// https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile
+enum GapDataTypes : 8 {
+ FLAGS = 0x01,
+ INCOMPLETE_LIST_16_BIT_UUIDS = 0x02,
+ COMPLETE_LIST_16_BIT_UUIDS = 0x03,
+ INCOMPLETE_LIST_32_BIT_UUIDS = 0x04,
+ COMPLETE_LIST_32_BIT_UUIDS = 0x05,
+ INCOMPLETE_LIST_128_BIT_UUIDS = 0x06,
+ COMPLETE_LIST_128_BIT_UUIDS = 0x07,
+ SHORTENED_LOCAL_NAME = 0x08,
+ COMPLETE_LOCAL_NAME = 0x09,
+ TX_POWER_LEVEL = 0x0A,
+ CLASS_OF_DEVICE = 0x0D,
+}
+
+// HCI ACL Packets
+
+enum PacketBoundaryFlag : 2 {
+ FIRST_NON_AUTOMATICALLY_FLUSHABLE = 0,
+ CONTINUING_FRAGMENT = 1,
+ FIRST_AUTOMATICALLY_FLUSHABLE = 2,
+ COMPLETE_PDU = 3,
+}
+
+enum BroadcastFlag : 2 {
+ POINT_TO_POINT = 0,
+ ACTIVE_SLAVE_BROADCAST = 1,
+}
+
+packet AclPacket {
+ handle : 12,
+ packet_boundary_flag : PacketBoundaryFlag,
+ broadcast_flag : BroadcastFlag,
+ _size_(_payload_) : 16,
+ _payload_,
+}
+
+// HCI SCO Packets
+
+enum PacketStatusFlag : 2 {
+ CORRECTLY_RECEIVED = 0,
+ POSSIBLY_INCOMPLETE = 1,
+ NO_DATA = 2,
+ PARTIALLY_LOST = 3,
+}
+
+packet ScoPacket {
+ handle : 12,
+ packet_status_flag : PacketStatusFlag,
+ _reserved_ : 2, // BroadcastFlag
+ _size_(_payload_) : 8,
+ _payload_,
+}
+
+// HCI Command Packets
+
+enum OpCode : 16 {
+ NONE = 0x0000,
+
+ // LINK_CONTROL
+ INQUIRY = 0x0401,
+ INQUIRY_CANCEL = 0x0402,
+ PERIODIC_INQUIRY_MODE = 0x0403,
+ EXIT_PERIODIC_INQUIRY_MODE = 0x0404,
+ CREATE_CONNECTION = 0x0405,
+ DISCONNECT = 0x0406,
+ CREATE_CONNECTION_CANCEL = 0x0408,
+ ACCEPT_CONNECTION_REQUEST = 0x0409,
+ REJECT_CONNECTION_REQUEST = 0x040A,
+ LINK_KEY_REQUEST_REPLY = 0x040B,
+ LINK_KEY_REQUEST_NEGATIVE_REPLY = 0x040C,
+ PIN_CODE_REQUEST_REPLY = 0x040D,
+ PIN_CODE_REQUEST_NEGATIVE_REPLY = 0x040E,
+ CHANGE_CONNECTION_PACKET_TYPE = 0x040F,
+ AUTHENTICATION_REQUESTED = 0x0411,
+ SET_CONNECTION_ENCRYPTION = 0x0413,
+ CHANGE_CONNECTION_LINK_KEY = 0x0415,
+ MASTER_LINK_KEY = 0x0417,
+ REMOTE_NAME_REQUEST = 0x0419,
+ REMOTE_NAME_REQUEST_CANCEL = 0x041A,
+ READ_REMOTE_SUPPORTED_FEATURES = 0x041B,
+ READ_REMOTE_EXTENDED_FEATURES = 0x041C,
+ READ_REMOTE_VERSION_INFORMATION = 0x041D,
+ READ_CLOCK_OFFSET = 0x041F,
+ READ_LMP_HANDLE = 0x0420,
+ SETUP_SYNCHRONOUS_CONNECTION = 0x0428,
+ ACCEPT_SYNCHRONOUS_CONNECTION = 0x0429,
+ REJECT_SYNCHRONOUS_CONNECTION = 0x042A,
+ IO_CAPABILITY_REQUEST_REPLY = 0x042B,
+ USER_CONFIRMATION_REQUEST_REPLY = 0x042C,
+ USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY = 0x042D,
+ USER_PASSKEY_REQUEST_REPLY = 0x042E,
+ USER_PASSKEY_REQUEST_NEGATIVE_REPLY = 0x042F,
+ REMOTE_OOB_DATA_REQUEST_REPLY = 0x0430,
+ REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY = 0x0433,
+ IO_CAPABILITY_REQUEST_NEGATIVE_REPLY = 0x0434,
+ ENHANCED_SETUP_SYNCHRONOUS_CONNECTION = 0x043D,
+ ENHANCED_ACCEPT_SYNCHRONOUS_CONNECTION = 0x043E,
+
+ // LINK_POLICY
+ HOLD_MODE = 0x0801,
+ SNIFF_MODE = 0x0803,
+ EXIT_SNIFF_MODE = 0x0804,
+ QOS_SETUP = 0x0807,
+ ROLE_DISCOVERY = 0x0809,
+ SWITCH_ROLE = 0x080B,
+ READ_LINK_POLICY_SETTINGS = 0x080C,
+ WRITE_LINK_POLICY_SETTINGS = 0x080D,
+ READ_DEFAULT_LINK_POLICY_SETTINGS = 0x080E,
+ WRITE_DEFAULT_LINK_POLICY_SETTINGS = 0x080F,
+ FLOW_SPECIFICATION = 0x0810,
+ SNIFF_SUBRATING = 0x0811,
+
+ // CONTROLLER_AND_BASEBAND
+ SET_EVENT_MASK = 0x0C01,
+ RESET = 0x0C03,
+ SET_EVENT_FILTER = 0x0C05,
+ FLUSH = 0x0C08,
+ READ_PIN_TYPE = 0x0C09,
+ WRITE_PIN_TYPE = 0x0C0A,
+ CREATE_NEW_UNIT_KEY = 0x0C0B,
+ READ_STORED_LINK_KEY = 0x0C0D,
+ WRITE_STORED_LINK_KEY = 0x0C11,
+ DELETE_STORED_LINK_KEY = 0x0C12,
+ WRITE_LOCAL_NAME = 0x0C13,
+ READ_LOCAL_NAME = 0x0C14,
+ READ_CONNECTION_ACCEPT_TIMEOUT = 0x0C15,
+ WRITE_CONNECTION_ACCEPT_TIMEOUT = 0x0C16,
+ READ_PAGE_TIMEOUT = 0x0C17,
+ WRITE_PAGE_TIMEOUT = 0x0C18,
+ READ_SCAN_ENABLE = 0x0C19,
+ WRITE_SCAN_ENABLE = 0x0C1A,
+ READ_PAGE_SCAN_ACTIVITY = 0x0C1B,
+ WRITE_PAGE_SCAN_ACTIVITY = 0x0C1C,
+ READ_INQUIRY_SCAN_ACTIVITY = 0x0C1D,
+ WRITE_INQUIRY_SCAN_ACTIVITY = 0x0C1E,
+ READ_AUTHENTICATION_ENABLE = 0x0C1F,
+ WRITE_AUTHENTICATION_ENABLE = 0x0C20,
+ READ_CLASS_OF_DEVICE = 0x0C23,
+ WRITE_CLASS_OF_DEVICE = 0x0C24,
+ READ_VOICE_SETTING = 0x0C25,
+ WRITE_VOICE_SETTING = 0x0C26,
+ READ_AUTOMATIC_FLUSH_TIMEOUT = 0x0C27,
+ WRITE_AUTOMATIC_FLUSH_TIMEOUT = 0x0C28,
+ READ_NUM_BROADCAST_RETRANSMITS = 0x0C29,
+ WRITE_NUM_BROADCAST_RETRANSMITS = 0x0C2A,
+ READ_HOLD_MODE_ACTIVITY = 0x0C2B,
+ WRITE_HOLD_MODE_ACTIVITY = 0x0C2C,
+ READ_TRANSMIT_POWER_LEVEL = 0x0C2D,
+ READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE = 0x0C2E,
+ WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE = 0x0C2F,
+ SET_CONTROLLER_TO_HOST_FLOW_CONTROL = 0x0C31,
+ HOST_BUFFER_SIZE = 0x0C33,
+ HOST_NUM_COMPLETED_PACKETS = 0x0C35,
+ READ_LINK_SUPERVISION_TIMEOUT = 0x0C36,
+ WRITE_LINK_SUPERVISION_TIMEOUT = 0x0C37,
+ READ_NUMBER_OF_SUPPORTED_IAC = 0x0C38,
+ READ_CURRENT_IAC_LAP = 0x0C39,
+ WRITE_CURRENT_IAC_LAP = 0x0C3A,
+ SET_AFH_HOST_CHANNEL_CLASSIFICATION = 0x0C3F,
+ READ_INQUIRY_SCAN_TYPE = 0x0C42,
+ WRITE_INQUIRY_SCAN_TYPE = 0x0C43,
+ READ_INQUIRY_MODE = 0x0C44,
+ WRITE_INQUIRY_MODE = 0x0C45,
+ READ_PAGE_SCAN_TYPE = 0x0C46,
+ WRITE_PAGE_SCAN_TYPE = 0x0C47,
+ READ_AFH_CHANNEL_ASSESSMENT_MODE = 0x0C48,
+ WRITE_AFH_CHANNEL_ASSESSMENT_MODE = 0x0C49,
+ READ_EXTENDED_INQUIRY_RESPONSE = 0x0C51,
+ WRITE_EXTENDED_INQUIRY_RESPONSE = 0x0C52,
+ REFRESH_ENCRYPTION_KEY = 0x0C53,
+ READ_SIMPLE_PAIRING_MODE = 0x0C55,
+ WRITE_SIMPLE_PAIRING_MODE = 0x0C56,
+ READ_LOCAL_OOB_DATA = 0x0C57,
+ READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL = 0x0C58,
+ WRITE_INQUIRY_TRANSMIT_POWER_LEVEL = 0x0C59,
+ SEND_KEYPRESS_NOTIFICATION = 0x0C60,
+
+ READ_LE_HOST_SUPPORT = 0x0C6C,
+ WRITE_LE_HOST_SUPPORT = 0x0C6D,
+
+ READ_SECURE_CONNECTIONS_HOST_SUPPORT = 0x0C79,
+ WRITE_SECURE_CONNECTIONS_HOST_SUPPORT = 0x0C7A,
+
+ // INFORMATIONAL_PARAMETERS
+ READ_LOCAL_VERSION_INFORMATION = 0x1001,
+ READ_LOCAL_SUPPORTED_COMMANDS = 0x1002,
+ READ_LOCAL_SUPPORTED_FEATURES = 0x1003,
+ READ_LOCAL_EXTENDED_FEATURES = 0x1004,
+ READ_BUFFER_SIZE = 0x1005,
+ READ_BD_ADDR = 0x1009,
+ READ_DATA_BLOCK_SIZE = 0x100A,
+ READ_LOCAL_SUPPORTED_CODECS = 0x100B,
+
+ // STATUS_PARAMETERS
+ READ_FAILED_CONTACT_COUNTER = 0x1401,
+ RESET_FAILED_CONTACT_COUNTER = 0x1402,
+ READ_LINK_QUALITY = 0x1403,
+ READ_RSSI = 0x1405,
+ READ_AFH_CHANNEL_MAP = 0x1406,
+ READ_CLOCK = 0x1407,
+ READ_ENCRYPTION_KEY_SIZE = 0x1408,
+
+ // TESTING
+ READ_LOOPBACK_MODE = 0x1801,
+ WRITE_LOOPBACK_MODE = 0x1802,
+ ENABLE_DEVICE_UNDER_TEST_MODE = 0x1803,
+ WRITE_SIMPLE_PAIRING_DEBUG_MODE = 0x1804,
+ WRITE_SECURE_CONNECTIONS_TEST_MODE = 0x180A,
+
+ // LE_CONTROLLER
+ LE_SET_EVENT_MASK = 0x2001,
+ LE_READ_BUFFER_SIZE = 0x2002,
+ LE_READ_LOCAL_SUPPORTED_FEATURES = 0x2003,
+ LE_SET_RANDOM_ADDRESS = 0x2005,
+ LE_SET_ADVERTISING_PARAMETERS = 0x2006,
+ LE_READ_ADVERTISING_CHANNEL_TX_POWER = 0x2007,
+ LE_SET_ADVERTISING_DATA = 0x2008,
+ LE_SET_SCAN_RESPONSE_DATA = 0x2009,
+ LE_SET_ADVERTISING_ENABLE = 0x200A,
+ LE_SET_SCAN_PARAMETERS = 0x200B,
+ LE_SET_SCAN_ENABLE = 0x200C,
+ LE_CREATE_CONNECTION = 0x200D,
+ LE_CREATE_CONNECTION_CANCEL = 0x200E,
+ LE_READ_WHITE_LIST_SIZE = 0x200F,
+ LE_CLEAR_WHITE_LIST = 0x2010,
+ LE_ADD_DEVICE_TO_WHITE_LIST = 0x2011,
+ LE_REMOVE_DEVICE_FROM_WHITE_LIST = 0x2012,
+ LE_CONNECTION_UPDATE = 0x2013,
+ LE_SET_HOST_CHANNEL_CLASSIFICATION = 0x2014,
+ LE_READ_CHANNEL_MAP = 0x2015,
+ LE_READ_REMOTE_FEATURES = 0x2016,
+ LE_ENCRYPT = 0x2017,
+ LE_RAND = 0x2018,
+ LE_START_ENCRYPTION = 0x2019,
+ LE_LONG_TERM_KEY_REQUEST_REPLY = 0x201A,
+ LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY = 0x201B,
+ LE_READ_SUPPORTED_STATES = 0x201C,
+ LE_RECEIVER_TEST = 0x201D,
+ LE_TRANSMITTER_TEST = 0x201E,
+ LE_TEST_END = 0x201F,
+ LE_REMOTE_CONNECTION_PARAMETER_REQUEST_REPLY = 0x2020,
+ LE_REMOTE_CONNECTION_PARAMETER_REQUEST_NEGATIVE_REPLY = 0x2021,
+
+ LE_SET_DATA_LENGTH = 0x2022,
+ LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH = 0x2023,
+ LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH = 0x2024,
+ LE_READ_LOCAL_P_256_PUBLIC_KEY_COMMAND = 0x2025,
+ LE_GENERATE_DHKEY_COMMAND = 0x2026,
+ LE_ADD_DEVICE_TO_RESOLVING_LIST = 0x2027,
+ LE_REMOVE_DEVICE_FROM_RESOLVING_LIST = 0x2028,
+ LE_CLEAR_RESOLVING_LIST = 0x2029,
+ LE_READ_RESOLVING_LIST_SIZE = 0x202A,
+ LE_READ_PEER_RESOLVABLE_ADDRESS = 0x202B,
+ LE_READ_LOCAL_RESOLVABLE_ADDRESS = 0x202C,
+ LE_SET_ADDRESS_RESOLUTION_ENABLE = 0x202D,
+ LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT = 0x202E,
+ LE_READ_MAXIMUM_DATA_LENGTH = 0x202F,
+ LE_READ_PHY = 0x2030,
+ LE_SET_DEFAULT_PHY = 0x2031,
+ LE_SET_PHY = 0x2032,
+ LE_ENHANCED_RECEIVER_TEST = 0x2033,
+ LE_ENHANCED_TRANSMITTER_TEST = 0x2034,
+ LE_SET_EXTENDED_ADVERTISING_RANDOM_ADDRESS = 0x2035,
+ LE_SET_EXTENDED_ADVERTISING_PARAMETERS = 0x2036,
+ LE_SET_EXTENDED_ADVERTISING_DATA = 0x2037,
+ LE_SET_EXTENDED_ADVERTISING_SCAN_RESPONSE = 0x2038,
+ LE_SET_EXTENDED_ADVERTISING_ENABLE = 0x2039,
+ LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH = 0x203A,
+ LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS = 0x203B,
+ LE_REMOVE_ADVERTISING_SET = 0x203C,
+ LE_CLEAR_ADVERTISING_SETS = 0x203D,
+ LE_SET_PERIODIC_ADVERTISING_PARAM = 0x203E,
+ LE_SET_PERIODIC_ADVERTISING_DATA = 0x203F,
+ LE_SET_PERIODIC_ADVERTISING_ENABLE = 0x2040,
+ LE_SET_EXTENDED_SCAN_PARAMETERS = 0x2041,
+ LE_SET_EXTENDED_SCAN_ENABLE = 0x2042,
+ LE_EXTENDED_CREATE_CONNECTION = 0x2043,
+ LE_PERIODIC_ADVERTISING_CREATE_SYNC = 0x2044,
+ LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL = 0x2045,
+ LE_PERIODIC_ADVERTISING_TERMINATE_SYNC = 0x2046,
+ LE_ADD_DEVICE_TO_PERIODIC_ADVERTISING_LIST = 0x2047,
+ LE_REMOVE_DEVICE_FROM_PERIODIC_ADVERTISING_LIST = 0x2048,
+ LE_CLEAR_PERIODIC_ADVERTISING_LIST = 0x2049,
+ LE_READ_PERIODIC_ADVERTISING_LIST_SIZE = 0x204A,
+ LE_READ_TRANSMIT_POWER = 0x204B,
+ LE_READ_RF_PATH_COMPENSATION_POWER = 0x204C,
+ LE_WRITE_RF_PATH_COMPENSATION_POWER = 0x204D,
+ LE_SET_PRIVACY_MODE = 0x204E,
+
+ // VENDOR_SPECIFIC
+ LE_GET_VENDOR_CAPABILITIES = 0xFD53,
+ LE_MULTI_ADVT = 0xFD54,
+ LE_BATCH_SCAN = 0xFD56,
+ LE_ADV_FILTER = 0xFD57,
+ LE_TRACK_ADV = 0xFD58,
+ LE_ENERGY_INFO = 0xFD59,
+ LE_EXTENDED_SCAN_PARAMS = 0xFD5A,
+ CONTROLLER_DEBUG_INFO = 0xFD5B,
+ CONTROLLER_A2DP_OPCODE = 0xFD5D,
+}
+
+packet CommandPacket {
+ op_code : OpCode,
+ _size_(_payload_) : 8,
+ _payload_,
+}
+
+// Packets for interfaces
+
+packet DiscoveryCommand : CommandPacket { _payload_, }
+packet ConnectionManagementCommand : CommandPacket { _payload_, }
+packet SecurityCommand : CommandPacket { _payload_, }
+packet ScoConnectionCommand : CommandPacket { _payload_, }
+packet LeAdvertisingCommand : CommandPacket { _payload_, }
+packet LeConnectionManagementCommand : CommandPacket { _payload_, }
+packet LeSecurityCommand : CommandPacket { _payload_, }
+packet VendorCommand : CommandPacket { _payload_, }
+
+// HCI Event Packets
+
+enum EventCode : 8 {
+ INQUIRY_COMPLETE = 0x01,
+ INQUIRY_RESULT = 0x02,
+ CONNECTION_COMPLETE = 0x03,
+ CONNECTION_REQUEST = 0x04,
+ DISCONNECTION_COMPLETE = 0x05,
+ AUTHENTICATION_COMPLETE = 0x06,
+ REMOTE_NAME_REQUEST_COMPLETE = 0x07,
+ ENCRYPTION_CHANGE = 0x08,
+ CHANGE_CONNECTION_LINK_KEY_COMPLETE = 0x09,
+ MASTER_LINK_KEY_COMPLETE = 0x0A,
+ READ_REMOTE_SUPPORTED_FEATURES_COMPLETE = 0x0B,
+ READ_REMOTE_VERSION_INFORMATION_COMPLETE = 0x0C,
+ QOS_SETUP_COMPLETE = 0x0D,
+ COMMAND_COMPLETE = 0x0E,
+ COMMAND_STATUS = 0x0F,
+ HARDWARE_ERROR = 0x10,
+ FLUSH_OCCURRED = 0x11,
+ ROLE_CHANGE = 0x12,
+ NUMBER_OF_COMPLETED_PACKETS = 0x13,
+ MODE_CHANGE = 0x14,
+ RETURN_LINK_KEYS = 0x15,
+ PIN_CODE_REQUEST = 0x16,
+ LINK_KEY_REQUEST = 0x17,
+ LINK_KEY_NOTIFICATION = 0x18,
+ LOOPBACK_COMMAND = 0x19,
+ DATA_BUFFER_OVERFLOW = 0x1A,
+ MAX_SLOTS_CHANGE = 0x1B,
+ READ_CLOCK_OFFSET_COMPLETE = 0x1C,
+ CONNECTION_PACKET_TYPE_CHANGE = 0x1D,
+ QOS_VIOLATION = 0x1E,
+ PAGE_SCAN_REPETITION_MODE_CHANGE = 0x20,
+ FLOW_SPECIFICATION_COMPLETE = 0x21,
+ INQUIRY_RESULT_WITH_RSSI = 0x22,
+ READ_REMOTE_EXTENDED_FEATURES_COMPLETE = 0x23,
+ SYNCHRONOUS_CONNECTION_COMPLETE = 0x2C,
+ SYNCHRONOUS_CONNECTION_CHANGED = 0x2D,
+ SNIFF_SUBRATING = 0x2E,
+ EXTENDED_INQUIRY_RESULT = 0x2F,
+ ENCRYPTION_KEY_REFRESH_COMPLETE = 0x30,
+ IO_CAPABILITY_REQUEST = 0x31,
+ IO_CAPABILITY_RESPONSE = 0x32,
+ USER_CONFIRMATION_REQUEST = 0x33,
+ USER_PASSKEY_REQUEST = 0x34,
+ REMOTE_OOB_DATA_REQUEST = 0x35,
+ SIMPLE_PAIRING_COMPLETE = 0x36,
+ LINK_SUPERVISION_TIMEOUT_CHANGED = 0x38,
+ ENHANCED_FLUSH_COMPLETE = 0x39,
+ USER_PASSKEY_NOTIFICATION = 0x3B,
+ KEYPRESS_NOTIFICATION = 0x3C,
+ REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION = 0x3D,
+ LE_META_EVENT = 0x3e,
+ NUMBER_OF_COMPLETED_DATA_BLOCKS = 0x48,
+}
+
+packet EventPacket {
+ event_code : EventCode,
+ _size_(_payload_) : 8,
+ _payload_,
+}
+
+// LE Events
+
+enum SubeventCode : 8 {
+ CONNECTION_COMPLETE = 0x01,
+ ADVERTISING_REPORT = 0x02,
+ CONNECTION_UPDATE_COMPLETE = 0x03,
+ READ_REMOTE_FEATURES_COMPLETE = 0x04,
+ LONG_TERM_KEY_REQUEST = 0x05,
+ REMOTE_CONNECTION_PARAMETER_REQUEST = 0x06,
+ DATA_LENGTH_CHANGE = 0x07,
+ READ_LOCAL_P256_PUBLIC_KEY_COMPLETE = 0x08,
+ GENERATE_DHKEY_COMPLETE = 0x09,
+ ENHANCED_CONNECTION_COMPLETE = 0x0a,
+ DIRECTED_ADVERTISING_REPORT = 0x0b,
+ PHY_UPDATE_COMPLETE = 0x0c,
+ EXTENDED_ADVERTISING_REPORT = 0x0D,
+ PERIODIC_ADVERTISING_SYNC_ESTABLISHED = 0x0E,
+ PERIODIC_ADVERTISING_REPORT = 0x0F,
+ PERIODIC_ADVERTISING_SYNC_LOST = 0x10,
+ SCAN_TIMEOUT = 0x11,
+ ADVERTISING_SET_TERMINATED = 0x12,
+ SCAN_REQUEST_RECEIVED = 0x13,
+}
+
+// Common definitions for commands and events
+
+enum FeatureFlag : 1 {
+ UNSUPPORTED = 0,
+ SUPPORTED = 1,
+}
+
+enum ErrorCode: 8 {
+ SUCCESS = 0x00,
+ UNKNOWN_HCI_COMMAND = 0x01,
+ UNKNOWN_CONNECTION = 0x02,
+ HARDWARE_FAILURE = 0x03,
+ PAGE_TIMEOUT = 0x04,
+ AUTHENTICATION_FAILURE = 0x05,
+ PIN_OR_KEY_MISSING = 0x06,
+ MEMORY_CAPACITY_EXCEEDED = 0x07,
+ CONNECTION_TIMEOUT = 0x08,
+ CONNECTION_LIMIT_EXCEEDED = 0x09,
+ SYNCHRONOUS_CONNECTION_LIMIT_EXCEEDED = 0x0A,
+ CONNECTION_ALREADY_EXISTS = 0x0B,
+ COMMAND_DISALLOWED = 0x0C,
+ CONNECTION_REJECTED_LIMITED_RESOURCES = 0x0D,
+ CONNECTION_REJECTED_SECURITY_REASONS = 0x0E,
+ CONNECTION_REJECTED_UNACCEPTABLE_BD_ADDR = 0x0F,
+ CONNECTION_ACCEPT_TIMEOUT = 0x10,
+ UNSUPORTED_FEATURE_OR_PARAMETER_VALUE = 0x11,
+ INVALID_HCI_COMMAND_PARAMETERS = 0x12,
+ REMOTE_USER_TERMINATED_CONNECTION = 0x13,
+ REMOTE_DEVICE_TERMINATED_CONNECTION_LOW_RESOURCES = 0x14,
+ REMOTE_DEVICE_TERMINATED_CONNECTION_POWER_OFF = 0x15,
+ CONNECTION_TERMINATED_BY_LOCAL_HOST = 0x16,
+ REPEATED_ATTEMPTS = 0x17,
+ PAIRING_NOT_ALLOWED = 0x18,
+ UNKNOWN_LMP_PDU = 0x19,
+ UNSUPPORTED_REMOTE_OR_LMP_FEATURE = 0x1A,
+ SCO_OFFSET_REJECTED = 0x1B,
+ SCO_INTERVAL_REJECTED = 0x1C,
+ SCO_AIR_MODE_REJECTED = 0x1D,
+ INVALID_LMP_OR_LL_PARAMETERS = 0x1E,
+ UNSPECIFIED_ERROR = 0x1F,
+ UNSUPPORTED_LMP_OR_LL_PARAMETER = 0x20,
+ ROLE_CHANGE_NOT_ALLOWED = 0x21,
+}
+
+// Events that are defined with their respective commands
+
+packet CommandComplete : EventPacket (event_code = COMMAND_COMPLETE){
+ num_hci_command_packets : 8,
+ command_op_code : OpCode,
+ _payload_,
+}
+
+packet CommandStatus : EventPacket (event_code = COMMAND_STATUS){
+ status : ErrorCode, // SUCCESS means PENDING
+ num_hci_command_packets : 8,
+ command_op_code : OpCode,
+ _payload_,
+}
+
+ // LINK_CONTROL
+packet Inquiry : DiscoveryCommand (op_code = INQUIRY) {
+ lap0 : 8, // 0x00 - 0x3F
+ _fixed_ = 0x9E8B : 16, // LAP upper bits are _fixed_
+ inquiry_length : 8, // 0x1 - 0x30 (times 1.28s)
+ num_responses : 8, // 0x00 unlimited
+}
+
+packet InquiryStatus : CommandStatus (command_op_code = INQUIRY) {
+}
+
+packet InquiryCancel : DiscoveryCommand (op_code = INQUIRY_CANCEL) {
+}
+
+packet InquiryCancelComplete : CommandComplete (command_op_code = INQUIRY_CANCEL) {
+ status : ErrorCode,
+}
+
+packet PeriodicInquiryMode : DiscoveryCommand (op_code = PERIODIC_INQUIRY_MODE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet PeriodicInquiryModeComplete : CommandComplete (command_op_code = PERIODIC_INQUIRY_MODE) {
+ status : ErrorCode,
+}
+
+packet ExitPeriodicInquiryMode : DiscoveryCommand (op_code = EXIT_PERIODIC_INQUIRY_MODE) {
+}
+
+packet ExitPeriodicInquiryModeComplete : CommandComplete (command_op_code = EXIT_PERIODIC_INQUIRY_MODE) {
+ status : ErrorCode,
+}
+
+enum PageScanRepetitionMode : 8 {
+ R0 = 0x00,
+ R1 = 0x01,
+ R2 = 0x02,
+}
+
+enum ClockOffsetValid : 1 {
+ INVALID = 0,
+ VALID = 1,
+}
+
+enum CreateConnectionRoleSwitch : 8 {
+ REMAIN_MASTER = 0x00,
+ ALLOW_ROLE_SWITCH = 0x01,
+}
+
+packet CreateConnection : ConnectionManagementCommand (op_code = CREATE_CONNECTION) {
+ bd_addr : Address,
+ packet_type : 16,
+ page_scan_repetition_mode : PageScanRepetitionMode,
+ _reserved_ : 8,
+ clock_offset : 15,
+ clock_offset_valid : ClockOffsetValid,
+ allow_role_switch : CreateConnectionRoleSwitch,
+}
+
+packet CreateConnectionStatus : CommandStatus (command_op_code = CREATE_CONNECTION) {
+}
+
+enum DisconnectReason : 8 {
+ AUTHENTICATION_FAILURE = 0x05,
+ REMOTE_USER_TERMINATED_CONNECTION = 0x13,
+ REMOTE_DEVICE_TERMINATED_CONNECTION_LOW_RESOURCES = 0x14,
+ REMOTE_DEVICE_TERMINATED_CONNECTION_POWER_OFF = 0x15,
+ UNSUPPORTED_REMOTE_FEATURE = 0x1A,
+ PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED = 0x29,
+ UNACCEPTABLE_CONNECTION_PARAMETERS = 0x3B,
+}
+
+packet Disconnect : ConnectionManagementCommand (op_code = DISCONNECT) {
+ connection_handle : 12,
+ _reserved_ : 4,
+ reason : DisconnectReason,
+}
+
+packet DisconnectStatus : CommandStatus (command_op_code = DISCONNECT) {
+}
+
+packet CreateConnectionCancel : ConnectionManagementCommand (op_code = CREATE_CONNECTION_CANCEL) {
+ bd_addr : Address,
+}
+
+packet CreateConnectionCancelComplete : CommandComplete (command_op_code = CREATE_CONNECTION_CANCEL) {
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+enum AcceptConnectionRequestRole : 8 {
+ BECOME_MASTER = 0x00,
+ REMAIN_SLAVE = 0x01,
+}
+
+packet AcceptConnectionRequest : ConnectionManagementCommand (op_code = ACCEPT_CONNECTION_REQUEST) {
+ bd_addr : Address,
+ role : AcceptConnectionRequestRole,
+}
+
+packet AcceptConnectionRequestStatus : CommandStatus (command_op_code = ACCEPT_CONNECTION_REQUEST) {
+}
+
+enum RejectConnectionReason : 8 {
+ LIMITED_RESOURCES = 0x0D,
+ SECURITY_REASONS = 0x0E,
+ UNACCEPTABLE_BD_ADDR = 0x0F,
+}
+
+packet RejectConnectionRequest : ConnectionManagementCommand (op_code = REJECT_CONNECTION_REQUEST) {
+ bd_addr : Address,
+ reason : RejectConnectionReason,
+}
+
+packet RejectConnectionRequestStatus : CommandStatus (command_op_code = REJECT_CONNECTION_REQUEST) {
+}
+
+packet LinkKeyRequestReply : SecurityCommand (op_code = LINK_KEY_REQUEST_REPLY) {
+ bd_addr : Address,
+ link_key_lo : 64,
+ link_key_hi : 64,
+}
+
+packet LinkKeyRequestReplyComplete : CommandComplete (command_op_code = LINK_KEY_REQUEST_REPLY) {
+ status : ErrorCode,
+}
+
+packet LinkKeyRequestNegativeReply : SecurityCommand (op_code = LINK_KEY_REQUEST_NEGATIVE_REPLY) {
+ bd_addr : Address,
+}
+
+packet LinkKeyRequestNegativeReplyComplete : CommandComplete (command_op_code = LINK_KEY_REQUEST_NEGATIVE_REPLY) {
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+packet PinCodeRequestReply : SecurityCommand (op_code = PIN_CODE_REQUEST_REPLY) {
+ bd_addr : Address,
+ pin_code_length : 5, // 0x01 - 0x10
+ _reserved_ : 3,
+ pin_code_1 : 8, // string parameter, first octet first
+ pin_code_2 : 8,
+ pin_code_3 : 8,
+ pin_code_4 : 8,
+ pin_code_5 : 8,
+ pin_code_6 : 8,
+ pin_code_7 : 8,
+ pin_code_8 : 8,
+ pin_code_9 : 8,
+ pin_code_10 : 8,
+ pin_code_11 : 8,
+ pin_code_12 : 8,
+ pin_code_13 : 8,
+ pin_code_14 : 8,
+ pin_code_15 : 8,
+}
+
+packet PinCodeRequestReplyComplete : CommandComplete (command_op_code = PIN_CODE_REQUEST_REPLY) {
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+packet PinCodeRequestNegativeReply : SecurityCommand (op_code = PIN_CODE_REQUEST_NEGATIVE_REPLY) {
+ bd_addr : Address,
+}
+
+packet PinCodeRequestNegativeReplyComplete : CommandComplete (command_op_code = PIN_CODE_REQUEST_NEGATIVE_REPLY) {
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+packet ChangeConnectionPacketType : ConnectionManagementCommand (op_code = CHANGE_CONNECTION_PACKET_TYPE) {
+ connection_handle : 12,
+ _reserved_ : 4,
+ packet_type : 16,
+}
+
+packet ChangeConnectionPacketTypeStatus : CommandStatus (command_op_code = CHANGE_CONNECTION_PACKET_TYPE) {
+}
+
+packet AuthenticationRequested : ConnectionManagementCommand (op_code = AUTHENTICATION_REQUESTED) {
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet AuthenticationRequestedStatus : CommandStatus (command_op_code = AUTHENTICATION_REQUESTED) {
+}
+
+packet SetConnectionEncryption : ConnectionManagementCommand (op_code = SET_CONNECTION_ENCRYPTION) {
+ connection_handle : 12,
+ _reserved_ : 4,
+ encryption_enable : Enable,
+}
+
+packet SetConnectionEncryptionStatus : CommandStatus (command_op_code = SET_CONNECTION_ENCRYPTION) {
+}
+
+packet ChangeConnectionLinkKey : ConnectionManagementCommand (op_code = CHANGE_CONNECTION_LINK_KEY) {
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet ChangeConnectionLinkKeyStatus : CommandStatus (command_op_code = CHANGE_CONNECTION_LINK_KEY) {
+}
+
+enum KeyFlag : 8 {
+ SEMI_PERMANENT = 0x00,
+ TEMPORARY = 0x01,
+}
+
+packet MasterLinkKey : ConnectionManagementCommand (op_code = MASTER_LINK_KEY) {
+ key_flag : KeyFlag,
+}
+
+packet MasterLinkKeyStatus : CommandStatus (command_op_code = MASTER_LINK_KEY) {
+}
+
+packet RemoteNameRequest : DiscoveryCommand (op_code = REMOTE_NAME_REQUEST) {
+ bd_addr : Address,
+ page_scan_repetition_mode : PageScanRepetitionMode,
+ _reserved_ : 8,
+ clock_offset : 15,
+ clock_offset_valid : ClockOffsetValid,
+}
+
+packet RemoteNameRequestStatus : CommandStatus (command_op_code = REMOTE_NAME_REQUEST) {
+}
+
+packet RemoteNameRequestCancel : DiscoveryCommand (op_code = REMOTE_NAME_REQUEST_CANCEL) {
+ bd_addr : Address,
+}
+
+packet RemoteNameRequestCancelComplete : CommandComplete (command_op_code = REMOTE_NAME_REQUEST_CANCEL) {
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+packet ReadRemoteSupportedFeatures : DiscoveryCommand (op_code = READ_REMOTE_SUPPORTED_FEATURES) {
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet ReadRemoteSupportedFeaturesStatus : CommandStatus (command_op_code = READ_REMOTE_SUPPORTED_FEATURES) {
+}
+
+packet ReadRemoteExtendedFeatures : DiscoveryCommand (op_code = READ_REMOTE_EXTENDED_FEATURES) {
+ connection_handle : 12,
+ _reserved_ : 4,
+ page_number : 8,
+}
+
+packet ReadRemoteExtendedFeaturesStatus : CommandStatus (command_op_code = READ_REMOTE_EXTENDED_FEATURES) {
+}
+
+packet ReadRemoteVersionInformation : DiscoveryCommand (op_code = READ_REMOTE_VERSION_INFORMATION) {
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet ReadRemoteVersionInformationStatus : CommandStatus (command_op_code = READ_REMOTE_VERSION_INFORMATION) {
+}
+
+packet ReadClockOffset : ConnectionManagementCommand (op_code = READ_CLOCK_OFFSET) {
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet ReadClockOffsetStatus : CommandStatus (command_op_code = READ_CLOCK_OFFSET) {
+}
+
+packet ReadLmpHandle : ConnectionManagementCommand (op_code = READ_LMP_HANDLE) {
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet ReadLmpHandleComplete : CommandComplete (command_op_code = READ_LMP_HANDLE) {
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ lmp_handle : 8,
+ _reserved_ : 32,
+}
+
+packet SetupSynchronousConnection : ScoConnectionCommand (op_code = SETUP_SYNCHRONOUS_CONNECTION) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet AcceptSynchronousConnection : ScoConnectionCommand (op_code = ACCEPT_SYNCHRONOUS_CONNECTION) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet RejectSynchronousConnection : ScoConnectionCommand (op_code = REJECT_SYNCHRONOUS_CONNECTION) {
+ _payload_, // placeholder (unimplemented)
+}
+
+enum IoCapability : 8 {
+ DISPLAY_ONLY = 0x00,
+ DISPLAY_YES_NO = 0x01,
+ KEYBOARD_ONLY = 0x02,
+ NO_INPUT_NO_OUTPUT = 0x03,
+}
+
+enum OobDataPresent : 8 {
+ NOT_PRESENT = 0x00,
+ P_192_PRESENT = 0x01,
+ P_256_PRESENT = 0x02,
+ P_192_AND_256_PRESENT = 0x03,
+}
+
+enum AuthenticationRequirements : 8 {
+ NO_BONDING = 0x00,
+ NO_BONDING_MITM_PROTECTION = 0x01,
+ DEDICATED_BONDING = 0x02,
+ DEDICATED_BONDING_MITM_PROTECTION = 0x03,
+ GENERAL_BONDING = 0x04,
+ GENERAL_BONDING_MITM_PROTECTION = 0x05,
+}
+
+packet IoCapabilityRequestReply : SecurityCommand (op_code = IO_CAPABILITY_REQUEST_REPLY) {
+ bd_addr : Address,
+ io_capability : IoCapability,
+ oob_present : OobDataPresent,
+ authentication_requirements : AuthenticationRequirements,
+}
+
+packet IoCapabilityRequestReplyComplete : CommandComplete (command_op_code = IO_CAPABILITY_REQUEST_REPLY) {
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+packet UserConfirmationRequestReply : SecurityCommand (op_code = USER_CONFIRMATION_REQUEST_REPLY) {
+ bd_addr : Address,
+}
+
+packet UserConfirmationRequestReplyComplete : CommandComplete (command_op_code = USER_CONFIRMATION_REQUEST_REPLY) {
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+packet UserConfirmationRequestNegativeReply : SecurityCommand (op_code = USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY) {
+ bd_addr : Address,
+}
+
+packet UserConfirmationRequestNegativeReplyComplete : CommandComplete (command_op_code = USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY) {
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+packet UserPasskeyRequestReply : SecurityCommand (op_code = USER_PASSKEY_REQUEST_REPLY) {
+ bd_addr : Address,
+ numeric_value : 32, // 000000-999999 decimal or 0x0-0xF423F
+}
+
+packet UserPasskeyReplyComplete : CommandComplete (command_op_code = USER_PASSKEY_REQUEST_REPLY) {
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+packet UserPasskeyRequestNegativeReply : SecurityCommand (op_code = USER_PASSKEY_REQUEST_NEGATIVE_REPLY) {
+ bd_addr : Address,
+}
+
+packet UserPasskeyRequestNegativeReplyComplete : CommandComplete (command_op_code = USER_PASSKEY_REQUEST_NEGATIVE_REPLY) {
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+packet RemoteOobDataRequestReply : SecurityCommand (op_code = REMOTE_OOB_DATA_REQUEST_REPLY) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet RemoteOobDataRequestReplyComplete : CommandComplete (command_op_code = REMOTE_OOB_DATA_REQUEST_REPLY) {
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+packet RemoteOobDataRequestNegativeReply : SecurityCommand (op_code = REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY) {
+ bd_addr : Address,
+}
+
+packet RemoteOobDataRequestNegativeReplyComplete : CommandComplete (command_op_code = REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY) {
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+packet IoCapabilityRequestNegativeReply : SecurityCommand (op_code = IO_CAPABILITY_REQUEST_NEGATIVE_REPLY) {
+ bd_addr : Address,
+ reason : ErrorCode,
+}
+
+packet IoCapabilityRequestNegativeReplyComplete : CommandComplete (command_op_code = IO_CAPABILITY_REQUEST_NEGATIVE_REPLY) {
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+packet EnhancedSetupSynchronousConnection : ScoConnectionCommand (op_code = ENHANCED_SETUP_SYNCHRONOUS_CONNECTION) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet EnhancedAcceptSynchronousConnection : ScoConnectionCommand (op_code = ENHANCED_ACCEPT_SYNCHRONOUS_CONNECTION) {
+ _payload_, // placeholder (unimplemented)
+}
+
+
+ // LINK_POLICY
+packet HoldMode : ConnectionManagementCommand (op_code = HOLD_MODE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet SniffMode : ConnectionManagementCommand (op_code = SNIFF_MODE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet ExitSniffMode : ConnectionManagementCommand (op_code = EXIT_SNIFF_MODE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet QosSetup : ConnectionManagementCommand (op_code = QOS_SETUP) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet RoleDiscovery : ConnectionManagementCommand (op_code = ROLE_DISCOVERY) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet SwitchRole : ConnectionManagementCommand (op_code = SWITCH_ROLE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet ReadLinkPolicySettings : ConnectionManagementCommand (op_code = READ_LINK_POLICY_SETTINGS) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet WriteLinkPolicySettings : ConnectionManagementCommand (op_code = WRITE_LINK_POLICY_SETTINGS) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet ReadDefaultLinkPolicySettings : ConnectionManagementCommand (op_code = READ_DEFAULT_LINK_POLICY_SETTINGS) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet WriteDefaultLinkPolicySettings : ConnectionManagementCommand (op_code = WRITE_DEFAULT_LINK_POLICY_SETTINGS) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet FlowSpecification : ConnectionManagementCommand (op_code = FLOW_SPECIFICATION) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet SniffSubrating : ConnectionManagementCommand (op_code = SNIFF_SUBRATING) {
+ _payload_, // placeholder (unimplemented)
+}
+
+
+ // CONTROLLER_AND_BASEBAND
+packet SetEventMask : CommandPacket (op_code = SET_EVENT_MASK) {
+ event_mask : 64,
+}
+
+packet SetEventMaskComplete : CommandComplete (command_op_code = SET_EVENT_MASK) {
+ status : ErrorCode,
+}
+
+packet Reset : CommandPacket (op_code = RESET) {
+}
+
+packet ResetComplete : CommandComplete (command_op_code = RESET) {
+ status : ErrorCode,
+}
+
+packet SetEventFilter : CommandPacket (op_code = SET_EVENT_FILTER) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet Flush : ConnectionManagementCommand (op_code = FLUSH) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet ReadPinType : CommandPacket (op_code = READ_PIN_TYPE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet WritePinType : CommandPacket (op_code = WRITE_PIN_TYPE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet CreateNewUnitKey : CommandPacket (op_code = CREATE_NEW_UNIT_KEY) {
+ _payload_, // placeholder (unimplemented)
+}
+
+enum ReadStoredLinkKeyReadAllFlag : 8 {
+ SPECIFIED_BD_ADDR = 0x00,
+ ALL = 0x01,
+}
+
+packet ReadStoredLinkKey : SecurityCommand (op_code = READ_STORED_LINK_KEY) {
+ bd_addr : Address,
+ read_all_flag : ReadStoredLinkKeyReadAllFlag,
+}
+
+packet ReadStoredLinkKeyComplete : CommandComplete (command_op_code = READ_STORED_LINK_KEY) {
+ status : ErrorCode,
+ max_num_keys : 16,
+ num_keys_read : 16,
+}
+
+packet WriteStoredLinkKey : SecurityCommand (op_code = WRITE_STORED_LINK_KEY) {
+ _payload_,
+}
+
+packet WriteStoredLinkKeyComplete : CommandComplete (command_op_code = WRITE_STORED_LINK_KEY) {
+ status : ErrorCode,
+ num_keys_written : 8,
+}
+
+enum DeleteStoredLinkKeyDeleteAllFlag : 8 {
+ SPECIFIED_BD_ADDR = 0x00,
+ ALL = 0x01,
+}
+
+packet DeleteStoredLinkKey : SecurityCommand (op_code = DELETE_STORED_LINK_KEY) {
+ bd_addr : Address,
+ delete_all_flag : DeleteStoredLinkKeyDeleteAllFlag,
+}
+
+packet DeleteStoredLinkKeyComplete : CommandComplete (command_op_code = DELETE_STORED_LINK_KEY) {
+ status : ErrorCode,
+ num_keys_deleted : 8,
+}
+
+packet WriteLocalName : CommandPacket (op_code = WRITE_LOCAL_NAME) {
+ _payload_,
+}
+
+packet WriteLocalNameComplete : CommandComplete (command_op_code = WRITE_LOCAL_NAME) {
+ status : ErrorCode,
+}
+
+packet ReadLocalName : CommandPacket (op_code = READ_LOCAL_NAME) {
+}
+
+packet ReadLocalNameComplete : CommandComplete (command_op_code = READ_LOCAL_NAME) {
+ status : ErrorCode,
+ _payload_,
+}
+
+packet ReadConnectionAcceptTimeout : ConnectionManagementCommand (op_code = READ_CONNECTION_ACCEPT_TIMEOUT) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet WriteConnectionAcceptTimeout : ConnectionManagementCommand (op_code = WRITE_CONNECTION_ACCEPT_TIMEOUT) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet ReadPageTimeout : DiscoveryCommand (op_code = READ_PAGE_TIMEOUT) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet WritePageTimeout : DiscoveryCommand (op_code = WRITE_PAGE_TIMEOUT) {
+ _payload_, // placeholder (unimplemented)
+}
+
+enum ScanEnable : 8 {
+ NO_SCANS = 0x00,
+ INQUIRY_SCAN_ONLY = 0x01,
+ PAGE_SCAN_ONLY = 0x02,
+ INQUIRY_AND_PAGE_SCAN = 0x03,
+}
+
+packet ReadScanEnable : DiscoveryCommand (op_code = READ_SCAN_ENABLE) {
+}
+
+packet ReadScanEnableComplete : CommandComplete (command_op_code = READ_SCAN_ENABLE) {
+ status : ErrorCode,
+ scan_enable : ScanEnable,
+}
+
+packet WriteScanEnable : DiscoveryCommand (op_code = WRITE_SCAN_ENABLE) {
+ scan_enable : ScanEnable,
+}
+
+packet WriteScanEnableComplete : CommandComplete (command_op_code = WRITE_SCAN_ENABLE) {
+ status : ErrorCode,
+}
+
+packet ReadPageScanActivity : DiscoveryCommand (op_code = READ_PAGE_SCAN_ACTIVITY) {
+}
+
+packet ReadPageScanActivityComplete : CommandComplete (command_op_code = READ_PAGE_SCAN_ACTIVITY) {
+ status : ErrorCode,
+ page_scan_interval : 16, // Range: 0x0012 to 0x1000; only even values are valid * 0x625 ms
+ page_scan_window : 16, // 0x0011 to PageScanInterval
+}
+
+packet WritePageScanActivity : DiscoveryCommand (op_code = WRITE_PAGE_SCAN_ACTIVITY) {
+ page_scan_interval : 16, // Range: 0x0012 to 0x1000; only even values are valid * 0x625 ms
+ page_scan_window : 16, // 0x0011 to PageScanInterval
+}
+
+packet WritePageScanActivityComplete : CommandComplete (command_op_code = WRITE_PAGE_SCAN_ACTIVITY) {
+ status : ErrorCode,
+}
+
+packet ReadInquiryScanActivity : DiscoveryCommand (op_code = READ_INQUIRY_SCAN_ACTIVITY) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet WriteInquiryScanActivity : DiscoveryCommand (op_code = WRITE_INQUIRY_SCAN_ACTIVITY) {
+ _payload_, // placeholder (unimplemented)
+}
+
+enum AuthenticationEnable : 8 {
+ NOT_REQUIRED = 0x00,
+ REQUIRED = 0x01,
+}
+
+packet ReadAuthenticationEnable : CommandPacket (op_code = READ_AUTHENTICATION_ENABLE) {
+}
+
+packet ReadAuthenticationEnableComplete : CommandComplete (command_op_code = READ_AUTHENTICATION_ENABLE) {
+ status : ErrorCode,
+ authentication_enable : AuthenticationEnable,
+}
+
+packet WriteAuthenticationEnable : CommandPacket (op_code = WRITE_AUTHENTICATION_ENABLE) {
+ authentication_enable : AuthenticationEnable,
+}
+
+packet WriteAuthenticationEnableComplete : CommandComplete (command_op_code = WRITE_AUTHENTICATION_ENABLE) {
+ status : ErrorCode,
+}
+
+packet ReadClassOfDevice : DiscoveryCommand (op_code = READ_CLASS_OF_DEVICE) {
+}
+
+packet ReadClassOfDeviceComplete : CommandComplete (command_op_code = READ_CLASS_OF_DEVICE) {
+ status : ErrorCode,
+ class_of_device : ClassOfDevice,
+}
+
+packet WriteClassOfDevice : DiscoveryCommand (op_code = WRITE_CLASS_OF_DEVICE) {
+ class_of_device : ClassOfDevice,
+}
+
+packet WriteClassOfDeviceComplete : CommandComplete (command_op_code = WRITE_CLASS_OF_DEVICE) {
+ status : ErrorCode,
+}
+
+packet ReadVoiceSetting : CommandPacket (op_code = READ_VOICE_SETTING) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet WriteVoiceSetting : CommandPacket (op_code = WRITE_VOICE_SETTING) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet ReadAutomaticFlushTimeout : ConnectionManagementCommand (op_code = READ_AUTOMATIC_FLUSH_TIMEOUT) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet WriteAutomaticFlushTimeout : ConnectionManagementCommand (op_code = WRITE_AUTOMATIC_FLUSH_TIMEOUT) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet ReadNumBroadcastRetransmits : CommandPacket (op_code = READ_NUM_BROADCAST_RETRANSMITS) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet WriteNumBroadcastRetransmits : CommandPacket (op_code = WRITE_NUM_BROADCAST_RETRANSMITS) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet ReadHoldModeActivity : CommandPacket (op_code = READ_HOLD_MODE_ACTIVITY) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet WriteHoldModeActivity : CommandPacket (op_code = WRITE_HOLD_MODE_ACTIVITY) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet ReadTransmitPowerLevel : ConnectionManagementCommand (op_code = READ_TRANSMIT_POWER_LEVEL) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet ReadSynchronousFlowControlEnable : CommandPacket (op_code = READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet WriteSynchronousFlowControlEnable : CommandPacket (op_code = WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet SetControllerToHostFlowControl : CommandPacket (op_code = SET_CONTROLLER_TO_HOST_FLOW_CONTROL) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet HostBufferSize : CommandPacket (op_code = HOST_BUFFER_SIZE) {
+ host_acl_data_packet_length : 16,
+ host_synchronous_data_packet_length : 8,
+ host_total_num_acl_data_packets : 16,
+ host_total_num_synchronous_data_packets : 16,
+}
+
+packet HostBufferSizeComplete : CommandComplete (command_op_code = HOST_BUFFER_SIZE) {
+ status : ErrorCode,
+}
+
+packet HostNumCompletedPackets : CommandPacket (op_code = HOST_NUM_COMPLETED_PACKETS) {
+ _payload_,
+}
+
+packet HostNumCompletedPacketsError : CommandComplete (command_op_code = HOST_NUM_COMPLETED_PACKETS) {
+ error_code : ErrorCode,
+}
+
+packet ReadLinkSupervisionTimeout : ConnectionManagementCommand (op_code = READ_LINK_SUPERVISION_TIMEOUT) {
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet ReadLinkSupervisionTimeoutComplete : CommandComplete (command_op_code = READ_LINK_SUPERVISION_TIMEOUT) {
+ status : ErrorCode,
+ handle : 12,
+ _reserved_ : 4,
+ link_supervision_timeout : 16, // 0x001-0xFFFF (0.625ms-40.9s)
+}
+
+packet WriteLinkSupervisionTimeout : ConnectionManagementCommand (op_code = WRITE_LINK_SUPERVISION_TIMEOUT) {
+ handle : 12,
+ _reserved_ : 4,
+ link_supervision_timeout : 16, // 0x001-0xFFFF (0.625ms-40.9s)
+}
+
+packet WriteLinkSupervisionTimeoutComplete : CommandComplete (command_op_code = WRITE_LINK_SUPERVISION_TIMEOUT) {
+ status : ErrorCode,
+ handle : 12,
+ _reserved_ : 4,
+}
+
+packet ReadNumberOfSupportedIac : DiscoveryCommand (op_code = READ_NUMBER_OF_SUPPORTED_IAC) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet ReadCurrentIacLap : DiscoveryCommand (op_code = READ_CURRENT_IAC_LAP) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet WriteCurrentIacLap : DiscoveryCommand (op_code = WRITE_CURRENT_IAC_LAP) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet SetAfhHostChannelClassification : CommandPacket (op_code = SET_AFH_HOST_CHANNEL_CLASSIFICATION) {
+ _payload_, // placeholder (unimplemented)
+}
+
+enum InquiryScanType : 8 {
+ STANDARD = 0x00,
+ INTERLACED = 0x01,
+}
+
+packet ReadInquiryScanType : DiscoveryCommand (op_code = READ_INQUIRY_SCAN_TYPE) {
+}
+
+packet ReadInquiryScanTypeComplete : CommandComplete (command_op_code = READ_INQUIRY_SCAN_TYPE) {
+ status : ErrorCode,
+ inquiry_scan_type : InquiryScanType,
+}
+
+packet WriteInquiryScanType : DiscoveryCommand (op_code = WRITE_INQUIRY_SCAN_TYPE) {
+ inquiry_scan_type : InquiryScanType,
+}
+
+packet WriteInquiryScanTypeComplete : CommandComplete (command_op_code = WRITE_INQUIRY_SCAN_TYPE) {
+ status : ErrorCode,
+}
+
+enum InquiryMode : 8 {
+ STANDARD = 0x00,
+ RSSI = 0x01,
+ RSSI_OR_EXTENDED = 0x02,
+}
+
+packet ReadInquiryMode : DiscoveryCommand (op_code = READ_INQUIRY_MODE) {
+}
+
+packet ReadInquiryModeComplete : CommandComplete (command_op_code = READ_INQUIRY_MODE) {
+ status : ErrorCode,
+ inquiry_mode : InquiryMode,
+}
+
+packet WriteInquiryMode : DiscoveryCommand (op_code = WRITE_INQUIRY_MODE) {
+ inquiry_mode : InquiryMode,
+}
+
+packet WriteInquiryModeComplete : CommandComplete (command_op_code = WRITE_INQUIRY_MODE) {
+ status : ErrorCode,
+}
+
+enum PageScanType : 8 {
+ STANDARD = 0x00,
+ INTERLACED = 0x01,
+}
+
+packet ReadPageScanType : DiscoveryCommand (op_code = READ_PAGE_SCAN_TYPE) {
+}
+
+packet ReadPageScanTypeComplete : CommandComplete (command_op_code = READ_PAGE_SCAN_TYPE) {
+ status : ErrorCode,
+ page_scan_type : PageScanType,
+}
+
+packet WritePageScanType : DiscoveryCommand (op_code = WRITE_PAGE_SCAN_TYPE) {
+ page_scan_type : PageScanType,
+}
+
+packet WritePageScanTypeComplete : CommandComplete (command_op_code = WRITE_PAGE_SCAN_TYPE) {
+ status : ErrorCode,
+}
+
+packet ReadAfhChannelAssessmentMode : CommandPacket (op_code = READ_AFH_CHANNEL_ASSESSMENT_MODE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet WriteAfhChannelAssessmentMode : CommandPacket (op_code = WRITE_AFH_CHANNEL_ASSESSMENT_MODE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+enum FecRequired : 8 {
+ NOT_REQUIRED = 0x00,
+ REQUIRED = 0x01,
+}
+
+packet ReadExtendedInquiryResponse : CommandPacket (op_code = READ_EXTENDED_INQUIRY_RESPONSE) {
+}
+
+packet ReadExtendedInquiryResponseComplete : CommandComplete (command_op_code = READ_EXTENDED_INQUIRY_RESPONSE) {
+ status : ErrorCode,
+ fec_required : FecRequired,
+ _payload_,
+}
+
+packet WriteExtendedInquiryResponse : CommandPacket (op_code = WRITE_EXTENDED_INQUIRY_RESPONSE) {
+ fec_required : FecRequired,
+ _payload_,
+}
+
+packet WriteExtendedInquiryResponseComplete : CommandComplete (command_op_code = WRITE_EXTENDED_INQUIRY_RESPONSE) {
+ status : ErrorCode,
+}
+
+packet RefreshEncryptionKey : SecurityCommand (op_code = REFRESH_ENCRYPTION_KEY) {
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet RefreshEncryptionKeyStatus : CommandStatus (command_op_code = REFRESH_ENCRYPTION_KEY) {
+}
+
+packet ReadSimplePairingMode : SecurityCommand (op_code = READ_SIMPLE_PAIRING_MODE) {
+}
+
+packet ReadSimplePairingModeComplete : CommandComplete (command_op_code = READ_SIMPLE_PAIRING_MODE) {
+ status : ErrorCode,
+ simple_pairing_mode : Enable,
+}
+
+packet WriteSimplePairingMode : SecurityCommand (op_code = WRITE_SIMPLE_PAIRING_MODE) {
+ simple_pairing_mode : Enable,
+}
+
+packet WriteSimplePairingModeComplete : CommandComplete (command_op_code = WRITE_SIMPLE_PAIRING_MODE) {
+ status : ErrorCode,
+}
+
+packet ReadLocalOobData : SecurityCommand (op_code = READ_LOCAL_OOB_DATA) {
+}
+
+packet ReadLocalOobDataComplete : CommandComplete (command_op_code = READ_LOCAL_OOB_DATA) {
+ status : ErrorCode,
+ clo : 64,
+ chi : 64,
+ rlo : 64,
+ rhi : 64,
+}
+
+packet ReadInquiryResponseTransmitPowerLevel : DiscoveryCommand (op_code = READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL) {
+}
+
+packet ReadInquiryResponseTransmitPowerLevelComplete : CommandComplete (command_op_code = READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL) {
+ status : ErrorCode,
+ tx_power : 8, // (-70dBm to 20dBm)
+}
+
+packet WriteInquiryTransmitPowerLevel : DiscoveryCommand (op_code = WRITE_INQUIRY_TRANSMIT_POWER_LEVEL) {
+ tx_power : 8,
+}
+
+packet WriteInquiryResponseTransmitPowerLevelComplete : CommandComplete (command_op_code = WRITE_INQUIRY_TRANSMIT_POWER_LEVEL) {
+ status : ErrorCode,
+}
+
+enum KeypressNotificationType : 8 {
+ ENTRY_STARTED = 0,
+ DIGIT_ENTERED = 1,
+ DIGIT_ERASED = 2,
+ CLEARED = 3,
+ ENTRY_COMPLETED = 4,
+}
+
+packet SendKeypressNotification : SecurityCommand (op_code = SEND_KEYPRESS_NOTIFICATION) {
+ bd_addr : Address,
+ notification_type : KeypressNotificationType,
+}
+
+packet SendKeypressNotificationComplete : CommandComplete (command_op_code = SEND_KEYPRESS_NOTIFICATION) {
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+enum SimultaneousLeHost : 8 {
+ DISABLED = 0x00,
+}
+
+packet ReadLeHostSupport : CommandPacket (op_code = READ_LE_HOST_SUPPORT) {
+}
+
+packet ReadLeHostSupportComplete : CommandComplete (command_op_code = READ_LE_HOST_SUPPORT) {
+ status : ErrorCode,
+ le_supported_host : Enable,
+ simultaneous_le_host : SimultaneousLeHost,
+}
+
+packet WriteLeHostSupport : CommandPacket (op_code = WRITE_LE_HOST_SUPPORT) {
+ le_supported_host : Enable,
+ simultaneous_le_host : SimultaneousLeHost,
+}
+
+packet WriteLeHostSupportComplete : CommandComplete (command_op_code = WRITE_LE_HOST_SUPPORT) {
+ status : ErrorCode,
+}
+
+packet ReadSecureConnectionsHostSupport : CommandPacket (op_code = READ_SECURE_CONNECTIONS_HOST_SUPPORT) {
+}
+
+packet ReadSecureConnectionsHostSupportComplete : CommandComplete (command_op_code = READ_SECURE_CONNECTIONS_HOST_SUPPORT) {
+ status : ErrorCode,
+ secure_connections_host_support : Enable,
+}
+
+packet WriteSecureConnectionsHostSupport : CommandPacket (op_code = WRITE_SECURE_CONNECTIONS_HOST_SUPPORT) {
+ secure_connections_host_support : Enable,
+}
+
+packet WriteSecureConnectionsHostSupportComplete : CommandComplete (command_op_code = WRITE_SECURE_CONNECTIONS_HOST_SUPPORT) {
+ status : ErrorCode,
+}
+
+ // INFORMATIONAL_PARAMETERS
+packet ReadLocalVersionInformation : CommandPacket (op_code = READ_LOCAL_VERSION_INFORMATION) {
+}
+
+packet ReadLocalSupportedCommands : CommandPacket (op_code = READ_LOCAL_SUPPORTED_COMMANDS) {
+}
+
+packet ReadLocalSupportedFeatures : CommandPacket (op_code = READ_LOCAL_SUPPORTED_FEATURES) {
+}
+
+packet ReadLocalExtendedFeatures : CommandPacket (op_code = READ_LOCAL_EXTENDED_FEATURES) {
+ page_number : 8,
+}
+
+packet ReadBufferSize : CommandPacket (op_code = READ_BUFFER_SIZE) {
+}
+
+packet ReadBdAddr : CommandPacket (op_code = READ_BD_ADDR) {
+}
+
+packet ReadDataBlockSize : CommandPacket (op_code = READ_DATA_BLOCK_SIZE) {
+}
+
+packet ReadLocalSupportedCodecs : CommandPacket (op_code = READ_LOCAL_SUPPORTED_CODECS) {
+}
+
+
+ // STATUS_PARAMETERS
+packet ReadFailedContactCounter : ConnectionManagementCommand (op_code = READ_FAILED_CONTACT_COUNTER) {
+ handle : 12,
+ _reserved_ : 4,
+}
+
+packet ResetFailedContactCounter : ConnectionManagementCommand (op_code = RESET_FAILED_CONTACT_COUNTER) {
+ handle : 12,
+ _reserved_ : 4,
+}
+
+packet ReadLinkQuality : ConnectionManagementCommand (op_code = READ_LINK_QUALITY) {
+ handle : 12,
+ _reserved_ : 4,
+}
+
+packet ReadRssi : ConnectionManagementCommand (op_code = READ_RSSI) {
+ handle : 12,
+ _reserved_ : 4,
+}
+
+packet ReadAfhChannelMap : ConnectionManagementCommand (op_code = READ_AFH_CHANNEL_MAP) {
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+enum WhichClock : 8 {
+ LOCAL = 0x00,
+ PICONET = 0x01,
+}
+
+packet ReadClock : ConnectionManagementCommand (op_code = READ_CLOCK) {
+ connection_handle : 12,
+ _reserved_ : 4,
+ which_clock : WhichClock,
+}
+
+packet ReadEncryptionKeySize : SecurityCommand (op_code = READ_ENCRYPTION_KEY_SIZE) {
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+
+ // TESTING
+enum LoopbackMode : 8 {
+ NO_LOOPBACK = 0x00,
+ ENABLE_LOCAL = 0x01,
+ ENABLE_REMOTE = 0x02,
+}
+
+packet ReadLoopbackMode : CommandPacket (op_code = READ_LOOPBACK_MODE) {
+}
+
+packet ReadLoopbackModeComplete : CommandComplete (command_op_code = READ_LOOPBACK_MODE) {
+ status : ErrorCode,
+ loopback_mode : LoopbackMode,
+}
+
+packet WriteLoopbackMode : CommandPacket (op_code = WRITE_LOOPBACK_MODE) {
+ loopback_mode : LoopbackMode,
+}
+
+packet WriteLoopbackModeComplete : CommandComplete (command_op_code = WRITE_LOOPBACK_MODE) {
+ status : ErrorCode,
+}
+
+packet EnableDeviceUnderTestMode : CommandPacket (op_code = ENABLE_DEVICE_UNDER_TEST_MODE) {
+}
+
+packet EnableDeviceUnderTestModeComplete : CommandComplete (command_op_code = ENABLE_DEVICE_UNDER_TEST_MODE) {
+ status : ErrorCode,
+}
+
+packet WriteSimplePairingDebugMode : CommandPacket (op_code = WRITE_SIMPLE_PAIRING_DEBUG_MODE) {
+ simple_pairing_debug_mode : Enable,
+}
+
+packet WriteSimplePairingDebugModeComplete : CommandComplete (command_op_code = WRITE_SIMPLE_PAIRING_DEBUG_MODE) {
+ status : ErrorCode,
+}
+
+packet WriteSecureConnectionsTestMode : CommandPacket (op_code = WRITE_SECURE_CONNECTIONS_TEST_MODE) {
+ connection_handle : 12,
+ _reserved_ : 4,
+ dm1_aclu_mode : Enable,
+ esco_loopback_mode : Enable,
+}
+
+packet WriteSecureConnectionsTestModeComplete : CommandComplete (command_op_code = WRITE_SECURE_CONNECTIONS_TEST_MODE) {
+ status : ErrorCode,
+}
+
+ // LE_CONTROLLER
+packet LeSetEventMask : CommandPacket (op_code = LE_SET_EVENT_MASK) {
+ le_event_mask : 64,
+}
+
+packet LeSetEventMaskComplete : CommandComplete (command_op_code = LE_SET_EVENT_MASK) {
+ status : ErrorCode,
+}
+
+packet LeReadBufferSize : CommandPacket (op_code = LE_READ_BUFFER_SIZE) {
+}
+
+packet LeReadBufferSizeComplete : CommandComplete (command_op_code = LE_READ_BUFFER_SIZE) {
+ status : ErrorCode,
+ hc_le_data_packet_length : 16,
+ hc_total_num_le_packets : 8,
+}
+
+packet LeReadLocalSupportedFeatures : CommandPacket (op_code = LE_READ_LOCAL_SUPPORTED_FEATURES) {
+}
+
+packet LeReadLocalSupportedFeaturesComplete : CommandComplete (command_op_code = LE_READ_LOCAL_SUPPORTED_FEATURES) {
+ status : ErrorCode,
+ le_features : 64,
+}
+
+packet LeSetRandomAddress : CommandPacket (op_code = LE_SET_RANDOM_ADDRESS) {
+ random_address : Address,
+}
+
+packet LeSetRandomAddressComplete : CommandComplete (command_op_code = LE_SET_RANDOM_ADDRESS) {
+ status : ErrorCode,
+}
+
+enum AdvertisingFilterPolicy : 1 {
+ ALL_DEVICES = 0, // Default
+ ONLY_WHITE_LISTED_DEVICES = 1,
+}
+
+enum PeerAddressType : 8 {
+ PUBLIC_DEVICE_OR_IDENTITY_ADDRESS = 0x00,
+ RANDOM_DEVICE_OR_IDENTITY_ADDRESS = 0x01,
+}
+
+enum AdvertisingEventType : 8 {
+ ADV_IND = 0x00,
+ ADV_DIRECT_IND = 0x01,
+ ADV_SCAN_IND = 0x02,
+ ADV_NONCONN_IND = 0x03,
+ SCAN_RSP = 0x04,
+}
+
+enum AddressType : 8 {
+ PUBLIC_DEVICE_ADDRESS = 0x00,
+ RANDOM_DEVICE_ADDRESS = 0x01,
+ PUBLIC_IDENTITY_ADDRESS = 0x02,
+ RANDOM_IDENTITY_ADDRESS = 0x03,
+}
+
+packet LeSetAdvertisingParameters : LeAdvertisingCommand (op_code = LE_SET_ADVERTISING_PARAMETERS) {
+ advertising_interval_min : 16,
+ advertising_interval_max : 16,
+ advertising_type : AdvertisingEventType,
+ own_address_type : AddressType,
+ peer_address_type : PeerAddressType,
+ peer_address : Address,
+ advertising_channel_map : 8,
+ connection_filter_policy : AdvertisingFilterPolicy,
+ scan_filter_policy : AdvertisingFilterPolicy,
+ _reserved_ : 6,
+}
+
+packet LeSetAdvertisingParametersComplete : CommandComplete (command_op_code = LE_SET_ADVERTISING_PARAMETERS) {
+ status : ErrorCode,
+}
+
+packet LeReadAdvertisingChannelTxPower : LeAdvertisingCommand (op_code = LE_READ_ADVERTISING_CHANNEL_TX_POWER) {
+}
+
+packet LeReadAdvertisingChannelTxPowerComplete : CommandComplete (command_op_code = LE_READ_ADVERTISING_CHANNEL_TX_POWER) {
+ status : ErrorCode,
+ transmit_power_level : 8, // (-20dBm to 10dBm) Accuracy: +/-4dB
+}
+
+packet LeSetAdvertisingData : LeAdvertisingCommand (op_code = LE_SET_ADVERTISING_DATA) {
+ _payload_,
+}
+
+packet LeSetAdvertisingDataComplete : CommandComplete (command_op_code = LE_SET_ADVERTISING_DATA) {
+ status : ErrorCode,
+}
+
+packet LeSetScanResponseData : LeAdvertisingCommand (op_code = LE_SET_SCAN_RESPONSE_DATA) {
+ _payload_,
+}
+
+packet LeSetScanResponseDataComplete : CommandComplete (command_op_code = LE_SET_SCAN_RESPONSE_DATA) {
+ status : ErrorCode,
+}
+
+packet LeSetAdvertisingEnable : LeAdvertisingCommand (op_code = LE_SET_ADVERTISING_ENABLE) {
+ advertising_enable : Enable, // Default DISABLED
+}
+
+packet LeSetAdvertisingEnableComplete : CommandComplete (command_op_code = LE_SET_ADVERTISING_ENABLE) {
+ status : ErrorCode,
+}
+
+enum LeScanType : 8 {
+ PASSIVE = 0x00, // Default
+ ACTIVE = 0x01,
+}
+
+enum LeSetScanningFilterPolicy : 8 {
+ ACCEPT_ALL = 0x00, // Default
+ WHITE_LIST_ONLY = 0x01,
+ CHECK_INITIATORS_IDENTITY = 0x02,
+ WHITE_LIST_AND_INITIATORS_IDENTITY = 0x03,
+}
+
+packet LeSetScanParameters : LeAdvertisingCommand (op_code = LE_SET_SCAN_PARAMETERS) {
+ le_scan_type : LeScanType,
+ le_scan_interval : 16, // 0x0004-0x4000 Default 0x10 (10ms)
+ le_scan_window : 16, // Default 0x10 (10ms)
+ own_address_type : AddressType,
+ scanning_filter_policy : LeSetScanningFilterPolicy,
+}
+
+packet LeSetScanParametersComplete : CommandComplete (command_op_code = LE_SET_SCAN_PARAMETERS) {
+ status : ErrorCode,
+}
+
+packet LeSetScanEnable : LeAdvertisingCommand (op_code = LE_SET_SCAN_ENABLE) {
+ le_scan_enable : Enable,
+ filter_duplicates : Enable,
+}
+
+packet LeSetScanEnableComplete : CommandComplete (command_op_code = LE_SET_SCAN_ENABLE) {
+ status : ErrorCode,
+}
+
+enum InitiatorFilterPolicy : 8 {
+ USE_PEER_ADDRESS = 0x00,
+ USE_WHITE_LIST = 0x01,
+}
+
+enum OwnAddressType : 8 {
+ PUBLIC_DEVICE_ADDRESS = 0x00,
+ RANDOM_DEVICE_ADDRESS = 0x01,
+ RESOLVABLE_OR_PUBLIC_ADDRESS = 0x02,
+ RESOLVABLE_OR_RANDOM_ADDRESS = 0x03,
+}
+
+packet LeCreateConnection : LeConnectionManagementCommand (op_code = LE_CREATE_CONNECTION) {
+ le_scan_interval : 16, // 0x0004-0x4000
+ le_scan_window : 16, // < = LeScanInterval
+ initiator_filter_policy : InitiatorFilterPolicy,
+ peer_address_type : AddressType,
+ peer_address : Address,
+ own_address_type : OwnAddressType,
+ conn_interval_min : 16, // 0x0006-0x0C80 (7.5ms to 4s)
+ conn_interval_max : 16, // 0x0006-0x0C80 (7.5ms to 4s)
+ conn_latency : 16, // 0x0006-0x01F3
+ supervision_timeout : 16, // 0x00A to 0x0C80 (100ms to 32s)
+ minimum_ce_length : 16, // 0.625ms
+ maximum_ce_length : 16, // 0.625ms
+}
+
+packet LeCreateConnectionStatus : CommandStatus (command_op_code = LE_CREATE_CONNECTION) {
+}
+
+packet LeCreateConnectionCancel : LeConnectionManagementCommand (op_code = LE_CREATE_CONNECTION_CANCEL) {
+}
+
+packet LeCreateConnectionCancelComplete : CommandComplete (command_op_code = LE_CREATE_CONNECTION_CANCEL) {
+ status : ErrorCode,
+}
+
+packet LeReadWhiteListSize : LeConnectionManagementCommand (op_code = LE_READ_WHITE_LIST_SIZE) {
+}
+
+packet LeReadWhiteListSizeComplete : CommandComplete (command_op_code = LE_READ_WHITE_LIST_SIZE) {
+ status : ErrorCode,
+ white_list_size : 8,
+}
+
+packet LeClearWhiteList : LeConnectionManagementCommand (op_code = LE_CLEAR_WHITE_LIST) {
+}
+
+packet LeClearWhiteListComplete : CommandComplete (command_op_code = LE_CLEAR_WHITE_LIST) {
+ status : ErrorCode,
+}
+
+enum WhiteListAddressType : 8 {
+ PUBLIC = 0x00,
+ RANDOM = 0x01,
+ ANONYMOUS_ADVERTISERS = 0xFF,
+}
+
+packet LeAddDeviceToWhiteList : LeConnectionManagementCommand (op_code = LE_ADD_DEVICE_TO_WHITE_LIST) {
+ address_type : WhiteListAddressType,
+ address : Address,
+}
+
+packet LeAddDeviceToWhiteListComplete : CommandComplete (command_op_code = LE_ADD_DEVICE_TO_WHITE_LIST) {
+ status : ErrorCode,
+}
+
+packet LeRemoveDeviceFromWhiteList : LeConnectionManagementCommand (op_code = LE_REMOVE_DEVICE_FROM_WHITE_LIST) {
+ address_type : WhiteListAddressType,
+ address : Address,
+}
+
+packet LeRemoveDeviceFromWhiteListComplete : CommandComplete (command_op_code = LE_REMOVE_DEVICE_FROM_WHITE_LIST) {
+ status : ErrorCode,
+}
+
+packet LeConnectionUpdate : LeConnectionManagementCommand (op_code = LE_CONNECTION_UPDATE) {
+ connection_handle : 12,
+ _reserved_ : 4,
+ conn_interval_min : 16, // 0x0006-0x0C80 (7.5ms to 4s)
+ conn_interval_max : 16, // 0x0006-0x0C80 (7.5ms to 4s)
+ conn_latency : 16, // 0x0006-0x01F3
+ supervision_timeout : 16, // 0x00A to 0x0C80 (100ms to 32s)
+ minimum_ce_length : 16, // 0.625ms
+ maximum_ce_length : 16, // 0.625ms
+}
+
+packet LeConnectionUpdateStatus : CommandStatus (command_op_code = LE_CONNECTION_UPDATE) {
+}
+
+packet LeSetHostChannelClassification : LeConnectionManagementCommand (op_code = LE_SET_HOST_CHANNEL_CLASSIFICATION) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeReadChannelMap : LeConnectionManagementCommand (op_code = LE_READ_CHANNEL_MAP) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeReadRemoteFeatures : LeConnectionManagementCommand (op_code = LE_READ_REMOTE_FEATURES) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeEncrypt : LeSecurityCommand (op_code = LE_ENCRYPT) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeRand : LeSecurityCommand (op_code = LE_RAND) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeStartEncryption : LeSecurityCommand (op_code = LE_START_ENCRYPTION) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeLongTermKeyRequestReply : LeSecurityCommand (op_code = LE_LONG_TERM_KEY_REQUEST_REPLY) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeLongTermKeyRequestNegativeReply : LeSecurityCommand (op_code = LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeReadSupportedStates : CommandPacket (op_code = LE_READ_SUPPORTED_STATES) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeReceiverTest : CommandPacket (op_code = LE_RECEIVER_TEST) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeTransmitterTest : CommandPacket (op_code = LE_TRANSMITTER_TEST) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeTestEnd : CommandPacket (op_code = LE_TEST_END) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeRemoteConnectionParameterRequestReply : LeConnectionManagementCommand (op_code = LE_REMOTE_CONNECTION_PARAMETER_REQUEST_REPLY) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeRemoteConnectionParameterRequestNegativeReply : LeConnectionManagementCommand (op_code = LE_REMOTE_CONNECTION_PARAMETER_REQUEST_NEGATIVE_REPLY) {
+ _payload_, // placeholder (unimplemented)
+}
+
+
+packet LeSetDataLength : LeConnectionManagementCommand (op_code = LE_SET_DATA_LENGTH) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeReadSuggestedDefaultDataLength : LeConnectionManagementCommand (op_code = LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeWriteSuggestedDefaultDataLength : LeConnectionManagementCommand (op_code = LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeReadLocalP256PublicKeyCommand : LeSecurityCommand (op_code = LE_READ_LOCAL_P_256_PUBLIC_KEY_COMMAND) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeGenerateDhkeyCommand : LeSecurityCommand (op_code = LE_GENERATE_DHKEY_COMMAND) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeAddDeviceToResolvingList : LeSecurityCommand (op_code = LE_ADD_DEVICE_TO_RESOLVING_LIST) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeRemoveDeviceFromResolvingList : LeSecurityCommand (op_code = LE_REMOVE_DEVICE_FROM_RESOLVING_LIST) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeClearResolvingList : LeSecurityCommand (op_code = LE_CLEAR_RESOLVING_LIST) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeReadResolvingListSize : LeSecurityCommand (op_code = LE_READ_RESOLVING_LIST_SIZE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeReadPeerResolvableAddress : LeSecurityCommand (op_code = LE_READ_PEER_RESOLVABLE_ADDRESS) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeReadLocalResolvableAddress : LeSecurityCommand (op_code = LE_READ_LOCAL_RESOLVABLE_ADDRESS) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeSetAddressResolutionEnable : LeSecurityCommand (op_code = LE_SET_ADDRESS_RESOLUTION_ENABLE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeSetResolvablePrivateAddressTimeout : LeSecurityCommand (op_code = LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeReadMaximumDataLength : CommandPacket (op_code = LE_READ_MAXIMUM_DATA_LENGTH) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeReadPhy : LeConnectionManagementCommand (op_code = LE_READ_PHY) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeSetDefaultPhy : LeConnectionManagementCommand (op_code = LE_SET_DEFAULT_PHY) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeSetPhy : LeConnectionManagementCommand (op_code = LE_SET_PHY) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeEnhancedReceiverTest : CommandPacket (op_code = LE_ENHANCED_RECEIVER_TEST) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeEnhancedTransmitterTest : CommandPacket (op_code = LE_ENHANCED_TRANSMITTER_TEST) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeSetExtendedAdvertisingRandomAddress : LeAdvertisingCommand (op_code = LE_SET_EXTENDED_ADVERTISING_RANDOM_ADDRESS) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeSetExtendedAdvertisingParameters : LeAdvertisingCommand (op_code = LE_SET_EXTENDED_ADVERTISING_PARAMETERS) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeSetExtendedAdvertisingData : LeAdvertisingCommand (op_code = LE_SET_EXTENDED_ADVERTISING_DATA) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeSetExtendedAdvertisingScanResponse : LeAdvertisingCommand (op_code = LE_SET_EXTENDED_ADVERTISING_SCAN_RESPONSE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeSetExtendedAdvertisingEnable : LeAdvertisingCommand (op_code = LE_SET_EXTENDED_ADVERTISING_ENABLE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeReadMaximumAdvertisingDataLength : CommandPacket (op_code = LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeReadNumberOfSupportedAdvertisingSets : CommandPacket (op_code = LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeRemoveAdvertisingSet : LeAdvertisingCommand (op_code = LE_REMOVE_ADVERTISING_SET) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeClearAdvertisingSets : LeAdvertisingCommand (op_code = LE_CLEAR_ADVERTISING_SETS) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeSetPeriodicAdvertisingParam : LeAdvertisingCommand (op_code = LE_SET_PERIODIC_ADVERTISING_PARAM) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeSetPeriodicAdvertisingData : LeAdvertisingCommand (op_code = LE_SET_PERIODIC_ADVERTISING_DATA) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeSetPeriodicAdvertisingEnable : LeAdvertisingCommand (op_code = LE_SET_PERIODIC_ADVERTISING_ENABLE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeSetExtendedScanParameters : LeAdvertisingCommand (op_code = LE_SET_EXTENDED_SCAN_PARAMETERS) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeSetExtendedScanEnable : LeAdvertisingCommand (op_code = LE_SET_EXTENDED_SCAN_ENABLE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeExtendedCreateConnection : LeConnectionManagementCommand (op_code = LE_EXTENDED_CREATE_CONNECTION) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LePeriodicAdvertisingCreateSync : LeAdvertisingCommand (op_code = LE_PERIODIC_ADVERTISING_CREATE_SYNC) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LePeriodicAdvertisingCreateSyncCancel : LeAdvertisingCommand (op_code = LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LePeriodicAdvertisingTerminateSync : LeAdvertisingCommand (op_code = LE_PERIODIC_ADVERTISING_TERMINATE_SYNC) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeAddDeviceToPeriodicAdvertisingList : LeAdvertisingCommand (op_code = LE_ADD_DEVICE_TO_PERIODIC_ADVERTISING_LIST) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeRemoveDeviceFromPeriodicAdvertisingList : LeAdvertisingCommand (op_code = LE_REMOVE_DEVICE_FROM_PERIODIC_ADVERTISING_LIST) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeClearPeriodicAdvertisingList : LeAdvertisingCommand (op_code = LE_CLEAR_PERIODIC_ADVERTISING_LIST) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeReadPeriodicAdvertisingListSize : LeAdvertisingCommand (op_code = LE_READ_PERIODIC_ADVERTISING_LIST_SIZE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeReadTransmitPower : LeAdvertisingCommand (op_code = LE_READ_TRANSMIT_POWER) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeReadRfPathCompensationPower : LeAdvertisingCommand (op_code = LE_READ_RF_PATH_COMPENSATION_POWER) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeWriteRfPathCompensationPower : LeAdvertisingCommand (op_code = LE_WRITE_RF_PATH_COMPENSATION_POWER) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeSetPrivacyMode : LeSecurityCommand (op_code = LE_SET_PRIVACY_MODE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+
+ // VENDOR_SPECIFIC
+packet LeGetVendorCapabilities : VendorCommand (op_code = LE_GET_VENDOR_CAPABILITIES) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeMultiAdvt : VendorCommand (op_code = LE_MULTI_ADVT) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeBatchScan : VendorCommand (op_code = LE_BATCH_SCAN) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeAdvFilter : VendorCommand (op_code = LE_ADV_FILTER) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeTrackAdv : VendorCommand (op_code = LE_TRACK_ADV) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeEnergyInfo : VendorCommand (op_code = LE_ENERGY_INFO) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeExtendedScanParams : VendorCommand (op_code = LE_EXTENDED_SCAN_PARAMS) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet ControllerDebugInfo : VendorCommand (op_code = CONTROLLER_DEBUG_INFO) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet ControllerA2DPOpcode : VendorCommand (op_code = CONTROLLER_A2DP_OPCODE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+// HCI Event Packets
+
+packet InquiryComplete : EventPacket (event_code = INQUIRY_COMPLETE){
+ status : ErrorCode,
+}
+
+packet InquiryResult : EventPacket (event_code = INQUIRY_RESULT){
+ num_responses : 8,
+ bd_addr : Address,
+ page_scan_repetition_mode : PageScanRepetitionMode,
+ _reserved_ : 8,
+ _reserved_ : 8,
+ class_of_device : ClassOfDevice,
+ clock_offset : 15,
+ _reserved_ : 1,
+}
+
+enum LinkType : 8 {
+ SCO = 0x00,
+ ACL = 0x01,
+}
+
+packet ConnectionComplete : EventPacket (event_code = CONNECTION_COMPLETE){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ bd_addr : Address,
+ link_type : LinkType,
+ encryption_enabled : Enable,
+}
+
+enum ConnectionRequestLinkType : 8 {
+ SCO = 0x00,
+ ACL = 0x01,
+ ESCO = 0x02,
+}
+
+packet ConnectionRequest : EventPacket (event_code = CONNECTION_REQUEST){
+ bd_addr : Address,
+ class_of_device : ClassOfDevice,
+ link_type : ConnectionRequestLinkType,
+}
+
+packet DisconnectionComplete : EventPacket (event_code = DISCONNECTION_COMPLETE){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ reason : ErrorCode,
+}
+
+packet AuthenticationComplete : EventPacket (event_code = AUTHENTICATION_COMPLETE){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet RemoteNameRequestComplete : EventPacket (event_code = REMOTE_NAME_REQUEST_COMPLETE){
+ status : ErrorCode,
+ bd_addr : Address,
+ _payload_,
+}
+
+enum EncryptionEnabled : 8 {
+ OFF = 0x00,
+ ON = 0x01, // E0 for BR/EDR and AES-CCM for LE
+ BR_EDR_AES_CCM = 0x02,
+}
+
+packet EncryptionChange : EventPacket (event_code = ENCRYPTION_CHANGE){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ encryption_enabled : EncryptionEnabled,
+}
+
+packet ChangeConnectionLinkKeyComplete : EventPacket (event_code = CHANGE_CONNECTION_LINK_KEY_COMPLETE){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet MasterLinkKeyComplete : EventPacket (event_code = MASTER_LINK_KEY_COMPLETE){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ key_flag : KeyFlag,
+}
+
+packet ReadRemoteSupportedFeaturesComplete : EventPacket (event_code = READ_REMOTE_SUPPORTED_FEATURES_COMPLETE){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ lmp_features : 64,
+}
+
+packet ReadRemoteVersionInformationComplete : EventPacket (event_code = READ_REMOTE_VERSION_INFORMATION_COMPLETE){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ version : 8,
+ manufacturer_name : 8,
+ sub_version : 8,
+}
+
+enum ServiceType : 8 {
+ NO_TRAFFIC = 0x00,
+ BEST_EFFORT = 0x01,
+ GUARANTEED = 0x02,
+}
+
+packet QosSetupComplete : EventPacket (event_code = QOS_SETUP_COMPLETE){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ _reserved_ : 8,
+ service_type : ServiceType,
+ token_rate : 32, // Octets/s
+ peak_bandwidth : 32, // Octets/s
+ latency : 32, // Octets/s
+ delay_variation : 32, // microseconds
+}
+
+// Command Complete and Command Status Events are implemented above Commands.
+
+packet HardwareError : EventPacket (event_code = HARDWARE_ERROR){
+ hardware_code : 8,
+}
+
+packet FlushOccurred : EventPacket (event_code = FLUSH_OCCURRED){
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+enum Role : 8 {
+ MASTER = 0x00,
+ SLAVE = 0x01,
+}
+
+packet RoleChange : EventPacket (event_code = ROLE_CHANGE){
+ status : ErrorCode,
+ bd_addr : Address,
+ new_role : Role,
+}
+
+packet NumberOfCompletedPackets : EventPacket (event_code = NUMBER_OF_COMPLETED_PACKETS){
+ _payload_,
+}
+
+enum Mode : 8 {
+ ACTIVE = 0x00,
+ HOLD = 0x01,
+ SNIFF = 0x02,
+}
+
+packet ModeChange : EventPacket (event_code = MODE_CHANGE){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ current_mode : Mode,
+ interval : 16, // 0x002 - 0xFFFE (1.25ms - 40.9s)
+}
+
+packet ReturnLinkKeys : EventPacket (event_code = RETURN_LINK_KEYS){
+ _payload_, // placeholder (unimplemented)
+}
+
+packet PinCodeRequest : EventPacket (event_code = PIN_CODE_REQUEST){
+ bd_addr : Address,
+}
+
+packet LinkKeyRequest : EventPacket (event_code = LINK_KEY_REQUEST){
+ bd_addr : Address,
+}
+
+packet LinkKeyNotification : EventPacket (event_code = LINK_KEY_NOTIFICATION){
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LoopbackCommand : EventPacket (event_code = LOOPBACK_COMMAND){
+ _payload_, // placeholder (unimplemented)
+}
+
+packet DataBufferOverflow : EventPacket (event_code = DATA_BUFFER_OVERFLOW){
+ link_type : LinkType,
+}
+
+packet MaxSlotsChange : EventPacket (event_code = MAX_SLOTS_CHANGE){
+ connection_handle : 12,
+ _reserved_ : 4,
+ lmp_max_slots : 8,
+}
+
+packet ReadClockOffsetComplete : EventPacket (event_code = READ_CLOCK_OFFSET_COMPLETE){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ clock_offset : 15,
+ _reserved_ : 1,
+}
+
+packet ConnectionPacketTypeChange : EventPacket (event_code = CONNECTION_PACKET_TYPE_CHANGE){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ packet_type : 16,
+}
+
+packet QosViolation : EventPacket (event_code = QOS_VIOLATION){
+ _payload_, // placeholder (unimplemented)
+}
+
+packet PageScanRepetitionModeChange : EventPacket (event_code = PAGE_SCAN_REPETITION_MODE_CHANGE){
+ _payload_, // placeholder (unimplemented)
+}
+
+packet FlowSpecificationComplete : EventPacket (event_code = FLOW_SPECIFICATION_COMPLETE){
+ _payload_, // placeholder (unimplemented)
+}
+
+packet InquiryResultWithRssi : EventPacket (event_code = INQUIRY_RESULT_WITH_RSSI){
+ num_responses : 8,
+ address : Address,
+ page_scan_repetition_mode : PageScanRepetitionMode,
+ _reserved_ : 8,
+ class_of_device : ClassOfDevice,
+ clock_offset : 15,
+ _reserved_ : 1,
+ rssi : 8,
+}
+
+packet ReadRemoteExtendedFeaturesComplete : EventPacket (event_code = READ_REMOTE_EXTENDED_FEATURES_COMPLETE){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ page_number : 8,
+ maximum_page_number : 8,
+ extended_lmp_features : 64,
+}
+
+packet SynchronousConnectionComplete : EventPacket (event_code = SYNCHRONOUS_CONNECTION_COMPLETE){
+ _payload_, // placeholder (unimplemented)
+}
+
+packet SynchronousConnectionChanged : EventPacket (event_code = SYNCHRONOUS_CONNECTION_CHANGED){
+ _payload_, // placeholder (unimplemented)
+}
+
+packet SniffSubratingEvent : EventPacket (event_code = SNIFF_SUBRATING){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ maximum_transmit_latency : 16, // 0x000 - 0xFFFE (0s - 40.9s)
+ maximum_receive_latency : 16, // 0x000 - 0xFFFE (0s - 40.9s)
+ minimum_remote_timeout : 16, // 0x000 - 0xFFFE (0s - 40.9s)
+ minimum_local_timeout : 16, // 0x000 - 0xFFFE (0s - 40.9s)
+}
+
+packet ExtendedInquiryResult : EventPacket (event_code = EXTENDED_INQUIRY_RESULT) {
+ _fixed_ = 0x01 : 8,
+ address : Address,
+ page_scan_repetition_mode : PageScanRepetitionMode,
+ _reserved_ : 8,
+ class_of_device : ClassOfDevice,
+ clock_offset : 15,
+ _reserved_ : 1,
+ rssi : 8,
+ _payload_,
+}
+
+packet EncryptionKeyRefreshComplete : EventPacket (event_code = ENCRYPTION_KEY_REFRESH_COMPLETE){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet IoCapabilityRequest : EventPacket (event_code = IO_CAPABILITY_REQUEST){
+ bd_addr : Address,
+}
+
+packet IoCapabilityResponse : EventPacket (event_code = IO_CAPABILITY_RESPONSE){
+ bd_addr : Address,
+ io_capability : IoCapability,
+ oob_data_present : OobDataPresent,
+ authentication_requirements : AuthenticationRequirements,
+}
+
+packet UserConfirmationRequest : EventPacket (event_code = USER_CONFIRMATION_REQUEST){
+ bd_addr : Address,
+ numeric_value : 20, // 0x00000-0xF423F (000000 - 999999)
+ _reserved_ : 12,
+}
+
+packet UserPasskeyRequest : EventPacket (event_code = USER_PASSKEY_REQUEST){
+ bd_addr : Address,
+}
+
+packet RemoteOobDataRequest : EventPacket (event_code = REMOTE_OOB_DATA_REQUEST){
+ bd_addr : Address,
+}
+
+packet SimplePairingComplete : EventPacket (event_code = SIMPLE_PAIRING_COMPLETE){
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+packet LinkSupervisionTimeoutChanged : EventPacket (event_code = LINK_SUPERVISION_TIMEOUT_CHANGED){
+ connection_handle : 12,
+ _reserved_ : 4,
+ link_supervision_timeout : 16, // 0x001-0xFFFF (0.625ms-40.9s)
+}
+
+packet EnhancedFlushComplete : EventPacket (event_code = ENHANCED_FLUSH_COMPLETE){
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet UserPasskeyNotification : EventPacket (event_code = USER_PASSKEY_NOTIFICATION){
+ bd_addr : Address,
+ passkey : 20, // 0x00000-0xF423F (000000 - 999999)
+ _reserved_ : 12,
+}
+
+packet KeypressNotification : EventPacket (event_code = KEYPRESS_NOTIFICATION){
+ bd_addr : Address,
+ notification_type : KeypressNotificationType,
+}
+
+packet RemoteHostSupportedFeaturesNotification : EventPacket (event_code = REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION){
+ bd_addr : Address,
+ host_supported_features : 64,
+}
+
+packet LeMetaEvent : EventPacket (event_code = LE_META_EVENT) {
+ subevent_code : SubeventCode,
+ _payload_,
+}
+
+packet NumberOfCompletedDataBlocks : EventPacket (event_code = NUMBER_OF_COMPLETED_DATA_BLOCKS){
+ _payload_, // placeholder (unimplemented)
+}
+
+// LE Events
+
+enum MasterClockAccuracy : 8 {
+ PPM_500 = 0x00,
+ PPM_250 = 0x01,
+ PPM_150 = 0x02,
+ PPM_100 = 0x03,
+ PPM_75 = 0x04,
+ PPM_50 = 0x05,
+ PPM_30 = 0x06,
+ PPM_20 = 0x07,
+}
+
+packet LeConnectionComplete : LeMetaEvent (subevent_code = CONNECTION_COMPLETE) {
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ role : Role,
+ peer_address_type : PeerAddressType,
+ peer_address : Address,
+ conn_interval : 16, // 0x006 - 0x0C80 (7.5ms - 4000ms)
+ conn_latency : 16, // Number of connection events
+ supervision_timeout : 16, // 0x000A to 0x0C80 (100ms to 32s)
+ master_clock_accuracy : MasterClockAccuracy,
+}
+
+packet LeAdvertisingReport : LeMetaEvent (subevent_code = ADVERTISING_REPORT) {
+ _payload_,
+}
+
+packet LeConnectionUpdateComplete : LeMetaEvent (subevent_code = CONNECTION_UPDATE_COMPLETE) {
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ conn_interval : 16, // 0x006 - 0x0C80 (7.5ms - 4000ms)
+ conn_latency : 16, // Number of connection events
+ supervision_timeout : 16, // 0x000A to 0x0C80 (100ms to 32s)
+}
+
+packet LeReadRemoteFeaturesComplete : LeMetaEvent (subevent_code = READ_REMOTE_FEATURES_COMPLETE) {
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ le_features : 64,
+}
+
+packet LeLongTermKeyRequest : LeMetaEvent (subevent_code = LONG_TERM_KEY_REQUEST) {
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ random_number : 64,
+ encrypted_diversifier : 16,
+}
+
+packet LeRemoteConnectionParameterRequest : LeMetaEvent (subevent_code = REMOTE_CONNECTION_PARAMETER_REQUEST) {
+ connection_handle : 12,
+ _reserved_ : 4,
+ interval_min : 16, // 0x006 - 0x0C80 (7.5ms - 4s)
+ interval_max : 16, // 0x006 - 0x0C80 (7.5ms - 4s)
+ latency : 16, // Number of connection events (0x0000 to 0x01f3 (499)
+ timeout : 16, // 0x000A to 0x0C80 (100ms to 32s)
+}
+
+packet LeDataLengthChange : LeMetaEvent (subevent_code = DATA_LENGTH_CHANGE) {
+ connection_handle : 12,
+ _reserved_ : 4,
+ max_tx_octets : 16, // 0x001B - 0x00FB
+ max_tx_time : 16, // 0x0148 - 0x4290
+ max_rx_octets : 16, // 0x001B - 0x00FB
+ max_rx_time : 16, // 0x0148 - 0x4290
+}
+
+packet ReadLocalP256PublicKeyComplete : LeMetaEvent (subevent_code = READ_LOCAL_P256_PUBLIC_KEY_COMPLETE) {
+ status : ErrorCode,
+ _payload_,
+}
+
+packet GenerateDhKeyComplete : LeMetaEvent (subevent_code = GENERATE_DHKEY_COMPLETE) {
+ status : ErrorCode,
+ _payload_,
+}
+
+packet LeEnhancedConnectionComplete : LeMetaEvent (subevent_code = ENHANCED_CONNECTION_COMPLETE) {
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ role : Role,
+ peer_address_type : PeerAddressType,
+ peer_address : Address,
+ local_resolvable_private_address : Address,
+ peer_resolvable_private_address : Address,
+ conn_interval : 16, // 0x006 - 0x0C80 (7.5ms - 4000ms)
+ conn_latency : 16, // Number of connection events
+ supervision_timeout : 16, // 0x000A to 0x0C80 (100ms to 32s)
+ master_clock_accuracy : MasterClockAccuracy,
+}
+
+enum DirectAdvertisingAddressType : 8 {
+ PUBLIC_DEVICE_ADDRESS = 0x00,
+ RANDOM_DEVICE_ADDRESS = 0x01,
+ PUBLIC_IDENTITY_ADDRESS = 0x02,
+ RANDOM_IDENTITY_ADDRESS = 0x03,
+ NO_ADDRESS = 0xFF,
+}
+
+enum DirectAdvertisingEventType : 8 {
+ ADV_DIRECT_IND = 0x01,
+}
+
+enum DirectAddressType : 8 {
+ RANDOM_DEVICE_ADDRESS = 0x01,
+}
+
+packet LeDirectedAdvertisingReport : LeMetaEvent (subevent_code = DIRECTED_ADVERTISING_REPORT) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LePhyUpdateComplete : LeMetaEvent (subevent_code = PHY_UPDATE_COMPLETE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeExtendedAdvertisingReport : LeMetaEvent (subevent_code = EXTENDED_ADVERTISING_REPORT) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LePeriodicAdvertisingSyncEstablished : LeMetaEvent (subevent_code = PERIODIC_ADVERTISING_SYNC_ESTABLISHED) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LePeriodicAdvertisingReport : LeMetaEvent (subevent_code = PERIODIC_ADVERTISING_REPORT) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LePeriodicAdvertisingSyncLost : LeMetaEvent (subevent_code = PERIODIC_ADVERTISING_SYNC_LOST) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeScanTimeout : LeMetaEvent (subevent_code = SCAN_TIMEOUT) {
+}
+
+packet LeAdvertisingSetTerminated : LeMetaEvent (subevent_code = ADVERTISING_SET_TERMINATED) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeScanRequestReceived : LeMetaEvent (subevent_code = SCAN_REQUEST_RECEIVED) {
+ _payload_, // placeholder (unimplemented)
+}
diff --git a/gd/l2cap/Android.bp b/gd/l2cap/Android.bp
new file mode 100644
index 0000000..07808f5
--- /dev/null
+++ b/gd/l2cap/Android.bp
@@ -0,0 +1,7 @@
+filegroup {
+ name: "BluetoothL2capTestSources",
+ srcs: [
+ "l2cap_packet_test.cc",
+ "fcs.cc",
+ ],
+}
diff --git a/gd/l2cap/fcs.cc b/gd/l2cap/fcs.cc
new file mode 100644
index 0000000..380ff66
--- /dev/null
+++ b/gd/l2cap/fcs.cc
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2019 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 "l2cap/fcs.h"
+
+namespace {
+// Table for optimizing the CRC calculation, which is a bitwise operation.
+static const uint16_t crctab[256] = {
+ 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1,
+ 0xc481, 0x0440, 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, 0x0a00, 0xcac1, 0xcb81, 0x0b40,
+ 0xc901, 0x09c0, 0x0880, 0xc841, 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, 0x1e00, 0xdec1,
+ 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41, 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
+ 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040, 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1,
+ 0xf281, 0x3240, 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441, 0x3c00, 0xfcc1, 0xfd81, 0x3d40,
+ 0xff01, 0x3fc0, 0x3e80, 0xfe41, 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, 0x2800, 0xe8c1,
+ 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
+ 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640, 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0,
+ 0x2080, 0xe041, 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240, 0x6600, 0xa6c1, 0xa781, 0x6740,
+ 0xa501, 0x65c0, 0x6480, 0xa441, 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, 0xaa01, 0x6ac0,
+ 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
+ 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1,
+ 0xb681, 0x7640, 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041, 0x5000, 0x90c1, 0x9181, 0x5140,
+ 0x9301, 0x53c0, 0x5280, 0x9241, 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440, 0x9c01, 0x5cc0,
+ 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
+ 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0,
+ 0x4c80, 0x8c41, 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, 0x8201, 0x42c0, 0x4380, 0x8341,
+ 0x4100, 0x81c1, 0x8081, 0x4040,
+};
+} // namespace
+
+namespace bluetooth {
+namespace l2cap {
+
+void Fcs::Initialize(Fcs& s) {
+ s.crc = 0;
+}
+
+void Fcs::AddByte(Fcs& s, uint8_t byte) {
+ s.crc = ((s.crc >> 8) & 0x00ff) ^ crctab[(s.crc & 0x00ff) ^ byte];
+}
+
+uint16_t Fcs::GetChecksum(const Fcs& s) {
+ return s.crc;
+}
+
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/fcs.h b/gd/l2cap/fcs.h
new file mode 100644
index 0000000..42dd7dc
--- /dev/null
+++ b/gd/l2cap/fcs.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2019 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>
+
+namespace bluetooth {
+namespace l2cap {
+
+// Frame Check Sequence from the L2CAP spec.
+class Fcs {
+ public:
+ static void Initialize(Fcs& s);
+
+ static void AddByte(Fcs& s, uint8_t byte);
+
+ static uint16_t GetChecksum(const Fcs& s);
+
+ private:
+ uint16_t crc;
+};
+
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/l2cap_packet_test.cc b/gd/l2cap/l2cap_packet_test.cc
new file mode 100644
index 0000000..683d060
--- /dev/null
+++ b/gd/l2cap/l2cap_packet_test.cc
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2019 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 "l2cap/l2cap_packets.h"
+
+#include <gtest/gtest.h>
+#include <forward_list>
+#include <memory>
+
+#include "os/log.h"
+#include "packet/bit_inserter.h"
+#include "packet/raw_builder.h"
+
+using bluetooth::packet::BitInserter;
+using bluetooth::packet::RawBuilder;
+using std::vector;
+
+namespace {
+vector<uint8_t> extended_information_start_frame = {
+ 0x0B /* First size byte */,
+ 0x00 /* Second size byte */,
+ 0xc1 /* First ChannelId byte */,
+ 0xc2,
+ 0x4A /* 0x12 ReqSeq, Final, IFrame */,
+ 0xD0 /* 0x13 ReqSeq */,
+ 0x89 /* 0x21 TxSeq sar = START */,
+ 0x8C /* 0x23 TxSeq */,
+ 0x10 /* first length byte */,
+ 0x11,
+ 0x01 /* first payload byte */,
+ 0x02,
+ 0x03,
+ 0x04,
+ 0x05,
+};
+} // namespace
+
+namespace bluetooth {
+namespace l2cap {
+
+TEST(L2capPacketTest, extendedInformationStartFrameTest) {
+ uint16_t channel_id = 0xc2c1;
+ uint16_t l2cap_sdu_length = 0x1110;
+ Final f = Final::POLL_RESPONSE;
+ uint16_t req_seq = 0x1312;
+ uint16_t tx_seq = 0x2321;
+
+ std::unique_ptr<RawBuilder> payload = std::make_unique<RawBuilder>();
+ payload->AddOctets4(0x04030201);
+ payload->AddOctets1(0x05);
+
+ auto packet = ExtendedInformationStartFrameBuilder::Create(channel_id, f, req_seq, tx_seq, l2cap_sdu_length,
+ std::move(payload));
+
+ ASSERT_EQ(extended_information_start_frame.size(), packet->size());
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+ PacketView<true> packet_bytes_view(packet_bytes);
+ ASSERT_EQ(extended_information_start_frame.size(), packet_bytes_view.size());
+
+ BasicFrameView basic_frame_view = BasicFrameView::Create(packet_bytes_view);
+ ASSERT_TRUE(basic_frame_view.IsValid());
+ ASSERT_EQ(channel_id, basic_frame_view.GetChannelId());
+
+ StandardFrameView standard_frame_view = StandardFrameView::Create(basic_frame_view);
+ ASSERT_TRUE(standard_frame_view.IsValid());
+ ASSERT_EQ(FrameType::I_FRAME, standard_frame_view.GetFrameType());
+}
+
+vector<uint8_t> i_frame_with_fcs = {
+ 0x0E, 0x00, 0x40, 0x00, 0x02, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x38, 0x61,
+};
+TEST(L2capPacketTest, iFrameWithFcsTest) {
+ uint16_t channel_id = 0x0040;
+ SegmentationAndReassembly sar = SegmentationAndReassembly::UNSEGMENTED; // 0
+ uint16_t req_seq = 0;
+ uint16_t tx_seq = 1;
+ RetransmissionDisable r = RetransmissionDisable::NORMAL; // 0
+
+ std::unique_ptr<RawBuilder> payload = std::make_unique<RawBuilder>();
+ vector<uint8_t> payload_bytes = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};
+ payload->AddOctets(payload_bytes);
+
+ auto packet = StandardInformationFrameWithFcsBuilder::Create(channel_id, tx_seq, r, req_seq, sar, std::move(payload));
+
+ ASSERT_EQ(i_frame_with_fcs.size(), packet->size());
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+ PacketView<true> packet_bytes_view(packet_bytes);
+ ASSERT_EQ(i_frame_with_fcs.size(), packet_bytes_view.size());
+
+ for (size_t i = 0; i < i_frame_with_fcs.size(); i++) {
+ ASSERT_EQ(i_frame_with_fcs[i], packet_bytes_view[i]);
+ }
+
+ BasicFrameWithFcsView basic_frame_view = BasicFrameWithFcsView::Create(packet_bytes_view);
+ ASSERT_TRUE(basic_frame_view.IsValid());
+ ASSERT_EQ(channel_id, basic_frame_view.GetChannelId());
+
+ StandardFrameWithFcsView standard_frame_view = StandardFrameWithFcsView::Create(basic_frame_view);
+ ASSERT_TRUE(standard_frame_view.IsValid());
+ ASSERT_EQ(FrameType::I_FRAME, standard_frame_view.GetFrameType());
+
+ StandardInformationFrameWithFcsView information_frame_view =
+ StandardInformationFrameWithFcsView::Create(standard_frame_view);
+ ASSERT_TRUE(information_frame_view.IsValid());
+ ASSERT_EQ(sar, information_frame_view.GetSar());
+ ASSERT_EQ(req_seq, information_frame_view.GetReqSeq());
+ ASSERT_EQ(tx_seq, information_frame_view.GetTxSeq());
+ ASSERT_EQ(r, information_frame_view.GetR());
+}
+
+vector<uint8_t> rr_frame_with_fcs = {
+ 0x04, 0x00, 0x40, 0x00, 0x01, 0x01, 0xD4, 0x14,
+};
+TEST(L2capPacketTest, rrFrameWithFcsTest) {
+ uint16_t channel_id = 0x0040;
+ SupervisoryFunction s = SupervisoryFunction::RECEIVER_READY; // 0
+ RetransmissionDisable r = RetransmissionDisable::NORMAL; // 0
+ uint16_t req_seq = 1;
+
+ auto packet = StandardSupervisoryFrameWithFcsBuilder::Create(channel_id, s, r, req_seq);
+
+ ASSERT_EQ(rr_frame_with_fcs.size(), packet->size());
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+ PacketView<true> packet_bytes_view(packet_bytes);
+ ASSERT_EQ(rr_frame_with_fcs.size(), packet_bytes_view.size());
+
+ for (size_t i = 0; i < rr_frame_with_fcs.size(); i++) {
+ ASSERT_EQ(rr_frame_with_fcs[i], packet_bytes_view[i]);
+ }
+
+ BasicFrameWithFcsView basic_frame_view = BasicFrameWithFcsView::Create(packet_bytes_view);
+ ASSERT_TRUE(basic_frame_view.IsValid());
+ ASSERT_EQ(channel_id, basic_frame_view.GetChannelId());
+
+ StandardFrameWithFcsView standard_frame_view = StandardFrameWithFcsView::Create(basic_frame_view);
+ ASSERT_TRUE(standard_frame_view.IsValid());
+ ASSERT_EQ(FrameType::S_FRAME, standard_frame_view.GetFrameType());
+
+ StandardSupervisoryFrameWithFcsView supervisory_frame_view =
+ StandardSupervisoryFrameWithFcsView::Create(standard_frame_view);
+ ASSERT_TRUE(supervisory_frame_view.IsValid());
+ ASSERT_EQ(s, supervisory_frame_view.GetS());
+ ASSERT_EQ(r, supervisory_frame_view.GetR());
+ ASSERT_EQ(req_seq, supervisory_frame_view.GetReqSeq());
+}
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/l2cap_packets.pdl b/gd/l2cap/l2cap_packets.pdl
new file mode 100644
index 0000000..dfd18d4
--- /dev/null
+++ b/gd/l2cap/l2cap_packets.pdl
@@ -0,0 +1,631 @@
+little_endian_packets
+
+checksum Fcs : 16 "l2cap/"
+
+packet BasicFrame {
+ _size_(_payload_) : 16,
+ channel_id : 16,
+ _payload_,
+}
+
+packet BasicFrameWithFcs {
+ _checksum_start_(fcs),
+ _size_(_payload_) : 16,
+ channel_id : 16,
+ _payload_ : [+2*8], // Include Fcs in the _size_
+ fcs : Fcs,
+}
+
+// ChannelId 2 is connectionless
+packet GroupFrame : BasicFrame (channel_id = 0x02) {
+ psm : 16,
+ _payload_,
+}
+
+enum FrameType : 1 {
+ I_FRAME = 0,
+ S_FRAME = 1,
+}
+
+enum SupervisoryFunction : 2 {
+ RECEIVER_READY = 0,
+ REJECT = 1,
+ RECEIVER_NOT_READY = 2,
+ SELECT_REJECT = 3,
+}
+
+enum RetransmissionDisable : 1 {
+ NORMAL = 0,
+ DISABLE = 1,
+}
+
+enum SegmentationAndReassembly : 2 {
+ UNSEGMENTED = 0,
+ START = 1,
+ END = 2,
+ CONTINUATION = 3,
+}
+
+packet StandardFrame : BasicFrame {
+ frame_type : FrameType,
+ _body_,
+}
+
+packet StandardFrameWithFcs : BasicFrameWithFcs {
+ frame_type : FrameType,
+ _body_,
+}
+
+group StandardSupervisoryControl {
+ _fixed_ = 0 : 1,
+ s : SupervisoryFunction,
+ _reserved_ : 3,
+ r : RetransmissionDisable,
+ req_seq : 6,
+ _reserved_ : 2,
+}
+
+group StandardInformationControl {
+ tx_seq : 6,
+ r : RetransmissionDisable,
+ req_seq : 6,
+ sar : SegmentationAndReassembly,
+}
+
+packet StandardSupervisoryFrame : StandardFrame (frame_type = S_FRAME) {
+ StandardSupervisoryControl,
+}
+
+packet StandardSupervisoryFrameWithFcs : StandardFrameWithFcs (frame_type = S_FRAME) {
+ StandardSupervisoryControl,
+}
+
+packet StandardInformationFrame : StandardFrame (frame_type = I_FRAME) {
+ StandardInformationControl,
+ _payload_,
+}
+
+packet StandardInformationFrameWithFcs : StandardFrameWithFcs (frame_type = I_FRAME) {
+ StandardInformationControl,
+ _payload_,
+}
+
+packet StandardInformationStartFrame : StandardInformationFrame (sar = START) {
+ l2cap_sdu_length : 16,
+ _payload_,
+}
+
+packet StandardInformationStartFrameWithFcs : StandardInformationFrameWithFcs (sar = START) {
+ l2cap_sdu_length : 16,
+ _payload_,
+}
+
+enum Poll : 1 {
+ NOT_SET = 0,
+ POLL = 1,
+}
+
+enum Final : 1 {
+ NOT_SET = 0,
+ POLL_RESPONSE = 1,
+}
+
+group EnhancedSupervisoryControl {
+ _fixed_ = 0 : 1,
+ s : SupervisoryFunction,
+ p : Poll,
+ _reserved_ : 2,
+ f : Final,
+ req_seq : 6,
+ _reserved_ : 2,
+}
+
+group EnhancedInformationControl {
+ tx_seq : 6,
+ f : Final,
+ req_seq : 6,
+ sar : SegmentationAndReassembly,
+}
+
+packet EnhancedSupervisoryFrame : StandardFrame (frame_type = S_FRAME) {
+ EnhancedSupervisoryControl,
+}
+
+packet EnhancedSupervisoryFrameWithFcs : StandardFrameWithFcs (frame_type = S_FRAME) {
+ EnhancedSupervisoryControl,
+}
+
+packet EnhancedInformationFrame : StandardFrame (frame_type = I_FRAME) {
+ EnhancedInformationControl,
+ _payload_,
+}
+
+packet EnhancedInformationFrameWithFcs : StandardFrameWithFcs (frame_type = I_FRAME) {
+ EnhancedInformationControl,
+ _payload_,
+}
+
+packet EnhancedInformationStartFrame : EnhancedInformationFrame (sar = START) {
+ l2cap_sdu_length : 16,
+ _payload_,
+}
+
+packet EnhancedInformationStartFrameWithFcs : EnhancedInformationFrameWithFcs (sar = START) {
+ l2cap_sdu_length : 16,
+ _payload_,
+}
+
+group ExtendedSupervisoryControl {
+ f : Final,
+ req_seq : 14,
+ s : SupervisoryFunction,
+ p : Poll,
+ _reserved_ : 5,
+ _reserved_ : 8,
+}
+
+group ExtendedInformationControl {
+ f : Final,
+ req_seq : 14,
+ sar : SegmentationAndReassembly,
+ tx_seq : 14,
+}
+
+packet ExtendedSupervisoryFrame : StandardFrame (frame_type = S_FRAME) {
+ ExtendedSupervisoryControl,
+}
+
+packet ExtendedSupervisoryFrameWithFcs : StandardFrameWithFcs (frame_type = S_FRAME) {
+ ExtendedSupervisoryControl,
+}
+
+packet ExtendedInformationFrame : StandardFrame (frame_type = I_FRAME) {
+ ExtendedInformationControl,
+ _payload_,
+}
+
+packet ExtendedInformationFrameWithFcs : StandardFrameWithFcs (frame_type = I_FRAME) {
+ ExtendedInformationControl,
+ _payload_,
+}
+
+packet ExtendedInformationStartFrame : ExtendedInformationFrame (sar = START) {
+ l2cap_sdu_length : 16,
+ _payload_,
+}
+
+packet ExtendedInformationStartFrameWithFcs : ExtendedInformationFrameWithFcs (sar = START) {
+ l2cap_sdu_length : 16,
+ _payload_,
+}
+
+packet FirstLeInformationFrame : BasicFrame {
+ l2cap_sdu_length : 16,
+ _payload_,
+}
+
+enum CommandCode : 8 {
+ COMMAND_REJECT = 0x01,
+ CONNECTION_REQUEST = 0x02,
+ CONNECTION_RESPONSE = 0x03,
+ CONFIGURATION_REQUEST = 0x04,
+ CONFIGURATION_RESPONSE = 0x05,
+ DISCONNECTION_REQUEST = 0x06,
+ DISCONNECTION_RESPONSE = 0x07,
+ ECHO_REQUEST = 0x08,
+ ECHO_RESPONSE = 0x09,
+ INFORMATION_REQUEST = 0x0A,
+ INFORMATION_RESPONSE = 0x0B,
+ CREATE_CHANNEL_REQUEST = 0x0C,
+ CREATE_CHANNEL_RESPONSE = 0x0D,
+ MOVE_CHANNEL_REQUEST = 0x0E,
+ MOVE_CHANNEL_RESPONSE = 0x0F,
+ MOVE_CHANNEL_CONFIRMATION_REQUEST = 0x10,
+ MOVE_CHANNEL_CONFIRMATION_RESPONSE = 0x11,
+}
+
+packet ControlFrame : BasicFrame (channel_id = 0x0001) {
+ code : CommandCode,
+ identifier : 8,
+ _size_(_payload_) : 16,
+ _payload_,
+}
+
+
+enum CommandRejectReason : 16 {
+ COMMAND_NOT_UNDERSTOOD = 0x0000,
+ SIGNALING_MTU_EXCEEDED = 0x0001,
+ INVALID_CID_IN_REQUEST = 0x0002,
+}
+
+packet CommandReject : ControlFrame (code = COMMAND_REJECT) {
+ reason : CommandRejectReason,
+ _body_,
+}
+
+packet CommandRejectNotUnderstood : CommandReject (reason = COMMAND_NOT_UNDERSTOOD) {
+}
+
+packet CommandRejectMtuExceeded : CommandReject (reason = SIGNALING_MTU_EXCEEDED) {
+ actual_mtu : 16,
+}
+
+packet CommandRejectInvalidCid : CommandReject (reason = INVALID_CID_IN_REQUEST) {
+ local_channel : 16, // Relative to the sender of the CommandReject
+ remote_channel : 16,
+}
+
+packet ConnectionRequest : ControlFrame (code = CONNECTION_REQUEST) {
+ psm : 16,
+ source_cid : 16,
+}
+
+enum ConnectionResponseResult : 16 {
+ SUCCESS = 0x0000,
+ PENDING = 0x0001,
+ PSM_NOT_SUPPORTED = 0x0002,
+ SECURITY_BLOCK = 0x0003,
+ NO_RESOURCES_AVAILABLE = 0x0004,
+ INVALID_CID = 0x0006,
+ SOURCE_CID_ALREADY_ALLOCATED = 0x0007,
+}
+
+enum ConnectionResponseStatus : 16 {
+ NO_FURTHER_INFORMATION_AVAILABLE = 0x0000,
+ AUTHENTICATION_PENDING = 0x0001,
+ AUTHORIZATION_PENDING = 0x0002,
+}
+
+packet ConnectionResponse : ControlFrame (code = CONNECTION_RESPONSE) {
+ destination_cid : 16,
+ source_cid : 16,
+ result : ConnectionResponseResult,
+ status : ConnectionResponseStatus,
+}
+
+enum ConfigurationContinuation : 1 {
+ END = 0,
+ CONTINUES = 1,
+}
+
+packet ConfigurationRequestBase : ControlFrame (code = CONFIGURATION_REQUEST) {
+ destination_cid : 16,
+ continuation : ConfigurationContinuation,
+ _reserved_ : 15,
+ _payload_,
+}
+
+enum ConfigurationOptionsType : 7 {
+ MTU = 0x01,
+ FLUSH_TIMEOUT = 0x02,
+ QUALITY_OF_SERVICE = 0x03,
+ RETRANSMISSION_AND_FLOW_CONTROL = 0x04,
+ FRAME_CHECK_SEQUENCE = 0x05,
+ EXTENDED_FLOW_SPECIFICATION = 0x06,
+ EXTENDED_WINDOW_SIZE = 0x07,
+}
+
+enum ConfigurationOptionIsHint : 1 {
+ OPTION_MUST_BE_RECOGNIZED = 0,
+ OPTION_IS_A_HINT = 1,
+}
+
+packet ConfigurationOptions {
+ type : ConfigurationOptionsType,
+ is_hint : ConfigurationOptionIsHint,
+ _size_(_payload_) : 8,
+ _payload_,
+}
+
+packet MtuConfigurationOption : ConfigurationOptions (type = MTU) {
+ mtu : 16,
+}
+
+packet FlushTimeoutConfigurationOption : ConfigurationOptions (type = FLUSH_TIMEOUT) {
+ flush_timeout : 16,
+}
+
+enum QosServiceType : 8 {
+ NO_TRAFFIC = 0x00,
+ BEST_EFFORT = 0x01, // Default
+ GUARANTEED = 0x02,
+}
+
+packet QualityOfServiceConfigurationOption : ConfigurationOptions (type = QUALITY_OF_SERVICE) {
+ _reserved_ : 8, // Flags
+ service_type : QosServiceType,
+ token_rate : 32, // 0 = ignore, 0xffffffff = max available
+ token_bucket_size : 32, // 0 = ignore, 0xffffffff = max available
+ peak_bandwidth : 32, // Octets/second 0 = ignore
+ latency : 32, // microseconds 0xffffffff = ignore
+ delay_variation : 32, // microseconds 0xffffffff = ignore
+}
+
+enum RetransmissionAndFlowControlModeOption : 8 {
+ L2CAP_BASIC = 0x00,
+ RETRANSMISSION = 0x01,
+ FLOW_CONTROL = 0x02,
+ ENHANCED_RETRANSMISSION = 0x03,
+ STREAMING = 0x04,
+}
+
+
+packet RetransmissionAndFlowControlConfigurationOption : ConfigurationOptions (type = RETRANSMISSION_AND_FLOW_CONTROL) {
+ mode : RetransmissionAndFlowControlModeOption,
+ tx_window_size : 8, // 1-32 for Flow Control and Retransmission, 1-63 for Enhanced
+ max_transmit : 8,
+ retransmission_time_out : 8,
+ monitor_time_out : 16,
+ maximum_pdu_size : 16,
+}
+
+enum FcsType : 8 {
+ NO_FCS = 0,
+ DEFAULT = 1, // 16-bit FCS
+}
+
+packet FrameCheckSequenceOption : ConfigurationOptions (type = FRAME_CHECK_SEQUENCE) {
+ fcs_type : FcsType,
+}
+
+
+packet ExtendedFlowSpecificationOption : ConfigurationOptions (type = EXTENDED_FLOW_SPECIFICATION) {
+ identifier : 8, // Default 0x01, must be 0x01 for Extended Flow-Best-Effort
+ service_type : QosServiceType,
+ maximum_sdu_size : 16, // Octets
+ sdu_interarrival_time : 32, // in microseconds
+ access_latency : 32, // in microseconds, without HCI and stack overheads
+ flush_timeout : 32, // in microseconds 0x0 = no retransmissions 0xFFFFFFFF = never flushed
+}
+
+packet ExtendedWindowSizeOption : ConfigurationOptions (type = EXTENDED_WINDOW_SIZE) {
+ max_window_size : 16, // 0x0000 = Valid for streaming, 0x0001-0x3FFF Valid for Enhanced Retransmission
+}
+
+packet ConfigurationRequest : ConfigurationRequestBase {
+ _payload_,
+}
+
+enum ConfigurationResponseResult : 16 {
+ SUCCESS = 0x0000,
+ UNACCEPTABLE_PARAMETERS = 0x0001,
+ REJECTED = 0x0002,
+ UNKNOWN_OPTIONS = 0x0003,
+ PENDING = 0x0004,
+ FLOW_SPEC_REJECTED = 0x0005,
+}
+
+packet ConfigurationResponseBase : ControlFrame (code = CONFIGURATION_RESPONSE) {
+ source_cid : 16,
+ continuation : ConfigurationContinuation,
+ _reserved_ : 15,
+ result : ConfigurationResponseResult,
+ _payload_,
+}
+
+packet ConfigurationResponse : ConfigurationResponseBase {
+ _payload_,
+}
+
+packet DisconnectionRequest : ControlFrame (code = DISCONNECTION_REQUEST) {
+ destination_cid : 16,
+ source_cid : 16,
+}
+
+packet DisconnectionResponse : ControlFrame (code = DISCONNECTION_RESPONSE) {
+ destination_cid : 16,
+ source_cid : 16,
+}
+
+packet EchoRequest : ControlFrame (code = ECHO_REQUEST) {
+ _payload_, // Optional and implementation specific
+}
+
+packet EchoResponse : ControlFrame (code = ECHO_RESPONSE) {
+ _payload_, // Optional and implementation specific
+}
+
+enum InformationRequestInfoType : 16 {
+ CONNECTIONLESS_MTU = 0x0001,
+ EXTENDED_FEATURES_SUPPORTED = 0x0002,
+ FIXED_CHANNELS_SUPPORTED = 0x0003,
+}
+
+packet InformationRequest : ControlFrame (code = INFORMATION_REQUEST) {
+ info_type : InformationRequestInfoType,
+}
+
+enum InformationRequestResult : 16 {
+ SUCCESS = 0x0000,
+ NOT_SUPPORTED = 0x0001,
+}
+
+packet InformationResponse : ControlFrame (code = INFORMATION_RESPONSE) {
+ info_type : InformationRequestInfoType,
+ result : InformationRequestResult,
+ _body_,
+}
+
+packet InformationResponseConnectionlessMtu : InformationResponse (info_type = CONNECTIONLESS_MTU) {
+ connectionless_mtu : 16,
+}
+
+packet InformationResponseExtendedFeatures : InformationResponse (info_type = EXTENDED_FEATURES_SUPPORTED) {
+ // ExtendedFeatureMask : 32,
+ flow_control_mode : 1,
+ retransmission_mode : 1,
+ bi_directional_qoS : 1,
+ enhanced_retransmission_mode : 1,
+ streaming_mode : 1,
+ fcs_option : 1,
+ extended_flow_specification_for_br_edr : 1,
+ fixed_channels : 1,
+ extended_window_size : 1,
+ unicast_connectionless_data_reception : 1,
+ _reserved_ : 22,
+}
+
+packet InformationResponseFixedChannels : InformationResponse (info_type = FIXED_CHANNELS_SUPPORTED) {
+ fixed_channels : 64, // bit 0 must be 0, bit 1 must be 1, all others 1 = supported
+}
+
+packet CreateChannelRequest : ControlFrame (code = CREATE_CHANNEL_REQUEST) {
+ psm : 16,
+ source_cid : 16,
+ controller_id : 8,
+}
+
+enum CreateChannelResponseResult : 16 {
+ SUCCESS = 0x0000,
+ PENDING = 0x0001,
+ PSM_NOT_SUPPORTED = 0x0002,
+ SECURITY_BLOCK = 0x0003,
+ NO_RESOURCES_AVAILABLE = 0x0004,
+ CONTROLLER_ID_NOT_SUPPORTED = 0x0005,
+ INVALID_CID = 0x0006,
+ SOURCE_CID_ALREADY_ALLOCATED = 0x0007,
+}
+
+enum CreateChannelResponseStatus : 16 {
+ NO_FURTHER_INFORMATION_AVAILABLE = 0x0000,
+ AUTHENTICATION_PENDING = 0x0001,
+ AUTHORIZATION_PENDING = 0x0002,
+}
+
+packet CreateChannelResponse : ControlFrame (code = CREATE_CHANNEL_RESPONSE) {
+ destination_cid : 16,
+ source_cid : 16,
+ result : CreateChannelResponseResult,
+ status : CreateChannelResponseStatus,
+}
+
+// AMP Only ?
+packet MoveChannelRequest : ControlFrame (code = MOVE_CHANNEL_REQUEST) {
+ initiator_cid : 16,
+ dest_controller_id : 8,
+}
+
+enum MoveChannelResponseResult : 16 {
+ SUCCESS = 0x0000,
+ PENDING = 0x0001,
+ CONTROLLER_ID_NOT_SUPPORTED = 0x0002,
+ NEW_CONTROLLER_ID_IS_SAME = 0x0003,
+ CONFIGURATION_NOT_SUPPORTED = 0x0004,
+ CHANNEL_COLLISION = 0x0005,
+ CHANNEL_NOT_ALLOWED_TO_BE_MOVED = 0x0006,
+}
+
+packet MoveChannelResponse : ControlFrame (code = MOVE_CHANNEL_RESPONSE) {
+ initiator_cid : 16,
+ result : MoveChannelResponseResult,
+}
+
+enum MoveChannelConfirmationResult : 16 {
+ SUCCESS = 0x0000,
+ FAILURE = 0x0001,
+}
+
+packet MoveChannelConfirmationRequest : ControlFrame (code = MOVE_CHANNEL_CONFIRMATION_REQUEST) {
+ initiator_cid : 16,
+ result : MoveChannelConfirmationResult,
+}
+
+packet MoveChannelConfirmationResponse : ControlFrame (code = MOVE_CHANNEL_CONFIRMATION_RESPONSE) {
+ initiator_cid : 16,
+}
+
+enum LeCommandCode : 8 {
+ COMMAND_REJECT = 0x01,
+ DISCONNECTION_REQUEST = 0x06,
+ DISCONNECTION_RESPONSE = 0x07,
+ CONNECTION_PARAMETER_UPDATE_REQUEST = 0x12,
+ CONNECTION_PARAMETER_UPDATE_RESPONSE = 0x13,
+ LE_CREDIT_BASED_CONNECTION_REQUEST = 0x14,
+ LE_CREDIT_BASED_CONNECTION_RESPONSE = 0x15,
+ LE_FLOW_CONTROL_CREDIT = 0x16,
+}
+
+packet LeControlFrame : BasicFrame (channel_id = 0x0005) {
+ code : LeCommandCode,
+ identifier : 8, // Must be non-zero
+ _size_(_payload_) : 16,
+ _payload_,
+}
+
+packet LeCommandReject : LeControlFrame (code = COMMAND_REJECT) {
+ reason : CommandRejectReason,
+ _payload_,
+}
+
+packet LeCommandRejectNotUnderstood : LeCommandReject (reason = COMMAND_NOT_UNDERSTOOD) {
+}
+
+packet LeCommandRejectMtuExceeded : LeCommandReject (reason = SIGNALING_MTU_EXCEEDED) {
+ actual_mtu : 16,
+}
+
+packet LeCommandRejectInvalidCid : LeCommandReject (reason = INVALID_CID_IN_REQUEST) {
+ local_channel : 16, // Relative to the sender of the CommandReject
+ remote_channel : 16,
+}
+
+packet LeDisconnectionRequest : LeControlFrame (code = DISCONNECTION_REQUEST) {
+ destination_cid : 16,
+ source_cid : 16,
+}
+
+packet LeDisconnectionResponse : LeControlFrame (code = DISCONNECTION_RESPONSE) {
+ destination_cid : 16,
+ source_cid : 16,
+}
+
+packet ConnectionParameterUpdateRequest : LeControlFrame (code = CONNECTION_PARAMETER_UPDATE_REQUEST) {
+ interval_min : 16,
+ interval_max : 16,
+ slave_latency : 16,
+ timeout_multiplier : 16,
+}
+
+enum ConnectionParameterUpdateResponseResult : 16 {
+ ACCEPTED = 0,
+ REJECTED = 1,
+}
+
+packet ConnectionParameterUpdateResponse : LeControlFrame (code = CONNECTION_PARAMETER_UPDATE_RESPONSE) {
+ result : ConnectionParameterUpdateResponseResult,
+}
+
+packet LeCreditBasedConnectionRequest : LeControlFrame (code = LE_CREDIT_BASED_CONNECTION_REQUEST) {
+ le_psm : 16, // 0x0001-0x007F Fixed, 0x0080-0x00FF Dynamic
+ source_cid : 16,
+ mtu : 16,
+ mps : 16,
+ initial_credits : 16,
+}
+
+enum LeCreditBasedConnectionResponseResult : 16 {
+ SUCCESS = 0x0000,
+ LE_PSM_NOT_SUPPORTED = 0x0002,
+ NO_RESOURCES_AVAILABLE = 0x0004,
+ INSUFFICIENT_AUTHENTICATION = 0x0005,
+ INSUFFICIENT_AUTHORIZATION = 0x0006,
+ INSUFFICIENT_ENCRYPTION_KEY_SIZE = 0x0007,
+ INSUFFICIENT_ENCRYPTION = 0x0008,
+ INVALID_SOURCE_CID = 0x0009,
+ SOURCE_CID_ALREADY_ALLOCATED = 0x000A,
+ UNACCEPTABLE_PARAMETERS = 0x000B,
+}
+
+packet LeCreditBasedConnectionResponse : LeControlFrame (code = LE_CREDIT_BASED_CONNECTION_RESPONSE) {
+ destination_cid : 16,
+ mtu : 16,
+ mps : 16,
+ initial_credits : 16,
+ result : LeCreditBasedConnectionResponseResult,
+}
+
+packet LeFlowControlCredit : LeControlFrame (code = LE_FLOW_CONTROL_CREDIT) {
+ cid : 16, // Receiver's destination CID
+ credits : 16,
+}
+
diff --git a/gd/module.cc b/gd/module.cc
new file mode 100644
index 0000000..6ab803b
--- /dev/null
+++ b/gd/module.cc
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2019 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 "module.h"
+
+using ::bluetooth::os::Handler;
+using ::bluetooth::os::Thread;
+
+namespace bluetooth {
+
+ModuleFactory::ModuleFactory(std::function<Module*()> ctor) : ctor_(ctor) {
+}
+
+Handler* Module::GetHandler() {
+ ASSERT_LOG(handler_ != nullptr, "Can't get handler when it's not started");
+ return handler_;
+}
+
+const ModuleRegistry* Module::GetModuleRegistry() {
+ return registry_;
+}
+
+Module* Module::GetDependency(const ModuleFactory* module) const {
+ for (auto& dependency : dependencies_.list_) {
+ if (dependency == module) {
+ return registry_->Get(module);
+ }
+ }
+
+ ASSERT_LOG(false, "Module was not listed as a dependency in ListDependencies");
+}
+
+Module* ModuleRegistry::Get(const ModuleFactory* module) const {
+ auto instance = started_modules_.find(module);
+ ASSERT(instance != started_modules_.end());
+ return instance->second;
+}
+
+bool ModuleRegistry::IsStarted(const ModuleFactory* module) const {
+ return started_modules_.find(module) != started_modules_.end();
+}
+
+void ModuleRegistry::Start(ModuleList* modules, Thread* thread) {
+ for (auto it = modules->list_.begin(); it != modules->list_.end(); it++) {
+ Start(*it, thread);
+ }
+}
+
+void ModuleRegistry::set_registry_and_handler(Module* instance, Thread* thread) const {
+ instance->registry_ = this;
+ instance->handler_ = new Handler(thread);
+}
+
+Module* ModuleRegistry::Start(const ModuleFactory* module, Thread* thread) {
+ auto started_instance = started_modules_.find(module);
+ if (started_instance != started_modules_.end()) {
+ return started_instance->second;
+ }
+
+ Module* instance = module->ctor_();
+ set_registry_and_handler(instance, thread);
+
+ instance->ListDependencies(&instance->dependencies_);
+ Start(&instance->dependencies_, thread);
+
+ instance->Start();
+ start_order_.push_back(module);
+ started_modules_[module] = instance;
+ return instance;
+}
+
+void ModuleRegistry::StopAll() {
+ // Since modules were brought up in dependency order,
+ // it is safe to tear down by going in reverse order.
+ for (auto it = start_order_.rbegin(); it != start_order_.rend(); it++) {
+ auto instance = started_modules_.find(*it);
+ ASSERT(instance != started_modules_.end());
+
+ instance->second->Stop();
+
+ delete instance->second->handler_;
+ delete instance->second;
+ started_modules_.erase(instance);
+ }
+
+ ASSERT(started_modules_.empty());
+ start_order_.clear();
+}
+
+os::Handler* ModuleRegistry::GetModuleHandler(const ModuleFactory* module) const {
+ auto started_instance = started_modules_.find(module);
+ if (started_instance != started_modules_.end()) {
+ return started_instance->second->GetHandler();
+ }
+ return nullptr;
+}
+} // namespace bluetooth
diff --git a/gd/module.h b/gd/module.h
new file mode 100644
index 0000000..046ee8c
--- /dev/null
+++ b/gd/module.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2019 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 <future>
+#include <map>
+#include <vector>
+
+#include "os/log.h"
+#include "os/handler.h"
+#include "os/thread.h"
+
+namespace bluetooth {
+
+const std::chrono::milliseconds kModuleStopTimeout = std::chrono::milliseconds(20);
+
+class Module;
+class ModuleRegistry;
+
+class ModuleFactory {
+ friend ModuleRegistry;
+ public:
+ ModuleFactory(std::function<Module*()> ctor);
+
+ private:
+ std::function<Module*()> ctor_;
+};
+
+class ModuleList {
+ friend ModuleRegistry;
+ friend Module;
+ public:
+ template <class T>
+ void add() {
+ list_.push_back(&T::Factory);
+ }
+
+ private:
+ std::vector<const ModuleFactory*> list_;
+};
+
+// Each leaf node module must have a factory like so:
+//
+// static const ModuleFactory Factory;
+//
+// which will provide a constructor for the module registry to call.
+// The module registry will also use the factory as the identifier
+// for that module.
+class Module {
+ friend ModuleRegistry;
+ public:
+ virtual ~Module() = default;
+ protected:
+ // Populate the provided list with modules that must start before yours
+ virtual void ListDependencies(ModuleList* list) = 0;
+
+ // You can grab your started dependencies during or after this call
+ // using GetDependency(), or access the module registry via GetModuleRegistry()
+ virtual void Start() = 0;
+
+ // Release all resources, you're about to be deleted
+ virtual void Stop() = 0;
+
+ ::bluetooth::os::Handler* GetHandler();
+
+ const ModuleRegistry* GetModuleRegistry();
+
+ template <class T>
+ T* GetDependency() const {
+ return static_cast<T*>(GetDependency(&T::Factory));
+ }
+
+ private:
+ Module* GetDependency(const ModuleFactory* module) const;
+
+ ::bluetooth::os::Handler* handler_ = nullptr;
+ ModuleList dependencies_;
+ const ModuleRegistry* registry_;
+};
+
+class ModuleRegistry {
+ friend Module;
+ friend class StackManager;
+ public:
+ template <class T>
+ bool IsStarted() const {
+ return IsStarted(&T::Factory);
+ }
+
+ bool IsStarted(const ModuleFactory* factory) const;
+
+ // Start all the modules on this list and their dependencies
+ // in dependency order
+ void Start(ModuleList* modules, ::bluetooth::os::Thread* thread);
+
+ template <class T>
+ T* Start(::bluetooth::os::Thread* thread) {
+ return static_cast<T*>(Start(&T::Factory, thread));
+ }
+
+ Module* Start(const ModuleFactory* id, ::bluetooth::os::Thread* thread);
+
+ // Stop all running modules in reverse order of start
+ void StopAll();
+
+ protected:
+ Module* Get(const ModuleFactory* module) const;
+
+ void set_registry_and_handler(Module* instance, ::bluetooth::os::Thread* thread) const;
+
+ os::Handler* GetModuleHandler(const ModuleFactory* module) const;
+
+ std::map<const ModuleFactory*, Module*> started_modules_;
+ std::vector<const ModuleFactory*> start_order_;
+};
+
+class TestModuleRegistry : public ModuleRegistry {
+ public:
+ void InjectTestModule(const ModuleFactory* module, Module* instance) {
+ start_order_.push_back(module);
+ started_modules_[module] = instance;
+ set_registry_and_handler(instance, &test_thread);
+ }
+
+ Module* GetModuleUnderTest(const ModuleFactory* module) const {
+ return Get(module);
+ }
+
+ os::Handler* GetTestModuleHandler(const ModuleFactory* module) const {
+ return GetModuleHandler(module);
+ }
+
+ os::Thread& GetTestThread() {
+ return test_thread;
+ }
+
+ bool SynchronizeModuleHandler(const ModuleFactory* module, std::chrono::milliseconds timeout) const {
+ std::promise<void> promise;
+ os::Handler* handler = GetTestModuleHandler(module);
+ handler->Post([&promise] { promise.set_value(); });
+ return promise.get_future().wait_for(timeout) == std::future_status::ready;
+ }
+
+ os::Thread test_thread{"test_thread", os::Thread::Priority::NORMAL};
+};
+
+} // namespace bluetooth
diff --git a/gd/module_unittest.cc b/gd/module_unittest.cc
new file mode 100644
index 0000000..d0efb5d
--- /dev/null
+++ b/gd/module_unittest.cc
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2019 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 "module.h"
+
+#include "gtest/gtest.h"
+
+using ::bluetooth::os::Thread;
+
+namespace bluetooth {
+namespace {
+
+class ModuleTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ thread_ = new Thread("test_thread", Thread::Priority::NORMAL);
+ registry_ = new ModuleRegistry();
+ }
+
+ void TearDown() override {
+ delete registry_;
+ delete thread_;
+ }
+
+ ModuleRegistry* registry_;
+ Thread* thread_;
+};
+
+class TestModuleNoDependency : public Module {
+ public:
+ static const ModuleFactory Factory;
+
+ protected:
+ void ListDependencies(ModuleList* list) override {
+ }
+
+ void Start() override {
+ // A module is not considered started until Start() finishes
+ EXPECT_FALSE(GetModuleRegistry()->IsStarted<TestModuleNoDependency>());
+ }
+
+ void Stop() override {
+ // A module is not considered stopped until after Stop() finishes
+ EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleNoDependency>());
+ }
+};
+
+const ModuleFactory TestModuleNoDependency::Factory = ModuleFactory([]() {
+ return new TestModuleNoDependency();
+});
+
+class TestModuleOneDependency : public Module {
+ public:
+ static const ModuleFactory Factory;
+
+ protected:
+ void ListDependencies(ModuleList* list) override {
+ list->add<TestModuleNoDependency>();
+ }
+
+ void Start() override {
+ EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleNoDependency>());
+
+ // A module is not considered started until Start() finishes
+ EXPECT_FALSE(GetModuleRegistry()->IsStarted<TestModuleOneDependency>());
+ }
+
+ void Stop() override {
+ EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleNoDependency>());
+
+ // A module is not considered stopped until after Stop() finishes
+ EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleOneDependency>());
+ }
+};
+
+const ModuleFactory TestModuleOneDependency::Factory = ModuleFactory([]() {
+ return new TestModuleOneDependency();
+});
+
+
+class TestModuleNoDependencyTwo : public Module {
+ public:
+ static const ModuleFactory Factory;
+
+ protected:
+ void ListDependencies(ModuleList* list) override {
+ }
+
+ void Start() override {
+ // A module is not considered started until Start() finishes
+ EXPECT_FALSE(GetModuleRegistry()->IsStarted<TestModuleNoDependencyTwo>());
+ }
+
+ void Stop() override {
+ // A module is not considered stopped until after Stop() finishes
+ EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleNoDependencyTwo>());
+ }
+};
+
+const ModuleFactory TestModuleNoDependencyTwo::Factory = ModuleFactory([]() {
+ return new TestModuleNoDependencyTwo();
+});
+
+class TestModuleTwoDependencies : public Module {
+ public:
+ static const ModuleFactory Factory;
+
+ protected:
+ void ListDependencies(ModuleList* list) override {
+ list->add<TestModuleOneDependency>();
+ list->add<TestModuleNoDependencyTwo>();
+ }
+
+ void Start() override {
+ EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleOneDependency>());
+ EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleNoDependencyTwo>());
+
+ // A module is not considered started until Start() finishes
+ EXPECT_FALSE(GetModuleRegistry()->IsStarted<TestModuleTwoDependencies>());
+ }
+
+ void Stop() override {
+ EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleOneDependency>());
+ EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleNoDependencyTwo>());
+
+ // A module is not considered stopped until after Stop() finishes
+ EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleTwoDependencies>());
+ }
+};
+
+const ModuleFactory TestModuleTwoDependencies::Factory = ModuleFactory([]() {
+ return new TestModuleTwoDependencies();
+});
+
+TEST_F(ModuleTest, no_dependency) {
+ ModuleList list;
+ list.add<TestModuleNoDependency>();
+ registry_->Start(&list, thread_);
+
+ EXPECT_TRUE(registry_->IsStarted<TestModuleNoDependency>());
+ EXPECT_FALSE(registry_->IsStarted<TestModuleOneDependency>());
+ EXPECT_FALSE(registry_->IsStarted<TestModuleNoDependencyTwo>());
+ EXPECT_FALSE(registry_->IsStarted<TestModuleTwoDependencies>());
+
+ registry_->StopAll();
+
+ EXPECT_FALSE(registry_->IsStarted<TestModuleNoDependency>());
+ EXPECT_FALSE(registry_->IsStarted<TestModuleOneDependency>());
+ EXPECT_FALSE(registry_->IsStarted<TestModuleNoDependencyTwo>());
+ EXPECT_FALSE(registry_->IsStarted<TestModuleTwoDependencies>());
+}
+
+TEST_F(ModuleTest, one_dependency) {
+ ModuleList list;
+ list.add<TestModuleOneDependency>();
+ registry_->Start(&list, thread_);
+
+ EXPECT_TRUE(registry_->IsStarted<TestModuleNoDependency>());
+ EXPECT_TRUE(registry_->IsStarted<TestModuleOneDependency>());
+ EXPECT_FALSE(registry_->IsStarted<TestModuleNoDependencyTwo>());
+ EXPECT_FALSE(registry_->IsStarted<TestModuleTwoDependencies>());
+
+ registry_->StopAll();
+
+ EXPECT_FALSE(registry_->IsStarted<TestModuleNoDependency>());
+ EXPECT_FALSE(registry_->IsStarted<TestModuleOneDependency>());
+ EXPECT_FALSE(registry_->IsStarted<TestModuleNoDependencyTwo>());
+ EXPECT_FALSE(registry_->IsStarted<TestModuleTwoDependencies>());
+}
+
+TEST_F(ModuleTest, two_dependencies) {
+ ModuleList list;
+ list.add<TestModuleTwoDependencies>();
+ registry_->Start(&list, thread_);
+
+ EXPECT_TRUE(registry_->IsStarted<TestModuleNoDependency>());
+ EXPECT_TRUE(registry_->IsStarted<TestModuleOneDependency>());
+ EXPECT_TRUE(registry_->IsStarted<TestModuleNoDependencyTwo>());
+ EXPECT_TRUE(registry_->IsStarted<TestModuleTwoDependencies>());
+
+ registry_->StopAll();
+
+ EXPECT_FALSE(registry_->IsStarted<TestModuleNoDependency>());
+ EXPECT_FALSE(registry_->IsStarted<TestModuleOneDependency>());
+ EXPECT_FALSE(registry_->IsStarted<TestModuleNoDependencyTwo>());
+ EXPECT_FALSE(registry_->IsStarted<TestModuleTwoDependencies>());
+}
+
+} // namespace
+} // namespace bluetooth
diff --git a/gd/os/Android.bp b/gd/os/Android.bp
new file mode 100644
index 0000000..b8ad91a
--- /dev/null
+++ b/gd/os/Android.bp
@@ -0,0 +1,32 @@
+filegroup {
+ name: "BluetoothOsSources_linux_generic",
+ srcs: [
+ "linux_generic/alarm.cc",
+ "linux_generic/handler.cc",
+ "linux_generic/reactor.cc",
+ "linux_generic/repeating_alarm.cc",
+ "linux_generic/reactive_semaphore.cc",
+ "linux_generic/thread.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothOsTestSources_linux_generic",
+ srcs: [
+ "linux_generic/alarm_unittest.cc",
+ "linux_generic/handler_unittest.cc",
+ "linux_generic/queue_unittest.cc",
+ "linux_generic/reactor_unittest.cc",
+ "linux_generic/repeating_alarm_unittest.cc",
+ "linux_generic/thread_unittest.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothOsBenchmarkSources",
+ srcs: [
+ "alarm_benchmark.cc",
+ "thread_benchmark.cc",
+ "queue_benchmark.cc",
+ ],
+}
diff --git a/gd/os/alarm.h b/gd/os/alarm.h
new file mode 100644
index 0000000..6c07474
--- /dev/null
+++ b/gd/os/alarm.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2019 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 <mutex>
+
+#include "os/thread.h"
+#include "os/utils.h"
+
+namespace bluetooth {
+namespace os {
+
+// A single-shot alarm for reactor-based thread, implemented by Linux timerfd.
+// When it's constructed, it will register a reactable on the specified thread; when it's destroyed, it will unregister
+// itself from the thread.
+class Alarm {
+ public:
+ // Create and register a single-shot alarm on given thread
+ explicit Alarm(Thread* thread);
+
+ // Unregister this alarm from the thread and release resource
+ ~Alarm();
+
+ DISALLOW_COPY_AND_ASSIGN(Alarm);
+
+ // Schedule the alarm with given delay
+ void Schedule(Closure task, std::chrono::milliseconds delay);
+
+ // Cancel the alarm. No-op if it's not armed.
+ void Cancel();
+
+ private:
+ Closure task_;
+ Thread* thread_;
+ int fd_ = 0;
+ Reactor::Reactable* token_;
+ mutable std::mutex mutex_;
+ void on_fire();
+};
+
+} // namespace os
+
+} // namespace bluetooth
diff --git a/gd/os/alarm_benchmark.cc b/gd/os/alarm_benchmark.cc
new file mode 100644
index 0000000..54b8a38
--- /dev/null
+++ b/gd/os/alarm_benchmark.cc
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2019 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 <chrono>
+#include <future>
+#include <unordered_map>
+
+#include "benchmark/benchmark.h"
+
+#include "os/alarm.h"
+#include "os/repeating_alarm.h"
+#include "os/thread.h"
+
+using ::benchmark::State;
+using ::bluetooth::os::Alarm;
+using ::bluetooth::os::RepeatingAlarm;
+using ::bluetooth::os::Thread;
+
+class BM_ReactableAlarm : public ::benchmark::Fixture {
+ protected:
+ void SetUp(State& st) override {
+ ::benchmark::Fixture::SetUp(st);
+ thread_ = std::make_unique<Thread>("timer_benchmark", Thread::Priority::REAL_TIME);
+ alarm_ = std::make_unique<Alarm>(thread_.get());
+ repeating_alarm_ = std::make_unique<RepeatingAlarm>(thread_.get());
+ map_.clear();
+ scheduled_tasks_ = 0;
+ task_length_ = 0;
+ task_interval_ = 0;
+ task_counter_ = 0;
+ promise_ = std::promise<void>();
+ }
+
+ void TearDown(State& st) override {
+ alarm_ = nullptr;
+ repeating_alarm_ = nullptr;
+ thread_->Stop();
+ thread_ = nullptr;
+ ::benchmark::Fixture::TearDown(st);
+ }
+
+ void AlarmSleepAndCountDelayedTime() {
+ auto end_time = std::chrono::steady_clock::now();
+ auto duration_since_start = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time_);
+ task_counter_++;
+ map_[duration_since_start.count() - task_counter_ * task_interval_]++;
+ std::this_thread::sleep_for(std::chrono::milliseconds(task_length_));
+ if (task_counter_ >= scheduled_tasks_) {
+ promise_.set_value();
+ }
+ }
+
+ void TimerFire() {
+ promise_.set_value();
+ }
+
+ int64_t scheduled_tasks_;
+ int64_t task_length_;
+ int64_t task_interval_;
+ int task_counter_;
+ std::unordered_map<int, int> map_;
+ std::promise<void> promise_;
+ std::chrono::time_point<std::chrono::steady_clock> start_time_;
+ std::unique_ptr<Thread> thread_;
+ std::unique_ptr<Alarm> alarm_;
+ std::unique_ptr<RepeatingAlarm> repeating_alarm_;
+};
+
+BENCHMARK_DEFINE_F(BM_ReactableAlarm, timer_performance_ms)(State& state) {
+ auto milliseconds = static_cast<int>(state.range(0));
+ for (auto _ : state) {
+ auto start_time_point = std::chrono::steady_clock::now();
+ alarm_->Schedule([this] { return TimerFire(); }, std::chrono::milliseconds(milliseconds));
+ promise_.get_future().get();
+ auto end_time_point = std::chrono::steady_clock::now();
+ auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time_point - start_time_point);
+ state.SetIterationTime(static_cast<double>(duration.count()) * 1e-6);
+ alarm_->Cancel();
+ }
+};
+
+BENCHMARK_REGISTER_F(BM_ReactableAlarm, timer_performance_ms)
+ ->Arg(1)
+ ->Arg(5)
+ ->Arg(10)
+ ->Arg(20)
+ ->Arg(100)
+ ->Arg(1000)
+ ->Arg(2000)
+ ->Iterations(1)
+ ->UseRealTime();
+
+BENCHMARK_DEFINE_F(BM_ReactableAlarm, periodic_accuracy)(State& state) {
+ for (auto _ : state) {
+ scheduled_tasks_ = state.range(0);
+ task_length_ = state.range(1);
+ task_interval_ = state.range(2);
+ start_time_ = std::chrono::steady_clock::now();
+ repeating_alarm_->Schedule([this] { AlarmSleepAndCountDelayedTime(); }, std::chrono::milliseconds(task_interval_));
+ promise_.get_future().get();
+ repeating_alarm_->Cancel();
+ }
+ for (const auto& delay : map_) {
+ state.counters[std::to_string(delay.first)] = delay.second;
+ }
+};
+
+BENCHMARK_REGISTER_F(BM_ReactableAlarm, periodic_accuracy)
+ ->Args({2000, 1, 5})
+ ->Args({2000, 3, 5})
+ ->Args({2000, 1, 7})
+ ->Args({2000, 3, 7})
+ ->Args({2000, 1, 20})
+ ->Args({2000, 5, 20})
+ ->Args({2000, 10, 20})
+ ->Args({2000, 15, 20})
+ ->Iterations(1)
+ ->UseRealTime();
diff --git a/gd/os/handler.h b/gd/os/handler.h
new file mode 100644
index 0000000..509723e
--- /dev/null
+++ b/gd/os/handler.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2019 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 <mutex>
+#include <queue>
+
+#include "os/thread.h"
+#include "os/utils.h"
+
+namespace bluetooth {
+namespace os {
+
+// A message-queue style handler for reactor-based thread to handle incoming events from different threads. When it's
+// constructed, it will register a reactable on the specified thread; when it's destroyed, it will unregister itself
+// from the thread.
+class Handler {
+ public:
+ // Create and register a handler on given thread
+ explicit Handler(Thread* thread);
+
+ // Unregister this handler from the thread and release resource. Unhandled events will be discarded and not executed.
+ ~Handler();
+
+ DISALLOW_COPY_AND_ASSIGN(Handler);
+
+ // Enqueue a closure to the queue of this handler
+ void Post(Closure closure);
+
+ // Remove all pending events from the queue of this handler
+ void Clear();
+
+ template <typename T>
+ friend class Queue;
+
+ private:
+ std::queue<Closure> tasks_;
+ Thread* thread_;
+ int fd_;
+ Reactor::Reactable* reactable_;
+ mutable std::mutex mutex_;
+ void handle_next_event();
+};
+
+} // namespace os
+} // namespace bluetooth
diff --git a/gd/os/linux_generic/alarm.cc b/gd/os/linux_generic/alarm.cc
new file mode 100644
index 0000000..7a3754b
--- /dev/null
+++ b/gd/os/linux_generic/alarm.cc
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2019 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 "os/alarm.h"
+
+#include <sys/timerfd.h>
+#include <cstring>
+#include <unistd.h>
+
+#include "os/log.h"
+#include "os/utils.h"
+
+#ifdef OS_ANDROID
+#define ALARM_CLOCK CLOCK_BOOTTIME_ALARM
+#else
+#define ALARM_CLOCK CLOCK_BOOTTIME
+#endif
+
+namespace bluetooth {
+namespace os {
+
+Alarm::Alarm(Thread* thread) : thread_(thread), fd_(timerfd_create(ALARM_CLOCK, 0)) {
+ ASSERT_LOG(fd_ != -1, "cannot create timerfd: %s", strerror(errno));
+
+ token_ = thread_->GetReactor()->Register(fd_, [this] { on_fire(); }, nullptr);
+}
+
+Alarm::~Alarm() {
+ thread_->GetReactor()->Unregister(token_);
+
+ int close_status;
+ RUN_NO_INTR(close_status = close(fd_));
+ ASSERT(close_status != -1);
+}
+
+void Alarm::Schedule(Closure task, std::chrono::milliseconds delay) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ long delay_ms = delay.count();
+ itimerspec timer_itimerspec{
+ {/* interval for periodic timer */},
+ {delay_ms / 1000, delay_ms % 1000 * 1000000}
+ };
+ int result = timerfd_settime(fd_, 0, &timer_itimerspec, nullptr);
+ ASSERT(result == 0);
+
+ task_ = std::move(task);
+}
+
+void Alarm::Cancel() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ itimerspec disarm_itimerspec{/* disarm timer */};
+ int result = timerfd_settime(fd_, 0, &disarm_itimerspec, nullptr);
+ ASSERT(result == 0);
+}
+
+void Alarm::on_fire() {
+ std::unique_lock<std::mutex> lock(mutex_);
+ auto task = std::move(task_);
+ uint64_t times_invoked;
+ auto bytes_read = read(fd_, ×_invoked, sizeof(uint64_t));
+ lock.unlock();
+ task();
+ ASSERT(bytes_read == static_cast<ssize_t>(sizeof(uint64_t)));
+ ASSERT(times_invoked == static_cast<uint64_t>(1));
+}
+
+} // namespace os
+} // namespace bluetooth
diff --git a/gd/os/linux_generic/alarm_unittest.cc b/gd/os/linux_generic/alarm_unittest.cc
new file mode 100644
index 0000000..3ffd0d9
--- /dev/null
+++ b/gd/os/linux_generic/alarm_unittest.cc
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2019 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 "os/alarm.h"
+
+#include <future>
+
+#include "gtest/gtest.h"
+
+namespace bluetooth {
+namespace os {
+namespace {
+
+class AlarmTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ thread_ = new Thread("test_thread", Thread::Priority::NORMAL);
+ alarm_ = new Alarm(thread_);
+ }
+
+ void TearDown() override {
+ delete alarm_;
+ delete thread_;
+ }
+ Alarm* alarm_;
+
+ private:
+ Thread* thread_;
+};
+
+TEST_F(AlarmTest, cancel_while_not_armed) {
+ alarm_->Cancel();
+}
+
+TEST_F(AlarmTest, schedule) {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ auto before = std::chrono::steady_clock::now();
+ int delay_ms = 10;
+ int delay_error_ms = 3;
+ alarm_->Schedule([&promise]() { promise.set_value(); }, std::chrono::milliseconds(delay_ms));
+ future.get();
+ auto after = std::chrono::steady_clock::now();
+ auto duration_ms = std::chrono::duration_cast<std::chrono::milliseconds>(after - before);
+ ASSERT_NEAR(duration_ms.count(), delay_ms, delay_error_ms);
+}
+
+TEST_F(AlarmTest, cancel_alarm) {
+ alarm_->Schedule([]() { ASSERT_TRUE(false) << "Should not happen"; }, std::chrono::milliseconds(3));
+ alarm_->Cancel();
+ std::this_thread::sleep_for(std::chrono::milliseconds(5));
+}
+
+TEST_F(AlarmTest, cancel_alarm_from_callback) {
+ alarm_->Schedule([this]() { this->alarm_->Cancel(); }, std::chrono::milliseconds(1));
+ std::this_thread::sleep_for(std::chrono::milliseconds(5));
+}
+
+TEST_F(AlarmTest, schedule_while_alarm_armed) {
+ alarm_->Schedule([]() { ASSERT_TRUE(false) << "Should not happen"; }, std::chrono::milliseconds(1));
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ alarm_->Schedule([&promise]() { promise.set_value(); }, std::chrono::milliseconds(10));
+ future.get();
+}
+
+TEST_F(AlarmTest, delete_while_alarm_armed) {
+ alarm_->Schedule([]() { ASSERT_TRUE(false) << "Should not happen"; }, std::chrono::milliseconds(1));
+ delete alarm_;
+ alarm_ = nullptr;
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+}
+
+} // namespace
+} // namespace os
+} // namespace bluetooth
diff --git a/gd/os/linux_generic/handler.cc b/gd/os/linux_generic/handler.cc
new file mode 100644
index 0000000..5d5fbed
--- /dev/null
+++ b/gd/os/linux_generic/handler.cc
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2019 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 "os/handler.h"
+
+#include <sys/eventfd.h>
+#include <cstring>
+#include <unistd.h>
+
+#include "os/log.h"
+#include "os/reactor.h"
+#include "os/utils.h"
+
+#ifndef EFD_SEMAPHORE
+#define EFD_SEMAPHORE 1
+#endif
+
+namespace bluetooth {
+namespace os {
+
+Handler::Handler(Thread* thread) : thread_(thread), fd_(eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK)) {
+ ASSERT(fd_ != -1);
+
+ reactable_ = thread_->GetReactor()->Register(fd_, [this] { this->handle_next_event(); }, nullptr);
+}
+
+Handler::~Handler() {
+ thread_->GetReactor()->Unregister(reactable_);
+ reactable_ = nullptr;
+
+ int close_status;
+ RUN_NO_INTR(close_status = close(fd_));
+ ASSERT(close_status != -1);
+}
+
+void Handler::Post(Closure closure) {
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ tasks_.emplace(std::move(closure));
+ }
+ uint64_t val = 1;
+ auto write_result = eventfd_write(fd_, val);
+ ASSERT(write_result != -1);
+}
+
+void Handler::Clear() {
+ std::lock_guard<std::mutex> lock(mutex_);
+
+ std::queue<Closure> empty;
+ std::swap(tasks_, empty);
+
+ uint64_t val;
+ while (eventfd_read(fd_, &val) == 0) {
+ }
+}
+
+void Handler::handle_next_event() {
+ Closure closure;
+ uint64_t val = 0;
+ auto read_result = eventfd_read(fd_, &val);
+ if (read_result == -1 && errno == EAGAIN) {
+ // We were told there was an item, but it was removed before we got there
+ // (aka the queue was cleared). Not a fatal error, so just bail.
+ return;
+ }
+
+ ASSERT(read_result != -1);
+
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ closure = std::move(tasks_.front());
+ tasks_.pop();
+ }
+ closure();
+}
+
+} // namespace os
+} // namespace bluetooth
diff --git a/gd/os/linux_generic/handler_unittest.cc b/gd/os/linux_generic/handler_unittest.cc
new file mode 100644
index 0000000..7e0488f
--- /dev/null
+++ b/gd/os/linux_generic/handler_unittest.cc
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2019 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 "os/handler.h"
+
+#include <sys/eventfd.h>
+#include <thread>
+
+#include "gtest/gtest.h"
+
+namespace bluetooth {
+namespace os {
+namespace {
+
+class HandlerTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ thread_ = new Thread("test_thread", Thread::Priority::NORMAL);
+ handler_ = new Handler(thread_);
+ }
+ void TearDown() override {
+ delete handler_;
+ delete thread_;
+ }
+
+ Handler* handler_;
+ Thread* thread_;
+};
+
+TEST_F(HandlerTest, empty) {}
+
+TEST_F(HandlerTest, post_task_invoked) {
+ int val = 0;
+ Closure closure = [&val]() { val++; };
+ handler_->Post(closure);
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ EXPECT_EQ(val, 1);
+}
+
+TEST_F(HandlerTest, post_task_cleared) {
+ int val = 0;
+ Closure closure = [&val]() {
+ val++;
+ std::this_thread::sleep_for(std::chrono::milliseconds(5));
+ };
+ handler_->Post(std::move(closure));
+ closure = []() {
+ ASSERT_TRUE(false);
+ };
+ std::this_thread::sleep_for(std::chrono::milliseconds(5));
+ handler_->Post(std::move(closure));
+ handler_->Clear();
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ EXPECT_EQ(val, 1);
+}
+
+} // namespace
+} // namespace os
+} // namespace bluetooth
diff --git a/gd/os/linux_generic/linux.h b/gd/os/linux_generic/linux.h
new file mode 100644
index 0000000..524aa7d
--- /dev/null
+++ b/gd/os/linux_generic/linux.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2019 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
+
+#ifndef EFD_SEMAPHORE
+#define EFD_SEMAPHORE 1
+#endif
diff --git a/gd/os/linux_generic/queue.tpp b/gd/os/linux_generic/queue.tpp
new file mode 100644
index 0000000..0993105
--- /dev/null
+++ b/gd/os/linux_generic/queue.tpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2019 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.
+ */
+
+template <typename T>
+Queue<T>::Queue(size_t capacity) : enqueue_(capacity), dequeue_(0){};
+
+template <typename T>
+Queue<T>::~Queue() {
+ ASSERT(enqueue_.handler_ == nullptr);
+ ASSERT(dequeue_.handler_ == nullptr);
+};
+
+template <typename T>
+void Queue<T>::RegisterEnqueue(Handler* handler, EnqueueCallback callback) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ ASSERT(enqueue_.handler_ == nullptr);
+ ASSERT(enqueue_.reactable_ == nullptr);
+ enqueue_.handler_ = handler;
+ enqueue_.reactable_ = enqueue_.handler_->thread_->GetReactor()->Register(
+ enqueue_.reactive_semaphore_.GetFd(), [this, callback] { EnqueueCallbackInternal(callback); }, nullptr);
+}
+
+template <typename T>
+void Queue<T>::UnregisterEnqueue() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ ASSERT(enqueue_.reactable_ != nullptr);
+ enqueue_.handler_->thread_->GetReactor()->Unregister(enqueue_.reactable_);
+ enqueue_.reactable_ = nullptr;
+ enqueue_.handler_ = nullptr;
+}
+
+template <typename T>
+void Queue<T>::RegisterDequeue(Handler* handler, DequeueCallback callback) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ ASSERT(dequeue_.handler_ == nullptr);
+ ASSERT(dequeue_.reactable_ == nullptr);
+ dequeue_.handler_ = handler;
+ dequeue_.reactable_ = dequeue_.handler_->thread_->GetReactor()->Register(dequeue_.reactive_semaphore_.GetFd(),
+ [callback] { callback(); }, nullptr);
+}
+
+template <typename T>
+void Queue<T>::UnregisterDequeue() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ ASSERT(dequeue_.reactable_ != nullptr);
+ dequeue_.handler_->thread_->GetReactor()->Unregister(dequeue_.reactable_);
+ dequeue_.reactable_ = nullptr;
+ dequeue_.handler_ = nullptr;
+}
+
+template <typename T>
+std::unique_ptr<T> Queue<T>::TryDequeue() {
+ std::lock_guard<std::mutex> lock(mutex_);
+
+ if (queue_.empty()) {
+ return nullptr;
+ }
+
+ dequeue_.reactive_semaphore_.Decrease();
+
+ std::unique_ptr<T> data = std::move(queue_.front());
+ queue_.pop();
+
+ enqueue_.reactive_semaphore_.Increase();
+
+ return data;
+}
+
+template <typename T>
+void Queue<T>::EnqueueCallbackInternal(EnqueueCallback callback) {
+ std::unique_ptr<T> data = callback();
+ ASSERT(data != nullptr);
+ std::lock_guard<std::mutex> lock(mutex_);
+ enqueue_.reactive_semaphore_.Decrease();
+ queue_.push(std::move(data));
+ dequeue_.reactive_semaphore_.Increase();
+}
diff --git a/gd/os/linux_generic/queue_unittest.cc b/gd/os/linux_generic/queue_unittest.cc
new file mode 100644
index 0000000..4fe9bd9
--- /dev/null
+++ b/gd/os/linux_generic/queue_unittest.cc
@@ -0,0 +1,729 @@
+/*
+ * Copyright 2019 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 "os/queue.h"
+
+#include <sys/eventfd.h>
+#include <future>
+#include <unordered_map>
+
+#include "gtest/gtest.h"
+#include "os/reactor.h"
+
+namespace bluetooth {
+namespace os {
+namespace {
+
+constexpr int kQueueSize = 10;
+constexpr int kHalfOfQueueSize = kQueueSize / 2;
+constexpr int kDoubleOfQueueSize = kQueueSize * 2;
+constexpr int kQueueSizeOne = 1;
+
+class QueueTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ enqueue_thread_ = new Thread("enqueue_thread", Thread::Priority::NORMAL);
+ enqueue_handler_ = new Handler(enqueue_thread_);
+ dequeue_thread_ = new Thread("dequeue_thread", Thread::Priority::NORMAL);
+ dequeue_handler_ = new Handler(dequeue_thread_);
+ }
+ void TearDown() override {
+ delete enqueue_handler_;
+ delete enqueue_thread_;
+ delete dequeue_handler_;
+ delete dequeue_thread_;
+ enqueue_handler_ = nullptr;
+ enqueue_thread_ = nullptr;
+ dequeue_handler_ = nullptr;
+ dequeue_thread_ = nullptr;
+ }
+
+ Thread* enqueue_thread_;
+ Handler* enqueue_handler_;
+ Thread* dequeue_thread_;
+ Handler* dequeue_handler_;
+};
+
+class TestEnqueueEnd {
+ public:
+ explicit TestEnqueueEnd(Queue<std::string>* queue, Handler* handler)
+ : count(0), handler_(handler), queue_(queue), delay_(0) {}
+
+ ~TestEnqueueEnd() {}
+
+ void RegisterEnqueue(std::unordered_map<int, std::promise<int>>* promise_map) {
+ promise_map_ = promise_map;
+ handler_->Post([this] { queue_->RegisterEnqueue(handler_, [this] { return EnqueueCallbackForTest(); }); });
+ }
+
+ void UnregisterEnqueue() {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+
+ handler_->Post([this, &promise] {
+ queue_->UnregisterEnqueue();
+ promise.set_value();
+ });
+ future.wait();
+ }
+
+ std::unique_ptr<std::string> EnqueueCallbackForTest() {
+ if (delay_ != 0) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(delay_));
+ }
+
+ count++;
+ std::unique_ptr<std::string> data = std::move(buffer_.front());
+ buffer_.pop();
+ std::string copy = *data;
+ if (buffer_.empty()) {
+ queue_->UnregisterEnqueue();
+ }
+
+ auto pair = promise_map_->find(buffer_.size());
+ if (pair != promise_map_->end()) {
+ pair->second.set_value(pair->first);
+ promise_map_->erase(pair->first);
+ }
+ return data;
+ }
+
+ void setDelay(int value) {
+ delay_ = value;
+ }
+
+ std::queue<std::unique_ptr<std::string>> buffer_;
+ int count;
+
+ private:
+ Handler* handler_;
+ Queue<std::string>* queue_;
+ std::unordered_map<int, std::promise<int>>* promise_map_;
+ int delay_;
+};
+
+class TestDequeueEnd {
+ public:
+ explicit TestDequeueEnd(Queue<std::string>* queue, Handler* handler, int capacity)
+ : count(0), handler_(handler), queue_(queue), capacity_(capacity), delay_(0) {}
+
+ ~TestDequeueEnd() {}
+
+ void RegisterDequeue(std::unordered_map<int, std::promise<int>>* promise_map) {
+ promise_map_ = promise_map;
+ handler_->Post([this] { queue_->RegisterDequeue(handler_, [this] { DequeueCallbackForTest(); }); });
+ }
+
+ void UnregisterDequeue() {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+
+ handler_->Post([this, &promise] {
+ queue_->UnregisterDequeue();
+ promise.set_value();
+ });
+ future.wait();
+ }
+
+ void DequeueCallbackForTest() {
+ if (delay_ != 0) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(delay_));
+ }
+
+ count++;
+ std::unique_ptr<std::string> data = queue_->TryDequeue();
+ buffer_.push(std::move(data));
+
+ if (buffer_.size() == capacity_) {
+ queue_->UnregisterDequeue();
+ }
+
+ auto pair = promise_map_->find(buffer_.size());
+ if (pair != promise_map_->end()) {
+ pair->second.set_value(pair->first);
+ promise_map_->erase(pair->first);
+ }
+ }
+
+ void setDelay(int value) {
+ delay_ = value;
+ }
+
+ std::queue<std::unique_ptr<std::string>> buffer_;
+ int count;
+
+ private:
+ Handler* handler_;
+ Queue<std::string>* queue_;
+ std::unordered_map<int, std::promise<int>>* promise_map_;
+ int capacity_;
+ int delay_;
+};
+
+// Enqueue end level : 0 -> queue is full, 1 - > queue isn't full
+// Dequeue end level : 0 -> queue is empty, 1 - > queue isn't empty
+
+// Test 1 : Queue is empty
+
+// Enqueue end level : 1
+// Dequeue end level : 0
+// Test 1-1 EnqueueCallback should continually be invoked when queue isn't full
+TEST_F(QueueTest, register_enqueue_with_empty_queue) {
+ Queue<std::string> queue(kQueueSize);
+ TestEnqueueEnd test_enqueue_end(&queue, enqueue_handler_);
+
+ // Push kQueueSize data to enqueue_end buffer
+ for (int i = 0; i < kQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+ EXPECT_EQ(test_enqueue_end.buffer_.size(), (size_t)kQueueSize);
+
+ // Register enqueue and expect data move to Queue
+ std::unordered_map<int, std::promise<int>> enqueue_promise_map;
+ enqueue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(0), std::forward_as_tuple());
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+ auto enqueue_future = enqueue_promise_map[0].get_future();
+ enqueue_future.wait();
+ EXPECT_EQ(enqueue_future.get(), 0);
+ std::this_thread::sleep_for(std::chrono::milliseconds(20));
+}
+
+// Enqueue end level : 1
+// Dequeue end level : 0
+// Test 1-2 DequeueCallback shouldn't be invoked when queue is empty
+TEST_F(QueueTest, register_dequeue_with_empty_queue) {
+ Queue<std::string> queue(kQueueSize);
+ TestDequeueEnd test_dequeue_end(&queue, dequeue_handler_, kQueueSize);
+
+ // Register dequeue, DequeueCallback shouldn't be invoked
+ std::unordered_map<int, std::promise<int>> dequeue_promise_map;
+ test_dequeue_end.RegisterDequeue(&dequeue_promise_map);
+ std::this_thread::sleep_for(std::chrono::milliseconds(20));
+ EXPECT_EQ(test_dequeue_end.count, 0);
+
+ test_dequeue_end.UnregisterDequeue();
+}
+
+// Test 2 : Queue is full
+
+// Enqueue end level : 0
+// Dequeue end level : 1
+// Test 2-1 EnqueueCallback shouldn't be invoked when queue is full
+TEST_F(QueueTest, register_enqueue_with_full_queue) {
+ Queue<std::string> queue(kQueueSize);
+ TestEnqueueEnd test_enqueue_end(&queue, enqueue_handler_);
+
+ // make Queue full
+ for (int i = 0; i < kQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+ std::unordered_map<int, std::promise<int>> enqueue_promise_map;
+ enqueue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(0), std::forward_as_tuple());
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+ auto enqueue_future = enqueue_promise_map[0].get_future();
+ enqueue_future.wait();
+ EXPECT_EQ(enqueue_future.get(), 0);
+
+ // push some data to enqueue_end buffer and register enqueue;
+ for (int i = 0; i < kHalfOfQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+
+ // EnqueueCallback shouldn't be invoked
+ std::this_thread::sleep_for(std::chrono::milliseconds(20));
+ EXPECT_EQ(test_enqueue_end.buffer_.size(), (size_t)kHalfOfQueueSize);
+ EXPECT_EQ(test_enqueue_end.count, kQueueSize);
+
+ test_enqueue_end.UnregisterEnqueue();
+}
+
+// Enqueue end level : 0
+// Dequeue end level : 1
+// Test 2-2 DequeueCallback should continually be invoked when queue isn't empty
+TEST_F(QueueTest, register_dequeue_with_full_queue) {
+ Queue<std::string> queue(kQueueSize);
+ TestEnqueueEnd test_enqueue_end(&queue, enqueue_handler_);
+ TestDequeueEnd test_dequeue_end(&queue, dequeue_handler_, kDoubleOfQueueSize);
+
+ // make Queue full
+ for (int i = 0; i < kQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+ std::unordered_map<int, std::promise<int>> enqueue_promise_map;
+ enqueue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(0), std::forward_as_tuple());
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+ auto enqueue_future = enqueue_promise_map[0].get_future();
+ enqueue_future.wait();
+ EXPECT_EQ(enqueue_future.get(), 0);
+
+ // Register dequeue and expect data move to dequeue end buffer
+ std::unordered_map<int, std::promise<int>> dequeue_promise_map;
+ dequeue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(kQueueSize), std::forward_as_tuple());
+ test_dequeue_end.RegisterDequeue(&dequeue_promise_map);
+ auto dequeue_future = dequeue_promise_map[kQueueSize].get_future();
+ dequeue_future.wait();
+ EXPECT_EQ(dequeue_future.get(), kQueueSize);
+
+ test_dequeue_end.UnregisterDequeue();
+}
+
+// Test 3 : Queue is non-empty and non-full
+
+// Enqueue end level : 1
+// Dequeue end level : 1
+// Test 3-1 Register enqueue with half empty queue, EnqueueCallback should continually be invoked
+TEST_F(QueueTest, register_enqueue_with_half_empty_queue) {
+ Queue<std::string> queue(kQueueSize);
+ TestEnqueueEnd test_enqueue_end(&queue, enqueue_handler_);
+
+ // make Queue half empty
+ for (int i = 0; i < kHalfOfQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+ std::unordered_map<int, std::promise<int>> enqueue_promise_map;
+ enqueue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(0), std::forward_as_tuple());
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+ auto enqueue_future = enqueue_promise_map[0].get_future();
+ enqueue_future.wait();
+ EXPECT_EQ(enqueue_future.get(), 0);
+
+ // push some data to enqueue_end buffer and register enqueue;
+ for (int i = 0; i < kHalfOfQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+
+ // Register enqueue and expect data move to Queue
+ enqueue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(0), std::forward_as_tuple());
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+ enqueue_future = enqueue_promise_map[0].get_future();
+ enqueue_future.wait();
+ EXPECT_EQ(enqueue_future.get(), 0);
+}
+
+// Enqueue end level : 1
+// Dequeue end level : 1
+// Test 3-2 Register dequeue with half empty queue, DequeueCallback should continually be invoked
+TEST_F(QueueTest, register_dequeue_with_half_empty_queue) {
+ Queue<std::string> queue(kQueueSize);
+ TestEnqueueEnd test_enqueue_end(&queue, enqueue_handler_);
+ TestDequeueEnd test_dequeue_end(&queue, dequeue_handler_, kQueueSize);
+
+ // make Queue half empty
+ for (int i = 0; i < kHalfOfQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+ std::unordered_map<int, std::promise<int>> enqueue_promise_map;
+ enqueue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(0), std::forward_as_tuple());
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+ auto enqueue_future = enqueue_promise_map[0].get_future();
+ enqueue_future.wait();
+ EXPECT_EQ(enqueue_future.get(), 0);
+
+ // Register dequeue and expect data move to dequeue end buffer
+ std::unordered_map<int, std::promise<int>> dequeue_promise_map;
+ dequeue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(kHalfOfQueueSize),
+ std::forward_as_tuple());
+ test_dequeue_end.RegisterDequeue(&dequeue_promise_map);
+ auto dequeue_future = dequeue_promise_map[kHalfOfQueueSize].get_future();
+ dequeue_future.wait();
+ EXPECT_EQ(dequeue_future.get(), kHalfOfQueueSize);
+
+ test_dequeue_end.UnregisterDequeue();
+}
+
+// Dynamic level test
+
+// Test 4 : Queue becomes full during test, EnqueueCallback should stop to be invoked
+
+// Enqueue end level : 1 -> 0
+// Dequeue end level : 1
+// Test 4-1 Queue becomes full due to only register EnqueueCallback
+TEST_F(QueueTest, queue_becomes_full_enqueue_callback_only) {
+ Queue<std::string> queue(kQueueSize);
+ TestEnqueueEnd test_enqueue_end(&queue, enqueue_handler_);
+
+ // push double of kQueueSize to enqueue end buffer
+ for (int i = 0; i < kDoubleOfQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+
+ // Register enqueue and expect kQueueSize data move to Queue
+ std::unordered_map<int, std::promise<int>> enqueue_promise_map;
+ enqueue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(kQueueSize), std::forward_as_tuple());
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+ auto enqueue_future = enqueue_promise_map[kQueueSize].get_future();
+ enqueue_future.wait();
+ EXPECT_EQ(enqueue_future.get(), kQueueSize);
+
+ // EnqueueCallback shouldn't be invoked and buffer size stay in kQueueSize
+ std::this_thread::sleep_for(std::chrono::milliseconds(20));
+ EXPECT_EQ(test_enqueue_end.buffer_.size(), (size_t)kQueueSize);
+ EXPECT_EQ(test_enqueue_end.count, kQueueSize);
+
+ test_enqueue_end.UnregisterEnqueue();
+}
+
+// Enqueue end level : 1 -> 0
+// Dequeue end level : 1
+// Test 4-2 Queue becomes full due to DequeueCallback unregister during test
+TEST_F(QueueTest, queue_becomes_full_dequeue_callback_unregister) {
+ Queue<std::string> queue(kQueueSize);
+ TestEnqueueEnd test_enqueue_end(&queue, enqueue_handler_);
+ TestDequeueEnd test_dequeue_end(&queue, dequeue_handler_, kHalfOfQueueSize);
+
+ // push double of kQueueSize to enqueue end buffer
+ for (int i = 0; i < kDoubleOfQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+
+ // Register dequeue
+ std::unordered_map<int, std::promise<int>> dequeue_promise_map;
+ dequeue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(kHalfOfQueueSize),
+ std::forward_as_tuple());
+ test_dequeue_end.RegisterDequeue(&dequeue_promise_map);
+ auto dequeue_future = dequeue_promise_map[kHalfOfQueueSize].get_future();
+
+ // Register enqueue
+ std::unordered_map<int, std::promise<int>> enqueue_promise_map;
+ enqueue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(kHalfOfQueueSize),
+ std::forward_as_tuple());
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+ auto enqueue_future = enqueue_promise_map[kHalfOfQueueSize].get_future();
+
+ // Dequeue end will unregister when buffer size is kHalfOfQueueSize
+ dequeue_future.wait();
+ EXPECT_EQ(dequeue_future.get(), kHalfOfQueueSize);
+
+ // EnqueueCallback shouldn't be invoked and buffer size stay in kHalfOfQueueSize
+ enqueue_future.wait();
+ EXPECT_EQ(enqueue_future.get(), kHalfOfQueueSize);
+ std::this_thread::sleep_for(std::chrono::milliseconds(20));
+ EXPECT_EQ(test_enqueue_end.buffer_.size(), (size_t)kHalfOfQueueSize);
+ EXPECT_EQ(test_enqueue_end.count, kQueueSize + kHalfOfQueueSize);
+
+ test_enqueue_end.UnregisterEnqueue();
+}
+
+// Enqueue end level : 1 -> 0
+// Dequeue end level : 1
+// Test 4-3 Queue becomes full due to DequeueCallback is slower
+TEST_F(QueueTest, queue_becomes_full_dequeue_callback_slower) {
+ Queue<std::string> queue(kQueueSize);
+ TestEnqueueEnd test_enqueue_end(&queue, enqueue_handler_);
+ TestDequeueEnd test_dequeue_end(&queue, dequeue_handler_, kDoubleOfQueueSize);
+
+ // push double of kDoubleOfQueueSize to enqueue end buffer
+ for (int i = 0; i < kDoubleOfQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+
+ // Set 20 ms delay for callback and register dequeue
+ std::unordered_map<int, std::promise<int>> dequeue_promise_map;
+ test_dequeue_end.setDelay(20);
+ test_dequeue_end.RegisterDequeue(&dequeue_promise_map);
+ auto dequeue_future = dequeue_promise_map[kHalfOfQueueSize].get_future();
+
+ // Register enqueue
+ std::unordered_map<int, std::promise<int>> enqueue_promise_map;
+ enqueue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(0), std::forward_as_tuple());
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+ auto enqueue_future = enqueue_promise_map[0].get_future();
+
+ // Wait for enqueue buffer empty and expect queue is full
+ enqueue_future.wait();
+ EXPECT_EQ(enqueue_future.get(), 0);
+ EXPECT_EQ(test_dequeue_end.buffer_.size(), kQueueSize);
+
+ test_dequeue_end.UnregisterDequeue();
+}
+
+// Enqueue end level : 0 -> 1
+// Dequeue end level : 1 -> 0
+// Test 5 Queue becomes full and non empty at same time.
+TEST_F(QueueTest, queue_becomes_full_and_non_empty_at_same_time) {
+ Queue<std::string> queue(kQueueSizeOne);
+ TestEnqueueEnd test_enqueue_end(&queue, enqueue_handler_);
+ TestDequeueEnd test_dequeue_end(&queue, dequeue_handler_, kDoubleOfQueueSize);
+
+ // push double of kQueueSize to enqueue end buffer
+ for (int i = 0; i < kQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+
+ // Register dequeue
+ std::unordered_map<int, std::promise<int>> dequeue_promise_map;
+ dequeue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(kQueueSize), std::forward_as_tuple());
+ test_dequeue_end.RegisterDequeue(&dequeue_promise_map);
+ auto dequeue_future = dequeue_promise_map[kQueueSize].get_future();
+
+ // Register enqueue
+ std::unordered_map<int, std::promise<int>> enqueue_promise_map;
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+ auto enqueue_future = enqueue_promise_map[0].get_future();
+
+ // Wait for all data move from enqueue end buffer to dequeue end buffer
+ dequeue_future.wait();
+ EXPECT_EQ(dequeue_future.get(), kQueueSize);
+
+ test_dequeue_end.UnregisterDequeue();
+}
+
+// Enqueue end level : 1 -> 0
+// Dequeue end level : 1
+// Test 6 Queue becomes not full during test, EnqueueCallback should start to be invoked
+TEST_F(QueueTest, queue_becomes_non_full_during_test) {
+ Queue<std::string> queue(kQueueSize);
+ TestEnqueueEnd test_enqueue_end(&queue, enqueue_handler_);
+ TestDequeueEnd test_dequeue_end(&queue, dequeue_handler_, kQueueSize * 3);
+
+ // make Queue full
+ for (int i = 0; i < kDoubleOfQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+ std::unordered_map<int, std::promise<int>> enqueue_promise_map;
+ enqueue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(kQueueSize), std::forward_as_tuple());
+ enqueue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(0), std::forward_as_tuple());
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+ auto enqueue_future = enqueue_promise_map[kQueueSize].get_future();
+ enqueue_future.wait();
+ EXPECT_EQ(enqueue_future.get(), kQueueSize);
+
+ // Expect kQueueSize data block in enqueue end buffer
+ std::this_thread::sleep_for(std::chrono::milliseconds(20));
+ EXPECT_EQ(test_enqueue_end.buffer_.size(), kQueueSize);
+
+ // Register dequeue
+ std::unordered_map<int, std::promise<int>> dequeue_promise_map;
+ test_dequeue_end.RegisterDequeue(&dequeue_promise_map);
+
+ // Expect enqueue end will empty
+ enqueue_future = enqueue_promise_map[0].get_future();
+ enqueue_future.wait();
+ EXPECT_EQ(enqueue_future.get(), 0);
+
+ test_dequeue_end.UnregisterDequeue();
+}
+
+// Enqueue end level : 0 -> 1
+// Dequeue end level : 1 -> 0
+// Test 7 Queue becomes non full and empty at same time. (Exactly same as Test 5)
+TEST_F(QueueTest, queue_becomes_non_full_and_empty_at_same_time) {
+ Queue<std::string> queue(kQueueSizeOne);
+ TestEnqueueEnd test_enqueue_end(&queue, enqueue_handler_);
+ TestDequeueEnd test_dequeue_end(&queue, dequeue_handler_, kDoubleOfQueueSize);
+
+ // push double of kQueueSize to enqueue end buffer
+ for (int i = 0; i < kQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+
+ // Register dequeue
+ std::unordered_map<int, std::promise<int>> dequeue_promise_map;
+ dequeue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(kQueueSize), std::forward_as_tuple());
+ test_dequeue_end.RegisterDequeue(&dequeue_promise_map);
+ auto dequeue_future = dequeue_promise_map[kQueueSize].get_future();
+
+ // Register enqueue
+ std::unordered_map<int, std::promise<int>> enqueue_promise_map;
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+ auto enqueue_future = enqueue_promise_map[0].get_future();
+
+ // Wait for all data move from enqueue end buffer to dequeue end buffer
+ dequeue_future.wait();
+ EXPECT_EQ(dequeue_future.get(), kQueueSize);
+
+ test_dequeue_end.UnregisterDequeue();
+}
+
+// Test 8 : Queue becomes empty during test, DequeueCallback should stop to be invoked
+
+// Enqueue end level : 1
+// Dequeue end level : 1 -> 0
+// Test 8-1 Queue becomes empty due to only register DequeueCallback
+TEST_F(QueueTest, queue_becomes_empty_dequeue_callback_only) {
+ Queue<std::string> queue(kQueueSize);
+ TestEnqueueEnd test_enqueue_end(&queue, enqueue_handler_);
+ TestDequeueEnd test_dequeue_end(&queue, dequeue_handler_, kHalfOfQueueSize);
+
+ // make Queue half empty
+ for (int i = 0; i < kHalfOfQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+ std::unordered_map<int, std::promise<int>> enqueue_promise_map;
+ enqueue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(0), std::forward_as_tuple());
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+ auto enqueue_future = enqueue_promise_map[0].get_future();
+ enqueue_future.wait();
+ EXPECT_EQ(enqueue_future.get(), 0);
+
+ // Register dequeue, expect kHalfOfQueueSize data move to dequeue end buffer
+ std::unordered_map<int, std::promise<int>> dequeue_promise_map;
+ dequeue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(kHalfOfQueueSize),
+ std::forward_as_tuple());
+ test_dequeue_end.RegisterDequeue(&dequeue_promise_map);
+ auto dequeue_future = dequeue_promise_map[kHalfOfQueueSize].get_future();
+ dequeue_future.wait();
+ EXPECT_EQ(dequeue_future.get(), kHalfOfQueueSize);
+
+ // Expect DequeueCallback should stop to be invoked
+ std::this_thread::sleep_for(std::chrono::milliseconds(20));
+ EXPECT_EQ(test_dequeue_end.count, kHalfOfQueueSize);
+}
+
+// Enqueue end level : 1
+// Dequeue end level : 1 -> 0
+// Test 8-2 Queue becomes empty due to EnqueueCallback unregister during test
+TEST_F(QueueTest, queue_becomes_empty_enqueue_callback_unregister) {
+ Queue<std::string> queue(kQueueSize);
+ TestEnqueueEnd test_enqueue_end(&queue, enqueue_handler_);
+ TestDequeueEnd test_dequeue_end(&queue, dequeue_handler_, kQueueSize);
+
+ // make Queue half empty
+ for (int i = 0; i < kHalfOfQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+ std::unordered_map<int, std::promise<int>> enqueue_promise_map;
+ enqueue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(0), std::forward_as_tuple());
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+ auto enqueue_future = enqueue_promise_map[0].get_future();
+ enqueue_future.wait();
+ EXPECT_EQ(enqueue_future.get(), 0);
+
+ // push kHalfOfQueueSize to enqueue end buffer and register enqueue.
+ for (int i = 0; i < kHalfOfQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+
+ // Register dequeue, expect kQueueSize move to dequeue end buffer
+ std::unordered_map<int, std::promise<int>> dequeue_promise_map;
+ dequeue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(kQueueSize), std::forward_as_tuple());
+ test_dequeue_end.RegisterDequeue(&dequeue_promise_map);
+ auto dequeue_future = dequeue_promise_map[kQueueSize].get_future();
+ dequeue_future.wait();
+ EXPECT_EQ(dequeue_future.get(), kQueueSize);
+
+ // Expect DequeueCallback should stop to be invoked
+ std::this_thread::sleep_for(std::chrono::milliseconds(20));
+ EXPECT_EQ(test_dequeue_end.count, kQueueSize);
+}
+
+// Enqueue end level : 1
+// Dequeue end level : 0 -> 1
+// Test 9 Queue becomes not empty during test, DequeueCallback should start to be invoked
+TEST_F(QueueTest, queue_becomes_non_empty_during_test) {
+ Queue<std::string> queue(kQueueSize);
+ TestEnqueueEnd test_enqueue_end(&queue, enqueue_handler_);
+ TestDequeueEnd test_dequeue_end(&queue, dequeue_handler_, kQueueSize);
+
+ // Register dequeue
+ std::unordered_map<int, std::promise<int>> dequeue_promise_map;
+ dequeue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(kQueueSize), std::forward_as_tuple());
+ test_dequeue_end.RegisterDequeue(&dequeue_promise_map);
+
+ // push kQueueSize data to enqueue end buffer and register enqueue
+ for (int i = 0; i < kQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+ std::unordered_map<int, std::promise<int>> enqueue_promise_map;
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+
+ // Expect kQueueSize data move to dequeue end buffer
+ auto dequeue_future = dequeue_promise_map[kQueueSize].get_future();
+ dequeue_future.wait();
+ EXPECT_EQ(dequeue_future.get(), kQueueSize);
+}
+
+TEST_F(QueueTest, pass_smart_pointer_and_unregister) {
+ Queue<std::string>* queue = new Queue<std::string>(kQueueSize);
+
+ // Enqueue a string
+ std::string valid = "Valid String";
+ std::shared_ptr<std::string> shared = std::make_shared<std::string>(valid);
+ queue->RegisterEnqueue(enqueue_handler_, [queue, shared]() {
+ queue->UnregisterEnqueue();
+ return std::make_unique<std::string>(*shared);
+ });
+
+ // Dequeue the string
+ queue->RegisterDequeue(dequeue_handler_, [queue, valid]() {
+ queue->UnregisterDequeue();
+ auto answer = *queue->TryDequeue();
+ ASSERT_EQ(answer, valid);
+ });
+
+ // Wait for both handlers to finish and delete the Queue
+ std::promise<void> promise;
+ auto future = promise.get_future();
+
+ enqueue_handler_->Post([this, queue, &promise]() {
+ dequeue_handler_->Post([queue, &promise] {
+ delete queue;
+ promise.set_value();
+ });
+ });
+ future.wait();
+}
+
+// Create all threads for death tests in the function that dies
+class QueueDeathTest : public ::testing::Test {
+ public:
+ void RegisterEnqueueAndDelete() {
+ Thread* enqueue_thread = new Thread("enqueue_thread", Thread::Priority::NORMAL);
+ Handler* enqueue_handler = new Handler(enqueue_thread);
+ Queue<std::string>* queue = new Queue<std::string>(kQueueSizeOne);
+ queue->RegisterEnqueue(enqueue_handler,
+ []() { return std::make_unique<std::string>("A string to fill the queue"); });
+ delete queue;
+ }
+
+ void RegisterDequeueAndDelete() {
+ Thread* dequeue_thread = new Thread("dequeue_thread", Thread::Priority::NORMAL);
+ Handler* dequeue_handler = new Handler(dequeue_thread);
+ Queue<std::string>* queue = new Queue<std::string>(kQueueSizeOne);
+ queue->RegisterDequeue(dequeue_handler, [queue]() { queue->TryDequeue(); });
+ delete queue;
+ }
+};
+
+TEST_F(QueueDeathTest, die_if_enqueue_not_unregistered) {
+ EXPECT_DEATH(RegisterEnqueueAndDelete(), "nqueue");
+}
+
+TEST_F(QueueDeathTest, die_if_dequeue_not_unregistered) {
+ EXPECT_DEATH(RegisterDequeueAndDelete(), "equeue");
+}
+} // namespace
+} // namespace os
+} // namespace bluetooth
diff --git a/gd/os/linux_generic/reactive_semaphore.cc b/gd/os/linux_generic/reactive_semaphore.cc
new file mode 100644
index 0000000..4cc0b4c
--- /dev/null
+++ b/gd/os/linux_generic/reactive_semaphore.cc
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2019 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 "reactive_semaphore.h"
+
+#include <sys/eventfd.h>
+#include <unistd.h>
+#include <functional>
+
+#include "os/linux_generic/linux.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace os {
+
+ReactiveSemaphore::ReactiveSemaphore(unsigned int value) : fd_(eventfd(value, EFD_SEMAPHORE | EFD_NONBLOCK)) {
+ ASSERT(fd_ != -1);
+}
+
+ReactiveSemaphore::~ReactiveSemaphore() {
+ int close_status;
+ RUN_NO_INTR(close_status = close(fd_));
+ ASSERT(close_status != -1);
+}
+
+void ReactiveSemaphore::Decrease() {
+ uint64_t val = 0;
+ auto read_result = eventfd_read(fd_, &val);
+ ASSERT(read_result != -1);
+}
+
+void ReactiveSemaphore::Increase() {
+ uint64_t val = 1;
+ auto write_result = eventfd_write(fd_, val);
+ ASSERT(write_result != -1);
+}
+
+int ReactiveSemaphore::GetFd() {
+ return fd_;
+}
+
+} // namespace os
+} // namespace bluetooth
diff --git a/gd/os/linux_generic/reactive_semaphore.h b/gd/os/linux_generic/reactive_semaphore.h
new file mode 100644
index 0000000..718666c
--- /dev/null
+++ b/gd/os/linux_generic/reactive_semaphore.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019 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 "os/utils.h"
+
+namespace bluetooth {
+namespace os {
+
+// A event_fd work in non-blocking and Semaphore mode
+class ReactiveSemaphore {
+ public:
+ // Creates a new ReactiveSemaphore with an initial value of |value|.
+ explicit ReactiveSemaphore(unsigned int value);
+ ~ReactiveSemaphore();
+ // Decrements the value of |fd_|, this will cause a crash if |fd_| unreadable.
+ void Decrease();
+ // Increase the value of |fd_|, this will cause a crash if |fd_| unwritable.
+ void Increase();
+ int GetFd();
+
+ DISALLOW_COPY_AND_ASSIGN(ReactiveSemaphore);
+
+ private:
+ int fd_;
+};
+
+} // namespace os
+} // namespace bluetooth
diff --git a/gd/os/linux_generic/reactor.cc b/gd/os/linux_generic/reactor.cc
new file mode 100644
index 0000000..5a52fdb
--- /dev/null
+++ b/gd/os/linux_generic/reactor.cc
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2019 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 "os/reactor.h"
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
+#include <unistd.h>
+#include <algorithm>
+#include <cerrno>
+#include <cstring>
+
+#include "os/log.h"
+
+namespace {
+
+// Use at most sizeof(epoll_event) * kEpollMaxEvents kernel memory
+constexpr int kEpollMaxEvents = 64;
+
+} // namespace
+
+namespace bluetooth {
+namespace os {
+
+class Reactor::Reactable {
+ public:
+ Reactable(int fd, Closure on_read_ready, Closure on_write_ready)
+ : fd_(fd),
+ on_read_ready_(std::move(on_read_ready)),
+ on_write_ready_(std::move(on_write_ready)),
+ is_executing_(false) {}
+ const int fd_;
+ Closure on_read_ready_;
+ Closure on_write_ready_;
+ bool is_executing_;
+ std::recursive_mutex lock_;
+};
+
+Reactor::Reactor()
+ : epoll_fd_(0),
+ control_fd_(0),
+ is_running_(false),
+ reactable_removed_(false) {
+ RUN_NO_INTR(epoll_fd_ = epoll_create1(EPOLL_CLOEXEC));
+ ASSERT_LOG(epoll_fd_ != -1, "could not create epoll fd: %s", strerror(errno));
+
+ control_fd_ = eventfd(0, EFD_NONBLOCK);
+ ASSERT(control_fd_ != -1);
+
+ epoll_event control_epoll_event = {EPOLLIN, {.ptr = nullptr}};
+ int result;
+ RUN_NO_INTR(result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, control_fd_, &control_epoll_event));
+ ASSERT(result != -1);
+}
+
+Reactor::~Reactor() {
+ int result;
+ RUN_NO_INTR(result = epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, control_fd_, nullptr));
+ ASSERT(result != -1);
+
+ RUN_NO_INTR(result = close(control_fd_));
+ ASSERT(result != -1);
+
+ RUN_NO_INTR(result = close(epoll_fd_));
+ ASSERT(result != -1);
+}
+
+void Reactor::Run() {
+ bool previously_running = is_running_.exchange(true);
+ ASSERT(!previously_running);
+
+ for (;;) {
+ {
+ std::unique_lock<std::mutex> lock(mutex_);
+ invalidation_list_.clear();
+ }
+ epoll_event events[kEpollMaxEvents];
+ int count;
+ RUN_NO_INTR(count = epoll_wait(epoll_fd_, events, kEpollMaxEvents, -1));
+ ASSERT(count != -1);
+
+ for (int i = 0; i < count; ++i) {
+ auto event = events[i];
+ ASSERT(event.events != 0u);
+
+ // If the ptr stored in epoll_event.data is nullptr, it means the control fd triggered
+ if (event.data.ptr == nullptr) {
+ uint64_t value;
+ eventfd_read(control_fd_, &value);
+ is_running_ = false;
+ return;
+ }
+ auto* reactable = static_cast<Reactor::Reactable*>(event.data.ptr);
+ {
+ std::unique_lock<std::mutex> lock(mutex_);
+ // See if this reactable has been removed in the meantime.
+ if (std::find(invalidation_list_.begin(), invalidation_list_.end(), reactable) != invalidation_list_.end()) {
+ continue;
+ }
+
+ std::lock_guard<std::recursive_mutex> reactable_lock(reactable->lock_);
+ lock.unlock();
+ reactable_removed_ = false;
+ reactable->is_executing_ = true;
+ if (event.events & (EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR) && reactable->on_read_ready_ != nullptr) {
+ reactable->on_read_ready_();
+ }
+ if (!reactable_removed_ && event.events & EPOLLOUT && reactable->on_write_ready_ != nullptr) {
+ reactable->on_write_ready_();
+ }
+ reactable->is_executing_ = false;
+ }
+ if (reactable_removed_) {
+ delete reactable;
+ reactable_removed_ = false;
+ }
+ }
+ }
+}
+
+void Reactor::Stop() {
+ if (!is_running_) {
+ LOG_WARN("not running, will stop once it's started");
+ }
+ auto control = eventfd_write(control_fd_, 1);
+ ASSERT(control != -1);
+}
+
+Reactor::Reactable* Reactor::Register(int fd, Closure on_read_ready, Closure on_write_ready) {
+ uint32_t poll_event_type = 0;
+ if (on_read_ready != nullptr) {
+ poll_event_type |= (EPOLLIN | EPOLLRDHUP);
+ }
+ if (on_write_ready != nullptr) {
+ poll_event_type |= EPOLLOUT;
+ }
+ auto* reactable = new Reactable(fd, on_read_ready, on_write_ready);
+ epoll_event event = {
+ .events = poll_event_type,
+ {.ptr = reactable}
+ };
+ int register_fd;
+ RUN_NO_INTR(register_fd = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd, &event));
+ ASSERT(register_fd != -1);
+ return reactable;
+}
+
+void Reactor::Unregister(Reactor::Reactable* reactable) {
+ ASSERT(reactable != nullptr);
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ invalidation_list_.push_back(reactable);
+ }
+ bool delaying_delete_until_callback_finished = false;
+ {
+ int result;
+ std::lock_guard<std::recursive_mutex> reactable_lock(reactable->lock_);
+ RUN_NO_INTR(result = epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, reactable->fd_, nullptr));
+ if (result == -1 && errno == ENOENT) {
+ LOG_INFO("reactable is invalid or unregistered");
+ } else {
+ ASSERT(result != -1);
+ }
+
+ // If we are unregistering during the callback event from this reactable, we delete it after the callback is executed.
+ // reactable->is_executing_ is protected by reactable->lock_, so it's thread safe.
+ if (reactable->is_executing_) {
+ reactable_removed_ = true;
+ delaying_delete_until_callback_finished = true;
+ }
+ }
+ // If we are unregistering outside of the callback event from this reactable, we delete it now
+ if (!delaying_delete_until_callback_finished) {
+ delete reactable;
+ }
+}
+
+void Reactor::ModifyRegistration(Reactor::Reactable* reactable, Closure on_read_ready, Closure on_write_ready) {
+ ASSERT(reactable != nullptr);
+
+ uint32_t poll_event_type = 0;
+ if (on_read_ready != nullptr) {
+ poll_event_type |= (EPOLLIN | EPOLLRDHUP);
+ }
+ if (on_write_ready != nullptr) {
+ poll_event_type |= EPOLLOUT;
+ }
+ {
+ std::lock_guard<std::recursive_mutex> reactable_lock(reactable->lock_);
+ reactable->on_read_ready_ = std::move(on_read_ready);
+ reactable->on_write_ready_ = std::move(on_write_ready);
+ }
+ epoll_event event = {
+ .events = poll_event_type,
+ {.ptr = reactable}
+ };
+ int modify_fd;
+ RUN_NO_INTR(modify_fd = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, reactable->fd_, &event));
+ ASSERT(modify_fd != -1);
+}
+
+} // namespace os
+} // namespace bluetooth
diff --git a/gd/os/linux_generic/reactor_unittest.cc b/gd/os/linux_generic/reactor_unittest.cc
new file mode 100644
index 0000000..9143b29
--- /dev/null
+++ b/gd/os/linux_generic/reactor_unittest.cc
@@ -0,0 +1,335 @@
+/*
+ * Copyright 2019 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 "os/reactor.h"
+
+#include <sys/eventfd.h>
+#include <chrono>
+#include <future>
+#include <thread>
+
+#include "gtest/gtest.h"
+
+namespace bluetooth {
+namespace os {
+namespace {
+
+constexpr int kReadReadyValue = 100;
+
+std::promise<int>* g_promise;
+
+class ReactorTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ g_promise = new std::promise<int>;
+ reactor_ = new Reactor;
+ }
+
+ void TearDown() override {
+ delete g_promise;
+ g_promise = nullptr;
+ delete reactor_;
+ reactor_ = nullptr;
+ }
+
+ Reactor* reactor_;
+};
+
+class SampleReactable {
+ public:
+ SampleReactable() : fd_(eventfd(0, EFD_NONBLOCK)) {
+ EXPECT_NE(fd_, -1);
+ }
+
+ ~SampleReactable() {
+ close(fd_);
+ }
+
+ void OnReadReady() {}
+
+ void OnWriteReady() {}
+
+ int fd_;
+};
+
+class FakeReactable {
+ public:
+ enum EventFdValue {
+ kSetPromise = 1,
+ kRegisterSampleReactable,
+ kUnregisterSampleReactable,
+ kSampleOutputValue,
+ };
+ FakeReactable() : fd_(eventfd(0, 0)), reactor_(nullptr) {
+ EXPECT_NE(fd_, -1);
+ }
+
+ FakeReactable(Reactor* reactor) : fd_(eventfd(0, 0)), reactor_(reactor) {
+ EXPECT_NE(fd_, -1);
+ }
+
+ ~FakeReactable() {
+ close(fd_);
+ }
+
+ void OnReadReady() {
+ uint64_t value = 0;
+ auto read_result = eventfd_read(fd_, &value);
+ EXPECT_EQ(read_result, 0);
+ if (value == kSetPromise && g_promise != nullptr) {
+ g_promise->set_value(kReadReadyValue);
+ }
+ if (value == kRegisterSampleReactable) {
+ reactable_ = reactor_->Register(sample_reactable_.fd_, [this] { this->sample_reactable_.OnReadReady(); },
+ [this] { this->sample_reactable_.OnWriteReady(); });
+ g_promise->set_value(kReadReadyValue);
+ }
+ if (value == kUnregisterSampleReactable) {
+ reactor_->Unregister(reactable_);
+ g_promise->set_value(kReadReadyValue);
+ }
+ }
+
+ void OnWriteReady() {
+ auto write_result = eventfd_write(fd_, output_data_);
+ output_data_ = 0;
+ EXPECT_EQ(write_result, 0);
+ }
+
+ void UnregisterInCallback() {
+ uint64_t value = 0;
+ auto read_result = eventfd_read(fd_, &value);
+ EXPECT_EQ(read_result, 0);
+ g_promise->set_value(kReadReadyValue);
+ reactor_->Unregister(reactable_);
+ }
+
+ SampleReactable sample_reactable_;
+ Reactor::Reactable* reactable_ = nullptr;
+ int fd_;
+
+ private:
+ Reactor* reactor_;
+ uint64_t output_data_ = kSampleOutputValue;
+};
+
+TEST_F(ReactorTest, start_and_stop) {
+ auto reactor_thread = std::thread(&Reactor::Run, reactor_);
+ reactor_->Stop();
+ reactor_thread.join();
+}
+
+TEST_F(ReactorTest, stop_and_start) {
+ auto reactor_thread = std::thread(&Reactor::Stop, reactor_);
+ auto another_thread = std::thread(&Reactor::Run, reactor_);
+ reactor_thread.join();
+ another_thread.join();
+}
+
+TEST_F(ReactorTest, stop_multi_times) {
+ auto reactor_thread = std::thread(&Reactor::Run, reactor_);
+ for (int i = 0; i < 5; i++) {
+ reactor_->Stop();
+ }
+ reactor_thread.join();
+}
+
+TEST_F(ReactorTest, cold_register_only) {
+ FakeReactable fake_reactable;
+ auto* reactable =
+ reactor_->Register(fake_reactable.fd_, std::bind(&FakeReactable::OnReadReady, &fake_reactable), nullptr);
+
+ reactor_->Unregister(reactable);
+}
+
+TEST_F(ReactorTest, cold_register) {
+ FakeReactable fake_reactable;
+ auto* reactable =
+ reactor_->Register(fake_reactable.fd_, std::bind(&FakeReactable::OnReadReady, &fake_reactable), nullptr);
+ auto reactor_thread = std::thread(&Reactor::Run, reactor_);
+ auto future = g_promise->get_future();
+
+ auto write_result = eventfd_write(fake_reactable.fd_, FakeReactable::kSetPromise);
+ EXPECT_EQ(write_result, 0);
+ EXPECT_EQ(future.get(), kReadReadyValue);
+ reactor_->Stop();
+ reactor_thread.join();
+ reactor_->Unregister(reactable);
+}
+
+TEST_F(ReactorTest, hot_register_from_different_thread) {
+ auto reactor_thread = std::thread(&Reactor::Run, reactor_);
+ auto future = g_promise->get_future();
+
+ FakeReactable fake_reactable;
+ auto* reactable =
+ reactor_->Register(fake_reactable.fd_, std::bind(&FakeReactable::OnReadReady, &fake_reactable), nullptr);
+ auto write_result = eventfd_write(fake_reactable.fd_, FakeReactable::kSetPromise);
+ EXPECT_EQ(write_result, 0);
+ EXPECT_EQ(future.get(), kReadReadyValue);
+ reactor_->Stop();
+ reactor_thread.join();
+
+ reactor_->Unregister(reactable);
+}
+
+TEST_F(ReactorTest, hot_unregister_from_different_thread) {
+ FakeReactable fake_reactable;
+ auto* reactable =
+ reactor_->Register(fake_reactable.fd_, std::bind(&FakeReactable::OnReadReady, &fake_reactable), nullptr);
+ auto reactor_thread = std::thread(&Reactor::Run, reactor_);
+ reactor_->Unregister(reactable);
+ auto future = g_promise->get_future();
+
+ auto write_result = eventfd_write(fake_reactable.fd_, FakeReactable::kSetPromise);
+ EXPECT_EQ(write_result, 0);
+ future.wait_for(std::chrono::milliseconds(10));
+ g_promise->set_value(2);
+ EXPECT_EQ(future.get(), 2);
+ reactor_->Stop();
+ reactor_thread.join();
+}
+
+TEST_F(ReactorTest, hot_register_from_same_thread) {
+ auto reactor_thread = std::thread(&Reactor::Run, reactor_);
+ auto future = g_promise->get_future();
+
+ FakeReactable fake_reactable(reactor_);
+ auto* reactable =
+ reactor_->Register(fake_reactable.fd_, std::bind(&FakeReactable::OnReadReady, &fake_reactable), nullptr);
+ auto write_result = eventfd_write(fake_reactable.fd_, FakeReactable::kRegisterSampleReactable);
+ EXPECT_EQ(write_result, 0);
+ EXPECT_EQ(future.get(), kReadReadyValue);
+ delete g_promise;
+ g_promise = new std::promise<int>;
+ future = g_promise->get_future();
+ write_result = eventfd_write(fake_reactable.fd_, FakeReactable::kUnregisterSampleReactable);
+ EXPECT_EQ(write_result, 0);
+ reactor_->Stop();
+ reactor_thread.join();
+
+ reactor_->Unregister(reactable);
+}
+
+TEST_F(ReactorTest, hot_unregister_from_same_thread) {
+ auto reactor_thread = std::thread(&Reactor::Run, reactor_);
+ auto future = g_promise->get_future();
+
+ FakeReactable fake_reactable(reactor_);
+ auto* reactable =
+ reactor_->Register(fake_reactable.fd_, std::bind(&FakeReactable::OnReadReady, &fake_reactable), nullptr);
+ auto write_result = eventfd_write(fake_reactable.fd_, FakeReactable::kRegisterSampleReactable);
+ EXPECT_EQ(write_result, 0);
+ EXPECT_EQ(future.get(), kReadReadyValue);
+ delete g_promise;
+ g_promise = new std::promise<int>;
+ future = g_promise->get_future();
+ write_result = eventfd_write(fake_reactable.fd_, FakeReactable::kUnregisterSampleReactable);
+ EXPECT_EQ(write_result, 0);
+ EXPECT_EQ(future.get(), kReadReadyValue);
+ reactor_->Stop();
+ reactor_thread.join();
+
+ reactor_->Unregister(reactable);
+}
+
+TEST_F(ReactorTest, hot_unregister_from_callback) {
+ auto reactor_thread = std::thread(&Reactor::Run, reactor_);
+
+ FakeReactable fake_reactable1(reactor_);
+ auto* reactable1 =
+ reactor_->Register(fake_reactable1.fd_, std::bind(&FakeReactable::OnReadReady, &fake_reactable1), nullptr);
+
+ FakeReactable fake_reactable2(reactor_);
+ auto* reactable2 = reactor_->Register(fake_reactable2.fd_,
+ std::bind(&FakeReactable::UnregisterInCallback, &fake_reactable2), nullptr);
+ fake_reactable2.reactable_ = reactable2;
+ auto write_result = eventfd_write(fake_reactable2.fd_, 1);
+ EXPECT_EQ(write_result, 0);
+ reactor_->Stop();
+ reactor_thread.join();
+
+ reactor_->Unregister(reactable1);
+}
+
+TEST_F(ReactorTest, hot_unregister_during_unregister_from_callback) {
+ auto reactor_thread = std::thread(&Reactor::Run, reactor_);
+ auto future = g_promise->get_future();
+
+ FakeReactable fake_reactable1(reactor_);
+ auto* reactable1 =
+ reactor_->Register(fake_reactable1.fd_, std::bind(&FakeReactable::OnReadReady, &fake_reactable1), nullptr);
+
+ FakeReactable fake_reactable2(reactor_);
+ auto* reactable2 = reactor_->Register(fake_reactable2.fd_,
+ std::bind(&FakeReactable::UnregisterInCallback, &fake_reactable2), nullptr);
+ fake_reactable2.reactable_ = reactable2;
+ auto write_result = eventfd_write(fake_reactable2.fd_, 1);
+ EXPECT_EQ(write_result, 0);
+ EXPECT_EQ(future.get(), kReadReadyValue);
+ reactor_->Unregister(reactable1);
+
+ reactor_->Stop();
+ reactor_thread.join();
+}
+
+TEST_F(ReactorTest, start_and_stop_multi_times) {
+ auto reactor_thread = std::thread(&Reactor::Run, reactor_);
+ reactor_->Stop();
+ reactor_thread.join();
+ for (int i = 0; i < 5; i++) {
+ reactor_thread = std::thread(&Reactor::Run, reactor_);
+ reactor_->Stop();
+ reactor_thread.join();
+ }
+}
+
+TEST_F(ReactorTest, on_write_ready) {
+ FakeReactable fake_reactable;
+ auto* reactable =
+ reactor_->Register(fake_reactable.fd_, nullptr, std::bind(&FakeReactable::OnWriteReady, &fake_reactable));
+ auto reactor_thread = std::thread(&Reactor::Run, reactor_);
+ uint64_t value = 0;
+ auto read_result = eventfd_read(fake_reactable.fd_, &value);
+ EXPECT_EQ(read_result, 0);
+ EXPECT_EQ(value, FakeReactable::kSampleOutputValue);
+
+ reactor_->Stop();
+ reactor_thread.join();
+
+ reactor_->Unregister(reactable);
+}
+
+TEST_F(ReactorTest, modify_registration) {
+ FakeReactable fake_reactable;
+ auto* reactable =
+ reactor_->Register(fake_reactable.fd_, std::bind(&FakeReactable::OnReadReady, &fake_reactable), nullptr);
+ reactor_->ModifyRegistration(reactable, nullptr, std::bind(&FakeReactable::OnWriteReady, &fake_reactable));
+ auto reactor_thread = std::thread(&Reactor::Run, reactor_);
+ uint64_t value = 0;
+ auto read_result = eventfd_read(fake_reactable.fd_, &value);
+ EXPECT_EQ(read_result, 0);
+ EXPECT_EQ(value, FakeReactable::kSampleOutputValue);
+
+ reactor_->Stop();
+ reactor_thread.join();
+
+ reactor_->Unregister(reactable);
+}
+
+} // namespace
+} // namespace os
+} // namespace bluetooth
diff --git a/gd/os/linux_generic/repeating_alarm.cc b/gd/os/linux_generic/repeating_alarm.cc
new file mode 100644
index 0000000..82dde26
--- /dev/null
+++ b/gd/os/linux_generic/repeating_alarm.cc
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2019 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 "os/repeating_alarm.h"
+
+#include <sys/timerfd.h>
+#include <cstring>
+#include <unistd.h>
+
+#include "os/log.h"
+#include "os/utils.h"
+
+#ifdef OS_ANDROID
+#define ALARM_CLOCK CLOCK_BOOTTIME_ALARM
+#else
+#define ALARM_CLOCK CLOCK_BOOTTIME
+#endif
+
+namespace bluetooth {
+namespace os {
+
+RepeatingAlarm::RepeatingAlarm(Thread* thread) : thread_(thread), fd_(timerfd_create(ALARM_CLOCK, 0)) {
+ ASSERT(fd_ != -1);
+
+ token_ = thread_->GetReactor()->Register(fd_, [this] { on_fire(); }, nullptr);
+}
+
+RepeatingAlarm::~RepeatingAlarm() {
+ thread_->GetReactor()->Unregister(token_);
+
+ int close_status;
+ RUN_NO_INTR(close_status = close(fd_));
+ ASSERT(close_status != -1);
+}
+
+void RepeatingAlarm::Schedule(Closure task, std::chrono::milliseconds period) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ long period_ms = period.count();
+ itimerspec timer_itimerspec{
+ {period_ms / 1000, period_ms % 1000 * 1000000},
+ {period_ms / 1000, period_ms % 1000 * 1000000}
+ };
+ int result = timerfd_settime(fd_, 0, &timer_itimerspec, nullptr);
+ ASSERT(result == 0);
+
+ task_ = std::move(task);
+}
+
+void RepeatingAlarm::Cancel() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ itimerspec disarm_itimerspec{/* disarm timer */};
+ int result = timerfd_settime(fd_, 0, &disarm_itimerspec, nullptr);
+ ASSERT(result == 0);
+}
+
+void RepeatingAlarm::on_fire() {
+ std::unique_lock<std::mutex> lock(mutex_);
+ auto task = task_;
+ uint64_t times_invoked;
+ auto bytes_read = read(fd_, ×_invoked, sizeof(uint64_t));
+ lock.unlock();
+ task();
+ ASSERT(bytes_read == static_cast<ssize_t>(sizeof(uint64_t)));
+}
+
+} // namespace os
+} // namespace bluetooth
diff --git a/gd/os/linux_generic/repeating_alarm_unittest.cc b/gd/os/linux_generic/repeating_alarm_unittest.cc
new file mode 100644
index 0000000..a017f66
--- /dev/null
+++ b/gd/os/linux_generic/repeating_alarm_unittest.cc
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2019 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 "os/repeating_alarm.h"
+
+#include <future>
+
+#include "gtest/gtest.h"
+
+namespace bluetooth {
+namespace os {
+namespace {
+
+constexpr int error_ms = 20;
+
+class RepeatingAlarmTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ thread_ = new Thread("test_thread", Thread::Priority::NORMAL);
+ alarm_ = new RepeatingAlarm(thread_);
+ }
+
+ void TearDown() override {
+ delete alarm_;
+ delete thread_;
+ }
+
+ void VerifyMultipleDelayedTasks(int scheduled_tasks, int task_length_ms, int interval_between_tasks_ms) {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ auto start_time = std::chrono::steady_clock::now();
+ int counter = 0;
+ alarm_->Schedule(
+ [&counter, &promise, start_time, scheduled_tasks, task_length_ms, interval_between_tasks_ms]() {
+ counter++;
+ auto time_now = std::chrono::steady_clock::now();
+ auto time_delta = time_now - start_time;
+ if (counter == scheduled_tasks) {
+ promise.set_value();
+ }
+ ASSERT_NEAR(time_delta.count(), interval_between_tasks_ms * 1000000 * counter, error_ms * 1000000);
+ std::this_thread::sleep_for(std::chrono::milliseconds(task_length_ms));
+ },
+ std::chrono::milliseconds(interval_between_tasks_ms));
+ future.get();
+ alarm_->Cancel();
+ }
+
+ RepeatingAlarm* alarm_;
+
+ private:
+ Thread* thread_;
+};
+
+TEST_F(RepeatingAlarmTest, cancel_while_not_armed) {
+ alarm_->Cancel();
+}
+
+TEST_F(RepeatingAlarmTest, schedule) {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ auto before = std::chrono::steady_clock::now();
+ int period_ms = 10;
+ alarm_->Schedule([&promise]() { promise.set_value(); }, std::chrono::milliseconds(period_ms));
+ future.get();
+ alarm_->Cancel();
+ auto after = std::chrono::steady_clock::now();
+ auto duration = after - before;
+ ASSERT_NEAR(duration.count(), period_ms * 1000000, error_ms * 1000000);
+}
+
+TEST_F(RepeatingAlarmTest, cancel_alarm) {
+ alarm_->Schedule([]() { ASSERT_TRUE(false); }, std::chrono::milliseconds(1));
+ alarm_->Cancel();
+ std::this_thread::sleep_for(std::chrono::milliseconds(5));
+}
+
+TEST_F(RepeatingAlarmTest, cancel_alarm_from_callback) {
+ alarm_->Schedule([this]() { this->alarm_->Cancel(); }, std::chrono::milliseconds(1));
+ std::this_thread::sleep_for(std::chrono::milliseconds(5));
+}
+
+TEST_F(RepeatingAlarmTest, schedule_while_alarm_armed) {
+ alarm_->Schedule([]() { ASSERT_TRUE(false); }, std::chrono::milliseconds(1));
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ alarm_->Schedule([&promise]() { promise.set_value(); }, std::chrono::milliseconds(10));
+ future.get();
+ alarm_->Cancel();
+}
+
+TEST_F(RepeatingAlarmTest, delete_while_alarm_armed) {
+ alarm_->Schedule([]() { ASSERT_TRUE(false); }, std::chrono::milliseconds(1));
+ delete alarm_;
+ alarm_ = nullptr;
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
+}
+
+TEST_F(RepeatingAlarmTest, verify_small) {
+ VerifyMultipleDelayedTasks(100, 1, 10);
+}
+
+TEST_F(RepeatingAlarmTest, verify_large) {
+ VerifyMultipleDelayedTasks(100, 3, 10);
+}
+
+} // namespace
+} // namespace os
+} // namespace bluetooth
diff --git a/gd/os/linux_generic/thread.cc b/gd/os/linux_generic/thread.cc
new file mode 100644
index 0000000..c2969fe
--- /dev/null
+++ b/gd/os/linux_generic/thread.cc
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2019 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 "os/thread.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <cerrno>
+#include <cstring>
+
+#include "os/log.h"
+
+namespace bluetooth {
+namespace os {
+
+namespace {
+constexpr int kRealTimeFifoSchedulingPriority = 1;
+}
+
+Thread::Thread(const std::string& name, const Priority priority)
+ : name_(name),
+ reactor_(),
+ running_thread_(&Thread::run, this, priority) {}
+
+void Thread::run(Priority priority) {
+ if (priority == Priority::REAL_TIME) {
+ struct sched_param rt_params = {.sched_priority = kRealTimeFifoSchedulingPriority};
+ auto linux_tid = static_cast<pid_t>(syscall(SYS_gettid));
+ int rc;
+ RUN_NO_INTR(rc = sched_setscheduler(linux_tid, SCHED_FIFO, &rt_params));
+ if (rc != 0) {
+ LOG_ERROR("unable to set SCHED_FIFO priority: %s", strerror(errno));
+ }
+ }
+ reactor_.Run();
+}
+
+Thread::~Thread() {
+ Stop();
+}
+
+bool Thread::Stop() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ ASSERT(std::this_thread::get_id() != running_thread_.get_id());
+
+ if (!running_thread_.joinable()) {
+ return false;
+ }
+ reactor_.Stop();
+ running_thread_.join();
+ return true;
+}
+
+bool Thread::IsSameThread() const {
+ return std::this_thread::get_id() == running_thread_.get_id();
+}
+
+Reactor* Thread::GetReactor() const {
+ return &reactor_;
+}
+
+std::string Thread::GetThreadName() const {
+ return name_;
+}
+
+std::string Thread::ToString() const {
+ return "Thread " + name_;
+}
+
+} // namespace os
+} // namespace bluetooth
diff --git a/gd/os/linux_generic/thread_unittest.cc b/gd/os/linux_generic/thread_unittest.cc
new file mode 100644
index 0000000..1e16edc
--- /dev/null
+++ b/gd/os/linux_generic/thread_unittest.cc
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2019 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 "os/thread.h"
+
+#include <sys/eventfd.h>
+
+#include "gtest/gtest.h"
+#include "os/reactor.h"
+
+namespace bluetooth {
+namespace os {
+namespace {
+
+constexpr int kCheckIsSameThread = 1;
+
+class SampleReactable {
+ public:
+ explicit SampleReactable(Thread* thread) : thread_(thread), fd_(eventfd(0, 0)), is_same_thread_checked_(false) {
+ EXPECT_NE(fd_, 0);
+ }
+
+ ~SampleReactable() {
+ close(fd_);
+ }
+
+ void OnReadReady() {
+ EXPECT_TRUE(thread_->IsSameThread());
+ is_same_thread_checked_ = true;
+ uint64_t val;
+ eventfd_read(fd_, &val);
+ }
+
+ bool IsSameThreadCheckDone() {
+ return is_same_thread_checked_;
+ }
+
+ Thread* thread_;
+ int fd_;
+ bool is_same_thread_checked_;
+};
+
+class ThreadTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ thread = new Thread("test", Thread::Priority::NORMAL);
+ }
+
+ void TearDown() override {
+ delete thread;
+ }
+ Thread* thread = nullptr;
+};
+
+TEST_F(ThreadTest, just_stop_no_op) {
+ thread->Stop();
+}
+
+TEST_F(ThreadTest, thread_name) {
+ EXPECT_EQ(thread->GetThreadName(), "test");
+}
+
+TEST_F(ThreadTest, thread_to_string) {
+ EXPECT_NE(thread->ToString().find("test"), std::string::npos);
+}
+
+TEST_F(ThreadTest, not_same_thread) {
+ EXPECT_FALSE(thread->IsSameThread());
+}
+
+TEST_F(ThreadTest, same_thread) {
+ Reactor* reactor = thread->GetReactor();
+ SampleReactable sample_reactable(thread);
+ auto* reactable =
+ reactor->Register(sample_reactable.fd_, std::bind(&SampleReactable::OnReadReady, &sample_reactable), nullptr);
+ int fd = sample_reactable.fd_;
+ int write_result = eventfd_write(fd, kCheckIsSameThread);
+ EXPECT_EQ(write_result, 0);
+ while (!sample_reactable.IsSameThreadCheckDone()) std::this_thread::yield();
+ reactor->Unregister(reactable);
+}
+
+} // namespace
+} // namespace os
+} // namespace bluetooth
diff --git a/gd/os/log.h b/gd/os/log.h
new file mode 100644
index 0000000..d7c6a8b
--- /dev/null
+++ b/gd/os/log.h
@@ -0,0 +1,66 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 <stdlib.h>
+
+#ifndef LOG_TAG
+#define LOG_TAG "bt"
+#endif
+
+#if defined(OS_ANDROID)
+
+#include <log/log.h>
+
+#define LOG_VERBOSE(fmt, args...) ALOGV("%s: " fmt, __PRETTY_FUNCTION__, ##args)
+#define LOG_DEBUG(fmt, args...) ALOGD("%s: " fmt, __PRETTY_FUNCTION__, ##args)
+#define LOG_INFO(fmt, args...) ALOGI("%s: " fmt, __PRETTY_FUNCTION__, ##args)
+#define LOG_WARN(fmt, args...) ALOGW("%s: " fmt, __PRETTY_FUNCTION__, ##args)
+#define LOG_ERROR(fmt, args...) ALOGE("%s: " fmt, __PRETTY_FUNCTION__, ##args)
+
+#else
+
+/* syslog didn't work well here since we would be redefining LOG_DEBUG. */
+#include <stdio.h>
+
+#define LOGWRAPPER(fmt, args...) fprintf(stderr, "%s - %s: " fmt "\n", LOG_TAG, __PRETTY_FUNCTION__, ##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__)
+
+#endif /* defined(OS_ANDROID) */
+
+#define ASSERT(condition) \
+ do { \
+ if (!(condition)) { \
+ LOG_ERROR("%s:%d assertion '" #condition "' failed", __FILE__, __LINE__); \
+ abort(); \
+ } \
+ } while (false)
+
+#define ASSERT_LOG(condition, fmt, args...) \
+ do { \
+ if (!(condition)) { \
+ LOG_ERROR("%s:%d assertion '" #condition "' failed - " fmt, __FILE__, __LINE__, ##args); \
+ abort(); \
+ } \
+ } while (false)
diff --git a/gd/os/queue.h b/gd/os/queue.h
new file mode 100644
index 0000000..ae1ba14
--- /dev/null
+++ b/gd/os/queue.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2019 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 <unistd.h>
+#include <functional>
+#include <mutex>
+#include <queue>
+
+#include "os/handler.h"
+#ifdef OS_LINUX_GENERIC
+#include "os/linux_generic/reactive_semaphore.h"
+#endif
+#include "os/log.h"
+
+namespace bluetooth {
+namespace os {
+
+// See documentation for |Queue|
+template <typename T>
+class IQueueEnqueue {
+ public:
+ using EnqueueCallback = std::function<std::unique_ptr<T>()>;
+ virtual ~IQueueEnqueue() = default;
+ virtual void RegisterEnqueue(Handler* handler, EnqueueCallback callback) = 0;
+ virtual void UnregisterEnqueue() = 0;
+};
+
+// See documentation for |Queue|
+template <typename T>
+class IQueueDequeue {
+ public:
+ using DequeueCallback = std::function<void()>;
+ virtual ~IQueueDequeue() = default;
+ virtual void RegisterDequeue(Handler* handler, DequeueCallback callback) = 0;
+ virtual void UnregisterDequeue() = 0;
+ virtual std::unique_ptr<T> TryDequeue() = 0;
+};
+
+template <typename T>
+class Queue : public IQueueEnqueue<T>, public IQueueDequeue<T> {
+ public:
+ // A function moving data from enqueue end buffer to queue, it will be continually be invoked until queue
+ // is full. Enqueue end should make sure buffer isn't empty and UnregisterEnqueue when buffer become empty.
+ using EnqueueCallback = std::function<std::unique_ptr<T>()>;
+ // A function moving data form queue to dequeue end buffer, it will be continually be invoked until queue
+ // is empty. TryDequeue should be use in this function to get data from queue.
+ using DequeueCallback = std::function<void()>;
+ // Create a queue with |capacity| is the maximum number of messages a queue can contain
+ explicit Queue(size_t capacity);
+ ~Queue();
+ // Register |callback| that will be called on |handler| when the queue is able to enqueue one piece of data.
+ // This will cause a crash if handler or callback has already been registered before.
+ void RegisterEnqueue(Handler* handler, EnqueueCallback callback) override;
+ // Unregister current EnqueueCallback from this queue, this will cause a crash if not registered yet.
+ void UnregisterEnqueue() override;
+ // Register |callback| that will be called on |handler| when the queue has at least one piece of data ready
+ // for dequeue. This will cause a crash if handler or callback has already been registered before.
+ void RegisterDequeue(Handler* handler, DequeueCallback callback) override;
+ // Unregister current DequeueCallback from this queue, this will cause a crash if not registered yet.
+ void UnregisterDequeue() override;
+
+ // Try to dequeue an item from this queue. Return nullptr when there is nothing in the queue.
+ std::unique_ptr<T> TryDequeue() override;
+
+ private:
+ void EnqueueCallbackInternal(EnqueueCallback callback);
+ // An internal queue that holds at most |capacity| pieces of data
+ std::queue<std::unique_ptr<T>> queue_;
+ // A mutex that guards data in this queue
+ std::mutex mutex_;
+
+ class QueueEndpoint {
+ public:
+#ifdef OS_LINUX_GENERIC
+ explicit QueueEndpoint(unsigned int initial_value)
+ : reactive_semaphore_(initial_value), handler_(nullptr), reactable_(nullptr) {}
+ ReactiveSemaphore reactive_semaphore_;
+#endif
+ Handler* handler_;
+ Reactor::Reactable* reactable_;
+ };
+
+ QueueEndpoint enqueue_;
+ QueueEndpoint dequeue_;
+};
+
+#ifdef OS_LINUX_GENERIC
+#include "os/linux_generic/queue.tpp"
+#endif
+
+} // namespace os
+} // namespace bluetooth
diff --git a/gd/os/queue_benchmark.cc b/gd/os/queue_benchmark.cc
new file mode 100644
index 0000000..7832a17
--- /dev/null
+++ b/gd/os/queue_benchmark.cc
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2019 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 "benchmark/benchmark.h"
+
+#include <future>
+
+#include "os/handler.h"
+#include "os/queue.h"
+#include "os/thread.h"
+
+using ::benchmark::State;
+
+namespace bluetooth {
+namespace os {
+
+class BM_QueuePerformance : public ::benchmark::Fixture {
+ protected:
+ void SetUp(State& st) override {
+ ::benchmark::Fixture::SetUp(st);
+ enqueue_thread_ = new Thread("enqueue_thread", Thread::Priority::NORMAL);
+ enqueue_handler_ = new Handler(enqueue_thread_);
+ dequeue_thread_ = new Thread("dequeue_thread", Thread::Priority::NORMAL);
+ dequeue_handler_ = new Handler(dequeue_thread_);
+ }
+
+ void TearDown(State& st) override {
+ delete enqueue_handler_;
+ delete enqueue_thread_;
+ delete dequeue_handler_;
+ delete dequeue_thread_;
+ enqueue_handler_ = nullptr;
+ enqueue_thread_ = nullptr;
+ dequeue_handler_ = nullptr;
+ dequeue_thread_ = nullptr;
+ benchmark::Fixture::TearDown(st);
+ }
+
+ Thread* enqueue_thread_;
+ Handler* enqueue_handler_;
+ Thread* dequeue_thread_;
+ Handler* dequeue_handler_;
+};
+
+class TestEnqueueEnd {
+ public:
+ explicit TestEnqueueEnd(int64_t count, Queue<std::string>* queue, Handler* handler, std::promise<void>* promise)
+ : count_(count), handler_(handler), queue_(queue), promise_(promise) {}
+
+ void RegisterEnqueue() {
+ handler_->Post([this] { queue_->RegisterEnqueue(handler_, [this] { return EnqueueCallbackForTest(); }); });
+ }
+
+ void push(std::string data) {
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ buffer_.push(std::move(data));
+ }
+ if (buffer_.size() == 1) {
+ RegisterEnqueue();
+ }
+ }
+
+ std::unique_ptr<std::string> EnqueueCallbackForTest() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::move(buffer_.front()));
+ buffer_.pop();
+
+ if (buffer_.empty()) {
+ queue_->UnregisterEnqueue();
+ }
+
+ count_--;
+ if (count_ == 0) {
+ promise_->set_value();
+ }
+
+ return data;
+ }
+
+ std::queue<std::string> buffer_;
+ int64_t count_;
+
+ private:
+ Handler* handler_;
+ Queue<std::string>* queue_;
+ std::promise<void>* promise_;
+ std::mutex mutex_;
+};
+
+class TestDequeueEnd {
+ public:
+ explicit TestDequeueEnd(int64_t count, Queue<std::string>* queue, Handler* handler, std::promise<void>* promise)
+ : count_(count), handler_(handler), queue_(queue), promise_(promise) {}
+
+ void RegisterDequeue() {
+ handler_->Post([this] { queue_->RegisterDequeue(handler_, [this] { DequeueCallbackForTest(); }); });
+ }
+
+ void DequeueCallbackForTest() {
+ std::string data = *(queue_->TryDequeue());
+ buffer_.push(data);
+
+ count_--;
+ if (count_ == 0) {
+ queue_->UnregisterDequeue();
+ promise_->set_value();
+ }
+ }
+
+ std::queue<std::string> buffer_;
+ int64_t count_;
+
+ private:
+ Handler* handler_;
+ Queue<std::string>* queue_;
+ std::promise<void>* promise_;
+};
+
+BENCHMARK_DEFINE_F(BM_QueuePerformance, send_packet_vary_by_packet_num)(State& state) {
+ for (auto _ : state) {
+ int64_t num_data_to_send_ = state.range(0);
+ Queue<std::string> queue(num_data_to_send_);
+
+ // register dequeue
+ std::promise<void> dequeue_promise;
+ auto dequeue_future = dequeue_promise.get_future();
+ TestDequeueEnd test_dequeue_end(num_data_to_send_, &queue, enqueue_handler_, &dequeue_promise);
+ test_dequeue_end.RegisterDequeue();
+
+ // Push data to enqueue end buffer and register enqueue
+ std::promise<void> enqueue_promise;
+ TestEnqueueEnd test_enqueue_end(num_data_to_send_, &queue, enqueue_handler_, &enqueue_promise);
+ for (int i = 0; i < num_data_to_send_; i++) {
+ std::string data = std::to_string(1);
+ test_enqueue_end.push(std::move(data));
+ }
+ dequeue_future.wait();
+ }
+
+ state.SetBytesProcessed(static_cast<int_fast64_t>(state.iterations()) * state.range(0));
+};
+
+BENCHMARK_REGISTER_F(BM_QueuePerformance, send_packet_vary_by_packet_num)
+ ->Arg(10)
+ ->Arg(100)
+ ->Arg(1000)
+ ->Arg(10000)
+ ->Arg(100000)
+ ->Iterations(100)
+ ->UseRealTime();
+
+BENCHMARK_DEFINE_F(BM_QueuePerformance, send_10000_packet_vary_by_packet_size)(State& state) {
+ for (auto _ : state) {
+ int64_t num_data_to_send_ = 10000;
+ int64_t packet_size = state.range(0);
+ Queue<std::string> queue(num_data_to_send_);
+
+ // register dequeue
+ std::promise<void> dequeue_promise;
+ auto dequeue_future = dequeue_promise.get_future();
+ TestDequeueEnd test_dequeue_end(num_data_to_send_, &queue, enqueue_handler_, &dequeue_promise);
+ test_dequeue_end.RegisterDequeue();
+
+ // Push data to enqueue end buffer and register enqueue
+ std::promise<void> enqueue_promise;
+ TestEnqueueEnd test_enqueue_end(num_data_to_send_, &queue, enqueue_handler_, &enqueue_promise);
+ for (int i = 0; i < num_data_to_send_; i++) {
+ std::string data = std::string(packet_size, 'x');
+ test_enqueue_end.push(std::move(data));
+ }
+ dequeue_future.wait();
+ }
+
+ state.SetBytesProcessed(static_cast<int_fast64_t>(state.iterations()) * state.range(0) * 10000);
+};
+
+BENCHMARK_REGISTER_F(BM_QueuePerformance, send_10000_packet_vary_by_packet_size)
+ ->Arg(10)
+ ->Arg(100)
+ ->Arg(1000)
+ ->Iterations(100)
+ ->UseRealTime();
+
+} // namespace os
+} // namespace bluetooth
diff --git a/gd/os/reactor.h b/gd/os/reactor.h
new file mode 100644
index 0000000..a0de131
--- /dev/null
+++ b/gd/os/reactor.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2019 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 <sys/epoll.h>
+#include <atomic>
+#include <functional>
+#include <list>
+#include <mutex>
+#include <thread>
+
+#include "os/utils.h"
+
+namespace bluetooth {
+namespace os {
+
+// Format of closure to be used in the entire stack
+using Closure = std::function<void()>;
+
+// A simple implementation of reactor-style looper.
+// When a reactor is running, the main loop is polling and blocked until at least one registered reactable is ready to
+// read or write. It will invoke on_read_ready() or on_write_ready(), which is registered with the reactor. Then, it
+// blocks again until ready event.
+class Reactor {
+ public:
+ // An object used for Unregister() and ModifyRegistration()
+ class Reactable;
+
+ // Construct a reactor on the current thread
+ Reactor();
+
+ // Destruct this reactor and release its resources
+ ~Reactor();
+
+ DISALLOW_COPY_AND_ASSIGN(Reactor);
+
+ // Start the reactor. The current thread will be blocked until Stop() is invoked and handled.
+ void Run();
+
+ // Stop the reactor. Must be invoked from a different thread. Note: all registered reactables will not be unregistered
+ // by Stop(). If the reactor is not running, it will be stopped once it's started.
+ void Stop();
+
+ // Register a reactable fd to this reactor. Returns a pointer to a Reactable. Caller must use this object to
+ // unregister or modify registration. Ownership of the memory space is NOT transferred to user.
+ Reactable* Register(int fd, Closure on_read_ready, Closure on_write_ready);
+
+ // Unregister a reactable from this reactor
+ void Unregister(Reactable* reactable);
+
+ // Modify the registration for a reactable with given reactable
+ void ModifyRegistration(Reactable* reactable, Closure on_read_ready, Closure on_write_ready);
+
+ private:
+ mutable std::mutex mutex_;
+ int epoll_fd_;
+ int control_fd_;
+ std::atomic<bool> is_running_;
+ std::list<Reactable*> invalidation_list_;
+ bool reactable_removed_;
+};
+
+} // namespace os
+} // namespace bluetooth
diff --git a/gd/os/repeating_alarm.h b/gd/os/repeating_alarm.h
new file mode 100644
index 0000000..776781a
--- /dev/null
+++ b/gd/os/repeating_alarm.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2019 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 <mutex>
+
+#include "os/thread.h"
+#include "os/utils.h"
+
+namespace bluetooth {
+namespace os {
+
+// A repeating alarm for reactor-based thread, implemented by Linux timerfd.
+// When it's constructed, it will register a reactable on the specified thread; when it's destroyed, it will unregister
+// itself from the thread.
+class RepeatingAlarm {
+ public:
+ // Create and register a repeating alarm on given thread
+ explicit RepeatingAlarm(Thread* thread);
+
+ // Unregister this alarm from the thread and release resource
+ ~RepeatingAlarm();
+
+ DISALLOW_COPY_AND_ASSIGN(RepeatingAlarm);
+
+ // Schedule a repeating alarm with given period
+ void Schedule(Closure task, std::chrono::milliseconds period);
+
+ // Cancel the alarm. No-op if it's not armed.
+ void Cancel();
+
+ private:
+ Closure task_;
+ Thread* thread_;
+ int fd_ = 0;
+ Reactor::Reactable* token_;
+ mutable std::mutex mutex_;
+ void on_fire();
+};
+
+} // namespace os
+} // namespace bluetooth
diff --git a/gd/os/thread.h b/gd/os/thread.h
new file mode 100644
index 0000000..d14d75e
--- /dev/null
+++ b/gd/os/thread.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2019 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 <mutex>
+#include <string>
+#include <thread>
+
+#include "os/reactor.h"
+#include "os/utils.h"
+
+namespace bluetooth {
+namespace os {
+
+// Reactor-based looper thread implementation. The thread runs immediately after it is constructed, and stops after
+// Stop() is invoked. To assign task to this thread, user needs to register a reactable object to the underlying
+// reactor.
+class Thread {
+ public:
+ // Used by thread constructor. Suggest the priority to the kernel scheduler. Use REAL_TIME if we need (soft) real-time
+ // scheduling guarantee for this thread; use NORMAL if no real-time guarantee is needed to save CPU time slice for
+ // other threads
+ enum class Priority {
+ REAL_TIME,
+ NORMAL,
+ };
+
+ // name: thread name for POSIX systems
+ // priority: priority for kernel scheduler
+ Thread(const std::string& name, Priority priority);
+
+ // Stop and destroy this thread
+ ~Thread();
+
+ DISALLOW_COPY_AND_ASSIGN(Thread);
+
+ // Stop this thread. Must be invoked from another thread. After this thread is stopped, it cannot be started again.
+ bool Stop();
+
+ // Return true if this function is invoked from this thread
+ bool IsSameThread() const;
+
+ // Return the POSIX thread name
+ std::string GetThreadName() const;
+
+ // Return a user-friendly string representation of this thread object
+ std::string ToString() const;
+
+ // Return the pointer of underlying reactor. The ownership is NOT transferred.
+ Reactor* GetReactor() const;
+
+ private:
+ void run(Priority priority);
+ mutable std::mutex mutex_;
+ const std::string name_;
+ mutable Reactor reactor_;
+ std::thread running_thread_;
+};
+
+} // namespace os
+} // namespace bluetooth
diff --git a/gd/os/thread_benchmark.cc b/gd/os/thread_benchmark.cc
new file mode 100644
index 0000000..dc22b9d
--- /dev/null
+++ b/gd/os/thread_benchmark.cc
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2019 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 <future>
+#include <memory>
+#include <thread>
+
+#include "benchmark/benchmark.h"
+
+#include "os/handler.h"
+#include "os/thread.h"
+
+using ::benchmark::State;
+using ::bluetooth::os::Handler;
+using ::bluetooth::os::Thread;
+
+#define NUM_MESSAGES_TO_SEND 100000
+
+class BM_ThreadPerformance : public ::benchmark::Fixture {
+ protected:
+ void SetUp(State& st) override {
+ benchmark::Fixture::SetUp(st);
+ counter_promise_ = std::promise<void>();
+ counter_ = 0;
+ }
+ void TearDown(State& st) override {
+ benchmark::Fixture::TearDown(st);
+ }
+ void callback_batch() {
+ counter_++;
+ if (counter_ >= num_messages_to_send_) {
+ counter_promise_.set_value();
+ }
+ }
+
+ void callback() {
+ counter_promise_.set_value();
+ }
+
+ int64_t num_messages_to_send_;
+ int64_t counter_;
+ std::promise<void> counter_promise_;
+};
+
+class BM_ReactorThread : public BM_ThreadPerformance {
+ protected:
+ void SetUp(State& st) override {
+ BM_ThreadPerformance::SetUp(st);
+ thread_ = std::make_unique<Thread>("BM_ReactorThread thread", Thread::Priority::NORMAL);
+ handler_ = std::make_unique<Handler>(thread_.get());
+ }
+ void TearDown(State& st) override {
+ handler_ = nullptr;
+ thread_->Stop();
+ thread_ = nullptr;
+ BM_ThreadPerformance::TearDown(st);
+ }
+ std::unique_ptr<Thread> thread_;
+ std::unique_ptr<Handler> handler_;
+};
+
+BENCHMARK_DEFINE_F(BM_ReactorThread, batch_enque_dequeue)(State& state) {
+ for (auto _ : state) {
+ num_messages_to_send_ = state.range(0);
+ counter_ = 0;
+ counter_promise_ = std::promise<void>();
+ std::future<void> counter_future = counter_promise_.get_future();
+ for (int i = 0; i < num_messages_to_send_; i++) {
+ handler_->Post([this]() { callback_batch(); });
+ }
+ counter_future.wait();
+ }
+};
+
+BENCHMARK_REGISTER_F(BM_ReactorThread, batch_enque_dequeue)
+ ->Arg(10)
+ ->Arg(1000)
+ ->Arg(10000)
+ ->Arg(100000)
+ ->Iterations(1)
+ ->UseRealTime();
+
+BENCHMARK_DEFINE_F(BM_ReactorThread, sequential_execution)(State& state) {
+ for (auto _ : state) {
+ num_messages_to_send_ = state.range(0);
+ for (int i = 0; i < num_messages_to_send_; i++) {
+ counter_promise_ = std::promise<void>();
+ std::future<void> counter_future = counter_promise_.get_future();
+ handler_->Post([this]() { callback(); });
+ counter_future.wait();
+ }
+ }
+};
+
+BENCHMARK_REGISTER_F(BM_ReactorThread, sequential_execution)
+ ->Arg(10)
+ ->Arg(1000)
+ ->Arg(10000)
+ ->Arg(100000)
+ ->Iterations(1)
+ ->UseRealTime();
diff --git a/gd/os/utils.h b/gd/os/utils.h
new file mode 100644
index 0000000..89fca66
--- /dev/null
+++ b/gd/os/utils.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2019 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>
+
+// A macro to re-try a syscall when it receives EINTR
+#ifndef RUN_NO_INTR
+#define RUN_NO_INTR(fn) \
+ do { \
+ } while ((fn) == -1 && errno == EINTR)
+#endif
+
+// A macro to disallow the copy constructor and operator= functions
+#ifndef DISALLOW_COPY_AND_ASSIGN
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ TypeName(const TypeName&) = delete; \
+ void operator=(const TypeName&) = delete
+#endif
diff --git a/gd/packet/Android.bp b/gd/packet/Android.bp
new file mode 100644
index 0000000..c65cf8c
--- /dev/null
+++ b/gd/packet/Android.bp
@@ -0,0 +1,22 @@
+filegroup {
+ name: "BluetoothPacketSources",
+ srcs: [
+ "bit_inserter.cc",
+ "byte_inserter.cc",
+ "byte_observer.cc",
+ "iterator.cc",
+ "packet_view.cc",
+ "raw_builder.cc",
+ "view.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothPacketTestSources",
+ srcs: [
+ "bit_inserter_unittest.cc",
+ "packet_builder_unittest.cc",
+ "packet_view_unittest.cc",
+ "raw_builder_unittest.cc",
+ ],
+}
diff --git a/gd/packet/base_packet_builder.h b/gd/packet/base_packet_builder.h
new file mode 100644
index 0000000..f093385
--- /dev/null
+++ b/gd/packet/base_packet_builder.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019 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 <forward_list>
+#include <iterator>
+#include <memory>
+#include <vector>
+
+#include "packet/bit_inserter.h"
+
+namespace bluetooth {
+namespace packet {
+
+// A little-endian PacketBuilder can contain a big-endian PacketBuilder,
+// so BasePacketBuilder provides a common base class.
+class BasePacketBuilder {
+ public:
+ virtual ~BasePacketBuilder() = default;
+
+ virtual size_t size() const = 0;
+
+ // Write to the vector with the given iterator.
+ virtual void Serialize(BitInserter& it) const = 0;
+
+ protected:
+ BasePacketBuilder() = default;
+};
+
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/bit_inserter.cc b/gd/packet/bit_inserter.cc
new file mode 100644
index 0000000..0180cd8
--- /dev/null
+++ b/gd/packet/bit_inserter.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2019 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 "packet/bit_inserter.h"
+
+#include "os/log.h"
+
+namespace bluetooth {
+namespace packet {
+
+BitInserter::BitInserter(std::vector<uint8_t>& vector) : ByteInserter(vector) {}
+
+BitInserter::~BitInserter() {
+ ASSERT(num_saved_bits_ == 0);
+}
+
+void BitInserter::insert_bits(uint8_t byte, size_t num_bits) {
+ size_t total_bits = num_bits + num_saved_bits_;
+ uint16_t new_value = saved_bits_ | (static_cast<uint16_t>(byte) << num_saved_bits_);
+ if (total_bits >= 8) {
+ uint8_t new_byte = static_cast<uint8_t>(new_value);
+ ByteInserter::insert_byte(new_byte);
+ total_bits -= 8;
+ new_value = new_value >> 8;
+ }
+ num_saved_bits_ = total_bits;
+ uint8_t mask = 0xff >> (8 - num_saved_bits_);
+ saved_bits_ = static_cast<uint8_t>(new_value) & mask;
+}
+
+void BitInserter::insert_byte(uint8_t byte) {
+ insert_bits(byte, 8);
+}
+
+bool BitInserter::IsByteAligned() {
+ return num_saved_bits_ == 0;
+}
+
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/bit_inserter.h b/gd/packet/bit_inserter.h
new file mode 100644
index 0000000..2aa1ad6
--- /dev/null
+++ b/gd/packet/bit_inserter.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019 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 <iterator>
+#include <memory>
+#include <vector>
+
+#include "packet/byte_inserter.h"
+
+namespace bluetooth {
+namespace packet {
+
+class BitInserter : public ByteInserter {
+ public:
+ BitInserter(std::vector<uint8_t>& vector);
+ virtual ~BitInserter();
+
+ void insert_bits(uint8_t byte, size_t num_bits);
+
+ void insert_byte(uint8_t byte);
+
+ bool IsByteAligned();
+
+ private:
+ size_t num_saved_bits_{0};
+ uint8_t saved_bits_{0};
+};
+
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/bit_inserter_unittest.cc b/gd/packet/bit_inserter_unittest.cc
new file mode 100644
index 0000000..fae19f8
--- /dev/null
+++ b/gd/packet/bit_inserter_unittest.cc
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2019 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 "packet/bit_inserter.h"
+
+#include <gtest/gtest.h>
+#include <memory>
+
+#include "os/log.h"
+
+using bluetooth::packet::BitInserter;
+using std::vector;
+
+namespace bluetooth {
+namespace packet {
+
+TEST(BitInserterTest, addMoreBits) {
+ std::vector<uint8_t> bytes;
+ BitInserter it(bytes);
+
+ for (size_t i = 0; i < 9; i++) {
+ it.insert_bits(static_cast<uint8_t>(i), i);
+ }
+ it.insert_bits(static_cast<uint8_t>(0b1010), 4);
+ std::vector<uint8_t> result = {0b00011101 /* 3 2 1 */, 0b00010101 /* 5 4 */, 0b11100011 /* 7 6 */, 0b10000000 /* 8 */,
+ 0b10100000 /* filled with 1010 */};
+
+ ASSERT_EQ(result.size(), bytes.size());
+ for (size_t i = 0; i < bytes.size(); i++) {
+ ASSERT_EQ(result[i], bytes[i]);
+ }
+}
+
+TEST(BitInserterTest, observerTest) {
+ std::vector<uint8_t> bytes;
+ BitInserter it(bytes);
+ std::vector<uint8_t> copy;
+
+ uint64_t checksum = 0x0123456789abcdef;
+ it.RegisterObserver(ByteObserver([©](uint8_t byte) { copy.push_back(byte); }, [checksum]() { return checksum; }));
+
+ for (size_t i = 0; i < 9; i++) {
+ it.insert_bits(static_cast<uint8_t>(i), i);
+ }
+ it.insert_bits(static_cast<uint8_t>(0b1010), 4);
+ std::vector<uint8_t> result = {0b00011101 /* 3 2 1 */, 0b00010101 /* 5 4 */, 0b11100011 /* 7 6 */, 0b10000000 /* 8 */,
+ 0b10100000 /* filled with 1010 */};
+
+ ASSERT_EQ(result.size(), bytes.size());
+ for (size_t i = 0; i < bytes.size(); i++) {
+ ASSERT_EQ(result[i], bytes[i]);
+ }
+
+ ASSERT_EQ(result.size(), copy.size());
+ for (size_t i = 0; i < copy.size(); i++) {
+ ASSERT_EQ(result[i], copy[i]);
+ }
+
+ ByteObserver observer = it.UnregisterObserver();
+ ASSERT_EQ(checksum, observer.GetValue());
+ uint8_t another_byte = 0xef;
+ it.insert_bits(another_byte, 8);
+ ASSERT_EQ(bytes.back(), another_byte);
+ ASSERT_EQ(result.size() + 1, bytes.size());
+ ASSERT_EQ(result.size(), copy.size());
+}
+
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/byte_inserter.cc b/gd/packet/byte_inserter.cc
new file mode 100644
index 0000000..f7fc9c0
--- /dev/null
+++ b/gd/packet/byte_inserter.cc
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2019 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 "packet/byte_inserter.h"
+
+#include "os/log.h"
+
+namespace bluetooth {
+namespace packet {
+
+ByteInserter::ByteInserter(std::vector<uint8_t>& vector) : std::back_insert_iterator<std::vector<uint8_t>>(vector) {}
+
+ByteInserter::~ByteInserter() {
+ ASSERT(registered_observers_.size() == 0);
+}
+
+void ByteInserter::RegisterObserver(ByteObserver observer) {
+ registered_observers_.push_back(observer);
+}
+
+ByteObserver ByteInserter::UnregisterObserver() {
+ ByteObserver observer = registered_observers_.back();
+ registered_observers_.pop_back();
+ return observer;
+}
+
+void ByteInserter::insert_byte(uint8_t byte) {
+ for (auto& observer : registered_observers_) {
+ observer.OnByte(byte);
+ }
+ std::back_insert_iterator<std::vector<uint8_t>>::operator=(byte);
+}
+
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/byte_inserter.h b/gd/packet/byte_inserter.h
new file mode 100644
index 0000000..2d49b33
--- /dev/null
+++ b/gd/packet/byte_inserter.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2019 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 <iterator>
+#include <memory>
+#include <vector>
+
+#include "packet/byte_observer.h"
+
+namespace bluetooth {
+namespace packet {
+
+class ByteInserter : public std::back_insert_iterator<std::vector<uint8_t>> {
+ public:
+ ByteInserter(std::vector<uint8_t>& vector);
+ virtual ~ByteInserter();
+
+ void insert_byte(uint8_t byte);
+
+ void RegisterObserver(ByteObserver observer);
+
+ ByteObserver UnregisterObserver();
+
+ private:
+ std::vector<ByteObserver> registered_observers_;
+};
+
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/byte_observer.cc b/gd/packet/byte_observer.cc
new file mode 100644
index 0000000..358a230
--- /dev/null
+++ b/gd/packet/byte_observer.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2019 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 "packet/byte_observer.h"
+
+namespace bluetooth {
+namespace packet {
+
+ByteObserver::ByteObserver(const std::function<void(uint8_t)>& on_byte, const std::function<uint64_t()>& get_value)
+ : on_byte_(on_byte), get_value_(get_value) {}
+
+void ByteObserver::OnByte(uint8_t byte) {
+ on_byte_(byte);
+}
+
+uint64_t ByteObserver::GetValue() {
+ return get_value_();
+}
+
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/byte_observer.h b/gd/packet/byte_observer.h
new file mode 100644
index 0000000..adfcfc1
--- /dev/null
+++ b/gd/packet/byte_observer.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2019 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 <functional>
+
+namespace bluetooth {
+namespace packet {
+
+class ByteObserver {
+ public:
+ ByteObserver(const std::function<void(uint8_t)>& on_byte_, const std::function<uint64_t()>& get_value_);
+
+ void OnByte(uint8_t byte);
+
+ uint64_t GetValue();
+
+ private:
+ std::function<void(uint8_t)> on_byte_;
+ std::function<uint64_t()> get_value_;
+};
+
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/iterator.cc b/gd/packet/iterator.cc
new file mode 100644
index 0000000..5167806
--- /dev/null
+++ b/gd/packet/iterator.cc
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2019 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 "packet/iterator.h"
+
+#include "os/log.h"
+
+namespace bluetooth {
+namespace packet {
+
+template <bool little_endian>
+Iterator<little_endian>::Iterator(std::forward_list<View> data, size_t offset) {
+ data_ = data;
+ index_ = offset;
+ length_ = 0;
+ for (auto& view : data) {
+ length_ += view.size();
+ }
+}
+
+template <bool little_endian>
+Iterator<little_endian> Iterator<little_endian>::operator+(int offset) {
+ auto itr(*this);
+
+ return itr += offset;
+}
+
+template <bool little_endian>
+Iterator<little_endian>& Iterator<little_endian>::operator+=(int offset) {
+ index_ += offset;
+ return *this;
+}
+
+template <bool little_endian>
+Iterator<little_endian> Iterator<little_endian>::operator++(int) {
+ auto itr(*this);
+ index_++;
+ return itr;
+}
+
+template <bool little_endian>
+Iterator<little_endian>& Iterator<little_endian>::operator++() {
+ index_++;
+ return *this;
+}
+
+template <bool little_endian>
+Iterator<little_endian> Iterator<little_endian>::operator-(int offset) {
+ auto itr(*this);
+
+ return itr -= offset;
+}
+
+template <bool little_endian>
+int Iterator<little_endian>::operator-(Iterator<little_endian>& itr) {
+ return index_ - itr.index_;
+}
+
+template <bool little_endian>
+Iterator<little_endian>& Iterator<little_endian>::operator-=(int offset) {
+ index_ -= offset;
+
+ return *this;
+}
+
+template <bool little_endian>
+Iterator<little_endian> Iterator<little_endian>::operator--(int) {
+ auto itr(*this);
+ if (index_ != 0) index_--;
+
+ return itr;
+}
+
+template <bool little_endian>
+Iterator<little_endian>& Iterator<little_endian>::operator--() {
+ if (index_ != 0) index_--;
+
+ return *this;
+}
+
+template <bool little_endian>
+Iterator<little_endian>& Iterator<little_endian>::operator=(const Iterator<little_endian>& itr) {
+ data_ = itr.data_;
+ index_ = itr.index_;
+
+ return *this;
+}
+
+template <bool little_endian>
+bool Iterator<little_endian>::operator==(const Iterator<little_endian>& itr) const {
+ return index_ == itr.index_;
+}
+
+template <bool little_endian>
+bool Iterator<little_endian>::operator!=(const Iterator<little_endian>& itr) const {
+ return !(*this == itr);
+}
+
+template <bool little_endian>
+bool Iterator<little_endian>::operator<(const Iterator<little_endian>& itr) const {
+ return index_ < itr.index_;
+}
+
+template <bool little_endian>
+bool Iterator<little_endian>::operator>(const Iterator<little_endian>& itr) const {
+ return index_ > itr.index_;
+}
+
+template <bool little_endian>
+bool Iterator<little_endian>::operator<=(const Iterator<little_endian>& itr) const {
+ return index_ <= itr.index_;
+}
+
+template <bool little_endian>
+bool Iterator<little_endian>::operator>=(const Iterator<little_endian>& itr) const {
+ return index_ >= itr.index_;
+}
+
+template <bool little_endian>
+uint8_t Iterator<little_endian>::operator*() const {
+ ASSERT_LOG(index_ < length_, "Index %zu out of bounds: %zu", index_, length_);
+ size_t index = index_;
+
+ for (auto view : data_) {
+ if (index < view.size()) {
+ return view[index];
+ }
+ index -= view.size();
+ }
+ ASSERT_LOG(false, "Out of fragments searching for index %zu", index_);
+ return 0;
+}
+
+template <bool little_endian>
+size_t Iterator<little_endian>::NumBytesRemaining() const {
+ if (length_ > index_) {
+ return length_ - index_;
+ } else {
+ return 0;
+ }
+}
+
+// Explicit instantiations for both types of Iterators.
+template class Iterator<true>;
+template class Iterator<false>;
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/iterator.h b/gd/packet/iterator.h
new file mode 100644
index 0000000..422c025
--- /dev/null
+++ b/gd/packet/iterator.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2019 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 <forward_list>
+
+#include "packet/view.h"
+
+namespace bluetooth {
+namespace packet {
+
+// Templated Iterator for endianness
+template <bool little_endian>
+class Iterator : public std::iterator<std::random_access_iterator_tag, uint8_t> {
+ public:
+ Iterator(std::forward_list<View> data, size_t offset);
+ Iterator(const Iterator& itr) = default;
+ virtual ~Iterator() = default;
+
+ // All addition and subtraction operators are unbounded.
+ Iterator operator+(int offset);
+ Iterator& operator+=(int offset);
+ Iterator operator++(int);
+ Iterator& operator++();
+
+ Iterator operator-(int offset);
+ int operator-(Iterator& itr);
+ Iterator& operator-=(int offset);
+ Iterator operator--(int);
+ Iterator& operator--();
+
+ Iterator& operator=(const Iterator& itr);
+
+ bool operator!=(const Iterator& itr) const;
+ bool operator==(const Iterator& itr) const;
+
+ bool operator<(const Iterator& itr) const;
+ bool operator>(const Iterator& itr) const;
+
+ bool operator<=(const Iterator& itr) const;
+ bool operator>=(const Iterator& itr) const;
+
+ uint8_t operator*() const;
+ uint8_t operator->() const;
+
+ size_t NumBytesRemaining() const;
+
+ // Get the next sizeof(FixedWidthPODType) bytes and return the filled type
+ template <typename FixedWidthPODType>
+ FixedWidthPODType extract() {
+ static_assert(std::is_pod<FixedWidthPODType>::value, "Iterator::extract requires a fixed-width type.");
+ FixedWidthPODType extracted_value;
+ uint8_t* value_ptr = (uint8_t*)&extracted_value;
+
+ for (size_t i = 0; i < sizeof(FixedWidthPODType); i++) {
+ size_t index = (little_endian ? i : sizeof(FixedWidthPODType) - i - 1);
+ value_ptr[index] = *((*this)++);
+ }
+ return extracted_value;
+ }
+
+ private:
+ std::forward_list<View> data_;
+ size_t index_;
+ size_t length_;
+};
+
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/packet_builder.h b/gd/packet/packet_builder.h
new file mode 100644
index 0000000..dec67db
--- /dev/null
+++ b/gd/packet/packet_builder.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2019 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 <forward_list>
+#include <iterator>
+#include <memory>
+#include <vector>
+
+#include "os/log.h"
+#include "packet/base_packet_builder.h"
+#include "packet/bit_inserter.h"
+
+namespace bluetooth {
+namespace packet {
+
+// Abstract base class that is subclassed to build specifc packets.
+// The template parameter little_endian controls the generation of insert().
+template <bool little_endian>
+class PacketBuilder : public BasePacketBuilder {
+ public:
+ PacketBuilder() = default;
+ virtual ~PacketBuilder() = default;
+
+ // Classes which need fragmentation should define a function like this:
+ // std::forward_list<DerivedBuilder>& Fragment(size_t max_size);
+
+ protected:
+ // Write sizeof(FixedWidthIntegerType) bytes using the iterator
+ template <typename FixedWidthPODType, typename std::enable_if<std::is_pod<FixedWidthPODType>::value, int>::type = 0>
+ void insert(FixedWidthPODType value, BitInserter& it) const {
+ uint8_t* raw_bytes = (uint8_t*)&value;
+ for (size_t i = 0; i < sizeof(FixedWidthPODType); i++) {
+ if (little_endian == true) {
+ it.insert_byte(raw_bytes[i]);
+ } else {
+ it.insert_byte(raw_bytes[sizeof(FixedWidthPODType) - i - 1]);
+ }
+ }
+ }
+
+ // Write num_bits bits using the iterator
+ template <typename FixedWidthIntegerType,
+ typename std::enable_if<std::is_pod<FixedWidthIntegerType>::value, int>::type = 0>
+ void insert(FixedWidthIntegerType value, BitInserter& it, size_t num_bits) const {
+ ASSERT(num_bits <= (sizeof(FixedWidthIntegerType) * 8));
+
+ for (size_t i = 0; i < num_bits / 8; i++) {
+ if (little_endian == true) {
+ it.insert_byte(static_cast<uint8_t>(value >> (i * 8)));
+ } else {
+ it.insert_byte(static_cast<uint8_t>(value >> (((num_bits / 8) - i - 1) * 8)));
+ }
+ }
+ if (num_bits % 8) {
+ it.insert_bits(static_cast<uint8_t>(value >> ((num_bits / 8) * 8)), num_bits % 8);
+ }
+ }
+
+ // Specialized insert that allows inserting enums without casting
+ template <typename Enum, typename std::enable_if<std::is_enum_v<Enum>, int>::type = 0>
+ inline void insert(Enum value, BitInserter& it) const {
+ using enum_type = typename std::underlying_type_t<Enum>;
+ static_assert(std::is_unsigned_v<enum_type>, "Enum type is signed. Did you forget to specify the enum size?");
+ insert<enum_type>(static_cast<enum_type>(value), it);
+ }
+
+ // Write a vector of FixedWidthIntegerType using the iterator
+ template <typename FixedWidthIntegerType>
+ void insert_vector(const std::vector<FixedWidthIntegerType>& vec, BitInserter& it) const {
+ static_assert(std::is_pod<FixedWidthIntegerType>::value,
+ "PacketBuilder::insert requires a vector with elements of a fixed-size.");
+ for (const auto& element : vec) {
+ insert(element, it);
+ }
+ }
+};
+
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/packet_builder_unittest.cc b/gd/packet/packet_builder_unittest.cc
new file mode 100644
index 0000000..46647a3
--- /dev/null
+++ b/gd/packet/packet_builder_unittest.cc
@@ -0,0 +1,247 @@
+/*
+ * Copyright 2019 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 "packet/packet_builder.h"
+
+#include <gtest/gtest.h>
+#include <forward_list>
+#include <memory>
+
+using bluetooth::packet::BasePacketBuilder;
+using bluetooth::packet::BitInserter;
+using bluetooth::packet::PacketBuilder;
+using std::vector;
+
+namespace {
+vector<uint8_t> count_all = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+};
+
+vector<uint8_t> count_1 = {
+ 0x00,
+ 0x01,
+ 0x02,
+};
+
+vector<uint8_t> count_2 = {
+ 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+};
+
+vector<uint8_t> count_3 = {
+ 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+};
+} // namespace
+
+namespace bluetooth {
+namespace packet {
+
+template <bool little_endian>
+class EndianBuilder : public PacketBuilder<little_endian> {
+ public:
+ EndianBuilder(uint8_t byte, uint16_t two_bytes, uint32_t four_bytes, uint64_t eight_bytes)
+ : byte_(byte), two_bytes_(two_bytes), four_bytes_(four_bytes), eight_bytes_(eight_bytes) {}
+ ~EndianBuilder() = default;
+
+ virtual size_t size() const override {
+ return sizeof(signature_) + sizeof(byte_) + sizeof(two_bytes_) + sizeof(four_bytes_) + sizeof(eight_bytes_);
+ }
+
+ virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
+ std::unique_ptr<std::vector<uint8_t>> packet = std::make_unique<std::vector<uint8_t>>();
+ packet->reserve(size());
+ BitInserter it(*packet);
+ Serialize(it);
+ return packet;
+ }
+
+ virtual void Serialize(BitInserter& it) const override {
+ PacketBuilder<little_endian>::insert(signature_, it);
+ PacketBuilder<little_endian>::insert(byte_, it);
+ PacketBuilder<little_endian>::insert(two_bytes_, it);
+ PacketBuilder<little_endian>::insert(four_bytes_, it);
+ PacketBuilder<little_endian>::insert(eight_bytes_, it);
+ }
+
+ private:
+ uint32_t signature_{(little_endian ? 0x03020100 : 0x00010203)};
+ uint8_t byte_;
+ uint16_t two_bytes_;
+ uint32_t four_bytes_;
+ uint64_t eight_bytes_;
+};
+
+class PacketBuilderEndianTest : public ::testing::Test {
+ public:
+ PacketBuilderEndianTest() = default;
+ ~PacketBuilderEndianTest() = default;
+};
+
+TEST(PacketBuilderEndianTest, insertTest) {
+ EndianBuilder<true> little(0x04, 0x0605, 0x0a090807, 0x1211100f0e0d0c0b);
+ EndianBuilder<false> big(0x04, 0x0506, 0x0708090a, 0x0b0c0d0e0f101112);
+ ASSERT_EQ(*big.FinalPacket(), *little.FinalPacket());
+}
+
+template <typename T>
+class VectorBuilder : public PacketBuilder<true> {
+ public:
+ VectorBuilder(const std::vector<uint64_t> vect) {
+ for (uint64_t element : vect) {
+ vect_.push_back(static_cast<T>(element));
+ }
+ }
+ ~VectorBuilder() = default;
+
+ virtual size_t size() const override {
+ return vect_.size() * sizeof(T);
+ }
+
+ virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
+ std::unique_ptr<std::vector<uint8_t>> packet = std::make_unique<std::vector<uint8_t>>();
+ packet->reserve(size());
+ BitInserter it(*packet);
+ Serialize(it);
+ return packet;
+ }
+
+ virtual void Serialize(BitInserter& it) const override {
+ PacketBuilder<true>::insert_vector(vect_, it);
+ }
+
+ private:
+ std::vector<T> vect_;
+};
+
+template <typename T>
+class InsertElementsBuilder : public PacketBuilder<true> {
+ public:
+ InsertElementsBuilder(const std::vector<uint64_t> vect) {
+ for (uint64_t element : vect) {
+ vect_.push_back(static_cast<T>(element));
+ }
+ }
+ virtual ~InsertElementsBuilder() = default;
+
+ virtual size_t size() const override {
+ return vect_.size() * sizeof(T);
+ }
+
+ virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
+ std::unique_ptr<std::vector<uint8_t>> packet = std::make_unique<std::vector<uint8_t>>();
+ packet->reserve(size());
+ BitInserter it(*packet);
+ Serialize(it);
+ return packet;
+ }
+
+ virtual void Serialize(BitInserter& it) const override {
+ for (T elem : vect_) {
+ PacketBuilder<true>::insert(elem, it);
+ }
+ }
+
+ private:
+ std::vector<T> vect_;
+};
+
+std::vector<uint64_t> vector_data{
+ 0x7060504030201000, 0x7161514131211101, 0x7262524232221202, 0x7363534333231303, 0x7464544434241404,
+ 0x7565554535251505, 0x7666564636261606, 0x7767574737271707, 0x7868584838281808,
+};
+
+template <typename T>
+class VectorBuilderTest : public ::testing::Test {
+ public:
+ VectorBuilderTest() = default;
+ ~VectorBuilderTest() = default;
+
+ void SetUp() {
+ packet_1_ = std::shared_ptr<VectorBuilder<T>>(new VectorBuilder<T>(vector_data));
+ packet_2_ = std::shared_ptr<InsertElementsBuilder<T>>(new InsertElementsBuilder<T>(vector_data));
+ }
+
+ void TearDown() {
+ packet_1_.reset();
+ packet_2_.reset();
+ }
+
+ std::shared_ptr<VectorBuilder<T>> packet_1_;
+ std::shared_ptr<InsertElementsBuilder<T>> packet_2_;
+};
+
+using VectorBaseTypes = ::testing::Types<uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, int64_t>;
+TYPED_TEST_CASE(VectorBuilderTest, VectorBaseTypes);
+
+TYPED_TEST(VectorBuilderTest, insertVectorTest) {
+ ASSERT_EQ(*(this->packet_1_->FinalPacket()), *(this->packet_2_->FinalPacket()));
+}
+
+class NestedBuilder : public PacketBuilder<true> {
+ public:
+ ~NestedBuilder() = default;
+
+ virtual size_t size() const override {
+ size_t payload_size = (payload_ ? payload_->size() : 0);
+ return 1 + payload_size;
+ }
+
+ static std::unique_ptr<NestedBuilder> Create(uint8_t level) {
+ return std::unique_ptr<NestedBuilder>(new NestedBuilder(level));
+ }
+
+ static std::unique_ptr<NestedBuilder> CreateNested(std::unique_ptr<BasePacketBuilder> payload, uint8_t level) {
+ return std::unique_ptr<NestedBuilder>(new NestedBuilder(std::move(payload), level));
+ }
+
+ virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
+ std::unique_ptr<std::vector<uint8_t>> packet = std::make_unique<std::vector<uint8_t>>();
+ packet->reserve(size());
+ BitInserter it(*packet);
+ Serialize(it);
+ return packet;
+ }
+
+ virtual void Serialize(BitInserter& it) const override {
+ PacketBuilder<true>::insert(level_, it);
+ if (payload_) {
+ payload_->Serialize(it);
+ }
+ }
+
+ private:
+ std::unique_ptr<BasePacketBuilder> payload_;
+ uint8_t level_;
+
+ NestedBuilder(std::unique_ptr<BasePacketBuilder> inner, uint8_t level) : payload_(std::move(inner)), level_(level) {}
+ NestedBuilder(uint8_t level) : level_(level) {}
+};
+
+class BuilderBuilderTest : public ::testing::Test {};
+
+TEST(BuilderBuilderTest, nestingTest) {
+ std::unique_ptr<BasePacketBuilder> innermost = NestedBuilder::Create(0);
+ std::unique_ptr<BasePacketBuilder> number_1 = NestedBuilder::CreateNested(std::move(innermost), 1);
+ std::unique_ptr<BasePacketBuilder> number_2 = NestedBuilder::CreateNested(std::move(number_1), 2);
+ std::unique_ptr<BasePacketBuilder> number_3 = NestedBuilder::CreateNested(std::move(number_2), 3);
+ std::unique_ptr<BasePacketBuilder> number_4 = NestedBuilder::CreateNested(std::move(number_3), 4);
+ std::unique_ptr<NestedBuilder> number_5 = NestedBuilder::CreateNested(std::move(number_4), 5);
+
+ std::vector<uint8_t> count_down{5, 4, 3, 2, 1, 0};
+ ASSERT_EQ(*number_5->FinalPacket(), count_down);
+}
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/packet_view.cc b/gd/packet/packet_view.cc
new file mode 100644
index 0000000..94522ae
--- /dev/null
+++ b/gd/packet/packet_view.cc
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2019 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 "packet/packet_view.h"
+
+#include <algorithm>
+
+#include "os/log.h"
+
+namespace bluetooth {
+namespace packet {
+
+template <bool little_endian>
+PacketView<little_endian>::PacketView(const std::forward_list<class View> fragments)
+ : fragments_(fragments), length_(0) {
+ for (auto fragment : fragments_) {
+ length_ += fragment.size();
+ }
+}
+
+template <bool little_endian>
+PacketView<little_endian>::PacketView(std::shared_ptr<std::vector<uint8_t>> packet)
+ : fragments_({View(packet, 0, packet->size())}), length_(packet->size()) {}
+
+template <bool little_endian>
+Iterator<little_endian> PacketView<little_endian>::begin() const {
+ return Iterator<little_endian>(this->fragments_, 0);
+}
+
+template <bool little_endian>
+Iterator<little_endian> PacketView<little_endian>::end() const {
+ return Iterator<little_endian>(this->fragments_, size());
+}
+
+template <bool little_endian>
+uint8_t PacketView<little_endian>::operator[](size_t index) const {
+ return at(index);
+}
+
+template <bool little_endian>
+uint8_t PacketView<little_endian>::at(size_t index) const {
+ ASSERT_LOG(index < length_, "Index %zu out of bounds", index);
+ for (const auto& fragment : fragments_) {
+ if (index < fragment.size()) {
+ return fragment[index];
+ }
+ index -= fragment.size();
+ }
+ ASSERT_LOG(false, "Out of fragments searching for index %zu", index);
+ return 0;
+}
+
+template <bool little_endian>
+size_t PacketView<little_endian>::size() const {
+ return length_;
+}
+
+template <bool little_endian>
+std::forward_list<View> PacketView<little_endian>::GetSubviewList(size_t begin, size_t end) const {
+ ASSERT(begin <= end);
+ ASSERT(end <= length_);
+
+ std::forward_list<View> view_list;
+ std::forward_list<View>::iterator it = view_list.before_begin();
+ size_t length = end - begin;
+ for (const auto& fragment : fragments_) {
+ if (begin >= fragment.size()) {
+ begin -= fragment.size();
+ } else {
+ View view(fragment, begin, begin + std::min(length, fragment.size() - begin));
+ length -= view.size();
+ it = view_list.insert_after(it, view);
+ begin = 0;
+ }
+ }
+ return view_list;
+}
+
+template <bool little_endian>
+PacketView<true> PacketView<little_endian>::GetLittleEndianSubview(size_t begin, size_t end) const {
+ return PacketView<true>(GetSubviewList(begin, end));
+}
+
+template <bool little_endian>
+PacketView<false> PacketView<little_endian>::GetBigEndianSubview(size_t begin, size_t end) const {
+ return PacketView<false>(GetSubviewList(begin, end));
+}
+
+// Explicit instantiations for both types of PacketViews.
+template class PacketView<true>;
+template class PacketView<false>;
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/packet_view.h b/gd/packet/packet_view.h
new file mode 100644
index 0000000..4b2f191
--- /dev/null
+++ b/gd/packet/packet_view.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2019 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 <forward_list>
+
+#include "packet/iterator.h"
+#include "packet/view.h"
+
+namespace bluetooth {
+namespace packet {
+
+static const bool kLittleEndian = true;
+
+// Abstract base class that is subclassed to provide type-specifc accessors.
+// Holds a shared pointer to the underlying data.
+// The template parameter little_endian controls the generation of extract().
+template <bool little_endian>
+class PacketView {
+ public:
+ PacketView(const std::forward_list<class View> fragments);
+ PacketView(const PacketView& PacketView) = default;
+ PacketView(std::shared_ptr<std::vector<uint8_t>> packet);
+ virtual ~PacketView() = default;
+
+ virtual Iterator<little_endian> begin() const;
+
+ virtual Iterator<little_endian> end() const;
+
+ uint8_t operator[](size_t i) const;
+
+ uint8_t at(size_t index) const;
+
+ size_t size() const;
+
+ PacketView<true> GetLittleEndianSubview(size_t begin, size_t end) const;
+
+ PacketView<false> GetBigEndianSubview(size_t begin, size_t end) const;
+
+ private:
+ std::forward_list<View> fragments_;
+ size_t length_;
+ PacketView<little_endian>() = delete;
+ std::forward_list<View> GetSubviewList(size_t begin, size_t end) const;
+};
+
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/packet_view_unittest.cc b/gd/packet/packet_view_unittest.cc
new file mode 100644
index 0000000..e88c2cf
--- /dev/null
+++ b/gd/packet/packet_view_unittest.cc
@@ -0,0 +1,510 @@
+/*
+ * Copyright 2019 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 "packet/packet_view.h"
+
+#include <gtest/gtest.h>
+#include <forward_list>
+#include <memory>
+
+#include "common/address.h"
+
+using bluetooth::common::Address;
+using bluetooth::packet::PacketView;
+using bluetooth::packet::View;
+using std::vector;
+
+namespace {
+vector<uint8_t> count_all = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+};
+
+vector<uint8_t> count_1 = {
+ 0x00,
+ 0x01,
+ 0x02,
+};
+
+vector<uint8_t> count_2 = {
+ 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+};
+
+vector<uint8_t> count_3 = {
+ 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+};
+} // namespace
+
+namespace bluetooth {
+namespace packet {
+
+template <typename T>
+class IteratorTest : public ::testing::Test {
+ public:
+ IteratorTest() = default;
+ ~IteratorTest() = default;
+
+ void SetUp() {
+ packet = std::shared_ptr<T>(new T({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())}));
+ }
+
+ void TearDown() {
+ packet.reset();
+ }
+
+ std::shared_ptr<T> packet;
+};
+
+using PacketViewTypes = ::testing::Types<PacketView<true>, PacketView<false>>;
+TYPED_TEST_CASE(IteratorTest, PacketViewTypes);
+
+class IteratorExtractTest : public ::testing::Test {
+ public:
+ IteratorExtractTest() = default;
+ ~IteratorExtractTest() = default;
+};
+
+template <typename T>
+class PacketViewTest : public IteratorTest<T> {
+ public:
+ PacketViewTest() = default;
+ ~PacketViewTest() = default;
+};
+
+using PacketViewTypes = ::testing::Types<PacketView<true>, PacketView<false>>;
+TYPED_TEST_CASE(PacketViewTest, PacketViewTypes);
+
+class PacketViewMultiViewTest : public ::testing::Test {
+ public:
+ PacketViewMultiViewTest() = default;
+ ~PacketViewMultiViewTest() = default;
+};
+
+class ViewTest : public ::testing::Test {
+ public:
+ ViewTest() = default;
+ ~ViewTest() = default;
+};
+
+TEST(IteratorExtractTest, extractLeTest) {
+ PacketView<true> packet({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
+ auto general_case = packet.begin();
+
+ ASSERT_EQ(0x00, general_case.extract<uint8_t>());
+ ASSERT_EQ(0x0201, general_case.extract<uint16_t>());
+ ASSERT_EQ(0x06050403u, general_case.extract<uint32_t>());
+ ASSERT_EQ(0x0e0d0c0b0a090807u, general_case.extract<uint64_t>());
+ ASSERT_EQ(0x0f, general_case.extract<uint8_t>());
+ Address raw({0x10, 0x11, 0x12, 0x13, 0x14, 0x15});
+ ASSERT_EQ(raw, general_case.extract<Address>());
+ ASSERT_EQ(0x16, general_case.extract<uint8_t>());
+}
+
+TEST(IteratorExtractTest, extractBeTest) {
+ PacketView<false> packet({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
+ auto general_case = packet.begin();
+
+ ASSERT_EQ(0x00, general_case.extract<uint8_t>());
+ ASSERT_EQ(0x0102, general_case.extract<uint16_t>());
+ ASSERT_EQ(0x03040506u, general_case.extract<uint32_t>());
+ ASSERT_EQ(0x0708090a0b0c0d0eu, general_case.extract<uint64_t>());
+ ASSERT_EQ(0x0f, general_case.extract<uint8_t>());
+ Address raw({0x15, 0x14, 0x13, 0x12, 0x11, 0x10});
+ ASSERT_EQ(raw, general_case.extract<Address>());
+ ASSERT_EQ(0x16, general_case.extract<uint8_t>());
+}
+
+TYPED_TEST(IteratorTest, extractBoundsDeathTest) {
+ auto bounds_test = this->packet->end();
+
+ ASSERT_DEATH(bounds_test.template extract<uint8_t>(), "");
+ ASSERT_DEATH(bounds_test.template extract<uint16_t>(), "");
+ ASSERT_DEATH(bounds_test.template extract<uint32_t>(), "");
+ ASSERT_DEATH(bounds_test.template extract<uint64_t>(), "");
+}
+
+TYPED_TEST(IteratorTest, dereferenceDeathTest) {
+ auto dereference_test = this->packet->end();
+
+ ASSERT_DEATH(*dereference_test, "");
+ ASSERT_EQ(0x1f, *(dereference_test - 1));
+}
+
+TYPED_TEST(IteratorTest, plusEqTest) {
+ auto plus_eq = this->packet->begin();
+ for (size_t i = 0; i < count_all.size(); i += 2) {
+ ASSERT_EQ(count_all[i], *plus_eq) << "+= test: Dereferenced iterator does not equal expected at index " << i;
+ plus_eq += 2;
+ }
+}
+
+TYPED_TEST(IteratorTest, preIncrementTest) {
+ auto plus_plus = this->packet->begin();
+ for (size_t i = 0; i < count_all.size() - 1; i++) {
+ ASSERT_EQ(count_all[i + 1], *(++plus_plus)) << "Pre-increment test: Dereferenced iterator does not equal expected "
+ << "at index " << i;
+ }
+}
+
+TYPED_TEST(IteratorTest, postIncrementTest) {
+ auto plus_plus = this->packet->begin();
+ for (size_t i = 0; i < count_all.size(); i++) {
+ ASSERT_EQ(count_all[i], *(plus_plus++)) << "Post-increment test: Dereferenced iterator does not equal expected "
+ << "at index " << i;
+ }
+}
+
+TYPED_TEST(IteratorTest, additionTest) {
+ auto plus = this->packet->begin();
+ for (size_t i = 0; i < count_all.size(); i++) {
+ ASSERT_EQ(count_all[i], *plus) << "+ test: Dereferenced iterator does not equal expected at index " << i;
+ plus = plus + 1;
+ }
+}
+
+TYPED_TEST(IteratorTest, minusEqTest) {
+ auto minus_eq = this->packet->end();
+ minus_eq -= 1;
+ size_t index = count_all.size() - 1;
+ for (size_t i = 0; index > i; i++) {
+ ASSERT_EQ(count_all[index], *minus_eq)
+ << "-= test: Dereferenced iterator does not equal expected at index " << index;
+ index -= i;
+ minus_eq -= i;
+ }
+}
+
+TYPED_TEST(IteratorTest, preDecrementTest) {
+ auto minus_minus = this->packet->end();
+ for (size_t i = count_all.size(); i > 0; i--) {
+ ASSERT_EQ(count_all[i - 1], *(--minus_minus))
+ << "Pre-decrement test: Dereferenced iterator does not equal expected "
+ << "at index " << i;
+ }
+}
+
+TYPED_TEST(IteratorTest, postDecrementTest) {
+ auto minus_minus = this->packet->end();
+ minus_minus--;
+ for (size_t i = count_all.size() - 1; i > 0; i--) {
+ ASSERT_EQ(count_all[i], *(minus_minus--)) << "Post-decrement test: Dereferenced iterator does not equal expected "
+ << "at index " << i;
+ }
+}
+
+TYPED_TEST(IteratorTest, subtractionTest) {
+ auto minus = this->packet->end();
+ minus = minus - 1;
+ for (size_t i = count_all.size() - 1; i > 0; i--) {
+ ASSERT_EQ(count_all[i], *minus) << "- test: Dereferenced iterator does not equal expected at index " << i;
+ minus = minus - 1;
+ }
+}
+
+TYPED_TEST(IteratorTest, differenceTest) {
+ auto begin = this->packet->begin();
+ auto end = this->packet->end();
+ int difference = end - begin;
+ ASSERT_EQ(difference, static_cast<int>(count_all.size()));
+ int neg_difference = begin - end;
+ ASSERT_EQ(neg_difference, -static_cast<int>(count_all.size()));
+}
+
+TYPED_TEST(IteratorTest, equalityTest) {
+ auto begin = this->packet->begin();
+ auto end = this->packet->end();
+ auto begin_copy = this->packet->begin();
+ auto end_copy = this->packet->end();
+ ASSERT_EQ(begin_copy, begin);
+ ASSERT_EQ(end_copy, end);
+}
+
+TYPED_TEST(IteratorTest, comparisonsTest) {
+ auto begin = this->packet->begin();
+ auto end = this->packet->end();
+ auto begin_copy = this->packet->begin();
+ auto end_copy = this->packet->end();
+ ASSERT_EQ(begin_copy, begin);
+ ASSERT_EQ(end_copy, end);
+ ASSERT_NE(begin, end);
+ ASSERT_TRUE(begin < end);
+ ASSERT_FALSE(end < end);
+ ASSERT_FALSE(end < begin);
+ ASSERT_FALSE(begin > end);
+ ASSERT_FALSE(end > end);
+ ASSERT_TRUE(end > begin);
+ ASSERT_TRUE(begin <= end);
+ ASSERT_TRUE(end <= end);
+ ASSERT_FALSE(end <= begin);
+ ASSERT_FALSE(begin >= end);
+ ASSERT_TRUE(end >= end);
+ ASSERT_TRUE(end >= begin);
+}
+
+TYPED_TEST(PacketViewTest, getLengthTest) {
+ size_t length = this->packet->size();
+ ASSERT_EQ(length, count_all.size());
+}
+
+TYPED_TEST(PacketViewTest, getAtIndexTest) {
+ size_t past_end = this->packet->size();
+ ASSERT_DEATH(this->packet->at(past_end), "");
+ size_t working_index = 0x1f;
+ ASSERT_EQ(0x1f, this->packet->at(working_index));
+}
+
+TYPED_TEST(PacketViewTest, arrayOperatorTest) {
+ size_t past_end = this->packet->size();
+ ASSERT_DEATH((*(this->packet))[past_end], "");
+ size_t working_index = 0x1f;
+ ASSERT_EQ(0x1f, (*(this->packet))[working_index]);
+}
+
+TYPED_TEST(PacketViewTest, numBytesRemainingTest) {
+ auto all = this->packet->begin();
+ size_t remaining = all.NumBytesRemaining();
+ for (size_t n = remaining; n > 0; n--) {
+ ASSERT_EQ(remaining, all.NumBytesRemaining());
+ all++;
+ remaining--;
+ }
+ ASSERT_EQ(static_cast<size_t>(0), all.NumBytesRemaining());
+ ASSERT_DEATH(*(all++), "");
+ all++;
+ ASSERT_EQ(static_cast<size_t>(0), all.NumBytesRemaining());
+ ASSERT_DEATH(*(all++), "");
+}
+
+using SubviewTestParam = std::pair<size_t, size_t>;
+class SubviewBaseTest : public ::testing::TestWithParam<SubviewTestParam> {
+ public:
+ class SubPacketView : public PacketView<true> {
+ public:
+ using PacketView<true>::PacketView;
+ PacketView<true> Slice(size_t header, size_t tail) {
+ return PacketView<true>::GetLittleEndianSubview(header, tail);
+ }
+ };
+};
+
+class SubviewPassTest : public SubviewBaseTest {};
+
+TEST_P(SubviewPassTest, subviewTest) {
+ auto header = GetParam().first;
+ auto tail = GetParam().second;
+ SubPacketView single_view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
+ SubPacketView multi_view({
+ View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
+ });
+
+ auto single_slice = single_view.Slice(header, tail);
+ auto multi_slice = multi_view.Slice(header, tail);
+
+ ASSERT_EQ(single_slice.size(), tail - header);
+ ASSERT_EQ(single_slice.size(), multi_slice.size());
+ for (size_t i = 0; i < single_slice.size(); i++) {
+ ASSERT_EQ(single_slice[i], multi_slice[i]);
+ }
+}
+
+static const size_t boundary_1 = count_1.size();
+static const size_t boundary_2 = count_1.size() + count_2.size();
+
+INSTANTIATE_TEST_CASE_P(
+ chopomatic, SubviewPassTest,
+ ::testing::Values(
+ // {begin, end} pairs for subsets into the PacketView
+ SubviewTestParam{0, 0}, SubviewTestParam{0, boundary_1}, SubviewTestParam{0, boundary_1 + 1},
+ SubviewTestParam{0, boundary_2}, SubviewTestParam{0, boundary_2 + 1}, SubviewTestParam{0, count_all.size()},
+ SubviewTestParam{boundary_1 - 1, boundary_1}, SubviewTestParam{boundary_1 - 1, boundary_1 + 1},
+ SubviewTestParam{boundary_1 - 1, boundary_2}, SubviewTestParam{boundary_1 - 1, boundary_2 + 1},
+ SubviewTestParam{boundary_1 - 1, count_all.size()}, SubviewTestParam{boundary_1, boundary_1},
+ SubviewTestParam{boundary_1, boundary_2}, SubviewTestParam{boundary_1, boundary_2 + 1},
+ SubviewTestParam{boundary_1, count_all.size()}, SubviewTestParam{boundary_2 - 1, boundary_2},
+ SubviewTestParam{boundary_2 - 1, boundary_2 + 1}, SubviewTestParam{boundary_2 - 1, count_all.size()},
+ SubviewTestParam{boundary_2, boundary_2}, SubviewTestParam{boundary_2, boundary_2 + 1},
+ SubviewTestParam{boundary_2, count_all.size()}, SubviewTestParam{count_all.size() - 1, count_all.size()},
+ SubviewTestParam{count_all.size(), count_all.size()}));
+
+class SubviewDeathTest : public SubviewBaseTest {};
+
+TEST_P(SubviewDeathTest, subviewDeathTest) {
+ auto header = GetParam().first;
+ auto tail = GetParam().second;
+ SubPacketView single_view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
+ SubPacketView multi_view({
+ View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
+ });
+
+ ASSERT_DEATH(auto single_slice = single_view.Slice(header, tail), "");
+ ASSERT_DEATH(auto multi_slice = multi_view.Slice(header, tail), "");
+}
+
+INSTANTIATE_TEST_CASE_P(chopomaticDeath, SubviewDeathTest,
+ ::testing::Values(
+ // {begin, end} pairs for subsets into the PacketView
+ SubviewTestParam{1, 0}, SubviewTestParam{count_all.size(), count_all.size() - 1},
+ SubviewTestParam{count_all.size(), count_all.size() + 1}));
+
+TEST(SubviewTest, simpleSubviewTest) {
+ PacketView<true> view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
+ PacketView<true> sub_1_view = view.GetLittleEndianSubview(0, view.size());
+ PacketView<true> sub_2_view = sub_1_view.GetLittleEndianSubview(0, sub_1_view.size());
+ PacketView<true> sub_3_view = sub_2_view.GetLittleEndianSubview(0, sub_2_view.size());
+ PacketView<true> sub_4_view = sub_3_view.GetLittleEndianSubview(0, sub_3_view.size());
+ ASSERT_EQ(sub_1_view.size(), view.size());
+ ASSERT_EQ(sub_2_view.size(), view.size());
+ ASSERT_EQ(sub_3_view.size(), view.size());
+ ASSERT_EQ(sub_4_view.size(), view.size());
+}
+
+TEST(SubviewTest, realSubviewTest) {
+ PacketView<true> view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
+ std::vector<PacketView<true>> sub_views{view};
+ for (size_t i = 1; i < 6; i++) {
+ size_t parent_size = sub_views[i - 1].size();
+ sub_views.push_back(sub_views[i - 1].GetLittleEndianSubview(1, parent_size - 1));
+ ASSERT_EQ(sub_views[i][0], i);
+ ASSERT_EQ(sub_views[i].size(), parent_size - 2);
+ }
+}
+
+TEST(SubviewTest, subSubviewTest) {
+ PacketView<true> single_view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
+ PacketView<true> multi_view({
+ View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
+ });
+ ASSERT_EQ(single_view.size(), multi_view.size());
+ for (size_t i = 0; i < count_all.size() / 2; i++) {
+ PacketView<true> sub_single_view = single_view.GetLittleEndianSubview(i, count_all.size() - i);
+ PacketView<true> sub_multi_view = multi_view.GetLittleEndianSubview(i, count_all.size() - i);
+ ASSERT_EQ(count_all.size() - 2 * i, sub_single_view.size());
+ ASSERT_EQ(sub_single_view.size(), sub_multi_view.size());
+ for (size_t j = 0; j < sub_single_view.size() / 2; j++) {
+ PacketView<true> sub_sub_single_view = sub_single_view.GetLittleEndianSubview(j, sub_single_view.size() - j);
+ PacketView<true> sub_sub_multi_view = sub_multi_view.GetLittleEndianSubview(j, sub_multi_view.size() - j);
+ ASSERT_EQ(sub_single_view.size() - 2 * j, sub_sub_single_view.size());
+ ASSERT_EQ(sub_sub_single_view.size(), sub_sub_multi_view.size());
+ }
+ }
+}
+
+TEST(PacketViewMultiViewTest, sizeTest) {
+ PacketView<true> single_view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
+ PacketView<true> multi_view({
+ View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
+ });
+ ASSERT_EQ(single_view.size(), multi_view.size());
+}
+
+TEST(PacketViewMultiViewTest, dereferenceTestLittleEndian) {
+ PacketView<true> single_view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
+ PacketView<true> multi_view({
+ View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
+ });
+ auto single_itr = single_view.begin();
+ auto multi_itr = multi_view.begin();
+ for (size_t i = 0; i < single_view.size(); i++) {
+ ASSERT_EQ(*(single_itr++), *(multi_itr++));
+ }
+ ASSERT_DEATH(*multi_itr, "");
+}
+
+TEST(PacketViewMultiViewTest, dereferenceTestBigEndian) {
+ PacketView<false> single_view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
+ PacketView<false> multi_view({
+ View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
+ });
+ auto single_itr = single_view.begin();
+ auto multi_itr = multi_view.begin();
+ for (size_t i = 0; i < single_view.size(); i++) {
+ ASSERT_EQ(*(single_itr++), *(multi_itr++));
+ }
+ ASSERT_DEATH(*multi_itr, "");
+}
+
+TEST(PacketViewMultiViewTest, arrayOperatorTest) {
+ PacketView<true> single_view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
+ PacketView<true> multi_view({
+ View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
+ });
+ for (size_t i = 0; i < single_view.size(); i++) {
+ ASSERT_EQ(single_view[i], multi_view[i]);
+ }
+ ASSERT_DEATH(multi_view[single_view.size()], "");
+}
+
+TEST(ViewTest, arrayOperatorTest) {
+ View view_all(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size());
+ size_t past_end = view_all.size();
+ for (size_t i = 0; i < past_end; i++) {
+ ASSERT_EQ(view_all[i], count_all[i]);
+ }
+ ASSERT_DEATH(view_all[past_end], "");
+
+ size_t header_size = 2;
+ size_t tail_size = 3;
+ View view_subset(std::make_shared<const vector<uint8_t>>(count_all), header_size, count_all.size() - tail_size);
+ View view_subset2(view_all, header_size, count_all.size() - tail_size);
+ size_t subset_length = view_subset.size();
+ for (size_t i = 0; i < subset_length; i++) {
+ ASSERT_EQ(view_subset[i], count_all[header_size + i]);
+ ASSERT_EQ(view_subset[i], view_subset2[i]);
+ }
+ ASSERT_DEATH(view_subset[subset_length + 1], "");
+ ASSERT_DEATH(view_subset2[subset_length + 1], "");
+}
+
+TEST(ViewTest, earlySubSubviewTest) {
+ View view(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size());
+ View sub_1_view(view, view.size() - 3, view.size() - 1);
+ View sub_2_view(sub_1_view, 1, 2);
+ ASSERT_EQ(sub_1_view.size(), 2u);
+ ASSERT_EQ(sub_2_view.size(), 1u);
+}
+
+TEST(ViewTest, subSubviewTest) {
+ View view(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size());
+ std::vector<View> sub_views{view};
+ for (size_t i = 1; i < 6; i++) {
+ size_t parent_size = sub_views[i - 1].size();
+ sub_views.push_back({View(sub_views[i - 1], 1, parent_size - 1)});
+ ASSERT_EQ(sub_views[i][0], i);
+ ASSERT_EQ(sub_views[i].size(), parent_size - 2);
+ }
+}
+
+TEST(ViewTest, zeroSubviewTest) {
+ View view(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size());
+ View subview(view, view.size(), view.size() + 1);
+ ASSERT_EQ(subview.size(), 0u);
+}
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/parser/Android.bp b/gd/packet/parser/Android.bp
new file mode 100644
index 0000000..133ce67
--- /dev/null
+++ b/gd/packet/parser/Android.bp
@@ -0,0 +1,42 @@
+cc_binary_host {
+ name: "bluetooth_packetgen",
+ srcs: [
+ "fields/array_field.cc",
+ "fields/body_field.cc",
+ "fields/checksum_field.cc",
+ "fields/checksum_start_field.cc",
+ "fields/custom_field.cc",
+ "fields/enum_field.cc",
+ "fields/fixed_field.cc",
+ "fields/group_field.cc",
+ "fields/packet_field.cc",
+ "fields/payload_field.cc",
+ "fields/reserved_field.cc",
+ "fields/scalar_field.cc",
+ "fields/size_field.cc",
+ "checksum_def.cc",
+ "custom_field_def.cc",
+ "enum_def.cc",
+ "enum_gen.cc",
+ "packet_def.cc",
+ "main.cc",
+ "language_y.yy",
+ "language_l.ll",
+ ],
+ static_libs: [
+ "libc++fs",
+ ],
+ cppflags: [
+ "-Wno-implicit-fallthrough",
+ "-fno-exceptions",
+ "-O0",
+ ],
+ ldflags: [
+ "-fuse-ld=ld",
+ "-O0",
+ ],
+ yacc: {
+ gen_location_hh: true,
+ gen_position_hh: true,
+ },
+}
diff --git a/gd/packet/parser/README b/gd/packet/parser/README
new file mode 100644
index 0000000..9006c94
--- /dev/null
+++ b/gd/packet/parser/README
@@ -0,0 +1,59 @@
+This file just contains some notes about the design and usage of the PDL language.
+
+-------
+ TERMS
+-------
+.pdl
+ The file type that defines packet definitions. You may think of each pdl file
+ as its own translation unit.
+
+Packet Views and Builders
+ Generated from a packet definition. Views are used to validate packets and
+ extract the fields that are defined in the pdl file. Builders check the input
+ arguments and can be serialized.
+
+Checksum types
+ checksum MyChecksumClass : 16 "path/to/the/class/"
+ Checksum fields need to implement the following three static methods:
+ static void Initialize(MyChecksumClass&);
+ static void AddByte(MyChecksumClass&, uint8_t);
+ // Assuming a 16-bit (uint16_t) checksum:
+ static uint16_t GetChecksum(MyChecksumClass&);
+-------------
+ LIMITATIONS
+-------------
+ - Size fields for a variable length field MUST come before the definition
+ of said field.
+
+ - Payload fields must be byte-aligned unless they have an unknown size.
+ Body fields are allowed to not be byte aligned.
+
+ - No conditionals
+
+ - Can not have to fields with the same name anywhere in the in an inheritence chain
+
+ - Can't handle size for Body type fields yet since they might not be byte aligned.
+
+ - Currently no arrays of custom types (might change later)
+
+-------
+ NOTES
+-------
+All field names should be in snake_case. Types should be in CamelCase.
+
+The _payload_ keyword generates a getter but _body_ doesn't. Therefore, a
+_payload_ must be byte aligned.
+
+Supports constraints on grandparents
+Supports multiple constraints
+Every field handles its own generation.
+One pdl file will result in one header file with all the packets
+
+Things to cover -
+ Constraints
+ Inheritence vs Contains
+
+Custom fields need the folowing functions:
+ static void Serialize(const Type&, MutableView&);
+ static std::optional<size_t> Size(Iterator);
+ static Type Parse(Iterator);
diff --git a/gd/packet/parser/checksum_def.cc b/gd/packet/parser/checksum_def.cc
new file mode 100644
index 0000000..38bd946
--- /dev/null
+++ b/gd/packet/parser/checksum_def.cc
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019 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 "checksum_def.h"
+
+#include "util.h"
+
+ChecksumDef::ChecksumDef(std::string name, std::string include, int size) : CustomFieldDef(name, include, size) {}
+
+PacketField* ChecksumDef::GetNewField(const std::string& name, ParseLocation loc) const {
+ return new ChecksumField(name, name_, size_, loc);
+}
+
+TypeDef::Type ChecksumDef::GetDefinitionType() const {
+ return TypeDef::Type::CHECKSUM;
+}
+
+void ChecksumDef::GenInclude(std::ostream& s) const {
+ CustomFieldDef::GenInclude(s);
+}
+
+void ChecksumDef::GenUsing(std::ostream& s) const {
+ CustomFieldDef::GenUsing(s);
+}
+
+void ChecksumDef::GenChecksumCheck(std::ostream& s) const {
+ s << "static_assert(ChecksumTypeChecker<" << name_ << "," << util::GetTypeForSize(size_) << ">::value, \"";
+ s << name_ << " is not a valid checksum type. Please see README for more details.\");";
+}
diff --git a/gd/packet/parser/checksum_def.h b/gd/packet/parser/checksum_def.h
new file mode 100644
index 0000000..d8f9142
--- /dev/null
+++ b/gd/packet/parser/checksum_def.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019 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 <iostream>
+
+#include "checksum_type_checker.h"
+#include "custom_field_def.h"
+#include "fields/checksum_field.h"
+#include "parse_location.h"
+#include "type_def.h"
+
+class ChecksumDef : public CustomFieldDef {
+ public:
+ ChecksumDef(std::string name, std::string include, int size);
+
+ virtual PacketField* GetNewField(const std::string& name, ParseLocation loc) const override;
+
+ virtual TypeDef::Type GetDefinitionType() const override;
+
+ virtual void GenInclude(std::ostream& s) const override;
+
+ virtual void GenUsing(std::ostream& s) const override;
+
+ void GenChecksumCheck(std::ostream& s) const;
+
+ const std::string include_;
+};
diff --git a/gd/packet/parser/checksum_type_checker.h b/gd/packet/parser/checksum_type_checker.h
new file mode 100644
index 0000000..a19ea59
--- /dev/null
+++ b/gd/packet/parser/checksum_type_checker.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2019 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 <optional>
+
+namespace bluetooth {
+namespace packet {
+namespace parser {
+
+// Checks for Initialize(), AddByte(), and GetChecksum().
+// T and TRET are the checksum class Type and the checksum return type
+// C and CRET are the substituted types for T and TRET
+template <typename T, typename TRET>
+class ChecksumTypeChecker {
+ public:
+ template <class C, void (*)(C&)>
+ struct InitializeChecker {};
+
+ template <class C, void (*)(C&, uint8_t byte)>
+ struct AddByteChecker {};
+
+ template <class C, typename CRET, CRET (*)(const C&)>
+ struct GetChecksumChecker {};
+
+ // If all the methods are defined, this one matches
+ template <class C, typename CRET>
+ static int Test(InitializeChecker<C, &C::Initialize>*, AddByteChecker<C, &C::AddByte>*,
+ GetChecksumChecker<C, CRET, &C::GetChecksum>*);
+
+ // This one matches everything else
+ template <class C, typename CRET>
+ static char Test(...);
+
+ // This checks which template was matched
+ static constexpr bool value = (sizeof(Test<T, TRET>(0, 0, 0)) == sizeof(int));
+};
+} // namespace parser
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/parser/custom_field_def.cc b/gd/packet/parser/custom_field_def.cc
new file mode 100644
index 0000000..9429e3f
--- /dev/null
+++ b/gd/packet/parser/custom_field_def.cc
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 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 "custom_field_def.h"
+
+#include "util.h"
+
+CustomFieldDef::CustomFieldDef(std::string name, std::string include, int size)
+ : TypeDef(name, size), include_(include) {
+ if (size % 8 != 0) {
+ ERROR() << "Custom fields must be byte aligned.";
+ }
+}
+
+PacketField* CustomFieldDef::GetNewField(const std::string& name, ParseLocation loc) const {
+ return new CustomField(name, name_, size_, loc);
+}
+
+TypeDef::Type CustomFieldDef::GetDefinitionType() const {
+ return TypeDef::Type::CUSTOM;
+}
+
+void CustomFieldDef::GenInclude(std::ostream& s) const {
+ s << "#include \"" << include_ << util::CamelCaseToUnderScore(GetTypeName()) << ".h\"\n";
+}
+
+void CustomFieldDef::GenUsing(std::ostream& s) const {
+ s << "using ::bluetooth::";
+ for (const auto& c : include_) {
+ switch (c) {
+ case '/':
+ s << "::";
+ break;
+ default:
+ s << c;
+ }
+ }
+ s << GetTypeName() << ";";
+}
diff --git a/gd/packet/parser/custom_field_def.h b/gd/packet/parser/custom_field_def.h
new file mode 100644
index 0000000..156ac8a
--- /dev/null
+++ b/gd/packet/parser/custom_field_def.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2019 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 <iostream>
+
+#include "fields/custom_field.h"
+#include "parse_location.h"
+#include "type_def.h"
+
+class CustomFieldDef : public TypeDef {
+ public:
+ CustomFieldDef(std::string name, std::string include, int size);
+
+ virtual PacketField* GetNewField(const std::string& name, ParseLocation loc) const override;
+
+ virtual Type GetDefinitionType() const override;
+
+ virtual void GenInclude(std::ostream& s) const;
+
+ virtual void GenUsing(std::ostream& s) const;
+
+ const std::string include_;
+};
diff --git a/gd/packet/parser/declarations.h b/gd/packet/parser/declarations.h
new file mode 100644
index 0000000..1a344f0
--- /dev/null
+++ b/gd/packet/parser/declarations.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2019 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 <deque>
+#include <map>
+#include <optional>
+
+#include "checksum_def.h"
+#include "custom_field_def.h"
+#include "enum_def.h"
+#include "enum_gen.h"
+#include "packet_def.h"
+
+class Declarations {
+ public:
+ void AddTypeDef(std::string name, TypeDef* def) {
+ type_defs_.insert(std::pair(name, def));
+ type_defs_queue_.push_back(std::pair(name, def));
+ }
+
+ TypeDef* GetTypeDef(const std::string& name) {
+ auto it = type_defs_.find(name);
+ if (it == type_defs_.end()) {
+ return nullptr;
+ }
+
+ return it->second;
+ }
+
+ void AddPacketDef(std::string name, PacketDef def) {
+ packet_defs_.insert(std::pair(name, def));
+ packet_defs_queue_.push_back(std::pair(name, def));
+ }
+
+ PacketDef* GetPacketDef(const std::string& name) {
+ auto it = packet_defs_.find(name);
+ if (it == packet_defs_.end()) {
+ return nullptr;
+ }
+
+ return &(it->second);
+ }
+
+ void AddGroupDef(std::string name, FieldList* group_def) {
+ group_defs_.insert(std::pair(name, group_def));
+ }
+
+ FieldList* GetGroupDef(std::string name) {
+ if (group_defs_.find(name) == group_defs_.end()) {
+ return nullptr;
+ }
+
+ return group_defs_.at(name);
+ }
+
+ std::map<std::string, FieldList*> group_defs_;
+
+ std::map<std::string, TypeDef*> type_defs_;
+ std::deque<std::pair<std::string, TypeDef*>> type_defs_queue_;
+ std::map<std::string, PacketDef> packet_defs_;
+ std::deque<std::pair<std::string, PacketDef>> packet_defs_queue_;
+ bool is_little_endian;
+};
diff --git a/gd/packet/parser/enum_def.cc b/gd/packet/parser/enum_def.cc
new file mode 100644
index 0000000..410af15
--- /dev/null
+++ b/gd/packet/parser/enum_def.cc
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2019 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 "enum_def.h"
+
+#include <iostream>
+#include <map>
+
+#include "fields/enum_field.h"
+#include "util.h"
+
+EnumDef::EnumDef(std::string name, int size) : TypeDef(name, size){};
+
+void EnumDef::AddEntry(std::string name, uint32_t value) {
+ if (value > util::GetMaxValueForBits(size_)) {
+ std::cerr << __func__ << ": Value provided is greater than max possible value for enum. " << name_ << "\n";
+ abort();
+ }
+
+ constants_.insert(std::pair(value, name));
+ entries_.insert(name);
+}
+
+PacketField* EnumDef::GetNewField(const std::string& name, ParseLocation loc) const {
+ return new EnumField(name, *this, "What is this for", loc);
+}
+
+bool EnumDef::HasEntry(std::string name) const {
+ return entries_.count(name) != 0;
+}
+
+TypeDef::Type EnumDef::GetDefinitionType() const {
+ return TypeDef::Type::ENUM;
+}
+
+void EnumDef::GenInclude(std::ostream&) const {}
+
+void EnumDef::GenUsing(std::ostream&) const {}
diff --git a/gd/packet/parser/enum_def.h b/gd/packet/parser/enum_def.h
new file mode 100644
index 0000000..97989e6
--- /dev/null
+++ b/gd/packet/parser/enum_def.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019 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 <map>
+#include <set>
+#include <string>
+
+#include "fields/packet_field.h"
+#include "type_def.h"
+
+// Holds the definition of an enum.
+class EnumDef : public TypeDef {
+ public:
+ EnumDef(std::string name, int size);
+
+ virtual PacketField* GetNewField(const std::string& name, ParseLocation loc) const;
+
+ void AddEntry(std::string name, uint32_t value);
+
+ bool HasEntry(std::string name) const;
+
+ virtual Type GetDefinitionType() const override;
+
+ virtual void GenInclude(std::ostream& s) const override;
+
+ virtual void GenUsing(std::ostream& s) const override;
+
+ // data
+ std::map<uint32_t, std::string> constants_;
+ std::set<std::string> entries_;
+};
diff --git a/gd/packet/parser/enum_gen.cc b/gd/packet/parser/enum_gen.cc
new file mode 100644
index 0000000..769a43a
--- /dev/null
+++ b/gd/packet/parser/enum_gen.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2019 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 "enum_gen.h"
+
+#include <iostream>
+
+#include "util.h"
+
+EnumGen::EnumGen(EnumDef e) : e_(e){};
+
+void EnumGen::GenDefinition(std::ostream& stream) {
+ stream << "enum class ";
+ stream << e_.name_;
+ stream << " : " << util::GetTypeForSize(e_.size_);
+ stream << " {";
+ for (const auto& pair : e_.constants_) {
+ stream << pair.second << " = 0x" << std::hex << pair.first << std::dec << ",";
+ }
+ stream << "};\n";
+}
+
+void EnumGen::GenLogging(std::ostream& stream) {
+ // Print out the switch statement that converts all the constants to strings.
+ stream << "inline std::string " << e_.name_ << "Text(const " << e_.name_ << "& param) {";
+ stream << "switch (param) {";
+ for (const auto& pair : e_.constants_) {
+ stream << "case " << e_.name_ << "::" << pair.second << ":";
+ stream << " return \"" << pair.second << "\";";
+ }
+ stream << "default:";
+ stream << " return std::string(\"Unknown " << e_.name_ << ": \") + std::to_string(static_cast<int>(param));";
+ stream << "}";
+ stream << "}\n\n";
+
+ // Print out the stream operator so that the constant can be written to streams.
+ stream << "inline std::ostream& operator<<(std::ostream& os, const " << e_.name_ << "& param) {";
+ stream << " return os << " << e_.name_ << "Text(param);";
+ stream << "}\n";
+}
diff --git a/gd/packet/parser/enum_gen.h b/gd/packet/parser/enum_gen.h
new file mode 100644
index 0000000..f3483dd
--- /dev/null
+++ b/gd/packet/parser/enum_gen.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2019 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 <iostream>
+
+#include "enum_def.h"
+
+// Generates the C++ code for an enum.
+class EnumGen {
+ public:
+ EnumGen(EnumDef e);
+
+ void GenDefinition(std::ostream& stream);
+
+ void GenLogging(std::ostream& stream);
+
+ EnumDef e_;
+};
diff --git a/gd/packet/parser/field_list.h b/gd/packet/parser/field_list.h
new file mode 100644
index 0000000..1cd7df4
--- /dev/null
+++ b/gd/packet/parser/field_list.h
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2019 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 <map>
+#include <set>
+#include <vector>
+
+#include "fields/packet_field.h"
+
+using FieldListIterator = std::vector<PacketField*>::const_iterator;
+using ReverseFieldListIterator = std::vector<PacketField*>::const_reverse_iterator;
+
+class FieldList {
+ public:
+ FieldList() = default;
+
+ FieldList(std::vector<PacketField*> fields) {
+ for (PacketField* field : fields) {
+ AppendField(field);
+ }
+ }
+
+ template <class Iterator>
+ FieldList(Iterator begin, Iterator end) {
+ while (begin != end) {
+ AppendField(*begin);
+ begin++;
+ }
+ }
+
+ PacketField* operator[](int index) const {
+ return field_list_[index];
+ }
+
+ PacketField* GetField(std::string field_name) const {
+ auto it = field_map_.find(field_name);
+ if (it == field_map_.end()) {
+ return nullptr;
+ }
+
+ return it->second;
+ }
+
+ void AppendField(PacketField* field) {
+ AddField(field);
+ field_list_.push_back(field);
+ }
+
+ void PrependField(PacketField* field) {
+ AddField(field);
+ field_list_.insert(field_list_.begin(), field);
+ }
+
+ FieldList GetFieldsBeforePayloadOrBody() const {
+ FieldList ret;
+ for (auto it = begin(); it != end(); it++) {
+ const auto& field = *it;
+ if (field->GetFieldType() == PacketField::Type::PAYLOAD || field->GetFieldType() == PacketField::Type::BODY) {
+ break;
+ }
+ ret.AppendField(*it);
+ }
+
+ return ret;
+ }
+
+ FieldList GetFieldsAfterPayloadOrBody() const {
+ FieldListIterator it;
+ for (it = begin(); it != end(); it++) {
+ const auto& field = *it;
+ if (field->GetFieldType() == PacketField::Type::PAYLOAD || field->GetFieldType() == PacketField::Type::BODY) {
+ // Increment it once to get first field after payload/body.
+ it++;
+ break;
+ }
+ }
+
+ return FieldList(it, end());
+ }
+
+ FieldList GetFieldsWithTypes(std::set<PacketField::Type> field_types) const {
+ FieldList ret;
+
+ for (const auto& field : field_list_) {
+ if (field_types.find(field->GetFieldType()) != field_types.end()) {
+ ret.AppendField(field);
+ }
+ }
+
+ return ret;
+ }
+
+ FieldList GetFieldsWithoutTypes(std::set<PacketField::Type> field_types) const {
+ FieldList ret;
+
+ for (const auto& field : field_list_) {
+ if (field_types.find(field->GetFieldType()) == field_types.end()) {
+ ret.AppendField(field);
+ }
+ }
+
+ return ret;
+ }
+
+ // Appends header fields of param to header fields of the current and
+ // prepends footer fields of the param to footer fields of the current.
+ // Ex. Assuming field_list_X has the layout:
+ // field_list_X_header
+ // payload/body
+ // field_list_X_footer
+ // The call to field_list_1.Merge(field_list_2) would result in
+ // field_list_1_header
+ // field_list_2_header
+ // payload/body (uses whatever was in field_list_2)
+ // field_list_2_footer
+ // field_list_1_footer
+ FieldList Merge(FieldList nested) const {
+ FieldList ret;
+
+ for (const auto& field : GetFieldsBeforePayloadOrBody()) {
+ ret.AppendField(field);
+ }
+
+ for (const auto& field : nested) {
+ ret.AppendField(field);
+ }
+
+ for (const auto& field : GetFieldsAfterPayloadOrBody()) {
+ ret.AppendField(field);
+ }
+
+ return ret;
+ }
+
+ bool HasPayloadOrBody() const {
+ return has_payload_ || has_body_;
+ }
+
+ bool HasPayload() const {
+ return has_payload_;
+ }
+
+ bool HasBody() const {
+ return has_body_;
+ }
+
+ FieldListIterator begin() const {
+ return field_list_.begin();
+ }
+
+ FieldListIterator end() const {
+ return field_list_.end();
+ }
+
+ ReverseFieldListIterator rbegin() const {
+ return field_list_.rbegin();
+ }
+
+ ReverseFieldListIterator rend() const {
+ return field_list_.rend();
+ }
+
+ size_t size() const {
+ return field_list_.size();
+ }
+
+ private:
+ void AddField(PacketField* field) {
+ if (field_map_.find(field->GetName()) != field_map_.end()) {
+ ERROR(field) << "Field with name \"" << field->GetName() << "\" was "
+ << "previously defined.\n";
+ }
+
+ if (field->GetFieldType() == PacketField::Type::PAYLOAD) {
+ if (HasBody()) {
+ ERROR(field) << "Can not have payload field in packet that already has a body.";
+ }
+ has_payload_ = true;
+ }
+
+ if (field->GetFieldType() == PacketField::Type::BODY) {
+ if (HasPayload()) {
+ ERROR(field) << "Can not have body field in packet that already has a payload.";
+ }
+ has_body_ = true;
+ }
+
+ field_map_.insert(std::pair(field->GetName(), field));
+ }
+
+ std::vector<PacketField*> field_list_;
+ std::map<std::string, PacketField*> field_map_;
+ bool has_payload_ = false;
+ bool has_body_ = false;
+};
diff --git a/gd/packet/parser/fields/all_fields.h b/gd/packet/parser/fields/all_fields.h
new file mode 100644
index 0000000..e8de77e
--- /dev/null
+++ b/gd/packet/parser/fields/all_fields.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2019 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 "fields/array_field.h"
+#include "fields/body_field.h"
+#include "fields/checksum_field.h"
+#include "fields/checksum_start_field.h"
+#include "fields/custom_field.h"
+#include "fields/enum_field.h"
+#include "fields/fixed_field.h"
+#include "fields/group_field.h"
+#include "fields/payload_field.h"
+#include "fields/reserved_field.h"
+#include "fields/scalar_field.h"
+#include "fields/size_field.h"
diff --git a/gd/packet/parser/fields/array_field.cc b/gd/packet/parser/fields/array_field.cc
new file mode 100644
index 0000000..bce768f
--- /dev/null
+++ b/gd/packet/parser/fields/array_field.cc
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2019 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 "fields/array_field.h"
+#include "util.h"
+
+ArrayField::ArrayField(std::string name, int element_size, std::string size_modifier, ParseLocation loc)
+ : PacketField(loc, name), element_size_(element_size), size_modifier_(size_modifier) {
+ // Make sure the element_size is a multiple of 8.
+ if (element_size % 8 != 0) ERROR(this) << "Can only have arrays with elements that are byte aligned.";
+}
+
+ArrayField::ArrayField(std::string name, int element_size, int fixed_size, ParseLocation loc)
+ : PacketField(loc, name), element_size_(element_size), fixed_size_(fixed_size) {
+ // Make sure the element_size is a multiple of 8.
+ if (element_size % 8 != 0) ERROR(this) << "Can only have arrays with elements that are byte aligned.";
+}
+
+ArrayField::ArrayField(std::string name, TypeDef* type_def, std::string size_modifier, ParseLocation loc)
+ : PacketField(loc, name), element_size_(type_def->size_), type_def_(type_def), size_modifier_(size_modifier) {
+ // If it is an enum array, make sure that the enum definition is byte aligned.
+ if (type_def_->size_ % 8 != 0) ERROR(this) << "Can only have arrays with elements that are byte aligned.";
+}
+
+ArrayField::ArrayField(std::string name, TypeDef* type_def, int fixed_size, ParseLocation loc)
+ : PacketField(loc, name), element_size_(type_def->size_), type_def_(type_def), fixed_size_(fixed_size) {
+ // If it is an enum array, make sure that the enum definition is byte aligned.
+ if (type_def_->size_ % 8 != 0) ERROR(this) << "Can only have arrays with elements that are byte aligned.";
+}
+
+PacketField::Type ArrayField::GetFieldType() const {
+ return PacketField::Type::ARRAY;
+}
+
+Size ArrayField::GetSize() const {
+ if (IsFixedSize() && element_size_ != -1) {
+ return Size(fixed_size_ * element_size_);
+ }
+
+ // If there is no size field, then it is of unknown size.
+ if (size_field_ == nullptr) {
+ return Size();
+ }
+
+ // size_field_ is of type SIZE
+ if (size_field_->GetFieldType() == PacketField::Type::SIZE) {
+ std::string ret = "Get" + util::UnderscoreToCamelCase(size_field_->GetName()) + "()";
+ if (!size_modifier_.empty()) ret += size_modifier_;
+ return ret;
+ }
+
+ // size_field_ is of type COUNT and it is a scalar array
+ if (!IsEnumArray() && !IsCustomFieldArray()) {
+ return "(Get" + util::UnderscoreToCamelCase(size_field_->GetName()) + "() * " + std::to_string(element_size_ / 8) +
+ ")";
+ }
+
+ if (IsCustomFieldArray()) {
+ return "(Get" + util::UnderscoreToCamelCase(size_field_->GetName()) + "() * " +
+ std::to_string(type_def_->size_ / 8) + ")";
+ }
+
+ // size_field_ is of type COUNT and it is an enum array
+ return "(Get" + util::UnderscoreToCamelCase(size_field_->GetName()) + "() * " + std::to_string(type_def_->size_ / 8) +
+ ")";
+}
+
+std::string ArrayField::GetType() const {
+ if (type_def_ != nullptr) {
+ return "std::vector<" + type_def_->name_ + ">";
+ }
+ return "std::vector<" + util::GetTypeForSize(element_size_) + ">";
+}
+
+void ArrayField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const {
+ if (start_offset.empty()) {
+ ERROR(this) << "Can not have an array with an ambiguous start offset.";
+ }
+
+ if (start_offset.bits() % 8 != 0) {
+ ERROR(this) << "Can not have an array that isn't byte aligned.";
+ }
+
+ if (GetSize().empty() && end_offset.empty()) {
+ ERROR(this) << "Ambiguous end offset for array with no defined size.";
+ }
+
+ s << GetType();
+ s << " Get" << util::UnderscoreToCamelCase(GetName()) << "() {";
+ s << "ASSERT(was_validated_);";
+
+ s << "auto it = begin() + " << start_offset.bytes() << " + " << start_offset.dynamic_string() << ";";
+
+ if (!GetSize().empty()) {
+ auto size = GetSize();
+ s << "auto array_end = it + " << size.bytes() << " /* bytes */ + " << size.dynamic_string() << ";";
+ } else {
+ s << "auto array_end = end() - " << end_offset.bytes() << " /* bytes */ - " << end_offset.dynamic_string() << ";";
+ }
+
+ // Add the element size so that we will extract as many elements as we can.
+ s << GetType() << " ret;";
+ std::string type = (type_def_ != nullptr) ? type_def_->name_ : util::GetTypeForSize(element_size_);
+ s << "while (it + sizeof(" << type << ") <= array_end) {";
+ s << "ret.push_back(it.extract<" << type << ">());";
+ s << "}";
+
+ s << "return ret;";
+ s << "}\n";
+}
+
+bool ArrayField::GenBuilderParameter(std::ostream& s) const {
+ std::string element_type = "";
+ if (type_def_ != nullptr) {
+ element_type = type_def_->GetTypeName();
+ } else {
+ if (element_size_ > 64 || element_size_ < 0)
+ ERROR(this) << __func__ << ": Not implemented for element size = " << element_size_;
+ element_type = util::GetTypeForSize(element_size_);
+ }
+
+ s << "const std::vector<" << element_type << ">& " << GetName();
+ return true;
+}
+
+bool ArrayField::HasParameterValidator() const {
+ if (fixed_size_ == -1) {
+ // Does not have parameter validator yet.
+ // TODO: See comment in GenParameterValidator
+ return false;
+ }
+ return true;
+}
+
+void ArrayField::GenParameterValidator(std::ostream& s) const {
+ if (fixed_size_ == -1) {
+ // No Parameter validator if its dynamically size.
+ // TODO: Maybe add a validator to ensure that the size isn't larger than what the size field can hold.
+ return;
+ }
+
+ s << "ASSERT(" << GetName() << ".size() == " << fixed_size_ << ");";
+}
+
+void ArrayField::GenInserter(std::ostream& s) const {
+ s << "for (const auto& val : " << GetName() << "_) {";
+ if (IsEnumArray()) {
+ s << "insert(static_cast<" << util::GetTypeForSize(type_def_->size_) << ">(val), i, " << type_def_->size_ << ");";
+ } else if (IsCustomFieldArray()) {
+ s << "insert(val, i);";
+ } else {
+ s << "insert(val, i, " << element_size_ << ");";
+ }
+ s << "}\n";
+}
+
+void ArrayField::GenValidator(std::ostream&) const {
+ // NOTE: We could check if the element size divides cleanly into the array size, but we decided to forgo that
+ // in favor of just returning as many elements as possible in a best effort style.
+ //
+ // Other than that there is nothing that arrays need to be validated on other than length so nothing needs to
+ // be done here.
+}
+
+bool ArrayField::IsEnumArray() const {
+ return type_def_ != nullptr && type_def_->GetDefinitionType() == TypeDef::Type::ENUM;
+}
+
+bool ArrayField::IsCustomFieldArray() const {
+ return type_def_ != nullptr && type_def_->GetDefinitionType() == TypeDef::Type::CUSTOM;
+}
+
+bool ArrayField::IsFixedSize() const {
+ return fixed_size_ != -1;
+}
+
+void ArrayField::SetSizeField(const SizeField* size_field) {
+ if (size_field->GetFieldType() == PacketField::Type::COUNT && !size_modifier_.empty()) {
+ ERROR(this, size_field) << "Can not use count field to describe array with a size modifier."
+ << " Use size instead";
+ }
+
+ if (IsFixedSize()) {
+ ERROR(this, size_field) << "Can not use size field with a fixed size array.";
+ }
+
+ size_field_ = size_field;
+}
+
+const std::string& ArrayField::GetSizeModifier() const {
+ return size_modifier_;
+}
diff --git a/gd/packet/parser/fields/array_field.h b/gd/packet/parser/fields/array_field.h
new file mode 100644
index 0000000..c348878
--- /dev/null
+++ b/gd/packet/parser/fields/array_field.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2019 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 "custom_field_def.h"
+#include "enum_def.h"
+#include "fields/packet_field.h"
+#include "fields/size_field.h"
+#include "parse_location.h"
+//#include "struct_def.h"
+
+class ArrayField : public PacketField {
+ public:
+ ArrayField(std::string name, int element_size, std::string size_modifier, ParseLocation loc);
+
+ ArrayField(std::string name, int element_size, int fixed_size, ParseLocation loc);
+
+ ArrayField(std::string name, TypeDef* type_def, std::string size_modifier, ParseLocation loc);
+
+ ArrayField(std::string name, TypeDef* type_def, int fixed_size, ParseLocation loc);
+
+ virtual PacketField::Type GetFieldType() const override;
+
+ virtual Size GetSize() const override;
+
+ virtual std::string GetType() const override;
+
+ virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+ virtual bool GenBuilderParameter(std::ostream& s) const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream& s) const override;
+
+ virtual void GenInserter(std::ostream& s) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+
+ bool IsEnumArray() const;
+
+ bool IsCustomFieldArray() const;
+
+ bool IsFixedSize() const;
+
+ void SetSizeField(const SizeField* size_field);
+
+ const std::string& GetSizeModifier() const;
+
+ const std::string name_;
+
+ const int element_size_{-1}; // units is bits
+ const TypeDef* type_def_{nullptr};
+
+ // Fixed size array or dynamic size, size is always in bytes, unless it is count.
+ const int fixed_size_{-1};
+ const SizeField* size_field_{nullptr};
+
+ // Size modifier is only used when size_field_ is of type SIZE and is not used with COUNT.
+ std::string size_modifier_{""};
+};
diff --git a/gd/packet/parser/fields/body_field.cc b/gd/packet/parser/fields/body_field.cc
new file mode 100644
index 0000000..6ed1d24
--- /dev/null
+++ b/gd/packet/parser/fields/body_field.cc
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2019 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 "fields/body_field.h"
+
+BodyField::BodyField(ParseLocation loc) : PacketField(loc, "body") {}
+
+PacketField::Type BodyField::GetFieldType() const {
+ return PacketField::Type::BODY;
+}
+
+Size BodyField::GetSize() const {
+ return Size(0);
+}
+
+std::string BodyField::GetType() const {
+ ERROR(this) << "No need to know the type of a body field.";
+ return "BodyType";
+}
+
+void BodyField::GenGetter(std::ostream&, Size, Size) const {}
+
+bool BodyField::GenBuilderParameter(std::ostream&) const {
+ return false;
+}
+
+bool BodyField::HasParameterValidator() const {
+ return false;
+}
+
+void BodyField::GenParameterValidator(std::ostream&) const {
+ // There is no validation needed for a payload
+}
+
+void BodyField::GenInserter(std::ostream&) const {
+ // Do nothing
+}
+
+void BodyField::GenValidator(std::ostream&) const {
+ // Do nothing
+}
diff --git a/gd/packet/parser/fields/body_field.h b/gd/packet/parser/fields/body_field.h
new file mode 100644
index 0000000..9cc2301
--- /dev/null
+++ b/gd/packet/parser/fields/body_field.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019 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 "fields/packet_field.h"
+#include "fields/size_field.h"
+#include "parse_location.h"
+
+class BodyField : public PacketField {
+ public:
+ BodyField(ParseLocation loc);
+
+ virtual PacketField::Type GetFieldType() const override;
+
+ virtual Size GetSize() const override;
+
+ virtual std::string GetType() const override;
+
+ virtual void GenGetter(std::ostream&, Size, Size) const override;
+
+ virtual bool GenBuilderParameter(std::ostream&) const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream&) const override;
+
+ virtual void GenInserter(std::ostream&) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+};
diff --git a/gd/packet/parser/fields/checksum_field.cc b/gd/packet/parser/fields/checksum_field.cc
new file mode 100644
index 0000000..4a29e4d
--- /dev/null
+++ b/gd/packet/parser/fields/checksum_field.cc
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2019 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 "fields/checksum_field.h"
+#include "util.h"
+
+ChecksumField::ChecksumField(std::string name, std::string type_name, int size, ParseLocation loc)
+ : PacketField(loc, name), type_name_(type_name), size_(size) {}
+
+PacketField::Type ChecksumField::GetFieldType() const {
+ return PacketField::Type::CHECKSUM;
+}
+
+Size ChecksumField::GetSize() const {
+ return size_;
+}
+
+std::string ChecksumField::GetType() const {
+ return type_name_;
+}
+
+void ChecksumField::GenGetter(std::ostream&, Size, Size) const {}
+
+bool ChecksumField::GenBuilderParameter(std::ostream&) const {
+ return false;
+}
+
+bool ChecksumField::HasParameterValidator() const {
+ return false;
+}
+
+void ChecksumField::GenParameterValidator(std::ostream&) const {
+ // Do nothing.
+}
+
+void ChecksumField::GenInserter(std::ostream& s) const {
+ s << "packet::ByteObserver observer = i.UnregisterObserver();";
+ s << "insert(static_cast<" << util::GetTypeForSize(size_) << ">(observer.GetValue()), i);";
+}
+
+void ChecksumField::GenValidator(std::ostream&) const {
+ // Done in packet_def.cc
+}
diff --git a/gd/packet/parser/fields/checksum_field.h b/gd/packet/parser/fields/checksum_field.h
new file mode 100644
index 0000000..5bf3923
--- /dev/null
+++ b/gd/packet/parser/fields/checksum_field.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2019 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 "fields/packet_field.h"
+#include "parse_location.h"
+
+class ChecksumField : public PacketField {
+ public:
+ ChecksumField(std::string name, std::string type_name, int size, ParseLocation loc);
+
+ virtual PacketField::Type GetFieldType() const override;
+
+ virtual Size GetSize() const override;
+
+ virtual std::string GetType() const override;
+
+ virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+ virtual bool GenBuilderParameter(std::ostream& s) const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream&) const override;
+
+ virtual void GenInserter(std::ostream& s) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+
+ private:
+ std::string type_name_;
+
+ public:
+ const int size_{-1};
+};
diff --git a/gd/packet/parser/fields/checksum_start_field.cc b/gd/packet/parser/fields/checksum_start_field.cc
new file mode 100644
index 0000000..75438f2
--- /dev/null
+++ b/gd/packet/parser/fields/checksum_start_field.cc
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2019 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 "fields/checksum_start_field.h"
+#include "util.h"
+
+ChecksumStartField::ChecksumStartField(std::string name, ParseLocation loc)
+ : PacketField(loc, name + "_start"), started_field_name_(name) {}
+
+PacketField::Type ChecksumStartField::GetFieldType() const {
+ return PacketField::Type::CHECKSUM_START;
+}
+
+Size ChecksumStartField::GetSize() const {
+ return Size(0);
+}
+
+std::string ChecksumStartField::GetType() const {
+ return "There's no type for Checksum Start fields";
+}
+
+void ChecksumStartField::GenGetter(std::ostream&, Size, Size) const {}
+
+bool ChecksumStartField::GenBuilderParameter(std::ostream&) const {
+ // There is no builder parameter for a size field
+ return false;
+}
+
+bool ChecksumStartField::HasParameterValidator() const {
+ return false;
+}
+
+void ChecksumStartField::GenParameterValidator(std::ostream&) const {}
+
+void ChecksumStartField::GenInserter(std::ostream&) const {
+ ERROR(this) << __func__ << ": This should not be called for checksum start fields";
+}
+
+void ChecksumStartField::GenValidator(std::ostream&) const {}
+
+std::string ChecksumStartField::GetStartedFieldName() const {
+ return started_field_name_;
+}
diff --git a/gd/packet/parser/fields/checksum_start_field.h b/gd/packet/parser/fields/checksum_start_field.h
new file mode 100644
index 0000000..248c146
--- /dev/null
+++ b/gd/packet/parser/fields/checksum_start_field.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2019 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 "fields/packet_field.h"
+#include "parse_location.h"
+
+class ChecksumStartField : public PacketField {
+ public:
+ ChecksumStartField(std::string name, ParseLocation loc);
+
+ std::string GetField() const;
+
+ virtual PacketField::Type GetFieldType() const override;
+
+ virtual Size GetSize() const override;
+
+ virtual std::string GetType() const override;
+
+ virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+ virtual bool GenBuilderParameter(std::ostream&) const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream&) const override;
+
+ virtual void GenInserter(std::ostream&) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+
+ virtual std::string GetStartedFieldName() const;
+
+ private:
+ std::string started_field_name_;
+};
diff --git a/gd/packet/parser/fields/custom_field.cc b/gd/packet/parser/fields/custom_field.cc
new file mode 100644
index 0000000..05952ab
--- /dev/null
+++ b/gd/packet/parser/fields/custom_field.cc
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2019 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 "fields/custom_field.h"
+#include "util.h"
+
+CustomField::CustomField(std::string name, std::string type_name, ParseLocation loc)
+ : PacketField(loc, name), type_name_(type_name) {}
+
+// Fixed size custom fields.
+CustomField::CustomField(std::string name, std::string type_name, int size, ParseLocation loc)
+ : PacketField(loc, name), type_name_(type_name), size_(size) {}
+
+PacketField::Type CustomField::GetFieldType() const {
+ return PacketField::Type::CUSTOM;
+}
+
+Size CustomField::GetSize() const {
+ return size_;
+}
+
+std::string CustomField::GetType() const {
+ return type_name_;
+}
+
+void CustomField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const {
+ s << GetType();
+ s << " Get" << util::UnderscoreToCamelCase(GetName()) << "() const {";
+
+ s << "auto it = ";
+ if (!start_offset.empty()) {
+ // Default to start if available.
+ if (start_offset.bits() % 8 != 0) {
+ ERROR(this) << "Custom Field must be byte aligned.";
+ }
+ s << "begin()";
+ if (start_offset.bits() / 8 != 0) s << " + " << start_offset.bits() / 8;
+ if (start_offset.has_dynamic()) s << " + " << start_offset.dynamic_string();
+ } else if (size_ != -1) {
+ // If the size of the custom field is already known, we can determine it's offset based on end().
+ if (!end_offset.empty()) {
+ if (end_offset.bits() % 8) {
+ ERROR(this) << "Custom Field must be byte aligned.";
+ }
+
+ int byte_offset = (end_offset.bits() + size_) / 8;
+ s << "end() - " << byte_offset;
+ if (end_offset.has_dynamic()) s << " - (" << end_offset.dynamic_string() << ")";
+ } else {
+ ERROR(this) << "Ambiguous offset for fixed size custom field.";
+ }
+ } else {
+ ERROR(this) << "Custom Field offset can not be determined from begin().";
+ }
+ s << ";";
+
+ s << "return it.extract<" << GetType() << ">();";
+ s << "}\n";
+}
+
+bool CustomField::GenBuilderParameter(std::ostream& s) const {
+ s << GetType() << " " << GetName();
+ return true;
+}
+
+bool CustomField::HasParameterValidator() const {
+ return false;
+}
+
+void CustomField::GenParameterValidator(std::ostream&) const {
+ // Do nothing.
+}
+
+void CustomField::GenInserter(std::ostream& s) const {
+ s << "insert(" << GetName() << "_, i);";
+}
+
+void CustomField::GenValidator(std::ostream&) const {
+ // Do nothing.
+}
diff --git a/gd/packet/parser/fields/custom_field.h b/gd/packet/parser/fields/custom_field.h
new file mode 100644
index 0000000..95a67a1
--- /dev/null
+++ b/gd/packet/parser/fields/custom_field.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2019 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 "fields/packet_field.h"
+#include "parse_location.h"
+
+class CustomField : public PacketField {
+ public:
+ CustomField(std::string name, std::string type_name, ParseLocation loc);
+
+ CustomField(std::string name, std::string type_name, int size, ParseLocation loc);
+
+ virtual PacketField::Type GetFieldType() const override;
+
+ virtual Size GetSize() const override;
+
+ virtual std::string GetType() const override;
+
+ virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+ virtual bool GenBuilderParameter(std::ostream& s) const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream&) const override;
+
+ virtual void GenInserter(std::ostream& s) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+
+ private:
+ std::string type_name_;
+
+ public:
+ const int size_{-1};
+};
diff --git a/gd/packet/parser/fields/enum_field.cc b/gd/packet/parser/fields/enum_field.cc
new file mode 100644
index 0000000..32a31d9
--- /dev/null
+++ b/gd/packet/parser/fields/enum_field.cc
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2019 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 "fields/enum_field.h"
+
+#include "util.h"
+
+EnumField::EnumField(std::string name, EnumDef enum_def, std::string value, ParseLocation loc)
+ : PacketField(loc, name), enum_def_(enum_def), value_(value) {}
+
+EnumDef EnumField::GetEnumDef() {
+ return enum_def_;
+}
+
+PacketField::Type EnumField::GetFieldType() const {
+ return PacketField::Type::ENUM;
+}
+
+Size EnumField::GetSize() const {
+ return enum_def_.size_;
+}
+
+std::string EnumField::GetType() const {
+ return enum_def_.name_;
+}
+
+void EnumField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const {
+ s << GetType();
+ s << " Get" << util::UnderscoreToCamelCase(GetName()) << "() const {";
+ s << "ASSERT(was_validated_);";
+
+ // Write the Getter Function Body
+ int num_leading_bits = 0;
+ int field_size = enum_def_.size_;
+
+ // Start from the beginning, if possible.
+ if (!start_offset.empty()) {
+ num_leading_bits = start_offset.bits() % 8;
+ s << "auto it = begin()"
+ << " + " << start_offset.bytes() << " + (" << start_offset.dynamic_string() << ");";
+ } else if (!end_offset.empty()) {
+ int offset_from_end = end_offset.bits() + field_size;
+ num_leading_bits = 8 - (offset_from_end % 8);
+ int byte_offset = (7 + offset_from_end) / 8;
+ s << "auto it = end() - " << byte_offset << " - (" << end_offset.dynamic_string() << ");";
+ } else {
+ ERROR(this) << "Ambiguous offset for field.";
+ }
+
+ // We don't need any masking, just return the extracted value.
+ if (num_leading_bits == 0 && util::RoundSizeUp(field_size) == field_size) {
+ s << "return it.extract<" << GetType() << ">();";
+ s << "}\n";
+ return;
+ }
+
+ // Extract the correct number of bytes. The return type could be different
+ // from the extract type if an earlier field causes the beginning of the
+ // current field to start in the middle of a byte.
+ std::string extract_type = util::GetTypeForSize(field_size + num_leading_bits);
+ s << "auto value = it.extract<" << extract_type << ">();";
+
+ // Right shift the result if necessary.
+ int shift_amount = num_leading_bits;
+ if (shift_amount != 0) {
+ s << "value >>= " << shift_amount << ";";
+ }
+
+ // Mask the result if necessary.
+ if (util::RoundSizeUp(field_size) != field_size) {
+ uint64_t mask = 0;
+ for (int i = 0; i < field_size; i++) {
+ mask <<= 1;
+ mask |= 1;
+ }
+ s << "value &= 0x" << std::hex << mask << std::dec << ";";
+ }
+
+ s << "return static_cast<" << GetType() << ">(value);";
+ s << "}\n";
+}
+
+bool EnumField::GenBuilderParameter(std::ostream& s) const {
+ s << GetType() << " " << GetName();
+ return true;
+}
+
+bool EnumField::HasParameterValidator() const {
+ return false;
+}
+
+void EnumField::GenParameterValidator(std::ostream&) const {
+ // Validated at compile time.
+}
+
+void EnumField::GenInserter(std::ostream& s) const {
+ s << "insert(static_cast<" << util::GetTypeForSize(GetSize().bits()) << ">(";
+ s << GetName() << "_), i, " << GetSize().bits() << ");";
+}
+
+void EnumField::GenValidator(std::ostream&) const {
+ // Do nothing
+}
diff --git a/gd/packet/parser/fields/enum_field.h b/gd/packet/parser/fields/enum_field.h
new file mode 100644
index 0000000..2ab77f1
--- /dev/null
+++ b/gd/packet/parser/fields/enum_field.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2019 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 "enum_def.h"
+#include "fields/packet_field.h"
+#include "parse_location.h"
+
+class EnumField : public PacketField {
+ public:
+ EnumField(std::string name, EnumDef enum_def, std::string value, ParseLocation loc);
+
+ EnumDef GetEnumDef();
+
+ virtual PacketField::Type GetFieldType() const override;
+
+ virtual Size GetSize() const override;
+
+ virtual std::string GetType() const override;
+
+ virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+ virtual bool GenBuilderParameter(std::ostream& s) const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream&) const override;
+
+ virtual void GenInserter(std::ostream& s) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+
+ private:
+ EnumDef enum_def_;
+ std::string value_;
+};
diff --git a/gd/packet/parser/fields/fixed_field.cc b/gd/packet/parser/fields/fixed_field.cc
new file mode 100644
index 0000000..6b53992
--- /dev/null
+++ b/gd/packet/parser/fields/fixed_field.cc
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2019 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 "fields/fixed_field.h"
+#include "util.h"
+
+int FixedField::unique_id_ = 0;
+
+FixedField::FixedField(int size, int64_t value, ParseLocation loc)
+ : PacketField(loc, "fixed_scalar" + std::to_string(unique_id_++)), type_(Type::FIXED_SCALAR), size_(size),
+ value_(value) {}
+
+FixedField::FixedField(EnumDef* enum_def, std::string value, ParseLocation loc)
+ : PacketField(loc, "fixed_scalar" + std::to_string(unique_id_++)), type_(Type::FIXED_ENUM), enum_(enum_def),
+ value_(value) {}
+
+PacketField::Type FixedField::GetFieldType() const {
+ return type_;
+}
+
+Size FixedField::GetSize() const {
+ if (type_ == PacketField::Type::FIXED_SCALAR) {
+ return size_;
+ }
+
+ return enum_->size_;
+}
+
+std::string FixedField::GetType() const {
+ if (type_ == PacketField::Type::FIXED_SCALAR) {
+ return util::GetTypeForSize(size_);
+ }
+
+ return enum_->name_;
+}
+
+void FixedField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const {
+ s << GetType();
+ s << " Get" << util::UnderscoreToCamelCase(GetName()) << "() const {";
+ s << "ASSERT(was_validated_);";
+
+ // Write the Getter Function Body
+ int num_leading_bits = 0;
+ int field_size = GetSize().bits();
+
+ // Handle if to start the iterator at begin or end.
+ if (!start_offset.empty()) {
+ // Default to start if available.
+ num_leading_bits = start_offset.bits() % 8;
+ s << "auto it = begin() + " << start_offset.bytes() << " + (" << start_offset.dynamic_string() << ");";
+ } else if (!end_offset.empty()) {
+ int offset_from_end = end_offset.bits() + field_size;
+ num_leading_bits = 8 - (offset_from_end % 8);
+ // Add 7 so it rounds up
+ int byte_offset = (7 + offset_from_end) / 8;
+ s << "auto it = end() - " << byte_offset << " - (" << end_offset.dynamic_string() << ");";
+ } else {
+ ERROR(this) << "Ambiguous offset for field.\n";
+ }
+
+ // We don't need any masking, just return the extracted value.
+ if (num_leading_bits == 0 && util::RoundSizeUp(field_size) == field_size) {
+ s << "return it.extract<" << GetType() << ">();";
+ s << "}\n";
+ return;
+ }
+
+ // Extract the correct number of bytes. The return type could be different
+ // from the extract type if an earlier field causes the beginning of the
+ // current field to start in the middle of a byte.
+ std::string extract_type = util::GetTypeForSize(field_size + num_leading_bits);
+ s << "auto value = it.extract<" << extract_type << ">();";
+
+ // Right shift to remove leading bits.
+ if (num_leading_bits != 0) {
+ s << "value >>= " << num_leading_bits << ";";
+ }
+
+ // Mask the result if necessary.
+ if (util::RoundSizeUp(field_size) != field_size) {
+ uint64_t mask = 0;
+ for (int i = 0; i < field_size; i++) {
+ mask <<= 1;
+ mask |= 1;
+ }
+ s << "value &= 0x" << std::hex << mask << std::dec << ";";
+ }
+
+ // Cast the result if necessary.
+ if (extract_type != GetType()) {
+ s << "return static_cast<" << GetType() << ">(value);";
+ } else {
+ s << "return value;";
+ }
+ s << "}\n";
+}
+
+bool FixedField::GenBuilderParameter(std::ostream&) const {
+ // No parameter needed for a fixed field.
+ return false;
+}
+
+bool FixedField::HasParameterValidator() const {
+ return false;
+}
+
+void FixedField::GenParameterValidator(std::ostream&) const {
+ // No parameter validator needed for a fixed field.
+}
+
+void FixedField::GenInserter(std::ostream& s) const {
+ s << "insert(";
+ if (type_ == PacketField::Type::FIXED_SCALAR) {
+ GenValue(s);
+ } else {
+ s << "static_cast<" << util::GetTypeForSize(GetSize().bits()) << ">(";
+ GenValue(s);
+ s << ")";
+ }
+ s << ", i , " << GetSize().bits() << ");";
+}
+
+void FixedField::GenValidator(std::ostream& s) const {
+ s << "if (Get" << util::UnderscoreToCamelCase(GetName()) << "() != ";
+ GenValue(s);
+ s << ") return false;";
+}
+
+void FixedField::GenValue(std::ostream& s) const {
+ if (type_ == PacketField::Type::FIXED_SCALAR) {
+ s << std::get<int64_t>(value_);
+ } else {
+ s << enum_->name_ << "::" << std::get<std::string>(value_);
+ }
+}
diff --git a/gd/packet/parser/fields/fixed_field.h b/gd/packet/parser/fields/fixed_field.h
new file mode 100644
index 0000000..f91e50c
--- /dev/null
+++ b/gd/packet/parser/fields/fixed_field.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2019 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 <variant>
+
+#include "enum_def.h"
+#include "fields/packet_field.h"
+#include "parse_location.h"
+
+class FixedField : public PacketField {
+ public:
+ FixedField(int size, int64_t value, ParseLocation loc);
+
+ FixedField(EnumDef* enum_def, std::string value, ParseLocation loc);
+
+ virtual PacketField::Type GetFieldType() const override;
+
+ virtual Size GetSize() const override;
+
+ virtual std::string GetType() const override;
+
+ virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+ virtual bool GenBuilderParameter(std::ostream&) const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream&) const override;
+
+ virtual void GenInserter(std::ostream& s) const override;
+
+ virtual void GenValidator(std::ostream& s) const override;
+
+ private:
+ void GenValue(std::ostream& s) const;
+
+ PacketField::Type type_;
+ int size_;
+ EnumDef* enum_;
+ std::variant<int64_t, std::string> value_;
+
+ static int unique_id_;
+};
diff --git a/gd/packet/parser/fields/group_field.cc b/gd/packet/parser/fields/group_field.cc
new file mode 100644
index 0000000..7e4caba
--- /dev/null
+++ b/gd/packet/parser/fields/group_field.cc
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2019 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 "fields/group_field.h"
+
+GroupField::GroupField(ParseLocation loc, std::list<PacketField*>* fields)
+ : PacketField(loc, "Groups have no name"), fields_(fields) {}
+
+GroupField::~GroupField() {
+ delete fields_;
+}
+
+PacketField::Type GroupField::GetFieldType() const {
+ return PacketField::Type::GROUP;
+}
+
+std::string GroupField::GetName() const {
+ ERROR(this) << "GetName should never be called.";
+ return "";
+}
+
+Size GroupField::GetSize() const {
+ ERROR(this) << "GetSize should never be called.";
+ return Size();
+}
+
+std::string GroupField::GetType() const {
+ ERROR(this) << "GetType should never be called.";
+ return "";
+}
+
+void GroupField::GenGetter(std::ostream&, Size, Size) const {
+ ERROR(this) << "GenGetter should never be called.";
+}
+
+bool GroupField::GenBuilderParameter(std::ostream&) const {
+ ERROR(this) << "GenBuilderParameter should never be called";
+ return false;
+}
+
+bool GroupField::HasParameterValidator() const {
+ ERROR(this) << "HasParameterValidator should never be called";
+ return false;
+}
+
+void GroupField::GenParameterValidator(std::ostream&) const {
+ ERROR(this) << "Not implemented";
+}
+
+void GroupField::GenInserter(std::ostream&) const {
+ ERROR(this) << "GenInserter should never be called.";
+}
+
+void GroupField::GenValidator(std::ostream&) const {
+ ERROR(this) << "GenValidator should never be called.";
+}
+
+const std::list<PacketField*>* GroupField::GetFields() const {
+ return fields_;
+}
diff --git a/gd/packet/parser/fields/group_field.h b/gd/packet/parser/fields/group_field.h
new file mode 100644
index 0000000..73e7e35
--- /dev/null
+++ b/gd/packet/parser/fields/group_field.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2019 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 <list>
+
+#include "fields/packet_field.h"
+#include "parse_location.h"
+
+class GroupField : public PacketField {
+ public:
+ GroupField(ParseLocation loc, std::list<PacketField*>* fields);
+
+ ~GroupField();
+
+ virtual PacketField::Type GetFieldType() const override;
+
+ virtual std::string GetName() const override;
+
+ virtual Size GetSize() const override;
+
+ virtual std::string GetType() const override;
+
+ virtual void GenGetter(std::ostream&, Size, Size) const override;
+
+ virtual bool GenBuilderParameter(std::ostream&) const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream&) const override;
+
+ virtual void GenInserter(std::ostream&) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+
+ const std::list<PacketField*>* GetFields() const;
+
+ private:
+ std::list<PacketField*>* fields_;
+};
diff --git a/gd/packet/parser/fields/packet_field.cc b/gd/packet/parser/fields/packet_field.cc
new file mode 100644
index 0000000..8a9468e
--- /dev/null
+++ b/gd/packet/parser/fields/packet_field.cc
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2019 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 "fields/packet_field.h"
+
+PacketField::PacketField(ParseLocation loc, std::string name) : loc_(loc), name_(name) {}
+
+std::string PacketField::GetDebugName() const {
+ std::string ret = "";
+ switch (GetFieldType()) {
+ case Type::GROUP:
+ ret = "GROUP";
+ break;
+ case Type::FIXED_SCALAR:
+ ret = "FIXED SCALAR";
+ break;
+ case Type::FIXED_ENUM:
+ ret = "FIXED ENUM";
+ break;
+ case Type::RESERVED_SCALAR:
+ ret = "RESERVED SCALAR";
+ break;
+ case Type::SCALAR:
+ ret = "SCALAR";
+ break;
+ case Type::ENUM:
+ ret = "ENUM";
+ break;
+ case Type::SIZE:
+ ret = "SIZE";
+ break;
+ case Type::COUNT:
+ ret = "COUNT";
+ break;
+ case Type::BODY:
+ ret = "BODY";
+ break;
+ case Type::PAYLOAD:
+ ret = "PAYLOAD";
+ break;
+ case Type::ARRAY:
+ ret = "ARRAY";
+ break;
+ case Type::CUSTOM:
+ ret = "CUSTOM";
+ break;
+ default:
+ std::cerr << "UNKNOWN DEBUG NAME TYPE\n";
+ abort();
+ }
+
+ return "Field{Type:" + ret + ", Name:" + GetName() + "}";
+}
+
+ParseLocation PacketField::GetLocation() const {
+ return loc_;
+}
+
+std::string PacketField::GetName() const {
+ return name_;
+}
diff --git a/gd/packet/parser/fields/packet_field.h b/gd/packet/parser/fields/packet_field.h
new file mode 100644
index 0000000..030101b
--- /dev/null
+++ b/gd/packet/parser/fields/packet_field.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2019 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 <iostream>
+#include <string>
+
+#include "logging.h"
+#include "parse_location.h"
+#include "size.h"
+
+// The base field that every packet needs to inherit from.
+class PacketField : public Loggable {
+ public:
+ virtual ~PacketField() = default;
+
+ PacketField(ParseLocation loc, std::string name);
+
+ enum class Type {
+ GROUP,
+ FIXED_SCALAR,
+ FIXED_ENUM,
+ RESERVED_SCALAR,
+ SCALAR,
+ ENUM,
+ SIZE,
+ COUNT,
+ BODY,
+ PAYLOAD,
+ ARRAY,
+ CUSTOM,
+ CHECKSUM,
+ CHECKSUM_START,
+ };
+
+ // Get the field type for the field.
+ virtual Type GetFieldType() const = 0;
+
+ // Returns the size of the field in bits and a string that evaluates into
+ // bytes for dynamically sized arrays.
+ virtual Size GetSize() const = 0;
+
+ // Get the type of the field to be used in the builders constructor and
+ // variables.
+ virtual std::string GetType() const = 0;
+
+ // Get parser getter definition. Start_offset points to the first bit of the
+ // field. end_offset is the first bit after the field. If an offset is empty
+ // that means that there was a field with an unknown size when trying to
+ // calculate the offset.
+ virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const = 0;
+
+ // Generate the parameter for Create(), return true if a parameter was added.
+ virtual bool GenBuilderParameter(std::ostream& s) const = 0;
+
+ // Returns whether or not the field must be validated.
+ virtual bool HasParameterValidator() const = 0;
+
+ // Fail if the value doesn't fit in the field.
+ virtual void GenParameterValidator(std::ostream& s) const = 0;
+
+ // Generate the inserter for pushing the data in the builder.
+ virtual void GenInserter(std::ostream& s) const = 0;
+
+ // Generate the validator for a field for the IsValid() function.
+ //
+ // The way this function works is by assuming that there is an iterator |it|
+ // that was defined earlier. The implementer of the function will then move
+ // it forward based on the dynamic size of the field and then check to see if
+ // its past the end of the packet.
+ // It should be unused for fixed size fields unless special consideration is
+ // needed. This is because all fixed size fields are tallied together with
+ // GetSize() and used as an initial offset. One special consideration is for
+ // enums where instead of checking if they can be read, they are checked to
+ // see if they contain the correct value.
+ virtual void GenValidator(std::ostream& s) const = 0;
+
+ std::string GetDebugName() const override;
+
+ ParseLocation GetLocation() const override;
+
+ virtual std::string GetName() const;
+
+ private:
+ ParseLocation loc_;
+ std::string name_;
+};
diff --git a/gd/packet/parser/fields/payload_field.cc b/gd/packet/parser/fields/payload_field.cc
new file mode 100644
index 0000000..b14085c
--- /dev/null
+++ b/gd/packet/parser/fields/payload_field.cc
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2019 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 "fields/payload_field.h"
+#include "util.h"
+
+PayloadField::PayloadField(std::string modifier, ParseLocation loc)
+ : PacketField(loc, "payload"), size_field_(nullptr), size_modifier_(modifier) {}
+
+void PayloadField::SetSizeField(const SizeField* size_field) {
+ if (size_field_ != nullptr) {
+ ERROR(this, size_field_, size_field) << "The size field for the payload has already been assigned.";
+ }
+
+ if (size_field->GetFieldType() == PacketField::Type::COUNT) {
+ ERROR(this, size_field) << "Can not use count field to describe a payload.";
+ }
+
+ size_field_ = size_field;
+}
+
+PacketField::Type PayloadField::GetFieldType() const {
+ return PacketField::Type::PAYLOAD;
+}
+
+Size PayloadField::GetSize() const {
+ if (size_field_ == nullptr) {
+ // Require a size field if there is a modifier.
+ if (!size_modifier_.empty()) {
+ ERROR(this) << "Missing size field for payload with size modifier.";
+ }
+
+ return Size();
+ }
+
+ std::string dynamic_size = "Get" + util::UnderscoreToCamelCase(size_field_->GetName()) + "()";
+ if (!size_modifier_.empty()) {
+ dynamic_size += "- (" + size_modifier_ + ") / 8";
+ }
+
+ return dynamic_size;
+}
+
+std::string PayloadField::GetType() const {
+ return "PacketView";
+}
+
+void PayloadField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const {
+ if (start_offset.empty()) {
+ ERROR(this) << "Can not have a payload that has an ambiguous start offset. "
+ << "Is there a field with an unknown length before the "
+ << "payload?\n";
+ }
+
+ if (start_offset.bits() % 8 != 0 && !GetSize().empty()) {
+ ERROR(this) << "Can not have a sized payload field "
+ << "at a non byte-aligned offset.\n";
+ }
+
+ if (GetSize().empty() && end_offset.empty()) {
+ ERROR(this) << "Ambiguous end offset for payload with no defined size.";
+ }
+
+ s << "PacketView<kLittleEndian> GetPayload() {";
+ s << "ASSERT(was_validated_);";
+
+ s << "size_t payload_begin = " << start_offset.bits() / 8 << " + (" << start_offset.dynamic_string() << ");";
+
+ // If the payload is sized, use the size + payload_begin for payload_end, otherwise use the end_offset.
+ if (!GetSize().empty()) {
+ // If the size isn't empty then it must have a dynamic string only.
+ s << "size_t payload_end = payload_begin + (" << GetSize().dynamic_string() << ");";
+ } else {
+ s << "size_t payload_end = size() - " << end_offset.bits() / 8 << " - (" << end_offset.dynamic_string() << ");";
+ }
+
+ s << "return GetLittleEndianSubview(payload_begin, payload_end);";
+ s << "}\n\n";
+
+ s << "PacketView<!kLittleEndian> GetPayloadBigEndian() {";
+
+ s << "size_t payload_begin = " << start_offset.bits() / 8 << " + (" << start_offset.dynamic_string() << ");";
+
+ // If the payload is sized, use the size + payload_begin for payload_end, otherwise use the end_offset.
+ if (!GetSize().empty()) {
+ // If the size isn't empty then it must have a dynamic string only.
+ s << "size_t payload_end = payload_begin + (" << GetSize().dynamic_string() << ");";
+ } else {
+ s << "size_t payload_end = size() - " << end_offset.bits() / 8 << " - (" << end_offset.dynamic_string() << ");";
+ }
+
+ s << "return GetBigEndianSubview(payload_begin, payload_end);";
+ s << "}\n";
+}
+
+bool PayloadField::GenBuilderParameter(std::ostream& s) const {
+ s << "std::unique_ptr<BasePacketBuilder> payload";
+ return true;
+}
+
+bool PayloadField::HasParameterValidator() const {
+ return false;
+}
+
+void PayloadField::GenParameterValidator(std::ostream&) const {
+ // There is no validation needed for a payload
+}
+
+void PayloadField::GenInserter(std::ostream&) const {
+ ERROR() << __func__ << " Should never be called.";
+}
+
+void PayloadField::GenValidator(std::ostream&) const {
+ // Do nothing
+}
diff --git a/gd/packet/parser/fields/payload_field.h b/gd/packet/parser/fields/payload_field.h
new file mode 100644
index 0000000..8787b41
--- /dev/null
+++ b/gd/packet/parser/fields/payload_field.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2019 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 "fields/packet_field.h"
+#include "fields/size_field.h"
+#include "parse_location.h"
+
+class PayloadField : public PacketField {
+ public:
+ PayloadField(std::string modifier, ParseLocation loc);
+
+ void SetSizeField(const SizeField* size_field);
+
+ virtual PacketField::Type GetFieldType() const override;
+
+ virtual Size GetSize() const override;
+
+ virtual std::string GetType() const override;
+
+ virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+ virtual bool GenBuilderParameter(std::ostream& s) const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream&) const override;
+
+ virtual void GenInserter(std::ostream&) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+
+ // Payload fields can only be dynamically sized.
+ const SizeField* size_field_;
+ // Only used if the size of the payload is based on another field.
+ std::string size_modifier_;
+};
diff --git a/gd/packet/parser/fields/reserved_field.cc b/gd/packet/parser/fields/reserved_field.cc
new file mode 100644
index 0000000..3db1527
--- /dev/null
+++ b/gd/packet/parser/fields/reserved_field.cc
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2019 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 "fields/reserved_field.h"
+#include "util.h"
+
+int ReservedField::unique_id_ = 0;
+
+ReservedField::ReservedField(int size, ParseLocation loc)
+ : PacketField(loc, "ReservedScalar" + std::to_string(unique_id_++)), type_(PacketField::Type::RESERVED_SCALAR),
+ size_(size) {}
+
+PacketField::Type ReservedField::GetFieldType() const {
+ return type_;
+}
+
+Size ReservedField::GetSize() const {
+ return size_;
+}
+
+std::string ReservedField::GetType() const {
+ return util::GetTypeForSize(size_);
+}
+
+void ReservedField::GenGetter(std::ostream&, Size, Size) const {
+ // There is no Getter for a reserved field
+}
+
+bool ReservedField::GenBuilderParameter(std::ostream&) const {
+ // There is no builder parameter for a reserved field
+ return false;
+}
+
+bool ReservedField::HasParameterValidator() const {
+ return false;
+}
+
+void ReservedField::GenParameterValidator(std::ostream&) const {
+ // There is no builder parameter for a reserved field
+}
+
+void ReservedField::GenInserter(std::ostream& s) const {
+ s << "insert(static_cast<" << util::GetTypeForSize(GetSize().bits()) << ">(0) /* Reserved */, i, " << GetSize().bits()
+ << " );\n";
+}
+
+void ReservedField::GenValidator(std::ostream&) const {
+ // There is no need to validate the value of a reserved field
+}
diff --git a/gd/packet/parser/fields/reserved_field.h b/gd/packet/parser/fields/reserved_field.h
new file mode 100644
index 0000000..46f7f7b
--- /dev/null
+++ b/gd/packet/parser/fields/reserved_field.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2019 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 "fields/packet_field.h"
+#include "parse_location.h"
+
+class ReservedField : public PacketField {
+ public:
+ ReservedField(int size, ParseLocation loc);
+
+ virtual PacketField::Type GetFieldType() const override;
+
+ virtual Size GetSize() const override;
+
+ virtual std::string GetType() const override;
+
+ virtual void GenGetter(std::ostream&, Size, Size) const override;
+
+ virtual bool GenBuilderParameter(std::ostream&) const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream&) const override;
+
+ virtual void GenInserter(std::ostream& s) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+
+ private:
+ PacketField::Type type_;
+ std::string name_;
+ int size_;
+ static int unique_id_;
+};
diff --git a/gd/packet/parser/fields/scalar_field.cc b/gd/packet/parser/fields/scalar_field.cc
new file mode 100644
index 0000000..91907b2
--- /dev/null
+++ b/gd/packet/parser/fields/scalar_field.cc
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2019 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 "fields/scalar_field.h"
+#include "util.h"
+
+ScalarField::ScalarField(std::string name, int size, ParseLocation loc) : PacketField(loc, name), size_(size) {}
+
+PacketField::Type ScalarField::GetFieldType() const {
+ return PacketField::Type::SCALAR;
+}
+
+Size ScalarField::GetSize() const {
+ return size_;
+}
+
+std::string ScalarField::GetType() const {
+ return util::GetTypeForSize(size_);
+}
+
+void ScalarField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const {
+ s << GetType();
+ s << " Get" << util::UnderscoreToCamelCase(GetName()) << "() const {";
+ s << "ASSERT(was_validated_);";
+
+ // Write the Getter Function Body
+ int num_leading_bits = 0;
+ int field_size = size_;
+
+ // Handle if to start the iterator at begin or end.
+ s << "auto it = ";
+ if (!start_offset.empty()) {
+ // Default to start if available.
+ num_leading_bits = start_offset.bits() % 8;
+ s << "begin()";
+ if (start_offset.bits() / 8 != 0) s << " + " << start_offset.bits() / 8;
+ if (start_offset.has_dynamic()) s << " + " << start_offset.dynamic_string();
+ } else if (!end_offset.empty()) {
+ num_leading_bits = (8 - ((end_offset.bits() + field_size) % 8)) % 8;
+ // Add 7 so it rounds up
+ int byte_offset = (7 + end_offset.bits() + field_size) / 8;
+ s << "end() - " << byte_offset;
+ if (end_offset.has_dynamic()) s << " - (" << end_offset.dynamic_string() << ")";
+ } else {
+ ERROR(this) << "Ambiguous offset for field.";
+ }
+ s << ";";
+
+ // We don't need any masking, just return the extracted value.
+ if (num_leading_bits == 0 && util::RoundSizeUp(field_size) == field_size) {
+ s << "return it.extract<" << util::GetTypeForSize(field_size) << ">();";
+ s << "}\n";
+ return;
+ }
+
+ // Extract the correct number of bytes. The return type could be different
+ // from the extract type if an earlier field causes the beginning of the
+ // current field to start in the middle of a byte.
+ std::string extract_type = util::GetTypeForSize(field_size + num_leading_bits);
+ s << "auto value = it.extract<" << extract_type << ">();";
+
+ // Right shift the result if necessary.
+ int shift_amount = num_leading_bits;
+ if (shift_amount != 0) {
+ s << "value >>= " << shift_amount << ";";
+ }
+
+ // Mask the result if necessary.
+ if (util::RoundSizeUp(field_size) != field_size) {
+ uint64_t mask = 0;
+ for (int i = 0; i < field_size; i++) {
+ mask <<= 1;
+ mask |= 1;
+ }
+ s << "value &= 0x" << std::hex << mask << std::dec << ";";
+ }
+
+ // Cast the result if necessary.
+ if (extract_type != util::GetTypeForSize(field_size)) {
+ s << "return static_cast<" << GetType() << ">(value);";
+ } else {
+ s << "return value;";
+ }
+ s << "}\n";
+}
+
+bool ScalarField::GenBuilderParameter(std::ostream& s) const {
+ if (size_ > 64 || size_ < 0) {
+ ERROR(this) << "Not implemented";
+ }
+ std::string param_type = util::GetTypeForSize(size_);
+ s << param_type << " " << GetName();
+ return true;
+}
+
+bool ScalarField::HasParameterValidator() const {
+ const auto bits = GetSize().bits();
+ return util::RoundSizeUp(bits) != bits;
+}
+
+void ScalarField::GenParameterValidator(std::ostream& s) const {
+ const auto bits = GetSize().bits();
+ if (util::RoundSizeUp(bits) == bits) {
+ return;
+ }
+ s << "ASSERT(" << GetName() << " < "
+ << "(static_cast<uint64_t>(1) << " << bits << "));";
+}
+
+void ScalarField::GenInserter(std::ostream& s) const {
+ if (GetSize().bits() == 8) {
+ s << "i.insert_byte(" << GetName() << "_);";
+ } else if (GetSize().bits() % 8 == 0) {
+ s << "insert(" << GetName() << "_, i);";
+ } else {
+ s << "insert(" << GetName() << "_, i," << GetSize().bits() << ");";
+ }
+}
+
+void ScalarField::GenValidator(std::ostream&) const {
+ // Do nothing since the fixed size fields will be handled seperatly.
+}
diff --git a/gd/packet/parser/fields/scalar_field.h b/gd/packet/parser/fields/scalar_field.h
new file mode 100644
index 0000000..4e52fd1
--- /dev/null
+++ b/gd/packet/parser/fields/scalar_field.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019 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 "fields/packet_field.h"
+#include "parse_location.h"
+
+class ScalarField : public PacketField {
+ public:
+ ScalarField(std::string name, int size, ParseLocation loc);
+
+ virtual PacketField::Type GetFieldType() const override;
+
+ virtual Size GetSize() const override;
+
+ virtual std::string GetType() const override;
+
+ virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+ virtual bool GenBuilderParameter(std::ostream& s) const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream& s) const override;
+
+ virtual void GenInserter(std::ostream& s) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+
+ private:
+ int size_;
+};
diff --git a/gd/packet/parser/fields/size_field.cc b/gd/packet/parser/fields/size_field.cc
new file mode 100644
index 0000000..bbb6a73
--- /dev/null
+++ b/gd/packet/parser/fields/size_field.cc
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2019 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 "fields/size_field.h"
+#include "util.h"
+
+SizeField::SizeField(std::string name, int size, bool is_count, ParseLocation loc)
+ : PacketField(loc, name + (is_count ? "_count" : "_size")), size_(size), is_count_(is_count),
+ sized_field_name_(name) {}
+
+PacketField::Type SizeField::GetFieldType() const {
+ return (is_count_ ? PacketField::Type::COUNT : PacketField::Type::SIZE);
+}
+
+Size SizeField::GetSize() const {
+ return size_;
+}
+
+std::string SizeField::GetType() const {
+ return util::GetTypeForSize(size_);
+}
+
+void SizeField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const {
+ s << "protected:";
+ s << GetType();
+ s << " Get" << util::UnderscoreToCamelCase(GetName()) << "() const {";
+ s << "ASSERT(was_validated_);";
+
+ // Write the Getter Function Body
+ int num_leading_bits = 0;
+
+ // Handle if to start the iterator at begin or end.
+ if (!start_offset.empty()) {
+ // Default to start if available.
+ num_leading_bits = start_offset.bits() % 8;
+ s << "auto it = begin() + " << start_offset.bits() / 8 << " + (" << start_offset.dynamic_string() << ");";
+ } else if (!end_offset.empty()) {
+ int offset_from_end = end_offset.bits() + size_;
+ num_leading_bits = 8 - (offset_from_end % 8);
+ // Add 7 so it rounds up
+ int byte_offset = (7 + offset_from_end) / 8;
+ s << "auto it = end() - " << byte_offset << " - (" << end_offset.dynamic_string() << ");";
+
+ } else {
+ ERROR(this) << "Ambiguous offset for field.";
+ }
+
+ // We don't need any masking, just return the extracted value.
+ if (num_leading_bits == 0 && util::RoundSizeUp(size_) == size_) {
+ s << "return it.extract<" << GetType() << ">();";
+ s << "}\n";
+ s << "public:\n";
+ return;
+ }
+
+ // Extract the correct number of bytes. The return type could be different
+ // from the extract type if an earlier field causes the beginning of the
+ // current field to start in the middle of a byte.
+ std::string extract_type = util::GetTypeForSize(size_ + num_leading_bits);
+ s << "auto value = it.extract<" << extract_type << ">();";
+
+ // Right shift the result to remove leading bits.
+ if (num_leading_bits != 0) {
+ s << "value >>= " << num_leading_bits << ";";
+ }
+
+ // Mask the result if necessary.
+ if (util::RoundSizeUp(size_) != size_) {
+ uint64_t mask = 0;
+ for (int i = 0; i < size_; i++) {
+ mask <<= 1;
+ mask |= 1;
+ }
+ s << "value &= 0x" << std::hex << mask << std::dec << ";";
+ }
+
+ // Cast the result if necessary.
+ if (extract_type != util::GetTypeForSize(size_)) {
+ s << "return static_cast<" << GetType() << ">(value);";
+ } else {
+ s << "return value;";
+ }
+ s << "}\n";
+ s << "public:\n";
+}
+
+bool SizeField::GenBuilderParameter(std::ostream&) const {
+ // There is no builder parameter for a size field
+ return false;
+}
+
+bool SizeField::HasParameterValidator() const {
+ return false;
+}
+
+void SizeField::GenParameterValidator(std::ostream&) const {
+ // There is no builder parameter for a size field
+ // TODO: Check if the payload fits in the packet?
+}
+
+void SizeField::GenInserter(std::ostream&) const {
+ ERROR(this) << __func__ << ": This should not be called for size fields";
+}
+
+void SizeField::GenValidator(std::ostream&) const {
+ // Do nothing since the fixed size fields will be handled specially.
+}
+
+std::string SizeField::GetSizedFieldName() const {
+ return sized_field_name_;
+}
diff --git a/gd/packet/parser/fields/size_field.h b/gd/packet/parser/fields/size_field.h
new file mode 100644
index 0000000..61e8666
--- /dev/null
+++ b/gd/packet/parser/fields/size_field.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 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 "fields/packet_field.h"
+#include "parse_location.h"
+
+class SizeField : public PacketField {
+ public:
+ SizeField(std::string name, int size, bool is_count, ParseLocation loc);
+
+ std::string GetField() const;
+
+ virtual PacketField::Type GetFieldType() const override;
+
+ virtual Size GetSize() const override;
+
+ virtual std::string GetType() const override;
+
+ virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+ virtual bool GenBuilderParameter(std::ostream&) const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream&) const override;
+
+ virtual void GenInserter(std::ostream&) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+
+ virtual std::string GetSizedFieldName() const;
+
+ private:
+ int size_;
+ bool is_count_;
+ std::string sized_field_name_;
+};
diff --git a/gd/packet/parser/language_l.ll b/gd/packet/parser/language_l.ll
new file mode 100644
index 0000000..1914ae9
--- /dev/null
+++ b/gd/packet/parser/language_l.ll
@@ -0,0 +1,119 @@
+%{
+
+#include <string>
+#include <map>
+#include <iostream>
+
+#include "declarations.h"
+#include "language_y.h"
+
+using token = yy::parser::token;
+
+#define YY_USER_ACTION yylloc->step(); yylloc->columns(yyleng);
+
+%}
+
+%option debug
+
+%option yylineno
+%option noyywrap
+%option nounput
+%option noinput
+%option reentrant
+%option bison-bridge
+%option bison-locations
+
+identifier [a-zA-Z][_a-zA-Z0-9]*
+size_modifier [+*/-][ +*/\-0-9]*
+intvalue (0|[1-9][0-9]*)
+hexvalue 0[x|X][0-9a-fA-F]+
+string_literal \".*\"
+
+%x COMMENT_STATE
+
+%%
+ /* NOTE:
+ * Rule ordering is important in order to establist priority. Some
+ * rules are a superset of other rules and will cause the sub rules to
+ * never match. Ex. Keywords must always go before identifiers, otherwise
+ * all keywords will be treated as an identifier.
+ */
+
+ /* Block Comment */
+"/*" { BEGIN(COMMENT_STATE); }
+<COMMENT_STATE>"*/" { BEGIN(INITIAL); }
+<COMMENT_STATE>[\n]+ { yylloc->lines(yyleng); }
+<COMMENT_STATE>. { /* do nothing */ }
+
+ /* Line Comment */
+"//"[^\r\n]* { /* do nothing */ }
+
+ /* Begin reserved keyword definitions */
+ /* Fields */
+"_body_" { return(token::BODY); }
+"_payload_" { return(token::PAYLOAD); }
+"_size_" { return(token::SIZE); }
+"_count_" { return(token::COUNT); }
+"_fixed_" { return(token::FIXED); }
+"_reserved_" { return(token::RESERVED); }
+"_checksum_start_" { return(token::CHECKSUM_START); }
+ /* Types */
+"checksum" { return(token::CHECKSUM); }
+"custom_field" { return(token::CUSTOM_FIELD); }
+"enum" { return(token::ENUM); }
+"group" { return(token::GROUP); }
+"packet" { return(token::PACKET); }
+"little_endian_packets" {
+ yylval->integer = 1;
+ return token::IS_LITTLE_ENDIAN;
+ }
+"big_endian_packets" {
+ yylval->integer = 0;
+ return token::IS_LITTLE_ENDIAN;
+ }
+
+ /* Begin identifier definitions */
+{string_literal} {
+ std::string with_quotes = std::string(yytext);
+ yylval->string = new std::string(with_quotes.begin() + 1, with_quotes.end() - 1);
+ return token::STRING;
+ }
+
+{size_modifier} {
+ yylval->string = new std::string(yytext);
+ return token::SIZE_MODIFIER;
+ }
+
+{identifier} {
+ yylval->string = new std::string(yytext);
+ return token::IDENTIFIER;
+ }
+
+{intvalue} {
+ yylval->integer = std::stoi(std::string(yytext), nullptr, 10);
+ return token::INTEGER;
+ }
+
+{hexvalue} {
+ yylval->integer = std::stoi(std::string(yytext), nullptr, 16);
+ return token::INTEGER;
+ }
+
+ /* Begin token definitions */
+":" { return(':'); }
+"{" { return('{'); }
+"}" { return('}'); }
+"[" { return('['); }
+"]" { return(']'); }
+"(" { return('('); }
+")" { return(')'); }
+"<" { return('<'); }
+">" { return('>'); }
+"=" { return('='); }
+"," { return(','); }
+
+(\n|\r\n)+ { yylloc->lines(yyleng); }
+[ \t\f\v]+ { /* Ignore all other whitespace */ }
+
+%%
+
diff --git a/gd/packet/parser/language_y.yy b/gd/packet/parser/language_y.yy
new file mode 100644
index 0000000..4b1c0ba
--- /dev/null
+++ b/gd/packet/parser/language_y.yy
@@ -0,0 +1,627 @@
+%{
+ #include <iostream>
+ #include <vector>
+ #include <list>
+ #include <map>
+
+ #include "declarations.h"
+ #include "logging.h"
+ #include "language_y.h"
+ #include "field_list.h"
+ #include "fields/all_fields.h"
+
+ extern int yylex(yy::parser::semantic_type*, yy::parser::location_type*, void *);
+
+ ParseLocation toParseLocation(yy::parser::location_type loc) {
+ return ParseLocation(loc.begin.line);
+ }
+ #define LOC toParseLocation(yylloc)
+%}
+
+%parse-param { void* scanner }
+%parse-param { Declarations* decls }
+%lex-param { void* scanner }
+
+%pure-parser
+%glr-parser
+%skeleton "glr.cc"
+
+%expect-rr 0
+
+%debug
+%error-verbose
+%verbose
+
+%union {
+ int integer;
+ std::string* string;
+
+ EnumDef* enum_definition;
+ std::map<int, std::string>* enumeration_values;
+ std::pair<int, std::string>* enumeration_value;
+
+ PacketDef* packet_definition_value;
+ FieldList* packet_field_definitions;
+ PacketField* packet_field_type;
+
+ std::map<std::string, std::variant<int64_t, std::string>>* constraint_list_t;
+ std::pair<std::string, std::variant<int64_t, std::string>>* constraint_t;
+}
+
+%token <integer> INTEGER
+%token <integer> IS_LITTLE_ENDIAN
+%token <string> IDENTIFIER
+%token <string> SIZE_MODIFIER
+%token <string> STRING
+
+%token ENUM "enum"
+%token PACKET "packet"
+%token PAYLOAD "payload"
+%token BODY "body"
+%token SIZE "size"
+%token COUNT "count"
+%token FIXED "fixed"
+%token RESERVED "reserved"
+%token GROUP "group"
+%token CUSTOM_FIELD "custom_field"
+%token CHECKSUM "checksum"
+%token CHECKSUM_START "checksum_start"
+
+%type<enum_definition> enum_definition
+%type<enumeration_values> enumeration_list
+%type<enumeration_value> enumeration
+
+%type<packet_definition_value> packet_definition;
+%type<packet_field_definitions> field_definition_list;
+%type<packet_field_type> field_definition;
+%type<packet_field_type> group_field_definition;
+%type<packet_field_type> type_def_field_definition;
+%type<packet_field_type> scalar_field_definition;
+%type<packet_field_type> checksum_start_field_definition;
+%type<packet_field_type> size_field_definition;
+%type<packet_field_type> payload_field_definition;
+%type<packet_field_type> body_field_definition;
+%type<packet_field_type> fixed_field_definition;
+%type<packet_field_type> reserved_field_definition;
+%type<packet_field_type> array_field_definition;
+
+%type<constraint_list_t> constraint_list;
+%type<constraint_t> constraint;
+%destructor { std::cout << "DESTROYING STRING " << *$$ << "\n"; delete $$; } IDENTIFIER STRING SIZE_MODIFIER
+
+%%
+
+file
+ : IS_LITTLE_ENDIAN declarations
+ {
+ decls->is_little_endian = ($1 == 1);
+ if (decls->is_little_endian) {
+ DEBUG() << "LITTLE ENDIAN ";
+ } else {
+ DEBUG() << "BIG ENDIAN ";
+ }
+ }
+
+declarations
+ : /* empty */
+ | declarations declaration
+
+declaration
+ : enum_definition
+ {
+ std::cerr << "FOUND ENUM\n\n";
+ decls->AddTypeDef($1->name_, $1);
+ }
+ | packet_definition
+ {
+ std::cerr << "FOUND PACKET\n\n";
+ decls->AddPacketDef($1->name_, std::move(*$1));
+ delete $1;
+ }
+ | group_definition
+ {
+ // All actions are handled in group_definition
+ }
+ | checksum_definition
+ {
+ // All actions are handled in checksum_definition
+ }
+ | custom_field_definition
+ {
+ // All actions are handled in custom_field_definition
+ }
+
+enum_definition
+ : ENUM IDENTIFIER ':' INTEGER '{' enumeration_list ',' '}'
+ {
+ std::cerr << "Enum Declared: name=" << *$2
+ << " size=" << $4 << "\n";
+
+ $$ = new EnumDef(std::move(*$2), $4);
+ for (const auto& e : *$6) {
+ $$->AddEntry(e.second, e.first);
+ }
+ delete $2;
+ delete $6;
+ }
+
+enumeration_list
+ : enumeration
+ {
+ std::cerr << "Enumerator with comma\n";
+ $$ = new std::map<int, std::string>();
+ $$->insert(std::move(*$1));
+ delete $1;
+ }
+ | enumeration_list ',' enumeration
+ {
+ std::cerr << "Enumerator with list\n";
+ $$ = $1;
+ $$->insert(std::move(*$3));
+ delete $3;
+ }
+
+enumeration
+ : IDENTIFIER '=' INTEGER
+ {
+ std::cerr << "Enumerator: name=" << *$1
+ << " value=" << $3 << "\n";
+ $$ = new std::pair($3, std::move(*$1));
+ delete $1;
+ }
+
+group_definition
+ : GROUP IDENTIFIER '{' field_definition_list '}'
+ {
+ decls->AddGroupDef(*$2, $4);
+ delete $2;
+ }
+
+checksum_definition
+ : CHECKSUM IDENTIFIER ':' INTEGER STRING
+ {
+ std::cerr << "Checksum field defined\n";
+ decls->AddTypeDef(*$2, new ChecksumDef(*$2, *$5, $4));
+ delete $2;
+ delete $5;
+ }
+
+custom_field_definition
+ : CUSTOM_FIELD IDENTIFIER ':' INTEGER STRING
+ {
+ decls->AddTypeDef(*$2, new CustomFieldDef(*$2, *$5, $4));
+ delete $2;
+ delete $5;
+ }
+
+packet_definition
+ : PACKET IDENTIFIER '{' field_definition_list '}' /* Packet with no parent */
+ {
+ auto&& packet_name = *$2;
+ auto&& field_definition_list = *$4;
+
+ DEBUG() << "Packet " << packet_name << " with no parent";
+ DEBUG() << "PACKET FIELD LIST SIZE: " << field_definition_list.size();
+ auto packet_definition = new PacketDef(std::move(packet_name), std::move(field_definition_list));
+ packet_definition->AssignSizeFields();
+
+ $$ = packet_definition;
+ delete $2;
+ delete $4;
+ }
+ | PACKET IDENTIFIER ':' IDENTIFIER '{' field_definition_list '}'
+ {
+ auto&& packet_name = *$2;
+ auto&& parent_packet_name = *$4;
+ auto&& field_definition_list = *$6;
+
+ DEBUG() << "Packet " << packet_name << " with parent " << parent_packet_name << "\n";
+ DEBUG() << "PACKET FIELD LIST SIZE: " << field_definition_list.size() << "\n";
+
+ auto parent_packet = decls->GetPacketDef(parent_packet_name);
+ if (parent_packet == nullptr) {
+ ERRORLOC(LOC) << "Could not find packet " << parent_packet_name
+ << " used as parent for " << packet_name;
+ }
+
+ auto packet_definition = new PacketDef(std::move(packet_name), std::move(field_definition_list), parent_packet);
+ packet_definition->AssignSizeFields();
+
+ $$ = packet_definition;
+ delete $2;
+ delete $4;
+ delete $6;
+ }
+ | PACKET IDENTIFIER ':' IDENTIFIER '(' constraint_list ')' '{' field_definition_list '}'
+ {
+ auto&& packet_name = *$2;
+ auto&& parent_packet_name = *$4;
+ auto&& constraints = *$6;
+ auto&& field_definition_list = *$9;
+
+ DEBUG() << "Packet " << packet_name << " with parent " << parent_packet_name << "\n";
+ DEBUG() << "PACKET FIELD LIST SIZE: " << field_definition_list.size() << "\n";
+ DEBUG() << "CONSTRAINT LIST SIZE: " << constraints.size() << "\n";
+
+ auto parent_packet = decls->GetPacketDef(parent_packet_name);
+ if (parent_packet == nullptr) {
+ ERRORLOC(LOC) << "Could not find packet " << parent_packet_name
+ << " used as parent for " << packet_name;
+ }
+
+ auto packet_definition = new PacketDef(std::move(packet_name), std::move(field_definition_list), parent_packet);
+ packet_definition->AssignSizeFields();
+
+ for (const auto& constraint : constraints) {
+ const auto& constraint_name = constraint.first;
+ const auto& constraint_value = constraint.second;
+ DEBUG() << "Parent constraint on " << constraint_name;
+ packet_definition->AddParentConstraint(constraint_name, constraint_value);
+ }
+
+ $$ = packet_definition;
+
+ delete $2;
+ delete $4;
+ delete $6;
+ delete $9;
+ }
+
+field_definition_list
+ : /* empty */
+ {
+ std::cerr << "Empty Field definition\n";
+ $$ = new FieldList();
+ }
+ | field_definition
+ {
+ std::cerr << "Field definition\n";
+ $$ = new FieldList();
+
+ if ($1->GetFieldType() == PacketField::Type::GROUP) {
+ auto group_fields = static_cast<GroupField*>($1)->GetFields();
+ FieldList reversed_fields(group_fields->rbegin(), group_fields->rend());
+ for (auto& field : reversed_fields) {
+ $$->PrependField(field);
+ }
+ delete $1;
+ break;
+ }
+
+ $$->PrependField($1);
+ }
+ | field_definition ',' field_definition_list
+ {
+ std::cerr << "Field definition with list\n";
+ $$ = $3;
+
+ if ($1->GetFieldType() == PacketField::Type::GROUP) {
+ auto group_fields = static_cast<GroupField*>($1)->GetFields();
+ FieldList reversed_fields(group_fields->rbegin(), group_fields->rend());
+ for (auto& field : reversed_fields) {
+ $$->PrependField(field);
+ }
+ delete $1;
+ break;
+ }
+
+ $$->PrependField($1);
+ }
+
+field_definition
+ : group_field_definition
+ {
+ DEBUG() << "Group Field";
+ $$ = $1;
+ }
+ | type_def_field_definition
+ {
+ std::cerr << "Field with a pre-defined type\n";
+ $$ = $1;
+ }
+ | scalar_field_definition
+ {
+ std::cerr << "Scalar field\n";
+ $$ = $1;
+ }
+ | checksum_start_field_definition
+ {
+ std::cerr << "Checksum start field\n";
+ $$ = $1;
+ }
+ | size_field_definition
+ {
+ std::cerr << "Size field\n";
+ $$ = $1;
+ }
+ | body_field_definition
+ {
+ std::cerr << "Body field\n";
+ $$ = $1;
+ }
+ | payload_field_definition
+ {
+ std::cerr << "Payload field\n";
+ $$ = $1;
+ }
+ | fixed_field_definition
+ {
+ std::cerr << "Fixed field\n";
+ $$ = $1;
+ }
+ | reserved_field_definition
+ {
+ std::cerr << "Reserved field\n";
+ $$ = $1;
+ }
+ | array_field_definition
+ {
+ std::cerr << "ARRAY field\n";
+ $$ = $1;
+ }
+
+group_field_definition
+ : IDENTIFIER
+ {
+ auto group = decls->GetGroupDef(*$1);
+ if (group == nullptr) {
+ ERRORLOC(LOC) << "Could not find group with name " << *$1;
+ }
+
+ std::list<PacketField*>* expanded_fields;
+ expanded_fields = new std::list<PacketField*>(group->begin(), group->end());
+ $$ = new GroupField(LOC, expanded_fields);
+ delete $1;
+ }
+ | IDENTIFIER '{' constraint_list '}'
+ {
+ std::cerr << "Group with fixed field(s) " << *$1 << "\n";
+ auto group = decls->GetGroupDef(*$1);
+ if (group == nullptr) {
+ ERRORLOC(LOC) << "Could not find group with name " << *$1;
+ }
+
+ std::list<PacketField*>* expanded_fields = new std::list<PacketField*>();
+ for (const auto field : *group) {
+ const auto constraint = $3->find(field->GetName());
+ if (constraint != $3->end()) {
+ if (field->GetFieldType() == PacketField::Type::SCALAR) {
+ std::cerr << "Fixing group scalar value\n";
+ expanded_fields->push_back(new FixedField(field->GetSize().bits(), std::get<int64_t>(constraint->second), LOC));
+ } else if (field->GetFieldType() == PacketField::Type::ENUM) {
+ std::cerr << "Fixing group enum value\n";
+
+ auto type_def = decls->GetTypeDef(field->GetType());
+ EnumDef* enum_def = (type_def->GetDefinitionType() == TypeDef::Type::ENUM ? (EnumDef*)type_def : nullptr);
+ if (enum_def == nullptr) {
+ ERRORLOC(LOC) << "No enum found of type " << field->GetType();
+ }
+ if (!enum_def->HasEntry(std::get<std::string>(constraint->second))) {
+ ERRORLOC(LOC) << "Enum " << field->GetType() << " has no enumeration " << std::get<std::string>(constraint->second);
+ }
+
+ expanded_fields->push_back(new FixedField(enum_def, std::get<std::string>(constraint->second), LOC));
+ } else {
+ ERRORLOC(LOC) << "Unimplemented constraint of type " << field->GetType();
+ }
+ $3->erase(constraint);
+ } else {
+ expanded_fields->push_back(field);
+ }
+ }
+ if ($3->size() > 0) {
+ ERRORLOC(LOC) << "Could not find member " << $3->begin()->first << " in group " << *$1;
+ }
+
+ $$ = new GroupField(LOC, expanded_fields);
+ delete $1;
+ delete $3;
+ }
+
+constraint_list
+ : constraint ',' constraint_list
+ {
+ std::cerr << "Group field value list\n";
+ $3->insert(*$1);
+ $$ = $3;
+ delete($1);
+ }
+ | constraint
+ {
+ std::cerr << "Group field value\n";
+ $$ = new std::map<std::string, std::variant<int64_t, std::string>>();
+ $$->insert(*$1);
+ delete($1);
+ }
+
+constraint
+ : IDENTIFIER '=' INTEGER
+ {
+ std::cerr << "Group with a fixed integer value=" << $1 << " value=" << $3 << "\n";
+
+ $$ = new std::pair(*$1, std::variant<int64_t,std::string>($3));
+ delete $1;
+ }
+ | IDENTIFIER '=' IDENTIFIER
+ {
+ DEBUG() << "Group with a fixed enum field value=" << *$3 << " enum=" << *$1;
+
+ $$ = new std::pair(*$1, std::variant<int64_t,std::string>(*$3));
+ delete $1;
+ delete $3;
+ }
+
+type_def_field_definition
+ : IDENTIFIER ':' IDENTIFIER
+ {
+ std::cerr << "Predefined type field " << *$1 << " : " << *$3 << "\n";
+ if (auto type_def = decls->GetTypeDef(*$3)) {
+ $$ = type_def->GetNewField(*$1, LOC);
+ } else {
+ ERRORLOC(LOC) << "No type with this name\n";
+ }
+ delete $1;
+ delete $3;
+ }
+
+scalar_field_definition
+ : IDENTIFIER ':' INTEGER
+ {
+ std::cerr << "Scalar field " << *$1 << " : " << $3 << "\n";
+ $$ = new ScalarField(*$1, $3, LOC);
+ delete $1;
+ }
+
+body_field_definition
+ : BODY
+ {
+ std::cerr << "Body field\n";
+ $$ = new BodyField(LOC);
+ }
+
+payload_field_definition
+ : PAYLOAD ':' '[' SIZE_MODIFIER ']'
+ {
+ std::cerr << "Payload field with modifier " << *$4 << "\n";
+ $$ = new PayloadField(*$4, LOC);
+ delete $4;
+ }
+ | PAYLOAD ':' '[' INTEGER ']'
+ {
+ ERRORLOC(LOC) << "Payload fields can only be dynamically sized.";
+ }
+ | PAYLOAD
+ {
+ std::cerr << "Payload field\n";
+ $$ = new PayloadField("", LOC);
+ }
+
+checksum_start_field_definition
+ : CHECKSUM_START '(' IDENTIFIER ')'
+ {
+ std::cerr << "ChecksumStart field defined\n";
+ $$ = new ChecksumStartField(*$3, LOC);
+ delete $3;
+ }
+
+size_field_definition
+ : SIZE '(' IDENTIFIER ')' ':' INTEGER
+ {
+ std::cerr << "Size field defined\n";
+ $$ = new SizeField(*$3, $6, false, LOC);
+ delete $3;
+ }
+ | SIZE '(' PAYLOAD ')' ':' INTEGER
+ {
+ std::cerr << "Size for payload defined\n";
+ $$ = new SizeField("payload", $6, false, LOC);
+ }
+ | COUNT '(' IDENTIFIER ')' ':' INTEGER
+ {
+ std::cerr << "Count field defined\n";
+ $$ = new SizeField(*$3, $6, true, LOC);
+ delete $3;
+ }
+ | COUNT '(' PAYLOAD ')' ':' INTEGER
+ {
+ ERRORLOC(LOC) << "Can not use count to describe payload fields.";
+ }
+
+fixed_field_definition
+ : FIXED '=' INTEGER ':' INTEGER
+ {
+ std::cerr << "Fixed field defined value=" << $3 << " size=" << $5 << "\n";
+ $$ = new FixedField($5, $3, LOC);
+ }
+ | FIXED '=' IDENTIFIER ':' IDENTIFIER
+ {
+ DEBUG() << "Fixed enum field defined value=" << *$3 << " enum=" << *$5;
+ auto type_def = decls->GetTypeDef(*$5);
+ if (type_def != nullptr) {
+ EnumDef* enum_def = (type_def->GetDefinitionType() == TypeDef::Type::ENUM ? (EnumDef*)type_def : nullptr);
+ if (!enum_def->HasEntry(*$3)) {
+ ERRORLOC(LOC) << "Previously defined enum " << enum_def->GetTypeName() << " has no entry for " << *$3;
+ }
+
+ $$ = new FixedField(enum_def, *$3, LOC);
+ } else {
+ ERRORLOC(LOC) << "No enum found with name " << *$5;
+ }
+
+ delete $3;
+ delete $5;
+ }
+
+reserved_field_definition
+ : RESERVED ':' INTEGER
+ {
+ std::cerr << "Reserved field of size=" << $3 << "\n";
+ $$ = new ReservedField($3, LOC);
+ }
+
+array_field_definition
+ : IDENTIFIER ':' INTEGER '[' ']'
+ {
+ DEBUG() << "Array field defined name=" << *$1 << " element_size=" << $3;
+ $$ = new ArrayField(*$1, $3, "", LOC);
+ delete $1;
+ }
+ | IDENTIFIER ':' INTEGER '[' SIZE_MODIFIER ']'
+ {
+ DEBUG() << "Array field defined name=" << *$1 << " element_size=" << $3
+ << " size_modifier=" << *$5;
+ $$ = new ArrayField(*$1, $3, *$5, LOC);
+ delete $1;
+ delete $5;
+ }
+ | IDENTIFIER ':' INTEGER '[' INTEGER ']'
+ {
+ DEBUG() << "Array field defined name=" << *$1 << " element_size=" << $3
+ << " fixed_size=" << $5;
+ $$ = new ArrayField(*$1, $3, $5, LOC);
+ delete $1;
+ }
+ | IDENTIFIER ':' IDENTIFIER '[' ']'
+ {
+ DEBUG() << "Array field defined name=" << *$1 << " type=" << *$3;
+ if (auto type_def = decls->GetTypeDef(*$3)) {
+ $$ = new ArrayField(*$1, type_def, "", LOC);
+ } else {
+ ERRORLOC(LOC) << "Can't find type used in array field.";
+ }
+ delete $1;
+ delete $3;
+ }
+ | IDENTIFIER ':' IDENTIFIER '[' SIZE_MODIFIER ']'
+ {
+ DEBUG() << "Array field defined name=" << *$1 << " type=" << *$3
+ << " size_modifier=" << *$5;
+ if (auto type_def = decls->GetTypeDef(*$3)) {
+ $$ = new ArrayField(*$1, type_def, *$5, LOC);
+ } else {
+ ERRORLOC(LOC) << "Can't find type used in array field.";
+ }
+ delete $1;
+ delete $3;
+ delete $5;
+ }
+ | IDENTIFIER ':' IDENTIFIER '[' INTEGER ']'
+ {
+ DEBUG() << "Array field defined name=" << *$1 << " type=" << *$3
+ << " fixed_size=" << $5;
+ if (auto type_def = decls->GetTypeDef(*$3)) {
+ $$ = new ArrayField(*$1, type_def, $5, LOC);
+ } else {
+ ERRORLOC(LOC) << "Can't find type used in array field.";
+ }
+ delete $1;
+ delete $3;
+ }
+
+%%
+
+
+void yy::parser::error(const yy::parser::location_type& loc, const std::string& error) {
+ std::cerr << error << " at location " << loc << "\n";
+ abort();
+}
diff --git a/gd/packet/parser/logging.h b/gd/packet/parser/logging.h
new file mode 100644
index 0000000..8d9e467
--- /dev/null
+++ b/gd/packet/parser/logging.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2019 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 <initializer_list>
+#include <iostream>
+#include <sstream>
+#include <vector>
+
+#include "parse_location.h"
+
+class Loggable {
+ public:
+ virtual ~Loggable() = default;
+ virtual std::string GetDebugName() const = 0;
+ virtual ParseLocation GetLocation() const = 0;
+};
+
+class LogMessage {
+ public:
+ LogMessage(ParseLocation loc, std::initializer_list<const Loggable*> tokens)
+ : debug_(false), loc_(loc), tokens_(tokens) {
+ Init();
+ }
+
+ LogMessage(bool debug, std::initializer_list<const Loggable*> tokens) : debug_(debug), tokens_(tokens) {
+ Init();
+ }
+
+ void Init() {
+ if (loc_.GetLine() != -1) {
+ stream_ << "\033[1mLine " << loc_.GetLine() << ": ";
+ }
+
+ if (!debug_) {
+ stream_ << "\033[1;31m";
+ stream_ << "ERROR: ";
+ stream_ << "\033[0m";
+ } else {
+ stream_ << "\033[1;m";
+ stream_ << "DEBUG: ";
+ stream_ << "\033[0m";
+ }
+ }
+
+ ~LogMessage() {
+ std::cerr << stream_.str() << "\n";
+ for (const auto& token : tokens_) {
+ // Bold line number
+ std::cerr << "\033[1m";
+ std::cerr << " Line " << token->GetLocation().GetLine() << ": ";
+ std::cerr << "\033[0m";
+ std::cerr << token->GetDebugName() << "\n";
+ }
+
+ if (!debug_) {
+ abort();
+ }
+ }
+
+ std::ostream& stream() {
+ return stream_;
+ }
+
+ private:
+ std::ostringstream stream_;
+ bool debug_;
+ ParseLocation loc_;
+ std::vector<const Loggable*> tokens_;
+};
+
+// Error Log stream. Aborts the program after the message is printed.
+// The arguments to the macro is a list of Loggable objects that are printed when the error is printed.
+#define ERROR(...) LogMessage(false, {__VA_ARGS__}).stream()
+
+// ParseLocation error log, the first argument is a location.
+#define ERRORLOC(_1, ...) LogMessage(_1, {__VA_ARGS__}).stream()
+
+#define DEBUG(...) LogMessage(true, {__VA_ARGS__}).stream()
diff --git a/gd/packet/parser/main.cc b/gd/packet/parser/main.cc
new file mode 100644
index 0000000..e3fe16a
--- /dev/null
+++ b/gd/packet/parser/main.cc
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2019 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 <unistd.h>
+#include <cstdio>
+#include <filesystem>
+#include <fstream>
+#include <iostream>
+#include <queue>
+#include <regex>
+#include <sstream>
+#include <vector>
+
+#include "declarations.h"
+
+#include "language_y.h"
+
+void yylex_init(void**);
+void yylex_destroy(void*);
+void yyset_debug(int, void*);
+void yyset_in(FILE*, void*);
+
+namespace {
+
+const std::string kBluetoothTopNamespace = "bluetooth";
+
+void parse_namespace(std::filesystem::path input_file_relative_path, std::vector<std::string>& token) {
+ std::filesystem::path gen_namespace = kBluetoothTopNamespace / input_file_relative_path;
+ std::string gen_namespace_str = gen_namespace;
+ std::regex path_tokenizer("/");
+ auto it = std::sregex_token_iterator(gen_namespace_str.cbegin(), gen_namespace_str.cend(), path_tokenizer, -1);
+ std::sregex_token_iterator it_end;
+ for (; it != it_end; ++it) {
+ token.push_back(it->str());
+ }
+}
+
+void generate_namespace_open(const std::vector<std::string>& token, std::ostream& output) {
+ for (auto it = token.begin(); it != token.end(); ++it) {
+ output << "namespace " << *it << " {" << std::endl;
+ }
+}
+
+void generate_namespace_close(const std::vector<std::string>& token, std::ostream& output) {
+ for (auto it = token.rbegin(); it != token.rend(); ++it) {
+ output << "} //namespace " << *it << std::endl;
+ }
+}
+
+bool parse_one_file(std::filesystem::path input_file, std::filesystem::path include_dir,
+ std::filesystem::path out_dir) {
+ auto gen_relative_path = input_file.lexically_relative(include_dir).parent_path();
+
+ auto input_filename = input_file.filename().string().substr(0, input_file.filename().string().find(".pdl"));
+ auto gen_path = out_dir / gen_relative_path;
+
+ std::filesystem::create_directories(gen_path);
+
+ auto gen_file = gen_path / (input_filename + ".h");
+
+ void* scanner;
+ yylex_init(&scanner);
+
+ FILE* in_file = fopen(input_file.string().c_str(), "r");
+ if (in_file == nullptr) {
+ std::cerr << "can't open " << input_file << ": " << strerror(errno) << std::endl;
+ return false;
+ }
+
+ yyset_in(in_file, scanner);
+
+ std::ofstream out_file;
+ out_file.open(gen_file);
+ if (!out_file.is_open()) {
+ std::cerr << "can't open " << gen_file << std::endl;
+ return false;
+ }
+
+ Declarations decls;
+ int ret = yy::parser(scanner, &decls).parse();
+
+ yylex_destroy(scanner);
+
+ if (ret != 0) {
+ std::cerr << "yylex parsing failed: returned " << ret << std::endl;
+ return false;
+ }
+
+ out_file << "\n\n";
+ out_file << "#pragma once\n";
+ out_file << "\n\n";
+ out_file << "#include <stdint.h>\n";
+ out_file << "#include <string>\n";
+ out_file << "#include <functional>\n";
+ out_file << "\n\n";
+ out_file << "#include \"os/log.h\"\n";
+ out_file << "#include \"packet/base_packet_builder.h\"\n";
+ out_file << "#include \"packet/bit_inserter.h\"\n";
+ out_file << "#include \"packet/packet_builder.h\"\n";
+ out_file << "#include \"packet/packet_view.h\"\n";
+ out_file << "#include \"packet/parser/checksum_type_checker.h\"\n";
+ out_file << "\n\n";
+
+ for (const auto& c : decls.type_defs_queue_) {
+ c.second->GenInclude(out_file);
+ }
+ out_file << "\n\n";
+
+ std::vector<std::string> namespace_list;
+ parse_namespace(gen_relative_path, namespace_list);
+ generate_namespace_open(namespace_list, out_file);
+ out_file << "\n\n";
+
+ for (const auto& c : decls.type_defs_queue_) {
+ c.second->GenUsing(out_file);
+ }
+ out_file << "\n\n";
+
+ out_file << "using ::bluetooth::packet::BasePacketBuilder;";
+ out_file << "using ::bluetooth::packet::BitInserter;";
+ out_file << "using ::bluetooth::packet::kLittleEndian;";
+ out_file << "using ::bluetooth::packet::PacketBuilder;";
+ out_file << "using ::bluetooth::packet::PacketView;";
+ out_file << "using ::bluetooth::packet::parser::ChecksumTypeChecker;";
+ out_file << "\n\n";
+
+ for (const auto& e : decls.type_defs_queue_) {
+ if (e.second->GetDefinitionType() == TypeDef::Type::ENUM) {
+ EnumGen gen(*(EnumDef*)e.second);
+ gen.GenDefinition(out_file);
+ out_file << "\n\n";
+ }
+ }
+ for (const auto& e : decls.type_defs_queue_) {
+ if (e.second->GetDefinitionType() == TypeDef::Type::ENUM) {
+ EnumGen gen(*(EnumDef*)e.second);
+ gen.GenLogging(out_file);
+ out_file << "\n\n";
+ }
+ }
+ for (const auto& ch : decls.type_defs_queue_) {
+ if (ch.second->GetDefinitionType() == TypeDef::Type::CHECKSUM) {
+ ((ChecksumDef*)ch.second)->GenChecksumCheck(out_file);
+ }
+ out_file << "\n/* Done ChecksumChecks */\n";
+ }
+
+ for (size_t i = 0; i < decls.packet_defs_queue_.size(); i++) {
+ decls.packet_defs_queue_[i].second.SetEndianness(decls.is_little_endian);
+ decls.packet_defs_queue_[i].second.GenParserDefinition(out_file);
+ out_file << "\n\n";
+ }
+
+ for (const auto p : decls.packet_defs_queue_) {
+ p.second.GenBuilderDefinition(out_file);
+ out_file << "\n\n";
+ }
+
+ generate_namespace_close(namespace_list, out_file);
+
+ out_file.close();
+ fclose(in_file);
+
+ return true;
+}
+
+} // namespace
+
+int main(int argc, const char** argv) {
+ std::filesystem::path out_dir;
+ std::filesystem::path include_dir;
+ std::queue<std::filesystem::path> input_files;
+ const std::string arg_out = "--out=";
+ const std::string arg_include = "--include=";
+
+ for (int i = 1; i < argc; i++) {
+ std::string arg = argv[i];
+ if (arg.find(arg_out) == 0) {
+ auto out_path = std::filesystem::path(arg.substr(arg_out.size()));
+ out_dir = std::filesystem::current_path() / std::filesystem::path(arg.substr(arg_out.size()));
+ } else if (arg.find(arg_include) == 0) {
+ auto include_path = std::filesystem::path(arg.substr(arg_out.size()));
+ include_dir = std::filesystem::current_path() / std::filesystem::path(arg.substr(arg_include.size()));
+ } else {
+ input_files.emplace(std::filesystem::current_path() / std::filesystem::path(arg));
+ }
+ }
+ if (out_dir == std::filesystem::path() || include_dir == std::filesystem::path()) {
+ std::cerr << "Usage: bt-packetgen --out=OUT --include=INCLUDE input_files..." << std::endl;
+ return 1;
+ }
+
+ while (!input_files.empty()) {
+ if (!parse_one_file(input_files.front(), include_dir, out_dir)) {
+ std::cerr << "Didn't parse " << input_files.front() << " correctly" << std::endl;
+ return 2;
+ }
+ input_files.pop();
+ }
+
+ return 0;
+}
diff --git a/gd/packet/parser/packet_def.cc b/gd/packet/parser/packet_def.cc
new file mode 100644
index 0000000..2332357
--- /dev/null
+++ b/gd/packet/parser/packet_def.cc
@@ -0,0 +1,782 @@
+/*
+ * Copyright 2019 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 "packet_def.h"
+
+#include <list>
+#include <set>
+
+#include "fields/all_fields.h"
+#include "util.h"
+
+PacketDef::PacketDef(std::string name, FieldList fields) : name_(name), fields_(fields), parent_(nullptr){};
+PacketDef::PacketDef(std::string name, FieldList fields, PacketDef* parent)
+ : name_(name), fields_(fields), parent_(parent){};
+
+void PacketDef::AddParentConstraint(std::string field_name, std::variant<int64_t, std::string> value) {
+ // NOTE: This could end up being very slow if there are a lot of constraints.
+ const auto& parent_params = parent_->GetParamList();
+ const auto& constrained_field = parent_params.GetField(field_name);
+ if (constrained_field == nullptr) {
+ ERROR() << "Attempting to constrain field " << field_name << " in parent packet " << parent_->name_
+ << ", but no such field exists.";
+ }
+
+ if (constrained_field->GetFieldType() == PacketField::Type::SCALAR) {
+ if (!std::holds_alternative<int64_t>(value)) {
+ ERROR(constrained_field) << "Attemting to constrain a scalar field using an enum value in packet "
+ << parent_->name_ << ".";
+ }
+ } else if (constrained_field->GetFieldType() == PacketField::Type::ENUM) {
+ if (!std::holds_alternative<std::string>(value)) {
+ ERROR(constrained_field) << "Attemting to constrain an enum field using an scalar value in packet "
+ << parent_->name_ << ".";
+ }
+ const auto& enum_def = static_cast<EnumField*>(constrained_field)->GetEnumDef();
+ if (!enum_def.HasEntry(std::get<std::string>(value))) {
+ ERROR(constrained_field) << "No matching enumeration \"" << std::get<std::string>(value)
+ << "for constraint on enum in parent packet " << parent_->name_ << ".";
+ }
+
+ // For enums, we have to qualify the value using the enum type name.
+ value = enum_def.GetTypeName() + "::" + std::get<std::string>(value);
+ } else {
+ ERROR(constrained_field) << "Field in parent packet " << parent_->name_ << " is not viable for constraining.";
+ }
+
+ parent_constraints_.insert(std::pair(field_name, value));
+}
+
+// Assign all size fields to their corresponding variable length fields.
+// Will crash if
+// - there aren't any fields that don't match up to a field.
+// - the size field points to a fixed size field.
+// - if the size field comes after the variable length field.
+void PacketDef::AssignSizeFields() {
+ for (const auto& field : fields_) {
+ DEBUG() << "field name: " << field->GetName();
+
+ if (field->GetFieldType() != PacketField::Type::SIZE && field->GetFieldType() != PacketField::Type::COUNT) {
+ continue;
+ }
+
+ const SizeField* size_field = nullptr;
+ size_field = static_cast<SizeField*>(field);
+ // Check to see if a corresponding field can be found.
+ const auto& var_len_field = fields_.GetField(size_field->GetSizedFieldName());
+ if (var_len_field == nullptr) {
+ ERROR(field) << "Could not find corresponding field for size/count field.";
+ }
+
+ // Do the ordering check to ensure the size field comes before the
+ // variable length field.
+ for (auto it = fields_.begin(); *it != size_field; it++) {
+ DEBUG() << "field name: " << (*it)->GetName();
+ if (*it == var_len_field) {
+ ERROR(var_len_field, size_field) << "Size/count field must come before the variable length field it describes.";
+ }
+ }
+
+ if (var_len_field->GetFieldType() == PacketField::Type::PAYLOAD) {
+ const auto& payload_field = static_cast<PayloadField*>(var_len_field);
+ payload_field->SetSizeField(size_field);
+ continue;
+ }
+
+ if (var_len_field->GetFieldType() == PacketField::Type::ARRAY) {
+ const auto& array_field = static_cast<ArrayField*>(var_len_field);
+ array_field->SetSizeField(size_field);
+ continue;
+ }
+
+ // TODO: If there is an array field without a size field, check to see if the
+ // parent has a size(payload) field. Or maybe we can just figure it out based
+ // on the offsets fo the packet.
+
+ // If we've reached this point then the field wasn't a variable length field.
+ // Check to see if the field is a variable length field
+ std::cerr << "Can not use size/count in reference to a fixed size field.\n";
+ abort();
+ }
+}
+
+void PacketDef::SetEndianness(bool is_little_endian) {
+ is_little_endian_ = is_little_endian;
+}
+
+// Get the size for the packet. You scan specify without_payload in order
+// to exclude payload fields as child packets will be overriding it.
+Size PacketDef::GetSize(bool without_payload) const {
+ auto size = Size();
+
+ for (const auto& field : fields_) {
+ if (without_payload && field->GetFieldType() == PacketField::Type::PAYLOAD) {
+ continue;
+ }
+
+ size += field->GetSize();
+ }
+
+ if (parent_ != nullptr) {
+ size += parent_->GetSize(true);
+ }
+
+ return size;
+}
+
+// Get the offset until the field is reached, if there is no field
+// returns an empty Size. from_end requests the offset to the field
+// starting from the end() iterator. If there is a field with an unknown
+// size along the traversal, then an empty size is returned.
+Size PacketDef::GetOffsetForField(std::string field_name, bool from_end) const {
+ // Check first if the field exists.
+ if (fields_.GetField(field_name) == nullptr) {
+ if (field_name != "payload" && field_name != "body") {
+ ERROR() << "Can't find a field offset for nonexistent field named: " << field_name;
+ } else {
+ return Size();
+ }
+ }
+
+ // We have to use a generic lambda to conditionally change iteration direction
+ // due to iterator and reverse_iterator being different types.
+ auto size_lambda = [&](auto from, auto to) -> Size {
+ auto size = Size(0);
+ for (auto it = from; it != to; it++) {
+ // We've reached the field, end the loop.
+ if ((*it)->GetName() == field_name) break;
+ const auto& field = *it;
+ // If there was a field that wasn't the payload with an unknown size,
+ // return an empty Size.
+ if (field->GetSize().empty()) {
+ return Size();
+ }
+ size += field->GetSize();
+ }
+ return size;
+ };
+
+ // Change iteration direction based on from_end.
+ auto size = Size();
+ if (from_end)
+ size = size_lambda(fields_.rbegin(), fields_.rend());
+ else
+ size = size_lambda(fields_.begin(), fields_.end());
+ if (size.empty()) return Size();
+
+ // For parent packets we need the offset until a payload or body field.
+ if (parent_ != nullptr) {
+ auto parent_payload_offset = parent_->GetOffsetForField("payload", from_end);
+ if (!parent_payload_offset.empty()) {
+ size += parent_payload_offset;
+ } else {
+ parent_payload_offset = parent_->GetOffsetForField("body", from_end);
+ if (!parent_payload_offset.empty()) {
+ size += parent_payload_offset;
+ } else {
+ return Size();
+ }
+ }
+ }
+
+ return size;
+}
+
+void PacketDef::GenParserDefinition(std::ostream& s) const {
+ s << "class " << name_ << "View";
+ if (parent_ != nullptr) {
+ s << " : public " << parent_->name_ << "View {";
+ } else {
+ s << " : public PacketView<" << (is_little_endian_ ? "" : "!") << "kLittleEndian> {";
+ }
+ s << " public:";
+
+ // Specialize function
+ if (parent_ != nullptr) {
+ s << "static " << name_ << "View Create(" << parent_->name_ << "View parent)";
+ s << "{ return " << name_ << "View(parent); }";
+ } else {
+ s << "static " << name_ << "View Create(PacketView<" << (is_little_endian_ ? "" : "!") << "kLittleEndian> packet) ";
+ s << "{ return " << name_ << "View(packet); }";
+ }
+
+ std::set<PacketField::Type> fixed_types = {
+ PacketField::Type::FIXED_SCALAR,
+ PacketField::Type::FIXED_ENUM,
+ };
+
+ // Print all of the public fields which are all the fields minus the fixed fields.
+ const auto& public_fields = fields_.GetFieldsWithoutTypes(fixed_types);
+ bool has_fixed_fields = public_fields.size() != fields_.size();
+ for (const auto& field : public_fields) {
+ GenParserFieldGetter(s, field);
+ s << "\n";
+ }
+ GenValidator(s);
+ s << "\n";
+
+ s << " protected:\n";
+ // Constructor from a View
+ if (parent_ != nullptr) {
+ s << name_ << "View(" << parent_->name_ << "View parent)";
+ s << " : " << parent_->name_ << "View(parent) { was_validated_ = false; }";
+ } else {
+ s << name_ << "View(PacketView<" << (is_little_endian_ ? "" : "!") << "kLittleEndian> packet) ";
+ s << " : PacketView<" << (is_little_endian_ ? "" : "!") << "kLittleEndian>(packet) { was_validated_ = false;}";
+ }
+
+ // Print the private fields which are the fixed fields.
+ if (has_fixed_fields) {
+ const auto& private_fields = fields_.GetFieldsWithTypes(fixed_types);
+ s << " private:\n";
+ for (const auto& field : private_fields) {
+ GenParserFieldGetter(s, field);
+ s << "\n";
+ }
+ }
+ s << "};\n";
+}
+
+void PacketDef::GenParserFieldGetter(std::ostream& s, const PacketField* field) const {
+ // Start field offset
+ auto start_field_offset = GetOffsetForField(field->GetName(), false);
+ auto end_field_offset = GetOffsetForField(field->GetName(), true);
+
+ if (start_field_offset.empty() && end_field_offset.empty()) {
+ std::cerr << "Field location for " << field->GetName() << " is ambiguous, "
+ << "no method exists to determine field location from begin() or end().\n";
+ abort();
+ }
+
+ field->GenGetter(s, start_field_offset, end_field_offset);
+}
+
+void PacketDef::GenSerialize(std::ostream& s) const {
+ auto header_fields = fields_.GetFieldsBeforePayloadOrBody();
+ auto footer_fields = fields_.GetFieldsAfterPayloadOrBody();
+
+ s << "protected:";
+ s << "void SerializeHeader(BitInserter&";
+ if (parent_ != nullptr || header_fields.size() != 0) {
+ s << " i ";
+ }
+ s << ") const {";
+
+ if (parent_ != nullptr) {
+ s << parent_->name_ << "Builder::SerializeHeader(i);";
+ }
+
+ for (const auto& field : header_fields) {
+ if (field->GetFieldType() == PacketField::Type::SIZE) {
+ const auto& field_name = ((SizeField*)field)->GetSizedFieldName();
+ const auto& sized_field = fields_.GetField(field_name);
+ if (sized_field == nullptr) {
+ ERROR(field) << __func__ << "Can't find sized field named " << field_name;
+ }
+ if (sized_field->GetFieldType() == PacketField::Type::PAYLOAD) {
+ s << "size_t payload_bytes = GetPayloadSize();";
+ std::string modifier = ((PayloadField*)sized_field)->size_modifier_;
+ if (modifier != "") {
+ s << "static_assert((" << modifier << ")%8 == 0, \"Modifiers must be byte-aligned\");";
+ s << "payload_bytes = payload_bytes + (" << modifier << ") / 8;";
+ }
+ s << "ASSERT(payload_bytes < (static_cast<size_t>(1) << " << field->GetSize().bits() << "));";
+ s << "insert(static_cast<" << field->GetType() << ">(payload_bytes), i," << field->GetSize().bits() << ");";
+ } else {
+ if (sized_field->GetFieldType() != PacketField::Type::ARRAY) {
+ ERROR(field) << __func__ << "Unhandled sized field type for " << field_name;
+ }
+ const auto& array_name = field_name + "_";
+ const ArrayField* array = (ArrayField*)sized_field;
+ if (array->element_size_ == -1) {
+ ERROR(field) << __func__ << "Unhandled dynamically sized field type for " << field_name;
+ } else {
+ s << "size_t " << array_name + "bytes = ";
+ s << array_name << ".size() * (" << array->element_size_ << " / 8);";
+ s << "ASSERT(" << array_name + "bytes < (1 << " << field->GetSize().bits() << "));";
+ s << "insert(" << array_name << "bytes";
+ s << array->GetSizeModifier() << ", i, ";
+ s << field->GetSize().bits() << ");";
+ }
+ }
+ } else if (field->GetFieldType() == PacketField::Type::CHECKSUM_START) {
+ const auto& field_name = ((ChecksumStartField*)field)->GetStartedFieldName();
+ const auto& started_field = fields_.GetField(field_name);
+ if (started_field == nullptr) {
+ ERROR(field) << __func__ << ": Can't find checksum field named " << field_name << "(" << field->GetName()
+ << ")";
+ }
+ s << "auto shared_checksum_ptr = std::make_shared<" << started_field->GetType() << ">();";
+ s << started_field->GetType() << "::Initialize(*shared_checksum_ptr);";
+ s << "i.RegisterObserver(packet::ByteObserver(";
+ s << "[shared_checksum_ptr](uint8_t byte){" << started_field->GetType()
+ << "::AddByte(*shared_checksum_ptr, byte);},";
+ s << "[shared_checksum_ptr](){ return static_cast<uint64_t>(" << started_field->GetType()
+ << "::GetChecksum(*shared_checksum_ptr));}));";
+ } else if (field->GetFieldType() == PacketField::Type::COUNT) {
+ const auto& array_name = ((SizeField*)field)->GetSizedFieldName() + "_";
+ s << "insert(" << array_name << ".size(), i, " << field->GetSize().bits() << ");";
+ } else {
+ field->GenInserter(s);
+ }
+ }
+ s << "}\n\n";
+
+ s << "void SerializeFooter(BitInserter&";
+ if (parent_ != nullptr || footer_fields.size() != 0) {
+ s << " i ";
+ }
+ s << ") const {";
+
+ for (const auto& field : footer_fields) {
+ field->GenInserter(s);
+ }
+ if (parent_ != nullptr) {
+ s << parent_->name_ << "Builder::SerializeFooter(i);";
+ }
+ s << "}\n\n";
+
+ s << "public:";
+ s << "virtual void Serialize(BitInserter& i) const override {";
+ s << "SerializeHeader(i);";
+ if (fields_.HasPayload()) {
+ s << "payload_->Serialize(i);";
+ }
+ s << "SerializeFooter(i);";
+
+ s << "}\n";
+}
+
+void PacketDef::GenBuilderSize(std::ostream& s) const {
+ auto header_fields = fields_.GetFieldsBeforePayloadOrBody();
+ auto footer_fields = fields_.GetFieldsAfterPayloadOrBody();
+
+ s << "protected:";
+ s << "size_t BitsOfHeader() const {";
+ s << "return ";
+
+ if (parent_ != nullptr) {
+ s << parent_->name_ << "Builder::BitsOfHeader() + ";
+ }
+
+ size_t header_bits = 0;
+ for (const auto& field : header_fields) {
+ header_bits += field->GetSize().bits();
+ }
+ s << header_bits << ";";
+
+ s << "}\n\n";
+
+ s << "size_t BitsOfFooter() const {";
+ s << "return ";
+ size_t footer_bits = 0;
+ for (const auto& field : footer_fields) {
+ footer_bits += field->GetSize().bits();
+ }
+
+ if (parent_ != nullptr) {
+ s << parent_->name_ << "Builder::BitsOfFooter() + ";
+ }
+ s << footer_bits << ";";
+ s << "}\n\n";
+
+ if (fields_.HasPayload()) {
+ s << "size_t GetPayloadSize() const {";
+ s << "if (payload_ != nullptr) {return payload_->size();}";
+ s << "else { return size() - (BitsOfHeader() + BitsOfFooter()) / 8;}";
+ s << ";}\n\n";
+ }
+
+ s << "public:";
+ s << "virtual size_t size() const override {";
+ s << "return (BitsOfHeader() / 8)";
+ if (fields_.HasPayload()) {
+ s << "+ payload_->size()";
+ }
+ s << " + (BitsOfFooter() / 8);";
+ s << "}\n";
+}
+
+void PacketDef::GenValidator(std::ostream& s) const {
+ // Get the static offset for all of our fields.
+ int bits_size = 0;
+ for (const auto& field : fields_) {
+ bits_size += field->GetSize().bits();
+ }
+
+ // Write the function declaration.
+ s << "virtual bool IsValid() " << (parent_ != nullptr ? " override" : "") << " {";
+ s << "if (was_validated_) { return true; } ";
+ s << "else { was_validated_ = true; was_validated_ = IsValid_(); return was_validated_; }";
+ s << "}";
+
+ s << "protected:";
+ s << "virtual bool IsValid_() const {";
+
+ // Offset by the parents known size. We know that any dynamic fields can
+ // already be called since the parent must have already been validated by
+ // this point.
+ auto parent_size = Size();
+ if (parent_ != nullptr) {
+ parent_size = parent_->GetSize(true);
+ }
+
+ s << "auto it = begin() + " << parent_size.bytes() << " + (" << parent_size.dynamic_string() << ");";
+
+ // Check if you can extract the static fields.
+ // At this point you know you can use the size getters without crashing
+ // as long as they follow the instruction that size fields cant come before
+ // their corrisponding variable length field.
+ s << "it += " << ((bits_size + 7) / 8) << " /* Total size of the fixed fields */;";
+ s << "if (it > end()) return false;";
+
+ // For any variable length fields, use their size check.
+ for (const auto& field : fields_) {
+ if (field->GetFieldType() == PacketField::Type::CHECKSUM_START) {
+ auto offset = GetOffsetForField(field->GetName(), false);
+ if (!offset.empty()) {
+ s << "size_t sum_index = " << offset.bytes() << " + (" << offset.dynamic_string() << ");";
+ } else {
+ offset = GetOffsetForField(field->GetName(), true);
+ if (offset.empty()) {
+ ERROR(field) << "Checksum Start Field offset can not be determined.";
+ }
+ s << "size_t sum_index = size() - " << offset.bytes() << " - (" << offset.dynamic_string() << ");";
+ }
+
+ const auto& field_name = ((ChecksumStartField*)field)->GetStartedFieldName();
+ const auto& started_field = fields_.GetField(field_name);
+ if (started_field == nullptr) {
+ ERROR(field) << __func__ << ": Can't find checksum field named " << field_name << "(" << field->GetName()
+ << ")";
+ }
+ auto end_offset = GetOffsetForField(started_field->GetName(), false);
+ if (!end_offset.empty()) {
+ s << "size_t end_sum_index = " << end_offset.bytes() << " + (" << end_offset.dynamic_string() << ");";
+ } else {
+ end_offset = GetOffsetForField(started_field->GetName(), true);
+ if (end_offset.empty()) {
+ ERROR(started_field) << "Checksum Field end_offset can not be determined.";
+ }
+ s << "size_t end_sum_index = size() - " << started_field->GetSize().bytes() << " - " << end_offset.bytes()
+ << " - (" << end_offset.dynamic_string() << ");";
+ }
+ if (is_little_endian_) {
+ s << "auto checksum_view = GetLittleEndianSubview(sum_index, end_sum_index);";
+ } else {
+ s << "auto checksum_view = GetBigEndianSubview(sum_index, end_sum_index);";
+ }
+ s << started_field->GetType() << " checksum;";
+ s << started_field->GetType() << "::Initialize(checksum);";
+ s << "for (uint8_t byte : checksum_view) { ";
+ s << started_field->GetType() << "::AddByte(checksum, byte);}";
+ s << "if (" << started_field->GetType() << "::GetChecksum(checksum) != (begin() + end_sum_index).extract<"
+ << util::GetTypeForSize(started_field->GetSize().bits()) << ">()) { return false; }";
+
+ continue;
+ }
+
+ auto field_size = field->GetSize();
+ // Fixed size fields have already been handled.
+ if (!field_size.has_dynamic()) {
+ continue;
+ }
+
+ // Custom fields with dynamic size must have the offset for the field passed in as well
+ // as the end iterator so that they may ensure that they don't try to read past the end.
+ // Custom fields with fixed sizes will be handled in the static offset checking.
+ if (field->GetFieldType() == PacketField::Type::CUSTOM) {
+ const auto& custom_size_var = field->GetName() + "_size";
+
+ // Check if we can determine offset from begin(), otherwise error because by this point,
+ // the size of the custom field is unknown and can't be subtracted from end() to get the
+ // offset.
+ auto offset = GetOffsetForField(field->GetName(), false);
+ if (offset.empty()) {
+ ERROR(field) << "Custom Field offset can not be determined from begin().";
+ }
+
+ if (offset.bits() % 8 != 0) {
+ ERROR(field) << "Custom fields must be byte aligned.";
+ }
+
+ // Custom fields are special as their size field takes an argument.
+ s << "const auto& " << custom_size_var << " = " << field_size.dynamic_string();
+ s << "(begin() + " << offset.bytes() << " + (" << offset.dynamic_string() << "));";
+
+ s << "if (!" << custom_size_var << ".has_value()) { return false; }";
+ s << "it += *" << custom_size_var << ";";
+ s << "if (it > end()) return false;";
+ continue;
+ } else {
+ s << "it += " << field_size.dynamic_string() << ";";
+ s << "if (it > end()) return false;";
+ }
+ }
+
+ // Validate constraints after validating the size
+ if (parent_constraints_.size() > 0 && parent_ == nullptr) {
+ ERROR() << "Can't have a constraint on a NULL parent";
+ }
+
+ for (const auto& constraint : parent_constraints_) {
+ s << "if (Get" << util::UnderscoreToCamelCase(constraint.first) << "() != ";
+ const auto& field = parent_->GetParamList().GetField(constraint.first);
+ if (field->GetFieldType() == PacketField::Type::SCALAR) {
+ s << std::get<int64_t>(constraint.second);
+ } else {
+ s << std::get<std::string>(constraint.second);
+ }
+ s << ") return false;";
+ }
+
+ // Validate the packets fields last
+ for (const auto& field : fields_) {
+ field->GenValidator(s);
+ s << "\n";
+ }
+
+ s << "return true;";
+ s << "}\n";
+ if (parent_ == nullptr) {
+ s << "bool was_validated_{false};\n";
+ }
+}
+
+void PacketDef::GenBuilderDefinition(std::ostream& s) const {
+ s << "class " << name_ << "Builder";
+ if (parent_ != nullptr) {
+ s << " : public " << parent_->name_ << "Builder";
+ } else {
+ if (is_little_endian_) {
+ s << " : public PacketBuilder<kLittleEndian>";
+ } else {
+ s << " : public PacketBuilder<!kLittleEndian>";
+ }
+ }
+ s << " {";
+ s << " public:";
+ s << " virtual ~" << name_ << "Builder()" << (parent_ != nullptr ? " override" : "") << " = default;";
+
+ if (!fields_.HasBody()) {
+ GenBuilderCreate(s);
+ s << "\n";
+ }
+
+ GenSerialize(s);
+ s << "\n";
+
+ GenBuilderSize(s);
+ s << "\n";
+
+ s << " protected:\n";
+ GenBuilderConstructor(s);
+ s << "\n";
+
+ GenBuilderParameterChecker(s);
+ s << "\n";
+
+ GenBuilderMembers(s);
+ s << "};\n";
+}
+
+FieldList PacketDef::GetParamList() const {
+ FieldList params;
+
+ std::set<PacketField::Type> param_types = {
+ PacketField::Type::SCALAR, PacketField::Type::ENUM, PacketField::Type::ARRAY,
+ PacketField::Type::CUSTOM, PacketField::Type::BODY, PacketField::Type::PAYLOAD,
+ };
+
+ if (parent_ != nullptr) {
+ auto parent_params = parent_->GetParamList().GetFieldsWithTypes(param_types);
+
+ // Do not include constrained fields in the params
+ for (const auto& field : parent_params) {
+ if (parent_constraints_.find(field->GetName()) == parent_constraints_.end()) {
+ params.AppendField(field);
+ }
+ }
+ }
+ // Add the parameters for this packet.
+ return params.Merge(fields_.GetFieldsWithTypes(param_types));
+}
+
+FieldList PacketDef::GetParametersToValidate() const {
+ FieldList params_to_validate;
+ for (const auto& field : GetParamList()) {
+ if (field->HasParameterValidator()) {
+ params_to_validate.AppendField(field);
+ }
+ }
+ return params_to_validate;
+}
+
+void PacketDef::GenBuilderCreate(std::ostream& s) const {
+ s << "static std::unique_ptr<" << name_ << "Builder> Create(";
+
+ auto params = GetParamList();
+ for (int i = 0; i < params.size(); i++) {
+ params[i]->GenBuilderParameter(s);
+ if (i != params.size() - 1) {
+ s << ", ";
+ }
+ }
+ s << ") {";
+
+ // Call the constructor
+ s << "auto builder = std::unique_ptr<" << name_ << "Builder>(new " << name_ << "Builder(";
+
+ params = params.GetFieldsWithoutTypes({
+ PacketField::Type::PAYLOAD,
+ PacketField::Type::BODY,
+ });
+ // Add the parameters.
+ for (int i = 0; i < params.size(); i++) {
+ s << params[i]->GetName();
+ if (i != params.size() - 1) {
+ s << ", ";
+ }
+ }
+
+ s << "));";
+ if (fields_.HasPayload()) {
+ s << "builder->payload_ = std::move(payload);";
+ }
+ s << "return builder;";
+ s << "}\n";
+}
+
+void PacketDef::GenBuilderParameterChecker(std::ostream& s) const {
+ FieldList params_to_validate = GetParametersToValidate();
+
+ // Skip writing this function if there is nothing to validate.
+ if (params_to_validate.size() == 0) {
+ return;
+ }
+
+ // Generate function arguments.
+ s << "void CheckParameterValues(";
+ for (int i = 0; i < params_to_validate.size(); i++) {
+ params_to_validate[i]->GenBuilderParameter(s);
+ if (i != params_to_validate.size() - 1) {
+ s << ", ";
+ }
+ }
+ s << ") {";
+
+ // Check the parameters.
+ for (const auto& field : params_to_validate) {
+ field->GenParameterValidator(s);
+ }
+ s << "}\n";
+}
+
+void PacketDef::GenBuilderConstructor(std::ostream& s) const {
+ s << name_ << "Builder(";
+
+ // Generate the constructor parameters.
+ auto params = GetParamList().GetFieldsWithoutTypes({
+ PacketField::Type::PAYLOAD,
+ PacketField::Type::BODY,
+ });
+ for (int i = 0; i < params.size(); i++) {
+ params[i]->GenBuilderParameter(s);
+ if (i != params.size() - 1) {
+ s << ", ";
+ }
+ }
+ s << ") :";
+
+ // Get the list of parent params to call the parent constructor with.
+ FieldList parent_params;
+ if (parent_ != nullptr) {
+ // Pass parameters to the parent constructor
+ s << parent_->name_ << "Builder(";
+ parent_params = parent_->GetParamList().GetFieldsWithoutTypes({
+ PacketField::Type::PAYLOAD,
+ PacketField::Type::BODY,
+ });
+
+ // Go through all the fields and replace constrained fields with fixed values
+ // when calling the parent constructor.
+ for (int i = 0; i < parent_params.size(); i++) {
+ const auto& field = parent_params[i];
+ const auto& constraint = parent_constraints_.find(field->GetName());
+ if (constraint != parent_constraints_.end()) {
+ if (field->GetFieldType() == PacketField::Type::SCALAR) {
+ s << std::get<int64_t>(constraint->second);
+ } else if (field->GetFieldType() == PacketField::Type::ENUM) {
+ s << std::get<std::string>(constraint->second);
+ } else {
+ ERROR(field) << "Constraints on non enum/scalar fields should be impossible.";
+ }
+
+ s << "/* " << field->GetName() << "_ */";
+ } else {
+ s << field->GetName();
+ }
+
+ if (i != parent_params.size() - 1) {
+ s << ", ";
+ }
+ }
+ s << ") ";
+ }
+
+ // Build a list of parameters that excludes all parent parameters.
+ FieldList saved_params;
+ for (const auto& field : params) {
+ if (parent_params.GetField(field->GetName()) == nullptr) {
+ saved_params.AppendField(field);
+ }
+ }
+ if (parent_ != nullptr && saved_params.size() > 0) {
+ s << ",";
+ }
+ for (int i = 0; i < saved_params.size(); i++) {
+ const auto& saved_param_name = saved_params[i]->GetName();
+ s << saved_param_name << "_(" << saved_param_name << ")";
+ if (i != saved_params.size() - 1) {
+ s << ",";
+ }
+ }
+ s << " {";
+
+ FieldList params_to_validate = GetParametersToValidate();
+
+ if (params_to_validate.size() > 0) {
+ s << "CheckParameterValues(";
+ for (int i = 0; i < params_to_validate.size(); i++) {
+ s << params_to_validate[i]->GetName() << "_";
+ if (i != params_to_validate.size() - 1) {
+ s << ", ";
+ }
+ }
+ s << ");";
+ }
+
+ s << "}\n";
+}
+
+void PacketDef::GenBuilderMembers(std::ostream& s) const {
+ // Add the parameter list.
+ for (int i = 0; i < fields_.size(); i++) {
+ if (fields_[i]->GenBuilderParameter(s)) {
+ s << "_;";
+ }
+ }
+}
diff --git a/gd/packet/parser/packet_def.h b/gd/packet/parser/packet_def.h
new file mode 100644
index 0000000..647fc4d
--- /dev/null
+++ b/gd/packet/parser/packet_def.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2019 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 <map>
+#include <variant>
+
+#include "enum_def.h"
+#include "field_list.h"
+#include "fields/packet_field.h"
+
+class PacketDef {
+ public:
+ PacketDef(std::string name, FieldList fields);
+ PacketDef(std::string name, FieldList fields, PacketDef* parent);
+
+ void AddParentConstraint(std::string field_name, std::variant<int64_t, std::string> value);
+
+ // Assign all size fields to their corresponding variable length fields.
+ // Will crash if
+ // - there aren't any fields that don't match up to a field.
+ // - the size field points to a fixed size field.
+ // - if the size field comes after the variable length field.
+ void AssignSizeFields();
+
+ void SetEndianness(bool is_little_endian);
+
+ // Get the size for the packet. You scan specify without_payload in order
+ // to exclude payload fields as child packets will be overriding it.
+ Size GetSize(bool without_payload = false) const;
+
+ // Get the offset until the field is reached, if there is no field
+ // returns an empty Size. from_end requests the offset to the field
+ // starting from the end() iterator. If there is a field with an unknown
+ // size along the traversal, then an empty size is returned.
+ Size GetOffsetForField(std::string field_name, bool from_end = false) const;
+
+ void GenParserDefinition(std::ostream& s) const;
+
+ void GenParserFieldGetter(std::ostream& s, const PacketField* field) const;
+
+ void GenSerialize(std::ostream& s) const;
+
+ void GenBuilderSize(std::ostream& s) const;
+
+ void GenValidator(std::ostream& s) const;
+
+ void GenBuilderDefinition(std::ostream& s) const;
+
+ FieldList GetParamList() const;
+
+ FieldList GetParametersToValidate() const;
+
+ void GenBuilderCreate(std::ostream& s) const;
+
+ void GenBuilderParameterChecker(std::ostream& s) const;
+
+ void GenBuilderConstructor(std::ostream& s) const;
+
+ void GenBuilderMembers(std::ostream& s) const;
+
+ std::string name_;
+ FieldList fields_;
+
+ std::variant<std::monostate, std::string, EnumDef*> specialize_on_;
+ std::variant<std::monostate, int, std::string> specialization_value_;
+
+ PacketDef* parent_; // Parent packet type
+
+ std::map<std::string, std::variant<int64_t, std::string>> parent_constraints_;
+ bool is_little_endian_;
+};
diff --git a/gd/packet/parser/parse_location.h b/gd/packet/parser/parse_location.h
new file mode 100644
index 0000000..80bdc72
--- /dev/null
+++ b/gd/packet/parser/parse_location.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2019 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
+
+class ParseLocation {
+ public:
+ ParseLocation() : line_(-1) {}
+
+ ParseLocation(int line) : line_(line) {}
+
+ int GetLine() {
+ return line_;
+ }
+
+ private:
+ int line_;
+};
diff --git a/gd/packet/parser/size.h b/gd/packet/parser/size.h
new file mode 100644
index 0000000..926d12c
--- /dev/null
+++ b/gd/packet/parser/size.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2019 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 <iterator>
+#include <sstream>
+#include <string>
+#include <vector>
+
+class Size {
+ public:
+ Size() {}
+
+ Size(int bits) {
+ is_valid_ = true;
+ bits_ = bits;
+ }
+
+ Size(std::string dynamic) {
+ is_valid_ = true;
+ dynamic_.push_back(dynamic);
+ }
+
+ Size(int bits, std::string dynamic) {
+ is_valid_ = true;
+ bits_ = bits;
+ dynamic_.push_back(dynamic);
+ }
+
+ Size(const Size& size) {
+ is_valid_ = size.is_valid_;
+ bits_ = size.bits_;
+ dynamic_ = size.dynamic_;
+ }
+
+ std::string dynamic_string() {
+ if (dynamic_.empty()) return " 0 /* dynamic */ ";
+
+ std::stringstream result;
+ // Print everything but the last element then append it manually to avoid
+ // the trailing "+" operator.
+ std::copy(dynamic_.begin(), dynamic_.end() - 1, std::ostream_iterator<std::string>(result, " + "));
+ result << dynamic_.back();
+ return result.str();
+ }
+
+ std::vector<std::string> dynamic_string_list() {
+ return dynamic_;
+ }
+
+ bool empty() {
+ return !is_valid_;
+ }
+
+ bool has_bits() {
+ return bits_ != 0;
+ }
+
+ bool has_dynamic() {
+ return !dynamic_.empty();
+ }
+
+ int bits() {
+ return bits_;
+ }
+
+ int bytes() {
+ return bits_ / 8;
+ }
+
+ Size operator+(int rhs) {
+ return Size(bits_ + rhs);
+ }
+
+ Size operator+(std::string rhs) {
+ auto ret = Size();
+ ret.is_valid_ = true;
+ ret.dynamic_.insert(ret.dynamic_.end(), dynamic_.begin(), dynamic_.end());
+ ret.dynamic_.push_back(rhs);
+ return ret;
+ }
+
+ Size operator+(const Size& rhs) {
+ auto ret = Size(bits_ += rhs.bits_);
+ ret.is_valid_ = true;
+ ret.dynamic_.insert(ret.dynamic_.end(), dynamic_.begin(), dynamic_.end());
+ ret.dynamic_.insert(ret.dynamic_.end(), rhs.dynamic_.begin(), rhs.dynamic_.end());
+ return ret;
+ }
+
+ Size& operator+=(int rhs) {
+ is_valid_ = true;
+ bits_ += rhs;
+ return *this;
+ }
+
+ Size& operator+=(std::string rhs) {
+ is_valid_ = true;
+ dynamic_.push_back(rhs);
+ return *this;
+ }
+
+ Size& operator+=(const Size& rhs) {
+ is_valid_ = true;
+ bits_ += rhs.bits_;
+ dynamic_.insert(dynamic_.end(), rhs.dynamic_.begin(), rhs.dynamic_.end());
+ return *this;
+ }
+
+ std::string ToString() {
+ std::stringstream str;
+ str << "Bits: " << bits_ << " | "
+ << "Dynamic: " << dynamic_string();
+ return str.str();
+ }
+
+ private:
+ bool is_valid_ = false;
+ int bits_ = 0;
+ std::vector<std::string> dynamic_;
+};
diff --git a/gd/packet/parser/test/Android.bp b/gd/packet/parser/test/Android.bp
new file mode 100644
index 0000000..a5849b3
--- /dev/null
+++ b/gd/packet/parser/test/Android.bp
@@ -0,0 +1,21 @@
+genrule {
+ name: "BluetoothPacketParserTestPacketPdlGen_h",
+ tools: [
+ "bluetooth_packetgen",
+ ],
+ cmd: "$(location bluetooth_packetgen) --include=system/bt/gd --out=$(genDir) $(in)",
+ srcs: [
+ "test_packets.pdl",
+ ],
+ out: [
+ "packet/parser/test/test_packets.h",
+ ],
+}
+
+filegroup {
+ name: "BluetoothPacketParserTestPacketTestSources",
+ srcs: [
+ "six_bytes.cc",
+ "generated_packet_test.cc",
+ ],
+}
diff --git a/gd/packet/parser/test/generated_packet_test.cc b/gd/packet/parser/test/generated_packet_test.cc
new file mode 100644
index 0000000..e1963ae
--- /dev/null
+++ b/gd/packet/parser/test/generated_packet_test.cc
@@ -0,0 +1,554 @@
+/*
+ * Copyright 2019 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 "packet/parser/test/test_packets.h"
+
+#include <gtest/gtest.h>
+#include <forward_list>
+#include <memory>
+
+#include "os/log.h"
+#include "packet/bit_inserter.h"
+#include "packet/parser/test/six_bytes.h"
+#include "packet/raw_builder.h"
+
+using ::bluetooth::packet::BitInserter;
+using ::bluetooth::packet::kLittleEndian;
+using ::bluetooth::packet::RawBuilder;
+using ::bluetooth::packet::parser::test::SixBytes;
+using std::vector;
+
+namespace {
+vector<uint8_t> child_two_two_three = {
+ 0x20 /* Reserved : 4, FourBits::TWO */,
+ 0x03 /* FourBits::THREE, Reserved : 4 */,
+};
+vector<uint8_t> child = {
+ 0x12 /* fixed */, 0x02 /* Size of the payload */, 0xa1 /* First byte of the payload */, 0xa2, 0xb1 /* footer */,
+};
+vector<uint8_t> child_with_six_bytes = {
+ 0x34 /* TwoBytes */,
+ 0x12,
+ 0xa1 /* First byte of the six_bytes */,
+ 0xa2,
+ 0xa3,
+ 0xa4,
+ 0xa5,
+ 0xa6,
+ 0xb1 /* Second six_bytes*/,
+ 0xb2,
+ 0xb3,
+ 0xb4,
+ 0xb5,
+ 0xb6,
+};
+
+} // namespace
+
+namespace bluetooth {
+namespace packet {
+namespace parser {
+using namespace test;
+
+TEST(GeneratedPacketTest, testChildTwoTwoThree) {
+ auto packet = ChildTwoTwoThreeBuilder::Create();
+
+ ASSERT_EQ(child_two_two_three.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(packet_bytes->size(), child_two_two_three.size());
+ for (size_t i = 0; i < child_two_two_three.size(); i++) {
+ ASSERT_EQ(packet_bytes->at(i), child_two_two_three[i]);
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ ParentView wrong_view = ParentView::Create(packet_bytes_view);
+ ASSERT_FALSE(wrong_view.IsValid());
+
+ ParentTwoView parent_view = ParentTwoView::Create(packet_bytes_view);
+ ASSERT_TRUE(parent_view.IsValid());
+ ASSERT_EQ(FourBits::TWO, parent_view.GetFourBits());
+
+ ChildTwoTwoView child_view = ChildTwoTwoView::Create(parent_view);
+ ASSERT_TRUE(child_view.IsValid());
+ ASSERT_EQ(FourBits::THREE, child_view.GetMoreBits());
+
+ ChildTwoTwoThreeView grandchild_view = ChildTwoTwoThreeView::Create(child_view);
+ ASSERT_TRUE(grandchild_view.IsValid());
+}
+
+TEST(GeneratedPacketTest, testChild) {
+ uint16_t field_name = 0xa2a1;
+ uint8_t footer = 0xb1;
+ auto packet = ChildBuilder::Create(field_name, footer);
+
+ ASSERT_EQ(child.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(packet_bytes->size(), child.size());
+ for (size_t i = 0; i < child.size(); i++) {
+ ASSERT_EQ(packet_bytes->at(i), child[i]);
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ ParentView parent_view = ParentView::Create(packet_bytes_view);
+ ASSERT_TRUE(parent_view.IsValid());
+ auto payload = parent_view.GetPayload();
+
+ ASSERT_EQ(child[1 /* skip fixed field */], payload.size());
+ for (size_t i = 0; i < payload.size(); i++) {
+ ASSERT_EQ(child[i + 2 /* fixed & size */], payload[i]);
+ }
+
+ ChildView child_view = ChildView::Create(parent_view);
+ ASSERT_TRUE(child_view.IsValid());
+
+ ASSERT_EQ(field_name, child_view.GetFieldName());
+}
+
+TEST(GeneratedPacketTest, testValidateWayTooSmall) {
+ std::vector<uint8_t> too_small_bytes = {0x34};
+ auto too_small = std::make_shared<std::vector<uint8_t>>(too_small_bytes.begin(), too_small_bytes.end());
+
+ ParentWithSixBytesView invalid_parent = ParentWithSixBytesView::Create(too_small);
+ ASSERT_FALSE(invalid_parent.IsValid());
+ ChildWithSixBytesView invalid = ChildWithSixBytesView::Create(ParentWithSixBytesView::Create(too_small));
+ ASSERT_FALSE(invalid.IsValid());
+}
+
+TEST(GeneratedPacketTest, testValidateTooSmall) {
+ std::vector<uint8_t> too_small_bytes = {0x34, 0x12, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x11};
+ auto too_small = std::make_shared<std::vector<uint8_t>>(too_small_bytes.begin(), too_small_bytes.end());
+
+ ParentWithSixBytesView valid_parent = ParentWithSixBytesView::Create(too_small);
+ ASSERT_TRUE(valid_parent.IsValid());
+ ChildWithSixBytesView invalid = ChildWithSixBytesView::Create(ParentWithSixBytesView::Create(too_small));
+ ASSERT_FALSE(invalid.IsValid());
+}
+
+TEST(GeneratedPacketTest, testValidateJustRight) {
+ std::vector<uint8_t> just_right_bytes = {0x34, 0x12, 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16};
+ auto just_right = std::make_shared<std::vector<uint8_t>>(just_right_bytes.begin(), just_right_bytes.end());
+
+ ChildWithSixBytesView valid = ChildWithSixBytesView::Create(ParentWithSixBytesView::Create(just_right));
+ ASSERT_TRUE(valid.IsValid());
+}
+
+TEST(GeneratedPacketTest, testValidateTooBig) {
+ std::vector<uint8_t> too_big_bytes = {0x34, 0x12, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x20};
+ auto too_big = std::make_shared<std::vector<uint8_t>>(too_big_bytes.begin(), too_big_bytes.end());
+
+ ChildWithSixBytesView lenient = ChildWithSixBytesView::Create(ParentWithSixBytesView::Create(too_big));
+ ASSERT_TRUE(lenient.IsValid());
+}
+
+TEST(GeneratedPacketTest, testValidateDeath) {
+ auto packet = ChildTwoTwoThreeBuilder::Create();
+
+ ASSERT_EQ(child_two_two_three.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(packet_bytes->size(), child_two_two_three.size());
+ for (size_t i = 0; i < child_two_two_three.size(); i++) {
+ ASSERT_EQ(packet_bytes->at(i), child_two_two_three[i]);
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ ParentView wrong_view = ParentView::Create(packet_bytes_view);
+ ASSERT_DEATH(wrong_view.GetPayload(), "validated");
+}
+
+TEST(GeneratedPacketTest, testValidatedParentDeath) {
+ uint16_t field_name = 0xa2a1;
+ uint8_t footer = 0xb1;
+ auto packet = ChildBuilder::Create(field_name, footer);
+
+ ASSERT_EQ(child.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(packet_bytes->size(), child.size());
+ for (size_t i = 0; i < child.size(); i++) {
+ ASSERT_EQ(packet_bytes->at(i), child[i]);
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ ParentView parent_view = ParentView::Create(packet_bytes_view);
+ ASSERT_TRUE(parent_view.IsValid());
+ auto payload = parent_view.GetPayload();
+
+ ASSERT_EQ(child[1 /* skip fixed field */], payload.size());
+ for (size_t i = 0; i < payload.size(); i++) {
+ ASSERT_EQ(child[i + 2 /* fixed & size */], payload[i]);
+ }
+
+ ChildView child_view = ChildView::Create(parent_view);
+ ASSERT_DEATH(child_view.GetFieldName(), "validated");
+}
+
+TEST(GeneratedPacketTest, testChildWithSixBytes) {
+ SixBytes six_bytes_a{{0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6}};
+ SixBytes six_bytes_b{{0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6}};
+ auto packet = ChildWithSixBytesBuilder::Create(six_bytes_a, six_bytes_b);
+
+ ASSERT_EQ(child_with_six_bytes.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(packet_bytes->size(), child_with_six_bytes.size());
+ for (size_t i = 0; i < child_with_six_bytes.size(); i++) {
+ ASSERT_EQ(packet_bytes->at(i), child_with_six_bytes[i]);
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ ParentWithSixBytesView parent_view = ParentWithSixBytesView::Create(packet_bytes_view);
+ ASSERT_TRUE(parent_view.IsValid());
+ ASSERT_EQ(six_bytes_a, parent_view.GetSixBytes());
+
+ ChildWithSixBytesView child_view = ChildWithSixBytesView::Create(parent_view);
+ ASSERT_TRUE(child_view.IsValid());
+
+ ASSERT_EQ(six_bytes_a, child_view.GetSixBytes());
+ ASSERT_EQ(six_bytes_a, ((ParentWithSixBytesView)child_view).GetSixBytes());
+ ASSERT_EQ(six_bytes_b, child_view.GetChildSixBytes());
+}
+
+namespace {
+vector<uint8_t> parent_with_sum = {
+ 0x11 /* TwoBytes */, 0x12, 0x21 /* Sum Bytes */, 0x22, 0x43 /* Sum, excluding TwoBytes */, 0x00,
+};
+
+} // namespace
+
+TEST(GeneratedPacketTest, testParentWithSum) {
+ uint16_t two_bytes = 0x1211;
+ uint16_t sum_bytes = 0x2221;
+ auto packet = ParentWithSumBuilder::Create(two_bytes, sum_bytes, std::make_unique<packet::RawBuilder>());
+
+ ASSERT_EQ(parent_with_sum.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(packet_bytes->size(), parent_with_sum.size());
+ for (size_t i = 0; i < parent_with_sum.size(); i++) {
+ ASSERT_EQ(packet_bytes->at(i), parent_with_sum[i]);
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ ParentWithSumView parent_view = ParentWithSumView::Create(packet_bytes_view);
+ ASSERT_TRUE(parent_view.IsValid());
+ ASSERT_EQ(two_bytes, parent_view.GetTwoBytes());
+
+ // Corrupt checksum
+ packet_bytes->back()++;
+ PacketView<kLittleEndian> corrupted_bytes_view(packet_bytes);
+ ParentWithSumView corrupted_view = ParentWithSumView::Create(corrupted_bytes_view);
+ ASSERT_FALSE(corrupted_view.IsValid());
+}
+
+namespace {
+vector<uint8_t> child_with_nested_sum = {
+ 0x11 /* TwoBytes */,
+ 0x12,
+ 0x21 /* Sum Bytes */,
+ 0x22,
+ 0x31 /* More Bytes */,
+ 0x32,
+ 0x33,
+ 0x34,
+ 0xca /* Nested Sum */,
+ 0x00,
+ 0xd7 /* Sum, excluding TwoBytes */,
+ 0x01,
+};
+
+} // namespace
+
+TEST(GeneratedPacketTest, testChildWithNestedSum) {
+ uint16_t two_bytes = 0x1211;
+ uint16_t sum_bytes = 0x2221;
+ uint32_t more_bytes = 0x34333231;
+ auto packet = ChildWithNestedSumBuilder::Create(two_bytes, sum_bytes, more_bytes);
+
+ ASSERT_EQ(child_with_nested_sum.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(packet_bytes->size(), child_with_nested_sum.size());
+ for (size_t i = 0; i < child_with_nested_sum.size(); i++) {
+ ASSERT_EQ(packet_bytes->at(i), child_with_nested_sum[i]);
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ ParentWithSumView parent_view = ParentWithSumView::Create(packet_bytes_view);
+ ASSERT_TRUE(parent_view.IsValid());
+ ASSERT_EQ(two_bytes, parent_view.GetTwoBytes());
+
+ ChildWithNestedSumView child_view = ChildWithNestedSumView::Create(parent_view);
+ ASSERT_TRUE(child_view.IsValid());
+
+ ASSERT_EQ(more_bytes, child_view.GetMoreBytes());
+}
+
+namespace {
+vector<uint8_t> parent_size_modifier = {
+ 0x02 /* Size */,
+ 0x11 /* TwoBytes */,
+ 0x12,
+};
+
+} // namespace
+
+TEST(GeneratedPacketTest, testParentSizeModifier) {
+ uint16_t two_bytes = 0x1211;
+ auto packet = ParentSizeModifierBuilder::Create(std::make_unique<RawBuilder>(), two_bytes);
+
+ ASSERT_EQ(parent_size_modifier.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(parent_size_modifier.size(), packet_bytes->size());
+ for (size_t i = 0; i < parent_size_modifier.size(); i++) {
+ ASSERT_EQ(parent_size_modifier[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ ParentSizeModifierView parent_view = ParentSizeModifierView::Create(packet_bytes_view);
+ ASSERT_TRUE(parent_view.IsValid());
+ ASSERT_EQ(two_bytes, parent_view.GetTwoBytes());
+}
+
+namespace {
+vector<uint8_t> child_size_modifier = {
+ 0x06 /* PayloadSize (TwoBytes + MoreBytes)*/,
+ 0x31 /* MoreBytes */,
+ 0x32,
+ 0x33,
+ 0x34,
+ 0x11 /* TwoBytes = 0x1211 */,
+ 0x12,
+};
+
+} // namespace
+
+TEST(GeneratedPacketTest, testChildSizeModifier) {
+ uint16_t two_bytes = 0x1211;
+ uint32_t more_bytes = 0x34333231;
+ auto packet = ChildSizeModifierBuilder::Create(more_bytes);
+
+ ASSERT_EQ(child_size_modifier.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(child_size_modifier.size(), packet_bytes->size());
+ for (size_t i = 0; i < child_size_modifier.size(); i++) {
+ ASSERT_EQ(child_size_modifier[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ ParentSizeModifierView parent_view = ParentSizeModifierView::Create(packet_bytes_view);
+ ASSERT_TRUE(parent_view.IsValid());
+ ASSERT_EQ(two_bytes, parent_view.GetTwoBytes());
+
+ ChildSizeModifierView child_view = ChildSizeModifierView::Create(parent_view);
+ ASSERT_TRUE(child_view.IsValid());
+
+ ASSERT_EQ(more_bytes, child_view.GetMoreBytes());
+}
+
+namespace {
+vector<uint8_t> fixed_array_enum{
+ 0x01, // ONE
+ 0x00,
+ 0x02, // TWO
+ 0x00,
+ 0x01, // ONE_TWO
+ 0x02,
+ 0x02, // TWO_THREE
+ 0x03,
+ 0xff, // FFFF
+ 0xff,
+};
+}
+
+TEST(GeneratedPacketTest, testFixedArrayEnum) {
+ std::vector<ForArrays> fixed_array{
+ {ForArrays::ONE, ForArrays::TWO, ForArrays::ONE_TWO, ForArrays::TWO_THREE, ForArrays::FFFF}};
+ auto packet = FixedArrayEnumBuilder::Create(fixed_array);
+ ASSERT_EQ(fixed_array_enum.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(fixed_array_enum.size(), packet_bytes->size());
+ for (size_t i = 0; i < fixed_array_enum.size(); i++) {
+ ASSERT_EQ(fixed_array_enum[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = FixedArrayEnumView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto array = view.GetEnumArray();
+ ASSERT_EQ(fixed_array.size(), array.size());
+ for (size_t i = 0; i < fixed_array.size(); i++) {
+ ASSERT_EQ(array[i], fixed_array[i]);
+ }
+}
+
+namespace {
+vector<uint8_t> sized_array_enum{
+ 0x0a, // _size_
+ 0x00,
+ 0x01, // ONE
+ 0x00,
+ 0x02, // TWO
+ 0x00,
+ 0x01, // ONE_TWO
+ 0x02,
+ 0x02, // TWO_THREE
+ 0x03,
+ 0xff, // FFFF
+ 0xff,
+};
+}
+
+TEST(GeneratedPacketTest, testSizedArrayEnum) {
+ std::vector<ForArrays> sized_array{
+ {ForArrays::ONE, ForArrays::TWO, ForArrays::ONE_TWO, ForArrays::TWO_THREE, ForArrays::FFFF}};
+ auto packet = SizedArrayEnumBuilder::Create(sized_array);
+ // TODO: Include the array size in the builder size()
+ // ASSERT_EQ(sized_array_enum.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(sized_array_enum.size(), packet_bytes->size());
+ for (size_t i = 0; i < sized_array_enum.size(); i++) {
+ ASSERT_EQ(sized_array_enum[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = SizedArrayEnumView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto array = view.GetEnumArray();
+ ASSERT_EQ(sized_array.size(), array.size());
+ for (size_t i = 0; i < sized_array.size(); i++) {
+ ASSERT_EQ(array[i], sized_array[i]);
+ }
+}
+
+namespace {
+vector<uint8_t> count_array_enum{
+ 0x03, // _count_
+ 0x01, // ONE
+ 0x00,
+ 0x02, // TWO_THREE
+ 0x03,
+ 0xff, // FFFF
+ 0xff,
+};
+}
+
+TEST(GeneratedPacketTest, testCountArrayEnum) {
+ std::vector<ForArrays> count_array{{ForArrays::ONE, ForArrays::TWO_THREE, ForArrays::FFFF}};
+ auto packet = CountArrayEnumBuilder::Create(count_array);
+ // TODO: Include the array size in the builder size()
+ // ASSERT_EQ(count_array_enum.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(count_array_enum.size(), packet_bytes->size());
+ for (size_t i = 0; i < count_array_enum.size(); i++) {
+ ASSERT_EQ(count_array_enum[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = CountArrayEnumView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto array = view.GetEnumArray();
+ ASSERT_EQ(count_array.size(), array.size());
+ for (size_t i = 0; i < count_array.size(); i++) {
+ ASSERT_EQ(array[i], count_array[i]);
+ }
+}
+
+TEST(GeneratedPacketTest, testFixedSizeByteArray) {
+ constexpr int byte_array_size = 32;
+ std::vector<uint8_t> byte_array(byte_array_size);
+ for (uint8_t i = 0; i < byte_array_size; i++) byte_array[i] = i;
+
+ constexpr int word_array_size = 8;
+ std::vector<uint32_t> word_array(word_array_size);
+ for (uint32_t i = 0; i < word_array_size; i++) word_array[i] = i;
+
+ auto packet = PacketWithFixedArraysOFBytesBuilder::Create(byte_array, word_array);
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(byte_array_size + word_array_size * sizeof(uint32_t), packet_bytes->size());
+
+ for (size_t i = 0; i < byte_array_size; i++) {
+ ASSERT_EQ(byte_array[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = PacketWithFixedArraysOFBytesView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto array = view.GetFixed256bitInBytes();
+ ASSERT_EQ(byte_array.size(), array.size());
+ for (size_t i = 0; i < array.size(); i++) {
+ ASSERT_EQ(array[i], byte_array[i]);
+ }
+
+ auto decoded_word_array = view.GetFixed256bitInWords();
+ ASSERT_EQ(word_array.size(), decoded_word_array.size());
+ for (size_t i = 0; i < decoded_word_array.size(); i++) {
+ ASSERT_EQ(word_array[i], decoded_word_array[i]);
+ }
+}
+
+} // namespace parser
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/parser/test/simple_sum.h b/gd/packet/parser/test/simple_sum.h
new file mode 100644
index 0000000..b66cb9a
--- /dev/null
+++ b/gd/packet/parser/test/simple_sum.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2019 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>
+
+namespace bluetooth {
+namespace packet {
+namespace parser {
+namespace test {
+
+class SimpleSum {
+ public:
+ static void Initialize(SimpleSum& s) {
+ s.sum = 0;
+ }
+
+ static void AddByte(SimpleSum& s, uint8_t byte) {
+ s.sum += byte;
+ }
+
+ static uint16_t GetChecksum(const SimpleSum& s) {
+ return s.sum;
+ }
+
+ private:
+ uint16_t sum;
+};
+
+} // namespace test
+} // namespace parser
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/parser/test/six_bytes.cc b/gd/packet/parser/test/six_bytes.cc
new file mode 100644
index 0000000..614dbaa
--- /dev/null
+++ b/gd/packet/parser/test/six_bytes.cc
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 "six_bytes.h"
+
+namespace bluetooth {
+namespace packet {
+namespace parser {
+namespace test {
+
+static_assert(sizeof(SixBytes) == 6, "SixBytes must be 6 bytes long!");
+
+SixBytes::SixBytes(const uint8_t (&six)[6]) {
+ std::copy(six, six + kLength, six_bytes);
+};
+
+} // namespace test
+} // namespace parser
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/parser/test/six_bytes.h b/gd/packet/parser/test/six_bytes.h
new file mode 100644
index 0000000..0f26324
--- /dev/null
+++ b/gd/packet/parser/test/six_bytes.h
@@ -0,0 +1,61 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 <stdint.h>
+#include <string>
+
+namespace bluetooth {
+namespace packet {
+namespace parser {
+namespace test {
+
+class SixBytes final {
+ public:
+ static constexpr unsigned int kLength = 6;
+
+ uint8_t six_bytes[kLength];
+
+ SixBytes() = default;
+ SixBytes(const uint8_t (&addr)[6]);
+
+ bool operator<(const SixBytes& rhs) const {
+ return (std::memcmp(six_bytes, rhs.six_bytes, sizeof(six_bytes)) < 0);
+ }
+ bool operator==(const SixBytes& rhs) const {
+ return (std::memcmp(six_bytes, rhs.six_bytes, sizeof(six_bytes)) == 0);
+ }
+ bool operator>(const SixBytes& rhs) const {
+ return (rhs < *this);
+ }
+ bool operator<=(const SixBytes& rhs) const {
+ return !(*this > rhs);
+ }
+ bool operator>=(const SixBytes& rhs) const {
+ return !(*this < rhs);
+ }
+ bool operator!=(const SixBytes& rhs) const {
+ return !(*this == rhs);
+ }
+};
+
+} // namespace test
+} // namespace parser
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/parser/test/test_packets.pdl b/gd/packet/parser/test/test_packets.pdl
new file mode 100644
index 0000000..4c97c9d
--- /dev/null
+++ b/gd/packet/parser/test/test_packets.pdl
@@ -0,0 +1,131 @@
+little_endian_packets
+
+custom_field SixBytes : 48 "packet/parser/test/"
+
+packet Parent {
+ _fixed_ = 0x12 : 8,
+ _size_(_payload_) : 8,
+ _payload_,
+ footer : 8,
+}
+
+packet Child : Parent {
+ field_name : 16,
+}
+
+enum FourBits : 4 {
+ ONE = 1,
+ TWO = 2,
+ THREE = 3,
+ LAZY_ME = 15,
+}
+
+packet ParentTwo {
+ _reserved_ : 4,
+ four_bits : FourBits,
+ _payload_,
+}
+
+packet ChildTwoThree : ParentTwo (four_bits = THREE) {
+ more_bits : FourBits,
+ _reserved_ : 4,
+ sixteen_bits : 16
+}
+
+packet ChildTwoTwo : ParentTwo (four_bits = TWO) {
+ more_bits : FourBits,
+ _reserved_ : 4,
+}
+
+packet ChildTwoTwoThree :ChildTwoTwo (more_bits = THREE) {
+}
+
+packet ParentWithSixBytes {
+ two_bytes : 16,
+ six_bytes : SixBytes,
+ _payload_,
+}
+
+packet ChildWithSixBytes : ParentWithSixBytes (two_bytes = 0x1234) {
+ child_six_bytes : SixBytes,
+}
+
+checksum SimpleSum : 16 "packet/parser/test/"
+
+packet ParentWithSum {
+ two_bytes : 16,
+ _checksum_start_(example_checksum),
+ sum_bytes : 16,
+ _payload_,
+ example_checksum : SimpleSum,
+}
+
+packet ChildWithSum : ParentWithSum {
+ more_bytes : 32,
+ another_byte : 8,
+}
+
+packet ChildWithNestedSum : ParentWithSum {
+ _checksum_start_(nested_checksum),
+ more_bytes : 32,
+ nested_checksum : SimpleSum,
+}
+
+packet ParentSizeModifier {
+ _size_(_payload_) : 8,
+ _payload_ : [+2*8], // Include two_bytes in the size
+ two_bytes : 16,
+}
+
+packet ChildSizeModifier : ParentSizeModifier (two_bytes = 0x1211) {
+ more_bytes : 32,
+}
+
+packet FieldsEndWithNumbers {
+ field_1 : 16,
+ field_2 : 16,
+ field_10 : 16,
+ field_11 : 16,
+}
+
+enum ForArrays : 16 {
+ ONE = 0x0001,
+ TWO = 0x0002,
+ ONE_TWO = 0x0201,
+ TWO_THREE = 0x0302,
+ FFFF = 0xffff,
+}
+
+packet FixedArrayEnum {
+ enum_array : ForArrays[5],
+}
+
+packet SizedArrayEnum {
+ _size_(enum_array) : 16,
+ enum_array : ForArrays[],
+}
+
+packet CountArrayEnum {
+ _count_(enum_array) : 8,
+ enum_array : ForArrays[],
+}
+
+packet SizedArrayCustom {
+ _size_(six_bytes_array) : 8,
+ an_extra_byte : 8,
+ six_bytes_array : SixBytes[+1],
+}
+
+packet FixedArrayCustom {
+ six_bytes_array : SixBytes[5],
+}
+
+packet CountArrayCustom {
+ _count_(six_bytes_array) : 8,
+ six_bytes_array : SixBytes[],
+}
+
+packet PacketWithFixedArraysOFBytes {
+ fixed_256bit_in_bytes : 8[32],
+ fixed_256bit_in_words : 32[8],
+}
diff --git a/gd/packet/parser/type_def.h b/gd/packet/parser/type_def.h
new file mode 100644
index 0000000..ceaf069
--- /dev/null
+++ b/gd/packet/parser/type_def.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2019 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 <iostream>
+
+#include "fields/packet_field.h"
+#include "fields/reserved_field.h"
+
+class TypeDef {
+ public:
+ TypeDef(std::string name) : name_(name) {}
+
+ TypeDef(std::string name, int size) : name_(name), size_(size) {}
+
+ virtual ~TypeDef() = default;
+
+ std::string GetTypeName() const {
+ return name_;
+ }
+
+ enum class Type {
+ INVALID,
+ ENUM,
+ CHECKSUM,
+ CUSTOM,
+ };
+
+ virtual Type GetDefinitionType() const = 0;
+
+ virtual PacketField* GetNewField(const std::string& name, ParseLocation loc) const = 0;
+
+ virtual void GenInclude(std::ostream& s) const = 0;
+
+ virtual void GenUsing(std::ostream& s) const = 0;
+
+ const std::string name_;
+ const int size_{-1};
+};
diff --git a/gd/packet/parser/util.h b/gd/packet/parser/util.h
new file mode 100644
index 0000000..b274e16
--- /dev/null
+++ b/gd/packet/parser/util.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2019 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 <algorithm>
+#include <iostream>
+#include <regex>
+#include <string>
+
+#include "logging.h"
+
+namespace util {
+
+inline std::string GetTypeForSize(int size) {
+ if (size > 64) {
+ ERROR() << __func__ << ": Cannot use a type larger than 64 bits. (" << size << ")\n";
+ }
+
+ if (size <= 8) return "uint8_t";
+
+ if (size <= 16) return "uint16_t";
+
+ if (size <= 32) return "uint32_t";
+
+ return "uint64_t";
+}
+
+inline int RoundSizeUp(int size) {
+ if (size > 64) {
+ ERROR() << __func__ << ": Cannot use a type larger than 64 bits. (" << size << ")\n";
+ }
+
+ if (size <= 8) return 8;
+ if (size <= 16) return 16;
+ if (size <= 32) return 32;
+ return 64;
+}
+
+// Returns the max value that can be contained unsigned in a number of bits.
+inline uint64_t GetMaxValueForBits(int bits) {
+ if (bits > 64) {
+ ERROR() << __func__ << ": Cannot use a type larger than 64 bits. (" << bits << ")\n";
+ }
+
+ uint64_t max = 0;
+ for (int i = 0; i < bits; i++) {
+ max <<= 1;
+ max |= 1;
+ }
+
+ return max;
+}
+
+inline std::string CamelCaseToUnderScore(std::string value) {
+ if (value[0] < 'A' || value[0] > 'Z') {
+ ERROR() << value << " doesn't look like CamelCase";
+ }
+
+ // Use static to avoid compiling the regex more than once.
+ static const std::regex camel_case_regex("[A-Z][a-z0-9]*");
+
+ // Add an underscore to the end of each pattern match.
+ value = std::regex_replace(value, camel_case_regex, "$&_");
+
+ // Remove the last underscore at the end of the string.
+ value.pop_back();
+
+ // Convert all characters to lowercase.
+ std::transform(value.begin(), value.end(), value.begin(), [](unsigned char c) { return std::tolower(c); });
+
+ return value;
+}
+
+inline std::string UnderscoreToCamelCase(std::string value) {
+ if (value[0] < 'a' || value[0] > 'z') {
+ ERROR() << value << " invalid identifier";
+ }
+
+ std::ostringstream camel_case;
+
+ bool capitalize = true;
+ for (unsigned char c : value) {
+ if (c == '_') {
+ capitalize = true;
+ } else {
+ if (capitalize) {
+ c = std::toupper(c);
+ capitalize = false;
+ }
+ camel_case << c;
+ }
+ }
+
+ return camel_case.str();
+}
+
+} // namespace util
diff --git a/gd/packet/raw_builder.cc b/gd/packet/raw_builder.cc
new file mode 100644
index 0000000..fd61417
--- /dev/null
+++ b/gd/packet/raw_builder.cc
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2019 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 "packet/raw_builder.h"
+
+#include <algorithm>
+
+#include "os/log.h"
+
+using std::vector;
+using bluetooth::common::Address;
+
+namespace bluetooth {
+namespace packet {
+
+RawBuilder::RawBuilder(size_t max_bytes) : max_bytes_(max_bytes) {}
+
+bool RawBuilder::AddOctets(size_t octets, const vector<uint8_t>& bytes) {
+ if (payload_.size() + octets > max_bytes_) return false;
+
+ if (octets != bytes.size()) return false;
+
+ payload_.insert(payload_.end(), bytes.begin(), bytes.end());
+
+ return true;
+}
+
+bool RawBuilder::AddOctets(const vector<uint8_t>& bytes) {
+ return AddOctets(bytes.size(), bytes);
+}
+
+bool RawBuilder::AddOctets(size_t octets, uint64_t value) {
+ vector<uint8_t> val_vector;
+
+ uint64_t v = value;
+
+ if (octets > sizeof(uint64_t)) return false;
+
+ for (size_t i = 0; i < octets; i++) {
+ val_vector.push_back(v & 0xff);
+ v = v >> 8;
+ }
+
+ if (v != 0) return false;
+
+ return AddOctets(octets, val_vector);
+}
+
+bool RawBuilder::AddAddress(const Address& address) {
+ if (payload_.size() + Address::kLength > max_bytes_) return false;
+
+ for (size_t i = 0; i < Address::kLength; i++) {
+ payload_.push_back(address.address[i]);
+ }
+ return true;
+}
+
+bool RawBuilder::AddOctets1(uint8_t value) {
+ return AddOctets(1, value);
+}
+
+bool RawBuilder::AddOctets2(uint16_t value) {
+ return AddOctets(2, value);
+}
+
+bool RawBuilder::AddOctets3(uint32_t value) {
+ return AddOctets(3, value);
+}
+
+bool RawBuilder::AddOctets4(uint32_t value) {
+ return AddOctets(4, value);
+}
+
+bool RawBuilder::AddOctets6(uint64_t value) {
+ return AddOctets(6, value);
+}
+
+bool RawBuilder::AddOctets8(uint64_t value) {
+ return AddOctets(8, value);
+}
+
+bool RawBuilder::CanAddOctets(size_t num_bytes) const {
+ return payload_.size() + num_bytes <= max_bytes_;
+}
+
+void RawBuilder::Serialize(BitInserter& it) const {
+ for (const auto& val : payload_) {
+ insert(val, it);
+ }
+}
+
+size_t RawBuilder::size() const {
+ return payload_.size();
+}
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/raw_builder.h b/gd/packet/raw_builder.h
new file mode 100644
index 0000000..8f9edf5
--- /dev/null
+++ b/gd/packet/raw_builder.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2019 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 "common/address.h"
+#include "packet/bit_inserter.h"
+#include "packet/packet_builder.h"
+
+namespace bluetooth {
+namespace packet {
+
+class RawBuilder : public PacketBuilder<true> {
+ public:
+ RawBuilder() = default;
+ RawBuilder(size_t max_bytes);
+ virtual ~RawBuilder() = default;
+
+ virtual size_t size() const override;
+
+ virtual void Serialize(BitInserter& it) const;
+
+ // Add |address| to the payload. Return true if:
+ // - the new size of the payload is still <= |max_bytes_|
+ bool AddAddress(const common::Address& address);
+
+ // Return true if |num_bytes| can be added to the payload.
+ bool CanAddOctets(size_t num_bytes) const;
+
+ // Add |octets| bytes to the payload. Return true if:
+ // - the size of |bytes| is equal to |octets| and
+ // - the new size of the payload is still <= |max_bytes_|
+ bool AddOctets(size_t octets, const std::vector<uint8_t>& bytes);
+
+ bool AddOctets(const std::vector<uint8_t>& bytes);
+
+ bool AddOctets1(uint8_t value);
+ bool AddOctets2(uint16_t value);
+ bool AddOctets3(uint32_t value);
+ bool AddOctets4(uint32_t value);
+ bool AddOctets6(uint64_t value);
+ bool AddOctets8(uint64_t value);
+
+ private:
+ // Add |octets| bytes to the payload. Return true if:
+ // - the value of |value| fits in |octets| bytes and
+ // - the new size of the payload is still <= |max_bytes_|
+ bool AddOctets(size_t octets, uint64_t value);
+
+ size_t max_bytes_{255};
+
+ // Underlying containers for storing the actual packet
+ std::vector<uint8_t> payload_;
+};
+
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/raw_builder_unittest.cc b/gd/packet/raw_builder_unittest.cc
new file mode 100644
index 0000000..27cecd6
--- /dev/null
+++ b/gd/packet/raw_builder_unittest.cc
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2019 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 "packet/raw_builder.h"
+
+#include <gtest/gtest.h>
+#include <forward_list>
+#include <memory>
+
+#include "common/address.h"
+
+using bluetooth::common::Address;
+using bluetooth::packet::BitInserter;
+using std::vector;
+
+namespace {
+vector<uint8_t> count = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+};
+
+} // namespace
+
+namespace bluetooth {
+namespace packet {
+
+class RawBuilderTest : public ::testing::Test {
+ public:
+ RawBuilderTest() = default;
+ ~RawBuilderTest() = default;
+};
+
+TEST(RawBuilderTest, buildCountTest) {
+ std::unique_ptr<RawBuilder> count_builder = std::make_unique<RawBuilder>();
+ ASSERT_EQ(0u, count_builder->size());
+ count_builder->AddOctets8(0x0706050403020100);
+ count_builder->AddOctets4(0x0b0a0908);
+ count_builder->AddOctets2(0x0d0c);
+ count_builder->AddOctets1(0x0e);
+ count_builder->AddOctets1(0x0f);
+ count_builder->AddAddress(Address({0x10, 0x11, 0x12, 0x13, 0x14, 0x15}));
+ std::vector<uint8_t> count_subset(count.begin() + 0x16, count.end());
+ count_builder->AddOctets(count_subset);
+
+ ASSERT_EQ(count.size(), count_builder->size());
+
+ std::vector<uint8_t> packet;
+ BitInserter it(packet);
+
+ count_builder->Serialize(it);
+
+ ASSERT_EQ(count, packet);
+}
+
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/view.cc b/gd/packet/view.cc
new file mode 100644
index 0000000..a98fb6c
--- /dev/null
+++ b/gd/packet/view.cc
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019 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 "packet/view.h"
+
+#include "os/log.h"
+
+namespace bluetooth {
+namespace packet {
+
+View::View(std::shared_ptr<const std::vector<uint8_t>> data, size_t begin, size_t end)
+ : data_(data), begin_(begin < data_->size() ? begin : data_->size()),
+ end_(end < data_->size() ? end : data_->size()) {}
+
+View::View(const View& view, size_t begin, size_t end) : data_(view.data_) {
+ begin_ = (begin < view.size() ? begin : view.size());
+ begin_ += view.begin_;
+ end_ = (end < view.size() ? end : view.size());
+ end_ += view.begin_;
+}
+
+uint8_t View::operator[](size_t i) const {
+ ASSERT_LOG(i + begin_ < end_, "Out of bounds access at %zu", i);
+ return data_->operator[](i + begin_);
+}
+
+size_t View::size() const {
+ return end_ - begin_;
+}
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/view.h b/gd/packet/view.h
new file mode 100644
index 0000000..4f3b508
--- /dev/null
+++ b/gd/packet/view.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019 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>
+
+namespace bluetooth {
+namespace packet {
+
+// Base class that holds a shared pointer to data with bounds.
+class View {
+ public:
+ View(std::shared_ptr<const std::vector<uint8_t>> data, size_t begin, size_t end);
+ View(const View& view, size_t begin, size_t end);
+ View(const View& view) = default;
+ virtual ~View() = default;
+
+ uint8_t operator[](size_t i) const;
+
+ size_t size() const;
+
+ private:
+ std::shared_ptr<const std::vector<uint8_t>> data_;
+ size_t begin_;
+ size_t end_;
+};
+
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/smp/Android.bp b/gd/smp/Android.bp
new file mode 100644
index 0000000..b67878f
--- /dev/null
+++ b/gd/smp/Android.bp
@@ -0,0 +1,14 @@
+filegroup {
+ name: "BluetoothSmpSources",
+ srcs: [
+ "ecc/multprecision.cc",
+ "ecc/p_256_ecc_pp.cc",
+ ]
+}
+
+filegroup {
+ name: "BluetoothSmpTestSources",
+ srcs: [
+ "ecc/multipoint_test.cc",
+ ]
+}
\ No newline at end of file
diff --git a/gd/smp/ecc/multipoint_test.cc b/gd/smp/ecc/multipoint_test.cc
new file mode 100644
index 0000000..ebed658
--- /dev/null
+++ b/gd/smp/ecc/multipoint_test.cc
@@ -0,0 +1,112 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 <gtest/gtest.h>
+
+#include "smp/ecc/p_256_ecc_pp.h"
+
+namespace bluetooth {
+namespace smp {
+namespace ecc {
+
+// Test ECC point validation
+TEST(SmpEccValidationTest, test_valid_points) {
+ Point p;
+
+ // Test data from Bluetooth Core Specification
+ // Version 5.0 | Vol 2, Part G | 7.1.2
+
+ // Sample 1
+ p.x[7] = 0x20b003d2;
+ p.x[6] = 0xf297be2c;
+ p.x[5] = 0x5e2c83a7;
+ p.x[4] = 0xe9f9a5b9;
+ p.x[3] = 0xeff49111;
+ p.x[2] = 0xacf4fddb;
+ p.x[1] = 0xcc030148;
+ p.x[0] = 0x0e359de6;
+
+ p.y[7] = 0xdc809c49;
+ p.y[6] = 0x652aeb6d;
+ p.y[5] = 0x63329abf;
+ p.y[4] = 0x5a52155c;
+ p.y[3] = 0x766345c2;
+ p.y[2] = 0x8fed3024;
+ p.y[1] = 0x741c8ed0;
+ p.y[0] = 0x1589d28b;
+
+ EXPECT_TRUE(ECC_ValidatePoint(p));
+
+ // Sample 2
+ p.x[7] = 0x2c31a47b;
+ p.x[6] = 0x5779809e;
+ p.x[5] = 0xf44cb5ea;
+ p.x[4] = 0xaf5c3e43;
+ p.x[3] = 0xd5f8faad;
+ p.x[2] = 0x4a8794cb;
+ p.x[1] = 0x987e9b03;
+ p.x[0] = 0x745c78dd;
+
+ p.y[7] = 0x91951218;
+ p.y[6] = 0x3898dfbe;
+ p.y[5] = 0xcd52e240;
+ p.y[4] = 0x8e43871f;
+ p.y[3] = 0xd0211091;
+ p.y[2] = 0x17bd3ed4;
+ p.y[1] = 0xeaf84377;
+ p.y[0] = 0x43715d4f;
+
+ EXPECT_TRUE(ECC_ValidatePoint(p));
+}
+
+TEST(SmpEccValidationTest, test_invalid_points) {
+ Point p;
+ multiprecision_init(p.x);
+ multiprecision_init(p.y);
+
+ EXPECT_FALSE(ECC_ValidatePoint(p));
+
+ // Sample 1
+ p.x[7] = 0x20b003d2;
+ p.x[6] = 0xf297be2c;
+ p.x[5] = 0x5e2c83a7;
+ p.x[4] = 0xe9f9a5b9;
+ p.x[3] = 0xeff49111;
+ p.x[2] = 0xacf4fddb;
+ p.x[1] = 0xcc030148;
+ p.x[0] = 0x0e359de6;
+
+ EXPECT_FALSE(ECC_ValidatePoint(p));
+
+ p.y[7] = 0xdc809c49;
+ p.y[6] = 0x652aeb6d;
+ p.y[5] = 0x63329abf;
+ p.y[4] = 0x5a52155c;
+ p.y[3] = 0x766345c2;
+ p.y[2] = 0x8fed3024;
+ p.y[1] = 0x741c8ed0;
+ p.y[0] = 0x1589d28b;
+
+ p.y[0]--;
+
+ EXPECT_FALSE(ECC_ValidatePoint(p));
+}
+
+} // namespace ecc
+} // namespace smp
+} // namespace bluetooth
diff --git a/gd/smp/ecc/multprecision.cc b/gd/smp/ecc/multprecision.cc
new file mode 100644
index 0000000..38b6f3f
--- /dev/null
+++ b/gd/smp/ecc/multprecision.cc
@@ -0,0 +1,504 @@
+/******************************************************************************
+ *
+ * Copyright 2006-2015 Broadcom 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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * This file contains simple pairing algorithms
+ *
+ ******************************************************************************/
+
+#include "smp/ecc/multprecision.h"
+#include <string.h>
+
+namespace bluetooth {
+namespace smp {
+namespace ecc {
+
+#define DWORD_BITS 32
+#define DWORD_BYTES 4
+#define DWORD_BITS_SHIFT 5
+
+void multiprecision_init(uint32_t* c) {
+ for (uint32_t i = 0; i < KEY_LENGTH_DWORDS_P256; i++) c[i] = 0;
+}
+
+void multiprecision_copy(uint32_t* c, const uint32_t* a) {
+ for (uint32_t i = 0; i < KEY_LENGTH_DWORDS_P256; i++) c[i] = a[i];
+}
+
+int multiprecision_compare(const uint32_t* a, const uint32_t* b) {
+ for (int i = KEY_LENGTH_DWORDS_P256 - 1; i >= 0; i--) {
+ if (a[i] > b[i]) return 1;
+ if (a[i] < b[i]) return -1;
+ }
+ return 0;
+}
+
+int multiprecision_iszero(const uint32_t* a) {
+ for (uint32_t i = 0; i < KEY_LENGTH_DWORDS_P256; i++)
+ if (a[i]) return 0;
+
+ return 1;
+}
+
+uint32_t multiprecision_dword_bits(uint32_t a) {
+ uint32_t i;
+ for (i = 0; i < DWORD_BITS; i++, a >>= 1)
+ if (a == 0) break;
+
+ return i;
+}
+
+uint32_t multiprecision_most_signdwords(const uint32_t* a) {
+ int i;
+ for (i = KEY_LENGTH_DWORDS_P256 - 1; i >= 0; i--)
+ if (a[i]) break;
+ return (i + 1);
+}
+
+uint32_t multiprecision_most_signbits(const uint32_t* a) {
+ int aMostSignDWORDs;
+
+ aMostSignDWORDs = multiprecision_most_signdwords(a);
+ if (aMostSignDWORDs == 0) return 0;
+
+ return (((aMostSignDWORDs - 1) << DWORD_BITS_SHIFT) + multiprecision_dword_bits(a[aMostSignDWORDs - 1]));
+}
+
+uint32_t multiprecision_add(uint32_t* c, const uint32_t* a, const uint32_t* b) {
+ uint32_t carrier;
+ uint32_t temp;
+
+ carrier = 0;
+ for (uint32_t i = 0; i < KEY_LENGTH_DWORDS_P256; i++) {
+ temp = a[i] + carrier;
+ carrier = (temp < carrier);
+ temp += b[i];
+ carrier |= (temp < b[i]);
+ c[i] = temp;
+ }
+
+ return carrier;
+}
+
+// c=a-b
+uint32_t multiprecision_sub(uint32_t* c, const uint32_t* a, const uint32_t* b) {
+ uint32_t borrow;
+ uint32_t temp;
+
+ borrow = 0;
+ for (uint32_t i = 0; i < KEY_LENGTH_DWORDS_P256; i++) {
+ temp = a[i] - borrow;
+ borrow = (temp > a[i]);
+ c[i] = temp - b[i];
+ borrow |= (c[i] > temp);
+ }
+
+ return borrow;
+}
+
+// c = a << 1
+void multiprecision_lshift_mod(uint32_t* c, const uint32_t* a, const uint32_t* modp) {
+ uint32_t carrier = multiprecision_lshift(c, a);
+ if (carrier) {
+ multiprecision_sub(c, c, modp);
+ } else if (multiprecision_compare(c, modp) >= 0) {
+ multiprecision_sub(c, c, modp);
+ }
+}
+
+// c=a>>1
+void multiprecision_rshift(uint32_t* c, const uint32_t* a) {
+ int j;
+ uint32_t b = 1;
+
+ j = DWORD_BITS - b;
+
+ uint32_t carrier = 0;
+ uint32_t temp;
+ for (int i = KEY_LENGTH_DWORDS_P256 - 1; i >= 0; i--) {
+ temp = a[i]; // in case of c==a
+ c[i] = (temp >> b) | carrier;
+ carrier = temp << j;
+ }
+}
+
+// Curve specific optimization when p is a pseudo-Mersenns prime,
+// p=2^(KEY_LENGTH_BITS)-omega
+void multiprecision_mersenns_mult_mod(uint32_t* c, const uint32_t* a, const uint32_t* b, const uint32_t* modp) {
+ uint32_t cc[2 * KEY_LENGTH_DWORDS_P256];
+
+ multiprecision_mult(cc, a, b);
+ multiprecision_fast_mod_P256(c, cc, modp);
+}
+
+// Curve specific optimization when p is a pseudo-Mersenns prime
+void multiprecision_mersenns_squa_mod(uint32_t* c, const uint32_t* a, const uint32_t* modp) {
+ multiprecision_mersenns_mult_mod(c, a, a, modp);
+}
+
+// c=(a+b) mod p, b<p, a<p
+void multiprecision_add_mod(uint32_t* c, const uint32_t* a, const uint32_t* b, const uint32_t* modp) {
+ uint32_t carrier = multiprecision_add(c, a, b);
+ if (carrier) {
+ multiprecision_sub(c, c, modp);
+ } else if (multiprecision_compare(c, modp) >= 0) {
+ multiprecision_sub(c, c, modp);
+ }
+}
+
+// c=(a-b) mod p, a<p, b<p
+void multiprecision_sub_mod(uint32_t* c, const uint32_t* a, const uint32_t* b, const uint32_t* modp) {
+ uint32_t borrow;
+
+ borrow = multiprecision_sub(c, a, b);
+ if (borrow) multiprecision_add(c, c, modp);
+}
+
+// c=a<<b, b<DWORD_BITS, c has a buffer size of Numuint32_ts+1
+uint32_t multiprecision_lshift(uint32_t* c, const uint32_t* a) {
+ int j;
+ uint32_t b = 1;
+ j = DWORD_BITS - b;
+
+ uint32_t carrier = 0;
+ uint32_t temp;
+
+ for (uint32_t i = 0; i < KEY_LENGTH_DWORDS_P256; i++) {
+ temp = a[i]; // in case c==a
+ c[i] = (temp << b) | carrier;
+ carrier = temp >> j;
+ }
+
+ return carrier;
+}
+
+// c=a*b; c must have a buffer of 2*Key_LENGTH_uint32_tS, c != a != b
+void multiprecision_mult(uint32_t* c, const uint32_t* a, const uint32_t* b) {
+ uint32_t W;
+ uint32_t U;
+ uint32_t V;
+
+ U = V = W = 0;
+ multiprecision_init(c);
+
+ // assume little endian right now
+ for (uint32_t i = 0; i < KEY_LENGTH_DWORDS_P256; i++) {
+ U = 0;
+ for (uint32_t j = 0; j < KEY_LENGTH_DWORDS_P256; j++) {
+ uint64_t result;
+ result = ((uint64_t)a[i]) * ((uint64_t)b[j]);
+ W = result >> 32;
+ V = a[i] * b[j];
+ V = V + U;
+ U = (V < U);
+ U += W;
+ V = V + c[i + j];
+ U += (V < c[i + j]);
+ c[i + j] = V;
+ }
+ c[i + KEY_LENGTH_DWORDS_P256] = U;
+ }
+}
+
+void multiprecision_fast_mod_P256(uint32_t* c, const uint32_t* a, const uint32_t* modp) {
+ uint32_t A;
+ uint32_t B;
+ uint32_t C;
+ uint32_t D;
+ uint32_t E;
+ uint32_t F;
+ uint32_t G;
+ uint8_t UA;
+ uint8_t UB;
+ uint8_t UC;
+ uint8_t UD;
+ uint8_t UE;
+ uint8_t UF;
+ uint8_t UG;
+ uint32_t U;
+
+ // C = a[13] + a[14] + a[15];
+ C = a[13];
+ C += a[14];
+ UC = (C < a[14]);
+ C += a[15];
+ UC += (C < a[15]);
+
+ // E = a[8] + a[9];
+ E = a[8];
+ E += a[9];
+ UE = (E < a[9]);
+
+ // F = a[9] + a[10];
+ F = a[9];
+ F += a[10];
+ UF = (F < a[10]);
+
+ // G = a[10] + a[11]
+ G = a[10];
+ G += a[11];
+ UG = (G < a[11]);
+
+ // B = a[12] + a[13] + a[14] + a[15] == C + a[12]
+ B = C;
+ UB = UC;
+ B += a[12];
+ UB += (B < a[12]);
+
+ // A = a[11] + a[12] + a[13] + a[14] == B + a[11] - a[15]
+ A = B;
+ UA = UB;
+ A += a[11];
+ UA += (A < a[11]);
+ UA -= (A < a[15]);
+ A -= a[15];
+
+ // D = a[10] + a[11] + a[12] + a[13] == A + a[10] - a[14]
+ D = A;
+ UD = UA;
+ D += a[10];
+ UD += (D < a[10]);
+ UD -= (D < a[14]);
+ D -= a[14];
+
+ c[0] = a[0];
+ c[0] += E;
+ U = (c[0] < E);
+ U += UE;
+ U -= (c[0] < A);
+ U -= UA;
+ c[0] -= A;
+
+ if (U & 0x80000000) {
+ uint32_t UU;
+ UU = 0 - U;
+ U = (a[1] < UU);
+ c[1] = a[1] - UU;
+ } else {
+ c[1] = a[1] + U;
+ U = (c[1] < a[1]);
+ }
+
+ c[1] += F;
+ U += (c[1] < F);
+ U += UF;
+ U -= (c[1] < B);
+ U -= UB;
+ c[1] -= B;
+
+ if (U & 0x80000000) {
+ uint32_t UU;
+ UU = 0 - U;
+ U = (a[2] < UU);
+ c[2] = a[2] - UU;
+ } else {
+ c[2] = a[2] + U;
+ U = (c[2] < a[2]);
+ }
+
+ c[2] += G;
+ U += (c[2] < G);
+ U += UG;
+ U -= (c[2] < C);
+ U -= UC;
+ c[2] -= C;
+
+ if (U & 0x80000000) {
+ uint32_t UU;
+ UU = 0 - U;
+ U = (a[3] < UU);
+ c[3] = a[3] - UU;
+ } else {
+ c[3] = a[3] + U;
+ U = (c[3] < a[3]);
+ }
+
+ c[3] += A;
+ U += (c[3] < A);
+ U += UA;
+ c[3] += a[11];
+ U += (c[3] < a[11]);
+ c[3] += a[12];
+ U += (c[3] < a[12]);
+ U -= (c[3] < a[14]);
+ c[3] -= a[14];
+ U -= (c[3] < a[15]);
+ c[3] -= a[15];
+ U -= (c[3] < E);
+ U -= UE;
+ c[3] -= E;
+
+ if (U & 0x80000000) {
+ uint32_t UU;
+ UU = 0 - U;
+ U = (a[4] < UU);
+ c[4] = a[4] - UU;
+ } else {
+ c[4] = a[4] + U;
+ U = (c[4] < a[4]);
+ }
+
+ c[4] += B;
+ U += (c[4] < B);
+ U += UB;
+ U -= (c[4] < a[15]);
+ c[4] -= a[15];
+ c[4] += a[12];
+ U += (c[4] < a[12]);
+ c[4] += a[13];
+ U += (c[4] < a[13]);
+ U -= (c[4] < F);
+ U -= UF;
+ c[4] -= F;
+
+ if (U & 0x80000000) {
+ uint32_t UU;
+ UU = 0 - U;
+ U = (a[5] < UU);
+ c[5] = a[5] - UU;
+ } else {
+ c[5] = a[5] + U;
+ U = (c[5] < a[5]);
+ }
+
+ c[5] += C;
+ U += (c[5] < C);
+ U += UC;
+ c[5] += a[13];
+ U += (c[5] < a[13]);
+ c[5] += a[14];
+ U += (c[5] < a[14]);
+ U -= (c[5] < G);
+ U -= UG;
+ c[5] -= G;
+
+ if (U & 0x80000000) {
+ uint32_t UU;
+ UU = 0 - U;
+ U = (a[6] < UU);
+ c[6] = a[6] - UU;
+ } else {
+ c[6] = a[6] + U;
+ U = (c[6] < a[6]);
+ }
+
+ c[6] += C;
+ U += (c[6] < C);
+ U += UC;
+ c[6] += a[14];
+ U += (c[6] < a[14]);
+ c[6] += a[14];
+ U += (c[6] < a[14]);
+ c[6] += a[15];
+ U += (c[6] < a[15]);
+ U -= (c[6] < E);
+ U -= UE;
+ c[6] -= E;
+
+ if (U & 0x80000000) {
+ uint32_t UU;
+ UU = 0 - U;
+ U = (a[7] < UU);
+ c[7] = a[7] - UU;
+ } else {
+ c[7] = a[7] + U;
+ U = (c[7] < a[7]);
+ }
+
+ c[7] += a[15];
+ U += (c[7] < a[15]);
+ c[7] += a[15];
+ U += (c[7] < a[15]);
+ c[7] += a[15];
+ U += (c[7] < a[15]);
+ c[7] += a[8];
+ U += (c[7] < a[8]);
+ U -= (c[7] < D);
+ U -= UD;
+ c[7] -= D;
+
+ if (U & 0x80000000) {
+ while (U) {
+ multiprecision_add(c, c, modp);
+ U++;
+ }
+ } else if (U) {
+ while (U) {
+ multiprecision_sub(c, c, modp);
+ U--;
+ }
+ }
+
+ if (multiprecision_compare(c, modp) >= 0) multiprecision_sub(c, c, modp);
+}
+
+void multiprecision_inv_mod(uint32_t* aminus, uint32_t* u, const uint32_t* modp) {
+ uint32_t v[KEY_LENGTH_DWORDS_P256];
+ uint32_t A[KEY_LENGTH_DWORDS_P256 + 1];
+ uint32_t C[KEY_LENGTH_DWORDS_P256 + 1];
+
+ multiprecision_copy(v, modp);
+ multiprecision_init(A);
+ multiprecision_init(C);
+ A[0] = 1;
+
+ while (!multiprecision_iszero(u)) {
+ while (!(u[0] & 0x01)) // u is even
+ {
+ multiprecision_rshift(u, u);
+ if (!(A[0] & 0x01)) // A is even
+ multiprecision_rshift(A, A);
+ else {
+ A[KEY_LENGTH_DWORDS_P256] = multiprecision_add(A, A, modp); // A =A+p
+ multiprecision_rshift(A, A);
+ A[KEY_LENGTH_DWORDS_P256 - 1] |= (A[KEY_LENGTH_DWORDS_P256] << 31);
+ }
+ }
+
+ while (!(v[0] & 0x01)) // v is even
+ {
+ multiprecision_rshift(v, v);
+ if (!(C[0] & 0x01)) // C is even
+ {
+ multiprecision_rshift(C, C);
+ } else {
+ C[KEY_LENGTH_DWORDS_P256] = multiprecision_add(C, C, modp); // C =C+p
+ multiprecision_rshift(C, C);
+ C[KEY_LENGTH_DWORDS_P256 - 1] |= (C[KEY_LENGTH_DWORDS_P256] << 31);
+ }
+ }
+
+ if (multiprecision_compare(u, v) >= 0) {
+ multiprecision_sub(u, u, v);
+ multiprecision_sub_mod(A, A, C, modp);
+ } else {
+ multiprecision_sub(v, v, u);
+ multiprecision_sub_mod(C, C, A, modp);
+ }
+ }
+
+ if (multiprecision_compare(C, modp) >= 0)
+ multiprecision_sub(aminus, C, modp);
+ else
+ multiprecision_copy(aminus, C);
+}
+
+} // namespace ecc
+} // namespace smp
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/smp/ecc/multprecision.h b/gd/smp/ecc/multprecision.h
new file mode 100644
index 0000000..01bb9ad
--- /dev/null
+++ b/gd/smp/ecc/multprecision.h
@@ -0,0 +1,56 @@
+/******************************************************************************
+ *
+ * Copyright 2006-2015 Broadcom 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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * This file contains simple pairing algorithms
+ *
+ ******************************************************************************/
+#pragma once
+
+#include <cstdint>
+
+namespace bluetooth {
+namespace smp {
+namespace ecc {
+
+#define KEY_LENGTH_DWORDS_P256 8
+/* Arithmetic Operations*/
+int multiprecision_compare(const uint32_t* a, const uint32_t* b);
+int multiprecision_iszero(const uint32_t* a);
+void multiprecision_init(uint32_t* c);
+void multiprecision_copy(uint32_t* c, const uint32_t* a);
+uint32_t multiprecision_dword_bits(uint32_t a);
+uint32_t multiprecision_most_signdwords(const uint32_t* a);
+uint32_t multiprecision_most_signbits(const uint32_t* a);
+void multiprecision_inv_mod(uint32_t* aminus, uint32_t* a, const uint32_t* modp);
+uint32_t multiprecision_add(uint32_t* c, const uint32_t* a, const uint32_t* b); // c=a+b
+void multiprecision_add_mod(uint32_t* c, const uint32_t* a, const uint32_t* b, const uint32_t* modp);
+uint32_t multiprecision_sub(uint32_t* c, const uint32_t* a, const uint32_t* b); // c=a-b
+void multiprecision_sub_mod(uint32_t* c, const uint32_t* a, const uint32_t* b, const uint32_t* modp);
+void multiprecision_rshift(uint32_t* c, const uint32_t* a); // c=a>>1, return carrier
+void multiprecision_lshift_mod(uint32_t* c, const uint32_t* a, const uint32_t* modp); // c=a<<b, return carrier
+uint32_t multiprecision_lshift(uint32_t* c, const uint32_t* a);
+void multiprecision_mult(uint32_t* c, const uint32_t* a, const uint32_t* b); // c=a*b
+void multiprecision_mersenns_mult_mod(uint32_t* c, const uint32_t* a, const uint32_t* b, const uint32_t* modp);
+void multiprecision_mersenns_squa_mod(uint32_t* c, const uint32_t* a, const uint32_t* modp);
+void multiprecision_fast_mod_P256(uint32_t* c, const uint32_t* a, const uint32_t* modp);
+
+} // namespace ecc
+} // namespace smp
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/smp/ecc/p_256_ecc_pp.cc b/gd/smp/ecc/p_256_ecc_pp.cc
new file mode 100644
index 0000000..e5d76c8
--- /dev/null
+++ b/gd/smp/ecc/p_256_ecc_pp.cc
@@ -0,0 +1,264 @@
+/******************************************************************************
+ *
+ * Copyright 2006-2015 Broadcom 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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * This file contains simple pairing algorithms using Elliptic Curve
+ * Cryptography for private public key
+ *
+ ******************************************************************************/
+#include "smp/ecc/p_256_ecc_pp.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "smp/ecc/multprecision.h"
+
+namespace bluetooth {
+namespace smp {
+namespace ecc {
+
+const uint32_t* modp = curve_p256.p;
+
+static void p_256_init_point(Point* q) {
+ memset(q, 0, sizeof(Point));
+}
+
+static void p_256_copy_point(Point* q, const Point* p) {
+ memcpy(q, p, sizeof(Point));
+}
+
+// q=2q
+static void ECC_Double(Point* q, const Point* p) {
+ uint32_t t1[KEY_LENGTH_DWORDS_P256];
+ uint32_t t2[KEY_LENGTH_DWORDS_P256];
+ uint32_t t3[KEY_LENGTH_DWORDS_P256];
+ const uint32_t* x1;
+ uint32_t* x3;
+ const uint32_t* y1;
+ uint32_t* y3;
+ const uint32_t* z1;
+ uint32_t* z3;
+
+ if (multiprecision_iszero(p->z)) {
+ multiprecision_init(q->z);
+ return; // return infinity
+ }
+
+ x1 = p->x;
+ y1 = p->y;
+ z1 = p->z;
+ x3 = q->x;
+ y3 = q->y;
+ z3 = q->z;
+
+ multiprecision_mersenns_squa_mod(t1, z1, modp); // t1=z1^2
+ multiprecision_sub_mod(t2, x1, t1, modp); // t2=x1-t1
+ multiprecision_add_mod(t1, x1, t1, modp); // t1=x1+t1
+ multiprecision_mersenns_mult_mod(t2, t1, t2, modp); // t2=t2*t1
+ multiprecision_lshift_mod(t3, t2, modp);
+ multiprecision_add_mod(t2, t3, t2, modp); // t2=3t2
+
+ multiprecision_mersenns_mult_mod(z3, y1, z1, modp); // z3=y1*z1
+ multiprecision_lshift_mod(z3, z3, modp);
+
+ multiprecision_mersenns_squa_mod(y3, y1, modp); // y3=y1^2
+ multiprecision_lshift_mod(y3, y3, modp);
+ multiprecision_mersenns_mult_mod(t3, y3, x1, modp); // t3=y3*x1=x1*y1^2
+ multiprecision_lshift_mod(t3, t3, modp);
+ multiprecision_mersenns_squa_mod(y3, y3, modp); // y3=y3^2=y1^4
+ multiprecision_lshift_mod(y3, y3, modp);
+
+ multiprecision_mersenns_squa_mod(x3, t2, modp); // x3=t2^2
+ multiprecision_lshift_mod(t1, t3, modp); // t1=2t3
+ multiprecision_sub_mod(x3, x3, t1, modp); // x3=x3-t1
+ multiprecision_sub_mod(t1, t3, x3, modp); // t1=t3-x3
+ multiprecision_mersenns_mult_mod(t1, t1, t2, modp); // t1=t1*t2
+ multiprecision_sub_mod(y3, t1, y3, modp); // y3=t1-y3
+}
+
+// q=q+p, zp must be 1
+static void ECC_Add(Point* r, Point* p, const Point* q) {
+ uint32_t t1[KEY_LENGTH_DWORDS_P256];
+ uint32_t t2[KEY_LENGTH_DWORDS_P256];
+ uint32_t* x1;
+ const uint32_t* x2;
+ uint32_t* x3;
+ uint32_t* y1;
+ const uint32_t* y2;
+ uint32_t* y3;
+ uint32_t* z1;
+ const uint32_t* z2;
+ uint32_t* z3;
+
+ x1 = p->x;
+ y1 = p->y;
+ z1 = p->z;
+ x2 = q->x;
+ y2 = q->y;
+ z2 = q->z;
+ x3 = r->x;
+ y3 = r->y;
+ z3 = r->z;
+
+ // if Q=infinity, return p
+ if (multiprecision_iszero(z2)) {
+ p_256_copy_point(r, p);
+ return;
+ }
+
+ // if P=infinity, return q
+ if (multiprecision_iszero(z1)) {
+ p_256_copy_point(r, q);
+ return;
+ }
+
+ multiprecision_mersenns_squa_mod(t1, z1, modp); // t1=z1^2
+ multiprecision_mersenns_mult_mod(t2, z1, t1, modp); // t2=t1*z1
+ multiprecision_mersenns_mult_mod(t1, x2, t1, modp); // t1=t1*x2
+ multiprecision_mersenns_mult_mod(t2, y2, t2, modp); // t2=t2*y2
+
+ multiprecision_sub_mod(t1, t1, x1, modp); // t1=t1-x1
+ multiprecision_sub_mod(t2, t2, y1, modp); // t2=t2-y1
+
+ if (multiprecision_iszero(t1)) {
+ if (multiprecision_iszero(t2)) {
+ ECC_Double(r, q);
+ return;
+ } else {
+ multiprecision_init(z3);
+ return; // return infinity
+ }
+ }
+
+ multiprecision_mersenns_mult_mod(z3, z1, t1, modp); // z3=z1*t1
+ multiprecision_mersenns_squa_mod(y3, t1, modp); // t3=t1^2
+ multiprecision_mersenns_mult_mod(z1, y3, t1, modp); // t4=t3*t1
+ multiprecision_mersenns_mult_mod(y3, y3, x1, modp); // t3=t3*x1
+ multiprecision_lshift_mod(t1, y3, modp); // t1=2*t3
+ multiprecision_mersenns_squa_mod(x3, t2, modp); // x3=t2^2
+ multiprecision_sub_mod(x3, x3, t1, modp); // x3=x3-t1
+ multiprecision_sub_mod(x3, x3, z1, modp); // x3=x3-t4
+ multiprecision_sub_mod(y3, y3, x3, modp); // t3=t3-x3
+ multiprecision_mersenns_mult_mod(y3, y3, t2, modp); // t3=t3*t2
+ multiprecision_mersenns_mult_mod(z1, z1, y1, modp); // t4=t4*t1
+ multiprecision_sub_mod(y3, y3, z1, modp);
+}
+
+// Computing the Non-Adjacent Form of a positive integer
+static void ECC_NAF(uint8_t* naf, uint32_t* NumNAF, uint32_t* k) {
+ uint32_t sign;
+ int i = 0;
+ int j;
+ uint32_t var;
+
+ while ((var = multiprecision_most_signbits(k)) >= 1) {
+ if (k[0] & 0x01) // k is odd
+ {
+ sign = (k[0] & 0x03); // 1 or 3
+
+ // k = k-naf[i]
+ if (sign == 1)
+ k[0] = k[0] & 0xFFFFFFFE;
+ else {
+ k[0] = k[0] + 1;
+ if (k[0] == 0) // overflow
+ {
+ j = 1;
+ do {
+ k[j]++;
+ } while (k[j++] == 0); // overflow
+ }
+ }
+ } else
+ sign = 0;
+
+ multiprecision_rshift(k, k);
+ naf[i / 4] |= (sign) << ((i % 4) * 2);
+ i++;
+ }
+
+ *NumNAF = i;
+}
+
+// Binary Non-Adjacent Form for point multiplication
+void ECC_PointMult_Bin_NAF(Point* q, const Point* p, uint32_t* n) {
+ uint32_t sign;
+ uint8_t naf[256 / 4 + 1];
+ uint32_t NumNaf;
+ Point minus_p;
+ Point r;
+
+ p_256_init_point(&r);
+
+ // initialization
+ p_256_init_point(q);
+
+ // -p
+ multiprecision_copy(minus_p.x, p->x);
+ multiprecision_sub(minus_p.y, modp, p->y);
+
+ multiprecision_init(minus_p.z);
+ minus_p.z[0] = 1;
+
+ // NAF
+ memset(naf, 0, sizeof(naf));
+ ECC_NAF(naf, &NumNaf, n);
+
+ for (int i = NumNaf - 1; i >= 0; i--) {
+ p_256_copy_point(&r, q);
+ ECC_Double(q, &r);
+ sign = (naf[i / 4] >> ((i % 4) * 2)) & 0x03;
+
+ if (sign == 1) {
+ p_256_copy_point(&r, q);
+ ECC_Add(q, &r, p);
+ } else if (sign == 3) {
+ p_256_copy_point(&r, q);
+ ECC_Add(q, &r, &minus_p);
+ }
+ }
+
+ multiprecision_inv_mod(minus_p.x, q->z, modp);
+ multiprecision_mersenns_squa_mod(q->z, minus_p.x, modp);
+ multiprecision_mersenns_mult_mod(q->x, q->x, q->z, modp);
+ multiprecision_mersenns_mult_mod(q->z, q->z, minus_p.x, modp);
+ multiprecision_mersenns_mult_mod(q->y, q->y, q->z, modp);
+}
+
+bool ECC_ValidatePoint(const Point& pt) {
+ // Ensure y^2 = x^3 + a*x + b (mod p); a = -3
+
+ // y^2 mod p
+ uint32_t y2_mod[KEY_LENGTH_DWORDS_P256] = {0};
+ multiprecision_mersenns_squa_mod(y2_mod, (uint32_t*)pt.y, modp);
+
+ // Right hand side calculation
+ uint32_t rhs[KEY_LENGTH_DWORDS_P256] = {0};
+ multiprecision_mersenns_squa_mod(rhs, (uint32_t*)pt.x, modp);
+ uint32_t three[KEY_LENGTH_DWORDS_P256] = {0};
+ three[0] = 3;
+ multiprecision_sub_mod(rhs, rhs, three, modp);
+ multiprecision_mersenns_mult_mod(rhs, rhs, (uint32_t*)pt.x, modp);
+ multiprecision_add_mod(rhs, rhs, curve_p256.b, modp);
+
+ return multiprecision_compare(rhs, y2_mod) == 0;
+}
+
+} // namespace ecc
+} // namespace smp
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/smp/ecc/p_256_ecc_pp.h b/gd/smp/ecc/p_256_ecc_pp.h
new file mode 100644
index 0000000..4fc4653
--- /dev/null
+++ b/gd/smp/ecc/p_256_ecc_pp.h
@@ -0,0 +1,75 @@
+/******************************************************************************
+ *
+ * Copyright 2006-2015 Broadcom 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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains simple pairing algorithms using Elliptic Curve
+ *Cryptography for private public key
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include "smp/ecc/multprecision.h"
+
+namespace bluetooth {
+namespace smp {
+namespace ecc {
+
+struct Point {
+ uint32_t x[KEY_LENGTH_DWORDS_P256];
+ uint32_t y[KEY_LENGTH_DWORDS_P256];
+ uint32_t z[KEY_LENGTH_DWORDS_P256];
+};
+
+struct elliptic_curve_t {
+ // curve's coefficients
+ uint32_t a[KEY_LENGTH_DWORDS_P256];
+ uint32_t b[KEY_LENGTH_DWORDS_P256];
+
+ // prime modulus
+ uint32_t p[KEY_LENGTH_DWORDS_P256];
+
+ // Omega, p = 2^m -omega
+ uint32_t omega[KEY_LENGTH_DWORDS_P256];
+
+ // base point, a point on E of order r
+ Point G;
+};
+
+// P-256 elliptic curve, as per BT Spec 5.1 Vol 2, Part H 7.6
+static constexpr elliptic_curve_t curve_p256{
+ .p = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0, 0x0, 0x0, 0x00000001, 0xFFFFFFFF},
+ .omega = {0},
+ .a = {0},
+ .b = {0x27d2604b, 0x3bce3c3e, 0xcc53b0f6, 0x651d06b0, 0x769886bc, 0xb3ebbd55, 0xaa3a93e7, 0x5ac635d8},
+
+ .G = {.x = {0xd898c296, 0xf4a13945, 0x2deb33a0, 0x77037d81, 0x63a440f2, 0xf8bce6e5, 0xe12c4247, 0x6b17d1f2},
+ .y = {0x37bf51f5, 0xcbb64068, 0x6b315ece, 0x2bce3357, 0x7c0f9e16, 0x8ee7eb4a, 0xfe1a7f9b, 0x4fe342e2}},
+};
+
+/* This function checks that point is on the elliptic curve*/
+bool ECC_ValidatePoint(const Point& point);
+
+void ECC_PointMult_Bin_NAF(Point* q, const Point* p, uint32_t* n);
+
+#define ECC_PointMult(q, p, n) ECC_PointMult_Bin_NAF(q, p, n)
+
+} // namespace ecc
+} // namespace smp
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/smp/smp_packets.pdl b/gd/smp/smp_packets.pdl
new file mode 100644
index 0000000..f8cc84c
--- /dev/null
+++ b/gd/smp/smp_packets.pdl
@@ -0,0 +1,161 @@
+little_endian_packets
+
+custom_field Address : 48 "hci/"
+
+enum Code : 8 {
+ PAIRING_REQUEST = 0x01,
+ PAIRING_RESPONSE = 0x02,
+ PAIRING_CONFIRM = 0x03,
+ PAIRING_RANDOM = 0x04,
+ PAIRING_FAILED = 0x05,
+ ENCRYPTION_INFORMATION = 0x06,
+ MASTER_IDENTIFICATION = 0x07,
+ IDENTITY_INFORMATION = 0x08,
+ IDENTITY_ADDRESS_INFORMATION = 0x09,
+ SIGNING_INFORMATION = 0x0A,
+ SECURITY_REQUEST = 0x0B,
+ PAIRING_PUBLIC_KEY = 0x0C,
+ PAIRING_DH_KEY_CHECK = 0x0D,
+ PAIRING_KEYPRESS_NOTIFICATION = 0x0E,
+}
+
+packet Command {
+ code : Code,
+ _payload_,
+}
+
+enum IoCapability : 8 {
+ DISPLAY_ONLY = 0x00,
+ DISPLAY_YES_NO = 0x01,
+ KEYBOARD_ONLY = 0x02,
+ NO_INPUT_NO_OUTPUT = 0x03,
+ KEYBOARD_DISPLAY = 0x04,
+}
+
+enum OobDataFlag : 8 {
+ NOT_PRESENT = 0x00,
+ PRESENT = 0x01,
+}
+
+enum BondingFlags : 2 {
+ NO_BONDING = 0,
+ BONDING = 1,
+}
+
+group AuthReq {
+ bonding_flags : BondingFlags,
+ mitm : 1, // Man-in-the-middle protection required
+ sc : 1, // Secure Connections
+ keypress : 1, // Only used in Passkey Entry
+ ct2 : 1, // Support for the h7 function.
+ _reserved_ : 2,
+}
+
+group PairingInfo {
+ io_capability : IoCapability,
+ oob_data_flag : OobDataFlag,
+ AuthReq,
+ maximum_encryption_key_size : 5, // 7 - 16
+ _reserved_ : 3,
+ // InitiatorKeyDistribution
+ initiator_enc_key : 1,
+ initiator_id_key : 1,
+ initiator_sign_key : 1,
+ initiator_link_key : 1,
+ _reserved_ : 4,
+ // ResponderKeyDistribution
+ responder_enc_key : 1,
+ responder_id_key : 1,
+ responder_sign_key : 1,
+ responder_link_key : 1,
+ _reserved_ : 4,
+}
+
+packet PairingRequest : Command (code = PAIRING_REQUEST) {
+ PairingInfo,
+}
+
+packet PairingResponse : Command (code = PAIRING_RESPONSE) {
+ PairingInfo,
+}
+
+packet PairingConfirm : Command (code = PAIRING_CONFIRM) {
+ confirm_value : 8[16], // Initiating device sends Mconfirm, responding device sends Sconfirm
+}
+
+packet PairingRandom : Command (code = PAIRING_RANDOM) {
+ random_value : 8[16], // Initiating device sends Mrand, responding device sends Srand
+}
+
+enum PairingFailedReason : 8 {
+ PASSKEY_ENTRY_FAILED = 0x01,
+ OOB_NOT_AVAILABLE = 0x02,
+ AUTHENTICATION_REQUIREMENTS = 0x03,
+ CONFIRM_VALUE_FAILED = 0x04,
+ PAIRING_NOT_SUPPORTED = 0x05,
+ ENCRYPTION_KEY_SIZE = 0x06,
+ COMMAND_NOT_SUPPORTED = 0x07,
+ UNSPECIFIED_REASON = 0x08,
+ REPEATED_ATTEMPTS = 0x09,
+ INVALID_PARAMETERS = 0x0A,
+ DHKEY_CHECK_FAILED = 0x0B,
+ NUMERIC_COMPARISON_FAILED = 0x0C,
+ BR_EDR_PAIRING_IN_PROGRESS = 0x0D,
+ CROSS_TRANSPORT_KEY_DERIVATION_NOT_ALLOWED = 0x0E,
+}
+
+packet PairingFailed : Command (code = PAIRING_FAILED) {
+ reason : PairingFailedReason,
+}
+
+packet EncryptionInformation : Command (code = ENCRYPTION_INFORMATION) {
+ long_term_key : 8[16],
+}
+
+packet MasterIdentification : Command (code = MASTER_IDENTIFICATION) {
+ ediv : 16,
+ rand : 64,
+}
+
+packet IdentityInformation : Command (code = IDENTITY_INFORMATION) {
+ identity_resolving_key : 8[16],
+}
+
+enum AddrType : 8 {
+ PUBLIC = 0x00,
+ STATIC_RANDOM = 0x01,
+}
+
+packet IdentityAddressInformation : Command (code = IDENTITY_ADDRESS_INFORMATION) {
+ addr_type : AddrType,
+ bd_addr : Address,
+}
+
+packet SigningInformation : Command (code = SIGNING_INFORMATION) {
+ signature_key : 8[16],
+}
+
+packet SecurityRequest : Command (code = SECURITY_REQUEST) {
+ AuthReq,
+}
+
+packet PairingPublicKey : Command (code = PAIRING_PUBLIC_KEY) {
+ public_key_x : 8[32],
+ public_key_y : 8[32],
+}
+
+packet PairingDhKeyCheck : Command (code = PAIRING_DH_KEY_CHECK) {
+ dh_key_check : 8[16],
+}
+
+enum KeypressNotificationType : 8 {
+ ENTRY_STARTED = 0,
+ DIGIT_ENTERED = 1,
+ DIGIT_ERASED = 2,
+ CLEARED = 3,
+ ENTRY_COMPLETED = 4,
+}
+
+packet PairingKeypressNotification : Command (code = PAIRING_KEYPRESS_NOTIFICATION) {
+ notification_type : KeypressNotificationType,
+}
diff --git a/gd/stack_manager.cc b/gd/stack_manager.cc
new file mode 100644
index 0000000..ad83674
--- /dev/null
+++ b/gd/stack_manager.cc
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2019 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 "stack_manager.h"
+
+#include <chrono>
+#include <future>
+#include <queue>
+
+#include "hal/hci_hal.h"
+#include "os/thread.h"
+#include "os/handler.h"
+#include "os/log.h"
+#include "module.h"
+
+using ::bluetooth::os::Handler;
+using ::bluetooth::os::Thread;
+
+namespace bluetooth {
+
+void StackManager::StartUp(ModuleList* modules, Thread* stack_thread) {
+ management_thread_ = new Thread("management_thread", Thread::Priority::NORMAL);
+ handler_ = new Handler(management_thread_);
+
+ std::promise<void>* promise = new std::promise<void>();
+ handler_->Post([this, promise, modules, stack_thread]() {
+ registry_.Start(modules, stack_thread);
+ promise->set_value();
+ });
+
+ auto future = promise->get_future();
+ auto init_status = future.wait_for(std::chrono::seconds(3));
+ ASSERT_LOG(init_status == std::future_status::ready, "Can't start stack");
+ delete promise;
+
+ LOG_INFO("init complete");
+}
+
+void StackManager::ShutDown() {
+ std::promise<void>* promise = new std::promise<void>();
+ handler_->Post([this, promise]() {
+ registry_.StopAll();
+ promise->set_value();
+ });
+
+ auto future = promise->get_future();
+ auto stop_status = future.wait_for(std::chrono::seconds(3));
+ ASSERT_LOG(stop_status == std::future_status::ready, "Can't stop stack");
+
+ delete promise;
+ delete handler_;
+ delete management_thread_;
+}
+} // namespace bluetooth
diff --git a/gd/stack_manager.h b/gd/stack_manager.h
new file mode 100644
index 0000000..2f971cb
--- /dev/null
+++ b/gd/stack_manager.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2019 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 "module.h"
+#include "os/thread.h"
+#include "os/handler.h"
+
+namespace bluetooth {
+
+class StackManager {
+ public:
+ void StartUp(ModuleList *modules, os::Thread* stack_thread);
+ void ShutDown();
+
+ template <class T>
+ T* GetInstance() const {
+ return static_cast<T*>(registry_.Get(&T::Factory));
+ }
+
+ private:
+ os::Thread* management_thread_;
+ os::Handler* handler_;
+ ModuleRegistry registry_;
+};
+
+} // namespace bluetooth
diff --git a/hci/AndroidTest.xml b/hci/AndroidTest.xml
deleted file mode 100644
index 944b454..0000000
--- a/hci/AndroidTest.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2017 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.
--->
-<configuration description="Config for net_test_hci">
- <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
- <option name="cleanup" value="true" />
- <option name="push" value="net_test_hci->/data/local/tmp/net_test_hci" />
- </target_preparer>
- <option name="test-suite-tag" value="apct" />
- <test class="com.android.tradefed.testtype.GTest" >
- <option name="native-test-device-path" value="/data/local/tmp" />
- <option name="module-name" value="net_test_hci" />
- </test>
-</configuration>
\ No newline at end of file
diff --git a/hci/BUILD.gn b/hci/BUILD.gn
index fc9c2ce..e29e256 100644
--- a/hci/BUILD.gn
+++ b/hci/BUILD.gn
@@ -38,6 +38,7 @@
]
deps = [
+ "//common",
"//third_party/libchrome:base",
]
}
diff --git a/hci/include/hci_layer.h b/hci/include/hci_layer.h
index 59ee443..5eb2bd5 100644
--- a/hci/include/hci_layer.h
+++ b/hci/include/hci_layer.h
@@ -18,8 +18,8 @@
#pragma once
-#include <base/bind.h>
-#include <base/tracked_objects.h>
+#include <base/callback.h>
+#include <base/location.h>
#include <stdbool.h>
#include "bt_types.h"
@@ -70,8 +70,7 @@
typedef struct hci_t {
// Set the callback that the HCI layer uses to send data upwards
void (*set_data_cb)(
- base::Callback<void(const tracked_objects::Location&, BT_HDR*)>
- send_data_cb);
+ base::Callback<void(const base::Location&, BT_HDR*)> send_data_cb);
// Send a command through the HCI layer
void (*transmit_command)(BT_HDR* command,
@@ -91,7 +90,6 @@
const btsnoop_t* btsnoop_interface,
const packet_fragmenter_t* packet_fragmenter_interface);
-void post_to_hci_message_loop(const tracked_objects::Location& from_here,
- BT_HDR* p_msg);
+void post_to_main_message_loop(const base::Location& from_here, BT_HDR* p_msg);
void hci_layer_cleanup_interface();
diff --git a/hci/src/btsnoop.cc b/hci/src/btsnoop.cc
index 9812b61..6938725 100644
--- a/hci/src/btsnoop.cc
+++ b/hci/src/btsnoop.cc
@@ -36,12 +36,12 @@
#include <unistd.h>
#include "bt_types.h"
+#include "common/time_util.h"
#include "hci/include/btsnoop.h"
#include "hci/include/btsnoop_mem.h"
#include "hci_layer.h"
#include "osi/include/log.h"
#include "osi/include/properties.h"
-#include "osi/include/time.h"
#include "stack_config.h"
// The number of of packets per btsnoop file before we rotate to the next
@@ -129,7 +129,7 @@
uint8_t* p = const_cast<uint8_t*>(buffer->data + buffer->offset);
std::lock_guard<std::mutex> lock(btsnoop_mutex);
- uint64_t timestamp_us = time_gettimeofday_us();
+ uint64_t timestamp_us = bluetooth::common::time_gettimeofday_us();
btsnoop_mem_capture(buffer, timestamp_us);
if (logfile_fd == INVALID_FD) return;
diff --git a/hci/src/hci_layer.cc b/hci/src/hci_layer.cc
index f1e0e7a..ed2908c 100644
--- a/hci/src/hci_layer.cc
+++ b/hci/src/hci_layer.cc
@@ -25,6 +25,7 @@
#include <base/run_loop.h>
#include <base/sequenced_task_runner.h>
#include <base/threading/thread.h>
+#include <frameworks/base/core/proto/android/bluetooth/hci/enums.pb.h>
#include <signal.h>
#include <string.h>
@@ -37,6 +38,8 @@
#include "btcore/include/module.h"
#include "btsnoop.h"
#include "buffer_allocator.h"
+#include "common/message_loop_thread.h"
+#include "common/metrics.h"
#include "hci_inject.h"
#include "hci_internals.h"
#include "hcidefs.h"
@@ -50,6 +53,8 @@
#define BT_HCI_TIMEOUT_TAG_NUM 1010000
+using bluetooth::common::MessageLoopThread;
+
extern void hci_initialize();
extern void hci_transmit(BT_HDR* packet);
extern void hci_close();
@@ -70,17 +75,17 @@
} waiting_command_t;
// Using a define here, because it can be stringified for the property lookup
-#define DEFAULT_STARTUP_TIMEOUT_MS 8000
+// Default timeout should be less than BLE_START_TIMEOUT and
+// having less than 3 sec would hold the wakelock for init
+#define DEFAULT_STARTUP_TIMEOUT_MS 2900
#define STRING_VALUE_OF(x) #x
-// RT priority for HCI thread
-static const int BT_HCI_RT_PRIORITY = 1;
-
// Abort if there is no response to an HCI command.
static const uint32_t COMMAND_PENDING_TIMEOUT_MS = 2000;
static const uint32_t COMMAND_PENDING_MUTEX_ACQUIRE_TIMEOUT_MS = 500;
static const uint32_t COMMAND_TIMEOUT_RESTART_MS = 5000;
static const int HCI_UNKNOWN_COMMAND_TIMED_OUT = 0x00ffffff;
+static const int HCI_STARTUP_TIMED_OUT = 0x00eeeeee;
// Our interface
static bool interface_created;
@@ -92,10 +97,7 @@
static const packet_fragmenter_t* packet_fragmenter;
static future_t* startup_future;
-static thread_t* thread; // We own this
-static std::mutex message_loop_mutex;
-static base::MessageLoop* message_loop_ = nullptr;
-static base::RunLoop* run_loop_ = nullptr;
+static MessageLoopThread hci_thread("bt_hci_thread");
static alarm_t* startup_timer;
@@ -111,8 +113,7 @@
static alarm_t* hci_timeout_abort_timer;
// The hand-off point for data going to a higher layer, set by the higher layer
-static base::Callback<void(const tracked_objects::Location&, BT_HDR*)>
- send_data_upwards;
+static base::Callback<void(const base::Location&, BT_HDR*)> send_data_upwards;
static bool filter_incoming_event(BT_HDR* packet);
static waiting_command_t* get_waiting_command(command_opcode_t opcode);
@@ -138,13 +139,10 @@
transmit_fragment, dispatch_reassembled, fragmenter_transmit_finished};
void initialization_complete() {
- std::lock_guard<std::mutex> lock(message_loop_mutex);
- message_loop_->task_runner()->PostTask(
- FROM_HERE, base::Bind(&event_finish_startup, nullptr));
+ hci_thread.DoInThread(FROM_HERE, base::Bind(&event_finish_startup, nullptr));
}
-void hci_event_received(const tracked_objects::Location& from_here,
- BT_HDR* packet) {
+void hci_event_received(const base::Location& from_here, BT_HDR* packet) {
btsnoop->capture(packet, true);
if (!filter_incoming_event(packet)) {
@@ -166,26 +164,6 @@
static future_t* hci_module_shut_down();
-void message_loop_run(UNUSED_ATTR void* context) {
- {
- std::lock_guard<std::mutex> lock(message_loop_mutex);
- message_loop_ = new base::MessageLoop();
- run_loop_ = new base::RunLoop();
- }
-
- message_loop_->task_runner()->PostTask(FROM_HERE,
- base::Bind(&hci_initialize));
- run_loop_->Run();
-
- {
- std::lock_guard<std::mutex> lock(message_loop_mutex);
- delete message_loop_;
- message_loop_ = nullptr;
- delete run_loop_;
- run_loop_ = nullptr;
- }
-}
-
static future_t* hci_module_start_up(void) {
LOG_INFO(LOG_TAG, "%s", __func__);
@@ -196,7 +174,7 @@
command_credits = 1;
// For now, always use the default timeout on non-Android builds.
- period_ms_t startup_timeout_ms = DEFAULT_STARTUP_TIMEOUT_MS;
+ uint64_t startup_timeout_ms = DEFAULT_STARTUP_TIMEOUT_MS;
// Grab the override startup timeout ms, if present.
char timeout_prop[PROPERTY_VALUE_MAX];
@@ -217,13 +195,14 @@
goto error;
}
- thread = thread_new("hci_thread");
- if (!thread) {
- LOG_ERROR(LOG_TAG, "%s unable to create thread.", __func__);
+ hci_thread.StartUp();
+ if (!hci_thread.IsRunning()) {
+ LOG_ERROR(LOG_TAG, "%s unable to start thread.", __func__);
goto error;
}
- if (!thread_set_rt_priority(thread, BT_HCI_RT_PRIORITY)) {
+ if (!hci_thread.EnableRealTimeScheduling()) {
LOG_ERROR(LOG_TAG, "%s unable to make thread RT.", __func__);
+ goto error;
}
commands_pending_response = list_new(NULL);
@@ -242,7 +221,7 @@
packet_fragmenter->init(&packet_fragmenter_callbacks);
- thread_post(thread, message_loop_run, NULL);
+ hci_thread.DoInThread(FROM_HERE, base::Bind(&hci_initialize));
LOG_DEBUG(LOG_TAG, "%s starting async portion", __func__);
return local_startup_future;
@@ -265,16 +244,7 @@
startup_timer = NULL;
}
- {
- std::lock_guard<std::mutex> lock(message_loop_mutex);
- message_loop_->task_runner()->PostTask(FROM_HERE, run_loop_->QuitClosure());
- }
-
- // Stop the thread to prevent Send() calls.
- if (thread) {
- thread_stop(thread);
- thread_join(thread);
- }
+ hci_thread.ShutDown();
// Close HCI to prevent callbacks.
hci_close();
@@ -288,9 +258,6 @@
packet_fragmenter->cleanup();
- thread_free(thread);
- thread = NULL;
-
// Clean up abort timer, if it exists.
if (hci_timeout_abort_timer != NULL) {
alarm_free(hci_timeout_abort_timer);
@@ -316,8 +283,7 @@
// Interface functions
static void set_data_cb(
- base::Callback<void(const tracked_objects::Location&, BT_HDR*)>
- send_data_cb) {
+ base::Callback<void(const base::Location&, BT_HDR*)> send_data_cb) {
send_data_upwards = std::move(send_data_cb);
}
@@ -378,6 +344,9 @@
std::lock_guard<std::recursive_timed_mutex> lock(
commands_pending_response_mutex);
alarm_cancel(startup_timer);
+ if (!startup_future) {
+ return;
+ }
future_ready(startup_future, FUTURE_SUCCESS);
startup_future = NULL;
}
@@ -385,18 +354,8 @@
static void startup_timer_expired(UNUSED_ATTR void* context) {
LOG_ERROR(LOG_TAG, "%s", __func__);
- std::unique_lock<std::recursive_timed_mutex> lock(
- commands_pending_response_mutex, std::defer_lock);
- if (!lock.try_lock_for(std::chrono::milliseconds(
- COMMAND_PENDING_MUTEX_ACQUIRE_TIMEOUT_MS))) {
- LOG_ERROR(LOG_TAG, "%s: Cannot obtain the mutex", __func__);
- // We cannot recover if the startup timer expired and we are deadlock,
- // hence abort.
- abort();
- }
- future_ready(startup_future, FUTURE_FAIL);
- startup_future = NULL;
- lock.unlock();
+ LOG_EVENT_INT(BT_HCI_TIMEOUT_TAG_NUM, HCI_STARTUP_TIMED_OUT);
+ abort();
}
// Command/packet transmitting functions
@@ -405,14 +364,12 @@
std::lock_guard<std::mutex> command_credits_lock(command_credits_mutex);
if (command_credits > 0) {
- std::lock_guard<std::mutex> message_loop_lock(message_loop_mutex);
- if (message_loop_ == nullptr) {
- // HCI Layer was shut down
+ if (!hci_thread.DoInThread(FROM_HERE, std::move(callback))) {
+ // HCI Layer was shut down or not running
buffer_allocator->free(wait_entry->command);
osi_free(wait_entry);
return;
}
- message_loop_->task_runner()->PostTask(FROM_HERE, std::move(callback));
command_credits--;
} else {
command_queue.push(std::move(callback));
@@ -434,14 +391,12 @@
}
static void enqueue_packet(void* packet) {
- std::lock_guard<std::mutex> lock(message_loop_mutex);
- if (message_loop_ == nullptr) {
- // HCI Layer was shut down
+ if (!hci_thread.DoInThread(FROM_HERE,
+ base::Bind(&event_packet_ready, packet))) {
+ // HCI Layer was shut down or not running
buffer_allocator->free(packet);
return;
}
- message_loop_->task_runner()->PostTask(
- FROM_HERE, base::Bind(&event_packet_ready, packet));
}
static void event_packet_ready(void* pkt) {
@@ -519,6 +474,7 @@
}
LOG_EVENT_INT(BT_HCI_TIMEOUT_TAG_NUM, wait_entry->opcode);
+ bluetooth::common::LogHciTimeoutEvent(wait_entry->opcode);
}
}
@@ -531,6 +487,7 @@
COMMAND_PENDING_MUTEX_ACQUIRE_TIMEOUT_MS))) {
LOG_ERROR(LOG_TAG, "%s: Cannot obtain the mutex", __func__);
LOG_EVENT_INT(BT_HCI_TIMEOUT_TAG_NUM, HCI_UNKNOWN_COMMAND_TIMED_OUT);
+ bluetooth::common::LogHciTimeoutEvent(android::bluetooth::hci::CMD_UNKNOWN);
} else {
command_timed_out_log_info(original_wait_entry);
lock.unlock();
@@ -576,19 +533,19 @@
// Event/packet receiving functions
void process_command_credits(int credits) {
std::lock_guard<std::mutex> command_credits_lock(command_credits_mutex);
- std::lock_guard<std::mutex> message_loop_lock(message_loop_mutex);
- if (message_loop_ == nullptr) {
- // HCI Layer was shut down
+ if (!hci_thread.IsRunning()) {
+ // HCI Layer was shut down or not running
return;
}
// Subtract commands in flight.
command_credits = credits - get_num_waiting_commands();
- while (command_credits > 0 && command_queue.size() > 0) {
- message_loop_->task_runner()->PostTask(FROM_HERE,
- std::move(command_queue.front()));
+ while (command_credits > 0 && !command_queue.empty()) {
+ if (!hci_thread.DoInThread(FROM_HERE, std::move(command_queue.front()))) {
+ LOG(ERROR) << __func__ << ": failed to enqueue command";
+ }
command_queue.pop();
command_credits--;
}
diff --git a/hci/src/hci_layer_android.cc b/hci/src/hci_layer_android.cc
index 183b74e..d3fa526 100644
--- a/hci/src/hci_layer_android.cc
+++ b/hci/src/hci_layer_android.cc
@@ -37,23 +37,32 @@
#define LOG_PATH "/data/misc/bluetooth/logs/firmware_events.log"
#define LAST_LOG_PATH "/data/misc/bluetooth/logs/firmware_events.log.last"
-using android::hardware::bluetooth::V1_0::IBluetoothHci;
-using android::hardware::bluetooth::V1_0::IBluetoothHciCallbacks;
-using android::hardware::bluetooth::V1_0::HciPacket;
-using android::hardware::bluetooth::V1_0::Status;
-using android::hardware::ProcessState;
+using ::android::hardware::hidl_death_recipient;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::ProcessState;
using ::android::hardware::Return;
using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
+using ::android::hardware::bluetooth::V1_0::HciPacket;
+using ::android::hardware::bluetooth::V1_0::IBluetoothHci;
+using ::android::hardware::bluetooth::V1_0::IBluetoothHciCallbacks;
+using ::android::hardware::bluetooth::V1_0::Status;
extern void initialization_complete();
-extern void hci_event_received(const tracked_objects::Location& from_here,
- BT_HDR* packet);
+extern void hci_event_received(const base::Location& from_here, BT_HDR* packet);
extern void acl_event_received(BT_HDR* packet);
extern void sco_data_received(BT_HDR* packet);
android::sp<IBluetoothHci> btHci;
+class BluetoothHciDeathRecipient : public hidl_death_recipient {
+ public:
+ virtual void serviceDied(uint64_t /*cookie*/, const android::wp<::android::hidl::base::V1_0::IBase>& /*who*/) {
+ LOG_ERROR(LOG_TAG, "Bluetooth HAL service died!");
+ abort();
+ }
+};
+android::sp<BluetoothHciDeathRecipient> bluetoothHciDeathRecipient = new BluetoothHciDeathRecipient();
+
class BluetoothHciCallbacks : public IBluetoothHciCallbacks {
public:
BluetoothHciCallbacks() {
@@ -74,25 +83,25 @@
return packet;
}
- Return<void> initializationComplete(Status status) {
+ Return<void> initializationComplete(Status status) override {
CHECK(status == Status::SUCCESS);
initialization_complete();
return Void();
}
- Return<void> hciEventReceived(const hidl_vec<uint8_t>& event) {
+ Return<void> hciEventReceived(const hidl_vec<uint8_t>& event) override {
BT_HDR* packet = WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_EVT, event);
hci_event_received(FROM_HERE, packet);
return Void();
}
- Return<void> aclDataReceived(const hidl_vec<uint8_t>& data) {
+ Return<void> aclDataReceived(const hidl_vec<uint8_t>& data) override {
BT_HDR* packet = WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_ACL, data);
acl_event_received(packet);
return Void();
}
- Return<void> scoDataReceived(const hidl_vec<uint8_t>& data) {
+ Return<void> scoDataReceived(const hidl_vec<uint8_t>& data) override {
BT_HDR* packet = WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_SCO, data);
sco_data_received(packet);
return Void();
@@ -107,6 +116,11 @@
btHci = IBluetoothHci::getService();
// If android.hardware.bluetooth* is not found, Bluetooth can not continue.
CHECK(btHci != nullptr);
+ auto death_link = btHci->linkToDeath(bluetoothHciDeathRecipient, 0);
+ if (!death_link.isOk()) {
+ LOG_ERROR(LOG_TAG, "%s: Unable to set the death recipient for the Bluetooth HAL", __func__);
+ abort();
+ }
LOG_INFO(LOG_TAG, "%s: IBluetoothHci::getService() returned %p (%s)",
__func__, btHci.get(), (btHci->isRemote() ? "remote" : "local"));
@@ -118,6 +132,12 @@
}
void hci_close() {
+ if (btHci != nullptr) {
+ auto death_unlink = btHci->unlinkToDeath(bluetoothHciDeathRecipient);
+ if (!death_unlink.isOk()) {
+ LOG_ERROR(LOG_TAG, "%s: Error unlinking death recipient from the Bluetooth HAL", __func__);
+ }
+ }
btHci->close();
btHci = nullptr;
}
diff --git a/hci/src/hci_layer_linux.cc b/hci/src/hci_layer_linux.cc
index e32b5ef..01ff5af 100644
--- a/hci/src/hci_layer_linux.cc
+++ b/hci/src/hci_layer_linux.cc
@@ -93,8 +93,7 @@
};
extern void initialization_complete();
-extern void hci_event_received(const tracked_objects::Location& from_here,
- BT_HDR* packet);
+extern void hci_event_received(const base::Location& from_here, BT_HDR* packet);
extern void acl_event_received(BT_HDR* packet);
extern void sco_data_received(BT_HDR* packet);
@@ -204,12 +203,12 @@
addr.hci_dev = hci_interface;
addr.hci_channel = HCI_CHANNEL_USER;
if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
- LOG(FATAL) << "socket bind error " << strerror(errno);
+ PLOG(FATAL) << "socket bind error";
}
int sv[2];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) {
- LOG(FATAL) << "socketpair failed: " << strerror(errno);
+ PLOG(FATAL) << "socketpair failed";
}
reader_thread_ctrl_fd = sv[0];
@@ -246,7 +245,7 @@
}
void hci_transmit(BT_HDR* packet) {
- uint8_t type;
+ uint8_t type = 0;
CHECK(bt_vendor_fd != -1);
@@ -275,7 +274,7 @@
if (ret != packet->len + 1) LOG(ERROR) << "Should have send whole packet";
- if (ret == -1) LOG(FATAL) << strerror(errno);
+ if (ret == -1) PLOG(FATAL) << "write failed";
}
static int wait_hcidev(void) {
@@ -289,7 +288,7 @@
fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
if (fd < 0) {
- LOG(ERROR) << "Bluetooth socket error: %s" << strerror(errno);
+ PLOG(ERROR) << "Bluetooth socket error";
return -1;
}
@@ -299,7 +298,7 @@
addr.hci_channel = HCI_CHANNEL_CONTROL;
if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
- LOG(ERROR) << "HCI Channel Control: " << strerror(errno);
+ PLOG(ERROR) << "HCI Channel Control";
close(fd);
return -1;
}
@@ -315,7 +314,7 @@
ssize_t wrote;
OSI_NO_INTR(wrote = write(fd, &ev, 6));
if (wrote != 6) {
- LOG(ERROR) << "Unable to write mgmt command: " << strerror(errno);
+ PLOG(ERROR) << "Unable to write mgmt command";
ret = -1;
goto end;
}
@@ -324,7 +323,7 @@
int n;
OSI_NO_INTR(n = poll(fds, 1, MGMT_EV_POLL_TIMEOUT));
if (n == -1) {
- LOG(ERROR) << "Poll error: " << strerror(errno);
+ PLOG(ERROR) << "Poll error";
ret = -1;
break;
} else if (n == 0) {
@@ -336,7 +335,7 @@
if (fds[0].revents & POLLIN) {
OSI_NO_INTR(n = read(fd, &ev, sizeof(struct mgmt_pkt)));
if (n < 0) {
- LOG(ERROR) << "Error reading control channel: " << strerror(errno);
+ PLOG(ERROR) << "Error reading control channel";
ret = -1;
break;
}
diff --git a/hci/test/packet_fragmenter_test.cc b/hci/test/packet_fragmenter_test.cc
index 483a66d..ca83dfa 100644
--- a/hci/test/packet_fragmenter_test.cc
+++ b/hci/test/packet_fragmenter_test.cc
@@ -291,7 +291,7 @@
class PacketFragmenterTest : public AllocationTestHarness {
protected:
- virtual void SetUp() {
+ void SetUp() override {
AllocationTestHarness::SetUp();
fragmenter =
packet_fragmenter_get_test_interface(&controller, &allocator_malloc);
@@ -309,7 +309,7 @@
fragmenter->init(&callbacks);
}
- virtual void TearDown() {
+ void TearDown() override {
fragmenter->cleanup();
AllocationTestHarness::TearDown();
}
diff --git a/include/hardware/avrcp/avrcp.h b/include/hardware/avrcp/avrcp.h
index 8adba47..577acb9 100644
--- a/include/hardware/avrcp/avrcp.h
+++ b/include/hardware/avrcp/avrcp.h
@@ -19,7 +19,7 @@
#include <set>
#include <string>
-#include <base/bind.h>
+#include <base/callback_forward.h>
#include "avrcp_common.h"
#include "raw_address.h"
@@ -72,10 +72,11 @@
class MediaCallbacks {
public:
- virtual void SendMediaUpdate(bool track_changed, bool play_state, bool queue);
+ virtual void SendMediaUpdate(bool track_changed, bool play_state,
+ bool queue) = 0;
virtual void SendFolderUpdate(bool available_players, bool addressed_players,
- bool uids_changed);
- virtual void SendActiveDeviceChanged(const RawAddress& address);
+ bool uids_changed) = 0;
+ virtual void SendActiveDeviceChanged(const RawAddress& address) = 0;
virtual ~MediaCallbacks() = default;
};
diff --git a/include/hardware/bluetooth.h b/include/hardware/bluetooth.h
index 36680bf..f97e116 100644
--- a/include/hardware/bluetooth.h
+++ b/include/hardware/bluetooth.h
@@ -38,7 +38,6 @@
#define BT_PROFILE_HANDSFREE_CLIENT_ID "handsfree_client"
#define BT_PROFILE_ADVANCED_AUDIO_ID "a2dp"
#define BT_PROFILE_ADVANCED_AUDIO_SINK_ID "a2dp_sink"
-#define BT_PROFILE_HEALTH_ID "health"
#define BT_PROFILE_SOCKETS_ID "socket"
#define BT_PROFILE_HIDHOST_ID "hidhost"
#define BT_PROFILE_HIDDEV_ID "hiddev"
@@ -50,9 +49,6 @@
#define BT_PROFILE_AV_RC_CTRL_ID "avrcp_ctrl"
#define BT_PROFILE_HEARING_AID_ID "hearing_aid"
-/** Bluetooth test interface IDs */
-#define BT_TEST_INTERFACE_MCAP_ID "mcap_test"
-
/** Bluetooth Device Name */
typedef struct { uint8_t name[249]; } __attribute__((packed)) bt_bdname_t;
@@ -66,6 +62,18 @@
/** Bluetooth Adapter State */
typedef enum { BT_STATE_OFF, BT_STATE_ON } bt_state_t;
+/** Bluetooth Adapter Input Output Capabilities which determine Pairing/Security
+ */
+typedef enum {
+ BT_IO_CAP_OUT, /* DisplayOnly */
+ BT_IO_CAP_IO, /* DisplayYesNo */
+ BT_IO_CAP_IN, /* KeyboardOnly */
+ BT_IO_CAP_NONE, /* NoInputNoOutput */
+ BT_IO_CAP_KBDISP, /* Keyboard display */
+ BT_IO_CAP_MAX,
+ BT_IO_CAP_UNKNOWN = 0xFF /* Unknown value */
+} bt_io_cap_t;
+
/** Bluetooth Error Status */
/** We need to build on this */
@@ -240,6 +248,20 @@
*/
BT_PROPERTY_LOCAL_LE_FEATURES,
+ /**
+ * Description - Local Input/Output Capabilities for classic Bluetooth
+ * Access mode - GET and SET
+ * Data Type - bt_io_cap_t.
+ */
+ BT_PROPERTY_LOCAL_IO_CAPS,
+
+ /**
+ * Description - Local Input/Output Capabilities for BLE
+ * Access mode - GET and SET
+ * Data Type - bt_io_cap_t.
+ */
+ BT_PROPERTY_LOCAL_IO_CAPS_BLE,
+
BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP = 0xFF,
} bt_property_type_t;
@@ -590,6 +612,14 @@
* Get the AvrcpTarget Service interface to interact with the Avrcp Service
*/
bluetooth::avrcp::ServiceInterface* (*get_avrcp_service)(void);
+
+ /**
+ * Obfuscate Bluetooth MAC address into a PII free ID string
+ *
+ * @param address Bluetooth MAC address to be obfuscated
+ * @return a string of uint8_t that is unique to this MAC address
+ */
+ std::string (*obfuscate_address)(const RawAddress& address);
} bt_interface_t;
#define BLUETOOTH_INTERFACE_STRING "bluetoothInterface"
diff --git a/include/hardware/bluetooth_headset_interface.h b/include/hardware/bluetooth_headset_interface.h
index a3e0e37..8527919 100644
--- a/include/hardware/bluetooth_headset_interface.h
+++ b/include/hardware/bluetooth_headset_interface.h
@@ -195,6 +195,7 @@
* @param call_setup_state current call setup state
* @param number phone number of the call
* @param type type of the call
+ * @param name caller display name
* @param bd_addr remote device address
* @return BT_STATUS_SUCCESS on success
*/
@@ -202,6 +203,7 @@
bthf_call_state_t call_setup_state,
const char* number,
bthf_call_addrtype_t type,
+ const char* name,
RawAddress* bd_addr) = 0;
/**
diff --git a/include/hardware/bt_av.h b/include/hardware/bt_av.h
index bdb1285..d38beaa 100644
--- a/include/hardware/bt_av.h
+++ b/include/hardware/bt_av.h
@@ -62,6 +62,7 @@
// Add an entry for each sink codec here
BTAV_A2DP_CODEC_INDEX_SINK_SBC = BTAV_A2DP_CODEC_INDEX_SINK_MIN,
BTAV_A2DP_CODEC_INDEX_SINK_AAC,
+ BTAV_A2DP_CODEC_INDEX_SINK_LDAC,
BTAV_A2DP_CODEC_INDEX_SINK_MAX,
@@ -154,6 +155,9 @@
case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
codec_name_str = "AAC (Sink)";
break;
+ case BTAV_A2DP_CODEC_INDEX_SINK_LDAC:
+ codec_name_str = "LDAC (Sink)";
+ break;
case BTAV_A2DP_CODEC_INDEX_MAX:
codec_name_str = "Unknown(CODEC_INDEX_MAX)";
break;
@@ -309,6 +313,9 @@
/** dis-connect from headset */
bt_status_t (*disconnect)(const RawAddress& bd_addr);
+ /** sets the connected device silence state */
+ bt_status_t (*set_silence_device)(const RawAddress& bd_addr, bool silence);
+
/** sets the connected device as active */
bt_status_t (*set_active_device)(const RawAddress& bd_addr);
diff --git a/include/hardware/bt_hearing_aid.h b/include/hardware/bt_hearing_aid.h
index 7ab0dc7..1911159 100644
--- a/include/hardware/bt_hearing_aid.h
+++ b/include/hardware/bt_hearing_aid.h
@@ -62,9 +62,6 @@
/** Add a hearing aid device to white list */
virtual void AddToWhiteList(const RawAddress& address) = 0;
- /** Remove a hearing aid device from white list */
- virtual void RemoveFromWhiteList(const RawAddress& address) = 0;
-
/** Set the volume */
virtual void SetVolume(int8_t volume) = 0;
diff --git a/include/hardware/bt_hl.h b/include/hardware/bt_hl.h
deleted file mode 100644
index 682605b..0000000
--- a/include/hardware/bt_hl.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-#ifndef ANDROID_INCLUDE_BT_HL_H
-#define ANDROID_INCLUDE_BT_HL_H
-
-__BEGIN_DECLS
-
-/* HL connection states */
-
-typedef enum { BTHL_MDEP_ROLE_SOURCE, BTHL_MDEP_ROLE_SINK } bthl_mdep_role_t;
-
-typedef enum {
- BTHL_APP_REG_STATE_REG_SUCCESS,
- BTHL_APP_REG_STATE_REG_FAILED,
- BTHL_APP_REG_STATE_DEREG_SUCCESS,
- BTHL_APP_REG_STATE_DEREG_FAILED
-} bthl_app_reg_state_t;
-
-typedef enum {
- BTHL_CHANNEL_TYPE_RELIABLE,
- BTHL_CHANNEL_TYPE_STREAMING,
- BTHL_CHANNEL_TYPE_ANY
-} bthl_channel_type_t;
-
-/* HL connection states */
-typedef enum {
- BTHL_CONN_STATE_CONNECTING,
- BTHL_CONN_STATE_CONNECTED,
- BTHL_CONN_STATE_DISCONNECTING,
- BTHL_CONN_STATE_DISCONNECTED,
- BTHL_CONN_STATE_DESTROYED
-} bthl_channel_state_t;
-
-typedef struct {
- bthl_mdep_role_t mdep_role;
- int data_type;
- bthl_channel_type_t channel_type;
- const char* mdep_description; /* MDEP description to be used in the SDP
- (optional); null terminated */
-} bthl_mdep_cfg_t;
-
-typedef struct {
- const char* application_name;
- const char*
- provider_name; /* provider name to be used in the SDP (optional); null
- terminated */
- const char* srv_name; /* service name to be used in the SDP (optional); null
- terminated*/
- const char*
- srv_desp; /* service description to be used in the SDP (optional); null
- terminated */
- int number_of_mdeps;
- bthl_mdep_cfg_t* mdep_cfg; /* Dynamic array */
-} bthl_reg_param_t;
-
-/** Callback for application registration status.
- * state will have one of the values from bthl_app_reg_state_t
- */
-typedef void (*bthl_app_reg_state_callback)(int app_id,
- bthl_app_reg_state_t state);
-
-/** Callback for channel connection state change.
- * state will have one of the values from
- * bthl_connection_state_t and fd (file descriptor)
- */
-typedef void (*bthl_channel_state_callback)(int app_id, RawAddress* bd_addr,
- int mdep_cfg_index, int channel_id,
- bthl_channel_state_t state, int fd);
-
-/** BT-HL callback structure. */
-typedef struct {
- /** set to sizeof(bthl_callbacks_t) */
- size_t size;
- bthl_app_reg_state_callback app_reg_state_cb;
- bthl_channel_state_callback channel_state_cb;
-} bthl_callbacks_t;
-
-/** Represents the standard BT-HL interface. */
-typedef struct {
- /** set to sizeof(bthl_interface_t) */
- size_t size;
-
- /**
- * Register the Bthl callbacks
- */
- bt_status_t (*init)(bthl_callbacks_t* callbacks);
-
- /** Register HL application */
- bt_status_t (*register_application)(bthl_reg_param_t* p_reg_param,
- int* app_id);
-
- /** Unregister HL application */
- bt_status_t (*unregister_application)(int app_id);
-
- /** connect channel */
- bt_status_t (*connect_channel)(int app_id, RawAddress* bd_addr,
- int mdep_cfg_index, int* channel_id);
-
- /** destroy channel */
- bt_status_t (*destroy_channel)(int channel_id);
-
- /** Close the Bthl callback **/
- void (*cleanup)(void);
-
-} bthl_interface_t;
-__END_DECLS
-
-#endif /* ANDROID_INCLUDE_BT_HL_H */
diff --git a/include/hardware/bt_rc.h b/include/hardware/bt_rc.h
index 9349eed..dc46eca 100644
--- a/include/hardware/bt_rc.h
+++ b/include/hardware/bt_rc.h
@@ -613,6 +613,11 @@
uint8_t depth);
typedef void (*btrc_ctrl_set_addressed_player_callback)(
const RawAddress& bd_addr, uint8_t status);
+typedef void (*btrc_ctrl_addressed_player_changed_callback)(
+ const RawAddress& bd_addr, uint16_t id);
+typedef void (*btrc_ctrl_now_playing_contents_changed_callback)(
+ const RawAddress& bd_addr);
+
/** BT-RC Controller callback structure. */
typedef struct {
/** set to sizeof(BtRcCallbacks) */
@@ -635,6 +640,9 @@
btrc_ctrl_change_path_callback change_folder_path_cb;
btrc_ctrl_set_browsed_player_callback set_browsed_player_cb;
btrc_ctrl_set_addressed_player_callback set_addressed_player_cb;
+ btrc_ctrl_addressed_player_changed_callback addressed_player_changed_cb;
+ btrc_ctrl_now_playing_contents_changed_callback
+ now_playing_contents_changed_cb;
} btrc_ctrl_callbacks_t;
/** Represents the standard BT-RC AVRCP Controller interface. */
diff --git a/internal_include/Android.bp b/internal_include/Android.bp
index 3ef202b..e550660 100644
--- a/internal_include/Android.bp
+++ b/internal_include/Android.bp
@@ -3,4 +3,4 @@
export_include_dirs: ["./"],
vendor_available: true,
host_supported: true,
-}
\ No newline at end of file
+}
diff --git a/internal_include/bt_target.h b/internal_include/bt_target.h
index cf09b15..67a67c5 100644
--- a/internal_include/bt_target.h
+++ b/internal_include/bt_target.h
@@ -275,9 +275,8 @@
#define BTM_NO_SSP_ON_INQUIRY FALSE
#endif
-/* Includes SCO if TRUE */
-#ifndef BTM_SCO_INCLUDED
-#define BTM_SCO_INCLUDED TRUE /* TRUE includes SCO code */
+#ifndef DISABLE_WBS
+#define DISABLE_WBS FALSE
#endif
/* This is used to work around a controller bug that doesn't like Disconnect
@@ -349,7 +348,7 @@
/* The number of SCO links. */
#ifndef BTM_MAX_SCO_LINKS
-#define BTM_MAX_SCO_LINKS 3
+#define BTM_MAX_SCO_LINKS 6
#endif
/* The number of security records for peer devices. */
@@ -405,14 +404,8 @@
#define BTM_PM_DEBUG FALSE
#endif
-/* This is set to TRUE if link is to be unparked due to BTM_CreateSCO API. */
-#ifndef BTM_SCO_WAKE_PARKED_LINK
-#define BTM_SCO_WAKE_PARKED_LINK TRUE
-#endif
-
/* If the user does not respond to security process requests within this many
- * seconds,
- * a negative response would be sent automatically.
+ * seconds, a negative response would be sent automatically.
* 30 is LMP response timeout value */
#ifndef BTM_SEC_TIMEOUT_VALUE
#define BTM_SEC_TIMEOUT_VALUE 35
@@ -662,6 +655,11 @@
#define GATT_MAX_APPS 32 /* note: 2 apps used internally GATT and GAP */
#endif
+/* connection manager doesn't generate it's own IDs. Instead, all GATT clients
+ * use their gatt_if to identify against conection manager. When stack tries to
+ * create l2cap connection, it will use this fixed ID. */
+#define CONN_MGR_ID_L2CAP (GATT_MAX_APPS + 10)
+
#ifndef GATT_MAX_PHY_CHANNEL
#define GATT_MAX_PHY_CHANNEL 7
#endif
@@ -1228,118 +1226,6 @@
/******************************************************************************
*
- * MCAP
- *
- *****************************************************************************/
-#ifndef MCA_INCLUDED
-#define MCA_INCLUDED FALSE
-#endif
-
-/* The MTU size for the L2CAP configuration on control channel. 48 is the
- * minimal */
-#ifndef MCA_CTRL_MTU
-#define MCA_CTRL_MTU 60
-#endif
-
-/* The maximum number of registered MCAP instances. */
-#ifndef MCA_NUM_REGS
-#define MCA_NUM_REGS 12
-#endif
-
-/* The maximum number of control channels (to difference devices) per registered
- * MCAP instances. */
-#ifndef MCA_NUM_LINKS
-#define MCA_NUM_LINKS 3
-#endif
-
-/* The maximum number of MDEP (including HDP echo) per registered MCAP
- * instances. */
-#ifndef MCA_NUM_DEPS
-#define MCA_NUM_DEPS 13
-#endif
-
-/* The maximum number of MDL link per control channel. */
-#ifndef MCA_NUM_MDLS
-#define MCA_NUM_MDLS 4
-#endif
-
-/* Buffer size to reassemble the SDU. */
-#ifndef MCA_USER_RX_BUF_SIZE
-#define MCA_USER_RX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
-#endif
-
-/* Buffer size to hold the SDU. */
-#ifndef MCA_USER_TX_BUF_SIZE
-#define MCA_USER_TX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
-#endif
-
-/*
- * Buffer size used to hold MPS segments during SDU reassembly
- */
-#ifndef MCA_FCR_RX_BUF_SIZE
-#define MCA_FCR_RX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
-#endif
-
-/*
- * Default buffer size used to hold MPS segments used in (re)transmissions.
- * The size of each buffer must be able to hold the maximum MPS segment size
- * passed in tL2CAP_FCR_OPTIONS plus BT_HDR (8) + HCI preamble (4) +
- * L2CAP_MIN_OFFSET (11 - as of BT 2.1 + EDR Spec).
- */
-#ifndef MCA_FCR_TX_BUF_SIZE
-#define MCA_FCR_TX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
-#endif
-
-/* MCAP control channel FCR Option:
-Size of the transmission window when using enhanced retransmission mode.
-1 is defined by HDP specification for control channel.
-*/
-#ifndef MCA_FCR_OPT_TX_WINDOW_SIZE
-#define MCA_FCR_OPT_TX_WINDOW_SIZE 1
-#endif
-
-/* MCAP control channel FCR Option:
-Number of transmission attempts for a single I-Frame before taking
-Down the connection. Used In ERTM mode only. Value is Ignored in basic and
-Streaming modes.
-Range: 0, 1-0xFF
-0 - infinite retransmissions
-1 - single transmission
-*/
-#ifndef MCA_FCR_OPT_MAX_TX_B4_DISCNT
-#define MCA_FCR_OPT_MAX_TX_B4_DISCNT 20
-#endif
-
-/* MCAP control channel FCR Option: Retransmission Timeout
-The AVRCP specification set a value in the range of 300 - 2000 ms
-Timeout (in msecs) to detect Lost I-Frames. Only used in Enhanced retransmission
-mode.
-Range: Minimum 2000 (2 secs) when supporting PBF.
- */
-#ifndef MCA_FCR_OPT_RETX_TOUT
-#define MCA_FCR_OPT_RETX_TOUT 2000
-#endif
-
-/* MCAP control channel FCR Option: Monitor Timeout
-The AVRCP specification set a value in the range of 300 - 2000 ms
-Timeout (in msecs) to detect Lost S-Frames. Only used in Enhanced retransmission
-mode.
-Range: Minimum 12000 (12 secs) when supporting PBF.
-*/
-#ifndef MCA_FCR_OPT_MONITOR_TOUT
-#define MCA_FCR_OPT_MONITOR_TOUT 12000
-#endif
-
-/* MCAP control channel FCR Option: Maximum PDU payload size.
-The maximum number of payload octets that the local device can receive in a
-single PDU.
-*/
-#ifndef MCA_FCR_OPT_MPS_SIZE
-#define MCA_FCR_OPT_MPS_SIZE 1000
-#endif
-
-/******************************************************************************
- *
* BTA
*
*****************************************************************************/
diff --git a/internal_include/bt_trace.h b/internal_include/bt_trace.h
index 97c761b..f27563d 100644
--- a/internal_include/bt_trace.h
+++ b/internal_include/bt_trace.h
@@ -66,7 +66,7 @@
#define BTTRC_ID_STK_SPP 39
#define BTTRC_ID_STK_TCS 40
#define BTTRC_ID_STK_VDP 41
-#define BTTRC_ID_STK_MCAP 42
+#define BTTRC_ID_STK_MCAP 42 /* OBSOLETE */
#define BTTRC_ID_STK_GATT 43
#define BTTRC_ID_STK_SMP 44
#define BTTRC_ID_STK_NFC 45
@@ -182,10 +182,6 @@
#define AVRC_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
#endif
-#ifndef MCA_INITIAL_TRACE_LEVEL
-#define MCA_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
-#endif
-
#ifndef HID_INITIAL_TRACE_LEVEL
#define HID_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
#endif
@@ -556,33 +552,6 @@
BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_API, ##__VA_ARGS__); \
}
-/* MCAP */
-#define MCA_TRACE_ERROR(...) \
- { \
- if (mca_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
- BT_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
- }
-#define MCA_TRACE_WARNING(...) \
- { \
- if (mca_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \
- BT_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
- }
-#define MCA_TRACE_EVENT(...) \
- { \
- if (mca_cb.trace_level >= BT_TRACE_LEVEL_EVENT) \
- BT_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
- }
-#define MCA_TRACE_DEBUG(...) \
- { \
- if (mca_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) \
- BT_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
- }
-#define MCA_TRACE_API(...) \
- { \
- if (mca_cb.trace_level >= BT_TRACE_LEVEL_API) \
- BT_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_API, ##__VA_ARGS__); \
- }
-
/* Define tracing for the SMP unit */
#define SMP_TRACE_ERROR(...) \
{ \
@@ -729,7 +698,7 @@
#include <base/logging.h>
-/* Prints intergral parameter x as hex string, with '0' fill */
+/* Prints integral parameter x as hex string, with '0' fill */
template <typename T>
std::string loghex(T x) {
static_assert(std::is_integral<T>::value,
@@ -740,6 +709,19 @@
return tmp.str();
}
+/* Prints integral array as hex string, with '0' fill */
+template <typename T, size_t N>
+std::string loghex(std::array<T, N> array) {
+ static_assert(std::is_integral<T>::value,
+ "type stored in array must be integral.");
+ std::stringstream tmp;
+ for (const auto& x : array) {
+ tmp << std::internal << std::hex << std::setfill('0')
+ << std::setw((sizeof(uint8_t) * 2) + 2) << +x;
+ }
+ return tmp.str();
+}
+
/**
* Obtains the string representation of a boolean value.
*
@@ -771,4 +753,53 @@
return *p_result;
}
+// This object puts the stream in a state where every time that a new line
+// occurs, the next line is indented a certain number of spaces. The stream is
+// reset to its previous state when the object is destroyed.
+class ScopedIndent {
+ public:
+ ScopedIndent(std::ostream& stream, int indent_size = DEFAULT_TAB)
+ : indented_buf_(stream, indent_size) {
+ old_stream_ = &stream;
+ old_stream_buf_ = stream.rdbuf();
+ stream.rdbuf(&indented_buf_);
+ }
+
+ ~ScopedIndent() { old_stream_->rdbuf(old_stream_buf_); }
+
+ static const size_t DEFAULT_TAB = 2;
+
+ private:
+ class IndentedStreamBuf : public std::streambuf {
+ public:
+ IndentedStreamBuf(std::ostream& stream, int indent_size)
+ : wrapped_buf_(stream.rdbuf()),
+ indent_size_(indent_size),
+ indent_next_line_(true){};
+
+ protected:
+ virtual int overflow(int character) override {
+ if (indent_next_line_ && character != '\n') {
+ for (int i = 0; i < indent_size_; i++) wrapped_buf_->sputc(' ');
+ }
+
+ indent_next_line_ = false;
+ if (character == '\n') {
+ indent_next_line_ = true;
+ }
+
+ return wrapped_buf_->sputc(character);
+ }
+
+ private:
+ std::streambuf* wrapped_buf_;
+ int indent_size_;
+ bool indent_next_line_;
+ };
+
+ std::ostream* old_stream_;
+ std::streambuf* old_stream_buf_;
+ IndentedStreamBuf indented_buf_;
+};
+
#endif
diff --git a/linux_include/log/log.h b/linux_include/log/log.h
new file mode 100644
index 0000000..2802f77
--- /dev/null
+++ b/linux_include/log/log.h
@@ -0,0 +1,33 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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
+
+/* This file provides empty implementation of android_errorWriteLog, which is
+ * not required on linux. It should be on include path only for linux build. */
+
+#if defined(OS_GENERIC)
+
+#include <cstdint>
+
+inline int android_errorWriteLog(int, const char*) { return 0; };
+inline int android_errorWriteWithInfoLog(int tag, const char* subTag,
+ int32_t uid, const char* data,
+ uint32_t dataLen) {
+ return 0;
+};
+#endif
diff --git a/main/Android.bp b/main/Android.bp
index 04d8ca6..f90d89d 100644
--- a/main/Android.bp
+++ b/main/Android.bp
@@ -1,4 +1,3 @@
-
// Bluetooth main HW module / shared library for target
// ========================================================
cc_library_shared {
@@ -40,18 +39,21 @@
shared_libs: [
"android.hardware.bluetooth@1.0",
"android.hardware.bluetooth.a2dp@1.0",
+ "android.hardware.bluetooth.audio@2.0",
"libaudioclient",
"libcutils",
"libdl",
+ "libfmq",
"libhidlbase",
"libhidltransport",
"libhwbinder",
"liblog",
+ "libprocessgroup",
"libprotobuf-cpp-lite",
"libutils",
"libtinyxml2",
"libz",
- "libstatslog",
+ "libcrypto",
],
static_libs: [
"libbt-sbc-decoder",
@@ -62,6 +64,7 @@
],
whole_static_libs: [
"libbt-bta",
+ "libbt-common",
"libbtdevice",
"libbtif",
"libbt-hci",
diff --git a/main/BUILD.gn b/main/BUILD.gn
index 2a07d7b..8152e3b 100644
--- a/main/BUILD.gn
+++ b/main/BUILD.gn
@@ -70,9 +70,11 @@
"//btcore",
"//btif",
"//device",
+ "//embdrv/g722",
"//embdrv/sbc",
"//hci",
"//osi",
+ "//packet",
"//stack",
"//third_party/libchrome:base",
"//third_party/tinyxml2",
diff --git a/main/bte_init.cc b/main/bte_init.cc
index afbd6bf..7addb18 100644
--- a/main/bte_init.cc
+++ b/main/bte_init.cc
@@ -48,10 +48,6 @@
#include "hidh_api.h"
#endif
-#if (MCA_INCLUDED == TRUE)
-#include "mca_api.h"
-#endif
-
#include "gatt_api.h"
#include "smp_api.h"
@@ -104,8 +100,4 @@
#if (HID_HOST_INCLUDED == TRUE)
HID_HostInit();
#endif
-
-#if (MCA_INCLUDED == TRUE)
- MCA_Init();
-#endif
}
diff --git a/main/bte_logmsg.cc b/main/bte_logmsg.cc
index 3ccb64d..22c357d 100644
--- a/main/bte_logmsg.cc
+++ b/main/bte_logmsg.cc
@@ -71,15 +71,55 @@
/* LayerIDs for BTA, currently everything maps onto appl_trace_level */
static const char* const bt_layer_tags[] = {
- "bt_btif", "bt_usb", "bt_serial", "bt_socket", "bt_rs232", "bt_lc",
- "bt_lm", "bt_hci", "bt_l2cap", "bt_rfcomm", "bt_sdp", "bt_tcs",
- "bt_obex", "bt_btm", "bt_gap", "UNUSED", "UNUSED", "bt_icp",
- "bt_hsp2", "bt_spp", "bt_ctp", "bt_bpp", "bt_hcrp", "bt_ftp",
- "bt_opp", "bt_btu", "bt_gki", /* OBSOLETED */
- "bt_bnep", "bt_pan", "bt_hfp", "bt_hid", "bt_bip", "bt_avp",
- "bt_a2d", "bt_sap", "bt_amp", "bt_mca", "bt_att", "bt_smp",
- "bt_nfc", "bt_nci", "bt_idep", "bt_ndep", "bt_llcp", "bt_rw",
- "bt_ce", "bt_snep", "bt_ndef", "bt_nfa",
+ "bt_btif",
+ "bt_usb",
+ "bt_serial",
+ "bt_socket",
+ "bt_rs232",
+ "bt_lc",
+ "bt_lm",
+ "bt_hci",
+ "bt_l2cap",
+ "bt_rfcomm",
+ "bt_sdp",
+ "bt_tcs",
+ "bt_obex",
+ "bt_btm",
+ "bt_gap",
+ "UNUSED",
+ "UNUSED",
+ "bt_icp",
+ "bt_hsp2",
+ "bt_spp",
+ "bt_ctp",
+ "bt_bpp",
+ "bt_hcrp",
+ "bt_ftp",
+ "bt_opp",
+ "bt_btu",
+ "bt_gki_deprecated",
+ "bt_bnep",
+ "bt_pan",
+ "bt_hfp",
+ "bt_hid",
+ "bt_bip",
+ "bt_avp",
+ "bt_a2d",
+ "bt_sap",
+ "bt_amp",
+ "bt_mca_deprecated",
+ "bt_att",
+ "bt_smp",
+ "bt_nfc",
+ "bt_nci",
+ "bt_idep",
+ "bt_ndep",
+ "bt_llcp",
+ "bt_rw",
+ "bt_ce",
+ "bt_snep",
+ "bt_ndef",
+ "bt_nfa",
};
static uint8_t BTAPP_SetTraceLevel(uint8_t new_level);
static uint8_t BTIF_SetTraceLevel(uint8_t new_level);
diff --git a/main/bte_main.cc b/main/bte_main.cc
index 7fdeef03..0498439 100644
--- a/main/bte_main.cc
+++ b/main/bte_main.cc
@@ -53,7 +53,6 @@
#include "osi/include/future.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
-#include "osi/include/thread.h"
#include "stack_config.h"
/*******************************************************************************
@@ -92,22 +91,17 @@
*
* Function post_to_hci_message_loop
*
- * Description Post an HCI event to the hci message queue
+ * Description Post an HCI event to the main thread
*
* Returns None
*
*****************************************************************************/
-void post_to_hci_message_loop(const tracked_objects::Location& from_here,
- BT_HDR* p_msg) {
- base::MessageLoop* hci_message_loop = get_message_loop();
- if (!hci_message_loop || !hci_message_loop->task_runner().get()) {
- LOG_ERROR(LOG_TAG, "%s: HCI message loop not running, accessed from %s",
- __func__, from_here.ToString().c_str());
- return;
+void post_to_main_message_loop(const base::Location& from_here, BT_HDR* p_msg) {
+ if (do_in_main_thread(from_here, base::Bind(&btu_hci_msg_process, p_msg)) !=
+ BT_STATUS_SUCCESS) {
+ LOG(ERROR) << __func__ << ": do_in_main_thread failed from "
+ << from_here.ToString();
}
-
- hci_message_loop->task_runner()->PostTask(
- from_here, base::Bind(&btu_hci_msg_process, p_msg));
}
/******************************************************************************
@@ -128,7 +122,7 @@
return;
}
- hci->set_data_cb(base::Bind(&post_to_hci_message_loop));
+ hci->set_data_cb(base::Bind(&post_to_main_message_loop));
module_init(get_module(STACK_CONFIG_MODULE));
}
diff --git a/osi/Android.bp b/osi/Android.bp
index ad2f44b..bcdaf5f 100644
--- a/osi/Android.bp
+++ b/osi/Android.bp
@@ -6,7 +6,7 @@
"system/bt/internal_include",
"system/bt/utils/include",
"system/bt/stack/include",
- ]
+ ],
}
// Static libraries required by other modules
@@ -19,7 +19,7 @@
],
host_supported: true,
shared: {
- enabled: false
+ enabled: false,
},
}
@@ -31,7 +31,7 @@
],
host_supported: true,
shared: {
- enabled: false
+ enabled: false,
},
}
@@ -54,7 +54,6 @@
"src/future.cc",
"src/hash_map_utils.cc",
"src/list.cc",
- "src/metrics.cc",
"src/mutex.cc",
"src/osi.cc",
"src/properties.cc",
@@ -65,7 +64,6 @@
"src/socket_utils/socket_local_client.cc",
"src/socket_utils/socket_local_server.cc",
"src/thread.cc",
- "src/time.cc",
"src/wakelock.cc",
],
shared_libs: [
@@ -104,24 +102,23 @@
"test/fixed_queue_test.cc",
"test/future_test.cc",
"test/hash_map_utils_test.cc",
- "test/leaky_bonded_queue_test.cc",
"test/list_test.cc",
- "test/metrics_test.cc",
"test/properties_test.cc",
"test/rand_test.cc",
"test/reactor_test.cc",
"test/ringbuffer_test.cc",
"test/semaphore_test.cc",
"test/thread_test.cc",
- "test/time_test.cc",
"test/wakelock_test.cc",
],
shared_libs: [
"liblog",
"libprotobuf-cpp-lite",
"libcutils",
+ "libcrypto",
],
static_libs: [
+ "libbt-common",
"libbt-protos-lite",
"libgmock",
"libosi",
diff --git a/osi/AndroidTest.xml b/osi/AndroidTest.xml
deleted file mode 100644
index aa723bb..0000000
--- a/osi/AndroidTest.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2017 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.
--->
-<configuration description="Config for net_test_osi">
- <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
- <option name="cleanup" value="true" />
- <option name="push" value="net_test_osi->/data/local/tmp/net_test_osi" />
- </target_preparer>
- <option name="test-suite-tag" value="apct" />
- <test class="com.android.tradefed.testtype.GTest" >
- <option name="native-test-device-path" value="/data/local/tmp" />
- <option name="module-name" value="net_test_osi" />
- </test>
-</configuration>
\ No newline at end of file
diff --git a/osi/BUILD.gn b/osi/BUILD.gn
index 93b74cc..c4fb0cb 100644
--- a/osi/BUILD.gn
+++ b/osi/BUILD.gn
@@ -27,7 +27,6 @@
"src/future.cc",
"src/hash_map_utils.cc",
"src/list.cc",
- "src/metrics_linux.cc",
"src/mutex.cc",
"src/osi.cc",
"src/properties.cc",
@@ -41,17 +40,19 @@
"src/socket_utils/socket_local_client.cc",
"src/socket_utils/socket_local_server.cc",
"src/thread.cc",
- "src/time.cc",
"src/wakelock.cc",
]
include_dirs = [
"//",
+ "//linux_include",
+ "//internal_include",
"//utils/include",
"//stack/include",
]
deps = [
+ "//common",
"//third_party/libchrome:base",
]
}
@@ -68,14 +69,12 @@
"test/config_test.cc",
"test/future_test.cc",
"test/hash_map_utils_test.cc",
- "test/leaky_bonded_queue_test.cc",
"test/list_test.cc",
"test/properties_test.cc",
"test/rand_test.cc",
"test/reactor_test.cc",
"test/ringbuffer_test.cc",
"test/thread_test.cc",
- "test/time_test.cc",
]
include_dirs = [
diff --git a/osi/include/alarm.h b/osi/include/alarm.h
index b7395ca..2db228b 100644
--- a/osi/include/alarm.h
+++ b/osi/include/alarm.h
@@ -20,7 +20,6 @@
#include <stdbool.h>
#include <stdint.h>
-#include "osi/include/time.h"
typedef struct alarm_t alarm_t;
typedef struct fixed_queue_t fixed_queue_t;
@@ -71,13 +70,13 @@
// thread is not same as the caller’s thread. If two (or more)
// alarms are set back-to-back with the same |interval_ms|, the
// callbacks will be called in the order the alarms are set.
-void alarm_set(alarm_t* alarm, period_ms_t interval_ms, alarm_callback_t cb,
+void alarm_set(alarm_t* alarm, uint64_t interval_ms, alarm_callback_t cb,
void* data);
// Sets an |alarm| to execute a callback in the main message loop. This function
// is same as |alarm_set| except that the |cb| callback is scheduled for
// execution in the context of the main message loop.
-void alarm_set_on_mloop(alarm_t* alarm, period_ms_t interval_ms,
+void alarm_set_on_mloop(alarm_t* alarm, uint64_t interval_ms,
alarm_callback_t cb, void* data);
// This function cancels the |alarm| if it was previously set.
@@ -94,7 +93,7 @@
// Figure out how much time until next expiration.
// Returns 0 if not armed. |alarm| may not be NULL.
// TODO: Remove this function once PM timers can be re-factored
-period_ms_t alarm_get_remaining_ms(const alarm_t* alarm);
+uint64_t alarm_get_remaining_ms(const alarm_t* alarm);
// Cleanup the alarm internal state.
// This function should be called by the OSI module cleanup during
diff --git a/osi/include/leaky_bonded_queue.h b/osi/include/leaky_bonded_queue.h
deleted file mode 100644
index 6861e8b..0000000
--- a/osi/include/leaky_bonded_queue.h
+++ /dev/null
@@ -1,158 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2016 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 <mutex>
-#include <queue>
-
-namespace system_bt_osi {
-
-/*
- * LeakyBondedQueue<T>
- *
- * - LeakyLondedQueue<T> is a fixed size queue that leaks oldest item when
- * reaching its capacity. This is useful in creating memory bonded data
- * structure where freshness is more important than full coverage.
- * - The queue is protected by a simple mutex and is thread-safe, although
- * improvements could be made to lock enqueue and dequeue separately, it
- * is not implemented at this moment due to lack of demand
- * - The queue uses unique_ptr to automatically free its content when it is
- * destructed. It is the user's responsibility to implement T's destructor
- * correctly.
- *
- */
-template <class T>
-class LeakyBondedQueue {
- public:
- LeakyBondedQueue(size_t capacity);
- /* Default destructor
- *
- * Call Clear() and free the queue structure itself
- */
- ~LeakyBondedQueue();
- /*
- * Add item NEW_ITEM to the underlining queue. If the queue is full, pop
- * the oldest item
- */
- void Enqueue(T* new_item);
- /*
- * Add item NEW_ITEM to the underlining queue. If the queue is full, dequeue
- * the oldest item and returns it to the caller. Return nullptr otherwise.
- */
- T* EnqueueWithPop(T* new_item);
- /*
- * Dequeues the oldest item from the queue. Return nullptr if queue is empty
- */
- T* Dequeue();
- /*
- * Returns the length of queue
- */
- size_t Length();
- /*
- * Returns the defined capacity of the queue
- */
- size_t Capacity();
- /*
- * Returns whether the queue is empty
- */
- bool Empty();
- /*
- * Pops all items from the queue
- */
- void Clear();
-
- private:
- // Put item in unique_ptr so that they get freed automatically when poped or
- // when queue_ is freed
- std::queue<std::unique_ptr<T>> queue_;
- std::mutex lock_;
- size_t capacity_;
-};
-
-/*
-* Definitions must be in the header for template classes
-*/
-
-template <class T>
-LeakyBondedQueue<T>::LeakyBondedQueue(size_t capacity) {
- capacity_ = capacity;
-}
-
-template <class T>
-LeakyBondedQueue<T>::~LeakyBondedQueue() {}
-
-template <class T>
-void LeakyBondedQueue<T>::Enqueue(T* new_item) {
- std::lock_guard<std::mutex> lock(lock_);
- if ((queue_.size() + 1) > capacity_) {
- queue_.pop();
- }
- std::unique_ptr<T> item_ptr(new_item);
- queue_.push(std::move(item_ptr));
-}
-
-template <class T>
-T* LeakyBondedQueue<T>::EnqueueWithPop(T* new_item) {
- std::lock_guard<std::mutex> lock(lock_);
- T* old_item = nullptr;
- if ((queue_.size() + 1) > capacity_) {
- std::unique_ptr<T> item = std::move(queue_.front());
- queue_.pop();
- old_item = item.release();
- }
- std::unique_ptr<T> item_ptr(new_item);
- queue_.push(std::move(item_ptr));
- return old_item;
-}
-
-template <class T>
-T* LeakyBondedQueue<T>::Dequeue() {
- std::lock_guard<std::mutex> lock(lock_);
- std::unique_ptr<T> item = std::move(queue_.front());
- queue_.pop();
- return item.release();
-}
-
-template <class T>
-void LeakyBondedQueue<T>::Clear() {
- std::lock_guard<std::mutex> lock(lock_);
- while (!queue_.empty()) {
- // unique_ptr does not need to be freed
- queue_.pop();
- }
-}
-
-template <class T>
-size_t LeakyBondedQueue<T>::Length() {
- std::lock_guard<std::mutex> lock(lock_);
- return queue_.size();
-}
-
-template <class T>
-size_t LeakyBondedQueue<T>::Capacity() {
- return capacity_;
-}
-
-template <class T>
-bool LeakyBondedQueue<T>::Empty() {
- std::lock_guard<std::mutex> lock(lock_);
- return queue_.empty();
-}
-
-} // namespace system_bt_osi
diff --git a/osi/include/metrics.h b/osi/include/metrics.h
deleted file mode 100644
index 504a16a..0000000
--- a/osi/include/metrics.h
+++ /dev/null
@@ -1,276 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2016 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 <bta/include/bta_api.h>
-#include <stdint.h>
-#include <memory>
-#include <string>
-
-namespace system_bt_osi {
-
-// Typedefs to hide protobuf definition to the rest of stack
-
-typedef enum {
- DEVICE_TYPE_UNKNOWN,
- DEVICE_TYPE_BREDR,
- DEVICE_TYPE_LE,
- DEVICE_TYPE_DUMO,
-} device_type_t;
-
-typedef enum {
- WAKE_EVENT_UNKNOWN,
- WAKE_EVENT_ACQUIRED,
- WAKE_EVENT_RELEASED,
-} wake_event_type_t;
-
-typedef enum {
- SCAN_TYPE_UNKNOWN,
- SCAN_TECH_TYPE_LE,
- SCAN_TECH_TYPE_BREDR,
- SCAN_TECH_TYPE_BOTH,
-} scan_tech_t;
-
-typedef enum {
- CONNECTION_TECHNOLOGY_TYPE_UNKNOWN,
- CONNECTION_TECHNOLOGY_TYPE_LE,
- CONNECTION_TECHNOLOGY_TYPE_BREDR,
-} connection_tech_t;
-
-typedef enum {
- DISCONNECT_REASON_UNKNOWN,
- DISCONNECT_REASON_METRICS_DUMP,
- DISCONNECT_REASON_NEXT_START_WITHOUT_END_PREVIOUS,
-} disconnect_reason_t;
-
-/* Values of A2DP metrics that we care about
- *
- * audio_duration_ms : sum of audio duration (in milliseconds).
- * device_class: device class of the paired device.
- * media_timer_min_ms : minimum scheduled time (in milliseconds)
- * of the media timer.
- * media_timer_max_ms: maximum scheduled time (in milliseconds)
- * of the media timer.
- * media_timer_avg_ms: average scheduled time (in milliseconds)
- * of the media timer.
- * buffer_overruns_max_count: TODO - not clear what this is.
- * buffer_overruns_total : number of times the media buffer with
- * audio data has overrun
- * buffer_underruns_average: TODO - not clear what this is.
- * buffer_underruns_count: number of times there was no enough
- * audio data to add to the media buffer.
- * NOTE: Negative values are invalid
-*/
-class A2dpSessionMetrics {
- public:
- A2dpSessionMetrics() {}
-
- /*
- * Update the metrics value in the current metrics object using the metrics
- * objects supplied
- */
- void Update(const A2dpSessionMetrics& metrics);
-
- /*
- * Compare whether two metrics objects are equal
- */
- bool operator==(const A2dpSessionMetrics& rhs) const;
-
- /*
- * Initialize all values to -1 which is invalid in order to make a distinction
- * between 0 and invalid values
- */
- int64_t audio_duration_ms = -1;
- int32_t media_timer_min_ms = -1;
- int32_t media_timer_max_ms = -1;
- int32_t media_timer_avg_ms = -1;
- int64_t total_scheduling_count = -1;
- int32_t buffer_overruns_max_count = -1;
- int32_t buffer_overruns_total = -1;
- float buffer_underruns_average = -1;
- int32_t buffer_underruns_count = -1;
- int64_t codec_index = -1;
- bool is_a2dp_offload = false;
-};
-
-class BluetoothMetricsLogger {
- public:
- static BluetoothMetricsLogger* GetInstance() {
- static BluetoothMetricsLogger* instance = new BluetoothMetricsLogger();
- return instance;
- }
-
- /*
- * Record a pairing event
- *
- * Parameters:
- * timestamp_ms: Unix epoch time in milliseconds
- * device_class: class of remote device
- * device_type: type of remote device
- * disconnect_reason: HCI reason for pairing disconnection.
- * See: stack/include/hcidefs.h
- */
- void LogPairEvent(uint32_t disconnect_reason, uint64_t timestamp_ms,
- uint32_t device_class, device_type_t device_type);
-
- /*
- * Record a wake event
- *
- * Parameters:
- * timestamp_ms: Unix epoch time in milliseconds
- * type: whether it was acquired or released
- * requestor: if provided is the service requesting the wake lock
- * name: the name of the wake lock held
- */
- void LogWakeEvent(wake_event_type_t type, const std::string& requestor,
- const std::string& name, uint64_t timestamp_ms);
-
- /*
- * Record a scan event
- *
- * Parameters
- * timestamp_ms : Unix epoch time in milliseconds
- * start : true if this is the beginning of the scan
- * initiator: a unique ID identifying the app starting the scan
- * type: whether the scan reports BR/EDR, LE, or both.
- * results: number of results to be reported.
- */
- void LogScanEvent(bool start, const std::string& initator, scan_tech_t type,
- uint32_t results, uint64_t timestamp_ms);
-
- /*
- * Start logging a Bluetooth session
- *
- * A Bluetooth session is defined a a connection between this device and
- * another remote device which may include multiple profiles and protocols
- *
- * Only one Bluetooth session can exist at one time. Calling this method twice
- * without LogBluetoothSessionEnd will result in logging a premature end of
- * current Bluetooth session
- *
- * Parameters:
- * connection_tech_type : type of connection technology
- * timestamp_ms : the timestamp for session start, 0 means now
- *
- */
- void LogBluetoothSessionStart(connection_tech_t connection_tech_type,
- uint64_t timestamp_ms);
-
- /*
- * Stop logging a Bluetooth session and pushes it to the log queue
- *
- * If no Bluetooth session exist, this method exits immediately
- *
- * Parameters:
- * disconnect_reason : A string representation of disconnect reason
- * timestamp_ms : the timestamp of session end, 0 means now
- *
- */
- void LogBluetoothSessionEnd(disconnect_reason_t disconnect_reason,
- uint64_t timestamp_ms);
-
- /*
- * Log information about remote device in a current Bluetooth session
- *
- * If a Bluetooth session does not exist, create one with default parameter
- * and timestamp now
- *
- * Parameters:
- * device_class : device_class defined in btm_api_types.h
- * device_type : type of remote device
- */
- void LogBluetoothSessionDeviceInfo(uint32_t device_class,
- device_type_t device_type);
-
- /*
- * Log A2DP Audio Session Information
- *
- * - Repeated calls to this method will override previous metrics if in the
- * same Bluetooth connection
- * - If a Bluetooth session does not exist, create one with default parameter
- * and timestamp now
- *
- * Parameters:
- * a2dp_session_metrics - pointer to struct holding a2dp stats
- *
- */
- void LogA2dpSession(const A2dpSessionMetrics& a2dp_session_metrics);
-
- /**
- * Log Headset profile RFCOMM connection event
- *
- * @param service_id the BTA service ID for this headset connection
- */
- void LogHeadsetProfileRfcConnection(tBTA_SERVICE_ID service_id);
-
- /*
- * Writes the metrics, in base64 protobuf format, into the descriptor FD,
- * metrics events are always cleared after dump
- */
- void WriteBase64(int fd);
- void WriteBase64String(std::string* serialized);
- void WriteString(std::string* serialized);
-
- /*
- * Reset the metrics logger by cleaning up its staging queues and existing
- * protobuf objects.
- */
- void Reset();
-
- /*
- * Maximum number of log entries for each session or event
- */
- static const size_t kMaxNumBluetoothSession = 50;
- static const size_t kMaxNumPairEvent = 50;
- static const size_t kMaxNumWakeEvent = 1000;
- static const size_t kMaxNumScanEvent = 50;
-
- private:
- BluetoothMetricsLogger();
-
- /*
- * When a Bluetooth session is on and the user initiates a metrics dump, we
- * need to be able to upload whatever we have first. This method breaks the
- * ongoing Bluetooth session into two sessions with the previous one labeled
- * as "METRICS_DUMP" for the disconnect reason.
- */
- void CutoffSession();
-
- /*
- * Build the internal metrics object using information gathered
- */
- void Build();
-
- /*
- * Reset objects related to current Bluetooth session
- */
- void ResetSession();
-
- /*
- * Reset the underlining BluetoothLog object
- */
- void ResetLog();
-
- /*
- * PIMPL style implementation to hide internal dependencies
- */
- struct impl;
- std::unique_ptr<impl> const pimpl_;
-};
-}
diff --git a/osi/include/time.h b/osi/include/time.h
deleted file mode 100644
index 8f533d0..0000000
--- a/osi/include/time.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/******************************************************************************
- *
- * Copyright 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 <stdint.h>
-
-typedef uint64_t period_ms_t;
-
-// Get the OS boot time in milliseconds.
-//
-// NOTE: The return value will rollover every 49.7 days,
-// hence it cannot be used for absolute time comparison.
-// Relative time comparison using 32-bits integers such
-// as (t2_u32 - t1_u32 < delta_u32) should work as expected as long
-// as there is no multiple rollover between t2_u32 and t1_u32.
-//
-// TODO: This function's return type should be modified to |period_ms_t|.
-// Be careful: some of the code that is using it assumes the return type
-// is uint32_t.
-uint32_t time_get_os_boottime_ms(void);
-
-// Get the OS boot time in microseconds.
-uint64_t time_get_os_boottime_us(void);
-
-// Get the current wall clock time in microseconds.
-uint64_t time_gettimeofday_us(void);
diff --git a/osi/src/alarm.cc b/osi/src/alarm.cc
index 83a661d..ea075db 100644
--- a/osi/src/alarm.cc
+++ b/osi/src/alarm.cc
@@ -46,21 +46,20 @@
#include "osi/include/semaphore.h"
#include "osi/include/thread.h"
#include "osi/include/wakelock.h"
+#include "stack/include/btu.h"
using base::Bind;
using base::CancelableClosure;
using base::MessageLoop;
-extern base::MessageLoop* get_message_loop();
-
// Callback and timer threads should run at RT priority in order to ensure they
// meet audio deadlines. Use this priority for all audio/timer related thread.
static const int THREAD_RT_PRIORITY = 1;
typedef struct {
size_t count;
- period_ms_t total_ms;
- period_ms_t max_ms;
+ uint64_t total_ms;
+ uint64_t max_ms;
} stat_t;
// Alarm-related information and statistics
@@ -70,7 +69,7 @@
size_t canceled_count;
size_t rescheduled_count;
size_t total_updates;
- period_ms_t last_update_ms;
+ uint64_t last_update_ms;
stat_t overdue_scheduling;
stat_t premature_scheduling;
} alarm_stats_t;
@@ -93,10 +92,10 @@
// mutex to provide a guarantee to its caller that the callback will not be
// in progress when it returns.
std::recursive_mutex* callback_mutex;
- period_ms_t creation_time;
- period_ms_t period;
- period_ms_t deadline;
- period_ms_t prev_deadline; // Previous deadline - used for accounting of
+ uint64_t creation_time_ms;
+ uint64_t period_ms;
+ uint64_t deadline_ms;
+ uint64_t prev_deadline_ms; // Previous deadline - used for accounting of
// periodic timers
bool is_periodic;
fixed_queue_t* queue; // The processing queue to add this alarm to
@@ -115,12 +114,6 @@
int64_t TIMER_INTERVAL_FOR_WAKELOCK_IN_MS = 3000;
static const clockid_t CLOCK_ID = CLOCK_BOOTTIME;
-#if (KERNEL_MISSING_CLOCK_BOOTTIME_ALARM == TRUE)
-static const clockid_t CLOCK_ID_ALARM = CLOCK_BOOTTIME;
-#else
-static const clockid_t CLOCK_ID_ALARM = CLOCK_BOOTTIME_ALARM;
-#endif
-
// This mutex ensures that the |alarm_set|, |alarm_cancel|, and alarm callback
// functions execute serially and not concurrently. As a result, this mutex
// also protects the |alarms| list.
@@ -141,8 +134,8 @@
static alarm_t* alarm_new_internal(const char* name, bool is_periodic);
static bool lazy_initialize(void);
-static period_ms_t now(void);
-static void alarm_set_internal(alarm_t* alarm, period_ms_t period,
+static uint64_t now_ms(void);
+static void alarm_set_internal(alarm_t* alarm, uint64_t period_ms,
alarm_callback_t cb, void* data,
fixed_queue_t* queue, bool for_msg_loop);
static void alarm_cancel_internal(alarm_t* alarm);
@@ -153,16 +146,16 @@
static void timer_callback(void* data);
static void callback_dispatch(void* context);
static bool timer_create_internal(const clockid_t clock_id, timer_t* timer);
-static void update_scheduling_stats(alarm_stats_t* stats, period_ms_t now_ms,
- period_ms_t deadline_ms);
+static void update_scheduling_stats(alarm_stats_t* stats, uint64_t now_ms,
+ uint64_t deadline_ms);
// Registers |queue| for processing alarm callbacks on |thread|.
// |queue| may not be NULL. |thread| may not be NULL.
static void alarm_register_processing_queue(fixed_queue_t* queue,
thread_t* thread);
-static void update_stat(stat_t* stat, period_ms_t delta) {
- if (stat->max_ms < delta) stat->max_ms = delta;
- stat->total_ms += delta;
+static void update_stat(stat_t* stat, uint64_t delta_ms) {
+ if (stat->max_ms < delta_ms) stat->max_ms = delta_ms;
+ stat->total_ms += delta_ms;
stat->count++;
}
@@ -204,30 +197,31 @@
osi_free(alarm);
}
-period_ms_t alarm_get_remaining_ms(const alarm_t* alarm) {
+uint64_t alarm_get_remaining_ms(const alarm_t* alarm) {
CHECK(alarm != NULL);
- period_ms_t remaining_ms = 0;
- period_ms_t just_now = now();
+ uint64_t remaining_ms = 0;
+ uint64_t just_now_ms = now_ms();
std::lock_guard<std::mutex> lock(alarms_mutex);
- if (alarm->deadline > just_now) remaining_ms = alarm->deadline - just_now;
+ if (alarm->deadline_ms > just_now_ms)
+ remaining_ms = alarm->deadline_ms - just_now_ms;
return remaining_ms;
}
-void alarm_set(alarm_t* alarm, period_ms_t interval_ms, alarm_callback_t cb,
+void alarm_set(alarm_t* alarm, uint64_t interval_ms, alarm_callback_t cb,
void* data) {
alarm_set_internal(alarm, interval_ms, cb, data, default_callback_queue,
false);
}
-void alarm_set_on_mloop(alarm_t* alarm, period_ms_t interval_ms,
+void alarm_set_on_mloop(alarm_t* alarm, uint64_t interval_ms,
alarm_callback_t cb, void* data) {
alarm_set_internal(alarm, interval_ms, cb, data, NULL, true);
}
// Runs in exclusion with alarm_cancel and timer_callback.
-static void alarm_set_internal(alarm_t* alarm, period_ms_t period,
+static void alarm_set_internal(alarm_t* alarm, uint64_t period_ms,
alarm_callback_t cb, void* data,
fixed_queue_t* queue, bool for_msg_loop) {
CHECK(alarms != NULL);
@@ -236,8 +230,8 @@
std::lock_guard<std::mutex> lock(alarms_mutex);
- alarm->creation_time = now();
- alarm->period = period;
+ alarm->creation_time_ms = now_ms();
+ alarm->period_ms = period_ms;
alarm->queue = queue;
alarm->callback = cb;
alarm->data = data;
@@ -268,8 +262,8 @@
remove_pending_alarm(alarm);
- alarm->deadline = 0;
- alarm->prev_deadline = 0;
+ alarm->deadline_ms = 0;
+ alarm->prev_deadline_ms = 0;
alarm->callback = NULL;
alarm->data = NULL;
alarm->stats.canceled_count++;
@@ -327,7 +321,11 @@
if (!timer_create_internal(CLOCK_ID, &timer)) goto error;
timer_initialized = true;
- if (!timer_create_internal(CLOCK_ID_ALARM, &wakeup_timer)) goto error;
+ if (!timer_create_internal(CLOCK_BOOTTIME_ALARM, &wakeup_timer)) {
+ if (!timer_create_internal(CLOCK_BOOTTIME, &wakeup_timer)) {
+ goto error;
+ }
+ }
wakeup_timer_initialized = true;
alarm_expired = semaphore_new(0);
@@ -387,7 +385,7 @@
return false;
}
-static period_ms_t now(void) {
+static uint64_t now_ms(void) {
CHECK(alarms != NULL);
struct timespec ts;
@@ -425,22 +423,23 @@
if (alarm->callback) remove_pending_alarm(alarm);
// Calculate the next deadline for this alarm
- period_ms_t just_now = now();
- period_ms_t ms_into_period = 0;
- if ((alarm->is_periodic) && (alarm->period != 0))
- ms_into_period = ((just_now - alarm->creation_time) % alarm->period);
- alarm->deadline = just_now + (alarm->period - ms_into_period);
+ uint64_t just_now_ms = now_ms();
+ uint64_t ms_into_period = 0;
+ if ((alarm->is_periodic) && (alarm->period_ms != 0))
+ ms_into_period =
+ ((just_now_ms - alarm->creation_time_ms) % alarm->period_ms);
+ alarm->deadline_ms = just_now_ms + (alarm->period_ms - ms_into_period);
// Add it into the timer list sorted by deadline (earliest deadline first).
if (list_is_empty(alarms) ||
- ((alarm_t*)list_front(alarms))->deadline > alarm->deadline) {
+ ((alarm_t*)list_front(alarms))->deadline_ms > alarm->deadline_ms) {
list_prepend(alarms, alarm);
} else {
for (list_node_t* node = list_begin(alarms); node != list_end(alarms);
node = list_next(node)) {
list_node_t* next = list_next(node);
if (next == list_end(alarms) ||
- ((alarm_t*)list_node(next))->deadline > alarm->deadline) {
+ ((alarm_t*)list_node(next))->deadline_ms > alarm->deadline_ms) {
list_insert_after(alarms, node, alarm);
break;
}
@@ -470,7 +469,7 @@
if (list_is_empty(alarms)) goto done;
next = static_cast<alarm_t*>(list_front(alarms));
- next_expiration = next->deadline - now();
+ next_expiration = next->deadline_ms - now_ms();
if (next_expiration < TIMER_INTERVAL_FOR_WAKELOCK_IN_MS) {
if (!timer_set) {
if (!wakelock_acquire()) {
@@ -479,8 +478,8 @@
}
}
- timer_time.it_value.tv_sec = (next->deadline / 1000);
- timer_time.it_value.tv_nsec = (next->deadline % 1000) * 1000000LL;
+ timer_time.it_value.tv_sec = (next->deadline_ms / 1000);
+ timer_time.it_value.tv_nsec = (next->deadline_ms % 1000) * 1000000LL;
// It is entirely unsafe to call timer_settime(2) with a zeroed timerspec
// for timers with *_ALARM clock IDs. Although the man page states that the
@@ -505,8 +504,8 @@
struct itimerspec wakeup_time;
memset(&wakeup_time, 0, sizeof(wakeup_time));
- wakeup_time.it_value.tv_sec = (next->deadline / 1000);
- wakeup_time.it_value.tv_nsec = (next->deadline % 1000) * 1000000LL;
+ wakeup_time.it_value.tv_sec = (next->deadline_ms / 1000);
+ wakeup_time.it_value.tv_nsec = (next->deadline_ms % 1000) * 1000000LL;
if (timer_settime(wakeup_timer, TIMER_ABSTIME, &wakeup_time, NULL) == -1)
LOG_ERROR(LOG_TAG, "%s unable to set wakeup timer: %s", __func__,
strerror(errno));
@@ -560,20 +559,25 @@
if (alarm == NULL) {
return; // The alarm was probably canceled
}
+
//
// If the alarm is not periodic, we've fully serviced it now, and can reset
// some of its internal state. This is useful to distinguish between expired
// alarms and active ones.
//
+ if (!alarm->callback) {
+ LOG(FATAL) << __func__
+ << ": timer callback is NULL! Name=" << alarm->stats.name;
+ }
alarm_callback_t callback = alarm->callback;
void* data = alarm->data;
- period_ms_t deadline = alarm->deadline;
+ uint64_t deadline_ms = alarm->deadline_ms;
if (alarm->is_periodic) {
// The periodic alarm has been rescheduled and alarm->deadline has been
// updated, hence we need to use the previous deadline.
- deadline = alarm->prev_deadline;
+ deadline_ms = alarm->prev_deadline_ms;
} else {
- alarm->deadline = 0;
+ alarm->deadline_ms = 0;
alarm->callback = NULL;
alarm->data = NULL;
alarm->queue = NULL;
@@ -583,7 +587,7 @@
lock.unlock();
// Update the statistics
- update_scheduling_stats(&alarm->stats, now(), deadline);
+ update_scheduling_stats(&alarm->stats, now_ms(), deadline_ms);
// NOTE: Do NOT access "alarm" after the callback, as a safety precaution
// in case the callback itself deleted the alarm.
@@ -624,7 +628,8 @@
// We're done here if there are no alarms or the alarm at the front is in
// the future. Exit right away since there's nothing left to do.
if (list_is_empty(alarms) ||
- (alarm = static_cast<alarm_t*>(list_front(alarms)))->deadline > now()) {
+ (alarm = static_cast<alarm_t*>(list_front(alarms)))->deadline_ms >
+ now_ms()) {
reschedule_root_alarm();
continue;
}
@@ -632,7 +637,7 @@
list_remove(alarms, alarm);
if (alarm->is_periodic) {
- alarm->prev_deadline = alarm->deadline;
+ alarm->prev_deadline_ms = alarm->deadline_ms;
schedule_next_instance(alarm);
alarm->stats.rescheduled_count++;
}
@@ -640,15 +645,15 @@
// Enqueue the alarm for processing
if (alarm->for_msg_loop) {
- if (!get_message_loop()) {
+ if (!get_main_message_loop()) {
LOG_ERROR(LOG_TAG, "%s: message loop already NULL. Alarm: %s", __func__,
alarm->stats.name);
continue;
}
alarm->closure.i.Reset(Bind(alarm_ready_mloop, alarm));
- get_message_loop()->task_runner()->PostTask(FROM_HERE,
- alarm->closure.i.callback());
+ get_main_message_loop()->task_runner()->PostTask(
+ FROM_HERE, alarm->closure.i.callback());
} else {
fixed_queue_enqueue(alarm->queue, alarm);
}
@@ -692,24 +697,24 @@
return true;
}
-static void update_scheduling_stats(alarm_stats_t* stats, period_ms_t now_ms,
- period_ms_t deadline_ms) {
+static void update_scheduling_stats(alarm_stats_t* stats, uint64_t now_ms,
+ uint64_t deadline_ms) {
stats->total_updates++;
stats->last_update_ms = now_ms;
if (deadline_ms < now_ms) {
// Overdue scheduling
- period_ms_t delta_ms = now_ms - deadline_ms;
+ uint64_t delta_ms = now_ms - deadline_ms;
update_stat(&stats->overdue_scheduling, delta_ms);
} else if (deadline_ms > now_ms) {
// Premature scheduling
- period_ms_t delta_ms = deadline_ms - now_ms;
+ uint64_t delta_ms = deadline_ms - now_ms;
update_stat(&stats->premature_scheduling, delta_ms);
}
}
static void dump_stat(int fd, stat_t* stat, const char* description) {
- period_ms_t average_time_ms = 0;
+ uint64_t average_time_ms = 0;
if (stat->count != 0) average_time_ms = stat->total_ms / stat->count;
dprintf(fd, "%-51s: %llu / %llu / %llu\n", description,
@@ -727,7 +732,7 @@
return;
}
- period_ms_t just_now = now();
+ uint64_t just_now_ms = now_ms();
dprintf(fd, " Total Alarms: %zu\n\n", list_length(alarms));
@@ -751,9 +756,9 @@
dprintf(fd, "%-51s: %llu / %llu / %lld\n",
" Time in ms (since creation/interval/remaining)",
- (unsigned long long)(just_now - alarm->creation_time),
- (unsigned long long)alarm->period,
- (long long)(alarm->deadline - just_now));
+ (unsigned long long)(just_now_ms - alarm->creation_time_ms),
+ (unsigned long long)alarm->period_ms,
+ (long long)(alarm->deadline_ms - just_now_ms));
dump_stat(fd, &stats->overdue_scheduling,
" Overdue scheduling time in ms (total/max/avg)");
diff --git a/osi/src/config.cc b/osi/src/config.cc
index d4ed2e6..e937959 100644
--- a/osi/src/config.cc
+++ b/osi/src/config.cc
@@ -17,7 +17,6 @@
******************************************************************************/
#include "osi/include/config.h"
-#include "log/log.h"
#include <base/files/file_path.h>
#include <base/logging.h>
@@ -25,6 +24,7 @@
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
+#include <log/log.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -172,7 +172,7 @@
}
std::string value_no_newline;
- size_t newline_position = value.find("\n");
+ size_t newline_position = value.find('\n');
if (newline_position != std::string::npos) {
android_errorWriteLog(0x534e4554, "70808273");
value_no_newline = value.substr(0, newline_position);
@@ -223,10 +223,11 @@
// Steps to ensure content of config file gets to disk:
//
// 1) Open and write to temp file (e.g. bt_config.conf.new).
- // 2) Sync the temp file to disk with fsync().
- // 3) Rename temp file to actual config file (e.g. bt_config.conf).
+ // 2) Flush the stream buffer to the temp file.
+ // 3) Sync the temp file to disk with fsync().
+ // 4) Rename temp file to actual config file (e.g. bt_config.conf).
// This ensures atomic update.
- // 4) Sync directory that has the conf file with fsync().
+ // 5) Sync directory that has the conf file with fsync().
// This ensures directory entries are up-to-date.
int dir_fd = -1;
FILE* fp = nullptr;
@@ -272,6 +273,13 @@
goto error;
}
+ // Flush the stream buffer to the temp file.
+ if (fflush(fp) < 0) {
+ LOG(ERROR) << __func__ << ": unable to write flush buffer to file '"
+ << temp_filename << "': " << strerror(errno);
+ goto error;
+ }
+
// Sync written temp file out to disk. fsync() is blocking until data makes it
// to disk.
if (fsync(fileno(fp)) < 0) {
diff --git a/osi/src/metrics.cc b/osi/src/metrics.cc
deleted file mode 100644
index 73450b9..0000000
--- a/osi/src/metrics.cc
+++ /dev/null
@@ -1,574 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2016 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_osi_metrics"
-
-#include <unistd.h>
-#include <algorithm>
-#include <array>
-#include <cerrno>
-#include <chrono>
-#include <cstdint>
-#include <cstring>
-#include <memory>
-#include <mutex>
-
-#include <base/base64.h>
-#include <base/logging.h>
-#include <include/hardware/bt_av.h>
-
-#include "bluetooth/metrics/bluetooth.pb.h"
-#include "osi/include/leaky_bonded_queue.h"
-#include "osi/include/log.h"
-#include "osi/include/osi.h"
-#include "osi/include/time.h"
-#include "stack/include/btm_api_types.h"
-
-#include "osi/include/metrics.h"
-
-namespace system_bt_osi {
-
-using bluetooth::metrics::BluetoothMetricsProto::A2DPSession;
-using bluetooth::metrics::BluetoothMetricsProto::A2dpSourceCodec;
-using bluetooth::metrics::BluetoothMetricsProto::BluetoothLog;
-using bluetooth::metrics::BluetoothMetricsProto::BluetoothSession;
-using bluetooth::metrics::BluetoothMetricsProto::
- BluetoothSession_ConnectionTechnologyType;
-using bluetooth::metrics::BluetoothMetricsProto::
- BluetoothSession_DisconnectReasonType;
-using bluetooth::metrics::BluetoothMetricsProto::DeviceInfo;
-using bluetooth::metrics::BluetoothMetricsProto::DeviceInfo_DeviceType;
-using bluetooth::metrics::BluetoothMetricsProto::PairEvent;
-using bluetooth::metrics::BluetoothMetricsProto::ScanEvent;
-using bluetooth::metrics::BluetoothMetricsProto::ScanEvent_ScanTechnologyType;
-using bluetooth::metrics::BluetoothMetricsProto::ScanEvent_ScanEventType;
-using bluetooth::metrics::BluetoothMetricsProto::WakeEvent;
-using bluetooth::metrics::BluetoothMetricsProto::WakeEvent_WakeEventType;
-using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileType;
-using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileType_MIN;
-using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileType_MAX;
-using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileType_ARRAYSIZE;
-using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileType_IsValid;
-using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileConnectionStats;
-/*
- * Get current OS boot time in millisecond
- */
-static int64_t time_get_os_boottime_ms(void) {
- return time_get_os_boottime_us() / 1000;
-}
-
-static float combine_averages(float avg_a, int64_t ct_a, float avg_b,
- int64_t ct_b) {
- if (ct_a > 0 && ct_b > 0) {
- return (avg_a * ct_a + avg_b * ct_b) / (ct_a + ct_b);
- } else if (ct_b > 0) {
- return avg_b;
- } else {
- return avg_a;
- }
-}
-
-static int32_t combine_averages(int32_t avg_a, int64_t ct_a, int32_t avg_b,
- int64_t ct_b) {
- if (ct_a > 0 && ct_b > 0) {
- return (avg_a * ct_a + avg_b * ct_b) / (ct_a + ct_b);
- } else if (ct_b > 0) {
- return avg_b;
- } else {
- return avg_a;
- }
-}
-
-void A2dpSessionMetrics::Update(const A2dpSessionMetrics& metrics) {
- if (metrics.audio_duration_ms >= 0) {
- audio_duration_ms = std::max(static_cast<int64_t>(0), audio_duration_ms);
- audio_duration_ms += metrics.audio_duration_ms;
- }
- if (metrics.media_timer_min_ms >= 0) {
- if (media_timer_min_ms < 0) {
- media_timer_min_ms = metrics.media_timer_min_ms;
- } else {
- media_timer_min_ms =
- std::min(media_timer_min_ms, metrics.media_timer_min_ms);
- }
- }
- if (metrics.media_timer_max_ms >= 0) {
- media_timer_max_ms =
- std::max(media_timer_max_ms, metrics.media_timer_max_ms);
- }
- if (metrics.media_timer_avg_ms >= 0 && metrics.total_scheduling_count >= 0) {
- if (media_timer_avg_ms < 0 || total_scheduling_count < 0) {
- media_timer_avg_ms = metrics.media_timer_avg_ms;
- total_scheduling_count = metrics.total_scheduling_count;
- } else {
- media_timer_avg_ms = combine_averages(
- media_timer_avg_ms, total_scheduling_count,
- metrics.media_timer_avg_ms, metrics.total_scheduling_count);
- total_scheduling_count += metrics.total_scheduling_count;
- }
- }
- if (metrics.buffer_overruns_max_count >= 0) {
- buffer_overruns_max_count =
- std::max(buffer_overruns_max_count, metrics.buffer_overruns_max_count);
- }
- if (metrics.buffer_overruns_total >= 0) {
- buffer_overruns_total =
- std::max(static_cast<int32_t>(0), buffer_overruns_total);
- buffer_overruns_total += metrics.buffer_overruns_total;
- }
- if (metrics.buffer_underruns_average >= 0 &&
- metrics.buffer_underruns_count >= 0) {
- if (buffer_underruns_average < 0 || buffer_underruns_count < 0) {
- buffer_underruns_average = metrics.buffer_underruns_average;
- buffer_underruns_count = metrics.buffer_underruns_count;
- } else {
- buffer_underruns_average = combine_averages(
- buffer_underruns_average, buffer_underruns_count,
- metrics.buffer_underruns_average, metrics.buffer_underruns_count);
- buffer_underruns_count += metrics.buffer_underruns_count;
- }
- }
- if (codec_index < 0) {
- codec_index = metrics.codec_index;
- }
- if (!is_a2dp_offload) {
- is_a2dp_offload = metrics.is_a2dp_offload;
- }
-}
-
-bool A2dpSessionMetrics::operator==(const A2dpSessionMetrics& rhs) const {
- return audio_duration_ms == rhs.audio_duration_ms &&
- media_timer_min_ms == rhs.media_timer_min_ms &&
- media_timer_max_ms == rhs.media_timer_max_ms &&
- media_timer_avg_ms == rhs.media_timer_avg_ms &&
- total_scheduling_count == rhs.total_scheduling_count &&
- buffer_overruns_max_count == rhs.buffer_overruns_max_count &&
- buffer_overruns_total == rhs.buffer_overruns_total &&
- buffer_underruns_average == rhs.buffer_underruns_average &&
- buffer_underruns_count == rhs.buffer_underruns_count &&
- codec_index == rhs.codec_index &&
- is_a2dp_offload == rhs.is_a2dp_offload;
-}
-
-static DeviceInfo_DeviceType get_device_type(device_type_t type) {
- switch (type) {
- case DEVICE_TYPE_BREDR:
- return DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR;
- case DEVICE_TYPE_LE:
- return DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_LE;
- case DEVICE_TYPE_DUMO:
- return DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_DUMO;
- case DEVICE_TYPE_UNKNOWN:
- default:
- return DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_UNKNOWN;
- }
-}
-
-static BluetoothSession_ConnectionTechnologyType get_connection_tech_type(
- connection_tech_t type) {
- switch (type) {
- case CONNECTION_TECHNOLOGY_TYPE_LE:
- return BluetoothSession_ConnectionTechnologyType::
- BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_LE;
- case CONNECTION_TECHNOLOGY_TYPE_BREDR:
- return BluetoothSession_ConnectionTechnologyType::
- BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR;
- case CONNECTION_TECHNOLOGY_TYPE_UNKNOWN:
- default:
- return BluetoothSession_ConnectionTechnologyType::
- BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_UNKNOWN;
- }
-}
-
-static ScanEvent_ScanTechnologyType get_scan_tech_type(scan_tech_t type) {
- switch (type) {
- case SCAN_TECH_TYPE_LE:
- return ScanEvent_ScanTechnologyType::
- ScanEvent_ScanTechnologyType_SCAN_TECH_TYPE_LE;
- case SCAN_TECH_TYPE_BREDR:
- return ScanEvent_ScanTechnologyType::
- ScanEvent_ScanTechnologyType_SCAN_TECH_TYPE_BREDR;
- case SCAN_TECH_TYPE_BOTH:
- return ScanEvent_ScanTechnologyType::
- ScanEvent_ScanTechnologyType_SCAN_TECH_TYPE_BOTH;
- case SCAN_TYPE_UNKNOWN:
- default:
- return ScanEvent_ScanTechnologyType::
- ScanEvent_ScanTechnologyType_SCAN_TYPE_UNKNOWN;
- }
-}
-
-static WakeEvent_WakeEventType get_wake_event_type(wake_event_type_t type) {
- switch (type) {
- case WAKE_EVENT_ACQUIRED:
- return WakeEvent_WakeEventType::WakeEvent_WakeEventType_ACQUIRED;
- case WAKE_EVENT_RELEASED:
- return WakeEvent_WakeEventType::WakeEvent_WakeEventType_RELEASED;
- case WAKE_EVENT_UNKNOWN:
- default:
- return WakeEvent_WakeEventType::WakeEvent_WakeEventType_UNKNOWN;
- }
-}
-
-static BluetoothSession_DisconnectReasonType get_disconnect_reason_type(
- disconnect_reason_t type) {
- switch (type) {
- case DISCONNECT_REASON_METRICS_DUMP:
- return BluetoothSession_DisconnectReasonType::
- BluetoothSession_DisconnectReasonType_METRICS_DUMP;
- case DISCONNECT_REASON_NEXT_START_WITHOUT_END_PREVIOUS:
- return BluetoothSession_DisconnectReasonType::
- BluetoothSession_DisconnectReasonType_NEXT_START_WITHOUT_END_PREVIOUS;
- case DISCONNECT_REASON_UNKNOWN:
- default:
- return BluetoothSession_DisconnectReasonType::
- BluetoothSession_DisconnectReasonType_UNKNOWN;
- }
-}
-
-static A2dpSourceCodec get_a2dp_source_codec(int64_t codec_index) {
- switch (codec_index) {
- case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
- return A2dpSourceCodec::A2DP_SOURCE_CODEC_SBC;
- case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
- return A2dpSourceCodec::A2DP_SOURCE_CODEC_AAC;
- case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
- return A2dpSourceCodec::A2DP_SOURCE_CODEC_APTX;
- case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD:
- return A2dpSourceCodec::A2DP_SOURCE_CODEC_APTX_HD;
- case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC:
- return A2dpSourceCodec::A2DP_SOURCE_CODEC_LDAC;
- default:
- return A2dpSourceCodec::A2DP_SOURCE_CODEC_UNKNOWN;
- }
-}
-
-struct BluetoothMetricsLogger::impl {
- impl(size_t max_bluetooth_session, size_t max_pair_event,
- size_t max_wake_event, size_t max_scan_event)
- : bt_session_queue_(
- new LeakyBondedQueue<BluetoothSession>(max_bluetooth_session)),
- pair_event_queue_(new LeakyBondedQueue<PairEvent>(max_pair_event)),
- wake_event_queue_(new LeakyBondedQueue<WakeEvent>(max_wake_event)),
- scan_event_queue_(new LeakyBondedQueue<ScanEvent>(max_scan_event)) {
- bluetooth_log_ = BluetoothLog::default_instance().New();
- headset_profile_connection_counts_.fill(0);
- bluetooth_session_ = nullptr;
- bluetooth_session_start_time_ms_ = 0;
- a2dp_session_metrics_ = A2dpSessionMetrics();
- }
-
- /* Bluetooth log lock protected */
- BluetoothLog* bluetooth_log_;
- std::array<int, HeadsetProfileType_ARRAYSIZE>
- headset_profile_connection_counts_;
- std::recursive_mutex bluetooth_log_lock_;
- /* End Bluetooth log lock protected */
- /* Bluetooth session lock protected */
- BluetoothSession* bluetooth_session_;
- uint64_t bluetooth_session_start_time_ms_;
- A2dpSessionMetrics a2dp_session_metrics_;
- std::recursive_mutex bluetooth_session_lock_;
- /* End bluetooth session lock protected */
- std::unique_ptr<LeakyBondedQueue<BluetoothSession>> bt_session_queue_;
- std::unique_ptr<LeakyBondedQueue<PairEvent>> pair_event_queue_;
- std::unique_ptr<LeakyBondedQueue<WakeEvent>> wake_event_queue_;
- std::unique_ptr<LeakyBondedQueue<ScanEvent>> scan_event_queue_;
-};
-
-BluetoothMetricsLogger::BluetoothMetricsLogger()
- : pimpl_(new impl(kMaxNumBluetoothSession, kMaxNumPairEvent,
- kMaxNumWakeEvent, kMaxNumScanEvent)) {}
-
-void BluetoothMetricsLogger::LogPairEvent(uint32_t disconnect_reason,
- uint64_t timestamp_ms,
- uint32_t device_class,
- device_type_t device_type) {
- PairEvent* event = new PairEvent();
- DeviceInfo* info = event->mutable_device_paired_with();
- info->set_device_class(device_class);
- info->set_device_type(get_device_type(device_type));
- event->set_disconnect_reason(disconnect_reason);
- event->set_event_time_millis(timestamp_ms);
- pimpl_->pair_event_queue_->Enqueue(event);
- {
- std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
- pimpl_->bluetooth_log_->set_num_pair_event(
- pimpl_->bluetooth_log_->num_pair_event() + 1);
- }
-}
-
-void BluetoothMetricsLogger::LogWakeEvent(wake_event_type_t type,
- const std::string& requestor,
- const std::string& name,
- uint64_t timestamp_ms) {
- WakeEvent* event = new WakeEvent();
- event->set_wake_event_type(get_wake_event_type(type));
- event->set_requestor(requestor);
- event->set_name(name);
- event->set_event_time_millis(timestamp_ms);
- pimpl_->wake_event_queue_->Enqueue(event);
- {
- std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
- pimpl_->bluetooth_log_->set_num_wake_event(
- pimpl_->bluetooth_log_->num_wake_event() + 1);
- }
-}
-
-void BluetoothMetricsLogger::LogScanEvent(bool start,
- const std::string& initator,
- scan_tech_t type, uint32_t results,
- uint64_t timestamp_ms) {
- ScanEvent* event = new ScanEvent();
- if (start) {
- event->set_scan_event_type(ScanEvent::SCAN_EVENT_START);
- } else {
- event->set_scan_event_type(ScanEvent::SCAN_EVENT_STOP);
- }
- event->set_initiator(initator);
- event->set_scan_technology_type(get_scan_tech_type(type));
- event->set_number_results(results);
- event->set_event_time_millis(timestamp_ms);
- pimpl_->scan_event_queue_->Enqueue(event);
- {
- std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
- pimpl_->bluetooth_log_->set_num_scan_event(
- pimpl_->bluetooth_log_->num_scan_event() + 1);
- }
-}
-
-void BluetoothMetricsLogger::LogBluetoothSessionStart(
- connection_tech_t connection_tech_type, uint64_t timestamp_ms) {
- std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
- if (pimpl_->bluetooth_session_ != nullptr) {
- LogBluetoothSessionEnd(DISCONNECT_REASON_NEXT_START_WITHOUT_END_PREVIOUS,
- 0);
- }
- if (timestamp_ms == 0) {
- timestamp_ms = time_get_os_boottime_ms();
- }
- pimpl_->bluetooth_session_start_time_ms_ = timestamp_ms;
- pimpl_->bluetooth_session_ = new BluetoothSession();
- pimpl_->bluetooth_session_->set_connection_technology_type(
- get_connection_tech_type(connection_tech_type));
-}
-
-void BluetoothMetricsLogger::LogBluetoothSessionEnd(
- disconnect_reason_t disconnect_reason, uint64_t timestamp_ms) {
- std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
- if (pimpl_->bluetooth_session_ == nullptr) {
- return;
- }
- if (timestamp_ms == 0) {
- timestamp_ms = time_get_os_boottime_ms();
- }
- int64_t session_duration_sec =
- (timestamp_ms - pimpl_->bluetooth_session_start_time_ms_) / 1000;
- pimpl_->bluetooth_session_->set_session_duration_sec(session_duration_sec);
- pimpl_->bluetooth_session_->set_disconnect_reason_type(
- get_disconnect_reason_type(disconnect_reason));
- pimpl_->bt_session_queue_->Enqueue(pimpl_->bluetooth_session_);
- pimpl_->bluetooth_session_ = nullptr;
- pimpl_->a2dp_session_metrics_ = A2dpSessionMetrics();
- {
- std::lock_guard<std::recursive_mutex> log_lock(pimpl_->bluetooth_log_lock_);
- pimpl_->bluetooth_log_->set_num_bluetooth_session(
- pimpl_->bluetooth_log_->num_bluetooth_session() + 1);
- }
-}
-
-void BluetoothMetricsLogger::LogBluetoothSessionDeviceInfo(
- uint32_t device_class, device_type_t device_type) {
- std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
- if (pimpl_->bluetooth_session_ == nullptr) {
- LogBluetoothSessionStart(CONNECTION_TECHNOLOGY_TYPE_UNKNOWN, 0);
- }
- DeviceInfo* info = pimpl_->bluetooth_session_->mutable_device_connected_to();
- info->set_device_class(device_class);
- info->set_device_type(DeviceInfo::DEVICE_TYPE_BREDR);
-}
-
-void BluetoothMetricsLogger::LogA2dpSession(
- const A2dpSessionMetrics& a2dp_session_metrics) {
- std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
- if (pimpl_->bluetooth_session_ == nullptr) {
- // When no bluetooth session exist, create one on system's behalf
- // Set connection type: for A2DP it is always BR/EDR
- LogBluetoothSessionStart(CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
- LogBluetoothSessionDeviceInfo(BTM_COD_MAJOR_AUDIO, DEVICE_TYPE_BREDR);
- }
- // Accumulate metrics
- pimpl_->a2dp_session_metrics_.Update(a2dp_session_metrics);
- // Get or allocate new A2DP session object
- A2DPSession* a2dp_session =
- pimpl_->bluetooth_session_->mutable_a2dp_session();
- a2dp_session->set_audio_duration_millis(
- pimpl_->a2dp_session_metrics_.audio_duration_ms);
- a2dp_session->set_media_timer_min_millis(
- pimpl_->a2dp_session_metrics_.media_timer_min_ms);
- a2dp_session->set_media_timer_max_millis(
- pimpl_->a2dp_session_metrics_.media_timer_max_ms);
- a2dp_session->set_media_timer_avg_millis(
- pimpl_->a2dp_session_metrics_.media_timer_avg_ms);
- a2dp_session->set_buffer_overruns_max_count(
- pimpl_->a2dp_session_metrics_.buffer_overruns_max_count);
- a2dp_session->set_buffer_overruns_total(
- pimpl_->a2dp_session_metrics_.buffer_overruns_total);
- a2dp_session->set_buffer_underruns_average(
- pimpl_->a2dp_session_metrics_.buffer_underruns_average);
- a2dp_session->set_buffer_underruns_count(
- pimpl_->a2dp_session_metrics_.buffer_underruns_count);
- a2dp_session->set_source_codec(
- get_a2dp_source_codec(pimpl_->a2dp_session_metrics_.codec_index));
- a2dp_session->set_is_a2dp_offload(
- pimpl_->a2dp_session_metrics_.is_a2dp_offload);
-}
-
-void BluetoothMetricsLogger::LogHeadsetProfileRfcConnection(
- tBTA_SERVICE_ID service_id) {
- std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
- switch (service_id) {
- case BTA_HSP_SERVICE_ID:
- pimpl_->headset_profile_connection_counts_[HeadsetProfileType::HSP]++;
- break;
- case BTA_HFP_SERVICE_ID:
- pimpl_->headset_profile_connection_counts_[HeadsetProfileType::HFP]++;
- break;
- default:
- pimpl_->headset_profile_connection_counts_
- [HeadsetProfileType::HEADSET_PROFILE_UNKNOWN]++;
- break;
- }
- return;
-}
-
-void BluetoothMetricsLogger::WriteString(std::string* serialized) {
- std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
- LOG_DEBUG(LOG_TAG, "%s building metrics", __func__);
- Build();
- LOG_DEBUG(LOG_TAG, "%s serializing metrics", __func__);
- if (!pimpl_->bluetooth_log_->SerializeToString(serialized)) {
- LOG_ERROR(LOG_TAG, "%s: error serializing metrics", __func__);
- }
- // Always clean up log objects
- pimpl_->bluetooth_log_->Clear();
-}
-
-void BluetoothMetricsLogger::WriteBase64String(std::string* serialized) {
- this->WriteString(serialized);
- base::Base64Encode(*serialized, serialized);
-}
-
-void BluetoothMetricsLogger::WriteBase64(int fd) {
- std::string protoBase64;
- this->WriteBase64String(&protoBase64);
- ssize_t ret;
- OSI_NO_INTR(ret = write(fd, protoBase64.c_str(), protoBase64.size()));
- if (ret == -1) {
- LOG_ERROR(LOG_TAG, "%s: error writing to dumpsys fd: %s (%d)", __func__,
- strerror(errno), errno);
- }
-}
-
-void BluetoothMetricsLogger::CutoffSession() {
- std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
- if (pimpl_->bluetooth_session_ != nullptr) {
- BluetoothSession* new_bt_session =
- new BluetoothSession(*pimpl_->bluetooth_session_);
- new_bt_session->clear_a2dp_session();
- new_bt_session->clear_rfcomm_session();
- LogBluetoothSessionEnd(DISCONNECT_REASON_METRICS_DUMP, 0);
- pimpl_->bluetooth_session_ = new_bt_session;
- pimpl_->bluetooth_session_start_time_ms_ = time_get_os_boottime_ms();
- pimpl_->a2dp_session_metrics_ = A2dpSessionMetrics();
- }
-}
-
-void BluetoothMetricsLogger::Build() {
- std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
- CutoffSession();
- BluetoothLog* bluetooth_log = pimpl_->bluetooth_log_;
- while (!pimpl_->bt_session_queue_->Empty() &&
- static_cast<size_t>(bluetooth_log->session_size()) <=
- pimpl_->bt_session_queue_->Capacity()) {
- bluetooth_log->mutable_session()->AddAllocated(
- pimpl_->bt_session_queue_->Dequeue());
- }
- while (!pimpl_->pair_event_queue_->Empty() &&
- static_cast<size_t>(bluetooth_log->pair_event_size()) <=
- pimpl_->pair_event_queue_->Capacity()) {
- bluetooth_log->mutable_pair_event()->AddAllocated(
- pimpl_->pair_event_queue_->Dequeue());
- }
- while (!pimpl_->scan_event_queue_->Empty() &&
- static_cast<size_t>(bluetooth_log->scan_event_size()) <=
- pimpl_->scan_event_queue_->Capacity()) {
- bluetooth_log->mutable_scan_event()->AddAllocated(
- pimpl_->scan_event_queue_->Dequeue());
- }
- while (!pimpl_->wake_event_queue_->Empty() &&
- static_cast<size_t>(bluetooth_log->wake_event_size()) <=
- pimpl_->wake_event_queue_->Capacity()) {
- bluetooth_log->mutable_wake_event()->AddAllocated(
- pimpl_->wake_event_queue_->Dequeue());
- }
- while (!pimpl_->bt_session_queue_->Empty() &&
- static_cast<size_t>(bluetooth_log->wake_event_size()) <=
- pimpl_->wake_event_queue_->Capacity()) {
- bluetooth_log->mutable_wake_event()->AddAllocated(
- pimpl_->wake_event_queue_->Dequeue());
- }
- for (size_t i = 0; i < HeadsetProfileType_ARRAYSIZE; ++i) {
- int num_times_connected = pimpl_->headset_profile_connection_counts_[i];
- if (HeadsetProfileType_IsValid(i) && num_times_connected > 0) {
- HeadsetProfileConnectionStats* headset_profile_connection_stats =
- bluetooth_log->add_headset_profile_connection_stats();
- // Able to static_cast because HeadsetProfileType_IsValid(i) is true
- headset_profile_connection_stats->set_headset_profile_type(
- static_cast<HeadsetProfileType>(i));
- headset_profile_connection_stats->set_num_times_connected(
- num_times_connected);
- }
- }
- pimpl_->headset_profile_connection_counts_.fill(0);
-}
-
-void BluetoothMetricsLogger::ResetSession() {
- std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
- if (pimpl_->bluetooth_session_ != nullptr) {
- delete pimpl_->bluetooth_session_;
- pimpl_->bluetooth_session_ = nullptr;
- }
- pimpl_->bluetooth_session_start_time_ms_ = 0;
- pimpl_->a2dp_session_metrics_ = A2dpSessionMetrics();
-}
-
-void BluetoothMetricsLogger::ResetLog() {
- std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
- pimpl_->bluetooth_log_->Clear();
-}
-
-void BluetoothMetricsLogger::Reset() {
- ResetSession();
- ResetLog();
- pimpl_->bt_session_queue_->Clear();
- pimpl_->pair_event_queue_->Clear();
- pimpl_->wake_event_queue_->Clear();
- pimpl_->scan_event_queue_->Clear();
-}
-
-} // namespace system_bt_osi
diff --git a/osi/src/metrics_linux.cc b/osi/src/metrics_linux.cc
deleted file mode 100644
index 162f4ca..0000000
--- a/osi/src/metrics_linux.cc
+++ /dev/null
@@ -1,204 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2016 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_osi_metrics"
-
-#include <unistd.h>
-#include <algorithm>
-#include <cerrno>
-#include <chrono>
-#include <cstdint>
-#include <cstring>
-#include <memory>
-#include <mutex>
-
-#include <base/base64.h>
-#include <base/logging.h>
-
-#include "osi/include/leaky_bonded_queue.h"
-#include "osi/include/log.h"
-#include "osi/include/osi.h"
-#include "osi/include/time.h"
-
-#include "osi/include/metrics.h"
-
-namespace system_bt_osi {
-
-// Maximum number of log entries for each repeated field
-#define MAX_NUM_BLUETOOTH_SESSION 50
-#define MAX_NUM_PAIR_EVENT 50
-#define MAX_NUM_WAKE_EVENT 50
-#define MAX_NUM_SCAN_EVENT 50
-
-static float combine_averages(float avg_a, int64_t ct_a, float avg_b,
- int64_t ct_b) {
- if (ct_a > 0 && ct_b > 0) {
- return (avg_a * ct_a + avg_b * ct_b) / (ct_a + ct_b);
- } else if (ct_b > 0) {
- return avg_b;
- } else {
- return avg_a;
- }
-}
-
-static int32_t combine_averages(int32_t avg_a, int64_t ct_a, int32_t avg_b,
- int64_t ct_b) {
- if (ct_a > 0 && ct_b > 0) {
- return (avg_a * ct_a + avg_b * ct_b) / (ct_a + ct_b);
- } else if (ct_b > 0) {
- return avg_b;
- } else {
- return avg_a;
- }
-}
-
-void A2dpSessionMetrics::Update(const A2dpSessionMetrics& metrics) {
- if (metrics.audio_duration_ms > 0) {
- audio_duration_ms = std::max(static_cast<int64_t>(0), audio_duration_ms);
- audio_duration_ms += metrics.audio_duration_ms;
- }
- if (metrics.media_timer_min_ms > 0) {
- if (media_timer_min_ms < 0) {
- media_timer_min_ms = metrics.media_timer_min_ms;
- } else {
- media_timer_min_ms =
- std::min(media_timer_min_ms, metrics.media_timer_min_ms);
- }
- }
- if (metrics.media_timer_max_ms > 0) {
- media_timer_max_ms =
- std::max(media_timer_max_ms, metrics.media_timer_max_ms);
- }
- if (metrics.media_timer_avg_ms > 0 && metrics.total_scheduling_count > 0) {
- if (media_timer_avg_ms < 0 || total_scheduling_count < 0) {
- media_timer_avg_ms = metrics.media_timer_avg_ms;
- total_scheduling_count = metrics.total_scheduling_count;
- } else {
- media_timer_avg_ms = combine_averages(
- media_timer_avg_ms, total_scheduling_count,
- metrics.media_timer_avg_ms, metrics.total_scheduling_count);
- total_scheduling_count += metrics.total_scheduling_count;
- }
- }
- if (metrics.buffer_overruns_max_count > 0) {
- buffer_overruns_max_count =
- std::max(buffer_overruns_max_count, metrics.buffer_overruns_max_count);
- }
- if (metrics.buffer_overruns_total > 0) {
- buffer_overruns_total =
- std::max(static_cast<int32_t>(0), buffer_overruns_total);
- buffer_overruns_total += metrics.buffer_overruns_total;
- }
- if (metrics.buffer_underruns_average > 0 &&
- metrics.buffer_underruns_count > 0) {
- if (buffer_underruns_average < 0 || buffer_underruns_count < 0) {
- buffer_underruns_average = metrics.buffer_underruns_average;
- buffer_underruns_count = metrics.buffer_underruns_count;
- } else {
- buffer_underruns_average = combine_averages(
- metrics.buffer_underruns_average, metrics.buffer_underruns_count,
- buffer_underruns_average, buffer_underruns_count);
- buffer_underruns_count += metrics.buffer_underruns_count;
- }
- }
-}
-
-bool A2dpSessionMetrics::operator==(const A2dpSessionMetrics& rhs) const {
- return audio_duration_ms == rhs.audio_duration_ms &&
- media_timer_min_ms == rhs.media_timer_min_ms &&
- media_timer_max_ms == rhs.media_timer_max_ms &&
- media_timer_avg_ms == rhs.media_timer_avg_ms &&
- total_scheduling_count == rhs.total_scheduling_count &&
- buffer_overruns_max_count == rhs.buffer_overruns_max_count &&
- buffer_overruns_total == rhs.buffer_overruns_total &&
- buffer_underruns_average == rhs.buffer_underruns_average &&
- buffer_underruns_count == rhs.buffer_underruns_count;
-}
-
-struct BluetoothMetricsLogger::impl {
- // TODO(siyuanh): Implement for linux
-};
-
-BluetoothMetricsLogger::BluetoothMetricsLogger() : pimpl_(new impl) {}
-
-void BluetoothMetricsLogger::LogPairEvent(uint32_t disconnect_reason,
- uint64_t timestamp_ms,
- uint32_t device_class,
- device_type_t device_type) {
- // TODO(siyuanh): Implement for linux
-}
-
-void BluetoothMetricsLogger::LogWakeEvent(wake_event_type_t type,
- const std::string& requestor,
- const std::string& name,
- uint64_t timestamp_ms) {
- // TODO(siyuanh): Implement for linux
-}
-
-void BluetoothMetricsLogger::LogScanEvent(bool start,
- const std::string& initator,
- scan_tech_t type, uint32_t results,
- uint64_t timestamp_ms) {
- // TODO(siyuanh): Implement for linux
-}
-
-void BluetoothMetricsLogger::LogBluetoothSessionStart(
- connection_tech_t connection_tech_type, uint64_t timestamp_ms) {
- // TODO(siyuanh): Implement for linux
-}
-
-void BluetoothMetricsLogger::LogBluetoothSessionEnd(
- disconnect_reason_t disconnect_reason, uint64_t timestamp_ms) {
- // TODO(siyuanh): Implement for linux
-}
-
-void BluetoothMetricsLogger::LogBluetoothSessionDeviceInfo(
- uint32_t device_class, device_type_t device_type) {
- // TODO(siyuanh): Implement for linux
-}
-
-void BluetoothMetricsLogger::LogA2dpSession(
- const A2dpSessionMetrics& a2dp_session_metrics) {
- // TODO(siyuanh): Implement for linux
-}
-
-void BluetoothMetricsLogger::WriteString(std::string* serialized, bool clear) {
- // TODO(siyuanh): Implement for linux
-}
-
-void BluetoothMetricsLogger::WriteBase64String(std::string* serialized,
- bool clear) {
- // TODO(siyuanh): Implement for linux
-}
-
-void BluetoothMetricsLogger::WriteBase64(int fd, bool clear) {
- // TODO(siyuanh): Implement for linux
-}
-
-void BluetoothMetricsLogger::CutoffSession() {
- // TODO(siyuanh): Implement for linux
-}
-
-void BluetoothMetricsLogger::Build() {
- // TODO(siyuanh): Implement for linux
-}
-
-void BluetoothMetricsLogger::Reset() {
- // TODO(siyuanh): Implement for linux
-}
-
-} // namespace system_bt_osi
diff --git a/osi/src/reactor.cc b/osi/src/reactor.cc
index ce1251c..7898170 100644
--- a/osi/src/reactor.cc
+++ b/osi/src/reactor.cc
@@ -72,7 +72,7 @@
ret->epoll_fd = INVALID_FD;
ret->event_fd = INVALID_FD;
- ret->epoll_fd = epoll_create(MAX_EVENTS);
+ ret->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
if (ret->epoll_fd == INVALID_FD) {
LOG_ERROR(LOG_TAG, "%s unable to create epoll instance: %s", __func__,
strerror(errno));
diff --git a/osi/src/time.cc b/osi/src/time.cc
deleted file mode 100644
index 1a47504..0000000
--- a/osi/src/time.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-/******************************************************************************
- *
- * Copyright 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_osi_time"
-
-#include <sys/time.h>
-#include <time.h>
-
-#include "osi/include/time.h"
-
-uint32_t time_get_os_boottime_ms(void) {
- return (uint32_t)(time_get_os_boottime_us() / 1000);
-}
-
-uint64_t time_get_os_boottime_us(void) {
- struct timespec ts_now;
- clock_gettime(CLOCK_BOOTTIME, &ts_now);
-
- return ((uint64_t)ts_now.tv_sec * 1000000L) +
- ((uint64_t)ts_now.tv_nsec / 1000);
-}
-
-uint64_t time_gettimeofday_us(void) {
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return static_cast<uint64_t>(tv.tv_sec) * 1000000ULL +
- static_cast<uint64_t>(tv.tv_usec);
-}
diff --git a/osi/src/wakelock.cc b/osi/src/wakelock.cc
index 46c462c..0f9a51b 100644
--- a/osi/src/wakelock.cc
+++ b/osi/src/wakelock.cc
@@ -34,15 +34,15 @@
#include <string>
#include "base/logging.h"
+#include "common/metrics.h"
#include "osi/include/alarm.h"
#include "osi/include/allocator.h"
#include "osi/include/log.h"
-#include "osi/include/metrics.h"
#include "osi/include/osi.h"
#include "osi/include/thread.h"
#include "osi/include/wakelock.h"
-using system_bt_osi::BluetoothMetricsLogger;
+using bluetooth::common::BluetoothMetricsLogger;
static bt_os_callouts_t* wakelock_os_callouts = NULL;
static bool is_native = true;
@@ -65,13 +65,13 @@
size_t released_count;
size_t acquired_errors;
size_t released_errors;
- period_ms_t min_acquired_interval_ms;
- period_ms_t max_acquired_interval_ms;
- period_ms_t last_acquired_interval_ms;
- period_ms_t total_acquired_interval_ms;
- period_ms_t last_acquired_timestamp_ms;
- period_ms_t last_released_timestamp_ms;
- period_ms_t last_reset_timestamp_ms;
+ uint64_t min_acquired_interval_ms;
+ uint64_t max_acquired_interval_ms;
+ uint64_t last_acquired_interval_ms;
+ uint64_t total_acquired_interval_ms;
+ uint64_t last_acquired_timestamp_ms;
+ uint64_t last_released_timestamp_ms;
+ uint64_t last_reset_timestamp_ms;
int last_acquired_error;
int last_released_error;
} wakelock_stats_t;
@@ -213,6 +213,10 @@
}
void wakelock_cleanup(void) {
+ if (wakelock_stats.is_acquired) {
+ LOG_ERROR(LOG_TAG, "%s releasing wake lock as part of cleanup", __func__);
+ wakelock_release();
+ }
wake_lock_path.clear();
wake_unlock_path.clear();
initialized = PTHREAD_ONCE_INIT;
@@ -224,7 +228,7 @@
if (unlock_path) wake_unlock_path = unlock_path;
}
-static period_ms_t now(void) {
+static uint64_t now_ms(void) {
struct timespec ts;
if (clock_gettime(CLOCK_ID, &ts) == -1) {
LOG_ERROR(LOG_TAG, "%s unable to get current time: %s", __func__,
@@ -251,7 +255,7 @@
wakelock_stats.total_acquired_interval_ms = 0;
wakelock_stats.last_acquired_timestamp_ms = 0;
wakelock_stats.last_released_timestamp_ms = 0;
- wakelock_stats.last_reset_timestamp_ms = now();
+ wakelock_stats.last_reset_timestamp_ms = now_ms();
}
//
@@ -263,7 +267,7 @@
// This function is thread-safe.
//
static void update_wakelock_acquired_stats(bt_status_t acquired_status) {
- const period_ms_t now_ms = now();
+ const uint64_t just_now_ms = now_ms();
std::lock_guard<std::mutex> lock(stats_mutex);
@@ -278,10 +282,10 @@
wakelock_stats.is_acquired = true;
wakelock_stats.acquired_count++;
- wakelock_stats.last_acquired_timestamp_ms = now_ms;
+ wakelock_stats.last_acquired_timestamp_ms = just_now_ms;
BluetoothMetricsLogger::GetInstance()->LogWakeEvent(
- system_bt_osi::WAKE_EVENT_ACQUIRED, "", "", now_ms);
+ bluetooth::common::WAKE_EVENT_ACQUIRED, "", "", just_now_ms);
}
//
@@ -293,7 +297,7 @@
// This function is thread-safe.
//
static void update_wakelock_released_stats(bt_status_t released_status) {
- const period_ms_t now_ms = now();
+ const uint64_t just_now_ms = now_ms();
std::lock_guard<std::mutex> lock(stats_mutex);
@@ -308,10 +312,10 @@
wakelock_stats.is_acquired = false;
wakelock_stats.released_count++;
- wakelock_stats.last_released_timestamp_ms = now_ms;
+ wakelock_stats.last_released_timestamp_ms = just_now_ms;
// Compute the acquired interval and update the statistics
- period_ms_t delta_ms = now_ms - wakelock_stats.last_acquired_timestamp_ms;
+ uint64_t delta_ms = just_now_ms - wakelock_stats.last_acquired_timestamp_ms;
if (delta_ms < wakelock_stats.min_acquired_interval_ms ||
wakelock_stats.released_count == 1) {
wakelock_stats.min_acquired_interval_ms = delta_ms;
@@ -323,32 +327,32 @@
wakelock_stats.total_acquired_interval_ms += delta_ms;
BluetoothMetricsLogger::GetInstance()->LogWakeEvent(
- system_bt_osi::WAKE_EVENT_RELEASED, "", "", now_ms);
+ bluetooth::common::WAKE_EVENT_RELEASED, "", "", just_now_ms);
}
void wakelock_debug_dump(int fd) {
- const period_ms_t now_ms = now();
+ const uint64_t just_now_ms = now_ms();
std::lock_guard<std::mutex> lock(stats_mutex);
// Compute the last acquired interval if the wakelock is still acquired
- period_ms_t delta_ms = 0;
- period_ms_t last_interval = wakelock_stats.last_acquired_interval_ms;
- period_ms_t min_interval = wakelock_stats.min_acquired_interval_ms;
- period_ms_t max_interval = wakelock_stats.max_acquired_interval_ms;
- period_ms_t ave_interval = 0;
+ uint64_t delta_ms = 0;
+ uint64_t last_interval_ms = wakelock_stats.last_acquired_interval_ms;
+ uint64_t min_interval_ms = wakelock_stats.min_acquired_interval_ms;
+ uint64_t max_interval_ms = wakelock_stats.max_acquired_interval_ms;
+ uint64_t avg_interval_ms = 0;
if (wakelock_stats.is_acquired) {
- delta_ms = now_ms - wakelock_stats.last_acquired_timestamp_ms;
- if (delta_ms > max_interval) max_interval = delta_ms;
- if (delta_ms < min_interval) min_interval = delta_ms;
- last_interval = delta_ms;
+ delta_ms = just_now_ms - wakelock_stats.last_acquired_timestamp_ms;
+ if (delta_ms > max_interval_ms) max_interval_ms = delta_ms;
+ if (delta_ms < min_interval_ms) min_interval_ms = delta_ms;
+ last_interval_ms = delta_ms;
}
- period_ms_t total_interval =
+ uint64_t total_interval_ms =
wakelock_stats.total_acquired_interval_ms + delta_ms;
if (wakelock_stats.acquired_count > 0)
- ave_interval = total_interval / wakelock_stats.acquired_count;
+ avg_interval_ms = total_interval_ms / wakelock_stats.acquired_count;
dprintf(fd, "\nBluetooth Wakelock Statistics:\n");
dprintf(fd, " Is acquired : %s\n",
@@ -361,13 +365,14 @@
wakelock_stats.last_acquired_error,
wakelock_stats.last_released_error);
dprintf(fd, " Last acquired time (ms) : %llu\n",
- (unsigned long long)last_interval);
+ (unsigned long long)last_interval_ms);
dprintf(fd, " Acquired time min/max/avg (ms) : %llu / %llu / %llu\n",
- (unsigned long long)min_interval, (unsigned long long)max_interval,
- (unsigned long long)ave_interval);
+ (unsigned long long)min_interval_ms,
+ (unsigned long long)max_interval_ms,
+ (unsigned long long)avg_interval_ms);
dprintf(fd, " Total acquired time (ms) : %llu\n",
- (unsigned long long)total_interval);
- dprintf(
- fd, " Total run time (ms) : %llu\n",
- (unsigned long long)(now_ms - wakelock_stats.last_reset_timestamp_ms));
+ (unsigned long long)total_interval_ms);
+ dprintf(fd, " Total run time (ms) : %llu\n",
+ (unsigned long long)(just_now_ms -
+ wakelock_stats.last_reset_timestamp_ms));
}
diff --git a/osi/test/alarm_mock.h b/osi/test/alarm_mock.h
new file mode 100644
index 0000000..44c1c9e
--- /dev/null
+++ b/osi/test/alarm_mock.h
@@ -0,0 +1,52 @@
+#pragma once
+#include <memory>
+
+struct alarm_t;
+
+class AlarmMock {
+ public:
+ MOCK_METHOD1(AlarmNew, alarm_t*(const char*));
+ MOCK_METHOD1(AlarmFree, void(alarm_t*));
+ MOCK_METHOD1(AlarmCancel, void(alarm_t*));
+ MOCK_METHOD4(AlarmSetOnMloop, void(alarm_t* alarm, uint64_t interval_ms,
+ alarm_callback_t cb, void* data));
+
+ alarm_t* AlarmNewImpl(const char* name) {
+ AlarmNew(name);
+ // We must return something from alarm_new in tests, if we just return null,
+ // unique_ptr will misbehave. Just reserve few bits they will be freed in
+ // AlarmFreeImpl
+ return (alarm_t*)new uint8_t[30];
+ }
+
+ void AlarmFreeImpl(alarm_t* alarm) {
+ uint8_t* ptr = (uint8_t*)alarm;
+ delete[] ptr;
+ return AlarmFree(alarm);
+ }
+
+ static inline AlarmMock* Get() {
+ if (!localAlarmMock) {
+ localAlarmMock = std::make_unique<AlarmMock>();
+ }
+ return localAlarmMock.get();
+ }
+
+ static inline void Reset() { localAlarmMock = std::make_unique<AlarmMock>(); }
+
+ private:
+ static std::unique_ptr<AlarmMock> localAlarmMock;
+};
+
+std::unique_ptr<AlarmMock> AlarmMock::localAlarmMock;
+
+alarm_t* alarm_new(const char* name) {
+ return AlarmMock::Get()->AlarmNewImpl(name);
+}
+
+void alarm_free(alarm_t* alarm) { AlarmMock::Get()->AlarmFreeImpl(alarm); }
+
+void alarm_set_on_mloop(alarm_t* alarm, uint64_t interval_ms,
+ alarm_callback_t cb, void* data) {
+ AlarmMock::Get()->AlarmSetOnMloop(alarm, interval_ms, cb, data);
+}
diff --git a/osi/test/alarm_test.cc b/osi/test/alarm_test.cc
index f7f473d..dbd63a0 100644
--- a/osi/test/alarm_test.cc
+++ b/osi/test/alarm_test.cc
@@ -22,14 +22,15 @@
#include "AlarmTestHarness.h"
+#include "common/message_loop_thread.h"
#include "osi/include/alarm.h"
#include "osi/include/fixed_queue.h"
#include "osi/include/osi.h"
#include "osi/include/semaphore.h"
-#include "osi/include/thread.h"
using base::Closure;
using base::TimeDelta;
+using bluetooth::common::MessageLoopThread;
static semaphore_t* semaphore;
static int cb_counter;
@@ -39,29 +40,13 @@
static void msleep(uint64_t ms) { usleep(ms * 1000); }
-base::MessageLoop* message_loop_;
-base::RunLoop* run_loop_;
-static semaphore_t* msg_loop_ready;
+static base::MessageLoop* message_loop_;
-void message_loop_run(UNUSED_ATTR void* context) {
- message_loop_ = new base::MessageLoop();
- run_loop_ = new base::RunLoop();
-
- semaphore_post(msg_loop_ready);
- run_loop_->Run();
-
- delete message_loop_;
- message_loop_ = nullptr;
-
- delete run_loop_;
- run_loop_ = nullptr;
-}
-
-base::MessageLoop* get_message_loop() { return message_loop_; }
+base::MessageLoop* get_main_message_loop() { return message_loop_; }
class AlarmTest : public AlarmTestHarness {
protected:
- virtual void SetUp() {
+ void SetUp() override {
AlarmTestHarness::SetUp();
cb_counter = 0;
cb_misordered_counter = 0;
@@ -69,7 +54,7 @@
semaphore = semaphore_new(0);
}
- virtual void TearDown() {
+ void TearDown() override {
semaphore_free(semaphore);
AlarmTestHarness::TearDown();
}
@@ -318,15 +303,12 @@
alarm_t* alarms[100];
// Initialize MesageLoop, and wait till it's initialized.
- msg_loop_ready = semaphore_new(0);
- thread_t* message_loop_thread_ = thread_new("btu message loop");
- if (!message_loop_thread_) {
+ MessageLoopThread message_loop_thread("btu message loop");
+ message_loop_thread.StartUp();
+ if (!message_loop_thread.IsRunning()) {
FAIL() << "unable to create btu message loop thread.";
}
-
- thread_post(message_loop_thread_, message_loop_run, nullptr);
- semaphore_wait(msg_loop_ready);
- semaphore_free(msg_loop_ready);
+ message_loop_ = message_loop_thread.message_loop();
for (int i = 0; i < 100; i++) {
const std::string alarm_name =
@@ -347,9 +329,7 @@
for (int i = 0; i < 100; i++) alarm_free(alarms[i]);
- message_loop_->task_runner()->PostTask(FROM_HERE,
- run_loop_->QuitWhenIdleClosure());
- thread_free(message_loop_thread_);
+ message_loop_thread.ShutDown();
EXPECT_FALSE(WakeLockHeld());
}
diff --git a/osi/test/config_test.cc b/osi/test/config_test.cc
index 58ce818..7c689c9 100644
--- a/osi/test/config_test.cc
+++ b/osi/test/config_test.cc
@@ -51,7 +51,7 @@
class ConfigTest : public AllocationTestHarness {
protected:
- virtual void SetUp() {
+ void SetUp() override {
AllocationTestHarness::SetUp();
FILE* fp = fopen(CONFIG_FILE, "wt");
fwrite(CONFIG_FILE_CONTENT, 1, sizeof(CONFIG_FILE_CONTENT), fp);
diff --git a/osi/test/future_test.cc b/osi/test/future_test.cc
index 26d319a..5e78739 100644
--- a/osi/test/future_test.cc
+++ b/osi/test/future_test.cc
@@ -20,9 +20,11 @@
#include "AllocationTestHarness.h"
+#include "common/message_loop_thread.h"
#include "osi/include/future.h"
#include "osi/include/osi.h"
-#include "osi/include/thread.h"
+
+using bluetooth::common::MessageLoopThread;
static const char* pass_back_data0 = "fancy a sandwich? it's a fancy sandwich";
static const char* pass_back_data1 =
@@ -38,12 +40,13 @@
future_t* future = future_new();
ASSERT_TRUE(future != NULL);
- thread_t* worker_thread = thread_new("worker thread");
- thread_post(worker_thread, post_to_future, future);
+ MessageLoopThread worker_thread("worker_thread");
+ worker_thread.StartUp();
+ worker_thread.DoInThread(FROM_HERE, base::Bind(post_to_future, future));
EXPECT_EQ(pass_back_data0, future_await(future));
- thread_free(worker_thread);
+ worker_thread.ShutDown();
}
TEST_F(FutureTest, test_future_immediate) {
diff --git a/osi/test/hash_map_utils_test.cc b/osi/test/hash_map_utils_test.cc
index 1e312d4..d5df2d7 100644
--- a/osi/test/hash_map_utils_test.cc
+++ b/osi/test/hash_map_utils_test.cc
@@ -27,8 +27,8 @@
class HashMapUtilsTest : public AllocationTestHarness {
protected:
- virtual void SetUp() { AllocationTestHarness::SetUp(); }
- virtual void TearDown() {
+ void SetUp() override { AllocationTestHarness::SetUp(); }
+ void TearDown() override {
map.clear();
AllocationTestHarness::TearDown();
}
diff --git a/osi/test/leaky_bonded_queue_test.cc b/osi/test/leaky_bonded_queue_test.cc
deleted file mode 100644
index 116676b..0000000
--- a/osi/test/leaky_bonded_queue_test.cc
+++ /dev/null
@@ -1,242 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2016 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 <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include <base/logging.h>
-
-#include "osi/include/leaky_bonded_queue.h"
-
-namespace testing {
-
-using system_bt_osi::LeakyBondedQueue;
-
-#define ITEM_EQ(a, b) \
- do { \
- EXPECT_EQ(a, b); \
- EXPECT_EQ((a)->index, (b)->index); \
- } while (0)
-
-class Item {
- public:
- Item(int i) { index = i; }
- virtual ~Item() {}
- int index;
-};
-
-class MockItem : public Item {
- public:
- MockItem(int i) : Item(i) {}
- ~MockItem() { Destruct(); }
- MOCK_METHOD0(Destruct, void());
-};
-
-TEST(LeakyBondedQueueTest, TestEnqueueDequeue) {
- MockItem* item1 = new MockItem(1);
- MockItem* item2 = new MockItem(2);
- MockItem* item3 = new MockItem(3);
- MockItem* item4 = new MockItem(4);
- LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(3);
- EXPECT_EQ(queue->Capacity(), static_cast<size_t>(3));
- EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
- queue->Enqueue(item1);
- EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
- queue->Enqueue(item2);
- EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
- queue->Enqueue(item3);
- EXPECT_EQ(queue->Length(), static_cast<size_t>(3));
- EXPECT_CALL(*item1, Destruct()).Times(1);
- queue->Enqueue(item4);
- EXPECT_EQ(queue->Length(), static_cast<size_t>(3));
- MockItem* item2_2 = queue->Dequeue();
- MockItem* item3_3 = queue->Dequeue();
- MockItem* item4_4 = queue->Dequeue();
- EXPECT_THAT(item2_2, NotNull());
- ITEM_EQ(item2_2, item2);
- EXPECT_THAT(item3_3, NotNull());
- ITEM_EQ(item3_3, item3);
- EXPECT_THAT(item4_4, NotNull());
- ITEM_EQ(item4_4, item4);
- LOG(INFO) << "All done release items";
- EXPECT_CALL(*item2_2, Destruct()).Times(1);
- delete item2_2;
- EXPECT_CALL(*item3_3, Destruct()).Times(1);
- delete item3_3;
- EXPECT_CALL(*item4_4, Destruct()).Times(1);
- delete item4_4;
- delete queue;
-}
-
-TEST(LeakyBondedQueueTest, TestEnqueueDequeue2) {
- MockItem* item1 = new MockItem(1);
- MockItem* item2 = new MockItem(2);
- MockItem* item3 = new MockItem(3);
- MockItem* item4 = new MockItem(4);
- LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(2);
- EXPECT_EQ(queue->Capacity(), static_cast<size_t>(2));
- EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
- queue->Enqueue(item1);
- EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
- MockItem* item1_1 = queue->Dequeue();
- ITEM_EQ(item1, item1_1);
- EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
- queue->Enqueue(item2);
- EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
- queue->Enqueue(item3);
- EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
- EXPECT_CALL(*item2, Destruct()).Times(1);
- queue->Enqueue(item4);
- EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
- EXPECT_CALL(*item3, Destruct()).Times(1);
- queue->Enqueue(item1);
- EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
- MockItem* item4_4_4 = queue->Dequeue();
- MockItem* item1_1_1 = queue->Dequeue();
- ITEM_EQ(item4_4_4, item4);
- ITEM_EQ(item1_1_1, item1);
- EXPECT_CALL(*item1_1_1, Destruct()).Times(1);
- delete item1_1_1;
- EXPECT_CALL(*item4_4_4, Destruct()).Times(1);
- delete item4_4_4;
- delete queue;
-}
-
-TEST(LeakyBondedQueueTest, TestEnqueuePop) {
- MockItem* item1 = new MockItem(1);
- MockItem* item2 = new MockItem(2);
- MockItem* item3 = new MockItem(3);
- MockItem* item4 = new MockItem(4);
- LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(2);
- EXPECT_EQ(queue->Capacity(), static_cast<size_t>(2));
- EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
- queue->Enqueue(item1);
- EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
- MockItem* item1_1 = queue->Dequeue();
- ITEM_EQ(item1, item1_1);
- EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
- queue->Enqueue(item2);
- EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
- queue->Enqueue(item3);
- EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
- MockItem* item2_2 = queue->EnqueueWithPop(item4);
- EXPECT_THAT(item2_2, NotNull());
- ITEM_EQ(item2_2, item2);
- EXPECT_CALL(*item2, Destruct()).Times(1);
- delete item2_2;
- EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
- MockItem* item3_3 = queue->EnqueueWithPop(item1);
- EXPECT_THAT(item3_3, NotNull());
- ITEM_EQ(item3_3, item3);
- EXPECT_CALL(*item3, Destruct()).Times(1);
- delete item3_3;
- EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
- MockItem* item4_4_4 = queue->Dequeue();
- MockItem* item1_1_1 = queue->Dequeue();
- ITEM_EQ(item4_4_4, item4);
- ITEM_EQ(item1_1_1, item1);
- EXPECT_CALL(*item1_1_1, Destruct()).Times(1);
- delete item1_1_1;
- EXPECT_CALL(*item4_4_4, Destruct()).Times(1);
- delete item4_4_4;
- delete queue;
-}
-
-TEST(LeakyBondedQueueTest, TestQueueClear) {
- MockItem* item1 = new MockItem(1);
- MockItem* item2 = new MockItem(2);
- MockItem* item3 = new MockItem(3);
- MockItem* item4 = new MockItem(4);
- LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(2);
- EXPECT_EQ(queue->Capacity(), static_cast<size_t>(2));
- EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
- queue->Enqueue(item1);
- EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
- MockItem* item1_1 = queue->Dequeue();
- ITEM_EQ(item1, item1_1);
- EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
- queue->Enqueue(item2);
- EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
- queue->Enqueue(item3);
- EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
- EXPECT_CALL(*item2, Destruct()).Times(1);
- queue->Enqueue(item4);
- EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
- EXPECT_CALL(*item3, Destruct()).Times(1);
- queue->Enqueue(item1);
- EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
- EXPECT_CALL(*item1, Destruct()).Times(1);
- EXPECT_CALL(*item4, Destruct()).Times(1);
- queue->Clear();
- delete queue;
-}
-
-TEST(LeakyBondedQueueTest, TestQueueFree) {
- MockItem* item1 = new MockItem(1);
- MockItem* item2 = new MockItem(2);
- MockItem* item3 = new MockItem(3);
- MockItem* item4 = new MockItem(4);
- LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(2);
- EXPECT_EQ(queue->Capacity(), static_cast<size_t>(2));
- EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
- queue->Enqueue(item1);
- EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
- MockItem* item1_1 = queue->Dequeue();
- ITEM_EQ(item1, item1_1);
- EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
- queue->Enqueue(item2);
- EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
- queue->Enqueue(item3);
- EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
- EXPECT_CALL(*item2, Destruct()).Times(1);
- queue->Enqueue(item4);
- EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
- EXPECT_CALL(*item3, Destruct()).Times(1);
- queue->Enqueue(item1);
- EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
- EXPECT_CALL(*item1, Destruct()).Times(1);
- EXPECT_CALL(*item4, Destruct()).Times(1);
- delete queue;
-}
-
-TEST(LeakyBondedQueueTest, TestPushNull) {
- MockItem* item1 = nullptr;
- LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(2);
- queue->Enqueue(item1);
- MockItem* item1_1 = queue->Dequeue();
- EXPECT_THAT(item1_1, IsNull());
-}
-
-TEST(LeakyBondedQueueTest, TestPushNullOverflowQueue) {
- MockItem* item1 = nullptr;
- MockItem* item2 = nullptr;
- LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(1);
- queue->Enqueue(item1);
- queue->Enqueue(item2);
- MockItem* item2_2 = queue->Dequeue();
- EXPECT_THAT(item2_2, IsNull());
-}
-
-TEST(LeakyBondedQueueTest, TestPushNullDeleteQueue) {
- MockItem* item1 = nullptr;
- MockItem* item2 = nullptr;
- LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(2);
- queue->Enqueue(item1);
- queue->Enqueue(item2);
- delete queue;
-}
-}
diff --git a/osi/test/metrics_test.cc b/osi/test/metrics_test.cc
deleted file mode 100644
index bfb548f..0000000
--- a/osi/test/metrics_test.cc
+++ /dev/null
@@ -1,1012 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2016 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 <chrono>
-#include <cstdint>
-#include <string>
-#include <thread>
-#include <vector>
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include <base/logging.h>
-#include <include/hardware/bt_av.h>
-
-#include "bluetooth/metrics/bluetooth.pb.h"
-#include "osi/include/metrics.h"
-#include "osi/include/time.h"
-
-#define BTM_COD_MAJOR_AUDIO_TEST 0x04
-
-namespace testing {
-
-using bluetooth::metrics::BluetoothMetricsProto::A2DPSession;
-using bluetooth::metrics::BluetoothMetricsProto::A2dpSourceCodec;
-using bluetooth::metrics::BluetoothMetricsProto::BluetoothLog;
-using bluetooth::metrics::BluetoothMetricsProto::BluetoothSession;
-using bluetooth::metrics::BluetoothMetricsProto::
- BluetoothSession_ConnectionTechnologyType;
-using bluetooth::metrics::BluetoothMetricsProto::
- BluetoothSession_DisconnectReasonType;
-using bluetooth::metrics::BluetoothMetricsProto::DeviceInfo;
-using bluetooth::metrics::BluetoothMetricsProto::DeviceInfo_DeviceType;
-using bluetooth::metrics::BluetoothMetricsProto::PairEvent;
-using bluetooth::metrics::BluetoothMetricsProto::RFCommSession;
-using bluetooth::metrics::BluetoothMetricsProto::ScanEvent;
-using bluetooth::metrics::BluetoothMetricsProto::ScanEvent_ScanTechnologyType;
-using bluetooth::metrics::BluetoothMetricsProto::ScanEvent_ScanEventType;
-using bluetooth::metrics::BluetoothMetricsProto::WakeEvent;
-using bluetooth::metrics::BluetoothMetricsProto::WakeEvent_WakeEventType;
-using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileType;
-using bluetooth::metrics::BluetoothMetricsProto::HeadsetProfileConnectionStats;
-using system_bt_osi::BluetoothMetricsLogger;
-using system_bt_osi::A2dpSessionMetrics;
-
-namespace {
-const size_t kMaxEventGenerationLimit = 5000;
-}
-
-/*
- * Get current OS boot time in ms
- */
-static int64_t time_get_os_boottime_ms(void) {
- return time_get_os_boottime_us() / 1000;
-}
-
-static void sleep_ms(int64_t t) {
- std::this_thread::sleep_for(std::chrono::milliseconds(t));
-}
-
-DeviceInfo* MakeDeviceInfo(int32_t device_class,
- DeviceInfo_DeviceType device_type) {
- DeviceInfo* info = new DeviceInfo();
- info->set_device_class(device_class);
- info->set_device_type(device_type);
- return info;
-}
-
-PairEvent* MakePairEvent(int32_t disconnect_reason, int64_t timestamp_ms,
- DeviceInfo* device_info) {
- PairEvent* event = new PairEvent();
- event->set_disconnect_reason(disconnect_reason);
- event->set_event_time_millis(timestamp_ms);
- if (device_info) event->set_allocated_device_paired_with(device_info);
- return event;
-}
-
-WakeEvent* MakeWakeEvent(WakeEvent_WakeEventType event_type,
- const std::string& requestor, const std::string& name,
- int64_t timestamp_ms) {
- WakeEvent* event = new WakeEvent();
- event->set_wake_event_type(event_type);
- event->set_requestor(requestor);
- event->set_name(name);
- event->set_event_time_millis(timestamp_ms);
- return event;
-}
-
-ScanEvent* MakeScanEvent(ScanEvent_ScanEventType event_type,
- const std::string& initiator,
- ScanEvent_ScanTechnologyType tech_type,
- int32_t num_results, int64_t timestamp_ms) {
- ScanEvent* event = new ScanEvent();
- event->set_scan_event_type(event_type);
- event->set_initiator(initiator);
- event->set_scan_technology_type(tech_type);
- event->set_number_results(num_results);
- event->set_event_time_millis(timestamp_ms);
- return event;
-}
-
-A2DPSession* MakeA2DPSession(const A2dpSessionMetrics& metrics,
- A2dpSourceCodec source_codec) {
- A2DPSession* session = new A2DPSession();
- session->set_media_timer_min_millis(metrics.media_timer_min_ms);
- session->set_media_timer_max_millis(metrics.media_timer_max_ms);
- session->set_media_timer_avg_millis(metrics.media_timer_avg_ms);
- session->set_buffer_overruns_max_count(metrics.buffer_overruns_max_count);
- session->set_buffer_overruns_total(metrics.buffer_overruns_total);
- session->set_buffer_underruns_average(metrics.buffer_underruns_average);
- session->set_buffer_underruns_count(metrics.buffer_underruns_count);
- session->set_audio_duration_millis(metrics.audio_duration_ms);
- session->set_source_codec(source_codec);
- session->set_is_a2dp_offload(metrics.is_a2dp_offload);
- return session;
-}
-
-BluetoothSession* MakeBluetoothSession(
- int64_t session_duration_sec,
- BluetoothSession_ConnectionTechnologyType conn_type,
- BluetoothSession_DisconnectReasonType disconnect_reason,
- DeviceInfo* device_info, RFCommSession* rfcomm_session,
- A2DPSession* a2dp_session) {
- BluetoothSession* session = new BluetoothSession();
- if (a2dp_session) session->set_allocated_a2dp_session(a2dp_session);
- if (rfcomm_session) session->set_allocated_rfcomm_session(rfcomm_session);
- if (device_info) session->set_allocated_device_connected_to(device_info);
- session->set_session_duration_sec(session_duration_sec);
- session->set_connection_technology_type(conn_type);
- session->set_disconnect_reason_type(disconnect_reason);
- return session;
-}
-
-BluetoothLog* MakeBluetoothLog(std::vector<BluetoothSession*> bt_sessions,
- std::vector<PairEvent*> pair_events,
- std::vector<WakeEvent*> wake_events,
- std::vector<ScanEvent*> scan_events) {
- BluetoothLog* bt_log = new BluetoothLog();
- for (BluetoothSession* session : bt_sessions) {
- bt_log->mutable_session()->AddAllocated(session);
- }
- bt_sessions.clear();
- for (PairEvent* event : pair_events) {
- bt_log->mutable_pair_event()->AddAllocated(event);
- }
- pair_events.clear();
- for (WakeEvent* event : wake_events) {
- bt_log->mutable_wake_event()->AddAllocated(event);
- }
- wake_events.clear();
- for (ScanEvent* event : scan_events) {
- bt_log->mutable_scan_event()->AddAllocated(event);
- }
- scan_events.clear();
- return bt_log;
-}
-
-void GenerateWakeEvents(size_t start, size_t end,
- std::vector<WakeEvent*>* wake_events) {
- for (size_t i = start; i < end; ++i) {
- wake_events->push_back(MakeWakeEvent(
- i % 2 == 0 ? WakeEvent_WakeEventType::WakeEvent_WakeEventType_ACQUIRED
- : WakeEvent_WakeEventType::WakeEvent_WakeEventType_RELEASED,
- "TEST_REQ", "TEST_NAME", i));
- }
-}
-
-#define COMPARE_A2DP_METRICS(a, b) \
- do { \
- EXPECT_EQ((a).audio_duration_ms, (b).audio_duration_ms); \
- EXPECT_EQ((a).media_timer_min_ms, (b).media_timer_min_ms); \
- EXPECT_EQ((a).media_timer_max_ms, (b).media_timer_max_ms); \
- EXPECT_EQ((a).media_timer_avg_ms, (b).media_timer_avg_ms); \
- EXPECT_EQ((a).total_scheduling_count, (b).total_scheduling_count); \
- EXPECT_EQ((a).buffer_overruns_max_count, (b).buffer_overruns_max_count); \
- EXPECT_EQ((a).buffer_overruns_total, (b).buffer_overruns_total); \
- EXPECT_THAT((a).buffer_underruns_average, \
- FloatNear((b).buffer_underruns_average, 0.01)); \
- (a).buffer_underruns_average = (b).buffer_underruns_average; \
- EXPECT_EQ((a).buffer_underruns_count, (b).buffer_underruns_count); \
- EXPECT_EQ((a).codec_index, (b).codec_index); \
- EXPECT_EQ((a).is_a2dp_offload, (b).is_a2dp_offload); \
- } while (0)
-
-/*
- * metrics_sum = metrics1 + metrics2
- */
-TEST(BluetoothA2DPSessionMetricsTest, TestUpdateNormal) {
- A2dpSessionMetrics metrics1;
- A2dpSessionMetrics metrics2;
- A2dpSessionMetrics metrics_sum;
- metrics1.audio_duration_ms = 10;
- metrics2.audio_duration_ms = 25;
- metrics_sum.audio_duration_ms = 35;
- metrics1.media_timer_min_ms = 10;
- metrics2.media_timer_min_ms = 25;
- metrics_sum.media_timer_min_ms = 10;
- metrics1.media_timer_max_ms = 100;
- metrics2.media_timer_max_ms = 200;
- metrics_sum.media_timer_max_ms = 200;
- metrics1.media_timer_avg_ms = 50;
- metrics1.total_scheduling_count = 50;
- metrics2.media_timer_avg_ms = 100;
- metrics2.total_scheduling_count = 50;
- metrics_sum.media_timer_avg_ms = 75;
- metrics_sum.total_scheduling_count = 100;
- metrics1.buffer_overruns_max_count = 70;
- metrics2.buffer_overruns_max_count = 80;
- metrics_sum.buffer_overruns_max_count = 80;
- metrics1.buffer_underruns_average = 80;
- metrics1.buffer_underruns_count = 1200;
- metrics2.buffer_underruns_average = 130;
- metrics2.buffer_underruns_count = 2400;
- metrics_sum.buffer_underruns_average = 113.33333333;
- metrics_sum.buffer_underruns_count = 3600;
- metrics1.codec_index = -1;
- metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
- metrics_sum.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
- metrics1.is_a2dp_offload = false;
- metrics2.is_a2dp_offload = true;
- metrics_sum.is_a2dp_offload = true;
- metrics1.Update(metrics2);
- COMPARE_A2DP_METRICS(metrics1, metrics_sum);
- EXPECT_TRUE(metrics1 == metrics_sum);
- EXPECT_EQ(metrics1, metrics_sum);
-}
-
-TEST(BluetoothA2DPSessionMetricsTest, TestUpdateNew) {
- A2dpSessionMetrics metrics1;
- A2dpSessionMetrics metrics2;
- A2dpSessionMetrics metrics_sum;
- metrics2.audio_duration_ms = 25;
- metrics_sum.audio_duration_ms = 25;
- metrics2.media_timer_min_ms = 25;
- metrics_sum.media_timer_min_ms = 25;
- metrics2.media_timer_max_ms = 200;
- metrics_sum.media_timer_max_ms = 200;
- metrics2.media_timer_avg_ms = 100;
- metrics2.total_scheduling_count = 50;
- metrics_sum.media_timer_avg_ms = 100;
- metrics_sum.total_scheduling_count = 50;
- metrics2.buffer_overruns_max_count = 80;
- metrics_sum.buffer_overruns_max_count = 80;
- metrics2.buffer_underruns_average = 130;
- metrics2.buffer_underruns_count = 2400;
- metrics_sum.buffer_underruns_average = 130;
- metrics_sum.buffer_underruns_count = 2400;
- metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_APTX;
- metrics_sum.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_APTX;
- metrics2.is_a2dp_offload = true;
- metrics_sum.is_a2dp_offload = true;
- metrics1.Update(metrics2);
- COMPARE_A2DP_METRICS(metrics1, metrics_sum);
- EXPECT_TRUE(metrics1 == metrics_sum);
- EXPECT_EQ(metrics1, metrics_sum);
-}
-
-TEST(BluetoothA2DPSessionMetricsTest, TestNullUpdate) {
- A2dpSessionMetrics metrics1;
- A2dpSessionMetrics metrics2;
- A2dpSessionMetrics metrics_sum;
- metrics2.audio_duration_ms = 25;
- metrics_sum.audio_duration_ms = 25;
- metrics2.media_timer_min_ms = 25;
- metrics_sum.media_timer_min_ms = 25;
- metrics2.media_timer_max_ms = 200;
- metrics_sum.media_timer_max_ms = 200;
- metrics2.media_timer_avg_ms = 100;
- metrics2.total_scheduling_count = 50;
- metrics_sum.media_timer_avg_ms = 100;
- metrics_sum.total_scheduling_count = 50;
- metrics2.buffer_overruns_max_count = 80;
- metrics_sum.buffer_overruns_max_count = 80;
- metrics2.buffer_underruns_average = 130;
- metrics2.buffer_underruns_count = 2400;
- metrics_sum.buffer_underruns_average = 130;
- metrics_sum.buffer_underruns_count = 2400;
- metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD;
- metrics_sum.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD;
- metrics2.is_a2dp_offload = true;
- metrics_sum.is_a2dp_offload = true;
- metrics2.Update(metrics1);
- COMPARE_A2DP_METRICS(metrics2, metrics_sum);
- EXPECT_TRUE(metrics2 == metrics_sum);
- EXPECT_EQ(metrics2, metrics_sum);
-}
-
-TEST(BluetoothA2DPSessionMetricsTest, TestPartialUpdate) {
- A2dpSessionMetrics metrics1;
- A2dpSessionMetrics metrics2;
- A2dpSessionMetrics metrics_sum;
- metrics1.audio_duration_ms = 10;
- metrics2.audio_duration_ms = 25;
- metrics_sum.audio_duration_ms = 35;
- metrics1.media_timer_min_ms = 10;
- metrics_sum.media_timer_min_ms = 10;
- metrics1.media_timer_max_ms = 100;
- metrics_sum.media_timer_max_ms = 100;
- metrics1.media_timer_avg_ms = 50;
- metrics1.total_scheduling_count = 50;
- metrics2.media_timer_avg_ms = 100;
- metrics_sum.media_timer_avg_ms = 50;
- metrics_sum.total_scheduling_count = 50;
- metrics1.buffer_overruns_max_count = 70;
- metrics_sum.buffer_overruns_max_count = 70;
- metrics1.buffer_underruns_average = 80;
- metrics1.buffer_underruns_count = 1200;
- metrics2.buffer_underruns_count = 2400;
- metrics_sum.buffer_underruns_average = 80;
- metrics_sum.buffer_underruns_count = 1200;
- metrics1.Update(metrics2);
- COMPARE_A2DP_METRICS(metrics1, metrics_sum);
- EXPECT_TRUE(metrics1 == metrics_sum);
- EXPECT_EQ(metrics1, metrics_sum);
-}
-
-class BluetoothMetricsLoggerTest : public Test {
- protected:
- // Use to hold test protos
- std::vector<PairEvent*> pair_events_;
- std::vector<WakeEvent*> wake_events_;
- std::vector<ScanEvent*> scan_events_;
- std::vector<BluetoothSession*> bt_sessions_;
- int64_t num_pair_event_ = 0;
- int64_t num_wake_event_ = 0;
- int64_t num_scan_event_ = 0;
- int64_t num_bt_session_ = 0;
- BluetoothLog* bt_log_;
- std::string bt_log_str_;
- std::string bt_log_ascii_str_;
-
- void UpdateLog() {
- for (BluetoothSession* session : bt_sessions_) {
- bt_log_->mutable_session()->AddAllocated(session);
- }
- if (num_bt_session_ > 0) {
- bt_log_->set_num_bluetooth_session(num_bt_session_);
- } else if (bt_sessions_.size() > 0) {
- bt_log_->set_num_bluetooth_session(bt_sessions_.size());
- }
- bt_sessions_.clear();
- for (PairEvent* event : pair_events_) {
- bt_log_->mutable_pair_event()->AddAllocated(event);
- }
- if (num_pair_event_ > 0) {
- bt_log_->set_num_pair_event(num_pair_event_);
- } else if (pair_events_.size() > 0) {
- bt_log_->set_num_pair_event(pair_events_.size());
- }
- pair_events_.clear();
- for (WakeEvent* event : wake_events_) {
- bt_log_->mutable_wake_event()->AddAllocated(event);
- }
- if (num_wake_event_ > 0) {
- bt_log_->set_num_wake_event(num_wake_event_);
- } else if (wake_events_.size() > 0) {
- bt_log_->set_num_wake_event(wake_events_.size());
- }
- wake_events_.clear();
- for (ScanEvent* event : scan_events_) {
- bt_log_->mutable_scan_event()->AddAllocated(event);
- }
- if (num_scan_event_ > 0) {
- bt_log_->set_num_scan_event(num_scan_event_);
- } else if (scan_events_.size() > 0) {
- bt_log_->set_num_scan_event(scan_events_.size());
- }
- scan_events_.clear();
- bt_log_->SerializeToString(&bt_log_str_);
- }
-
- void ClearLog() {
- for (BluetoothSession* session : bt_sessions_) {
- session->Clear();
- delete session;
- }
- bt_sessions_.clear();
- for (PairEvent* event : pair_events_) {
- event->Clear();
- delete event;
- }
- pair_events_.clear();
- for (WakeEvent* event : wake_events_) {
- event->Clear();
- delete event;
- }
- wake_events_.clear();
- for (ScanEvent* event : scan_events_) {
- event->Clear();
- delete event;
- }
- scan_events_.clear();
- bt_log_->Clear();
- }
-
- void SetUp() {
- bt_log_ = new BluetoothLog();
- // Clear existing metrics entries, if any
- BluetoothMetricsLogger::GetInstance()->Reset();
- }
- void TearDown() {
- // Clear remaining metrics entries, if any
- BluetoothMetricsLogger::GetInstance()->Reset();
- ClearLog();
- delete bt_log_;
- }
-
- public:
-};
-
-TEST_F(BluetoothMetricsLoggerTest, PairEventTest) {
- pair_events_.push_back(MakePairEvent(
- 35, 12345,
- MakeDeviceInfo(
- 42, DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR)));
- UpdateLog();
- BluetoothMetricsLogger::GetInstance()->LogPairEvent(
- 35, 12345, 42, system_bt_osi::DEVICE_TYPE_BREDR);
- std::string msg_str;
- BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
- EXPECT_THAT(msg_str, StrEq(bt_log_str_));
-}
-
-TEST_F(BluetoothMetricsLoggerTest, WakeEventTest) {
- wake_events_.push_back(
- MakeWakeEvent(WakeEvent_WakeEventType::WakeEvent_WakeEventType_ACQUIRED,
- "TEST_REQ", "TEST_NAME", 12345));
- UpdateLog();
- BluetoothMetricsLogger::GetInstance()->LogWakeEvent(
- system_bt_osi::WAKE_EVENT_ACQUIRED, "TEST_REQ", "TEST_NAME", 12345);
- std::string msg_str;
- BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
- EXPECT_THAT(msg_str, StrEq(bt_log_str_));
-}
-
-TEST_F(BluetoothMetricsLoggerTest, WakeEventOverrunTest) {
- GenerateWakeEvents(
- kMaxEventGenerationLimit - BluetoothMetricsLogger::kMaxNumWakeEvent,
- kMaxEventGenerationLimit, &wake_events_);
- num_wake_event_ = kMaxEventGenerationLimit;
- UpdateLog();
- for (size_t i = 0; i < kMaxEventGenerationLimit; ++i) {
- BluetoothMetricsLogger::GetInstance()->LogWakeEvent(
- i % 2 == 0 ? system_bt_osi::WAKE_EVENT_ACQUIRED
- : system_bt_osi::WAKE_EVENT_RELEASED,
- "TEST_REQ", "TEST_NAME", i);
- }
- std::string msg_str;
- BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
- EXPECT_THAT(msg_str, StrEq(bt_log_str_));
-}
-
-TEST_F(BluetoothMetricsLoggerTest, ScanEventTest) {
- scan_events_.push_back(MakeScanEvent(
- ScanEvent_ScanEventType::ScanEvent_ScanEventType_SCAN_EVENT_STOP,
- "TEST_INITIATOR", ScanEvent_ScanTechnologyType::
- ScanEvent_ScanTechnologyType_SCAN_TECH_TYPE_BREDR,
- 42, 123456));
- UpdateLog();
- BluetoothMetricsLogger::GetInstance()->LogScanEvent(
- false, "TEST_INITIATOR", system_bt_osi::SCAN_TECH_TYPE_BREDR, 42, 123456);
- std::string msg_str;
- BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
- EXPECT_THAT(msg_str, StrEq(bt_log_str_));
-}
-
-TEST_F(BluetoothMetricsLoggerTest, BluetoothSessionTest) {
- bt_sessions_.push_back(MakeBluetoothSession(
- 10,
- BluetoothSession_ConnectionTechnologyType::
- BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_LE,
- BluetoothSession_DisconnectReasonType::
- BluetoothSession_DisconnectReasonType_UNKNOWN,
- nullptr, nullptr, nullptr));
- UpdateLog();
- BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
- system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_LE, 123456);
- BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
- system_bt_osi::DISCONNECT_REASON_UNKNOWN, 133456);
- std::string msg_str;
- BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
- EXPECT_THAT(msg_str, StrEq(bt_log_str_));
-}
-
-TEST_F(BluetoothMetricsLoggerTest, BluetoothSessionDumpBeforeEndTest) {
- bt_sessions_.push_back(MakeBluetoothSession(
- 1,
- BluetoothSession_ConnectionTechnologyType::
- BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_LE,
- BluetoothSession_DisconnectReasonType::
- BluetoothSession_DisconnectReasonType_METRICS_DUMP,
- nullptr, nullptr, nullptr));
- UpdateLog();
- BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
- system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_LE, time_get_os_boottime_ms());
- sleep_ms(1000);
- std::string msg_str;
- BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
- EXPECT_THAT(msg_str, StrEq(bt_log_str_));
-}
-
-TEST_F(BluetoothMetricsLoggerTest, BluetoothSessionStartBeforeEndTest) {
- bt_sessions_.push_back(MakeBluetoothSession(
- 1,
- BluetoothSession_ConnectionTechnologyType::
- BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_UNKNOWN,
- BluetoothSession_DisconnectReasonType::
- BluetoothSession_DisconnectReasonType_NEXT_START_WITHOUT_END_PREVIOUS,
- nullptr, nullptr, nullptr));
- bt_sessions_.push_back(MakeBluetoothSession(
- 2,
- BluetoothSession_ConnectionTechnologyType::
- BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_LE,
- BluetoothSession_DisconnectReasonType::
- BluetoothSession_DisconnectReasonType_METRICS_DUMP,
- nullptr, nullptr, nullptr));
- UpdateLog();
- BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
- system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_UNKNOWN, 0);
- sleep_ms(1000);
- BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
- system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_LE, 0);
- sleep_ms(2000);
- std::string msg_str;
- BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
- EXPECT_THAT(msg_str, StrEq(bt_log_str_));
-}
-
-/*
- * Test Case: A2DPSessionTwoUpdatesTest
- *
- * 1. Create Instance
- * 2. LogBluetoothSessionStart
- * 3. LogBluetoothSessionDeviceInfo
- * 4. LogA2dpSession
- * 5. LogA2dpSession
- * 6. LogBluetoothSessionEnd
- * 7. WriteString
- *
- */
-TEST_F(BluetoothMetricsLoggerTest, A2DPSessionTwoUpdatesTest) {
- /* Same metrics from BluetoothA2DPSessionMetricsTest.TestUpdateNormal */
- A2dpSessionMetrics metrics1;
- A2dpSessionMetrics metrics2;
- A2dpSessionMetrics metrics_sum;
- metrics1.audio_duration_ms = 10;
- metrics2.audio_duration_ms = 25;
- metrics_sum.audio_duration_ms = 35;
- metrics1.media_timer_min_ms = 10;
- metrics2.media_timer_min_ms = 25;
- metrics_sum.media_timer_min_ms = 10;
- metrics1.media_timer_max_ms = 100;
- metrics2.media_timer_max_ms = 200;
- metrics_sum.media_timer_max_ms = 200;
- metrics1.media_timer_avg_ms = 50;
- metrics1.total_scheduling_count = 50;
- metrics2.media_timer_avg_ms = 100;
- metrics2.total_scheduling_count = 50;
- metrics_sum.media_timer_avg_ms = 75;
- metrics_sum.total_scheduling_count = 100;
- metrics1.buffer_overruns_max_count = 70;
- metrics2.buffer_overruns_max_count = 80;
- metrics_sum.buffer_overruns_max_count = 80;
- metrics1.buffer_underruns_average = 80;
- metrics1.buffer_underruns_count = 1200;
- metrics2.buffer_underruns_average = 130;
- metrics2.buffer_underruns_count = 2400;
- metrics_sum.buffer_underruns_average = 113.33333333;
- metrics_sum.buffer_underruns_count = 3600;
- metrics1.codec_index = -1;
- metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
- metrics_sum.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
- metrics1.is_a2dp_offload = false;
- metrics2.is_a2dp_offload = true;
- metrics_sum.is_a2dp_offload = true;
- DeviceInfo* info = MakeDeviceInfo(
- BTM_COD_MAJOR_AUDIO_TEST,
- DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
- A2DPSession* session =
- MakeA2DPSession(metrics_sum, A2dpSourceCodec::A2DP_SOURCE_CODEC_AAC);
- bt_sessions_.push_back(MakeBluetoothSession(
- 10,
- BluetoothSession_ConnectionTechnologyType::
- BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
- BluetoothSession_DisconnectReasonType::
- BluetoothSession_DisconnectReasonType_UNKNOWN,
- info, nullptr, session));
- UpdateLog();
- BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
- system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_BREDR, 123456);
- BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionDeviceInfo(
- BTM_COD_MAJOR_AUDIO_TEST, system_bt_osi::DEVICE_TYPE_BREDR);
- BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics1);
- BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics2);
- BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
- system_bt_osi::DISCONNECT_REASON_UNKNOWN, 133456);
- std::string msg_str;
- BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
- EXPECT_THAT(msg_str, StrEq(bt_log_str_));
-}
-
-/*
- * Test Case: A2DPSessionTwoUpdatesSeparatedbyDumpTest
- *
- * 1. Create Instance
- * 2. LogBluetoothSessionStart
- * 3. LogBluetoothSessionDeviceInfo
- * 4. LogA2dpSession
- * 5. WriteString
- * 6. LogA2dpSession
- * 7. LogBluetoothSessionEnd
- * 8. WriteString
- *
- */
-TEST_F(BluetoothMetricsLoggerTest, A2DPSessionTwoUpdatesSeparatedbyDumpTest) {
- /* Same metrics from BluetoothA2DPSessionMetricsTest.TestUpdateNormal */
- A2dpSessionMetrics metrics1;
- A2dpSessionMetrics metrics2;
- metrics1.audio_duration_ms = 10;
- metrics2.audio_duration_ms = 25;
- metrics1.media_timer_min_ms = 10;
- metrics2.media_timer_min_ms = 25;
- metrics1.media_timer_max_ms = 100;
- metrics2.media_timer_max_ms = 200;
- metrics1.media_timer_avg_ms = 50;
- metrics1.total_scheduling_count = 50;
- metrics2.media_timer_avg_ms = 100;
- metrics2.total_scheduling_count = 50;
- metrics1.buffer_overruns_max_count = 70;
- metrics2.buffer_overruns_max_count = 80;
- metrics1.buffer_underruns_average = 80;
- metrics1.buffer_underruns_count = 1200;
- metrics2.buffer_underruns_average = 130;
- metrics2.buffer_underruns_count = 2400;
- metrics1.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_SBC;
- metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
- DeviceInfo* info = MakeDeviceInfo(
- BTM_COD_MAJOR_AUDIO_TEST,
- DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
- A2DPSession* session =
- MakeA2DPSession(metrics1, A2dpSourceCodec::A2DP_SOURCE_CODEC_SBC);
- bt_sessions_.push_back(MakeBluetoothSession(
- 1,
- BluetoothSession_ConnectionTechnologyType::
- BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
- BluetoothSession_DisconnectReasonType::
- BluetoothSession_DisconnectReasonType_METRICS_DUMP,
- info, nullptr, session));
- UpdateLog();
- BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
- system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
- BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionDeviceInfo(
- BTM_COD_MAJOR_AUDIO_TEST, system_bt_osi::DEVICE_TYPE_BREDR);
- BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics1);
- sleep_ms(1000);
- std::string msg_str;
- BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
- EXPECT_THAT(msg_str, StrEq(bt_log_str_));
- ClearLog();
- info = MakeDeviceInfo(
- BTM_COD_MAJOR_AUDIO_TEST,
- DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
- session = MakeA2DPSession(metrics2, A2dpSourceCodec::A2DP_SOURCE_CODEC_AAC);
- bt_sessions_.push_back(MakeBluetoothSession(
- 1,
- BluetoothSession_ConnectionTechnologyType::
- BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
- BluetoothSession_DisconnectReasonType::
- BluetoothSession_DisconnectReasonType_UNKNOWN,
- info, nullptr, session));
- UpdateLog();
- sleep_ms(1000);
- BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics2);
- BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
- system_bt_osi::DISCONNECT_REASON_UNKNOWN, 0);
- msg_str.clear();
- BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
- EXPECT_THAT(msg_str, StrEq(bt_log_str_));
-}
-
-/*
- * Test Case: A2DPSessionTwoUpdatesSeparatedbyEndTest
- *
- * 1. Create Instance
- * 2. LogBluetoothSessionStart
- * 3. LogA2dpSession
- * 4. LogBluetoothSessionEnd
- * 5. LogBluetoothSessionStart
- * 6. LogA2dpSession
- * 7. LogBluetoothSessionEnd
- * 8. WriteString
- *
- */
-TEST_F(BluetoothMetricsLoggerTest, A2DPSessionTwoUpdatesSeparatedbyEndTest) {
- /* Same metrics from BluetoothA2DPSessionMetricsTest.TestUpdateNormal */
- A2dpSessionMetrics metrics1;
- metrics1.audio_duration_ms = 10;
- metrics1.media_timer_min_ms = 10;
- metrics1.media_timer_max_ms = 100;
- metrics1.media_timer_avg_ms = 50;
- metrics1.total_scheduling_count = 50;
- metrics1.buffer_overruns_max_count = 70;
- metrics1.buffer_underruns_average = 80;
- metrics1.buffer_underruns_count = 1200;
- metrics1.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_SBC;
- DeviceInfo* info = MakeDeviceInfo(
- BTM_COD_MAJOR_AUDIO_TEST,
- DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
- A2DPSession* session =
- MakeA2DPSession(metrics1, A2dpSourceCodec::A2DP_SOURCE_CODEC_SBC);
- bt_sessions_.push_back(MakeBluetoothSession(
- 1,
- BluetoothSession_ConnectionTechnologyType::
- BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
- BluetoothSession_DisconnectReasonType::
- BluetoothSession_DisconnectReasonType_UNKNOWN,
- info, nullptr, session));
- UpdateLog();
- BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
- system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
- BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionDeviceInfo(
- BTM_COD_MAJOR_AUDIO_TEST, system_bt_osi::DEVICE_TYPE_BREDR);
- BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics1);
- sleep_ms(1000);
- BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
- system_bt_osi::DISCONNECT_REASON_UNKNOWN, 0);
- std::string msg_str;
- BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
- EXPECT_THAT(msg_str, StrEq(bt_log_str_));
- ClearLog();
- A2dpSessionMetrics metrics2;
- metrics2.audio_duration_ms = 25;
- metrics2.media_timer_min_ms = 25;
- metrics2.media_timer_max_ms = 200;
- metrics2.media_timer_avg_ms = 100;
- metrics2.total_scheduling_count = 50;
- metrics2.buffer_overruns_max_count = 80;
- metrics2.buffer_underruns_average = 130;
- metrics2.buffer_underruns_count = 2400;
- metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
- session = MakeA2DPSession(metrics2, A2dpSourceCodec::A2DP_SOURCE_CODEC_AAC);
- bt_sessions_.push_back(MakeBluetoothSession(
- 1,
- BluetoothSession_ConnectionTechnologyType::
- BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
- BluetoothSession_DisconnectReasonType::
- BluetoothSession_DisconnectReasonType_UNKNOWN,
- nullptr, nullptr, session));
- UpdateLog();
- BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
- system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
- sleep_ms(1000);
- BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics2);
- BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
- system_bt_osi::DISCONNECT_REASON_UNKNOWN, 0);
- msg_str.clear();
- BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
- EXPECT_THAT(msg_str, StrEq(bt_log_str_));
-}
-
-/*
- * Test Case 1: A2DPSessionOnlyTest
- *
- * 1. Create Instance
- * 4. LogA2dpSession
- * 5. WriteString
- * 6. LogA2dpSession
- * 8. WriteString
- *
- */
-TEST_F(BluetoothMetricsLoggerTest, A2DPSessionOnlyTest) {
- /* Same metrics from BluetoothA2DPSessionMetricsTest.TestUpdateNormal */
- A2dpSessionMetrics metrics1;
- A2dpSessionMetrics metrics2;
- A2dpSessionMetrics metrics_sum;
- metrics1.audio_duration_ms = 10;
- metrics2.audio_duration_ms = 25;
- metrics_sum.audio_duration_ms = 35;
- metrics1.media_timer_min_ms = 10;
- metrics2.media_timer_min_ms = 25;
- metrics_sum.media_timer_min_ms = 10;
- metrics1.media_timer_max_ms = 100;
- metrics2.media_timer_max_ms = 200;
- metrics_sum.media_timer_max_ms = 200;
- metrics1.media_timer_avg_ms = 50;
- metrics1.total_scheduling_count = 50;
- metrics2.media_timer_avg_ms = 100;
- metrics2.total_scheduling_count = 50;
- metrics_sum.media_timer_avg_ms = 75;
- metrics_sum.total_scheduling_count = 100;
- metrics1.buffer_overruns_max_count = 70;
- metrics2.buffer_overruns_max_count = 80;
- metrics_sum.buffer_overruns_max_count = 80;
- metrics1.buffer_underruns_average = 80;
- metrics1.buffer_underruns_count = 1200;
- metrics2.buffer_underruns_average = 130;
- metrics2.buffer_underruns_count = 2400;
- metrics_sum.buffer_underruns_average = 113.33333333;
- metrics_sum.buffer_underruns_count = 3600;
- metrics1.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_SBC;
- metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
- metrics_sum.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_SBC;
- DeviceInfo* info = MakeDeviceInfo(
- BTM_COD_MAJOR_AUDIO_TEST,
- DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
- A2DPSession* session =
- MakeA2DPSession(metrics_sum, A2dpSourceCodec::A2DP_SOURCE_CODEC_SBC);
- bt_sessions_.push_back(MakeBluetoothSession(
- 1,
- BluetoothSession_ConnectionTechnologyType::
- BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
- BluetoothSession_DisconnectReasonType::
- BluetoothSession_DisconnectReasonType_METRICS_DUMP,
- info, nullptr, session));
- UpdateLog();
- BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics1);
- BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics2);
- sleep_ms(1000);
- std::string msg_str;
- BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
- EXPECT_THAT(msg_str, StrEq(bt_log_str_));
-}
-
-/*
- * Test Case: A2DPSessionDumpBeforeTwoUpdatesTest
- *
- * 1. Create Instance
- * 2. LogBluetoothSessionStart
- * 3. LogBluetoothSessionDeviceInfo
- * 5. WriteString
- * 6. LogA2dpSession
- * 7. LogA2dpSession
- * 8. LogBluetoothSessionEnd
- * 9. WriteString
- *
- */
-TEST_F(BluetoothMetricsLoggerTest, A2DPSessionDumpBeforeTwoUpdatesTest) {
- /* Same metrics from BluetoothA2DPSessionMetricsTest.TestUpdateNormal */
- A2dpSessionMetrics metrics1;
- A2dpSessionMetrics metrics2;
- A2dpSessionMetrics metrics_sum;
- metrics1.audio_duration_ms = 10;
- metrics2.audio_duration_ms = 25;
- metrics_sum.audio_duration_ms = 35;
- metrics1.media_timer_min_ms = 10;
- metrics2.media_timer_min_ms = 25;
- metrics_sum.media_timer_min_ms = 10;
- metrics1.media_timer_max_ms = 100;
- metrics2.media_timer_max_ms = 200;
- metrics_sum.media_timer_max_ms = 200;
- metrics1.media_timer_avg_ms = 50;
- metrics1.total_scheduling_count = 50;
- metrics2.media_timer_avg_ms = 100;
- metrics2.total_scheduling_count = 50;
- metrics_sum.media_timer_avg_ms = 75;
- metrics_sum.total_scheduling_count = 100;
- metrics1.buffer_overruns_max_count = 70;
- metrics2.buffer_overruns_max_count = 80;
- metrics_sum.buffer_overruns_max_count = 80;
- metrics1.buffer_underruns_average = 80;
- metrics1.buffer_underruns_count = 1200;
- metrics2.buffer_underruns_average = 130;
- metrics2.buffer_underruns_count = 2400;
- metrics_sum.buffer_underruns_average = 113.33333333;
- metrics_sum.buffer_underruns_count = 3600;
- metrics1.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_SBC;
- metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
- metrics_sum.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_SBC;
- DeviceInfo* info = MakeDeviceInfo(
- BTM_COD_MAJOR_AUDIO_TEST,
- DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
- bt_sessions_.push_back(MakeBluetoothSession(
- 1,
- BluetoothSession_ConnectionTechnologyType::
- BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
- BluetoothSession_DisconnectReasonType::
- BluetoothSession_DisconnectReasonType_METRICS_DUMP,
- info, nullptr, nullptr));
- UpdateLog();
- BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
- system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
- BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionDeviceInfo(
- BTM_COD_MAJOR_AUDIO_TEST, system_bt_osi::DEVICE_TYPE_BREDR);
- sleep_ms(1000);
- std::string msg_str;
- BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
- EXPECT_THAT(msg_str, StrEq(bt_log_str_));
- ClearLog();
- info = MakeDeviceInfo(
- BTM_COD_MAJOR_AUDIO_TEST,
- DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
- A2DPSession* session =
- MakeA2DPSession(metrics_sum, A2dpSourceCodec::A2DP_SOURCE_CODEC_SBC);
- bt_sessions_.push_back(MakeBluetoothSession(
- 1,
- BluetoothSession_ConnectionTechnologyType::
- BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
- BluetoothSession_DisconnectReasonType::
- BluetoothSession_DisconnectReasonType_UNKNOWN,
- info, nullptr, session));
- UpdateLog();
- BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics1);
- BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics2);
- sleep_ms(1000);
- BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
- system_bt_osi::DISCONNECT_REASON_UNKNOWN, 0);
- msg_str.clear();
- BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
- EXPECT_THAT(msg_str, StrEq(bt_log_str_));
-}
-
-TEST_F(BluetoothMetricsLoggerTest, LogHeadsetProfileRfcConnectionTest) {
- BluetoothMetricsLogger::GetInstance()->LogHeadsetProfileRfcConnection(
- BTA_HSP_SERVICE_ID);
- BluetoothMetricsLogger::GetInstance()->LogHeadsetProfileRfcConnection(
- BTA_HFP_SERVICE_ID);
- BluetoothMetricsLogger::GetInstance()->LogHeadsetProfileRfcConnection(
- BTA_HFP_SERVICE_ID);
- std::string msg_str;
- BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
- BluetoothLog* metrics = BluetoothLog::default_instance().New();
- metrics->ParseFromString(msg_str);
- EXPECT_EQ(metrics->headset_profile_connection_stats_size(), 2);
- bool hfp_correct = false;
- bool hsp_correct = false;
- for (const HeadsetProfileConnectionStats& headset_profile_connection_stats :
- metrics->headset_profile_connection_stats()) {
- switch (headset_profile_connection_stats.headset_profile_type()) {
- case HeadsetProfileType::HFP:
- EXPECT_EQ(headset_profile_connection_stats.num_times_connected(), 2);
- hfp_correct = true;
- break;
- case HeadsetProfileType::HSP:
- EXPECT_EQ(headset_profile_connection_stats.num_times_connected(), 1);
- hsp_correct = true;
- break;
- default:
- FAIL();
- }
- }
- EXPECT_TRUE(hfp_correct);
- EXPECT_TRUE(hsp_correct);
- metrics->clear_headset_profile_connection_stats();
- EXPECT_EQ(metrics->headset_profile_connection_stats_size(), 0);
- msg_str.clear();
- // Verify that dump after clean up result in an empty list
- BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
- metrics->ParseFromString(msg_str);
- EXPECT_EQ(metrics->headset_profile_connection_stats_size(), 0);
- delete metrics;
-}
-
-TEST_F(BluetoothMetricsLoggerTest, LogHeadsetProfileRfcConnectionErrorTest) {
- BluetoothMetricsLogger::GetInstance()->LogHeadsetProfileRfcConnection(
- BTA_HSP_SERVICE_ID);
- BluetoothMetricsLogger::GetInstance()->LogHeadsetProfileRfcConnection(
- BTA_HFP_SERVICE_ID);
- BluetoothMetricsLogger::GetInstance()->LogHeadsetProfileRfcConnection(
- BTA_BIP_SERVICE_ID);
- BluetoothMetricsLogger::GetInstance()->LogHeadsetProfileRfcConnection(
- BTA_HSP_SERVICE_ID);
- std::string msg_str;
- BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
- BluetoothLog* metrics = BluetoothLog::default_instance().New();
- metrics->ParseFromString(msg_str);
- EXPECT_EQ(metrics->headset_profile_connection_stats_size(), 3);
- bool hfp_correct = false;
- bool hsp_correct = false;
- bool unknown_correct = false;
- for (const HeadsetProfileConnectionStats& headset_profile_connection_stats :
- metrics->headset_profile_connection_stats()) {
- switch (headset_profile_connection_stats.headset_profile_type()) {
- case HeadsetProfileType::HFP:
- EXPECT_EQ(headset_profile_connection_stats.num_times_connected(), 1);
- hfp_correct = true;
- break;
- case HeadsetProfileType::HSP:
- EXPECT_EQ(headset_profile_connection_stats.num_times_connected(), 2);
- hsp_correct = true;
- break;
- default:
- EXPECT_EQ(headset_profile_connection_stats.num_times_connected(), 1);
- unknown_correct = true;
- break;
- }
- }
- EXPECT_TRUE(hfp_correct);
- EXPECT_TRUE(hsp_correct);
- EXPECT_TRUE(unknown_correct);
- metrics->clear_headset_profile_connection_stats();
- EXPECT_EQ(metrics->headset_profile_connection_stats_size(), 0);
- // Verify that dump after clean up result in an empty list
- BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
- metrics->ParseFromString(msg_str);
- EXPECT_EQ(metrics->headset_profile_connection_stats_size(), 0);
- delete metrics;
-}
-}
diff --git a/osi/test/semaphore_test.cc b/osi/test/semaphore_test.cc
index 44aee8d..54046a8 100644
--- a/osi/test/semaphore_test.cc
+++ b/osi/test/semaphore_test.cc
@@ -6,10 +6,12 @@
#include <sys/select.h>
#include <unistd.h>
+#include "common/message_loop_thread.h"
#include "osi/include/osi.h"
#include "osi/include/reactor.h"
#include "osi/include/semaphore.h"
-#include "osi/include/thread.h"
+
+using bluetooth::common::MessageLoopThread;
struct SemaphoreTestSequenceHelper {
semaphore_t* semaphore;
@@ -71,16 +73,18 @@
TEST_F(SemaphoreTest, test_ensure_wait) {
semaphore_t* semaphore = semaphore_new(0);
ASSERT_TRUE(semaphore != NULL);
- thread_t* thread = thread_new("semaphore_test_thread");
- ASSERT_TRUE(thread != NULL);
+ MessageLoopThread thread("semaphore_test_thread");
+ thread.StartUp();
+ ASSERT_TRUE(thread.IsRunning());
EXPECT_FALSE(semaphore_try_wait(semaphore));
SemaphoreTestSequenceHelper sequence_helper = {semaphore, 0};
- thread_post(thread, sleep_then_increment_counter, &sequence_helper);
+ thread.DoInThread(FROM_HERE,
+ base::Bind(sleep_then_increment_counter, &sequence_helper));
semaphore_wait(semaphore);
EXPECT_EQ(sequence_helper.counter, 1)
<< "semaphore_wait() did not wait for counter to increment";
semaphore_free(semaphore);
- thread_free(thread);
+ thread.ShutDown();
}
diff --git a/osi/test/time_test.cc b/osi/test/time_test.cc
deleted file mode 100644
index f14842d..0000000
--- a/osi/test/time_test.cc
+++ /dev/null
@@ -1,154 +0,0 @@
-/******************************************************************************
- *
- * Copyright 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 <gtest/gtest.h>
-
-#include "AllocationTestHarness.h"
-
-#include "osi/include/time.h"
-
-// Generous upper bound: 10 seconds
-static const uint32_t TEST_TIME_DELTA_UPPER_BOUND_MS = 10 * 1000;
-
-class TimeTest : public AllocationTestHarness {};
-
-//
-// Test that the return value of time_get_os_boottime_ms() is not zero.
-//
-// NOTE: For now this test is disabled, because the return value
-// of time_get_os_boottime_ms() is 32-bits integer that could wrap-around
-// in 49.7 days. It should be re-enabled if/after the wrap-around issue
-// is resolved (e.g., if the return value is 64-bits integer).
-//
-#if 0
-TEST_F(TimeTest, test_time_get_os_boottime_ms_not_zero) {
- uint32_t t1 = time_get_os_boottime_ms();
- ASSERT_TRUE(t1 > 0);
-}
-#endif
-
-//
-// Test that the return value of time_get_os_boottime_us() is not zero.
-//
-TEST_F(TimeTest, test_time_get_os_boottime_us_not_zero) {
- uint64_t t1 = time_get_os_boottime_us();
- ASSERT_TRUE(t1 > 0);
-}
-
-//
-// Test that the return value of time_get_os_boottime_ms()
-// is monotonically increasing within reasonable boundries.
-//
-TEST_F(TimeTest, test_time_get_os_boottime_ms_increases_upper_bound) {
- uint32_t t1 = time_get_os_boottime_ms();
- uint32_t t2 = time_get_os_boottime_ms();
- ASSERT_TRUE((t2 - t1) < TEST_TIME_DELTA_UPPER_BOUND_MS);
-}
-
-//
-// Test that the return value of time_get_os_boottime_us()
-// is monotonically increasing within reasonable boundries.
-//
-TEST_F(TimeTest, test_time_get_os_boottime_us_increases_upper_bound) {
- uint64_t t1 = time_get_os_boottime_us();
- uint64_t t2 = time_get_os_boottime_us();
- ASSERT_TRUE((t2 - t1) < TEST_TIME_DELTA_UPPER_BOUND_MS * 1000);
-}
-
-//
-// Test that the return value of time_get_os_boottime_ms()
-// is increasing.
-//
-TEST_F(TimeTest, test_time_get_os_boottime_ms_increases_lower_bound) {
- static const uint32_t TEST_TIME_SLEEP_MS = 100;
- struct timespec delay;
-
- delay.tv_sec = TEST_TIME_SLEEP_MS / 1000;
- delay.tv_nsec = 1000 * 1000 * (TEST_TIME_SLEEP_MS % 1000);
-
- // Take two timestamps with sleep in-between
- uint32_t t1 = time_get_os_boottime_ms();
- int err = nanosleep(&delay, &delay);
- uint32_t t2 = time_get_os_boottime_ms();
-
- ASSERT_TRUE(err == 0);
- ASSERT_TRUE((t2 - t1) >= TEST_TIME_SLEEP_MS);
- ASSERT_TRUE((t2 - t1) < TEST_TIME_DELTA_UPPER_BOUND_MS);
-}
-
-//
-// Test that the return value of time_get_os_boottime_us()
-// is increasing.
-//
-TEST_F(TimeTest, test_time_get_os_boottime_us_increases_lower_bound) {
- static const uint64_t TEST_TIME_SLEEP_US = 100 * 1000;
- struct timespec delay;
-
- delay.tv_sec = TEST_TIME_SLEEP_US / (1000 * 1000);
- delay.tv_nsec = 1000 * (TEST_TIME_SLEEP_US % (1000 * 1000));
-
- // Take two timestamps with sleep in-between
- uint64_t t1 = time_get_os_boottime_us();
- int err = nanosleep(&delay, &delay);
- uint64_t t2 = time_get_os_boottime_us();
-
- ASSERT_TRUE(err == 0);
- ASSERT_TRUE(t2 > t1);
- ASSERT_TRUE((t2 - t1) >= TEST_TIME_SLEEP_US);
- ASSERT_TRUE((t2 - t1) < TEST_TIME_DELTA_UPPER_BOUND_MS * 1000);
-}
-
-//
-// Test that the return value of time_gettimeofday_us() is not zero.
-//
-TEST_F(TimeTest, test_time_gettimeofday_us_not_zero) {
- uint64_t t1 = time_gettimeofday_us();
- ASSERT_TRUE(t1 > 0);
-}
-
-//
-// Test that the return value of time_gettimeofday_us()
-// is monotonically increasing within reasonable boundaries.
-//
-TEST_F(TimeTest, test_time_gettimeofday_us_increases_upper_bound) {
- uint64_t t1 = time_gettimeofday_us();
- uint64_t t2 = time_gettimeofday_us();
- ASSERT_TRUE((t2 - t1) < TEST_TIME_DELTA_UPPER_BOUND_MS * 1000);
-}
-
-//
-// Test that the return value of time_gettimeofday_us()
-// is increasing.
-//
-TEST_F(TimeTest, test_time_gettimeofday_us_increases_lower_bound) {
- static const uint64_t TEST_TIME_SLEEP_US = 100 * 1000;
- struct timespec delay;
-
- delay.tv_sec = TEST_TIME_SLEEP_US / (1000 * 1000);
- delay.tv_nsec = 1000 * (TEST_TIME_SLEEP_US % (1000 * 1000));
-
- // Take two timestamps with sleep in-between
- uint64_t t1 = time_gettimeofday_us();
- int err = nanosleep(&delay, &delay);
- uint64_t t2 = time_gettimeofday_us();
-
- ASSERT_TRUE(err == 0);
- ASSERT_TRUE(t2 > t1);
- ASSERT_TRUE((t2 - t1) >= TEST_TIME_SLEEP_US);
- ASSERT_TRUE((t2 - t1) < TEST_TIME_DELTA_UPPER_BOUND_MS * 1000);
-}
diff --git a/osi/test/wakelock_test.cc b/osi/test/wakelock_test.cc
index 0e027be..a1dfc05 100644
--- a/osi/test/wakelock_test.cc
+++ b/osi/test/wakelock_test.cc
@@ -45,7 +45,7 @@
class WakelockTest : public AllocationTestHarness {
protected:
- virtual void SetUp() {
+ void SetUp() override {
AllocationTestHarness::SetUp();
// TODO (jamuraa): maybe use base::CreateNewTempDirectory instead?
@@ -69,7 +69,7 @@
creat(unlock_path_.c_str(), S_IRWXU);
}
- virtual void TearDown() {
+ void TearDown() override {
is_wake_lock_acquired = false;
wakelock_cleanup();
wakelock_set_os_callouts(NULL);
diff --git a/packet/Android.bp b/packet/Android.bp
index 8338c2d..44d0625 100644
--- a/packet/Android.bp
+++ b/packet/Android.bp
@@ -15,8 +15,13 @@
cc_test {
name: "net_test_btpackets",
defaults: ["fluoride_defaults"],
+ test_suites: ["device-tests"],
host_supported: true,
local_include_dirs: ["tests"],
+ include_dirs: [
+ "system/bt/",
+ "system/bt/include",
+ ],
srcs: [
"tests/avrcp/avrcp_browse_packet_test.cc",
"tests/avrcp/avrcp_packet_test.cc",
diff --git a/packet/BUILD.gn b/packet/BUILD.gn
new file mode 100644
index 0000000..37d6ca4
--- /dev/null
+++ b/packet/BUILD.gn
@@ -0,0 +1,52 @@
+#
+# Copyright 2018 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.
+#
+
+static_library("packet") {
+ sources = [
+ "avrcp/get_folder_items.cc",
+ "avrcp/register_notification_packet.cc",
+ "avrcp/change_path.cc",
+ "avrcp/get_total_number_of_items.cc",
+ "avrcp/capabilities_packet.cc",
+ "avrcp/pass_through_packet.cc",
+ "avrcp/set_browsed_player.cc",
+ "avrcp/avrcp_reject_packet.cc",
+ "avrcp/set_absolute_volume.cc",
+ "avrcp/avrcp_packet.cc",
+ "avrcp/get_element_attributes_packet.cc",
+ "avrcp/get_play_status_packet.cc",
+ "avrcp/general_reject_packet.cc",
+ "avrcp/avrcp_browse_packet.cc",
+ "avrcp/get_item_attributes.cc",
+ "avrcp/play_item.cc",
+ "avrcp/vendor_packet.cc",
+ "avrcp/set_addressed_player.cc",
+ "base/iterator.cc",
+ "base/packet.cc",
+ "base/packet_builder.cc",
+ ]
+
+ include_dirs = [
+ "//",
+ "//internal_include",
+ "//stack/include",
+ "//profile/avrcp",
+ ]
+
+ deps = [
+ "//third_party/libchrome:base"
+ ]
+}
diff --git a/packet/avrcp/Android.bp b/packet/avrcp/Android.bp
index 80e93e8..b54288f 100644
--- a/packet/avrcp/Android.bp
+++ b/packet/avrcp/Android.bp
@@ -5,6 +5,10 @@
export_header_lib_headers: ["avrcp_headers"],
export_include_dirs: ["."],
host_supported: true,
+ include_dirs: [
+ "system/bt/",
+ "system/bt/include",
+ ],
srcs: [
"avrcp_browse_packet.cc",
"avrcp_packet.cc",
diff --git a/packet/avrcp/avrcp_browse_packet.cc b/packet/avrcp/avrcp_browse_packet.cc
index f4a7691..07b5485 100644
--- a/packet/avrcp/avrcp_browse_packet.cc
+++ b/packet/avrcp/avrcp_browse_packet.cc
@@ -61,7 +61,7 @@
uint16_t BrowsePacket::GetLength() const {
auto it = begin() + static_cast<size_t>(1);
- return base::ByteSwap(it.extract<uint16_t>());
+ return it.extractBE<uint16_t>();
}
bool BrowsePacket::IsValid() const {
@@ -88,4 +88,4 @@
}
} // namespace avrcp
-} // namespace bluetooth
\ No newline at end of file
+} // namespace bluetooth
diff --git a/packet/avrcp/avrcp_browse_packet.h b/packet/avrcp/avrcp_browse_packet.h
index d62f0e2..038f576 100644
--- a/packet/avrcp/avrcp_browse_packet.h
+++ b/packet/avrcp/avrcp_browse_packet.h
@@ -20,11 +20,11 @@
#include <base/macros.h>
#include <iostream>
-#include "avrcp_common.h"
-#include "avrcp_logging_helper.h"
-#include "iterator.h"
-#include "packet.h"
-#include "packet_builder.h"
+#include "hardware/avrcp/avrcp_common.h"
+#include "hardware/avrcp/avrcp_logging_helper.h"
+#include "packet/base/iterator.h"
+#include "packet/base/packet.h"
+#include "packet/base/packet_builder.h"
namespace bluetooth {
namespace avrcp {
@@ -75,7 +75,7 @@
using ::bluetooth::Packet::Packet;
private:
- virtual std::pair<size_t, size_t> GetPayloadIndecies() const;
+ virtual std::pair<size_t, size_t> GetPayloadIndecies() const override;
DISALLOW_COPY_AND_ASSIGN(BrowsePacket);
};
diff --git a/packet/avrcp/avrcp_packet.h b/packet/avrcp/avrcp_packet.h
index 1e56186..ee0e0d5 100644
--- a/packet/avrcp/avrcp_packet.h
+++ b/packet/avrcp/avrcp_packet.h
@@ -20,11 +20,11 @@
#include <base/macros.h>
#include <iostream>
-#include "avrcp_common.h"
-#include "avrcp_logging_helper.h"
-#include "iterator.h"
-#include "packet.h"
-#include "packet_builder.h"
+#include "hardware/avrcp/avrcp_common.h"
+#include "hardware/avrcp/avrcp_logging_helper.h"
+#include "packet/base/iterator.h"
+#include "packet/base/packet.h"
+#include "packet/base/packet_builder.h"
namespace bluetooth {
namespace avrcp {
@@ -87,7 +87,7 @@
Opcode GetOpcode() const;
// Overloaded Functions
- virtual bool IsValid() const;
+ virtual bool IsValid() const override;
virtual std::string ToString() const override;
protected:
@@ -103,9 +103,9 @@
}
private:
- virtual std::pair<size_t, size_t> GetPayloadIndecies() const;
+ virtual std::pair<size_t, size_t> GetPayloadIndecies() const override;
DISALLOW_COPY_AND_ASSIGN(Packet);
};
} // namespace avrcp
-} // namespace bluetooth
\ No newline at end of file
+} // namespace bluetooth
diff --git a/packet/avrcp/change_path.cc b/packet/avrcp/change_path.cc
index 3c69903..b5f9ab4 100644
--- a/packet/avrcp/change_path.cc
+++ b/packet/avrcp/change_path.cc
@@ -52,7 +52,7 @@
uint16_t ChangePathRequest::GetUidCounter() const {
auto it = begin() + BrowsePacket::kMinSize();
- return base::ByteSwap(it.extract<uint16_t>());
+ return it.extractBE<uint16_t>();
}
Direction ChangePathRequest::GetDirection() const {
@@ -62,7 +62,7 @@
uint64_t ChangePathRequest::GetUid() const {
auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(3);
- return base::ByteSwap(it.extract<uint64_t>());
+ return it.extractBE<uint64_t>();
}
bool ChangePathRequest::IsValid() const {
@@ -109,4 +109,4 @@
}
} // namespace avrcp
-} // namespace bluetooth
\ No newline at end of file
+} // namespace bluetooth
diff --git a/packet/avrcp/get_element_attributes_packet.cc b/packet/avrcp/get_element_attributes_packet.cc
index c26207e..8634ce0 100644
--- a/packet/avrcp/get_element_attributes_packet.cc
+++ b/packet/avrcp/get_element_attributes_packet.cc
@@ -40,7 +40,7 @@
std::vector<Attribute> attribute_list;
for (size_t i = 0; i < number_of_attributes; i++) {
- attribute_list.push_back((Attribute)base::ByteSwap(it.extract<uint32_t>()));
+ attribute_list.push_back((Attribute)it.extractBE<uint32_t>());
}
return attribute_list;
@@ -132,7 +132,7 @@
VendorPacketBuilder::PushHeader(pkt, size() - VendorPacket::kMinSize());
AddPayloadOctets1(pkt, entries_.size());
- for (auto attribute_entry : entries_) {
+ for (const auto& attribute_entry : entries_) {
PushAttributeValue(pkt, attribute_entry);
}
@@ -140,4 +140,4 @@
}
} // namespace avrcp
-} // namespace bluetooth
\ No newline at end of file
+} // namespace bluetooth
diff --git a/packet/avrcp/get_element_attributes_packet.h b/packet/avrcp/get_element_attributes_packet.h
index 03fa8d1..e60844c 100644
--- a/packet/avrcp/get_element_attributes_packet.h
+++ b/packet/avrcp/get_element_attributes_packet.h
@@ -51,7 +51,7 @@
std::vector<Attribute> GetAttributesRequested() const;
// Overloaded Functions
- virtual bool IsValid() const;
+ virtual bool IsValid() const override;
virtual std::string ToString() const override;
protected:
diff --git a/packet/avrcp/get_folder_items.cc b/packet/avrcp/get_folder_items.cc
index c95bb4a..4e6e3a1 100644
--- a/packet/avrcp/get_folder_items.cc
+++ b/packet/avrcp/get_folder_items.cc
@@ -236,12 +236,12 @@
uint32_t GetFolderItemsRequest::GetStartItem() const {
auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(1);
- return base::ByteSwap(it.extract<uint32_t>());
+ return it.extractBE<uint32_t>();
}
uint32_t GetFolderItemsRequest::GetEndItem() const {
auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(5);
- return base::ByteSwap(it.extract<uint32_t>());
+ return it.extractBE<uint32_t>();
}
uint8_t GetFolderItemsRequest::GetNumAttributes() const {
@@ -263,7 +263,7 @@
// to have this function return a vector with all the attributes
for (size_t i = 0; i < number_of_attributes; i++) {
- attribute_list.push_back((Attribute)base::ByteSwap(it.extract<uint32_t>()));
+ attribute_list.push_back((Attribute)it.extractBE<uint32_t>());
}
return attribute_list;
@@ -342,4 +342,4 @@
}
} // namespace avrcp
-} // namespace bluetooth
\ No newline at end of file
+} // namespace bluetooth
diff --git a/packet/avrcp/get_item_attributes.cc b/packet/avrcp/get_item_attributes.cc
index 3430474..fb2ba87 100644
--- a/packet/avrcp/get_item_attributes.cc
+++ b/packet/avrcp/get_item_attributes.cc
@@ -70,7 +70,7 @@
if (status_ != Status::NO_ERROR) return true;
AddPayloadOctets1(pkt, entries_.size());
- for (auto entry : entries_) {
+ for (const auto& entry : entries_) {
AddPayloadOctets4(pkt, base::ByteSwap((uint32_t)entry.attribute()));
uint16_t character_set = 0x006a; // UTF-8
AddPayloadOctets2(pkt, base::ByteSwap(character_set));
@@ -91,12 +91,12 @@
uint64_t GetItemAttributesRequest::GetUid() const {
auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(1);
- return base::ByteSwap(it.extract<uint64_t>());
+ return it.extractBE<uint64_t>();
}
uint16_t GetItemAttributesRequest::GetUidCounter() const {
auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(9);
- return base::ByteSwap(it.extract<uint16_t>());
+ return it.extractBE<uint16_t>();
}
uint8_t GetItemAttributesRequest::GetNumAttributes() const {
@@ -111,7 +111,7 @@
std::vector<Attribute> attribute_list;
for (size_t i = 0; i < number_of_attributes; i++) {
- attribute_list.push_back((Attribute)base::ByteSwap(it.extract<uint32_t>()));
+ attribute_list.push_back((Attribute)it.extractBE<uint32_t>());
}
return attribute_list;
@@ -147,4 +147,4 @@
}
} // namespace avrcp
-} // namespace bluetooth
\ No newline at end of file
+} // namespace bluetooth
diff --git a/packet/avrcp/play_item.cc b/packet/avrcp/play_item.cc
index 27b242b..d7bb9b7 100644
--- a/packet/avrcp/play_item.cc
+++ b/packet/avrcp/play_item.cc
@@ -53,12 +53,12 @@
uint64_t PlayItemRequest::GetUid() const {
auto it = begin() + VendorPacket::kMinSize() + static_cast<size_t>(1);
- return base::ByteSwap(it.extract<uint64_t>());
+ return it.extractBE<uint64_t>();
}
uint16_t PlayItemRequest::GetUidCounter() const {
auto it = begin() + VendorPacket::kMinSize() + static_cast<size_t>(9);
- return base::ByteSwap(it.extract<uint16_t>());
+ return it.extractBE<uint16_t>();
}
bool PlayItemRequest::IsValid() const {
@@ -86,4 +86,4 @@
}
} // namespace avrcp
-} // namespace bluetooth
\ No newline at end of file
+} // namespace bluetooth
diff --git a/packet/avrcp/register_notification_packet.cc b/packet/avrcp/register_notification_packet.cc
index 86115e1..adb5e59 100644
--- a/packet/avrcp/register_notification_packet.cc
+++ b/packet/avrcp/register_notification_packet.cc
@@ -234,7 +234,7 @@
uint32_t RegisterNotificationRequest::GetInterval() const {
auto it = begin() + VendorPacket::kMinSize() + static_cast<size_t>(1);
- return base::ByteSwap(it.extract<uint32_t>());
+ return it.extractBE<uint32_t>();
}
bool RegisterNotificationRequest::IsValid() const {
@@ -288,4 +288,4 @@
}
} // namespace avrcp
-} // namespace bluetooth
\ No newline at end of file
+} // namespace bluetooth
diff --git a/packet/avrcp/set_addressed_player.cc b/packet/avrcp/set_addressed_player.cc
index f4b4ddd..d1a9909 100644
--- a/packet/avrcp/set_addressed_player.cc
+++ b/packet/avrcp/set_addressed_player.cc
@@ -48,7 +48,7 @@
uint16_t SetAddressedPlayerRequest::GetPlayerId() const {
auto it = begin() + VendorPacket::kMinSize();
- return base::ByteSwap(it.extract<uint16_t>());
+ return it.extractBE<uint16_t>();
}
bool SetAddressedPlayerRequest::IsValid() const {
@@ -74,4 +74,4 @@
}
} // namespace avrcp
-} // namespace bluetooth
\ No newline at end of file
+} // namespace bluetooth
diff --git a/packet/avrcp/set_browsed_player.cc b/packet/avrcp/set_browsed_player.cc
index b8463fa..fa0c768 100644
--- a/packet/avrcp/set_browsed_player.cc
+++ b/packet/avrcp/set_browsed_player.cc
@@ -80,7 +80,7 @@
uint16_t SetBrowsedPlayerRequest::GetPlayerId() const {
auto it = begin() + BrowsePacket::kMinSize();
- return base::ByteSwap(it.extract<uint16_t>());
+ return it.extractBE<uint16_t>();
}
bool SetBrowsedPlayerRequest::IsValid() const {
@@ -100,4 +100,4 @@
}
} // namespace avrcp
-} // namespace bluetooth
\ No newline at end of file
+} // namespace bluetooth
diff --git a/packet/avrcp/vendor_packet.cc b/packet/avrcp/vendor_packet.cc
index 982cf81..4525cfb 100644
--- a/packet/avrcp/vendor_packet.cc
+++ b/packet/avrcp/vendor_packet.cc
@@ -96,7 +96,7 @@
uint16_t VendorPacket::GetParameterLength() const {
auto it = begin() + Packet::kMinSize() + static_cast<size_t>(5);
// Swap to little endian
- return base::ByteSwap(it.extract<uint16_t>());
+ return it.extractBE<uint16_t>();
}
bool VendorPacket::IsValid() const {
@@ -128,4 +128,4 @@
}
} // namespace avrcp
-} // namespace bluetooth
\ No newline at end of file
+} // namespace bluetooth
diff --git a/packet/base/iterator.h b/packet/base/iterator.h
index c4ad32c..782150d 100644
--- a/packet/base/iterator.h
+++ b/packet/base/iterator.h
@@ -71,6 +71,22 @@
return extracted_value;
}
+ // Extract in Little Endian Format
+ template <typename FixedWidthIntegerType>
+ FixedWidthIntegerType extractBE() {
+ static_assert(std::is_integral<FixedWidthIntegerType>::value,
+ "Iterator::extract requires an integral type.");
+
+ FixedWidthIntegerType extracted_value = 0;
+ for (size_t i = 0; i < sizeof(FixedWidthIntegerType); i++) {
+ extracted_value |= static_cast<FixedWidthIntegerType>(**this)
+ << (sizeof(FixedWidthIntegerType) - 1 - i) * 8;
+ (*this)++;
+ }
+
+ return extracted_value;
+ }
+
uint8_t extract8() { return extract<uint8_t>(); }
uint16_t extract16() { return extract<uint16_t>(); }
uint32_t extract32() { return extract<uint32_t>(); }
@@ -81,4 +97,4 @@
size_t index_;
}; // Iterator
-} // namespace bluetooth
\ No newline at end of file
+} // namespace bluetooth
diff --git a/packet/tests/base/iterator_test.cc b/packet/tests/base/iterator_test.cc
index 5794686..57743de 100644
--- a/packet/tests/base/iterator_test.cc
+++ b/packet/tests/base/iterator_test.cc
@@ -65,6 +65,16 @@
ASSERT_EQ(0x00010000000a0013u, general_case.extract<uint64_t>());
}
+TEST_F(IteratorTest, extractBETest) {
+ auto packet = TestPacket::Make(test_l2cap_data);
+ Iterator general_case = packet->begin();
+
+ ASSERT_EQ(0x02u, general_case.extractBE<uint8_t>());
+ ASSERT_EQ(0xdc2eu, general_case.extractBE<uint16_t>());
+ ASSERT_EQ(0x66006200u, general_case.extractBE<uint32_t>());
+ ASSERT_EQ(0x13000a0000000100u, general_case.extractBE<uint64_t>());
+}
+
TEST_P(IteratorTest, payloadBoundsTest) {
auto packet = GetTestPacket();
ASSERT_EQ(static_cast<size_t>(packet->end() - packet->begin()),
@@ -89,6 +99,19 @@
"index_ != packet_->packet_end_index_");
}
+TEST_P(IteratorTest, extractBEBoundsDeathTest) {
+ auto packet = GetTestPacket();
+ Iterator bounds_test = packet->end();
+ ASSERT_DEATH(bounds_test.extractBE<uint8_t>(),
+ "index_ != packet_->packet_end_index_");
+ ASSERT_DEATH(bounds_test.extractBE<uint16_t>(),
+ "index_ != packet_->packet_end_index_");
+ ASSERT_DEATH(bounds_test.extractBE<uint32_t>(),
+ "index_ != packet_->packet_end_index_");
+ ASSERT_DEATH(bounds_test.extractBE<uint64_t>(),
+ "index_ != packet_->packet_end_index_");
+}
+
TEST_P(IteratorTest, dereferenceDeathTest) {
auto packet = GetTestPacket();
Iterator dereference_test = packet->end();
@@ -273,4 +296,4 @@
}
}
-} // namespace bluetooth
\ No newline at end of file
+} // namespace bluetooth
diff --git a/profile/avrcp/Android.bp b/profile/avrcp/Android.bp
index 3d95e9f..d73a5fb 100644
--- a/profile/avrcp/Android.bp
+++ b/profile/avrcp/Android.bp
@@ -1,6 +1,9 @@
cc_library_static {
name: "avrcp-target-service",
- defaults: ["fluoride_defaults"],
+ defaults: [
+ "fluoride_defaults",
+ "clang_file_coverage",
+ ],
host_supported: true,
include_dirs: [
"system/bt",
@@ -18,11 +21,18 @@
"libbluetooth-types",
"libosi",
],
+ shared_libs: [
+ "libchrome",
+ ],
}
cc_test {
name: "net_test_avrcp",
- defaults: ["fluoride_defaults"],
+ test_suites: ["general-tests"],
+ defaults: [
+ "fluoride_defaults",
+ "clang_coverage_bin",
+ ],
host_supported: true,
include_dirs: [
"system/bt",
@@ -37,11 +47,14 @@
static_libs: [
"libgmock",
"lib-bt-packets",
- "avrcp-target-service",
- "libbtdevice",
"libosi",
"liblog",
"libcutils",
+ "libbtdevice",
+ "avrcp-target-service",
+ ],
+ shared_libs: [
+ "libchrome",
],
sanitize: {
cfi: false,
diff --git a/profile/avrcp/BUILD.gn b/profile/avrcp/BUILD.gn
new file mode 100644
index 0000000..c37e0a7
--- /dev/null
+++ b/profile/avrcp/BUILD.gn
@@ -0,0 +1,34 @@
+#
+# Copyright 2018 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.
+#
+
+static_library("profile_avrcp") {
+ sources = [
+ "connection_handler.cc",
+ "device.cc",
+ ]
+
+ include_dirs = [
+ "//",
+ "//btcore/include",
+ "//internal_include",
+ "//stack/include",
+ "//profile/avrcp",
+ ]
+
+ deps = [
+ "//third_party/libchrome:base"
+ ]
+}
diff --git a/profile/avrcp/avrcp_internal.h b/profile/avrcp/avrcp_internal.h
index c2e6549..4aeffdf 100644
--- a/profile/avrcp/avrcp_internal.h
+++ b/profile/avrcp/avrcp_internal.h
@@ -82,6 +82,7 @@
class A2dpInterface {
public:
virtual RawAddress active_peer() = 0;
+ virtual bool is_peer_in_silence_mode(const RawAddress& peer_address) = 0;
virtual ~A2dpInterface() = default;
-};
\ No newline at end of file
+};
diff --git a/profile/avrcp/avrcp_message_converter.h b/profile/avrcp/avrcp_message_converter.h
index 389a497..8de704b 100644
--- a/profile/avrcp/avrcp_message_converter.h
+++ b/profile/avrcp/avrcp_message_converter.h
@@ -19,7 +19,7 @@
#include <iostream>
#include <vector>
-#include "avrcp_packet.h"
+#include "packet/avrcp/avrcp_packet.h"
// These classes are temporary placeholders to easily switch between BT_HDR and
// packets.
@@ -41,7 +41,7 @@
const std::vector<uint8_t>& GetData() { return *data_; };
- virtual std::string ToString() const {
+ virtual std::string ToString() const override {
std::stringstream ss;
ss << "VectorPacket:" << std::endl;
ss << " â”” Payload =";
diff --git a/profile/avrcp/connection_handler.cc b/profile/avrcp/connection_handler.cc
index 66237ed..3177506 100644
--- a/profile/avrcp/connection_handler.cc
+++ b/profile/avrcp/connection_handler.cc
@@ -22,9 +22,9 @@
#include "avrc_defs.h"
#include "avrcp_message_converter.h"
-#include "avrcp_packet.h"
#include "bt_types.h"
#include "btu.h"
+#include "packet/avrcp/avrcp_packet.h"
// TODO (apanicke): Remove dependency on this header once we cleanup feature
// handling.
#include "bta/include/bta_av_api.h"
@@ -151,7 +151,7 @@
std::vector<std::shared_ptr<Device>> ConnectionHandler::GetListOfDevices()
const {
std::vector<std::shared_ptr<Device>> list;
- for (auto device : device_map_) {
+ for (const auto& device : device_map_) {
list.push_back(device.second);
}
return list;
@@ -176,8 +176,9 @@
return avrc_->FindService(
UUID_SERVCLASS_AV_REMOTE_CONTROL, bdaddr, &db_params,
- base::Bind(&ConnectionHandler::SdpCb, base::Unretained(this),
- bdaddr, cb, disc_db)) == AVRC_SUCCESS;
+ base::Bind(&ConnectionHandler::SdpCb,
+ weak_ptr_factory_.GetWeakPtr(), bdaddr, cb, disc_db)) ==
+ AVRC_SUCCESS;
}
bool ConnectionHandler::AvrcpConnect(bool initiator, const RawAddress& bdaddr) {
@@ -192,7 +193,7 @@
weak_ptr_factory_.GetWeakPtr());
}
open_cb.msg_cback =
- base::Bind(&ConnectionHandler::MessageCb, base::Unretained(this));
+ base::Bind(&ConnectionHandler::MessageCb, weak_ptr_factory_.GetWeakPtr());
open_cb.company_id = AVRC_CO_GOOGLE;
open_cb.conn = initiator ? AVRC_CONN_INT
: AVRC_CONN_ACP; // 0 if initiator, 1 if acceptor
@@ -272,13 +273,20 @@
device_map_.erase(handle);
} break;
- case AVRC_BROWSE_OPEN_IND_EVT:
+ case AVRC_BROWSE_OPEN_IND_EVT: {
LOG(INFO) << __PRETTY_FUNCTION__ << ": Browse Open Event";
// NOTE (apanicke): We don't need to explicitly handle this message
// since the AVCTP Layer will still send us browsing messages
// regardless. It would be useful to note this though for future
// compatibility issues.
- break;
+ if (device_map_.find(handle) == device_map_.end()) {
+ LOG(WARNING) << "Browse Opened received from device that doesn't exist";
+ return;
+ }
+
+ auto browse_mtu = avrc_->GetBrowseMtu(handle) - AVCT_HDR_LEN;
+ device_map_[handle]->SetBrowseMtu(browse_mtu);
+ } break;
case AVRC_BROWSE_CLOSE_IND_EVT:
LOG(INFO) << __PRETTY_FUNCTION__ << ": Browse Close Event";
break;
@@ -302,7 +310,7 @@
LOG(INFO) << __PRETTY_FUNCTION__ << ": Connection Opened Event";
auto&& callback = base::Bind(&ConnectionHandler::SendMessage,
- base::Unretained(this), handle);
+ weak_ptr_factory_.GetWeakPtr(), handle);
auto&& ctrl_mtu = avrc_->GetPeerMtu(handle) - AVCT_HDR_LEN;
auto&& browse_mtu = avrc_->GetBrowseMtu(handle) - AVCT_HDR_LEN;
std::shared_ptr<Device> newDevice = std::make_shared<Device>(
@@ -356,13 +364,20 @@
device_map_.erase(handle);
} break;
- case AVRC_BROWSE_OPEN_IND_EVT:
+ case AVRC_BROWSE_OPEN_IND_EVT: {
LOG(INFO) << __PRETTY_FUNCTION__ << ": Browse Open Event";
// NOTE (apanicke): We don't need to explicitly handle this message
// since the AVCTP Layer will still send us browsing messages
// regardless. It would be useful to note this though for future
// compatibility issues.
- break;
+ if (device_map_.find(handle) == device_map_.end()) {
+ LOG(WARNING) << "Browse Opened received from device that doesn't exist";
+ return;
+ }
+
+ auto browse_mtu = avrc_->GetBrowseMtu(handle) - AVCT_HDR_LEN;
+ device_map_[handle]->SetBrowseMtu(browse_mtu);
+ } break;
case AVRC_BROWSE_CLOSE_IND_EVT:
LOG(INFO) << __PRETTY_FUNCTION__ << ": Browse Close Event";
break;
@@ -374,7 +389,7 @@
void ConnectionHandler::MessageCb(uint8_t handle, uint8_t label, uint8_t opcode,
tAVRC_MSG* p_msg) {
- if (device_map_[handle] == nullptr) {
+ if (device_map_.find(handle) == device_map_.end()) {
LOG(ERROR) << "Message received for unconnected device: handle="
<< loghex(handle);
return;
diff --git a/profile/avrcp/connection_handler.h b/profile/avrcp/connection_handler.h
index 63bc8a0..e22cb6a 100644
--- a/profile/avrcp/connection_handler.h
+++ b/profile/avrcp/connection_handler.h
@@ -22,9 +22,9 @@
#include <memory>
#include "avrcp_internal.h"
-#include "avrcp_packet.h"
-#include "device.h"
-#include "packet.h"
+#include "packet/avrcp/avrcp_packet.h"
+#include "packet/base/packet.h"
+#include "profile/avrcp/device.h"
#include "raw_address.h"
namespace bluetooth {
diff --git a/profile/avrcp/device.cc b/profile/avrcp/device.cc
index 7f8ecae..cf94cfc 100644
--- a/profile/avrcp/device.cc
+++ b/profile/avrcp/device.cc
@@ -13,11 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include "device.h"
#include <base/message_loop/message_loop.h>
#include "connection_handler.h"
-#include "device.h"
+#include "packet/avrcp/avrcp_reject_packet.h"
+#include "packet/avrcp/general_reject_packet.h"
+#include "packet/avrcp/get_play_status_packet.h"
+#include "packet/avrcp/pass_through_packet.h"
+#include "packet/avrcp/set_absolute_volume.h"
+#include "packet/avrcp/set_addressed_player.h"
#include "stack_config.h"
namespace bluetooth {
@@ -52,12 +58,23 @@
volume_interface_ = volume_interface;
}
-base::WeakPtr<Device> Device::Get() { return weak_ptr_factory_.GetWeakPtr(); }
+base::WeakPtr<Device> Device::Get() {
+ return weak_ptr_factory_.GetWeakPtr();
+}
+
+void Device::SetBrowseMtu(uint16_t browse_mtu) {
+ DEVICE_LOG(INFO) << __PRETTY_FUNCTION__ << ": browse_mtu = " << browse_mtu;
+ browse_mtu_ = browse_mtu;
+}
bool Device::IsActive() const {
return address_ == a2dp_interface_->active_peer();
}
+bool Device::IsInSilenceMode() const {
+ return a2dp_interface_->is_peer_in_silence_mode(address_);
+}
+
void Device::VendorPacketHandler(uint8_t label,
std::shared_ptr<VendorPacket> pkt) {
CHECK(media_interface_);
@@ -457,7 +474,7 @@
// We still try to send updates while music is playing to the non active
// device even though the device thinks the music is paused. This makes
// the status bar on the remote device move.
- if (status.state == PlayState::PLAYING) {
+ if (status.state == PlayState::PLAYING && !IsInSilenceMode()) {
DEVICE_VLOG(0) << __func__ << ": Queue next play position update";
play_pos_update_cb_.Reset(base::Bind(&Device::HandlePlayPosUpdate,
weak_ptr_factory_.GetWeakPtr()));
@@ -1041,7 +1058,7 @@
// right now we always use folders of mixed type
FolderItem folder_item(vfs_ids_.get_uid(folder.media_id), 0x00,
folder.is_playable, folder.name);
- builder->AddFolder(folder_item);
+ if (!builder->AddFolder(folder_item)) break;
} else if (items[i].type == ListItem::SONG) {
auto song = items[i].song;
auto title =
@@ -1058,7 +1075,9 @@
filter_attributes_requested(song, pkt->GetAttributesRequested());
}
- builder->AddSong(song_item);
+ // If we fail to add a song, don't accidentally add one later that might
+ // fit.
+ if (!builder->AddSong(song_item)) break;
}
}
@@ -1091,7 +1110,10 @@
item.attributes_ =
filter_attributes_requested(song, pkt->GetAttributesRequested());
}
- builder->AddSong(item);
+
+ // If we fail to add a song, don't accidentally add one later that might
+ // fit.
+ if (!builder->AddSong(item)) break;
}
send_message(label, true, std::move(builder));
@@ -1131,9 +1153,12 @@
}
void Device::SendMediaUpdate(bool metadata, bool play_status, bool queue) {
+ bool is_silence = IsInSilenceMode();
+
CHECK(media_interface_);
DEVICE_VLOG(4) << __func__ << ": Metadata=" << metadata
- << " : play_status= " << play_status << " : queue=" << queue;
+ << " : play_status= " << play_status << " : queue=" << queue
+ << " ; is_silence=" << is_silence;
if (queue) {
HandleNowPlayingUpdate();
@@ -1141,7 +1166,9 @@
if (play_status) {
HandlePlayStatusUpdate();
- HandlePlayPosUpdate();
+ if (!is_silence) {
+ HandlePlayPosUpdate();
+ }
}
if (metadata) HandleTrackUpdate();
@@ -1284,40 +1311,29 @@
}
std::ostream& operator<<(std::ostream& out, const Device& d) {
- out << " " << d.address_.ToString();
+ out << d.address_.ToString();
if (d.IsActive()) out << " <Active>";
out << std::endl;
- out << " Current Volume: " << volumeToStr(d.volume_) << std::endl;
- out << " Current Browsed Player ID: " << d.curr_browsed_player_id_
- << std::endl;
- out << " Registered Notifications: " << std::endl;
- if (d.track_changed_.first) {
- out << " Track Changed" << std::endl;
- }
- if (d.play_status_changed_.first) {
- out << " Play Status" << std::endl;
- }
- if (d.play_pos_changed_.first) {
- out << " Play Position" << std::endl;
- }
- if (d.now_playing_changed_.first) {
- out << " Now Playing" << std::endl;
- }
- if (d.addr_player_changed_.first) {
- out << " Addressed Player" << std::endl;
- }
- if (d.avail_players_changed_.first) {
- out << " Available Players" << std::endl;
- }
- if (d.uids_changed_.first) {
- out << " UIDs Changed" << std::endl;
- }
- out << " Last Play State: " << d.last_play_status_.state << std::endl;
- out << " Last Song Sent ID: \"" << d.last_song_info_.media_id << "\""
+ ScopedIndent indent(out);
+ out << "Current Volume: " << volumeToStr(d.volume_) << std::endl;
+ out << "Current Browsed Player ID: " << d.curr_browsed_player_id_
<< std::endl;
- out << " Current Folder: \"" << d.CurrentFolder() << "\"" << std::endl;
- out << " MTU Sizes: CTRL=" << d.ctrl_mtu_ << " BROWSE=" << d.browse_mtu_
+ out << "Registered Notifications:\n";
+ {
+ ScopedIndent indent(out);
+ if (d.track_changed_.first) out << "Track Changed\n";
+ if (d.play_status_changed_.first) out << "Play Status\n";
+ if (d.play_pos_changed_.first) out << "Play Position\n";
+ if (d.now_playing_changed_.first) out << "Now Playing\n";
+ if (d.addr_player_changed_.first) out << "Addressed Player\n";
+ if (d.avail_players_changed_.first) out << "Available Players\n";
+ if (d.uids_changed_.first) out << "UIDs Changed\n";
+ }
+ out << "Last Play State: " << d.last_play_status_.state << std::endl;
+ out << "Last Song Sent ID: \"" << d.last_song_info_.media_id << "\"\n";
+ out << "Current Folder: \"" << d.CurrentFolder() << "\"\n";
+ out << "MTU Sizes: CTRL=" << d.ctrl_mtu_ << " BROWSE=" << d.browse_mtu_
<< std::endl;
// TODO (apanicke): Add supported features as well as media keys
return out;
diff --git a/profile/avrcp/device.h b/profile/avrcp/device.h
index b1f3420..18bfc98 100644
--- a/profile/avrcp/device.h
+++ b/profile/avrcp/device.h
@@ -23,10 +23,22 @@
#include <base/bind.h>
#include <base/cancelable_callback.h>
-#include "avrcp.h"
#include "avrcp_internal.h"
-#include "avrcp_packet.h"
-#include "media_id_map.h"
+#include "hardware/avrcp/avrcp.h"
+#include "packet/avrcp/avrcp_browse_packet.h"
+#include "packet/avrcp/avrcp_packet.h"
+#include "packet/avrcp/capabilities_packet.h"
+#include "packet/avrcp/change_path.h"
+#include "packet/avrcp/get_element_attributes_packet.h"
+#include "packet/avrcp/get_folder_items.h"
+#include "packet/avrcp/get_item_attributes.h"
+#include "packet/avrcp/get_total_number_of_items.h"
+#include "packet/avrcp/play_item.h"
+#include "packet/avrcp/register_notification_packet.h"
+#include "packet/avrcp/set_addressed_player.h"
+#include "packet/avrcp/set_browsed_player.h"
+#include "packet/avrcp/vendor_packet.h"
+#include "profile/avrcp/media_id_map.h"
#include "raw_address.h"
namespace bluetooth {
@@ -69,6 +81,11 @@
bool Disconnect();
/**
+ * Returns true if the current device is silenced.
+ */
+ bool IsInSilenceMode() const;
+
+ /**
* Returns true if the current device is active.
*/
bool IsActive() const;
@@ -85,6 +102,12 @@
VolumeInterface* volume_interface);
/**
+ * Set the maximum size of a AVRCP Browsing Packet. This is done after the
+ * connection of the Browsing channel.
+ */
+ void SetBrowseMtu(uint16_t browse_mtu);
+
+ /**
* Notify the device that metadata, play_status, and/or queue have updated
* via a boolean. Each boolean represents whether its respective content has
* updated.
diff --git a/profile/avrcp/tests/avrcp_connection_handler_test.cc b/profile/avrcp/tests/avrcp_connection_handler_test.cc
index 4f542f6..15ea55e 100644
--- a/profile/avrcp/tests/avrcp_connection_handler_test.cc
+++ b/profile/avrcp/tests/avrcp_connection_handler_test.cc
@@ -25,12 +25,13 @@
#include "connection_handler.h"
using ::testing::_;
+using ::testing::DoAll;
+using ::testing::MockFunction;
+using ::testing::NiceMock;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::SaveArgPointee;
using ::testing::SetArgPointee;
-using ::testing::MockFunction;
-using ::testing::NiceMock;
using ::testing::StrictMock;
namespace bluetooth {
diff --git a/profile/avrcp/tests/avrcp_device_test.cc b/profile/avrcp/tests/avrcp_device_test.cc
index 1a9f29a..206e7e2 100644
--- a/profile/avrcp/tests/avrcp_device_test.cc
+++ b/profile/avrcp/tests/avrcp_device_test.cc
@@ -41,8 +41,8 @@
using TestBrowsePacket = TestPacketType<BrowsePacket>;
using ::testing::_;
-using ::testing::MockFunction;
using ::testing::Mock;
+using ::testing::MockFunction;
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::SaveArg;
@@ -57,7 +57,7 @@
// Add more tests to increase code coverage.
class AvrcpDeviceTest : public ::testing::Test {
public:
- virtual void SetUp() override {
+ void SetUp() override {
// NOTE: We use a wrapper lambda for the MockFunction in order to
// add a const qualifier to the response. Otherwise the MockFunction
// type doesn't match the callback type and a compiler error occurs.
@@ -71,7 +71,7 @@
test_device = new Device(RawAddress::kAny, true, cb, 0xFFFF, 0xFFFF);
}
- virtual void TearDown() override {
+ void TearDown() override {
delete test_device;
Mock::VerifyAndClear(&response_cb);
}
@@ -813,16 +813,24 @@
base::Bind([](MockFunction<void(uint8_t, bool, const AvrcpResponse&)>* a,
uint8_t b, bool c, AvrcpResponse d) { a->Call(b, c, d); },
&response_cb);
- Device device(RawAddress::kAny, true, cb, 0xFFFF, truncated_packet->size());
+
+ Device device(RawAddress::kAny, true, cb, 0xFFFF,
+ truncated_packet->size() + FolderItem::kHeaderSize() + 5);
device.RegisterInterfaces(&interface, &a2dp_interface, nullptr);
FolderInfo info0 = {"test_id0", true, "Test Folder0"};
FolderInfo info1 = {"test_id1", true, "Test Folder1"};
- FolderInfo info2 = {"test_id1", true, "Truncated folder"};
+ FolderInfo info2 = {"test_id2", true, "Truncated folder"};
+ // Used to ensure that adding an item that would fit in the MTU fails if
+ // adding a large item failed.
+ FolderInfo small_info = {"test_id2", true, "Small"};
+
ListItem item0 = {ListItem::FOLDER, info0, SongInfo()};
ListItem item1 = {ListItem::FOLDER, info1, SongInfo()};
- ListItem item2 = {ListItem::FOLDER, info1, SongInfo()};
- std::vector<ListItem> list0 = {item0, item1, item2};
+ ListItem item2 = {ListItem::FOLDER, info2, SongInfo()};
+ ListItem item3 = {ListItem::FOLDER, small_info, SongInfo()};
+
+ std::vector<ListItem> list0 = {item0, item1, item2, item3};
EXPECT_CALL(interface, GetFolderItems(_, "", _))
.WillRepeatedly(InvokeCb<2>(list0));
diff --git a/profile/avrcp/tests/avrcp_test_helper.h b/profile/avrcp/tests/avrcp_test_helper.h
index 16fc31f..edf3592 100644
--- a/profile/avrcp/tests/avrcp_test_helper.h
+++ b/profile/avrcp/tests/avrcp_test_helper.h
@@ -76,6 +76,7 @@
MOCK_METHOD1(event_open, void(const RawAddress&));
MOCK_METHOD1(event_close, void(const RawAddress&));
MOCK_METHOD0(active_peer, RawAddress());
+ MOCK_METHOD1(is_peer_in_silence_mode, bool(const RawAddress&));
};
class MockSdpInterface : public SdpInterface {
diff --git a/profile/sdp/Android.bp b/profile/sdp/Android.bp
new file mode 100644
index 0000000..5abd77b
--- /dev/null
+++ b/profile/sdp/Android.bp
@@ -0,0 +1,40 @@
+cc_library_static {
+ name: "sdp_service",
+ defaults: [
+ "fluoride_defaults",
+ "clang_file_coverage",
+ ],
+ host_supported: true,
+ include_dirs: [
+ "system/bt/",
+ ],
+ srcs: [
+ "common/data_element_reader.cc",
+ ],
+ static_libs: [
+ "lib-bt-packets",
+ "libbluetooth-types",
+ ],
+}
+
+cc_test {
+ name: "bluetooth_test_sdp",
+ test_suites: ["general-tests"],
+ defaults: [
+ "fluoride_defaults",
+ "clang_coverage_bin",
+ ],
+ host_supported: true,
+ include_dirs: [
+ "system/bt/",
+ ],
+ srcs: [
+ "common/test/data_element_reader_test.cc",
+ ],
+ static_libs: [
+ "libgmock",
+ "sdp_service",
+ "lib-bt-packets",
+ "libbluetooth-types",
+ ],
+}
diff --git a/profile/sdp/common/data_element_reader.cc b/profile/sdp/common/data_element_reader.cc
new file mode 100644
index 0000000..675100f
--- /dev/null
+++ b/profile/sdp/common/data_element_reader.cc
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2018 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 "data_element_reader.h"
+
+#include <base/logging.h>
+#include <type_traits>
+
+#include "sdp_logging_helper.h"
+
+// A helper macro that can verify that there is enough data remaining in the
+// reader to extract without overflowing. end_ - it_ should never be negative
+// so casting it to a size_t is always safe. If it does fail, set it_ to end_
+// so that all additional readings fail.
+#define CHECK_REMAINING_LEN(x) \
+ do { \
+ if ((size_t)(end_ - it_) < x) { \
+ LOG(WARNING) << __func__ << ": Extract would read past end of data."; \
+ return ParseFail(); \
+ } \
+ } while (0)
+
+namespace bluetooth {
+namespace sdp {
+
+DataElementReader::DataElement DataElementReader::ReadNext() {
+ if (it_ > end_) LOG(FATAL) << "Beginning of buffer is past end of buffer.";
+ if (it_ == end_) return std::monostate();
+
+ uint8_t descriptor = *it_++;
+ DataElementType type = static_cast<DataElementType>(descriptor >> 3);
+ DataElementSize size = static_cast<DataElementSize>(descriptor & 0b00000111);
+
+ // All types with a value greater than URL are currently reserved.
+ if (type > DataElementType::MAX_VALUE) {
+ LOG(WARNING) << __func__ << ": Trying to use a reserved data element type";
+ return ParseFail();
+ }
+
+ switch (type) {
+ case DataElementType::BOOLEAN:
+ if (size != DataElementSize::BYTE1) {
+ LOG(WARNING) << __func__ << ": Invalid size for bool: " << size;
+ return ParseFail();
+ }
+
+ CHECK_REMAINING_LEN(1);
+ return (it_.extract<uint8_t>() != 0);
+ case DataElementType::SIGNED_INT:
+ return ReadSignedInt(size);
+ case DataElementType::UNSIGNED_INT:
+ return ReadUnsignedInt(size);
+ case DataElementType::UUID:
+ return ReadUuid(size);
+ case DataElementType::STRING:
+ return ReadString(size);
+ case DataElementType::DATA_ELEMENT_SEQUENCE:
+ return ReadSequence(size);
+ default:
+ // TODO: The other data element types are never used in the previous SDP
+ // implementation. We should properly handle them in the future though
+ // for completeness.
+ LOG(ERROR) << __func__ << ": Unhandled Data Element Type: " << type;
+ }
+
+ return ParseFail();
+}
+
+DataElementReader::DataElement DataElementReader::ParseFail() {
+ it_ = end_;
+ return std::monostate();
+}
+
+template <class IntegerType>
+DataElementReader::DataElement DataElementReader::ReadInteger() {
+ static_assert(std::is_integral<IntegerType>::value,
+ "ReadInteger requires an integral type.");
+
+ CHECK_REMAINING_LEN(sizeof(IntegerType));
+ return it_.extractBE<IntegerType>();
+}
+
+DataElementReader::DataElement DataElementReader::ReadLargeInt() {
+ CHECK_REMAINING_LEN(16);
+
+ std::array<uint8_t, 16> array;
+ for (size_t i = 0; i < sizeof(uint8_t[16]); i++) {
+ array[i] = it_.extract<uint8_t>();
+ }
+
+ return array;
+}
+
+DataElementReader::DataElement DataElementReader::ReadSignedInt(
+ DataElementSize size) {
+ switch (size) {
+ case DataElementSize::BYTE1:
+ return ReadInteger<int8_t>();
+ case DataElementSize::BYTE2:
+ return ReadInteger<int16_t>();
+ case DataElementSize::BYTE4:
+ return ReadInteger<int32_t>();
+ case DataElementSize::BYTE8:
+ return ReadInteger<int64_t>();
+ case DataElementSize::BYTE16:
+ return ReadLargeInt();
+ default:
+ LOG(WARNING) << __func__ << ": Invalid size for int: " << size;
+ }
+
+ return ParseFail();
+}
+
+DataElementReader::DataElement DataElementReader::ReadUnsignedInt(
+ DataElementSize size) {
+ switch (size) {
+ case DataElementSize::BYTE1:
+ return ReadInteger<uint8_t>();
+ case DataElementSize::BYTE2:
+ return ReadInteger<uint16_t>();
+ case DataElementSize::BYTE4:
+ return ReadInteger<uint32_t>();
+ case DataElementSize::BYTE8:
+ return ReadInteger<uint64_t>();
+ case DataElementSize::BYTE16:
+ return ReadLargeInt();
+ default:
+ LOG(WARNING) << __func__ << ": Invalid size for uint: " << size;
+ }
+
+ return ParseFail();
+}
+
+DataElementReader::DataElement DataElementReader::ReadUuid(
+ DataElementSize size) {
+ if (size == DataElementSize::BYTE2) {
+ CHECK_REMAINING_LEN(2);
+ return Uuid::From16Bit(it_.extractBE<uint16_t>());
+ }
+
+ if (size == DataElementSize::BYTE4) {
+ CHECK_REMAINING_LEN(4);
+ return Uuid::From32Bit(it_.extractBE<uint32_t>());
+ }
+
+ if (size == DataElementSize::BYTE16) {
+ CHECK_REMAINING_LEN(16);
+
+ Uuid::UUID128Bit uuid_array;
+ for (int i = 0; i < 16; i++) {
+ uuid_array[i] = it_.extract<uint8_t>();
+ }
+
+ return Uuid::From128BitBE(uuid_array);
+ }
+
+ LOG(WARNING) << __func__ << ": Invalid size for UUID: " << size;
+ return ParseFail();
+}
+
+DataElementReader::DataElement DataElementReader::ReadString(
+ DataElementSize size) {
+ uint32_t num_bytes = 0;
+
+ switch (size) {
+ case DataElementSize::ADDITIONAL_8BIT:
+ CHECK_REMAINING_LEN(1);
+ num_bytes = it_.extractBE<uint8_t>();
+ break;
+ case DataElementSize::ADDITIONAL_16BIT:
+ CHECK_REMAINING_LEN(2);
+ num_bytes = it_.extractBE<uint16_t>();
+ break;
+ case DataElementSize::ADDITIONAL_32BIT:
+ CHECK_REMAINING_LEN(4);
+ num_bytes = it_.extractBE<uint32_t>();
+ break;
+ default:
+ LOG(WARNING) << __func__ << ": Invalid size for string: " << size;
+ return ParseFail();
+ }
+
+ CHECK_REMAINING_LEN(num_bytes);
+
+ std::string str;
+ for (uint32_t i = 0; i < num_bytes; i++) {
+ str.push_back(it_.extractBE<uint8_t>());
+ }
+
+ return str;
+}
+
+DataElementReader::DataElement DataElementReader::ReadSequence(
+ DataElementSize size) {
+ uint32_t num_bytes = 0;
+
+ switch (size) {
+ case DataElementSize::ADDITIONAL_8BIT:
+ CHECK_REMAINING_LEN(1);
+ num_bytes = it_.extractBE<uint8_t>();
+ break;
+ case DataElementSize::ADDITIONAL_16BIT:
+ CHECK_REMAINING_LEN(2);
+ num_bytes = it_.extractBE<uint16_t>();
+ break;
+ case DataElementSize::ADDITIONAL_32BIT:
+ CHECK_REMAINING_LEN(4);
+ num_bytes = it_.extractBE<uint32_t>();
+ break;
+ default:
+ LOG(WARNING) << __func__ << ": Invalid size for string: " << size;
+ return ParseFail();
+ }
+
+ CHECK_REMAINING_LEN(num_bytes);
+
+ // Create a parser that points to the beginning of the next sequence and move
+ // the iterator to past the end of the new sequence.
+ auto&& temp = DataElementReader(it_, it_ + num_bytes);
+ it_ += num_bytes;
+ return std::move(temp);
+}
+
+} // namespace sdp
+} // namespace bluetooth
diff --git a/profile/sdp/common/data_element_reader.h b/profile/sdp/common/data_element_reader.h
new file mode 100644
index 0000000..13346bd
--- /dev/null
+++ b/profile/sdp/common/data_element_reader.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2018 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 <array>
+#include <variant>
+
+#include "bluetooth/uuid.h"
+#include "packet.h"
+#include "sdp_common.h"
+#include "stack/include/bt_types.h"
+
+namespace bluetooth {
+namespace sdp {
+
+// A helper class that helps extract data element objects from SDP packets.
+class DataElementReader {
+ public:
+ // If the DataElement contains monostate, that means parsing has failed.
+ using DataElement =
+ std::variant<std::monostate, bool, int8_t, int16_t, int32_t, int64_t,
+ uint8_t, uint16_t, uint32_t, uint64_t, Octet16, Uuid,
+ std::string, DataElementReader>;
+
+ DataElementReader(Iterator begin, Iterator end) : it_(begin), end_(end){};
+
+ // Get the next Data Element in the data. If reading fails for any reason,
+ // the DataElementReader becomes invalid and will continuously fail to read
+ // from that point onward.
+ DataElement ReadNext();
+
+ private:
+ // Extraction Helpers
+ DataElement ParseFail();
+ template <class IntegerType>
+ DataElement ReadInteger();
+ DataElement ReadLargeInt();
+
+ // Extraction Functions
+ DataElement ReadSignedInt(DataElementSize size);
+ DataElement ReadUnsignedInt(DataElementSize size);
+ DataElement ReadUuid(DataElementSize size);
+ DataElement ReadString(DataElementSize size);
+ DataElement ReadSequence(DataElementSize size);
+
+ Iterator it_;
+ Iterator end_;
+};
+
+} // namespace sdp
+} // namespace bluetooth
diff --git a/profile/sdp/common/test/data_element_reader_test.cc b/profile/sdp/common/test/data_element_reader_test.cc
new file mode 100644
index 0000000..9361ac7
--- /dev/null
+++ b/profile/sdp/common/test/data_element_reader_test.cc
@@ -0,0 +1,412 @@
+/*
+ * Copyright 2018 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/logging.h>
+#include <gtest/gtest.h>
+
+#include "common/data_element_reader.h"
+
+namespace bluetooth {
+namespace sdp {
+
+using namespace testing;
+using DataElement = DataElementReader::DataElement;
+
+// A helper class to help work with the Data Element classes.
+class ReaderPacket : public ::bluetooth::Packet {
+ public:
+ using Packet::Packet;
+
+ static std::shared_ptr<ReaderPacket> Make(std::vector<uint8_t> payload) {
+ auto pkt = std::shared_ptr<ReaderPacket>(new ReaderPacket());
+ pkt->packet_start_index_ = 0;
+ pkt->packet_end_index_ = payload.size();
+ pkt->data_ = std::make_shared<std::vector<uint8_t>>(std::move(payload));
+ return pkt;
+ }
+
+ std::string ToString() const override { return ""; }
+ bool IsValid() const override { return true; }
+ std::pair<size_t, size_t> GetPayloadIndecies() const override {
+ return std::pair<size_t, size_t>(packet_start_index_, packet_end_index_);
+ }
+};
+
+bool operator!=(DataElementReader a, DataElementReader b);
+
+// A helper function to help compare DataElementReader objects.
+bool operator==(DataElementReader a, DataElementReader b) {
+ while (true) {
+ DataElement a_elem = a.ReadNext();
+ DataElement b_elem = b.ReadNext();
+
+ if (a_elem != b_elem) return false;
+
+ // If we get here that means both a and b have reached the end.
+ if (a_elem == DataElement(std::monostate())) break;
+ }
+
+ return true;
+}
+
+bool operator!=(DataElementReader a, DataElementReader b) { return !(a == b); }
+
+// A helper function to convert a type and a size to a descriptor byte.
+constexpr uint8_t Desc(DataElementType t, DataElementSize s) {
+ return static_cast<uint8_t>(t) << 3 | static_cast<uint8_t>(s);
+}
+
+// Helper that can create a Data Element reader from a vector.
+DataElementReader CreateReader(std::vector<uint8_t> payload) {
+ auto packet = ReaderPacket::Make(std::move(payload));
+ return DataElementReader(packet->begin(), packet->end());
+}
+
+// Test all the valid cases of reading the next Data Element.
+using ValidTestParam = std::tuple<std::vector<uint8_t>, DataElement>;
+class ValidReadTest : public TestWithParam<ValidTestParam> {};
+
+std::vector<ValidTestParam> valid_values = {
+ // Boolean Tests
+ ValidTestParam{
+ {Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x01},
+ true,
+ },
+ ValidTestParam{
+ {Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x00},
+ false,
+ },
+
+ // Signed Integer Tests
+ ValidTestParam{
+ {Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE1), 0xFF},
+ static_cast<int8_t>(-1)},
+ ValidTestParam{
+ {Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE2), 0xFF, 0xFF},
+ static_cast<int16_t>(-1)},
+ ValidTestParam{{Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE4),
+ 0xFF, 0xFF, 0xFF, 0xFF},
+ static_cast<int32_t>(-1)},
+ ValidTestParam{{Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE8),
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ static_cast<int64_t>(-1)},
+ ValidTestParam{{Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE16),
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ std::array<uint8_t, 16>{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF}},
+
+ // Unsigned Integer Tests
+ ValidTestParam{
+ {Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE1), 0x01},
+ static_cast<uint8_t>(1)},
+ ValidTestParam{{Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE2),
+ 0x00, 0x01},
+ static_cast<uint16_t>(1)},
+ ValidTestParam{{Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE4),
+ 0x00, 0x00, 0x00, 0x01},
+ static_cast<uint32_t>(1)},
+ ValidTestParam{{Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE8),
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
+ static_cast<uint64_t>(1)},
+ ValidTestParam{
+ {Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE16), 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01},
+ std::array<uint8_t, 16>{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01}},
+
+ // UUID Tests
+ ValidTestParam{
+ {Desc(DataElementType::UUID, DataElementSize::BYTE2), 0x01, 0x02},
+ Uuid::From16Bit(0x0102)},
+ ValidTestParam{{Desc(DataElementType::UUID, DataElementSize::BYTE4), 0x01,
+ 0x02, 0x03, 0x04},
+ Uuid::From32Bit(0x01020304)},
+ ValidTestParam{
+ {Desc(DataElementType::UUID, DataElementSize::BYTE16), 0x00, 0x01, 0x02,
+ 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
+ 0x0F},
+ Uuid::From128BitBE({0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F})},
+
+ // String Tests
+ ValidTestParam{
+ {Desc(DataElementType::STRING, DataElementSize::ADDITIONAL_8BIT), 0x05,
+ 'T', 'e', 's', 't', '1'},
+ std::string("Test1")},
+ ValidTestParam{
+ {Desc(DataElementType::STRING, DataElementSize::ADDITIONAL_16BIT), 0x00,
+ 0x05, 'T', 'e', 's', 't', '2'},
+ std::string("Test2")},
+ ValidTestParam{
+ {Desc(DataElementType::STRING, DataElementSize::ADDITIONAL_32BIT), 0x00,
+ 0x00, 0x00, 0x05, 'T', 'e', 's', 't', '3'},
+ std::string("Test3")},
+
+ // Nested Data Element List Tests
+ ValidTestParam{
+ {Desc(DataElementType::DATA_ELEMENT_SEQUENCE,
+ DataElementSize::ADDITIONAL_8BIT),
+ 0x04, Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x01,
+ Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x00},
+ CreateReader(
+ {Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x01,
+ Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x00})},
+ ValidTestParam{
+ {Desc(DataElementType::DATA_ELEMENT_SEQUENCE,
+ DataElementSize::ADDITIONAL_16BIT),
+ 0x00, 0x04, Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1),
+ 0x01, Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x00},
+ CreateReader(
+ {Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x01,
+ Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x00})},
+ ValidTestParam{
+ {Desc(DataElementType::DATA_ELEMENT_SEQUENCE,
+ DataElementSize::ADDITIONAL_32BIT),
+ 0x00, 0x00, 0x00, 0x04,
+ Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x01,
+ Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x00},
+ CreateReader(
+ {Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x01,
+ Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x00})},
+};
+
+INSTANTIATE_TEST_CASE_P(ReadNext, ValidReadTest, ValuesIn(valid_values));
+TEST_P(ValidReadTest, Test) {
+ auto packet = ReaderPacket::Make(std::get<0>(GetParam()));
+ auto value = std::get<1>(GetParam());
+
+ DataElementReader reader(packet->begin(), packet->end());
+ auto read_value = reader.ReadNext();
+
+ ASSERT_EQ(value, read_value);
+
+ // Test that there is no additional data to read.
+ ASSERT_EQ(reader.ReadNext(), DataElement(std::monostate()));
+}
+
+// Test that a nested reader is correctly bounded and can't read past its
+// defined end.
+TEST(ReadNext, BoundedSubreaderTest) {
+ std::vector<uint8_t> payload = {
+ // Subsequence descriptor byte.
+ Desc(DataElementType::DATA_ELEMENT_SEQUENCE,
+ DataElementSize::ADDITIONAL_8BIT),
+ // Subsequence length.
+ 0x04,
+ // Subsequence that contains two booleans with values true and false.
+ Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x01,
+ Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x00,
+ // Additional int16 at the end of the original sequence.
+ Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE2), 0x01, 0x23};
+
+ auto packet = ReaderPacket::Make(payload);
+ DataElementReader reader(packet->begin(), packet->end());
+
+ // The first thing read should be the subsequence.
+ auto data_element = reader.ReadNext();
+ ASSERT_TRUE(std::holds_alternative<DataElementReader>(data_element));
+
+ // Check that the subsequence matches the premade sequence.
+ auto subreader = std::get<DataElementReader>(data_element);
+ data_element = subreader.ReadNext();
+ ASSERT_TRUE(std::holds_alternative<bool>(data_element));
+ ASSERT_TRUE(std::get<bool>(data_element));
+ data_element = subreader.ReadNext();
+ ASSERT_TRUE(std::holds_alternative<bool>(data_element));
+ ASSERT_FALSE(std::get<bool>(data_element));
+
+ // Check that there is no additional data to be read from the subreader.
+ ASSERT_EQ(subreader.ReadNext(), DataElement(std::monostate()));
+
+ // Check that we can still read the int16 from the original reader.
+ data_element = reader.ReadNext();
+ ASSERT_TRUE(std::holds_alternative<int16_t>(data_element));
+ auto int16_value = std::get<int16_t>(data_element);
+ ASSERT_EQ(int16_value, 0x0123);
+
+ // Check that there is no additional data to be read from the base reader.
+ ASSERT_EQ(reader.ReadNext(), DataElement(std::monostate()));
+}
+
+// Test that trying to read an empty packet fails.
+TEST(ReadNext, NoDataTest) {
+ auto packet = ReaderPacket::Make({});
+ DataElementReader reader(packet->begin(), packet->end());
+
+ ASSERT_EQ(reader.ReadNext(), DataElement(std::monostate()));
+}
+
+// Test that using a reserved value for type fails.
+TEST(ReadNext, InvalidTypeTest) {
+ auto packet = ReaderPacket::Make({0xFF});
+ DataElementReader reader(packet->begin(), packet->end());
+
+ ASSERT_EQ(reader.ReadNext(), DataElement(std::monostate()));
+}
+
+// Test all invalid parses due to incorrect lengths or invalid sizes. All tests
+// should return std::monostate.
+using InvalidTestParam = std::vector<uint8_t>;
+class InvalidReadTest : public TestWithParam<InvalidTestParam> {};
+
+std::vector<InvalidTestParam> invalid_values = {
+ // Boolean Tests:
+ // Invalid size field.
+ InvalidTestParam{
+ Desc(DataElementType::BOOLEAN, DataElementSize::BYTE2),
+ },
+ // Insufficient data.
+ InvalidTestParam{Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1)},
+
+ // Signed Integer Tests:
+ // Invalid size field.
+ InvalidTestParam{
+ Desc(DataElementType::SIGNED_INT, DataElementSize::ADDITIONAL_8BIT)},
+ // 1 byte insufficient data.
+ InvalidTestParam{Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE1)},
+ // 2 byte insufficient data.
+ InvalidTestParam{Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE2),
+ 0x00},
+ // 4 byte insufficient data.
+ InvalidTestParam{Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE4),
+ 0x00, 0x00, 0x00},
+ // 8 Byte insufficient data.
+ InvalidTestParam{Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE8),
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ // 16 Byte insufficient data.
+ InvalidTestParam{Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE16),
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00},
+
+ // Unsigned Integer Tests:
+ // Invalid size field.
+ InvalidTestParam{
+ Desc(DataElementType::UNSIGNED_INT, DataElementSize::ADDITIONAL_8BIT)},
+ // 1 byte insufficient data.
+ InvalidTestParam{
+ Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE1)},
+ // 2 byte insufficient data.
+ InvalidTestParam{
+ Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE2), 0x00},
+ // 4 byte insufficient data.
+ InvalidTestParam{
+ Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE4), 0x00, 0x00,
+ 0x00},
+ // 8 Byte insufficient data.
+ InvalidTestParam{
+ Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE8), 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00},
+ // 16 Byte insufficient data.
+ InvalidTestParam{
+ Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE16), 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+ // UUID Tests:
+ // Invalid size field.
+ InvalidTestParam{
+ Desc(DataElementType::UUID, DataElementSize::ADDITIONAL_8BIT)},
+ // 2 byte insufficient data.
+ InvalidTestParam{Desc(DataElementType::UUID, DataElementSize::BYTE2), 0x00},
+ // 4 byte insufficient data.
+ InvalidTestParam{Desc(DataElementType::UUID, DataElementSize::BYTE4), 0x00,
+ 0x00, 0x00},
+ // 16 Byte insufficient data.
+ InvalidTestParam{Desc(DataElementType::UUID, DataElementSize::BYTE16), 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00},
+
+ // String Tests:
+ // Invalid size field.
+ InvalidTestParam{Desc(DataElementType::STRING, DataElementSize::BYTE1)},
+ // Insufficient data for additional 8 bits len.
+ InvalidTestParam{
+ Desc(DataElementType::STRING, DataElementSize::ADDITIONAL_8BIT)},
+ // Insufficient data for additional 16 bits len.
+ InvalidTestParam{
+ Desc(DataElementType::STRING, DataElementSize::ADDITIONAL_16BIT),
+ 0x00,
+ },
+ // Insufficient data for additional 32 bit len.
+ InvalidTestParam{
+ Desc(DataElementType::STRING, DataElementSize::ADDITIONAL_32BIT),
+ 0x00,
+ 0x00,
+ 0x00,
+ },
+ // Insufficient data for reported length.
+ InvalidTestParam{
+ Desc(DataElementType::STRING, DataElementSize::ADDITIONAL_8BIT), 0x04,
+ '1', '2', '3'},
+
+ // Nested Data Element List Tests:
+ // Invalid size field.
+ InvalidTestParam{
+ Desc(DataElementType::DATA_ELEMENT_SEQUENCE, DataElementSize::BYTE1)},
+ // Insufficient data for additional 8 bits len.
+ InvalidTestParam{Desc(DataElementType::DATA_ELEMENT_SEQUENCE,
+ DataElementSize::ADDITIONAL_8BIT)},
+ // Insufficient data for additional 16 bits len.
+ InvalidTestParam{
+ Desc(DataElementType::DATA_ELEMENT_SEQUENCE,
+ DataElementSize::ADDITIONAL_16BIT),
+ 0x00,
+ },
+ // Insufficient data for additional 32 bit len.
+ InvalidTestParam{
+ Desc(DataElementType::DATA_ELEMENT_SEQUENCE,
+ DataElementSize::ADDITIONAL_32BIT),
+ 0x00,
+ 0x00,
+ 0x00,
+ },
+ // Insufficient data for reported length.
+ InvalidTestParam{Desc(DataElementType::DATA_ELEMENT_SEQUENCE,
+ DataElementSize::ADDITIONAL_8BIT),
+ 0x04, 0x00, 0x00, 0x00},
+
+ // Unhandled Data Element Types Tests:
+ // NOTE: These tests should go away as we begin to handle the types.
+ // Nil Type.
+ InvalidTestParam{Desc(DataElementType::NIL, DataElementSize::BYTE1)},
+ // Data Element Alternative List Type.
+ InvalidTestParam{Desc(DataElementType::DATA_ELEMENT_ALTERNATIVE,
+ DataElementSize::ADDITIONAL_8BIT),
+ 0x00},
+ // URL Type.
+ InvalidTestParam{
+ Desc(DataElementType::URL, DataElementSize::ADDITIONAL_8BIT), 0x00}};
+
+INSTANTIATE_TEST_CASE_P(ReadNext, InvalidReadTest, ValuesIn(invalid_values));
+TEST_P(InvalidReadTest, Test) {
+ auto packet = ReaderPacket::Make(GetParam());
+ DataElementReader reader(packet->begin(), packet->end());
+
+ ASSERT_EQ(reader.ReadNext(), DataElement(std::monostate()));
+}
+
+// Test that trying to read from a reader with start > end crashes.
+TEST(DataElementReader, BadBoundsDeathTest) {
+ auto packet = ReaderPacket::Make({0x00, 0x00, 0x00, 0x00});
+ DataElementReader reader(packet->end(), packet->begin());
+ ASSERT_DEATH(reader.ReadNext(), "Beginning of buffer is past end of buffer.");
+}
+
+} // namespace sdp
+} // namespace bluetooth
diff --git a/profile/sdp/sdp_common.h b/profile/sdp/sdp_common.h
new file mode 100644
index 0000000..4a07a63
--- /dev/null
+++ b/profile/sdp/sdp_common.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2018 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
+
+namespace bluetooth {
+namespace sdp {
+
+enum class PduId : uint8_t {
+ RESERVED = 0x00,
+ ERROR = 0x01,
+ SERVICE_SEARCH_REQUEST = 0x02,
+ SERVICE_SEARCH_RESPONSE = 0x03,
+ SERVICE_ATTRIBUTE_REQUEST = 0x04,
+ SERVICE_ATTRIBUTE_RESPONSE = 0x05,
+ SERVICE_SEARCH_ATTRIBUTE_REQUEST = 0x06,
+ SERVICE_SEARCH_ATTRIBUTE_RESPONSE = 0x07,
+ MAX_VALUE = 0x07,
+};
+
+enum class AttributeId : uint16_t {
+ SERVICE_RECORD_HANDLE = 0x0000,
+ SERVICE_CLASS_ID_LIST = 0x0001,
+ SERVICE_RECORD_STATE = 0x0002,
+ SERVICE_ID = 0x0003,
+ PROTOCOL_DESCRIPTOR_LIST = 0x0004,
+ BROWSE_GROUP_LIST = 0x0005,
+ LANGUAGE_BASE_ATTRIBUTE_ID_LIST = 0x0006,
+ SERVICE_INFO_TIME_TO_LIVE = 0x0007,
+ SERVICE_AVAILABILITY = 0x0008,
+ PROFILE_DESCRIPTOR_LIST = 0x0009,
+ DOCUMENTATION_URL = 0x000A,
+ CLIENT_EXECUTABLE_URL = 0x000B,
+ ICON_URL = 0x000C,
+ ADDITIONAL_PROTOCOL_DESCRIPTOR_LIST = 0x000D,
+
+ // The following attributes are only used in the SDP server service record.
+ // They are only valid if ServiceDiscoveryServerServiceClassID is in the
+ // ServiceClassIDList. See Bluetooth Core v5.0 Section 5.2.
+ VERSION_NUMBER_LIST = 0x0200,
+ SERVICE_DATABASE_STATE = 0x0201,
+};
+
+// The Attribute ID's of these attributes are calculated by adding the offset
+// value for the attribute to the attribute ID base (contained in the
+// LanguageBaseAttributeIDList attribute value).
+enum AttributeIdOffset : uint16_t {
+ SERVICE_NAME = 0x0000,
+ SERVICE_DESCRIPTION = 0x0001,
+ PROVIDER_NAME = 0x0002,
+};
+
+// Constant that define the different types of data element.
+enum class DataElementType : uint8_t {
+ NIL = 0x00,
+ UNSIGNED_INT = 0x01,
+ SIGNED_INT = 0x02,
+ UUID = 0x03,
+ STRING = 0x04,
+ BOOLEAN = 0x05,
+ DATA_ELEMENT_SEQUENCE = 0x06,
+ DATA_ELEMENT_ALTERNATIVE = 0x07,
+ URL = 0x08,
+ MAX_VALUE = 0x08,
+};
+
+// Constant that define the different sizes of data element.
+enum class DataElementSize : uint8_t {
+ BYTE1 = 0x0, // Exception: If the data element is NIL then size is 0 bytes
+ BYTE2 = 0x1,
+ BYTE4 = 0x2,
+ BYTE8 = 0x3,
+ BYTE16 = 0x4,
+ // The size types below represent that the first X bits of the value
+ // represents the size of the remaining data.
+ ADDITIONAL_8BIT = 0x5,
+ ADDITIONAL_16BIT = 0x6,
+ ADDITIONAL_32BIT = 0x7,
+};
+
+} // namespace sdp
+} // namespace bluetooth
diff --git a/profile/sdp/sdp_logging_helper.h b/profile/sdp/sdp_logging_helper.h
new file mode 100644
index 0000000..e947329
--- /dev/null
+++ b/profile/sdp/sdp_logging_helper.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2018 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 <iomanip>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <type_traits>
+
+#include "bt_trace.h"
+#include "sdp_common.h"
+
+namespace bluetooth {
+namespace sdp {
+
+#ifndef CASE_RETURN_TEXT
+#define CASE_RETURN_TEXT(code) \
+ case code: \
+ return #code
+#endif
+
+inline std::string PduIdText(const PduId& id) {
+ switch (id) {
+ CASE_RETURN_TEXT(PduId::RESERVED);
+ CASE_RETURN_TEXT(PduId::ERROR);
+ CASE_RETURN_TEXT(PduId::SERVICE_SEARCH_REQUEST);
+ CASE_RETURN_TEXT(PduId::SERVICE_SEARCH_RESPONSE);
+ CASE_RETURN_TEXT(PduId::SERVICE_ATTRIBUTE_REQUEST);
+ CASE_RETURN_TEXT(PduId::SERVICE_ATTRIBUTE_RESPONSE);
+ CASE_RETURN_TEXT(PduId::SERVICE_SEARCH_ATTRIBUTE_REQUEST);
+ CASE_RETURN_TEXT(PduId::SERVICE_SEARCH_ATTRIBUTE_RESPONSE);
+ default:
+ return "Unknown PduId: " + loghex((uint8_t)id);
+ }
+}
+
+inline std::ostream& operator<<(std::ostream& os, const PduId& id) {
+ return os << PduIdText(id);
+}
+
+inline std::string AttributeIdText(const AttributeId& id) {
+ switch (id) {
+ CASE_RETURN_TEXT(AttributeId::SERVICE_RECORD_HANDLE);
+ CASE_RETURN_TEXT(AttributeId::SERVICE_CLASS_ID_LIST);
+ CASE_RETURN_TEXT(AttributeId::SERVICE_RECORD_STATE);
+ CASE_RETURN_TEXT(AttributeId::SERVICE_ID);
+ CASE_RETURN_TEXT(AttributeId::PROTOCOL_DESCRIPTOR_LIST);
+ CASE_RETURN_TEXT(AttributeId::BROWSE_GROUP_LIST);
+ CASE_RETURN_TEXT(AttributeId::LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
+ CASE_RETURN_TEXT(AttributeId::SERVICE_INFO_TIME_TO_LIVE);
+ CASE_RETURN_TEXT(AttributeId::SERVICE_AVAILABILITY);
+ CASE_RETURN_TEXT(AttributeId::PROFILE_DESCRIPTOR_LIST);
+ CASE_RETURN_TEXT(AttributeId::DOCUMENTATION_URL);
+ CASE_RETURN_TEXT(AttributeId::CLIENT_EXECUTABLE_URL);
+ CASE_RETURN_TEXT(AttributeId::ICON_URL);
+ CASE_RETURN_TEXT(AttributeId::ADDITIONAL_PROTOCOL_DESCRIPTOR_LIST);
+ CASE_RETURN_TEXT(AttributeId::VERSION_NUMBER_LIST);
+ CASE_RETURN_TEXT(AttributeId::SERVICE_DATABASE_STATE);
+ default:
+ return "Unknown AttributeId: " + loghex((uint16_t)id);
+ }
+}
+
+inline std::ostream& operator<<(std::ostream& os, const AttributeId& id) {
+ return os << AttributeIdText(id);
+}
+
+inline std::string DataElementTypeText(const DataElementType& type) {
+ switch (type) {
+ CASE_RETURN_TEXT(DataElementType::NIL);
+ CASE_RETURN_TEXT(DataElementType::UNSIGNED_INT);
+ CASE_RETURN_TEXT(DataElementType::SIGNED_INT);
+ CASE_RETURN_TEXT(DataElementType::UUID);
+ CASE_RETURN_TEXT(DataElementType::STRING);
+ CASE_RETURN_TEXT(DataElementType::BOOLEAN);
+ CASE_RETURN_TEXT(DataElementType::DATA_ELEMENT_SEQUENCE);
+ CASE_RETURN_TEXT(DataElementType::DATA_ELEMENT_ALTERNATIVE);
+ CASE_RETURN_TEXT(DataElementType::URL);
+ default:
+ return "Unknown DataElementType: " + loghex((uint8_t)type);
+ }
+}
+
+inline std::ostream& operator<<(std::ostream& os, const DataElementType& type) {
+ return os << DataElementTypeText(type);
+}
+
+inline std::string DataElementSizeText(const DataElementSize& size) {
+ switch (size) {
+ CASE_RETURN_TEXT(DataElementSize::BYTE1);
+ CASE_RETURN_TEXT(DataElementSize::BYTE2);
+ CASE_RETURN_TEXT(DataElementSize::BYTE4);
+ CASE_RETURN_TEXT(DataElementSize::BYTE8);
+ CASE_RETURN_TEXT(DataElementSize::BYTE16);
+ CASE_RETURN_TEXT(DataElementSize::ADDITIONAL_8BIT);
+ CASE_RETURN_TEXT(DataElementSize::ADDITIONAL_16BIT);
+ CASE_RETURN_TEXT(DataElementSize::ADDITIONAL_32BIT);
+ default:
+ return "Unknown DataElementSize: " + loghex((uint8_t)size);
+ }
+}
+
+inline std::ostream& operator<<(std::ostream& os, const DataElementSize& size) {
+ return os << DataElementSizeText(size);
+}
+
+} // namespace sdp
+} // namespace bluetooth
diff --git a/proto/Android.bp b/proto/Android.bp
index 0f97c72..c8a852d 100644
--- a/proto/Android.bp
+++ b/proto/Android.bp
@@ -16,4 +16,3 @@
},
srcs: ["bluetooth/metrics/bluetooth.proto"],
}
-
diff --git a/service/Android.bp b/service/Android.bp
index d24e0fa..4b21d0d 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -8,17 +8,23 @@
include_dirs: [
"system/bt",
],
- header_libs: [ "libbluetooth_headers" ],
+ header_libs: ["libbluetooth_headers"],
}
// Source variables
// ========================================================
btserviceDaemonSrc = [
+ "a2dp_sink.cc",
+ "a2dp_source.cc",
"adapter.cc",
+ "avrcp_control.cc",
+ "avrcp_target.cc",
"daemon.cc",
"gatt_client.cc",
"gatt_server.cc",
"gatt_server_old.cc",
+ "hal/bluetooth_av_interface.cc",
+ "hal/bluetooth_avrcp_interface.cc",
"hal/bluetooth_gatt_interface.cc",
"hal/bluetooth_interface.cc",
"ipc/ipc_handler.cc",
@@ -36,6 +42,10 @@
]
btserviceBinderDaemonSrc = [
+ "ipc/binder/bluetooth_a2dp_sink_binder_server.cc",
+ "ipc/binder/bluetooth_a2dp_source_binder_server.cc",
+ "ipc/binder/bluetooth_avrcp_control_binder_server.cc",
+ "ipc/binder/bluetooth_avrcp_target_binder_server.cc",
"ipc/binder/bluetooth_binder_server.cc",
"ipc/binder/bluetooth_gatt_client_binder_server.cc",
"ipc/binder/bluetooth_gatt_server_binder_server.cc",
@@ -49,8 +59,10 @@
// Main unit test sources. These get built for host and target.
// ========================================================
btserviceBaseTestSrc = [
+ "hal/fake_bluetooth_av_interface.cc",
"hal/fake_bluetooth_gatt_interface.cc",
"hal/fake_bluetooth_interface.cc",
+ "test/a2dp_sink_unittest.cc",
"test/adapter_unittest.cc",
"test/advertise_data_unittest.cc",
"test/fake_hal_util.cc",
@@ -68,9 +80,9 @@
name: "bluetoothtbd",
defaults: ["fluoride_service_defaults"],
srcs: btserviceBinderDaemonSrc +
- btserviceLinuxSrc +
- btserviceDaemonSrc +
- ["main.cc"],
+ btserviceLinuxSrc +
+ btserviceDaemonSrc +
+ ["main.cc"],
static_libs: [
"libbluetooth-binder-common",
"libbtcore",
@@ -79,6 +91,7 @@
],
shared_libs: [
+ "libchrome",
"libbinder",
"libcutils",
"liblog",
@@ -95,9 +108,9 @@
test_suites: ["device-tests"],
defaults: ["fluoride_service_defaults"],
srcs: btserviceBaseTestSrc +
- btserviceDaemonSrc + [
- "test/main.cc",
- ],
+ btserviceDaemonSrc + [
+ "test/main.cc",
+ ],
aidl: {
include_dirs: [
"system/bt/service/common",
@@ -109,7 +122,12 @@
"libgmock",
"liblog",
"libbluetooth-types",
+ "libutils",
],
+ shared_libs: [
+ "libchrome",
+ ],
+
host_supported: true,
target: {
// This includes Binder related tests that can only be run
@@ -124,7 +142,6 @@
],
shared_libs: [
"libbinder",
- "libutils",
],
},
host: {
diff --git a/service/AndroidTest.xml b/service/AndroidTest.xml
deleted file mode 100644
index 0beba75..0000000
--- a/service/AndroidTest.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2017 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.
--->
-<configuration description="Config for bluetoothtbd_test">
- <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
- <option name="cleanup" value="true" />
- <option name="push" value="bluetoothtbd_test->/data/local/tmp/bluetoothtbd_test" />
- </target_preparer>
- <option name="test-suite-tag" value="apct" />
- <test class="com.android.tradefed.testtype.GTest" >
- <option name="native-test-device-path" value="/data/local/tmp" />
- <option name="module-name" value="bluetoothtbd_test" />
- </test>
-</configuration>
\ No newline at end of file
diff --git a/service/BUILD.gn b/service/BUILD.gn
index 2fb94b5..59acb16 100644
--- a/service/BUILD.gn
+++ b/service/BUILD.gn
@@ -16,12 +16,21 @@
source_set("service") {
sources = [
+ "a2dp_sink.cc",
+ "a2dp_source.cc",
"adapter.cc",
+ "avrcp_control.cc",
+ "avrcp_target.cc",
+ "common/bluetooth/a2dp_codec_config.cc",
"common/bluetooth/adapter_state.cc",
"common/bluetooth/advertise_data.cc",
"common/bluetooth/advertise_settings.cc",
+ "common/bluetooth/avrcp_int_value.cc",
+ "common/bluetooth/avrcp_media_attr.cc",
+ "common/bluetooth/avrcp_register_notification_response.cc",
"common/bluetooth/characteristic.cc",
"common/bluetooth/descriptor.cc",
+ "common/bluetooth/remote_device_props.cc",
"common/bluetooth/scan_filter.cc",
"common/bluetooth/scan_result.cc",
"common/bluetooth/scan_settings.cc",
@@ -35,6 +44,8 @@
"hal/bluetooth_interface.cc",
"ipc/dbus/bluetooth_adapter.cc",
"ipc/dbus/ipc_handler_dbus.cc",
+ "hal/bluetooth_av_interface.cc",
+ "hal/bluetooth_avrcp_interface.cc",
"hal/fake_bluetooth_gatt_interface.cc",
"hal/fake_bluetooth_interface.cc",
"ipc/ipc_handler.cc",
@@ -50,6 +61,7 @@
include_dirs = [
"//",
+ "//linux_include",
"//include",
"//service/common",
"//third_party/modp_b64/modp64",
@@ -57,6 +69,7 @@
deps = [
"//types",
+ "//osi",
"//third_party/libchrome:base",
]
}
diff --git a/service/a2dp_sink.cc b/service/a2dp_sink.cc
new file mode 100644
index 0000000..4d59c7c
--- /dev/null
+++ b/service/a2dp_sink.cc
@@ -0,0 +1,154 @@
+//
+// Copyright 2017 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/a2dp_sink.h"
+
+#include <base/logging.h>
+#include <base/memory/ptr_util.h>
+
+#include "service/logging_helpers.h"
+
+using bluetooth::hal::BluetoothAvInterface;
+
+namespace bluetooth {
+
+// static
+const int A2dpSink::kSingletonInstanceId = 0;
+
+A2dpSink::A2dpSink(const Uuid& uuid) : app_identifier_(uuid) {
+ hal::BluetoothAvInterface::Get()->AddA2dpSinkObserver(this);
+}
+
+A2dpSink::~A2dpSink() {
+ hal::BluetoothAvInterface::Get()->RemoveA2dpSinkObserver(this);
+}
+
+const Uuid& A2dpSink::GetAppIdentifier() const { return app_identifier_; }
+
+int A2dpSink::GetInstanceId() const { return kSingletonInstanceId; }
+
+void A2dpSink::SetDelegate(Delegate* delegate) {
+ std::lock_guard<std::mutex> lock(delegate_mutex_);
+ delegate_ = delegate;
+}
+
+bool A2dpSink::Enable() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ return hal::BluetoothAvInterface::Get()->A2dpSinkEnable();
+}
+
+void A2dpSink::Disable() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ hal::BluetoothAvInterface::Get()->A2dpSinkDisable();
+}
+
+bool A2dpSink::Connect(const std::string& device_address) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ RawAddress addr;
+ if (!RawAddress::FromString(device_address, addr)) {
+ LOG(ERROR) << "Invalid device address given: " << device_address;
+ return false;
+ }
+
+ bt_status_t status =
+ hal::BluetoothAvInterface::Get()->GetA2dpSinkHALInterface()->connect(
+ addr);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to connect";
+ return false;
+ }
+
+ return true;
+}
+
+bool A2dpSink::Disconnect(const std::string& device_address) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ RawAddress addr;
+ if (!RawAddress::FromString(device_address, addr)) {
+ LOG(ERROR) << "Invalid device address given: " << device_address;
+ return false;
+ }
+
+ bt_status_t status =
+ hal::BluetoothAvInterface::Get()->GetA2dpSinkHALInterface()->disconnect(
+ addr);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to disconnect";
+ return false;
+ }
+
+ return true;
+}
+
+void A2dpSink::SetAudioFocusState(int focus_state) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ hal::BluetoothAvInterface::Get()
+ ->GetA2dpSinkHALInterface()
+ ->set_audio_focus_state(focus_state);
+}
+
+void A2dpSink::SetAudioTrackGain(float gain) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ hal::BluetoothAvInterface::Get()
+ ->GetA2dpSinkHALInterface()
+ ->set_audio_track_gain(gain);
+}
+
+void A2dpSink::ConnectionStateCallback(BluetoothAvInterface* iface,
+ const RawAddress& bd_addr,
+ btav_connection_state_t state) {
+ std::string device_address = BtAddrString(&bd_addr);
+ std::lock_guard<std::mutex> lock(delegate_mutex_);
+
+ if (delegate_)
+ delegate_->OnConnectionState(device_address, static_cast<int>(state));
+}
+
+void A2dpSink::AudioStateCallback(BluetoothAvInterface* iface,
+ const RawAddress& bd_addr,
+ btav_audio_state_t state) {
+ std::string device_address = BtAddrString(&bd_addr);
+ std::lock_guard<std::mutex> lock(delegate_mutex_);
+
+ if (delegate_)
+ delegate_->OnAudioState(device_address, static_cast<int>(state));
+}
+
+void A2dpSink::AudioConfigCallback(BluetoothAvInterface* iface,
+ const RawAddress& bd_addr,
+ uint32_t sample_rate,
+ uint8_t channel_count) {
+ std::string device_address = BtAddrString(&bd_addr);
+ std::lock_guard<std::mutex> lock(delegate_mutex_);
+ if (delegate_)
+ delegate_->OnAudioConfig(device_address, sample_rate, channel_count);
+}
+
+// A2dpSinkFactory implementation
+// ========================================================
+A2dpSinkFactory::A2dpSinkFactory() = default;
+A2dpSinkFactory::~A2dpSinkFactory() = default;
+
+bool A2dpSinkFactory::RegisterInstance(const Uuid& uuid,
+ const RegisterCallback& callback) {
+ VLOG(1) << __func__ << " - Uuid: " << uuid.ToString();
+
+ auto a2dp_sink = base::WrapUnique(new A2dpSink(uuid));
+ callback(BLE_STATUS_SUCCESS, uuid, std::move(a2dp_sink));
+ return true;
+}
+
+} // namespace bluetooth
diff --git a/service/a2dp_sink.h b/service/a2dp_sink.h
new file mode 100644
index 0000000..7a62805
--- /dev/null
+++ b/service/a2dp_sink.h
@@ -0,0 +1,103 @@
+//
+// Copyright (C) 2017 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 <vector>
+
+#include <base/macros.h>
+
+#include "service/bluetooth_instance.h"
+#include "service/hal/bluetooth_av_interface.h"
+
+namespace bluetooth {
+
+class A2dpSink : public BluetoothInstance,
+ private hal::BluetoothAvInterface::A2dpSinkObserver {
+ public:
+ // We only allow one instance of this object at a time.
+ static const int kSingletonInstanceId;
+
+ class Delegate {
+ public:
+ virtual void OnConnectionState(const std::string& device_address,
+ int state) = 0;
+ virtual void OnAudioState(const std::string& device_address, int state) = 0;
+ virtual void OnAudioConfig(const std::string& device_address,
+ uint32_t sample_rate, uint8_t channel_count) = 0;
+
+ protected:
+ virtual ~Delegate() = default;
+ };
+
+ ~A2dpSink() override;
+
+ void SetDelegate(Delegate* delegate);
+
+ // BluetoothInstance implementation:
+ const Uuid& GetAppIdentifier() const override;
+ int GetInstanceId() const override;
+
+ bool Enable();
+ void Disable();
+ bool Connect(const std::string& device_address);
+ bool Disconnect(const std::string& device_address);
+ void SetAudioFocusState(int focus_state);
+ void SetAudioTrackGain(float gain);
+
+ private:
+ friend class A2dpSinkFactory;
+
+ explicit A2dpSink(const Uuid& uuid);
+
+ // hal::bluetooth::hal::BluetoothAvInterface::Observer implementation:
+ void ConnectionStateCallback(bluetooth::hal::BluetoothAvInterface* iface,
+ const RawAddress& bd_addr,
+ btav_connection_state_t state) override;
+ void AudioStateCallback(bluetooth::hal::BluetoothAvInterface* iface,
+ const RawAddress& bd_addr,
+ btav_audio_state_t state) override;
+ void AudioConfigCallback(bluetooth::hal::BluetoothAvInterface* iface,
+ const RawAddress& bd_addr, uint32_t sample_rate,
+ uint8_t channel_count) override;
+
+ // See getters above for documentation.
+ const Uuid app_identifier_;
+
+ std::mutex mutex_;
+ std::mutex delegate_mutex_;
+ Delegate* delegate_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(A2dpSink);
+};
+
+class A2dpSinkFactory : public BluetoothInstanceFactory {
+ public:
+ A2dpSinkFactory();
+ ~A2dpSinkFactory() override;
+
+ // BluetoothInstanceFactory override:
+ bool RegisterInstance(const Uuid& uuid,
+ const RegisterCallback& callback) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(A2dpSinkFactory);
+};
+
+} // namespace bluetooth
diff --git a/service/a2dp_source.cc b/service/a2dp_source.cc
new file mode 100644
index 0000000..9e77007
--- /dev/null
+++ b/service/a2dp_source.cc
@@ -0,0 +1,216 @@
+//
+// Copyright (C) 2017 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/a2dp_source.h"
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "service/logging_helpers.h"
+
+#define PARSE_ADDR(str) \
+ ({ \
+ RawAddress tmp; \
+ if (!RawAddress::FromString((str), tmp)) { \
+ LOG(ERROR) << "Invalid device address given: " << (str); \
+ return false; \
+ } \
+ tmp; \
+ })
+
+#define TRY_RET(expr, err_msg) \
+ do { \
+ if (!(expr)) { \
+ LOG(ERROR) << err_msg; \
+ return false; \
+ } \
+ return true; \
+ } while (0)
+
+#define TRY_RET_FUNC(expr) TRY_RET(expr, __func__ << " failed")
+
+using bluetooth::hal::BluetoothAvInterface;
+using LockGuard = std::lock_guard<std::mutex>;
+
+namespace bluetooth {
+
+namespace {
+
+btav_a2dp_codec_config_t CodecConfigToFluoride(const A2dpCodecConfig& config) {
+ btav_a2dp_codec_config_t ret = {
+ .codec_type = static_cast<btav_a2dp_codec_index_t>(config.codec_type()),
+ .codec_priority =
+ static_cast<btav_a2dp_codec_priority_t>(config.codec_priority()),
+ .sample_rate =
+ static_cast<btav_a2dp_codec_sample_rate_t>(config.sample_rate()),
+ .bits_per_sample = static_cast<btav_a2dp_codec_bits_per_sample_t>(
+ config.bits_per_sample()),
+ .channel_mode =
+ static_cast<btav_a2dp_codec_channel_mode_t>(config.channel_mode()),
+ .codec_specific_1 = config.codec_specific_1(),
+ .codec_specific_2 = config.codec_specific_2(),
+ .codec_specific_3 = config.codec_specific_3(),
+ .codec_specific_4 = config.codec_specific_4(),
+ };
+
+ return ret;
+}
+
+std::vector<btav_a2dp_codec_config_t> CodecConfigsToFluoride(
+ const std::vector<A2dpCodecConfig>& configs) {
+ std::vector<btav_a2dp_codec_config_t> ret;
+ ret.reserve(configs.size());
+ for (const auto& config : configs) {
+ ret.push_back(CodecConfigToFluoride(config));
+ }
+
+ return ret;
+}
+A2dpCodecConfig FluorideCodecToCodec(const btav_a2dp_codec_config_t& config) {
+ A2dpCodecConfig ret(config.codec_type, config.codec_priority,
+ config.sample_rate, config.bits_per_sample,
+ config.channel_mode, config.codec_specific_1,
+ config.codec_specific_2, config.codec_specific_3,
+ config.codec_specific_4);
+
+ return ret;
+}
+
+std::vector<A2dpCodecConfig> FluorideCodecsToCodec(
+ const std::vector<btav_a2dp_codec_config_t>& configs) {
+ std::vector<A2dpCodecConfig> ret;
+ ret.reserve(configs.size());
+ for (const auto& config : configs) {
+ ret.push_back(FluorideCodecToCodec(config));
+ }
+
+ return ret;
+}
+
+} // namespace
+
+// static
+const int A2dpSource::kSingletonInstanceId = 0;
+
+A2dpSource::A2dpSource(const Uuid& uuid) : app_identifier_(uuid) {
+ hal::BluetoothAvInterface::Get()->AddA2dpSourceObserver(this);
+}
+
+A2dpSource::~A2dpSource() {
+ hal::BluetoothAvInterface::Get()->RemoveA2dpSourceObserver(this);
+}
+
+const Uuid& A2dpSource::GetAppIdentifier() const { return app_identifier_; }
+
+int A2dpSource::GetInstanceId() const { return kSingletonInstanceId; }
+
+void A2dpSource::SetDelegate(Delegate* delegate) {
+ LockGuard lock(delegate_mutex_);
+ delegate_ = delegate;
+}
+
+bool A2dpSource::Enable(const std::vector<A2dpCodecConfig>& codec_priorities) {
+ auto fluoride_priorities = CodecConfigsToFluoride(codec_priorities);
+ LockGuard lock(mutex_);
+ return hal::BluetoothAvInterface::Get()->A2dpSourceEnable(
+ fluoride_priorities);
+}
+
+void A2dpSource::Disable() {
+ LockGuard lock(mutex_);
+ hal::BluetoothAvInterface::Get()->A2dpSourceDisable();
+}
+
+bool A2dpSource::Connect(const std::string& device_address) {
+ RawAddress addr = PARSE_ADDR(device_address);
+ LockGuard lock(mutex_);
+ TRY_RET_FUNC(
+ hal::BluetoothAvInterface::Get()->GetA2dpSourceHALInterface()->connect(
+ addr) == BT_STATUS_SUCCESS);
+}
+
+bool A2dpSource::Disconnect(const std::string& device_address) {
+ RawAddress addr = PARSE_ADDR(device_address);
+ LockGuard lock(mutex_);
+ TRY_RET_FUNC(
+ hal::BluetoothAvInterface::Get()->GetA2dpSourceHALInterface()->disconnect(
+ addr) == BT_STATUS_SUCCESS);
+}
+
+bool A2dpSource::ConfigCodec(
+ const std::string& device_address,
+ const std::vector<A2dpCodecConfig>& codec_preferences) {
+ RawAddress addr = PARSE_ADDR(device_address);
+ auto fluoride_preferences = CodecConfigsToFluoride(codec_preferences);
+ LockGuard lock(mutex_);
+ TRY_RET_FUNC(hal::BluetoothAvInterface::Get()
+ ->GetA2dpSourceHALInterface()
+ ->config_codec(addr, fluoride_preferences) ==
+ BT_STATUS_SUCCESS);
+}
+
+void A2dpSource::ConnectionStateCallback(BluetoothAvInterface* iface,
+ const RawAddress& bd_addr,
+ btav_connection_state_t state) {
+ auto device_address = BtAddrString(&bd_addr);
+ LockGuard lock(delegate_mutex_);
+ if (delegate_)
+ delegate_->OnConnectionState(device_address, static_cast<int>(state));
+}
+
+void A2dpSource::AudioStateCallback(BluetoothAvInterface* iface,
+ const RawAddress& bd_addr,
+ btav_audio_state_t state) {
+ auto device_address = BtAddrString(&bd_addr);
+ LockGuard lock(delegate_mutex_);
+ if (delegate_)
+ delegate_->OnAudioState(device_address, static_cast<int>(state));
+}
+
+void A2dpSource::AudioConfigCallback(
+ BluetoothAvInterface* iface, const RawAddress& bd_addr,
+ const btav_a2dp_codec_config_t& codec_config_fluoride,
+ const std::vector<btav_a2dp_codec_config_t>
+ codecs_local_capabilities_fluoride,
+ const std::vector<btav_a2dp_codec_config_t>
+ codecs_selectable_capabilities_fluoride) {
+ auto device_address = BtAddrString(&bd_addr);
+ auto codec_config = FluorideCodecToCodec(codec_config_fluoride);
+ auto codecs_local_capabilities =
+ FluorideCodecsToCodec(codecs_local_capabilities_fluoride);
+ auto codecs_selectable_capabilities =
+ FluorideCodecsToCodec(codecs_selectable_capabilities_fluoride);
+ LockGuard lock(delegate_mutex_);
+ if (delegate_)
+ delegate_->OnAudioConfig(device_address, codec_config,
+ codecs_local_capabilities,
+ codecs_selectable_capabilities);
+}
+
+// A2dpSourceFactory implementation
+// ========================================================
+A2dpSourceFactory::A2dpSourceFactory() = default;
+A2dpSourceFactory::~A2dpSourceFactory() = default;
+
+bool A2dpSourceFactory::RegisterInstance(const Uuid& uuid,
+ const RegisterCallback& callback) {
+ VLOG(1) << __func__ << " - UUID: " << uuid.ToString();
+
+ auto a2dp_source = base::WrapUnique(new A2dpSource(uuid));
+ callback(BLE_STATUS_SUCCESS, uuid, std::move(a2dp_source));
+ return true;
+}
+
+} // namespace bluetooth
diff --git a/service/a2dp_source.h b/service/a2dp_source.h
new file mode 100644
index 0000000..f4e3ab3
--- /dev/null
+++ b/service/a2dp_source.h
@@ -0,0 +1,116 @@
+//
+// Copyright (C) 2017 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 <vector>
+
+#include <base/macros.h>
+
+#include "service/bluetooth_instance.h"
+#include "service/common/bluetooth/a2dp_codec_config.h"
+#include "service/hal/bluetooth_av_interface.h"
+
+namespace bluetooth {
+
+class A2dpSource : public BluetoothInstance,
+ private hal::BluetoothAvInterface::A2dpSourceObserver {
+ public:
+ // We only allow one instance of this object at a time.
+ static const int kSingletonInstanceId;
+
+ class Delegate {
+ public:
+ virtual void OnConnectionState(const std::string& device_address,
+ int state) = 0;
+ virtual void OnAudioState(const std::string& device_address, int state) = 0;
+ virtual void OnAudioConfig(
+ const std::string& device_address, A2dpCodecConfig codec_config,
+ const std::vector<A2dpCodecConfig>& codecs_local_capabilities,
+ const std::vector<A2dpCodecConfig>& codecs_selectable_capabilities) = 0;
+
+ protected:
+ virtual ~Delegate() = default;
+ };
+
+ ~A2dpSource() override;
+
+ void SetDelegate(Delegate* delegate);
+
+ // BluetoothInstance implementation:
+ const Uuid& GetAppIdentifier() const override;
+ int GetInstanceId() const override;
+
+ bool Enable(const std::vector<A2dpCodecConfig>& codec_priorities);
+ void Disable();
+ bool Connect(const std::string& device_address);
+ bool Disconnect(const std::string& device_address);
+ bool ConfigCodec(const std::string& device_address,
+ const std::vector<A2dpCodecConfig>& codec_preferences);
+
+ private:
+ friend class A2dpSourceFactory;
+
+ explicit A2dpSource(const Uuid& uuid);
+
+ // hal::bluetooth::hal::BluetoothAvInterface::Observer implementation:
+ void ConnectionStateCallback(hal::BluetoothAvInterface* iface,
+ const RawAddress& bd_addr,
+ btav_connection_state_t state) override;
+ void AudioStateCallback(hal::BluetoothAvInterface* iface,
+ const RawAddress& bd_addr,
+ btav_audio_state_t state) override;
+ void AudioConfigCallback(
+ hal::BluetoothAvInterface* iface, const RawAddress& bd_addr,
+ const btav_a2dp_codec_config_t& codec_config,
+ const std::vector<btav_a2dp_codec_config_t> codecs_local_capabilities,
+ const std::vector<btav_a2dp_codec_config_t>
+ codecs_selectable_capabilities) override;
+
+ // For |GetAppIdentifier|.
+ const Uuid app_identifier_;
+
+ std::mutex mutex_;
+
+ // A second mutex is used only for |delegate_|. We cannot use |mutex_| because
+ // it may cause a deadlock if the caller and Delegate both take the same lock
+ // 'clock'.
+ // In that scenario, the caller may take 'clock' first and will try to take
+ // |mutex_| second. The callback will take |mutex_| first and invoke a
+ // delegate function which attempts to take 'clock'.
+ std::mutex delegate_mutex_;
+ Delegate* delegate_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(A2dpSource);
+};
+
+class A2dpSourceFactory : public BluetoothInstanceFactory {
+ public:
+ A2dpSourceFactory();
+ ~A2dpSourceFactory() override;
+
+ // BluetoothInstanceFactory override:
+ bool RegisterInstance(const Uuid& uuid,
+ const RegisterCallback& callback) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(A2dpSourceFactory);
+};
+
+} // namespace bluetooth
diff --git a/service/adapter.cc b/service/adapter.cc
index 853ffdf..669aeff 100644
--- a/service/adapter.cc
+++ b/service/adapter.cc
@@ -24,6 +24,10 @@
#include <base/logging.h>
#include <base/observer_list.h>
+#include "service/a2dp_sink.h"
+#include "service/a2dp_source.h"
+#include "service/avrcp_control.h"
+#include "service/avrcp_target.h"
#include "service/common/bluetooth/util/atomic_string.h"
#include "service/gatt_client.h"
#include "service/gatt_server.h"
@@ -38,6 +42,89 @@
namespace bluetooth {
+namespace {
+
+RemoteDeviceProps ParseRemoteDeviceProps(int num_properties,
+ bt_property_t* properties) {
+ std::string name;
+ std::string address;
+ std::vector<Uuid> service_uuids;
+ int32_t device_class = 0;
+ int32_t device_type = 0;
+ int32_t rssi = 0;
+
+ for (int i = 0; i < num_properties; ++i) {
+ bt_property_t* property = properties + i;
+ switch (property->type) {
+ case BT_PROPERTY_BDNAME: {
+ if (property->len < 0) {
+ NOTREACHED() << "Invalid length for BT_PROPERTY_BDNAME";
+ break;
+ }
+ bt_bdname_t* hal_name = reinterpret_cast<bt_bdname_t*>(property->val);
+ name = reinterpret_cast<char*>(hal_name->name);
+ break;
+ }
+ case BT_PROPERTY_BDADDR: {
+ if (property->len != sizeof(RawAddress)) {
+ NOTREACHED() << "Invalid length for BT_PROPERTY_BDADDR";
+ break;
+ }
+ address = BtAddrString(reinterpret_cast<RawAddress*>(property->val));
+ break;
+ }
+ case BT_PROPERTY_UUIDS: {
+ if (property->len < 0) {
+ NOTREACHED() << "Negative length on BT_PROPERTY_UUIDS:";
+ break;
+ }
+ if (property->len % sizeof(Uuid) != 0) {
+ NOTREACHED() << "Trailing bytes on BT_PROPERTY_UUIDS:";
+ }
+ auto uuids = static_cast<const Uuid*>(property->val);
+
+ for (size_t i = 0; i < property->len / sizeof(Uuid); ++i) {
+ service_uuids.push_back(uuids[i]);
+ }
+ break;
+ }
+ case BT_PROPERTY_CLASS_OF_DEVICE: {
+ if (property->len != sizeof(int32_t)) {
+ NOTREACHED() << "Invalid length for BT_PROPERTY_CLASS_OF_DEVICE";
+ break;
+ }
+ device_class = *reinterpret_cast<const int32_t*>(property->val);
+ break;
+ }
+ case BT_PROPERTY_TYPE_OF_DEVICE: {
+ if (property->len != sizeof(int32_t)) {
+ NOTREACHED() << "Invalid length for BT_PROPERTY_TYPE_OF_DEVICE";
+ break;
+ }
+ device_type = *reinterpret_cast<const int32_t*>(property->val);
+ break;
+ }
+ case BT_PROPERTY_REMOTE_RSSI: {
+ if (property->len != sizeof(int8_t)) {
+ NOTREACHED() << "Invalid length for BT_PROPERTY_REMOTE_RSSI";
+ break;
+ }
+ rssi = *reinterpret_cast<const int8_t*>(property->val);
+ break;
+ }
+ default:
+ VLOG(1) << "Unhandled adapter property: "
+ << BtPropertyText(property->type);
+ break;
+ }
+ }
+
+ return RemoteDeviceProps(name, address, service_uuids, device_class,
+ device_type, rssi);
+}
+
+} // namespace
+
// static
const char Adapter::kDefaultAddress[] = "00:00:00:00:00:00";
// static
@@ -69,6 +156,41 @@
// Default implementation does nothing
}
+void Adapter::Observer::OnScanEnableChanged(Adapter* adapter,
+ bool scan_enabled) {
+ // Default implementation does nothing
+}
+
+void Adapter::Observer::OnSspRequest(Adapter* adapter,
+ const std::string& device_address,
+ const std::string& device_name, int cod,
+ int pairing_variant, int pass_key) {
+ // Default implementation does nothing
+}
+
+void Adapter::Observer::OnBondStateChanged(Adapter* adapter, int status,
+ const std::string& device_address,
+ int state) {
+ // Default implementation does nothing
+}
+
+void Adapter::Observer::OnGetBondedDevices(
+ Adapter* adapter, int status,
+ const std::vector<std::string>& bonded_devices) {
+ // Default implementation does nothing
+}
+
+void Adapter::Observer::OnGetRemoteDeviceProperties(
+ Adapter* adapter, int status, const std::string& device_address,
+ const RemoteDeviceProps& properties) {
+ // Default implementation does nothing
+}
+
+void Adapter::Observer::OnDeviceFound(Adapter* adapter,
+ const RemoteDeviceProps& properties) {
+ // Default implementation does nothing
+}
+
// The real Adapter implementation used in production.
class AdapterImpl : public Adapter, public hal::BluetoothInterface::Observer {
public:
@@ -78,6 +200,10 @@
name_(kDefaultName) {
memset(&local_le_features_, 0, sizeof(local_le_features_));
hal::BluetoothInterface::Get()->AddObserver(this);
+ a2dp_sink_factory_.reset(new A2dpSinkFactory);
+ a2dp_source_factory_.reset(new A2dpSourceFactory);
+ avrcp_control_factory_.reset(new AvrcpControlFactory);
+ avrcp_target_factory_.reset(new AvrcpTargetFactory);
ble_client_factory_.reset(new LowEnergyClientFactory(*this));
ble_advertiser_factory_.reset(new LowEnergyAdvertiserFactory());
ble_scanner_factory_.reset(new LowEnergyScannerFactory(*this));
@@ -183,6 +309,84 @@
std::string GetAddress() const override { return address_.Get(); }
+ bool SetScanMode(int scan_mode) override {
+ switch (scan_mode) {
+ case BT_SCAN_MODE_NONE:
+ case BT_SCAN_MODE_CONNECTABLE:
+ case BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE:
+ break;
+ default:
+ LOG(ERROR) << "Unknown scan mode: " << scan_mode;
+ return false;
+ }
+
+ auto bd_scanmode = static_cast<bt_scan_mode_t>(scan_mode);
+
+ if (!SetAdapterProperty(BT_PROPERTY_ADAPTER_SCAN_MODE, &bd_scanmode,
+ sizeof(bd_scanmode))) {
+ LOG(ERROR) << "Failed to set scan mode to : " << scan_mode;
+ return false;
+ }
+
+ return true;
+ }
+
+ bool SetScanEnable(bool scan_enable) override {
+ if (scan_enable) {
+ int status =
+ hal::BluetoothInterface::Get()->GetHALInterface()->start_discovery();
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to enable scanning";
+ return false;
+ }
+ } else {
+ int status =
+ hal::BluetoothInterface::Get()->GetHALInterface()->cancel_discovery();
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to disable scanning";
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool SspReply(const std::string& device_address, int variant, bool accept,
+ int32_t pass_key) override {
+ RawAddress addr;
+ if (!RawAddress::FromString(device_address, addr)) {
+ LOG(ERROR) << "Invalid device address given: " << device_address;
+ return false;
+ }
+
+ int status = hal::BluetoothInterface::Get()->GetHALInterface()->ssp_reply(
+ &addr, static_cast<bt_ssp_variant_t>(variant), accept, pass_key);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to send SSP response - status: "
+ << BtStatusText((const bt_status_t)status);
+ return false;
+ }
+
+ return true;
+ }
+
+ bool CreateBond(const std::string& device_address, int transport) override {
+ RawAddress addr;
+ if (!RawAddress::FromString(device_address, addr)) {
+ LOG(ERROR) << "Invalid device address given: " << device_address;
+ return false;
+ }
+
+ int status = hal::BluetoothInterface::Get()->GetHALInterface()->create_bond(
+ &addr, transport);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to create bond - status: "
+ << BtStatusText((const bt_status_t)status);
+ return false;
+ }
+
+ return true;
+ }
+
bool IsMultiAdvertisementSupported() override {
lock_guard<mutex> lock(local_le_features_lock_);
return local_le_features_.max_adv_instance >= kMinAdvInstancesForMultiAdv;
@@ -209,6 +413,72 @@
kMinOffloadedScanStorageBytes;
}
+ bool GetBondedDevices() override {
+ int status =
+ hal::BluetoothInterface::Get()->GetHALInterface()->get_adapter_property(
+ BT_PROPERTY_ADAPTER_BONDED_DEVICES);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to get bonded devices. Status: "
+ << BtStatusText(static_cast<bt_status_t>(status));
+ return false;
+ }
+
+ return true;
+ }
+
+ bool RemoveBond(const std::string& device_address) override {
+ RawAddress addr;
+ if (!RawAddress::FromString(device_address, addr)) {
+ LOG(ERROR) << "Invalid device address given: " << device_address;
+ return false;
+ }
+
+ int status =
+ hal::BluetoothInterface::Get()->GetHALInterface()->remove_bond(&addr);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to send remove bond - status: "
+ << BtStatusText(static_cast<bt_status_t>(status));
+ return false;
+ }
+
+ return true;
+ }
+
+ bool GetRemoteDeviceProperties(const std::string& device_address) override {
+ RawAddress addr;
+ if (!RawAddress::FromString(device_address, addr)) {
+ LOG(ERROR) << "Invalid device address given: " << device_address;
+ return false;
+ }
+
+ int status = hal::BluetoothInterface::Get()
+ ->GetHALInterface()
+ ->get_remote_device_properties(&addr);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to send GetRemoteDeviceProperties - status: "
+ << BtStatusText((const bt_status_t)status);
+ return false;
+ }
+
+ return true;
+ }
+
+ A2dpSinkFactory* GetA2dpSinkFactory() const override {
+ return a2dp_sink_factory_.get();
+ }
+
+ A2dpSourceFactory* GetA2dpSourceFactory() const override {
+ return a2dp_source_factory_.get();
+ }
+
+ AvrcpControlFactory* GetAvrcpControlFactory() const override {
+ return avrcp_control_factory_.get();
+ }
+
+ AvrcpTargetFactory* GetAvrcpTargetFactory() const override {
+ return avrcp_target_factory_.get();
+ }
+
LowEnergyClientFactory* GetLowEnergyClientFactory() const override {
return ble_client_factory_.get();
}
@@ -257,6 +527,16 @@
if (status != BT_STATUS_SUCCESS) {
LOG(ERROR) << "status: " << BtStatusText(status);
+
+ for (int i = 0; i < num_properties; ++i) {
+ bt_property_t* property = properties + i;
+ if (property->type == BT_PROPERTY_ADAPTER_BONDED_DEVICES) {
+ lock_guard<mutex> lock(observers_lock_);
+ for (auto& observer : observers_) {
+ observer.OnGetBondedDevices(this, status, {});
+ }
+ }
+ }
return;
}
@@ -290,6 +570,29 @@
LOG(INFO) << "Supported LE features updated";
break;
}
+ case BT_PROPERTY_ADAPTER_BONDED_DEVICES: {
+ if (property->len < 0) {
+ NOTREACHED() << "Negative property length";
+ break;
+ }
+ auto addrs = reinterpret_cast<const RawAddress*>(property->val);
+ if (property->len % sizeof(addrs[0]) != 0) {
+ LOG(ERROR) << "Invalid property length: " << property->len;
+ // TODO(bcf): Seems to be a bug where we hit this somewhat
+ // frequently.
+ break;
+ }
+ std::vector<std::string> str_addrs;
+
+ for (size_t i = 0; i < property->len / sizeof(addrs[0]); ++i)
+ str_addrs.push_back(BtAddrString(addrs + i));
+
+ lock_guard<mutex> lock(observers_lock_);
+ for (auto& observer : observers_) {
+ observer.OnGetBondedDevices(this, status, str_addrs);
+ }
+ break;
+ }
default:
VLOG(1) << "Unhandled adapter property: "
<< BtPropertyText(property->type);
@@ -300,9 +603,82 @@
}
}
- void SSPRequestCallback(RawAddress*, bt_bdname_t*, uint32_t, bt_ssp_variant_t,
+ void RemoteDevicePropertiesCallback(bt_status_t status,
+ RawAddress* remote_bdaddr,
+ int num_properties,
+ bt_property_t* properties) override {
+ std::string device_address = BtAddrString(remote_bdaddr);
+ if (status != BT_STATUS_SUCCESS) {
+ lock_guard<mutex> lock(observers_lock_);
+ for (auto& observer : observers_) {
+ observer.OnGetRemoteDeviceProperties(this, status, device_address,
+ RemoteDeviceProps());
+ }
+ return;
+ }
+
+ RemoteDeviceProps props =
+ ParseRemoteDeviceProps(num_properties, properties);
+
+ std::string address = BtAddrString(remote_bdaddr);
+ props.set_address(address);
+
+ lock_guard<mutex> lock(observers_lock_);
+ for (auto& observer : observers_) {
+ observer.OnGetRemoteDeviceProperties(this, status, device_address, props);
+ }
+ }
+
+ void DeviceFoundCallback(int num_properties,
+ bt_property_t* properties) override {
+ RemoteDeviceProps props =
+ ParseRemoteDeviceProps(num_properties, properties);
+
+ lock_guard<mutex> lock(observers_lock_);
+ for (auto& observer : observers_) {
+ observer.OnDeviceFound(this, props);
+ }
+ }
+
+ void DiscoveryStateChangedCallback(bt_discovery_state_t state) override {
+ bool enabled = false;
+ switch (state) {
+ case BT_DISCOVERY_STOPPED:
+ enabled = false;
+ break;
+ case BT_DISCOVERY_STARTED:
+ enabled = true;
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ for (auto& observer : observers_) {
+ observer.OnScanEnableChanged(this, enabled);
+ }
+ }
+
+ void SSPRequestCallback(RawAddress* remote_bdaddr, bt_bdname_t* bd_name,
+ uint32_t cod, bt_ssp_variant_t pairing_variant,
uint32_t pass_key) override {
- LOG(INFO) << "Passkey is: " << pass_key;
+ std::string device_address = BtAddrString(remote_bdaddr);
+ std::string name = reinterpret_cast<char*>(bd_name->name);
+
+ lock_guard<mutex> lock(observers_lock_);
+ for (auto& observer : observers_) {
+ observer.OnSspRequest(this, device_address, name, cod, pairing_variant,
+ pass_key);
+ }
+ }
+
+ void BondStateChangedCallback(bt_status_t status, RawAddress* remote_bdaddr,
+ bt_bond_state_t state) override {
+ std::string device_address = BtAddrString(remote_bdaddr);
+
+ lock_guard<mutex> lock(observers_lock_);
+ for (auto& observer : observers_) {
+ observer.OnBondStateChanged(this, status, device_address, state);
+ }
}
void AclStateChangedCallback(bt_status_t status,
@@ -392,6 +768,18 @@
std::mutex connected_devices_lock_;
std::unordered_set<std::string> connected_devices_;
+ // Factory used to create per-app A2dpSink instances.
+ std::unique_ptr<A2dpSinkFactory> a2dp_sink_factory_;
+
+ // Factory used to create per-app A2dpSource instances.
+ std::unique_ptr<A2dpSourceFactory> a2dp_source_factory_;
+
+ // Factory used to create per-app AvrcpControl instances.
+ std::unique_ptr<AvrcpControlFactory> avrcp_control_factory_;
+
+ // Factory used to create per-app AvrcpTarget instances.
+ std::unique_ptr<AvrcpTargetFactory> avrcp_target_factory_;
+
// Factory used to create per-app LowEnergyClient instances.
std::unique_ptr<LowEnergyClientFactory> ble_client_factory_;
diff --git a/service/adapter.h b/service/adapter.h
index 3becaae..edb8afe 100644
--- a/service/adapter.h
+++ b/service/adapter.h
@@ -1,5 +1,5 @@
//
-// Copyright 2015 Google, Inc.
+// 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.
@@ -17,13 +17,20 @@
#pragma once
#include <memory>
+#include <string>
+#include <vector>
#include <base/macros.h>
#include "service/common/bluetooth/adapter_state.h"
+#include "service/common/bluetooth/remote_device_props.h"
namespace bluetooth {
+class A2dpSinkFactory;
+class A2dpSourceFactory;
+class AvrcpControlFactory;
+class AvrcpTargetFactory;
class GattClientFactory;
class GattServerFactory;
class LowEnergyAdvertiserFactory;
@@ -61,6 +68,34 @@
// true and vice versa.
virtual void OnDeviceConnectionStateChanged(
Adapter* adapter, const std::string& device_address, bool connected);
+
+ // Called when scanning is enabled or disabled.
+ virtual void OnScanEnableChanged(Adapter* adapter, bool scan_enabled);
+
+ // Called when a SSP pairing request comes from a remote device.
+ virtual void OnSspRequest(Adapter* adapter,
+ const std::string& device_address,
+ const std::string& device_name, int cod,
+ int pairing_variant, int pass_key);
+
+ // Called when a remote device bond state changes.
+ virtual void OnBondStateChanged(Adapter* adapter, int status,
+ const std::string& device_address,
+ int state);
+
+ // Called in response to |GetBondedDevices|.
+ virtual void OnGetBondedDevices(
+ Adapter* adapter, int status,
+ const std::vector<std::string>& bonded_devices);
+
+ // Called in response to |GetRemoteDeviceProperties|.
+ virtual void OnGetRemoteDeviceProperties(Adapter* adapter, int status,
+ const std::string& device_address,
+ const RemoteDeviceProps& props);
+
+ // Called when a device is found through scanning.
+ virtual void OnDeviceFound(Adapter* adapter,
+ const RemoteDeviceProps& props);
};
// Returns an Adapter implementation to be used in production. Don't use these
@@ -103,6 +138,19 @@
// Returns the local adapter addess in string form (XX:XX:XX:XX:XX:XX).
virtual std::string GetAddress() const = 0;
+ // Set discoverability mode.
+ virtual bool SetScanMode(int scan_mode) = 0;
+
+ // Enable or disable discoverability.
+ virtual bool SetScanEnable(bool scan_enable) = 0;
+
+ // Reply to an SSP request received in |OnSspRequest|.
+ virtual bool SspReply(const std::string& device_address, int variant,
+ bool accept, int32_t pass_key) = 0;
+
+ // Create a bond with device specified by |device_address|.
+ virtual bool CreateBond(const std::string& device_address, int transport) = 0;
+
// Returns true if the local adapter supports the Low-Energy
// multi-advertisement feature.
virtual bool IsMultiAdvertisementSupported() = 0;
@@ -122,6 +170,36 @@
// Returns true if hardware-backed batch scanning is supported.
virtual bool IsOffloadedScanBatchingSupported() = 0;
+ // When the stack call completes, |OnGetBondedDevices| will be called.
+ virtual bool GetBondedDevices() = 0;
+
+ // When the stack call completets, |OnBondStateChanged| will be called.
+ virtual bool RemoveBond(const std::string& device_address) = 0;
+
+ // When the stack call completets, |OnGetRemoteDeviceProperties| will be
+ // called.
+ virtual bool GetRemoteDeviceProperties(const std::string& device_address) = 0;
+
+ // Returns a pointer to the A2dpSinkFactory. This can be used to
+ // register per-application A2dpSinkClient instances to perform A2DP sink
+ // operations.
+ virtual A2dpSinkFactory* GetA2dpSinkFactory() const = 0;
+
+ // Returns a pointer to the A2dpSourceFactory. This can be used to
+ // register per-application A2dpSourceClient instances to perform A2DP source
+ // operations.
+ virtual A2dpSourceFactory* GetA2dpSourceFactory() const = 0;
+
+ // Returns a pointer to the AvrcpControlFactory. This can be used to register
+ // per-application AvrcpControlClient instances to perform AVRCP control
+ // operations.
+ virtual AvrcpControlFactory* GetAvrcpControlFactory() const = 0;
+
+ // Returns a pointer to the AvrcpTargetFactory. This can be used to register
+ // per-application AvrcpTargetClient instances to perform AVRCP target
+ // operations.
+ virtual AvrcpTargetFactory* GetAvrcpTargetFactory() const = 0;
+
// Returns a pointer to the LowEnergyClientFactory. This can be used to
// register per-application LowEnergyClient instances to perform BLE GAP
// operations.
diff --git a/service/avrcp_control.cc b/service/avrcp_control.cc
new file mode 100644
index 0000000..18dc2aa
--- /dev/null
+++ b/service/avrcp_control.cc
@@ -0,0 +1,231 @@
+//
+// Copyright 2017 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/avrcp_control.h"
+
+#include <cerrno>
+#include <climits>
+#include <string>
+
+#include <base/logging.h>
+#include <base/memory/ptr_util.h>
+#include <base/strings/string_number_conversions.h>
+
+#include "service/logging_helpers.h"
+
+#include "stack/include/avrc_defs.h"
+
+
+namespace bluetooth {
+
+AvrcpControl::AvrcpControl(const Uuid& uuid, int control_id)
+ : app_identifier_(uuid), control_id_(control_id) {
+ hal::BluetoothAvrcpInterface::Get()->AddControlObserver(this);
+}
+
+AvrcpControl::~AvrcpControl() {
+ hal::BluetoothAvrcpInterface::Get()->RemoveControlObserver(this);
+}
+
+const Uuid& AvrcpControl::GetAppIdentifier() const { return app_identifier_; }
+
+int AvrcpControl::GetInstanceId() const { return control_id_; }
+
+void AvrcpControl::SetDelegate(Delegate* delegate) {
+ std::lock_guard<std::mutex> lock(delegate_mutex_);
+ delegate_ = delegate;
+}
+
+bool AvrcpControl::Enable() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ return hal::BluetoothAvrcpInterface::Get()->AvrcpControlEnable();
+}
+
+void AvrcpControl::Disable() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ hal::BluetoothAvrcpInterface::Get()->AvrcpControlDisable();
+}
+
+bool AvrcpControl::SendPassThroughCommand(const std::string& device_address,
+ uint8_t key_code, bool key_pressed) {
+ RawAddress addr;
+ if (!RawAddress::FromString(device_address, addr)) {
+ LOG(ERROR) << "Invalid device address given: " << device_address;
+ return false;
+ }
+
+ uint8_t key_state = key_pressed ? AVRC_STATE_PRESS : AVRC_STATE_RELEASE;
+ bt_status_t status;
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ status = hal::BluetoothAvrcpInterface::Get()
+ ->GetControlHALInterface()
+ ->send_pass_through_cmd(addr, key_code, key_state);
+ }
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to send passthrough command";
+ return false;
+ }
+
+ return true;
+}
+
+bool AvrcpControl::SetAbsVolumeResponse(const std::string& device_address,
+ int32_t abs_vol, int32_t label) {
+ RawAddress addr;
+ if (!RawAddress::FromString(device_address, addr)) {
+ LOG(ERROR) << "Invalid device address given: " << device_address;
+ return false;
+ }
+
+ bt_status_t status;
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ status = hal::BluetoothAvrcpInterface::Get()
+ ->GetControlHALInterface()
+ ->set_volume_rsp(addr, abs_vol, label);
+ }
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to send set absolute volume response";
+ return false;
+ }
+
+ return true;
+}
+
+bool AvrcpControl::RegisterForAbsVolumeCallbackResponse(
+ const std::string& device_address, int32_t response_type, int32_t abs_vol,
+ int32_t label) {
+ RawAddress addr;
+ if (!RawAddress::FromString(device_address, addr)) {
+ LOG(ERROR) << "Invalid device address given: " << device_address;
+ return false;
+ }
+
+ bt_status_t status;
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ status = hal::BluetoothAvrcpInterface::Get()
+ ->GetControlHALInterface()
+ ->register_abs_vol_rsp(
+ addr, static_cast<btrc_notification_type_t>(response_type),
+ abs_vol, label);
+ }
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR)
+ << "Failed to send send register for absolute volume change callback";
+ return false;
+ }
+
+ return true;
+}
+
+void AvrcpControl::ConnectionStateCallback(bool rc_connect, bool bt_connect,
+ const RawAddress& bd_addr) {
+ std::string device_address = BtAddrString(&bd_addr);
+ std::lock_guard<std::mutex> lock(delegate_mutex_);
+ if (delegate_)
+ delegate_->OnConnectionState(rc_connect, bt_connect, device_address);
+}
+
+void AvrcpControl::CtrlSetabsvolCmdCallback(const RawAddress& bd_addr,
+ uint8_t abs_vol, uint8_t label) {
+ std::string device_address = BtAddrString(&bd_addr);
+ std::lock_guard<std::mutex> lock(delegate_mutex_);
+ if (delegate_)
+ delegate_->OnSetAbsVolumeRequest(device_address, abs_vol, label);
+}
+
+void AvrcpControl::CtrlRegisternotificationAbsVolCallback(
+ const RawAddress& bd_addr, uint8_t label) {
+ std::string device_address = BtAddrString(&bd_addr);
+ std::lock_guard<std::mutex> lock(delegate_mutex_);
+ if (delegate_)
+ delegate_->OnRegisterForAbsVolumeCallbackRequest(device_address, label);
+}
+
+void AvrcpControl::CtrlTrackChangedCallback(const RawAddress& bd_addr,
+ uint8_t num_attr,
+ btrc_element_attr_val_t* p_attrs) {
+ std::string device_address = BtAddrString(&bd_addr);
+
+ std::string title;
+ std::string artist;
+ std::string album;
+ std::string genre;
+ int track_num = -1;
+ int num_tracks = -1;
+ int play_time = -1;
+
+ for (size_t i = 0; i < num_attr; ++i) {
+ auto attr_text = reinterpret_cast<char*>(p_attrs[i].text);
+ switch (p_attrs[i].attr_id) {
+ case BTRC_MEDIA_ATTR_ID_TITLE:
+ title = attr_text;
+ break;
+ case BTRC_MEDIA_ATTR_ID_ARTIST:
+ artist = attr_text;
+ break;
+ case BTRC_MEDIA_ATTR_ID_ALBUM:
+ album = attr_text;
+ break;
+ case BTRC_MEDIA_ATTR_ID_TRACK_NUM:
+ if (!base::StringToInt(attr_text, &track_num)) {
+ LOG(ERROR) << "Failed to parse track number";
+ }
+ break;
+ case BTRC_MEDIA_ATTR_ID_NUM_TRACKS:
+ if (!base::StringToInt(attr_text, &num_tracks)) {
+ LOG(ERROR) << "Failed to parse number of tracks";
+ }
+ break;
+ case BTRC_MEDIA_ATTR_ID_GENRE:
+ genre = attr_text;
+ break;
+ case BTRC_MEDIA_ATTR_ID_PLAYING_TIME:
+ if (!base::StringToInt(attr_text, &play_time)) {
+ LOG(ERROR) << "Failed to parse playing time";
+ }
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+
+ const AvrcpMediaAttr attr(title, artist, album, genre, track_num, num_tracks,
+ play_time);
+
+ std::lock_guard<std::mutex> lock(delegate_mutex_);
+ if (delegate_) delegate_->OnTrackChanged(device_address, attr);
+}
+
+// AvrcpControlFactory implementation
+// ========================================================
+
+AvrcpControlFactory::AvrcpControlFactory() = default;
+AvrcpControlFactory::~AvrcpControlFactory() = default;
+
+bool AvrcpControlFactory::RegisterInstance(const Uuid& uuid,
+ const RegisterCallback& callback) {
+ VLOG(1) << __func__ << " - Uuid: " << uuid.ToString();
+
+ int control_id = next_control_id_++;
+ std::unique_ptr<AvrcpControl> hf_client(new AvrcpControl(uuid, control_id));
+ callback(BLE_STATUS_SUCCESS, uuid, std::move(hf_client));
+ return true;
+}
+
+} // namespace bluetooth
diff --git a/service/avrcp_control.h b/service/avrcp_control.h
new file mode 100644
index 0000000..7cde24d
--- /dev/null
+++ b/service/avrcp_control.h
@@ -0,0 +1,135 @@
+//
+// Copyright (C) 2017 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 "base/macros.h"
+
+#include "bluetooth/uuid.h"
+#include "service/bluetooth_instance.h"
+#include "service/common/bluetooth/avrcp_media_attr.h"
+#include "service/common/bluetooth/service.h"
+#include "service/hal/bluetooth_avrcp_interface.h"
+
+namespace bluetooth {
+
+class AvrcpControl : public BluetoothInstance,
+ private hal::BluetoothAvrcpInterface::ControlObserver {
+ public:
+ class Delegate {
+ public:
+ virtual void OnConnectionState(bool rc_connect, bool bt_connect,
+ const std::string& device_address) = 0;
+
+ virtual void OnTrackChanged(const std::string& device_address,
+ const AvrcpMediaAttr& attr) = 0;
+
+ virtual void OnSetAbsVolumeRequest(const std::string& device_address,
+ int32_t abs_vol, int32_t label) = 0;
+
+ virtual void OnRegisterForAbsVolumeCallbackRequest(
+ const std::string& device_address, int32_t label) = 0;
+
+ protected:
+ virtual ~Delegate() = default;
+ };
+
+ // The destructor automatically unregisters this instance from the stack.
+ ~AvrcpControl() override;
+
+ // Assigns a delegate to this instance. |delegate| must out-live this
+ // AvrcpControl instance.
+ void SetDelegate(Delegate* delegate);
+
+ // BluetoothClientInstace overrides:
+ const Uuid& GetAppIdentifier() const override;
+ int GetInstanceId() const override;
+
+ bool Enable();
+ void Disable();
+
+ // Send a remote control button command. Commands which can be sent
+ // are defined here:
+ // http://1394ta.org/wp-content/uploads/2015/07/2007001.pdf
+ bool SendPassThroughCommand(const std::string& device_address,
+ uint8_t key_code, bool key_pressed);
+
+ // Send a response to a request to change absolute volume.
+ bool SetAbsVolumeResponse(const std::string& device_address, int32_t abs_vol,
+ int32_t label);
+
+ // Send a response to a register for absolute volume change callback.
+ bool RegisterForAbsVolumeCallbackResponse(const std::string& device_address,
+ int32_t response_type,
+ int32_t abs_vol, int32_t label);
+
+ private:
+ friend class AvrcpControlFactory;
+
+ // Constructor shouldn't be called directly as instances are meant to be
+ // obtained from the factory.
+ AvrcpControl(const Uuid& uuid, int control_id);
+
+ // hal::BluetoothAvrcpInterface::ControlObserver implementation:
+ void ConnectionStateCallback(bool rc_connect, bool bt_connect,
+ const RawAddress& bd_addr) override;
+ void CtrlSetabsvolCmdCallback(const RawAddress& bd_addr, uint8_t abs_vol,
+ uint8_t label) override;
+ void CtrlRegisternotificationAbsVolCallback(const RawAddress& bd_addr,
+ uint8_t label) override;
+ void CtrlTrackChangedCallback(const RawAddress& bd_addr, uint8_t num_attr,
+ btrc_element_attr_val_t* p_attrs) override;
+
+ // See getters for documentation.
+ const Uuid app_identifier_;
+ const int control_id_;
+
+ // Mutex that synchronizes access to the entries below.
+ std::mutex mutex_;
+
+ // Raw handle to the Delegate, which must outlive this AvrcpControl instance.
+ std::mutex delegate_mutex_;
+ Delegate* delegate_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(AvrcpControl);
+};
+
+// AvrcpControlFactory is used to register and obtain a per-application
+// AvrcpControl
+// instance. Users should call RegisterClient to obtain their own unique
+// AvrcpControl instance that has been registered with the Bluetooth stack.
+class AvrcpControlFactory
+ : public BluetoothInstanceFactory,
+ private hal::BluetoothAvrcpInterface::ControlObserver {
+ public:
+ // Don't construct/destruct directly except in tests. Instead, obtain a handle
+ // from an Adapter instance.
+ AvrcpControlFactory();
+ ~AvrcpControlFactory() override;
+
+ // BluetoothInstanceFactory override:
+ bool RegisterInstance(const Uuid& uuid,
+ const RegisterCallback& callback) override;
+
+ private:
+ std::atomic<int> next_control_id_{0};
+ DISALLOW_COPY_AND_ASSIGN(AvrcpControlFactory);
+};
+
+} // namespace bluetooth
diff --git a/service/avrcp_target.cc b/service/avrcp_target.cc
new file mode 100644
index 0000000..fb63fba
--- /dev/null
+++ b/service/avrcp_target.cc
@@ -0,0 +1,381 @@
+//
+// Copyright (C) 2017 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/avrcp_target.h"
+
+#include <algorithm>
+#include <cerrno>
+#include <climits>
+#include <string>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "service/logging_helpers.h"
+
+#include "stack/include/avrc_defs.h"
+
+#define PARSE_ADDR(str) \
+ ({ \
+ RawAddress tmp; \
+ if (!RawAddress::FromString((str), tmp)) { \
+ LOG(ERROR) << "Invalid device address given: " << (str); \
+ return false; \
+ } \
+ tmp; \
+ })
+
+#define TRY_RET(expr, err_msg) \
+ do { \
+ if (!(expr)) { \
+ LOG(ERROR) << err_msg; \
+ return false; \
+ } \
+ return true; \
+ } while (0)
+
+#define TRY_RET_FUNC(expr) TRY_RET(expr, __func__ << " failed")
+
+using LockGuard = std::lock_guard<std::mutex>;
+
+namespace bluetooth {
+
+namespace {
+
+std::vector<btrc_player_setting_text_t> StringValueToPlayerSettingsText(
+ const std::vector<AvrcpStringValue>& attrs) {
+ std::vector<btrc_player_setting_text_t> btrc_attrs(attrs.size());
+ for (size_t i = 0; i < attrs.size(); ++i) {
+ btrc_attrs[i].id = attrs[i].id();
+ std::string str(attrs[i].value());
+ size_t to_copy = std::min(sizeof(btrc_attrs[i].text) - 1, str.size());
+ if (to_copy < str.size()) {
+ LOG(WARNING) << "Value truncated";
+ }
+
+ memcpy(btrc_attrs[i].text, str.data(), to_copy);
+ btrc_attrs[i].text[to_copy] = '\0';
+ }
+
+ return btrc_attrs;
+}
+
+std::vector<btrc_element_attr_val_t> StringValueToElementAttrVal(
+ const std::vector<AvrcpStringValue>& attrs) {
+ std::vector<btrc_element_attr_val_t> btrc_attrs(attrs.size());
+ for (size_t i = 0; i < attrs.size(); ++i) {
+ btrc_attrs[i].attr_id = attrs[i].id();
+ std::string str(attrs[i].value());
+ size_t to_copy = std::min(sizeof(btrc_attrs[i].text) - 1, str.size());
+ if (to_copy < str.size()) {
+ LOG(WARNING) << "Value truncated";
+ }
+
+ memcpy(btrc_attrs[i].text, str.data(), to_copy);
+ btrc_attrs[i].text[to_copy] = '\0';
+ }
+
+ return btrc_attrs;
+}
+
+} // namespace
+
+// static
+const int AvrcpTarget::kSingletonInstanceId = 0;
+
+AvrcpTarget::AvrcpTarget(const Uuid& uuid) : app_identifier_(uuid) {
+ hal::BluetoothAvrcpInterface::Get()->AddTargetObserver(this);
+}
+
+AvrcpTarget::~AvrcpTarget() {
+ hal::BluetoothAvrcpInterface::Get()->RemoveTargetObserver(this);
+}
+
+const Uuid& AvrcpTarget::GetAppIdentifier() const { return app_identifier_; }
+
+int AvrcpTarget::GetInstanceId() const { return kSingletonInstanceId; }
+
+void AvrcpTarget::SetDelegate(Delegate* delegate) {
+ LockGuard lock(delegate_mutex_);
+ delegate_ = delegate;
+}
+
+bool AvrcpTarget::Enable() {
+ LockGuard lock(mutex_);
+ return hal::BluetoothAvrcpInterface::Get()->AvrcpTargetEnable();
+}
+
+void AvrcpTarget::Disable() {
+ LockGuard lock(mutex_);
+ hal::BluetoothAvrcpInterface::Get()->AvrcpTargetDisable();
+}
+
+bool AvrcpTarget::GetPlayStatusResponse(const std::string& str_addr,
+ int32_t play_status, uint32_t song_len,
+ uint32_t song_pos) {
+ RawAddress addr = PARSE_ADDR(str_addr);
+ LockGuard lock(mutex_);
+ TRY_RET_FUNC(hal::BluetoothAvrcpInterface::Get()
+ ->GetTargetHALInterface()
+ ->get_play_status_rsp(
+ addr, static_cast<btrc_play_status_t>(play_status),
+ song_len, song_pos) == BT_STATUS_SUCCESS);
+}
+
+bool AvrcpTarget::ListPlayerAppAttrResponse(const std::string& str_addr,
+ const std::vector<int32_t>& attrs) {
+ RawAddress addr = PARSE_ADDR(str_addr);
+
+ std::vector<btrc_player_attr_t> btrc_attrs;
+ btrc_attrs.reserve(attrs.size());
+ for (auto attr : attrs) {
+ btrc_attrs.push_back(static_cast<btrc_player_attr_t>(attr));
+ }
+
+ LockGuard lock(mutex_);
+ TRY_RET_FUNC(hal::BluetoothAvrcpInterface::Get()
+ ->GetTargetHALInterface()
+ ->list_player_app_attr_rsp(addr, btrc_attrs.size(),
+ btrc_attrs.data()) ==
+ BT_STATUS_SUCCESS);
+}
+
+bool AvrcpTarget::GetPlayerAppValueResponse(
+ const std::string& str_addr, const std::vector<AvrcpIntValue>& values) {
+ RawAddress addr = PARSE_ADDR(str_addr);
+ btrc_player_settings_t btrc_values;
+ if (values.size() >= arraysize(btrc_values.attr_ids)) {
+ LOG(ERROR) << "Too many attribute values";
+ return false;
+ }
+
+ btrc_values.num_attr = values.size();
+ for (size_t i = 0; i < values.size(); ++i) {
+ btrc_values.attr_ids[i] = values[i].id();
+ btrc_values.attr_values[i] = values[i].value();
+ }
+
+ LockGuard lock(mutex_);
+ TRY_RET_FUNC(hal::BluetoothAvrcpInterface::Get()
+ ->GetTargetHALInterface()
+ ->get_player_app_value_rsp(addr, &btrc_values) ==
+ BT_STATUS_SUCCESS);
+}
+
+bool AvrcpTarget::GetPlayerAppAttrTextResponse(
+ const std::string& str_addr, const std::vector<AvrcpStringValue>& attrs) {
+ RawAddress addr = PARSE_ADDR(str_addr);
+ auto btrc_attrs = StringValueToPlayerSettingsText(attrs);
+ LockGuard lock(mutex_);
+ TRY_RET_FUNC(hal::BluetoothAvrcpInterface::Get()
+ ->GetTargetHALInterface()
+ ->get_player_app_attr_text_rsp(addr, btrc_attrs.size(),
+ btrc_attrs.data()) ==
+ BT_STATUS_SUCCESS);
+}
+
+bool AvrcpTarget::GetPlayerAppValueTextResponse(
+ const std::string& str_addr, const std::vector<AvrcpStringValue>& values) {
+ RawAddress addr = PARSE_ADDR(str_addr);
+ auto btrc_values = StringValueToPlayerSettingsText(values);
+ LockGuard lock(mutex_);
+ TRY_RET_FUNC(hal::BluetoothAvrcpInterface::Get()
+ ->GetTargetHALInterface()
+ ->get_player_app_value_text_rsp(addr, btrc_values.size(),
+ btrc_values.data()) ==
+ BT_STATUS_SUCCESS);
+}
+
+bool AvrcpTarget::GetElementAttrResponse(
+ const std::string& str_addr, const std::vector<AvrcpStringValue>& attrs) {
+ RawAddress addr = PARSE_ADDR(str_addr);
+ auto btrc_attrs = StringValueToElementAttrVal(attrs);
+ LockGuard lock(mutex_);
+ TRY_RET_FUNC(
+ hal::BluetoothAvrcpInterface::Get()
+ ->GetTargetHALInterface()
+ ->get_element_attr_rsp(addr, btrc_attrs.size(), btrc_attrs.data()) ==
+ BT_STATUS_SUCCESS);
+}
+
+bool AvrcpTarget::SetPlayerAppValueResponse(const std::string& str_addr,
+ int32_t rsp_status) {
+ RawAddress addr = PARSE_ADDR(str_addr);
+ LockGuard lock(mutex_);
+ TRY_RET_FUNC(hal::BluetoothAvrcpInterface::Get()
+ ->GetTargetHALInterface()
+ ->set_player_app_value_rsp(
+ addr, static_cast<btrc_status_t>(rsp_status)) ==
+ BT_STATUS_SUCCESS);
+}
+
+bool AvrcpTarget::RegisterNotificationResponse(
+ int32_t event_id, int32_t type,
+ const AvrcpRegisterNotificationResponse& param) {
+ auto param_copy = param.data();
+ LockGuard lock(mutex_);
+ TRY_RET_FUNC(hal::BluetoothAvrcpInterface::Get()
+ ->GetTargetHALInterface()
+ ->register_notification_rsp(
+ static_cast<btrc_event_id_t>(event_id),
+ static_cast<btrc_notification_type_t>(type),
+ ¶m_copy) == BT_STATUS_SUCCESS);
+}
+
+bool AvrcpTarget::SetVolume(int volume) {
+ LockGuard lock(mutex_);
+ TRY_RET_FUNC(
+ hal::BluetoothAvrcpInterface::Get()->GetTargetHALInterface()->set_volume(
+ volume) == BT_STATUS_SUCCESS);
+}
+
+void AvrcpTarget::RemoteFeaturesCallback(const RawAddress& bd_addr,
+ btrc_remote_features_t features) {
+ auto str_addr = BtAddrString(&bd_addr);
+ LockGuard lock(delegate_mutex_);
+ if (delegate_)
+ delegate_->OnGetRemoteFeatures(str_addr, static_cast<int32_t>(features));
+}
+
+void AvrcpTarget::GetPlayStatusCallback(const RawAddress& bd_addr) {
+ auto str_addr = BtAddrString(&bd_addr);
+ LockGuard lock(delegate_mutex_);
+ if (delegate_) delegate_->OnGetPlayStatus(str_addr);
+}
+
+void AvrcpTarget::ListPlayerAppAttrCallback(const RawAddress& bd_addr) {
+ auto str_addr = BtAddrString(&bd_addr);
+ LockGuard lock(delegate_mutex_);
+ if (delegate_) delegate_->OnListPlayerAppAttr(str_addr);
+}
+
+void AvrcpTarget::ListPlayerAppValuesCallback(btrc_player_attr_t attr_id,
+ const RawAddress& bd_addr) {
+ auto str_addr = BtAddrString(&bd_addr);
+ LockGuard lock(delegate_mutex_);
+ if (delegate_)
+ delegate_->OnListPlayerAppValues(str_addr, static_cast<int32_t>(attr_id));
+}
+
+void AvrcpTarget::GetPlayerAppValueCallback(uint8_t num_attr,
+ btrc_player_attr_t* p_attrs,
+ const RawAddress& bd_addr) {
+ auto str_addr = BtAddrString(&bd_addr);
+ std::vector<int32_t> attr_vec;
+ attr_vec.reserve(num_attr);
+ for (auto* it = p_attrs; it != p_attrs + num_attr; ++it) {
+ attr_vec.push_back(*it);
+ }
+
+ LockGuard lock(delegate_mutex_);
+ if (delegate_) delegate_->OnGetPlayerAppValue(str_addr, attr_vec);
+}
+
+void AvrcpTarget::GetPlayerAppAttrsTextCallback(uint8_t num_attr,
+ btrc_player_attr_t* p_attrs,
+ const RawAddress& bd_addr) {
+ auto str_addr = BtAddrString(&bd_addr);
+ std::vector<int32_t> attr_vec;
+ attr_vec.reserve(num_attr);
+ for (auto* it = p_attrs; it != p_attrs + num_attr; ++it) {
+ attr_vec.push_back(*it);
+ }
+
+ LockGuard lock(delegate_mutex_);
+ if (delegate_) delegate_->OnGetPlayerAppAttrsText(str_addr, attr_vec);
+}
+
+void AvrcpTarget::GetPlayerAppValuesTextCallback(uint8_t attr_id,
+ uint8_t num_val,
+ uint8_t* p_vals,
+ const RawAddress& bd_addr) {
+ auto str_addr = BtAddrString(&bd_addr);
+ std::vector<int32_t> val_vec;
+ val_vec.reserve(num_val);
+ for (auto* it = p_vals; it != p_vals + num_val; ++it) {
+ val_vec.push_back(*it);
+ }
+ LockGuard lock(delegate_mutex_);
+ if (delegate_)
+ delegate_->OnGetPlayerAppValuesText(str_addr, attr_id, val_vec);
+}
+
+void AvrcpTarget::SetPlayerAppValueCallback(btrc_player_settings_t* p_vals,
+ const RawAddress& bd_addr) {
+ auto str_addr = BtAddrString(&bd_addr);
+ std::vector<AvrcpIntValue> values;
+ values.reserve(p_vals->num_attr);
+ for (size_t i = 0; i < p_vals->num_attr; ++i) {
+ values.emplace_back(p_vals->attr_ids[i], p_vals->attr_values[i]);
+ }
+
+ LockGuard lock(delegate_mutex_);
+ if (delegate_) delegate_->OnSetPlayerAppValue(str_addr, values);
+}
+
+void AvrcpTarget::GetElementAttrCallback(uint8_t num_attr,
+ btrc_media_attr_t* p_attrs,
+ const RawAddress& bd_addr) {
+ auto str_addr = BtAddrString(&bd_addr);
+ std::vector<int32_t> attr_vec;
+ attr_vec.reserve(num_attr);
+ for (auto* it = p_attrs; it != p_attrs + num_attr; ++it) {
+ attr_vec.push_back(*it);
+ }
+ LockGuard lock(delegate_mutex_);
+ if (delegate_) delegate_->OnGetElementAttrs(str_addr, attr_vec);
+}
+
+void AvrcpTarget::RegisterNotificationCallback(btrc_event_id_t event_id,
+ uint32_t param,
+ const RawAddress& bd_addr) {
+ auto str_addr = BtAddrString(&bd_addr);
+ LockGuard lock(delegate_mutex_);
+ if (delegate_)
+ delegate_->OnRegisterNotification(str_addr, static_cast<int32_t>(event_id),
+ param);
+}
+
+void AvrcpTarget::VolumeChangeCallback(uint8_t volume, uint8_t ctype,
+ const RawAddress& bd_addr) {
+ auto str_addr = BtAddrString(&bd_addr);
+ LockGuard lock(delegate_mutex_);
+ if (delegate_) delegate_->OnVolumeChange(str_addr, volume, ctype);
+}
+
+void AvrcpTarget::PassthroughCmdCallback(int id, int key_state,
+ const RawAddress& bd_addr) {
+ auto str_addr = BtAddrString(&bd_addr);
+ LockGuard lock(delegate_mutex_);
+ if (delegate_) delegate_->OnPassThroughCommand(str_addr, id, key_state);
+}
+
+// AvrcpTargetFactory implementation
+// ========================================================
+
+AvrcpTargetFactory::AvrcpTargetFactory() = default;
+AvrcpTargetFactory::~AvrcpTargetFactory() = default;
+
+bool AvrcpTargetFactory::RegisterInstance(const Uuid& uuid,
+ const RegisterCallback& callback) {
+ VLOG(1) << __func__ << " - UUID: " << uuid.ToString();
+
+ auto avrcp_target = base::WrapUnique(new AvrcpTarget(uuid));
+ callback(BLE_STATUS_SUCCESS, uuid, std::move(avrcp_target));
+ return true;
+}
+
+} // namespace bluetooth
diff --git a/service/avrcp_target.h b/service/avrcp_target.h
new file mode 100644
index 0000000..8c2bcce
--- /dev/null
+++ b/service/avrcp_target.h
@@ -0,0 +1,179 @@
+//
+// Copyright (C) 2017 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 <mutex>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+
+#include "service/common/bluetooth/avrcp_int_value.h"
+#include "service/common/bluetooth/avrcp_register_notification_response.h"
+#include "service/common/bluetooth/avrcp_string_value.h"
+
+#include "service/bluetooth_instance.h"
+#include "service/hal/bluetooth_avrcp_interface.h"
+
+namespace bluetooth {
+
+// Note: presently this only supports
+// (BTRC_FEAT_METADATA | BTRC_FEAT_ABSOLUTE_VOLUME)
+class AvrcpTarget : public BluetoothInstance,
+ private hal::BluetoothAvrcpInterface::TargetObserver {
+ public:
+ // We only allow one instance of this object at a time.
+ static const int kSingletonInstanceId;
+
+ class Delegate {
+ public:
+ virtual void OnGetRemoteFeatures(const std::string& addr,
+ int32_t features) = 0;
+ virtual void OnGetPlayStatus(const std::string& addr) = 0;
+ virtual void OnListPlayerAppAttr(const std::string& addr) = 0;
+ virtual void OnListPlayerAppValues(const std::string& addr,
+ int32_t attr_id) = 0;
+ virtual void OnGetPlayerAppValue(const std::string& addr,
+ const std::vector<int32_t>& attrs) = 0;
+ virtual void OnGetPlayerAppAttrsText(const std::string& addr,
+ const std::vector<int32_t>& attrs) = 0;
+ virtual void OnGetPlayerAppValuesText(
+ const std::string& addr, int32_t attr_id,
+ const std::vector<int32_t>& values) = 0;
+ virtual void OnSetPlayerAppValue(
+ const std::string& addr, const std::vector<AvrcpIntValue>& values) = 0;
+ virtual void OnGetElementAttrs(const std::string& addr,
+ const std::vector<int32_t>& attrs) = 0;
+ virtual void OnRegisterNotification(const std::string& addr,
+ int32_t event_id, uint32_t param) = 0;
+ virtual void OnVolumeChange(const std::string& addr, int32_t volume,
+ int32_t ctype) = 0;
+ virtual void OnPassThroughCommand(const std::string& addr, int32_t id,
+ int32_t key_state) = 0;
+
+ protected:
+ virtual ~Delegate() = default;
+ };
+
+ // The destructor automatically unregisters this instance from the stack.
+ ~AvrcpTarget() override;
+
+ // Assigns a delegate to this instance. |delegate| must out-live this
+ // AvrcpTarget instance.
+ void SetDelegate(Delegate* delegate);
+
+ // BluetoothClientInstace overrides:
+ const Uuid& GetAppIdentifier() const override;
+ int GetInstanceId() const override;
+
+ bool Enable();
+ void Disable();
+
+ bool GetPlayStatusResponse(const std::string& addr, int32_t play_status,
+ uint32_t song_len, uint32_t song_pos);
+
+ bool ListPlayerAppAttrResponse(const std::string& addr,
+ const std::vector<int32_t>& attrs);
+
+ bool GetPlayerAppValueResponse(const std::string& addr,
+ const std::vector<AvrcpIntValue>& values);
+
+ bool GetPlayerAppAttrTextResponse(const std::string& addr,
+ const std::vector<AvrcpStringValue>& attrs);
+
+ bool GetPlayerAppValueTextResponse(
+ const std::string& addr, const std::vector<AvrcpStringValue>& attrs);
+
+ bool GetElementAttrResponse(const std::string& addr,
+ const std::vector<AvrcpStringValue>& attrs);
+
+ bool SetPlayerAppValueResponse(const std::string& addr, int32_t rsp_status);
+
+ bool RegisterNotificationResponse(
+ int32_t event_id, int32_t type,
+ const AvrcpRegisterNotificationResponse& param);
+
+ bool SetVolume(int volume);
+
+ private:
+ friend class AvrcpTargetFactory;
+
+ // Constructor shouldn't be called directly as instances are meant to be
+ // obtained from the factory.
+ AvrcpTarget(const Uuid& uuid);
+
+ // hal::BluetoothAvrcpInterface::TargetObserver implementation:
+ void RemoteFeaturesCallback(const RawAddress& bd_addr,
+ btrc_remote_features_t features) override;
+ void GetPlayStatusCallback(const RawAddress& bd_addr) override;
+ void ListPlayerAppAttrCallback(const RawAddress& bd_addr) override;
+ void ListPlayerAppValuesCallback(btrc_player_attr_t attr_id,
+ const RawAddress& bd_addr) override;
+ void GetPlayerAppValueCallback(uint8_t num_attr, btrc_player_attr_t* p_attrs,
+ const RawAddress& bd_addr) override;
+ void GetPlayerAppAttrsTextCallback(uint8_t num_attr,
+ btrc_player_attr_t* p_attrs,
+ const RawAddress& bd_addr) override;
+ void GetPlayerAppValuesTextCallback(uint8_t attr_id, uint8_t num_val,
+ uint8_t* p_vals,
+ const RawAddress& bd_addr) override;
+ void SetPlayerAppValueCallback(btrc_player_settings_t* p_vals,
+ const RawAddress& bd_addr) override;
+ void GetElementAttrCallback(uint8_t num_attr, btrc_media_attr_t* p_attrs,
+ const RawAddress& bd_addr) override;
+ void RegisterNotificationCallback(btrc_event_id_t event_id, uint32_t param,
+ const RawAddress& bd_addr) override;
+ void VolumeChangeCallback(uint8_t volume, uint8_t ctype,
+ const RawAddress& bd_addr) override;
+ void PassthroughCmdCallback(int id, int key_state,
+ const RawAddress& bd_addr) override;
+
+ // See getters for documentation.
+ const Uuid app_identifier_;
+
+ // Mutex that synchronizes access to the entries below.
+ std::mutex mutex_;
+
+ // Raw handle to the Delegate, which must outlive this AvrcpTarget instance.
+ std::mutex delegate_mutex_;
+ Delegate* delegate_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(AvrcpTarget);
+};
+
+// AvrcpTargetFactory is used to register and obtain a per-application
+// AvrcpTarget
+// instance. Users should call RegisterClient to obtain their own unique
+// AvrcpTarget instance that has been registered with the Bluetooth stack.
+class AvrcpTargetFactory
+ : public BluetoothInstanceFactory,
+ private hal::BluetoothAvrcpInterface::TargetObserver {
+ public:
+ // Don't construct/destruct directly except in tests. Instead, obtain a handle
+ // from an Adapter instance.
+ AvrcpTargetFactory();
+ ~AvrcpTargetFactory() override;
+
+ // BluetoothInstanceFactory override:
+ bool RegisterInstance(const Uuid& uuid,
+ const RegisterCallback& callback) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AvrcpTargetFactory);
+};
+
+} // namespace bluetooth
diff --git a/service/client/main.cc b/service/client/main.cc
index e3b4c92..43228a4 100644
--- a/service/client/main.cc
+++ b/service/client/main.cc
@@ -161,6 +161,60 @@
return Status::ok();
}
+ Status OnSspRequest(const String16& device_address,
+ const String16& device_name, int32_t cod,
+ int32_t pairing_variant, int32_t pass_key) override {
+ // no-op
+ return Status::ok();
+ }
+
+ Status OnGetBondedDevices(
+ int32_t status,
+ const ::std::vector<String16>& device_addresses) override {
+ BeginAsyncOut();
+ std::cout << "Bonded devices:\n";
+ for (const auto& device_address : device_addresses) {
+ std::cout << " " << device_address << "\n";
+ }
+ EndAsyncOut();
+ return Status::ok();
+ }
+
+ Status OnBondStateChanged(int32_t status, const String16& device_address,
+ int32_t state) override {
+ BeginAsyncOut();
+ std::cout << COLOR_BOLDWHITE "Device address: " << COLOR_BOLDYELLOW "["
+ << device_address << " bond state: " << state << " ] "
+ << COLOR_BOLDWHITE "- status: "
+ << (status == 0 ? "SUCCESS" : "FAIL") << COLOR_OFF;
+ EndAsyncOut();
+ return Status::ok();
+ }
+
+ Status OnGetRemoteDeviceProperties(
+ int32_t status, const String16& device_address,
+ const android::bluetooth::BluetoothRemoteDeviceProps& props) override {
+ // no-op
+ return Status::ok();
+ }
+
+ Status OnDeviceFound(
+ const android::bluetooth::BluetoothRemoteDeviceProps& props) override {
+ // no-op
+ return Status::ok();
+ }
+
+ Status OnDeviceConnectionStateChanged(const String16& device_address,
+ bool connected) override {
+ // no-op
+ return Status::ok();
+ }
+
+ Status OnScanEnableChanged(bool scan_enabled) override {
+ // no-op
+ return Status::ok();
+ }
+
private:
DISALLOW_COPY_AND_ASSIGN(CLIBluetoothCallback);
};
@@ -337,7 +391,7 @@
void HandleEnable(IBluetooth* bt_iface, const vector<string>& args) {
bool is_restricted_mode = false;
- for (auto iter : args) {
+ for (const auto& iter : args) {
const std::string& arg = iter;
if (arg == "-h") {
static const char kUsage[] =
diff --git a/service/common/Android.bp b/service/common/Android.bp
index b3fbfc4..e3bde74 100644
--- a/service/common/Android.bp
+++ b/service/common/Android.bp
@@ -7,13 +7,18 @@
"-fvisibility=default",
],
host_supported: true,
- header_libs: [ "libbluetooth_headers" ],
+ header_libs: ["libbluetooth_headers"],
srcs: [
+ "bluetooth/a2dp_codec_config.cc",
"bluetooth/adapter_state.cc",
"bluetooth/advertise_data.cc",
"bluetooth/advertise_settings.cc",
+ "bluetooth/avrcp_int_value.cc",
+ "bluetooth/avrcp_media_attr.cc",
+ "bluetooth/avrcp_register_notification_response.cc",
"bluetooth/characteristic.cc",
"bluetooth/descriptor.cc",
+ "bluetooth/remote_device_props.cc",
"bluetooth/scan_filter.cc",
"bluetooth/scan_result.cc",
"bluetooth/scan_settings.cc",
@@ -35,9 +40,17 @@
/* we export all classes, so change default visibility, instead of having EXPORT_SYMBOL on each class*/
"-fvisibility=default",
],
- header_libs: [ "libbluetooth_headers" ],
+ header_libs: ["libbluetooth_headers"],
srcs: [
"android/bluetooth/IBluetooth.aidl",
+ "android/bluetooth/IBluetoothA2dpSink.aidl",
+ "android/bluetooth/IBluetoothA2dpSinkCallback.aidl",
+ "android/bluetooth/IBluetoothA2dpSource.aidl",
+ "android/bluetooth/IBluetoothA2dpSourceCallback.aidl",
+ "android/bluetooth/IBluetoothAvrcpControl.aidl",
+ "android/bluetooth/IBluetoothAvrcpControlCallback.aidl",
+ "android/bluetooth/IBluetoothAvrcpTarget.aidl",
+ "android/bluetooth/IBluetoothAvrcpTargetCallback.aidl",
"android/bluetooth/IBluetoothCallback.aidl",
"android/bluetooth/IBluetoothGattClient.aidl",
"android/bluetooth/IBluetoothGattClientCallback.aidl",
@@ -51,10 +64,16 @@
"android/bluetooth/IBluetoothLowEnergyCallback.aidl",
"android/bluetooth/advertise_data.cc",
"android/bluetooth/advertise_settings.cc",
+ "android/bluetooth/bluetooth_a2dp_codec_config.cc",
+ "android/bluetooth/bluetooth_avrcp_int_value.cc",
+ "android/bluetooth/bluetooth_avrcp_media_attr.cc",
+ "android/bluetooth/bluetooth_avrcp_register_notification_response.cc",
+ "android/bluetooth/bluetooth_avrcp_string_value.cc",
"android/bluetooth/bluetooth_gatt_characteristic.cc",
"android/bluetooth/bluetooth_gatt_descriptor.cc",
"android/bluetooth/bluetooth_gatt_included_service.cc",
"android/bluetooth/bluetooth_gatt_service.cc",
+ "android/bluetooth/bluetooth_remote_device_props.cc",
"android/bluetooth/scan_filter.cc",
"android/bluetooth/scan_result.cc",
"android/bluetooth/scan_settings.cc",
@@ -75,5 +94,5 @@
],
static_libs: [
"libbluetooth-types",
- ]
+ ],
}
diff --git a/service/common/android/bluetooth/BluetoothA2dpCodecConfig.aidl b/service/common/android/bluetooth/BluetoothA2dpCodecConfig.aidl
new file mode 100644
index 0000000..083cd75
--- /dev/null
+++ b/service/common/android/bluetooth/BluetoothA2dpCodecConfig.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothA2dpCodecConfig cpp_header "android/bluetooth/bluetooth_a2dp_codec_config.h";
diff --git a/service/common/android/bluetooth/BluetoothAvrcpIntValue.aidl b/service/common/android/bluetooth/BluetoothAvrcpIntValue.aidl
new file mode 100644
index 0000000..e126393
--- /dev/null
+++ b/service/common/android/bluetooth/BluetoothAvrcpIntValue.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothAvrcpIntValue cpp_header "android/bluetooth/bluetooth_avrcp_int_value.h";
diff --git a/service/common/android/bluetooth/BluetoothAvrcpMediaAttr.aidl b/service/common/android/bluetooth/BluetoothAvrcpMediaAttr.aidl
new file mode 100644
index 0000000..03355ac
--- /dev/null
+++ b/service/common/android/bluetooth/BluetoothAvrcpMediaAttr.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothAvrcpMediaAttr cpp_header "android/bluetooth/bluetooth_avrcp_media_attr.h";
diff --git a/service/common/android/bluetooth/BluetoothAvrcpRegisterNotificationResponse.aidl b/service/common/android/bluetooth/BluetoothAvrcpRegisterNotificationResponse.aidl
new file mode 100644
index 0000000..147a187
--- /dev/null
+++ b/service/common/android/bluetooth/BluetoothAvrcpRegisterNotificationResponse.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothAvrcpRegisterNotificationResponse cpp_header "android/bluetooth/bluetooth_avrcp_register_notification_response.h";
diff --git a/service/common/android/bluetooth/BluetoothAvrcpStringValue.aidl b/service/common/android/bluetooth/BluetoothAvrcpStringValue.aidl
new file mode 100644
index 0000000..5bbfbd4
--- /dev/null
+++ b/service/common/android/bluetooth/BluetoothAvrcpStringValue.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothAvrcpStringValue cpp_header "android/bluetooth/bluetooth_avrcp_string_value.h";
diff --git a/service/common/android/bluetooth/BluetoothRemoteDeviceProps.aidl b/service/common/android/bluetooth/BluetoothRemoteDeviceProps.aidl
new file mode 100644
index 0000000..db80295
--- /dev/null
+++ b/service/common/android/bluetooth/BluetoothRemoteDeviceProps.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothRemoteDeviceProps cpp_header "android/bluetooth/bluetooth_remote_device_props.h";
diff --git a/service/common/android/bluetooth/IBluetooth.aidl b/service/common/android/bluetooth/IBluetooth.aidl
index cc1e015..3986ad7 100644
--- a/service/common/android/bluetooth/IBluetooth.aidl
+++ b/service/common/android/bluetooth/IBluetooth.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 The Android Open Source Project
+ * Copyright (C) 2016 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.
@@ -22,6 +22,10 @@
import android.bluetooth.IBluetoothLeScanner;
import android.bluetooth.IBluetoothGattClient;
import android.bluetooth.IBluetoothGattServer;
+import android.bluetooth.IBluetoothA2dpSink;
+import android.bluetooth.IBluetoothA2dpSource;
+import android.bluetooth.IBluetoothAvrcpControl;
+import android.bluetooth.IBluetoothAvrcpTarget;
import android.bluetooth.UUID;
@@ -36,6 +40,17 @@
UUID[] GetUUIDs();
boolean SetName(String name);
String GetName();
+ boolean SetScanMode(int scan_mode);
+ boolean SetScanEnable(boolean scan_enable);
+ boolean SspReply(
+ String device_address,
+ int variant,
+ boolean accept,
+ int passkey);
+ boolean CreateBond(String device_address, int transport);
+ boolean GetBondedDevices();
+ boolean RemoveBond(String device_address);
+ boolean GetRemoteDeviceProperties(String device_address);
void RegisterCallback(IBluetoothCallback callback);
void UnregisterCallback(IBluetoothCallback callback);
@@ -47,4 +62,8 @@
IBluetoothLeScanner GetLeScannerInterface();
IBluetoothGattClient GetGattClientInterface();
IBluetoothGattServer GetGattServerInterface();
+ IBluetoothA2dpSink GetA2dpSinkInterface();
+ IBluetoothA2dpSource GetA2dpSourceInterface();
+ IBluetoothAvrcpControl GetAvrcpControlInterface();
+ IBluetoothAvrcpTarget GetAvrcpTargetInterface();
}
diff --git a/service/common/android/bluetooth/IBluetoothA2dpSink.aidl b/service/common/android/bluetooth/IBluetoothA2dpSink.aidl
new file mode 100644
index 0000000..dec7d28
--- /dev/null
+++ b/service/common/android/bluetooth/IBluetoothA2dpSink.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.IBluetoothA2dpSinkCallback;
+
+interface IBluetoothA2dpSink {
+ boolean Register(in IBluetoothA2dpSinkCallback callback);
+ void Unregister();
+
+ boolean Enable();
+ boolean Disable();
+ boolean Connect(String device_address);
+ boolean Disconnect(String device_address);
+ boolean SetAudioFocusState(int state);
+ boolean SetAudioTrackGain(float gain);
+}
diff --git a/service/common/android/bluetooth/IBluetoothA2dpSinkCallback.aidl b/service/common/android/bluetooth/IBluetoothA2dpSinkCallback.aidl
new file mode 100644
index 0000000..e12be24
--- /dev/null
+++ b/service/common/android/bluetooth/IBluetoothA2dpSinkCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.bluetooth;
+
+oneway interface IBluetoothA2dpSinkCallback {
+ void OnRegistered(int status);
+ void OnConnectionState(String device_address, int state);
+ void OnAudioState(String device_address, int state);
+ void OnAudioConfig(String device_address, int sample_rate, int channel_count);
+}
diff --git a/service/common/android/bluetooth/IBluetoothA2dpSource.aidl b/service/common/android/bluetooth/IBluetoothA2dpSource.aidl
new file mode 100644
index 0000000..344292c
--- /dev/null
+++ b/service/common/android/bluetooth/IBluetoothA2dpSource.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.IBluetoothA2dpSourceCallback;
+import android.bluetooth.BluetoothA2dpCodecConfig;
+
+interface IBluetoothA2dpSource {
+ boolean Register(in IBluetoothA2dpSourceCallback callback);
+ void Unregister();
+
+ boolean Enable(in BluetoothA2dpCodecConfig[] codec_priorities);
+ boolean Disable();
+ boolean Connect(String device_address);
+ boolean Disconnect(String device_address);
+ boolean ConfigCodec(String device_address,
+ in BluetoothA2dpCodecConfig[] codec_preferences);
+
+}
diff --git a/service/common/android/bluetooth/IBluetoothA2dpSourceCallback.aidl b/service/common/android/bluetooth/IBluetoothA2dpSourceCallback.aidl
new file mode 100644
index 0000000..4d4a82d
--- /dev/null
+++ b/service/common/android/bluetooth/IBluetoothA2dpSourceCallback.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothA2dpCodecConfig;
+
+oneway interface IBluetoothA2dpSourceCallback {
+ void OnRegistered(int status);
+ void OnConnectionState(String device_address, int state);
+ void OnAudioState(String device_address, int state);
+ void OnAudioConfig(
+ String device_address,
+ in BluetoothA2dpCodecConfig codec_config,
+ in BluetoothA2dpCodecConfig[] codecs_local_capabilities,
+ in BluetoothA2dpCodecConfig[] codecs_selectable_capabilities);
+}
diff --git a/service/common/android/bluetooth/IBluetoothAvrcpControl.aidl b/service/common/android/bluetooth/IBluetoothAvrcpControl.aidl
new file mode 100644
index 0000000..0e65a71
--- /dev/null
+++ b/service/common/android/bluetooth/IBluetoothAvrcpControl.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.IBluetoothAvrcpControlCallback;
+
+interface IBluetoothAvrcpControl {
+ boolean Register(in IBluetoothAvrcpControlCallback callback);
+ void Unregister(int id);
+ void UnregisterAll();
+
+ boolean Enable(int id);
+ boolean Disable(int id);
+
+ boolean SendPassThroughCommand(int id, String device_address,
+ int key_code, boolean key_pressed);
+
+ boolean SetAbsVolumeResponse(int id, String device_address, int abs_vol,
+ int label);
+
+ boolean RegisterForAbsVolumeCallbackResponse(int id, String device_address,
+ int response_type, int abs_vol, int label);
+}
diff --git a/service/common/android/bluetooth/IBluetoothAvrcpControlCallback.aidl b/service/common/android/bluetooth/IBluetoothAvrcpControlCallback.aidl
new file mode 100644
index 0000000..68f0db2
--- /dev/null
+++ b/service/common/android/bluetooth/IBluetoothAvrcpControlCallback.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothAvrcpMediaAttr;
+
+oneway interface IBluetoothAvrcpControlCallback {
+ void OnRegistered(int status, int id);
+ void OnConnectionState(
+ boolean rc_connect,
+ boolean bt_connect,
+ String device_address);
+
+ void OnTrackChanged(String device_address, in BluetoothAvrcpMediaAttr track_info);
+ void OnSetAbsVolumeRequest(String device_address, int abs_vol, int label);
+ void OnRegisterForAbsVolumeCallbackRequest(String device_address, int label);
+}
diff --git a/service/common/android/bluetooth/IBluetoothAvrcpTarget.aidl b/service/common/android/bluetooth/IBluetoothAvrcpTarget.aidl
new file mode 100644
index 0000000..6654f86
--- /dev/null
+++ b/service/common/android/bluetooth/IBluetoothAvrcpTarget.aidl
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.IBluetoothAvrcpTargetCallback;
+
+import android.bluetooth.BluetoothAvrcpIntValue;
+import android.bluetooth.BluetoothAvrcpStringValue;
+import android.bluetooth.BluetoothAvrcpRegisterNotificationResponse;
+
+interface IBluetoothAvrcpTarget {
+ boolean Register(in IBluetoothAvrcpTargetCallback callback);
+ void Unregister(int id);
+ void UnregisterAll();
+
+ boolean Enable();
+ boolean Disable();
+
+ boolean GetPlayStatusResponse(String addr,
+ int play_status, int song_len, int song_pos);
+
+ boolean ListPlayerAppAttrResponse(String addr, in int[] attrs);
+
+ boolean GetPlayerAppValueResponse(String addr,
+ in BluetoothAvrcpIntValue[] values);
+
+ boolean GetPlayerAppAttrTextResponse(String addr,
+ in BluetoothAvrcpStringValue[] attrs);
+
+ boolean GetPlayerAppValueTextResponse(String addr,
+ in BluetoothAvrcpStringValue[] values);
+
+ boolean GetElementAttrResponse(String addr,
+ in BluetoothAvrcpStringValue[] attrs);
+
+ boolean SetPlayerAppValueResponse(String addr, int rsp_status);
+
+ boolean RegisterNotificationResponse(
+ int event_id,
+ int type,
+ in BluetoothAvrcpRegisterNotificationResponse param);
+
+ boolean SetVolume(int volume);
+}
diff --git a/service/common/android/bluetooth/IBluetoothAvrcpTargetCallback.aidl b/service/common/android/bluetooth/IBluetoothAvrcpTargetCallback.aidl
new file mode 100644
index 0000000..15d45f3
--- /dev/null
+++ b/service/common/android/bluetooth/IBluetoothAvrcpTargetCallback.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothAvrcpIntValue;
+
+oneway interface IBluetoothAvrcpTargetCallback {
+ void OnRegistered(int status);
+ void OnGetRemoteFeatures(String addr, int features);
+ void OnGetPlayStatus(String addr);
+ void OnListPlayerAppAttr(String addr);
+ void OnListPlayerAppValues(String addr, int attr_id);
+ void OnGetPlayerAppValue(String addr, in int[] attrs);
+ void OnGetPlayerAppAttrsText(String addr, in int[] attrs);
+ void OnGetPlayerAppValuesText(String addr, int attr_id, in int[] values);
+ void OnSetPlayerAppValue(String addr, in BluetoothAvrcpIntValue[] values);
+ void OnGetElementAttrs(String addr, in int[] attrs);
+ void OnRegisterNotification(String addr, int event_id, int param);
+ void OnVolumeChange(String addr, int volume, int ctype);
+ void OnPassThroughCommand(String addr, int id, int key_state);
+}
diff --git a/service/common/android/bluetooth/IBluetoothCallback.aidl b/service/common/android/bluetooth/IBluetoothCallback.aidl
index 96b7cdc..a83d5d8 100644
--- a/service/common/android/bluetooth/IBluetoothCallback.aidl
+++ b/service/common/android/bluetooth/IBluetoothCallback.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 The Android Open Source Project
+ * Copyright (C) 2016 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.
@@ -16,6 +16,26 @@
package android.bluetooth;
+import android.bluetooth.BluetoothRemoteDeviceProps;
+
oneway interface IBluetoothCallback {
- void OnBluetoothStateChange(int prev_state, int new_state);
+ void OnBluetoothStateChange(int prev_state, int new_state);
+ void OnScanEnableChanged(boolean scan_enabled);
+ void OnDeviceConnectionStateChanged(
+ String device_address,
+ boolean connected);
+ void OnSspRequest(
+ String device_address,
+ String device_name,
+ int cod,
+ int pairing_variant,
+ int pass_key);
+ void OnGetBondedDevices(int status, in String[] device_addresses);
+ void OnBondStateChanged(int status, String device_address, int state);
+ void OnGetRemoteDeviceProperties(
+ int status,
+ String device_address,
+ in BluetoothRemoteDeviceProps props);
+ void OnDeviceFound(
+ in BluetoothRemoteDeviceProps props);
}
diff --git a/service/common/android/bluetooth/bluetooth_a2dp_codec_config.cc b/service/common/android/bluetooth/bluetooth_a2dp_codec_config.cc
new file mode 100644
index 0000000..8e7b709
--- /dev/null
+++ b/service/common/android/bluetooth/bluetooth_a2dp_codec_config.cc
@@ -0,0 +1,103 @@
+//
+// Copyright (C) 2017 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 "android/bluetooth/bluetooth_a2dp_codec_config.h"
+
+#include <utils/String16.h>
+#include <utils/String8.h>
+
+using android::OK;
+using android::String16;
+using android::String8;
+
+namespace android {
+namespace bluetooth {
+
+status_t BluetoothA2dpCodecConfig::writeToParcel(Parcel* parcel) const {
+ status_t status = parcel->writeInt32(codec_type_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(codec_priority_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(sample_rate_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(bits_per_sample_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(channel_mode_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt64(codec_specific_1_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt64(codec_specific_2_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt64(codec_specific_3_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt64(codec_specific_4_);
+ if (status != OK) return status;
+
+ return status;
+}
+
+status_t BluetoothA2dpCodecConfig::readFromParcel(const Parcel* parcel) {
+ int32_t tmp;
+ status_t status = parcel->readInt32(&tmp);
+ if (status != OK) return status;
+ codec_type_ = tmp;
+
+ status = parcel->readInt32(&tmp);
+ if (status != OK) return status;
+ codec_priority_ = tmp;
+
+ status = parcel->readInt32(&tmp);
+ if (status != OK) return status;
+ sample_rate_ = tmp;
+
+ status = parcel->readInt32(&tmp);
+ if (status != OK) return status;
+ bits_per_sample_ = tmp;
+
+ status = parcel->readInt32(&tmp);
+ if (status != OK) return status;
+ channel_mode_ = tmp;
+
+ int64_t tmp64;
+ status = parcel->readInt64(&tmp64);
+ if (status != OK) return status;
+ codec_specific_1_ = tmp64;
+
+ status = parcel->readInt64(&tmp64);
+ if (status != OK) return status;
+ codec_specific_2_ = tmp64;
+
+ status = parcel->readInt64(&tmp64);
+ if (status != OK) return status;
+ codec_specific_3_ = tmp64;
+
+ status = parcel->readInt64(&tmp64);
+ if (status != OK) return status;
+ codec_specific_4_ = tmp64;
+
+ return status;
+}
+
+} // namespace bluetooth
+} // namespace android
diff --git a/service/common/android/bluetooth/bluetooth_a2dp_codec_config.h b/service/common/android/bluetooth/bluetooth_a2dp_codec_config.h
new file mode 100644
index 0000000..0071d67
--- /dev/null
+++ b/service/common/android/bluetooth/bluetooth_a2dp_codec_config.h
@@ -0,0 +1,57 @@
+//
+// Copyright (C) 2017 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 <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+#include "bluetooth/a2dp_codec_config.h"
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+
+namespace android {
+namespace bluetooth {
+
+class BluetoothA2dpCodecConfig : public Parcelable,
+ public ::bluetooth::A2dpCodecConfig {
+ public:
+ BluetoothA2dpCodecConfig() = default;
+ BluetoothA2dpCodecConfig(const ::bluetooth::A2dpCodecConfig& other)
+ : ::bluetooth::A2dpCodecConfig(other) {} // NOLINT(implicit)
+ BluetoothA2dpCodecConfig(const BluetoothA2dpCodecConfig& other)
+ : ::bluetooth::A2dpCodecConfig(other) {} // NOLINT(implicit)
+ ~BluetoothA2dpCodecConfig() = default;
+
+ // Write |this| parcelable to the given |parcel|. Keep in mind that
+ // implementations of writeToParcel must be manually kept in sync
+ // with readFromParcel and the Java equivalent versions of these methods.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t writeToParcel(Parcel* parcel) const override;
+
+ // Read data from the given |parcel| into |this|. After readFromParcel
+ // completes, |this| should have equivalent state to the object that
+ // wrote itself to the parcel.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t readFromParcel(const Parcel* parcel) override;
+};
+
+} // namespace bluetooth
+} // namespace android
diff --git a/service/common/android/bluetooth/bluetooth_avrcp_int_value.cc b/service/common/android/bluetooth/bluetooth_avrcp_int_value.cc
new file mode 100644
index 0000000..c2a895c
--- /dev/null
+++ b/service/common/android/bluetooth/bluetooth_avrcp_int_value.cc
@@ -0,0 +1,53 @@
+//
+// Copyright (C) 2017 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 "android/bluetooth/bluetooth_avrcp_int_value.h"
+
+#include <utils/String16.h>
+#include <utils/String8.h>
+
+using android::OK;
+using android::String16;
+using android::String8;
+
+namespace android {
+namespace bluetooth {
+
+status_t BluetoothAvrcpIntValue::writeToParcel(Parcel* parcel) const {
+ status_t status = parcel->writeInt32(id_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(value_);
+ if (status != OK) return status;
+
+ return status;
+}
+
+status_t BluetoothAvrcpIntValue::readFromParcel(const Parcel* parcel) {
+ int32_t tmp;
+ status_t status = parcel->readInt32(&tmp);
+ if (status != OK) return status;
+ id_ = tmp;
+
+ status = parcel->readInt32(&tmp);
+ if (status != OK) return status;
+ value_ = tmp;
+
+ return status;
+}
+
+} // namespace bluetooth
+} // namespace android
diff --git a/service/common/android/bluetooth/bluetooth_avrcp_int_value.h b/service/common/android/bluetooth/bluetooth_avrcp_int_value.h
new file mode 100644
index 0000000..80eed7c
--- /dev/null
+++ b/service/common/android/bluetooth/bluetooth_avrcp_int_value.h
@@ -0,0 +1,57 @@
+//
+// Copyright (C) 2017 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 <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+#include "bluetooth/avrcp_int_value.h"
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+
+namespace android {
+namespace bluetooth {
+
+class BluetoothAvrcpIntValue : public Parcelable,
+ public ::bluetooth::AvrcpIntValue {
+ public:
+ BluetoothAvrcpIntValue() = default;
+ BluetoothAvrcpIntValue(const ::bluetooth::AvrcpIntValue& other)
+ : ::bluetooth::AvrcpIntValue(other) {} // NOLINT(implicit)
+ BluetoothAvrcpIntValue(const BluetoothAvrcpIntValue& other)
+ : ::bluetooth::AvrcpIntValue(other) {} // NOLINT(implicit)
+ ~BluetoothAvrcpIntValue() = default;
+
+ // Write |this| parcelable to the given |parcel|. Keep in mind that
+ // implementations of writeToParcel must be manually kept in sync
+ // with readFromParcel and the Java equivalent versions of these methods.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t writeToParcel(Parcel* parcel) const override;
+
+ // Read data from the given |parcel| into |this|. After readFromParcel
+ // completes, |this| should have equivalent state to the object that
+ // wrote itself to the parcel.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t readFromParcel(const Parcel* parcel) override;
+};
+
+} // namespace bluetooth
+} // namespace android
diff --git a/service/common/android/bluetooth/bluetooth_avrcp_media_attr.cc b/service/common/android/bluetooth/bluetooth_avrcp_media_attr.cc
new file mode 100644
index 0000000..b29204e
--- /dev/null
+++ b/service/common/android/bluetooth/bluetooth_avrcp_media_attr.cc
@@ -0,0 +1,93 @@
+//
+// Copyright 2017 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 "android/bluetooth/bluetooth_avrcp_media_attr.h"
+
+#include <utils/String16.h>
+#include <utils/String8.h>
+
+using android::OK;
+using android::String16;
+using android::String8;
+
+namespace android {
+namespace bluetooth {
+
+status_t BluetoothAvrcpMediaAttr::writeToParcel(Parcel* parcel) const {
+ status_t status =
+ parcel->writeString16(String16(title_.c_str(), title_.size()));
+ if (status != OK) return status;
+
+ status = parcel->writeString16(String16(artist_.c_str(), artist_.size()));
+ if (status != OK) return status;
+
+ status = parcel->writeString16(String16(album_.c_str(), album_.size()));
+ if (status != OK) return status;
+
+ status = parcel->writeString16(String16(genre_.c_str(), genre_.size()));
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(track_num_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(num_tracks_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(play_time_);
+ if (status != OK) return status;
+
+ return status;
+}
+
+status_t BluetoothAvrcpMediaAttr::readFromParcel(const Parcel* parcel) {
+ String16 title;
+ status_t status = parcel->readString16(&title);
+ if (status != OK) return status;
+ title_ = String8(title).string();
+
+ String16 artist;
+ status = parcel->readString16(&artist);
+ if (status != OK) return status;
+ artist_ = String8(artist).string();
+
+ String16 album;
+ status = parcel->readString16(&album);
+ if (status != OK) return status;
+ album_ = String8(album).string();
+
+ String16 genre;
+ status = parcel->readString16(&genre);
+ if (status != OK) return status;
+ genre_ = String8(genre).string();
+
+ int32_t tmp;
+ status = parcel->readInt32(&tmp);
+ if (status != OK) return status;
+ track_num_ = tmp;
+
+ status = parcel->readInt32(&tmp);
+ if (status != OK) return status;
+ num_tracks_ = tmp;
+
+ status = parcel->readInt32(&tmp);
+ if (status != OK) return status;
+ play_time_ = tmp;
+
+ return status;
+}
+
+} // namespace bluetooth
+} // namespace android
diff --git a/service/common/android/bluetooth/bluetooth_avrcp_media_attr.h b/service/common/android/bluetooth/bluetooth_avrcp_media_attr.h
new file mode 100644
index 0000000..d41fef6
--- /dev/null
+++ b/service/common/android/bluetooth/bluetooth_avrcp_media_attr.h
@@ -0,0 +1,57 @@
+//
+// Copyright (C) 2017 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 <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+#include "bluetooth/avrcp_media_attr.h"
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+
+namespace android {
+namespace bluetooth {
+
+class BluetoothAvrcpMediaAttr : public Parcelable,
+ public ::bluetooth::AvrcpMediaAttr {
+ public:
+ BluetoothAvrcpMediaAttr() = default;
+ BluetoothAvrcpMediaAttr(const ::bluetooth::AvrcpMediaAttr& other)
+ : ::bluetooth::AvrcpMediaAttr(other) {} // NOLINT(implicit)
+ BluetoothAvrcpMediaAttr(const BluetoothAvrcpMediaAttr& other)
+ : ::bluetooth::AvrcpMediaAttr(other) {} // NOLINT(implicit)
+ ~BluetoothAvrcpMediaAttr() = default;
+
+ // Write |this| parcelable to the given |parcel|. Keep in mind that
+ // implementations of writeToParcel must be manually kept in sync
+ // with readFromParcel and the Java equivalent versions of these methods.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t writeToParcel(Parcel* parcel) const override;
+
+ // Read data from the given |parcel| into |this|. After readFromParcel
+ // completes, |this| should have equivalent state to the object that
+ // wrote itself to the parcel.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t readFromParcel(const Parcel* parcel) override;
+};
+
+} // namespace bluetooth
+} // namespace android
diff --git a/service/common/android/bluetooth/bluetooth_avrcp_register_notification_response.cc b/service/common/android/bluetooth/bluetooth_avrcp_register_notification_response.cc
new file mode 100644
index 0000000..2ff5a17
--- /dev/null
+++ b/service/common/android/bluetooth/bluetooth_avrcp_register_notification_response.cc
@@ -0,0 +1,46 @@
+//
+// Copyright (C) 2017 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 "android/bluetooth/bluetooth_avrcp_register_notification_response.h"
+
+#include <utils/String16.h>
+#include <utils/String8.h>
+
+using android::OK;
+using android::String16;
+using android::String8;
+
+namespace android {
+namespace bluetooth {
+
+status_t BluetoothAvrcpRegisterNotificationResponse::writeToParcel(
+ Parcel* parcel) const {
+ status_t status = parcel->write(&data_, sizeof(data_));
+ if (status != OK) return status;
+
+ return status;
+}
+
+status_t BluetoothAvrcpRegisterNotificationResponse::readFromParcel(
+ const Parcel* parcel) {
+ status_t status = parcel->read(&data_, sizeof(data_));
+ if (status != OK) return status;
+
+ return status;
+}
+
+} // namespace bluetooth
+} // namespace android
diff --git a/service/common/android/bluetooth/bluetooth_avrcp_register_notification_response.h b/service/common/android/bluetooth/bluetooth_avrcp_register_notification_response.h
new file mode 100644
index 0000000..0a34d1e
--- /dev/null
+++ b/service/common/android/bluetooth/bluetooth_avrcp_register_notification_response.h
@@ -0,0 +1,60 @@
+//
+// Copyright (C) 2017 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 <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+#include "bluetooth/avrcp_register_notification_response.h"
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+
+namespace android {
+namespace bluetooth {
+
+class BluetoothAvrcpRegisterNotificationResponse
+ : public Parcelable,
+ public ::bluetooth::AvrcpRegisterNotificationResponse {
+ public:
+ BluetoothAvrcpRegisterNotificationResponse() = default;
+ BluetoothAvrcpRegisterNotificationResponse(
+ const AvrcpRegisterNotificationResponse& other)
+ : ::bluetooth::AvrcpRegisterNotificationResponse(other) {}
+ BluetoothAvrcpRegisterNotificationResponse(
+ const BluetoothAvrcpRegisterNotificationResponse& other)
+ : ::bluetooth::AvrcpRegisterNotificationResponse(other) {}
+ ~BluetoothAvrcpRegisterNotificationResponse() = default;
+
+ // Write |this| parcelable to the given |parcel|. Keep in mind that
+ // implementations of writeToParcel must be manually kept in sync
+ // with readFromParcel and the Java equivalent versions of these methods.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t writeToParcel(Parcel* parcel) const override;
+
+ // Read data from the given |parcel| into |this|. After readFromParcel
+ // completes, |this| should have equivalent state to the object that
+ // wrote itself to the parcel.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t readFromParcel(const Parcel* parcel) override;
+};
+
+} // namespace bluetooth
+} // namespace android
diff --git a/service/common/android/bluetooth/bluetooth_avrcp_string_value.cc b/service/common/android/bluetooth/bluetooth_avrcp_string_value.cc
new file mode 100644
index 0000000..ded9105
--- /dev/null
+++ b/service/common/android/bluetooth/bluetooth_avrcp_string_value.cc
@@ -0,0 +1,54 @@
+//
+// Copyright (C) 2017 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 "android/bluetooth/bluetooth_avrcp_string_value.h"
+
+#include <utils/String16.h>
+#include <utils/String8.h>
+
+using android::OK;
+using android::String16;
+using android::String8;
+
+namespace android {
+namespace bluetooth {
+
+status_t BluetoothAvrcpStringValue::writeToParcel(Parcel* parcel) const {
+ status_t status = parcel->writeInt32(id_);
+ if (status != OK) return status;
+
+ status = parcel->writeString16(String16(value_.c_str(), value_.size()));
+ if (status != OK) return status;
+
+ return status;
+}
+
+status_t BluetoothAvrcpStringValue::readFromParcel(const Parcel* parcel) {
+ int32_t tmp;
+ status_t status = parcel->readInt32(&tmp);
+ if (status != OK) return status;
+ id_ = tmp;
+
+ String16 value;
+ status = parcel->readString16(&value);
+ if (status != OK) return status;
+ value_ = String8(value).string();
+
+ return status;
+}
+
+} // namespace bluetooth
+} // namespace android
diff --git a/service/common/android/bluetooth/bluetooth_avrcp_string_value.h b/service/common/android/bluetooth/bluetooth_avrcp_string_value.h
new file mode 100644
index 0000000..8f7e952
--- /dev/null
+++ b/service/common/android/bluetooth/bluetooth_avrcp_string_value.h
@@ -0,0 +1,57 @@
+//
+// Copyright (C) 2017 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 <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+#include "bluetooth/avrcp_string_value.h"
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+
+namespace android {
+namespace bluetooth {
+
+class BluetoothAvrcpStringValue : public Parcelable,
+ public ::bluetooth::AvrcpStringValue {
+ public:
+ BluetoothAvrcpStringValue() = default;
+ BluetoothAvrcpStringValue(const ::bluetooth::AvrcpStringValue& other)
+ : ::bluetooth::AvrcpStringValue(other) {} // NOLINT(implicit)
+ BluetoothAvrcpStringValue(const BluetoothAvrcpStringValue& other)
+ : ::bluetooth::AvrcpStringValue(other) {} // NOLINT(implicit)
+ ~BluetoothAvrcpStringValue() = default;
+
+ // Write |this| parcelable to the given |parcel|. Keep in mind that
+ // implementations of writeToParcel must be manually kept in sync
+ // with readFromParcel and the Java equivalent versions of these methods.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t writeToParcel(Parcel* parcel) const override;
+
+ // Read data from the given |parcel| into |this|. After readFromParcel
+ // completes, |this| should have equivalent state to the object that
+ // wrote itself to the parcel.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t readFromParcel(const Parcel* parcel) override;
+};
+
+} // namespace bluetooth
+} // namespace android
diff --git a/service/common/android/bluetooth/bluetooth_remote_device_props.cc b/service/common/android/bluetooth/bluetooth_remote_device_props.cc
new file mode 100644
index 0000000..21974da
--- /dev/null
+++ b/service/common/android/bluetooth/bluetooth_remote_device_props.cc
@@ -0,0 +1,91 @@
+//
+// Copyright 2017 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 "android/bluetooth/bluetooth_remote_device_props.h"
+
+#include <utils/String16.h>
+#include <utils/String8.h>
+
+#include "android/bluetooth/uuid.h"
+
+using android::OK;
+using android::String16;
+using android::String8;
+
+namespace android {
+namespace bluetooth {
+
+status_t BluetoothRemoteDeviceProps::writeToParcel(Parcel* parcel) const {
+ status_t status =
+ parcel->writeString16(String16(name_.c_str(), name_.size()));
+ if (status != OK) return status;
+
+ status = parcel->writeString16(String16(address_.c_str(), address_.size()));
+ if (status != OK) return status;
+
+ std::vector<UUID> uuids;
+ for (const auto& uuid : service_uuids_) {
+ uuids.push_back(uuid);
+ }
+
+ status = parcel->writeParcelableVector(uuids);
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(device_class_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(device_type_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(rssi_);
+ if (status != OK) return status;
+
+ return status;
+}
+
+status_t BluetoothRemoteDeviceProps::readFromParcel(const Parcel* parcel) {
+ String16 name;
+ status_t status = parcel->readString16(&name);
+ if (status != OK) return status;
+ name_ = String8(name).string();
+
+ String16 address;
+ status = parcel->readString16(&address);
+ if (status != OK) return status;
+ address_ = String8(address).string();
+
+ std::vector<UUID> uuids;
+ status = parcel->readParcelableVector(&uuids);
+ if (status != OK) return status;
+
+ for (const auto& uuid : uuids) {
+ service_uuids_.push_back(uuid.uuid);
+ }
+
+ status = parcel->readInt32(&device_class_);
+ if (status != OK) return status;
+
+ status = parcel->readInt32(&device_type_);
+ if (status != OK) return status;
+
+ status = parcel->readInt32(&rssi_);
+ if (status != OK) return status;
+
+ return status;
+}
+
+} // namespace bluetooth
+} // namespace android
diff --git a/service/common/android/bluetooth/bluetooth_remote_device_props.h b/service/common/android/bluetooth/bluetooth_remote_device_props.h
new file mode 100644
index 0000000..e2ad346
--- /dev/null
+++ b/service/common/android/bluetooth/bluetooth_remote_device_props.h
@@ -0,0 +1,57 @@
+//
+// Copyright (C) 2017 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 <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+#include "bluetooth/remote_device_props.h"
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+
+namespace android {
+namespace bluetooth {
+
+class BluetoothRemoteDeviceProps : public Parcelable,
+ public ::bluetooth::RemoteDeviceProps {
+ public:
+ BluetoothRemoteDeviceProps() = default;
+ BluetoothRemoteDeviceProps(const ::bluetooth::RemoteDeviceProps& other)
+ : ::bluetooth::RemoteDeviceProps(other) {} // NOLINT(implicit)
+ BluetoothRemoteDeviceProps(const BluetoothRemoteDeviceProps& other)
+ : ::bluetooth::RemoteDeviceProps(other) {} // NOLINT(implicit)
+ ~BluetoothRemoteDeviceProps() = default;
+
+ // Write |this| parcelable to the given |parcel|. Keep in mind that
+ // implementations of writeToParcel must be manually kept in sync
+ // with readFromParcel and the Java equivalent versions of these methods.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t writeToParcel(Parcel* parcel) const override;
+
+ // Read data from the given |parcel| into |this|. After readFromParcel
+ // completes, |this| should have equivalent state to the object that
+ // wrote itself to the parcel.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t readFromParcel(const Parcel* parcel) override;
+};
+
+} // namespace bluetooth
+} // namespace android
diff --git a/service/common/bluetooth/a2dp_codec_config.cc b/service/common/bluetooth/a2dp_codec_config.cc
new file mode 100644
index 0000000..2b5e5ba
--- /dev/null
+++ b/service/common/bluetooth/a2dp_codec_config.cc
@@ -0,0 +1,41 @@
+//
+// Copyright (C) 2017 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 "bluetooth/a2dp_codec_config.h"
+
+namespace bluetooth {
+
+A2dpCodecConfig::A2dpCodecConfig() = default;
+A2dpCodecConfig::A2dpCodecConfig(const A2dpCodecConfig& other) = default;
+A2dpCodecConfig::A2dpCodecConfig(int codec_type, int codec_priority,
+ int sample_rate, int bits_per_sample,
+ int channel_mode, int64_t codec_specific_1,
+ int64_t codec_specific_2,
+ int64_t codec_specific_3,
+ int64_t codec_specific_4)
+ : codec_type_(codec_type),
+ codec_priority_(codec_priority),
+ sample_rate_(sample_rate),
+ bits_per_sample_(bits_per_sample),
+ channel_mode_(channel_mode),
+ codec_specific_1_(codec_specific_1),
+ codec_specific_2_(codec_specific_2),
+ codec_specific_3_(codec_specific_3),
+ codec_specific_4_(codec_specific_4) {}
+
+A2dpCodecConfig::~A2dpCodecConfig() = default;
+
+} // namespace bluetooth
diff --git a/service/common/bluetooth/a2dp_codec_config.h b/service/common/bluetooth/a2dp_codec_config.h
new file mode 100644
index 0000000..10dbfcb
--- /dev/null
+++ b/service/common/bluetooth/a2dp_codec_config.h
@@ -0,0 +1,56 @@
+//
+// Copyright (C) 2017 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 <cstdint>
+
+namespace bluetooth {
+
+// Should match btav_a2dp_codec_config_t in bt_av.h
+class A2dpCodecConfig {
+ public:
+ A2dpCodecConfig();
+ A2dpCodecConfig(const A2dpCodecConfig& other);
+ A2dpCodecConfig(int codec_type, int codec_priority, int sample_rate,
+ int bits_per_sample, int channel_mode,
+ int64_t codec_specific_1, int64_t codec_specific_2,
+ int64_t codec_specific_3, int64_t codec_specific_4);
+ ~A2dpCodecConfig();
+
+ int codec_type() const { return codec_type_; }
+ int codec_priority() const { return codec_priority_; }
+ int sample_rate() const { return sample_rate_; }
+ int bits_per_sample() const { return bits_per_sample_; }
+ int channel_mode() const { return channel_mode_; }
+ int64_t codec_specific_1() const { return codec_specific_1_; }
+ int64_t codec_specific_2() const { return codec_specific_2_; }
+ int64_t codec_specific_3() const { return codec_specific_3_; }
+ int64_t codec_specific_4() const { return codec_specific_4_; }
+
+ protected:
+ int codec_type_ = 0;
+ int codec_priority_ = 0;
+ int sample_rate_ = 0;
+ int bits_per_sample_ = 0;
+ int channel_mode_ = 0;
+ int64_t codec_specific_1_ = 0;
+ int64_t codec_specific_2_ = 0;
+ int64_t codec_specific_3_ = 0;
+ int64_t codec_specific_4_ = 0;
+};
+
+} // namespace bluetooth
diff --git a/service/common/bluetooth/avrcp_int_value.cc b/service/common/bluetooth/avrcp_int_value.cc
new file mode 100644
index 0000000..5ea07d4
--- /dev/null
+++ b/service/common/bluetooth/avrcp_int_value.cc
@@ -0,0 +1,26 @@
+//
+// Copyright (C) 2017 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 "bluetooth/avrcp_int_value.h"
+
+namespace bluetooth {
+
+AvrcpIntValue::AvrcpIntValue() = default;
+AvrcpIntValue::AvrcpIntValue(const AvrcpIntValue& other) = default;
+AvrcpIntValue::AvrcpIntValue(int id, int value) : id_(id), value_(value) {}
+AvrcpIntValue::~AvrcpIntValue() = default;
+
+} // namespace bluetooth
diff --git a/service/common/bluetooth/avrcp_int_value.h b/service/common/bluetooth/avrcp_int_value.h
new file mode 100644
index 0000000..d9cf510
--- /dev/null
+++ b/service/common/bluetooth/avrcp_int_value.h
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2017 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
+
+namespace bluetooth {
+
+class AvrcpIntValue {
+ public:
+ AvrcpIntValue();
+ AvrcpIntValue(const AvrcpIntValue& other);
+ AvrcpIntValue(int id, int value);
+ ~AvrcpIntValue();
+
+ int id() const { return id_; }
+ int value() const { return value_; }
+
+ protected:
+ int id_ = 0;
+ int value_ = 0;
+};
+
+} // namespace bluetooth
diff --git a/service/common/bluetooth/avrcp_media_attr.cc b/service/common/bluetooth/avrcp_media_attr.cc
new file mode 100644
index 0000000..fc50957
--- /dev/null
+++ b/service/common/bluetooth/avrcp_media_attr.cc
@@ -0,0 +1,38 @@
+//
+// Copyright 2017 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 "bluetooth/avrcp_media_attr.h"
+
+namespace bluetooth {
+
+AvrcpMediaAttr::AvrcpMediaAttr() = default;
+AvrcpMediaAttr::AvrcpMediaAttr(const AvrcpMediaAttr& other) = default;
+AvrcpMediaAttr::AvrcpMediaAttr(const std::string& title,
+ const std::string& artist,
+ const std::string& album,
+ const std::string& genre, int track_num,
+ int num_tracks, int play_time)
+ : title_(title),
+ artist_(artist),
+ album_(album),
+ genre_(genre),
+ track_num_(track_num),
+ num_tracks_(num_tracks),
+ play_time_(play_time) {}
+
+AvrcpMediaAttr::~AvrcpMediaAttr() = default;
+
+} // namespace bluetooth
diff --git a/service/common/bluetooth/avrcp_media_attr.h b/service/common/bluetooth/avrcp_media_attr.h
new file mode 100644
index 0000000..31a7cfd
--- /dev/null
+++ b/service/common/bluetooth/avrcp_media_attr.h
@@ -0,0 +1,50 @@
+//
+// Copyright (C) 2017 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 {
+
+class AvrcpMediaAttr {
+ public:
+ AvrcpMediaAttr();
+ AvrcpMediaAttr(const AvrcpMediaAttr& other);
+ AvrcpMediaAttr(const std::string& title, const std::string& artist,
+ const std::string& album, const std::string& genre,
+ int track_num, int num_tracks, int play_time);
+ ~AvrcpMediaAttr();
+
+ const std::string& title() const { return title_; }
+ const std::string& artist() const { return artist_; }
+ const std::string& album() const { return album_; }
+ const std::string& genre() const { return genre_; }
+ int track_num() const { return track_num_; }
+ int num_tracks() const { return num_tracks_; }
+ int play_time() const { return play_time_; }
+
+ protected:
+ std::string title_;
+ std::string artist_;
+ std::string album_;
+ std::string genre_;
+ int track_num_ = -1;
+ int num_tracks_ = -1;
+ int play_time_ = -1;
+};
+
+} // namespace bluetooth
diff --git a/service/common/bluetooth/avrcp_register_notification_response.cc b/service/common/bluetooth/avrcp_register_notification_response.cc
new file mode 100644
index 0000000..6200f77
--- /dev/null
+++ b/service/common/bluetooth/avrcp_register_notification_response.cc
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2017 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 "bluetooth/avrcp_register_notification_response.h"
+
+namespace bluetooth {
+
+AvrcpRegisterNotificationResponse::AvrcpRegisterNotificationResponse() =
+ default;
+AvrcpRegisterNotificationResponse::AvrcpRegisterNotificationResponse(
+ const AvrcpRegisterNotificationResponse& other) = default;
+AvrcpRegisterNotificationResponse::AvrcpRegisterNotificationResponse(
+ const btrc_register_notification_t& data)
+ : data_(data) {}
+AvrcpRegisterNotificationResponse::~AvrcpRegisterNotificationResponse() =
+ default;
+
+} // namespace bluetooth
diff --git a/service/common/bluetooth/avrcp_register_notification_response.h b/service/common/bluetooth/avrcp_register_notification_response.h
new file mode 100644
index 0000000..3c78da2
--- /dev/null
+++ b/service/common/bluetooth/avrcp_register_notification_response.h
@@ -0,0 +1,38 @@
+//
+// Copyright (C) 2017 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 <hardware/bt_common_types.h>
+#include <hardware/bt_rc.h>
+
+namespace bluetooth {
+
+class AvrcpRegisterNotificationResponse {
+ public:
+ AvrcpRegisterNotificationResponse();
+ AvrcpRegisterNotificationResponse(
+ const AvrcpRegisterNotificationResponse& other);
+ AvrcpRegisterNotificationResponse(const btrc_register_notification_t& data);
+ ~AvrcpRegisterNotificationResponse();
+
+ const btrc_register_notification_t& data() const { return data_; }
+
+ protected:
+ btrc_register_notification_t data_;
+};
+
+} // namespace bluetooth
diff --git a/service/common/bluetooth/avrcp_string_value.h b/service/common/bluetooth/avrcp_string_value.h
new file mode 100644
index 0000000..0b5cca4
--- /dev/null
+++ b/service/common/bluetooth/avrcp_string_value.h
@@ -0,0 +1,38 @@
+//
+// Copyright (C) 2017 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 {
+
+class AvrcpStringValue {
+ public:
+ AvrcpStringValue() = default;
+ AvrcpStringValue(const AvrcpStringValue& other) = default;
+ AvrcpStringValue(int id, const std::string& value) : id_(id), value_(value){};
+ ~AvrcpStringValue() = default;
+
+ int id() const { return id_; }
+ const std::string& value() const { return value_; }
+
+ protected:
+ int id_ = 0;
+ std::string value_;
+};
+
+} // namespace bluetooth
diff --git a/service/common/bluetooth/remote_device_props.cc b/service/common/bluetooth/remote_device_props.cc
new file mode 100644
index 0000000..930421f
--- /dev/null
+++ b/service/common/bluetooth/remote_device_props.cc
@@ -0,0 +1,38 @@
+//
+// Copyright 2017 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 "bluetooth/remote_device_props.h"
+
+using std::string;
+
+namespace bluetooth {
+
+RemoteDeviceProps::RemoteDeviceProps() = default;
+RemoteDeviceProps::RemoteDeviceProps(const RemoteDeviceProps& other) = default;
+RemoteDeviceProps::RemoteDeviceProps(const std::string& name,
+ const std::string& address,
+ const std::vector<Uuid>& service_uuids,
+ int32_t device_class, int32_t device_type,
+ int32_t rssi)
+ : name_(name),
+ address_(address),
+ service_uuids_(service_uuids),
+ device_class_(device_class),
+ device_type_(device_type),
+ rssi_(rssi) {}
+RemoteDeviceProps::~RemoteDeviceProps() = default;
+
+} // namespace bluetooth
diff --git a/service/common/bluetooth/remote_device_props.h b/service/common/bluetooth/remote_device_props.h
new file mode 100644
index 0000000..f8b3b1b
--- /dev/null
+++ b/service/common/bluetooth/remote_device_props.h
@@ -0,0 +1,53 @@
+//
+// Copyright (C) 2017 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 "bluetooth/uuid.h"
+
+namespace bluetooth {
+
+class RemoteDeviceProps {
+ public:
+ RemoteDeviceProps();
+ RemoteDeviceProps(const RemoteDeviceProps& other);
+ RemoteDeviceProps(const std::string& name, const std::string& address,
+ const std::vector<Uuid>& service_uuids,
+ int32_t device_class, int32_t device_type, int32_t rssi);
+ ~RemoteDeviceProps();
+
+ void set_address(const std::string& address) { address_ = address; }
+
+ const std::string& name() const { return name_; }
+ const std::string& address() const { return address_; }
+ const std::vector<Uuid>& service_uuids() const { return service_uuids_; }
+ int32_t device_class() const { return device_class_; }
+ int32_t device_type() const { return device_type_; }
+ int32_t rssi() const { return rssi_; }
+
+ protected:
+ std::string name_;
+ std::string address_;
+ std::vector<Uuid> service_uuids_;
+ int32_t device_class_ = -1;
+ int32_t device_type_ = -1;
+ int32_t rssi_ = -1;
+};
+
+} // namespace bluetooth
diff --git a/service/daemon.cc b/service/daemon.cc
index 86a3b5a..a64c2d8 100644
--- a/service/daemon.cc
+++ b/service/daemon.cc
@@ -22,6 +22,8 @@
#include <base/run_loop.h>
#include "service/adapter.h"
+#include "service/hal/bluetooth_av_interface.h"
+#include "service/hal/bluetooth_avrcp_interface.h"
#include "service/hal/bluetooth_gatt_interface.h"
#include "service/hal/bluetooth_interface.h"
#include "service/ipc/ipc_manager.h"
@@ -69,6 +71,10 @@
if (!hal::BluetoothGattInterface::Initialize()) goto failed;
+ if (!hal::BluetoothAvInterface::Initialize()) goto failed;
+
+ if (!hal::BluetoothAvrcpInterface::Initialize()) goto failed;
+
return true;
failed:
@@ -81,6 +87,10 @@
hal::BluetoothGattInterface::CleanUp();
if (hal::BluetoothInterface::IsInitialized())
hal::BluetoothInterface::CleanUp();
+ if (hal::BluetoothAvInterface::IsInitialized())
+ hal::BluetoothAvInterface::CleanUp();
+ if (hal::BluetoothAvrcpInterface::IsInitialized())
+ hal::BluetoothAvrcpInterface::CleanUp();
}
void CleanUpBluetoothStack() {
diff --git a/service/example/heart_rate/server_main.cc b/service/example/heart_rate/server_main.cc
index 8ffded6..7423462 100644
--- a/service/example/heart_rate/server_main.cc
+++ b/service/example/heart_rate/server_main.cc
@@ -41,10 +41,7 @@
std::string kServiceName = "bluetooth-service";
void QuitMessageLoop() {
- // I don't know why both of these calls are necessary but the message loop
- // doesn't stop unless I call both. Bug in base::MessageLoop?
base::RunLoop().Quit();
- base::MessageLoop::current()->QuitNow();
}
// Handles the case where the Bluetooth process dies.
@@ -134,7 +131,7 @@
}
LOG(ERROR) << "Starting Heart Rate server failed asynchronously";
- main_loop.QuitWhenIdle();
+ base::RunLoop().QuitWhenIdle();
};
bool advertise =
diff --git a/service/gatt_server_old.cc b/service/gatt_server_old.cc
index e97a6c5..b583d93 100644
--- a/service/gatt_server_old.cc
+++ b/service/gatt_server_old.cc
@@ -23,6 +23,8 @@
#include <unistd.h>
#include <base/bind.h>
+#include <base/bind_helpers.h>
+#include <base/callback.h>
#include <algorithm>
#include <array>
#include <condition_variable>
@@ -77,8 +79,6 @@
} // namespace
-void DoNothing(uint8_t p) {}
-
namespace bluetooth {
namespace gatt {
@@ -354,11 +354,11 @@
// Setup our advertisement. This has no callback.
g_internal->gatt->advertiser->SetData(0 /* std_inst */, false,
{/*TODO: put inverval 2,2 here*/},
- base::Bind(&DoNothing));
+ base::DoNothing());
g_internal->gatt->advertiser->Enable(
0 /* std_inst */, true, base::Bind(&EnableAdvertisingCallback),
- 0 /* no duration */, 0 /* no maxExtAdvEvent*/, base::Bind(&DoNothing));
+ 0 /* no duration */, 0 /* no maxExtAdvEvent*/, base::DoNothing());
}
void ServiceStoppedCallback(int status, int server_if, int srvc_handle) {
@@ -579,7 +579,7 @@
// Setup our advertisement. This has no callback.
internal_->gatt->advertiser->SetData(0, false, /* beacon, not scan response */
- {}, base::Bind(&DoNothing));
+ {}, base::DoNothing());
// transmit_name, /* name */
// 2, 2, interval
// mutable_manufacturer_data,
@@ -605,7 +605,7 @@
// Setup our advertisement. This has no callback.
internal_->gatt->advertiser->SetData(0, true, /* scan response */
- {}, base::Bind(&DoNothing));
+ {}, base::DoNothing());
// transmit_name, /* name */
// false, /* no txpower */
// 2, 2, interval
diff --git a/service/hal/bluetooth_av_interface.cc b/service/hal/bluetooth_av_interface.cc
new file mode 100644
index 0000000..68f5bd0
--- /dev/null
+++ b/service/hal/bluetooth_av_interface.cc
@@ -0,0 +1,364 @@
+//
+// Copyright 2017 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_av_interface.h"
+
+#include <shared_mutex>
+
+#include <base/logging.h>
+#include <base/memory/ptr_util.h>
+#include <base/observer_list.h>
+
+#include "service/hal/bluetooth_interface.h"
+
+namespace bluetooth {
+namespace hal {
+
+namespace {
+
+BluetoothAvInterface* g_interface = nullptr;
+
+#if defined(OS_GENERIC) && defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION < 3500)
+using shared_mutex_impl = std::shared_mutex;
+#else
+using shared_mutex_impl = std::shared_timed_mutex;
+#endif
+
+// Mutex used by callbacks to access |g_interface|. If we initialize or clean it
+// use unique_lock. If only accessing |g_interface| use shared lock.
+shared_mutex_impl g_instance_lock;
+
+base::ObserverList<BluetoothAvInterface::A2dpSourceObserver>*
+GetA2dpSourceObservers();
+base::ObserverList<BluetoothAvInterface::A2dpSinkObserver>*
+GetA2dpSinkObservers();
+
+#define VERIFY_INTERFACE_OR_RETURN() \
+ do { \
+ if (!g_interface) { \
+ LOG(WARNING) << "Callback received while |g_interface| is NULL"; \
+ return; \
+ } \
+ } while (0)
+
+} // namespace
+
+void SourceConnectionStateCallback(const RawAddress& bd_addr,
+ btav_connection_state_t state) {
+ std::shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+
+ for (auto& observer : *GetA2dpSourceObservers()) {
+ observer.ConnectionStateCallback(g_interface, bd_addr, state);
+ }
+}
+
+void SourceAudioStateCallback(const RawAddress& bd_addr,
+ btav_audio_state_t state) {
+ std::shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetA2dpSourceObservers()) {
+ observer.AudioStateCallback(g_interface, bd_addr, state);
+ }
+}
+
+void SourceAudioConfigCallback(
+ const RawAddress& bd_addr, btav_a2dp_codec_config_t codec_config,
+ std::vector<btav_a2dp_codec_config_t> codecs_local_capabilities,
+ std::vector<btav_a2dp_codec_config_t> codecs_selectable_capabilities) {
+ std::shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetA2dpSourceObservers()) {
+ observer.AudioConfigCallback(g_interface, bd_addr, codec_config,
+ codecs_local_capabilities,
+ codecs_selectable_capabilities);
+ }
+}
+
+void SinkConnectionStateCallback(const RawAddress& bd_addr,
+ btav_connection_state_t state) {
+ std::shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetA2dpSinkObservers()) {
+ observer.ConnectionStateCallback(g_interface, bd_addr, state);
+ }
+}
+
+void SinkAudioStateCallback(const RawAddress& bd_addr,
+ btav_audio_state_t state) {
+ std::shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetA2dpSinkObservers()) {
+ observer.AudioStateCallback(g_interface, bd_addr, state);
+ }
+}
+
+void SinkAudioConfigCallback(const RawAddress& bd_addr, uint32_t sample_rate,
+ uint8_t channel_count) {
+ std::shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetA2dpSinkObservers()) {
+ observer.AudioConfigCallback(g_interface, bd_addr, sample_rate,
+ channel_count);
+ }
+}
+
+btav_source_callbacks_t av_source_callbacks = {
+ .size = sizeof(btav_source_callbacks_t),
+ .connection_state_cb = SourceConnectionStateCallback,
+ .audio_state_cb = SourceAudioStateCallback,
+ .audio_config_cb = SourceAudioConfigCallback,
+};
+
+btav_sink_callbacks_t av_sink_callbacks = {
+ .size = sizeof(btav_sink_callbacks_t),
+ .connection_state_cb = SinkConnectionStateCallback,
+ .audio_state_cb = SinkAudioStateCallback,
+ .audio_config_cb = SinkAudioConfigCallback,
+};
+
+class BluetoothAvInterfaceImpl : public BluetoothAvInterface {
+ public:
+ BluetoothAvInterfaceImpl() = default;
+ ~BluetoothAvInterfaceImpl() override {
+ A2dpSinkDisable();
+ A2dpSourceDisable();
+ }
+
+ bool A2dpSourceEnable(
+ std::vector<btav_a2dp_codec_config_t> codec_priorities) override {
+ if (source_enabled_) {
+ return true;
+ }
+
+ // Right now we only support one connected audio device.
+ int max_connected_audio_devices = 1;
+ if (hal_source_iface_->init(
+ &av_source_callbacks, max_connected_audio_devices,
+ std::move(codec_priorities)) != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to initialize HAL A2DP source interface";
+ return false;
+ }
+ source_enabled_ = true;
+ return true;
+ }
+
+ void A2dpSourceDisable() override {
+ if (!source_enabled_) {
+ return;
+ }
+
+ hal_source_iface_->cleanup();
+ source_enabled_ = false;
+ }
+
+ bool A2dpSinkEnable() override {
+ if (sink_enabled_) {
+ return true;
+ }
+ if (hal_sink_iface_->init(&av_sink_callbacks) != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to initialize HAL A2DP sink interface";
+ return false;
+ }
+ sink_enabled_ = true;
+ return true;
+ }
+
+ void A2dpSinkDisable() override {
+ if (!sink_enabled_) {
+ return;
+ }
+ hal_sink_iface_->cleanup();
+ sink_enabled_ = false;
+ }
+
+ void AddA2dpSourceObserver(A2dpSourceObserver* observer) override {
+ a2dp_source_observers_.AddObserver(observer);
+ }
+
+ void RemoveA2dpSourceObserver(A2dpSourceObserver* observer) override {
+ a2dp_source_observers_.RemoveObserver(observer);
+ }
+
+ void AddA2dpSinkObserver(A2dpSinkObserver* observer) override {
+ a2dp_sink_observers_.AddObserver(observer);
+ }
+
+ void RemoveA2dpSinkObserver(A2dpSinkObserver* observer) override {
+ a2dp_sink_observers_.RemoveObserver(observer);
+ }
+
+ const btav_source_interface_t* GetA2dpSourceHALInterface() override {
+ return hal_source_iface_;
+ }
+
+ const btav_sink_interface_t* GetA2dpSinkHALInterface() override {
+ return hal_sink_iface_;
+ }
+
+ bool Initialize() {
+ const bt_interface_t* bt_iface =
+ BluetoothInterface::Get()->GetHALInterface();
+ CHECK(bt_iface);
+
+ const auto* hal_source_iface =
+ reinterpret_cast<const btav_source_interface_t*>(
+ bt_iface->get_profile_interface(BT_PROFILE_ADVANCED_AUDIO_ID));
+ if (!hal_source_iface) {
+ LOG(ERROR) << "Failed to obtain A2DP source interface handle";
+ return false;
+ }
+
+ const auto* hal_sink_iface = reinterpret_cast<const btav_sink_interface_t*>(
+ bt_iface->get_profile_interface(BT_PROFILE_ADVANCED_AUDIO_SINK_ID));
+ if (!hal_sink_iface) {
+ LOG(ERROR) << "Failed to obtain A2DP sink interface handle";
+ return false;
+ }
+
+ hal_sink_iface_ = hal_sink_iface;
+ hal_source_iface_ = hal_source_iface;
+
+ // Only initialize the sink interface.
+ return A2dpSinkEnable();
+ }
+
+ base::ObserverList<A2dpSourceObserver>* source_observers() {
+ return &a2dp_source_observers_;
+ }
+
+ base::ObserverList<A2dpSinkObserver>* sink_observers() {
+ return &a2dp_sink_observers_;
+ }
+
+ private:
+ base::ObserverList<A2dpSourceObserver> a2dp_source_observers_;
+ base::ObserverList<A2dpSinkObserver> a2dp_sink_observers_;
+
+ const btav_source_interface_t* hal_source_iface_ = nullptr;
+ const btav_sink_interface_t* hal_sink_iface_ = nullptr;
+
+ bool source_enabled_ = false;
+ bool sink_enabled_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothAvInterfaceImpl);
+};
+
+namespace {
+
+base::ObserverList<BluetoothAvInterface::A2dpSourceObserver>*
+GetA2dpSourceObservers() {
+ CHECK(g_interface);
+ return static_cast<BluetoothAvInterfaceImpl*>(g_interface)
+ ->source_observers();
+}
+
+base::ObserverList<BluetoothAvInterface::A2dpSinkObserver>*
+GetA2dpSinkObservers() {
+ CHECK(g_interface);
+ return static_cast<BluetoothAvInterfaceImpl*>(g_interface)->sink_observers();
+}
+
+} // namespace
+
+void BluetoothAvInterface::A2dpSourceObserver::ConnectionStateCallback(
+ BluetoothAvInterface* iface, const RawAddress& bd_addr,
+ btav_connection_state_t state) {
+ // Do nothing.
+}
+
+void BluetoothAvInterface::A2dpSourceObserver::AudioStateCallback(
+ BluetoothAvInterface* iface, const RawAddress& bd_addr,
+ btav_audio_state_t state) {
+ // Do nothing.
+}
+
+void BluetoothAvInterface::A2dpSourceObserver::AudioConfigCallback(
+ BluetoothAvInterface* iface, const RawAddress& bd_addr,
+ const btav_a2dp_codec_config_t& codec_config,
+ const std::vector<btav_a2dp_codec_config_t> codecs_local_capabilities,
+ const std::vector<btav_a2dp_codec_config_t>
+ codecs_selectable_capabilities) {
+ // Do nothing.
+}
+
+void BluetoothAvInterface::A2dpSinkObserver::ConnectionStateCallback(
+ BluetoothAvInterface* iface, const RawAddress& bd_addr,
+ btav_connection_state_t state) {
+ // Do nothing.
+}
+
+void BluetoothAvInterface::A2dpSinkObserver::AudioStateCallback(
+ BluetoothAvInterface* iface, const RawAddress& bd_addr,
+ btav_audio_state_t state) {
+ // Do nothing.
+}
+
+void BluetoothAvInterface::A2dpSinkObserver::AudioConfigCallback(
+ BluetoothAvInterface* iface, const RawAddress& bd_addr,
+ uint32_t sample_rate, uint8_t channel_count) {
+ // Do nothing.
+}
+
+// static
+bool BluetoothAvInterface::Initialize() {
+ std::unique_lock<shared_mutex_impl> lock(g_instance_lock);
+ CHECK(!g_interface);
+
+ auto impl = std::make_unique<BluetoothAvInterfaceImpl>();
+ if (!impl->Initialize()) {
+ LOG(ERROR) << "Failed to initialize BluetoothAvInterface";
+ return false;
+ }
+
+ g_interface = impl.release();
+ return true;
+}
+
+// static
+void BluetoothAvInterface::CleanUp() {
+ std::unique_lock<shared_mutex_impl> lock(g_instance_lock);
+ CHECK(g_interface);
+
+ delete g_interface;
+ g_interface = nullptr;
+}
+
+// static
+bool BluetoothAvInterface::IsInitialized() {
+ std::shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ return g_interface != nullptr;
+}
+
+// static
+void BluetoothAvInterface::InitializeForTesting(
+ BluetoothAvInterface* test_instance) {
+ std::unique_lock<shared_mutex_impl> lock(g_instance_lock);
+ CHECK(test_instance);
+ CHECK(!g_interface);
+
+ g_interface = test_instance;
+}
+
+// static
+BluetoothAvInterface* BluetoothAvInterface::Get() {
+ std::shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ CHECK(g_interface);
+ return g_interface;
+}
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/service/hal/bluetooth_av_interface.h b/service/hal/bluetooth_av_interface.h
new file mode 100644
index 0000000..9346143
--- /dev/null
+++ b/service/hal/bluetooth_av_interface.h
@@ -0,0 +1,96 @@
+//
+// Copyright (C) 2017 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>
+#include <hardware/bt_av.h>
+
+#include <vector>
+
+namespace bluetooth {
+namespace hal {
+
+class BluetoothAvInterface {
+ public:
+ class A2dpSourceObserver {
+ public:
+ virtual void ConnectionStateCallback(BluetoothAvInterface* iface,
+ const RawAddress& bd_addr,
+ btav_connection_state_t state);
+ virtual void AudioStateCallback(BluetoothAvInterface* iface,
+ const RawAddress& bd_addr,
+ btav_audio_state_t state);
+ virtual void AudioConfigCallback(
+ BluetoothAvInterface* iface, const RawAddress& bd_addr,
+ const btav_a2dp_codec_config_t& codec_config,
+ const std::vector<btav_a2dp_codec_config_t> codecs_local_capabilities,
+ const std::vector<btav_a2dp_codec_config_t>
+ codecs_selectable_capabilities);
+
+ protected:
+ virtual ~A2dpSourceObserver() = default;
+ };
+
+ class A2dpSinkObserver {
+ public:
+ virtual void ConnectionStateCallback(BluetoothAvInterface* iface,
+ const RawAddress& bd_addr,
+ btav_connection_state_t state);
+ virtual void AudioStateCallback(BluetoothAvInterface* iface,
+ const RawAddress& bd_addr,
+ btav_audio_state_t state);
+ virtual void AudioConfigCallback(BluetoothAvInterface* iface,
+ const RawAddress& bd_addr,
+ uint32_t sample_rate,
+ uint8_t channel_count);
+
+ protected:
+ virtual ~A2dpSinkObserver() = default;
+ };
+
+ static bool Initialize();
+ static void CleanUp();
+ static bool IsInitialized();
+ static void InitializeForTesting(BluetoothAvInterface* test_instance);
+
+ static BluetoothAvInterface* Get();
+
+ virtual bool A2dpSourceEnable(
+ std::vector<btav_a2dp_codec_config_t> codec_priorities) = 0;
+ virtual void A2dpSourceDisable() = 0;
+ virtual bool A2dpSinkEnable() = 0;
+ virtual void A2dpSinkDisable() = 0;
+
+ virtual void AddA2dpSourceObserver(A2dpSourceObserver* observer) = 0;
+ virtual void RemoveA2dpSourceObserver(A2dpSourceObserver* observer) = 0;
+ virtual void AddA2dpSinkObserver(A2dpSinkObserver* observer) = 0;
+ virtual void RemoveA2dpSinkObserver(A2dpSinkObserver* observer) = 0;
+
+ virtual const btav_source_interface_t* GetA2dpSourceHALInterface() = 0;
+ virtual const btav_sink_interface_t* GetA2dpSinkHALInterface() = 0;
+
+ protected:
+ BluetoothAvInterface() = default;
+ virtual ~BluetoothAvInterface() = default;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BluetoothAvInterface);
+};
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/service/hal/bluetooth_avrcp_interface.cc b/service/hal/bluetooth_avrcp_interface.cc
new file mode 100644
index 0000000..02e7316
--- /dev/null
+++ b/service/hal/bluetooth_avrcp_interface.cc
@@ -0,0 +1,891 @@
+//
+// Copyright 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_avrcp_interface.h"
+
+#include <mutex>
+#include <shared_mutex>
+
+#include <base/logging.h>
+#include <base/observer_list.h>
+
+#include "service/hal/bluetooth_interface.h"
+#include "service/logging_helpers.h"
+
+using std::lock_guard;
+using std::mutex;
+using std::shared_lock;
+using std::unique_lock;
+#if defined(OS_GENERIC) && defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION < 3500)
+using shared_mutex_impl = std::shared_mutex;
+#else
+using shared_mutex_impl = std::shared_timed_mutex;
+#endif
+
+namespace bluetooth {
+namespace hal {
+
+namespace {
+
+// The global BluetoothAvrcpInterface instance.
+BluetoothAvrcpInterface* g_interface = nullptr;
+
+// Mutex used by callbacks to access |g_interface|. If we initialize or clean it
+// use unique_lock. If only accessing |g_interface| use shared lock.
+// TODO(jpawlowski): this should be just shared_mutex, as we currently don't use
+// timed methods. Change to shared_mutex when we upgrade to C++14
+shared_mutex_impl g_instance_lock;
+
+// Helper for obtaining the observer lists. This is forward declared here
+// and defined below since it depends on BluetoothInterfaceImpl.
+base::ObserverList<BluetoothAvrcpInterface::TargetObserver>*
+GetTargetObservers();
+
+base::ObserverList<BluetoothAvrcpInterface::ControlObserver>*
+GetControlObservers();
+
+#define VERIFY_INTERFACE_OR_RETURN() \
+ do { \
+ if (!g_interface) { \
+ LOG(WARNING) << "Callback received while |g_interface| is NULL"; \
+ return; \
+ } \
+ } while (0)
+
+void RemoteFeaturesCallback(const RawAddress& bd_addr,
+ btrc_remote_features_t features) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.RemoteFeaturesCallback(bd_addr, features);
+ }
+}
+
+void GetPlayStatusCallback(const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.GetPlayStatusCallback(bd_addr);
+ }
+}
+
+void ListPlayerAppAttrCallback(const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.ListPlayerAppAttrCallback(bd_addr);
+ }
+}
+
+void ListPlayerAppValuesCallback(btrc_player_attr_t attr_id,
+ const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.ListPlayerAppValuesCallback(attr_id, bd_addr);
+ }
+}
+
+void GetPlayerAppValueCallback(uint8_t num_attr, btrc_player_attr_t* p_attrs,
+ const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.GetPlayerAppValueCallback(num_attr, p_attrs, bd_addr);
+ }
+}
+
+void GetPlayerAppAttrsTextCallback(uint8_t num_attr,
+ btrc_player_attr_t* p_attrs,
+ const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.GetPlayerAppAttrsTextCallback(num_attr, p_attrs, bd_addr);
+ }
+}
+
+void GetPlayerAppValuesTextCallback(uint8_t attr_id, uint8_t num_val,
+ uint8_t* p_vals,
+ const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.GetPlayerAppValuesTextCallback(attr_id, num_val, p_vals, bd_addr);
+ }
+}
+
+void SetPlayerAppValueCallback(btrc_player_settings_t* p_vals,
+ const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.SetPlayerAppValueCallback(p_vals, bd_addr);
+ }
+}
+
+void GetElementAttrCallback(uint8_t num_attr, btrc_media_attr_t* p_attrs,
+ const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.GetElementAttrCallback(num_attr, p_attrs, bd_addr);
+ }
+}
+
+void RegisterNotificationCallback(btrc_event_id_t event_id, uint32_t param,
+ const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.RegisterNotificationCallback(event_id, param, bd_addr);
+ }
+}
+
+void VolumeChangeCallback(uint8_t volume, uint8_t ctype,
+ const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.VolumeChangeCallback(volume, ctype, bd_addr);
+ }
+}
+
+void PassthroughCmdCallback(int id, int key_state, const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.PassthroughCmdCallback(id, key_state, bd_addr);
+ }
+}
+
+void SetAddressedPlayerCallback(uint16_t player_id, const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.SetAddressedPlayerCallback(player_id, bd_addr);
+ }
+}
+
+void SetBrowsedPlayerCallback(uint16_t player_id, const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.SetBrowsedPlayerCallback(player_id, bd_addr);
+ }
+}
+
+void GetFolderItemsCallback(uint8_t scope, uint32_t start_item,
+ uint32_t end_item, uint8_t num_attr,
+ uint32_t* p_attr_ids, const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.GetFolderItemsCallback(scope, start_item, end_item, num_attr,
+ p_attr_ids, bd_addr);
+ }
+}
+
+void ChangePathCallback(uint8_t direction, uint8_t* folder_uid,
+ const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.ChangePathCallback(direction, folder_uid, bd_addr);
+ }
+}
+
+void GetItemAttrCallback(uint8_t scope, uint8_t* uid, uint16_t uid_counter,
+ uint8_t num_attr, btrc_media_attr_t* p_attrs,
+ const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.GetItemAttrCallback(scope, uid, uid_counter, num_attr, p_attrs,
+ bd_addr);
+ }
+}
+
+void PlayItemCallback(uint8_t scope, uint16_t uid_counter, uint8_t* uid,
+ const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.PlayItemCallback(scope, uid_counter, uid, bd_addr);
+ }
+}
+
+void GetTotalNumOfItemsCallback(uint8_t scope, const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.GetTotalNumOfItemsCallback(scope, bd_addr);
+ }
+}
+
+void SearchCallback(uint16_t charset_id, uint16_t str_len, uint8_t* p_str,
+ const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.SearchCallback(str_len, p_str, bd_addr);
+ }
+}
+
+void AddToNowPlayingCallback(uint8_t scope, uint8_t* uid, uint16_t uid_counter,
+ const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetTargetObservers()) {
+ observer.AddToNowPlayingCallback(scope, uid, uid_counter, bd_addr);
+ }
+}
+
+void PassthroughRspCallback(const RawAddress& bd_addr, int id, int key_state) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.PassthroughRspCallback(bd_addr, id, key_state);
+ }
+}
+
+void GroupnavigationRspCallback(int id, int key_state) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.GroupnavigationRspCallback(id, key_state);
+ }
+}
+
+void ConnectionStateCallback(bool rc_connect, bool bt_connect,
+ const RawAddress& bd_addr) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.ConnectionStateCallback(rc_connect, bt_connect, bd_addr);
+ }
+}
+
+void CtrlGetrcfeaturesCallback(const RawAddress& bd_addr, int features) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.CtrlGetrcfeaturesCallback(bd_addr, features);
+ }
+}
+
+void CtrlSetplayerapplicationsettingRspCallback(const RawAddress& bd_addr,
+ uint8_t accepted) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+
+ for (auto& observer : *GetControlObservers()) {
+ observer.CtrlSetplayerapplicationsettingRspCallback(bd_addr, accepted);
+ }
+}
+
+void CtrlPlayerapplicationsettingCallback(
+ const RawAddress& bd_addr, uint8_t num_attr,
+ btrc_player_app_attr_t* app_attrs, uint8_t num_ext_attr,
+ btrc_player_app_ext_attr_t* ext_attrs) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.CtrlPlayerapplicationsettingCallback(bd_addr, num_attr, app_attrs,
+ num_ext_attr, ext_attrs);
+ }
+}
+
+void CtrlPlayerapplicationsettingChangedCallback(
+ const RawAddress& bd_addr, const btrc_player_settings_t& vals) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.CtrlPlayerapplicationsettingChangedCallback(bd_addr, vals);
+ }
+}
+
+void CtrlSetabsvolCmdCallback(const RawAddress& bd_addr, uint8_t abs_vol,
+ uint8_t label) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.CtrlSetabsvolCmdCallback(bd_addr, abs_vol, label);
+ }
+}
+
+void CtrlRegisternotificationAbsVolCallback(const RawAddress& bd_addr,
+ uint8_t label) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.CtrlRegisternotificationAbsVolCallback(bd_addr, label);
+ }
+}
+
+void CtrlTrackChangedCallback(const RawAddress& bd_addr, uint8_t num_attr,
+ btrc_element_attr_val_t* p_attrs) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.CtrlTrackChangedCallback(bd_addr, num_attr, p_attrs);
+ }
+}
+
+void CtrlPlayPositionChangedCallback(const RawAddress& bd_addr,
+ uint32_t song_len, uint32_t song_pos) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.CtrlPlayPositionChangedCallback(bd_addr, song_len, song_pos);
+ }
+}
+
+void CtrlPlayStatusChangedCallback(const RawAddress& bd_addr,
+ btrc_play_status_t play_status) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.CtrlPlayStatusChangedCallback(bd_addr, play_status);
+ }
+}
+
+void CtrlGetFolderItemsCallback(const RawAddress& bd_addr, btrc_status_t status,
+ const btrc_folder_items_t* folder_items,
+ uint8_t count) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.CtrlGetFolderItemsCallback(bd_addr, status, folder_items, count);
+ }
+}
+
+void CtrlChangePathCallback(const RawAddress& bd_addr, uint32_t count) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.CtrlChangePathCallback(bd_addr, count);
+ }
+}
+
+void CtrlSetBrowsedPlayerCallback(const RawAddress& bd_addr, uint8_t num_items,
+ uint8_t depth) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.CtrlSetBrowsedPlayerCallback(bd_addr, num_items, depth);
+ }
+}
+
+void CtrlSetAddressedPlayerCallback(const RawAddress& bd_addr, uint8_t status) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__;
+ VERIFY_INTERFACE_OR_RETURN();
+ for (auto& observer : *GetControlObservers()) {
+ observer.CtrlSetAddressedPlayerCallback(bd_addr, status);
+ }
+}
+
+btrc_callbacks_t target_callbacks = {
+ .size = sizeof(btrc_callbacks_t),
+ .remote_features_cb = RemoteFeaturesCallback,
+ .get_play_status_cb = GetPlayStatusCallback,
+ .list_player_app_attr_cb = ListPlayerAppAttrCallback,
+ .list_player_app_values_cb = ListPlayerAppValuesCallback,
+ .get_player_app_value_cb = GetPlayerAppValueCallback,
+ .get_player_app_attrs_text_cb = GetPlayerAppAttrsTextCallback,
+ .get_player_app_values_text_cb = GetPlayerAppValuesTextCallback,
+ .set_player_app_value_cb = SetPlayerAppValueCallback,
+ .get_element_attr_cb = GetElementAttrCallback,
+ .register_notification_cb = RegisterNotificationCallback,
+ .volume_change_cb = VolumeChangeCallback,
+ .passthrough_cmd_cb = PassthroughCmdCallback,
+ .set_addressed_player_cb = SetAddressedPlayerCallback,
+ .set_browsed_player_cb = SetBrowsedPlayerCallback,
+ .get_folder_items_cb = GetFolderItemsCallback,
+ .change_path_cb = ChangePathCallback,
+ .get_item_attr_cb = GetItemAttrCallback,
+ .play_item_cb = PlayItemCallback,
+ .get_total_num_of_items_cb = GetTotalNumOfItemsCallback,
+ .search_cb = SearchCallback,
+ .add_to_now_playing_cb = AddToNowPlayingCallback,
+};
+
+btrc_ctrl_callbacks_t control_callbacks = {
+ .size = sizeof(btrc_ctrl_callbacks_t),
+ .passthrough_rsp_cb = PassthroughRspCallback,
+ .groupnavigation_rsp_cb = GroupnavigationRspCallback,
+ .connection_state_cb = ConnectionStateCallback,
+ .getrcfeatures_cb = CtrlGetrcfeaturesCallback,
+ .setplayerappsetting_rsp_cb = CtrlSetplayerapplicationsettingRspCallback,
+ .playerapplicationsetting_cb = CtrlPlayerapplicationsettingCallback,
+ .playerapplicationsetting_changed_cb =
+ CtrlPlayerapplicationsettingChangedCallback,
+ .setabsvol_cmd_cb = CtrlSetabsvolCmdCallback,
+ .registernotification_absvol_cb = CtrlRegisternotificationAbsVolCallback,
+ .track_changed_cb = CtrlTrackChangedCallback,
+ .play_position_changed_cb = CtrlPlayPositionChangedCallback,
+ .play_status_changed_cb = CtrlPlayStatusChangedCallback,
+ .get_folder_items_cb = CtrlGetFolderItemsCallback,
+ .change_folder_path_cb = CtrlChangePathCallback,
+ .set_browsed_player_cb = CtrlSetBrowsedPlayerCallback,
+ .set_addressed_player_cb = CtrlSetAddressedPlayerCallback,
+};
+
+} // namespace
+
+// BluetoothAvrcpInterface implementation for production.
+class BluetoothAvrcpInterfaceImpl : public BluetoothAvrcpInterface {
+ public:
+ BluetoothAvrcpInterfaceImpl() : control_iface_(nullptr) {}
+
+ ~BluetoothAvrcpInterfaceImpl() override {
+ if (control_iface_) control_iface_->cleanup();
+ }
+
+ bool AvrcpControlEnable() override {
+ if (control_enabled_) {
+ return true;
+ }
+
+ if (control_iface_->init(&control_callbacks) != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to initialize HAL AVRCP control interface";
+ return false;
+ }
+
+ control_enabled_ = true;
+ return true;
+ }
+
+ void AvrcpControlDisable() override {
+ if (!control_enabled_) {
+ return;
+ }
+
+ control_iface_->cleanup();
+ control_enabled_ = false;
+ }
+
+ bool AvrcpTargetEnable() override {
+ if (target_enabled_) {
+ return true;
+ }
+
+ if (target_iface_->init(&target_callbacks) != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to initialize HAL AVRCP target interface";
+ return false;
+ }
+
+ target_enabled_ = true;
+ return true;
+ }
+
+ void AvrcpTargetDisable() override {
+ if (!target_enabled_) {
+ return;
+ }
+
+ target_iface_->cleanup();
+ target_enabled_ = false;
+ }
+
+ void AddTargetObserver(TargetObserver* observer) override {
+ target_observers_.AddObserver(observer);
+ }
+
+ void RemoveTargetObserver(TargetObserver* observer) override {
+ target_observers_.RemoveObserver(observer);
+ }
+
+ void AddControlObserver(ControlObserver* observer) override {
+ control_observers_.AddObserver(observer);
+ }
+
+ void RemoveControlObserver(ControlObserver* observer) override {
+ control_observers_.RemoveObserver(observer);
+ }
+
+ const btrc_interface_t* GetTargetHALInterface() const override {
+ return target_iface_;
+ }
+
+ const btrc_ctrl_interface_t* GetControlHALInterface() const override {
+ return control_iface_;
+ }
+
+ // Initialize the interface.
+ bool Initialize() {
+ const bt_interface_t* bt_iface =
+ BluetoothInterface::Get()->GetHALInterface();
+ CHECK(bt_iface);
+
+ auto* target_iface = reinterpret_cast<const btrc_interface_t*>(
+ bt_iface->get_profile_interface(BT_PROFILE_AV_RC_ID));
+ if (!target_iface) {
+ LOG(ERROR) << "Failed to obtain HAL AVRCP target interface handle";
+ return false;
+ }
+
+ auto* control_iface = reinterpret_cast<const btrc_ctrl_interface_t*>(
+ bt_iface->get_profile_interface(BT_PROFILE_AV_RC_CTRL_ID));
+ if (!control_iface) {
+ LOG(ERROR) << "Failed to obtain HAL AVRCP control interface handle";
+ return false;
+ }
+
+ control_iface_ = control_iface;
+ target_iface_ = target_iface;
+
+ // Only initialize the control interface.
+ return AvrcpControlEnable();
+ }
+
+ base::ObserverList<TargetObserver>* target_observers() {
+ return &target_observers_;
+ }
+
+ base::ObserverList<ControlObserver>* control_observers() {
+ return &control_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<TargetObserver> target_observers_;
+ base::ObserverList<ControlObserver> control_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 btrc_interface_t* target_iface_ = nullptr;
+ const btrc_ctrl_interface_t* control_iface_ = nullptr;
+
+ bool control_enabled_ = false;
+ bool target_enabled_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothAvrcpInterfaceImpl);
+};
+
+namespace {
+
+base::ObserverList<BluetoothAvrcpInterface::TargetObserver>*
+GetTargetObservers() {
+ CHECK(g_interface);
+ return static_cast<BluetoothAvrcpInterfaceImpl*>(g_interface)
+ ->target_observers();
+}
+
+base::ObserverList<BluetoothAvrcpInterface::ControlObserver>*
+GetControlObservers() {
+ CHECK(g_interface);
+ return static_cast<BluetoothAvrcpInterfaceImpl*>(g_interface)
+ ->control_observers();
+}
+
+} // namespace
+
+void BluetoothAvrcpInterface::TargetObserver::RemoteFeaturesCallback(
+ const RawAddress& bd_addr, btrc_remote_features_t features) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::GetPlayStatusCallback(
+ const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::ListPlayerAppAttrCallback(
+ const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::ListPlayerAppValuesCallback(
+ btrc_player_attr_t attr_id, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::GetPlayerAppValueCallback(
+ uint8_t num_attr, btrc_player_attr_t* p_attrs, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::GetPlayerAppAttrsTextCallback(
+ uint8_t num_attr, btrc_player_attr_t* p_attrs, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::GetPlayerAppValuesTextCallback(
+ uint8_t attr_id, uint8_t num_val, uint8_t* p_vals,
+ const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::SetPlayerAppValueCallback(
+ btrc_player_settings_t* p_vals, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::GetElementAttrCallback(
+ uint8_t num_attr, btrc_media_attr_t* p_attrs, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::RegisterNotificationCallback(
+ btrc_event_id_t event_id, uint32_t param, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::VolumeChangeCallback(
+ uint8_t volume, uint8_t ctype, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::PassthroughCmdCallback(
+ int id, int key_state, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::SetAddressedPlayerCallback(
+ uint16_t player_id, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::SetBrowsedPlayerCallback(
+ uint16_t player_id, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::GetFolderItemsCallback(
+ uint8_t scope, uint32_t start_item, uint32_t end_item, uint8_t num_attr,
+ uint32_t* p_attr_ids, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::ChangePathCallback(
+ uint8_t direction, uint8_t* folder_uid, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::GetItemAttrCallback(
+ uint8_t scope, uint8_t* uid, uint16_t uid_counter, uint8_t num_attr,
+ btrc_media_attr_t* p_attrs, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::PlayItemCallback(
+ uint8_t scope, uint16_t uid_counter, uint8_t* uid,
+ const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::GetTotalNumOfItemsCallback(
+ uint8_t scope, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::SearchCallback(
+ uint16_t str_len, uint8_t* p_str, const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::TargetObserver::AddToNowPlayingCallback(
+ uint8_t scope, uint8_t* uid, uint16_t uid_counter,
+ const RawAddress& bd_addr) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::PassthroughRspCallback(
+ const RawAddress& /* bd_addr */, int /* id */, int /* key_state */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::GroupnavigationRspCallback(
+ int /* id */, int /* key_state */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::ConnectionStateCallback(
+ bool /* rc_connect */, bool /* bt_connect */,
+ const RawAddress& /* bd_addr */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::CtrlGetrcfeaturesCallback(
+ const RawAddress& /* bd_addr */, int /* features */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::
+ CtrlSetplayerapplicationsettingRspCallback(const RawAddress& /* bd_addr */,
+ uint8_t /* accepted */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::
+ CtrlPlayerapplicationsettingCallback(
+ const RawAddress& /* bd_addr */, uint8_t /* num_attr */,
+ btrc_player_app_attr_t* /* app_attrs */, uint8_t /* num_ext_attr */,
+ btrc_player_app_ext_attr_t* /* ext_attrs */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::
+ CtrlPlayerapplicationsettingChangedCallback(
+ const RawAddress& /* bd_addr*/,
+ const btrc_player_settings_t& /* vals */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::CtrlSetabsvolCmdCallback(
+ const RawAddress& /* bd_addr */, uint8_t /* abs_vol */,
+ uint8_t /* label */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::
+ CtrlRegisternotificationAbsVolCallback(const RawAddress& /* bd_addr */,
+ uint8_t /* label */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::CtrlTrackChangedCallback(
+ const RawAddress& /*bd_addr */, uint8_t /* num_attr */,
+ btrc_element_attr_val_t* /* p_attrs */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::CtrlPlayPositionChangedCallback(
+ const RawAddress& /* bd_addr */, uint32_t /* song_len */,
+ uint32_t /* song_pos */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::CtrlPlayStatusChangedCallback(
+ const RawAddress& /* bd_addr */, btrc_play_status_t /* play_status */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::CtrlGetFolderItemsCallback(
+ const RawAddress& /* bd_addr */, btrc_status_t /* status */,
+ const btrc_folder_items_t* /*folder_items */, uint8_t /* count */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::CtrlChangePathCallback(
+ const RawAddress& /* bd_addr */, uint32_t /* count */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::CtrlSetBrowsedPlayerCallback(
+ const RawAddress& /* bd_addr */, uint8_t /* num_items */,
+ uint8_t /* depth */) {
+ // Do nothing.
+}
+
+void BluetoothAvrcpInterface::ControlObserver::CtrlSetAddressedPlayerCallback(
+ const RawAddress& /* bd_addr */, uint8_t /* status */) {
+ // Do nothing.
+}
+
+// static
+bool BluetoothAvrcpInterface::Initialize() {
+ unique_lock<shared_mutex_impl> lock(g_instance_lock);
+ CHECK(!g_interface);
+
+ std::unique_ptr<BluetoothAvrcpInterfaceImpl> impl(
+ new BluetoothAvrcpInterfaceImpl());
+ if (!impl->Initialize()) {
+ LOG(ERROR) << "Failed to initialize BluetoothAvrcpInterface";
+ return false;
+ }
+
+ g_interface = impl.release();
+
+ return true;
+}
+
+// static
+void BluetoothAvrcpInterface::CleanUp() {
+ unique_lock<shared_mutex_impl> lock(g_instance_lock);
+ CHECK(g_interface);
+
+ delete g_interface;
+ g_interface = nullptr;
+}
+
+// static
+bool BluetoothAvrcpInterface::IsInitialized() {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+
+ return g_interface != nullptr;
+}
+
+// static
+BluetoothAvrcpInterface* BluetoothAvrcpInterface::Get() {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ CHECK(g_interface);
+ return g_interface;
+}
+
+// static
+void BluetoothAvrcpInterface::InitializeForTesting(
+ BluetoothAvrcpInterface* test_instance) {
+ unique_lock<shared_mutex_impl> lock(g_instance_lock);
+ CHECK(test_instance);
+ CHECK(!g_interface);
+
+ g_interface = test_instance;
+}
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/service/hal/bluetooth_avrcp_interface.h b/service/hal/bluetooth_avrcp_interface.h
new file mode 100644
index 0000000..08d6989
--- /dev/null
+++ b/service/hal/bluetooth_avrcp_interface.h
@@ -0,0 +1,179 @@
+//
+// Copyright (C) 2017 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>
+#include <hardware/bt_rc.h>
+
+namespace bluetooth {
+namespace hal {
+
+class BluetoothAvrcpInterface {
+ public:
+ // 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.
+ class TargetObserver {
+ public:
+ virtual ~TargetObserver() = default;
+
+ virtual void RemoteFeaturesCallback(const RawAddress& bd_addr,
+ btrc_remote_features_t features);
+ virtual void GetPlayStatusCallback(const RawAddress& bd_addr);
+ virtual void ListPlayerAppAttrCallback(const RawAddress& bd_addr);
+ virtual void ListPlayerAppValuesCallback(btrc_player_attr_t attr_id,
+ const RawAddress& bd_addr);
+ virtual void GetPlayerAppValueCallback(uint8_t num_attr,
+ btrc_player_attr_t* p_attrs,
+ const RawAddress& bd_addr);
+ virtual void GetPlayerAppAttrsTextCallback(uint8_t num_attr,
+ btrc_player_attr_t* p_attrs,
+ const RawAddress& bd_addr);
+ virtual void GetPlayerAppValuesTextCallback(uint8_t attr_id,
+ uint8_t num_val,
+ uint8_t* p_vals,
+ const RawAddress& bd_addr);
+ virtual void SetPlayerAppValueCallback(btrc_player_settings_t* p_vals,
+ const RawAddress& bd_addr);
+ virtual void GetElementAttrCallback(uint8_t num_attr,
+ btrc_media_attr_t* p_attrs,
+ const RawAddress& bd_addr);
+ virtual void RegisterNotificationCallback(btrc_event_id_t event_id,
+ uint32_t param,
+ const RawAddress& bd_addr);
+ virtual void VolumeChangeCallback(uint8_t volume, uint8_t ctype,
+ const RawAddress& bd_addr);
+ virtual void PassthroughCmdCallback(int id, int key_state,
+ const RawAddress& bd_addr);
+ virtual void SetAddressedPlayerCallback(uint16_t player_id,
+ const RawAddress& bd_addr);
+ virtual void SetBrowsedPlayerCallback(uint16_t player_id,
+ const RawAddress& bd_addr);
+ virtual void GetFolderItemsCallback(uint8_t scope, uint32_t start_item,
+ uint32_t end_item, uint8_t num_attr,
+ uint32_t* p_attr_ids,
+ const RawAddress& bd_addr);
+ virtual void ChangePathCallback(uint8_t direction, uint8_t* folder_uid,
+ const RawAddress& bd_addr);
+ virtual void GetItemAttrCallback(uint8_t scope, uint8_t* uid,
+ uint16_t uid_counter, uint8_t num_attr,
+ btrc_media_attr_t* p_attrs,
+ const RawAddress& bd_addr);
+ virtual void PlayItemCallback(uint8_t scope, uint16_t uid_counter,
+ uint8_t* uid, const RawAddress& bd_addr);
+ virtual void GetTotalNumOfItemsCallback(uint8_t scope,
+ const RawAddress& bd_addr);
+ virtual void SearchCallback(uint16_t str_len, uint8_t* p_str,
+ const RawAddress& bd_addr);
+ virtual void AddToNowPlayingCallback(uint8_t scope, uint8_t* uid,
+ uint16_t uid_counter,
+ const RawAddress& bd_addr);
+ };
+
+ class ControlObserver {
+ public:
+ virtual ~ControlObserver() = default;
+
+ virtual void PassthroughRspCallback(const RawAddress& bd_addr, int id,
+ int key_state);
+ virtual void GroupnavigationRspCallback(int id, int key_state);
+ virtual void ConnectionStateCallback(bool rc_connect, bool bt_connect,
+ const RawAddress& bd_addr);
+ virtual void CtrlGetrcfeaturesCallback(const RawAddress& bd_addr,
+ int features);
+ virtual void CtrlSetplayerapplicationsettingRspCallback(
+ const RawAddress& bd_addr, uint8_t accepted);
+ virtual void CtrlPlayerapplicationsettingCallback(
+ const RawAddress& bd_addr, uint8_t num_attr,
+ btrc_player_app_attr_t* app_attrs, uint8_t num_ext_attr,
+ btrc_player_app_ext_attr_t* ext_attrs);
+ virtual void CtrlPlayerapplicationsettingChangedCallback(
+ const RawAddress& bd_addr, const btrc_player_settings_t& p_vals);
+ virtual void CtrlSetabsvolCmdCallback(const RawAddress& bd_addr,
+ uint8_t abs_vol, uint8_t label);
+ virtual void CtrlRegisternotificationAbsVolCallback(
+ const RawAddress& bd_addr, uint8_t label);
+ virtual void CtrlTrackChangedCallback(const RawAddress& bd_addr,
+ uint8_t num_attr,
+ btrc_element_attr_val_t* p_attrs);
+ virtual void CtrlPlayPositionChangedCallback(const RawAddress& bd_addr,
+ uint32_t song_len,
+ uint32_t song_pos);
+ virtual void CtrlPlayStatusChangedCallback(const RawAddress& bd_addr,
+ btrc_play_status_t play_status);
+ virtual void CtrlGetFolderItemsCallback(
+ const RawAddress& bd_addr, btrc_status_t status,
+ const btrc_folder_items_t* folder_items, uint8_t count);
+ virtual void CtrlChangePathCallback(const RawAddress& bd_addr,
+ uint32_t count);
+ virtual void CtrlSetBrowsedPlayerCallback(const RawAddress& bd_addr,
+ uint8_t num_items, uint8_t depth);
+ virtual void CtrlSetAddressedPlayerCallback(const RawAddress& bd_addr,
+ uint8_t status);
+ };
+
+ // Initialize and clean up the BluetoothInterface singleton. Returns false if
+ // the underlying HAL interface failed to initialize, and true on success.
+ static bool Initialize();
+
+ // Shuts down and cleans up the interface. CleanUp must be called on the same
+ // thread that called Initialize.
+ static void CleanUp();
+
+ // Returns true if the interface was initialized and a global singleton has
+ // been created.
+ static bool IsInitialized();
+
+ // Initialize for testing. Use this to inject a test version of
+ // BluetoothAvrcpInterface. To be used from unit tests only.
+ static void InitializeForTesting(BluetoothAvrcpInterface* test_instance);
+
+ // Returns the BluetoothAvrcpInterface singleton. If the interface has
+ // not been initialized, returns nullptr. This method is thread-safe, in that
+ // it will block if the internal lock is being held by another thread. Don't
+ // call this re-entrantly from an observer event as this may cause a deadlock.
+ static BluetoothAvrcpInterface* Get();
+
+ virtual bool AvrcpControlEnable() = 0;
+ virtual void AvrcpControlDisable() = 0;
+ virtual bool AvrcpTargetEnable() = 0;
+ virtual void AvrcpTargetDisable() = 0;
+
+ // Thread-safety is guaranteed by ObserverList.
+ virtual void AddTargetObserver(TargetObserver* observer) = 0;
+ virtual void RemoveTargetObserver(TargetObserver* observer) = 0;
+
+ // Thread-safety is guaranteed by ObserverList.
+ virtual void AddControlObserver(ControlObserver* observer) = 0;
+ virtual void RemoveControlObserver(ControlObserver* observer) = 0;
+
+ // The HAL module pointers provided by the shared Bluetooth library
+ virtual const btrc_interface_t* GetTargetHALInterface() const = 0;
+ virtual const btrc_ctrl_interface_t* GetControlHALInterface() const = 0;
+
+ protected:
+ BluetoothAvrcpInterface() = default;
+ virtual ~BluetoothAvrcpInterface() = default;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BluetoothAvrcpInterface);
+};
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/service/hal/bluetooth_gatt_interface.cc b/service/hal/bluetooth_gatt_interface.cc
index 35b295b..d61a238 100644
--- a/service/hal/bluetooth_gatt_interface.cc
+++ b/service/hal/bluetooth_gatt_interface.cc
@@ -148,7 +148,7 @@
LOG(INFO) << __func__ << " - conn_id: " << conn_id << " - status: " << status
<< " - registered: " << registered << " - handle: " << handle;
FOR_EACH_CLIENT_OBSERVER(RegisterForNotificationCallback(
- g_interface, conn_id, status, registered, handle));
+ g_interface, conn_id, registered, status, handle));
}
void NotifyCallback(int conn_id, const btgatt_notify_params_t& p_data) {
@@ -594,7 +594,7 @@
void BluetoothGattInterface::ClientObserver::RegisterForNotificationCallback(
BluetoothGattInterface* /* gatt_iface */, int /* conn_id */,
- int /* status */, int /* registered */, uint16_t /* handle */) {
+ int /* registered */, int /* status */, uint16_t /* handle */) {
// Do nothing
}
diff --git a/service/hal/bluetooth_gatt_interface.h b/service/hal/bluetooth_gatt_interface.h
index 08b0e9b..ccd0ae9 100644
--- a/service/hal/bluetooth_gatt_interface.h
+++ b/service/hal/bluetooth_gatt_interface.h
@@ -81,8 +81,8 @@
int conn_id, int status);
virtual void RegisterForNotificationCallback(
- BluetoothGattInterface* gatt_iface, int conn_id, int status,
- int registered, uint16_t handle);
+ BluetoothGattInterface* gatt_iface, int conn_id, int registered,
+ int status, uint16_t handle);
virtual void NotifyCallback(BluetoothGattInterface* gatt_iface, int conn_id,
const btgatt_notify_params_t& p_data);
diff --git a/service/hal/bluetooth_interface.cc b/service/hal/bluetooth_interface.cc
index 9296966..a08fb7b 100644
--- a/service/hal/bluetooth_interface.cc
+++ b/service/hal/bluetooth_interface.cc
@@ -98,6 +98,13 @@
status, remote_bd_addr, num_properties, properties));
}
+void DeviceFoundCallback(int num_properties, bt_property_t* properties) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+ VLOG(1) << " Device found.";
+ FOR_EACH_BLUETOOTH_OBSERVER(DeviceFoundCallback(num_properties, properties));
+}
+
void DiscoveryStateChangedCallback(bt_discovery_state_t state) {
shared_lock<shared_mutex_impl> lock(g_instance_lock);
VERIFY_INTERFACE_OR_RETURN();
@@ -190,7 +197,7 @@
AdapterStateChangedCallback,
AdapterPropertiesCallback,
RemoteDevicePropertiesCallback,
- nullptr, /* device_found_cb */
+ DeviceFoundCallback,
DiscoveryStateChangedCallback,
PinRequestCallback,
SSPRequestCallback,
@@ -309,6 +316,11 @@
// Do nothing.
}
+void BluetoothInterface::Observer::DeviceFoundCallback(
+ int /* num_properties */, bt_property_t* /* properties */) {
+ // Do nothing.
+}
+
void BluetoothInterface::Observer::DiscoveryStateChangedCallback(
bt_discovery_state_t /* state */) {
// Do nothing.
diff --git a/service/hal/bluetooth_interface.h b/service/hal/bluetooth_interface.h
index 897835f..a1c8e62 100644
--- a/service/hal/bluetooth_interface.h
+++ b/service/hal/bluetooth_interface.h
@@ -57,6 +57,8 @@
RawAddress* remote_bd_addr,
int num_properties,
bt_property_t* properties);
+ virtual void DeviceFoundCallback(int num_properties,
+ bt_property_t* properties);
virtual void DiscoveryStateChangedCallback(bt_discovery_state_t state);
virtual void PinRequestCallback(RawAddress* remote_bd_addr,
bt_bdname_t* bd_name, uint32_t cod,
diff --git a/service/hal/fake_bluetooth_av_interface.cc b/service/hal/fake_bluetooth_av_interface.cc
new file mode 100644
index 0000000..39a6331
--- /dev/null
+++ b/service/hal/fake_bluetooth_av_interface.cc
@@ -0,0 +1,151 @@
+//
+// Copyright 2017 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_av_interface.h"
+
+namespace bluetooth {
+namespace hal {
+namespace {
+
+// The global test handler instances. We have to have globals since the HAL
+// interface methods all have to be global and their signatures don't allow us
+// to pass in user_data.
+std::shared_ptr<FakeBluetoothAvInterface::TestA2dpSinkHandler>
+ g_a2dp_sink_handler;
+
+bt_status_t FakeInit(btav_sink_callbacks_t* callbacks) {
+ return BT_STATUS_SUCCESS;
+}
+
+bt_status_t FakeConnect(const RawAddress& bd_addr) {
+ if (g_a2dp_sink_handler) return g_a2dp_sink_handler->Connect(bd_addr);
+ return BT_STATUS_FAIL;
+}
+
+bt_status_t FakeDisconnect(const RawAddress& bd_addr) {
+ if (g_a2dp_sink_handler) return g_a2dp_sink_handler->Disconnect(bd_addr);
+ return BT_STATUS_FAIL;
+}
+
+void FakeCleanup(void) {}
+
+void FakeSetAudioFocusState(int focus_state) {
+ if (g_a2dp_sink_handler)
+ return g_a2dp_sink_handler->SetAudioFocusState(focus_state);
+}
+
+void FakeSetAudioTrackGain(float gain) {
+ if (g_a2dp_sink_handler) return g_a2dp_sink_handler->SetAudioTrackGain(gain);
+}
+
+btav_source_interface_t fake_a2dp_source_interface = {
+ .size = sizeof(btav_source_interface_t),
+ .init = nullptr,
+ .connect = nullptr,
+ .disconnect = nullptr,
+ .config_codec = nullptr,
+ .cleanup = nullptr,
+};
+
+btav_sink_interface_t fake_a2dp_sink_interface = {
+ .size = sizeof(btav_sink_interface_t),
+ .init = FakeInit,
+ .connect = FakeConnect,
+ .disconnect = FakeDisconnect,
+ .cleanup = FakeCleanup,
+ .set_audio_focus_state = FakeSetAudioFocusState,
+ .set_audio_track_gain = FakeSetAudioTrackGain,
+};
+
+} // namespace
+
+FakeBluetoothAvInterface::FakeBluetoothAvInterface(
+ std::shared_ptr<TestA2dpSinkHandler> a2dp_sink_handler) {
+ CHECK(!g_a2dp_sink_handler);
+
+ if (a2dp_sink_handler) g_a2dp_sink_handler = a2dp_sink_handler;
+}
+
+FakeBluetoothAvInterface::~FakeBluetoothAvInterface() {
+ g_a2dp_sink_handler = nullptr;
+}
+
+void FakeBluetoothAvInterface::NotifyConnectionState(
+ const RawAddress& bda, btav_connection_state_t state) {
+ for (auto& observer : a2dp_sink_observers_) {
+ observer.ConnectionStateCallback(this, bda, state);
+ }
+}
+void FakeBluetoothAvInterface::NotifyAudioState(const RawAddress& bda,
+ btav_audio_state_t state) {
+ for (auto& observer : a2dp_sink_observers_) {
+ observer.AudioStateCallback(this, bda, state);
+ }
+}
+void FakeBluetoothAvInterface::NotifyAudioConfig(const RawAddress& bda,
+ uint32_t sample_rate,
+ uint8_t channel_count) {
+ for (auto& observer : a2dp_sink_observers_) {
+ observer.AudioConfigCallback(this, bda, sample_rate, channel_count);
+ }
+}
+
+bool FakeBluetoothAvInterface::A2dpSourceEnable(
+ std::vector<btav_a2dp_codec_config_t> codec_priorities) {
+ return true;
+}
+
+void FakeBluetoothAvInterface::A2dpSourceDisable() {}
+
+bool FakeBluetoothAvInterface::A2dpSinkEnable() { return true; }
+
+void FakeBluetoothAvInterface::A2dpSinkDisable() {}
+
+void FakeBluetoothAvInterface::AddA2dpSourceObserver(
+ A2dpSourceObserver* observer) {
+ CHECK(observer);
+ a2dp_source_observers_.AddObserver(observer);
+}
+
+void FakeBluetoothAvInterface::RemoveA2dpSourceObserver(
+ A2dpSourceObserver* observer) {
+ CHECK(observer);
+ a2dp_source_observers_.RemoveObserver(observer);
+}
+
+void FakeBluetoothAvInterface::AddA2dpSinkObserver(A2dpSinkObserver* observer) {
+ CHECK(observer);
+ a2dp_sink_observers_.AddObserver(observer);
+}
+
+void FakeBluetoothAvInterface::RemoveA2dpSinkObserver(
+ A2dpSinkObserver* observer) {
+ CHECK(observer);
+ a2dp_sink_observers_.RemoveObserver(observer);
+}
+
+const btav_source_interface_t*
+FakeBluetoothAvInterface::GetA2dpSourceHALInterface() {
+ return &fake_a2dp_source_interface;
+}
+
+const btav_sink_interface_t*
+FakeBluetoothAvInterface::GetA2dpSinkHALInterface() {
+ return &fake_a2dp_sink_interface;
+}
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/service/hal/fake_bluetooth_av_interface.h b/service/hal/fake_bluetooth_av_interface.h
new file mode 100644
index 0000000..c979434
--- /dev/null
+++ b/service/hal/fake_bluetooth_av_interface.h
@@ -0,0 +1,82 @@
+//
+// Copyright (C) 2017 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/observer_list.h>
+
+#include "service/hal/bluetooth_av_interface.h"
+
+namespace bluetooth {
+namespace hal {
+
+class FakeBluetoothAvInterface : public BluetoothAvInterface {
+ public:
+ // Handles HAL Bluetooth A2DP sink API calls for testing. Test code can
+ // provide a fake or mock implementation of this and all calls will be routed
+ // to it.
+ class TestA2dpSinkHandler {
+ public:
+ virtual bt_status_t Connect(RawAddress bda) = 0;
+ virtual bt_status_t Disconnect(RawAddress bda) = 0;
+ virtual void SetAudioFocusState(int focus_state) = 0;
+ virtual void SetAudioTrackGain(float gain) = 0;
+
+ protected:
+ virtual ~TestA2dpSinkHandler() = default;
+ };
+
+ // Constructs the fake with the given handlers. Implementations can
+ // provide their own handlers or simply pass "nullptr" for the default
+ // behavior in which BT_STATUS_FAIL will be returned from all calls.
+ FakeBluetoothAvInterface(
+ std::shared_ptr<TestA2dpSinkHandler> a2dp_sink_handler);
+ ~FakeBluetoothAvInterface();
+
+ // The methods below can be used to notify observers with certain events and
+ // given parameters.
+
+ // A2DP sink callbacks
+ void NotifyConnectionState(const RawAddress& bda,
+ btav_connection_state_t state);
+ void NotifyAudioState(const RawAddress& bda, btav_audio_state_t state);
+ void NotifyAudioConfig(const RawAddress& bda, uint32_t sample_rate,
+ uint8_t channel_count);
+
+ // BluetoothAvInterface overrides:
+ bool A2dpSourceEnable(
+ std::vector<btav_a2dp_codec_config_t> codec_priorities) override;
+ void A2dpSourceDisable() override;
+ bool A2dpSinkEnable() override;
+ void A2dpSinkDisable() override;
+ void AddA2dpSourceObserver(A2dpSourceObserver* observer) override;
+ void RemoveA2dpSourceObserver(A2dpSourceObserver* observer) override;
+ void AddA2dpSinkObserver(A2dpSinkObserver* observer) override;
+ void RemoveA2dpSinkObserver(A2dpSinkObserver* observer) override;
+ const btav_source_interface_t* GetA2dpSourceHALInterface() override;
+ const btav_sink_interface_t* GetA2dpSinkHALInterface() override;
+
+ private:
+ base::ObserverList<A2dpSourceObserver> a2dp_source_observers_;
+ base::ObserverList<A2dpSinkObserver> a2dp_sink_observers_;
+ std::shared_ptr<TestA2dpSinkHandler> scanner_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeBluetoothAvInterface);
+};
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/service/hal/fake_bluetooth_interface.cc b/service/hal/fake_bluetooth_interface.cc
index eb550e7..7979155 100644
--- a/service/hal/fake_bluetooth_interface.cc
+++ b/service/hal/fake_bluetooth_interface.cc
@@ -74,6 +74,7 @@
nullptr, /* interop_database_clear */
nullptr, /* interop_database_add */
nullptr, /* get_avrcp_service */
+ nullptr, /* obfuscate_address */
};
} // namespace
diff --git a/service/ipc/binder/bluetooth_a2dp_sink_binder_server.cc b/service/ipc/binder/bluetooth_a2dp_sink_binder_server.cc
new file mode 100644
index 0000000..1609aa8
--- /dev/null
+++ b/service/ipc/binder/bluetooth_a2dp_sink_binder_server.cc
@@ -0,0 +1,222 @@
+//
+// Copyright 2017 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_a2dp_sink_binder_server.h"
+
+#include <base/logging.h>
+
+#include "service/adapter.h"
+
+using android::String16;
+using android::String8;
+using android::binder::Status;
+
+using android::bluetooth::IBluetoothA2dpSinkCallback;
+
+namespace ipc {
+namespace binder {
+
+BluetoothA2dpSinkBinderServer::BluetoothA2dpSinkBinderServer(
+ bluetooth::Adapter* adapter)
+ : adapter_(adapter) {
+ CHECK(adapter);
+}
+
+Status BluetoothA2dpSinkBinderServer::Register(
+ const android::sp<IBluetoothA2dpSinkCallback>& callback,
+ bool* _aidl_return) {
+ auto factory = adapter_->GetA2dpSinkFactory();
+ *_aidl_return = RegisterInstanceBase(callback, factory);
+ return Status::ok();
+}
+
+Status BluetoothA2dpSinkBinderServer::Unregister() {
+ UnregisterAllBase();
+ return Status::ok();
+}
+
+Status BluetoothA2dpSinkBinderServer::Enable(bool* _aidl_return) {
+ std::lock_guard<std::mutex> lock(*maps_lock());
+ auto a2dp_sink = GetA2dpSink();
+ if (!a2dp_sink) {
+ LOG(ERROR) << "Failed to get A2DP sink instance";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ if (!a2dp_sink->Enable()) {
+ LOG(ERROR) << "Failed to enable";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ *_aidl_return = true;
+ return Status::ok();
+}
+
+Status BluetoothA2dpSinkBinderServer::Disable(bool* _aidl_return) {
+ std::lock_guard<std::mutex> lock(*maps_lock());
+ auto a2dp_sink = GetA2dpSink();
+ if (!a2dp_sink) {
+ LOG(ERROR) << "Failed to get A2DP sink instance";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ a2dp_sink->Disable();
+ *_aidl_return = true;
+ return Status::ok();
+}
+
+Status BluetoothA2dpSinkBinderServer::Connect(const String16& device_address,
+ bool* _aidl_return) {
+ std::lock_guard<std::mutex> lock(*maps_lock());
+ auto a2dp_sink = GetA2dpSink();
+ if (!a2dp_sink) {
+ LOG(ERROR) << "Failed to get A2DP sink instance";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ if (!a2dp_sink->Connect(String8(device_address).string())) {
+ LOG(ERROR) << "Failed to connect";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ *_aidl_return = true;
+ return Status::ok();
+}
+
+Status BluetoothA2dpSinkBinderServer::Disconnect(const String16& device_address,
+ bool* _aidl_return) {
+ std::lock_guard<std::mutex> lock(*maps_lock());
+ auto a2dp_sink = GetA2dpSink();
+ if (!a2dp_sink) {
+ LOG(ERROR) << "Failed to get A2DP sink instance";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ if (!a2dp_sink->Disconnect(String8(device_address).string())) {
+ LOG(ERROR) << "Failed to connect";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ *_aidl_return = true;
+ return Status::ok();
+}
+
+Status BluetoothA2dpSinkBinderServer::SetAudioFocusState(int focus_state,
+ bool* _aidl_return) {
+ std::lock_guard<std::mutex> lock(*maps_lock());
+ auto a2dp_sink = GetA2dpSink();
+ if (!a2dp_sink) {
+ LOG(ERROR) << "Failed to get A2DP instance";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ a2dp_sink->SetAudioFocusState(focus_state);
+ *_aidl_return = true;
+ return Status::ok();
+}
+
+Status BluetoothA2dpSinkBinderServer::SetAudioTrackGain(float gain,
+ bool* _aidl_return) {
+ std::lock_guard<std::mutex> lock(*maps_lock());
+ auto a2dp_sink = GetA2dpSink();
+ if (!a2dp_sink) {
+ LOG(ERROR) << "Failed to get A2DP instance";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ a2dp_sink->SetAudioTrackGain(gain);
+ *_aidl_return = true;
+ return Status::ok();
+}
+
+void BluetoothA2dpSinkBinderServer::OnConnectionState(
+ const std::string& device_address, int state) {
+ std::lock_guard<std::mutex> lock(*maps_lock());
+ auto cb = GetA2dpSinkCallback();
+ if (!cb.get()) {
+ LOG(WARNING) << "Callback for this GattServer was deleted.";
+ return;
+ }
+
+ cb->OnConnectionState(String16(device_address.c_str()), state);
+}
+
+void BluetoothA2dpSinkBinderServer::OnAudioState(
+ const std::string& device_address, int state) {
+ std::lock_guard<std::mutex> lock(*maps_lock());
+ auto cb = GetA2dpSinkCallback();
+ if (!cb.get()) {
+ LOG(WARNING) << "Callback for this GattServer was deleted.";
+ return;
+ }
+
+ cb->OnAudioState(String16(device_address.c_str()), state);
+}
+
+void BluetoothA2dpSinkBinderServer::OnAudioConfig(
+ const std::string& device_address, uint32_t sample_rate,
+ uint8_t channel_count) {
+ std::lock_guard<std::mutex> lock(*maps_lock());
+ auto cb = GetA2dpSinkCallback();
+ if (!cb.get()) {
+ LOG(WARNING) << "Callback for this GattServer was deleted.";
+ return;
+ }
+
+ cb->OnAudioConfig(String16(device_address.c_str()), sample_rate,
+ channel_count);
+}
+
+bool BluetoothA2dpSinkBinderServer::HasInstance() {
+ return GetA2dpSink() != nullptr;
+}
+
+android::sp<IBluetoothA2dpSinkCallback>
+BluetoothA2dpSinkBinderServer::GetA2dpSinkCallback() {
+ auto cb = GetCallback(bluetooth::A2dpSink::kSingletonInstanceId);
+ return android::sp<IBluetoothA2dpSinkCallback>(
+ static_cast<IBluetoothA2dpSinkCallback*>(cb.get()));
+}
+
+std::shared_ptr<bluetooth::A2dpSink>
+BluetoothA2dpSinkBinderServer::GetA2dpSink() {
+ return std::static_pointer_cast<bluetooth::A2dpSink>(
+ GetInstance(bluetooth::A2dpSink::kSingletonInstanceId));
+}
+
+void BluetoothA2dpSinkBinderServer::OnRegisterInstanceImpl(
+ bluetooth::BLEStatus status, android::sp<IInterface> callback,
+ bluetooth::BluetoothInstance* instance) {
+ VLOG(1) << __func__ << " instance ID: " << instance->GetInstanceId()
+ << " status: " << status;
+ bluetooth::A2dpSink* a2dp_sink = static_cast<bluetooth::A2dpSink*>(instance);
+ a2dp_sink->SetDelegate(this);
+
+ android::sp<IBluetoothA2dpSinkCallback> cb(
+ static_cast<IBluetoothA2dpSinkCallback*>(callback.get()));
+ cb->OnRegistered(status);
+}
+
+} // namespace binder
+} // namespace ipc
diff --git a/service/ipc/binder/bluetooth_a2dp_sink_binder_server.h b/service/ipc/binder/bluetooth_a2dp_sink_binder_server.h
new file mode 100644
index 0000000..e18af54
--- /dev/null
+++ b/service/ipc/binder/bluetooth_a2dp_sink_binder_server.h
@@ -0,0 +1,86 @@
+//
+// Copyright (C) 2017 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 <map>
+#include <string>
+
+#include <base/macros.h>
+
+#include <android/bluetooth/BnBluetoothA2dpSink.h>
+#include <android/bluetooth/IBluetoothA2dpSinkCallback.h>
+
+#include "service/a2dp_sink.h"
+#include "service/ipc/binder/interface_with_instances_base.h"
+
+namespace bluetooth {
+class Adapter;
+} // namespace bluetooth
+
+namespace ipc {
+namespace binder {
+
+class BluetoothA2dpSinkBinderServer
+ : public InterfaceWithInstancesBase,
+ public android::bluetooth::BnBluetoothA2dpSink,
+ public bluetooth::A2dpSink::Delegate {
+ public:
+ explicit BluetoothA2dpSinkBinderServer(bluetooth::Adapter* adapter);
+ ~BluetoothA2dpSinkBinderServer() override = default;
+
+ // IBluetoothA2dpSink implementation:
+ android::binder::Status Register(
+ const android::sp<android::bluetooth::IBluetoothA2dpSinkCallback>&
+ callback,
+ bool* _aidl_return) override;
+ android::binder::Status Enable(bool* _aidl_return) override;
+ android::binder::Status Disable(bool* _aidl_return) override;
+ android::binder::Status Unregister() override;
+ android::binder::Status Connect(const android::String16& device_address,
+ bool* _aidl_return) override;
+ android::binder::Status Disconnect(const android::String16& device_address,
+ bool* _aidl_return) override;
+ android::binder::Status SetAudioFocusState(int state,
+ bool* _aidl_return) override;
+ android::binder::Status SetAudioTrackGain(float gain,
+ bool* _aidl_return) override;
+
+ // bluetooth::bluetooth::A2dpSink::Delegate implementation:
+ void OnConnectionState(const std::string& device_address, int state) override;
+ void OnAudioState(const std::string& device_address, int state) override;
+ void OnAudioConfig(const std::string& device_address, uint32_t sample_rate,
+ uint8_t channel_count) override;
+
+ bool HasInstance();
+
+ private:
+ android::sp<android::bluetooth::IBluetoothA2dpSinkCallback>
+ GetA2dpSinkCallback();
+ std::shared_ptr<bluetooth::A2dpSink> GetA2dpSink();
+
+ // InterfaceWithInstancesBase override:
+ void OnRegisterInstanceImpl(bluetooth::BLEStatus status,
+ android::sp<IInterface> callback,
+ bluetooth::BluetoothInstance* instance) override;
+
+ bluetooth::Adapter* adapter_; // weak
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothA2dpSinkBinderServer);
+};
+
+} // namespace binder
+} // namespace ipc
diff --git a/service/ipc/binder/bluetooth_a2dp_source_binder_server.cc b/service/ipc/binder/bluetooth_a2dp_source_binder_server.cc
new file mode 100644
index 0000000..51e6dff
--- /dev/null
+++ b/service/ipc/binder/bluetooth_a2dp_source_binder_server.cc
@@ -0,0 +1,226 @@
+//
+// Copyright (C) 2017 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_a2dp_source_binder_server.h"
+
+#include <base/logging.h>
+
+#include "service/adapter.h"
+
+#define AIDL_RET(value) \
+ do { \
+ *_aidl_return = (value); \
+ return Status::ok(); \
+ } while (0)
+
+#define TRY_GET_SOURCE() \
+ ({ \
+ auto source = GetA2dpSource(); \
+ if (!source) { \
+ LOG(ERROR) << __func__ << ": " \
+ << "Failed to get A2DP source interface"; \
+ AIDL_RET(false); \
+ } \
+ source; \
+ })
+
+#define TRY_GET_CB() \
+ ({ \
+ auto cb = GetA2dpSourceCallback(); \
+ if (!cb.get()) { \
+ LOG(WARNING) << "Callback for A2DP SOURCE was deleted"; \
+ return; \
+ } \
+ cb; \
+ })
+
+#define TRY_RET(expr, msg) \
+ do { \
+ if (!(expr)) { \
+ LOG(ERROR) << msg; \
+ AIDL_RET(false); \
+ } \
+ AIDL_RET(true); \
+ } while (0)
+
+#define TRY_RET_FUNC(expr) TRY_RET(expr, __func__ << " failed")
+
+using android::String16;
+using android::String8;
+using android::binder::Status;
+using android::bluetooth::BluetoothA2dpCodecConfig;
+using android::bluetooth::IBluetoothA2dpSourceCallback;
+
+using LockGuard = std::lock_guard<std::mutex>;
+
+namespace ipc {
+namespace binder {
+
+namespace {
+
+std::vector<bluetooth::A2dpCodecConfig> A2dpCodecsFromBinder(
+ const std::vector<BluetoothA2dpCodecConfig>& codecs) {
+ std::vector<bluetooth::A2dpCodecConfig> ret;
+ ret.reserve(codecs.size());
+ for (const auto& config : codecs) {
+ ret.push_back(config);
+ }
+
+ return ret;
+}
+
+std::vector<BluetoothA2dpCodecConfig> A2dpCodecsToBinder(
+ const std::vector<bluetooth::A2dpCodecConfig>& codecs) {
+ std::vector<BluetoothA2dpCodecConfig> ret;
+ ret.reserve(codecs.size());
+ for (const auto& config : codecs) {
+ ret.push_back(config);
+ }
+
+ return ret;
+}
+
+} // namespace
+
+BluetoothA2dpSourceBinderServer::BluetoothA2dpSourceBinderServer(
+ bluetooth::Adapter* adapter)
+ : adapter_(adapter) {
+ CHECK(adapter);
+}
+
+BluetoothA2dpSourceBinderServer::~BluetoothA2dpSourceBinderServer() = default;
+
+bool BluetoothA2dpSourceBinderServer::HasInstance() {
+ return GetA2dpSource() != nullptr;
+}
+
+Status BluetoothA2dpSourceBinderServer::Register(
+ const android::sp<IBluetoothA2dpSourceCallback>& callback,
+ bool* _aidl_return) {
+ auto factory = adapter_->GetA2dpSourceFactory();
+ *_aidl_return = RegisterInstanceBase(callback, factory);
+ return Status::ok();
+}
+
+Status BluetoothA2dpSourceBinderServer::Unregister() {
+ UnregisterAllBase();
+ return Status::ok();
+}
+
+Status BluetoothA2dpSourceBinderServer::Enable(
+ const std::vector<android::bluetooth::BluetoothA2dpCodecConfig>&
+ codec_priorities,
+ bool* _aidl_return) {
+ auto codec_priorities_non_binder = A2dpCodecsFromBinder(codec_priorities);
+
+ LockGuard lock(*maps_lock());
+ auto a2dp_source = TRY_GET_SOURCE();
+ TRY_RET_FUNC(a2dp_source->Enable(codec_priorities_non_binder));
+}
+
+Status BluetoothA2dpSourceBinderServer::Disable(bool* _aidl_return) {
+ LockGuard lock(*maps_lock());
+ auto a2dp_source = TRY_GET_SOURCE();
+ a2dp_source->Disable();
+ AIDL_RET(true);
+}
+
+Status BluetoothA2dpSourceBinderServer::Connect(const String16& device_address,
+ bool* _aidl_return) {
+ LockGuard lock(*maps_lock());
+ auto a2dp_source = TRY_GET_SOURCE();
+ TRY_RET_FUNC(a2dp_source->Connect(String8(device_address).string()));
+}
+
+Status BluetoothA2dpSourceBinderServer::Disconnect(
+ const String16& device_address, bool* _aidl_return) {
+ LockGuard lock(*maps_lock());
+ auto a2dp_source = TRY_GET_SOURCE();
+ TRY_RET_FUNC(a2dp_source->Disconnect(String8(device_address).string()));
+}
+
+Status BluetoothA2dpSourceBinderServer::ConfigCodec(
+ const android::String16& device_address,
+ const std::vector<android::bluetooth::BluetoothA2dpCodecConfig>&
+ codec_preferences,
+ bool* _aidl_return) {
+ auto codec_preferences_non_binder = A2dpCodecsFromBinder(codec_preferences);
+
+ LockGuard lock(*maps_lock());
+ auto a2dp_source = TRY_GET_SOURCE();
+ TRY_RET_FUNC(a2dp_source->ConfigCodec(String8(device_address).string(),
+ codec_preferences_non_binder));
+}
+
+void BluetoothA2dpSourceBinderServer::OnConnectionState(
+ const std::string& device_address, int state) {
+ LockGuard lock(*maps_lock());
+ auto cb = TRY_GET_CB();
+ cb->OnConnectionState(String16(device_address.c_str()), state);
+}
+
+void BluetoothA2dpSourceBinderServer::OnAudioState(
+ const std::string& device_address, int state) {
+ LockGuard lock(*maps_lock());
+ auto cb = TRY_GET_CB();
+ cb->OnAudioState(String16(device_address.c_str()), state);
+}
+
+void BluetoothA2dpSourceBinderServer::OnAudioConfig(
+ const std::string& device_address, bluetooth::A2dpCodecConfig codec_config,
+ const std::vector<bluetooth::A2dpCodecConfig>& codecs_local_capabilities,
+ const std::vector<bluetooth::A2dpCodecConfig>&
+ codecs_selectable_capabilities) {
+ auto binder_codecs_local_capabilities =
+ A2dpCodecsToBinder(codecs_local_capabilities);
+ auto binder_codecs_selectable_capabilities =
+ A2dpCodecsToBinder(codecs_selectable_capabilities);
+
+ LockGuard lock(*maps_lock());
+ auto cb = TRY_GET_CB();
+ cb->OnAudioConfig(String16(device_address.c_str()), codec_config,
+ binder_codecs_local_capabilities,
+ binder_codecs_selectable_capabilities);
+}
+
+android::sp<IBluetoothA2dpSourceCallback>
+BluetoothA2dpSourceBinderServer::GetA2dpSourceCallback() {
+ auto cb = GetCallback(bluetooth::A2dpSource::kSingletonInstanceId);
+ return android::sp<IBluetoothA2dpSourceCallback>(
+ static_cast<IBluetoothA2dpSourceCallback*>(cb.get()));
+}
+
+std::shared_ptr<bluetooth::A2dpSource>
+BluetoothA2dpSourceBinderServer::GetA2dpSource() {
+ return std::static_pointer_cast<bluetooth::A2dpSource>(
+ GetInstance(bluetooth::A2dpSource::kSingletonInstanceId));
+}
+
+void BluetoothA2dpSourceBinderServer::OnRegisterInstanceImpl(
+ bluetooth::BLEStatus status, android::sp<IInterface> callback,
+ bluetooth::BluetoothInstance* instance) {
+ VLOG(1) << __func__ << " instance ID: " << instance->GetInstanceId()
+ << " status: " << status;
+ bluetooth::A2dpSource* a2dp_source =
+ static_cast<bluetooth::A2dpSource*>(instance);
+ a2dp_source->SetDelegate(this);
+
+ android::sp<IBluetoothA2dpSourceCallback> cb(
+ static_cast<IBluetoothA2dpSourceCallback*>(callback.get()));
+ cb->OnRegistered(status);
+}
+
+} // namespace binder
+} // namespace ipc
diff --git a/service/ipc/binder/bluetooth_a2dp_source_binder_server.h b/service/ipc/binder/bluetooth_a2dp_source_binder_server.h
new file mode 100644
index 0000000..160a38a
--- /dev/null
+++ b/service/ipc/binder/bluetooth_a2dp_source_binder_server.h
@@ -0,0 +1,95 @@
+//
+// Copyright (C) 2017 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 <map>
+#include <string>
+#include <vector>
+
+#include <base/macros.h>
+
+#include <android/bluetooth/BnBluetoothA2dpSource.h>
+#include <android/bluetooth/IBluetoothA2dpSourceCallback.h>
+
+#include "service/a2dp_source.h"
+#include "service/ipc/binder/interface_with_instances_base.h"
+
+namespace bluetooth {
+class Adapter;
+} // namespace bluetooth
+
+namespace ipc {
+namespace binder {
+
+class BluetoothA2dpSourceBinderServer
+ : public InterfaceWithInstancesBase,
+ public android::bluetooth::BnBluetoothA2dpSource,
+ public bluetooth::A2dpSource::Delegate {
+ public:
+ explicit BluetoothA2dpSourceBinderServer(bluetooth::Adapter* adapter);
+ ~BluetoothA2dpSourceBinderServer() override;
+
+ bool HasInstance();
+
+ // IBluetoothA2dpSource implementation:
+ android::binder::Status Register(
+ const android::sp<android::bluetooth::IBluetoothA2dpSourceCallback>&
+ callback,
+ bool* _aidl_return) override;
+ android::binder::Status Unregister() override;
+ android::binder::Status Enable(
+ const std::vector<android::bluetooth::BluetoothA2dpCodecConfig>&
+ codec_priorities,
+ bool* _aidl_return) override;
+ android::binder::Status Disable(bool* _aidl_return) override;
+ android::binder::Status Connect(const android::String16& device_address,
+ bool* _aidl_return) override;
+ android::binder::Status Disconnect(const android::String16& device_address,
+ bool* _aidl_return) override;
+ android::binder::Status ConfigCodec(
+ const android::String16& device_address,
+ const std::vector<android::bluetooth::BluetoothA2dpCodecConfig>&
+ codec_preferences,
+ bool* _aidl_return) override;
+
+ private:
+ // bluetooth::bluetooth::A2dpSource::Delegate implementation:
+ void OnConnectionState(const std::string& device_address, int state) override;
+ void OnAudioState(const std::string& device_address, int state) override;
+ void OnAudioConfig(
+ const std::string& device_address,
+ bluetooth::A2dpCodecConfig codec_config,
+ const std::vector<bluetooth::A2dpCodecConfig>& codecs_local_capabilities,
+ const std::vector<bluetooth::A2dpCodecConfig>&
+ codecs_selectable_capabilities) override;
+
+ android::sp<android::bluetooth::IBluetoothA2dpSourceCallback>
+ GetA2dpSourceCallback();
+ std::shared_ptr<bluetooth::A2dpSource> GetA2dpSource();
+
+ // InterfaceWithInstancesBase override:
+ void OnRegisterInstanceImpl(bluetooth::BLEStatus status,
+ android::sp<IInterface> callback,
+ bluetooth::BluetoothInstance* instance) override;
+
+ bluetooth::Adapter* const adapter_; // weak
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothA2dpSourceBinderServer);
+};
+
+} // namespace binder
+} // namespace ipc
diff --git a/service/ipc/binder/bluetooth_avrcp_control_binder_server.cc b/service/ipc/binder/bluetooth_avrcp_control_binder_server.cc
new file mode 100644
index 0000000..d816859
--- /dev/null
+++ b/service/ipc/binder/bluetooth_avrcp_control_binder_server.cc
@@ -0,0 +1,236 @@
+//
+// Copyright 2017 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_avrcp_control_binder_server.h"
+
+#include <string>
+
+#include "base/logging.h"
+
+#include "service/adapter.h"
+
+using android::String16;
+using android::String8;
+using android::binder::Status;
+using android::bluetooth::IBluetoothAvrcpControlCallback;
+
+namespace ipc {
+namespace binder {
+
+namespace {
+const int kInvalidInstanceId = -1;
+} // namespace
+
+BluetoothAvrcpControlBinderServer::BluetoothAvrcpControlBinderServer(
+ bluetooth::Adapter* adapter)
+ : adapter_(adapter) {
+ CHECK(adapter_);
+}
+
+Status BluetoothAvrcpControlBinderServer::Register(
+ const android::sp<IBluetoothAvrcpControlCallback>& callback,
+ bool* _aidl_return) {
+ VLOG(2) << __func__;
+
+ bluetooth::AvrcpControlFactory* gatt_client_factory =
+ adapter_->GetAvrcpControlFactory();
+
+ *_aidl_return = RegisterInstanceBase(callback, gatt_client_factory);
+ return Status::ok();
+}
+
+Status BluetoothAvrcpControlBinderServer::Unregister(int32_t id) {
+ VLOG(2) << __func__;
+ UnregisterInstanceBase(id);
+ return Status::ok();
+}
+
+Status BluetoothAvrcpControlBinderServer::UnregisterAll() {
+ VLOG(2) << __func__;
+ UnregisterAllBase();
+ return Status::ok();
+}
+
+Status BluetoothAvrcpControlBinderServer::Enable(int32_t id,
+ bool* _aidl_return) {
+ std::lock_guard<std::mutex> lock(*maps_lock());
+ auto avrcp_control = GetAvrcpControl(id);
+ if (!avrcp_control) {
+ LOG(ERROR) << "Failed to get avrcp control instance";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ if (!avrcp_control->Enable()) {
+ LOG(ERROR) << "Failed to enable";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ *_aidl_return = true;
+ return Status::ok();
+}
+
+Status BluetoothAvrcpControlBinderServer::Disable(int32_t id,
+ bool* _aidl_return) {
+ std::lock_guard<std::mutex> lock(*maps_lock());
+ auto avrcp_control = GetAvrcpControl(id);
+ if (!avrcp_control) {
+ LOG(ERROR) << "Failed to get avrcp control instance";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ avrcp_control->Disable();
+ *_aidl_return = true;
+ return Status::ok();
+}
+
+Status BluetoothAvrcpControlBinderServer::SendPassThroughCommand(
+ int32_t id, const String16& device_address, int32_t key_code,
+ bool key_pressed, bool* _aidl_return) {
+ std::lock_guard<std::mutex> lock(*maps_lock());
+ auto avrcp_control = GetAvrcpControl(id);
+ if (!avrcp_control) {
+ LOG(ERROR) << "Failed to get avrcp control instance";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ if (!avrcp_control->SendPassThroughCommand(String8(device_address).string(),
+ key_code, key_pressed)) {
+ LOG(ERROR) << "Failed to send pass through command";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ *_aidl_return = true;
+ return Status::ok();
+}
+
+android::binder::Status BluetoothAvrcpControlBinderServer::SetAbsVolumeResponse(
+ int32_t id, const android::String16& device_address, int32_t abs_vol,
+ int32_t label, bool* _aidl_return) {
+ std::lock_guard<std::mutex> lock(*maps_lock());
+ auto avrcp_control = GetAvrcpControl(id);
+ if (!avrcp_control) {
+ LOG(ERROR) << "Failed to get avrcp control instance";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ if (!avrcp_control->SetAbsVolumeResponse(String8(device_address).string(),
+ abs_vol, label)) {
+ LOG(ERROR) << "Failed to send set absolute volume response";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+ *_aidl_return = true;
+ return Status::ok();
+}
+
+android::binder::Status
+BluetoothAvrcpControlBinderServer::RegisterForAbsVolumeCallbackResponse(
+ int32_t id, const android::String16& device_address, int32_t response_type,
+ int32_t abs_vol, int32_t label, bool* _aidl_return) {
+ std::lock_guard<std::mutex> lock(*maps_lock());
+ auto avrcp_control = GetAvrcpControl(id);
+ if (!avrcp_control) {
+ LOG(ERROR) << "Failed to get avrcp control instance";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ if (!avrcp_control->RegisterForAbsVolumeCallbackResponse(
+ String8(device_address).string(), response_type, abs_vol, label)) {
+ LOG(ERROR)
+ << "Failed to send register for absolute volume callback response";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+ *_aidl_return = true;
+ return Status::ok();
+}
+
+void BluetoothAvrcpControlBinderServer::OnConnectionState(
+ bool rc_connect, bool bt_connect, const std::string& device_address) {
+ auto func = [rc_connect, bt_connect, &device_address](IInterface* cb) {
+ auto avrcp_control_cb = static_cast<IBluetoothAvrcpControlCallback*>(cb);
+ avrcp_control_cb->OnConnectionState(rc_connect, bt_connect,
+ String16(device_address.c_str()));
+ };
+
+ ForEachCallback(func);
+}
+
+void BluetoothAvrcpControlBinderServer::OnTrackChanged(
+ const std::string& device_address, const bluetooth::AvrcpMediaAttr& attr) {
+ auto binder_attr = android::bluetooth::BluetoothAvrcpMediaAttr(attr);
+
+ auto func = [&device_address, &binder_attr](IInterface* cb) {
+ auto avrcp_control_cb = static_cast<IBluetoothAvrcpControlCallback*>(cb);
+ avrcp_control_cb->OnTrackChanged(String16(device_address.c_str()),
+ binder_attr);
+ };
+
+ ForEachCallback(func);
+}
+
+void BluetoothAvrcpControlBinderServer::OnSetAbsVolumeRequest(
+ const std::string& device_address, int32_t abs_vol, int32_t label) {
+ auto addr_s16 = String16(device_address.c_str(), device_address.size());
+ auto func = [&addr_s16, abs_vol, label](IInterface* cb) {
+ auto avrcp_control_cb = static_cast<IBluetoothAvrcpControlCallback*>(cb);
+ avrcp_control_cb->OnSetAbsVolumeRequest(addr_s16, abs_vol, label);
+ };
+
+ ForEachCallback(func);
+}
+
+void BluetoothAvrcpControlBinderServer::OnRegisterForAbsVolumeCallbackRequest(
+ const std::string& device_address, int32_t label) {
+ auto addr_s16 = String16(device_address.c_str(), device_address.size());
+ auto func = [&addr_s16, label](IInterface* cb) {
+ auto avrcp_control_cb = static_cast<IBluetoothAvrcpControlCallback*>(cb);
+ avrcp_control_cb->OnRegisterForAbsVolumeCallbackRequest(addr_s16, label);
+ };
+
+ ForEachCallback(func);
+}
+
+std::shared_ptr<bluetooth::AvrcpControl>
+BluetoothAvrcpControlBinderServer::GetAvrcpControl(int id) {
+ return std::static_pointer_cast<bluetooth::AvrcpControl>(GetInstance(id));
+}
+
+void BluetoothAvrcpControlBinderServer::OnRegisterInstanceImpl(
+ bluetooth::BLEStatus status, android::sp<IInterface> callback,
+ bluetooth::BluetoothInstance* instance) {
+ VLOG(1) << __func__ << " client ID: " << instance->GetInstanceId()
+ << " status: " << status;
+
+ bluetooth::AvrcpControl* avrcp_control =
+ static_cast<bluetooth::AvrcpControl*>(instance);
+ avrcp_control->SetDelegate(this);
+
+ android::sp<IBluetoothAvrcpControlCallback> cb(
+ static_cast<IBluetoothAvrcpControlCallback*>(callback.get()));
+ cb->OnRegistered(status, (status == bluetooth::BLE_STATUS_SUCCESS)
+ ? instance->GetInstanceId()
+ : kInvalidInstanceId);
+}
+
+} // namespace binder
+} // namespace ipc
diff --git a/service/ipc/binder/bluetooth_avrcp_control_binder_server.h b/service/ipc/binder/bluetooth_avrcp_control_binder_server.h
new file mode 100644
index 0000000..11cf1f3
--- /dev/null
+++ b/service/ipc/binder/bluetooth_avrcp_control_binder_server.h
@@ -0,0 +1,89 @@
+//
+// Copyright (C) 2017 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 <map>
+#include <string>
+
+#include "base/macros.h"
+
+#include "android/bluetooth/BnBluetoothAvrcpControl.h"
+#include "android/bluetooth/IBluetoothAvrcpControlCallback.h"
+
+#include "service/avrcp_control.h"
+#include "service/ipc/binder/interface_with_instances_base.h"
+
+namespace bluetooth {
+class Adapter;
+} // namespace bluetooth
+
+namespace ipc {
+namespace binder {
+
+class BluetoothAvrcpControlBinderServer
+ : public InterfaceWithInstancesBase,
+ public android::bluetooth::BnBluetoothAvrcpControl,
+ public bluetooth::AvrcpControl::Delegate {
+ public:
+ explicit BluetoothAvrcpControlBinderServer(bluetooth::Adapter* adapter);
+ ~BluetoothAvrcpControlBinderServer() override = default;
+
+ // IBluetoothAvrcpControl implementation:
+ android::binder::Status Register(
+ const android::sp<::android::bluetooth::IBluetoothAvrcpControlCallback>&
+ callback,
+ bool* _aidl_return) override;
+ android::binder::Status Unregister(int32_t id) override;
+ android::binder::Status UnregisterAll() override;
+ android::binder::Status Enable(int32_t id, bool* _aidl_return) override;
+ android::binder::Status Disable(int32_t id, bool* _aidl_return) override;
+ android::binder::Status SendPassThroughCommand(
+ int32_t id, const android::String16& device_address, int32_t key_code,
+ bool key_pressed, bool* _aidl_return) override;
+ android::binder::Status SetAbsVolumeResponse(
+ int32_t id, const android::String16& device_address, int32_t abs_vol,
+ int32_t label, bool* _aidl_return) override;
+ android::binder::Status RegisterForAbsVolumeCallbackResponse(
+ int32_t id, const android::String16& device_address,
+ int32_t response_type, int32_t abs_vol, int32_t label,
+ bool* _aidl_return) override;
+
+ private:
+ // bluetooth::bluetooth::AvrcpControl::Delegate implementation:
+ void OnConnectionState(bool rc_connect, bool bt_connect,
+ const std::string& device_address) override;
+ void OnTrackChanged(const std::string& device_address,
+ const bluetooth::AvrcpMediaAttr& attr) override;
+ void OnSetAbsVolumeRequest(const std::string& device_address, int32_t abs_vol,
+ int32_t label) override;
+ void OnRegisterForAbsVolumeCallbackRequest(const std::string& device_address,
+ int32_t label) override;
+
+ // InterfaceWithInstancesBase override:
+ void OnRegisterInstanceImpl(bluetooth::BLEStatus status,
+ android::sp<IInterface> callback,
+ bluetooth::BluetoothInstance* instance) override;
+
+ std::shared_ptr<bluetooth::AvrcpControl> GetAvrcpControl(int id);
+
+ bluetooth::Adapter* adapter_; // weak
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothAvrcpControlBinderServer);
+};
+
+} // namespace binder
+} // namespace ipc
diff --git a/service/ipc/binder/bluetooth_avrcp_target_binder_server.cc b/service/ipc/binder/bluetooth_avrcp_target_binder_server.cc
new file mode 100644
index 0000000..1652b10
--- /dev/null
+++ b/service/ipc/binder/bluetooth_avrcp_target_binder_server.cc
@@ -0,0 +1,339 @@
+//
+// Copyright (C) 2017 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_avrcp_target_binder_server.h"
+
+#include <string>
+
+#include "base/logging.h"
+
+#include "service/adapter.h"
+
+#define AIDL_RET(value) \
+ do { \
+ *_aidl_return = (value); \
+ return Status::ok(); \
+ } while (0)
+
+#define TRY_GET_TARGET() \
+ ({ \
+ auto target = GetAvrcpTarget(); \
+ if (!target) { \
+ LOG(ERROR) << __func__ << ": " \
+ << "Failed to get AVRCP target interface"; \
+ AIDL_RET(false); \
+ } \
+ target; \
+ })
+
+#define TRY_GET_CB() \
+ ({ \
+ auto cb = GetAvrcpTargetCallback(); \
+ if (!cb.get()) { \
+ LOG(WARNING) << "Callback for AVRCP target was deleted"; \
+ return; \
+ } \
+ cb; \
+ })
+
+#define TRY_RET(expr, msg) \
+ do { \
+ if (!(expr)) { \
+ LOG(ERROR) << msg; \
+ AIDL_RET(false); \
+ } \
+ AIDL_RET(true); \
+ } while (0)
+
+#define TRY_RET_FUNC(expr) TRY_RET(expr, __func__ << " failed")
+
+using android::String16;
+using android::String8;
+using android::binder::Status;
+using android::bluetooth::BluetoothAvrcpIntValue;
+using android::bluetooth::IBluetoothAvrcpTargetCallback;
+
+using LockGuard = std::lock_guard<std::mutex>;
+
+namespace ipc {
+namespace binder {
+
+BluetoothAvrcpTargetBinderServer::BluetoothAvrcpTargetBinderServer(
+ bluetooth::Adapter* adapter)
+ : adapter_(adapter) {
+ CHECK(adapter_);
+}
+
+BluetoothAvrcpTargetBinderServer::~BluetoothAvrcpTargetBinderServer() = default;
+
+bool BluetoothAvrcpTargetBinderServer::HasInstance() {
+ return GetAvrcpTarget() != nullptr;
+}
+
+Status BluetoothAvrcpTargetBinderServer::Register(
+ const android::sp<IBluetoothAvrcpTargetCallback>& callback,
+ bool* _aidl_return) {
+ VLOG(2) << __func__;
+
+ bluetooth::AvrcpTargetFactory* gatt_client_factory =
+ adapter_->GetAvrcpTargetFactory();
+
+ *_aidl_return = RegisterInstanceBase(callback, gatt_client_factory);
+ return Status::ok();
+}
+
+Status BluetoothAvrcpTargetBinderServer::Unregister(int32_t id) {
+ VLOG(2) << __func__;
+ UnregisterInstanceBase(id);
+ return Status::ok();
+}
+
+Status BluetoothAvrcpTargetBinderServer::UnregisterAll() {
+ VLOG(2) << __func__;
+ UnregisterAllBase();
+ return Status::ok();
+}
+
+Status BluetoothAvrcpTargetBinderServer::Enable(bool* _aidl_return) {
+ auto avrcp_target = TRY_GET_TARGET();
+ TRY_RET_FUNC(avrcp_target->Enable());
+}
+
+Status BluetoothAvrcpTargetBinderServer::Disable(bool* _aidl_return) {
+ auto avrcp_target = TRY_GET_TARGET();
+ avrcp_target->Disable();
+ AIDL_RET(true);
+}
+
+Status BluetoothAvrcpTargetBinderServer::GetPlayStatusResponse(
+ const android::String16& addr, int32_t play_status, int32_t song_len,
+ int32_t song_pos, bool* _aidl_return) {
+ auto avrcp_target = TRY_GET_TARGET();
+ TRY_RET_FUNC(avrcp_target->GetPlayStatusResponse(
+ String8(addr).string(), play_status, song_len, song_pos));
+}
+
+Status BluetoothAvrcpTargetBinderServer::ListPlayerAppAttrResponse(
+ const android::String16& addr, const std::vector<int32_t>& attrs,
+ bool* _aidl_return) {
+ auto avrcp_target = TRY_GET_TARGET();
+ TRY_RET_FUNC(
+ avrcp_target->ListPlayerAppAttrResponse(String8(addr).string(), attrs));
+}
+
+Status BluetoothAvrcpTargetBinderServer::GetPlayerAppValueResponse(
+ const android::String16& addr,
+ const std::vector<::android::bluetooth::BluetoothAvrcpIntValue>& values,
+ bool* _aidl_return) {
+ auto avrcp_target = TRY_GET_TARGET();
+ std::vector<bluetooth::AvrcpIntValue> non_binder;
+ non_binder.reserve(values.size());
+ for (const auto& val : values) {
+ non_binder.push_back(val);
+ }
+ TRY_RET_FUNC(avrcp_target->GetPlayerAppValueResponse(String8(addr).string(),
+ non_binder));
+}
+
+Status BluetoothAvrcpTargetBinderServer::GetPlayerAppAttrTextResponse(
+ const android::String16& addr,
+ const std::vector<::android::bluetooth::BluetoothAvrcpStringValue>& attrs,
+ bool* _aidl_return) {
+ auto avrcp_target = TRY_GET_TARGET();
+ std::vector<bluetooth::AvrcpStringValue> non_binder;
+ non_binder.reserve(attrs.size());
+ for (const auto& val : attrs) {
+ non_binder.push_back(val);
+ }
+ TRY_RET_FUNC(avrcp_target->GetPlayerAppAttrTextResponse(
+ String8(addr).string(), non_binder));
+}
+
+Status BluetoothAvrcpTargetBinderServer::GetPlayerAppValueTextResponse(
+ const android::String16& addr,
+ const std::vector<::android::bluetooth::BluetoothAvrcpStringValue>& values,
+ bool* _aidl_return) {
+ auto avrcp_target = TRY_GET_TARGET();
+ std::vector<bluetooth::AvrcpStringValue> non_binder;
+ non_binder.reserve(values.size());
+ for (const auto& val : values) {
+ non_binder.push_back(val);
+ }
+ TRY_RET_FUNC(avrcp_target->GetPlayerAppValueTextResponse(
+ String8(addr).string(), non_binder));
+}
+
+Status BluetoothAvrcpTargetBinderServer::GetElementAttrResponse(
+ const android::String16& addr,
+ const std::vector<::android::bluetooth::BluetoothAvrcpStringValue>& attrs,
+ bool* _aidl_return) {
+ auto avrcp_target = TRY_GET_TARGET();
+ std::vector<bluetooth::AvrcpStringValue> non_binder;
+ non_binder.reserve(attrs.size());
+ for (const auto& val : attrs) {
+ non_binder.push_back(val);
+ }
+ TRY_RET_FUNC(
+ avrcp_target->GetElementAttrResponse(String8(addr).string(), non_binder));
+}
+
+Status BluetoothAvrcpTargetBinderServer::SetPlayerAppValueResponse(
+ const android::String16& addr, int32_t rsp_status, bool* _aidl_return) {
+ auto avrcp_target = TRY_GET_TARGET();
+ TRY_RET_FUNC(avrcp_target->SetPlayerAppValueResponse(String8(addr).string(),
+ rsp_status));
+}
+
+Status BluetoothAvrcpTargetBinderServer::RegisterNotificationResponse(
+ int32_t event_id, int32_t type,
+ const ::android::bluetooth::BluetoothAvrcpRegisterNotificationResponse&
+ param,
+ bool* _aidl_return) {
+ auto avrcp_target = TRY_GET_TARGET();
+ TRY_RET_FUNC(
+ avrcp_target->RegisterNotificationResponse(event_id, type, param));
+}
+
+Status BluetoothAvrcpTargetBinderServer::SetVolume(int32_t volume,
+ bool* _aidl_return) {
+ auto avrcp_target = TRY_GET_TARGET();
+ TRY_RET_FUNC(avrcp_target->SetVolume(volume));
+}
+
+void BluetoothAvrcpTargetBinderServer::OnGetRemoteFeatures(
+ const std::string& addr, int32_t features) {
+ LockGuard lock(*maps_lock());
+ auto cb = TRY_GET_CB();
+ cb->OnGetRemoteFeatures(String16(addr.data(), addr.size()), features);
+}
+
+void BluetoothAvrcpTargetBinderServer::OnGetPlayStatus(
+ const std::string& addr) {
+ LockGuard lock(*maps_lock());
+ auto cb = TRY_GET_CB();
+ cb->OnGetPlayStatus(String16(addr.data(), addr.size()));
+}
+
+void BluetoothAvrcpTargetBinderServer::OnListPlayerAppAttr(
+ const std::string& addr) {
+ LockGuard lock(*maps_lock());
+ auto cb = TRY_GET_CB();
+ cb->OnListPlayerAppAttr(String16(addr.data(), addr.size()));
+}
+
+void BluetoothAvrcpTargetBinderServer::OnListPlayerAppValues(
+ const std::string& addr, int32_t attr_id) {
+ LockGuard lock(*maps_lock());
+ auto cb = TRY_GET_CB();
+ cb->OnListPlayerAppValues(String16(addr.data(), addr.size()), attr_id);
+}
+
+void BluetoothAvrcpTargetBinderServer::OnGetPlayerAppValue(
+ const std::string& addr, const std::vector<int32_t>& attrs) {
+ LockGuard lock(*maps_lock());
+ auto cb = TRY_GET_CB();
+ cb->OnGetPlayerAppValue(String16(addr.data(), addr.size()), attrs);
+}
+
+void BluetoothAvrcpTargetBinderServer::OnGetPlayerAppAttrsText(
+ const std::string& addr, const std::vector<int32_t>& attrs) {
+ LockGuard lock(*maps_lock());
+ auto cb = TRY_GET_CB();
+ cb->OnGetPlayerAppAttrsText(String16(addr.data(), addr.size()), attrs);
+}
+
+void BluetoothAvrcpTargetBinderServer::OnGetPlayerAppValuesText(
+ const std::string& addr, int32_t attr_id,
+ const std::vector<int32_t>& values) {
+ LockGuard lock(*maps_lock());
+ auto cb = TRY_GET_CB();
+ cb->OnGetPlayerAppValuesText(String16(addr.data(), addr.size()), attr_id,
+ values);
+}
+
+void BluetoothAvrcpTargetBinderServer::OnSetPlayerAppValue(
+ const std::string& addr,
+ const std::vector<bluetooth::AvrcpIntValue>& values) {
+ std::vector<BluetoothAvrcpIntValue> binder_values;
+ binder_values.reserve(values.size());
+ for (const auto& val : values) {
+ binder_values.push_back(val);
+ }
+
+ LockGuard lock(*maps_lock());
+ auto cb = TRY_GET_CB();
+ cb->OnSetPlayerAppValue(String16(addr.data(), addr.size()), binder_values);
+}
+
+void BluetoothAvrcpTargetBinderServer::OnGetElementAttrs(
+ const std::string& addr, const std::vector<int32_t>& attrs) {
+ LockGuard lock(*maps_lock());
+ auto cb = TRY_GET_CB();
+ cb->OnGetElementAttrs(String16(addr.data(), addr.size()), attrs);
+}
+
+void BluetoothAvrcpTargetBinderServer::OnRegisterNotification(
+ const std::string& addr, int32_t event_id, uint32_t param) {
+ LockGuard lock(*maps_lock());
+ auto cb = TRY_GET_CB();
+ cb->OnRegisterNotification(String16(addr.data(), addr.size()), event_id,
+ param);
+}
+
+void BluetoothAvrcpTargetBinderServer::OnVolumeChange(const std::string& addr,
+ int32_t volume,
+ int32_t ctype) {
+ LockGuard lock(*maps_lock());
+ auto cb = TRY_GET_CB();
+ cb->OnVolumeChange(String16(addr.data(), addr.size()), volume, ctype);
+}
+
+void BluetoothAvrcpTargetBinderServer::OnPassThroughCommand(
+ const std::string& addr, int32_t id, int32_t key_state) {
+ LockGuard lock(*maps_lock());
+ auto cb = TRY_GET_CB();
+ cb->OnPassThroughCommand(String16(addr.data(), addr.size()), id, key_state);
+}
+
+android::sp<IBluetoothAvrcpTargetCallback>
+BluetoothAvrcpTargetBinderServer::GetAvrcpTargetCallback() {
+ auto cb = GetCallback(bluetooth::AvrcpTarget::kSingletonInstanceId);
+ return android::sp<IBluetoothAvrcpTargetCallback>(
+ static_cast<IBluetoothAvrcpTargetCallback*>(cb.get()));
+}
+
+std::shared_ptr<bluetooth::AvrcpTarget>
+BluetoothAvrcpTargetBinderServer::GetAvrcpTarget() {
+ return std::static_pointer_cast<bluetooth::AvrcpTarget>(
+ GetInstance(bluetooth::AvrcpTarget::kSingletonInstanceId));
+}
+
+void BluetoothAvrcpTargetBinderServer::OnRegisterInstanceImpl(
+ bluetooth::BLEStatus status, android::sp<IInterface> callback,
+ bluetooth::BluetoothInstance* instance) {
+ VLOG(1) << __func__ << " client ID: " << instance->GetInstanceId()
+ << " status: " << status;
+
+ bluetooth::AvrcpTarget* avrcp_target =
+ static_cast<bluetooth::AvrcpTarget*>(instance);
+ avrcp_target->SetDelegate(this);
+
+ android::sp<IBluetoothAvrcpTargetCallback> cb(
+ static_cast<IBluetoothAvrcpTargetCallback*>(callback.get()));
+ cb->OnRegistered(status);
+}
+
+} // namespace binder
+} // namespace ipc
diff --git a/service/ipc/binder/bluetooth_avrcp_target_binder_server.h b/service/ipc/binder/bluetooth_avrcp_target_binder_server.h
new file mode 100644
index 0000000..9d2bba0
--- /dev/null
+++ b/service/ipc/binder/bluetooth_avrcp_target_binder_server.h
@@ -0,0 +1,131 @@
+//
+// Copyright (C) 2017 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 <map>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+
+#include "android/bluetooth/BnBluetoothAvrcpTarget.h"
+#include "android/bluetooth/IBluetoothAvrcpTargetCallback.h"
+
+#include "service/avrcp_target.h"
+#include "service/ipc/binder/interface_with_instances_base.h"
+
+namespace bluetooth {
+class Adapter;
+} // namespace bluetooth
+
+namespace ipc {
+namespace binder {
+
+class BluetoothAvrcpTargetBinderServer
+ : public InterfaceWithInstancesBase,
+ public android::bluetooth::BnBluetoothAvrcpTarget,
+ public bluetooth::AvrcpTarget::Delegate {
+ public:
+ explicit BluetoothAvrcpTargetBinderServer(bluetooth::Adapter* adapter);
+ ~BluetoothAvrcpTargetBinderServer() override;
+
+ bool HasInstance();
+
+ // IBluetoothAvrcpTarget implementation:
+ android::binder::Status Register(
+ const android::sp<android::bluetooth::IBluetoothAvrcpTargetCallback>&
+ callback,
+ bool* _aidl_return) override;
+ android::binder::Status Unregister(int32_t id) override;
+ android::binder::Status UnregisterAll() override;
+ android::binder::Status Enable(bool* _aidl_return) override;
+ android::binder::Status Disable(bool* _aidl_return) override;
+ android::binder::Status GetPlayStatusResponse(const android::String16& addr,
+ int32_t play_status,
+ int32_t song_len,
+ int32_t song_pos,
+ bool* _aidl_return) override;
+ android::binder::Status ListPlayerAppAttrResponse(
+ const android::String16& addr, const std::vector<int32_t>& attrs,
+ bool* _aidl_return) override;
+ android::binder::Status GetPlayerAppValueResponse(
+ const android::String16& addr,
+ const std::vector<android::bluetooth::BluetoothAvrcpIntValue>& values,
+ bool* _aidl_return) override;
+ android::binder::Status GetPlayerAppAttrTextResponse(
+ const android::String16& addr,
+ const std::vector<android::bluetooth::BluetoothAvrcpStringValue>& attrs,
+ bool* _aidl_return) override;
+ android::binder::Status GetPlayerAppValueTextResponse(
+ const android::String16& addr,
+ const std::vector<android::bluetooth::BluetoothAvrcpStringValue>& values,
+ bool* _aidl_return) override;
+ android::binder::Status GetElementAttrResponse(
+ const android::String16& addr,
+ const std::vector<android::bluetooth::BluetoothAvrcpStringValue>& attrs,
+ bool* _aidl_return) override;
+ android::binder::Status SetPlayerAppValueResponse(
+ const android::String16& addr, int32_t rsp_status,
+ bool* _aidl_return) override;
+ android::binder::Status RegisterNotificationResponse(
+ int32_t event_id, int32_t type,
+ const android::bluetooth::BluetoothAvrcpRegisterNotificationResponse&
+ param,
+ bool* _aidl_return) override;
+ android::binder::Status SetVolume(int32_t volume,
+ bool* _aidl_return) override;
+
+ private:
+ // bluetooth::bluetooth::AvrcpTarget::Delegate implementation:
+ void OnGetRemoteFeatures(const std::string& addr, int32_t features) override;
+ void OnGetPlayStatus(const std::string& addr) override;
+ void OnListPlayerAppAttr(const std::string& addr) override;
+ void OnListPlayerAppValues(const std::string& addr, int32_t attr_id) override;
+ void OnGetPlayerAppValue(const std::string& addr,
+ const std::vector<int32_t>& attrs) override;
+ void OnGetPlayerAppAttrsText(const std::string& addr,
+ const std::vector<int32_t>& attrs) override;
+ void OnGetPlayerAppValuesText(const std::string& addr, int32_t attr_id,
+ const std::vector<int32_t>& values) override;
+ void OnSetPlayerAppValue(
+ const std::string& addr,
+ const std::vector<bluetooth::AvrcpIntValue>& values) override;
+ void OnGetElementAttrs(const std::string& addr,
+ const std::vector<int32_t>& attrs) override;
+ void OnRegisterNotification(const std::string& addr, int32_t event_id,
+ uint32_t param) override;
+ void OnVolumeChange(const std::string& addr, int32_t volume,
+ int32_t ctype) override;
+ void OnPassThroughCommand(const std::string& addr, int32_t id,
+ int32_t key_state) override;
+
+ // InterfaceWithInstancesBase override:
+ void OnRegisterInstanceImpl(bluetooth::BLEStatus status,
+ android::sp<IInterface> callback,
+ bluetooth::BluetoothInstance* instance) override;
+
+ android::sp<android::bluetooth::IBluetoothAvrcpTargetCallback>
+ GetAvrcpTargetCallback();
+ std::shared_ptr<bluetooth::AvrcpTarget> GetAvrcpTarget();
+
+ bluetooth::Adapter* const adapter_; // weak
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothAvrcpTargetBinderServer);
+};
+
+} // namespace binder
+} // namespace ipc
diff --git a/service/ipc/binder/bluetooth_binder_server.cc b/service/ipc/binder/bluetooth_binder_server.cc
index 2d32cee..ca36019 100644
--- a/service/ipc/binder/bluetooth_binder_server.cc
+++ b/service/ipc/binder/bluetooth_binder_server.cc
@@ -18,6 +18,10 @@
#include <base/logging.h>
+#include "service/ipc/binder/bluetooth_a2dp_sink_binder_server.h"
+#include "service/ipc/binder/bluetooth_a2dp_source_binder_server.h"
+#include "service/ipc/binder/bluetooth_avrcp_control_binder_server.h"
+#include "service/ipc/binder/bluetooth_avrcp_target_binder_server.h"
#include "service/ipc/binder/bluetooth_gatt_client_binder_server.h"
#include "service/ipc/binder/bluetooth_gatt_server_binder_server.h"
#include "service/ipc/binder/bluetooth_le_advertiser_binder_server.h"
@@ -107,6 +111,59 @@
return Status::ok();
}
+Status BluetoothBinderServer::SetScanMode(int32_t scan_mode,
+ bool* _aidl_return) {
+ VLOG(2) << __func__;
+ *_aidl_return = adapter_->SetScanMode(scan_mode);
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::SetScanEnable(bool scan_enable,
+ bool* _aidl_return) {
+ VLOG(2) << __func__;
+ *_aidl_return = adapter_->SetScanEnable(scan_enable);
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::SspReply(
+ const ::android::String16& device_address, int32_t variant, bool accept,
+ int32_t passkey, bool* _aidl_return) {
+ VLOG(2) << __func__;
+ *_aidl_return = adapter_->SspReply(String8(device_address).string(), variant,
+ accept, passkey);
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::CreateBond(
+ const ::android::String16& device_address, int32_t transport,
+ bool* _aidl_return) {
+ VLOG(2) << __func__;
+ *_aidl_return =
+ adapter_->CreateBond(String8(device_address).string(), transport);
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::GetBondedDevices(bool* _aidl_return) {
+ VLOG(2) << __func__;
+ *_aidl_return = adapter_->GetBondedDevices();
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::RemoveBond(
+ const ::android::String16& device_address, bool* _aidl_return) {
+ VLOG(2) << __func__;
+ *_aidl_return = adapter_->RemoveBond(String8(device_address).string());
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::GetRemoteDeviceProperties(
+ const ::android::String16& device_address, bool* _aidl_return) {
+ VLOG(2) << __func__;
+ *_aidl_return =
+ adapter_->GetRemoteDeviceProperties(String8(device_address).string());
+ return Status::ok();
+}
+
Status BluetoothBinderServer::RegisterCallback(
const ::android::sp<IBluetoothCallback>& callback) {
VLOG(2) << __func__;
@@ -136,6 +193,52 @@
return Status::ok();
}
+Status BluetoothBinderServer::GetA2dpSinkInterface(
+ ::android::sp<IBluetoothA2dpSink>* _aidl_return) {
+ VLOG(2) << __func__;
+
+ if (!adapter_->IsEnabled()) {
+ LOG(ERROR) << "Cannot obtain IBluetoothA2dpSink interface while disabled";
+ *_aidl_return = nullptr;
+ return Status::ok();
+ }
+
+ if (!a2dp_sink_interface_.get())
+ a2dp_sink_interface_ = new BluetoothA2dpSinkBinderServer(adapter_);
+
+ if (a2dp_sink_interface_->HasInstance()) {
+ LOG(ERROR) << "Only one A2dpSink interface allowed at a time";
+ *_aidl_return = nullptr;
+ return Status::ok();
+ }
+
+ *_aidl_return = a2dp_sink_interface_;
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::GetA2dpSourceInterface(
+ ::android::sp<IBluetoothA2dpSource>* _aidl_return) {
+ VLOG(2) << __func__;
+
+ if (!adapter_->IsEnabled()) {
+ LOG(ERROR) << "Cannot obtain IBluetoothA2dpSource interface while disabled";
+ *_aidl_return = nullptr;
+ return Status::ok();
+ }
+
+ if (!a2dp_source_interface_.get())
+ a2dp_source_interface_ = new BluetoothA2dpSourceBinderServer(adapter_);
+
+ if (a2dp_source_interface_->HasInstance()) {
+ LOG(ERROR) << "Only one A2dpSource interface allowed at a time";
+ *_aidl_return = nullptr;
+ return Status::ok();
+ }
+
+ *_aidl_return = a2dp_source_interface_;
+ return Status::ok();
+}
+
Status BluetoothBinderServer::GetLowEnergyInterface(
::android::sp<IBluetoothLowEnergy>* _aidl_return) {
VLOG(2) << __func__;
@@ -222,6 +325,48 @@
return Status::ok();
}
+Status BluetoothBinderServer::GetAvrcpControlInterface(
+ ::android::sp<IBluetoothAvrcpControl>* _aidl_return) {
+ VLOG(2) << __func__;
+
+ if (!adapter_->IsEnabled()) {
+ LOG(ERROR)
+ << "Cannot obtain IBluetoothAvrcpControl interface while disabled";
+ *_aidl_return = NULL;
+ return Status::ok();
+ }
+
+ if (!avrcp_control_interface_.get())
+ avrcp_control_interface_ = new BluetoothAvrcpControlBinderServer(adapter_);
+
+ *_aidl_return = avrcp_control_interface_;
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::GetAvrcpTargetInterface(
+ ::android::sp<IBluetoothAvrcpTarget>* _aidl_return) {
+ VLOG(2) << __func__;
+
+ if (!adapter_->IsEnabled()) {
+ LOG(ERROR)
+ << "Cannot obtain IBluetoothAvrcpTarget interface while disabled";
+ *_aidl_return = NULL;
+ return Status::ok();
+ }
+
+ if (!avrcp_target_interface_.get())
+ avrcp_target_interface_ = new BluetoothAvrcpTargetBinderServer(adapter_);
+
+ if (avrcp_target_interface_->HasInstance()) {
+ LOG(ERROR) << "Only one AVRCP target interface allowed at a time";
+ *_aidl_return = nullptr;
+ return Status::ok();
+ }
+
+ *_aidl_return = avrcp_target_interface_;
+ return Status::ok();
+}
+
android::status_t BluetoothBinderServer::dump(
int fd, const android::Vector<android::String16>& args) {
VLOG(2) << __func__ << " called with fd " << fd;
@@ -249,5 +394,97 @@
});
}
+void BluetoothBinderServer::OnDeviceConnectionStateChanged(
+ bluetooth::Adapter* adapter, const std::string& device_address,
+ bool connected) {
+ CHECK_EQ(adapter, adapter_);
+ auto addr_s16 = String16(device_address.c_str(), device_address.size());
+ callbacks_.ForEach([&addr_s16, connected](IBluetoothCallback* callback) {
+ callback->OnDeviceConnectionStateChanged(addr_s16, connected);
+ });
+}
+
+void BluetoothBinderServer::OnScanEnableChanged(bluetooth::Adapter* adapter,
+ bool scan_enabled) {
+ CHECK_EQ(adapter, adapter_);
+ callbacks_.ForEach([scan_enabled](IBluetoothCallback* callback) {
+ callback->OnScanEnableChanged(scan_enabled);
+ });
+}
+
+void BluetoothBinderServer::OnSspRequest(bluetooth::Adapter* adapter,
+ const std::string& device_address,
+ const std::string& device_name,
+ int cod, int pairing_variant,
+ int pass_key) {
+ CHECK_EQ(adapter, adapter_);
+ VLOG(2) << "Received ssp request: device_address: " << device_address
+ << ", device_name: " << device_name << ", cod: " << cod
+ << ", pairing_variant: " << pairing_variant
+ << ", pass_key: " << pass_key;
+
+ android::String16 addr_s16(device_address.c_str());
+ android::String16 name_s16(device_name.c_str());
+ callbacks_.ForEach([&addr_s16, &name_s16, cod, pairing_variant,
+ pass_key](IBluetoothCallback* callback) {
+ callback->OnSspRequest(addr_s16, name_s16, cod, pairing_variant, pass_key);
+ });
+}
+
+void BluetoothBinderServer::OnBondStateChanged(
+ bluetooth::Adapter* adapter, int status, const std::string& device_address,
+ int state) {
+ CHECK_EQ(adapter, adapter_);
+ VLOG(2) << "Received " << __func__ << " "
+ << "status: " << status << ", device_address: " << device_address
+ << ", state: " << state;
+ android::String16 addr_s16(device_address.c_str(), device_address.size());
+ callbacks_.ForEach([status, &addr_s16, state](IBluetoothCallback* callback) {
+ callback->OnBondStateChanged(status, addr_s16, state);
+ });
+}
+
+void BluetoothBinderServer::OnGetBondedDevices(
+ bluetooth::Adapter* adapter, int status,
+ const std::vector<std::string>& bonded_devices) {
+ CHECK_EQ(adapter, adapter_);
+ VLOG(2) << "Received " << __func__;
+ std::vector<android::String16> devices_s16;
+ devices_s16.reserve(bonded_devices.size());
+ for (const auto& device : bonded_devices)
+ devices_s16.emplace_back(device.c_str(), device.size());
+
+ callbacks_.ForEach([status, &devices_s16](IBluetoothCallback* callback) {
+ callback->OnGetBondedDevices(status, devices_s16);
+ });
+}
+
+void BluetoothBinderServer::OnGetRemoteDeviceProperties(
+ bluetooth::Adapter* adapter, int status, const std::string& device_address,
+ const bluetooth::RemoteDeviceProps& properties) {
+ CHECK_EQ(adapter, adapter_);
+ VLOG(2) << "Received " << __func__ << " "
+ << "status: " << status << ", device_address: " << device_address;
+ android::String16 addr_s16(device_address.c_str(), device_address.size());
+ auto binder_props =
+ android::bluetooth::BluetoothRemoteDeviceProps(properties);
+ callbacks_.ForEach(
+ [status, &addr_s16, &binder_props](IBluetoothCallback* callback) {
+ callback->OnGetRemoteDeviceProperties(status, addr_s16, binder_props);
+ });
+}
+
+void BluetoothBinderServer::OnDeviceFound(
+ bluetooth::Adapter* adapter,
+ const bluetooth::RemoteDeviceProps& properties) {
+ CHECK_EQ(adapter, adapter_);
+ VLOG(2) << "Received " << __func__ << " ";
+ auto binder_props =
+ android::bluetooth::BluetoothRemoteDeviceProps(properties);
+ callbacks_.ForEach([&binder_props](IBluetoothCallback* callback) {
+ callback->OnDeviceFound(binder_props);
+ });
+}
+
} // namespace binder
} // namespace ipc
diff --git a/service/ipc/binder/bluetooth_binder_server.h b/service/ipc/binder/bluetooth_binder_server.h
index b03a815..bfeb589 100644
--- a/service/ipc/binder/bluetooth_binder_server.h
+++ b/service/ipc/binder/bluetooth_binder_server.h
@@ -1,5 +1,5 @@
//
-// Copyright 2015 Google, Inc.
+// 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.
@@ -24,14 +24,18 @@
#include <utils/Vector.h>
#include <android/bluetooth/BnBluetooth.h>
+#include <android/bluetooth/IBluetoothA2dpSink.h>
+#include <android/bluetooth/IBluetoothA2dpSource.h>
+#include <android/bluetooth/IBluetoothAvrcpControl.h>
+#include <android/bluetooth/IBluetoothAvrcpTarget.h>
#include <android/bluetooth/IBluetoothCallback.h>
#include <android/bluetooth/IBluetoothGattClient.h>
#include <android/bluetooth/IBluetoothGattServer.h>
#include <android/bluetooth/IBluetoothLeAdvertiser.h>
#include <android/bluetooth/IBluetoothLeScanner.h>
#include <android/bluetooth/IBluetoothLowEnergy.h>
-#include <bluetooth/uuid.h>
+#include "bluetooth/uuid.h"
#include "service/adapter.h"
#include "service/ipc/binder/remote_callback_list.h"
@@ -39,16 +43,24 @@
using android::binder::Status;
using android::bluetooth::BnBluetooth;
+using android::bluetooth::IBluetoothA2dpSink;
+using android::bluetooth::IBluetoothA2dpSource;
+using android::bluetooth::IBluetoothAvrcpControl;
+using android::bluetooth::IBluetoothAvrcpTarget;
using android::bluetooth::IBluetoothCallback;
using android::bluetooth::IBluetoothGattClient;
using android::bluetooth::IBluetoothGattServer;
-using android::bluetooth::IBluetoothLowEnergy;
using android::bluetooth::IBluetoothLeAdvertiser;
using android::bluetooth::IBluetoothLeScanner;
+using android::bluetooth::IBluetoothLowEnergy;
namespace ipc {
namespace binder {
+class BluetoothA2dpSinkBinderServer;
+class BluetoothA2dpSourceBinderServer;
+class BluetoothAvrcpTargetBinderServer;
+
// Implements the server side of the IBluetooth Binder interface.
class BluetoothBinderServer : public BnBluetooth,
public bluetooth::Adapter::Observer {
@@ -68,12 +80,27 @@
::std::vector<::android::bluetooth::UUID>* _aidl_return) override;
Status SetName(const ::android::String16& name, bool* _aidl_return) override;
Status GetName(::android::String16* _aidl_return) override;
+ Status SetScanMode(int32_t scan_mode, bool* _aidl_return) override;
+ Status SetScanEnable(bool scan_enable, bool* _aidl_return) override;
+ Status SspReply(const ::android::String16& device_address, int32_t variant,
+ bool accept, int32_t passkey, bool* _aidl_return) override;
+ Status CreateBond(const ::android::String16& device_address,
+ int32_t transport, bool* _aidl_return) override;
+ Status GetBondedDevices(bool* _aidl_return) override;
+ Status RemoveBond(const ::android::String16& device_address,
+ bool* _aidl_return) override;
+ Status GetRemoteDeviceProperties(const ::android::String16& device_address,
+ bool* _aidl_return) override;
Status RegisterCallback(
const ::android::sp<IBluetoothCallback>& callback) override;
Status UnregisterCallback(
const ::android::sp<IBluetoothCallback>& callback) override;
Status IsMultiAdvertisementSupported(bool* _aidl_return) override;
+ Status GetA2dpSinkInterface(
+ ::android::sp<IBluetoothA2dpSink>* _aidl_return) override;
+ Status GetA2dpSourceInterface(
+ ::android::sp<IBluetoothA2dpSource>* _aidl_return) override;
Status GetLowEnergyInterface(
::android::sp<IBluetoothLowEnergy>* _aidl_return) override;
Status GetLeAdvertiserInterface(
@@ -84,6 +111,10 @@
::android::sp<IBluetoothGattClient>* _aidl_return) override;
Status GetGattServerInterface(
::android::sp<IBluetoothGattServer>* _aidl_return) override;
+ Status GetAvrcpControlInterface(
+ ::android::sp<IBluetoothAvrcpControl>* _aidl_return) override;
+ Status GetAvrcpTargetInterface(
+ ::android::sp<IBluetoothAvrcpTarget>* _aidl_return) override;
android::status_t dump(
int fd, const android::Vector<android::String16>& args) override;
@@ -93,10 +124,43 @@
bluetooth::AdapterState prev_state,
bluetooth::AdapterState new_state) override;
+ void OnDeviceConnectionStateChanged(bluetooth::Adapter* adapter,
+ const std::string& device_address,
+ bool connected) override;
+
+ void OnScanEnableChanged(bluetooth::Adapter* adapter,
+ bool scan_enabled) override;
+
+ void OnSspRequest(bluetooth::Adapter* adapter,
+ const std::string& device_address,
+ const std::string& device_name, int cod,
+ int pairing_variant, int pass_key) override;
+
+ void OnBondStateChanged(bluetooth::Adapter* adapter, int status,
+ const std::string& device_address,
+ int state) override;
+ void OnGetBondedDevices(
+ bluetooth::Adapter* adapter, int status,
+ const std::vector<std::string>& bonded_devices) override;
+ void OnGetRemoteDeviceProperties(
+ bluetooth::Adapter* adapter, int status,
+ const std::string& device_address,
+ const bluetooth::RemoteDeviceProps& properties) override;
+ void OnDeviceFound(bluetooth::Adapter* adapter,
+ const bluetooth::RemoteDeviceProps& properties) override;
+
private:
bluetooth::Adapter* adapter_; // weak
RemoteCallbackList<IBluetoothCallback> callbacks_;
+ // The IBluetoothA2dpSink interface handle. This is lazily initialized on the
+ // first call to GetA2dpSinkInterface().
+ android::sp<BluetoothA2dpSinkBinderServer> a2dp_sink_interface_;
+
+ // The IBluetoothA2dpSource interface handle. This is lazily initialized on
+ // the first call to GetA2dpSourceInterface().
+ android::sp<BluetoothA2dpSourceBinderServer> a2dp_source_interface_;
+
// The IBluetoothLowEnergy interface handle. This is lazily initialized on the
// first call to GetLowEnergyInterface().
android::sp<IBluetoothLowEnergy> low_energy_interface_;
@@ -117,6 +181,14 @@
// the first call to GetGattServerInterface().
android::sp<IBluetoothGattServer> gatt_server_interface_;
+ // The IBluetoothAvrcpControl interface handle. This is lazily initialized on
+ // the first call to GetAvrcpControlInterface().
+ android::sp<IBluetoothAvrcpControl> avrcp_control_interface_;
+
+ // The IBluetoothAvrcpTarget interface handle. This is lazily initialized on
+ // the first call to GetAvrcpTargetInterface().
+ android::sp<BluetoothAvrcpTargetBinderServer> avrcp_target_interface_;
+
DISALLOW_COPY_AND_ASSIGN(BluetoothBinderServer);
};
diff --git a/service/ipc/binder/interface_with_instances_base.cc b/service/ipc/binder/interface_with_instances_base.cc
index ba24657..1716bbd 100644
--- a/service/ipc/binder/interface_with_instances_base.cc
+++ b/service/ipc/binder/interface_with_instances_base.cc
@@ -86,6 +86,16 @@
id_to_instance_.clear();
}
+void InterfaceWithInstancesBase::ForEachCallback(
+ const std::function<void(IInterface*)>& func) {
+ VLOG(2) << __func__;
+ std::lock_guard<std::mutex> lock(maps_lock_);
+ for (auto& pair : id_to_instance_) {
+ auto cb = id_to_cb_.Get(pair.first);
+ func(cb.get());
+ }
+}
+
android::sp<IInterface> InterfaceWithInstancesBase::GetCallback(
int instance_id) {
return id_to_cb_.Get(instance_id);
diff --git a/service/ipc/binder/interface_with_instances_base.h b/service/ipc/binder/interface_with_instances_base.h
index 90224b6..05f2817 100644
--- a/service/ipc/binder/interface_with_instances_base.h
+++ b/service/ipc/binder/interface_with_instances_base.h
@@ -1,5 +1,5 @@
//
-// Copyright 2015 Google, Inc.
+// 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.
@@ -20,8 +20,8 @@
#include <unordered_map>
#include <base/macros.h>
-#include <bluetooth/uuid.h>
+#include "bluetooth/uuid.h"
#include "service/bluetooth_instance.h"
#include "service/ipc/binder/remote_callback_map.h"
@@ -57,6 +57,8 @@
// Unregisters all registered instances.
void UnregisterAllBase();
+ void ForEachCallback(const std::function<void(IInterface*)>& func);
+
// Returns a handle to the lock used to synchronize access to the internal
// data structures. Subclasses should acquire this before accessing the maps.
std::mutex* maps_lock() { return &maps_lock_; }
diff --git a/service/ipc/ipc_handler_linux.cc b/service/ipc/ipc_handler_linux.cc
index 7fe724e..ebfae12 100644
--- a/service/ipc/ipc_handler_linux.cc
+++ b/service/ipc/ipc_handler_linux.cc
@@ -89,7 +89,7 @@
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);
+ PLOG(ERROR) << "Failed to bind IPC socket to address";
return false;
}
@@ -141,7 +141,7 @@
int status = listen(socket_.get(), SOMAXCONN);
if (status < 0) {
- LOG(ERROR) << "Failed to listen on domain socket: " << strerror(errno);
+ PLOG(ERROR) << "Failed to listen on domain socket";
origin_task_runner_->PostTask(
FROM_HERE, base::Bind(&IPCHandlerLinux::ShutDownOnOriginThread, this));
return;
@@ -158,7 +158,7 @@
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);
+ PLOG(ERROR) << "Failed to accept client connection";
continue;
}
diff --git a/service/ipc/ipc_handler_linux.h b/service/ipc/ipc_handler_linux.h
index 21c71d2..7cd6efa 100644
--- a/service/ipc/ipc_handler_linux.h
+++ b/service/ipc/ipc_handler_linux.h
@@ -17,7 +17,6 @@
#pragma once
#include <atomic>
-
#include <base/files/file_path.h>
#include <base/files/scoped_file.h>
#include <base/macros.h>
diff --git a/service/low_energy_advertiser.cc b/service/low_energy_advertiser.cc
index 4f4bff9..7bc5f25 100644
--- a/service/low_energy_advertiser.cc
+++ b/service/low_energy_advertiser.cc
@@ -16,14 +16,16 @@
#include "service/low_energy_advertiser.h"
-#include <base/bind.h>
-#include <base/logging.h>
-
#include "service/adapter.h"
#include "service/logging_helpers.h"
#include "stack/include/bt_types.h"
#include "stack/include/hcidefs.h"
+#include <base/bind.h>
+#include <base/bind_helpers.h>
+#include <base/callback.h>
+#include <base/logging.h>
+
using std::lock_guard;
using std::mutex;
@@ -53,7 +55,7 @@
ms = kAdvertisingIntervalLowMs;
break;
case AdvertiseSettings::MODE_LOW_POWER:
- // Fall through
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
default:
ms = kAdvertisingIntervalHighMs;
break;
@@ -77,7 +79,7 @@
power = -7;
break;
case AdvertiseSettings::TX_POWER_LEVEL_HIGH:
- // Fall through
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
default:
power = 1;
break;
@@ -113,8 +115,6 @@
out_params->scan_request_notification_enable = 0;
}
-void DoNothing(uint8_t status) {}
-
} // namespace
// LowEnergyAdvertiser implementation
@@ -133,8 +133,7 @@
// Stop advertising and ignore the result.
hal::BluetoothGattInterface::Get()->GetAdvertiserHALInterface()->Enable(
- advertiser_id_, false, base::Bind(&DoNothing), 0, 0,
- base::Bind(&DoNothing));
+ advertiser_id_, false, base::DoNothing(), 0, 0, base::DoNothing());
hal::BluetoothGattInterface::Get()->GetAdvertiserHALInterface()->Unregister(
advertiser_id_);
}
diff --git a/service/low_energy_scanner.cc b/service/low_energy_scanner.cc
index 1527563..82f3ab4 100644
--- a/service/low_energy_scanner.cc
+++ b/service/low_energy_scanner.cc
@@ -16,14 +16,15 @@
#include "service/low_energy_scanner.h"
-#include <base/bind.h>
-#include <base/logging.h>
-
#include "service/adapter.h"
#include "service/logging_helpers.h"
#include "stack/include/bt_types.h"
#include "stack/include/hcidefs.h"
+#include <base/bind.h>
+#include <base/callback.h>
+#include <base/logging.h>
+
using std::lock_guard;
using std::mutex;
diff --git a/service/test/a2dp_sink_unittest.cc b/service/test/a2dp_sink_unittest.cc
new file mode 100644
index 0000000..06fb88e
--- /dev/null
+++ b/service/test/a2dp_sink_unittest.cc
@@ -0,0 +1,271 @@
+//
+// Copyright 2017 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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "service/a2dp_sink.h"
+#include "service/hal/fake_bluetooth_av_interface.h"
+
+using ::testing::_;
+using ::testing::Return;
+
+namespace bluetooth {
+namespace {
+
+class MockA2dpSinkHandler
+ : public hal::FakeBluetoothAvInterface::TestA2dpSinkHandler {
+ public:
+ MockA2dpSinkHandler() = default;
+ ~MockA2dpSinkHandler() override = default;
+
+ MOCK_METHOD1(Connect, bt_status_t(RawAddress));
+ MOCK_METHOD1(Disconnect, bt_status_t(RawAddress));
+ MOCK_METHOD1(SetAudioFocusState, void(int));
+ MOCK_METHOD1(SetAudioTrackGain, void(float));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockA2dpSinkHandler);
+};
+
+class TestDelegate : public A2dpSink::Delegate {
+ public:
+ TestDelegate() = default;
+ ~TestDelegate() override = default;
+
+ struct RequestData {
+ std::string device_address;
+ int state = -1;
+ uint32_t sample_rate = 0;
+ uint8_t channel_count = 0;
+ int count = 0;
+ };
+
+ // A2dpSink::Delegate implementation:
+ void OnConnectionState(const std::string& device_address,
+ int state) override {
+ ++connection_state_.count;
+ connection_state_.device_address = device_address;
+ connection_state_.state = state;
+ }
+ void OnAudioState(const std::string& device_address, int state) override {
+ ++audio_state_.count;
+ audio_state_.device_address = device_address;
+ audio_state_.state = state;
+ }
+ void OnAudioConfig(const std::string& device_address, uint32_t sample_rate,
+ uint8_t channel_count) override {
+ ++audio_config_.count;
+ audio_config_.device_address = device_address;
+ audio_config_.sample_rate = sample_rate;
+ audio_config_.channel_count = channel_count;
+ }
+
+ const RequestData& connection_state() const { return connection_state_; }
+ const RequestData& audio_state() const { return audio_state_; }
+ const RequestData& audio_config() const { return audio_config_; }
+
+ private:
+ RequestData connection_state_;
+ RequestData audio_state_;
+ RequestData audio_config_;
+};
+
+class A2dpSinkTest : public ::testing::Test {
+ public:
+ A2dpSinkTest() = default;
+ ~A2dpSinkTest() override = default;
+
+ void SetUp() override {
+ mock_handler_.reset(new MockA2dpSinkHandler());
+ fake_hal_av_iface_ = new hal::FakeBluetoothAvInterface(mock_handler_);
+ hal::BluetoothAvInterface::InitializeForTesting(fake_hal_av_iface_);
+ factory_.reset(new A2dpSinkFactory());
+ }
+
+ void TearDown() override {
+ factory_.reset();
+ hal::BluetoothAvInterface::CleanUp();
+ }
+
+ protected:
+ hal::FakeBluetoothAvInterface* fake_hal_av_iface_;
+ std::shared_ptr<MockA2dpSinkHandler> mock_handler_;
+ std::unique_ptr<A2dpSinkFactory> factory_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(A2dpSinkTest);
+};
+
+class A2dpSinkPostRegisterTest : public A2dpSinkTest {
+ public:
+ A2dpSinkPostRegisterTest() = default;
+ ~A2dpSinkPostRegisterTest() override = default;
+
+ void SetUp() override {
+ A2dpSinkTest::SetUp();
+ Uuid uuid = Uuid::GetRandom();
+ auto callback = [&](BLEStatus status, const Uuid& in_uuid,
+ std::unique_ptr<BluetoothInstance> in_client) {
+ CHECK(in_uuid == uuid);
+ CHECK(in_client.get());
+ CHECK(status == BLE_STATUS_SUCCESS);
+
+ a2dp_sink_ = std::unique_ptr<A2dpSink>(
+ static_cast<A2dpSink*>(in_client.release()));
+ };
+
+ factory_->RegisterInstance(uuid, callback);
+ }
+
+ void TearDown() override {
+ a2dp_sink_ = nullptr;
+ A2dpSinkTest::TearDown();
+ }
+
+ protected:
+ void Connect(const std::string& addr) {
+ RawAddress hal_addr;
+ ASSERT_TRUE(RawAddress::FromString(addr, hal_addr));
+
+ EXPECT_CALL(*mock_handler_, Connect(hal_addr))
+ .WillOnce(Return(BT_STATUS_SUCCESS));
+
+ EXPECT_TRUE(a2dp_sink_->Connect(addr));
+ }
+
+ void Disconnect(const std::string& addr) {
+ RawAddress hal_addr;
+ ASSERT_TRUE(RawAddress::FromString(addr, hal_addr));
+
+ EXPECT_CALL(*mock_handler_, Disconnect(hal_addr))
+ .WillOnce(Return(BT_STATUS_SUCCESS));
+
+ EXPECT_TRUE(a2dp_sink_->Disconnect(addr));
+ }
+
+ std::unique_ptr<A2dpSink> a2dp_sink_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(A2dpSinkPostRegisterTest);
+};
+
+TEST_F(A2dpSinkTest, RegisterA2dpSink) {
+ // These will be asynchronously populate with a result when the callback
+ // executes.
+ BLEStatus status = BLE_STATUS_SUCCESS;
+ Uuid cb_uuid;
+ std::unique_ptr<A2dpSink> a2dp_sink;
+ int callback_count = 0;
+
+ auto callback = [&](BLEStatus in_status, const Uuid& uuid,
+ std::unique_ptr<BluetoothInstance> in_a2dp_sink) {
+ status = in_status;
+ cb_uuid = uuid;
+ a2dp_sink = std::unique_ptr<A2dpSink>(
+ static_cast<A2dpSink*>(in_a2dp_sink.release()));
+ callback_count++;
+ };
+
+ Uuid uuid0 = Uuid::GetRandom();
+
+ // This should always succeed.
+ EXPECT_TRUE(factory_->RegisterInstance(uuid0, callback));
+ EXPECT_EQ(1, callback_count);
+
+ testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+ ASSERT_TRUE(a2dp_sink.get() !=
+ nullptr); // Assert to terminate in case of error
+ EXPECT_EQ(BLE_STATUS_SUCCESS, status);
+ EXPECT_EQ(bluetooth::A2dpSink::kSingletonInstanceId,
+ a2dp_sink->GetInstanceId());
+ EXPECT_EQ(uuid0, a2dp_sink->GetAppIdentifier());
+ EXPECT_EQ(uuid0, cb_uuid);
+
+ testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+}
+
+TEST_F(A2dpSinkPostRegisterTest, Connect) {
+ static const char kTestAddr[] = "AA:BB:CC:DD:EE:FF";
+ Connect(kTestAddr);
+ Disconnect(kTestAddr);
+}
+
+TEST_F(A2dpSinkPostRegisterTest, SetAudioFocusState) {
+ static const char kTestAddr[] = "AA:BB:CC:DD:EE:FF";
+ static const int kFocusState = 2;
+ Connect(kTestAddr);
+
+ EXPECT_CALL(*mock_handler_, SetAudioFocusState(kFocusState));
+ a2dp_sink_->SetAudioFocusState(kFocusState);
+
+ Disconnect(kTestAddr);
+}
+
+TEST_F(A2dpSinkPostRegisterTest, SetAudioTrackGain) {
+ static const char kTestAddr[] = "AA:BB:CC:DD:EE:FF";
+ static const float kTrackGain = 0.5;
+ Connect(kTestAddr);
+
+ EXPECT_CALL(*mock_handler_, SetAudioTrackGain(kTrackGain));
+ a2dp_sink_->SetAudioTrackGain(kTrackGain);
+
+ Disconnect(kTestAddr);
+}
+
+TEST_F(A2dpSinkPostRegisterTest, CallbackTest) {
+ static const char kTestAddr[] = "AA:BB:CC:DD:EE:FF";
+ RawAddress hal_addr;
+ ASSERT_TRUE(RawAddress::FromString(kTestAddr, hal_addr));
+
+ TestDelegate delegate;
+ a2dp_sink_->SetDelegate(&delegate);
+ Connect(kTestAddr);
+
+ // OnConnectionState
+ const int kConnectionState = 2;
+ EXPECT_EQ(0, delegate.connection_state().count);
+ fake_hal_av_iface_->NotifyConnectionState(
+ hal_addr, static_cast<btav_connection_state_t>(kConnectionState));
+ EXPECT_EQ(1, delegate.connection_state().count);
+ EXPECT_EQ(kTestAddr, delegate.connection_state().device_address);
+ EXPECT_EQ(kConnectionState, delegate.connection_state().state);
+
+ // OnAudioState
+ const int kAudioState = 1;
+ EXPECT_EQ(0, delegate.audio_state().count);
+ fake_hal_av_iface_->NotifyAudioState(
+ hal_addr, static_cast<btav_audio_state_t>(kAudioState));
+ EXPECT_EQ(1, delegate.audio_state().count);
+ EXPECT_EQ(kTestAddr, delegate.audio_state().device_address);
+ EXPECT_EQ(kAudioState, delegate.audio_state().state);
+
+ // OnAudioConfig
+ const uint32_t kSampleRate = 44100;
+ const uint32_t kChannelCount = 2;
+ EXPECT_EQ(0, delegate.audio_config().count);
+ fake_hal_av_iface_->NotifyAudioConfig(hal_addr, kSampleRate, kChannelCount);
+ EXPECT_EQ(1, delegate.audio_config().count);
+ EXPECT_EQ(kTestAddr, delegate.audio_config().device_address);
+ EXPECT_EQ(kSampleRate, delegate.audio_config().sample_rate);
+ EXPECT_EQ(kChannelCount, delegate.audio_config().channel_count);
+
+ Disconnect(kTestAddr);
+}
+
+} // namespace
+} // namespace bluetooth
diff --git a/service/test/low_energy_client_unittest.cc b/service/test/low_energy_client_unittest.cc
index 3bf566c..ce3c7c0 100644
--- a/service/test/low_energy_client_unittest.cc
+++ b/service/test/low_energy_client_unittest.cc
@@ -58,13 +58,13 @@
int connection_state_count() const { return connection_state_count_; }
void OnConnectionState(LowEnergyClient* client, int status,
- const char* address, bool connected) {
+ const char* address, bool connected) override {
ASSERT_TRUE(client);
connection_state_count_++;
}
void OnMtuChanged(LowEnergyClient* client, int status, const char* address,
- int mtu) {
+ int mtu) override {
ASSERT_TRUE(client);
last_mtu_ = mtu;
}
diff --git a/service/test/low_energy_scanner_unittest.cc b/service/test/low_energy_scanner_unittest.cc
index c8b16f3..9a7875d 100644
--- a/service/test/low_energy_scanner_unittest.cc
+++ b/service/test/low_energy_scanner_unittest.cc
@@ -72,12 +72,12 @@
MOCK_METHOD1(StopSync, void(uint16_t));
void ScanFilterAdd(int filter_index, std::vector<ApcfCommand> filters,
- FilterConfigCallback cb){};
+ FilterConfigCallback cb) override{};
void ScanFilterParamSetup(
uint8_t client_if, uint8_t action, uint8_t filt_index,
std::unique_ptr<btgatt_filt_param_setup_t> filt_param,
- FilterParamSetupCallback cb) {
+ FilterParamSetupCallback cb) override {
ScanFilterParamSetupImpl(client_if, action, filt_index, filt_param.get(),
std::move(cb));
}
@@ -92,7 +92,8 @@
int scan_result_count() const { return scan_result_count_; }
const ScanResult& last_scan_result() const { return last_scan_result_; }
- void OnScanResult(LowEnergyScanner* scanner, const ScanResult& scan_result) {
+ void OnScanResult(LowEnergyScanner* scanner,
+ const ScanResult& scan_result) override {
ASSERT_TRUE(scanner);
scan_result_count_++;
last_scan_result_ = scan_result;
diff --git a/service/test/mock_adapter.h b/service/test/mock_adapter.h
index 4b93792..2c496b1 100644
--- a/service/test/mock_adapter.h
+++ b/service/test/mock_adapter.h
@@ -37,11 +37,24 @@
MOCK_CONST_METHOD0(GetName, std::string());
MOCK_METHOD1(SetName, bool(const std::string&));
MOCK_CONST_METHOD0(GetAddress, std::string());
+ MOCK_METHOD1(SetScanMode, bool(int));
+ MOCK_METHOD1(SetScanEnable, bool(bool));
+ MOCK_METHOD4(SspReply, bool(const std::string&, int, bool, int32_t));
+ MOCK_METHOD2(CreateBond,
+ bool(const std::string& device_address, int transport));
MOCK_METHOD0(IsMultiAdvertisementSupported, bool());
MOCK_METHOD1(IsDeviceConnected, bool(const std::string&));
MOCK_METHOD0(GetTotalNumberOfTrackableAdvertisements, int());
MOCK_METHOD0(IsOffloadedFilteringSupported, bool());
MOCK_METHOD0(IsOffloadedScanBatchingSupported, bool());
+ MOCK_METHOD0(GetBondedDevices, bool());
+ MOCK_METHOD1(RemoveBond, bool(const std::string&));
+ MOCK_METHOD1(GetRemoteDeviceProperties,
+ bool(const std::string& device_address));
+ MOCK_CONST_METHOD0(GetA2dpSinkFactory, A2dpSinkFactory*());
+ MOCK_CONST_METHOD0(GetA2dpSourceFactory, A2dpSourceFactory*());
+ MOCK_CONST_METHOD0(GetAvrcpControlFactory, AvrcpControlFactory*());
+ MOCK_CONST_METHOD0(GetAvrcpTargetFactory, AvrcpTargetFactory*());
MOCK_CONST_METHOD0(GetLowEnergyClientFactory, LowEnergyClientFactory*());
MOCK_CONST_METHOD0(GetLeAdvertiserFactory, LowEnergyAdvertiserFactory*());
MOCK_CONST_METHOD0(GetLeScannerFactory, LowEnergyScannerFactory*());
diff --git a/stack/Android.bp b/stack/Android.bp
index 03e2c94..995d381 100644
--- a/stack/Android.bp
+++ b/stack/Android.bp
@@ -1,3 +1,9 @@
+crypto_toolbox_srcs = [
+ "crypto_toolbox/aes.cc",
+ "crypto_toolbox/aes_cmac.cc",
+ "crypto_toolbox/crypto_toolbox.cc",
+]
+
// Bluetooth stack static library for target
// ========================================================
cc_library_static {
@@ -40,7 +46,8 @@
"system/bt/bta/sys",
"system/bt/utils/include",
],
- srcs: [
+ cflags: ["-Wno-implicit-fallthrough"],
+ srcs: crypto_toolbox_srcs + [
"a2dp/a2dp_aac.cc",
"a2dp/a2dp_aac_decoder.cc",
"a2dp/a2dp_aac_encoder.cc",
@@ -57,6 +64,7 @@
"a2dp/a2dp_vendor_aptx_hd_encoder.cc",
"a2dp/a2dp_vendor_ldac.cc",
"a2dp/a2dp_vendor_ldac_abr.cc",
+ "a2dp/a2dp_vendor_ldac_decoder.cc",
"a2dp/a2dp_vendor_ldac_encoder.cc",
"avct/avct_api.cc",
"avct/avct_bcb_act.cc",
@@ -91,6 +99,7 @@
"btm/btm_ble_adv_filter.cc",
"btm/btm_ble_batchscan.cc",
"btm/btm_ble_bgconn.cc",
+ "btm/btm_ble_connection_establishment.cc",
"btm/btm_ble_cont_energy.cc",
"btm/btm_ble_gap.cc",
"btm/btm_ble_multi_adv.cc",
@@ -108,6 +117,7 @@
"gap/gap_ble.cc",
"gap/gap_conn.cc",
"gatt/att_protocol.cc",
+ "gatt/connection_manager.cc",
"gatt/gatt_api.cc",
"gatt/gatt_attr.cc",
"gatt/gatt_auth.cc",
@@ -130,13 +140,6 @@
"l2cap/l2c_main.cc",
"l2cap/l2c_utils.cc",
"l2cap/l2cap_client.cc",
- "mcap/mca_api.cc",
- "mcap/mca_cact.cc",
- "mcap/mca_csm.cc",
- "mcap/mca_dact.cc",
- "mcap/mca_dsm.cc",
- "mcap/mca_l2c.cc",
- "mcap/mca_main.cc",
"pan/pan_api.cc",
"pan/pan_main.cc",
"pan/pan_utils.cc",
@@ -155,19 +158,16 @@
"sdp/sdp_main.cc",
"sdp/sdp_server.cc",
"sdp/sdp_utils.cc",
- "smp/aes.cc",
"smp/p_256_curvepara.cc",
"smp/p_256_ecc_pp.cc",
"smp/p_256_multprecision.cc",
"smp/smp_act.cc",
"smp/smp_api.cc",
"smp/smp_br_main.cc",
- "smp/smp_cmac.cc",
"smp/smp_keys.cc",
"smp/smp_l2c.cc",
"smp/smp_main.cc",
"smp/smp_utils.cc",
- "srvc/srvc_battery.cc",
"srvc/srvc_dis.cc",
"srvc/srvc_eng.cc",
],
@@ -183,7 +183,7 @@
required: [
"libldacBT_enc",
"libldacBT_abr",
- ]
+ ],
}
// Bluetooth stack unit tests for target
@@ -191,6 +191,7 @@
cc_test {
name: "net_test_stack",
defaults: ["fluoride_defaults"],
+ test_suites: ["device-tests"],
local_include_dirs: [
"include",
],
@@ -202,6 +203,7 @@
"test/stack_a2dp_test.cc",
],
shared_libs: [
+ "libcrypto",
"libhidlbase",
"liblog",
"libprotobuf-cpp-lite",
@@ -211,6 +213,7 @@
static_libs: [
"libbt-bta",
"libbt-stack",
+ "libbt-common",
"libbt-sbc-decoder",
"libbt-sbc-encoder",
"libFraunhoferAAC",
@@ -225,53 +228,59 @@
}
cc_test {
- name: "net_test_stack_rfcomm",
- defaults: ["fluoride_defaults"],
- host_supported: true,
- local_include_dirs: [
- "include",
- "btm",
- "l2cap",
- "smp",
- "rfcomm",
- "test/common",
- ],
- include_dirs: [
- "system/bt",
- "system/bt/internal_include",
- "system/bt/btcore/include",
- "system/bt/hci/include",
- "system/bt/utils/include",
- ],
- srcs: [
- "rfcomm/port_api.cc",
- "rfcomm/port_rfc.cc",
- "rfcomm/port_utils.cc",
- "rfcomm/rfc_l2cap_if.cc",
- "rfcomm/rfc_mx_fsm.cc",
- "rfcomm/rfc_port_fsm.cc",
- "rfcomm/rfc_port_if.cc",
- "rfcomm/rfc_ts_frames.cc",
- "rfcomm/rfc_utils.cc",
- "test/common/mock_btm_layer.cc",
- "test/common/mock_btu_layer.cc",
- "test/common/mock_l2cap_layer.cc",
- "test/common/stack_test_packet_utils.cc",
- "test/rfcomm/stack_rfcomm_test.cc",
- "test/rfcomm/stack_rfcomm_test_main.cc",
- "test/rfcomm/stack_rfcomm_test_utils.cc",
- "test/rfcomm/stack_rfcomm_test_utils_test.cc",
- ],
- shared_libs: [
- "libcutils",
- "libprotobuf-cpp-lite",
- ],
- static_libs: [
- "liblog",
- "libgmock",
- "libosi",
- "libbt-protos-lite",
- ],
+ name: "net_test_stack_rfcomm",
+ defaults: ["fluoride_defaults"],
+ test_suites: ["device-tests"],
+ host_supported: true,
+ local_include_dirs: [
+ "include",
+ "btm",
+ "l2cap",
+ "smp",
+ "rfcomm",
+ "test/common",
+ ],
+ include_dirs: [
+ "system/bt",
+ "system/bt/internal_include",
+ "system/bt/btcore/include",
+ "system/bt/hci/include",
+ "system/bt/utils/include",
+ ],
+ srcs: [
+ "rfcomm/port_api.cc",
+ "rfcomm/port_rfc.cc",
+ "rfcomm/port_utils.cc",
+ "rfcomm/rfc_l2cap_if.cc",
+ "rfcomm/rfc_mx_fsm.cc",
+ "rfcomm/rfc_port_fsm.cc",
+ "rfcomm/rfc_port_if.cc",
+ "rfcomm/rfc_ts_frames.cc",
+ "rfcomm/rfc_utils.cc",
+ "test/common/mock_btm_layer.cc",
+ "test/common/mock_btu_layer.cc",
+ "test/common/mock_l2cap_layer.cc",
+ "test/common/stack_test_packet_utils.cc",
+ "test/rfcomm/stack_rfcomm_test.cc",
+ "test/rfcomm/stack_rfcomm_test_main.cc",
+ "test/rfcomm/stack_rfcomm_test_utils.cc",
+ "test/rfcomm/stack_rfcomm_test_utils_test.cc",
+ ],
+ shared_libs: [
+ "libcutils",
+ "libprotobuf-cpp-lite",
+ "libcrypto",
+ ],
+ static_libs: [
+ "liblog",
+ "libgmock",
+ "libosi",
+ "libbt-common",
+ "libbt-protos-lite",
+ ],
+ sanitize: {
+ cfi: false,
+ },
}
// Bluetooth stack smp unit tests for target
@@ -279,6 +288,7 @@
cc_test {
name: "net_test_stack_smp",
defaults: ["fluoride_defaults"],
+ test_suites: ["device-tests"],
local_include_dirs: [
"include",
"btm",
@@ -292,15 +302,15 @@
"system/bt/hci/include",
"system/bt/utils/include",
],
- srcs: [
+ srcs: crypto_toolbox_srcs + [
"smp/smp_keys.cc",
- "smp/aes.cc",
"smp/p_256_curvepara.cc",
"smp/p_256_ecc_pp.cc",
"smp/p_256_multprecision.cc",
"smp/smp_api.cc",
"smp/smp_main.cc",
"smp/smp_utils.cc",
+ "test/crypto_toolbox_test.cc",
"test/stack_smp_test.cc",
],
shared_libs: [
@@ -313,12 +323,12 @@
],
}
-
// Bluetooth stack multi-advertising unit tests for target
// ========================================================
cc_test {
name: "net_test_stack_multi_adv",
defaults: ["fluoride_defaults"],
+ test_suites: ["device-tests"],
local_include_dirs: [
"include",
"btm",
@@ -353,6 +363,7 @@
cc_test {
name: "net_test_stack_ad_parser",
defaults: ["fluoride_defaults"],
+ test_suites: ["device-tests"],
local_include_dirs: [
"include",
],
@@ -391,6 +402,7 @@
"libprotobuf-cpp-lite",
],
static_libs: [
+ "libbt-common",
"libbluetooth-types",
"libgmock",
"libosi",
@@ -400,3 +412,37 @@
cfi: false,
},
}
+
+// Bluetooth stack connection multiplexing
+// ========================================================
+cc_test {
+ name: "net_test_gatt_conn_multiplexing",
+ defaults: ["fluoride_defaults"],
+ local_include_dirs: [
+ "include",
+ "btm",
+ ],
+ include_dirs: [
+ "system/bt",
+ "system/bt/internal_include",
+ "system/bt/btcore/include",
+ "system/bt/hci/include",
+ "system/bt/internal_include",
+ "system/bt/utils/include",
+ ],
+ srcs: [
+ "gatt/connection_manager.cc",
+ "test/gatt_connection_manager_test.cc",
+ ],
+ shared_libs: [
+ "libcutils",
+ ],
+ static_libs: [
+ "libbluetooth-types",
+ "liblog",
+ "libgmock",
+ ],
+ sanitize: {
+ cfi: false,
+ },
+}
diff --git a/stack/BUILD.gn b/stack/BUILD.gn
index 6f3c55a..00680c8 100644
--- a/stack/BUILD.gn
+++ b/stack/BUILD.gn
@@ -14,6 +14,22 @@
# limitations under the License.
#
+static_library("crypto_toolbox") {
+ sources = [
+ "crypto_toolbox/crypto_toolbox.cc",
+ "crypto_toolbox/aes.cc",
+ "crypto_toolbox/aes_cmac.cc",
+ ]
+
+ include_dirs = [
+ "//",
+ ]
+
+ deps = [
+ "//third_party/libchrome:base",
+ ]
+}
+
static_library("stack") {
sources = [
"a2dp/a2dp_aac.cc",
@@ -32,6 +48,7 @@
"a2dp/a2dp_vendor_aptx_hd_encoder.cc",
"a2dp/a2dp_vendor_ldac.cc",
"a2dp/a2dp_vendor_ldac_abr.cc",
+ "a2dp/a2dp_vendor_ldac_decoder.cc",
"a2dp/a2dp_vendor_ldac_encoder.cc",
"avct/avct_api.cc",
"avct/avct_bcb_act.cc",
@@ -83,6 +100,7 @@
"gap/gap_ble.cc",
"gap/gap_conn.cc",
"gatt/att_protocol.cc",
+ "gatt/connection_manager.cc",
"gatt/gatt_api.cc",
"gatt/gatt_attr.cc",
"gatt/gatt_auth.cc",
@@ -105,13 +123,6 @@
"l2cap/l2c_main.cc",
"l2cap/l2c_utils.cc",
"l2cap/l2cap_client.cc",
- "mcap/mca_api.cc",
- "mcap/mca_cact.cc",
- "mcap/mca_csm.cc",
- "mcap/mca_dact.cc",
- "mcap/mca_dsm.cc",
- "mcap/mca_l2c.cc",
- "mcap/mca_main.cc",
"pan/pan_api.cc",
"pan/pan_main.cc",
"pan/pan_utils.cc",
@@ -130,19 +141,16 @@
"sdp/sdp_main.cc",
"sdp/sdp_server.cc",
"sdp/sdp_utils.cc",
- "smp/aes.cc",
"smp/p_256_curvepara.cc",
"smp/p_256_ecc_pp.cc",
"smp/p_256_multprecision.cc",
"smp/smp_act.cc",
"smp/smp_api.cc",
"smp/smp_br_main.cc",
- "smp/smp_cmac.cc",
"smp/smp_keys.cc",
"smp/smp_l2c.cc",
"smp/smp_main.cc",
"smp/smp_utils.cc",
- "srvc/srvc_battery.cc",
"srvc/srvc_dis.cc",
"srvc/srvc_eng.cc",
]
@@ -162,6 +170,8 @@
"sdp",
"smp",
"srvc",
+ "//linux_include",
+ "//internal_include",
"//btcore/include",
"//vnd/include",
"//vnd/ble",
@@ -179,6 +189,7 @@
]
deps = [
+ ":crypto_toolbox",
"//types",
"//third_party/libchrome:base",
"//third_party/libldac:libldacBT_enc",
@@ -226,6 +237,7 @@
"//btcore",
"//device",
"//embdrv/sbc",
+ "//embdrv/g722",
"//hci",
"//types",
"//main:bluetooth",
@@ -234,6 +246,77 @@
]
}
+executable("net_test_stack_crypto_toolbox") {
+ testonly = true
+ sources = [
+ "test/crypto_toolbox_test.cc",
+ ]
+
+ include_dirs = [
+ "//",
+ ]
+
+ deps = [
+ ":crypto_toolbox",
+ "//third_party/googletest:gmock_main",
+ "//third_party/libchrome:base",
+ ]
+}
+
+executable("net_test_stack_smp") {
+ testonly = true
+ sources = [
+ "smp/p_256_curvepara.cc",
+ "smp/p_256_ecc_pp.cc",
+ "smp/p_256_multprecision.cc",
+ "smp/smp_keys.cc",
+ "smp/smp_api.cc",
+ "smp/smp_main.cc",
+ "smp/smp_utils.cc",
+ "test/stack_smp_test.cc",
+ ]
+
+ include_dirs = [
+ "//",
+ "//linux_include",
+ "//internal_include",
+ "//btcore/include",
+ "//hci/include",
+ "//utils/include",
+ "//bta/include",
+ "//bta/sys",
+ "//btcore/include",
+ "//embdrv/sbc/encoder/include",
+ "//hci/include",
+ "//internal_include",
+ "//stack/a2dp",
+ "//stack/l2cap",
+ "//stack/btm",
+ "//stack/include",
+ "//third_party/tinyxml2",
+ "//udrv/include",
+ "//utils/include",
+ "//vnd/include"
+ ]
+
+ libs = [
+ "-ldl",
+ "-lpthread",
+ "-lresolv",
+ "-lrt",
+ "-lz",
+ "-latomic",
+ ]
+
+ deps = [
+ ":crypto_toolbox",
+ "//osi",
+ "//types",
+ "//third_party/googletest:gmock_main",
+ "//third_party/libchrome:base",
+ ]
+}
+
executable("net_test_stack_multi_adv") {
testonly = true
sources = [
diff --git a/stack/a2dp/a2dp_aac.cc b/stack/a2dp/a2dp_aac.cc
index 7792631..df641be 100644
--- a/stack/a2dp/a2dp_aac.cc
+++ b/stack/a2dp/a2dp_aac.cc
@@ -191,7 +191,18 @@
(*(p_codec_info + 2) & A2DP_AAC_BIT_RATE_MASK2);
p_codec_info += 3;
- if (is_capability) return A2DP_SUCCESS;
+ if (is_capability) {
+ // NOTE: The checks here are very liberal. We should be using more
+ // pedantic checks specific to the SRC or SNK as specified in the spec.
+ if (A2DP_BitsSet(p_ie->objectType) == A2DP_SET_ZERO_BIT)
+ return A2DP_BAD_OBJ_TYPE;
+ if (A2DP_BitsSet(p_ie->sampleRate) == A2DP_SET_ZERO_BIT)
+ return A2DP_BAD_SAMP_FREQ;
+ if (A2DP_BitsSet(p_ie->channelMode) == A2DP_SET_ZERO_BIT)
+ return A2DP_BAD_CH_MODE;
+
+ return A2DP_SUCCESS;
+ }
if (A2DP_BitsSet(p_ie->objectType) != A2DP_SET_ONE_BIT)
return A2DP_BAD_OBJ_TYPE;
@@ -391,6 +402,21 @@
return -1;
}
+int A2DP_GetTrackBitsPerSampleAac(const uint8_t* p_codec_info) {
+ tA2DP_AAC_CIE aac_cie;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoAac(&aac_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ // NOTE: The bits per sample never changes for AAC
+ return 16;
+}
+
int A2DP_GetTrackChannelCountAac(const uint8_t* p_codec_info) {
tA2DP_AAC_CIE aac_cie;
@@ -1324,6 +1350,7 @@
sizeof(ota_codec_peer_config_));
return false;
}
+
bool A2dpCodecConfigAacBase::setPeerCodecCapabilities(
const uint8_t* p_peer_codec_capabilities) {
std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
@@ -1415,7 +1442,7 @@
return true;
}
-period_ms_t A2dpCodecConfigAacSink::encoderIntervalMs() const {
+uint64_t A2dpCodecConfigAacSink::encoderIntervalMs() const {
// TODO: This method applies only to Source codecs
return 0;
}
diff --git a/stack/a2dp/a2dp_aac_encoder.cc b/stack/a2dp/a2dp_aac_encoder.cc
index 43b6181..f6c68a6 100644
--- a/stack/a2dp/a2dp_aac_encoder.cc
+++ b/stack/a2dp/a2dp_aac_encoder.cc
@@ -27,6 +27,7 @@
#include "a2dp_aac.h"
#include "bt_common.h"
+#include "common/time_util.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
@@ -37,12 +38,6 @@
// A2DP AAC encoder interval in milliseconds
#define A2DP_AAC_ENCODER_INTERVAL_MS 20
-/*
- * 2DH5 payload size of:
- * 679 bytes - (4 bytes L2CAP Header + 12 bytes AVDTP Header)
- */
-#define MAX_2MBPS_AVDTP_MTU 663
-
// offset
#if (BTA_AV_CO_CP_SCMS_T == TRUE)
#define A2DP_AAC_OFFSET (AVDT_MEDIA_OFFSET + 1)
@@ -131,7 +126,8 @@
aacEncClose(&a2dp_aac_encoder_cb.aac_handle);
memset(&a2dp_aac_encoder_cb, 0, sizeof(a2dp_aac_encoder_cb));
- a2dp_aac_encoder_cb.stats.session_start_us = time_get_os_boottime_us();
+ a2dp_aac_encoder_cb.stats.session_start_us =
+ bluetooth::common::time_get_os_boottime_us();
a2dp_aac_encoder_cb.read_callback = read_callback;
a2dp_aac_encoder_cb.enqueue_callback = enqueue_callback;
@@ -483,7 +479,7 @@
a2dp_aac_encoder_cb.aac_feeding_state.counter = 0;
}
-period_ms_t a2dp_aac_get_encoder_interval_ms(void) {
+uint64_t a2dp_aac_get_encoder_interval_ms(void) {
return A2DP_AAC_ENCODER_INTERVAL_MS;
}
@@ -694,7 +690,7 @@
return true;
}
-period_ms_t A2dpCodecConfigAacSource::encoderIntervalMs() const {
+uint64_t A2dpCodecConfigAacSource::encoderIntervalMs() const {
return a2dp_aac_get_encoder_interval_ms();
}
diff --git a/stack/a2dp/a2dp_codec_config.cc b/stack/a2dp/a2dp_codec_config.cc
index 47856fe..edf7e0c 100644
--- a/stack/a2dp/a2dp_codec_config.cc
+++ b/stack/a2dp/a2dp_codec_config.cc
@@ -129,7 +129,10 @@
codec_config = new A2dpCodecConfigAptxHd(codec_priority);
break;
case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC:
- codec_config = new A2dpCodecConfigLdac(codec_priority);
+ codec_config = new A2dpCodecConfigLdacSource(codec_priority);
+ break;
+ case BTAV_A2DP_CODEC_INDEX_SINK_LDAC:
+ codec_config = new A2dpCodecConfigLdacSink(codec_priority);
break;
case BTAV_A2DP_CODEC_INDEX_MAX:
break;
@@ -188,6 +191,8 @@
codec_config[4]; // blk_len | subbands | Alloc Method
p_a2dp_offload->codec_info[1] = codec_config[5]; // Min bit pool
p_a2dp_offload->codec_info[2] = codec_config[6]; // Max bit pool
+ p_a2dp_offload->codec_info[3] =
+ codec_config[3]; // Sample freq | channel mode
break;
case A2DP_MEDIA_CT_AAC:
p_a2dp_offload->codec_info[0] = codec_config[3]; // object type
@@ -220,13 +225,18 @@
p_a2dp_offload->codec_info[6] =
A2DP_LDAC_QUALITY_LOW; // Low birate
break;
- case 3: // fall through
+ case 3:
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
default:
p_a2dp_offload->codec_info[6] =
A2DP_LDAC_QUALITY_ABR_OFFLOAD; // ABR in offload
break;
}
}
+ p_a2dp_offload->codec_info[7] =
+ codec_config[10]; // LDAC specific channel mode
+ LOG_VERBOSE(LOG_TAG, "%s: Ldac specific channelmode =%d", __func__,
+ p_a2dp_offload->codec_info[7]);
}
break;
default:
@@ -668,6 +678,11 @@
return iter->second;
}
+bool A2dpCodecs::isSupportedCodec(btav_a2dp_codec_index_t codec_index) {
+ std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+ return indexed_codecs_.find(codec_index) != indexed_codecs_.end();
+}
+
bool A2dpCodecs::setCodecConfig(const uint8_t* p_peer_codec_info,
bool is_capability,
uint8_t* p_result_codec_config,
@@ -1214,6 +1229,26 @@
return -1;
}
+int A2DP_GetTrackBitsPerSample(const uint8_t* p_codec_info) {
+ tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+ LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+ switch (codec_type) {
+ case A2DP_MEDIA_CT_SBC:
+ return A2DP_GetTrackBitsPerSampleSbc(p_codec_info);
+ case A2DP_MEDIA_CT_AAC:
+ return A2DP_GetTrackBitsPerSampleAac(p_codec_info);
+ case A2DP_MEDIA_CT_NON_A2DP:
+ return A2DP_VendorGetTrackBitsPerSample(p_codec_info);
+ default:
+ break;
+ }
+
+ LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+ return -1;
+}
+
int A2DP_GetTrackChannelCount(const uint8_t* p_codec_info) {
tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
diff --git a/stack/a2dp/a2dp_sbc.cc b/stack/a2dp/a2dp_sbc.cc
index bef5bf9..4c48993 100644
--- a/stack/a2dp/a2dp_sbc.cc
+++ b/stack/a2dp/a2dp_sbc.cc
@@ -197,7 +197,22 @@
return A2DP_BAD_MAX_BITPOOL;
}
- if (is_capability) return A2DP_SUCCESS;
+ if (is_capability) {
+ // NOTE: The checks here are very liberal. We should be using more
+ // pedantic checks specific to the SRC or SNK as specified in the spec.
+ if (A2DP_BitsSet(p_ie->samp_freq) == A2DP_SET_ZERO_BIT)
+ return A2DP_BAD_SAMP_FREQ;
+ if (A2DP_BitsSet(p_ie->ch_mode) == A2DP_SET_ZERO_BIT)
+ return A2DP_BAD_CH_MODE;
+ if (A2DP_BitsSet(p_ie->block_len) == A2DP_SET_ZERO_BIT)
+ return A2DP_BAD_BLOCK_LEN;
+ if (A2DP_BitsSet(p_ie->num_subbands) == A2DP_SET_ZERO_BIT)
+ return A2DP_BAD_SUBBANDS;
+ if (A2DP_BitsSet(p_ie->alloc_method) == A2DP_SET_ZERO_BIT)
+ return A2DP_BAD_ALLOC_METHOD;
+
+ return A2DP_SUCCESS;
+ }
if (A2DP_BitsSet(p_ie->samp_freq) != A2DP_SET_ONE_BIT)
return A2DP_BAD_SAMP_FREQ;
@@ -468,6 +483,20 @@
return -1;
}
+int A2DP_GetTrackBitsPerSampleSbc(const uint8_t* p_codec_info) {
+ tA2DP_SBC_CIE sbc_cie;
+
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ // NOTE: The bits per sample never changes for SBC
+ return 16;
+}
+
int A2DP_GetTrackChannelCountSbc(const uint8_t* p_codec_info) {
tA2DP_SBC_CIE sbc_cie;
@@ -840,8 +869,8 @@
A2dpCodecConfigSbcSource::A2dpCodecConfigSbcSource(
btav_a2dp_codec_priority_t codec_priority)
- : A2dpCodecConfigSbcBase(BTAV_A2DP_CODEC_INDEX_SOURCE_SBC, "SBC",
- codec_priority, true) {
+ : A2dpCodecConfigSbcBase(BTAV_A2DP_CODEC_INDEX_SOURCE_SBC,
+ A2DP_CodecIndexStrSbc(), codec_priority, true) {
// Compute the local capability
if (a2dp_sbc_source_caps.samp_freq & A2DP_SBC_IE_SAMP_FREQ_44) {
codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
@@ -1525,8 +1554,9 @@
A2dpCodecConfigSbcSink::A2dpCodecConfigSbcSink(
btav_a2dp_codec_priority_t codec_priority)
- : A2dpCodecConfigSbcBase(BTAV_A2DP_CODEC_INDEX_SINK_SBC, "SBC(Sink)",
- codec_priority, false) {}
+ : A2dpCodecConfigSbcBase(BTAV_A2DP_CODEC_INDEX_SINK_SBC,
+ A2DP_CodecIndexStrSbcSink(), codec_priority,
+ false) {}
A2dpCodecConfigSbcSink::~A2dpCodecConfigSbcSink() {}
@@ -1555,7 +1585,7 @@
return false;
}
-period_ms_t A2dpCodecConfigSbcSink::encoderIntervalMs() const {
+uint64_t A2dpCodecConfigSbcSink::encoderIntervalMs() const {
// TODO: This method applies only to Source codecs
return 0;
}
diff --git a/stack/a2dp/a2dp_sbc_encoder.cc b/stack/a2dp/a2dp_sbc_encoder.cc
index bd09989..aac7e6d 100644
--- a/stack/a2dp/a2dp_sbc_encoder.cc
+++ b/stack/a2dp/a2dp_sbc_encoder.cc
@@ -28,6 +28,7 @@
#include "a2dp_sbc.h"
#include "a2dp_sbc_up_sample.h"
#include "bt_common.h"
+#include "common/time_util.h"
#include "embdrv/sbc/encoder/include/sbc_encoder.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
@@ -43,11 +44,6 @@
#define A2DP_SBC_NON_EDR_MAX_RATE 229
-/*
- * 2DH5 payload size of:
- * 679 bytes - (4 bytes L2CAP Header + 12 bytes AVDTP Header)
- */
-#define MAX_2MBPS_AVDTP_MTU 663
#define A2DP_SBC_MAX_PCM_ITER_NUM_PER_TICK 3
#define A2DP_SBC_MAX_HQ_FRAME_SIZE_44_1 119
@@ -142,7 +138,8 @@
a2dp_source_enqueue_callback_t enqueue_callback) {
memset(&a2dp_sbc_encoder_cb, 0, sizeof(a2dp_sbc_encoder_cb));
- a2dp_sbc_encoder_cb.stats.session_start_us = time_get_os_boottime_us();
+ a2dp_sbc_encoder_cb.stats.session_start_us =
+ bluetooth::common::time_get_os_boottime_us();
a2dp_sbc_encoder_cb.read_callback = read_callback;
a2dp_sbc_encoder_cb.enqueue_callback = enqueue_callback;
@@ -399,7 +396,7 @@
a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue = 0;
}
-period_ms_t a2dp_sbc_get_encoder_interval_ms(void) {
+uint64_t a2dp_sbc_get_encoder_interval_ms(void) {
return A2DP_SBC_ENCODER_INTERVAL_MS;
}
@@ -860,7 +857,7 @@
switch (p_encoder_params->s16ChannelMode) {
case SBC_MONO:
- /* FALLTHROUGH */
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case SBC_DUAL:
frame_len = A2DP_SBC_FRAME_HEADER_SIZE_BYTES +
((uint32_t)(A2DP_SBC_SCALE_FACTOR_BITS *
@@ -909,7 +906,7 @@
return p_encoder_params->u16BitRate * 1000;
}
-period_ms_t A2dpCodecConfigSbcSource::encoderIntervalMs() const {
+uint64_t A2dpCodecConfigSbcSource::encoderIntervalMs() const {
return a2dp_sbc_get_encoder_interval_ms();
}
diff --git a/stack/a2dp/a2dp_vendor.cc b/stack/a2dp/a2dp_vendor.cc
index 1a6dcc2..bcea13d 100644
--- a/stack/a2dp/a2dp_vendor.cc
+++ b/stack/a2dp/a2dp_vendor.cc
@@ -54,24 +54,33 @@
return false;
}
-bool A2DP_IsVendorSinkCodecValid(UNUSED_ATTR const uint8_t* p_codec_info) {
- // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
- // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+bool A2DP_IsVendorSinkCodecValid(const uint8_t* p_codec_info) {
+ uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+ uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
// Add checks based on <vendor_id, codec_id>
// NOTE: Should be done only for local Sink codecs.
+ // Check for LDAC
+ if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+ return A2DP_IsVendorSinkCodecValidLdac(p_codec_info);
+ }
+
return false;
}
-bool A2DP_IsVendorPeerSourceCodecValid(
- UNUSED_ATTR const uint8_t* p_codec_info) {
- // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
- // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+bool A2DP_IsVendorPeerSourceCodecValid(const uint8_t* p_codec_info) {
+ uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+ uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
// Add checks based on <vendor_id, codec_id>
// NOTE: Should be done only for local Sink codecs.
+ // Check for LDAC
+ if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+ return A2DP_IsVendorPeerSourceCodecValidLdac(p_codec_info);
+ }
+
return false;
}
@@ -101,24 +110,33 @@
return false;
}
-bool A2DP_IsVendorSinkCodecSupported(UNUSED_ATTR const uint8_t* p_codec_info) {
- // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
- // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+bool A2DP_IsVendorSinkCodecSupported(const uint8_t* p_codec_info) {
+ uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+ uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
// Add checks based on <vendor_id, codec_id>
// NOTE: Should be done only for local Sink codecs.
+ // Check for LDAC
+ if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+ return A2DP_IsVendorSinkCodecSupportedLdac(p_codec_info);
+ }
+
return false;
}
-bool A2DP_IsVendorPeerSourceCodecSupported(
- UNUSED_ATTR const uint8_t* p_codec_info) {
- // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
- // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+bool A2DP_IsVendorPeerSourceCodecSupported(const uint8_t* p_codec_info) {
+ uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+ uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
// Add checks based on <vendor_id, codec_id> and peer codec capabilities
// NOTE: Should be done only for local Sink codecs.
+ // Check for LDAC
+ if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+ return A2DP_IsPeerSourceCodecSupportedLdac(p_codec_info);
+ }
+
return false;
}
@@ -170,7 +188,7 @@
return true;
}
-const char* A2DP_VendorCodecName(UNUSED_ATTR const uint8_t* p_codec_info) {
+const char* A2DP_VendorCodecName(const uint8_t* p_codec_info) {
uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
@@ -328,6 +346,32 @@
return -1;
}
+int A2DP_VendorGetTrackBitsPerSample(const uint8_t* p_codec_info) {
+ uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+ uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+ // Check for aptX
+ if (vendor_id == A2DP_APTX_VENDOR_ID &&
+ codec_id == A2DP_APTX_CODEC_ID_BLUETOOTH) {
+ return A2DP_VendorGetTrackBitsPerSampleAptx(p_codec_info);
+ }
+
+ // Check for aptX-HD
+ if (vendor_id == A2DP_APTX_HD_VENDOR_ID &&
+ codec_id == A2DP_APTX_HD_CODEC_ID_BLUETOOTH) {
+ return A2DP_VendorGetTrackBitsPerSampleAptxHd(p_codec_info);
+ }
+
+ // Check for LDAC
+ if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+ return A2DP_VendorGetTrackBitsPerSampleLdac(p_codec_info);
+ }
+
+ // Add checks based on <vendor_id, codec_id>
+
+ return -1;
+}
+
int A2DP_VendorGetTrackChannelCount(const uint8_t* p_codec_info) {
uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
@@ -354,14 +398,18 @@
return -1;
}
-int A2DP_VendorGetSinkTrackChannelType(
- UNUSED_ATTR const uint8_t* p_codec_info) {
- // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
- // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+int A2DP_VendorGetSinkTrackChannelType(const uint8_t* p_codec_info) {
+ uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+ uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
// Add checks based on <vendor_id, codec_id>
// NOTE: Should be done only for local Sink codecs.
+ // Check for LDAC
+ if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+ return A2DP_VendorGetSinkTrackChannelTypeLdac(p_codec_info);
+ }
+
return -1;
}
@@ -453,7 +501,17 @@
const tA2DP_DECODER_INTERFACE* A2DP_VendorGetDecoderInterface(
const uint8_t* p_codec_info) {
- // We do not support vendor codecs for decoding right now.
+ uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+ uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+ // Add checks based on <vendor_id, codec_id>
+ // NOTE: Should be done only for local Sink codecs.
+
+ // Check for LDAC
+ if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+ return A2DP_VendorGetDecoderInterfaceLdac(p_codec_info);
+ }
+
return NULL;
}
@@ -511,10 +569,16 @@
}
btav_a2dp_codec_index_t A2DP_VendorSinkCodecIndex(const uint8_t* p_codec_info) {
- // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
- // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+ uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+ uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
// Add checks based on <vendor_id, codec_id>
+ // NOTE: Should be done only for local Sink codecs.
+
+ // Check for LDAC
+ if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+ return A2DP_VendorSinkCodecIndexLdac(p_codec_info);
+ }
return BTAV_A2DP_CODEC_INDEX_MAX;
}
@@ -533,6 +597,8 @@
return A2DP_VendorCodecIndexStrAptxHd();
case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC:
return A2DP_VendorCodecIndexStrLdac();
+ case BTAV_A2DP_CODEC_INDEX_SINK_LDAC:
+ return A2DP_VendorCodecIndexStrLdacSink();
// Add a switch statement for each vendor-specific codec
case BTAV_A2DP_CODEC_INDEX_MAX:
break;
@@ -556,6 +622,8 @@
return A2DP_VendorInitCodecConfigAptxHd(p_cfg);
case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC:
return A2DP_VendorInitCodecConfigLdac(p_cfg);
+ case BTAV_A2DP_CODEC_INDEX_SINK_LDAC:
+ return A2DP_VendorInitCodecConfigLdacSink(p_cfg);
// Add a switch statement for each vendor-specific codec
case BTAV_A2DP_CODEC_INDEX_MAX:
break;
diff --git a/stack/a2dp/a2dp_vendor_aptx.cc b/stack/a2dp/a2dp_vendor_aptx.cc
index 7017f06..e3e844d 100644
--- a/stack/a2dp/a2dp_vendor_aptx.cc
+++ b/stack/a2dp/a2dp_vendor_aptx.cc
@@ -155,7 +155,16 @@
p_ie->sampleRate = *p_codec_info & 0xF0;
p_codec_info++;
- if (is_capability) return A2DP_SUCCESS;
+ if (is_capability) {
+ // NOTE: The checks here are very liberal. We should be using more
+ // pedantic checks specific to the SRC or SNK as specified in the spec.
+ if (A2DP_BitsSet(p_ie->sampleRate) == A2DP_SET_ZERO_BIT)
+ return A2DP_BAD_SAMP_FREQ;
+ if (A2DP_BitsSet(p_ie->channelMode) == A2DP_SET_ZERO_BIT)
+ return A2DP_BAD_CH_MODE;
+
+ return A2DP_SUCCESS;
+ }
if (A2DP_BitsSet(p_ie->sampleRate) != A2DP_SET_ONE_BIT)
return A2DP_BAD_SAMP_FREQ;
@@ -304,6 +313,21 @@
return -1;
}
+int A2DP_VendorGetTrackBitsPerSampleAptx(const uint8_t* p_codec_info) {
+ tA2DP_APTX_CIE aptx_cie;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoAptx(&aptx_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ // NOTE: The bits per sample never changes for aptX
+ return 16;
+}
+
int A2DP_VendorGetTrackChannelCountAptx(const uint8_t* p_codec_info) {
tA2DP_APTX_CIE aptx_cie;
@@ -419,8 +443,8 @@
A2dpCodecConfigAptx::A2dpCodecConfigAptx(
btav_a2dp_codec_priority_t codec_priority)
- : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_APTX, "aptX",
- codec_priority) {
+ : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_APTX,
+ A2DP_VendorCodecIndexStrAptx(), codec_priority) {
// Compute the local capability
if (a2dp_aptx_source_caps.sampleRate & A2DP_APTX_SAMPLERATE_44100) {
codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
diff --git a/stack/a2dp/a2dp_vendor_aptx_encoder.cc b/stack/a2dp/a2dp_vendor_aptx_encoder.cc
index 0252935..e7d0145 100644
--- a/stack/a2dp/a2dp_vendor_aptx_encoder.cc
+++ b/stack/a2dp/a2dp_vendor_aptx_encoder.cc
@@ -26,6 +26,8 @@
#include "a2dp_vendor.h"
#include "a2dp_vendor_aptx.h"
#include "bt_common.h"
+#include "common/scoped_scs_exit.h"
+#include "common/time_util.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
@@ -53,6 +55,25 @@
static tAPTX_ENCODER_ENCODE_STEREO aptx_encoder_encode_stereo_func;
static tAPTX_ENCODER_SIZEOF_PARAMS aptx_encoder_sizeof_params_func;
+__attribute__((no_sanitize("shadow-call-stack")))
+static int aptx_encoder_init(void* state, short endian) {
+ ScopedSCSExit x;
+ return aptx_encoder_init_func(state, endian);
+}
+
+__attribute__((no_sanitize("shadow-call-stack")))
+static int aptx_encoder_encode_stereo(void* state, void* pcmL, void* pcmR,
+ void* buffer) {
+ ScopedSCSExit x;
+ return aptx_encoder_encode_stereo_func(state, pcmL, pcmR, buffer);
+}
+
+__attribute__((no_sanitize("shadow-call-stack")))
+static int aptx_encoder_sizeof_params() {
+ ScopedSCSExit x;
+ return aptx_encoder_sizeof_params_func();
+}
+
// offset
#if (BTA_AV_CO_CP_SCMS_T == TRUE)
#define A2DP_APTX_OFFSET (AVDT_MEDIA_OFFSET + 1)
@@ -174,7 +195,8 @@
a2dp_source_enqueue_callback_t enqueue_callback) {
memset(&a2dp_aptx_encoder_cb, 0, sizeof(a2dp_aptx_encoder_cb));
- a2dp_aptx_encoder_cb.stats.session_start_us = time_get_os_boottime_us();
+ a2dp_aptx_encoder_cb.stats.session_start_us =
+ bluetooth::common::time_get_os_boottime_us();
a2dp_aptx_encoder_cb.read_callback = read_callback;
a2dp_aptx_encoder_cb.enqueue_callback = enqueue_callback;
@@ -190,9 +212,9 @@
#endif
a2dp_aptx_encoder_cb.aptx_encoder_state =
- osi_malloc(aptx_encoder_sizeof_params_func());
+ osi_malloc(aptx_encoder_sizeof_params());
if (a2dp_aptx_encoder_cb.aptx_encoder_state != NULL) {
- aptx_encoder_init_func(a2dp_aptx_encoder_cb.aptx_encoder_state, 0);
+ aptx_encoder_init(a2dp_aptx_encoder_cb.aptx_encoder_state, 0);
} else {
LOG_ERROR(LOG_TAG, "%s: Cannot allocate aptX encoder state", __func__);
// TODO: Return an error?
@@ -369,7 +391,7 @@
aptx_init_framing_params(&a2dp_aptx_encoder_cb.framing_params);
}
-period_ms_t a2dp_vendor_aptx_get_encoder_interval_ms(void) {
+uint64_t a2dp_vendor_aptx_get_encoder_interval_ms(void) {
return a2dp_aptx_encoder_cb.framing_params.sleep_time_ns / (1000 * 1000);
}
@@ -464,8 +486,8 @@
pcmR[i] = (uint16_t) * (data16_in + ((2 * j) + 1));
}
- aptx_encoder_encode_stereo_func(a2dp_aptx_encoder_cb.aptx_encoder_state,
- &pcmL, &pcmR, &encoded_sample);
+ aptx_encoder_encode_stereo(a2dp_aptx_encoder_cb.aptx_encoder_state, &pcmL,
+ &pcmR, &encoded_sample);
data_out[*data_out_index + 0] = (uint8_t)((encoded_sample[0] >> 8) & 0xff);
data_out[*data_out_index + 1] = (uint8_t)((encoded_sample[0] >> 0) & 0xff);
@@ -480,7 +502,7 @@
return pcm_bytes_encoded;
}
-period_ms_t A2dpCodecConfigAptx::encoderIntervalMs() const {
+uint64_t A2dpCodecConfigAptx::encoderIntervalMs() const {
return a2dp_vendor_aptx_get_encoder_interval_ms();
}
diff --git a/stack/a2dp/a2dp_vendor_aptx_hd.cc b/stack/a2dp/a2dp_vendor_aptx_hd.cc
index 798e4fd..9e19d5f 100644
--- a/stack/a2dp/a2dp_vendor_aptx_hd.cc
+++ b/stack/a2dp/a2dp_vendor_aptx_hd.cc
@@ -171,7 +171,16 @@
p_ie->acl_sprint_reserved2 = *(p_codec_info++);
p_ie->acl_sprint_reserved3 = *(p_codec_info++);
- if (is_capability) return A2DP_SUCCESS;
+ if (is_capability) {
+ // NOTE: The checks here are very liberal. We should be using more
+ // pedantic checks specific to the SRC or SNK as specified in the spec.
+ if (A2DP_BitsSet(p_ie->sampleRate) == A2DP_SET_ZERO_BIT)
+ return A2DP_BAD_SAMP_FREQ;
+ if (A2DP_BitsSet(p_ie->channelMode) == A2DP_SET_ZERO_BIT)
+ return A2DP_BAD_CH_MODE;
+
+ return A2DP_SUCCESS;
+ }
if (A2DP_BitsSet(p_ie->sampleRate) != A2DP_SET_ONE_BIT)
return A2DP_BAD_SAMP_FREQ;
@@ -319,6 +328,22 @@
return -1;
}
+int A2DP_VendorGetTrackBitsPerSampleAptxHd(const uint8_t* p_codec_info) {
+ tA2DP_APTX_HD_CIE aptx_hd_cie;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status =
+ A2DP_ParseInfoAptxHd(&aptx_hd_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ // NOTE: The bits per sample never changes for aptX-HD
+ return 24;
+}
+
int A2DP_VendorGetTrackChannelCountAptxHd(const uint8_t* p_codec_info) {
tA2DP_APTX_HD_CIE aptx_hd_cie;
@@ -436,8 +461,8 @@
A2dpCodecConfigAptxHd::A2dpCodecConfigAptxHd(
btav_a2dp_codec_priority_t codec_priority)
- : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD, "aptX-HD",
- codec_priority) {
+ : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD,
+ A2DP_VendorCodecIndexStrAptxHd(), codec_priority) {
// Compute the local capability
if (a2dp_aptx_hd_source_caps.sampleRate & A2DP_APTX_HD_SAMPLERATE_44100) {
codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
diff --git a/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc b/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc
index d72ec5a..d271e0d 100644
--- a/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc
+++ b/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc
@@ -26,6 +26,8 @@
#include "a2dp_vendor.h"
#include "a2dp_vendor_aptx_hd.h"
#include "bt_common.h"
+#include "common/scoped_scs_exit.h"
+#include "common/time_util.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
@@ -54,6 +56,25 @@
static tAPTX_HD_ENCODER_ENCODE_STEREO aptx_hd_encoder_encode_stereo_func;
static tAPTX_HD_ENCODER_SIZEOF_PARAMS aptx_hd_encoder_sizeof_params_func;
+__attribute__((no_sanitize("shadow-call-stack")))
+static int aptx_hd_encoder_init(void* state, short endian) {
+ ScopedSCSExit x;
+ return aptx_hd_encoder_init_func(state, endian);
+}
+
+__attribute__((no_sanitize("shadow-call-stack")))
+static int aptx_hd_encoder_encode_stereo(void* state, void* pcmL, void* pcmR,
+ void* buffer) {
+ ScopedSCSExit x;
+ return aptx_hd_encoder_encode_stereo_func(state, pcmL, pcmR, buffer);
+}
+
+__attribute__((no_sanitize("shadow-call-stack")))
+static int aptx_hd_encoder_sizeof_params() {
+ ScopedSCSExit x;
+ return aptx_hd_encoder_sizeof_params_func();
+}
+
// offset
#if (BTA_AV_CO_CP_SCMS_T == TRUE)
#define A2DP_APTX_HD_OFFSET (AVDT_MEDIA_OFFSET + 1)
@@ -174,7 +195,8 @@
a2dp_source_enqueue_callback_t enqueue_callback) {
memset(&a2dp_aptx_hd_encoder_cb, 0, sizeof(a2dp_aptx_hd_encoder_cb));
- a2dp_aptx_hd_encoder_cb.stats.session_start_us = time_get_os_boottime_us();
+ a2dp_aptx_hd_encoder_cb.stats.session_start_us =
+ bluetooth::common::time_get_os_boottime_us();
a2dp_aptx_hd_encoder_cb.read_callback = read_callback;
a2dp_aptx_hd_encoder_cb.enqueue_callback = enqueue_callback;
@@ -191,9 +213,9 @@
#endif
a2dp_aptx_hd_encoder_cb.aptx_hd_encoder_state =
- osi_malloc(aptx_hd_encoder_sizeof_params_func());
+ osi_malloc(aptx_hd_encoder_sizeof_params());
if (a2dp_aptx_hd_encoder_cb.aptx_hd_encoder_state != NULL) {
- aptx_hd_encoder_init_func(a2dp_aptx_hd_encoder_cb.aptx_hd_encoder_state, 0);
+ aptx_hd_encoder_init(a2dp_aptx_hd_encoder_cb.aptx_hd_encoder_state, 0);
} else {
LOG_ERROR(LOG_TAG, "%s: Cannot allocate aptX-HD encoder state", __func__);
// TODO: Return an error?
@@ -353,7 +375,7 @@
aptx_hd_init_framing_params(&a2dp_aptx_hd_encoder_cb.framing_params);
}
-period_ms_t a2dp_vendor_aptx_hd_get_encoder_interval_ms(void) {
+uint64_t a2dp_vendor_aptx_hd_get_encoder_interval_ms(void) {
return a2dp_aptx_hd_encoder_cb.framing_params.sleep_time_ns / (1000 * 1000);
}
@@ -458,7 +480,7 @@
p += 3;
}
- aptx_hd_encoder_encode_stereo_func(
+ aptx_hd_encoder_encode_stereo(
a2dp_aptx_hd_encoder_cb.aptx_hd_encoder_state, &pcmL, &pcmR,
&encoded_sample);
@@ -477,7 +499,7 @@
return pcm_bytes_encoded;
}
-period_ms_t A2dpCodecConfigAptxHd::encoderIntervalMs() const {
+uint64_t A2dpCodecConfigAptxHd::encoderIntervalMs() const {
return a2dp_vendor_aptx_hd_get_encoder_interval_ms();
}
diff --git a/stack/a2dp/a2dp_vendor_ldac.cc b/stack/a2dp/a2dp_vendor_ldac.cc
index 266db81..4949e74 100644
--- a/stack/a2dp/a2dp_vendor_ldac.cc
+++ b/stack/a2dp/a2dp_vendor_ldac.cc
@@ -31,6 +31,7 @@
#include <base/logging.h>
#include "a2dp_vendor.h"
+#include "a2dp_vendor_ldac_decoder.h"
#include "a2dp_vendor_ldac_encoder.h"
#include "bt_utils.h"
#include "btif_av_co.h"
@@ -60,6 +61,19 @@
(BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16 | BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24 |
BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32)};
+/* LDAC Sink codec capabilities */
+static const tA2DP_LDAC_CIE a2dp_ldac_sink_caps = {
+ A2DP_LDAC_VENDOR_ID, // vendorId
+ A2DP_LDAC_CODEC_ID, // codecId
+ // sampleRate
+ (A2DP_LDAC_SAMPLING_FREQ_44100 | A2DP_LDAC_SAMPLING_FREQ_48000 |
+ A2DP_LDAC_SAMPLING_FREQ_88200 | A2DP_LDAC_SAMPLING_FREQ_96000),
+ // channelMode
+ (A2DP_LDAC_CHANNEL_MODE_DUAL | A2DP_LDAC_CHANNEL_MODE_STEREO),
+ // bits_per_sample
+ (BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16 | BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24 |
+ BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32)};
+
/* Default LDAC codec configuration */
static const tA2DP_LDAC_CIE a2dp_ldac_default_config = {
A2DP_LDAC_VENDOR_ID, // vendorId
@@ -78,6 +92,12 @@
a2dp_vendor_ldac_send_frames,
a2dp_vendor_ldac_set_transmit_queue_length};
+static const tA2DP_DECODER_INTERFACE a2dp_decoder_interface_ldac = {
+ a2dp_vendor_ldac_decoder_init,
+ a2dp_vendor_ldac_decoder_cleanup,
+ a2dp_vendor_ldac_decoder_decode_packet,
+};
+
UNUSED_ATTR static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilityLdac(
const tA2DP_LDAC_CIE* p_cap, const uint8_t* p_codec_info,
bool is_peer_codec_info);
@@ -162,7 +182,16 @@
p_ie->sampleRate = *p_codec_info++ & A2DP_LDAC_SAMPLING_FREQ_MASK;
p_ie->channelMode = *p_codec_info++ & A2DP_LDAC_CHANNEL_MODE_MASK;
- if (is_capability) return A2DP_SUCCESS;
+ if (is_capability) {
+ // NOTE: The checks here are very liberal. We should be using more
+ // pedantic checks specific to the SRC or SNK as specified in the spec.
+ if (A2DP_BitsSet(p_ie->sampleRate) == A2DP_SET_ZERO_BIT)
+ return A2DP_BAD_SAMP_FREQ;
+ if (A2DP_BitsSet(p_ie->channelMode) == A2DP_SET_ZERO_BIT)
+ return A2DP_BAD_CH_MODE;
+
+ return A2DP_SUCCESS;
+ }
if (A2DP_BitsSet(p_ie->sampleRate) != A2DP_SET_ONE_BIT)
return A2DP_BAD_SAMP_FREQ;
@@ -199,6 +228,22 @@
(A2DP_ParseInfoLdac(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
}
+bool A2DP_IsVendorSinkCodecValidLdac(const uint8_t* p_codec_info) {
+ tA2DP_LDAC_CIE cfg_cie;
+
+ /* Use a liberal check when parsing the codec info */
+ return (A2DP_ParseInfoLdac(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+ (A2DP_ParseInfoLdac(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
+}
+
+bool A2DP_IsVendorPeerSourceCodecValidLdac(const uint8_t* p_codec_info) {
+ tA2DP_LDAC_CIE cfg_cie;
+
+ /* Use a liberal check when parsing the codec info */
+ return (A2DP_ParseInfoLdac(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+ (A2DP_ParseInfoLdac(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
+}
+
bool A2DP_IsVendorPeerSinkCodecValidLdac(const uint8_t* p_codec_info) {
tA2DP_LDAC_CIE cfg_cie;
@@ -207,6 +252,15 @@
(A2DP_ParseInfoLdac(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
}
+bool A2DP_IsVendorSinkCodecSupportedLdac(const uint8_t* p_codec_info) {
+ return A2DP_CodecInfoMatchesCapabilityLdac(&a2dp_ldac_sink_caps, p_codec_info,
+ false) == A2DP_SUCCESS;
+}
+bool A2DP_IsPeerSourceCodecSupportedLdac(const uint8_t* p_codec_info) {
+ return A2DP_CodecInfoMatchesCapabilityLdac(&a2dp_ldac_sink_caps, p_codec_info,
+ true) == A2DP_SUCCESS;
+}
+
// Checks whether A2DP LDAC codec configuration matches with a device's codec
// capabilities. |p_cap| is the LDAC codec configuration. |p_codec_info| is
// the device's codec capabilities.
@@ -361,6 +415,35 @@
return -1;
}
+int A2DP_VendorGetTrackBitsPerSampleLdac(const uint8_t* p_codec_info) {
+ tA2DP_LDAC_CIE ldac_cie;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoLdac(&ldac_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+#if 1
+ return 32;
+#else
+ // TODO : Implement proc to care about bit per sample in A2DP_ParseInfoLdac()
+
+ switch (ldac_cie.bits_per_sample) {
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
+ return 16;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24:
+ return 24;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32:
+ return 32;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE:
+ return -1;
+ }
+#endif
+}
+
int A2DP_VendorGetTrackChannelCountLdac(const uint8_t* p_codec_info) {
tA2DP_LDAC_CIE ldac_cie;
@@ -384,6 +467,29 @@
return -1;
}
+int A2DP_VendorGetSinkTrackChannelTypeLdac(const uint8_t* p_codec_info) {
+ tA2DP_LDAC_CIE ldac_cie;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoLdac(&ldac_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ switch (ldac_cie.channelMode) {
+ case A2DP_LDAC_CHANNEL_MODE_MONO:
+ return 1;
+ case A2DP_LDAC_CHANNEL_MODE_DUAL:
+ return 3;
+ case A2DP_LDAC_CHANNEL_MODE_STEREO:
+ return 3;
+ }
+
+ return -1;
+}
+
int A2DP_VendorGetChannelModeCodeLdac(const uint8_t* p_codec_info) {
tA2DP_LDAC_CIE ldac_cie;
@@ -483,6 +589,13 @@
return &a2dp_encoder_interface_ldac;
}
+const tA2DP_DECODER_INTERFACE* A2DP_VendorGetDecoderInterfaceLdac(
+ const uint8_t* p_codec_info) {
+ if (!A2DP_IsVendorSinkCodecValidLdac(p_codec_info)) return NULL;
+
+ return &a2dp_decoder_interface_ldac;
+}
+
bool A2DP_VendorAdjustCodecLdac(uint8_t* p_codec_info) {
tA2DP_LDAC_CIE cfg_cie;
@@ -498,8 +611,15 @@
return BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC;
}
+btav_a2dp_codec_index_t A2DP_VendorSinkCodecIndexLdac(
+ UNUSED_ATTR const uint8_t* p_codec_info) {
+ return BTAV_A2DP_CODEC_INDEX_SINK_LDAC;
+}
+
const char* A2DP_VendorCodecIndexStrLdac(void) { return "LDAC"; }
+const char* A2DP_VendorCodecIndexStrLdacSink(void) { return "LDAC SINK"; }
+
bool A2DP_VendorInitCodecConfigLdac(AvdtpSepConfig* p_cfg) {
if (A2DP_BuildInfoLdac(AVDT_MEDIA_TYPE_AUDIO, &a2dp_ldac_source_caps,
p_cfg->codec_info) != A2DP_SUCCESS) {
@@ -517,6 +637,11 @@
return true;
}
+bool A2DP_VendorInitCodecConfigLdacSink(AvdtpSepConfig* p_cfg) {
+ return A2DP_BuildInfoLdac(AVDT_MEDIA_TYPE_AUDIO, &a2dp_ldac_sink_caps,
+ p_cfg->codec_info) == A2DP_SUCCESS;
+}
+
UNUSED_ATTR static void build_codec_config(const tA2DP_LDAC_CIE& config_cie,
btav_a2dp_codec_config_t* result) {
if (config_cie.sampleRate & A2DP_LDAC_SAMPLING_FREQ_44100)
@@ -542,10 +667,11 @@
}
}
-A2dpCodecConfigLdac::A2dpCodecConfigLdac(
+A2dpCodecConfigLdacSource::A2dpCodecConfigLdacSource(
btav_a2dp_codec_priority_t codec_priority)
- : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC, "LDAC",
- codec_priority) {
+ : A2dpCodecConfigLdacBase(BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC,
+ A2DP_VendorCodecIndexStrLdac(), codec_priority,
+ true) {
// Compute the local capability
if (a2dp_ldac_source_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_44100) {
codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
@@ -578,9 +704,9 @@
}
}
-A2dpCodecConfigLdac::~A2dpCodecConfigLdac() {}
+A2dpCodecConfigLdacSource::~A2dpCodecConfigLdacSource() {}
-bool A2dpCodecConfigLdac::init() {
+bool A2dpCodecConfigLdacSource::init() {
if (!isValid()) return false;
// Load the encoder
@@ -592,7 +718,7 @@
return true;
}
-bool A2dpCodecConfigLdac::useRtpHeaderMarkerBit() const { return false; }
+bool A2dpCodecConfigLdacSource::useRtpHeaderMarkerBit() const { return false; }
//
// Selects the best sample rate from |sampleRate|.
@@ -822,15 +948,17 @@
return false;
}
-bool A2dpCodecConfigLdac::setCodecConfig(const uint8_t* p_peer_codec_info,
- bool is_capability,
- uint8_t* p_result_codec_config) {
+bool A2dpCodecConfigLdacBase::setCodecConfig(const uint8_t* p_peer_codec_info,
+ bool is_capability,
+ uint8_t* p_result_codec_config) {
std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
tA2DP_LDAC_CIE peer_info_cie;
tA2DP_LDAC_CIE result_config_cie;
uint8_t channelMode;
uint8_t sampleRate;
btav_a2dp_codec_bits_per_sample_t bits_per_sample;
+ const tA2DP_LDAC_CIE* p_a2dp_ldac_caps =
+ (is_source_) ? &a2dp_ldac_source_caps : &a2dp_ldac_sink_caps;
// Save the internal state
btav_a2dp_codec_config_t saved_codec_config = codec_config_;
@@ -860,13 +988,13 @@
// Build the preferred configuration
//
memset(&result_config_cie, 0, sizeof(result_config_cie));
- result_config_cie.vendorId = a2dp_ldac_source_caps.vendorId;
- result_config_cie.codecId = a2dp_ldac_source_caps.codecId;
+ result_config_cie.vendorId = p_a2dp_ldac_caps->vendorId;
+ result_config_cie.codecId = p_a2dp_ldac_caps->codecId;
//
// Select the sample frequency
//
- sampleRate = a2dp_ldac_source_caps.sampleRate & peer_info_cie.sampleRate;
+ sampleRate = p_a2dp_ldac_caps->sampleRate & peer_info_cie.sampleRate;
codec_config_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
switch (codec_user_config_.sample_rate) {
case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
@@ -910,6 +1038,7 @@
codec_capability_.sample_rate = codec_user_config_.sample_rate;
codec_config_.sample_rate = codec_user_config_.sample_rate;
}
+ break;
case BTAV_A2DP_CODEC_SAMPLE_RATE_16000:
case BTAV_A2DP_CODEC_SAMPLE_RATE_24000:
case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
@@ -985,8 +1114,7 @@
LOG_ERROR(LOG_TAG,
"%s: cannot match sample frequency: local caps = 0x%x "
"peer info = 0x%x",
- __func__, a2dp_ldac_source_caps.sampleRate,
- peer_info_cie.sampleRate);
+ __func__, p_a2dp_ldac_caps->sampleRate, peer_info_cie.sampleRate);
goto fail;
}
@@ -995,7 +1123,7 @@
//
// NOTE: this information is NOT included in the LDAC A2DP codec description
// that is sent OTA.
- bits_per_sample = a2dp_ldac_source_caps.bits_per_sample;
+ bits_per_sample = p_a2dp_ldac_caps->bits_per_sample;
codec_config_.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
switch (codec_user_config_.bits_per_sample) {
case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
@@ -1030,7 +1158,7 @@
do {
// Compute the selectable capability
codec_selectable_capability_.bits_per_sample =
- a2dp_ldac_source_caps.bits_per_sample;
+ p_a2dp_ldac_caps->bits_per_sample;
if (codec_config_.bits_per_sample != BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE)
break;
@@ -1040,7 +1168,7 @@
// No user preference - the the codec audio config
if (select_audio_bits_per_sample(&codec_audio_config_,
- a2dp_ldac_source_caps.bits_per_sample,
+ p_a2dp_ldac_caps->bits_per_sample,
&result_config_cie, &codec_config_)) {
break;
}
@@ -1052,7 +1180,7 @@
}
// No user preference - use the best match
- if (select_best_bits_per_sample(a2dp_ldac_source_caps.bits_per_sample,
+ if (select_best_bits_per_sample(p_a2dp_ldac_caps->bits_per_sample,
&result_config_cie, &codec_config_)) {
break;
}
@@ -1069,7 +1197,7 @@
//
// Select the channel mode
//
- channelMode = a2dp_ldac_source_caps.channelMode & peer_info_cie.channelMode;
+ channelMode = p_a2dp_ldac_caps->channelMode & peer_info_cie.channelMode;
codec_config_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
switch (codec_user_config_.channel_mode) {
case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
@@ -1148,7 +1276,7 @@
LOG_ERROR(LOG_TAG,
"%s: cannot match channel mode: local caps = 0x%x "
"peer info = 0x%x",
- __func__, a2dp_ldac_source_caps.channelMode,
+ __func__, p_a2dp_ldac_caps->channelMode,
peer_info_cie.channelMode);
goto fail;
}
@@ -1200,12 +1328,14 @@
return false;
}
-bool A2dpCodecConfigLdac::setPeerCodecCapabilities(
+bool A2dpCodecConfigLdacBase::setPeerCodecCapabilities(
const uint8_t* p_peer_codec_capabilities) {
std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
tA2DP_LDAC_CIE peer_info_cie;
uint8_t channelMode;
uint8_t sampleRate;
+ const tA2DP_LDAC_CIE* p_a2dp_ldac_caps =
+ (is_source_) ? &a2dp_ldac_source_caps : &a2dp_ldac_sink_caps;
// Save the internal state
btav_a2dp_codec_config_t saved_codec_selectable_capability =
@@ -1223,7 +1353,7 @@
}
// Compute the selectable capability - sample rate
- sampleRate = a2dp_ldac_source_caps.sampleRate & peer_info_cie.sampleRate;
+ sampleRate = p_a2dp_ldac_caps->sampleRate & peer_info_cie.sampleRate;
if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_44100) {
codec_selectable_capability_.sample_rate |=
BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
@@ -1251,10 +1381,10 @@
// Compute the selectable capability - bits per sample
codec_selectable_capability_.bits_per_sample =
- a2dp_ldac_source_caps.bits_per_sample;
+ p_a2dp_ldac_caps->bits_per_sample;
// Compute the selectable capability - channel mode
- channelMode = a2dp_ldac_source_caps.channelMode & peer_info_cie.channelMode;
+ channelMode = p_a2dp_ldac_caps->channelMode & peer_info_cie.channelMode;
if (channelMode & A2DP_LDAC_CHANNEL_MODE_MONO) {
codec_selectable_capability_.channel_mode |=
BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
@@ -1280,3 +1410,46 @@
sizeof(ota_codec_peer_capability_));
return false;
}
+
+A2dpCodecConfigLdacSink::A2dpCodecConfigLdacSink(
+ btav_a2dp_codec_priority_t codec_priority)
+ : A2dpCodecConfigLdacBase(BTAV_A2DP_CODEC_INDEX_SINK_LDAC,
+ A2DP_VendorCodecIndexStrLdacSink(),
+ codec_priority, false) {}
+
+A2dpCodecConfigLdacSink::~A2dpCodecConfigLdacSink() {}
+
+bool A2dpCodecConfigLdacSink::init() {
+ if (!isValid()) return false;
+
+ // Load the decoder
+ if (!A2DP_VendorLoadDecoderLdac()) {
+ LOG_ERROR(LOG_TAG, "%s: cannot load the decoder", __func__);
+ return false;
+ }
+
+ return true;
+}
+
+uint64_t A2dpCodecConfigLdacSink::encoderIntervalMs() const {
+ // TODO: This method applies only to Source codecs
+ return 0;
+}
+
+int A2dpCodecConfigLdacSink::getEffectiveMtu() const {
+ // TODO: This method applies only to Source codecs
+ return 0;
+}
+
+bool A2dpCodecConfigLdacSink::useRtpHeaderMarkerBit() const {
+ // TODO: This method applies only to Source codecs
+ return false;
+}
+
+bool A2dpCodecConfigLdacSink::updateEncoderUserConfig(
+ UNUSED_ATTR const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ UNUSED_ATTR bool* p_restart_input, UNUSED_ATTR bool* p_restart_output,
+ UNUSED_ATTR bool* p_config_updated) {
+ // TODO: This method applies only to Source codecs
+ return false;
+}
diff --git a/stack/a2dp/a2dp_vendor_ldac_decoder.cc b/stack/a2dp/a2dp_vendor_ldac_decoder.cc
new file mode 100644
index 0000000..444af34
--- /dev/null
+++ b/stack/a2dp/a2dp_vendor_ldac_decoder.cc
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2016 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 "a2dp_vendor_ldac_decoder"
+#define ATRACE_TAG ATRACE_TAG_AUDIO
+
+#include "a2dp_vendor_ldac_decoder.h"
+
+#ifndef OS_GENERIC
+#include <cutils/trace.h>
+#endif
+#include <dlfcn.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <ldacBT.h>
+
+#include "a2dp_vendor.h"
+#include "a2dp_vendor_ldac.h"
+#include "bt_common.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+//
+// Decoder for LDAC Source Codec
+//
+
+//
+// The LDAC decoder shared library, and the functions to use
+//
+static const char* LDAC_DECODER_LIB_NAME = "libldacBT_dec.so";
+static void* ldac_decoder_lib_handle = NULL;
+
+static const char* LDAC_GET_HANDLE_NAME = "ldacBT_get_handle";
+typedef HANDLE_LDAC_BT (*tLDAC_GET_HANDLE)(void);
+
+static const char* LDAC_FREE_HANDLE_NAME = "ldacBT_free_handle";
+typedef void (*tLDAC_FREE_HANDLE)(HANDLE_LDAC_BT hLdacParam);
+
+static const char* LDAC_CLOSE_HANDLE_NAME = "ldacBT_close_handle";
+typedef void (*tLDAC_CLOSE_HANDLE)(HANDLE_LDAC_BT hLdacParam);
+
+static const char* LDAC_GET_VERSION_NAME = "ldacBT_get_version";
+typedef int (*tLDAC_GET_VERSION)(void);
+
+static const char* LDAC_GET_BITRATE_NAME = "ldacBT_get_bitrate";
+typedef int (*tLDAC_GET_BITRATE)(HANDLE_LDAC_BT hLdacParam);
+
+static const char* LDAC_GET_SAMPLING_FREQ_NAME = "ldacBT_get_sampling_freq";
+typedef int (*tLDAC_GET_SAMPLING_FREQ)(HANDLE_LDAC_BT hLdacParam);
+
+static const char* LDAC_INIT_HANDLE_DECODE_NAME = "ldacBT_init_handle_decode";
+typedef int (*tLDAC_INIT_HANDLE_DECODE)(HANDLE_LDAC_BT hLdacParam, int cm,
+ int sf, int var0, int var1, int var2);
+
+static const char* LDAC_DECODE_NAME = "ldacBT_decode";
+typedef int (*tLDAC_DECODE)(HANDLE_LDAC_BT hLdacBt, unsigned char* p_bs,
+ unsigned char* p_pcm, LDACBT_SMPL_FMT_T fmt,
+ int bs_bytes, int* used_bytes, int* wrote_bytes);
+
+static const char* LDAC_GET_ERROR_CODE_NAME = "ldacBT_get_error_code";
+typedef int (*tLDAC_GET_ERROR_CODE)(HANDLE_LDAC_BT hLdacParam);
+
+static tLDAC_GET_HANDLE ldac_get_handle_func;
+static tLDAC_FREE_HANDLE ldac_free_handle_func;
+static tLDAC_CLOSE_HANDLE ldac_close_handle_func;
+static tLDAC_GET_VERSION ldac_get_version_func;
+static tLDAC_GET_BITRATE ldac_get_bitrate_func;
+static tLDAC_GET_SAMPLING_FREQ ldac_get_sampling_freq_func;
+static tLDAC_INIT_HANDLE_DECODE ldac_init_handle_decode_func;
+static tLDAC_DECODE ldac_decode_func;
+static tLDAC_GET_ERROR_CODE ldac_get_error_code_func;
+
+// offset
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+#define A2DP_LDAC_OFFSET (AVDT_MEDIA_OFFSET + A2DP_LDAC_MPL_HDR_LEN + 1)
+#else
+#define A2DP_LDAC_OFFSET (AVDT_MEDIA_OFFSET + A2DP_LDAC_MPL_HDR_LEN)
+#endif
+
+typedef struct {
+ uint32_t sample_rate;
+ uint8_t channel_mode;
+ uint8_t bits_per_sample;
+ int pcm_wlength;
+ LDACBT_SMPL_FMT_T pcm_fmt;
+} tA2DP_LDAC_DECODER_PARAMS;
+
+typedef struct {
+ bool use_SCMS_T;
+ bool is_peer_edr; // True if the peer device supports EDR
+ bool peer_supports_3mbps; // True if the peer device supports 3Mbps EDR
+ uint16_t peer_mtu; // MTU of the A2DP peer
+ uint32_t timestamp; // Timestamp for the A2DP frames
+
+ HANDLE_LDAC_BT ldac_handle;
+ bool has_ldac_handle; // True if ldac_handle is valid
+ unsigned char* decode_buf;
+ decoded_data_callback_t decode_callback;
+} tA2DP_LDAC_DECODER_CB;
+
+static tA2DP_LDAC_DECODER_CB a2dp_ldac_decoder_cb;
+
+static void* load_func(const char* func_name) {
+ void* func_ptr = dlsym(ldac_decoder_lib_handle, func_name);
+ if (func_ptr == NULL) {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot find function '%s' in the decoder library: %s",
+ __func__, func_name, dlerror());
+ A2DP_VendorUnloadDecoderLdac();
+ return NULL;
+ }
+ return func_ptr;
+}
+
+bool A2DP_VendorLoadDecoderLdac(void) {
+ if (ldac_decoder_lib_handle != NULL) return true; // Already loaded
+
+ // Initialize the control block
+ memset(&a2dp_ldac_decoder_cb, 0, sizeof(a2dp_ldac_decoder_cb));
+
+ // Open the decoder library
+ ldac_decoder_lib_handle = dlopen(LDAC_DECODER_LIB_NAME, RTLD_NOW);
+ if (ldac_decoder_lib_handle == NULL) {
+ LOG_ERROR(LOG_TAG, "%s: cannot open LDAC decoder library %s: %s", __func__,
+ LDAC_DECODER_LIB_NAME, dlerror());
+ return false;
+ }
+
+ // Load all functions
+ ldac_get_handle_func = (tLDAC_GET_HANDLE)load_func(LDAC_GET_HANDLE_NAME);
+ if (ldac_get_handle_func == NULL) return false;
+ ldac_free_handle_func = (tLDAC_FREE_HANDLE)load_func(LDAC_FREE_HANDLE_NAME);
+ if (ldac_free_handle_func == NULL) return false;
+ ldac_close_handle_func =
+ (tLDAC_CLOSE_HANDLE)load_func(LDAC_CLOSE_HANDLE_NAME);
+ if (ldac_close_handle_func == NULL) return false;
+ ldac_get_version_func = (tLDAC_GET_VERSION)load_func(LDAC_GET_VERSION_NAME);
+ if (ldac_get_version_func == NULL) return false;
+ ldac_get_bitrate_func = (tLDAC_GET_BITRATE)load_func(LDAC_GET_BITRATE_NAME);
+ if (ldac_get_bitrate_func == NULL) return false;
+ ldac_get_sampling_freq_func =
+ (tLDAC_GET_SAMPLING_FREQ)load_func(LDAC_GET_SAMPLING_FREQ_NAME);
+ if (ldac_get_sampling_freq_func == NULL) return false;
+ ldac_init_handle_decode_func =
+ (tLDAC_INIT_HANDLE_DECODE)load_func(LDAC_INIT_HANDLE_DECODE_NAME);
+ if (ldac_init_handle_decode_func == NULL) return false;
+ ldac_decode_func = (tLDAC_DECODE)load_func(LDAC_DECODE_NAME);
+ if (ldac_decode_func == NULL) return false;
+ ldac_get_error_code_func =
+ (tLDAC_GET_ERROR_CODE)load_func(LDAC_GET_ERROR_CODE_NAME);
+ if (ldac_get_error_code_func == NULL) return false;
+
+ return true;
+}
+
+void A2DP_VendorUnloadDecoderLdac(void) {
+ // Cleanup any LDAC-related state
+ if (a2dp_ldac_decoder_cb.has_ldac_handle && ldac_free_handle_func != NULL)
+ ldac_free_handle_func(a2dp_ldac_decoder_cb.ldac_handle);
+ memset(&a2dp_ldac_decoder_cb, 0, sizeof(a2dp_ldac_decoder_cb));
+
+ ldac_get_handle_func = NULL;
+ ldac_free_handle_func = NULL;
+ ldac_close_handle_func = NULL;
+ ldac_get_version_func = NULL;
+ ldac_get_bitrate_func = NULL;
+ ldac_get_sampling_freq_func = NULL;
+ ldac_init_handle_decode_func = NULL;
+ ldac_decode_func = NULL;
+ ldac_get_error_code_func = NULL;
+
+ if (ldac_decoder_lib_handle != NULL) {
+ dlclose(ldac_decoder_lib_handle);
+ ldac_decoder_lib_handle = NULL;
+ }
+}
+
+bool a2dp_vendor_ldac_decoder_init(decoded_data_callback_t decode_callback) {
+ if (a2dp_ldac_decoder_cb.has_ldac_handle)
+ ldac_free_handle_func(a2dp_ldac_decoder_cb.ldac_handle);
+ memset(&a2dp_ldac_decoder_cb, 0, sizeof(a2dp_ldac_decoder_cb));
+
+ a2dp_vendor_ldac_decoder_cleanup();
+
+ a2dp_ldac_decoder_cb.ldac_handle = ldac_get_handle_func();
+ a2dp_ldac_decoder_cb.has_ldac_handle = true;
+ a2dp_ldac_decoder_cb.decode_buf = static_cast<unsigned char*>(
+ osi_malloc(sizeof(a2dp_ldac_decoder_cb.decode_buf[0]) * LDACBT_MAX_LSU *
+ LDAC_PRCNCH * sizeof(int)));
+ a2dp_ldac_decoder_cb.decode_callback = decode_callback;
+
+ // initialize
+ ldac_init_handle_decode_func(a2dp_ldac_decoder_cb.ldac_handle,
+ LDACBT_CHANNEL_MODE_STEREO, 96000, 0, 0, 0);
+ return true;
+}
+
+void a2dp_vendor_ldac_decoder_cleanup(void) {
+ if (a2dp_ldac_decoder_cb.has_ldac_handle)
+ ldac_free_handle_func(a2dp_ldac_decoder_cb.ldac_handle);
+ memset(&a2dp_ldac_decoder_cb, 0, sizeof(a2dp_ldac_decoder_cb));
+}
+
+bool a2dp_vendor_ldac_decoder_decode_packet(BT_HDR* p_buf) {
+ unsigned char* pBuffer =
+ reinterpret_cast<unsigned char*>(p_buf->data + p_buf->offset);
+ // unsigned int bufferSize = p_buf->len;
+ unsigned int bytesValid = p_buf->len;
+ int err;
+ LDACBT_SMPL_FMT_T fmt;
+ int bs_bytes, used_bytes, wrote_bytes, frame_number;
+
+ fmt = LDACBT_SMPL_FMT_S32;
+ frame_number = (int)pBuffer[0];
+ pBuffer++;
+ bs_bytes = (int)bytesValid - 1;
+ bytesValid -= 1;
+ LOG_VERBOSE(LOG_TAG, "%s:INPUT size : %d, frame : %d", __func__, bs_bytes,
+ frame_number);
+
+ while (bytesValid > 0) {
+#if 0
+ err = ldacDecoder_Fill(a2dp_ldac_decoder_cb.ldac_handle,
+ &pBuffer, &bufferSize, &bytesValid);
+ if (err != LDACBT_ERR_NONE) {
+ LOG_ERROR(LOG_TAG, "%s: ldacDecoder_Fill failed: 0x%x", __func__,
+ static_cast<unsigned>(err));
+ return false;
+ }
+#endif
+ while (true) {
+ // Todo : implement LDAC Buffer Control Operation instead of
+ // ldac_decode_func().
+ err = ldac_decode_func(a2dp_ldac_decoder_cb.ldac_handle, pBuffer,
+ a2dp_ldac_decoder_cb.decode_buf, fmt, bs_bytes,
+ &used_bytes, &wrote_bytes);
+ // if (err == LDAC_DEC_NOT_ENOUGH_FRAMES) {
+ // break;
+ // }
+ if (LDACBT_ERROR(err)) {
+ err = ldac_get_error_code_func(a2dp_ldac_decoder_cb.ldac_handle);
+ LOG_ERROR(LOG_TAG, "%s: ldacDecoder_DecodeFrame failed: %d:%d:%d",
+ __func__, LDACBT_API_ERR(err), LDACBT_HANDLE_ERR(err),
+ LDACBT_BLOCK_ERR(err));
+ if (LDACBT_FATAL(err)) {
+ break;
+ }
+ }
+
+ if (wrote_bytes > 0) {
+ size_t frame_len = (size_t)wrote_bytes;
+ a2dp_ldac_decoder_cb.decode_callback(
+ reinterpret_cast<uint8_t*>(a2dp_ldac_decoder_cb.decode_buf),
+ frame_len);
+ }
+ pBuffer += used_bytes;
+ bs_bytes -= used_bytes;
+ if (bs_bytes <= 1) {
+ bytesValid = 0;
+ break;
+ }
+ }
+ }
+
+ return true;
+}
diff --git a/stack/a2dp/a2dp_vendor_ldac_encoder.cc b/stack/a2dp/a2dp_vendor_ldac_encoder.cc
index 21d5e72..ca6c2fc 100644
--- a/stack/a2dp/a2dp_vendor_ldac_encoder.cc
+++ b/stack/a2dp/a2dp_vendor_ldac_encoder.cc
@@ -33,6 +33,7 @@
#include "a2dp_vendor_ldac.h"
#include "a2dp_vendor_ldac_abr.h"
#include "bt_common.h"
+#include "common/time_util.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
@@ -285,7 +286,8 @@
a2dp_ldac_abr_free_handle(a2dp_ldac_encoder_cb.ldac_abr_handle);
memset(&a2dp_ldac_encoder_cb, 0, sizeof(a2dp_ldac_encoder_cb));
- a2dp_ldac_encoder_cb.stats.session_start_us = time_get_os_boottime_us();
+ a2dp_ldac_encoder_cb.stats.session_start_us =
+ bluetooth::common::time_get_os_boottime_us();
a2dp_ldac_encoder_cb.read_callback = read_callback;
a2dp_ldac_encoder_cb.enqueue_callback = enqueue_callback;
@@ -313,7 +315,7 @@
&restart_output, &config_updated);
}
-bool A2dpCodecConfigLdac::updateEncoderUserConfig(
+bool A2dpCodecConfigLdacSource::updateEncoderUserConfig(
const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params, bool* p_restart_input,
bool* p_restart_output, bool* p_config_updated) {
a2dp_ldac_encoder_cb.is_peer_edr = p_peer_params->is_peer_edr;
@@ -533,7 +535,7 @@
a2dp_ldac_encoder_cb.ldac_feeding_state.counter = 0;
}
-period_ms_t a2dp_vendor_ldac_get_encoder_interval_ms(void) {
+uint64_t a2dp_vendor_ldac_get_encoder_interval_ms(void) {
return A2DP_LDAC_ENCODER_INTERVAL_MS;
}
@@ -759,15 +761,15 @@
a2dp_ldac_encoder_cb.TxQueueLength = transmit_queue_length;
}
-period_ms_t A2dpCodecConfigLdac::encoderIntervalMs() const {
+uint64_t A2dpCodecConfigLdacSource::encoderIntervalMs() const {
return a2dp_vendor_ldac_get_encoder_interval_ms();
}
-int A2dpCodecConfigLdac::getEffectiveMtu() const {
+int A2dpCodecConfigLdacSource::getEffectiveMtu() const {
return a2dp_ldac_encoder_cb.TxAaMtuSize;
}
-void A2dpCodecConfigLdac::debug_codec_dump(int fd) {
+void A2dpCodecConfigLdacSource::debug_codec_dump(int fd) {
a2dp_ldac_encoder_stats_t* stats = &a2dp_ldac_encoder_cb.stats;
tA2DP_LDAC_ENCODER_PARAMS* p_encoder_params =
&a2dp_ldac_encoder_cb.ldac_encoder_params;
diff --git a/stack/avdt/avdt_api.cc b/stack/avdt/avdt_api.cc
index 43954b4..903862e 100644
--- a/stack/avdt/avdt_api.cc
+++ b/stack/avdt/avdt_api.cc
@@ -1212,6 +1212,8 @@
}
void stack_debug_avdtp_api_dump(int fd) {
+ if (appl_trace_level < BT_TRACE_LEVEL_DEBUG) return;
+
dprintf(fd, "\nAVDTP Stack State:\n");
dprintf(fd, " AVDTP signalling L2CAP channel MTU: %d\n",
avdtp_cb.rcb.ctrl_mtu);
@@ -1219,6 +1221,9 @@
for (size_t i = 0; i < AVDT_NUM_LINKS; i++) {
const AvdtpCcb& ccb = avdtp_cb.ccb[i];
+ if (ccb.peer_addr.IsEmpty()) {
+ continue;
+ }
dprintf(fd, "\n Channel control block: %zu peer: %s\n", i,
ccb.peer_addr.ToString().c_str());
dprintf(fd, " Allocated: %s\n", ccb.allocated ? "true" : "false");
@@ -1235,6 +1240,9 @@
for (size_t i = 0; i < AVDT_NUM_SEPS; i++) {
const AvdtpScb& scb = ccb.scb[i];
+ if (!scb.in_use) {
+ continue;
+ }
dprintf(fd, "\n Stream control block: %zu\n", i);
dprintf(fd, " SEP codec: %s\n",
A2DP_CodecName(scb.stream_config.cfg.codec_info));
diff --git a/stack/avdt/avdt_ccb_act.cc b/stack/avdt/avdt_ccb_act.cc
index 52f3857..3059d8a 100644
--- a/stack/avdt/avdt_ccb_act.cc
+++ b/stack/avdt/avdt_ccb_act.cc
@@ -122,7 +122,7 @@
if (i == AVDT_NUM_SEPS) {
alarm_cancel(p_ccb->ret_ccb_timer);
alarm_cancel(p_ccb->rsp_ccb_timer);
- period_ms_t interval_ms = avdtp_cb.rcb.idle_tout * 1000;
+ uint64_t interval_ms = avdtp_cb.rcb.idle_tout * 1000;
alarm_set_on_mloop(p_ccb->idle_ccb_timer, interval_ms,
avdt_ccb_idle_ccb_timer_timeout, p_ccb);
}
@@ -780,7 +780,7 @@
/* restart ret timer */
alarm_cancel(p_ccb->idle_ccb_timer);
alarm_cancel(p_ccb->rsp_ccb_timer);
- period_ms_t interval_ms = avdtp_cb.rcb.ret_tout * 1000;
+ uint64_t interval_ms = avdtp_cb.rcb.ret_tout * 1000;
alarm_set_on_mloop(p_ccb->ret_ccb_timer, interval_ms,
avdt_ccb_ret_ccb_timer_timeout, p_ccb);
}
diff --git a/stack/avdt/avdt_msg.cc b/stack/avdt/avdt_msg.cc
index cf517d1..0ac9b64 100644
--- a/stack/avdt/avdt_msg.cc
+++ b/stack/avdt/avdt_msg.cc
@@ -1135,13 +1135,13 @@
(sig == AVDT_SIG_SECURITY) || (avdtp_cb.rcb.ret_tout == 0)) {
alarm_cancel(p_ccb->idle_ccb_timer);
alarm_cancel(p_ccb->ret_ccb_timer);
- period_ms_t interval_ms = avdtp_cb.rcb.sig_tout * 1000;
+ uint64_t interval_ms = avdtp_cb.rcb.sig_tout * 1000;
alarm_set_on_mloop(p_ccb->rsp_ccb_timer, interval_ms,
avdt_ccb_rsp_ccb_timer_timeout, p_ccb);
} else if (sig != AVDT_SIG_DELAY_RPT) {
alarm_cancel(p_ccb->idle_ccb_timer);
alarm_cancel(p_ccb->rsp_ccb_timer);
- period_ms_t interval_ms = avdtp_cb.rcb.ret_tout * 1000;
+ uint64_t interval_ms = avdtp_cb.rcb.ret_tout * 1000;
alarm_set_on_mloop(p_ccb->ret_ccb_timer, interval_ms,
avdt_ccb_ret_ccb_timer_timeout, p_ccb);
}
diff --git a/stack/avdt/avdt_scb.cc b/stack/avdt/avdt_scb.cc
index eacdf83..c1c0de4 100644
--- a/stack/avdt/avdt_scb.cc
+++ b/stack/avdt/avdt_scb.cc
@@ -894,7 +894,7 @@
}
uint8_t index = hdl - 1;
- size_t i = index / AVDT_NUM_LINKS;
+ size_t i = index / AVDT_NUM_SEPS;
size_t j = index % AVDT_NUM_SEPS;
AvdtpScb* p_scb = &avdtp_cb.ccb[i].scb[j];
diff --git a/stack/avrc/avrc_pars_ct.cc b/stack/avrc/avrc_pars_ct.cc
index 2b77618..80dc882 100644
--- a/stack/avrc/avrc_pars_ct.cc
+++ b/stack/avrc/avrc_pars_ct.cc
@@ -184,6 +184,16 @@
break;
case AVRC_EVT_ADDR_PLAYER_CHANGE:
+ min_len += 4;
+ if (len < min_len) goto length_error;
+ BE_STREAM_TO_UINT16(p_rsp->param.addr_player.player_id, p_stream);
+ BE_STREAM_TO_UINT16(p_rsp->param.addr_player.uid_counter, p_stream);
+ break;
+
+ case AVRC_EVT_PLAY_POS_CHANGED:
+ min_len += 4;
+ if (len < min_len) goto length_error;
+ BE_STREAM_TO_UINT32(p_rsp->param.play_pos, p_stream);
break;
case AVRC_EVT_UIDS_CHANGE:
@@ -191,7 +201,6 @@
case AVRC_EVT_TRACK_REACHED_END:
case AVRC_EVT_TRACK_REACHED_START:
- case AVRC_EVT_PLAY_POS_CHANGED:
case AVRC_EVT_BATTERY_STATUS_CHANGE:
case AVRC_EVT_SYSTEM_STATUS_CHANGE:
default:
@@ -442,7 +451,7 @@
set_br_pl_rsp->charset_id, set_br_pl_rsp->folder_depth);
set_br_pl_rsp->p_folders = (tAVRC_NAME*)osi_malloc(
- set_br_pl_rsp->num_items * sizeof(tAVRC_NAME));
+ set_br_pl_rsp->folder_depth * sizeof(tAVRC_NAME));
/* Read each of the folder in the depth */
for (uint32_t i = 0; i < set_br_pl_rsp->folder_depth; i++) {
diff --git a/stack/bnep/bnep_utils.cc b/stack/bnep/bnep_utils.cc
index 48fd5d1..6d6d709 100644
--- a/stack/bnep/bnep_utils.cc
+++ b/stack/bnep/bnep_utils.cc
@@ -22,10 +22,10 @@
*
******************************************************************************/
-#include <cutils/log.h>
-
+#include <log/log.h>
#include <stdio.h>
#include <string.h>
+
#include "bnep_int.h"
#include "bt_common.h"
#include "bt_types.h"
diff --git a/stack/btm/ble_advertiser_hci_interface.cc b/stack/btm/ble_advertiser_hci_interface.cc
index 574ef71..dddf8d4 100644
--- a/stack/btm/ble_advertiser_hci_interface.cc
+++ b/stack/btm/ble_advertiser_hci_interface.cc
@@ -17,11 +17,6 @@
******************************************************************************/
#include "ble_advertiser_hci_interface.h"
-#include <base/callback.h>
-#include <base/location.h>
-#include <base/logging.h>
-#include <queue>
-#include <utility>
#include "btm_api.h"
#include "btm_ble_api.h"
#include "btm_int_types.h"
@@ -29,6 +24,14 @@
#include "hcidefs.h"
#include "log/log.h"
+#include <queue>
+#include <utility>
+
+#include <base/bind.h>
+#include <base/callback.h>
+#include <base/location.h>
+#include <base/logging.h>
+
#define BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN 8
#define BTM_BLE_MULTI_ADV_ENB_LEN 3
#define BTM_BLE_MULTI_ADV_SET_PARAM_LEN 24
@@ -43,11 +46,11 @@
using status_cb = BleAdvertiserHciInterface::status_cb;
-using hci_cmd_cb = base::Callback<void(uint8_t* /* return_parameters */,
- uint16_t /* return_parameters_length*/)>;
-extern void btu_hcif_send_cmd_with_cb(
- const tracked_objects::Location& posted_from, uint16_t opcode,
- uint8_t* params, uint8_t params_len, hci_cmd_cb cb);
+using hci_cmd_cb = base::OnceCallback<void(
+ uint8_t* /* return_parameters */, uint16_t /* return_parameters_length*/)>;
+extern void btu_hcif_send_cmd_with_cb(const base::Location& posted_from,
+ uint16_t opcode, uint8_t* params,
+ uint8_t params_len, hci_cmd_cb cb);
namespace {
BleAdvertiserHciInterface* instance = nullptr;
@@ -92,9 +95,8 @@
}
class BleAdvertiserVscHciInterfaceImpl : public BleAdvertiserHciInterface {
- void SendAdvCmd(const tracked_objects::Location& posted_from,
- uint8_t param_len, uint8_t* param_buf,
- status_cb command_complete) {
+ void SendAdvCmd(const base::Location& posted_from, uint8_t param_len,
+ uint8_t* param_buf, status_cb command_complete) {
btu_hcif_send_cmd_with_cb(posted_from, HCI_BLE_MULTI_ADV_OCF, param_buf,
param_len,
base::Bind(&btm_ble_multi_adv_vsc_cmpl_cback,
@@ -321,7 +323,7 @@
}
class BleAdvertiserLegacyHciInterfaceImpl : public BleAdvertiserHciInterface {
- void SendAdvCmd(const tracked_objects::Location& posted_from, uint16_t opcode,
+ void SendAdvCmd(const base::Location& posted_from, uint16_t opcode,
uint8_t* param_buf, uint8_t param_buf_len,
status_cb command_complete) {
btu_hcif_send_cmd_with_cb(
@@ -510,7 +512,7 @@
};
class BleAdvertiserHciExtendedImpl : public BleAdvertiserHciInterface {
- void SendAdvCmd(const tracked_objects::Location& posted_from, uint16_t opcode,
+ void SendAdvCmd(const base::Location& posted_from, uint16_t opcode,
uint8_t* param_buf, uint8_t param_buf_len,
status_cb command_complete) {
btu_hcif_send_cmd_with_cb(
diff --git a/stack/btm/ble_advertiser_hci_interface.h b/stack/btm/ble_advertiser_hci_interface.h
index c08bb86..24e501d 100644
--- a/stack/btm/ble_advertiser_hci_interface.h
+++ b/stack/btm/ble_advertiser_hci_interface.h
@@ -19,10 +19,11 @@
#ifndef BLE_ADVERTISER_HCI_INTERFACE_H
#define BLE_ADVERTISER_HCI_INTERFACE_H
-#include <base/bind.h>
#include <vector>
#include "stack/include/bt_types.h"
+#include <base/callback.h>
+
/* This class is an abstraction of HCI commands used for managing
* advertisements. Please see VSC HCI SPEC at
* https://static.googleusercontent.com/media/source.android.com/en//devices/Android-6.0-Bluetooth-HCI-Reqs.pdf
diff --git a/stack/btm/btm_acl.cc b/stack/btm/btm_acl.cc
index ee2530a..dcb2fb4 100644
--- a/stack/btm/btm_acl.cc
+++ b/stack/btm/btm_acl.cc
@@ -45,6 +45,7 @@
#include "btm_api.h"
#include "btm_int.h"
#include "btu.h"
+#include "common/metrics.h"
#include "device/include/controller.h"
#include "device/include/interop.h"
#include "hcidefs.h"
@@ -163,8 +164,8 @@
break;
case BTM_BLE_ADDR_STATIC:
- conn_addr = p_dev_rec->ble.static_addr;
- *p_addr_type = p_dev_rec->ble.static_addr_type;
+ conn_addr = p_dev_rec->ble.identity_addr;
+ *p_addr_type = p_dev_rec->ble.identity_addr_type;
break;
default:
@@ -537,9 +538,7 @@
tBTM_CMPL_CB* p_cb) {
tACL_CONN* p;
tBTM_SEC_DEV_REC* p_dev_rec = NULL;
-#if (BTM_SCO_INCLUDED == TRUE)
bool is_sco_active;
-#endif
tBTM_STATUS status;
tBTM_PM_MODE pwr_mode;
tBTM_PM_PWR_MD settings;
@@ -567,12 +566,10 @@
if (interop_match_addr(INTEROP_DISABLE_ROLE_SWITCH, &remote_bd_addr))
return BTM_DEV_BLACKLISTED;
-#if (BTM_SCO_INCLUDED == TRUE)
/* Check if there is any SCO Active on this BD Address */
is_sco_active = btm_is_sco_active_by_bdaddr(remote_bd_addr);
if (is_sco_active) return (BTM_NO_RESOURCES);
-#endif
/* Ignore role switch request if the previous request was not completed */
if (p->switch_role_state != BTM_ACL_SWKEY_STATE_IDLE) {
@@ -892,6 +889,11 @@
if (p_acl_cb->transport == BT_TRANSPORT_BR_EDR) {
btm_read_remote_features(p_acl_cb->hci_handle);
}
+ bluetooth::common::LogRemoteVersionInfo(
+ handle, status, p_acl_cb->lmp_version, p_acl_cb->manufacturer,
+ p_acl_cb->lmp_subversion);
+ } else {
+ bluetooth::common::LogRemoteVersionInfo(handle, status, 0, 0, 0);
}
if (p_acl_cb->transport == BT_TRANSPORT_LE) {
diff --git a/stack/btm/btm_ble.cc b/stack/btm/btm_ble.cc
index 0c4bdd9..77604ee 100644
--- a/stack/btm/btm_ble.cc
+++ b/stack/btm/btm_ble.cc
@@ -43,15 +43,10 @@
#include "l2c_int.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
-#include "smp_api.h"
+#include "stack/crypto_toolbox/crypto_toolbox.h"
-extern bool aes_cipher_msg_auth_code(BT_OCTET16 key, uint8_t* input,
- uint16_t length, uint16_t tlen,
- uint8_t* p_signature);
extern void gatt_notify_phy_updated(uint8_t status, uint16_t handle,
uint8_t tx_phy, uint8_t rx_phy);
-extern void btm_ble_advertiser_notify_terminated_legacy(
- uint8_t status, uint16_t connection_handle);
/******************************************************************************/
/* External Function to be called by other modules */
@@ -185,8 +180,7 @@
break;
case BTM_BLE_KEY_TYPE_ER:
- memcpy(p_devcb->ble_encryption_key_value, p_key->er,
- sizeof(BT_OCTET16));
+ p_devcb->ble_encryption_key_value = p_key->er;
break;
default:
@@ -196,54 +190,16 @@
}
}
-/*******************************************************************************
- *
- * Function BTM_GetDeviceEncRoot
- *
- * Description This function is called to read the local device encryption
- * root.
- *
- * Returns void
- * the local device ER is copied into ble_encr_key_value
- *
- ******************************************************************************/
-void BTM_GetDeviceEncRoot(BT_OCTET16 ble_encr_key_value) {
- BTM_TRACE_DEBUG("%s", __func__);
- memcpy(ble_encr_key_value, btm_cb.devcb.ble_encryption_key_value,
- BT_OCTET16_LEN);
+/** Returns local device encryption root (ER) */
+const Octet16& BTM_GetDeviceEncRoot() {
+ return btm_cb.devcb.ble_encryption_key_value;
}
-/*******************************************************************************
- *
- * Function BTM_GetDeviceIDRoot
- *
- * Description This function is called to read the local device identity
- * root.
- *
- * Returns void
- * the local device IR is copied into irk
- *
- ******************************************************************************/
-void BTM_GetDeviceIDRoot(BT_OCTET16 irk) {
- BTM_TRACE_DEBUG("BTM_GetDeviceIDRoot ");
+/** Returns local device identity root (IR). */
+const Octet16& BTM_GetDeviceIDRoot() { return btm_cb.devcb.id_keys.irk; }
- memcpy(irk, btm_cb.devcb.id_keys.irk, BT_OCTET16_LEN);
-}
-
-/*******************************************************************************
- *
- * Function BTM_GetDeviceDHK
- *
- * Description This function is called to read the local device DHK.
- *
- * Returns void
- * the local device DHK is copied into dhk
- *
- ******************************************************************************/
-void BTM_GetDeviceDHK(BT_OCTET16 dhk) {
- BTM_TRACE_DEBUG("BTM_GetDeviceDHK");
- memcpy(dhk, btm_cb.devcb.id_keys.dhk, BT_OCTET16_LEN);
-}
+/** Return local device DHK. */
+const Octet16& BTM_GetDeviceDHK() { return btm_cb.devcb.id_keys.dhk; }
/*******************************************************************************
*
@@ -476,8 +432,8 @@
memset(&oob, 0, sizeof(tSMP_SC_OOB_DATA));
oob.peer_oob_data.present = true;
- memcpy(&oob.peer_oob_data.randomizer, p_r, BT_OCTET16_LEN);
- memcpy(&oob.peer_oob_data.commitment, p_c, BT_OCTET16_LEN);
+ memcpy(&oob.peer_oob_data.randomizer, p_r, OCTET16_LEN);
+ memcpy(&oob.peer_oob_data.commitment, p_c, OCTET16_LEN);
oob.peer_oob_data.addr_rcvd_from.type = p_dev_rec->ble.ble_addr_type;
oob.peer_oob_data.addr_rcvd_from.bda = bd_addr;
@@ -514,7 +470,7 @@
new_param = true;
}
- if (new_param && p_ble_cb->conn_state == BLE_BG_CONN) {
+ if (new_param && btm_ble_get_conn_st() == BLE_CONNECTING) {
btm_ble_suspend_bg_conn();
}
} else {
@@ -796,6 +752,7 @@
tBTM_STATUS BTM_SetBleDataLength(const RawAddress& bd_addr,
uint16_t tx_pdu_length) {
tACL_CONN* p_acl = btm_bda_to_acl(bd_addr, BT_TRANSPORT_LE);
+ uint16_t tx_time = BTM_BLE_DATA_TX_TIME_MAX_LEGACY;
if (p_acl == NULL) {
BTM_TRACE_ERROR("%s: Wrong mode: no LE link exist or LE not supported",
@@ -820,9 +777,10 @@
else if (tx_pdu_length < BTM_BLE_DATA_SIZE_MIN)
tx_pdu_length = BTM_BLE_DATA_SIZE_MIN;
- /* always set the TxTime to be max, as controller does not care for now */
- btsnd_hcic_ble_set_data_length(p_acl->hci_handle, tx_pdu_length,
- BTM_BLE_DATA_TX_TIME_MAX);
+ if (controller_get_interface()->get_bt_version()->hci_version >= HCI_PROTO_VERSION_5_0)
+ tx_time = BTM_BLE_DATA_TX_TIME_MAX;
+
+ btsnd_hcic_ble_set_data_length(p_acl->hci_handle, tx_pdu_length, tx_time);
return BTM_SUCCESS;
}
@@ -1086,13 +1044,13 @@
* p_callback : Pointer to the callback function.
* p_ref_data : Pointer to be returned along with the callback.
*
- * Returns true if link already meets the required security; otherwise
- * false.
+ * Returns Returns - L2CAP LE Connection Response Result Code.
*
******************************************************************************/
-bool btm_ble_start_sec_check(const RawAddress& bd_addr, uint16_t psm,
- bool is_originator, tBTM_SEC_CALLBACK* p_callback,
- void* p_ref_data) {
+tL2CAP_LE_RESULT_CODE btm_ble_start_sec_check(const RawAddress& bd_addr,
+ uint16_t psm, bool is_originator,
+ tBTM_SEC_CALLBACK* p_callback,
+ void* p_ref_data) {
/* Find the service record for the PSM */
tBTM_SEC_SERV_REC* p_serv_rec = btm_sec_find_first_serv(is_originator, psm);
@@ -1101,20 +1059,45 @@
if (!p_serv_rec) {
BTM_TRACE_WARNING("%s PSM: %d no application registerd", __func__, psm);
(*p_callback)(&bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_MODE_UNSUPPORTED);
- return false;
+ return L2CAP_LE_RESULT_NO_PSM;
+ }
+ uint8_t sec_flag = 0;
+ BTM_GetSecurityFlagsByTransport(bd_addr, &sec_flag, BT_TRANSPORT_LE);
+
+ if (!is_originator) {
+ if ((p_serv_rec->security_flags & BTM_SEC_IN_ENCRYPT) &&
+ !(sec_flag & BTM_SEC_ENCRYPTED)) {
+ BTM_TRACE_ERROR(
+ "%s: L2CAP_LE_RESULT_INSUFFICIENT_ENCRYP. service "
+ "security_flags=0x%x, "
+ "sec_flag=0x%x",
+ __func__, p_serv_rec->security_flags, sec_flag);
+ return L2CAP_LE_RESULT_INSUFFICIENT_ENCRYP;
+ } else if ((p_serv_rec->security_flags & BTM_SEC_IN_AUTHENTICATE) &&
+ !(sec_flag &
+ (BTM_SEC_LINK_KEY_AUTHED | BTM_SEC_AUTHENTICATED))) {
+ BTM_TRACE_ERROR(
+ "%s: L2CAP_LE_RESULT_INSUFFICIENT_AUTHENTICATION. service "
+ "security_flags=0x%x, "
+ "sec_flag=0x%x",
+ __func__, p_serv_rec->security_flags, sec_flag);
+ return L2CAP_LE_RESULT_INSUFFICIENT_AUTHENTICATION;
+ }
+ /* TODO: When security is required, then must check that the key size of our
+ service is equal or smaller than the incoming connection key size. */
}
tBTM_SEC_ACTION sec_act = btm_ble_determine_security_act(
is_originator, bd_addr, p_serv_rec->security_flags);
tBTM_BLE_SEC_ACT ble_sec_act = BTM_BLE_SEC_NONE;
- bool status = false;
+ tL2CAP_LE_RESULT_CODE result = L2CAP_LE_RESULT_CONN_OK;
switch (sec_act) {
case BTM_SEC_OK:
BTM_TRACE_DEBUG("%s Security met", __func__);
p_callback(&bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_SUCCESS);
- status = true;
+ result = L2CAP_LE_RESULT_CONN_OK;
break;
case BTM_SEC_ENCRYPT:
@@ -1137,14 +1120,14 @@
break;
}
- if (ble_sec_act == BTM_BLE_SEC_NONE) return status;
+ if (ble_sec_act == BTM_BLE_SEC_NONE) return result;
tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_LE);
p_lcb->sec_act = sec_act;
BTM_SetEncryption(bd_addr, BT_TRANSPORT_LE, p_callback, p_ref_data,
ble_sec_act);
- return false;
+ return L2CAP_LE_RESULT_CONN_OK;
}
/*******************************************************************************
@@ -1178,7 +1161,7 @@
if (op_code == HCI_BLE_RAND)
params.param_len = BT_OCTET8_LEN;
else
- params.param_len = BT_OCTET16_LEN;
+ params.param_len = OCTET16_LEN;
/* Fetch return info from HCI event message */
memcpy(p_dest, p, params.param_len);
@@ -1279,7 +1262,6 @@
tBTM_LE_KEY_VALUE* p_keys, bool pass_to_application) {
tBTM_SEC_DEV_REC* p_rec;
tBTM_LE_EVT_DATA cb_data;
- uint8_t i;
BTM_TRACE_DEBUG("btm_sec_save_le_key key_type=0x%x pass_to_application=%d",
key_type, pass_to_application);
@@ -1293,7 +1275,7 @@
switch (key_type) {
case BTM_LE_KEY_PENC:
- memcpy(p_rec->ble.keys.pltk, p_keys->penc_key.ltk, BT_OCTET16_LEN);
+ p_rec->ble.keys.pltk = p_keys->penc_key.ltk;
memcpy(p_rec->ble.keys.rand, p_keys->penc_key.rand, BT_OCTET8_LEN);
p_rec->ble.keys.sec_level = p_keys->penc_key.sec_level;
p_rec->ble.keys.ediv = p_keys->penc_key.ediv;
@@ -1310,28 +1292,24 @@
break;
case BTM_LE_KEY_PID:
- for (i = 0; i < BT_OCTET16_LEN; i++) {
- p_rec->ble.keys.irk[i] = p_keys->pid_key.irk[i];
- }
-
- // memcpy( p_rec->ble.keys.irk, p_keys->pid_key, BT_OCTET16_LEN); todo
- // will crash the system
- p_rec->ble.static_addr = p_keys->pid_key.static_addr;
- p_rec->ble.static_addr_type = p_keys->pid_key.addr_type;
+ p_rec->ble.keys.irk = p_keys->pid_key.irk;
+ p_rec->ble.identity_addr = p_keys->pid_key.identity_addr;
+ p_rec->ble.identity_addr_type = p_keys->pid_key.identity_addr_type;
p_rec->ble.key_type |= BTM_LE_KEY_PID;
BTM_TRACE_DEBUG(
"%s: BTM_LE_KEY_PID key_type=0x%x save peer IRK, change bd_addr=%s "
- "to static_addr=%s",
+ "to id_addr=%s id_addr_type=0x%x",
__func__, p_rec->ble.key_type, p_rec->bd_addr.ToString().c_str(),
- p_keys->pid_key.static_addr.ToString().c_str());
- /* update device record address as static address */
- p_rec->bd_addr = p_keys->pid_key.static_addr;
+ p_keys->pid_key.identity_addr.ToString().c_str(),
+ p_keys->pid_key.identity_addr_type);
+ /* update device record address as identity address */
+ p_rec->bd_addr = p_keys->pid_key.identity_addr;
/* combine DUMO device security record if needed */
btm_consolidate_dev(p_rec);
break;
case BTM_LE_KEY_PCSRK:
- memcpy(p_rec->ble.keys.pcsrk, p_keys->pcsrk_key.csrk, BT_OCTET16_LEN);
+ p_rec->ble.keys.pcsrk = p_keys->pcsrk_key.csrk;
p_rec->ble.keys.srk_sec_level = p_keys->pcsrk_key.sec_level;
p_rec->ble.keys.counter = p_keys->pcsrk_key.counter;
p_rec->ble.key_type |= BTM_LE_KEY_PCSRK;
@@ -1349,7 +1327,7 @@
break;
case BTM_LE_KEY_LENC:
- memcpy(p_rec->ble.keys.lltk, p_keys->lenc_key.ltk, BT_OCTET16_LEN);
+ p_rec->ble.keys.lltk = p_keys->lenc_key.ltk;
p_rec->ble.keys.div = p_keys->lenc_key.div; /* update DIV */
p_rec->ble.keys.sec_level = p_keys->lenc_key.sec_level;
p_rec->ble.keys.key_size = p_keys->lenc_key.key_size;
@@ -1363,7 +1341,7 @@
break;
case BTM_LE_KEY_LCSRK: /* local CSRK has been delivered */
- memcpy(p_rec->ble.keys.lcsrk, p_keys->lcsrk_key.csrk, BT_OCTET16_LEN);
+ p_rec->ble.keys.lcsrk = p_keys->lcsrk_key.csrk;
p_rec->ble.keys.div = p_keys->lcsrk_key.div; /* update DIV */
p_rec->ble.keys.local_csrk_sec_level = p_keys->lcsrk_key.sec_level;
p_rec->ble.keys.local_counter = p_keys->lcsrk_key.counter;
@@ -1556,6 +1534,7 @@
}
/* if salve role then fall through to call SMP_Pair below which will send a
sec_request to request the master to encrypt the link */
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case BTM_BLE_SEC_ENCRYPT_NO_MITM:
case BTM_BLE_SEC_ENCRYPT_MITM:
auth_req = (sec_act == BTM_BLE_SEC_ENCRYPT_NO_MITM)
@@ -1602,7 +1581,6 @@
void btm_ble_ltk_request(uint16_t handle, uint8_t rand[8], uint16_t ediv) {
tBTM_CB* p_cb = &btm_cb;
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(handle);
- BT_OCTET8 dummy_stk = {0};
BTM_TRACE_DEBUG("btm_ble_ltk_request");
@@ -1611,23 +1589,17 @@
memcpy(p_cb->enc_rand, rand, BT_OCTET8_LEN);
if (p_dev_rec != NULL) {
- if (!smp_proc_ltk_request(p_dev_rec->bd_addr))
- btm_ble_ltk_request_reply(p_dev_rec->bd_addr, false, dummy_stk);
+ if (!smp_proc_ltk_request(p_dev_rec->bd_addr)) {
+ btm_ble_ltk_request_reply(p_dev_rec->bd_addr, false, Octet16{0});
+ }
}
}
-/*******************************************************************************
- *
- * Function btm_ble_start_encrypt
- *
- * Description This function is called to start LE encryption.
- *
- *
- * Returns BTM_SUCCESS if encryption was started successfully
- *
- ******************************************************************************/
+/** This function is called to start LE encryption.
+ * Returns BTM_SUCCESS if encryption was started successfully
+ */
tBTM_STATUS btm_ble_start_encrypt(const RawAddress& bda, bool use_stk,
- BT_OCTET16 stk) {
+ Octet16* p_stk) {
tBTM_CB* p_cb = &btm_cb;
tBTM_SEC_DEV_REC* p_rec = btm_find_dev(bda);
BT_OCTET8 dummy_rand = {0};
@@ -1647,7 +1619,7 @@
p_cb->enc_handle = p_rec->ble_hci_handle;
if (use_stk) {
- btsnd_hcic_ble_start_enc(p_rec->ble_hci_handle, dummy_rand, 0, stk);
+ btsnd_hcic_ble_start_enc(p_rec->ble_hci_handle, dummy_rand, 0, *p_stk);
} else if (p_rec->ble.key_type & BTM_LE_KEY_PENC) {
btsnd_hcic_ble_start_enc(p_rec->ble_hci_handle, p_rec->ble.keys.rand,
p_rec->ble.keys.ediv, p_rec->ble.keys.pltk);
@@ -1698,7 +1670,9 @@
if (p_dev_rec->p_callback && enc_cback) {
if (encr_enable)
btm_sec_dev_rec_cback_event(p_dev_rec, BTM_SUCCESS, true);
- else if (p_dev_rec->role_master)
+ else if (p_dev_rec->sec_flags & ~BTM_SEC_LE_LINK_KEY_KNOWN) {
+ btm_sec_dev_rec_cback_event(p_dev_rec, BTM_FAILED_ON_SECURITY, true);
+ } else if (p_dev_rec->role_master)
btm_sec_dev_rec_cback_event(p_dev_rec, BTM_ERR_PROCESSING, true);
}
/* to notify GATT to send data if any request is pending */
@@ -1717,7 +1691,7 @@
*
******************************************************************************/
void btm_ble_ltk_request_reply(const RawAddress& bda, bool use_stk,
- BT_OCTET16 stk) {
+ const Octet16& stk) {
tBTM_SEC_DEV_REC* p_rec = btm_find_dev(bda);
tBTM_CB* p_cb = &btm_cb;
@@ -1914,126 +1888,6 @@
}
/*****************************************************************************
- * Function btm_ble_conn_complete
- *
- * Description LE connection complete.
- *
- *****************************************************************************/
-void btm_ble_conn_complete(uint8_t* p, UNUSED_ATTR uint16_t evt_len,
- bool enhanced) {
-#if (BLE_PRIVACY_SPT == TRUE)
- uint8_t peer_addr_type;
-#endif
- RawAddress local_rpa, peer_rpa;
- uint8_t role, status, bda_type;
- uint16_t handle;
- RawAddress bda;
- uint16_t conn_interval, conn_latency, conn_timeout;
- bool match = false;
-
- STREAM_TO_UINT8(status, p);
- STREAM_TO_UINT16(handle, p);
- STREAM_TO_UINT8(role, p);
- STREAM_TO_UINT8(bda_type, p);
- STREAM_TO_BDADDR(bda, p);
-
- if (status == 0) {
- if (enhanced) {
- STREAM_TO_BDADDR(local_rpa, p);
- STREAM_TO_BDADDR(peer_rpa, p);
- }
-
- STREAM_TO_UINT16(conn_interval, p);
- STREAM_TO_UINT16(conn_latency, p);
- STREAM_TO_UINT16(conn_timeout, p);
- handle = HCID_GET_HANDLE(handle);
-
-#if (BLE_PRIVACY_SPT == TRUE)
- peer_addr_type = bda_type;
- match = btm_identity_addr_to_random_pseudo(&bda, &bda_type, true);
-
- /* possiblly receive connection complete with resolvable random while
- the device has been paired */
- if (!match && BTM_BLE_IS_RESOLVE_BDA(bda)) {
- tBTM_SEC_DEV_REC* match_rec = btm_ble_resolve_random_addr(bda);
- if (match_rec) {
- LOG_INFO(LOG_TAG, "%s matched and resolved random address", __func__);
- match = true;
- match_rec->ble.active_addr_type = BTM_BLE_ADDR_RRA;
- match_rec->ble.cur_rand_addr = bda;
- if (!btm_ble_init_pseudo_addr(match_rec, bda)) {
- /* assign the original address to be the current report address */
- bda = match_rec->ble.pseudo_addr;
- } else {
- bda = match_rec->bd_addr;
- }
- } else {
- LOG_INFO(LOG_TAG, "%s unable to match and resolve random address",
- __func__);
- }
- }
-#endif
-
- btm_ble_connected(bda, handle, HCI_ENCRYPT_MODE_DISABLED, role, bda_type,
- match);
-
- l2cble_conn_comp(handle, role, bda, bda_type, conn_interval, conn_latency,
- conn_timeout);
-
-#if (BLE_PRIVACY_SPT == TRUE)
- if (enhanced) {
- btm_ble_refresh_local_resolvable_private_addr(bda, local_rpa);
-
- if (peer_addr_type & BLE_ADDR_TYPE_ID_BIT)
- btm_ble_refresh_peer_resolvable_private_addr(bda, peer_rpa,
- BLE_ADDR_RANDOM);
- }
-#endif
- } else {
- role = HCI_ROLE_UNKNOWN;
- if (status != HCI_ERR_ADVERTISING_TIMEOUT) {
- btm_ble_set_conn_st(BLE_CONN_IDLE);
-#if (BLE_PRIVACY_SPT == TRUE)
- btm_ble_disable_resolving_list(BTM_BLE_RL_INIT, true);
-#endif
- } else {
-#if (BLE_PRIVACY_SPT == TRUE)
- btm_cb.ble_ctr_cb.inq_var.adv_mode = BTM_BLE_ADV_DISABLE;
- btm_ble_disable_resolving_list(BTM_BLE_RL_ADV, true);
-#endif
- }
- }
-
- btm_ble_update_mode_operation(role, &bda, status);
-
- if (role == HCI_ROLE_SLAVE)
- btm_ble_advertiser_notify_terminated_legacy(status, handle);
-}
-
-/*****************************************************************************
- * Function btm_ble_create_ll_conn_complete
- *
- * Description LE connection complete.
- *
- *****************************************************************************/
-void btm_ble_create_ll_conn_complete(uint8_t status) {
- if (status == HCI_SUCCESS) return;
-
- btm_ble_set_conn_st(BLE_CONN_IDLE);
- btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, NULL, status);
-
- LOG(WARNING) << "LE Create Connection attempt failed, status="
- << loghex(status);
-
- if (status == HCI_ERR_COMMAND_DISALLOWED) {
- /* There is already either direct connect, or whitelist connection
- * pending, but we don't know which one, or to which state should we
- * transition now. This can be triggered only in case of rare race
- * condition. Crash to recover. */
- LOG(FATAL) << "LE Create Connection - command disallowed";
- }
-}
-/*****************************************************************************
* Function btm_proc_smp_cback
*
* Description This function is the SMP callback handler.
@@ -2062,8 +1916,8 @@
case SMP_OOB_REQ_EVT:
case SMP_NC_REQ_EVT:
case SMP_SC_OOB_REQ_EVT:
- /* fall through */
p_dev_rec->sec_flags |= BTM_SEC_LE_AUTHENTICATED;
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case SMP_SEC_REQUEST_EVT:
if (event == SMP_SEC_REQUEST_EVT &&
@@ -2074,7 +1928,7 @@
btm_cb.pairing_bda = bd_addr;
p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
btm_cb.pairing_flags |= BTM_PAIR_FLAGS_LE_ACTIVE;
- /* fall through */
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case SMP_COMPLT_EVT:
if (btm_cb.api.p_le_callback) {
@@ -2184,45 +2038,42 @@
tBTM_SEC_DEV_REC* p_rec = btm_find_dev(bd_addr);
BTM_TRACE_DEBUG("%s", __func__);
- bool ret = false;
if (p_rec == NULL) {
BTM_TRACE_ERROR("%s-data signing can not be done from unknown device",
__func__);
- } else {
- uint8_t* p_mac = (uint8_t*)signature;
- uint8_t* pp;
- uint8_t* p_buf = (uint8_t*)osi_malloc(len + 4);
-
- BTM_TRACE_DEBUG("%s-Start to generate Local CSRK", __func__);
- pp = p_buf;
- /* prepare plain text */
- if (p_text) {
- memcpy(p_buf, p_text, len);
- pp = (p_buf + len);
- }
-
- UINT32_TO_STREAM(pp, p_rec->ble.keys.local_counter);
- UINT32_TO_STREAM(p_mac, p_rec->ble.keys.local_counter);
-
- ret = aes_cipher_msg_auth_code(p_rec->ble.keys.lcsrk, p_buf,
- (uint16_t)(len + 4), BTM_CMAC_TLEN_SIZE,
- p_mac);
- if (ret) {
- btm_ble_increment_sign_ctr(bd_addr, true);
- }
-
- BTM_TRACE_DEBUG("%s p_mac = %d", __func__, p_mac);
- BTM_TRACE_DEBUG(
- "p_mac[0] = 0x%02x p_mac[1] = 0x%02x p_mac[2] = 0x%02x p_mac[3] = "
- "0x%02x",
- *p_mac, *(p_mac + 1), *(p_mac + 2), *(p_mac + 3));
- BTM_TRACE_DEBUG(
- "p_mac[4] = 0x%02x p_mac[5] = 0x%02x p_mac[6] = 0x%02x p_mac[7] = "
- "0x%02x",
- *(p_mac + 4), *(p_mac + 5), *(p_mac + 6), *(p_mac + 7));
- osi_free(p_buf);
+ return false;
}
- return ret;
+
+ uint8_t* p_mac = (uint8_t*)signature;
+ uint8_t* pp;
+ uint8_t* p_buf = (uint8_t*)osi_malloc(len + 4);
+
+ BTM_TRACE_DEBUG("%s-Start to generate Local CSRK", __func__);
+ pp = p_buf;
+ /* prepare plain text */
+ if (p_text) {
+ memcpy(p_buf, p_text, len);
+ pp = (p_buf + len);
+ }
+
+ UINT32_TO_STREAM(pp, p_rec->ble.keys.local_counter);
+ UINT32_TO_STREAM(p_mac, p_rec->ble.keys.local_counter);
+
+ crypto_toolbox::aes_cmac(p_rec->ble.keys.lcsrk, p_buf, (uint16_t)(len + 4),
+ BTM_CMAC_TLEN_SIZE, p_mac);
+ btm_ble_increment_sign_ctr(bd_addr, true);
+
+ BTM_TRACE_DEBUG("%s p_mac = %d", __func__, p_mac);
+ BTM_TRACE_DEBUG(
+ "p_mac[0] = 0x%02x p_mac[1] = 0x%02x p_mac[2] = 0x%02x p_mac[3] = "
+ "0x%02x",
+ *p_mac, *(p_mac + 1), *(p_mac + 2), *(p_mac + 3));
+ BTM_TRACE_DEBUG(
+ "p_mac[4] = 0x%02x p_mac[5] = 0x%02x p_mac[6] = 0x%02x p_mac[7] = "
+ "0x%02x",
+ *(p_mac + 4), *(p_mac + 5), *(p_mac + 6), *(p_mac + 7));
+ osi_free(p_buf);
+ return true;
}
/*******************************************************************************
@@ -2256,12 +2107,11 @@
BTM_TRACE_DEBUG("%s rcv_cnt=%d >= expected_cnt=%d", __func__, counter,
p_rec->ble.keys.counter);
- if (aes_cipher_msg_auth_code(p_rec->ble.keys.pcsrk, p_orig, len,
- BTM_CMAC_TLEN_SIZE, p_mac)) {
- if (memcmp(p_mac, p_comp, BTM_CMAC_TLEN_SIZE) == 0) {
- btm_ble_increment_sign_ctr(bd_addr, false);
- verified = true;
- }
+ crypto_toolbox::aes_cmac(p_rec->ble.keys.pcsrk, p_orig, len,
+ BTM_CMAC_TLEN_SIZE, p_mac);
+ if (memcmp(p_mac, p_comp, BTM_CMAC_TLEN_SIZE) == 0) {
+ btm_ble_increment_sign_ctr(bd_addr, false);
+ verified = true;
}
}
return verified;
@@ -2395,16 +2245,7 @@
/*******************************************************************************
* Utility functions for LE device IR/ER generation
******************************************************************************/
-/*******************************************************************************
- *
- * Function btm_notify_new_key
- *
- * Description This function is to notify application new keys have been
- * generated.
- *
- * Returns void
- *
- ******************************************************************************/
+/** This function is to notify application new keys have been generated. */
static void btm_notify_new_key(uint8_t key_type) {
tBTM_BLE_LOCAL_KEYS* p_local_keys = NULL;
@@ -2432,112 +2273,67 @@
}
}
-/*******************************************************************************
- *
- * Function btm_ble_process_irk
- *
- * Description This function is called when IRK is generated, store it in
- * local control block.
- *
- * Returns void
- *
- ******************************************************************************/
-static void btm_ble_process_irk(tSMP_ENC* p) {
- BTM_TRACE_DEBUG("btm_ble_process_irk");
- if (p && p->opcode == HCI_BLE_ENCRYPT) {
- memcpy(btm_cb.devcb.id_keys.irk, p->param_buf, BT_OCTET16_LEN);
- btm_notify_new_key(BTM_BLE_KEY_TYPE_ID);
+/** implementation of btm_ble_reset_id */
+static void btm_ble_reset_id_impl(const Octet16& rand1, const Octet16& rand2) {
+ /* Regenerate Identity Root */
+ btm_cb.devcb.id_keys.ir = rand1;
+ uint8_t btm_ble_dhk_pt = 0x03;
+
+ /* generate DHK= Eir({0x03, 0x00, 0x00 ...}) */
+ btm_cb.devcb.id_keys.dhk =
+ crypto_toolbox::aes_128(btm_cb.devcb.id_keys.ir, &btm_ble_dhk_pt, 1);
+
+ uint8_t btm_ble_irk_pt = 0x01;
+ /* IRK = D1(IR, 1) */
+ btm_cb.devcb.id_keys.irk =
+ crypto_toolbox::aes_128(btm_cb.devcb.id_keys.ir, &btm_ble_irk_pt, 1);
+
+ btm_notify_new_key(BTM_BLE_KEY_TYPE_ID);
#if (BLE_PRIVACY_SPT == TRUE)
- /* if privacy is enabled, new RPA should be calculated */
- if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE) {
- btm_gen_resolvable_private_addr(base::Bind(&btm_gen_resolve_paddr_low));
- }
-#endif
- } else {
- BTM_TRACE_ERROR("Generating IRK exception.");
+ /* if privacy is enabled, new RPA should be calculated */
+ if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE) {
+ btm_gen_resolvable_private_addr(base::Bind(&btm_gen_resolve_paddr_low));
}
+#endif
/* proceed generate ER */
- btsnd_hcic_ble_rand(base::Bind([](BT_OCTET8 rand1) {
- memcpy(&btm_cb.devcb.ble_encryption_key_value[0], rand1, BT_OCTET8_LEN);
-
- btsnd_hcic_ble_rand(base::Bind([](BT_OCTET8 rand2) {
- memcpy(&btm_cb.devcb.ble_encryption_key_value[8], rand2, BT_OCTET8_LEN);
- btm_notify_new_key(BTM_BLE_KEY_TYPE_ER);
- }));
-
- }));
+ btm_cb.devcb.ble_encryption_key_value = rand2;
+ btm_notify_new_key(BTM_BLE_KEY_TYPE_ER);
}
-/*******************************************************************************
- *
- * Function btm_ble_process_dhk
- *
- * Description This function is called when DHK is calculated, store it in
- * local control block, and proceed to generate ER, a 128-bits
- * random number.
- *
- * Returns void
- *
- ******************************************************************************/
-static void btm_ble_process_dhk(tSMP_ENC* p) {
- uint8_t btm_ble_irk_pt = 0x01;
- tSMP_ENC output;
+struct reset_id_data {
+ Octet16 rand1;
+ Octet16 rand2;
+};
- BTM_TRACE_DEBUG("btm_ble_process_dhk");
-
- if (p && p->opcode == HCI_BLE_ENCRYPT) {
- memcpy(btm_cb.devcb.id_keys.dhk, p->param_buf, BT_OCTET16_LEN);
- BTM_TRACE_DEBUG("BLE DHK generated.");
-
- /* IRK = D1(IR, 1) */
- if (!SMP_Encrypt(btm_cb.devcb.id_keys.ir, BT_OCTET16_LEN, &btm_ble_irk_pt,
- 1, &output)) {
- /* reset all identity root related key */
- memset(&btm_cb.devcb.id_keys, 0, sizeof(tBTM_BLE_LOCAL_ID_KEYS));
- } else {
- btm_ble_process_irk(&output);
- }
- } else {
- /* reset all identity root related key */
- memset(&btm_cb.devcb.id_keys, 0, sizeof(tBTM_BLE_LOCAL_ID_KEYS));
- }
-}
-
-/*******************************************************************************
- *
- * Function btm_ble_reset_id
- *
- * Description This function is called to reset LE device identity.
- *
- * Returns void
- *
- ******************************************************************************/
+/** This function is called to reset LE device identity. */
void btm_ble_reset_id(void) {
BTM_TRACE_DEBUG("btm_ble_reset_id");
- /* Regenerate Identity Root*/
+ /* In order to reset identity, we need four random numbers. Make four nested
+ * calls to generate them first, then proceed to perform the actual reset in
+ * btm_ble_reset_id_impl. */
btsnd_hcic_ble_rand(base::Bind([](BT_OCTET8 rand) {
- BTM_TRACE_DEBUG("btm_ble_process_ir1");
- memcpy(btm_cb.devcb.id_keys.ir, rand, BT_OCTET8_LEN);
-
- btsnd_hcic_ble_rand(base::Bind([](BT_OCTET8 rand) {
- uint8_t btm_ble_dhk_pt = 0x03;
- tSMP_ENC output;
-
- BTM_TRACE_DEBUG("btm_ble_process_ir2");
-
- /* remembering in control block */
- memcpy(&btm_cb.devcb.id_keys.ir[8], rand, 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);
-
- BTM_TRACE_DEBUG("BLE IR generated.");
- }));
+ reset_id_data tmp;
+ memcpy(tmp.rand1.data(), rand, BT_OCTET8_LEN);
+ btsnd_hcic_ble_rand(base::Bind(
+ [](reset_id_data tmp, BT_OCTET8 rand) {
+ memcpy(tmp.rand1.data() + 8, rand, BT_OCTET8_LEN);
+ btsnd_hcic_ble_rand(base::Bind(
+ [](reset_id_data tmp, BT_OCTET8 rand) {
+ memcpy(tmp.rand2.data(), rand, BT_OCTET8_LEN);
+ btsnd_hcic_ble_rand(base::Bind(
+ [](reset_id_data tmp, BT_OCTET8 rand) {
+ memcpy(tmp.rand2.data() + 8, rand, BT_OCTET8_LEN);
+ // when all random numbers are ready, do the actual reset.
+ btm_ble_reset_id_impl(tmp.rand1, tmp.rand2);
+ },
+ tmp));
+ },
+ tmp));
+ },
+ tmp));
}));
}
@@ -2549,11 +2345,6 @@
bool adv_mode = btm_cb.ble_ctr_cb.inq_var.adv_mode;
BTM_TRACE_DEBUG("%s", __func__);
- if (btm_ble_get_conn_st() == BLE_DIR_CONN) {
- BTM_TRACE_ERROR("%s: Cannot set random address. Direct conn ongoing",
- __func__);
- return;
- }
if (adv_mode == BTM_BLE_ADV_ENABLE)
btsnd_hcic_ble_set_adv_enable(BTM_BLE_ADV_DISABLE);
diff --git a/stack/btm/btm_ble_addr.cc b/stack/btm/btm_ble_addr.cc
index 2d0acc6..000066e 100644
--- a/stack/btm/btm_ble_addr.cc
+++ b/stack/btm/btm_ble_addr.cc
@@ -33,88 +33,66 @@
#include "hcimsgs.h"
#include "btm_ble_int.h"
-#include "smp_api.h"
+#include "stack/crypto_toolbox/crypto_toolbox.h"
-/*******************************************************************************
- *
- * Function btm_gen_resolve_paddr_cmpl
- *
- * Description This is callback functioin when resolvable private address
- * generation is complete.
- *
- * Returns void
- *
- ******************************************************************************/
-static void btm_gen_resolve_paddr_cmpl(tSMP_ENC* p) {
- tBTM_LE_RANDOM_CB* p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
- BTM_TRACE_EVENT("btm_gen_resolve_paddr_cmpl");
+/* This function generates Resolvable Private Address (RPA) from Identity
+ * Resolving Key |irk| and |random|*/
+RawAddress generate_rpa_from_irk_and_rand(const Octet16& irk,
+ BT_OCTET8 random) {
+ random[2] &= (~BLE_RESOLVE_ADDR_MASK);
+ random[2] |= BLE_RESOLVE_ADDR_MSB;
- if (p) {
- /* set hash to be LSB of rpAddress */
- p_cb->private_addr.address[5] = p->param_buf[0];
- p_cb->private_addr.address[4] = p->param_buf[1];
- p_cb->private_addr.address[3] = p->param_buf[2];
- /* set it to controller */
- btm_ble_set_random_address(p_cb->private_addr);
+ RawAddress address;
+ address.address[2] = random[0];
+ address.address[1] = random[1];
+ address.address[0] = random[2];
- p_cb->own_addr_type = BLE_ADDR_RANDOM;
+ /* encrypt with IRK */
+ Octet16 p = crypto_toolbox::aes_128(irk, random, 3);
- /* start a periodical timer to refresh random addr */
- period_ms_t interval_ms = BTM_BLE_PRIVATE_ADDR_INT_MS;
-#if (BTM_BLE_CONFORMANCE_TESTING == TRUE)
- interval_ms = btm_cb.ble_ctr_cb.rpa_tout * 1000;
-#endif
- alarm_set_on_mloop(p_cb->refresh_raddr_timer, interval_ms,
- btm_ble_refresh_raddr_timer_timeout, NULL);
- } else {
- /* random address set failure */
- BTM_TRACE_DEBUG("set random address failed");
- }
+ /* set hash to be LSB of rpAddress */
+ address.address[5] = p[0];
+ address.address[4] = p[1];
+ address.address[3] = p[2];
+ return address;
}
-/*******************************************************************************
- *
- * Function btm_gen_resolve_paddr_low
- *
- * Description This function is called when random address has generate the
- * random number base for low 3 byte bd address.
- *
- * Returns void
- *
- ******************************************************************************/
-void btm_gen_resolve_paddr_low(BT_OCTET8 rand) {
+
+/** This function is called when random address for local controller was
+ * generated */
+void btm_gen_resolve_paddr_low(const RawAddress& address) {
tBTM_LE_RANDOM_CB* p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
- tSMP_ENC output;
BTM_TRACE_EVENT("btm_gen_resolve_paddr_low");
- rand[2] &= (~BLE_RESOLVE_ADDR_MASK);
- rand[2] |= BLE_RESOLVE_ADDR_MSB;
- p_cb->private_addr.address[2] = rand[0];
- p_cb->private_addr.address[1] = rand[1];
- p_cb->private_addr.address[0] = rand[2];
+ p_cb->private_addr = address;
- /* encrypt with ur IRK */
- if (!SMP_Encrypt(btm_cb.devcb.id_keys.irk, BT_OCTET16_LEN, rand, 3,
- &output)) {
- btm_gen_resolve_paddr_cmpl(NULL);
- } else {
- btm_gen_resolve_paddr_cmpl(&output);
- }
+ /* set it to controller */
+ btm_ble_set_random_address(p_cb->private_addr);
+
+ p_cb->own_addr_type = BLE_ADDR_RANDOM;
+
+ /* start a periodical timer to refresh random addr */
+ uint64_t interval_ms = BTM_BLE_PRIVATE_ADDR_INT_MS;
+#if (BTM_BLE_CONFORMANCE_TESTING == TRUE)
+ interval_ms = btm_cb.ble_ctr_cb.rpa_tout * 1000;
+#endif
+ alarm_set_on_mloop(p_cb->refresh_raddr_timer, interval_ms,
+ btm_ble_refresh_raddr_timer_timeout, NULL);
}
-/*******************************************************************************
- *
- * Function btm_gen_resolvable_private_addr
- *
- * Description This function generate a resolvable private address.
- *
- * Returns void
- *
- ******************************************************************************/
-void btm_gen_resolvable_private_addr(base::Callback<void(BT_OCTET8)> cb) {
+
+/** This function generate a resolvable private address using local IRK */
+void btm_gen_resolvable_private_addr(
+ base::Callback<void(const RawAddress&)> cb) {
BTM_TRACE_EVENT("%s", __func__);
/* generate 3B rand as BD LSB, SRK with it, get BD MSB */
- btsnd_hcic_ble_rand(std::move(cb));
+ btsnd_hcic_ble_rand(base::Bind(
+ [](base::Callback<void(const RawAddress&)> cb, BT_OCTET8 random) {
+ const Octet16& irk = BTM_GetDeviceIDRoot();
+ cb.Run(generate_rpa_from_irk_and_rand(irk, random));
+ },
+ std::move(cb)));
}
+
/*******************************************************************************
*
* Function btm_gen_non_resolve_paddr_cmpl
@@ -169,33 +147,6 @@
/*******************************************************************************
* Utility functions for Random address resolving
******************************************************************************/
-/*******************************************************************************
- *
- * Function btm_ble_proc_resolve_x
- *
- * Description This function compares the X with random address 3 MSO bytes
- * to find a match.
- *
- * Returns true on match, false otherwise
- *
- ******************************************************************************/
-static bool btm_ble_proc_resolve_x(const tSMP_ENC& encrypt_output,
- const RawAddress& random_bda) {
- BTM_TRACE_EVENT("btm_ble_proc_resolve_x");
-
- /* compare the hash with 3 LSB of bd address */
- uint8_t comp[3];
- comp[0] = random_bda.address[5];
- comp[1] = random_bda.address[4];
- comp[2] = random_bda.address[3];
-
- if (!memcmp(encrypt_output.param_buf, comp, 3)) {
- BTM_TRACE_EVENT("match is found");
- return true;
- }
-
- return false;
-}
/*******************************************************************************
*
@@ -217,71 +168,56 @@
return false;
}
-/*******************************************************************************
- *
- * Function btm_ble_addr_resolvable
- *
- * Description This function checks if a RPA is resolvable by the device
- * key.
- *
- * Returns true is resolvable; false otherwise.
- *
- ******************************************************************************/
+/* Return true if given Resolvable Privae Address |rpa| matches Identity
+ * Resolving Key |irk| */
+static bool rpa_matches_irk(const RawAddress& rpa, const Octet16& irk) {
+ /* use the 3 MSB of bd address as prand */
+ uint8_t rand[3];
+ rand[0] = rpa.address[2];
+ rand[1] = rpa.address[1];
+ rand[2] = rpa.address[0];
+
+ /* generate X = E irk(R0, R1, R2) and R is random address 3 LSO */
+ Octet16 x = crypto_toolbox::aes_128(irk, &rand[0], 3);
+
+ rand[0] = rpa.address[5];
+ rand[1] = rpa.address[4];
+ rand[2] = rpa.address[3];
+
+ if (memcmp(x.data(), &rand[0], 3) == 0) {
+ // match
+ return true;
+ }
+ // not a match
+ return false;
+}
+
+/** This function checks if a RPA is resolvable by the device key.
+ * Returns true is resolvable; false otherwise.
+ */
bool btm_ble_addr_resolvable(const RawAddress& rpa,
tBTM_SEC_DEV_REC* p_dev_rec) {
- bool rt = false;
+ if (!BTM_BLE_IS_RESOLVE_BDA(rpa)) return false;
- if (!BTM_BLE_IS_RESOLVE_BDA(rpa)) return rt;
-
- uint8_t rand[3];
- tSMP_ENC output;
if ((p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) &&
(p_dev_rec->ble.key_type & BTM_LE_KEY_PID)) {
BTM_TRACE_DEBUG("%s try to resolve", __func__);
- /* use the 3 MSB of bd address as prand */
- rand[0] = rpa.address[2];
- rand[1] = rpa.address[1];
- rand[2] = rpa.address[0];
- /* generate X = E irk(R0, R1, R2) and R is random address 3 LSO */
- SMP_Encrypt(p_dev_rec->ble.keys.irk, BT_OCTET16_LEN, &rand[0], 3, &output);
-
- rand[0] = rpa.address[5];
- rand[1] = rpa.address[4];
- rand[2] = rpa.address[3];
-
- if (!memcmp(output.param_buf, &rand[0], 3)) {
+ if (rpa_matches_irk(rpa, p_dev_rec->ble.keys.irk)) {
btm_ble_init_pseudo_addr(p_dev_rec, rpa);
- rt = true;
+ return true;
}
}
- return rt;
+ return false;
}
-/*******************************************************************************
- *
- * Function btm_ble_match_random_bda
- *
- * Description This function match the random address to the appointed
- * device record, starting from calculating IRK. If the record
- * index exceeds the maximum record number, matching failed and
- * send a callback.
- *
- * Returns None.
- *
- ******************************************************************************/
+/** This function match the random address to the appointed device record,
+ * starting from calculating IRK. If the record index exceeds the maximum record
+ * number, matching failed and send a callback. */
static bool btm_ble_match_random_bda(void* data, void* context) {
- RawAddress* random_bda = (RawAddress*)context;
- /* use the 3 MSB of bd address as prand */
-
- uint8_t rand[3];
- rand[0] = random_bda->address[2];
- rand[1] = random_bda->address[1];
- rand[2] = random_bda->address[0];
-
BTM_TRACE_EVENT("%s next iteration", __func__);
+ RawAddress* random_bda = (RawAddress*)context;
- tSMP_ENC output;
tBTM_SEC_DEV_REC* p_dev_rec = static_cast<tBTM_SEC_DEV_REC*>(data);
BTM_TRACE_DEBUG("sec_flags = %02x device_type = %d", p_dev_rec->sec_flags,
@@ -291,22 +227,20 @@
!(p_dev_rec->ble.key_type & BTM_LE_KEY_PID))
return true;
- /* generate X = E irk(R0, R1, R2) and R is random address 3 LSO */
- SMP_Encrypt(p_dev_rec->ble.keys.irk, BT_OCTET16_LEN, &rand[0], 3, &output);
- // if it was match, finish iteration, otherwise continue
- return !btm_ble_proc_resolve_x(output, *random_bda);
+ if (rpa_matches_irk(*random_bda, p_dev_rec->ble.keys.irk)) {
+ BTM_TRACE_EVENT("match is found");
+ // if it was match, finish iteration, otherwise continue
+ return false;
+ }
+
+ // not a match, continue iteration
+ return true;
}
-/*******************************************************************************
- *
- * Function btm_ble_resolve_random_addr
- *
- * Description This function is called to resolve a random address.
- *
- * Returns pointer to the security record of the device whom a random
- * address is matched to.
- *
- ******************************************************************************/
+/** This function is called to resolve a random address.
+ * Returns pointer to the security record of the device whom a random address is
+ * matched to.
+ */
tBTM_SEC_DEV_REC* btm_ble_resolve_random_addr(const RawAddress& random_bda) {
BTM_TRACE_EVENT("%s", __func__);
@@ -326,13 +260,7 @@
/*******************************************************************************
* address mapping between pseudo address and real connection address
******************************************************************************/
-/*******************************************************************************
- *
- * Function btm_find_dev_by_identity_addr
- *
- * Description find the security record whose LE static address is matching
- *
- ******************************************************************************/
+/** Find the security record whose LE identity address is matching */
tBTM_SEC_DEV_REC* btm_find_dev_by_identity_addr(const RawAddress& bd_addr,
uint8_t addr_type) {
#if (BLE_PRIVACY_SPT == TRUE)
@@ -341,12 +269,12 @@
node = list_next(node)) {
tBTM_SEC_DEV_REC* p_dev_rec =
static_cast<tBTM_SEC_DEV_REC*>(list_node(node));
- if (p_dev_rec->ble.static_addr == bd_addr) {
- if ((p_dev_rec->ble.static_addr_type & (~BLE_ADDR_TYPE_ID_BIT)) !=
+ if (p_dev_rec->ble.identity_addr == bd_addr) {
+ if ((p_dev_rec->ble.identity_addr_type & (~BLE_ADDR_TYPE_ID_BIT)) !=
(addr_type & (~BLE_ADDR_TYPE_ID_BIT)))
BTM_TRACE_WARNING(
"%s find pseudo->random match with diff addr type: %d vs %d",
- __func__, p_dev_rec->ble.static_addr_type, addr_type);
+ __func__, p_dev_rec->ble.identity_addr_type, addr_type);
/* found the match */
return p_dev_rec;
@@ -399,16 +327,16 @@
*
******************************************************************************/
bool btm_random_pseudo_to_identity_addr(RawAddress* random_pseudo,
- uint8_t* p_static_addr_type) {
+ uint8_t* p_identity_addr_type) {
#if (BLE_PRIVACY_SPT == TRUE)
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(*random_pseudo);
if (p_dev_rec != NULL) {
if (p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) {
- *p_static_addr_type = p_dev_rec->ble.static_addr_type;
- *random_pseudo = p_dev_rec->ble.static_addr;
+ *p_identity_addr_type = p_dev_rec->ble.identity_addr_type;
+ *random_pseudo = p_dev_rec->ble.identity_addr;
if (controller_get_interface()->supports_ble_privacy())
- *p_static_addr_type |= BLE_ADDR_TYPE_ID_BIT;
+ *p_identity_addr_type |= BLE_ADDR_TYPE_ID_BIT;
return true;
}
}
@@ -458,10 +386,10 @@
if (p_acl != NULL) {
if (rra_type == BTM_BLE_ADDR_PSEUDO) {
- /* use static address, resolvable_private_addr is empty */
+ /* use identity address, resolvable_private_addr is empty */
if (rra_dummy) {
- p_acl->active_remote_addr_type = p_sec_rec->ble.static_addr_type;
- p_acl->active_remote_addr = p_sec_rec->ble.static_addr;
+ p_acl->active_remote_addr_type = p_sec_rec->ble.identity_addr_type;
+ p_acl->active_remote_addr = p_sec_rec->ble.identity_addr;
} else {
p_acl->active_remote_addr_type = BLE_ADDR_RANDOM;
p_acl->active_remote_addr = rpa;
diff --git a/stack/btm/btm_ble_adv_filter.cc b/stack/btm/btm_ble_adv_filter.cc
index 54e038e..f69f1a2 100644
--- a/stack/btm/btm_ble_adv_filter.cc
+++ b/stack/btm/btm_ble_adv_filter.cc
@@ -18,11 +18,6 @@
#define LOG_TAG "bt_btm_ble"
-#include <base/bind.h>
-#include <string.h>
-#include <algorithm>
-#include <vector>
-
#include "bt_target.h"
#include "bt_types.h"
@@ -34,6 +29,13 @@
#include "hcidefs.h"
#include "hcimsgs.h"
+#include <string.h>
+#include <algorithm>
+#include <vector>
+
+#include <base/bind.h>
+#include <base/bind_helpers.h>
+
using base::Bind;
using bluetooth::Uuid;
@@ -594,8 +596,6 @@
memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
}
-void DoNothing(uint8_t a, uint8_t b, uint8_t c) {}
-
void BTM_LE_PF_set(tBTM_BLE_PF_FILT_INDEX filt_index,
std::vector<ApcfCommand> commands,
tBTM_BLE_PF_CFG_CBACK cb) {
@@ -620,7 +620,8 @@
target_addr.bda = cmd.address;
target_addr.type = cmd.addr_type;
- BTM_LE_PF_addr_filter(action, filt_index, target_addr, Bind(DoNothing));
+ BTM_LE_PF_addr_filter(action, filt_index, target_addr,
+ base::DoNothing());
break;
}
@@ -632,24 +633,24 @@
case BTM_BLE_PF_SRVC_SOL_UUID: {
BTM_LE_PF_uuid_filter(action, filt_index, cmd.type, cmd.uuid,
BTM_BLE_PF_LOGIC_AND, cmd.uuid_mask,
- Bind(DoNothing));
+ base::DoNothing());
break;
}
case BTM_BLE_PF_LOCAL_NAME: {
- BTM_LE_PF_local_name(action, filt_index, cmd.name, Bind(DoNothing));
+ BTM_LE_PF_local_name(action, filt_index, cmd.name, base::DoNothing());
break;
}
case BTM_BLE_PF_MANU_DATA: {
BTM_LE_PF_manu_data(action, filt_index, cmd.company, cmd.company_mask,
- cmd.data, cmd.data_mask, Bind(DoNothing));
+ cmd.data, cmd.data_mask, base::DoNothing());
break;
}
case BTM_BLE_PF_SRVC_DATA_PATTERN: {
BTM_LE_PF_srvc_data_pattern(action, filt_index, cmd.data, cmd.data_mask,
- Bind(DoNothing));
+ base::DoNothing());
break;
}
diff --git a/stack/btm/btm_ble_bgconn.cc b/stack/btm/btm_ble_bgconn.cc
index 952e953..73256c8 100644
--- a/stack/btm/btm_ble_bgconn.cc
+++ b/stack/btm/btm_ble_bgconn.cc
@@ -23,50 +23,45 @@
******************************************************************************/
#include <base/logging.h>
-#include <string.h>
#include <unordered_map>
#include "bt_types.h"
-#include "bt_utils.h"
#include "btm_int.h"
#include "btu.h"
#include "device/include/controller.h"
#include "hcimsgs.h"
#include "l2c_int.h"
-#include "osi/include/allocator.h"
-#include "osi/include/osi.h"
-#ifndef BTM_BLE_SCAN_PARAM_TOUT
-#define BTM_BLE_SCAN_PARAM_TOUT 50 /* 50 seconds */
-#endif
-
-static void btm_suspend_wl_activity(tBTM_BLE_WL_STATE wl_state);
-static void btm_resume_wl_activity(tBTM_BLE_WL_STATE wl_state);
+extern void btm_send_hci_create_connection(
+ uint16_t scan_int, uint16_t scan_win, uint8_t init_filter_policy,
+ uint8_t addr_type_peer, const RawAddress& bda_peer, uint8_t addr_type_own,
+ uint16_t conn_int_min, uint16_t conn_int_max, uint16_t conn_latency,
+ uint16_t conn_timeout, uint16_t min_ce_len, uint16_t max_ce_len,
+ uint8_t phy);
+extern void btm_ble_create_conn_cancel();
// Unfortunately (for now?) we have to maintain a copy of the device whitelist
// on the host to determine if a device is pending to be connected or not. This
// controls whether the host should keep trying to scan for whitelisted
// peripherals or not.
// TODO: Move all of this to controller/le/background_list or similar?
-typedef struct background_connection_t {
+struct BackgroundConnection {
RawAddress address;
uint8_t addr_type;
-
bool in_controller_wl;
uint8_t addr_type_in_wl;
-
bool pending_removal;
-} background_connection_t;
+};
struct BgConnHash {
- bool operator()(const RawAddress& x) const {
+ std::size_t operator()(const RawAddress& x) const {
const uint8_t* a = x.address;
return a[0] ^ (a[1] << 8) ^ (a[2] << 16) ^ (a[3] << 24) ^ a[4] ^
(a[5] << 8);
}
};
-static std::unordered_map<RawAddress, background_connection_t, BgConnHash>
+static std::unordered_map<RawAddress, BackgroundConnection, BgConnHash>
background_connections;
static void background_connection_add(uint8_t addr_type,
@@ -74,9 +69,9 @@
auto map_iter = background_connections.find(address);
if (map_iter == background_connections.end()) {
background_connections[address] =
- background_connection_t{address, addr_type, false, 0, false};
+ BackgroundConnection{address, addr_type, false, 0, false};
} else {
- background_connection_t* connection = &map_iter->second;
+ BackgroundConnection* connection = &map_iter->second;
connection->addr_type = addr_type;
connection->pending_removal = false;
}
@@ -97,7 +92,7 @@
static bool background_connections_pending() {
for (auto& map_el : background_connections) {
- background_connection_t* connection = &map_el.second;
+ BackgroundConnection* connection = &map_el.second;
if (connection->pending_removal) continue;
const bool connected =
BTM_IsAclConnectionUp(connection->address, BT_TRANSPORT_LE);
@@ -155,18 +150,42 @@
*
******************************************************************************/
void btm_ble_bgconn_cancel_if_disconnected(const RawAddress& bd_addr) {
- if (btm_cb.ble_ctr_cb.conn_state != BLE_BG_CONN) return;
+ if (btm_ble_get_conn_st() != BLE_CONNECTING) return;
auto map_it = background_connections.find(bd_addr);
if (map_it != background_connections.end()) {
- background_connection_t* connection = &map_it->second;
+ BackgroundConnection* connection = &map_it->second;
if (!connection->in_controller_wl && !connection->pending_removal &&
!BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_LE)) {
- btm_ble_start_auto_conn(false);
+ btm_ble_stop_auto_conn();
}
}
}
+bool BTM_BackgroundConnectAddressKnown(const RawAddress& address) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(address);
+
+ // not a known device, or a classic device, we assume public address
+ if (p_dev_rec == NULL || (p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) == 0)
+ return true;
+
+ // bonded device with identity address known
+ if (p_dev_rec->ble.identity_addr != address &&
+ !p_dev_rec->ble.identity_addr.IsEmpty()) {
+ return true;
+ }
+
+ // Public address, Random Static, or Random Non-Resolvable Address known
+ if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_PUBLIC ||
+ !BTM_BLE_IS_RESOLVE_BDA(address)) {
+ return true;
+ }
+
+ // Only Resolvable Private Address (RPA) is known, we don't allow it into
+ // the background connection procedure.
+ return false;
+}
+
/*******************************************************************************
*
* Function btm_add_dev_to_controller
@@ -175,33 +194,34 @@
******************************************************************************/
bool btm_add_dev_to_controller(bool to_add, const RawAddress& bd_addr) {
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
- bool started = false;
if (p_dev_rec != NULL && p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) {
if (to_add) {
- if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_PUBLIC ||
- !BTM_BLE_IS_RESOLVE_BDA(bd_addr)) {
+ if (p_dev_rec->ble.identity_addr != bd_addr &&
+ !p_dev_rec->ble.identity_addr.IsEmpty()) {
+ background_connection_add(p_dev_rec->ble.identity_addr_type,
+ p_dev_rec->ble.identity_addr);
+ } else {
background_connection_add(p_dev_rec->ble.ble_addr_type, bd_addr);
- started = true;
- p_dev_rec->ble.in_controller_list |= BTM_WHITE_LIST_BIT;
- } else if (p_dev_rec->ble.static_addr != bd_addr &&
- !p_dev_rec->ble.static_addr.IsEmpty()) {
- background_connection_add(p_dev_rec->ble.static_addr_type,
- p_dev_rec->ble.static_addr);
- started = true;
- p_dev_rec->ble.in_controller_list |= BTM_WHITE_LIST_BIT;
- }
- } else {
- if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_PUBLIC ||
- !BTM_BLE_IS_RESOLVE_BDA(bd_addr)) {
- background_connection_remove(bd_addr);
- started = true;
+
+ if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_RANDOM &&
+ BTM_BLE_IS_RESOLVE_BDA(bd_addr)) {
+ LOG(INFO) << __func__ << " addig RPA into white list";
+ }
}
- if (!p_dev_rec->ble.static_addr.IsEmpty() &&
- p_dev_rec->ble.static_addr != bd_addr) {
- background_connection_remove(p_dev_rec->ble.static_addr);
- started = true;
+ p_dev_rec->ble.in_controller_list |= BTM_WHITE_LIST_BIT;
+ } else {
+ if (!p_dev_rec->ble.identity_addr.IsEmpty() &&
+ p_dev_rec->ble.identity_addr != bd_addr) {
+ background_connection_remove(p_dev_rec->ble.identity_addr);
+ } else {
+ background_connection_remove(bd_addr);
+
+ if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_RANDOM &&
+ BTM_BLE_IS_RESOLVE_BDA(bd_addr)) {
+ LOG(INFO) << __func__ << " removing RPA from white list";
+ }
}
p_dev_rec->ble.in_controller_list &= ~BTM_WHITE_LIST_BIT;
@@ -209,15 +229,29 @@
} else {
/* not a known device, i.e. attempt to connect to device never seen before
*/
- started = true;
if (to_add)
background_connection_add(BLE_ADDR_PUBLIC, bd_addr);
else
background_connection_remove(bd_addr);
}
- return started;
+ return true;
}
+
+/** White list add complete */
+void wl_add_complete(uint8_t* p_data, uint16_t /* evt_len */) {
+ uint8_t status;
+ STREAM_TO_UINT8(status, p_data);
+ VLOG(2) << __func__ << ": status=" << loghex(status);
+}
+
+/** White list element remove complete */
+void wl_remove_complete(uint8_t* p_data, uint16_t /* evt_len */) {
+ uint8_t status;
+ STREAM_TO_UINT8(status, p_data);
+ VLOG(2) << __func__ << ": status=" << loghex(status);
+}
+
/*******************************************************************************
*
* Function btm_execute_wl_dev_operation
@@ -229,20 +263,22 @@
// handle removals first to avoid filling up controller's white list
for (auto map_it = background_connections.begin();
map_it != background_connections.end();) {
- background_connection_t* connection = &map_it->second;
+ BackgroundConnection* connection = &map_it->second;
if (connection->pending_removal) {
- btsnd_hcic_ble_remove_from_white_list(connection->addr_type_in_wl,
- connection->address);
+ btsnd_hcic_ble_remove_from_white_list(
+ connection->addr_type_in_wl, connection->address,
+ base::BindOnce(&wl_remove_complete));
map_it = background_connections.erase(map_it);
} else
++map_it;
}
for (auto& map_el : background_connections) {
- background_connection_t* connection = &map_el.second;
+ BackgroundConnection* connection = &map_el.second;
const bool connected =
BTM_IsAclConnectionUp(connection->address, BT_TRANSPORT_LE);
if (!connection->in_controller_wl && !connected) {
- btsnd_hcic_ble_add_white_list(connection->addr_type, connection->address);
+ btsnd_hcic_ble_add_white_list(connection->addr_type, connection->address,
+ base::BindOnce(&wl_add_complete));
connection->in_controller_wl = true;
connection->addr_type_in_wl = connection->addr_type;
} else if (connection->in_controller_wl && connected) {
@@ -250,8 +286,9 @@
connection between two LE addresses. Not all controllers handle this
correctly, therefore we must make sure connected devices are not in
the white list when bg connection attempt is active. */
- btsnd_hcic_ble_remove_from_white_list(connection->addr_type_in_wl,
- connection->address);
+ btsnd_hcic_ble_remove_from_white_list(
+ connection->addr_type_in_wl, connection->address,
+ base::BindOnce(&wl_remove_complete));
connection->in_controller_wl = false;
}
}
@@ -260,58 +297,6 @@
/*******************************************************************************
*
- * Function btm_update_dev_to_white_list
- *
- * Description This function adds or removes a device into/from
- * the white list.
- *
- ******************************************************************************/
-bool btm_update_dev_to_white_list(bool to_add, const RawAddress& bd_addr) {
- tBTM_BLE_CB* p_cb = &btm_cb.ble_ctr_cb;
-
- if (to_add &&
- background_connections_count() ==
- controller_get_interface()->get_ble_white_list_size()) {
- BTM_TRACE_ERROR("%s Whitelist full, unable to add device", __func__);
- return false;
- }
-
- btm_suspend_wl_activity(p_cb->wl_state);
- btm_add_dev_to_controller(to_add, bd_addr);
- btm_resume_wl_activity(p_cb->wl_state);
- return true;
-}
-
-/*******************************************************************************
- *
- * Function btm_ble_clear_white_list
- *
- * Description This function clears the white list.
- *
- ******************************************************************************/
-void btm_ble_clear_white_list(void) {
- BTM_TRACE_EVENT("btm_ble_clear_white_list");
- btsnd_hcic_ble_clear_white_list();
- background_connections_clear();
-}
-
-/*******************************************************************************
- *
- * Function btm_ble_clear_white_list_complete
- *
- * Description Indicates white list cleared.
- *
- ******************************************************************************/
-void btm_ble_clear_white_list_complete(uint8_t* p_data,
- UNUSED_ATTR uint16_t evt_len) {
- uint8_t status;
-
- STREAM_TO_UINT8(status, p_data);
- BTM_TRACE_EVENT("%s status=%d", __func__, status);
-}
-
-/*******************************************************************************
- *
* Function btm_ble_white_list_init
*
* Description Initialize white list size
@@ -321,98 +306,44 @@
BTM_TRACE_DEBUG("%s white_list_size = %d", __func__, white_list_size);
}
-/*******************************************************************************
- *
- * Function btm_ble_add_2_white_list_complete
- *
- * Description White list element added
- *
- ******************************************************************************/
-void btm_ble_add_2_white_list_complete(uint8_t status) {
- BTM_TRACE_EVENT("%s status=%d", __func__, status);
-}
-
-/*******************************************************************************
- *
- * Function btm_ble_remove_from_white_list_complete
- *
- * Description White list element removal complete
- *
- ******************************************************************************/
-void btm_ble_remove_from_white_list_complete(uint8_t* p,
- UNUSED_ATTR uint16_t evt_len) {
- BTM_TRACE_EVENT("%s status=%d", __func__, *p);
-}
-
-void btm_ble_create_conn_cancel_complete(uint8_t* p) {
- uint8_t status;
- STREAM_TO_UINT8(status, p);
-
- if (status == HCI_ERR_COMMAND_DISALLOWED) {
- /* This is a sign that logic around keeping connection state is broken */
- LOG(ERROR)
- << "Attempt to cancel LE connection, when no connection is pending.";
- if (btm_ble_get_conn_st() == BLE_CONN_CANCEL) {
- btm_ble_set_conn_st(BLE_CONN_IDLE);
- btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, nullptr, status);
- }
- }
-}
-
-void btm_send_hci_create_connection(
- uint16_t scan_int, uint16_t scan_win, uint8_t init_filter_policy,
- uint8_t addr_type_peer, const RawAddress& bda_peer, uint8_t addr_type_own,
- uint16_t conn_int_min, uint16_t conn_int_max, uint16_t conn_latency,
- uint16_t conn_timeout, uint16_t min_ce_len, uint16_t max_ce_len,
- uint8_t initiating_phys) {
- if (controller_get_interface()->supports_ble_extended_advertising()) {
- EXT_CONN_PHY_CFG phy_cfg[3]; // maximum three phys
-
- int phy_cnt =
- std::bitset<std::numeric_limits<uint8_t>::digits>(initiating_phys)
- .count();
-
- LOG_ASSERT(phy_cnt < 3) << "More than three phys provided";
- // TODO(jpawlowski): tune parameters for different transports
- for (int i = 0; i < phy_cnt; i++) {
- phy_cfg[i].scan_int = scan_int;
- phy_cfg[i].scan_win = scan_win;
- phy_cfg[i].conn_int_min = conn_int_min;
- phy_cfg[i].conn_int_max = conn_int_max;
- phy_cfg[i].conn_latency = conn_latency;
- phy_cfg[i].sup_timeout = conn_timeout;
- phy_cfg[i].min_ce_len = min_ce_len;
- phy_cfg[i].max_ce_len = max_ce_len;
- }
-
- addr_type_peer &= ~BLE_ADDR_TYPE_ID_BIT;
- btsnd_hcic_ble_ext_create_conn(init_filter_policy, addr_type_own,
- addr_type_peer, bda_peer, initiating_phys,
- phy_cfg);
- } else {
- btsnd_hcic_ble_create_ll_conn(scan_int, scan_win, init_filter_policy,
- addr_type_peer, bda_peer, addr_type_own,
- conn_int_min, conn_int_max, conn_latency,
- conn_timeout, min_ce_len, max_ce_len);
- }
-}
-
-/*******************************************************************************
- *
- * Function btm_ble_start_auto_conn
- *
- * Description This function is to start/stop auto connection procedure.
- *
- * Parameters start: true to start; false to stop.
- *
- * Returns void
- *
- ******************************************************************************/
-bool btm_ble_start_auto_conn(bool start) {
+bool BTM_SetLeConnectionModeToFast() {
+ VLOG(2) << __func__;
tBTM_BLE_CB* p_cb = &btm_cb.ble_ctr_cb;
- bool exec = true;
- uint16_t scan_int;
- uint16_t scan_win;
+ if ((p_cb->scan_int == BTM_BLE_SCAN_PARAM_UNDEF &&
+ p_cb->scan_win == BTM_BLE_SCAN_PARAM_UNDEF) ||
+ (p_cb->scan_int == BTM_BLE_SCAN_SLOW_INT_1 &&
+ p_cb->scan_win == BTM_BLE_SCAN_SLOW_WIN_1)) {
+ p_cb->scan_int = BTM_BLE_SCAN_FAST_INT;
+ p_cb->scan_win = BTM_BLE_SCAN_FAST_WIN;
+ return true;
+ }
+ return false;
+}
+
+void BTM_SetLeConnectionModeToSlow() {
+ VLOG(2) << __func__;
+ tBTM_BLE_CB* p_cb = &btm_cb.ble_ctr_cb;
+ if ((p_cb->scan_int == BTM_BLE_SCAN_PARAM_UNDEF &&
+ p_cb->scan_win == BTM_BLE_SCAN_PARAM_UNDEF) ||
+ (p_cb->scan_int == BTM_BLE_SCAN_FAST_INT &&
+ p_cb->scan_win == BTM_BLE_SCAN_FAST_WIN)) {
+ p_cb->scan_int = BTM_BLE_SCAN_SLOW_INT_1;
+ p_cb->scan_win = BTM_BLE_SCAN_SLOW_WIN_1;
+ }
+}
+
+/** This function is to start auto connection procedure */
+bool btm_ble_start_auto_conn() {
+ tBTM_BLE_CB* p_cb = &btm_cb.ble_ctr_cb;
+
+ BTM_TRACE_EVENT("%s", __func__);
+
+ uint16_t scan_int = (p_cb->scan_int == BTM_BLE_SCAN_PARAM_UNDEF)
+ ? BTM_BLE_SCAN_SLOW_INT_1
+ : p_cb->scan_int;
+ uint16_t scan_win = (p_cb->scan_win == BTM_BLE_SCAN_PARAM_UNDEF)
+ ? BTM_BLE_SCAN_SLOW_WIN_1
+ : p_cb->scan_win;
uint8_t own_addr_type = p_cb->addr_mgnt_cb.own_addr_type;
uint8_t peer_addr_type = BLE_ADDR_PUBLIC;
@@ -420,63 +351,60 @@
if (controller_get_interface()->supports_ble_2m_phy()) phy |= PHY_LE_2M;
if (controller_get_interface()->supports_ble_coded_phy()) phy |= PHY_LE_CODED;
- BTM_TRACE_EVENT("%s start=%d", __func__, start);
-
- if (start) {
- if (p_cb->conn_state == BLE_CONN_IDLE && background_connections_pending() &&
- btm_ble_topology_check(BTM_BLE_STATE_INIT) && l2cu_can_allocate_lcb()) {
- p_cb->wl_state |= BTM_BLE_WL_INIT;
-
- btm_execute_wl_dev_operation();
-
-#if (BLE_PRIVACY_SPT == TRUE)
- btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_INIT);
-#endif
- scan_int = (p_cb->scan_int == BTM_BLE_SCAN_PARAM_UNDEF)
- ? BTM_BLE_SCAN_SLOW_INT_1
- : p_cb->scan_int;
- scan_win = (p_cb->scan_win == BTM_BLE_SCAN_PARAM_UNDEF)
- ? BTM_BLE_SCAN_SLOW_WIN_1
- : p_cb->scan_win;
-
-#if (BLE_PRIVACY_SPT == TRUE)
- if (btm_cb.ble_ctr_cb.rl_state != BTM_BLE_RL_IDLE &&
- controller_get_interface()->supports_ble_privacy()) {
- own_addr_type |= BLE_ADDR_TYPE_ID_BIT;
- peer_addr_type |= BLE_ADDR_TYPE_ID_BIT;
- }
-#endif
-
- btm_send_hci_create_connection(
- scan_int, /* uint16_t scan_int */
- scan_win, /* uint16_t scan_win */
- 0x01, /* uint8_t white_list */
- peer_addr_type, /* uint8_t addr_type_peer */
- RawAddress::kEmpty, /* BD_ADDR bda_peer */
- own_addr_type, /* uint8_t addr_type_own */
- BTM_BLE_CONN_INT_MIN_DEF, /* uint16_t conn_int_min */
- BTM_BLE_CONN_INT_MAX_DEF, /* uint16_t conn_int_max */
- BTM_BLE_CONN_SLAVE_LATENCY_DEF, /* uint16_t conn_latency */
- BTM_BLE_CONN_TIMEOUT_DEF, /* uint16_t conn_timeout */
- 0, /* uint16_t min_len */
- 0, /* uint16_t max_len */
- phy);
- btm_ble_set_conn_st(BLE_BG_CONN);
- } else {
- exec = false;
- }
- } else {
- if (p_cb->conn_state == BLE_BG_CONN) {
- btsnd_hcic_ble_create_conn_cancel();
- btm_ble_set_conn_st(BLE_CONN_CANCEL);
- p_cb->wl_state &= ~BTM_BLE_WL_INIT;
- } else {
- BTM_TRACE_DEBUG("conn_st = %d, not in auto conn state, cannot stop",
- p_cb->conn_state);
- exec = false;
- }
+ if (!btm_ble_topology_check(BTM_BLE_STATE_INIT)) {
+ LOG(INFO) << "initate background connection fail, topology limitation";
+ return false;
}
- return exec;
+
+ if (btm_ble_get_conn_st() != BLE_CONN_IDLE ||
+ !background_connections_pending() || !l2cu_can_allocate_lcb()) {
+ return false;
+ }
+
+ p_cb->wl_state |= BTM_BLE_WL_INIT;
+
+ btm_execute_wl_dev_operation();
+
+#if (BLE_PRIVACY_SPT == TRUE)
+ btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_INIT);
+ if (btm_cb.ble_ctr_cb.rl_state != BTM_BLE_RL_IDLE &&
+ controller_get_interface()->supports_ble_privacy()) {
+ own_addr_type |= BLE_ADDR_TYPE_ID_BIT;
+ peer_addr_type |= BLE_ADDR_TYPE_ID_BIT;
+ }
+#endif
+
+ btm_send_hci_create_connection(
+ scan_int, /* uint16_t scan_int */
+ scan_win, /* uint16_t scan_win */
+ 0x01, /* uint8_t white_list */
+ peer_addr_type, /* uint8_t addr_type_peer */
+ RawAddress::kEmpty, /* BD_ADDR bda_peer */
+ own_addr_type, /* uint8_t addr_type_own */
+ BTM_BLE_CONN_INT_MIN_DEF, /* uint16_t conn_int_min */
+ BTM_BLE_CONN_INT_MAX_DEF, /* uint16_t conn_int_max */
+ BTM_BLE_CONN_SLAVE_LATENCY_DEF, /* uint16_t conn_latency */
+ BTM_BLE_CONN_TIMEOUT_DEF, /* uint16_t conn_timeout */
+ 0, /* uint16_t min_len */
+ 0, /* uint16_t max_len */
+ phy);
+ return true;
+}
+
+/** This function is to stop auto connection procedure */
+bool btm_ble_stop_auto_conn() {
+ BTM_TRACE_EVENT("%s", __func__);
+
+ if (btm_ble_get_conn_st() != BLE_CONNECTING) {
+ BTM_TRACE_DEBUG("conn_st = %d, not in auto conn state, cannot stop",
+ btm_ble_get_conn_st());
+ return false;
+ }
+
+ btm_ble_create_conn_cancel();
+
+ btm_cb.ble_ctr_cb.wl_state &= ~BTM_BLE_WL_INIT;
+ return true;
}
/*******************************************************************************
@@ -493,38 +421,9 @@
******************************************************************************/
bool btm_ble_suspend_bg_conn(void) {
BTM_TRACE_EVENT("%s", __func__);
+ return btm_ble_stop_auto_conn();
+}
- if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_AUTO)
- return btm_ble_start_auto_conn(false);
-
- return false;
-}
-/*******************************************************************************
- *
- * Function btm_suspend_wl_activity
- *
- * Description This function is to suspend white list related activity
- *
- * Returns none.
- *
- ******************************************************************************/
-static void btm_suspend_wl_activity(tBTM_BLE_WL_STATE wl_state) {
- if (wl_state & BTM_BLE_WL_INIT) {
- btm_ble_start_auto_conn(false);
- }
-}
-/*******************************************************************************
- *
- * Function btm_resume_wl_activity
- *
- * Description This function is to resume white list related activity
- *
- * Returns none.
- *
- ******************************************************************************/
-static void btm_resume_wl_activity(tBTM_BLE_WL_STATE wl_state) {
- btm_ble_resume_bg_conn();
-}
/*******************************************************************************
*
* Function btm_ble_resume_bg_conn
@@ -537,113 +436,49 @@
* Returns none.
*
******************************************************************************/
-bool btm_ble_resume_bg_conn(void) {
- tBTM_BLE_CB* p_cb = &btm_cb.ble_ctr_cb;
- if (p_cb->bg_conn_type == BTM_BLE_CONN_AUTO) {
- return btm_ble_start_auto_conn(true);
+bool btm_ble_resume_bg_conn(void) { return btm_ble_start_auto_conn(); }
+
+/** Adds the device into white list. Returns false if white list is full and
+ * device can't be added, true otherwise. */
+bool BTM_WhiteListAdd(const RawAddress& address) {
+ VLOG(1) << __func__ << ": " << address;
+
+ if (background_connections_count() ==
+ controller_get_interface()->get_ble_white_list_size()) {
+ BTM_TRACE_ERROR("%s Whitelist full, unable to add device", __func__);
+ return false;
}
- return false;
-}
-/*******************************************************************************
- *
- * Function btm_ble_get_conn_st
- *
- * Description This function get BLE connection state
- *
- * Returns connection state
- *
- ******************************************************************************/
-tBTM_BLE_CONN_ST btm_ble_get_conn_st(void) {
- return btm_cb.ble_ctr_cb.conn_state;
-}
-/*******************************************************************************
- *
- * Function btm_ble_set_conn_st
- *
- * Description This function set BLE connection state
- *
- * Returns None.
- *
- ******************************************************************************/
-void btm_ble_set_conn_st(tBTM_BLE_CONN_ST new_st) {
- btm_cb.ble_ctr_cb.conn_state = new_st;
-
- if (new_st == BLE_BG_CONN || new_st == BLE_DIR_CONN)
- btm_ble_set_topology_mask(BTM_BLE_STATE_INIT_BIT);
- else
- btm_ble_clear_topology_mask(BTM_BLE_STATE_INIT_BIT);
-}
-
-/*******************************************************************************
- *
- * Function btm_ble_enqueue_direct_conn_req
- *
- * Description This function enqueue the direct connection request
- *
- * Returns None.
- *
- ******************************************************************************/
-void btm_ble_enqueue_direct_conn_req(void* p_param) {
- tBTM_BLE_CONN_REQ* p =
- (tBTM_BLE_CONN_REQ*)osi_malloc(sizeof(tBTM_BLE_CONN_REQ));
-
- p->p_param = p_param;
-
- fixed_queue_enqueue(btm_cb.ble_ctr_cb.conn_pending_q, p);
-}
-/*******************************************************************************
- *
- * Function btm_ble_dequeue_direct_conn_req
- *
- * Description This function dequeues the direct connection request
- *
- * Returns None.
- *
- ******************************************************************************/
-void btm_ble_dequeue_direct_conn_req(const RawAddress& rem_bda) {
- if (fixed_queue_is_empty(btm_cb.ble_ctr_cb.conn_pending_q)) return;
-
- list_t* list = fixed_queue_get_list(btm_cb.ble_ctr_cb.conn_pending_q);
- for (const list_node_t* node = list_begin(list); node != list_end(list);
- node = list_next(node)) {
- tBTM_BLE_CONN_REQ* p_req = (tBTM_BLE_CONN_REQ*)list_node(node);
- tL2C_LCB* p_lcb = (tL2C_LCB*)p_req->p_param;
- if ((p_lcb == NULL) || (!p_lcb->in_use)) {
- continue;
- }
- // If BD address matches
- if (rem_bda == p_lcb->remote_bd_addr) {
- fixed_queue_try_remove_from_queue(btm_cb.ble_ctr_cb.conn_pending_q,
- p_req);
- l2cu_release_lcb((tL2C_LCB*)p_req->p_param);
- osi_free((void*)p_req);
- break;
- }
+ if (btm_cb.ble_ctr_cb.wl_state & BTM_BLE_WL_INIT) {
+ btm_ble_stop_auto_conn();
}
+ btm_add_dev_to_controller(true, address);
+ btm_ble_resume_bg_conn();
+ return true;
}
-/*******************************************************************************
- *
- * Function btm_send_pending_direct_conn
- *
- * Description This function send the pending direct connection request in
- * queue
- *
- * Returns true if started, false otherwise
- *
- ******************************************************************************/
-bool btm_send_pending_direct_conn(void) {
- tBTM_BLE_CONN_REQ* p_req;
- bool rt = false;
- p_req = (tBTM_BLE_CONN_REQ*)fixed_queue_try_dequeue(
- btm_cb.ble_ctr_cb.conn_pending_q);
- if (p_req != NULL) {
- tL2C_LCB* p_lcb = (tL2C_LCB*)(p_req->p_param);
- /* Ignore entries that might have been released while queued. */
- if (p_lcb->in_use) rt = l2cble_init_direct_conn(p_lcb);
- osi_free(p_req);
+/** Removes the device from white list */
+void BTM_WhiteListRemove(const RawAddress& address) {
+ VLOG(1) << __func__ << ": " << address;
+ if (btm_cb.ble_ctr_cb.wl_state & BTM_BLE_WL_INIT) {
+ btm_ble_stop_auto_conn();
}
+ btm_add_dev_to_controller(false, address);
+ btm_ble_resume_bg_conn();
+}
- return rt;
+/** clear white list complete */
+void wl_clear_complete(uint8_t* p_data, uint16_t /* evt_len */) {
+ uint8_t status;
+ STREAM_TO_UINT8(status, p_data);
+ VLOG(2) << __func__ << ": status=" << loghex(status);
+}
+
+/** Clear the whitelist, end any pending whitelist connections */
+void BTM_WhiteListClear() {
+ VLOG(1) << __func__;
+ if (!controller_get_interface()->supports_ble()) return;
+ btm_ble_stop_auto_conn();
+ btsnd_hcic_ble_clear_white_list(base::BindOnce(&wl_clear_complete));
+ background_connections_clear();
}
diff --git a/stack/btm/btm_ble_bgconn.h b/stack/btm/btm_ble_bgconn.h
new file mode 100644
index 0000000..45ab2ec
--- /dev/null
+++ b/stack/btm/btm_ble_bgconn.h
@@ -0,0 +1,40 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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 "types/raw_address.h"
+
+/** Adds the device into white list. Returns false if white list is full and
+ * device can't be added, true otherwise. */
+extern bool BTM_WhiteListAdd(const RawAddress& address);
+
+/** Removes the device from white list */
+extern void BTM_WhiteListRemove(const RawAddress& address);
+
+/** Clear the whitelist, end any pending whitelist connections */
+extern void BTM_WhiteListClear();
+
+/* Use fast scan window/interval for LE connection establishment.
+ * This does not send any requests to controller, instead it changes the
+ * parameters that will be used after next add/remove request.
+ * Returns true, if the change is scheduled, false otherwise. */
+extern bool BTM_SetLeConnectionModeToFast();
+
+/* Use slow scan window/interval for LE connection establishment.
+ * This does not send any requests to controller, instead it changes the
+ * parameters that will be used after next add/remove request */
+extern void BTM_SetLeConnectionModeToSlow();
\ No newline at end of file
diff --git a/stack/btm/btm_ble_connection_establishment.cc b/stack/btm/btm_ble_connection_establishment.cc
new file mode 100644
index 0000000..c0d7791
--- /dev/null
+++ b/stack/btm/btm_ble_connection_establishment.cc
@@ -0,0 +1,254 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 <frameworks/base/core/proto/android/bluetooth/enums.pb.h>
+#include <frameworks/base/core/proto/android/bluetooth/hci/enums.pb.h>
+
+#include "bt_types.h"
+#include "btm_int.h"
+#include "common/metrics.h"
+#include "device/include/controller.h"
+#include "l2c_int.h"
+#include "stack/gatt/connection_manager.h"
+#include "stack/include/hcimsgs.h"
+
+extern void btm_ble_advertiser_notify_terminated_legacy(
+ uint8_t status, uint16_t connection_handle);
+
+/** This function get BLE connection state */
+tBTM_BLE_CONN_ST btm_ble_get_conn_st(void) {
+ return btm_cb.ble_ctr_cb.conn_state;
+}
+
+/** This function set BLE connection state */
+void btm_ble_set_conn_st(tBTM_BLE_CONN_ST new_st) {
+ btm_cb.ble_ctr_cb.conn_state = new_st;
+
+ if (new_st == BLE_CONNECTING)
+ btm_ble_set_topology_mask(BTM_BLE_STATE_INIT_BIT);
+ else
+ btm_ble_clear_topology_mask(BTM_BLE_STATE_INIT_BIT);
+}
+
+void btm_send_hci_create_connection(
+ uint16_t scan_int, uint16_t scan_win, uint8_t init_filter_policy,
+ uint8_t addr_type_peer, const RawAddress& bda_peer, uint8_t addr_type_own,
+ uint16_t conn_int_min, uint16_t conn_int_max, uint16_t conn_latency,
+ uint16_t conn_timeout, uint16_t min_ce_len, uint16_t max_ce_len,
+ uint8_t initiating_phys) {
+ if (controller_get_interface()->supports_ble_extended_advertising()) {
+ EXT_CONN_PHY_CFG phy_cfg[3]; // maximum three phys
+
+ int phy_cnt =
+ std::bitset<std::numeric_limits<uint8_t>::digits>(initiating_phys)
+ .count();
+
+ LOG_ASSERT(phy_cnt <= 3) << "More than three phys provided";
+ // TODO(jpawlowski): tune parameters for different transports
+ for (int i = 0; i < phy_cnt; i++) {
+ phy_cfg[i].scan_int = scan_int;
+ phy_cfg[i].scan_win = scan_win;
+ phy_cfg[i].conn_int_min = conn_int_min;
+ phy_cfg[i].conn_int_max = conn_int_max;
+ phy_cfg[i].conn_latency = conn_latency;
+ phy_cfg[i].sup_timeout = conn_timeout;
+ phy_cfg[i].min_ce_len = min_ce_len;
+ phy_cfg[i].max_ce_len = max_ce_len;
+ }
+
+ addr_type_peer &= ~BLE_ADDR_TYPE_ID_BIT;
+ btsnd_hcic_ble_ext_create_conn(init_filter_policy, addr_type_own,
+ addr_type_peer, bda_peer, initiating_phys,
+ phy_cfg);
+ } else {
+ btsnd_hcic_ble_create_ll_conn(scan_int, scan_win, init_filter_policy,
+ addr_type_peer, bda_peer, addr_type_own,
+ conn_int_min, conn_int_max, conn_latency,
+ conn_timeout, min_ce_len, max_ce_len);
+ }
+
+ btm_ble_set_conn_st(BLE_CONNECTING);
+}
+
+/** LE connection complete. */
+void btm_ble_create_ll_conn_complete(uint8_t status) {
+ if (status == HCI_SUCCESS) return;
+
+ LOG(WARNING) << "LE Create Connection attempt failed, status="
+ << loghex(status);
+
+ if (status == HCI_ERR_COMMAND_DISALLOWED) {
+ btm_ble_set_conn_st(BLE_CONNECTING);
+ LOG(ERROR) << "LE Create Connection - command disallowed";
+ } else {
+ btm_ble_set_conn_st(BLE_CONN_IDLE);
+ btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, NULL, status);
+ }
+}
+
+/** LE connection complete. */
+void btm_ble_conn_complete(uint8_t* p, UNUSED_ATTR uint16_t evt_len,
+ bool enhanced) {
+#if (BLE_PRIVACY_SPT == TRUE)
+ uint8_t peer_addr_type;
+#endif
+ RawAddress local_rpa, peer_rpa;
+ uint8_t role, status, bda_type;
+ uint16_t handle;
+ RawAddress bda;
+ uint16_t conn_interval, conn_latency, conn_timeout;
+ bool match = false;
+
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_UINT16(handle, p);
+ STREAM_TO_UINT8(role, p);
+ STREAM_TO_UINT8(bda_type, p);
+ STREAM_TO_BDADDR(bda, p);
+ if (enhanced) {
+ STREAM_TO_BDADDR(local_rpa, p);
+ STREAM_TO_BDADDR(peer_rpa, p);
+ }
+ STREAM_TO_UINT16(conn_interval, p);
+ STREAM_TO_UINT16(conn_latency, p);
+ STREAM_TO_UINT16(conn_timeout, p);
+ handle = HCID_GET_HANDLE(handle);
+
+ uint32_t hci_ble_event =
+ enhanced ? android::bluetooth::hci::BLE_EVT_ENHANCED_CONN_COMPLETE_EVT
+ : android::bluetooth::hci::BLE_EVT_CONN_COMPLETE_EVT;
+
+ if (status == HCI_SUCCESS) {
+#if (BLE_PRIVACY_SPT == TRUE)
+ peer_addr_type = bda_type;
+ bool addr_is_rpa =
+ (peer_addr_type == BLE_ADDR_RANDOM && BTM_BLE_IS_RESOLVE_BDA(bda));
+
+ /* We must translate whatever address we received into the "pseudo" address.
+ * i.e. if we bonded with device that was using RPA for first connection,
+ * "pseudo" address is equal to this RPA. If it later decides to use Public
+ * address, or Random Static Address, we convert it into the "pseudo"
+ * address here. */
+ if (!addr_is_rpa || peer_addr_type & BLE_ADDR_TYPE_ID_BIT) {
+ match = btm_identity_addr_to_random_pseudo(&bda, &bda_type, true);
+ }
+
+ /* possiblly receive connection complete with resolvable random while
+ the device has been paired */
+ if (!match && addr_is_rpa) {
+ tBTM_SEC_DEV_REC* match_rec = btm_ble_resolve_random_addr(bda);
+ if (match_rec) {
+ LOG(INFO) << __func__ << ": matched and resolved random address";
+ match = true;
+ match_rec->ble.active_addr_type = BTM_BLE_ADDR_RRA;
+ match_rec->ble.cur_rand_addr = bda;
+ if (!btm_ble_init_pseudo_addr(match_rec, bda)) {
+ /* assign the original address to be the current report address */
+ bda = match_rec->ble.pseudo_addr;
+ } else {
+ bda = match_rec->bd_addr;
+ }
+ } else {
+ LOG(INFO) << __func__ << ": unable to match and resolve random address";
+ }
+ }
+#endif
+ // Log for the HCI success case after resolving Bluetooth address
+ bluetooth::common::LogLinkLayerConnectionEvent(
+ &bda, handle, android::bluetooth::DIRECTION_UNKNOWN,
+ android::bluetooth::LINK_TYPE_ACL, android::bluetooth::hci::CMD_UNKNOWN,
+ android::bluetooth::hci::EVT_BLE_META, hci_ble_event, status,
+ android::bluetooth::hci::STATUS_UNKNOWN);
+
+ if (role == HCI_ROLE_MASTER) {
+ btm_ble_set_conn_st(BLE_CONN_IDLE);
+ }
+
+ connection_manager::on_connection_complete(bda);
+ btm_ble_connected(bda, handle, HCI_ENCRYPT_MODE_DISABLED, role, bda_type,
+ match);
+
+ l2cble_conn_comp(handle, role, bda, bda_type, conn_interval, conn_latency,
+ conn_timeout);
+
+#if (BLE_PRIVACY_SPT == TRUE)
+ if (enhanced) {
+ btm_ble_refresh_local_resolvable_private_addr(bda, local_rpa);
+
+ if (peer_addr_type & BLE_ADDR_TYPE_ID_BIT)
+ btm_ble_refresh_peer_resolvable_private_addr(bda, peer_rpa,
+ BLE_ADDR_RANDOM);
+ }
+#endif
+ } else {
+ // Log for non HCI success case
+ bluetooth::common::LogLinkLayerConnectionEvent(
+ &bda, handle, android::bluetooth::DIRECTION_UNKNOWN,
+ android::bluetooth::LINK_TYPE_ACL, android::bluetooth::hci::CMD_UNKNOWN,
+ android::bluetooth::hci::EVT_BLE_META, hci_ble_event, status,
+ android::bluetooth::hci::STATUS_UNKNOWN);
+
+ role = HCI_ROLE_UNKNOWN;
+ if (status != HCI_ERR_ADVERTISING_TIMEOUT) {
+ btm_ble_set_conn_st(BLE_CONN_IDLE);
+#if (BLE_PRIVACY_SPT == TRUE)
+ btm_ble_disable_resolving_list(BTM_BLE_RL_INIT, true);
+#endif
+ } else {
+#if (BLE_PRIVACY_SPT == TRUE)
+ btm_cb.ble_ctr_cb.inq_var.adv_mode = BTM_BLE_ADV_DISABLE;
+ btm_ble_disable_resolving_list(BTM_BLE_RL_ADV, true);
+#endif
+ }
+ }
+
+ btm_ble_update_mode_operation(role, &bda, status);
+
+ if (role == HCI_ROLE_SLAVE)
+ btm_ble_advertiser_notify_terminated_legacy(status, handle);
+}
+
+void btm_ble_create_conn_cancel() {
+ btsnd_hcic_ble_create_conn_cancel();
+ btm_ble_set_conn_st(BLE_CONN_CANCEL);
+}
+
+void btm_ble_create_conn_cancel_complete(uint8_t* p) {
+ uint8_t status;
+ STREAM_TO_UINT8(status, p);
+ if (status != HCI_SUCCESS) {
+ // Only log errors to prevent log spam due to whitelist connections
+ bluetooth::common::LogLinkLayerConnectionEvent(
+ nullptr, bluetooth::common::kUnknownConnectionHandle,
+ android::bluetooth::DIRECTION_OUTGOING,
+ android::bluetooth::LINK_TYPE_ACL,
+ android::bluetooth::hci::CMD_BLE_CREATE_CONN_CANCEL,
+ android::bluetooth::hci::EVT_COMMAND_COMPLETE,
+ android::bluetooth::hci::BLE_EVT_UNKNOWN, status,
+ android::bluetooth::hci::STATUS_UNKNOWN);
+ }
+
+ if (status == HCI_ERR_COMMAND_DISALLOWED) {
+ /* This is a sign that logic around keeping connection state is broken */
+ LOG(ERROR)
+ << "Attempt to cancel LE connection, when no connection is pending.";
+ if (btm_ble_get_conn_st() == BLE_CONN_CANCEL) {
+ btm_ble_set_conn_st(BLE_CONN_IDLE);
+ btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, nullptr, status);
+ }
+ }
+}
diff --git a/stack/btm/btm_ble_gap.cc b/stack/btm/btm_ble_gap.cc
index 1f8263f..ca40a2b 100644
--- a/stack/btm/btm_ble_gap.cc
+++ b/stack/btm/btm_ble_gap.cc
@@ -452,7 +452,7 @@
btm_cb.ble_ctr_cb.scan_activity |= BTM_LE_OBSERVE_ACTIVE;
if (duration != 0) {
/* start observer timer */
- period_ms_t duration_ms = duration * 1000;
+ uint64_t duration_ms = duration * 1000;
alarm_set_on_mloop(btm_cb.ble_ctr_cb.observer_timer, duration_ms,
btm_ble_observer_timer_timeout, NULL);
}
@@ -513,8 +513,8 @@
if (btm_cb.cmn_ble_vsc_cb.version_supported >=
BTM_VSC_CHIP_CAPABILITY_M_VERSION) {
STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.total_trackable_advertisers, p);
- STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.extended_scan_support, p);
- STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.debug_logging_supported, p);
+ STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.extended_scan_support, p);
+ STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.debug_logging_supported, p);
}
btm_cb.cmn_ble_vsc_cb.values_read = true;
@@ -696,59 +696,6 @@
#endif
}
-/**
- * Set BLE connectable mode to auto connect
- */
-void BTM_BleStartAutoConn() {
- BTM_TRACE_EVENT("%s", __func__);
- if (!controller_get_interface()->supports_ble()) return;
-
- if (btm_cb.ble_ctr_cb.bg_conn_type != BTM_BLE_CONN_AUTO) {
- btm_ble_start_auto_conn(true);
- btm_cb.ble_ctr_cb.bg_conn_type = BTM_BLE_CONN_AUTO;
- }
-}
-
-/*******************************************************************************
- *
- * Function BTM_BleClearBgConnDev
- *
- * Description This function is called to clear the whitelist,
- * end any pending whitelist connections,
- * and reset the local bg device list.
- *
- * Parameters void
- *
- * Returns void
- *
- ******************************************************************************/
-void BTM_BleClearBgConnDev(void) {
- if (!controller_get_interface()->supports_ble()) return;
- btm_ble_start_auto_conn(false);
- btm_ble_clear_white_list();
- gatt_reset_bgdev_list();
-}
-
-/*******************************************************************************
- *
- * Function BTM_BleUpdateBgConnDev
- *
- * Description This function is called to add or remove a device into/from
- * background connection procedure. The background connection
- * procedure is decided by the background connection type, it
- * can be auto connection, or selective connection.
- *
- * Parameters add_remove: true to add; false to remove.
- * remote_bda: device address to add/remove.
- *
- * Returns void
- *
- ******************************************************************************/
-bool BTM_BleUpdateBgConnDev(bool add_remove, const RawAddress& remote_bda) {
- BTM_TRACE_EVENT("%s() add=%d", __func__, add_remove);
- return btm_update_dev_to_white_list(add_remove, remote_bda);
-}
-
/*******************************************************************************
*
* Function BTM_BleSetConnectableMode
@@ -822,8 +769,8 @@
if ((p_dev_rec = btm_find_or_alloc_dev(p_cb->direct_bda.bda)) != NULL &&
p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) {
btm_ble_enable_resolving_list(BTM_BLE_RL_ADV);
- p_peer_addr_ptr = p_dev_rec->ble.static_addr;
- *p_peer_addr_type = p_dev_rec->ble.static_addr_type;
+ p_peer_addr_ptr = p_dev_rec->ble.identity_addr;
+ *p_peer_addr_type = p_dev_rec->ble.identity_addr_type;
*p_own_addr_type = BLE_ADDR_RANDOM_ID;
return evt_type;
}
@@ -853,8 +800,8 @@
* peer */
tBTM_SEC_DEV_REC* p_dev_rec =
static_cast<tBTM_SEC_DEV_REC*>(list_node(n));
- p_peer_addr_ptr = p_dev_rec->ble.static_addr;
- *p_peer_addr_type = p_dev_rec->ble.static_addr_type;
+ p_peer_addr_ptr = p_dev_rec->ble.identity_addr;
+ *p_peer_addr_type = p_dev_rec->ble.identity_addr_type;
*p_own_addr_type = BLE_ADDR_RANDOM_ID;
} else {
@@ -875,64 +822,6 @@
return evt_type;
}
-/*******************************************************************************
- *
- * Function BTM_BleSetAdvParams
- *
- * Description This function is called to set advertising parameters.
- *
- * Parameters adv_int_min: minimum advertising interval
- * adv_int_max: maximum advertising interval
- * p_dir_bda: connectable direct initiator's LE device address
- * chnl_map: advertising channel map.
- *
- * Returns void
- *
- ******************************************************************************/
-tBTM_STATUS BTM_BleSetAdvParams(uint16_t adv_int_min, uint16_t adv_int_max,
- const RawAddress& p_dir_bda,
- tBTM_BLE_ADV_CHNL_MAP chnl_map) {
- tBTM_LE_RANDOM_CB* p_addr_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
- tBTM_BLE_INQ_CB* p_cb = &btm_cb.ble_ctr_cb.inq_var;
- tBTM_STATUS status = BTM_SUCCESS;
- RawAddress address = RawAddress::kEmpty;
- tBLE_ADDR_TYPE init_addr_type = BLE_ADDR_PUBLIC;
- tBLE_ADDR_TYPE own_addr_type = p_addr_cb->own_addr_type;
- uint8_t adv_mode = p_cb->adv_mode;
-
- BTM_TRACE_EVENT("BTM_BleSetAdvParams");
-
- if (!controller_get_interface()->supports_ble()) return BTM_ILLEGAL_VALUE;
-
- if (!BTM_BLE_ISVALID_PARAM(adv_int_min, BTM_BLE_ADV_INT_MIN,
- BTM_BLE_ADV_INT_MAX) ||
- !BTM_BLE_ISVALID_PARAM(adv_int_max, BTM_BLE_ADV_INT_MIN,
- BTM_BLE_ADV_INT_MAX)) {
- return BTM_ILLEGAL_VALUE;
- }
-
- p_cb->adv_interval_min = adv_int_min;
- p_cb->adv_interval_max = adv_int_max;
- p_cb->adv_chnl_map = chnl_map;
- p_cb->direct_bda.bda = p_dir_bda;
-
- BTM_TRACE_EVENT("update params for an active adv");
-
- btm_ble_stop_adv();
-
- p_cb->evt_type = btm_set_conn_mode_adv_init_addr(
- p_cb, address, &init_addr_type, &own_addr_type);
-
- /* update adv params */
- btsnd_hcic_ble_write_adv_params(
- p_cb->adv_interval_min, p_cb->adv_interval_max, p_cb->evt_type,
- own_addr_type, init_addr_type, address, p_cb->adv_chnl_map, p_cb->afp);
-
- if (adv_mode == BTM_BLE_ADV_ENABLE) btm_ble_start_adv();
-
- return status;
-}
-
/**
* This function is called to set scan parameters. |cb| is called with operation
* status
@@ -1416,7 +1305,7 @@
if (duration != 0) {
/* start inquiry timer */
- period_ms_t duration_ms = duration * 1000;
+ uint64_t duration_ms = duration * 1000;
alarm_set_on_mloop(p_ble_cb->inq_var.inquiry_timer, duration_ms,
btm_ble_inquiry_timer_timeout, NULL);
}
@@ -2591,8 +2480,7 @@
now in order */
if (btm_ble_get_conn_st() == BLE_CONN_IDLE &&
status != HCI_ERR_HOST_REJECT_RESOURCES &&
- status != HCI_ERR_MAX_NUM_OF_CONNECTIONS &&
- !btm_send_pending_direct_conn()) {
+ status != HCI_ERR_MAX_NUM_OF_CONNECTIONS) {
btm_ble_resume_bg_conn();
}
}
@@ -2619,7 +2507,6 @@
p_cb->observer_timer = alarm_new("btm_ble.observer_timer");
p_cb->cur_states = 0;
- p_cb->conn_pending_q = fixed_queue_new(SIZE_MAX);
p_cb->inq_var.adv_mode = BTM_BLE_ADV_DISABLE;
p_cb->inq_var.scan_type = BTM_BLE_SCAN_MODE_NONE;
diff --git a/stack/btm/btm_ble_int.h b/stack/btm/btm_ble_int.h
index d4cb411..fc1bfcf 100644
--- a/stack/btm/btm_ble_int.h
+++ b/stack/btm/btm_ble_int.h
@@ -68,7 +68,6 @@
extern void btm_read_ble_local_supported_states_complete(uint8_t* p,
uint16_t evt_len);
extern tBTM_BLE_CONN_ST btm_ble_get_conn_st(void);
-extern void btm_ble_set_conn_st(tBTM_BLE_CONN_ST new_st);
extern tBTM_STATUS btm_ble_start_adv(void);
extern tBTM_STATUS btm_ble_stop_adv(void);
extern void btm_le_on_advertising_set_terminated(uint8_t* p, uint16_t length);
@@ -80,7 +79,7 @@
tBTM_LE_AUTH_REQ auth_req,
tBTM_BLE_SEC_REQ_ACT* p_sec_req_act);
extern void btm_ble_ltk_request_reply(const RawAddress& bda, bool use_stk,
- BT_OCTET16 stk);
+ const Octet16& stk);
extern uint8_t btm_proc_smp_cback(tSMP_EVT event, const RawAddress& bd_addr,
tSMP_EVT_DATA* p_data);
extern tBTM_STATUS btm_ble_set_encryption(const RawAddress& bd_addr,
@@ -89,7 +88,7 @@
extern void btm_ble_ltk_request(uint16_t handle, uint8_t rand[8],
uint16_t ediv);
extern tBTM_STATUS btm_ble_start_encrypt(const RawAddress& bda, bool use_stk,
- BT_OCTET16 stk);
+ Octet16* p_stk);
extern void btm_ble_link_encrypted(const RawAddress& bd_addr,
uint8_t encr_enable);
@@ -116,31 +115,15 @@
extern uint8_t btm_ble_read_sec_key_size(const RawAddress& bd_addr);
/* white list function */
-extern bool btm_update_dev_to_white_list(bool to_add,
- const RawAddress& bd_addr);
extern void btm_update_scanner_filter_policy(tBTM_BLE_SFP scan_policy);
extern void btm_update_adv_filter_policy(tBTM_BLE_AFP adv_policy);
-extern void btm_ble_clear_white_list(void);
-extern void btm_read_white_list_size_complete(uint8_t* p, uint16_t evt_len);
-extern void btm_ble_add_2_white_list_complete(uint8_t status);
-extern void btm_ble_remove_from_white_list_complete(uint8_t* p,
- uint16_t evt_len);
-extern void btm_ble_clear_white_list_complete(uint8_t* p, uint16_t evt_len);
extern void btm_ble_white_list_init(uint8_t white_list_size);
/* background connection function */
extern bool btm_ble_suspend_bg_conn(void);
extern bool btm_ble_resume_bg_conn(void);
-extern void btm_send_hci_create_connection(
- uint16_t scan_int, uint16_t scan_win, uint8_t init_filter_policy,
- uint8_t addr_type_peer, const RawAddress& bda_peer, uint8_t addr_type_own,
- uint16_t conn_int_min, uint16_t conn_int_max, uint16_t conn_latency,
- uint16_t conn_timeout, uint16_t min_ce_len, uint16_t max_ce_len,
- uint8_t phy);
-extern bool btm_ble_start_auto_conn(bool start);
-extern bool btm_ble_start_select_conn(bool start);
-extern bool btm_ble_renew_bg_conn_params(bool add, const RawAddress& bd_addr);
-extern void btm_write_dir_conn_wl(const RawAddress& target_addr);
+extern bool btm_ble_start_auto_conn();
+extern bool btm_ble_stop_auto_conn();
extern void btm_ble_update_mode_operation(uint8_t link_role,
const RawAddress* bda,
uint8_t status);
@@ -148,18 +131,14 @@
extern void btm_ble_update_link_topology_mask(uint8_t role, bool increase);
extern void btm_ble_bgconn_cancel_if_disconnected(const RawAddress& bd_addr);
-/* direct connection utility */
-extern bool btm_send_pending_direct_conn(void);
-extern void btm_ble_enqueue_direct_conn_req(void* p_param);
-extern void btm_ble_dequeue_direct_conn_req(const RawAddress& rem_bda);
-
/* BLE address management */
-extern void btm_gen_resolvable_private_addr(base::Callback<void(BT_OCTET8)> cb);
+extern void btm_gen_resolvable_private_addr(
+ base::Callback<void(const RawAddress& rpa)> cb);
extern void btm_gen_non_resolvable_private_addr(tBTM_BLE_ADDR_CBACK* p_cback,
void* p);
extern tBTM_SEC_DEV_REC* btm_ble_resolve_random_addr(
const RawAddress& random_bda);
-extern void btm_gen_resolve_paddr_low(BT_OCTET8 rand);
+extern void btm_gen_resolve_paddr_low(const RawAddress& address);
/* privacy function */
#if (BLE_PRIVACY_SPT == TRUE)
@@ -168,7 +147,7 @@
uint8_t* p_addr_type,
bool refresh);
extern bool btm_random_pseudo_to_identity_addr(RawAddress* random_pseudo,
- uint8_t* p_static_addr_type);
+ uint8_t* p_identity_addr_type);
extern void btm_ble_refresh_peer_resolvable_private_addr(
const RawAddress& pseudo_bda, const RawAddress& rra, uint8_t rra_type);
extern void btm_ble_refresh_local_resolvable_private_addr(
diff --git a/stack/btm/btm_ble_int_types.h b/stack/btm/btm_ble_int_types.h
index 2167f2f..d2fa554 100644
--- a/stack/btm/btm_ble_int_types.h
+++ b/stack/btm/btm_ble_int_types.h
@@ -185,9 +185,8 @@
} tBTM_LE_BG_CONN_DEV;
/* white list using state as a bit mask */
-#define BTM_BLE_WL_IDLE 0
-#define BTM_BLE_WL_INIT 1
-typedef uint8_t tBTM_BLE_WL_STATE;
+constexpr uint8_t BTM_BLE_WL_IDLE = 0;
+constexpr uint8_t BTM_BLE_WL_INIT = 1;
/* resolving list using state as a bit mask */
#define BTM_BLE_RL_IDLE 0
@@ -198,8 +197,7 @@
/* BLE connection state */
#define BLE_CONN_IDLE 0
-#define BLE_DIR_CONN 1
-#define BLE_BG_CONN 2
+#define BLE_CONNECTING 2
#define BLE_CONN_CANCEL 3
typedef uint8_t tBTM_BLE_CONN_ST;
@@ -287,14 +285,12 @@
alarm_t* observer_timer;
/* background connection procedure cb value */
- tBTM_BLE_CONN_TYPE bg_conn_type;
- uint32_t scan_int;
- uint32_t scan_win;
+ uint16_t scan_int;
+ uint16_t scan_win;
/* white list information */
- tBTM_BLE_WL_STATE wl_state;
+ uint8_t wl_state;
- fixed_queue_t* conn_pending_q;
tBTM_BLE_CONN_ST conn_state;
/* random address management control block */
diff --git a/stack/btm/btm_ble_multi_adv.cc b/stack/btm/btm_ble_multi_adv.cc
index 60490fb..120b384 100644
--- a/stack/btm/btm_ble_multi_adv.cc
+++ b/stack/btm/btm_ble_multi_adv.cc
@@ -17,16 +17,6 @@
*
******************************************************************************/
-#include <base/bind.h>
-#include <base/location.h>
-#include <base/logging.h>
-#include <base/memory/weak_ptr.h>
-#include <base/strings/string_number_conversions.h>
-#include <base/time/time.h>
-#include <string.h>
-#include <queue>
-#include <vector>
-
#include "bt_target.h"
#include "device/include/controller.h"
#include "osi/include/alarm.h"
@@ -35,6 +25,18 @@
#include "ble_advertiser_hci_interface.h"
#include "btm_int_types.h"
+#include <string.h>
+#include <queue>
+#include <vector>
+
+#include <base/bind.h>
+#include <base/bind_helpers.h>
+#include <base/location.h>
+#include <base/logging.h>
+#include <base/memory/weak_ptr.h>
+#include <base/strings/string_number_conversions.h>
+#include <base/time/time.h>
+
using base::Bind;
using base::TimeDelta;
using base::TimeTicks;
@@ -44,7 +46,7 @@
uint8_t /* inst_id */, int8_t /* tx_power */, uint8_t /* status */)>;
using SetEnableData = BleAdvertiserHciInterface::SetEnableData;
extern void btm_gen_resolvable_private_addr(
- base::Callback<void(uint8_t[8])> cb);
+ base::Callback<void(const RawAddress& rpa)> cb);
constexpr int ADV_DATA_LEN_MAX = 251;
@@ -113,12 +115,9 @@
void btm_ble_adv_raddr_timer_timeout(void* data);
-void DoNothing(uint8_t) {}
-void DoNothing2(uint8_t, uint8_t) {}
-
struct closure_data {
base::Closure user_task;
- tracked_objects::Location posted_from;
+ base::Location posted_from;
};
static void alarm_closure_cb(void* p) {
@@ -129,9 +128,8 @@
}
// Periodic alarms are not supported, because we clean up data in callback
-void alarm_set_closure(const tracked_objects::Location& posted_from,
- alarm_t* alarm, period_ms_t interval_ms,
- base::Closure user_task) {
+void alarm_set_closure(const base::Location& posted_from, alarm_t* alarm,
+ uint64_t interval_ms, base::Closure user_task) {
closure_data* data = new closure_data;
data->posted_from = posted_from;
data->user_task = std::move(user_task);
@@ -172,7 +170,7 @@
weak_factory_.GetWeakPtr()));
}
- ~BleAdvertisingManagerImpl() { adv_inst.clear(); }
+ ~BleAdvertisingManagerImpl() override { adv_inst.clear(); }
void GetOwnAddress(uint8_t inst_id, GetAddressCallback cb) override {
cb.Run(adv_inst[inst_id].own_address_type, adv_inst[inst_id].own_address);
@@ -187,38 +185,8 @@
}
}
- void OnRpaGenerationComplete(base::Callback<void(RawAddress)> cb,
- uint8_t rand[8]) {
- VLOG(1) << __func__;
-
- RawAddress bda;
-
- rand[2] &= (~BLE_RESOLVE_ADDR_MASK);
- rand[2] |= BLE_RESOLVE_ADDR_MSB;
-
- bda.address[2] = rand[0];
- bda.address[1] = rand[1];
- bda.address[0] = rand[2];
-
- BT_OCTET16 irk;
- BTM_GetDeviceIDRoot(irk);
- tSMP_ENC output;
-
- if (!SMP_Encrypt(irk, BT_OCTET16_LEN, rand, 3, &output))
- LOG_ASSERT(false) << "SMP_Encrypt failed";
-
- /* set hash to be LSB of rpAddress */
- bda.address[5] = output.param_buf[0];
- bda.address[4] = output.param_buf[1];
- bda.address[3] = output.param_buf[2];
-
- cb.Run(bda);
- }
-
- void GenerateRpa(base::Callback<void(RawAddress)> cb) {
- btm_gen_resolvable_private_addr(
- Bind(&BleAdvertisingManagerImpl::OnRpaGenerationComplete,
- weak_factory_.GetWeakPtr(), std::move(cb)));
+ void GenerateRpa(base::Callback<void(const RawAddress&)> cb) {
+ btm_gen_resolvable_private_addr(std::move(cb));
}
void ConfigureRpa(AdvertisingInstance* p_inst, MultiAdvCb configuredCb) {
@@ -236,7 +204,7 @@
GenerateRpa(Bind(
[](AdvertisingInstance* p_inst, MultiAdvCb configuredCb,
- RawAddress bda) {
+ const RawAddress& bda) {
/* Connectable advertising set must be disabled when updating RPA */
bool restart = p_inst->IsEnabled() && p_inst->IsConnectable();
@@ -246,7 +214,7 @@
if (restart) {
p_inst->enable_status = false;
hci_interface->Enable(false, p_inst->inst_id, 0x00, 0x00,
- Bind(DoNothing));
+ base::DoNothing());
}
/* set it to controller */
@@ -263,7 +231,7 @@
if (restart) {
p_inst->enable_status = true;
hci_interface->Enable(true, p_inst->inst_id, 0x00, 0x00,
- Bind(DoNothing));
+ base::DoNothing());
}
},
p_inst, std::move(configuredCb)));
@@ -285,7 +253,7 @@
[](AdvertisingInstance* p_inst,
base::Callback<void(uint8_t /* inst_id */, uint8_t /* status */)>
cb,
- RawAddress bda) {
+ const RawAddress& bda) {
p_inst->own_address = bda;
alarm_set_on_mloop(p_inst->adv_raddr_timer,
@@ -630,7 +598,7 @@
base::Closure cb = Bind(
&BleAdvertisingManagerImpl::Enable, weak_factory_.GetWeakPtr(), inst_id,
- 0 /* disable */, std::move(timeout_cb), 0, 0, base::Bind(DoNothing));
+ 0 /* disable */, std::move(timeout_cb), 0, 0, base::DoNothing());
// schedule disable when the timeout passes
alarm_set_closure(FROM_HERE, p_inst->timeout_timer, duration * 10,
@@ -714,7 +682,7 @@
// TODO: disable only if was enabled, currently no use scenario needs
// that,
// we always set parameters before enabling
- // GetHciInterface()->Enable(false, inst_id, Bind(DoNothing));
+ // GetHciInterface()->Enable(false, inst_id, base::DoNothing());
p_inst->advertising_event_properties =
p_params->advertising_event_properties;
p_inst->tx_power = p_params->tx_power;
@@ -889,18 +857,18 @@
if (adv_inst[inst_id].IsEnabled()) {
p_inst->enable_status = false;
- GetHciInterface()->Enable(false, inst_id, 0x00, 0x00, Bind(DoNothing));
+ GetHciInterface()->Enable(false, inst_id, 0x00, 0x00, base::DoNothing());
}
if (p_inst->periodic_enabled) {
p_inst->periodic_enabled = false;
GetHciInterface()->SetPeriodicAdvertisingEnable(false, inst_id,
- Bind(DoNothing));
+ base::DoNothing());
}
alarm_cancel(p_inst->adv_raddr_timer);
p_inst->in_use = false;
- GetHciInterface()->RemoveAdvertisingSet(inst_id, Bind(DoNothing));
+ GetHciInterface()->RemoveAdvertisingSet(inst_id, base::DoNothing());
p_inst->address_update_required = false;
}
@@ -931,7 +899,7 @@
}
}
- void Suspend() {
+ void Suspend() override {
std::vector<SetEnableData> sets;
for (AdvertisingInstance& inst : adv_inst) {
@@ -943,7 +911,8 @@
sets.emplace_back(SetEnableData{.handle = inst.inst_id});
}
- if (!sets.empty()) GetHciInterface()->Enable(false, sets, Bind(DoNothing));
+ if (!sets.empty())
+ GetHciInterface()->Enable(false, sets, base::DoNothing());
}
void Resume() override {
@@ -958,7 +927,7 @@
}
}
- if (!sets.empty()) GetHciInterface()->Enable(true, sets, Bind(DoNothing));
+ if (!sets.empty()) GetHciInterface()->Enable(true, sets, base::DoNothing());
}
void OnAdvertisingSetTerminated(
@@ -999,7 +968,7 @@
RecomputeTimeout(p_inst, TimeTicks::Now());
if (p_inst->enable_status) {
GetHciInterface()->Enable(true, advertising_handle, p_inst->duration,
- p_inst->maxExtAdvEvents, Bind(DoNothing));
+ p_inst->maxExtAdvEvents, base::DoNothing());
}
} else {
@@ -1040,7 +1009,7 @@
void btm_ble_adv_raddr_timer_timeout(void* data) {
BleAdvertisingManagerImpl* ptr = instance_weakptr.get();
- if (ptr) ptr->ConfigureRpa((AdvertisingInstance*)data, base::Bind(DoNothing));
+ if (ptr) ptr->ConfigureRpa((AdvertisingInstance*)data, base::DoNothing());
}
} // namespace
@@ -1073,7 +1042,7 @@
if (BleAdvertiserHciInterface::Get()->QuirkAdvertiserZeroHandle()) {
// If handle 0 can't be used, register advertiser for it, but never use it.
- BleAdvertisingManager::Get().get()->RegisterAdvertiser(Bind(DoNothing2));
+ BleAdvertisingManager::Get().get()->RegisterAdvertiser(base::DoNothing());
}
}
diff --git a/stack/btm/btm_ble_privacy.cc b/stack/btm/btm_ble_privacy.cc
index 3845ba6..4f1d386 100644
--- a/stack/btm/btm_ble_privacy.cc
+++ b/stack/btm/btm_ble_privacy.cc
@@ -415,15 +415,15 @@
return BTM_WRONG_MODE;
if (controller_get_interface()->supports_ble_privacy()) {
- btsnd_hcic_ble_rm_device_resolving_list(p_dev_rec->ble.static_addr_type,
- p_dev_rec->ble.static_addr);
+ btsnd_hcic_ble_rm_device_resolving_list(p_dev_rec->ble.identity_addr_type,
+ p_dev_rec->ble.identity_addr);
} else {
uint8_t param[20] = {0};
uint8_t* p = param;
UINT8_TO_STREAM(p, BTM_BLE_META_REMOVE_IRK_ENTRY);
- UINT8_TO_STREAM(p, p_dev_rec->ble.static_addr_type);
- BDADDR_TO_STREAM(p, p_dev_rec->ble.static_addr);
+ UINT8_TO_STREAM(p, p_dev_rec->ble.identity_addr_type);
+ BDADDR_TO_STREAM(p, p_dev_rec->ble.identity_addr);
BTM_VendorSpecificCommand(HCI_VENDOR_BLE_RPA_VSC,
BTM_BLE_META_REMOVE_IRK_LEN, param,
@@ -474,8 +474,8 @@
return BTM_WRONG_MODE;
if (controller_get_interface()->supports_ble_privacy()) {
- btsnd_hcic_ble_read_resolvable_addr_peer(p_dev_rec->ble.static_addr_type,
- p_dev_rec->ble.static_addr);
+ btsnd_hcic_ble_read_resolvable_addr_peer(p_dev_rec->ble.identity_addr_type,
+ p_dev_rec->ble.identity_addr);
} else {
uint8_t param[20] = {0};
uint8_t* p = param;
@@ -514,12 +514,6 @@
/* if already suspended */
if (p_ble_cb->suspended_rl_state != BTM_BLE_RL_IDLE) return true;
- /* direct connection active, wait until it completed */
- if (btm_ble_get_conn_st() == BLE_DIR_CONN) {
- BTM_TRACE_ERROR("resolving list can not be edited, EnQ now");
- return false;
- }
-
p_ble_cb->suspended_rl_state = BTM_BLE_RL_IDLE;
if (p_ble_cb->inq_var.adv_mode == BTM_BLE_ADV_ENABLE) {
@@ -728,35 +722,35 @@
btm_ble_update_resolving_list(p_dev_rec->bd_addr, true);
if (controller_get_interface()->supports_ble_privacy()) {
- uint8_t* peer_irk = p_dev_rec->ble.keys.irk;
- uint8_t* local_irk = btm_cb.devcb.id_keys.irk;
+ const Octet16& peer_irk = p_dev_rec->ble.keys.irk;
+ const Octet16& local_irk = btm_cb.devcb.id_keys.irk;
- if (p_dev_rec->ble.static_addr.IsEmpty()) {
- p_dev_rec->ble.static_addr = p_dev_rec->bd_addr;
- p_dev_rec->ble.static_addr_type = p_dev_rec->ble.ble_addr_type;
+ if (p_dev_rec->ble.identity_addr.IsEmpty()) {
+ p_dev_rec->ble.identity_addr = p_dev_rec->bd_addr;
+ p_dev_rec->ble.identity_addr_type = p_dev_rec->ble.ble_addr_type;
}
BTM_TRACE_DEBUG("%s: adding device %s to controller resolving list",
- __func__, p_dev_rec->ble.static_addr.ToString().c_str());
+ __func__, p_dev_rec->ble.identity_addr.ToString().c_str());
// use identical IRK for now
- btsnd_hcic_ble_add_device_resolving_list(p_dev_rec->ble.static_addr_type,
- p_dev_rec->ble.static_addr,
+ btsnd_hcic_ble_add_device_resolving_list(p_dev_rec->ble.identity_addr_type,
+ p_dev_rec->ble.identity_addr,
peer_irk, local_irk);
if (controller_get_interface()->supports_ble_set_privacy_mode()) {
BTM_TRACE_DEBUG("%s: adding device privacy mode", __func__);
- btsnd_hcic_ble_set_privacy_mode(p_dev_rec->ble.static_addr_type,
- p_dev_rec->ble.static_addr, 0x01);
+ btsnd_hcic_ble_set_privacy_mode(p_dev_rec->ble.identity_addr_type,
+ p_dev_rec->ble.identity_addr, 0x01);
}
} else {
uint8_t param[40] = {0};
uint8_t* p = param;
UINT8_TO_STREAM(p, BTM_BLE_META_ADD_IRK_ENTRY);
- ARRAY_TO_STREAM(p, p_dev_rec->ble.keys.irk, BT_OCTET16_LEN);
- UINT8_TO_STREAM(p, p_dev_rec->ble.static_addr_type);
- BDADDR_TO_STREAM(p, p_dev_rec->ble.static_addr);
+ ARRAY_TO_STREAM(p, p_dev_rec->ble.keys.irk, OCTET16_LEN);
+ UINT8_TO_STREAM(p, p_dev_rec->ble.identity_addr_type);
+ BDADDR_TO_STREAM(p, p_dev_rec->ble.identity_addr);
BTM_VendorSpecificCommand(HCI_VENDOR_BLE_RPA_VSC, BTM_BLE_META_ADD_IRK_LEN,
param, btm_ble_resolving_list_vsc_op_cmpl);
diff --git a/stack/btm/btm_dev.cc b/stack/btm/btm_dev.cc
index 5368fad..d5e2850 100644
--- a/stack/btm/btm_dev.cc
+++ b/stack/btm/btm_dev.cc
@@ -60,7 +60,7 @@
******************************************************************************/
bool BTM_SecAddDevice(const RawAddress& bd_addr, DEV_CLASS dev_class,
BD_NAME bd_name, uint8_t* features,
- uint32_t trusted_mask[], LINK_KEY link_key,
+ uint32_t trusted_mask[], LinkKey* p_link_key,
uint8_t key_type, tBTM_IO_CAP io_cap,
uint8_t pin_length) {
BTM_TRACE_API("%s: link key type:%x", __func__, key_type);
@@ -120,10 +120,10 @@
BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask);
- if (link_key) {
+ if (p_link_key) {
VLOG(2) << __func__ << ": BDA: " << bd_addr;
p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_KNOWN;
- memcpy(p_dev_rec->link_key, link_key, LINK_KEY_LEN);
+ p_dev_rec->link_key = *p_link_key;
p_dev_rec->link_key_type = key_type;
p_dev_rec->pin_code_length = pin_length;
@@ -149,6 +149,12 @@
return true;
}
+void wipe_secrets_and_remove(tBTM_SEC_DEV_REC* p_dev_rec) {
+ p_dev_rec->link_key.fill(0);
+ memset(&p_dev_rec->ble.keys, 0, sizeof(tBTM_SEC_BLE_KEYS));
+ list_remove(btm_cb.sec_dev_rec, p_dev_rec);
+}
+
/** Free resources associated with the device associated with |bd_addr| address.
*
* *** WARNING ***
@@ -170,7 +176,10 @@
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
if (p_dev_rec != NULL) {
RawAddress bda = p_dev_rec->bd_addr;
- btm_sec_free_dev(p_dev_rec);
+
+ /* Clear out any saved BLE keys */
+ btm_sec_clear_ble_keys(p_dev_rec);
+ wipe_secrets_and_remove(p_dev_rec);
/* Tell controller to get rid of the link key, if it has one stored */
BTM_DeleteStoredLinkKey(&bda, NULL);
}
@@ -257,19 +266,6 @@
/*******************************************************************************
*
- * Function btm_sec_free_dev
- *
- * Description Mark device record as not used
- *
- ******************************************************************************/
-void btm_sec_free_dev(tBTM_SEC_DEV_REC* p_dev_rec) {
- /* Clear out any saved BLE keys */
- btm_sec_clear_ble_keys(p_dev_rec);
- list_remove(btm_cb.sec_dev_rec, p_dev_rec);
-}
-
-/*******************************************************************************
- *
* Function btm_dev_support_switch
*
* Description This function is called by the L2CAP to check if remote
@@ -285,10 +281,8 @@
uint8_t xx;
bool feature_empty = true;
-#if (BTM_SCO_INCLUDED == TRUE)
/* Role switch is not allowed if a SCO is up */
if (btm_is_sco_active_by_bdaddr(bd_addr)) return (false);
-#endif
p_dev_rec = btm_find_dev(bd_addr);
if (p_dev_rec &&
controller_get_interface()->supports_master_slave_role_switch()) {
@@ -413,7 +407,7 @@
p_target_rec->bond_type = temp_rec.bond_type;
/* remove the combined record */
- list_remove(btm_cb.sec_dev_rec, p_dev_rec);
+ wipe_secrets_and_remove(p_dev_rec);
// p_dev_rec gets freed in list_remove, we should not access it further
continue;
}
@@ -425,7 +419,7 @@
p_target_rec->device_type |= p_dev_rec->device_type;
/* remove the combined record */
- list_remove(btm_cb.sec_dev_rec, p_dev_rec);
+ wipe_secrets_and_remove(p_dev_rec);
}
}
}
@@ -514,7 +508,7 @@
if (list_length(btm_cb.sec_dev_rec) > BTM_SEC_MAX_DEVICE_RECORDS) {
p_dev_rec = btm_find_oldest_dev_rec();
- list_remove(btm_cb.sec_dev_rec, p_dev_rec);
+ wipe_secrets_and_remove(p_dev_rec);
}
p_dev_rec =
diff --git a/stack/btm/btm_devctl.cc b/stack/btm/btm_devctl.cc
index 2e425aa..bc3fb56 100644
--- a/stack/btm/btm_devctl.cc
+++ b/stack/btm/btm_devctl.cc
@@ -34,16 +34,17 @@
#include "btcore/include/module.h"
#include "btm_int.h"
#include "btu.h"
+#include "common/message_loop_thread.h"
#include "device/include/controller.h"
#include "hci_layer.h"
#include "hcimsgs.h"
#include "l2c_int.h"
#include "osi/include/osi.h"
-#include "osi/include/thread.h"
+#include "stack/gatt/connection_manager.h"
#include "gatt_int.h"
-extern thread_t* bt_workqueue_thread;
+extern bluetooth::common::MessageLoopThread bt_startup_thread;
/******************************************************************************/
/* L O C A L D A T A D E F I N I T I O N S */
@@ -66,6 +67,7 @@
static void btm_decode_ext_features_page(uint8_t page_number,
const BD_FEATURES p_features);
+static void BTM_BT_Quality_Report_VSE_CBack(uint8_t length, uint8_t* p_stream);
/*******************************************************************************
*
@@ -76,7 +78,7 @@
* Returns void
*
******************************************************************************/
-void btm_dev_init(void) {
+void btm_dev_init() {
/* Initialize nonzero defaults */
memset(btm_cb.cfg.bd_name, 0, sizeof(tBTM_LOC_BD_NAME));
@@ -188,8 +190,7 @@
btm_cb.btm_inq_vars.page_scan_type = HCI_DEF_SCAN_TYPE;
btm_cb.ble_ctr_cb.conn_state = BLE_CONN_IDLE;
- btm_cb.ble_ctr_cb.bg_conn_type = BTM_BLE_CONN_NONE;
- gatt_reset_bgdev_list();
+ connection_manager::reset(true);
btm_pm_reset();
@@ -231,7 +232,7 @@
btm_db_reset();
module_start_up_callbacked_wrapper(get_module(CONTROLLER_MODULE),
- bt_workqueue_thread, reset_complete);
+ &bt_startup_thread, reset_complete);
}
/*******************************************************************************
@@ -320,9 +321,7 @@
/* Create (e)SCO supported packet types mask */
btm_cb.btm_sco_pkt_types_supported = 0;
-#if (BTM_SCO_INCLUDED == TRUE)
btm_cb.sco_cb.esco_supported = false;
-#endif
if (HCI_SCO_LINK_SUPPORTED(p_features)) {
btm_cb.btm_sco_pkt_types_supported = ESCO_PKT_TYPES_MASK_HV1;
@@ -867,3 +866,74 @@
/* Call the call back to pass the device status to application */
if (p_cb) (*p_cb)(status);
}
+
+/*******************************************************************************
+ *
+ * Function BTM_BT_Quality_Report_VSE_CBack
+ *
+ * Description Callback invoked on receiving of Vendor Specific Events.
+ * This function will call registered BQR report receiver if
+ * Bluetooth Quality Report sub-event is identified.
+ *
+ * Parameters: length - Lengths of all of the parameters contained in the
+ * Vendor Specific Event.
+ * p_stream - A pointer to the quality report which is sent
+ * from the Bluetooth controller via Vendor Specific Event.
+ *
+ ******************************************************************************/
+static void BTM_BT_Quality_Report_VSE_CBack(uint8_t length, uint8_t* p_stream) {
+ if (length == 0) {
+ LOG(WARNING) << __func__ << ": Lengths of all of the parameters are zero.";
+ return;
+ }
+
+ uint8_t sub_event = 0;
+ STREAM_TO_UINT8(sub_event, p_stream);
+ length--;
+
+ if (sub_event == HCI_VSE_SUBCODE_BQR_SUB_EVT) {
+ LOG(INFO) << __func__
+ << ": BQR sub event, report length: " << std::to_string(length);
+
+ if (btm_cb.p_bqr_report_receiver == nullptr) {
+ LOG(WARNING) << __func__ << ": No registered report receiver.";
+ return;
+ }
+
+ btm_cb.p_bqr_report_receiver(length, p_stream);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BT_Quality_Report_VSE_Register
+ *
+ * Description Register/Deregister for Bluetooth Quality Report VSE sub
+ * event Callback.
+ *
+ * Parameters: is_register - True/False to register/unregister for VSE.
+ * p_bqr_report_receiver - The receiver for receiving Bluetooth
+ * Quality Report VSE sub event.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_BT_Quality_Report_VSE_Register(
+ bool is_register, tBTM_BT_QUALITY_REPORT_RECEIVER* p_bqr_report_receiver) {
+ tBTM_STATUS retval =
+ BTM_RegisterForVSEvents(BTM_BT_Quality_Report_VSE_CBack, is_register);
+
+ if (retval != BTM_SUCCESS) {
+ LOG(WARNING) << __func__ << ": Fail to (un)register VSEvents: " << retval
+ << ", is_register: " << logbool(is_register);
+ return retval;
+ }
+
+ if (is_register) {
+ btm_cb.p_bqr_report_receiver = p_bqr_report_receiver;
+ } else {
+ btm_cb.p_bqr_report_receiver = nullptr;
+ }
+
+ LOG(INFO) << __func__ << ": Success to (un)register VSEvents."
+ << " is_register: " << logbool(is_register);
+ return retval;
+}
diff --git a/stack/btm/btm_inq.cc b/stack/btm/btm_inq.cc
index bdcce38..1a5d7f5 100644
--- a/stack/btm/btm_inq.cc
+++ b/stack/btm/btm_inq.cc
@@ -30,9 +30,9 @@
#include <stdlib.h>
#include <string.h>
+#include "common/time_util.h"
#include "device/include/controller.h"
#include "osi/include/osi.h"
-#include "osi/include/time.h"
#include "advertise_data_parser.h"
#include "bt_common.h"
@@ -1324,7 +1324,7 @@
uint16_t xx;
tINQ_DB_ENT* p_ent = btm_cb.btm_inq_vars.inq_db;
tINQ_DB_ENT* p_old = btm_cb.btm_inq_vars.inq_db;
- uint32_t ot = 0xFFFFFFFF;
+ uint64_t ot = UINT64_MAX;
for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++) {
if (!p_ent->in_use) {
@@ -1738,7 +1738,7 @@
p_cur->dev_class[2] = dc[2];
p_cur->clock_offset = clock_offset | BTM_CLOCK_OFFSET_VALID;
- p_i->time_of_resp = time_get_os_boottime_ms();
+ p_i->time_of_resp = bluetooth::common::time_get_os_boottime_ms();
if (p_i->inq_count != p_inq->inq_counter)
p_inq->inq_cmpl_info.num_resp++; /* A new response was found */
@@ -1951,7 +1951,7 @@
*
******************************************************************************/
tBTM_STATUS btm_initiate_rem_name(const RawAddress& remote_bda, uint8_t origin,
- period_ms_t timeout_ms, tBTM_CMPL_CB* p_cb) {
+ uint64_t timeout_ms, tBTM_CMPL_CB* p_cb) {
tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
/*** Make sure the device is ready ***/
diff --git a/stack/btm/btm_int.h b/stack/btm/btm_int.h
index 21f7ce3..6b80717 100644
--- a/stack/btm/btm_int.h
+++ b/stack/btm/btm_int.h
@@ -39,6 +39,7 @@
#include "btm_ble_int.h"
#include "btm_int_types.h"
+#include "l2cdefs.h"
#include "smp_api.h"
extern tBTM_CB btm_cb;
@@ -53,7 +54,7 @@
******************************************
*/
extern tBTM_STATUS btm_initiate_rem_name(const RawAddress& remote_bda,
- uint8_t origin, period_ms_t timeout_ms,
+ uint8_t origin, uint64_t timeout_ms,
tBTM_CMPL_CB* p_cb);
extern void btm_process_remote_name(const RawAddress* bda, BD_NAME name,
@@ -142,12 +143,7 @@
extern void btm_pm_proc_ssr_evt(uint8_t* p, uint16_t evt_len);
extern tBTM_STATUS btm_read_power_mode_state(const RawAddress& remote_bda,
tBTM_PM_STATE* pmState);
-#if (BTM_SCO_INCLUDED == TRUE)
extern void btm_sco_chk_pend_unpark(uint8_t hci_status, uint16_t hci_handle);
-#else
-#define btm_sco_chk_pend_unpark(hci_status, hci_handle)
-#endif /* BTM_SCO_INCLUDED */
-
extern void btm_qos_setup_timeout(void* data);
extern void btm_qos_setup_complete(uint8_t status, uint16_t handle,
FLOW_SPEC* p_flow);
@@ -181,10 +177,6 @@
extern void btm_read_local_name_timeout(void* data);
extern void btm_read_local_name_complete(uint8_t* p, uint16_t evt_len);
-extern void btm_ble_add_2_white_list_complete(uint8_t status);
-extern void btm_ble_remove_from_white_list_complete(uint8_t* p,
- uint16_t evt_len);
-extern void btm_ble_clear_white_list_complete(uint8_t* p, uint16_t evt_len);
extern void btm_ble_create_conn_cancel_complete(uint8_t* p);
extern bool btm_ble_addr_resolvable(const RawAddress& rpa,
tBTM_SEC_DEV_REC* p_dev_rec);
@@ -200,6 +192,8 @@
extern void btm_vendor_specific_evt(uint8_t* p, uint8_t evt_len);
extern void btm_delete_stored_link_key_complete(uint8_t* p);
extern void btm_report_device_status(tBTM_DEV_STATUS status);
+extern tBTM_STATUS BTM_BT_Quality_Report_VSE_Register(
+ bool is_register, tBTM_BT_QUALITY_REPORT_RECEIVER* p_bqr_report_receiver);
/* Internal functions provided by btm_dev.cc
*********************************************
@@ -208,7 +202,7 @@
extern tBTM_SEC_DEV_REC* btm_sec_allocate_dev_rec(void);
extern tBTM_SEC_DEV_REC* btm_sec_alloc_dev(const RawAddress& bd_addr);
-extern void btm_sec_free_dev(tBTM_SEC_DEV_REC* p_dev_rec);
+extern void wipe_secrets_and_remove(tBTM_SEC_DEV_REC* p_dev_rec);
extern tBTM_SEC_DEV_REC* btm_find_dev(const RawAddress& bd_addr);
extern tBTM_SEC_DEV_REC* btm_find_or_alloc_dev(const RawAddress& bd_addr);
extern tBTM_SEC_DEV_REC* btm_find_dev_by_handle(uint16_t handle);
@@ -256,7 +250,7 @@
extern void btm_keypress_notif_evt(uint8_t* p);
extern void btm_simple_pair_complete(uint8_t* p);
extern void btm_sec_link_key_notification(const RawAddress& p_bda,
- uint8_t* p_link_key,
+ const Octet16& link_key,
uint8_t key_type);
extern void btm_sec_link_key_request(const RawAddress& p_bda);
extern void btm_sec_pin_code_request(const RawAddress& p_bda);
@@ -274,10 +268,9 @@
const RawAddress& new_pseudo_addr);
extern tBTM_SEC_SERV_REC* btm_sec_find_first_serv(CONNECTION_TYPE conn_type,
uint16_t psm);
-extern bool btm_ble_start_sec_check(const RawAddress& bd_addr, uint16_t psm,
- bool is_originator,
- tBTM_SEC_CALLBACK* p_callback,
- void* p_ref_data);
+extern tL2CAP_LE_RESULT_CODE btm_ble_start_sec_check(
+ const RawAddress& bd_addr, uint16_t psm, bool is_originator,
+ tBTM_SEC_CALLBACK* p_callback, void* p_ref_data);
extern tINQ_DB_ENT* btm_inq_db_new(const RawAddress& p_bda);
diff --git a/stack/btm/btm_int_types.h b/stack/btm/btm_int_types.h
index 8f91cef..a0460b1 100644
--- a/stack/btm/btm_int_types.h
+++ b/stack/btm/btm_int_types.h
@@ -18,6 +18,7 @@
#ifndef BTM_INT_TYPES_H
#define BTM_INT_TYPES_H
+#include "btif/include/btif_bqr.h"
#include "btm_api_types.h"
#include "btm_ble_api_types.h"
#include "btm_ble_int_types.h"
@@ -170,7 +171,7 @@
uint8_t le_supported_states[BTM_LE_SUPPORT_STATE_SIZE];
tBTM_BLE_LOCAL_ID_KEYS id_keys; /* local BLE ID keys */
- BT_OCTET16 ble_encryption_key_value; /* BLE encryption key */
+ Octet16 ble_encryption_key_value; /* BLE encryption key */
#if (BTM_BLE_CONFORMANCE_TESTING == TRUE)
bool no_disc_if_pair_fail;
@@ -210,7 +211,7 @@
} tINQ_BDADDR;
typedef struct {
- uint32_t time_of_resp;
+ uint64_t time_of_resp;
uint32_t
inq_count; /* "timestamps" the entry with a particular inquiry count */
/* Used for determining if a response has already been */
@@ -369,7 +370,6 @@
esco_data_path_t sco_route; /* HCI, PCM, or TEST */
} tSCO_CB;
-#if (BTM_SCO_INCLUDED == TRUE)
extern void btm_set_sco_ind_cback(tBTM_SCO_IND_CBACK* sco_ind_cb);
extern void btm_accept_sco_link(uint16_t sco_inx, enh_esco_params_t* p_setup,
tBTM_SCO_CB* p_conn_cb, tBTM_SCO_CB* p_disc_cb);
@@ -377,13 +377,6 @@
extern void btm_sco_chk_pend_rolechange(uint16_t hci_handle);
extern void btm_sco_disc_chk_pend_for_modechange(uint16_t hci_handle);
-#else
-#define btm_accept_sco_link(sco_inx, p_setup, p_conn_cb, p_disc_cb)
-#define btm_reject_sco_link(sco_inx)
-#define btm_set_sco_ind_cback(sco_ind_cb)
-#define btm_sco_chk_pend_rolechange(hci_handle)
-#endif /* BTM_SCO_INCLUDED */
-
/*
* Define structure for Security Service Record.
* A record exists for each service registered with the Security Manager
@@ -415,12 +408,12 @@
/* LE Security information of device in Slave Role */
typedef struct {
- BT_OCTET16 irk; /* peer diverified identity root */
- BT_OCTET16 pltk; /* peer long term key */
- BT_OCTET16 pcsrk; /* peer SRK peer device used to secured sign local data */
+ Octet16 irk; /* peer diverified identity root */
+ Octet16 pltk; /* peer long term key */
+ Octet16 pcsrk; /* peer SRK peer device used to secured sign local data */
- BT_OCTET16 lltk; /* local long term key */
- BT_OCTET16 lcsrk; /* local SRK peer device used to secured sign local data */
+ Octet16 lltk; /* local long term key */
+ Octet16 lcsrk; /* local SRK peer device used to secured sign local data */
BT_OCTET8 rand; /* random vector for LTK generation */
uint16_t ediv; /* LTK diversifier of this slave device */
@@ -440,8 +433,8 @@
RawAddress pseudo_addr; /* LE pseudo address of the device if different from
device address */
tBLE_ADDR_TYPE ble_addr_type; /* LE device type: public or random address */
- tBLE_ADDR_TYPE static_addr_type; /* static address type */
- RawAddress static_addr; /* static address */
+ tBLE_ADDR_TYPE identity_addr_type; /* identity address type */
+ RawAddress identity_addr; /* identity address */
#define BTM_WHITE_LIST_BIT 0x01
#define BTM_RESOLVING_LIST_BIT 0x02
@@ -479,7 +472,7 @@
uint16_t clock_offset; /* Latest known clock offset */
RawAddress bd_addr; /* BD_ADDR of the device */
DEV_CLASS dev_class; /* DEV_CLASS of the device */
- LINK_KEY link_key; /* Device link key */
+ LinkKey link_key; /* Device link key */
uint8_t pin_code_length; /* Length of the pin_code used for paring */
#define BTM_SEC_AUTHORIZED BTM_SEC_FLAG_AUTHORIZED /* 0x01 */
@@ -732,6 +725,9 @@
#define CONN_ORIENT_ORIG true
typedef bool CONNECTION_TYPE;
+// Bluetooth Quality Report - Report receiver
+typedef void(tBTM_BT_QUALITY_REPORT_RECEIVER)(uint8_t len, uint8_t* p_stream);
+
/* Define a structure to hold all the BTM data
*/
@@ -784,12 +780,10 @@
*****************************************************/
tBTM_INQUIRY_VAR_ST btm_inq_vars;
-/*****************************************************
-** SCO Management
-*****************************************************/
-#if (BTM_SCO_INCLUDED == TRUE)
+ /*****************************************************
+ ** SCO Management
+ *****************************************************/
tSCO_CB sco_cb;
-#endif
/*****************************************************
** Security Management
@@ -801,8 +795,7 @@
tBTM_SEC_DEV_REC* p_collided_dev_rec;
alarm_t* sec_collision_timer;
- uint32_t collision_start_time;
- uint32_t max_collision_delay;
+ uint64_t collision_start_time;
uint32_t dev_rec_count; /* Counter used for device record timestamp */
uint8_t security_mode;
bool pairing_disabled;
@@ -839,6 +832,8 @@
tBTM_SEC_QUEUE_ENTRY format */
char state_temp_buffer[BTM_STATE_BUFFER_SIZE];
+ // BQR Receiver
+ tBTM_BT_QUALITY_REPORT_RECEIVER* p_bqr_report_receiver;
} tBTM_CB;
/* security action for L2CAP COC channels */
diff --git a/stack/btm/btm_main.cc b/stack/btm/btm_main.cc
index 011feb7..f58f444 100644
--- a/stack/btm/btm_main.cc
+++ b/stack/btm/btm_main.cc
@@ -66,9 +66,7 @@
btm_sec_init(BTM_SEC_MODE_SC);
else
btm_sec_init(BTM_SEC_MODE_SP);
-#if (BTM_SCO_INCLUDED == TRUE)
btm_sco_init(); /* SCO Database and Structures (If included) */
-#endif
btm_cb.sec_dev_rec = list_new(osi_free);
@@ -83,6 +81,16 @@
fixed_queue_free(btm_cb.sec_pending_q, NULL);
btm_cb.sec_pending_q = NULL;
+ list_node_t* end = list_end(btm_cb.sec_dev_rec);
+ list_node_t* node = list_begin(btm_cb.sec_dev_rec);
+ while (node != end) {
+ tBTM_SEC_DEV_REC* p_dev_rec = static_cast<tBTM_SEC_DEV_REC*>(list_node(node));
+
+ // we do list_remove in, must grab next before removing
+ node = list_next(node);
+ wipe_secrets_and_remove(p_dev_rec);
+ }
+
list_free(btm_cb.sec_dev_rec);
btm_cb.sec_dev_rec = NULL;
diff --git a/stack/btm/btm_pm.cc b/stack/btm/btm_pm.cc
index af06c1b..793c854 100644
--- a/stack/btm/btm_pm.cc
+++ b/stack/btm/btm_pm.cc
@@ -813,10 +813,8 @@
(*btm_cb.pm_reg_db[yy].cback)(p->remote_addr, mode, interval, hci_status);
}
}
-#if (BTM_SCO_INCLUDED == TRUE)
/*check if sco disconnect is waiting for the mode change */
btm_sco_disc_chk_pend_for_modechange(hci_handle);
-#endif
/* If mode change was because of an active role switch or change link key */
btm_cont_rswitch(p, btm_find_dev(p->remote_addr), hci_status);
diff --git a/stack/btm/btm_sco.cc b/stack/btm/btm_sco.cc
index 6e7f97c..d8d2def 100644
--- a/stack/btm/btm_sco.cc
+++ b/stack/btm/btm_sco.cc
@@ -40,8 +40,6 @@
#include "hcimsgs.h"
#include "osi/include/osi.h"
-#if (BTM_SCO_INCLUDED == TRUE)
-
/******************************************************************************/
/* L O C A L D A T A D E F I N I T I O N S */
/******************************************************************************/
@@ -485,8 +483,7 @@
if (p->state == SCO_ST_UNUSED) {
if (remote_bda) {
if (is_orig) {
-/* can not create SCO link if in park mode */
-#if (BTM_SCO_WAKE_PARKED_LINK == TRUE)
+ // can not create SCO link if in park mode
tBTM_PM_STATE state;
if ((btm_read_power_mode_state(*remote_bda, &state) == BTM_SUCCESS)) {
if (state == BTM_PM_ST_SNIFF || state == BTM_PM_ST_PARK ||
@@ -503,12 +500,6 @@
LOG(ERROR) << __func__ << ": failed to read power mode for "
<< *remote_bda;
}
-#else // BTM_SCO_WAKE_PARKED_LINK
- uint8_t mode;
- if ((BTM_ReadPowerMode(*remote_bda, &mode) == BTM_SUCCESS) &&
- (mode == BTM_PM_MD_PARK))
- return (BTM_WRONG_MODE);
-#endif // BTM_SCO_WAKE_PARKED_LINK
}
p->esco.data.bd_addr = *remote_bda;
p->rem_bd_known = true;
@@ -580,7 +571,6 @@
return BTM_NO_RESOURCES;
}
-#if (BTM_SCO_WAKE_PARKED_LINK == TRUE)
/*******************************************************************************
*
* Function btm_sco_chk_pend_unpark
@@ -614,7 +604,6 @@
}
#endif // BTM_MAX_SCO_LINKS
}
-#endif // BTM_SCO_WAKE_PARKED_LINK
/*******************************************************************************
*
@@ -1691,43 +1680,3 @@
return (voice_settings);
}
-
-#else /* SCO_EXCLUDED == TRUE (Link in stubs) */
-
-tBTM_STATUS BTM_CreateSco(const RawAddress* remote_bda, bool is_orig,
- uint16_t pkt_types, uint16_t* p_sco_inx,
- tBTM_SCO_CB* p_conn_cb, tBTM_SCO_CB* p_disc_cb) {
- return (BTM_NO_RESOURCES);
-}
-tBTM_STATUS BTM_RemoveSco(uint16_t sco_inx) { return (BTM_NO_RESOURCES); }
-tBTM_STATUS BTM_SetScoPacketTypes(uint16_t sco_inx, uint16_t pkt_types) {
- return (BTM_NO_RESOURCES);
-}
-uint16_t BTM_ReadScoPacketTypes(uint16_t sco_inx) { return (0); }
-uint16_t BTM_ReadDeviceScoPacketTypes(void) { return (0); }
-uint16_t BTM_ReadScoHandle(uint16_t sco_inx) {
- return (BTM_INVALID_HCI_HANDLE);
-}
-const RawAddress* BTM_ReadScoBdAddr(uint16_t sco_inx) {
- return ((uint8_t*)NULL);
-}
-uint16_t BTM_ReadScoDiscReason(void) { return (BTM_INVALID_SCO_DISC_REASON); }
-tBTM_STATUS BTM_SetEScoMode(enh_esco_params_t* p_parms) {
- return (BTM_MODE_UNSUPPORTED);
-}
-tBTM_STATUS BTM_RegForEScoEvts(uint16_t sco_inx,
- tBTM_ESCO_CBACK* p_esco_cback) {
- return (BTM_ILLEGAL_VALUE);
-}
-tBTM_STATUS BTM_ReadEScoLinkParms(uint16_t sco_inx, tBTM_ESCO_DATA* p_parms) {
- return (BTM_MODE_UNSUPPORTED);
-}
-tBTM_STATUS BTM_ChangeEScoLinkParms(uint16_t sco_inx,
- tBTM_CHG_ESCO_PARAMS* p_parms) {
- return (BTM_MODE_UNSUPPORTED);
-}
-void BTM_EScoConnRsp(uint16_t sco_inx, uint8_t hci_status,
- enh_esco_params_t* p_parms) {}
-uint8_t BTM_GetNumScoLinks(void) { return (0); }
-
-#endif /* If SCO is being used */
diff --git a/stack/btm/btm_sec.cc b/stack/btm/btm_sec.cc
index 19280ad..4db757e 100644
--- a/stack/btm/btm_sec.cc
+++ b/stack/btm/btm_sec.cc
@@ -24,18 +24,22 @@
#define LOG_TAG "bt_btm_sec"
+#include <frameworks/base/core/proto/android/bluetooth/enums.pb.h>
+#include <frameworks/base/core/proto/android/bluetooth/hci/enums.pb.h>
#include <log/log.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
+#include "common/metrics.h"
+#include "common/time_util.h"
#include "device/include/controller.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
-#include "osi/include/time.h"
#include "bt_types.h"
#include "bt_utils.h"
+#include "btif_storage.h"
#include "btm_int.h"
#include "btu.h"
#include "hcimsgs.h"
@@ -49,6 +53,8 @@
bool(APPL_AUTH_WRITE_EXCEPTION)(const RawAddress& bd_addr);
#endif
+extern void btm_ble_advertiser_notify_terminated_legacy(
+ uint8_t status, uint16_t connection_handle);
extern void bta_dm_remove_device(const RawAddress& bd_addr);
/*******************************************************************************
@@ -226,7 +232,6 @@
*
******************************************************************************/
bool BTM_SecRegister(const tBTM_APPL_INFO* p_cb_info) {
- BT_OCTET16 temp_value = {0};
BTM_TRACE_EVENT("%s application registered", __func__);
@@ -235,8 +240,9 @@
if (p_cb_info->p_le_callback) {
BTM_TRACE_EVENT("%s SMP_Register( btm_proc_smp_cback )", __func__);
SMP_Register(btm_proc_smp_cback);
+ Octet16 zero{0};
/* if no IR is loaded, need to regenerate all the keys */
- if (memcmp(btm_cb.devcb.id_keys.ir, &temp_value, sizeof(BT_OCTET16)) == 0) {
+ if (btm_cb.devcb.id_keys.ir == zero) {
btm_ble_reset_id();
}
} else {
@@ -1171,15 +1177,15 @@
* the device or device record does not contain link key info
*
* Parameters: bd_addr - Address of the device
- * link_key - Link Key is copied into this array
+ * link_key - Link Key is copied into this pointer
*
******************************************************************************/
tBTM_STATUS BTM_SecGetDeviceLinkKey(const RawAddress& bd_addr,
- LINK_KEY link_key) {
+ LinkKey* link_key) {
tBTM_SEC_DEV_REC* p_dev_rec;
p_dev_rec = btm_find_dev(bd_addr);
if ((p_dev_rec != NULL) && (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)) {
- memcpy(link_key, p_dev_rec->link_key, LINK_KEY_LEN);
+ *link_key = p_dev_rec->link_key;
return (BTM_SUCCESS);
}
return (BTM_UNKNOWN_ADDR);
@@ -1435,7 +1441,6 @@
* BTM_MAX_PASSKEY_VAL(999999(0xF423F)).
*
******************************************************************************/
-#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
void BTM_PasskeyReqReply(tBTM_STATUS res, const RawAddress& bd_addr,
uint32_t passkey) {
BTM_TRACE_API("BTM_PasskeyReqReply: State: %s res:%d",
@@ -1482,7 +1487,6 @@
btsnd_hcic_user_passkey_reply(bd_addr, passkey);
}
}
-#endif
/*******************************************************************************
*
@@ -1498,13 +1502,11 @@
* type - notification type
*
******************************************************************************/
-#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
void BTM_SendKeypressNotif(const RawAddress& bd_addr, tBTM_SP_KEY_TYPE type) {
/* This API only make sense between PASSKEY_REQ and SP complete */
if (btm_cb.pairing_state == BTM_PAIR_STATE_KEY_ENTRY)
btsnd_hcic_send_keypress_notif(bd_addr, type);
}
-#endif
/*******************************************************************************
*
@@ -1564,7 +1566,7 @@
*
******************************************************************************/
void BTM_RemoteOobDataReply(tBTM_STATUS res, const RawAddress& bd_addr,
- BT_OCTET16 c, BT_OCTET16 r) {
+ const Octet16& c, const Octet16& r) {
BTM_TRACE_EVENT("%s() - State: %s res: %d", __func__,
btm_pair_state_descr(btm_cb.pairing_state), res);
@@ -1602,8 +1604,8 @@
* Returns Number of bytes in p_data.
*
******************************************************************************/
-uint16_t BTM_BuildOobData(uint8_t* p_data, uint16_t max_len, BT_OCTET16 c,
- BT_OCTET16 r, uint8_t name_len) {
+uint16_t BTM_BuildOobData(uint8_t* p_data, uint16_t max_len, const Octet16& c,
+ const Octet16& r, uint8_t name_len) {
uint8_t* p = p_data;
uint16_t len = 0;
uint16_t name_size;
@@ -1624,7 +1626,7 @@
if (max_len >= delta) {
*p++ = BTM_OOB_HASH_C_SIZE + 1;
*p++ = BTM_EIR_OOB_SSP_HASH_C_TYPE;
- ARRAY_TO_STREAM(p, c, BTM_OOB_HASH_C_SIZE);
+ ARRAY_TO_STREAM(p, c.data(), BTM_OOB_HASH_C_SIZE);
len += delta;
max_len -= delta;
}
@@ -1634,7 +1636,7 @@
if (max_len >= delta) {
*p++ = BTM_OOB_RAND_R_SIZE + 1;
*p++ = BTM_EIR_OOB_SSP_RAND_R_TYPE;
- ARRAY_TO_STREAM(p, r, BTM_OOB_RAND_R_SIZE);
+ ARRAY_TO_STREAM(p, r.data(), BTM_OOB_RAND_R_SIZE);
len += delta;
max_len -= delta;
}
@@ -2609,10 +2611,18 @@
******************************************************************************/
void btm_create_conn_cancel_complete(uint8_t* p) {
uint8_t status;
-
STREAM_TO_UINT8(status, p);
+ RawAddress bd_addr;
+ STREAM_TO_BDADDR(bd_addr, p);
BTM_TRACE_EVENT("btm_create_conn_cancel_complete(): in State: %s status:%d",
btm_pair_state_descr(btm_cb.pairing_state), status);
+ bluetooth::common::LogLinkLayerConnectionEvent(
+ &bd_addr, bluetooth::common::kUnknownConnectionHandle,
+ android::bluetooth::DIRECTION_OUTGOING, android::bluetooth::LINK_TYPE_ACL,
+ android::bluetooth::hci::CMD_CREATE_CONNECTION_CANCEL,
+ android::bluetooth::hci::EVT_COMMAND_COMPLETE,
+ android::bluetooth::hci::BLE_EVT_UNKNOWN, status,
+ android::bluetooth::hci::STATUS_UNKNOWN);
/* if the create conn cancel cmd was issued by the bond cancel,
** the application needs to be notified that bond cancel succeeded
@@ -2691,7 +2701,6 @@
void btm_sec_init(uint8_t sec_mode) {
btm_cb.security_mode = sec_mode;
btm_cb.pairing_bda = RawAddress::kAny;
- btm_cb.max_collision_delay = BTM_SEC_MAX_COLLISION_DELAY;
}
/*******************************************************************************
@@ -2722,7 +2731,7 @@
void btm_sec_dev_reset(void) {
if (controller_get_interface()->supports_simple_pairing()) {
/* set the default IO capabilities */
- btm_cb.devcb.loc_io_caps = BTM_LOCAL_IO_CAPS;
+ btm_cb.devcb.loc_io_caps = btif_storage_get_local_io_caps();
/* add mx service to use no security */
BTM_SetSecurityLevel(false, "RFC_MUX", BTM_SEC_SERVICE_RFC_MUX,
BTM_SEC_NONE, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, 0);
@@ -2793,7 +2802,7 @@
/* set up the control block to indicated dedicated bonding */
btm_cb.pairing_flags |= BTM_PAIR_FLAGS_DISC_WHEN_DONE;
- if (!l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR)) {
+ if (!l2cu_create_conn_br_edr(p_lcb)) {
LOG(WARNING) << "Security Manager: failed create allocate LCB "
<< p_dev_rec->bd_addr;
@@ -3401,26 +3410,27 @@
evt_data.cfm_req.just_works = true;
-/* process user confirm req in association with the auth_req param */
-#if (BTM_LOCAL_IO_CAPS == BTM_IO_CAP_IO)
- if (p_dev_rec->rmt_io_caps == BTM_IO_CAP_UNKNOWN) {
- BTM_TRACE_ERROR(
- "%s did not receive IO cap response prior"
- " to BTM_SP_CFM_REQ_EVT, failing pairing request",
- __func__);
- status = BTM_WRONG_MODE;
- BTM_ConfirmReqReply(status, p_bda);
- return;
+ /* process user confirm req in association with the auth_req param */
+ if (btm_cb.devcb.loc_io_caps == BTM_IO_CAP_IO) {
+ if (p_dev_rec->rmt_io_caps == BTM_IO_CAP_UNKNOWN) {
+ BTM_TRACE_ERROR(
+ "%s did not receive IO cap response prior"
+ " to BTM_SP_CFM_REQ_EVT, failing pairing request",
+ __func__);
+ status = BTM_WRONG_MODE;
+ BTM_ConfirmReqReply(status, p_bda);
+ return;
+ }
+ if ((p_dev_rec->rmt_io_caps == BTM_IO_CAP_IO) &&
+ (btm_cb.devcb.loc_io_caps == BTM_IO_CAP_IO) &&
+ ((p_dev_rec->rmt_auth_req & BTM_AUTH_SP_YES) ||
+ (btm_cb.devcb.loc_auth_req & BTM_AUTH_SP_YES))) {
+ /* Both devices are DisplayYesNo and one or both devices want to
+ authenticate -> use authenticated link key */
+ evt_data.cfm_req.just_works = false;
+ }
}
- if ((p_dev_rec->rmt_io_caps == BTM_IO_CAP_IO) &&
- (btm_cb.devcb.loc_io_caps == BTM_IO_CAP_IO) &&
- ((p_dev_rec->rmt_auth_req & BTM_AUTH_SP_YES) ||
- (btm_cb.devcb.loc_auth_req & BTM_AUTH_SP_YES))) {
- /* Both devices are DisplayYesNo and one or both devices want to
- authenticate -> use authenticated link key */
- evt_data.cfm_req.just_works = false;
- }
-#endif
+
BTM_TRACE_DEBUG(
"btm_proc_sp_req_evt() just_works:%d, io loc:%d, rmt:%d, auth "
"loc:%d, rmt:%d",
@@ -3443,12 +3453,12 @@
btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
break;
-#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
case BTM_SP_KEY_REQ_EVT:
- /* HCI_USER_PASSKEY_REQUEST_EVT */
- btm_sec_change_pairing_state(BTM_PAIR_STATE_KEY_ENTRY);
+ if (btm_cb.devcb.loc_io_caps != BTM_IO_CAP_NONE) {
+ /* HCI_USER_PASSKEY_REQUEST_EVT */
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_KEY_ENTRY);
+ }
break;
-#endif
}
if (btm_cb.api.p_sp_callback) {
@@ -3466,12 +3476,10 @@
if (event == BTM_SP_CFM_REQ_EVT) {
BTM_TRACE_DEBUG("calling BTM_ConfirmReqReply with status: %d", status);
BTM_ConfirmReqReply(status, p_bda);
- }
-#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
- else if (event == BTM_SP_KEY_REQ_EVT) {
+ } else if (btm_cb.devcb.loc_io_caps != BTM_IO_CAP_NONE &&
+ event == BTM_SP_KEY_REQ_EVT) {
BTM_PasskeyReqReply(status, p_bda, 0);
}
-#endif
return;
}
@@ -3492,12 +3500,9 @@
if (p_dev_rec != NULL) {
btm_sec_disconnect(p_dev_rec->hci_handle, HCI_ERR_AUTH_FAILURE);
}
- }
-#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
- else {
+ } else if (btm_cb.devcb.loc_io_caps != BTM_IO_CAP_NONE) {
btsnd_hcic_user_passkey_neg_reply(p_bda);
}
-#endif
}
/*******************************************************************************
@@ -3612,8 +3617,8 @@
void btm_rem_oob_req(uint8_t* p) {
tBTM_SP_RMT_OOB evt_data;
tBTM_SEC_DEV_REC* p_dev_rec;
- BT_OCTET16 c;
- BT_OCTET16 r;
+ Octet16 c;
+ Octet16 r;
RawAddress& p_bda = evt_data.bd_addr;
@@ -3658,8 +3663,8 @@
BTM_TRACE_EVENT("btm_read_local_oob_complete:%d", status);
if (status == HCI_SUCCESS) {
evt_data.status = BTM_SUCCESS;
- STREAM_TO_ARRAY16(evt_data.c, p);
- STREAM_TO_ARRAY16(evt_data.r, p);
+ STREAM_TO_ARRAY16(evt_data.c.data(), p);
+ STREAM_TO_ARRAY16(evt_data.r.data(), p);
} else
evt_data.status = BTM_ERR_PROCESSING;
@@ -3684,10 +3689,10 @@
tBTM_SEC_DEV_REC* p_dev_rec;
if (!btm_cb.collision_start_time)
- btm_cb.collision_start_time = time_get_os_boottime_ms();
+ btm_cb.collision_start_time = bluetooth::common::time_get_os_boottime_ms();
- if ((time_get_os_boottime_ms() - btm_cb.collision_start_time) <
- btm_cb.max_collision_delay) {
+ if ((bluetooth::common::time_get_os_boottime_ms() -
+ btm_cb.collision_start_time) < BTM_SEC_MAX_COLLISION_DELAY) {
if (handle == BTM_SEC_INVALID_HANDLE) {
p_dev_rec = btm_sec_find_dev_by_sec_state(BTM_SEC_STATE_AUTHENTICATING);
if (p_dev_rec == NULL)
@@ -4112,6 +4117,7 @@
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bda);
uint8_t res;
bool is_pairing_device = false;
+ bool addr_matched;
tACL_CONN* p_acl_cb;
uint8_t bit_shift = 0;
@@ -4201,8 +4207,9 @@
p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
- if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) &&
- (btm_cb.pairing_bda == bda)) {
+ addr_matched = (btm_cb.pairing_bda == bda);
+
+ if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) && addr_matched) {
/* if we rejected incoming connection from bonding device */
if ((status == HCI_ERR_HOST_REJECT_DEVICE) &&
(btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT)) {
@@ -4298,7 +4305,7 @@
}
}
- if (btm_cb.pairing_bda != bda) {
+ if (!addr_matched) {
/* Don't callback unless this Connection-Complete-failure event has the
* same mac address as the bonding device */
VLOG(1) << __func__
@@ -4522,6 +4529,12 @@
p_dev_rec->ble_hci_handle = BTM_SEC_INVALID_HANDLE;
p_dev_rec->sec_flags &= ~(BTM_SEC_LE_AUTHENTICATED | BTM_SEC_LE_ENCRYPTED);
p_dev_rec->enc_key_size = 0;
+
+ // This is for chips that don't support being in connected and advertising
+ // state at same time.
+ if (!p_dev_rec->is_originator) {
+ btm_ble_advertiser_notify_terminated_legacy(HCI_SUCCESS, handle);
+ }
} else {
p_dev_rec->hci_handle = BTM_SEC_INVALID_HANDLE;
p_dev_rec->sec_flags &=
@@ -4571,18 +4584,9 @@
}
}
-/*******************************************************************************
- *
- * Function btm_sec_link_key_notification
- *
- * Description This function is called when a new connection link key is
- * generated
- *
- * Returns Pointer to the record or NULL
- *
- ******************************************************************************/
-void btm_sec_link_key_notification(const RawAddress& p_bda, uint8_t* p_link_key,
- uint8_t key_type) {
+/** This function is called when a new connection link key is generated */
+void btm_sec_link_key_notification(const RawAddress& p_bda,
+ const Octet16& link_key, uint8_t key_type) {
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_or_alloc_dev(p_bda);
bool we_are_bonding = false;
bool ltk_derived_lk = false;
@@ -4615,7 +4619,7 @@
/* BR/EDR connection, update the encryption key size to be 16 as always */
p_dev_rec->enc_key_size = 16;
- memcpy(p_dev_rec->link_key, p_link_key, LINK_KEY_LEN);
+ p_dev_rec->link_key = link_key;
if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) &&
(btm_cb.pairing_bda == p_bda)) {
@@ -4631,7 +4635,7 @@
BTM_TRACE_DEBUG("%s() Save LTK derived LK (key_type = %d)", __func__,
p_dev_rec->link_key_type);
(*btm_cb.api.p_link_key_callback)(p_bda, p_dev_rec->dev_class,
- p_dev_rec->sec_bd_name, p_link_key,
+ p_dev_rec->sec_bd_name, link_key,
p_dev_rec->link_key_type);
}
} else {
@@ -4695,7 +4699,7 @@
p_dev_rec->link_key_type);
} else {
(*btm_cb.api.p_link_key_callback)(p_bda, p_dev_rec->dev_class,
- p_dev_rec->sec_bd_name, p_link_key,
+ p_dev_rec->sec_bd_name, link_key,
p_dev_rec->link_key_type);
}
}
@@ -4751,11 +4755,9 @@
static void btm_sec_pairing_timeout(UNUSED_ATTR void* data) {
tBTM_CB* p_cb = &btm_cb;
tBTM_SEC_DEV_REC* p_dev_rec;
-#if (BTM_LOCAL_IO_CAPS == BTM_IO_CAP_NONE)
- tBTM_AUTH_REQ auth_req = BTM_AUTH_AP_NO;
-#else
- tBTM_AUTH_REQ auth_req = BTM_AUTH_AP_YES;
-#endif
+ tBTM_AUTH_REQ auth_req = (btm_cb.devcb.loc_io_caps == BTM_IO_CAP_NONE)
+ ? BTM_AUTH_AP_NO
+ : BTM_AUTH_AP_YES;
uint8_t name[2];
p_dev_rec = btm_find_dev(p_cb->pairing_bda);
@@ -4791,12 +4793,13 @@
/* btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); */
break;
-#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
case BTM_PAIR_STATE_KEY_ENTRY:
- btsnd_hcic_user_passkey_neg_reply(p_cb->pairing_bda);
- /* btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); */
+ if (btm_cb.devcb.loc_io_caps != BTM_IO_CAP_NONE) {
+ btsnd_hcic_user_passkey_neg_reply(p_cb->pairing_bda);
+ } else {
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
+ }
break;
-#endif /* !BTM_IO_CAP_NONE */
case BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS:
if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
diff --git a/stack/btu/btu_hcif.cc b/stack/btu/btu_hcif.cc
index fbd7695..b9543fd 100644
--- a/stack/btu/btu_hcif.cc
+++ b/stack/btu/btu_hcif.cc
@@ -32,6 +32,8 @@
#include <base/location.h>
#include <base/logging.h>
#include <base/threading/thread.h>
+#include <frameworks/base/core/proto/android/bluetooth/enums.pb.h>
+#include <frameworks/base/core/proto/android/bluetooth/hci/enums.pb.h>
#include <log/log.h>
#include <statslog.h>
#include <stdio.h>
@@ -44,6 +46,7 @@
#include "btm_api.h"
#include "btm_int.h"
#include "btu.h"
+#include "common/metrics.h"
#include "device/include/controller.h"
#include "hci_layer.h"
#include "hcimsgs.h"
@@ -51,10 +54,11 @@
#include "osi/include/log.h"
#include "osi/include/osi.h"
-using tracked_objects::Location;
+using base::Location;
extern void btm_process_cancel_complete(uint8_t status, uint8_t mode);
extern void btm_ble_test_command_complete(uint8_t* p);
+extern void smp_cancel_start_encryption_attempt();
/******************************************************************************/
/* L O C A L F U N C T I O N P R O T O T Y P E S */
@@ -128,16 +132,110 @@
static void btu_ble_proc_enhanced_conn_cmpl(uint8_t* p, uint16_t evt_len);
#endif
-static void do_in_hci_thread(const tracked_objects::Location& from_here,
- const base::Closure& task) {
- base::MessageLoop* hci_message_loop = get_message_loop();
- if (!hci_message_loop || !hci_message_loop->task_runner().get()) {
- LOG_ERROR(LOG_TAG, "%s: HCI message loop not running, accessed from %s",
- __func__, from_here.ToString().c_str());
- return;
- }
+/**
+ * Log HCI event metrics that are not handled in special functions
+ * @param evt_code event code
+ * @param p_event pointer to event parameter, skipping paremter length
+ */
+void btu_hcif_log_event_metrics(uint8_t evt_code, uint8_t* p_event) {
+ uint32_t cmd = android::bluetooth::hci::CMD_UNKNOWN;
+ uint16_t status = android::bluetooth::hci::STATUS_UNKNOWN;
+ uint16_t reason = android::bluetooth::hci::STATUS_UNKNOWN;
+ uint16_t handle = bluetooth::common::kUnknownConnectionHandle;
+ int64_t value = 0;
- hci_message_loop->task_runner()->PostTask(from_here, task);
+ RawAddress bda = RawAddress::kEmpty;
+ switch (evt_code) {
+ case HCI_IO_CAPABILITY_REQUEST_EVT:
+ case HCI_IO_CAPABILITY_RESPONSE_EVT:
+ case HCI_LINK_KEY_REQUEST_EVT:
+ case HCI_LINK_KEY_NOTIFICATION_EVT:
+ case HCI_USER_PASSKEY_REQUEST_EVT:
+ case HCI_USER_PASSKEY_NOTIFY_EVT:
+ case HCI_USER_CONFIRMATION_REQUEST_EVT:
+ case HCI_KEYPRESS_NOTIFY_EVT:
+ case HCI_REMOTE_OOB_DATA_REQUEST_EVT:
+ STREAM_TO_BDADDR(bda, p_event);
+ bluetooth::common::LogClassicPairingEvent(bda, handle, cmd, evt_code, status, reason, value);
+ break;
+ case HCI_SIMPLE_PAIRING_COMPLETE_EVT:
+ case HCI_RMT_NAME_REQUEST_COMP_EVT:
+ STREAM_TO_UINT8(status, p_event);
+ STREAM_TO_BDADDR(bda, p_event);
+ bluetooth::common::LogClassicPairingEvent(bda, handle, cmd, evt_code, status, reason, value);
+ break;
+ case HCI_AUTHENTICATION_COMP_EVT:
+ STREAM_TO_UINT8(status, p_event);
+ STREAM_TO_UINT16(handle, p_event);
+ handle = HCID_GET_HANDLE(handle);
+ bluetooth::common::LogClassicPairingEvent(bda, handle, cmd, evt_code, status, reason, value);
+ break;
+ case HCI_ENCRYPTION_CHANGE_EVT: {
+ uint8_t encryption_enabled;
+ STREAM_TO_UINT8(status, p_event);
+ STREAM_TO_UINT16(handle, p_event);
+ STREAM_TO_UINT8(encryption_enabled, p_event);
+ bluetooth::common::LogClassicPairingEvent(bda, handle, cmd, evt_code, status, reason, encryption_enabled);
+ break;
+ }
+ case HCI_CONNECTION_COMP_EVT: {
+ uint8_t link_type;
+ STREAM_TO_UINT8(status, p_event);
+ STREAM_TO_UINT16(handle, p_event);
+ STREAM_TO_BDADDR(bda, p_event);
+ STREAM_TO_UINT8(link_type, p_event);
+ handle = HCID_GET_HANDLE(handle);
+ bluetooth::common::LogLinkLayerConnectionEvent(
+ &bda, handle, android::bluetooth::DIRECTION_UNKNOWN, link_type, cmd,
+ evt_code, android::bluetooth::hci::BLE_EVT_UNKNOWN, status, reason);
+ break;
+ }
+ case HCI_CONNECTION_REQUEST_EVT: {
+ DEV_CLASS dc;
+ uint8_t link_type;
+ STREAM_TO_BDADDR(bda, p_event);
+ STREAM_TO_DEVCLASS(dc, p_event);
+ STREAM_TO_UINT8(link_type, p_event);
+ bluetooth::common::LogLinkLayerConnectionEvent(
+ &bda, bluetooth::common::kUnknownConnectionHandle,
+ android::bluetooth::DIRECTION_INCOMING, link_type, cmd, evt_code,
+ android::bluetooth::hci::BLE_EVT_UNKNOWN, status, reason);
+ break;
+ }
+ case HCI_DISCONNECTION_COMP_EVT: {
+ STREAM_TO_UINT8(status, p_event);
+ STREAM_TO_UINT16(handle, p_event);
+ STREAM_TO_UINT8(reason, p_event);
+ handle = HCID_GET_HANDLE(handle);
+ bluetooth::common::LogLinkLayerConnectionEvent(
+ nullptr, handle, android::bluetooth::DIRECTION_UNKNOWN,
+ android::bluetooth::LINK_TYPE_UNKNOWN, cmd, evt_code,
+ android::bluetooth::hci::BLE_EVT_UNKNOWN, status, reason);
+ break;
+ }
+ case HCI_ESCO_CONNECTION_COMP_EVT: {
+ uint8_t link_type;
+ STREAM_TO_UINT8(status, p_event);
+ STREAM_TO_UINT16(handle, p_event);
+ STREAM_TO_BDADDR(bda, p_event);
+ STREAM_TO_UINT8(link_type, p_event);
+ handle = HCID_GET_HANDLE(handle);
+ bluetooth::common::LogLinkLayerConnectionEvent(
+ &bda, handle, android::bluetooth::DIRECTION_UNKNOWN, link_type, cmd,
+ evt_code, android::bluetooth::hci::BLE_EVT_UNKNOWN, status, reason);
+ break;
+ }
+ case HCI_ESCO_CONNECTION_CHANGED_EVT: {
+ STREAM_TO_UINT8(status, p_event);
+ STREAM_TO_UINT16(handle, p_event);
+ handle = HCID_GET_HANDLE(handle);
+ bluetooth::common::LogLinkLayerConnectionEvent(
+ nullptr, handle, android::bluetooth::DIRECTION_UNKNOWN,
+ android::bluetooth::LINK_TYPE_UNKNOWN, cmd, evt_code,
+ android::bluetooth::hci::BLE_EVT_UNKNOWN, status, reason);
+ break;
+ }
+ }
}
/*******************************************************************************
@@ -157,6 +255,8 @@
STREAM_TO_UINT8(hci_evt_code, p);
STREAM_TO_UINT8(hci_evt_len, p);
+ btu_hcif_log_event_metrics(hci_evt_code, p);
+
switch (hci_evt_code) {
case HCI_INQUIRY_COMP_EVT:
btu_hcif_inquiry_comp_evt(p);
@@ -366,6 +466,245 @@
}
}
+static void btu_hcif_log_command_metrics(uint16_t opcode, uint8_t* p_cmd,
+ uint16_t cmd_status,
+ bool is_cmd_status) {
+ static uint16_t kUnknownBleEvt = android::bluetooth::hci::BLE_EVT_UNKNOWN;
+
+ uint16_t hci_event = android::bluetooth::hci::EVT_COMMAND_STATUS;
+ if (!is_cmd_status) {
+ hci_event = android::bluetooth::hci::EVT_UNKNOWN;
+ cmd_status = android::bluetooth::hci::STATUS_UNKNOWN;
+ }
+
+ RawAddress bd_addr;
+ uint16_t handle;
+ uint8_t reason;
+
+ switch (opcode) {
+ case HCI_CREATE_CONNECTION:
+ case HCI_CREATE_CONNECTION_CANCEL:
+ STREAM_TO_BDADDR(bd_addr, p_cmd);
+ bluetooth::common::LogLinkLayerConnectionEvent(
+ &bd_addr, bluetooth::common::kUnknownConnectionHandle,
+ android::bluetooth::DIRECTION_OUTGOING,
+ android::bluetooth::LINK_TYPE_ACL, opcode, hci_event, kUnknownBleEvt,
+ cmd_status, android::bluetooth::hci::STATUS_UNKNOWN);
+ break;
+ case HCI_DISCONNECT:
+ STREAM_TO_UINT16(handle, p_cmd);
+ STREAM_TO_UINT8(reason, p_cmd);
+ bluetooth::common::LogLinkLayerConnectionEvent(
+ nullptr, handle, android::bluetooth::DIRECTION_UNKNOWN,
+ android::bluetooth::LINK_TYPE_UNKNOWN, opcode, hci_event,
+ kUnknownBleEvt, cmd_status, reason);
+ break;
+ case HCI_SETUP_ESCO_CONNECTION:
+ case HCI_ENH_SETUP_ESCO_CONNECTION:
+ STREAM_TO_UINT16(handle, p_cmd);
+ bluetooth::common::LogLinkLayerConnectionEvent(
+ nullptr, handle, android::bluetooth::DIRECTION_OUTGOING,
+ android::bluetooth::LINK_TYPE_UNKNOWN, opcode, hci_event,
+ kUnknownBleEvt, cmd_status, android::bluetooth::hci::STATUS_UNKNOWN);
+ break;
+ case HCI_ACCEPT_CONNECTION_REQUEST:
+ case HCI_ACCEPT_ESCO_CONNECTION:
+ case HCI_ENH_ACCEPT_ESCO_CONNECTION:
+ STREAM_TO_BDADDR(bd_addr, p_cmd);
+ bluetooth::common::LogLinkLayerConnectionEvent(
+ &bd_addr, bluetooth::common::kUnknownConnectionHandle,
+ android::bluetooth::DIRECTION_INCOMING,
+ android::bluetooth::LINK_TYPE_UNKNOWN, opcode, hci_event,
+ kUnknownBleEvt, cmd_status, android::bluetooth::hci::STATUS_UNKNOWN);
+ break;
+ case HCI_REJECT_CONNECTION_REQUEST:
+ case HCI_REJECT_ESCO_CONNECTION:
+ STREAM_TO_BDADDR(bd_addr, p_cmd);
+ STREAM_TO_UINT8(reason, p_cmd);
+ bluetooth::common::LogLinkLayerConnectionEvent(
+ &bd_addr, bluetooth::common::kUnknownConnectionHandle,
+ android::bluetooth::DIRECTION_INCOMING,
+ android::bluetooth::LINK_TYPE_UNKNOWN, opcode, hci_event,
+ kUnknownBleEvt, cmd_status, reason);
+ break;
+
+ // BLE Commands
+ case HCI_BLE_CREATE_LL_CONN: {
+ p_cmd += 2; // Skip LE_Scan_Interval
+ p_cmd += 2; // Skip LE_Scan_Window;
+ uint8_t initiator_filter_policy;
+ STREAM_TO_UINT8(initiator_filter_policy, p_cmd);
+ uint8_t peer_address_type;
+ STREAM_TO_UINT8(peer_address_type, p_cmd);
+ STREAM_TO_BDADDR(bd_addr, p_cmd);
+ // Peer address should not be used if initiator filter policy is not 0x00
+ const RawAddress* bd_addr_p = nullptr;
+ if (initiator_filter_policy == 0x00) {
+ bd_addr_p = &bd_addr;
+#if (BLE_PRIVACY_SPT == TRUE)
+ if (peer_address_type == BLE_ADDR_PUBLIC_ID ||
+ peer_address_type == BLE_ADDR_RANDOM_ID) {
+ // if identity address is not matched, this address is invalid
+ if (!btm_identity_addr_to_random_pseudo(&bd_addr, &peer_address_type,
+ false)) {
+ bd_addr_p = nullptr;
+ }
+ }
+#endif
+ }
+ if (initiator_filter_policy == 0x00 ||
+ (cmd_status != HCI_SUCCESS && !is_cmd_status)) {
+ // Selectively log to avoid log spam due to whitelist connections:
+ // - When doing non-whitelist connection
+ // - When there is an error in command status
+ bluetooth::common::LogLinkLayerConnectionEvent(
+ bd_addr_p, bluetooth::common::kUnknownConnectionHandle,
+ android::bluetooth::DIRECTION_OUTGOING,
+ android::bluetooth::LINK_TYPE_ACL, opcode, hci_event,
+ kUnknownBleEvt, cmd_status,
+ android::bluetooth::hci::STATUS_UNKNOWN);
+ }
+ break;
+ }
+ case HCI_LE_EXTENDED_CREATE_CONNECTION: {
+ uint8_t initiator_filter_policy;
+ STREAM_TO_UINT8(initiator_filter_policy, p_cmd);
+ p_cmd += 1; // Skip Own_Address_Type
+ uint8_t peer_addr_type;
+ STREAM_TO_UINT8(peer_addr_type, p_cmd);
+ STREAM_TO_BDADDR(bd_addr, p_cmd);
+ // Peer address should not be used if initiator filter policy is not 0x00
+ const RawAddress* bd_addr_p = nullptr;
+ if (initiator_filter_policy == 0x00) {
+ bd_addr_p = &bd_addr;
+#if (BLE_PRIVACY_SPT == TRUE)
+ // if identity address is not matched, this should be a static address
+ btm_identity_addr_to_random_pseudo(&bd_addr, &peer_addr_type, false);
+#endif
+ }
+ if (initiator_filter_policy == 0x00 ||
+ (cmd_status != HCI_SUCCESS && !is_cmd_status)) {
+ // Selectively log to avoid log spam due to whitelist connections:
+ // - When doing non-whitelist connection
+ // - When there is an error in command status
+ bluetooth::common::LogLinkLayerConnectionEvent(
+ bd_addr_p, bluetooth::common::kUnknownConnectionHandle,
+ android::bluetooth::DIRECTION_OUTGOING,
+ android::bluetooth::LINK_TYPE_ACL, opcode, hci_event,
+ kUnknownBleEvt, cmd_status,
+ android::bluetooth::hci::STATUS_UNKNOWN);
+ }
+ break;
+ }
+ case HCI_BLE_CREATE_CONN_CANCEL:
+ if (cmd_status != HCI_SUCCESS && !is_cmd_status) {
+ // Only log errors to prevent log spam due to whitelist connections
+ bluetooth::common::LogLinkLayerConnectionEvent(
+ nullptr, bluetooth::common::kUnknownConnectionHandle,
+ android::bluetooth::DIRECTION_OUTGOING,
+ android::bluetooth::LINK_TYPE_ACL, opcode, hci_event,
+ kUnknownBleEvt, cmd_status,
+ android::bluetooth::hci::STATUS_UNKNOWN);
+ }
+ break;
+ case HCI_BLE_CLEAR_WHITE_LIST:
+ bluetooth::common::LogLinkLayerConnectionEvent(
+ nullptr, bluetooth::common::kUnknownConnectionHandle,
+ android::bluetooth::DIRECTION_INCOMING,
+ android::bluetooth::LINK_TYPE_ACL, opcode, hci_event, kUnknownBleEvt,
+ cmd_status, android::bluetooth::hci::STATUS_UNKNOWN);
+ break;
+ case HCI_BLE_ADD_WHITE_LIST:
+ case HCI_BLE_REMOVE_WHITE_LIST: {
+ uint8_t peer_addr_type;
+ STREAM_TO_UINT8(peer_addr_type, p_cmd);
+ STREAM_TO_BDADDR(bd_addr, p_cmd);
+ const RawAddress* bd_addr_p = nullptr;
+ // When peer_addr_type is 0xFF, bd_addr should be ignored per BT spec
+ if (peer_addr_type != BLE_ADDR_ANONYMOUS) {
+ bd_addr_p = &bd_addr;
+#if (BLE_PRIVACY_SPT == TRUE)
+ bool addr_is_rpa = peer_addr_type == BLE_ADDR_RANDOM &&
+ BTM_BLE_IS_RESOLVE_BDA(bd_addr);
+ // Only try to match identity address for pseudo if address is not RPA
+ if (!addr_is_rpa) {
+ // if identity address is not matched, this should be a static address
+ btm_identity_addr_to_random_pseudo(&bd_addr, &peer_addr_type, false);
+ }
+#endif
+ }
+ bluetooth::common::LogLinkLayerConnectionEvent(
+ bd_addr_p, bluetooth::common::kUnknownConnectionHandle,
+ android::bluetooth::DIRECTION_INCOMING,
+ android::bluetooth::LINK_TYPE_ACL, opcode, hci_event, kUnknownBleEvt,
+ cmd_status, android::bluetooth::hci::STATUS_UNKNOWN);
+ break;
+ }
+ case HCI_READ_LOCAL_OOB_DATA:
+ bluetooth::common::LogClassicPairingEvent(RawAddress::kEmpty, bluetooth::common::kUnknownConnectionHandle, opcode,
+ hci_event, cmd_status, android::bluetooth::hci::STATUS_UNKNOWN, 0);
+ break;
+ case HCI_WRITE_SIMPLE_PAIRING_MODE: {
+ uint8_t simple_pairing_mode;
+ STREAM_TO_UINT8(simple_pairing_mode, p_cmd);
+ bluetooth::common::LogClassicPairingEvent(RawAddress::kEmpty, bluetooth::common::kUnknownConnectionHandle, opcode,
+ hci_event, cmd_status, android::bluetooth::hci::STATUS_UNKNOWN,
+ simple_pairing_mode);
+ break;
+ }
+ case HCI_WRITE_SECURE_CONNS_SUPPORT: {
+ uint8_t secure_conn_host_support;
+ STREAM_TO_UINT8(secure_conn_host_support, p_cmd);
+ bluetooth::common::LogClassicPairingEvent(RawAddress::kEmpty, bluetooth::common::kUnknownConnectionHandle, opcode,
+ hci_event, cmd_status, android::bluetooth::hci::STATUS_UNKNOWN,
+ secure_conn_host_support);
+ break;
+ }
+ case HCI_AUTHENTICATION_REQUESTED:
+ STREAM_TO_UINT16(handle, p_cmd);
+ bluetooth::common::LogClassicPairingEvent(RawAddress::kEmpty, handle, opcode, hci_event, cmd_status,
+ android::bluetooth::hci::STATUS_UNKNOWN, 0);
+ break;
+ case HCI_SET_CONN_ENCRYPTION: {
+ STREAM_TO_UINT16(handle, p_cmd);
+ uint8_t encryption_enable;
+ STREAM_TO_UINT8(encryption_enable, p_cmd);
+ bluetooth::common::LogClassicPairingEvent(RawAddress::kEmpty, handle, opcode, hci_event, cmd_status,
+ android::bluetooth::hci::STATUS_UNKNOWN, encryption_enable);
+ break;
+ }
+ case HCI_DELETE_STORED_LINK_KEY: {
+ uint8_t delete_all_flag;
+ STREAM_TO_BDADDR(bd_addr, p_cmd);
+ STREAM_TO_UINT8(delete_all_flag, p_cmd);
+ bluetooth::common::LogClassicPairingEvent(bd_addr, bluetooth::common::kUnknownConnectionHandle, opcode, hci_event,
+ cmd_status, android::bluetooth::hci::STATUS_UNKNOWN, delete_all_flag);
+ break;
+ }
+ case HCI_RMT_NAME_REQUEST:
+ case HCI_RMT_NAME_REQUEST_CANCEL:
+ case HCI_LINK_KEY_REQUEST_REPLY:
+ case HCI_LINK_KEY_REQUEST_NEG_REPLY:
+ case HCI_IO_CAPABILITY_REQUEST_REPLY:
+ case HCI_USER_CONF_REQUEST_REPLY:
+ case HCI_USER_CONF_VALUE_NEG_REPLY:
+ case HCI_USER_PASSKEY_REQ_REPLY:
+ case HCI_USER_PASSKEY_REQ_NEG_REPLY:
+ case HCI_REM_OOB_DATA_REQ_REPLY:
+ case HCI_REM_OOB_DATA_REQ_NEG_REPLY:
+ STREAM_TO_BDADDR(bd_addr, p_cmd);
+ bluetooth::common::LogClassicPairingEvent(bd_addr, bluetooth::common::kUnknownConnectionHandle, opcode, hci_event,
+ cmd_status, android::bluetooth::hci::STATUS_UNKNOWN, 0);
+ break;
+ case HCI_IO_CAP_REQ_NEG_REPLY:
+ STREAM_TO_BDADDR(bd_addr, p_cmd);
+ STREAM_TO_UINT8(reason, p_cmd);
+ bluetooth::common::LogClassicPairingEvent(bd_addr, bluetooth::common::kUnknownConnectionHandle, opcode, hci_event,
+ cmd_status, reason, 0);
+ break;
+ }
+}
+
/*******************************************************************************
*
* Function btu_hcif_send_cmd
@@ -392,13 +731,18 @@
vsc_callback = *((void**)(p_buf + 1));
}
+ // Skip parameter length before logging
+ stream++;
+ btu_hcif_log_command_metrics(opcode, stream,
+ android::bluetooth::hci::STATUS_UNKNOWN, false);
+
hci_layer_get_interface()->transmit_command(
p_buf, btu_hcif_command_complete_evt, btu_hcif_command_status_evt,
vsc_callback);
}
-using hci_cmd_cb = base::Callback<void(uint8_t* /* return_parameters */,
- uint16_t /* return_parameters_length*/)>;
+using hci_cmd_cb = base::OnceCallback<void(
+ uint8_t* /* return_parameters */, uint16_t /* return_parameters_length*/)>;
struct cmd_with_cb_data {
hci_cmd_cb cb;
@@ -415,18 +759,84 @@
cb_wrapper->posted_from.~Location();
}
+/**
+ * Log command complete events that is not handled individually in this file
+ * @param opcode opcode of the command
+ * @param p_return_params pointer to returned parameter after parameter length
+ * field
+ */
+static void btu_hcif_log_command_complete_metrics(uint16_t opcode,
+ uint8_t* p_return_params) {
+ uint16_t status = android::bluetooth::hci::STATUS_UNKNOWN;
+ uint16_t reason = android::bluetooth::hci::STATUS_UNKNOWN;
+ uint16_t hci_event = android::bluetooth::hci::EVT_COMMAND_COMPLETE;
+ uint16_t hci_ble_event = android::bluetooth::hci::BLE_EVT_UNKNOWN;
+ RawAddress bd_addr = RawAddress::kEmpty;
+ switch (opcode) {
+ case HCI_BLE_CLEAR_WHITE_LIST:
+ case HCI_BLE_ADD_WHITE_LIST:
+ case HCI_BLE_REMOVE_WHITE_LIST: {
+ STREAM_TO_UINT8(status, p_return_params);
+ bluetooth::common::LogLinkLayerConnectionEvent(
+ nullptr, bluetooth::common::kUnknownConnectionHandle,
+ android::bluetooth::DIRECTION_INCOMING,
+ android::bluetooth::LINK_TYPE_ACL, opcode, hci_event, hci_ble_event,
+ status, reason);
+ break;
+ }
+ case HCI_DELETE_STORED_LINK_KEY:
+ case HCI_READ_LOCAL_OOB_DATA:
+ case HCI_WRITE_SIMPLE_PAIRING_MODE:
+ case HCI_WRITE_SECURE_CONNS_SUPPORT:
+ STREAM_TO_UINT8(status, p_return_params);
+ bluetooth::common::LogClassicPairingEvent(RawAddress::kEmpty, bluetooth::common::kUnknownConnectionHandle, opcode,
+ hci_event, status, reason, 0);
+ break;
+ case HCI_READ_ENCR_KEY_SIZE: {
+ uint16_t handle;
+ uint8_t key_size;
+ STREAM_TO_UINT8(status, p_return_params);
+ STREAM_TO_UINT16(handle, p_return_params);
+ STREAM_TO_UINT8(key_size, p_return_params);
+ bluetooth::common::LogClassicPairingEvent(RawAddress::kEmpty, handle, opcode, hci_event, status, reason,
+ key_size);
+ break;
+ }
+ case HCI_LINK_KEY_REQUEST_REPLY:
+ case HCI_LINK_KEY_REQUEST_NEG_REPLY:
+ case HCI_IO_CAPABILITY_REQUEST_REPLY:
+ case HCI_IO_CAP_REQ_NEG_REPLY:
+ case HCI_USER_CONF_REQUEST_REPLY:
+ case HCI_USER_CONF_VALUE_NEG_REPLY:
+ case HCI_USER_PASSKEY_REQ_REPLY:
+ case HCI_USER_PASSKEY_REQ_NEG_REPLY:
+ case HCI_REM_OOB_DATA_REQ_REPLY:
+ case HCI_REM_OOB_DATA_REQ_NEG_REPLY:
+ STREAM_TO_UINT8(status, p_return_params);
+ STREAM_TO_BDADDR(bd_addr, p_return_params);
+ bluetooth::common::LogClassicPairingEvent(bd_addr, bluetooth::common::kUnknownConnectionHandle, opcode, hci_event,
+ status, reason, 0);
+ break;
+ }
+}
+
static void btu_hcif_command_complete_evt_with_cb_on_task(BT_HDR* event,
void* context) {
command_opcode_t opcode;
- uint8_t* stream =
- event->data + event->offset +
- 3; // 2 to skip the event headers, 1 to skip the command credits
+ // 2 for event header: event code (1) + parameter length (1)
+ // 1 for num_hci_pkt command credit
+ uint8_t* stream = event->data + event->offset + 3;
STREAM_TO_UINT16(opcode, stream);
+ btu_hcif_log_command_complete_metrics(opcode, stream);
+
cmd_with_cb_data* cb_wrapper = (cmd_with_cb_data*)context;
HCI_TRACE_DEBUG("command complete for: %s",
cb_wrapper->posted_from.ToString().c_str());
- cb_wrapper->cb.Run(stream, event->len - 5);
+ // 2 for event header: event code (1) + parameter length (1)
+ // 3 for command complete header: num_hci_pkt (1) + opcode (2)
+ uint16_t param_len = static_cast<uint16_t>(event->len - 5);
+ std::move(cb_wrapper->cb).Run(stream, param_len);
cmd_with_cb_data_cleanup(cb_wrapper);
osi_free(cb_wrapper);
@@ -435,9 +845,9 @@
static void btu_hcif_command_complete_evt_with_cb(BT_HDR* response,
void* context) {
- do_in_hci_thread(FROM_HERE,
- base::Bind(btu_hcif_command_complete_evt_with_cb_on_task,
- response, context));
+ do_in_main_thread(FROM_HERE,
+ base::Bind(btu_hcif_command_complete_evt_with_cb_on_task,
+ response, context));
}
static void btu_hcif_command_status_evt_with_cb_on_task(uint8_t status,
@@ -449,11 +859,15 @@
CHECK(status != 0);
+ // stream + 1 to skip parameter length field
+ // No need to check length since stream is written by us
+ btu_hcif_log_command_metrics(opcode, stream + 1, status, true);
+
// report command status error
cmd_with_cb_data* cb_wrapper = (cmd_with_cb_data*)context;
HCI_TRACE_DEBUG("command status for: %s",
cb_wrapper->posted_from.ToString().c_str());
- cb_wrapper->cb.Run(&status, sizeof(uint16_t));
+ std::move(cb_wrapper->cb).Run(&status, sizeof(uint16_t));
cmd_with_cb_data_cleanup(cb_wrapper);
osi_free(cb_wrapper);
@@ -468,7 +882,7 @@
return;
}
- do_in_hci_thread(
+ do_in_main_thread(
FROM_HERE, base::Bind(btu_hcif_command_status_evt_with_cb_on_task, status,
command, context));
}
@@ -476,9 +890,9 @@
/* This function is called to send commands to the Host Controller. |cb| is
* called when command status event is called with error code, or when the
* command complete event is received. */
-void btu_hcif_send_cmd_with_cb(const tracked_objects::Location& posted_from,
- uint16_t opcode, uint8_t* params,
- uint8_t params_len, hci_cmd_cb cb) {
+void btu_hcif_send_cmd_with_cb(const Location& posted_from, uint16_t opcode,
+ uint8_t* params, uint8_t params_len,
+ hci_cmd_cb cb) {
BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
uint8_t* pp = (uint8_t*)(p + 1);
@@ -491,11 +905,14 @@
memcpy(pp, params, params_len);
}
+ btu_hcif_log_command_metrics(opcode, pp,
+ android::bluetooth::hci::STATUS_UNKNOWN, false);
+
cmd_with_cb_data* cb_wrapper =
(cmd_with_cb_data*)osi_malloc(sizeof(cmd_with_cb_data));
cmd_with_cb_data_init(cb_wrapper);
- cb_wrapper->cb = cb;
+ cb_wrapper->cb = std::move(cb);
cb_wrapper->posted_from = posted_from;
hci_layer_get_interface()->transmit_command(
@@ -578,9 +995,7 @@
RawAddress bda;
uint8_t link_type;
uint8_t enc_mode;
-#if (BTM_SCO_INCLUDED == TRUE)
tBTM_ESCO_DATA esco_data;
-#endif
STREAM_TO_UINT8(status, p);
STREAM_TO_UINT16(handle, p);
@@ -601,15 +1016,12 @@
btm_sec_connected(bda, handle, status, enc_mode);
l2c_link_hci_conn_comp(status, handle, bda);
- }
-#if (BTM_SCO_INCLUDED == TRUE)
- else {
+ } else {
memset(&esco_data, 0, sizeof(tBTM_ESCO_DATA));
/* esco_data.link_type = HCI_LINK_TYPE_SCO; already zero */
esco_data.bd_addr = bda;
btm_sco_connected(status, &bda, handle, &esco_data);
}
-#endif /* BTM_SCO_INCLUDED */
}
/*******************************************************************************
@@ -634,12 +1046,9 @@
/* passing request to l2cap */
if (link_type == HCI_LINK_TYPE_ACL) {
btm_sec_conn_req(bda, dc);
- }
-#if (BTM_SCO_INCLUDED == TRUE)
- else {
+ } else {
btm_sco_conn_req(bda, dc, link_type);
}
-#endif /* BTM_SCO_INCLUDED */
}
/*******************************************************************************
@@ -652,10 +1061,11 @@
*
******************************************************************************/
static void btu_hcif_disconnection_comp_evt(uint8_t* p) {
+ uint8_t status;
uint16_t handle;
uint8_t reason;
- ++p;
+ STREAM_TO_UINT8(status, p);
STREAM_TO_UINT16(handle, p);
STREAM_TO_UINT8(reason, p);
@@ -668,12 +1078,8 @@
__func__, reason, handle);
}
-#if (BTM_SCO_INCLUDED == TRUE)
/* If L2CAP doesn't know about it, send it to SCO */
if (!l2c_link_hci_disc_comp(handle, reason)) btm_sco_removed(handle, reason);
-#else
- l2c_link_hci_disc_comp(handle, reason);
-#endif /* BTM_SCO_INCLUDED */
/* Notify security manager */
btm_sec_disconnected(handle, reason);
@@ -725,14 +1131,6 @@
static void read_encryption_key_size_complete_after_encryption_change(
uint8_t status, uint16_t handle, uint8_t key_size) {
- int ret = android::util::stats_write(
- android::util::BLUETOOTH_CLASSIC_PAIRING_EVENT_REPORTED, "", handle,
- HCI_READ_ENCR_KEY_SIZE, HCI_COMMAND_COMPLETE_EVT, status, 0, key_size);
- if (ret < 0) {
- LOG(WARNING) << __func__ << ": failed to log encryption key size "
- << std::to_string(key_size);
- }
-
if (status != HCI_SUCCESS) {
LOG(INFO) << __func__ << ": disconnecting, status: " << loghex(status);
btsnd_hcic_disconnect(handle, HCI_ERR_PEER_USER);
@@ -868,7 +1266,6 @@
*
******************************************************************************/
static void btu_hcif_esco_connection_comp_evt(uint8_t* p) {
-#if (BTM_SCO_INCLUDED == TRUE)
tBTM_ESCO_DATA data;
uint16_t handle;
RawAddress bda;
@@ -885,9 +1282,10 @@
STREAM_TO_UINT16(data.tx_pkt_len, p);
STREAM_TO_UINT8(data.air_mode, p);
+ handle = HCID_GET_HANDLE(handle);
+
data.bd_addr = bda;
btm_sco_connected(status, &bda, handle, &data);
-#endif
}
/*******************************************************************************
@@ -900,7 +1298,6 @@
*
******************************************************************************/
static void btu_hcif_esco_connection_chg_evt(uint8_t* p) {
-#if (BTM_SCO_INCLUDED == TRUE)
uint16_t handle;
uint16_t tx_pkt_len;
uint16_t rx_pkt_len;
@@ -916,9 +1313,10 @@
STREAM_TO_UINT16(rx_pkt_len, p);
STREAM_TO_UINT16(tx_pkt_len, p);
+ handle = HCID_GET_HANDLE(handle);
+
btm_esco_proc_conn_chg(status, handle, tx_interval, retrans_window,
rx_pkt_len, tx_pkt_len);
-#endif
}
/*******************************************************************************
@@ -983,18 +1381,6 @@
break;
/* BLE Commands sComplete*/
- case HCI_BLE_ADD_WHITE_LIST:
- btm_ble_add_2_white_list_complete(*p);
- break;
-
- case HCI_BLE_CLEAR_WHITE_LIST:
- btm_ble_clear_white_list_complete(p, evt_len);
- break;
-
- case HCI_BLE_REMOVE_WHITE_LIST:
- btm_ble_remove_from_white_list_complete(p, evt_len);
- break;
-
case HCI_BLE_RAND:
case HCI_BLE_ENCRYPT:
btm_ble_rand_enc_complete(p, opcode, (tBTM_RAND_ENC_CB*)p_cplt_cback);
@@ -1065,23 +1451,23 @@
static void btu_hcif_command_complete_evt_on_task(BT_HDR* event,
void* context) {
command_opcode_t opcode;
- uint8_t* stream =
- event->data + event->offset +
- 3; // 2 to skip the event headers, 1 to skip the command credits
+ // 2 for event header: event code (1) + parameter length (1)
+ // 1 for num_hci_pkt command credit
+ uint8_t* stream = event->data + event->offset + 3;
STREAM_TO_UINT16(opcode, stream);
- btu_hcif_hdl_command_complete(
- opcode, stream,
- event->len -
- 5, // 3 for the command complete headers, 2 for the event headers
- context);
+ btu_hcif_log_command_complete_metrics(opcode, stream);
+ // 2 for event header: event code (1) + parameter length (1)
+ // 3 for command complete header: num_hci_pkt (1) + opcode (2)
+ uint16_t param_len = static_cast<uint16_t>(event->len - 5);
+ btu_hcif_hdl_command_complete(opcode, stream, param_len, context);
osi_free(event);
}
static void btu_hcif_command_complete_evt(BT_HDR* response, void* context) {
- do_in_hci_thread(FROM_HERE, base::Bind(btu_hcif_command_complete_evt_on_task,
- response, context));
+ do_in_main_thread(FROM_HERE, base::Bind(btu_hcif_command_complete_evt_on_task,
+ response, context));
}
/*******************************************************************************
@@ -1096,27 +1482,107 @@
static void btu_hcif_hdl_command_status(uint16_t opcode, uint8_t status,
uint8_t* p_cmd,
void* p_vsc_status_cback) {
+ CHECK_NE(p_cmd, nullptr) << "Null command for opcode 0x" << loghex(opcode);
+ p_cmd++; // Skip parameter total length
+
RawAddress bd_addr;
uint16_t handle;
-#if (BTM_SCO_INCLUDED == TRUE)
- tBTM_ESCO_DATA esco_data;
-#endif
switch (opcode) {
- case HCI_EXIT_SNIFF_MODE:
- case HCI_EXIT_PARK_MODE:
-#if (BTM_SCO_WAKE_PARKED_LINK == TRUE)
+ // Link Control Commands
+ case HCI_INQUIRY:
if (status != HCI_SUCCESS) {
- /* Allow SCO initiation to continue if waiting for change mode event */
- if (p_cmd != NULL) {
- p_cmd++; /* bypass length field */
- STREAM_TO_UINT16(handle, p_cmd);
- btm_sco_chk_pend_unpark(status, handle);
+ // Tell inquiry processing that we are done
+ btm_process_inq_complete(status, BTM_BR_INQUIRY_MASK);
+ }
+ break;
+ case HCI_QOS_SETUP:
+ if (status != HCI_SUCCESS) {
+ // Tell qos setup that we are done
+ btm_qos_setup_complete(status, 0, nullptr);
+ }
+ break;
+ case HCI_SWITCH_ROLE:
+ if (status != HCI_SUCCESS) {
+ // Tell BTM that the command failed
+ STREAM_TO_BDADDR(bd_addr, p_cmd);
+ btm_acl_role_changed(status, &bd_addr, BTM_ROLE_UNDEFINED);
+ l2c_link_role_changed(nullptr, BTM_ROLE_UNDEFINED,
+ HCI_ERR_COMMAND_DISALLOWED);
+ }
+ break;
+ case HCI_CREATE_CONNECTION:
+ if (status != HCI_SUCCESS) {
+ STREAM_TO_BDADDR(bd_addr, p_cmd);
+ btm_sec_connected(bd_addr, HCI_INVALID_HANDLE, status, 0);
+ l2c_link_hci_conn_comp(status, HCI_INVALID_HANDLE, bd_addr);
+ }
+ break;
+ case HCI_AUTHENTICATION_REQUESTED:
+ if (status != HCI_SUCCESS) {
+ // Device refused to start authentication
+ // This is treated as an authentication failure
+ btm_sec_auth_complete(BTM_INVALID_HCI_HANDLE, status);
+ }
+ break;
+ case HCI_SET_CONN_ENCRYPTION:
+ if (status != HCI_SUCCESS) {
+ // Device refused to start encryption
+ // This is treated as an encryption failure
+ btm_sec_encrypt_change(BTM_INVALID_HCI_HANDLE, status, false);
+ }
+ break;
+ case HCI_RMT_NAME_REQUEST:
+ if (status != HCI_SUCCESS) {
+ // Tell inquiry processing that we are done
+ btm_process_remote_name(nullptr, nullptr, 0, status);
+ btm_sec_rmt_name_request_complete(nullptr, nullptr, status);
+ }
+ break;
+ case HCI_READ_RMT_EXT_FEATURES:
+ if (status != HCI_SUCCESS) {
+ STREAM_TO_UINT16(handle, p_cmd);
+ btm_read_remote_ext_features_failed(status, handle);
+ }
+ break;
+ case HCI_SETUP_ESCO_CONNECTION:
+ case HCI_ENH_SETUP_ESCO_CONNECTION:
+ if (status != HCI_SUCCESS) {
+ STREAM_TO_UINT16(handle, p_cmd);
+ // Determine if initial connection failed or is a change of setup
+ if (btm_is_sco_active(handle)) {
+ btm_esco_proc_conn_chg(status, handle, 0, 0, 0, 0);
+ } else {
+ btm_sco_connected(status, nullptr, handle, nullptr);
}
}
-#endif
- /* Case Falls Through */
+ break;
+ // BLE Commands
+ case HCI_BLE_CREATE_LL_CONN:
+ case HCI_LE_EXTENDED_CREATE_CONNECTION:
+ if (status != HCI_SUCCESS) {
+ btm_ble_create_ll_conn_complete(status);
+ }
+ break;
+ case HCI_BLE_START_ENC:
+ // Race condition: disconnection happened right before we send
+ // "LE Encrypt", controller responds with no connection, we should
+ // cancel the encryption attempt, rather than unpair the device.
+ if (status == HCI_ERR_NO_CONNECTION) {
+ smp_cancel_start_encryption_attempt();
+ }
+ break;
+
+ // Link Policy Commands
+ case HCI_EXIT_SNIFF_MODE:
+ case HCI_EXIT_PARK_MODE:
+ if (status != HCI_SUCCESS) {
+ // Allow SCO initiation to continue if waiting for change mode event
+ STREAM_TO_UINT16(handle, p_cmd);
+ btm_sco_chk_pend_unpark(status, handle);
+ }
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case HCI_HOLD_MODE:
case HCI_SNIFF_MODE:
case HCI_PARK_MODE:
@@ -1124,112 +1590,9 @@
break;
default:
- /* If command failed to start, we may need to tell BTM */
- if (status != HCI_SUCCESS) {
- switch (opcode) {
- case HCI_INQUIRY:
- /* Tell inquiry processing that we are done */
- btm_process_inq_complete(status, BTM_BR_INQUIRY_MASK);
- break;
-
- case HCI_RMT_NAME_REQUEST:
- /* Tell inquiry processing that we are done */
- btm_process_remote_name(NULL, NULL, 0, status);
-
- btm_sec_rmt_name_request_complete(NULL, NULL, status);
- break;
-
- case HCI_QOS_SETUP_COMP_EVT:
- /* Tell qos setup that we are done */
- btm_qos_setup_complete(status, 0, NULL);
- break;
-
- case HCI_SWITCH_ROLE:
- /* Tell BTM that the command failed */
- /* read bd addr out of stored command */
- if (p_cmd != NULL) {
- p_cmd++;
- STREAM_TO_BDADDR(bd_addr, p_cmd);
- btm_acl_role_changed(status, &bd_addr, BTM_ROLE_UNDEFINED);
- } else
- btm_acl_role_changed(status, NULL, BTM_ROLE_UNDEFINED);
- l2c_link_role_changed(nullptr, BTM_ROLE_UNDEFINED,
- HCI_ERR_COMMAND_DISALLOWED);
- break;
-
- case HCI_CREATE_CONNECTION:
- /* read bd addr out of stored command */
- if (p_cmd != NULL) {
- p_cmd++;
- STREAM_TO_BDADDR(bd_addr, p_cmd);
- btm_sec_connected(bd_addr, HCI_INVALID_HANDLE, status, 0);
- l2c_link_hci_conn_comp(status, HCI_INVALID_HANDLE, bd_addr);
- }
- break;
-
- case HCI_READ_RMT_EXT_FEATURES:
- if (p_cmd != NULL) {
- p_cmd++; /* skip command length */
- STREAM_TO_UINT16(handle, p_cmd);
- } else
- handle = HCI_INVALID_HANDLE;
-
- btm_read_remote_ext_features_failed(status, handle);
- break;
-
- case HCI_AUTHENTICATION_REQUESTED:
- /* Device refused to start authentication. That should be treated
- * as authentication failure. */
- btm_sec_auth_complete(BTM_INVALID_HCI_HANDLE, status);
- break;
-
- case HCI_SET_CONN_ENCRYPTION:
- /* Device refused to start encryption. That should be treated as
- * encryption failure. */
- btm_sec_encrypt_change(BTM_INVALID_HCI_HANDLE, status, false);
- break;
-
- case HCI_BLE_CREATE_LL_CONN:
- case HCI_LE_EXTENDED_CREATE_CONNECTION:
- btm_ble_create_ll_conn_complete(status);
- break;
-
-#if (BTM_SCO_INCLUDED == TRUE)
- case HCI_SETUP_ESCO_CONNECTION:
- case HCI_ENH_SETUP_ESCO_CONNECTION:
- /* read handle out of stored command */
- if (p_cmd != NULL) {
- p_cmd++;
- STREAM_TO_UINT16(handle, p_cmd);
-
- /* Determine if initial connection failed or is a change
- * of setup */
- if (btm_is_sco_active(handle))
- btm_esco_proc_conn_chg(status, handle, 0, 0, 0, 0);
- else
- btm_sco_connected(status, NULL, handle, &esco_data);
- }
- break;
-#endif
-
- /* This is commented out until an upper layer cares about returning
- event
- #if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
- case HCI_ENHANCED_FLUSH:
- break;
- #endif
- */
- default:
- if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC)
- btm_vsc_complete(&status, opcode, 1,
- (tBTM_VSC_CMPL_CB*)p_vsc_status_cback);
- break;
- }
-
- } else {
- if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC)
- btm_vsc_complete(&status, opcode, 1,
- (tBTM_VSC_CMPL_CB*)p_vsc_status_cback);
+ if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC) {
+ btm_vsc_complete(&status, opcode, 1,
+ (tBTM_VSC_CMPL_CB*)p_vsc_status_cback);
}
}
}
@@ -1249,14 +1612,18 @@
uint8_t* stream = event->data + event->offset;
STREAM_TO_UINT16(opcode, stream);
+ // stream + 1 to skip parameter length field
+ // No need to check length since stream is written by us
+ btu_hcif_log_command_metrics(opcode, stream + 1, status, true);
+
btu_hcif_hdl_command_status(opcode, status, stream, context);
osi_free(event);
}
static void btu_hcif_command_status_evt(uint8_t status, BT_HDR* command,
void* context) {
- do_in_hci_thread(FROM_HERE, base::Bind(btu_hcif_command_status_evt_on_task,
- status, command, context));
+ do_in_main_thread(FROM_HERE, base::Bind(btu_hcif_command_status_evt_on_task,
+ status, command, context));
}
/*******************************************************************************
@@ -1349,9 +1716,7 @@
STREAM_TO_UINT16(handle, p);
STREAM_TO_UINT8(current_mode, p);
STREAM_TO_UINT16(interval, p);
-#if (BTM_SCO_WAKE_PARKED_LINK == TRUE)
btm_sco_chk_pend_unpark(status, handle);
-#endif
btm_pm_proc_mode_change(status, handle, current_mode, interval);
#if (HID_DEV_INCLUDED == TRUE && HID_DEV_PM_INCLUDED == TRUE)
@@ -1422,11 +1787,11 @@
******************************************************************************/
static void btu_hcif_link_key_notification_evt(uint8_t* p) {
RawAddress bda;
- LINK_KEY key;
+ Octet16 key;
uint8_t key_type;
STREAM_TO_BDADDR(bda, p);
- STREAM_TO_ARRAY16(key, p);
+ STREAM_TO_ARRAY16(key.data(), p);
STREAM_TO_UINT8(key_type, p);
btm_sec_link_key_notification(bda, key, key_type);
@@ -1686,14 +2051,6 @@
static void read_encryption_key_size_complete_after_key_refresh(
uint8_t status, uint16_t handle, uint8_t key_size) {
- int ret = android::util::stats_write(
- android::util::BLUETOOTH_CLASSIC_PAIRING_EVENT_REPORTED, "", handle,
- HCI_READ_ENCR_KEY_SIZE, HCI_COMMAND_COMPLETE_EVT, status, 0, key_size);
- if (ret < 0) {
- LOG(WARNING) << __func__ << ": failed to log encryption key size "
- << std::to_string(key_size);
- }
-
if (status != HCI_SUCCESS) {
LOG(INFO) << __func__ << ": disconnecting, status: " << loghex(status);
btsnd_hcic_disconnect(handle, HCI_ERR_PEER_USER);
diff --git a/stack/btu/btu_init.cc b/stack/btu/btu_init.cc
index cad79df..e6e5a74 100644
--- a/stack/btu/btu_init.cc
+++ b/stack/btu/btu_init.cc
@@ -25,6 +25,7 @@
#include "bt_target.h"
#include "btm_int.h"
#include "btu.h"
+#include "common/message_loop_thread.h"
#include "device/include/controller.h"
#include "gatt_api.h"
#include "gatt_int.h"
@@ -32,20 +33,12 @@
#include "osi/include/alarm.h"
#include "osi/include/fixed_queue.h"
#include "osi/include/log.h"
-#include "osi/include/thread.h"
#include "sdpint.h"
#include "smp_int.h"
-// RT priority for audio-related tasks
-#define BTU_TASK_RT_PRIORITY 1
+using bluetooth::common::MessageLoopThread;
-// Communication queue from hci thread to bt_workqueue.
-extern fixed_queue_t* btu_hci_msg_queue;
-
-thread_t* bt_workqueue_thread;
-static const char* BT_WORKQUEUE_NAME = "bt_workqueue";
-
-extern void PLATFORM_DisableHciTransport(uint8_t bDisable);
+MessageLoopThread bt_startup_thread("bt_startup_thread");
void btu_task_start_up(void* context);
void btu_task_shut_down(void* context);
@@ -60,7 +53,7 @@
* Returns void
*
*****************************************************************************/
-void btu_init_core(void) {
+void btu_init_core() {
/* Initialize the mandatory core stack components */
btm_init();
@@ -85,7 +78,7 @@
* Returns void
*
*****************************************************************************/
-void btu_free_core(void) {
+void btu_free_core() {
/* Free the mandatory core stack components */
gatt_free();
@@ -108,29 +101,25 @@
* Returns void
*
*****************************************************************************/
-void BTU_StartUp(void) {
+void BTU_StartUp() {
btu_trace_level = HCI_INITIAL_TRACE_LEVEL;
-
- bt_workqueue_thread = thread_new(BT_WORKQUEUE_NAME);
- if (bt_workqueue_thread == NULL) goto error_exit;
-
- thread_set_rt_priority(bt_workqueue_thread, BTU_TASK_RT_PRIORITY);
-
- // Continue startup on bt workqueue thread.
- thread_post(bt_workqueue_thread, btu_task_start_up, NULL);
- return;
-
-error_exit:;
- LOG_ERROR(LOG_TAG, "%s Unable to allocate resources for bt_workqueue",
- __func__);
- BTU_ShutDown();
+ bt_startup_thread.StartUp();
+ if (!bt_startup_thread.EnableRealTimeScheduling()) {
+ LOG(ERROR) << __func__ << ": Unable to set real time scheduling policy for "
+ << bt_startup_thread;
+ BTU_ShutDown();
+ return;
+ }
+ if (!bt_startup_thread.DoInThread(FROM_HERE,
+ base::Bind(btu_task_start_up, nullptr))) {
+ LOG(ERROR) << __func__ << ": Unable to continue start-up on "
+ << bt_startup_thread;
+ BTU_ShutDown();
+ return;
+ }
}
-void BTU_ShutDown(void) {
- btu_task_shut_down(NULL);
-
-
- thread_free(bt_workqueue_thread);
-
- bt_workqueue_thread = NULL;
+void BTU_ShutDown() {
+ btu_task_shut_down(nullptr);
+ bt_startup_thread.ShutDown();
}
diff --git a/stack/btu/btu_task.cc b/stack/btu/btu_task.cc
index 7d2527a..49c9697 100644
--- a/stack/btu/btu_task.cc
+++ b/stack/btu/btu_task.cc
@@ -23,31 +23,27 @@
#include <stdlib.h>
#include <string.h>
+#include "bta/sys/bta_sys.h"
+#include "btcore/include/module.h"
+#include "bte.h"
+#include "btif/include/btif_common.h"
+#include "common/message_loop_thread.h"
+#include "osi/include/osi.h"
+#include "stack/btm/btm_int.h"
+#include "stack/include/btu.h"
+#include "stack/l2cap/l2c_int.h"
+
#include <base/bind.h>
#include <base/logging.h>
#include <base/run_loop.h>
#include <base/threading/thread.h>
-#include "bta/sys/bta_sys.h"
-#include "btcore/include/module.h"
-#include "bte.h"
-#include "btif/include/btif_common.h"
-#include "osi/include/osi.h"
-#include "osi/include/thread.h"
-#include "stack/btm/btm_int.h"
-#include "stack/include/btu.h"
-#include "stack/l2cap/l2c_int.h"
-
-static const int THREAD_RT_PRIORITY = 1;
+using bluetooth::common::MessageLoopThread;
/* Define BTU storage area */
uint8_t btu_trace_level = HCI_INITIAL_TRACE_LEVEL;
-extern thread_t* bt_workqueue_thread;
-
-static base::MessageLoop* message_loop_ = NULL;
-static base::RunLoop* run_loop_ = NULL;
-static thread_t* message_loop_thread_;
+static MessageLoopThread main_thread("bt_main_thread");
void btu_hci_msg_process(BT_HDR* p_msg) {
/* Determine the input message type. */
@@ -63,10 +59,8 @@
break;
case BT_EVT_TO_BTU_HCI_SCO:
-#if (BTM_SCO_INCLUDED == TRUE)
btm_route_sco_data(p_msg);
break;
-#endif
case BT_EVT_TO_BTU_HCI_EVT:
btu_hcif_process_event((uint8_t)(p_msg->event & BT_SUB_EVT_MASK), p_msg);
@@ -83,24 +77,19 @@
}
}
-base::MessageLoop* get_message_loop() { return message_loop_; }
+bluetooth::common::MessageLoopThread* get_main_thread() { return &main_thread; }
-void btu_message_loop_run(UNUSED_ATTR void* context) {
- message_loop_ = new base::MessageLoop();
- run_loop_ = new base::RunLoop();
+base::MessageLoop* get_main_message_loop() {
+ return main_thread.message_loop();
+}
- // Inform the bt jni thread initialization is ok.
- message_loop_->task_runner()->PostTask(
- FROM_HERE, base::Bind(base::IgnoreResult(&btif_transfer_context),
- btif_init_ok, 0, nullptr, 0, nullptr));
-
- run_loop_->Run();
-
- delete message_loop_;
- message_loop_ = NULL;
-
- delete run_loop_;
- run_loop_ = NULL;
+bt_status_t do_in_main_thread(const base::Location& from_here,
+ base::OnceClosure task) {
+ if (!main_thread.DoInThread(from_here, std::move(task))) {
+ LOG(ERROR) << __func__ << ": failed from " << from_here.ToString();
+ return BT_STATUS_FAIL;
+ }
+ return BT_STATUS_SUCCESS;
}
void btu_task_start_up(UNUSED_ATTR void* context) {
@@ -123,21 +112,22 @@
*/
module_init(get_module(BTE_LOGMSG_MODULE));
- message_loop_thread_ = thread_new("btu message loop");
- if (!message_loop_thread_) {
- LOG(FATAL) << __func__ << " unable to create btu message loop thread.";
+ main_thread.StartUp();
+ if (!main_thread.IsRunning()) {
+ LOG(FATAL) << __func__ << ": unable to start btu message loop thread.";
}
-
- thread_set_rt_priority(message_loop_thread_, THREAD_RT_PRIORITY);
- thread_post(message_loop_thread_, btu_message_loop_run, nullptr);
-
+ if (!main_thread.EnableRealTimeScheduling()) {
+ LOG(FATAL) << __func__ << ": unable to enable real time scheduling";
+ }
+ if (do_in_jni_thread(FROM_HERE, base::Bind(btif_init_ok, 0, nullptr)) !=
+ BT_STATUS_SUCCESS) {
+ LOG(FATAL) << __func__ << ": unable to continue starting Bluetooth";
+ }
}
void btu_task_shut_down(UNUSED_ATTR void* context) {
// Shutdown message loop on task completed
- if (run_loop_ && message_loop_) {
- message_loop_->task_runner()->PostTask(FROM_HERE, run_loop_->QuitClosure());
- }
+ main_thread.ShutDown();
module_clean_up(get_module(BTE_LOGMSG_MODULE));
diff --git a/stack/crypto_toolbox/aes.cc b/stack/crypto_toolbox/aes.cc
new file mode 100644
index 0000000..f53894e
--- /dev/null
+++ b/stack/crypto_toolbox/aes.cc
@@ -0,0 +1,950 @@
+/*
+ ---------------------------------------------------------------------------
+ Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.
+
+ LICENSE TERMS
+
+ The redistribution and use of this software (with or without changes)
+ is allowed without the payment of fees or royalties provided that:
+
+ 1. source code distributions include the above copyright notice, this
+ list of conditions and the following disclaimer;
+
+ 2. binary distributions include the above copyright notice, this list
+ of conditions and the following disclaimer in their documentation;
+
+ 3. the name of the copyright holder is not used to endorse products
+ built using this software without specific written permission.
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness
+ and/or fitness for purpose.
+ ---------------------------------------------------------------------------
+ Issue 09/09/2006
+
+ This is an AES implementation that uses only 8-bit byte operations on the
+ cipher state (there are options to use 32-bit types if available).
+
+ The combination of mix columns and byte substitution used here is based on
+ that developed by Karl Malbrain. His contribution is acknowledged.
+ */
+
+/* define if you have a fast memcpy function on your system */
+#if 1
+#define HAVE_MEMCPY
+#include <string.h>
+#if 0
+#if defined(_MSC_VER)
+#include <intrin.h>
+#pragma intrinsic(memcpy)
+#endif
+#endif
+#endif
+
+#include <stdint.h>
+#include <stdlib.h>
+
+/* define if you have fast 32-bit types on your system */
+#if 1
+#define HAVE_UINT_32T
+#endif
+
+/* define if you don't want any tables */
+#if 1
+#define USE_TABLES
+#endif
+
+/* On Intel Core 2 duo VERSION_1 is faster */
+
+/* alternative versions (test for performance on your system) */
+#if 1
+#define VERSION_1
+#endif
+
+#include "aes.h"
+
+#if defined(HAVE_UINT_32T)
+typedef uint32_t uint_32t;
+#endif
+
+/* functions for finite field multiplication in the AES Galois field */
+
+#define WPOLY 0x011b
+#define BPOLY 0x1b
+#define DPOLY 0x008d
+
+#define f1(x) (x)
+#define f2(x) (((x) << 1) ^ ((((x) >> 7) & 1) * WPOLY))
+#define f4(x) \
+ (((x) << 2) ^ ((((x) >> 6) & 1) * WPOLY) ^ ((((x) >> 6) & 2) * WPOLY))
+#define f8(x) \
+ (((x) << 3) ^ ((((x) >> 5) & 1) * WPOLY) ^ ((((x) >> 5) & 2) * WPOLY) ^ \
+ ((((x) >> 5) & 4) * WPOLY))
+#define d2(x) (((x) >> 1) ^ ((x)&1 ? DPOLY : 0))
+
+#define f3(x) (f2(x) ^ (x))
+#define f9(x) (f8(x) ^ (x))
+#define fb(x) (f8(x) ^ f2(x) ^ (x))
+#define fd(x) (f8(x) ^ f4(x) ^ (x))
+#define fe(x) (f8(x) ^ f4(x) ^ f2(x))
+
+#if defined(USE_TABLES)
+
+#define sb_data(w) \
+ { /* S Box data values */ \
+ w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5), \
+ w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), \
+ w(0x76), w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), \
+ w(0x47), w(0xf0), w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), \
+ w(0xa4), w(0x72), w(0xc0), w(0xb7), w(0xfd), w(0x93), w(0x26), \
+ w(0x36), w(0x3f), w(0xf7), w(0xcc), w(0x34), w(0xa5), w(0xe5), \
+ w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15), w(0x04), w(0xc7), \
+ w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a), w(0x07), \
+ w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75), \
+ w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), \
+ w(0xa0), w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), \
+ w(0x2f), w(0x84), w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), \
+ w(0xfc), w(0xb1), w(0x5b), w(0x6a), w(0xcb), w(0xbe), w(0x39), \
+ w(0x4a), w(0x4c), w(0x58), w(0xcf), w(0xd0), w(0xef), w(0xaa), \
+ w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85), w(0x45), w(0xf9), \
+ w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8), w(0x51), \
+ w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5), \
+ w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), \
+ w(0xd2), w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), \
+ w(0x44), w(0x17), w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), \
+ w(0x5d), w(0x19), w(0x73), w(0x60), w(0x81), w(0x4f), w(0xdc), \
+ w(0x22), w(0x2a), w(0x90), w(0x88), w(0x46), w(0xee), w(0xb8), \
+ w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb), w(0xe0), w(0x32), \
+ w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c), w(0xc2), \
+ w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79), \
+ w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), \
+ w(0xa9), w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), \
+ w(0xae), w(0x08), w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), \
+ w(0xa6), w(0xb4), w(0xc6), w(0xe8), w(0xdd), w(0x74), w(0x1f), \
+ w(0x4b), w(0xbd), w(0x8b), w(0x8a), w(0x70), w(0x3e), w(0xb5), \
+ w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e), w(0x61), w(0x35), \
+ w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e), w(0xe1), \
+ w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94), \
+ w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), \
+ w(0xdf), w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), \
+ w(0x42), w(0x68), w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), \
+ w(0x54), w(0xbb), w(0x16) \
+ }
+
+#define isb_data(w) \
+ { /* inverse S Box data values */ \
+ w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38), \
+ w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), \
+ w(0xfb), w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), \
+ w(0xff), w(0x87), w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), \
+ w(0xde), w(0xe9), w(0xcb), w(0x54), w(0x7b), w(0x94), w(0x32), \
+ w(0xa6), w(0xc2), w(0x23), w(0x3d), w(0xee), w(0x4c), w(0x95), \
+ w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e), w(0x08), w(0x2e), \
+ w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2), w(0x76), \
+ w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25), \
+ w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), \
+ w(0x16), w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), \
+ w(0xb6), w(0x92), w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), \
+ w(0xed), w(0xb9), w(0xda), w(0x5e), w(0x15), w(0x46), w(0x57), \
+ w(0xa7), w(0x8d), w(0x9d), w(0x84), w(0x90), w(0xd8), w(0xab), \
+ w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a), w(0xf7), w(0xe4), \
+ w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06), w(0xd0), \
+ w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02), \
+ w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), \
+ w(0x6b), w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), \
+ w(0xdc), w(0xea), w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), \
+ w(0xb4), w(0xe6), w(0x73), w(0x96), w(0xac), w(0x74), w(0x22), \
+ w(0xe7), w(0xad), w(0x35), w(0x85), w(0xe2), w(0xf9), w(0x37), \
+ w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e), w(0x47), w(0xf1), \
+ w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89), w(0x6f), \
+ w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b), \
+ w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), \
+ w(0x20), w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), \
+ w(0x5a), w(0xf4), w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), \
+ w(0x07), w(0xc7), w(0x31), w(0xb1), w(0x12), w(0x10), w(0x59), \
+ w(0x27), w(0x80), w(0xec), w(0x5f), w(0x60), w(0x51), w(0x7f), \
+ w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d), w(0x2d), w(0xe5), \
+ w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef), w(0xa0), \
+ w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0), \
+ w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), \
+ w(0x61), w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), \
+ w(0xd6), w(0x26), w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), \
+ w(0x21), w(0x0c), w(0x7d) \
+ }
+
+#define mm_data(w) \
+ { /* basic data for forming finite field tables */ \
+ w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07), \
+ w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), \
+ w(0x0f), w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), \
+ w(0x16), w(0x17), w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), \
+ w(0x1d), w(0x1e), w(0x1f), w(0x20), w(0x21), w(0x22), w(0x23), \
+ w(0x24), w(0x25), w(0x26), w(0x27), w(0x28), w(0x29), w(0x2a), \
+ w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f), w(0x30), w(0x31), \
+ w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37), w(0x38), \
+ w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f), \
+ w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), \
+ w(0x47), w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), \
+ w(0x4e), w(0x4f), w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), \
+ w(0x55), w(0x56), w(0x57), w(0x58), w(0x59), w(0x5a), w(0x5b), \
+ w(0x5c), w(0x5d), w(0x5e), w(0x5f), w(0x60), w(0x61), w(0x62), \
+ w(0x63), w(0x64), w(0x65), w(0x66), w(0x67), w(0x68), w(0x69), \
+ w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f), w(0x70), \
+ w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77), \
+ w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), \
+ w(0x7f), w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), \
+ w(0x86), w(0x87), w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), \
+ w(0x8d), w(0x8e), w(0x8f), w(0x90), w(0x91), w(0x92), w(0x93), \
+ w(0x94), w(0x95), w(0x96), w(0x97), w(0x98), w(0x99), w(0x9a), \
+ w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f), w(0xa0), w(0xa1), \
+ w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7), w(0xa8), \
+ w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf), \
+ w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), \
+ w(0xb7), w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), \
+ w(0xbe), w(0xbf), w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), \
+ w(0xc5), w(0xc6), w(0xc7), w(0xc8), w(0xc9), w(0xca), w(0xcb), \
+ w(0xcc), w(0xcd), w(0xce), w(0xcf), w(0xd0), w(0xd1), w(0xd2), \
+ w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7), w(0xd8), w(0xd9), \
+ w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf), w(0xe0), \
+ w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7), \
+ w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), \
+ w(0xef), w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), \
+ w(0xf6), w(0xf7), w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), \
+ w(0xfd), w(0xfe), w(0xff) \
+ }
+
+static const uint_8t sbox[256] = sb_data(f1);
+static const uint_8t isbox[256] = isb_data(f1);
+
+static const uint_8t gfm2_sbox[256] = sb_data(f2);
+static const uint_8t gfm3_sbox[256] = sb_data(f3);
+
+static const uint_8t gfmul_9[256] = mm_data(f9);
+static const uint_8t gfmul_b[256] = mm_data(fb);
+static const uint_8t gfmul_d[256] = mm_data(fd);
+static const uint_8t gfmul_e[256] = mm_data(fe);
+
+#define s_box(x) sbox[(x)]
+#define is_box(x) isbox[(x)]
+#define gfm2_sb(x) gfm2_sbox[(x)]
+#define gfm3_sb(x) gfm3_sbox[(x)]
+#define gfm_9(x) gfmul_9[(x)]
+#define gfm_b(x) gfmul_b[(x)]
+#define gfm_d(x) gfmul_d[(x)]
+#define gfm_e(x) gfmul_e[(x)]
+
+#else
+
+/* this is the high bit of x right shifted by 1 */
+/* position. Since the starting polynomial has */
+/* 9 bits (0x11b), this right shift keeps the */
+/* values of all top bits within a byte */
+
+static uint_8t hibit(const uint_8t x) {
+ uint_8t r = (uint_8t)((x >> 1) | (x >> 2));
+
+ r |= (r >> 2);
+ r |= (r >> 4);
+ return (r + 1) >> 1;
+}
+
+/* return the inverse of the finite field element x */
+
+static uint_8t gf_inv(const uint_8t x) {
+ uint_8t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0;
+
+ if (x < 2) return x;
+
+ for (;;) {
+ if (n1)
+ while (n2 >= n1) /* divide polynomial p2 by p1 */
+ {
+ n2 /= n1; /* shift smaller polynomial left */
+ p2 ^= (p1 * n2) & 0xff; /* and remove from larger one */
+ v2 ^= (v1 * n2); /* shift accumulated value and */
+ n2 = hibit(p2); /* add into result */
+ }
+ else
+ return v1;
+
+ if (n2) /* repeat with values swapped */
+ while (n1 >= n2) {
+ n1 /= n2;
+ p1 ^= p2 * n1;
+ v1 ^= v2 * n1;
+ n1 = hibit(p1);
+ }
+ else
+ return v2;
+ }
+}
+
+/* The forward and inverse affine transformations used in the S-box */
+uint_8t fwd_affine(const uint_8t x) {
+#if defined(HAVE_UINT_32T)
+ uint_32t w = x;
+ w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4);
+ return 0x63 ^ ((w ^ (w >> 8)) & 0xff);
+#else
+ return 0x63 ^ x ^ (x << 1) ^ (x << 2) ^ (x << 3) ^ (x << 4) ^ (x >> 7) ^
+ (x >> 6) ^ (x >> 5) ^ (x >> 4);
+#endif
+}
+
+uint_8t inv_affine(const uint_8t x) {
+#if defined(HAVE_UINT_32T)
+ uint_32t w = x;
+ w = (w << 1) ^ (w << 3) ^ (w << 6);
+ return 0x05 ^ ((w ^ (w >> 8)) & 0xff);
+#else
+ return 0x05 ^ (x << 1) ^ (x << 3) ^ (x << 6) ^ (x >> 7) ^ (x >> 5) ^ (x >> 2);
+#endif
+}
+
+#define s_box(x) fwd_affine(gf_inv(x))
+#define is_box(x) gf_inv(inv_affine(x))
+#define gfm2_sb(x) f2(s_box(x))
+#define gfm3_sb(x) f3(s_box(x))
+#define gfm_9(x) f9(x)
+#define gfm_b(x) fb(x)
+#define gfm_d(x) fd(x)
+#define gfm_e(x) fe(x)
+
+#endif
+
+#if defined(HAVE_MEMCPY)
+#define block_copy_nn(d, s, l) memcpy(d, s, l)
+#define block_copy(d, s) memcpy(d, s, N_BLOCK)
+#else
+#define block_copy_nn(d, s, l) copy_block_nn(d, s, l)
+#define block_copy(d, s) copy_block(d, s)
+#endif
+
+#if !defined(HAVE_MEMCPY)
+static void copy_block(void* d, const void* s) {
+#if defined(HAVE_UINT_32T)
+ ((uint_32t*)d)[0] = ((uint_32t*)s)[0];
+ ((uint_32t*)d)[1] = ((uint_32t*)s)[1];
+ ((uint_32t*)d)[2] = ((uint_32t*)s)[2];
+ ((uint_32t*)d)[3] = ((uint_32t*)s)[3];
+#else
+ ((uint_8t*)d)[0] = ((uint_8t*)s)[0];
+ ((uint_8t*)d)[1] = ((uint_8t*)s)[1];
+ ((uint_8t*)d)[2] = ((uint_8t*)s)[2];
+ ((uint_8t*)d)[3] = ((uint_8t*)s)[3];
+ ((uint_8t*)d)[4] = ((uint_8t*)s)[4];
+ ((uint_8t*)d)[5] = ((uint_8t*)s)[5];
+ ((uint_8t*)d)[6] = ((uint_8t*)s)[6];
+ ((uint_8t*)d)[7] = ((uint_8t*)s)[7];
+ ((uint_8t*)d)[8] = ((uint_8t*)s)[8];
+ ((uint_8t*)d)[9] = ((uint_8t*)s)[9];
+ ((uint_8t*)d)[10] = ((uint_8t*)s)[10];
+ ((uint_8t*)d)[11] = ((uint_8t*)s)[11];
+ ((uint_8t*)d)[12] = ((uint_8t*)s)[12];
+ ((uint_8t*)d)[13] = ((uint_8t*)s)[13];
+ ((uint_8t*)d)[14] = ((uint_8t*)s)[14];
+ ((uint_8t*)d)[15] = ((uint_8t*)s)[15];
+#endif
+}
+
+static void copy_block_nn(void* d, const void* s, uint_8t nn) {
+ while (nn--) *((uint_8t*)d)++ = *((uint_8t*)s)++;
+}
+#endif
+
+static void xor_block(void* d, const void* s) {
+#if defined(HAVE_UINT_32T)
+ ((uint_32t*)d)[0] ^= ((uint_32t*)s)[0];
+ ((uint_32t*)d)[1] ^= ((uint_32t*)s)[1];
+ ((uint_32t*)d)[2] ^= ((uint_32t*)s)[2];
+ ((uint_32t*)d)[3] ^= ((uint_32t*)s)[3];
+#else
+ ((uint_8t*)d)[0] ^= ((uint_8t*)s)[0];
+ ((uint_8t*)d)[1] ^= ((uint_8t*)s)[1];
+ ((uint_8t*)d)[2] ^= ((uint_8t*)s)[2];
+ ((uint_8t*)d)[3] ^= ((uint_8t*)s)[3];
+ ((uint_8t*)d)[4] ^= ((uint_8t*)s)[4];
+ ((uint_8t*)d)[5] ^= ((uint_8t*)s)[5];
+ ((uint_8t*)d)[6] ^= ((uint_8t*)s)[6];
+ ((uint_8t*)d)[7] ^= ((uint_8t*)s)[7];
+ ((uint_8t*)d)[8] ^= ((uint_8t*)s)[8];
+ ((uint_8t*)d)[9] ^= ((uint_8t*)s)[9];
+ ((uint_8t*)d)[10] ^= ((uint_8t*)s)[10];
+ ((uint_8t*)d)[11] ^= ((uint_8t*)s)[11];
+ ((uint_8t*)d)[12] ^= ((uint_8t*)s)[12];
+ ((uint_8t*)d)[13] ^= ((uint_8t*)s)[13];
+ ((uint_8t*)d)[14] ^= ((uint_8t*)s)[14];
+ ((uint_8t*)d)[15] ^= ((uint_8t*)s)[15];
+#endif
+}
+
+static void copy_and_key(void* d, const void* s, const void* k) {
+#if defined(HAVE_UINT_32T)
+ ((uint_32t*)d)[0] = ((uint_32t*)s)[0] ^ ((uint_32t*)k)[0];
+ ((uint_32t*)d)[1] = ((uint_32t*)s)[1] ^ ((uint_32t*)k)[1];
+ ((uint_32t*)d)[2] = ((uint_32t*)s)[2] ^ ((uint_32t*)k)[2];
+ ((uint_32t*)d)[3] = ((uint_32t*)s)[3] ^ ((uint_32t*)k)[3];
+#elif 1
+ ((uint_8t*)d)[0] = ((uint_8t*)s)[0] ^ ((uint_8t*)k)[0];
+ ((uint_8t*)d)[1] = ((uint_8t*)s)[1] ^ ((uint_8t*)k)[1];
+ ((uint_8t*)d)[2] = ((uint_8t*)s)[2] ^ ((uint_8t*)k)[2];
+ ((uint_8t*)d)[3] = ((uint_8t*)s)[3] ^ ((uint_8t*)k)[3];
+ ((uint_8t*)d)[4] = ((uint_8t*)s)[4] ^ ((uint_8t*)k)[4];
+ ((uint_8t*)d)[5] = ((uint_8t*)s)[5] ^ ((uint_8t*)k)[5];
+ ((uint_8t*)d)[6] = ((uint_8t*)s)[6] ^ ((uint_8t*)k)[6];
+ ((uint_8t*)d)[7] = ((uint_8t*)s)[7] ^ ((uint_8t*)k)[7];
+ ((uint_8t*)d)[8] = ((uint_8t*)s)[8] ^ ((uint_8t*)k)[8];
+ ((uint_8t*)d)[9] = ((uint_8t*)s)[9] ^ ((uint_8t*)k)[9];
+ ((uint_8t*)d)[10] = ((uint_8t*)s)[10] ^ ((uint_8t*)k)[10];
+ ((uint_8t*)d)[11] = ((uint_8t*)s)[11] ^ ((uint_8t*)k)[11];
+ ((uint_8t*)d)[12] = ((uint_8t*)s)[12] ^ ((uint_8t*)k)[12];
+ ((uint_8t*)d)[13] = ((uint_8t*)s)[13] ^ ((uint_8t*)k)[13];
+ ((uint_8t*)d)[14] = ((uint_8t*)s)[14] ^ ((uint_8t*)k)[14];
+ ((uint_8t*)d)[15] = ((uint_8t*)s)[15] ^ ((uint_8t*)k)[15];
+#else
+ block_copy(d, s);
+ xor_block(d, k);
+#endif
+}
+
+static void add_round_key(uint_8t d[N_BLOCK], const uint_8t k[N_BLOCK]) {
+ xor_block(d, k);
+}
+
+static void shift_sub_rows(uint_8t st[N_BLOCK]) {
+ uint_8t tt;
+
+ st[0] = s_box(st[0]);
+ st[4] = s_box(st[4]);
+ st[8] = s_box(st[8]);
+ st[12] = s_box(st[12]);
+
+ tt = st[1];
+ st[1] = s_box(st[5]);
+ st[5] = s_box(st[9]);
+ st[9] = s_box(st[13]);
+ st[13] = s_box(tt);
+
+ tt = st[2];
+ st[2] = s_box(st[10]);
+ st[10] = s_box(tt);
+ tt = st[6];
+ st[6] = s_box(st[14]);
+ st[14] = s_box(tt);
+
+ tt = st[15];
+ st[15] = s_box(st[11]);
+ st[11] = s_box(st[7]);
+ st[7] = s_box(st[3]);
+ st[3] = s_box(tt);
+}
+
+static void inv_shift_sub_rows(uint_8t st[N_BLOCK]) {
+ uint_8t tt;
+
+ st[0] = is_box(st[0]);
+ st[4] = is_box(st[4]);
+ st[8] = is_box(st[8]);
+ st[12] = is_box(st[12]);
+
+ tt = st[13];
+ st[13] = is_box(st[9]);
+ st[9] = is_box(st[5]);
+ st[5] = is_box(st[1]);
+ st[1] = is_box(tt);
+
+ tt = st[2];
+ st[2] = is_box(st[10]);
+ st[10] = is_box(tt);
+ tt = st[6];
+ st[6] = is_box(st[14]);
+ st[14] = is_box(tt);
+
+ tt = st[3];
+ st[3] = is_box(st[7]);
+ st[7] = is_box(st[11]);
+ st[11] = is_box(st[15]);
+ st[15] = is_box(tt);
+}
+
+#if defined(VERSION_1)
+static void mix_sub_columns(uint_8t dt[N_BLOCK]) {
+ uint_8t st[N_BLOCK];
+ block_copy(st, dt);
+#else
+static void mix_sub_columns(uint_8t dt[N_BLOCK], uint_8t st[N_BLOCK]) {
+#endif
+ dt[0] = gfm2_sb(st[0]) ^ gfm3_sb(st[5]) ^ s_box(st[10]) ^ s_box(st[15]);
+ dt[1] = s_box(st[0]) ^ gfm2_sb(st[5]) ^ gfm3_sb(st[10]) ^ s_box(st[15]);
+ dt[2] = s_box(st[0]) ^ s_box(st[5]) ^ gfm2_sb(st[10]) ^ gfm3_sb(st[15]);
+ dt[3] = gfm3_sb(st[0]) ^ s_box(st[5]) ^ s_box(st[10]) ^ gfm2_sb(st[15]);
+
+ dt[4] = gfm2_sb(st[4]) ^ gfm3_sb(st[9]) ^ s_box(st[14]) ^ s_box(st[3]);
+ dt[5] = s_box(st[4]) ^ gfm2_sb(st[9]) ^ gfm3_sb(st[14]) ^ s_box(st[3]);
+ dt[6] = s_box(st[4]) ^ s_box(st[9]) ^ gfm2_sb(st[14]) ^ gfm3_sb(st[3]);
+ dt[7] = gfm3_sb(st[4]) ^ s_box(st[9]) ^ s_box(st[14]) ^ gfm2_sb(st[3]);
+
+ dt[8] = gfm2_sb(st[8]) ^ gfm3_sb(st[13]) ^ s_box(st[2]) ^ s_box(st[7]);
+ dt[9] = s_box(st[8]) ^ gfm2_sb(st[13]) ^ gfm3_sb(st[2]) ^ s_box(st[7]);
+ dt[10] = s_box(st[8]) ^ s_box(st[13]) ^ gfm2_sb(st[2]) ^ gfm3_sb(st[7]);
+ dt[11] = gfm3_sb(st[8]) ^ s_box(st[13]) ^ s_box(st[2]) ^ gfm2_sb(st[7]);
+
+ dt[12] = gfm2_sb(st[12]) ^ gfm3_sb(st[1]) ^ s_box(st[6]) ^ s_box(st[11]);
+ dt[13] = s_box(st[12]) ^ gfm2_sb(st[1]) ^ gfm3_sb(st[6]) ^ s_box(st[11]);
+ dt[14] = s_box(st[12]) ^ s_box(st[1]) ^ gfm2_sb(st[6]) ^ gfm3_sb(st[11]);
+ dt[15] = gfm3_sb(st[12]) ^ s_box(st[1]) ^ s_box(st[6]) ^ gfm2_sb(st[11]);
+}
+
+#if defined(VERSION_1)
+static void inv_mix_sub_columns(uint_8t dt[N_BLOCK]) {
+ uint_8t st[N_BLOCK];
+ block_copy(st, dt);
+#else
+static void inv_mix_sub_columns(uint_8t dt[N_BLOCK], uint_8t st[N_BLOCK]) {
+#endif
+ dt[0] = is_box(gfm_e(st[0]) ^ gfm_b(st[1]) ^ gfm_d(st[2]) ^ gfm_9(st[3]));
+ dt[5] = is_box(gfm_9(st[0]) ^ gfm_e(st[1]) ^ gfm_b(st[2]) ^ gfm_d(st[3]));
+ dt[10] = is_box(gfm_d(st[0]) ^ gfm_9(st[1]) ^ gfm_e(st[2]) ^ gfm_b(st[3]));
+ dt[15] = is_box(gfm_b(st[0]) ^ gfm_d(st[1]) ^ gfm_9(st[2]) ^ gfm_e(st[3]));
+
+ dt[4] = is_box(gfm_e(st[4]) ^ gfm_b(st[5]) ^ gfm_d(st[6]) ^ gfm_9(st[7]));
+ dt[9] = is_box(gfm_9(st[4]) ^ gfm_e(st[5]) ^ gfm_b(st[6]) ^ gfm_d(st[7]));
+ dt[14] = is_box(gfm_d(st[4]) ^ gfm_9(st[5]) ^ gfm_e(st[6]) ^ gfm_b(st[7]));
+ dt[3] = is_box(gfm_b(st[4]) ^ gfm_d(st[5]) ^ gfm_9(st[6]) ^ gfm_e(st[7]));
+
+ dt[8] = is_box(gfm_e(st[8]) ^ gfm_b(st[9]) ^ gfm_d(st[10]) ^ gfm_9(st[11]));
+ dt[13] = is_box(gfm_9(st[8]) ^ gfm_e(st[9]) ^ gfm_b(st[10]) ^ gfm_d(st[11]));
+ dt[2] = is_box(gfm_d(st[8]) ^ gfm_9(st[9]) ^ gfm_e(st[10]) ^ gfm_b(st[11]));
+ dt[7] = is_box(gfm_b(st[8]) ^ gfm_d(st[9]) ^ gfm_9(st[10]) ^ gfm_e(st[11]));
+
+ dt[12] =
+ is_box(gfm_e(st[12]) ^ gfm_b(st[13]) ^ gfm_d(st[14]) ^ gfm_9(st[15]));
+ dt[1] = is_box(gfm_9(st[12]) ^ gfm_e(st[13]) ^ gfm_b(st[14]) ^ gfm_d(st[15]));
+ dt[6] = is_box(gfm_d(st[12]) ^ gfm_9(st[13]) ^ gfm_e(st[14]) ^ gfm_b(st[15]));
+ dt[11] =
+ is_box(gfm_b(st[12]) ^ gfm_d(st[13]) ^ gfm_9(st[14]) ^ gfm_e(st[15]));
+}
+
+#if defined(AES_ENC_PREKEYED) || defined(AES_DEC_PREKEYED)
+
+/* Set the cipher key for the pre-keyed version */
+/* NOTE: If the length_type used for the key length is an
+ unsigned 8-bit character, a key length of 256 bits must
+ be entered as a length in bytes (valid inputs are hence
+ 128, 192, 16, 24 and 32).
+*/
+
+return_type aes_set_key(const unsigned char key[], length_type keylen,
+ aes_context ctx[1]) {
+ uint_8t cc, rc, hi;
+
+ switch (keylen) {
+ case 16:
+ case 128: /* length in bits (128 = 8*16) */
+ keylen = 16;
+ break;
+ case 24:
+ case 192: /* length in bits (192 = 8*24) */
+ keylen = 24;
+ break;
+ case 32:
+ /* case 256: length in bits (256 = 8*32) */
+ keylen = 32;
+ break;
+ default:
+ ctx->rnd = 0;
+ return (return_type)-1;
+ }
+ block_copy_nn(ctx->ksch, key, keylen);
+ hi = (keylen + 28) << 2;
+ ctx->rnd = (hi >> 4) - 1;
+ for (cc = keylen, rc = 1; cc < hi; cc += 4) {
+ uint_8t tt, t0, t1, t2, t3;
+
+ t0 = ctx->ksch[cc - 4];
+ t1 = ctx->ksch[cc - 3];
+ t2 = ctx->ksch[cc - 2];
+ t3 = ctx->ksch[cc - 1];
+ if (cc % keylen == 0) {
+ tt = t0;
+ t0 = s_box(t1) ^ rc;
+ t1 = s_box(t2);
+ t2 = s_box(t3);
+ t3 = s_box(tt);
+ rc = f2(rc);
+ } else if (keylen > 24 && cc % keylen == 16) {
+ t0 = s_box(t0);
+ t1 = s_box(t1);
+ t2 = s_box(t2);
+ t3 = s_box(t3);
+ }
+ tt = cc - keylen;
+ ctx->ksch[cc + 0] = ctx->ksch[tt + 0] ^ t0;
+ ctx->ksch[cc + 1] = ctx->ksch[tt + 1] ^ t1;
+ ctx->ksch[cc + 2] = ctx->ksch[tt + 2] ^ t2;
+ ctx->ksch[cc + 3] = ctx->ksch[tt + 3] ^ t3;
+ }
+ return 0;
+}
+
+#endif
+
+#if defined(AES_ENC_PREKEYED)
+
+/* Encrypt a single block of 16 bytes */
+
+return_type aes_encrypt(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK], const aes_context ctx[1]) {
+ if (ctx->rnd) {
+ uint_8t s1[N_BLOCK], r;
+ copy_and_key(s1, in, ctx->ksch);
+
+ for (r = 1; r < ctx->rnd; ++r)
+#if defined(VERSION_1)
+ {
+ mix_sub_columns(s1);
+ add_round_key(s1, ctx->ksch + r * N_BLOCK);
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ mix_sub_columns(s2, s1);
+ copy_and_key(s1, s2, ctx->ksch + r * N_BLOCK);
+ }
+#endif
+ shift_sub_rows(s1);
+ copy_and_key(out, s1, ctx->ksch + r * N_BLOCK);
+ } else
+ return (return_type)-1;
+ return 0;
+}
+
+/* CBC encrypt a number of blocks (input and return an IV) */
+
+return_type aes_cbc_encrypt(const unsigned char* in, unsigned char* out,
+ int n_block, unsigned char iv[N_BLOCK],
+ const aes_context ctx[1]) {
+ while (n_block--) {
+ xor_block(iv, in);
+ if (aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE;
+ memcpy(out, iv, N_BLOCK);
+ in += N_BLOCK;
+ out += N_BLOCK;
+ }
+ return EXIT_SUCCESS;
+}
+
+#endif
+
+#if defined(AES_DEC_PREKEYED)
+
+/* Decrypt a single block of 16 bytes */
+
+return_type aes_decrypt(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK], const aes_context ctx[1]) {
+ if (ctx->rnd) {
+ uint_8t s1[N_BLOCK], r;
+ copy_and_key(s1, in, ctx->ksch + ctx->rnd * N_BLOCK);
+ inv_shift_sub_rows(s1);
+
+ for (r = ctx->rnd; --r;)
+#if defined(VERSION_1)
+ {
+ add_round_key(s1, ctx->ksch + r * N_BLOCK);
+ inv_mix_sub_columns(s1);
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ copy_and_key(s2, s1, ctx->ksch + r * N_BLOCK);
+ inv_mix_sub_columns(s1, s2);
+ }
+#endif
+ copy_and_key(out, s1, ctx->ksch);
+ } else
+ return (return_type)-1;
+ return 0;
+}
+
+/* CBC decrypt a number of blocks (input and return an IV) */
+
+return_type aes_cbc_decrypt(const unsigned char* in, unsigned char* out,
+ int n_block, unsigned char iv[N_BLOCK],
+ const aes_context ctx[1]) {
+ while (n_block--) {
+ uint_8t tmp[N_BLOCK];
+
+ memcpy(tmp, in, N_BLOCK);
+ if (aes_decrypt(in, out, ctx) != EXIT_SUCCESS) return EXIT_FAILURE;
+ xor_block(out, iv);
+ memcpy(iv, tmp, N_BLOCK);
+ in += N_BLOCK;
+ out += N_BLOCK;
+ }
+ return EXIT_SUCCESS;
+}
+
+#endif
+
+#if defined(AES_ENC_128_OTFK)
+
+/* The 'on the fly' encryption key update for for 128 bit keys */
+
+static void update_encrypt_key_128(uint_8t k[N_BLOCK], uint_8t* rc) {
+ uint_8t cc;
+
+ k[0] ^= s_box(k[13]) ^ *rc;
+ k[1] ^= s_box(k[14]);
+ k[2] ^= s_box(k[15]);
+ k[3] ^= s_box(k[12]);
+ *rc = f2(*rc);
+
+ for (cc = 4; cc < 16; cc += 4) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+}
+
+/* Encrypt a single block of 16 bytes with 'on the fly' 128 bit keying */
+
+void aes_encrypt_128(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[N_BLOCK],
+ unsigned char o_key[N_BLOCK]) {
+ uint_8t s1[N_BLOCK], r, rc = 1;
+
+ if (o_key != key) block_copy(o_key, key);
+ copy_and_key(s1, in, o_key);
+
+ for (r = 1; r < 10; ++r)
+#if defined(VERSION_1)
+ {
+ mix_sub_columns(s1);
+ update_encrypt_key_128(o_key, &rc);
+ add_round_key(s1, o_key);
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ mix_sub_columns(s2, s1);
+ update_encrypt_key_128(o_key, &rc);
+ copy_and_key(s1, s2, o_key);
+ }
+#endif
+
+ shift_sub_rows(s1);
+ update_encrypt_key_128(o_key, &rc);
+ copy_and_key(out, s1, o_key);
+}
+
+#endif
+
+#if defined(AES_DEC_128_OTFK)
+
+/* The 'on the fly' decryption key update for for 128 bit keys */
+
+static void update_decrypt_key_128(uint_8t k[N_BLOCK], uint_8t* rc) {
+ uint_8t cc;
+
+ for (cc = 12; cc > 0; cc -= 4) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+ *rc = d2(*rc);
+ k[0] ^= s_box(k[13]) ^ *rc;
+ k[1] ^= s_box(k[14]);
+ k[2] ^= s_box(k[15]);
+ k[3] ^= s_box(k[12]);
+}
+
+/* Decrypt a single block of 16 bytes with 'on the fly' 128 bit keying */
+
+void aes_decrypt_128(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[N_BLOCK],
+ unsigned char o_key[N_BLOCK]) {
+ uint_8t s1[N_BLOCK], r, rc = 0x6c;
+ if (o_key != key) block_copy(o_key, key);
+
+ copy_and_key(s1, in, o_key);
+ inv_shift_sub_rows(s1);
+
+ for (r = 10; --r;)
+#if defined(VERSION_1)
+ {
+ update_decrypt_key_128(o_key, &rc);
+ add_round_key(s1, o_key);
+ inv_mix_sub_columns(s1);
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ update_decrypt_key_128(o_key, &rc);
+ copy_and_key(s2, s1, o_key);
+ inv_mix_sub_columns(s1, s2);
+ }
+#endif
+ update_decrypt_key_128(o_key, &rc);
+ copy_and_key(out, s1, o_key);
+}
+
+#endif
+
+#if defined(AES_ENC_256_OTFK)
+
+/* The 'on the fly' encryption key update for for 256 bit keys */
+
+static void update_encrypt_key_256(uint_8t k[2 * N_BLOCK], uint_8t* rc) {
+ uint_8t cc;
+
+ k[0] ^= s_box(k[29]) ^ *rc;
+ k[1] ^= s_box(k[30]);
+ k[2] ^= s_box(k[31]);
+ k[3] ^= s_box(k[28]);
+ *rc = f2(*rc);
+
+ for (cc = 4; cc < 16; cc += 4) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+
+ k[16] ^= s_box(k[12]);
+ k[17] ^= s_box(k[13]);
+ k[18] ^= s_box(k[14]);
+ k[19] ^= s_box(k[15]);
+
+ for (cc = 20; cc < 32; cc += 4) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+}
+
+/* Encrypt a single block of 16 bytes with 'on the fly' 256 bit keying */
+
+void aes_encrypt_256(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[2 * N_BLOCK],
+ unsigned char o_key[2 * N_BLOCK]) {
+ uint_8t s1[N_BLOCK], r, rc = 1;
+ if (o_key != key) {
+ block_copy(o_key, key);
+ block_copy(o_key + 16, key + 16);
+ }
+ copy_and_key(s1, in, o_key);
+
+ for (r = 1; r < 14; ++r)
+#if defined(VERSION_1)
+ {
+ mix_sub_columns(s1);
+ if (r & 1)
+ add_round_key(s1, o_key + 16);
+ else {
+ update_encrypt_key_256(o_key, &rc);
+ add_round_key(s1, o_key);
+ }
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ mix_sub_columns(s2, s1);
+ if (r & 1)
+ copy_and_key(s1, s2, o_key + 16);
+ else {
+ update_encrypt_key_256(o_key, &rc);
+ copy_and_key(s1, s2, o_key);
+ }
+ }
+#endif
+
+ shift_sub_rows(s1);
+ update_encrypt_key_256(o_key, &rc);
+ copy_and_key(out, s1, o_key);
+}
+
+#endif
+
+#if defined(AES_DEC_256_OTFK)
+
+/* The 'on the fly' encryption key update for for 256 bit keys */
+
+static void update_decrypt_key_256(uint_8t k[2 * N_BLOCK], uint_8t* rc) {
+ uint_8t cc;
+
+ for (cc = 28; cc > 16; cc -= 4) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+
+ k[16] ^= s_box(k[12]);
+ k[17] ^= s_box(k[13]);
+ k[18] ^= s_box(k[14]);
+ k[19] ^= s_box(k[15]);
+
+ for (cc = 12; cc > 0; cc -= 4) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+
+ *rc = d2(*rc);
+ k[0] ^= s_box(k[29]) ^ *rc;
+ k[1] ^= s_box(k[30]);
+ k[2] ^= s_box(k[31]);
+ k[3] ^= s_box(k[28]);
+}
+
+/* Decrypt a single block of 16 bytes with 'on the fly'
+ 256 bit keying
+*/
+void aes_decrypt_256(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[2 * N_BLOCK],
+ unsigned char o_key[2 * N_BLOCK]) {
+ uint_8t s1[N_BLOCK], r, rc = 0x80;
+
+ if (o_key != key) {
+ block_copy(o_key, key);
+ block_copy(o_key + 16, key + 16);
+ }
+
+ copy_and_key(s1, in, o_key);
+ inv_shift_sub_rows(s1);
+
+ for (r = 14; --r;)
+#if defined(VERSION_1)
+ {
+ if ((r & 1)) {
+ update_decrypt_key_256(o_key, &rc);
+ add_round_key(s1, o_key + 16);
+ } else
+ add_round_key(s1, o_key);
+ inv_mix_sub_columns(s1);
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ if ((r & 1)) {
+ update_decrypt_key_256(o_key, &rc);
+ copy_and_key(s2, s1, o_key + 16);
+ } else
+ copy_and_key(s2, s1, o_key);
+ inv_mix_sub_columns(s1, s2);
+ }
+#endif
+ copy_and_key(out, s1, o_key);
+}
+
+#endif
diff --git a/stack/smp/aes.h b/stack/crypto_toolbox/aes.h
similarity index 100%
rename from stack/smp/aes.h
rename to stack/crypto_toolbox/aes.h
diff --git a/stack/crypto_toolbox/aes_cmac.cc b/stack/crypto_toolbox/aes_cmac.cc
new file mode 100644
index 0000000..72b07bd
--- /dev/null
+++ b/stack/crypto_toolbox/aes_cmac.cc
@@ -0,0 +1,217 @@
+/******************************************************************************
+ *
+ * Copyright 2008-2012 Broadcom 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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the implementation of the AES128 and AES CMAC algorithm.
+ *
+ ******************************************************************************/
+
+#include "stack/crypto_toolbox/aes.h"
+#include "stack/crypto_toolbox/crypto_toolbox.h"
+
+#include <base/logging.h>
+#include <base/strings/string_number_conversions.h>
+
+namespace crypto_toolbox {
+
+namespace {
+
+typedef struct {
+ uint8_t* text;
+ uint16_t len;
+ uint16_t round;
+} tCMAC_CB;
+
+thread_local tCMAC_CB cmac_cb;
+
+/* Rb for AES-128 as block cipher, LSB as [0] */
+Octet16 const_Rb{0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+/** utility function to do an biteise exclusive-OR of two bit strings of the
+ * length of OCTET16_LEN. Result is stored in first argument.
+ */
+static void xor_128(Octet16* a, const Octet16& b) {
+ CHECK(a);
+ uint8_t i, *aa = a->data();
+ const uint8_t* bb = b.data();
+
+ for (i = 0; i < OCTET16_LEN; i++) {
+ aa[i] = aa[i] ^ bb[i];
+ }
+}
+} // namespace
+
+/* This function computes AES_128(key, message) */
+Octet16 aes_128(const Octet16& key, const Octet16& message) {
+ Octet16 key_reversed;
+ Octet16 message_reversed;
+ Octet16 output;
+
+ std::reverse_copy(key.begin(), key.end(), key_reversed.begin());
+ std::reverse_copy(message.begin(), message.end(), message_reversed.begin());
+
+ aes_context ctx;
+ aes_set_key(key_reversed.data(), key_reversed.size(), &ctx);
+ aes_encrypt(message_reversed.data(), output.data(), &ctx);
+
+ std::reverse(output.begin(), output.end());
+ return output;
+}
+
+/** utility function to padding the given text to be a 128 bits data. The
+ * parameter dest is input and output parameter, it must point to a
+ * OCTET16_LEN memory space; where include length bytes valid data. */
+static void padding(Octet16* dest, uint8_t length) {
+ uint8_t i, *p = dest->data();
+ /* original last block */
+ for (i = length; i < OCTET16_LEN; i++)
+ p[OCTET16_LEN - i - 1] = (i == length) ? 0x80 : 0;
+}
+
+/** utility function to left shift one bit for a 128 bits value. */
+static void leftshift_onebit(uint8_t* input, uint8_t* output) {
+ uint8_t i, overflow = 0, next_overflow = 0;
+ DVLOG(2) << __func__;
+ /* input[0] is LSB */
+ for (i = 0; i < OCTET16_LEN; i++) {
+ next_overflow = (input[i] & 0x80) ? 1 : 0;
+ output[i] = (input[i] << 1) | overflow;
+ overflow = next_overflow;
+ }
+ return;
+}
+
+/** This function is the calculation of block cipher using AES-128. */
+static Octet16 cmac_aes_k_calculate(const Octet16& key) {
+ Octet16 output;
+ Octet16 x{0}; // zero initialized
+
+ DVLOG(2) << __func__;
+
+ uint8_t i = 1;
+ while (i <= cmac_cb.round) {
+ /* Mi' := Mi (+) X */
+ xor_128((Octet16*)&cmac_cb.text[(cmac_cb.round - i) * OCTET16_LEN], x);
+
+ output = aes_128(key, &cmac_cb.text[(cmac_cb.round - i) * OCTET16_LEN],
+ OCTET16_LEN);
+ x = output;
+ i++;
+ }
+
+ return output;
+}
+
+/** This function proceeed to prepare the last block of message Mn depending on
+ * the size of the message.
+ */
+static void cmac_prepare_last_block(const Octet16& k1, const Octet16& k2) {
+ // uint8_t x[16] = {0};
+ bool flag;
+
+ DVLOG(2) << __func__;
+ /* last block is a complete block set flag to 1 */
+ flag = ((cmac_cb.len % OCTET16_LEN) == 0 && cmac_cb.len != 0) ? true : false;
+
+ DVLOG(2) << "flag=" << flag << " round=" << cmac_cb.round;
+
+ if (flag) { /* last block is complete block */
+ xor_128((Octet16*)&cmac_cb.text[0], k1);
+ } else /* padding then xor with k2 */
+ {
+ padding((Octet16*)&cmac_cb.text[0], (uint8_t)(cmac_cb.len % 16));
+
+ xor_128((Octet16*)&cmac_cb.text[0], k2);
+ }
+}
+
+/** This is the function to generate the two subkeys.
+ * |key| is CMAC key, expect SRK when used by SMP.
+ */
+static void cmac_generate_subkey(const Octet16& key) {
+ DVLOG(2) << __func__;
+
+ Octet16 zero{};
+ Octet16 p = aes_128(key, zero.data(), OCTET16_LEN);
+
+ Octet16 k1, k2;
+ uint8_t* pp = p.data();
+
+ /* If MSB(L) = 0, then K1 = L << 1 */
+ if ((pp[OCTET16_LEN - 1] & 0x80) != 0) {
+ /* Else K1 = ( L << 1 ) (+) Rb */
+ leftshift_onebit(pp, k1.data());
+ xor_128(&k1, const_Rb);
+ } else {
+ leftshift_onebit(pp, k1.data());
+ }
+
+ if ((k1[OCTET16_LEN - 1] & 0x80) != 0) {
+ /* K2 = (K1 << 1) (+) Rb */
+ leftshift_onebit(k1.data(), k2.data());
+ xor_128(&k2, const_Rb);
+ } else {
+ /* If MSB(K1) = 0, then K2 = K1 << 1 */
+ leftshift_onebit(k1.data(), k2.data());
+ }
+
+ cmac_prepare_last_block(k1, k2);
+}
+
+/** key - CMAC key in little endian order
+ * input - text to be signed in little endian byte order.
+ * length - length of the input in byte.
+ */
+Octet16 aes_cmac(const Octet16& key, const uint8_t* input, uint16_t length) {
+ uint16_t len, diff;
+ /* n is number of rounds */
+ uint16_t n = (length + OCTET16_LEN - 1) / OCTET16_LEN;
+
+ DVLOG(2) << __func__;
+
+ if (n == 0) n = 1;
+ len = n * OCTET16_LEN;
+
+ DVLOG(2) << "AES128_CMAC started, allocate buffer size=" << len;
+ /* allocate a memory space of multiple of 16 bytes to hold text */
+ cmac_cb.text = (uint8_t*)alloca(len);
+ cmac_cb.round = n;
+ diff = len - length;
+
+ if (input != NULL && length > 0) {
+ memcpy(&cmac_cb.text[diff], input, (int)length);
+ cmac_cb.len = length;
+ } else {
+ cmac_cb.len = 0;
+ }
+
+ /* prepare calculation for subkey s and last block of data */
+ cmac_generate_subkey(key);
+ /* start calculation */
+ Octet16 signature = cmac_aes_k_calculate(key);
+
+ /* clean up */
+ memset(&cmac_cb, 0, sizeof(tCMAC_CB));
+ // cmac_cb.text is auto-freed by alloca
+
+ return signature;
+}
+
+} // namespace crypto_toolbox
diff --git a/stack/crypto_toolbox/crypto_toolbox.cc b/stack/crypto_toolbox/crypto_toolbox.cc
new file mode 100644
index 0000000..d5c8e5d
--- /dev/null
+++ b/stack/crypto_toolbox/crypto_toolbox.cc
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2018 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 "stack/crypto_toolbox/crypto_toolbox.h"
+#include "stack/crypto_toolbox/aes.h"
+
+#include <algorithm>
+
+#include <base/logging.h>
+#include <base/strings/string_number_conversions.h>
+
+using base::HexEncode;
+
+namespace crypto_toolbox {
+
+Octet16 h6(const Octet16& w, std::array<uint8_t, 4> keyid) {
+ return aes_cmac(w, keyid.data(), keyid.size());
+}
+
+Octet16 h7(const Octet16& salt, const Octet16& w) {
+ return aes_cmac(salt, w.data(), w.size());
+}
+
+Octet16 f4(const uint8_t* u, const uint8_t* v, const Octet16& x, uint8_t z) {
+ constexpr size_t msg_len = BT_OCTET32_LEN /* U size */ +
+ BT_OCTET32_LEN /* V size */ + 1 /* Z size */;
+
+ DVLOG(2) << "U=" << HexEncode(u, BT_OCTET32_LEN)
+ << ", V=" << HexEncode(v, BT_OCTET32_LEN)
+ << ", X=" << HexEncode(x.data(), x.size()) << ", Z=" << std::hex
+ << +z;
+
+ std::array<uint8_t, msg_len> msg;
+ auto it = msg.begin();
+ it = std::copy(&z, &z + 1, it);
+ it = std::copy(v, v + BT_OCTET32_LEN, it);
+ it = std::copy(u, u + BT_OCTET32_LEN, it);
+ return aes_cmac(x, msg.data(), msg.size());
+}
+
+/** helper for f5 */
+static Octet16 calculate_mac_key_or_ltk(const Octet16& t, uint8_t counter,
+ uint8_t* key_id, const Octet16& n1,
+ const Octet16& n2, uint8_t* a1,
+ uint8_t* a2, uint8_t* length) {
+ constexpr size_t msg_len = 1 /* Counter size */ + 4 /* keyID size */ +
+ OCTET16_LEN /* N1 size */ +
+ OCTET16_LEN /* N2 size */ + 7 /* A1 size*/ +
+ 7 /* A2 size*/ + 2 /* Length size */;
+ std::array<uint8_t, msg_len> msg;
+ auto it = msg.begin();
+ it = std::copy(length, length + 2, it);
+ it = std::copy(a2, a2 + 7, it);
+ it = std::copy(a1, a1 + 7, it);
+ it = std::copy(n2.begin(), n2.end(), it);
+ it = std::copy(n1.begin(), n1.end(), it);
+ it = std::copy(key_id, key_id + 4, it);
+ it = std::copy(&counter, &counter + 1, it);
+
+ return aes_cmac(t, msg.data(), msg.size());
+}
+
+void f5(const uint8_t* w, const Octet16& n1, const Octet16& n2, uint8_t* a1,
+ uint8_t* a2, Octet16* mac_key, Octet16* ltk) {
+ DVLOG(2) << __func__ << "W=" << HexEncode(w, BT_OCTET32_LEN)
+ << ", N1=" << HexEncode(n1.data(), n1.size())
+ << ", N2=" << HexEncode(n2.data(), n2.size())
+ << ", A1=" << HexEncode(a1, 7) << ", A2=" << HexEncode(a2, 7);
+
+ const Octet16 salt{0xBE, 0x83, 0x60, 0x5A, 0xDB, 0x0B, 0x37, 0x60,
+ 0x38, 0xA5, 0xF5, 0xAA, 0x91, 0x83, 0x88, 0x6C};
+ Octet16 t = aes_cmac(salt, w, BT_OCTET32_LEN);
+
+ DVLOG(2) << "T=" << HexEncode(t.data(), t.size());
+
+ uint8_t key_id[4] = {0x65, 0x6c, 0x74, 0x62}; /* 0x62746c65 */
+ uint8_t length[2] = {0x00, 0x01}; /* 0x0100 */
+
+ *mac_key = calculate_mac_key_or_ltk(t, 0, key_id, n1, n2, a1, a2, length);
+
+ *ltk = calculate_mac_key_or_ltk(t, 1, key_id, n1, n2, a1, a2, length);
+
+ DVLOG(2) << "mac_key=" << HexEncode(mac_key->data(), mac_key->size());
+ DVLOG(2) << "ltk=" << HexEncode(ltk->data(), ltk->size());
+}
+
+Octet16 f6(const Octet16& w, const Octet16& n1, const Octet16& n2,
+ const Octet16& r, uint8_t* iocap, uint8_t* a1, uint8_t* a2) {
+ const uint8_t msg_len = OCTET16_LEN /* N1 size */ +
+ OCTET16_LEN /* N2 size */ + OCTET16_LEN /* R size */ +
+ 3 /* IOcap size */ + 7 /* A1 size*/
+ + 7 /* A2 size*/;
+
+ DVLOG(2) << __func__ << "W=" << HexEncode(w.data(), w.size())
+ << ", N1=" << HexEncode(n1.data(), n1.size())
+ << ", N2=" << HexEncode(n2.data(), n2.size())
+ << ", R=" << HexEncode(r.data(), r.size())
+ << ", IOcap=" << HexEncode(iocap, 3) << ", A1=" << HexEncode(a1, 7)
+ << ", A2=" << HexEncode(a2, 7);
+
+ std::array<uint8_t, msg_len> msg;
+ auto it = msg.begin();
+ it = std::copy(a2, a2 + 7, it);
+ it = std::copy(a1, a1 + 7, it);
+ it = std::copy(iocap, iocap + 3, it);
+ it = std::copy(r.begin(), r.end(), it);
+ it = std::copy(n2.begin(), n2.end(), it);
+ it = std::copy(n1.begin(), n1.end(), it);
+
+ return aes_cmac(w, msg.data(), msg.size());
+}
+
+uint32_t g2(const uint8_t* u, const uint8_t* v, const Octet16& x,
+ const Octet16& y) {
+ constexpr size_t msg_len = BT_OCTET32_LEN /* U size */ +
+ BT_OCTET32_LEN /* V size */
+ + OCTET16_LEN /* Y size */;
+
+ DVLOG(2) << __func__ << "U=" << HexEncode(u, BT_OCTET32_LEN)
+ << ", V=" << HexEncode(v, BT_OCTET32_LEN)
+ << ", X=" << HexEncode(x.data(), x.size())
+ << ", Y=" << HexEncode(y.data(), y.size());
+
+ std::array<uint8_t, msg_len> msg;
+ auto it = msg.begin();
+ it = std::copy(y.begin(), y.end(), it);
+ it = std::copy(v, v + BT_OCTET32_LEN, it);
+ it = std::copy(u, u + BT_OCTET32_LEN, it);
+
+ Octet16 cmac = aes_cmac(x, msg.data(), msg.size());
+
+ /* vres = cmac mod 2**32 mod 10**6 */
+ uint32_t vres;
+ uint8_t* p = cmac.data();
+ STREAM_TO_UINT32(vres, p);
+
+ vres = vres % 1000000;
+ return vres;
+}
+
+Octet16 ltk_to_link_key(const Octet16& ltk, bool use_h7) {
+ Octet16 ilk; /* intermidiate link key */
+ if (use_h7) {
+ constexpr Octet16 salt{0x31, 0x70, 0x6D, 0x74, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ ilk = h7(salt, ltk);
+ } else {
+ /* "tmp1" mapping to extended ASCII, little endian*/
+ constexpr std::array<uint8_t, 4> keyID_tmp1 = {0x31, 0x70, 0x6D, 0x74};
+ ilk = h6(ltk, keyID_tmp1);
+ }
+
+ /* "lebr" mapping to extended ASCII, little endian */
+ constexpr std::array<uint8_t, 4> keyID_lebr = {0x72, 0x62, 0x65, 0x6c};
+ return h6(ilk, keyID_lebr);
+}
+
+Octet16 link_key_to_ltk(const Octet16& link_key, bool use_h7) {
+ Octet16 iltk; /* intermidiate long term key */
+ if (use_h7) {
+ constexpr Octet16 salt{0x32, 0x70, 0x6D, 0x74, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ iltk = h7(salt, link_key);
+ } else {
+ /* "tmp2" mapping to extended ASCII, little endian */
+ constexpr std::array<uint8_t, 4> keyID_tmp2 = {0x32, 0x70, 0x6D, 0x74};
+ iltk = h6(link_key, keyID_tmp2);
+ }
+
+ /* "brle" mapping to extended ASCII, little endian */
+ constexpr std::array<uint8_t, 4> keyID_brle = {0x65, 0x6c, 0x72, 0x62};
+ return h6(iltk, keyID_brle);
+}
+
+} // namespace crypto_toolbox
diff --git a/stack/crypto_toolbox/crypto_toolbox.h b/stack/crypto_toolbox/crypto_toolbox.h
new file mode 100644
index 0000000..b445fa2
--- /dev/null
+++ b/stack/crypto_toolbox/crypto_toolbox.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 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 "stack/include/bt_types.h"
+
+namespace crypto_toolbox {
+
+extern Octet16 aes_128(const Octet16& key, const Octet16& message);
+extern Octet16 aes_cmac(const Octet16& key, const uint8_t* message,
+ uint16_t length);
+extern Octet16 f4(const uint8_t* u, const uint8_t* v, const Octet16& x,
+ uint8_t z);
+extern void f5(const uint8_t* w, const Octet16& n1, const Octet16& n2,
+ uint8_t* a1, uint8_t* a2, Octet16* mac_key, Octet16* ltk);
+extern Octet16 f6(const Octet16& w, const Octet16& n1, const Octet16& n2,
+ const Octet16& r, uint8_t* iocap, uint8_t* a1, uint8_t* a2);
+extern Octet16 h6(const Octet16& w, std::array<uint8_t, 4> keyid);
+extern Octet16 h7(const Octet16& salt, const Octet16& w);
+extern uint32_t g2(const uint8_t* u, const uint8_t* v, const Octet16& x,
+ const Octet16& y);
+extern Octet16 ltk_to_link_key(const Octet16& ltk, bool use_h7);
+extern Octet16 link_key_to_ltk(const Octet16& link_key, bool use_h7);
+
+/* This function computes AES_128(key, message). |key| must be 128bit.
+ * |message| can be at most 16 bytes long, it's length in bytes is given in
+ * |length| */
+inline Octet16 aes_128(const Octet16& key, const uint8_t* message,
+ const uint8_t length) {
+ CHECK(length <= OCTET16_LEN) << "you tried aes_128 more than 16 bytes!";
+ Octet16 msg{0};
+ std::copy(message, message + length, msg.begin());
+ return aes_128(key, msg);
+}
+
+// |tlen| - lenth of mac desired
+// |p_signature| - data pointer to where signed data to be stored, tlen long.
+inline void aes_cmac(const Octet16& key, const uint8_t* message,
+ uint16_t length, uint16_t tlen, uint8_t* p_signature) {
+ Octet16 signature = aes_cmac(key, message, length);
+
+ uint8_t* p_mac = signature.data() + (OCTET16_LEN - tlen);
+ memcpy(p_signature, p_mac, tlen);
+}
+
+inline Octet16 aes_cmac(const Octet16& key, const Octet16& message) {
+ return aes_cmac(key, message.data(), message.size());
+}
+
+} // namespace crypto_toolbox
\ No newline at end of file
diff --git a/stack/gatt/att_protocol.cc b/stack/gatt/att_protocol.cc
index 142216c..5d3d4a8 100644
--- a/stack/gatt/att_protocol.cc
+++ b/stack/gatt/att_protocol.cc
@@ -352,9 +352,7 @@
"ATT_RSP_READ_BLOB/GATT_RSP_PREPARE_WRITE: len = %d offset = %d",
p_msg->attr_value.len, p_msg->attr_value.offset);
offset = p_msg->attr_value.offset;
- /* Coverity: [FALSE-POSITIVE error] intended fall through */
- /* Missing break statement between cases in switch statement */
- /* fall through */
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case GATT_RSP_READ_BY_TYPE:
case GATT_RSP_READ:
case GATT_HANDLE_VALUE_NOTIF:
@@ -482,7 +480,7 @@
case GATT_REQ_READ_BLOB:
offset = p_msg->read_blob.offset;
- /* fall through */
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case GATT_REQ_READ:
handle =
(op_code == GATT_REQ_READ) ? p_msg->handle : p_msg->read_blob.handle;
@@ -498,7 +496,7 @@
case GATT_REQ_PREPARE_WRITE:
offset = p_msg->attr_value.offset;
- /* fall through */
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case GATT_REQ_WRITE:
case GATT_CMD_WRITE:
case GATT_SIGN_CMD_WRITE:
diff --git a/stack/gatt/connection_manager.cc b/stack/gatt/connection_manager.cc
new file mode 100644
index 0000000..cfbb02e
--- /dev/null
+++ b/stack/gatt/connection_manager.cc
@@ -0,0 +1,295 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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 "connection_manager.h"
+
+#include <base/bind.h>
+#include <base/callback.h>
+#include <base/location.h>
+#include <base/logging.h>
+#include <map>
+#include <memory>
+#include <set>
+
+#include "internal_include/bt_trace.h"
+#include "osi/include/alarm.h"
+#include "stack/btm/btm_ble_bgconn.h"
+
+#define DIRECT_CONNECT_TIMEOUT (30 * 1000) /* 30 seconds */
+
+struct closure_data {
+ base::OnceClosure user_task;
+ base::Location posted_from;
+};
+
+static void alarm_closure_cb(void* p) {
+ closure_data* data = (closure_data*)p;
+ VLOG(1) << "executing timer scheduled at %s" << data->posted_from.ToString();
+ std::move(data->user_task).Run();
+ delete data;
+}
+
+// Periodic alarms are not supported, because we clean up data in callback
+void alarm_set_closure(const base::Location& posted_from, alarm_t* alarm,
+ uint64_t interval_ms, base::OnceClosure user_task) {
+ closure_data* data = new closure_data;
+ data->posted_from = posted_from;
+ data->user_task = std::move(user_task);
+ VLOG(1) << "scheduling timer %s" << data->posted_from.ToString();
+ alarm_set_on_mloop(alarm, interval_ms, alarm_closure_cb, data);
+}
+
+using unique_alarm_ptr = std::unique_ptr<alarm_t, decltype(&alarm_free)>;
+
+namespace connection_manager {
+
+struct tAPPS_CONNECTING {
+ // ids of clients doing background connection to given device
+ std::set<tAPP_ID> doing_bg_conn;
+
+ // Apps trying to do direct connection.
+ std::map<tAPP_ID, unique_alarm_ptr> doing_direct_conn;
+};
+
+namespace {
+// Maps address to apps trying to connect to it
+std::map<RawAddress, tAPPS_CONNECTING> bgconn_dev;
+
+bool anyone_connecting(
+ const std::map<RawAddress, tAPPS_CONNECTING>::iterator it) {
+ return (!it->second.doing_bg_conn.empty() ||
+ !it->second.doing_direct_conn.empty());
+}
+
+} // namespace
+
+/** background connection device from the list. Returns pointer to the device
+ * record, or nullptr if not found */
+std::set<tAPP_ID> get_apps_connecting_to(const RawAddress& address) {
+ auto it = bgconn_dev.find(address);
+ return (it != bgconn_dev.end()) ? it->second.doing_bg_conn
+ : std::set<tAPP_ID>();
+}
+
+/** Add a device from the background connection list. Returns true if device
+ * added to the list, or already in list, false otherwise */
+bool background_connect_add(uint8_t app_id, const RawAddress& address) {
+ auto it = bgconn_dev.find(address);
+ bool in_white_list = false;
+ if (it != bgconn_dev.end()) {
+ // device already in the whitelist, just add interested app to the list
+ if (it->second.doing_bg_conn.count(app_id)) {
+ LOG(INFO) << "App id=" << loghex(app_id)
+ << "already doing background connection to " << address;
+ return true;
+ }
+
+ // Already in white list ?
+ if (anyone_connecting(it)) {
+ in_white_list = true;
+ }
+ }
+
+ if (!in_white_list) {
+ // the device is not in the whitelist
+ if (!BTM_WhiteListAdd(address)) return false;
+ }
+
+ // create endtry for address, and insert app_id.
+ bgconn_dev[address].doing_bg_conn.insert(app_id);
+ return true;
+}
+
+/** Removes all registrations for connection for given device.
+ * Returns true if anything was removed, false otherwise */
+bool remove_unconditional(const RawAddress& address) {
+ auto it = bgconn_dev.find(address);
+ if (it == bgconn_dev.end()) return false;
+
+ BTM_WhiteListRemove(address);
+ bgconn_dev.erase(it);
+ return true;
+}
+
+/** Remove device from the background connection device list or listening to
+ * advertising list. Returns true if device was on the list and was succesfully
+ * removed */
+bool background_connect_remove(uint8_t app_id, const RawAddress& address) {
+ VLOG(2) << __func__;
+ auto it = bgconn_dev.find(address);
+ if (it == bgconn_dev.end()) return false;
+
+ if (!it->second.doing_bg_conn.erase(app_id)) return false;
+
+ if (anyone_connecting(it)) return true;
+
+ // no more apps interested - remove from whitelist and delete record
+ BTM_WhiteListRemove(address);
+ bgconn_dev.erase(it);
+ return true;
+}
+
+/** deregister all related background connetion device. */
+void on_app_deregistered(uint8_t app_id) {
+ auto it = bgconn_dev.begin();
+ auto end = bgconn_dev.end();
+ /* update the BG conn device list */
+ while (it != end) {
+ it->second.doing_bg_conn.erase(app_id);
+
+ it->second.doing_direct_conn.erase(app_id);
+
+ if (anyone_connecting(it)) {
+ it++;
+ continue;
+ }
+
+ BTM_WhiteListRemove(it->first);
+ it = bgconn_dev.erase(it);
+ }
+}
+
+void on_connection_complete(const RawAddress& address) {
+ VLOG(2) << __func__;
+ auto it = bgconn_dev.find(address);
+
+ while (it != bgconn_dev.end() && !it->second.doing_direct_conn.empty()) {
+ uint8_t app_id = it->second.doing_direct_conn.begin()->first;
+ direct_connect_remove(app_id, address);
+ it = bgconn_dev.find(address);
+ }
+}
+
+/** Reset bg device list. If called after controller reset, set |after_reset| to
+ * true, as there is no need to wipe controller white list in this case. */
+void reset(bool after_reset) {
+ bgconn_dev.clear();
+ if (!after_reset) BTM_WhiteListClear();
+}
+
+void wl_direct_connect_timeout_cb(uint8_t app_id, const RawAddress& address) {
+ on_connection_timed_out(app_id, address);
+
+ // TODO: this would free the timer, from within the timer callback, which is
+ // bad.
+ direct_connect_remove(app_id, address);
+}
+
+/** Add a device to the direcgt connection list. Returns true if device
+ * added to the list, false otherwise */
+bool direct_connect_add(uint8_t app_id, const RawAddress& address) {
+ auto it = bgconn_dev.find(address);
+ bool in_white_list = false;
+
+ if (it != bgconn_dev.end()) {
+ // app already trying to connect to this particular device
+ if (it->second.doing_direct_conn.count(app_id)) {
+ LOG(INFO) << "direct connect attempt from app_id=" << loghex(app_id)
+ << " already in progress";
+ return false;
+ }
+
+ // are we already in the white list ?
+ if (anyone_connecting(it)) {
+ in_white_list = true;
+ }
+ }
+
+ bool params_changed = BTM_SetLeConnectionModeToFast();
+
+ if (!in_white_list) {
+ if (!BTM_WhiteListAdd(address)) {
+ // if we can't add to white list, turn parameters back to slow.
+ if (params_changed) BTM_SetLeConnectionModeToSlow();
+ return false;
+ }
+ }
+
+ // Setup a timer
+ alarm_t* timeout = alarm_new("wl_conn_params_30s");
+ alarm_set_closure(
+ FROM_HERE, timeout, DIRECT_CONNECT_TIMEOUT,
+ base::BindOnce(&wl_direct_connect_timeout_cb, app_id, address));
+
+ bgconn_dev[address].doing_direct_conn.emplace(
+ app_id, unique_alarm_ptr(timeout, &alarm_free));
+ return true;
+}
+
+bool any_direct_connect_left() {
+ for (const auto& tmp : bgconn_dev) {
+ if (!tmp.second.doing_direct_conn.empty()) return true;
+ }
+ return false;
+}
+
+bool direct_connect_remove(uint8_t app_id, const RawAddress& address) {
+ VLOG(2) << __func__ << ": "
+ << "app_id: " << +app_id << ", address:" << address;
+ auto it = bgconn_dev.find(address);
+ if (it == bgconn_dev.end()) return false;
+
+ auto app_it = it->second.doing_direct_conn.find(app_id);
+ if (app_it == it->second.doing_direct_conn.end()) return false;
+
+ // this will free the alarm
+ it->second.doing_direct_conn.erase(app_it);
+
+ // if we removed last direct connection, lower the scan parameters used for
+ // connecting
+ if (!any_direct_connect_left()) {
+ BTM_SetLeConnectionModeToSlow();
+ }
+
+ if (anyone_connecting(it)) return true;
+
+ // no more apps interested - remove from whitelist
+ BTM_WhiteListRemove(address);
+ bgconn_dev.erase(it);
+ return true;
+}
+
+void dump(int fd) {
+ dprintf(fd, "\nconnection_manager state:\n");
+ if (bgconn_dev.empty()) {
+ dprintf(fd, "\n\tno Low Energy connection attempts\n");
+ return;
+ }
+
+ dprintf(fd, "\n\tdevices attempting connection: %d\n",
+ (int)bgconn_dev.size());
+ for (const auto& entry : bgconn_dev) {
+ dprintf(fd, "\n\t * %s: ", entry.first.ToString().c_str());
+
+ if (!entry.second.doing_direct_conn.empty()) {
+ dprintf(fd, "\n\t\tapps doing direct connect: ");
+ for (const auto& id : entry.second.doing_direct_conn) {
+ dprintf(fd, "%d, ", id.first);
+ }
+ }
+
+ if (entry.second.doing_bg_conn.empty()) {
+ dprintf(fd, "\n\t\tapps doing background connect: ");
+ for (const auto& id : entry.second.doing_bg_conn) {
+ dprintf(fd, "%d, ", id);
+ }
+ }
+ }
+}
+
+} // namespace connection_manager
diff --git a/stack/gatt/connection_manager.h b/stack/gatt/connection_manager.h
new file mode 100644
index 0000000..4704c8f
--- /dev/null
+++ b/stack/gatt/connection_manager.h
@@ -0,0 +1,61 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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 <set>
+
+#include "types/raw_address.h"
+
+/* connection_manager takes care of all the low-level details of LE connection
+ * initiation. It accept requests from multiple subsystems to connect to
+ * devices, and multiplex them into whitelist add/remove, and scan parameter
+ * changes.
+ *
+ * There is no code for app_id generation. GATT clients use their GATT_IF, and
+ * L2CAP layer uses CONN_MGR_ID_L2CAP as fixed app_id. In case any further
+ * subsystems also use connection_manager, we should consider adding a proper
+ * mechanism for app_id generation.
+ */
+namespace connection_manager {
+
+using tAPP_ID = uint8_t;
+
+/* for background connection */
+extern bool background_connect_add(tAPP_ID app_id, const RawAddress& address);
+extern bool background_connect_remove(tAPP_ID app_id,
+ const RawAddress& address);
+extern bool remove_unconditional(const RawAddress& address);
+
+extern void reset(bool after_reset);
+
+extern void on_app_deregistered(tAPP_ID app_id);
+extern void on_connection_complete(const RawAddress& address);
+
+extern std::set<tAPP_ID> get_apps_connecting_to(const RawAddress& remote_bda);
+
+extern bool direct_connect_add(tAPP_ID app_id, const RawAddress& address);
+extern bool direct_connect_remove(tAPP_ID app_id, const RawAddress& address);
+
+extern void dump(int fd);
+
+/* This callback will be executed when direct connect attempt fails due to
+ * timeout. It must be implemented by users of connection_manager */
+extern void on_connection_timed_out(uint8_t app_id, const RawAddress& address);
+
+} // namespace connection_manager
diff --git a/stack/gatt/gatt_api.cc b/stack/gatt/gatt_api.cc
index b983318..4195548 100644
--- a/stack/gatt/gatt_api.cc
+++ b/stack/gatt/gatt_api.cc
@@ -24,7 +24,6 @@
#include "bt_target.h"
#include <base/strings/string_number_conversions.h>
-#include <base/strings/stringprintf.h>
#include <stdio.h>
#include <string.h>
#include "bt_common.h"
@@ -33,10 +32,11 @@
#include "gatt_api.h"
#include "gatt_int.h"
#include "l2c_api.h"
+#include "stack/gatt/connection_manager.h"
-using base::StringPrintf;
using bluetooth::Uuid;
+extern bool BTM_BackgroundConnectAddressKnown(const RawAddress& address);
/**
* Add an service handle range to the list in decending order of the start
* handle. Return reference to the newly added element.
@@ -184,9 +184,8 @@
/* check for space */
if (num_handles > (0xFFFF - s_hdl + 1)) {
- LOG(ERROR) << StringPrintf(
- "GATTS_ReserveHandles: no handles, s_hdl: %u needed: %u", s_hdl,
- num_handles);
+ LOG(ERROR) << __func__ << ": no handles, s_hdl=" << +s_hdl
+ << " needed=" << num_handles;
return GATT_INTERNAL_ERROR;
}
@@ -204,10 +203,11 @@
gatts_init_service_db(list.svc_db, svc_uuid, is_pri, s_hdl, num_handles);
- VLOG(1) << StringPrintf(
- "%s: handles needed:%u s_hdl=%u e_hdl=%u %s is_primary=%d", __func__,
- num_handles, list.asgn_range.s_handle, list.asgn_range.e_handle,
- list.asgn_range.svc_uuid.ToString().c_str(), list.asgn_range.is_primary);
+ VLOG(1) << __func__ << ": handles needed=" << num_handles
+ << ", s_hdl=" << loghex(list.asgn_range.s_handle)
+ << ", e_hdl=" << loghex(list.asgn_range.e_handle)
+ << ", uuid=" << list.asgn_range.svc_uuid
+ << ", is_primary=" << +list.asgn_range.is_primary;
service->attribute_handle = s_hdl;
@@ -221,17 +221,16 @@
!(el->permissions & GATT_WRITE_SIGNED_PERM)) ||
((el->permissions & GATT_WRITE_SIGNED_PERM) &&
!(el->properties & GATT_CHAR_PROP_BIT_AUTH))) {
- VLOG(1) << StringPrintf(
- "Invalid configuration property=0x%02x perm=0x%04x ",
- el->properties, el->permissions);
+ VLOG(1) << "Invalid configuration property=" << loghex(el->properties)
+ << ", perm=" << loghex(el->permissions);
return GATT_INTERNAL_ERROR;
}
if (is_gatt_attr_type(uuid)) {
- LOG(ERROR) << StringPrintf(
- "%s: attept to add characteristic with UUID equal to GATT "
- "Attribute Type %s ",
- __func__, uuid.ToString().c_str());
+ LOG(ERROR) << __func__
+ << ": attept to add characteristic with UUID equal to GATT "
+ "Attribute Type "
+ << uuid;
return GATT_INTERNAL_ERROR;
}
@@ -239,10 +238,10 @@
list.svc_db, el->permissions, el->properties, uuid);
} else if (el->type == BTGATT_DB_DESCRIPTOR) {
if (is_gatt_attr_type(uuid)) {
- LOG(ERROR) << StringPrintf(
- "%s: attept to add descriptor with UUID equal to GATT "
- "Attribute Type %s",
- __func__, uuid.ToString().c_str());
+ LOG(ERROR) << __func__
+ << ": attept to add descriptor with UUID equal to GATT "
+ "Attribute Type "
+ << uuid;
return GATT_INTERNAL_ERROR;
}
@@ -294,9 +293,9 @@
gatt_update_last_srv_info();
- VLOG(1) << StringPrintf(
- "%s: allocated el: s_hdl=%d e_hdl=%d type=0x%x sdp_hdl=0x%x", __func__,
- elem.s_hdl, elem.e_hdl, elem.type, elem.sdp_handle);
+ VLOG(1) << __func__ << ": allocated el s_hdl=" << loghex(elem.s_hdl)
+ << ", e_hdl=" << loghex(elem.e_hdl) << ", type=" << loghex(elem.type)
+ << ", sdp_hdl=" << loghex(elem.sdp_handle);
gatt_proc_srv_chg();
@@ -354,8 +353,8 @@
GATTS_StopService(it->asgn_range.s_handle);
}
- VLOG(1) << StringPrintf("released handles s_hdl=%u e_hdl=%u",
- it->asgn_range.s_handle, it->asgn_range.e_handle);
+ VLOG(1) << "released handles s_hdl=" << loghex(it->asgn_range.s_handle)
+ << ", e_hdl=" << loghex(it->asgn_range.e_handle);
if ((it->asgn_range.s_handle >= gatt_cb.hdl_cfg.app_start_hdl) &&
gatt_cb.cb_info.p_nv_save_callback)
@@ -377,12 +376,12 @@
*
******************************************************************************/
void GATTS_StopService(uint16_t service_handle) {
- LOG(INFO) << __func__ << ": 0x" << std::hex << +service_handle;
+ LOG(INFO) << __func__ << ": " << loghex(service_handle);
auto it = gatt_sr_find_i_rcb_by_handle(service_handle);
if (it == gatt_cb.srv_list_info->end()) {
- LOG(ERROR) << StringPrintf("%s: service_handle: %u is not in use", __func__,
- service_handle);
+ LOG(ERROR) << __func__ << ": service_handle=" << loghex(service_handle)
+ << " is not in use";
}
if (it->sdp_handle) {
@@ -410,11 +409,6 @@
******************************************************************************/
tGATT_STATUS GATTS_HandleValueIndication(uint16_t conn_id, uint16_t attr_handle,
uint16_t val_len, uint8_t* p_val) {
- tGATT_STATUS cmd_status = GATT_NO_RESOURCES;
-
- tGATT_VALUE indication;
- BT_HDR* p_msg;
- tGATT_VALUE* p_buf;
tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
@@ -422,12 +416,13 @@
VLOG(1) << __func__;
if ((p_reg == NULL) || (p_tcb == NULL)) {
- LOG(ERROR) << __func__ << ": Unknown conn_id: " << +conn_id;
+ LOG(ERROR) << __func__ << ": Unknown conn_id=" << loghex(conn_id);
return (tGATT_STATUS)GATT_INVALID_CONN_ID;
}
if (!GATT_HANDLE_IS_VALID(attr_handle)) return GATT_ILLEGAL_PARAMETER;
+ tGATT_VALUE indication;
indication.conn_id = conn_id;
indication.handle = attr_handle;
indication.len = val_len;
@@ -436,24 +431,20 @@
if (GATT_HANDLE_IS_VALID(p_tcb->indicate_handle)) {
VLOG(1) << "Add a pending indication";
- p_buf = gatt_add_pending_ind(p_tcb, &indication);
- if (p_buf != NULL) {
- cmd_status = GATT_SUCCESS;
- } else {
- cmd_status = GATT_NO_RESOURCES;
- }
- } else {
- tGATT_SR_MSG gatt_sr_msg;
- gatt_sr_msg.attr_value = indication;
- p_msg = attp_build_sr_msg(*p_tcb, GATT_HANDLE_VALUE_IND, &gatt_sr_msg);
- if (p_msg != NULL) {
- cmd_status = attp_send_sr_msg(*p_tcb, p_msg);
+ gatt_add_pending_ind(p_tcb, &indication);
+ return GATT_SUCCESS;
+ }
- if (cmd_status == GATT_SUCCESS || cmd_status == GATT_CONGESTED) {
- p_tcb->indicate_handle = indication.handle;
- gatt_start_conf_timer(p_tcb);
- }
- }
+ tGATT_SR_MSG gatt_sr_msg;
+ gatt_sr_msg.attr_value = indication;
+ BT_HDR* p_msg =
+ attp_build_sr_msg(*p_tcb, GATT_HANDLE_VALUE_IND, &gatt_sr_msg);
+ if (!p_msg) return GATT_NO_RESOURCES;
+
+ tGATT_STATUS cmd_status = attp_send_sr_msg(*p_tcb, p_msg);
+ if (cmd_status == GATT_SUCCESS || cmd_status == GATT_CONGESTED) {
+ p_tcb->indicate_handle = indication.handle;
+ gatt_start_conf_timer(p_tcb);
}
return cmd_status;
}
@@ -532,19 +523,17 @@
tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
- VLOG(1) << __func__
- << StringPrintf(": conn_id: %u trans_id: %u Status: 0x%04x",
- conn_id, trans_id, status);
+ VLOG(1) << __func__ << ": conn_id=" << loghex(conn_id)
+ << ", trans_id=" << loghex(trans_id) << ", status=" << loghex(status);
if ((p_reg == NULL) || (p_tcb == NULL)) {
- LOG(ERROR) << StringPrintf("Unknown conn_id: %u ", conn_id);
+ LOG(ERROR) << "Unknown conn_id=" << loghex(conn_id);
return (tGATT_STATUS)GATT_INVALID_CONN_ID;
}
if (p_tcb->sr_cmd.trans_id != trans_id) {
- LOG(ERROR) << StringPrintf("conn_id: %u waiting for op_code = %02x",
- conn_id, p_tcb->sr_cmd.op_code);
-
+ LOG(ERROR) << "conn_id=" << loghex(conn_id)
+ << " waiting for op_code=" << loghex(p_tcb->sr_cmd.op_code);
return (GATT_WRONG_STATE);
}
/* Process App response */
@@ -582,7 +571,7 @@
tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
- VLOG(1) << __func__ << StringPrintf("conn_id=%d mtu=%d", conn_id, mtu);
+ VLOG(1) << __func__ << ": conn_id=" << loghex(conn_id) << ", mtu=" << +mtu;
if ((p_tcb == NULL) || (p_reg == NULL) || (mtu < GATT_DEF_BLE_MTU_SIZE) ||
(mtu > GATT_MAX_MTU_SIZE)) {
@@ -618,32 +607,36 @@
*
* Parameters conn_id: connection identifier.
* disc_type:discovery type.
- * p_param: parameters of discovery requirement.
+ * start_handle and end_handle: range of handles for discovery
+ * uuid: uuid to discovery. set to Uuid::kEmpty for requests
+ * that don't need it
*
* Returns GATT_SUCCESS if command received/sent successfully.
*
******************************************************************************/
tGATT_STATUS GATTC_Discover(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
- tGATT_DISC_PARAM* p_param) {
+ uint16_t start_handle, uint16_t end_handle,
+ const Uuid& uuid) {
tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
- LOG(INFO) << __func__
- << StringPrintf(" conn_id=%d disc_type=%d", conn_id, disc_type);
-
- if ((p_tcb == NULL) || (p_reg == NULL) || (p_param == NULL) ||
- (disc_type >= GATT_DISC_MAX)) {
- LOG(ERROR) << StringPrintf("Illegal param: disc_type %d conn_id = %d",
- disc_type, conn_id);
+ if ((p_tcb == NULL) || (p_reg == NULL) || (disc_type >= GATT_DISC_MAX)) {
+ LOG(ERROR) << __func__ << " Illegal param: disc_type=" << +disc_type
+ << " conn_id=" << loghex(conn_id);
return GATT_ILLEGAL_PARAMETER;
}
- if (!GATT_HANDLE_IS_VALID(p_param->s_handle) ||
- !GATT_HANDLE_IS_VALID(p_param->e_handle) ||
+ LOG(INFO) << __func__ << " conn_id=" << loghex(conn_id)
+ << ", disc_type=" << +disc_type
+ << ", s_handle=" << loghex(start_handle)
+ << ", e_handle=" << loghex(end_handle);
+
+ if (!GATT_HANDLE_IS_VALID(start_handle) ||
+ !GATT_HANDLE_IS_VALID(end_handle) ||
/* search by type does not have a valid UUID param */
- (disc_type == GATT_DISC_SRVC_BY_UUID && p_param->service.IsEmpty())) {
+ (disc_type == GATT_DISC_SRVC_BY_UUID && uuid.IsEmpty())) {
return GATT_ILLEGAL_PARAMETER;
}
@@ -657,14 +650,20 @@
p_clcb->operation = GATTC_OPTYPE_DISCOVERY;
p_clcb->op_subtype = disc_type;
- p_clcb->s_handle = p_param->s_handle;
- p_clcb->e_handle = p_param->e_handle;
- p_clcb->uuid = p_param->service;
+ p_clcb->s_handle = start_handle;
+ p_clcb->e_handle = end_handle;
+ p_clcb->uuid = uuid;
gatt_act_discovery(p_clcb);
return GATT_SUCCESS;
}
+tGATT_STATUS GATTC_Discover(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
+ uint16_t start_handle, uint16_t end_handle) {
+ return GATTC_Discover(conn_id, disc_type, start_handle, end_handle,
+ Uuid::kEmpty);
+}
+
/*******************************************************************************
*
* Function GATTC_Read
@@ -686,17 +685,18 @@
tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
- VLOG(1) << __func__ << StringPrintf(" conn_id=%d type=%d", conn_id, type);
+ VLOG(1) << __func__ << ": conn_id=" << loghex(conn_id)
+ << ", type=" << loghex(type);
if ((p_tcb == NULL) || (p_reg == NULL) || (p_read == NULL) ||
((type >= GATT_READ_MAX) || (type == 0))) {
- LOG(ERROR) << StringPrintf(" Illegal param: conn_id %d, type 0%d,", conn_id,
- type);
+ LOG(ERROR) << ": illegal param: conn_id=" << loghex(conn_id)
+ << "type=" << loghex(type);
return GATT_ILLEGAL_PARAMETER;
}
if (gatt_is_clcb_allocated(conn_id)) {
- LOG(ERROR) << StringPrintf(" GATT_BUSY conn_id = %d", conn_id);
+ LOG(ERROR) << "GATT_BUSY conn_id=" << loghex(conn_id);
return GATT_BUSY;
}
@@ -739,7 +739,7 @@
}
/* start security check */
- gatt_security_check_start(p_clcb);
+ if (gatt_security_check_start(p_clcb)) p_tcb->pending_enc_clcb.push(p_clcb);
return GATT_SUCCESS;
}
@@ -767,14 +767,13 @@
if ((p_tcb == NULL) || (p_reg == NULL) || (p_write == NULL) ||
((type != GATT_WRITE) && (type != GATT_WRITE_PREPARE) &&
(type != GATT_WRITE_NO_RSP))) {
- LOG(ERROR) << __func__
- << StringPrintf(" Illegal param: conn_id %d, type 0%d,", conn_id,
- type);
+ LOG(ERROR) << __func__ << " Illegal param: conn_id=" << loghex(conn_id)
+ << ", type=" << loghex(type);
return GATT_ILLEGAL_PARAMETER;
}
if (gatt_is_clcb_allocated(conn_id)) {
- LOG(ERROR) << StringPrintf("GATT_BUSY conn_id = %d", conn_id);
+ LOG(ERROR) << "GATT_BUSY conn_id=" << loghex(conn_id);
return GATT_BUSY;
}
@@ -794,7 +793,7 @@
p->offset = 0;
}
- gatt_security_check_start(p_clcb);
+ if (gatt_security_check_start(p_clcb)) p_tcb->pending_enc_clcb.push(p_clcb);
return GATT_SUCCESS;
}
@@ -818,16 +817,16 @@
tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
- VLOG(1) << __func__
- << StringPrintf(": conn_id=%d is_execute=%d", conn_id, is_execute);
+ VLOG(1) << __func__ << ": conn_id=" << loghex(conn_id)
+ << ", is_execute=" << +is_execute;
if ((p_tcb == NULL) || (p_reg == NULL)) {
- LOG(ERROR) << StringPrintf(" Illegal param: conn_id %d", conn_id);
+ LOG(ERROR) << " Illegal param: conn_id=" << loghex(conn_id);
return GATT_ILLEGAL_PARAMETER;
}
if (gatt_is_clcb_allocated(conn_id)) {
- LOG(ERROR) << StringPrintf(" GATT_BUSY conn_id = %d", conn_id);
+ LOG(ERROR) << " GATT_BUSY conn_id=" << loghex(conn_id);
return GATT_BUSY;
}
@@ -855,17 +854,17 @@
*
******************************************************************************/
tGATT_STATUS GATTC_SendHandleValueConfirm(uint16_t conn_id, uint16_t handle) {
- VLOG(1) << __func__
- << StringPrintf(" conn_id=%d handle=0x%x", conn_id, handle);
+ VLOG(1) << __func__ << " conn_id=" << loghex(conn_id)
+ << ", handle=" << loghex(handle);
tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(GATT_GET_TCB_IDX(conn_id));
if (!p_tcb) {
- LOG(ERROR) << StringPrintf(" Unknown conn_id: %u", conn_id);
+ LOG(ERROR) << "Unknown conn_id=" << loghex(conn_id);
return GATT_ILLEGAL_PARAMETER;
}
if (p_tcb->ind_count == 0) {
- VLOG(1) << " conn_id: " << +conn_id
+ VLOG(1) << " conn_id: " << loghex(conn_id)
<< " ignored not waiting for indicaiton ack";
return GATT_SUCCESS;
}
@@ -904,10 +903,9 @@
******************************************************************************/
void GATT_SetIdleTimeout(const RawAddress& bd_addr, uint16_t idle_tout,
tBT_TRANSPORT transport) {
- tGATT_TCB* p_tcb;
bool status = false;
- p_tcb = gatt_find_tcb_by_addr(bd_addr, transport);
+ tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, transport);
if (p_tcb != NULL) {
if (p_tcb->att_lcid == L2CAP_ATT_CID) {
status = L2CA_SetFixedChannelTout(bd_addr, L2CAP_ATT_CID, idle_tout);
@@ -921,9 +919,8 @@
}
}
- VLOG(1) << __func__
- << StringPrintf(" idle_tout=%d status=%d(1-OK 0-not performed)",
- idle_tout, status);
+ VLOG(1) << __func__ << " idle_tout=" << idle_tout << ", status=" << +status
+ << " (1-OK 0-not performed)";
}
/*******************************************************************************
@@ -992,7 +989,7 @@
tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
/* Index 0 is GAP and is never deregistered */
if ((gatt_if == 0) || (p_reg == NULL)) {
- LOG(ERROR) << "invalid gatt_if: " << +gatt_if;
+ LOG(ERROR) << "invalid gatt_if=" << +gatt_if;
return;
}
@@ -1001,7 +998,8 @@
other application
deregisteration need to bed performed in an orderly fashion
no check for now */
- for (auto it = gatt_cb.srv_list_info->begin(); it != gatt_cb.srv_list_info->end(); ) {
+ for (auto it = gatt_cb.srv_list_info->begin();
+ it != gatt_cb.srv_list_info->end();) {
if (it->gatt_if == gatt_if) {
GATTS_StopService(it++->s_hdl);
} else {
@@ -1017,25 +1015,24 @@
tGATT_TCB* p_tcb;
int i, j;
for (i = 0, p_tcb = gatt_cb.tcb; i < GATT_MAX_PHY_CHANNEL; i++, p_tcb++) {
- if (p_tcb->in_use) {
- if (gatt_get_ch_state(p_tcb) != GATT_CH_CLOSE) {
- gatt_update_app_use_link_flag(gatt_if, p_tcb, false, true);
- }
+ if (!p_tcb->in_use) continue;
- tGATT_CLCB* p_clcb;
- for (j = 0, p_clcb = &gatt_cb.clcb[j]; j < GATT_CL_MAX_LCB;
- j++, p_clcb++) {
- if (p_clcb->in_use && (p_clcb->p_reg->gatt_if == gatt_if) &&
- (p_clcb->p_tcb->tcb_idx == p_tcb->tcb_idx)) {
- alarm_cancel(p_clcb->gatt_rsp_timer_ent);
- gatt_clcb_dealloc(p_clcb);
- break;
- }
+ if (gatt_get_ch_state(p_tcb) != GATT_CH_CLOSE) {
+ gatt_update_app_use_link_flag(gatt_if, p_tcb, false, true);
+ }
+
+ tGATT_CLCB* p_clcb;
+ for (j = 0, p_clcb = &gatt_cb.clcb[j]; j < GATT_CL_MAX_LCB; j++, p_clcb++) {
+ if (p_clcb->in_use && (p_clcb->p_reg->gatt_if == gatt_if) &&
+ (p_clcb->p_tcb->tcb_idx == p_tcb->tcb_idx)) {
+ alarm_cancel(p_clcb->gatt_rsp_timer_ent);
+ gatt_clcb_dealloc(p_clcb);
+ break;
}
}
}
- gatt_deregister_bgdev_list(gatt_if);
+ connection_manager::on_app_deregistered(gatt_if);
memset(p_reg, 0, sizeof(tGATT_REG));
}
@@ -1061,7 +1058,7 @@
uint16_t conn_id;
tGATT_TRANSPORT transport;
- VLOG(1) << __func__ << " gatt_if=" << gatt_if;
+ VLOG(1) << __func__ << " gatt_if=" << +gatt_if;
p_reg = gatt_get_regcb(gatt_if);
if (p_reg != NULL) {
start_idx = 0;
@@ -1103,30 +1100,46 @@
bool GATT_Connect(tGATT_IF gatt_if, const RawAddress& bd_addr, bool is_direct,
tBT_TRANSPORT transport, bool opportunistic,
uint8_t initiating_phys) {
- tGATT_REG* p_reg;
- bool status = false;
-
- LOG(INFO) << __func__ << "gatt_if=" << +gatt_if << " " << bd_addr;
+ LOG(INFO) << __func__ << "gatt_if=" << +gatt_if << ", address=" << bd_addr;
/* Make sure app is registered */
- p_reg = gatt_get_regcb(gatt_if);
- if (p_reg == NULL) {
- LOG(ERROR) << "gatt_if = " << gatt_if << " is not registered";
- return (false);
+ tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
+ if (!p_reg) {
+ LOG(ERROR) << "gatt_if = " << +gatt_if << " is not registered";
+ return false;
}
- if (is_direct)
- status = gatt_act_connect(p_reg, bd_addr, transport, opportunistic,
- initiating_phys);
- else {
- if (transport == BT_TRANSPORT_LE)
- status = gatt_update_auto_connect_dev(gatt_if, true, bd_addr);
- else {
- LOG(ERROR) << "Unsupported transport for background connection";
+ if (!is_direct && transport != BT_TRANSPORT_LE) {
+ LOG(ERROR) << "Unsupported transport for background connection";
+ return false;
+ }
+
+ if (opportunistic) {
+ LOG(INFO) << __func__ << " opportunistic connection";
+ return true;
+ }
+
+ bool ret;
+ if (is_direct) {
+ ret = gatt_act_connect(p_reg, bd_addr, transport, initiating_phys);
+ } else {
+ if (!BTM_BackgroundConnectAddressKnown(bd_addr)) {
+ // RPA can rotate, causing address to "expire" in the background
+ // connection list. RPA is allowed for direct connect, as such request
+ // times out after 30 seconds
+ LOG(INFO) << "Can't add RPA to background connection.";
+ ret = true;
+ } else {
+ ret = connection_manager::background_connect_add(gatt_if, bd_addr);
}
}
- return status;
+ tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, transport);
+ // background connections don't necessarily create tcb
+ if (p_tcb && ret)
+ gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, true, !is_direct);
+
+ return ret;
}
/*******************************************************************************
@@ -1146,42 +1159,39 @@
******************************************************************************/
bool GATT_CancelConnect(tGATT_IF gatt_if, const RawAddress& bd_addr,
bool is_direct) {
- LOG(INFO) << __func__ << ": gatt_if=" << +gatt_if;
+ LOG(INFO) << __func__ << ": gatt_if:" << +gatt_if << ", address: " << bd_addr
+ << ", direct:" << is_direct;
- if (gatt_if && !gatt_get_regcb(gatt_if)) {
- LOG(ERROR) << "gatt_if =" << +gatt_if << " is not registered";
- return false;
- }
-
- if (is_direct) {
- if (gatt_if) {
- return gatt_cancel_open(gatt_if, bd_addr);
- }
-
- VLOG(1) << " unconditional";
- /* only LE connection can be cancelled */
- tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE);
- if (!p_tcb || p_tcb->app_hold_link.empty()) {
- LOG(ERROR) << __func__ << " no app found";
+ tGATT_REG* p_reg;
+ if (gatt_if) {
+ p_reg = gatt_get_regcb(gatt_if);
+ if (!p_reg) {
+ LOG(ERROR) << "gatt_if=" << +gatt_if << " is not registered";
return false;
}
+ if (is_direct)
+ return gatt_cancel_open(gatt_if, bd_addr);
+ else
+ return gatt_auto_connect_dev_remove(p_reg->gatt_if, bd_addr);
+ }
+
+ VLOG(1) << " unconditional";
+
+ /* only LE connection can be cancelled */
+ tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE);
+ if (p_tcb && !p_tcb->app_hold_link.empty()) {
for (auto it = p_tcb->app_hold_link.begin();
it != p_tcb->app_hold_link.end();) {
auto next = std::next(it);
// gatt_cancel_open modifies the app_hold_link.
- if (!gatt_cancel_open(*it, bd_addr)) return false;
+ gatt_cancel_open(*it, bd_addr);
it = next;
}
-
- return true;
}
- // is not direct
- if (gatt_if) return gatt_remove_bg_dev_for_app(gatt_if, bd_addr);
-
- if (!gatt_clear_bg_dev_for_addr(bd_addr)) {
+ if (!connection_manager::remove_unconditional(bd_addr)) {
LOG(ERROR)
<< __func__
<< ": no app associated with the bg device for unconditional removal";
@@ -1204,20 +1214,15 @@
*
******************************************************************************/
tGATT_STATUS GATT_Disconnect(uint16_t conn_id) {
- tGATT_STATUS ret = GATT_ILLEGAL_PARAMETER;
- tGATT_TCB* p_tcb = NULL;
- tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
+ LOG(INFO) << __func__ << " conn_id=" << loghex(conn_id);
+
uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
+ tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+ if (!p_tcb) return GATT_ILLEGAL_PARAMETER;
- LOG(INFO) << __func__ << " conn_id=" << +conn_id;
-
- p_tcb = gatt_get_tcb_by_idx(tcb_idx);
-
- if (p_tcb) {
- gatt_update_app_use_link_flag(gatt_if, p_tcb, false, true);
- ret = GATT_SUCCESS;
- }
- return ret;
+ tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
+ gatt_update_app_use_link_flag(gatt_if, p_tcb, false, true);
+ return GATT_SUCCESS;
}
/*******************************************************************************
@@ -1240,17 +1245,15 @@
tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
- bool status = false;
- VLOG(1) << __func__ << " conn_id=" << +conn_id;
+ VLOG(1) << __func__ << " conn_id=" << loghex(conn_id);
- if (p_tcb && p_reg) {
- bd_addr = p_tcb->peer_bda;
- *p_gatt_if = gatt_if;
- *p_transport = p_tcb->transport;
- status = true;
- }
- return status;
+ if (!p_tcb || !p_reg) return false;
+
+ bd_addr = p_tcb->peer_bda;
+ *p_gatt_if = gatt_if;
+ *p_transport = p_tcb->transport;
+ return true;
}
/*******************************************************************************
diff --git a/stack/gatt/gatt_attr.cc b/stack/gatt/gatt_attr.cc
index 75a8057..8861a7a 100644
--- a/stack/gatt/gatt_attr.cc
+++ b/stack/gatt/gatt_attr.cc
@@ -385,41 +385,35 @@
*
******************************************************************************/
static void gatt_cl_start_config_ccc(tGATT_PROFILE_CLCB* p_clcb) {
- tGATT_DISC_PARAM srvc_disc_param;
- tGATT_VALUE ccc_value;
VLOG(1) << __func__ << ": stage: " << +p_clcb->ccc_stage;
- memset(&srvc_disc_param, 0, sizeof(tGATT_DISC_PARAM));
- memset(&ccc_value, 0, sizeof(tGATT_VALUE));
-
switch (p_clcb->ccc_stage) {
case GATT_SVC_CHANGED_SERVICE: /* discover GATT service */
- srvc_disc_param.s_handle = 1;
- srvc_disc_param.e_handle = 0xffff;
- srvc_disc_param.service = Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER);
- GATTC_Discover(p_clcb->conn_id, GATT_DISC_SRVC_BY_UUID, &srvc_disc_param);
+ GATTC_Discover(p_clcb->conn_id, GATT_DISC_SRVC_BY_UUID, 0x0001, 0xffff,
+ Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER));
break;
case GATT_SVC_CHANGED_CHARACTERISTIC: /* discover service change char */
- srvc_disc_param.s_handle = 1;
- srvc_disc_param.e_handle = p_clcb->e_handle;
- srvc_disc_param.service = Uuid::From16Bit(GATT_UUID_GATT_SRV_CHGD);
- GATTC_Discover(p_clcb->conn_id, GATT_DISC_CHAR, &srvc_disc_param);
+ GATTC_Discover(p_clcb->conn_id, GATT_DISC_CHAR, 0x0001, p_clcb->e_handle,
+ Uuid::From16Bit(GATT_UUID_GATT_SRV_CHGD));
break;
case GATT_SVC_CHANGED_DESCRIPTOR: /* discover service change ccc */
- srvc_disc_param.s_handle = p_clcb->s_handle;
- srvc_disc_param.e_handle = p_clcb->e_handle;
- GATTC_Discover(p_clcb->conn_id, GATT_DISC_CHAR_DSCPT, &srvc_disc_param);
+ GATTC_Discover(p_clcb->conn_id, GATT_DISC_CHAR_DSCPT, p_clcb->s_handle,
+ p_clcb->e_handle);
break;
case GATT_SVC_CHANGED_CONFIGURE_CCCD: /* write ccc */
+ {
+ tGATT_VALUE ccc_value;
+ memset(&ccc_value, 0, sizeof(tGATT_VALUE));
ccc_value.handle = p_clcb->s_handle;
ccc_value.len = 2;
ccc_value.value[0] = GATT_CLT_CONFIG_INDICATION;
GATTC_Write(p_clcb->conn_id, GATT_WRITE, &ccc_value);
break;
+ }
}
}
diff --git a/stack/gatt/gatt_auth.cc b/stack/gatt/gatt_auth.cc
index 3794388..ba44c71 100644
--- a/stack/gatt/gatt_auth.cc
+++ b/stack/gatt/gatt_auth.cc
@@ -188,11 +188,13 @@
gatt_sec_check_complete(status, p_clcb, p_tcb->sec_act);
/* start all other pending operation in queue */
+ std::queue<tGATT_CLCB*> new_pending_clcbs;
while (!p_tcb->pending_enc_clcb.empty()) {
tGATT_CLCB* p_clcb = p_tcb->pending_enc_clcb.front();
p_tcb->pending_enc_clcb.pop();
- gatt_security_check_start(p_clcb);
+ if (gatt_security_check_start(p_clcb)) new_pending_clcbs.push(p_clcb);
}
+ p_tcb->pending_enc_clcb = new_pending_clcbs;
}
/*******************************************************************************
@@ -223,11 +225,13 @@
if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENC_PENDING) {
gatt_set_sec_act(p_tcb, GATT_SEC_NONE);
+ std::queue<tGATT_CLCB*> new_pending_clcbs;
while (!p_tcb->pending_enc_clcb.empty()) {
tGATT_CLCB* p_clcb = p_tcb->pending_enc_clcb.front();
p_tcb->pending_enc_clcb.pop();
- gatt_security_check_start(p_clcb);
+ if (gatt_security_check_start(p_clcb)) new_pending_clcbs.push(p_clcb);
}
+ p_tcb->pending_enc_clcb = new_pending_clcbs;
}
}
/*******************************************************************************
@@ -397,8 +401,8 @@
return status;
}
-/** check link security */
-void gatt_security_check_start(tGATT_CLCB* p_clcb) {
+/** check link security, return true if p_clcb should be added back to queue */
+bool gatt_security_check_start(tGATT_CLCB* p_clcb) {
tGATT_TCB* p_tcb = p_clcb->p_tcb;
tGATT_SEC_ACTION sec_act_old = gatt_get_sec_act(p_tcb);
@@ -430,17 +434,17 @@
gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
gatt_end_operation(p_clcb, GATT_INSUF_ENCRYPTION, NULL);
- return;
+ return false;
}
}
- p_tcb->pending_enc_clcb.push(p_clcb);
- break;
+ return true;
case GATT_SEC_ENC_PENDING:
- p_tcb->pending_enc_clcb.push(p_clcb);
/* wait for link encrypotion to finish */
- break;
+ return true;
default:
gatt_sec_check_complete(true, p_clcb, gatt_sec_act);
break;
}
+
+ return false;
}
diff --git a/stack/gatt/gatt_cl.cc b/stack/gatt/gatt_cl.cc
index dca4973..2650a30 100644
--- a/stack/gatt/gatt_cl.cc
+++ b/stack/gatt/gatt_cl.cc
@@ -297,7 +297,7 @@
bool gatt_check_write_long_terminate(tGATT_TCB& tcb, tGATT_CLCB* p_clcb,
tGATT_VALUE* p_rsp_value) {
tGATT_VALUE* p_attr = (tGATT_VALUE*)p_clcb->p_attr_buf;
- bool exec = false;
+ bool terminate = false;
tGATT_EXEC_FLAG flag = GATT_PREP_WRITE_EXEC;
VLOG(1) << __func__;
@@ -310,19 +310,18 @@
/* data does not match */
p_clcb->status = GATT_ERROR;
flag = GATT_PREP_WRITE_CANCEL;
- exec = true;
+ terminate = true;
} else /* response checking is good */
{
p_clcb->status = GATT_SUCCESS;
/* update write offset and check if end of attribute value */
- if ((p_attr->offset += p_rsp_value->len) >= p_attr->len) exec = true;
+ if ((p_attr->offset += p_rsp_value->len) >= p_attr->len) terminate = true;
}
}
- if (exec) {
+ if (terminate && p_clcb->op_subtype != GATT_WRITE_PREPARE) {
gatt_send_queue_write_cancel(tcb, p_clcb, flag);
- return true;
}
- return false;
+ return terminate;
}
/** Send prepare write */
@@ -586,15 +585,15 @@
memcpy(value.value, p, value.len);
+ if (!gatt_check_write_long_terminate(tcb, p_clcb, &value)) {
+ gatt_send_prepare_write(tcb, p_clcb);
+ return;
+ }
+
if (p_clcb->op_subtype == GATT_WRITE_PREPARE) {
- p_clcb->status = GATT_SUCCESS;
/* application should verify handle offset
and value are matched or not */
-
gatt_end_operation(p_clcb, p_clcb->status, &value);
- } else if (p_clcb->op_subtype == GATT_WRITE) {
- if (!gatt_check_write_long_terminate(tcb, p_clcb, &value))
- gatt_send_prepare_write(tcb, p_clcb);
}
}
/*******************************************************************************
diff --git a/stack/gatt/gatt_db.cc b/stack/gatt/gatt_db.cc
index 31a262d..2d0c5b0 100644
--- a/stack/gatt/gatt_db.cc
+++ b/stack/gatt/gatt_db.cc
@@ -601,10 +601,10 @@
break;
case GATT_UUID_CHAR_CLIENT_CONFIG:
- /* fall through */
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case GATT_UUID_CHAR_SRVR_CONFIG:
max_size = 2;
- /* fall through */
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case GATT_UUID_CHAR_DESCRIPTION:
default: /* any other must be character value declaration */
status = GATT_SUCCESS;
diff --git a/stack/gatt/gatt_int.h b/stack/gatt/gatt_int.h
index 5052918..2c00fd7 100644
--- a/stack/gatt/gatt_int.h
+++ b/stack/gatt/gatt_int.h
@@ -331,11 +331,6 @@
uint32_t service_change;
} tGATT_SVC_CHG;
-typedef struct {
- std::unordered_set<tGATT_IF> gatt_if;
- RawAddress remote_bda;
-} tGATT_BG_CONN_DEV;
-
#define GATT_SVC_CHANGED_CONNECTING 1 /* wait for connection */
#define GATT_SVC_CHANGED_SERVICE 2 /* GATT service discovery */
#define GATT_SVC_CHANGED_CHARACTERISTIC 3 /* service change char discovery */
@@ -386,7 +381,6 @@
tGATT_APPL_INFO cb_info;
tGATT_HDL_CFG hdl_cfg;
- std::list<tGATT_BG_CONN_DEV> bgconn_dev;
} tGATT_CB;
#define GATT_SIZE_OF_SRV_CHG_HNDL_RANGE 4
@@ -402,10 +396,10 @@
/* from gatt_main.cc */
extern bool gatt_disconnect(tGATT_TCB* p_tcb);
extern bool gatt_act_connect(tGATT_REG* p_reg, const RawAddress& bd_addr,
- tBT_TRANSPORT transport, bool opportunistic,
- int8_t initiating_phys);
+ tBT_TRANSPORT transport, int8_t initiating_phys);
extern bool gatt_connect(const RawAddress& rem_bda, tGATT_TCB* p_tcb,
- tBT_TRANSPORT transport, uint8_t initiating_phys);
+ tBT_TRANSPORT transport, uint8_t initiating_phys,
+ tGATT_IF gatt_if);
extern void gatt_data_process(tGATT_TCB& p_tcb, BT_HDR* p_buf);
extern void gatt_update_app_use_link_flag(tGATT_IF gatt_if, tGATT_TCB* p_tcb,
bool is_add, bool check_acl_link);
@@ -461,7 +455,7 @@
tBT_TRANSPORT* p_transport);
extern void gatt_set_srv_chg(void);
extern void gatt_delete_dev_from_srv_chg_clt_list(const RawAddress& bd_addr);
-extern tGATT_VALUE* gatt_add_pending_ind(tGATT_TCB* p_tcb, tGATT_VALUE* p_ind);
+extern void gatt_add_pending_ind(tGATT_TCB* p_tcb, tGATT_VALUE* p_ind);
extern void gatt_free_srvc_db_buffer_app_id(const bluetooth::Uuid& app_id);
extern bool gatt_cl_send_next_cmd_inq(tGATT_TCB& tcb);
@@ -473,14 +467,8 @@
extern tGATTS_SRV_CHG* gatt_add_srv_chg_clt(tGATTS_SRV_CHG* p_srv_chg);
/* for background connection */
-extern bool gatt_update_auto_connect_dev(tGATT_IF gatt_if, bool add,
+extern bool gatt_auto_connect_dev_remove(tGATT_IF gatt_if,
const RawAddress& bd_addr);
-extern bool gatt_is_bg_dev_for_app(tGATT_BG_CONN_DEV* p_dev, tGATT_IF gatt_if);
-extern bool gatt_remove_bg_dev_for_app(tGATT_IF gatt_if,
- const RawAddress& bd_addr);
-extern uint8_t gatt_clear_bg_dev_for_addr(const RawAddress& bd_addr);
-extern tGATT_BG_CONN_DEV* gatt_find_bg_dev(const RawAddress& remote_bda);
-extern void gatt_deregister_bgdev_list(tGATT_IF gatt_if);
/* server function */
extern std::list<tGATT_SRV_LIST_ELEM>::iterator gatt_sr_find_i_rcb_by_handle(
@@ -548,7 +536,7 @@
tGATT_EXEC_FLAG flag);
/* gatt_auth.cc */
-extern void gatt_security_check_start(tGATT_CLCB* p_clcb);
+extern bool gatt_security_check_start(tGATT_CLCB* p_clcb);
extern void gatt_verify_signature(tGATT_TCB& tcb, BT_HDR* p_buf);
extern tGATT_STATUS gatt_get_link_encrypt_status(tGATT_TCB& tcb);
extern tGATT_SEC_ACTION gatt_get_sec_act(tGATT_TCB* p_tcb);
diff --git a/stack/gatt/gatt_main.cc b/stack/gatt/gatt_main.cc
index afae25f..87bae6e 100644
--- a/stack/gatt/gatt_main.cc
+++ b/stack/gatt/gatt_main.cc
@@ -29,6 +29,7 @@
#include "btif_storage.h"
#include "btm_ble_int.h"
#include "btm_int.h"
+#include "connection_manager.h"
#include "device/include/interop.h"
#include "gatt_int.h"
#include "l2c_api.h"
@@ -101,6 +102,7 @@
VLOG(1) << __func__;
gatt_cb = tGATT_CB();
+ connection_manager::reset(true);
memset(&fixed_reg, 0, sizeof(tL2CAP_FIXED_CHNL_REG));
gatt_cb.def_mtu_size = GATT_DEF_BLE_MTU_SIZE;
@@ -192,21 +194,40 @@
*
******************************************************************************/
bool gatt_connect(const RawAddress& rem_bda, tGATT_TCB* p_tcb,
- tBT_TRANSPORT transport, uint8_t initiating_phys) {
- bool gatt_ret = false;
-
+ tBT_TRANSPORT transport, uint8_t initiating_phys,
+ tGATT_IF gatt_if) {
if (gatt_get_ch_state(p_tcb) != GATT_CH_OPEN)
gatt_set_ch_state(p_tcb, GATT_CH_CONN);
- if (transport == BT_TRANSPORT_LE) {
- p_tcb->att_lcid = L2CAP_ATT_CID;
- gatt_ret = L2CA_ConnectFixedChnl(L2CAP_ATT_CID, rem_bda, initiating_phys);
- } else {
+ if (transport != BT_TRANSPORT_LE) {
p_tcb->att_lcid = L2CA_ConnectReq(BT_PSM_ATT, rem_bda);
- if (p_tcb->att_lcid != 0) gatt_ret = true;
+ return p_tcb->att_lcid != 0;
}
- return gatt_ret;
+ // Already connected, send the callback, mark the link as used
+ if (gatt_get_ch_state(p_tcb) == GATT_CH_OPEN) {
+ /* very similar to gatt_send_conn_cback, but no good way to reuse the code
+ */
+
+ /* notifying application about the connection up event */
+ for (int i = 0; i < GATT_MAX_APPS; i++) {
+ tGATT_REG* p_reg = &gatt_cb.cl_rcb[i];
+
+ if (!p_reg->in_use || p_reg->gatt_if != gatt_if) continue;
+
+ gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, true, true);
+ if (p_reg->app_cb.p_conn_cb) {
+ uint16_t conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if);
+ (*p_reg->app_cb.p_conn_cb)(p_reg->gatt_if, p_tcb->peer_bda, conn_id,
+ true, 0, p_tcb->transport);
+ }
+ }
+
+ return true;
+ }
+
+ p_tcb->att_lcid = L2CAP_ATT_CID;
+ return connection_manager::direct_connect_add(gatt_if, rem_bda);
}
/*******************************************************************************
@@ -222,33 +243,32 @@
*
******************************************************************************/
bool gatt_disconnect(tGATT_TCB* p_tcb) {
- bool ret = false;
- tGATT_CH_STATE ch_state;
-
VLOG(1) << __func__;
- if (p_tcb != NULL) {
- ret = true;
- ch_state = gatt_get_ch_state(p_tcb);
- if (ch_state != GATT_CH_CLOSING) {
- if (p_tcb->att_lcid == L2CAP_ATT_CID) {
- if (ch_state == GATT_CH_OPEN) {
- /* only LCB exist between remote device and local */
- ret = L2CA_RemoveFixedChnl(L2CAP_ATT_CID, p_tcb->peer_bda);
- } else {
- ret = L2CA_CancelBleConnectReq(p_tcb->peer_bda);
- if (!ret) gatt_set_ch_state(p_tcb, GATT_CH_CLOSE);
- }
- gatt_set_ch_state(p_tcb, GATT_CH_CLOSING);
- } else {
- if ((ch_state == GATT_CH_OPEN) || (ch_state == GATT_CH_CFG))
- ret = L2CA_DisconnectReq(p_tcb->att_lcid);
- else
- VLOG(1) << __func__ << " gatt_disconnect channel not opened";
- }
+ if (!p_tcb) return false;
+
+ tGATT_CH_STATE ch_state = gatt_get_ch_state(p_tcb);
+ if (ch_state == GATT_CH_CLOSING) {
+ VLOG(1) << __func__ << " already in closing state";
+ return true;
+ }
+
+ bool ret = true;
+ if (p_tcb->att_lcid == L2CAP_ATT_CID) {
+ if (ch_state == GATT_CH_OPEN) {
+ /* only LCB exist between remote device and local */
+ ret = L2CA_RemoveFixedChnl(L2CAP_ATT_CID, p_tcb->peer_bda);
} else {
- VLOG(1) << __func__ << " already in closing state";
+ L2CA_CancelBleConnectReq(p_tcb->peer_bda);
+ gatt_cleanup_upon_disc(p_tcb->peer_bda, HCI_ERR_CONN_CAUSE_LOCAL_HOST, p_tcb->transport);
+ return true;
}
+ gatt_set_ch_state(p_tcb, GATT_CH_CLOSING);
+ } else {
+ if ((ch_state == GATT_CH_OPEN) || (ch_state == GATT_CH_CFG))
+ ret = L2CA_DisconnectReq(p_tcb->att_lcid);
+ else
+ VLOG(1) << __func__ << " gatt_disconnect channel not opened";
}
return ret;
@@ -311,97 +331,85 @@
// device, skip updating the device state.
if (!gatt_update_app_hold_link_status(gatt_if, p_tcb, is_add)) return;
- if (!check_acl_link ||
- p_tcb->att_lcid !=
- L2CAP_ATT_CID || /* only update link idle timer for fixed channel */
- (BTM_GetHCIConnHandle(p_tcb->peer_bda, p_tcb->transport) ==
- GATT_INVALID_ACL_HANDLE)) {
+ if (!check_acl_link) {
return;
}
+ bool is_valid_handle =
+ (BTM_GetHCIConnHandle(p_tcb->peer_bda, p_tcb->transport) !=
+ GATT_INVALID_ACL_HANDLE);
+
if (is_add) {
- VLOG(1) << "disable link idle timer";
- /* acl link is connected disable the idle timeout */
- GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_NO_IDLE_TIMEOUT,
- p_tcb->transport);
- } else {
- if (p_tcb->app_hold_link.empty()) {
- /* acl link is connected but no application needs to use the link
- so set the timeout value to GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP seconds
- */
- VLOG(1) << " start link idle timer = "
- << GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP << " sec";
- GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP,
+ if (p_tcb->att_lcid == L2CAP_ATT_CID && is_valid_handle) {
+ VLOG(1) << "disable link idle timer";
+ /* acl link is connected disable the idle timeout */
+ GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_NO_IDLE_TIMEOUT,
p_tcb->transport);
}
+ } else {
+ if (p_tcb->app_hold_link.empty()) {
+ // acl link is connected but no application needs to use the link
+ if (p_tcb->att_lcid == L2CAP_ATT_CID && is_valid_handle) {
+ /* for fixed channel, set the timeout value to
+ GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP seconds */
+ VLOG(1) << " start link idle timer = "
+ << GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP << " sec";
+ GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP,
+ p_tcb->transport);
+ } else
+ // disconnect the dynamic channel
+ gatt_disconnect(p_tcb);
+ }
}
}
-/*******************************************************************************
- *
- * Function gatt_act_connect
- *
- * Description GATT connection initiation.
- *
- * Returns void.
- *
- ******************************************************************************/
+/** GATT connection initiation */
bool gatt_act_connect(tGATT_REG* p_reg, const RawAddress& bd_addr,
- tBT_TRANSPORT transport, bool opportunistic,
- int8_t initiating_phys) {
- bool ret = false;
- tGATT_TCB* p_tcb;
- uint8_t st;
-
- p_tcb = gatt_find_tcb_by_addr(bd_addr, transport);
+ tBT_TRANSPORT transport, int8_t initiating_phys) {
+ tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, transport);
if (p_tcb != NULL) {
- ret = true;
- st = gatt_get_ch_state(p_tcb);
-
/* before link down, another app try to open a GATT connection */
+ uint8_t st = gatt_get_ch_state(p_tcb);
if (st == GATT_CH_OPEN && p_tcb->app_hold_link.empty() &&
transport == BT_TRANSPORT_LE) {
- if (!gatt_connect(bd_addr, p_tcb, transport, initiating_phys))
- ret = false;
+ if (!gatt_connect(bd_addr, p_tcb, transport, initiating_phys,
+ p_reg->gatt_if))
+ return false;
} else if (st == GATT_CH_CLOSING) {
+ LOG(INFO) << "Must finish disconnection before new connection";
/* need to complete the closing first */
- ret = false;
+ return false;
}
- } else {
- p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr, transport);
- if (p_tcb != NULL) {
- if (!gatt_connect(bd_addr, p_tcb, transport, initiating_phys)) {
- LOG(ERROR) << "gatt_connect failed";
- fixed_queue_free(p_tcb->pending_ind_q, NULL);
- *p_tcb = tGATT_TCB();
- } else
- ret = true;
- } else {
- ret = 0;
- LOG(ERROR) << "Max TCB for gatt_if [ " << +p_reg->gatt_if << "] reached.";
- }
+
+ return true;
}
- if (ret) {
- if (!opportunistic)
- gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, true, false);
- else
- VLOG(1) << __func__
- << ": connection is opportunistic, not updating app usage";
+ p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr, transport);
+ if (!p_tcb) {
+ LOG(ERROR) << "Max TCB for gatt_if [ " << +p_reg->gatt_if << "] reached.";
+ return false;
}
- return ret;
+ if (!gatt_connect(bd_addr, p_tcb, transport, initiating_phys,
+ p_reg->gatt_if)) {
+ LOG(ERROR) << "gatt_connect failed";
+ fixed_queue_free(p_tcb->pending_ind_q, NULL);
+ *p_tcb = tGATT_TCB();
+ return false;
+ }
+
+ return true;
}
-/*******************************************************************************
- *
- * Function gatt_le_connect_cback
- *
- * Description This callback function is called by L2CAP to indicate that
- * the ATT fixed channel for LE is
- * connected (conn = true)/disconnected (conn = false).
- *
- ******************************************************************************/
+namespace connection_manager {
+void on_connection_timed_out(uint8_t app_id, const RawAddress& address) {
+ gatt_le_connect_cback(L2CAP_ATT_CID, address, false, 0xff, BT_TRANSPORT_LE);
+}
+} // namespace connection_manager
+
+/** This callback function is called by L2CAP to indicate that the ATT fixed
+ * channel for LE is connected (conn = true)/disconnected (conn = false).
+ */
static void gatt_le_connect_cback(uint16_t chan, const RawAddress& bd_addr,
bool connected, uint16_t reason,
tBT_TRANSPORT transport) {
@@ -423,54 +431,47 @@
gatt_add_a_bonded_dev_for_srv_chg(bd_addr);
}
- if (connected) {
- /* do we have a channel initiating a connection? */
- if (p_tcb) {
- /* we are initiating connection */
- if (gatt_get_ch_state(p_tcb) == GATT_CH_CONN) {
- /* send callback */
- gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
- p_tcb->payload_size = GATT_DEF_BLE_MTU_SIZE;
-
- gatt_send_conn_cback(p_tcb);
- }
- if (check_srv_chg) gatt_chk_srv_chg(p_srv_chg_clt);
- }
- /* this is incoming connection or background connection callback */
-
- else {
- p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr, BT_TRANSPORT_LE);
- if (p_tcb != NULL) {
- p_tcb->att_lcid = L2CAP_ATT_CID;
-
- gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
-
- p_tcb->payload_size = GATT_DEF_BLE_MTU_SIZE;
-
- gatt_send_conn_cback(p_tcb);
- if (check_srv_chg) {
- gatt_chk_srv_chg(p_srv_chg_clt);
- }
- } else {
- LOG(ERROR) << "CCB max out, no rsources";
- }
- }
- } else {
+ if (!connected) {
gatt_cleanup_upon_disc(bd_addr, reason, transport);
VLOG(1) << "ATT disconnected";
+ return;
+ }
+
+ /* do we have a channel initiating a connection? */
+ if (p_tcb) {
+ /* we are initiating connection */
+ if (gatt_get_ch_state(p_tcb) == GATT_CH_CONN) {
+ /* send callback */
+ gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
+ p_tcb->payload_size = GATT_DEF_BLE_MTU_SIZE;
+
+ gatt_send_conn_cback(p_tcb);
+ }
+ if (check_srv_chg) gatt_chk_srv_chg(p_srv_chg_clt);
+ }
+ /* this is incoming connection or background connection callback */
+
+ else {
+ p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr, BT_TRANSPORT_LE);
+ if (!p_tcb) {
+ LOG(ERROR) << "CCB max out, no rsources";
+ return;
+ }
+
+ p_tcb->att_lcid = L2CAP_ATT_CID;
+
+ gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
+
+ p_tcb->payload_size = GATT_DEF_BLE_MTU_SIZE;
+
+ gatt_send_conn_cback(p_tcb);
+ if (check_srv_chg) {
+ gatt_chk_srv_chg(p_srv_chg_clt);
+ }
}
}
-/*******************************************************************************
- *
- * Function gatt_channel_congestion
- *
- * Description This function is called to process the congestion callback
- * from lcb
- *
- * Returns void
- *
- ******************************************************************************/
+/** This function is called to process the congestion callback from lcb */
static void gatt_channel_congestion(tGATT_TCB* p_tcb, bool congested) {
uint8_t i = 0;
tGATT_REG* p_reg = NULL;
@@ -501,7 +502,7 @@
tGATT_TCB* p_tcb =
gatt_find_tcb_by_addr(p_dev_rec->ble.pseudo_addr, BT_TRANSPORT_LE);
- if (p_tcb == NULL) return;
+ if (!p_tcb) return;
for (int i = 0; i < GATT_MAX_APPS; i++) {
tGATT_REG* p_reg = &gatt_cb.cl_rcb[i];
@@ -517,13 +518,11 @@
uint16_t latency, uint16_t timeout,
uint8_t status) {
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(handle);
- if (!p_dev_rec) {
- return;
- }
+ if (!p_dev_rec) return;
tGATT_TCB* p_tcb =
gatt_find_tcb_by_addr(p_dev_rec->ble.pseudo_addr, BT_TRANSPORT_LE);
- if (p_tcb == NULL) return;
+ if (!p_tcb) return;
for (int i = 0; i < GATT_MAX_APPS; i++) {
tGATT_REG* p_reg = &gatt_cb.cl_rcb[i];
@@ -535,23 +534,14 @@
}
}
-/*******************************************************************************
- *
- * Function gatt_le_cong_cback
- *
- * Description This function is called when GATT fixed channel is congested
- * or uncongested.
- *
- * Returns void
- *
- ******************************************************************************/
+/** This function is called when GATT fixed channel is congested or uncongested
+ */
static void gatt_le_cong_cback(const RawAddress& remote_bda, bool congested) {
tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(remote_bda, BT_TRANSPORT_LE);
+ if (!p_tcb) return;
/* if uncongested, check to see if there is any more pending data */
- if (p_tcb != NULL) {
gatt_channel_congestion(p_tcb, congested);
- }
}
/*******************************************************************************
@@ -572,10 +562,10 @@
******************************************************************************/
static void gatt_le_data_ind(uint16_t chan, const RawAddress& bd_addr,
BT_HDR* p_buf) {
- tGATT_TCB* p_tcb;
/* Find CCB based on bd addr */
- if ((p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE)) != NULL) {
+ tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE);
+ if (p_tcb) {
if (gatt_get_ch_state(p_tcb) < GATT_CH_OPEN) {
LOG(WARNING) << "ATT - Ignored L2CAP data while in state: "
<< +gatt_get_ch_state(p_tcb);
@@ -600,13 +590,11 @@
static void gatt_l2cif_connect_ind_cback(const RawAddress& bd_addr,
uint16_t lcid,
UNUSED_ATTR uint16_t psm, uint8_t id) {
- /* do we already have a control channel for this peer? */
uint8_t result = L2CAP_CONN_OK;
- tL2CAP_CFG_INFO cfg;
- tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_BR_EDR);
+ LOG(INFO) << "Connection indication cid = " << +lcid;
- LOG(ERROR) << "Connection indication cid = " << +lcid;
/* new connection ? */
+ tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_BR_EDR);
if (p_tcb == NULL) {
/* allocate tcb */
p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr, BT_TRANSPORT_BR_EDR);
@@ -625,253 +613,192 @@
L2CA_ConnectRsp(bd_addr, id, lcid, result, 0);
/* if result ok, proceed with connection */
- if (result == L2CAP_CONN_OK) {
- /* transition to configuration state */
- gatt_set_ch_state(p_tcb, GATT_CH_CFG);
+ if (result != L2CAP_CONN_OK) return;
- /* Send L2CAP config req */
- memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
- cfg.mtu_present = true;
- cfg.mtu = GATT_MAX_MTU_SIZE;
+ /* transition to configuration state */
+ gatt_set_ch_state(p_tcb, GATT_CH_CFG);
- L2CA_ConfigReq(lcid, &cfg);
- }
+ /* Send L2CAP config req */
+ tL2CAP_CFG_INFO cfg;
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.mtu_present = true;
+ cfg.mtu = GATT_MAX_MTU_SIZE;
+
+ L2CA_ConfigReq(lcid, &cfg);
}
-/*******************************************************************************
- *
- * Function gatt_l2c_connect_cfm_cback
- *
- * Description This is the L2CAP connect confirm callback function.
- *
- *
- * Returns void
- *
- ******************************************************************************/
+/** This is the L2CAP connect confirm callback function */
static void gatt_l2cif_connect_cfm_cback(uint16_t lcid, uint16_t result) {
tGATT_TCB* p_tcb;
tL2CAP_CFG_INFO cfg;
/* look up clcb for this channel */
p_tcb = gatt_find_tcb_by_cid(lcid);
- if (p_tcb != NULL) {
- VLOG(1) << __func__
- << StringPrintf(" result: %d ch_state: %d, lcid:0x%x", result,
- gatt_get_ch_state(p_tcb), p_tcb->att_lcid);
+ if (!p_tcb) return;
- /* if in correct state */
- if (gatt_get_ch_state(p_tcb) == GATT_CH_CONN) {
- /* if result successful */
- if (result == L2CAP_CONN_OK) {
- /* set channel state */
- gatt_set_ch_state(p_tcb, GATT_CH_CFG);
+ VLOG(1) << __func__
+ << StringPrintf(" result: %d ch_state: %d, lcid:0x%x", result,
+ gatt_get_ch_state(p_tcb), p_tcb->att_lcid);
- /* Send L2CAP config req */
- memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
- cfg.mtu_present = true;
- cfg.mtu = GATT_MAX_MTU_SIZE;
- L2CA_ConfigReq(lcid, &cfg);
- }
- /* else initiating connection failure */
- else {
- gatt_cleanup_upon_disc(p_tcb->peer_bda, result, GATT_TRANSPORT_BR_EDR);
- }
- } else /* wrong state, disconnect it */
- {
- if (result == L2CAP_CONN_OK) {
- /* just in case the peer also accepts our connection - Send L2CAP
- * disconnect req */
- L2CA_DisconnectReq(lcid);
- }
+ /* if in correct state */
+ if (gatt_get_ch_state(p_tcb) == GATT_CH_CONN) {
+ /* if result successful */
+ if (result == L2CAP_CONN_OK) {
+ /* set channel state */
+ gatt_set_ch_state(p_tcb, GATT_CH_CFG);
+
+ /* Send L2CAP config req */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.mtu_present = true;
+ cfg.mtu = GATT_MAX_MTU_SIZE;
+ L2CA_ConfigReq(lcid, &cfg);
+ }
+ /* else initiating connection failure */
+ else {
+ gatt_cleanup_upon_disc(p_tcb->peer_bda, result, GATT_TRANSPORT_BR_EDR);
+ }
+ } else /* wrong state, disconnect it */
+ {
+ if (result == L2CAP_CONN_OK) {
+ /* just in case the peer also accepts our connection - Send L2CAP
+ * disconnect req */
+ L2CA_DisconnectReq(lcid);
}
}
}
-/*******************************************************************************
- *
- * Function gatt_l2cif_config_cfm_cback
- *
- * Description This is the L2CAP config confirm callback function.
- *
- *
- * Returns void
- *
- ******************************************************************************/
+/** This is the L2CAP config confirm callback function */
void gatt_l2cif_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
- tGATT_TCB* p_tcb;
- tGATTS_SRV_CHG* p_srv_chg_clt = NULL;
/* look up clcb for this channel */
- p_tcb = gatt_find_tcb_by_cid(lcid);
- if (p_tcb != NULL) {
- /* if in correct state */
- if (gatt_get_ch_state(p_tcb) == GATT_CH_CFG) {
- /* if result successful */
- if (p_cfg->result == L2CAP_CFG_OK) {
- /* update flags */
- p_tcb->ch_flags |= GATT_L2C_CFG_CFM_DONE;
+ tGATT_TCB* p_tcb = gatt_find_tcb_by_cid(lcid);
+ if (!p_tcb) return;
- /* if configuration complete */
- if (p_tcb->ch_flags & GATT_L2C_CFG_IND_DONE) {
- gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
+ /* if in incorrect state */
+ if (gatt_get_ch_state(p_tcb) != GATT_CH_CFG) return;
- p_srv_chg_clt = gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda);
- if (p_srv_chg_clt != NULL) {
- gatt_chk_srv_chg(p_srv_chg_clt);
- } else {
- if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda))
- gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
- }
-
- /* send callback */
- gatt_send_conn_cback(p_tcb);
- }
- }
- /* else failure */
- else {
- /* Send L2CAP disconnect req */
- L2CA_DisconnectReq(lcid);
- }
- }
+ /* if result not successful */
+ if (p_cfg->result != L2CAP_CFG_OK) {
+ /* Send L2CAP disconnect req */
+ L2CA_DisconnectReq(lcid);
+ return;
}
+
+ /* update flags */
+ p_tcb->ch_flags |= GATT_L2C_CFG_CFM_DONE;
+
+ /* if configuration not complete */
+ if (!(p_tcb->ch_flags & GATT_L2C_CFG_IND_DONE)) return;
+
+ gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
+
+ tGATTS_SRV_CHG* p_srv_chg_clt =
+ gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda);
+ if (p_srv_chg_clt != NULL) {
+ gatt_chk_srv_chg(p_srv_chg_clt);
+ } else {
+ if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda))
+ gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
+ }
+
+ /* send callback */
+ gatt_send_conn_cback(p_tcb);
}
-/*******************************************************************************
- *
- * Function gatt_l2cif_config_ind_cback
- *
- * Description This is the L2CAP config indication callback function.
- *
- *
- * Returns void
- *
- ******************************************************************************/
+/** This is the L2CAP config indication callback function */
void gatt_l2cif_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
- tGATT_TCB* p_tcb;
tGATTS_SRV_CHG* p_srv_chg_clt = NULL;
/* look up clcb for this channel */
- p_tcb = gatt_find_tcb_by_cid(lcid);
- if (p_tcb != NULL) {
- /* GATT uses the smaller of our MTU and peer's MTU */
- if (p_cfg->mtu_present &&
- (p_cfg->mtu >= GATT_MIN_BR_MTU_SIZE && p_cfg->mtu < L2CAP_DEFAULT_MTU))
- p_tcb->payload_size = p_cfg->mtu;
- else
- p_tcb->payload_size = L2CAP_DEFAULT_MTU;
+ tGATT_TCB* p_tcb = gatt_find_tcb_by_cid(lcid);
+ if (!p_tcb) return;
- /* send L2CAP configure response */
- memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
- p_cfg->result = L2CAP_CFG_OK;
- L2CA_ConfigRsp(lcid, p_cfg);
+ /* GATT uses the smaller of our MTU and peer's MTU */
+ if (p_cfg->mtu_present &&
+ (p_cfg->mtu >= GATT_MIN_BR_MTU_SIZE && p_cfg->mtu < L2CAP_DEFAULT_MTU))
+ p_tcb->payload_size = p_cfg->mtu;
+ else
+ p_tcb->payload_size = L2CAP_DEFAULT_MTU;
- /* if first config ind */
- if ((p_tcb->ch_flags & GATT_L2C_CFG_IND_DONE) == 0) {
- /* update flags */
- p_tcb->ch_flags |= GATT_L2C_CFG_IND_DONE;
+ /* send L2CAP configure response */
+ memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ p_cfg->result = L2CAP_CFG_OK;
+ L2CA_ConfigRsp(lcid, p_cfg);
- /* if configuration complete */
- if (p_tcb->ch_flags & GATT_L2C_CFG_CFM_DONE) {
- gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
- p_srv_chg_clt = gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda);
- if (p_srv_chg_clt != NULL) {
- gatt_chk_srv_chg(p_srv_chg_clt);
- } else {
- if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda))
- gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
- }
+ /* if not first config ind */
+ if ((p_tcb->ch_flags & GATT_L2C_CFG_IND_DONE)) return;
- /* send callback */
- gatt_send_conn_cback(p_tcb);
- }
- }
+ /* update flags */
+ p_tcb->ch_flags |= GATT_L2C_CFG_IND_DONE;
+
+ /* if configuration not complete */
+ if ((p_tcb->ch_flags & GATT_L2C_CFG_CFM_DONE) == 0) return;
+
+ gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
+ p_srv_chg_clt = gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda);
+ if (p_srv_chg_clt != NULL) {
+ gatt_chk_srv_chg(p_srv_chg_clt);
+ } else {
+ if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda))
+ gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
}
+
+ /* send callback */
+ gatt_send_conn_cback(p_tcb);
}
-/*******************************************************************************
- *
- * Function gatt_l2cif_disconnect_ind_cback
- *
- * Description This is the L2CAP disconnect indication callback function.
- *
- *
- * Returns void
- *
- ******************************************************************************/
+/** This is the L2CAP disconnect indication callback function */
void gatt_l2cif_disconnect_ind_cback(uint16_t lcid, bool ack_needed) {
- tGATT_TCB* p_tcb;
- uint16_t reason;
/* look up clcb for this channel */
- p_tcb = gatt_find_tcb_by_cid(lcid);
- if (p_tcb != NULL) {
- if (ack_needed) {
- /* send L2CAP disconnect response */
- L2CA_DisconnectRsp(lcid);
- }
- if (gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda) == NULL) {
- if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda))
- gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
- }
- /* if ACL link is still up, no reason is logged, l2cap is disconnect from
- * peer */
- reason = L2CA_GetDisconnectReason(p_tcb->peer_bda, p_tcb->transport);
- if (reason == 0) reason = GATT_CONN_TERMINATE_PEER_USER;
+ tGATT_TCB* p_tcb = gatt_find_tcb_by_cid(lcid);
+ if (!p_tcb) return;
- /* send disconnect callback */
- gatt_cleanup_upon_disc(p_tcb->peer_bda, reason, GATT_TRANSPORT_BR_EDR);
+ if (ack_needed) {
+ /* send L2CAP disconnect response */
+ L2CA_DisconnectRsp(lcid);
}
+
+ if (gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda) == NULL) {
+ if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda))
+ gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
+ }
+ /* if ACL link is still up, no reason is logged, l2cap is disconnect from
+ * peer */
+ uint16_t reason = L2CA_GetDisconnectReason(p_tcb->peer_bda, p_tcb->transport);
+ if (reason == 0) reason = GATT_CONN_TERMINATE_PEER_USER;
+
+ /* send disconnect callback */
+ gatt_cleanup_upon_disc(p_tcb->peer_bda, reason, GATT_TRANSPORT_BR_EDR);
}
-/*******************************************************************************
- *
- * Function gatt_l2cif_disconnect_cfm_cback
- *
- * Description This is the L2CAP disconnect confirm callback function.
- *
- *
- * Returns void
- *
- ******************************************************************************/
+/** This is the L2CAP disconnect confirm callback function */
static void gatt_l2cif_disconnect_cfm_cback(uint16_t lcid,
UNUSED_ATTR uint16_t result) {
- tGATT_TCB* p_tcb;
- uint16_t reason;
/* look up clcb for this channel */
- p_tcb = gatt_find_tcb_by_cid(lcid);
- if (p_tcb != NULL) {
- /* If the device is not in the service changed client list, add it... */
- if (gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda) == NULL) {
- if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda))
- gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
- }
+ tGATT_TCB* p_tcb = gatt_find_tcb_by_cid(lcid);
+ if (!p_tcb) return;
- /* send disconnect callback */
- /* if ACL link is still up, no reason is logged, l2cap is disconnect from
- * peer */
- reason = L2CA_GetDisconnectReason(p_tcb->peer_bda, p_tcb->transport);
- if (reason == 0) reason = GATT_CONN_TERMINATE_LOCAL_HOST;
-
- gatt_cleanup_upon_disc(p_tcb->peer_bda, reason, GATT_TRANSPORT_BR_EDR);
+ /* If the device is not in the service changed client list, add it... */
+ if (gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda) == NULL) {
+ if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda))
+ gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
}
+
+ /* send disconnect callback */
+ /* if ACL link is still up, no reason is logged, l2cap is disconnect from
+ * peer */
+ uint16_t reason = L2CA_GetDisconnectReason(p_tcb->peer_bda, p_tcb->transport);
+ if (reason == 0) reason = GATT_CONN_TERMINATE_LOCAL_HOST;
+
+ gatt_cleanup_upon_disc(p_tcb->peer_bda, reason, GATT_TRANSPORT_BR_EDR);
}
-/*******************************************************************************
- *
- * Function gatt_l2cif_data_ind_cback
- *
- * Description This is the L2CAP data indication callback function.
- *
- *
- * Returns void
- *
- ******************************************************************************/
+/** This is the L2CAP data indication callback function */
static void gatt_l2cif_data_ind_cback(uint16_t lcid, BT_HDR* p_buf) {
- tGATT_TCB* p_tcb;
-
/* look up clcb for this channel */
- if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL &&
- gatt_get_ch_state(p_tcb) == GATT_CH_OPEN) {
+ tGATT_TCB* p_tcb = gatt_find_tcb_by_cid(lcid);
+ if (p_tcb && gatt_get_ch_state(p_tcb) == GATT_CH_OPEN) {
/* process the data */
gatt_data_process(*p_tcb, p_buf);
}
@@ -879,15 +806,7 @@
osi_free(p_buf);
}
-/*******************************************************************************
- *
- * Function gatt_l2cif_congest_cback
- *
- * Description L2CAP congestion callback
- *
- * Returns void
- *
- ******************************************************************************/
+/** L2CAP congestion callback */
static void gatt_l2cif_congest_cback(uint16_t lcid, bool congested) {
tGATT_TCB* p_tcb = gatt_find_tcb_by_cid(lcid);
@@ -896,34 +815,26 @@
}
}
-/*******************************************************************************
- *
- * Function gatt_send_conn_cback
- *
- * Description Callback used to notify layer above about a connection.
- *
- *
- * Returns void
- *
- ******************************************************************************/
+/** Callback used to notify layer above about a connection */
static void gatt_send_conn_cback(tGATT_TCB* p_tcb) {
uint8_t i;
tGATT_REG* p_reg;
uint16_t conn_id;
- tGATT_BG_CONN_DEV* p_bg_dev = gatt_find_bg_dev(p_tcb->peer_bda);
+ std::set<tGATT_IF> apps =
+ connection_manager::get_apps_connecting_to(p_tcb->peer_bda);
/* notifying all applications for the connection up event */
for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) {
- if (p_reg->in_use) {
- if (p_bg_dev && gatt_is_bg_dev_for_app(p_bg_dev, p_reg->gatt_if))
- gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, true, true);
+ if (!p_reg->in_use) continue;
- if (p_reg->app_cb.p_conn_cb) {
- conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if);
- (*p_reg->app_cb.p_conn_cb)(p_reg->gatt_if, p_tcb->peer_bda, conn_id,
- true, 0, p_tcb->transport);
- }
+ if (apps.find(p_reg->gatt_if) != apps.end())
+ gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, true, true);
+
+ if (p_reg->app_cb.p_conn_cb) {
+ conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if);
+ (*p_reg->app_cb.p_conn_cb)(p_reg->gatt_if, p_tcb->peer_bda, conn_id, true,
+ 0, p_tcb->transport);
}
}
@@ -986,71 +897,45 @@
}
}
-/*******************************************************************************
- *
- * Function gatt_add_a_bonded_dev_for_srv_chg
- *
- * Description Add a bonded dev to the service changed client list
- *
- * Returns void
- *
- ******************************************************************************/
+/** Add a bonded dev to the service changed client list */
void gatt_add_a_bonded_dev_for_srv_chg(const RawAddress& bda) {
tGATTS_SRV_CHG_REQ req;
tGATTS_SRV_CHG srv_chg_clt;
srv_chg_clt.bda = bda;
srv_chg_clt.srv_changed = false;
- if (gatt_add_srv_chg_clt(&srv_chg_clt) != NULL) {
- req.srv_chg.bda = bda;
- req.srv_chg.srv_changed = false;
- if (gatt_cb.cb_info.p_srv_chg_callback)
- (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_ADD_CLIENT, &req,
- NULL);
- }
+ if (!gatt_add_srv_chg_clt(&srv_chg_clt)) return;
+
+ req.srv_chg.bda = bda;
+ req.srv_chg.srv_changed = false;
+ if (gatt_cb.cb_info.p_srv_chg_callback)
+ (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_ADD_CLIENT, &req,
+ NULL);
}
-/*******************************************************************************
- *
- * Function gatt_send_srv_chg_ind
- *
- * Description This function is called to send a service chnaged indication
- * to the specified bd address
- *
- * Returns void
- *
- ******************************************************************************/
+/** This function is called to send a service chnaged indication to the
+ * specified bd address */
void gatt_send_srv_chg_ind(const RawAddress& peer_bda) {
+ VLOG(1) << __func__;
+
+ if (!gatt_cb.handle_of_h_r) return;
+
+ uint16_t conn_id = gatt_profile_find_conn_id_by_bd_addr(peer_bda);
+ if (conn_id == GATT_INVALID_CONN_ID) {
+ LOG(ERROR) << "Unable to find conn_id for " << peer_bda;
+ return;
+ }
+
uint8_t handle_range[GATT_SIZE_OF_SRV_CHG_HNDL_RANGE];
uint8_t* p = handle_range;
- uint16_t conn_id;
-
- VLOG(1) << "gatt_send_srv_chg_ind";
-
- if (gatt_cb.handle_of_h_r) {
- conn_id = gatt_profile_find_conn_id_by_bd_addr(peer_bda);
- if (conn_id != GATT_INVALID_CONN_ID) {
- UINT16_TO_STREAM(p, 1);
- UINT16_TO_STREAM(p, 0xFFFF);
- GATTS_HandleValueIndication(conn_id, gatt_cb.handle_of_h_r,
- GATT_SIZE_OF_SRV_CHG_HNDL_RANGE,
- handle_range);
- } else {
- LOG(ERROR) << "Unable to find conn_id for " << peer_bda;
- }
- }
+ UINT16_TO_STREAM(p, 1);
+ UINT16_TO_STREAM(p, 0xFFFF);
+ GATTS_HandleValueIndication(conn_id, gatt_cb.handle_of_h_r,
+ GATT_SIZE_OF_SRV_CHG_HNDL_RANGE, handle_range);
}
-/*******************************************************************************
- *
- * Function gatt_chk_srv_chg
- *
- * Description Check sending service chnaged Indication is required or not
- * if required then send the Indication
- *
- * Returns void
- *
- ******************************************************************************/
+/** Check sending service chnaged Indication is required or not if required then
+ * send the Indication */
void gatt_chk_srv_chg(tGATTS_SRV_CHG* p_srv_chg_clt) {
VLOG(1) << __func__ << " srv_changed=" << +p_srv_chg_clt->srv_changed;
@@ -1059,130 +944,93 @@
}
}
-/*******************************************************************************
- *
- * Function gatt_init_srv_chg
- *
- * Description This function is used to initialize the service changed
- * attribute value
- *
- * Returns void
- *
- ******************************************************************************/
+/** This function is used to initialize the service changed attribute value */
void gatt_init_srv_chg(void) {
tGATTS_SRV_CHG_REQ req;
tGATTS_SRV_CHG_RSP rsp;
- bool status;
- uint8_t num_clients, i;
tGATTS_SRV_CHG srv_chg_clt;
VLOG(1) << __func__;
- if (gatt_cb.cb_info.p_srv_chg_callback) {
- status = (*gatt_cb.cb_info.p_srv_chg_callback)(
- GATTS_SRV_CHG_CMD_READ_NUM_CLENTS, NULL, &rsp);
+ if (!gatt_cb.cb_info.p_srv_chg_callback) {
+ VLOG(1) << __func__ << " callback not registered yet";
+ return;
+ }
- if (status && rsp.num_clients) {
- VLOG(1) << "num_srv_chg_clt_clients=" << +rsp.num_clients;
- num_clients = rsp.num_clients;
- i = 1; /* use one based index */
- while ((i <= num_clients) && status) {
- req.client_read_index = i;
- status = (*gatt_cb.cb_info.p_srv_chg_callback)(
- GATTS_SRV_CHG_CMD_READ_CLENT, &req, &rsp);
- if (status) {
- memcpy(&srv_chg_clt, &rsp.srv_chg, sizeof(tGATTS_SRV_CHG));
- if (gatt_add_srv_chg_clt(&srv_chg_clt) == NULL) {
- LOG(ERROR) << "Unable to add a service change client";
- status = false;
- }
- }
- i++;
+ bool status = (*gatt_cb.cb_info.p_srv_chg_callback)(
+ GATTS_SRV_CHG_CMD_READ_NUM_CLENTS, NULL, &rsp);
+
+ if (!(status && rsp.num_clients)) return;
+
+ VLOG(1) << "num_srv_chg_clt_clients=" << +rsp.num_clients;
+ uint8_t num_clients = rsp.num_clients;
+ uint8_t i = 1; /* use one based index */
+ while ((i <= num_clients) && status) {
+ req.client_read_index = i;
+ status = (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_READ_CLENT,
+ &req, &rsp);
+ if (status) {
+ memcpy(&srv_chg_clt, &rsp.srv_chg, sizeof(tGATTS_SRV_CHG));
+ if (gatt_add_srv_chg_clt(&srv_chg_clt) == NULL) {
+ LOG(ERROR) << "Unable to add a service change client";
+ status = false;
}
}
- } else {
- VLOG(1) << __func__ << " callback not registered yet";
+ i++;
}
}
-/*******************************************************************************
- *
- * Function gatt_proc_srv_chg
- *
- * Description This function is process the service changed request
- *
- * Returns void
- *
- ******************************************************************************/
+/**This function is process the service changed request */
void gatt_proc_srv_chg(void) {
- uint8_t start_idx, found_idx;
RawAddress bda;
- tGATT_TCB* p_tcb;
tBT_TRANSPORT transport;
+ uint8_t found_idx;
VLOG(1) << __func__;
- if (gatt_cb.cb_info.p_srv_chg_callback && gatt_cb.handle_of_h_r) {
- gatt_set_srv_chg();
- start_idx = 0;
- while (
- gatt_find_the_connected_bda(start_idx, bda, &found_idx, &transport)) {
- p_tcb = &gatt_cb.tcb[found_idx];
+ if (!gatt_cb.cb_info.p_srv_chg_callback || !gatt_cb.handle_of_h_r) return;
- bool send_indication = true;
+ gatt_set_srv_chg();
+ uint8_t start_idx = 0;
+ while (gatt_find_the_connected_bda(start_idx, bda, &found_idx, &transport)) {
+ tGATT_TCB* p_tcb = &gatt_cb.tcb[found_idx];
- if (gatt_is_srv_chg_ind_pending(p_tcb)) {
- send_indication = false;
- VLOG(1) << "discard srv chg - already has one in the queue";
- }
+ bool send_indication = true;
- // Some LE GATT clients don't respond to service changed indications.
- char remote_name[BTM_MAX_REM_BD_NAME_LEN] = "";
- if (send_indication &&
- btif_storage_get_stored_remote_name(bda, remote_name)) {
- if (interop_match_name(INTEROP_GATTC_NO_SERVICE_CHANGED_IND,
- remote_name)) {
- VLOG(1) << "discard srv chg - interop matched " << remote_name;
- send_indication = false;
- }
- }
-
- if (send_indication) gatt_send_srv_chg_ind(bda);
-
- start_idx = ++found_idx;
+ if (gatt_is_srv_chg_ind_pending(p_tcb)) {
+ send_indication = false;
+ VLOG(1) << "discard srv chg - already has one in the queue";
}
+
+ // Some LE GATT clients don't respond to service changed indications.
+ char remote_name[BTM_MAX_REM_BD_NAME_LEN] = "";
+ if (send_indication &&
+ btif_storage_get_stored_remote_name(bda, remote_name)) {
+ if (interop_match_name(INTEROP_GATTC_NO_SERVICE_CHANGED_IND,
+ remote_name)) {
+ VLOG(1) << "discard srv chg - interop matched " << remote_name;
+ send_indication = false;
+ }
+ }
+
+ if (send_indication) gatt_send_srv_chg_ind(bda);
+
+ start_idx = ++found_idx;
}
}
-/*******************************************************************************
- *
- * Function gatt_set_ch_state
- *
- * Description This function set the ch_state in tcb
- *
- * Returns none
- *
- ******************************************************************************/
+/** This function set the ch_state in tcb */
void gatt_set_ch_state(tGATT_TCB* p_tcb, tGATT_CH_STATE ch_state) {
- if (p_tcb) {
- VLOG(1) << __func__ << ": old=" << +p_tcb->ch_state << " new=" << ch_state;
- p_tcb->ch_state = ch_state;
- }
+ if (!p_tcb) return;
+
+ VLOG(1) << __func__ << ": old=" << +p_tcb->ch_state
+ << " new=" << loghex(ch_state);
+ p_tcb->ch_state = ch_state;
}
-/*******************************************************************************
- *
- * Function gatt_get_ch_state
- *
- * Description This function get the ch_state in tcb
- *
- * Returns none
- *
- ******************************************************************************/
+/** This function get the ch_state in tcb */
tGATT_CH_STATE gatt_get_ch_state(tGATT_TCB* p_tcb) {
- tGATT_CH_STATE ch_state = GATT_CH_CLOSE;
- if (p_tcb) {
- VLOG(1) << "gatt_get_ch_state: ch_state=" << +p_tcb->ch_state;
- ch_state = p_tcb->ch_state;
- }
- return ch_state;
+ if (!p_tcb) return GATT_CH_CLOSE;
+
+ VLOG(1) << "gatt_get_ch_state: ch_state=" << +p_tcb->ch_state;
+ return p_tcb->ch_state;
}
diff --git a/stack/gatt/gatt_sr.cc b/stack/gatt/gatt_sr.cc
index b9921fe..94d81ef 100644
--- a/stack/gatt/gatt_sr.cc
+++ b/stack/gatt/gatt_sr.cc
@@ -22,12 +22,13 @@
*
******************************************************************************/
-#include <log/log.h>
#include "bt_target.h"
#include "bt_utils.h"
#include "osi/include/osi.h"
+#include <log/log.h>
#include <string.h>
+
#include "gatt_int.h"
#include "l2c_api.h"
#include "l2c_int.h"
@@ -335,7 +336,7 @@
} else /* nothing needs to be executed , send response now */
{
LOG(ERROR) << "gatt_process_exec_write_req: no prepare write pending";
- gatt_send_error_rsp(tcb, GATT_INVALID_OFFSET, GATT_REQ_EXEC_WRITE, 0, false);
+ gatt_send_error_rsp(tcb, GATT_ERROR, GATT_REQ_EXEC_WRITE, 0, false);
}
}
@@ -749,7 +750,7 @@
else
tcb.payload_size = mtu;
- LOG(ERROR) << "MTU request PDU with MTU size " << +tcb.payload_size;
+ LOG(INFO) << "MTU request PDU with MTU size " << +tcb.payload_size;
l2cble_set_fixed_channel_tx_data_length(tcb.peer_bda, L2CAP_ATT_CID,
tcb.payload_size);
@@ -884,13 +885,13 @@
sr_data.write_req.is_prep = true;
STREAM_TO_UINT16(sr_data.write_req.offset, p);
len -= 2;
- /* fall through */
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case GATT_SIGN_CMD_WRITE:
if (op_code == GATT_SIGN_CMD_WRITE) {
VLOG(1) << "Write CMD with data sigining";
len -= GATT_AUTH_SIGN_LEN;
}
- /* fall through */
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case GATT_CMD_WRITE:
case GATT_REQ_WRITE:
if (op_code == GATT_REQ_WRITE || op_code == GATT_REQ_PREPARE_WRITE)
@@ -1076,7 +1077,7 @@
* Returns void
*
******************************************************************************/
-static void gatts_proc_srv_chg_ind_ack(tGATT_TCB tcb) {
+void gatts_proc_srv_chg_ind_ack(tGATT_TCB tcb) {
tGATTS_SRV_CHG_REQ req;
tGATTS_SRV_CHG* p_buf = NULL;
diff --git a/stack/gatt/gatt_utils.cc b/stack/gatt/gatt_utils.cc
index 9e8d3b9..2bd4240 100644
--- a/stack/gatt/gatt_utils.cc
+++ b/stack/gatt/gatt_utils.cc
@@ -30,11 +30,13 @@
#include "stdio.h"
#include "btm_int.h"
+#include "connection_manager.h"
#include "gatt_api.h"
#include "gatt_int.h"
#include "gattdefs.h"
#include "l2cdefs.h"
#include "sdp_api.h"
+#include "stack/gatt/connection_manager.h"
using base::StringPrintf;
using bluetooth::Uuid;
@@ -155,25 +157,13 @@
}
}
-/*******************************************************************************
- *
- * Function gatt_add_pending_ind
- *
- * Description Add a pending indication
- *
- * Returns Pointer to the current pending indication buffer, NULL no buffer
- * available
- *
- ******************************************************************************/
-tGATT_VALUE* gatt_add_pending_ind(tGATT_TCB* p_tcb, tGATT_VALUE* p_ind) {
- tGATT_VALUE* p_buf = (tGATT_VALUE*)osi_malloc(sizeof(tGATT_VALUE));
-
+/** Add a pending indication */
+void gatt_add_pending_ind(tGATT_TCB* p_tcb, tGATT_VALUE* p_ind) {
VLOG(1) << __func__ << "enqueue a pending indication";
+ tGATT_VALUE* p_buf = (tGATT_VALUE*)osi_malloc(sizeof(tGATT_VALUE));
memcpy(p_buf, p_ind, sizeof(tGATT_VALUE));
fixed_queue_enqueue(p_tcb->pending_ind_q, p_buf);
-
- return p_buf;
}
/*******************************************************************************
@@ -318,7 +308,6 @@
*
******************************************************************************/
tGATTS_SRV_CHG* gatt_is_bda_in_the_srv_chg_clt_list(const RawAddress& bda) {
- tGATTS_SRV_CHG* p_buf = NULL;
VLOG(1) << __func__ << ": " << bda;
@@ -330,11 +319,11 @@
tGATTS_SRV_CHG* p_buf = (tGATTS_SRV_CHG*)list_node(node);
if (bda == p_buf->bda) {
VLOG(1) << "bda is in the srv chg clt list";
- break;
+ return p_buf;
}
}
- return p_buf;
+ return NULL;
}
/*******************************************************************************
@@ -529,7 +518,7 @@
*
******************************************************************************/
void gatt_start_rsp_timer(tGATT_CLCB* p_clcb) {
- period_ms_t timeout_ms = GATT_WAIT_FOR_RSP_TIMEOUT_MS;
+ uint64_t timeout_ms = GATT_WAIT_FOR_RSP_TIMEOUT_MS;
if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
p_clcb->op_subtype == GATT_DISC_SRVC_ALL) {
@@ -608,6 +597,8 @@
gatt_disconnect(p_clcb->p_tcb);
}
+extern void gatts_proc_srv_chg_ind_ack(tGATT_TCB tcb);
+
/*******************************************************************************
*
* Function gatt_indication_confirmation_timeout
@@ -620,6 +611,26 @@
void gatt_indication_confirmation_timeout(void* data) {
tGATT_TCB* p_tcb = (tGATT_TCB*)data;
+ if (p_tcb->indicate_handle == gatt_cb.handle_of_h_r) {
+ /* There are some GATT Server only devices, that don't implement GATT client
+ * functionalities, and ignore "Service Changed" indication. Android does
+ * not have CCC in "Service Changed" characteristic, and sends it to all
+ * bonded devices. This leads to situation where remote can ignore the
+ * indication, and trigger 30s timeout, then reconnection in a loop.
+ *
+ * Since chances of healthy Client device keeping connection for 30 seconds
+ * and not responding to "Service Changed" indication are very low, assume
+ * we are dealing with Server only device, and don't trigger disconnection.
+ *
+ * TODO: In future, we should properly expose CCC, and send indication only
+ * to devices that register for it.
+ */
+ LOG(WARNING) << " Service Changed notification timed out in 30 "
+ "seconds, assuming server-only remote, not disconnecting";
+ gatts_proc_srv_chg_ind_ack(*p_tcb);
+ return;
+ }
+
LOG(WARNING) << __func__ << " disconnecting...";
gatt_disconnect(p_tcb);
}
@@ -1095,15 +1106,8 @@
}
}
}
-/*******************************************************************************
- *
- * Function gatt_cancel_open
- *
- * Description Cancel open request
- *
- * Returns Boolean
- *
- ******************************************************************************/
+
+/** Cancel LE Create Connection request */
bool gatt_cancel_open(tGATT_IF gatt_if, const RawAddress& bda) {
tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bda, BT_TRANSPORT_LE);
if (!p_tcb) return true;
@@ -1117,6 +1121,7 @@
if (p_tcb->app_hold_link.empty()) gatt_disconnect(p_tcb);
+ connection_manager::direct_connect_remove(gatt_if, bda);
return true;
}
@@ -1307,156 +1312,9 @@
return (uint8_t*)"Op Code Exceed Max";
}
-/** Returns true if this is one of the background devices for the application,
- * false otherwise */
-bool gatt_is_bg_dev_for_app(tGATT_BG_CONN_DEV* p_dev, tGATT_IF gatt_if) {
- return p_dev->gatt_if.count(gatt_if);
-}
-
-/** background connection device from the list. Returns pointer to the device
- * record, or nullptr if not found */
-tGATT_BG_CONN_DEV* gatt_find_bg_dev(const RawAddress& remote_bda) {
- for (tGATT_BG_CONN_DEV& dev : gatt_cb.bgconn_dev) {
- if (dev.remote_bda == remote_bda) {
- return &dev;
- }
- }
- return nullptr;
-}
-
-std::list<tGATT_BG_CONN_DEV>::iterator gatt_find_bg_dev_it(
- const RawAddress& remote_bda) {
- auto& list = gatt_cb.bgconn_dev;
- for (auto it = list.begin(); it != list.end(); it++) {
- if (it->remote_bda == remote_bda) {
- return it;
- }
- }
- return list.end();
-}
-
-/** Add a device from the background connection list. Returns true if device
- * added to the list, or already in list, false otherwise */
-bool gatt_add_bg_dev_list(tGATT_REG* p_reg, const RawAddress& bd_addr) {
- tGATT_IF gatt_if = p_reg->gatt_if;
-
- tGATT_BG_CONN_DEV* p_dev = gatt_find_bg_dev(bd_addr);
- if (p_dev) {
- // device already in the whitelist, just add interested app to the list
- if (!p_dev->gatt_if.insert(gatt_if).second) {
- LOG(ERROR) << "device already in iniator white list";
- }
-
- return true;
- }
- // the device is not in the whitelist
-
- if (!BTM_BleUpdateBgConnDev(true, bd_addr)) return false;
-
- gatt_cb.bgconn_dev.emplace_back();
- tGATT_BG_CONN_DEV& dev = gatt_cb.bgconn_dev.back();
- dev.remote_bda = bd_addr;
- dev.gatt_if.insert(gatt_if);
- return true;
-}
-
/** Remove the application interface for the specified background device */
-bool gatt_remove_bg_dev_for_app(tGATT_IF gatt_if, const RawAddress& bd_addr) {
+bool gatt_auto_connect_dev_remove(tGATT_IF gatt_if, const RawAddress& bd_addr) {
tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE);
- bool status;
-
if (p_tcb) gatt_update_app_use_link_flag(gatt_if, p_tcb, false, false);
- status = gatt_update_auto_connect_dev(gatt_if, false, bd_addr);
- return status;
-}
-
-/** Removes all registrations for background connection for given device.
- * Returns true if anything was removed, false otherwise */
-uint8_t gatt_clear_bg_dev_for_addr(const RawAddress& bd_addr) {
- auto dev_it = gatt_find_bg_dev_it(bd_addr);
- if (dev_it == gatt_cb.bgconn_dev.end()) return false;
-
- CHECK(BTM_BleUpdateBgConnDev(false, dev_it->remote_bda));
- gatt_cb.bgconn_dev.erase(dev_it);
- return true;
-}
-
-/** Remove device from the background connection device list or listening to
- * advertising list. Returns true if device was on the list and was succesfully
- * removed */
-bool gatt_remove_bg_dev_from_list(tGATT_REG* p_reg, const RawAddress& bd_addr) {
- tGATT_IF gatt_if = p_reg->gatt_if;
- auto dev_it = gatt_find_bg_dev_it(bd_addr);
- if (dev_it == gatt_cb.bgconn_dev.end()) return false;
-
- if (!dev_it->gatt_if.erase(gatt_if)) return false;
-
- if (!dev_it->gatt_if.empty()) return true;
-
- // no more apps interested - remove from whitelist and delete record
- CHECK(BTM_BleUpdateBgConnDev(false, dev_it->remote_bda));
- gatt_cb.bgconn_dev.erase(dev_it);
- return true;
-}
-/** deregister all related back ground connetion device. */
-void gatt_deregister_bgdev_list(tGATT_IF gatt_if) {
- auto it = gatt_cb.bgconn_dev.begin();
- auto end = gatt_cb.bgconn_dev.end();
- /* update the BG conn device list */
- while (it != end) {
- it->gatt_if.erase(gatt_if);
- if (it->gatt_if.size()) {
- it++;
- continue;
- }
-
- BTM_BleUpdateBgConnDev(false, it->remote_bda);
- it = gatt_cb.bgconn_dev.erase(it);
- }
-}
-
-/*******************************************************************************
- *
- * Function gatt_reset_bgdev_list
- *
- * Description reset bg device list
- *
- * Returns pointer to the device record
- *
- ******************************************************************************/
-void gatt_reset_bgdev_list(void) { gatt_cb.bgconn_dev.clear(); }
-/*******************************************************************************
- *
- * Function gatt_update_auto_connect_dev
- *
- * Description This function add or remove a device for background
- * connection procedure.
- *
- * Parameters gatt_if: Application ID.
- * add: add peer device
- * bd_addr: peer device address.
- *
- * Returns true if connection started; false otherwise.
- *
- ******************************************************************************/
-bool gatt_update_auto_connect_dev(tGATT_IF gatt_if, bool add,
- const RawAddress& bd_addr) {
- tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE);
-
- VLOG(1) << __func__;
- /* Make sure app is registered */
- tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
- if (!p_reg) {
- LOG(ERROR) << __func__ << " gatt_if is not registered " << +gatt_if;
- return false;
- }
-
- if (!add) return gatt_remove_bg_dev_from_list(p_reg, bd_addr);
-
- bool ret = gatt_add_bg_dev_list(p_reg, bd_addr);
- if (ret && p_tcb != NULL) {
- /* if a connected device, update the link holding number */
- gatt_update_app_use_link_flag(gatt_if, p_tcb, true, true);
- }
- return ret;
+ return connection_manager::background_connect_remove(gatt_if, bd_addr);
}
diff --git a/stack/hcic/hciblecmds.cc b/stack/hcic/hciblecmds.cc
index 30d8d75..001532d 100644
--- a/stack/hcic/hciblecmds.cc
+++ b/stack/hcic/hciblecmds.cc
@@ -244,50 +244,36 @@
btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
}
-void btsnd_hcic_ble_clear_white_list(void) {
- BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
- uint8_t* pp = (uint8_t*)(p + 1);
-
- p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CLEAR_WHITE_LIST;
- p->offset = 0;
-
- UINT16_TO_STREAM(pp, HCI_BLE_CLEAR_WHITE_LIST);
- UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_CLEAR_WHITE_LIST);
-
- btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+void btsnd_hcic_ble_clear_white_list(
+ base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
+ btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_CLEAR_WHITE_LIST, nullptr, 0,
+ std::move(cb));
}
-void btsnd_hcic_ble_add_white_list(uint8_t addr_type, const RawAddress& bda) {
- BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
- uint8_t* pp = (uint8_t*)(p + 1);
-
- p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_ADD_WHITE_LIST;
- p->offset = 0;
-
- UINT16_TO_STREAM(pp, HCI_BLE_ADD_WHITE_LIST);
- UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_ADD_WHITE_LIST);
+void btsnd_hcic_ble_add_white_list(
+ uint8_t addr_type, const RawAddress& bda,
+ base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
+ uint8_t param[HCIC_PARAM_SIZE_ADD_WHITE_LIST];
+ uint8_t* pp = param;
UINT8_TO_STREAM(pp, addr_type);
BDADDR_TO_STREAM(pp, bda);
- btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+ btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_ADD_WHITE_LIST, param,
+ HCIC_PARAM_SIZE_ADD_WHITE_LIST, std::move(cb));
}
-void btsnd_hcic_ble_remove_from_white_list(uint8_t addr_type,
- const RawAddress& bda) {
- BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
- uint8_t* pp = (uint8_t*)(p + 1);
-
- p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_REMOVE_WHITE_LIST;
- p->offset = 0;
-
- UINT16_TO_STREAM(pp, HCI_BLE_REMOVE_WHITE_LIST);
- UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_REMOVE_WHITE_LIST);
+void btsnd_hcic_ble_remove_from_white_list(
+ uint8_t addr_type, const RawAddress& bda,
+ base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
+ uint8_t param[HCIC_PARAM_SIZE_REMOVE_WHITE_LIST];
+ uint8_t* pp = param;
UINT8_TO_STREAM(pp, addr_type);
BDADDR_TO_STREAM(pp, bda);
- btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+ btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_REMOVE_WHITE_LIST, param,
+ HCIC_PARAM_SIZE_REMOVE_WHITE_LIST, std::move(cb));
}
void btsnd_hcic_ble_upd_ll_conn_params(uint16_t handle, uint16_t conn_int_min,
@@ -405,8 +391,7 @@
void btsnd_hcic_ble_start_enc(uint16_t handle,
uint8_t rand[HCIC_BLE_RAND_DI_SIZE],
- uint16_t ediv,
- uint8_t ltk[HCIC_BLE_ENCRYT_KEY_SIZE]) {
+ uint16_t ediv, const Octet16& ltk) {
BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
uint8_t* pp = (uint8_t*)(p + 1);
@@ -419,13 +404,12 @@
UINT16_TO_STREAM(pp, handle);
ARRAY_TO_STREAM(pp, rand, HCIC_BLE_RAND_DI_SIZE);
UINT16_TO_STREAM(pp, ediv);
- ARRAY_TO_STREAM(pp, ltk, HCIC_BLE_ENCRYT_KEY_SIZE);
+ ARRAY_TO_STREAM(pp, ltk.data(), HCIC_BLE_ENCRYT_KEY_SIZE);
btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
}
-void btsnd_hcic_ble_ltk_req_reply(uint16_t handle,
- uint8_t ltk[HCIC_BLE_ENCRYT_KEY_SIZE]) {
+void btsnd_hcic_ble_ltk_req_reply(uint16_t handle, const Octet16& ltk) {
BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
uint8_t* pp = (uint8_t*)(p + 1);
@@ -436,7 +420,7 @@
UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_LTK_REQ_REPLY);
UINT16_TO_STREAM(pp, handle);
- ARRAY_TO_STREAM(pp, ltk, HCIC_BLE_ENCRYT_KEY_SIZE);
+ ARRAY_TO_STREAM(pp, ltk.data(), HCIC_BLE_ENCRYT_KEY_SIZE);
btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
}
@@ -560,9 +544,10 @@
}
#endif
-void btsnd_hcic_ble_add_device_resolving_list(
- uint8_t addr_type_peer, const RawAddress& bda_peer,
- uint8_t irk_peer[HCIC_BLE_IRK_SIZE], uint8_t irk_local[HCIC_BLE_IRK_SIZE]) {
+void btsnd_hcic_ble_add_device_resolving_list(uint8_t addr_type_peer,
+ const RawAddress& bda_peer,
+ const Octet16& irk_peer,
+ const Octet16& irk_local) {
BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
uint8_t* pp = (uint8_t*)(p + 1);
@@ -573,8 +558,8 @@
UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_ADD_DEV_RESOLVING_LIST);
UINT8_TO_STREAM(pp, addr_type_peer);
BDADDR_TO_STREAM(pp, bda_peer);
- ARRAY_TO_STREAM(pp, irk_peer, HCIC_BLE_ENCRYT_KEY_SIZE);
- ARRAY_TO_STREAM(pp, irk_local, HCIC_BLE_ENCRYT_KEY_SIZE);
+ ARRAY_TO_STREAM(pp, irk_peer.data(), HCIC_BLE_ENCRYT_KEY_SIZE);
+ ARRAY_TO_STREAM(pp, irk_local.data(), HCIC_BLE_ENCRYT_KEY_SIZE);
btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
}
diff --git a/stack/hcic/hcicmds.cc b/stack/hcic/hcicmds.cc
index 0778afc..2e849a4 100644
--- a/stack/hcic/hcicmds.cc
+++ b/stack/hcic/hcicmds.cc
@@ -142,7 +142,6 @@
btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
}
-#if (BTM_SCO_INCLUDED == TRUE)
void btsnd_hcic_add_SCO_conn(uint16_t handle, uint16_t packet_types) {
BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
uint8_t* pp = (uint8_t*)(p + 1);
@@ -158,7 +157,6 @@
btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
}
-#endif /* BTM_SCO_INCLUDED */
void btsnd_hcic_create_conn_cancel(const RawAddress& dest) {
BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
@@ -207,7 +205,7 @@
}
void btsnd_hcic_link_key_req_reply(const RawAddress& bd_addr,
- LINK_KEY link_key) {
+ const LinkKey& link_key) {
BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
uint8_t* pp = (uint8_t*)(p + 1);
@@ -218,7 +216,7 @@
UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_LINK_KEY_REQ_REPLY);
BDADDR_TO_STREAM(pp, bd_addr);
- ARRAY16_TO_STREAM(pp, link_key);
+ ARRAY16_TO_STREAM(pp, link_key.data());
btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
}
@@ -1196,8 +1194,8 @@
btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
}
-void btsnd_hcic_rem_oob_reply(const RawAddress& bd_addr, uint8_t* p_c,
- uint8_t* p_r) {
+void btsnd_hcic_rem_oob_reply(const RawAddress& bd_addr, const Octet16& c,
+ const Octet16& r) {
BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
uint8_t* pp = (uint8_t*)(p + 1);
@@ -1208,8 +1206,8 @@
UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_REM_OOB_REPLY);
BDADDR_TO_STREAM(pp, bd_addr);
- ARRAY16_TO_STREAM(pp, p_c);
- ARRAY16_TO_STREAM(pp, p_r);
+ ARRAY16_TO_STREAM(pp, c.data());
+ ARRAY16_TO_STREAM(pp, r.data());
btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
}
diff --git a/stack/hid/hidh_api.cc b/stack/hid/hidh_api.cc
index ad84daf..de62385 100644
--- a/stack/hid/hidh_api.cc
+++ b/stack/hid/hidh_api.cc
@@ -295,8 +295,8 @@
if (!hh_cb.reg_flag) return (HID_ERR_NOT_REGISTERED);
for (i = 0; i < HID_HOST_MAX_DEVICES; i++) {
- alarm_free(hh_cb.devices[i].conn.process_repage_timer);
HID_HostRemoveDev(i);
+ alarm_free(hh_cb.devices[i].conn.process_repage_timer);
}
hidh_conn_dereg();
diff --git a/stack/hid/hidh_conn.cc b/stack/hid/hidh_conn.cc
index 6f99c88..6b729e5 100644
--- a/stack/hid/hidh_conn.cc
+++ b/stack/hid/hidh_conn.cc
@@ -656,7 +656,7 @@
(!(hh_cb.devices[dhandle].attr_mask & HID_RECONN_INIT)) &&
(hh_cb.devices[dhandle].attr_mask & HID_NORMALLY_CONNECTABLE)) {
hh_cb.devices[dhandle].conn_tries = 0;
- period_ms_t interval_ms = HID_HOST_REPAGE_WIN * 1000;
+ uint64_t interval_ms = HID_HOST_REPAGE_WIN * 1000;
alarm_set_on_mloop(hh_cb.devices[dhandle].conn.process_repage_timer,
interval_ms, hidh_process_repage_timer_timeout,
UINT_TO_PTR(dhandle));
@@ -1073,7 +1073,7 @@
p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
#if (HID_HOST_REPAGE_WIN > 0)
- period_ms_t interval_ms = HID_HOST_REPAGE_WIN * 1000;
+ uint64_t interval_ms = HID_HOST_REPAGE_WIN * 1000;
alarm_set_on_mloop(p_dev->conn.process_repage_timer, interval_ms,
hidh_process_repage_timer_timeout, UINT_TO_PTR(dhandle));
#else
diff --git a/stack/include/a2dp_aac.h b/stack/include/a2dp_aac.h
index 29b2753..94ba730 100644
--- a/stack/include/a2dp_aac.h
+++ b/stack/include/a2dp_aac.h
@@ -48,7 +48,7 @@
virtual ~A2dpCodecConfigAacSource();
bool init() override;
- period_ms_t encoderIntervalMs() const override;
+ uint64_t encoderIntervalMs() const override;
int getEffectiveMtu() const override;
private:
@@ -66,7 +66,7 @@
virtual ~A2dpCodecConfigAacSink();
bool init() override;
- period_ms_t encoderIntervalMs() const override;
+ uint64_t encoderIntervalMs() const override;
int getEffectiveMtu() const override;
private:
@@ -147,6 +147,12 @@
// contains invalid codec information.
int A2DP_GetTrackSampleRateAac(const uint8_t* p_codec_info);
+// Gets the track bits per sample value for the A2DP AAC codec.
+// |p_codec_info| is a pointer to the AAC codec_info to decode.
+// Returns the track bits per sample on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetTrackBitsPerSampleAac(const uint8_t* p_codec_info);
+
// Gets the channel count for the A2DP AAC codec.
// |p_codec_info| is a pointer to the AAC codec_info to decode.
// Returns the channel count on success, or -1 if |p_codec_info|
diff --git a/stack/include/a2dp_aac_encoder.h b/stack/include/a2dp_aac_encoder.h
index e6b7323..143a577 100644
--- a/stack/include/a2dp_aac_encoder.h
+++ b/stack/include/a2dp_aac_encoder.h
@@ -22,7 +22,6 @@
#define A2DP_AAC_ENCODER_H
#include "a2dp_codec_api.h"
-#include "osi/include/time.h"
// Loads the A2DP AAC encoder.
// Return true on success, otherwise false.
@@ -51,7 +50,7 @@
void a2dp_aac_feeding_flush(void);
// Get the A2DP AAC encoder interval (in milliseconds).
-period_ms_t a2dp_aac_get_encoder_interval_ms(void);
+uint64_t a2dp_aac_get_encoder_interval_ms(void);
// Prepare and send A2DP AAC encoded frames.
// |timestamp_us| is the current timestamp (in microseconds).
diff --git a/stack/include/a2dp_codec_api.h b/stack/include/a2dp_codec_api.h
index 9fdc13b..45cbf9c 100644
--- a/stack/include/a2dp_codec_api.h
+++ b/stack/include/a2dp_codec_api.h
@@ -34,7 +34,6 @@
#include "a2dp_api.h"
#include "audio_a2dp_hw/include/audio_a2dp_hw.h"
#include "avdt_api.h"
-#include "osi/include/time.h"
class tBT_A2DP_OFFLOAD;
@@ -217,7 +216,7 @@
virtual bool isValid() const;
// Returns the encoder's periodic interval (in milliseconds).
- virtual period_ms_t encoderIntervalMs() const = 0;
+ virtual uint64_t encoderIntervalMs() const = 0;
// Checks whether the A2DP Codec Configuration is valid.
// Returns true if A2DP Codec Configuration stored in |codec_config|
@@ -302,6 +301,10 @@
// Returns the Sink codec if found, otherwise nullptr.
A2dpCodecConfig* findSinkCodecConfig(const uint8_t* p_codec_info);
+ // Checks whether the codec for |codec_index| is supported.
+ // Returns true if the codec is supported, otherwise false.
+ bool isSupportedCodec(btav_a2dp_codec_index_t codec_index);
+
// Gets the codec config that is currently selected.
// Returns the codec config that is currently selected, or nullptr if
// no codec is selected.
@@ -527,7 +530,7 @@
void (*feeding_flush)(void);
// Get the A2DP encoder interval (in milliseconds).
- period_ms_t (*get_encoder_interval_ms)(void);
+ uint64_t (*get_encoder_interval_ms)(void);
// Prepare and send A2DP encoded frames.
// |timestamp_us| is the current timestamp (in microseconds).
@@ -639,6 +642,12 @@
// contains invalid codec information.
int A2DP_GetTrackSampleRate(const uint8_t* p_codec_info);
+// Gets the track bits per sample value for the A2DP codec.
+// |p_codec_info| is a pointer to the codec_info to decode.
+// Returns the track bits per sample on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetTrackBitsPerSample(const uint8_t* p_codec_info);
+
// Gets the channel count for the A2DP codec.
// |p_codec_info| is a pointer to the codec_info to decode.
// Returns the channel count on success, or -1 if |p_codec_info|
diff --git a/stack/include/a2dp_sbc.h b/stack/include/a2dp_sbc.h
index 0381d31..5f7b0aa 100644
--- a/stack/include/a2dp_sbc.h
+++ b/stack/include/a2dp_sbc.h
@@ -48,7 +48,7 @@
virtual ~A2dpCodecConfigSbcSource();
bool init() override;
- period_ms_t encoderIntervalMs() const override;
+ uint64_t encoderIntervalMs() const override;
int getEffectiveMtu() const override;
private:
@@ -66,7 +66,7 @@
virtual ~A2dpCodecConfigSbcSink();
bool init() override;
- period_ms_t encoderIntervalMs() const override;
+ uint64_t encoderIntervalMs() const override;
int getEffectiveMtu() const override;
private:
@@ -143,6 +143,12 @@
// contains invalid codec information.
int A2DP_GetTrackSampleRateSbc(const uint8_t* p_codec_info);
+// Gets the track bits per sample value for the A2DP SBC codec.
+// |p_codec_info| is a pointer to the SBC codec_info to decode.
+// Returns the track bits per sample on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetTrackBitsPerSampleSbc(const uint8_t* p_codec_info);
+
// Gets the channel count for the A2DP SBC codec.
// |p_codec_info| is a pointer to the SBC codec_info to decode.
// Returns the channel count on success, or -1 if |p_codec_info|
diff --git a/stack/include/a2dp_sbc_encoder.h b/stack/include/a2dp_sbc_encoder.h
index a853012..0acf16f 100644
--- a/stack/include/a2dp_sbc_encoder.h
+++ b/stack/include/a2dp_sbc_encoder.h
@@ -25,7 +25,6 @@
#define A2DP_SBC_ENCODER_H
#include "a2dp_codec_api.h"
-#include "osi/include/time.h"
// Loads the A2DP SBC encoder.
// Return true on success, otherwise false.
@@ -54,7 +53,7 @@
void a2dp_sbc_feeding_flush(void);
// Get the A2DP SBC encoder interval (in milliseconds).
-period_ms_t a2dp_sbc_get_encoder_interval_ms(void);
+uint64_t a2dp_sbc_get_encoder_interval_ms(void);
// Prepare and send A2DP SBC encoded frames.
// |timestamp_us| is the current timestamp (in microseconds).
diff --git a/stack/include/a2dp_vendor.h b/stack/include/a2dp_vendor.h
index 0b5ba7c..117e25c 100644
--- a/stack/include/a2dp_vendor.h
+++ b/stack/include/a2dp_vendor.h
@@ -117,6 +117,12 @@
// contains invalid codec information.
int A2DP_VendorGetTrackSampleRate(const uint8_t* p_codec_info);
+// Gets the track bits per sample value for the A2DP vendor-specific codec.
+// |p_codec_info| is a pointer to the vendor-specific codec_info to decode.
+// Returns the track sample rate on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetTrackBitsPerSample(const uint8_t* p_codec_info);
+
// Gets the channel count for the A2DP vendor-specific codec.
// |p_codec_info| is a pointer to the vendor-specific codec_info to decode.
// Returns the channel count on success, or -1 if |p_codec_info|
diff --git a/stack/include/a2dp_vendor_aptx.h b/stack/include/a2dp_vendor_aptx.h
index 38a1245..bf4ebf0 100644
--- a/stack/include/a2dp_vendor_aptx.h
+++ b/stack/include/a2dp_vendor_aptx.h
@@ -31,7 +31,7 @@
virtual ~A2dpCodecConfigAptx();
bool init() override;
- period_ms_t encoderIntervalMs() const override;
+ uint64_t encoderIntervalMs() const override;
int getEffectiveMtu() const override;
bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
uint8_t* p_result_codec_config) override;
@@ -91,6 +91,12 @@
// contains invalid codec information.
int A2DP_VendorGetTrackSampleRateAptx(const uint8_t* p_codec_info);
+// Gets the track bits per sample value for the A2DP aptX codec.
+// |p_codec_info| is a pointer to the aptX codec_info to decode.
+// Returns the track bits per sample on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetTrackBitsPerSampleAptx(const uint8_t* p_codec_info);
+
// Gets the track bitrate value for the A2DP aptX codec.
// |p_codec_info| is a pointer to the aptX codec_info to decode.
// Returns the track sample rate on success, or -1 if |p_codec_info|
diff --git a/stack/include/a2dp_vendor_aptx_encoder.h b/stack/include/a2dp_vendor_aptx_encoder.h
index 7deaca3..c0954fa 100644
--- a/stack/include/a2dp_vendor_aptx_encoder.h
+++ b/stack/include/a2dp_vendor_aptx_encoder.h
@@ -22,7 +22,6 @@
#define A2DP_VENDOR_APTX_ENCODER_H
#include "a2dp_codec_api.h"
-#include "osi/include/time.h"
// Loads the A2DP aptX encoder.
// Return true on success, otherwise false.
@@ -52,7 +51,7 @@
void a2dp_vendor_aptx_feeding_flush(void);
// Get the A2DP aptX encoder interval (in milliseconds).
-period_ms_t a2dp_vendor_aptx_get_encoder_interval_ms(void);
+uint64_t a2dp_vendor_aptx_get_encoder_interval_ms(void);
// Prepare and send A2DP aptX encoded frames.
// |timestamp_us| is the current timestamp (in microseconds).
diff --git a/stack/include/a2dp_vendor_aptx_hd.h b/stack/include/a2dp_vendor_aptx_hd.h
index 05ca16f..8efe8c6 100644
--- a/stack/include/a2dp_vendor_aptx_hd.h
+++ b/stack/include/a2dp_vendor_aptx_hd.h
@@ -31,7 +31,7 @@
virtual ~A2dpCodecConfigAptxHd();
bool init() override;
- period_ms_t encoderIntervalMs() const override;
+ uint64_t encoderIntervalMs() const override;
int getEffectiveMtu() const override;
bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
uint8_t* p_result_codec_config) override;
@@ -91,6 +91,12 @@
// contains invalid codec information.
int A2DP_VendorGetTrackSampleRateAptxHd(const uint8_t* p_codec_info);
+// Gets the track bits per sample value for the A2DP aptX-HD codec.
+// |p_codec_info| is a pointer to the aptX-HD codec_info to decode.
+// Returns the track bits per sample on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetTrackBitsPerSampleAptxHd(const uint8_t* p_codec_info);
+
// Gets the track bitrate value for the A2DP aptX-HD codec.
// |p_codec_info| is a pointer to the aptX-HD codec_info to decode.
// Returns the track sample rate on success, or -1 if |p_codec_info|
diff --git a/stack/include/a2dp_vendor_aptx_hd_encoder.h b/stack/include/a2dp_vendor_aptx_hd_encoder.h
index 53e7d02..84ef8a0 100644
--- a/stack/include/a2dp_vendor_aptx_hd_encoder.h
+++ b/stack/include/a2dp_vendor_aptx_hd_encoder.h
@@ -22,7 +22,6 @@
#define A2DP_VENDOR_APTX_HD_ENCODER_H
#include "a2dp_codec_api.h"
-#include "osi/include/time.h"
// Loads the A2DP aptX-HD encoder.
// Return true on success, otherwise false.
@@ -52,7 +51,7 @@
void a2dp_vendor_aptx_hd_feeding_flush(void);
// Get the A2DP aptX-HD encoder interval (in milliseconds).
-period_ms_t a2dp_vendor_aptx_hd_get_encoder_interval_ms(void);
+uint64_t a2dp_vendor_aptx_hd_get_encoder_interval_ms(void);
// Prepare and send A2DP aptX-HD encoded frames.
// |timestamp_us| is the current timestamp (in microseconds).
diff --git a/stack/include/a2dp_vendor_ldac.h b/stack/include/a2dp_vendor_ldac.h
index ccb5d1e..9b1958f 100644
--- a/stack/include/a2dp_vendor_ldac.h
+++ b/stack/include/a2dp_vendor_ldac.h
@@ -25,20 +25,33 @@
#include "a2dp_vendor_ldac_constants.h"
#include "avdt_api.h"
-class A2dpCodecConfigLdac : public A2dpCodecConfig {
- public:
- A2dpCodecConfigLdac(btav_a2dp_codec_priority_t codec_priority);
- virtual ~A2dpCodecConfigLdac();
-
- bool init() override;
- period_ms_t encoderIntervalMs() const override;
- int getEffectiveMtu() const override;
+class A2dpCodecConfigLdacBase : public A2dpCodecConfig {
+ protected:
+ A2dpCodecConfigLdacBase(btav_a2dp_codec_index_t codec_index,
+ const std::string& name,
+ btav_a2dp_codec_priority_t codec_priority,
+ bool is_source)
+ : A2dpCodecConfig(codec_index, name, codec_priority),
+ is_source_(is_source) {}
bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
uint8_t* p_result_codec_config) override;
bool setPeerCodecCapabilities(
const uint8_t* p_peer_codec_capabilities) override;
private:
+ bool is_source_; // True if local is Source
+};
+
+class A2dpCodecConfigLdacSource : public A2dpCodecConfigLdacBase {
+ public:
+ A2dpCodecConfigLdacSource(btav_a2dp_codec_priority_t codec_priority);
+ virtual ~A2dpCodecConfigLdacSource();
+
+ bool init() override;
+ uint64_t encoderIntervalMs() const override;
+ int getEffectiveMtu() const override;
+
+ private:
bool useRtpHeaderMarkerBit() const override;
bool updateEncoderUserConfig(
const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
@@ -47,6 +60,23 @@
void debug_codec_dump(int fd) override;
};
+class A2dpCodecConfigLdacSink : public A2dpCodecConfigLdacBase {
+ public:
+ A2dpCodecConfigLdacSink(btav_a2dp_codec_priority_t codec_priority);
+ virtual ~A2dpCodecConfigLdacSink();
+
+ bool init() override;
+ uint64_t encoderIntervalMs() const override;
+ int getEffectiveMtu() const override;
+
+ private:
+ bool useRtpHeaderMarkerBit() const override;
+ bool updateEncoderUserConfig(
+ const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ bool* p_restart_input, bool* p_restart_output,
+ bool* p_config_updated) override;
+};
+
// Checks whether the codec capabilities contain a valid A2DP LDAC Source
// codec.
// NOTE: only codecs that are implemented are considered valid.
@@ -54,6 +84,13 @@
// codec, otherwise false.
bool A2DP_IsVendorSourceCodecValidLdac(const uint8_t* p_codec_info);
+// Checks whether the codec capabilities contain a valid A2DP LDAC Sink
+// codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid LDAC
+// codec, otherwise false.
+bool A2DP_IsVendorSinkCodecValidLdac(const uint8_t* p_codec_info);
+
// Checks whether the codec capabilities contain a valid peer A2DP LDAC Sink
// codec.
// NOTE: only codecs that are implemented are considered valid.
@@ -61,6 +98,26 @@
// codec, otherwise false.
bool A2DP_IsVendorPeerSinkCodecValidLdac(const uint8_t* p_codec_info);
+// Checks whether the codec capabilities contain a valid peer A2DP LDAC Source
+// codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid LDAC
+// codec, otherwise false.
+bool A2DP_IsVendorPeerSourceCodecValidLdac(const uint8_t* p_codec_info);
+
+// Checks whether A2DP LDAC Sink codec is supported.
+// |p_codec_info| contains information about the codec capabilities.
+// Returns true if the A2DP LDAC Sink codec is supported, otherwise false.
+bool A2DP_IsVendorSinkCodecSupportedLdac(const uint8_t* p_codec_info);
+
+// Checks whether an A2DP LDAC Source codec for a peer Source device is
+// supported.
+// |p_codec_info| contains information about the codec capabilities of the
+// peer device.
+// Returns true if the A2DP LDAC Source codec for a peer Source device is
+// supported, otherwise false.
+bool A2DP_IsPeerSourceCodecSupportedLdac(const uint8_t* p_codec_info);
+
// Checks whether the A2DP data packets should contain RTP header.
// |content_protection_enabled| is true if Content Protection is
// enabled. |p_codec_info| contains information about the codec capabilities.
@@ -91,6 +148,12 @@
// contains invalid codec information.
int A2DP_VendorGetTrackSampleRateLdac(const uint8_t* p_codec_info);
+// Gets the track bits per sample value for the A2DP LDAC codec.
+// |p_codec_info| is a pointer to the LDAC codec_info to decode.
+// Returns the track bits per sample on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetTrackBitsPerSampleLdac(const uint8_t* p_codec_info);
+
// Gets the track bitrate value for the A2DP LDAC codec.
// |p_codec_info| is a pointer to the LDAC codec_info to decode.
// Returns the track sample rate on success, or -1 if |p_codec_info|
@@ -103,6 +166,13 @@
// contains invalid codec information.
int A2DP_VendorGetTrackChannelCountLdac(const uint8_t* p_codec_info);
+// Gets the channel type for the A2DP LDAC codec.
+// 1 for mono, or 3 for dual channel/stereo.
+// |p_codec_info| is a pointer to the LDAC codec_info to decode.
+// Returns the channel count on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetSinkTrackChannelTypeLdac(const uint8_t* p_codec_info);
+
// Gets the channel mode code for the A2DP LDAC codec.
// The actual value is codec-specific - see |A2DP_LDAC_CHANNEL_MODE_*|.
// |p_codec_info| is a pointer to the LDAC codec_info to decode.
@@ -140,6 +210,14 @@
const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterfaceLdac(
const uint8_t* p_codec_info);
+// Gets the current A2DP LDAC decoder interface that can be used to decode
+// received A2DP packets - see |tA2DP_DECODER_INTERFACE|.
+// |p_codec_info| contains the codec information.
+// Returns the A2DP LDAC decoder interface if the |p_codec_info| is valid and
+// supported, otherwise NULL.
+const tA2DP_DECODER_INTERFACE* A2DP_VendorGetDecoderInterfaceLdac(
+ const uint8_t* p_codec_info);
+
// Adjusts the A2DP LDAC codec, based on local support and Bluetooth
// specification.
// |p_codec_info| contains the codec information to adjust.
@@ -152,11 +230,24 @@
btav_a2dp_codec_index_t A2DP_VendorSourceCodecIndexLdac(
const uint8_t* p_codec_info);
+// Gets the A2DP LDAC Sink codec index for a given |p_codec_info|.
+// Returns the corresponding |btav_a2dp_codec_index_t| on success,
+// otherwise |BTAV_A2DP_CODEC_INDEX_MAX|.
+btav_a2dp_codec_index_t A2DP_VendorSinkCodecIndexLdac(
+ const uint8_t* p_codec_info);
+
// Gets the A2DP LDAC Source codec name.
const char* A2DP_VendorCodecIndexStrLdac(void);
+// Gets the A2DP LDAC Sink codec name.
+const char* A2DP_VendorCodecIndexStrLdacSink(void);
+
// Initializes A2DP LDAC Source codec information into |AvdtpSepConfig|
// configuration entry pointed by |p_cfg|.
bool A2DP_VendorInitCodecConfigLdac(AvdtpSepConfig* p_cfg);
+// Initializes A2DP LDAC Sink codec information into |AvdtpSepConfig|
+// configuration entry pointed by |p_cfg|.
+bool A2DP_VendorInitCodecConfigLdacSink(AvdtpSepConfig* p_cfg);
+
#endif // A2DP_VENDOR_LDAC_H
diff --git a/stack/include/a2dp_vendor_ldac_decoder.h b/stack/include/a2dp_vendor_ldac_decoder.h
new file mode 100644
index 0000000..2a05baa
--- /dev/null
+++ b/stack/include/a2dp_vendor_ldac_decoder.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016 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.
+ */
+
+//
+// Interface to the A2DP LDAC Decoder
+//
+
+#ifndef A2DP_VENDOR_LDAC_DECODER_H
+#define A2DP_VENDOR_LDAC_DECODER_H
+
+#include "a2dp_codec_api.h"
+
+// Loads the A2DP LDAC decoder.
+// Return true on success, otherwise false.
+bool A2DP_VendorLoadDecoderLdac(void);
+
+// Unloads the A2DP LDAC decoder.
+void A2DP_VendorUnloadDecoderLdac(void);
+
+// Initialize the A2DP LDAC decoder.
+bool a2dp_vendor_ldac_decoder_init(decoded_data_callback_t decode_callback);
+
+// Cleanup the A2DP LDAC decoder.
+void a2dp_vendor_ldac_decoder_cleanup(void);
+
+// Decodes |p_buf|. Calls |decode_callback| passed into
+// |a2dp_vendor_ldac_decoder_init| if decoded frames are available.
+bool a2dp_vendor_ldac_decoder_decode_packet(BT_HDR* p_buf);
+
+#endif // A2DP_VENDOR_LDAC_DECODER_H
diff --git a/stack/include/a2dp_vendor_ldac_encoder.h b/stack/include/a2dp_vendor_ldac_encoder.h
index 810f03b..f5e320a 100644
--- a/stack/include/a2dp_vendor_ldac_encoder.h
+++ b/stack/include/a2dp_vendor_ldac_encoder.h
@@ -22,7 +22,6 @@
#define A2DP_VENDOR_LDAC_ENCODER_H
#include "a2dp_codec_api.h"
-#include "osi/include/time.h"
// Loads the A2DP LDAC encoder.
// Return true on success, otherwise false.
@@ -52,7 +51,7 @@
void a2dp_vendor_ldac_feeding_flush(void);
// Get the A2DP LDAC encoder interval (in milliseconds).
-period_ms_t a2dp_vendor_ldac_get_encoder_interval_ms(void);
+uint64_t a2dp_vendor_ldac_get_encoder_interval_ms(void);
// Prepare and send A2DP LDAC encoded frames.
// |timestamp_us| is the current timestamp (in microseconds).
diff --git a/stack/include/avdt_api.h b/stack/include/avdt_api.h
index fd0721c..09e7f7c 100644
--- a/stack/include/avdt_api.h
+++ b/stack/include/avdt_api.h
@@ -71,6 +71,9 @@
*/
#define AVDT_MARKER_SET 0x80
+#define MAX_2MBPS_AVDTP_MTU 663 // 2DH5 MTU=679, -12 for AVDTP, -4 for L2CAP
+#define MAX_3MBPS_AVDTP_MTU 1005 // 3DH5 MTU=1021, -12 for AVDTP, -4 for L2CAP
+
/* SEP Type. This indicates the stream endpoint type. */
#define AVDT_TSEP_SRC 0 /* Source SEP */
#define AVDT_TSEP_SNK 1 /* Sink SEP */
diff --git a/stack/include/avrc_api.h b/stack/include/avrc_api.h
index 1aa8ea4..77c37de 100644
--- a/stack/include/avrc_api.h
+++ b/stack/include/avrc_api.h
@@ -24,13 +24,13 @@
#ifndef AVRC_API_H
#define AVRC_API_H
-#include <base/bind.h>
-
#include "avct_api.h"
#include "avrc_defs.h"
#include "bt_target.h"
#include "sdp_api.h"
+#include <base/callback.h>
+
/*****************************************************************************
* constants
****************************************************************************/
diff --git a/stack/include/bt_types.h b/stack/include/bt_types.h
index 3c479af..4121a19 100644
--- a/stack/include/bt_types.h
+++ b/stack/include/bt_types.h
@@ -562,15 +562,28 @@
#define BT_OCTET8_LEN 8
typedef uint8_t BT_OCTET8[BT_OCTET8_LEN]; /* octet array: size 16 */
-#define LINK_KEY_LEN 16
-typedef uint8_t LINK_KEY[LINK_KEY_LEN]; /* Link Key */
-
#define AMP_LINK_KEY_LEN 32
typedef uint8_t
AMP_LINK_KEY[AMP_LINK_KEY_LEN]; /* Dedicated AMP and GAMP Link Keys */
-#define BT_OCTET16_LEN 16
-typedef uint8_t BT_OCTET16[BT_OCTET16_LEN]; /* octet array: size 16 */
+/* Some C files include this header file */
+#ifdef __cplusplus
+
+#include <array>
+
+constexpr int OCTET16_LEN = 16;
+typedef std::array<uint8_t, OCTET16_LEN> Octet16;
+
+constexpr int LINK_KEY_LEN = OCTET16_LEN;
+typedef Octet16 LinkKey; /* Link Key */
+
+/* Sample LTK from BT Spec 5.1 | Vol 6, Part C 1
+ * 0x4C68384139F574D836BCF34E9DFB01BF */
+constexpr Octet16 SAMPLE_LTK = {0xbf, 0x01, 0xfb, 0x9d, 0x4e, 0xf3, 0xbc, 0x36,
+ 0xd8, 0x74, 0xf5, 0x39, 0x41, 0x38, 0x68, 0x4c};
+inline bool is_sample_ltk(const Octet16& ltk) { return ltk == SAMPLE_LTK; }
+
+#endif
#define PIN_CODE_LEN 16
typedef uint8_t PIN_CODE[PIN_CODE_LEN]; /* Pin Code (upto 128 bits) MSB is 0 */
@@ -814,7 +827,7 @@
#define TRACE_LAYER_A2DP 0x00210000
#define TRACE_LAYER_SAP 0x00220000
#define TRACE_LAYER_AMP 0x00230000
-#define TRACE_LAYER_MCA 0x00240000
+#define TRACE_LAYER_MCA 0x00240000 /* OBSOLETED */
#define TRACE_LAYER_ATT 0x00250000
#define TRACE_LAYER_SMP 0x00260000
#define TRACE_LAYER_NFC 0x00270000
@@ -926,12 +939,4 @@
/* Define a function for logging */
typedef void(BT_LOG_FUNC)(int trace_type, const char* fmt_str, ...);
-static inline bool is_sample_ltk(const BT_OCTET16 ltk) {
- /* Sample LTK from BT Spec 5.1 | Vol 6, Part C 1
- * 0x4C68384139F574D836BCF34E9DFB01BF */
- const uint8_t SAMPLE_LTK[] = {0xbf, 0x01, 0xfb, 0x9d, 0x4e, 0xf3, 0xbc, 0x36,
- 0xd8, 0x74, 0xf5, 0x39, 0x41, 0x38, 0x68, 0x4c};
- return memcmp(ltk, SAMPLE_LTK, BT_OCTET16_LEN) == 0;
-}
-
#endif
diff --git a/stack/include/btm_api.h b/stack/include/btm_api.h
index 6ffc0f9..df4cbe0 100644
--- a/stack/include/btm_api.h
+++ b/stack/include/btm_api.h
@@ -1407,7 +1407,7 @@
******************************************************************************/
extern bool BTM_SecAddDevice(const RawAddress& bd_addr, DEV_CLASS dev_class,
BD_NAME bd_name, uint8_t* features,
- uint32_t trusted_mask[], LINK_KEY link_key,
+ uint32_t trusted_mask[], LinkKey* link_key,
uint8_t key_type, tBTM_IO_CAP io_cap,
uint8_t pin_length);
@@ -1446,7 +1446,7 @@
*
******************************************************************************/
extern tBTM_STATUS BTM_SecGetDeviceLinkKey(const RawAddress& bd_addr,
- LINK_KEY link_key);
+ LinkKey* link_key);
/*******************************************************************************
*
@@ -1662,7 +1662,7 @@
*
******************************************************************************/
extern void BTM_RemoteOobDataReply(tBTM_STATUS res, const RawAddress& bd_addr,
- BT_OCTET16 c, BT_OCTET16 r);
+ const Octet16& c, const Octet16& r);
/*******************************************************************************
*
@@ -1683,7 +1683,8 @@
*
******************************************************************************/
extern uint16_t BTM_BuildOobData(uint8_t* p_data, uint16_t max_len,
- BT_OCTET16 c, BT_OCTET16 r, uint8_t name_len);
+ const Octet16& c, const Octet16& r,
+ uint8_t name_len);
/*******************************************************************************
*
diff --git a/stack/include/btm_api_types.h b/stack/include/btm_api_types.h
index 8cc9485..965087c 100644
--- a/stack/include/btm_api_types.h
+++ b/stack/include/btm_api_types.h
@@ -1332,8 +1332,8 @@
*/
typedef uint8_t(tBTM_LINK_KEY_CALLBACK)(const RawAddress& bd_addr,
DEV_CLASS dev_class,
- tBTM_BD_NAME bd_name, uint8_t* key,
- uint8_t key_type);
+ tBTM_BD_NAME bd_name,
+ const LinkKey& key, uint8_t key_type);
/* Remote Name Resolved. Parameters are
* BD Address of remote
@@ -1480,8 +1480,8 @@
/* data type for BTM_SP_LOC_OOB_EVT */
typedef struct {
tBTM_STATUS status; /* */
- BT_OCTET16 c; /* Simple Pairing Hash C */
- BT_OCTET16 r; /* Simple Pairing Randomnizer R */
+ Octet16 c; /* Simple Pairing Hash C */
+ Octet16 r; /* Simple Pairing Randomnizer R */
} tBTM_SP_LOC_OOB;
/* data type for BTM_SP_RMT_OOB_EVT */
@@ -1631,7 +1631,7 @@
/* BLE encryption keys */
typedef struct {
- BT_OCTET16 ltk;
+ Octet16 ltk;
BT_OCTET8 rand;
uint16_t ediv;
uint8_t sec_level;
@@ -1641,13 +1641,13 @@
/* BLE CSRK keys */
typedef struct {
uint32_t counter;
- BT_OCTET16 csrk;
+ Octet16 csrk;
uint8_t sec_level;
} tBTM_LE_PCSRK_KEYS;
/* BLE Encryption reproduction keys */
typedef struct {
- BT_OCTET16 ltk;
+ Octet16 ltk;
uint16_t div;
uint8_t key_size;
uint8_t sec_level;
@@ -1658,13 +1658,13 @@
uint32_t counter;
uint16_t div;
uint8_t sec_level;
- BT_OCTET16 csrk;
+ Octet16 csrk;
} tBTM_LE_LCSRK_KEYS;
typedef struct {
- BT_OCTET16 irk;
- tBLE_ADDR_TYPE addr_type;
- RawAddress static_addr;
+ Octet16 irk;
+ tBLE_ADDR_TYPE identity_addr_type;
+ RawAddress identity_addr;
} tBTM_LE_PID_KEYS;
typedef union {
@@ -1704,15 +1704,15 @@
#define BTM_BLE_KEY_TYPE_COUNTER 3 // tobe obsolete
typedef struct {
- BT_OCTET16 ir;
- BT_OCTET16 irk;
- BT_OCTET16 dhk;
+ Octet16 ir;
+ Octet16 irk;
+ Octet16 dhk;
} tBTM_BLE_LOCAL_ID_KEYS;
typedef union {
tBTM_BLE_LOCAL_ID_KEYS id_keys;
- BT_OCTET16 er;
+ Octet16 er;
} tBTM_BLE_LOCAL_KEYS;
/* New LE identity key for local device.
@@ -1808,63 +1808,6 @@
} tBTM_DELETE_STORED_LINK_KEY_COMPLETE;
-/* MIP evnets, callbacks */
-enum {
- BTM_MIP_MODE_CHG_EVT,
- BTM_MIP_DISCONNECT_EVT,
- BTM_MIP_PKTS_COMPL_EVT,
- BTM_MIP_RXDATA_EVT
-};
-typedef uint8_t tBTM_MIP_EVT;
-
-typedef struct {
- tBTM_MIP_EVT event;
- RawAddress bd_addr;
- uint16_t mip_id;
-} tBTM_MIP_MODE_CHANGE;
-
-typedef struct {
- tBTM_MIP_EVT event;
- uint16_t mip_id;
- uint8_t disc_reason;
-} tBTM_MIP_CONN_TIMEOUT;
-
-#define BTM_MIP_MAX_RX_LEN 17
-
-typedef struct {
- tBTM_MIP_EVT event;
- uint16_t mip_id;
- uint8_t rx_len;
- uint8_t rx_data[BTM_MIP_MAX_RX_LEN];
-} tBTM_MIP_RXDATA;
-
-typedef struct {
- tBTM_MIP_EVT event;
- RawAddress bd_addr;
- uint8_t data[11]; /* data[0] shows Vender-specific device type */
-} tBTM_MIP_EIR_HANDSHAKE;
-
-typedef struct {
- tBTM_MIP_EVT event;
- uint16_t num_sent; /* Completed packet count at the controller */
-} tBTM_MIP_PKTS_COMPL;
-
-typedef union {
- tBTM_MIP_EVT event;
- tBTM_MIP_MODE_CHANGE mod_chg;
- tBTM_MIP_CONN_TIMEOUT conn_tmo;
- tBTM_MIP_EIR_HANDSHAKE eir;
- tBTM_MIP_PKTS_COMPL completed;
- tBTM_MIP_RXDATA rxdata;
-} tBTM_MIP_EVENT_DATA;
-
-/* MIP event callback function */
-typedef void(tBTM_MIP_EVENTS_CB)(tBTM_MIP_EVT event, tBTM_MIP_EVENT_DATA data);
-
-/* MIP Device query callback function */
-typedef bool(tBTM_MIP_QUERY_CB)(const RawAddress& dev_addr, uint8_t* p_mode,
- LINK_KEY link_key);
-
/* ACL link on, SCO link ongoing, sniff mode */
#define BTM_CONTRL_ACTIVE 1
/* Scan state - paging/inquiry/trying to connect*/
diff --git a/stack/include/btm_ble_api.h b/stack/include/btm_ble_api.h
index c8ffa5e..5bf325a 100644
--- a/stack/include/btm_ble_api.h
+++ b/stack/include/btm_ble_api.h
@@ -77,22 +77,6 @@
/*******************************************************************************
*
- * Function BTM_BleSetAdvParams
- *
- * Description This function is called to set advertising parameters.
- *
- * Parameters: None.
- *
- * Returns void
- *
- ******************************************************************************/
-extern tBTM_STATUS BTM_BleSetAdvParams(uint16_t adv_int_min,
- uint16_t adv_int_max,
- tBLE_BD_ADDR* p_dir_bda,
- tBTM_BLE_ADV_CHNL_MAP chnl_map);
-
-/*******************************************************************************
- *
* Function BTM_BleObtainVendorCapabilities
*
* Description This function is called to obatin vendor capabilties
@@ -196,43 +180,14 @@
tBTM_INQ_RESULTS_CB* p_results_cb,
tBTM_CMPL_CB* p_cmpl_cb);
-/*******************************************************************************
- *
- * Function BTM_GetDeviceIDRoot
- *
- * Description This function is called to read the local device identity
- * root.
- *
- * Returns void
- * the local device ER is copied into er
- *
- ******************************************************************************/
-extern void BTM_GetDeviceIDRoot(BT_OCTET16 ir);
+/** Returns local device encryption root (ER) */
+const Octet16& BTM_GetDeviceEncRoot();
-/*******************************************************************************
- *
- * Function BTM_GetDeviceEncRoot
- *
- * Description This function is called to read the local device encryption
- * root.
- *
- * Returns void
- * the local device ER is copied into er
- *
- ******************************************************************************/
-extern void BTM_GetDeviceEncRoot(BT_OCTET16 er);
+/** Returns local device identity root (IR) */
+extern const Octet16& BTM_GetDeviceIDRoot();
-/*******************************************************************************
- *
- * Function BTM_GetDeviceDHK
- *
- * Description This function is called to read the local device DHK.
- *
- * Returns void
- * the local device DHK is copied into dhk
- *
- ******************************************************************************/
-extern void BTM_GetDeviceDHK(BT_OCTET16 dhk);
+/** Return local device DHK. */
+extern const Octet16& BTM_GetDeviceDHK();
/*******************************************************************************
*
@@ -405,44 +360,7 @@
******************************************************************************/
extern void BTM_BleLoadLocalKeys(uint8_t key_type, tBTM_BLE_LOCAL_KEYS* p_key);
-/**
- * Set BLE connectable mode to auto connect
- */
-extern void BTM_BleStartAutoConn();
-
-/*******************************************************************************
- *
- * Function BTM_BleUpdateBgConnDev
- *
- * Description This function is called to add or remove a device into/from
- * background connection procedure. The background connection
-* procedure is decided by the background connection type, it
-*can be
-* auto connection, or selective connection.
- *
- * Parameters add_remove: true to add; false to remove.
- * remote_bda: device address to add/remove.
- *
- * Returns void
- *
- ******************************************************************************/
-extern bool BTM_BleUpdateBgConnDev(bool add_remove,
- const RawAddress& remote_bda);
-
-/*******************************************************************************
- *
- * Function BTM_BleClearBgConnDev
- *
- * Description This function is called to clear the whitelist,
- * end any pending whitelist connections,
- * and reset the local bg device list.
- *
- * Parameters void
- *
- * Returns void
- *
- ******************************************************************************/
-extern void BTM_BleClearBgConnDev(void);
+#include "stack/btm/btm_ble_bgconn.h"
/********************************************************
*
diff --git a/stack/include/btm_ble_api_types.h b/stack/include/btm_ble_api_types.h
index 327a2e6..9f0201c 100644
--- a/stack/include/btm_ble_api_types.h
+++ b/stack/include/btm_ble_api_types.h
@@ -135,7 +135,7 @@
#define BTM_BLE_CONN_SUP_TOUT_MAX 0x0C80
/* use this value when a specific value not to be overwritten */
#define BTM_BLE_CONN_PARAM_UNDEF 0xffff
-#define BTM_BLE_SCAN_PARAM_UNDEF 0xffffffff
+#define BTM_BLE_SCAN_PARAM_UNDEF 0xffff
/* default connection parameters if not configured, use GAP recommended value
* for auto/selective connection */
@@ -203,13 +203,6 @@
#define BTM_BLE_CONN_INT_MIN_HEARINGAID 0x0010
#endif
-#define BTM_BLE_DIR_CONN_FALLBACK_UNDIR 1
-#define BTM_BLE_DIR_CONN_FALLBACK_NO_ADV 2
-
-#ifndef BTM_BLE_DIR_CONN_FALLBACK
-#define BTM_BLE_DIR_CONN_FALLBACK BTM_BLE_DIR_CONN_FALLBACK_UNDIR
-#endif
-
#define BTM_CMAC_TLEN_SIZE 8 /* 64 bits */
#define BTM_BLE_AUTH_SIGN_LEN \
12 /* BLE data signature length 8 Bytes + 4 bytes counter*/
@@ -279,7 +272,7 @@
uint8_t status;
uint8_t param_len;
uint16_t opcode;
- uint8_t param_buf[BT_OCTET16_LEN];
+ uint8_t param_buf[OCTET16_LEN];
} tBTM_RAND_ENC;
/* General callback function for notifying an application that a synchronous
@@ -335,7 +328,8 @@
/* Preferred maximum number of microseconds that the local Controller
should use to transmit a single Link Layer Data Channel PDU. */
#define BTM_BLE_DATA_TX_TIME_MIN 0x0148
-#define BTM_BLE_DATA_TX_TIME_MAX 0x0848
+#define BTM_BLE_DATA_TX_TIME_MAX_LEGACY 0x0848
+#define BTM_BLE_DATA_TX_TIME_MAX 0x4290
/* adv tx power in dBm */
typedef struct {
@@ -494,9 +488,6 @@
typedef uint8_t BTM_BLE_RSSI_VALUE;
typedef uint16_t BTM_BLE_ADV_INFO_TIMESTAMP;
-enum { BTM_BLE_CONN_NONE, BTM_BLE_CONN_AUTO };
-typedef uint8_t tBTM_BLE_CONN_TYPE;
-
#define ADV_INFO_PRESENT 0x00
#define NO_ADV_INFO_PRESENT 0x01
diff --git a/stack/include/btu.h b/stack/include/btu.h
index 5841efa..77d5051 100644
--- a/stack/include/btu.h
+++ b/stack/include/btu.h
@@ -27,12 +27,14 @@
#ifndef BTU_H
#define BTU_H
+#include "bt_common.h"
+#include "bt_target.h"
+#include "common/message_loop_thread.h"
+#include "osi/include/alarm.h"
+
#include <base/callback.h>
#include <base/location.h>
#include <base/threading/thread.h>
-#include "bt_common.h"
-#include "bt_target.h"
-#include "osi/include/alarm.h"
/* Global BTU data */
extern uint8_t btu_trace_level;
@@ -42,10 +44,10 @@
*/
void btu_hcif_process_event(uint8_t controller_id, BT_HDR* p_buf);
void btu_hcif_send_cmd(uint8_t controller_id, BT_HDR* p_msg);
-void btu_hcif_send_cmd_with_cb(const tracked_objects::Location& posted_from,
+void btu_hcif_send_cmd_with_cb(const base::Location& posted_from,
uint16_t opcode, uint8_t* params,
uint8_t params_len,
- base::Callback<void(uint8_t*, uint16_t)> cb);
+ base::OnceCallback<void(uint8_t*, uint16_t)> cb);
/* Functions provided by btu_init.cc
***********************************
@@ -56,7 +58,10 @@
/* Functions provided by btu_task.cc
***********************************
*/
-base::MessageLoop* get_message_loop();
+bluetooth::common::MessageLoopThread* get_main_thread();
+base::MessageLoop* get_main_message_loop();
+bt_status_t do_in_main_thread(const base::Location& from_here,
+ base::OnceClosure task);
void BTU_StartUp(void);
void BTU_ShutDown(void);
diff --git a/stack/include/gatt_api.h b/stack/include/gatt_api.h
index f9c0642..069a179 100644
--- a/stack/include/gatt_api.h
+++ b/stack/include/gatt_api.h
@@ -410,14 +410,6 @@
};
typedef uint8_t tGATT_DISC_TYPE;
-/* Discover parameters of different discovery types
-*/
-typedef struct {
- bluetooth::Uuid service;
- uint16_t s_handle;
- uint16_t e_handle;
-} tGATT_DISC_PARAM;
-
/* GATT read type enumeration
*/
enum {
@@ -825,13 +817,19 @@
*
* Parameters conn_id: connection identifier.
* disc_type:discovery type.
- * p_param: parameters of discovery requirement.
+ * start_handle and end_handle: range of handles for discovery
+ * uuid: uuid to discovery. set to Uuid::kEmpty for requests
+ * that don't need it
*
* Returns GATT_SUCCESS if command received/sent successfully.
*
******************************************************************************/
extern tGATT_STATUS GATTC_Discover(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
- tGATT_DISC_PARAM* p_param);
+ uint16_t start_handle, uint16_t end_handle,
+ const bluetooth::Uuid& uuid);
+extern tGATT_STATUS GATTC_Discover(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
+ uint16_t start_handle, uint16_t end_handle);
+
/*******************************************************************************
*
* Function GATTC_Read
@@ -1084,7 +1082,8 @@
// initiated outside GATT.
extern void gatt_notify_enc_cmpl(const RawAddress& bd_addr);
-// Reset bg device list.
-extern void gatt_reset_bgdev_list(void);
+/** Reset bg device list. If called after controller reset, set |after_reset| to
+ * true, as there is no need to wipe controller white list in this case. */
+extern void gatt_reset_bgdev_list(bool after_reset);
#endif /* GATT_API_H */
diff --git a/stack/include/gattdefs.h b/stack/include/gattdefs.h
index 5f5093d..186542c 100644
--- a/stack/include/gattdefs.h
+++ b/stack/include/gattdefs.h
@@ -28,7 +28,7 @@
#define GATT_ILLEGAL_UUID 0
/* GATT attribute types
-*/
+ */
#define GATT_UUID_PRI_SERVICE 0x2800
#define GATT_UUID_SEC_SERVICE 0x2801
#define GATT_UUID_INCLUDE_SERVICE 0x2802
@@ -52,8 +52,12 @@
#define GATT_UUID_EXT_RPT_REF_DESCR 0x2907
#define GATT_UUID_RPT_REF_DESCR 0x2908
+/* Client Characteristic Configuration bits */
+#define GATT_CHAR_CLIENT_CONFIG_NOTIFICATION 0x0001
+#define GATT_CHAR_CLIENT_CONFIG_INDICTION 0x0002
+
/* GAP Profile Attributes
-*/
+ */
#define GATT_UUID_GAP_DEVICE_NAME 0x2A00
#define GATT_UUID_GAP_ICON 0x2A01
#define GATT_UUID_GAP_PREF_CONN_PARAM 0x2A04
diff --git a/stack/include/hcidefs.h b/stack/include/hcidefs.h
index 8f91743..ef87b5b 100644
--- a/stack/include/hcidefs.h
+++ b/stack/include/hcidefs.h
@@ -423,6 +423,9 @@
/* A2DP offload OCF */
#define HCI_CONTROLLER_A2DP_OPCODE_OCF (0x015D | HCI_GRP_VENDOR_SPECIFIC)
+/* Bluetooth Quality Report OCF */
+#define HCI_CONTROLLER_BQR_OPCODE_OCF (0x015E | HCI_GRP_VENDOR_SPECIFIC)
+
/* subcode for multi adv feature */
#define BTM_BLE_MULTI_ADV_SET_PARAM 0x01
#define BTM_BLE_MULTI_ADV_WRITE_ADV_DATA 0x02
@@ -449,6 +452,9 @@
/* debug info sub event */
#define HCI_VSE_SUBCODE_DEBUG_INFO_SUB_EVT 0x57
+/* Bluetooth Quality Report sub event */
+#define HCI_VSE_SUBCODE_BQR_SUB_EVT 0x58
+
/* LE supported states definition */
#define HCI_LE_ADV_STATE 0x00000001
#define HCI_LE_SCAN_STATE 0x00000002
@@ -788,12 +794,7 @@
0x0000000000200000 Connectionless Broadcast Channel Map Change Event
0x0000000000400000 Inquiry Response Notification Event
*/
-#if (BLE_PRIVACY_SPT == TRUE)
-/* BLE event mask */
-#define HCI_BLE_EVENT_MASK_DEF "\x00\x00\x00\x00\x00\x00\x07\xff"
-#else
-#define HCI_BLE_EVENT_MASK_DEF "\x00\x00\x00\x00\x00\x00\x00\x7f"
-#endif
+
/*
* Definitions for packet type masks (BT1.2 and BT2.0 definitions)
*/
diff --git a/stack/include/hcimsgs.h b/stack/include/hcimsgs.h
index 63ea8f4..5682a5c 100644
--- a/stack/include/hcimsgs.h
+++ b/stack/include/hcimsgs.h
@@ -89,10 +89,8 @@
#define HCI_DISC_REASON_OFF 2
/* Disconnect */
-#if (BTM_SCO_INCLUDED == TRUE)
/* Add SCO Connection */
extern void btsnd_hcic_add_SCO_conn(uint16_t handle, uint16_t packet_types);
-#endif /* BTM_SCO_INCLUDED */
#define HCIC_PARAM_SIZE_ADD_SCO_CONN 4
@@ -128,7 +126,7 @@
/* Link Key Request Reply */
extern void btsnd_hcic_link_key_req_reply(const RawAddress& bd_addr,
- LINK_KEY link_key);
+ const LinkKey& link_key);
#define HCIC_PARAM_SIZE_LINK_KEY_REQ_REPLY 22
@@ -428,8 +426,8 @@
#define HCI_USER_PASSKEY_NEG_BD_ADDR_OFF 0
/* Remote OOB Data Request Reply */
-extern void btsnd_hcic_rem_oob_reply(const RawAddress& bd_addr, uint8_t* p_c,
- uint8_t* p_r);
+extern void btsnd_hcic_rem_oob_reply(const RawAddress& bd_addr,
+ const Octet16& c, const Octet16& r);
#define HCIC_PARAM_SIZE_REM_OOB_REPLY 38
@@ -670,7 +668,6 @@
* message size
******************************************************************************/
#define HCIC_BLE_RAND_DI_SIZE 8
-#define HCIC_BLE_ENCRYT_KEY_SIZE 16
#define HCIC_BLE_IRK_SIZE 16
#define HCIC_PARAM_SIZE_SET_USED_FEAT_CMD 8
@@ -762,13 +759,16 @@
extern void btsnd_hcic_ble_read_white_list_size(void);
-extern void btsnd_hcic_ble_clear_white_list(void);
+extern void btsnd_hcic_ble_clear_white_list(
+ base::OnceCallback<void(uint8_t*, uint16_t)> cb);
-extern void btsnd_hcic_ble_add_white_list(uint8_t addr_type,
- const RawAddress& bda);
+extern void btsnd_hcic_ble_add_white_list(
+ uint8_t addr_type, const RawAddress& bda,
+ base::OnceCallback<void(uint8_t*, uint16_t)> cb);
-extern void btsnd_hcic_ble_remove_from_white_list(uint8_t addr_type,
- const RawAddress& bda);
+extern void btsnd_hcic_ble_remove_from_white_list(
+ uint8_t addr_type, const RawAddress& bda,
+ base::OnceCallback<void(uint8_t*, uint16_t)> cb);
extern void btsnd_hcic_ble_upd_ll_conn_params(
uint16_t handle, uint16_t conn_int_min, uint16_t conn_int_max,
@@ -790,11 +790,9 @@
extern void btsnd_hcic_ble_start_enc(uint16_t handle,
uint8_t rand[HCIC_BLE_RAND_DI_SIZE],
- uint16_t ediv,
- uint8_t ltk[HCIC_BLE_ENCRYT_KEY_SIZE]);
+ uint16_t ediv, const Octet16& ltk);
-extern void btsnd_hcic_ble_ltk_req_reply(uint16_t handle,
- uint8_t ltk[HCIC_BLE_ENCRYT_KEY_SIZE]);
+extern void btsnd_hcic_ble_ltk_req_reply(uint16_t handle, const Octet16& ltk);
extern void btsnd_hcic_ble_ltk_req_neg_reply(uint16_t handle);
@@ -830,9 +828,10 @@
uint16_t tx_octets,
uint16_t tx_time);
-extern void btsnd_hcic_ble_add_device_resolving_list(
- uint8_t addr_type_peer, const RawAddress& bda_peer,
- uint8_t irk_peer[HCIC_BLE_IRK_SIZE], uint8_t irk_local[HCIC_BLE_IRK_SIZE]);
+extern void btsnd_hcic_ble_add_device_resolving_list(uint8_t addr_type_peer,
+ const RawAddress& bda_peer,
+ const Octet16& irk_peer,
+ const Octet16& irk_local);
struct scanning_phy_cfg {
uint8_t scan_type;
@@ -867,10 +866,6 @@
uint8_t initiating_phys,
EXT_CONN_PHY_CFG* phy_cfg);
-extern void btsnd_hcic_ble_add_device_resolving_list(
- uint8_t addr_type_peer, const RawAddress& bda_peer,
- uint8_t irk_peer[HCIC_BLE_IRK_SIZE], uint8_t irk_local[HCIC_BLE_IRK_SIZE]);
-
extern void btsnd_hcic_ble_rm_device_resolving_list(uint8_t addr_type_peer,
const RawAddress& bda_peer);
diff --git a/stack/include/l2cdefs.h b/stack/include/l2cdefs.h
index 4f4c894..2d4d6db 100644
--- a/stack/include/l2cdefs.h
+++ b/stack/include/l2cdefs.h
@@ -125,18 +125,20 @@
#define L2CAP_CONN_NO_LINK 255
#define L2CAP_CONN_CANCEL 256 /* L2CAP connection cancelled */
-/* Define the LE L2CAP connection result codes
-*/
-#define L2CAP_LE_CONN_OK 0
-#define L2CAP_LE_NO_PSM 2
-#define L2CAP_LE_NO_RESOURCES 4
-#define L2CAP_LE_INSUFFICIENT_AUTHENTICATION 5
-#define L2CAP_LE_INSUFFICIENT_AUTHORIZATION 6
-#define L2CAP_LE_INSUFFICIENT_ENCRYP_KEY_SIZE 7
-#define L2CAP_LE_INSUFFICIENT_ENCRYP 8
+/* Define the LE L2CAP Connection Response Result codes
+ */
+#define L2CAP_LE_RESULT_CONN_OK 0
+#define L2CAP_LE_RESULT_NO_PSM 2
+#define L2CAP_LE_RESULT_NO_RESOURCES 4
+#define L2CAP_LE_RESULT_INSUFFICIENT_AUTHENTICATION 5
+#define L2CAP_LE_RESULT_INSUFFICIENT_AUTHORIZATION 6
+#define L2CAP_LE_RESULT_INSUFFICIENT_ENCRYP_KEY_SIZE 7
+#define L2CAP_LE_RESULT_INSUFFICIENT_ENCRYP 8
/* We don't like peer device response */
-#define L2CAP_LE_INVALID_SOURCE_CID 9
-#define L2CAP_LE_SOURCE_CID_ALREADY_ALLOCATED 0x0A
+#define L2CAP_LE_RESULT_INVALID_SOURCE_CID 9
+#define L2CAP_LE_RESULT_SOURCE_CID_ALREADY_ALLOCATED 0x0A
+
+typedef uint8_t tL2CAP_LE_RESULT_CODE;
/* Define L2CAP Move Channel Response result codes
*/
diff --git a/stack/include/mca_api.h b/stack/include/mca_api.h
deleted file mode 100644
index 539d6c2..0000000
--- a/stack/include/mca_api.h
+++ /dev/null
@@ -1,553 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2009-2012 Broadcom 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.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- * This interface file contains the interface to the Multi-Channel
- * Adaptation Protocol (MCAP).
- *
- ******************************************************************************/
-#ifndef MCA_API_H
-#define MCA_API_H
-
-#include "bt_target.h"
-#include "l2c_api.h"
-
-/* move the following to bt_target.h or other place later */
-#define MCA_NUM_TC_TBL ((MCA_NUM_REGS) * (MCA_NUM_LINKS) * (MCA_NUM_MDLS + 1))
-/* Number of control channel control blocks */
-#define MCA_NUM_CCBS ((MCA_NUM_REGS) * (MCA_NUM_LINKS))
-/* Number of data channel control blocks */
-#define MCA_NUM_DCBS ((MCA_NUM_REGS) * (MCA_NUM_LINKS) * (MCA_NUM_MDLS))
-
-/*****************************************************************************
- * constants
- ****************************************************************************/
-/* API function return value result codes. */
-#define MCA_SUCCESS 0 /* Function successful */
-#define MCA_BAD_PARAMS 1 /* Invalid parameters */
-#define MCA_NO_RESOURCES 2 /* Not enough resources */
-#define MCA_BAD_HANDLE 3 /* Bad handle */
-#define MCA_BUSY 4 /* A procedure is already in progress */
-#define MCA_WRITE_FAIL 5 /* Write failed */
-#define MCA_BAD_MDL_ID 6 /* MDL ID is not valid for the current API */
-typedef uint8_t tMCA_RESULT;
-
-/* MDEP data type. */
-#define MCA_TDEP_ECHO 0 /* MDEP for echo test */
-#define MCA_TDEP_DATA 1 /* MDEP for normal data */
-
-/* Control callback events. */
-#define MCA_ERROR_RSP_EVT 0 /* error response */
-#define MCA_CREATE_IND_EVT 1 /* create mdl indication */
-#define MCA_CREATE_CFM_EVT 2 /* create mdl confirm */
-#define MCA_RECONNECT_IND_EVT 3 /* reconnect mdl indication */
-#define MCA_RECONNECT_CFM_EVT 4 /* reconnect mdl confirm */
-#define MCA_ABORT_IND_EVT 5 /* abort mdl indication */
-#define MCA_ABORT_CFM_EVT 6 /* abort mdl confirm */
-#define MCA_DELETE_IND_EVT 7 /* delete mdl indication */
-#define MCA_DELETE_CFM_EVT 8 /* delete mdl confirm */
-
-/* request sync capabilities & requirements */
-#define MCA_SYNC_CAP_IND_EVT 0x11
-#define MCA_SYNC_CAP_CFM_EVT 0x12 /* indicate completion */
-/* request to set the time-stamp clock */
-#define MCA_SYNC_SET_IND_EVT 0x13
-#define MCA_SYNC_SET_CFM_EVT 0x14 /* indicate completion */
-/* update of the actual time-stamp clock instant from the sync slave */
-#define MCA_SYNC_INFO_IND_EVT 0x15
-
-#define MCA_CONNECT_IND_EVT 0x20 /* Control channel connected */
-#define MCA_DISCONNECT_IND_EVT 0x21 /* Control channel disconnected */
-#define MCA_OPEN_IND_EVT 0x22 /* Data channel open indication */
-#define MCA_OPEN_CFM_EVT 0x23 /* Data channel open confirm */
-#define MCA_CLOSE_IND_EVT 0x24 /* Data channel close indication */
-#define MCA_CLOSE_CFM_EVT 0x25 /* Data channel close confirm */
-#define MCA_CONG_CHG_EVT 0x26 /* congestion change event */
-#define MCA_RSP_TOUT_IND_EVT \
- 0x27 /* Control channel message response timeout \
- */
-/*****************************************************************************
- * Type Definitions
- ****************************************************************************/
-typedef uint8_t
- tMCA_HANDLE; /* the handle for registration. 1 based index to rcb */
-typedef uint8_t tMCA_CL; /* the handle for a control channel; reported at
- MCA_CONNECT_IND_EVT */
-typedef uint8_t
- tMCA_DEP; /* the handle for MCA_CreateDep. This is also the local mdep_id */
-typedef uint16_t tMCA_DL; /* the handle for the data channel. This is reported
- at MCA_OPEN_CFM_EVT or MCA_OPEN_IND_EVT */
-
-/* This is the data callback function. It is executed when MCAP has a data
- * packet ready for the application.
-*/
-typedef void(tMCA_DATA_CBACK)(tMCA_DL mdl, BT_HDR* p_pkt);
-
-/* This structure contains parameters which are set at registration. */
-typedef struct {
- uint32_t rsp_tout; /* MCAP signaling response timeout */
- uint16_t ctrl_psm; /* L2CAP PSM for the MCAP control channel */
- uint16_t data_psm; /* L2CAP PSM for the MCAP data channel */
- uint16_t sec_mask; /* Security mask for BTM_SetSecurityLevel() */
-} tMCA_REG;
-
-/* This structure contains parameters to create a MDEP. */
-typedef struct {
- uint8_t type; /* MCA_TDEP_DATA, or MCA_TDEP_ECHO. a regiatration may have only
- one MCA_TDEP_ECHO MDEP */
- uint8_t max_mdl; /* The maximum number of MDLs for this MDEP (max is
- MCA_NUM_MDLS) */
- tMCA_DATA_CBACK* p_data_cback; /* Data callback function */
-} tMCA_CS;
-
-#define MCA_FCS_NONE 0 /* fcs_present=false */
-#define MCA_FCS_BYPASS 0x10 /* fcs_present=true, fcs=L2CAP_CFG_FCS_BYPASS */
-#define MCA_FCS_USE 0x11 /* fcs_present=true, fcs=L2CAP_CFG_FCS_USE */
-#define MCA_FCS_PRESNT_MASK 0x10 /* fcs_present=true */
-#define MCA_FCS_USE_MASK 0x01 /* mask for fcs */
-typedef uint8_t tMCA_FCS_OPT;
-
-/* This structure contains L2CAP configuration parameters for the channel. */
-typedef struct {
- tL2CAP_FCR_OPTS fcr_opt;
- uint16_t user_rx_buf_size;
- uint16_t user_tx_buf_size;
- uint16_t fcr_rx_buf_size;
- uint16_t fcr_tx_buf_size;
- tMCA_FCS_OPT fcs;
- uint16_t data_mtu; /* L2CAP MTU of the MCAP data channel */
-} tMCA_CHNL_CFG;
-
-/* Header structure for callback event parameters. */
-typedef struct {
- uint16_t mdl_id; /* The associated MDL ID */
- uint8_t op_code; /* The op (request/response) code */
-} tMCA_EVT_HDR;
-
-/* Response Header structure for callback event parameters. */
-typedef struct {
- uint16_t mdl_id; /* The associated MDL ID */
- uint8_t op_code; /* The op (request/response) code */
- uint8_t rsp_code; /* The response code */
-} tMCA_RSP_EVT;
-
-/* This data structure is associated with the MCA_CREATE_IND_EVT. */
-typedef struct {
- uint16_t mdl_id; /* The associated MDL ID */
- uint8_t op_code; /* The op (request/response) code */
- uint8_t dep_id; /* MDEP ID */
- uint8_t cfg; /* The configuration to negotiate */
-} tMCA_CREATE_IND;
-
-/* This data structure is associated with the MCA_CREATE_CFM_EVT. */
-typedef struct {
- uint16_t mdl_id; /* The associated MDL ID */
- uint8_t op_code; /* The op (request/response) code */
- uint8_t rsp_code; /* The response code. */
- uint8_t cfg; /* The configuration to negotiate */
-} tMCA_CREATE_CFM;
-
-/* This data structure is associated with MCA_CONNECT_IND_EVT. */
-typedef struct {
- RawAddress bd_addr; /* The peer address */
- uint16_t mtu; /* peer mtu */
-} tMCA_CONNECT_IND;
-
-/* This data structure is associated with MCA_DISCONNECT_IND_EVT. */
-typedef struct {
- RawAddress bd_addr; /* The peer address */
- uint16_t reason; /* disconnect reason given by L2CAP */
-} tMCA_DISCONNECT_IND;
-
-/* This data structure is for MCA_OPEN_IND_EVT, and MCA_OPEN_CFM_EVT. */
-typedef struct {
- uint16_t mdl_id; /* The associated MDL ID */
- tMCA_DL mdl; /* The handle for the data channel */
- uint16_t mtu; /* peer mtu */
-} tMCA_DL_OPEN;
-
-/* This data structure is for MCA_CLOSE_IND_EVT and MCA_CLOSE_CFM_EVT. */
-typedef struct {
- uint16_t mdl_id; /* The associated MDL ID */
- tMCA_DL mdl; /* The handle for the data channel */
- uint16_t reason; /* disconnect reason given by L2CAP */
-} tMCA_DL_CLOSE;
-
-/* This data structure is associated with MCA_CONG_CHG_EVT. */
-typedef struct {
- uint16_t mdl_id; /* N/A - This is a place holder */
- tMCA_DL mdl; /* The handle for the data channel */
- bool cong; /* true, if the channel is congested */
-} tMCA_CONG_CHG;
-
-/* Union of all control callback event data structures */
-typedef union {
- tMCA_EVT_HDR hdr;
- tMCA_RSP_EVT rsp;
- tMCA_CREATE_IND create_ind;
- tMCA_CREATE_CFM create_cfm;
- tMCA_EVT_HDR reconnect_ind;
- tMCA_RSP_EVT reconnect_cfm;
- tMCA_EVT_HDR abort_ind;
- tMCA_RSP_EVT abort_cfm;
- tMCA_EVT_HDR delete_ind;
- tMCA_RSP_EVT delete_cfm;
- tMCA_CONNECT_IND connect_ind;
- tMCA_DISCONNECT_IND disconnect_ind;
- tMCA_DL_OPEN open_ind;
- tMCA_DL_OPEN open_cfm;
- tMCA_DL_CLOSE close_ind;
- tMCA_DL_CLOSE close_cfm;
- tMCA_CONG_CHG cong_chg;
-} tMCA_CTRL;
-
-/* This is the control callback function. This function passes control events
- * to the application.
-*/
-typedef void(tMCA_CTRL_CBACK)(tMCA_HANDLE handle, tMCA_CL mcl, uint8_t event,
- tMCA_CTRL* p_data);
-
-/*******************************************************************************
- *
- * Function MCA_Init
- *
- * Description Initialize MCAP internal control blocks.
- * This function is called at stack start up.
- *
- * Returns void
- *
- ******************************************************************************/
-extern void MCA_Init(void);
-
-/*******************************************************************************
- *
- * Function MCA_SetTraceLevel
- *
- * Description This function sets the debug trace level for MCA.
- * If 0xff is passed, the current trace level is returned.
- *
- * Input Parameters:
- * level: The level to set the MCA tracing to:
- * 0xff-returns the current setting.
- * 0-turns off tracing.
- * >= 1-Errors.
- * >= 2-Warnings.
- * >= 3-APIs.
- * >= 4-Events.
- * >= 5-Debug.
- *
- * Returns The new trace level or current trace level if
- * the input parameter is 0xff.
- *
- ******************************************************************************/
-extern uint8_t MCA_SetTraceLevel(uint8_t level);
-
-/*******************************************************************************
- *
- * Function MCA_Register
- *
- * Description This function registers an MCAP implementation.
- * It is assumed that the control channel PSM and data channel
- * PSM are not used by any other instances of the stack.
- * If the given p_reg->ctrl_psm is 0, this handle is INT only.
- *
- * Returns 0, if failed. Otherwise, the MCA handle.
- *
- ******************************************************************************/
-extern tMCA_HANDLE MCA_Register(tMCA_REG* p_reg, tMCA_CTRL_CBACK* p_cback);
-
-/*******************************************************************************
- *
- * Function MCA_Deregister
- *
- * Description Deregister an MCAP implementation. Before this function can
- * be called, all control and data channels must be removed
- * with MCA_DisconnectReq and MCA_CloseReq.
- *
- * Returns void
- *
- ******************************************************************************/
-extern void MCA_Deregister(tMCA_HANDLE handle);
-
-/*******************************************************************************
- *
- * Function MCA_CreateDep
- *
- * Description Create a data endpoint. If the MDEP is created
- * successfully, the MDEP ID is returned in *p_dep. After a
- * data endpoint is created, an application can initiate a
- * connection between this endpoint and an endpoint on a peer
- * device.
- *
- * Returns MCA_SUCCESS if successful, otherwise error.
- *
- ******************************************************************************/
-extern tMCA_RESULT MCA_CreateDep(tMCA_HANDLE handle, tMCA_DEP* p_dep,
- tMCA_CS* p_cs);
-
-/*******************************************************************************
- *
- * Function MCA_DeleteDep
- *
- * Description Delete a data endpoint. This function is called when
- * the implementation is no longer using a data endpoint.
- * If this function is called when the endpoint is connected
- * the connection is closed and the data endpoint
- * is removed.
- *
- * Returns MCA_SUCCESS if successful, otherwise error.
- *
- ******************************************************************************/
-extern tMCA_RESULT MCA_DeleteDep(tMCA_HANDLE handle, tMCA_DEP dep);
-
-/*******************************************************************************
- *
- * Function MCA_ConnectReq
- *
- * Description This function initiates an MCAP control channel connection
- * to the peer device. When the connection is completed, an
- * MCA_CONNECT_IND_EVT is reported to the application via its
- * control callback function.
- * This control channel is identified by tMCA_CL.
- * If the connection attempt fails, an MCA_DISCONNECT_IND_EVT
- * is reported. The security mask parameter overrides the
- * outgoing security mask set in MCA_Register().
- *
- * Returns MCA_SUCCESS if successful, otherwise error.
- *
- ******************************************************************************/
-extern tMCA_RESULT MCA_ConnectReq(tMCA_HANDLE handle, const RawAddress& bd_addr,
- uint16_t ctrl_psm, uint16_t sec_mask);
-
-/*******************************************************************************
- *
- * Function MCA_DisconnectReq
- *
- * Description This function disconnect an MCAP control channel
- * to the peer device.
- * If associated data channel exists, they are disconnected.
- * When the MCL is disconnected an MCA_DISCONNECT_IND_EVT is
- * reported to the application via its control callback
- * function.
- *
- * Returns MCA_SUCCESS if successful, otherwise error.
- *
- ******************************************************************************/
-extern tMCA_RESULT MCA_DisconnectReq(tMCA_CL mcl);
-
-/*******************************************************************************
- *
- * Function MCA_CreateMdl
- *
- * Description This function sends a CREATE_MDL request to the peer device.
- * When the response is received, a MCA_CREATE_CFM_EVT is
- * reported with the given MDL ID.
- * If the response is successful, a data channel is open
- * with the given p_chnl_cfg
- * When the data channel is open successfully, a
- * MCA_OPEN_CFM_EVT is reported. This data channel is
- * identified as tMCA_DL.
- *
- * Returns MCA_SUCCESS if successful, otherwise error.
- *
- ******************************************************************************/
-extern tMCA_RESULT MCA_CreateMdl(tMCA_CL mcl, tMCA_DEP dep, uint16_t data_psm,
- uint16_t mdl_id, uint8_t peer_dep_id,
- uint8_t cfg, const tMCA_CHNL_CFG* p_chnl_cfg);
-
-/*******************************************************************************
- *
- * Function MCA_CreateMdlRsp
- *
- * Description This function sends a CREATE_MDL response to the peer device
- * in response to a received MCA_CREATE_IND_EVT.
- * If the rsp_code is successful, a data channel is open
- * with the given p_chnl_cfg
- * When the data channel is open successfully, a
- * MCA_OPEN_IND_EVT is reported. This data channel is
- * identified as tMCA_DL.
- *
- * Returns MCA_SUCCESS if successful, otherwise error.
- *
- ******************************************************************************/
-extern tMCA_RESULT MCA_CreateMdlRsp(tMCA_CL mcl, tMCA_DEP dep, uint16_t mdl_id,
- uint8_t cfg, uint8_t rsp_code,
- const tMCA_CHNL_CFG* p_chnl_cfg);
-
-/*******************************************************************************
- *
- * Function MCA_CloseReq
- *
- * Description Close a data channel. When the channel is closed, an
- * MCA_CLOSE_CFM_EVT is sent to the application via the
- * control callback function for this handle.
- *
- * Returns MCA_SUCCESS if successful, otherwise error.
- *
- ******************************************************************************/
-extern tMCA_RESULT MCA_CloseReq(tMCA_DL mdl);
-
-/*******************************************************************************
- *
- * Function MCA_ReconnectMdl
- *
- * Description This function sends a RECONNECT_MDL request to the peer
- * device. When the response is received, a
- * MCA_RECONNECT_CFM_EVT is reported. If the response is
- * successful, a data channel is open. When the data channel is
- * open successfully, a MCA_OPEN_CFM_EVT is reported.
- *
- * Returns MCA_SUCCESS if successful, otherwise error.
- *
- ******************************************************************************/
-extern tMCA_RESULT MCA_ReconnectMdl(tMCA_CL mcl, tMCA_DEP dep,
- uint16_t data_psm, uint16_t mdl_id,
- const tMCA_CHNL_CFG* p_chnl_cfg);
-
-/*******************************************************************************
- *
- * Function MCA_ReconnectMdlRsp
- *
- * Description Send a RECONNECT_MDL response to the peer device in response
- * to a MCA_RECONNECT_IND_EVT event.
- * If the response is successful, a data channel is open.
- * When the data channel is open successfully, a
- * MCA_OPEN_IND_EVT is reported.
- *
- * Returns MCA_SUCCESS if successful, otherwise error.
- *
- ******************************************************************************/
-extern tMCA_RESULT MCA_ReconnectMdlRsp(tMCA_CL mcl, tMCA_DEP dep,
- uint16_t mdl_id, uint8_t rsp_code,
- const tMCA_CHNL_CFG* p_chnl_cfg);
-
-/*******************************************************************************
- *
- * Function MCA_DataChnlCfg
- *
- * Description This function initiates a data channel connection toward the
- * connected peer device.
- * When the data channel is open successfully, a
- * MCA_OPEN_CFM_EVT is reported. This data channel is
- * identified as tMCA_DL.
- *
- * Returns MCA_SUCCESS if successful, otherwise error.
- *
- ******************************************************************************/
-extern tMCA_RESULT MCA_DataChnlCfg(tMCA_CL mcl,
- const tMCA_CHNL_CFG* p_chnl_cfg);
-
-/*******************************************************************************
- *
- * Function MCA_Abort
- *
- * Description This function sends a ABORT_MDL request to the peer device.
- * When the response is received, a MCA_ABORT_CFM_EVT is
- * reported.
- *
- * Returns MCA_SUCCESS if successful, otherwise error.
- *
- ******************************************************************************/
-extern tMCA_RESULT MCA_Abort(tMCA_CL mcl);
-
-/*******************************************************************************
- *
- * Function MCA_Delete
- *
- * Description This function sends a DELETE_MDL request to the peer device.
- * When the response is received, a MCA_DELETE_CFM_EVT is
- * reported.
- *
- * Returns MCA_SUCCESS if successful, otherwise error.
- *
- ******************************************************************************/
-extern tMCA_RESULT MCA_Delete(tMCA_CL mcl, uint16_t mdl_id);
-
-/*******************************************************************************
- *
- * Function MCA_WriteReq
- *
- * Description Send a data packet to the peer device.
- *
- * The application passes the packet using the BT_HDR
- * structure. The offset field must be equal to or greater than
- * L2CAP_MIN_OFFSET. This allows enough space in the buffer for
- * the L2CAP header.
- *
- * The memory pointed to by p_pkt must be a GKI buffer
- * allocated by the application. This buffer will be freed
- * by the protocol stack; the application must not free
- * this buffer.
- *
- * Returns MCA_SUCCESS if successful, otherwise error.
- *
- ******************************************************************************/
-extern tMCA_RESULT MCA_WriteReq(tMCA_DL mdl, BT_HDR* p_pkt);
-
-/*******************************************************************************
- *
- * Function MCA_GetL2CapChannel
- *
- * Description Get the L2CAP CID used by the given data channel handle.
- *
- * Returns L2CAP channel ID if successful, otherwise 0.
- *
- ******************************************************************************/
-extern uint16_t MCA_GetL2CapChannel(tMCA_DL mdl);
-
-/**
- * The following definitions are for test interface only, they mirror function
- * definitions above. This struct allows an external application to load and
- * call these methods without linking against the core library.
- */
-typedef struct {
- size_t size;
- void (*init)(void);
- tMCA_HANDLE (*register_application)(tMCA_REG* p_reg,
- tMCA_CTRL_CBACK* p_cback);
- void (*deregister_application)(tMCA_HANDLE handle);
- tMCA_RESULT (*create_mdep)(tMCA_HANDLE handle, tMCA_DEP* p_dep,
- tMCA_CS* p_cs);
- tMCA_RESULT (*delete_mdep)(tMCA_HANDLE handle, tMCA_DEP dep);
- tMCA_RESULT (*connect_mcl)(tMCA_HANDLE handle, const RawAddress& bd_addr,
- uint16_t ctrl_psm, uint16_t sec_mask);
- tMCA_RESULT (*disconnect_mcl)(tMCA_CL mcl);
- tMCA_RESULT (*create_mdl_request)(tMCA_CL mcl, tMCA_DEP dep,
- uint16_t data_psm, uint16_t mdl_id,
- uint8_t peer_dep_id, uint8_t cfg,
- const tMCA_CHNL_CFG* p_chnl_cfg);
- tMCA_RESULT (*create_mdl_response)(tMCA_CL mcl, tMCA_DEP dep, uint16_t mdl_id,
- uint8_t cfg, uint8_t rsp_code,
- const tMCA_CHNL_CFG* p_chnl_cfg);
- tMCA_RESULT (*close_mdl_request)(tMCA_DL mdl);
- tMCA_RESULT (*reconnect_mdl_request)(tMCA_CL mcl, tMCA_DEP dep,
- uint16_t data_psm, uint16_t mdl_id,
- const tMCA_CHNL_CFG* p_chnl_cfg);
- tMCA_RESULT (*reconnect_mdl_response)(tMCA_CL mcl, tMCA_DEP dep,
- uint16_t mdl_id, uint8_t rsp_code,
- const tMCA_CHNL_CFG* p_chnl_cfg);
- tMCA_RESULT (*data_channel_config)(tMCA_CL mcl,
- const tMCA_CHNL_CFG* p_chnl_cfg);
- tMCA_RESULT (*abort_mdl)(tMCA_CL mcl);
- tMCA_RESULT (*delete_mdl)(tMCA_CL mcl, uint16_t mdl_id);
- tMCA_RESULT (*write_mdl)(tMCA_DL mdl, BT_HDR* p_pkt);
- uint16_t (*get_l2cap_channel)(tMCA_DL mdl);
-} btmcap_test_interface_t;
-
-#endif /* MCA_API_H */
diff --git a/stack/include/mca_defs.h b/stack/include/mca_defs.h
deleted file mode 100644
index 7b6d3c2..0000000
--- a/stack/include/mca_defs.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2009-2012 Broadcom 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.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- * This contains constants definitions and other information from the MCAP
- * specification.
- *
- ******************************************************************************/
-#ifndef MCA_DEFS_H
-#define MCA_DEFS_H
-
-/*****************************************************************************
- * constants
- ****************************************************************************/
-#define MCA_MIN_MTU 48
-
-/* standard op codes */
-/* invalid opcode response */
-#define MCA_OP_ERROR_RSP 0x00
-/* create an MDL, wait for an associated data channel connection */
-#define MCA_OP_MDL_CREATE_REQ 0x01
-/* response to above request */
-#define MCA_OP_MDL_CREATE_RSP 0x02
-/* req to prepare to rvc a data channel conn associated with a prev MDL */
-#define MCA_OP_MDL_RECONNECT_REQ 0x03
-/* response to above request */
-#define MCA_OP_MDL_RECONNECT_RSP 0x04
-/* stop waiting for a data channel connection */
-#define MCA_OP_MDL_ABORT_REQ 0x05
-/* response to above request */
-#define MCA_OP_MDL_ABORT_RSP 0x06
-/* delete an MDL */
-#define MCA_OP_MDL_DELETE_REQ 0x07
-/* response to above request */
-#define MCA_OP_MDL_DELETE_RSP 0x08
-#define MCA_NUM_STANDARD_OPCODE (1 + MCA_OP_MDL_DELETE_RSP)
-
-/* clock synchronization op codes */
-/* request sync capabilities & requirements */
-#define MCA_OP_SYNC_CAP_REQ 0x11
-/* indicate completion */
-#define MCA_OP_SYNC_CAP_RSP 0x12
-/* request to set the time-stamp clock */
-#define MCA_OP_SYNC_SET_REQ 0x13
-/* indicate completion */
-#define MCA_OP_SYNC_SET_RSP 0x14
-/* update of the actual time-stamp clock instant from the sync slave */
-#define MCA_OP_SYNC_INFO_IND 0x15
-
-#define MCA_FIRST_SYNC_OP MCA_OP_SYNC_CAP_REQ
-#define MCA_LAST_SYNC_OP MCA_OP_SYNC_INFO_IND
-
-/* response code */
-/* The corresponding request was received and processed successfully. */
-#define MCA_RSP_SUCCESS 0x00
-/* The Op Code received is not valid (i.e. neither a Standard Op Code nor a
- * Clock Synchronization Protocol Op Code). */
-#define MCA_RSP_BAD_OPCODE 0x01
-/* One or more of the values in the received request is invalid. */
-#define MCA_RSP_BAD_PARAM 0x02
-/* MCA_RSP_BAD_PARAM shall be used when:
-- The request length is invalid
-- Some of the parameters have invalid values and none of the other defined
-Response Codes are more appropriate.
-*/
-/* The MDEP ID referenced does not exist on this device. */
-#define MCA_RSP_BAD_MDEP 0x03
-/* The requested MDEP currently has as many active MDLs as it can manage
- * simultaneously. */
-#define MCA_RSP_MDEP_BUSY 0x04
-/* The MDL ID referenced is invalid. */
-#define MCA_RSP_BAD_MDL 0x05
-/* MCA_RSP_BAD_MDL shall be used when:
-- A reserved or invalid value for MDL ID was used.
-- The MDL ID referenced is not available (was never created, has been deleted,
-or was otherwise lost),
-- The MDL ID referenced in the Abort request is not the same value that was used
-to initiate the PENDING state
-*/
-/* The device is temporarily unable to complete the request. This is intended
- * for reasons not related to the physical sensor (e.g. communication resources
- * unavailable). */
-#define MCA_RSP_MDL_BUSY 0x06
-/* The received request is invalid in the current state. */
-#define MCA_RSP_BAD_OP 0x07
-/* MCA_RSP_BAD_OP is used when
-- Abort request was received while not in the PENDING state.
-- Create, Reconnect, or Delete request was received while in the PENDING state.
-- A response is received when a request is expected
-*/
-/* The device is temporarily unable to complete the request. This is intended
- * for reasons relating to the physical sensor (e.g. hardware fault, low
- * battery), or when processing resources are temporarily committed to other
- * processes. */
-#define MCA_RSP_NO_RESOURCE 0x08
-/* An internal error other than those listed in this table was encountered while
- * processing the request. */
-#define MCA_RSP_ERROR 0x09
-/* The Op Code that was used in this request is not supported. */
-#define MCA_RSP_NO_SUPPORT 0x0A
-/* A configuration required by a MD_CREATE_MDL or MD_RECONNECT_MDL operation has
- * been rejected. */
-#define MCA_RSP_CFG_REJ 0x0B
-
-/* the valid range for MDEP ID is 1-0x7F */
-#define MCA_MAX_MDEP_ID 0x7F
-#define MCA_IS_VALID_MDL_ID(xxx) (((xxx) > 0) && ((xxx) <= 0xFEFF))
-#define MCA_ALL_MDL_ID 0xFFFF
-
-#endif /* MCA_DEFS_H */
diff --git a/stack/include/port_api.h b/stack/include/port_api.h
index aedbe74..b0a7e63 100644
--- a/stack/include/port_api.h
+++ b/stack/include/port_api.h
@@ -309,7 +309,7 @@
* p_lcid - OUT L2CAP's LCID
*
******************************************************************************/
-extern int PORT_CheckConnection(uint16_t handle, RawAddress& bd_addr,
+extern int PORT_CheckConnection(uint16_t handle, RawAddress* bd_addr,
uint16_t* p_lcid);
/*******************************************************************************
@@ -323,7 +323,7 @@
* bd_addr - bd_addr of the peer
*
******************************************************************************/
-extern bool PORT_IsOpening(RawAddress& bd_addr);
+extern bool PORT_IsOpening(RawAddress* bd_addr);
/*******************************************************************************
*
diff --git a/stack/include/sdpdefs.h b/stack/include/sdpdefs.h
index 05b3cc1..4e4b7b9 100644
--- a/stack/include/sdpdefs.h
+++ b/stack/include/sdpdefs.h
@@ -143,11 +143,6 @@
#define ATTR_ID_HID_SSR_HOST_MAX_LAT 0x020F
#define ATTR_ID_HID_SSR_HOST_MIN_TOUT 0x0210
-/* These values are for the HDP profile */
-#define ATTR_ID_HDP_SUP_FEAT_LIST 0x0200 /* Supported features list */
-#define ATTR_ID_HDP_DATA_EXCH_SPEC 0x0301 /* Data exchange specification */
-#define ATTR_ID_HDP_MCAP_SUP_PROC 0x0302 /* MCAP supported procedures */
-
/* Define common 16-bit protocol UUIDs
*/
#define UUID_PROTOCOL_SDP 0x0001
diff --git a/stack/include/smp_api.h b/stack/include/smp_api.h
index 816407d..8a66aae 100644
--- a/stack/include/smp_api.h
+++ b/stack/include/smp_api.h
@@ -176,24 +176,6 @@
/*******************************************************************************
*
- * Function SMP_Encrypt
- *
- * Description Encrypt the data with the specified key.
- *
- * Parameters: key - Pointer to key key[0] conatins the MSB
- * key_len - key length
- * plain_text - Pointer to data to be encrypted
- * plain_text[0] conatins the MSB
- * pt_len - plain text length
- * p_out - pointer to the encrypted outputs
- *
- * Returns Boolean - true: encryption is successful
- ******************************************************************************/
-extern bool SMP_Encrypt(uint8_t* key, uint8_t key_len, uint8_t* plain_text,
- uint8_t pt_len, tSMP_ENC* p_out);
-
-/*******************************************************************************
- *
* Function SMP_KeypressNotification
*
* Description Notify SM about Keypress Notification.
@@ -227,16 +209,4 @@
// Proceed to send LTK, DIV and ER to master if bonding the devices.
extern void smp_link_encrypted(const RawAddress& bda, uint8_t encr_enable);
-//
-// The AES-CMAC Generation Function with tlen implemented.
-// |key| - CMAC key in little endian order, expect SRK when used by SMP.
-// |input| - text to be signed in little endian byte order.
-// |length| - length of the input in byte.
-// |tlen| - lenth of mac desired
-// |p_signature| - data pointer to where signed data to be stored, tlen long.
-// Returns false if out of resources, true in other cases.
-//
-bool aes_cipher_msg_auth_code(BT_OCTET16 key, uint8_t* input, uint16_t length,
- uint16_t tlen, uint8_t* p_signature);
-
#endif /* SMP_API_H */
diff --git a/stack/include/smp_api_types.h b/stack/include/smp_api_types.h
index fad8b75..cee1204 100644
--- a/stack/include/smp_api_types.h
+++ b/stack/include/smp_api_types.h
@@ -109,10 +109,6 @@
#define SMP_IO_CAP_MAX BTM_IO_CAP_MAX
typedef uint8_t tSMP_IO_CAP;
-#ifndef SMP_DEFAULT_IO_CAPS
-#define SMP_DEFAULT_IO_CAPS SMP_IO_CAP_KBDISP
-#endif
-
/* OOB data present or not */
enum { SMP_OOB_NONE, SMP_OOB_PRESENT, SMP_OOB_UNKNOWN };
typedef uint8_t tSMP_OOB_FLAG;
@@ -224,8 +220,8 @@
/* the data associated with the info sent to the peer via OOB interface */
typedef struct {
bool present;
- BT_OCTET16 randomizer;
- BT_OCTET16 commitment;
+ Octet16 randomizer;
+ Octet16 commitment;
tBLE_BD_ADDR addr_sent_to;
BT_OCTET32 private_key_used; /* is used to calculate: */
@@ -238,8 +234,8 @@
/* the data associated with the info received from the peer via OOB interface */
typedef struct {
bool present;
- BT_OCTET16 randomizer;
- BT_OCTET16 commitment;
+ Octet16 randomizer;
+ Octet16 commitment;
tBLE_BD_ADDR addr_rcvd_from;
} tSMP_PEER_OOB_DATA;
@@ -261,7 +257,7 @@
uint8_t status;
uint8_t param_len;
uint16_t opcode;
- uint8_t param_buf[BT_OCTET16_LEN];
+ uint8_t param_buf[OCTET16_LEN];
} tSMP_ENC;
/* Security Manager events - Called by the stack when Security Manager related
diff --git a/stack/include/srvc_api.h b/stack/include/srvc_api.h
index e968998..ad01237 100644
--- a/stack/include/srvc_api.h
+++ b/stack/include/srvc_api.h
@@ -165,35 +165,4 @@
extern bool DIS_ReadDISInfo(const RawAddress& peer_bda,
tDIS_READ_CBACK* p_cback, tDIS_ATTR_MASK mask);
-/*******************************************************************************
- * BATTERY SERVICE API
- ******************************************************************************/
-/*******************************************************************************
- *
- * Function Battery_Instantiate
- *
- * Description Instantiate a Battery service
- *
- ******************************************************************************/
-extern uint16_t Battery_Instantiate(uint8_t app_id, tBA_REG_INFO* p_reg_info);
-
-/*******************************************************************************
- *
- * Function Battery_Rsp
- *
- * Description Respond to a battery service request
- *
- ******************************************************************************/
-extern void Battery_Rsp(uint8_t app_id, tGATT_STATUS st, uint8_t event,
- tBA_RSP_DATA* p_rsp);
-/*******************************************************************************
- *
- * Function Battery_Notify
- *
- * Description Send battery level notification
- *
- ******************************************************************************/
-extern void Battery_Notify(uint8_t app_id, const RawAddress& remote_bda,
- uint8_t battery_level);
-
#endif
diff --git a/stack/l2cap/l2c_api.cc b/stack/l2cap/l2c_api.cc
index 951a45b..6dc41de 100644
--- a/stack/l2cap/l2c_api.cc
+++ b/stack/l2cap/l2c_api.cc
@@ -275,7 +275,7 @@
*
******************************************************************************/
uint16_t L2CA_ConnectReq(uint16_t psm, const RawAddress& p_bd_addr) {
- return L2CA_ErtmConnectReq(psm, p_bd_addr, NULL);
+ return L2CA_ErtmConnectReq(psm, p_bd_addr, nullptr);
}
/*******************************************************************************
@@ -297,10 +297,6 @@
******************************************************************************/
uint16_t L2CA_ErtmConnectReq(uint16_t psm, const RawAddress& p_bd_addr,
tL2CAP_ERTM_INFO* p_ertm_info) {
- tL2C_LCB* p_lcb;
- tL2C_CCB* p_ccb;
- tL2C_RCB* p_rcb;
-
VLOG(1) << __func__ << "BDA " << p_bd_addr
<< StringPrintf(" PSM: 0x%04x allowed:0x%x preferred:%d", psm,
(p_ertm_info) ? p_ertm_info->allowed_modes : 0,
@@ -308,36 +304,36 @@
/* Fail if we have not established communications with the controller */
if (!BTM_IsDeviceUp()) {
- L2CAP_TRACE_WARNING("L2CAP connect req - BTU not ready");
- return (0);
+ LOG(WARNING) << __func__ << ": BTU not ready";
+ return 0;
}
/* Fail if the PSM is not registered */
- p_rcb = l2cu_find_rcb_by_psm(psm);
- if (p_rcb == NULL) {
- L2CAP_TRACE_WARNING("L2CAP - no RCB for L2CA_conn_req, PSM: 0x%04x", psm);
- return (0);
+ tL2C_RCB* p_rcb = l2cu_find_rcb_by_psm(psm);
+ if (p_rcb == nullptr) {
+ LOG(WARNING) << __func__ << ": no RCB, PSM=" << loghex(psm);
+ return 0;
}
/* First, see if we already have a link to the remote */
/* assume all ERTM l2cap connection is going over BR/EDR for now */
- p_lcb = l2cu_find_lcb_by_bd_addr(p_bd_addr, BT_TRANSPORT_BR_EDR);
- if (p_lcb == NULL) {
+ tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(p_bd_addr, BT_TRANSPORT_BR_EDR);
+ if (p_lcb == nullptr) {
/* No link. Get an LCB and start link establishment */
p_lcb = l2cu_allocate_lcb(p_bd_addr, false, BT_TRANSPORT_BR_EDR);
/* currently use BR/EDR for ERTM mode l2cap connection */
- if ((p_lcb == NULL) || (!l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR))) {
- L2CAP_TRACE_WARNING(
- "L2CAP - conn not started for PSM: 0x%04x p_lcb: 0x%08x", psm,
- p_lcb);
- return (0);
+ if ((p_lcb == nullptr) || (!l2cu_create_conn_br_edr(p_lcb))) {
+ LOG(WARNING) << __func__
+ << ": connection not started for PSM=" << loghex(psm)
+ << ", p_lcb=" << p_lcb;
+ return 0;
}
}
/* Allocate a channel control block */
- p_ccb = l2cu_allocate_ccb(p_lcb, 0);
- if (p_ccb == NULL) {
- L2CAP_TRACE_WARNING("L2CAP - no CCB for L2CA_conn_req, PSM: 0x%04x", psm);
- return (0);
+ tL2C_CCB* p_ccb = l2cu_allocate_ccb(p_lcb, 0);
+ if (p_ccb == nullptr) {
+ LOG(WARNING) << __func__ << ": no CCB, PSM=" << loghex(psm);
+ return 0;
}
/* Save registration info */
@@ -366,16 +362,14 @@
/* If link is up, start the L2CAP connection */
if (p_lcb->link_state == LST_CONNECTED) {
- l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONNECT_REQ, NULL);
- }
-
- /* If link is disconnecting, save link info to retry after disconnect
- * Possible Race condition when a reconnect occurs
- * on the channel during a disconnect of link. This
- * ccb will be automatically retried after link disconnect
- * arrives
- */
- else if (p_lcb->link_state == LST_DISCONNECTING) {
+ l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONNECT_REQ, nullptr);
+ } else if (p_lcb->link_state == LST_DISCONNECTING) {
+ /* If link is disconnecting, save link info to retry after disconnect
+ * Possible Race condition when a reconnect occurs
+ * on the channel during a disconnect of link. This
+ * ccb will be automatically retried after link disconnect
+ * arrives
+ */
L2CAP_TRACE_DEBUG("L2CAP API - link disconnecting: RETRY LATER");
/* Save ccb so it can be started after disconnect is finished */
@@ -386,7 +380,7 @@
psm, p_ccb->local_cid);
/* Return the local CID as our handle */
- return (p_ccb->local_cid);
+ return p_ccb->local_cid;
}
/*******************************************************************************
@@ -537,7 +531,7 @@
p_lcb = l2cu_allocate_lcb(p_bd_addr, false, BT_TRANSPORT_LE);
if ((p_lcb == NULL)
/* currently use BR/EDR for ERTM mode l2cap connection */
- || (!l2cu_create_conn(p_lcb, BT_TRANSPORT_LE))) {
+ || (!l2cu_create_conn_le(p_lcb))) {
L2CAP_TRACE_WARNING("%s conn not started for PSM: 0x%04x p_lcb: 0x%08x",
__func__, psm, p_lcb);
return 0;
@@ -982,7 +976,7 @@
L2CAP_TRACE_WARNING("L2CAP - no LCB for L2CA_ping");
return (false);
}
- if (!l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR)) {
+ if (!l2cu_create_conn_br_edr(p_lcb)) {
return (false);
}
@@ -1748,12 +1742,16 @@
return false;
}
- if (!l2cu_create_conn(p_lcb, transport, initiating_phys)) {
- L2CAP_TRACE_WARNING("%s() - create_conn failed", __func__);
+ bool ret = ((transport == BT_TRANSPORT_LE)
+ ? l2cu_create_conn_le(p_lcb, initiating_phys)
+ : l2cu_create_conn_br_edr(p_lcb));
+
+ if (!ret) {
+ L2CAP_TRACE_WARNING("%s() - create connection failed", __func__);
l2cu_release_lcb(p_lcb);
- return false;
}
- return true;
+
+ return ret;
}
/*******************************************************************************
diff --git a/stack/l2cap/l2c_ble.cc b/stack/l2cap/l2c_ble.cc
index 5fc01f9..bd1a503 100644
--- a/stack/l2cap/l2c_ble.cc
+++ b/stack/l2cap/l2c_ble.cc
@@ -32,10 +32,12 @@
#include "btu.h"
#include "device/include/controller.h"
#include "hcimsgs.h"
+#include "l2c_api.h"
#include "l2c_int.h"
#include "l2cdefs.h"
#include "log/log.h"
#include "osi/include/osi.h"
+#include "stack/gatt/connection_manager.h"
#include "stack_config.h"
using base::StringPrintf;
@@ -54,26 +56,19 @@
*
******************************************************************************/
bool L2CA_CancelBleConnectReq(const RawAddress& rem_bda) {
- tL2C_LCB* p_lcb;
+ tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, BT_TRANSPORT_LE);
- /* There can be only one BLE connection request outstanding at a time */
- if (btm_ble_get_conn_st() == BLE_CONN_IDLE) {
- L2CAP_TRACE_WARNING("%s - no connection pending", __func__);
- return (false);
+ tACL_CONN* p_acl = btm_bda_to_acl(rem_bda, BT_TRANSPORT_LE);
+ if (p_acl) {
+ if (p_lcb != NULL && p_lcb->link_state == LST_CONNECTING) {
+ L2CAP_TRACE_WARNING("%s - disconnecting the LE link", __func__);
+ L2CA_RemoveFixedChnl(L2CAP_ATT_CID, rem_bda);
+ return (true);
+ }
}
- if (rem_bda != l2cb.ble_connecting_bda) {
- LOG(WARNING) << __func__
- << " different BDA Connecting: " << l2cb.ble_connecting_bda
- << " Cancel: " << rem_bda;
+ connection_manager::direct_connect_remove(CONN_MGR_ID_L2CAP, rem_bda);
- btm_ble_dequeue_direct_conn_req(rem_bda);
- return (false);
- }
-
- btsnd_hcic_ble_create_conn_cancel();
-
- p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, BT_TRANSPORT_LE);
/* Do not remove lcb if an LE link is already up as a peripheral */
if (p_lcb != NULL &&
!(p_lcb->link_role == HCI_ROLE_SLAVE &&
@@ -81,9 +76,6 @@
p_lcb->disc_reason = L2CAP_CONN_CANCEL;
l2cu_release_lcb(p_lcb);
}
- /* update state to be cancel, wait for connection cancel complete */
- btm_ble_set_conn_st(BLE_CONN_CANCEL);
-
return (true);
}
@@ -261,39 +253,30 @@
}
}
-/*******************************************************************************
- *
- * Function l2cble_scanner_conn_comp
- *
- * Description This function is called when an HCI Connection Complete
- * event is received while we are a scanner (so we are master).
- *
- * Returns void
- *
- ******************************************************************************/
-void l2cble_scanner_conn_comp(uint16_t handle, const RawAddress& bda,
- tBLE_ADDR_TYPE type, uint16_t conn_interval,
- uint16_t conn_latency, uint16_t conn_timeout) {
- tL2C_LCB* p_lcb;
- tBTM_SEC_DEV_REC* p_dev_rec = btm_find_or_alloc_dev(bda);
+/** This function is called when an HCI Connection Complete event is received.
+ */
+void l2cble_conn_comp(uint16_t handle, uint8_t role, const RawAddress& bda,
+ tBLE_ADDR_TYPE type, uint16_t conn_interval,
+ uint16_t conn_latency, uint16_t conn_timeout) {
+ btm_ble_update_link_topology_mask(role, true);
+
+ // role == HCI_ROLE_MASTER => scanner completed connection
+ // role == HCI_ROLE_SLAVE => advertiser completed connection
L2CAP_TRACE_DEBUG(
- "l2cble_scanner_conn_comp: HANDLE=%d addr_type=%d conn_interval=%d "
+ "%s: HANDLE=%d addr_type=%d conn_interval=%d "
"slave_latency=%d supervision_tout=%d",
- handle, type, conn_interval, conn_latency, conn_timeout);
-
- l2cb.is_ble_connecting = false;
+ __func__, handle, type, conn_interval, conn_latency, conn_timeout);
/* See if we have a link control block for the remote device */
- p_lcb = l2cu_find_lcb_by_bd_addr(bda, BT_TRANSPORT_LE);
+ tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(bda, BT_TRANSPORT_LE);
/* If we don't have one, create one. this is auto connection complete. */
if (!p_lcb) {
p_lcb = l2cu_allocate_lcb(bda, false, BT_TRANSPORT_LE);
if (!p_lcb) {
btm_sec_disconnect(handle, HCI_ERR_NO_CONNECTION);
- L2CAP_TRACE_ERROR("l2cble_scanner_conn_comp - failed to allocate LCB");
- btm_ble_set_conn_st(BLE_CONN_IDLE);
+ LOG(ERROR) << __func__ << "failed to allocate LCB";
return;
} else {
if (!l2cu_initialize_fixed_ccb(
@@ -301,25 +284,24 @@
&l2cb.fixed_reg[L2CAP_ATT_CID - L2CAP_FIRST_FIXED_CHNL]
.fixed_chnl_opts)) {
btm_sec_disconnect(handle, HCI_ERR_NO_CONNECTION);
- L2CAP_TRACE_WARNING("l2cble_scanner_conn_comp - LCB but no CCB");
- btm_ble_set_conn_st(BLE_CONN_IDLE);
+ LOG(WARNING) << __func__ << "LCB but no CCB";
return;
}
}
- } else if (p_lcb->link_state != LST_CONNECTING) {
- L2CAP_TRACE_ERROR("L2CAP got BLE scanner conn_comp in bad state: %d",
- p_lcb->link_state);
- btm_ble_set_conn_st(BLE_CONN_IDLE);
+ } else if (role == HCI_ROLE_MASTER && p_lcb->link_state != LST_CONNECTING) {
+ LOG(ERROR) << "L2CAP got BLE scanner conn_comp in bad state: "
+ << +p_lcb->link_state;
return;
}
- alarm_cancel(p_lcb->l2c_lcb_timer);
+
+ if (role == HCI_ROLE_MASTER) alarm_cancel(p_lcb->l2c_lcb_timer);
/* Save the handle */
p_lcb->handle = handle;
/* Connected OK. Change state to connected, we were scanning so we are master
*/
- p_lcb->link_role = HCI_ROLE_MASTER;
+ p_lcb->link_role = role;
p_lcb->transport = BT_TRANSPORT_LE;
/* update link parameter, set slave link as non-spec default upon link up */
@@ -329,6 +311,7 @@
p_lcb->conn_update_mask = L2C_BLE_NOT_DEFAULT_PARAM;
/* Tell BTM Acl management about the link */
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_or_alloc_dev(bda);
btm_acl_created(bda, NULL, p_dev_rec->sec_bd_name, handle, p_lcb->link_role,
BT_TRANSPORT_LE);
@@ -336,116 +319,17 @@
L2CAP_FIXED_CHNL_BLE_SIG_BIT |
L2CAP_FIXED_CHNL_SMP_BIT;
- btm_ble_set_conn_st(BLE_CONN_IDLE);
-
#if (BLE_PRIVACY_SPT == TRUE)
btm_ble_disable_resolving_list(BTM_BLE_RL_INIT, true);
#endif
-}
-/*******************************************************************************
- *
- * Function l2cble_advertiser_conn_comp
- *
- * Description This function is called when an HCI Connection Complete
- * event is received while we are an advertiser (so we are
- * slave).
- *
- * Returns void
- *
- ******************************************************************************/
-void l2cble_advertiser_conn_comp(uint16_t handle, const RawAddress& bda,
- UNUSED_ATTR tBLE_ADDR_TYPE type,
- UNUSED_ATTR uint16_t conn_interval,
- UNUSED_ATTR uint16_t conn_latency,
- UNUSED_ATTR uint16_t conn_timeout) {
- tL2C_LCB* p_lcb;
- tBTM_SEC_DEV_REC* p_dev_rec;
-
- /* See if we have a link control block for the remote device */
- p_lcb = l2cu_find_lcb_by_bd_addr(bda, BT_TRANSPORT_LE);
-
- /* If we don't have one, create one and accept the connection. */
- if (!p_lcb) {
- p_lcb = l2cu_allocate_lcb(bda, false, BT_TRANSPORT_LE);
- if (!p_lcb) {
- btm_sec_disconnect(handle, HCI_ERR_NO_CONNECTION);
- L2CAP_TRACE_ERROR("l2cble_advertiser_conn_comp - failed to allocate LCB");
- return;
- } else {
- if (!l2cu_initialize_fixed_ccb(
- p_lcb, L2CAP_ATT_CID,
- &l2cb.fixed_reg[L2CAP_ATT_CID - L2CAP_FIRST_FIXED_CHNL]
- .fixed_chnl_opts)) {
- btm_sec_disconnect(handle, HCI_ERR_NO_CONNECTION);
- L2CAP_TRACE_WARNING("l2cble_scanner_conn_comp - LCB but no CCB");
- return;
- }
+ if (role == HCI_ROLE_SLAVE) {
+ if (!HCI_LE_SLAVE_INIT_FEAT_EXC_SUPPORTED(
+ controller_get_interface()->get_features_ble()->as_array)) {
+ p_lcb->link_state = LST_CONNECTED;
+ l2cu_process_fixed_chnl_resp(p_lcb);
}
}
-
- /* Save the handle */
- p_lcb->handle = handle;
-
- /* Connected OK. Change state to connected, we were advertising, so we are
- * slave */
- p_lcb->link_role = HCI_ROLE_SLAVE;
- p_lcb->transport = BT_TRANSPORT_LE;
-
- /* update link parameter, set slave link as non-spec default upon link up */
- p_lcb->min_interval = p_lcb->max_interval = conn_interval;
- p_lcb->timeout = conn_timeout;
- p_lcb->latency = conn_latency;
- p_lcb->conn_update_mask = L2C_BLE_NOT_DEFAULT_PARAM;
-
- /* Tell BTM Acl management about the link */
- p_dev_rec = btm_find_or_alloc_dev(bda);
-
- btm_acl_created(bda, NULL, p_dev_rec->sec_bd_name, handle, p_lcb->link_role,
- BT_TRANSPORT_LE);
-
-#if (BLE_PRIVACY_SPT == TRUE)
- btm_ble_disable_resolving_list(BTM_BLE_RL_ADV, true);
-#endif
-
- p_lcb->peer_chnl_mask[0] = L2CAP_FIXED_CHNL_ATT_BIT |
- L2CAP_FIXED_CHNL_BLE_SIG_BIT |
- L2CAP_FIXED_CHNL_SMP_BIT;
-
- if (!HCI_LE_SLAVE_INIT_FEAT_EXC_SUPPORTED(
- controller_get_interface()->get_features_ble()->as_array)) {
- p_lcb->link_state = LST_CONNECTED;
- l2cu_process_fixed_chnl_resp(p_lcb);
- }
-
- /* when adv and initiating are both active, cancel the direct connection */
- if (l2cb.is_ble_connecting && bda == l2cb.ble_connecting_bda) {
- L2CA_CancelBleConnectReq(bda);
- }
-}
-
-/*******************************************************************************
- *
- * Function l2cble_conn_comp
- *
- * Description This function is called when an HCI Connection Complete
- * event is received.
- *
- * Returns void
- *
- ******************************************************************************/
-void l2cble_conn_comp(uint16_t handle, uint8_t role, const RawAddress& bda,
- tBLE_ADDR_TYPE type, uint16_t conn_interval,
- uint16_t conn_latency, uint16_t conn_timeout) {
- btm_ble_update_link_topology_mask(role, true);
-
- if (role == HCI_ROLE_MASTER) {
- l2cble_scanner_conn_comp(handle, bda, type, conn_interval, conn_latency,
- conn_timeout);
- } else {
- l2cble_advertiser_conn_comp(handle, bda, type, conn_interval, conn_latency,
- conn_timeout);
- }
}
/*******************************************************************************
@@ -695,8 +579,8 @@
if (p_ccb) {
L2CAP_TRACE_WARNING("L2CAP - rcvd conn req for duplicated cid: 0x%04x",
rcid);
- l2cu_reject_ble_connection(p_lcb, id,
- L2CAP_LE_SOURCE_CID_ALREADY_ALLOCATED);
+ l2cu_reject_ble_connection(
+ p_lcb, id, L2CAP_LE_RESULT_SOURCE_CID_ALREADY_ALLOCATED);
break;
}
@@ -704,7 +588,7 @@
if (p_rcb == NULL) {
L2CAP_TRACE_WARNING("L2CAP - rcvd conn req for unknown PSM: 0x%04x",
con_info.psm);
- l2cu_reject_ble_connection(p_lcb, id, L2CAP_LE_NO_PSM);
+ l2cu_reject_ble_connection(p_lcb, id, L2CAP_LE_RESULT_NO_PSM);
break;
} else {
if (!p_rcb->api.pL2CA_ConnectInd_Cb) {
@@ -789,7 +673,7 @@
p_ccb->peer_conn_cfg.mps < L2CAP_LE_MIN_MPS ||
p_ccb->peer_conn_cfg.mps > L2CAP_LE_MAX_MPS) {
L2CAP_TRACE_ERROR("L2CAP don't like the params");
- con_info.l2cap_result = L2CAP_LE_NO_RESOURCES;
+ con_info.l2cap_result = L2CAP_LE_RESULT_NO_RESOURCES;
l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP_NEG, &con_info);
break;
}
@@ -800,13 +684,13 @@
p_ccb->is_first_seg = true;
p_ccb->peer_cfg.fcr.mode = L2CAP_FCR_LE_COC_MODE;
- if (con_info.l2cap_result == L2CAP_LE_CONN_OK)
+ if (con_info.l2cap_result == L2CAP_LE_RESULT_CONN_OK)
l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP, &con_info);
else
l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP_NEG, &con_info);
} else {
L2CAP_TRACE_DEBUG("I DO NOT remember the connection req");
- con_info.l2cap_result = L2CAP_LE_INVALID_SOURCE_CID;
+ con_info.l2cap_result = L2CAP_LE_RESULT_INVALID_SOURCE_CID;
l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP_NEG, &con_info);
}
break;
@@ -873,129 +757,20 @@
}
}
-/*******************************************************************************
- *
- * Function l2cble_init_direct_conn
- *
- * Description This function is to initate a direct connection
- *
- * Returns true connection initiated, false otherwise.
- *
- ******************************************************************************/
-bool l2cble_init_direct_conn(tL2C_LCB* p_lcb) {
- tBTM_SEC_DEV_REC* p_dev_rec = btm_find_or_alloc_dev(p_lcb->remote_bd_addr);
- tBTM_BLE_CB* p_cb = &btm_cb.ble_ctr_cb;
- uint16_t scan_int;
- uint16_t scan_win;
- RawAddress peer_addr;
- uint8_t peer_addr_type = BLE_ADDR_PUBLIC;
- uint8_t own_addr_type = BLE_ADDR_PUBLIC;
-
- /* There can be only one BLE connection request outstanding at a time */
- if (p_dev_rec == NULL) {
- L2CAP_TRACE_WARNING("unknown device, can not initate connection");
- return (false);
- }
-
- scan_int = (p_cb->scan_int == BTM_BLE_SCAN_PARAM_UNDEF)
- ? BTM_BLE_SCAN_FAST_INT
- : p_cb->scan_int;
- scan_win = (p_cb->scan_win == BTM_BLE_SCAN_PARAM_UNDEF)
- ? BTM_BLE_SCAN_FAST_WIN
- : p_cb->scan_win;
-
- peer_addr_type = p_lcb->ble_addr_type;
- peer_addr = p_lcb->remote_bd_addr;
-
-#if (BLE_PRIVACY_SPT == TRUE)
- own_addr_type =
- btm_cb.ble_ctr_cb.privacy_mode ? BLE_ADDR_RANDOM : BLE_ADDR_PUBLIC;
- if (p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) {
- if (btm_cb.ble_ctr_cb.privacy_mode >= BTM_PRIVACY_1_2)
- own_addr_type |= BLE_ADDR_TYPE_ID_BIT;
-
- btm_ble_enable_resolving_list(BTM_BLE_RL_INIT);
- btm_random_pseudo_to_identity_addr(&peer_addr, &peer_addr_type);
- } else {
- btm_ble_disable_resolving_list(BTM_BLE_RL_INIT, true);
-
- // If we have a current RPA, use that instead.
- if (!p_dev_rec->ble.cur_rand_addr.IsEmpty()) {
- peer_addr = p_dev_rec->ble.cur_rand_addr;
- }
- }
-#endif
-
- if (!btm_ble_topology_check(BTM_BLE_STATE_INIT)) {
- l2cu_release_lcb(p_lcb);
- L2CAP_TRACE_ERROR("initate direct connection fail, topology limitation");
- return false;
- }
-
- btm_send_hci_create_connection(
- scan_int, /* uint16_t scan_int */
- scan_win, /* uint16_t scan_win */
- false, /* uint8_t white_list */
- peer_addr_type, /* uint8_t addr_type_peer */
- peer_addr, /* BD_ADDR bda_peer */
- own_addr_type, /* uint8_t addr_type_own */
- (uint16_t)(
- (p_dev_rec->conn_params.min_conn_int != BTM_BLE_CONN_PARAM_UNDEF)
- ? p_dev_rec->conn_params.min_conn_int
- : BTM_BLE_CONN_INT_MIN_DEF), /* uint16_t conn_int_min */
- (uint16_t)(
- (p_dev_rec->conn_params.max_conn_int != BTM_BLE_CONN_PARAM_UNDEF)
- ? p_dev_rec->conn_params.max_conn_int
- : BTM_BLE_CONN_INT_MAX_DEF), /* uint16_t conn_int_max */
- (uint16_t)(
- (p_dev_rec->conn_params.slave_latency != BTM_BLE_CONN_PARAM_UNDEF)
- ? p_dev_rec->conn_params.slave_latency
- : BTM_BLE_CONN_SLAVE_LATENCY_DEF), /* uint16_t conn_latency */
- (uint16_t)(
- (p_dev_rec->conn_params.supervision_tout != BTM_BLE_CONN_PARAM_UNDEF)
- ? p_dev_rec->conn_params.supervision_tout
- : BTM_BLE_CONN_TIMEOUT_DEF), /* conn_timeout */
- 0, /* uint16_t min_len */
- 0, /* uint16_t max_len */
- p_lcb->initiating_phys);
+/** This function is to initate a direct connection. Returns true if connection
+ * initiated, false otherwise. */
+bool l2cble_create_conn(tL2C_LCB* p_lcb) {
+ bool ret = connection_manager::direct_connect_add(CONN_MGR_ID_L2CAP,
+ p_lcb->remote_bd_addr);
+ if (!ret) return ret;
p_lcb->link_state = LST_CONNECTING;
- l2cb.is_ble_connecting = true;
- l2cb.ble_connecting_bda = p_lcb->remote_bd_addr;
+
+ // TODO: we should not need this timer at all, the connection failure should
+ // be reported from lower layer
alarm_set_on_mloop(p_lcb->l2c_lcb_timer, L2CAP_BLE_LINK_CONNECT_TIMEOUT_MS,
l2c_lcb_timer_timeout, p_lcb);
- btm_ble_set_conn_st(BLE_DIR_CONN);
-
- return (true);
-}
-
-/*******************************************************************************
- *
- * Function l2cble_create_conn
- *
- * Description This function initiates an acl connection via HCI
- *
- * Returns true if successful, false if connection not started.
- *
- ******************************************************************************/
-bool l2cble_create_conn(tL2C_LCB* p_lcb) {
- tBTM_BLE_CONN_ST conn_st = btm_ble_get_conn_st();
- bool rt = false;
-
- /* There can be only one BLE connection request outstanding at a time */
- if (conn_st == BLE_CONN_IDLE) {
- rt = l2cble_init_direct_conn(p_lcb);
- } else {
- L2CAP_TRACE_WARNING(
- "L2CAP - LE - cannot start new connection at conn st: %d", conn_st);
-
- btm_ble_enqueue_direct_conn_req(p_lcb);
-
- if (conn_st == BLE_BG_CONN) btm_ble_suspend_bg_conn();
-
- rt = true;
- }
- return rt;
+ return true;
}
/*******************************************************************************
@@ -1439,20 +1214,20 @@
* Description This function is called by LE COC link to meet the
* security requirement for the link
*
- * Returns true - security procedures are started
- * false - failure
+ * Returns Returns - L2CAP LE Connection Response Result Code.
*
******************************************************************************/
-bool l2ble_sec_access_req(const RawAddress& bd_addr, uint16_t psm,
- bool is_originator, tL2CAP_SEC_CBACK* p_callback,
- void* p_ref_data) {
+tL2CAP_LE_RESULT_CODE l2ble_sec_access_req(const RawAddress& bd_addr,
+ uint16_t psm, bool is_originator,
+ tL2CAP_SEC_CBACK* p_callback,
+ void* p_ref_data) {
L2CAP_TRACE_DEBUG("%s", __func__);
- bool status;
+ tL2CAP_LE_RESULT_CODE result;
tL2C_LCB* p_lcb = NULL;
if (!p_callback) {
L2CAP_TRACE_ERROR("%s No callback function", __func__);
- return false;
+ return L2CAP_LE_RESULT_NO_RESOURCES;
}
p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_LE);
@@ -1460,14 +1235,14 @@
if (!p_lcb) {
L2CAP_TRACE_ERROR("%s Security check for unknown device", __func__);
p_callback(bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_UNKNOWN_ADDR);
- return false;
+ return L2CAP_LE_RESULT_NO_RESOURCES;
}
tL2CAP_SEC_DATA* p_buf =
(tL2CAP_SEC_DATA*)osi_malloc((uint16_t)sizeof(tL2CAP_SEC_DATA));
if (!p_buf) {
p_callback(bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_NO_RESOURCES);
- return false;
+ return L2CAP_LE_RESULT_NO_RESOURCES;
}
p_buf->psm = psm;
@@ -1475,10 +1250,10 @@
p_buf->p_callback = p_callback;
p_buf->p_ref_data = p_ref_data;
fixed_queue_enqueue(p_lcb->le_sec_pending_q, p_buf);
- status = btm_ble_start_sec_check(bd_addr, psm, is_originator,
+ result = btm_ble_start_sec_check(bd_addr, psm, is_originator,
&l2cble_sec_comp, p_ref_data);
- return status;
+ return result;
}
/* This function is called to adjust the connection intervals based on various
diff --git a/stack/l2cap/l2c_csm.cc b/stack/l2cap/l2c_csm.cc
index bb89eac..06ef7e8 100644
--- a/stack/l2cap/l2c_csm.cc
+++ b/stack/l2cap/l2c_csm.cc
@@ -30,6 +30,7 @@
#include "bt_target.h"
#include "btm_int.h"
#include "btu.h"
+#include "common/time_util.h"
#include "hcidefs.h"
#include "hcimsgs.h"
#include "l2c_int.h"
@@ -238,8 +239,19 @@
if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE) {
p_ccb->chnl_state = CST_TERM_W4_SEC_COMP;
- l2ble_sec_access_req(p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
- false, &l2c_link_sec_comp2, p_ccb);
+ tL2CAP_LE_RESULT_CODE result = l2ble_sec_access_req(
+ p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm, false,
+ &l2c_link_sec_comp2, p_ccb);
+
+ switch (result) {
+ case L2CAP_LE_RESULT_INSUFFICIENT_AUTHENTICATION:
+ case L2CAP_LE_RESULT_INSUFFICIENT_ENCRYP_KEY_SIZE:
+ case L2CAP_LE_RESULT_INSUFFICIENT_ENCRYP:
+ l2cu_reject_ble_connection(p_ccb->p_lcb, p_ccb->remote_id, result);
+ l2cu_release_ccb(p_ccb);
+ break;
+ // TODO: Handle the other return codes
+ }
} else {
/* Cancel sniff mode if needed */
{
@@ -442,8 +454,9 @@
l2c_ccb_timer_timeout, p_ccb);
} else {
if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
- l2cu_reject_ble_connection(p_ccb->p_lcb, p_ccb->remote_id,
- L2CAP_LE_INSUFFICIENT_AUTHENTICATION);
+ l2cu_reject_ble_connection(
+ p_ccb->p_lcb, p_ccb->remote_id,
+ L2CAP_LE_RESULT_INSUFFICIENT_AUTHENTICATION);
else
l2cu_send_peer_connect_rsp(p_ccb, L2CAP_CONN_SECURITY_BLOCK, 0);
l2cu_release_ccb(p_ccb);
@@ -804,7 +817,8 @@
}
#if (L2CAP_ERTM_STATS == TRUE)
- p_ccb->fcrb.connect_tick_count = time_get_os_boottime_ms();
+ p_ccb->fcrb.connect_tick_count =
+ bluetooth::common::time_get_os_boottime_ms();
#endif
/* See if we can forward anything on the hold queue */
if (!fixed_queue_is_empty(p_ccb->xmit_hold_q)) {
@@ -892,7 +906,8 @@
if (p_ccb->fcrb.wait_ack) l2c_fcr_start_timer(p_ccb);
#if (L2CAP_ERTM_STATS == TRUE)
- p_ccb->fcrb.connect_tick_count = time_get_os_boottime_ms();
+ p_ccb->fcrb.connect_tick_count =
+ bluetooth::common::time_get_os_boottime_ms();
#endif
/* See if we can forward anything on the hold queue */
diff --git a/stack/l2cap/l2c_fcr.cc b/stack/l2cap/l2c_fcr.cc
index 88503fb..857a0bf 100644
--- a/stack/l2cap/l2c_fcr.cc
+++ b/stack/l2cap/l2c_fcr.cc
@@ -34,6 +34,7 @@
#include "btm_api.h"
#include "btm_int.h"
#include "btu.h"
+#include "common/time_util.h"
#include "hcimsgs.h"
#include "l2c_api.h"
#include "l2c_int.h"
@@ -231,7 +232,8 @@
#if (L2CAP_ERTM_STATS == TRUE)
if ((p_ccb->local_cid >= L2CAP_BASE_APPL_CID) &&
(p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)) {
- uint32_t dur = time_get_os_boottime_ms() - p_ccb->fcrb.connect_tick_count;
+ uint64_t dur = bluetooth::common::time_get_os_boottime_ms() -
+ p_ccb->fcrb.connect_tick_count;
size_t p_str_size = 120;
char* p_str = (char*)osi_malloc(p_str_size);
uint16_t i;
@@ -1804,7 +1806,9 @@
* to include extra 4 octets at the end.
*/
p = ((uint8_t*)(p_wack + 1)) + p_wack->offset + p_wack->len;
- UINT32_TO_STREAM(p, time_get_os_boottime_ms());
+ // Have to cast to uint32_t which wraps in 49.7 days
+ UINT32_TO_STREAM(p, static_cast<uint32_t>(
+ bluetooth::common::time_get_os_boottime_ms()));
#endif
/* We will not save the FCS in case we reconfigure and change options */
if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS) p_wack->len -= L2CAP_FCS_LEN;
@@ -2395,7 +2399,9 @@
}
STREAM_TO_UINT32(timestamp, p);
- delay = time_get_os_boottime_ms() - timestamp;
+ delay = static_cast<uint32_t>(
+ bluetooth::common::time_get_os_boottime_ms()) -
+ timestamp;
p_ccb->fcrb.ack_delay_avg[index] += delay;
if (delay > p_ccb->fcrb.ack_delay_max[index])
@@ -2416,7 +2422,7 @@
p_ccb->fcrb.ack_delay_avg[index] /= L2CAP_ERTM_STATS_AVG_NUM_SAMPLES;
/* calculate throughput */
- timestamp = time_get_os_boottime_ms();
+ timestamp = bluetooth::common::time_get_os_boottime_ms();
if (timestamp - p_ccb->fcrb.throughput_start > 0)
p_ccb->fcrb.throughput[index] /=
(timestamp - p_ccb->fcrb.throughput_start);
diff --git a/stack/l2cap/l2c_int.h b/stack/l2cap/l2c_int.h
index 421e34d..0b71a19 100644
--- a/stack/l2cap/l2c_int.h
+++ b/stack/l2cap/l2c_int.h
@@ -28,6 +28,7 @@
#include "bt_common.h"
#include "btm_api.h"
+#include "btm_ble_api.h"
#include "l2c_api.h"
#include "l2cdefs.h"
#include "osi/include/alarm.h"
@@ -53,6 +54,8 @@
static_assert(L2CAP_LE_CREDIT_THRESHOLD < L2CAP_LE_CREDIT_DEFAULT,
"Threshold must be smaller then default credits");
+#define L2CAP_NO_IDLE_TIMEOUT 0xFFFF
+
/*
* Timeout values (in milliseconds).
*/
@@ -209,7 +212,7 @@
alarm_t* mon_retrans_timer; /* Timer Monitor or Retransmission */
#if (L2CAP_ERTM_STATS == TRUE)
- uint32_t connect_tick_count; /* Time channel was established */
+ uint64_t connect_tick_count; /* Time channel was established */
uint32_t ertm_pkt_counts[2]; /* Packets sent and received */
uint32_t ertm_byte_counts[2]; /* Bytes sent and received */
uint32_t s_frames_sent[4]; /* S-frames sent (RR, REJ, RNR, SREJ) */
@@ -503,8 +506,6 @@
#endif
uint16_t num_ble_links_active; /* Number of LE links active */
- bool is_ble_connecting;
- RawAddress ble_connecting_bda;
uint16_t controller_le_xmit_window; /* Total ACL window for all links */
tL2C_BLE_FIXED_CHNLS_MASK l2c_ble_fixed_chnls_mask; // LE fixed channels mask
uint16_t num_lm_ble_bufs; /* # of ACL buffers on controller */
@@ -688,9 +689,9 @@
extern tL2C_LCB* l2cu_find_lcb_by_state(tL2C_LINK_STATE state);
extern bool l2cu_lcb_disconnecting(void);
-extern bool l2cu_create_conn(tL2C_LCB* p_lcb, tBT_TRANSPORT transport);
-extern bool l2cu_create_conn(tL2C_LCB* p_lcb, tBT_TRANSPORT transport,
- uint8_t initiating_phys);
+extern bool l2cu_create_conn_br_edr(tL2C_LCB* p_lcb);
+extern bool l2cu_create_conn_le(tL2C_LCB* p_lcb);
+extern bool l2cu_create_conn_le(tL2C_LCB* p_lcb, uint8_t initiating_phys);
extern bool l2cu_create_conn_after_switch(tL2C_LCB* p_lcb);
extern BT_HDR* l2cu_get_next_buffer_to_send(tL2C_LCB* p_lcb,
tL2C_TX_COMPLETE_CB_INFO* p_cbi);
@@ -788,7 +789,6 @@
const RawAddress& bda, tBLE_ADDR_TYPE type,
uint16_t conn_interval, uint16_t conn_latency,
uint16_t conn_timeout);
-extern bool l2cble_init_direct_conn(tL2C_LCB* p_lcb);
extern void l2cble_notify_le_connection(const RawAddress& bda);
extern void l2c_ble_link_adjust_allocation(void);
extern void l2cble_process_conn_update_evt(uint16_t handle, uint8_t status,
@@ -800,10 +800,11 @@
extern void l2cble_send_peer_disc_req(tL2C_CCB* p_ccb);
extern void l2cble_send_flow_control_credit(tL2C_CCB* p_ccb,
uint16_t credit_value);
-extern bool l2ble_sec_access_req(const RawAddress& bd_addr, uint16_t psm,
- bool is_originator,
- tL2CAP_SEC_CBACK* p_callback,
- void* p_ref_data);
+extern tL2CAP_LE_RESULT_CODE l2ble_sec_access_req(const RawAddress& bd_addr,
+ uint16_t psm,
+ bool is_originator,
+ tL2CAP_SEC_CBACK* p_callback,
+ void* p_ref_data);
#if (BLE_LLT_INCLUDED == TRUE)
extern void l2cble_process_rc_param_request_evt(uint16_t handle,
diff --git a/stack/l2cap/l2c_link.cc b/stack/l2cap/l2c_link.cc
index db7e613..8e04c6e 100644
--- a/stack/l2cap/l2c_link.cc
+++ b/stack/l2cap/l2c_link.cc
@@ -159,10 +159,15 @@
/* See if we have a link control block for the remote device */
p_lcb = l2cu_find_lcb_by_bd_addr(ci.bd_addr, BT_TRANSPORT_BR_EDR);
- /* If we don't have one, this is an error */
- if (!p_lcb) {
- L2CAP_TRACE_WARNING("L2CAP got conn_comp for unknown BD_ADDR");
- return (false);
+ /* If we don't have one, allocate one */
+ if (p_lcb == nullptr) {
+ L2CAP_TRACE_WARNING("No available link control block, try allocate one");
+ p_lcb = l2cu_allocate_lcb(ci.bd_addr, false, BT_TRANSPORT_BR_EDR);
+ if (p_lcb == nullptr) {
+ L2CAP_TRACE_WARNING("%s: Failed to allocate an LCB", __func__);
+ return (false);
+ }
+ p_lcb->link_state = LST_CONNECTING;
}
if (p_lcb->link_state != LST_CONNECTING) {
@@ -217,7 +222,7 @@
alarm_set_on_mloop(p_lcb->l2c_lcb_timer, L2CAP_ECHO_RSP_TIMEOUT_MS,
l2c_lcb_timer_timeout, p_lcb);
} else if (!p_lcb->ccb_queue.p_first_ccb) {
- period_ms_t timeout_ms = L2CAP_LINK_STARTUP_TOUT * 1000;
+ uint64_t timeout_ms = L2CAP_LINK_STARTUP_TOUT * 1000;
alarm_set_on_mloop(p_lcb->l2c_lcb_timer, timeout_ms,
l2c_lcb_timer_timeout, p_lcb);
}
@@ -253,7 +258,7 @@
* controller */
p_lcb->link_state = LST_CONNECTING;
} else {
- l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR);
+ l2cu_create_conn_br_edr(p_lcb);
}
}
}
@@ -383,11 +388,9 @@
p_ccb = pn;
}
-#if (BTM_SCO_INCLUDED == TRUE)
if (p_lcb->transport == BT_TRANSPORT_BR_EDR)
/* Tell SCO management to drop any SCOs on this ACL */
btm_sco_acl_removed(&p_lcb->remote_bd_addr);
-#endif
/* If waiting for disconnect and reconnect is pending start the reconnect
now
@@ -408,7 +411,6 @@
/* for LE link, always drop and re-open to ensure to get LE remote feature
*/
if (p_lcb->transport == BT_TRANSPORT_LE) {
- l2cb.is_ble_connecting = false;
btm_acl_removed(p_lcb->remote_bd_addr, p_lcb->transport);
} else {
#if (L2CAP_NUM_FIXED_CHNLS > 0)
@@ -441,8 +443,13 @@
}
#endif
}
- if (l2cu_create_conn(p_lcb, transport))
- lcb_is_free = false; /* still using this lcb */
+ if (p_lcb->transport == BT_TRANSPORT_LE) {
+ if (l2cu_create_conn_le(p_lcb))
+ lcb_is_free = false; /* still using this lcb */
+ } else {
+ if (l2cu_create_conn_br_edr(p_lcb))
+ lcb_is_free = false; /* still using this lcb */
+ }
}
p_lcb->p_pending_ccb = NULL;
@@ -455,7 +462,7 @@
if (lcb_is_free &&
((p_lcb = l2cu_find_lcb_by_state(LST_CONNECT_HOLDING)) != NULL)) {
/* we found one-- create a connection */
- l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR);
+ l2cu_create_conn_br_edr(p_lcb);
}
return status;
@@ -524,9 +531,7 @@
p_ccb = pn;
}
- if (p_lcb->link_state == LST_CONNECTING && l2cb.is_ble_connecting) {
- L2CA_CancelBleConnectReq(l2cb.ble_connecting_bda);
- }
+
/* Release the LCB */
l2cu_release_lcb(p_lcb);
}
@@ -557,7 +562,7 @@
/* If no channels in use, drop the link. */
if (!p_lcb->ccb_queue.p_first_ccb) {
- period_ms_t timeout_ms;
+ uint64_t timeout_ms;
bool start_timeout = true;
rc = btm_sec_disconnect(p_lcb->handle, HCI_ERR_PEER_USER);
diff --git a/stack/l2cap/l2c_utils.cc b/stack/l2cap/l2c_utils.cc
index ced48a2..448acaa 100644
--- a/stack/l2cap/l2c_utils.cc
+++ b/stack/l2cap/l2c_utils.cc
@@ -152,10 +152,8 @@
/* Release any unfinished L2CAP packet on this link */
osi_free_and_reset((void**)&p_lcb->p_hcit_rcv_acl);
-#if (BTM_SCO_INCLUDED == TRUE)
if (p_lcb->transport == BT_TRANSPORT_BR_EDR) /* Release all SCO links */
btm_remove_sco_links(p_lcb->remote_bd_addr);
-#endif
if (p_lcb->sent_not_acked > 0) {
if (p_lcb->transport == BT_TRANSPORT_LE) {
@@ -171,11 +169,6 @@
}
}
- // Reset BLE connecting flag only if the address matches
- if (p_lcb->transport == BT_TRANSPORT_LE &&
- l2cb.ble_connecting_bda == p_lcb->remote_bd_addr)
- l2cb.is_ble_connecting = false;
-
#if (L2CAP_NUM_FIXED_CHNLS > 0)
l2cu_process_fixed_disc_cback(p_lcb);
#endif
@@ -1540,7 +1533,7 @@
if ((p_lcb->link_state == LST_CONNECTED) ||
(p_lcb->link_state == LST_CONNECTING) ||
(p_lcb->link_state == LST_DISCONNECTING)) {
- period_ms_t timeout_ms = L2CAP_BONDING_TIMEOUT * 1000;
+ uint64_t timeout_ms = L2CAP_BONDING_TIMEOUT * 1000;
if (p_lcb->idle_timeout == 0) {
btsnd_hcic_disconnect(p_lcb->handle, HCI_ERR_PEER_USER);
@@ -1622,18 +1615,28 @@
p_ccb->in_use = false;
/* If no channels on the connection, start idle timeout */
- if ((p_lcb) && p_lcb->in_use && (p_lcb->link_state == LST_CONNECTED)) {
- if (!p_lcb->ccb_queue.p_first_ccb) {
- // Closing a security channel on LE device should not start connection
- // timeout
- if (p_lcb->transport == BT_TRANSPORT_LE &&
- p_ccb->local_cid == L2CAP_SMP_CID)
- return;
+ if ((p_lcb) && p_lcb->in_use) {
+ if (p_lcb->link_state == LST_CONNECTED) {
+ if (!p_lcb->ccb_queue.p_first_ccb) {
+ // Closing a security channel on LE device should not start connection
+ // timeout
+ if (p_lcb->transport == BT_TRANSPORT_LE &&
+ p_ccb->local_cid == L2CAP_SMP_CID)
+ return;
- l2cu_no_dynamic_ccbs(p_lcb);
- } else {
- /* Link is still active, adjust channel quotas. */
- l2c_link_adjust_chnl_allocation();
+ l2cu_no_dynamic_ccbs(p_lcb);
+ } else {
+ /* Link is still active, adjust channel quotas. */
+ l2c_link_adjust_chnl_allocation();
+ }
+ } else if (p_lcb->link_state == LST_CONNECTING) {
+ if (!p_lcb->ccb_queue.p_first_ccb) {
+ if (p_lcb->transport == BT_TRANSPORT_LE &&
+ p_ccb->local_cid == L2CAP_ATT_CID) {
+ L2CAP_TRACE_WARNING("%s - disconnecting the LE link", __func__);
+ l2cu_no_dynamic_ccbs(p_lcb);
+ }
+ }
}
}
}
@@ -2100,45 +2103,36 @@
l2c_link_hci_disc_comp(p_lcb->handle, (uint8_t)-1);
}
}
- l2cb.is_ble_connecting = false;
}
-/*******************************************************************************
- *
- * Function l2cu_create_conn
- *
- * Description This function initiates an acl connection via HCI
- *
- * Returns true if successful, false if get buffer fails.
- *
- ******************************************************************************/
-bool l2cu_create_conn(tL2C_LCB* p_lcb, tBT_TRANSPORT transport) {
+bool l2cu_create_conn_le(tL2C_LCB* p_lcb) {
uint8_t phy = controller_get_interface()->get_le_all_initiating_phys();
- return l2cu_create_conn(p_lcb, transport, phy);
+ return l2cu_create_conn_le(p_lcb, phy);
}
-bool l2cu_create_conn(tL2C_LCB* p_lcb, tBT_TRANSPORT transport,
- uint8_t initiating_phys) {
- int xx;
- tL2C_LCB* p_lcb_cur = &l2cb.lcb_pool[0];
-#if (BTM_SCO_INCLUDED == TRUE)
- bool is_sco_active;
-#endif
-
+/* This function initiates an acl connection to a LE device.
+ * Returns true if request started successfully, false otherwise. */
+bool l2cu_create_conn_le(tL2C_LCB* p_lcb, uint8_t initiating_phys) {
tBT_DEVICE_TYPE dev_type;
tBLE_ADDR_TYPE addr_type;
BTM_ReadDevInfo(p_lcb->remote_bd_addr, &dev_type, &addr_type);
- if (transport == BT_TRANSPORT_LE) {
- if (!controller_get_interface()->supports_ble()) return false;
+ if (!controller_get_interface()->supports_ble()) return false;
- p_lcb->ble_addr_type = addr_type;
- p_lcb->transport = BT_TRANSPORT_LE;
- p_lcb->initiating_phys = initiating_phys;
+ p_lcb->ble_addr_type = addr_type;
+ p_lcb->transport = BT_TRANSPORT_LE;
+ p_lcb->initiating_phys = initiating_phys;
- return (l2cble_create_conn(p_lcb));
- }
+ return (l2cble_create_conn(p_lcb));
+}
+
+/* This function initiates an acl connection to a Classic device via HCI.
+ * Returns true on success, false otherwise. */
+bool l2cu_create_conn_br_edr(tL2C_LCB* p_lcb) {
+ int xx;
+ tL2C_LCB* p_lcb_cur = &l2cb.lcb_pool[0];
+ bool is_sco_active;
/* If there is a connection where we perform as a slave, try to switch roles
for this connection */
@@ -2147,7 +2141,6 @@
if (p_lcb_cur == p_lcb) continue;
if ((p_lcb_cur->in_use) && (p_lcb_cur->link_role == HCI_ROLE_SLAVE)) {
-#if (BTM_SCO_INCLUDED == TRUE)
/* The LMP_switch_req shall be sent only if the ACL logical transport
is in active mode, when encryption is disabled, and all synchronous
logical transports on the same physical link are disabled." */
@@ -2161,7 +2154,6 @@
if (is_sco_active)
continue; /* No Master Slave switch not allowed when SCO Active */
-#endif
/*4_1_TODO check if btm_cb.devcb.local_features to be used instead */
if (HCI_SWITCH_SUPPORTED(BTM_ReadLocalFeatures())) {
/* mark this lcb waiting for switch to be completed and
@@ -2601,7 +2593,7 @@
******************************************************************************/
void l2cu_no_dynamic_ccbs(tL2C_LCB* p_lcb) {
tBTM_STATUS rc;
- period_ms_t timeout_ms = p_lcb->idle_timeout * 1000;
+ uint64_t timeout_ms = p_lcb->idle_timeout * 1000;
bool start_timeout = true;
#if (L2CAP_NUM_FIXED_CHNLS > 0)
@@ -2610,6 +2602,12 @@
for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++) {
if ((p_lcb->p_fixed_ccbs[xx] != NULL) &&
(p_lcb->p_fixed_ccbs[xx]->fixed_chnl_idle_tout * 1000 > timeout_ms)) {
+
+ if (p_lcb->p_fixed_ccbs[xx]->fixed_chnl_idle_tout == L2CAP_NO_IDLE_TIMEOUT) {
+ L2CAP_TRACE_DEBUG("%s NO IDLE timeout set for fixed cid 0x%04x", __func__,
+ p_lcb->p_fixed_ccbs[xx]->local_cid);
+ start_timeout = false;
+ }
timeout_ms = p_lcb->p_fixed_ccbs[xx]->fixed_chnl_idle_tout * 1000;
}
}
@@ -2674,28 +2672,34 @@
/* Tell all registered fixed channels about the connection */
for (int xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++) {
+ uint16_t channel_id = xx + L2CAP_FIRST_FIXED_CHNL;
+
+ /* See BT Spec Ver 5.0 | Vol 3, Part A 2.1 table 2.1 and 2.2 */
+
/* skip sending LE fix channel callbacks on BR/EDR links */
if (p_lcb->transport == BT_TRANSPORT_BR_EDR &&
- xx + L2CAP_FIRST_FIXED_CHNL >= L2CAP_ATT_CID &&
- xx + L2CAP_FIRST_FIXED_CHNL <= L2CAP_SMP_CID)
+ channel_id >= L2CAP_ATT_CID && channel_id <= L2CAP_SMP_CID)
continue;
- if (l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb != NULL) {
- if (p_lcb->peer_chnl_mask[(xx + L2CAP_FIRST_FIXED_CHNL) / 8] &
- (1 << ((xx + L2CAP_FIRST_FIXED_CHNL) % 8))) {
- if (p_lcb->p_fixed_ccbs[xx])
- p_lcb->p_fixed_ccbs[xx]->chnl_state = CST_OPEN;
- (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL,
- p_lcb->remote_bd_addr, true, 0,
- p_lcb->transport);
- } else {
- (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(
- xx + L2CAP_FIRST_FIXED_CHNL, p_lcb->remote_bd_addr, false,
- p_lcb->disc_reason, p_lcb->transport);
- if (p_lcb->p_fixed_ccbs[xx]) {
- l2cu_release_ccb(p_lcb->p_fixed_ccbs[xx]);
- p_lcb->p_fixed_ccbs[xx] = NULL;
- }
+ /* skip sending BR fix channel callbacks on LE links */
+ if (p_lcb->transport == BT_TRANSPORT_LE && channel_id == L2CAP_SMP_BR_CID)
+ continue;
+
+ if (!l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb) continue;
+
+ if (p_lcb->peer_chnl_mask[(channel_id) / 8] & (1 << ((channel_id) % 8))) {
+ if (p_lcb->p_fixed_ccbs[xx])
+ p_lcb->p_fixed_ccbs[xx]->chnl_state = CST_OPEN;
+ (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(
+ channel_id, p_lcb->remote_bd_addr, true, 0, p_lcb->transport);
+ } else {
+ (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(
+ channel_id, p_lcb->remote_bd_addr, false, p_lcb->disc_reason,
+ p_lcb->transport);
+
+ if (p_lcb->p_fixed_ccbs[xx]) {
+ l2cu_release_ccb(p_lcb->p_fixed_ccbs[xx]);
+ p_lcb->p_fixed_ccbs[xx] = NULL;
}
}
}
diff --git a/stack/mcap/mca_api.cc b/stack/mcap/mca_api.cc
deleted file mode 100644
index 578d53e..0000000
--- a/stack/mcap/mca_api.cc
+++ /dev/null
@@ -1,860 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2009-2012 Broadcom 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.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- * This is the API implementation file for the Multi-Channel Adaptation
- * Protocol (MCAP).
- *
- ******************************************************************************/
-#include <base/logging.h>
-#include <string.h>
-
-#include "bt_target.h"
-#include "btm_api.h"
-#include "btm_int.h"
-#include "mca_api.h"
-#include "mca_defs.h"
-#include "mca_int.h"
-
-#include "btu.h"
-
-/*******************************************************************************
- *
- * Function mca_process_timeout
- *
- * Description This function is called by BTU when an MCA timer
- * expires.
- *
- * This function is for use internal to the stack only.
- *
- * Returns void
- *
- ******************************************************************************/
-void mca_ccb_timer_timeout(void* data) {
- tMCA_CCB* p_ccb = (tMCA_CCB*)data;
-
- mca_ccb_event(p_ccb, MCA_CCB_RSP_TOUT_EVT, NULL);
-}
-
-/*******************************************************************************
- *
- * Function MCA_Init
- *
- * Description Initialize MCAP main control block.
- * This function is called at stack start up.
- *
- * Returns void
- *
- ******************************************************************************/
-void MCA_Init(void) {
- memset(&mca_cb, 0, sizeof(tMCA_CB));
-
-#if defined(MCA_INITIAL_TRACE_LEVEL)
- mca_cb.trace_level = MCA_INITIAL_TRACE_LEVEL;
-#else
- mca_cb.trace_level = BT_TRACE_LEVEL_NONE;
-#endif
-}
-
-/*******************************************************************************
- *
- * Function MCA_SetTraceLevel
- *
- * Description This function sets the debug trace level for MCA.
- * If 0xff is passed, the current trace level is returned.
- *
- * Input Parameters:
- * level: The level to set the MCA tracing to:
- * 0xff-returns the current setting.
- * 0-turns off tracing.
- * >= 1-Errors.
- * >= 2-Warnings.
- * >= 3-APIs.
- * >= 4-Events.
- * >= 5-Debug.
- *
- * Returns The new trace level or current trace level if
- * the input parameter is 0xff.
- *
- ******************************************************************************/
-uint8_t MCA_SetTraceLevel(uint8_t level) {
- if (level != 0xFF) mca_cb.trace_level = level;
-
- return (mca_cb.trace_level);
-}
-
-/*******************************************************************************
- *
- * Function MCA_Register
- *
- * Description This function registers an MCAP implementation.
- * It is assumed that the control channel PSM and data channel
- * PSM are not used by any other instances of the stack.
- * If the given p_reg->ctrl_psm is 0, this handle is INT only.
- *
- * Returns 0, if failed. Otherwise, the MCA handle.
- *
- ******************************************************************************/
-tMCA_HANDLE MCA_Register(tMCA_REG* p_reg, tMCA_CTRL_CBACK* p_cback) {
- tMCA_RCB* p_rcb;
- tMCA_HANDLE handle = 0;
- tL2CAP_APPL_INFO l2c_cacp_appl;
- tL2CAP_APPL_INFO l2c_dacp_appl;
-
- CHECK(p_reg != NULL);
- CHECK(p_cback != NULL);
-
- MCA_TRACE_API("MCA_Register: ctrl_psm:0x%x, data_psm:0x%x", p_reg->ctrl_psm,
- p_reg->data_psm);
-
- p_rcb = mca_rcb_alloc(p_reg);
- if (p_rcb != NULL) {
- if (p_reg->ctrl_psm) {
- if (L2C_INVALID_PSM(p_reg->ctrl_psm) ||
- L2C_INVALID_PSM(p_reg->data_psm)) {
- MCA_TRACE_ERROR("INVALID_PSM");
- return 0;
- }
-
- l2c_cacp_appl = *(tL2CAP_APPL_INFO*)&mca_l2c_int_appl;
- l2c_cacp_appl.pL2CA_ConnectCfm_Cb = NULL;
- l2c_dacp_appl = *(tL2CAP_APPL_INFO*)&l2c_cacp_appl;
- l2c_cacp_appl.pL2CA_ConnectInd_Cb = mca_l2c_cconn_ind_cback;
- l2c_dacp_appl.pL2CA_ConnectInd_Cb = mca_l2c_dconn_ind_cback;
- if (L2CA_Register(p_reg->ctrl_psm, (tL2CAP_APPL_INFO*)&l2c_cacp_appl) &&
- L2CA_Register(p_reg->data_psm, (tL2CAP_APPL_INFO*)&l2c_dacp_appl)) {
- /* set security level */
- BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_MCAP_CTRL,
- p_reg->sec_mask, p_reg->ctrl_psm,
- BTM_SEC_PROTO_MCA, MCA_CTRL_TCID);
-
- /* in theory, we do not need this one for data_psm
- * If we don't, L2CAP rejects with security block (3),
- * which is different reject code from what MCAP spec suggests.
- * we set this one, so mca_l2c_dconn_ind_cback can reject /w no
- * resources (4) */
- BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_MCAP_DATA,
- p_reg->sec_mask, p_reg->data_psm,
- BTM_SEC_PROTO_MCA, MCA_CTRL_TCID);
- } else {
- MCA_TRACE_ERROR("Failed to register to L2CAP");
- return 0;
- }
- } else
- p_rcb->reg.data_psm = 0;
- handle = mca_rcb_to_handle(p_rcb);
- p_rcb->p_cback = p_cback;
- p_rcb->reg.rsp_tout = p_reg->rsp_tout;
- }
- return handle;
-}
-
-/*******************************************************************************
- *
- * Function MCA_Deregister
- *
- * Description Deregister an MCAP implementation. Before this function can
- * be called, all control and data channels must be removed
- * with MCA_DisconnectReq and MCA_CloseReq.
- *
- * Returns void
- *
- ******************************************************************************/
-void MCA_Deregister(tMCA_HANDLE handle) {
- tMCA_RCB* p_rcb = mca_rcb_by_handle(handle);
-
- MCA_TRACE_API("MCA_Deregister: %d", handle);
- if (p_rcb && p_rcb->reg.ctrl_psm) {
- L2CA_Deregister(p_rcb->reg.ctrl_psm);
- L2CA_Deregister(p_rcb->reg.data_psm);
- btm_sec_clr_service_by_psm(p_rcb->reg.ctrl_psm);
- btm_sec_clr_service_by_psm(p_rcb->reg.data_psm);
- }
- mca_rcb_dealloc(handle);
-}
-
-/*******************************************************************************
- *
- * Function MCA_CreateDep
- *
- * Description Create a data endpoint. If the MDEP is created successfully,
- * the MDEP ID is returned in *p_dep. After a data endpoint is
- * created, an application can initiate a connection between
- * this endpoint and an endpoint on a peer device.
- *
- * Returns MCA_SUCCESS if successful, otherwise error.
- *
- ******************************************************************************/
-tMCA_RESULT MCA_CreateDep(tMCA_HANDLE handle, tMCA_DEP* p_dep, tMCA_CS* p_cs) {
- tMCA_RESULT result = MCA_BAD_HANDLE;
- int i;
- tMCA_RCB* p_rcb = mca_rcb_by_handle(handle);
- tMCA_CS* p_depcs;
-
- CHECK(p_dep != NULL);
- CHECK(p_cs != NULL);
- CHECK(p_cs->p_data_cback != NULL);
-
- MCA_TRACE_API("MCA_CreateDep: %d", handle);
- if (p_rcb) {
- if (p_cs->max_mdl > MCA_NUM_MDLS) {
- MCA_TRACE_ERROR("max_mdl: %d is too big", p_cs->max_mdl);
- result = MCA_BAD_PARAMS;
- } else {
- p_depcs = p_rcb->dep;
- if (p_cs->type == MCA_TDEP_ECHO) {
- if (p_depcs->p_data_cback) {
- MCA_TRACE_ERROR("Already has ECHO MDEP");
- return MCA_NO_RESOURCES;
- }
- memcpy(p_depcs, p_cs, sizeof(tMCA_CS));
- *p_dep = 0;
- result = MCA_SUCCESS;
- } else {
- result = MCA_NO_RESOURCES;
- /* non-echo MDEP starts from 1 */
- p_depcs++;
- for (i = 1; i < MCA_NUM_DEPS; i++, p_depcs++) {
- if (p_depcs->p_data_cback == NULL) {
- memcpy(p_depcs, p_cs, sizeof(tMCA_CS));
- /* internally use type as the mdep id */
- p_depcs->type = i;
- *p_dep = i;
- result = MCA_SUCCESS;
- break;
- }
- }
- }
- }
- }
- return result;
-}
-
-/*******************************************************************************
- *
- * Function MCA_DeleteDep
- *
- * Description Delete a data endpoint. This function is called when
- * the implementation is no longer using a data endpoint.
- * If this function is called when the endpoint is connected
- * the connection is closed and the data endpoint
- * is removed.
- *
- * Returns MCA_SUCCESS if successful, otherwise error.
- *
- ******************************************************************************/
-tMCA_RESULT MCA_DeleteDep(tMCA_HANDLE handle, tMCA_DEP dep) {
- tMCA_RESULT result = MCA_BAD_HANDLE;
- tMCA_RCB* p_rcb = mca_rcb_by_handle(handle);
- tMCA_DCB* p_dcb;
- int i, max;
- tMCA_CS* p_depcs;
-
- MCA_TRACE_API("MCA_DeleteDep: %d dep:%d", handle, dep);
- if (p_rcb) {
- if (dep < MCA_NUM_DEPS && p_rcb->dep[dep].p_data_cback) {
- result = MCA_SUCCESS;
- p_rcb->dep[dep].p_data_cback = NULL;
- p_depcs = &(p_rcb->dep[dep]);
- i = handle - 1;
- max = MCA_NUM_MDLS * MCA_NUM_LINKS;
- p_dcb = &mca_cb.dcb[i * max];
- /* make sure no MDL exists for this MDEP */
- for (i = 0; i < max; i++, p_dcb++) {
- if (p_dcb->state && p_dcb->p_cs == p_depcs) {
- mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
- }
- }
- }
- }
- return result;
-}
-
-/*******************************************************************************
- *
- * Function MCA_ConnectReq
- *
- * Description This function initiates an MCAP control channel connection
- * to the peer device. When the connection is completed, an
- * MCA_CONNECT_IND_EVT is reported to the application via its
- * control callback function.
- * This control channel is identified by the tMCA_CL.
- * If the connection attempt fails, an MCA_DISCONNECT_IND_EVT
- * is reported. The security mask parameter overrides the
- * outgoing security mask set in MCA_Register().
- *
- * Returns MCA_SUCCESS if successful, otherwise error.
- *
- ******************************************************************************/
-tMCA_RESULT MCA_ConnectReq(tMCA_HANDLE handle, const RawAddress& bd_addr,
- uint16_t ctrl_psm, uint16_t sec_mask) {
- tMCA_RESULT result = MCA_BAD_HANDLE;
- tMCA_CCB* p_ccb;
- tMCA_TC_TBL* p_tbl;
-
- MCA_TRACE_API("MCA_ConnectReq: %d psm:0x%x", handle, ctrl_psm);
- p_ccb = mca_ccb_by_bd(handle, bd_addr);
- if (p_ccb == NULL)
- p_ccb = mca_ccb_alloc(handle, bd_addr);
- else {
- MCA_TRACE_ERROR("control channel already exists");
- return MCA_BUSY;
- }
-
- if (p_ccb) {
- p_ccb->ctrl_vpsm =
- L2CA_Register(ctrl_psm, (tL2CAP_APPL_INFO*)&mca_l2c_int_appl);
- result = MCA_NO_RESOURCES;
- if (p_ccb->ctrl_vpsm) {
- BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_MCAP_CTRL, sec_mask,
- p_ccb->ctrl_vpsm, BTM_SEC_PROTO_MCA, MCA_CTRL_TCID);
- p_ccb->lcid = mca_l2c_open_req(bd_addr, p_ccb->ctrl_vpsm, NULL);
- if (p_ccb->lcid) {
- p_tbl = mca_tc_tbl_calloc(p_ccb);
- if (p_tbl) {
- p_tbl->state = MCA_TC_ST_CONN;
- p_ccb->sec_mask = sec_mask;
- result = MCA_SUCCESS;
- }
- }
- }
- if (result != MCA_SUCCESS) mca_ccb_dealloc(p_ccb, NULL);
- }
- return result;
-}
-
-/*******************************************************************************
- *
- * Function MCA_DisconnectReq
- *
- * Description This function disconnect an MCAP control channel
- * to the peer device.
- * If associated data channel exists, they are disconnected.
- * When the MCL is disconnected an MCA_DISCONNECT_IND_EVT is
- * reported to the application via its control callback
- * function.
- *
- * Returns MCA_SUCCESS if successful, otherwise error.
- *
- ******************************************************************************/
-tMCA_RESULT MCA_DisconnectReq(tMCA_CL mcl) {
- tMCA_RESULT result = MCA_BAD_HANDLE;
- tMCA_CCB* p_ccb = mca_ccb_by_hdl(mcl);
-
- MCA_TRACE_API("MCA_DisconnectReq: %d ", mcl);
- if (p_ccb) {
- result = MCA_SUCCESS;
- mca_ccb_event(p_ccb, MCA_CCB_API_DISCONNECT_EVT, NULL);
- }
- return result;
-}
-
-/*******************************************************************************
- *
- * Function MCA_CreateMdl
- *
- * Description This function sends a CREATE_MDL request to the peer device.
- * When the response is received, a MCA_CREATE_CFM_EVT is
- * reported with the given MDL ID.
- * If the response is successful, a data channel is open
- * with the given p_chnl_cfg
- * If p_chnl_cfg is NULL, the data channel is not initiated
- * until MCA_DataChnlCfg is called to provide the p_chnl_cfg.
- * When the data channel is open successfully, a
- * MCA_OPEN_CFM_EVT is reported. This data channel is
- * identified as tMCA_DL.
- *
- * Returns MCA_SUCCESS if successful, otherwise error.
- *
- ******************************************************************************/
-tMCA_RESULT MCA_CreateMdl(tMCA_CL mcl, tMCA_DEP dep, uint16_t data_psm,
- uint16_t mdl_id, uint8_t peer_dep_id, uint8_t cfg,
- const tMCA_CHNL_CFG* p_chnl_cfg) {
- tMCA_RESULT result = MCA_BAD_HANDLE;
- tMCA_CCB* p_ccb = mca_ccb_by_hdl(mcl);
- tMCA_DCB* p_dcb;
-
- MCA_TRACE_API("MCA_CreateMdl: %d dep=%d mdl_id=%d peer_dep_id=%d", mcl, dep,
- mdl_id, peer_dep_id);
- if (p_ccb) {
- if (p_ccb->p_tx_req || p_ccb->p_rx_msg || p_ccb->cong) {
- MCA_TRACE_ERROR("pending req");
- return MCA_BUSY;
- }
-
- if ((peer_dep_id > MCA_MAX_MDEP_ID) || (!MCA_IS_VALID_MDL_ID(mdl_id))) {
- MCA_TRACE_ERROR("bad peer dep id:%d or bad mdl id: %d ", peer_dep_id,
- mdl_id);
- return MCA_BAD_PARAMS;
- }
-
- if (mca_ccb_uses_mdl_id(p_ccb, mdl_id)) {
- MCA_TRACE_ERROR("mdl id: %d is used in the control link", mdl_id);
- return MCA_BAD_MDL_ID;
- }
-
- p_dcb = mca_dcb_alloc(p_ccb, dep);
- result = MCA_NO_RESOURCES;
- if (p_dcb) {
- /* save the info required by dcb connection */
- p_dcb->p_chnl_cfg = p_chnl_cfg;
- p_dcb->mdl_id = mdl_id;
- if (!p_ccb->data_vpsm)
- p_ccb->data_vpsm =
- L2CA_Register(data_psm, (tL2CAP_APPL_INFO*)&mca_l2c_int_appl);
- if (p_ccb->data_vpsm) {
- tMCA_CCB_EVT* mca_ccb_evt =
- (tMCA_CCB_EVT*)osi_malloc(sizeof(tMCA_CCB_EVT));
- tMCA_CCB_MSG* p_evt_data = &mca_ccb_evt->api;
- p_evt_data->dcb_idx = mca_dcb_to_hdl(p_dcb);
- p_evt_data->mdep_id = peer_dep_id;
- p_evt_data->mdl_id = mdl_id;
- p_evt_data->param = cfg;
- p_evt_data->op_code = MCA_OP_MDL_CREATE_REQ;
- p_evt_data->hdr.event = MCA_CCB_API_REQ_EVT;
- p_evt_data->hdr.layer_specific = false;
- mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, mca_ccb_evt);
- return MCA_SUCCESS;
- }
-
- mca_dcb_dealloc(p_dcb, NULL);
- }
- }
- return result;
-}
-
-/*******************************************************************************
- *
- * Function MCA_CreateMdlRsp
- *
- * Description This function sends a CREATE_MDL response to the peer device
- * in response to a received MCA_CREATE_IND_EVT.
- * If the rsp_code is successful, a data channel is open
- * with the given p_chnl_cfg
- * When the data channel is open successfully, a
- * MCA_OPEN_IND_EVT
- * is reported. This data channel is identified as tMCA_DL.
- *
- * Returns MCA_SUCCESS if successful, otherwise error.
- *
- ******************************************************************************/
-tMCA_RESULT MCA_CreateMdlRsp(tMCA_CL mcl, tMCA_DEP dep, uint16_t mdl_id,
- uint8_t cfg, uint8_t rsp_code,
- const tMCA_CHNL_CFG* p_chnl_cfg) {
- tMCA_RESULT result = MCA_BAD_HANDLE;
- tMCA_CCB* p_ccb = mca_ccb_by_hdl(mcl);
-
- MCA_TRACE_API("MCA_CreateMdlRsp: %d dep=%d mdl_id=%d cfg=%d rsp_code=%d", mcl,
- dep, mdl_id, cfg, rsp_code);
- CHECK(p_chnl_cfg != NULL);
- if (p_ccb) {
- if (p_ccb->cong) {
- MCA_TRACE_ERROR("congested");
- return MCA_BUSY;
- }
- if (p_ccb->p_rx_msg && (p_ccb->p_rx_msg->mdep_id == dep) &&
- (p_ccb->p_rx_msg->mdl_id == mdl_id) &&
- (p_ccb->p_rx_msg->op_code == MCA_OP_MDL_CREATE_REQ)) {
- tMCA_CCB_MSG evt_data;
- result = MCA_SUCCESS;
- evt_data.dcb_idx = 0;
- if (rsp_code == MCA_RSP_SUCCESS) {
- tMCA_DCB* p_dcb = mca_dcb_alloc(p_ccb, dep);
- if (p_dcb) {
- evt_data.dcb_idx = mca_dcb_to_hdl(p_dcb);
- p_dcb->p_chnl_cfg = p_chnl_cfg;
- p_dcb->mdl_id = mdl_id;
- } else {
- rsp_code = MCA_RSP_MDEP_BUSY;
- result = MCA_NO_RESOURCES;
- }
- }
-
- if (result == MCA_SUCCESS) {
- evt_data.mdl_id = mdl_id;
- evt_data.param = cfg;
- evt_data.rsp_code = rsp_code;
- evt_data.op_code = MCA_OP_MDL_CREATE_RSP;
- tMCA_CCB_EVT mca_ccb_evt;
- mca_ccb_evt.api = evt_data;
- mca_ccb_event(p_ccb, MCA_CCB_API_RSP_EVT, &mca_ccb_evt);
- }
- } else {
- MCA_TRACE_ERROR(
- "The given MCL is not expecting a MCA_CreateMdlRsp with the given "
- "parameters");
- result = MCA_BAD_PARAMS;
- }
- }
- return result;
-}
-
-/*******************************************************************************
- *
- * Function MCA_CloseReq
- *
- * Description Close a data channel. When the channel is closed, an
- * MCA_CLOSE_CFM_EVT is sent to the application via the
- * control callback function for this handle.
- *
- * Returns MCA_SUCCESS if successful, otherwise error.
- *
- ******************************************************************************/
-tMCA_RESULT MCA_CloseReq(tMCA_DL mdl) {
- tMCA_RESULT result = MCA_BAD_HANDLE;
- tMCA_DCB* p_dcb = mca_dcb_by_hdl(mdl);
-
- MCA_TRACE_API("MCA_CloseReq: %d ", mdl);
- if (p_dcb) {
- result = MCA_SUCCESS;
- mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
- }
- return result;
-}
-
-/*******************************************************************************
- *
- * Function MCA_ReconnectMdl
- *
- * Description This function sends a RECONNECT_MDL request to the peer
- * device. When the response is received, a
- * MCA_RECONNECT_CFM_EVT is reported. If p_chnl_cfg is NULL,
- * the data channel is not initiated until MCA_DataChnlCfg is
- * called to provide the p_chnl_cfg. If the response is
- * successful, a data channel is open. When the data channel is
- * open successfully, a MCA_OPEN_CFM_EVT is reported.
- *
- * Returns MCA_SUCCESS if successful, otherwise error.
- *
- ******************************************************************************/
-tMCA_RESULT MCA_ReconnectMdl(tMCA_CL mcl, tMCA_DEP dep, uint16_t data_psm,
- uint16_t mdl_id, const tMCA_CHNL_CFG* p_chnl_cfg) {
- tMCA_RESULT result = MCA_BAD_HANDLE;
- tMCA_CCB* p_ccb = mca_ccb_by_hdl(mcl);
- tMCA_DCB* p_dcb;
-
- MCA_TRACE_API("MCA_ReconnectMdl: %d ", mcl);
- CHECK(p_chnl_cfg != NULL);
- if (p_ccb) {
- if (p_ccb->p_tx_req || p_ccb->p_rx_msg || p_ccb->cong) {
- MCA_TRACE_ERROR("pending req");
- return MCA_BUSY;
- }
-
- if (!MCA_IS_VALID_MDL_ID(mdl_id)) {
- MCA_TRACE_ERROR("bad mdl id: %d ", mdl_id);
- return MCA_BAD_PARAMS;
- }
-
- if (mca_ccb_uses_mdl_id(p_ccb, mdl_id)) {
- MCA_TRACE_ERROR("mdl id: %d is used in the control link", mdl_id);
- return MCA_BAD_MDL_ID;
- }
-
- p_dcb = mca_dcb_alloc(p_ccb, dep);
- result = MCA_NO_RESOURCES;
- if (p_dcb) {
- tMCA_CCB_EVT* mca_ccb_evt =
- (tMCA_CCB_EVT*)osi_malloc(sizeof(tMCA_CCB_EVT));
- tMCA_CCB_MSG* p_evt_data = &mca_ccb_evt->api;
-
- p_dcb->p_chnl_cfg = p_chnl_cfg;
- p_dcb->mdl_id = mdl_id;
- if (!p_ccb->data_vpsm)
- p_ccb->data_vpsm =
- L2CA_Register(data_psm, (tL2CAP_APPL_INFO*)&mca_l2c_int_appl);
- p_evt_data->dcb_idx = mca_dcb_to_hdl(p_dcb);
- p_evt_data->mdl_id = mdl_id;
- p_evt_data->op_code = MCA_OP_MDL_RECONNECT_REQ;
- p_evt_data->hdr.event = MCA_CCB_API_REQ_EVT;
- mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, mca_ccb_evt);
- return MCA_SUCCESS;
- }
- }
- return result;
-}
-
-/*******************************************************************************
- *
- * Function MCA_ReconnectMdlRsp
- *
- * Description This function sends a RECONNECT_MDL response to the peer
- * device in response to a MCA_RECONNECT_IND_EVT event.
- * If the response is successful, a data channel is open.
- * When the data channel is open successfully, a
- * MCA_OPEN_IND_EVT is reported.
- *
- * Returns MCA_SUCCESS if successful, otherwise error.
- *
- ******************************************************************************/
-tMCA_RESULT MCA_ReconnectMdlRsp(tMCA_CL mcl, tMCA_DEP dep, uint16_t mdl_id,
- uint8_t rsp_code,
- const tMCA_CHNL_CFG* p_chnl_cfg) {
- tMCA_RESULT result = MCA_BAD_HANDLE;
- tMCA_CCB* p_ccb = mca_ccb_by_hdl(mcl);
- tMCA_DCB* p_dcb;
-
- MCA_TRACE_API("MCA_ReconnectMdlRsp: %d ", mcl);
- CHECK(p_chnl_cfg != NULL);
- if (p_ccb) {
- if (p_ccb->cong) {
- MCA_TRACE_ERROR("congested");
- return MCA_BUSY;
- }
- if (p_ccb->p_rx_msg && (p_ccb->p_rx_msg->mdl_id == mdl_id) &&
- (p_ccb->p_rx_msg->op_code == MCA_OP_MDL_RECONNECT_REQ)) {
- result = MCA_SUCCESS;
- tMCA_CCB_MSG evt_data;
- evt_data.dcb_idx = 0;
- if (rsp_code == MCA_RSP_SUCCESS) {
- p_dcb = mca_dcb_alloc(p_ccb, dep);
- if (p_dcb) {
- evt_data.dcb_idx = mca_dcb_to_hdl(p_dcb);
- p_dcb->p_chnl_cfg = p_chnl_cfg;
- p_dcb->mdl_id = mdl_id;
- } else {
- MCA_TRACE_ERROR("Out of MDL for this MDEP");
- rsp_code = MCA_RSP_MDEP_BUSY;
- result = MCA_NO_RESOURCES;
- }
- }
-
- evt_data.mdl_id = mdl_id;
- evt_data.rsp_code = rsp_code;
- evt_data.op_code = MCA_OP_MDL_RECONNECT_RSP;
- tMCA_CCB_EVT mca_ccb_evt;
- mca_ccb_evt.api = evt_data;
- mca_ccb_event(p_ccb, MCA_CCB_API_RSP_EVT, &mca_ccb_evt);
- } else {
- MCA_TRACE_ERROR(
- "The given MCL is not expecting a MCA_ReconnectMdlRsp with the given "
- "parameters");
- result = MCA_BAD_PARAMS;
- }
- }
- return result;
-}
-
-/*******************************************************************************
- *
- * Function MCA_DataChnlCfg
- *
- * Description This function initiates a data channel connection toward the
- * connected peer device.
- * When the data channel is open successfully, a
- * MCA_OPEN_CFM_EVT is reported. This data channel is
- * identified as tMCA_DL.
- *
- * Returns MCA_SUCCESS if successful, otherwise error.
- *
- ******************************************************************************/
-tMCA_RESULT MCA_DataChnlCfg(tMCA_CL mcl, const tMCA_CHNL_CFG* p_chnl_cfg) {
- tMCA_RESULT result = MCA_BAD_HANDLE;
- tMCA_CCB* p_ccb = mca_ccb_by_hdl(mcl);
- tMCA_DCB* p_dcb;
- tMCA_TC_TBL* p_tbl;
-
- MCA_TRACE_API("MCA_DataChnlCfg: %d ", mcl);
- CHECK(p_chnl_cfg != NULL);
- if (p_ccb) {
- result = MCA_NO_RESOURCES;
- if ((p_ccb->p_tx_req == NULL) || (p_ccb->status != MCA_CCB_STAT_PENDING) ||
- ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) == NULL)) {
- MCA_TRACE_ERROR("The given MCL is not expecting this API:%d",
- p_ccb->status);
- return result;
- }
-
- p_dcb->p_chnl_cfg = p_chnl_cfg;
- BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_MCAP_DATA, p_ccb->sec_mask,
- p_ccb->data_vpsm, BTM_SEC_PROTO_MCA,
- p_ccb->p_tx_req->dcb_idx);
- p_dcb->lcid =
- mca_l2c_open_req(p_ccb->peer_addr, p_ccb->data_vpsm, p_dcb->p_chnl_cfg);
- if (p_dcb->lcid) {
- p_tbl = mca_tc_tbl_dalloc(p_dcb);
- if (p_tbl) {
- p_tbl->state = MCA_TC_ST_CONN;
- result = MCA_SUCCESS;
- }
- }
- }
- return result;
-}
-
-/*******************************************************************************
- *
- * Function MCA_Abort
- *
- * Description This function sends a ABORT_MDL request to the peer device.
- * When the response is received, a MCA_ABORT_CFM_EVT is
- * reported.
- *
- * Returns MCA_SUCCESS if successful, otherwise error.
- *
- ******************************************************************************/
-tMCA_RESULT MCA_Abort(tMCA_CL mcl) {
- tMCA_RESULT result = MCA_BAD_HANDLE;
- tMCA_CCB* p_ccb = mca_ccb_by_hdl(mcl);
- tMCA_DCB* p_dcb;
-
- MCA_TRACE_API("MCA_Abort: %d", mcl);
- if (p_ccb) {
- result = MCA_NO_RESOURCES;
- /* verify that we are waiting for data channel to come up with the given mdl
- */
- if ((p_ccb->p_tx_req == NULL) || (p_ccb->status != MCA_CCB_STAT_PENDING) ||
- ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) == NULL)) {
- MCA_TRACE_ERROR("The given MCL is not expecting this API:%d",
- p_ccb->status);
- return result;
- }
-
- if (p_ccb->cong) {
- MCA_TRACE_ERROR("congested");
- return MCA_BUSY;
- }
-
- tMCA_CCB_EVT* mca_ccb_evt = (tMCA_CCB_EVT*)osi_malloc(sizeof(tMCA_CCB_EVT));
- tMCA_CCB_MSG* p_evt_data = &mca_ccb_evt->api;
- result = MCA_SUCCESS;
- p_evt_data->op_code = MCA_OP_MDL_ABORT_REQ;
- p_evt_data->hdr.event = MCA_CCB_API_REQ_EVT;
- mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, mca_ccb_evt);
- }
- return result;
-}
-
-/*******************************************************************************
- *
- * Function MCA_Delete
- *
- * Description This function sends a DELETE_MDL request to the peer device.
- * When the response is received, a MCA_DELETE_CFM_EVT is
- * reported.
- *
- * Returns MCA_SUCCESS if successful, otherwise error.
- *
- ******************************************************************************/
-tMCA_RESULT MCA_Delete(tMCA_CL mcl, uint16_t mdl_id) {
- tMCA_RESULT result = MCA_BAD_HANDLE;
- tMCA_CCB* p_ccb = mca_ccb_by_hdl(mcl);
-
- MCA_TRACE_API("MCA_Delete: %d ", mcl);
- if (p_ccb) {
- if (p_ccb->cong) {
- MCA_TRACE_ERROR("congested");
- return MCA_BUSY;
- }
- if (!MCA_IS_VALID_MDL_ID(mdl_id) && (mdl_id != MCA_ALL_MDL_ID)) {
- MCA_TRACE_ERROR("bad mdl id: %d ", mdl_id);
- return MCA_BAD_PARAMS;
- }
-
- tMCA_CCB_EVT* mca_ccb_evt = (tMCA_CCB_EVT*)osi_malloc(sizeof(tMCA_CCB_EVT));
- tMCA_CCB_MSG* p_evt_data = &mca_ccb_evt->api;
- result = MCA_SUCCESS;
- p_evt_data->mdl_id = mdl_id;
- p_evt_data->op_code = MCA_OP_MDL_DELETE_REQ;
- p_evt_data->hdr.event = MCA_CCB_API_REQ_EVT;
- mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, mca_ccb_evt);
- }
- return result;
-}
-
-/*******************************************************************************
- *
- * Function MCA_WriteReq
- *
- * Description Send a data packet to the peer device.
- *
- * The application passes the packet using the BT_HDR
- * structure. The offset field must be equal to or greater than
- * L2CAP_MIN_OFFSET. This allows enough space in the buffer for
- * the L2CAP header.
- *
- * The memory pointed to by p_pkt must be a GKI buffer
- * allocated by the application. This buffer will be freed
- * by the protocol stack; the application must not free
- * this buffer.
- *
- * Returns MCA_SUCCESS if successful, otherwise error.
- *
- ******************************************************************************/
-tMCA_RESULT MCA_WriteReq(tMCA_DL mdl, BT_HDR* p_pkt) {
- tMCA_RESULT result = MCA_BAD_HANDLE;
- tMCA_DCB* p_dcb = mca_dcb_by_hdl(mdl);
- tMCA_DCB_EVT evt_data;
-
- MCA_TRACE_API("MCA_WriteReq: %d ", mdl);
- if (p_dcb) {
- if (p_dcb->cong) {
- result = MCA_BUSY;
- } else {
- evt_data.p_pkt = p_pkt;
- result = MCA_SUCCESS;
- mca_dcb_event(p_dcb, MCA_DCB_API_WRITE_EVT, &evt_data);
- }
- }
- return result;
-}
-
-/*******************************************************************************
- *
- * Function MCA_GetL2CapChannel
- *
- * Description Get the L2CAP CID used by the given data channel handle.
- *
- * Returns L2CAP channel ID if successful, otherwise 0.
- *
- ******************************************************************************/
-uint16_t MCA_GetL2CapChannel(tMCA_DL mdl) {
- uint16_t lcid = 0;
- tMCA_DCB* p_dcb = mca_dcb_by_hdl(mdl);
-
- MCA_TRACE_API("MCA_GetL2CapChannel: %d ", mdl);
- if (p_dcb) lcid = p_dcb->lcid;
- return lcid;
-}
-
-static const btmcap_test_interface_t mcap_test_interface = {
- sizeof(btmcap_test_interface_t),
- MCA_Init,
- MCA_Register,
- MCA_Deregister,
- MCA_CreateDep,
- MCA_DeleteDep,
- MCA_ConnectReq,
- MCA_DisconnectReq,
- MCA_CreateMdl,
- MCA_CreateMdlRsp,
- MCA_CloseReq,
- MCA_ReconnectMdl,
- MCA_ReconnectMdlRsp,
- MCA_DataChnlCfg,
- MCA_Abort,
- MCA_Delete,
- MCA_WriteReq,
- MCA_GetL2CapChannel,
-};
-
-const btmcap_test_interface_t* stack_mcap_get_interface(void) {
- BTIF_TRACE_EVENT("%s", __func__);
- return &mcap_test_interface;
-}
diff --git a/stack/mcap/mca_cact.cc b/stack/mcap/mca_cact.cc
index 45159ca..e6d73d6 100644
--- a/stack/mcap/mca_cact.cc
+++ b/stack/mcap/mca_cact.cc
@@ -129,7 +129,7 @@
p_msg->hdr.layer_specific = true; /* mark this message as sent */
p_pkt->len = p - p_start;
L2CA_DataWrite(p_ccb->lcid, p_pkt);
- period_ms_t interval_ms = p_ccb->p_rcb->reg.rsp_tout * 1000;
+ uint64_t interval_ms = p_ccb->p_rcb->reg.rsp_tout * 1000;
alarm_set_on_mloop(p_ccb->mca_ccb_timer, interval_ms,
mca_ccb_timer_timeout, p_ccb);
}
diff --git a/stack/mcap/mca_csm.cc b/stack/mcap/mca_csm.cc
deleted file mode 100644
index 4b3a4a0..0000000
--- a/stack/mcap/mca_csm.cc
+++ /dev/null
@@ -1,328 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2009-2012 Broadcom 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.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- * This is the implementation file for the MCAP Control channel state
- * machine.
- *
- ******************************************************************************/
-#include <string.h>
-
-#include "bt_target.h"
-#include "btu.h"
-#include "mca_api.h"
-#include "mca_defs.h"
-#include "mca_int.h"
-
-/*****************************************************************************
- * data channel state machine constants and types
- ****************************************************************************/
-enum {
- MCA_CCB_FREE_MSG,
- MCA_CCB_SND_REQ,
- MCA_CCB_SND_RSP,
- MCA_CCB_DO_DISCONN,
- MCA_CCB_CONG,
- MCA_CCB_HDL_REQ,
- MCA_CCB_HDL_RSP,
- MCA_CCB_LL_OPEN,
- MCA_CCB_DL_OPEN,
- MCA_CCB_DEALLOC,
- MCA_CCB_RSP_TOUT,
- MCA_CCB_NUM_ACTIONS
-};
-#define MCA_CCB_IGNORE MCA_CCB_NUM_ACTIONS
-
-/* action function list */
-const tMCA_CCB_ACTION mca_ccb_action[] = {
- mca_ccb_free_msg, mca_ccb_snd_req, mca_ccb_snd_rsp, mca_ccb_do_disconn,
- mca_ccb_cong, mca_ccb_hdl_req, mca_ccb_hdl_rsp, mca_ccb_ll_open,
- mca_ccb_dl_open, mca_ccb_dealloc, mca_ccb_rsp_tout,
-};
-
-/* state table information */
-#define MCA_CCB_ACTIONS 1 /* number of actions */
-#define MCA_CCB_ACT_COL 0 /* position of action function */
-#define MCA_CCB_NEXT_STATE 1 /* position of next state */
-#define MCA_CCB_NUM_COLS 2 /* number of columns in state tables */
-
-/* state table for opening state */
-const uint8_t mca_ccb_st_opening[][MCA_CCB_NUM_COLS] = {
- /* Event Action Next State */
- /* MCA_CCB_API_CONNECT_EVT */ {MCA_CCB_IGNORE, MCA_CCB_OPENING_ST},
- /* MCA_CCB_API_DISCONNECT_EVT */ {MCA_CCB_DO_DISCONN, MCA_CCB_CLOSING_ST},
- /* MCA_CCB_API_REQ_EVT */ {MCA_CCB_FREE_MSG, MCA_CCB_OPENING_ST},
- /* MCA_CCB_API_RSP_EVT */ {MCA_CCB_IGNORE, MCA_CCB_OPENING_ST},
- /* MCA_CCB_MSG_REQ_EVT */ {MCA_CCB_FREE_MSG, MCA_CCB_OPENING_ST},
- /* MCA_CCB_MSG_RSP_EVT */ {MCA_CCB_FREE_MSG, MCA_CCB_OPENING_ST},
- /* MCA_CCB_DL_OPEN_EVT */ {MCA_CCB_IGNORE, MCA_CCB_OPENING_ST},
- /* MCA_CCB_LL_OPEN_EVT */ {MCA_CCB_LL_OPEN, MCA_CCB_OPEN_ST},
- /* MCA_CCB_LL_CLOSE_EVT */ {MCA_CCB_DEALLOC, MCA_CCB_NULL_ST},
- /* MCA_CCB_LL_CONG_EVT */ {MCA_CCB_CONG, MCA_CCB_OPENING_ST},
- /* MCA_CCB_RSP_TOUT_EVT */ {MCA_CCB_IGNORE, MCA_CCB_OPENING_ST}};
-
-/* state table for open state */
-const uint8_t mca_ccb_st_open[][MCA_CCB_NUM_COLS] = {
- /* Event Action Next State */
- /* MCA_CCB_API_CONNECT_EVT */ {MCA_CCB_IGNORE, MCA_CCB_OPEN_ST},
- /* MCA_CCB_API_DISCONNECT_EVT */ {MCA_CCB_DO_DISCONN, MCA_CCB_CLOSING_ST},
- /* MCA_CCB_API_REQ_EVT */ {MCA_CCB_SND_REQ, MCA_CCB_OPEN_ST},
- /* MCA_CCB_API_RSP_EVT */ {MCA_CCB_SND_RSP, MCA_CCB_OPEN_ST},
- /* MCA_CCB_MSG_REQ_EVT */ {MCA_CCB_HDL_REQ, MCA_CCB_OPEN_ST},
- /* MCA_CCB_MSG_RSP_EVT */ {MCA_CCB_HDL_RSP, MCA_CCB_OPEN_ST},
- /* MCA_CCB_DL_OPEN_EVT */ {MCA_CCB_DL_OPEN, MCA_CCB_OPEN_ST},
- /* MCA_CCB_LL_OPEN_EVT */ {MCA_CCB_IGNORE, MCA_CCB_OPEN_ST},
- /* MCA_CCB_LL_CLOSE_EVT */ {MCA_CCB_DEALLOC, MCA_CCB_NULL_ST},
- /* MCA_CCB_LL_CONG_EVT */ {MCA_CCB_CONG, MCA_CCB_OPEN_ST},
- /* MCA_CCB_RSP_TOUT_EVT */ {MCA_CCB_RSP_TOUT, MCA_CCB_OPEN_ST}};
-
-/* state table for closing state */
-const uint8_t mca_ccb_st_closing[][MCA_CCB_NUM_COLS] = {
- /* Event Action Next State */
- /* MCA_CCB_API_CONNECT_EVT */ {MCA_CCB_IGNORE, MCA_CCB_CLOSING_ST},
- /* MCA_CCB_API_DISCONNECT_EVT */ {MCA_CCB_IGNORE, MCA_CCB_CLOSING_ST},
- /* MCA_CCB_API_REQ_EVT */ {MCA_CCB_FREE_MSG, MCA_CCB_CLOSING_ST},
- /* MCA_CCB_API_RSP_EVT */ {MCA_CCB_IGNORE, MCA_CCB_CLOSING_ST},
- /* MCA_CCB_MSG_REQ_EVT */ {MCA_CCB_FREE_MSG, MCA_CCB_CLOSING_ST},
- /* MCA_CCB_MSG_RSP_EVT */ {MCA_CCB_FREE_MSG, MCA_CCB_CLOSING_ST},
- /* MCA_CCB_DL_OPEN_EVT */ {MCA_CCB_IGNORE, MCA_CCB_CLOSING_ST},
- /* MCA_CCB_LL_OPEN_EVT */ {MCA_CCB_IGNORE, MCA_CCB_CLOSING_ST},
- /* MCA_CCB_LL_CLOSE_EVT */ {MCA_CCB_DEALLOC, MCA_CCB_NULL_ST},
- /* MCA_CCB_LL_CONG_EVT */ {MCA_CCB_IGNORE, MCA_CCB_CLOSING_ST},
- /* MCA_CCB_RSP_TOUT_EVT */ {MCA_CCB_IGNORE, MCA_CCB_CLOSING_ST}};
-
-/* type for state table */
-typedef const uint8_t (*tMCA_CCB_ST_TBL)[MCA_CCB_NUM_COLS];
-
-/* state table */
-const tMCA_CCB_ST_TBL mca_ccb_st_tbl[] = {mca_ccb_st_opening, mca_ccb_st_open,
- mca_ccb_st_closing};
-
-/* verbose event strings for trace */
-static const char* const mca_ccb_evt_str[] = {
- "API_CONNECT_EVT", "API_DISCONNECT_EVT", "API_REQ_EVT", "API_RSP_EVT",
- "MSG_REQ_EVT", "MSG_RSP_EVT", "DL_OPEN_EVT", "LL_OPEN_EVT",
- "LL_CLOSE_EVT", "LL_CONG_EVT", "RSP_TOUT_EVT"};
-/* verbose state strings for trace */
-static const char* const mca_ccb_st_str[] = {"NULL_ST", "OPENING_ST", "OPEN_ST",
- "CLOSING_ST"};
-
-/*******************************************************************************
- *
- * Function mca_stop_timer
- *
- * Description This function is stop a MCAP timer
- *
- * This function is for use internal to MCAP only.
- *
- * Returns void
- *
- ******************************************************************************/
-void mca_stop_timer(tMCA_CCB* p_ccb) { alarm_cancel(p_ccb->mca_ccb_timer); }
-
-/*******************************************************************************
- *
- * Function mca_ccb_event
- *
- * Description This function is the CCB state machine main function.
- * It uses the state and action function tables to execute
- * action functions.
- *
- * Returns void.
- *
- ******************************************************************************/
-void mca_ccb_event(tMCA_CCB* p_ccb, uint8_t event, tMCA_CCB_EVT* p_data) {
- tMCA_CCB_ST_TBL state_table;
- uint8_t action;
-
- MCA_TRACE_EVENT("CCB ccb=%d event=%s state=%s", mca_ccb_to_hdl(p_ccb),
- mca_ccb_evt_str[event], mca_ccb_st_str[p_ccb->state]);
-
- /* look up the state table for the current state */
- state_table = mca_ccb_st_tbl[p_ccb->state - 1];
-
- /* set next state */
- p_ccb->state = state_table[event][MCA_CCB_NEXT_STATE];
-
- /* execute action functions */
- action = state_table[event][MCA_CCB_ACT_COL];
- if (action != MCA_CCB_IGNORE) {
- (*mca_ccb_action[action])(p_ccb, p_data);
- }
-}
-
-/*******************************************************************************
- *
- * Function mca_ccb_by_bd
- *
- * Description This function looks up the CCB based on the BD address.
- * It returns a pointer to the CCB.
- * If no CCB is found it returns NULL.
- *
- * Returns void.
- *
- ******************************************************************************/
-tMCA_CCB* mca_ccb_by_bd(tMCA_HANDLE handle, const RawAddress& bd_addr) {
- tMCA_CCB* p_ccb = NULL;
- tMCA_RCB* p_rcb = mca_rcb_by_handle(handle);
- tMCA_CCB* p_ccb_tmp;
- int i;
-
- if (p_rcb) {
- i = handle - 1;
- p_ccb_tmp = &mca_cb.ccb[i * MCA_NUM_LINKS];
- for (i = 0; i < MCA_NUM_LINKS; i++, p_ccb_tmp++) {
- if (p_ccb_tmp->state != MCA_CCB_NULL_ST &&
- p_ccb_tmp->peer_addr == bd_addr) {
- p_ccb = p_ccb_tmp;
- break;
- }
- }
- }
- return p_ccb;
-}
-
-/*******************************************************************************
- *
- * Function mca_ccb_alloc
- *
- * Description This function allocates a CCB and copies the BD address to
- * the CCB. It returns a pointer to the CCB. If no CCB can
- * be allocated it returns NULL.
- *
- * Returns void.
- *
- ******************************************************************************/
-tMCA_CCB* mca_ccb_alloc(tMCA_HANDLE handle, const RawAddress& bd_addr) {
- tMCA_CCB* p_ccb = NULL;
- tMCA_RCB* p_rcb = mca_rcb_by_handle(handle);
- tMCA_CCB* p_ccb_tmp;
- int i;
-
- MCA_TRACE_DEBUG("mca_ccb_alloc handle:0x%x", handle);
- if (p_rcb) {
- i = handle - 1;
- p_ccb_tmp = &mca_cb.ccb[i * MCA_NUM_LINKS];
- for (i = 0; i < MCA_NUM_LINKS; i++, p_ccb_tmp++) {
- if (p_ccb_tmp->state == MCA_CCB_NULL_ST) {
- p_ccb_tmp->p_rcb = p_rcb;
- p_ccb_tmp->mca_ccb_timer = alarm_new("mca.mca_ccb_timer");
- p_ccb_tmp->state = MCA_CCB_OPENING_ST;
- p_ccb_tmp->cong = true;
- p_ccb_tmp->peer_addr = bd_addr;
- p_ccb = p_ccb_tmp;
- break;
- }
- }
- }
- return p_ccb;
-}
-
-/*******************************************************************************
- *
- * Function mca_ccb_dealloc
- *
- * Description This function deallocates a CCB.
- *
- * Returns void.
- *
- ******************************************************************************/
-void mca_ccb_dealloc(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data) {
- tMCA_CTRL evt_data;
-
- MCA_TRACE_DEBUG("mca_ccb_dealloc ctrl_vpsm:0x%x", p_ccb->ctrl_vpsm);
- mca_dcb_close_by_mdl_id(p_ccb, MCA_ALL_MDL_ID);
- if (p_ccb->ctrl_vpsm) {
- L2CA_Deregister(p_ccb->ctrl_vpsm);
- }
- if (p_ccb->data_vpsm) {
- L2CA_Deregister(p_ccb->data_vpsm);
- }
- osi_free_and_reset((void**)&p_ccb->p_rx_msg);
- osi_free_and_reset((void**)&p_ccb->p_tx_req);
- mca_stop_timer(p_ccb);
-
- if (p_data) {
- /* non-NULL -> an action function -> report disconnect event */
- evt_data.disconnect_ind.bd_addr = p_ccb->peer_addr;
- evt_data.disconnect_ind.reason = p_data->close.reason;
- mca_ccb_report_event(p_ccb, MCA_DISCONNECT_IND_EVT, &evt_data);
- }
- mca_free_tc_tbl_by_lcid(p_ccb->lcid);
- alarm_free(p_ccb->mca_ccb_timer);
- memset(p_ccb, 0, sizeof(tMCA_CCB));
-}
-
-/*******************************************************************************
- *
- * Function mca_ccb_to_hdl
- *
- * Description This function converts a pointer to a CCB to a tMCA_CL
- * and returns the value.
- *
- * Returns void.
- *
- ******************************************************************************/
-tMCA_CL mca_ccb_to_hdl(tMCA_CCB* p_ccb) {
- return (uint8_t)(p_ccb - mca_cb.ccb + 1);
-}
-
-/*******************************************************************************
- *
- * Function mca_ccb_by_hdl
- *
- * Description This function converts an index value to a CCB. It returns
- * a pointer to the CCB. If no valid CCB matches the index it
- * returns NULL.
- *
- * Returns void.
- *
- ******************************************************************************/
-tMCA_CCB* mca_ccb_by_hdl(tMCA_CL mcl) {
- tMCA_CCB* p_ccb = NULL;
- if (mcl && mcl <= MCA_NUM_CCBS && mca_cb.ccb[mcl - 1].state)
- p_ccb = &mca_cb.ccb[mcl - 1];
- return p_ccb;
-}
-
-/*******************************************************************************
- *
- * Function mca_ccb_uses_mdl_id
- *
- * Description This function checkes if a given mdl_id is in use.
- *
- * Returns true, if the given mdl_id is currently used in the MCL.
- *
- ******************************************************************************/
-bool mca_ccb_uses_mdl_id(tMCA_CCB* p_ccb, uint16_t mdl_id) {
- bool uses = false;
- tMCA_DCB* p_dcb;
- int i;
-
- i = mca_ccb_to_hdl(p_ccb) - 1;
- p_dcb = &mca_cb.dcb[i * MCA_NUM_MDLS];
- for (i = 0; i < MCA_NUM_MDLS; i++, p_dcb++) {
- if (p_dcb->state != MCA_DCB_NULL_ST && p_dcb->mdl_id == mdl_id) {
- uses = true;
- break;
- }
- }
-
- return uses;
-}
diff --git a/stack/mcap/mca_dact.cc b/stack/mcap/mca_dact.cc
deleted file mode 100644
index 8ee3ac1..0000000
--- a/stack/mcap/mca_dact.cc
+++ /dev/null
@@ -1,157 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2009-2012 Broadcom 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.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- * This is the implementation file for the MCAP Data Channel Action
- * Functions.
- *
- ******************************************************************************/
-
-#include <stddef.h>
-#include "bt_common.h"
-#include "bt_target.h"
-#include "bt_utils.h"
-#include "mca_api.h"
-#include "mca_int.h"
-#include "osi/include/osi.h"
-
-/*******************************************************************************
- *
- * Function mca_dcb_report_cong
- *
- * Description This function is called to report the congestion flag.
- *
- * Returns void.
- *
- ******************************************************************************/
-void mca_dcb_report_cong(tMCA_DCB* p_dcb) {
- tMCA_CTRL evt_data;
-
- evt_data.cong_chg.cong = p_dcb->cong;
- evt_data.cong_chg.mdl = mca_dcb_to_hdl(p_dcb);
- evt_data.cong_chg.mdl_id = p_dcb->mdl_id;
- mca_ccb_report_event(p_dcb->p_ccb, MCA_CONG_CHG_EVT, &evt_data);
-}
-
-/*******************************************************************************
- *
- * Function mca_dcb_tc_open
- *
- * Description This function is called to report MCA_OPEN_IND_EVT or
- * MCA_OPEN_CFM_EVT event.
- * It also clears the congestion flag (dcb.cong).
- *
- * Returns void.
- *
- ******************************************************************************/
-void mca_dcb_tc_open(tMCA_DCB* p_dcb, tMCA_DCB_EVT* p_data) {
- tMCA_CTRL evt_data;
- tMCA_CCB* p_ccb = p_dcb->p_ccb;
- uint8_t event = MCA_OPEN_IND_EVT;
-
- if (p_data->open.param == MCA_INT) event = MCA_OPEN_CFM_EVT;
- p_dcb->cong = false;
- evt_data.open_cfm.mtu = p_data->open.peer_mtu;
- evt_data.open_cfm.mdl_id = p_dcb->mdl_id;
- evt_data.open_cfm.mdl = mca_dcb_to_hdl(p_dcb);
- mca_ccb_event(p_ccb, MCA_CCB_DL_OPEN_EVT, NULL);
- mca_ccb_report_event(p_ccb, event, &evt_data);
-}
-
-/*******************************************************************************
- *
- * Function mca_dcb_cong
- *
- * Description This function sets the congestion state for the DCB.
- *
- * Returns void.
- *
- ******************************************************************************/
-void mca_dcb_cong(tMCA_DCB* p_dcb, tMCA_DCB_EVT* p_data) {
- p_dcb->cong = p_data->llcong;
- mca_dcb_report_cong(p_dcb);
-}
-
-/*******************************************************************************
- *
- * Function mca_dcb_free_data
- *
- * Description This function frees the received message.
- *
- * Returns void.
- *
- ******************************************************************************/
-void mca_dcb_free_data(UNUSED_ATTR tMCA_DCB* p_dcb, tMCA_DCB_EVT* p_data) {
- osi_free(p_data);
-}
-
-/*******************************************************************************
- *
- * Function mca_dcb_do_disconn
- *
- * Description This function closes a data channel.
- *
- * Returns void.
- *
- ******************************************************************************/
-void mca_dcb_do_disconn(tMCA_DCB* p_dcb, UNUSED_ATTR tMCA_DCB_EVT* p_data) {
- if ((p_dcb->lcid == 0) || (!L2CA_DisconnectReq(p_dcb->lcid))) {
- tMCA_CLOSE close;
- close.param = MCA_INT;
- close.reason = L2CAP_DISC_OK;
- close.lcid = 0;
- tMCA_DCB_EVT mca_dcb_evt;
- mca_dcb_evt.close = close;
- mca_dcb_event(p_dcb, MCA_DCB_TC_CLOSE_EVT, &mca_dcb_evt);
- }
-}
-
-/*******************************************************************************
- *
- * Function mca_dcb_snd_data
- *
- * Description Send the data from application to the peer device.
- *
- * Returns void.
- *
- ******************************************************************************/
-void mca_dcb_snd_data(tMCA_DCB* p_dcb, tMCA_DCB_EVT* p_data) {
- uint8_t status;
-
- /* do not need to check cong, because API already checked the status */
- status = L2CA_DataWrite(p_dcb->lcid, p_data->p_pkt);
- if (status == L2CAP_DW_CONGESTED) {
- p_dcb->cong = true;
- mca_dcb_report_cong(p_dcb);
- }
-}
-
-/*******************************************************************************
- *
- * Function mca_dcb_hdl_data
- *
- * Description This function reports the received data through the data
- * callback function.
- *
- * Returns void.
- *
- ******************************************************************************/
-void mca_dcb_hdl_data(tMCA_DCB* p_dcb, tMCA_DCB_EVT* p_data) {
- (*p_dcb->p_cs->p_data_cback)(mca_dcb_to_hdl(p_dcb), (BT_HDR*)p_data);
-}
diff --git a/stack/mcap/mca_dsm.cc b/stack/mcap/mca_dsm.cc
deleted file mode 100644
index 0d26931..0000000
--- a/stack/mcap/mca_dsm.cc
+++ /dev/null
@@ -1,295 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2009-2012 Broadcom 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.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- * This is the implementation file for the MCAP Data chahnel state machine.
- *
- ******************************************************************************/
-#include <string.h>
-
-#include "bt_target.h"
-#include "mca_api.h"
-#include "mca_defs.h"
-#include "mca_int.h"
-
-/*****************************************************************************
- * data channel state machine constants and types
- ****************************************************************************/
-enum {
- MCA_DCB_TC_OPEN,
- MCA_DCB_CONG,
- MCA_DCB_FREE_DATA,
- MCA_DCB_DEALLOC,
- MCA_DCB_DO_DISCONN,
- MCA_DCB_SND_DATA,
- MCA_DCB_HDL_DATA,
- MCA_DCB_NUM_ACTIONS
-};
-#define MCA_DCB_IGNORE MCA_DCB_NUM_ACTIONS
-
-/* action function list */
-const tMCA_DCB_ACTION mca_dcb_action[] = {
- mca_dcb_tc_open, mca_dcb_cong, mca_dcb_free_data, mca_dcb_dealloc,
- mca_dcb_do_disconn, mca_dcb_snd_data, mca_dcb_hdl_data};
-
-/* state table information */
-#define MCA_DCB_ACTIONS 1 /* number of actions */
-#define MCA_DCB_ACT_COL 0 /* position of action function */
-#define MCA_DCB_NEXT_STATE 1 /* position of next state */
-#define MCA_DCB_NUM_COLS 2 /* number of columns in state tables */
-
-/* state table for opening state */
-const uint8_t mca_dcb_st_opening[][MCA_DCB_NUM_COLS] = {
- /* Event Action Next State */
- /* MCA_DCB_API_CLOSE_EVT */ {MCA_DCB_DO_DISCONN, MCA_DCB_CLOSING_ST},
- /* MCA_DCB_API_WRITE_EVT */ {MCA_DCB_IGNORE, MCA_DCB_OPENING_ST},
- /* MCA_DCB_TC_OPEN_EVT */ {MCA_DCB_TC_OPEN, MCA_DCB_OPEN_ST},
- /* MCA_DCB_TC_CLOSE_EVT */ {MCA_DCB_DEALLOC, MCA_DCB_NULL_ST},
- /* MCA_DCB_TC_CONG_EVT */ {MCA_DCB_CONG, MCA_DCB_OPENING_ST},
- /* MCA_DCB_TC_DATA_EVT */ {MCA_DCB_FREE_DATA, MCA_DCB_OPENING_ST}};
-
-/* state table for open state */
-const uint8_t mca_dcb_st_open[][MCA_DCB_NUM_COLS] = {
- /* Event Action Next State */
- /* MCA_DCB_API_CLOSE_EVT */ {MCA_DCB_DO_DISCONN, MCA_DCB_CLOSING_ST},
- /* MCA_DCB_API_WRITE_EVT */ {MCA_DCB_SND_DATA, MCA_DCB_OPEN_ST},
- /* MCA_DCB_TC_OPEN_EVT */ {MCA_DCB_IGNORE, MCA_DCB_OPEN_ST},
- /* MCA_DCB_TC_CLOSE_EVT */ {MCA_DCB_DEALLOC, MCA_DCB_NULL_ST},
- /* MCA_DCB_TC_CONG_EVT */ {MCA_DCB_CONG, MCA_DCB_OPEN_ST},
- /* MCA_DCB_TC_DATA_EVT */ {MCA_DCB_HDL_DATA, MCA_DCB_OPEN_ST}};
-
-/* state table for closing state */
-const uint8_t mca_dcb_st_closing[][MCA_DCB_NUM_COLS] = {
- /* Event Action Next State */
- /* MCA_DCB_API_CLOSE_EVT */ {MCA_DCB_IGNORE, MCA_DCB_CLOSING_ST},
- /* MCA_DCB_API_WRITE_EVT */ {MCA_DCB_IGNORE, MCA_DCB_CLOSING_ST},
- /* MCA_DCB_TC_OPEN_EVT */ {MCA_DCB_TC_OPEN, MCA_DCB_OPEN_ST},
- /* MCA_DCB_TC_CLOSE_EVT */ {MCA_DCB_DEALLOC, MCA_DCB_NULL_ST},
- /* MCA_DCB_TC_CONG_EVT */ {MCA_DCB_IGNORE, MCA_DCB_CLOSING_ST},
- /* MCA_DCB_TC_DATA_EVT */ {MCA_DCB_FREE_DATA, MCA_DCB_CLOSING_ST}};
-
-/* type for state table */
-typedef const uint8_t (*tMCA_DCB_ST_TBL)[MCA_DCB_NUM_COLS];
-
-/* state table */
-const tMCA_DCB_ST_TBL mca_dcb_st_tbl[] = {mca_dcb_st_opening, mca_dcb_st_open,
- mca_dcb_st_closing};
-
-/* verbose event strings for trace */
-const char* const mca_dcb_evt_str[] = {"API_CLOSE_EVT", "API_WRITE_EVT",
- "TC_OPEN_EVT", "TC_CLOSE_EVT",
- "TC_CONG_EVT", "TC_DATA_EVT"};
-/* verbose state strings for trace */
-const char* const mca_dcb_st_str[] = {"NULL_ST", "OPENING_ST", "OPEN_ST",
- "CLOSING_ST"};
-
-/*******************************************************************************
- *
- * Function mca_dcb_event
- *
- * Description This function is the DCB state machine main function.
- * It uses the state and action function tables to execute
- * action functions.
- *
- * Returns void.
- *
- ******************************************************************************/
-void mca_dcb_event(tMCA_DCB* p_dcb, uint8_t event, tMCA_DCB_EVT* p_data) {
- tMCA_DCB_ST_TBL state_table;
- uint8_t action;
-
- if (p_dcb == NULL) return;
- MCA_TRACE_EVENT("DCB dcb=%d event=%s state=%s", mca_dcb_to_hdl(p_dcb),
- mca_dcb_evt_str[event], mca_dcb_st_str[p_dcb->state]);
-
- /* look up the state table for the current state */
- state_table = mca_dcb_st_tbl[p_dcb->state - 1];
-
- /* set next state */
- p_dcb->state = state_table[event][MCA_DCB_NEXT_STATE];
-
- /* execute action functions */
- action = state_table[event][MCA_DCB_ACT_COL];
- if (action != MCA_DCB_IGNORE) {
- (*mca_dcb_action[action])(p_dcb, p_data);
- }
-}
-
-/*******************************************************************************
- *
- * Function mca_dcb_alloc
- *
- * Description This function is called to allocate an DCB.
- * It initializes the DCB with the data passed to the function.
- *
- * Returns tMCA_DCB *
- *
- ******************************************************************************/
-tMCA_DCB* mca_dcb_alloc(tMCA_CCB* p_ccb, tMCA_DEP dep) {
- tMCA_DCB *p_dcb = NULL, *p_dcb_tmp;
- tMCA_RCB* p_rcb = p_ccb->p_rcb;
- tMCA_CS* p_cs;
- int i, max;
-
- if (dep < MCA_NUM_DEPS) {
- p_cs = &p_rcb->dep[dep];
- i = mca_ccb_to_hdl(p_ccb) - 1;
- p_dcb_tmp = &mca_cb.dcb[i * MCA_NUM_MDLS];
- /* make sure p_cs->max_mdl is smaller than MCA_NUM_MDLS at MCA_CreateDep */
- max = p_cs->max_mdl;
- for (i = 0; i < max; i++, p_dcb_tmp++) {
- if (p_dcb_tmp->state == MCA_DCB_NULL_ST) {
- p_dcb_tmp->p_ccb = p_ccb;
- p_dcb_tmp->state = MCA_DCB_OPENING_ST;
- p_dcb_tmp->cong = true;
- p_dcb_tmp->p_cs = p_cs;
- p_dcb = p_dcb_tmp;
- break;
- }
- }
- }
- return p_dcb;
-}
-
-/*******************************************************************************
- *
- * Function mca_dep_free_mdl
- *
- * Description This function is called to check the number of free mdl for
- * the given dep.
- *
- * Returns the number of free mdl for the given dep
- *
- ******************************************************************************/
-uint8_t mca_dep_free_mdl(tMCA_CCB* p_ccb, tMCA_DEP dep) {
- tMCA_DCB* p_dcb;
- tMCA_RCB* p_rcb = p_ccb->p_rcb;
- tMCA_CS* p_cs;
- int i, max;
- uint8_t count = 0;
- uint8_t left;
-
- if (dep < MCA_NUM_DEPS) {
- p_cs = &p_rcb->dep[dep];
- i = mca_ccb_to_hdl(p_ccb) - 1;
- p_dcb = &mca_cb.dcb[i * MCA_NUM_MDLS];
- /* make sure p_cs->max_mdl is smaller than MCA_NUM_MDLS at MCA_CreateDep */
- max = p_cs->max_mdl;
- for (i = 0; i < max; i++, p_dcb++) {
- if ((p_dcb->state != MCA_DCB_NULL_ST) && (p_dcb->p_cs == p_cs)) {
- count++;
- break;
- }
- }
- } else {
- max = 0;
- MCA_TRACE_WARNING("Invalid Dep ID");
- }
- left = max - count;
- return left;
-}
-
-/*******************************************************************************
- *
- * Function mca_dcb_dealloc
- *
- * Description This function deallocates an DCB.
- *
- * Returns void.
- *
- ******************************************************************************/
-void mca_dcb_dealloc(tMCA_DCB* p_dcb, tMCA_DCB_EVT* p_data) {
- tMCA_CCB* p_ccb = p_dcb->p_ccb;
- uint8_t event = MCA_CLOSE_IND_EVT;
- tMCA_CTRL evt_data;
-
- MCA_TRACE_DEBUG("mca_dcb_dealloc");
- osi_free_and_reset((void**)&p_dcb->p_data);
- if (p_data) {
- /* non-NULL -> an action function -> report disconnect event */
- evt_data.close_cfm.mdl = mca_dcb_to_hdl(p_dcb);
- evt_data.close_cfm.reason = p_data->close.reason;
- evt_data.close_cfm.mdl_id = p_dcb->mdl_id;
- if (p_data->close.param == MCA_INT) event = MCA_CLOSE_CFM_EVT;
- if (p_data->close.lcid) mca_ccb_report_event(p_ccb, event, &evt_data);
- }
- mca_free_tc_tbl_by_lcid(p_dcb->lcid);
- memset(p_dcb, 0, sizeof(tMCA_DCB));
-}
-
-/*******************************************************************************
- *
- * Function mca_dcb_to_hdl
- *
- * Description Convert a pointer to a DCB to a handle (tMCA_DL).
- * It returns the handle.
- *
- * Returns tMCA_DL.
- *
- ******************************************************************************/
-tMCA_DL mca_dcb_to_hdl(tMCA_DCB* p_dcb) {
- return (uint8_t)(p_dcb - mca_cb.dcb + 1);
-}
-
-/*******************************************************************************
- *
- * Function mca_dcb_by_hdl
- *
- * Description This function finds the DCB for a handle (tMCA_DL).
- * It returns a pointer to the DCB.
- * If no DCB matches the handle it returns NULL.
- *
- * Returns tMCA_DCB *
- *
- ******************************************************************************/
-tMCA_DCB* mca_dcb_by_hdl(tMCA_DL hdl) {
- tMCA_DCB* p_dcb = NULL;
- if (hdl && hdl <= MCA_NUM_DCBS && mca_cb.dcb[hdl - 1].state)
- p_dcb = &mca_cb.dcb[hdl - 1];
- return p_dcb;
-}
-
-/*******************************************************************************
- *
- * Function mca_dcb_close_by_mdl_id
- *
- * Description This function finds the DCB for a mdl_id and
- * disconnect the mdl
- *
- * Returns void
- *
- ******************************************************************************/
-void mca_dcb_close_by_mdl_id(tMCA_CCB* p_ccb, uint16_t mdl_id) {
- tMCA_DCB* p_dcb;
- int i;
-
- MCA_TRACE_DEBUG("mca_dcb_close_by_mdl_id mdl_id=%d", mdl_id);
- i = mca_ccb_to_hdl(p_ccb) - 1;
- p_dcb = &mca_cb.dcb[i * MCA_NUM_MDLS];
- for (i = 0; i < MCA_NUM_MDLS; i++, p_dcb++) {
- if (p_dcb->state) {
- if (p_dcb->mdl_id == mdl_id) {
- mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
- break;
- } else if (mdl_id == MCA_ALL_MDL_ID) {
- mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
- }
- }
- }
-}
diff --git a/stack/mcap/mca_int.h b/stack/mcap/mca_int.h
deleted file mode 100644
index 9ae5d57..0000000
--- a/stack/mcap/mca_int.h
+++ /dev/null
@@ -1,370 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2009-2012 Broadcom 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.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- * This file contains interfaces which are internal to MCAP.
- *
- ******************************************************************************/
-#ifndef MCA_INT_H
-#define MCA_INT_H
-#include "bt_common.h"
-#include "mca_api.h"
-#include "osi/include/alarm.h"
-
-/*****************************************************************************
- * constants
- ****************************************************************************/
-
-/* INT initiates the L2CAP channel */
-#define MCA_ACP 0
-#define MCA_INT 1
-
-/*****************************************************************************
- * Type Definitions
- ****************************************************************************/
-
-/* Header structure for api/received request/response. */
-typedef struct {
- BT_HDR hdr; /* layer specific information */
- uint8_t op_code; /* the request/response opcode */
- uint8_t rsp_code; /* valid only if op_code is a response */
- uint16_t mdl_id; /* the MDL ID associated with this request/response */
- uint8_t param; /* other parameter */
- uint8_t mdep_id; /* the MDEP ID associated with this request/response */
- /* tMCA_HANDLE rcb_idx; For internal use only */
- /* tMCA_CL ccb_idx; For internal use only */
- tMCA_DL dcb_idx; /* For internal use only */
-} tMCA_CCB_MSG;
-
-/* This data structure is for AVDT_OPEN_IND_EVT and AVDT_OPEN_CFM_EVT. */
-typedef struct {
- BT_HDR hdr; /* Event header */
- uint16_t peer_mtu; /* Transport channel L2CAP MTU of the peer */
- uint16_t lcid; /* L2CAP LCID */
- uint8_t param;
-} tMCA_OPEN;
-
-typedef struct {
- uint16_t reason; /* disconnect reason from L2CAP */
- uint8_t param; /* MCA_INT or MCA_ACP */
- uint16_t lcid; /* L2CAP LCID */
-} tMCA_CLOSE;
-
-/* Header structure for state machine event parameters. */
-typedef union {
- BT_HDR hdr; /* layer specific information */
- tMCA_CCB_MSG api;
- bool llcong;
- uint8_t param;
- tMCA_OPEN open;
- tMCA_CLOSE close;
-} tMCA_CCB_EVT;
-
-/* control channel states */
-enum {
- MCA_CCB_NULL_ST, /* not allocated */
- MCA_CCB_OPENING_ST,
- MCA_CCB_OPEN_ST, /* open */
- MCA_CCB_CLOSING_ST, /* disconnecting */
- MCA_CCB_MAX_ST
-};
-typedef uint8_t tMCA_CCB_STATE;
-
-/* control channel events */
-enum {
- MCA_CCB_API_CONNECT_EVT, /* application initiates a connect request. */
- MCA_CCB_API_DISCONNECT_EVT, /* application initiates a disconnect request. */
- MCA_CCB_API_REQ_EVT, /* application initiates a request. The request may be
- create_mdl, delete_mdl, reconnect_mdl or abort_mdl. */
- MCA_CCB_API_RSP_EVT, /* application initiates a create_mdl or reconnect_mdl
- response. */
- MCA_CCB_MSG_REQ_EVT, /* a create_mdl, delete_mdl, reconnect_mdl or abort_mdl
- request message is received from the peer. */
- MCA_CCB_MSG_RSP_EVT, /* Response received event. This event is sent whenever
- a response message is received for an outstanding
- request message. */
- MCA_CCB_DL_OPEN_EVT, /* data channel open. */
- MCA_CCB_LL_OPEN_EVT, /* Lower layer open. This event is sent when the lower
- layer channel is open. */
- MCA_CCB_LL_CLOSE_EVT, /* Lower layer close. This event is sent when the lower
- layer channel is closed. */
- MCA_CCB_LL_CONG_EVT, /* Lower layer congestion. This event is sent when the
- lower layer is congested. */
- MCA_CCB_RSP_TOUT_EVT /* time out for waiting the message response on the
- control channel */
-};
-
-/* Header structure for callback event parameters. */
-typedef union {
- tMCA_OPEN open;
- tMCA_CLOSE close;
- BT_HDR hdr; /* layer specific information */
- BT_HDR* p_pkt;
- bool llcong;
- uint16_t mdl_id; /* the MDL ID associated with this request/response */
-
- /* tMCA_HANDLE rcb_idx; For internal use only */
- /* tMCA_CL ccb_idx; For internal use only */
- /* tMCA_DL dcb_idx; For internal use only */
-} tMCA_DCB_EVT;
-
-/* data channel states */
-enum {
- MCA_DCB_NULL_ST, /* not allocated */
- MCA_DCB_OPENING_ST, /* create/reconnect sequence is successful, waiting for
- data channel connection */
- MCA_DCB_OPEN_ST, /* open */
- MCA_DCB_CLOSING_ST, /* disconnecting */
- MCA_DCB_MAX_ST
-};
-typedef uint8_t tMCA_DCB_STATE;
-
-/* data channel events */
-enum {
- MCA_DCB_API_CLOSE_EVT, /* This event is sent when the application wants to
- disconnect the data channel.*/
- MCA_DCB_API_WRITE_EVT, /* This event is sent when the application wants to
- send a data packet to the peer.*/
- MCA_DCB_TC_OPEN_EVT, /* Transport Channel open. This event is sent when the
- channel is open.*/
- MCA_DCB_TC_CLOSE_EVT, /* Transport Channel close.*/
- MCA_DCB_TC_CONG_EVT, /* Transport Channel congestion status.*/
- MCA_DCB_TC_DATA_EVT /* This event is sent when a data packet is received from
- the peer.*/
-};
-
-/* "states" used in transport channel table */
-#define MCA_TC_ST_UNUSED 0 /* Unused - unallocated */
-#define MCA_TC_ST_IDLE 1 /* No connection */
-#define MCA_TC_ST_ACP 2 /* Waiting to accept a connection */
-#define MCA_TC_ST_INT 3 /* Initiating a connection */
-#define MCA_TC_ST_CONN 4 /* Waiting for connection confirm */
-#define MCA_TC_ST_CFG 5 /* Waiting for configuration complete */
-#define MCA_TC_ST_OPEN 6 /* Channel opened */
-#define MCA_TC_ST_SEC_INT 7 /* Security process as INT */
-#define MCA_TC_ST_SEC_ACP 8 /* Security process as ACP */
-
-/* Configuration flags. tMCA_TC_TBL.cfg_flags */
-#define MCA_L2C_CFG_IND_DONE (1 << 0)
-#define MCA_L2C_CFG_CFM_DONE (1 << 1)
-#define MCA_L2C_CFG_CONN_INT (1 << 2)
-#define MCA_L2C_CFG_CONN_ACP (1 << 3)
-#define MCA_L2C_CFG_DISCN_INT (1 << 4)
-#define MCA_L2C_CFG_DISCN_ACP (1 << 5)
-
-#define MCA_CTRL_TCID 0 /* to identify control channel by tMCA_TC_TBL.tcid */
-
-/* transport channel table */
-typedef struct {
- uint16_t peer_mtu; /* L2CAP mtu of the peer device */
- uint16_t my_mtu; /* Our MTU for this channel */
- uint16_t lcid; /* L2CAP LCID */
- uint8_t tcid; /* transport channel id (0, for control channel. (MDEP ID + 1)
- for data channel) */
- tMCA_DL cb_idx; /* 1-based index to ccb or dcb */
- uint8_t state; /* transport channel state */
- uint8_t cfg_flags; /* L2CAP configuration flags */
- uint8_t id; /* L2CAP id sent by peer device (need this to handle security
- pending) */
-} tMCA_TC_TBL;
-
-/* transport control block */
-typedef struct {
- tMCA_TC_TBL tc_tbl[MCA_NUM_TC_TBL];
- uint8_t lcid_tbl[MAX_L2CAP_CHANNELS]; /* map LCID to tc_tbl index */
-} tMCA_TC;
-
-/* registration control block */
-typedef struct {
- tMCA_REG reg; /* the parameter at register */
- tMCA_CS dep[MCA_NUM_DEPS]; /* the registration info for each MDEP */
- tMCA_CTRL_CBACK* p_cback; /* control callback function */
-} tMCA_RCB;
-
-enum {
- MCA_CCB_STAT_NORM, /* normal operation (based on ccb state) */
- MCA_CCB_STAT_PENDING, /* waiting for data channel */
- MCA_CCB_STAT_RECONN, /* reinitiate connection after transitioning from CLOSING
- to IDLE state */
- MCA_CCB_STAT_DISC /* MCA_DisconnectReq or MCA_Deregister is called. waiting
- for all associated CL and DL to detach */
-};
-typedef uint8_t tMCA_CCB_STAT;
-
-/* control channel control block */
-/* the ccbs association with the rcbs
- * ccb[0] ...ccb[MCA_NUM_LINKS*1-1] -> rcb[0]
- * ccb[MCA_NUM_LINKS*1]...ccb[MCA_NUM_LINKS*2-1] -> rcb[1]
- * ccb[MCA_NUM_LINKS*2]...ccb[MCA_NUM_LINKS*3-1] -> rcb[2]
- */
-typedef struct {
- tMCA_RCB* p_rcb; /* the associated registration control block */
- alarm_t* mca_ccb_timer; /* MCA CCB timer entry */
- tMCA_CCB_MSG* p_tx_req; /* Current request being sent/awaiting response */
- tMCA_CCB_MSG* p_rx_msg; /* Current message received/being processed */
- RawAddress peer_addr; /* BD address of peer */
- uint16_t sec_mask; /* Security mask for connections as initiator */
- uint16_t ctrl_vpsm; /* The virtual PSM that peer is listening for control
- channel */
- uint16_t
- data_vpsm; /* The virtual PSM that peer is listening for data channel. */
- uint16_t lcid; /* L2CAP lcid for this control channel */
- uint8_t state; /* The CCB state machine state */
- bool cong; /* Whether control channel is congested */
- tMCA_CCB_STAT status; /* see tMCA_CCB_STAT */
-} tMCA_CCB;
-typedef void (*tMCA_CCB_ACTION)(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data);
-
-enum {
- MCA_DCB_STAT_NORM, /* normal operation (based on dcb state) */
- MCA_DCB_STAT_DEL, /* MCA_Delete is called. waiting for the DL to detach */
- MCA_DCB_STAT_DISC /* MCA_CloseReq is called. waiting for the DL to detach */
-};
-typedef uint8_t tMCA_DCB_STAT;
-
-/* data channel control block */
-/* the dcbs association with the ccbs
- * dcb[0] ...dcb[MCA_NUM_MDLS*1-1] -> ccb[0]
- * dcb[MCA_NUM_MDLS*1]...dcb[MCA_NUM_MDLS*2-1] -> ccb[1]
- * dcb[MCA_NUM_MDLS*2]...dcb[MCA_NUM_MDLS*3-1] -> ccb[2]
- *
- * the dcbs association with the rcbs
- * dcb[0]
- * ...dcb[MCA_NUM_MDLS*1*MCA_NUM_LINKS*1-1] -> rcb[0]
- * dcb[MCA_NUM_MDLS*1*MCA_NUM_LINKS*1]
- * ...dcb[MCA_NUM_MDLS*2*MCA_NUM_LINKS*2-1] -> rcb[1]
- * dcb[MCA_NUM_MDLS*2*MCA_NUM_LINKS*2]
- * ...dcb[MCA_NUM_MDLS*3*MCA_NUM_LINKS*3-1] -> rcb[2]
- */
-typedef struct {
- tMCA_CCB* p_ccb; /* the associated control control block */
- BT_HDR* p_data; /* data packet held due to L2CAP channel congestion */
- tMCA_CS* p_cs; /* the associated MDEP info. p_cs->type is the mdep id(internal
- use) */
- const tMCA_CHNL_CFG* p_chnl_cfg; /* cfg params for L2CAP channel */
- uint16_t mdl_id; /* the MDL ID for this data channel */
- uint16_t lcid; /* L2CAP lcid */
- uint8_t state; /* The DCB state machine state */
- bool cong; /* Whether data channel is congested */
- tMCA_DCB_STAT status; /* see tMCA_DCB_STAT */
-} tMCA_DCB;
-
-typedef void (*tMCA_DCB_ACTION)(tMCA_DCB* p_ccb, tMCA_DCB_EVT* p_data);
-
-/* Control block for MCA */
-typedef struct {
- tMCA_RCB rcb[MCA_NUM_REGS]; /* registration control block */
- tMCA_CCB ccb[MCA_NUM_CCBS]; /* control channel control blocks */
- tMCA_DCB dcb[MCA_NUM_DCBS]; /* data channel control blocks */
- tMCA_TC tc; /* transport control block */
- uint8_t trace_level; /* trace level */
-} tMCA_CB;
-
-/* csm functions */
-extern void mca_ccb_event(tMCA_CCB* p_ccb, uint8_t event, tMCA_CCB_EVT* p_data);
-extern tMCA_CCB* mca_ccb_by_bd(tMCA_HANDLE handle, const RawAddress& bd_addr);
-extern tMCA_CCB* mca_ccb_alloc(tMCA_HANDLE handle, const RawAddress& bd_addr);
-extern void mca_ccb_rsp_tout(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data);
-extern void mca_ccb_dealloc(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data);
-extern tMCA_CL mca_ccb_to_hdl(tMCA_CCB* p_ccb);
-extern tMCA_CCB* mca_ccb_by_hdl(tMCA_CL mcl);
-extern bool mca_ccb_uses_mdl_id(tMCA_CCB* p_ccb, uint16_t mdl_id);
-
-/* cact functions */
-extern void mca_ccb_report_event(tMCA_CCB* p_ccb, uint8_t event,
- tMCA_CTRL* p_data);
-extern void mca_ccb_free_msg(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data);
-extern void mca_ccb_snd_req(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data);
-extern void mca_ccb_snd_rsp(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data);
-extern void mca_ccb_do_disconn(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data);
-extern void mca_ccb_cong(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data);
-extern void mca_ccb_hdl_req(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data);
-extern void mca_ccb_hdl_rsp(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data);
-extern void mca_ccb_ll_open(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data);
-extern void mca_ccb_dl_open(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data);
-
-/* dsm functions */
-extern void mca_dcb_event(tMCA_DCB* p_dcb, uint8_t event, tMCA_DCB_EVT* p_data);
-extern tMCA_DCB* mca_dcb_alloc(tMCA_CCB* p_ccb, tMCA_DEP dep);
-extern uint8_t mca_dep_free_mdl(tMCA_CCB* p_ccb, tMCA_DEP dep);
-extern void mca_dcb_dealloc(tMCA_DCB* p_dcb, tMCA_DCB_EVT* p_data);
-extern tMCA_DL mca_dcb_to_hdl(tMCA_DCB* p_dcb);
-extern tMCA_DCB* mca_dcb_by_hdl(tMCA_DL hdl);
-extern void mca_dcb_close_by_mdl_id(tMCA_CCB* p_ccb, uint16_t mdl_id);
-
-/* dact functions */
-extern void mca_dcb_tc_open(tMCA_DCB* p_dcb, tMCA_DCB_EVT* p_data);
-extern void mca_dcb_cong(tMCA_DCB* p_dcb, tMCA_DCB_EVT* p_data);
-extern void mca_dcb_free_data(tMCA_DCB* p_dcb, tMCA_DCB_EVT* p_data);
-extern void mca_dcb_do_disconn(tMCA_DCB* p_dcb, tMCA_DCB_EVT* p_data);
-extern void mca_dcb_snd_data(tMCA_DCB* p_dcb, tMCA_DCB_EVT* p_data);
-extern void mca_dcb_hdl_data(tMCA_DCB* p_dcb, tMCA_DCB_EVT* p_data);
-
-/* main/utils functions */
-extern tMCA_HANDLE mca_handle_by_cpsm(uint16_t psm);
-extern tMCA_HANDLE mca_handle_by_dpsm(uint16_t psm);
-extern tMCA_TC_TBL* mca_tc_tbl_calloc(tMCA_CCB* p_ccb);
-extern tMCA_TC_TBL* mca_tc_tbl_dalloc(tMCA_DCB* p_dcb);
-extern tMCA_TC_TBL* mca_tc_tbl_by_lcid(uint16_t lcid);
-extern void mca_free_tc_tbl_by_lcid(uint16_t lcid);
-extern void mca_set_cfg_by_tbl(tL2CAP_CFG_INFO* p_cfg, tMCA_TC_TBL* p_tbl);
-extern void mca_tc_close_ind(tMCA_TC_TBL* p_tbl, uint16_t reason);
-extern void mca_tc_open_ind(tMCA_TC_TBL* p_tbl);
-extern void mca_tc_cong_ind(tMCA_TC_TBL* p_tbl, bool is_congested);
-extern void mca_tc_data_ind(tMCA_TC_TBL* p_tbl, BT_HDR* p_buf);
-extern tMCA_RCB* mca_rcb_alloc(tMCA_REG* p_reg);
-extern void mca_rcb_dealloc(tMCA_HANDLE handle);
-extern tMCA_HANDLE mca_rcb_to_handle(tMCA_RCB* p_rcb);
-extern tMCA_RCB* mca_rcb_by_handle(tMCA_HANDLE handle);
-extern bool mca_is_valid_dep_id(tMCA_RCB* p_rcb, tMCA_DEP dep);
-extern void mca_ccb_timer_timeout(void* data);
-extern void mca_stop_timer(tMCA_CCB* p_ccb);
-
-/* l2c functions */
-extern uint16_t mca_l2c_open_req(const RawAddress& bd_addr, uint16_t PSM,
- const tMCA_CHNL_CFG* p_chnl_cfg);
-
-/* callback function declarations */
-extern void mca_l2c_cconn_ind_cback(const RawAddress& bd_addr, uint16_t lcid,
- uint16_t psm, uint8_t id);
-extern void mca_l2c_dconn_ind_cback(const RawAddress& bd_addr, uint16_t lcid,
- uint16_t psm, uint8_t id);
-extern void mca_l2c_connect_cfm_cback(uint16_t lcid, uint16_t result);
-extern void mca_l2c_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg);
-extern void mca_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg);
-extern void mca_l2c_disconnect_ind_cback(uint16_t lcid, bool ack_needed);
-extern void mca_l2c_disconnect_cfm_cback(uint16_t lcid, uint16_t result);
-extern void mca_l2c_congestion_ind_cback(uint16_t lcid, bool is_congested);
-extern void mca_l2c_data_ind_cback(uint16_t lcid, BT_HDR* p_buf);
-
-/*****************************************************************************
- * global data
- ****************************************************************************/
-
-/******************************************************************************
- * Main Control Block
- ******************************************************************************/
-extern tMCA_CB mca_cb;
-
-/* L2CAP callback registration structure */
-extern const tL2CAP_APPL_INFO mca_l2c_int_appl;
-extern const tL2CAP_FCR_OPTS mca_l2c_fcr_opts_def;
-extern const uint8_t mca_std_msg_len[];
-
-#endif /* MCA_INT_H */
diff --git a/stack/mcap/mca_l2c.cc b/stack/mcap/mca_l2c.cc
deleted file mode 100644
index e0540fa..0000000
--- a/stack/mcap/mca_l2c.cc
+++ /dev/null
@@ -1,540 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2009-2012 Broadcom 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.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- * This is the implementation file for the MCAP at L2CAP Interface.
- *
- ******************************************************************************/
-#include <string.h>
-
-#include "bt_target.h"
-#include "bt_utils.h"
-#include "btm_api.h"
-#include "btm_int.h"
-#include "mca_api.h"
-#include "mca_defs.h"
-#include "mca_int.h"
-#include "osi/include/osi.h"
-
-/* L2CAP callback function structure */
-const tL2CAP_APPL_INFO mca_l2c_int_appl = {
- NULL,
- mca_l2c_connect_cfm_cback,
- NULL,
- mca_l2c_config_ind_cback,
- mca_l2c_config_cfm_cback,
- mca_l2c_disconnect_ind_cback,
- mca_l2c_disconnect_cfm_cback,
- NULL,
- mca_l2c_data_ind_cback,
- mca_l2c_congestion_ind_cback,
- NULL,
- NULL /* tL2CA_CREDITS_RECEIVED_CB */};
-
-/* Control channel eL2CAP default options */
-const tL2CAP_FCR_OPTS mca_l2c_fcr_opts_def = {
- L2CAP_FCR_ERTM_MODE, /* Mandatory for MCAP */
- MCA_FCR_OPT_TX_WINDOW_SIZE, /* Tx window size */
- MCA_FCR_OPT_MAX_TX_B4_DISCNT, /* Maximum transmissions before
- disconnecting */
- MCA_FCR_OPT_RETX_TOUT, /* Retransmission timeout (2 secs) */
- MCA_FCR_OPT_MONITOR_TOUT, /* Monitor timeout (12 secs) */
- MCA_FCR_OPT_MPS_SIZE /* MPS segment size */
-};
-
-/*******************************************************************************
- *
- * Function mca_sec_check_complete_term
- *
- * Description The function called when Security Manager finishes
- * verification of the service side connection
- *
- * Returns void
- *
- ******************************************************************************/
-static void mca_sec_check_complete_term(const RawAddress* bd_addr,
- UNUSED_ATTR tBT_TRANSPORT transport,
- void* p_ref_data, uint8_t res) {
- tMCA_TC_TBL* p_tbl = (tMCA_TC_TBL*)p_ref_data;
- tL2CAP_CFG_INFO cfg;
- tL2CAP_ERTM_INFO ertm_info;
-
- MCA_TRACE_DEBUG("mca_sec_check_complete_term res: %d", res);
-
- if (res == BTM_SUCCESS) {
- MCA_TRACE_DEBUG("lcid:x%x id:x%x", p_tbl->lcid, p_tbl->id);
- /* Set the FCR options: control channel mandates ERTM */
- ertm_info.preferred_mode = mca_l2c_fcr_opts_def.mode;
- ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_ERTM;
- ertm_info.user_rx_buf_size = MCA_USER_RX_BUF_SIZE;
- ertm_info.user_tx_buf_size = MCA_USER_TX_BUF_SIZE;
- ertm_info.fcr_rx_buf_size = MCA_FCR_RX_BUF_SIZE;
- ertm_info.fcr_tx_buf_size = MCA_FCR_TX_BUF_SIZE;
- /* Send response to the L2CAP layer. */
- L2CA_ErtmConnectRsp(*bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_OK,
- L2CAP_CONN_OK, &ertm_info);
-
- /* transition to configuration state */
- p_tbl->state = MCA_TC_ST_CFG;
-
- /* Send L2CAP config req */
- mca_set_cfg_by_tbl(&cfg, p_tbl);
- L2CA_ConfigReq(p_tbl->lcid, &cfg);
- } else {
- L2CA_ConnectRsp(*bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_SECURITY_BLOCK,
- L2CAP_CONN_OK);
- mca_tc_close_ind(p_tbl, L2CAP_CONN_SECURITY_BLOCK);
- }
-}
-
-/*******************************************************************************
- *
- * Function mca_sec_check_complete_orig
- *
- * Description The function called when Security Manager finishes
- * verification of the service side connection
- *
- * Returns void
- *
- ******************************************************************************/
-static void mca_sec_check_complete_orig(UNUSED_ATTR const RawAddress* bd_addr,
- UNUSED_ATTR tBT_TRANSPORT transport,
- void* p_ref_data, uint8_t res) {
- tMCA_TC_TBL* p_tbl = (tMCA_TC_TBL*)p_ref_data;
- tL2CAP_CFG_INFO cfg;
-
- MCA_TRACE_DEBUG("mca_sec_check_complete_orig res: %d", res);
-
- if (res == BTM_SUCCESS) {
- /* set channel state */
- p_tbl->state = MCA_TC_ST_CFG;
-
- /* Send L2CAP config req */
- mca_set_cfg_by_tbl(&cfg, p_tbl);
- L2CA_ConfigReq(p_tbl->lcid, &cfg);
- } else {
- L2CA_DisconnectReq(p_tbl->lcid);
- mca_tc_close_ind(p_tbl, L2CAP_CONN_SECURITY_BLOCK);
- }
-}
-/*******************************************************************************
- *
- * Function mca_l2c_cconn_ind_cback
- *
- * Description This is the L2CAP connect indication callback function.
- *
- * Returns void
- *
- ******************************************************************************/
-void mca_l2c_cconn_ind_cback(const RawAddress& bd_addr, uint16_t lcid,
- uint16_t psm, uint8_t id) {
- tMCA_HANDLE handle = mca_handle_by_cpsm(psm);
- tMCA_CCB* p_ccb;
- tMCA_TC_TBL* p_tbl = NULL;
- uint16_t result = L2CAP_CONN_NO_RESOURCES;
- tBTM_STATUS rc;
- tL2CAP_ERTM_INFO ertm_info, *p_ertm_info = NULL;
- tL2CAP_CFG_INFO cfg;
-
- MCA_TRACE_EVENT("mca_l2c_cconn_ind_cback: lcid:x%x psm:x%x id:x%x", lcid, psm,
- id);
-
- /* do we already have a control channel for this peer? */
- p_ccb = mca_ccb_by_bd(handle, bd_addr);
- if (p_ccb == NULL) {
- /* no, allocate ccb */
- p_ccb = mca_ccb_alloc(handle, bd_addr);
- if (p_ccb != NULL) {
- /* allocate and set up entry */
- p_ccb->lcid = lcid;
- p_tbl = mca_tc_tbl_calloc(p_ccb);
- p_tbl->id = id;
- p_tbl->cfg_flags = MCA_L2C_CFG_CONN_ACP;
- /* proceed with connection */
- /* Check the security */
- rc = btm_sec_mx_access_request(bd_addr, psm, false, BTM_SEC_PROTO_MCA, 0,
- &mca_sec_check_complete_term, p_tbl);
- if (rc == BTM_CMD_STARTED) {
- /* Set the FCR options: control channel mandates ERTM */
- ertm_info.preferred_mode = mca_l2c_fcr_opts_def.mode;
- ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_ERTM;
- ertm_info.user_rx_buf_size = MCA_USER_RX_BUF_SIZE;
- ertm_info.user_tx_buf_size = MCA_USER_TX_BUF_SIZE;
- ertm_info.fcr_rx_buf_size = MCA_FCR_RX_BUF_SIZE;
- ertm_info.fcr_tx_buf_size = MCA_FCR_TX_BUF_SIZE;
- p_ertm_info = &ertm_info;
- result = L2CAP_CONN_PENDING;
- } else
- result = L2CAP_CONN_OK;
- }
-
- /* deal with simultaneous control channel connect case */
- }
- /* else reject their connection */
-
- if (!p_tbl || (p_tbl->state != MCA_TC_ST_CFG)) {
- /* Send L2CAP connect rsp */
- L2CA_ErtmConnectRsp(bd_addr, id, lcid, result, L2CAP_CONN_OK, p_ertm_info);
-
- /* if result ok, proceed with connection and send L2CAP
- config req */
- if (result == L2CAP_CONN_OK) {
- /* set channel state */
- p_tbl->state = MCA_TC_ST_CFG;
-
- /* Send L2CAP config req */
- mca_set_cfg_by_tbl(&cfg, p_tbl);
- L2CA_ConfigReq(p_tbl->lcid, &cfg);
- }
- }
-}
-
-/*******************************************************************************
- *
- * Function mca_l2c_dconn_ind_cback
- *
- * Description This is the L2CAP connect indication callback function.
- *
- *
- * Returns void
- *
- ******************************************************************************/
-void mca_l2c_dconn_ind_cback(const RawAddress& bd_addr, uint16_t lcid,
- uint16_t psm, uint8_t id) {
- tMCA_HANDLE handle = mca_handle_by_dpsm(psm);
- tMCA_CCB* p_ccb;
- tMCA_DCB* p_dcb;
- tMCA_TC_TBL* p_tbl = NULL;
- uint16_t result;
- tL2CAP_CFG_INFO cfg;
- tL2CAP_ERTM_INFO *p_ertm_info = NULL, ertm_info;
- const tMCA_CHNL_CFG* p_chnl_cfg;
-
- MCA_TRACE_EVENT("mca_l2c_dconn_ind_cback: lcid:x%x psm:x%x ", lcid, psm);
-
- if (((p_ccb = mca_ccb_by_bd(handle, bd_addr)) != NULL) && /* find the CCB */
- (p_ccb->status ==
- MCA_CCB_STAT_PENDING) && /* this CCB is expecting a MDL */
- (p_ccb->p_tx_req &&
- (p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) != NULL)) {
- /* found the associated dcb in listening mode */
- /* proceed with connection */
- p_dcb->lcid = lcid;
- p_tbl = mca_tc_tbl_dalloc(p_dcb);
- p_tbl->id = id;
- p_tbl->cfg_flags = MCA_L2C_CFG_CONN_ACP;
- p_chnl_cfg = p_dcb->p_chnl_cfg;
- /* assume that control channel has verified the security requirement */
- /* Set the FCR options: control channel mandates ERTM */
- ertm_info.preferred_mode = p_chnl_cfg->fcr_opt.mode;
- ertm_info.allowed_modes = (1 << p_chnl_cfg->fcr_opt.mode);
- ertm_info.user_rx_buf_size = p_chnl_cfg->user_rx_buf_size;
- ertm_info.user_tx_buf_size = p_chnl_cfg->user_tx_buf_size;
- ertm_info.fcr_rx_buf_size = p_chnl_cfg->fcr_rx_buf_size;
- ertm_info.fcr_tx_buf_size = p_chnl_cfg->fcr_tx_buf_size;
- p_ertm_info = &ertm_info;
- result = L2CAP_CONN_OK;
- } else {
- /* else we're not listening for traffic channel; reject
- * (this error code is specified by MCAP spec) */
- result = L2CAP_CONN_NO_RESOURCES;
- }
-
- /* Send L2CAP connect rsp */
- L2CA_ErtmConnectRsp(bd_addr, id, lcid, result, result, p_ertm_info);
-
- /* if result ok, proceed with connection */
- if (result == L2CAP_CONN_OK) {
- /* transition to configuration state */
- p_tbl->state = MCA_TC_ST_CFG;
-
- /* Send L2CAP config req */
- mca_set_cfg_by_tbl(&cfg, p_tbl);
- L2CA_ConfigReq(lcid, &cfg);
- }
-}
-
-/*******************************************************************************
- *
- * Function mca_l2c_connect_cfm_cback
- *
- * Description This is the L2CAP connect confirm callback function.
- *
- *
- * Returns void
- *
- ******************************************************************************/
-void mca_l2c_connect_cfm_cback(uint16_t lcid, uint16_t result) {
- tMCA_TC_TBL* p_tbl;
- tL2CAP_CFG_INFO cfg;
- tMCA_CCB* p_ccb;
-
- MCA_TRACE_DEBUG("mca_l2c_connect_cfm_cback lcid: x%x, result: %d", lcid,
- result);
- /* look up info for this channel */
- p_tbl = mca_tc_tbl_by_lcid(lcid);
- if (p_tbl != NULL) {
- MCA_TRACE_DEBUG("p_tbl state: %d, tcid: %d", p_tbl->state, p_tbl->tcid);
- /* if in correct state */
- if (p_tbl->state == MCA_TC_ST_CONN) {
- /* if result successful */
- if (result == L2CAP_CONN_OK) {
- if (p_tbl->tcid != 0) {
- /* set channel state */
- p_tbl->state = MCA_TC_ST_CFG;
-
- /* Send L2CAP config req */
- mca_set_cfg_by_tbl(&cfg, p_tbl);
- L2CA_ConfigReq(lcid, &cfg);
- } else {
- p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
- if (p_ccb == NULL) {
- result = L2CAP_CONN_NO_RESOURCES;
- } else {
- /* set channel state */
- p_tbl->state = MCA_TC_ST_SEC_INT;
- p_tbl->lcid = lcid;
- p_tbl->cfg_flags = MCA_L2C_CFG_CONN_INT;
-
- /* Check the security */
- btm_sec_mx_access_request(p_ccb->peer_addr, p_ccb->ctrl_vpsm, true,
- BTM_SEC_PROTO_MCA, p_tbl->tcid,
- &mca_sec_check_complete_orig, p_tbl);
- }
- }
- }
-
- /* failure; notify adaption that channel closed */
- if (result != L2CAP_CONN_OK) {
- p_tbl->cfg_flags |= MCA_L2C_CFG_DISCN_INT;
- mca_tc_close_ind(p_tbl, result);
- }
- }
- }
-}
-
-/*******************************************************************************
- *
- * Function mca_l2c_config_cfm_cback
- *
- * Description This is the L2CAP config confirm callback function.
- *
- *
- * Returns void
- *
- ******************************************************************************/
-void mca_l2c_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
- tMCA_TC_TBL* p_tbl;
-
- /* look up info for this channel */
- p_tbl = mca_tc_tbl_by_lcid(lcid);
- if (p_tbl != NULL) {
- /* if in correct state */
- if (p_tbl->state == MCA_TC_ST_CFG) {
- /* if result successful */
- if (p_cfg->result == L2CAP_CONN_OK) {
- /* update cfg_flags */
- p_tbl->cfg_flags |= MCA_L2C_CFG_CFM_DONE;
-
- /* if configuration complete */
- if (p_tbl->cfg_flags & MCA_L2C_CFG_IND_DONE) {
- mca_tc_open_ind(p_tbl);
- }
- }
- /* else failure */
- else {
- /* Send L2CAP disconnect req */
- L2CA_DisconnectReq(lcid);
- }
- }
- }
-}
-
-/*******************************************************************************
- *
- * Function mca_l2c_config_ind_cback
- *
- * Description This is the L2CAP config indication callback function.
- *
- *
- * Returns void
- *
- ******************************************************************************/
-void mca_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
- tMCA_TC_TBL* p_tbl;
- uint16_t result = L2CAP_CFG_OK;
-
- /* look up info for this channel */
- p_tbl = mca_tc_tbl_by_lcid(lcid);
- if (p_tbl != NULL) {
- /* store the mtu in tbl */
- if (p_cfg->mtu_present) {
- p_tbl->peer_mtu = p_cfg->mtu;
- if (p_tbl->peer_mtu < MCA_MIN_MTU) {
- result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
- }
- } else {
- p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
- }
- MCA_TRACE_DEBUG("peer_mtu: %d, lcid: x%x mtu_present:%d", p_tbl->peer_mtu,
- lcid, p_cfg->mtu_present);
-
- /* send L2CAP configure response */
- memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
- p_cfg->result = result;
- L2CA_ConfigRsp(lcid, p_cfg);
-
- /* if first config ind */
- if ((p_tbl->cfg_flags & MCA_L2C_CFG_IND_DONE) == 0) {
- /* update cfg_flags */
- p_tbl->cfg_flags |= MCA_L2C_CFG_IND_DONE;
-
- /* if configuration complete */
- if (p_tbl->cfg_flags & MCA_L2C_CFG_CFM_DONE) {
- mca_tc_open_ind(p_tbl);
- }
- }
- }
-}
-
-/*******************************************************************************
- *
- * Function mca_l2c_disconnect_ind_cback
- *
- * Description This is the L2CAP disconnect indication callback function.
- *
- *
- * Returns void
- *
- ******************************************************************************/
-void mca_l2c_disconnect_ind_cback(uint16_t lcid, bool ack_needed) {
- tMCA_TC_TBL* p_tbl;
- uint16_t reason = L2CAP_DISC_TIMEOUT;
-
- MCA_TRACE_DEBUG("mca_l2c_disconnect_ind_cback lcid: %d, ack_needed: %d", lcid,
- ack_needed);
- /* look up info for this channel */
- p_tbl = mca_tc_tbl_by_lcid(lcid);
- if (p_tbl != NULL) {
- if (ack_needed) {
- /* send L2CAP disconnect response */
- L2CA_DisconnectRsp(lcid);
- }
-
- p_tbl->cfg_flags = MCA_L2C_CFG_DISCN_ACP;
- if (ack_needed) reason = L2CAP_DISC_OK;
- mca_tc_close_ind(p_tbl, reason);
- }
-}
-
-/*******************************************************************************
- *
- * Function mca_l2c_disconnect_cfm_cback
- *
- * Description This is the L2CAP disconnect confirm callback function.
- *
- *
- * Returns void
- *
- ******************************************************************************/
-void mca_l2c_disconnect_cfm_cback(uint16_t lcid, uint16_t result) {
- tMCA_TC_TBL* p_tbl;
-
- MCA_TRACE_DEBUG("mca_l2c_disconnect_cfm_cback lcid: x%x, result: %d", lcid,
- result);
- /* look up info for this channel */
- p_tbl = mca_tc_tbl_by_lcid(lcid);
- if (p_tbl != NULL) {
- p_tbl->cfg_flags = MCA_L2C_CFG_DISCN_INT;
- mca_tc_close_ind(p_tbl, result);
- }
-}
-
-/*******************************************************************************
- *
- * Function mca_l2c_congestion_ind_cback
- *
- * Description This is the L2CAP congestion indication callback function.
- *
- *
- * Returns void
- *
- ******************************************************************************/
-void mca_l2c_congestion_ind_cback(uint16_t lcid, bool is_congested) {
- tMCA_TC_TBL* p_tbl;
-
- /* look up info for this channel */
- p_tbl = mca_tc_tbl_by_lcid(lcid);
- if (p_tbl != NULL) {
- mca_tc_cong_ind(p_tbl, is_congested);
- }
-}
-
-/*******************************************************************************
- *
- * Function mca_l2c_data_ind_cback
- *
- * Description This is the L2CAP data indication callback function.
- *
- *
- * Returns void
- *
- ******************************************************************************/
-void mca_l2c_data_ind_cback(uint16_t lcid, BT_HDR* p_buf) {
- tMCA_TC_TBL* p_tbl;
-
- /* look up info for this channel */
- p_tbl = mca_tc_tbl_by_lcid(lcid);
- if (p_tbl != NULL) {
- mca_tc_data_ind(p_tbl, p_buf);
- } else /* prevent buffer leak */
- osi_free(p_buf);
-}
-
-/*******************************************************************************
- *
- * Function mca_l2c_open_req
- *
- * Description This function calls L2CA_ConnectReq() to initiate a L2CAP
- * channel.
- *
- * Returns void.
- *
- ******************************************************************************/
-uint16_t mca_l2c_open_req(const RawAddress& bd_addr, uint16_t psm,
- const tMCA_CHNL_CFG* p_chnl_cfg) {
- tL2CAP_ERTM_INFO ertm_info;
-
- if (p_chnl_cfg) {
- ertm_info.preferred_mode = p_chnl_cfg->fcr_opt.mode;
- ertm_info.allowed_modes = (1 << p_chnl_cfg->fcr_opt.mode);
- ertm_info.user_rx_buf_size = p_chnl_cfg->user_rx_buf_size;
- ertm_info.user_tx_buf_size = p_chnl_cfg->user_tx_buf_size;
- ertm_info.fcr_rx_buf_size = p_chnl_cfg->fcr_rx_buf_size;
- ertm_info.fcr_tx_buf_size = p_chnl_cfg->fcr_tx_buf_size;
- } else {
- ertm_info.preferred_mode = mca_l2c_fcr_opts_def.mode;
- ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_ERTM;
- ertm_info.user_rx_buf_size = MCA_USER_RX_BUF_SIZE;
- ertm_info.user_tx_buf_size = MCA_USER_TX_BUF_SIZE;
- ertm_info.fcr_rx_buf_size = MCA_FCR_RX_BUF_SIZE;
- ertm_info.fcr_tx_buf_size = MCA_FCR_TX_BUF_SIZE;
- }
- return L2CA_ErtmConnectReq(psm, bd_addr, &ertm_info);
-}
diff --git a/stack/mcap/mca_main.cc b/stack/mcap/mca_main.cc
deleted file mode 100644
index 0185721..0000000
--- a/stack/mcap/mca_main.cc
+++ /dev/null
@@ -1,570 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2009-2012 Broadcom 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.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- * This is the implementation file for the MCAP Main Control Block and
- * Utility functions.
- *
- ******************************************************************************/
-#include <base/logging.h>
-#include <string.h>
-
-#include "bt_common.h"
-#include "bt_target.h"
-#include "l2c_api.h"
-#include "mca_api.h"
-#include "mca_defs.h"
-#include "mca_int.h"
-
-/* Main Control block for MCA */
-tMCA_CB mca_cb;
-
-/*****************************************************************************
- * constants
- ****************************************************************************/
-
-/* table of standard opcode message size */
-const uint8_t mca_std_msg_len[MCA_NUM_STANDARD_OPCODE] = {
- 4, /* MCA_OP_ERROR_RSP */
- 5, /* MCA_OP_MDL_CREATE_REQ */
- 5, /* MCA_OP_MDL_CREATE_RSP */
- 3, /* MCA_OP_MDL_RECONNECT_REQ */
- 4, /* MCA_OP_MDL_RECONNECT_RSP */
- 3, /* MCA_OP_MDL_ABORT_REQ */
- 4, /* MCA_OP_MDL_ABORT_RSP */
- 3, /* MCA_OP_MDL_DELETE_REQ */
- 4 /* MCA_OP_MDL_DELETE_RSP */
-};
-
-/*******************************************************************************
- *
- * Function mca_handle_by_cpsm
- *
- * Description This function returns the handle for the given control
- * channel PSM. 0, if not found.
- *
- * Returns the MCA handle.
- *
- ******************************************************************************/
-tMCA_HANDLE mca_handle_by_cpsm(uint16_t psm) {
- int i;
- tMCA_HANDLE handle = 0;
- tMCA_RCB* p_rcb = &mca_cb.rcb[0];
-
- for (i = 0; i < MCA_NUM_REGS; i++, p_rcb++) {
- if (p_rcb->p_cback && p_rcb->reg.ctrl_psm == psm) {
- handle = i + 1;
- break;
- }
- }
- return handle;
-}
-
-/*******************************************************************************
- *
- * Function mca_handle_by_dpsm
- *
- * Description This function returns the handle for the given data
- * channel PSM. 0, if not found.
- *
- * Returns the MCA handle.
- *
- ******************************************************************************/
-tMCA_HANDLE mca_handle_by_dpsm(uint16_t psm) {
- int i;
- tMCA_HANDLE handle = 0;
- tMCA_RCB* p_rcb = &mca_cb.rcb[0];
-
- for (i = 0; i < MCA_NUM_REGS; i++, p_rcb++) {
- if (p_rcb->p_cback && p_rcb->reg.data_psm == psm) {
- handle = i + 1;
- break;
- }
- }
- return handle;
-}
-
-/*******************************************************************************
- *
- * Function mca_tc_tbl_calloc
- *
- * Description This function allocates a transport table for the given
- * control channel.
- *
- * Returns The tranport table.
- *
- ******************************************************************************/
-tMCA_TC_TBL* mca_tc_tbl_calloc(tMCA_CCB* p_ccb) {
- tMCA_TC_TBL* p_tbl = mca_cb.tc.tc_tbl;
- int i;
-
- /* find next free entry in tc table */
- for (i = 0; i < MCA_NUM_TC_TBL; i++, p_tbl++) {
- if (p_tbl->state == MCA_TC_ST_UNUSED) {
- break;
- }
- }
-
- /* sanity check */
- CHECK(i != MCA_NUM_TC_TBL);
-
- /* initialize entry */
- p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
- p_tbl->cfg_flags = 0;
- p_tbl->cb_idx = mca_ccb_to_hdl(p_ccb);
- p_tbl->tcid = MCA_CTRL_TCID;
- p_tbl->my_mtu = MCA_CTRL_MTU;
- p_tbl->state = MCA_TC_ST_IDLE;
- p_tbl->lcid = p_ccb->lcid;
- mca_cb.tc.lcid_tbl[p_ccb->lcid - L2CAP_BASE_APPL_CID] = i;
-
- MCA_TRACE_DEBUG("%s() - cb_idx: %d", __func__, p_tbl->cb_idx);
- return p_tbl;
-}
-
-/*******************************************************************************
- *
- * Function mca_tc_tbl_dalloc
- *
- * Description This function allocates a transport table for the given
- * data channel.
- *
- * Returns The tranport table.
- *
- ******************************************************************************/
-tMCA_TC_TBL* mca_tc_tbl_dalloc(tMCA_DCB* p_dcb) {
- tMCA_TC_TBL* p_tbl = mca_cb.tc.tc_tbl;
- int i;
-
- /* find next free entry in tc table */
- for (i = 0; i < MCA_NUM_TC_TBL; i++, p_tbl++) {
- if (p_tbl->state == MCA_TC_ST_UNUSED) {
- break;
- }
- }
-
- /* sanity check */
- CHECK(i != MCA_NUM_TC_TBL);
-
- /* initialize entry */
- p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
- p_tbl->cfg_flags = 0;
- p_tbl->cb_idx = mca_dcb_to_hdl(p_dcb);
- p_tbl->tcid = p_dcb->p_cs->type + 1;
- p_tbl->my_mtu = p_dcb->p_chnl_cfg->data_mtu;
- p_tbl->state = MCA_TC_ST_IDLE;
- p_tbl->lcid = p_dcb->lcid;
- mca_cb.tc.lcid_tbl[p_dcb->lcid - L2CAP_BASE_APPL_CID] = i;
-
- MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx: %d", __func__, p_tbl->tcid,
- p_tbl->cb_idx);
- return p_tbl;
-}
-
-/*******************************************************************************
- *
- * Function mca_tc_tbl_by_lcid
- *
- * Description Find the transport channel table entry by LCID.
- *
- *
- * Returns The tranport table.
- *
- ******************************************************************************/
-tMCA_TC_TBL* mca_tc_tbl_by_lcid(uint16_t lcid) {
- uint8_t idx;
-
- if (lcid >= L2CAP_BASE_APPL_CID) {
- idx = mca_cb.tc.lcid_tbl[lcid - L2CAP_BASE_APPL_CID];
-
- if (idx < MCA_NUM_TC_TBL) {
- return &mca_cb.tc.tc_tbl[idx];
- }
- }
- return NULL;
-}
-
-/*******************************************************************************
- *
- * Function mca_free_tc_tbl_by_lcid
- *
- * Description Find the transport table entry by LCID
- * and free the tc_tbl
- *
- * Returns void.
- *
- ******************************************************************************/
-void mca_free_tc_tbl_by_lcid(uint16_t lcid) {
- uint8_t idx;
-
- if (lcid >= L2CAP_BASE_APPL_CID) {
- idx = mca_cb.tc.lcid_tbl[lcid - L2CAP_BASE_APPL_CID];
-
- if (idx < MCA_NUM_TC_TBL) {
- mca_cb.tc.tc_tbl[idx].state = MCA_TC_ST_UNUSED;
- }
- }
-}
-
-/*******************************************************************************
- *
- * Function mca_set_cfg_by_tbl
- *
- * Description Set the L2CAP configuration information
- *
- * Returns none.
- *
- ******************************************************************************/
-void mca_set_cfg_by_tbl(tL2CAP_CFG_INFO* p_cfg, tMCA_TC_TBL* p_tbl) {
- tMCA_DCB* p_dcb;
- const tL2CAP_FCR_OPTS* p_opt;
- tMCA_FCS_OPT fcs = MCA_FCS_NONE;
-
- if (p_tbl->tcid == MCA_CTRL_TCID) {
- p_opt = &mca_l2c_fcr_opts_def;
- } else {
- p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
- if (p_dcb) {
- p_opt = &p_dcb->p_chnl_cfg->fcr_opt;
- fcs = p_dcb->p_chnl_cfg->fcs;
- }
- }
- memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
- p_cfg->mtu_present = true;
- p_cfg->mtu = p_tbl->my_mtu;
- p_cfg->fcr_present = true;
- memcpy(&p_cfg->fcr, p_opt, sizeof(tL2CAP_FCR_OPTS));
- if (fcs & MCA_FCS_PRESNT_MASK) {
- p_cfg->fcs_present = true;
- p_cfg->fcs = (fcs & MCA_FCS_USE_MASK);
- }
-}
-
-/*******************************************************************************
- *
- * Function mca_tc_close_ind
- *
- * Description This function is called by the L2CAP interface when the
- * L2CAP channel is closed. It looks up the CCB or DCB for
- * the channel and sends it a close event. The reason
- * parameter is the same value passed by the L2CAP
- * callback function.
- *
- * Returns Nothing.
- *
- ******************************************************************************/
-void mca_tc_close_ind(tMCA_TC_TBL* p_tbl, uint16_t reason) {
- tMCA_CCB* p_ccb;
- tMCA_DCB* p_dcb;
-
- MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx:%d, old: %d", __func__, p_tbl->tcid,
- p_tbl->cb_idx, p_tbl->state);
-
- /* Check if the transport channel is in use */
- if (p_tbl->state == MCA_TC_ST_UNUSED) return;
-
- tMCA_CLOSE close;
-
- close.param = MCA_ACP;
- close.reason = reason;
- close.lcid = p_tbl->lcid;
-
- /* clear mca_tc_tbl entry */
- if (p_tbl->cfg_flags & MCA_L2C_CFG_DISCN_INT) close.param = MCA_INT;
- p_tbl->cfg_flags = 0;
- p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
-
- /* if control channel, notify ccb of the channel close */
- if (p_tbl->tcid == MCA_CTRL_TCID) {
- p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
- tMCA_CCB_EVT mca_ccb_evt;
- mca_ccb_evt.close = close;
- mca_ccb_event(p_ccb, MCA_CCB_LL_CLOSE_EVT, &mca_ccb_evt);
- } else {
- /* notify dcb of the channel close */
- p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
- if (p_dcb != NULL) {
- tMCA_DCB_EVT mca_dcb_evt;
- mca_dcb_evt.close = close;
- mca_dcb_event(p_dcb, MCA_DCB_TC_CLOSE_EVT, &mca_dcb_evt);
- }
- }
- p_tbl->state = MCA_TC_ST_UNUSED;
-}
-
-/*******************************************************************************
- *
- * Function mca_tc_open_ind
- *
- * Description This function is called by the L2CAP interface when
- * the L2CAP channel is opened. It looks up the CCB or DCB
- * for the channel and sends it an open event.
- *
- * Returns Nothing.
- *
- ******************************************************************************/
-void mca_tc_open_ind(tMCA_TC_TBL* p_tbl) {
- tMCA_CCB* p_ccb;
- tMCA_DCB* p_dcb;
- tMCA_OPEN open;
-
- MCA_TRACE_DEBUG("mca_tc_open_ind tcid: %d, cb_idx: %d", p_tbl->tcid,
- p_tbl->cb_idx);
- p_tbl->state = MCA_TC_ST_OPEN;
-
- open.peer_mtu = p_tbl->peer_mtu;
- open.lcid = p_tbl->lcid;
- /* use param to indicate the role of connection.
- * MCA_ACP, if ACP */
- open.param = MCA_INT;
- if (p_tbl->cfg_flags & MCA_L2C_CFG_CONN_ACP) {
- open.param = MCA_ACP;
- }
-
- /* if control channel, notify ccb that the channel is open */
- if (p_tbl->tcid == MCA_CTRL_TCID) {
- p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
- tMCA_CCB_EVT mca_ccb_evt;
- mca_ccb_evt.open = open;
- mca_ccb_event(p_ccb, MCA_CCB_LL_OPEN_EVT, &mca_ccb_evt);
- } else {
- /* must be data channel, notify dcb that the channel is open */
- p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
-
- /* put lcid in event data */
- if (p_dcb != NULL) {
- tMCA_DCB_EVT mca_dcb_evt;
- mca_dcb_evt.open = open;
- mca_dcb_event(p_dcb, MCA_DCB_TC_OPEN_EVT, &mca_dcb_evt);
- }
- }
-}
-
-/*******************************************************************************
- *
- * Function mca_tc_cong_ind
- *
- * Description This function is called by the L2CAP interface layer when
- * L2CAP calls the congestion callback. It looks up the CCB
- * or DCB for the channel and sends it a congestion event.
- * The is_congested parameter is the same value passed by
- * the L2CAP callback function.
- *
- *
- * Returns Nothing.
- *
- ******************************************************************************/
-void mca_tc_cong_ind(tMCA_TC_TBL* p_tbl, bool is_congested) {
- tMCA_CCB* p_ccb;
- tMCA_DCB* p_dcb;
-
- MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx: %d", __func__, p_tbl->tcid,
- p_tbl->cb_idx);
-
- /* if control channel, notify ccb of congestion */
- if (p_tbl->tcid == MCA_CTRL_TCID) {
- p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
- tMCA_CCB_EVT mca_ccb_evt;
- mca_ccb_evt.llcong = is_congested;
- mca_ccb_event(p_ccb, MCA_CCB_LL_CONG_EVT, &mca_ccb_evt);
- } else {
- /* notify dcb that channel open */
- p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
- if (p_dcb != NULL) {
- tMCA_DCB_EVT mca_dcb_evt;
- mca_dcb_evt.llcong = is_congested;
- mca_dcb_event(p_dcb, MCA_DCB_TC_CONG_EVT, &mca_dcb_evt);
- }
- }
-}
-
-/*******************************************************************************
- *
- * Function mca_tc_data_ind
- *
- * Description This function is called by the L2CAP interface layer when
- * incoming data is received from L2CAP. It looks up the CCB
- * or DCB for the channel and routes the data accordingly.
- *
- * Returns Nothing.
- *
- ******************************************************************************/
-void mca_tc_data_ind(tMCA_TC_TBL* p_tbl, BT_HDR* p_buf) {
- tMCA_CCB* p_ccb;
- tMCA_DCB* p_dcb;
- uint8_t event = MCA_CCB_MSG_RSP_EVT;
- uint8_t* p;
- uint8_t rej_rsp_code = MCA_RSP_SUCCESS;
-
- MCA_TRACE_DEBUG("%s: tcid: %d, cb_idx: %d", __func__, p_tbl->tcid,
- p_tbl->cb_idx);
-
- /* if control channel, handle control message */
- if (p_tbl->tcid == MCA_CTRL_TCID) {
- p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
- if (p_ccb) {
- p = (uint8_t*)(p_buf + 1) + p_buf->offset;
- /* all the request opcode has bit 0 set. response code has bit 0 clear */
- if ((*p) & 0x01) event = MCA_CCB_MSG_REQ_EVT;
-
- if (*p < MCA_NUM_STANDARD_OPCODE) {
- if (p_buf->len != mca_std_msg_len[*p]) {
- MCA_TRACE_ERROR("%s: opcode 0x%02x required len: %d, got len: %d",
- __func__, *p, mca_std_msg_len[*p], p_buf->len);
- rej_rsp_code = MCA_RSP_BAD_PARAM;
- }
- } else if ((*p >= MCA_FIRST_SYNC_OP) && (*p <= MCA_LAST_SYNC_OP)) {
- MCA_TRACE_ERROR("%s: unsupported SYNC opcode: 0x%02x len:%d", __func__,
- *p, p_buf->len);
- /* reject unsupported request */
- rej_rsp_code = MCA_RSP_NO_SUPPORT;
- } else {
- MCA_TRACE_ERROR("%s: bad opcode: 0x%02x len:%d", __func__, *p,
- p_buf->len);
- /* reject unsupported request */
- rej_rsp_code = MCA_RSP_BAD_OPCODE;
- }
-
- p_buf->layer_specific = rej_rsp_code;
- /* forward the request/response to state machine */
- mca_ccb_event(p_ccb, event, (tMCA_CCB_EVT*)p_buf);
- } else {
- osi_free(p_buf);
- }
- } else {
- /* send event to dcb */
- p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
- if (p_dcb != NULL) {
- mca_dcb_event(p_dcb, MCA_DCB_TC_DATA_EVT, (tMCA_DCB_EVT*)p_buf);
- } else {
- osi_free(p_buf);
- }
- }
-}
-
-/*******************************************************************************
- *
- * Function mca_rcb_alloc
- *
- * Description This function allocates a registration control block.
- * If no free RCB is available, it returns NULL.
- *
- * Returns tMCA_RCB *
- *
- ******************************************************************************/
-tMCA_RCB* mca_rcb_alloc(tMCA_REG* p_reg) {
- int i;
- tMCA_RCB* p_rcb = NULL;
-
- for (i = 0; i < MCA_NUM_REGS; i++) {
- if (mca_cb.rcb[i].p_cback == NULL) {
- p_rcb = &mca_cb.rcb[i];
- memcpy(&p_rcb->reg, p_reg, sizeof(tMCA_REG));
- break;
- }
- }
- return p_rcb;
-}
-
-/*******************************************************************************
- *
- * Function mca_rcb_dealloc
- *
- * Description This function deallocates the RCB with the given handle.
- *
- * Returns void.
- *
- ******************************************************************************/
-void mca_rcb_dealloc(tMCA_HANDLE handle) {
- int i;
- bool done = true;
- tMCA_RCB* p_rcb;
- tMCA_CCB* p_ccb;
-
- if (handle && (handle <= MCA_NUM_REGS)) {
- handle--;
- p_rcb = &mca_cb.rcb[handle];
- if (p_rcb->p_cback) {
- p_ccb = &mca_cb.ccb[handle * MCA_NUM_LINKS];
- /* check if all associated CCB are disconnected */
- for (i = 0; i < MCA_NUM_LINKS; i++, p_ccb++) {
- if (p_ccb->p_rcb) {
- done = false;
- mca_ccb_event(p_ccb, MCA_CCB_API_DISCONNECT_EVT, NULL);
- }
- }
-
- if (done) {
- memset(p_rcb, 0, sizeof(tMCA_RCB));
- MCA_TRACE_DEBUG("%s() - reset MCA_RCB index=%d", __func__, handle);
- }
- }
- }
-}
-
-/*******************************************************************************
- *
- * Function mca_rcb_to_handle
- *
- * Description This function converts a pointer to an RCB to
- * a handle (tMCA_HANDLE). It returns the handle.
- *
- * Returns void.
- *
- ******************************************************************************/
-tMCA_HANDLE mca_rcb_to_handle(tMCA_RCB* p_rcb) {
- return (uint8_t)(p_rcb - mca_cb.rcb + 1);
-}
-
-/*******************************************************************************
- *
- * Function mca_rcb_by_handle
- *
- * Description This function finds the RCB for a handle (tMCA_HANDLE).
- * It returns a pointer to the RCB. If no RCB matches the
- * handle it returns NULL.
- *
- * Returns tMCA_RCB *
- *
- ******************************************************************************/
-tMCA_RCB* mca_rcb_by_handle(tMCA_HANDLE handle) {
- tMCA_RCB* p_rcb = NULL;
-
- if (handle && (handle <= MCA_NUM_REGS) && mca_cb.rcb[handle - 1].p_cback) {
- p_rcb = &mca_cb.rcb[handle - 1];
- }
- return p_rcb;
-}
-
-/*******************************************************************************
- *
- * Function mca_is_valid_dep_id
- *
- * Description This function checks if the given dep_id is valid.
- *
- * Returns true, if this is a valid local dep_id
- *
- ******************************************************************************/
-bool mca_is_valid_dep_id(tMCA_RCB* p_rcb, tMCA_DEP dep) {
- bool valid = false;
- if (dep < MCA_NUM_DEPS && p_rcb->dep[dep].p_data_cback) {
- valid = true;
- }
- return valid;
-}
diff --git a/stack/rfcomm/port_api.cc b/stack/rfcomm/port_api.cc
index 1ae8667..0bb817d 100644
--- a/stack/rfcomm/port_api.cc
+++ b/stack/rfcomm/port_api.cc
@@ -118,7 +118,7 @@
*p_handle = 0;
if ((scn == 0) || (scn >= PORT_MAX_RFC_PORTS)) {
- /* Server Channel Number(SCN) should be in range 1...30 */
+ // Server Channel Number (SCN) should be in range [1, 30]
LOG(ERROR) << __func__ << ": Invalid SCN, bd_addr=" << bd_addr
<< ", scn=" << static_cast<int>(scn)
<< ", is_server=" << is_server
@@ -127,8 +127,8 @@
return (PORT_INVALID_SCN);
}
- /* For client that originate connection on the existing none initiator */
- /* multiplexer channel DLCI should be odd */
+ // For client that originates connection on the existing none initiator
+ // multiplexer channel, DLCI should be odd.
uint8_t dlci;
tRFC_MCB* p_mcb = port_find_mcb(bd_addr);
if (p_mcb && !p_mcb->is_initiator && !is_server) {
@@ -137,13 +137,13 @@
dlci = (scn << 1);
}
- /* For the server side always allocate a new port. On the client side */
- /* do not allow the same (dlci, bd_addr) to be opened twice by application */
+ // On the client side, do not allow the same (dlci, bd_addr) to be opened
+ // twice by application
tPORT* p_port;
if (!is_server) {
p_port = port_find_port(dlci, bd_addr);
if (p_port != nullptr) {
- /* if existing port is also a client port */
+ // if existing port is also a client port, error out
if (!p_port->is_server) {
LOG(ERROR) << __func__ << ": already at opened state "
<< static_cast<int>(p_port->state)
@@ -153,22 +153,26 @@
<< ", bd_addr=" << bd_addr << ", scn=" << std::to_string(scn)
<< ", is_server=" << is_server << ", mtu=" << mtu
<< ", uuid=" << loghex(uuid) << ", dlci=" << +dlci
- << ", p_mcb=" << p_mcb << ", port=" << +p_port->inx;
- *p_handle = p_port->inx;
+ << ", p_mcb=" << p_mcb
+ << ", port=" << std::to_string(p_port->handle);
+ *p_handle = p_port->handle;
return (PORT_ALREADY_OPENED);
}
}
}
+ // On the server side, always allocate a new port.
p_port = port_allocate_port(dlci, bd_addr);
if (p_port == nullptr) {
LOG(ERROR) << __func__ << ": no resources, bd_addr=" << bd_addr
<< ", scn=" << std::to_string(scn) << ", is_server=" << is_server
<< ", mtu=" << mtu << ", uuid=" << loghex(uuid)
<< ", dlci=" << +dlci;
- return (PORT_NO_RESOURCES);
+ return PORT_NO_RESOURCES;
}
+ *p_handle = p_port->handle;
+ // Get default signal state
switch (uuid) {
case UUID_PROTOCOL_OBEX:
p_port->default_signal_state = PORT_OBEX_DEFAULT_SIGNAL_STATE;
@@ -189,42 +193,35 @@
break;
}
- *p_handle = p_port->inx;
-
+ // Assign port specific values
p_port->state = PORT_STATE_OPENING;
p_port->uuid = uuid;
p_port->is_server = is_server;
p_port->scn = scn;
p_port->ev_mask = 0;
- /* If the MTU is not specified (0), keep MTU decision until the
- * PN frame has to be send
- * at that time connection should be established and we
- * will know for sure our prefered MTU
- */
-
+ // Find MTU
+ // If the MTU is not specified (0), keep MTU decision until the PN frame has
+ // to be send at that time connection should be established and we will know
+ // for sure our prefered MTU
uint16_t rfcomm_mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD;
-
if (mtu) {
p_port->mtu = (mtu < rfcomm_mtu) ? mtu : rfcomm_mtu;
} else {
p_port->mtu = rfcomm_mtu;
}
- /* server doesn't need to release port when closing */
+ // Other states
+ // server doesn't need to release port when closing
if (is_server) {
p_port->keep_port_handle = true;
-
- /* keep mtu that user asked, p_port->mtu could be updated during param
- * negotiation */
+ // keep mtu that user asked, p_port->mtu could be updated during param
+ // negotiation
p_port->keep_mtu = p_port->mtu;
}
-
p_port->local_ctrl.modem_signal = p_port->default_signal_state;
p_port->local_ctrl.fc = false;
-
p_port->p_mgmt_callback = p_mgmt_cb;
-
p_port->bd_addr = bd_addr;
LOG(INFO) << __func__ << ": bd_addr=" << bd_addr
@@ -234,12 +231,12 @@
<< ", signal_state=" << loghex(p_port->default_signal_state)
<< ", p_port=" << p_port;
- /* If this is not initiator of the connection need to just wait */
+ // If this is not initiator of the connection need to just wait
if (p_port->is_server) {
return (PORT_SUCCESS);
}
- /* Open will be continued after security checks are passed */
+ // Open will be continued after security checks are passed
return port_open_continue(p_port);
}
@@ -286,24 +283,21 @@
*
******************************************************************************/
int RFCOMM_RemoveServer(uint16_t handle) {
- tPORT* p_port;
-
- RFCOMM_TRACE_API("RFCOMM_RemoveServer() handle:%d", handle);
-
/* Check if handle is valid to avoid crashing */
if ((handle == 0) || (handle > MAX_RFC_PORTS)) {
- RFCOMM_TRACE_ERROR("RFCOMM_RemoveServer() BAD handle:%d", handle);
+ LOG(ERROR) << __func__ << ": bad handle " << handle;
return (PORT_BAD_HANDLE);
}
- p_port = &rfc_cb.port.port[handle - 1];
+ tPORT* p_port = &rfc_cb.port.port[handle - 1];
/* Do not report any events to the client any more. */
- p_port->p_mgmt_callback = NULL;
+ p_port->p_mgmt_callback = nullptr;
if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
- RFCOMM_TRACE_EVENT("RFCOMM_RemoveServer() Not opened:%d", handle);
+ VLOG(1) << __func__ << ": handle " << handle << " not opened";
return (PORT_SUCCESS);
}
+ LOG(INFO) << __func__ << ": handle=" << handle;
/* this port will be deallocated after closing */
p_port->keep_port_handle = false;
@@ -486,18 +480,19 @@
* p_lcid - OUT L2CAP's LCID
*
******************************************************************************/
-int PORT_CheckConnection(uint16_t handle, RawAddress& bd_addr,
+int PORT_CheckConnection(uint16_t handle, RawAddress* bd_addr,
uint16_t* p_lcid) {
- tPORT* p_port;
-
- RFCOMM_TRACE_API("PORT_CheckConnection() handle:%d", handle);
-
/* Check if handle is valid to avoid crashing */
if ((handle == 0) || (handle > MAX_RFC_PORTS)) {
return (PORT_BAD_HANDLE);
}
-
- p_port = &rfc_cb.port.port[handle - 1];
+ tPORT* p_port = &rfc_cb.port.port[handle - 1];
+ RFCOMM_TRACE_DEBUG(
+ "%s: handle=%d, in_use=%d, port_state=%d, p_mcb=%p, peer_ready=%d, "
+ "rfc_state=%d",
+ __func__, handle, p_port->in_use, p_port->state, p_port->rfc.p_mcb,
+ (p_port->rfc.p_mcb ? p_port->rfc.p_mcb->peer_ready : -1),
+ p_port->rfc.state);
if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
return (PORT_NOT_OPENED);
@@ -508,7 +503,7 @@
return (PORT_LINE_ERR);
}
- bd_addr = p_port->rfc.p_mcb->bd_addr;
+ *bd_addr = p_port->rfc.p_mcb->bd_addr;
if (p_lcid) *p_lcid = p_port->rfc.p_mcb->lcid;
return (PORT_SUCCESS);
@@ -525,28 +520,23 @@
* bd_addr - bd_addr of the peer
*
******************************************************************************/
-bool PORT_IsOpening(RawAddress& bd_addr) {
- uint8_t xx, yy;
- tRFC_MCB* p_mcb = NULL;
- tPORT* p_port;
- bool found_port;
-
+bool PORT_IsOpening(RawAddress* bd_addr) {
/* Check for any rfc_mcb which is in the middle of opening. */
- for (xx = 0; xx < MAX_BD_CONNECTIONS; xx++) {
- if ((rfc_cb.port.rfc_mcb[xx].state > RFC_MX_STATE_IDLE) &&
- (rfc_cb.port.rfc_mcb[xx].state < RFC_MX_STATE_CONNECTED)) {
- bd_addr = rfc_cb.port.rfc_mcb[xx].bd_addr;
+ for (auto& multiplexer_cb : rfc_cb.port.rfc_mcb) {
+ if ((multiplexer_cb.state > RFC_MX_STATE_IDLE) &&
+ (multiplexer_cb.state < RFC_MX_STATE_CONNECTED)) {
+ *bd_addr = multiplexer_cb.bd_addr;
return true;
}
- if (rfc_cb.port.rfc_mcb[xx].state == RFC_MX_STATE_CONNECTED) {
- found_port = false;
- p_mcb = &rfc_cb.port.rfc_mcb[xx];
- p_port = &rfc_cb.port.port[0];
+ if (multiplexer_cb.state == RFC_MX_STATE_CONNECTED) {
+ bool found_port = false;
+ tPORT* p_port = nullptr;
- for (yy = 0; yy < MAX_RFC_PORTS; yy++, p_port++) {
- if (p_port->rfc.p_mcb == p_mcb) {
+ for (tPORT& port : rfc_cb.port.port) {
+ if (port.rfc.p_mcb == &multiplexer_cb) {
found_port = true;
+ p_port = &port;
break;
}
}
@@ -554,7 +544,7 @@
if ((!found_port) ||
(found_port && (p_port->rfc.state < RFC_STATE_OPENED))) {
/* Port is not established yet. */
- bd_addr = rfc_cb.port.rfc_mcb[xx].bd_addr;
+ *bd_addr = multiplexer_cb.bd_addr;
return true;
}
}
@@ -827,7 +817,7 @@
events &= p_port->ev_mask;
if (p_port->p_callback && events) {
- p_port->p_callback(events, p_port->inx);
+ p_port->p_callback(events, p_port->handle);
}
}
return (PORT_SUCCESS);
@@ -894,7 +884,7 @@
events &= p_port->ev_mask;
if (p_port->p_callback && events) {
- p_port->p_callback(events, p_port->inx);
+ p_port->p_callback(events, p_port->handle);
}
}
return (PORT_SUCCESS);
@@ -1118,7 +1108,7 @@
events &= p_port->ev_mask;
if ((p_port->p_callback != NULL) && events)
- (p_port->p_callback)(events, p_port->inx);
+ (p_port->p_callback)(events, p_port->handle);
}
return (PORT_SUCCESS);
@@ -1306,7 +1296,7 @@
osi_free(p_buf);
if ((p_port->p_callback != NULL) && (p_port->ev_mask & PORT_EV_ERR))
- p_port->p_callback(PORT_EV_ERR, p_port->inx);
+ p_port->p_callback(PORT_EV_ERR, p_port->handle);
return (PORT_TX_FULL);
}
@@ -1384,7 +1374,7 @@
event &= p_port->ev_mask;
/* Send event to the application */
- if (p_port->p_callback && event) (p_port->p_callback)(event, p_port->inx);
+ if (p_port->p_callback && event) (p_port->p_callback)(event, p_port->handle);
return (PORT_SUCCESS);
}
@@ -1539,7 +1529,7 @@
event &= p_port->ev_mask;
/* Send event to the application */
- if (p_port->p_callback && event) (p_port->p_callback)(event, p_port->inx);
+ if (p_port->p_callback && event) (p_port->p_callback)(event, p_port->handle);
return (PORT_SUCCESS);
}
@@ -1650,7 +1640,7 @@
event &= p_port->ev_mask;
/* Send event to the application */
- if (p_port->p_callback && event) (p_port->p_callback)(event, p_port->inx);
+ if (p_port->p_callback && event) (p_port->p_callback)(event, p_port->handle);
return (PORT_SUCCESS);
}
diff --git a/stack/rfcomm/port_int.h b/stack/rfcomm/port_int.h
index db7d0fd..ecd8fbc 100644
--- a/stack/rfcomm/port_int.h
+++ b/stack/rfcomm/port_int.h
@@ -90,8 +90,8 @@
typedef struct {
alarm_t* mcb_timer; /* MCB timer */
fixed_queue_t* cmd_q; /* Queue for command messages on this mux */
- uint8_t port_inx[RFCOMM_MAX_DLCI + 1]; /* Array for quick access to */
- /* tPORT based on dlci */
+ uint8_t port_handles[RFCOMM_MAX_DLCI + 1]; /* Array for quick access to */
+ /* port handles based on dlci */
RawAddress bd_addr; /* BD ADDR of the peer if initiator */
uint16_t lcid; /* Local cid used for this channel */
uint16_t peer_l2cap_mtu; /* Max frame that can be sent to peer L2CAP */
@@ -139,7 +139,7 @@
* Define control block containing information about PORT connection
*/
typedef struct {
- uint8_t inx; /* Index of this control block in the port_info array */
+ uint8_t handle; // Starting from 1, unique for this object
bool in_use; /* True when structure is allocated */
#define PORT_STATE_CLOSED 0
diff --git a/stack/rfcomm/port_rfc.cc b/stack/rfcomm/port_rfc.cc
index 5ec5631..3228f64 100644
--- a/stack/rfcomm/port_rfc.cc
+++ b/stack/rfcomm/port_rfc.cc
@@ -56,13 +56,11 @@
*
******************************************************************************/
int port_open_continue(tPORT* p_port) {
- tRFC_MCB* p_mcb;
-
RFCOMM_TRACE_EVENT("port_open_continue, p_port:%p", p_port);
/* Check if multiplexer channel has already been established */
- p_mcb = rfc_alloc_multiplexer_channel(p_port->bd_addr, true);
- if (p_mcb == NULL) {
+ tRFC_MCB* p_mcb = rfc_alloc_multiplexer_channel(p_port->bd_addr, true);
+ if (p_mcb == nullptr) {
RFCOMM_TRACE_WARNING("port_open_continue no mx channel");
port_release_port(p_port);
return (PORT_NO_RESOURCES);
@@ -70,24 +68,22 @@
p_port->rfc.p_mcb = p_mcb;
- p_mcb->port_inx[p_port->dlci] = p_port->inx;
+ p_mcb->port_handles[p_port->dlci] = p_port->handle;
/* Connection is up and we know local and remote features, select MTU */
port_select_mtu(p_port);
if (p_mcb->state == RFC_MX_STATE_CONNECTED) {
- RFCOMM_ParNegReq(p_mcb, p_port->dlci, p_port->mtu);
+ RFCOMM_ParameterNegotiationRequest(p_mcb, p_port->dlci, p_port->mtu);
} else if ((p_mcb->state == RFC_MX_STATE_IDLE) ||
(p_mcb->state == RFC_MX_STATE_DISC_WAIT_UA)) {
- /* In RFC_MX_STATE_IDLE state, MX state machine will create connection */
- /* In RFC_MX_STATE_DISC_WAIT_UA state, MX state machine will recreate
- * connection */
- /* after disconnecting is completed */
+ // In RFC_MX_STATE_IDLE state, MX state machine will create connection
+ // In RFC_MX_STATE_DISC_WAIT_UA state, MX state machine will recreate
+ // connection after disconnecting is completed
RFCOMM_StartReq(p_mcb);
} else {
- /* MX state machine ignores RFC_MX_EVENT_START_REQ in these states */
- /* When it enters RFC_MX_STATE_CONNECTED, it will check any openning ports
- */
+ // MX state machine ignores RFC_MX_EVENT_START_REQ in these states
+ // When it enters RFC_MX_STATE_CONNECTED, it will check any openning ports
RFCOMM_TRACE_DEBUG(
"port_open_continue: mx state(%d) mx channel is openning",
p_mcb->state);
@@ -128,7 +124,8 @@
if (p_mcb == NULL) return;
- RFCOMM_PortNegReq(p_mcb, p_port->dlci, &p_port->user_port_pars);
+ RFCOMM_PortParameterNegotiationRequest(p_mcb, p_port->dlci,
+ &p_port->user_port_pars);
}
/*******************************************************************************
@@ -162,14 +159,14 @@
if (p_port->ev_mask & PORT_EV_ERR) events |= PORT_EV_ERR;
if ((p_port->p_callback != NULL) && events)
- p_port->p_callback(events, p_port->inx);
+ p_port->p_callback(events, p_port->handle);
/* Check if RFCOMM side has been closed while the message was queued */
if ((p_mcb == NULL) || (p_port->rfc.state == RFC_STATE_CLOSED)) {
/* Call management callback function before calling port_release_port() to
* clear tPort */
if (p_port->p_mgmt_callback)
- p_port->p_mgmt_callback(PORT_CLOSED, p_port->inx);
+ p_port->p_mgmt_callback(PORT_CLOSED, p_port->handle);
port_release_port(p_port);
} else {
@@ -188,37 +185,39 @@
*
******************************************************************************/
void PORT_StartCnf(tRFC_MCB* p_mcb, uint16_t result) {
- tPORT* p_port;
- int i;
bool no_ports_up = true;
- RFCOMM_TRACE_EVENT("PORT_StartCnf result:%d", result);
+ RFCOMM_TRACE_EVENT("%s: result %d", __func__, result);
- p_port = &rfc_cb.port.port[0];
- for (i = 0; i < MAX_RFC_PORTS; i++, p_port++) {
+ tPORT* p_port = &rfc_cb.port.port[0];
+ for (int i = 0; i < MAX_RFC_PORTS; i++, p_port++) {
if (p_port->rfc.p_mcb == p_mcb) {
no_ports_up = false;
- if (result == RFCOMM_SUCCESS)
- RFCOMM_ParNegReq(p_mcb, p_port->dlci, p_port->mtu);
- else {
- RFCOMM_TRACE_WARNING("PORT_StartCnf failed result:%d", result);
+ if (result == RFCOMM_SUCCESS) {
+ RFCOMM_TRACE_EVENT("%s: dlci %d", __func__, p_port->dlci);
+ RFCOMM_ParameterNegotiationRequest(p_mcb, p_port->dlci, p_port->mtu);
+ } else {
+ RFCOMM_TRACE_WARNING("%s: failed result:%d", __func__, result);
/* Warning: result is also set to 4 when l2cap connection
fails due to l2cap connect cnf (no_resources) */
- if (result == HCI_ERR_PAGE_TIMEOUT)
+ if (result == HCI_ERR_PAGE_TIMEOUT) {
p_port->error = PORT_PAGE_TIMEOUT;
- else
+ } else {
p_port->error = PORT_START_FAILED;
+ }
rfc_release_multiplexer_channel(p_mcb);
/* Send event to the application */
- if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECT_ERR))
- (p_port->p_callback)(PORT_EV_CONNECT_ERR, p_port->inx);
+ if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECT_ERR)) {
+ (p_port->p_callback)(PORT_EV_CONNECT_ERR, p_port->handle);
+ }
- if (p_port->p_mgmt_callback)
- p_port->p_mgmt_callback(PORT_START_FAILED, p_port->inx);
+ if (p_port->p_mgmt_callback) {
+ p_port->p_mgmt_callback(PORT_START_FAILED, p_port->handle);
+ }
port_release_port(p_port);
}
@@ -272,12 +271,9 @@
******************************************************************************/
void PORT_ParNegInd(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu, uint8_t cl,
uint8_t k) {
+ RFCOMM_TRACE_EVENT("%s: bd_addr=%s, dlci=%d, mtu=%d", __func__,
+ p_mcb->bd_addr.ToString().c_str(), dlci, mtu);
tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
- uint8_t our_cl;
- uint8_t our_k;
-
- RFCOMM_TRACE_EVENT("PORT_ParNegInd dlci:%d mtu:%d", dlci, mtu);
-
if (!p_port) {
/* This can be a first request for this port */
p_port = port_find_dlci_port(dlci);
@@ -292,9 +288,9 @@
rfc_check_mcb_active(p_mcb);
return;
}
- RFCOMM_TRACE_EVENT("%s: port_inx[dlci:%d]:%d->%d", __func__, dlci,
- p_mcb->port_inx[dlci], p_port->inx);
- p_mcb->port_inx[dlci] = p_port->inx;
+ RFCOMM_TRACE_EVENT("%s: port_handles[dlci:%d]:%d->%d", __func__, dlci,
+ p_mcb->port_handles[dlci], p_port->handle);
+ p_mcb->port_handles[dlci] = p_port->handle;
}
p_port->bd_addr = p_mcb->bd_addr;
@@ -329,6 +325,8 @@
/* after the DLCI is already established-- the PN in that case must have cl =
* 0. */
/* See RFCOMM spec 5.5.3 */
+ uint8_t our_cl;
+ uint8_t our_k;
if (cl == RFCOMM_PN_CONV_LAYER_TYPE_1) {
our_cl = RFCOMM_PN_CONV_LAYER_TYPE_1;
our_k = 0;
@@ -346,7 +344,7 @@
our_cl = RFCOMM_PN_CONV_LAYER_TYPE_1;
our_k = 0;
}
- RFCOMM_ParNegRsp(p_mcb, dlci, p_port->mtu, our_cl, our_k);
+ RFCOMM_ParameterNegotiationResponse(p_mcb, dlci, p_port->mtu, our_cl, our_k);
}
/*******************************************************************************
@@ -362,12 +360,13 @@
******************************************************************************/
void PORT_ParNegCnf(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu, uint8_t cl,
uint8_t k) {
- tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
-
RFCOMM_TRACE_EVENT("PORT_ParNegCnf dlci:%d mtu:%d cl: %d k: %d", dlci, mtu,
cl, k);
-
- if (!p_port) return;
+ tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+ if (!p_port) {
+ LOG(WARNING) << __func__ << ": port is null for " << p_mcb->bd_addr;
+ return;
+ }
/* Flow control mechanism not set yet. Negotiate flow control mechanism. */
if (p_mcb->flow == PORT_FC_UNDEFINED) {
@@ -377,19 +376,17 @@
if ((PORT_FC_DEFAULT == PORT_FC_TS710) &&
(cl == RFCOMM_PN_CONV_LAYER_CBFC_R)) {
RFCOMM_TRACE_WARNING("%s, negotiation fails, index=%d", __func__,
- p_port->inx);
+ p_port->handle);
rfc_send_disc(p_mcb, p_port->dlci);
rfc_port_closed(p_port);
return;
- }
- /* Our stack is configured for credit-based and they responded with
- credit-based. */
- else if (cl == RFCOMM_PN_CONV_LAYER_CBFC_R) {
+ } else if (cl == RFCOMM_PN_CONV_LAYER_CBFC_R) {
+ // Our stack is configured for credit-based and they responded with
+ // credit-based.
p_mcb->flow = PORT_FC_CREDIT;
- }
- /* They responded with any other value. Treat this as negotiation to
- TS07.10. */
- else {
+ } else {
+ // They responded with any other value. Treat this as negotiation to
+ // TS07.10.
p_mcb->flow = PORT_FC_TS710;
}
}
@@ -436,7 +433,7 @@
RFCOMM_DlcEstablishRsp(p_mcb, dlci, 0, RFCOMM_ERROR);
return;
}
- p_mcb->port_inx[dlci] = p_port->inx;
+ p_mcb->port_handles[dlci] = p_port->handle;
}
/* If L2CAP's mtu less then RFCOMM's take it */
@@ -450,10 +447,10 @@
/* This is the server side. If application wants to know when connection */
/* is established, thats the place */
if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECTED))
- (p_port->p_callback)(PORT_EV_CONNECTED, p_port->inx);
+ (p_port->p_callback)(PORT_EV_CONNECTED, p_port->handle);
if (p_port->p_mgmt_callback)
- p_port->p_mgmt_callback(PORT_SUCCESS, p_port->inx);
+ p_port->p_mgmt_callback(PORT_SUCCESS, p_port->handle);
p_port->state = PORT_STATE_OPENED;
}
@@ -490,10 +487,10 @@
rfc_timer_stop(p_mcb);
if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECTED))
- (p_port->p_callback)(PORT_EV_CONNECTED, p_port->inx);
+ (p_port->p_callback)(PORT_EV_CONNECTED, p_port->handle);
if (p_port->p_mgmt_callback)
- p_port->p_mgmt_callback(PORT_SUCCESS, p_port->inx);
+ p_port->p_mgmt_callback(PORT_SUCCESS, p_port->handle);
p_port->state = PORT_STATE_OPENED;
@@ -501,7 +498,8 @@
*/
if ((p_port->uuid == UUID_SERVCLASS_DIALUP_NETWORKING) ||
(p_port->uuid == UUID_SERVCLASS_FAX))
- RFCOMM_PortNegReq(p_port->rfc.p_mcb, p_port->dlci, NULL);
+ RFCOMM_PortParameterNegotiationRequest(p_port->rfc.p_mcb, p_port->dlci,
+ NULL);
else
RFCOMM_ControlReq(p_port->rfc.p_mcb, p_port->dlci, &p_port->local_ctrl);
}
@@ -527,15 +525,15 @@
/* This can be a first request for this port */
p_port = port_find_dlci_port(dlci);
if (!p_port) {
- RFCOMM_PortNegRsp(p_mcb, dlci, p_pars, 0);
+ RFCOMM_PortParameterNegotiationResponse(p_mcb, dlci, p_pars, 0);
return;
}
- p_mcb->port_inx[dlci] = p_port->inx;
+ p_mcb->port_handles[dlci] = p_port->handle;
}
/* Check if the flow control is acceptable on local side */
p_port->peer_port_pars = *p_pars;
- RFCOMM_PortNegRsp(p_mcb, dlci, p_pars, param_mask);
+ RFCOMM_PortParameterNegotiationResponse(p_mcb, dlci, p_pars, param_mask);
}
/*******************************************************************************
@@ -596,9 +594,9 @@
p_port->peer_ctrl = *p_pars;
- if (!(p_port->port_ctrl & PORT_CTRL_REQ_SENT))
+ if (!(p_port->port_ctrl & PORT_CTRL_REQ_SENT)) {
RFCOMM_ControlReq(p_port->rfc.p_mcb, p_port->dlci, &p_port->local_ctrl);
- else {
+ } else {
/* If this is the first time we received control RFCOMM is connected */
if (!(p_port->port_ctrl & PORT_CTRL_IND_RECEIVED)) {
event |= (PORT_EV_CONNECTED & p_port->ev_mask);
@@ -615,7 +613,7 @@
/* execute call back function only if the application is registered for events
*/
- if (event && p_port->p_callback) (p_port->p_callback)(event, p_port->inx);
+ if (event && p_port->p_callback) (p_port->p_callback)(event, p_port->handle);
RFCOMM_TRACE_EVENT(
"PORT_ControlInd DTR_DSR : %d, RTS_CTS : %d, RI : %d, DCD : %d",
@@ -655,7 +653,7 @@
/* execute call back function only if the application is registered for events
*/
- if (event && p_port->p_callback) (p_port->p_callback)(event, p_port->inx);
+ if (event && p_port->p_callback) (p_port->p_callback)(event, p_port->handle);
}
/*******************************************************************************
@@ -683,7 +681,7 @@
if (line_status & ~(PORT_ERR_OVERRUN | PORT_ERR_BREAK)) event |= PORT_EV_ERR;
if ((p_port->p_callback != NULL) && (p_port->ev_mask & event))
- p_port->p_callback((p_port->ev_mask & event), p_port->inx);
+ p_port->p_callback((p_port->ev_mask & event), p_port->handle);
}
/*******************************************************************************
@@ -695,12 +693,10 @@
*
******************************************************************************/
void PORT_DlcReleaseInd(tRFC_MCB* p_mcb, uint8_t dlci) {
+ VLOG(1) << __func__ << ": dlci=" << std::to_string(dlci)
+ << ", bd_addr=" << p_mcb->bd_addr;
tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
-
- RFCOMM_TRACE_EVENT("PORT_DlcReleaseInd");
-
if (!p_port) return;
-
port_rfc_closed(p_port, PORT_CLOSED);
}
@@ -775,7 +771,7 @@
* receive data */
if (p_port->p_data_co_callback) {
/* Another packet is delivered to user. Send credits to peer if required */
- if (p_port->p_data_co_callback(p_port->inx, (uint8_t*)p_buf, -1,
+ if (p_port->p_data_co_callback(p_port->handle, (uint8_t*)p_buf, -1,
DATA_CO_CALLBACK_TYPE_INCOMING)) {
port_flow_control_peer(p_port, true, 1);
} else {
@@ -788,8 +784,8 @@
if (p_port->p_data_callback) {
/* Another packet is delivered to user. Send credits to peer if required */
port_flow_control_peer(p_port, true, 1);
- p_port->p_data_callback(p_port->inx, (uint8_t*)(p_buf + 1) + p_buf->offset,
- p_buf->len);
+ p_port->p_data_callback(p_port->handle,
+ (uint8_t*)(p_buf + 1) + p_buf->offset, p_buf->len);
osi_free(p_buf);
return;
}
@@ -837,7 +833,7 @@
/* Mask out all events that are not of interest to user */
events &= p_port->ev_mask;
- if (p_port->p_callback && events) p_port->p_callback(events, p_port->inx);
+ if (p_port->p_callback && events) p_port->p_callback(events, p_port->handle);
}
/*******************************************************************************
@@ -884,7 +880,8 @@
events &= p_port->ev_mask;
/* Send event to the application */
- if (p_port->p_callback && events) (p_port->p_callback)(events, p_port->inx);
+ if (p_port->p_callback && events)
+ (p_port->p_callback)(events, p_port->handle);
/* If DLCI is not 0 event applies to one port only */
if (dlci != 0) break;
@@ -962,7 +959,7 @@
p_port->rfc.state = RFC_STATE_CLOSED;
if (p_mcb) {
- p_mcb->port_inx[p_port->dlci] = 0;
+ p_mcb->port_handles[p_port->dlci] = 0;
/* If there are no more ports opened on this MCB release it */
rfc_check_mcb_active(p_mcb);
@@ -993,17 +990,19 @@
}
if ((p_port->p_callback != NULL) && events)
- p_port->p_callback(events, p_port->inx);
+ p_port->p_callback(events, p_port->handle);
- if (p_port->p_mgmt_callback) p_port->p_mgmt_callback(res, p_port->inx);
+ if (p_port->p_mgmt_callback) p_port->p_mgmt_callback(res, p_port->handle);
p_port->rfc.state = RFC_STATE_CLOSED;
- RFCOMM_TRACE_WARNING(
- "%s: RFCOMM connection closed, index=%d, state=%d reason=%s[%d], "
- "UUID=%04X, bd_addr=%s, is_server=%d",
- __func__, p_port->inx, p_port->state, PORT_GetResultString(res), res,
- p_port->uuid, p_port->bd_addr.ToString().c_str(), p_port->is_server);
+ LOG(INFO) << __func__ << ": RFCOMM connection closed, index="
+ << std::to_string(p_port->handle)
+ << ", state=" << std::to_string(p_port->state)
+ << ", reason=" << PORT_GetResultString(res) << "["
+ << std::to_string(res) << "], UUID=" << loghex(p_port->uuid)
+ << ", bd_addr=" << p_port->bd_addr
+ << ", is_server=" << p_port->is_server;
port_release_port(p_port);
}
diff --git a/stack/rfcomm/port_utils.cc b/stack/rfcomm/port_utils.cc
index e9a9036..7798375 100644
--- a/stack/rfcomm/port_utils.cc
+++ b/stack/rfcomm/port_utils.cc
@@ -61,36 +61,36 @@
*
******************************************************************************/
tPORT* port_allocate_port(uint8_t dlci, const RawAddress& bd_addr) {
- tPORT* p_port = &rfc_cb.port.port[0];
- uint8_t xx, yy;
-
- for (xx = 0, yy = rfc_cb.rfc.last_port + 1; xx < MAX_RFC_PORTS; xx++, yy++) {
- if (yy >= MAX_RFC_PORTS) yy = 0;
-
- p_port = &rfc_cb.port.port[yy];
+ uint8_t port_index = rfc_cb.rfc.last_port_index + static_cast<uint8_t>(1);
+ // Loop at most MAX_RFC_PORTS items
+ for (int loop_counter = 0; loop_counter < MAX_RFC_PORTS;
+ loop_counter++, port_index++) {
+ if (port_index >= MAX_RFC_PORTS) {
+ port_index = 0;
+ }
+ tPORT* p_port = &rfc_cb.port.port[port_index];
if (!p_port->in_use) {
+ // Assume that we already called port_release_port on this
memset(p_port, 0, sizeof(tPORT));
-
p_port->in_use = true;
- p_port->inx = yy + 1;
-
- /* During the open set default state for the port connection */
+ // handle is a port handle starting from 1
+ p_port->handle = port_index + static_cast<uint8_t>(1);
+ // During the open set default state for the port connection
port_set_defaults(p_port);
-
p_port->rfc.port_timer = alarm_new("rfcomm_port.port_timer");
- rfc_cb.rfc.last_port = yy;
-
p_port->dlci = dlci;
p_port->bd_addr = bd_addr;
-
- RFCOMM_TRACE_DEBUG("rfc_cb.port.port[%d]:%p allocated, last_port:%d", yy,
- p_port, rfc_cb.rfc.last_port);
- VLOG(1) << __func__ << ": bd_addr:" << bd_addr;
- return (p_port);
+ rfc_cb.rfc.last_port_index = port_index;
+ RFCOMM_TRACE_DEBUG(
+ "%s: rfc_cb.port.port[%d]:%p chosen, "
+ "last_port_index:%d, bd_addr=%s",
+ __func__, port_index, p_port, rfc_cb.rfc.last_port_index,
+ bd_addr.ToString().c_str());
+ return p_port;
}
}
-
- /* If here, no free PORT found */
+ LOG(WARNING) << __func__ << ": running out of free ports for dlci "
+ << std::to_string(dlci) << ", bd_addr " << bd_addr;
return nullptr;
}
@@ -146,7 +146,7 @@
packet_size = btm_get_max_packet_size(p_port->bd_addr);
if (packet_size == 0) {
/* something is very wrong */
- RFCOMM_TRACE_WARNING("port_select_mtu bad packet size");
+ LOG(WARNING) << __func__ << ": bad packet size 0 for" << p_port->bd_addr;
p_port->mtu = RFCOMM_DEFAULT_MTU;
} else {
/* We try to negotiate MTU that each packet can be split into whole
@@ -166,17 +166,16 @@
p_port->mtu = ((L2CAP_MTU_SIZE + L2CAP_PKT_OVERHEAD) / packet_size *
packet_size) -
RFCOMM_DATA_OVERHEAD - L2CAP_PKT_OVERHEAD;
- RFCOMM_TRACE_DEBUG(
- "port_select_mtu selected %d based on connection speed",
- p_port->mtu);
+ RFCOMM_TRACE_DEBUG("%s: selected %d based on connection speed",
+ __func__, p_port->mtu);
} else {
p_port->mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD;
- RFCOMM_TRACE_DEBUG(
- "port_select_mtu selected %d based on l2cap PDU size", p_port->mtu);
+ RFCOMM_TRACE_DEBUG("%s: selected %d based on l2cap PDU size", __func__,
+ p_port->mtu);
}
}
} else {
- RFCOMM_TRACE_DEBUG("port_select_mtu application selected %d", p_port->mtu);
+ RFCOMM_TRACE_DEBUG("%s: application selected %d", __func__, p_port->mtu);
}
p_port->credit_rx_max = (PORT_RX_HIGH_WM / p_port->mtu);
if (p_port->credit_rx_max > PORT_RX_BUF_HIGH_WM)
@@ -188,7 +187,7 @@
if (p_port->rx_buf_critical > PORT_RX_BUF_CRITICAL_WM)
p_port->rx_buf_critical = PORT_RX_BUF_CRITICAL_WM;
RFCOMM_TRACE_DEBUG(
- "port_select_mtu credit_rx_max %d, credit_rx_low %d, rx_buf_critical %d",
+ "%s: credit_rx_max %d, credit_rx_low %d, rx_buf_critical %d", __func__,
p_port->credit_rx_max, p_port->credit_rx_low, p_port->rx_buf_critical);
}
@@ -226,7 +225,7 @@
if (p_port->rfc.state == RFC_STATE_CLOSED) {
if (p_port->rfc.p_mcb) {
- p_port->rfc.p_mcb->port_inx[p_port->dlci] = 0;
+ p_port->rfc.p_mcb->port_handles[p_port->dlci] = 0;
/* If there are no more ports opened on this MCB release it */
rfc_check_mcb_active(p_port->rfc.p_mcb);
@@ -242,7 +241,8 @@
mutex_global_unlock();
if (p_port->keep_port_handle) {
- RFCOMM_TRACE_DEBUG("%s Re-initialize handle: %d", __func__, p_port->inx);
+ RFCOMM_TRACE_DEBUG("%s Re-initialize handle: %d", __func__,
+ p_port->handle);
/* save event mask and callback */
uint32_t mask = p_port->ev_mask;
@@ -264,7 +264,7 @@
p_port->local_ctrl.modem_signal = p_port->default_signal_state;
p_port->bd_addr = RawAddress::kAny;
} else {
- RFCOMM_TRACE_DEBUG("%s Clean-up handle: %d", __func__, p_port->inx);
+ RFCOMM_TRACE_DEBUG("%s Clean-up handle: %d", __func__, p_port->handle);
alarm_free(p_port->rfc.port_timer);
memset(p_port, 0, sizeof(tPORT));
}
@@ -317,14 +317,14 @@
return nullptr;
}
- uint8_t inx = p_mcb->port_inx[dlci];
- if (inx == 0) {
+ uint8_t handle = p_mcb->port_handles[dlci];
+ if (handle == 0) {
LOG(INFO) << __func__ << ": Cannot find allocated RFCOMM app port for DLCI "
<< std::to_string(dlci) << " on " << p_mcb->bd_addr
<< ", p_mcb=" << p_mcb;
return nullptr;
}
- return &rfc_cb.port.port[inx - 1];
+ return &rfc_cb.port.port[handle - 1];
}
/*******************************************************************************
diff --git a/stack/rfcomm/rfc_int.h b/stack/rfcomm/rfc_int.h
index 05afa9d..22aab66 100644
--- a/stack/rfcomm/rfc_int.h
+++ b/stack/rfcomm/rfc_int.h
@@ -56,18 +56,23 @@
extern void RFCOMM_DlcReleaseReq(tRFC_MCB* p_mcb, uint8_t dlci);
-extern void RFCOMM_ParNegReq(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu);
-extern void RFCOMM_ParNegRsp(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu,
- uint8_t cl, uint8_t k);
+extern void RFCOMM_ParameterNegotiationRequest(tRFC_MCB* p_mcb, uint8_t dlci,
+ uint16_t mtu);
+extern void RFCOMM_ParameterNegotiationResponse(tRFC_MCB* p_mcb, uint8_t dlci,
+ uint16_t mtu, uint8_t cl,
+ uint8_t k);
extern void RFCOMM_TestReq(uint8_t* p_data, uint16_t len);
extern void RFCOMM_FlowReq(tRFC_MCB* p_mcb, uint8_t dlci, bool state);
-extern void RFCOMM_PortNegReq(tRFC_MCB* p_mcb, uint8_t dlci,
- tPORT_STATE* p_pars);
-extern void RFCOMM_PortNegRsp(tRFC_MCB* p_mcb, uint8_t dlci,
- tPORT_STATE* p_pars, uint16_t param_mask);
+extern void RFCOMM_PortParameterNegotiationRequest(tRFC_MCB* p_mcb,
+ uint8_t dlci,
+ tPORT_STATE* p_pars);
+extern void RFCOMM_PortParameterNegotiationResponse(tRFC_MCB* p_mcb,
+ uint8_t dlci,
+ tPORT_STATE* p_pars,
+ uint16_t param_mask);
extern void RFCOMM_ControlReq(tRFC_MCB* p_mcb, uint8_t dlci,
tPORT_CTRL* p_pars);
@@ -221,7 +226,7 @@
tRFC_MCB* p_rfc_lcid_mcb[MAX_L2CAP_CHANNELS];
bool peer_rx_disabled; /* If true peer sent FCOFF */
uint8_t last_mux; /* Last mux allocated */
- uint8_t last_port; /* Last port allocated */
+ uint8_t last_port_index; // Index of last port allocated in rfc_cb.port
} tRFCOMM_CB;
/* Main Control Block for the RFCOMM Layer (PORT and RFC) */
diff --git a/stack/rfcomm/rfc_l2cap_if.cc b/stack/rfcomm/rfc_l2cap_if.cc
index a20f399..3275d77 100644
--- a/stack/rfcomm/rfc_l2cap_if.cc
+++ b/stack/rfcomm/rfc_l2cap_if.cc
@@ -26,8 +26,8 @@
#include "bt_target.h"
#include "bt_common.h"
+#include "common/time_util.h"
#include "osi/include/osi.h"
-#include "osi/include/time.h"
#include "bt_utils.h"
#include "l2c_api.h"
@@ -105,19 +105,21 @@
"LCID(0x%x), acceptor's LCID(0x%x)",
p_mcb->lcid, p_mcb->pending_lcid);
- rfc_timer_start(p_mcb, (uint16_t)(time_get_os_boottime_ms() % 10 + 2));
+ rfc_timer_start(
+ p_mcb,
+ (uint16_t)(bluetooth::common::time_get_os_boottime_ms() % 10 + 2));
return;
} else {
/* we cannot accept connection request from peer at this state */
/* don't update lcid */
- p_mcb = NULL;
+ p_mcb = nullptr;
}
} else {
/* store mcb even if null */
rfc_save_lcid_mcb(p_mcb, lcid);
}
- if (p_mcb == NULL) {
+ if (p_mcb == nullptr) {
L2CA_ConnectRsp(bd_addr, id, lcid, L2CAP_CONN_NO_RESOURCES, 0);
return;
}
@@ -163,13 +165,13 @@
/* update direction bit */
for (int i = 0; i < RFCOMM_MAX_DLCI; i += 2) {
- uint8_t idx = p_mcb->port_inx[i];
- if (idx != 0) {
- p_mcb->port_inx[i] = 0;
- p_mcb->port_inx[i + 1] = idx;
- rfc_cb.port.port[idx - 1].dlci += 1;
- RFCOMM_TRACE_DEBUG("RFCOMM MX, port_handle=%d, DLCI[%d->%d]", idx, i,
- rfc_cb.port.port[idx - 1].dlci);
+ uint8_t handle = p_mcb->port_handles[i];
+ if (handle != 0) {
+ p_mcb->port_handles[i] = 0;
+ p_mcb->port_handles[i + 1] = handle;
+ rfc_cb.port.port[handle - 1].dlci += 1;
+ RFCOMM_TRACE_DEBUG("RFCOMM MX, port_handle=%d, DLCI[%d->%d]", handle,
+ i, rfc_cb.port.port[handle - 1].dlci);
}
}
@@ -254,17 +256,16 @@
*
******************************************************************************/
void RFCOMM_DisconnectInd(uint16_t lcid, bool is_conf_needed) {
+ VLOG(1) << __func__ << ": lcid=" << loghex(lcid)
+ << ", is_conf_needed=" << is_conf_needed;
tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid);
-
if (is_conf_needed) {
L2CA_DisconnectRsp(lcid);
}
-
if (!p_mcb) {
- RFCOMM_TRACE_WARNING("RFCOMM_DisconnectInd LCID:0x%x", lcid);
+ LOG(WARNING) << __func__ << ": no mcb for lcid " << loghex(lcid);
return;
}
-
rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_DISC_IND, nullptr);
}
@@ -299,7 +300,7 @@
}
if (rfc_cb.rfc.rx_frame.dlci == RFCOMM_MX_DLCI) {
- RFCOMM_TRACE_DEBUG("%s: Handle multiplexer event %d, p_mcb=%p", __func__,
+ RFCOMM_TRACE_DEBUG("%s: handle multiplexer event %d, p_mcb=%p", __func__,
event, p_mcb);
/* Take special care of the Multiplexer Control Messages */
if (event == RFC_EVENT_UIH) {
@@ -341,10 +342,11 @@
osi_free(p_buf);
return;
}
- RFCOMM_TRACE_DEBUG("%s: port_inx[dlci=%d]:%d->%d, p_mcb=%p", __func__,
+ RFCOMM_TRACE_DEBUG("%s: port_handles[dlci=%d]:%d->%d, p_mcb=%p", __func__,
rfc_cb.rfc.rx_frame.dlci,
- p_mcb->port_inx[rfc_cb.rfc.rx_frame.dlci], p_port->inx);
- p_mcb->port_inx[rfc_cb.rfc.rx_frame.dlci] = p_port->inx;
+ p_mcb->port_handles[rfc_cb.rfc.rx_frame.dlci],
+ p_port->handle);
+ p_mcb->port_handles[rfc_cb.rfc.rx_frame.dlci] = p_port->handle;
p_port->rfc.p_mcb = p_mcb;
}
@@ -419,6 +421,14 @@
*
******************************************************************************/
void rfc_save_lcid_mcb(tRFC_MCB* p_mcb, uint16_t lcid) {
- if (lcid < L2CAP_BASE_APPL_CID) return;
- rfc_cb.rfc.p_rfc_lcid_mcb[lcid - L2CAP_BASE_APPL_CID] = p_mcb;
+ if (lcid < L2CAP_BASE_APPL_CID) {
+ LOG(ERROR) << __func__ << ": LCID " << lcid << " is too small";
+ return;
+ }
+ auto mcb_index = static_cast<size_t>(lcid - L2CAP_BASE_APPL_CID);
+ if (mcb_index >= MAX_L2CAP_CHANNELS) {
+ LOG(ERROR) << __func__ << ": LCID " << lcid << " is too large";
+ return;
+ }
+ rfc_cb.rfc.p_rfc_lcid_mcb[mcb_index] = p_mcb;
}
diff --git a/stack/rfcomm/rfc_mx_fsm.cc b/stack/rfcomm/rfc_mx_fsm.cc
index dfab62f..d1da01e 100644
--- a/stack/rfcomm/rfc_mx_fsm.cc
+++ b/stack/rfcomm/rfc_mx_fsm.cc
@@ -69,6 +69,9 @@
*
******************************************************************************/
void rfc_mx_sm_execute(tRFC_MCB* p_mcb, uint16_t event, void* p_data) {
+ CHECK(p_mcb != nullptr) << __func__ << ": NULL mcb for event " << event;
+ VLOG(1) << __func__ << ": bd_addr=" << p_mcb->bd_addr
+ << ", state=" << std::to_string(p_mcb->state) << ", event=" << event;
switch (p_mcb->state) {
case RFC_MX_STATE_IDLE:
rfc_mx_sm_state_idle(p_mcb, event, p_data);
@@ -112,7 +115,7 @@
*
******************************************************************************/
void rfc_mx_sm_state_idle(tRFC_MCB* p_mcb, uint16_t event, void* p_data) {
- RFCOMM_TRACE_EVENT("rfc_mx_sm_state_idle - evt:%d", event);
+ RFCOMM_TRACE_EVENT("%s: evt %d", __func__, event);
switch (event) {
case RFC_MX_EVENT_START_REQ: {
/* Initialize L2CAP MTU */
@@ -120,7 +123,9 @@
uint16_t lcid = L2CA_ConnectReq(BT_PSM_RFCOMM, p_mcb->bd_addr);
if (lcid == 0) {
- rfc_save_lcid_mcb(NULL, p_mcb->lcid);
+ LOG(ERROR) << __func__ << ": failed to open L2CAP channel for "
+ << p_mcb->bd_addr;
+ rfc_save_lcid_mcb(nullptr, p_mcb->lcid);
p_mcb->lcid = 0;
PORT_StartCnf(p_mcb, RFCOMM_ERROR);
return;
@@ -182,7 +187,7 @@
******************************************************************************/
void rfc_mx_sm_state_wait_conn_cnf(tRFC_MCB* p_mcb, uint16_t event,
void* p_data) {
- RFCOMM_TRACE_EVENT("rfc_mx_sm_state_wait_conn_cnf - evt:%d", event);
+ RFCOMM_TRACE_EVENT("%s: evt %d", __func__, event);
switch (event) {
case RFC_MX_EVENT_START_REQ:
RFCOMM_TRACE_ERROR("Mx error state %d event %d", p_mcb->state, event);
@@ -218,7 +223,7 @@
/* we gave up outgoing connection request then try peer's request */
if (p_mcb->pending_lcid) {
uint16_t i;
- uint8_t idx;
+ uint8_t handle;
RFCOMM_TRACE_DEBUG(
"RFCOMM MX retry as acceptor in collision case - evt:%d in "
@@ -233,13 +238,13 @@
/* update direction bit */
for (i = 0; i < RFCOMM_MAX_DLCI; i += 2) {
- idx = p_mcb->port_inx[i];
- if (idx != 0) {
- p_mcb->port_inx[i] = 0;
- p_mcb->port_inx[i + 1] = idx;
- rfc_cb.port.port[idx - 1].dlci += 1;
+ handle = p_mcb->port_handles[i];
+ if (handle != 0) {
+ p_mcb->port_handles[i] = 0;
+ p_mcb->port_handles[i + 1] = handle;
+ rfc_cb.port.port[handle - 1].dlci += 1;
RFCOMM_TRACE_DEBUG("RFCOMM MX - DLCI:%d -> %d", i,
- rfc_cb.port.port[idx - 1].dlci);
+ rfc_cb.port.port[handle - 1].dlci);
}
}
@@ -264,7 +269,7 @@
*
******************************************************************************/
void rfc_mx_sm_state_configure(tRFC_MCB* p_mcb, uint16_t event, void* p_data) {
- RFCOMM_TRACE_EVENT("rfc_mx_sm_state_configure - evt:%d", event);
+ RFCOMM_TRACE_EVENT("%s: event %d", __func__, event);
switch (event) {
case RFC_MX_EVENT_START_REQ:
case RFC_MX_EVENT_CONN_CNF:
@@ -286,6 +291,8 @@
return;
case RFC_EVENT_TIMEOUT:
+ LOG(ERROR) << __func__ << ": L2CAP configuration timeout for "
+ << p_mcb->bd_addr;
p_mcb->state = RFC_MX_STATE_IDLE;
L2CA_DisconnectReq(p_mcb->lcid);
@@ -308,7 +315,7 @@
******************************************************************************/
void rfc_mx_sm_sabme_wait_ua(tRFC_MCB* p_mcb, uint16_t event,
UNUSED_ATTR void* p_data) {
- RFCOMM_TRACE_EVENT("rfc_mx_sm_sabme_wait_ua - evt:%d", event);
+ RFCOMM_TRACE_EVENT("%s: event %d", __func__, event);
switch (event) {
case RFC_MX_EVENT_START_REQ:
case RFC_MX_EVENT_CONN_CNF:
@@ -342,7 +349,7 @@
case RFC_EVENT_DM:
rfc_timer_stop(p_mcb);
- /* Case falls through */
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case RFC_MX_EVENT_CONF_IND: /* workaround: we don't support reconfig */
case RFC_MX_EVENT_CONF_CNF: /* workaround: we don't support reconfig */
@@ -368,7 +375,7 @@
*
******************************************************************************/
void rfc_mx_sm_state_wait_sabme(tRFC_MCB* p_mcb, uint16_t event, void* p_data) {
- RFCOMM_TRACE_EVENT("rfc_mx_sm_state_wait_sabme - evt:%d", event);
+ RFCOMM_TRACE_EVENT("%s: event %d", __func__, event);
switch (event) {
case RFC_MX_EVENT_DISC_IND:
p_mcb->state = RFC_MX_STATE_IDLE;
@@ -431,7 +438,7 @@
******************************************************************************/
void rfc_mx_sm_state_connected(tRFC_MCB* p_mcb, uint16_t event,
UNUSED_ATTR void* p_data) {
- RFCOMM_TRACE_EVENT("rfc_mx_sm_state_connected - evt:%d", event);
+ RFCOMM_TRACE_EVENT("%s: event %d", __func__, event);
switch (event) {
case RFC_EVENT_TIMEOUT:
@@ -475,7 +482,7 @@
void* p_data) {
BT_HDR* p_buf;
- RFCOMM_TRACE_EVENT("rfc_mx_sm_state_disc_wait_ua - evt:%d", event);
+ RFCOMM_TRACE_EVENT("%s: event %d", __func__, event);
switch (event) {
case RFC_EVENT_UA:
case RFC_EVENT_DM:
@@ -549,12 +556,8 @@
*
******************************************************************************/
static void rfc_mx_send_config_req(tRFC_MCB* p_mcb) {
- tL2CAP_CFG_INFO cfg;
-
RFCOMM_TRACE_EVENT("rfc_mx_send_config_req");
-
- memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
-
+ tL2CAP_CFG_INFO cfg = {};
cfg.mtu_present = true;
cfg.mtu = L2CAP_MTU_SIZE;
@@ -580,11 +583,15 @@
*
******************************************************************************/
static void rfc_mx_conf_cnf(tRFC_MCB* p_mcb, tL2CAP_CFG_INFO* p_cfg) {
- RFCOMM_TRACE_EVENT("rfc_mx_conf_cnf p_cfg:%08x res:%d ", p_cfg,
+ RFCOMM_TRACE_EVENT("rfc_mx_conf_cnf p_cfg:%08x result:%d ", p_cfg,
(p_cfg) ? p_cfg->result : 0);
if (p_cfg->result != L2CAP_CFG_OK) {
+ LOG(ERROR) << __func__ << ": failed to configure L2CAP for "
+ << p_mcb->bd_addr;
if (p_mcb->is_initiator) {
+ LOG(ERROR) << __func__ << ": disconnect L2CAP due to config failure for "
+ << p_mcb->bd_addr;
PORT_StartCnf(p_mcb, p_cfg->result);
L2CA_DisconnectReq(p_mcb->lcid);
}
@@ -619,10 +626,11 @@
static void rfc_mx_conf_ind(tRFC_MCB* p_mcb, tL2CAP_CFG_INFO* p_cfg) {
/* Save peer L2CAP MTU if present */
/* RFCOMM adds 3-4 bytes in the beginning and 1 bytes FCS */
- if (p_cfg->mtu_present)
+ if (p_cfg->mtu_present) {
p_mcb->peer_l2cap_mtu = p_cfg->mtu - RFCOMM_MIN_OFFSET - 1;
- else
+ } else {
p_mcb->peer_l2cap_mtu = L2CAP_DEFAULT_MTU - RFCOMM_MIN_OFFSET - 1;
+ }
p_cfg->mtu_present = false;
p_cfg->flush_to_present = false;
diff --git a/stack/rfcomm/rfc_port_fsm.cc b/stack/rfcomm/rfc_port_fsm.cc
index 4ff4628..f486bdd 100644
--- a/stack/rfcomm/rfc_port_fsm.cc
+++ b/stack/rfcomm/rfc_port_fsm.cc
@@ -64,11 +64,11 @@
*
******************************************************************************/
void rfc_port_sm_execute(tPORT* p_port, uint16_t event, void* p_data) {
- if (!p_port) {
- RFCOMM_TRACE_WARNING("NULL port event %d", event);
- return;
- }
-
+ CHECK(p_port != nullptr) << __func__ << ": NULL port event " << event;
+ VLOG(1) << __func__ << ": BD_ADDR=" << p_port->bd_addr
+ << ", PORT=" << std::to_string(p_port->handle)
+ << ", STATE=" << std::to_string(p_port->rfc.state)
+ << ", EVENT=" << event;
switch (p_port->rfc.state) {
case RFC_STATE_CLOSED:
rfc_port_sm_state_closed(p_port, event, p_data);
@@ -143,7 +143,8 @@
return;
case RFC_EVENT_DM:
- RFCOMM_TRACE_WARNING("%s, RFC_EVENT_DM, index=%d", __func__, p_port->inx);
+ RFCOMM_TRACE_WARNING("%s, RFC_EVENT_DM, index=%d", __func__,
+ p_port->handle);
rfc_port_closed(p_port);
return;
@@ -194,7 +195,7 @@
case RFC_EVENT_CLEAR:
RFCOMM_TRACE_WARNING("%s, RFC_EVENT_CLEAR, index=%d", __func__,
- p_port->inx);
+ p_port->handle);
rfc_port_closed(p_port);
return;
@@ -210,7 +211,8 @@
return;
case RFC_EVENT_DM:
- RFCOMM_TRACE_WARNING("%s, RFC_EVENT_DM, index=%d", __func__, p_port->inx);
+ RFCOMM_TRACE_WARNING("%s, RFC_EVENT_DM, index=%d", __func__,
+ p_port->handle);
p_port->rfc.p_mcb->is_disc_initiator = true;
PORT_DlcEstablishCnf(p_port->rfc.p_mcb, p_port->dlci,
p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_ERROR);
@@ -219,7 +221,7 @@
case RFC_EVENT_DISC:
RFCOMM_TRACE_WARNING("%s, RFC_EVENT_DISC, index=%d", __func__,
- p_port->inx);
+ p_port->handle);
rfc_send_ua(p_port->rfc.p_mcb, p_port->dlci);
PORT_DlcEstablishCnf(p_port->rfc.p_mcb, p_port->dlci,
p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_ERROR);
@@ -282,7 +284,7 @@
case RFC_EVENT_CLEAR:
RFCOMM_TRACE_WARNING("%s, RFC_EVENT_CLEAR, index=%d", __func__,
- p_port->inx);
+ p_port->handle);
btm_sec_abort_access_req(p_port->rfc.p_mcb->bd_addr);
rfc_port_closed(p_port);
return;
@@ -339,7 +341,8 @@
case RFC_EVENT_SEC_COMPLETE:
if (*((uint8_t*)p_data) != BTM_SUCCESS) {
RFCOMM_TRACE_ERROR("%s, RFC_EVENT_SEC_COMPLETE, index=%d, result=%d",
- __func__, event, p_port->inx, *((uint8_t*)p_data));
+ __func__, event, p_port->handle,
+ *((uint8_t*)p_data));
p_port->rfc.p_mcb->is_disc_initiator = true;
PORT_DlcEstablishCnf(p_port->rfc.p_mcb, p_port->dlci, 0,
RFCOMM_SECURITY_ERR);
@@ -359,7 +362,7 @@
case RFC_EVENT_CLOSE:
RFCOMM_TRACE_WARNING("%s, RFC_EVENT_CLOSE, index=%d", __func__,
- p_port->inx);
+ p_port->handle);
btm_sec_abort_access_req(p_port->rfc.p_mcb->bd_addr);
rfc_port_closed(p_port);
return;
@@ -403,7 +406,7 @@
case RFC_EVENT_CLEAR:
RFCOMM_TRACE_WARNING("%s, RFC_EVENT_CLEAR, index=%d", __func__,
- p_port->inx);
+ p_port->handle);
rfc_port_closed(p_port);
return;
@@ -435,7 +438,8 @@
return;
case RFC_EVENT_DM:
- RFCOMM_TRACE_WARNING("%s, RFC_EVENT_DM, index=%d", __func__, p_port->inx);
+ RFCOMM_TRACE_WARNING("%s, RFC_EVENT_DM, index=%d", __func__,
+ p_port->handle);
PORT_DlcReleaseInd(p_port->rfc.p_mcb, p_port->dlci);
rfc_port_closed(p_port);
return;
@@ -484,7 +488,7 @@
case RFC_EVENT_CLEAR:
RFCOMM_TRACE_WARNING("%s, RFC_EVENT_CLEAR, index=%d", __func__, event,
- p_port->inx);
+ p_port->handle);
rfc_port_closed(p_port);
return;
@@ -494,11 +498,11 @@
case RFC_EVENT_UA:
p_port->rfc.p_mcb->is_disc_initiator = true;
- /* Case falls through */
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case RFC_EVENT_DM:
RFCOMM_TRACE_WARNING("%s, RFC_EVENT_DM|RFC_EVENT_UA[%d], index=%d",
- __func__, event, p_port->inx);
+ __func__, event, p_port->handle);
rfc_port_closed(p_port);
return;
@@ -517,7 +521,7 @@
case RFC_EVENT_TIMEOUT:
RFCOMM_TRACE_ERROR("%s, RFC_EVENT_TIMEOUT, index=%d", __func__,
- p_port->inx);
+ p_port->handle);
rfc_port_closed(p_port);
return;
}
@@ -545,7 +549,9 @@
*
******************************************************************************/
void rfc_process_pn(tRFC_MCB* p_mcb, bool is_command, MX_FRAME* p_frame) {
- tPORT* p_port;
+ RFCOMM_TRACE_DEBUG("%s: is_initiator=%d, is_cmd=%d, state=%d, bd_addr=%s",
+ __func__, p_mcb->is_initiator, is_command, p_mcb->state,
+ p_mcb->bd_addr.ToString().c_str());
uint8_t dlci = p_frame->dlci;
if (is_command) {
@@ -563,7 +569,7 @@
return;
}
/* If we are not awaiting response just ignore it */
- p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+ tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
if ((p_port == nullptr) || !(p_port->rfc.expected_rsp & RFC_RSP_PN)) {
LOG(WARNING) << ": Ignore unwanted response, p_mcb=" << p_mcb
<< ", bd_addr=" << p_mcb->bd_addr
diff --git a/stack/rfcomm/rfc_port_if.cc b/stack/rfcomm/rfc_port_if.cc
index 2ce5f9e..097d774 100644
--- a/stack/rfcomm/rfc_port_if.cc
+++ b/stack/rfcomm/rfc_port_if.cc
@@ -115,7 +115,7 @@
/*******************************************************************************
*
- * Function RFCOMM_ParNegReq
+ * Function RFCOMM_ParameterNegotiationRequest
*
* Description This function is called by the user app to start
* DLC parameter negotiation. Port emulation can send this
@@ -124,7 +124,8 @@
* block.
*
******************************************************************************/
-void RFCOMM_ParNegReq(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu) {
+void RFCOMM_ParameterNegotiationRequest(tRFC_MCB* p_mcb, uint8_t dlci,
+ uint16_t mtu) {
uint8_t flow;
uint8_t cl;
uint8_t k;
@@ -166,14 +167,14 @@
/*******************************************************************************
*
- * Function RFCOMM_ParNegRsp
+ * Function RFCOMM_ParameterNegotiationResponse
*
* Description This function is called by the user app to acknowledge
* DLC parameter negotiation.
*
******************************************************************************/
-void RFCOMM_ParNegRsp(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu, uint8_t cl,
- uint8_t k) {
+void RFCOMM_ParameterNegotiationResponse(tRFC_MCB* p_mcb, uint8_t dlci,
+ uint16_t mtu, uint8_t cl, uint8_t k) {
if (p_mcb->state != RFC_MX_STATE_CONNECTED) return;
/* Send Parameter Negotiation Response UIH frame */
@@ -182,7 +183,7 @@
/*******************************************************************************
*
- * Function RFCOMM_PortNegReq
+ * Function RFCOMM_PortParameterNegotiationRequest
*
* Description This function is called by the user app to start
* Remote Port parameter negotiation. Port emulation can
@@ -191,7 +192,8 @@
* control block.
*
******************************************************************************/
-void RFCOMM_PortNegReq(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_STATE* p_pars) {
+void RFCOMM_PortParameterNegotiationRequest(tRFC_MCB* p_mcb, uint8_t dlci,
+ tPORT_STATE* p_pars) {
if (p_mcb->state != RFC_MX_STATE_CONNECTED) {
PORT_PortNegCnf(p_mcb, dlci, nullptr, RFCOMM_ERROR);
return;
@@ -215,14 +217,15 @@
/*******************************************************************************
*
- * Function RFCOMM_PortNegRsp
+ * Function RFCOMM_PortParameterNegotiationResponse
*
* Description This function is called by the user app to acknowledge
* Port parameters negotiation.
*
******************************************************************************/
-void RFCOMM_PortNegRsp(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_STATE* p_pars,
- uint16_t param_mask) {
+void RFCOMM_PortParameterNegotiationResponse(tRFC_MCB* p_mcb, uint8_t dlci,
+ tPORT_STATE* p_pars,
+ uint16_t param_mask) {
if (p_mcb->state != RFC_MX_STATE_CONNECTED) return;
rfc_send_rpn(p_mcb, dlci, false, p_pars, param_mask);
diff --git a/stack/rfcomm/rfc_ts_frames.cc b/stack/rfcomm/rfc_ts_frames.cc
index e3b4b8f..d253b40 100644
--- a/stack/rfcomm/rfc_ts_frames.cc
+++ b/stack/rfcomm/rfc_ts_frames.cc
@@ -154,14 +154,19 @@
uint8_t credits;
p_buf->offset -= RFCOMM_CTRL_FRAME_LEN;
- if (p_buf->len > 127) p_buf->offset--;
+ if (p_buf->len > 127) {
+ p_buf->offset--;
+ }
- if (dlci)
+ if (dlci) {
credits = (uint8_t)p_buf->layer_specific;
- else
+ } else {
credits = 0;
+ }
- if (credits) p_buf->offset--;
+ if (credits) {
+ p_buf->offset--;
+ }
p_data = (uint8_t*)(p_buf + 1) + p_buf->offset;
@@ -219,11 +224,11 @@
** We will use the fact that we reply in the same context so rx_frame can
*still be used.
*/
- if (is_command)
+ if (is_command) {
*p_data++ = RFCOMM_PN_PRIORITY_0;
- else
+ } else {
*p_data++ = rfc_cb.rfc.rx_frame.u.pn.priority;
-
+ }
*p_data++ = RFCOMM_T1_DSEC;
*p_data++ = mtu & 0xFF;
*p_data++ = mtu >> 8;
@@ -537,8 +542,9 @@
p_frame->credit = *p_data++;
p_buf->len--;
p_buf->offset++;
- } else
+ } else {
p_frame->credit = 0;
+ }
if (p_buf->len != len) {
RFCOMM_TRACE_ERROR("Bad Length2 %d %d", p_buf->len, len);
@@ -599,8 +605,9 @@
/* we assume that this is ok to allow bad implementations to work */
RFCOMM_TRACE_ERROR("Bad UIH - response");
return (RFC_EVENT_UIH);
- } else
+ } else {
return (RFC_EVENT_UIH);
+ }
}
return (RFC_EVENT_BAD_FRAME);
@@ -619,7 +626,6 @@
MX_FRAME* p_rx_frame = &rfc_cb.rfc.rx_frame;
uint16_t length = p_buf->len;
uint8_t ea, cr, mx_len;
- bool is_command;
if (length < 2) {
RFCOMM_TRACE_ERROR(
@@ -643,7 +649,7 @@
length--;
- is_command = p_rx_frame->cr;
+ bool is_command = p_rx_frame->cr;
ea = *p_data & RFCOMM_EA;
@@ -669,8 +675,8 @@
return;
}
- RFCOMM_TRACE_DEBUG("%s: type=%d, p_mcb=%p", __func__, p_rx_frame->type,
- p_mcb);
+ RFCOMM_TRACE_DEBUG("%s: type=0x%02x, bd_addr=%s", __func__, p_rx_frame->type,
+ p_mcb->bd_addr.ToString().c_str());
switch (p_rx_frame->type) {
case RFCOMM_MX_PN:
if (length != RFCOMM_MX_PN_LEN) {
diff --git a/stack/rfcomm/rfc_utils.cc b/stack/rfcomm/rfc_utils.cc
index 74e336a..3dee8a1 100644
--- a/stack/rfcomm/rfc_utils.cc
+++ b/stack/rfcomm/rfc_utils.cc
@@ -225,7 +225,7 @@
void rfc_timer_start(tRFC_MCB* p_mcb, uint16_t timeout) {
RFCOMM_TRACE_EVENT("%s - timeout:%d seconds", __func__, timeout);
- period_ms_t interval_ms = timeout * 1000;
+ uint64_t interval_ms = timeout * 1000;
alarm_set_on_mloop(p_mcb->mcb_timer, interval_ms, rfcomm_mcb_timer_timeout,
p_mcb);
}
@@ -253,7 +253,7 @@
void rfc_port_timer_start(tPORT* p_port, uint16_t timeout) {
RFCOMM_TRACE_EVENT("%s - timeout:%d seconds", __func__, timeout);
- period_ms_t interval_ms = timeout * 1000;
+ uint64_t interval_ms = timeout * 1000;
alarm_set_on_mloop(p_port->rfc.port_timer, interval_ms,
rfcomm_port_timer_timeout, p_port);
}
@@ -285,7 +285,7 @@
uint16_t i;
for (i = 0; i < RFCOMM_MAX_DLCI; i++) {
- if (p_mcb->port_inx[i] != 0) {
+ if (p_mcb->port_handles[i] != 0) {
p_mcb->is_disc_initiator = false;
return;
}
@@ -353,7 +353,7 @@
/* If multiplexer channel was up mark it as down */
if (p_mcb) {
- p_mcb->port_inx[p_port->dlci] = 0;
+ p_mcb->port_handles[p_port->dlci] = 0;
/* If there are no more ports opened on this MCB release it */
rfc_check_mcb_active(p_mcb);
diff --git a/stack/sdp/sdp_db.cc b/stack/sdp/sdp_db.cc
index d8cee9a..28eae10 100644
--- a/stack/sdp/sdp_db.cc
+++ b/stack/sdp/sdp_db.cc
@@ -792,34 +792,33 @@
******************************************************************************/
bool SDP_DeleteAttribute(uint32_t handle, uint16_t attr_id) {
#if (SDP_SERVER_ENABLED == TRUE)
- uint16_t xx, yy;
tSDP_RECORD* p_rec = &sdp_cb.server_db.record[0];
uint8_t* pad_ptr;
uint32_t len; /* Number of bytes in the entry */
/* Find the record in the database */
- for (xx = 0; xx < sdp_cb.server_db.num_records; xx++, p_rec++) {
+ for (uint16_t xx = 0; xx < sdp_cb.server_db.num_records; xx++, p_rec++) {
if (p_rec->record_handle == handle) {
tSDP_ATTRIBUTE* p_attr = &p_rec->attribute[0];
SDP_TRACE_API("Deleting attr_id 0x%04x for handle 0x%x", attr_id, handle);
/* Found it. Now, find the attribute */
- for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++) {
+ for (uint16_t yy = 0; yy < p_rec->num_attributes; yy++, p_attr++) {
if (p_attr->id == attr_id) {
pad_ptr = p_attr->value_ptr;
len = p_attr->len;
if (len) {
- for (yy = 0; yy < p_rec->num_attributes; yy++) {
- if (p_rec->attribute[yy].value_ptr > pad_ptr)
- p_rec->attribute[yy].value_ptr -= len;
+ for (uint16_t zz = 0; zz < p_rec->num_attributes; zz++) {
+ if (p_rec->attribute[zz].value_ptr > pad_ptr)
+ p_rec->attribute[zz].value_ptr -= len;
}
}
/* Found it. Shift everything up one */
p_rec->num_attributes--;
- for (yy = xx; yy < p_rec->num_attributes; yy++, p_attr++) {
+ for (uint16_t zz = xx; zz < p_rec->num_attributes; zz++, p_attr++) {
*p_attr = *(p_attr + 1);
}
@@ -827,7 +826,9 @@
if (len) {
xx =
(p_rec->free_pad_ptr - ((pad_ptr + len) - &p_rec->attr_pad[0]));
- for (yy = 0; yy < xx; yy++, pad_ptr++) *pad_ptr = *(pad_ptr + len);
+ for (uint16_t zz = 0; zz < xx; zz++, pad_ptr++) {
+ *pad_ptr = *(pad_ptr + len);
+ }
p_rec->free_pad_ptr -= len;
}
return (true);
diff --git a/stack/sdp/sdp_discovery.cc b/stack/sdp/sdp_discovery.cc
index 1ca2ad3..29377b0 100644
--- a/stack/sdp/sdp_discovery.cc
+++ b/stack/sdp/sdp_discovery.cc
@@ -39,10 +39,6 @@
using bluetooth::Uuid;
-#ifndef SDP_DEBUG_RAW
-#define SDP_DEBUG_RAW false
-#endif
-
/******************************************************************************/
/* L O C A L F U N C T I O N P R O T O T Y P E S */
/******************************************************************************/
@@ -168,11 +164,6 @@
/* Set the length of the SDP data in the buffer */
p_cmd->len = (uint16_t)(p - p_start);
-#if (SDP_DEBUG_RAW == TRUE)
- SDP_TRACE_WARNING("sdp_snd_service_search_req cont_len :%d disc_state:%d",
- cont_len, p_ccb->disc_state);
-#endif
-
L2CA_DataWrite(p_ccb->connection_id, p_cmd);
/* Start inactivity timer */
@@ -219,10 +210,6 @@
uint8_t *p, rsp_pdu;
bool invalid_pdu = true;
-#if (SDP_DEBUG_RAW == TRUE)
- SDP_TRACE_WARNING("sdp_disc_server_rsp disc_state:%d", p_ccb->disc_state);
-#endif
-
/* stop inactivity timer when we receive a response */
alarm_cancel(p_ccb->sdp_conn_timer);
@@ -351,17 +338,6 @@
uint8_t* p;
uint8_t type;
-#if (SDP_DEBUG_RAW == TRUE)
- uint8_t num_array[SDP_MAX_LIST_BYTE_COUNT];
- uint32_t i;
-
- for (i = 0; i < p_ccb->list_len; i++) {
- snprintf((char*)&num_array[i * 2], sizeof(num_array) - i * 2, "%02X",
- (uint8_t)(p_ccb->rsp_list[i]));
- }
- SDP_TRACE_WARNING("result :%s", num_array);
-#endif
-
if (p_ccb->p_db->raw_data) {
cpy_len = p_ccb->p_db->raw_size - p_ccb->p_db->raw_used;
list_len = p_ccb->list_len;
@@ -413,23 +389,12 @@
uint16_t param_len, list_byte_count;
bool cont_request_needed = false;
-#if (SDP_DEBUG_RAW == TRUE)
- SDP_TRACE_WARNING("process_service_attr_rsp raw inc:%d",
- SDP_RAW_DATA_INCLUDED);
-#endif
/* If p_reply is NULL, we were called after the records handles were read */
if (p_reply) {
-#if (SDP_DEBUG_RAW == TRUE)
- SDP_TRACE_WARNING("ID & len: 0x%02x-%02x-%02x-%02x", p_reply[0], p_reply[1],
- p_reply[2], p_reply[3]);
-#endif
/* Skip transaction ID and length */
p_reply += 4;
BE_STREAM_TO_UINT16(list_byte_count, p_reply);
-#if (SDP_DEBUG_RAW == TRUE)
- SDP_TRACE_WARNING("list_byte_count:%d", list_byte_count);
-#endif
/* Copy the response to the scratchpad. First, a safety check on the length
*/
@@ -438,21 +403,11 @@
return;
}
-#if (SDP_DEBUG_RAW == TRUE)
- SDP_TRACE_WARNING("list_len: %d, list_byte_count: %d", p_ccb->list_len,
- list_byte_count);
-#endif
if (p_ccb->rsp_list == NULL)
p_ccb->rsp_list = (uint8_t*)osi_malloc(SDP_MAX_LIST_BYTE_COUNT);
memcpy(&p_ccb->rsp_list[p_ccb->list_len], p_reply, list_byte_count);
p_ccb->list_len += list_byte_count;
p_reply += list_byte_count;
-#if (SDP_DEBUG_RAW == TRUE)
- SDP_TRACE_WARNING("list_len: %d(attr_rsp)", p_ccb->list_len);
-
- /* Check if we need to request a continuation */
- SDP_TRACE_WARNING("*p_reply:%d(%d)", *p_reply, SDP_MAX_CONTINUATION_LEN);
-#endif
if (*p_reply) {
if (*p_reply > SDP_MAX_CONTINUATION_LEN) {
sdp_disconnect(p_ccb, SDP_INVALID_CONT_STATE);
@@ -529,6 +484,7 @@
alarm_set_on_mloop(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
sdp_conn_timer_timeout, p_ccb);
} else {
+ sdpu_log_attribute_metrics(p_ccb->device_address, p_ccb->p_db);
sdp_disconnect(p_ccb, SDP_SUCCESS);
return;
}
@@ -552,9 +508,6 @@
uint16_t param_len, lists_byte_count = 0;
bool cont_request_needed = false;
-#if (SDP_DEBUG_RAW == TRUE)
- SDP_TRACE_WARNING("process_service_search_attr_rsp");
-#endif
/* If p_reply is NULL, we were called for the initial read */
if (p_reply) {
if (p_reply + 4 /* transaction ID and length */ + sizeof(lists_byte_count) >
@@ -564,17 +517,10 @@
return;
}
-#if (SDP_DEBUG_RAW == TRUE)
- SDP_TRACE_WARNING("ID & len: 0x%02x-%02x-%02x-%02x", p_reply[0], p_reply[1],
- p_reply[2], p_reply[3]);
-#endif
/* Skip transaction ID and length */
p_reply += 4;
BE_STREAM_TO_UINT16(lists_byte_count, p_reply);
-#if (SDP_DEBUG_RAW == TRUE)
- SDP_TRACE_WARNING("lists_byte_count:%d", lists_byte_count);
-#endif
/* Copy the response to the scratchpad. First, a safety check on the length
*/
@@ -583,11 +529,6 @@
return;
}
-#if (SDP_DEBUG_RAW == TRUE)
- SDP_TRACE_WARNING("list_len: %d, list_byte_count: %d", p_ccb->list_len,
- lists_byte_count);
-#endif
-
if (p_reply + lists_byte_count + 1 /* continuation */ > p_reply_end) {
android_errorWriteLog(0x534e4554, "79884292");
sdp_disconnect(p_ccb, SDP_INVALID_PDU_SIZE);
@@ -599,12 +540,6 @@
memcpy(&p_ccb->rsp_list[p_ccb->list_len], p_reply, lists_byte_count);
p_ccb->list_len += lists_byte_count;
p_reply += lists_byte_count;
-#if (SDP_DEBUG_RAW == TRUE)
- SDP_TRACE_WARNING("list_len: %d(search_attr_rsp)", p_ccb->list_len);
-
- /* Check if we need to request a continuation */
- SDP_TRACE_WARNING("*p_reply:%d(%d)", *p_reply, SDP_MAX_CONTINUATION_LEN);
-#endif
if (*p_reply) {
if (*p_reply > SDP_MAX_CONTINUATION_LEN) {
sdp_disconnect(p_ccb, SDP_INVALID_CONT_STATE);
@@ -615,9 +550,6 @@
}
}
-#if (SDP_DEBUG_RAW == TRUE)
- SDP_TRACE_WARNING("cont_request_needed:%d", cont_request_needed);
-#endif
/* If continuation request (or first time request) */
if ((cont_request_needed) || (!p_reply)) {
BT_HDR* p_msg = (BT_HDR*)osi_malloc(SDP_DATA_BUF_SIZE);
@@ -717,6 +649,7 @@
}
/* Since we got everything we need, disconnect the call */
+ sdpu_log_attribute_metrics(p_ccb->device_address, p_ccb->p_db);
sdp_disconnect(p_ccb, SDP_SUCCESS);
}
@@ -901,7 +834,7 @@
break;
}
}
- /* Case falls through */
+ FALLTHROUGH_INTENDED; /* FALLTHROUGH */
case TWO_COMP_INT_DESC_TYPE:
switch (attr_len) {
diff --git a/stack/sdp/sdp_server.cc b/stack/sdp/sdp_server.cc
index 386f62f..c9949b7 100644
--- a/stack/sdp/sdp_server.cc
+++ b/stack/sdp/sdp_server.cc
@@ -23,7 +23,7 @@
*
******************************************************************************/
-#include <cutils/log.h>
+#include <log/log.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/stack/sdp/sdp_utils.cc b/stack/sdp/sdp_utils.cc
index c57a499..2c3aee2 100644
--- a/stack/sdp/sdp_utils.cc
+++ b/stack/sdp/sdp_utils.cc
@@ -26,6 +26,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <utility>
+#include <vector>
#include "bt_common.h"
#include "bt_types.h"
@@ -38,12 +40,251 @@
#include "sdpint.h"
#include "btu.h"
+#include "common/metrics.h"
using bluetooth::Uuid;
static const uint8_t sdp_base_uuid[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
0x5F, 0x9B, 0x34, 0xFB};
+template <typename T>
+static std::array<char, sizeof(T)> to_little_endian_array(T x) {
+ static_assert(std::is_integral<T>::value,
+ "to_little_endian_array parameter must be integral.");
+ std::array<char, sizeof(T)> array = {};
+ for (size_t i = 0; i < array.size(); i++) {
+ array[i] = static_cast<char>((x >> (8 * i)) & 0xFF);
+ }
+ return array;
+}
+
+/**
+ * Find the list of profile versions from Bluetooth Profile Descriptor list
+ * attribute in a SDP record
+ *
+ * @param p_rec SDP record to search
+ * @return a vector of <UUID, VERSION> pairs, empty if not found
+ */
+static std::vector<std::pair<uint16_t, uint16_t>> sdpu_find_profile_version(
+ tSDP_DISC_REC* p_rec) {
+ std::vector<std::pair<uint16_t, uint16_t>> result;
+ for (tSDP_DISC_ATTR* p_attr = p_rec->p_first_attr; p_attr != nullptr;
+ p_attr = p_attr->p_next_attr) {
+ // Find the profile descriptor list */
+ if (p_attr->attr_id != ATTR_ID_BT_PROFILE_DESC_LIST ||
+ SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE) {
+ continue;
+ }
+ // Walk through the protocol descriptor list
+ for (tSDP_DISC_ATTR* p_sattr = p_attr->attr_value.v.p_sub_attr;
+ p_sattr != nullptr; p_sattr = p_sattr->p_next_attr) {
+ // Safety check - each entry should itself be a sequence
+ if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) !=
+ DATA_ELE_SEQ_DESC_TYPE) {
+ LOG(WARNING) << __func__ << ": Descriptor type is not sequence: "
+ << loghex(SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type));
+ return std::vector<std::pair<uint16_t, uint16_t>>();
+ }
+ // Now, see if the entry contains the profile UUID we are interested in
+ for (tSDP_DISC_ATTR* p_ssattr = p_sattr->attr_value.v.p_sub_attr;
+ p_ssattr != nullptr; p_ssattr = p_ssattr->p_next_attr) {
+ if (SDP_DISC_ATTR_TYPE(p_ssattr->attr_len_type) != UUID_DESC_TYPE ||
+ SDP_DISC_ATTR_LEN(p_ssattr->attr_len_type) != 2) {
+ continue;
+ }
+ uint16_t uuid = p_ssattr->attr_value.v.u16;
+ // Next attribute should be the version attribute
+ tSDP_DISC_ATTR* version_attr = p_ssattr->p_next_attr;
+ if (SDP_DISC_ATTR_TYPE(version_attr->attr_len_type) != UINT_DESC_TYPE ||
+ SDP_DISC_ATTR_LEN(version_attr->attr_len_type) != 2) {
+ LOG(WARNING) << __func__ << ": Bad version type "
+ << loghex(
+ SDP_DISC_ATTR_TYPE(version_attr->attr_len_type))
+ << ", or length "
+ << SDP_DISC_ATTR_LEN(version_attr->attr_len_type);
+ return std::vector<std::pair<uint16_t, uint16_t>>();
+ }
+ // High order 8 bits is the major number, low order is the
+ // minor number (big endian)
+ uint16_t version = version_attr->attr_value.v.u16;
+ result.emplace_back(uuid, version);
+ }
+ }
+ }
+ return result;
+}
+
+/**
+ * Find the most specific 16-bit service uuid represented by a SDP record
+ *
+ * @param p_rec pointer to a SDP record
+ * @return most specific 16-bit service uuid, 0 if not found
+ */
+static uint16_t sdpu_find_most_specific_service_uuid(tSDP_DISC_REC* p_rec) {
+ for (tSDP_DISC_ATTR* p_attr = p_rec->p_first_attr; p_attr != nullptr;
+ p_attr = p_attr->p_next_attr) {
+ if (p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST &&
+ SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE) {
+ tSDP_DISC_ATTR* p_first_attr = p_attr->attr_value.v.p_sub_attr;
+ if (SDP_DISC_ATTR_TYPE(p_first_attr->attr_len_type) == UUID_DESC_TYPE &&
+ SDP_DISC_ATTR_LEN(p_first_attr->attr_len_type) == 2) {
+ return p_first_attr->attr_value.v.u16;
+ } else if (SDP_DISC_ATTR_TYPE(p_first_attr->attr_len_type) ==
+ DATA_ELE_SEQ_DESC_TYPE) {
+ // Workaround for Toyota G Block car kit:
+ // It incorrectly puts an extra data element sequence in this attribute
+ for (tSDP_DISC_ATTR* p_extra_sattr =
+ p_first_attr->attr_value.v.p_sub_attr;
+ p_extra_sattr != nullptr;
+ p_extra_sattr = p_extra_sattr->p_next_attr) {
+ // Return the first UUID data element
+ if (SDP_DISC_ATTR_TYPE(p_extra_sattr->attr_len_type) ==
+ UUID_DESC_TYPE &&
+ SDP_DISC_ATTR_LEN(p_extra_sattr->attr_len_type) == 2) {
+ return p_extra_sattr->attr_value.v.u16;
+ }
+ }
+ } else {
+ LOG(WARNING) << __func__ << ": Bad Service Class ID list attribute";
+ return 0;
+ }
+ } else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) {
+ if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE &&
+ SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 2) {
+ return p_attr->attr_value.v.u16;
+ }
+ }
+ }
+ return 0;
+}
+
+void sdpu_log_attribute_metrics(const RawAddress& bda,
+ tSDP_DISCOVERY_DB* p_db) {
+ CHECK_NE(p_db, nullptr);
+ bool has_di_record = false;
+ for (tSDP_DISC_REC* p_rec = p_db->p_first_rec; p_rec != nullptr;
+ p_rec = p_rec->p_next_rec) {
+ uint16_t service_uuid = sdpu_find_most_specific_service_uuid(p_rec);
+ if (service_uuid == 0) {
+ LOG(INFO) << __func__ << ": skipping record without service uuid " << bda;
+ continue;
+ }
+ // Log the existence of a profile role
+ // This can be different from Bluetooth Profile Descriptor List
+ bluetooth::common::LogSdpAttribute(bda, service_uuid, 0, 0, nullptr);
+ // Log profile version from Bluetooth Profile Descriptor List
+ auto uuid_version_array = sdpu_find_profile_version(p_rec);
+ for (const auto& uuid_version_pair : uuid_version_array) {
+ uint16_t profile_uuid = uuid_version_pair.first;
+ uint16_t version = uuid_version_pair.second;
+ auto version_array = to_little_endian_array(version);
+ bluetooth::common::LogSdpAttribute(
+ bda, profile_uuid, ATTR_ID_BT_PROFILE_DESC_LIST, version_array.size(),
+ version_array.data());
+ }
+ // Log protocol version from Protocol Descriptor List
+ uint16_t protocol_uuid = 0;
+ switch (service_uuid) {
+ case UUID_SERVCLASS_AUDIO_SOURCE:
+ case UUID_SERVCLASS_AUDIO_SINK:
+ protocol_uuid = UUID_PROTOCOL_AVDTP;
+ break;
+ case UUID_SERVCLASS_AV_REMOTE_CONTROL:
+ case UUID_SERVCLASS_AV_REM_CTRL_CONTROL:
+ case UUID_SERVCLASS_AV_REM_CTRL_TARGET:
+ protocol_uuid = UUID_PROTOCOL_AVCTP;
+ break;
+ case UUID_SERVCLASS_PANU:
+ case UUID_SERVCLASS_GN:
+ protocol_uuid = UUID_PROTOCOL_BNEP;
+ break;
+ }
+ if (protocol_uuid != 0) {
+ tSDP_PROTOCOL_ELEM protocol_elements = {};
+ if (SDP_FindProtocolListElemInRec(p_rec, protocol_uuid,
+ &protocol_elements)) {
+ if (protocol_elements.num_params >= 1) {
+ uint16_t version = protocol_elements.params[0];
+ auto version_array = to_little_endian_array(version);
+ bluetooth::common::LogSdpAttribute(
+ bda, protocol_uuid, ATTR_ID_PROTOCOL_DESC_LIST,
+ version_array.size(), version_array.data());
+ }
+ }
+ }
+ // Log profile supported features from various supported feature attributes
+ switch (service_uuid) {
+ case UUID_SERVCLASS_AG_HANDSFREE:
+ case UUID_SERVCLASS_HF_HANDSFREE:
+ case UUID_SERVCLASS_AV_REMOTE_CONTROL:
+ case UUID_SERVCLASS_AV_REM_CTRL_CONTROL:
+ case UUID_SERVCLASS_AV_REM_CTRL_TARGET:
+ case UUID_SERVCLASS_AUDIO_SOURCE:
+ case UUID_SERVCLASS_AUDIO_SINK: {
+ tSDP_DISC_ATTR* p_attr =
+ SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES);
+ if (p_attr == nullptr) {
+ break;
+ }
+ uint16_t supported_features = p_attr->attr_value.v.u16;
+ auto version_array = to_little_endian_array(supported_features);
+ bluetooth::common::LogSdpAttribute(
+ bda, service_uuid, ATTR_ID_SUPPORTED_FEATURES, version_array.size(),
+ version_array.data());
+ break;
+ }
+ case UUID_SERVCLASS_MESSAGE_NOTIFICATION:
+ case UUID_SERVCLASS_MESSAGE_ACCESS: {
+ tSDP_DISC_ATTR* p_attr =
+ SDP_FindAttributeInRec(p_rec, ATTR_ID_MAP_SUPPORTED_FEATURES);
+ if (p_attr == nullptr) {
+ break;
+ }
+ uint32_t map_supported_features = p_attr->attr_value.v.u32;
+ auto features_array = to_little_endian_array(map_supported_features);
+ bluetooth::common::LogSdpAttribute(
+ bda, service_uuid, ATTR_ID_MAP_SUPPORTED_FEATURES,
+ features_array.size(), features_array.data());
+ break;
+ }
+ case UUID_SERVCLASS_PBAP_PCE:
+ case UUID_SERVCLASS_PBAP_PSE: {
+ tSDP_DISC_ATTR* p_attr =
+ SDP_FindAttributeInRec(p_rec, ATTR_ID_PBAP_SUPPORTED_FEATURES);
+ if (p_attr == nullptr) {
+ break;
+ }
+ uint32_t pbap_supported_features = p_attr->attr_value.v.u32;
+ auto features_array = to_little_endian_array(pbap_supported_features);
+ bluetooth::common::LogSdpAttribute(
+ bda, service_uuid, ATTR_ID_PBAP_SUPPORTED_FEATURES,
+ features_array.size(), features_array.data());
+ break;
+ }
+ }
+ if (service_uuid == UUID_SERVCLASS_PNP_INFORMATION) {
+ has_di_record = true;
+ }
+ }
+ // Log the first DI record if there is one
+ if (has_di_record) {
+ tSDP_DI_GET_RECORD di_record = {};
+ if (SDP_GetDiRecord(1, &di_record, p_db) == SDP_SUCCESS) {
+ auto version_array = to_little_endian_array(di_record.spec_id);
+ bluetooth::common::LogSdpAttribute(
+ bda, UUID_SERVCLASS_PNP_INFORMATION, ATTR_ID_SPECIFICATION_ID,
+ version_array.size(), version_array.data());
+ std::stringstream ss;
+ // [N - native]::SDP::[DIP - Device ID Profile]
+ ss << "N:SDP::DIP::" << loghex(di_record.rec.vendor_id_source);
+ bluetooth::common::LogManufacturerInfo(
+ bda, android::bluetooth::DeviceInfoSrcEnum::DEVICE_INFO_INTERNAL,
+ ss.str(), loghex(di_record.rec.vendor), loghex(di_record.rec.product),
+ loghex(di_record.rec.version), "");
+ }
+ }
+}
+
/*******************************************************************************
*
* Function sdpu_find_ccb_by_cid
diff --git a/stack/sdp/sdpint.h b/stack/sdp/sdpint.h
index 0d44c9d..6ba9597 100644
--- a/stack/sdp/sdpint.h
+++ b/stack/sdp/sdpint.h
@@ -247,6 +247,8 @@
/* Functions provided by sdp_utils.cc
*/
+extern void sdpu_log_attribute_metrics(const RawAddress& bda,
+ tSDP_DISCOVERY_DB* p_db);
extern tCONN_CB* sdpu_find_ccb_by_cid(uint16_t cid);
extern tCONN_CB* sdpu_find_ccb_by_db(tSDP_DISCOVERY_DB* p_db);
extern tCONN_CB* sdpu_allocate_ccb(void);
diff --git a/stack/smp/aes.cc b/stack/smp/aes.cc
deleted file mode 100644
index 362a4ee..0000000
--- a/stack/smp/aes.cc
+++ /dev/null
@@ -1,953 +0,0 @@
-/*
- ---------------------------------------------------------------------------
- Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.
-
- LICENSE TERMS
-
- The redistribution and use of this software (with or without changes)
- is allowed without the payment of fees or royalties provided that:
-
- 1. source code distributions include the above copyright notice, this
- list of conditions and the following disclaimer;
-
- 2. binary distributions include the above copyright notice, this list
- of conditions and the following disclaimer in their documentation;
-
- 3. the name of the copyright holder is not used to endorse products
- built using this software without specific written permission.
-
- DISCLAIMER
-
- This software is provided 'as is' with no explicit or implied warranties
- in respect of its properties, including, but not limited to, correctness
- and/or fitness for purpose.
- ---------------------------------------------------------------------------
- Issue 09/09/2006
-
- This is an AES implementation that uses only 8-bit byte operations on the
- cipher state (there are options to use 32-bit types if available).
-
- The combination of mix columns and byte substitution used here is based on
- that developed by Karl Malbrain. His contribution is acknowledged.
- */
-
-/* define if you have a fast memcpy function on your system */
-#if 1
-#define HAVE_MEMCPY
-#include <string.h>
-#if 0
-#if defined(_MSC_VER)
-#include <intrin.h>
-#pragma intrinsic(memcpy)
-#endif
-#endif
-#endif
-
-#include <stdlib.h>
-
-/* add the target configuration to allow using internal data types and
- * compilation options */
-#include "bt_target.h"
-
-/* define if you have fast 32-bit types on your system */
-#if 1
-#define HAVE_UINT_32T
-#endif
-
-/* define if you don't want any tables */
-#if 1
-#define USE_TABLES
-#endif
-
-/* On Intel Core 2 duo VERSION_1 is faster */
-
-/* alternative versions (test for performance on your system) */
-#if 1
-#define VERSION_1
-#endif
-
-#include "aes.h"
-
-#if defined(HAVE_UINT_32T)
-typedef uint32_t uint_32t;
-#endif
-
-/* functions for finite field multiplication in the AES Galois field */
-
-#define WPOLY 0x011b
-#define BPOLY 0x1b
-#define DPOLY 0x008d
-
-#define f1(x) (x)
-#define f2(x) (((x) << 1) ^ ((((x) >> 7) & 1) * WPOLY))
-#define f4(x) \
- (((x) << 2) ^ ((((x) >> 6) & 1) * WPOLY) ^ ((((x) >> 6) & 2) * WPOLY))
-#define f8(x) \
- (((x) << 3) ^ ((((x) >> 5) & 1) * WPOLY) ^ ((((x) >> 5) & 2) * WPOLY) ^ \
- ((((x) >> 5) & 4) * WPOLY))
-#define d2(x) (((x) >> 1) ^ ((x)&1 ? DPOLY : 0))
-
-#define f3(x) (f2(x) ^ (x))
-#define f9(x) (f8(x) ^ (x))
-#define fb(x) (f8(x) ^ f2(x) ^ (x))
-#define fd(x) (f8(x) ^ f4(x) ^ (x))
-#define fe(x) (f8(x) ^ f4(x) ^ f2(x))
-
-#if defined(USE_TABLES)
-
-#define sb_data(w) \
- { /* S Box data values */ \
- w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5), \
- w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), \
- w(0x76), w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), \
- w(0x47), w(0xf0), w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), \
- w(0xa4), w(0x72), w(0xc0), w(0xb7), w(0xfd), w(0x93), w(0x26), \
- w(0x36), w(0x3f), w(0xf7), w(0xcc), w(0x34), w(0xa5), w(0xe5), \
- w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15), w(0x04), w(0xc7), \
- w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a), w(0x07), \
- w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75), \
- w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), \
- w(0xa0), w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), \
- w(0x2f), w(0x84), w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), \
- w(0xfc), w(0xb1), w(0x5b), w(0x6a), w(0xcb), w(0xbe), w(0x39), \
- w(0x4a), w(0x4c), w(0x58), w(0xcf), w(0xd0), w(0xef), w(0xaa), \
- w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85), w(0x45), w(0xf9), \
- w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8), w(0x51), \
- w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5), \
- w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), \
- w(0xd2), w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), \
- w(0x44), w(0x17), w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), \
- w(0x5d), w(0x19), w(0x73), w(0x60), w(0x81), w(0x4f), w(0xdc), \
- w(0x22), w(0x2a), w(0x90), w(0x88), w(0x46), w(0xee), w(0xb8), \
- w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb), w(0xe0), w(0x32), \
- w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c), w(0xc2), \
- w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79), \
- w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), \
- w(0xa9), w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), \
- w(0xae), w(0x08), w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), \
- w(0xa6), w(0xb4), w(0xc6), w(0xe8), w(0xdd), w(0x74), w(0x1f), \
- w(0x4b), w(0xbd), w(0x8b), w(0x8a), w(0x70), w(0x3e), w(0xb5), \
- w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e), w(0x61), w(0x35), \
- w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e), w(0xe1), \
- w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94), \
- w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), \
- w(0xdf), w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), \
- w(0x42), w(0x68), w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), \
- w(0x54), w(0xbb), w(0x16) \
- }
-
-#define isb_data(w) \
- { /* inverse S Box data values */ \
- w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38), \
- w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), \
- w(0xfb), w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), \
- w(0xff), w(0x87), w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), \
- w(0xde), w(0xe9), w(0xcb), w(0x54), w(0x7b), w(0x94), w(0x32), \
- w(0xa6), w(0xc2), w(0x23), w(0x3d), w(0xee), w(0x4c), w(0x95), \
- w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e), w(0x08), w(0x2e), \
- w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2), w(0x76), \
- w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25), \
- w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), \
- w(0x16), w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), \
- w(0xb6), w(0x92), w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), \
- w(0xed), w(0xb9), w(0xda), w(0x5e), w(0x15), w(0x46), w(0x57), \
- w(0xa7), w(0x8d), w(0x9d), w(0x84), w(0x90), w(0xd8), w(0xab), \
- w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a), w(0xf7), w(0xe4), \
- w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06), w(0xd0), \
- w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02), \
- w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), \
- w(0x6b), w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), \
- w(0xdc), w(0xea), w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), \
- w(0xb4), w(0xe6), w(0x73), w(0x96), w(0xac), w(0x74), w(0x22), \
- w(0xe7), w(0xad), w(0x35), w(0x85), w(0xe2), w(0xf9), w(0x37), \
- w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e), w(0x47), w(0xf1), \
- w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89), w(0x6f), \
- w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b), \
- w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), \
- w(0x20), w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), \
- w(0x5a), w(0xf4), w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), \
- w(0x07), w(0xc7), w(0x31), w(0xb1), w(0x12), w(0x10), w(0x59), \
- w(0x27), w(0x80), w(0xec), w(0x5f), w(0x60), w(0x51), w(0x7f), \
- w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d), w(0x2d), w(0xe5), \
- w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef), w(0xa0), \
- w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0), \
- w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), \
- w(0x61), w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), \
- w(0xd6), w(0x26), w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), \
- w(0x21), w(0x0c), w(0x7d) \
- }
-
-#define mm_data(w) \
- { /* basic data for forming finite field tables */ \
- w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07), \
- w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), \
- w(0x0f), w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), \
- w(0x16), w(0x17), w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), \
- w(0x1d), w(0x1e), w(0x1f), w(0x20), w(0x21), w(0x22), w(0x23), \
- w(0x24), w(0x25), w(0x26), w(0x27), w(0x28), w(0x29), w(0x2a), \
- w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f), w(0x30), w(0x31), \
- w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37), w(0x38), \
- w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f), \
- w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), \
- w(0x47), w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), \
- w(0x4e), w(0x4f), w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), \
- w(0x55), w(0x56), w(0x57), w(0x58), w(0x59), w(0x5a), w(0x5b), \
- w(0x5c), w(0x5d), w(0x5e), w(0x5f), w(0x60), w(0x61), w(0x62), \
- w(0x63), w(0x64), w(0x65), w(0x66), w(0x67), w(0x68), w(0x69), \
- w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f), w(0x70), \
- w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77), \
- w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), \
- w(0x7f), w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), \
- w(0x86), w(0x87), w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), \
- w(0x8d), w(0x8e), w(0x8f), w(0x90), w(0x91), w(0x92), w(0x93), \
- w(0x94), w(0x95), w(0x96), w(0x97), w(0x98), w(0x99), w(0x9a), \
- w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f), w(0xa0), w(0xa1), \
- w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7), w(0xa8), \
- w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf), \
- w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), \
- w(0xb7), w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), \
- w(0xbe), w(0xbf), w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), \
- w(0xc5), w(0xc6), w(0xc7), w(0xc8), w(0xc9), w(0xca), w(0xcb), \
- w(0xcc), w(0xcd), w(0xce), w(0xcf), w(0xd0), w(0xd1), w(0xd2), \
- w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7), w(0xd8), w(0xd9), \
- w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf), w(0xe0), \
- w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7), \
- w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), \
- w(0xef), w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), \
- w(0xf6), w(0xf7), w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), \
- w(0xfd), w(0xfe), w(0xff) \
- }
-
-static const uint_8t sbox[256] = sb_data(f1);
-static const uint_8t isbox[256] = isb_data(f1);
-
-static const uint_8t gfm2_sbox[256] = sb_data(f2);
-static const uint_8t gfm3_sbox[256] = sb_data(f3);
-
-static const uint_8t gfmul_9[256] = mm_data(f9);
-static const uint_8t gfmul_b[256] = mm_data(fb);
-static const uint_8t gfmul_d[256] = mm_data(fd);
-static const uint_8t gfmul_e[256] = mm_data(fe);
-
-#define s_box(x) sbox[(x)]
-#define is_box(x) isbox[(x)]
-#define gfm2_sb(x) gfm2_sbox[(x)]
-#define gfm3_sb(x) gfm3_sbox[(x)]
-#define gfm_9(x) gfmul_9[(x)]
-#define gfm_b(x) gfmul_b[(x)]
-#define gfm_d(x) gfmul_d[(x)]
-#define gfm_e(x) gfmul_e[(x)]
-
-#else
-
-/* this is the high bit of x right shifted by 1 */
-/* position. Since the starting polynomial has */
-/* 9 bits (0x11b), this right shift keeps the */
-/* values of all top bits within a byte */
-
-static uint_8t hibit(const uint_8t x) {
- uint_8t r = (uint_8t)((x >> 1) | (x >> 2));
-
- r |= (r >> 2);
- r |= (r >> 4);
- return (r + 1) >> 1;
-}
-
-/* return the inverse of the finite field element x */
-
-static uint_8t gf_inv(const uint_8t x) {
- uint_8t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0;
-
- if (x < 2) return x;
-
- for (;;) {
- if (n1)
- while (n2 >= n1) /* divide polynomial p2 by p1 */
- {
- n2 /= n1; /* shift smaller polynomial left */
- p2 ^= (p1 * n2) & 0xff; /* and remove from larger one */
- v2 ^= (v1 * n2); /* shift accumulated value and */
- n2 = hibit(p2); /* add into result */
- }
- else
- return v1;
-
- if (n2) /* repeat with values swapped */
- while (n1 >= n2) {
- n1 /= n2;
- p1 ^= p2 * n1;
- v1 ^= v2 * n1;
- n1 = hibit(p1);
- }
- else
- return v2;
- }
-}
-
-/* The forward and inverse affine transformations used in the S-box */
-uint_8t fwd_affine(const uint_8t x) {
-#if defined(HAVE_UINT_32T)
- uint_32t w = x;
- w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4);
- return 0x63 ^ ((w ^ (w >> 8)) & 0xff);
-#else
- return 0x63 ^ x ^ (x << 1) ^ (x << 2) ^ (x << 3) ^ (x << 4) ^ (x >> 7) ^
- (x >> 6) ^ (x >> 5) ^ (x >> 4);
-#endif
-}
-
-uint_8t inv_affine(const uint_8t x) {
-#if defined(HAVE_UINT_32T)
- uint_32t w = x;
- w = (w << 1) ^ (w << 3) ^ (w << 6);
- return 0x05 ^ ((w ^ (w >> 8)) & 0xff);
-#else
- return 0x05 ^ (x << 1) ^ (x << 3) ^ (x << 6) ^ (x >> 7) ^ (x >> 5) ^ (x >> 2);
-#endif
-}
-
-#define s_box(x) fwd_affine(gf_inv(x))
-#define is_box(x) gf_inv(inv_affine(x))
-#define gfm2_sb(x) f2(s_box(x))
-#define gfm3_sb(x) f3(s_box(x))
-#define gfm_9(x) f9(x)
-#define gfm_b(x) fb(x)
-#define gfm_d(x) fd(x)
-#define gfm_e(x) fe(x)
-
-#endif
-
-#if defined(HAVE_MEMCPY)
-#define block_copy_nn(d, s, l) memcpy(d, s, l)
-#define block_copy(d, s) memcpy(d, s, N_BLOCK)
-#else
-#define block_copy_nn(d, s, l) copy_block_nn(d, s, l)
-#define block_copy(d, s) copy_block(d, s)
-#endif
-
-#if !defined(HAVE_MEMCPY)
-static void copy_block(void* d, const void* s) {
-#if defined(HAVE_UINT_32T)
- ((uint_32t*)d)[0] = ((uint_32t*)s)[0];
- ((uint_32t*)d)[1] = ((uint_32t*)s)[1];
- ((uint_32t*)d)[2] = ((uint_32t*)s)[2];
- ((uint_32t*)d)[3] = ((uint_32t*)s)[3];
-#else
- ((uint_8t*)d)[0] = ((uint_8t*)s)[0];
- ((uint_8t*)d)[1] = ((uint_8t*)s)[1];
- ((uint_8t*)d)[2] = ((uint_8t*)s)[2];
- ((uint_8t*)d)[3] = ((uint_8t*)s)[3];
- ((uint_8t*)d)[4] = ((uint_8t*)s)[4];
- ((uint_8t*)d)[5] = ((uint_8t*)s)[5];
- ((uint_8t*)d)[6] = ((uint_8t*)s)[6];
- ((uint_8t*)d)[7] = ((uint_8t*)s)[7];
- ((uint_8t*)d)[8] = ((uint_8t*)s)[8];
- ((uint_8t*)d)[9] = ((uint_8t*)s)[9];
- ((uint_8t*)d)[10] = ((uint_8t*)s)[10];
- ((uint_8t*)d)[11] = ((uint_8t*)s)[11];
- ((uint_8t*)d)[12] = ((uint_8t*)s)[12];
- ((uint_8t*)d)[13] = ((uint_8t*)s)[13];
- ((uint_8t*)d)[14] = ((uint_8t*)s)[14];
- ((uint_8t*)d)[15] = ((uint_8t*)s)[15];
-#endif
-}
-
-static void copy_block_nn(void* d, const void* s, uint_8t nn) {
- while (nn--) *((uint_8t*)d)++ = *((uint_8t*)s)++;
-}
-#endif
-
-static void xor_block(void* d, const void* s) {
-#if defined(HAVE_UINT_32T)
- ((uint_32t*)d)[0] ^= ((uint_32t*)s)[0];
- ((uint_32t*)d)[1] ^= ((uint_32t*)s)[1];
- ((uint_32t*)d)[2] ^= ((uint_32t*)s)[2];
- ((uint_32t*)d)[3] ^= ((uint_32t*)s)[3];
-#else
- ((uint_8t*)d)[0] ^= ((uint_8t*)s)[0];
- ((uint_8t*)d)[1] ^= ((uint_8t*)s)[1];
- ((uint_8t*)d)[2] ^= ((uint_8t*)s)[2];
- ((uint_8t*)d)[3] ^= ((uint_8t*)s)[3];
- ((uint_8t*)d)[4] ^= ((uint_8t*)s)[4];
- ((uint_8t*)d)[5] ^= ((uint_8t*)s)[5];
- ((uint_8t*)d)[6] ^= ((uint_8t*)s)[6];
- ((uint_8t*)d)[7] ^= ((uint_8t*)s)[7];
- ((uint_8t*)d)[8] ^= ((uint_8t*)s)[8];
- ((uint_8t*)d)[9] ^= ((uint_8t*)s)[9];
- ((uint_8t*)d)[10] ^= ((uint_8t*)s)[10];
- ((uint_8t*)d)[11] ^= ((uint_8t*)s)[11];
- ((uint_8t*)d)[12] ^= ((uint_8t*)s)[12];
- ((uint_8t*)d)[13] ^= ((uint_8t*)s)[13];
- ((uint_8t*)d)[14] ^= ((uint_8t*)s)[14];
- ((uint_8t*)d)[15] ^= ((uint_8t*)s)[15];
-#endif
-}
-
-static void copy_and_key(void* d, const void* s, const void* k) {
-#if defined(HAVE_UINT_32T)
- ((uint_32t*)d)[0] = ((uint_32t*)s)[0] ^ ((uint_32t*)k)[0];
- ((uint_32t*)d)[1] = ((uint_32t*)s)[1] ^ ((uint_32t*)k)[1];
- ((uint_32t*)d)[2] = ((uint_32t*)s)[2] ^ ((uint_32t*)k)[2];
- ((uint_32t*)d)[3] = ((uint_32t*)s)[3] ^ ((uint_32t*)k)[3];
-#elif 1
- ((uint_8t*)d)[0] = ((uint_8t*)s)[0] ^ ((uint_8t*)k)[0];
- ((uint_8t*)d)[1] = ((uint_8t*)s)[1] ^ ((uint_8t*)k)[1];
- ((uint_8t*)d)[2] = ((uint_8t*)s)[2] ^ ((uint_8t*)k)[2];
- ((uint_8t*)d)[3] = ((uint_8t*)s)[3] ^ ((uint_8t*)k)[3];
- ((uint_8t*)d)[4] = ((uint_8t*)s)[4] ^ ((uint_8t*)k)[4];
- ((uint_8t*)d)[5] = ((uint_8t*)s)[5] ^ ((uint_8t*)k)[5];
- ((uint_8t*)d)[6] = ((uint_8t*)s)[6] ^ ((uint_8t*)k)[6];
- ((uint_8t*)d)[7] = ((uint_8t*)s)[7] ^ ((uint_8t*)k)[7];
- ((uint_8t*)d)[8] = ((uint_8t*)s)[8] ^ ((uint_8t*)k)[8];
- ((uint_8t*)d)[9] = ((uint_8t*)s)[9] ^ ((uint_8t*)k)[9];
- ((uint_8t*)d)[10] = ((uint_8t*)s)[10] ^ ((uint_8t*)k)[10];
- ((uint_8t*)d)[11] = ((uint_8t*)s)[11] ^ ((uint_8t*)k)[11];
- ((uint_8t*)d)[12] = ((uint_8t*)s)[12] ^ ((uint_8t*)k)[12];
- ((uint_8t*)d)[13] = ((uint_8t*)s)[13] ^ ((uint_8t*)k)[13];
- ((uint_8t*)d)[14] = ((uint_8t*)s)[14] ^ ((uint_8t*)k)[14];
- ((uint_8t*)d)[15] = ((uint_8t*)s)[15] ^ ((uint_8t*)k)[15];
-#else
- block_copy(d, s);
- xor_block(d, k);
-#endif
-}
-
-static void add_round_key(uint_8t d[N_BLOCK], const uint_8t k[N_BLOCK]) {
- xor_block(d, k);
-}
-
-static void shift_sub_rows(uint_8t st[N_BLOCK]) {
- uint_8t tt;
-
- st[0] = s_box(st[0]);
- st[4] = s_box(st[4]);
- st[8] = s_box(st[8]);
- st[12] = s_box(st[12]);
-
- tt = st[1];
- st[1] = s_box(st[5]);
- st[5] = s_box(st[9]);
- st[9] = s_box(st[13]);
- st[13] = s_box(tt);
-
- tt = st[2];
- st[2] = s_box(st[10]);
- st[10] = s_box(tt);
- tt = st[6];
- st[6] = s_box(st[14]);
- st[14] = s_box(tt);
-
- tt = st[15];
- st[15] = s_box(st[11]);
- st[11] = s_box(st[7]);
- st[7] = s_box(st[3]);
- st[3] = s_box(tt);
-}
-
-static void inv_shift_sub_rows(uint_8t st[N_BLOCK]) {
- uint_8t tt;
-
- st[0] = is_box(st[0]);
- st[4] = is_box(st[4]);
- st[8] = is_box(st[8]);
- st[12] = is_box(st[12]);
-
- tt = st[13];
- st[13] = is_box(st[9]);
- st[9] = is_box(st[5]);
- st[5] = is_box(st[1]);
- st[1] = is_box(tt);
-
- tt = st[2];
- st[2] = is_box(st[10]);
- st[10] = is_box(tt);
- tt = st[6];
- st[6] = is_box(st[14]);
- st[14] = is_box(tt);
-
- tt = st[3];
- st[3] = is_box(st[7]);
- st[7] = is_box(st[11]);
- st[11] = is_box(st[15]);
- st[15] = is_box(tt);
-}
-
-#if defined(VERSION_1)
-static void mix_sub_columns(uint_8t dt[N_BLOCK]) {
- uint_8t st[N_BLOCK];
- block_copy(st, dt);
-#else
-static void mix_sub_columns(uint_8t dt[N_BLOCK], uint_8t st[N_BLOCK]) {
-#endif
- dt[0] = gfm2_sb(st[0]) ^ gfm3_sb(st[5]) ^ s_box(st[10]) ^ s_box(st[15]);
- dt[1] = s_box(st[0]) ^ gfm2_sb(st[5]) ^ gfm3_sb(st[10]) ^ s_box(st[15]);
- dt[2] = s_box(st[0]) ^ s_box(st[5]) ^ gfm2_sb(st[10]) ^ gfm3_sb(st[15]);
- dt[3] = gfm3_sb(st[0]) ^ s_box(st[5]) ^ s_box(st[10]) ^ gfm2_sb(st[15]);
-
- dt[4] = gfm2_sb(st[4]) ^ gfm3_sb(st[9]) ^ s_box(st[14]) ^ s_box(st[3]);
- dt[5] = s_box(st[4]) ^ gfm2_sb(st[9]) ^ gfm3_sb(st[14]) ^ s_box(st[3]);
- dt[6] = s_box(st[4]) ^ s_box(st[9]) ^ gfm2_sb(st[14]) ^ gfm3_sb(st[3]);
- dt[7] = gfm3_sb(st[4]) ^ s_box(st[9]) ^ s_box(st[14]) ^ gfm2_sb(st[3]);
-
- dt[8] = gfm2_sb(st[8]) ^ gfm3_sb(st[13]) ^ s_box(st[2]) ^ s_box(st[7]);
- dt[9] = s_box(st[8]) ^ gfm2_sb(st[13]) ^ gfm3_sb(st[2]) ^ s_box(st[7]);
- dt[10] = s_box(st[8]) ^ s_box(st[13]) ^ gfm2_sb(st[2]) ^ gfm3_sb(st[7]);
- dt[11] = gfm3_sb(st[8]) ^ s_box(st[13]) ^ s_box(st[2]) ^ gfm2_sb(st[7]);
-
- dt[12] = gfm2_sb(st[12]) ^ gfm3_sb(st[1]) ^ s_box(st[6]) ^ s_box(st[11]);
- dt[13] = s_box(st[12]) ^ gfm2_sb(st[1]) ^ gfm3_sb(st[6]) ^ s_box(st[11]);
- dt[14] = s_box(st[12]) ^ s_box(st[1]) ^ gfm2_sb(st[6]) ^ gfm3_sb(st[11]);
- dt[15] = gfm3_sb(st[12]) ^ s_box(st[1]) ^ s_box(st[6]) ^ gfm2_sb(st[11]);
-}
-
-#if defined(VERSION_1)
-static void inv_mix_sub_columns(uint_8t dt[N_BLOCK]) {
- uint_8t st[N_BLOCK];
- block_copy(st, dt);
-#else
-static void inv_mix_sub_columns(uint_8t dt[N_BLOCK], uint_8t st[N_BLOCK]) {
-#endif
- dt[0] = is_box(gfm_e(st[0]) ^ gfm_b(st[1]) ^ gfm_d(st[2]) ^ gfm_9(st[3]));
- dt[5] = is_box(gfm_9(st[0]) ^ gfm_e(st[1]) ^ gfm_b(st[2]) ^ gfm_d(st[3]));
- dt[10] = is_box(gfm_d(st[0]) ^ gfm_9(st[1]) ^ gfm_e(st[2]) ^ gfm_b(st[3]));
- dt[15] = is_box(gfm_b(st[0]) ^ gfm_d(st[1]) ^ gfm_9(st[2]) ^ gfm_e(st[3]));
-
- dt[4] = is_box(gfm_e(st[4]) ^ gfm_b(st[5]) ^ gfm_d(st[6]) ^ gfm_9(st[7]));
- dt[9] = is_box(gfm_9(st[4]) ^ gfm_e(st[5]) ^ gfm_b(st[6]) ^ gfm_d(st[7]));
- dt[14] = is_box(gfm_d(st[4]) ^ gfm_9(st[5]) ^ gfm_e(st[6]) ^ gfm_b(st[7]));
- dt[3] = is_box(gfm_b(st[4]) ^ gfm_d(st[5]) ^ gfm_9(st[6]) ^ gfm_e(st[7]));
-
- dt[8] = is_box(gfm_e(st[8]) ^ gfm_b(st[9]) ^ gfm_d(st[10]) ^ gfm_9(st[11]));
- dt[13] = is_box(gfm_9(st[8]) ^ gfm_e(st[9]) ^ gfm_b(st[10]) ^ gfm_d(st[11]));
- dt[2] = is_box(gfm_d(st[8]) ^ gfm_9(st[9]) ^ gfm_e(st[10]) ^ gfm_b(st[11]));
- dt[7] = is_box(gfm_b(st[8]) ^ gfm_d(st[9]) ^ gfm_9(st[10]) ^ gfm_e(st[11]));
-
- dt[12] =
- is_box(gfm_e(st[12]) ^ gfm_b(st[13]) ^ gfm_d(st[14]) ^ gfm_9(st[15]));
- dt[1] = is_box(gfm_9(st[12]) ^ gfm_e(st[13]) ^ gfm_b(st[14]) ^ gfm_d(st[15]));
- dt[6] = is_box(gfm_d(st[12]) ^ gfm_9(st[13]) ^ gfm_e(st[14]) ^ gfm_b(st[15]));
- dt[11] =
- is_box(gfm_b(st[12]) ^ gfm_d(st[13]) ^ gfm_9(st[14]) ^ gfm_e(st[15]));
-}
-
-#if defined(AES_ENC_PREKEYED) || defined(AES_DEC_PREKEYED)
-
-/* Set the cipher key for the pre-keyed version */
-/* NOTE: If the length_type used for the key length is an
- unsigned 8-bit character, a key length of 256 bits must
- be entered as a length in bytes (valid inputs are hence
- 128, 192, 16, 24 and 32).
-*/
-
-return_type aes_set_key(const unsigned char key[], length_type keylen,
- aes_context ctx[1]) {
- uint_8t cc, rc, hi;
-
- switch (keylen) {
- case 16:
- case 128: /* length in bits (128 = 8*16) */
- keylen = 16;
- break;
- case 24:
- case 192: /* length in bits (192 = 8*24) */
- keylen = 24;
- break;
- case 32:
- /* case 256: length in bits (256 = 8*32) */
- keylen = 32;
- break;
- default:
- ctx->rnd = 0;
- return (return_type)-1;
- }
- block_copy_nn(ctx->ksch, key, keylen);
- hi = (keylen + 28) << 2;
- ctx->rnd = (hi >> 4) - 1;
- for (cc = keylen, rc = 1; cc < hi; cc += 4) {
- uint_8t tt, t0, t1, t2, t3;
-
- t0 = ctx->ksch[cc - 4];
- t1 = ctx->ksch[cc - 3];
- t2 = ctx->ksch[cc - 2];
- t3 = ctx->ksch[cc - 1];
- if (cc % keylen == 0) {
- tt = t0;
- t0 = s_box(t1) ^ rc;
- t1 = s_box(t2);
- t2 = s_box(t3);
- t3 = s_box(tt);
- rc = f2(rc);
- } else if (keylen > 24 && cc % keylen == 16) {
- t0 = s_box(t0);
- t1 = s_box(t1);
- t2 = s_box(t2);
- t3 = s_box(t3);
- }
- tt = cc - keylen;
- ctx->ksch[cc + 0] = ctx->ksch[tt + 0] ^ t0;
- ctx->ksch[cc + 1] = ctx->ksch[tt + 1] ^ t1;
- ctx->ksch[cc + 2] = ctx->ksch[tt + 2] ^ t2;
- ctx->ksch[cc + 3] = ctx->ksch[tt + 3] ^ t3;
- }
- return 0;
-}
-
-#endif
-
-#if defined(AES_ENC_PREKEYED)
-
-/* Encrypt a single block of 16 bytes */
-
-return_type aes_encrypt(const unsigned char in[N_BLOCK],
- unsigned char out[N_BLOCK], const aes_context ctx[1]) {
- if (ctx->rnd) {
- uint_8t s1[N_BLOCK], r;
- copy_and_key(s1, in, ctx->ksch);
-
- for (r = 1; r < ctx->rnd; ++r)
-#if defined(VERSION_1)
- {
- mix_sub_columns(s1);
- add_round_key(s1, ctx->ksch + r * N_BLOCK);
- }
-#else
- {
- uint_8t s2[N_BLOCK];
- mix_sub_columns(s2, s1);
- copy_and_key(s1, s2, ctx->ksch + r * N_BLOCK);
- }
-#endif
- shift_sub_rows(s1);
- copy_and_key(out, s1, ctx->ksch + r * N_BLOCK);
- } else
- return (return_type)-1;
- return 0;
-}
-
-/* CBC encrypt a number of blocks (input and return an IV) */
-
-return_type aes_cbc_encrypt(const unsigned char* in, unsigned char* out,
- int n_block, unsigned char iv[N_BLOCK],
- const aes_context ctx[1]) {
- while (n_block--) {
- xor_block(iv, in);
- if (aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE;
- memcpy(out, iv, N_BLOCK);
- in += N_BLOCK;
- out += N_BLOCK;
- }
- return EXIT_SUCCESS;
-}
-
-#endif
-
-#if defined(AES_DEC_PREKEYED)
-
-/* Decrypt a single block of 16 bytes */
-
-return_type aes_decrypt(const unsigned char in[N_BLOCK],
- unsigned char out[N_BLOCK], const aes_context ctx[1]) {
- if (ctx->rnd) {
- uint_8t s1[N_BLOCK], r;
- copy_and_key(s1, in, ctx->ksch + ctx->rnd * N_BLOCK);
- inv_shift_sub_rows(s1);
-
- for (r = ctx->rnd; --r;)
-#if defined(VERSION_1)
- {
- add_round_key(s1, ctx->ksch + r * N_BLOCK);
- inv_mix_sub_columns(s1);
- }
-#else
- {
- uint_8t s2[N_BLOCK];
- copy_and_key(s2, s1, ctx->ksch + r * N_BLOCK);
- inv_mix_sub_columns(s1, s2);
- }
-#endif
- copy_and_key(out, s1, ctx->ksch);
- } else
- return (return_type)-1;
- return 0;
-}
-
-/* CBC decrypt a number of blocks (input and return an IV) */
-
-return_type aes_cbc_decrypt(const unsigned char* in, unsigned char* out,
- int n_block, unsigned char iv[N_BLOCK],
- const aes_context ctx[1]) {
- while (n_block--) {
- uint_8t tmp[N_BLOCK];
-
- memcpy(tmp, in, N_BLOCK);
- if (aes_decrypt(in, out, ctx) != EXIT_SUCCESS) return EXIT_FAILURE;
- xor_block(out, iv);
- memcpy(iv, tmp, N_BLOCK);
- in += N_BLOCK;
- out += N_BLOCK;
- }
- return EXIT_SUCCESS;
-}
-
-#endif
-
-#if defined(AES_ENC_128_OTFK)
-
-/* The 'on the fly' encryption key update for for 128 bit keys */
-
-static void update_encrypt_key_128(uint_8t k[N_BLOCK], uint_8t* rc) {
- uint_8t cc;
-
- k[0] ^= s_box(k[13]) ^ *rc;
- k[1] ^= s_box(k[14]);
- k[2] ^= s_box(k[15]);
- k[3] ^= s_box(k[12]);
- *rc = f2(*rc);
-
- for (cc = 4; cc < 16; cc += 4) {
- k[cc + 0] ^= k[cc - 4];
- k[cc + 1] ^= k[cc - 3];
- k[cc + 2] ^= k[cc - 2];
- k[cc + 3] ^= k[cc - 1];
- }
-}
-
-/* Encrypt a single block of 16 bytes with 'on the fly' 128 bit keying */
-
-void aes_encrypt_128(const unsigned char in[N_BLOCK],
- unsigned char out[N_BLOCK],
- const unsigned char key[N_BLOCK],
- unsigned char o_key[N_BLOCK]) {
- uint_8t s1[N_BLOCK], r, rc = 1;
-
- if (o_key != key) block_copy(o_key, key);
- copy_and_key(s1, in, o_key);
-
- for (r = 1; r < 10; ++r)
-#if defined(VERSION_1)
- {
- mix_sub_columns(s1);
- update_encrypt_key_128(o_key, &rc);
- add_round_key(s1, o_key);
- }
-#else
- {
- uint_8t s2[N_BLOCK];
- mix_sub_columns(s2, s1);
- update_encrypt_key_128(o_key, &rc);
- copy_and_key(s1, s2, o_key);
- }
-#endif
-
- shift_sub_rows(s1);
- update_encrypt_key_128(o_key, &rc);
- copy_and_key(out, s1, o_key);
-}
-
-#endif
-
-#if defined(AES_DEC_128_OTFK)
-
-/* The 'on the fly' decryption key update for for 128 bit keys */
-
-static void update_decrypt_key_128(uint_8t k[N_BLOCK], uint_8t* rc) {
- uint_8t cc;
-
- for (cc = 12; cc > 0; cc -= 4) {
- k[cc + 0] ^= k[cc - 4];
- k[cc + 1] ^= k[cc - 3];
- k[cc + 2] ^= k[cc - 2];
- k[cc + 3] ^= k[cc - 1];
- }
- *rc = d2(*rc);
- k[0] ^= s_box(k[13]) ^ *rc;
- k[1] ^= s_box(k[14]);
- k[2] ^= s_box(k[15]);
- k[3] ^= s_box(k[12]);
-}
-
-/* Decrypt a single block of 16 bytes with 'on the fly' 128 bit keying */
-
-void aes_decrypt_128(const unsigned char in[N_BLOCK],
- unsigned char out[N_BLOCK],
- const unsigned char key[N_BLOCK],
- unsigned char o_key[N_BLOCK]) {
- uint_8t s1[N_BLOCK], r, rc = 0x6c;
- if (o_key != key) block_copy(o_key, key);
-
- copy_and_key(s1, in, o_key);
- inv_shift_sub_rows(s1);
-
- for (r = 10; --r;)
-#if defined(VERSION_1)
- {
- update_decrypt_key_128(o_key, &rc);
- add_round_key(s1, o_key);
- inv_mix_sub_columns(s1);
- }
-#else
- {
- uint_8t s2[N_BLOCK];
- update_decrypt_key_128(o_key, &rc);
- copy_and_key(s2, s1, o_key);
- inv_mix_sub_columns(s1, s2);
- }
-#endif
- update_decrypt_key_128(o_key, &rc);
- copy_and_key(out, s1, o_key);
-}
-
-#endif
-
-#if defined(AES_ENC_256_OTFK)
-
-/* The 'on the fly' encryption key update for for 256 bit keys */
-
-static void update_encrypt_key_256(uint_8t k[2 * N_BLOCK], uint_8t* rc) {
- uint_8t cc;
-
- k[0] ^= s_box(k[29]) ^ *rc;
- k[1] ^= s_box(k[30]);
- k[2] ^= s_box(k[31]);
- k[3] ^= s_box(k[28]);
- *rc = f2(*rc);
-
- for (cc = 4; cc < 16; cc += 4) {
- k[cc + 0] ^= k[cc - 4];
- k[cc + 1] ^= k[cc - 3];
- k[cc + 2] ^= k[cc - 2];
- k[cc + 3] ^= k[cc - 1];
- }
-
- k[16] ^= s_box(k[12]);
- k[17] ^= s_box(k[13]);
- k[18] ^= s_box(k[14]);
- k[19] ^= s_box(k[15]);
-
- for (cc = 20; cc < 32; cc += 4) {
- k[cc + 0] ^= k[cc - 4];
- k[cc + 1] ^= k[cc - 3];
- k[cc + 2] ^= k[cc - 2];
- k[cc + 3] ^= k[cc - 1];
- }
-}
-
-/* Encrypt a single block of 16 bytes with 'on the fly' 256 bit keying */
-
-void aes_encrypt_256(const unsigned char in[N_BLOCK],
- unsigned char out[N_BLOCK],
- const unsigned char key[2 * N_BLOCK],
- unsigned char o_key[2 * N_BLOCK]) {
- uint_8t s1[N_BLOCK], r, rc = 1;
- if (o_key != key) {
- block_copy(o_key, key);
- block_copy(o_key + 16, key + 16);
- }
- copy_and_key(s1, in, o_key);
-
- for (r = 1; r < 14; ++r)
-#if defined(VERSION_1)
- {
- mix_sub_columns(s1);
- if (r & 1)
- add_round_key(s1, o_key + 16);
- else {
- update_encrypt_key_256(o_key, &rc);
- add_round_key(s1, o_key);
- }
- }
-#else
- {
- uint_8t s2[N_BLOCK];
- mix_sub_columns(s2, s1);
- if (r & 1)
- copy_and_key(s1, s2, o_key + 16);
- else {
- update_encrypt_key_256(o_key, &rc);
- copy_and_key(s1, s2, o_key);
- }
- }
-#endif
-
- shift_sub_rows(s1);
- update_encrypt_key_256(o_key, &rc);
- copy_and_key(out, s1, o_key);
-}
-
-#endif
-
-#if defined(AES_DEC_256_OTFK)
-
-/* The 'on the fly' encryption key update for for 256 bit keys */
-
-static void update_decrypt_key_256(uint_8t k[2 * N_BLOCK], uint_8t* rc) {
- uint_8t cc;
-
- for (cc = 28; cc > 16; cc -= 4) {
- k[cc + 0] ^= k[cc - 4];
- k[cc + 1] ^= k[cc - 3];
- k[cc + 2] ^= k[cc - 2];
- k[cc + 3] ^= k[cc - 1];
- }
-
- k[16] ^= s_box(k[12]);
- k[17] ^= s_box(k[13]);
- k[18] ^= s_box(k[14]);
- k[19] ^= s_box(k[15]);
-
- for (cc = 12; cc > 0; cc -= 4) {
- k[cc + 0] ^= k[cc - 4];
- k[cc + 1] ^= k[cc - 3];
- k[cc + 2] ^= k[cc - 2];
- k[cc + 3] ^= k[cc - 1];
- }
-
- *rc = d2(*rc);
- k[0] ^= s_box(k[29]) ^ *rc;
- k[1] ^= s_box(k[30]);
- k[2] ^= s_box(k[31]);
- k[3] ^= s_box(k[28]);
-}
-
-/* Decrypt a single block of 16 bytes with 'on the fly'
- 256 bit keying
-*/
-void aes_decrypt_256(const unsigned char in[N_BLOCK],
- unsigned char out[N_BLOCK],
- const unsigned char key[2 * N_BLOCK],
- unsigned char o_key[2 * N_BLOCK]) {
- uint_8t s1[N_BLOCK], r, rc = 0x80;
-
- if (o_key != key) {
- block_copy(o_key, key);
- block_copy(o_key + 16, key + 16);
- }
-
- copy_and_key(s1, in, o_key);
- inv_shift_sub_rows(s1);
-
- for (r = 14; --r;)
-#if defined(VERSION_1)
- {
- if ((r & 1)) {
- update_decrypt_key_256(o_key, &rc);
- add_round_key(s1, o_key + 16);
- } else
- add_round_key(s1, o_key);
- inv_mix_sub_columns(s1);
- }
-#else
- {
- uint_8t s2[N_BLOCK];
- if ((r & 1)) {
- update_decrypt_key_256(o_key, &rc);
- copy_and_key(s2, s1, o_key + 16);
- } else
- copy_and_key(s2, s1, o_key);
- inv_mix_sub_columns(s1, s2);
- }
-#endif
- copy_and_key(out, s1, o_key);
-}
-
-#endif
diff --git a/stack/smp/crypto_toolbox.h b/stack/smp/crypto_toolbox.h
new file mode 100644
index 0000000..d3fceff
--- /dev/null
+++ b/stack/smp/crypto_toolbox.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 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 "stack/include/bt_types.h"
+
+/* Functions below implement cryptographic toolbox, as described in BT Spec
+ * Ver 5.0 | Vol 3, Part H CRYPTOGRAPHIC TOOLBOX. Please see the spec for
+ * description.
+ *
+ * Example of usage is avaliable in cryptographic_toolbox_test.cc */
+
+extern Octet16 smp_calculate_f4(uint8_t* u, uint8_t* v, const Octet16& x,
+ uint8_t z);
+extern uint32_t smp_calculate_g2(uint8_t* u, uint8_t* v, const Octet16& x,
+ const Octet16& y);
+extern void smp_calculate_f5(uint8_t* w, const Octet16& n1, const Octet16& n2,
+ uint8_t* a1, uint8_t* a2, Octet16* mac_key,
+ Octet16* ltk);
+extern Octet16 smp_calculate_f6(const Octet16& w, const Octet16& n1,
+ const Octet16& n2, const Octet16& r,
+ uint8_t* iocap, uint8_t* a1, uint8_t* a2);
+extern Octet16 smp_calculate_h6(const Octet16& w, std::array<uint8_t, 4> keyid);
+extern Octet16 smp_calculate_h7(const Octet16& salt, const Octet16& w);
+extern Octet16 smp_calculate_ltk_to_link_key(const Octet16& ltk, bool use_h7);
+extern Octet16 smp_calculate_link_key_to_ltk(const Octet16& link_key,
+ bool use_h7);
diff --git a/stack/smp/p_256_curvepara.cc b/stack/smp/p_256_curvepara.cc
index 5fb71a3..ebdf266 100644
--- a/stack/smp/p_256_curvepara.cc
+++ b/stack/smp/p_256_curvepara.cc
@@ -25,53 +25,49 @@
#include <string.h>
#include "p_256_ecc_pp.h"
-void p_256_init_curve(uint32_t keyLength) {
- elliptic_curve_t* ec;
+void p_256_init_curve() {
+ elliptic_curve_t* ec = &curve_p256;
- if (keyLength == KEY_LENGTH_DWORDS_P256) {
- ec = &curve_p256;
+ ec->p[7] = 0xFFFFFFFF;
+ ec->p[6] = 0x00000001;
+ ec->p[5] = 0x0;
+ ec->p[4] = 0x0;
+ ec->p[3] = 0x0;
+ ec->p[2] = 0xFFFFFFFF;
+ ec->p[1] = 0xFFFFFFFF;
+ ec->p[0] = 0xFFFFFFFF;
- ec->p[7] = 0xFFFFFFFF;
- ec->p[6] = 0x00000001;
- ec->p[5] = 0x0;
- ec->p[4] = 0x0;
- ec->p[3] = 0x0;
- ec->p[2] = 0xFFFFFFFF;
- ec->p[1] = 0xFFFFFFFF;
- ec->p[0] = 0xFFFFFFFF;
+ memset(ec->omega, 0, KEY_LENGTH_DWORDS_P256);
+ memset(ec->a, 0, KEY_LENGTH_DWORDS_P256);
- memset(ec->omega, 0, KEY_LENGTH_DWORDS_P256);
- memset(ec->a, 0, KEY_LENGTH_DWORDS_P256);
+ ec->a_minus3 = true;
- ec->a_minus3 = true;
+ // b
+ ec->b[7] = 0x5ac635d8;
+ ec->b[6] = 0xaa3a93e7;
+ ec->b[5] = 0xb3ebbd55;
+ ec->b[4] = 0x769886bc;
+ ec->b[3] = 0x651d06b0;
+ ec->b[2] = 0xcc53b0f6;
+ ec->b[1] = 0x3bce3c3e;
+ ec->b[0] = 0x27d2604b;
- // b
- ec->b[7] = 0x5ac635d8;
- ec->b[6] = 0xaa3a93e7;
- ec->b[5] = 0xb3ebbd55;
- ec->b[4] = 0x769886bc;
- ec->b[3] = 0x651d06b0;
- ec->b[2] = 0xcc53b0f6;
- ec->b[1] = 0x3bce3c3e;
- ec->b[0] = 0x27d2604b;
+ // base point
+ ec->G.x[7] = 0x6b17d1f2;
+ ec->G.x[6] = 0xe12c4247;
+ ec->G.x[5] = 0xf8bce6e5;
+ ec->G.x[4] = 0x63a440f2;
+ ec->G.x[3] = 0x77037d81;
+ ec->G.x[2] = 0x2deb33a0;
+ ec->G.x[1] = 0xf4a13945;
+ ec->G.x[0] = 0xd898c296;
- // base point
- ec->G.x[7] = 0x6b17d1f2;
- ec->G.x[6] = 0xe12c4247;
- ec->G.x[5] = 0xf8bce6e5;
- ec->G.x[4] = 0x63a440f2;
- ec->G.x[3] = 0x77037d81;
- ec->G.x[2] = 0x2deb33a0;
- ec->G.x[1] = 0xf4a13945;
- ec->G.x[0] = 0xd898c296;
-
- ec->G.y[7] = 0x4fe342e2;
- ec->G.y[6] = 0xfe1a7f9b;
- ec->G.y[5] = 0x8ee7eb4a;
- ec->G.y[4] = 0x7c0f9e16;
- ec->G.y[3] = 0x2bce3357;
- ec->G.y[2] = 0x6b315ece;
- ec->G.y[1] = 0xcbb64068;
- ec->G.y[0] = 0x37bf51f5;
- }
+ ec->G.y[7] = 0x4fe342e2;
+ ec->G.y[6] = 0xfe1a7f9b;
+ ec->G.y[5] = 0x8ee7eb4a;
+ ec->G.y[4] = 0x7c0f9e16;
+ ec->G.y[3] = 0x2bce3357;
+ ec->G.y[2] = 0x6b315ece;
+ ec->G.y[1] = 0xcbb64068;
+ ec->G.y[0] = 0x37bf51f5;
}
diff --git a/stack/smp/p_256_ecc_pp.cc b/stack/smp/p_256_ecc_pp.cc
index ff5dbde..cef368a 100644
--- a/stack/smp/p_256_ecc_pp.cc
+++ b/stack/smp/p_256_ecc_pp.cc
@@ -38,7 +38,7 @@
}
// q=2q
-static void ECC_Double(Point* q, Point* p, uint32_t keyLength) {
+static void ECC_Double(Point* q, Point* p) {
uint32_t t1[KEY_LENGTH_DWORDS_P256];
uint32_t t2[KEY_LENGTH_DWORDS_P256];
uint32_t t3[KEY_LENGTH_DWORDS_P256];
@@ -49,8 +49,8 @@
uint32_t* z1;
uint32_t* z3;
- if (multiprecision_iszero(p->z, keyLength)) {
- multiprecision_init(q->z, keyLength);
+ if (multiprecision_iszero(p->z)) {
+ multiprecision_init(q->z);
return; // return infinity
}
@@ -61,33 +61,33 @@
y3 = q->y;
z3 = q->z;
- multiprecision_mersenns_squa_mod(t1, z1, keyLength); // t1=z1^2
- multiprecision_sub_mod(t2, x1, t1, keyLength); // t2=x1-t1
- multiprecision_add_mod(t1, x1, t1, keyLength); // t1=x1+t1
- multiprecision_mersenns_mult_mod(t2, t1, t2, keyLength); // t2=t2*t1
- multiprecision_lshift_mod(t3, t2, keyLength);
- multiprecision_add_mod(t2, t3, t2, keyLength); // t2=3t2
+ multiprecision_mersenns_squa_mod(t1, z1); // t1=z1^2
+ multiprecision_sub_mod(t2, x1, t1); // t2=x1-t1
+ multiprecision_add_mod(t1, x1, t1); // t1=x1+t1
+ multiprecision_mersenns_mult_mod(t2, t1, t2); // t2=t2*t1
+ multiprecision_lshift_mod(t3, t2);
+ multiprecision_add_mod(t2, t3, t2); // t2=3t2
- multiprecision_mersenns_mult_mod(z3, y1, z1, keyLength); // z3=y1*z1
- multiprecision_lshift_mod(z3, z3, keyLength);
+ multiprecision_mersenns_mult_mod(z3, y1, z1); // z3=y1*z1
+ multiprecision_lshift_mod(z3, z3);
- multiprecision_mersenns_squa_mod(y3, y1, keyLength); // y3=y1^2
- multiprecision_lshift_mod(y3, y3, keyLength);
- multiprecision_mersenns_mult_mod(t3, y3, x1, keyLength); // t3=y3*x1=x1*y1^2
- multiprecision_lshift_mod(t3, t3, keyLength);
- multiprecision_mersenns_squa_mod(y3, y3, keyLength); // y3=y3^2=y1^4
- multiprecision_lshift_mod(y3, y3, keyLength);
+ multiprecision_mersenns_squa_mod(y3, y1); // y3=y1^2
+ multiprecision_lshift_mod(y3, y3);
+ multiprecision_mersenns_mult_mod(t3, y3, x1); // t3=y3*x1=x1*y1^2
+ multiprecision_lshift_mod(t3, t3);
+ multiprecision_mersenns_squa_mod(y3, y3); // y3=y3^2=y1^4
+ multiprecision_lshift_mod(y3, y3);
- multiprecision_mersenns_squa_mod(x3, t2, keyLength); // x3=t2^2
- multiprecision_lshift_mod(t1, t3, keyLength); // t1=2t3
- multiprecision_sub_mod(x3, x3, t1, keyLength); // x3=x3-t1
- multiprecision_sub_mod(t1, t3, x3, keyLength); // t1=t3-x3
- multiprecision_mersenns_mult_mod(t1, t1, t2, keyLength); // t1=t1*t2
- multiprecision_sub_mod(y3, t1, y3, keyLength); // y3=t1-y3
+ multiprecision_mersenns_squa_mod(x3, t2); // x3=t2^2
+ multiprecision_lshift_mod(t1, t3); // t1=2t3
+ multiprecision_sub_mod(x3, x3, t1); // x3=x3-t1
+ multiprecision_sub_mod(t1, t3, x3); // t1=t3-x3
+ multiprecision_mersenns_mult_mod(t1, t1, t2); // t1=t1*t2
+ multiprecision_sub_mod(y3, t1, y3); // y3=t1-y3
}
// q=q+p, zp must be 1
-static void ECC_Add(Point* r, Point* p, Point* q, uint32_t keyLength) {
+static void ECC_Add(Point* r, Point* p, Point* q) {
uint32_t t1[KEY_LENGTH_DWORDS_P256];
uint32_t t2[KEY_LENGTH_DWORDS_P256];
uint32_t* x1;
@@ -111,58 +111,57 @@
z3 = r->z;
// if Q=infinity, return p
- if (multiprecision_iszero(z2, keyLength)) {
+ if (multiprecision_iszero(z2)) {
p_256_copy_point(r, p);
return;
}
// if P=infinity, return q
- if (multiprecision_iszero(z1, keyLength)) {
+ if (multiprecision_iszero(z1)) {
p_256_copy_point(r, q);
return;
}
- multiprecision_mersenns_squa_mod(t1, z1, keyLength); // t1=z1^2
- multiprecision_mersenns_mult_mod(t2, z1, t1, keyLength); // t2=t1*z1
- multiprecision_mersenns_mult_mod(t1, x2, t1, keyLength); // t1=t1*x2
- multiprecision_mersenns_mult_mod(t2, y2, t2, keyLength); // t2=t2*y2
+ multiprecision_mersenns_squa_mod(t1, z1); // t1=z1^2
+ multiprecision_mersenns_mult_mod(t2, z1, t1); // t2=t1*z1
+ multiprecision_mersenns_mult_mod(t1, x2, t1); // t1=t1*x2
+ multiprecision_mersenns_mult_mod(t2, y2, t2); // t2=t2*y2
- multiprecision_sub_mod(t1, t1, x1, keyLength); // t1=t1-x1
- multiprecision_sub_mod(t2, t2, y1, keyLength); // t2=t2-y1
+ multiprecision_sub_mod(t1, t1, x1); // t1=t1-x1
+ multiprecision_sub_mod(t2, t2, y1); // t2=t2-y1
- if (multiprecision_iszero(t1, keyLength)) {
- if (multiprecision_iszero(t2, keyLength)) {
- ECC_Double(r, q, keyLength);
+ if (multiprecision_iszero(t1)) {
+ if (multiprecision_iszero(t2)) {
+ ECC_Double(r, q);
return;
} else {
- multiprecision_init(z3, keyLength);
+ multiprecision_init(z3);
return; // return infinity
}
}
- multiprecision_mersenns_mult_mod(z3, z1, t1, keyLength); // z3=z1*t1
- multiprecision_mersenns_squa_mod(y3, t1, keyLength); // t3=t1^2
- multiprecision_mersenns_mult_mod(z1, y3, t1, keyLength); // t4=t3*t1
- multiprecision_mersenns_mult_mod(y3, y3, x1, keyLength); // t3=t3*x1
- multiprecision_lshift_mod(t1, y3, keyLength); // t1=2*t3
- multiprecision_mersenns_squa_mod(x3, t2, keyLength); // x3=t2^2
- multiprecision_sub_mod(x3, x3, t1, keyLength); // x3=x3-t1
- multiprecision_sub_mod(x3, x3, z1, keyLength); // x3=x3-t4
- multiprecision_sub_mod(y3, y3, x3, keyLength); // t3=t3-x3
- multiprecision_mersenns_mult_mod(y3, y3, t2, keyLength); // t3=t3*t2
- multiprecision_mersenns_mult_mod(z1, z1, y1, keyLength); // t4=t4*t1
- multiprecision_sub_mod(y3, y3, z1, keyLength);
+ multiprecision_mersenns_mult_mod(z3, z1, t1); // z3=z1*t1
+ multiprecision_mersenns_squa_mod(y3, t1); // t3=t1^2
+ multiprecision_mersenns_mult_mod(z1, y3, t1); // t4=t3*t1
+ multiprecision_mersenns_mult_mod(y3, y3, x1); // t3=t3*x1
+ multiprecision_lshift_mod(t1, y3); // t1=2*t3
+ multiprecision_mersenns_squa_mod(x3, t2); // x3=t2^2
+ multiprecision_sub_mod(x3, x3, t1); // x3=x3-t1
+ multiprecision_sub_mod(x3, x3, z1); // x3=x3-t4
+ multiprecision_sub_mod(y3, y3, x3); // t3=t3-x3
+ multiprecision_mersenns_mult_mod(y3, y3, t2); // t3=t3*t2
+ multiprecision_mersenns_mult_mod(z1, z1, y1); // t4=t4*t1
+ multiprecision_sub_mod(y3, y3, z1);
}
// Computing the Non-Adjacent Form of a positive integer
-static void ECC_NAF(uint8_t* naf, uint32_t* NumNAF, uint32_t* k,
- uint32_t keyLength) {
+static void ECC_NAF(uint8_t* naf, uint32_t* NumNAF, uint32_t* k) {
uint32_t sign;
int i = 0;
int j;
uint32_t var;
- while ((var = multiprecision_most_signbits(k, keyLength)) >= 1) {
+ while ((var = multiprecision_most_signbits(k)) >= 1) {
if (k[0] & 0x01) // k is odd
{
sign = (k[0] & 0x03); // 1 or 3
@@ -183,7 +182,7 @@
} else
sign = 0;
- multiprecision_rshift(k, k, keyLength);
+ multiprecision_rshift(k, k);
naf[i / 4] |= (sign) << ((i % 4) * 2);
i++;
}
@@ -192,8 +191,7 @@
}
// Binary Non-Adjacent Form for point multiplication
-void ECC_PointMult_Bin_NAF(Point* q, Point* p, uint32_t* n,
- uint32_t keyLength) {
+void ECC_PointMult_Bin_NAF(Point* q, Point* p, uint32_t* n) {
uint32_t sign;
uint8_t naf[256 / 4 + 1];
uint32_t NumNaf;
@@ -201,69 +199,64 @@
Point r;
uint32_t* modp;
- if (keyLength == KEY_LENGTH_DWORDS_P256) {
- modp = curve_p256.p;
- } else {
- modp = curve.p;
- }
+ modp = curve_p256.p;
p_256_init_point(&r);
- multiprecision_init(p->z, keyLength);
+ multiprecision_init(p->z);
p->z[0] = 1;
// initialization
p_256_init_point(q);
// -p
- multiprecision_copy(minus_p.x, p->x, keyLength);
- multiprecision_sub(minus_p.y, modp, p->y, keyLength);
+ multiprecision_copy(minus_p.x, p->x);
+ multiprecision_sub(minus_p.y, modp, p->y);
- multiprecision_init(minus_p.z, keyLength);
+ multiprecision_init(minus_p.z);
minus_p.z[0] = 1;
// NAF
memset(naf, 0, sizeof(naf));
- ECC_NAF(naf, &NumNaf, n, keyLength);
+ ECC_NAF(naf, &NumNaf, n);
for (int i = NumNaf - 1; i >= 0; i--) {
p_256_copy_point(&r, q);
- ECC_Double(q, &r, keyLength);
+ ECC_Double(q, &r);
sign = (naf[i / 4] >> ((i % 4) * 2)) & 0x03;
if (sign == 1) {
p_256_copy_point(&r, q);
- ECC_Add(q, &r, p, keyLength);
+ ECC_Add(q, &r, p);
} else if (sign == 3) {
p_256_copy_point(&r, q);
- ECC_Add(q, &r, &minus_p, keyLength);
+ ECC_Add(q, &r, &minus_p);
}
}
- multiprecision_inv_mod(minus_p.x, q->z, keyLength);
- multiprecision_mersenns_squa_mod(q->z, minus_p.x, keyLength);
- multiprecision_mersenns_mult_mod(q->x, q->x, q->z, keyLength);
- multiprecision_mersenns_mult_mod(q->z, q->z, minus_p.x, keyLength);
- multiprecision_mersenns_mult_mod(q->y, q->y, q->z, keyLength);
+ multiprecision_inv_mod(minus_p.x, q->z);
+ multiprecision_mersenns_squa_mod(q->z, minus_p.x);
+ multiprecision_mersenns_mult_mod(q->x, q->x, q->z);
+ multiprecision_mersenns_mult_mod(q->z, q->z, minus_p.x);
+ multiprecision_mersenns_mult_mod(q->y, q->y, q->z);
}
bool ECC_ValidatePoint(const Point& pt) {
- const size_t kl = KEY_LENGTH_DWORDS_P256;
- p_256_init_curve(kl);
+ p_256_init_curve();
// Ensure y^2 = x^3 + a*x + b (mod p); a = -3
// y^2 mod p
- uint32_t y2_mod[kl] = {0};
- multiprecision_mersenns_squa_mod(y2_mod, (uint32_t*)pt.y, kl);
+ uint32_t y2_mod[KEY_LENGTH_DWORDS_P256] = {0};
+ multiprecision_mersenns_squa_mod(y2_mod, (uint32_t*)pt.y);
// Right hand side calculation
- uint32_t rhs[kl] = {0};
- multiprecision_mersenns_squa_mod(rhs, (uint32_t*)pt.x, kl);
- uint32_t three[kl] = {0};
+ uint32_t rhs[KEY_LENGTH_DWORDS_P256] = {0};
+ multiprecision_mersenns_squa_mod(rhs, (uint32_t*)pt.x);
+ uint32_t three[KEY_LENGTH_DWORDS_P256] = {0};
three[0] = 3;
- multiprecision_sub_mod(rhs, rhs, three, kl);
- multiprecision_mersenns_mult_mod(rhs, rhs, (uint32_t*)pt.x, kl);
- multiprecision_add_mod(rhs, rhs, curve_p256.b, kl);
+ multiprecision_sub_mod(rhs, rhs, three);
+ multiprecision_mersenns_mult_mod(rhs, rhs, (uint32_t*)pt.x);
+ multiprecision_add_mod(rhs, rhs, curve_p256.b);
- return multiprecision_compare(rhs, y2_mod, kl) == 0;
+ return multiprecision_compare(rhs, y2_mod) == 0;
}
diff --git a/stack/smp/p_256_ecc_pp.h b/stack/smp/p_256_ecc_pp.h
index b49b72a..4dff0a8 100644
--- a/stack/smp/p_256_ecc_pp.h
+++ b/stack/smp/p_256_ecc_pp.h
@@ -58,9 +58,8 @@
bool ECC_ValidatePoint(const Point& p);
-void ECC_PointMult_Bin_NAF(Point* q, Point* p, uint32_t* n, uint32_t keyLength);
+void ECC_PointMult_Bin_NAF(Point* q, Point* p, uint32_t* n);
-#define ECC_PointMult(q, p, n, keyLength) \
- ECC_PointMult_Bin_NAF(q, p, n, keyLength)
+#define ECC_PointMult(q, p, n) ECC_PointMult_Bin_NAF(q, p, n)
-void p_256_init_curve(uint32_t keyLength);
+void p_256_init_curve();
diff --git a/stack/smp/p_256_multprecision.cc b/stack/smp/p_256_multprecision.cc
index 286aca1..0310829 100644
--- a/stack/smp/p_256_multprecision.cc
+++ b/stack/smp/p_256_multprecision.cc
@@ -27,24 +27,24 @@
#include "bt_target.h"
#include "p_256_ecc_pp.h"
-void multiprecision_init(uint32_t* c, uint32_t keyLength) {
- for (uint32_t i = 0; i < keyLength; i++) c[i] = 0;
+void multiprecision_init(uint32_t* c) {
+ for (uint32_t i = 0; i < KEY_LENGTH_DWORDS_P256; i++) c[i] = 0;
}
-void multiprecision_copy(uint32_t* c, uint32_t* a, uint32_t keyLength) {
- for (uint32_t i = 0; i < keyLength; i++) c[i] = a[i];
+void multiprecision_copy(uint32_t* c, uint32_t* a) {
+ for (uint32_t i = 0; i < KEY_LENGTH_DWORDS_P256; i++) c[i] = a[i];
}
-int multiprecision_compare(uint32_t* a, uint32_t* b, uint32_t keyLength) {
- for (int i = keyLength - 1; i >= 0; i--) {
+int multiprecision_compare(uint32_t* a, uint32_t* b) {
+ for (int i = KEY_LENGTH_DWORDS_P256 - 1; i >= 0; i--) {
if (a[i] > b[i]) return 1;
if (a[i] < b[i]) return -1;
}
return 0;
}
-int multiprecision_iszero(uint32_t* a, uint32_t keyLength) {
- for (uint32_t i = 0; i < keyLength; i++)
+int multiprecision_iszero(uint32_t* a) {
+ for (uint32_t i = 0; i < KEY_LENGTH_DWORDS_P256; i++)
if (a[i]) return 0;
return 1;
@@ -58,30 +58,29 @@
return i;
}
-uint32_t multiprecision_most_signdwords(uint32_t* a, uint32_t keyLength) {
+uint32_t multiprecision_most_signdwords(uint32_t* a) {
int i;
- for (i = keyLength - 1; i >= 0; i--)
+ for (i = KEY_LENGTH_DWORDS_P256 - 1; i >= 0; i--)
if (a[i]) break;
return (i + 1);
}
-uint32_t multiprecision_most_signbits(uint32_t* a, uint32_t keyLength) {
+uint32_t multiprecision_most_signbits(uint32_t* a) {
int aMostSignDWORDs;
- aMostSignDWORDs = multiprecision_most_signdwords(a, keyLength);
+ aMostSignDWORDs = multiprecision_most_signdwords(a);
if (aMostSignDWORDs == 0) return 0;
return (((aMostSignDWORDs - 1) << DWORD_BITS_SHIFT) +
multiprecision_dword_bits(a[aMostSignDWORDs - 1]));
}
-uint32_t multiprecision_add(uint32_t* c, uint32_t* a, uint32_t* b,
- uint32_t keyLength) {
+uint32_t multiprecision_add(uint32_t* c, uint32_t* a, uint32_t* b) {
uint32_t carrier;
uint32_t temp;
carrier = 0;
- for (uint32_t i = 0; i < keyLength; i++) {
+ for (uint32_t i = 0; i < KEY_LENGTH_DWORDS_P256; i++) {
temp = a[i] + carrier;
carrier = (temp < carrier);
temp += b[i];
@@ -93,13 +92,12 @@
}
// c=a-b
-uint32_t multiprecision_sub(uint32_t* c, uint32_t* a, uint32_t* b,
- uint32_t keyLength) {
+uint32_t multiprecision_sub(uint32_t* c, uint32_t* a, uint32_t* b) {
uint32_t borrow;
uint32_t temp;
borrow = 0;
- for (uint32_t i = 0; i < keyLength; i++) {
+ for (uint32_t i = 0; i < KEY_LENGTH_DWORDS_P256; i++) {
temp = a[i] - borrow;
borrow = (temp > a[i]);
c[i] = temp - b[i];
@@ -110,27 +108,20 @@
}
// c = a << 1
-void multiprecision_lshift_mod(uint32_t* c, uint32_t* a, uint32_t keyLength) {
+void multiprecision_lshift_mod(uint32_t* c, uint32_t* a) {
uint32_t carrier;
- uint32_t* modp;
+ uint32_t* modp = curve_p256.p;
- if (keyLength == KEY_LENGTH_DWORDS_P192) {
- modp = curve.p;
- } else if (keyLength == KEY_LENGTH_DWORDS_P256) {
- modp = curve_p256.p;
- } else
- return;
-
- carrier = multiprecision_lshift(c, a, keyLength);
+ carrier = multiprecision_lshift(c, a);
if (carrier) {
- multiprecision_sub(c, c, modp, keyLength);
- } else if (multiprecision_compare(c, modp, keyLength) >= 0) {
- multiprecision_sub(c, c, modp, keyLength);
+ multiprecision_sub(c, c, modp);
+ } else if (multiprecision_compare(c, modp) >= 0) {
+ multiprecision_sub(c, c, modp);
}
}
// c=a>>1
-void multiprecision_rshift(uint32_t* c, uint32_t* a, uint32_t keyLength) {
+void multiprecision_rshift(uint32_t* c, uint32_t* a) {
int j;
uint32_t b = 1;
@@ -138,7 +129,7 @@
uint32_t carrier = 0;
uint32_t temp;
- for (int i = keyLength - 1; i >= 0; i--) {
+ for (int i = KEY_LENGTH_DWORDS_P256 - 1; i >= 0; i--) {
temp = a[i]; // in case of c==a
c[i] = (temp >> b) | carrier;
carrier = temp << j;
@@ -147,64 +138,42 @@
// Curve specific optimization when p is a pseudo-Mersenns prime,
// p=2^(KEY_LENGTH_BITS)-omega
-void multiprecision_mersenns_mult_mod(uint32_t* c, uint32_t* a, uint32_t* b,
- uint32_t keyLength) {
+void multiprecision_mersenns_mult_mod(uint32_t* c, uint32_t* a, uint32_t* b) {
uint32_t cc[2 * KEY_LENGTH_DWORDS_P256];
- multiprecision_mult(cc, a, b, keyLength);
- if (keyLength == 6) {
- multiprecision_fast_mod(c, cc);
- } else if (keyLength == 8) {
- multiprecision_fast_mod_P256(c, cc);
- }
+ multiprecision_mult(cc, a, b);
+ multiprecision_fast_mod_P256(c, cc);
}
// Curve specific optimization when p is a pseudo-Mersenns prime
-void multiprecision_mersenns_squa_mod(uint32_t* c, uint32_t* a,
- uint32_t keyLength) {
- multiprecision_mersenns_mult_mod(c, a, a, keyLength);
+void multiprecision_mersenns_squa_mod(uint32_t* c, uint32_t* a) {
+ multiprecision_mersenns_mult_mod(c, a, a);
}
// c=(a+b) mod p, b<p, a<p
-void multiprecision_add_mod(uint32_t* c, uint32_t* a, uint32_t* b,
- uint32_t keyLength) {
+void multiprecision_add_mod(uint32_t* c, uint32_t* a, uint32_t* b) {
uint32_t carrier;
- uint32_t* modp;
+ uint32_t* modp = curve_p256.p;
- if (keyLength == KEY_LENGTH_DWORDS_P192) {
- modp = curve.p;
- } else if (keyLength == KEY_LENGTH_DWORDS_P256) {
- modp = curve_p256.p;
- } else
- return;
-
- carrier = multiprecision_add(c, a, b, keyLength);
+ carrier = multiprecision_add(c, a, b);
if (carrier) {
- multiprecision_sub(c, c, modp, keyLength);
- } else if (multiprecision_compare(c, modp, keyLength) >= 0) {
- multiprecision_sub(c, c, modp, keyLength);
+ multiprecision_sub(c, c, modp);
+ } else if (multiprecision_compare(c, modp) >= 0) {
+ multiprecision_sub(c, c, modp);
}
}
// c=(a-b) mod p, a<p, b<p
-void multiprecision_sub_mod(uint32_t* c, uint32_t* a, uint32_t* b,
- uint32_t keyLength) {
+void multiprecision_sub_mod(uint32_t* c, uint32_t* a, uint32_t* b) {
uint32_t borrow;
- uint32_t* modp;
+ uint32_t* modp = curve_p256.p;
- if (keyLength == KEY_LENGTH_DWORDS_P192) {
- modp = curve.p;
- } else if (keyLength == KEY_LENGTH_DWORDS_P256) {
- modp = curve_p256.p;
- } else
- return;
-
- borrow = multiprecision_sub(c, a, b, keyLength);
- if (borrow) multiprecision_add(c, c, modp, keyLength);
+ borrow = multiprecision_sub(c, a, b);
+ if (borrow) multiprecision_add(c, c, modp);
}
// c=a<<b, b<DWORD_BITS, c has a buffer size of Numuint32_ts+1
-uint32_t multiprecision_lshift(uint32_t* c, uint32_t* a, uint32_t keyLength) {
+uint32_t multiprecision_lshift(uint32_t* c, uint32_t* a) {
int j;
uint32_t b = 1;
j = DWORD_BITS - b;
@@ -212,7 +181,7 @@
uint32_t carrier = 0;
uint32_t temp;
- for (uint32_t i = 0; i < keyLength; i++) {
+ for (uint32_t i = 0; i < KEY_LENGTH_DWORDS_P256; i++) {
temp = a[i]; // in case c==a
c[i] = (temp << b) | carrier;
carrier = temp >> j;
@@ -222,19 +191,18 @@
}
// c=a*b; c must have a buffer of 2*Key_LENGTH_uint32_tS, c != a != b
-void multiprecision_mult(uint32_t* c, uint32_t* a, uint32_t* b,
- uint32_t keyLength) {
+void multiprecision_mult(uint32_t* c, uint32_t* a, uint32_t* b) {
uint32_t W;
uint32_t U;
uint32_t V;
U = V = W = 0;
- multiprecision_init(c, keyLength);
+ multiprecision_init(c);
// assume little endian right now
- for (uint32_t i = 0; i < keyLength; i++) {
+ for (uint32_t i = 0; i < KEY_LENGTH_DWORDS_P256; i++) {
U = 0;
- for (uint32_t j = 0; j < keyLength; j++) {
+ for (uint32_t j = 0; j < KEY_LENGTH_DWORDS_P256; j++) {
uint64_t result;
result = ((uint64_t)a[i]) * ((uint64_t)b[j]);
W = result >> 32;
@@ -246,78 +214,7 @@
U += (V < c[i + j]);
c[i + j] = V;
}
- c[i + keyLength] = U;
- }
-}
-
-void multiprecision_fast_mod(uint32_t* c, uint32_t* a) {
- uint32_t U;
- uint32_t V;
- uint32_t* modp = curve.p;
-
- c[0] = a[0] + a[6];
- U = c[0] < a[0];
- c[0] += a[10];
- U += c[0] < a[10];
-
- c[1] = a[1] + U;
- U = c[1] < a[1];
- c[1] += a[7];
- U += c[1] < a[7];
- c[1] += a[11];
- U += c[1] < a[11];
-
- c[2] = a[2] + U;
- U = c[2] < a[2];
- c[2] += a[6];
- U += c[2] < a[6];
- c[2] += a[8];
- U += c[2] < a[8];
- c[2] += a[10];
- U += c[2] < a[10];
-
- c[3] = a[3] + U;
- U = c[3] < a[3];
- c[3] += a[7];
- U += c[3] < a[7];
- c[3] += a[9];
- U += c[3] < a[9];
- c[3] += a[11];
- U += c[3] < a[11];
-
- c[4] = a[4] + U;
- U = c[4] < a[4];
- c[4] += a[8];
- U += c[4] < a[8];
- c[4] += a[10];
- U += c[4] < a[10];
-
- c[5] = a[5] + U;
- U = c[5] < a[5];
- c[5] += a[9];
- U += c[5] < a[9];
- c[5] += a[11];
- U += c[5] < a[11];
-
- c[0] += U;
- V = c[0] < U;
- c[1] += V;
- V = c[1] < V;
- c[2] += V;
- V = c[2] < V;
- c[2] += U;
- V = c[2] < U;
- c[3] += V;
- V = c[3] < V;
- c[4] += V;
- V = c[4] < V;
- c[5] += V;
- V = c[5] < V;
-
- if (V) {
- multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P192);
- } else if (multiprecision_compare(c, modp, KEY_LENGTH_DWORDS_P192) >= 0) {
- multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P192);
+ c[i + KEY_LENGTH_DWORDS_P256] = U;
}
}
@@ -541,74 +438,67 @@
if (U & 0x80000000) {
while (U) {
- multiprecision_add(c, c, modp, KEY_LENGTH_DWORDS_P256);
+ multiprecision_add(c, c, modp);
U++;
}
} else if (U) {
while (U) {
- multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P256);
+ multiprecision_sub(c, c, modp);
U--;
}
}
- if (multiprecision_compare(c, modp, KEY_LENGTH_DWORDS_P256) >= 0)
- multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P256);
+ if (multiprecision_compare(c, modp) >= 0) multiprecision_sub(c, c, modp);
}
-void multiprecision_inv_mod(uint32_t* aminus, uint32_t* u, uint32_t keyLength) {
+void multiprecision_inv_mod(uint32_t* aminus, uint32_t* u) {
uint32_t v[KEY_LENGTH_DWORDS_P256];
uint32_t A[KEY_LENGTH_DWORDS_P256 + 1];
uint32_t C[KEY_LENGTH_DWORDS_P256 + 1];
- uint32_t* modp;
+ uint32_t* modp = curve_p256.p;
- if (keyLength == KEY_LENGTH_DWORDS_P256) {
- modp = curve_p256.p;
- } else {
- modp = curve.p;
- }
-
- multiprecision_copy(v, modp, keyLength);
- multiprecision_init(A, keyLength);
- multiprecision_init(C, keyLength);
+ multiprecision_copy(v, modp);
+ multiprecision_init(A);
+ multiprecision_init(C);
A[0] = 1;
- while (!multiprecision_iszero(u, keyLength)) {
+ while (!multiprecision_iszero(u)) {
while (!(u[0] & 0x01)) // u is even
{
- multiprecision_rshift(u, u, keyLength);
+ multiprecision_rshift(u, u);
if (!(A[0] & 0x01)) // A is even
- multiprecision_rshift(A, A, keyLength);
+ multiprecision_rshift(A, A);
else {
- A[keyLength] = multiprecision_add(A, A, modp, keyLength); // A =A+p
- multiprecision_rshift(A, A, keyLength);
- A[keyLength - 1] |= (A[keyLength] << 31);
+ A[KEY_LENGTH_DWORDS_P256] = multiprecision_add(A, A, modp); // A =A+p
+ multiprecision_rshift(A, A);
+ A[KEY_LENGTH_DWORDS_P256 - 1] |= (A[KEY_LENGTH_DWORDS_P256] << 31);
}
}
while (!(v[0] & 0x01)) // v is even
{
- multiprecision_rshift(v, v, keyLength);
+ multiprecision_rshift(v, v);
if (!(C[0] & 0x01)) // C is even
{
- multiprecision_rshift(C, C, keyLength);
+ multiprecision_rshift(C, C);
} else {
- C[keyLength] = multiprecision_add(C, C, modp, keyLength); // C =C+p
- multiprecision_rshift(C, C, keyLength);
- C[keyLength - 1] |= (C[keyLength] << 31);
+ C[KEY_LENGTH_DWORDS_P256] = multiprecision_add(C, C, modp); // C =C+p
+ multiprecision_rshift(C, C);
+ C[KEY_LENGTH_DWORDS_P256 - 1] |= (C[KEY_LENGTH_DWORDS_P256] << 31);
}
}
- if (multiprecision_compare(u, v, keyLength) >= 0) {
- multiprecision_sub(u, u, v, keyLength);
- multiprecision_sub_mod(A, A, C, keyLength);
+ if (multiprecision_compare(u, v) >= 0) {
+ multiprecision_sub(u, u, v);
+ multiprecision_sub_mod(A, A, C);
} else {
- multiprecision_sub(v, v, u, keyLength);
- multiprecision_sub_mod(C, C, A, keyLength);
+ multiprecision_sub(v, v, u);
+ multiprecision_sub_mod(C, C, A);
}
}
- if (multiprecision_compare(C, modp, keyLength) >= 0)
- multiprecision_sub(aminus, C, modp, keyLength);
+ if (multiprecision_compare(C, modp) >= 0)
+ multiprecision_sub(aminus, C, modp);
else
- multiprecision_copy(aminus, C, keyLength);
+ multiprecision_copy(aminus, C);
}
diff --git a/stack/smp/p_256_multprecision.h b/stack/smp/p_256_multprecision.h
index fbbd88d..a98fe4d 100644
--- a/stack/smp/p_256_multprecision.h
+++ b/stack/smp/p_256_multprecision.h
@@ -12,8 +12,7 @@
* 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.
- *
+ * limitations under the License. *
******************************************************************************/
/*******************************************************************************
@@ -29,40 +28,30 @@
#define DWORD_BYTES 4
#define DWORD_BITS_SHIFT 5
-#define KEY_LENGTH_DWORDS_P192 6
#define KEY_LENGTH_DWORDS_P256 8
/* Arithmetic Operations */
-int multiprecision_compare(uint32_t* a, uint32_t* b, uint32_t keyLength);
-int multiprecision_iszero(uint32_t* a, uint32_t keyLength);
-void multiprecision_init(uint32_t* c, uint32_t keyLength);
-void multiprecision_copy(uint32_t* c, uint32_t* a, uint32_t keyLength);
+int multiprecision_compare(uint32_t* a, uint32_t* b);
+int multiprecision_iszero(uint32_t* a);
+void multiprecision_init(uint32_t* c);
+void multiprecision_copy(uint32_t* c, uint32_t* a);
uint32_t multiprecision_dword_bits(uint32_t a);
-uint32_t multiprecision_most_signdwords(uint32_t* a, uint32_t keyLength);
-uint32_t multiprecision_most_signbits(uint32_t* a, uint32_t keyLength);
-void multiprecision_inv_mod(uint32_t* aminus, uint32_t* a, uint32_t keyLength);
-uint32_t multiprecision_add(uint32_t* c, uint32_t* a, uint32_t* b,
- uint32_t keyLength); // c=a+b
-void multiprecision_add_mod(uint32_t* c, uint32_t* a, uint32_t* b,
- uint32_t keyLength);
-uint32_t multiprecision_sub(uint32_t* c, uint32_t* a, uint32_t* b,
- uint32_t keyLength); // c=a-b
-void multiprecision_sub_mod(uint32_t* c, uint32_t* a, uint32_t* b,
- uint32_t keyLength);
-void multiprecision_rshift(uint32_t* c, uint32_t* a,
- uint32_t keyLength); // c=a>>1, return carrier
-void multiprecision_lshift_mod(uint32_t* c, uint32_t* a,
- uint32_t keyLength); // c=a<<b, return carrier
-uint32_t multiprecision_lshift(uint32_t* c, uint32_t* a,
- uint32_t keyLength); // c=a<<b, return carrier
-void multiprecision_mult(uint32_t* c, uint32_t* a, uint32_t* b,
- uint32_t keyLength); // c=a*b
-void multiprecision_mersenns_mult_mod(uint32_t* c, uint32_t* a, uint32_t* b,
- uint32_t keyLength);
-void multiprecision_mersenns_squa_mod(uint32_t* c, uint32_t* a,
- uint32_t keyLength);
-uint32_t multiprecision_lshift(uint32_t* c, uint32_t* a, uint32_t keyLength);
-void multiprecision_mult(uint32_t* c, uint32_t* a, uint32_t* b,
- uint32_t keyLength);
+uint32_t multiprecision_most_signdwords(uint32_t* a);
+uint32_t multiprecision_most_signbits(uint32_t* a);
+void multiprecision_inv_mod(uint32_t* aminus, uint32_t* a);
+uint32_t multiprecision_add(uint32_t* c, uint32_t* a, uint32_t* b); // c=a+b
+void multiprecision_add_mod(uint32_t* c, uint32_t* a, uint32_t* b);
+uint32_t multiprecision_sub(uint32_t* c, uint32_t* a, uint32_t* b); // c=a-b
+void multiprecision_sub_mod(uint32_t* c, uint32_t* a, uint32_t* b);
+void multiprecision_rshift(uint32_t* c, uint32_t* a); // c=a>>1, return carrier
+void multiprecision_lshift_mod(uint32_t* c,
+ uint32_t* a); // c=a<<b, return carrier
+uint32_t multiprecision_lshift(uint32_t* c,
+ uint32_t* a); // c=a<<b, return carrier
+void multiprecision_mult(uint32_t* c, uint32_t* a, uint32_t* b); // c=a*b
+void multiprecision_mersenns_mult_mod(uint32_t* c, uint32_t* a, uint32_t* b);
+void multiprecision_mersenns_squa_mod(uint32_t* c, uint32_t* a);
+uint32_t multiprecision_lshift(uint32_t* c, uint32_t* a);
+void multiprecision_mult(uint32_t* c, uint32_t* a, uint32_t* b);
void multiprecision_fast_mod(uint32_t* c, uint32_t* a);
void multiprecision_fast_mod_P256(uint32_t* c, uint32_t* a);
diff --git a/stack/smp/smp_act.cc b/stack/smp/smp_act.cc
index b775d5d..db6ed66 100644
--- a/stack/smp/smp_act.cc
+++ b/stack/smp/smp_act.cc
@@ -16,8 +16,10 @@
*
******************************************************************************/
+#include <log/log.h>
#include <string.h>
#include "btif_common.h"
+#include "btif_storage.h"
#include "device/include/interop.h"
#include "internal_include/bt_target.h"
#include "stack/btm/btm_int.h"
@@ -105,7 +107,7 @@
case SMP_IO_CAP_REQ_EVT:
cb_data.io_req.auth_req = p_cb->peer_auth_req;
cb_data.io_req.oob_data = SMP_OOB_NONE;
- cb_data.io_req.io_cap = SMP_DEFAULT_IO_CAPS;
+ cb_data.io_req.io_cap = btif_storage_get_local_io_caps_ble();
cb_data.io_req.max_key_size = SMP_MAX_ENC_KEY_SIZE;
cb_data.io_req.init_keys = p_cb->local_i_key;
cb_data.io_req.resp_keys = p_cb->local_r_key;
@@ -350,7 +352,7 @@
smp_send_cmd(SMP_OPCODE_MASTER_ID, p_cb);
/* save the DIV and key size information when acting as slave device */
- memcpy(le_key.lenc_key.ltk, p_cb->ltk, BT_OCTET16_LEN);
+ le_key.lenc_key.ltk = p_cb->ltk;
le_key.lenc_key.div = p_cb->div;
le_key.lenc_key.key_size = p_cb->loc_enc_size;
le_key.lenc_key.sec_level = p_cb->sec_level;
@@ -384,10 +386,7 @@
smp_key_distribution_by_transport(p_cb, NULL);
}
-/*******************************************************************************
- * Function smp_send_csrk_info
- * Description send CSRK command.
- ******************************************************************************/
+/** send CSRK command. */
void smp_send_csrk_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
tBTM_LE_KEY_VALUE key;
SMP_TRACE_DEBUG("%s", __func__);
@@ -397,7 +396,7 @@
key.lcsrk_key.div = p_cb->div;
key.lcsrk_key.sec_level = p_cb->sec_level;
key.lcsrk_key.counter = 0; /* initialize the local counter */
- memcpy(key.lcsrk_key.csrk, p_cb->csrk, BT_OCTET16_LEN);
+ key.lcsrk_key.csrk = p_cb->csrk;
btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LCSRK, &key, true);
}
@@ -410,8 +409,11 @@
******************************************************************************/
void smp_send_ltk_reply(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
SMP_TRACE_DEBUG("%s", __func__);
+
+ Octet16 stk;
+ memcpy(stk.data(), p_data->key.p_data, stk.size());
/* send stk as LTK response */
- btm_ble_ltk_request_reply(p_cb->pairing_bda, true, p_data->key.p_data);
+ btm_ble_ltk_request_reply(p_cb->pairing_bda, true, stk);
}
/*******************************************************************************
@@ -419,7 +421,7 @@
* Description process security request.
******************************************************************************/
void smp_proc_sec_req(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
- tBTM_LE_AUTH_REQ auth_req = *(tBTM_LE_AUTH_REQ*)p_data;
+ tBTM_LE_AUTH_REQ auth_req = *(tBTM_LE_AUTH_REQ*)p_data->p_data;
tBTM_BLE_SEC_REQ_ACT sec_req_act;
SMP_TRACE_DEBUG("%s: auth_req=0x%x", __func__, auth_req);
@@ -583,13 +585,8 @@
}
}
-/*******************************************************************************
- * Function smp_proc_confirm
- * Description process pairing confirm from peer device
- ******************************************************************************/
+/** process pairing confirm from peer device */
void smp_proc_confirm(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
- uint8_t* p = p_data->p_data;
-
SMP_TRACE_DEBUG("%s", __func__);
if (smp_command_has_invalid_parameters(p_cb)) {
@@ -599,18 +596,18 @@
return;
}
- if (p != NULL) {
- /* save the SConfirm for comparison later */
- STREAM_TO_ARRAY(p_cb->rconfirm, p, BT_OCTET16_LEN);
+ if (p_data) {
+ uint8_t* p = p_data->p_data;
+ if (p != NULL) {
+ /* save the SConfirm for comparison later */
+ STREAM_TO_ARRAY(p_cb->rconfirm.data(), p, OCTET16_LEN);
+ }
}
p_cb->flags |= SMP_PAIR_FLAGS_CMD_CONFIRM;
}
-/*******************************************************************************
- * Function smp_proc_init
- * Description process pairing initializer from peer device
- ******************************************************************************/
+/** process pairing initializer from peer device */
void smp_proc_init(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
uint8_t* p = p_data->p_data;
@@ -624,7 +621,7 @@
}
/* save the SRand for comparison */
- STREAM_TO_ARRAY(p_cb->rrand, p, BT_OCTET16_LEN);
+ STREAM_TO_ARRAY(p_cb->rrand.data(), p, OCTET16_LEN);
}
/*******************************************************************************
@@ -644,7 +641,7 @@
}
/* save the SRand for comparison */
- STREAM_TO_ARRAY(p_cb->rrand, p, BT_OCTET16_LEN);
+ STREAM_TO_ARRAY(p_cb->rrand.data(), p, OCTET16_LEN);
}
/*******************************************************************************
@@ -706,7 +703,7 @@
p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_COMM;
if (p != NULL) {
- STREAM_TO_ARRAY(p_cb->remote_commitment, p, BT_OCTET16_LEN);
+ STREAM_TO_ARRAY(p_cb->remote_commitment.data(), p, OCTET16_LEN);
}
}
@@ -727,7 +724,7 @@
}
if (p != NULL) {
- STREAM_TO_ARRAY(p_cb->remote_dhkey_check, p, BT_OCTET16_LEN);
+ STREAM_TO_ARRAY(p_cb->remote_dhkey_check.data(), p, OCTET16_LEN);
}
p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_DHK_CHK;
@@ -906,10 +903,7 @@
}
}
-/*******************************************************************************
- * Function smp_proc_enc_info
- * Description process encryption information from peer device
- ******************************************************************************/
+/** process encryption information from peer device */
void smp_proc_enc_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
uint8_t* p = p_data->p_data;
@@ -923,14 +917,12 @@
return;
}
- STREAM_TO_ARRAY(p_cb->ltk, p, BT_OCTET16_LEN);
+ STREAM_TO_ARRAY(p_cb->ltk.data(), p, OCTET16_LEN);
smp_key_distribution(p_cb, NULL);
}
-/*******************************************************************************
- * Function smp_proc_master_id
- * Description process master ID from slave device
- ******************************************************************************/
+
+/** process master ID from slave device */
void smp_proc_master_id(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
uint8_t* p = p_data->p_data;
tBTM_LE_KEY_VALUE le_key;
@@ -950,7 +942,7 @@
STREAM_TO_ARRAY(le_key.penc_key.rand, p, BT_OCTET8_LEN);
/* store the encryption keys from peer device */
- memcpy(le_key.penc_key.ltk, p_cb->ltk, BT_OCTET16_LEN);
+ le_key.lenc_key.ltk = p_cb->ltk;
le_key.penc_key.sec_level = p_cb->sec_level;
le_key.penc_key.key_size = p_cb->loc_enc_size;
@@ -961,10 +953,7 @@
smp_key_distribution(p_cb, NULL);
}
-/*******************************************************************************
- * Function smp_proc_id_info
- * Description process identity information from peer device
- ******************************************************************************/
+/** process identity information from peer device */
void smp_proc_id_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
uint8_t* p = p_data->p_data;
@@ -978,14 +967,11 @@
return;
}
- STREAM_TO_ARRAY(p_cb->tk, p, BT_OCTET16_LEN); /* reuse TK for IRK */
+ STREAM_TO_ARRAY(p_cb->tk.data(), p, OCTET16_LEN); /* reuse TK for IRK */
smp_key_distribution_by_transport(p_cb, NULL);
}
-/*******************************************************************************
- * Function smp_proc_id_addr
- * Description process identity address from peer device
- ******************************************************************************/
+/** process identity address from peer device */
void smp_proc_id_addr(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
uint8_t* p = p_data->p_data;
tBTM_LE_KEY_VALUE pid_key;
@@ -993,14 +979,14 @@
SMP_TRACE_DEBUG("%s", __func__);
smp_update_key_mask(p_cb, SMP_SEC_KEY_TYPE_ID, true);
- STREAM_TO_UINT8(pid_key.pid_key.addr_type, p);
- STREAM_TO_BDADDR(pid_key.pid_key.static_addr, p);
- memcpy(pid_key.pid_key.irk, p_cb->tk, BT_OCTET16_LEN);
+ STREAM_TO_UINT8(pid_key.pid_key.identity_addr_type, p);
+ STREAM_TO_BDADDR(pid_key.pid_key.identity_addr, p);
+ pid_key.pid_key.irk = p_cb->tk;
/* to use as BD_ADDR for lk derived from ltk */
p_cb->id_addr_rcvd = true;
- p_cb->id_addr_type = pid_key.pid_key.addr_type;
- p_cb->id_addr = pid_key.pid_key.static_addr;
+ p_cb->id_addr_type = pid_key.pid_key.identity_addr_type;
+ p_cb->id_addr = pid_key.pid_key.identity_addr;
/* store the ID key from peer device */
if ((p_cb->peer_auth_req & SMP_AUTH_BOND) &&
@@ -1009,10 +995,7 @@
smp_key_distribution_by_transport(p_cb, NULL);
}
-/*******************************************************************************
- * Function smp_proc_srk_info
- * Description process security information from peer device
- ******************************************************************************/
+/* process security information from peer device */
void smp_proc_srk_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
tBTM_LE_KEY_VALUE le_key;
@@ -1023,7 +1006,8 @@
le_key.pcsrk_key.sec_level = p_cb->sec_level;
/* get peer CSRK */
- maybe_non_aligned_memcpy(le_key.pcsrk_key.csrk, p_data->p_data, BT_OCTET16_LEN);
+ maybe_non_aligned_memcpy(le_key.pcsrk_key.csrk.data(), p_data->p_data,
+ OCTET16_LEN);
/* initialize the peer counter */
le_key.pcsrk_key.counter = 0;
@@ -1040,7 +1024,7 @@
******************************************************************************/
void smp_proc_compare(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
SMP_TRACE_DEBUG("%s", __func__);
- if (!memcmp(p_cb->rconfirm, p_data->key.p_data, BT_OCTET16_LEN)) {
+ if (!memcmp(p_cb->rconfirm.data(), p_data->key.p_data, OCTET16_LEN)) {
/* compare the max encryption key size, and save the smaller one for the
* link */
if (p_cb->peer_enc_size < p_cb->loc_enc_size)
@@ -1090,10 +1074,12 @@
tBTM_STATUS cmd;
SMP_TRACE_DEBUG("%s", __func__);
- if (p_data != NULL)
- cmd = btm_ble_start_encrypt(p_cb->pairing_bda, true, p_data->key.p_data);
- else
+ if (p_data != NULL) {
+ cmd = btm_ble_start_encrypt(p_cb->pairing_bda, true,
+ (Octet16*)p_data->key.p_data);
+ } else {
cmd = btm_ble_start_encrypt(p_cb->pairing_bda, false, NULL);
+ }
if (cmd != BTM_CMD_STARTED && cmd != BTM_BUSY) {
tSMP_INT_DATA smp_int_data;
@@ -1278,10 +1264,10 @@
tSMP_KEY key;
key.key_type = SMP_KEY_TYPE_TK;
- key.p_data = p_cb->tk;
+ key.p_data = p_cb->tk.data();
smp_int_data.key = key;
- memset(p_cb->tk, 0, BT_OCTET16_LEN);
+ p_cb->tk = {0};
/* TK, ready */
int_evt = SMP_KEY_READY_EVT;
}
@@ -1439,18 +1425,6 @@
}
/*******************************************************************************
- * Function smp_fast_conn_param
- * Description apply default connection parameter for pairing process
- ******************************************************************************/
-void smp_fast_conn_param(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
- /* Disable L2CAP connection parameter updates while bonding since
- some peripherals are not able to revert to fast connection parameters
- during the start of service discovery. Connection paramter updates
- get enabled again once service discovery completes. */
- L2CA_EnableUpdateBleConnParams(p_cb->pairing_bda, false);
-}
-
-/*******************************************************************************
* Function smp_both_have_public_keys
* Description The function is called when both local and peer public keys are
* saved.
@@ -1494,7 +1468,7 @@
switch (p_cb->selected_association_model) {
case SMP_MODEL_SEC_CONN_JUSTWORKS:
case SMP_MODEL_SEC_CONN_NUM_COMP:
- memset(p_cb->local_random, 0, BT_OCTET16_LEN);
+ p_cb->local_random = {0};
smp_start_nonce_generation(p_cb);
break;
case SMP_MODEL_SEC_CONN_PASSKEY_ENT:
@@ -1684,10 +1658,10 @@
* received from the peer DHKey check value.
******************************************************************************/
void smp_match_dhkey_checks(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
-
SMP_TRACE_DEBUG("%s", __func__);
- if (memcmp(p_data->key.p_data, p_cb->remote_dhkey_check, BT_OCTET16_LEN)) {
+ if (memcmp(p_data->key.p_data, p_cb->remote_dhkey_check.data(),
+ OCTET16_LEN)) {
SMP_TRACE_WARNING("dhkey chcks do no match");
tSMP_INT_DATA smp_int_data;
smp_int_data.status = SMP_DHKEY_CHK_FAIL;
@@ -1773,10 +1747,10 @@
uint8_t* p = NULL;
SMP_TRACE_DEBUG("%s", __func__);
- p = p_cb->local_random;
+ p = p_cb->local_random.data();
UINT32_TO_STREAM(p, p_data->passkey);
- p = p_cb->peer_random;
+ p = p_cb->peer_random.data();
UINT32_TO_STREAM(p, p_data->passkey);
p_cb->round = 0;
@@ -1793,21 +1767,18 @@
tSMP_SC_OOB_DATA* p_sc_oob_data = &p_cb->sc_oob_data;
if (p_sc_oob_data->loc_oob_data.present) {
- memcpy(p_cb->local_random, p_sc_oob_data->loc_oob_data.randomizer,
- sizeof(p_cb->local_random));
+ p_cb->local_random = p_sc_oob_data->loc_oob_data.randomizer;
} else {
SMP_TRACE_EVENT("%s: local OOB randomizer is absent", __func__);
- memset(p_cb->local_random, 0, sizeof(p_cb->local_random));
+ p_cb->local_random = {0};
}
if (!p_sc_oob_data->peer_oob_data.present) {
SMP_TRACE_EVENT("%s: peer OOB data is absent", __func__);
- memset(p_cb->peer_random, 0, sizeof(p_cb->peer_random));
+ p_cb->peer_random = {0};
} else {
- memcpy(p_cb->peer_random, p_sc_oob_data->peer_oob_data.randomizer,
- sizeof(p_cb->peer_random));
- memcpy(p_cb->remote_commitment, p_sc_oob_data->peer_oob_data.commitment,
- sizeof(p_cb->remote_commitment));
+ p_cb->peer_random = p_sc_oob_data->peer_oob_data.randomizer;
+ p_cb->remote_commitment = p_sc_oob_data->peer_oob_data.commitment;
/* check commitment */
if (!smp_check_commitment(p_cb)) {
@@ -1823,7 +1794,7 @@
SMP_TRACE_EVENT(
"%s: peer didn't receive local OOB data, set local randomizer to 0",
__func__);
- memset(p_cb->local_random, 0, sizeof(p_cb->local_random));
+ p_cb->local_random = {0};
}
}
@@ -1855,12 +1826,12 @@
******************************************************************************/
void smp_set_local_oob_random_commitment(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
SMP_TRACE_DEBUG("%s", __func__);
- memcpy(p_cb->sc_oob_data.loc_oob_data.randomizer, p_cb->rand, BT_OCTET16_LEN);
+ p_cb->sc_oob_data.loc_oob_data.randomizer = p_cb->rand;
- smp_calculate_f4(p_cb->sc_oob_data.loc_oob_data.publ_key_used.x,
- p_cb->sc_oob_data.loc_oob_data.publ_key_used.x,
- p_cb->sc_oob_data.loc_oob_data.randomizer, 0,
- p_cb->sc_oob_data.loc_oob_data.commitment);
+ p_cb->sc_oob_data.loc_oob_data.commitment =
+ crypto_toolbox::f4(p_cb->sc_oob_data.loc_oob_data.publ_key_used.x,
+ p_cb->sc_oob_data.loc_oob_data.publ_key_used.x,
+ p_cb->sc_oob_data.loc_oob_data.randomizer, 0);
#if (SMP_DEBUG == TRUE)
uint8_t* p_print = NULL;
@@ -1878,9 +1849,9 @@
smp_debug_print_nbyte_little_endian(p_print, "publ_key_used.y",
BT_OCTET32_LEN);
p_print = (uint8_t*)&p_cb->sc_oob_data.loc_oob_data.randomizer;
- smp_debug_print_nbyte_little_endian(p_print, "randomizer", BT_OCTET16_LEN);
+ smp_debug_print_nbyte_little_endian(p_print, "randomizer", OCTET16_LEN);
p_print = (uint8_t*)&p_cb->sc_oob_data.loc_oob_data.commitment;
- smp_debug_print_nbyte_little_endian(p_print, "commitment", BT_OCTET16_LEN);
+ smp_debug_print_nbyte_little_endian(p_print, "commitment", OCTET16_LEN);
SMP_TRACE_DEBUG("");
#endif
@@ -1922,6 +1893,11 @@
}
}
+void smp_cancel_start_encryption_attempt() {
+ SMP_TRACE_ERROR("%s: Encryption request cancelled", __func__);
+ smp_sm_event(&smp_cb, SMP_DISCARD_SEC_REQ_EVT, NULL);
+}
+
/*******************************************************************************
*
* Function smp_proc_ltk_request
diff --git a/stack/smp/smp_api.cc b/stack/smp/smp_api.cc
index d096da5..e082356 100644
--- a/stack/smp/smp_api.cc
+++ b/stack/smp/smp_api.cc
@@ -62,7 +62,7 @@
smp_l2cap_if_init();
/* initialization of P-256 parameters */
- p_256_init_curve(KEY_LENGTH_DWORDS_P256);
+ p_256_init_curve();
/* Initialize failure case for certification */
smp_cb.cert_failure =
@@ -328,7 +328,7 @@
smp_int_data.passkey = passkey;
smp_sm_event(&smp_cb, SMP_SC_KEY_READY_EVT, &smp_int_data);
} else {
- smp_convert_string_to_tk(p_cb->tk, passkey);
+ smp_convert_string_to_tk(&p_cb->tk, passkey);
}
return;
@@ -406,12 +406,12 @@
smp_int_data.status = SMP_OOB_FAIL;
smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
} else {
- if (len > BT_OCTET16_LEN) len = BT_OCTET16_LEN;
+ if (len > OCTET16_LEN) len = OCTET16_LEN;
- memcpy(p_cb->tk, p_data, len);
+ memcpy(p_cb->tk.data(), p_data, len);
key.key_type = SMP_KEY_TYPE_TK;
- key.p_data = p_cb->tk;
+ key.p_data = p_cb->tk.data();
tSMP_INT_DATA smp_int_data;
smp_int_data.key = key;
@@ -484,31 +484,6 @@
/*******************************************************************************
*
- * Function SMP_Encrypt
- *
- * Description This function is called to encrypt the data with the
- * specified key
- *
- * Parameters: key - Pointer to key key[0] conatins the MSB
- * key_len - key length
- * plain_text - Pointer to data to be encrypted
- * plain_text[0] conatins the MSB
- * pt_len - plain text length
- * p_out - output of the encrypted texts
- *
- * Returns Boolean - request is successful
- ******************************************************************************/
-bool SMP_Encrypt(uint8_t* key, uint8_t key_len, uint8_t* plain_text,
- uint8_t pt_len, tSMP_ENC* p_out)
-
-{
- bool status = false;
- status = smp_encrypt_data(key, key_len, plain_text, pt_len, p_out);
- return status;
-}
-
-/*******************************************************************************
- *
* Function SMP_KeypressNotification
*
* Description This function is called to notify Security Manager about
diff --git a/stack/smp/smp_cmac.cc b/stack/smp/smp_cmac.cc
deleted file mode 100644
index 42f91a0..0000000
--- a/stack/smp/smp_cmac.cc
+++ /dev/null
@@ -1,313 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2008-2012 Broadcom 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.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- * This file contains the implementation of the AES128 CMAC algorithm.
- *
- ******************************************************************************/
-
-#include "bt_target.h"
-
-#include <stdio.h>
-#include <string.h>
-
-#include "btm_ble_api.h"
-#include "hcimsgs.h"
-#include "smp_int.h"
-
-typedef struct {
- uint8_t* text;
- uint16_t len;
- uint16_t round;
-} tCMAC_CB;
-
-tCMAC_CB cmac_cb;
-
-/* Rb for AES-128 as block cipher, LSB as [0] */
-BT_OCTET16 const_Rb = {0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-
-void print128(BT_OCTET16 x, const uint8_t* key_name) {
-#if (SMP_DEBUG == TRUE && SMP_DEBUG_VERBOSE == TRUE)
- uint8_t* p = (uint8_t*)x;
- uint8_t i;
-
- SMP_TRACE_WARNING("%s(MSB ~ LSB) = ", key_name);
-
- for (i = 0; i < 4; i++) {
- SMP_TRACE_WARNING("%02x %02x %02x %02x", p[BT_OCTET16_LEN - i * 4 - 1],
- p[BT_OCTET16_LEN - i * 4 - 2],
- p[BT_OCTET16_LEN - i * 4 - 3],
- p[BT_OCTET16_LEN - i * 4 - 4]);
- }
-#endif
-}
-
-/*******************************************************************************
- *
- * Function padding
- *
- * Description utility function to padding the given text to be a 128 bits
- * data. The parameter dest is input and output parameter, it
- * must point to a BT_OCTET16_LEN memory space; where include
- * length bytes valid data.
- *
- * Returns void
- *
- ******************************************************************************/
-static void padding(BT_OCTET16 dest, uint8_t length) {
- uint8_t i, *p = dest;
- /* original last block */
- for (i = length; i < BT_OCTET16_LEN; i++)
- p[BT_OCTET16_LEN - i - 1] = (i == length) ? 0x80 : 0;
-}
-/*******************************************************************************
- *
- * Function leftshift_onebit
- *
- * Description utility function to left shift one bit for a 128 bits value.
- *
- * Returns void
- *
- ******************************************************************************/
-static void leftshift_onebit(uint8_t* input, uint8_t* output) {
- uint8_t i, overflow = 0, next_overflow = 0;
- SMP_TRACE_EVENT("leftshift_onebit ");
- /* input[0] is LSB */
- for (i = 0; i < BT_OCTET16_LEN; i++) {
- next_overflow = (input[i] & 0x80) ? 1 : 0;
- output[i] = (input[i] << 1) | overflow;
- overflow = next_overflow;
- }
- return;
-}
-/*******************************************************************************
- *
- * Function cmac_aes_cleanup
- *
- * Description clean up function for AES_CMAC algorithm.
- *
- * Returns void
- *
- ******************************************************************************/
-static void cmac_aes_cleanup(void) {
- osi_free(cmac_cb.text);
- memset(&cmac_cb, 0, sizeof(tCMAC_CB));
-}
-
-/*******************************************************************************
- *
- * Function cmac_aes_k_calculate
- *
- * Description This function is the calculation of block cipher using
- * AES-128.
- *
- * Returns void
- *
- ******************************************************************************/
-static bool cmac_aes_k_calculate(BT_OCTET16 key, uint8_t* p_signature,
- uint16_t tlen) {
- tSMP_ENC output;
- uint8_t i = 1, err = 0;
- uint8_t x[16] = {0};
- uint8_t* p_mac;
-
- SMP_TRACE_EVENT("cmac_aes_k_calculate ");
-
- while (i <= cmac_cb.round) {
- smp_xor_128(&cmac_cb.text[(cmac_cb.round - i) * BT_OCTET16_LEN],
- x); /* Mi' := Mi (+) X */
-
- if (!SMP_Encrypt(key, BT_OCTET16_LEN,
- &cmac_cb.text[(cmac_cb.round - i) * BT_OCTET16_LEN],
- BT_OCTET16_LEN, &output)) {
- err = 1;
- break;
- }
-
- memcpy(x, output.param_buf, BT_OCTET16_LEN);
- i++;
- }
-
- if (!err) {
- p_mac = output.param_buf + (BT_OCTET16_LEN - tlen);
- memcpy(p_signature, p_mac, tlen);
-
- SMP_TRACE_DEBUG("tlen = %d p_mac = %d", tlen, p_mac);
- SMP_TRACE_DEBUG(
- "p_mac[0] = 0x%02x p_mac[1] = 0x%02x p_mac[2] = 0x%02x p_mac[3] = "
- "0x%02x",
- *p_mac, *(p_mac + 1), *(p_mac + 2), *(p_mac + 3));
- SMP_TRACE_DEBUG(
- "p_mac[4] = 0x%02x p_mac[5] = 0x%02x p_mac[6] = 0x%02x p_mac[7] = "
- "0x%02x",
- *(p_mac + 4), *(p_mac + 5), *(p_mac + 6), *(p_mac + 7));
-
- return true;
-
- } else
- return false;
-}
-/*******************************************************************************
- *
- * Function cmac_prepare_last_block
- *
- * Description This function proceeed to prepare the last block of message
- * Mn depending on the size of the message.
- *
- * Returns void
- *
- ******************************************************************************/
-static void cmac_prepare_last_block(BT_OCTET16 k1, BT_OCTET16 k2) {
- // uint8_t x[16] = {0};
- bool flag;
-
- SMP_TRACE_EVENT("cmac_prepare_last_block ");
- /* last block is a complete block set flag to 1 */
- flag =
- ((cmac_cb.len % BT_OCTET16_LEN) == 0 && cmac_cb.len != 0) ? true : false;
-
- SMP_TRACE_WARNING("flag = %d round = %d", flag, cmac_cb.round);
-
- if (flag) { /* last block is complete block */
- smp_xor_128(&cmac_cb.text[0], k1);
- } else /* padding then xor with k2 */
- {
- padding(&cmac_cb.text[0], (uint8_t)(cmac_cb.len % 16));
-
- smp_xor_128(&cmac_cb.text[0], k2);
- }
-}
-/*******************************************************************************
- *
- * Function cmac_subkey_cont
- *
- * Description This is the callback function when CIPHk(0[128]) is
- * completed.
- *
- * Returns void
- *
- ******************************************************************************/
-static void cmac_subkey_cont(tSMP_ENC* p) {
- uint8_t k1[BT_OCTET16_LEN], k2[BT_OCTET16_LEN];
- uint8_t* pp = p->param_buf;
- SMP_TRACE_EVENT("cmac_subkey_cont ");
- print128(pp, (const uint8_t*)"K1 before shift");
-
- /* If MSB(L) = 0, then K1 = L << 1 */
- if ((pp[BT_OCTET16_LEN - 1] & 0x80) != 0) {
- /* Else K1 = ( L << 1 ) (+) Rb */
- leftshift_onebit(pp, k1);
- smp_xor_128(k1, const_Rb);
- } else {
- leftshift_onebit(pp, k1);
- }
-
- if ((k1[BT_OCTET16_LEN - 1] & 0x80) != 0) {
- /* K2 = (K1 << 1) (+) Rb */
- leftshift_onebit(k1, k2);
- smp_xor_128(k2, const_Rb);
- } else {
- /* If MSB(K1) = 0, then K2 = K1 << 1 */
- leftshift_onebit(k1, k2);
- }
-
- print128(k1, (const uint8_t*)"K1");
- print128(k2, (const uint8_t*)"K2");
-
- cmac_prepare_last_block(k1, k2);
-}
-/*******************************************************************************
- *
- * Function cmac_generate_subkey
- *
- * Description This is the function to generate the two subkeys.
- *
- * Parameters key - CMAC key, expect SRK when used by SMP.
- *
- * Returns void
- *
- ******************************************************************************/
-static bool cmac_generate_subkey(BT_OCTET16 key) {
- BT_OCTET16 z = {0};
- bool ret = true;
- tSMP_ENC output;
- SMP_TRACE_EVENT(" cmac_generate_subkey");
-
- if (SMP_Encrypt(key, BT_OCTET16_LEN, z, BT_OCTET16_LEN, &output)) {
- cmac_subkey_cont(&output);
- ;
- } else
- ret = false;
-
- return ret;
-}
-/*******************************************************************************
- *
- * Function aes_cipher_msg_auth_code
- *
- * Description This is the AES-CMAC Generation Function with tlen
- * implemented.
- *
- * Parameters key - CMAC key in little endian order, expect SRK when used
- * by SMP.
- * input - text to be signed in little endian byte order.
- * length - length of the input in byte.
- * tlen - lenth of mac desired
- * p_signature - data pointer to where signed data to be
- * stored, tlen long.
- *
- * Returns false if out of resources, true in other cases.
- *
- ******************************************************************************/
-bool aes_cipher_msg_auth_code(BT_OCTET16 key, uint8_t* input, uint16_t length,
- uint16_t tlen, uint8_t* p_signature) {
- uint16_t len, diff;
- uint16_t n = (length + BT_OCTET16_LEN - 1) /
- BT_OCTET16_LEN; /* n is number of rounds */
- bool ret = false;
-
- SMP_TRACE_EVENT("%s", __func__);
-
- if (n == 0) n = 1;
- len = n * BT_OCTET16_LEN;
-
- SMP_TRACE_WARNING("AES128_CMAC started, allocate buffer size = %d", len);
- /* allocate a memory space of multiple of 16 bytes to hold text */
- cmac_cb.text = (uint8_t*)osi_calloc(len);
- cmac_cb.round = n;
- diff = len - length;
-
- if (input != NULL && length > 0) {
- memcpy(&cmac_cb.text[diff], input, (int)length);
- cmac_cb.len = length;
- } else {
- cmac_cb.len = 0;
- }
-
- /* prepare calculation for subkey s and last block of data */
- if (cmac_generate_subkey(key)) {
- /* start calculation */
- ret = cmac_aes_k_calculate(key, p_signature, tlen);
- }
- /* clean up */
- cmac_aes_cleanup();
-
- return ret;
-}
diff --git a/stack/smp/smp_int.h b/stack/smp/smp_int.h
index 1685ffe..9886d4f 100644
--- a/stack/smp/smp_int.h
+++ b/stack/smp/smp_int.h
@@ -28,6 +28,7 @@
#include "btm_ble_api.h"
#include "btu.h"
#include "smp_api.h"
+#include "stack/crypto_toolbox/crypto_toolbox.h"
/* Legacy mode */
#define SMP_MODEL_ENCRYPTION_ONLY 0 /* Just Works model */
@@ -244,10 +245,6 @@
/* check if authentication requirement need MITM protection */
#define SMP_NO_MITM_REQUIRED(x) (((x)&SMP_AUTH_YN_BIT) == 0)
-#define SMP_ENCRYT_KEY_SIZE 16
-#define SMP_ENCRYT_DATA_SIZE 16
-#define SMP_ECNCRPYT_STATUS HCI_SUCCESS
-
typedef struct {
RawAddress bd_addr;
BT_HDR* p_copy;
@@ -273,18 +270,18 @@
uint8_t cb_evt;
tSMP_SEC_LEVEL sec_level;
bool connect_initialized;
- BT_OCTET16 confirm;
- BT_OCTET16 rconfirm;
- BT_OCTET16 rrand; /* for SC this is peer nonce */
- BT_OCTET16 rand; /* for SC this is local nonce */
+ Octet16 confirm;
+ Octet16 rconfirm;
+ Octet16 rrand; /* for SC this is peer nonce */
+ Octet16 rand; /* for SC this is local nonce */
BT_OCTET32 private_key;
BT_OCTET32 dhkey;
- BT_OCTET16 commitment;
- BT_OCTET16 remote_commitment;
- BT_OCTET16 local_random; /* local randomizer - passkey or OOB randomizer */
- BT_OCTET16 peer_random; /* peer randomizer - passkey or OOB randomizer */
- BT_OCTET16 dhkey_check;
- BT_OCTET16 remote_dhkey_check;
+ Octet16 commitment;
+ Octet16 remote_commitment;
+ Octet16 local_random; /* local randomizer - passkey or OOB randomizer */
+ Octet16 peer_random; /* peer randomizer - passkey or OOB randomizer */
+ Octet16 dhkey_check;
+ Octet16 remote_dhkey_check;
tSMP_PUBLIC_KEY loc_publ_key;
tSMP_PUBLIC_KEY peer_publ_key;
tSMP_OOB_DATA_TYPE req_oob_type;
@@ -307,7 +304,7 @@
uint8_t
round; /* authentication stage 1 round for passkey association model */
uint32_t number_to_display;
- BT_OCTET16 mac_key;
+ Octet16 mac_key;
uint8_t peer_enc_size;
uint8_t loc_enc_size;
uint8_t peer_i_key;
@@ -315,10 +312,10 @@
uint8_t local_i_key;
uint8_t local_r_key;
- BT_OCTET16 tk;
- BT_OCTET16 ltk;
+ Octet16 tk;
+ Octet16 ltk;
uint16_t div;
- BT_OCTET16 csrk; /* storage for local CSRK */
+ Octet16 csrk; /* storage for local CSRK */
uint16_t ediv;
BT_OCTET8 enc_rand;
uint8_t addr_type;
@@ -345,29 +342,6 @@
extern void smp_sm_event(tSMP_CB* p_cb, tSMP_EVENT event,
tSMP_INT_DATA* p_data);
-extern void smp_proc_sec_request(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
-extern void smp_set_fail_nc(bool enable);
-extern void smp_set_fail_conf(bool enable);
-extern void smp_set_passk_entry_fail(bool enable);
-extern void smp_set_oob_fail(bool enable);
-extern void smp_set_peer_sc_notif(bool enable);
-extern void smp_aes_cmac_rfc4493_chk(uint8_t* key, uint8_t* msg,
- uint8_t msg_len, uint8_t mac_len,
- uint8_t* mac);
-extern void smp_f4_calc_chk(uint8_t* U, uint8_t* V, uint8_t* X, uint8_t* Z,
- uint8_t* mac);
-extern void smp_g2_calc_chk(uint8_t* U, uint8_t* V, uint8_t* X, uint8_t* Y);
-extern void smp_h6_calc_chk(uint8_t* key, uint8_t* key_id, uint8_t* mac);
-extern void smp_f5_key_calc_chk(uint8_t* w, uint8_t* mac);
-extern void smp_f5_mackey_or_ltk_calc_chk(uint8_t* t, uint8_t* counter,
- uint8_t* key_id, uint8_t* n1,
- uint8_t* n2, uint8_t* a1, uint8_t* a2,
- uint8_t* length, uint8_t* mac);
-extern void smp_f5_calc_chk(uint8_t* w, uint8_t* n1, uint8_t* n2, uint8_t* a1,
- uint8_t* a2, uint8_t* mac_key, uint8_t* ltk);
-extern void smp_f6_calc_chk(uint8_t* w, uint8_t* n1, uint8_t* n2, uint8_t* r,
- uint8_t* iocap, uint8_t* a1, uint8_t* a2,
- uint8_t* mac);
extern tSMP_STATE smp_get_state(void);
extern void smp_set_state(tSMP_STATE state);
@@ -419,7 +393,6 @@
extern void smp_key_distribution(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
extern void smp_proc_srk_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
extern void smp_generate_csrk(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
-extern void smp_fast_conn_param(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
extern void smp_key_pick_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
extern void smp_both_have_public_keys(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
extern void smp_start_secure_connection_phase1(tSMP_CB* p_cb,
@@ -467,17 +440,16 @@
extern void smp_data_ind(const RawAddress& bd_addr, BT_HDR* p_buf);
/* smp_util.cc */
+extern void smp_log_metrics(const RawAddress& bd_addr, bool is_outgoing,
+ const uint8_t* p_buf, size_t buf_len);
extern bool smp_send_cmd(uint8_t cmd_code, tSMP_CB* p_cb);
extern void smp_cb_cleanup(tSMP_CB* p_cb);
extern void smp_reset_control_value(tSMP_CB* p_cb);
extern void smp_proc_pairing_cmpl(tSMP_CB* p_cb);
-extern void smp_convert_string_to_tk(BT_OCTET16 tk, uint32_t passkey);
-extern void smp_mask_enc_key(uint8_t loc_enc_size, uint8_t* p_data);
+extern void smp_convert_string_to_tk(Octet16* tk, uint32_t passkey);
+extern void smp_mask_enc_key(uint8_t loc_enc_size, Octet16* p_data);
extern void smp_rsp_timeout(void* data);
extern void smp_delayed_auth_complete_timeout(void* data);
-extern void smp_xor_128(BT_OCTET16 a, BT_OCTET16 b);
-extern bool smp_encrypt_data(uint8_t* key, uint8_t key_len, uint8_t* plain_text,
- uint8_t pt_len, tSMP_ENC* p_out);
extern bool smp_command_has_invalid_parameters(tSMP_CB* p_cb);
extern void smp_reject_unexpected_pairing_command(const RawAddress& bd_addr);
extern tSMP_ASSO_MODEL smp_select_association_model(tSMP_CB* p_cb);
@@ -489,7 +461,7 @@
extern void smp_collect_peer_ble_address(uint8_t* le_addr, tSMP_CB* p_cb);
extern bool smp_check_commitment(tSMP_CB* p_cb);
extern void smp_save_secure_connections_long_term_key(tSMP_CB* p_cb);
-extern bool smp_calculate_f5_mackey_and_long_term_key(tSMP_CB* p_cb);
+extern void smp_calculate_f5_mackey_and_long_term_key(tSMP_CB* p_cb);
extern void smp_remove_fixed_channel(tSMP_CB* p_cb);
extern bool smp_request_oob_data(tSMP_CB* p_cb);
@@ -505,7 +477,7 @@
extern void smp_use_oob_private_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
extern void smp_compute_dhkey(tSMP_CB* p_cb);
extern void smp_calculate_local_commitment(tSMP_CB* p_cb);
-extern void smp_calculate_peer_commitment(tSMP_CB* p_cb, BT_OCTET16 output_buf);
+extern Octet16 smp_calculate_peer_commitment(tSMP_CB* p_cb);
extern void smp_calculate_numeric_comparison_display_number(
tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
extern void smp_calculate_local_dhkey_check(tSMP_CB* p_cb,
@@ -515,31 +487,21 @@
extern void smp_start_nonce_generation(tSMP_CB* p_cb);
extern bool smp_calculate_link_key_from_long_term_key(tSMP_CB* p_cb);
extern bool smp_calculate_long_term_key_from_link_key(tSMP_CB* p_cb);
-extern void smp_calculate_f4(uint8_t* u, uint8_t* v, uint8_t* x, uint8_t z,
- uint8_t* c);
-extern uint32_t smp_calculate_g2(uint8_t* u, uint8_t* v, uint8_t* x,
- uint8_t* y);
-extern bool smp_calculate_f5(uint8_t* w, uint8_t* n1, uint8_t* n2, uint8_t* a1,
- uint8_t* a2, uint8_t* mac_key, uint8_t* ltk);
-extern bool smp_calculate_f5_mackey_or_long_term_key(
- uint8_t* t, uint8_t* counter, uint8_t* key_id, uint8_t* n1, uint8_t* n2,
- uint8_t* a1, uint8_t* a2, uint8_t* length, uint8_t* mac);
-extern bool smp_calculate_f5_key(uint8_t* w, uint8_t* t);
-extern bool smp_calculate_f6(uint8_t* w, uint8_t* n1, uint8_t* n2, uint8_t* r,
- uint8_t* iocap, uint8_t* a1, uint8_t* a2,
- uint8_t* f3);
-extern bool smp_calculate_h6(uint8_t* w, uint8_t* keyid, uint8_t* h2);
-extern bool smp_calculate_h7(uint8_t* salt, uint8_t* w, uint8_t* h2);
+
#if (SMP_DEBUG == TRUE)
extern void smp_debug_print_nbyte_little_endian(uint8_t* p,
const char* key_name,
uint8_t len);
+
+inline void smp_debug_print_nbyte_little_endian(const Octet16& p,
+ const char* key_name,
+ uint8_t len) {
+ smp_debug_print_nbyte_little_endian(const_cast<uint8_t*>(p.data()), key_name,
+ len);
+}
#endif
-/* smp_cmac.cc */
-extern bool aes_cipher_msg_auth_code(BT_OCTET16 key, uint8_t* input,
- uint16_t length, uint16_t tlen,
- uint8_t* p_signature);
-extern void print128(BT_OCTET16 x, const uint8_t* key_name);
+extern void print128(const Octet16& x, const uint8_t* key_name);
+extern void smp_xor_128(Octet16* a, const Octet16& b);
#endif /* SMP_INT_H */
diff --git a/stack/smp/smp_keys.cc b/stack/smp/smp_keys.cc
index 6be1da4..64c969d 100644
--- a/stack/smp/smp_keys.cc
+++ b/stack/smp/smp_keys.cc
@@ -28,7 +28,6 @@
#endif
#include <base/bind.h>
#include <string.h>
-#include "aes.h"
#include "bt_utils.h"
#include "btm_ble_api.h"
#include "btm_ble_int.h"
@@ -38,16 +37,19 @@
#include "osi/include/osi.h"
#include "p_256_ecc_pp.h"
#include "smp_int.h"
+#include "stack/crypto_toolbox/crypto_toolbox.h"
+
+#include <algorithm>
using base::Bind;
+using crypto_toolbox::aes_128;
#ifndef SMP_MAX_ENC_REPEAT
#define SMP_MAX_ENC_REPEAT 3
#endif
-static void smp_process_stk(tSMP_CB* p_cb, tSMP_ENC* p);
-static bool smp_calculate_legacy_short_term_key(tSMP_CB* p_cb,
- tSMP_ENC* output);
+static void smp_process_stk(tSMP_CB* p_cb, Octet16* p);
+static Octet16 smp_calculate_legacy_short_term_key(tSMP_CB* p_cb);
static void smp_process_private_key(tSMP_CB* p_cb);
#define SMP_PASSKEY_MASK 0xfff00000
@@ -75,6 +77,13 @@
#endif
}
+inline void smp_debug_print_nbyte_little_endian(const Octet16& p,
+ const char* key_name,
+ uint8_t len) {
+ smp_debug_print_nbyte_little_endian(const_cast<uint8_t*>(p.data()), key_name,
+ len);
+}
+
void smp_debug_print_nbyte_big_endian(uint8_t* p, const char* key_name,
uint8_t len) {
#if (SMP_DEBUG == TRUE)
@@ -98,80 +107,9 @@
#endif
}
-/*******************************************************************************
- *
- * Function smp_encrypt_data
- *
- * Description This function is called to encrypt data.
- * It uses AES-128 encryption algorithm.
- * Plain_text is encrypted using key, the result is at p_out.
- *
- * Returns void
- *
- ******************************************************************************/
-bool smp_encrypt_data(uint8_t* key, uint8_t key_len, uint8_t* plain_text,
- uint8_t pt_len, tSMP_ENC* p_out) {
- aes_context ctx;
- uint8_t* p_start = NULL;
- uint8_t* p = NULL;
- uint8_t* p_rev_data = NULL; /* input data in big endilan format */
- uint8_t* p_rev_key = NULL; /* input key in big endilan format */
- uint8_t* p_rev_output = NULL; /* encrypted output in big endilan format */
-
- SMP_TRACE_DEBUG("%s", __func__);
- if ((p_out == NULL) || (key_len != SMP_ENCRYT_KEY_SIZE)) {
- SMP_TRACE_ERROR("%s failed", __func__);
- return false;
- }
-
- p_start = (uint8_t*)osi_calloc(SMP_ENCRYT_DATA_SIZE * 4);
-
- if (pt_len > SMP_ENCRYT_DATA_SIZE) pt_len = SMP_ENCRYT_DATA_SIZE;
-
- p = p_start;
- ARRAY_TO_STREAM(p, plain_text, pt_len); /* byte 0 to byte 15 */
- p_rev_data = p = p_start + SMP_ENCRYT_DATA_SIZE; /* start at byte 16 */
- REVERSE_ARRAY_TO_STREAM(p, p_start,
- SMP_ENCRYT_DATA_SIZE); /* byte 16 to byte 31 */
- p_rev_key = p; /* start at byte 32 */
- REVERSE_ARRAY_TO_STREAM(p, key, SMP_ENCRYT_KEY_SIZE); /* byte 32 to byte 47 */
-
-#if (SMP_DEBUG == TRUE && SMP_DEBUG_VERBOSE == TRUE)
- smp_debug_print_nbyte_little_endian(key, "Key", SMP_ENCRYT_KEY_SIZE);
- smp_debug_print_nbyte_little_endian(p_start, "Plain text",
- SMP_ENCRYT_DATA_SIZE);
-#endif
- p_rev_output = p;
- aes_set_key(p_rev_key, SMP_ENCRYT_KEY_SIZE, &ctx);
- aes_encrypt(p_rev_data, p, &ctx); /* outputs in byte 48 to byte 63 */
-
- p = p_out->param_buf;
- REVERSE_ARRAY_TO_STREAM(p, p_rev_output, SMP_ENCRYT_DATA_SIZE);
-#if (SMP_DEBUG == TRUE && SMP_DEBUG_VERBOSE == TRUE)
- smp_debug_print_nbyte_little_endian(p_out->param_buf, "Encrypted text",
- SMP_ENCRYT_KEY_SIZE);
-#endif
-
- p_out->param_len = SMP_ENCRYT_KEY_SIZE;
- p_out->status = HCI_SUCCESS;
- p_out->opcode = HCI_BLE_ENCRYPT;
-
- osi_free(p_start);
-
- return true;
-}
-
-/*******************************************************************************
- *
- * Function smp_proc_passkey
- *
- * Description This function is called to process a passkey.
- *
- * Returns void
- *
- ******************************************************************************/
+/** This function is called to process a passkey. */
void smp_proc_passkey(tSMP_CB* p_cb, BT_OCTET8 rand) {
- uint8_t* tt = p_cb->tk;
+ uint8_t* tt = p_cb->tk.data();
uint32_t passkey; /* 19655 test number; */
uint8_t* pp = rand;
@@ -183,7 +121,7 @@
while (passkey > BTM_MAX_PASSKEY_VAL) passkey >>= 1;
/* save the TK */
- memset(p_cb->tk, 0, BT_OCTET16_LEN);
+ p_cb->tk = {0};
UINT32_TO_STREAM(tt, passkey);
if (p_cb->p_callback) {
@@ -200,7 +138,7 @@
} else {
tSMP_KEY key;
key.key_type = SMP_KEY_TYPE_TK;
- key.p_data = p_cb->tk;
+ key.p_data = p_cb->tk.data();
tSMP_INT_DATA smp_int_data;
smp_int_data.key = key;
smp_sm_event(p_cb, SMP_KEY_READY_EVT, &smp_int_data);
@@ -234,22 +172,15 @@
*
******************************************************************************/
void smp_generate_stk(tSMP_CB* p_cb, UNUSED_ATTR tSMP_INT_DATA* p_data) {
- tSMP_ENC output;
+ Octet16 output;
SMP_TRACE_DEBUG("%s", __func__);
if (p_cb->le_secure_connections_mode_is_used) {
SMP_TRACE_WARNING("FOR LE SC LTK IS USED INSTEAD OF STK");
- output.param_len = SMP_ENCRYT_KEY_SIZE;
- output.status = HCI_SUCCESS;
- output.opcode = HCI_BLE_ENCRYPT;
- memcpy(output.param_buf, p_cb->ltk, SMP_ENCRYT_DATA_SIZE);
- } else if (!smp_calculate_legacy_short_term_key(p_cb, &output)) {
- SMP_TRACE_ERROR("%s failed", __func__);
- tSMP_INT_DATA smp_int_data;
- smp_int_data.status = SMP_PAIR_FAIL_UNKNOWN;
- smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
- return;
+ output = p_cb->ltk;
+ } else {
+ output = smp_calculate_legacy_short_term_key(p_cb);
}
smp_process_stk(p_cb, &output);
@@ -259,33 +190,20 @@
* This function is called to calculate CSRK
*/
void smp_compute_csrk(uint16_t div, tSMP_CB* p_cb) {
- BT_OCTET16 er;
uint8_t buffer[4]; /* for (r || DIV) r=1*/
uint16_t r = 1;
uint8_t* p = buffer;
- tSMP_ENC output;
p_cb->div = div;
SMP_TRACE_DEBUG("%s: div=%x", __func__, p_cb->div);
- BTM_GetDeviceEncRoot(er);
+ const Octet16& er = BTM_GetDeviceEncRoot();
/* CSRK = d1(ER, DIV, 1) */
UINT16_TO_STREAM(p, p_cb->div);
UINT16_TO_STREAM(p, r);
- if (!SMP_Encrypt(er, BT_OCTET16_LEN, buffer, 4, &output)) {
- SMP_TRACE_ERROR("smp_generate_csrk failed");
- tSMP_INT_DATA smp_int_data;
- smp_int_data.status = SMP_PAIR_FAIL_UNKNOWN;
- if (p_cb->smp_over_br) {
- smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &smp_int_data);
- } else {
- smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
- }
- } else {
- memcpy((void*)p_cb->csrk, output.param_buf, BT_OCTET16_LEN);
- smp_send_csrk_info(p_cb, NULL);
- }
+ p_cb->csrk = aes_128(er, buffer, 4);
+ smp_send_csrk_info(p_cb, NULL);
}
/**
@@ -349,22 +267,16 @@
*p_data = p;
}
-/*******************************************************************************
- *
- * Function smp_gen_p1_4_confirm
- *
- * Description Generate Confirm/Compare Step1:
+/** Generate Confirm/Compare Step1:
* p1 = (MSB) pres || preq || rat' || iat' (LSB)
* Fill in values LSB first thus
* p1 = iat' || rat' || preq || pres
- *
- * Returns void
- *
- ******************************************************************************/
-void smp_gen_p1_4_confirm(tSMP_CB* p_cb, tBLE_ADDR_TYPE remote_bd_addr_type,
- BT_OCTET16 p1) {
+ */
+Octet16 smp_gen_p1_4_confirm(tSMP_CB* p_cb,
+ tBLE_ADDR_TYPE remote_bd_addr_type) {
SMP_TRACE_DEBUG("%s", __func__);
- uint8_t* p = (uint8_t*)p1;
+ Octet16 p1;
+ uint8_t* p = p1.data();
if (p_cb->role == HCI_ROLE_MASTER) {
/* iat': initiator's (local) address type */
UINT8_TO_STREAM(p, p_cb->addr_type);
@@ -384,28 +296,23 @@
/* pres : Pairing Response (local) command */
smp_concatenate_local(p_cb, &p, SMP_OPCODE_PAIRING_RSP);
}
- smp_debug_print_nbyte_little_endian((uint8_t*)p1,
- "p1 = iat' || rat' || preq || pres", 16);
+ smp_debug_print_nbyte_little_endian(p1, "p1 = iat' || rat' || preq || pres",
+ 16);
+
+ return p1;
}
-/*******************************************************************************
- *
- * Function smp_gen_p2_4_confirm
- *
- * Description Generate Confirm/Compare Step2:
+/** Generate Confirm/Compare Step2:
* p2 = (MSB) padding || ia || ra (LSB)
* Fill values LSB first and thus:
* p2 = ra || ia || padding
- *
- * Returns void
- *
- ******************************************************************************/
-void smp_gen_p2_4_confirm(tSMP_CB* p_cb, const RawAddress& remote_bda,
- BT_OCTET16 p2) {
+ */
+Octet16 smp_gen_p2_4_confirm(tSMP_CB* p_cb, const RawAddress& remote_bda) {
SMP_TRACE_DEBUG("%s", __func__);
- uint8_t* p = (uint8_t*)p2;
+ Octet16 p2{0};
+ uint8_t* p = p2.data();
/* 32-bit Padding */
- memset(p, 0, sizeof(BT_OCTET16));
+ memset(p, 0, OCTET16_LEN);
if (p_cb->role == HCI_ROLE_MASTER) {
/* ra : Responder's (remote) address */
BDADDR_TO_STREAM(p, remote_bda);
@@ -418,6 +325,7 @@
BDADDR_TO_STREAM(p, remote_bda);
}
smp_debug_print_nbyte_little_endian(p2, "p2 = ra || ia || padding", 16);
+ return p2;
}
/*******************************************************************************
@@ -429,8 +337,8 @@
* Returns tSMP_STATUS status of confirmation calculation
*
******************************************************************************/
-tSMP_STATUS smp_calculate_comfirm(tSMP_CB* p_cb, BT_OCTET16 rand,
- tSMP_ENC* output) {
+tSMP_STATUS smp_calculate_comfirm(tSMP_CB* p_cb, const Octet16& rand,
+ Octet16* output) {
SMP_TRACE_DEBUG("%s", __func__);
RawAddress remote_bda;
tBLE_ADDR_TYPE remote_bd_addr_type = 0;
@@ -443,31 +351,21 @@
/* get local connection specific bluetooth address */
BTM_ReadConnectionAddr(p_cb->pairing_bda, p_cb->local_bda, &p_cb->addr_type);
/* generate p1 = pres || preq || rat' || iat' */
- BT_OCTET16 p1;
- smp_gen_p1_4_confirm(p_cb, remote_bd_addr_type, p1);
+ Octet16 p1 = smp_gen_p1_4_confirm(p_cb, remote_bd_addr_type);
/* p1' = rand XOR p1 */
- smp_xor_128(p1, rand);
- smp_debug_print_nbyte_little_endian((uint8_t*)p1, "p1' = p1 XOR r", 16);
+ smp_xor_128(&p1, rand);
+ smp_debug_print_nbyte_little_endian(p1, "p1' = p1 XOR r", 16);
/* calculate e1 = e(k, p1'), where k = TK */
- smp_debug_print_nbyte_little_endian(p_cb->tk, "TK", 16);
- memset(output, 0, sizeof(tSMP_ENC));
- if (!SMP_Encrypt(p_cb->tk, BT_OCTET16_LEN, p1, BT_OCTET16_LEN, output)) {
- SMP_TRACE_ERROR("%s: failed encryption at e1 = e(k, p1')");
- return SMP_PAIR_FAIL_UNKNOWN;
- }
- smp_debug_print_nbyte_little_endian(output->param_buf, "e1 = e(k, p1')", 16);
+ smp_debug_print_nbyte_little_endian(p_cb->tk.data(), "TK", 16);
+ Octet16 e1 = aes_128(p_cb->tk, p1);
+ smp_debug_print_nbyte_little_endian(e1.data(), "e1 = e(k, p1')", 16);
/* generate p2 = padding || ia || ra */
- BT_OCTET16 p2;
- smp_gen_p2_4_confirm(p_cb, remote_bda, p2);
+ Octet16 p2 = smp_gen_p2_4_confirm(p_cb, remote_bda);
/* calculate p2' = (p2 XOR e1) */
- smp_xor_128(p2, output->param_buf);
- smp_debug_print_nbyte_little_endian((uint8_t*)p2, "p2' = p2 XOR e1", 16);
+ smp_xor_128(&p2, e1);
+ smp_debug_print_nbyte_little_endian(p2, "p2' = p2 XOR e1", 16);
/* calculate: c1 = e(k, p2') */
- memset(output, 0, sizeof(tSMP_ENC));
- if (!SMP_Encrypt(p_cb->tk, BT_OCTET16_LEN, p2, BT_OCTET16_LEN, output)) {
- SMP_TRACE_ERROR("%s: failed encryption at e1 = e(k, p2')");
- return SMP_PAIR_FAIL_UNKNOWN;
- }
+ *output = aes_128(p_cb->tk, p2);
return SMP_SUCCESS;
}
@@ -484,8 +382,8 @@
******************************************************************************/
static void smp_generate_confirm(tSMP_CB* p_cb) {
SMP_TRACE_DEBUG("%s", __func__);
- smp_debug_print_nbyte_little_endian((uint8_t*)p_cb->rand, "local_rand", 16);
- tSMP_ENC output;
+ smp_debug_print_nbyte_little_endian(p_cb->rand.data(), "local_rand", 16);
+ Octet16 output;
tSMP_STATUS status = smp_calculate_comfirm(p_cb, p_cb->rand, &output);
if (status != SMP_SUCCESS) {
tSMP_INT_DATA smp_int_data;
@@ -494,11 +392,11 @@
return;
}
tSMP_KEY key;
- memcpy(p_cb->confirm, output.param_buf, BT_OCTET16_LEN);
+ p_cb->confirm = output;
smp_debug_print_nbyte_little_endian(p_cb->confirm, "Local Confirm generated",
16);
key.key_type = SMP_KEY_TYPE_CFM;
- key.p_data = output.param_buf;
+ key.p_data = output.data();
tSMP_INT_DATA smp_int_data;
smp_int_data.key = key;
smp_sm_event(p_cb, SMP_KEY_READY_EVT, &smp_int_data);
@@ -521,7 +419,7 @@
/* generate MRand or SRand */
btsnd_hcic_ble_rand(Bind(
[](tSMP_CB* p_cb, BT_OCTET8 rand) {
- memcpy((void*)p_cb->rand, rand, 8);
+ memcpy(p_cb->rand.data(), rand, 8);
/* generate 64 MSB of MRand or SRand */
btsnd_hcic_ble_rand(Bind(
@@ -548,8 +446,8 @@
******************************************************************************/
void smp_generate_compare(tSMP_CB* p_cb, UNUSED_ATTR tSMP_INT_DATA* p_data) {
SMP_TRACE_DEBUG("smp_generate_compare ");
- smp_debug_print_nbyte_little_endian((uint8_t*)p_cb->rrand, "peer rand", 16);
- tSMP_ENC output;
+ smp_debug_print_nbyte_little_endian(p_cb->rrand, "peer rand", 16);
+ Octet16 output;
tSMP_STATUS status = smp_calculate_comfirm(p_cb, p_cb->rrand, &output);
if (status != SMP_SUCCESS) {
tSMP_INT_DATA smp_int_data;
@@ -558,48 +456,38 @@
return;
}
tSMP_KEY key;
- smp_debug_print_nbyte_little_endian(output.param_buf,
- "Remote Confirm generated", 16);
+ smp_debug_print_nbyte_little_endian(output.data(), "Remote Confirm generated",
+ 16);
key.key_type = SMP_KEY_TYPE_CMP;
- key.p_data = output.param_buf;
+ key.p_data = output.data();
tSMP_INT_DATA smp_int_data;
smp_int_data.key = key;
smp_sm_event(p_cb, SMP_KEY_READY_EVT, &smp_int_data);
}
-/*******************************************************************************
- *
- * Function smp_process_stk
- *
- * Description This function is called when STK is generated
- * proceed to send the encrypt the link using STK.
- *
- * Returns void
- *
- ******************************************************************************/
-static void smp_process_stk(tSMP_CB* p_cb, tSMP_ENC* p) {
+/** This function is called when STK is generated proceed to send the encrypt
+ * the link using STK. */
+static void smp_process_stk(tSMP_CB* p_cb, Octet16* p) {
tSMP_KEY key;
SMP_TRACE_DEBUG("smp_process_stk ");
#if (SMP_DEBUG == TRUE)
SMP_TRACE_ERROR("STK Generated");
#endif
- smp_mask_enc_key(p_cb->loc_enc_size, p->param_buf);
+ smp_mask_enc_key(p_cb->loc_enc_size, p);
key.key_type = SMP_KEY_TYPE_STK;
- key.p_data = p->param_buf;
+ key.p_data = p->data();
tSMP_INT_DATA smp_int_data;
smp_int_data.key = key;
smp_sm_event(p_cb, SMP_KEY_READY_EVT, &smp_int_data);
}
-/**
- * This function is to calculate EDIV = Y xor DIV
- */
-static void smp_process_ediv(tSMP_CB* p_cb, tSMP_ENC* p) {
+/** This function calculates EDIV = Y xor DIV */
+static void smp_process_ediv(tSMP_CB* p_cb, Octet16& p) {
tSMP_KEY key;
- uint8_t* pp = p->param_buf;
+ uint8_t* pp = p.data();
uint16_t y;
SMP_TRACE_DEBUG("smp_process_ediv ");
@@ -610,7 +498,7 @@
/* send LTK ready */
SMP_TRACE_ERROR("LTK ready");
key.key_type = SMP_KEY_TYPE_LTK;
- key.p_data = p->param_buf;
+ key.p_data = p.data();
tSMP_INT_DATA smp_int_data;
smp_int_data.key = key;
@@ -623,19 +511,11 @@
static void smp_generate_y(tSMP_CB* p_cb, BT_OCTET8 rand) {
SMP_TRACE_DEBUG("%s ", __func__);
- BT_OCTET16 dhk;
- BTM_GetDeviceDHK(dhk);
+ const Octet16& dhk = BTM_GetDeviceDHK();
memcpy(p_cb->enc_rand, rand, BT_OCTET8_LEN);
- tSMP_ENC output;
- if (!SMP_Encrypt(dhk, BT_OCTET16_LEN, rand, BT_OCTET8_LEN, &output)) {
- SMP_TRACE_ERROR("%s failed", __func__);
- tSMP_INT_DATA smp_int_data;
- smp_int_data.status = SMP_PAIR_FAIL_UNKNOWN;
- smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
- } else {
- smp_process_ediv(p_cb, &output);
- }
+ Octet16 output = aes_128(dhk, rand, BT_OCTET8_LEN);
+ smp_process_ediv(p_cb, output);
}
/**
@@ -645,25 +525,16 @@
p_cb->div = div;
SMP_TRACE_DEBUG("%s", __func__);
- BT_OCTET16 er;
- BTM_GetDeviceEncRoot(er);
+ const Octet16& er = BTM_GetDeviceEncRoot();
- tSMP_ENC output;
/* LTK = d1(ER, DIV, 0)= e(ER, DIV)*/
- if (!SMP_Encrypt(er, BT_OCTET16_LEN, (uint8_t*)&p_cb->div, sizeof(uint16_t),
- &output)) {
- SMP_TRACE_ERROR("%s failed", __func__);
- tSMP_INT_DATA smp_int_data;
- smp_int_data.status = SMP_PAIR_FAIL_UNKNOWN;
- smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
- } else {
- /* mask the LTK */
- smp_mask_enc_key(p_cb->loc_enc_size, output.param_buf);
- memcpy((void*)p_cb->ltk, output.param_buf, BT_OCTET16_LEN);
+ Octet16 ltk = aes_128(er, (uint8_t*)&p_cb->div, sizeof(uint16_t));
+ /* mask the LTK */
+ smp_mask_enc_key(p_cb->loc_enc_size, <k);
+ p_cb->ltk = ltk;
- /* generate EDIV and rand now */
- btsnd_hcic_ble_rand(Bind(&smp_generate_y, p_cb));
- }
+ /* generate EDIV and rand now */
+ btsnd_hcic_ble_rand(Bind(&smp_generate_y, p_cb));
}
/*******************************************************************************
@@ -710,36 +581,21 @@
}
}
-/*******************************************************************************
- *
- * Function smp_calculate_legacy_short_term_key
- *
- * Description The function calculates legacy STK.
- *
- * Returns false if out of resources, true in other cases.
- *
- ******************************************************************************/
-bool smp_calculate_legacy_short_term_key(tSMP_CB* p_cb, tSMP_ENC* output) {
+/* The function calculates legacy STK */
+Octet16 smp_calculate_legacy_short_term_key(tSMP_CB* p_cb) {
SMP_TRACE_DEBUG("%s", __func__);
- BT_OCTET16 ptext;
- uint8_t* p = ptext;
- memset(p, 0, BT_OCTET16_LEN);
+ Octet16 text{0};
if (p_cb->role == HCI_ROLE_MASTER) {
- memcpy(p, p_cb->rand, BT_OCTET8_LEN);
- memcpy(&p[BT_OCTET8_LEN], p_cb->rrand, BT_OCTET8_LEN);
+ memcpy(text.data(), p_cb->rand.data(), BT_OCTET8_LEN);
+ memcpy(text.data() + BT_OCTET8_LEN, p_cb->rrand.data(), BT_OCTET8_LEN);
} else {
- memcpy(p, p_cb->rrand, BT_OCTET8_LEN);
- memcpy(&p[BT_OCTET8_LEN], p_cb->rand, BT_OCTET8_LEN);
+ memcpy(text.data(), p_cb->rrand.data(), BT_OCTET8_LEN);
+ memcpy(text.data() + BT_OCTET8_LEN, p_cb->rand.data(), BT_OCTET8_LEN);
}
/* generate STK = Etk(rand|rrand)*/
- bool encrypted =
- SMP_Encrypt(p_cb->tk, BT_OCTET16_LEN, ptext, BT_OCTET16_LEN, output);
- if (!encrypted) {
- SMP_TRACE_ERROR("%s failed", __func__);
- }
- return encrypted;
+ return aes_128(p_cb->tk, text);
}
/*******************************************************************************
@@ -835,8 +691,7 @@
SMP_TRACE_DEBUG("%s", __func__);
memcpy(private_key, p_cb->private_key, BT_OCTET32_LEN);
- ECC_PointMult(&public_key, &(curve_p256.G), (uint32_t*)private_key,
- KEY_LENGTH_DWORDS_P256);
+ ECC_PointMult(&public_key, &(curve_p256.G), (uint32_t*)private_key);
memcpy(p_cb->loc_publ_key.x, public_key.x, BT_OCTET32_LEN);
memcpy(p_cb->loc_publ_key.y, public_key.y, BT_OCTET32_LEN);
@@ -872,8 +727,7 @@
memcpy(peer_publ_key.x, p_cb->peer_publ_key.x, BT_OCTET32_LEN);
memcpy(peer_publ_key.y, p_cb->peer_publ_key.y, BT_OCTET32_LEN);
- ECC_PointMult(&new_publ_key, &peer_publ_key, (uint32_t*)private_key,
- KEY_LENGTH_DWORDS_P256);
+ ECC_PointMult(&new_publ_key, &peer_publ_key, (uint32_t*)private_key);
memcpy(p_cb->dhkey, new_publ_key.x, BT_OCTET32_LEN);
@@ -889,15 +743,7 @@
BT_OCTET32_LEN);
}
-/*******************************************************************************
- *
- * Function smp_calculate_local_commitment
- *
- * Description The function calculates and saves local commmitment in CB.
- *
- * Returns void
- *
- ******************************************************************************/
+/** The function calculates and saves local commmitment in CB. */
void smp_calculate_local_commitment(tSMP_CB* p_cb) {
uint8_t random_input;
@@ -910,21 +756,22 @@
SMP_TRACE_WARNING(
"local commitment calc on master is not expected "
"for Just Works/Numeric Comparison models");
- smp_calculate_f4(p_cb->loc_publ_key.x, p_cb->peer_publ_key.x, p_cb->rand,
- 0, p_cb->commitment);
+ p_cb->commitment = crypto_toolbox::f4(
+ p_cb->loc_publ_key.x, p_cb->peer_publ_key.x, p_cb->rand, 0);
break;
case SMP_MODEL_SEC_CONN_PASSKEY_ENT:
case SMP_MODEL_SEC_CONN_PASSKEY_DISP:
random_input =
- smp_calculate_random_input(p_cb->local_random, p_cb->round);
- smp_calculate_f4(p_cb->loc_publ_key.x, p_cb->peer_publ_key.x, p_cb->rand,
- random_input, p_cb->commitment);
+ smp_calculate_random_input(p_cb->local_random.data(), p_cb->round);
+ p_cb->commitment =
+ crypto_toolbox::f4(p_cb->loc_publ_key.x, p_cb->peer_publ_key.x,
+ p_cb->rand, random_input);
break;
case SMP_MODEL_SEC_CONN_OOB:
SMP_TRACE_WARNING(
"local commitment calc is expected for OOB model BEFORE pairing");
- smp_calculate_f4(p_cb->loc_publ_key.x, p_cb->loc_publ_key.x,
- p_cb->local_random, 0, p_cb->commitment);
+ p_cb->commitment = crypto_toolbox::f4(
+ p_cb->loc_publ_key.x, p_cb->loc_publ_key.x, p_cb->local_random, 0);
break;
default:
SMP_TRACE_ERROR("Association Model = %d is not used in LE SC",
@@ -935,21 +782,12 @@
SMP_TRACE_EVENT("local commitment calculation is completed");
}
-/*******************************************************************************
- *
- * Function smp_calculate_peer_commitment
- *
- * Description The function calculates and saves peer commmitment at the
- * provided output buffer.
- *
- * Returns void
- *
- ******************************************************************************/
-void smp_calculate_peer_commitment(tSMP_CB* p_cb, BT_OCTET16 output_buf) {
+/** The function calculates peer commmitment */
+Octet16 smp_calculate_peer_commitment(tSMP_CB* p_cb) {
uint8_t ri;
SMP_TRACE_DEBUG("%s", __func__);
-
+ Octet16 output;
switch (p_cb->selected_association_model) {
case SMP_MODEL_SEC_CONN_JUSTWORKS:
case SMP_MODEL_SEC_CONN_NUM_COMP:
@@ -957,97 +795,27 @@
SMP_TRACE_WARNING(
"peer commitment calc on slave is not expected "
"for Just Works/Numeric Comparison models");
- smp_calculate_f4(p_cb->peer_publ_key.x, p_cb->loc_publ_key.x, p_cb->rrand,
- 0, output_buf);
+ output = crypto_toolbox::f4(p_cb->peer_publ_key.x, p_cb->loc_publ_key.x,
+ p_cb->rrand, 0);
break;
case SMP_MODEL_SEC_CONN_PASSKEY_ENT:
case SMP_MODEL_SEC_CONN_PASSKEY_DISP:
- ri = smp_calculate_random_input(p_cb->peer_random, p_cb->round);
- smp_calculate_f4(p_cb->peer_publ_key.x, p_cb->loc_publ_key.x, p_cb->rrand,
- ri, output_buf);
+ ri = smp_calculate_random_input(p_cb->peer_random.data(), p_cb->round);
+ output = crypto_toolbox::f4(p_cb->peer_publ_key.x, p_cb->loc_publ_key.x,
+ p_cb->rrand, ri);
break;
case SMP_MODEL_SEC_CONN_OOB:
- smp_calculate_f4(p_cb->peer_publ_key.x, p_cb->peer_publ_key.x,
- p_cb->peer_random, 0, output_buf);
+ output = crypto_toolbox::f4(p_cb->peer_publ_key.x, p_cb->peer_publ_key.x,
+ p_cb->peer_random, 0);
break;
default:
SMP_TRACE_ERROR("Association Model = %d is not used in LE SC",
p_cb->selected_association_model);
- return;
+ return output;
}
SMP_TRACE_EVENT("peer commitment calculation is completed");
-}
-
-/*******************************************************************************
- *
- * Function smp_calculate_f4
- *
- * Description The function calculates
- * C = f4(U, V, X, Z) = AES-CMAC (U||V||Z)
- * X
- * where
- * input: U is 256 bit,
- * V is 256 bit,
- * X is 128 bit,
- * Z is 8 bit,
- * output: C is 128 bit.
- *
- * Returns void
- *
- * Note The LSB is the first octet, the MSB is the last octet of
- * the AES-CMAC input/output stream.
- *
- ******************************************************************************/
-void smp_calculate_f4(uint8_t* u, uint8_t* v, uint8_t* x, uint8_t z,
- uint8_t* c) {
- uint8_t msg_len = BT_OCTET32_LEN /* U size */ + BT_OCTET32_LEN /* V size */ +
- 1 /* Z size */;
- uint8_t msg[BT_OCTET32_LEN + BT_OCTET32_LEN + 1];
- uint8_t key[BT_OCTET16_LEN];
- uint8_t cmac[BT_OCTET16_LEN];
- uint8_t* p = NULL;
-#if (SMP_DEBUG == TRUE)
- uint8_t* p_prnt = NULL;
-#endif
-
- SMP_TRACE_DEBUG("%s", __func__);
-
-#if (SMP_DEBUG == TRUE)
- p_prnt = u;
- smp_debug_print_nbyte_little_endian(p_prnt, "U", BT_OCTET32_LEN);
- p_prnt = v;
- smp_debug_print_nbyte_little_endian(p_prnt, "V", BT_OCTET32_LEN);
- p_prnt = x;
- smp_debug_print_nbyte_little_endian(p_prnt, "X", BT_OCTET16_LEN);
- p_prnt = &z;
- smp_debug_print_nbyte_little_endian(p_prnt, "Z", 1);
-#endif
-
- p = msg;
- UINT8_TO_STREAM(p, z);
- ARRAY_TO_STREAM(p, v, BT_OCTET32_LEN);
- ARRAY_TO_STREAM(p, u, BT_OCTET32_LEN);
-#if (SMP_DEBUG == TRUE)
- p_prnt = msg;
- smp_debug_print_nbyte_little_endian(p_prnt, "M", msg_len);
-#endif
-
- p = key;
- ARRAY_TO_STREAM(p, x, BT_OCTET16_LEN);
-#if (SMP_DEBUG == TRUE)
- p_prnt = key;
- smp_debug_print_nbyte_little_endian(p_prnt, "K", BT_OCTET16_LEN);
-#endif
-
- aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac);
-#if (SMP_DEBUG == TRUE)
- p_prnt = cmac;
- smp_debug_print_nbyte_little_endian(p_prnt, "AES_CMAC", BT_OCTET16_LEN);
-#endif
-
- p = c;
- ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN);
+ return output;
}
/*******************************************************************************
@@ -1065,10 +833,10 @@
SMP_TRACE_DEBUG("%s", __func__);
if (p_cb->role == HCI_ROLE_MASTER) {
- p_cb->number_to_display = smp_calculate_g2(
+ p_cb->number_to_display = crypto_toolbox::g2(
p_cb->loc_publ_key.x, p_cb->peer_publ_key.x, p_cb->rand, p_cb->rrand);
} else {
- p_cb->number_to_display = smp_calculate_g2(
+ p_cb->number_to_display = crypto_toolbox::g2(
p_cb->peer_publ_key.x, p_cb->loc_publ_key.x, p_cb->rrand, p_cb->rand);
}
@@ -1089,398 +857,6 @@
return;
}
-/*******************************************************************************
- *
- * Function smp_calculate_g2
- *
- * Description The function calculates
- * g2(U, V, X, Y) = AES-CMAC (U||V||Y) mod 2**32 mod 10**6
- * X
- * and
- * Vres = g2(U, V, X, Y) mod 10**6
- * where
- * input: U is 256 bit,
- * V is 256 bit,
- * X is 128 bit,
- * Y is 128 bit,
- *
- * Returns Vres.
- * Expected value has to be in the range [0 - 999999] i.e.
- * [0 - 0xF423F].
- * Vres = 1000000 means that the calculation fails.
- *
- * Note The LSB is the first octet, the MSB is the last octet of
- * the AES-CMAC input/output stream.
- *
- ******************************************************************************/
-uint32_t smp_calculate_g2(uint8_t* u, uint8_t* v, uint8_t* x, uint8_t* y) {
- uint8_t msg_len = BT_OCTET32_LEN /* U size */ + BT_OCTET32_LEN /* V size */
- + BT_OCTET16_LEN /* Y size */;
- uint8_t msg[BT_OCTET32_LEN + BT_OCTET32_LEN + BT_OCTET16_LEN];
- uint8_t key[BT_OCTET16_LEN];
- uint8_t cmac[BT_OCTET16_LEN];
- uint8_t* p = NULL;
- uint32_t vres;
-#if (SMP_DEBUG == TRUE)
- uint8_t* p_prnt = NULL;
-#endif
-
- SMP_TRACE_DEBUG("%s", __func__);
-
- p = msg;
- ARRAY_TO_STREAM(p, y, BT_OCTET16_LEN);
- ARRAY_TO_STREAM(p, v, BT_OCTET32_LEN);
- ARRAY_TO_STREAM(p, u, BT_OCTET32_LEN);
-#if (SMP_DEBUG == TRUE)
- p_prnt = u;
- smp_debug_print_nbyte_little_endian(p_prnt, "U", BT_OCTET32_LEN);
- p_prnt = v;
- smp_debug_print_nbyte_little_endian(p_prnt, "V", BT_OCTET32_LEN);
- p_prnt = x;
- smp_debug_print_nbyte_little_endian(p_prnt, "X", BT_OCTET16_LEN);
- p_prnt = y;
- smp_debug_print_nbyte_little_endian(p_prnt, "Y", BT_OCTET16_LEN);
-#endif
-
- p = key;
- ARRAY_TO_STREAM(p, x, BT_OCTET16_LEN);
-#if (SMP_DEBUG == TRUE)
- p_prnt = key;
- smp_debug_print_nbyte_little_endian(p_prnt, "K", BT_OCTET16_LEN);
-#endif
-
- if (!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac)) {
- SMP_TRACE_ERROR("%s failed", __func__);
- return (BTM_MAX_PASSKEY_VAL + 1);
- }
-
-#if (SMP_DEBUG == TRUE)
- p_prnt = cmac;
- smp_debug_print_nbyte_little_endian(p_prnt, "AES-CMAC", BT_OCTET16_LEN);
-#endif
-
- /* vres = cmac mod 2**32 mod 10**6 */
- p = &cmac[0];
- STREAM_TO_UINT32(vres, p);
-#if (SMP_DEBUG == TRUE)
- p_prnt = (uint8_t*)&vres;
- smp_debug_print_nbyte_little_endian(p_prnt, "cmac mod 2**32", 4);
-#endif
-
- while (vres > BTM_MAX_PASSKEY_VAL) vres -= (BTM_MAX_PASSKEY_VAL + 1);
-#if (SMP_DEBUG == TRUE)
- p_prnt = (uint8_t*)&vres;
- smp_debug_print_nbyte_little_endian(p_prnt, "cmac mod 2**32 mod 10**6", 4);
-#endif
-
- SMP_TRACE_ERROR("Value for numeric comparison = %d", vres);
- return vres;
-}
-
-/*******************************************************************************
- *
- * Function smp_calculate_f5
- *
- * Description The function provides two AES-CMAC that are supposed to be
- * used as
- * - MacKey (used in pairing DHKey check calculation);
- * - LTK (used to ecrypt the link after completion of Phase 2
- * and on reconnection, to derive BR/EDR LK).
- * The function inputs are W, N1, N2, A1, A2.
- * F5 rules:
- * - the value used as key in MacKey/LTK (T) is calculated
- * (function smp_calculate_f5_key(...));
- * The formula is:
- * T = AES-CMAC (W)
- * salt
- * where salt is internal parameter of
- * smp_calculate_f5_key(...).
- * - MacKey and LTK are calculated as AES-MAC values received
- * with the key T calculated in the previous step and the
- * plaintext message built from the external parameters N1,
- * N2, A1, A2 and the internal parameters counter, keyID,
- * length.
- * The function smp_calculate_f5_mackey_or_long_term_key(...)
- * is used in the calculations.
- * The same formula is used in calculation of MacKey and LTK
- * and the same parameter values except the value of the
- * internal parameter counter:
- * - in MacKey calculations the value is 0;
- * - in LTK calculations the value is 1.
- * MacKey =
- * AES-CMAC (Counter=0||keyID||N1||N2||A1||A2||Length=256)
- * T
- * LTK =
- * AES-CMAC (Counter=1||keyID||N1||N2||A1||A2||Length=256)
- * T
- * The parameters are
- * input:
- * W is 256 bits,
- * N1 is 128 bits,
- * N2 is 128 bits,
- * A1 is 56 bit,
- * A2 is 56 bit.
- * internal:
- * Counter is 8 bits, its value is 0 for MacKey,
- * 1 for LTK;
- * KeyId is 32 bits, its value is
- * 0x62746c65 (MSB~LSB);
- * Length is 16 bits, its value is 0x0100
- * (MSB~LSB).
- * output:
- * MacKey is 128 bits;
- * LTK is 128 bits
- *
- * Returns false if out of resources, true in other cases.
- *
- * Note The LSB is the first octet, the MSB is the last octet of
- * the AES-CMAC input/output stream.
- *
- ******************************************************************************/
-bool smp_calculate_f5(uint8_t* w, uint8_t* n1, uint8_t* n2, uint8_t* a1,
- uint8_t* a2, uint8_t* mac_key, uint8_t* ltk) {
- BT_OCTET16 t; /* AES-CMAC output in smp_calculate_f5_key(...), key in */
- /* smp_calculate_f5_mackey_or_long_term_key(...) */
-#if (SMP_DEBUG == TRUE)
- uint8_t* p_prnt = NULL;
-#endif
- /* internal parameters: */
-
- /*
- counter is 0 for MacKey,
- is 1 for LTK
- */
- uint8_t counter_mac_key[1] = {0};
- uint8_t counter_ltk[1] = {1};
- /*
- keyID 62746c65
- */
- uint8_t key_id[4] = {0x65, 0x6c, 0x74, 0x62};
- /*
- length 0100
- */
- uint8_t length[2] = {0x00, 0x01};
-
- SMP_TRACE_DEBUG("%s", __func__);
-#if (SMP_DEBUG == TRUE)
- p_prnt = w;
- smp_debug_print_nbyte_little_endian(p_prnt, "W", BT_OCTET32_LEN);
- p_prnt = n1;
- smp_debug_print_nbyte_little_endian(p_prnt, "N1", BT_OCTET16_LEN);
- p_prnt = n2;
- smp_debug_print_nbyte_little_endian(p_prnt, "N2", BT_OCTET16_LEN);
- p_prnt = a1;
- smp_debug_print_nbyte_little_endian(p_prnt, "A1", 7);
- p_prnt = a2;
- smp_debug_print_nbyte_little_endian(p_prnt, "A2", 7);
-#endif
-
- if (!smp_calculate_f5_key(w, t)) {
- SMP_TRACE_ERROR("%s failed to calc T", __func__);
- return false;
- }
-#if (SMP_DEBUG == TRUE)
- p_prnt = t;
- smp_debug_print_nbyte_little_endian(p_prnt, "T", BT_OCTET16_LEN);
-#endif
-
- if (!smp_calculate_f5_mackey_or_long_term_key(t, counter_mac_key, key_id, n1,
- n2, a1, a2, length, mac_key)) {
- SMP_TRACE_ERROR("%s failed to calc MacKey", __func__);
- return false;
- }
-#if (SMP_DEBUG == TRUE)
- p_prnt = mac_key;
- smp_debug_print_nbyte_little_endian(p_prnt, "MacKey", BT_OCTET16_LEN);
-#endif
-
- if (!smp_calculate_f5_mackey_or_long_term_key(t, counter_ltk, key_id, n1, n2,
- a1, a2, length, ltk)) {
- SMP_TRACE_ERROR("%s failed to calc LTK", __func__);
- return false;
- }
-#if (SMP_DEBUG == TRUE)
- p_prnt = ltk;
- smp_debug_print_nbyte_little_endian(p_prnt, "LTK", BT_OCTET16_LEN);
-#endif
-
- return true;
-}
-
-/*******************************************************************************
- *
- * Function smp_calculate_f5_mackey_or_long_term_key
- *
- * Description The function calculates the value of MacKey or LTK by the
- * rules defined for f5 function.
- * At the moment exactly the same formula is used to calculate
- * LTK and MacKey.
- * The difference is the value of input parameter Counter:
- * - in MacKey calculations the value is 0;
- * - in LTK calculations the value is 1.
- * The formula:
- * mac = AES-CMAC (Counter||keyID||N1||N2||A1||A2||Length)
- * T
- * where
- * input: T is 256 bits;
- * Counter is 8 bits, its value is 0 for MacKey,
- * 1 for LTK;
- * keyID is 32 bits, its value is 0x62746c65;
- * N1 is 128 bits;
- * N2 is 128 bits;
- * A1 is 56 bits;
- * A2 is 56 bits;
- * Length is 16 bits, its value is 0x0100
- * output: LTK is 128 bit.
- *
- * Returns false if out of resources, true in other cases.
- *
- * Note The LSB is the first octet, the MSB is the last octet of
- * the AES-CMAC input/output stream.
- *
- ******************************************************************************/
-bool smp_calculate_f5_mackey_or_long_term_key(uint8_t* t, uint8_t* counter,
- uint8_t* key_id, uint8_t* n1,
- uint8_t* n2, uint8_t* a1,
- uint8_t* a2, uint8_t* length,
- uint8_t* mac) {
- uint8_t* p = NULL;
- uint8_t cmac[BT_OCTET16_LEN];
- uint8_t key[BT_OCTET16_LEN];
- uint8_t msg_len = 1 /* Counter size */ + 4 /* keyID size */ +
- BT_OCTET16_LEN /* N1 size */ +
- BT_OCTET16_LEN /* N2 size */ + 7 /* A1 size*/ +
- 7 /* A2 size*/ + 2 /* Length size */;
- uint8_t msg[1 + 4 + BT_OCTET16_LEN + BT_OCTET16_LEN + 7 + 7 + 2];
- bool ret = true;
-#if (SMP_DEBUG == TRUE)
- uint8_t* p_prnt = NULL;
-#endif
-
- SMP_TRACE_DEBUG("%s", __func__);
-#if (SMP_DEBUG == TRUE)
- p_prnt = t;
- smp_debug_print_nbyte_little_endian(p_prnt, "T", BT_OCTET16_LEN);
- p_prnt = counter;
- smp_debug_print_nbyte_little_endian(p_prnt, "Counter", 1);
- p_prnt = key_id;
- smp_debug_print_nbyte_little_endian(p_prnt, "KeyID", 4);
- p_prnt = n1;
- smp_debug_print_nbyte_little_endian(p_prnt, "N1", BT_OCTET16_LEN);
- p_prnt = n2;
- smp_debug_print_nbyte_little_endian(p_prnt, "N2", BT_OCTET16_LEN);
- p_prnt = a1;
- smp_debug_print_nbyte_little_endian(p_prnt, "A1", 7);
- p_prnt = a2;
- smp_debug_print_nbyte_little_endian(p_prnt, "A2", 7);
- p_prnt = length;
- smp_debug_print_nbyte_little_endian(p_prnt, "Length", 2);
-#endif
-
- p = key;
- ARRAY_TO_STREAM(p, t, BT_OCTET16_LEN);
-#if (SMP_DEBUG == TRUE)
- p_prnt = key;
- smp_debug_print_nbyte_little_endian(p_prnt, "K", BT_OCTET16_LEN);
-#endif
- p = msg;
- ARRAY_TO_STREAM(p, length, 2);
- ARRAY_TO_STREAM(p, a2, 7);
- ARRAY_TO_STREAM(p, a1, 7);
- ARRAY_TO_STREAM(p, n2, BT_OCTET16_LEN);
- ARRAY_TO_STREAM(p, n1, BT_OCTET16_LEN);
- ARRAY_TO_STREAM(p, key_id, 4);
- ARRAY_TO_STREAM(p, counter, 1);
-#if (SMP_DEBUG == TRUE)
- p_prnt = msg;
- smp_debug_print_nbyte_little_endian(p_prnt, "M", msg_len);
-#endif
-
- if (!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac)) {
- SMP_TRACE_ERROR("%s failed", __func__);
- ret = false;
- }
-
-#if (SMP_DEBUG == TRUE)
- p_prnt = cmac;
- smp_debug_print_nbyte_little_endian(p_prnt, "AES-CMAC", BT_OCTET16_LEN);
-#endif
-
- p = mac;
- ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN);
- return ret;
-}
-
-/*******************************************************************************
- *
- * Function smp_calculate_f5_key
- *
- * Description The function calculates key T used in calculation of
- * MacKey and LTK (f5 output is defined as MacKey || LTK).
- * T = AES-CMAC (W)
- * salt
- * where
- * Internal: salt is 128 bit.
- * input: W is 256 bit.
- * Output: T is 128 bit.
- *
- * Returns false if out of resources, true in other cases.
- *
- * Note The LSB is the first octet, the MSB is the last octet of
- * the AES-CMAC input/output stream.
- *
- ******************************************************************************/
-bool smp_calculate_f5_key(uint8_t* w, uint8_t* t) {
- uint8_t* p = NULL;
- /* Please see 2.2.7 LE Secure Connections Key Generation Function f5 */
- /*
- salt: 6C88 8391 AAF5 A538 6037 0BDB 5A60 83BE
- */
- BT_OCTET16 salt = {0xBE, 0x83, 0x60, 0x5A, 0xDB, 0x0B, 0x37, 0x60,
- 0x38, 0xA5, 0xF5, 0xAA, 0x91, 0x83, 0x88, 0x6C};
-#if (SMP_DEBUG == TRUE)
- uint8_t* p_prnt = NULL;
-#endif
-
- SMP_TRACE_DEBUG("%s", __func__);
-#if (SMP_DEBUG == TRUE)
- p_prnt = salt;
- smp_debug_print_nbyte_little_endian(p_prnt, "salt", BT_OCTET16_LEN);
- p_prnt = w;
- smp_debug_print_nbyte_little_endian(p_prnt, "W", BT_OCTET32_LEN);
-#endif
-
- BT_OCTET16 key;
- BT_OCTET32 msg;
-
- p = key;
- ARRAY_TO_STREAM(p, salt, BT_OCTET16_LEN);
- p = msg;
- ARRAY_TO_STREAM(p, w, BT_OCTET32_LEN);
-#if (SMP_DEBUG == TRUE)
- p_prnt = key;
- smp_debug_print_nbyte_little_endian(p_prnt, "K", BT_OCTET16_LEN);
- p_prnt = msg;
- smp_debug_print_nbyte_little_endian(p_prnt, "M", BT_OCTET32_LEN);
-#endif
-
- BT_OCTET16 cmac;
- bool ret = true;
- if (!aes_cipher_msg_auth_code(key, msg, BT_OCTET32_LEN, BT_OCTET16_LEN,
- cmac)) {
- SMP_TRACE_ERROR("%s failed", __func__);
- ret = false;
- }
-
-#if (SMP_DEBUG == TRUE)
- p_prnt = cmac;
- smp_debug_print_nbyte_little_endian(p_prnt, "AES-CMAC", BT_OCTET16_LEN);
-#endif
-
- p = t;
- ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN);
- return ret;
-}
/*******************************************************************************
*
@@ -1507,8 +883,8 @@
smp_collect_local_ble_address(a, p_cb);
smp_collect_peer_ble_address(b, p_cb);
- smp_calculate_f6(p_cb->mac_key, p_cb->rand, p_cb->rrand, p_cb->peer_random,
- iocap, a, b, p_cb->dhkey_check);
+ p_cb->dhkey_check = crypto_toolbox::f6(p_cb->mac_key, p_cb->rand, p_cb->rrand,
+ p_cb->peer_random, iocap, a, b);
SMP_TRACE_EVENT("local DHKey check calculation is completed");
}
@@ -1524,8 +900,6 @@
******************************************************************************/
void smp_calculate_peer_dhkey_check(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
uint8_t iocap[3], a[7], b[7];
- BT_OCTET16 param_buf;
- bool ret;
tSMP_KEY key;
SMP_TRACE_DEBUG("%s", __func__);
@@ -1534,119 +908,21 @@
smp_collect_local_ble_address(a, p_cb);
smp_collect_peer_ble_address(b, p_cb);
- ret = smp_calculate_f6(p_cb->mac_key, p_cb->rrand, p_cb->rand,
- p_cb->local_random, iocap, b, a, param_buf);
+ Octet16 param_buf = crypto_toolbox::f6(p_cb->mac_key, p_cb->rrand, p_cb->rand,
+ p_cb->local_random, iocap, b, a);
- if (ret) {
- SMP_TRACE_EVENT("peer DHKey check calculation is completed");
+ SMP_TRACE_EVENT("peer DHKey check calculation is completed");
#if (SMP_DEBUG == TRUE)
- smp_debug_print_nbyte_little_endian(param_buf, "peer DHKey check",
- BT_OCTET16_LEN);
+ smp_debug_print_nbyte_little_endian(param_buf, "peer DHKey check",
+ OCTET16_LEN);
#endif
- key.key_type = SMP_KEY_TYPE_PEER_DHK_CHCK;
- key.p_data = param_buf;
- tSMP_INT_DATA smp_int_data;
- smp_int_data.key = key;
- smp_sm_event(p_cb, SMP_SC_KEY_READY_EVT, &smp_int_data);
- } else {
- SMP_TRACE_EVENT("peer DHKey check calculation failed");
- tSMP_INT_DATA smp_int_data;
- smp_int_data.status = SMP_PAIR_FAIL_UNKNOWN;
- smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
- }
+ key.key_type = SMP_KEY_TYPE_PEER_DHK_CHCK;
+ key.p_data = param_buf.data();
+ tSMP_INT_DATA smp_int_data;
+ smp_int_data.key = key;
+ smp_sm_event(p_cb, SMP_SC_KEY_READY_EVT, &smp_int_data);
}
-/*******************************************************************************
- *
- * Function smp_calculate_f6
- *
- * Description The function calculates
- * C = f6(W, N1, N2, R, IOcap, A1, A2) =
- * AES-CMAC (N1||N2||R||IOcap||A1||A2)
- * W
- * where
- * input: W is 128 bit,
- * N1 is 128 bit,
- * N2 is 128 bit,
- * R is 128 bit,
- * IOcap is 24 bit,
- * A1 is 56 bit,
- * A2 is 56 bit,
- * output: C is 128 bit.
- *
- * Returns false if out of resources, true in other cases.
- *
- * Note The LSB is the first octet, the MSB is the last octet of
- * the AES-CMAC input/output stream.
- *
- ******************************************************************************/
-bool smp_calculate_f6(uint8_t* w, uint8_t* n1, uint8_t* n2, uint8_t* r,
- uint8_t* iocap, uint8_t* a1, uint8_t* a2, uint8_t* c) {
- uint8_t* p = NULL;
- uint8_t msg_len = BT_OCTET16_LEN /* N1 size */ +
- BT_OCTET16_LEN /* N2 size */ + BT_OCTET16_LEN /* R size */ +
- 3 /* IOcap size */ + 7 /* A1 size*/
- + 7 /* A2 size*/;
- uint8_t msg[BT_OCTET16_LEN + BT_OCTET16_LEN + BT_OCTET16_LEN + 3 + 7 + 7];
-#if (SMP_DEBUG == TRUE)
- uint8_t* p_print = NULL;
-#endif
-
- SMP_TRACE_DEBUG("%s", __func__);
-#if (SMP_DEBUG == TRUE)
- p_print = w;
- smp_debug_print_nbyte_little_endian(p_print, "W", BT_OCTET16_LEN);
- p_print = n1;
- smp_debug_print_nbyte_little_endian(p_print, "N1", BT_OCTET16_LEN);
- p_print = n2;
- smp_debug_print_nbyte_little_endian(p_print, "N2", BT_OCTET16_LEN);
- p_print = r;
- smp_debug_print_nbyte_little_endian(p_print, "R", BT_OCTET16_LEN);
- p_print = iocap;
- smp_debug_print_nbyte_little_endian(p_print, "IOcap", 3);
- p_print = a1;
- smp_debug_print_nbyte_little_endian(p_print, "A1", 7);
- p_print = a2;
- smp_debug_print_nbyte_little_endian(p_print, "A2", 7);
-#endif
-
- uint8_t cmac[BT_OCTET16_LEN];
- uint8_t key[BT_OCTET16_LEN];
-
- p = key;
- ARRAY_TO_STREAM(p, w, BT_OCTET16_LEN);
-#if (SMP_DEBUG == TRUE)
- p_print = key;
- smp_debug_print_nbyte_little_endian(p_print, "K", BT_OCTET16_LEN);
-#endif
-
- p = msg;
- ARRAY_TO_STREAM(p, a2, 7);
- ARRAY_TO_STREAM(p, a1, 7);
- ARRAY_TO_STREAM(p, iocap, 3);
- ARRAY_TO_STREAM(p, r, BT_OCTET16_LEN);
- ARRAY_TO_STREAM(p, n2, BT_OCTET16_LEN);
- ARRAY_TO_STREAM(p, n1, BT_OCTET16_LEN);
-#if (SMP_DEBUG == TRUE)
- p_print = msg;
- smp_debug_print_nbyte_little_endian(p_print, "M", msg_len);
-#endif
-
- bool ret = true;
- if (!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac)) {
- SMP_TRACE_ERROR("%s failed", __func__);
- ret = false;
- }
-
-#if (SMP_DEBUG == TRUE)
- p_print = cmac;
- smp_debug_print_nbyte_little_endian(p_print, "AES-CMAC", BT_OCTET16_LEN);
-#endif
-
- p = c;
- ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN);
- return ret;
-}
/*******************************************************************************
*
@@ -1662,8 +938,6 @@
tBTM_SEC_DEV_REC* p_dev_rec;
RawAddress bda_for_lk;
tBLE_ADDR_TYPE conn_addr_type;
- BT_OCTET16 salt = {0x31, 0x70, 0x6D, 0x74, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
SMP_TRACE_DEBUG("%s", __func__);
@@ -1686,79 +960,44 @@
return false;
}
- BT_OCTET16 intermediate_link_key;
- bool ret = true;
+ Octet16 link_key =
+ crypto_toolbox::ltk_to_link_key(p_cb->ltk, p_cb->key_derivation_h7_used);
- if (p_cb->key_derivation_h7_used)
- ret = smp_calculate_h7((uint8_t*)salt, p_cb->ltk, intermediate_link_key);
- else
- ret = smp_calculate_h6(p_cb->ltk, (uint8_t*)"1pmt" /* reversed "tmp1" */,
- intermediate_link_key);
- if (!ret) {
- SMP_TRACE_ERROR("%s failed to derive intermediate_link_key", __func__);
- return ret;
- }
-
- BT_OCTET16 link_key;
- ret = smp_calculate_h6(intermediate_link_key,
- (uint8_t*)"rbel" /* reversed "lebr" */, link_key);
- if (!ret) {
- SMP_TRACE_ERROR("%s failed", __func__);
- } else {
- uint8_t link_key_type;
- if (btm_cb.security_mode == BTM_SEC_MODE_SC) {
- /* Secure Connections Only Mode */
+ uint8_t link_key_type;
+ if (btm_cb.security_mode == BTM_SEC_MODE_SC) {
+ /* Secure Connections Only Mode */
+ link_key_type = BTM_LKEY_TYPE_AUTH_COMB_P_256;
+ } else if (controller_get_interface()->supports_secure_connections()) {
+ /* both transports are SC capable */
+ if (p_cb->sec_level == SMP_SEC_AUTHENTICATED)
link_key_type = BTM_LKEY_TYPE_AUTH_COMB_P_256;
- } else if (controller_get_interface()->supports_secure_connections()) {
- /* both transports are SC capable */
- if (p_cb->sec_level == SMP_SEC_AUTHENTICATED)
- link_key_type = BTM_LKEY_TYPE_AUTH_COMB_P_256;
- else
- link_key_type = BTM_LKEY_TYPE_UNAUTH_COMB_P_256;
- } else if (btm_cb.security_mode == BTM_SEC_MODE_SP) {
- /* BR/EDR transport is SSP capable */
- if (p_cb->sec_level == SMP_SEC_AUTHENTICATED)
- link_key_type = BTM_LKEY_TYPE_AUTH_COMB;
- else
- link_key_type = BTM_LKEY_TYPE_UNAUTH_COMB;
- } else {
- SMP_TRACE_ERROR(
- "%s failed to update link_key. Sec Mode = %d, sm4 = 0x%02x", __func__,
- btm_cb.security_mode, p_dev_rec->sm4);
- return false;
- }
-
- link_key_type += BTM_LTK_DERIVED_LKEY_OFFSET;
-
- uint8_t* p;
- BT_OCTET16 notif_link_key;
- p = notif_link_key;
- ARRAY16_TO_STREAM(p, link_key);
-
- btm_sec_link_key_notification(bda_for_lk, notif_link_key, link_key_type);
-
- SMP_TRACE_EVENT("%s is completed", __func__);
+ else
+ link_key_type = BTM_LKEY_TYPE_UNAUTH_COMB_P_256;
+ } else if (btm_cb.security_mode == BTM_SEC_MODE_SP) {
+ /* BR/EDR transport is SSP capable */
+ if (p_cb->sec_level == SMP_SEC_AUTHENTICATED)
+ link_key_type = BTM_LKEY_TYPE_AUTH_COMB;
+ else
+ link_key_type = BTM_LKEY_TYPE_UNAUTH_COMB;
+ } else {
+ SMP_TRACE_ERROR("%s failed to update link_key. Sec Mode = %d, sm4 = 0x%02x",
+ __func__, btm_cb.security_mode, p_dev_rec->sm4);
+ return false;
}
- return ret;
+ link_key_type += BTM_LTK_DERIVED_LKEY_OFFSET;
+
+ Octet16 notif_link_key = link_key;
+ btm_sec_link_key_notification(bda_for_lk, notif_link_key, link_key_type);
+
+ SMP_TRACE_EVENT("%s is completed", __func__);
+
+ return true;
}
-/*******************************************************************************
- *
- * Function smp_calculate_long_term_key_from_link_key
- *
- * Description The function calculates and saves SC LTK derived from BR/EDR
- * link key.
- *
- * Returns false if out of resources, true in other cases.
- *
- ******************************************************************************/
+/** The function calculates and saves SC LTK derived from BR/EDR link key. */
bool smp_calculate_long_term_key_from_link_key(tSMP_CB* p_cb) {
- bool ret = true;
tBTM_SEC_DEV_REC* p_dev_rec;
- uint8_t rev_link_key[16];
- BT_OCTET16 salt = {0x32, 0x70, 0x6D, 0x74, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
SMP_TRACE_DEBUG("%s", __func__);
@@ -1782,153 +1021,17 @@
return false;
}
- uint8_t* p1;
- uint8_t* p2;
- p1 = rev_link_key;
- p2 = p_dev_rec->link_key;
- REVERSE_ARRAY_TO_STREAM(p1, p2, 16);
+ Octet16 rev_link_key;
+ std::reverse_copy(p_dev_rec->link_key.begin(), p_dev_rec->link_key.end(),
+ rev_link_key.begin());
+ p_cb->ltk = crypto_toolbox::link_key_to_ltk(rev_link_key,
+ p_cb->key_derivation_h7_used);
- BT_OCTET16 intermediate_long_term_key;
- if (p_cb->key_derivation_h7_used) {
- ret = smp_calculate_h7((uint8_t*)salt, rev_link_key,
- intermediate_long_term_key);
- } else {
- /* "tmp2" obtained from the spec */
- ret = smp_calculate_h6(rev_link_key, (uint8_t*)"2pmt" /* reversed "tmp2" */,
- intermediate_long_term_key);
- }
-
- if (!ret) {
- SMP_TRACE_ERROR("%s failed to derive intermediate_long_term_key", __func__);
- return ret;
- }
-
- /* "brle" obtained from the spec */
- ret = smp_calculate_h6(intermediate_long_term_key,
- (uint8_t*)"elrb" /* reversed "brle" */, p_cb->ltk);
-
- if (!ret) {
- SMP_TRACE_ERROR("%s failed", __func__);
- } else {
- p_cb->sec_level = (br_link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256)
- ? SMP_SEC_AUTHENTICATED
- : SMP_SEC_UNAUTHENTICATE;
- SMP_TRACE_EVENT("%s is completed", __func__);
- }
-
- return ret;
-}
-
-/*******************************************************************************
- *
- * Function smp_calculate_h6
- *
- * Description The function calculates
- * C = h6(W, KeyID) = AES-CMAC (KeyID)
- * W
- * where
- * input: W is 128 bit,
- * KeyId is 32 bit,
- * output: C is 128 bit.
- *
- * Returns false if out of resources, true in other cases.
- *
- * Note The LSB is the first octet, the MSB is the last octet of
- * the AES-CMAC input/output stream.
- *
- ******************************************************************************/
-bool smp_calculate_h6(uint8_t* w, uint8_t* keyid, uint8_t* c) {
-#if (SMP_DEBUG == TRUE)
- uint8_t* p_print = NULL;
-#endif
-
- SMP_TRACE_DEBUG("%s", __func__);
-#if (SMP_DEBUG == TRUE)
- p_print = w;
- smp_debug_print_nbyte_little_endian(p_print, "W", BT_OCTET16_LEN);
- p_print = keyid;
- smp_debug_print_nbyte_little_endian(p_print, "keyID", 4);
-#endif
-
- uint8_t* p = NULL;
- uint8_t key[BT_OCTET16_LEN];
-
- p = key;
- ARRAY_TO_STREAM(p, w, BT_OCTET16_LEN);
-
-#if (SMP_DEBUG == TRUE)
- p_print = key;
- smp_debug_print_nbyte_little_endian(p_print, "K", BT_OCTET16_LEN);
-#endif
-
- uint8_t msg_len = 4 /* KeyID size */;
- uint8_t msg[4];
-
- p = msg;
- ARRAY_TO_STREAM(p, keyid, 4);
-
-#if (SMP_DEBUG == TRUE)
- p_print = msg;
- smp_debug_print_nbyte_little_endian(p_print, "M", msg_len);
-#endif
-
- bool ret = true;
- uint8_t cmac[BT_OCTET16_LEN];
- if (!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac)) {
- SMP_TRACE_ERROR("%s failed", __func__);
- ret = false;
- }
-
-#if (SMP_DEBUG == TRUE)
- p_print = cmac;
- smp_debug_print_nbyte_little_endian(p_print, "AES-CMAC", BT_OCTET16_LEN);
-#endif
-
- p = c;
- ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN);
- return ret;
-}
-
-/*******************************************************************************
-**
-** Function smp_calculate_h7
-**
-** Description The function calculates
-** C = h7(SALT, W) = AES-CMAC (W)
-** SALT
-** where
-** input: W is 128 bit,
-** SALT is 128 bit,
-** output: C is 128 bit.
-**
-** Returns FALSE if out of resources, TRUE in other cases.
-**
-** Note The LSB is the first octet, the MSB is the last octet of
-** the AES-CMAC input/output stream.
-**
-*******************************************************************************/
-bool smp_calculate_h7(uint8_t* salt, uint8_t* w, uint8_t* c) {
- SMP_TRACE_DEBUG("%s", __FUNCTION__);
-
- uint8_t key[BT_OCTET16_LEN];
- uint8_t* p = key;
- ARRAY_TO_STREAM(p, salt, BT_OCTET16_LEN);
-
- uint8_t msg_len = BT_OCTET16_LEN /* msg size */;
- uint8_t msg[BT_OCTET16_LEN];
- p = msg;
- ARRAY_TO_STREAM(p, w, BT_OCTET16_LEN);
-
- bool ret = true;
- uint8_t cmac[BT_OCTET16_LEN];
- if (!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac)) {
- SMP_TRACE_ERROR("%s failed", __FUNCTION__);
- ret = false;
- }
-
- p = c;
- ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN);
- return ret;
+ p_cb->sec_level = (br_link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256)
+ ? SMP_SEC_AUTHENTICATED
+ : SMP_SEC_UNAUTHENTICATE;
+ SMP_TRACE_EVENT("%s is completed", __func__);
+ return true;
}
/**
@@ -1938,10 +1041,10 @@
SMP_TRACE_DEBUG("%s", __func__);
btsnd_hcic_ble_rand(Bind(
[](tSMP_CB* p_cb, BT_OCTET8 rand) {
- memcpy((void*)p_cb->rand, rand, BT_OCTET8_LEN);
+ memcpy(p_cb->rand.data(), rand, BT_OCTET8_LEN);
btsnd_hcic_ble_rand(Bind(
[](tSMP_CB* p_cb, BT_OCTET8 rand) {
- memcpy((void*)&p_cb->rand[8], rand, BT_OCTET8_LEN);
+ memcpy(p_cb->rand.data() + 8, rand, BT_OCTET8_LEN);
SMP_TRACE_DEBUG("%s round %d", __func__, p_cb->round);
/* notifies SM that it has new nonce. */
smp_sm_event(p_cb, SMP_HAVE_LOC_NONCE_EVT, NULL);
diff --git a/stack/smp/smp_l2c.cc b/stack/smp/smp_l2c.cc
index 1e0cb71..b6881e6 100644
--- a/stack/smp/smp_l2c.cc
+++ b/stack/smp/smp_l2c.cc
@@ -26,6 +26,7 @@
#include <string.h>
#include "btm_ble_api.h"
+#include "common/metrics.h"
#include "l2c_api.h"
#include "smp_int.h"
@@ -172,6 +173,9 @@
alarm_set_on_mloop(p_cb->smp_rsp_timer_ent, SMP_WAIT_FOR_RSP_TIMEOUT_MS,
smp_rsp_timeout, NULL);
+ smp_log_metrics(p_cb->pairing_bda, false /* incoming */,
+ p_buf->data + p_buf->offset, p_buf->len);
+
if (cmd == SMP_OPCODE_CONFIRM) {
SMP_TRACE_DEBUG(
"in %s cmd = 0x%02x, peer_auth_req = 0x%02x,"
@@ -310,6 +314,9 @@
alarm_set_on_mloop(p_cb->smp_rsp_timer_ent, SMP_WAIT_FOR_RSP_TIMEOUT_MS,
smp_rsp_timeout, NULL);
+ smp_log_metrics(p_cb->pairing_bda, false /* incoming */,
+ p_buf->data + p_buf->offset, p_buf->len);
+
p_cb->rcvd_cmd_code = cmd;
p_cb->rcvd_cmd_len = (uint8_t)p_buf->len;
tSMP_INT_DATA smp_int_data;
diff --git a/stack/smp/smp_main.cc b/stack/smp/smp_main.cc
index 9c4334a..89ecb4f 100644
--- a/stack/smp/smp_main.cc
+++ b/stack/smp/smp_main.cc
@@ -18,7 +18,7 @@
#include "bt_target.h"
-#include <cutils/log.h>
+#include <log/log.h>
#include <string.h>
#include "smp_int.h"
@@ -155,7 +155,6 @@
SMP_SET_LOCAL_OOB_KEYS,
SMP_SET_LOCAL_OOB_RAND_COMMITMENT,
SMP_IDLE_TERMINATE,
- SMP_FAST_CONN_PARAM,
SMP_SM_NO_ACTION
};
@@ -219,8 +218,7 @@
smp_process_secure_connection_oob_data,
smp_set_local_oob_keys,
smp_set_local_oob_random_commitment,
- smp_idle_terminate,
- smp_fast_conn_param};
+ smp_idle_terminate};
/************ SMP Master FSM State/Event Indirection Table **************/
static const uint8_t smp_master_entry_map[][SMP_STATE_MAX] = {
@@ -344,7 +342,7 @@
/* SEC_GRANT */
{SMP_PROC_SEC_GRANT, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_APP_RSP},
/* IO_RSP */
- {SMP_SEND_PAIR_REQ, SMP_FAST_CONN_PARAM, SMP_STATE_PAIR_REQ_RSP},
+ {SMP_SEND_PAIR_REQ, SMP_SM_NO_ACTION, SMP_STATE_PAIR_REQ_RSP},
/* TK ready */
/* KEY_READY */
@@ -352,7 +350,7 @@
/* start enc mode setup */
/* ENC_REQ */
- {SMP_START_ENC, SMP_FAST_CONN_PARAM, SMP_STATE_ENCRYPTION_PENDING},
+ {SMP_START_ENC, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING},
/* DISCARD_SEC_REQ */
{SMP_PROC_DISCARD, SMP_SM_NO_ACTION, SMP_STATE_IDLE}
/* user confirms NC 'OK', i.e. phase 1 is completed */
@@ -630,7 +628,7 @@
{
/* Event Action Next State */
/* IO_RSP */
- {SMP_PROC_IO_RSP, SMP_FAST_CONN_PARAM, SMP_STATE_PAIR_REQ_RSP},
+ {SMP_PROC_IO_RSP, SMP_SM_NO_ACTION, SMP_STATE_PAIR_REQ_RSP},
/* SEC_GRANT */
{SMP_PROC_SEC_GRANT, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_APP_RSP},
diff --git a/stack/smp/smp_utils.cc b/stack/smp/smp_utils.cc
index 5027e3d..f81e21d 100644
--- a/stack/smp/smp_utils.cc
+++ b/stack/smp/smp_utils.cc
@@ -29,6 +29,7 @@
#include "bt_utils.h"
#include "btm_ble_api.h"
#include "btm_int.h"
+#include "common/metrics.h"
#include "device/include/controller.h"
#include "hcidefs.h"
#include "l2c_api.h"
@@ -37,20 +38,21 @@
#include "smp_int.h"
#define SMP_PAIRING_REQ_SIZE 7
-#define SMP_CONFIRM_CMD_SIZE (BT_OCTET16_LEN + 1)
-#define SMP_RAND_CMD_SIZE (BT_OCTET16_LEN + 1)
-#define SMP_INIT_CMD_SIZE (BT_OCTET16_LEN + 1)
-#define SMP_ENC_INFO_SIZE (BT_OCTET16_LEN + 1)
+#define SMP_CONFIRM_CMD_SIZE (OCTET16_LEN + 1)
+#define SMP_RAND_CMD_SIZE (OCTET16_LEN + 1)
+#define SMP_INIT_CMD_SIZE (OCTET16_LEN + 1)
+#define SMP_ENC_INFO_SIZE (OCTET16_LEN + 1)
#define SMP_MASTER_ID_SIZE (BT_OCTET8_LEN + 2 + 1)
-#define SMP_ID_INFO_SIZE (BT_OCTET16_LEN + 1)
+#define SMP_ID_INFO_SIZE (OCTET16_LEN + 1)
#define SMP_ID_ADDR_SIZE (BD_ADDR_LEN + 1 + 1)
-#define SMP_SIGN_INFO_SIZE (BT_OCTET16_LEN + 1)
+#define SMP_SIGN_INFO_SIZE (OCTET16_LEN + 1)
#define SMP_PAIR_FAIL_SIZE 2
#define SMP_SECURITY_REQUEST_SIZE 2
#define SMP_PAIR_PUBL_KEY_SIZE (1 /* opcode */ + (2 * BT_OCTET32_LEN))
-#define SMP_PAIR_COMMITM_SIZE (1 /* opcode */ + BT_OCTET16_LEN /*Commitment*/)
+#define SMP_PAIR_COMMITM_SIZE (1 /* opcode */ + OCTET16_LEN /*Commitment*/)
#define SMP_PAIR_DHKEY_CHECK_SIZE \
- (1 /* opcode */ + BT_OCTET16_LEN /*DHKey Check*/)
+ (1 /* opcode */ + OCTET16_LEN /*DHKey \
+ Check*/)
#define SMP_PAIR_KEYPR_NOTIF_SIZE (1 /* opcode */ + 1 /*Notif Type*/)
/* SMP command sizes per spec */
@@ -294,6 +296,34 @@
static tSMP_ASSO_MODEL smp_select_association_model_secure_connections(
tSMP_CB* p_cb);
+/**
+ * Log metrics data for SMP command
+ *
+ * @param bd_addr current pairing address
+ * @param is_outgoing whether this command is outgoing
+ * @param p_buf buffer to the beginning of SMP command
+ * @param buf_len length available to read for p_buf
+ */
+void smp_log_metrics(const RawAddress& bd_addr, bool is_outgoing,
+ const uint8_t* p_buf, size_t buf_len) {
+ if (buf_len < 1) {
+ LOG(WARNING) << __func__ << ": buffer is too small, size is " << buf_len;
+ return;
+ }
+ uint8_t cmd;
+ STREAM_TO_UINT8(cmd, p_buf);
+ buf_len--;
+ uint8_t failure_reason = 0;
+ if (cmd == SMP_OPCODE_PAIRING_FAILED && buf_len >= 1) {
+ STREAM_TO_UINT8(failure_reason, p_buf);
+ }
+ android::bluetooth::DirectionEnum direction =
+ is_outgoing ? android::bluetooth::DirectionEnum::DIRECTION_OUTGOING
+ : android::bluetooth::DirectionEnum::DIRECTION_INCOMING;
+ bluetooth::common::LogSmpPairingEvent(bd_addr, cmd, direction,
+ failure_reason);
+}
+
/*******************************************************************************
*
* Function smp_send_msg_to_L2CAP
@@ -312,6 +342,9 @@
SMP_TRACE_EVENT("%s", __func__);
smp_cb.total_tx_unacked += 1;
+ smp_log_metrics(rem_bda, true /* outgoing */,
+ p_toL2CAP->data + p_toL2CAP->offset, p_toL2CAP->len);
+
l2cap_ret = L2CA_SendFixedChnlData(fixed_cid, rem_bda, p_toL2CAP);
if (l2cap_ret == L2CAP_DW_FAILED) {
smp_cb.total_tx_unacked -= 1;
@@ -453,7 +486,7 @@
p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
UINT8_TO_STREAM(p, SMP_OPCODE_CONFIRM);
- ARRAY_TO_STREAM(p, p_cb->confirm, BT_OCTET16_LEN);
+ ARRAY_TO_STREAM(p, p_cb->confirm, OCTET16_LEN);
p_buf->offset = L2CAP_MIN_OFFSET;
p_buf->len = SMP_CONFIRM_CMD_SIZE;
@@ -477,7 +510,7 @@
p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
UINT8_TO_STREAM(p, SMP_OPCODE_RAND);
- ARRAY_TO_STREAM(p, p_cb->rand, BT_OCTET16_LEN);
+ ARRAY_TO_STREAM(p, p_cb->rand, OCTET16_LEN);
p_buf->offset = L2CAP_MIN_OFFSET;
p_buf->len = SMP_RAND_CMD_SIZE;
@@ -502,7 +535,7 @@
p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
UINT8_TO_STREAM(p, SMP_OPCODE_ENCRYPT_INFO);
- ARRAY_TO_STREAM(p, p_cb->ltk, BT_OCTET16_LEN);
+ ARRAY_TO_STREAM(p, p_cb->ltk, OCTET16_LEN);
p_buf->offset = L2CAP_MIN_OFFSET;
p_buf->len = SMP_ENC_INFO_SIZE;
@@ -546,7 +579,6 @@
static BT_HDR* smp_build_identity_info_cmd(UNUSED_ATTR uint8_t cmd_code,
UNUSED_ATTR tSMP_CB* p_cb) {
uint8_t* p;
- BT_OCTET16 irk;
BT_HDR* p_buf =
(BT_HDR*)osi_malloc(sizeof(BT_HDR) + SMP_ID_INFO_SIZE + L2CAP_MIN_OFFSET);
@@ -554,10 +586,10 @@
p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
- BTM_GetDeviceIDRoot(irk);
+ const Octet16& irk = BTM_GetDeviceIDRoot();
UINT8_TO_STREAM(p, SMP_OPCODE_IDENTITY_INFO);
- ARRAY_TO_STREAM(p, irk, BT_OCTET16_LEN);
+ ARRAY_TO_STREAM(p, irk.data(), OCTET16_LEN);
p_buf->offset = L2CAP_MIN_OFFSET;
p_buf->len = SMP_ID_INFO_SIZE;
@@ -608,7 +640,7 @@
p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
UINT8_TO_STREAM(p, SMP_OPCODE_SIGN_INFO);
- ARRAY_TO_STREAM(p, p_cb->csrk, BT_OCTET16_LEN);
+ ARRAY_TO_STREAM(p, p_cb->csrk, OCTET16_LEN);
p_buf->offset = L2CAP_MIN_OFFSET;
p_buf->len = SMP_SIGN_INFO_SIZE;
@@ -715,7 +747,7 @@
p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
UINT8_TO_STREAM(p, SMP_OPCODE_CONFIRM);
- ARRAY_TO_STREAM(p, p_cb->commitment, BT_OCTET16_LEN);
+ ARRAY_TO_STREAM(p, p_cb->commitment, OCTET16_LEN);
p_buf->offset = L2CAP_MIN_OFFSET;
p_buf->len = SMP_PAIR_COMMITM_SIZE;
@@ -740,7 +772,7 @@
p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
UINT8_TO_STREAM(p, SMP_OPCODE_PAIR_DHKEY_CHECK);
- ARRAY_TO_STREAM(p, p_cb->dhkey_check, BT_OCTET16_LEN);
+ ARRAY_TO_STREAM(p, p_cb->dhkey_check, OCTET16_LEN);
p_buf->offset = L2CAP_MIN_OFFSET;
p_buf->len = SMP_PAIR_DHKEY_CHECK_SIZE;
@@ -773,66 +805,42 @@
return p_buf;
}
-/*******************************************************************************
- *
- * Function smp_convert_string_to_tk
- *
- * Description This function is called to convert a 6 to 16 digits numeric
- * character string into SMP TK.
- *
- *
- * Returns void
- *
- ******************************************************************************/
-void smp_convert_string_to_tk(BT_OCTET16 tk, uint32_t passkey) {
- uint8_t* p = tk;
+/** This function is called to convert a 6 to 16 digits numeric character string
+ * into SMP TK. */
+void smp_convert_string_to_tk(Octet16* tk, uint32_t passkey) {
+ uint8_t* p = tk->data();
tSMP_KEY key;
SMP_TRACE_EVENT("smp_convert_string_to_tk");
UINT32_TO_STREAM(p, passkey);
key.key_type = SMP_KEY_TYPE_TK;
- key.p_data = tk;
+ key.p_data = tk->data();
tSMP_INT_DATA smp_int_data;
smp_int_data.key = key;
smp_sm_event(&smp_cb, SMP_KEY_READY_EVT, &smp_int_data);
}
-/*******************************************************************************
- *
- * Function smp_mask_enc_key
- *
- * Description This function is called to mask off the encryption key based
- * on the maximum encryption key size.
- *
- *
- * Returns void
- *
- ******************************************************************************/
-void smp_mask_enc_key(uint8_t loc_enc_size, uint8_t* p_data) {
+/** This function is called to mask off the encryption key based on the maximum
+ * encryption key size. */
+void smp_mask_enc_key(uint8_t loc_enc_size, Octet16* p_data) {
SMP_TRACE_EVENT("smp_mask_enc_key");
- if (loc_enc_size < BT_OCTET16_LEN) {
- for (; loc_enc_size < BT_OCTET16_LEN; loc_enc_size++)
- *(p_data + loc_enc_size) = 0;
+ if (loc_enc_size < OCTET16_LEN) {
+ for (; loc_enc_size < OCTET16_LEN; loc_enc_size++)
+ (*p_data)[loc_enc_size] = 0;
}
return;
}
-/*******************************************************************************
- *
- * Function smp_xor_128
- *
- * Description utility function to do an biteise exclusive-OR of two bit
- * strings of the length of BT_OCTET16_LEN.
- *
- * Returns void
- *
- ******************************************************************************/
-void smp_xor_128(BT_OCTET16 a, BT_OCTET16 b) {
- uint8_t i, *aa = a, *bb = b;
+/** utility function to do an biteise exclusive-OR of two bit strings of the
+ * length of OCTET16_LEN. Result is stored in first argument.
+ */
+void smp_xor_128(Octet16* a, const Octet16& b) {
+ CHECK(a);
+ uint8_t i, *aa = a->data();
+ const uint8_t* bb = b.data();
- SMP_TRACE_EVENT("smp_xor_128");
- for (i = 0; i < BT_OCTET16_LEN; i++) {
+ for (i = 0; i < OCTET16_LEN; i++) {
aa[i] = aa[i] ^ bb[i];
}
}
@@ -1408,15 +1416,14 @@
*
******************************************************************************/
bool smp_check_commitment(tSMP_CB* p_cb) {
- BT_OCTET16 expected;
SMP_TRACE_DEBUG("%s", __func__);
- smp_calculate_peer_commitment(p_cb, expected);
+ Octet16 expected = smp_calculate_peer_commitment(p_cb);
print128(expected, (const uint8_t*)"calculated peer commitment");
print128(p_cb->remote_commitment, (const uint8_t*)"received peer commitment");
- if (memcmp(p_cb->remote_commitment, expected, BT_OCTET16_LEN)) {
+ if (memcmp(p_cb->remote_commitment.data(), expected.data(), OCTET16_LEN)) {
SMP_TRACE_WARNING("%s: Commitment check fails", __func__);
return false;
}
@@ -1440,7 +1447,7 @@
tBTM_LE_KEY_VALUE ple_key;
SMP_TRACE_DEBUG("%s-Save LTK as local LTK key", __func__);
- memcpy(lle_key.lenc_key.ltk, p_cb->ltk, BT_OCTET16_LEN);
+ lle_key.lenc_key.ltk = p_cb->ltk;
lle_key.lenc_key.div = 0;
lle_key.lenc_key.key_size = p_cb->loc_enc_size;
lle_key.lenc_key.sec_level = p_cb->sec_level;
@@ -1449,52 +1456,38 @@
SMP_TRACE_DEBUG("%s-Save LTK as peer LTK key", __func__);
ple_key.penc_key.ediv = 0;
memset(ple_key.penc_key.rand, 0, BT_OCTET8_LEN);
- memcpy(ple_key.penc_key.ltk, p_cb->ltk, BT_OCTET16_LEN);
+ ple_key.penc_key.ltk = p_cb->ltk;
ple_key.penc_key.sec_level = p_cb->sec_level;
ple_key.penc_key.key_size = p_cb->loc_enc_size;
btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PENC, &ple_key, true);
}
-/*******************************************************************************
- *
- * Function smp_calculate_f5_mackey_and_long_term_key
- *
- * Description The function calculates MacKey and LTK and saves them in CB.
- * To calculate MacKey and LTK it calls smp_calc_f5(...).
- * MacKey is used in dhkey calculation, LTK is used to encrypt
- * the link.
- *
- * Returns false if out of resources, true otherwise.
- *
- ******************************************************************************/
-bool smp_calculate_f5_mackey_and_long_term_key(tSMP_CB* p_cb) {
+/** The function calculates MacKey and LTK and saves them in CB. To calculate
+ * MacKey and LTK it calls smp_calc_f5(...). MacKey is used in dhkey
+ * calculation, LTK is used to encrypt the link. */
+void smp_calculate_f5_mackey_and_long_term_key(tSMP_CB* p_cb) {
uint8_t a[7];
uint8_t b[7];
- uint8_t* p_na;
- uint8_t* p_nb;
+ Octet16 na;
+ Octet16 nb;
SMP_TRACE_DEBUG("%s", __func__);
if (p_cb->role == HCI_ROLE_MASTER) {
smp_collect_local_ble_address(a, p_cb);
smp_collect_peer_ble_address(b, p_cb);
- p_na = p_cb->rand;
- p_nb = p_cb->rrand;
+ na = p_cb->rand;
+ nb = p_cb->rrand;
} else {
smp_collect_local_ble_address(b, p_cb);
smp_collect_peer_ble_address(a, p_cb);
- p_na = p_cb->rrand;
- p_nb = p_cb->rand;
+ na = p_cb->rrand;
+ nb = p_cb->rand;
}
- if (!smp_calculate_f5(p_cb->dhkey, p_na, p_nb, a, b, p_cb->mac_key,
- p_cb->ltk)) {
- SMP_TRACE_ERROR("%s failed", __func__);
- return false;
- }
+ crypto_toolbox::f5(p_cb->dhkey, na, nb, a, b, &p_cb->mac_key, &p_cb->ltk);
SMP_TRACE_EVENT("%s is completed", __func__);
- return true;
}
/*******************************************************************************
@@ -1535,3 +1528,15 @@
return true;
}
+
+void print128(const Octet16& x, const uint8_t* key_name) {
+ if (VLOG_IS_ON(2) && DLOG_IS_ON(INFO)) {
+ uint8_t* p = (uint8_t*)x.data();
+
+ DVLOG(2) << key_name << " (MSB ~ LSB) = ";
+ for (int i = 0; i < 4; i++) {
+ DVLOG(2) << +p[OCTET16_LEN - i * 4 - 1] << +p[OCTET16_LEN - i * 4 - 2]
+ << +p[OCTET16_LEN - i * 4 - 3] << +p[OCTET16_LEN - i * 4 - 4];
+ }
+ }
+}
diff --git a/stack/srvc/srvc_battery.cc b/stack/srvc/srvc_battery.cc
deleted file mode 100644
index 8b5d93e..0000000
--- a/stack/srvc/srvc_battery.cc
+++ /dev/null
@@ -1,362 +0,0 @@
-/******************************************************************************
- *
- * Copyright 1999-2013 Broadcom 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.
- *
- ******************************************************************************/
-
-#include "bt_target.h"
-#include "bt_utils.h"
-#include "gatt_api.h"
-#include "gatt_int.h"
-#include "osi/include/osi.h"
-#include "srvc_battery_int.h"
-#include "srvc_eng_int.h"
-
-#define BA_MAX_CHAR_NUM 1
-
-/* max 3 descriptors, 1 desclration and 1 value */
-#define BA_MAX_ATTR_NUM (BA_MAX_CHAR_NUM * 5 + 1)
-
-#ifndef BATTER_LEVEL_PROP
-#define BATTER_LEVEL_PROP (GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY)
-#endif
-
-#ifndef BATTER_LEVEL_PERM
-#define BATTER_LEVEL_PERM (GATT_PERM_READ)
-#endif
-
-tBATTERY_CB battery_cb;
-
-/*******************************************************************************
- * battery_valid_handle_range
- *
- * validate a handle to be a DIS attribute handle or not.
- ******************************************************************************/
-bool battery_valid_handle_range(uint16_t handle) {
- uint8_t i = 0;
- tBA_INST* p_inst = &battery_cb.battery_inst[0];
-
- for (; i < BA_MAX_INT_NUM; i++, p_inst++) {
- if (handle == p_inst->ba_level_hdl || handle == p_inst->clt_cfg_hdl ||
- handle == p_inst->rpt_ref_hdl || handle == p_inst->pres_fmt_hdl) {
- return true;
- }
- }
- return false;
-}
-/*******************************************************************************
- * battery_s_write_attr_value
- *
- * Process write DIS attribute request.
- ******************************************************************************/
-uint8_t battery_s_write_attr_value(uint8_t clcb_idx, tGATT_WRITE_REQ* p_value,
- tGATT_STATUS* p_status) {
- uint8_t *p = p_value->value, i;
- uint16_t handle = p_value->handle;
- tBA_INST* p_inst = &battery_cb.battery_inst[0];
- tGATT_STATUS st = GATT_NOT_FOUND;
- tBA_WRITE_DATA cfg;
- uint8_t act = SRVC_ACT_RSP;
-
- for (i = 0; i < BA_MAX_INT_NUM; i++, p_inst++) {
- /* read battery level */
- if (handle == p_inst->clt_cfg_hdl) {
- cfg.remote_bda = srvc_eng_cb.clcb[clcb_idx].bda;
- STREAM_TO_UINT16(cfg.clt_cfg, p);
-
- if (p_inst->p_cback) {
- p_inst->pending_clcb_idx = clcb_idx;
- p_inst->pending_evt = BA_WRITE_CLT_CFG_REQ;
- p_inst->pending_handle = handle;
- cfg.need_rsp = p_value->need_rsp;
- act = SRVC_ACT_PENDING;
-
- (*p_inst->p_cback)(p_inst->app_id, BA_WRITE_CLT_CFG_REQ, &cfg);
- }
- } else /* all other handle is not writable */
- {
- st = GATT_WRITE_NOT_PERMIT;
- break;
- }
- }
- *p_status = st;
-
- return act;
-}
-/*******************************************************************************
- * BA Attributes Database Server Request callback
- ******************************************************************************/
-uint8_t battery_s_read_attr_value(uint8_t clcb_idx, uint16_t handle,
- UNUSED_ATTR tGATT_VALUE* p_value,
- bool is_long, tGATT_STATUS* p_status) {
- uint8_t i;
- tBA_INST* p_inst = &battery_cb.battery_inst[0];
- tGATT_STATUS st = GATT_NOT_FOUND;
- uint8_t act = SRVC_ACT_RSP;
-
- for (i = 0; i < BA_MAX_INT_NUM; i++, p_inst++) {
- /* read battery level */
- if (handle == p_inst->ba_level_hdl || handle == p_inst->clt_cfg_hdl ||
- handle == p_inst->rpt_ref_hdl || handle == p_inst->pres_fmt_hdl) {
- if (is_long) st = GATT_NOT_LONG;
-
- if (p_inst->p_cback) {
- if (handle == p_inst->ba_level_hdl)
- p_inst->pending_evt = BA_READ_LEVEL_REQ;
- if (handle == p_inst->clt_cfg_hdl)
- p_inst->pending_evt = BA_READ_CLT_CFG_REQ;
- if (handle == p_inst->pres_fmt_hdl)
- p_inst->pending_evt = BA_READ_PRE_FMT_REQ;
- if (handle == p_inst->rpt_ref_hdl)
- p_inst->pending_evt = BA_READ_RPT_REF_REQ;
-
- p_inst->pending_clcb_idx = clcb_idx;
- p_inst->pending_handle = handle;
- act = SRVC_ACT_PENDING;
-
- (*p_inst->p_cback)(p_inst->app_id, p_inst->pending_evt, NULL);
- } else /* application is not registered */
- st = GATT_ERR_UNLIKELY;
- break;
- }
- /* else attribute not found */
- }
-
- *p_status = st;
- return act;
-}
-
-/*******************************************************************************
- *
- * Function battery_gatt_c_read_ba_req
- *
- * Description Read remote device BA level attribute request.
- *
- * Returns void
- *
- ******************************************************************************/
-bool battery_gatt_c_read_ba_req(UNUSED_ATTR uint16_t conn_id) { return true; }
-
-/*******************************************************************************
- *
- * Function battery_c_cmpl_cback
- *
- * Description Client operation complete callback.
- *
- * Returns void
- *
- ******************************************************************************/
-void battery_c_cmpl_cback(UNUSED_ATTR tSRVC_CLCB* p_clcb,
- UNUSED_ATTR tGATTC_OPTYPE op,
- UNUSED_ATTR tGATT_STATUS status,
- UNUSED_ATTR tGATT_CL_COMPLETE* p_data) {}
-
-/*******************************************************************************
- *
- * Function Battery_Instantiate
- *
- * Description Instantiate a Battery service
- *
- ******************************************************************************/
-uint16_t Battery_Instantiate(uint8_t app_id, tBA_REG_INFO* p_reg_info) {
- uint16_t srvc_hdl = 0;
- tGATT_STATUS status = GATT_ERROR;
- tBA_INST* p_inst;
-
- if (battery_cb.inst_id == BA_MAX_INT_NUM) {
- LOG(ERROR) << "MAX battery service has been reached";
- return 0;
- }
-
- p_inst = &battery_cb.battery_inst[battery_cb.inst_id];
-
- btgatt_db_element_t service[BA_MAX_ATTR_NUM] = {};
-
- bluetooth::Uuid service_uuid =
- bluetooth::Uuid::From16Bit(UUID_SERVCLASS_BATTERY);
- service[0].type = /* p_reg_info->is_pri */ BTGATT_DB_PRIMARY_SERVICE;
- service[0].uuid = service_uuid;
-
- bluetooth::Uuid char_uuid =
- bluetooth::Uuid::From16Bit(GATT_UUID_BATTERY_LEVEL);
- service[1].type = BTGATT_DB_CHARACTERISTIC;
- service[1].uuid = char_uuid;
- service[1].properties = GATT_CHAR_PROP_BIT_READ;
- if (p_reg_info->ba_level_descr & BA_LEVEL_NOTIFY)
- service[1].properties |= GATT_CHAR_PROP_BIT_NOTIFY;
-
- int i = 2;
- if (p_reg_info->ba_level_descr & BA_LEVEL_NOTIFY) {
- bluetooth::Uuid desc_uuid =
- bluetooth::Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG);
-
- service[i].type = BTGATT_DB_DESCRIPTOR;
- service[i].uuid = desc_uuid;
- service[i].permissions = (GATT_PERM_READ | GATT_PERM_WRITE);
- i++;
- }
-
- /* need presentation format descriptor? */
- if (p_reg_info->ba_level_descr & BA_LEVEL_PRE_FMT) {
- bluetooth::Uuid desc_uuid =
- bluetooth::Uuid::From16Bit(GATT_UUID_CHAR_PRESENT_FORMAT);
-
- service[i].type = BTGATT_DB_DESCRIPTOR;
- service[i].uuid = desc_uuid;
- service[i].permissions = GATT_PERM_READ;
- i++;
- }
-
- /* need presentation format descriptor? */
- if (p_reg_info->ba_level_descr & BA_LEVEL_RPT_REF) {
- bluetooth::Uuid desc_uuid =
- bluetooth::Uuid::From16Bit(GATT_UUID_RPT_REF_DESCR);
-
- service[i].type = BTGATT_DB_DESCRIPTOR;
- service[i].uuid = desc_uuid;
- service[i].permissions = GATT_PERM_READ;
- i++;
- }
-
- GATTS_AddService(srvc_eng_cb.gatt_if, service, i);
-
- if (status != GATT_SUCCESS) {
- battery_cb.inst_id--;
- LOG(ERROR) << __func__ << " Failed to add battery servuce!";
- }
-
- battery_cb.inst_id++;
-
- p_inst->app_id = app_id;
- p_inst->p_cback = p_reg_info->p_cback;
-
- srvc_hdl = service[0].attribute_handle;
- p_inst->ba_level_hdl = service[1].attribute_handle;
-
- i = 2;
- if (p_reg_info->ba_level_descr & BA_LEVEL_NOTIFY) {
- p_inst->clt_cfg_hdl = service[i].attribute_handle;
- i++;
- }
-
- if (p_reg_info->ba_level_descr & BA_LEVEL_PRE_FMT) {
- p_inst->pres_fmt_hdl = service[i].attribute_handle;
- i++;
- }
-
- if (p_reg_info->ba_level_descr & BA_LEVEL_RPT_REF) {
- p_inst->rpt_ref_hdl = service[i].attribute_handle;
- i++;
- }
-
- return srvc_hdl;
-}
-/*******************************************************************************
- *
- * Function Battery_Rsp
- *
- * Description Respond to a battery service request
- *
- ******************************************************************************/
-void Battery_Rsp(uint8_t app_id, tGATT_STATUS st, uint8_t event,
- tBA_RSP_DATA* p_rsp) {
- tBA_INST* p_inst = &battery_cb.battery_inst[0];
- tGATTS_RSP rsp;
- uint8_t* pp;
-
- uint8_t i = 0;
- while (i < BA_MAX_INT_NUM) {
- if (p_inst->app_id == app_id && p_inst->ba_level_hdl != 0) break;
- i++;
- }
-
- if (i == BA_MAX_INT_NUM) return;
-
- memset(&rsp, 0, sizeof(tGATTS_RSP));
-
- if (p_inst->pending_evt == event) {
- switch (event) {
- case BA_READ_CLT_CFG_REQ:
- rsp.attr_value.handle = p_inst->pending_handle;
- rsp.attr_value.len = 2;
- pp = rsp.attr_value.value;
- UINT16_TO_STREAM(pp, p_rsp->clt_cfg);
- srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp);
- break;
-
- case BA_READ_LEVEL_REQ:
- rsp.attr_value.handle = p_inst->pending_handle;
- rsp.attr_value.len = 1;
- pp = rsp.attr_value.value;
- UINT8_TO_STREAM(pp, p_rsp->ba_level);
- srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp);
- break;
-
- case BA_WRITE_CLT_CFG_REQ:
- srvc_sr_rsp(p_inst->pending_clcb_idx, st, NULL);
- break;
-
- case BA_READ_RPT_REF_REQ:
- rsp.attr_value.handle = p_inst->pending_handle;
- rsp.attr_value.len = 2;
- pp = rsp.attr_value.value;
- UINT8_TO_STREAM(pp, p_rsp->rpt_ref.rpt_id);
- UINT8_TO_STREAM(pp, p_rsp->rpt_ref.rpt_type);
- srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp);
- break;
-
- default:
- break;
- }
- p_inst->pending_clcb_idx = 0;
- p_inst->pending_evt = 0;
- p_inst->pending_handle = 0;
- }
- return;
-}
-/*******************************************************************************
- *
- * Function Battery_Notify
- *
- * Description Send battery level notification
- *
- ******************************************************************************/
-void Battery_Notify(uint8_t app_id, const RawAddress& remote_bda,
- uint8_t battery_level) {
- tBA_INST* p_inst = &battery_cb.battery_inst[0];
- uint8_t i = 0;
-
- while (i < BA_MAX_INT_NUM) {
- if (p_inst->app_id == app_id && p_inst->ba_level_hdl != 0) break;
- i++;
- }
-
- if (i == BA_MAX_INT_NUM || p_inst->clt_cfg_hdl == 0) return;
-
- srvc_sr_notify(remote_bda, p_inst->ba_level_hdl, 1, &battery_level);
-}
-/*******************************************************************************
- *
- * Function Battery_ReadBatteryLevel
- *
- * Description Read remote device Battery Level information.
- *
- * Returns void
- *
- ******************************************************************************/
-bool Battery_ReadBatteryLevel(const RawAddress&) {
- /* to be implemented */
- return true;
-}
diff --git a/stack/srvc/srvc_battery_int.h b/stack/srvc/srvc_battery_int.h
deleted file mode 100644
index 2ffb85a..0000000
--- a/stack/srvc/srvc_battery_int.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/******************************************************************************
- *
- * Copyright 1999-2012 Broadcom 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.
- *
- ******************************************************************************/
-
-#ifndef SRVC_BATTERY_INT_H
-#define SRVC_BATTERY_INT_H
-
-#include "bt_target.h"
-#include "gatt_api.h"
-#include "srvc_api.h"
-
-#ifndef BA_MAX_INT_NUM
-#define BA_MAX_INT_NUM 4
-#endif
-
-#define BATTERY_LEVEL_SIZE 1
-
-typedef struct {
- uint8_t app_id;
- uint16_t ba_level_hdl;
- uint16_t clt_cfg_hdl;
- uint16_t rpt_ref_hdl;
- uint16_t pres_fmt_hdl;
-
- tBA_CBACK* p_cback;
-
- uint16_t pending_handle;
- uint8_t pending_clcb_idx;
- uint8_t pending_evt;
-
-} tBA_INST;
-
-typedef struct {
- tBA_INST battery_inst[BA_MAX_INT_NUM];
- uint8_t inst_id;
- bool enabled;
-
-} tBATTERY_CB;
-
-/* Global GATT data */
-extern tBATTERY_CB battery_cb;
-
-extern bool battery_valid_handle_range(uint16_t handle);
-
-extern uint8_t battery_s_write_attr_value(uint8_t clcb_idx,
- tGATT_WRITE_REQ* p_value,
- tGATT_STATUS* p_status);
-extern uint8_t battery_s_read_attr_value(uint8_t clcb_idx, uint16_t handle,
- tGATT_VALUE* p_value, bool is_long,
- tGATT_STATUS* p_status);
-
-#endif
diff --git a/stack/srvc/srvc_eng.cc b/stack/srvc/srvc_eng.cc
index af57ff1..564a2ea 100644
--- a/stack/srvc/srvc_eng.cc
+++ b/stack/srvc/srvc_eng.cc
@@ -23,7 +23,6 @@
#include "osi/include/osi.h"
#include "srvc_eng_int.h"
-#include "srvc_battery_int.h"
#include "srvc_dis_int.h"
using base::StringPrintf;
@@ -213,12 +212,6 @@
if (dis_valid_handle_range(p_data->handle))
act = dis_read_attr_value(clcb_idx, p_data->handle, &p_rsp->attr_value,
p_data->is_long, p_status);
-
- else if (battery_valid_handle_range(p_data->handle))
- act =
- battery_s_read_attr_value(clcb_idx, p_data->handle, &p_rsp->attr_value,
- p_data->is_long, p_status);
-
else
*p_status = status;
return act;
@@ -233,8 +226,6 @@
if (dis_valid_handle_range(p_data->handle)) {
act = dis_write_attr_value(p_data, p_status);
- } else if (battery_valid_handle_range(p_data->handle)) {
- act = battery_s_write_attr_value(clcb_idx, p_data, p_status);
} else
*p_status = GATT_NOT_FOUND;
diff --git a/stack/test/ble_advertiser_test.cc b/stack/test/ble_advertiser_test.cc
index 65a30d5..952aa41 100644
--- a/stack/test/ble_advertiser_test.cc
+++ b/stack/test/ble_advertiser_test.cc
@@ -47,24 +47,16 @@
uint16_t BTM_ReadDiscoverability(uint16_t* p_window, uint16_t* p_interval) {
return true;
}
-bool SMP_Encrypt(uint8_t* key, uint8_t key_len, uint8_t* plain_text,
- uint8_t pt_len, tSMP_ENC* p_out) {
- return true;
-}
-void BTM_GetDeviceIDRoot(BT_OCTET16 irk) {}
-void btm_ble_update_dmt_flag_bits(uint8_t* flag_value,
- const uint16_t connect_mode,
- const uint16_t disc_mode) {}
void btm_acl_update_conn_addr(uint16_t conn_handle, const RawAddress& address) {
}
-void btm_gen_resolvable_private_addr(base::Callback<void(uint8_t[8])> cb) {
- uint8_t fake_rand[8] = {0, 0, 0, 0, 0, 0, 0, 0};
- cb.Run(fake_rand);
+void btm_gen_resolvable_private_addr(
+ base::Callback<void(const RawAddress& rpa)> cb) {
+ cb.Run(RawAddress::kEmpty);
}
alarm_callback_t last_alarm_cb = nullptr;
void* last_alarm_data = nullptr;
-void alarm_set_on_mloop(alarm_t* alarm, period_ms_t interval_ms,
+void alarm_set_on_mloop(alarm_t* alarm, uint64_t interval_ms,
alarm_callback_t cb, void* data) {
last_alarm_cb = cb;
last_alarm_data = data;
@@ -139,7 +131,7 @@
cmd_complete);
};
- bool QuirkAdvertiserZeroHandle() { return false; }
+ bool QuirkAdvertiserZeroHandle() override { return false; }
private:
DISALLOW_COPY_AND_ASSIGN(AdvertiserHciMock);
@@ -161,7 +153,7 @@
std::unique_ptr<AdvertiserHciMock> hci_mock;
- virtual void SetUp() {
+ void SetUp() override {
hci_mock.reset(new AdvertiserHciMock());
base::Callback<void(uint8_t)> inst_cnt_Cb;
@@ -176,7 +168,7 @@
inst_cnt_Cb.Run(num_adv_instances);
}
- virtual void TearDown() {
+ void TearDown() override {
BleAdvertisingManager::CleanUp();
hci_mock.reset();
}
diff --git a/stack/test/common/mock_btu_layer.cc b/stack/test/common/mock_btu_layer.cc
index f5bbf7a..6d7abe9 100644
--- a/stack/test/common/mock_btu_layer.cc
+++ b/stack/test/common/mock_btu_layer.cc
@@ -18,4 +18,4 @@
#include <base/message_loop/message_loop.h>
-base::MessageLoop* get_message_loop() { return nullptr; }
\ No newline at end of file
+base::MessageLoop* get_main_message_loop() { return nullptr; }
\ No newline at end of file
diff --git a/stack/test/crypto_toolbox_test.cc b/stack/test/crypto_toolbox_test.cc
new file mode 100644
index 0000000..727668d
--- /dev/null
+++ b/stack/test/crypto_toolbox_test.cc
@@ -0,0 +1,400 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "stack/crypto_toolbox/aes.h"
+#include "stack/crypto_toolbox/crypto_toolbox.h"
+
+#include <base/logging.h>
+#include <base/strings/string_number_conversions.h>
+#include <vector>
+
+using ::testing::ElementsAreArray;
+
+namespace crypto_toolbox {
+
+// BT Spec 5.0 | Vol 3, Part H D.1
+TEST(CryptoToolboxTest, bt_spec_test_d_1_test) {
+ uint8_t k[] = {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
+
+ uint8_t m[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+ uint8_t aes_cmac_k_m[] = {0x7d, 0xf7, 0x6b, 0x0c, 0x1a, 0xb8, 0x99, 0xb3,
+ 0x3e, 0x42, 0xf0, 0x47, 0xb9, 0x1b, 0x54, 0x6f};
+
+ uint8_t output[16];
+ aes_context ctx;
+ aes_set_key(k, sizeof(k), &ctx);
+ aes_encrypt(m, output, &ctx); /* outputs in byte 48 to byte 63 */
+
+ EXPECT_THAT(output, ElementsAreArray(aes_cmac_k_m, OCTET16_LEN));
+
+ // useful for debugging
+ // LOG(INFO) << "k " << base::HexEncode(k, OCTET16_LEN);
+ // LOG(INFO) << "m " << base::HexEncode(m, sizeof(m));
+ // LOG(INFO) << "output " << base::HexEncode(output, OCTET16_LEN);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.1.1
+TEST(CryptoToolboxTest, bt_spec_example_d_1_1_test) {
+ Octet16 k{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
+
+ Octet16 aes_cmac_k_m{0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28,
+ 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(k), std::end(k));
+ std::reverse(std::begin(aes_cmac_k_m), std::end(aes_cmac_k_m));
+
+ Octet16 output = aes_cmac(k, nullptr /* empty message */, 0);
+
+ EXPECT_EQ(output, aes_cmac_k_m);
+
+ // useful for debugging
+ // LOG(INFO) << "k " << base::HexEncode(k.data(), k.size());
+ // LOG(INFO) << "aes_cmac(k,nullptr) "
+ // << base::HexEncode(output.data(), output.size());
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.1.2
+TEST(CryptoToolboxTest, bt_spec_example_d_1_2_test) {
+ Octet16 k{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
+
+ Octet16 m = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a};
+
+ Octet16 aes_cmac_k_m{0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44,
+ 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(k), std::end(k));
+ std::reverse(std::begin(m), std::end(m));
+ std::reverse(std::begin(aes_cmac_k_m), std::end(aes_cmac_k_m));
+
+ Octet16 output = aes_cmac(k, m);
+
+ EXPECT_EQ(output, aes_cmac_k_m);
+
+ // useful for debugging
+ // LOG(INFO) << "k " << base::HexEncode(k.data(), k.size());
+ // LOG(INFO) << "m " << base::HexEncode(m, sizeof(m));
+ // LOG(INFO) << "aes_cmac(k,m) "
+ // << base::HexEncode(output.data(), output.size());
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.1.3
+TEST(CryptoToolboxTest, bt_spec_example_d_1_3_test) {
+ Octet16 k{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
+
+ uint8_t m[] = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d,
+ 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57,
+ 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf,
+ 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11};
+
+ Octet16 aes_cmac_k_m{0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30,
+ 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(k), std::end(k));
+ std::reverse(std::begin(m), std::end(m));
+ std::reverse(std::begin(aes_cmac_k_m), std::end(aes_cmac_k_m));
+
+ Octet16 output = aes_cmac(k, m, sizeof(m));
+ EXPECT_EQ(output, aes_cmac_k_m);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.1.4
+TEST(CryptoToolboxTest, bt_spec_example_d_1_4_test) {
+ Octet16 k{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
+
+ uint8_t m[] = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d,
+ 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57,
+ 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf,
+ 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+ 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, 0xf6, 0x9f,
+ 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b,
+ 0xe6, 0x6c, 0x37, 0x10};
+
+ Octet16 aes_cmac_k_m{0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92,
+ 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(k), std::end(k));
+ std::reverse(std::begin(m), std::end(m));
+ std::reverse(std::begin(aes_cmac_k_m), std::end(aes_cmac_k_m));
+
+ Octet16 output = aes_cmac(k, m, sizeof(m));
+
+ EXPECT_EQ(output, aes_cmac_k_m);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.2
+TEST(CryptoToolboxTest, bt_spec_example_d_2_test) {
+ std::vector<uint8_t> u{0x20, 0xb0, 0x03, 0xd2, 0xf2, 0x97, 0xbe, 0x2c,
+ 0x5e, 0x2c, 0x83, 0xa7, 0xe9, 0xf9, 0xa5, 0xb9,
+ 0xef, 0xf4, 0x91, 0x11, 0xac, 0xf4, 0xfd, 0xdb,
+ 0xcc, 0x03, 0x01, 0x48, 0x0e, 0x35, 0x9d, 0xe6};
+ std::vector<uint8_t> v{0x55, 0x18, 0x8b, 0x3d, 0x32, 0xf6, 0xbb, 0x9a,
+ 0x90, 0x0a, 0xfc, 0xfb, 0xee, 0xd4, 0xe7, 0x2a,
+ 0x59, 0xcb, 0x9a, 0xc2, 0xf1, 0x9d, 0x7c, 0xfb,
+ 0x6b, 0x4f, 0xdd, 0x49, 0xf4, 0x7f, 0xc5, 0xfd};
+ Octet16 x{0xd5, 0xcb, 0x84, 0x54, 0xd1, 0x77, 0x73, 0x3e,
+ 0xff, 0xff, 0xb2, 0xec, 0x71, 0x2b, 0xae, 0xab};
+ uint8_t z = 0x00;
+
+ Octet16 aes_cmac_k_m{0xf2, 0xc9, 0x16, 0xf1, 0x07, 0xa9, 0xbd, 0x1c,
+ 0xf1, 0xed, 0xa1, 0xbe, 0xa9, 0x74, 0x87, 0x2d};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(u), std::end(u));
+ std::reverse(std::begin(v), std::end(v));
+ std::reverse(std::begin(x), std::end(x));
+ std::reverse(std::begin(aes_cmac_k_m), std::end(aes_cmac_k_m));
+
+ Octet16 output = f4(u.data(), v.data(), x, z);
+
+ EXPECT_EQ(output, aes_cmac_k_m);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.3
+TEST(CryptoToolboxTest, bt_spec_example_d_3_test) {
+ std::array<uint8_t, 32> dhkey_w{
+ 0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, 0x34, 0x10, 0x10,
+ 0xa6, 0x0a, 0x39, 0x7d, 0x9b, 0x99, 0x79, 0x6b, 0x13, 0xb4, 0xf8,
+ 0x66, 0xf1, 0x86, 0x8d, 0x34, 0xf3, 0x73, 0xbf, 0xa6, 0x98};
+ Octet16 n1{0xd5, 0xcb, 0x84, 0x54, 0xd1, 0x77, 0x73, 0x3e,
+ 0xff, 0xff, 0xb2, 0xec, 0x71, 0x2b, 0xae, 0xab};
+ Octet16 n2{0xa6, 0xe8, 0xe7, 0xcc, 0x25, 0xa7, 0x5f, 0x6e,
+ 0x21, 0x65, 0x83, 0xf7, 0xff, 0x3d, 0xc4, 0xcf};
+ std::array<uint8_t, 7> a1{0x00, 0x56, 0x12, 0x37, 0x37, 0xbf, 0xce};
+ std::array<uint8_t, 7> a2{0x00, 0xa7, 0x13, 0x70, 0x2d, 0xcf, 0xc1};
+
+ Octet16 expected_ltk{0x69, 0x86, 0x79, 0x11, 0x69, 0xd7, 0xcd, 0x23,
+ 0x98, 0x05, 0x22, 0xb5, 0x94, 0x75, 0x0a, 0x38};
+ Octet16 expected_mac_key{0x29, 0x65, 0xf1, 0x76, 0xa1, 0x08, 0x4a, 0x02,
+ 0xfd, 0x3f, 0x6a, 0x20, 0xce, 0x63, 0x6e, 0x20};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(dhkey_w), std::end(dhkey_w));
+ std::reverse(std::begin(n1), std::end(n1));
+ std::reverse(std::begin(n2), std::end(n2));
+ std::reverse(std::begin(a1), std::end(a1));
+ std::reverse(std::begin(a2), std::end(a2));
+ std::reverse(std::begin(expected_ltk), std::end(expected_ltk));
+ std::reverse(std::begin(expected_mac_key), std::end(expected_mac_key));
+
+ Octet16 mac_key, ltk;
+ f5(dhkey_w.data(), n1, n2, a1.data(), a2.data(), &mac_key, <k);
+
+ EXPECT_EQ(mac_key, expected_mac_key);
+ EXPECT_EQ(ltk, expected_ltk);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.4
+TEST(CryptoToolboxTest, bt_spec_example_d_4_test) {
+ Octet16 n1{0xd5, 0xcb, 0x84, 0x54, 0xd1, 0x77, 0x73, 0x3e,
+ 0xff, 0xff, 0xb2, 0xec, 0x71, 0x2b, 0xae, 0xab};
+ Octet16 n2{0xa6, 0xe8, 0xe7, 0xcc, 0x25, 0xa7, 0x5f, 0x6e,
+ 0x21, 0x65, 0x83, 0xf7, 0xff, 0x3d, 0xc4, 0xcf};
+ Octet16 r{0x12, 0xa3, 0x34, 0x3b, 0xb4, 0x53, 0xbb, 0x54,
+ 0x08, 0xda, 0x42, 0xd2, 0x0c, 0x2d, 0x0f, 0xc8};
+ std::vector<uint8_t> IOcap{0x01, 0x01, 0x02};
+ std::vector<uint8_t> a1{0x00, 0x56, 0x12, 0x37, 0x37, 0xbf, 0xce};
+ std::vector<uint8_t> a2{0x00, 0xa7, 0x13, 0x70, 0x2d, 0xcf, 0xc1};
+
+ Octet16 MacKey{0x29, 0x65, 0xf1, 0x76, 0xa1, 0x08, 0x4a, 0x02,
+ 0xfd, 0x3f, 0x6a, 0x20, 0xce, 0x63, 0x6e, 0x20};
+
+ Octet16 expected_aes_cmac{0xe3, 0xc4, 0x73, 0x98, 0x9c, 0xd0, 0xe8, 0xc5,
+ 0xd2, 0x6c, 0x0b, 0x09, 0xda, 0x95, 0x8f, 0x61};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(n1), std::end(n1));
+ std::reverse(std::begin(n2), std::end(n2));
+ std::reverse(std::begin(r), std::end(r));
+ std::reverse(std::begin(IOcap), std::end(IOcap));
+ std::reverse(std::begin(a1), std::end(a1));
+ std::reverse(std::begin(a2), std::end(a2));
+ std::reverse(std::begin(MacKey), std::end(MacKey));
+ std::reverse(std::begin(expected_aes_cmac), std::end(expected_aes_cmac));
+
+ Octet16 aes_cmac = f6(MacKey, n1, n2, r, IOcap.data(), a1.data(), a2.data());
+
+ EXPECT_EQ(aes_cmac, expected_aes_cmac);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.5
+TEST(CryptoToolboxTest, bt_spec_example_d_5_test) {
+ std::array<uint8_t, 32> u{0x20, 0xb0, 0x03, 0xd2, 0xf2, 0x97, 0xbe, 0x2c,
+ 0x5e, 0x2c, 0x83, 0xa7, 0xe9, 0xf9, 0xa5, 0xb9,
+ 0xef, 0xf4, 0x91, 0x11, 0xac, 0xf4, 0xfd, 0xdb,
+ 0xcc, 0x03, 0x01, 0x48, 0x0e, 0x35, 0x9d, 0xe6};
+ std::array<uint8_t, 32> v{0x55, 0x18, 0x8b, 0x3d, 0x32, 0xf6, 0xbb, 0x9a,
+ 0x90, 0x0a, 0xfc, 0xfb, 0xee, 0xd4, 0xe7, 0x2a,
+ 0x59, 0xcb, 0x9a, 0xc2, 0xf1, 0x9d, 0x7c, 0xfb,
+ 0x6b, 0x4f, 0xdd, 0x49, 0xf4, 0x7f, 0xc5, 0xfd};
+
+ Octet16 x{0xd5, 0xcb, 0x84, 0x54, 0xd1, 0x77, 0x73, 0x3e,
+ 0xff, 0xff, 0xb2, 0xec, 0x71, 0x2b, 0xae, 0xab};
+ Octet16 y{0xa6, 0xe8, 0xe7, 0xcc, 0x25, 0xa7, 0x5f, 0x6e,
+ 0x21, 0x65, 0x83, 0xf7, 0xff, 0x3d, 0xc4, 0xcf};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(u), std::end(u));
+ std::reverse(std::begin(v), std::end(v));
+ std::reverse(std::begin(x), std::end(x));
+ std::reverse(std::begin(y), std::end(y));
+
+ uint32_t val = g2(u.data(), v.data(), x, y);
+
+ /* the returned value is already mod 1000000, so do mod on the test result
+ * value too */
+ EXPECT_EQ(val, 0x2f9ed5baU % 1000000);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.6
+TEST(CryptoToolboxTest, bt_spec_example_d_6_test) {
+ Octet16 key{0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05,
+ 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b};
+ std::array<uint8_t, 4> keyID{0x6c, 0x65, 0x62, 0x72};
+ Octet16 expected_aes_cmac{0x2d, 0x9a, 0xe1, 0x02, 0xe7, 0x6d, 0xc9, 0x1c,
+ 0xe8, 0xd3, 0xa9, 0xe2, 0x80, 0xb1, 0x63, 0x99};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(key), std::end(key));
+ std::reverse(std::begin(keyID), std::end(keyID));
+ std::reverse(std::begin(expected_aes_cmac), std::end(expected_aes_cmac));
+
+ Octet16 aes_cmac = h6(key, keyID);
+ EXPECT_EQ(aes_cmac, expected_aes_cmac);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.7
+TEST(CryptoToolboxTest, bt_spec_example_d_7_test) {
+ Octet16 IRK{0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05,
+ 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b};
+ Octet16 prand{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x81, 0x94};
+ Octet16 expected_aes_128{0x15, 0x9d, 0x5f, 0xb7, 0x2e, 0xbe, 0x23, 0x11,
+ 0xa4, 0x8c, 0x1b, 0xdc, 0xc4, 0x0d, 0xfb, 0xaa};
+ std::array<uint8_t, 3> expected_ah{0x0d, 0xfb, 0xaa};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(IRK), std::end(IRK));
+ std::reverse(std::begin(prand), std::end(prand));
+ std::reverse(std::begin(expected_aes_128), std::end(expected_aes_128));
+ std::reverse(std::begin(expected_ah), std::end(expected_ah));
+
+ Octet16 result = aes_128(IRK, prand.data(), 3);
+ EXPECT_EQ(expected_aes_128, result);
+
+ // little/big endian 24 bits
+ EXPECT_EQ(result[0], expected_ah[0]);
+ EXPECT_EQ(result[1], expected_ah[1]);
+ EXPECT_EQ(result[2], expected_ah[2]);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.8
+TEST(CryptoToolboxTest, bt_spec_example_d_8_test) {
+ Octet16 Key{0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05,
+ 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b};
+ Octet16 SALT{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x74, 0x6D, 0x70, 0x31};
+ Octet16 expected_aes_cmac{0xfb, 0x17, 0x35, 0x97, 0xc6, 0xa3, 0xc0, 0xec,
+ 0xd2, 0x99, 0x8c, 0x2a, 0x75, 0xa5, 0x70, 0x11};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(Key), std::end(Key));
+ std::reverse(std::begin(SALT), std::end(SALT));
+ std::reverse(std::begin(expected_aes_cmac), std::end(expected_aes_cmac));
+
+ Octet16 aes_cmac = h7(SALT, Key);
+ EXPECT_EQ(expected_aes_cmac, aes_cmac);
+}
+
+extern Octet16 smp_calculate_ltk_to_link_key(const Octet16& ltk, bool use_h7);
+
+// BT Spec 5.0 | Vol 3, Part H D.9
+TEST(CryptoToolboxTest, bt_spec_example_d_9_test) {
+ Octet16 LTK{0x36, 0x8d, 0xf9, 0xbc, 0xe3, 0x26, 0x4b, 0x58,
+ 0xbd, 0x06, 0x6c, 0x33, 0x33, 0x4f, 0xbf, 0x64};
+ Octet16 expected_link_key{0x28, 0x7a, 0xd3, 0x79, 0xdc, 0xa4, 0x02, 0x53,
+ 0x0a, 0x39, 0xf1, 0xf4, 0x30, 0x47, 0xb8, 0x35};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(LTK), std::end(LTK));
+ std::reverse(std::begin(expected_link_key), std::end(expected_link_key));
+
+ Octet16 link_key = ltk_to_link_key(LTK, true);
+ EXPECT_EQ(expected_link_key, link_key);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.10
+TEST(CryptoToolboxTest, bt_spec_example_d_10_test) {
+ Octet16 LTK{0x36, 0x8d, 0xf9, 0xbc, 0xe3, 0x26, 0x4b, 0x58,
+ 0xbd, 0x06, 0x6c, 0x33, 0x33, 0x4f, 0xbf, 0x64};
+ Octet16 expected_link_key{0xbc, 0x1c, 0xa4, 0xef, 0x63, 0x3f, 0xc1, 0xbd,
+ 0x0d, 0x82, 0x30, 0xaf, 0xee, 0x38, 0x8f, 0xb0};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(LTK), std::end(LTK));
+ std::reverse(std::begin(expected_link_key), std::end(expected_link_key));
+
+ Octet16 link_key = ltk_to_link_key(LTK, false);
+ EXPECT_EQ(expected_link_key, link_key);
+}
+
+// // BT Spec 5.0 | Vol 3, Part H D.11
+TEST(CryptoToolboxTest, bt_spec_example_d_11_test) {
+ Octet16 link_key{0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00};
+ Octet16 expected_ltk{0xe8, 0x5e, 0x09, 0xeb, 0x5e, 0xcc, 0xb3, 0xe2,
+ 0x69, 0x41, 0x8a, 0x13, 0x32, 0x11, 0xbc, 0x79};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(link_key), std::end(link_key));
+ std::reverse(std::begin(expected_ltk), std::end(expected_ltk));
+
+ Octet16 ltk = link_key_to_ltk(link_key, true);
+ EXPECT_EQ(expected_ltk, ltk);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.12
+TEST(CryptoToolboxTest, bt_spec_example_d_12_test) {
+ Octet16 link_key{0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00};
+ Octet16 expected_ltk{0xa8, 0x13, 0xfb, 0x72, 0xf1, 0xa3, 0xdf, 0xa1,
+ 0x8a, 0x2c, 0x9a, 0x43, 0xf1, 0x0d, 0x0a, 0x30};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(link_key), std::end(link_key));
+ std::reverse(std::begin(expected_ltk), std::end(expected_ltk));
+
+ Octet16 ltk = link_key_to_ltk(link_key, false);
+ EXPECT_EQ(expected_ltk, ltk);
+}
+
+} // namespace crypto_toolbox
diff --git a/stack/test/gatt_connection_manager_test.cc b/stack/test/gatt_connection_manager_test.cc
new file mode 100644
index 0000000..0997aa8
--- /dev/null
+++ b/stack/test/gatt_connection_manager_test.cc
@@ -0,0 +1,274 @@
+#include "stack/gatt/connection_manager.h"
+
+#include <base/bind.h>
+#include <base/callback.h>
+#include <base/location.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <memory>
+#include "osi/include/alarm.h"
+#include "osi/test/alarm_mock.h"
+
+using testing::_;
+using testing::Mock;
+using testing::Return;
+using testing::SaveArg;
+
+using connection_manager::tAPP_ID;
+
+namespace {
+// convinience mock, for verifying whitelist operaitons on lower layer are
+// actually scheduled
+class WhiteListMock {
+ public:
+ MOCK_METHOD1(WhiteListAdd, bool(const RawAddress&));
+ MOCK_METHOD1(WhiteListRemove, void(const RawAddress&));
+ MOCK_METHOD0(WhiteListClear, void());
+ MOCK_METHOD0(SetLeConnectionModeToFast, bool());
+ MOCK_METHOD0(SetLeConnectionModeToSlow, void());
+ MOCK_METHOD2(OnConnectionTimedOut, void(uint8_t, const RawAddress&));
+};
+
+std::unique_ptr<WhiteListMock> localWhiteListMock;
+} // namespace
+
+RawAddress address1{{0x01, 0x01, 0x01, 0x01, 0x01, 0x01}};
+RawAddress address2{{0x22, 0x22, 0x02, 0x22, 0x33, 0x22}};
+
+constexpr tAPP_ID CLIENT1 = 1;
+constexpr tAPP_ID CLIENT2 = 2;
+constexpr tAPP_ID CLIENT3 = 3;
+constexpr tAPP_ID CLIENT10 = 10;
+
+// Implementation of btm_ble_bgconn.h API for test.
+bool BTM_WhiteListAdd(const RawAddress& address) {
+ return localWhiteListMock->WhiteListAdd(address);
+}
+
+void BTM_WhiteListRemove(const RawAddress& address) {
+ return localWhiteListMock->WhiteListRemove(address);
+}
+
+void BTM_WhiteListClear() { return localWhiteListMock->WhiteListClear(); }
+
+bool BTM_SetLeConnectionModeToFast() {
+ return localWhiteListMock->SetLeConnectionModeToFast();
+}
+
+void BTM_SetLeConnectionModeToSlow() {
+ localWhiteListMock->SetLeConnectionModeToSlow();
+}
+
+namespace connection_manager {
+class BleConnectionManager : public testing::Test {
+ void SetUp() override {
+ localWhiteListMock = std::make_unique<WhiteListMock>();
+ }
+
+ void TearDown() override {
+ connection_manager::reset(true);
+ AlarmMock::Reset();
+ localWhiteListMock.reset();
+ }
+};
+
+void on_connection_timed_out(uint8_t app_id, const RawAddress& address) {
+ localWhiteListMock->OnConnectionTimedOut(app_id, address);
+}
+
+/** Verify that app can add a device to white list, it is returned as interested
+ * app, and then can remove the device later. */
+TEST_F(BleConnectionManager, test_background_connection_add_remove) {
+ EXPECT_CALL(*localWhiteListMock, WhiteListAdd(address1))
+ .WillOnce(Return(true));
+ EXPECT_CALL(*localWhiteListMock, WhiteListRemove(_)).Times(0);
+
+ EXPECT_TRUE(background_connect_add(CLIENT1, address1));
+
+ Mock::VerifyAndClearExpectations(localWhiteListMock.get());
+
+ std::set<tAPP_ID> apps = get_apps_connecting_to(address1);
+ EXPECT_EQ(apps.size(), 1UL);
+ EXPECT_EQ(apps.count(CLIENT1), 1UL);
+
+ EXPECT_CALL(*localWhiteListMock, WhiteListAdd(_)).Times(0);
+ EXPECT_CALL(*localWhiteListMock, WhiteListRemove(address1)).Times(1);
+
+ EXPECT_TRUE(background_connect_remove(CLIENT1, address1));
+
+ EXPECT_EQ(get_apps_connecting_to(address1).size(), 0UL);
+
+ Mock::VerifyAndClearExpectations(localWhiteListMock.get());
+}
+
+/** Verify that multiple clients adding same device multiple times, result in
+ * device being added to whtie list only once, also, that device is removed only
+ * after last client removes it. */
+TEST_F(BleConnectionManager, test_background_connection_multiple_clients) {
+ EXPECT_CALL(*localWhiteListMock, WhiteListAdd(address1))
+ .WillOnce(Return(true));
+ EXPECT_CALL(*localWhiteListMock, WhiteListRemove(_)).Times(0);
+ EXPECT_TRUE(background_connect_add(CLIENT1, address1));
+ EXPECT_TRUE(background_connect_add(CLIENT1, address1));
+ EXPECT_TRUE(background_connect_add(CLIENT2, address1));
+ EXPECT_TRUE(background_connect_add(CLIENT3, address1));
+
+ EXPECT_EQ(get_apps_connecting_to(address1).size(), 3UL);
+
+ Mock::VerifyAndClearExpectations(localWhiteListMock.get());
+
+ EXPECT_CALL(*localWhiteListMock, WhiteListAdd(_)).Times(0);
+
+ // removing from nonexisting client, should fail
+ EXPECT_FALSE(background_connect_remove(CLIENT10, address1));
+
+ EXPECT_TRUE(background_connect_remove(CLIENT1, address1));
+ // already removed, removing from same client twice should return false;
+ EXPECT_FALSE(background_connect_remove(CLIENT1, address1));
+ EXPECT_TRUE(background_connect_remove(CLIENT2, address1));
+
+ EXPECT_CALL(*localWhiteListMock, WhiteListRemove(address1)).Times(1);
+ EXPECT_TRUE(background_connect_remove(CLIENT3, address1));
+
+ EXPECT_EQ(get_apps_connecting_to(address1).size(), 0UL);
+
+ Mock::VerifyAndClearExpectations(localWhiteListMock.get());
+}
+
+/** Verify adding/removing device to direct connection. */
+TEST_F(BleConnectionManager, test_direct_connection_client) {
+ // Direct connect attempt: use faster scan parameters, add to white list,
+ // start 30 timeout
+ EXPECT_CALL(*localWhiteListMock, SetLeConnectionModeToFast()).Times(1);
+ EXPECT_CALL(*localWhiteListMock, WhiteListAdd(address1))
+ .WillOnce(Return(true));
+ EXPECT_CALL(*localWhiteListMock, WhiteListRemove(_)).Times(0);
+ EXPECT_CALL(*AlarmMock::Get(), AlarmNew(_)).Times(1);
+ EXPECT_CALL(*AlarmMock::Get(), AlarmSetOnMloop(_, _, _, _)).Times(1);
+ EXPECT_TRUE(direct_connect_add(CLIENT1, address1));
+
+ // App already doing a direct connection, attempt to re-add result in failure
+ EXPECT_FALSE(direct_connect_add(CLIENT1, address1));
+
+ // Client that don't do direct connection should fail attempt to stop it
+ EXPECT_FALSE(direct_connect_remove(CLIENT2, address1));
+
+ Mock::VerifyAndClearExpectations(localWhiteListMock.get());
+
+ EXPECT_CALL(*localWhiteListMock, SetLeConnectionModeToSlow()).Times(1);
+ EXPECT_CALL(*localWhiteListMock, WhiteListRemove(_)).Times(1);
+ EXPECT_CALL(*AlarmMock::Get(), AlarmFree(_)).Times(1);
+
+ // Removal should lower the connection parameters, and free the alarm.
+ // Even though we call WhiteListRemove, it won't be executed over HCI until
+ // whitelist is in use, i.e. next connection attempt
+ EXPECT_TRUE(direct_connect_remove(CLIENT1, address1));
+
+ Mock::VerifyAndClearExpectations(localWhiteListMock.get());
+}
+
+/** Verify direct connection timeout does remove device from white list, and
+ * lower the connection scan parameters */
+TEST_F(BleConnectionManager, test_direct_connect_timeout) {
+ EXPECT_CALL(*localWhiteListMock, SetLeConnectionModeToFast()).Times(1);
+ EXPECT_CALL(*localWhiteListMock, WhiteListAdd(address1))
+ .WillOnce(Return(true));
+ EXPECT_CALL(*AlarmMock::Get(), AlarmNew(_)).Times(1);
+ alarm_callback_t alarm_callback = nullptr;
+ void* alarm_data = nullptr;
+
+ EXPECT_CALL(*AlarmMock::Get(), AlarmSetOnMloop(_, _, _, _))
+ .Times(1)
+ .WillOnce(DoAll(SaveArg<2>(&alarm_callback), SaveArg<3>(&alarm_data)));
+
+ // Start direct connect attempt...
+ EXPECT_TRUE(direct_connect_add(CLIENT1, address1));
+
+ Mock::VerifyAndClearExpectations(localWhiteListMock.get());
+
+ EXPECT_CALL(*localWhiteListMock, SetLeConnectionModeToSlow()).Times(1);
+ EXPECT_CALL(*localWhiteListMock, WhiteListRemove(_)).Times(1);
+ EXPECT_CALL(*localWhiteListMock, OnConnectionTimedOut(CLIENT1, address1)).Times(1);
+ EXPECT_CALL(*AlarmMock::Get(), AlarmFree(_)).Times(1);
+
+ // simulate timeout seconds passed, alarm executing
+ alarm_callback(alarm_data);
+
+ Mock::VerifyAndClearExpectations(localWhiteListMock.get());
+}
+
+/** Verify that we properly handle successfull direct connection */
+TEST_F(BleConnectionManager, test_direct_connection_success) {
+ EXPECT_CALL(*localWhiteListMock, SetLeConnectionModeToFast()).Times(1);
+ EXPECT_CALL(*localWhiteListMock, WhiteListAdd(address1))
+ .WillOnce(Return(true));
+ EXPECT_CALL(*AlarmMock::Get(), AlarmNew(_)).Times(1);
+ EXPECT_CALL(*AlarmMock::Get(), AlarmSetOnMloop(_, _, _, _)).Times(1);
+
+ // Start direct connect attempt...
+ EXPECT_TRUE(direct_connect_add(CLIENT1, address1));
+
+ Mock::VerifyAndClearExpectations(localWhiteListMock.get());
+
+ EXPECT_CALL(*localWhiteListMock, SetLeConnectionModeToSlow()).Times(1);
+ EXPECT_CALL(*localWhiteListMock, WhiteListRemove(address1)).Times(1);
+ EXPECT_CALL(*AlarmMock::Get(), AlarmFree(_)).Times(1);
+ // simulate event from lower layers - connections was established
+ // successfully.
+ on_connection_complete(address1);
+}
+
+/** Verify that we properly handle application unregistration */
+TEST_F(BleConnectionManager, test_app_unregister) {
+ /* Test scenario:
+ * - Client 1 connecting to address1 and address2.
+ * - Client 2 connecting to address2
+ * - unregistration of Client1 should trigger address1 removal from white list
+ * - unregistration of Client2 should trigger address2 removal
+ */
+
+ EXPECT_CALL(*localWhiteListMock, WhiteListAdd(address1))
+ .WillOnce(Return(true));
+ EXPECT_CALL(*localWhiteListMock, WhiteListAdd(address2))
+ .WillOnce(Return(true));
+ EXPECT_TRUE(direct_connect_add(CLIENT1, address1));
+ EXPECT_TRUE(background_connect_add(CLIENT1, address2));
+ EXPECT_TRUE(direct_connect_add(CLIENT2, address2));
+ Mock::VerifyAndClearExpectations(localWhiteListMock.get());
+
+ EXPECT_CALL(*localWhiteListMock, WhiteListRemove(address1)).Times(1);
+ on_app_deregistered(CLIENT1);
+ Mock::VerifyAndClearExpectations(localWhiteListMock.get());
+
+ EXPECT_CALL(*localWhiteListMock, WhiteListRemove(address2)).Times(1);
+ on_app_deregistered(CLIENT2);
+}
+
+/** Verify adding device to both direct connection and background connection. */
+TEST_F(BleConnectionManager, test_direct_and_background_connect) {
+ EXPECT_CALL(*localWhiteListMock, SetLeConnectionModeToFast()).Times(1);
+ EXPECT_CALL(*localWhiteListMock, WhiteListAdd(address1))
+ .WillOnce(Return(true));
+ EXPECT_CALL(*localWhiteListMock, WhiteListRemove(_)).Times(0);
+ EXPECT_CALL(*AlarmMock::Get(), AlarmNew(_)).Times(1);
+ EXPECT_CALL(*AlarmMock::Get(), AlarmSetOnMloop(_, _, _, _)).Times(1);
+ // add device as both direct and background connection
+ EXPECT_TRUE(direct_connect_add(CLIENT1, address1));
+ EXPECT_TRUE(background_connect_add(CLIENT1, address1));
+
+ Mock::VerifyAndClearExpectations(localWhiteListMock.get());
+
+ EXPECT_CALL(*localWhiteListMock, SetLeConnectionModeToSlow()).Times(1);
+ EXPECT_CALL(*AlarmMock::Get(), AlarmFree(_)).Times(1);
+ // not removing from white list yet, as the background connection is still
+ // pending.
+ EXPECT_TRUE(direct_connect_remove(CLIENT1, address1));
+
+ // remove from white list, because no more interest in device.
+ EXPECT_CALL(*localWhiteListMock, WhiteListRemove(_)).Times(1);
+ EXPECT_TRUE(background_connect_remove(CLIENT1, address1));
+
+ Mock::VerifyAndClearExpectations(localWhiteListMock.get());
+}
+
+} // namespace connection_manager
diff --git a/stack/test/stack_a2dp_test.cc b/stack/test/stack_a2dp_test.cc
index 63dfb28..fecb3ca 100644
--- a/stack/test/stack_a2dp_test.cc
+++ b/stack/test/stack_a2dp_test.cc
@@ -173,6 +173,7 @@
static const char* APTX_ENCODER_LIB_NAME = "libaptX_encoder.so";
static const char* APTX_HD_ENCODER_LIB_NAME = "libaptXHD_encoder.so";
static const char* LDAC_ENCODER_LIB_NAME = "libldacBT_enc.so";
+static const char* LDAC_DECODER_LIB_NAME = "libldacBT_dec.so";
static bool has_shared_library(const char* name) {
void* lib_handle = dlopen(name, RTLD_NOW);
@@ -223,6 +224,11 @@
case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
supported = true;
break;
+ case BTAV_A2DP_CODEC_INDEX_SINK_LDAC:
+ // Codec LDAC is supported only if the device has the corresponding
+ // shared library installed.
+ supported = has_shared_library(LDAC_DECODER_LIB_NAME);
+ break;
case BTAV_A2DP_CODEC_INDEX_MAX:
// Needed to avoid using "default:" case so we can capture when
// a new codec is added, and it can be included here.
diff --git a/stack/test/stack_btu_test.cc b/stack/test/stack_btu_test.cc
index 97e95d2..2502646 100644
--- a/stack/test/stack_btu_test.cc
+++ b/stack/test/stack_btu_test.cc
@@ -26,9 +26,9 @@
#include <unistd.h>
#include "btcore/include/module.h"
+#include "common/message_loop_thread.h"
#include "osi/include/alarm.h"
#include "osi/include/fixed_queue.h"
-#include "osi/include/thread.h"
#include "stack/include/btu.h"
class TimeoutHelper {
@@ -60,17 +60,17 @@
TimeoutHelper helper;
// External function definitions
-void btu_message_loop_run(void* context);
void btu_task_start_up(void* context);
void btu_task_shut_down(void* context);
/* Below are methods and variables that must be implemented if we don't want to
* compile the whole stack. They will be removed, or changed into mocks one by
* one in the future, as the refactoring progresses */
-void btif_transfer_context(void (*)(unsigned short, char*), uint16_t, char*,
- int, void (*)(unsigned short, char*, char*)) {
+bt_status_t do_in_jni_thread(const base::Location& from_here,
+ base::OnceClosure task) {
helper.notify();
-};
+ return BT_STATUS_SUCCESS;
+}
void btu_init_core(){};
void btif_init_ok(unsigned short, char*){};
@@ -82,18 +82,17 @@
bool module_init(module_t const*) { return true; };
void module_clean_up(module_t const*){};
-thread_t* bt_workqueue_thread;
+bluetooth::common::MessageLoopThread bt_startup_thread("test alarm thread");
class BtuMessageLoopTest : public testing::Test {
public:
MOCK_METHOD0(TestCallback, void(void));
base::MessageLoop* message_loop;
- virtual void SetUp() {
+ void SetUp() override {
// Initialize alarms to prevent btu_task_shut_down from crashing
alarm_new("test alarm");
- bt_workqueue_thread = thread_new("test alarm thread");
-
+ bt_startup_thread.StartUp();
// btu_task_start_up calls btif_transfer_context to let the stack know
// start up is finished
btu_task_start_up(nullptr);
@@ -101,16 +100,17 @@
"BTU startup timed out"));
}
- virtual void TearDown() {
+ void TearDown() override {
btu_task_shut_down(nullptr);
alarm_cleanup();
+ bt_startup_thread.ShutDown();
}
void Fail(std::string message) { FAIL() << message; }
};
TEST_F(BtuMessageLoopTest, send_message) {
- message_loop = get_message_loop();
+ message_loop = get_main_message_loop();
EXPECT_FALSE(message_loop == nullptr);
EXPECT_CALL(*this, TestCallback()).Times(1);
diff --git a/stack/test/stack_smp_test.cc b/stack/test/stack_smp_test.cc
index 12c10f6..d83430c 100644
--- a/stack/test/stack_smp_test.cc
+++ b/stack/test/stack_smp_test.cc
@@ -81,70 +81,58 @@
va_end(args);
}
-extern void smp_gen_p1_4_confirm(tSMP_CB* p_cb,
- tBLE_ADDR_TYPE remote_bd_addr_type,
- BT_OCTET16 p1);
+extern Octet16 smp_gen_p1_4_confirm(tSMP_CB* p_cb,
+ tBLE_ADDR_TYPE remote_bd_addr_type);
-extern void smp_gen_p2_4_confirm(tSMP_CB* p_cb, const RawAddress& remote_bda,
- BT_OCTET16 p2);
+extern Octet16 smp_gen_p2_4_confirm(tSMP_CB* p_cb,
+ const RawAddress& remote_bda);
-extern tSMP_STATUS smp_calculate_comfirm(tSMP_CB* p_cb, BT_OCTET16 rand,
- tSMP_ENC* output);
+extern tSMP_STATUS smp_calculate_comfirm(tSMP_CB* p_cb, const Octet16& rand,
+ Octet16* output);
namespace testing {
-void dump_uint128(BT_OCTET16 a, char* buffer) {
- for (unsigned int i = 0; i < sizeof(BT_OCTET16); ++i) {
+void dump_uint128(const Octet16& a, char* buffer) {
+ for (unsigned int i = 0; i < OCTET16_LEN; ++i) {
snprintf(buffer, 3, "%02x", a[i]);
buffer += 2;
}
*buffer = '\0';
}
-void dump_uint128_reverse(BT_OCTET16 a, char* buffer) {
- for (int i = (int)(sizeof(BT_OCTET16) - 1); i >= 0; --i) {
+void dump_uint128_reverse(const Octet16& a, char* buffer) {
+ for (int i = (int)(OCTET16_LEN - 1); i >= 0; --i) {
snprintf(buffer, 3, "%02x", a[i]);
buffer += 2;
}
*buffer = '\0';
}
-void print_uint128(BT_OCTET16 a) {
- for (unsigned int i = 0; i < sizeof(BT_OCTET16); ++i) {
+void print_uint128(const Octet16& a) {
+ for (unsigned int i = 0; i < OCTET16_LEN; ++i) {
printf("%02x", a[i]);
}
printf("\n");
}
-void parse_uint128(const char* input, BT_OCTET16 output) {
- memset(output, 0, sizeof(BT_OCTET16));
- for (unsigned int count = 0; count < sizeof(BT_OCTET16); count++) {
+Octet16 parse_uint128(const char* input) {
+ Octet16 output{0};
+ for (unsigned int count = 0; count < OCTET16_LEN; count++) {
sscanf(input, "%2hhx", &output[count]);
input += 2;
}
-}
-
-void reverse_array_inplace(BT_OCTET16 a) {
- uint8_t tmp;
- uint8_t* a_end = a + sizeof(BT_OCTET16) - 1;
- while (a_end > a) {
- tmp = *a_end;
- *a_end = *a;
- *a = tmp;
- ++a;
- --a_end;
- }
+ return output;
}
class SmpCalculateConfirmTest : public Test {
protected:
tSMP_CB p_cb_;
// Set random to 0x5783D52156AD6F0E6388274EC6702EE0
- BT_OCTET16 rand_ = {0x57, 0x83, 0xD5, 0x21, 0x56, 0xAD, 0x6F, 0x0E,
- 0x63, 0x88, 0x27, 0x4E, 0xC6, 0x70, 0x2E, 0xE0};
+ Octet16 rand_{0x57, 0x83, 0xD5, 0x21, 0x56, 0xAD, 0x6F, 0x0E,
+ 0x63, 0x88, 0x27, 0x4E, 0xC6, 0x70, 0x2E, 0xE0};
- void SetUp() {
- memset(p_cb_.tk, 0, sizeof(p_cb_.tk));
+ void SetUp() override {
+ p_cb_.tk = {0};
// Set pairing request packet to 0x070710000001(01)
p_cb_.local_io_capability = 0x01;
p_cb_.loc_oob_flag = 0x00;
@@ -161,68 +149,63 @@
p_cb_.peer_r_key = 0x05;
// Set role to master
p_cb_.role = HCI_ROLE_MASTER;
- reverse_array_inplace(rand_);
+ std::reverse(rand_.begin(), rand_.end());
}
- void TearDown() {}
+ void TearDown() override {}
public:
};
// Test smp_gen_p2_4_confirm function implementation
TEST_F(SmpCalculateConfirmTest, test_smp_gen_p2_4_confirm_as_master) {
- BT_OCTET16 p2;
RawAddress remote_bda;
tBLE_ADDR_TYPE remote_bd_addr_type = 0;
BTM_ReadRemoteConnectionAddr(p_cb_.pairing_bda, remote_bda,
&remote_bd_addr_type);
BTM_ReadConnectionAddr(p_cb_.pairing_bda, p_cb_.local_bda, &p_cb_.addr_type);
- smp_gen_p2_4_confirm(&p_cb_, remote_bda, p2);
+ Octet16 p2 = smp_gen_p2_4_confirm(&p_cb_, remote_bda);
// Correct p2 is 0x00000000a1a2a3a4a5a6b1b2b3b4b5b6
const char expected_p2_str[] = "00000000a1a2a3a4a5a6b1b2b3b4b5b6";
- char p2_str[2 * sizeof(BT_OCTET16) + 1];
+ char p2_str[2 * OCTET16_LEN + 1];
dump_uint128_reverse(p2, p2_str);
ASSERT_THAT(p2_str, StrEq(expected_p2_str));
}
-// Test smp_gen_p1_4_confirm and SMP_Encrypt function implementation
-TEST_F(SmpCalculateConfirmTest, test_SMP_Encrypt_as_master) {
- BT_OCTET16 p1;
+// Test smp_gen_p1_4_confirm and aes_128 function implementation
+TEST_F(SmpCalculateConfirmTest, test_aes_128_as_master) {
RawAddress remote_bda;
tBLE_ADDR_TYPE remote_bd_addr_type = 0;
BTM_ReadRemoteConnectionAddr(p_cb_.pairing_bda, remote_bda,
&remote_bd_addr_type);
BTM_ReadConnectionAddr(p_cb_.pairing_bda, p_cb_.local_bda, &p_cb_.addr_type);
- smp_gen_p1_4_confirm(&p_cb_, remote_bd_addr_type, p1);
+ Octet16 p1 = smp_gen_p1_4_confirm(&p_cb_, remote_bd_addr_type);
// Correct p1 is 0x05000800000302070710000001010001
const char expected_p1_str[] = "05000800000302070710000001010001";
- char p1_str[2 * sizeof(BT_OCTET16) + 1];
+ char p1_str[2 * OCTET16_LEN + 1];
dump_uint128_reverse(p1, p1_str);
ASSERT_THAT(p1_str, StrEq(expected_p1_str));
- smp_xor_128(p1, rand_);
+ smp_xor_128(&p1, rand_);
// Correct p1 xor r is 0x5283dd2156ae6d096498274ec7712ee1
const char expected_p1_xor_r_str[] = "5283dd2156ae6d096498274ec7712ee1";
- char p1_xor_r_str[2 * sizeof(BT_OCTET16) + 1];
+ char p1_xor_r_str[2 * OCTET16_LEN + 1];
dump_uint128_reverse(p1, p1_xor_r_str);
ASSERT_THAT(p1_xor_r_str, StrEq(expected_p1_xor_r_str));
- tSMP_ENC output;
- memset(&output, 0, sizeof(tSMP_ENC));
- ASSERT_TRUE(
- SMP_Encrypt(p_cb_.tk, BT_OCTET16_LEN, p1, BT_OCTET16_LEN, &output));
+ Octet16 output = crypto_toolbox::aes_128(p_cb_.tk, p1.data(), OCTET16_LEN);
const char expected_p1_prime_str[] = "02c7aa2a9857ac866ff91232df0e3c95";
- char p1_prime_str[2 * sizeof(BT_OCTET16) + 1];
- dump_uint128_reverse(output.param_buf, p1_prime_str);
+ char p1_prime_str[2 * OCTET16_LEN + 1];
+ dump_uint128_reverse(output, p1_prime_str);
ASSERT_THAT(p1_prime_str, StrEq(expected_p1_prime_str));
}
// Test smp_calculate_comfirm function implementation
TEST_F(SmpCalculateConfirmTest, test_smp_calculate_comfirm_as_master) {
- tSMP_ENC output;
+ Octet16 output;
tSMP_STATUS status = smp_calculate_comfirm(&p_cb_, rand_, &output);
EXPECT_EQ(status, SMP_SUCCESS);
// Correct MConfirm is 0x1e1e3fef878988ead2a74dc5bef13b86
const char expected_confirm_str[] = "1e1e3fef878988ead2a74dc5bef13b86";
- char confirm_str[2 * sizeof(BT_OCTET16) + 1];
- dump_uint128_reverse(output.param_buf, confirm_str);
+ char confirm_str[2 * OCTET16_LEN + 1];
+ dump_uint128_reverse(output, confirm_str);
ASSERT_THAT(confirm_str, StrEq(expected_confirm_str));
}
@@ -278,8 +261,8 @@
TEST(SmpEccValidationTest, test_invalid_points) {
Point p;
- multiprecision_init(p.x, 8);
- multiprecision_init(p.y, 8);
+ multiprecision_init(p.x);
+ multiprecision_init(p.y);
EXPECT_FALSE(ECC_ValidatePoint(p));
diff --git a/test/gen_coverage.py b/test/gen_coverage.py
new file mode 100755
index 0000000..c699d3b
--- /dev/null
+++ b/test/gen_coverage.py
@@ -0,0 +1,412 @@
+#!/usr/bin/env python
+#
+# Copyright 2018, 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.
+
+import argparse
+import datetime
+import logging
+import json
+import os
+import shutil
+import subprocess
+import sys
+import webbrowser
+
+from run_host_unit_tests import *
+
+"""
+This script is used to generate code coverage results host supported libraries.
+The script by default will generate an html report that summarizes the coverage
+results of the specified tests. The results can also be browsed to provide a
+report of which lines have been traveled upon execution of the binary.
+
+NOTE: Code that is compiled out or hidden by a #DEFINE will be listed as
+having been executed 0 times, thus reducing overall coverage.
+
+The steps in order to add coverage support to a new library and its
+corrisponding host test are as follows.
+
+1. Add "clang_file_coverage" (defined in //build/Android.bp) as a default to the
+ source library(s) you want statistics for.
+ NOTE: Forgoing this default will cause no coverage data to be generated for
+ the source files in the library.
+
+2. Add "clang_coverage_bin" as a default to the host supported test binary that
+ excercises the libraries that you covered in step 1.
+ NOTE: Forgetting to add this will cause there to be *NO* coverage data
+ generated when the binary is run.
+
+3. Add the host test binary name and the files/directories you want coverage
+ statistics for to the COVERAGE_TESTS variable defined below. You may add
+ individual filenames or a directory to be tested.
+ NOTE: Avoid using a / at the beginning of a covered_files entry as this
+ breaks how the coverage generator resolves filenames.
+
+TODO: Support generating XML data and printing results to standard out.
+"""
+
+COVERAGE_TESTS = [
+ {
+ "test_name": "net_test_avrcp",
+ "covered_files": [
+ "system/bt/profile/avrcp",
+ ],
+ }, {
+ "test_name": "bluetooth_test_sdp",
+ "covered_files": [
+ "system/bt/profile/sdp",
+ ],
+ }, {
+ "test_name": "test-vendor_test_host",
+ "covered_files": [
+ "system/bt/vendor_libs/test_vendor_lib/include",
+ "system/bt/vendor_libs/test_vendor_lib/src",
+ ],
+ }, {
+ "test_name": "rootcanal-packets_test_host",
+ "covered_files": [
+ "system/bt/vendor_libs/test_vendor_lib/packets",
+ ],
+ }, {
+ "test_name": "bluetooth_test_common",
+ "covered_files": [
+ "system/bt/common",
+ ],
+ },
+]
+
+WORKING_DIR = '/tmp/coverage'
+SOONG_UI_BASH = 'build/soong/soong_ui.bash'
+LLVM_DIR = 'prebuilts/clang/host/linux-x86/clang-r353983b/bin'
+LLVM_MERGE = LLVM_DIR + '/llvm-profdata'
+LLVM_COV = LLVM_DIR + '/llvm-cov'
+
+def write_root_html_head(f):
+ # Write the header part of the root html file. This was pulled from the
+ # page source of one of the generated html files.
+ f.write("<!doctype html><html><head>" \
+ "<meta name='viewport' content='width=device-width,initial-scale=1'><met" \
+ "a charset='UTF-8'><link rel='stylesheet' type='text/css' href='style.cs" \
+ "s'></head><body><h2>Coverage Report</h2><h4>Created: " +
+ str(datetime.datetime.now().strftime('%Y-%m-%d %H:%M')) +
+ "</h4><p>Click <a href='http://clang.llvm.org/docs/SourceBasedCodeCovera" \
+ "ge.html#interpreting-reports'>here</a> for information about interpreti" \
+ "ng this report.</p><div class='centered'><table><tr><td class='column-e" \
+ "ntry-bold'>Filename</td><td class='column-entry-bold'>Function Coverage" \
+ "</td><td class='column-entry-bold'>Instantiation Coverage</td><td class" \
+ "='column-entry-bold'>Line Coverage</td><td class='column-entry-bold'>Re" \
+ "gion Coverage</td></tr>"
+ )
+
+
+def write_root_html_column(f, covered, count):
+ percent = covered * 100.0 / count
+ value = "%.2f%% (%d/%d) " % (percent, covered, count)
+ color = 'column-entry-yellow'
+ if percent == 100:
+ color = 'column-entry-green'
+ if percent < 80.0:
+ color = 'column-entry-red'
+ f.write("<td class=\'" + color + "\'><pre>" + value + "</pre></td>")
+
+
+def write_root_html_rows(f, tests):
+ totals = {
+ "functions":{
+ "covered": 0,
+ "count": 0
+ },
+ "instantiations":{
+ "covered": 0,
+ "count": 0
+ },
+ "lines":{
+ "covered": 0,
+ "count": 0
+ },
+ "regions":{
+ "covered": 0,
+ "count": 0
+ }
+ }
+
+ # Write the tests with their coverage summaries.
+ for test in tests:
+ test_name = test['test_name']
+ covered_files = test['covered_files']
+ json_results = generate_coverage_json(test)
+ test_totals = json_results['data'][0]['totals']
+
+ f.write("<tr class='light-row'><td><pre><a href=\'" +
+ os.path.join(test_name, "index.html") + "\'>" + test_name +
+ "</a></pre></td>")
+ for field_name in ['functions', 'instantiations', 'lines', 'regions']:
+ field = test_totals[field_name]
+ totals[field_name]['covered'] += field['covered']
+ totals[field_name]['count'] += field['count']
+ write_root_html_column(f, field['covered'], field['count'])
+ f.write("</tr>");
+
+ #Write the totals row.
+ f.write("<tr class='light-row-bold'><td><pre>Totals</a></pre></td>")
+ for field_name in ['functions', 'instantiations', 'lines', 'regions']:
+ field = totals[field_name]
+ write_root_html_column(f, field['covered'], field['count'])
+ f.write("</tr>");
+
+
+def write_root_html_tail(f):
+ # Pulled from the generated html coverage report.
+ f.write("</table></div><h5>Generated by llvm-cov -- llvm version 7.0.2svn<" \
+ "/h5></body></html>")
+
+
+def generate_root_html(tests):
+ # Copy the css file from one of the coverage reports.
+ source_file = os.path.join(os.path.join(WORKING_DIR, tests[0]['test_name']), "style.css")
+ dest_file = os.path.join(WORKING_DIR, "style.css")
+ shutil.copy2(source_file, dest_file)
+
+ # Write the root index.html file that sumarizes all the tests.
+ f = open(os.path.join(WORKING_DIR, "index.html"), "w")
+ write_root_html_head(f)
+ write_root_html_rows(f, tests)
+ write_root_html_tail(f)
+
+
+def get_profraw_for_test(test_name):
+ test_root = get_native_test_root_or_die()
+ test_cmd = os.path.join(os.path.join(test_root, test_name), test_name)
+ if not os.path.isfile(test_cmd):
+ logging.error('The test ' + test_name + ' does not exist, please compile first')
+ sys.exit(1)
+
+ profraw_file_name = test_name + ".profraw"
+ profraw_path = os.path.join(WORKING_DIR, os.path.join(test_name, profraw_file_name))
+ llvm_env_var = "LLVM_PROFILE_FILE=\"" + profraw_path + "\""
+
+ test_cmd = llvm_env_var + " " + test_cmd
+ logging.info('Generating profraw data for ' + test_name)
+ logging.debug('cmd: ' + test_cmd)
+ if subprocess.call(test_cmd, shell=True) != 0:
+ logging.error('Test ' + test_name + ' failed. Please fix the test before generating coverage.')
+ sys.exit(1)
+
+ if not os.path.isfile(profraw_path):
+ logging.error('Generating the profraw file failed. Did you remember to add the proper compiler flags to your build?')
+ sys.exit(1)
+
+ return profraw_file_name
+
+
+def merge_profraw_data(test_name):
+ cmd = []
+ cmd.append(os.path.join(get_android_root_or_die(), LLVM_MERGE + " merge "))
+
+ test_working_dir = os.path.join(WORKING_DIR, test_name);
+ cmd.append(os.path.join(test_working_dir, test_name + ".profraw"))
+ profdata_file = os.path.join(test_working_dir, test_name + ".profdata")
+
+ cmd.append('-o ' + profdata_file)
+ logging.info('Combining profraw files into profdata for ' + test_name)
+ logging.debug('cmd: ' + " ".join(cmd))
+ if subprocess.call(" ".join(cmd), shell=True) != 0:
+ logging.error('Failed to merge profraw files for ' + test_name)
+ sys.exit(1)
+
+
+def generate_coverage_html(test):
+ COVERAGE_ROOT = '/proc/self/cwd'
+
+ test_name = test['test_name']
+ file_list = test['covered_files']
+
+ test_working_dir = os.path.join(WORKING_DIR, test_name)
+ test_profdata_file = os.path.join(test_working_dir, test_name + ".profdata")
+
+ cmd = [
+ os.path.join(get_android_root_or_die(), LLVM_COV),
+ "show",
+ "-format=html",
+ "-summary-only",
+ "-show-line-counts-or-regions",
+ "-show-instantiation-summary",
+ "-instr-profile=" + test_profdata_file,
+ "-path-equivalence=\"" + COVERAGE_ROOT + "\",\"" +
+ get_android_root_or_die() + "\"",
+ "-output-dir=" + test_working_dir
+ ]
+
+ # We have to have one object file not as an argument otherwise we can't specify source files.
+ test_cmd = os.path.join(os.path.join(get_native_test_root_or_die(), test_name), test_name)
+ cmd.append(test_cmd)
+
+ # Filter out the specific files we want coverage for
+ for filename in file_list:
+ cmd.append(os.path.join(get_android_root_or_die(), filename))
+
+ logging.info('Generating coverage report for ' + test['test_name'])
+ logging.debug('cmd: ' + " ".join(cmd))
+ if subprocess.call(" ".join(cmd), shell=True) != 0:
+ logging.error('Failed to generate coverage for ' + test['test_name'])
+ sys.exit(1)
+
+
+def generate_coverage_json(test):
+ COVERAGE_ROOT = '/proc/self/cwd'
+ test_name = test['test_name']
+ file_list = test['covered_files']
+
+ test_working_dir = os.path.join(WORKING_DIR, test_name)
+ test_profdata_file = os.path.join(test_working_dir, test_name + ".profdata")
+
+ cmd = [
+ os.path.join(get_android_root_or_die(), LLVM_COV),
+ "export",
+ "-summary-only",
+ "-show-region-summary",
+ "-instr-profile=" + test_profdata_file,
+ "-path-equivalence=\"" + COVERAGE_ROOT + "\",\"" + get_android_root_or_die() + "\"",
+ ]
+
+ test_cmd = os.path.join(os.path.join(get_native_test_root_or_die(), test_name), test_name)
+ cmd.append(test_cmd)
+
+ # Filter out the specific files we want coverage for
+ for filename in file_list:
+ cmd.append(os.path.join(get_android_root_or_die(), filename))
+
+ logging.info('Generating coverage json for ' + test['test_name'])
+ logging.debug('cmd: ' + " ".join(cmd))
+
+ json_str = subprocess.check_output(" ".join(cmd), shell=True)
+ return json.loads(json_str)
+
+
+def write_json_summary(test):
+ test_name = test['test_name']
+ test_working_dir = os.path.join(WORKING_DIR, test_name)
+ test_json_summary_file = os.path.join(test_working_dir, test_name + '.json')
+ logging.debug('Writing json summary file: ' + test_json_summary_file)
+ json_file = open(test_json_summary_file, 'w')
+ json.dump(generate_coverage_json(test), json_file)
+ json_file.close()
+
+
+def list_tests():
+ for test in COVERAGE_TESTS:
+ print "Test Name: " + test['test_name']
+ print "Covered Files: "
+ for covered_file in test['covered_files']:
+ print " " + covered_file
+ print
+
+
+def main():
+ parser = argparse.ArgumentParser(description='Generate code coverage for enabled tests.')
+ parser.add_argument(
+ '-l', '--list-tests',
+ action='store_true',
+ dest='list_tests',
+ help='List all the available tests to be run as well as covered files.')
+ parser.add_argument(
+ '-a', '--all',
+ action='store_true',
+ help='Runs all available tests and prints their outputs. If no tests ' \
+ 'are specified via the -t option all tests will be run.')
+ parser.add_argument(
+ '-t', '--test',
+ dest='tests',
+ action='append',
+ type=str,
+ metavar='TESTNAME',
+ default=[],
+ help='Specifies a test to be run. Multiple tests can be specified by ' \
+ 'using this option multiple times. ' \
+ 'Example: \"gen_coverage.py -t test1 -t test2\"')
+ parser.add_argument(
+ '-o', '--output',
+ type=str,
+ metavar='DIRECTORY',
+ default='/tmp/coverage',
+ help='Specifies the directory to store all files. The directory will be ' \
+ 'created if it does not exist. Default is \"/tmp/coverage\"')
+ parser.add_argument(
+ '-s', '--skip-html',
+ dest='skip_html',
+ action='store_true',
+ help='Skip opening up the results of the coverage report in a browser.')
+ parser.add_argument(
+ '-j', '--json-file',
+ dest='json_file',
+ action='store_true',
+ help='Write out summary results to json file in test directory.')
+
+ logging.basicConfig(stream=sys.stderr, level=logging.DEBUG, format='%(levelname)s %(message)s')
+ logging.addLevelName(logging.DEBUG, "[\033[1;34m%s\033[0m]" % logging.getLevelName(logging.DEBUG))
+ logging.addLevelName(logging.INFO, "[\033[1;34m%s\033[0m]" % logging.getLevelName(logging.INFO))
+ logging.addLevelName(logging.WARNING, "[\033[1;31m%s\033[0m]" % logging.getLevelName(logging.WARNING))
+ logging.addLevelName(logging.ERROR, "[\033[1;31m%s\033[0m]" % logging.getLevelName(logging.ERROR))
+
+ args = parser.parse_args()
+ logging.debug("Args: " + str(args))
+
+ # Set the working directory
+ global WORKING_DIR
+ WORKING_DIR = os.path.abspath(args.output)
+ logging.debug("Working Dir: " + WORKING_DIR)
+
+ # Print out the list of tests then exit
+ if args.list_tests:
+ list_tests()
+ sys.exit(0)
+
+ # Check to see if a test was specified and if so only generate coverage for
+ # that test.
+ if len(args.tests) == 0:
+ args.all = True
+
+ tests_to_run = []
+ for test in COVERAGE_TESTS:
+ if args.all or test['test_name'] in args.tests:
+ tests_to_run.append(test)
+ if test['test_name'] in args.tests:
+ args.tests.remove(test['test_name'])
+
+ # Error if a test was specified but doesn't exist.
+ if len(args.tests) != 0:
+ for test_name in args.tests:
+ logging.error('\"' + test_name + '\" was not found in the list of available tests.')
+ sys.exit(1)
+
+ # Generate the info for the tests
+ for test in tests_to_run:
+ logging.info('Getting coverage for ' + test['test_name'])
+ get_profraw_for_test(test['test_name'])
+ merge_profraw_data(test['test_name'])
+ if args.json_file:
+ write_json_summary(test)
+ generate_coverage_html(test)
+
+ # Generate the root index.html page that sumarizes all of the coverage reports.
+ generate_root_html(tests_to_run)
+
+ # Open the results in a browser.
+ if not args.skip_html:
+ webbrowser.open('file://' + os.path.join(WORKING_DIR, 'index.html'))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/rootcanal/Android.bp b/test/rootcanal/Android.bp
index 7371c99..e312c0e 100644
--- a/test/rootcanal/Android.bp
+++ b/test/rootcanal/Android.bp
@@ -45,7 +45,7 @@
"android.hardware.bluetooth-async",
"android.hardware.bluetooth-hci",
"libbt-rootcanal",
- "libbluetooth-types",
+ "libbt-rootcanal-types",
],
include_dirs: [
"system/bt",
@@ -82,10 +82,10 @@
"-DHAS_NO_BDROID_BUILDCFG",
],
static_libs: [
- "libbluetooth-types",
"android.hardware.bluetooth-async",
"android.hardware.bluetooth-hci",
"libbt-rootcanal",
+ "libbt-rootcanal-types",
],
include_dirs: [
"system/bt",
diff --git a/test/rootcanal/bluetooth_hci.cc b/test/rootcanal/bluetooth_hci.cc
index b0281a0..c8352da 100644
--- a/test/rootcanal/bluetooth_hci.cc
+++ b/test/rootcanal/bluetooth_hci.cc
@@ -19,13 +19,13 @@
#include "bluetooth_hci.h"
#include <base/logging.h>
+#include <cutils/properties.h>
+#include <netdb.h>
+#include <netinet/in.h>
#include <string.h>
#include <utils/Log.h>
-#include "acl_packet.h"
-#include "event_packet.h"
#include "hci_internals.h"
-#include "sco_packet.h"
namespace android {
namespace hardware {
@@ -34,37 +34,43 @@
namespace sim {
using android::hardware::hidl_vec;
-using test_vendor_lib::AclPacket;
-using test_vendor_lib::AsyncManager;
using test_vendor_lib::AsyncTaskId;
-using test_vendor_lib::CommandPacket;
using test_vendor_lib::DualModeController;
-using test_vendor_lib::EventPacket;
-using test_vendor_lib::ScoPacket;
using test_vendor_lib::TaskCallback;
-using test_vendor_lib::TestChannelTransport;
+
+namespace {
+
+bool BtTestConsoleEnabled() {
+ // Assume enabled by default.
+ return property_get_bool("bt.rootcanal_test_console", true);
+}
+
+} // namespace
class BluetoothDeathRecipient : public hidl_death_recipient {
public:
BluetoothDeathRecipient(const sp<IBluetoothHci> hci) : mHci(hci) {}
- virtual void serviceDied(
+ void serviceDied(
uint64_t /* cookie */,
- const wp<::android::hidl::base::V1_0::IBase>& /* who */) {
+ const wp<::android::hidl::base::V1_0::IBase>& /* who */) override {
ALOGE("BluetoothDeathRecipient::serviceDied - Bluetooth service died");
has_died_ = true;
mHci->close();
}
sp<IBluetoothHci> mHci;
- bool getHasDied() const { return has_died_; }
- void setHasDied(bool has_died) { has_died_ = has_died; }
+ bool getHasDied() const {
+ return has_died_;
+ }
+ void setHasDied(bool has_died) {
+ has_died_ = has_died;
+ }
private:
bool has_died_;
};
-BluetoothHci::BluetoothHci()
- : death_recipient_(new BluetoothDeathRecipient(this)) {}
+BluetoothHci::BluetoothHci() : death_recipient_(new BluetoothDeathRecipient(this)) {}
Return<void> BluetoothHci::initialize(const sp<IBluetoothHciCallbacks>& cb) {
ALOGI("%s", __func__);
@@ -75,71 +81,93 @@
}
death_recipient_->setHasDied(false);
- cb->linkToDeath(death_recipient_, 0);
+ auto link_ret = cb->linkToDeath(death_recipient_, 0);
+ CHECK(link_ret.isOk()) << "Error calling linkToDeath.";
test_channel_transport_.RegisterCommandHandler(
[this](const std::string& name, const std::vector<std::string>& args) {
async_manager_.ExecAsync(
- std::chrono::milliseconds(0), [this, name, args]() {
- controller_.HandleTestChannelCommand(name, args);
- });
+ std::chrono::milliseconds(0),
+ [this, name, args]() { test_channel_.HandleCommand(name, args); });
});
- controller_.RegisterEventChannel([cb](std::unique_ptr<EventPacket> event) {
- size_t header_bytes = event->GetHeaderSize();
- size_t payload_bytes = event->GetPayloadSize();
- hidl_vec<uint8_t> hci_event;
- hci_event.resize(header_bytes + payload_bytes);
- memcpy(hci_event.data(), event->GetHeader().data(), header_bytes);
- memcpy(hci_event.data() + header_bytes, event->GetPayload().data(),
- payload_bytes);
+ controller_ = std::make_shared<DualModeController>();
- cb->hciEventReceived(hci_event);
- });
+ controller_->Initialize({"dmc", "3C:5A:B4:01:02:03"});
- controller_.RegisterAclChannel([cb](std::unique_ptr<AclPacket> packet) {
- std::vector<uint8_t> acl_vector = packet->GetPacket();
- hidl_vec<uint8_t> acl_packet = acl_vector;
+ controller_->RegisterEventChannel(
+ [this, cb](std::shared_ptr<std::vector<uint8_t>> packet) {
+ hidl_vec<uint8_t> hci_event(packet->begin(), packet->end());
+ auto ret = cb->hciEventReceived(hci_event);
+ if (!ret.isOk()) {
+ CHECK(death_recipient_->getHasDied())
+ << "Error sending event callback, but no death notification.";
+ }
+ });
- cb->aclDataReceived(acl_packet);
- });
+ controller_->RegisterAclChannel(
+ [this, cb](std::shared_ptr<std::vector<uint8_t>> packet) {
+ hidl_vec<uint8_t> acl_packet(packet->begin(), packet->end());
+ auto ret = cb->aclDataReceived(acl_packet);
+ if (!ret.isOk()) {
+ CHECK(death_recipient_->getHasDied())
+ << "Error sending acl callback, but no death notification.";
+ }
+ });
- controller_.RegisterScoChannel([cb](std::unique_ptr<ScoPacket> packet) {
- size_t header_bytes = packet->GetHeaderSize();
- size_t payload_bytes = packet->GetPayloadSize();
- hidl_vec<uint8_t> sco_packet;
- sco_packet.resize(header_bytes + payload_bytes);
- memcpy(sco_packet.data(), packet->GetHeader().data(), header_bytes);
- memcpy(sco_packet.data() + header_bytes, packet->GetPayload().data(),
- payload_bytes);
+ controller_->RegisterScoChannel(
+ [this, cb](std::shared_ptr<std::vector<uint8_t>> packet) {
+ hidl_vec<uint8_t> sco_packet(packet->begin(), packet->end());
+ auto ret = cb->aclDataReceived(sco_packet);
+ if (!ret.isOk()) {
+ CHECK(death_recipient_->getHasDied())
+ << "Error sending sco callback, but no death notification.";
+ }
+ });
- cb->scoDataReceived(sco_packet);
- });
-
- controller_.RegisterTaskScheduler(
+ controller_->RegisterTaskScheduler(
[this](std::chrono::milliseconds delay, const TaskCallback& task) {
return async_manager_.ExecAsync(delay, task);
});
- controller_.RegisterPeriodicTaskScheduler(
+ controller_->RegisterPeriodicTaskScheduler(
[this](std::chrono::milliseconds delay, std::chrono::milliseconds period,
const TaskCallback& task) {
return async_manager_.ExecAsyncPeriodically(delay, period, task);
});
- controller_.RegisterTaskCancel(
+ controller_->RegisterTaskCancel(
[this](AsyncTaskId task) { async_manager_.CancelAsyncTask(task); });
- SetUpTestChannel(6111);
+ test_model_.Reset();
+ // Add the controller as a device in the model.
+ test_model_.Add(controller_);
- unlink_cb_ = [cb](sp<BluetoothDeathRecipient>& death_recipient) {
+ if (BtTestConsoleEnabled()) {
+ SetUpTestChannel(6111);
+ SetUpHciServer(6211,
+ [this](int fd) { test_model_.IncomingHciConnection(fd); });
+ SetUpLinkLayerServer(
+ 6311, [this](int fd) { test_model_.IncomingLinkLayerConnection(fd); });
+ }
+
+ unlink_cb_ = [this, cb](sp<BluetoothDeathRecipient>& death_recipient) {
if (death_recipient->getHasDied())
ALOGI("Skipping unlink call, service died.");
- else
- cb->unlinkToDeath(death_recipient);
+ else {
+ auto ret = cb->unlinkToDeath(death_recipient);
+ if (!ret.isOk()) {
+ CHECK(death_recipient_->getHasDied())
+ << "Error calling unlink, but no death notification.";
+ }
+ }
};
- cb->initializationComplete(Status::SUCCESS);
+ auto init_ret = cb->initializationComplete(Status::SUCCESS);
+ if (!init_ret.isOk()) {
+ CHECK(death_recipient_->getHasDied())
+ << "Error sending init callback, but no death notification.";
+ }
return Void();
}
@@ -150,53 +178,131 @@
Return<void> BluetoothHci::sendHciCommand(const hidl_vec<uint8_t>& packet) {
async_manager_.ExecAsync(std::chrono::milliseconds(0), [this, packet]() {
- uint16_t opcode = packet[0] | (packet[1] << 8);
- std::unique_ptr<CommandPacket> command =
- std::unique_ptr<CommandPacket>(new CommandPacket(opcode));
- for (size_t i = 3; i < packet.size(); i++)
- command->AddPayloadOctets1(packet[i]);
-
- controller_.HandleCommand(std::move(command));
+ std::shared_ptr<std::vector<uint8_t>> packet_copy =
+ std::shared_ptr<std::vector<uint8_t>>(new std::vector<uint8_t>(packet));
+ controller_->HandleCommand(packet_copy);
});
return Void();
}
Return<void> BluetoothHci::sendAclData(const hidl_vec<uint8_t>& packet) {
async_manager_.ExecAsync(std::chrono::milliseconds(0), [this, packet]() {
- uint16_t channel = (packet[0] | (packet[1] << 8)) & 0xfff;
- AclPacket::PacketBoundaryFlags boundary_flags =
- static_cast<AclPacket::PacketBoundaryFlags>((packet[1] & 0x30) >> 4);
- AclPacket::BroadcastFlags broadcast_flags =
- static_cast<AclPacket::BroadcastFlags>((packet[1] & 0xC0) >> 6);
-
- std::unique_ptr<AclPacket> acl = std::unique_ptr<AclPacket>(
- new AclPacket(channel, boundary_flags, broadcast_flags));
- for (size_t i = 4; i < packet.size(); i++)
- acl->AddPayloadOctets1(packet[i]);
-
- controller_.HandleAcl(std::move(acl));
+ std::shared_ptr<std::vector<uint8_t>> packet_copy =
+ std::shared_ptr<std::vector<uint8_t>>(new std::vector<uint8_t>(packet));
+ controller_->HandleAcl(packet_copy);
});
return Void();
}
Return<void> BluetoothHci::sendScoData(const hidl_vec<uint8_t>& packet) {
async_manager_.ExecAsync(std::chrono::milliseconds(0), [this, packet]() {
- uint16_t channel = (packet[0] | (packet[1] << 8)) & 0xfff;
- ScoPacket::PacketStatusFlags packet_status =
- static_cast<ScoPacket::PacketStatusFlags>((packet[1] & 0x30) >> 4);
- std::unique_ptr<ScoPacket> sco =
- std::unique_ptr<ScoPacket>(new ScoPacket(channel, packet_status));
- for (size_t i = 3; i < packet.size(); i++)
- sco->AddPayloadOctets1(packet[i]);
-
- controller_.HandleSco(std::move(sco));
+ std::shared_ptr<std::vector<uint8_t>> packet_copy =
+ std::shared_ptr<std::vector<uint8_t>>(new std::vector<uint8_t>(packet));
+ controller_->HandleSco(packet_copy);
});
return Void();
}
+void BluetoothHci::SetUpHciServer(int port, const std::function<void(int)>& connection_callback) {
+ int socket_fd = remote_hci_transport_.SetUp(port);
+
+ test_channel_.RegisterSendResponse(
+ [](const std::string& response) { ALOGI("No HCI Response channel: %s", response.c_str()); });
+
+ if (socket_fd == -1) {
+ ALOGE("Remote HCI channel SetUp(%d) failed.", port);
+ return;
+ }
+
+ async_manager_.WatchFdForNonBlockingReads(socket_fd, [this, connection_callback](int socket_fd) {
+ int conn_fd = remote_hci_transport_.Accept(socket_fd);
+ if (conn_fd < 0) {
+ ALOGE("Error watching remote HCI channel fd.");
+ return;
+ }
+ int flags = fcntl(conn_fd, F_GETFL, NULL);
+ int ret;
+ ret = fcntl(conn_fd, F_SETFL, flags | O_NONBLOCK);
+ CHECK(ret != -1) << "Error setting O_NONBLOCK " << strerror(errno);
+
+ connection_callback(conn_fd);
+ });
+}
+
+void BluetoothHci::SetUpLinkLayerServer(int port, const std::function<void(int)>& connection_callback) {
+ int socket_fd = remote_link_layer_transport_.SetUp(port);
+
+ test_channel_.RegisterSendResponse(
+ [](const std::string& response) { ALOGI("No LinkLayer Response channel: %s", response.c_str()); });
+
+ if (socket_fd == -1) {
+ ALOGE("Remote LinkLayer channel SetUp(%d) failed.", port);
+ return;
+ }
+
+ async_manager_.WatchFdForNonBlockingReads(socket_fd, [this, connection_callback](int socket_fd) {
+ int conn_fd = remote_link_layer_transport_.Accept(socket_fd);
+ if (conn_fd < 0) {
+ ALOGE("Error watching remote LinkLayer channel fd.");
+ return;
+ }
+ int flags = fcntl(conn_fd, F_GETFL, NULL);
+ int ret = fcntl(conn_fd, F_SETFL, flags | O_NONBLOCK);
+ CHECK(ret != -1) << "Error setting O_NONBLOCK " << strerror(errno);
+
+ connection_callback(conn_fd);
+ });
+}
+
+int BluetoothHci::ConnectToRemoteServer(const std::string& server, int port) {
+ int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (socket_fd < 1) {
+ ALOGI("socket() call failed: %s", strerror(errno));
+ return -1;
+ }
+
+ struct hostent* host;
+ host = gethostbyname(server.c_str());
+ if (host == NULL) {
+ ALOGI("gethostbyname() failed for %s: %s", server.c_str(), strerror(errno));
+ return -1;
+ }
+
+ struct sockaddr_in serv_addr;
+ memset((void*)&serv_addr, 0, sizeof(serv_addr));
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_addr.s_addr = INADDR_ANY;
+ serv_addr.sin_port = htons(port);
+
+ int result = connect(socket_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
+ if (result < 0) {
+ ALOGI("connect() failed for %s@%d: %s", server.c_str(), port, strerror(errno));
+ return -1;
+ }
+
+ int flags = fcntl(socket_fd, F_GETFL, NULL);
+ int ret = fcntl(socket_fd, F_SETFL, flags | O_NONBLOCK);
+ CHECK(ret != -1) << "Error setting O_NONBLOCK " << strerror(errno);
+
+ return socket_fd;
+}
+
void BluetoothHci::SetUpTestChannel(int port) {
int socket_fd = test_channel_transport_.SetUp(port);
+ test_channel_.RegisterSendResponse(
+ [](const std::string& response) { ALOGI("No test channel: %s", response.c_str()); });
+
+ // Add some default devices for easier debugging
+ test_channel_.AddDefaults();
+
+ // This should be configurable in the future.
+ ALOGI("Adding Beacons so the scan list is not empty.");
+ test_channel_.Add({"beacon", "be:ac:10:00:00:01", "1000"});
+ test_channel_.AddDeviceToPhy({"1", "0"});
+ test_channel_.Add({"beacon", "be:ac:10:00:00:02", "1000"});
+ test_channel_.AddDeviceToPhy({"2", "0"});
+
if (socket_fd == -1) {
ALOGE("Test channel SetUp(%d) failed.", port);
return;
@@ -210,10 +316,12 @@
return;
}
ALOGI("Test channel connection accepted.");
+ test_channel_.RegisterSendResponse(
+ [this, conn_fd](const std::string& response) { test_channel_transport_.SendResponse(conn_fd, response); });
+
async_manager_.WatchFdForNonBlockingReads(conn_fd, [this](int conn_fd) {
- test_channel_transport_.OnCommandReady(conn_fd, [this, conn_fd]() {
- async_manager_.StopWatchingFileDescriptor(conn_fd);
- });
+ test_channel_transport_.OnCommandReady(conn_fd,
+ [this, conn_fd]() { async_manager_.StopWatchingFileDescriptor(conn_fd); });
});
});
}
@@ -223,7 +331,7 @@
return new BluetoothHci();
}
-} // namespace gce
+} // namespace sim
} // namespace V1_0
} // namespace bluetooth
} // namespace hardware
diff --git a/test/rootcanal/bluetooth_hci.h b/test/rootcanal/bluetooth_hci.h
index 05ec206..96d0ed8 100644
--- a/test/rootcanal/bluetooth_hci.h
+++ b/test/rootcanal/bluetooth_hci.h
@@ -22,9 +22,11 @@
#include "hci_packetizer.h"
-#include "async_manager.h"
-#include "dual_mode_controller.h"
-#include "test_channel_transport.h"
+#include "model/controller/dual_mode_controller.h"
+#include "model/setup/async_manager.h"
+#include "model/setup/test_channel_transport.h"
+#include "model/setup/test_command_handler.h"
+#include "model/setup/test_model.h"
namespace android {
namespace hardware {
@@ -38,17 +40,13 @@
public:
BluetoothHci();
- ::android::hardware::Return<void> initialize(
- const sp<IBluetoothHciCallbacks>& cb) override;
+ ::android::hardware::Return<void> initialize(const sp<IBluetoothHciCallbacks>& cb) override;
- ::android::hardware::Return<void> sendHciCommand(
- const ::android::hardware::hidl_vec<uint8_t>& packet) override;
+ ::android::hardware::Return<void> sendHciCommand(const ::android::hardware::hidl_vec<uint8_t>& packet) override;
- ::android::hardware::Return<void> sendAclData(
- const ::android::hardware::hidl_vec<uint8_t>& packet) override;
+ ::android::hardware::Return<void> sendAclData(const ::android::hardware::hidl_vec<uint8_t>& packet) override;
- ::android::hardware::Return<void> sendScoData(
- const ::android::hardware::hidl_vec<uint8_t>& packet) override;
+ ::android::hardware::Return<void> sendScoData(const ::android::hardware::hidl_vec<uint8_t>& packet) override;
::android::hardware::Return<void> close() override;
@@ -66,10 +64,31 @@
test_vendor_lib::AsyncManager async_manager_;
void SetUpTestChannel(int port);
+ void SetUpHciServer(int port, const std::function<void(int)>& on_connect);
+ void SetUpLinkLayerServer(int port, const std::function<void(int)>& on_connect);
+ int ConnectToRemoteServer(const std::string& server, int port);
- test_vendor_lib::DualModeController controller_;
+ std::shared_ptr<test_vendor_lib::DualModeController> controller_;
test_vendor_lib::TestChannelTransport test_channel_transport_;
+ test_vendor_lib::TestChannelTransport remote_hci_transport_;
+ test_vendor_lib::TestChannelTransport remote_link_layer_transport_;
+
+ test_vendor_lib::TestModel test_model_{
+ [this](std::chrono::milliseconds delay, const test_vendor_lib::TaskCallback& task) {
+ return async_manager_.ExecAsync(delay, task);
+ },
+
+ [this](std::chrono::milliseconds delay, std::chrono::milliseconds period,
+ const test_vendor_lib::TaskCallback& task) {
+ return async_manager_.ExecAsyncPeriodically(delay, period, task);
+ },
+
+ [this](test_vendor_lib::AsyncTaskId task) { async_manager_.CancelAsyncTask(task); },
+
+ [this](const std::string& server, int port) { return ConnectToRemoteServer(server, port); }};
+
+ test_vendor_lib::TestCommandHandler test_channel_{test_model_};
};
extern "C" IBluetoothHci* HIDL_FETCH_IBluetoothHci(const char* name);
diff --git a/test/rootcanal/service.cc b/test/rootcanal/service.cc
index e08f735..64fa9c7 100644
--- a/test/rootcanal/service.cc
+++ b/test/rootcanal/service.cc
@@ -23,11 +23,11 @@
#include "bluetooth_hci.h"
+using ::android::sp;
using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::joinRpcThreadpool;
using ::android::hardware::bluetooth::V1_0::IBluetoothHci;
using ::android::hardware::bluetooth::V1_0::sim::BluetoothHci;
-using ::android::hardware::joinRpcThreadpool;
-using ::android::sp;
int main(int /* argc */, char** /* argv */) {
sp<IBluetoothHci> bluetooth = new BluetoothHci;
diff --git a/test/run_benchmarks.sh b/test/run_benchmarks.sh
new file mode 100755
index 0000000..af4b012
--- /dev/null
+++ b/test/run_benchmarks.sh
@@ -0,0 +1,129 @@
+#!/bin/sh
+# A utility script that runs benchmark on Android device
+#
+# Note: Only one Android device can be connected when running this script
+#
+# Example usage:
+# $ cd system/bt
+# $ ./test/run_benchmarks.sh bluetooth_benchmark_example
+
+known_benchmarks=(
+ bluetooth_benchmark_thread_performance
+ bluetooth_benchmark_timer_performance
+)
+
+usage() {
+ binary="$(basename "$0")"
+ echo "Usage: ${binary} --help"
+ echo " ${binary} [-i <iterations>] [-s <specific device>] [--all] [<benchmark name>[.<filter>] ...] [--<arg> ...]"
+ echo
+ echo "Unknown long arguments are passed to the benchmark."
+ echo
+ echo "Known benchmark names:"
+
+ for name in "${known_benchmarks[@]}"
+ do
+ echo " ${name}"
+ done
+}
+
+iterations=1
+device=
+benchmarks=()
+benchmark_args=()
+while [ $# -gt 0 ]
+do
+ case "$1" in
+ -h|--help)
+ usage
+ exit 0
+ ;;
+ -i)
+ shift
+ if [ $# -eq 0 ]; then
+ echo "error: number of iterations expected" 1>&2
+ usage
+ exit 2
+ fi
+ iterations=$(( $1 ))
+ shift
+ ;;
+ -s)
+ shift
+ if [ $# -eq 0 ]; then
+ echo "error: no device specified" 1>&2
+ usage
+ exit 2
+ fi
+ device="$1"
+ shift
+ ;;
+ --all)
+ benchmarks+=( "${known_benchmarks[@]}" )
+ shift
+ ;;
+ --*)
+ benchmark_args+=( "$1" )
+ shift
+ ;;
+ *)
+ benchmarks+=( "$1" )
+ shift
+ ;;
+ esac
+done
+
+if [ "${#benchmarks[@]}" -eq 0 ]; then
+ benchmarks+=( "${known_benchmarks[@]}" )
+fi
+
+adb=( "adb" )
+if [ -n "${device}" ]; then
+ adb+=( "-s" "${device}" )
+fi
+
+source ${ANDROID_BUILD_TOP}/build/envsetup.sh
+target_arch=$(gettargetarch)
+
+failed_benchmarks=()
+for spec in "${benchmarks[@]}"
+do
+ name="${spec%%.*}"
+ if [[ $target_arch == *"64"* ]]; then
+ binary="/data/benchmarktest64/${name}/${name}"
+ else
+ binary="/data/benchmarktest/${name}/${name}"
+ fi
+
+ push_command=( "${adb[@]}" push {"${ANDROID_PRODUCT_OUT}",}"${binary}" )
+ benchmark_command=( "${adb[@]}" shell "${binary}" )
+ if [ "${name}" != "${spec}" ]; then
+ filter="${spec#*.}"
+ benchmark_command+=( "--benchmark_filter=${filter}" )
+ fi
+ benchmark_command+=( "${benchmark_args[@]}" )
+
+ echo "--- ${name} ---"
+ echo "pushing..."
+ "${push_command[@]}"
+ echo "running..."
+ failed_count=0
+ for i in $(seq 1 ${iterations})
+ do
+ "${benchmark_command[@]}" || failed_count=$(( $failed_count + 1 ))
+ done
+
+ if [ $failed_count != 0 ]; then
+ failed_benchmarks+=( "${name} ${failed_count}/${iterations}" )
+ fi
+done
+
+if [ "${#failed_benchmarks[@]}" -ne 0 ]; then
+ for failed_benchmark in "${failed_benchmarks[@]}"
+ do
+ echo "!!! FAILED TEST: ${failed_benchmark} !!!"
+ done
+ exit 1
+fi
+
+exit 0
diff --git a/test/run_host_unit_tests.py b/test/run_host_unit_tests.py
index a99140e..3d3f1c7 100755
--- a/test/run_host_unit_tests.py
+++ b/test/run_host_unit_tests.py
@@ -21,9 +21,9 @@
# Registered host based unit tests
# Must have 'host_supported: true'
HOST_TESTS = [
+ 'bluetooth_test_common',
'bluetoothtbd_test',
'net_test_avrcp',
- 'net_test_btif_state_machine',
'net_test_btcore',
'net_test_types',
'net_test_btpackets',
@@ -200,6 +200,20 @@
print 'TEST FAILLED: ' + HOST_TESTS[index]
sys.exit(0)
print 'TEST PASSED ' + str(len(test_results)) + ' tests were run'
+
+ dist_dir = get_android_dist_dir_or_die()
+ log_output_path = os.path.join(dist_dir, 'gtest/coverage')
+ cmd_path = os.path.join(get_android_root_or_die(), 'system/bt/test')
+ print cmd_path
+ cmd = [
+ os.path.join(cmd_path, 'gen_coverage.py'),
+ '--skip-html',
+ '--json-file',
+ '-o',
+ log_output_path,
+ ]
+ subprocess.call(cmd)
+
sys.exit(0)
diff --git a/test/run_unit_tests.sh b/test/run_unit_tests.sh
index 066e8e1..8041afc 100755
--- a/test/run_unit_tests.sh
+++ b/test/run_unit_tests.sh
@@ -1,6 +1,9 @@
#!/bin/sh
known_tests=(
+ audio_bluetooth_hw_test
+ bluetooth-test-audio-hal-interface
+ bluetooth_test_common
bluetoothtbd_test
net_test_audio_a2dp_hw
net_test_avrcp
@@ -9,7 +12,6 @@
net_test_bta
net_test_btif
net_test_btif_profile_queue
- net_test_btif_state_machine
net_test_device
net_test_hci
net_test_stack
@@ -21,6 +23,7 @@
net_test_osi
net_test_performance
net_test_stack_rfcomm
+ net_test_gatt_conn_multiplexing
)
known_remote_tests=(
diff --git a/test/suite/Android.bp b/test/suite/Android.bp
index ed5b531..85b46fa 100644
--- a/test/suite/Android.bp
+++ b/test/suite/Android.bp
@@ -36,7 +36,7 @@
"rfcomm/rfcomm_test.cc",
"rfcomm/rfcomm_unittest.cc",
],
- header_libs: [ "libhardware_headers" ],
+ header_libs: ["libhardware_headers"],
shared_libs: [
"liblog",
"libcutils",
@@ -49,21 +49,3 @@
"libbluetoothtbd_hal",
],
}
-
-// Bluetooth test suite for target
-// ========================================================
-cc_test {
- name: "net_test_performance",
- defaults: ["fluoride_defaults"],
- include_dirs: ["system/bt"],
- srcs: [
- "core/thread_performance_test.cc",
- ],
- shared_libs: [
- "liblog",
- ],
- static_libs: [
- "libgmock",
- "libosi",
- ],
-}
diff --git a/test/suite/AndroidTest.xml b/test/suite/AndroidTest.xml
deleted file mode 100644
index d7778e1..0000000
--- a/test/suite/AndroidTest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2017 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.
--->
-<configuration description="Config for net_test_bluetooth">
- <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
- <option name="cleanup" value="true" />
- <option name="push" value="net_test_bluetooth->/data/local/tmp/net_test_bluetooth" />
- </target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <option name="run-command" value="stop" />
- </target_preparer>
- <option name="test-suite-tag" value="apct" />
- <test class="com.android.tradefed.testtype.GTest" >
- <option name="native-test-device-path" value="/data/local/tmp" />
- <option name="module-name" value="net_test_bluetooth" />
- </test>
-</configuration>
diff --git a/test/suite/core/thread_performance_test.cc b/test/suite/core/thread_performance_test.cc
deleted file mode 100644
index b3f7461..0000000
--- a/test/suite/core/thread_performance_test.cc
+++ /dev/null
@@ -1,130 +0,0 @@
-#include <base/bind.h>
-#include <base/logging.h>
-#include <base/run_loop.h>
-#include <base/threading/thread.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <unistd.h>
-#include <chrono>
-#include <iostream>
-
-#include "osi/include/fixed_queue.h"
-#include "osi/include/thread.h"
-
-#define NUM_MESSAGES_TO_SEND 1000000
-
-base::MessageLoop* message_loop;
-base::RunLoop* run_loop;
-thread_t* thread;
-
-volatile static int counter = 0;
-volatile bool loop_ready = false;
-
-void set_loop_ready() { loop_ready = true; }
-
-void callback(fixed_queue_t* queue, void* data) {
- if (queue != nullptr) {
- fixed_queue_dequeue(queue);
- }
-
- counter++;
-}
-
-void run_message_loop(void* UNUSED) {
- message_loop = new base::MessageLoop();
- run_loop = new base::RunLoop();
-
- message_loop->task_runner()->PostTask(FROM_HERE, base::Bind(&set_loop_ready));
-
- run_loop->Run();
-
- delete message_loop;
- message_loop = nullptr;
-
- delete run_loop;
- run_loop = nullptr;
-}
-
-class PerformanceTest : public testing::Test {
- public:
- fixed_queue_t* bt_msg_queue;
-
- void SetUp() override {
- counter = 0;
-
- bt_msg_queue = fixed_queue_new(SIZE_MAX);
- thread = thread_new("performance test thread");
- thread_post(thread, run_message_loop, nullptr);
- }
-
- void TearDown() override {
- fixed_queue_free(bt_msg_queue, NULL);
- bt_msg_queue = nullptr;
-
- thread_free(thread);
- thread = nullptr;
- }
-};
-
-TEST_F(PerformanceTest, message_loop_speed_test) {
- loop_ready = false;
- int test_data = 0;
-
- std::chrono::steady_clock::time_point start_time =
- std::chrono::steady_clock::now();
- while (!loop_ready) {
- }
- for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
- fixed_queue_enqueue(bt_msg_queue, (void*)&test_data);
- message_loop->task_runner()->PostTask(
- FROM_HERE, base::Bind(&callback, bt_msg_queue, nullptr));
- }
-
- message_loop->task_runner()->PostTask(FROM_HERE,
- run_loop->QuitWhenIdleClosure());
- while (counter < NUM_MESSAGES_TO_SEND) {
- }
-
- std::chrono::steady_clock::time_point end_time =
- std::chrono::steady_clock::now();
- std::chrono::milliseconds duration =
- std::chrono::duration_cast<std::chrono::milliseconds>(end_time -
- start_time);
-
- LOG(INFO) << "Message loop took " << duration.count() << "ms for "
- << NUM_MESSAGES_TO_SEND << " messages";
-}
-
-TEST_F(PerformanceTest, reactor_thread_speed_test) {
- counter = 0;
- int test_data = 0;
-
- thread = thread_new("queue performance test thread");
- bt_msg_queue = fixed_queue_new(SIZE_MAX);
- fixed_queue_register_dequeue(bt_msg_queue, thread_get_reactor(thread),
- callback, NULL);
-
- std::chrono::steady_clock::time_point start_time =
- std::chrono::steady_clock::now();
- for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
- fixed_queue_enqueue(bt_msg_queue, (void*)&test_data);
- }
-
- while (counter < NUM_MESSAGES_TO_SEND) {
- };
-
- std::chrono::steady_clock::time_point end_time =
- std::chrono::steady_clock::now();
- std::chrono::milliseconds duration =
- std::chrono::duration_cast<std::chrono::milliseconds>(end_time -
- start_time);
-
- LOG(INFO) << "Reactor thread took " << duration.count() << "ms for "
- << NUM_MESSAGES_TO_SEND << " messages";
-
- fixed_queue_free(bt_msg_queue, NULL);
- bt_msg_queue = nullptr;
-
- thread_free(thread);
- thread = nullptr;
-}
diff --git a/tools/Android.bp b/tools/Android.bp
deleted file mode 100644
index 9f75ba7..0000000
--- a/tools/Android.bp
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright 2017 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.
- */
-subdirs = [
- "mcap_tool",
-]
diff --git a/tools/mcap_tool/Android.bp b/tools/mcap_tool/Android.bp
deleted file mode 100644
index eec750c..0000000
--- a/tools/mcap_tool/Android.bp
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2017 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.
- */
-cc_binary {
- name: "mcap_tool",
- defaults : ["fluoride_defaults"],
- srcs: [
- "mcap_test_app.cc",
- "mcap_test_mcl.cc",
- "mcap_test_mdep.cc",
- "mcap_test_mdl.cc",
- "mcap_tool.cc",
- ],
- include_dirs: [
- "system/bt",
- "system/bt/internal_include",
- "system/bt/stack/include",
- "system/bt/btcore/include",
- ],
- tags: ["debug", "optional"],
- shared_libs: [
- "libcutils",
- "libutils",
- ],
- static_libs: [
- "libbtcore",
- "libosi",
- ]
-}
diff --git a/tools/mcap_tool/BUILD.gn b/tools/mcap_tool/BUILD.gn
deleted file mode 100644
index d41ed56..0000000
--- a/tools/mcap_tool/BUILD.gn
+++ /dev/null
@@ -1,44 +0,0 @@
-#
-# Copyright 2017 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.
-#
-executable("mcap_tool") {
- testonly = true
- sources = [
- "mcap_tool.cc",
- "mcap_test_app.cc",
- "mcap_test_mcl.cc",
- "mcap_test_mdep.cc",
- "mcap_test_mdl.cc",
- ]
- include_dirs = [
- "//",
- "//internal_include",
- "//stack/include",
- "//btif/include",
- "//btcore/include",
- "//tools/mcap_tool",
- ]
- libs = [
- "-lpthread",
- "-lrt",
- "-ldl",
- ]
- deps = [
- "//btcore",
- "//osi",
- "//third_party/libchrome:base",
- "//types",
- ]
-}
diff --git a/tools/mcap_tool/mcap_test_app.cc b/tools/mcap_tool/mcap_test_app.cc
deleted file mode 100644
index 9515f20..0000000
--- a/tools/mcap_tool/mcap_test_app.cc
+++ /dev/null
@@ -1,536 +0,0 @@
-/*
- * Copyright 2017 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 "mcap_test_app.h"
-#include "mca_defs.h"
-
-namespace SYSTEM_BT_TOOLS_MCAP_TOOL {
-
-#define CASE_RETURN_STR(const) \
- case const: \
- return #const;
-
-static const char* dump_mcap_events(const uint8_t event) {
- switch (event) {
- CASE_RETURN_STR(MCA_ERROR_RSP_EVT)
- CASE_RETURN_STR(MCA_CREATE_IND_EVT)
- CASE_RETURN_STR(MCA_CREATE_CFM_EVT)
- CASE_RETURN_STR(MCA_RECONNECT_IND_EVT)
- CASE_RETURN_STR(MCA_RECONNECT_CFM_EVT)
- CASE_RETURN_STR(MCA_ABORT_IND_EVT)
- CASE_RETURN_STR(MCA_ABORT_CFM_EVT)
- CASE_RETURN_STR(MCA_DELETE_IND_EVT)
- CASE_RETURN_STR(MCA_DELETE_CFM_EVT)
- CASE_RETURN_STR(MCA_SYNC_CAP_IND_EVT)
- CASE_RETURN_STR(MCA_SYNC_CAP_CFM_EVT)
- CASE_RETURN_STR(MCA_SYNC_SET_IND_EVT)
- CASE_RETURN_STR(MCA_SYNC_SET_CFM_EVT)
- CASE_RETURN_STR(MCA_SYNC_INFO_IND_EVT)
- CASE_RETURN_STR(MCA_CONNECT_IND_EVT)
- CASE_RETURN_STR(MCA_DISCONNECT_IND_EVT)
- CASE_RETURN_STR(MCA_OPEN_IND_EVT)
- CASE_RETURN_STR(MCA_OPEN_CFM_EVT)
- CASE_RETURN_STR(MCA_CLOSE_IND_EVT)
- CASE_RETURN_STR(MCA_CLOSE_CFM_EVT)
- CASE_RETURN_STR(MCA_CONG_CHG_EVT)
- CASE_RETURN_STR(MCA_RSP_TOUT_IND_EVT)
- default:
- return "Unknown event";
- }
-}
-
-static void print_mcap_event(const tMCA_DISCONNECT_IND* mcap_disconnect_ind) {
- printf("%s: peer_bd_addr=%s,l2cap_disconnect_reason=0x%04x\n", __func__,
- mcap_disconnect_ind->bd_addr.ToString().c_str(),
- mcap_disconnect_ind->reason);
-}
-
-static void print_mcap_event(const tMCA_CONNECT_IND* mcap_connect_ind) {
- printf("%s: peer_bd_addr=%s, peer_mtu=%d \n", __func__,
- mcap_connect_ind->bd_addr.ToString().c_str(), mcap_connect_ind->mtu);
-}
-
-static void print_mcap_event(const tMCA_RSP_EVT* mcap_rsp) {
- printf("%s: response, mdl_id=%d, op_code=0x%02x, rsp_code=0x%02x\n", __func__,
- mcap_rsp->mdl_id, mcap_rsp->op_code, mcap_rsp->rsp_code);
-}
-
-static void print_mcap_event(const tMCA_EVT_HDR* mcap_evt_hdr) {
- printf("%s: event, mdl_id=%d, op_code=0x%02x\n", __func__,
- mcap_evt_hdr->mdl_id, mcap_evt_hdr->op_code);
-}
-
-static void print_mcap_event(const tMCA_CREATE_IND* mcap_create_ind) {
- printf("%s: mdl_id=%d, op_code=0x%02x, dep_id=%d, cfg=0x%02x\n", __func__,
- mcap_create_ind->mdl_id, mcap_create_ind->op_code,
- mcap_create_ind->dep_id, mcap_create_ind->cfg);
-}
-
-static void print_mcap_event(const tMCA_CREATE_CFM* mcap_create_cfm) {
- printf("%s: mdl_id=%d, op_code=0x%02x, rsp_code=%d, cfg=0x%02x\n", __func__,
- mcap_create_cfm->mdl_id, mcap_create_cfm->op_code,
- mcap_create_cfm->rsp_code, mcap_create_cfm->cfg);
-}
-
-static void print_mcap_event(const tMCA_DL_OPEN* mcap_dl_open) {
- printf("%s: mdl_id=%d, mdl_handle=%d, mtu=%d\n", __func__,
- mcap_dl_open->mdl_id, mcap_dl_open->mdl, mcap_dl_open->mtu);
-}
-
-static void print_mcap_event(const tMCA_DL_CLOSE* mcap_dl_close) {
- printf("%s: mdl_id=%d, mdl_handle=%d, l2cap_disconnect_reason=0x%04x\n",
- __func__, mcap_dl_close->mdl_id, mcap_dl_close->mdl,
- mcap_dl_close->reason);
-}
-
-static void print_mcap_event(const tMCA_CONG_CHG* mcap_congestion_change) {
- printf("%s: mdl_id=%d, mdl_handle=%d, congested=%d\n", __func__,
- mcap_congestion_change->mdl_id, mcap_congestion_change->mdl,
- mcap_congestion_change->cong);
-}
-
-McapTestApp::McapTestApp(btmcap_test_interface_t* mcap_test_interface)
- : _mcl_list(), _mdep_list() {
- _mcap_test_interface = mcap_test_interface;
-}
-
-btmcap_test_interface_t* McapTestApp::GetInterface() {
- return _mcap_test_interface;
-}
-
-bool McapTestApp::Register(uint16_t ctrl_psm, uint16_t data_psm,
- uint16_t sec_mask, tMCA_CTRL_CBACK* callback) {
- if (!callback) {
- LOG(ERROR) << "callback is null";
- return false;
- }
- _mca_reg.rsp_tout = 5000;
- _mca_reg.ctrl_psm = ctrl_psm;
- _mca_reg.data_psm = data_psm;
- _mca_reg.sec_mask = sec_mask;
- _mcap_handle =
- _mcap_test_interface->register_application(&_mca_reg, callback);
- return _mcap_handle > 0;
-}
-
-void McapTestApp::Deregister() {
- _mcap_test_interface->deregister_application(_mcap_handle);
- _mcap_handle = 0;
-}
-
-bool McapTestApp::Registered() { return _mcap_handle > 0; }
-
-bool McapTestApp::ConnectMcl(const RawAddress& bd_addr, uint16_t ctrl_psm,
- uint16_t sec_mask) {
- if (!Registered()) {
- LOG(ERROR) << "Application not registered";
- return false;
- }
- McapMcl* mcap_mcl = FindMclByPeerAddress(bd_addr);
- if (!mcap_mcl) {
- LOG(INFO) << "MCL does not exist, creating new MCL";
- _mcl_list.push_back(McapMcl(_mcap_test_interface, _mcap_handle, bd_addr));
- mcap_mcl = &_mcl_list[_mcl_list.size() - 1];
- }
- if (mcap_mcl->GetHandle() != 0) {
- LOG(ERROR) << "MCL is still active, cannot make another connection";
- return false;
- }
- return mcap_mcl->Connect(ctrl_psm, sec_mask);
-}
-
-bool McapTestApp::CreateMdep(uint8_t type, uint8_t max_mdl,
- tMCA_DATA_CBACK* data_callback) {
- if (!data_callback) {
- LOG(ERROR) << "Data callback is null";
- return false;
- }
- _mdep_list.push_back(McapMdep(_mcap_test_interface, _mcap_handle, type,
- max_mdl, data_callback));
- return _mdep_list[_mdep_list.size() - 1].Create();
-}
-
-uint8_t McapTestApp::GetHandle() { return _mcap_handle; }
-
-McapMcl* McapTestApp::FindMclByPeerAddress(const RawAddress& bd_addr) {
- for (McapMcl& mcl : _mcl_list) {
- if (mcl.GetPeerAddress() == bd_addr) {
- return &mcl;
- }
- }
- return nullptr;
-}
-
-McapMcl* McapTestApp::FindMclByHandle(tMCA_CL mcl_handle) {
- for (McapMcl& mcl : _mcl_list) {
- if (mcl.GetHandle() == mcl_handle) {
- return &mcl;
- }
- }
- return nullptr;
-}
-
-McapMdep* McapTestApp::FindMdepByHandle(tMCA_DEP mdep_handle) {
- for (McapMdep& mdep : _mdep_list) {
- if (mdep.GetHandle() == mdep_handle) {
- return &mdep;
- }
- }
- return nullptr;
-}
-
-void McapTestApp::RemoveMclByHandle(tMCA_CL mcl_handle) {
- LOG(INFO) << "Removing MCL handle " << (int)mcl_handle;
- for (std::vector<McapMcl>::iterator it = _mcl_list.begin();
- it != _mcl_list.end(); ++it) {
- if (it->GetHandle() == mcl_handle) {
- _mcl_list.erase(it);
- LOG(INFO) << "Removed MCL handle " << (int)mcl_handle;
- return;
- }
- }
-}
-
-bool McapTestApp::IsRegistered() { return _mcap_handle > 0; }
-
-void McapTestApp::ControlCallback(tMCA_HANDLE handle, tMCA_CL mcl,
- uint8_t event, tMCA_CTRL* p_data) {
- McapMcl* mcap_mcl = FindMclByHandle(mcl);
- McapMdl* mcap_mdl = nullptr;
- printf("%s: mcap_handle=%d, mcl_handle=%d, event=%s (0x%02x)\n", __func__,
- handle, mcl, dump_mcap_events(event), event);
- if (_mcap_handle != handle) {
- LOG(ERROR) << "MCAP handle mismatch, self=" << _mcap_handle
- << ", other=" << handle;
- return;
- }
- switch (event) {
- case MCA_ERROR_RSP_EVT:
- print_mcap_event(&p_data->rsp);
- break;
-
- case MCA_CREATE_CFM_EVT:
- // Called when MCA_CreateMdl succeeded step 1 when response is received
- print_mcap_event(&p_data->create_cfm);
- if (!mcap_mcl) {
- LOG(ERROR) << "No MCL for mcl_handle " << (int)mcl;
- break;
- }
- if (!mcap_mcl->IsConnected()) {
- LOG(ERROR) << "MCL " << (int)mcl << " not connected";
- break;
- }
- mcap_mdl = mcap_mcl->FindMdlById(p_data->create_cfm.mdl_id);
- if (!mcap_mdl) {
- LOG(ERROR) << "MDL not found for id " << p_data->create_cfm.mdl_id;
- break;
- }
- if (mcap_mdl->GetResponseCode() >= 0) {
- LOG(ERROR) << "MDL already got response " << mcap_mdl->GetResponseCode()
- << " for id " << p_data->create_cfm.mdl_id;
- break;
- }
- mcap_mdl->SetResponseCode(p_data->create_cfm.rsp_code);
- break;
-
- case MCA_CREATE_IND_EVT: {
- // Should be replied with MCA_CreateMdlRsp
- print_mcap_event(&p_data->create_ind);
- if (!mcap_mcl) {
- LOG(ERROR) << "No MCL for mcl_handle " << (int)mcl;
- break;
- }
- if (!mcap_mcl->IsConnected()) {
- LOG(ERROR) << "MCL " << (int)mcl << " not connected";
- break;
- }
- McapMdep* mcap_mdep = FindMdepByHandle(p_data->create_ind.dep_id);
- if (!mcap_mdep) {
- LOG(ERROR) << "MDEP ID " << (int)p_data->create_ind.dep_id
- << " does not exist";
- _mcap_test_interface->create_mdl_response(
- mcl, p_data->create_ind.dep_id, p_data->create_ind.mdl_id, 0,
- MCA_RSP_BAD_MDEP, get_test_channel_config());
- break;
- }
- bool ret = mcap_mcl->CreateMdlResponse(
- mcap_mdep->GetHandle(), p_data->create_ind.mdl_id,
- p_data->create_ind.dep_id, p_data->create_ind.cfg);
- LOG(INFO) << (ret ? "SUCCESS" : "FAIL");
- if (!ret) {
- _mcap_test_interface->create_mdl_response(
- mcl, p_data->create_ind.dep_id, p_data->create_ind.mdl_id, 0,
- MCA_RSP_NO_RESOURCE, get_test_channel_config());
- }
- break;
- }
- case MCA_RECONNECT_IND_EVT: {
- // Called when remote device asks to reconnect
- // reply with MCA_ReconnectMdlRsp
- print_mcap_event(&p_data->reconnect_ind);
- if (!mcap_mcl) {
- LOG(ERROR) << "No MCL for mcl_handle " << (int)mcl;
- break;
- }
- if (!mcap_mcl->IsConnected()) {
- LOG(ERROR) << "MCL " << (int)mcl << " not connected";
- break;
- }
- mcap_mdl = mcap_mcl->FindMdlById(p_data->reconnect_ind.mdl_id);
- if (mcap_mdl && !mcap_mdl->IsConnected()) {
- LOG(INFO) << "Creating reconnect response for MDL "
- << (int)p_data->reconnect_ind.mdl_id;
- mcap_mdl->ReconnectResponse();
- break;
- }
- LOG_IF(WARNING, mcap_mdl && mcap_mdl->IsConnected())
- << "MDL ID " << (int)p_data->reconnect_ind.mdl_id
- << " is already connected";
- LOG_IF(WARNING, !mcap_mdl) << "No MDL for mdl_id "
- << p_data->reconnect_ind.mdl_id;
- tMCA_DEP mdep_handle = 0;
- if (_mdep_list.size() > 0) {
- mdep_handle = _mdep_list[0].GetHandle();
- } else {
- LOG(ERROR) << "Cannot find any available MDEP";
- }
- tMCA_RESULT ret = _mcap_test_interface->reconnect_mdl_response(
- mcl, mdep_handle, p_data->reconnect_ind.mdl_id, MCA_RSP_BAD_MDL,
- get_test_channel_config());
- LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << ret;
- break;
- }
- case MCA_RECONNECT_CFM_EVT:
- // Called when MCA_ReconnectMdl step 1, receives a response
- print_mcap_event(&p_data->reconnect_cfm);
- if (!mcap_mcl) {
- LOG(ERROR) << "No MCL for mcl_handle " << (int)mcl;
- break;
- }
- if (!mcap_mcl->IsConnected()) {
- LOG(ERROR) << "MCL not connected for mcl_handle " << (int)mcl;
- break;
- }
- mcap_mdl = mcap_mcl->FindMdlById(p_data->reconnect_cfm.mdl_id);
- if (!mcap_mdl) {
- LOG(ERROR) << "MDL not found for id " << p_data->reconnect_cfm.mdl_id;
- break;
- }
- if (mcap_mdl->GetResponseCode() >= 0) {
- LOG(ERROR) << "MDL already got response " << mcap_mdl->GetResponseCode()
- << " for id " << p_data->reconnect_cfm.mdl_id;
- break;
- }
- mcap_mdl->SetResponseCode(p_data->reconnect_cfm.rsp_code);
- break;
-
- case MCA_ABORT_IND_EVT:
- print_mcap_event(&p_data->abort_ind);
- if (!mcap_mcl) {
- LOG(ERROR) << "No MCL for mcl_handle " << (int)mcl;
- break;
- }
- if (!mcap_mcl->IsConnected()) {
- LOG(ERROR) << "MCL not connected for mcl_handle " << (int)mcl;
- break;
- }
- mcap_mdl = mcap_mcl->FindMdlById(p_data->abort_ind.mdl_id);
- if (!mcap_mdl) {
- LOG(ERROR) << "MDL not found for id " << (int)p_data->abort_ind.mdl_id;
- break;
- }
- if (mcap_mdl->IsConnected()) {
- LOG(ERROR) << "MDL is already connected for id "
- << (int)p_data->abort_ind.mdl_id;
- }
- mcap_mcl->RemoveMdl(p_data->abort_ind.mdl_id);
- break;
-
- case MCA_ABORT_CFM_EVT:
- // Called when MCA_Abort succeeded
- print_mcap_event(&p_data->abort_cfm);
- if (!mcap_mcl) {
- LOG(ERROR) << "No MCL for mcl_handle " << (int)mcl;
- break;
- }
- if (!mcap_mcl->IsConnected()) {
- LOG(ERROR) << "MCL " << (int)mcl << " not connected";
- break;
- }
- mcap_mdl = mcap_mcl->FindMdlById(p_data->abort_cfm.mdl_id);
- if (!mcap_mdl) {
- LOG(ERROR) << "MDL not found for id " << (int)p_data->abort_cfm.mdl_id;
- break;
- }
- if (mcap_mdl->IsConnected()) {
- LOG(ERROR) << "MDL is already connected for id "
- << (int)p_data->abort_cfm.mdl_id;
- }
- mcap_mcl->RemoveMdl(p_data->abort_cfm.mdl_id);
- break;
-
- case MCA_DELETE_IND_EVT:
- print_mcap_event(&p_data->delete_ind);
- if (!mcap_mcl) {
- LOG(ERROR) << "No MCL for mcl_handle " << (int)mcl;
- break;
- }
- if (!mcap_mcl->IsConnected()) {
- LOG(ERROR) << "MCL " << (int)mcl << " not connected";
- break;
- }
- if (p_data->delete_ind.mdl_id == MCA_ALL_MDL_ID) {
- mcap_mcl->RemoveAllMdl();
- } else {
- mcap_mcl->RemoveMdl(p_data->delete_ind.mdl_id);
- }
- break;
-
- case MCA_DELETE_CFM_EVT:
- // Called when MCA_Delete succeeded
- print_mcap_event(&p_data->delete_cfm);
- if (!mcap_mcl) {
- LOG(ERROR) << "No MCL for mcl_handle " << (int)mcl;
- break;
- }
- if (!mcap_mcl->IsConnected()) {
- LOG(ERROR) << "MCL " << (int)mcl << " not connected";
- break;
- }
- if (p_data->delete_cfm.rsp_code) {
- LOG(ERROR) << "No success response " << (int)p_data->delete_cfm.rsp_code
- << " when deleting MDL_ID "
- << (int)p_data->delete_cfm.mdl_id;
- break;
- }
- if (p_data->delete_cfm.mdl_id == MCA_ALL_MDL_ID) {
- mcap_mcl->RemoveAllMdl();
- } else {
- mcap_mcl->RemoveMdl(p_data->delete_cfm.mdl_id);
- }
- break;
-
- case MCA_CONNECT_IND_EVT: {
- // Called when MCA_ConnectReq succeeded
- print_mcap_event(&p_data->connect_ind);
- LOG(INFO) << "Received MCL handle " << (int)mcl;
- RawAddress bd_addr = p_data->connect_ind.bd_addr;
- mcap_mcl = FindMclByPeerAddress(bd_addr);
- if (!mcap_mcl) {
- LOG(INFO) << "Creating new MCL for ID " << (int)mcl;
- _mcl_list.push_back(
- McapMcl(_mcap_test_interface, _mcap_handle, bd_addr));
- mcap_mcl = &_mcl_list[_mcl_list.size() - 1];
- }
- if (mcap_mcl->IsConnected()) {
- LOG(ERROR) << "MCL is already connected for handle " << (int)mcl;
- break;
- }
- mcap_mcl->SetHandle(mcl);
- mcap_mcl->SetMtu(p_data->connect_ind.mtu);
- break;
- }
- case MCA_DISCONNECT_IND_EVT: {
- // Called when MCA_ConnectReq failed or MCA_DisconnectReq succeeded
- print_mcap_event(&p_data->disconnect_ind);
- RawAddress bd_addr = p_data->disconnect_ind.bd_addr;
- mcap_mcl = FindMclByPeerAddress(bd_addr);
- if (!mcap_mcl) {
- LOG(ERROR) << "No MCL for BD addr " << bd_addr;
- break;
- }
- if (!mcap_mcl->IsConnected()) {
- LOG(WARNING) << "MCL for " << bd_addr << " is already disconnected";
- }
- mcap_mcl->SetHandle(0);
- mcap_mcl->SetMtu(0);
- mcap_mcl->ResetAllMdl();
- break;
- }
- case MCA_OPEN_IND_EVT:
- // Called when MCA_CreateMdlRsp succeeded step 2, data channel is open
- // Called when MCA_ReconnectMdlRsp succeeded step 2, data channel is open
- case MCA_OPEN_CFM_EVT:
- // Called when MCA_CreateMdl succeeded step 2, data channel is open
- // Called when MCA_ReconnectMdl succeeded step 2, data channel is open
- // Called when MCA_DataChnlCfg succeeded
- print_mcap_event(&p_data->open_ind);
- if (!mcap_mcl) {
- LOG(ERROR) << "No MCL for mcl_handle " << (int)mcl;
- break;
- }
- if (!mcap_mcl->IsConnected()) {
- LOG(ERROR) << "MCL not connected for mcl_handle " << (int)mcl;
- break;
- }
- mcap_mdl = mcap_mcl->FindMdlById(p_data->open_ind.mdl_id);
- if (mcap_mdl) {
- if (mcap_mdl->IsConnected()) {
- LOG(ERROR) << "MDL is already connected for mcl_handle "
- << (int)p_data->open_ind.mdl_id;
- break;
- }
- mcap_mdl->SetMtu(p_data->open_ind.mtu);
- mcap_mdl->SetHandle(p_data->open_ind.mdl);
- } else {
- LOG(ERROR) << "No MDL for mdl_id " << (int)p_data->reconnect_ind.mdl_id;
- }
- break;
-
- case MCA_CLOSE_IND_EVT:
- case MCA_CLOSE_CFM_EVT:
- // Called when MCA_CloseReq is successful
- print_mcap_event(&p_data->close_cfm);
- if (!mcap_mcl) {
- LOG(ERROR) << "No MCL for mcl_handle " << (int)mcl;
- break;
- }
- if (!mcap_mcl->IsConnected()) {
- LOG(ERROR) << "MCL not connected for mcl_handle " << (int)mcl;
- break;
- }
- mcap_mdl = mcap_mcl->FindMdlById(p_data->close_cfm.mdl_id);
- if (mcap_mdl) {
- mcap_mdl->SetMtu(0);
- mcap_mdl->SetHandle(0);
- } else {
- LOG(WARNING) << "No MDL for mdl_id " << (int)p_data->close_cfm.mdl_id;
- }
- break;
-
- case MCA_CONG_CHG_EVT:
- print_mcap_event(&p_data->cong_chg);
- if (!mcap_mcl) {
- LOG(ERROR) << "No MCL for mcl_handle " << (int)mcl;
- break;
- }
- if (!mcap_mcl->IsConnected()) {
- LOG(ERROR) << "MCL not connected for mcl_handle " << (int)mcl;
- break;
- }
- break;
-
- case MCA_RSP_TOUT_IND_EVT:
- case MCA_SYNC_CAP_IND_EVT:
- case MCA_SYNC_CAP_CFM_EVT:
- case MCA_SYNC_SET_IND_EVT:
- case MCA_SYNC_SET_CFM_EVT:
- case MCA_SYNC_INFO_IND_EVT:
- print_mcap_event(&p_data->hdr);
- break;
- }
-}
-
-} // namespace SYSTEM_BT_TOOLS_MCAP_TOOL
diff --git a/tools/mcap_tool/mcap_test_app.h b/tools/mcap_tool/mcap_test_app.h
deleted file mode 100644
index db81657..0000000
--- a/tools/mcap_tool/mcap_test_app.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright 2017 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 <iterator>
-#include <memory>
-#include <string>
-#include <unordered_map>
-#include <vector>
-
-#include <base/logging.h>
-
-#include "mca_api.h"
-
-#include "mcap_test_mcl.h"
-#include "mcap_test_mdep.h"
-
-namespace SYSTEM_BT_TOOLS_MCAP_TOOL {
-
-extern const tMCA_CHNL_CFG MCAP_TEST_CHANNEL_CONFIG;
-
-class McapTestApp {
- public:
- /**
- * McapTestApp is the root node for an MCAP application
- *
- * @param mcap_test_interface interface to MCAP APIs on Bluetooth stack
- * from get_test_interface()
- */
- McapTestApp(btmcap_test_interface_t* mcap_test_interface);
- btmcap_test_interface_t* GetInterface();
- /**
- * Register an application with the Bluetooth stack
- * @param ctrl_psm Control channel L2CAP PSM
- * @param data_psm Data channel L2CAP PSM
- * @param sec_mask Security Mask
- * @param callback Control channel callback
- * @return
- */
- bool Register(uint16_t ctrl_psm, uint16_t data_psm, uint16_t sec_mask,
- tMCA_CTRL_CBACK* callback);
- /**
- * De-register the current application
- */
- void Deregister();
- /**
- * Check if current application is registered
- * @return True if registered
- */
- bool Registered();
- /**
- * Create MCAP Communication Link
- * @param bd_addr Peer Bluetooth Address
- * @param ctrl_psm Control channel L2CAP PSM, should be the same as registered
- * value for most cases
- * @param sec_mask Security mask
- * @return True on success
- */
- bool ConnectMcl(const RawAddress& bd_addr, uint16_t ctrl_psm,
- uint16_t sec_mask);
- /**
- * Create MCAP Data End Point
- * @param type 0 - MCA_TDEP_ECHO, 1 - MCA_TDEP_DATA
- * @param max_mdl Maximum number of data channels for this end point
- * @param data_callback Data callback
- * @return True on success
- */
- bool CreateMdep(uint8_t type, uint8_t max_mdl,
- tMCA_DATA_CBACK* data_callback);
- // Simple methods that are self-explanatory
- uint8_t GetHandle();
- McapMcl* FindMclByPeerAddress(const RawAddress& bd_addr);
- McapMcl* FindMclByHandle(tMCA_CL mcl_handle);
- McapMdep* FindMdepByHandle(tMCA_DEP mdep_handle);
- void RemoveMclByHandle(tMCA_CL mcl_handle);
- bool IsRegistered();
- /**
- * Callback function for control channel, need to be called by an external
- * function registered during McapTestApp::Register()
- * @param handle MCAP application handle, should be the same as GetHandle()
- * @param mcl MCL handle, FindMclByHandle(mcl) should return non-null value
- * @param event Control event
- * @param p_data Control data
- */
- void ControlCallback(tMCA_HANDLE handle, tMCA_CL mcl, uint8_t event,
- tMCA_CTRL* p_data);
-
- private:
- // Initialized during start up
- tMCA_REG _mca_reg;
- btmcap_test_interface_t* _mcap_test_interface = nullptr;
- std::vector<McapMcl> _mcl_list;
- std::vector<McapMdep> _mdep_list;
-
- // Initialized later
- tMCA_HANDLE _mcap_handle = 0;
-};
-
-} // namespace SYSTEM_BT_TOOLS_MCAP_TOOL
diff --git a/tools/mcap_tool/mcap_test_mcl.cc b/tools/mcap_tool/mcap_test_mcl.cc
deleted file mode 100644
index 53cc329..0000000
--- a/tools/mcap_tool/mcap_test_mcl.cc
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Copyright 2017 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 <cstring>
-
-#include <base/logging.h>
-
-#include "mca_api.h"
-#include "mca_defs.h"
-#include "mcap_test_mcl.h"
-
-namespace SYSTEM_BT_TOOLS_MCAP_TOOL {
-
-McapMcl::McapMcl(btmcap_test_interface_t* mcap_test_interface,
- tMCA_HANDLE mcap_handle, const RawAddress& peer_bd_addr)
- : _mdl_list() {
- _mcap_handle = mcap_handle;
- _mcap_test_interface = mcap_test_interface;
- memcpy(_peer_bd_addr.address, peer_bd_addr.address,
- sizeof(_peer_bd_addr.address));
-}
-
-bool McapMcl::Connect(uint16_t ctrl_psm, uint16_t sec_mask) {
- tMCA_RESULT ret = _mcap_test_interface->connect_mcl(
- _mcap_handle, _peer_bd_addr, ctrl_psm, sec_mask);
- LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
- return ret == MCA_SUCCESS;
-}
-
-bool McapMcl::Disconnect() {
- if (!IsConnected()) {
- LOG(ERROR) << "MCL is not connected";
- return false;
- }
- tMCA_RESULT ret = _mcap_test_interface->disconnect_mcl(_mcl_handle);
- LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
- return ret == MCA_SUCCESS;
-}
-
-McapMdl* McapMcl::AllocateMdl(tMCA_DEP mdep_handle, uint16_t mdl_id,
- uint8_t dep_id, uint8_t cfg) {
- if (!IsConnected()) {
- LOG(ERROR) << "MCL is not connected";
- return nullptr;
- }
- if (FindMdlById(mdl_id) != nullptr) {
- LOG(ERROR) << "mdl_id=" << mdl_id << "already exists";
- return nullptr;
- }
- if (!HasAvailableMdl()) {
- LOG(ERROR) << "No more avaible MDL, currently " << _mdl_list.size();
- return nullptr;
- }
- _mdl_list.push_back(McapMdl(_mcap_test_interface, _mcl_handle, mdep_handle,
- mdl_id, dep_id, cfg));
- return &_mdl_list[_mdl_list.size() - 1];
-}
-
-bool McapMcl::CreateMdl(tMCA_DEP mdep_handle, uint16_t data_psm,
- uint16_t mdl_id, uint8_t peer_dep_id, uint8_t cfg,
- bool should_connect) {
- if (!IsConnected()) {
- LOG(ERROR) << "MCL is not connected";
- return false;
- }
- McapMdl* mcap_mdl = FindMdlById(mdl_id);
- if (!mcap_mdl) {
- LOG(INFO) << "mdl_id=" << mdl_id << "does not exists, creating new one";
- mcap_mdl = AllocateMdl(mdep_handle, mdl_id, peer_dep_id, cfg);
- if (!mcap_mdl) {
- return false;
- }
- }
- if (mcap_mdl->IsConnected()) {
- LOG(ERROR) << "mdl_id=" << mdl_id << "is already connected with handle "
- << (int)mcap_mdl->GetHandle();
- return false;
- }
- return mcap_mdl->Create(data_psm, should_connect);
-}
-
-bool McapMcl::DataChannelConfig() {
- tMCA_RESULT ret = _mcap_test_interface->data_channel_config(
- _mcl_handle, get_test_channel_config());
- LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
- return ret == MCA_SUCCESS;
-}
-
-bool McapMcl::CreateMdlResponse(tMCA_DEP mdep_handle, uint16_t mdl_id,
- uint8_t my_dep_id, uint8_t cfg) {
- if (!IsConnected()) {
- LOG(ERROR) << "MCL is not connected";
- return false;
- }
- McapMdl* mcap_mdl = FindMdlById(mdl_id);
- if (!mcap_mdl) {
- LOG(INFO) << "mdl_id=" << mdl_id << " does not exists, creating new one";
- mcap_mdl = AllocateMdl(mdep_handle, mdl_id, my_dep_id, cfg);
- if (!mcap_mdl) {
- LOG(ERROR) << "MDL cannot be created";
- return false;
- }
- }
- if (mcap_mdl->IsConnected()) {
- LOG(INFO) << "mdl_id=" << mdl_id << " is already connected with handle "
- << (int)mcap_mdl->GetHandle() << ", updating context";
- mcap_mdl->UpdateContext(mdep_handle, my_dep_id, cfg);
- }
- return mcap_mdl->CreateResponse();
-}
-
-bool McapMcl::AbortMdl() {
- tMCA_RESULT ret = _mcap_test_interface->abort_mdl(_mcl_handle);
- LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
- return ret == MCA_SUCCESS;
-}
-
-bool McapMcl::DeleteMdl(uint16_t mdl_id) {
- tMCA_RESULT ret = _mcap_test_interface->delete_mdl(_mcl_handle, mdl_id);
- LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
- return ret == MCA_SUCCESS;
-}
-
-RawAddress& McapMcl::GetPeerAddress() { return _peer_bd_addr; }
-
-void McapMcl::SetHandle(tMCA_CL handle) { _mcl_handle = handle; }
-
-tMCA_CL McapMcl::GetHandle() const { return _mcl_handle; }
-
-void McapMcl::SetMtu(uint16_t mtu) { _control_mtu = mtu; }
-
-uint16_t McapMcl::GetMtu() { return _control_mtu; }
-
-McapMdl* McapMcl::FindMdlById(uint16_t mdl_id) {
- for (McapMdl& mdl : _mdl_list) {
- if (mdl.GetId() == mdl_id) {
- return &mdl;
- }
- }
- return nullptr;
-}
-
-McapMdl* McapMcl::FindMdlByHandle(tMCA_DL mdl_handle) {
- for (McapMdl& mdl : _mdl_list) {
- if (mdl.GetHandle() == mdl_handle) {
- return &mdl;
- }
- }
- return nullptr;
-}
-
-void McapMcl::RemoveAllMdl() { _mdl_list.clear(); }
-
-void McapMcl::RemoveMdl(uint16_t mdl_id) {
- LOG(INFO) << "Removing MDL id " << (int)mdl_id;
- for (std::vector<McapMdl>::iterator it = _mdl_list.begin();
- it != _mdl_list.end(); ++it) {
- if (it->GetId() == mdl_id) {
- _mdl_list.erase(it);
- LOG(INFO) << "Removed MDL id " << (int)mdl_id;
- return;
- }
- }
-}
-
-void McapMcl::ResetAllMdl() {
- for (McapMdl& mcap_mdl : _mdl_list) {
- mcap_mdl.SetHandle(0);
- mcap_mdl.SetMtu(0);
- mcap_mdl.SetResponseCode(-1);
- }
-}
-
-void McapMcl::ResetMdl(uint16_t mdl_id) {
- LOG(INFO) << "Closing MDL id " << (int)mdl_id;
- McapMdl* mcap_mdl = FindMdlById(mdl_id);
- if (!mcap_mdl) {
- LOG(ERROR) << "Cannot find MDL for id " << (int)mdl_id;
- return;
- }
- if (mcap_mdl->IsConnected()) {
- LOG(ERROR) << "MDL " << (int)mdl_id << " is still connected";
- return;
- }
- mcap_mdl->SetHandle(0);
- mcap_mdl->SetMtu(0);
- mcap_mdl->SetResponseCode(-1);
-}
-
-bool McapMcl::IsConnected() { return _mcl_handle > 0; }
-
-int McapMcl::ConnectedMdlCount() {
- int count = 0;
- for (McapMdl& mcap_mdl : _mdl_list) {
- if (mcap_mdl.IsConnected()) {
- count++;
- }
- }
- return count;
-}
-
-bool McapMcl::HasAvailableMdl() { return ConnectedMdlCount() < MCA_NUM_MDLS; }
-
-} // namespace SYSTEM_BT_TOOLS_MCAP_TOOL
diff --git a/tools/mcap_tool/mcap_test_mcl.h b/tools/mcap_tool/mcap_test_mcl.h
deleted file mode 100644
index 6700fb1..0000000
--- a/tools/mcap_tool/mcap_test_mcl.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright 2017 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 <vector>
-
-#include "mca_api.h"
-#include "mcap_test_mdl.h"
-
-namespace SYSTEM_BT_TOOLS_MCAP_TOOL {
-
-class McapMcl {
- public:
- /**
- * A controller for a MCAP Communication Link (MCL)
- * @param mcap_test_interface Underlining interface to Bluetooth stack
- * @param mcap_handle Parent application handle
- * @param peer_bd_addr Peer Bluetooth MAC address
- */
- McapMcl(btmcap_test_interface_t* mcap_test_interface, tMCA_HANDLE mcap_handle,
- const RawAddress& peer_bd_addr);
- /**
- * Connect this MCL's control channel
- * @param ctrl_psm Control channel L2CAP PSM
- * @param sec_mask Security mask
- * @return True on success
- */
- bool Connect(uint16_t ctrl_psm, uint16_t sec_mask);
- /**
- * Disconnect from control channel
- * @return
- */
- bool Disconnect();
- /**
- * Close this MCL connection
- * @return
- */
- bool Close();
- /**
- * Allocate an MCAP Data Link (MDL) object and save to this MCL object
- * @param mdep_handle MDEP handle for data, MDEP must be prior created
- * @param mdl_id Desired MDL ID, user supported
- * @param dep_id Peer MDEP ID
- * @param cfg Configuration flags
- * @return True on success
- */
- McapMdl* AllocateMdl(tMCA_DEP mdep_handle, uint16_t mdl_id, uint8_t dep_id,
- uint8_t cfg);
- /**
- * Send CREATE_MDL message to peer device, will allocate an MDL if the MDL for
- * corresponding MDL ID was not allocated before
- * @param mdep_handle MDEP handle for data, MDEP must be prior created
- * @param data_psm Data channel L2CAP PSM
- * @param mdl_id Desired MDL ID, user supported
- * @param peer_dep_id Peer MDEP ID
- * @param cfg Configuration flags
- * @param should_connect whether we should connect L2CAP immediately
- * @return True on success
- */
- bool CreateMdl(tMCA_DEP mdep_handle, uint16_t data_psm, uint16_t mdl_id,
- uint8_t peer_dep_id, uint8_t cfg, bool should_connect);
- /**
- * Configure data channel, unblock any pending MDL L2CAP connection requests
- * @return True on Success
- */
- bool DataChannelConfig();
- /**
- * Respond to CREATE_MDL message received from peer device, will allocate an
- * MDL if the MDL for corresponding MDL ID was not allocated before
- * @param mdep_handle MDEP handle for data, MDEP must be prior created
- * @param mdl_id Desired MDL ID, peer supported
- * @param my_dep_id My MDEP ID
- * @param cfg Configuration flags
- * @return True on success
- */
- bool CreateMdlResponse(tMCA_DEP mdep_handle, uint16_t mdl_id,
- uint8_t my_dep_id, uint8_t cfg);
- /**
- * Send ABORT_MDL request, aborting all pending CREATE_MDL requests
- * @return
- */
- bool AbortMdl();
- /**
- * Send DELETE_MDL request to remote
- * @param mdl_id None zero value mdl_id, 0xFFFF for all remote MDLs
- * @return True on success
- */
- bool DeleteMdl(uint16_t mdl_id);
- // Simple methods that are self-explanatory
- RawAddress& GetPeerAddress();
- void SetHandle(tMCA_CL handle);
- tMCA_CL GetHandle() const;
- void SetMtu(uint16_t mtu);
- uint16_t GetMtu();
- McapMdl* FindMdlById(uint16_t mdl_id);
- McapMdl* FindMdlByHandle(tMCA_DL mdl_handle);
- void RemoveAllMdl();
- void RemoveMdl(uint16_t mdl_id);
- void ResetAllMdl();
- void ResetMdl(uint16_t mdl_id);
- bool IsConnected();
- int ConnectedMdlCount();
- bool HasAvailableMdl();
-
- private:
- // Initialized during start up
- btmcap_test_interface_t* _mcap_test_interface;
- tMCA_HANDLE _mcap_handle;
- RawAddress _peer_bd_addr;
- std::vector<McapMdl> _mdl_list;
-
- // Initialized later
- tMCA_CL _mcl_handle = 0;
- uint16_t _control_mtu = 0;
-};
-
-} // namespace SYSTEM_BT_TOOLS_MCAP_TOOL
diff --git a/tools/mcap_tool/mcap_test_mdep.cc b/tools/mcap_tool/mcap_test_mdep.cc
deleted file mode 100644
index bd2ce23..0000000
--- a/tools/mcap_tool/mcap_test_mdep.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2017 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/logging.h>
-
-#include "mcap_test_mdep.h"
-
-namespace SYSTEM_BT_TOOLS_MCAP_TOOL {
-
-McapMdep::McapMdep(btmcap_test_interface_t* mcap_test_interface,
- tMCA_HANDLE mcap_handle, uint8_t type, uint8_t max_mdl,
- tMCA_DATA_CBACK* data_callback) {
- _mcap_test_interface = mcap_test_interface;
- _mcap_handle = mcap_handle;
- _mca_cs.type = (0 == type) ? MCA_TDEP_ECHO : MCA_TDEP_DATA;
- _mca_cs.max_mdl = max_mdl;
- _mca_cs.p_data_cback = data_callback;
-}
-
-bool McapMdep::Create() {
- tMCA_RESULT ret =
- _mcap_test_interface->create_mdep(_mcap_handle, &_mdep_handle, &_mca_cs);
- LOG(INFO) << "mdep_handle=" << (int)_mdep_handle;
- LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
- return ret == MCA_SUCCESS;
-}
-
-bool McapMdep::Delete() {
- tMCA_RESULT ret =
- _mcap_test_interface->create_mdep(_mcap_handle, &_mdep_handle, &_mca_cs);
- LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
- return ret == MCA_SUCCESS;
-}
-
-tMCA_DEP McapMdep::GetHandle() const { return _mdep_handle; }
-
-bool McapMdep::IsRegistered() { return _mdep_handle > 0; }
-
-} // namespace SYSTEM_BT_TOOLS_MCAP_TOOL
diff --git a/tools/mcap_tool/mcap_test_mdep.h b/tools/mcap_tool/mcap_test_mdep.h
deleted file mode 100644
index 2278781..0000000
--- a/tools/mcap_tool/mcap_test_mdep.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2017 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 "mca_api.h"
-
-namespace SYSTEM_BT_TOOLS_MCAP_TOOL {
-
-class McapMdep {
- public:
- /**
- * A control abstraction for a MCAP Data End Point (MDEP)
- * @param mcap_test_interface Underlining MCAP interface to Bluetooth stack
- * @param mcap_handle Parent MCAP application handle
- * @param type 0 for Echo, 1 for Normal, nothing else
- * @param max_mdl Maximum number of MDL's allowed
- * @param data_callback Data channel callback function
- */
- McapMdep(btmcap_test_interface_t* mcap_test_interface,
- tMCA_HANDLE mcap_handle, uint8_t type, uint8_t max_mdl,
- tMCA_DATA_CBACK* data_callback);
- /**
- * Actually create the MDEP in the stack
- * @return True if success
- */
- bool Create();
- /**
- * Destroy the MDEP in the stack
- * @return True if success
- */
- bool Delete();
- // Simple methods that are self-explanatory
- tMCA_DEP GetHandle() const;
- bool IsRegistered();
-
- private:
- // Initialized during start up
- btmcap_test_interface_t* _mcap_test_interface;
- tMCA_HANDLE _mcap_handle;
- tMCA_CS _mca_cs;
-
- // Initialized later
- tMCA_DEP _mdep_handle = 0;
-};
-
-} // namespace SYSTEM_BT_TOOLS_MCAP_TOOL
diff --git a/tools/mcap_tool/mcap_test_mdl.cc b/tools/mcap_tool/mcap_test_mdl.cc
deleted file mode 100644
index f0cd572..0000000
--- a/tools/mcap_tool/mcap_test_mdl.cc
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright 2017 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/logging.h>
-
-#include "mca_defs.h"
-#include "mcap_test_mdl.h"
-
-namespace SYSTEM_BT_TOOLS_MCAP_TOOL {
-
-/* Test MCAP Channel Configurations */
-const tMCA_CHNL_CFG MCAP_TEST_CHANNEL_CONFIG = {
- .fcr_opt =
- {
- L2CAP_FCR_ERTM_MODE,
- MCA_FCR_OPT_TX_WINDOW_SIZE, /* Tx window size */
- /* Maximum transmissions before disconnecting */
- MCA_FCR_OPT_MAX_TX_B4_DISCNT,
- MCA_FCR_OPT_RETX_TOUT, /* retransmission timeout (2 secs) */
- MCA_FCR_OPT_MONITOR_TOUT, /* Monitor timeout (12 secs) */
- MCA_FCR_OPT_MPS_SIZE, /* MPS segment size */
- },
- .user_rx_buf_size = BT_DEFAULT_BUFFER_SIZE,
- .user_tx_buf_size = BT_DEFAULT_BUFFER_SIZE,
- .fcr_rx_buf_size = BT_DEFAULT_BUFFER_SIZE,
- .fcr_tx_buf_size = BT_DEFAULT_BUFFER_SIZE,
- .fcs = MCA_FCS_NONE,
- .data_mtu = 572 /* L2CAP MTU of the MCAP data channel */
-};
-
-const tMCA_CHNL_CFG* get_test_channel_config() {
- return &MCAP_TEST_CHANNEL_CONFIG;
-}
-
-McapMdl::McapMdl(btmcap_test_interface_t* mcap_test_interface,
- tMCA_CL mcl_handle, tMCA_DEP mdep_handle, uint16_t mdl_id,
- uint8_t dep_id, uint8_t cfg) {
- _mcap_test_interface = mcap_test_interface;
- _mcl_handle = mcl_handle;
- _mdep_handle = mdep_handle;
- _mdl_id = mdl_id;
- _dep_id = dep_id;
- _cfg = cfg;
-}
-
-bool McapMdl::UpdateContext(tMCA_DEP mdep_handle, uint8_t dep_id, uint8_t cfg) {
- if (!_mdl_handle) {
- LOG(ERROR) << "MDL handle not initialized";
- }
- _mdep_handle = mdep_handle;
- _dep_id = dep_id;
- _cfg = cfg;
- tMCA_RESULT ret = _mcap_test_interface->close_mdl_request(_mdl_handle);
- LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
- if (ret != MCA_SUCCESS) return false;
- SetHandle(0);
- SetResponseCode(-1);
- SetMtu(0);
- return true;
-}
-
-bool McapMdl::Create(uint16_t data_psm, bool should_connect) {
- tMCA_RESULT ret = _mcap_test_interface->create_mdl_request(
- _mcl_handle, _mdep_handle, data_psm, _mdl_id, _dep_id, _cfg,
- should_connect ? &MCAP_TEST_CHANNEL_CONFIG : nullptr);
- LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
- return ret == MCA_SUCCESS;
-}
-
-bool McapMdl::Close() {
- if (!_mdl_handle) {
- LOG(ERROR) << "MDL handle not initialized";
- return false;
- }
- tMCA_RESULT ret = _mcap_test_interface->close_mdl_request(_mdl_handle);
- LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
- return ret == MCA_SUCCESS;
-}
-
-bool McapMdl::Reconnect(uint16_t data_psm) {
- tMCA_RESULT ret = _mcap_test_interface->reconnect_mdl_request(
- _mcl_handle, _mdep_handle, data_psm, _mdl_id, &MCAP_TEST_CHANNEL_CONFIG);
- LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
- return ret == MCA_SUCCESS;
-}
-
-bool McapMdl::ReconnectResponse() {
- tMCA_RESULT ret = _mcap_test_interface->reconnect_mdl_response(
- _mcl_handle, _mdep_handle, _mdl_id, MCA_RSP_SUCCESS,
- &MCAP_TEST_CHANNEL_CONFIG);
- LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
- return ret == MCA_SUCCESS;
-}
-
-bool McapMdl::CreateResponse() {
- tMCA_RESULT ret = _mcap_test_interface->create_mdl_response(
- _mcl_handle, _dep_id, _mdl_id, _cfg, MCA_SUCCESS,
- &MCAP_TEST_CHANNEL_CONFIG);
- LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
- return ret == MCA_SUCCESS;
-}
-
-bool McapMdl::IsConnected() { return _mdl_handle > 0; }
-
-uint16_t McapMdl::GetId() { return _mdl_id; }
-
-int32_t McapMdl::GetResponseCode() { return _mdl_rsp_code; }
-
-void McapMdl::SetResponseCode(int32_t rsp_code) { _mdl_rsp_code = rsp_code; }
-
-void McapMdl::SetHandle(tMCA_DL mdl_handle) { _mdl_handle = mdl_handle; }
-
-tMCA_DL McapMdl::GetHandle() { return _mdl_handle; }
-
-void McapMdl::SetMtu(uint16_t mtu) { _data_mtu = mtu; }
-
-uint16_t McapMdl::GetMtu() { return _data_mtu; }
-
-} // namespace SYSTEM_BT_TOOLS_MCAP_TOOL
diff --git a/tools/mcap_tool/mcap_test_mdl.h b/tools/mcap_tool/mcap_test_mdl.h
deleted file mode 100644
index 56d8d8c..0000000
--- a/tools/mcap_tool/mcap_test_mdl.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 2017 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 "mca_api.h"
-
-namespace SYSTEM_BT_TOOLS_MCAP_TOOL {
-
-const tMCA_CHNL_CFG* get_test_channel_config();
-
-class McapMdl {
- public:
- /**
- * An abstraction for the MCAP Data Link (MDL)
- * @param mcap_test_interface Underlining MCAP interface to Bluetooth stack
- * @param mcl_handle Parent MCL handle
- * @param mdep_handle Associated MDEP handle
- * @param mdl_id Desired MDL ID, application supported
- * @param dep_id Peer or self MDEP ID
- * @param cfg Configuration flags
- */
- McapMdl(btmcap_test_interface_t* mcap_test_interface, tMCA_CL mcl_handle,
- tMCA_DEP mdep_handle, uint16_t mdl_id, uint8_t dep_id, uint8_t cfg);
- /**
- * Update this MDL's context so that it can be reused for a new connection
- * This will close this MDL connection at the same time
- * @param mdep_handle Associated MDEP handle
- * @param dep_id Peer or self MDEP ID
- * @param cfg Configuration flags
- * @return True on success
- */
- bool UpdateContext(tMCA_DEP mdep_handle, uint8_t dep_id, uint8_t cfg);
- /**
- * Request to create this MDL to remote device through MCL
- * The create command won't initiate an L2CAP connection unless a non-null
- * config is given
- * @param data_psm Data channel L2CAP PSM
- * @return True on success
- */
- bool Create(uint16_t data_psm, bool should_connect);
- /**
- * Connect this MDL to remote by configuring the data channel
- * @return True on success
- */
- bool Connect();
- /**
- * Close this MDL connection
- * @return True on success
- */
- bool Close();
- /**
- * Request to reconnect connect this MDL to remote device through MCL
- * @param data_psm Data channel L2CAP PSM
- * @return True on success
- */
- bool Reconnect(uint16_t data_psm);
- /**
- * Respond to a reconnect request from peer
- * @return True on success
- */
- bool ReconnectResponse();
- /**
- * Respond to a connect request from peer
- * @return True on success
- */
- bool CreateResponse();
- bool IsConnected();
- int32_t GetResponseCode();
- void SetResponseCode(int32_t rsp_code);
- uint16_t GetId();
- void SetHandle(tMCA_DL mdl_handle);
- tMCA_DL GetHandle();
- void SetMtu(uint16_t mtu);
- uint16_t GetMtu();
-
- private:
- // Initialized at start up
- btmcap_test_interface_t* _mcap_test_interface;
- tMCA_CL _mcl_handle;
- tMCA_DEP _mdep_handle;
- uint16_t _mdl_id;
- uint8_t _dep_id;
- uint8_t _cfg;
-
- // Initialized later
- tMCA_DL _mdl_handle = 0;
- uint16_t _data_mtu = 0;
- int32_t _mdl_rsp_code = -1;
-};
-
-} // namespace SYSTEM_BT_TOOLS_MCAP_TOOL
diff --git a/tools/mcap_tool/mcap_tool.cc b/tools/mcap_tool/mcap_tool.cc
deleted file mode 100644
index 6ed26aa..0000000
--- a/tools/mcap_tool/mcap_tool.cc
+++ /dev/null
@@ -1,959 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2015, The linux Foundation. All rights reserved.
- *
- * Not a Contribution.
- *
- * Copyright 2009-2012 Broadcom 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.
- *
- ******************************************************************************/
-
-/************************************************************************************
- *
- * Filename: mcap_tool.cc
- *
- * Description: Fluoride MCAP Test Tool application
- *
- ***********************************************************************************/
-#include <pthread.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifndef OS_GENERIC
-#include <sys/capability.h>
-#endif
-#include <sys/prctl.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <hardware/bluetooth.h>
-#ifndef OS_GENERIC
-#include <private/android_filesystem_config.h>
-#endif
-#include <base/logging.h>
-
-#include "bt_types.h"
-#include "l2c_api.h"
-#include "mca_api.h"
-#include "mca_defs.h"
-#include "osi/include/compat.h"
-#include "hal_util.h"
-#include "mcap_test_app.h"
-#include "mcap_test_mcl.h"
-#include "mcap_test_mdep.h"
-#include "mcap_test_mdl.h"
-
-using SYSTEM_BT_TOOLS_MCAP_TOOL::McapTestApp;
-using SYSTEM_BT_TOOLS_MCAP_TOOL::McapMcl;
-using SYSTEM_BT_TOOLS_MCAP_TOOL::McapMdep;
-using SYSTEM_BT_TOOLS_MCAP_TOOL::McapMdl;
-
-/******************************************************************************
- * Constants & Macros
- *****************************************************************************/
-#define PID_FILE "/data/.bdt_pid"
-
-#ifndef MAX
-#define MAX(x, y) ((x) > (y) ? (x) : (y))
-#endif
-
-#ifndef MIN
-#define MIN(x, y) ((x) < (y) ? (x) : (y))
-#endif
-
-#define CASE_RETURN_STR(const) \
- case const: \
- return #const;
-
-#ifndef OS_GENERIC
-/* Permission Groups */
-static gid_t groups[] = {AID_NET_BT, AID_INET, AID_NET_BT_ADMIN,
- AID_SYSTEM, AID_MISC, AID_SDCARD_RW,
- AID_NET_ADMIN, AID_VPN};
-#endif
-/******************************************************************************
- * Static variables
- *****************************************************************************/
-/* Console loop states */
-static bool global_main_done = false;
-static bt_status_t global_status;
-static bool global_strict_mode = false;
-
-/* Device and Profile Interfaces */
-const bt_interface_t* sBtInterface = nullptr;
-static btmcap_test_interface_t* sMcapTestInterface = nullptr;
-static McapTestApp* sMcapTestApp = nullptr;
-
-/* Bluetooth stack states */
-static bool global_bt_enabled = false;
-static int global_adapter_state = BT_STATE_OFF;
-static int global_pair_state = BT_BOND_STATE_NONE;
-/************************************************************************************
-** Static functions
-************************************************************************************/
-static void process_cmd(char* p, bool is_job);
-
-/*******************************************************************************
- ** Misc helper functions
- *******************************************************************************/
-static const char* dump_bt_status(const bt_status_t status) {
- switch (status) {
- CASE_RETURN_STR(BT_STATUS_SUCCESS)
- CASE_RETURN_STR(BT_STATUS_FAIL)
- CASE_RETURN_STR(BT_STATUS_NOT_READY)
- CASE_RETURN_STR(BT_STATUS_NOMEM)
- CASE_RETURN_STR(BT_STATUS_BUSY)
- CASE_RETURN_STR(BT_STATUS_UNSUPPORTED)
- default:
- return "unknown status code";
- }
-}
-
-/************************************************************************************
-** MCAP Callbacks
-************************************************************************************/
-static void mcap_ctrl_callback(tMCA_HANDLE handle, tMCA_CL mcl, uint8_t event,
- tMCA_CTRL* p_data) {
- sMcapTestApp->ControlCallback(handle, mcl, event, p_data);
-}
-
-static void mcap_data_cb(tMCA_DL mdl, BT_HDR* p_pkt) {
- printf("%s: mdl=%d, event=%d, len=%d, offset=%d, layer_specific=%d\n",
- __func__, mdl, p_pkt->event, p_pkt->len, p_pkt->offset,
- p_pkt->layer_specific);
- printf("%s: HEXDUMP OF DATA LENGTH %u:\n", __func__, p_pkt->len);
- printf("=========================Begin=========================\n");
- bool newline = false;
- for (int i = 0; i < p_pkt->len; ++i) {
- printf("%02x", p_pkt->data[i]);
- if (i > 0 && (i % 25) == 0) {
- printf("\n");
- newline = true;
- } else {
- printf(" ");
- newline = false;
- }
- }
- if (!newline) printf("\n");
- printf("=========================End===========================\n");
-}
-
-/************************************************************************************
-** Shutdown helper functions
-************************************************************************************/
-
-static void console_shutdown(void) {
- LOG(INFO) << __func__ << ": Shutdown Fluoride MCAP test app";
- global_main_done = true;
-}
-
-/*****************************************************************************
-** Android's init.rc does not yet support applying linux capabilities
-*****************************************************************************/
-
-#ifndef OS_GENERIC
-static void config_permissions(void) {
- struct __user_cap_header_struct header;
- struct __user_cap_data_struct cap[2];
-
- printf("set_aid_and_cap : pid %d, uid %d gid %d", getpid(), getuid(),
- getgid());
-
- header.pid = 0;
-
- prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
-
- setuid(AID_BLUETOOTH);
- setgid(AID_BLUETOOTH);
-
- header.version = _LINUX_CAPABILITY_VERSION_3;
-
- cap[CAP_TO_INDEX(CAP_NET_RAW)].permitted |= CAP_TO_MASK(CAP_NET_RAW);
- cap[CAP_TO_INDEX(CAP_NET_ADMIN)].permitted |= CAP_TO_MASK(CAP_NET_ADMIN);
- cap[CAP_TO_INDEX(CAP_NET_BIND_SERVICE)].permitted |=
- CAP_TO_MASK(CAP_NET_BIND_SERVICE);
- cap[CAP_TO_INDEX(CAP_SYS_RAWIO)].permitted |= CAP_TO_MASK(CAP_SYS_RAWIO);
- cap[CAP_TO_INDEX(CAP_SYS_NICE)].permitted |= CAP_TO_MASK(CAP_SYS_NICE);
- cap[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
- cap[CAP_TO_INDEX(CAP_WAKE_ALARM)].permitted |= CAP_TO_MASK(CAP_WAKE_ALARM);
-
- cap[CAP_TO_INDEX(CAP_NET_RAW)].effective |= CAP_TO_MASK(CAP_NET_RAW);
- cap[CAP_TO_INDEX(CAP_NET_ADMIN)].effective |= CAP_TO_MASK(CAP_NET_ADMIN);
- cap[CAP_TO_INDEX(CAP_NET_BIND_SERVICE)].effective |=
- CAP_TO_MASK(CAP_NET_BIND_SERVICE);
- cap[CAP_TO_INDEX(CAP_SYS_RAWIO)].effective |= CAP_TO_MASK(CAP_SYS_RAWIO);
- cap[CAP_TO_INDEX(CAP_SYS_NICE)].effective |= CAP_TO_MASK(CAP_SYS_NICE);
- cap[CAP_TO_INDEX(CAP_SETGID)].effective |= CAP_TO_MASK(CAP_SETGID);
- cap[CAP_TO_INDEX(CAP_WAKE_ALARM)].effective |= CAP_TO_MASK(CAP_WAKE_ALARM);
-
- capset(&header, &cap[0]);
- setgroups(sizeof(groups) / sizeof(groups[0]), groups);
-}
-#endif
-
-/*******************************************************************************
- ** Console helper functions
- *******************************************************************************/
-
-void skip_blanks(char** p) {
- while (**p == ' ') (*p)++;
-}
-
-uint32_t get_int(char** p, int DefaultValue) {
- uint32_t Value = 0;
- unsigned char UseDefault;
-
- UseDefault = 1;
- skip_blanks(p);
-
- while (((**p) <= '9' && (**p) >= '0')) {
- Value = Value * 10 + (**p) - '0';
- UseDefault = 0;
- (*p)++;
- }
-
- if (UseDefault)
- return DefaultValue;
- else
- return Value;
-}
-
-int get_signed_int(char** p, int DefaultValue) {
- int Value = 0;
- unsigned char UseDefault;
- unsigned char NegativeNum = 0;
-
- UseDefault = 1;
- skip_blanks(p);
-
- if ((**p) == '-') {
- NegativeNum = 1;
- (*p)++;
- }
- while (((**p) <= '9' && (**p) >= '0')) {
- Value = Value * 10 + (**p) - '0';
- UseDefault = 0;
- (*p)++;
- }
-
- if (UseDefault)
- return DefaultValue;
- else
- return ((NegativeNum == 0) ? Value : -Value);
-}
-
-void get_str(char** p, char* Buffer) {
- skip_blanks(p);
-
- while (**p != 0 && **p != ' ') {
- *Buffer = **p;
- (*p)++;
- Buffer++;
- }
-
- *Buffer = 0;
-}
-
-uint32_t get_hex_any(char** p, int DefaultValue, unsigned int NumOfNibble) {
- uint32_t Value = 0;
- unsigned char UseDefault;
- // unsigned char NumOfNibble = 8; //Since we are returning uint32, max
- // allowed is 4 bytes(8 nibbles).
-
- UseDefault = 1;
- skip_blanks(p);
-
- while ((NumOfNibble) &&
- (((**p) <= '9' && (**p) >= '0') || ((**p) <= 'f' && (**p) >= 'a') ||
- ((**p) <= 'F' && (**p) >= 'A'))) {
- if (**p >= 'a')
- Value = Value * 16 + (**p) - 'a' + 10;
- else if (**p >= 'A')
- Value = Value * 16 + (**p) - 'A' + 10;
- else
- Value = Value * 16 + (**p) - '0';
- UseDefault = 0;
- (*p)++;
- NumOfNibble--;
- }
-
- if (UseDefault)
- return DefaultValue;
- else
- return Value;
-}
-uint32_t get_hex(char** p, int DefaultValue) {
- return get_hex_any(p, DefaultValue, 8);
-}
-uint8_t get_hex_byte(char** p, int DefaultValue) {
- return get_hex_any(p, DefaultValue, 2);
-}
-
-bool is_cmd(const char* cmd, const char* str) {
- return (strlen(str) == strlen(cmd)) && (strncmp(cmd, str, strlen(str)) == 0);
-}
-
-typedef void(console_cmd_handler_t)(char* p);
-
-typedef struct {
- const char* name;
- console_cmd_handler_t* handler;
- const char* help;
- bool is_job;
-} cmd_t;
-
-extern const cmd_t console_cmd_list[];
-static int console_cmd_maxlen = 0;
-
-static void* cmdjob_handler(void* param) {
- char* job_cmd = (char*)param;
- LOG(INFO) << "cmdjob starting: " << job_cmd;
- process_cmd(job_cmd, true);
- LOG(INFO) << "cmdjob terminating";
- free(job_cmd);
- return nullptr;
-}
-
-static int create_cmdjob(char* cmd) {
- CHECK(cmd);
- char* job_cmd = (char*)calloc(1, strlen(cmd) + 1); /* freed in job handler */
- if (job_cmd) {
- strlcpy(job_cmd, cmd, strlen(job_cmd) + 1);
- pthread_t thread_id;
- int ret =
- pthread_create(&thread_id, nullptr, cmdjob_handler, (void*)job_cmd);
- LOG_IF(ERROR, ret != 0) << "Error during pthread_create";
- } else {
- LOG(INFO) << "Cannot Allocate memory for cmdjob: " << cmd;
- }
- return 0;
-}
-
-/*******************************************************************************
- ** Load stack lib
- *******************************************************************************/
-
-int HAL_load(void) {
- LOG(INFO) << "Loading HAL library and extensions";
- bt_interface_t* interface;
- int err = hal_util_load_bt_library((const bt_interface_t**)&interface);
- if (err) {
- LOG(ERROR) << "Error loading HAL library: " << strerror(err);
- return err;
- }
- sBtInterface = interface;
- LOG(INFO) << "HAL library loaded";
- return err;
-}
-
-int HAL_unload(void) {
- int err = 0;
- LOG(INFO) << "Unloading HAL lib";
- sBtInterface = nullptr;
- LOG(INFO) << "HAL library unloaded, status: " << strerror(err);
- return err;
-}
-
-/*******************************************************************************
- ** HAL test functions & callbacks
- *******************************************************************************/
-
-void setup_test_env(void) {
- int i = 0;
- while (console_cmd_list[i].name) {
- console_cmd_maxlen =
- MAX(console_cmd_maxlen, (int)strlen(console_cmd_list[i].name));
- i++;
- }
-}
-
-void check_return_status(bt_status_t status) {
- if (status != BT_STATUS_SUCCESS) {
- LOG(INFO) << "HAL REQUEST FAILED status : " << status << " ("
- << dump_bt_status(status) << ")";
- } else {
- LOG(INFO) << "HAL REQUEST SUCCESS";
- }
-}
-
-static void adapter_state_changed(bt_state_t state) {
- int V1 = 1000, V2 = 2;
- bt_property_t property = {BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT, 4, &V1};
- bt_property_t property1 = {BT_PROPERTY_ADAPTER_SCAN_MODE, 2, &V2};
- bt_property_t property2 = {BT_PROPERTY_BDNAME, 6, (void*)"Fluoride_Test"};
-
- global_adapter_state = state;
-
- if (state == BT_STATE_ON) {
- global_bt_enabled = true;
- global_status = (bt_status_t)sBtInterface->set_adapter_property(&property1);
- global_status = (bt_status_t)sBtInterface->set_adapter_property(&property);
- global_status = (bt_status_t)sBtInterface->set_adapter_property(&property2);
- } else {
- global_bt_enabled = false;
- }
-}
-
-static void adapter_properties_changed(bt_status_t status, int num_properties,
- bt_property_t* properties) {
- RawAddress bd_addr;
- if (!properties) {
- printf("properties is null\n");
- return;
- }
- switch (properties->type) {
- case BT_PROPERTY_BDADDR:
- memcpy(bd_addr.address, properties->val,
- MIN((size_t)properties->len, sizeof(bd_addr)));
- LOG(INFO) << "Local Bd Addr = " << bd_addr;
- break;
- default:
- break;
- }
- return;
-}
-
-static void discovery_state_changed(bt_discovery_state_t state) {
- LOG(INFO) << "Discovery State Updated: "
- << (state == BT_DISCOVERY_STOPPED ? "STOPPED" : "STARTED");
-}
-
-static void pin_request_cb(RawAddress* remote_bd_addr, bt_bdname_t* bd_name,
- uint32_t cod, bool min_16_digit) {
- bt_pin_code_t pincode = {{0x31, 0x32, 0x33, 0x34}};
-
- if (BT_STATUS_SUCCESS !=
- sBtInterface->pin_reply(remote_bd_addr, true, 4, &pincode)) {
- LOG(INFO) << "Pin Reply failed";
- }
-}
-
-static void ssp_request_cb(RawAddress* remote_bd_addr, bt_bdname_t* bd_name,
- uint32_t cod, bt_ssp_variant_t pairing_variant,
- uint32_t pass_key) {
- LOG(INFO) << __func__ << ": device_name:" << bd_name->name
- << ", pairing_variant: " << (int)pairing_variant
- << ", passkey: " << unsigned(pass_key);
- if (BT_STATUS_SUCCESS !=
- sBtInterface->ssp_reply(remote_bd_addr, pairing_variant, true,
- pass_key)) {
- LOG(ERROR) << "SSP Reply failed";
- }
-}
-
-static void bond_state_changed_cb(bt_status_t status,
- RawAddress* remote_bd_addr,
- bt_bond_state_t state) {
- LOG(INFO) << "Bond State Changed = " << state;
- global_pair_state = state;
-}
-
-static void acl_state_changed(bt_status_t status, RawAddress* remote_bd_addr,
- bt_acl_state_t state) {
- LOG(INFO) << __func__ << ": remote_bd_addr=" << *remote_bd_addr
- << ", acl status=" << (state == BT_ACL_STATE_CONNECTED
- ? "ACL Connected"
- : "ACL Disconnected");
-}
-
-static void dut_mode_recv(uint16_t opcode, uint8_t* buf, uint8_t len) {
- LOG(INFO) << "DUT MODE RECV : NOT IMPLEMENTED";
-}
-
-static bt_callbacks_t bt_callbacks = {
- sizeof(bt_callbacks_t),
- adapter_state_changed,
- adapter_properties_changed, /*adapter_properties_cb */
- nullptr, /* remote_device_properties_cb */
- nullptr, /* device_found_cb */
- discovery_state_changed, /* discovery_state_changed_cb */
- pin_request_cb, /* pin_request_cb */
- ssp_request_cb, /* ssp_request_cb */
- bond_state_changed_cb, /*bond_state_changed_cb */
- acl_state_changed, /* acl_state_changed_cb */
- nullptr, /* thread_evt_cb */
- dut_mode_recv, /*dut_mode_recv_cb */
- nullptr, /* le_test_mode_cb */
- nullptr /* energy_info_cb */
-};
-
-static bool set_wake_alarm(uint64_t delay_millis, bool should_wake, alarm_cb cb,
- void* data) {
- static timer_t timer;
- static bool timer_created;
-
- if (!timer_created) {
- struct sigevent sigevent;
- memset(&sigevent, 0, sizeof(sigevent));
- sigevent.sigev_notify = SIGEV_THREAD;
- sigevent.sigev_notify_function = (void (*)(union sigval))cb;
- sigevent.sigev_value.sival_ptr = data;
- timer_create(CLOCK_MONOTONIC, &sigevent, &timer);
- timer_created = true;
- }
-
- struct itimerspec new_value;
- new_value.it_value.tv_sec = delay_millis / 1000;
- new_value.it_value.tv_nsec = (delay_millis % 1000) * 1000 * 1000;
- new_value.it_interval.tv_sec = 0;
- new_value.it_interval.tv_nsec = 0;
- timer_settime(timer, 0, &new_value, nullptr);
-
- return true;
-}
-
-static int acquire_wake_lock(const char* lock_name) {
- return BT_STATUS_SUCCESS;
-}
-
-static int release_wake_lock(const char* lock_name) {
- return BT_STATUS_SUCCESS;
-}
-
-static bt_os_callouts_t callouts = {
- sizeof(bt_os_callouts_t), set_wake_alarm, acquire_wake_lock,
- release_wake_lock,
-};
-
-void adapter_init(void) {
- LOG(INFO) << __func__;
- global_status = (bt_status_t)sBtInterface->init(&bt_callbacks);
- if (global_status == BT_STATUS_SUCCESS) {
- global_status = (bt_status_t)sBtInterface->set_os_callouts(&callouts);
- }
- check_return_status(global_status);
-}
-
-void adapter_enable(void) {
- LOG(INFO) << __func__;
- if (global_bt_enabled) {
- LOG(INFO) << __func__ << ": Bluetooth is already enabled";
- return;
- }
- global_status = (bt_status_t)sBtInterface->enable(global_strict_mode);
- check_return_status(global_status);
-}
-
-void adapter_disable(void) {
- LOG(INFO) << __func__;
- if (!global_bt_enabled) {
- LOG(INFO) << __func__ << ": Bluetooth is already disabled";
- return;
- }
- global_status = (bt_status_t)sBtInterface->disable();
- check_return_status(global_status);
-}
-void adapter_dut_mode_configure(char* p) {
- LOG(INFO) << __func__;
- if (!global_bt_enabled) {
- LOG(INFO) << __func__
- << ": Bluetooth must be enabled for test_mode to work.";
- return;
- }
- int32_t mode = get_signed_int(&p, -1); // arg1
- if ((mode != 0) && (mode != 1)) {
- LOG(INFO) << __func__ << "Please specify mode: 1 to enter, 0 to exit";
- return;
- }
- global_status = (bt_status_t)sBtInterface->dut_mode_configure(mode);
- check_return_status(global_status);
-}
-
-void adapter_cleanup(void) {
- LOG(INFO) << __func__;
- sBtInterface->cleanup();
-}
-
-/*******************************************************************************
- ** Console commands
- *******************************************************************************/
-
-void do_help(char* p) {
- int i = 0;
- char line[128];
- int pos = 0;
-
- while (console_cmd_list[i].name != nullptr) {
- pos = snprintf(line, sizeof(line), "%s", (char*)console_cmd_list[i].name);
- printf("%s %s\n", (char*)line, (char*)console_cmd_list[i].help);
- i++;
- }
-}
-
-void do_quit(char* p) { console_shutdown(); }
-
-/*******************************************************************
- *
- * BT TEST CONSOLE COMMANDS
- *
- * Parses argument lists and passes to API test function
- *
- */
-
-void do_init(char* p) { adapter_init(); }
-
-void do_enable(char* p) { adapter_enable(); }
-
-void do_disable(char* p) { adapter_disable(); }
-
-void do_cleanup(char* p) { adapter_cleanup(); }
-
-/**
- * MCAP API commands
- */
-void do_mcap_register(char* p) {
- uint16_t ctrl_psm = get_hex(&p, 0); // arg1
- uint16_t data_psm = get_hex(&p, 0); // arg2
- uint16_t sec_mask = get_int(&p, 0); // arg3
- printf("%s: ctrl_psm=0x%04x, data_psm=0x%04x, sec_mask=0x%04x\n", __func__,
- ctrl_psm, data_psm, sec_mask);
- if (!ctrl_psm || !data_psm) {
- printf("%s: Invalid Parameters\n", __func__);
- return;
- }
- sMcapTestApp->Register(ctrl_psm, data_psm, sec_mask, mcap_ctrl_callback);
- printf("%s: mcap_handle=%d\n", __func__, sMcapTestApp->GetHandle());
-}
-
-void do_mcap_deregister(char* p) {
- printf("%s: mcap_handle=%d\n", __func__, sMcapTestApp->GetHandle());
- sMcapTestApp->Deregister();
- printf("%s: handle=%d\n", __func__, sMcapTestApp->GetHandle());
-}
-
-void do_mcap_create_mdep(char* p) {
- int type = get_int(&p, -1); // arg1
- printf("%s: mcap_handle=%d, type=%d\n", __func__, sMcapTestApp->GetHandle(),
- type);
- bool ret = sMcapTestApp->CreateMdep(type, MCA_NUM_MDLS, mcap_data_cb);
- printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL");
-}
-
-static void do_mcap_delete_mdep(char* p) {
- uint8_t mdep_handle = get_int(&p, 0);
- printf("%s: mcap_handle=%d, mdep_handle=%d\n", __func__,
- sMcapTestApp->GetHandle(), mdep_handle);
- if (!mdep_handle) {
- printf("%s: Invalid Parameters\n", __func__);
- return;
- }
- McapMdep* mcap_mdep = sMcapTestApp->FindMdepByHandle(mdep_handle);
- if (!mcap_mdep) {
- LOG(ERROR) << "No MDEP for handle " << (int)mdep_handle;
- return;
- }
- bool ret = mcap_mdep->Delete();
- printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL");
-}
-
-static void do_mcap_connect_mcl(char* p) {
- char buf[64];
- get_str(&p, buf); // arg1
- RawAddress bd_addr;
- bool valid_bd_addr = RawAddress::FromString(buf, bd_addr);
- uint16_t ctrl_psm = get_hex(&p, 0); // arg2
- uint16_t sec_mask = get_int(&p, 0); // arg3
- printf("%s: mcap_handle=%d, ctrl_psm=0x%04x, secMask=0x%04x, bd_addr=%s\n",
- __func__, sMcapTestApp->GetHandle(), ctrl_psm, sec_mask, buf);
- if (!ctrl_psm || !valid_bd_addr) {
- printf("%s: Invalid Parameters\n", __func__);
- return;
- }
- bool ret = sMcapTestApp->ConnectMcl(bd_addr, ctrl_psm, sec_mask);
- printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL");
-}
-
-static void do_mcap_disconnect_mcl(char* p) {
- char buf[64];
- get_str(&p, buf); // arg1
- RawAddress bd_addr;
- bool valid_bd_addr = RawAddress::FromString(buf, bd_addr);
- printf("%s: bd_addr=%s\n", __func__, buf);
- if (!valid_bd_addr) {
- printf("%s: Invalid Parameters\n", __func__);
- return;
- }
- McapMcl* mcap_mcl = sMcapTestApp->FindMclByPeerAddress(bd_addr);
- if (!mcap_mcl) {
- LOG(ERROR) << "No MCL for bd_addr " << buf;
- return;
- }
- bool ret = mcap_mcl->Disconnect();
- printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL");
-}
-
-static void do_mcap_create_mdl(char* p) {
- char buf[64];
- get_str(&p, buf); // arg1
- RawAddress bd_addr;
- bool valid_bd_addr = RawAddress::FromString(buf, bd_addr);
- uint16_t mdep_handle = get_int(&p, 0); // arg2
- uint16_t data_psm = get_hex(&p, 0); // arg3
- uint16_t mdl_id = get_int(&p, 0); // arg4
- uint8_t peer_dep_id = get_int(&p, 0); // arg5
- uint8_t cfg = get_hex(&p, 0); // arg6
- int do_not_connect = get_int(&p, 0); // arg7
- printf(
- "%s: bd_addr=%s, mdep_handle=%d, data_psm=0x%04x, mdl_id=%d,"
- " peer_dep_id=%d, cfg=0x%02x, do_not_connect=%d\n",
- __func__, buf, mdep_handle, data_psm, mdl_id, peer_dep_id, cfg,
- do_not_connect);
- if (!data_psm || !peer_dep_id || !valid_bd_addr || !mdep_handle) {
- printf("%s: Invalid Parameters\n", __func__);
- return;
- }
- McapMcl* mcap_mcl = sMcapTestApp->FindMclByPeerAddress(bd_addr);
- if (!mcap_mcl) {
- LOG(ERROR) << "No MCL for bd_addr " << buf;
- return;
- }
- bool ret = mcap_mcl->CreateMdl(mdep_handle, data_psm, mdl_id, peer_dep_id,
- cfg, !do_not_connect);
- printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL");
-}
-
-static void do_mcap_data_channel_config(char* p) {
- char buf[64];
- get_str(&p, buf); // arg1
- RawAddress bd_addr;
- bool valid_bd_addr = RawAddress::FromString(buf, bd_addr);
- printf("%s: bd_addr=%s\n", __func__, buf);
- if (!valid_bd_addr) {
- printf("%s: Invalid Parameters\n", __func__);
- return;
- }
- McapMcl* mcap_mcl = sMcapTestApp->FindMclByPeerAddress(bd_addr);
- if (!mcap_mcl) {
- LOG(ERROR) << "No MCL for bd_addr " << buf;
- return;
- }
- bool ret = mcap_mcl->DataChannelConfig();
- printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL");
-}
-
-static void do_mcap_abort_mdl(char* p) {
- char buf[64];
- get_str(&p, buf); // arg1
- RawAddress bd_addr;
- bool valid_bd_addr = RawAddress::FromString(buf, bd_addr);
- printf("%s: bd_addr=%s\n", __func__, buf);
- if (!valid_bd_addr) {
- printf("%s: Invalid Parameters\n", __func__);
- return;
- }
- McapMcl* mcap_mcl = sMcapTestApp->FindMclByPeerAddress(bd_addr);
- if (!mcap_mcl) {
- LOG(ERROR) << "No MCL for bd_addr " << buf;
- return;
- }
- bool ret = mcap_mcl->AbortMdl();
- printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL");
-}
-
-static void do_mcap_delete_mdl(char* p) {
- char buf[64];
- get_str(&p, buf); // arg1
- RawAddress bd_addr;
- bool valid_bd_addr = RawAddress::FromString(buf, bd_addr);
- uint16_t mdl_id = get_int(&p, 0); // arg2
- printf("%s: bd_addr=%s, mdl_id=%d\n", __func__, buf, mdl_id);
- if (!valid_bd_addr) {
- printf("%s: Invalid Parameters\n", __func__);
- return;
- }
- McapMcl* mcap_mcl = sMcapTestApp->FindMclByPeerAddress(bd_addr);
- if (!mcap_mcl) {
- LOG(ERROR) << "No MCL for bd_addr " << buf;
- return;
- }
- bool ret = mcap_mcl->DeleteMdl(mdl_id);
- printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL");
-}
-
-static void do_mcap_close_mdl(char* p) {
- char buf[64];
- get_str(&p, buf); // arg1
- RawAddress bd_addr;
- bool valid_bd_addr = RawAddress::FromString(buf, bd_addr);
- uint16_t mdl_id = get_int(&p, 0); // arg2
- printf("%s: bd_addr=%s, mdl_id=%d\n", __func__, buf, mdl_id);
- if (!valid_bd_addr || !mdl_id) {
- printf("%s: Invalid Parameters\n", __func__);
- return;
- }
- McapMcl* mcap_mcl = sMcapTestApp->FindMclByPeerAddress(bd_addr);
- if (!mcap_mcl) {
- LOG(ERROR) << "No MCL for bd_addr " << buf;
- return;
- }
- McapMdl* mcap_mdl = mcap_mcl->FindMdlById(mdl_id);
- if (!mcap_mdl) {
- LOG(ERROR) << "No MDL for ID " << (int)mdl_id;
- return;
- }
- bool ret = mcap_mdl->Close();
- printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL");
-}
-
-static void do_mcap_reconnect_mdl(char* p) {
- char buf[64];
- get_str(&p, buf); // arg1
- RawAddress bd_addr;
- bool valid_bd_addr = RawAddress::FromString(buf, bd_addr);
- uint16_t data_psm = get_hex(&p, 0); // arg1
- uint16_t mdl_id = get_int(&p, 0); // arg2
- printf("%s: data_psm=0x%04x, mdl_id=%d\n", __func__, data_psm, mdl_id);
- if (!valid_bd_addr) {
- printf("%s: Invalid Parameters\n", __func__);
- return;
- }
- McapMcl* mcap_mcl = sMcapTestApp->FindMclByPeerAddress(bd_addr);
- if (!mcap_mcl) {
- LOG(ERROR) << "No MCL for bd_addr " << buf;
- return;
- }
- McapMdl* mcap_mdl = mcap_mcl->FindMdlById(mdl_id);
- if (!mcap_mdl) {
- LOG(ERROR) << "No MDL for ID " << (int)mdl_id;
- return;
- }
- bool ret = mcap_mdl->Reconnect(data_psm);
- printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL");
-}
-
-static void do_pairing(char* p) {
- RawAddress bd_addr;
- if (!RawAddress::FromString(p, bd_addr)) {
- LOG(ERROR) << "Invalid Bluetooth address " << p;
- return;
- }
- if (BT_STATUS_SUCCESS !=
- sBtInterface->create_bond(&bd_addr, BT_TRANSPORT_BR_EDR)) {
- LOG(ERROR) << "Failed to Initiate Pairing";
- return;
- }
-}
-
-/** CONSOLE COMMAND TABLE */
-
-const cmd_t console_cmd_list[] = {
- /* INTERNAL */
- {"help", do_help, "", 0},
- {"quit", do_quit, "", 0},
- /* API CONSOLE COMMANDS */
- /* Init and Cleanup shall be called automatically */
- {"enable_bluetooth", do_enable, "", 0},
- {"disable_bluetooth", do_disable, "", 0},
- {"pair", do_pairing, "BD_ADDR<xx:xx:xx:xx:xx:xx>", 0},
- {"register", do_mcap_register,
- "ctrl_psm<hex> data_psm<hex> security_mask<0-10>", 0},
- {"deregister", do_mcap_deregister, "", 0},
- {"create_mdep", do_mcap_create_mdep, "type<0-Echo, 1-Normal>", 0},
- {"delete_mdep", do_mcap_delete_mdep, "mdep_handle<int>", 0},
- {"connect_mcl", do_mcap_connect_mcl,
- "BD_ADDR<xx:xx:xx:xx:xx:xx> ctrl_psm<hex> security_mask<0-10>", 0},
- {"disconnect_mcl", do_mcap_disconnect_mcl, "BD_ADDR<xx:xx:xx:xx:xx:xx>", 0},
- {"create_mdl", do_mcap_create_mdl,
- "BD_ADDR<xx:xx:xx:xx:xx:xx> mdep_handle<int> data_psm<hex> mdl_id<int> "
- "peer_dep_id<int> cfg<hex> "
- "do_not_connect<0-connect,1-wait_for_data_channel_config>",
- 0},
- {"data_channel_config", do_mcap_data_channel_config,
- "BD_ADDR<xx:xx:xx:xx:xx:xx>", 0},
- {"abort_mdl", do_mcap_abort_mdl, "BD_ADDR<xx:xx:xx:xx:xx:xx>", 0},
- {"close_mdl", do_mcap_close_mdl, "BD_ADDR<xx:xx:xx:xx:xx:xx> mdl_id<int>",
- 0},
- {"delete_mdl", do_mcap_delete_mdl, "BD_ADDR<xx:xx:xx:xx:xx:xx> mdl_id<int>",
- 0},
- {"reconnect_mdl", do_mcap_reconnect_mdl,
- "BD_ADDR<xx:xx:xx:xx:xx:xx> data_psm<hex> mdl_id<int>", 0},
- /* last entry */
- {nullptr, nullptr, "", 0},
-};
-
-/** Main console command handler */
-
-static void process_cmd(char* p, bool is_job) {
- char cmd[2048];
- int i = 0;
- char* p_saved = p;
-
- get_str(&p, cmd); // arg1
-
- /* table commands */
- while (console_cmd_list[i].name != nullptr) {
- if (is_cmd(cmd, console_cmd_list[i].name)) {
- if (!is_job && console_cmd_list[i].is_job)
- create_cmdjob(p_saved);
- else {
- console_cmd_list[i].handler(p);
- }
- return;
- }
- i++;
- }
- LOG(ERROR) << "Unknown command: " << p_saved;
- do_help(nullptr);
-}
-
-int main(int argc, char* argv[]) {
- setbuf(stdout, NULL);
-#if !defined(OS_GENERIC)
- config_permissions();
-#endif
- LOG(INFO) << "Fluoride MCAP test app is starting";
-
- if (HAL_load() < 0) {
- fprintf(stderr, "%s: HAL failed to initialize, exit\n", __func__);
- unlink(PID_FILE);
- exit(0);
- }
-
- setup_test_env();
-
- /* Automatically perform the init */
- adapter_init();
- sleep(2);
- adapter_enable();
- sleep(2);
- sMcapTestInterface =
- (btmcap_test_interface_t*)sBtInterface->get_profile_interface(
- BT_TEST_INTERFACE_MCAP_ID);
- sMcapTestInterface->init();
- sMcapTestApp = new McapTestApp(sMcapTestInterface);
-
- /* Main loop */
- char line[2048];
- while (!global_main_done) {
- memset(line, '\0', sizeof(line));
- /* command prompt */
- printf(">");
- fflush(stdout);
- fgets(line, sizeof(line), stdin);
- if (line[0] != '\0') {
- /* Remove line feed */
- line[strlen(line) - 1] = 0;
- if (strlen(line) != 0) process_cmd(line, false);
- }
- }
- adapter_cleanup();
- HAL_unload();
- LOG(INFO) << "Fluoride MCAP test app is terminating";
-
- return 0;
-}
diff --git a/tools/scripts/dump_hearingaid_audio.py b/tools/scripts/dump_hearingaid_audio.py
new file mode 100755
index 0000000..ca2eed2
--- /dev/null
+++ b/tools/scripts/dump_hearingaid_audio.py
@@ -0,0 +1,632 @@
+#!/usr/bin/env python
+# Copyright 2018 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.
+#
+#
+#
+#
+# This script extracts Hearing Aid audio data from btsnoop.
+# Generates a valid audio file which can be played using player like smplayer.
+#
+# Audio File Name Format:
+# [PEER_ADDRESS]-[START_TIMESTAMP]-[AUDIO_TYPE]-[SAMPLE_RATE].[CODEC]
+#
+# Debug Infomation File Name Format:
+# debug_ver_[DEBUG_VERSION]-[PEER_ADDRESS]-[START_TIMESTAMP]-[AUDIO_TYPE]-[SAMPLE_RATE].txt
+#
+# Player:
+# smplayer
+#
+# NOTE:
+# Please make sure you HCI Snoop data file includes the following frames:
+# HearingAid "LE Enhanced Connection Complete", GATT write for Audio Control
+# Point with "Start cmd", and the data frames.
+
+import argparse
+import os
+import struct
+import sys
+import time
+
+IS_SENT = "IS_SENT"
+PEER_ADDRESS = "PEER_ADDRESS"
+CONNECTION_HANDLE = "CONNECTION_HANDLE"
+AUDIO_CONTROL_ATTR_HANDLE = "AUDIO_CONTROL_ATTR_HANDLE"
+START = "START"
+TIMESTAMP_STR_FORMAT = "TIMESTAMP_STR_FORMAT"
+TIMESTAMP_TIME_FORMAT = "TIMESTAMP_TIME_FORMAT"
+CODEC = "CODEC"
+SAMPLE_RATE = "SAMPLE_RATE"
+AUDIO_TYPE = "AUDIO_TYPE"
+DEBUG_VERSION = "DEBUG_VERSION"
+DEBUG_DATA = "DEBUG_DATA"
+AUDIO_DATA_B = "AUDIO_DATA_B"
+
+# Debug packet header struct
+header_list_str = ["Event Processed",
+ "Number Packet Nacked By Slave",
+ "Number Packet Nacked By Master"]
+# Debug frame information structs
+data_list_str = ["Event Number",
+ "Overrun",
+ "Underrun",
+ "Skips",
+ "Rendered Audio Frame",
+ "First PDU Option",
+ "Second PDU Option",
+ "Third PDU Option"]
+
+AUDIO_CONTROL_POINT_UUID = "f0d4de7e4a88476c9d9f1937b0996cc0"
+SEC_CONVERT = 1000000
+folder = None
+full_debug = False
+simple_debug = False
+
+force_audio_control_attr_handle = None
+default_audio_control_attr_handle = 0x0079
+
+audio_data = {}
+
+#=======================================================================
+# Parse ACL Data Function
+#=======================================================================
+
+#-----------------------------------------------------------------------
+# Parse Hearing Aid Packet
+#-----------------------------------------------------------------------
+
+def parse_acl_ha_debug_buffer(data, result):
+ """This function extracts HA debug buffer"""
+ if len(data) < 5:
+ return
+
+ version, data = unpack_data(data, 1)
+ update_audio_data(CONNECTION_HANDLE, result[CONNECTION_HANDLE], DEBUG_VERSION, str(version))
+
+ debug_str = result[TIMESTAMP_TIME_FORMAT];
+ for p in range(3):
+ byte_data, data = unpack_data(data, 1)
+ debug_str = debug_str + ", " + header_list_str[p] + "=" + str(byte_data).rjust(3)
+
+ if full_debug:
+ debug_str = debug_str + "\n" + "|".join(data_list_str) + "\n"
+ while True:
+ if len(data) < 7:
+ break
+ base = 0
+ data_list_content = []
+ for counter in range(6):
+ p = base + counter
+ byte_data, data = unpack_data(data, 1)
+ if p == 1:
+ data_list_content.append(str(byte_data & 0x03).rjust(len(data_list_str[p])))
+ data_list_content.append(str((byte_data >> 2) & 0x03).rjust(len(data_list_str[p + 1])))
+ data_list_content.append(str((byte_data >> 4) & 0x0f).rjust(len(data_list_str[p + 2])))
+ base = 2
+ else:
+ data_list_content.append(str(byte_data).rjust(len(data_list_str[p])))
+ debug_str = debug_str + "|".join(data_list_content) + "\n"
+
+ update_audio_data(CONNECTION_HANDLE, result[CONNECTION_HANDLE], DEBUG_DATA, debug_str)
+
+def parse_acl_ha_audio_data(data, result):
+ """This function extracts HA audio data."""
+ if len(data) < 2:
+ return
+ # Remove audio packet number
+ audio_data_b = data[1:]
+ update_audio_data(CONNECTION_HANDLE, result[CONNECTION_HANDLE],
+ AUDIO_DATA_B, audio_data_b)
+
+
+def parse_acl_ha_audio_type(data, result):
+ """This function parses HA audio control cmd audio type."""
+ audio_type, data = unpack_data(data, 1)
+ if audio_type is None:
+ return
+ elif audio_type == 0x01:
+ audio_type = "Ringtone"
+ elif audio_type == 0x02:
+ audio_type = "Phonecall"
+ elif audio_type == 0x03:
+ audio_type = "Media"
+ else:
+ audio_type = "Unknown"
+ update_audio_data(CONNECTION_HANDLE, result[CONNECTION_HANDLE],
+ AUDIO_TYPE, audio_type)
+
+
+def parse_acl_ha_codec(data, result):
+ """This function parses HA audio control cmd codec and sample rate."""
+ codec, data = unpack_data(data, 1)
+ if codec == 0x01:
+ codec = "G722"
+ sample_rate = "16KHZ"
+ elif codec == 0x02:
+ codec = "G722"
+ sample_rate = "24KHZ"
+ else:
+ codec = "Unknown"
+ sample_rate = "Unknown"
+ update_audio_data(CONNECTION_HANDLE, result[CONNECTION_HANDLE],
+ CODEC, codec)
+ update_audio_data(CONNECTION_HANDLE, result[CONNECTION_HANDLE],
+ SAMPLE_RATE, sample_rate)
+ parse_acl_ha_audio_type(data, result)
+
+
+def parse_acl_ha_audio_control_cmd(data, result):
+ """This function parses HA audio control cmd is start/stop."""
+ control_cmd, data = unpack_data(data, 1)
+ if control_cmd == 0x01:
+ update_audio_data(CONNECTION_HANDLE, result[CONNECTION_HANDLE],
+ START, True)
+ update_audio_data(CONNECTION_HANDLE, result[CONNECTION_HANDLE],
+ TIMESTAMP_STR_FORMAT, result[TIMESTAMP_STR_FORMAT])
+ parse_acl_ha_codec(data, result)
+ elif control_cmd == 0x02:
+ update_audio_data(CONNECTION_HANDLE, result[CONNECTION_HANDLE],
+ START, False)
+
+
+#-----------------------------------------------------------------------
+# Parse ACL Packet
+#-----------------------------------------------------------------------
+
+def parse_acl_att_long_uuid(data, result):
+ """This function parses ATT long UUID to get attr_handle."""
+ # len (1 byte) + start_attr_handle (2 bytes) + properties (1 byte) +
+ # attr_handle (2 bytes) + long_uuid (16 bytes) = 22 bytes
+ if len(data) < 22:
+ return
+ # skip unpack len, start_attr_handle, properties.
+ data = data[4:]
+ attr_handle, data = unpack_data(data, 2)
+ long_uuid_list = []
+ for p in range(0, 16):
+ long_uuid_list.append("{0:02x}".format(struct.unpack(">B", data[p])[0]))
+ long_uuid_list.reverse()
+ long_uuid = "".join(long_uuid_list)
+ # Check long_uuid is AUDIO_CONTROL_POINT uuid to get the attr_handle.
+ if long_uuid == AUDIO_CONTROL_POINT_UUID:
+ update_audio_data(CONNECTION_HANDLE, result[CONNECTION_HANDLE],
+ AUDIO_CONTROL_ATTR_HANDLE, attr_handle)
+
+
+def parse_acl_opcode(data, result):
+ """This function parses acl data opcode."""
+ # opcode (1 byte) = 1 bytes
+ if len(data) < 1:
+ return
+ opcode, data = unpack_data(data, 1)
+ # Check opcode is 0x12 (write request) and attr_handle is
+ # audio_control_attr_handle for check it is HA audio control cmd.
+ if result[IS_SENT] and opcode == 0x12:
+ if len(data) < 2:
+ return
+ attr_handle, data = unpack_data(data, 2)
+ if attr_handle == \
+ get_audio_control_attr_handle(result[CONNECTION_HANDLE]):
+ parse_acl_ha_audio_control_cmd(data, result)
+ # Check opcode is 0x09 (read response) to parse ATT long UUID.
+ elif not result[IS_SENT] and opcode == 0x09:
+ parse_acl_att_long_uuid(data, result)
+
+
+def parse_acl_handle(data, result):
+ """This function parses acl data handle."""
+ # connection_handle (2 bytes) + total_len (2 bytes) + pdu (2 bytes)
+ # + channel_id (2 bytes) = 8 bytes
+ if len(data) < 8:
+ return
+ connection_handle, data = unpack_data(data, 2)
+ connection_handle = connection_handle & 0x0FFF
+ # skip unpack total_len
+ data = data[2:]
+ pdu, data = unpack_data(data, 2)
+ channel_id, data = unpack_data(data, 2)
+
+ # Check ATT packet or "Coc Data Packet" to get ATT information and audio
+ # data.
+ if connection_handle <= 0x0EFF:
+ if channel_id <= 0x003F:
+ result[CONNECTION_HANDLE] = connection_handle
+ parse_acl_opcode(data, result)
+ elif channel_id >= 0x0040 and channel_id <= 0x007F:
+ result[CONNECTION_HANDLE] = connection_handle
+ sdu, data = unpack_data(data, 2)
+ if pdu - 2 == sdu:
+ if result[IS_SENT]:
+ parse_acl_ha_audio_data(data, result)
+ else:
+ if simple_debug:
+ parse_acl_ha_debug_buffer(data, result)
+
+
+#=======================================================================
+# Parse HCI EVT Function
+#=======================================================================
+
+
+def parse_hci_evt_peer_address(data, result):
+ """This function parses peer address from hci event."""
+ peer_address_list = []
+ address_empty_list = ["00", "00", "00", "00", "00", "00"]
+ for n in range(0, 3):
+ if len(data) < 6:
+ return
+ for p in range(0, 6):
+ peer_address_list.append("{0:02x}".format(struct.unpack(">B",
+ data[p])[0]))
+ # Check the address is empty or not.
+ if peer_address_list == address_empty_list:
+ del peer_address_list[:]
+ data = data[6:]
+ else:
+ break
+ peer_address_list.reverse()
+ peer_address = "_".join(peer_address_list)
+ update_audio_data("", "", PEER_ADDRESS, peer_address)
+ update_audio_data(PEER_ADDRESS, peer_address, CONNECTION_HANDLE,
+ result[CONNECTION_HANDLE])
+
+
+def parse_hci_evt_code(data, result):
+ """This function parses hci event content."""
+ # hci_evt (1 byte) + param_total_len (1 byte) + sub_event (1 byte)
+ # + status (1 byte) + connection_handle (2 bytes) + role (1 byte)
+ # + address_type (1 byte) = 8 bytes
+ if len(data) < 8:
+ return
+ hci_evt, data = unpack_data(data, 1)
+ # skip unpack param_total_len.
+ data = data[1:]
+ sub_event, data = unpack_data(data, 1)
+ status, data = unpack_data(data, 1)
+ connection_handle, data = unpack_data(data, 2)
+ connection_handle = connection_handle & 0x0FFF
+ # skip unpack role, address_type.
+ data = data[2:]
+ # We will directly check it is LE Enhanced Connection Complete or not
+ # for get Connection Handle and Address.
+ if not result[IS_SENT] and hci_evt == 0x3E and sub_event == 0x0A \
+ and status == 0x00 and connection_handle <= 0x0EFF:
+ result[CONNECTION_HANDLE] = connection_handle
+ parse_hci_evt_peer_address(data, result)
+
+
+#=======================================================================
+# Common Parse Function
+#=======================================================================
+
+
+def parse_packet_data(data, result):
+ """This function parses packet type."""
+ packet_type, data = unpack_data(data, 1)
+ if packet_type == 0x02:
+ # Try to check HearingAid audio control packet and data packet.
+ parse_acl_handle(data, result)
+ elif packet_type == 0x04:
+ # Try to check HearingAid connection successful packet.
+ parse_hci_evt_code(data, result)
+
+
+def parse_packet(btsnoop_file):
+ """This function parses packet len, timestamp."""
+ packet_result = {}
+
+ # ori_len (4 bytes) + include_len (4 bytes) + packet_flag (4 bytes)
+ # + drop (4 bytes) + timestamp (8 bytes) = 24 bytes
+ packet_header = btsnoop_file.read(24)
+ if len(packet_header) != 24:
+ return False
+
+ ori_len, include_len, packet_flag, drop, timestamp = \
+ struct.unpack(">IIIIq", packet_header)
+
+ if ori_len == include_len:
+ packet_data = btsnoop_file.read(ori_len)
+ if len(packet_data) != ori_len:
+ return False
+ if packet_flag != 2 and drop == 0:
+ packet_result[IS_SENT] = (packet_flag == 0)
+ packet_result[TIMESTAMP_STR_FORMAT], packet_result[TIMESTAMP_TIME_FORMAT] = convert_time_str(timestamp)
+ parse_packet_data(packet_data, packet_result)
+ else:
+ return False
+
+ return True
+
+
+#=======================================================================
+# Update and DumpData Function
+#=======================================================================
+
+
+def dump_audio_data(data):
+ """This function dumps audio data into file."""
+ file_type = "." + data[CODEC]
+ file_name_list = []
+ file_name_list.append(data[PEER_ADDRESS])
+ file_name_list.append(data[TIMESTAMP_STR_FORMAT])
+ file_name_list.append(data[AUDIO_TYPE])
+ file_name_list.append(data[SAMPLE_RATE])
+ if folder is not None:
+ if not os.path.exists(folder):
+ os.makedirs(folder)
+ audio_file_name = os.path.join(folder, "-".join(file_name_list) + file_type)
+ if data.has_key(DEBUG_VERSION):
+ file_prefix = "debug_ver_" + data[DEBUG_VERSION] + "-"
+ debug_file_name = os.path.join(folder, file_prefix + "-".join(file_name_list) + ".txt")
+ else:
+ audio_file_name = "-".join(file_name_list) + file_type
+ if data.has_key(DEBUG_VERSION):
+ file_prefix = "debug_ver_" + data[DEBUG_VERSION] + "-"
+ debug_file_name = file_prefix + "-".join(file_name_list) + ".txt"
+
+ sys.stdout.write("Start to dump Audio File : %s\n" % audio_file_name)
+ if data.has_key(AUDIO_DATA_B):
+ with open(audio_file_name, "wb+") as audio_file:
+ audio_file.write(data[AUDIO_DATA_B])
+ sys.stdout.write("Finished to dump Audio File: %s\n\n" % audio_file_name)
+ else:
+ sys.stdout.write("Fail to dump Audio File: %s\n" % audio_file_name)
+ sys.stdout.write("There isn't any Hearing Aid audio data.\n\n")
+
+ if simple_debug:
+ sys.stdout.write("Start to dump audio %s Debug File\n" % audio_file_name)
+ if data.has_key(DEBUG_DATA):
+ with open(debug_file_name, "wb+") as debug_file:
+ debug_file.write(data[DEBUG_DATA])
+ sys.stdout.write("Finished to dump Debug File: %s\n\n" % debug_file_name)
+ else:
+ sys.stdout.write("Fail to dump audio %s Debug File\n" % audio_file_name)
+ sys.stdout.write("There isn't any Hearing Aid debug data.\n\n")
+
+
+
+def update_audio_data(relate_key, relate_value, key, value):
+ """
+ This function records the dump audio file related information.
+ audio_data = {
+ PEER_ADDRESS:{
+ PEER_ADDRESS: PEER_ADDRESS,
+ CONNECTION_HANDLE: CONNECTION_HANDLE,
+ AUDIO_CONTROL_ATTR_HANDLE: AUDIO_CONTROL_ATTR_HANDLE,
+ START: True or False,
+ TIMESTAMP_STR_FORMAT: START_TIMESTAMP_STR_FORMAT,
+ CODEC: CODEC,
+ SAMPLE_RATE: SAMPLE_RATE,
+ AUDIO_TYPE: AUDIO_TYPE,
+ DEBUG_VERSION: DEBUG_VERSION,
+ DEBUG_DATA: DEBUG_DATA,
+ AUDIO_DATA_B: AUDIO_DATA_B
+ },
+ PEER_ADDRESS_2:{
+ PEER_ADDRESS: PEER_ADDRESS,
+ CONNECTION_HANDLE: CONNECTION_HANDLE,
+ AUDIO_CONTROL_ATTR_HANDLE: AUDIO_CONTROL_ATTR_HANDLE,
+ START: True or False,
+ TIMESTAMP_STR_FORMAT: START_TIMESTAMP_STR_FORMAT,
+ CODEC: CODEC,
+ SAMPLE_RATE: SAMPLE_RATE,
+ AUDIO_TYPE: AUDIO_TYPE,
+ DEBUG_VERSION: DEBUG_VERSION,
+ DEBUG_DATA: DEBUG_DATA,
+ AUDIO_DATA_B: AUDIO_DATA_B
+ }
+ }
+ """
+ if key == PEER_ADDRESS:
+ if audio_data.has_key(value):
+ # Dump audio data and clear previous data.
+ update_audio_data(key, value, START, False)
+ # Extra clear CONNECTION_HANDLE due to new connection create.
+ if audio_data[value].has_key(CONNECTION_HANDLE):
+ audio_data[value].pop(CONNECTION_HANDLE, "")
+ else:
+ device_audio_data = {key: value}
+ temp_audio_data = {value: device_audio_data}
+ audio_data.update(temp_audio_data)
+ else:
+ for i in audio_data:
+ if audio_data[i].has_key(relate_key) \
+ and audio_data[i][relate_key] == relate_value:
+ if key == START:
+ if audio_data[i].has_key(key) and audio_data[i][key]:
+ dump_audio_data(audio_data[i])
+ # Clear data except PEER_ADDRESS, CONNECTION_HANDLE and
+ # AUDIO_CONTROL_ATTR_HANDLE.
+ audio_data[i].pop(key, "")
+ audio_data[i].pop(TIMESTAMP_STR_FORMAT, "")
+ audio_data[i].pop(CODEC, "")
+ audio_data[i].pop(SAMPLE_RATE, "")
+ audio_data[i].pop(AUDIO_TYPE, "")
+ audio_data[i].pop(DEBUG_VERSION, "")
+ audio_data[i].pop(DEBUG_DATA, "")
+ audio_data[i].pop(AUDIO_DATA_B, "")
+ elif key == AUDIO_DATA_B or key == DEBUG_DATA:
+ if audio_data[i].has_key(START) and audio_data[i][START]:
+ if audio_data[i].has_key(key):
+ ori_data = audio_data[i].pop(key, "")
+ value = ori_data + value
+ else:
+ # Audio doesn't start, don't record.
+ return
+ device_audio_data = {key: value}
+ audio_data[i].update(device_audio_data)
+
+
+#=======================================================================
+# Tool Function
+#=======================================================================
+
+
+def get_audio_control_attr_handle(connection_handle):
+ """This function gets audio_control_attr_handle."""
+ # If force_audio_control_attr_handle is set, will use it first.
+ if force_audio_control_attr_handle is not None:
+ return force_audio_control_attr_handle
+
+ # Try to check the audio_control_attr_handle is record into audio_data.
+ for i in audio_data:
+ if audio_data[i].has_key(CONNECTION_HANDLE) \
+ and audio_data[i][CONNECTION_HANDLE] == connection_handle:
+ if audio_data[i].has_key(AUDIO_CONTROL_ATTR_HANDLE):
+ return audio_data[i][AUDIO_CONTROL_ATTR_HANDLE]
+
+ # Return default attr_handle if audio_data doesn't record it.
+ return default_audio_control_attr_handle
+
+
+def unpack_data(data, byte):
+ """This function unpacks data."""
+ if byte == 1:
+ value = struct.unpack(">B", data[0])[0]
+ elif byte == 2:
+ value = struct.unpack(">H", data[1]+data[0])[0]
+ else:
+ value = ""
+ data = data[byte:]
+ return value, data
+
+
+def convert_time_str(timestamp):
+ """This function converts time to string format."""
+ really_timestamp = float(timestamp) / SEC_CONVERT
+ local_timestamp = time.localtime(really_timestamp)
+ dt = really_timestamp - long(really_timestamp)
+ ms_str = "{0:06}".format(int(round(dt * 1000000)))
+
+ str_format = time.strftime("%m_%d__%H_%M_%S", local_timestamp)
+ full_str_format = str_format + "_" + ms_str
+
+ time_format = time.strftime("%m-%d %H:%M:%S", local_timestamp)
+ full_time_format = time_format + "." + ms_str
+ return full_str_format, full_time_format
+
+
+def set_config():
+ """This function is for set config by flag and check the argv is correct."""
+ argv_parser = argparse.ArgumentParser(
+ description="Extracts Hearing Aid audio data from BTSNOOP.")
+ argv_parser.add_argument("BTSNOOP", help="BLUETOOTH BTSNOOP file.")
+ argv_parser.add_argument("-f", "--folder", help="select output folder.",
+ dest="folder")
+ argv_parser.add_argument("-c1", "--connection-handle1",
+ help="set a fake connection handle 1 to capture \
+ audio dump.", dest="connection_handle1", type=int)
+ argv_parser.add_argument("-c2", "--connection-handle2",
+ help="set a fake connection handle 2 to capture \
+ audio dump.", dest="connection_handle2", type=int)
+ argv_parser.add_argument("-ns", "--no-start", help="No audio 'Start' cmd is \
+ needed before extracting audio data.",
+ dest="no_start", default="False")
+ argv_parser.add_argument("-dc", "--default-codec", help="set a default \
+ codec.", dest="codec", default="G722")
+ argv_parser.add_argument("-a", "--attr-handle",
+ help="force to select audio control attr handle.",
+ dest="audio_control_attr_handle", type=int)
+ argv_parser.add_argument("-d", "--debug",
+ help="dump full debug buffer content.",
+ dest="full_debug", default="False")
+ argv_parser.add_argument("-sd", "--simple-debug",
+ help="dump debug buffer header content.",
+ dest="simple_debug", default="False")
+ arg = argv_parser.parse_args()
+
+ if arg.folder is not None:
+ global folder
+ folder = arg.folder
+
+ if arg.connection_handle1 is not None and arg.connection_handle2 is not None \
+ and arg.connection_handle1 == arg.connection_handle2:
+ argv_parser.error("connection_handle1 can't be same with \
+ connection_handle2")
+ exit(1)
+
+ if not (arg.no_start.lower() == "true" or arg.no_start.lower() == "false"):
+ argv_parser.error("-ns/--no-start arg is invalid, it should be true/false.")
+ exit(1)
+
+ if arg.connection_handle1 is not None:
+ fake_name = "ConnectionHandle" + str(arg.connection_handle1)
+ update_audio_data("", "", PEER_ADDRESS, fake_name)
+ update_audio_data(PEER_ADDRESS, fake_name, CONNECTION_HANDLE,
+ arg.connection_handle1)
+ if arg.no_start.lower() == "true":
+ update_audio_data(PEER_ADDRESS, fake_name, START, True)
+ update_audio_data(PEER_ADDRESS, fake_name, TIMESTAMP_STR_FORMAT, "Unknown")
+ update_audio_data(PEER_ADDRESS, fake_name, CODEC, arg.codec)
+ update_audio_data(PEER_ADDRESS, fake_name, SAMPLE_RATE, "Unknown")
+ update_audio_data(PEER_ADDRESS, fake_name, AUDIO_TYPE, "Unknown")
+
+ if arg.connection_handle2 is not None:
+ fake_name = "ConnectionHandle" + str(arg.connection_handle2)
+ update_audio_data("", "", PEER_ADDRESS, fake_name)
+ update_audio_data(PEER_ADDRESS, fake_name, CONNECTION_HANDLE,
+ arg.connection_handle2)
+ if arg.no_start.lower() == "true":
+ update_audio_data(PEER_ADDRESS, fake_name, START, True)
+ update_audio_data(PEER_ADDRESS, fake_name, TIMESTAMP_STR_FORMAT, "Unknown")
+ update_audio_data(PEER_ADDRESS, fake_name, CODEC, arg.codec)
+ update_audio_data(PEER_ADDRESS, fake_name, SAMPLE_RATE, "Unknown")
+ update_audio_data(PEER_ADDRESS, fake_name, AUDIO_TYPE, "Unknown")
+
+ if arg.audio_control_attr_handle is not None:
+ global force_audio_control_attr_handle
+ force_audio_control_attr_handle = arg.audio_control_attr_handle
+
+ global full_debug
+ global simple_debug
+ if arg.full_debug.lower() == "true":
+ full_debug = True
+ simple_debug = True
+ elif arg.simple_debug.lower() == "true":
+ simple_debug = True
+
+ if os.path.isfile(arg.BTSNOOP):
+ return arg.BTSNOOP
+ else:
+ argv_parser.error("BTSNOOP file not found: %s" % arg.BTSNOOP)
+ exit(1)
+
+
+def main():
+ btsnoop_file_name = set_config()
+
+ with open(btsnoop_file_name, "rb") as btsnoop_file:
+ identification = btsnoop_file.read(8)
+ if identification != "btsnoop\0":
+ sys.stderr.write(
+ "Check identification fail. It is not correct btsnoop file.")
+ exit(1)
+
+ ver, data_link = struct.unpack(">II", btsnoop_file.read(4 + 4))
+ if (ver != 1) or (data_link != 1002):
+ sys.stderr.write(
+ "Check ver or dataLink fail. It is not correct btsnoop file.")
+ exit(1)
+
+ while True:
+ if not parse_packet(btsnoop_file):
+ break
+
+ for i in audio_data:
+ if audio_data[i].get(START, False):
+ dump_audio_data(audio_data[i])
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tools/scripts/dump_metrics_ascii.py b/tools/scripts/dump_metrics_ascii.py
new file mode 100755
index 0000000..c24d299
--- /dev/null
+++ b/tools/scripts/dump_metrics_ascii.py
@@ -0,0 +1,140 @@
+#!/usr/bin/env python3
+# Copyright 2018 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.
+
+import base64
+import logging
+import os
+import subprocess
+import sys
+import tempfile
+from distutils.spawn import find_executable
+import google.protobuf.text_format as text_format
+from importlib import import_module
+
+def compile_proto(proto_path, output_dir):
+ """Invoke Protocol Compiler to generate python from given source .proto."""
+ # Find compiler path
+ protoc = None
+ if 'PROTOC' in os.environ and os.path.exists(os.environ['PROTOC']):
+ protoc = os.environ['PROTOC']
+ if not protoc:
+ protoc = find_executable('protoc')
+ if not protoc:
+ logging.error(
+ "Cannot find Protobuf compiler (>=3.0.0), please install"
+ "protobuf-compiler package. Prefer copying from <top>/prebuilts/tools"
+ )
+ logging.error(" prebuilts/tools/linux-x86_64/protoc/bin/protoc")
+ logging.error("If prebuilts are not available, use apt-get:")
+ logging.error(" sudo apt-get install protobuf-compiler")
+ return None
+ # Validate input proto path
+ if not os.path.exists(proto_path):
+ logging.error('Can\'t find required file: %s\n' % proto_path)
+ return None
+ # Validate output py-proto path
+ if not os.path.exists(output_dir):
+ os.mkdirs(output_dir)
+ elif not os.path.isdir(output_dir):
+ logging.error("Output path is not a valid directory: %s" %
+ (output_dir))
+ return None
+ input_dir = os.path.dirname(proto_path)
+ output_filename = os.path.basename(proto_path).replace('.proto', '_pb2.py')
+ output_path = os.path.join(output_dir, output_filename)
+ protoc_command = [
+ protoc, '-I=%s' % (input_dir), '--python_out=%s' % (output_dir),
+ proto_path
+ ]
+ if subprocess.call(protoc_command, stderr=subprocess.STDOUT) != 0:
+ logging.error("Fail to compile proto")
+ return None
+ output_module_name = os.path.splitext(output_filename)[0]
+ return output_module_name
+
+
+def compile_import_proto(output_dir, proto_path):
+ """
+ Compile protobuf from PROTO_PATH and put the result in OUTPUT_DIR.
+ Return the imported module to caller.
+ :param output_dir: To store generated python proto library
+ :param proto_path: Path to the .proto file that needs to be compiled
+ :return: python proto module
+ """
+ output_module_name = compile_proto(proto_path, output_dir)
+ if not output_module_name:
+ return None
+ sys.path.append(output_dir)
+ output_module = None
+ try:
+ output_module = import_module(output_module_name)
+ except ImportError:
+ logging.error("Cannot import generated py-proto %s" %
+ (output_module_name))
+ return output_module
+
+
+def parse_proto_to_ascii(binary_proto_msg):
+ """
+ Parse binary protobuf message to human readable ascii string
+ :param binary_proto_msg:
+ :return: ascii string of the message
+ """
+ return text_format.MessageToString(binary_proto_msg)
+
+def dump_metrics():
+ os.system('adb wait-for-device')
+ p = subprocess.Popen("adb shell dumpsys bluetooth_manager --proto-bin",
+ shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+ stdin=subprocess.PIPE)
+ return p.communicate()
+
+def get_bluetooth_metrics(proto_native_str_64, bluetooth_proto_module):
+ bluetooth_log = bluetooth_proto_module.BluetoothLog()
+ proto_native_str = base64.b64decode(proto_native_str_64)
+ bluetooth_log.MergeFromString(proto_native_str)
+ return bluetooth_log
+
+def main():
+ root = logging.getLogger()
+ root.setLevel(logging.DEBUG)
+ log_handler = logging.StreamHandler(sys.stderr)
+ log_handler.setLevel(logging.DEBUG)
+ formatter = logging.Formatter(
+ "%(asctime)s %(levelname)s %(message)s")
+ log_handler.setFormatter(formatter)
+ root.addHandler(log_handler)
+ if len(sys.argv) < 2:
+ logging.error("Not enough arguments. Need at least 2")
+ logging.error("Usage: " + sys.argv[0] + " <path_to_metric_proto>")
+ sys.exit(1)
+ if sys.argv[1] == "-h":
+ logging.info("Usage: " + sys.argv[0] + " <path_to_metric_proto>")
+ logging.info("Requires Protobuf compiler, protoc, version >=3.0.0")
+ sys.exit(0)
+ bluetooth_proto_module = compile_import_proto(tempfile.gettempdir(),
+ sys.argv[1])
+ if not bluetooth_proto_module:
+ logging.error("Cannot compile " + sys.argv[1])
+ sys.exit(1)
+ stdout, stderr = dump_metrics()
+ stdout = stdout.strip()
+ stderr = stderr.strip()
+ bluetooth_log = get_bluetooth_metrics(stdout, bluetooth_proto_module)
+ bluetooth_log_ascii = parse_proto_to_ascii(bluetooth_log)
+ print(bluetooth_log_ascii)
+
+if __name__ == "__main__":
+ main()
diff --git a/types/Android.bp b/types/Android.bp
index 5867d63..444b6ff 100644
--- a/types/Android.bp
+++ b/types/Android.bp
@@ -16,6 +16,7 @@
],
host_supported: true,
srcs: [
+ "class_of_device.cc",
"raw_address.cc",
"bluetooth/uuid.cc",
],
@@ -30,6 +31,7 @@
defaults: ["fluoride_defaults"],
host_supported: true,
srcs: [
+ "test/class_of_device_unittest.cc",
"test/raw_address_unittest.cc",
"test/bluetooth/uuid_unittest.cc",
],
diff --git a/types/BUILD.gn b/types/BUILD.gn
index 617bbb6..fa9a4af 100644
--- a/types/BUILD.gn
+++ b/types/BUILD.gn
@@ -20,8 +20,9 @@
]
sources = [
- "raw_address.cc",
"bluetooth/uuid.cc",
+ "le_address.cc",
+ "raw_address.cc",
]
include_dirs = [
diff --git a/types/class_of_device.cc b/types/class_of_device.cc
new file mode 100644
index 0000000..775a412
--- /dev/null
+++ b/types/class_of_device.cc
@@ -0,0 +1,78 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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 "class_of_device.h"
+
+#include <base/strings/string_split.h>
+#include <base/strings/stringprintf.h>
+#include <stdint.h>
+#include <algorithm>
+#include <vector>
+
+static_assert(sizeof(ClassOfDevice) == ClassOfDevice::kLength,
+ "ClassOfDevice must be 3 bytes long!");
+
+ClassOfDevice::ClassOfDevice(const uint8_t (&class_of_device)[kLength]) {
+ std::copy(class_of_device, class_of_device + kLength, cod);
+};
+
+std::string ClassOfDevice::ToString() const {
+ return base::StringPrintf("%03x-%01x-%02x",
+ (static_cast<uint16_t>(cod[2]) << 4) | cod[1] >> 4,
+ cod[1] & 0x0f, cod[0]);
+}
+
+bool ClassOfDevice::FromString(const std::string& from, ClassOfDevice& to) {
+ ClassOfDevice new_cod;
+ if (from.length() != 8) return false;
+
+ std::vector<std::string> byte_tokens =
+ base::SplitString(from, "-", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+
+ if (byte_tokens.size() != 3) return false;
+ if (byte_tokens[0].length() != 3) return false;
+ if (byte_tokens[1].length() != 1) return false;
+ if (byte_tokens[2].length() != 2) return false;
+
+ uint16_t values[3];
+
+ for (size_t i = 0; i < kLength; i++) {
+ const auto& token = byte_tokens[i];
+
+ char* temp = nullptr;
+ values[i] = strtol(token.c_str(), &temp, 16);
+ if (*temp != '\0') return false;
+ }
+
+ new_cod.cod[0] = values[2];
+ new_cod.cod[1] = values[1] | ((values[0] & 0xf) << 4);
+ new_cod.cod[2] = values[0] >> 4;
+
+ to = new_cod;
+ return true;
+}
+
+size_t ClassOfDevice::FromOctets(const uint8_t* from) {
+ std::copy(from, from + kLength, cod);
+ return kLength;
+};
+
+bool ClassOfDevice::IsValid(const std::string& cod) {
+ ClassOfDevice tmp;
+ return ClassOfDevice::FromString(cod, tmp);
+}
diff --git a/types/class_of_device.h b/types/class_of_device.h
new file mode 100644
index 0000000..8c2ab37
--- /dev/null
+++ b/types/class_of_device.h
@@ -0,0 +1,54 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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>
+
+/** Bluetooth Class of Device */
+class ClassOfDevice final {
+ public:
+ static constexpr unsigned int kLength = 3;
+
+ uint8_t cod[kLength];
+
+ ClassOfDevice() = default;
+ ClassOfDevice(const uint8_t (&class_of_device)[kLength]);
+
+ bool operator==(const ClassOfDevice& rhs) const {
+ return (std::memcmp(cod, rhs.cod, sizeof(cod)) == 0);
+ }
+
+ std::string ToString() const;
+
+ // Converts |string| to ClassOfDevice and places it in |to|. If |from| does
+ // not represent a Class of Device, |to| is not modified and this function
+ // returns false. Otherwise, it returns true.
+ static bool FromString(const std::string& from, ClassOfDevice& to);
+
+ // Copies |from| raw Class of Device octets to the local object.
+ // Returns the number of copied octets (always ClassOfDevice::kLength)
+ size_t FromOctets(const uint8_t* from);
+
+ static bool IsValid(const std::string& class_of_device);
+};
+
+inline std::ostream& operator<<(std::ostream& os, const ClassOfDevice& c) {
+ os << c.ToString();
+ return os;
+}
diff --git a/types/test/class_of_device_unittest.cc b/types/test/class_of_device_unittest.cc
new file mode 100644
index 0000000..5d652a5
--- /dev/null
+++ b/types/test/class_of_device_unittest.cc
@@ -0,0 +1,96 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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 <gtest/gtest.h>
+
+#include "class_of_device.h"
+
+static const char* test_class = "efc-d-ab";
+static const uint8_t test_bytes[]{0xab, 0xcd, 0xef};
+
+TEST(ClassOfDeviceUnittest, test_constructor_array) {
+ ClassOfDevice cod(test_bytes);
+
+ ASSERT_EQ(test_bytes[0], cod.cod[0]);
+ ASSERT_EQ(test_bytes[1], cod.cod[1]);
+ ASSERT_EQ(test_bytes[2], cod.cod[2]);
+
+ std::string ret = cod.ToString();
+
+ ASSERT_STREQ(test_class, ret.c_str());
+}
+
+TEST(ClassOfDeviceUnittest, test_to_from_str) {
+ ClassOfDevice cod;
+ ClassOfDevice::FromString(test_class, cod);
+
+ ASSERT_EQ(test_bytes[0], cod.cod[0]);
+ ASSERT_EQ(test_bytes[1], cod.cod[1]);
+ ASSERT_EQ(test_bytes[2], cod.cod[2]);
+
+ std::string ret = cod.ToString();
+
+ ASSERT_STREQ(test_class, ret.c_str());
+}
+
+TEST(ClassOfDeviceUnittest, test_from_octets) {
+ ClassOfDevice cod;
+ size_t expected_result = ClassOfDevice::kLength;
+ ASSERT_EQ(expected_result, cod.FromOctets(test_bytes));
+
+ ASSERT_EQ(test_bytes[0], cod.cod[0]);
+ ASSERT_EQ(test_bytes[1], cod.cod[1]);
+ ASSERT_EQ(test_bytes[2], cod.cod[2]);
+
+ std::string ret = cod.ToString();
+
+ ASSERT_STREQ(test_class, ret.c_str());
+}
+
+TEST(ClassOfDeviceTest, test_copy) {
+ ClassOfDevice cod1;
+ ClassOfDevice cod2;
+ ClassOfDevice::FromString(test_class, cod1);
+ cod2 = cod1;
+
+ ASSERT_EQ(cod1.cod[0], cod2.cod[0]);
+ ASSERT_EQ(cod1.cod[1], cod2.cod[1]);
+ ASSERT_EQ(cod1.cod[2], cod2.cod[2]);
+}
+
+TEST(ClassOfDeviceTest, IsValid) {
+ EXPECT_FALSE(ClassOfDevice::IsValid(""));
+ EXPECT_FALSE(ClassOfDevice::IsValid("000000"));
+ EXPECT_FALSE(ClassOfDevice::IsValid("00-00-00"));
+ EXPECT_FALSE(ClassOfDevice::IsValid("000-0-0"));
+ EXPECT_TRUE(ClassOfDevice::IsValid("000-0-00"));
+ EXPECT_TRUE(ClassOfDevice::IsValid("ABc-d-00"));
+ EXPECT_TRUE(ClassOfDevice::IsValid("aBc-D-eF"));
+}
+
+TEST(ClassOfDeviceTest, classOfDeviceFromString) {
+ ClassOfDevice cod;
+
+ EXPECT_TRUE(ClassOfDevice::FromString("000-0-00", cod));
+ const ClassOfDevice result0 = {{0x00, 0x00, 0x00}};
+ EXPECT_EQ(0, memcmp(&cod, &result0, sizeof(cod)));
+
+ EXPECT_TRUE(ClassOfDevice::FromString("ab2-1-4C", cod));
+ const ClassOfDevice result1 = {{0x4c, 0x21, 0xab}};
+ EXPECT_EQ(0, memcmp(&cod, &result1, sizeof(cod)));
+}
diff --git a/udrv/Android.bp b/udrv/Android.bp
index 9bf1d83..4605c53 100644
--- a/udrv/Android.bp
+++ b/udrv/Android.bp
@@ -5,15 +5,15 @@
"ulinux/uipc.cc",
],
include_dirs: [
- "system/bt",
- "system/bt/internal_include",
- "system/bt/utils/include",
- "system/bt/stack/include",
+ "system/bt",
+ "system/bt/internal_include",
+ "system/bt/utils/include",
+ "system/bt/stack/include",
],
local_include_dirs: [
- "include",
+ "include",
],
shared_libs: [
- "liblog",
+ "liblog",
],
}
diff --git a/udrv/BUILD.gn b/udrv/BUILD.gn
index 8a0fc92..3712bd4 100644
--- a/udrv/BUILD.gn
+++ b/udrv/BUILD.gn
@@ -26,5 +26,6 @@
"//internal_include",
"//stack/include",
"//utils/include",
+ "//third_party/libchrome",
]
}
diff --git a/utils/Android.bp b/utils/Android.bp
index 6a6c510..3a40750 100644
--- a/utils/Android.bp
+++ b/utils/Android.bp
@@ -12,4 +12,7 @@
"system/bt/stack/include",
],
srcs: ["src/bt_utils.cc"],
+ shared_libs: [
+ "libprocessgroup",
+ ],
}
diff --git a/utils/BUILD.gn b/utils/BUILD.gn
index c6e7dab..46b7236 100644
--- a/utils/BUILD.gn
+++ b/utils/BUILD.gn
@@ -23,5 +23,7 @@
"include",
"//",
"//stack/include",
+ "//third_party/libchrome",
+ "//third_party/googletest/googletest/include/",
]
}
diff --git a/utils/src/bt_utils.cc b/utils/src/bt_utils.cc
index 6d93ac4..fda47f6 100644
--- a/utils/src/bt_utils.cc
+++ b/utils/src/bt_utils.cc
@@ -39,7 +39,7 @@
#define A2DP_RT_PRIORITY 1
#ifndef OS_GENERIC
-#include <cutils/sched_policy.h>
+#include <processgroup/sched_policy.h>
#endif
#include "bt_types.h"
diff --git a/vendor_libs/linux/interface/Android.bp b/vendor_libs/linux/interface/Android.bp
index 8d6caa4..c4b6041 100644
--- a/vendor_libs/linux/interface/Android.bp
+++ b/vendor_libs/linux/interface/Android.bp
@@ -22,9 +22,12 @@
"h4_protocol.cc",
"bluetooth_hci.cc",
"async_fd_watcher.cc",
- "service.cc"
+ "service.cc",
],
- cflags: ["-Wall", "-Werror"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
header_libs: ["libbluetooth_headers"],
shared_libs: [
"android.hardware.bluetooth@1.0",
@@ -40,4 +43,3 @@
],
init_rc: ["android.hardware.bluetooth@1.0-service.btlinux.rc"],
}
-
diff --git a/vendor_libs/linux/interface/bluetooth_hci.cc b/vendor_libs/linux/interface/bluetooth_hci.cc
index 8507f7a..5ed2ff6 100644
--- a/vendor_libs/linux/interface/bluetooth_hci.cc
+++ b/vendor_libs/linux/interface/bluetooth_hci.cc
@@ -39,7 +39,6 @@
#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 WRITE_NO_INTR(fn) \
do { \
} while ((fn) == -1 && errno == EINTR)
@@ -154,7 +153,7 @@
/* validate mentioned hci interface is present and registered with sock system */
while (1) {
int n;
- WRITE_NO_INTR(n = poll(fds, 1, MGMT_EV_POLL_TIMEOUT));
+ WRITE_NO_INTR(n = poll(fds, 1, -1));
if (n == -1) {
ALOGE( "Poll error: %s", strerror(errno));
ret = -1;
@@ -246,9 +245,9 @@
public:
BluetoothDeathRecipient(const sp<IBluetoothHci> hci) : mHci(hci) {}
- virtual void serviceDied(
+ void serviceDied(
uint64_t /*cookie*/,
- const wp<::android::hidl::base::V1_0::IBase>& /*who*/) {
+ const wp<::android::hidl::base::V1_0::IBase>& /*who*/) override {
ALOGE("BluetoothDeathRecipient::serviceDied - Bluetooth service died");
has_died_ = true;
mHci->close();
diff --git a/vendor_libs/linux/sepolicy/file_contexts b/vendor_libs/linux/sepolicy/file_contexts
deleted file mode 100644
index 4300140..0000000
--- a/vendor_libs/linux/sepolicy/file_contexts
+++ /dev/null
@@ -1,2 +0,0 @@
-/sys/class/rfkill/rfkill[0-9]/state u:object_r:sysfs_bluetooth_writable:s0
-/system/vendor/bin/hw/android\.hardware\.bluetooth@1\.0-service\.btlinux u:object_r:hal_bluetooth_btlinux_exec:s0
diff --git a/vendor_libs/linux/sepolicy/hal_bluetooth_btlinux.te b/vendor_libs/linux/sepolicy/hal_bluetooth_btlinux.te
deleted file mode 100644
index 22d9cf0..0000000
--- a/vendor_libs/linux/sepolicy/hal_bluetooth_btlinux.te
+++ /dev/null
@@ -1,8 +0,0 @@
-type hal_bluetooth_btlinux, domain;
-type hal_bluetooth_btlinux_exec, exec_type, file_type, vendor_file_type;
-
-hal_server_domain(hal_bluetooth_btlinux, hal_bluetooth)
-init_daemon_domain(hal_bluetooth_btlinux)
-
-allow hal_bluetooth_btlinux self:socket { create bind read write };
-allow hal_bluetooth_btlinux self:bluetooth_socket { create bind read write };
diff --git a/vendor_libs/test_vendor_lib/Android.bp b/vendor_libs/test_vendor_lib/Android.bp
index ef927f4..aded1c3 100644
--- a/vendor_libs/test_vendor_lib/Android.bp
+++ b/vendor_libs/test_vendor_lib/Android.bp
@@ -3,30 +3,38 @@
cc_library_static {
name: "libbt-rootcanal",
defaults: ["libchrome_support_defaults"],
+ host_supported: true,
proprietary: true,
srcs: [
- "src/acl_packet.cc",
- "src/async_manager.cc",
- "src/beacon.cc",
- "src/beacon_swarm.cc",
- "src/broken_adv.cc",
- "src/bt_address.cc",
- "src/classic.cc",
- "src/command_packet.cc",
- "src/connection.cc",
- "src/device.cc",
- "src/device_factory.cc",
- "src/device_properties.cc",
- "src/dual_mode_controller.cc",
- "src/event_packet.cc",
- "src/hci_packet.cc",
- "src/keyboard.cc",
- "src/l2cap_packet.cc",
- "src/l2cap_sdu.cc",
- "src/packet.cc",
- "src/packet_stream.cc",
- "src/sco_packet.cc",
- "src/test_channel_transport.cc",
+ "model/controller/acl_connection.cc",
+ "model/controller/acl_connection_handler.cc",
+ "model/controller/dual_mode_controller.cc",
+ "model/controller/link_layer_controller.cc",
+ "model/controller/security_manager.cc",
+ "model/devices/beacon.cc",
+ "model/devices/beacon_swarm.cc",
+ "model/devices/broken_adv.cc",
+ "model/devices/car_kit.cc",
+ "model/devices/classic.cc",
+ "model/devices/device.cc",
+ "model/devices/device_properties.cc",
+ "model/devices/h4_packetizer.cc",
+ "model/devices/h4_protocol.cc",
+ "model/devices/hci_packetizer.cc",
+ "model/devices/hci_protocol.cc",
+ "model/devices/hci_socket_device.cc",
+ "model/devices/keyboard.cc",
+ "model/devices/link_layer_socket_device.cc",
+ "model/devices/loopback.cc",
+ "model/devices/polled_socket.cc",
+ "model/devices/remote_loopback_device.cc",
+ "model/devices/sniffer.cc",
+ "model/setup/async_manager.cc",
+ "model/setup/device_boutique.cc",
+ "model/setup/phy_layer_factory.cc",
+ "model/setup/test_channel_transport.cc",
+ "model/setup/test_command_handler.cc",
+ "model/setup/test_model.cc",
],
cflags: [
"-fvisibility=hidden",
@@ -35,7 +43,10 @@
local_include_dirs: [
"include",
],
- export_include_dirs: ["include"],
+ export_include_dirs: [
+ "include",
+ ".",
+ ],
header_libs: [
"libbluetooth_headers",
],
@@ -50,32 +61,26 @@
"libbase",
"liblog",
],
+ whole_static_libs: [
+ "libbt-rootcanal-packets",
+ ],
static_libs: [
- "libbluetooth-types",
- ]
+ "libbt-rootcanal-types",
+ ],
}
// test-vendor unit tests for host
// ========================================================
cc_test_host {
name: "test-vendor_test_host",
- defaults: ["libchrome_support_defaults"],
+ defaults: [
+ "libchrome_support_defaults",
+ "clang_file_coverage",
+ "clang_coverage_bin",
+ ],
srcs: [
- "src/async_manager.cc",
- "src/bt_address.cc",
- "src/hci_packet.cc",
- "src/command_packet.cc",
- "src/event_packet.cc",
- "src/packet.cc",
- "src/packet_stream.cc",
- "src/l2cap_packet.cc",
- "src/l2cap_sdu.cc",
"test/async_manager_unittest.cc",
- "test/bt_address_unittest.cc",
- "test/packet_stream_unittest.cc",
- "test/iterator_test.cc",
- "test/l2cap_test.cc",
- "test/l2cap_sdu_test.cc",
+ "test/security_manager_unittest.cc",
],
header_libs: [
"libbluetooth_headers",
@@ -93,10 +98,43 @@
"liblog",
],
static_libs: [
- "libbluetooth-types",
+ "libbt-rootcanal-types",
+ "libbt-rootcanal",
],
cflags: [
"-fvisibility=hidden",
"-DLOG_NDEBUG=1",
],
}
+
+// Linux RootCanal Executable
+// ========================================================
+cc_test_host {
+ name: "root-canal",
+ defaults: [
+ "libchrome_support_defaults",
+ ],
+ srcs: [
+ "desktop/root_canal_main.cc",
+ "desktop/test_environment.cc",
+ ],
+ header_libs: [
+ "libbluetooth_headers",
+ ],
+ local_include_dirs: [
+ "include",
+ ],
+ include_dirs: [
+ "system/bt",
+ "system/bt/utils/include",
+ "system/bt/hci/include",
+ "system/bt/stack/include",
+ ],
+ shared_libs: [
+ "liblog",
+ ],
+ static_libs: [
+ "libbt-rootcanal-types",
+ "libbt-rootcanal",
+ ],
+}
diff --git a/vendor_libs/test_vendor_lib/desktop/root_canal_main.cc b/vendor_libs/test_vendor_lib/desktop/root_canal_main.cc
new file mode 100644
index 0000000..5432292
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/desktop/root_canal_main.cc
@@ -0,0 +1,69 @@
+//
+// Copyright 2017 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 "root_canal"
+
+#include "test_environment.h"
+
+#include <base/logging.h>
+#include <utils/Log.h>
+#include <future>
+
+#include "hci_internals.h"
+
+using ::android::bluetooth::root_canal::TestEnvironment;
+
+constexpr uint16_t kTestPort = 6401;
+constexpr uint16_t kHciServerPort = 6402;
+constexpr uint16_t kLinkServerPort = 6403;
+
+int main(int argc, char** argv) {
+ ALOGI("main");
+ uint16_t test_port = kTestPort;
+ uint16_t hci_server_port = kHciServerPort;
+ uint16_t link_server_port = kLinkServerPort;
+
+ for (int arg = 0; arg < argc; arg++) {
+ int port = atoi(argv[arg]);
+ ALOGI("%d: %s (%d)", arg, argv[arg], port);
+ if (port < 0 || port > 0xffff) {
+ ALOGW("%s out of range", argv[arg]);
+ } else {
+ switch (arg) {
+ case 0: // executable name
+ break;
+ case 1:
+ test_port = port;
+ break;
+ case 2:
+ hci_server_port = port;
+ break;
+ case 3:
+ link_server_port = port;
+ break;
+ default:
+ ALOGW("Ignored option %s", argv[arg]);
+ }
+ }
+ }
+
+ TestEnvironment root_canal(test_port, hci_server_port, link_server_port);
+ std::promise<void> barrier;
+ std::future<void> barrier_future = barrier.get_future();
+ root_canal.initialize(std::move(barrier));
+ barrier_future.wait();
+ root_canal.close();
+}
diff --git a/vendor_libs/test_vendor_lib/desktop/test_environment.cc b/vendor_libs/test_vendor_lib/desktop/test_environment.cc
new file mode 100644
index 0000000..2822335
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/desktop/test_environment.cc
@@ -0,0 +1,182 @@
+//
+// Copyright 2017 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 "root_canal"
+
+#include "test_environment.h"
+
+#include <base/logging.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <utils/Log.h>
+
+#include "hci_internals.h"
+
+namespace android {
+namespace bluetooth {
+namespace root_canal {
+
+using test_vendor_lib::AsyncTaskId;
+using test_vendor_lib::DualModeController;
+using test_vendor_lib::TaskCallback;
+
+void TestEnvironment::initialize(std::promise<void> barrier) {
+ ALOGI("%s", __func__);
+
+ barrier_ = std::move(barrier);
+
+ test_channel_transport_.RegisterCommandHandler([this](const std::string& name, const std::vector<std::string>& args) {
+ async_manager_.ExecAsync(std::chrono::milliseconds(0),
+ [this, name, args]() { test_channel_.HandleCommand(name, args); });
+ });
+
+ test_model_.Reset();
+
+ SetUpTestChannel();
+ SetUpHciServer([this](int fd) { test_model_.IncomingHciConnection(fd); });
+ SetUpLinkLayerServer([this](int fd) { test_model_.IncomingLinkLayerConnection(fd); });
+
+ ALOGI("%s: Finished", __func__);
+}
+
+void TestEnvironment::close() {
+ ALOGI("%s", __func__);
+}
+
+void TestEnvironment::SetUpHciServer(const std::function<void(int)>& connection_callback) {
+ int socket_fd = remote_hci_transport_.SetUp(hci_server_port_);
+
+ test_channel_.RegisterSendResponse(
+ [](const std::string& response) { ALOGI("No HCI Response channel: %s", response.c_str()); });
+
+ if (socket_fd == -1) {
+ ALOGE("Remote HCI channel SetUp(%d) failed.", hci_server_port_);
+ return;
+ }
+
+ async_manager_.WatchFdForNonBlockingReads(socket_fd, [this, connection_callback](int socket_fd) {
+ int conn_fd = remote_hci_transport_.Accept(socket_fd);
+ if (conn_fd < 0) {
+ ALOGE("Error watching remote HCI channel fd.");
+ return;
+ }
+ int flags = fcntl(conn_fd, F_GETFL, NULL);
+ int ret;
+ ret = fcntl(conn_fd, F_SETFL, flags | O_NONBLOCK);
+ CHECK(ret != -1) << "Error setting O_NONBLOCK " << strerror(errno);
+
+ connection_callback(conn_fd);
+ });
+}
+
+void TestEnvironment::SetUpLinkLayerServer(const std::function<void(int)>& connection_callback) {
+ int socket_fd = remote_link_layer_transport_.SetUp(link_server_port_);
+
+ test_channel_.RegisterSendResponse(
+ [](const std::string& response) { ALOGI("No LinkLayer Response channel: %s", response.c_str()); });
+
+ if (socket_fd == -1) {
+ ALOGE("Remote LinkLayer channel SetUp(%d) failed.", link_server_port_);
+ return;
+ }
+
+ async_manager_.WatchFdForNonBlockingReads(socket_fd, [this, connection_callback](int socket_fd) {
+ int conn_fd = remote_link_layer_transport_.Accept(socket_fd);
+ if (conn_fd < 0) {
+ ALOGE("Error watching remote LinkLayer channel fd.");
+ return;
+ }
+ int flags = fcntl(conn_fd, F_GETFL, NULL);
+ int ret = fcntl(conn_fd, F_SETFL, flags | O_NONBLOCK);
+ CHECK(ret != -1) << "Error setting O_NONBLOCK " << strerror(errno);
+
+ connection_callback(conn_fd);
+ });
+}
+
+int TestEnvironment::ConnectToRemoteServer(const std::string& server, int port) {
+ int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (socket_fd < 1) {
+ ALOGI("socket() call failed: %s", strerror(errno));
+ return -1;
+ }
+
+ struct hostent* host;
+ host = gethostbyname(server.c_str());
+ if (host == NULL) {
+ ALOGI("gethostbyname() failed for %s: %s", server.c_str(), strerror(errno));
+ return -1;
+ }
+
+ struct sockaddr_in serv_addr;
+ memset((void*)&serv_addr, 0, sizeof(serv_addr));
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_addr.s_addr = INADDR_ANY;
+ serv_addr.sin_port = htons(port);
+
+ int result = connect(socket_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
+ if (result < 0) {
+ ALOGI("connect() failed for %s@%d: %s", server.c_str(), port, strerror(errno));
+ return -1;
+ }
+
+ int flags = fcntl(socket_fd, F_GETFL, NULL);
+ int ret = fcntl(socket_fd, F_SETFL, flags | O_NONBLOCK);
+ CHECK(ret != -1) << "Error setting O_NONBLOCK " << strerror(errno);
+
+ return socket_fd;
+}
+
+void TestEnvironment::SetUpTestChannel() {
+ int socket_fd = test_channel_transport_.SetUp(test_port_);
+ test_channel_.AddPhy({"BR_EDR"});
+ test_channel_.AddPhy({"LOW_ENERGY"});
+ test_channel_.SetTimerPeriod({"100"});
+ test_channel_.StartTimer({});
+
+ test_channel_.RegisterSendResponse(
+ [](const std::string& response) { ALOGI("No test channel: %s", response.c_str()); });
+
+ if (socket_fd == -1) {
+ ALOGE("Test channel SetUp(%d) failed.", test_port_);
+ return;
+ }
+
+ ALOGI("Test channel SetUp() successful");
+ async_manager_.WatchFdForNonBlockingReads(socket_fd, [this](int socket_fd) {
+ int conn_fd = test_channel_transport_.Accept(socket_fd);
+ if (conn_fd < 0) {
+ ALOGE("Error watching test channel fd.");
+ barrier_.set_value();
+ return;
+ }
+ ALOGI("Test channel connection accepted.");
+ test_channel_.RegisterSendResponse(
+ [this, conn_fd](const std::string& response) { test_channel_transport_.SendResponse(conn_fd, response); });
+
+ async_manager_.WatchFdForNonBlockingReads(conn_fd, [this](int conn_fd) {
+ test_channel_transport_.OnCommandReady(conn_fd, [this, conn_fd]() {
+ async_manager_.StopWatchingFileDescriptor(conn_fd);
+ barrier_.set_value();
+ });
+ });
+ });
+}
+
+} // namespace root_canal
+} // namespace bluetooth
+} // namespace android
diff --git a/vendor_libs/test_vendor_lib/desktop/test_environment.h b/vendor_libs/test_vendor_lib/desktop/test_environment.h
new file mode 100644
index 0000000..f48789b
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/desktop/test_environment.h
@@ -0,0 +1,78 @@
+//
+// Copyright 2017 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 <future>
+
+#include "model/controller/dual_mode_controller.h"
+#include "model/setup/async_manager.h"
+#include "model/setup/test_channel_transport.h"
+#include "model/setup/test_command_handler.h"
+#include "model/setup/test_model.h"
+
+namespace android {
+namespace bluetooth {
+namespace root_canal {
+
+class TestEnvironment {
+ public:
+ TestEnvironment(uint16_t test_port, uint16_t hci_server_port, uint16_t link_server_port)
+ : test_port_(test_port), hci_server_port_(hci_server_port), link_server_port_(link_server_port) {}
+
+ void initialize(std::promise<void> barrier);
+
+ void close();
+
+ private:
+ uint16_t test_port_;
+ uint16_t hci_server_port_;
+ uint16_t link_server_port_;
+ std::promise<void> barrier_;
+
+ test_vendor_lib::AsyncManager async_manager_;
+
+ void SetUpTestChannel();
+ void SetUpHciServer(const std::function<void(int)>& on_connect);
+ void SetUpLinkLayerServer(const std::function<void(int)>& on_connect);
+ int ConnectToRemoteServer(const std::string& server, int port);
+
+ std::shared_ptr<test_vendor_lib::DualModeController> controller_;
+
+ test_vendor_lib::TestChannelTransport test_channel_transport_;
+ test_vendor_lib::TestChannelTransport remote_hci_transport_;
+ test_vendor_lib::TestChannelTransport remote_link_layer_transport_;
+
+ test_vendor_lib::TestModel test_model_{
+ [this](std::chrono::milliseconds delay, const test_vendor_lib::TaskCallback& task) {
+ return async_manager_.ExecAsync(delay, task);
+ },
+
+ [this](std::chrono::milliseconds delay, std::chrono::milliseconds period,
+ const test_vendor_lib::TaskCallback& task) {
+ return async_manager_.ExecAsyncPeriodically(delay, period, task);
+ },
+
+ [this](test_vendor_lib::AsyncTaskId task) { async_manager_.CancelAsyncTask(task); },
+
+ [this](const std::string& server, int port) { return ConnectToRemoteServer(server, port); }};
+
+ test_vendor_lib::TestCommandHandler test_channel_{test_model_};
+};
+
+} // namespace root_canal
+} // namespace bluetooth
+} // namespace android
diff --git a/vendor_libs/test_vendor_lib/include/acl.h b/vendor_libs/test_vendor_lib/include/acl.h
new file mode 100644
index 0000000..c7c7b34
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/include/acl.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2017 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>
+
+namespace test_vendor_lib {
+namespace acl {
+
+// ACL data packets are specified in the Bluetooth Core Specification Version
+// 4.2, Volume 2, Part E, Section 5.4.2
+static constexpr uint16_t kReservedHandle = 0xF00;
+
+enum class PacketBoundaryFlagsType : uint8_t {
+ FIRST_NON_AUTOMATICALLY_FLUSHABLE = 0,
+ CONTINUING = 1,
+ FIRST_AUTOMATICALLY_FLUSHABLE = 2,
+ COMPLETE = 3
+};
+
+enum class BroadcastFlagsType : uint8_t {
+ POINT_TO_POINT = 0,
+ ACTIVE_SLAVE_BROADCAST = 1,
+ PARKED_SLAVE_BROADCAST = 2,
+ RESERVED = 3
+};
+} // namespace acl
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/acl_packet.h b/vendor_libs/test_vendor_lib/include/acl_packet.h
deleted file mode 100644
index 30f3389..0000000
--- a/vendor_libs/test_vendor_lib/include/acl_packet.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2017 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 <string>
-#include <vector>
-
-namespace test_vendor_lib {
-
-// ACL data packets are specified in the Bluetooth Core Specification Version
-// 4.2, Volume 2, Part E, Section 5.4.2
-class AclPacket {
- public:
- typedef enum {
- FirstNonAutomaticallyFlushable,
- Continuing,
- FirstAutomaticallyFlushable,
- Complete
- } PacketBoundaryFlags;
- typedef enum {
- PointToPoint,
- ActiveSlaveBroadcast,
- ParkedSlaveBroadcast,
- Reserved
- } BroadcastFlags;
-
- virtual ~AclPacket() = default;
-
- uint16_t GetChannel() const {
- return (raw_packet_[0] | (raw_packet_[1] << 8)) & 0xfff;
- }
-
- PacketBoundaryFlags GetPacketBoundaryFlags() const {
- return static_cast<PacketBoundaryFlags>((raw_packet_[1] & 0x30) >> 4);
- }
-
- BroadcastFlags GetBroadcastFlags() const {
- return static_cast<BroadcastFlags>((raw_packet_[1] & 0xC0) >> 6);
- }
-
- explicit AclPacket(uint16_t channel,
- AclPacket::PacketBoundaryFlags boundary_flags,
- AclPacket::BroadcastFlags broadcast);
-
- size_t GetPacketSize() const;
-
- const std::vector<uint8_t>& GetPacket() const;
-
- void AddPayloadOctets(size_t octets, const std::vector<uint8_t>& bytes);
-
- private:
- // Add |octets| bytes to the payload.
- void AddPayloadOctets(size_t octets, uint64_t value);
-
- static const size_t kHeaderSize = 4;
-
- public:
- // Add type-checking versions
- void AddPayloadOctets1(uint8_t value) { AddPayloadOctets(1, value); }
- void AddPayloadOctets2(uint16_t value) { AddPayloadOctets(2, value); }
- void AddPayloadOctets3(uint32_t value) { AddPayloadOctets(3, value); }
- void AddPayloadOctets4(uint32_t value) { AddPayloadOctets(4, value); }
- void AddPayloadOctets6(uint64_t value) { AddPayloadOctets(6, value); }
- void AddPayloadOctets8(uint64_t value) { AddPayloadOctets(8, value); }
-
- private:
- std::vector<uint8_t> raw_packet_;
-};
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/async_manager.h b/vendor_libs/test_vendor_lib/include/async_manager.h
deleted file mode 100644
index 1e94edf..0000000
--- a/vendor_libs/test_vendor_lib/include/async_manager.h
+++ /dev/null
@@ -1,113 +0,0 @@
-#ifndef TEST_VENDOR_LIB_ASYNC_MANAGER_H_
-#define TEST_VENDOR_LIB_ASYNC_MANAGER_H_
-
-#include <time.h>
-#include <cstdint>
-#include <map>
-#include <set>
-#include "errno.h"
-#include "stdio.h"
-
-#include <chrono>
-#include <functional>
-#include <memory>
-#include <mutex>
-#include <utility>
-
-namespace test_vendor_lib {
-
-using TaskCallback = std::function<void(void)>;
-using ReadCallback = std::function<void(int)>;
-using CriticalCallback = std::function<void(void)>;
-using AsyncTaskId = uint16_t;
-constexpr uint16_t kInvalidTaskId = 0;
-
-// Manages tasks that should be done in the future. It can watch file
-// descriptors to call a given callback when it is certain that a non-blocking
-// read is possible or can call a callback at a specific time (aproximately) and
-// (optionally) repeat the call periodically.
-// The class is thread safe in the sense that all its member functions can be
-// called simultaneously from different concurrent threads. The exception to
-// this rule is the class destructor, which is unsafe to call concurrently with
-// calls to other class member functions. This exception also has its own
-// exception: it is safe to destroy the object even if some of its callbacks may
-// call its member functions, because the destructor will make sure all callback
-// calling threads are stopped before actually destroying anything. Callbacks
-// that wait for file descriptor always run on the same thread, so there is no
-// need of additional synchronization between them. The same applies to task
-// callbacks since they also run on a thread of their own, however it is
-// possible for a read callback and a task callback to execute at the same time
-// (they are garanteed to run in different threads) so synchronization is needed
-// to access common state (other than the internal state of the AsyncManager
-// class). While not required, it is strongly recommended to use the
-// Synchronize(const CriticalCallback&) member function to execute code inside
-// critical sections. Callbacks passed to this method on the same AsyncManager
-// object from different threads are granted to *NOT* run concurrently.
-class AsyncManager {
- public:
- // Starts watching a file descriptor in a separate thread. The
- // on_read_fd_ready_callback() will be asynchronously called when it is
- // guaranteed that a call to read() on the FD will not block. No promise is
- // made about when in the future the callback will be called, in particular,
- // it is perfectly possible to have it called before this function returns. A
- // return of 0 means success, an error code is returned otherwise.
- int WatchFdForNonBlockingReads(int file_descriptor,
- const ReadCallback& on_read_fd_ready_callback);
-
- // If the fd was not being watched before the call will be ignored.
- void StopWatchingFileDescriptor(int file_descriptor);
-
- // Schedules an action to occur in the future. Even if the delay given is not
- // positive the callback will be called asynchronously.
- AsyncTaskId ExecAsync(std::chrono::milliseconds delay,
- const TaskCallback& callback);
-
- // Schedules an action to occur periodically in the future. If the delay given
- // is not positive the callback will be asynchronously called once for each
- // time in the past that it should have been called and then scheduled for
- // future times.
- AsyncTaskId ExecAsyncPeriodically(std::chrono::milliseconds delay,
- std::chrono::milliseconds period,
- const TaskCallback& callback);
-
- // Cancels the/every future ocurrence of the action specified by this id. It
- // is guaranteed that the asociated callback will not be called after this
- // method returns (it could be called during the execution of the method).
- // The calling thread may block until the scheduling thread acknowledges the
- // cancelation.
- bool CancelAsyncTask(AsyncTaskId async_task_id);
-
- // Execs the given code in a synchronized manner. It is guaranteed that code
- // given on (possibly)concurrent calls to this member function on the same
- // AsyncManager object will never be executed simultaneously. It is the
- // class's user's resposability to ensure that no calls to Synchronize are
- // made from inside a CriticalCallback, since that would cause a lock to be
- // acquired twice with unpredictable results. It is strongly recommended to
- // have very simple CriticalCallbacks, preferably using lambda expressions.
- void Synchronize(const CriticalCallback&);
-
- AsyncManager();
-
- ~AsyncManager();
-
- private:
- // Implementation of the FD watching part of AsyncManager, extracted to its
- // own class for clarity purposes.
- class AsyncFdWatcher;
-
- // Implementation of the asynchronous tasks part of AsyncManager, extracted to
- // its own class for clarity purposes.
- class AsyncTaskManager;
-
- AsyncManager(const AsyncManager&) = delete;
- AsyncManager& operator=(const AsyncManager&) = delete;
-
- // Kept as pointers because we may want to support reseting either without
- // destroying the other one
- std::unique_ptr<AsyncFdWatcher> fdWatcher_p_;
- std::unique_ptr<AsyncTaskManager> taskManager_p_;
-
- std::mutex synchronization_mutex_;
-};
-} // namespace test_vendor_lib
-#endif // TEST_VENDOR_LIB_ASYNC_MANAGER_H_
diff --git a/vendor_libs/test_vendor_lib/include/beacon.h b/vendor_libs/test_vendor_lib/include/beacon.h
deleted file mode 100644
index 8943b96..0000000
--- a/vendor_libs/test_vendor_lib/include/beacon.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2016 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 "bt_address.h"
-#include "device.h"
-#include "stack/include/btm_ble_api.h"
-
-namespace test_vendor_lib {
-
-// A simple device that advertises periodically and is not connectable.
-class Beacon : public Device {
- public:
- Beacon();
- virtual ~Beacon() = default;
-
- // Return a string representation of the type of device.
- virtual std::string GetTypeString() const override { return "beacon"; }
-
- // Set the address and advertising interval from string args.
- virtual void Initialize(const std::vector<std::string>& args) override;
-};
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/beacon_swarm.h b/vendor_libs/test_vendor_lib/include/beacon_swarm.h
deleted file mode 100644
index e07ae55..0000000
--- a/vendor_libs/test_vendor_lib/include/beacon_swarm.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2016 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 "bt_address.h"
-#include "device.h"
-#include "stack/include/btm_ble_api.h"
-
-namespace test_vendor_lib {
-
-// Pretend to be a lot of beacons by changing the advertising address.
-class BeaconSwarm : public Device {
- public:
- BeaconSwarm();
- virtual ~BeaconSwarm() = default;
-
- // Set the address and advertising interval from string args.
- virtual void Initialize(const std::vector<std::string>& args) override;
-
- // Return a string representation of the type of device.
- virtual std::string GetTypeString() const override { return "beacon_swarm"; }
-
- void TimerTick() override;
-};
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/broken_adv.h b/vendor_libs/test_vendor_lib/include/broken_adv.h
deleted file mode 100644
index 9f7cd87..0000000
--- a/vendor_libs/test_vendor_lib/include/broken_adv.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2016 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 "bt_address.h"
-#include "device.h"
-
-namespace test_vendor_lib {
-
-class BrokenAdv : public Device {
- public:
- BrokenAdv();
- ~BrokenAdv() = default;
-
- // Initialize the device based on the values of |args|.
- virtual void Initialize(const std::vector<std::string>& args) override;
-
- // Return a string representation of the type of device.
- virtual std::string GetTypeString() const override { return "broken_adv"; }
-
- // Return the string representation of the device.
- virtual std::string ToString() const override;
-
- // Use the timer tick to update advertisements.
- void TimerTick() override;
-
- // Change which advertisements are broken and the address of the device.
- void UpdateAdvertisement();
-
- // Change which data is broken and the address of the device.
- void UpdatePageScan();
-
- private:
- std::vector<uint8_t> constant_adv_data_;
-};
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/bt_address.h b/vendor_libs/test_vendor_lib/include/bt_address.h
deleted file mode 100644
index d656c34..0000000
--- a/vendor_libs/test_vendor_lib/include/bt_address.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright 2016 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 <string>
-#include <vector>
-
-namespace test_vendor_lib {
-
-// Encapsulate handling for Bluetooth Addresses:
-// - store the address
-// - convert to/from strings and vectors of bytes
-// - check strings to see if they represent a valid address
-class BtAddress {
- public:
- // Conversion constants
- static const size_t kStringLength = 17; // "XX:XX:XX:XX:XX:XX"
- static const size_t kOctets = 6; // "X0:X1:X2:X3:X4:X5"
-
- BtAddress() : address_(0){};
- virtual ~BtAddress() = default;
-
- // Returns true if |addr| has the form "XX:XX:XX:XX:XX:XX":
- // - the length of |addr| is >= kStringLength
- // - every third character is ':'
- // - each remaining character is a hexadecimal digit
- static bool IsValid(const std::string& addr);
-
- inline bool operator==(const BtAddress& right) const {
- return address_ == right.address_;
- }
- inline bool operator!=(const BtAddress& right) const {
- return address_ != right.address_;
- }
- inline bool operator<(const BtAddress& right) const {
- return address_ < right.address_;
- }
- inline bool operator>(const BtAddress& right) const {
- return address_ > right.address_;
- }
- inline bool operator<=(const BtAddress& right) const {
- return address_ <= right.address_;
- }
- inline bool operator>=(const BtAddress& right) const {
- return address_ >= right.address_;
- }
-
- inline void operator=(const BtAddress& right) { address_ = right.address_; }
- inline void operator|=(const BtAddress& right) { address_ |= right.address_; }
- inline void operator&=(const BtAddress& right) { address_ &= right.address_; }
-
- // Set the address to the address represented by |str|.
- // returns true if |str| represents a valid address, otherwise false.
- bool FromString(const std::string& str);
-
- // Set the address to the address represented by |str|.
- // returns true if octets.size() >= kOctets, otherwise false.
- bool FromVector(const std::vector<uint8_t>& octets);
-
- // Appends the Bluetooth address to the vector |octets|.
- void ToVector(std::vector<uint8_t>& octets) const;
-
- // Return a string representation of the Bluetooth address, in this format:
- // "xx:xx:xx:xx:xx:xx", where x represents a lowercase hexadecimal digit.
- std::string ToString() const;
-
- private:
- // The Bluetooth Address is stored in the lower 48 bits of a 64-bit value
- uint64_t address_;
-};
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/classic.h b/vendor_libs/test_vendor_lib/include/classic.h
deleted file mode 100644
index 0aeba2f..0000000
--- a/vendor_libs/test_vendor_lib/include/classic.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2016 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 "bt_address.h"
-#include "device.h"
-
-namespace test_vendor_lib {
-
-class Classic : public Device {
- public:
- Classic();
- ~Classic() = default;
-
- // Initialize the device based on the values of |args|.
- virtual void Initialize(const std::vector<std::string>& args) override;
-
- // Return a string representation of the type of device.
- virtual std::string GetTypeString() const override { return "classic"; }
-};
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/command_packet.h b/vendor_libs/test_vendor_lib/include/command_packet.h
deleted file mode 100644
index 36ab8d2..0000000
--- a/vendor_libs/test_vendor_lib/include/command_packet.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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 "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:
- explicit CommandPacket(std::vector<uint8_t> header);
- explicit CommandPacket(uint16_t opcode);
- CommandPacket(std::vector<uint8_t> header, std::vector<uint8_t> payload);
-
- CommandPacket(const CommandPacket&) = default;
- CommandPacket& operator=(const CommandPacket&) = default;
- CommandPacket(CommandPacket&&) = default;
- CommandPacket& operator=(CommandPacket&&) = default;
- 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 of a command packet header, which consists of a 2 octet opcode
- static const size_t kCommandHeaderSize = 2;
-};
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/connection.h b/vendor_libs/test_vendor_lib/include/connection.h
deleted file mode 100644
index 2a4f662..0000000
--- a/vendor_libs/test_vendor_lib/include/connection.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2016 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 <queue>
-#include <string>
-#include <vector>
-
-#include "async_manager.h"
-#include "device.h"
-
-#include "hci/include/hci_hal.h"
-
-namespace test_vendor_lib {
-
-// Model the connection of a device to the controller.
-class Connection {
- public:
- Connection(std::shared_ptr<Device> dev, uint16_t handle)
- : dev_(dev), handle_(handle), connected_(true), encrypted_(false) {}
-
- virtual ~Connection() = default;
-
- // Return a string representing the connection for logging.
- const std::string ToString();
-
- // Return a pointer to the device in the connection.
- std::shared_ptr<Device> GetDevice() { return dev_; }
-
- // Return true if the handle matches and the device is connected.
- inline bool operator==(uint16_t handle) {
- return (handle_ == handle) && connected_;
- }
-
- // Return true if the handle doesn't match or the device is not connected.
- inline bool operator!=(uint16_t handle) {
- return (handle_ != handle) || !connected_;
- }
-
- void Disconnect() { connected_ = false; };
- bool Connected() { return connected_; };
-
- void Encrypt() { encrypted_ = true; };
- bool Encrypted() { return encrypted_; };
-
- // Add an action to the connection queue.
- void AddAction(const TaskCallback& task);
-
- // Execute the next action in the connection queue to simulate packet
- // exchange.
- void SendToDevice();
-
- // Add a message from the device.
- void AddMessage(const std::vector<uint8_t>& message);
-
- // Receive data from the device to simulate packet exchange.
- bool ReceiveFromDevice(std::vector<uint8_t>& data);
-
- private:
- // A shared pointer to the connected device
- std::shared_ptr<Device> dev_;
-
- // The connection handle
- uint16_t handle_;
-
- // State variables
- bool connected_;
- bool encrypted_;
-
- // Actions for the next packet exchange.
- std::queue<TaskCallback> actions_;
-
- // Messages from the device for the next packet exchange.
- std::queue<std::vector<uint8_t>> messages_;
-};
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/device.h b/vendor_libs/test_vendor_lib/include/device.h
deleted file mode 100644
index e2924c4..0000000
--- a/vendor_libs/test_vendor_lib/include/device.h
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright 2016 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 <chrono>
-#include <cstdint>
-#include <string>
-#include <vector>
-
-#include "bt_address.h"
-
-#include "hci/include/hci_hal.h"
-#include "stack/include/btm_ble_api.h"
-
-namespace test_vendor_lib {
-
-// Represent a Bluetooth Device
-// - Provide Get*() and Set*() functions for device attributes.
-class Device {
- public:
- Device() : time_stamp_(std::chrono::steady_clock::now()) {}
- virtual ~Device() = default;
-
- // Initialize the device based on the values of |args|.
- virtual void Initialize(const std::vector<std::string>& args) = 0;
-
- // Return a string representation of the type of device.
- virtual std::string GetTypeString() const = 0;
-
- // Return the string representation of the device.
- virtual std::string ToString() const;
-
- // Return a reference to the address.
- const BtAddress& GetBtAddress() const { return address_; }
-
- // Set the address to the |addr|.
- void SetBtAddress(const BtAddress& addr) { address_ = addr; }
-
- // Return the address type.
- uint8_t GetAddressType() const { return address_type_; }
-
- // Decide whether to accept a connection request
- // May need to be extended to check peer address & type, and other
- // connection parameters.
- // Return true if the device accepts the connection request.
- virtual bool LeConnect() { return false; }
-
- // Return the advertisement data.
- const std::vector<uint8_t>& GetAdvertisement() const { return adv_data_; }
-
- // Return the advertisement type.
- uint8_t GetAdvertisementType() const { return advertising_type_; }
-
- // Set the advertisement interval in milliseconds.
- void SetAdvertisementInterval(std::chrono::milliseconds ms) {
- advertising_interval_ms_ = ms;
- }
-
- // Return true if there is a scan response (allows for empty responses).
- bool HasScanResponse() const { return scan_response_present_; }
-
- // Return the scan response data.
- const std::vector<uint8_t>& GetScanResponse() const { return scan_data_; }
-
- // Returns true if the host could see an advertisement in the next
- // |scan_time| milliseconds.
- virtual bool IsAdvertisementAvailable(
- std::chrono::milliseconds scan_time) const;
-
- // Returns true if the host could see a page scan now.
- virtual bool IsPageScanAvailable() const;
-
- // Return the device class.
- // The device class is a 3-byte value. Look for DEV_CLASS in
- // stack/include/bt_types.h
- uint32_t GetDeviceClass() const { return device_class_; }
-
- // Return the clock offset, which is a defined in the Spec as:
- // (CLKN_16-2 slave - CLKN_16-2 master ) mod 2**15.
- // Bluetooth Core Specification Version 4.2, Volume 2, Part C, Section 4.3.2
- uint16_t GetClockOffset() const { return clock_offset_; }
-
- // Set the clock offset.
- void SetClockOffset(uint16_t offset) { clock_offset_ = offset; }
-
- // Return the page scan repetition mode.
- // Bluetooth Core Specification Version 4.2, Volume 2, Part B, Section 8.3.1
- // The values are:
- // 0 - R0 T_page_scan <= 1.28s and T_page_scan == T_window and
- // 1 - R1 T_page_scan <= 1.28s
- // 2 - R2 T_page_scan <= 2.56s
- uint8_t GetPageScanRepetitionMode() const {
- return page_scan_repetition_mode_;
- }
-
- // Return the extended inquiry data.
- const std::vector<uint8_t>& GetExtendedInquiryData() const {
- return extended_inquiry_data_;
- }
-
- // Let the device know that time has passed.
- virtual void TimerTick() {}
-
- protected:
- BtAddress address_;
-
- // Address type is defined in the spec:
- // 0x00 Public Device Address
- // 0x01 Random Device Address
- // 0x02 Public Identity Address
- // 0x03 Random (static) Identity Address
- // 0x04 – 0xFF Reserved for future use
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.12
- uint8_t address_type_;
-
- std::chrono::steady_clock::time_point time_stamp_;
-
- // Return the device class.
- // The device class is a 3-byte value. Look for DEV_CLASS in
- // stack/include/bt_types.h
- uint32_t device_class_;
-
- // Return the page scan repetition mode.
- // Bluetooth Core Specification Version 4.2, Volume 2, Part B, Section 8.3.1
- // The values are:
- // 0 - R0 T_page_scan <= 1.28s and T_page_scan == T_window and
- // 1 - R1 T_page_scan <= 1.28s
- // 2 - R2 T_page_scan <= 2.56s
- uint8_t page_scan_repetition_mode_;
-
- // The time between page scans.
- std::chrono::milliseconds page_scan_delay_ms_;
-
- std::vector<uint8_t> extended_inquiry_data_;
-
- // Classic Bluetooth CLKN_slave[16..2] - CLKN_master[16..2]
- // Bluetooth Core Specification Version 4.2, Volume 2, Part C, Section 4.3.2
- uint16_t clock_offset_;
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.5
- uint8_t advertising_type_;
-
- // The spec defines the advertising interval as a 16-bit value, but since it
- // is never sent in packets, we use std::chrono::milliseconds.
- std::chrono::milliseconds advertising_interval_ms_;
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.7
-
- // Bluetooth Core Specification Version 4.2, Volume 3, Part C, Section
- // 11.1
- // https://www.bluetooth.com/specifications/assigned-numbers
- // Supplement to Bluetooth Core Specification | CSSv6, Part A
- std::vector<uint8_t> adv_data_ = {0x07, // Length
- BTM_BLE_AD_TYPE_NAME_CMPL,
- 'd',
- 'e',
- 'v',
- 'i',
- 'c',
- 'e'};
-
- bool scan_response_present_ = true;
- std::vector<uint8_t> scan_data_ = {0x04, // Length
- BTM_BLE_AD_TYPE_NAME_SHORT, 'd', 'e', 'v'};
-
- public:
- static const uint8_t kBtAddressTypePublic = 0x00;
- static const uint8_t kBtAddressTypeRandom = 0x01;
- static const uint8_t kBtAddressTypePublicIdentity = 0x02;
- static const uint8_t kBtAddressTypeRandomIdentity = 0x03;
-};
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/device_factory.h b/vendor_libs/test_vendor_lib/include/device_factory.h
deleted file mode 100644
index a66a2e0..0000000
--- a/vendor_libs/test_vendor_lib/include/device_factory.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2016 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 <string>
-#include <vector>
-
-#include "device.h"
-
-namespace test_vendor_lib {
-
-// Encapsulate the details of supported devices to hide them from the
-// Controller.
-class DeviceFactory {
- public:
- DeviceFactory();
- virtual ~DeviceFactory() = default;
-
- // Call the constructor for the matching device type (arg[0]) and then call
- // the matching Initialize() function with args.
- static std::shared_ptr<Device> Create(const std::vector<std::string>& args);
-};
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/device_properties.h b/vendor_libs/test_vendor_lib/include/device_properties.h
deleted file mode 100644
index 98876d5..0000000
--- a/vendor_libs/test_vendor_lib/include/device_properties.h
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * 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 <unordered_map>
-#include <vector>
-
-#include "acl_packet.h"
-#include "async_manager.h"
-#include "base/json/json_value_converter.h"
-#include "base/time/time.h"
-#include "bt_address.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 DeviceProperties {
- public:
- explicit DeviceProperties(const std::string& file_name);
-
- // Access private configuration data
-
- // Specification Version 4.2, Volume 2, Part E, Section 7.4.1
- const std::vector<uint8_t>& GetLocalVersionInformation() const;
-
- // Specification Version 4.2, Volume 2, Part E, Section 7.4.2
- const std::vector<uint8_t>& GetLocalSupportedCommands() const {
- return local_supported_commands_;
- }
-
- // Specification Version 4.2, Volume 2, Part E, Section 7.4.3
- uint64_t GetLocalSupportedFeatures() const {
- return local_extended_features_[0];
- };
-
- // Specification Version 4.2, Volume 2, Part E, Section 7.4.4
- uint8_t GetLocalExtendedFeaturesMaximumPageNumber() const {
- return local_extended_features_.size() - 1;
- };
-
- uint64_t GetLocalExtendedFeatures(uint8_t page_number) const {
- CHECK(page_number < local_extended_features_.size());
- return local_extended_features_[page_number];
- };
-
- // Specification Version 4.2, Volume 2, Part E, Section 7.4.5
- uint16_t GetAclDataPacketSize() const { return acl_data_packet_size_; }
-
- uint8_t GetSynchronousDataPacketSize() const { return sco_data_packet_size_; }
-
- uint16_t GetTotalNumAclDataPackets() const { return num_acl_data_packets_; }
-
- uint16_t GetTotalNumSynchronousDataPackets() const {
- return num_sco_data_packets_;
- }
-
- const BtAddress& GetAddress() const { return address_; }
-
- // Specification Version 4.2, Volume 2, Part E, Section 7.4.8
- const std::vector<uint8_t>& GetSupportedCodecs() const {
- return supported_codecs_;
- }
-
- const std::vector<uint32_t>& GetVendorSpecificCodecs() const {
- return vendor_specific_codecs_;
- }
-
- const std::string& GetLocalName() const { return local_name_; }
-
- uint8_t GetVersion() const { return version_; }
-
- uint16_t GetRevision() const { return revision_; }
-
- uint8_t GetLmpPalVersion() const { return lmp_pal_version_; }
-
- uint16_t GetLmpPalSubversion() const { return lmp_pal_subversion_; }
-
- uint16_t GetManufacturerName() const { return manufacturer_name_; }
-
- // Specification Version 4.2, Volume 2, Part E, Section 7.8.2
- uint16_t GetLeDataPacketLength() const { return le_data_packet_length_; }
-
- uint8_t GetTotalNumLeDataPackets() const { return num_le_data_packets_; }
-
- // Specification Version 4.2, Volume 2, Part E, Section 7.8.3
- uint64_t GetLeLocalSupportedFeatures() const {
- return le_supported_features_;
- }
-
- // Specification Version 4.2, Volume 2, Part E, Section 7.8.14
- uint8_t GetLeWhiteListSize() const { return le_white_list_size_; }
-
- // Specification Version 4.2, Volume 2, Part E, Section 7.8.27
- uint64_t GetLeSupportedStates() const { return le_supported_states_; }
-
- // Vendor-specific commands (see hcidefs.h)
- const std::vector<uint8_t>& GetLeVendorCap() const { return le_vendor_cap_; }
-
- static void RegisterJSONConverter(
- base::JSONValueConverter<DeviceProperties>* 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_;
- std::vector<uint8_t> supported_codecs_;
- std::vector<uint32_t> vendor_specific_codecs_;
- std::vector<uint8_t> local_supported_commands_;
- std::string local_name_;
- std::vector<uint64_t> local_extended_features_;
- BtAddress address_;
-
- uint16_t le_data_packet_length_;
- uint8_t num_le_data_packets_;
- uint8_t le_white_list_size_;
- uint64_t le_supported_features_;
- uint64_t le_supported_states_;
- std::vector<uint8_t> le_vendor_cap_;
-};
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/dual_mode_controller.h b/vendor_libs/test_vendor_lib/include/dual_mode_controller.h
deleted file mode 100644
index 4f7041c..0000000
--- a/vendor_libs/test_vendor_lib/include/dual_mode_controller.h
+++ /dev/null
@@ -1,483 +0,0 @@
-/*
- * 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 <unordered_map>
-#include <vector>
-
-#include "acl_packet.h"
-#include "async_manager.h"
-#include "base/time/time.h"
-#include "bt_address.h"
-#include "command_packet.h"
-#include "connection.h"
-#include "device.h"
-#include "device_properties.h"
-#include "event_packet.h"
-#include "sco_packet.h"
-#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:
- // Sets all of the methods to be used as callbacks in the HciHandler.
- DualModeController();
-
- ~DualModeController() = default;
-
- // Route commands and data from the stack.
- void HandleAcl(std::unique_ptr<AclPacket> acl_packet);
- void HandleCommand(std::unique_ptr<CommandPacket> command_packet);
- void HandleSco(std::unique_ptr<ScoPacket> sco_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);
-
- // Set the callbacks for scheduling tasks.
- void RegisterTaskScheduler(
- std::function<AsyncTaskId(std::chrono::milliseconds, const TaskCallback&)>
- evtScheduler);
-
- void RegisterPeriodicTaskScheduler(
- std::function<AsyncTaskId(std::chrono::milliseconds,
- std::chrono::milliseconds, const TaskCallback&)>
- periodicEvtScheduler);
-
- void RegisterTaskCancel(std::function<void(AsyncTaskId)> cancel);
-
- // Set the callbacks for sending packets to the HCI.
- void RegisterEventChannel(
- const std::function<void(std::unique_ptr<EventPacket>)>& send_event);
-
- void RegisterAclChannel(
- const std::function<void(std::unique_ptr<AclPacket>)>& send_acl);
-
- void RegisterScoChannel(
- const std::function<void(std::unique_ptr<ScoPacket>)>& send_sco);
-
- // 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: 0x0004
- // OCF: 0x000B
- // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.4.8
- void HciReadLocalSupportedCodecs(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);
-
- void InquiryTimeout();
-
- // 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 Commands
-
- // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.7.1
- void HciReadLoopbackMode(const std::vector<uint8_t>& args);
-
- // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.7.2
- void HciWriteLoopbackMode(const std::vector<uint8_t>& args);
-
- // LE Controller Commands
-
- // OGF: 0x0008
- // OCF: 0x0001
- // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.1
- void HciLeSetEventMask(const std::vector<uint8_t>& args);
-
- // OGF: 0x0008
- // OCF: 0x0002
- // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.2
- void HciLeReadBufferSize(const std::vector<uint8_t>& args);
-
- // OGF: 0x0008
- // OCF: 0x0003
- // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.3
- void HciLeReadLocalSupportedFeatures(const std::vector<uint8_t>& args);
-
- // OGF: 0x0008
- // OCF: 0x0005
- // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.4
- void HciLeSetRandomAddress(const std::vector<uint8_t>& args);
-
- // OGF: 0x0008
- // OCF: 0x0006
- // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.5
- void HciLeSetAdvertisingParameters(const std::vector<uint8_t>& args);
-
- // OGF: 0x0008
- // OCF: 0x0008
- // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.7
- void HciLeSetAdvertisingData(const std::vector<uint8_t>& args);
-
- // OGF: 0x0008
- // OCF: 0x000B
- // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.10
- void HciLeSetScanParameters(const std::vector<uint8_t>& args);
-
- // OGF: 0x0008
- // OCF: 0x000C
- // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.11
- void HciLeSetScanEnable(const std::vector<uint8_t>& args);
-
- // OGF: 0x0008
- // OCF: 0x000D
- // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.12
- void HciLeCreateConnection(const std::vector<uint8_t>& args);
-
- // OGF: 0x0008
- // OCF: 0x000E
- // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.13
- void HciLeConnectionCancel(const std::vector<uint8_t>& args);
-
- // OGF: 0x0008
- // OCF: 0x000F
- // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.14
- void HciLeReadWhiteListSize(const std::vector<uint8_t>& args);
-
- // OGF: 0x0008
- // OCF: 0x0016
- // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.21
- void HciLeReadRemoteUsedFeatures(const std::vector<uint8_t>& args);
- void HciLeReadRemoteUsedFeaturesB(uint16_t handle);
-
- // OGF: 0x0008
- // OCF: 0x0018
- // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.23
- void HciLeRand(const std::vector<uint8_t>& args);
-
- // OGF: 0x0008
- // OCF: 0x001C
- // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.27
- void HciLeReadSupportedStates(const std::vector<uint8_t>& args);
-
- // Vendor-specific commands (see hcidefs.h)
-
- // OGF: 0x00FC
- // OCF: 0x0027
- void HciBleVendorSleepMode(const std::vector<uint8_t>& args);
-
- // OGF: 0x00FC
- // OCF: 0x0153
- void HciBleVendorCap(const std::vector<uint8_t>& args);
-
- // OGF: 0x00FC
- // OCF: 0x0154
- void HciBleVendorMultiAdv(const std::vector<uint8_t>& args);
-
- // OGF: 0x00FC
- // OCF: 0x0155
- void HciBleVendor155(const std::vector<uint8_t>& args);
-
- // OGF: 0x00FC
- // OCF: 0x0157
- void HciBleVendor157(const std::vector<uint8_t>& args);
-
- // OGF: 0x00FC
- // OCF: 0x0159
- void HciBleEnergyInfo(const std::vector<uint8_t>& args);
-
- // Test
- void HciBleAdvertisingFilter(const std::vector<uint8_t>& args);
-
- // OGF: 0x00FC
- // OCF: 0x015A
- void HciBleExtendedScanParams(const std::vector<uint8_t>& args);
-
- // Test Channel commands:
-
- // Add devices
- void TestChannelAdd(const std::vector<std::string>& args);
-
- // Remove devices by index
- void TestChannelDel(const std::vector<std::string>& args);
-
- // List the devices that the controller knows about
- void TestChannelList(const std::vector<std::string>& args) const;
-
- void Connections();
-
- void LeScan();
-
- void PageScan();
-
- void HandleTimerTick();
- void SetTimerPeriod(std::chrono::milliseconds new_period);
- void StartTimer();
- void StopTimer();
-
- 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.
- };
-
- // Set a timer for a future action
- void AddControllerEvent(std::chrono::milliseconds,
- const TaskCallback& callback);
-
- void AddConnectionAction(const TaskCallback& callback, uint16_t handle);
-
- // 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;
-
- // Sends a command complete event with no return parameters. This event is
- // typically sent for commands that can be completed immediately.
- void SendCommandCompleteOnlyStatus(uint16_t command_opcode,
- uint8_t status) 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;
-
- void SetEventDelay(int64_t delay);
-
- // Callbacks to schedule tasks.
- std::function<AsyncTaskId(std::chrono::milliseconds, const TaskCallback&)>
- schedule_task_;
- std::function<AsyncTaskId(std::chrono::milliseconds,
- std::chrono::milliseconds, const TaskCallback&)>
- schedule_periodic_task_;
-
- std::function<void(AsyncTaskId)> cancel_task_;
-
- // Callbacks to send packets back to the HCI.
- std::function<void(std::unique_ptr<AclPacket>)> send_acl_;
- std::function<void(std::unique_ptr<EventPacket>)> send_event_;
- std::function<void(std::unique_ptr<ScoPacket>)> send_sco_;
-
- // 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_;
-
- bool inquiry_responses_limited_;
- uint8_t inquiry_num_responses_;
- uint8_t inquiry_lap_[3];
-
- std::vector<uint8_t> le_event_mask_;
-
- BtAddress le_random_address_;
-
- uint8_t le_scan_type_;
- uint16_t le_scan_interval_;
- uint16_t le_scan_window_;
- uint8_t own_address_type_;
- uint8_t scanning_filter_policy_;
-
- uint8_t le_scan_enable_;
- uint8_t filter_duplicates_;
-
- bool le_connect_;
- uint8_t initiator_filter_policy_;
-
- BtAddress peer_address_;
- uint8_t peer_address_type_;
-
- uint8_t loopback_mode_;
-
- State state_;
-
- DeviceProperties properties_;
-
- std::vector<std::shared_ptr<Device>> devices_;
-
- std::vector<AsyncTaskId> controller_events_;
-
- std::vector<std::shared_ptr<Connection>> connections_;
-
- AsyncTaskId timer_tick_task_;
- std::chrono::milliseconds timer_period_ = std::chrono::milliseconds(100);
-
- DualModeController(const DualModeController& cmdPckt) = delete;
- DualModeController& operator=(const DualModeController& cmdPckt) = delete;
-};
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/event_packet.h b/vendor_libs/test_vendor_lib/include/event_packet.h
deleted file mode 100644
index f861c07..0000000
--- a/vendor_libs/test_vendor_lib/include/event_packet.h
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * 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 "base/logging.h"
-#include "bt_address.h"
-#include "packet.h"
-
-namespace test_vendor_lib {
-
-// Event Packets are specified in the Bluetooth Core Specification Version 4.2,
-// Volume 2, Part E, Section 5.4.4
-class EventPacket : public Packet {
- public:
- virtual ~EventPacket() override = default;
-
- uint8_t GetEventCode() const;
-
- // Static functions for creating event packets:
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.1
- static std::unique_ptr<EventPacket> CreateInquiryCompleteEvent(
- uint8_t status);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.14
- // This should only be used for testing to send non-standard packets
- // Most code should use the more specific functions that follow
- static std::unique_ptr<EventPacket> CreateCommandCompleteEvent(
- uint16_t command_opcode,
- const std::vector<uint8_t>& event_return_parameters);
-
- static std::unique_ptr<EventPacket> CreateCommandCompleteOnlyStatusEvent(
- uint16_t command_opcode, uint8_t status);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.15
- static std::unique_ptr<EventPacket> CreateCommandStatusEvent(
- uint8_t status, uint16_t command_opcode);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.19
- static std::unique_ptr<EventPacket> CreateNumberOfCompletedPacketsEvent(
- uint16_t handle, uint16_t num_completed_packets);
-
- void AddCompletedPackets(uint16_t handle, uint16_t num_completed_packets);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.10
- static std::unique_ptr<EventPacket> CreateCommandCompleteDeleteStoredLinkKey(
- uint8_t status, uint16_t num_keys_deleted);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.12
- static std::unique_ptr<EventPacket> CreateCommandCompleteReadLocalName(
- uint8_t status, const std::string& local_name);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.1
- static std::unique_ptr<EventPacket>
- CreateCommandCompleteReadLocalVersionInformation(uint8_t status,
- uint8_t hci_version,
- uint16_t hci_revision,
- uint8_t lmp_pal_version,
- uint16_t manufacturer_name,
- uint16_t lmp_pal_subversion);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.2
- static std::unique_ptr<EventPacket>
- CreateCommandCompleteReadLocalSupportedCommands(
- uint8_t status, const std::vector<uint8_t>& supported_commands);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.4
- static std::unique_ptr<EventPacket>
- CreateCommandCompleteReadLocalExtendedFeatures(
- uint8_t status, uint8_t page_number, uint8_t maximum_page_number,
- uint64_t extended_lmp_features);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.5
- static std::unique_ptr<EventPacket> CreateCommandCompleteReadBufferSize(
- uint8_t status, uint16_t hc_acl_data_packet_length,
- uint8_t hc_synchronous_data_packet_length,
- uint16_t hc_total_num_acl_data_packets,
- uint16_t hc_total_synchronous_data_packets);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.6
- static std::unique_ptr<EventPacket> CreateCommandCompleteReadBdAddr(
- uint8_t status, const BtAddress& bt_address);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.8
- static std::unique_ptr<EventPacket>
- CreateCommandCompleteReadLocalSupportedCodecs(
- uint8_t status, const std::vector<uint8_t>& supported_codecs,
- const std::vector<uint32_t>& vendor_specific_codecs);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.6.1
- static std::unique_ptr<EventPacket> CreateCommandCompleteReadLoopbackMode(
- uint8_t status, uint8_t mode);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.2
- static std::unique_ptr<EventPacket> CreateInquiryResultEvent();
-
- // Returns true if the result can be added to the event packet.
- bool AddInquiryResult(const BtAddress& bt_address,
- uint8_t page_scan_repetition_mode,
- uint32_t class_of_device, uint16_t clock_offset);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.3
- static std::unique_ptr<EventPacket> CreateConnectionCompleteEvent(
- uint8_t status, uint16_t handle, const BtAddress& address,
- uint8_t link_type, bool encryption_enabled);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.25
- static std::unique_ptr<EventPacket> CreateLoopbackCommandEvent(
- uint16_t opcode, const std::vector<uint8_t>& payload);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.38
- static std::unique_ptr<EventPacket> CreateExtendedInquiryResultEvent(
- const BtAddress& bt_address, uint8_t page_scan_repetition_mode,
- uint32_t class_of_device, uint16_t clock_offset, uint8_t rssi,
- const std::vector<uint8_t>& extended_inquiry_response);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
- // 7.7.65.1
- static std::unique_ptr<EventPacket> CreateLeConnectionCompleteEvent(
- uint8_t status, uint16_t handle, uint8_t role, uint8_t peer_address_type,
- const BtAddress& peer, uint16_t interval, uint16_t latency,
- uint16_t supervision_timeout);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
- // 7.7.65.2
- static std::unique_ptr<EventPacket> CreateLeAdvertisingReportEvent();
-
- // Returns true if the report can be added to the event packet.
- bool AddLeAdvertisingReport(uint8_t event_type, uint8_t addr_type,
- const BtAddress& addr,
- const std::vector<uint8_t>& data, uint8_t rssi);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
- // 7.7.65.4
- static std::unique_ptr<EventPacket> CreateLeRemoteUsedFeaturesEvent(
- uint8_t status, uint16_t handle, uint64_t features);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.2
- static std::unique_ptr<EventPacket> CreateCommandCompleteLeReadBufferSize(
- uint8_t status, uint16_t hc_le_data_packet_length,
- uint8_t hc_total_num_le_data_packets);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.3
- static std::unique_ptr<EventPacket>
- CreateCommandCompleteLeReadLocalSupportedFeatures(uint8_t status,
- uint64_t le_features);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.14
- static std::unique_ptr<EventPacket> CreateCommandCompleteLeReadWhiteListSize(
- uint8_t status, uint8_t white_list_size);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.23
- static std::unique_ptr<EventPacket> CreateCommandCompleteLeRand(
- uint8_t status, uint64_t random_val);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.27
- static std::unique_ptr<EventPacket>
- CreateCommandCompleteLeReadSupportedStates(uint8_t status,
- uint64_t le_states);
-
- // Vendor-specific commands (see hcidefs.h)
-
- static std::unique_ptr<EventPacket> CreateCommandCompleteLeVendorCap(
- uint8_t status, const std::vector<uint8_t>& vendor_cap);
-
- // Size of a data packet header, which consists of a 1 octet event code
- static const size_t kEventHeaderSize = 1;
-
- private:
- explicit EventPacket(uint8_t event_code);
- EventPacket(uint8_t event_code, const std::vector<uint8_t>& payload);
-};
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/hci.h b/vendor_libs/test_vendor_lib/include/hci.h
new file mode 100644
index 0000000..11eb029
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/include/hci.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2018 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 "include/hci/event_code.h"
+#include "include/hci/le_sub_event_code.h"
+#include "include/hci/op_code.h"
+#include "include/hci/status.h"
+
+namespace test_vendor_lib {
+namespace hci {
+
+enum class PacketType : uint8_t {
+ UNKNOWN = 0,
+ COMMAND = 1,
+ ACL = 2,
+ SCO = 3,
+ EVENT = 4,
+};
+
+enum class LinkType : uint8_t {
+ SCO = 0x00,
+ ACL = 0x01,
+ ESCO = 0x02,
+};
+
+enum class LoopbackMode : uint8_t {
+ NO = 0x00,
+ LOCAL = 0x01,
+ REMOTE = 0x02,
+};
+
+/* HCI, PAL, and LMP Version numbers are the same */
+enum class Version : uint8_t {
+ V1_0 = 0,
+ V1_1 = 1,
+ V1_2 = 2,
+ V2_0 = 3,
+ V2_1 = 4,
+ V3_0 = 5,
+ V4_0 = 6,
+ V4_1 = 7,
+ V4_2 = 8,
+ V5_0 = 9,
+};
+
+} // namespace hci
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/hci/event_code.h b/vendor_libs/test_vendor_lib/include/hci/event_code.h
new file mode 100644
index 0000000..c0bdcbc
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/include/hci/event_code.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2018 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>
+
+namespace test_vendor_lib {
+namespace hci {
+
+enum class EventCode : uint8_t {
+ INQUIRY_COMPLETE = 0x01,
+ INQUIRY_RESULT = 0x02,
+ CONNECTION_COMPLETE = 0x03,
+ CONNECTION_REQUEST = 0x04,
+ DISCONNECTION_COMPLETE = 0x05,
+ AUTHENTICATION_COMPLETE = 0x06,
+ REMOTE_NAME_REQUEST_COMPLETE = 0x07,
+ ENCRYPTION_CHANGE = 0x08,
+ CHANGE_CONNECTION_LINK_KEY_COMPLETE = 0x09,
+ MASTER_LINK_KEY_COMPLETE = 0x0A,
+ READ_REMOTE_SUPPORTED_FEATURES_COMPLETE = 0x0B,
+ READ_REMOTE_VERSION_INFORMATION_COMPLETE = 0x0C,
+ QOS_SETUP_COMPLETE = 0x0D,
+ COMMAND_COMPLETE = 0x0E,
+ COMMAND_STATUS = 0x0F,
+ HARDWARE_ERROR = 0x10,
+ FLUSH_OCCURED = 0x11,
+ ROLE_CHANGE = 0x12,
+ NUMBER_OF_COMPLETED_PACKETS = 0x13,
+ MODE_CHANGE = 0x14,
+ RETURN_LINK_KEYS = 0x15,
+ PIN_CODE_REQUEST = 0x16,
+ LINK_KEY_REQUEST = 0x17,
+ LINK_KEY_NOTIFICATION = 0x18,
+ LOOPBACK_COMMAND = 0x19,
+ DATA_BUFFER_OVERFLOW = 0x1A,
+ MAX_SLOTS_CHANGE = 0x1B,
+ READ_CLOCK_OFFSET_COMPLETE = 0x1C,
+ CONNECTION_PACKET_TYPE_CHANGE = 0x1D,
+ QOS_VIOLATION = 0x1E,
+ PAGE_SCAN_REPETITION_MODE_CHANGE = 0x20,
+ FLOW_SPECIFICATION_COMPLETE = 0x21,
+ INQUIRY_RESULT_WITH_RSSI = 0x22,
+ READ_REMOTE_EXTENDED_FEATURES_COMPLETE = 0x23,
+ SYNCHRONOUS_CONNECTION_COMPLETE = 0x2C,
+ SYNCHRONOUS_CONNECTION_CHANGED = 0x2D,
+ SNIFF_SUBRATING = 0x2E,
+ EXTENDED_INQUIRY_RESULT = 0x2F,
+ ENCRYPTION_KEY_REFRESH_COMPLETE = 0x30,
+ IO_CAPABILITY_REQUEST = 0x31,
+ IO_CAPABILITY_RESPONSE = 0x32,
+ USER_CONFIRMATION_REQUEST = 0x33,
+ USER_PASSKEY_REQUEST = 0x34,
+ REMOTE_OOB_DATA_REQUEST = 0x35,
+ SIMPLE_PAIRING_COMPLETE = 0x36,
+ LINK_SUPERVISION_TIMEOUT_CHANGED = 0x38,
+ ENHANCED_FLUSH_COMPLETE = 0x39,
+ USER_PASSKEY_NOTIFICATION = 0x3B,
+ KEYPRESS_NOTIFICATION = 0x3C,
+ REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION = 0x3D,
+ LE_META_EVENT = 0x3e,
+ PHYSICAL_LINK_COMPLETE = 0x40,
+ CHANNEL_SELECTED = 0x41,
+ DISCONNECTION_PHYSICAL_LINK_COMPLETE = 0x42,
+ PHYSICAL_LINK_LOSS_EARLY_WARNING = 0x43,
+ PHYSICAL_LINK_RECOVERY = 0x44,
+ LOGICAL_LINK_COMPLETE = 0x45,
+ DISCONNECTION_LOGICAL_LINK_COMPLETE = 0x46,
+ FLOW_SPEC_MODIFY_COMPLETE = 0x47,
+ NUMBER_OF_COMPLETED_DATA_BLOCKS = 0x48,
+ SHORT_RANGE_MODE_CHANGE_COMPLETE = 0x4C,
+};
+}
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/hci/le_sub_event_code.h b/vendor_libs/test_vendor_lib/include/hci/le_sub_event_code.h
new file mode 100644
index 0000000..42edecd
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/include/hci/le_sub_event_code.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2018 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>
+
+namespace test_vendor_lib {
+namespace hci {
+
+enum class LeSubEventCode : uint8_t {
+ CONNECTION_COMPLETE = 0x01,
+ ADVERTISING_REPORT = 0x02,
+ CONNECTION_UPDATE_COMPLETE = 0x03,
+ READ_REMOTE_FEATURES_COMPLETE = 0x04,
+ LONG_TERM_KEY_REQUEST = 0x05,
+ REMOTE_CONNECTION_PARAMETER_REQUEST = 0x06,
+ DATA_LENGTH_CHANGE = 0x07,
+ ENHANCED_CONNECTION_COMPLETE = 0x0a,
+ DIRECTED_ADVERTISING_REPORT = 0x0b,
+ PHY_UPDATE_COMPLETE = 0x0c,
+ EXTENDED_ADVERTISING_REPORT = 0x0D,
+ PERIODIC_ADVERTISING_SYNC_ESTABLISHED = 0x0E,
+ PERIODIC_ADVERTISING_REPORT = 0x0F,
+ PERIODIC_ADVERTISING_SYNC_LOST = 0x10,
+ SCAN_TIMEOUT = 0x11,
+ ADVERTISING_SET_TERMINATED = 0x12,
+ SCAN_REQUEST_RECEIVED = 0x13,
+};
+}
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/hci/op_code.h b/vendor_libs/test_vendor_lib/include/hci/op_code.h
new file mode 100644
index 0000000..931145d
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/include/hci/op_code.h
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2018 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>
+
+namespace test_vendor_lib {
+namespace hci {
+
+using CommandGroups = enum {
+ LINK_CONTROL = 0x01 << 10, /* 0x0400 */
+ LINK_POLICY = 0x02 << 10, /* 0x0800 */
+ CONTROLLER_AND_BASEBAND = 0x03 << 10, /* 0x0C00 */
+ INFORMATIONAL_PARAMETERS = 0x04 << 10, /* 0x1000 */
+ STATUS_PARAMETERS = 0x05 << 10, /* 0x1400 */
+ TESTING = 0x06 << 10, /* 0x1800 */
+ LE_CONTROLLER = 0x08 << 10, /* 0x2000 */
+ VENDOR_SPECIFIC = 0x3F << 10, /* 0xFC00 */
+};
+
+enum class OpCode : uint16_t {
+ NONE = 0x0000,
+
+ /* LINK_CONTROL */
+ INQUIRY = LINK_CONTROL | 0x0001,
+ INQUIRY_CANCEL = LINK_CONTROL | 0x0002,
+ PERIODIC_INQUIRY_MODE = LINK_CONTROL | 0x0003,
+ EXIT_PERIODIC_INQUIRY_MODE = LINK_CONTROL | 0x0004,
+ CREATE_CONNECTION = LINK_CONTROL | 0x0005,
+ DISCONNECT = LINK_CONTROL | 0x0006,
+ CREATE_CONNECTION_CANCEL = LINK_CONTROL | 0x0008,
+ ACCEPT_CONNECTION_REQUEST = LINK_CONTROL | 0x0009,
+ REJECT_CONNECTION_REQUEST = LINK_CONTROL | 0x000A,
+ LINK_KEY_REQUEST_REPLY = LINK_CONTROL | 0x000B,
+ LINK_KEY_REQUEST_NEGATIVE_REPLY = LINK_CONTROL | 0x000C,
+ PIN_CODE_REQUEST_REPLY = LINK_CONTROL | 0x000D,
+ PIN_CODE_REQUEST_NEGATIVE_REPLY = LINK_CONTROL | 0x000E,
+ CHANGE_CONNECTION_PACKET_TYPE = LINK_CONTROL | 0x000F,
+ AUTHENTICATION_REQUESTED = LINK_CONTROL | 0x0011,
+ SET_CONNECTION_ENCRYPTION = LINK_CONTROL | 0x0013,
+ CHANGE_CONNECTION_LINK_KEY = LINK_CONTROL | 0x0015,
+ MASTER_LINK_KEY = LINK_CONTROL | 0x0017,
+ REMOTE_NAME_REQUEST = LINK_CONTROL | 0x0019,
+ REMOTE_NAME_REQUEST_CANCEL = LINK_CONTROL | 0x001A,
+ READ_REMOTE_SUPPORTED_FEATURES = LINK_CONTROL | 0x001B,
+ READ_REMOTE_EXTENDED_FEATURES = LINK_CONTROL | 0x001C,
+ READ_REMOTE_VERSION_INFORMATION = LINK_CONTROL | 0x001D,
+ READ_CLOCK_OFFSET = LINK_CONTROL | 0x001F,
+ READ_LMP_HANDLE = LINK_CONTROL | 0x0020,
+ SETUP_SYNCHRONOUS_CONNECTION = LINK_CONTROL | 0x0028,
+ ACCEPT_SYNCHRONOUS_CONNECTION = LINK_CONTROL | 0x0029,
+ REJECT_SYNCHRONOUS_CONNECTION = LINK_CONTROL | 0x002A,
+ IO_CAPABILITY_REQUEST_REPLY = LINK_CONTROL | 0x002B,
+ USER_CONFIRMATION_REQUEST_REPLY = LINK_CONTROL | 0x002C,
+ USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY = LINK_CONTROL | 0x002D,
+ USER_PASSKEY_REQUEST_REPLY = LINK_CONTROL | 0x002E,
+ USER_PASSKEY_REQUEST_NEGATIVE_REPLY = LINK_CONTROL | 0x002F,
+ REMOTE_OOB_DATA_REQUEST_REPLY = LINK_CONTROL | 0x0030,
+ REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY = LINK_CONTROL | 0x0033,
+ IO_CAPABILITY_REQUEST_NEGATIVE_REPLY = LINK_CONTROL | 0x0034,
+ ENHANCED_SETUP_SYNCHRONOUS_CONNECTION = LINK_CONTROL | 0x003D,
+ ENHANCED_ACCEPT_SYNCHRONOUS_CONNECTION = LINK_CONTROL | 0x003E,
+
+ /* LINK_POLICY */
+ HOLD_MODE = LINK_POLICY | 0x0001,
+ SNIFF_MODE = LINK_POLICY | 0x0003,
+ EXIT_SNIFF_MODE = LINK_POLICY | 0x0004,
+ QOS_SETUP = LINK_POLICY | 0x0007,
+ ROLE_DISCOVERY = LINK_POLICY | 0x0009,
+ SWITCH_ROLE = LINK_POLICY | 0x000B,
+ READ_LINK_POLICY_SETTINGS = LINK_POLICY | 0x000C,
+ WRITE_LINK_POLICY_SETTINGS = LINK_POLICY | 0x000D,
+ READ_DEFAULT_LINK_POLICY_SETTINGS = LINK_POLICY | 0x000E,
+ WRITE_DEFAULT_LINK_POLICY_SETTINGS = LINK_POLICY | 0x000F,
+ FLOW_SPECIFICATION = LINK_POLICY | 0x0010,
+ SNIFF_SUBRATING = LINK_POLICY | 0x0011,
+
+ /* CONTROLLER_AND_BASEBAND */
+ SET_EVENT_MASK = CONTROLLER_AND_BASEBAND | 0x0001,
+ RESET = CONTROLLER_AND_BASEBAND | 0x0003,
+ SET_EVENT_FILTER = CONTROLLER_AND_BASEBAND | 0x0005,
+ FLUSH = CONTROLLER_AND_BASEBAND | 0x0008,
+ READ_PIN_TYPE = CONTROLLER_AND_BASEBAND | 0x0009,
+ WRITE_PIN_TYPE = CONTROLLER_AND_BASEBAND | 0x000A,
+ CREATE_NEW_UNIT_KEY = CONTROLLER_AND_BASEBAND | 0x000B,
+ READ_STORED_LINK_KEY = CONTROLLER_AND_BASEBAND | 0x000D,
+ WRITE_STORED_LINK_KEY = CONTROLLER_AND_BASEBAND | 0x0011,
+ DELETE_STORED_LINK_KEY = CONTROLLER_AND_BASEBAND | 0x0012,
+ WRITE_LOCAL_NAME = CONTROLLER_AND_BASEBAND | 0x0013,
+ READ_LOCAL_NAME = CONTROLLER_AND_BASEBAND | 0x0014,
+ READ_CONNECTION_ACCEPT_TIMEOUT = CONTROLLER_AND_BASEBAND | 0x0015,
+ WRITE_CONNECTION_ACCEPT_TIMEOUT = CONTROLLER_AND_BASEBAND | 0x0016,
+ READ_PAGE_TIMEOUT = CONTROLLER_AND_BASEBAND | 0x0017,
+ WRITE_PAGE_TIMEOUT = CONTROLLER_AND_BASEBAND | 0x0018,
+ READ_SCAN_ENABLE = CONTROLLER_AND_BASEBAND | 0x0019,
+ WRITE_SCAN_ENABLE = CONTROLLER_AND_BASEBAND | 0x001A,
+ READ_PAGE_SCAN_ACTIVITY = CONTROLLER_AND_BASEBAND | 0x001B,
+ WRITE_PAGE_SCAN_ACTIVITY = CONTROLLER_AND_BASEBAND | 0x001C,
+ READ_INQUIRY_SCAN_ACTIVITY = CONTROLLER_AND_BASEBAND | 0x001D,
+ WRITE_INQUIRY_SCAN_ACTIVITY = CONTROLLER_AND_BASEBAND | 0x001E,
+ READ_AUTHENTICATION_ENABLE = CONTROLLER_AND_BASEBAND | 0x001F,
+ WRITE_AUTHENTICATION_ENABLE = CONTROLLER_AND_BASEBAND | 0x0020,
+ READ_CLASS_OF_DEVICE = CONTROLLER_AND_BASEBAND | 0x0023,
+ WRITE_CLASS_OF_DEVICE = CONTROLLER_AND_BASEBAND | 0x0024,
+ READ_VOICE_SETTING = CONTROLLER_AND_BASEBAND | 0x0025,
+ WRITE_VOICE_SETTING = CONTROLLER_AND_BASEBAND | 0x0026,
+ READ_AUTOMATIC_FLUSH_TIMEOUT = CONTROLLER_AND_BASEBAND | 0x0027,
+ WRITE_AUTOMATIC_FLUSH_TIMEOUT = CONTROLLER_AND_BASEBAND | 0x0028,
+ READ_NUM_BROADCAST_RETRANSMITS = CONTROLLER_AND_BASEBAND | 0x0029,
+ WRITE_NUM_BROADCAST_RETRANSMITS = CONTROLLER_AND_BASEBAND | 0x002A,
+ READ_HOLD_MODE_ACTIVITY = CONTROLLER_AND_BASEBAND | 0x002B,
+ WRITE_HOLD_MODE_ACTIVITY = CONTROLLER_AND_BASEBAND | 0x002C,
+ READ_TRANSMIT_POWER_LEVEL = CONTROLLER_AND_BASEBAND | 0x002D,
+ READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE = CONTROLLER_AND_BASEBAND | 0x002E,
+ WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE = CONTROLLER_AND_BASEBAND | 0x002F,
+ SET_CONTROLLER_TO_HOST_FLOW_CONTROL = CONTROLLER_AND_BASEBAND | 0x0031,
+ HOST_BUFFER_SIZE = CONTROLLER_AND_BASEBAND | 0x0033,
+ HOST_NUM_COMPLETED_PACKETS = CONTROLLER_AND_BASEBAND | 0x0035,
+ READ_LINK_SUPERVISION_TIMEOUT = CONTROLLER_AND_BASEBAND | 0x0036,
+ WRITE_LINK_SUPERVISION_TIMEOUT = CONTROLLER_AND_BASEBAND | 0x0037,
+ READ_NUMBER_OF_SUPPORTED_IAC = CONTROLLER_AND_BASEBAND | 0x0038,
+ READ_CURRENT_IAC_LAP = CONTROLLER_AND_BASEBAND | 0x0039,
+ WRITE_CURRENT_IAC_LAP = CONTROLLER_AND_BASEBAND | 0x003A,
+ SET_AFH_HOST_CHANNEL_CLASSIFICATION = CONTROLLER_AND_BASEBAND | 0x003F,
+ READ_LE_HOST_SUPPORT = CONTROLLER_AND_BASEBAND | 0x6C,
+ WRITE_LE_HOST_SUPPORT = CONTROLLER_AND_BASEBAND | 0x6D,
+ READ_INQUIRY_SCAN_TYPE = CONTROLLER_AND_BASEBAND | 0x0042,
+ WRITE_INQUIRY_SCAN_TYPE = CONTROLLER_AND_BASEBAND | 0x0043,
+ READ_INQUIRY_MODE = CONTROLLER_AND_BASEBAND | 0x0044,
+ WRITE_INQUIRY_MODE = CONTROLLER_AND_BASEBAND | 0x0045,
+ READ_PAGE_SCAN_TYPE = CONTROLLER_AND_BASEBAND | 0x0046,
+ WRITE_PAGE_SCAN_TYPE = CONTROLLER_AND_BASEBAND | 0x0047,
+ READ_AFH_CHANNEL_ASSESSMENT_MODE = CONTROLLER_AND_BASEBAND | 0x0048,
+ WRITE_AFH_CHANNEL_ASSESSMENT_MODE = CONTROLLER_AND_BASEBAND | 0x0049,
+ READ_EXTENDED_INQUIRY_RESPONSE = CONTROLLER_AND_BASEBAND | 0x0051,
+ WRITE_EXTENDED_INQUIRY_RESPONSE = CONTROLLER_AND_BASEBAND | 0x0052,
+ REFRESH_ENCRYPTION_KEY = CONTROLLER_AND_BASEBAND | 0x0053,
+ READ_SIMPLE_PAIRING_MODE = CONTROLLER_AND_BASEBAND | 0x0055,
+ WRITE_SIMPLE_PAIRING_MODE = CONTROLLER_AND_BASEBAND | 0x0056,
+ READ_LOCAL_OOB_DATA = CONTROLLER_AND_BASEBAND | 0x0057,
+ READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL = CONTROLLER_AND_BASEBAND | 0x0058,
+ WRITE_INQUIRY_TRANSMIT_POWER_LEVEL = CONTROLLER_AND_BASEBAND | 0x0059,
+ SEND_KEYPRESS_NOTIFICATION = CONTROLLER_AND_BASEBAND | 0x0060,
+
+ READ_SECURE_CONNECTIONS_HOST_SUPPORT = CONTROLLER_AND_BASEBAND | 0x0079,
+ WRITE_SECURE_CONNECTIONS_HOST_SUPPORT = CONTROLLER_AND_BASEBAND | 0x007A,
+
+ /* INFORMATIONAL_PARAMETERS */
+ READ_LOCAL_VERSION_INFORMATION = INFORMATIONAL_PARAMETERS | 0x0001,
+ READ_LOCAL_SUPPORTED_COMMANDS = INFORMATIONAL_PARAMETERS | 0x0002,
+ READ_LOCAL_SUPPORTED_FEATURES = INFORMATIONAL_PARAMETERS | 0x0003,
+ READ_LOCAL_EXTENDED_FEATURES = INFORMATIONAL_PARAMETERS | 0x0004,
+ READ_BUFFER_SIZE = INFORMATIONAL_PARAMETERS | 0x0005,
+ READ_BD_ADDR = INFORMATIONAL_PARAMETERS | 0x0009,
+ READ_DATA_BLOCK_SIZE = INFORMATIONAL_PARAMETERS | 0x000A,
+ READ_LOCAL_SUPPORTED_CODECS = INFORMATIONAL_PARAMETERS | 0x000B,
+
+ /* STATUS_PARAMETERS */
+ READ_FAILED_CONTACT_COUNTER = STATUS_PARAMETERS | 0x0001,
+ RESET_FAILED_CONTACT_COUNTER = STATUS_PARAMETERS | 0x0002,
+ READ_LINK_QUALITY = STATUS_PARAMETERS | 0x0003,
+ READ_RSSI = STATUS_PARAMETERS | 0x0005,
+ READ_AFH_CHANNEL_MAP = STATUS_PARAMETERS | 0x0006,
+ READ_CLOCK = STATUS_PARAMETERS | 0x0007,
+ READ_ENCRYPTION_KEY_SIZE = STATUS_PARAMETERS | 0x0008,
+
+ /* TESTING */
+ READ_LOOPBACK_MODE = TESTING | 0x0001,
+ WRITE_LOOPBACK_MODE = TESTING | 0x0002,
+ ENABLE_DEVICE_UNDER_TEST_MODE = TESTING | 0x0003,
+ WRITE_SIMPLE_PAIRING_DEBUG_MODE = TESTING | 0x0004,
+ WRITE_SECURE_CONNECTIONS_TEST_MODE = TESTING | 0x000A,
+
+ /* LE_CONTROLLER */
+ LE_SET_EVENT_MASK = LE_CONTROLLER | 0x0001,
+ LE_READ_BUFFER_SIZE = LE_CONTROLLER | 0x0002,
+ LE_READ_LOCAL_SUPPORTED_FEATURES = LE_CONTROLLER | 0x0003,
+ LE_WRITE_LOCAL_SUPPORTED_FEATURES = LE_CONTROLLER | 0x0004,
+ LE_SET_RANDOM_ADDRESS = LE_CONTROLLER | 0x0005,
+ LE_SET_ADVERTISING_PARAMETERS = LE_CONTROLLER | 0x0006,
+ LE_READ_ADVERTISING_CHANNEL_TX_POWER = LE_CONTROLLER | 0x0007,
+ LE_SET_ADVERTISING_DATA = LE_CONTROLLER | 0x0008,
+ LE_SET_SCAN_RSPONSE_DATA = LE_CONTROLLER | 0x0009,
+ LE_SET_ADVERTISING_ENABLE = LE_CONTROLLER | 0x000A,
+ LE_SET_SCAN_PARAMETERS = LE_CONTROLLER | 0x000B,
+ LE_SET_SCAN_ENABLE = LE_CONTROLLER | 0x000C,
+ LE_CREATE_CONNECTION = LE_CONTROLLER | 0x000D,
+ LE_CREATE_CONNECTION_CANCEL = LE_CONTROLLER | 0x000E,
+ LE_READ_WHITE_LIST_SIZE = LE_CONTROLLER | 0x000F,
+ LE_CLEAR_WHITE_LIST = LE_CONTROLLER | 0x0010,
+ LE_ADD_DEVICE_TO_WHITE_LIST = LE_CONTROLLER | 0x0011,
+ LE_REMOVE_DEVICE_FROM_WHITE_LIST = LE_CONTROLLER | 0x0012,
+ LE_CONNECTION_UPDATE = LE_CONTROLLER | 0x0013,
+ LE_SET_HOST_CHANNEL_CLASSIFICATION = LE_CONTROLLER | 0x0014,
+ LE_READ_CHANNEL_MAP = LE_CONTROLLER | 0x0015,
+ LE_READ_REMOTE_FEATURES = LE_CONTROLLER | 0x0016,
+ LE_ENCRYPT = LE_CONTROLLER | 0x0017,
+ LE_RAND = LE_CONTROLLER | 0x0018,
+ LE_START_ENCRYPTION = LE_CONTROLLER | 0x0019,
+ LE_LONG_TERM_KEY_REQUEST_REPLY = LE_CONTROLLER | 0x001A,
+ LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY = LE_CONTROLLER | 0x001B,
+ LE_READ_SUPPORTED_STATES = LE_CONTROLLER | 0x001C,
+ LE_RECEIVER_TEST = LE_CONTROLLER | 0x001D,
+ LE_TRANSMITTER_TEST = LE_CONTROLLER | 0x001E,
+ LE_TEST_END = LE_CONTROLLER | 0x001F,
+ LE_REMOTE_CONNECTION_PARAMETER_REQUEST_REPLY = LE_CONTROLLER | 0x0020,
+ LE_REMOTE_CONNECTION_PARAMETER_REQUEST_NEGATIVE_REPLY = LE_CONTROLLER | 0x0021,
+
+ LE_SET_DATA_LENGTH = LE_CONTROLLER | 0x0022,
+ LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH = LE_CONTROLLER | 0x0023,
+ LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH = LE_CONTROLLER | 0x0024,
+ LE_READ_LOCAL_P_256_PUBLIC_KEY_COMMAND = LE_CONTROLLER | 0x0025,
+ LE_GENERATE_DHKEY_COMMAND = LE_CONTROLLER | 0x0026,
+ LE_ADD_DEVICE_TO_RESOLVING_LIST = LE_CONTROLLER | 0x0027,
+ LE_REMOVE_DEVICE_FROM_RESOLVING_LIST = LE_CONTROLLER | 0x0028,
+ LE_CLEAR_RESOLVING_LIST = LE_CONTROLLER | 0x0029,
+ LE_READ_RESOLVING_LIST_SIZE = LE_CONTROLLER | 0x002A,
+ LE_READ_PEER_RESOLVABLE_ADDRESS = LE_CONTROLLER | 0x002B,
+ LE_READ_LOCAL_RESOLVABLE_ADDRESS = LE_CONTROLLER | 0x002C,
+ LE_SET_ADDRESS_RESOLUTION_ENABLE = LE_CONTROLLER | 0x002D,
+ LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT = LE_CONTROLLER | 0x002E,
+ LE_READ_MAXIMUM_DATA_LENGTH = LE_CONTROLLER | 0x002F,
+ LE_READ_PHY = LE_CONTROLLER | 0x0030,
+ LE_SET_DEFAULT_PHY = LE_CONTROLLER | 0x0031,
+ LE_SET_PHY = LE_CONTROLLER | 0x0032,
+ LE_ENHANCED_RECEIVER_TEST = LE_CONTROLLER | 0x0033,
+ LE_ENHANCED_TRANSMITTER_TEST = LE_CONTROLLER | 0x0034,
+ LE_SET_EXTENDED_ADVERTISING_RANDOM_ADDRESS = LE_CONTROLLER | 0x35,
+ LE_SET_EXTENDED_ADVERTISING_PARAMETERS = LE_CONTROLLER | 0x36,
+ LE_SET_EXTENDED_ADVERTISING_DATA = LE_CONTROLLER | 0x37,
+ LE_SET_EXTENDED_ADVERTISING_SCAN_RESPONSE = LE_CONTROLLER | 0x38,
+ LE_SET_EXTENDED_ADVERTISING_ENABLE = LE_CONTROLLER | 0x39,
+ LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH = LE_CONTROLLER | 0x003A,
+ LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS = LE_CONTROLLER | 0x003B,
+ LE_REMOVE_ADVERTISING_SET = LE_CONTROLLER | 0x003C,
+ LE_CLEAR_ADVERTISING_SETS = LE_CONTROLLER | 0x003D,
+ LE_SET_PERIODIC_ADVERTISING_PARAM = LE_CONTROLLER | 0x003E,
+ LE_SET_PERIODIC_ADVERTISING_DATA = LE_CONTROLLER | 0x003F,
+ LE_SET_PERIODIC_ADVERTISING_ENABLE = LE_CONTROLLER | 0x0040,
+ LE_SET_EXTENDED_SCAN_PARAMETERS = LE_CONTROLLER | 0x0041,
+ LE_SET_EXTENDED_SCAN_ENABLE = LE_CONTROLLER | 0x0042,
+ LE_EXTENDED_CREATE_CONNECTION = LE_CONTROLLER | 0x0043,
+ LE_PERIODIC_ADVERTISING_CREATE_SYNC = LE_CONTROLLER | 0x0044,
+ LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL = LE_CONTROLLER | 0x0045,
+ LE_PERIODIC_ADVERTISING_TERMINATE_SYNC = LE_CONTROLLER | 0x0046,
+ LE_ADD_DEVICE_TO_PERIODIC_ADVERTISING_LIST = LE_CONTROLLER | 0x0047,
+ LE_REMOVE_DEVICE_FROM_PERIODIC_ADVERTISING_LIST = LE_CONTROLLER | 0x0048,
+ LE_CLEAR_PERIODIC_ADVERTISING_LIST = LE_CONTROLLER | 0x0049,
+ LE_READ_PERIODIC_ADVERTISING_LIST_SIZE = LE_CONTROLLER | 0x004A,
+ LE_READ_TRANSMIT_POWER = LE_CONTROLLER | 0x004B,
+ LE_READ_RF_PATH_COMPENSATION_POWER = LE_CONTROLLER | 0x004C,
+ LE_WRITE_RF_PATH_COMPENSATION_POWER = LE_CONTROLLER | 0x004D,
+ LE_SET_PRIVACY_MODE = LE_CONTROLLER | 0x004E,
+
+ /* VENDOR_SPECIFIC */
+ LE_GET_VENDOR_CAPABILITIES = VENDOR_SPECIFIC | 0x0153,
+ LE_MULTI_ADVT = VENDOR_SPECIFIC | 0x0154,
+ LE_BATCH_SCAN = VENDOR_SPECIFIC | 0x0156,
+ LE_ADV_FILTER = VENDOR_SPECIFIC | 0x0157,
+ LE_TRACK_ADV = VENDOR_SPECIFIC | 0x0158,
+ LE_ENERGY_INFO = VENDOR_SPECIFIC | 0x0159,
+ LE_EXTENDED_SCAN_PARAMS = VENDOR_SPECIFIC | 0x015A,
+ CONTROLLER_DEBUG_INFO = VENDOR_SPECIFIC | 0x015B,
+ CONTROLLER_A2DP_OPCODE = VENDOR_SPECIFIC | 0x015D,
+};
+
+} // namespace hci
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/hci/status.h b/vendor_libs/test_vendor_lib/include/hci/status.h
new file mode 100644
index 0000000..4452cfa
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/include/hci/status.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2018 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>
+
+namespace test_vendor_lib {
+namespace hci {
+
+enum class Status : uint8_t {
+ SUCCESS = 0,
+ UNKNOWN_COMMAND = 1,
+ UNKNOWN_CONNECTION = 2,
+ HARDWARE_FAILURE = 3,
+ PAGE_TIMEOUT = 4,
+ AUTHENTICATION_FAILURE = 5,
+ PIN_OR_KEY_MISSING = 6,
+ MEMORY_CAPACITY_EXCEEDED = 7,
+ CONNECTION_TIMEOUT = 8,
+ COMMAND_DISALLOWED = 0x0c,
+ CONNECTION_REJECTED_LIMITED_RESOURCES = 0x0d,
+ CONNECTION_REJECTED_SECURITY = 0x0e,
+ CONNECTION_REJECTED_UNACCEPTABLE_BD_ADDR = 0x0f,
+ INVALID_HCI_COMMAND_PARAMETERS = 0x12,
+ REMOTE_USER_TERMINATED_CONNECTION = 0x13,
+ CONNECTION_TERMINATED_BY_LOCAL_HOST = 0x16,
+ UNSPECIFIED_ERROR = 0x1f,
+ ENCRYPTION_MODE_NOT_ACCEPTABLE = 0x25,
+ HOST_BUSY_PAIRING = 0x38,
+ CONTROLLER_BUSY = 0x3a,
+};
+}
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/hci_packet.h b/vendor_libs/test_vendor_lib/include/hci_packet.h
deleted file mode 100644
index f7be08e..0000000
--- a/vendor_libs/test_vendor_lib/include/hci_packet.h
+++ /dev/null
@@ -1,86 +0,0 @@
-#pragma once
-#include <iterator>
-#include <memory>
-#include <type_traits>
-
-#include "base/logging.h"
-
-namespace test_vendor_lib {
-
-// Iterator is a custom iterator class for HciPackets.
-class Iterator
- : public std::iterator<std::random_access_iterator_tag, uint8_t> {
- public:
- Iterator(std::shared_ptr<class HciPacket> packet, size_t i);
- Iterator(const Iterator& itr);
-
- ~Iterator() {}
-
- operator bool() const;
-
- // All addition and subtraction operators are bounded from 0 to the length of
- // the packet.
- Iterator operator+(size_t offset);
- Iterator& operator+=(size_t offset);
- Iterator operator++(int);
- Iterator& operator++();
-
- Iterator operator-(size_t offset);
- int operator-(Iterator& itr);
- Iterator& operator-=(size_t offset);
- Iterator operator--(int);
- Iterator& operator--();
-
- Iterator& operator=(const Iterator& itr);
-
- bool operator!=(Iterator& itr);
- bool operator==(Iterator& itr);
-
- bool operator<(Iterator& itr);
- bool operator>(Iterator& itr);
-
- bool operator<=(Iterator& itr);
- bool operator>=(Iterator& itr);
-
- uint8_t& operator*() const;
- uint8_t* operator->() const;
-
- // Get the next sizeof(FixedWidthIntegerType) bytes and return the filled type
- template <typename FixedWidthIntegerType>
- FixedWidthIntegerType extract() {
- static_assert(std::is_integral<FixedWidthIntegerType>::value,
- "Iterator::extract requires an integral type.");
- FixedWidthIntegerType extracted_value = 0;
-
- for (size_t i = 0; i < sizeof(FixedWidthIntegerType); i++) {
- extracted_value |= static_cast<FixedWidthIntegerType>(**this) << i * 8;
- (*this)++;
- }
-
- return extracted_value;
- }
-
- private:
- std::shared_ptr<class HciPacket> hci_packet_;
- size_t index_;
-
-}; // Iterator
-
-// HciPacket is an abstract class that will serve as the base class for all
-// packet types.
-class HciPacket : public std::enable_shared_from_this<HciPacket> {
- public:
- virtual ~HciPacket() = default;
-
- Iterator get_begin();
- Iterator get_end();
-
- uint8_t operator[](size_t i);
-
- virtual size_t get_length() = 0;
-
- virtual uint8_t& get_at_index(size_t index) = 0;
-
-}; // HciPacket
-
-}; // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/inquiry.h b/vendor_libs/test_vendor_lib/include/inquiry.h
new file mode 100644
index 0000000..f989af4
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/include/inquiry.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2018 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
+
+namespace test_vendor_lib {
+
+class Inquiry {
+ public:
+ enum class InquiryState : uint8_t {
+ STANDBY = 0x00,
+ INQUIRY = 0x01,
+ };
+ enum class InquiryType : uint8_t {
+ STANDARD = 0x00,
+ RSSI = 0x01,
+ EXTENDED = 0x02,
+ };
+};
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/keyboard.h b/vendor_libs/test_vendor_lib/include/keyboard.h
deleted file mode 100644
index 9d1cfbf..0000000
--- a/vendor_libs/test_vendor_lib/include/keyboard.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2016 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 "bt_address.h"
-#include "device.h"
-
-namespace test_vendor_lib {
-
-class Keyboard : public Device {
- public:
- Keyboard();
- virtual ~Keyboard() = default;
-
- // Initialize the device based on the values of |args|.
- virtual void Initialize(const std::vector<std::string>& args) override;
-
- // Return a string representation of the type of device.
- virtual std::string GetTypeString() const override;
-
- virtual bool LeConnect();
-
- virtual bool IsPageScanAvailable() const override;
-};
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/l2cap_packet.h b/vendor_libs/test_vendor_lib/include/l2cap_packet.h
deleted file mode 100644
index 1205ee1..0000000
--- a/vendor_libs/test_vendor_lib/include/l2cap_packet.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2017 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 <cmath>
-#include <cstdint>
-#include <iterator>
-#include <memory>
-#include <vector>
-
-#include "base/macros.h"
-#include "hci_packet.h"
-#include "l2cap_sdu.h"
-
-namespace test_vendor_lib {
-
-const int kSduHeaderLength = 4;
-
-class L2capPacket : public HciPacket {
- public:
- // Returns an assembled L2cap object if successful, nullptr if failure.
- static std::shared_ptr<L2capPacket> assemble(
- const std::vector<std::shared_ptr<L2capSdu> >& sdu_packet);
-
- // Returns a fragmented vector of L2capSdu objects if successful
- // Returns an empty vector of L2capSdu objects if unsuccessful
- std::vector<std::shared_ptr<L2capSdu> > fragment(uint16_t maximum_sdu_size,
- uint8_t txseq,
- uint8_t reqseq);
-
- uint16_t get_l2cap_cid() const;
-
- // HciPacket Functions
- size_t get_length();
- uint8_t& get_at_index(size_t index);
-
- private:
- L2capPacket() = default;
-
- // Entire L2CAP packet: length, CID, and payload in that order.
- std::vector<uint8_t> l2cap_packet_;
-
- DISALLOW_COPY_AND_ASSIGN(L2capPacket);
-
- // Helper functions for fragmenting.
- static void set_sdu_header_length(std::vector<uint8_t>& sdu, uint16_t length);
-
- static void set_total_sdu_length(std::vector<uint8_t>& sdu,
- uint16_t total_sdu_length);
-
- static void set_sdu_cid(std::vector<uint8_t>& sdu, uint16_t cid);
-
- static void set_sdu_control_bytes(std::vector<uint8_t>& sdu, uint8_t txseq,
- uint8_t reqseq);
-
- bool check_l2cap_packet() const;
-
-}; // L2capPacket
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/l2cap_sdu.h b/vendor_libs/test_vendor_lib/include/l2cap_sdu.h
deleted file mode 100644
index 489f001..0000000
--- a/vendor_libs/test_vendor_lib/include/l2cap_sdu.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright 2017 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 <iterator>
-#include <vector>
-
-#include "hci_packet.h"
-
-namespace test_vendor_lib {
-
-// Abstract representation of an SDU packet that contains an L2CAP
-// payload. This class is meant to be used in collaboration with
-// the L2cap class defined in l2cap.h. For example, an SDU packet
-// may look as follows:
-//
-// vector<uint8_t> sdu = {0x04, 0x00, 0x48, 0x00, 0x04, 0x00, 0xab,
-// 0xcd, 0x78, 0x56}
-//
-// The first two bytes (in little endian) should be read as 0x0004
-// and is the length of the payload of the SDU packet.
-//
-// The next two bytes (also in little endian) are the channel ID
-// and should be read as 0x0048. These should remain the same for
-// any number of SDUs that are a part of the same packet stream.
-//
-// Following the CID bytes, are the total length bytes. Since this
-// SDU only requires a single packet, the length here is the same
-// as the length in the first two bytes of the packet. Again stored
-// in little endian.
-//
-// Next comes the two control bytes. These begin the L2CAP payload
-// of the SDU packet; however, they will not be added to the L2CAP
-// packet that is being constructed in the assemble function that
-// will be creating an L2CAP packet from a stream of L2capSdu
-// objects.
-//
-// The final two bytes are the frame check sequence that should be
-// calculated from the start of the vector to the end of the
-// payload.
-//
-// Thus, calling assemble on this example would create a
-// zero-length L2CAP packet because the information payload of the
-// L2CAP packet will not include either of the control or FCS
-// bytes.
-//
-class L2capSdu : public HciPacket {
- public:
- // Returns a unique_ptr to an L2capSdu object that is constructed with the
- // assumption that the SDU packet is complete and correct.
- static std::shared_ptr<L2capSdu> L2capSduConstructor(
- std::vector<uint8_t> create_from);
-
- // Adds an FCS to create_from and returns a unique_ptr to an L2capSdu object.
- static std::shared_ptr<L2capSdu> L2capSduBuilder(
- std::vector<uint8_t> create_from);
-
- // Get the FCS bytes from the end of the L2CAP payload of an SDU
- // packet.
- uint16_t get_fcs() const;
-
- uint16_t get_payload_length() const;
-
- uint16_t calculate_fcs() const;
-
- // Get the two control bytes that begin the L2CAP payload. These
- // bytes will contain information such as the Segmentation and
- // Reassembly bits, and the TxSeq/ReqSeq numbers.
- uint16_t get_controls() const;
-
- uint16_t get_total_l2cap_length() const;
-
- size_t get_vector_size() const;
-
- uint16_t get_channel_id() const;
-
- // Returns true if the SDU control sequence for Segmentation and
- // Reassembly is 00b, false otherwise.
- static bool is_complete_l2cap(const L2capSdu& sdu);
-
- // Returns true if the SDU control sequence for Segmentation and
- // Reassembly is 01b, false otherwise.
- static bool is_starting_sdu(const L2capSdu& sdu);
-
- // Returns true if the SDU control sequence for Segmentation and
- // Reasembly is 10b, false otherwise.
- static bool is_ending_sdu(const L2capSdu& sdu);
-
- // HciPacket functions
- size_t get_length();
- uint8_t& get_at_index(size_t index);
-
- private:
- // This is the SDU packet in bytes.
- std::vector<uint8_t> sdu_data_;
-
- // Returns a completed L2capSdu object.
- L2capSdu(std::vector<uint8_t>&& create_from);
-
- // Table for precalculated lfsr values.
- static const uint16_t lfsr_table_[256];
-
- uint16_t convert_from_little_endian(const unsigned int starting_index) const;
-
-}; // L2capSdu
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/l2cap_test_packets.h b/vendor_libs/test_vendor_lib/include/l2cap_test_packets.h
deleted file mode 100644
index 652ad34..0000000
--- a/vendor_libs/test_vendor_lib/include/l2cap_test_packets.h
+++ /dev/null
@@ -1,1446 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2017 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 <cstdint>
-#include <vector>
-namespace {
-
-// Complete SDUs that should always assemble.
-std::vector<std::vector<uint8_t> > good_sdu = {
- {0x0c, 0x00, 0x47, 0x00, 0x02, 0x41, 0x12, 0x00, 0x00, 0x01, 0x02, 0x03,
- 0x04, 0x05, 0xeb, 0x0f},
-
- {0x0a, 0x00, 0x47, 0x00, 0x04, 0xc1, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
- 0x5a, 0x8a},
-
- {0x0a, 0x00, 0x47, 0x00, 0x06, 0x81, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
- 0x68, 0x1e}};
-
-// The complete L2CAP packet that should be created by calling assemble on the
-// good_sdu vector.
-std::vector<uint8_t> good_l2cap_packet = {
- 0x12, 0x00, 0x47, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
- 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11};
-
-// SDUs that are missing a payload.
-std::vector<std::vector<uint8_t> > empty_sdu_payload = {
- {0x06, 0x00, 0x47, 0x00, 0x02, 0x41, 0x00, 0x00, 0xde, 0xf1},
-
- {0x04, 0x00, 0x47, 0x00, 0x04, 0x81, 0xd7, 0x90}};
-
-// The l2cap packet that should be created by calling assemble on the
-// empty_sdu_payload vector.
-std::vector<uint8_t> empty_l2cap_payload = {0x00, 0x00, 0x47, 0x00};
-
-// SDUs that have all of the control bytes set to be the start of the SDU.
-std::vector<std::vector<uint8_t> > all_first_packet = {
- {0x0c, 0x00, 0x47, 0x00, 0x02, 0x41, 0x18, 0x00, 0x00, 0x01, 0x02, 0x03,
- 0x04, 0x05, 0x6b, 0x70},
-
- {0x0c, 0x00, 0x47, 0x00, 0x02, 0x41, 0x18, 0x00, 0x00, 0x01, 0x02, 0x03,
- 0x04, 0x05, 0x6b, 0x70},
-
- {0x0c, 0x00, 0x47, 0x00, 0x02, 0x41, 0x18, 0x00, 0x00, 0x01, 0x02, 0x03,
- 0x04, 0x05, 0x6b, 0x70}};
-
-// A complete L2CAP packet that has not been segmented.
-std::vector<std::vector<uint8_t> > one_sdu = {{0x0b, 0x00, 0x47, 0x00, 0x02,
- 0x00, 0x01, 0x02, 0x03, 0x04,
- 0x05, 0x06, 0x07, 0x4a, 0x2f}};
-
-// l2cap_test_packet_[1-9] are SDUs that were extracted from snoop logs.
-std::vector<uint8_t> l2cap_test_packet_1 = {
- 0xf8, 0x03, 0x47, 0x00, 0x02, 0x41, 0x95, 0x1f, 0x02, 0x1f, 0x95, 0xcb,
- 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x33, 0x00, 0x49, 0x00, 0x4d, 0x00,
- 0x47, 0x00, 0x5f, 0x00, 0x32, 0x00, 0x30, 0x00, 0x31, 0x00, 0x37, 0x00,
- 0x30, 0x00, 0x36, 0x00, 0x30, 0x00, 0x36, 0x00, 0x5f, 0x00, 0x31, 0x00,
- 0x35, 0x00, 0x34, 0x00, 0x33, 0x00, 0x33, 0x00, 0x38, 0x00, 0x2e, 0x00,
- 0x6a, 0x00, 0x70, 0x00, 0x67, 0x00, 0x00, 0x42, 0x00, 0x0e, 0x69, 0x6d,
- 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x65, 0x67, 0x00, 0xc3, 0x00, 0x12,
- 0x30, 0x03, 0x97, 0x01, 0x48, 0x1f, 0x45, 0xff, 0xd8, 0xff, 0xe0, 0x00,
- 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x00, 0xff, 0xe1, 0x2b, 0x18, 0x45, 0x78, 0x69, 0x66, 0x00,
- 0x00, 0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x01,
- 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0c, 0xc0, 0x01,
- 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x09, 0x90, 0x01,
- 0x0f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x4c, 0x47, 0x45, 0x00, 0x01,
- 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x9e, 0x01,
- 0x12, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01,
- 0x1a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa6, 0x01,
- 0x1b, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xae, 0x01,
- 0x28, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x01,
- 0x31, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xb6, 0x01,
- 0x32, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xbd, 0x02,
- 0x13, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x87,
- 0x69, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xd2, 0x00,
- 0x00, 0x02, 0x78, 0x4e, 0x65, 0x78, 0x75, 0x73, 0x20, 0x35, 0x00, 0x00,
- 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00,
- 0x00, 0x00, 0x01, 0x50, 0x69, 0x63, 0x61, 0x73, 0x61, 0x00, 0x32, 0x30,
- 0x31, 0x37, 0x3a, 0x30, 0x36, 0x3a, 0x30, 0x36, 0x20, 0x31, 0x35, 0x3a,
- 0x34, 0x33, 0x3a, 0x33, 0x38, 0x00, 0x00, 0x00, 0x15, 0x82, 0x9a, 0x00,
- 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0xd4, 0x82, 0x9d, 0x00,
- 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0xdc, 0x88, 0x27, 0x00,
- 0x03, 0x00, 0x00, 0x00, 0x01, 0x02, 0x1f, 0x00, 0x00, 0x90, 0x00, 0x00,
- 0x07, 0x00, 0x00, 0x00, 0x04, 0x30, 0x32, 0x32, 0x30, 0x90, 0x03, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x01, 0xe4, 0x90, 0x04, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x01, 0xf8, 0x91, 0x01, 0x00,
- 0x07, 0x00, 0x00, 0x00, 0x04, 0x01, 0x02, 0x03, 0x00, 0x92, 0x01, 0x00,
- 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x0c, 0x92, 0x02, 0x00,
- 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x14, 0x92, 0x09, 0x00,
- 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x92, 0x0a, 0x00,
- 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x1c, 0x92, 0x90, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x02, 0x24, 0x92, 0x91, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x02, 0x2b, 0x92, 0x92, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x02, 0x32, 0xa0, 0x00, 0x00,
- 0x07, 0x00, 0x00, 0x00, 0x04, 0x30, 0x31, 0x30, 0x30, 0xa0, 0x01, 0x00,
- 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0xa0, 0x02, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0a, 0x0a, 0xa0, 0x03, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x07, 0x77, 0xa0, 0x05, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x5a, 0xa4, 0x03, 0x00,
- 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x20, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x02, 0x39, 0x00, 0x00, 0x00,
- 0x00, 0x01, 0xfc, 0x8c, 0xb2, 0x3b, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x00,
- 0xf0, 0x00, 0x00, 0x00, 0x64, 0x32, 0x30, 0x31, 0x37, 0x3a, 0x30, 0x36,
- 0x3a, 0x30, 0x36, 0x20, 0x31, 0x35, 0x3a, 0x34, 0x33, 0x3a, 0x33, 0x38,
- 0x00, 0x32, 0x30, 0x31, 0x37, 0x3a, 0x30, 0x36, 0x3a, 0x30, 0x36, 0x20,
- 0x31, 0x35, 0x3a, 0x34, 0x33, 0x3a, 0x33, 0x38, 0x00, 0xff, 0xff, 0xfe,
- 0x16, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00,
- 0x64, 0x00, 0x00, 0x0f, 0x82, 0x00, 0x00, 0x03, 0xe8, 0x39, 0x39, 0x39,
- 0x37, 0x32, 0x39, 0x00, 0x39, 0x39, 0x39, 0x37, 0x32, 0x39, 0x00, 0x39,
- 0x39, 0x39, 0x37, 0x32, 0x39, 0x00, 0x31, 0x30, 0x61, 0x66, 0x39, 0x37,
- 0x31, 0x37, 0x63, 0x31, 0x30, 0x36, 0x36, 0x33, 0x65, 0x62, 0x30, 0x30,
- 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
- 0x30, 0x30, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x04, 0x52, 0x39, 0x38, 0x00, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00,
- 0x04, 0x30, 0x31, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01,
- 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x01,
- 0x1a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0xc6, 0x01,
- 0x1b, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0xce, 0x01,
- 0x28, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x02,
- 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0xd6, 0x02,
- 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x28, 0x39, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0xff, 0xd8, 0xff, 0xe0, 0x00,
- 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x00, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x05, 0x03, 0x04, 0x04,
- 0x04, 0x03, 0x05, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x0c,
- 0x08, 0x07, 0x07, 0x07, 0x07, 0x0f, 0x0b, 0x0b, 0x09, 0x0c, 0x11, 0x0f,
- 0x12, 0x12, 0x11, 0x0f, 0x11, 0x11, 0x13, 0x16, 0x1c, 0x17, 0x13, 0x14,
- 0x1a, 0x15, 0x11, 0x11, 0x18, 0x21, 0x18, 0x1a, 0x1d, 0x1d, 0x1f, 0x1f,
- 0x1f, 0x13, 0x17, 0x22, 0x24, 0x22, 0x1e, 0x24, 0x1c, 0x1e, 0x1f, 0x1e,
- 0xff, 0xdb, 0x00, 0x43, 0x01, 0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x0e,
- 0x08, 0x08, 0x0e, 0x1e, 0x14, 0x11, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
- 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
- 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
- 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
- 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0xff, 0xc0, 0x00,
- 0x11, 0x08, 0x00, 0x78, 0x00, 0xa0, 0x03, 0x01, 0x22, 0x00, 0xaa, 0x72};
-
-std::vector<uint8_t> l2cap_test_packet_2 = {
- 0xf6, 0x03, 0x47, 0x00, 0x04, 0xc1, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01,
- 0xff, 0xc4, 0x00, 0x1c, 0x00, 0x00, 0x03, 0x00, 0x03, 0x01, 0x01, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x06, 0x07,
- 0x00, 0x04, 0x08, 0x03, 0x02, 0x01, 0xff, 0xc4, 0x00, 0x40, 0x10, 0x00,
- 0x01, 0x03, 0x02, 0x05, 0x02, 0x04, 0x04, 0x04, 0x03, 0x06, 0x04, 0x07,
- 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x11, 0x00, 0x06, 0x12,
- 0x21, 0x31, 0x07, 0x41, 0x13, 0x22, 0x51, 0x61, 0x14, 0x32, 0x71, 0x81,
- 0x08, 0x42, 0x91, 0xa1, 0x15, 0x16, 0xc1, 0x23, 0x52, 0x62, 0x82, 0xb1,
- 0xe1, 0x24, 0x43, 0x72, 0xf0, 0x17, 0x25, 0x33, 0x92, 0xb2, 0xd1, 0xd2,
- 0xff, 0xc4, 0x00, 0x1c, 0x01, 0x00, 0x03, 0x01, 0x01, 0x00, 0x03, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x06, 0x07,
- 0x04, 0x03, 0x00, 0x02, 0x08, 0x01, 0xff, 0xc4, 0x00, 0x37, 0x11, 0x00,
- 0x01, 0x02, 0x04, 0x04, 0x03, 0x06, 0x04, 0x05, 0x04, 0x03, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x00, 0x04, 0x05, 0x11, 0x06, 0x21,
- 0x31, 0x41, 0x12, 0x51, 0x71, 0x13, 0x22, 0x61, 0x81, 0x91, 0xa1, 0x07,
- 0xb1, 0xc1, 0xf0, 0x14, 0x42, 0xd1, 0xe1, 0xf1, 0x15, 0x24, 0x32, 0x82,
- 0x33, 0x52, 0x72, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11,
- 0x03, 0x11, 0x00, 0x3f, 0x00, 0xb1, 0x31, 0x2c, 0x2d, 0xd8, 0xd2, 0xda,
- 0x43, 0x26, 0x4a, 0x99, 0x1e, 0x15, 0x98, 0x2e, 0x2f, 0x51, 0x49, 0x0b,
- 0x03, 0x70, 0x90, 0x6c, 0x9f, 0x4d, 0xb7, 0xf5, 0xc3, 0x0b, 0x4f, 0x09,
- 0x1f, 0x08, 0xa5, 0x95, 0xb6, 0xb7, 0x50, 0x4e, 0x95, 0xab, 0xe4, 0xbf,
- 0x2a, 0xb1, 0x17, 0xb8, 0xb1, 0xde, 0xdd, 0xf1, 0x34, 0xa1, 0x3b, 0x25,
- 0xb6, 0x5d, 0x67, 0xe2, 0xda, 0x5b, 0xeb, 0x49, 0xf0, 0xd2, 0x83, 0xe1,
- 0xa9, 0x37, 0xbe, 0x91, 0x72, 0xab, 0x5f, 0x73, 0x7f, 0xb6, 0x1d, 0x28,
- 0xf0, 0xdf, 0xf1, 0x9b, 0x05, 0x2e, 0x20, 0x32, 0xd8, 0x64, 0x23, 0x52,
- 0x4a, 0x9c, 0xb7, 0x2b, 0x52, 0x8d, 0xd5, 0xe9, 0xe5, 0xdb, 0x83, 0xea,
- 0x30, 0x09, 0x75, 0x86, 0x25, 0xec, 0x1e, 0x58, 0x4d, 0xf9, 0x90, 0x20,
- 0x87, 0x60, 0x4e, 0x91, 0xb2, 0xc3, 0x72, 0x63, 0xcd, 0x40, 0x76, 0x63,
- 0xd2, 0x5b, 0x4a, 0x75, 0x04, 0x20, 0x06, 0xf9, 0xdb, 0xcd, 0xdc, 0x83,
- 0xe9, 0x6b, 0xec, 0x0d, 0xf1, 0xba, 0x5f, 0x76, 0xe9, 0x50, 0x43, 0x65,
- 0xd9, 0x05, 0x21, 0x08, 0xf2, 0x92, 0x94, 0x05, 0x73, 0x72, 0x48, 0x20,
- 0x5c, 0xaa, 0xf8, 0xf8, 0xa9, 0x34, 0x97, 0xe4, 0x3e, 0xc7, 0xc4, 0x80,
- 0x95, 0x90, 0x90, 0x9d, 0x1a, 0x94, 0x8b, 0xd8, 0x6d, 0xb5, 0x80, 0xef,
- 0xf7, 0xc7, 0xeb, 0x14, 0xb7, 0xdb, 0x79, 0x45, 0x2f, 0xb6, 0x50, 0x55,
- 0x7b, 0x96, 0x86, 0xb4, 0xf1, 0xc2, 0xaf, 0x7e, 0xc3, 0x7c, 0x65, 0x77,
- 0x15, 0x52, 0x98, 0x36, 0x53, 0xc3, 0xca, 0xe7, 0xe5, 0x78, 0xf0, 0xb0,
- 0xb3, 0x99, 0x11, 0xae, 0xa6, 0xd8, 0x91, 0x2c, 0x38, 0x3c, 0x37, 0xb4,
- 0x36, 0xa6, 0x99, 0xd2, 0xb2, 0xb0, 0xda, 0x01, 0x04, 0xea, 0x24, 0x8d,
- 0xcd, 0xb6, 0xfa, 0x63, 0x62, 0x92, 0xdb, 0x2c, 0xb8, 0xcb, 0x29, 0x7d,
- 0x97, 0x94, 0x5b, 0x53, 0xa0, 0x22, 0xfa, 0x02, 0x52, 0x52, 0x35, 0x12,
- 0x2f, 0x71, 0x7b, 0x72, 0x77, 0xe0, 0x63, 0xc2, 0xb9, 0x43, 0xa9, 0x39,
- 0x09, 0xc8, 0xd0, 0x1f, 0x6d, 0x95, 0xbb, 0xa5, 0x7f, 0x10, 0xfa, 0x3c,
- 0x5d, 0xf5, 0x58, 0x24, 0x20, 0x5b, 0x51, 0x3c, 0x58, 0x9b, 0x5a, 0xf7,
- 0xbd, 0xf1, 0x2f, 0xcd, 0x94, 0x9c, 0xff, 0x00, 0x4a, 0x94, 0xe4, 0xba,
- 0x8e, 0x60, 0xa8, 0xba, 0xc0, 0x05, 0x1a, 0xe2, 0x47, 0x09, 0x09, 0x4f,
- 0xa6, 0x94, 0x8b, 0xa7, 0xd8, 0x0f, 0xb6, 0x0a, 0xd3, 0xaa, 0x54, 0xe9,
- 0xe5, 0xa1, 0x29, 0x98, 0x4a, 0x4a, 0xb4, 0x0a, 0xba, 0x6f, 0x9d, 0xb7,
- 0x16, 0xbf, 0x21, 0x7b, 0x9d, 0x84, 0x0d, 0xa8, 0x4c, 0xb9, 0x26, 0xd9,
- 0x73, 0xb2, 0x52, 0xc0, 0xff, 0x00, 0xa8, 0x07, 0xda, 0xf7, 0xeb, 0x95,
- 0x84, 0x55, 0xdb, 0x4c, 0x26, 0xa4, 0x3e, 0xdb, 0x0b, 0x2e, 0xcb, 0x91,
- 0x24, 0xbe, 0xa2, 0x2c, 0x08, 0x52, 0x86, 0xca, 0xb7, 0x17, 0x00, 0x58,
- 0xed, 0x72, 0x0e, 0xf8, 0xf8, 0x7e, 0x6c, 0x28, 0xce, 0x3a, 0xc3, 0x25,
- 0x90, 0x88, 0xc9, 0xd4, 0xe9, 0x71, 0xc0, 0x09, 0x52, 0x85, 0xed, 0xa8,
- 0xf7, 0xbd, 0xff, 0x00, 0x4d, 0x86, 0x39, 0x96, 0xa7, 0xd4, 0x6a, 0x63,
- 0x28, 0x5b, 0x1f, 0xce, 0x33, 0xf5, 0x36, 0x0a, 0x5c, 0x49, 0x75, 0x6b,
- 0x70, 0xab, 0x8b, 0x8b, 0x91, 0x63, 0x6b, 0x6d, 0x6e, 0xd8, 0x00, 0xee,
- 0x76, 0xca, 0xce, 0x27, 0xc6, 0x6a, 0x8b, 0x32, 0x78, 0x69, 0x3f, 0xda,
- 0x3a, 0xa6, 0xca, 0x89, 0xb7, 0x2a, 0x3b, 0x9f, 0x7c, 0x37, 0xff, 0x00,
- 0x41, 0x69, 0x1f, 0xf2, 0xbe, 0x07, 0xa7, 0xd4, 0x88, 0x54, 0x18, 0xaa,
- 0x61, 0xcf, 0xf8, 0xa4, 0xd6, 0x7a, 0xe5, 0xf3, 0x1f, 0xac, 0x75, 0x8c,
- 0x0c, 0xc3, 0x02, 0xa3, 0x50, 0x6a, 0x9c, 0xc5, 0x62, 0x92, 0xe4, 0xa7,
- 0x10, 0xb6, 0xbe, 0x1d, 0xb9, 0x2d, 0xad, 0x00, 0x80, 0x3f, 0x2f, 0xcc,
- 0xb5, 0x0b, 0x1e, 0x2c, 0x07, 0xb9, 0xc7, 0xae, 0x68, 0x96, 0xa4, 0xd2,
- 0xcb, 0x31, 0x25, 0x29, 0x72, 0x00, 0x0d, 0x96, 0xda, 0xec, 0x9b, 0xf7,
- 0xb0, 0xd8, 0xf7, 0xda, 0xc7, 0xb6, 0x21, 0x79, 0x22, 0x3d, 0x1e, 0xbf,
- 0x45, 0x8b, 0x3c, 0xd3, 0x95, 0x11, 0xb9, 0x26, 0xf1, 0x5c, 0x69, 0x65,
- 0xa7, 0x10, 0xa0, 0xe6, 0x84, 0x9d, 0xb7, 0x1e, 0x71, 0x89, 0xac, 0x0a,
- 0x9d, 0x56, 0x8f, 0x38, 0x48, 0x8d, 0x52, 0x9d, 0x0d, 0x65, 0xc2, 0x54,
- 0xeb, 0x2e, 0xa9, 0x0a, 0x55, 0x8d, 0x89, 0xe7, 0x7e, 0xfc, 0xe0, 0x0d,
- 0x79, 0xb6, 0xe9, 0x8a, 0x42, 0x50, 0x4a, 0x82, 0xc6, 0xbf, 0xa4, 0x51,
- 0xbe, 0x1b, 0xc8, 0x2b, 0x18, 0x35, 0x32, 0xe3, 0x87, 0xb2, 0x53, 0x2a,
- 0x09, 0xe1, 0xd6, 0xe4, 0x8b, 0xe6, 0x76, 0xf4, 0x31, 0xd6, 0x31, 0x67,
- 0x66, 0x00, 0xda, 0x90, 0x22, 0xc6, 0x79, 0xb4, 0x20, 0xa1, 0x6f, 0xbc,
- 0x0a, 0x41, 0x09, 0xf3, 0x6b, 0x09, 0x37, 0xb0, 0x36, 0xdc, 0x12, 0x4e,
- 0xd8, 0x11, 0x51, 0x7f, 0xf8, 0xed, 0x5a, 0x1c, 0x88, 0x35, 0x04, 0xa5,
- 0xc8, 0x4d, 0x2d, 0x4d, 0xa9, 0xc8, 0xd6, 0x6b, 0x52, 0x87, 0x99, 0x4a,
- 0xb8, 0xdc, 0x93, 0xc0, 0x06, 0xdc, 0xe2, 0x21, 0x13, 0xa9, 0xd9, 0xb0,
- 0xb1, 0xe1, 0x4a, 0xaf, 0x3a, 0xe9, 0x4a, 0xb5, 0x21, 0x6e, 0xb0, 0x85,
- 0x9f, 0x6b, 0xa8, 0x6f, 0x7f, 0xb6, 0x35, 0xe2, 0xf5, 0x37, 0x37, 0xca,
- 0x7c, 0x35, 0x51, 0xaf, 0xae, 0x13, 0x00, 0xfc, 0xed, 0x46, 0xd7, 0x71,
- 0xfe, 0x22, 0x0d, 0xc7, 0xe8, 0x70, 0x10, 0xcf, 0xb0, 0x53, 0x61, 0x73,
- 0xe9, 0xfa, 0xc3, 0xcc, 0xc6, 0x09, 0x7a, 0x50, 0x15, 0x29, 0x1c, 0x5f,
- 0xf9, 0xb9, 0xfa, 0x67, 0xe5, 0x68, 0xe8, 0x7a, 0x34, 0x17, 0x60, 0x34,
- 0xa0, 0x66, 0x53, 0xdb, 0x53, 0x84, 0xea, 0x5b, 0x67, 0x4d, 0xfd, 0xfc,
- 0xbe, 0xfb, 0xf3, 0xbf, 0xd3, 0x6c, 0x7d, 0x66, 0x57, 0x5b};
-
-std::vector<uint8_t> l2cap_test_packet_3 = {
- 0xf6, 0x03, 0x47, 0x00, 0x06, 0xc1, 0x87, 0xeb, 0x74, 0xf8, 0xb1, 0xe1,
- 0xd2, 0xc4, 0x35, 0x49, 0x90, 0xcb, 0xae, 0xc3, 0x73, 0x7d, 0x3a, 0x90,
- 0x9b, 0x90, 0x45, 0xed, 0xbd, 0xf6, 0x3c, 0x0e, 0x6d, 0x89, 0xa6, 0x46,
- 0x89, 0x56, 0xac, 0x4b, 0x81, 0x35, 0xac, 0xdc, 0xfd, 0x56, 0x31, 0x7d,
- 0x2a, 0x29, 0x60, 0x0b, 0x25, 0x49, 0x58, 0xd9, 0xc0, 0x07, 0x96, 0xe3,
- 0xb1, 0xb6, 0xd8, 0xac, 0xe7, 0xb4, 0x45, 0x6a, 0xaf, 0x4b, 0x43, 0x4a,
- 0x6d, 0x25, 0xa9, 0x32, 0x11, 0xa1, 0x24, 0x5d, 0x29, 0x53, 0x5b, 0x6d,
- 0xd8, 0x5c, 0x60, 0xad, 0x29, 0x4d, 0xcc, 0x38, 0x3b, 0xb6, 0x00, 0x8d,
- 0x77, 0x85, 0xb9, 0x96, 0x19, 0x49, 0x52, 0x10, 0x9c, 0xc2, 0x54, 0x73,
- 0x1a, 0x10, 0x92, 0x47, 0xbd, 0xa2, 0x1c, 0x9f, 0xfc, 0x40, 0x7a, 0x32,
- 0x5f, 0x97, 0x99, 0x1d, 0x52, 0xdb, 0x36, 0x11, 0x92, 0xe2, 0x90, 0xd3,
- 0x62, 0xdc, 0x0d, 0x24, 0x11, 0xb1, 0xc2, 0xfd, 0x5a, 0x5e, 0x60, 0x42,
- 0x2c, 0xfc, 0x07, 0x18, 0x75, 0x2a, 0xba, 0x26, 0x21, 0xe5, 0x3f, 0x63,
- 0xfd, 0xe4, 0xa9, 0x47, 0xca, 0x46, 0xe3, 0x71, 0xdf, 0x19, 0xd6, 0x3a,
- 0xd5, 0x5e, 0x91, 0x0d, 0x2f, 0xc1, 0x21, 0x94, 0x29, 0xd7, 0x2e, 0x15,
- 0x65, 0x05, 0x5b, 0x4e, 0xe4, 0x7d, 0xf8, 0x38, 0x0b, 0x42, 0xea, 0x69,
- 0x30, 0x9b, 0x6a, 0xb9, 0x4b, 0x43, 0xe1, 0xb0, 0x12, 0x1d, 0x8e, 0x7c,
- 0x32, 0x8f, 0xb7, 0x6f, 0xb6, 0x28, 0xcb, 0x99, 0x92, 0x95, 0x74, 0x36,
- 0xa0, 0x94, 0xa8, 0x8b, 0x8c, 0xac, 0x39, 0x74, 0x88, 0xa6, 0x1f, 0xc4,
- 0x18, 0xbd, 0x12, 0x9f, 0x8e, 0x67, 0x85, 0xe6, 0xd4, 0x4d, 0xd2, 0x6d,
- 0x71, 0x6d, 0x6d, 0x98, 0x3e, 0x40, 0xf9, 0x40, 0xf9, 0x19, 0x9a, 0xad,
- 0xe3, 0x3b, 0x11, 0x6e, 0xca, 0xa9, 0x6b, 0x56, 0x8d, 0x72, 0x5c, 0x4a,
- 0xad, 0x7b, 0x0b, 0x24, 0xe9, 0x3a, 0x71, 0xf7, 0x97, 0xaa, 0x19, 0x86,
- 0x65, 0x52, 0x24, 0x66, 0xe9, 0x0d, 0xb7, 0xe3, 0x38, 0x1b, 0x49, 0x44,
- 0x50, 0xab, 0x82, 0xab, 0x5e, 0xc4, 0x6f, 0x6c, 0x35, 0xb3, 0x4b, 0xcb,
- 0x79, 0x89, 0xe4, 0xce, 0xa6, 0x26, 0x6c, 0x69, 0x5a, 0x82, 0x95, 0x29,
- 0x2b, 0x52, 0x1d, 0x41, 0x3b, 0x8b, 0x91, 0xda, 0xc3, 0x6d, 0x88, 0xd8,
- 0xe1, 0x93, 0x2f, 0xcf, 0xab, 0xe5, 0x7c, 0xc7, 0x4d, 0x46, 0x60, 0x97,
- 0x0e, 0x75, 0x31, 0xe9, 0x08, 0x69, 0x12, 0x8c, 0x60, 0x87, 0xda, 0xf4,
- 0xbe, 0x8b, 0x05, 0x0f, 0xb0, 0x3d, 0xf1, 0x8a, 0x64, 0xd5, 0x5a, 0x1c,
- 0x52, 0xae, 0x24, 0xa0, 0x67, 0x6b, 0x01, 0xfc, 0xfa, 0xc3, 0x75, 0x33,
- 0xe2, 0x63, 0x4f, 0xbc, 0x99, 0x57, 0xd2, 0x59, 0x73, 0x4e, 0x12, 0x32,
- 0xbf, 0xcf, 0xd6, 0x06, 0xf5, 0x01, 0xd9, 0x74, 0xac, 0xba, 0xdb, 0x2f,
- 0x33, 0x1d, 0xba, 0x85, 0x36, 0xae, 0xe4, 0x77, 0x5d, 0x61, 0xad, 0x96,
- 0x0b, 0x63, 0x70, 0x07, 0xfd, 0x37, 0xb6, 0x1f, 0xba, 0x4b, 0x5b, 0x95,
- 0x3f, 0x2b, 0xc1, 0x44, 0xc7, 0x1e, 0x96, 0x02, 0x8d, 0xca, 0x9b, 0xb2,
- 0x94, 0x41, 0x24, 0x12, 0x2f, 0xcd, 0xec, 0x37, 0xe7, 0xdf, 0x13, 0xbe,
- 0xb2, 0x54, 0x4c, 0xba, 0xce, 0x60, 0x5c, 0x25, 0x87, 0xe9, 0xee, 0x4a,
- 0x6e, 0x49, 0xf0, 0xd3, 0x72, 0x95, 0x29, 0x24, 0x03, 0xa8, 0x1d, 0xb9,
- 0x3b, 0x7b, 0x7b, 0x60, 0xef, 0x43, 0x5d, 0x29, 0x88, 0xdb, 0x8b, 0x72,
- 0x33, 0x65, 0x5e, 0x25, 0xee, 0x17, 0x7b, 0x10, 0x05, 0xac, 0x0d, 0x89,
- 0xdb, 0x83, 0x85, 0x8c, 0x5a, 0x78, 0x66, 0x9a, 0x58, 0xdd, 0x20, 0x9f,
- 0x3b, 0x9f, 0xac, 0x3b, 0xd5, 0xdb, 0xb9, 0x4a, 0xd5, 0xa9, 0x00, 0xfb,
- 0x40, 0xac, 0xbf, 0x98, 0xbe, 0x31, 0x9a, 0xab, 0x73, 0x42, 0xde, 0x80,
- 0xc7, 0x87, 0xa9, 0x2b, 0x6c, 0x10, 0xe0, 0x28, 0xbe, 0xe0, 0xec, 0x47,
- 0xa7, 0xfb, 0x62, 0x9b, 0x94, 0x9a, 0xa9, 0xd6, 0x72, 0xa8, 0x95, 0x90,
- 0x33, 0x73, 0x72, 0xd6, 0x86, 0x2e, 0x69, 0x92, 0xbc, 0xcb, 0x61, 0x76,
- 0xf9, 0x52, 0x54, 0x6f, 0xa7, 0xd8, 0x92, 0x3d, 0x14, 0x31, 0x03, 0x76,
- 0x3b, 0x4d, 0xe4, 0xcc, 0xcd, 0x23, 0x58, 0xbb, 0x8d, 0xa2, 0xe9, 0x04,
- 0xd9, 0x20, 0x04, 0x8d, 0xbd, 0x76, 0xc4, 0xf3, 0x2a, 0x55, 0x33, 0x44,
- 0x4c, 0xf6, 0x22, 0xe5, 0x27, 0xa6, 0xae, 0xa2, 0xe4, 0xa0, 0x96, 0x44,
- 0x72, 0x6e, 0x0d, 0x85, 0xcd, 0x87, 0x6b, 0x5e, 0xff, 0x00, 0xbe, 0x3d,
- 0xa6, 0x9a, 0x94, 0x98, 0xa7, 0xcb, 0x4a, 0x4c, 0xb4, 0x16, 0x14, 0x9b,
- 0xe6, 0x01, 0xcf, 0x2d, 0xb5, 0xdf, 0x50, 0x41, 0x89, 0x54, 0x8c, 0xa3,
- 0xc2, 0xa1, 0x3d, 0x50, 0x65, 0xee, 0x12, 0x85, 0x81, 0x62, 0x6c, 0x2d,
- 0x62, 0x49, 0xdc, 0x65, 0x6d, 0xd2, 0x44, 0x5c, 0x1e, 0xcf, 0x3d, 0x5a,
- 0x62, 0xa4, 0xe5, 0x3e, 0xa5, 0x50, 0xa7, 0xd2, 0xdd, 0x49, 0xd2, 0x84,
- 0xbc, 0xd6, 0x95, 0x39, 0xcd, 0x82, 0x6f, 0x7b, 0xf1, 0xce, 0xe0, 0x7a,
- 0xe1, 0x83, 0x20, 0xbf, 0xd4, 0x0a, 0xad, 0x42, 0x4b, 0xd5, 0x6c, 0xe0,
- 0xf1, 0x66, 0x24, 0xe6, 0xee, 0xcb, 0x6d, 0x20, 0x02, 0x9b, 0x82, 0x52,
- 0xab, 0x0f, 0x4d, 0x88, 0xf7, 0xc1, 0x8c, 0xd5, 0x2e, 0x8a, 0x7a, 0x5d,
- 0x4e, 0x8b, 0x5b, 0x8e, 0xd2, 0xab, 0x06, 0xea, 0x50, 0x6d, 0x3b, 0xa1,
- 0xb2, 0xa3, 0xa0, 0x58, 0x7f, 0xcc, 0x50, 0xb5, 0x80, 0xdc, 0x83, 0xbe,
- 0x24, 0xbd, 0x36, 0xcc, 0x33, 0xb2, 0xcd, 0x54, 0x25, 0x42, 0x4a, 0x5a,
- 0x2e, 0x02, 0x96, 0xdc, 0x90, 0x4a, 0x55, 0x7d, 0x89, 0xb7, 0x04, 0x81,
- 0xff, 0x00, 0xd6, 0xf8, 0x54, 0xad, 0xe1, 0x4a, 0x6d, 0x38, 0x07, 0x19,
- 0x69, 0x20, 0x1b, 0xe4, 0x52, 0x2f, 0x96, 0xe0, 0xf2, 0x3b, 0x7d, 0x61,
- 0xaf, 0x0d, 0x62, 0x79, 0x8a, 0xb0, 0x52, 0x1c, 0x02, 0xe9, 0x09, 0xcc,
- 0x68, 0x4a, 0x85, 0xed, 0xa7, 0xf9, 0x0d, 0xc7, 0x8e, 0xd1, 0xd8, 0x64,
- 0xff, 0x00, 0xc5, 0xb4, 0xd3, 0x68, 0x05, 0x28, 0x0a, 0x5a, 0x92, 0x4f,
- 0xe5, 0x4b, 0x97, 0xb7, 0xe8, 0x71, 0x1a, 0xab, 0xfe, 0x21, 0x29, 0xd4,
- 0x7e, 0xa5, 0xce, 0xca, 0x35, 0xea, 0x64, 0x91, 0x09, 0x01, 0x05, 0x12,
- 0xda, 0x40, 0x50, 0x4e, 0xa1, 0xdd, 0x3c, 0xd8, 0x7a, 0xef, 0x8a, 0xc5,
- 0x36, 0xa9, 0x0e, 0x44, 0x84, 0xe8, 0x73, 0xfb, 0x59, 0x2c, 0x29, 0x4d,
- 0xa7, 0xbf, 0x65, 0x7f, 0xa1, 0xc7, 0x13, 0xf5, 0x06, 0x9b, 0x52, 0xac,
- 0xfe, 0x20, 0x6a, 0x90, 0x20, 0x45, 0x91, 0x2a, 0x5b, 0x8b, 0x6d, 0xb6,
- 0x19, 0x6c, 0x5d, 0x4b, 0xb2, 0x78, 0x1f, 0xbe, 0xfc, 0x0c, 0x21, 0x61,
- 0xb9, 0x66, 0xa7, 0xdb, 0xb3, 0xa7, 0x44, 0x2b, 0x43, 0x6b, 0x10, 0xb4,
- 0x81, 0xec, 0x77, 0xb8, 0xcc, 0xc1, 0xa7, 0xf8, 0x99, 0x48, 0x36, 0xce,
- 0xe0, 0x67, 0xc8, 0x85, 0x1f, 0xa6, 0xa2, 0x3a, 0x3b, 0x33, 0xe4, 0x8c,
- 0x85, 0xd4, 0x46, 0xda, 0xae, 0x52, 0xc4, 0x07, 0x64, 0x2e, 0xc0, 0x49,
- 0x61, 0x00, 0x2b, 0xe8, 0xbb, 0x6f, 0xbe, 0x14, 0xab, 0xb9, 0x30, 0x50,
- 0x22, 0xff, 0x00, 0x0f, 0xfe, 0x13, 0x18, 0x7c, 0x72, 0x96, 0xc0, 0x90,
- 0x41, 0x29, 0x41, 0x50, 0xb0, 0xbf, 0x1e, 0x5e, 0x76, 0xdb, 0xdc, 0xfa,
- 0xb5, 0xf4, 0xeb, 0x24, 0x53, 0x7a, 0x71, 0x45, 0x44, 0xe6};
-
-std::vector<uint8_t> l2cap_test_packet_4 = {
- 0xf6, 0x03, 0x47, 0x00, 0x08, 0xc1, 0x7a, 0xa1, 0x5b, 0xa8, 0x32, 0x89,
- 0xd3, 0x96, 0xda, 0xa5, 0x25, 0xb5, 0xf9, 0x1b, 0x08, 0x3a, 0x92, 0x80,
- 0x7f, 0x32, 0xb5, 0x5a, 0xea, 0xf6, 0xb0, 0xbe, 0x06, 0x75, 0x3e, 0xa9,
- 0x5a, 0xce, 0x51, 0xa1, 0xc3, 0xa7, 0xb0, 0x61, 0xc5, 0x5c, 0x80, 0x59,
- 0x52, 0x8d, 0x9c, 0x58, 0x48, 0x24, 0x1b, 0x7e, 0x54, 0xef, 0xdf, 0x72,
- 0x71, 0xda, 0x98, 0xf4, 0xe8, 0x9f, 0xec, 0xa5, 0x9d, 0x2e, 0x32, 0x35,
- 0xb8, 0xc8, 0x78, 0x03, 0xe9, 0xa6, 0xa7, 0x6b, 0x46, 0x87, 0xc3, 0x45,
- 0xae, 0x35, 0xa4, 0x5f, 0x9e, 0xff, 0x00, 0xbf, 0xa6, 0x9b, 0xc2, 0xfc,
- 0xa9, 0xf1, 0x13, 0x97, 0xbc, 0x4a, 0x32, 0x2e, 0xd4, 0x0b, 0xb4, 0xa0,
- 0x11, 0xa7, 0xcc, 0xd3, 0x89, 0x52, 0x94, 0x94, 0x8b, 0x00, 0x2f, 0x72,
- 0x3d, 0xb1, 0x36, 0xeb, 0x1c, 0x07, 0x28, 0xd3, 0x6b, 0xb4, 0xc9, 0x4e,
- 0x15, 0x25, 0x82, 0xb5, 0x31, 0xa4, 0xdd, 0x29, 0x4a, 0x9c, 0x43, 0xa9,
- 0x23, 0xfc, 0xaa, 0xfd, 0xf1, 0xbb, 0x2e, 0x55, 0x6a, 0x87, 0x1a, 0xbc,
- 0x89, 0x20, 0x29, 0x69, 0x63, 0x5a, 0x52, 0xb0, 0x6c, 0x51, 0xa1, 0x40,
- 0xf1, 0xea, 0x06, 0x06, 0x67, 0xc9, 0x92, 0x33, 0x14, 0x36, 0xe4, 0xcb,
- 0x5f, 0x8a, 0xec, 0x9a, 0x6c, 0x7b, 0xab, 0x48, 0x04, 0xff, 0x00, 0x62,
- 0x11, 0xfb, 0x14, 0xe2, 0xb3, 0x88, 0x78, 0x7f, 0x01, 0x26, 0xb3, 0xa8,
- 0x03, 0xe9, 0xfa, 0x46, 0x4f, 0x85, 0x0c, 0x3c, 0xa9, 0xba, 0xd4, 0xba,
- 0x45, 0xc2, 0xc5, 0xc5, 0xb5, 0xe2, 0xb1, 0xb7, 0xce, 0xde, 0x71, 0x36,
- 0xa6, 0x4b, 0xaa, 0xbf, 0x20, 0x98, 0xaf, 0x68, 0x69, 0xb4, 0xdf, 0x4d,
- 0xb6, 0xb0, 0xf6, 0xe4, 0x93, 0x87, 0x95, 0xaa, 0x38, 0xa5, 0x44, 0x4a,
- 0x81, 0xf8, 0xd4, 0xeb, 0x32, 0x1d, 0x1b, 0x21, 0x49, 0x36, 0x29, 0xb0,
- 0xf5, 0x1b, 0xdc, 0xfd, 0x30, 0x0f, 0x2d, 0xd1, 0xd3, 0x0d, 0xa6, 0xde,
- 0xa8, 0xb8, 0x12, 0xb0, 0x2f, 0x60, 0x0a, 0x83, 0x7b, 0x6f, 0x6b, 0x72,
- 0xac, 0x36, 0xd2, 0xa8, 0x46, 0xbb, 0x1e, 0x4c, 0xa8, 0x92, 0x22, 0xa0,
- 0x34, 0xc9, 0x71, 0xa6, 0x0b, 0xa1, 0x4a, 0x3d, 0xbc, 0xd6, 0x3b, 0x2b,
- 0x93, 0x7e, 0x01, 0xdb, 0x9c, 0x28, 0x4c, 0xad, 0x2e, 0x2a, 0xc8, 0x02,
- 0xdc, 0xe2, 0xc1, 0x46, 0x2f, 0x50, 0x25, 0x7f, 0x11, 0x50, 0x75, 0x5c,
- 0x4a, 0xff, 0x00, 0x16, 0xef, 0xa7, 0x5b, 0xe9, 0xd3, 0x6d, 0xf3, 0xc8,
- 0x6e, 0xf4, 0xff, 0x00, 0x3d, 0x4c, 0xca, 0xf9, 0x88, 0x7c, 0x2c, 0x1d,
- 0x46, 0x63, 0x29, 0x6c, 0xa4, 0x27, 0x40, 0xb2, 0x38, 0x59, 0xf5, 0x27,
- 0x7f, 0xd7, 0x1d, 0x08, 0xce, 0x65, 0x6e, 0xa7, 0x54, 0xa7, 0x4f, 0xac,
- 0xa6, 0x3c, 0x79, 0x29, 0x7e, 0x13, 0xc8, 0x49, 0x50, 0x05, 0x45, 0xd0,
- 0xa4, 0xad, 0x36, 0xfc, 0xdc, 0x03, 0x8e, 0x7d, 0x32, 0xa0, 0x57, 0xa9,
- 0x52, 0x6a, 0xeb, 0x52, 0x19, 0xaa, 0x46, 0x8a, 0x52, 0x96, 0xb4, 0x24,
- 0x2d, 0xc2, 0x15, 0xdf, 0xe8, 0x07, 0x1c, 0x91, 0xfa, 0x63, 0xa0, 0xf3,
- 0x25, 0x39, 0x0e, 0x51, 0x29, 0x12, 0xc2, 0x59, 0xb3, 0x52, 0x60, 0x91,
- 0x74, 0x0b, 0xdb, 0xc3, 0x3d, 0xff, 0x00, 0x4c, 0x14, 0xa5, 0x29, 0x69,
- 0x70, 0x24, 0x69, 0xcb, 0xce, 0x13, 0xa6, 0xa7, 0x45, 0x49, 0xf7, 0x5d,
- 0x75, 0x20, 0x29, 0x79, 0x65, 0xb0, 0xd2, 0xde, 0x62, 0x21, 0xff, 0x00,
- 0x88, 0xf6, 0x9b, 0xa9, 0x52, 0x2a, 0xb2, 0xa1, 0x21, 0x6d, 0x21, 0x55,
- 0x37, 0x96, 0xce, 0xa1, 0xa4, 0xe8, 0x52, 0xc1, 0xbe, 0x9e, 0xc2, 0xd7,
- 0xdb, 0x12, 0x9e, 0x9c, 0xd2, 0xe6, 0xd5, 0x5f, 0x31, 0xe1, 0x34, 0xeb,
- 0xce, 0xa9, 0x77, 0x5a, 0x95, 0xe6, 0x48, 0x48, 0x16, 0x25, 0x46, 0xf6,
- 0x03, 0x91, 0x8b, 0xa6, 0x64, 0xa0, 0x53, 0xb3, 0x35, 0x3e, 0x43, 0x55,
- 0x17, 0x8b, 0x4d, 0x25, 0xe2, 0xe2, 0x8a, 0x57, 0xa7, 0x6b, 0x9b, 0x8b,
- 0x8c, 0x20, 0x55, 0xf3, 0xad, 0x03, 0x2c, 0x43, 0x5e, 0x5a, 0xca, 0x8c,
- 0xc6, 0x6e, 0xc7, 0x77, 0xd1, 0x65, 0x24, 0x2b, 0xde, 0xff, 0x00, 0x3e,
- 0x29, 0x53, 0xb4, 0xa6, 0x9e, 0x71, 0x2f, 0xbc, 0xab, 0x21, 0x09, 0x00,
- 0xff, 0x00, 0x3f, 0x66, 0x3e, 0x6d, 0xa0, 0xe2, 0x09, 0xa6, 0xd8, 0x5c,
- 0x8c, 0x8b, 0x65, 0x4f, 0x95, 0xa8, 0xdf, 0xf2, 0xa4, 0x13, 0xaf, 0xcf,
- 0x28, 0x6c, 0x8e, 0xec, 0x2c, 0xa7, 0x0d, 0x98, 0xad, 0x3d, 0xfc, 0x46,
- 0xa5, 0x21, 0x21, 0xa4, 0x45, 0x8e, 0x92, 0x55, 0xb7, 0x01, 0x29, 0xf4,
- 0xdc, 0xf9, 0x8f, 0xfa, 0x63, 0xe2, 0xa1, 0x42, 0xcc, 0xf5, 0x67, 0x04,
- 0xfa, 0xac, 0x96, 0xd8, 0x75, 0x2b, 0x40, 0x6a, 0x1b, 0x67, 0x59, 0x66,
- 0xff, 0x00, 0x4f, 0x99, 0x7f, 0xb0, 0xf7, 0xc0, 0x8c, 0x9b, 0x51, 0xa7,
- 0x46, 0xa6, 0xaa, 0x5c, 0xe9, 0xaf, 0x3d, 0x52, 0x99, 0xaf, 0xc5, 0x74,
- 0x2e, 0xca, 0x52, 0x38, 0xb1, 0x3f, 0x30, 0x16, 0xbe, 0xc2, 0xc3, 0x7c,
- 0x51, 0x1e, 0xcd, 0xd4, 0xc5, 0x25, 0xa8, 0xca, 0x9d, 0x09, 0x98, 0xcd,
- 0xa5, 0xb6, 0x8a, 0x84, 0x93, 0xad, 0x56, 0x1c, 0x9b, 0x26, 0xfe, 0xbb,
- 0x8e, 0x6f, 0x85, 0xaa, 0x96, 0x21, 0x2a, 0x4f, 0xe1, 0xa4, 0xc7, 0x0a,
- 0x34, 0xbe, 0xe7, 0xa7, 0x21, 0xef, 0x0e, 0x94, 0x6c, 0x22, 0xdc, 0xab,
- 0x9f, 0x8d, 0x9d, 0x3d, 0xac, 0xc1, 0xcc, 0x93, 0x98, 0x1d, 0x07, 0x84,
- 0x44, 0x73, 0x33, 0xd3, 0xe9, 0x30, 0x26, 0x95, 0xbb, 0xe3, 0x04, 0xb6,
- 0x94, 0x3e, 0x82, 0x2d, 0x72, 0x97, 0x08, 0xbe, 0xde, 0x84, 0x1c, 0x51,
- 0xba, 0x0d, 0x3d, 0x72, 0x29, 0x25, 0x6c, 0x48, 0x5b, 0x5a, 0x96, 0x97,
- 0x2e, 0xa2, 0x12, 0x1b, 0x00, 0x8b, 0xf3, 0x7b, 0xdf, 0xb6, 0x17, 0xb3,
- 0x4c, 0x5a, 0x6d, 0x43, 0x2d, 0x66, 0x37, 0x20, 0xba, 0x99, 0x29, 0x44,
- 0x67, 0x9c, 0x2e, 0x24, 0x6c, 0x56, 0x97, 0x8a, 0xbf, 0xf8, 0xd8, 0xfd,
- 0xf1, 0xf5, 0xf8, 0x7d, 0x6c, 0x38, 0x66, 0x43, 0x4a, 0x1d, 0xf0, 0x8b,
- 0xc1, 0xd0, 0x7c, 0x3b, 0xa5, 0x28, 0xd3, 0x7b, 0x0b, 0x5f, 0xbe, 0xd6,
- 0x27, 0x1e, 0x63, 0x04, 0x36, 0x4b, 0x2e, 0xb7, 0xba, 0x47, 0xb4, 0x3e,
- 0xcf, 0xa5, 0x60, 0xa0, 0xab, 0x74, 0x88, 0x1f, 0x4d, 0x6a, 0x75, 0x5a,
- 0x85, 0x98, 0xe0, 0xb0, 0x94, 0x95, 0x49, 0x75, 0xb6, 0xc0, 0xe6, 0xc0,
- 0x5a, 0xdb, 0xfa, 0x5b, 0x9c, 0x13, 0xc9, 0xf5, 0xea, 0x5f, 0x4b, 0xa2,
- 0x4c, 0xa8, 0xc4, 0x9e, 0xc2, 0x6b, 0x13, 0x9b, 0x51, 0x54, 0x94, 0xb4,
- 0x16, 0xea, 0x49, 0x04, 0x14, 0xb6, 0x54, 0x3c, 0xa9, 0x17, 0xed, 0xb9,
- 0x3e, 0x98, 0x0f, 0x42, 0x62, 0xa9, 0x22, 0x74, 0xb8, 0x14, 0xe9, 0x11,
- 0x23, 0xc7, 0x92, 0xe0, 0x52, 0xca, 0x95, 0xa0, 0x71, 0x62, 0x9d, 0x86,
- 0xff, 0x00, 0x41, 0x6b, 0xf0, 0x4e, 0x08, 0x37, 0xd1, 0x25, 0x57, 0x67,
- 0x99, 0x55, 0x4c, 0xd8, 0xb5, 0xb8, 0xad, 0x92, 0x94, 0x37, 0xa7, 0x48,
- 0xec, 0x07, 0x60, 0x31, 0x96, 0x6b, 0x15, 0x52, 0x29, 0xf2, 0xad, 0x05,
- 0xaa, 0xee, 0x84, 0x81, 0xa1, 0x36, 0xc8, 0x5e, 0xff, 0x00, 0x7e, 0xd1,
- 0x3c, 0x6b, 0x0b, 0x55, 0xa7, 0x66, 0x5e, 0xba, 0xb8, 0x18, 0x52, 0xf8,
- 0xb2, 0x20, 0x15, 0x1d, 0xb3, 0xfb, 0xf3, 0x3a, 0xb0, 0x21};
-
-std::vector<uint8_t> l2cap_test_packet_5 = {
- 0xf6, 0x03, 0x47, 0x00, 0x0a, 0xc1, 0x0a, 0x8d, 0x2e, 0xa1, 0x99, 0xd9,
- 0x12, 0x98, 0xab, 0x13, 0x50, 0x64, 0x87, 0x9b, 0xf1, 0x1c, 0xb0, 0x48,
- 0xd4, 0x76, 0x1f, 0xdd, 0x1e, 0xa7, 0xe8, 0x37, 0xbe, 0x1b, 0xe9, 0x35,
- 0x68, 0x53, 0x99, 0x55, 0x32, 0x7c, 0x66, 0x51, 0x53, 0x41, 0x0e, 0x3c,
- 0xeb, 0x29, 0x1e, 0x1b, 0x8d, 0x95, 0x69, 0x0b, 0xd8, 0xec, 0x49, 0x3f,
- 0x4d, 0xb0, 0x73, 0x2e, 0xf4, 0x5f, 0x24, 0xd0, 0x90, 0xbf, 0x8e, 0xcd,
- 0x32, 0x8b, 0x65, 0x43, 0xc4, 0x02, 0x62, 0x12, 0x92, 0x47, 0xaf, 0x9a,
- 0xe7, 0xe9, 0x86, 0x58, 0x39, 0x6b, 0xa3, 0x14, 0x79, 0xc9, 0x9a, 0xe5,
- 0x4a, 0x13, 0xb2, 0xda, 0x01, 0x21, 0xc7, 0x65, 0xeb, 0xb0, 0x1c, 0x6c,
- 0x4e, 0x9b, 0x62, 0x73, 0x52, 0xc5, 0xcd, 0x4d, 0x3a, 0x57, 0xc2, 0xb5,
- 0x93, 0xc9, 0x3f, 0xc6, 0x50, 0xf7, 0x23, 0x4e, 0x44, 0xab, 0x61, 0xb6,
- 0x80, 0x00, 0x6c, 0x9f, 0xd8, 0x6b, 0xce, 0x1b, 0x24, 0x43, 0x99, 0x1a,
- 0x65, 0x00, 0x38, 0xb5, 0x29, 0x25, 0xa5, 0xb4, 0xbb, 0x7a, 0xea, 0x40,
- 0xfe, 0x98, 0xf0, 0xae, 0xcd, 0xc9, 0x3d, 0x32, 0x7a, 0xa7, 0x99, 0x24,
- 0x31, 0x09, 0x35, 0x49, 0x48, 0x4a, 0x65, 0xc9, 0x2b, 0x25, 0xd2, 0x81,
- 0xc2, 0x4a, 0xbf, 0x28, 0x3f, 0xdc, 0x4e, 0xe4, 0xf3, 0x7c, 0x22, 0x75,
- 0xaf, 0xad, 0x59, 0x7e, 0x9b, 0x0e, 0x9f, 0x13, 0x2c, 0x4c, 0x6e, 0x6c,
- 0xf2, 0xfa, 0x34, 0xe8, 0x21, 0xd0, 0x11, 0xbe, 0xa2, 0x42, 0x4d, 0xf7,
- 0xd8, 0x0e, 0x09, 0x3c, 0x71, 0x88, 0xd6, 0x70, 0xcd, 0x31, 0xf3, 0x25,
- 0x41, 0x2e, 0xd5, 0x68, 0x95, 0x29, 0xe9, 0x4a, 0x8a, 0xc3, 0x0b, 0x49,
- 0x4a, 0x50, 0xa3, 0xed, 0xdc, 0xf6, 0xb9, 0xdf, 0x18, 0xf0, 0xa6, 0x0d,
- 0xa8, 0x55, 0x07, 0x6a, 0xb5, 0x76, 0x4d, 0xd8, 0x85, 0x0c, 0xee, 0x41,
- 0x37, 0xb5, 0xad, 0xa1, 0xf1, 0xcb, 0x2d, 0xe3, 0xde, 0xa9, 0x5b, 0x6a,
- 0x59, 0x09, 0x41, 0x69, 0x4e, 0x2f, 0x50, 0x00, 0x16, 0xbe, 0xd7, 0x37,
- 0xca, 0xc3, 0x61, 0x99, 0xbe, 0xd0, 0xe3, 0x37, 0xac, 0xc9, 0xcd, 0xb9,
- 0x8d, 0x72, 0x65, 0xca, 0x8d, 0x1a, 0x9f, 0x1d, 0xc0, 0x98, 0xa8, 0x20,
- 0x0d, 0x42, 0xe4, 0x03, 0x63, 0xb8, 0x16, 0x37, 0xb7, 0x3f, 0xd0, 0x3d,
- 0x2b, 0xa9, 0x52, 0xa8, 0xb5, 0x1b, 0xc2, 0x9e, 0xa9, 0x3e, 0x0a, 0xac,
- 0xea, 0x96, 0x92, 0xef, 0x8e, 0x02, 0x48, 0xb6, 0xc3, 0x6d, 0xcf, 0x3e,
- 0xc3, 0x1e, 0x39, 0x2a, 0x3c, 0x19, 0xad, 0x95, 0x46, 0xc8, 0xae, 0xb0,
- 0x11, 0x75, 0x17, 0x9d, 0x6d, 0x94, 0x22, 0xd7, 0xb5, 0xb5, 0x38, 0x40,
- 0xf6, 0xe4, 0x9f, 0x6c, 0x13, 0x55, 0x4e, 0xbe, 0x89, 0x0e, 0xb1, 0x0b,
- 0x25, 0x25, 0xf0, 0xcb, 0xab, 0x6c, 0x3a, 0xd8, 0x6d, 0x68, 0x5d, 0xb7,
- 0xd8, 0xa4, 0xd8, 0xd8, 0x11, 0x72, 0x0d, 0xb1, 0x5d, 0x63, 0x05, 0xca,
- 0xa1, 0x29, 0x42, 0x5c, 0xb0, 0x1a, 0x00, 0x3f, 0x7b, 0xf9, 0x98, 0x4a,
- 0xfe, 0xb9, 0x5b, 0x71, 0xc2, 0x96, 0xa4, 0x14, 0xa2, 0x79, 0xe5, 0x97,
- 0x90, 0xb5, 0xba, 0x46, 0xf3, 0x75, 0x37, 0x73, 0x65, 0x1e, 0xb1, 0x53,
- 0x96, 0xd2, 0x51, 0x25, 0xe8, 0x2a, 0x43, 0x89, 0x4b, 0x6a, 0x4e, 0xe1,
- 0xb2, 0x01, 0x37, 0xee, 0x7f, 0x7b, 0x13, 0x8d, 0x2a, 0xad, 0x06, 0xac,
- 0xed, 0x0f, 0x2f, 0xcd, 0x85, 0x49, 0x95, 0x22, 0x3b, 0xb4, 0xb6, 0x42,
- 0x5c, 0x61, 0xa5, 0x2c, 0x13, 0xa4, 0x13, 0x7b, 0x0d, 0x8d, 0xcf, 0x7c,
- 0x7d, 0x48, 0x77, 0xa8, 0xd2, 0xe9, 0xef, 0xf8, 0x39, 0x6d, 0x2c, 0xc7,
- 0x28, 0x50, 0x71, 0x20, 0x04, 0xdd, 0x36, 0xdc, 0x12, 0x2e, 0x78, 0xf4,
- 0xdf, 0x1e, 0x1d, 0x31, 0xce, 0x99, 0xaa, 0x9b, 0x96, 0xc5, 0x39, 0xfa,
- 0xb5, 0x3a, 0x0e, 0x95, 0xa9, 0xa6, 0x93, 0xf1, 0x0a, 0x42, 0x96, 0x80,
- 0x4d, 0xb5, 0x24, 0x0b, 0x0b, 0x5e, 0xc0, 0x92, 0x36, 0x03, 0x1a, 0xeb,
- 0xf4, 0xd0, 0xe4, 0xa3, 0x52, 0xa8, 0x24, 0xf0, 0xee, 0x6c, 0x32, 0x1c,
- 0xc9, 0xb0, 0x83, 0x38, 0x0e, 0x7a, 0xa5, 0x86, 0x2a, 0x53, 0x35, 0x2a,
- 0x8b, 0x25, 0x01, 0xdd, 0x12, 0x02, 0x95, 0x9f, 0x44, 0x82, 0x72, 0x19,
- 0xe9, 0x68, 0x13, 0x23, 0x20, 0x67, 0x9a, 0xa2, 0xd2, 0x5a, 0xa5, 0xaa,
- 0x24, 0x72, 0x6c, 0x16, 0xf1, 0xd3, 0x72, 0x76, 0x16, 0xc3, 0x36, 0x42,
- 0xe9, 0x8e, 0x68, 0xa5, 0x3a, 0xec, 0x31, 0x5e, 0xa2, 0x35, 0x2a, 0x45,
- 0x99, 0x0d, 0xf8, 0xda, 0x9c, 0x4a, 0xb7, 0x16, 0x00, 0x7e, 0x6d, 0xef,
- 0xf5, 0x03, 0x04, 0x17, 0x54, 0xcc, 0x09, 0x74, 0x3e, 0xac, 0xcd, 0x1d,
- 0x85, 0x83, 0xa8, 0x29, 0x0b, 0x2a, 0x50, 0xf7, 0x1e, 0x71, 0x8d, 0x79,
- 0xf9, 0x8e, 0xb7, 0xf0, 0x4e, 0xd3, 0x0e, 0x64, 0x68, 0xb6, 0xe5, 0xd0,
- 0xa9, 0xa1, 0xd8, 0xed, 0xad, 0x77, 0x37, 0x2a, 0xb6, 0x92, 0xb2, 0x77,
- 0x3c, 0xaa, 0xfe, 0xf8, 0x0a, 0xde, 0x16, 0x9c, 0x29, 0xe0, 0x20, 0x01,
- 0xd4, 0x7d, 0x2f, 0x05, 0x2a, 0xbf, 0x13, 0xe8, 0x73, 0x93, 0x05, 0xd2,
- 0x54, 0xe2, 0x8f, 0x81, 0x00, 0x0f, 0x00, 0x48, 0x19, 0x72, 0xd4, 0xc1,
- 0x8c, 0xbf, 0xd0, 0xc9, 0x10, 0xa5, 0x2e, 0x54, 0x9c, 0xe1, 0x19, 0x84,
- 0xa9, 0x65, 0x4a, 0x07, 0x65, 0x13, 0xde, 0xfa, 0xad, 0x7d, 0xfd, 0x71,
- 0x4a, 0xcf, 0x79, 0x96, 0x83, 0x46, 0xca, 0xb1, 0x62, 0xbb, 0x5c, 0x8b,
- 0x29, 0xf8, 0xcf, 0x32, 0xe2, 0xfc, 0x35, 0x02, 0x43, 0x6d, 0x24, 0xdd,
- 0x4a, 0xb6, 0xc3, 0xf2, 0x8d, 0xf9, 0x27, 0x10, 0x77, 0x17, 0x45, 0xf1,
- 0x94, 0x26, 0x66, 0xb9, 0x4f, 0xac, 0x9e, 0x4a, 0x91, 0x73, 0xf7, 0xb1,
- 0xc7, 0xb5, 0x7b, 0x2a, 0x51, 0x6a, 0x79, 0x3e, 0x5c, 0xc8, 0x95, 0x19,
- 0xcf, 0xa9, 0xa4, 0xeb, 0xb2, 0x9f, 0x51, 0x06, 0xde, 0xa3, 0x83, 0x82,
- 0xac, 0xe1, 0xa9, 0x86, 0x7b, 0xe9, 0x29, 0xe2, 0xea, 0x4f, 0xd2, 0x03,
- 0x2f, 0xe2, 0x75, 0x19, 0xa7, 0x12, 0x7b, 0x27, 0x2d, 0x71, 0x6e, 0xe8,
- 0x02, 0xfb, 0x5c, 0xdc, 0x9b, 0x40, 0x2c, 0xcf, 0x57, 0xa5, 0xc9, 0x6e,
- 0x75, 0x35, 0x55, 0xa5, 0xb1, 0x19, 0xc7, 0x54, 0x7c, 0x26, 0x93, 0x7b,
- 0x79, 0x89, 0xb0, 0x3b, 0x6d, 0x85, 0x08, 0xd4, 0x6c, 0xa4, 0xf4, 0x84,
- 0x80, 0x9a, 0x9c, 0x85, 0x13, 0x62, 0xb2, 0xda, 0x95, 0xfa, 0x01, 0x8e,
- 0x87, 0x43, 0xf1, 0x29, 0x61, 0x8a, 0x76, 0x5c, 0xc9, 0xf4, 0x09, 0x50,
- 0x62, 0x46, 0x6c, 0x27, 0xc6, 0x6c, 0xba, 0xe3, 0xde, 0x51, 0xa9, 0x45,
- 0x77, 0xe4, 0x9b, 0xf0, 0x0f, 0xdf, 0x18, 0xff, 0x00, 0x54, 0x59, 0xa4,
- 0x7f, 0x66, 0x3a, 0x74, 0xc4, 0x37, 0x00, 0xf9, 0xda, 0x4a, 0x54, 0x01,
- 0xf6, 0xf2, 0x7f, 0xa8, 0x18, 0x2d, 0x3f, 0x3d, 0x34, 0x5b, 0x4a, 0x9e,
- 0x65, 0x27, 0xc8, 0x9b, 0x75, 0x17, 0xfa, 0x43, 0xf4, 0xae, 0x1a, 0x69,
- 0x94, 0x87, 0x99, 0x96, 0x48, 0x0b, 0xef, 0x1b, 0x01, 0xbe, 0xe7, 0x33,
- 0x6f, 0x41, 0x12, 0x68, 0xb9, 0x4d, 0x86, 0x23, 0x7c, 0x44, 0x6a, 0x0d,
- 0x5a, 0x53, 0x62, 0xca, 0xf2, 0xc5, 0x74, 0x5c, 0x7d, 0x54, 0x9b, 0x71,
- 0xef, 0x82, 0xf0, 0x32, 0x95, 0x69, 0x6f, 0x29, 0x11, 0xb2, 0x24, 0x97,
- 0xd2, 0x4d, 0xd2, 0x5f, 0x6c, 0xa4, 0xe9, 0x3c, 0x96, 0xae};
-
-std::vector<uint8_t> l2cap_test_packet_6 = {
- 0xf6, 0x03, 0x47, 0x00, 0x0c, 0xc1, 0x5c, 0x0b, 0x8c, 0x33, 0x2b, 0xac,
- 0x14, 0x79, 0x95, 0x37, 0x6a, 0x2b, 0xca, 0x2e, 0xbb, 0x31, 0x0b, 0x4b,
- 0x8a, 0x2a, 0x71, 0xd2, 0x02, 0xbb, 0x10, 0x92, 0x42, 0x47, 0x1c, 0x01,
- 0x82, 0x8b, 0xeb, 0x4e, 0x66, 0x76, 0x58, 0x71, 0x14, 0xe9, 0x11, 0x12,
- 0xf0, 0xd4, 0x35, 0x35, 0x74, 0xda, 0xc3, 0x72, 0x49, 0x36, 0xda, 0xdc,
- 0xe1, 0x69, 0x58, 0x8d, 0x6d, 0x9e, 0xe8, 0x48, 0xe8, 0x91, 0x1d, 0x84,
- 0xc2, 0x19, 0x3c, 0x29, 0x09, 0x1e, 0x9f, 0x40, 0x60, 0x2b, 0x99, 0x1f,
- 0xa9, 0x12, 0x68, 0x52, 0xa0, 0xc4, 0xa0, 0xc3, 0xa7, 0x46, 0x76, 0x3a,
- 0xdb, 0x5a, 0x02, 0x14, 0x14, 0xa4, 0x11, 0xba, 0x45, 0xc5, 0x85, 0xfd,
- 0x70, 0x13, 0xa5, 0xd9, 0x39, 0xd8, 0xcb, 0xf0, 0x5a, 0x9d, 0x32, 0x9a,
- 0xea, 0xd6, 0x59, 0x90, 0x1a, 0x59, 0x2a, 0x4a, 0xfd, 0x2c, 0x38, 0xb5,
- 0xb1, 0xd1, 0x7d, 0x1c, 0xcd, 0x33, 0xb3, 0x35, 0x0d, 0xea, 0x9c, 0x97,
- 0x94, 0xb2, 0xd4, 0xa2, 0xc3, 0x8d, 0xad, 0x20, 0x8b, 0x69, 0x06, 0xe0,
- 0x81, 0xf5, 0x18, 0x8b, 0xe7, 0x5f, 0x8a, 0xa4, 0x75, 0x36, 0xac, 0x23,
- 0xad, 0x49, 0x40, 0x9e, 0x56, 0x50, 0xa2, 0x40, 0x20, 0x80, 0x47, 0x18,
- 0x15, 0x58, 0x9f, 0x76, 0x71, 0xa4, 0xba, 0xb5, 0x5c, 0x79, 0x0f, 0xbd,
- 0x20, 0x7c, 0xea, 0xbf, 0x11, 0x72, 0x75, 0x1f, 0x28, 0x97, 0x3a, 0xc5,
- 0x52, 0xb5, 0x29, 0x70, 0x68, 0xb2, 0xdc, 0x8f, 0x31, 0x0d, 0x97, 0x95,
- 0xe1, 0x91, 0x7d, 0xd4, 0x76, 0xbd, 0xf6, 0xb5, 0xb9, 0xde, 0xfb, 0x61,
- 0x36, 0xb9, 0xfc, 0xcf, 0x47, 0x7c, 0xb5, 0x57, 0x7e, 0xb3, 0xc6, 0xea,
- 0x4c, 0x85, 0x14, 0x1f, 0xdf, 0x0d, 0x9d, 0x3b, 0x8f, 0x36, 0x99, 0x9b,
- 0xeb, 0x4b, 0x1a, 0x89, 0x6a, 0x31, 0xb1, 0x4f, 0x3a, 0x49, 0x2b, 0xb8,
- 0x27, 0xd8, 0x7e, 0xa7, 0x1e, 0x39, 0x6b, 0xa9, 0x5f, 0x1c, 0xfb, 0xb1,
- 0x6b, 0xd1, 0x14, 0xe2, 0x5c, 0x73, 0x50, 0x79, 0xb4, 0xa5, 0x6a, 0x48,
- 0x1c, 0x02, 0x95, 0x6c, 0xa0, 0x2f, 0xc6, 0x1b, 0xa9, 0x32, 0xf2, 0x32,
- 0xf2, 0x4d, 0xad, 0x49, 0x4f, 0x12, 0xaf, 0x9a, 0x80, 0x39, 0xf9, 0xe9,
- 0x12, 0x49, 0xfa, 0xa5, 0x4c, 0x4f, 0xbc, 0x86, 0x87, 0x1b, 0x68, 0xb6,
- 0x40, 0xd8, 0x8b, 0xf2, 0x84, 0x96, 0xaa, 0xce, 0xc8, 0x64, 0xc4, 0x65,
- 0x87, 0x54, 0xca, 0xc5, 0x94, 0x84, 0xb2, 0x92, 0x55, 0xbd, 0xcf, 0x98,
- 0xdc, 0xfe, 0xf8, 0xd9, 0x4b, 0xae, 0x34, 0x14, 0xf2, 0xe8, 0x0c, 0x21,
- 0x29, 0xdc, 0xf8, 0x82, 0xc7, 0xf4, 0xbe, 0x2a, 0xa7, 0x28, 0xb1, 0x2d,
- 0x46, 0xab, 0x95, 0xaa, 0x10, 0x52, 0xf2, 0x95, 0xe2, 0xa5, 0xa4, 0x37,
- 0x76, 0xaf, 0x6e, 0x34, 0x9d, 0xc7, 0xaf, 0xd7, 0x08, 0x35, 0x18, 0xf2,
- 0x20, 0xd4, 0x16, 0xc5, 0x5d, 0x2a, 0x65, 0xf0, 0x8b, 0x8f, 0x35, 0xc1,
- 0xed, 0xa8, 0x11, 0xee, 0x38, 0xc7, 0x5a, 0x85, 0x4e, 0xa9, 0x4f, 0x1c,
- 0x69, 0x42, 0x78, 0x79, 0x81, 0xf7, 0x6f, 0x94, 0x68, 0xa3, 0xcc, 0x53,
- 0x6a, 0xaa, 0x2d, 0xa5, 0x44, 0x2f, 0x74, 0x9b, 0x83, 0xe3, 0xd6, 0x19,
- 0xfa, 0x3f, 0x06, 0x8b, 0x5b, 0xcf, 0xf4, 0x09, 0x4f, 0xc0, 0x43, 0x5e,
- 0x12, 0x1d, 0x79, 0x2d, 0xa1, 0x45, 0x20, 0xba, 0x84, 0x9d, 0x17, 0x23,
- 0x7b, 0x03, 0x63, 0xf6, 0xb6, 0x3a, 0x0e, 0xbb, 0xd3, 0xa6, 0x44, 0x24,
- 0x0c, 0xbd, 0x3d, 0xba, 0x6c, 0xb2, 0xd8, 0x21, 0xb5, 0x30, 0x85, 0xa1,
- 0x47, 0xd4, 0x02, 0x2e, 0x2f, 0xed, 0x8e, 0x7e, 0xfc, 0x3c, 0x32, 0xb7,
- 0xb3, 0xe5, 0x27, 0x72, 0xa4, 0x21, 0x52, 0x75, 0x90, 0x3e, 0x54, 0xe8,
- 0x51, 0xfe, 0x98, 0x6c, 0xfc, 0x47, 0xe7, 0xdc, 0xd7, 0x94, 0xb3, 0xed,
- 0x1d, 0xda, 0x05, 0x5d, 0x71, 0xdb, 0x11, 0x0a, 0x8b, 0x7a, 0x02, 0x9b,
- 0x76, 0xe4, 0x6c, 0xb4, 0x91, 0xb8, 0xed, 0x89, 0xee, 0x39, 0x99, 0xaa,
- 0xb9, 0x88, 0xd8, 0x44, 0x8b, 0xe5, 0xb2, 0x5a, 0x0a, 0xf0, 0xdf, 0x23,
- 0xcf, 0x6d, 0x61, 0xef, 0x0d, 0x38, 0xdc, 0x9d, 0x35, 0xc5, 0x9f, 0xca,
- 0xb2, 0x0e, 0xe6, 0xd7, 0x00, 0x7c, 0xe0, 0x1f, 0x50, 0x8f, 0x55, 0xf2,
- 0xa3, 0xaa, 0x45, 0x4a, 0x04, 0x79, 0xb0, 0x55, 0xb8, 0x91, 0x19, 0x8d,
- 0x4d, 0xaa, 0xde, 0xa3, 0x80, 0x47, 0xd3, 0x09, 0xea, 0xae, 0xf5, 0x11,
- 0x6d, 0xa5, 0xc7, 0x1c, 0x99, 0x15, 0xbd, 0x65, 0x01, 0x49, 0x8b, 0xa0,
- 0x6a, 0xb5, 0xf4, 0x8b, 0x27, 0x9d, 0x8f, 0xe9, 0x8b, 0x87, 0x4c, 0xba,
- 0xd9, 0x4b, 0xce, 0x4d, 0xff, 0x00, 0x07, 0xcc, 0x94, 0x71, 0x16, 0x72,
- 0x80, 0x05, 0x6d, 0x5d, 0x71, 0xdd, 0x27, 0x61, 0x71, 0xc8, 0x37, 0x3d,
- 0xef, 0xcf, 0x38, 0x79, 0x9f, 0x93, 0x8c, 0x58, 0x4e, 0xd4, 0x68, 0xf2,
- 0x4b, 0x4c, 0xdb, 0x53, 0x8c, 0x2c, 0x6a, 0x09, 0x23, 0x6f, 0x29, 0x3b,
- 0x8f, 0x4f, 0xbe, 0x04, 0x9c, 0x77, 0x52, 0x92, 0x58, 0x97, 0xa9, 0xdd,
- 0x2a, 0xe6, 0x0e, 0x47, 0xd2, 0x0e, 0x25, 0x2e, 0x4c, 0x27, 0x8d, 0xa7,
- 0x8d, 0x8e, 0xd7, 0xb7, 0x95, 0xf5, 0xf5, 0xf5, 0x89, 0x1f, 0x47, 0xa4,
- 0x67, 0x06, 0x27, 0x4a, 0x35, 0xc7, 0x25, 0x86, 0xd4, 0xd1, 0x08, 0xf1,
- 0x52, 0x52, 0x1c, 0xba, 0x55, 0x71, 0xbf, 0xd0, 0x1f, 0xbe, 0x00, 0xaf,
- 0x5c, 0xa8, 0x5a, 0x94, 0x10, 0x5a, 0x84, 0xcb, 0x81, 0x5c, 0x27, 0x48,
- 0xf1, 0xd4, 0x3e, 0xe4, 0x95, 0x7b, 0x9f, 0xd3, 0x14, 0x2f, 0xe6, 0xaa,
- 0x6d, 0x4d, 0x6c, 0xd3, 0xdb, 0x42, 0x5a, 0x79, 0x32, 0x1d, 0x2a, 0x4a,
- 0x2e, 0x92, 0x2c, 0x40, 0xb6, 0xae, 0x49, 0xb0, 0xb9, 0x3e, 0xf8, 0x47,
- 0xcc, 0xb4, 0xc3, 0x4a, 0x6d, 0x6b, 0x2e, 0x25, 0xc2, 0xe4, 0xa7, 0xc1,
- 0x08, 0xb8, 0x03, 0x4b, 0xa4, 0xff, 0x00, 0xa1, 0x18, 0x6f, 0xa9, 0xce,
- 0x2e, 0x6a, 0x8a, 0xda, 0x9c, 0x37, 0x25, 0x47, 0xdb, 0xf9, 0x87, 0x1c,
- 0x20, 0xa3, 0xda, 0x25, 0xc3, 0x9a, 0x80, 0x56, 0xb9, 0x9d, 0xb7, 0x85,
- 0x77, 0xe9, 0xb4, 0xfa, 0xab, 0x28, 0x11, 0xe7, 0x2e, 0x39, 0x24, 0x85,
- 0xad, 0x06, 0xc1, 0x06, 0xfe, 0xd7, 0xfb, 0xed, 0x82, 0x39, 0x17, 0x2c,
- 0xd0, 0xd9, 0x9e, 0xf4, 0x3c, 0xcf, 0x54, 0x5f, 0x88, 0xbb, 0x18, 0x8b,
- 0x5b, 0xc4, 0xb6, 0xbd, 0xf9, 0x0a, 0x1d, 0xfd, 0xb6, 0xf4, 0xb6, 0x25,
- 0x94, 0xb9, 0x92, 0x62, 0x49, 0x75, 0xd8, 0xce, 0xa9, 0xb5, 0x29, 0xc5,
- 0x6d, 0x7d, 0xb9, 0x3b, 0x1c, 0x51, 0x28, 0x4e, 0x48, 0xaa, 0xd2, 0x5e,
- 0x79, 0xf8, 0xbe, 0x46, 0x52, 0x95, 0x2c, 0x84, 0xdd, 0x04, 0x15, 0x69,
- 0xe7, 0xd6, 0xfd, 0xb0, 0x15, 0xd3, 0x31, 0x2c, 0x9b, 0x71, 0x92, 0x9e,
- 0xb0, 0x2a, 0x5d, 0x9a, 0x26, 0x2b, 0x50, 0x2a, 0x68, 0x31, 0x30, 0xad,
- 0xc0, 0x04, 0x28, 0xfb, 0x67, 0xd7, 0x3f, 0x13, 0x15, 0xe8, 0x99, 0x07,
- 0x2d, 0x48, 0x6d, 0x0d, 0xc5, 0x61, 0x12, 0xdc, 0x5b, 0x6e, 0x5d, 0xa5,
- 0x2f, 0xec, 0x13, 0xb8, 0x3c, 0x1b, 0x0d, 0xf7, 0xbd, 0xce, 0x05, 0xc1,
- 0xa4, 0x39, 0x43, 0xca, 0x15, 0x0a, 0x3b, 0xad, 0x84, 0x2e, 0x3b, 0x6f,
- 0xb4, 0x42, 0x56, 0x5c, 0x06, 0xc5, 0x44, 0x79, 0xac, 0x2e, 0x34, 0xdb,
- 0x7b, 0x0c, 0x2b, 0x65, 0x9a, 0xcd, 0x47, 0x2d, 0x54, 0x92};
-
-std::vector<uint8_t> l2cap_test_packet_7 = {
- 0xf6, 0x03, 0x47, 0x00, 0x0e, 0xc1, 0xa0, 0xaa, 0x33, 0xea, 0x72, 0x1b,
- 0xab, 0xb2, 0xa3, 0xea, 0x1a, 0xae, 0x3c, 0xd7, 0x07, 0xe6, 0xb5, 0xff,
- 0x00, 0xec, 0x61, 0xd2, 0x7e, 0x67, 0x6b, 0x30, 0x49, 0x9a, 0xb0, 0x9f,
- 0x04, 0x2c, 0x36, 0x1f, 0xb6, 0xc0, 0x21, 0x68, 0x20, 0x8d, 0xb8, 0xb5,
- 0xb0, 0xc7, 0x84, 0x66, 0x82, 0xa7, 0x14, 0x39, 0xa4, 0xfd, 0x22, 0x3f,
- 0xf1, 0x5f, 0x0e, 0xcc, 0x52, 0x24, 0xd0, 0xdb, 0x80, 0x1b, 0x2d, 0x26,
- 0xe3, 0x96, 0x63, 0xe7, 0x1a, 0xf4, 0xf9, 0xb2, 0xe3, 0xe5, 0xb9, 0x2f,
- 0xb6, 0x99, 0x09, 0x53, 0x71, 0xf4, 0x25, 0xc4, 0x70, 0x8b, 0x2b, 0x7b,
- 0xff, 0x00, 0x97, 0xd3, 0x08, 0x59, 0x5f, 0xab, 0x71, 0xd2, 0xa5, 0xc5,
- 0xae, 0x53, 0x64, 0x25, 0xbd, 0x56, 0xf8, 0x86, 0x5e, 0x2a, 0x5a, 0x2c,
- 0x6f, 0x7b, 0x1e, 0x37, 0xdf, 0x6c, 0x58, 0xd2, 0xdd, 0x2e, 0xa5, 0xd2,
- 0x9a, 0x1f, 0xf0, 0xc2, 0xcf, 0xc5, 0xae, 0x0b, 0xc2, 0x62, 0x19, 0xf9,
- 0x8d, 0xd3, 0xb2, 0x96, 0x3e, 0xa9, 0xef, 0x8e, 0x46, 0x7d, 0x6b, 0x8b,
- 0x52, 0x93, 0x09, 0xc4, 0x95, 0xa1, 0x0f, 0xad, 0x36, 0x1c, 0xde, 0xe4,
- 0x6d, 0x83, 0x75, 0x4a, 0x93, 0xe8, 0x29, 0x71, 0xbc, 0xb6, 0x3e, 0x36,
- 0x8a, 0x83, 0xd5, 0xe9, 0x96, 0x29, 0xb2, 0x4e, 0xb2, 0x78, 0x41, 0x4d,
- 0x88, 0x23, 0x5b, 0x00, 0x05, 0xf7, 0xd8, 0xe9, 0x1d, 0x04, 0xec, 0xac,
- 0xbb, 0x9a, 0xa0, 0xae, 0x45, 0x3a, 0xb4, 0x15, 0x2d, 0xb2, 0x16, 0xd1,
- 0x69, 0x94, 0xb6, 0xf2, 0x8d, 0xff, 0x00, 0x38, 0xb5, 0x96, 0x07, 0x3c,
- 0x5f, 0x1f, 0x12, 0x8e, 0x69, 0x0d, 0x33, 0x26, 0xa0, 0x83, 0x52, 0x84,
- 0x96, 0xf4, 0x78, 0x91, 0xd0, 0x94, 0x92, 0x9b, 0x8f, 0x99, 0x36, 0xb1,
- 0xe3, 0x8d, 0xb0, 0x1f, 0xa4, 0x19, 0x3e, 0x7c, 0x69, 0x10, 0xf3, 0x0b,
- 0x8c, 0x7c, 0x38, 0x68, 0x97, 0x63, 0xb0, 0xf1, 0xf3, 0xba, 0x46, 0xe0,
- 0x1e, 0x39, 0xf4, 0xed, 0x83, 0x15, 0xac, 0xf6, 0xed, 0x26, 0x24, 0x88,
- 0x34, 0x94, 0xaf, 0xc6, 0xd4, 0x4b, 0xcb, 0x6d, 0x37, 0xd1, 0x7d, 0xac,
- 0x3d, 0xf9, 0xdb, 0x9c, 0x63, 0x5c, 0x8c, 0xac, 0xcc, 0xa9, 0x76, 0x75,
- 0x01, 0xbe, 0x56, 0xca, 0xfe, 0x50, 0xc0, 0xd2, 0x18, 0x9a, 0x94, 0x33,
- 0x33, 0xcd, 0x04, 0x11, 0xbd, 0xed, 0x97, 0x80, 0xd7, 0xa0, 0xb1, 0x31,
- 0x7b, 0xe9, 0x12, 0xe8, 0xec, 0xe5, 0x1b, 0xd3, 0x65, 0x25, 0x2b, 0x7e,
- 0x38, 0x94, 0xb2, 0xa5, 0x15, 0x0b, 0x8d, 0x8d, 0xc6, 0xd6, 0x20, 0x1d,
- 0xc0, 0xe0, 0x8c, 0x47, 0xfa, 0xd7, 0x35, 0x11, 0x33, 0xed, 0x55, 0xe7,
- 0x8b, 0x6a, 0xd4, 0x84, 0xb8, 0x46, 0xab, 0x0b, 0x80, 0x47, 0xef, 0x6c,
- 0x6c, 0xf4, 0x0a, 0x53, 0xf3, 0xe4, 0xd4, 0x59, 0xbc, 0x86, 0x5b, 0x4c,
- 0x72, 0xd8, 0x4b, 0xbb, 0x06, 0xf5, 0x21, 0x57, 0x1f, 0x5b, 0x81, 0x7c,
- 0x2a, 0x7e, 0x26, 0x9b, 0x7e, 0x36, 0x64, 0x8b, 0xe6, 0x4b, 0xa8, 0x98,
- 0xd2, 0x3c, 0xac, 0x82, 0xa2, 0xa0, 0x9b, 0x77, 0x23, 0x6d, 0xf7, 0xc2,
- 0x83, 0xbc, 0x0b, 0x68, 0x34, 0x9d, 0x02, 0xb2, 0xe9, 0x09, 0xce, 0x80,
- 0x86, 0x94, 0xb4, 0x1b, 0x8b, 0x9d, 0x75, 0xb5, 0xf2, 0x8d, 0x18, 0x68,
- 0x47, 0xf3, 0x58, 0x60, 0x04, 0x24, 0x96, 0x46, 0xab, 0xaa, 0xdb, 0x59,
- 0x69, 0x23, 0x7e, 0xe4, 0xf6, 0x18, 0x8c, 0x65, 0x88, 0x92, 0xe5, 0xd7,
- 0xfe, 0x12, 0x23, 0x0b, 0x79, 0xd5, 0x28, 0xa7, 0x4a, 0x47, 0xbf, 0xed,
- 0x8b, 0x58, 0x8b, 0x1d, 0x59, 0xe9, 0xb6, 0xd6, 0xa0, 0xd2, 0x1c, 0x80,
- 0x95, 0x6c, 0x6c, 0x51, 0xe6, 0x26, 0xff, 0x00, 0x6e, 0x70, 0x0e, 0xa7,
- 0x99, 0x72, 0xbe, 0x49, 0x79, 0xf6, 0x29, 0x30, 0x99, 0x9c, 0xe3, 0xaa,
- 0xd6, 0xe0, 0x4a, 0x8a, 0x75, 0x2b, 0x7b, 0x82, 0x46, 0xf6, 0x3d, 0xc6,
- 0x1e, 0xa4, 0xe4, 0x91, 0x35, 0x4c, 0x61, 0x4e, 0x2a, 0xc9, 0x48, 0x37,
- 0xf5, 0x88, 0xd4, 0xe4, 0xeb, 0xb2, 0xb5, 0x59, 0x86, 0xd8, 0x41, 0x5a,
- 0xd4, 0x13, 0x6e, 0x43, 0x5c, 0xc9, 0xf3, 0x86, 0x4c, 0xb5, 0x16, 0x9f,
- 0x93, 0x61, 0x8a, 0x85, 0x46, 0xa4, 0xc7, 0x8e, 0xa4, 0xa8, 0x2d, 0x09,
- 0x57, 0x97, 0x56, 0xdb, 0x7b, 0x9d, 0xb0, 0xbd, 0x9d, 0x69, 0xd5, 0x4c,
- 0xc7, 0x25, 0xea, 0xab, 0x2c, 0x06, 0xda, 0x6e, 0x3a, 0xec, 0x93, 0xf3,
- 0x2a, 0xf6, 0x55, 0xcd, 0xb8, 0xe0, 0x58, 0x5c, 0xfb, 0xde, 0xf8, 0x9b,
- 0xe6, 0x0c, 0xd3, 0x2b, 0x30, 0xd5, 0x05, 0x4a, 0xa4, 0xab, 0xbf, 0xa9,
- 0x21, 0x0d, 0x36, 0x90, 0x96, 0x9a, 0x48, 0xb5, 0x92, 0x00, 0x1e, 0x82,
- 0xd8, 0x7d, 0x9d, 0xd4, 0x5a, 0x62, 0xe8, 0x72, 0x22, 0xc7, 0x6d, 0xe5,
- 0x3a, 0xe4, 0x52, 0xd0, 0x48, 0x05, 0x37, 0x51, 0xb0, 0xd4, 0x3d, 0x3b,
- 0xfe, 0xd8, 0xc7, 0x51, 0x9f, 0x79, 0xf6, 0x44, 0xac, 0x93, 0x47, 0x83,
- 0xa1, 0x37, 0xb7, 0xdf, 0x58, 0xdf, 0x45, 0xa1, 0xa1, 0x89, 0x83, 0x3f,
- 0x38, 0xbe, 0x27, 0x8f, 0x90, 0x17, 0xe5, 0x19, 0xf8, 0x7e, 0xa9, 0x7f,
- 0x0c, 0xcf, 0x74, 0xe6, 0x41, 0x4a, 0xd2, 0xeb, 0xce, 0xb3, 0xa8, 0xde,
- 0xe0, 0x68, 0x5e, 0xff, 0x00, 0xed, 0x86, 0xef, 0xc4, 0xae, 0x57, 0xad,
- 0x66, 0x9c, 0xf5, 0x96, 0xa9, 0x99, 0x7a, 0x9d, 0x22, 0xa3, 0x2d, 0xe8,
- 0xaa, 0x40, 0x08, 0x48, 0x09, 0x16, 0x37, 0x25, 0x44, 0xec, 0x91, 0x6d,
- 0xee, 0x48, 0x18, 0x40, 0xe9, 0x72, 0x97, 0x1f, 0x38, 0xd0, 0xe4, 0x4c,
- 0x01, 0x82, 0xed, 0x49, 0xc4, 0x5d, 0xc5, 0x00, 0x2e, 0xa4, 0xe9, 0x1b,
- 0xf1, 0xc9, 0xb6, 0x3a, 0x7f, 0x38, 0x67, 0x5a, 0x2e, 0x59, 0xa6, 0xa5,
- 0xe0, 0x17, 0x2e, 0xa6, 0xb8, 0xfa, 0x52, 0xdb, 0x00, 0xd8, 0x26, 0xfb,
- 0x6b, 0x20, 0x5c, 0xef, 0xc2, 0x45, 0xf0, 0x93, 0x8e, 0x17, 0x35, 0x2b,
- 0x5d, 0x93, 0x71, 0x96, 0x8a, 0xd6, 0x59, 0x02, 0xde, 0x3d, 0xe1, 0xed,
- 0xbc, 0x50, 0xb0, 0xeb, 0x0d, 0xcd, 0x53, 0xdf, 0x6c, 0x1d, 0x56, 0x6f,
- 0xe5, 0x63, 0xf4, 0x85, 0xbe, 0x94, 0xf4, 0x72, 0x85, 0xd3, 0xd8, 0x08,
- 0xcc, 0xb9, 0x96, 0x4b, 0x33, 0xab, 0x2c, 0xd8, 0x87, 0x41, 0xbc, 0x68,
- 0x8b, 0xec, 0x1b, 0x07, 0xff, 0x00, 0x51, 0x63, 0xfb, 0xdd, 0xbb, 0x0e,
- 0xf8, 0xdb, 0xcc, 0xd9, 0xc6, 0x7d, 0x6e, 0x97, 0x22, 0x99, 0x97, 0xdc,
- 0x30, 0xd2, 0xa6, 0xd4, 0x18, 0x23, 0xe7, 0x70, 0xff, 0x00, 0x7d, 0x44,
- 0xf0, 0x2f, 0xe9, 0xbd, 0xed, 0xef, 0x88, 0x96, 0x6e, 0xcd, 0xdd, 0x45,
- 0xce, 0x15, 0x44, 0x29, 0xea, 0x7c, 0xe4, 0x42, 0x6a, 0xe1, 0xa6, 0x49,
- 0x08, 0xda, 0xe7, 0x7b, 0x5f, 0xcb, 0x7f, 0x41, 0xe9, 0xdf, 0x07, 0xa9,
- 0xaf, 0xe7, 0x01, 0x14, 0xb6, 0xb8, 0x4d, 0x0f, 0x11, 0x21, 0x09, 0x40,
- 0x76, 0xe5, 0x24, 0xef, 0x60, 0x07, 0xdf, 0x6c, 0x0f, 0x6b, 0x07, 0xd4,
- 0xa6, 0xdd, 0x13, 0x53, 0xa8, 0x2b, 0x5e, 0xc2, 0xdd, 0xd4, 0xf4, 0x82,
- 0xcd, 0x87, 0x52, 0x9e, 0xce, 0x55, 0xb2, 0x40, 0xde, 0xc7, 0xda, 0xff,
- 0x00, 0x3f, 0xe6, 0x14, 0xb2, 0x2c, 0x09, 0x51, 0x33, 0x8c, 0x66, 0x96,
- 0xe1, 0x7d, 0xc5, 0x2d, 0xc4, 0x94, 0x29, 0xcb, 0xf9, 0x86, 0xc6, 0xe4,
- 0x5e, 0xdd, 0xf0, 0x56, 0x6c, 0xc9, 0x93, 0x95, 0xfa, 0xf6};
-
-std::vector<uint8_t> l2cap_test_packet_8 = {
- 0xf6, 0x03, 0x47, 0x00, 0x10, 0xc1, 0x53, 0x69, 0x65, 0xc7, 0x52, 0xcc,
- 0xa7, 0x94, 0x02, 0xd5, 0xa8, 0xa0, 0x6b, 0xde, 0xde, 0xbd, 0xbf, 0x4c,
- 0x39, 0xe4, 0xec, 0x9f, 0x57, 0x77, 0x33, 0x35, 0x50, 0x9f, 0x4e, 0x44,
- 0x25, 0x34, 0xab, 0xa5, 0xd0, 0x8d, 0x3a, 0x81, 0xd8, 0x85, 0x71, 0xc7,
- 0x37, 0xe4, 0x93, 0x84, 0x99, 0x2f, 0xb0, 0xd5, 0x72, 0xae, 0x88, 0xe8,
- 0x7a, 0x4a, 0xdb, 0x98, 0xf0, 0x75, 0x09, 0x68, 0x9d, 0x0a, 0xd5, 0xb0,
- 0xbf, 0x1b, 0xdb, 0x0e, 0x75, 0x19, 0x29, 0x84, 0x51, 0xd0, 0x85, 0xa0,
- 0xf1, 0xf1, 0xde, 0xdb, 0xd8, 0x8f, 0xda, 0x1b, 0xb0, 0xc3, 0x8c, 0xc8,
- 0x9f, 0xee, 0x94, 0x1b, 0x04, 0x2b, 0xfc, 0x8d, 0xb6, 0x1b, 0x9e, 0x86,
- 0x13, 0x32, 0xee, 0x51, 0x95, 0x26, 0x62, 0x97, 0x2b, 0xca, 0x85, 0x38,
- 0x74, 0x36, 0x8d, 0xd4, 0xab, 0x9d, 0xbe, 0x98, 0x69, 0xa8, 0xfc, 0x0d,
- 0x1c, 0x22, 0x1c, 0x55, 0x32, 0x08, 0x1b, 0xa5, 0x0e, 0x6a, 0x08, 0xf5,
- 0x04, 0x8e, 0x4f, 0x7d, 0xb1, 0xf9, 0x3a, 0x8f, 0x99, 0xea, 0x68, 0x4a,
- 0x63, 0xc8, 0x85, 0x01, 0xbe, 0x74, 0x97, 0x81, 0xd3, 0x7f, 0x5b, 0x72,
- 0x71, 0xa3, 0x1b, 0xa7, 0x33, 0x18, 0x92, 0xdb, 0x95, 0x3a, 0xd3, 0x84,
- 0xba, 0x82, 0xa1, 0xe0, 0x46, 0x71, 0x6a, 0x29, 0xe3, 0xb0, 0x36, 0xc6,
- 0x54, 0xe1, 0xea, 0x8c, 0xd0, 0x0b, 0x75, 0x36, 0x1c, 0xb2, 0x10, 0xa0,
- 0xf7, 0xc4, 0x6c, 0x37, 0x86, 0xc1, 0x96, 0xa4, 0x1e, 0x35, 0x0c, 0x8a,
- 0xc8, 0xb9, 0x3d, 0x32, 0xf6, 0xc8, 0x43, 0x2e, 0x4d, 0x99, 0x97, 0xd4,
- 0x5c, 0x4d, 0x69, 0x97, 0x3c, 0x55, 0x0b, 0xa6, 0x42, 0xaf, 0x66, 0xc6,
- 0x92, 0x6c, 0x12, 0x0d, 0xbe, 0xfe, 0xbd, 0xf0, 0xcf, 0x05, 0xa8, 0x4e,
- 0xd6, 0x27, 0x1a, 0x5b, 0xc8, 0x2c, 0x08, 0x8d, 0x82, 0xb6, 0x55, 0x70,
- 0xa5, 0x00, 0xaf, 0x5e, 0xdb, 0xe1, 0x61, 0x8e, 0x9b, 0x44, 0x0a, 0x68,
- 0xbd, 0x5a, 0x7d, 0x69, 0x28, 0x05, 0x2a, 0x5a, 0xc8, 0xf2, 0xfa, 0x7b,
- 0x7d, 0x30, 0xdd, 0x95, 0xa9, 0x54, 0xbc, 0xb6, 0xc4, 0x8b, 0xcf, 0x69,
- 0x48, 0x5f, 0x9c, 0xf9, 0x49, 0x3b, 0x0b, 0x6e, 0x7b, 0xe1, 0x86, 0x83,
- 0x40, 0x98, 0x91, 0x9b, 0x0f, 0x39, 0x60, 0x90, 0x0e, 0xf1, 0x1b, 0xc6,
- 0xf8, 0xe6, 0x56, 0xbb, 0x28, 0xa4, 0xa5, 0x4a, 0x53, 0x84, 0x8d, 0x41,
- 0xd8, 0xc6, 0x8e, 0x49, 0x2b, 0xfe, 0x58, 0xa4, 0x2c, 0x3a, 0xb4, 0x07,
- 0x1a, 0x2d, 0x2e, 0xcb, 0x29, 0xbe, 0x95, 0x91, 0xcf, 0xf9, 0x86, 0x34,
- 0x1b, 0xc8, 0xf4, 0x8c, 0xaf, 0x5e, 0x7b, 0x30, 0xd7, 0x5a, 0x69, 0xe4,
- 0x15, 0xf8, 0x89, 0x2e, 0x3a, 0x34, 0x81, 0xea, 0x07, 0xae, 0x0e, 0xf4,
- 0xc1, 0xba, 0x5d, 0x63, 0xa7, 0xae, 0xc4, 0x55, 0x72, 0x1c, 0x19, 0xf0,
- 0x66, 0x38, 0x02, 0x5f, 0x41, 0xf9, 0x54, 0x41, 0x1c, 0x6f, 0x6f, 0x70,
- 0x0e, 0xe2, 0xc7, 0x1e, 0x95, 0x1c, 0xa7, 0x95, 0x6a, 0x8f, 0x78, 0x99,
- 0xa7, 0x38, 0xbb, 0x31, 0x60, 0xec, 0xdc, 0x55, 0x04, 0xb2, 0x91, 0xed,
- 0xab, 0x73, 0xf5, 0x23, 0x1e, 0xf3, 0x75, 0x49, 0x44, 0x23, 0x3e, 0xf2,
- 0x92, 0x4d, 0x87, 0x99, 0xce, 0x3e, 0x82, 0xa0, 0x54, 0x25, 0x95, 0x47,
- 0x96, 0xed, 0x52, 0x14, 0xb4, 0x0c, 0xae, 0x0e, 0x47, 0x63, 0x7d, 0xad,
- 0x7f, 0x13, 0xf3, 0x08, 0x59, 0xa7, 0xa9, 0x90, 0xe7, 0xd4, 0x3f, 0x87,
- 0xd3, 0xd6, 0x44, 0x73, 0xb1, 0x7d, 0x46, 0xca, 0xb7, 0x64, 0x8b, 0x7c,
- 0xa3, 0x8d, 0x86, 0xe7, 0xb9, 0xed, 0x80, 0xd4, 0x1a, 0xac, 0x04, 0xb8,
- 0xe1, 0x71, 0x0b, 0xd2, 0xb7, 0x09, 0xdc, 0xdf, 0x49, 0xdf, 0x6b, 0x1f,
- 0xad, 0xcf, 0xed, 0x8a, 0xe2, 0x32, 0x5e, 0x40, 0x85, 0x1d, 0x89, 0x14,
- 0xa8, 0x54, 0xea, 0xb8, 0x52, 0x94, 0x1c, 0x0f, 0x4f, 0x53, 0x3e, 0x1f,
- 0xf7, 0x46, 0xc8, 0x37, 0x36, 0xbd, 0xed, 0xc6, 0x18, 0xa9, 0xf4, 0xfe,
- 0x9a, 0xa6, 0x12, 0x14, 0xfd, 0x0c, 0x31, 0x25, 0x0a, 0x21, 0xe6, 0x58,
- 0x43, 0xce, 0x83, 0xb6, 0xc5, 0x2e, 0x5b, 0x71, 0xfa, 0x61, 0x36, 0xa1,
- 0x3e, 0x26, 0x94, 0x4b, 0xae, 0x0f, 0x33, 0x18, 0x26, 0x3b, 0x79, 0xb7,
- 0x4a, 0x9e, 0x70, 0x78, 0x00, 0x32, 0x1e, 0xa7, 0xde, 0x37, 0x7a, 0x17,
- 0xe0, 0x3b, 0x48, 0x42, 0x53, 0xe0, 0x3a, 0xfb, 0xa9, 0x5b, 0xee, 0x29,
- 0xa1, 0xc9, 0x06, 0xc7, 0x9e, 0xc0, 0x5b, 0x02, 0x7f, 0x12, 0x50, 0xd2,
- 0xdd, 0x7e, 0x93, 0x25, 0x20, 0x05, 0x29, 0x82, 0x90, 0x37, 0xb1, 0xb1,
- 0x1e, 0x9f, 0x43, 0x86, 0xaa, 0x5d, 0x7f, 0x25, 0x51, 0x5d, 0x0b, 0xa7,
- 0x50, 0xaa, 0x37, 0x00, 0x68, 0x09, 0x69, 0x66, 0xc3, 0xef, 0x84, 0xbe,
- 0xa7, 0xe6, 0x98, 0xb9, 0xb2, 0xbf, 0x16, 0x33, 0x50, 0x64, 0xc2, 0xf8,
- 0x26, 0xff, 0x00, 0xe7, 0x24, 0xa5, 0x4a, 0x4f, 0xae, 0xe3, 0x8d, 0xf9,
- 0xe3, 0x6c, 0x60, 0x4b, 0x8c, 0xf6, 0x25, 0x01, 0x60, 0xaa, 0xf7, 0xc8,
- 0xc6, 0x57, 0x18, 0xec, 0x90, 0x45, 0xf2, 0xf1, 0xb7, 0xca, 0xe6, 0x24,
- 0x3d, 0x41, 0x97, 0x21, 0x1f, 0x0d, 0xf0, 0x4e, 0xa2, 0x3c, 0xc7, 0x96,
- 0x4e, 0xa5, 0x10, 0x0f, 0x86, 0x05, 0x92, 0x8b, 0x9f, 0xca, 0x76, 0xfd,
- 0x31, 0x3c, 0x10, 0xaa, 0xae, 0xbe, 0xaf, 0xfc, 0xad, 0x97, 0x97, 0x7d,
- 0xce, 0x92, 0xa3, 0xfa, 0xe2, 0xae, 0x8a, 0x4c, 0x1a, 0xef, 0x50, 0x69,
- 0x54, 0x9a, 0x83, 0xc9, 0x62, 0x3f, 0xc0, 0xba, 0xf1, 0x71, 0x36, 0x3a,
- 0x52, 0x3e, 0x5d, 0xcf, 0xa0, 0x37, 0xbe, 0x07, 0xe6, 0x8c, 0x85, 0x9a,
- 0xe3, 0xcf, 0x28, 0xc9, 0xd5, 0x29, 0xb5, 0x66, 0x42, 0x43, 0x88, 0x44,
- 0x72, 0xa2, 0xbd, 0x2a, 0xbd, 0xb9, 0xdd, 0x5c, 0x1b, 0x73, 0xf5, 0xc5,
- 0x33, 0x0d, 0xb6, 0xf3, 0x34, 0xd0, 0xe7, 0x19, 0xb1, 0xb9, 0x00, 0x01,
- 0x90, 0xb9, 0x1a, 0xab, 0x2f, 0x28, 0x57, 0x55, 0x29, 0xb7, 0xc2, 0xa6,
- 0x0a, 0x49, 0xd8, 0xdb, 0x5c, 0xa0, 0x05, 0x1f, 0x29, 0x54, 0xdd, 0xa7,
- 0xa9, 0xe7, 0xe3, 0x53, 0xa2, 0x10, 0x9b, 0xb7, 0xe2, 0x4f, 0x09, 0x2e,
- 0x0b, 0x5e, 0xe0, 0x04, 0x2a, 0xff, 0x00, 0xb6, 0x3c, 0x19, 0xcb, 0xd9,
- 0xd9, 0x45, 0x3f, 0x0d, 0x47, 0x8e, 0x9d, 0x48, 0x4a, 0xbc, 0xa5, 0x2a,
- 0xb5, 0xc6, 0xd7, 0xb9, 0x36, 0x3e, 0xd8, 0x0e, 0x89, 0x59, 0xb5, 0x89,
- 0x4b, 0x82, 0xa9, 0x72, 0xe3, 0xb8, 0x83, 0x65, 0x24, 0xf9, 0x74, 0x9f,
- 0x43, 0xb6, 0xc7, 0xeb, 0x82, 0xb4, 0xea, 0x6e, 0x75, 0x9e, 0xca, 0xa5,
- 0x36, 0xed, 0x49, 0xc4, 0xa1, 0x5a, 0x54, 0x52, 0x6f, 0xc7, 0x3c, 0x63,
- 0x43, 0xb8, 0xa9, 0xa6, 0xcf, 0x0a, 0x8a, 0xc5, 0xbf, 0xf3, 0xf7, 0xe8,
- 0x04, 0x71, 0x6e, 0x9f, 0x4a, 0x51, 0xcd, 0x0b, 0x3d, 0x48, 0xfa, 0xde,
- 0x33, 0x30, 0xe5, 0xec, 0xe9, 0x12, 0x9a, 0x89, 0xd5, 0x86, 0x99, 0x6a,
- 0x34, 0x75, 0x78, 0x88, 0xd4, 0x05, 0x8a, 0x86, 0xe1, 0x36, 0xb7, 0x7b,
- 0x7d, 0x31, 0xeb, 0x53, 0xa8, 0x67, 0xc8, 0x49, 0x65, 0x6e, 0x39, 0x22,
- 0x13, 0x2a, 0x17, 0x65, 0x41, 0xb5, 0xb4, 0x9b, 0x13, 0xdb, 0x55, 0x88,
- 0x1b, 0xf7, 0xc3, 0xfd, 0x0e, 0x44, 0xc7, 0xa8, 0x2c, 0xc1, 0xac, 0x34,
- 0x92, 0xb6, 0x27, 0xc7, 0x6d, 0x68, 0x51, 0xb8, 0xa4, 0x1d};
-
-std::vector<uint8_t> l2cap_test_packet_9 = {0x09, 0x00, 0x47, 0x00, 0x12,
- 0x81, 0x3c, 0x1d, 0xc7, 0x62,
- 0x45, 0x1a, 0x78};
-
-// complete_l2cap_packet is the l2cap packet that should be created when
-// assemble is called on a vector<L2capSdu*> that contains the previous 9 test
-// packets.
-std::vector<uint8_t> complete_l2cap_packet = {
- 0x95, 0x1f, 0x47, 0x00, 0x02, 0x1f, 0x95, 0xcb, 0x00, 0x00, 0x00, 0x01,
- 0x01, 0x00, 0x33, 0x00, 0x49, 0x00, 0x4d, 0x00, 0x47, 0x00, 0x5f, 0x00,
- 0x32, 0x00, 0x30, 0x00, 0x31, 0x00, 0x37, 0x00, 0x30, 0x00, 0x36, 0x00,
- 0x30, 0x00, 0x36, 0x00, 0x5f, 0x00, 0x31, 0x00, 0x35, 0x00, 0x34, 0x00,
- 0x33, 0x00, 0x33, 0x00, 0x38, 0x00, 0x2e, 0x00, 0x6a, 0x00, 0x70, 0x00,
- 0x67, 0x00, 0x00, 0x42, 0x00, 0x0e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f,
- 0x6a, 0x70, 0x65, 0x67, 0x00, 0xc3, 0x00, 0x12, 0x30, 0x03, 0x97, 0x01,
- 0x48, 0x1f, 0x45, 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49,
- 0x46, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0xff,
- 0xe1, 0x2b, 0x18, 0x45, 0x78, 0x69, 0x66, 0x00, 0x00, 0x4d, 0x4d, 0x00,
- 0x2a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x04, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x0c, 0xc0, 0x01, 0x01, 0x00, 0x04, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x09, 0x90, 0x01, 0x0f, 0x00, 0x02, 0x00,
- 0x00, 0x00, 0x04, 0x4c, 0x47, 0x45, 0x00, 0x01, 0x10, 0x00, 0x02, 0x00,
- 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x9e, 0x01, 0x12, 0x00, 0x03, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x1a, 0x00, 0x05, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa6, 0x01, 0x1b, 0x00, 0x05, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xae, 0x01, 0x28, 0x00, 0x03, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x01, 0x31, 0x00, 0x02, 0x00,
- 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xb6, 0x01, 0x32, 0x00, 0x02, 0x00,
- 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xbd, 0x02, 0x13, 0x00, 0x03, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x87, 0x69, 0x00, 0x04, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x02, 0x78, 0x4e,
- 0x65, 0x78, 0x75, 0x73, 0x20, 0x35, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x50,
- 0x69, 0x63, 0x61, 0x73, 0x61, 0x00, 0x32, 0x30, 0x31, 0x37, 0x3a, 0x30,
- 0x36, 0x3a, 0x30, 0x36, 0x20, 0x31, 0x35, 0x3a, 0x34, 0x33, 0x3a, 0x33,
- 0x38, 0x00, 0x00, 0x00, 0x15, 0x82, 0x9a, 0x00, 0x05, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x01, 0xd4, 0x82, 0x9d, 0x00, 0x05, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x01, 0xdc, 0x88, 0x27, 0x00, 0x03, 0x00, 0x00, 0x00,
- 0x01, 0x02, 0x1f, 0x00, 0x00, 0x90, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
- 0x04, 0x30, 0x32, 0x32, 0x30, 0x90, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x14, 0x00, 0x00, 0x01, 0xe4, 0x90, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x14, 0x00, 0x00, 0x01, 0xf8, 0x91, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00,
- 0x04, 0x01, 0x02, 0x03, 0x00, 0x92, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x02, 0x0c, 0x92, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x02, 0x14, 0x92, 0x09, 0x00, 0x03, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x92, 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x02, 0x1c, 0x92, 0x90, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x07, 0x00, 0x00, 0x02, 0x24, 0x92, 0x91, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x07, 0x00, 0x00, 0x02, 0x2b, 0x92, 0x92, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x07, 0x00, 0x00, 0x02, 0x32, 0xa0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
- 0x04, 0x30, 0x31, 0x30, 0x30, 0xa0, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x00, 0xa0, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x0a, 0x0a, 0xa0, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x07, 0x77, 0xa0, 0x05, 0x00, 0x04, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x02, 0x5a, 0xa4, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x21, 0x00, 0x00, 0x02, 0x39, 0x00, 0x00, 0x00, 0x00, 0x01, 0xfc, 0x8c,
- 0xb2, 0x3b, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00,
- 0x64, 0x32, 0x30, 0x31, 0x37, 0x3a, 0x30, 0x36, 0x3a, 0x30, 0x36, 0x20,
- 0x31, 0x35, 0x3a, 0x34, 0x33, 0x3a, 0x33, 0x38, 0x00, 0x32, 0x30, 0x31,
- 0x37, 0x3a, 0x30, 0x36, 0x3a, 0x30, 0x36, 0x20, 0x31, 0x35, 0x3a, 0x34,
- 0x33, 0x3a, 0x33, 0x38, 0x00, 0xff, 0xff, 0xfe, 0x16, 0x00, 0x00, 0x00,
- 0x64, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x0f,
- 0x82, 0x00, 0x00, 0x03, 0xe8, 0x39, 0x39, 0x39, 0x37, 0x32, 0x39, 0x00,
- 0x39, 0x39, 0x39, 0x37, 0x32, 0x39, 0x00, 0x39, 0x39, 0x39, 0x37, 0x32,
- 0x39, 0x00, 0x31, 0x30, 0x61, 0x66, 0x39, 0x37, 0x31, 0x37, 0x63, 0x31,
- 0x30, 0x36, 0x36, 0x33, 0x65, 0x62, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
- 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00,
- 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x52, 0x39, 0x38,
- 0x00, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x30, 0x31, 0x30,
- 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x03, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x01, 0x1a, 0x00, 0x05, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0xc6, 0x01, 0x1b, 0x00, 0x05, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0xce, 0x01, 0x28, 0x00, 0x03, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0xd6, 0x02, 0x02, 0x00, 0x04, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x28, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00,
- 0x00, 0x00, 0x01, 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49,
- 0x46, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0xff,
- 0xdb, 0x00, 0x43, 0x00, 0x05, 0x03, 0x04, 0x04, 0x04, 0x03, 0x05, 0x04,
- 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x0c, 0x08, 0x07, 0x07, 0x07,
- 0x07, 0x0f, 0x0b, 0x0b, 0x09, 0x0c, 0x11, 0x0f, 0x12, 0x12, 0x11, 0x0f,
- 0x11, 0x11, 0x13, 0x16, 0x1c, 0x17, 0x13, 0x14, 0x1a, 0x15, 0x11, 0x11,
- 0x18, 0x21, 0x18, 0x1a, 0x1d, 0x1d, 0x1f, 0x1f, 0x1f, 0x13, 0x17, 0x22,
- 0x24, 0x22, 0x1e, 0x24, 0x1c, 0x1e, 0x1f, 0x1e, 0xff, 0xdb, 0x00, 0x43,
- 0x01, 0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x0e, 0x08, 0x08, 0x0e, 0x1e,
- 0x14, 0x11, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
- 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
- 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
- 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
- 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0xff, 0xc0, 0x00, 0x11, 0x08, 0x00, 0x78,
- 0x00, 0xa0, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01,
- 0xff, 0xc4, 0x00, 0x1c, 0x00, 0x00, 0x03, 0x00, 0x03, 0x01, 0x01, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x06, 0x07,
- 0x00, 0x04, 0x08, 0x03, 0x02, 0x01, 0xff, 0xc4, 0x00, 0x40, 0x10, 0x00,
- 0x01, 0x03, 0x02, 0x05, 0x02, 0x04, 0x04, 0x04, 0x03, 0x06, 0x04, 0x07,
- 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x11, 0x00, 0x06, 0x12,
- 0x21, 0x31, 0x07, 0x41, 0x13, 0x22, 0x51, 0x61, 0x14, 0x32, 0x71, 0x81,
- 0x08, 0x42, 0x91, 0xa1, 0x15, 0x16, 0xc1, 0x23, 0x52, 0x62, 0x82, 0xb1,
- 0xe1, 0x24, 0x43, 0x72, 0xf0, 0x17, 0x25, 0x33, 0x92, 0xb2, 0xd1, 0xd2,
- 0xff, 0xc4, 0x00, 0x1c, 0x01, 0x00, 0x03, 0x01, 0x01, 0x00, 0x03, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x06, 0x07,
- 0x04, 0x03, 0x00, 0x02, 0x08, 0x01, 0xff, 0xc4, 0x00, 0x37, 0x11, 0x00,
- 0x01, 0x02, 0x04, 0x04, 0x03, 0x06, 0x04, 0x05, 0x04, 0x03, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x00, 0x04, 0x05, 0x11, 0x06, 0x21,
- 0x31, 0x41, 0x12, 0x51, 0x71, 0x13, 0x22, 0x61, 0x81, 0x91, 0xa1, 0x07,
- 0xb1, 0xc1, 0xf0, 0x14, 0x42, 0xd1, 0xe1, 0xf1, 0x15, 0x24, 0x32, 0x82,
- 0x33, 0x52, 0x72, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11,
- 0x03, 0x11, 0x00, 0x3f, 0x00, 0xb1, 0x31, 0x2c, 0x2d, 0xd8, 0xd2, 0xda,
- 0x43, 0x26, 0x4a, 0x99, 0x1e, 0x15, 0x98, 0x2e, 0x2f, 0x51, 0x49, 0x0b,
- 0x03, 0x70, 0x90, 0x6c, 0x9f, 0x4d, 0xb7, 0xf5, 0xc3, 0x0b, 0x4f, 0x09,
- 0x1f, 0x08, 0xa5, 0x95, 0xb6, 0xb7, 0x50, 0x4e, 0x95, 0xab, 0xe4, 0xbf,
- 0x2a, 0xb1, 0x17, 0xb8, 0xb1, 0xde, 0xdd, 0xf1, 0x34, 0xa1, 0x3b, 0x25,
- 0xb6, 0x5d, 0x67, 0xe2, 0xda, 0x5b, 0xeb, 0x49, 0xf0, 0xd2, 0x83, 0xe1,
- 0xa9, 0x37, 0xbe, 0x91, 0x72, 0xab, 0x5f, 0x73, 0x7f, 0xb6, 0x1d, 0x28,
- 0xf0, 0xdf, 0xf1, 0x9b, 0x05, 0x2e, 0x20, 0x32, 0xd8, 0x64, 0x23, 0x52,
- 0x4a, 0x9c, 0xb7, 0x2b, 0x52, 0x8d, 0xd5, 0xe9, 0xe5, 0xdb, 0x83, 0xea,
- 0x30, 0x09, 0x75, 0x86, 0x25, 0xec, 0x1e, 0x58, 0x4d, 0xf9, 0x90, 0x20,
- 0x87, 0x60, 0x4e, 0x91, 0xb2, 0xc3, 0x72, 0x63, 0xcd, 0x40, 0x76, 0x63,
- 0xd2, 0x5b, 0x4a, 0x75, 0x04, 0x20, 0x06, 0xf9, 0xdb, 0xcd, 0xdc, 0x83,
- 0xe9, 0x6b, 0xec, 0x0d, 0xf1, 0xba, 0x5f, 0x76, 0xe9, 0x50, 0x43, 0x65,
- 0xd9, 0x05, 0x21, 0x08, 0xf2, 0x92, 0x94, 0x05, 0x73, 0x72, 0x48, 0x20,
- 0x5c, 0xaa, 0xf8, 0xf8, 0xa9, 0x34, 0x97, 0xe4, 0x3e, 0xc7, 0xc4, 0x80,
- 0x95, 0x90, 0x90, 0x9d, 0x1a, 0x94, 0x8b, 0xd8, 0x6d, 0xb5, 0x80, 0xef,
- 0xf7, 0xc7, 0xeb, 0x14, 0xb7, 0xdb, 0x79, 0x45, 0x2f, 0xb6, 0x50, 0x55,
- 0x7b, 0x96, 0x86, 0xb4, 0xf1, 0xc2, 0xaf, 0x7e, 0xc3, 0x7c, 0x65, 0x77,
- 0x15, 0x52, 0x98, 0x36, 0x53, 0xc3, 0xca, 0xe7, 0xe5, 0x78, 0xf0, 0xb0,
- 0xb3, 0x99, 0x11, 0xae, 0xa6, 0xd8, 0x91, 0x2c, 0x38, 0x3c, 0x37, 0xb4,
- 0x36, 0xa6, 0x99, 0xd2, 0xb2, 0xb0, 0xda, 0x01, 0x04, 0xea, 0x24, 0x8d,
- 0xcd, 0xb6, 0xfa, 0x63, 0x62, 0x92, 0xdb, 0x2c, 0xb8, 0xcb, 0x29, 0x7d,
- 0x97, 0x94, 0x5b, 0x53, 0xa0, 0x22, 0xfa, 0x02, 0x52, 0x52, 0x35, 0x12,
- 0x2f, 0x71, 0x7b, 0x72, 0x77, 0xe0, 0x63, 0xc2, 0xb9, 0x43, 0xa9, 0x39,
- 0x09, 0xc8, 0xd0, 0x1f, 0x6d, 0x95, 0xbb, 0xa5, 0x7f, 0x10, 0xfa, 0x3c,
- 0x5d, 0xf5, 0x58, 0x24, 0x20, 0x5b, 0x51, 0x3c, 0x58, 0x9b, 0x5a, 0xf7,
- 0xbd, 0xf1, 0x2f, 0xcd, 0x94, 0x9c, 0xff, 0x00, 0x4a, 0x94, 0xe4, 0xba,
- 0x8e, 0x60, 0xa8, 0xba, 0xc0, 0x05, 0x1a, 0xe2, 0x47, 0x09, 0x09, 0x4f,
- 0xa6, 0x94, 0x8b, 0xa7, 0xd8, 0x0f, 0xb6, 0x0a, 0xd3, 0xaa, 0x54, 0xe9,
- 0xe5, 0xa1, 0x29, 0x98, 0x4a, 0x4a, 0xb4, 0x0a, 0xba, 0x6f, 0x9d, 0xb7,
- 0x16, 0xbf, 0x21, 0x7b, 0x9d, 0x84, 0x0d, 0xa8, 0x4c, 0xb9, 0x26, 0xd9,
- 0x73, 0xb2, 0x52, 0xc0, 0xff, 0x00, 0xa8, 0x07, 0xda, 0xf7, 0xeb, 0x95,
- 0x84, 0x55, 0xdb, 0x4c, 0x26, 0xa4, 0x3e, 0xdb, 0x0b, 0x2e, 0xcb, 0x91,
- 0x24, 0xbe, 0xa2, 0x2c, 0x08, 0x52, 0x86, 0xca, 0xb7, 0x17, 0x00, 0x58,
- 0xed, 0x72, 0x0e, 0xf8, 0xf8, 0x7e, 0x6c, 0x28, 0xce, 0x3a, 0xc3, 0x25,
- 0x90, 0x88, 0xc9, 0xd4, 0xe9, 0x71, 0xc0, 0x09, 0x52, 0x85, 0xed, 0xa8,
- 0xf7, 0xbd, 0xff, 0x00, 0x4d, 0x86, 0x39, 0x96, 0xa7, 0xd4, 0x6a, 0x63,
- 0x28, 0x5b, 0x1f, 0xce, 0x33, 0xf5, 0x36, 0x0a, 0x5c, 0x49, 0x75, 0x6b,
- 0x70, 0xab, 0x8b, 0x8b, 0x91, 0x63, 0x6b, 0x6d, 0x6e, 0xd8, 0x00, 0xee,
- 0x76, 0xca, 0xce, 0x27, 0xc6, 0x6a, 0x8b, 0x32, 0x78, 0x69, 0x3f, 0xda,
- 0x3a, 0xa6, 0xca, 0x89, 0xb7, 0x2a, 0x3b, 0x9f, 0x7c, 0x37, 0xff, 0x00,
- 0x41, 0x69, 0x1f, 0xf2, 0xbe, 0x07, 0xa7, 0xd4, 0x88, 0x54, 0x18, 0xaa,
- 0x61, 0xcf, 0xf8, 0xa4, 0xd6, 0x7a, 0xe5, 0xf3, 0x1f, 0xac, 0x75, 0x8c,
- 0x0c, 0xc3, 0x02, 0xa3, 0x50, 0x6a, 0x9c, 0xc5, 0x62, 0x92, 0xe4, 0xa7,
- 0x10, 0xb6, 0xbe, 0x1d, 0xb9, 0x2d, 0xad, 0x00, 0x80, 0x3f, 0x2f, 0xcc,
- 0xb5, 0x0b, 0x1e, 0x2c, 0x07, 0xb9, 0xc7, 0xae, 0x68, 0x96, 0xa4, 0xd2,
- 0xcb, 0x31, 0x25, 0x29, 0x72, 0x00, 0x0d, 0x96, 0xda, 0xec, 0x9b, 0xf7,
- 0xb0, 0xd8, 0xf7, 0xda, 0xc7, 0xb6, 0x21, 0x79, 0x22, 0x3d, 0x1e, 0xbf,
- 0x45, 0x8b, 0x3c, 0xd3, 0x95, 0x11, 0xb9, 0x26, 0xf1, 0x5c, 0x69, 0x65,
- 0xa7, 0x10, 0xa0, 0xe6, 0x84, 0x9d, 0xb7, 0x1e, 0x71, 0x89, 0xac, 0x0a,
- 0x9d, 0x56, 0x8f, 0x38, 0x48, 0x8d, 0x52, 0x9d, 0x0d, 0x65, 0xc2, 0x54,
- 0xeb, 0x2e, 0xa9, 0x0a, 0x55, 0x8d, 0x89, 0xe7, 0x7e, 0xfc, 0xe0, 0x0d,
- 0x79, 0xb6, 0xe9, 0x8a, 0x42, 0x50, 0x4a, 0x82, 0xc6, 0xbf, 0xa4, 0x51,
- 0xbe, 0x1b, 0xc8, 0x2b, 0x18, 0x35, 0x32, 0xe3, 0x87, 0xb2, 0x53, 0x2a,
- 0x09, 0xe1, 0xd6, 0xe4, 0x8b, 0xe6, 0x76, 0xf4, 0x31, 0xd6, 0x31, 0x67,
- 0x66, 0x00, 0xda, 0x90, 0x22, 0xc6, 0x79, 0xb4, 0x20, 0xa1, 0x6f, 0xbc,
- 0x0a, 0x41, 0x09, 0xf3, 0x6b, 0x09, 0x37, 0xb0, 0x36, 0xdc, 0x12, 0x4e,
- 0xd8, 0x11, 0x51, 0x7f, 0xf8, 0xed, 0x5a, 0x1c, 0x88, 0x35, 0x04, 0xa5,
- 0xc8, 0x4d, 0x2d, 0x4d, 0xa9, 0xc8, 0xd6, 0x6b, 0x52, 0x87, 0x99, 0x4a,
- 0xb8, 0xdc, 0x93, 0xc0, 0x06, 0xdc, 0xe2, 0x21, 0x13, 0xa9, 0xd9, 0xb0,
- 0xb1, 0xe1, 0x4a, 0xaf, 0x3a, 0xe9, 0x4a, 0xb5, 0x21, 0x6e, 0xb0, 0x85,
- 0x9f, 0x6b, 0xa8, 0x6f, 0x7f, 0xb6, 0x35, 0xe2, 0xf5, 0x37, 0x37, 0xca,
- 0x7c, 0x35, 0x51, 0xaf, 0xae, 0x13, 0x00, 0xfc, 0xed, 0x46, 0xd7, 0x71,
- 0xfe, 0x22, 0x0d, 0xc7, 0xe8, 0x70, 0x10, 0xcf, 0xb0, 0x53, 0x61, 0x73,
- 0xe9, 0xfa, 0xc3, 0xcc, 0xc6, 0x09, 0x7a, 0x50, 0x15, 0x29, 0x1c, 0x5f,
- 0xf9, 0xb9, 0xfa, 0x67, 0xe5, 0x68, 0xe8, 0x7a, 0x34, 0x17, 0x60, 0x34,
- 0xa0, 0x66, 0x53, 0xdb, 0x53, 0x84, 0xea, 0x5b, 0x67, 0x4d, 0xfd, 0xfc,
- 0xbe, 0xfb, 0xf3, 0xbf, 0xd3, 0x6c, 0x7d, 0x66, 0x87, 0xeb, 0x74, 0xf8,
- 0xb1, 0xe1, 0xd2, 0xc4, 0x35, 0x49, 0x90, 0xcb, 0xae, 0xc3, 0x73, 0x7d,
- 0x3a, 0x90, 0x9b, 0x90, 0x45, 0xed, 0xbd, 0xf6, 0x3c, 0x0e, 0x6d, 0x89,
- 0xa6, 0x46, 0x89, 0x56, 0xac, 0x4b, 0x81, 0x35, 0xac, 0xdc, 0xfd, 0x56,
- 0x31, 0x7d, 0x2a, 0x29, 0x60, 0x0b, 0x25, 0x49, 0x58, 0xd9, 0xc0, 0x07,
- 0x96, 0xe3, 0xb1, 0xb6, 0xd8, 0xac, 0xe7, 0xb4, 0x45, 0x6a, 0xaf, 0x4b,
- 0x43, 0x4a, 0x6d, 0x25, 0xa9, 0x32, 0x11, 0xa1, 0x24, 0x5d, 0x29, 0x53,
- 0x5b, 0x6d, 0xd8, 0x5c, 0x60, 0xad, 0x29, 0x4d, 0xcc, 0x38, 0x3b, 0xb6,
- 0x00, 0x8d, 0x77, 0x85, 0xb9, 0x96, 0x19, 0x49, 0x52, 0x10, 0x9c, 0xc2,
- 0x54, 0x73, 0x1a, 0x10, 0x92, 0x47, 0xbd, 0xa2, 0x1c, 0x9f, 0xfc, 0x40,
- 0x7a, 0x32, 0x5f, 0x97, 0x99, 0x1d, 0x52, 0xdb, 0x36, 0x11, 0x92, 0xe2,
- 0x90, 0xd3, 0x62, 0xdc, 0x0d, 0x24, 0x11, 0xb1, 0xc2, 0xfd, 0x5a, 0x5e,
- 0x60, 0x42, 0x2c, 0xfc, 0x07, 0x18, 0x75, 0x2a, 0xba, 0x26, 0x21, 0xe5,
- 0x3f, 0x63, 0xfd, 0xe4, 0xa9, 0x47, 0xca, 0x46, 0xe3, 0x71, 0xdf, 0x19,
- 0xd6, 0x3a, 0xd5, 0x5e, 0x91, 0x0d, 0x2f, 0xc1, 0x21, 0x94, 0x29, 0xd7,
- 0x2e, 0x15, 0x65, 0x05, 0x5b, 0x4e, 0xe4, 0x7d, 0xf8, 0x38, 0x0b, 0x42,
- 0xea, 0x69, 0x30, 0x9b, 0x6a, 0xb9, 0x4b, 0x43, 0xe1, 0xb0, 0x12, 0x1d,
- 0x8e, 0x7c, 0x32, 0x8f, 0xb7, 0x6f, 0xb6, 0x28, 0xcb, 0x99, 0x92, 0x95,
- 0x74, 0x36, 0xa0, 0x94, 0xa8, 0x8b, 0x8c, 0xac, 0x39, 0x74, 0x88, 0xa6,
- 0x1f, 0xc4, 0x18, 0xbd, 0x12, 0x9f, 0x8e, 0x67, 0x85, 0xe6, 0xd4, 0x4d,
- 0xd2, 0x6d, 0x71, 0x6d, 0x6d, 0x98, 0x3e, 0x40, 0xf9, 0x40, 0xf9, 0x19,
- 0x9a, 0xad, 0xe3, 0x3b, 0x11, 0x6e, 0xca, 0xa9, 0x6b, 0x56, 0x8d, 0x72,
- 0x5c, 0x4a, 0xad, 0x7b, 0x0b, 0x24, 0xe9, 0x3a, 0x71, 0xf7, 0x97, 0xaa,
- 0x19, 0x86, 0x65, 0x52, 0x24, 0x66, 0xe9, 0x0d, 0xb7, 0xe3, 0x38, 0x1b,
- 0x49, 0x44, 0x50, 0xab, 0x82, 0xab, 0x5e, 0xc4, 0x6f, 0x6c, 0x35, 0xb3,
- 0x4b, 0xcb, 0x79, 0x89, 0xe4, 0xce, 0xa6, 0x26, 0x6c, 0x69, 0x5a, 0x82,
- 0x95, 0x29, 0x2b, 0x52, 0x1d, 0x41, 0x3b, 0x8b, 0x91, 0xda, 0xc3, 0x6d,
- 0x88, 0xd8, 0xe1, 0x93, 0x2f, 0xcf, 0xab, 0xe5, 0x7c, 0xc7, 0x4d, 0x46,
- 0x60, 0x97, 0x0e, 0x75, 0x31, 0xe9, 0x08, 0x69, 0x12, 0x8c, 0x60, 0x87,
- 0xda, 0xf4, 0xbe, 0x8b, 0x05, 0x0f, 0xb0, 0x3d, 0xf1, 0x8a, 0x64, 0xd5,
- 0x5a, 0x1c, 0x52, 0xae, 0x24, 0xa0, 0x67, 0x6b, 0x01, 0xfc, 0xfa, 0xc3,
- 0x75, 0x33, 0xe2, 0x63, 0x4f, 0xbc, 0x99, 0x57, 0xd2, 0x59, 0x73, 0x4e,
- 0x12, 0x32, 0xbf, 0xcf, 0xd6, 0x06, 0xf5, 0x01, 0xd9, 0x74, 0xac, 0xba,
- 0xdb, 0x2f, 0x33, 0x1d, 0xba, 0x85, 0x36, 0xae, 0xe4, 0x77, 0x5d, 0x61,
- 0xad, 0x96, 0x0b, 0x63, 0x70, 0x07, 0xfd, 0x37, 0xb6, 0x1f, 0xba, 0x4b,
- 0x5b, 0x95, 0x3f, 0x2b, 0xc1, 0x44, 0xc7, 0x1e, 0x96, 0x02, 0x8d, 0xca,
- 0x9b, 0xb2, 0x94, 0x41, 0x24, 0x12, 0x2f, 0xcd, 0xec, 0x37, 0xe7, 0xdf,
- 0x13, 0xbe, 0xb2, 0x54, 0x4c, 0xba, 0xce, 0x60, 0x5c, 0x25, 0x87, 0xe9,
- 0xee, 0x4a, 0x6e, 0x49, 0xf0, 0xd3, 0x72, 0x95, 0x29, 0x24, 0x03, 0xa8,
- 0x1d, 0xb9, 0x3b, 0x7b, 0x7b, 0x60, 0xef, 0x43, 0x5d, 0x29, 0x88, 0xdb,
- 0x8b, 0x72, 0x33, 0x65, 0x5e, 0x25, 0xee, 0x17, 0x7b, 0x10, 0x05, 0xac,
- 0x0d, 0x89, 0xdb, 0x83, 0x85, 0x8c, 0x5a, 0x78, 0x66, 0x9a, 0x58, 0xdd,
- 0x20, 0x9f, 0x3b, 0x9f, 0xac, 0x3b, 0xd5, 0xdb, 0xb9, 0x4a, 0xd5, 0xa9,
- 0x00, 0xfb, 0x40, 0xac, 0xbf, 0x98, 0xbe, 0x31, 0x9a, 0xab, 0x73, 0x42,
- 0xde, 0x80, 0xc7, 0x87, 0xa9, 0x2b, 0x6c, 0x10, 0xe0, 0x28, 0xbe, 0xe0,
- 0xec, 0x47, 0xa7, 0xfb, 0x62, 0x9b, 0x94, 0x9a, 0xa9, 0xd6, 0x72, 0xa8,
- 0x95, 0x90, 0x33, 0x73, 0x72, 0xd6, 0x86, 0x2e, 0x69, 0x92, 0xbc, 0xcb,
- 0x61, 0x76, 0xf9, 0x52, 0x54, 0x6f, 0xa7, 0xd8, 0x92, 0x3d, 0x14, 0x31,
- 0x03, 0x76, 0x3b, 0x4d, 0xe4, 0xcc, 0xcd, 0x23, 0x58, 0xbb, 0x8d, 0xa2,
- 0xe9, 0x04, 0xd9, 0x20, 0x04, 0x8d, 0xbd, 0x76, 0xc4, 0xf3, 0x2a, 0x55,
- 0x33, 0x44, 0x4c, 0xf6, 0x22, 0xe5, 0x27, 0xa6, 0xae, 0xa2, 0xe4, 0xa0,
- 0x96, 0x44, 0x72, 0x6e, 0x0d, 0x85, 0xcd, 0x87, 0x6b, 0x5e, 0xff, 0x00,
- 0xbe, 0x3d, 0xa6, 0x9a, 0x94, 0x98, 0xa7, 0xcb, 0x4a, 0x4c, 0xb4, 0x16,
- 0x14, 0x9b, 0xe6, 0x01, 0xcf, 0x2d, 0xb5, 0xdf, 0x50, 0x41, 0x89, 0x54,
- 0x8c, 0xa3, 0xc2, 0xa1, 0x3d, 0x50, 0x65, 0xee, 0x12, 0x85, 0x81, 0x62,
- 0x6c, 0x2d, 0x62, 0x49, 0xdc, 0x65, 0x6d, 0xd2, 0x44, 0x5c, 0x1e, 0xcf,
- 0x3d, 0x5a, 0x62, 0xa4, 0xe5, 0x3e, 0xa5, 0x50, 0xa7, 0xd2, 0xdd, 0x49,
- 0xd2, 0x84, 0xbc, 0xd6, 0x95, 0x39, 0xcd, 0x82, 0x6f, 0x7b, 0xf1, 0xce,
- 0xe0, 0x7a, 0xe1, 0x83, 0x20, 0xbf, 0xd4, 0x0a, 0xad, 0x42, 0x4b, 0xd5,
- 0x6c, 0xe0, 0xf1, 0x66, 0x24, 0xe6, 0xee, 0xcb, 0x6d, 0x20, 0x02, 0x9b,
- 0x82, 0x52, 0xab, 0x0f, 0x4d, 0x88, 0xf7, 0xc1, 0x8c, 0xd5, 0x2e, 0x8a,
- 0x7a, 0x5d, 0x4e, 0x8b, 0x5b, 0x8e, 0xd2, 0xab, 0x06, 0xea, 0x50, 0x6d,
- 0x3b, 0xa1, 0xb2, 0xa3, 0xa0, 0x58, 0x7f, 0xcc, 0x50, 0xb5, 0x80, 0xdc,
- 0x83, 0xbe, 0x24, 0xbd, 0x36, 0xcc, 0x33, 0xb2, 0xcd, 0x54, 0x25, 0x42,
- 0x4a, 0x5a, 0x2e, 0x02, 0x96, 0xdc, 0x90, 0x4a, 0x55, 0x7d, 0x89, 0xb7,
- 0x04, 0x81, 0xff, 0x00, 0xd6, 0xf8, 0x54, 0xad, 0xe1, 0x4a, 0x6d, 0x38,
- 0x07, 0x19, 0x69, 0x20, 0x1b, 0xe4, 0x52, 0x2f, 0x96, 0xe0, 0xf2, 0x3b,
- 0x7d, 0x61, 0xaf, 0x0d, 0x62, 0x79, 0x8a, 0xb0, 0x52, 0x1c, 0x02, 0xe9,
- 0x09, 0xcc, 0x68, 0x4a, 0x85, 0xed, 0xa7, 0xf9, 0x0d, 0xc7, 0x8e, 0xd1,
- 0xd8, 0x64, 0xff, 0x00, 0xc5, 0xb4, 0xd3, 0x68, 0x05, 0x28, 0x0a, 0x5a,
- 0x92, 0x4f, 0xe5, 0x4b, 0x97, 0xb7, 0xe8, 0x71, 0x1a, 0xab, 0xfe, 0x21,
- 0x29, 0xd4, 0x7e, 0xa5, 0xce, 0xca, 0x35, 0xea, 0x64, 0x91, 0x09, 0x01,
- 0x05, 0x12, 0xda, 0x40, 0x50, 0x4e, 0xa1, 0xdd, 0x3c, 0xd8, 0x7a, 0xef,
- 0x8a, 0xc5, 0x36, 0xa9, 0x0e, 0x44, 0x84, 0xe8, 0x73, 0xfb, 0x59, 0x2c,
- 0x29, 0x4d, 0xa7, 0xbf, 0x65, 0x7f, 0xa1, 0xc7, 0x13, 0xf5, 0x06, 0x9b,
- 0x52, 0xac, 0xfe, 0x20, 0x6a, 0x90, 0x20, 0x45, 0x91, 0x2a, 0x5b, 0x8b,
- 0x6d, 0xb6, 0x19, 0x6c, 0x5d, 0x4b, 0xb2, 0x78, 0x1f, 0xbe, 0xfc, 0x0c,
- 0x21, 0x61, 0xb9, 0x66, 0xa7, 0xdb, 0xb3, 0xa7, 0x44, 0x2b, 0x43, 0x6b,
- 0x10, 0xb4, 0x81, 0xec, 0x77, 0xb8, 0xcc, 0xc1, 0xa7, 0xf8, 0x99, 0x48,
- 0x36, 0xce, 0xe0, 0x67, 0xc8, 0x85, 0x1f, 0xa6, 0xa2, 0x3a, 0x3b, 0x33,
- 0xe4, 0x8c, 0x85, 0xd4, 0x46, 0xda, 0xae, 0x52, 0xc4, 0x07, 0x64, 0x2e,
- 0xc0, 0x49, 0x61, 0x00, 0x2b, 0xe8, 0xbb, 0x6f, 0xbe, 0x14, 0xab, 0xb9,
- 0x30, 0x50, 0x22, 0xff, 0x00, 0x0f, 0xfe, 0x13, 0x18, 0x7c, 0x72, 0x96,
- 0xc0, 0x90, 0x41, 0x29, 0x41, 0x50, 0xb0, 0xbf, 0x1e, 0x5e, 0x76, 0xdb,
- 0xdc, 0xfa, 0xb5, 0xf4, 0xeb, 0x24, 0x53, 0x7a, 0x71, 0x45, 0x7a, 0xa1,
- 0x5b, 0xa8, 0x32, 0x89, 0xd3, 0x96, 0xda, 0xa5, 0x25, 0xb5, 0xf9, 0x1b,
- 0x08, 0x3a, 0x92, 0x80, 0x7f, 0x32, 0xb5, 0x5a, 0xea, 0xf6, 0xb0, 0xbe,
- 0x06, 0x75, 0x3e, 0xa9, 0x5a, 0xce, 0x51, 0xa1, 0xc3, 0xa7, 0xb0, 0x61,
- 0xc5, 0x5c, 0x80, 0x59, 0x52, 0x8d, 0x9c, 0x58, 0x48, 0x24, 0x1b, 0x7e,
- 0x54, 0xef, 0xdf, 0x72, 0x71, 0xda, 0x98, 0xf4, 0xe8, 0x9f, 0xec, 0xa5,
- 0x9d, 0x2e, 0x32, 0x35, 0xb8, 0xc8, 0x78, 0x03, 0xe9, 0xa6, 0xa7, 0x6b,
- 0x46, 0x87, 0xc3, 0x45, 0xae, 0x35, 0xa4, 0x5f, 0x9e, 0xff, 0x00, 0xbf,
- 0xa6, 0x9b, 0xc2, 0xfc, 0xa9, 0xf1, 0x13, 0x97, 0xbc, 0x4a, 0x32, 0x2e,
- 0xd4, 0x0b, 0xb4, 0xa0, 0x11, 0xa7, 0xcc, 0xd3, 0x89, 0x52, 0x94, 0x94,
- 0x8b, 0x00, 0x2f, 0x72, 0x3d, 0xb1, 0x36, 0xeb, 0x1c, 0x07, 0x28, 0xd3,
- 0x6b, 0xb4, 0xc9, 0x4e, 0x15, 0x25, 0x82, 0xb5, 0x31, 0xa4, 0xdd, 0x29,
- 0x4a, 0x9c, 0x43, 0xa9, 0x23, 0xfc, 0xaa, 0xfd, 0xf1, 0xbb, 0x2e, 0x55,
- 0x6a, 0x87, 0x1a, 0xbc, 0x89, 0x20, 0x29, 0x69, 0x63, 0x5a, 0x52, 0xb0,
- 0x6c, 0x51, 0xa1, 0x40, 0xf1, 0xea, 0x06, 0x06, 0x67, 0xc9, 0x92, 0x33,
- 0x14, 0x36, 0xe4, 0xcb, 0x5f, 0x8a, 0xec, 0x9a, 0x6c, 0x7b, 0xab, 0x48,
- 0x04, 0xff, 0x00, 0x62, 0x11, 0xfb, 0x14, 0xe2, 0xb3, 0x88, 0x78, 0x7f,
- 0x01, 0x26, 0xb3, 0xa8, 0x03, 0xe9, 0xfa, 0x46, 0x4f, 0x85, 0x0c, 0x3c,
- 0xa9, 0xba, 0xd4, 0xba, 0x45, 0xc2, 0xc5, 0xc5, 0xb5, 0xe2, 0xb1, 0xb7,
- 0xce, 0xde, 0x71, 0x36, 0xa6, 0x4b, 0xaa, 0xbf, 0x20, 0x98, 0xaf, 0x68,
- 0x69, 0xb4, 0xdf, 0x4d, 0xb6, 0xb0, 0xf6, 0xe4, 0x93, 0x87, 0x95, 0xaa,
- 0x38, 0xa5, 0x44, 0x4a, 0x81, 0xf8, 0xd4, 0xeb, 0x32, 0x1d, 0x1b, 0x21,
- 0x49, 0x36, 0x29, 0xb0, 0xf5, 0x1b, 0xdc, 0xfd, 0x30, 0x0f, 0x2d, 0xd1,
- 0xd3, 0x0d, 0xa6, 0xde, 0xa8, 0xb8, 0x12, 0xb0, 0x2f, 0x60, 0x0a, 0x83,
- 0x7b, 0x6f, 0x6b, 0x72, 0xac, 0x36, 0xd2, 0xa8, 0x46, 0xbb, 0x1e, 0x4c,
- 0xa8, 0x92, 0x22, 0xa0, 0x34, 0xc9, 0x71, 0xa6, 0x0b, 0xa1, 0x4a, 0x3d,
- 0xbc, 0xd6, 0x3b, 0x2b, 0x93, 0x7e, 0x01, 0xdb, 0x9c, 0x28, 0x4c, 0xad,
- 0x2e, 0x2a, 0xc8, 0x02, 0xdc, 0xe2, 0xc1, 0x46, 0x2f, 0x50, 0x25, 0x7f,
- 0x11, 0x50, 0x75, 0x5c, 0x4a, 0xff, 0x00, 0x16, 0xef, 0xa7, 0x5b, 0xe9,
- 0xd3, 0x6d, 0xf3, 0xc8, 0x6e, 0xf4, 0xff, 0x00, 0x3d, 0x4c, 0xca, 0xf9,
- 0x88, 0x7c, 0x2c, 0x1d, 0x46, 0x63, 0x29, 0x6c, 0xa4, 0x27, 0x40, 0xb2,
- 0x38, 0x59, 0xf5, 0x27, 0x7f, 0xd7, 0x1d, 0x08, 0xce, 0x65, 0x6e, 0xa7,
- 0x54, 0xa7, 0x4f, 0xac, 0xa6, 0x3c, 0x79, 0x29, 0x7e, 0x13, 0xc8, 0x49,
- 0x50, 0x05, 0x45, 0xd0, 0xa4, 0xad, 0x36, 0xfc, 0xdc, 0x03, 0x8e, 0x7d,
- 0x32, 0xa0, 0x57, 0xa9, 0x52, 0x6a, 0xeb, 0x52, 0x19, 0xaa, 0x46, 0x8a,
- 0x52, 0x96, 0xb4, 0x24, 0x2d, 0xc2, 0x15, 0xdf, 0xe8, 0x07, 0x1c, 0x91,
- 0xfa, 0x63, 0xa0, 0xf3, 0x25, 0x39, 0x0e, 0x51, 0x29, 0x12, 0xc2, 0x59,
- 0xb3, 0x52, 0x60, 0x91, 0x74, 0x0b, 0xdb, 0xc3, 0x3d, 0xff, 0x00, 0x4c,
- 0x14, 0xa5, 0x29, 0x69, 0x70, 0x24, 0x69, 0xcb, 0xce, 0x13, 0xa6, 0xa7,
- 0x45, 0x49, 0xf7, 0x5d, 0x75, 0x20, 0x29, 0x79, 0x65, 0xb0, 0xd2, 0xde,
- 0x62, 0x21, 0xff, 0x00, 0x88, 0xf6, 0x9b, 0xa9, 0x52, 0x2a, 0xb2, 0xa1,
- 0x21, 0x6d, 0x21, 0x55, 0x37, 0x96, 0xce, 0xa1, 0xa4, 0xe8, 0x52, 0xc1,
- 0xbe, 0x9e, 0xc2, 0xd7, 0xdb, 0x12, 0x9e, 0x9c, 0xd2, 0xe6, 0xd5, 0x5f,
- 0x31, 0xe1, 0x34, 0xeb, 0xce, 0xa9, 0x77, 0x5a, 0x95, 0xe6, 0x48, 0x48,
- 0x16, 0x25, 0x46, 0xf6, 0x03, 0x91, 0x8b, 0xa6, 0x64, 0xa0, 0x53, 0xb3,
- 0x35, 0x3e, 0x43, 0x55, 0x17, 0x8b, 0x4d, 0x25, 0xe2, 0xe2, 0x8a, 0x57,
- 0xa7, 0x6b, 0x9b, 0x8b, 0x8c, 0x20, 0x55, 0xf3, 0xad, 0x03, 0x2c, 0x43,
- 0x5e, 0x5a, 0xca, 0x8c, 0xc6, 0x6e, 0xc7, 0x77, 0xd1, 0x65, 0x24, 0x2b,
- 0xde, 0xff, 0x00, 0x3e, 0x29, 0x53, 0xb4, 0xa6, 0x9e, 0x71, 0x2f, 0xbc,
- 0xab, 0x21, 0x09, 0x00, 0xff, 0x00, 0x3f, 0x66, 0x3e, 0x6d, 0xa0, 0xe2,
- 0x09, 0xa6, 0xd8, 0x5c, 0x8c, 0x8b, 0x65, 0x4f, 0x95, 0xa8, 0xdf, 0xf2,
- 0xa4, 0x13, 0xaf, 0xcf, 0x28, 0x6c, 0x8e, 0xec, 0x2c, 0xa7, 0x0d, 0x98,
- 0xad, 0x3d, 0xfc, 0x46, 0xa5, 0x21, 0x21, 0xa4, 0x45, 0x8e, 0x92, 0x55,
- 0xb7, 0x01, 0x29, 0xf4, 0xdc, 0xf9, 0x8f, 0xfa, 0x63, 0xe2, 0xa1, 0x42,
- 0xcc, 0xf5, 0x67, 0x04, 0xfa, 0xac, 0x96, 0xd8, 0x75, 0x2b, 0x40, 0x6a,
- 0x1b, 0x67, 0x59, 0x66, 0xff, 0x00, 0x4f, 0x99, 0x7f, 0xb0, 0xf7, 0xc0,
- 0x8c, 0x9b, 0x51, 0xa7, 0x46, 0xa6, 0xaa, 0x5c, 0xe9, 0xaf, 0x3d, 0x52,
- 0x99, 0xaf, 0xc5, 0x74, 0x2e, 0xca, 0x52, 0x38, 0xb1, 0x3f, 0x30, 0x16,
- 0xbe, 0xc2, 0xc3, 0x7c, 0x51, 0x1e, 0xcd, 0xd4, 0xc5, 0x25, 0xa8, 0xca,
- 0x9d, 0x09, 0x98, 0xcd, 0xa5, 0xb6, 0x8a, 0x84, 0x93, 0xad, 0x56, 0x1c,
- 0x9b, 0x26, 0xfe, 0xbb, 0x8e, 0x6f, 0x85, 0xaa, 0x96, 0x21, 0x2a, 0x4f,
- 0xe1, 0xa4, 0xc7, 0x0a, 0x34, 0xbe, 0xe7, 0xa7, 0x21, 0xef, 0x0e, 0x94,
- 0x6c, 0x22, 0xdc, 0xab, 0x9f, 0x8d, 0x9d, 0x3d, 0xac, 0xc1, 0xcc, 0x93,
- 0x98, 0x1d, 0x07, 0x84, 0x44, 0x73, 0x33, 0xd3, 0xe9, 0x30, 0x26, 0x95,
- 0xbb, 0xe3, 0x04, 0xb6, 0x94, 0x3e, 0x82, 0x2d, 0x72, 0x97, 0x08, 0xbe,
- 0xde, 0x84, 0x1c, 0x51, 0xba, 0x0d, 0x3d, 0x72, 0x29, 0x25, 0x6c, 0x48,
- 0x5b, 0x5a, 0x96, 0x97, 0x2e, 0xa2, 0x12, 0x1b, 0x00, 0x8b, 0xf3, 0x7b,
- 0xdf, 0xb6, 0x17, 0xb3, 0x4c, 0x5a, 0x6d, 0x43, 0x2d, 0x66, 0x37, 0x20,
- 0xba, 0x99, 0x29, 0x44, 0x67, 0x9c, 0x2e, 0x24, 0x6c, 0x56, 0x97, 0x8a,
- 0xbf, 0xf8, 0xd8, 0xfd, 0xf1, 0xf5, 0xf8, 0x7d, 0x6c, 0x38, 0x66, 0x43,
- 0x4a, 0x1d, 0xf0, 0x8b, 0xc1, 0xd0, 0x7c, 0x3b, 0xa5, 0x28, 0xd3, 0x7b,
- 0x0b, 0x5f, 0xbe, 0xd6, 0x27, 0x1e, 0x63, 0x04, 0x36, 0x4b, 0x2e, 0xb7,
- 0xba, 0x47, 0xb4, 0x3e, 0xcf, 0xa5, 0x60, 0xa0, 0xab, 0x74, 0x88, 0x1f,
- 0x4d, 0x6a, 0x75, 0x5a, 0x85, 0x98, 0xe0, 0xb0, 0x94, 0x95, 0x49, 0x75,
- 0xb6, 0xc0, 0xe6, 0xc0, 0x5a, 0xdb, 0xfa, 0x5b, 0x9c, 0x13, 0xc9, 0xf5,
- 0xea, 0x5f, 0x4b, 0xa2, 0x4c, 0xa8, 0xc4, 0x9e, 0xc2, 0x6b, 0x13, 0x9b,
- 0x51, 0x54, 0x94, 0xb4, 0x16, 0xea, 0x49, 0x04, 0x14, 0xb6, 0x54, 0x3c,
- 0xa9, 0x17, 0xed, 0xb9, 0x3e, 0x98, 0x0f, 0x42, 0x62, 0xa9, 0x22, 0x74,
- 0xb8, 0x14, 0xe9, 0x11, 0x23, 0xc7, 0x92, 0xe0, 0x52, 0xca, 0x95, 0xa0,
- 0x71, 0x62, 0x9d, 0x86, 0xff, 0x00, 0x41, 0x6b, 0xf0, 0x4e, 0x08, 0x37,
- 0xd1, 0x25, 0x57, 0x67, 0x99, 0x55, 0x4c, 0xd8, 0xb5, 0xb8, 0xad, 0x92,
- 0x94, 0x37, 0xa7, 0x48, 0xec, 0x07, 0x60, 0x31, 0x96, 0x6b, 0x15, 0x52,
- 0x29, 0xf2, 0xad, 0x05, 0xaa, 0xee, 0x84, 0x81, 0xa1, 0x36, 0xc8, 0x5e,
- 0xff, 0x00, 0x7e, 0xd1, 0x3c, 0x6b, 0x0b, 0x55, 0xa7, 0x66, 0x5e, 0xba,
- 0xb8, 0x18, 0x52, 0xf8, 0xb2, 0x20, 0x15, 0x1d, 0xb3, 0xfb, 0xf3, 0x3a,
- 0x0a, 0x8d, 0x2e, 0xa1, 0x99, 0xd9, 0x12, 0x98, 0xab, 0x13, 0x50, 0x64,
- 0x87, 0x9b, 0xf1, 0x1c, 0xb0, 0x48, 0xd4, 0x76, 0x1f, 0xdd, 0x1e, 0xa7,
- 0xe8, 0x37, 0xbe, 0x1b, 0xe9, 0x35, 0x68, 0x53, 0x99, 0x55, 0x32, 0x7c,
- 0x66, 0x51, 0x53, 0x41, 0x0e, 0x3c, 0xeb, 0x29, 0x1e, 0x1b, 0x8d, 0x95,
- 0x69, 0x0b, 0xd8, 0xec, 0x49, 0x3f, 0x4d, 0xb0, 0x73, 0x2e, 0xf4, 0x5f,
- 0x24, 0xd0, 0x90, 0xbf, 0x8e, 0xcd, 0x32, 0x8b, 0x65, 0x43, 0xc4, 0x02,
- 0x62, 0x12, 0x92, 0x47, 0xaf, 0x9a, 0xe7, 0xe9, 0x86, 0x58, 0x39, 0x6b,
- 0xa3, 0x14, 0x79, 0xc9, 0x9a, 0xe5, 0x4a, 0x13, 0xb2, 0xda, 0x01, 0x21,
- 0xc7, 0x65, 0xeb, 0xb0, 0x1c, 0x6c, 0x4e, 0x9b, 0x62, 0x73, 0x52, 0xc5,
- 0xcd, 0x4d, 0x3a, 0x57, 0xc2, 0xb5, 0x93, 0xc9, 0x3f, 0xc6, 0x50, 0xf7,
- 0x23, 0x4e, 0x44, 0xab, 0x61, 0xb6, 0x80, 0x00, 0x6c, 0x9f, 0xd8, 0x6b,
- 0xce, 0x1b, 0x24, 0x43, 0x99, 0x1a, 0x65, 0x00, 0x38, 0xb5, 0x29, 0x25,
- 0xa5, 0xb4, 0xbb, 0x7a, 0xea, 0x40, 0xfe, 0x98, 0xf0, 0xae, 0xcd, 0xc9,
- 0x3d, 0x32, 0x7a, 0xa7, 0x99, 0x24, 0x31, 0x09, 0x35, 0x49, 0x48, 0x4a,
- 0x65, 0xc9, 0x2b, 0x25, 0xd2, 0x81, 0xc2, 0x4a, 0xbf, 0x28, 0x3f, 0xdc,
- 0x4e, 0xe4, 0xf3, 0x7c, 0x22, 0x75, 0xaf, 0xad, 0x59, 0x7e, 0x9b, 0x0e,
- 0x9f, 0x13, 0x2c, 0x4c, 0x6e, 0x6c, 0xf2, 0xfa, 0x34, 0xe8, 0x21, 0xd0,
- 0x11, 0xbe, 0xa2, 0x42, 0x4d, 0xf7, 0xd8, 0x0e, 0x09, 0x3c, 0x71, 0x88,
- 0xd6, 0x70, 0xcd, 0x31, 0xf3, 0x25, 0x41, 0x2e, 0xd5, 0x68, 0x95, 0x29,
- 0xe9, 0x4a, 0x8a, 0xc3, 0x0b, 0x49, 0x4a, 0x50, 0xa3, 0xed, 0xdc, 0xf6,
- 0xb9, 0xdf, 0x18, 0xf0, 0xa6, 0x0d, 0xa8, 0x55, 0x07, 0x6a, 0xb5, 0x76,
- 0x4d, 0xd8, 0x85, 0x0c, 0xee, 0x41, 0x37, 0xb5, 0xad, 0xa1, 0xf1, 0xcb,
- 0x2d, 0xe3, 0xde, 0xa9, 0x5b, 0x6a, 0x59, 0x09, 0x41, 0x69, 0x4e, 0x2f,
- 0x50, 0x00, 0x16, 0xbe, 0xd7, 0x37, 0xca, 0xc3, 0x61, 0x99, 0xbe, 0xd0,
- 0xe3, 0x37, 0xac, 0xc9, 0xcd, 0xb9, 0x8d, 0x72, 0x65, 0xca, 0x8d, 0x1a,
- 0x9f, 0x1d, 0xc0, 0x98, 0xa8, 0x20, 0x0d, 0x42, 0xe4, 0x03, 0x63, 0xb8,
- 0x16, 0x37, 0xb7, 0x3f, 0xd0, 0x3d, 0x2b, 0xa9, 0x52, 0xa8, 0xb5, 0x1b,
- 0xc2, 0x9e, 0xa9, 0x3e, 0x0a, 0xac, 0xea, 0x96, 0x92, 0xef, 0x8e, 0x02,
- 0x48, 0xb6, 0xc3, 0x6d, 0xcf, 0x3e, 0xc3, 0x1e, 0x39, 0x2a, 0x3c, 0x19,
- 0xad, 0x95, 0x46, 0xc8, 0xae, 0xb0, 0x11, 0x75, 0x17, 0x9d, 0x6d, 0x94,
- 0x22, 0xd7, 0xb5, 0xb5, 0x38, 0x40, 0xf6, 0xe4, 0x9f, 0x6c, 0x13, 0x55,
- 0x4e, 0xbe, 0x89, 0x0e, 0xb1, 0x0b, 0x25, 0x25, 0xf0, 0xcb, 0xab, 0x6c,
- 0x3a, 0xd8, 0x6d, 0x68, 0x5d, 0xb7, 0xd8, 0xa4, 0xd8, 0xd8, 0x11, 0x72,
- 0x0d, 0xb1, 0x5d, 0x63, 0x05, 0xca, 0xa1, 0x29, 0x42, 0x5c, 0xb0, 0x1a,
- 0x00, 0x3f, 0x7b, 0xf9, 0x98, 0x4a, 0xfe, 0xb9, 0x5b, 0x71, 0xc2, 0x96,
- 0xa4, 0x14, 0xa2, 0x79, 0xe5, 0x97, 0x90, 0xb5, 0xba, 0x46, 0xf3, 0x75,
- 0x37, 0x73, 0x65, 0x1e, 0xb1, 0x53, 0x96, 0xd2, 0x51, 0x25, 0xe8, 0x2a,
- 0x43, 0x89, 0x4b, 0x6a, 0x4e, 0xe1, 0xb2, 0x01, 0x37, 0xee, 0x7f, 0x7b,
- 0x13, 0x8d, 0x2a, 0xad, 0x06, 0xac, 0xed, 0x0f, 0x2f, 0xcd, 0x85, 0x49,
- 0x95, 0x22, 0x3b, 0xb4, 0xb6, 0x42, 0x5c, 0x61, 0xa5, 0x2c, 0x13, 0xa4,
- 0x13, 0x7b, 0x0d, 0x8d, 0xcf, 0x7c, 0x7d, 0x48, 0x77, 0xa8, 0xd2, 0xe9,
- 0xef, 0xf8, 0x39, 0x6d, 0x2c, 0xc7, 0x28, 0x50, 0x71, 0x20, 0x04, 0xdd,
- 0x36, 0xdc, 0x12, 0x2e, 0x78, 0xf4, 0xdf, 0x1e, 0x1d, 0x31, 0xce, 0x99,
- 0xaa, 0x9b, 0x96, 0xc5, 0x39, 0xfa, 0xb5, 0x3a, 0x0e, 0x95, 0xa9, 0xa6,
- 0x93, 0xf1, 0x0a, 0x42, 0x96, 0x80, 0x4d, 0xb5, 0x24, 0x0b, 0x0b, 0x5e,
- 0xc0, 0x92, 0x36, 0x03, 0x1a, 0xeb, 0xf4, 0xd0, 0xe4, 0xa3, 0x52, 0xa8,
- 0x24, 0xf0, 0xee, 0x6c, 0x32, 0x1c, 0xc9, 0xb0, 0x83, 0x38, 0x0e, 0x7a,
- 0xa5, 0x86, 0x2a, 0x53, 0x35, 0x2a, 0x8b, 0x25, 0x01, 0xdd, 0x12, 0x02,
- 0x95, 0x9f, 0x44, 0x82, 0x72, 0x19, 0xe9, 0x68, 0x13, 0x23, 0x20, 0x67,
- 0x9a, 0xa2, 0xd2, 0x5a, 0xa5, 0xaa, 0x24, 0x72, 0x6c, 0x16, 0xf1, 0xd3,
- 0x72, 0x76, 0x16, 0xc3, 0x36, 0x42, 0xe9, 0x8e, 0x68, 0xa5, 0x3a, 0xec,
- 0x31, 0x5e, 0xa2, 0x35, 0x2a, 0x45, 0x99, 0x0d, 0xf8, 0xda, 0x9c, 0x4a,
- 0xb7, 0x16, 0x00, 0x7e, 0x6d, 0xef, 0xf5, 0x03, 0x04, 0x17, 0x54, 0xcc,
- 0x09, 0x74, 0x3e, 0xac, 0xcd, 0x1d, 0x85, 0x83, 0xa8, 0x29, 0x0b, 0x2a,
- 0x50, 0xf7, 0x1e, 0x71, 0x8d, 0x79, 0xf9, 0x8e, 0xb7, 0xf0, 0x4e, 0xd3,
- 0x0e, 0x64, 0x68, 0xb6, 0xe5, 0xd0, 0xa9, 0xa1, 0xd8, 0xed, 0xad, 0x77,
- 0x37, 0x2a, 0xb6, 0x92, 0xb2, 0x77, 0x3c, 0xaa, 0xfe, 0xf8, 0x0a, 0xde,
- 0x16, 0x9c, 0x29, 0xe0, 0x20, 0x01, 0xd4, 0x7d, 0x2f, 0x05, 0x2a, 0xbf,
- 0x13, 0xe8, 0x73, 0x93, 0x05, 0xd2, 0x54, 0xe2, 0x8f, 0x81, 0x00, 0x0f,
- 0x00, 0x48, 0x19, 0x72, 0xd4, 0xc1, 0x8c, 0xbf, 0xd0, 0xc9, 0x10, 0xa5,
- 0x2e, 0x54, 0x9c, 0xe1, 0x19, 0x84, 0xa9, 0x65, 0x4a, 0x07, 0x65, 0x13,
- 0xde, 0xfa, 0xad, 0x7d, 0xfd, 0x71, 0x4a, 0xcf, 0x79, 0x96, 0x83, 0x46,
- 0xca, 0xb1, 0x62, 0xbb, 0x5c, 0x8b, 0x29, 0xf8, 0xcf, 0x32, 0xe2, 0xfc,
- 0x35, 0x02, 0x43, 0x6d, 0x24, 0xdd, 0x4a, 0xb6, 0xc3, 0xf2, 0x8d, 0xf9,
- 0x27, 0x10, 0x77, 0x17, 0x45, 0xf1, 0x94, 0x26, 0x66, 0xb9, 0x4f, 0xac,
- 0x9e, 0x4a, 0x91, 0x73, 0xf7, 0xb1, 0xc7, 0xb5, 0x7b, 0x2a, 0x51, 0x6a,
- 0x79, 0x3e, 0x5c, 0xc8, 0x95, 0x19, 0xcf, 0xa9, 0xa4, 0xeb, 0xb2, 0x9f,
- 0x51, 0x06, 0xde, 0xa3, 0x83, 0x82, 0xac, 0xe1, 0xa9, 0x86, 0x7b, 0xe9,
- 0x29, 0xe2, 0xea, 0x4f, 0xd2, 0x03, 0x2f, 0xe2, 0x75, 0x19, 0xa7, 0x12,
- 0x7b, 0x27, 0x2d, 0x71, 0x6e, 0xe8, 0x02, 0xfb, 0x5c, 0xdc, 0x9b, 0x40,
- 0x2c, 0xcf, 0x57, 0xa5, 0xc9, 0x6e, 0x75, 0x35, 0x55, 0xa5, 0xb1, 0x19,
- 0xc7, 0x54, 0x7c, 0x26, 0x93, 0x7b, 0x79, 0x89, 0xb0, 0x3b, 0x6d, 0x85,
- 0x08, 0xd4, 0x6c, 0xa4, 0xf4, 0x84, 0x80, 0x9a, 0x9c, 0x85, 0x13, 0x62,
- 0xb2, 0xda, 0x95, 0xfa, 0x01, 0x8e, 0x87, 0x43, 0xf1, 0x29, 0x61, 0x8a,
- 0x76, 0x5c, 0xc9, 0xf4, 0x09, 0x50, 0x62, 0x46, 0x6c, 0x27, 0xc6, 0x6c,
- 0xba, 0xe3, 0xde, 0x51, 0xa9, 0x45, 0x77, 0xe4, 0x9b, 0xf0, 0x0f, 0xdf,
- 0x18, 0xff, 0x00, 0x54, 0x59, 0xa4, 0x7f, 0x66, 0x3a, 0x74, 0xc4, 0x37,
- 0x00, 0xf9, 0xda, 0x4a, 0x54, 0x01, 0xf6, 0xf2, 0x7f, 0xa8, 0x18, 0x2d,
- 0x3f, 0x3d, 0x34, 0x5b, 0x4a, 0x9e, 0x65, 0x27, 0xc8, 0x9b, 0x75, 0x17,
- 0xfa, 0x43, 0xf4, 0xae, 0x1a, 0x69, 0x94, 0x87, 0x99, 0x96, 0x48, 0x0b,
- 0xef, 0x1b, 0x01, 0xbe, 0xe7, 0x33, 0x6f, 0x41, 0x12, 0x68, 0xb9, 0x4d,
- 0x86, 0x23, 0x7c, 0x44, 0x6a, 0x0d, 0x5a, 0x53, 0x62, 0xca, 0xf2, 0xc5,
- 0x74, 0x5c, 0x7d, 0x54, 0x9b, 0x71, 0xef, 0x82, 0xf0, 0x32, 0x95, 0x69,
- 0x6f, 0x29, 0x11, 0xb2, 0x24, 0x97, 0xd2, 0x4d, 0xd2, 0x5f, 0x6c, 0xa4,
- 0xe9, 0x3c, 0x5c, 0x0b, 0x8c, 0x33, 0x2b, 0xac, 0x14, 0x79, 0x95, 0x37,
- 0x6a, 0x2b, 0xca, 0x2e, 0xbb, 0x31, 0x0b, 0x4b, 0x8a, 0x2a, 0x71, 0xd2,
- 0x02, 0xbb, 0x10, 0x92, 0x42, 0x47, 0x1c, 0x01, 0x82, 0x8b, 0xeb, 0x4e,
- 0x66, 0x76, 0x58, 0x71, 0x14, 0xe9, 0x11, 0x12, 0xf0, 0xd4, 0x35, 0x35,
- 0x74, 0xda, 0xc3, 0x72, 0x49, 0x36, 0xda, 0xdc, 0xe1, 0x69, 0x58, 0x8d,
- 0x6d, 0x9e, 0xe8, 0x48, 0xe8, 0x91, 0x1d, 0x84, 0xc2, 0x19, 0x3c, 0x29,
- 0x09, 0x1e, 0x9f, 0x40, 0x60, 0x2b, 0x99, 0x1f, 0xa9, 0x12, 0x68, 0x52,
- 0xa0, 0xc4, 0xa0, 0xc3, 0xa7, 0x46, 0x76, 0x3a, 0xdb, 0x5a, 0x02, 0x14,
- 0x14, 0xa4, 0x11, 0xba, 0x45, 0xc5, 0x85, 0xfd, 0x70, 0x13, 0xa5, 0xd9,
- 0x39, 0xd8, 0xcb, 0xf0, 0x5a, 0x9d, 0x32, 0x9a, 0xea, 0xd6, 0x59, 0x90,
- 0x1a, 0x59, 0x2a, 0x4a, 0xfd, 0x2c, 0x38, 0xb5, 0xb1, 0xd1, 0x7d, 0x1c,
- 0xcd, 0x33, 0xb3, 0x35, 0x0d, 0xea, 0x9c, 0x97, 0x94, 0xb2, 0xd4, 0xa2,
- 0xc3, 0x8d, 0xad, 0x20, 0x8b, 0x69, 0x06, 0xe0, 0x81, 0xf5, 0x18, 0x8b,
- 0xe7, 0x5f, 0x8a, 0xa4, 0x75, 0x36, 0xac, 0x23, 0xad, 0x49, 0x40, 0x9e,
- 0x56, 0x50, 0xa2, 0x40, 0x20, 0x80, 0x47, 0x18, 0x15, 0x58, 0x9f, 0x76,
- 0x71, 0xa4, 0xba, 0xb5, 0x5c, 0x79, 0x0f, 0xbd, 0x20, 0x7c, 0xea, 0xbf,
- 0x11, 0x72, 0x75, 0x1f, 0x28, 0x97, 0x3a, 0xc5, 0x52, 0xb5, 0x29, 0x70,
- 0x68, 0xb2, 0xdc, 0x8f, 0x31, 0x0d, 0x97, 0x95, 0xe1, 0x91, 0x7d, 0xd4,
- 0x76, 0xbd, 0xf6, 0xb5, 0xb9, 0xde, 0xfb, 0x61, 0x36, 0xb9, 0xfc, 0xcf,
- 0x47, 0x7c, 0xb5, 0x57, 0x7e, 0xb3, 0xc6, 0xea, 0x4c, 0x85, 0x14, 0x1f,
- 0xdf, 0x0d, 0x9d, 0x3b, 0x8f, 0x36, 0x99, 0x9b, 0xeb, 0x4b, 0x1a, 0x89,
- 0x6a, 0x31, 0xb1, 0x4f, 0x3a, 0x49, 0x2b, 0xb8, 0x27, 0xd8, 0x7e, 0xa7,
- 0x1e, 0x39, 0x6b, 0xa9, 0x5f, 0x1c, 0xfb, 0xb1, 0x6b, 0xd1, 0x14, 0xe2,
- 0x5c, 0x73, 0x50, 0x79, 0xb4, 0xa5, 0x6a, 0x48, 0x1c, 0x02, 0x95, 0x6c,
- 0xa0, 0x2f, 0xc6, 0x1b, 0xa9, 0x32, 0xf2, 0x32, 0xf2, 0x4d, 0xad, 0x49,
- 0x4f, 0x12, 0xaf, 0x9a, 0x80, 0x39, 0xf9, 0xe9, 0x12, 0x49, 0xfa, 0xa5,
- 0x4c, 0x4f, 0xbc, 0x86, 0x87, 0x1b, 0x68, 0xb6, 0x40, 0xd8, 0x8b, 0xf2,
- 0x84, 0x96, 0xaa, 0xce, 0xc8, 0x64, 0xc4, 0x65, 0x87, 0x54, 0xca, 0xc5,
- 0x94, 0x84, 0xb2, 0x92, 0x55, 0xbd, 0xcf, 0x98, 0xdc, 0xfe, 0xf8, 0xd9,
- 0x4b, 0xae, 0x34, 0x14, 0xf2, 0xe8, 0x0c, 0x21, 0x29, 0xdc, 0xf8, 0x82,
- 0xc7, 0xf4, 0xbe, 0x2a, 0xa7, 0x28, 0xb1, 0x2d, 0x46, 0xab, 0x95, 0xaa,
- 0x10, 0x52, 0xf2, 0x95, 0xe2, 0xa5, 0xa4, 0x37, 0x76, 0xaf, 0x6e, 0x34,
- 0x9d, 0xc7, 0xaf, 0xd7, 0x08, 0x35, 0x18, 0xf2, 0x20, 0xd4, 0x16, 0xc5,
- 0x5d, 0x2a, 0x65, 0xf0, 0x8b, 0x8f, 0x35, 0xc1, 0xed, 0xa8, 0x11, 0xee,
- 0x38, 0xc7, 0x5a, 0x85, 0x4e, 0xa9, 0x4f, 0x1c, 0x69, 0x42, 0x78, 0x79,
- 0x81, 0xf7, 0x6f, 0x94, 0x68, 0xa3, 0xcc, 0x53, 0x6a, 0xaa, 0x2d, 0xa5,
- 0x44, 0x2f, 0x74, 0x9b, 0x83, 0xe3, 0xd6, 0x19, 0xfa, 0x3f, 0x06, 0x8b,
- 0x5b, 0xcf, 0xf4, 0x09, 0x4f, 0xc0, 0x43, 0x5e, 0x12, 0x1d, 0x79, 0x2d,
- 0xa1, 0x45, 0x20, 0xba, 0x84, 0x9d, 0x17, 0x23, 0x7b, 0x03, 0x63, 0xf6,
- 0xb6, 0x3a, 0x0e, 0xbb, 0xd3, 0xa6, 0x44, 0x24, 0x0c, 0xbd, 0x3d, 0xba,
- 0x6c, 0xb2, 0xd8, 0x21, 0xb5, 0x30, 0x85, 0xa1, 0x47, 0xd4, 0x02, 0x2e,
- 0x2f, 0xed, 0x8e, 0x7e, 0xfc, 0x3c, 0x32, 0xb7, 0xb3, 0xe5, 0x27, 0x72,
- 0xa4, 0x21, 0x52, 0x75, 0x90, 0x3e, 0x54, 0xe8, 0x51, 0xfe, 0x98, 0x6c,
- 0xfc, 0x47, 0xe7, 0xdc, 0xd7, 0x94, 0xb3, 0xed, 0x1d, 0xda, 0x05, 0x5d,
- 0x71, 0xdb, 0x11, 0x0a, 0x8b, 0x7a, 0x02, 0x9b, 0x76, 0xe4, 0x6c, 0xb4,
- 0x91, 0xb8, 0xed, 0x89, 0xee, 0x39, 0x99, 0xaa, 0xb9, 0x88, 0xd8, 0x44,
- 0x8b, 0xe5, 0xb2, 0x5a, 0x0a, 0xf0, 0xdf, 0x23, 0xcf, 0x6d, 0x61, 0xef,
- 0x0d, 0x38, 0xdc, 0x9d, 0x35, 0xc5, 0x9f, 0xca, 0xb2, 0x0e, 0xe6, 0xd7,
- 0x00, 0x7c, 0xe0, 0x1f, 0x50, 0x8f, 0x55, 0xf2, 0xa3, 0xaa, 0x45, 0x4a,
- 0x04, 0x79, 0xb0, 0x55, 0xb8, 0x91, 0x19, 0x8d, 0x4d, 0xaa, 0xde, 0xa3,
- 0x80, 0x47, 0xd3, 0x09, 0xea, 0xae, 0xf5, 0x11, 0x6d, 0xa5, 0xc7, 0x1c,
- 0x99, 0x15, 0xbd, 0x65, 0x01, 0x49, 0x8b, 0xa0, 0x6a, 0xb5, 0xf4, 0x8b,
- 0x27, 0x9d, 0x8f, 0xe9, 0x8b, 0x87, 0x4c, 0xba, 0xd9, 0x4b, 0xce, 0x4d,
- 0xff, 0x00, 0x07, 0xcc, 0x94, 0x71, 0x16, 0x72, 0x80, 0x05, 0x6d, 0x5d,
- 0x71, 0xdd, 0x27, 0x61, 0x71, 0xc8, 0x37, 0x3d, 0xef, 0xcf, 0x38, 0x79,
- 0x9f, 0x93, 0x8c, 0x58, 0x4e, 0xd4, 0x68, 0xf2, 0x4b, 0x4c, 0xdb, 0x53,
- 0x8c, 0x2c, 0x6a, 0x09, 0x23, 0x6f, 0x29, 0x3b, 0x8f, 0x4f, 0xbe, 0x04,
- 0x9c, 0x77, 0x52, 0x92, 0x58, 0x97, 0xa9, 0xdd, 0x2a, 0xe6, 0x0e, 0x47,
- 0xd2, 0x0e, 0x25, 0x2e, 0x4c, 0x27, 0x8d, 0xa7, 0x8d, 0x8e, 0xd7, 0xb7,
- 0x95, 0xf5, 0xf5, 0xf5, 0x89, 0x1f, 0x47, 0xa4, 0x67, 0x06, 0x27, 0x4a,
- 0x35, 0xc7, 0x25, 0x86, 0xd4, 0xd1, 0x08, 0xf1, 0x52, 0x52, 0x1c, 0xba,
- 0x55, 0x71, 0xbf, 0xd0, 0x1f, 0xbe, 0x00, 0xaf, 0x5c, 0xa8, 0x5a, 0x94,
- 0x10, 0x5a, 0x84, 0xcb, 0x81, 0x5c, 0x27, 0x48, 0xf1, 0xd4, 0x3e, 0xe4,
- 0x95, 0x7b, 0x9f, 0xd3, 0x14, 0x2f, 0xe6, 0xaa, 0x6d, 0x4d, 0x6c, 0xd3,
- 0xdb, 0x42, 0x5a, 0x79, 0x32, 0x1d, 0x2a, 0x4a, 0x2e, 0x92, 0x2c, 0x40,
- 0xb6, 0xae, 0x49, 0xb0, 0xb9, 0x3e, 0xf8, 0x47, 0xcc, 0xb4, 0xc3, 0x4a,
- 0x6d, 0x6b, 0x2e, 0x25, 0xc2, 0xe4, 0xa7, 0xc1, 0x08, 0xb8, 0x03, 0x4b,
- 0xa4, 0xff, 0x00, 0xa1, 0x18, 0x6f, 0xa9, 0xce, 0x2e, 0x6a, 0x8a, 0xda,
- 0x9c, 0x37, 0x25, 0x47, 0xdb, 0xf9, 0x87, 0x1c, 0x20, 0xa3, 0xda, 0x25,
- 0xc3, 0x9a, 0x80, 0x56, 0xb9, 0x9d, 0xb7, 0x85, 0x77, 0xe9, 0xb4, 0xfa,
- 0xab, 0x28, 0x11, 0xe7, 0x2e, 0x39, 0x24, 0x85, 0xad, 0x06, 0xc1, 0x06,
- 0xfe, 0xd7, 0xfb, 0xed, 0x82, 0x39, 0x17, 0x2c, 0xd0, 0xd9, 0x9e, 0xf4,
- 0x3c, 0xcf, 0x54, 0x5f, 0x88, 0xbb, 0x18, 0x8b, 0x5b, 0xc4, 0xb6, 0xbd,
- 0xf9, 0x0a, 0x1d, 0xfd, 0xb6, 0xf4, 0xb6, 0x25, 0x94, 0xb9, 0x92, 0x62,
- 0x49, 0x75, 0xd8, 0xce, 0xa9, 0xb5, 0x29, 0xc5, 0x6d, 0x7d, 0xb9, 0x3b,
- 0x1c, 0x51, 0x28, 0x4e, 0x48, 0xaa, 0xd2, 0x5e, 0x79, 0xf8, 0xbe, 0x46,
- 0x52, 0x95, 0x2c, 0x84, 0xdd, 0x04, 0x15, 0x69, 0xe7, 0xd6, 0xfd, 0xb0,
- 0x15, 0xd3, 0x31, 0x2c, 0x9b, 0x71, 0x92, 0x9e, 0xb0, 0x2a, 0x5d, 0x9a,
- 0x26, 0x2b, 0x50, 0x2a, 0x68, 0x31, 0x30, 0xad, 0xc0, 0x04, 0x28, 0xfb,
- 0x67, 0xd7, 0x3f, 0x13, 0x15, 0xe8, 0x99, 0x07, 0x2d, 0x48, 0x6d, 0x0d,
- 0xc5, 0x61, 0x12, 0xdc, 0x5b, 0x6e, 0x5d, 0xa5, 0x2f, 0xec, 0x13, 0xb8,
- 0x3c, 0x1b, 0x0d, 0xf7, 0xbd, 0xce, 0x05, 0xc1, 0xa4, 0x39, 0x43, 0xca,
- 0x15, 0x0a, 0x3b, 0xad, 0x84, 0x2e, 0x3b, 0x6f, 0xb4, 0x42, 0x56, 0x5c,
- 0x06, 0xc5, 0x44, 0x79, 0xac, 0x2e, 0x34, 0xdb, 0x7b, 0x0c, 0x2b, 0x65,
- 0x9a, 0xcd, 0x47, 0x2d, 0xa0, 0xaa, 0x33, 0xea, 0x72, 0x1b, 0xab, 0xb2,
- 0xa3, 0xea, 0x1a, 0xae, 0x3c, 0xd7, 0x07, 0xe6, 0xb5, 0xff, 0x00, 0xec,
- 0x61, 0xd2, 0x7e, 0x67, 0x6b, 0x30, 0x49, 0x9a, 0xb0, 0x9f, 0x04, 0x2c,
- 0x36, 0x1f, 0xb6, 0xc0, 0x21, 0x68, 0x20, 0x8d, 0xb8, 0xb5, 0xb0, 0xc7,
- 0x84, 0x66, 0x82, 0xa7, 0x14, 0x39, 0xa4, 0xfd, 0x22, 0x3f, 0xf1, 0x5f,
- 0x0e, 0xcc, 0x52, 0x24, 0xd0, 0xdb, 0x80, 0x1b, 0x2d, 0x26, 0xe3, 0x96,
- 0x63, 0xe7, 0x1a, 0xf4, 0xf9, 0xb2, 0xe3, 0xe5, 0xb9, 0x2f, 0xb6, 0x99,
- 0x09, 0x53, 0x71, 0xf4, 0x25, 0xc4, 0x70, 0x8b, 0x2b, 0x7b, 0xff, 0x00,
- 0x97, 0xd3, 0x08, 0x59, 0x5f, 0xab, 0x71, 0xd2, 0xa5, 0xc5, 0xae, 0x53,
- 0x64, 0x25, 0xbd, 0x56, 0xf8, 0x86, 0x5e, 0x2a, 0x5a, 0x2c, 0x6f, 0x7b,
- 0x1e, 0x37, 0xdf, 0x6c, 0x58, 0xd2, 0xdd, 0x2e, 0xa5, 0xd2, 0x9a, 0x1f,
- 0xf0, 0xc2, 0xcf, 0xc5, 0xae, 0x0b, 0xc2, 0x62, 0x19, 0xf9, 0x8d, 0xd3,
- 0xb2, 0x96, 0x3e, 0xa9, 0xef, 0x8e, 0x46, 0x7d, 0x6b, 0x8b, 0x52, 0x93,
- 0x09, 0xc4, 0x95, 0xa1, 0x0f, 0xad, 0x36, 0x1c, 0xde, 0xe4, 0x6d, 0x83,
- 0x75, 0x4a, 0x93, 0xe8, 0x29, 0x71, 0xbc, 0xb6, 0x3e, 0x36, 0x8a, 0x83,
- 0xd5, 0xe9, 0x96, 0x29, 0xb2, 0x4e, 0xb2, 0x78, 0x41, 0x4d, 0x88, 0x23,
- 0x5b, 0x00, 0x05, 0xf7, 0xd8, 0xe9, 0x1d, 0x04, 0xec, 0xac, 0xbb, 0x9a,
- 0xa0, 0xae, 0x45, 0x3a, 0xb4, 0x15, 0x2d, 0xb2, 0x16, 0xd1, 0x69, 0x94,
- 0xb6, 0xf2, 0x8d, 0xff, 0x00, 0x38, 0xb5, 0x96, 0x07, 0x3c, 0x5f, 0x1f,
- 0x12, 0x8e, 0x69, 0x0d, 0x33, 0x26, 0xa0, 0x83, 0x52, 0x84, 0x96, 0xf4,
- 0x78, 0x91, 0xd0, 0x94, 0x92, 0x9b, 0x8f, 0x99, 0x36, 0xb1, 0xe3, 0x8d,
- 0xb0, 0x1f, 0xa4, 0x19, 0x3e, 0x7c, 0x69, 0x10, 0xf3, 0x0b, 0x8c, 0x7c,
- 0x38, 0x68, 0x97, 0x63, 0xb0, 0xf1, 0xf3, 0xba, 0x46, 0xe0, 0x1e, 0x39,
- 0xf4, 0xed, 0x83, 0x15, 0xac, 0xf6, 0xed, 0x26, 0x24, 0x88, 0x34, 0x94,
- 0xaf, 0xc6, 0xd4, 0x4b, 0xcb, 0x6d, 0x37, 0xd1, 0x7d, 0xac, 0x3d, 0xf9,
- 0xdb, 0x9c, 0x63, 0x5c, 0x8c, 0xac, 0xcc, 0xa9, 0x76, 0x75, 0x01, 0xbe,
- 0x56, 0xca, 0xfe, 0x50, 0xc0, 0xd2, 0x18, 0x9a, 0x94, 0x33, 0x33, 0xcd,
- 0x04, 0x11, 0xbd, 0xed, 0x97, 0x80, 0xd7, 0xa0, 0xb1, 0x31, 0x7b, 0xe9,
- 0x12, 0xe8, 0xec, 0xe5, 0x1b, 0xd3, 0x65, 0x25, 0x2b, 0x7e, 0x38, 0x94,
- 0xb2, 0xa5, 0x15, 0x0b, 0x8d, 0x8d, 0xc6, 0xd6, 0x20, 0x1d, 0xc0, 0xe0,
- 0x8c, 0x47, 0xfa, 0xd7, 0x35, 0x11, 0x33, 0xed, 0x55, 0xe7, 0x8b, 0x6a,
- 0xd4, 0x84, 0xb8, 0x46, 0xab, 0x0b, 0x80, 0x47, 0xef, 0x6c, 0x6c, 0xf4,
- 0x0a, 0x53, 0xf3, 0xe4, 0xd4, 0x59, 0xbc, 0x86, 0x5b, 0x4c, 0x72, 0xd8,
- 0x4b, 0xbb, 0x06, 0xf5, 0x21, 0x57, 0x1f, 0x5b, 0x81, 0x7c, 0x2a, 0x7e,
- 0x26, 0x9b, 0x7e, 0x36, 0x64, 0x8b, 0xe6, 0x4b, 0xa8, 0x98, 0xd2, 0x3c,
- 0xac, 0x82, 0xa2, 0xa0, 0x9b, 0x77, 0x23, 0x6d, 0xf7, 0xc2, 0x83, 0xbc,
- 0x0b, 0x68, 0x34, 0x9d, 0x02, 0xb2, 0xe9, 0x09, 0xce, 0x80, 0x86, 0x94,
- 0xb4, 0x1b, 0x8b, 0x9d, 0x75, 0xb5, 0xf2, 0x8d, 0x18, 0x68, 0x47, 0xf3,
- 0x58, 0x60, 0x04, 0x24, 0x96, 0x46, 0xab, 0xaa, 0xdb, 0x59, 0x69, 0x23,
- 0x7e, 0xe4, 0xf6, 0x18, 0x8c, 0x65, 0x88, 0x92, 0xe5, 0xd7, 0xfe, 0x12,
- 0x23, 0x0b, 0x79, 0xd5, 0x28, 0xa7, 0x4a, 0x47, 0xbf, 0xed, 0x8b, 0x58,
- 0x8b, 0x1d, 0x59, 0xe9, 0xb6, 0xd6, 0xa0, 0xd2, 0x1c, 0x80, 0x95, 0x6c,
- 0x6c, 0x51, 0xe6, 0x26, 0xff, 0x00, 0x6e, 0x70, 0x0e, 0xa7, 0x99, 0x72,
- 0xbe, 0x49, 0x79, 0xf6, 0x29, 0x30, 0x99, 0x9c, 0xe3, 0xaa, 0xd6, 0xe0,
- 0x4a, 0x8a, 0x75, 0x2b, 0x7b, 0x82, 0x46, 0xf6, 0x3d, 0xc6, 0x1e, 0xa4,
- 0xe4, 0x91, 0x35, 0x4c, 0x61, 0x4e, 0x2a, 0xc9, 0x48, 0x37, 0xf5, 0x88,
- 0xd4, 0xe4, 0xeb, 0xb2, 0xb5, 0x59, 0x86, 0xd8, 0x41, 0x5a, 0xd4, 0x13,
- 0x6e, 0x43, 0x5c, 0xc9, 0xf3, 0x86, 0x4c, 0xb5, 0x16, 0x9f, 0x93, 0x61,
- 0x8a, 0x85, 0x46, 0xa4, 0xc7, 0x8e, 0xa4, 0xa8, 0x2d, 0x09, 0x57, 0x97,
- 0x56, 0xdb, 0x7b, 0x9d, 0xb0, 0xbd, 0x9d, 0x69, 0xd5, 0x4c, 0xc7, 0x25,
- 0xea, 0xab, 0x2c, 0x06, 0xda, 0x6e, 0x3a, 0xec, 0x93, 0xf3, 0x2a, 0xf6,
- 0x55, 0xcd, 0xb8, 0xe0, 0x58, 0x5c, 0xfb, 0xde, 0xf8, 0x9b, 0xe6, 0x0c,
- 0xd3, 0x2b, 0x30, 0xd5, 0x05, 0x4a, 0xa4, 0xab, 0xbf, 0xa9, 0x21, 0x0d,
- 0x36, 0x90, 0x96, 0x9a, 0x48, 0xb5, 0x92, 0x00, 0x1e, 0x82, 0xd8, 0x7d,
- 0x9d, 0xd4, 0x5a, 0x62, 0xe8, 0x72, 0x22, 0xc7, 0x6d, 0xe5, 0x3a, 0xe4,
- 0x52, 0xd0, 0x48, 0x05, 0x37, 0x51, 0xb0, 0xd4, 0x3d, 0x3b, 0xfe, 0xd8,
- 0xc7, 0x51, 0x9f, 0x79, 0xf6, 0x44, 0xac, 0x93, 0x47, 0x83, 0xa1, 0x37,
- 0xb7, 0xdf, 0x58, 0xdf, 0x45, 0xa1, 0xa1, 0x89, 0x83, 0x3f, 0x38, 0xbe,
- 0x27, 0x8f, 0x90, 0x17, 0xe5, 0x19, 0xf8, 0x7e, 0xa9, 0x7f, 0x0c, 0xcf,
- 0x74, 0xe6, 0x41, 0x4a, 0xd2, 0xeb, 0xce, 0xb3, 0xa8, 0xde, 0xe0, 0x68,
- 0x5e, 0xff, 0x00, 0xed, 0x86, 0xef, 0xc4, 0xae, 0x57, 0xad, 0x66, 0x9c,
- 0xf5, 0x96, 0xa9, 0x99, 0x7a, 0x9d, 0x22, 0xa3, 0x2d, 0xe8, 0xaa, 0x40,
- 0x08, 0x48, 0x09, 0x16, 0x37, 0x25, 0x44, 0xec, 0x91, 0x6d, 0xee, 0x48,
- 0x18, 0x40, 0xe9, 0x72, 0x97, 0x1f, 0x38, 0xd0, 0xe4, 0x4c, 0x01, 0x82,
- 0xed, 0x49, 0xc4, 0x5d, 0xc5, 0x00, 0x2e, 0xa4, 0xe9, 0x1b, 0xf1, 0xc9,
- 0xb6, 0x3a, 0x7f, 0x38, 0x67, 0x5a, 0x2e, 0x59, 0xa6, 0xa5, 0xe0, 0x17,
- 0x2e, 0xa6, 0xb8, 0xfa, 0x52, 0xdb, 0x00, 0xd8, 0x26, 0xfb, 0x6b, 0x20,
- 0x5c, 0xef, 0xc2, 0x45, 0xf0, 0x93, 0x8e, 0x17, 0x35, 0x2b, 0x5d, 0x93,
- 0x71, 0x96, 0x8a, 0xd6, 0x59, 0x02, 0xde, 0x3d, 0xe1, 0xed, 0xbc, 0x50,
- 0xb0, 0xeb, 0x0d, 0xcd, 0x53, 0xdf, 0x6c, 0x1d, 0x56, 0x6f, 0xe5, 0x63,
- 0xf4, 0x85, 0xbe, 0x94, 0xf4, 0x72, 0x85, 0xd3, 0xd8, 0x08, 0xcc, 0xb9,
- 0x96, 0x4b, 0x33, 0xab, 0x2c, 0xd8, 0x87, 0x41, 0xbc, 0x68, 0x8b, 0xec,
- 0x1b, 0x07, 0xff, 0x00, 0x51, 0x63, 0xfb, 0xdd, 0xbb, 0x0e, 0xf8, 0xdb,
- 0xcc, 0xd9, 0xc6, 0x7d, 0x6e, 0x97, 0x22, 0x99, 0x97, 0xdc, 0x30, 0xd2,
- 0xa6, 0xd4, 0x18, 0x23, 0xe7, 0x70, 0xff, 0x00, 0x7d, 0x44, 0xf0, 0x2f,
- 0xe9, 0xbd, 0xed, 0xef, 0x88, 0x96, 0x6e, 0xcd, 0xdd, 0x45, 0xce, 0x15,
- 0x44, 0x29, 0xea, 0x7c, 0xe4, 0x42, 0x6a, 0xe1, 0xa6, 0x49, 0x08, 0xda,
- 0xe7, 0x7b, 0x5f, 0xcb, 0x7f, 0x41, 0xe9, 0xdf, 0x07, 0xa9, 0xaf, 0xe7,
- 0x01, 0x14, 0xb6, 0xb8, 0x4d, 0x0f, 0x11, 0x21, 0x09, 0x40, 0x76, 0xe5,
- 0x24, 0xef, 0x60, 0x07, 0xdf, 0x6c, 0x0f, 0x6b, 0x07, 0xd4, 0xa6, 0xdd,
- 0x13, 0x53, 0xa8, 0x2b, 0x5e, 0xc2, 0xdd, 0xd4, 0xf4, 0x82, 0xcd, 0x87,
- 0x52, 0x9e, 0xce, 0x55, 0xb2, 0x40, 0xde, 0xc7, 0xda, 0xff, 0x00, 0x3f,
- 0xe6, 0x14, 0xb2, 0x2c, 0x09, 0x51, 0x33, 0x8c, 0x66, 0x96, 0xe1, 0x7d,
- 0xc5, 0x2d, 0xc4, 0x94, 0x29, 0xcb, 0xf9, 0x86, 0xc6, 0xe4, 0x5e, 0xdd,
- 0xf0, 0x56, 0x6c, 0xc9, 0x93, 0x95, 0x53, 0x69, 0x65, 0xc7, 0x52, 0xcc,
- 0xa7, 0x94, 0x02, 0xd5, 0xa8, 0xa0, 0x6b, 0xde, 0xde, 0xbd, 0xbf, 0x4c,
- 0x39, 0xe4, 0xec, 0x9f, 0x57, 0x77, 0x33, 0x35, 0x50, 0x9f, 0x4e, 0x44,
- 0x25, 0x34, 0xab, 0xa5, 0xd0, 0x8d, 0x3a, 0x81, 0xd8, 0x85, 0x71, 0xc7,
- 0x37, 0xe4, 0x93, 0x84, 0x99, 0x2f, 0xb0, 0xd5, 0x72, 0xae, 0x88, 0xe8,
- 0x7a, 0x4a, 0xdb, 0x98, 0xf0, 0x75, 0x09, 0x68, 0x9d, 0x0a, 0xd5, 0xb0,
- 0xbf, 0x1b, 0xdb, 0x0e, 0x75, 0x19, 0x29, 0x84, 0x51, 0xd0, 0x85, 0xa0,
- 0xf1, 0xf1, 0xde, 0xdb, 0xd8, 0x8f, 0xda, 0x1b, 0xb0, 0xc3, 0x8c, 0xc8,
- 0x9f, 0xee, 0x94, 0x1b, 0x04, 0x2b, 0xfc, 0x8d, 0xb6, 0x1b, 0x9e, 0x86,
- 0x13, 0x32, 0xee, 0x51, 0x95, 0x26, 0x62, 0x97, 0x2b, 0xca, 0x85, 0x38,
- 0x74, 0x36, 0x8d, 0xd4, 0xab, 0x9d, 0xbe, 0x98, 0x69, 0xa8, 0xfc, 0x0d,
- 0x1c, 0x22, 0x1c, 0x55, 0x32, 0x08, 0x1b, 0xa5, 0x0e, 0x6a, 0x08, 0xf5,
- 0x04, 0x8e, 0x4f, 0x7d, 0xb1, 0xf9, 0x3a, 0x8f, 0x99, 0xea, 0x68, 0x4a,
- 0x63, 0xc8, 0x85, 0x01, 0xbe, 0x74, 0x97, 0x81, 0xd3, 0x7f, 0x5b, 0x72,
- 0x71, 0xa3, 0x1b, 0xa7, 0x33, 0x18, 0x92, 0xdb, 0x95, 0x3a, 0xd3, 0x84,
- 0xba, 0x82, 0xa1, 0xe0, 0x46, 0x71, 0x6a, 0x29, 0xe3, 0xb0, 0x36, 0xc6,
- 0x54, 0xe1, 0xea, 0x8c, 0xd0, 0x0b, 0x75, 0x36, 0x1c, 0xb2, 0x10, 0xa0,
- 0xf7, 0xc4, 0x6c, 0x37, 0x86, 0xc1, 0x96, 0xa4, 0x1e, 0x35, 0x0c, 0x8a,
- 0xc8, 0xb9, 0x3d, 0x32, 0xf6, 0xc8, 0x43, 0x2e, 0x4d, 0x99, 0x97, 0xd4,
- 0x5c, 0x4d, 0x69, 0x97, 0x3c, 0x55, 0x0b, 0xa6, 0x42, 0xaf, 0x66, 0xc6,
- 0x92, 0x6c, 0x12, 0x0d, 0xbe, 0xfe, 0xbd, 0xf0, 0xcf, 0x05, 0xa8, 0x4e,
- 0xd6, 0x27, 0x1a, 0x5b, 0xc8, 0x2c, 0x08, 0x8d, 0x82, 0xb6, 0x55, 0x70,
- 0xa5, 0x00, 0xaf, 0x5e, 0xdb, 0xe1, 0x61, 0x8e, 0x9b, 0x44, 0x0a, 0x68,
- 0xbd, 0x5a, 0x7d, 0x69, 0x28, 0x05, 0x2a, 0x5a, 0xc8, 0xf2, 0xfa, 0x7b,
- 0x7d, 0x30, 0xdd, 0x95, 0xa9, 0x54, 0xbc, 0xb6, 0xc4, 0x8b, 0xcf, 0x69,
- 0x48, 0x5f, 0x9c, 0xf9, 0x49, 0x3b, 0x0b, 0x6e, 0x7b, 0xe1, 0x86, 0x83,
- 0x40, 0x98, 0x91, 0x9b, 0x0f, 0x39, 0x60, 0x90, 0x0e, 0xf1, 0x1b, 0xc6,
- 0xf8, 0xe6, 0x56, 0xbb, 0x28, 0xa4, 0xa5, 0x4a, 0x53, 0x84, 0x8d, 0x41,
- 0xd8, 0xc6, 0x8e, 0x49, 0x2b, 0xfe, 0x58, 0xa4, 0x2c, 0x3a, 0xb4, 0x07,
- 0x1a, 0x2d, 0x2e, 0xcb, 0x29, 0xbe, 0x95, 0x91, 0xcf, 0xf9, 0x86, 0x34,
- 0x1b, 0xc8, 0xf4, 0x8c, 0xaf, 0x5e, 0x7b, 0x30, 0xd7, 0x5a, 0x69, 0xe4,
- 0x15, 0xf8, 0x89, 0x2e, 0x3a, 0x34, 0x81, 0xea, 0x07, 0xae, 0x0e, 0xf4,
- 0xc1, 0xba, 0x5d, 0x63, 0xa7, 0xae, 0xc4, 0x55, 0x72, 0x1c, 0x19, 0xf0,
- 0x66, 0x38, 0x02, 0x5f, 0x41, 0xf9, 0x54, 0x41, 0x1c, 0x6f, 0x6f, 0x70,
- 0x0e, 0xe2, 0xc7, 0x1e, 0x95, 0x1c, 0xa7, 0x95, 0x6a, 0x8f, 0x78, 0x99,
- 0xa7, 0x38, 0xbb, 0x31, 0x60, 0xec, 0xdc, 0x55, 0x04, 0xb2, 0x91, 0xed,
- 0xab, 0x73, 0xf5, 0x23, 0x1e, 0xf3, 0x75, 0x49, 0x44, 0x23, 0x3e, 0xf2,
- 0x92, 0x4d, 0x87, 0x99, 0xce, 0x3e, 0x82, 0xa0, 0x54, 0x25, 0x95, 0x47,
- 0x96, 0xed, 0x52, 0x14, 0xb4, 0x0c, 0xae, 0x0e, 0x47, 0x63, 0x7d, 0xad,
- 0x7f, 0x13, 0xf3, 0x08, 0x59, 0xa7, 0xa9, 0x90, 0xe7, 0xd4, 0x3f, 0x87,
- 0xd3, 0xd6, 0x44, 0x73, 0xb1, 0x7d, 0x46, 0xca, 0xb7, 0x64, 0x8b, 0x7c,
- 0xa3, 0x8d, 0x86, 0xe7, 0xb9, 0xed, 0x80, 0xd4, 0x1a, 0xac, 0x04, 0xb8,
- 0xe1, 0x71, 0x0b, 0xd2, 0xb7, 0x09, 0xdc, 0xdf, 0x49, 0xdf, 0x6b, 0x1f,
- 0xad, 0xcf, 0xed, 0x8a, 0xe2, 0x32, 0x5e, 0x40, 0x85, 0x1d, 0x89, 0x14,
- 0xa8, 0x54, 0xea, 0xb8, 0x52, 0x94, 0x1c, 0x0f, 0x4f, 0x53, 0x3e, 0x1f,
- 0xf7, 0x46, 0xc8, 0x37, 0x36, 0xbd, 0xed, 0xc6, 0x18, 0xa9, 0xf4, 0xfe,
- 0x9a, 0xa6, 0x12, 0x14, 0xfd, 0x0c, 0x31, 0x25, 0x0a, 0x21, 0xe6, 0x58,
- 0x43, 0xce, 0x83, 0xb6, 0xc5, 0x2e, 0x5b, 0x71, 0xfa, 0x61, 0x36, 0xa1,
- 0x3e, 0x26, 0x94, 0x4b, 0xae, 0x0f, 0x33, 0x18, 0x26, 0x3b, 0x79, 0xb7,
- 0x4a, 0x9e, 0x70, 0x78, 0x00, 0x32, 0x1e, 0xa7, 0xde, 0x37, 0x7a, 0x17,
- 0xe0, 0x3b, 0x48, 0x42, 0x53, 0xe0, 0x3a, 0xfb, 0xa9, 0x5b, 0xee, 0x29,
- 0xa1, 0xc9, 0x06, 0xc7, 0x9e, 0xc0, 0x5b, 0x02, 0x7f, 0x12, 0x50, 0xd2,
- 0xdd, 0x7e, 0x93, 0x25, 0x20, 0x05, 0x29, 0x82, 0x90, 0x37, 0xb1, 0xb1,
- 0x1e, 0x9f, 0x43, 0x86, 0xaa, 0x5d, 0x7f, 0x25, 0x51, 0x5d, 0x0b, 0xa7,
- 0x50, 0xaa, 0x37, 0x00, 0x68, 0x09, 0x69, 0x66, 0xc3, 0xef, 0x84, 0xbe,
- 0xa7, 0xe6, 0x98, 0xb9, 0xb2, 0xbf, 0x16, 0x33, 0x50, 0x64, 0xc2, 0xf8,
- 0x26, 0xff, 0x00, 0xe7, 0x24, 0xa5, 0x4a, 0x4f, 0xae, 0xe3, 0x8d, 0xf9,
- 0xe3, 0x6c, 0x60, 0x4b, 0x8c, 0xf6, 0x25, 0x01, 0x60, 0xaa, 0xf7, 0xc8,
- 0xc6, 0x57, 0x18, 0xec, 0x90, 0x45, 0xf2, 0xf1, 0xb7, 0xca, 0xe6, 0x24,
- 0x3d, 0x41, 0x97, 0x21, 0x1f, 0x0d, 0xf0, 0x4e, 0xa2, 0x3c, 0xc7, 0x96,
- 0x4e, 0xa5, 0x10, 0x0f, 0x86, 0x05, 0x92, 0x8b, 0x9f, 0xca, 0x76, 0xfd,
- 0x31, 0x3c, 0x10, 0xaa, 0xae, 0xbe, 0xaf, 0xfc, 0xad, 0x97, 0x97, 0x7d,
- 0xce, 0x92, 0xa3, 0xfa, 0xe2, 0xae, 0x8a, 0x4c, 0x1a, 0xef, 0x50, 0x69,
- 0x54, 0x9a, 0x83, 0xc9, 0x62, 0x3f, 0xc0, 0xba, 0xf1, 0x71, 0x36, 0x3a,
- 0x52, 0x3e, 0x5d, 0xcf, 0xa0, 0x37, 0xbe, 0x07, 0xe6, 0x8c, 0x85, 0x9a,
- 0xe3, 0xcf, 0x28, 0xc9, 0xd5, 0x29, 0xb5, 0x66, 0x42, 0x43, 0x88, 0x44,
- 0x72, 0xa2, 0xbd, 0x2a, 0xbd, 0xb9, 0xdd, 0x5c, 0x1b, 0x73, 0xf5, 0xc5,
- 0x33, 0x0d, 0xb6, 0xf3, 0x34, 0xd0, 0xe7, 0x19, 0xb1, 0xb9, 0x00, 0x01,
- 0x90, 0xb9, 0x1a, 0xab, 0x2f, 0x28, 0x57, 0x55, 0x29, 0xb7, 0xc2, 0xa6,
- 0x0a, 0x49, 0xd8, 0xdb, 0x5c, 0xa0, 0x05, 0x1f, 0x29, 0x54, 0xdd, 0xa7,
- 0xa9, 0xe7, 0xe3, 0x53, 0xa2, 0x10, 0x9b, 0xb7, 0xe2, 0x4f, 0x09, 0x2e,
- 0x0b, 0x5e, 0xe0, 0x04, 0x2a, 0xff, 0x00, 0xb6, 0x3c, 0x19, 0xcb, 0xd9,
- 0xd9, 0x45, 0x3f, 0x0d, 0x47, 0x8e, 0x9d, 0x48, 0x4a, 0xbc, 0xa5, 0x2a,
- 0xb5, 0xc6, 0xd7, 0xb9, 0x36, 0x3e, 0xd8, 0x0e, 0x89, 0x59, 0xb5, 0x89,
- 0x4b, 0x82, 0xa9, 0x72, 0xe3, 0xb8, 0x83, 0x65, 0x24, 0xf9, 0x74, 0x9f,
- 0x43, 0xb6, 0xc7, 0xeb, 0x82, 0xb4, 0xea, 0x6e, 0x75, 0x9e, 0xca, 0xa5,
- 0x36, 0xed, 0x49, 0xc4, 0xa1, 0x5a, 0x54, 0x52, 0x6f, 0xc7, 0x3c, 0x63,
- 0x43, 0xb8, 0xa9, 0xa6, 0xcf, 0x0a, 0x8a, 0xc5, 0xbf, 0xf3, 0xf7, 0xe8,
- 0x04, 0x71, 0x6e, 0x9f, 0x4a, 0x51, 0xcd, 0x0b, 0x3d, 0x48, 0xfa, 0xde,
- 0x33, 0x30, 0xe5, 0xec, 0xe9, 0x12, 0x9a, 0x89, 0xd5, 0x86, 0x99, 0x6a,
- 0x34, 0x75, 0x78, 0x88, 0xd4, 0x05, 0x8a, 0x86, 0xe1, 0x36, 0xb7, 0x7b,
- 0x7d, 0x31, 0xeb, 0x53, 0xa8, 0x67, 0xc8, 0x49, 0x65, 0x6e, 0x39, 0x22,
- 0x13, 0x2a, 0x17, 0x65, 0x41, 0xb5, 0xb4, 0x9b, 0x13, 0xdb, 0x55, 0x88,
- 0x1b, 0xf7, 0xc3, 0xfd, 0x0e, 0x44, 0xc7, 0xa8, 0x2c, 0xc1, 0xac, 0x34,
- 0x92, 0xb6, 0x27, 0xc7, 0x6d, 0x68, 0x51, 0xb8, 0x3c, 0x1d, 0xc7, 0x62,
- 0x45};
-} // namespace
diff --git a/vendor_libs/test_vendor_lib/include/le_advertisement.h b/vendor_libs/test_vendor_lib/include/le_advertisement.h
new file mode 100644
index 0000000..a5c1396
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/include/le_advertisement.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2018 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>
+
+namespace test_vendor_lib {
+
+class LeAdvertisement {
+ public:
+ enum class AdvertisementType : uint8_t {
+ ADV_IND = 0, // Connectable and scannable
+ ADV_DIRECT_IND = 1, // Connectable directed
+ ADV_SCAN_IND = 2, // Scannable undirected
+ ADV_NONCONN_IND = 3, // Non connectable undirected
+ SCAN_RESPONSE = 4,
+ };
+ enum class AddressType : uint8_t {
+ PUBLIC = 0,
+ RANDOM = 1,
+ PUBLIC_IDENTITY = 2,
+ RANDOM_IDENTITY = 3,
+ };
+};
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/link.h b/vendor_libs/test_vendor_lib/include/link.h
new file mode 100644
index 0000000..1c60e3d
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/include/link.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2018 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
+
+namespace test_vendor_lib {
+class Link {
+ public:
+ static constexpr size_t kSizeBytes = sizeof(uint32_t);
+ static constexpr size_t kTypeBytes = sizeof(uint8_t);
+
+ enum class PacketType : uint8_t {
+ UNKNOWN,
+ ACL,
+ COMMAND,
+ DISCONNECT,
+ ENCRYPT_CONNECTION,
+ ENCRYPT_CONNECTION_RESPONSE,
+ EVENT,
+ INQUIRY,
+ INQUIRY_RESPONSE,
+ IO_CAPABILITY_REQUEST,
+ IO_CAPABILITY_RESPONSE,
+ IO_CAPABILITY_NEGATIVE_RESPONSE,
+ LE_ADVERTISEMENT,
+ LE_SCAN,
+ LE_SCAN_RESPONSE,
+ PAGE,
+ PAGE_RESPONSE,
+ RESPONSE,
+ SCO,
+ };
+};
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/packet.h b/vendor_libs/test_vendor_lib/include/packet.h
deleted file mode 100644
index 8bad493..0000000
--- a/vendor_libs/test_vendor_lib/include/packet.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * 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 "bt_address.h"
-#include "hci/include/hci_hal.h"
-
-namespace test_vendor_lib {
-
-const size_t kReservedZero = 0;
-
-// 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;
-
- size_t GetPayloadSize() const;
-
- const std::vector<uint8_t>& GetHeader() const;
-
- uint8_t GetHeaderSize() const;
-
- serial_data_type_t GetType() const;
-
- // Add |octets| bytes to the payload. Return true if:
- // - the size of |bytes| is equal to |octets| and
- // - the new size of the payload is still < |kMaxPayloadOctets|
- bool AddPayloadOctets(size_t octets, const std::vector<uint8_t>& bytes);
-
- private:
- // Add |octets| bytes to the payload. Return true if:
- // - the value of |value| fits in |octets| bytes and
- // - the new size of the payload is still < |kMaxPayloadOctets|
- bool AddPayloadOctets(size_t octets, uint64_t value);
-
- public:
- // Add type-checking versions
- bool AddPayloadOctets1(uint8_t value) { return AddPayloadOctets(1, value); }
- bool AddPayloadOctets2(uint16_t value) { return AddPayloadOctets(2, value); }
- bool AddPayloadOctets3(uint32_t value) { return AddPayloadOctets(3, value); }
- bool AddPayloadOctets4(uint32_t value) { return AddPayloadOctets(4, value); }
- bool AddPayloadOctets6(uint64_t value) { return AddPayloadOctets(6, value); }
- bool AddPayloadOctets8(uint64_t value) { return AddPayloadOctets(8, value); }
-
- // Add |address| to the payload. Return true if:
- // - the new size of the payload is still < |kMaxPayloadOctets|
- bool AddPayloadBtAddress(const BtAddress& address);
-
- // Return true if |num_bytes| can be added to the payload.
- bool CanAddPayloadOctets(size_t num_bytes) const {
- return GetPayloadSize() + num_bytes <= kMaxPayloadOctets;
- }
-
- protected:
- // Constructs an empty packet of type |type| and header |header|
- Packet(serial_data_type_t type, std::vector<uint8_t> header);
-
- bool IncrementPayloadCounter(size_t index);
- bool IncrementPayloadCounter(size_t index, uint8_t max_val);
-
- private:
- const size_t kMaxPayloadOctets = 256; // Includes the size byte.
-
- // Underlying containers for storing the actual packet
-
- // The packet type is one of DATA_TYPE_ACL, DATA_TYPE_COMMAND,
- // DATA_TYPE_EVENT, or DATA_TYPE_SCO.
- serial_data_type_t type_;
-
- std::vector<uint8_t> header_;
-
- std::vector<uint8_t> payload_;
-};
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/packet_stream.h b/vendor_libs/test_vendor_lib/include/packet_stream.h
deleted file mode 100644
index e2cec7d..0000000
--- a/vendor_libs/test_vendor_lib/include/packet_stream.h
+++ /dev/null
@@ -1,66 +0,0 @@
-//
-// 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 "command_packet.h"
-#include "event_packet.h"
-#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(std::unique_ptr<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
diff --git a/vendor_libs/test_vendor_lib/include/phy.h b/vendor_libs/test_vendor_lib/include/phy.h
new file mode 100644
index 0000000..da3673c
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/include/phy.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2018 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
+
+namespace test_vendor_lib {
+
+class Phy {
+ public:
+ enum class Type {
+ LOW_ENERGY,
+ BR_EDR,
+ };
+};
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/sco.h b/vendor_libs/test_vendor_lib/include/sco.h
new file mode 100644
index 0000000..b3691cf
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/include/sco.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2018 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>
+
+namespace test_vendor_lib {
+namespace sco {
+
+// SCO data packets are specified in the Bluetooth Core Specification Version
+// 4.2, Volume 2, Part E, Section 5.4.3
+enum class PacketStatusFlagsType : uint8_t {
+ CORRECTLY_RECEIVED = 0,
+ POSSIBLY_INCOMPLETE = 1,
+ NO_DATA = 2,
+ PARTIALLY_LOST = 3
+};
+} // namespace sco
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/sco_packet.h b/vendor_libs/test_vendor_lib/include/sco_packet.h
deleted file mode 100644
index 7b95063..0000000
--- a/vendor_libs/test_vendor_lib/include/sco_packet.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2017 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 <string>
-#include <vector>
-
-#include "packet.h"
-
-namespace test_vendor_lib {
-
-// SCO data packets are specified in the Bluetooth Core Specification Version
-// 4.2, Volume 2, Part E, Section 5.4.3
-class ScoPacket : public Packet {
- public:
- virtual ~ScoPacket() override = default;
- typedef enum {
- CorrectlyReceived,
- PossiblyIncomplete,
- NoData,
- PartiallyLost
- } PacketStatusFlags;
-
- uint16_t GetChannel() const;
-
- PacketStatusFlags GetPacketStatusFlags() const;
-
- explicit ScoPacket(uint16_t channel, PacketStatusFlags status_flags);
-};
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/test_channel_transport.h b/vendor_libs/test_vendor_lib/include/test_channel_transport.h
deleted file mode 100644
index 069f91e..0000000
--- a/vendor_libs/test_vendor_lib/include/test_channel_transport.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * 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 <string>
-#include <vector>
-
-#include "base/files/scoped_file.h"
-
-namespace test_vendor_lib {
-
-// Manages communications between test channel and the controller. Mirrors the
-// HciTransport for the test channel.
-class TestChannelTransport {
- public:
- TestChannelTransport() {}
-
- ~TestChannelTransport() {}
-
- // Opens a port and returns the file descriptor for the socket.
- // Returns -1 on an error.
- int SetUp(int port);
-
- // Closes the port (if succesfully opened in SetUp).
- void CleanUp();
-
- // Waits for a connection request from the test channel program and
- // returns the file descriptor to watch for run-time parameters.
- // Returns -1 on an error.
- int Accept(int listen_fd);
-
- // Sets the callback that fires when data is read in WatchFd().
- void RegisterCommandHandler(
- const std::function<void(const std::string&,
- const std::vector<std::string>&)>& callback);
-
- void OnCommandReady(int fd, std::function<void(void)> unwatch);
-
- private:
- std::function<void(const std::string&, const std::vector<std::string>&)>
- command_handler_;
-
- int listen_fd_ = -1;
-
- TestChannelTransport(const TestChannelTransport& cmdPckt) = delete;
- TestChannelTransport& operator=(const TestChannelTransport& cmdPckt) = delete;
-};
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/controller/acl_connection.cc b/vendor_libs/test_vendor_lib/model/controller/acl_connection.cc
new file mode 100644
index 0000000..460f550
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/controller/acl_connection.cc
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2018 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 "acl_connection"
+
+#include "acl_connection.h"
+
+#include "base/logging.h"
+
+#include "osi/include/log.h"
+
+using std::shared_ptr;
+
+namespace test_vendor_lib {} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/controller/acl_connection.h b/vendor_libs/test_vendor_lib/model/controller/acl_connection.h
new file mode 100644
index 0000000..796d04e
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/controller/acl_connection.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2018 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 "types/address.h"
+
+namespace test_vendor_lib {
+
+// Model the connection of a device to the controller.
+class AclConnection {
+ public:
+ AclConnection(const Address& addr) : address_(addr), connected_(false), encrypted_(false) {}
+
+ virtual ~AclConnection() = default;
+
+ void SetConnected(bool connected) {
+ connected_ = connected;
+ };
+ bool IsConnected() const {
+ return connected_;
+ };
+
+ void Encrypt() {
+ encrypted_ = true;
+ };
+ bool IsEncrypted() const {
+ return encrypted_;
+ };
+
+ const Address& GetAddress() const {
+ return address_;
+ }
+ void SetAddress(const Address& address) {
+ address_ = address;
+ }
+
+ private:
+ Address address_;
+
+ // State variables
+ bool connected_;
+ bool encrypted_;
+};
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.cc b/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.cc
new file mode 100644
index 0000000..2d5ff97
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.cc
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2018 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 "acl_connection_handler"
+
+#include "acl_connection_handler.h"
+
+#include "base/logging.h"
+
+#include "osi/include/log.h"
+#include "types/address.h"
+
+using std::shared_ptr;
+
+namespace test_vendor_lib {
+
+bool AclConnectionHandler::HasHandle(uint16_t handle) const {
+ if (acl_connections_.count(handle) == 0) {
+ return false;
+ }
+ return true;
+}
+
+uint16_t AclConnectionHandler::GetUnusedHandle() {
+ static uint16_t sNextHandle = acl::kReservedHandle - 2;
+ while (acl_connections_.count(sNextHandle) == 1) {
+ sNextHandle = (sNextHandle + 1) % acl::kReservedHandle;
+ }
+ uint16_t unused_handle = sNextHandle;
+ sNextHandle = (sNextHandle + 1) % acl::kReservedHandle;
+ return unused_handle;
+}
+
+bool AclConnectionHandler::CreatePendingConnection(const Address& addr) {
+ if ((pending_connections_.size() + 1 > max_pending_connections_) || HasPendingConnection(addr)) {
+ return false;
+ }
+ pending_connections_.insert(addr);
+ return true;
+}
+
+bool AclConnectionHandler::HasPendingConnection(const Address& addr) {
+ return pending_connections_.count(addr) == 1;
+}
+
+bool AclConnectionHandler::CancelPendingConnection(const Address& addr) {
+ if (!HasPendingConnection(addr)) {
+ return false;
+ }
+ pending_connections_.erase(addr);
+ return true;
+}
+
+uint16_t AclConnectionHandler::CreateConnection(const Address& addr) {
+ if (CancelPendingConnection(addr)) {
+ uint16_t handle = GetUnusedHandle();
+ acl_connections_.emplace(handle, addr);
+ SetConnected(handle, true);
+ return handle;
+ }
+ return acl::kReservedHandle;
+}
+
+bool AclConnectionHandler::Disconnect(uint16_t handle) {
+ return acl_connections_.erase(handle) > 0;
+}
+
+uint16_t AclConnectionHandler::GetHandle(const Address& addr) const {
+ for (auto pair : acl_connections_) {
+ if (std::get<AclConnection>(pair).GetAddress() == addr) {
+ return std::get<0>(pair);
+ }
+ }
+ return acl::kReservedHandle;
+}
+
+const Address& AclConnectionHandler::GetAddress(uint16_t handle) const {
+ CHECK(HasHandle(handle)) << "Handle unknown " << handle;
+ return acl_connections_.at(handle).GetAddress();
+}
+
+void AclConnectionHandler::SetConnected(uint16_t handle, bool connected) {
+ if (!HasHandle(handle)) {
+ return;
+ }
+ acl_connections_.at(handle).SetConnected(connected);
+}
+
+bool AclConnectionHandler::IsConnected(uint16_t handle) const {
+ if (!HasHandle(handle)) {
+ return false;
+ }
+ return acl_connections_.at(handle).IsConnected();
+}
+
+void AclConnectionHandler::Encrypt(uint16_t handle) {
+ if (!HasHandle(handle)) {
+ return;
+ }
+ acl_connections_.at(handle).Encrypt();
+}
+
+bool AclConnectionHandler::IsEncrypted(uint16_t handle) const {
+ if (!HasHandle(handle)) {
+ return false;
+ }
+ return acl_connections_.at(handle).IsEncrypted();
+}
+
+void AclConnectionHandler::SetAddress(uint16_t handle, const Address& address) {
+ if (!HasHandle(handle)) {
+ return;
+ }
+ acl_connections_.at(handle).SetAddress(address);
+}
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.h b/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.h
new file mode 100644
index 0000000..fda1d3d
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2018 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 <set>
+#include <unordered_map>
+
+#include "acl_connection.h"
+#include "include/acl.h"
+#include "types/address.h"
+
+namespace test_vendor_lib {
+
+class AclConnectionHandler {
+ public:
+ AclConnectionHandler(size_t max_pending_connections = 1) : max_pending_connections_(max_pending_connections) {}
+
+ virtual ~AclConnectionHandler() = default;
+
+ bool CreatePendingConnection(const Address& addr);
+ bool HasPendingConnection(const Address& addr);
+ bool CancelPendingConnection(const Address& addr);
+
+ uint16_t CreateConnection(const Address& addr);
+ bool Disconnect(uint16_t handle);
+ bool HasHandle(uint16_t handle) const;
+
+ uint16_t GetHandle(const Address& addr) const;
+ const Address& GetAddress(uint16_t handle) const;
+
+ void SetConnected(uint16_t handle, bool connected);
+ bool IsConnected(uint16_t handle) const;
+
+ void Encrypt(uint16_t handle);
+ bool IsEncrypted(uint16_t handle) const;
+
+ void SetAddress(uint16_t handle, const Address& address);
+
+ private:
+ std::unordered_map<uint16_t, AclConnection> acl_connections_;
+ size_t max_pending_connections_;
+ std::set<Address> pending_connections_;
+ uint16_t GetUnusedHandle();
+};
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.cc b/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.cc
new file mode 100644
index 0000000..0c55e47
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.cc
@@ -0,0 +1,1096 @@
+/*
+ * 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 "dual_mode_controller.h"
+
+#include <memory>
+
+#include <base/files/file_util.h>
+#include <base/json/json_reader.h>
+#include <base/logging.h>
+#include <base/values.h>
+
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+#include "hci.h"
+#include "packets/hci/acl_packet_view.h"
+#include "packets/hci/command_packet_view.h"
+#include "packets/hci/event_packet_builder.h"
+#include "packets/hci/sco_packet_view.h"
+
+using std::vector;
+using test_vendor_lib::hci::EventCode;
+using test_vendor_lib::hci::OpCode;
+
+namespace {
+
+size_t LastNonZero(test_vendor_lib::packets::PacketView<true> view) {
+ for (size_t i = view.size() - 1; i > 0; i--) {
+ if (view[i] != 0) {
+ return i;
+ }
+ }
+ return 0;
+}
+
+} // namespace
+
+namespace test_vendor_lib {
+constexpr char DualModeController::kControllerPropertiesFile[];
+constexpr uint16_t DualModeController::kSecurityManagerNumKeys;
+
+// Device methods.
+void DualModeController::Initialize(const std::vector<std::string>& args) {
+ if (args.size() < 2) return;
+
+ Address addr;
+ if (Address::FromString(args[1], addr)) properties_.SetAddress(addr);
+};
+
+std::string DualModeController::GetTypeString() const {
+ return "Simulated Bluetooth Controller";
+}
+
+void DualModeController::IncomingPacket(packets::LinkLayerPacketView incoming) {
+ link_layer_controller_.IncomingPacket(incoming);
+}
+
+void DualModeController::TimerTick() {
+ link_layer_controller_.TimerTick();
+}
+
+void DualModeController::SendLinkLayerPacket(std::shared_ptr<packets::LinkLayerPacketBuilder> to_send,
+ Phy::Type phy_type) {
+ for (auto phy_pair : phy_layers_) {
+ auto phy_list = std::get<1>(phy_pair);
+ if (phy_type != std::get<0>(phy_pair)) {
+ continue;
+ }
+ for (auto phy : phy_list) {
+ phy->Send(to_send);
+ }
+ }
+}
+
+/*
+void DualModeController::AddConnectionAction(const TaskCallback& task,
+ uint16_t handle) {
+ for (size_t i = 0; i < connections_.size(); i++)
+ if (connections_[i]->GetHandle() == handle)
+connections_[i]->AddAction(task);
+}
+*/
+
+void DualModeController::SendCommandCompleteSuccess(OpCode command_opcode) const {
+ send_event_(packets::EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(command_opcode, hci::Status::SUCCESS)
+ ->ToVector());
+}
+
+void DualModeController::SendCommandCompleteUnknownOpCodeEvent(uint16_t command_opcode) const {
+ send_event_(packets::EventPacketBuilder::CreateCommandCompleteUnknownOpCodeEvent(command_opcode)->ToVector());
+}
+
+void DualModeController::SendCommandCompleteOnlyStatus(OpCode command_opcode, hci::Status status) const {
+ send_event_(packets::EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(command_opcode, status)->ToVector());
+}
+
+void DualModeController::SendCommandCompleteStatusAndAddress(OpCode command_opcode, hci::Status status,
+ const Address& address) const {
+ send_event_(packets::EventPacketBuilder::CreateCommandCompleteStatusAndAddressEvent(command_opcode, status, address)
+ ->ToVector());
+}
+
+void DualModeController::SendCommandStatus(hci::Status status, OpCode command_opcode) const {
+ send_event_(packets::EventPacketBuilder::CreateCommandStatusEvent(status, command_opcode)->ToVector());
+}
+
+void DualModeController::SendCommandStatusSuccess(OpCode command_opcode) const {
+ SendCommandStatus(hci::Status::SUCCESS, command_opcode);
+}
+
+DualModeController::DualModeController(const std::string& properties_filename, uint16_t num_keys)
+ : Device(properties_filename), security_manager_(num_keys) {
+ loopback_mode_ = hci::LoopbackMode::NO;
+
+ Address public_address;
+ CHECK(Address::FromString("3C:5A:B4:04:05:06", public_address));
+ properties_.SetAddress(public_address);
+
+ link_layer_controller_.RegisterRemoteChannel(
+ [this](std::shared_ptr<packets::LinkLayerPacketBuilder> packet, Phy::Type phy_type) {
+ DualModeController::SendLinkLayerPacket(packet, phy_type);
+ });
+
+#define SET_HANDLER(opcode, method) \
+ active_hci_commands_[static_cast<uint16_t>(opcode)] = [this](packets::PacketView<true> param) { method(param); };
+ SET_HANDLER(OpCode::RESET, HciReset);
+ SET_HANDLER(OpCode::READ_BUFFER_SIZE, HciReadBufferSize);
+ SET_HANDLER(OpCode::HOST_BUFFER_SIZE, HciHostBufferSize);
+ SET_HANDLER(OpCode::SNIFF_SUBRATING, HciSniffSubrating);
+ SET_HANDLER(OpCode::READ_LOCAL_VERSION_INFORMATION, HciReadLocalVersionInformation);
+ SET_HANDLER(OpCode::READ_BD_ADDR, HciReadBdAddr);
+ SET_HANDLER(OpCode::READ_LOCAL_SUPPORTED_COMMANDS, HciReadLocalSupportedCommands);
+ SET_HANDLER(OpCode::READ_LOCAL_SUPPORTED_CODECS, HciReadLocalSupportedCodecs);
+ SET_HANDLER(OpCode::READ_LOCAL_EXTENDED_FEATURES, HciReadLocalExtendedFeatures);
+ SET_HANDLER(OpCode::READ_REMOTE_EXTENDED_FEATURES, HciReadRemoteExtendedFeatures);
+ SET_HANDLER(OpCode::READ_REMOTE_SUPPORTED_FEATURES, HciReadRemoteSupportedFeatures);
+ SET_HANDLER(OpCode::READ_CLOCK_OFFSET, HciReadClockOffset);
+ SET_HANDLER(OpCode::IO_CAPABILITY_REQUEST_REPLY, HciIoCapabilityRequestReply);
+ SET_HANDLER(OpCode::USER_CONFIRMATION_REQUEST_REPLY, HciUserConfirmationRequestReply);
+ SET_HANDLER(OpCode::USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY, HciUserConfirmationRequestNegativeReply);
+ SET_HANDLER(OpCode::IO_CAPABILITY_REQUEST_NEGATIVE_REPLY, HciIoCapabilityRequestNegativeReply);
+ SET_HANDLER(OpCode::WRITE_SIMPLE_PAIRING_MODE, HciWriteSimplePairingMode);
+ SET_HANDLER(OpCode::WRITE_LE_HOST_SUPPORT, HciWriteLeHostSupport);
+ SET_HANDLER(OpCode::SET_EVENT_MASK, HciSetEventMask);
+ SET_HANDLER(OpCode::WRITE_INQUIRY_MODE, HciWriteInquiryMode);
+ SET_HANDLER(OpCode::WRITE_PAGE_SCAN_TYPE, HciWritePageScanType);
+ SET_HANDLER(OpCode::WRITE_INQUIRY_SCAN_TYPE, HciWriteInquiryScanType);
+ SET_HANDLER(OpCode::AUTHENTICATION_REQUESTED, HciAuthenticationRequested);
+ SET_HANDLER(OpCode::SET_CONNECTION_ENCRYPTION, HciSetConnectionEncryption);
+ SET_HANDLER(OpCode::WRITE_AUTHENTICATION_ENABLE, HciWriteAuthenticationEnable);
+ SET_HANDLER(OpCode::READ_AUTHENTICATION_ENABLE, HciReadAuthenticationEnable);
+ SET_HANDLER(OpCode::WRITE_CLASS_OF_DEVICE, HciWriteClassOfDevice);
+ SET_HANDLER(OpCode::WRITE_PAGE_TIMEOUT, HciWritePageTimeout);
+ SET_HANDLER(OpCode::WRITE_LINK_SUPERVISION_TIMEOUT, HciWriteLinkSupervisionTimeout);
+ SET_HANDLER(OpCode::WRITE_DEFAULT_LINK_POLICY_SETTINGS, HciWriteDefaultLinkPolicySettings);
+ SET_HANDLER(OpCode::WRITE_LINK_POLICY_SETTINGS, HciWriteLinkPolicySettings);
+ SET_HANDLER(OpCode::CHANGE_CONNECTION_PACKET_TYPE, HciChangeConnectionPacketType);
+ SET_HANDLER(OpCode::WRITE_LOCAL_NAME, HciWriteLocalName);
+ SET_HANDLER(OpCode::READ_LOCAL_NAME, HciReadLocalName);
+ SET_HANDLER(OpCode::WRITE_EXTENDED_INQUIRY_RESPONSE, HciWriteExtendedInquiryResponse);
+ SET_HANDLER(OpCode::WRITE_VOICE_SETTING, HciWriteVoiceSetting);
+ SET_HANDLER(OpCode::WRITE_CURRENT_IAC_LAP, HciWriteCurrentIacLap);
+ SET_HANDLER(OpCode::WRITE_INQUIRY_SCAN_ACTIVITY, HciWriteInquiryScanActivity);
+ SET_HANDLER(OpCode::WRITE_SCAN_ENABLE, HciWriteScanEnable);
+ SET_HANDLER(OpCode::SET_EVENT_FILTER, HciSetEventFilter);
+ SET_HANDLER(OpCode::INQUIRY, HciInquiry);
+ SET_HANDLER(OpCode::INQUIRY_CANCEL, HciInquiryCancel);
+ SET_HANDLER(OpCode::ACCEPT_CONNECTION_REQUEST, HciAcceptConnectionRequest);
+ SET_HANDLER(OpCode::REJECT_CONNECTION_REQUEST, HciRejectConnectionRequest);
+ SET_HANDLER(OpCode::LINK_KEY_REQUEST_REPLY, HciLinkKeyRequestReply);
+ SET_HANDLER(OpCode::LINK_KEY_REQUEST_NEGATIVE_REPLY, HciLinkKeyRequestNegativeReply);
+ SET_HANDLER(OpCode::DELETE_STORED_LINK_KEY, HciDeleteStoredLinkKey);
+ SET_HANDLER(OpCode::REMOTE_NAME_REQUEST, HciRemoteNameRequest);
+ SET_HANDLER(OpCode::LE_SET_EVENT_MASK, HciLeSetEventMask);
+ SET_HANDLER(OpCode::LE_READ_BUFFER_SIZE, HciLeReadBufferSize);
+ SET_HANDLER(OpCode::LE_READ_LOCAL_SUPPORTED_FEATURES, HciLeReadLocalSupportedFeatures);
+ SET_HANDLER(OpCode::LE_SET_RANDOM_ADDRESS, HciLeSetRandomAddress);
+ SET_HANDLER(OpCode::LE_SET_ADVERTISING_DATA, HciLeSetAdvertisingData);
+ SET_HANDLER(OpCode::LE_SET_ADVERTISING_PARAMETERS, HciLeSetAdvertisingParameters);
+ SET_HANDLER(OpCode::LE_SET_SCAN_PARAMETERS, HciLeSetScanParameters);
+ SET_HANDLER(OpCode::LE_SET_SCAN_ENABLE, HciLeSetScanEnable);
+ SET_HANDLER(OpCode::LE_CREATE_CONNECTION, HciLeCreateConnection);
+ SET_HANDLER(OpCode::CREATE_CONNECTION, HciCreateConnection);
+ SET_HANDLER(OpCode::DISCONNECT, HciDisconnect);
+ SET_HANDLER(OpCode::LE_CREATE_CONNECTION_CANCEL, HciLeConnectionCancel);
+ SET_HANDLER(OpCode::LE_READ_WHITE_LIST_SIZE, HciLeReadWhiteListSize);
+ SET_HANDLER(OpCode::LE_CLEAR_WHITE_LIST, HciLeClearWhiteList);
+ SET_HANDLER(OpCode::LE_ADD_DEVICE_TO_WHITE_LIST, HciLeAddDeviceToWhiteList);
+ SET_HANDLER(OpCode::LE_REMOVE_DEVICE_FROM_WHITE_LIST, HciLeRemoveDeviceFromWhiteList);
+ SET_HANDLER(OpCode::LE_RAND, HciLeRand);
+ SET_HANDLER(OpCode::LE_READ_SUPPORTED_STATES, HciLeReadSupportedStates);
+ SET_HANDLER(OpCode::LE_GET_VENDOR_CAPABILITIES, HciLeVendorCap);
+ SET_HANDLER(OpCode::LE_MULTI_ADVT, HciLeVendorMultiAdv);
+ SET_HANDLER(OpCode::LE_ADV_FILTER, HciLeAdvertisingFilter);
+ SET_HANDLER(OpCode::LE_ENERGY_INFO, HciLeEnergyInfo);
+ SET_HANDLER(OpCode::LE_EXTENDED_SCAN_PARAMS, HciLeExtendedScanParams);
+ SET_HANDLER(OpCode::LE_READ_REMOTE_FEATURES, HciLeReadRemoteFeatures);
+ SET_HANDLER(OpCode::READ_REMOTE_VERSION_INFORMATION, HciReadRemoteVersionInformation);
+ SET_HANDLER(OpCode::LE_CONNECTION_UPDATE, HciLeConnectionUpdate);
+ SET_HANDLER(OpCode::LE_START_ENCRYPTION, HciLeStartEncryption);
+ // Testing Commands
+ SET_HANDLER(OpCode::READ_LOOPBACK_MODE, HciReadLoopbackMode);
+ SET_HANDLER(OpCode::WRITE_LOOPBACK_MODE, HciWriteLoopbackMode);
+#undef SET_HANDLER
+}
+
+void DualModeController::HciSniffSubrating(packets::PacketView<true> args) {
+ CHECK(args.size() == 8) << __func__ << " size=" << args.size();
+
+ uint16_t handle = args.begin().extract<uint16_t>();
+
+ send_event_(packets::EventPacketBuilder::CreateSniffSubratingEvent(hci::Status::SUCCESS, handle)->ToVector());
+}
+
+void DualModeController::RegisterTaskScheduler(
+ std::function<AsyncTaskId(std::chrono::milliseconds, const TaskCallback&)> oneshot_scheduler) {
+ link_layer_controller_.RegisterTaskScheduler(oneshot_scheduler);
+}
+
+void DualModeController::RegisterPeriodicTaskScheduler(
+ std::function<AsyncTaskId(std::chrono::milliseconds, std::chrono::milliseconds, const TaskCallback&)>
+ periodic_scheduler) {
+ link_layer_controller_.RegisterPeriodicTaskScheduler(periodic_scheduler);
+}
+
+void DualModeController::RegisterTaskCancel(std::function<void(AsyncTaskId)> task_cancel) {
+ link_layer_controller_.RegisterTaskCancel(task_cancel);
+}
+
+void DualModeController::HandleAcl(std::shared_ptr<std::vector<uint8_t>> packet) {
+ auto acl_packet = packets::AclPacketView::Create(packet);
+ if (loopback_mode_ == hci::LoopbackMode::LOCAL) {
+ uint16_t handle = acl_packet.GetHandle();
+ send_acl_(packet);
+ send_event_(packets::EventPacketBuilder::CreateNumberOfCompletedPacketsEvent(handle, 1)->ToVector());
+ return;
+ }
+
+ link_layer_controller_.SendAclToRemote(acl_packet);
+}
+
+void DualModeController::HandleSco(std::shared_ptr<std::vector<uint8_t>> packet) {
+ auto sco_packet = packets::ScoPacketView::Create(packet);
+ if (loopback_mode_ == hci::LoopbackMode::LOCAL) {
+ uint16_t handle = sco_packet.GetHandle();
+ send_sco_(packet);
+ send_event_(packets::EventPacketBuilder::CreateNumberOfCompletedPacketsEvent(handle, 1)->ToVector());
+ return;
+ }
+}
+
+void DualModeController::HandleCommand(std::shared_ptr<std::vector<uint8_t>> packet) {
+ auto command_packet = packets::CommandPacketView::Create(packet);
+ uint16_t opcode = command_packet.GetOpcode();
+ hci::OpCode op = static_cast<hci::OpCode>(opcode);
+
+ if (loopback_mode_ == hci::LoopbackMode::LOCAL &&
+ // Loopback exceptions.
+ op != OpCode::RESET && op != OpCode::SET_CONTROLLER_TO_HOST_FLOW_CONTROL && op != OpCode::HOST_BUFFER_SIZE &&
+ op != OpCode::HOST_NUM_COMPLETED_PACKETS && op != OpCode::READ_BUFFER_SIZE && op != OpCode::READ_LOOPBACK_MODE &&
+ op != OpCode::WRITE_LOOPBACK_MODE) {
+ send_event_(packets::EventPacketBuilder::CreateLoopbackCommandEvent(op, command_packet.GetPayload())->ToVector());
+ } else if (active_hci_commands_.count(opcode) > 0) {
+ active_hci_commands_[opcode](command_packet.GetPayload());
+ } else {
+ SendCommandCompleteUnknownOpCodeEvent(opcode);
+ LOG_INFO(LOG_TAG, "Command opcode: 0x%04X, OGF: 0x%04X, OCF: 0x%04X", opcode, opcode & 0xFC00, opcode & 0x03FF);
+ }
+}
+
+void DualModeController::RegisterEventChannel(
+ const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& callback) {
+ link_layer_controller_.RegisterEventChannel(callback);
+ send_event_ = callback;
+}
+
+void DualModeController::RegisterAclChannel(
+ const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& callback) {
+ link_layer_controller_.RegisterAclChannel(callback);
+ send_acl_ = callback;
+}
+
+void DualModeController::RegisterScoChannel(
+ const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& callback) {
+ link_layer_controller_.RegisterScoChannel(callback);
+ send_sco_ = callback;
+}
+
+void DualModeController::HciReset(packets::PacketView<true> args) {
+ CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+ link_layer_controller_.Reset();
+ if (loopback_mode_ == hci::LoopbackMode::LOCAL) {
+ loopback_mode_ = hci::LoopbackMode::NO;
+ }
+
+ SendCommandCompleteSuccess(OpCode::RESET);
+}
+
+void DualModeController::HciReadBufferSize(packets::PacketView<true> args) {
+ CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+ std::shared_ptr<packets::EventPacketBuilder> command_complete =
+ packets::EventPacketBuilder::CreateCommandCompleteReadBufferSize(
+ hci::Status::SUCCESS, properties_.GetAclDataPacketSize(), properties_.GetSynchronousDataPacketSize(),
+ properties_.GetTotalNumAclDataPackets(), properties_.GetTotalNumSynchronousDataPackets());
+
+ send_event_(command_complete->ToVector());
+}
+
+void DualModeController::HciHostBufferSize(packets::PacketView<true> args) {
+ CHECK(args.size() == 7) << __func__ << " size=" << args.size();
+ SendCommandCompleteSuccess(OpCode::HOST_BUFFER_SIZE);
+}
+
+void DualModeController::HciReadLocalVersionInformation(packets::PacketView<true> args) {
+ CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+ std::shared_ptr<packets::EventPacketBuilder> command_complete =
+ packets::EventPacketBuilder::CreateCommandCompleteReadLocalVersionInformation(
+ hci::Status::SUCCESS, properties_.GetVersion(), properties_.GetRevision(), properties_.GetLmpPalVersion(),
+ properties_.GetManufacturerName(), properties_.GetLmpPalSubversion());
+ send_event_(command_complete->ToVector());
+}
+
+void DualModeController::HciReadRemoteVersionInformation(packets::PacketView<true> args) {
+ CHECK(args.size() == 2) << __func__ << " size=" << args.size();
+
+ uint16_t handle = args.begin().extract<uint16_t>();
+
+ hci::Status status =
+ link_layer_controller_.SendCommandToRemoteByHandle(OpCode::READ_REMOTE_VERSION_INFORMATION, args, handle);
+
+ SendCommandStatus(status, OpCode::READ_REMOTE_VERSION_INFORMATION);
+}
+
+void DualModeController::HciReadBdAddr(packets::PacketView<true> args) {
+ CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+ std::shared_ptr<packets::EventPacketBuilder> command_complete =
+ packets::EventPacketBuilder::CreateCommandCompleteReadBdAddr(hci::Status::SUCCESS, properties_.GetAddress());
+ send_event_(command_complete->ToVector());
+}
+
+void DualModeController::HciReadLocalSupportedCommands(packets::PacketView<true> args) {
+ CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+ std::shared_ptr<packets::EventPacketBuilder> command_complete =
+ packets::EventPacketBuilder::CreateCommandCompleteReadLocalSupportedCommands(hci::Status::SUCCESS,
+ properties_.GetSupportedCommands());
+ send_event_(command_complete->ToVector());
+}
+
+void DualModeController::HciReadLocalSupportedCodecs(packets::PacketView<true> args) {
+ CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+ std::shared_ptr<packets::EventPacketBuilder> command_complete =
+ packets::EventPacketBuilder::CreateCommandCompleteReadLocalSupportedCodecs(
+ hci::Status::SUCCESS, properties_.GetSupportedCodecs(), properties_.GetVendorSpecificCodecs());
+ send_event_(command_complete->ToVector());
+}
+
+void DualModeController::HciReadLocalExtendedFeatures(packets::PacketView<true> args) {
+ CHECK(args.size() == 1) << __func__ << " size=" << args.size();
+ uint8_t page_number = args.begin().extract<uint8_t>();
+ send_event_(packets::EventPacketBuilder::CreateCommandCompleteReadLocalExtendedFeatures(
+ hci::Status::SUCCESS, page_number, properties_.GetExtendedFeaturesMaximumPageNumber(),
+ properties_.GetExtendedFeatures(page_number))
+ ->ToVector());
+}
+
+void DualModeController::HciReadRemoteExtendedFeatures(packets::PacketView<true> args) {
+ CHECK(args.size() == 3) << __func__ << " size=" << args.size();
+
+ uint16_t handle = args.begin().extract<uint16_t>();
+
+ hci::Status status =
+ link_layer_controller_.SendCommandToRemoteByHandle(OpCode::READ_REMOTE_EXTENDED_FEATURES, args, handle);
+
+ SendCommandStatus(status, OpCode::READ_REMOTE_EXTENDED_FEATURES);
+}
+
+void DualModeController::HciReadRemoteSupportedFeatures(packets::PacketView<true> args) {
+ CHECK(args.size() == 2) << __func__ << " size=" << args.size();
+
+ uint16_t handle = args.begin().extract<uint16_t>();
+
+ hci::Status status =
+ link_layer_controller_.SendCommandToRemoteByHandle(OpCode::READ_REMOTE_SUPPORTED_FEATURES, args, handle);
+
+ SendCommandStatus(status, OpCode::READ_REMOTE_SUPPORTED_FEATURES);
+}
+
+void DualModeController::HciReadClockOffset(packets::PacketView<true> args) {
+ CHECK(args.size() == 2) << __func__ << " size=" << args.size();
+
+ uint16_t handle = args.begin().extract<uint16_t>();
+
+ hci::Status status = link_layer_controller_.SendCommandToRemoteByHandle(OpCode::READ_CLOCK_OFFSET, args, handle);
+
+ SendCommandStatus(status, OpCode::READ_CLOCK_OFFSET);
+}
+
+void DualModeController::HciIoCapabilityRequestReply(packets::PacketView<true> args) {
+ CHECK(args.size() == 9) << __func__ << " size=" << args.size();
+
+ auto args_itr = args.begin();
+ Address peer = args_itr.extract<Address>();
+ uint8_t io_capability = args_itr.extract<uint8_t>();
+ uint8_t oob_data_present_flag = args_itr.extract<uint8_t>();
+ uint8_t authentication_requirements = args_itr.extract<uint8_t>();
+
+ hci::Status status = link_layer_controller_.IoCapabilityRequestReply(peer, io_capability, oob_data_present_flag,
+ authentication_requirements);
+
+ SendCommandCompleteStatusAndAddress(OpCode::IO_CAPABILITY_REQUEST_REPLY, status, peer);
+}
+
+void DualModeController::HciUserConfirmationRequestReply(packets::PacketView<true> args) {
+ CHECK(args.size() == 6) << __func__ << " size=" << args.size();
+
+ Address peer = args.begin().extract<Address>();
+
+ hci::Status status = link_layer_controller_.UserConfirmationRequestReply(peer);
+
+ SendCommandCompleteStatusAndAddress(OpCode::USER_CONFIRMATION_REQUEST_REPLY, status, peer);
+}
+
+void DualModeController::HciUserConfirmationRequestNegativeReply(packets::PacketView<true> args) {
+ CHECK(args.size() == 6) << __func__ << " size=" << args.size();
+
+ Address peer = args.begin().extract<Address>();
+
+ hci::Status status = link_layer_controller_.UserConfirmationRequestNegativeReply(peer);
+
+ SendCommandCompleteStatusAndAddress(OpCode::USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY, status, peer);
+}
+
+void DualModeController::HciUserPasskeyRequestReply(packets::PacketView<true> args) {
+ CHECK(args.size() == 10) << __func__ << " size=" << args.size();
+
+ auto args_itr = args.begin();
+ Address peer = args_itr.extract<Address>();
+ uint32_t numeric_value = args_itr.extract<uint32_t>();
+
+ hci::Status status = link_layer_controller_.UserPasskeyRequestReply(peer, numeric_value);
+
+ SendCommandCompleteStatusAndAddress(OpCode::USER_PASSKEY_REQUEST_REPLY, status, peer);
+}
+
+void DualModeController::HciUserPasskeyRequestNegativeReply(packets::PacketView<true> args) {
+ CHECK(args.size() == 6) << __func__ << " size=" << args.size();
+
+ Address peer = args.begin().extract<Address>();
+
+ hci::Status status = link_layer_controller_.UserPasskeyRequestNegativeReply(peer);
+
+ SendCommandCompleteStatusAndAddress(OpCode::USER_PASSKEY_REQUEST_NEGATIVE_REPLY, status, peer);
+}
+
+void DualModeController::HciRemoteOobDataRequestReply(packets::PacketView<true> args) {
+ CHECK(args.size() == 38) << __func__ << " size=" << args.size();
+
+ auto args_itr = args.begin();
+ Address peer = args_itr.extract<Address>();
+ std::vector<uint8_t> c;
+ std::vector<uint8_t> r;
+ for (size_t i = 0; i < 16; i++) {
+ c.push_back(args_itr.extract<uint8_t>());
+ }
+ for (size_t i = 0; i < 16; i++) {
+ r.push_back(args_itr.extract<uint8_t>());
+ }
+ hci::Status status = link_layer_controller_.RemoteOobDataRequestReply(peer, c, r);
+
+ SendCommandCompleteStatusAndAddress(OpCode::REMOTE_OOB_DATA_REQUEST_REPLY, status, peer);
+}
+
+void DualModeController::HciRemoteOobDataRequestNegativeReply(packets::PacketView<true> args) {
+ CHECK(args.size() == 6) << __func__ << " size=" << args.size();
+
+ Address peer = args.begin().extract<Address>();
+
+ hci::Status status = link_layer_controller_.RemoteOobDataRequestNegativeReply(peer);
+
+ SendCommandCompleteStatusAndAddress(OpCode::REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY, status, peer);
+}
+
+void DualModeController::HciIoCapabilityRequestNegativeReply(packets::PacketView<true> args) {
+ CHECK(args.size() == 7) << __func__ << " size=" << args.size();
+
+ auto args_itr = args.begin();
+ Address peer = args_itr.extract<Address>();
+ hci::Status reason = args_itr.extract<hci::Status>();
+
+ hci::Status status = link_layer_controller_.IoCapabilityRequestNegativeReply(peer, reason);
+
+ SendCommandCompleteStatusAndAddress(OpCode::IO_CAPABILITY_REQUEST_NEGATIVE_REPLY, status, peer);
+}
+
+void DualModeController::HciWriteSimplePairingMode(packets::PacketView<true> args) {
+ CHECK(args.size() == 1) << __func__ << " size=" << args.size();
+ CHECK(args[0] == 1 || args[0] == 0);
+ link_layer_controller_.WriteSimplePairingMode(args[0] == 1);
+ SendCommandCompleteSuccess(OpCode::WRITE_SIMPLE_PAIRING_MODE);
+}
+
+void DualModeController::HciChangeConnectionPacketType(packets::PacketView<true> args) {
+ CHECK(args.size() == 4) << __func__ << " size=" << args.size();
+ auto args_itr = args.begin();
+ uint16_t handle = args_itr.extract<uint16_t>();
+ uint16_t packet_type = args_itr.extract<uint16_t>();
+
+ hci::Status status = link_layer_controller_.ChangeConnectionPacketType(handle, packet_type);
+
+ SendCommandStatus(status, OpCode::CHANGE_CONNECTION_PACKET_TYPE);
+}
+
+void DualModeController::HciWriteLeHostSupport(packets::PacketView<true> args) {
+ CHECK(args.size() == 2) << __func__ << " size=" << args.size();
+ SendCommandCompleteSuccess(OpCode::WRITE_LE_HOST_SUPPORT);
+}
+
+void DualModeController::HciSetEventMask(packets::PacketView<true> args) {
+ CHECK(args.size() == 8) << __func__ << " size=" << args.size();
+ SendCommandCompleteSuccess(OpCode::SET_EVENT_MASK);
+}
+
+void DualModeController::HciWriteInquiryMode(packets::PacketView<true> args) {
+ CHECK(args.size() == 1) << __func__ << " size=" << args.size();
+ link_layer_controller_.SetInquiryMode(args[0]);
+ SendCommandCompleteSuccess(OpCode::WRITE_INQUIRY_MODE);
+}
+
+void DualModeController::HciWritePageScanType(packets::PacketView<true> args) {
+ CHECK(args.size() == 1) << __func__ << " size=" << args.size();
+ SendCommandCompleteSuccess(OpCode::WRITE_PAGE_SCAN_TYPE);
+}
+
+void DualModeController::HciWriteInquiryScanType(packets::PacketView<true> args) {
+ CHECK(args.size() == 1) << __func__ << " size=" << args.size();
+ SendCommandCompleteSuccess(OpCode::WRITE_INQUIRY_SCAN_TYPE);
+}
+
+void DualModeController::HciAuthenticationRequested(packets::PacketView<true> args) {
+ CHECK(args.size() == 2) << __func__ << " size=" << args.size();
+ uint16_t handle = args.begin().extract<uint16_t>();
+ hci::Status status = link_layer_controller_.AuthenticationRequested(handle);
+
+ SendCommandStatus(status, OpCode::AUTHENTICATION_REQUESTED);
+}
+
+void DualModeController::HciSetConnectionEncryption(packets::PacketView<true> args) {
+ CHECK(args.size() == 3) << __func__ << " size=" << args.size();
+ auto args_itr = args.begin();
+ uint16_t handle = args_itr.extract<uint16_t>();
+ uint8_t encryption_enable = args_itr.extract<uint8_t>();
+ hci::Status status = link_layer_controller_.SetConnectionEncryption(handle, encryption_enable);
+
+ SendCommandStatus(status, OpCode::SET_CONNECTION_ENCRYPTION);
+}
+
+void DualModeController::HciWriteAuthenticationEnable(packets::PacketView<true> args) {
+ CHECK(args.size() == 1) << __func__ << " size=" << args.size();
+ properties_.SetAuthenticationEnable(args[0]);
+ SendCommandCompleteSuccess(OpCode::WRITE_AUTHENTICATION_ENABLE);
+}
+
+void DualModeController::HciReadAuthenticationEnable(packets::PacketView<true> args) {
+ CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+ std::shared_ptr<packets::EventPacketBuilder> command_complete =
+ packets::EventPacketBuilder::CreateCommandCompleteReadAuthenticationEnable(hci::Status::SUCCESS,
+ properties_.GetAuthenticationEnable());
+ send_event_(command_complete->ToVector());
+}
+
+void DualModeController::HciWriteClassOfDevice(packets::PacketView<true> args) {
+ CHECK(args.size() == 3) << __func__ << " size=" << args.size();
+ properties_.SetClassOfDevice(args[0], args[1], args[2]);
+ SendCommandCompleteSuccess(OpCode::WRITE_CLASS_OF_DEVICE);
+}
+
+void DualModeController::HciWritePageTimeout(packets::PacketView<true> args) {
+ CHECK(args.size() == 2) << __func__ << " size=" << args.size();
+ SendCommandCompleteSuccess(OpCode::WRITE_PAGE_TIMEOUT);
+}
+
+void DualModeController::HciWriteDefaultLinkPolicySettings(packets::PacketView<true> args) {
+ CHECK(args.size() == 2) << __func__ << " size=" << args.size();
+ SendCommandCompleteSuccess(OpCode::WRITE_DEFAULT_LINK_POLICY_SETTINGS);
+}
+
+void DualModeController::HciWriteLinkPolicySettings(packets::PacketView<true> args) {
+ CHECK(args.size() == 4) << __func__ << " size=" << args.size();
+
+ auto args_itr = args.begin();
+ uint16_t handle = args_itr.extract<uint16_t>();
+ uint16_t settings = args_itr.extract<uint16_t>();
+
+ hci::Status status = link_layer_controller_.WriteLinkPolicySettings(handle, settings);
+
+ send_event_(packets::EventPacketBuilder::CreateCommandCompleteWriteLinkPolicySettings(status, handle)->ToVector());
+}
+
+void DualModeController::HciWriteLinkSupervisionTimeout(packets::PacketView<true> args) {
+ CHECK(args.size() == 4) << __func__ << " size=" << args.size();
+
+ auto args_itr = args.begin();
+ uint16_t handle = args_itr.extract<uint16_t>();
+ uint16_t timeout = args_itr.extract<uint16_t>();
+
+ hci::Status status = link_layer_controller_.WriteLinkSupervisionTimeout(handle, timeout);
+
+ send_event_(
+ packets::EventPacketBuilder::CreateCommandCompleteWriteLinkSupervisionTimeout(status, handle)->ToVector());
+}
+
+void DualModeController::HciReadLocalName(packets::PacketView<true> args) {
+ CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+ std::shared_ptr<packets::EventPacketBuilder> command_complete =
+ packets::EventPacketBuilder::CreateCommandCompleteReadLocalName(hci::Status::SUCCESS, properties_.GetName());
+ send_event_(command_complete->ToVector());
+}
+
+void DualModeController::HciWriteLocalName(packets::PacketView<true> args) {
+ CHECK(args.size() == 248) << __func__ << " size=" << args.size();
+ std::vector<uint8_t> clipped(args.begin(), args.begin() + LastNonZero(args) + 1);
+ properties_.SetName(clipped);
+ SendCommandCompleteSuccess(OpCode::WRITE_LOCAL_NAME);
+}
+
+void DualModeController::HciWriteExtendedInquiryResponse(packets::PacketView<true> args) {
+ CHECK(args.size() == 241) << __func__ << " size=" << args.size();
+ // Strip FEC byte and trailing zeros
+ std::vector<uint8_t> clipped(args.begin() + 1, args.begin() + LastNonZero(args) + 1);
+ properties_.SetExtendedInquiryData(clipped);
+ LOG_WARN(LOG_TAG, "Write EIR Inquiry - Size = %d (%d)", static_cast<int>(properties_.GetExtendedInquiryData().size()),
+ static_cast<int>(clipped.size()));
+ SendCommandCompleteSuccess(OpCode::WRITE_EXTENDED_INQUIRY_RESPONSE);
+}
+
+void DualModeController::HciWriteVoiceSetting(packets::PacketView<true> args) {
+ CHECK(args.size() == 2) << __func__ << " size=" << args.size();
+ SendCommandCompleteSuccess(OpCode::WRITE_VOICE_SETTING);
+}
+
+void DualModeController::HciWriteCurrentIacLap(packets::PacketView<true> args) {
+ CHECK(args.size() > 0);
+ CHECK(args.size() == 1 + (3 * args[0])); // count + 3-byte IACs
+
+ SendCommandCompleteSuccess(OpCode::WRITE_CURRENT_IAC_LAP);
+}
+
+void DualModeController::HciWriteInquiryScanActivity(packets::PacketView<true> args) {
+ CHECK(args.size() == 4) << __func__ << " size=" << args.size();
+ SendCommandCompleteSuccess(OpCode::WRITE_INQUIRY_SCAN_ACTIVITY);
+}
+
+void DualModeController::HciWriteScanEnable(packets::PacketView<true> args) {
+ CHECK(args.size() == 1) << __func__ << " size=" << args.size();
+ link_layer_controller_.SetInquiryScanEnable(args[0] & 0x1);
+ link_layer_controller_.SetPageScanEnable(args[0] & 0x2);
+ SendCommandCompleteSuccess(OpCode::WRITE_SCAN_ENABLE);
+}
+
+void DualModeController::HciSetEventFilter(packets::PacketView<true> args) {
+ CHECK(args.size() > 0);
+ SendCommandCompleteSuccess(OpCode::SET_EVENT_FILTER);
+}
+
+void DualModeController::HciInquiry(packets::PacketView<true> args) {
+ CHECK(args.size() == 5) << __func__ << " size=" << args.size();
+ link_layer_controller_.SetInquiryLAP(args[0] | (args[1] << 8) | (args[2] << 16));
+ link_layer_controller_.SetInquiryMaxResponses(args[4]);
+ link_layer_controller_.StartInquiry(std::chrono::milliseconds(args[3] * 1280));
+
+ SendCommandStatusSuccess(OpCode::INQUIRY);
+}
+
+void DualModeController::HciInquiryCancel(packets::PacketView<true> args) {
+ CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+ link_layer_controller_.InquiryCancel();
+ SendCommandCompleteSuccess(OpCode::INQUIRY_CANCEL);
+}
+
+void DualModeController::HciAcceptConnectionRequest(packets::PacketView<true> args) {
+ CHECK(args.size() == 7) << __func__ << " size=" << args.size();
+ Address addr = args.begin().extract<Address>();
+ bool try_role_switch = args[6] == 0;
+ hci::Status status = link_layer_controller_.AcceptConnectionRequest(addr, try_role_switch);
+ SendCommandStatus(status, OpCode::ACCEPT_CONNECTION_REQUEST);
+}
+
+void DualModeController::HciRejectConnectionRequest(packets::PacketView<true> args) {
+ CHECK(args.size() == 7) << __func__ << " size=" << args.size();
+ auto args_itr = args.begin();
+ Address addr = args_itr.extract<Address>();
+ uint8_t reason = args_itr.extract<uint8_t>();
+ hci::Status status = link_layer_controller_.RejectConnectionRequest(addr, reason);
+ SendCommandStatus(status, OpCode::REJECT_CONNECTION_REQUEST);
+}
+
+void DualModeController::HciLinkKeyRequestReply(packets::PacketView<true> args) {
+ CHECK(args.size() == 22) << __func__ << " size=" << args.size();
+ Address addr = args.begin().extract<Address>();
+ packets::PacketView<true> key = args.SubViewLittleEndian(6, 22);
+ hci::Status status = link_layer_controller_.LinkKeyRequestReply(addr, key);
+ send_event_(packets::EventPacketBuilder::CreateCommandCompleteLinkKeyRequestReply(status, addr)->ToVector());
+}
+
+void DualModeController::HciLinkKeyRequestNegativeReply(packets::PacketView<true> args) {
+ CHECK(args.size() == 6) << __func__ << " size=" << args.size();
+ Address addr = args.begin().extract<Address>();
+ hci::Status status = link_layer_controller_.LinkKeyRequestNegativeReply(addr);
+ send_event_(packets::EventPacketBuilder::CreateCommandCompleteLinkKeyRequestNegativeReply(status, addr)->ToVector());
+}
+
+void DualModeController::HciDeleteStoredLinkKey(packets::PacketView<true> args) {
+ CHECK(args.size() == 7) << __func__ << " size=" << args.size();
+
+ uint16_t deleted_keys = 0;
+
+ if (args[6] == 0) {
+ Address addr = args.begin().extract<Address>();
+ deleted_keys = security_manager_.DeleteKey(addr);
+ }
+
+ if (args[6] == 1) {
+ security_manager_.DeleteAllKeys();
+ }
+
+ send_event_(packets::EventPacketBuilder::CreateCommandCompleteDeleteStoredLinkKey(hci::Status::SUCCESS, deleted_keys)
+ ->ToVector());
+}
+
+void DualModeController::HciRemoteNameRequest(packets::PacketView<true> args) {
+ CHECK(args.size() == 10) << __func__ << " size=" << args.size();
+
+ Address remote_addr = args.begin().extract<Address>();
+
+ hci::Status status =
+ link_layer_controller_.SendCommandToRemoteByAddress(OpCode::REMOTE_NAME_REQUEST, args, remote_addr, false);
+
+ SendCommandStatus(status, OpCode::REMOTE_NAME_REQUEST);
+}
+
+void DualModeController::HciLeSetEventMask(packets::PacketView<true> args) {
+ CHECK(args.size() == 8) << __func__ << " size=" << args.size();
+ /*
+ uint64_t mask = args.begin().extract<uint64_t>();
+ link_layer_controller_.SetLeEventMask(mask);
+ */
+ SendCommandCompleteSuccess(OpCode::LE_SET_EVENT_MASK);
+}
+
+void DualModeController::HciLeReadBufferSize(packets::PacketView<true> args) {
+ CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+ std::shared_ptr<packets::EventPacketBuilder> command_complete =
+ packets::EventPacketBuilder::CreateCommandCompleteLeReadBufferSize(
+ hci::Status::SUCCESS, properties_.GetLeDataPacketLength(), properties_.GetTotalNumLeDataPackets());
+ send_event_(command_complete->ToVector());
+}
+
+void DualModeController::HciLeReadLocalSupportedFeatures(packets::PacketView<true> args) {
+ CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+ std::shared_ptr<packets::EventPacketBuilder> command_complete =
+ packets::EventPacketBuilder::CreateCommandCompleteLeReadLocalSupportedFeatures(
+ hci::Status::SUCCESS, properties_.GetLeSupportedFeatures());
+ send_event_(command_complete->ToVector());
+}
+
+void DualModeController::HciLeSetRandomAddress(packets::PacketView<true> args) {
+ CHECK(args.size() == 6) << __func__ << " size=" << args.size();
+ properties_.SetLeAddress(args.begin().extract<Address>());
+ SendCommandCompleteSuccess(OpCode::LE_SET_RANDOM_ADDRESS);
+}
+
+void DualModeController::HciLeSetAdvertisingParameters(packets::PacketView<true> args) {
+ CHECK(args.size() == 15) << __func__ << " size=" << args.size();
+
+ SendCommandCompleteSuccess(OpCode::LE_SET_ADVERTISING_PARAMETERS);
+}
+
+void DualModeController::HciLeSetAdvertisingData(packets::PacketView<true> args) {
+ CHECK(args.size() > 0);
+ SendCommandCompleteSuccess(OpCode::LE_SET_ADVERTISING_DATA);
+}
+
+void DualModeController::HciLeSetScanParameters(packets::PacketView<true> args) {
+ CHECK(args.size() == 7) << __func__ << " size=" << args.size();
+ link_layer_controller_.SetLeScanType(args[0]);
+ link_layer_controller_.SetLeScanInterval(args[1] | (args[2] << 8));
+ link_layer_controller_.SetLeScanWindow(args[3] | (args[4] << 8));
+ link_layer_controller_.SetLeAddressType(args[5]);
+ link_layer_controller_.SetLeScanFilterPolicy(args[6]);
+ SendCommandCompleteSuccess(OpCode::LE_SET_SCAN_PARAMETERS);
+}
+
+void DualModeController::HciLeSetScanEnable(packets::PacketView<true> args) {
+ CHECK(args.size() == 2) << __func__ << " size=" << args.size();
+ LOG_INFO(LOG_TAG, "SetScanEnable: %d %d", args[0], args[1]);
+ link_layer_controller_.SetLeScanEnable(args[0]);
+ link_layer_controller_.SetLeFilterDuplicates(args[1]);
+ SendCommandCompleteSuccess(OpCode::LE_SET_SCAN_ENABLE);
+}
+
+void DualModeController::HciLeCreateConnection(packets::PacketView<true> args) {
+ CHECK(args.size() == 25) << __func__ << " size=" << args.size();
+ auto args_itr = args.begin();
+ link_layer_controller_.SetLeScanInterval(args_itr.extract<uint16_t>());
+ link_layer_controller_.SetLeScanWindow(args_itr.extract<uint16_t>());
+ uint8_t initiator_filter_policy = args_itr.extract<uint8_t>();
+ link_layer_controller_.SetLeInitiatorFilterPolicy(initiator_filter_policy);
+
+ if (initiator_filter_policy == 0) { // White list not used
+ uint8_t peer_address_type = args_itr.extract<uint8_t>();
+ Address peer_address = args_itr.extract<Address>();
+ link_layer_controller_.SetLePeerAddressType(peer_address_type);
+ link_layer_controller_.SetLePeerAddress(peer_address);
+ }
+ link_layer_controller_.SetLeAddressType(args_itr.extract<uint8_t>());
+ link_layer_controller_.SetLeConnectionIntervalMin(args_itr.extract<uint16_t>());
+ link_layer_controller_.SetLeConnectionIntervalMax(args_itr.extract<uint16_t>());
+ link_layer_controller_.SetLeConnectionLatency(args_itr.extract<uint16_t>());
+ link_layer_controller_.SetLeSupervisionTimeout(args_itr.extract<uint16_t>());
+ link_layer_controller_.SetLeMinimumCeLength(args_itr.extract<uint16_t>());
+ link_layer_controller_.SetLeMaximumCeLength(args_itr.extract<uint16_t>());
+
+ hci::Status status = link_layer_controller_.SetLeConnect(true);
+
+ SendCommandStatus(status, OpCode::LE_CREATE_CONNECTION);
+}
+
+void DualModeController::HciLeConnectionUpdate(packets::PacketView<true> args) {
+ CHECK(args.size() == 14) << __func__ << " size=" << args.size();
+
+ SendCommandStatus(hci::Status::CONNECTION_REJECTED_UNACCEPTABLE_BD_ADDR, OpCode::LE_CONNECTION_UPDATE);
+
+ send_event_(packets::EventPacketBuilder::CreateLeConnectionUpdateCompleteEvent(hci::Status::SUCCESS, 0x0002, 0x0006,
+ 0x0000, 0x01f4)
+ ->ToVector());
+}
+
+void DualModeController::HciCreateConnection(packets::PacketView<true> args) {
+ CHECK(args.size() == 13) << __func__ << " size=" << args.size();
+
+ auto args_itr = args.begin();
+ Address address = args_itr.extract<Address>();
+ uint16_t packet_type = args_itr.extract<uint16_t>();
+ uint8_t page_scan_mode = args_itr.extract<uint8_t>();
+ uint16_t clock_offset = args_itr.extract<uint16_t>();
+ uint8_t allow_role_switch = args_itr.extract<uint8_t>();
+
+ hci::Status status =
+ link_layer_controller_.CreateConnection(address, packet_type, page_scan_mode, clock_offset, allow_role_switch);
+
+ SendCommandStatus(status, OpCode::CREATE_CONNECTION);
+}
+
+void DualModeController::HciDisconnect(packets::PacketView<true> args) {
+ CHECK(args.size() == 3) << __func__ << " size=" << args.size();
+
+ auto args_itr = args.begin();
+ uint16_t handle = args_itr.extract<uint16_t>();
+ uint8_t reason = args_itr.extract<uint8_t>();
+
+ hci::Status status = link_layer_controller_.Disconnect(handle, reason);
+
+ SendCommandStatus(status, OpCode::DISCONNECT);
+}
+
+void DualModeController::HciLeConnectionCancel(packets::PacketView<true> args) {
+ CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+ link_layer_controller_.SetLeConnect(false);
+ SendCommandStatusSuccess(OpCode::LE_CREATE_CONNECTION_CANCEL);
+ /* For testing Jakub's patch: Figure out a neat way to call this without
+ recompiling. I'm thinking about a bad device. */
+ /*
+ SendCommandCompleteOnlyStatus(OpCode::LE_CREATE_CONNECTION_CANCEL,
+ Status::ERR_COMMAND_DISALLOWED);
+ */
+}
+
+void DualModeController::HciLeReadWhiteListSize(packets::PacketView<true> args) {
+ CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+ std::shared_ptr<packets::EventPacketBuilder> command_complete =
+ packets::EventPacketBuilder::CreateCommandCompleteLeReadWhiteListSize(hci::Status::SUCCESS,
+ properties_.GetLeWhiteListSize());
+ send_event_(command_complete->ToVector());
+}
+
+void DualModeController::HciLeClearWhiteList(packets::PacketView<true> args) {
+ CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+ link_layer_controller_.LeWhiteListClear();
+ SendCommandCompleteSuccess(OpCode::LE_CLEAR_WHITE_LIST);
+}
+
+void DualModeController::HciLeAddDeviceToWhiteList(packets::PacketView<true> args) {
+ CHECK(args.size() == 7) << __func__ << " size=" << args.size();
+
+ if (link_layer_controller_.LeWhiteListFull()) {
+ SendCommandCompleteOnlyStatus(OpCode::LE_ADD_DEVICE_TO_WHITE_LIST, hci::Status::MEMORY_CAPACITY_EXCEEDED);
+ return;
+ }
+ auto args_itr = args.begin();
+ uint8_t addr_type = args_itr.extract<uint8_t>();
+ Address address = args_itr.extract<Address>();
+ link_layer_controller_.LeWhiteListAddDevice(address, addr_type);
+ SendCommandCompleteSuccess(OpCode::LE_ADD_DEVICE_TO_WHITE_LIST);
+}
+
+void DualModeController::HciLeRemoveDeviceFromWhiteList(packets::PacketView<true> args) {
+ CHECK(args.size() == 7) << __func__ << " size=" << args.size();
+
+ auto args_itr = args.begin();
+ uint8_t addr_type = args_itr.extract<uint8_t>();
+ Address address = args_itr.extract<Address>();
+ link_layer_controller_.LeWhiteListRemoveDevice(address, addr_type);
+ SendCommandCompleteSuccess(OpCode::LE_REMOVE_DEVICE_FROM_WHITE_LIST);
+}
+
+/*
+void DualModeController::HciLeReadRemoteUsedFeaturesRsp(uint16_t handle,
+ uint64_t features) {
+ std::shared_ptr<packets::EventPacketBuilder> event =
+ packets::EventPacketBuilder::CreateLeRemoteUsedFeaturesEvent(
+ hci::Status::SUCCESS, handle, features);
+ send_event_(event->ToVector());
+}
+*/
+
+void DualModeController::HciLeReadRemoteFeatures(packets::PacketView<true> args) {
+ CHECK(args.size() == 2) << __func__ << " size=" << args.size();
+
+ uint16_t handle = args.begin().extract<uint16_t>();
+
+ hci::Status status =
+ link_layer_controller_.SendCommandToRemoteByHandle(OpCode::LE_READ_REMOTE_FEATURES, args, handle);
+
+ SendCommandStatus(status, OpCode::LE_READ_REMOTE_FEATURES);
+}
+
+void DualModeController::HciLeRand(packets::PacketView<true> args) {
+ CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+ uint64_t random_val = 0;
+ for (size_t rand_bytes = 0; rand_bytes < sizeof(uint64_t); rand_bytes += sizeof(RAND_MAX)) {
+ random_val = (random_val << (8 * sizeof(RAND_MAX))) | random();
+ }
+ std::shared_ptr<packets::EventPacketBuilder> command_complete =
+ packets::EventPacketBuilder::CreateCommandCompleteLeRand(hci::Status::SUCCESS, random_val);
+ send_event_(command_complete->ToVector());
+}
+
+void DualModeController::HciLeReadSupportedStates(packets::PacketView<true> args) {
+ CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+ std::shared_ptr<packets::EventPacketBuilder> command_complete =
+ packets::EventPacketBuilder::CreateCommandCompleteLeReadSupportedStates(hci::Status::SUCCESS,
+ properties_.GetLeSupportedStates());
+ send_event_(command_complete->ToVector());
+}
+
+void DualModeController::HciLeVendorCap(packets::PacketView<true> args) {
+ CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+ vector<uint8_t> caps = properties_.GetLeVendorCap();
+ if (caps.size() == 0) {
+ SendCommandCompleteOnlyStatus(OpCode::LE_GET_VENDOR_CAPABILITIES, hci::Status::UNKNOWN_COMMAND);
+ return;
+ }
+
+ std::shared_ptr<packets::EventPacketBuilder> command_complete =
+ packets::EventPacketBuilder::CreateCommandCompleteLeGetVendorCapabilities(hci::Status::SUCCESS,
+ properties_.GetLeVendorCap());
+ send_event_(command_complete->ToVector());
+}
+
+void DualModeController::HciLeVendorMultiAdv(packets::PacketView<true> args) {
+ CHECK(args.size() > 0);
+ SendCommandCompleteOnlyStatus(OpCode::LE_MULTI_ADVT, hci::Status::UNKNOWN_COMMAND);
+}
+
+void DualModeController::HciLeAdvertisingFilter(packets::PacketView<true> args) {
+ CHECK(args.size() > 0);
+ SendCommandCompleteOnlyStatus(OpCode::LE_ADV_FILTER, hci::Status::UNKNOWN_COMMAND);
+}
+
+void DualModeController::HciLeEnergyInfo(packets::PacketView<true> args) {
+ CHECK(args.size() > 0);
+ SendCommandCompleteOnlyStatus(OpCode::LE_ENERGY_INFO, hci::Status::UNKNOWN_COMMAND);
+}
+
+void DualModeController::HciLeExtendedScanParams(packets::PacketView<true> args) {
+ CHECK(args.size() > 0);
+ SendCommandCompleteOnlyStatus(OpCode::LE_EXTENDED_SCAN_PARAMS, hci::Status::UNKNOWN_COMMAND);
+}
+
+void DualModeController::HciLeStartEncryption(packets::PacketView<true> args) {
+ CHECK(args.size() == 28) << __func__ << " size=" << args.size();
+
+ auto args_itr = args.begin();
+ uint16_t handle = args_itr.extract<uint16_t>();
+ // uint64_t random_number = args_itr.extract<uint64_t>();
+ // uint16_t encrypted_diversifier = args_itr.extract<uint16_t>();
+ // std::vector<uint8_t> long_term_key;
+ // for (size_t i = 0; i < 16; i++) {
+ // long_term_key.push_back(args_itr.extract<uint18_t>();
+ // }
+ SendCommandStatus(hci::Status::SUCCESS, OpCode::LE_START_ENCRYPTION);
+
+ send_event_(packets::EventPacketBuilder::CreateEncryptionChange(hci::Status::SUCCESS, handle, 0x01)->ToVector());
+#if 0
+
+ std::shared_ptr<packets::AclPacketBuilder> encryption_information =
+ std::make_shared<packets::AclPacketBuilder>(
+ 0x0002, Acl::FIRST_AUTOMATICALLY_FLUSHABLE, Acl::POINT_TO_POINT,
+ std::vector<uint8_t>({}));
+
+ encryption_information->AddPayloadOctets2(0x0011);
+ encryption_information->AddPayloadOctets2(0x0006);
+ encryption_information->AddPayloadOctets1(0x06);
+ encryption_information->AddPayloadOctets8(0x0706050403020100);
+ encryption_information->AddPayloadOctets8(0x0F0E0D0C0B0A0908);
+
+ send_acl_(encryption_information);
+
+ encryption_information = std::make_shared<packets::AclPacketBuilder>(
+ 0x0002, Acl::FIRST_AUTOMATICALLY_FLUSHABLE, Acl::POINT_TO_POINT,
+ std::vector<uint8_t>({}));
+
+ encryption_information->AddPayloadOctets2(0x000B);
+ encryption_information->AddPayloadOctets2(0x0006);
+ encryption_information->AddPayloadOctets1(0x07);
+ encryption_information->AddPayloadOctets2(0xBEEF);
+ encryption_information->AddPayloadOctets8(0x0706050403020100);
+
+ send_acl_(encryption_information);
+
+ encryption_information = std::make_shared<packets::AclPacketBuilder>(
+ 0x0002, Acl::FIRST_AUTOMATICALLY_FLUSHABLE, Acl::POINT_TO_POINT,
+ std::vector<uint8_t>({}));
+
+ encryption_information->AddPayloadOctets2(0x0011);
+ encryption_information->AddPayloadOctets2(0x0006);
+ encryption_information->AddPayloadOctets1(0x08);
+ encryption_information->AddPayloadOctets8(0x0F0E0D0C0B0A0908);
+ encryption_information->AddPayloadOctets8(0x0706050403020100);
+
+ send_acl_(encryption_information);
+
+ encryption_information = std::make_shared<packets::AclPacketBuilder>(
+ 0x0002, Acl::FIRST_AUTOMATICALLY_FLUSHABLE, Acl::POINT_TO_POINT,
+ std::vector<uint8_t>({}));
+
+ encryption_information->AddPayloadOctets2(0x0008);
+ encryption_information->AddPayloadOctets2(0x0006);
+ encryption_information->AddPayloadOctets1(0x09);
+ encryption_information->AddPayloadOctets1(0x01);
+ encryption_information->AddPayloadOctets6(0xDEADBEEFF00D);
+ send_acl_(encryption_information);
+ // send_event_(packets::EventPacketBuilder::CreateLeStartEncryption()->ToVector());
+
+#endif
+}
+
+void DualModeController::HciReadLoopbackMode(packets::PacketView<true> args) {
+ CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+ send_event_(packets::EventPacketBuilder::CreateCommandCompleteReadLoopbackMode(hci::Status::SUCCESS, loopback_mode_)
+ ->ToVector());
+}
+
+void DualModeController::HciWriteLoopbackMode(packets::PacketView<true> args) {
+ CHECK(args.size() == 1) << __func__ << " size=" << args.size();
+ loopback_mode_ = static_cast<hci::LoopbackMode>(args[0]);
+ // ACL channel
+ uint16_t acl_handle = 0x123;
+ send_event_(packets::EventPacketBuilder::CreateConnectionCompleteEvent(
+ hci::Status::SUCCESS, acl_handle, properties_.GetAddress(), hci::LinkType::ACL, false)
+ ->ToVector());
+ // SCO channel
+ uint16_t sco_handle = 0x345;
+ send_event_(packets::EventPacketBuilder::CreateConnectionCompleteEvent(
+ hci::Status::SUCCESS, sco_handle, properties_.GetAddress(), hci::LinkType::SCO, false)
+ ->ToVector());
+ SendCommandCompleteSuccess(OpCode::WRITE_LOOPBACK_MODE);
+}
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.h b/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.h
new file mode 100644
index 0000000..f33bbb8
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.h
@@ -0,0 +1,405 @@
+/*
+ * 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 <unistd.h>
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "base/time/time.h"
+#include "link_layer_controller.h"
+#include "model/devices/device.h"
+#include "model/setup/async_manager.h"
+#include "security_manager.h"
+#include "types/address.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 Device {
+ // The location of the config file loaded to populate controller attributes.
+ static constexpr char kControllerPropertiesFile[] = "/etc/bluetooth/controller_properties.json";
+ static constexpr uint16_t kSecurityManagerNumKeys = 15;
+
+ public:
+ // Sets all of the methods to be used as callbacks in the HciHandler.
+ DualModeController(const std::string& properties_filename = std::string(kControllerPropertiesFile),
+ uint16_t num_keys = kSecurityManagerNumKeys);
+
+ ~DualModeController() = default;
+
+ // Device methods.
+ virtual void Initialize(const std::vector<std::string>& args) override;
+
+ virtual std::string GetTypeString() const override;
+
+ virtual void IncomingPacket(packets::LinkLayerPacketView incoming) override;
+
+ virtual void TimerTick() override;
+
+ // Send packets to remote devices
+ void SendLinkLayerPacket(std::shared_ptr<packets::LinkLayerPacketBuilder> to_send, Phy::Type phy_type);
+
+ // Route commands and data from the stack.
+ void HandleAcl(std::shared_ptr<std::vector<uint8_t>> acl_packet);
+ void HandleCommand(std::shared_ptr<std::vector<uint8_t>> command_packet);
+ void HandleSco(std::shared_ptr<std::vector<uint8_t>> sco_packet);
+
+ // Set the callbacks for scheduling tasks.
+ void RegisterTaskScheduler(std::function<AsyncTaskId(std::chrono::milliseconds, const TaskCallback&)> evtScheduler);
+
+ void RegisterPeriodicTaskScheduler(
+ std::function<AsyncTaskId(std::chrono::milliseconds, std::chrono::milliseconds, const TaskCallback&)>
+ periodicEvtScheduler);
+
+ void RegisterTaskCancel(std::function<void(AsyncTaskId)> cancel);
+
+ // Set the callbacks for sending packets to the HCI.
+ void RegisterEventChannel(const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& send_event);
+
+ void RegisterAclChannel(const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& send_acl);
+
+ void RegisterScoChannel(const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& send_sco);
+
+ // Controller commands. For error codes, see the Bluetooth Core Specification,
+ // Version 4.2, Volume 2, Part D (page 370).
+
+ // Link Control Commands
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.1
+
+ // 7.1.1
+ void HciInquiry(packets::PacketView<true> args);
+
+ // 7.1.2
+ void HciInquiryCancel(packets::PacketView<true> args);
+
+ // 7.1.5
+ void HciCreateConnection(packets::PacketView<true> args);
+
+ // 7.1.6
+ void HciDisconnect(packets::PacketView<true> args);
+
+ // 7.1.8
+ void HciAcceptConnectionRequest(packets::PacketView<true> args);
+
+ // 7.1.9
+ void HciRejectConnectionRequest(packets::PacketView<true> args);
+
+ // 7.1.10
+ void HciLinkKeyRequestReply(packets::PacketView<true> args);
+
+ // 7.1.11
+ void HciLinkKeyRequestNegativeReply(packets::PacketView<true> args);
+
+ // 7.1.14
+ void HciChangeConnectionPacketType(packets::PacketView<true> args);
+
+ // 7.1.15
+ void HciAuthenticationRequested(packets::PacketView<true> args);
+
+ // 7.1.16
+ void HciSetConnectionEncryption(packets::PacketView<true> args);
+
+ // 7.1.19
+ void HciRemoteNameRequest(packets::PacketView<true> args);
+
+ // 7.1.21
+ void HciReadRemoteSupportedFeatures(packets::PacketView<true> args);
+
+ // 7.1.22
+ void HciReadRemoteExtendedFeatures(packets::PacketView<true> args);
+
+ // 7.1.23
+ void HciReadRemoteVersionInformation(packets::PacketView<true> args);
+
+ // 7.1.24
+ void HciReadClockOffset(packets::PacketView<true> args);
+
+ // 7.1.29
+ void HciIoCapabilityRequestReply(packets::PacketView<true> args);
+
+ // 7.1.30
+ void HciUserConfirmationRequestReply(packets::PacketView<true> args);
+
+ // 7.1.31
+ void HciUserConfirmationRequestNegativeReply(packets::PacketView<true> args);
+
+ // 7.1.32
+ void HciUserPasskeyRequestReply(packets::PacketView<true> args);
+
+ // 7.1.33
+ void HciUserPasskeyRequestNegativeReply(packets::PacketView<true> args);
+
+ // 7.1.34
+ void HciRemoteOobDataRequestReply(packets::PacketView<true> args);
+
+ // 7.1.35
+ void HciRemoteOobDataRequestNegativeReply(packets::PacketView<true> args);
+
+ // 7.1.36
+ void HciIoCapabilityRequestNegativeReply(packets::PacketView<true> args);
+
+ // Link Policy Commands
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.2
+
+ // 7.2.10
+ void HciWriteLinkPolicySettings(packets::PacketView<true> args);
+
+ // 7.2.12
+ void HciWriteDefaultLinkPolicySettings(packets::PacketView<true> args);
+
+ // 7.2.14
+ void HciSniffSubrating(packets::PacketView<true> args);
+
+ // Link Controller Commands
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3
+
+ // 7.3.1
+ void HciSetEventMask(packets::PacketView<true> args);
+
+ // 7.3.2
+ void HciReset(packets::PacketView<true> args);
+
+ // 7.3.3
+ void HciSetEventFilter(packets::PacketView<true> args);
+
+ // 7.3.10
+ void HciDeleteStoredLinkKey(packets::PacketView<true> args);
+
+ // 7.3.11
+ void HciWriteLocalName(packets::PacketView<true> args);
+
+ // 7.3.12
+ void HciReadLocalName(packets::PacketView<true> args);
+
+ // 7.3.16
+ void HciWritePageTimeout(packets::PacketView<true> args);
+
+ // 7.3.18
+ void HciWriteScanEnable(packets::PacketView<true> args);
+
+ // 7.3.22
+ void HciWriteInquiryScanActivity(packets::PacketView<true> args);
+
+ // 7.3.23
+ void HciReadAuthenticationEnable(packets::PacketView<true> args);
+
+ // 7.3.24
+ void HciWriteAuthenticationEnable(packets::PacketView<true> args);
+
+ // 7.3.26
+ void HciWriteClassOfDevice(packets::PacketView<true> args);
+
+ // 7.3.28
+ void HciWriteVoiceSetting(packets::PacketView<true> args);
+
+ // 7.3.39
+ void HciHostBufferSize(packets::PacketView<true> args);
+
+ // 7.3.42
+ void HciWriteLinkSupervisionTimeout(packets::PacketView<true> args);
+
+ // 7.3.45
+ void HciWriteCurrentIacLap(packets::PacketView<true> args);
+
+ // 7.3.48
+ void HciWriteInquiryScanType(packets::PacketView<true> args);
+
+ // 7.3.50
+ void HciWriteInquiryMode(packets::PacketView<true> args);
+
+ // 7.3.52
+ void HciWritePageScanType(packets::PacketView<true> args);
+
+ // 7.3.56
+ void HciWriteExtendedInquiryResponse(packets::PacketView<true> args);
+
+ // 7.3.59
+ void HciWriteSimplePairingMode(packets::PacketView<true> args);
+
+ // 7.3.79
+ void HciWriteLeHostSupport(packets::PacketView<true> args);
+
+ // Informational Parameters Commands
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.4
+
+ // 7.4.5
+ void HciReadBufferSize(packets::PacketView<true> args);
+
+ // 7.4.1
+ void HciReadLocalVersionInformation(packets::PacketView<true> args);
+
+ // 7.4.6
+ void HciReadBdAddr(packets::PacketView<true> args);
+
+ // 7.4.2
+ void HciReadLocalSupportedCommands(packets::PacketView<true> args);
+
+ // 7.4.4
+ void HciReadLocalExtendedFeatures(packets::PacketView<true> args);
+
+ // 7.4.8
+ void HciReadLocalSupportedCodecs(packets::PacketView<true> args);
+
+ // Status Parameters Commands
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.5
+
+ // Test Commands
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.7
+
+ // 7.7.1
+ void HciReadLoopbackMode(packets::PacketView<true> args);
+
+ // 7.7.2
+ void HciWriteLoopbackMode(packets::PacketView<true> args);
+
+ // LE Controller Commands
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8
+
+ // 7.8.1
+ void HciLeSetEventMask(packets::PacketView<true> args);
+
+ // 7.8.2
+ void HciLeReadBufferSize(packets::PacketView<true> args);
+
+ // 7.8.3
+ void HciLeReadLocalSupportedFeatures(packets::PacketView<true> args);
+
+ // 7.8.4
+ void HciLeSetRandomAddress(packets::PacketView<true> args);
+
+ // 7.8.5
+ void HciLeSetAdvertisingParameters(packets::PacketView<true> args);
+
+ // 7.8.7
+ void HciLeSetAdvertisingData(packets::PacketView<true> args);
+
+ // 7.8.10
+ void HciLeSetScanParameters(packets::PacketView<true> args);
+
+ // 7.8.11
+ void HciLeSetScanEnable(packets::PacketView<true> args);
+
+ // 7.8.12
+ void HciLeCreateConnection(packets::PacketView<true> args);
+
+ // 7.8.18
+ void HciLeConnectionUpdate(packets::PacketView<true> args);
+
+ // 7.8.13
+ void HciLeConnectionCancel(packets::PacketView<true> args);
+
+ // 7.8.14
+ void HciLeReadWhiteListSize(packets::PacketView<true> args);
+
+ // 7.8.15
+ void HciLeClearWhiteList(packets::PacketView<true> args);
+
+ // 7.8.16
+ void HciLeAddDeviceToWhiteList(packets::PacketView<true> args);
+
+ // 7.8.17
+ void HciLeRemoveDeviceFromWhiteList(packets::PacketView<true> args);
+
+ // 7.8.21
+ void HciLeReadRemoteFeatures(packets::PacketView<true> args);
+
+ // 7.8.23
+ void HciLeRand(packets::PacketView<true> args);
+
+ // 7.8.24
+ void HciLeStartEncryption(packets::PacketView<true> args);
+
+ // 7.8.27
+ void HciLeReadSupportedStates(packets::PacketView<true> args);
+
+ // Vendor-specific Commands
+
+ void HciLeVendorSleepMode(packets::PacketView<true> args);
+ void HciLeVendorCap(packets::PacketView<true> args);
+ void HciLeVendorMultiAdv(packets::PacketView<true> args);
+ void HciLeVendor155(packets::PacketView<true> args);
+ void HciLeVendor157(packets::PacketView<true> args);
+ void HciLeEnergyInfo(packets::PacketView<true> args);
+ void HciLeAdvertisingFilter(packets::PacketView<true> args);
+ void HciLeExtendedScanParams(packets::PacketView<true> args);
+
+ void SetTimerPeriod(std::chrono::milliseconds new_period);
+ void StartTimer();
+ void StopTimer();
+
+ protected:
+ LinkLayerController link_layer_controller_{properties_};
+
+ private:
+ // Set a timer for a future action
+ void AddControllerEvent(std::chrono::milliseconds, const TaskCallback& callback);
+
+ void AddConnectionAction(const TaskCallback& callback, uint16_t handle);
+
+ // Creates a command complete event and sends it back to the HCI.
+ void SendCommandComplete(hci::OpCode command_opcode, const std::vector<uint8_t>& return_parameters) const;
+
+ // Sends a command complete event with no return parameters.
+ void SendCommandCompleteSuccess(hci::OpCode command_opcode) const;
+
+ void SendCommandCompleteUnknownOpCodeEvent(uint16_t command_opcode) const;
+
+ // Sends a command complete event with no return parameters.
+ void SendCommandCompleteOnlyStatus(hci::OpCode command_opcode, hci::Status status) const;
+
+ void SendCommandCompleteStatusAndAddress(hci::OpCode command_opcode, hci::Status status,
+ const Address& address) const;
+
+ // Creates a command status event and sends it back to the HCI.
+ void SendCommandStatus(hci::Status status, hci::OpCode command_opcode) const;
+
+ // Sends a command status event with default event parameters.
+ void SendCommandStatusSuccess(hci::OpCode command_opcode) const;
+
+ // Callbacks to send packets back to the HCI.
+ std::function<void(std::shared_ptr<std::vector<uint8_t>>)> send_acl_;
+ std::function<void(std::shared_ptr<std::vector<uint8_t>>)> send_event_;
+ std::function<void(std::shared_ptr<std::vector<uint8_t>>)> send_sco_;
+
+ // 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(packets::PacketView<true>)>> active_hci_commands_;
+
+ hci::LoopbackMode loopback_mode_;
+
+ SecurityManager security_manager_;
+
+ DualModeController(const DualModeController& cmdPckt) = delete;
+ DualModeController& operator=(const DualModeController& cmdPckt) = delete;
+};
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.cc b/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.cc
new file mode 100644
index 0000000..03a494c
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.cc
@@ -0,0 +1,1146 @@
+/*
+ * Copyright 2017 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 "link_layer_controller"
+
+#include "link_layer_controller.h"
+
+#include <base/logging.h>
+
+#include "hci.h"
+#include "osi/include/log.h"
+#include "packets/hci/acl_packet_builder.h"
+#include "packets/hci/command_packet_view.h"
+#include "packets/hci/event_packet_builder.h"
+#include "packets/hci/sco_packet_builder.h"
+#include "packets/link_layer/command_builder.h"
+#include "packets/link_layer/command_view.h"
+#include "packets/link_layer/disconnect_view.h"
+#include "packets/link_layer/encrypt_connection_view.h"
+#include "packets/link_layer/inquiry_response_view.h"
+#include "packets/link_layer/inquiry_view.h"
+#include "packets/link_layer/io_capability_view.h"
+#include "packets/link_layer/le_advertisement_view.h"
+#include "packets/link_layer/page_response_view.h"
+#include "packets/link_layer/page_view.h"
+#include "packets/link_layer/response_view.h"
+
+using std::vector;
+using namespace std::chrono;
+using namespace test_vendor_lib::packets;
+
+namespace test_vendor_lib {
+
+// TODO: Model Rssi?
+static uint8_t GetRssi() {
+ static uint8_t rssi = 0;
+ rssi += 5;
+ if (rssi > 128) {
+ rssi = rssi % 7;
+ }
+ return -(rssi);
+}
+
+void LinkLayerController::SendLELinkLayerPacket(std::shared_ptr<LinkLayerPacketBuilder> packet) {
+ if (schedule_task_) {
+ schedule_task_(milliseconds(50), [this, packet]() { send_to_remote_(packet, Phy::Type::LOW_ENERGY); });
+ } else {
+ send_to_remote_(packet, Phy::Type::LOW_ENERGY);
+ }
+}
+
+void LinkLayerController::SendLinkLayerPacket(std::shared_ptr<LinkLayerPacketBuilder> packet) {
+ if (schedule_task_) {
+ schedule_task_(milliseconds(50), [this, packet]() { send_to_remote_(packet, Phy::Type::BR_EDR); });
+ } else {
+ send_to_remote_(packet, Phy::Type::BR_EDR);
+ }
+}
+
+hci::Status LinkLayerController::SendCommandToRemoteByAddress(hci::OpCode opcode, PacketView<true> args,
+ const Address& remote, bool use_public_address) {
+ std::shared_ptr<LinkLayerPacketBuilder> command;
+ Address local_address;
+ if (use_public_address) {
+ local_address = properties_.GetAddress();
+ } else {
+ local_address = properties_.GetLeAddress();
+ }
+ command = LinkLayerPacketBuilder::WrapCommand(CommandBuilder::Create(static_cast<uint16_t>(opcode), args),
+ local_address, remote);
+ SendLinkLayerPacket(std::move(command));
+ return hci::Status::SUCCESS;
+}
+
+hci::Status LinkLayerController::SendCommandToRemoteByHandle(hci::OpCode opcode, PacketView<true> args,
+ uint16_t handle) {
+ // TODO: Handle LE connections
+ bool use_public_address = true;
+ if (!classic_connections_.HasHandle(handle)) {
+ return hci::Status::UNKNOWN_CONNECTION;
+ }
+ return SendCommandToRemoteByAddress(opcode, args, classic_connections_.GetAddress(handle), use_public_address);
+}
+
+hci::Status LinkLayerController::SendAclToRemote(AclPacketView acl_packet) {
+ // TODO: Handle LE connections
+ uint16_t handle = acl_packet.GetHandle();
+ if (!classic_connections_.HasHandle(handle)) {
+ return hci::Status::UNKNOWN_CONNECTION;
+ }
+
+ std::unique_ptr<ViewForwarderBuilder> acl_builder = ViewForwarderBuilder::Create(acl_packet);
+
+ std::shared_ptr<LinkLayerPacketBuilder> acl = LinkLayerPacketBuilder::WrapAcl(
+ std::move(acl_builder), properties_.GetAddress(), classic_connections_.GetAddress(handle));
+
+ LOG_INFO(LOG_TAG, "%s(%s): handle 0x%x size %d", __func__, properties_.GetAddress().ToString().c_str(), handle,
+ static_cast<int>(acl_packet.size()));
+
+ schedule_task_(milliseconds(5), [this, handle]() {
+ send_event_(EventPacketBuilder::CreateNumberOfCompletedPacketsEvent(handle, 1)->ToVector());
+ });
+ SendLinkLayerPacket(acl);
+ return hci::Status::SUCCESS;
+}
+
+void LinkLayerController::IncomingPacket(LinkLayerPacketView incoming) {
+ // TODO: Resolvable private addresses?
+ if (incoming.GetDestinationAddress() != properties_.GetAddress() &&
+ incoming.GetDestinationAddress() != properties_.GetLeAddress() &&
+ incoming.GetDestinationAddress() != Address::kEmpty) {
+ // Drop packets not addressed to me
+ return;
+ }
+
+ switch (incoming.GetType()) {
+ case Link::PacketType::ACL:
+ IncomingAclPacket(incoming);
+ break;
+ case Link::PacketType::COMMAND:
+ IncomingCommandPacket(incoming);
+ break;
+ case Link::PacketType::DISCONNECT:
+ IncomingDisconnectPacket(incoming);
+ break;
+ case Link::PacketType::ENCRYPT_CONNECTION:
+ IncomingEncryptConnection(incoming);
+ break;
+ case Link::PacketType::ENCRYPT_CONNECTION_RESPONSE:
+ IncomingEncryptConnectionResponse(incoming);
+ break;
+ case Link::PacketType::INQUIRY:
+ if (inquiry_scans_enabled_) {
+ IncomingInquiryPacket(incoming);
+ }
+ break;
+ case Link::PacketType::INQUIRY_RESPONSE:
+ IncomingInquiryResponsePacket(incoming);
+ break;
+ case Link::PacketType::IO_CAPABILITY_REQUEST:
+ IncomingIoCapabilityRequestPacket(incoming);
+ break;
+ case Link::PacketType::IO_CAPABILITY_RESPONSE:
+ IncomingIoCapabilityResponsePacket(incoming);
+ break;
+ case Link::PacketType::IO_CAPABILITY_NEGATIVE_RESPONSE:
+ IncomingIoCapabilityNegativeResponsePacket(incoming);
+ break;
+ case Link::PacketType::LE_ADVERTISEMENT:
+ if (le_scan_enable_ || le_connect_) {
+ IncomingLeAdvertisementPacket(incoming);
+ }
+ break;
+ case Link::PacketType::LE_SCAN:
+ // TODO: Check Advertising flags and see if we are scannable.
+ IncomingLeScanPacket(incoming);
+ break;
+ case Link::PacketType::LE_SCAN_RESPONSE:
+ if (le_scan_enable_ && le_scan_type_ == 1) {
+ IncomingLeScanResponsePacket(incoming);
+ }
+ break;
+ case Link::PacketType::PAGE:
+ if (page_scans_enabled_) {
+ IncomingPagePacket(incoming);
+ }
+ break;
+ case Link::PacketType::PAGE_RESPONSE:
+ IncomingPageResponsePacket(incoming);
+ break;
+ case Link::PacketType::RESPONSE:
+ IncomingResponsePacket(incoming);
+ break;
+ default:
+ LOG_WARN(LOG_TAG, "Dropping unhandled packet of type %d", static_cast<int32_t>(incoming.GetType()));
+ }
+}
+
+void LinkLayerController::IncomingAclPacket(LinkLayerPacketView incoming) {
+ LOG_INFO(LOG_TAG, "Acl Packet %s -> %s", incoming.GetSourceAddress().ToString().c_str(),
+ incoming.GetDestinationAddress().ToString().c_str());
+ AclPacketView acl_view = AclPacketView::Create(incoming.GetPayload());
+ LOG_INFO(LOG_TAG, "%s: remote handle 0x%x size %d", __func__, acl_view.GetHandle(),
+ static_cast<int>(acl_view.size()));
+ uint16_t local_handle = classic_connections_.GetHandle(incoming.GetSourceAddress());
+ LOG_INFO(LOG_TAG, "%s: local handle 0x%x", __func__, local_handle);
+
+ acl::PacketBoundaryFlagsType boundary_flags = acl_view.GetPacketBoundaryFlags();
+ acl::BroadcastFlagsType broadcast_flags = acl_view.GetBroadcastFlags();
+ std::unique_ptr<ViewForwarderBuilder> builder = ViewForwarderBuilder::Create(acl_view.GetPayload());
+ std::unique_ptr<AclPacketBuilder> local_acl =
+ AclPacketBuilder::Create(local_handle, boundary_flags, broadcast_flags, std::move(builder));
+ send_acl_(local_acl->ToVector());
+}
+
+void LinkLayerController::IncomingCommandPacket(LinkLayerPacketView incoming) {
+ // TODO: Check the destination address to see if this packet is for me.
+ CommandView command = CommandView::GetCommand(incoming);
+ hci::OpCode opcode = static_cast<hci::OpCode>(command.GetOpcode());
+ auto args = command.GetData();
+ std::vector<uint64_t> response_data;
+
+ switch (opcode) {
+ case (hci::OpCode::REMOTE_NAME_REQUEST): {
+ std::vector<uint8_t> name = properties_.GetName();
+ LOG_INFO(LOG_TAG, "Remote Name (Local Name) %d", static_cast<int>(name.size()));
+ response_data.push_back(static_cast<uint8_t>(hci::Status::SUCCESS));
+ response_data.push_back(name.size());
+ uint64_t word = 0;
+ for (size_t i = 0; i < name.size(); i++) {
+ if (i > 0 && (i % 8 == 0)) {
+ response_data.push_back(word);
+ word = 0;
+ }
+ word |= static_cast<uint64_t>(name[i]) << (8 * (i % 8));
+ }
+ response_data.push_back(word);
+ } break;
+ case (hci::OpCode::READ_REMOTE_SUPPORTED_FEATURES):
+ LOG_INFO(LOG_TAG, "(%s) Remote Supported Features Requested by: %s %x",
+ incoming.GetDestinationAddress().ToString().c_str(), incoming.GetSourceAddress().ToString().c_str(),
+ static_cast<int>(properties_.GetSupportedFeatures()));
+ response_data.push_back(static_cast<uint8_t>(hci::Status::SUCCESS));
+ response_data.push_back(properties_.GetSupportedFeatures());
+ break;
+ case (hci::OpCode::READ_REMOTE_EXTENDED_FEATURES): {
+ uint8_t page_number = (args + 2).extract<uint8_t>(); // skip the handle
+ LOG_INFO(LOG_TAG, "(%s) Remote Extended Features %d Requested by: %s",
+ incoming.GetDestinationAddress().ToString().c_str(), page_number,
+ incoming.GetSourceAddress().ToString().c_str());
+ uint8_t max_page_number = properties_.GetExtendedFeaturesMaximumPageNumber();
+ if (page_number > max_page_number) {
+ response_data.push_back(static_cast<uint8_t>(hci::Status::INVALID_HCI_COMMAND_PARAMETERS));
+ response_data.push_back(page_number);
+ response_data.push_back(max_page_number);
+ response_data.push_back(0);
+ } else {
+ response_data.push_back(static_cast<uint8_t>(hci::Status::SUCCESS));
+ response_data.push_back(page_number);
+ response_data.push_back(max_page_number);
+ response_data.push_back(properties_.GetExtendedFeatures(page_number));
+ }
+ } break;
+ case (hci::OpCode::READ_REMOTE_VERSION_INFORMATION):
+ response_data.push_back(static_cast<uint8_t>(hci::Status::SUCCESS));
+ response_data.push_back(properties_.GetLmpPalVersion());
+ response_data.push_back(properties_.GetManufacturerName());
+ response_data.push_back(properties_.GetLmpPalSubversion());
+ break;
+ case (hci::OpCode::READ_CLOCK_OFFSET):
+ response_data.push_back(static_cast<uint8_t>(hci::Status::SUCCESS));
+ response_data.push_back(properties_.GetClockOffset());
+ break;
+ default:
+ LOG_INFO(LOG_TAG, "Dropping unhandled command 0x%04x", static_cast<uint16_t>(opcode));
+ return;
+ }
+ SendLinkLayerPacket(
+ LinkLayerPacketBuilder::WrapResponse(ResponseBuilder::Create(static_cast<uint16_t>(opcode), response_data),
+ properties_.GetAddress(), incoming.GetSourceAddress()));
+}
+
+void LinkLayerController::IncomingDisconnectPacket(LinkLayerPacketView incoming) {
+ LOG_INFO(LOG_TAG, "Disconnect Packet");
+ DisconnectView disconnect = DisconnectView::GetDisconnect(incoming);
+ Address peer = incoming.GetSourceAddress();
+ uint16_t handle = classic_connections_.GetHandle(peer);
+ if (handle == acl::kReservedHandle) {
+ LOG_INFO(LOG_TAG, "%s: Unknown connection @%s", __func__, peer.ToString().c_str());
+ return;
+ }
+ CHECK(classic_connections_.Disconnect(handle)) << "GetHandle() returned invalid handle " << handle;
+
+ uint8_t reason = disconnect.GetReason();
+ schedule_task_(milliseconds(20), [this, handle, reason]() { DisconnectCleanup(handle, reason); });
+}
+
+void LinkLayerController::IncomingEncryptConnection(LinkLayerPacketView incoming) {
+ LOG_INFO(LOG_TAG, "%s", __func__);
+ // TODO: Check keys
+ Address peer = incoming.GetSourceAddress();
+ uint16_t handle = classic_connections_.GetHandle(peer);
+ if (handle == acl::kReservedHandle) {
+ LOG_INFO(LOG_TAG, "%s: Unknown connection @%s", __func__, peer.ToString().c_str());
+ return;
+ }
+ send_event_(EventPacketBuilder::CreateEncryptionChange(hci::Status::SUCCESS, handle, 1)->ToVector());
+ SendLinkLayerPacket(LinkLayerPacketBuilder::WrapEncryptConnectionResponse(
+ EncryptConnectionBuilder::Create(security_manager_.GetKey(peer)), properties_.GetAddress(), peer));
+}
+
+void LinkLayerController::IncomingEncryptConnectionResponse(LinkLayerPacketView incoming) {
+ LOG_INFO(LOG_TAG, "%s", __func__);
+ // TODO: Check keys
+ uint16_t handle = classic_connections_.GetHandle(incoming.GetSourceAddress());
+ if (handle == acl::kReservedHandle) {
+ LOG_INFO(LOG_TAG, "%s: Unknown connection @%s", __func__, incoming.GetSourceAddress().ToString().c_str());
+ return;
+ }
+ send_event_(EventPacketBuilder::CreateEncryptionChange(hci::Status::SUCCESS, handle, 1)->ToVector());
+}
+
+void LinkLayerController::IncomingInquiryPacket(LinkLayerPacketView incoming) {
+ InquiryView inquiry = InquiryView::GetInquiry(incoming);
+ std::unique_ptr<InquiryResponseBuilder> inquiry_response;
+ switch (inquiry.GetType()) {
+ case (Inquiry::InquiryType::STANDARD):
+ inquiry_response = InquiryResponseBuilder::CreateStandard(
+ properties_.GetPageScanRepetitionMode(), properties_.GetClassOfDevice(), properties_.GetClockOffset());
+ break;
+
+ case (Inquiry::InquiryType::RSSI):
+ inquiry_response =
+ InquiryResponseBuilder::CreateRssi(properties_.GetPageScanRepetitionMode(), properties_.GetClassOfDevice(),
+ properties_.GetClockOffset(), GetRssi());
+ break;
+
+ case (Inquiry::InquiryType::EXTENDED):
+ inquiry_response = InquiryResponseBuilder::CreateExtended(
+ properties_.GetPageScanRepetitionMode(), properties_.GetClassOfDevice(), properties_.GetClockOffset(),
+ GetRssi(), properties_.GetExtendedInquiryData());
+ break;
+ default:
+ LOG_WARN(LOG_TAG, "Unhandled Incoming Inquiry of type %d", static_cast<int>(inquiry.GetType()));
+ return;
+ }
+ SendLinkLayerPacket(LinkLayerPacketBuilder::WrapInquiryResponse(std::move(inquiry_response), properties_.GetAddress(),
+ incoming.GetSourceAddress()));
+ // TODO: Send an Inquriy Response Notification Event 7.7.74
+}
+
+void LinkLayerController::IncomingInquiryResponsePacket(LinkLayerPacketView incoming) {
+ InquiryResponseView inquiry_response = InquiryResponseView::GetInquiryResponse(incoming);
+ std::vector<uint8_t> eir;
+
+ switch (inquiry_response.GetType()) {
+ case (Inquiry::InquiryType::STANDARD): {
+ LOG_WARN(LOG_TAG, "Incoming Standard Inquiry Response");
+ // TODO: Support multiple inquiries in the same packet.
+ std::unique_ptr<EventPacketBuilder> inquiry_result = EventPacketBuilder::CreateInquiryResultEvent();
+ bool result_added =
+ inquiry_result->AddInquiryResult(incoming.GetSourceAddress(), inquiry_response.GetPageScanRepetitionMode(),
+ inquiry_response.GetClassOfDevice(), inquiry_response.GetClockOffset());
+ CHECK(result_added);
+ send_event_(inquiry_result->ToVector());
+ } break;
+
+ case (Inquiry::InquiryType::RSSI):
+ LOG_WARN(LOG_TAG, "Incoming RSSI Inquiry Response");
+ send_event_(EventPacketBuilder::CreateExtendedInquiryResultEvent(
+ incoming.GetSourceAddress(), inquiry_response.GetPageScanRepetitionMode(),
+ inquiry_response.GetClassOfDevice(), inquiry_response.GetClockOffset(), GetRssi(), eir)
+ ->ToVector());
+ break;
+
+ case (Inquiry::InquiryType::EXTENDED): {
+ LOG_WARN(LOG_TAG, "Incoming Extended Inquiry Response");
+ auto eir_itr = inquiry_response.GetExtendedData();
+ size_t eir_bytes = eir_itr.NumBytesRemaining();
+ LOG_WARN(LOG_TAG, "Payload size = %d", static_cast<int>(eir_bytes));
+ for (size_t i = 0; i < eir_bytes; i++) {
+ eir.push_back(eir_itr.extract<uint8_t>());
+ }
+ send_event_(EventPacketBuilder::CreateExtendedInquiryResultEvent(
+ incoming.GetSourceAddress(), inquiry_response.GetPageScanRepetitionMode(),
+ inquiry_response.GetClassOfDevice(), inquiry_response.GetClockOffset(), GetRssi(), eir)
+ ->ToVector());
+ } break;
+ default:
+ LOG_WARN(LOG_TAG, "Unhandled Incoming Inquiry Response of type %d", static_cast<int>(inquiry_response.GetType()));
+ }
+}
+
+void LinkLayerController::IncomingIoCapabilityRequestPacket(LinkLayerPacketView incoming) {
+ LOG_DEBUG(LOG_TAG, "%s", __func__);
+ if (!simple_pairing_mode_enabled_) {
+ LOG_WARN(LOG_TAG, "%s: Only simple pairing mode is implemented", __func__);
+ return;
+ }
+ auto request = IoCapabilityView::GetIoCapability(incoming);
+ Address peer = incoming.GetSourceAddress();
+
+ uint8_t io_capability = request.GetIoCapability();
+ uint8_t oob_data_present = request.GetOobDataPresent();
+ uint8_t authentication_requirements = request.GetAuthenticationRequirements();
+
+ uint16_t handle = classic_connections_.GetHandle(peer);
+ if (handle == acl::kReservedHandle) {
+ LOG_INFO(LOG_TAG, "%s: Device not connected %s", __func__, peer.ToString().c_str());
+ return;
+ }
+
+ security_manager_.AuthenticationRequest(peer, handle);
+
+ security_manager_.SetPeerIoCapability(peer, io_capability, oob_data_present, authentication_requirements);
+
+ send_event_(EventPacketBuilder::CreateIoCapabilityResponseEvent(peer, io_capability, oob_data_present,
+ authentication_requirements)
+ ->ToVector());
+
+ StartSimplePairing(peer);
+}
+
+void LinkLayerController::IncomingIoCapabilityResponsePacket(LinkLayerPacketView incoming) {
+ LOG_DEBUG(LOG_TAG, "%s", __func__);
+ auto response = IoCapabilityView::GetIoCapability(incoming);
+ Address peer = incoming.GetSourceAddress();
+ uint8_t io_capability = response.GetIoCapability();
+ uint8_t oob_data_present = response.GetOobDataPresent();
+ uint8_t authentication_requirements = response.GetAuthenticationRequirements();
+
+ security_manager_.SetPeerIoCapability(peer, io_capability, oob_data_present, authentication_requirements);
+
+ send_event_(EventPacketBuilder::CreateIoCapabilityResponseEvent(peer, io_capability, oob_data_present,
+ authentication_requirements)
+ ->ToVector());
+
+ PairingType pairing_type = security_manager_.GetSimplePairingType();
+ if (pairing_type != PairingType::INVALID) {
+ schedule_task_(milliseconds(5), [this, peer, pairing_type]() { AuthenticateRemoteStage1(peer, pairing_type); });
+ } else {
+ LOG_INFO(LOG_TAG, "%s: Security Manager returned INVALID", __func__);
+ }
+}
+
+void LinkLayerController::IncomingIoCapabilityNegativeResponsePacket(LinkLayerPacketView incoming) {
+ LOG_DEBUG(LOG_TAG, "%s", __func__);
+ Address peer = incoming.GetSourceAddress();
+
+ CHECK(security_manager_.GetAuthenticationAddress() == peer);
+
+ security_manager_.InvalidateIoCapabilities();
+}
+
+void LinkLayerController::IncomingLeAdvertisementPacket(LinkLayerPacketView incoming) {
+ LOG_INFO(LOG_TAG, "LE Advertisement Packet");
+ // TODO: Handle multiple advertisements per packet.
+
+ LeAdvertisementView advertisement = LeAdvertisementView::GetLeAdvertisementView(incoming);
+ LeAdvertisement::AdvertisementType adv_type = advertisement.GetAdvertisementType();
+ LeAdvertisement::AddressType addr_type = advertisement.GetAddressType();
+
+ if (le_scan_enable_) {
+ vector<uint8_t> ad;
+ auto itr = advertisement.GetData();
+ size_t ad_size = itr.NumBytesRemaining();
+ LOG_INFO(LOG_TAG, "Sending advertisement %d", static_cast<int>(ad_size));
+ for (size_t i = 0; i < ad_size; i++) {
+ ad.push_back(itr.extract<uint8_t>());
+ }
+ std::unique_ptr<EventPacketBuilder> le_adverts = EventPacketBuilder::CreateLeAdvertisingReportEvent();
+
+ if (!le_adverts->AddLeAdvertisingReport(adv_type, addr_type, incoming.GetSourceAddress(), ad, GetRssi())) {
+ LOG_INFO(LOG_TAG, "Couldn't add the advertising report.");
+ } else {
+ send_event_(le_adverts->ToVector());
+ }
+ }
+
+#if 0
+ // Connect
+ if (le_connect_ && (adv_type == BTM_BLE_CONNECT_EVT ||
+ adv_type == BTM_BLE_CONNECT_DIR_EVT)) {
+ LOG_INFO(LOG_TAG, "Connecting to device %d", static_cast<int>(dev));
+ if (le_peer_address_ == addr && le_peer_address_type_ == addr_type &&
+ remote_devices_[dev]->LeConnect()) {
+ uint16_t handle = LeGetHandle();
+ send_event_(EventPacketBuilder::CreateLeConnectionCompleteEvent(
+ hci::Status::SUCCESS, handle, HCI_ROLE_MASTER, addr_type, addr, 1,
+ 2, 3)->ToVector());
+
+ // TODO: LeGetConnInterval(), LeGetConnLatency(),
+ // LeGetSupervisionTimeout()));
+ le_connect_ = false;
+
+ std::shared_ptr<Connection> new_connection =
+ std::make_shared<Connection>(remote_devices_[dev], handle);
+ /*
+ connections_.push_back(new_connection);
+
+ remote_devices_[dev]->SetConnection(new_connection);
+ */
+ }
+
+ if (LeWhiteListContainsDevice(addr, addr_type) &&
+ remote_devices_[dev]->LeConnect()) {
+ LOG_INFO(LOG_TAG, "White List Connecting to device %d",
+ static_cast<int>(dev));
+ uint16_t handle = LeGetHandle();
+ send_event_(EventPacketBuilder::CreateLeConnectionCompleteEvent(
+ hci::Status::SUCCESS, handle, HCI_ROLE_MASTER, addr_type, addr, 1,
+ 2, 3)->ToVector());
+ // TODO: LeGetConnInterval(), LeGetConnLatency(),
+ // LeGetSupervisionTimeout()));
+ le_connect_ = false;
+
+ std::shared_ptr<Connection> new_connection =
+ std::make_shared<Connection>(remote_devices_[dev], handle);
+ /*
+ connections_.push_back(new_connection);
+ remote_devices_[dev]->SetConnection(new_connection);
+ */
+ }
+ }
+#endif
+
+ // Active scanning
+ if (le_scan_enable_ && le_scan_type_ == 1) {
+ LOG_INFO(LOG_TAG, "Send Scan Packet");
+ std::shared_ptr<LinkLayerPacketBuilder> to_send =
+ LinkLayerPacketBuilder::WrapLeScan(properties_.GetLeAddress(), incoming.GetSourceAddress());
+ SendLELinkLayerPacket(to_send);
+ }
+}
+
+void LinkLayerController::IncomingLeScanPacket(LinkLayerPacketView incoming) {
+ LOG_INFO(LOG_TAG, "LE Scan Packet");
+ std::unique_ptr<LeAdvertisementBuilder> response = LeAdvertisementBuilder::Create(
+ static_cast<LeAdvertisement::AddressType>(properties_.GetLeAddressType()),
+ static_cast<LeAdvertisement::AdvertisementType>(properties_.GetLeAdvertisementType()),
+ properties_.GetLeScanResponse());
+ std::shared_ptr<LinkLayerPacketBuilder> to_send = LinkLayerPacketBuilder::WrapLeScanResponse(
+ std::move(response), properties_.GetLeAddress(), incoming.GetSourceAddress());
+ SendLELinkLayerPacket(to_send);
+}
+
+void LinkLayerController::IncomingLeScanResponsePacket(LinkLayerPacketView incoming) {
+ LOG_INFO(LOG_TAG, "LE Scan Response Packet");
+ LeAdvertisementView scan_response = LeAdvertisementView::GetLeAdvertisementView(incoming);
+ vector<uint8_t> ad;
+ auto itr = scan_response.GetData();
+ size_t scan_size = itr.NumBytesRemaining();
+ for (size_t i = 0; i < scan_size; i++) {
+ ad.push_back(itr.extract<uint8_t>());
+ }
+
+ std::unique_ptr<EventPacketBuilder> le_adverts = EventPacketBuilder::CreateLeAdvertisingReportEvent();
+
+ if (!le_adverts->AddLeAdvertisingReport(scan_response.GetAdvertisementType(), scan_response.GetAddressType(),
+ incoming.GetSourceAddress(), ad, GetRssi())) {
+ LOG_INFO(LOG_TAG, "Couldn't add the scan response.");
+ } else {
+ LOG_INFO(LOG_TAG, "Sending scan response");
+ send_event_(le_adverts->ToVector());
+ }
+}
+
+void LinkLayerController::IncomingPagePacket(LinkLayerPacketView incoming) {
+ PageView page = PageView::GetPage(incoming);
+ LOG_INFO(LOG_TAG, "%s from %s", __func__, incoming.GetSourceAddress().ToString().c_str());
+
+ if (!classic_connections_.CreatePendingConnection(incoming.GetSourceAddress())) {
+ // Send a response to indicate that we're busy, or drop the packet?
+ LOG_WARN(LOG_TAG, "%s: Failed to create a pending connection", __func__);
+ }
+
+ send_event_(EventPacketBuilder::CreateConnectionRequestEvent(incoming.GetSourceAddress(), page.GetClassOfDevice(),
+ hci::LinkType::ACL)
+ ->ToVector());
+}
+
+void LinkLayerController::IncomingPageResponsePacket(LinkLayerPacketView incoming) {
+ LOG_INFO(LOG_TAG, "%s: %s", __func__, incoming.GetSourceAddress().ToString().c_str());
+ uint16_t handle = classic_connections_.CreateConnection(incoming.GetSourceAddress());
+ if (handle == acl::kReservedHandle) {
+ LOG_WARN(LOG_TAG, "%s: No free handles", __func__);
+ return;
+ }
+ LOG_INFO(LOG_TAG, "%s: Sending CreateConnectionComplete", __func__);
+ send_event_(EventPacketBuilder::CreateConnectionCompleteEvent(hci::Status::SUCCESS, handle,
+ incoming.GetSourceAddress(), hci::LinkType::ACL, false)
+ ->ToVector());
+}
+
+void LinkLayerController::IncomingResponsePacket(LinkLayerPacketView incoming) {
+ ResponseView response = ResponseView::GetResponse(incoming);
+
+ // TODO: Check to see if I'm expecting this response.
+
+ hci::OpCode opcode = static_cast<hci::OpCode>(response.GetOpcode());
+ auto args = response.GetResponseData();
+ hci::Status status = static_cast<hci::Status>(args.extract<uint64_t>());
+
+ uint16_t handle = classic_connections_.GetHandle(incoming.GetSourceAddress());
+
+ switch (opcode) {
+ case (hci::OpCode::REMOTE_NAME_REQUEST): {
+ std::string remote_name = "";
+ size_t length = args.extract<uint64_t>();
+ uint64_t word = 0;
+ for (size_t b = 0; b < length; b++) {
+ size_t byte = b % 8;
+ if (byte == 0) {
+ word = args.extract<uint64_t>();
+ }
+ remote_name += static_cast<uint8_t>(word >> (byte * 8));
+ }
+ send_event_(
+ EventPacketBuilder::CreateRemoteNameRequestCompleteEvent(status, incoming.GetSourceAddress(), remote_name)
+ ->ToVector());
+ } break;
+ case (hci::OpCode::READ_REMOTE_SUPPORTED_FEATURES): {
+ send_event_(
+ EventPacketBuilder::CreateRemoteSupportedFeaturesEvent(status, handle, args.extract<uint64_t>())->ToVector());
+ } break;
+ case (hci::OpCode::READ_REMOTE_EXTENDED_FEATURES): {
+ if (status == hci::Status::SUCCESS) {
+ send_event_(EventPacketBuilder::CreateReadRemoteExtendedFeaturesEvent(
+ status, handle, args.extract<uint64_t>(), args.extract<uint64_t>(), args.extract<uint64_t>())
+ ->ToVector());
+ } else {
+ send_event_(EventPacketBuilder::CreateReadRemoteExtendedFeaturesEvent(status, handle, 0, 0, 0)->ToVector());
+ }
+ } break;
+ case (hci::OpCode::READ_REMOTE_VERSION_INFORMATION): {
+ send_event_(EventPacketBuilder::CreateReadRemoteVersionInformationEvent(
+ status, handle, args.extract<uint64_t>(), args.extract<uint64_t>(), args.extract<uint64_t>())
+ ->ToVector());
+ LOG_INFO(LOG_TAG, "Read remote version handle 0x%04x", handle);
+ } break;
+ case (hci::OpCode::READ_CLOCK_OFFSET): {
+ send_event_(EventPacketBuilder::CreateReadClockOffsetEvent(status, handle, args.extract<uint64_t>())->ToVector());
+ } break;
+ default:
+ LOG_INFO(LOG_TAG, "Unhandled response to command 0x%04x", static_cast<uint16_t>(opcode));
+ }
+}
+
+void LinkLayerController::TimerTick() {
+ if (inquiry_state_ == Inquiry::InquiryState::INQUIRY) Inquiry();
+ if (inquiry_state_ == Inquiry::InquiryState::INQUIRY) PageScan();
+ Connections();
+}
+
+void LinkLayerController::Connections() {
+ // TODO: Keep connections alive?
+}
+
+void LinkLayerController::RegisterEventChannel(
+ const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& callback) {
+ send_event_ = callback;
+}
+
+void LinkLayerController::RegisterAclChannel(
+ const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& callback) {
+ send_acl_ = callback;
+}
+
+void LinkLayerController::RegisterScoChannel(
+ const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& callback) {
+ send_sco_ = callback;
+}
+
+void LinkLayerController::RegisterRemoteChannel(
+ const std::function<void(std::shared_ptr<LinkLayerPacketBuilder>, Phy::Type)>& callback) {
+ send_to_remote_ = callback;
+}
+
+void LinkLayerController::RegisterTaskScheduler(
+ std::function<AsyncTaskId(milliseconds, const TaskCallback&)> event_scheduler) {
+ schedule_task_ = event_scheduler;
+}
+
+void LinkLayerController::RegisterPeriodicTaskScheduler(
+ std::function<AsyncTaskId(milliseconds, milliseconds, const TaskCallback&)> periodic_event_scheduler) {
+ schedule_periodic_task_ = periodic_event_scheduler;
+}
+
+void LinkLayerController::RegisterTaskCancel(std::function<void(AsyncTaskId)> task_cancel) {
+ cancel_task_ = task_cancel;
+}
+
+void LinkLayerController::AddControllerEvent(milliseconds delay, const TaskCallback& task) {
+ controller_events_.push_back(schedule_task_(delay, task));
+}
+
+void LinkLayerController::WriteSimplePairingMode(bool enabled) {
+ CHECK(enabled) << "The spec says don't disable this!";
+ simple_pairing_mode_enabled_ = enabled;
+}
+
+void LinkLayerController::StartSimplePairing(const Address& address) {
+ // IO Capability Exchange (See the Diagram in the Spec)
+ send_event_(EventPacketBuilder::CreateIoCapabilityRequestEvent(address)->ToVector());
+
+ // Get a Key, then authenticate
+ // PublicKeyExchange(address);
+ // AuthenticateRemoteStage1(address);
+ // AuthenticateRemoteStage2(address);
+}
+
+void LinkLayerController::AuthenticateRemoteStage1(const Address& peer, PairingType pairing_type) {
+ CHECK(security_manager_.GetAuthenticationAddress() == peer);
+ // TODO: Public key exchange first?
+ switch (pairing_type) {
+ case PairingType::AUTO_CONFIRMATION:
+ send_event_(EventPacketBuilder::CreateUserConfirmationRequestEvent(peer, 123456)->ToVector());
+ break;
+ case PairingType::CONFIRM_Y_N:
+ CHECK(false) << __func__ << "Unimplemented PairingType" << static_cast<int>(pairing_type);
+ break;
+ case PairingType::DISPLAY_PIN:
+ CHECK(false) << __func__ << "Unimplemented PairingType" << static_cast<int>(pairing_type);
+ break;
+ case PairingType::DISPLAY_AND_CONFIRM:
+ CHECK(false) << __func__ << "Unimplemented PairingType" << static_cast<int>(pairing_type);
+ break;
+ case PairingType::INPUT_PIN:
+ CHECK(false) << __func__ << "Unimplemented PairingType" << static_cast<int>(pairing_type);
+ break;
+ case PairingType::INVALID:
+ CHECK(false) << __func__ << "Unimplemented PairingType" << static_cast<int>(pairing_type);
+ break;
+ default:
+ CHECK(false) << __func__ << ": Invalid PairingType " << static_cast<int>(pairing_type);
+ }
+}
+
+void LinkLayerController::AuthenticateRemoteStage2(const Address& peer) {
+ uint16_t handle = security_manager_.GetAuthenticationHandle();
+ CHECK(security_manager_.GetAuthenticationAddress() == peer);
+ // Check key in security_manager_ ?
+ send_event_(EventPacketBuilder::CreateAuthenticationCompleteEvent(hci::Status::SUCCESS, handle)->ToVector());
+}
+
+hci::Status LinkLayerController::LinkKeyRequestReply(const Address& peer, PacketView<true> key) {
+ std::vector<uint8_t> key_vec(key.begin(), key.end());
+ security_manager_.WriteKey(peer, key_vec);
+ security_manager_.AuthenticationRequestFinished();
+
+ schedule_task_(milliseconds(5), [this, peer]() { AuthenticateRemoteStage2(peer); });
+
+ return hci::Status::SUCCESS;
+}
+
+hci::Status LinkLayerController::LinkKeyRequestNegativeReply(const Address& address) {
+ security_manager_.DeleteKey(address);
+ // Simple pairing to get a key
+ uint16_t handle = classic_connections_.GetHandle(address);
+ if (handle == acl::kReservedHandle) {
+ LOG_INFO(LOG_TAG, "%s: Device not connected %s", __func__, address.ToString().c_str());
+ return hci::Status::UNKNOWN_CONNECTION;
+ }
+
+ security_manager_.AuthenticationRequest(address, handle);
+
+ schedule_task_(milliseconds(5), [this, address]() { StartSimplePairing(address); });
+ return hci::Status::SUCCESS;
+}
+
+hci::Status LinkLayerController::IoCapabilityRequestReply(const Address& peer, uint8_t io_capability,
+ uint8_t oob_data_present_flag,
+ uint8_t authentication_requirements) {
+ security_manager_.SetLocalIoCapability(peer, io_capability, oob_data_present_flag, authentication_requirements);
+
+ PairingType pairing_type = security_manager_.GetSimplePairingType();
+ if (pairing_type != PairingType::INVALID) {
+ schedule_task_(milliseconds(5), [this, peer, pairing_type]() { AuthenticateRemoteStage1(peer, pairing_type); });
+ SendLinkLayerPacket(LinkLayerPacketBuilder::WrapIoCapabilityResponse(
+ IoCapabilityBuilder::Create(io_capability, oob_data_present_flag, authentication_requirements),
+ properties_.GetAddress(), peer));
+ } else {
+ LOG_INFO(LOG_TAG, "%s: Requesting remote capability", __func__);
+ SendLinkLayerPacket(LinkLayerPacketBuilder::WrapIoCapabilityRequest(
+ IoCapabilityBuilder::Create(io_capability, oob_data_present_flag, authentication_requirements),
+ properties_.GetAddress(), peer));
+ }
+
+ return hci::Status::SUCCESS;
+}
+
+hci::Status LinkLayerController::IoCapabilityRequestNegativeReply(const Address& peer, hci::Status reason) {
+ if (security_manager_.GetAuthenticationAddress() != peer) {
+ return hci::Status::AUTHENTICATION_FAILURE;
+ }
+
+ security_manager_.InvalidateIoCapabilities();
+
+ SendLinkLayerPacket(LinkLayerPacketBuilder::WrapIoCapabilityNegativeResponse(
+ IoCapabilityNegativeResponseBuilder::Create(static_cast<uint8_t>(reason)), properties_.GetAddress(), peer));
+
+ return hci::Status::SUCCESS;
+}
+
+hci::Status LinkLayerController::UserConfirmationRequestReply(const Address& peer) {
+ if (security_manager_.GetAuthenticationAddress() != peer) {
+ return hci::Status::AUTHENTICATION_FAILURE;
+ }
+ // TODO: Key could be calculated here.
+ std::vector<uint8_t> key_vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+ security_manager_.WriteKey(peer, key_vec);
+
+ security_manager_.AuthenticationRequestFinished();
+
+ schedule_task_(milliseconds(5), [this, peer]() { AuthenticateRemoteStage2(peer); });
+ return hci::Status::SUCCESS;
+}
+
+hci::Status LinkLayerController::UserConfirmationRequestNegativeReply(const Address& peer) {
+ if (security_manager_.GetAuthenticationAddress() != peer) {
+ return hci::Status::AUTHENTICATION_FAILURE;
+ }
+ return hci::Status::SUCCESS;
+}
+
+hci::Status LinkLayerController::UserPasskeyRequestReply(const Address& peer, uint32_t numeric_value) {
+ if (security_manager_.GetAuthenticationAddress() != peer) {
+ return hci::Status::AUTHENTICATION_FAILURE;
+ }
+ LOG_INFO(LOG_TAG, "TODO:Do something with the passkey %06d", numeric_value);
+ return hci::Status::SUCCESS;
+}
+
+hci::Status LinkLayerController::UserPasskeyRequestNegativeReply(const Address& peer) {
+ if (security_manager_.GetAuthenticationAddress() != peer) {
+ return hci::Status::AUTHENTICATION_FAILURE;
+ }
+ return hci::Status::SUCCESS;
+}
+
+hci::Status LinkLayerController::RemoteOobDataRequestReply(const Address& peer, const std::vector<uint8_t>& c,
+ const std::vector<uint8_t>& r) {
+ if (security_manager_.GetAuthenticationAddress() != peer) {
+ return hci::Status::AUTHENTICATION_FAILURE;
+ }
+ LOG_INFO(LOG_TAG, "TODO:Do something with the OOB data c=%d r=%d", c[0], r[0]);
+ return hci::Status::SUCCESS;
+}
+
+hci::Status LinkLayerController::RemoteOobDataRequestNegativeReply(const Address& peer) {
+ if (security_manager_.GetAuthenticationAddress() != peer) {
+ return hci::Status::AUTHENTICATION_FAILURE;
+ }
+ return hci::Status::SUCCESS;
+}
+
+void LinkLayerController::HandleAuthenticationRequest(const Address& address, uint16_t handle) {
+ if (simple_pairing_mode_enabled_ == true) {
+ security_manager_.AuthenticationRequest(address, handle);
+ send_event_(EventPacketBuilder::CreateLinkKeyRequestEvent(address)->ToVector());
+ } else { // Should never happen for our phones
+ // Check for a key, try to authenticate, ask for a PIN.
+ send_event_(
+ EventPacketBuilder::CreateAuthenticationCompleteEvent(hci::Status::AUTHENTICATION_FAILURE, handle)->ToVector());
+ }
+}
+
+hci::Status LinkLayerController::AuthenticationRequested(uint16_t handle) {
+ if (!classic_connections_.HasHandle(handle)) {
+ LOG_INFO(LOG_TAG, "Authentication Requested for unknown handle %04x", handle);
+ return hci::Status::UNKNOWN_CONNECTION;
+ }
+
+ Address remote = classic_connections_.GetAddress(handle);
+
+ schedule_task_(milliseconds(5), [this, remote, handle]() { HandleAuthenticationRequest(remote, handle); });
+
+ return hci::Status::SUCCESS;
+}
+
+void LinkLayerController::HandleSetConnectionEncryption(const Address& peer, uint16_t handle,
+ uint8_t encryption_enable) {
+ // TODO: Block ACL traffic or at least guard against it
+
+ if (classic_connections_.IsEncrypted(handle) && encryption_enable) {
+ send_event_(
+ EventPacketBuilder::CreateEncryptionChange(hci::Status::SUCCESS, handle, encryption_enable)->ToVector());
+ return;
+ }
+
+ SendLinkLayerPacket(LinkLayerPacketBuilder::WrapEncryptConnection(
+ EncryptConnectionBuilder::Create(security_manager_.GetKey(peer)), properties_.GetAddress(), peer));
+}
+
+hci::Status LinkLayerController::SetConnectionEncryption(uint16_t handle, uint8_t encryption_enable) {
+ if (!classic_connections_.HasHandle(handle)) {
+ LOG_INFO(LOG_TAG, "Authentication Requested for unknown handle %04x", handle);
+ return hci::Status::UNKNOWN_CONNECTION;
+ }
+
+ if (classic_connections_.IsEncrypted(handle) && !encryption_enable) {
+ return hci::Status::ENCRYPTION_MODE_NOT_ACCEPTABLE;
+ }
+ Address remote = classic_connections_.GetAddress(handle);
+
+ schedule_task_(milliseconds(5), [this, remote, handle, encryption_enable]() {
+ HandleSetConnectionEncryption(remote, handle, encryption_enable);
+ });
+
+ return hci::Status::SUCCESS;
+}
+
+hci::Status LinkLayerController::AcceptConnectionRequest(const Address& addr, bool try_role_switch) {
+ if (!classic_connections_.HasPendingConnection(addr)) {
+ LOG_INFO(LOG_TAG, "%s: No pending connection", __func__);
+ return hci::Status::UNKNOWN_CONNECTION;
+ }
+
+ LOG_INFO(LOG_TAG, "%s: Accept in 200ms", __func__);
+ schedule_task_(milliseconds(200), [this, addr, try_role_switch]() {
+ LOG_INFO(LOG_TAG, "%s: Accepted", __func__);
+ MakeSlaveConnection(addr, try_role_switch);
+ });
+
+ return hci::Status::SUCCESS;
+}
+
+void LinkLayerController::MakeSlaveConnection(const Address& addr, bool try_role_switch) {
+ std::shared_ptr<LinkLayerPacketBuilder> to_send = LinkLayerPacketBuilder::WrapPageResponse(
+ PageResponseBuilder::Create(try_role_switch), properties_.GetAddress(), addr);
+ LOG_INFO(LOG_TAG, "%s sending page response to %s", __func__, addr.ToString().c_str());
+ SendLinkLayerPacket(to_send);
+
+ uint16_t handle = classic_connections_.CreateConnection(addr);
+ if (handle == acl::kReservedHandle) {
+ LOG_INFO(LOG_TAG, "%s CreateConnection failed", __func__);
+ return;
+ }
+ LOG_INFO(LOG_TAG, "%s CreateConnection returned handle 0x%x", __func__, handle);
+ send_event_(
+ EventPacketBuilder::CreateConnectionCompleteEvent(hci::Status::SUCCESS, handle, addr, hci::LinkType::ACL, false)
+ ->ToVector());
+}
+
+hci::Status LinkLayerController::RejectConnectionRequest(const Address& addr, uint8_t reason) {
+ if (!classic_connections_.HasPendingConnection(addr)) {
+ LOG_INFO(LOG_TAG, "%s: No pending connection", __func__);
+ return hci::Status::UNKNOWN_CONNECTION;
+ }
+
+ LOG_INFO(LOG_TAG, "%s: Reject in 200ms", __func__);
+ schedule_task_(milliseconds(200), [this, addr, reason]() {
+ LOG_INFO(LOG_TAG, "%s: Reject", __func__);
+ RejectSlaveConnection(addr, reason);
+ });
+
+ return hci::Status::SUCCESS;
+}
+
+void LinkLayerController::RejectSlaveConnection(const Address& addr, uint8_t reason) {
+ CHECK(reason > 0x0f || reason < 0x0d);
+ send_event_(EventPacketBuilder::CreateConnectionCompleteEvent(static_cast<hci::Status>(reason), 0xeff, addr,
+ hci::LinkType::ACL, false)
+ ->ToVector());
+}
+
+hci::Status LinkLayerController::CreateConnection(const Address& addr, uint16_t, uint8_t, uint16_t,
+ uint8_t allow_role_switch) {
+ if (!classic_connections_.CreatePendingConnection(addr)) {
+ return hci::Status::CONTROLLER_BUSY;
+ }
+
+ std::unique_ptr<PageBuilder> page = PageBuilder::Create(properties_.GetClassOfDevice(), allow_role_switch);
+ SendLinkLayerPacket(LinkLayerPacketBuilder::WrapPage(std::move(page), properties_.GetAddress(), addr));
+
+ return hci::Status::SUCCESS;
+}
+
+hci::Status LinkLayerController::CreateConnectionCancel(const Address& addr) {
+ if (!classic_connections_.CancelPendingConnection(addr)) {
+ return hci::Status::UNKNOWN_CONNECTION;
+ }
+ return hci::Status::SUCCESS;
+}
+
+hci::Status LinkLayerController::Disconnect(uint16_t handle, uint8_t reason) {
+ // TODO: Handle LE
+ if (!classic_connections_.HasHandle(handle)) {
+ return hci::Status::UNKNOWN_CONNECTION;
+ }
+
+ const Address& remote = classic_connections_.GetAddress(handle);
+ std::shared_ptr<LinkLayerPacketBuilder> to_send =
+ LinkLayerPacketBuilder::WrapDisconnect(DisconnectBuilder::Create(reason), properties_.GetAddress(), remote);
+ SendLinkLayerPacket(to_send);
+ CHECK(classic_connections_.Disconnect(handle)) << "Disconnecting " << handle;
+
+ schedule_task_(milliseconds(20), [this, handle]() {
+ DisconnectCleanup(handle, static_cast<uint8_t>(hci::Status::CONNECTION_TERMINATED_BY_LOCAL_HOST));
+ });
+
+ return hci::Status::SUCCESS;
+}
+
+void LinkLayerController::DisconnectCleanup(uint16_t handle, uint8_t reason) {
+ // TODO: Clean up other connection state.
+ send_event_(EventPacketBuilder::CreateDisconnectionCompleteEvent(hci::Status::SUCCESS, handle, reason)->ToVector());
+}
+
+hci::Status LinkLayerController::ChangeConnectionPacketType(uint16_t handle, uint16_t types) {
+ if (!classic_connections_.HasHandle(handle)) {
+ return hci::Status::UNKNOWN_CONNECTION;
+ }
+ std::unique_ptr<EventPacketBuilder> packet =
+ EventPacketBuilder::CreateConnectionPacketTypeChangedEvent(hci::Status::SUCCESS, handle, types);
+ std::shared_ptr<std::vector<uint8_t>> raw_packet = packet->ToVector();
+ if (schedule_task_) {
+ schedule_task_(milliseconds(20), [this, raw_packet]() { send_event_(raw_packet); });
+ } else {
+ send_event_(raw_packet);
+ }
+
+ return hci::Status::SUCCESS;
+}
+
+hci::Status LinkLayerController::WriteLinkPolicySettings(uint16_t handle, uint16_t) {
+ if (!classic_connections_.HasHandle(handle)) {
+ return hci::Status::UNKNOWN_CONNECTION;
+ }
+ return hci::Status::SUCCESS;
+}
+
+hci::Status LinkLayerController::WriteLinkSupervisionTimeout(uint16_t handle, uint16_t) {
+ if (!classic_connections_.HasHandle(handle)) {
+ return hci::Status::UNKNOWN_CONNECTION;
+ }
+ return hci::Status::SUCCESS;
+}
+
+void LinkLayerController::LeWhiteListClear() {
+ le_white_list_.clear();
+}
+
+void LinkLayerController::LeWhiteListAddDevice(Address addr, uint8_t addr_type) {
+ std::tuple<Address, uint8_t> new_tuple = std::make_tuple(addr, addr_type);
+ for (auto dev : le_white_list_) {
+ if (dev == new_tuple) {
+ return;
+ }
+ }
+ le_white_list_.emplace_back(new_tuple);
+}
+
+void LinkLayerController::LeWhiteListRemoveDevice(Address addr, uint8_t addr_type) {
+ // TODO: Add checks to see if advertising, scanning, or a connection request
+ // with the white list is ongoing.
+ std::tuple<Address, uint8_t> erase_tuple = std::make_tuple(addr, addr_type);
+ for (size_t i = 0; i < le_white_list_.size(); i++) {
+ if (le_white_list_[i] == erase_tuple) {
+ le_white_list_.erase(le_white_list_.begin() + i);
+ }
+ }
+}
+
+bool LinkLayerController::LeWhiteListContainsDevice(Address addr, uint8_t addr_type) {
+ std::tuple<Address, uint8_t> sought_tuple = std::make_tuple(addr, addr_type);
+ for (size_t i = 0; i < le_white_list_.size(); i++) {
+ if (le_white_list_[i] == sought_tuple) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool LinkLayerController::LeWhiteListFull() {
+ return le_white_list_.size() >= properties_.GetLeWhiteListSize();
+}
+
+void LinkLayerController::Reset() {
+ inquiry_state_ = Inquiry::InquiryState::STANDBY;
+ last_inquiry_ = steady_clock::now();
+ le_scan_enable_ = 0;
+ le_connect_ = 0;
+}
+
+void LinkLayerController::PageScan() {}
+
+void LinkLayerController::StartInquiry(milliseconds timeout) {
+ schedule_task_(milliseconds(timeout), [this]() { LinkLayerController::InquiryTimeout(); });
+ inquiry_state_ = Inquiry::InquiryState::INQUIRY;
+ LOG_INFO(LOG_TAG, "InquiryState = %d ", static_cast<int>(inquiry_state_));
+}
+
+void LinkLayerController::InquiryCancel() {
+ CHECK(inquiry_state_ == Inquiry::InquiryState::INQUIRY);
+ inquiry_state_ = Inquiry::InquiryState::STANDBY;
+}
+
+void LinkLayerController::InquiryTimeout() {
+ if (inquiry_state_ == Inquiry::InquiryState::INQUIRY) {
+ inquiry_state_ = Inquiry::InquiryState::STANDBY;
+ send_event_(EventPacketBuilder::CreateInquiryCompleteEvent(hci::Status::SUCCESS)->ToVector());
+ }
+}
+
+void LinkLayerController::SetInquiryMode(uint8_t mode) {
+ inquiry_mode_ = static_cast<Inquiry::InquiryType>(mode);
+}
+
+void LinkLayerController::SetInquiryLAP(uint64_t lap) {
+ inquiry_lap_ = lap;
+}
+
+void LinkLayerController::SetInquiryMaxResponses(uint8_t max) {
+ inquiry_max_responses_ = max;
+}
+
+void LinkLayerController::Inquiry() {
+ steady_clock::time_point now = steady_clock::now();
+ if (duration_cast<milliseconds>(now - last_inquiry_) < milliseconds(2000)) {
+ return;
+ }
+ LOG_INFO(LOG_TAG, "Inquiry ");
+ std::unique_ptr<InquiryBuilder> inquiry = InquiryBuilder::Create(inquiry_mode_);
+ std::shared_ptr<LinkLayerPacketBuilder> to_send =
+ LinkLayerPacketBuilder::WrapInquiry(std::move(inquiry), properties_.GetAddress());
+ SendLinkLayerPacket(to_send);
+ last_inquiry_ = now;
+}
+
+void LinkLayerController::SetInquiryScanEnable(bool enable) {
+ inquiry_scans_enabled_ = enable;
+}
+
+void LinkLayerController::SetPageScanEnable(bool enable) {
+ page_scans_enabled_ = enable;
+}
+
+/* TODO: Connection handling
+ // TODO: Handle in the link manager.
+ uint16_t handle = LeGetHandle();
+
+ std::shared_ptr<Connection> new_connection =
+ std::make_shared<Connection>(peer, handle);
+ connections_.push_back(new_connection);
+ peer->SetConnection(new_connection);
+
+ send_event_(EventPacketBuilder::CreateLeEnhancedConnectionCompleteEvent(
+ hci::Status::SUCCESS, handle, 0x00, // role
+ le_peer_address_type_, le_peer_address_, Address::kEmpty,
+ Address::kEmpty, 0x0024, 0x0000, 0x01f4)->ToVector());
+*/
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h b/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h
new file mode 100644
index 0000000..5cec196
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h
@@ -0,0 +1,269 @@
+/*
+ * Copyright 2017 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 "acl_connection_handler.h"
+#include "include/hci.h"
+#include "include/inquiry.h"
+#include "include/link.h"
+#include "include/phy.h"
+#include "model/devices/device_properties.h"
+#include "model/setup/async_manager.h"
+#include "packets/hci/acl_packet_view.h"
+#include "packets/hci/sco_packet_view.h"
+#include "packets/link_layer/link_layer_packet_builder.h"
+#include "packets/link_layer/link_layer_packet_view.h"
+#include "security_manager.h"
+#include "types/address.h"
+
+namespace test_vendor_lib {
+
+class LinkLayerController {
+ public:
+ LinkLayerController(const DeviceProperties& properties) : properties_(properties) {}
+ hci::Status SendCommandToRemoteByAddress(hci::OpCode opcode, packets::PacketView<true> args, const Address& remote,
+ bool use_public_address);
+ hci::Status SendCommandToRemoteByHandle(hci::OpCode opcode, packets::PacketView<true> args, uint16_t handle);
+ hci::Status SendScoToRemote(packets::ScoPacketView sco_packet);
+ hci::Status SendAclToRemote(packets::AclPacketView acl_packet);
+
+ void WriteSimplePairingMode(bool enabled);
+ void StartSimplePairing(const Address& address);
+ void AuthenticateRemoteStage1(const Address& address, PairingType pairing_type);
+ void AuthenticateRemoteStage2(const Address& address);
+ hci::Status LinkKeyRequestReply(const Address& address, packets::PacketView<true> key);
+ hci::Status LinkKeyRequestNegativeReply(const Address& address);
+ hci::Status IoCapabilityRequestReply(const Address& peer, uint8_t io_capability, uint8_t oob_data_present_flag,
+ uint8_t authentication_requirements);
+ hci::Status IoCapabilityRequestNegativeReply(const Address& peer, hci::Status reason);
+ hci::Status UserConfirmationRequestReply(const Address& peer);
+ hci::Status UserConfirmationRequestNegativeReply(const Address& peer);
+ hci::Status UserPasskeyRequestReply(const Address& peer, uint32_t numeric_value);
+ hci::Status UserPasskeyRequestNegativeReply(const Address& peer);
+ hci::Status RemoteOobDataRequestReply(const Address& peer, const std::vector<uint8_t>& c,
+ const std::vector<uint8_t>& r);
+ hci::Status RemoteOobDataRequestNegativeReply(const Address& peer);
+ void HandleSetConnectionEncryption(const Address& address, uint16_t handle, uint8_t encryption_enable);
+ hci::Status SetConnectionEncryption(uint16_t handle, uint8_t encryption_enable);
+ void HandleAuthenticationRequest(const Address& address, uint16_t handle);
+ hci::Status AuthenticationRequested(uint16_t handle);
+
+ hci::Status AcceptConnectionRequest(const Address& addr, bool try_role_switch);
+ void MakeSlaveConnection(const Address& addr, bool try_role_switch);
+ hci::Status RejectConnectionRequest(const Address& addr, uint8_t reason);
+ void RejectSlaveConnection(const Address& addr, uint8_t reason);
+ hci::Status CreateConnection(const Address& addr, uint16_t packet_type, uint8_t page_scan_mode, uint16_t clock_offset,
+ uint8_t allow_role_switch);
+ hci::Status CreateConnectionCancel(const Address& addr);
+ hci::Status Disconnect(uint16_t handle, uint8_t reason);
+
+ private:
+ void DisconnectCleanup(uint16_t handle, uint8_t reason);
+
+ public:
+ void IncomingPacket(packets::LinkLayerPacketView incoming);
+
+ void TimerTick();
+
+ // Set the callbacks for sending packets to the HCI.
+ void RegisterEventChannel(const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& send_event);
+
+ void RegisterAclChannel(const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& send_acl);
+
+ void RegisterScoChannel(const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& send_sco);
+
+ void RegisterRemoteChannel(
+ const std::function<void(std::shared_ptr<packets::LinkLayerPacketBuilder>, Phy::Type)>& send_to_remote);
+
+ // Set the callbacks for scheduling tasks.
+ void RegisterTaskScheduler(
+ std::function<AsyncTaskId(std::chrono::milliseconds, const TaskCallback&)> event_scheduler);
+
+ void RegisterPeriodicTaskScheduler(
+ std::function<AsyncTaskId(std::chrono::milliseconds, std::chrono::milliseconds, const TaskCallback&)>
+ periodic_event_scheduler);
+
+ void RegisterTaskCancel(std::function<void(AsyncTaskId)> cancel);
+ void Reset();
+ void AddControllerEvent(std::chrono::milliseconds delay, const TaskCallback& task);
+
+ void PageScan();
+ void Connections();
+
+ void LeWhiteListClear();
+ void LeWhiteListAddDevice(Address addr, uint8_t addr_type);
+ void LeWhiteListRemoveDevice(Address addr, uint8_t addr_type);
+ bool LeWhiteListContainsDevice(Address addr, uint8_t addr_type);
+ bool LeWhiteListFull();
+
+ void SetLeScanEnable(uint8_t le_scan_enable) {
+ le_scan_enable_ = le_scan_enable;
+ }
+ void SetLeScanType(uint8_t le_scan_type) {
+ le_scan_type_ = le_scan_type;
+ }
+ void SetLeScanInterval(uint16_t le_scan_interval) {
+ le_scan_interval_ = le_scan_interval;
+ }
+ void SetLeScanWindow(uint16_t le_scan_window) {
+ le_scan_window_ = le_scan_window;
+ }
+ void SetLeScanFilterPolicy(uint8_t le_scan_filter_policy) {
+ le_scan_filter_policy_ = le_scan_filter_policy;
+ }
+ void SetLeFilterDuplicates(uint8_t le_scan_filter_duplicates) {
+ le_scan_filter_duplicates_ = le_scan_filter_duplicates;
+ }
+ void SetLeAddressType(uint8_t le_address_type) {
+ le_address_type_ = le_address_type;
+ }
+ hci::Status SetLeConnect(bool le_connect) {
+ le_connect_ = le_connect;
+ return hci::Status::SUCCESS;
+ }
+ void SetLeConnectionIntervalMin(uint16_t min) {
+ le_connection_interval_min_ = min;
+ }
+ void SetLeConnectionIntervalMax(uint16_t max) {
+ le_connection_interval_max_ = max;
+ }
+ void SetLeConnectionLatency(uint16_t latency) {
+ le_connection_latency_ = latency;
+ }
+ void SetLeSupervisionTimeout(uint16_t timeout) {
+ le_connection_supervision_timeout_ = timeout;
+ }
+ void SetLeMinimumCeLength(uint16_t min) {
+ le_connection_minimum_ce_length_ = min;
+ }
+ void SetLeMaximumCeLength(uint16_t max) {
+ le_connection_maximum_ce_length_ = max;
+ }
+ void SetLeInitiatorFilterPolicy(uint8_t le_initiator_filter_policy) {
+ le_initiator_filter_policy_ = le_initiator_filter_policy;
+ }
+ void SetLePeerAddressType(uint8_t peer_address_type) {
+ le_peer_address_type_ = peer_address_type;
+ }
+ void SetLePeerAddress(const Address& peer_address) {
+ le_peer_address_ = peer_address;
+ }
+
+ // Classic
+ void StartInquiry(std::chrono::milliseconds timeout);
+ void InquiryCancel();
+ void InquiryTimeout();
+ void SetInquiryMode(uint8_t mode);
+ void SetInquiryLAP(uint64_t lap);
+ void SetInquiryMaxResponses(uint8_t max);
+ void Inquiry();
+
+ void SetInquiryScanEnable(bool enable);
+ void SetPageScanEnable(bool enable);
+
+ hci::Status ChangeConnectionPacketType(uint16_t handle, uint16_t types);
+ hci::Status WriteLinkPolicySettings(uint16_t handle, uint16_t settings);
+ hci::Status WriteLinkSupervisionTimeout(uint16_t handle, uint16_t timeout);
+
+ protected:
+ void SendLELinkLayerPacket(std::shared_ptr<packets::LinkLayerPacketBuilder> packet);
+ void SendLinkLayerPacket(std::shared_ptr<packets::LinkLayerPacketBuilder> packet);
+ void IncomingAclPacket(packets::LinkLayerPacketView packet);
+ void IncomingAclAckPacket(packets::LinkLayerPacketView packet);
+ void IncomingCommandPacket(packets::LinkLayerPacketView packet);
+ void IncomingCreateConnectionPacket(packets::LinkLayerPacketView packet);
+ void IncomingDisconnectPacket(packets::LinkLayerPacketView packet);
+ void IncomingEncryptConnection(packets::LinkLayerPacketView packet);
+ void IncomingEncryptConnectionResponse(packets::LinkLayerPacketView packet);
+ void IncomingInquiryPacket(packets::LinkLayerPacketView packet);
+ void IncomingInquiryResponsePacket(packets::LinkLayerPacketView packet);
+ void IncomingIoCapabilityRequestPacket(packets::LinkLayerPacketView packet);
+ void IncomingIoCapabilityResponsePacket(packets::LinkLayerPacketView packet);
+ void IncomingIoCapabilityNegativeResponsePacket(packets::LinkLayerPacketView packet);
+ void IncomingLeAdvertisementPacket(packets::LinkLayerPacketView packet);
+ void IncomingLeScanPacket(packets::LinkLayerPacketView packet);
+ void IncomingLeScanResponsePacket(packets::LinkLayerPacketView packet);
+ void IncomingPagePacket(packets::LinkLayerPacketView packet);
+ void IncomingPageResponsePacket(packets::LinkLayerPacketView packet);
+ void IncomingResponsePacket(packets::LinkLayerPacketView packet);
+
+ private:
+ const DeviceProperties& properties_;
+ AclConnectionHandler classic_connections_;
+ // Add timestamps?
+ std::vector<std::shared_ptr<packets::LinkLayerPacketBuilder>> commands_awaiting_responses_;
+
+ // Timing related state
+ std::vector<AsyncTaskId> controller_events_;
+ AsyncTaskId timer_tick_task_;
+ std::chrono::milliseconds timer_period_ = std::chrono::milliseconds(100);
+
+ // Callbacks to schedule tasks.
+ std::function<AsyncTaskId(std::chrono::milliseconds, const TaskCallback&)> schedule_task_;
+ std::function<AsyncTaskId(std::chrono::milliseconds, std::chrono::milliseconds, const TaskCallback&)>
+ schedule_periodic_task_;
+ std::function<void(AsyncTaskId)> cancel_task_;
+
+ // Callbacks to send packets back to the HCI.
+ std::function<void(std::shared_ptr<std::vector<uint8_t>>)> send_acl_;
+ std::function<void(std::shared_ptr<std::vector<uint8_t>>)> send_event_;
+ std::function<void(std::shared_ptr<std::vector<uint8_t>>)> send_sco_;
+
+ // Callback to send packets to remote devices.
+ std::function<void(std::shared_ptr<packets::LinkLayerPacketBuilder>, Phy::Type phy_type)> send_to_remote_;
+
+ // LE state
+ std::vector<uint8_t> le_event_mask_;
+
+ std::vector<std::tuple<Address, uint8_t>> le_white_list_;
+
+ uint8_t le_scan_enable_;
+ uint8_t le_scan_type_;
+ uint16_t le_scan_interval_;
+ uint16_t le_scan_window_;
+ uint8_t le_scan_filter_policy_;
+ uint8_t le_scan_filter_duplicates_;
+ uint8_t le_address_type_;
+
+ bool le_connect_;
+ uint16_t le_connection_interval_min_;
+ uint16_t le_connection_interval_max_;
+ uint16_t le_connection_latency_;
+ uint16_t le_connection_supervision_timeout_;
+ uint16_t le_connection_minimum_ce_length_;
+ uint16_t le_connection_maximum_ce_length_;
+ uint8_t le_initiator_filter_policy_;
+
+ Address le_peer_address_;
+ uint8_t le_peer_address_type_;
+
+ // Classic state
+
+ SecurityManager security_manager_{10};
+ std::chrono::steady_clock::time_point last_inquiry_;
+ Inquiry::InquiryType inquiry_mode_;
+ Inquiry::InquiryState inquiry_state_;
+ uint64_t inquiry_lap_;
+ uint8_t inquiry_max_responses_;
+
+ bool page_scans_enabled_{false};
+ bool inquiry_scans_enabled_{false};
+
+ bool simple_pairing_mode_enabled_{false};
+};
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/controller/security_manager.cc b/vendor_libs/test_vendor_lib/model/controller/security_manager.cc
new file mode 100644
index 0000000..6ab1351
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/controller/security_manager.cc
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2017 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 "security_manager"
+
+#include "security_manager.h"
+
+#include "base/logging.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+uint16_t SecurityManager::DeleteAllKeys() {
+ uint16_t size = key_store_.size();
+ key_store_.clear();
+ return size;
+}
+
+uint16_t SecurityManager::DeleteKey(const Address& addr) {
+ uint16_t count = key_store_.count(addr.ToString());
+ if (count) {
+ key_store_.erase(addr.ToString());
+ }
+ return count;
+}
+
+uint16_t SecurityManager::ReadAllKeys() const {
+ return key_store_.size();
+}
+
+uint16_t SecurityManager::ReadKey(const Address& addr) const {
+ return key_store_.count(addr.ToString());
+}
+
+uint16_t SecurityManager::WriteKey(const Address& addr, const std::vector<uint8_t>& key) {
+ if (key_store_.size() >= max_keys_) {
+ return 0;
+ }
+ key_store_[addr.ToString()] = key;
+ return 1;
+}
+
+const std::vector<uint8_t>& SecurityManager::GetKey(const Address& addr) const {
+ CHECK(ReadKey(addr)) << "No such key";
+ return key_store_.at(addr.ToString());
+}
+
+void SecurityManager::AuthenticationRequest(const Address& addr, uint16_t handle) {
+ authenticating_ = true;
+ current_handle_ = handle;
+ peer_address_ = addr;
+}
+
+void SecurityManager::AuthenticationRequestFinished() {
+ authenticating_ = false;
+}
+
+bool SecurityManager::AuthenticationInProgress() {
+ return authenticating_;
+}
+
+uint16_t SecurityManager::GetAuthenticationHandle() {
+ return current_handle_;
+}
+
+Address SecurityManager::GetAuthenticationAddress() {
+ return peer_address_;
+}
+
+void SecurityManager::SetPeerIoCapability(const Address& addr, uint8_t io_capability, uint8_t oob_present_flag,
+ uint8_t authentication_requirements) {
+ CHECK_EQ(addr, peer_address_);
+ peer_capabilities_valid_ = true;
+ if (io_capability <= static_cast<uint8_t>(IoCapabilityType::NO_INPUT_NO_OUTPUT)) {
+ peer_io_capability_ = static_cast<IoCapabilityType>(io_capability);
+ } else {
+ peer_io_capability_ = IoCapabilityType::INVALID;
+ peer_capabilities_valid_ = false;
+ }
+ peer_oob_present_flag_ = (oob_present_flag == 1);
+ if (authentication_requirements <= static_cast<uint8_t>(AuthenticationType::GENERAL_BONDING_MITM)) {
+ peer_authentication_requirements_ = static_cast<AuthenticationType>(authentication_requirements);
+ } else {
+ peer_authentication_requirements_ = AuthenticationType::INVALID;
+ peer_capabilities_valid_ = false;
+ }
+}
+
+void SecurityManager::SetLocalIoCapability(const Address& peer, uint8_t io_capability, uint8_t oob_present_flag,
+ uint8_t authentication_requirements) {
+ CHECK_EQ(peer, peer_address_);
+ CHECK(io_capability <= static_cast<uint8_t>(IoCapabilityType::NO_INPUT_NO_OUTPUT))
+ << "io_capability = " << io_capability;
+ CHECK(oob_present_flag <= 1) << "oob_present_flag = " << oob_present_flag;
+ CHECK(authentication_requirements <= static_cast<uint8_t>(AuthenticationType::GENERAL_BONDING_MITM))
+ << "authentication_requirements = " << authentication_requirements;
+ host_io_capability_ = static_cast<IoCapabilityType>(io_capability);
+ host_oob_present_flag_ = (oob_present_flag == 1);
+ host_authentication_requirements_ = static_cast<AuthenticationType>(authentication_requirements);
+ host_capabilities_valid_ = true;
+}
+
+void SecurityManager::InvalidateIoCapabilities() {
+ host_capabilities_valid_ = false;
+ peer_capabilities_valid_ = false;
+}
+
+PairingType SecurityManager::GetSimplePairingType() {
+ if (!host_capabilities_valid_ || !peer_capabilities_valid_) {
+ return PairingType::INVALID;
+ }
+ bool host_requires_mitm = (host_authentication_requirements_ == AuthenticationType::NO_BONDING_MITM) ||
+ (host_authentication_requirements_ == AuthenticationType::DEDICATED_BONDING_MITM) ||
+ (host_authentication_requirements_ == AuthenticationType::GENERAL_BONDING_MITM);
+ bool peer_requires_mitm = (peer_authentication_requirements_ == AuthenticationType::NO_BONDING_MITM) ||
+ (peer_authentication_requirements_ == AuthenticationType::DEDICATED_BONDING_MITM) ||
+ (peer_authentication_requirements_ == AuthenticationType::GENERAL_BONDING_MITM);
+ if (!(peer_requires_mitm || host_requires_mitm)) {
+ return PairingType::AUTO_CONFIRMATION;
+ }
+ return PairingType::INVALID;
+}
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/controller/security_manager.h b/vendor_libs/test_vendor_lib/model/controller/security_manager.h
new file mode 100644
index 0000000..94284cb
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/controller/security_manager.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2017 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 <string>
+#include <unordered_map>
+#include <vector>
+
+#include "types/address.h"
+
+namespace test_vendor_lib {
+
+enum class PairingType : uint8_t {
+ AUTO_CONFIRMATION,
+ CONFIRM_Y_N,
+ DISPLAY_PIN,
+ DISPLAY_AND_CONFIRM,
+ INPUT_PIN,
+ INVALID = 0xff,
+};
+
+enum class IoCapabilityType : uint8_t {
+ DISPLAY_ONLY = 0,
+ DISPLAY_YES_NO = 1,
+ KEYBOARD_ONLY = 2,
+ NO_INPUT_NO_OUTPUT = 3,
+ INVALID = 0xff,
+};
+
+enum class AuthenticationType : uint8_t {
+ NO_BONDING = 0,
+ NO_BONDING_MITM = 1,
+ DEDICATED_BONDING = 2,
+ DEDICATED_BONDING_MITM = 3,
+ GENERAL_BONDING = 4,
+ GENERAL_BONDING_MITM = 5,
+ INVALID = 0xff,
+};
+
+// Encapsulate the details of storing and retrieving keys.
+class SecurityManager {
+ public:
+ SecurityManager(uint16_t num_keys) : max_keys_(num_keys) {}
+ virtual ~SecurityManager() = default;
+
+ uint16_t DeleteAllKeys();
+ uint16_t DeleteKey(const Address& addr);
+ uint16_t ReadAllKeys() const;
+ uint16_t ReadKey(const Address& addr) const;
+ uint16_t WriteKey(const Address& addr, const std::vector<uint8_t>& key);
+ uint16_t ReadCapacity() const {
+ return max_keys_;
+ };
+
+ const std::vector<uint8_t>& GetKey(const Address& addr) const;
+
+ void AuthenticationRequest(const Address& addr, uint16_t handle);
+ void AuthenticationRequestFinished();
+
+ bool AuthenticationInProgress();
+ uint16_t GetAuthenticationHandle();
+ Address GetAuthenticationAddress();
+
+ void SetPeerIoCapability(const Address& addr, uint8_t io_capability, uint8_t oob_present_flag,
+ uint8_t authentication_requirements);
+ void SetLocalIoCapability(const Address& peer, uint8_t io_capability, uint8_t oob_present_flag,
+ uint8_t authentication_requirements);
+
+ PairingType GetSimplePairingType();
+
+ void InvalidateIoCapabilities();
+
+ private:
+ uint16_t max_keys_;
+ std::unordered_map<std::string, std::vector<uint8_t>> key_store_;
+
+ bool peer_capabilities_valid_{false};
+ IoCapabilityType peer_io_capability_;
+ bool peer_oob_present_flag_;
+ AuthenticationType peer_authentication_requirements_;
+
+ bool host_capabilities_valid_{false};
+ IoCapabilityType host_io_capability_;
+ bool host_oob_present_flag_;
+ AuthenticationType host_authentication_requirements_;
+
+ bool authenticating_{false};
+ uint16_t current_handle_;
+ Address peer_address_;
+};
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/beacon.cc b/vendor_libs/test_vendor_lib/model/devices/beacon.cc
new file mode 100644
index 0000000..1adaf29
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/beacon.cc
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2016 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 "beacon"
+
+#include "beacon.h"
+
+#include "le_advertisement.h"
+#include "model/setup/device_boutique.h"
+#include "osi/include/log.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+bool Beacon::registered_ = DeviceBoutique::Register(LOG_TAG, &Beacon::Create);
+
+Beacon::Beacon() {
+ advertising_interval_ms_ = std::chrono::milliseconds(1280);
+ properties_.SetLeAdvertisementType(BTM_BLE_NON_CONNECT_EVT);
+ properties_.SetLeAdvertisement({0x0F, // Length
+ BTM_BLE_AD_TYPE_NAME_CMPL, 'g', 'D', 'e', 'v', 'i', 'c', 'e', '-', 'b', 'e', 'a', 'c',
+ 'o', 'n',
+ 0x02, // Length
+ BTM_BLE_AD_TYPE_FLAG, BTM_BLE_BREDR_NOT_SPT | BTM_BLE_GEN_DISC_FLAG});
+
+ properties_.SetLeScanResponse({0x05, // Length
+ BTM_BLE_AD_TYPE_NAME_SHORT, 'b', 'e', 'a', 'c'});
+}
+
+std::string Beacon::GetTypeString() const {
+ return "beacon";
+}
+
+std::string Beacon::ToString() const {
+ std::string dev = GetTypeString() + "@" + properties_.GetLeAddress().ToString();
+
+ return dev;
+}
+
+void Beacon::Initialize(const vector<std::string>& args) {
+ if (args.size() < 2) return;
+
+ Address addr;
+ if (Address::FromString(args[1], addr)) properties_.SetLeAddress(addr);
+
+ if (args.size() < 3) return;
+
+ SetAdvertisementInterval(std::chrono::milliseconds(std::stoi(args[2])));
+}
+
+void Beacon::TimerTick() {
+ LOG_INFO(LOG_TAG, "TimerTick()");
+ if (IsAdvertisementAvailable(std::chrono::milliseconds(5000))) {
+ LOG_INFO(LOG_TAG, "Generating Advertisement %d", static_cast<int>(properties_.GetLeAdvertisement().size()));
+ std::unique_ptr<packets::LeAdvertisementBuilder> ad = packets::LeAdvertisementBuilder::Create(
+ LeAdvertisement::AddressType::PUBLIC,
+ static_cast<LeAdvertisement::AdvertisementType>(properties_.GetLeAdvertisementType()),
+ properties_.GetLeAdvertisement());
+ std::shared_ptr<packets::LinkLayerPacketBuilder> to_send =
+ packets::LinkLayerPacketBuilder::WrapLeAdvertisement(std::move(ad), properties_.GetLeAddress());
+ std::vector<std::shared_ptr<PhyLayer>> le_phys = phy_layers_[Phy::Type::LOW_ENERGY];
+ for (std::shared_ptr<PhyLayer> phy : le_phys) {
+ LOG_INFO(LOG_TAG, "Sending Advertisement on a Phy");
+ phy->Send(to_send);
+ }
+ }
+}
+
+void Beacon::IncomingPacket(packets::LinkLayerPacketView packet) {
+ LOG_INFO(LOG_TAG, "Got a packet of type %d", static_cast<int>(packet.GetType()));
+ if (packet.GetDestinationAddress() == properties_.GetLeAddress() && packet.GetType() == Link::PacketType::LE_SCAN) {
+ LOG_INFO(LOG_TAG, "Got a scan");
+ std::unique_ptr<packets::LeAdvertisementBuilder> scan_response = packets::LeAdvertisementBuilder::Create(
+ LeAdvertisement::AddressType::PUBLIC, LeAdvertisement::AdvertisementType::SCAN_RESPONSE,
+ properties_.GetLeScanResponse());
+ std::shared_ptr<packets::LinkLayerPacketBuilder> to_send = packets::LinkLayerPacketBuilder::WrapLeScanResponse(
+ std::move(scan_response), properties_.GetLeAddress(), packet.GetSourceAddress());
+ std::vector<std::shared_ptr<PhyLayer>> le_phys = phy_layers_[Phy::Type::LOW_ENERGY];
+ for (auto phy : le_phys) {
+ LOG_INFO(LOG_TAG, "Sending a Scan Response on a Phy");
+ phy->Send(to_send);
+ }
+ }
+}
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/beacon.h b/vendor_libs/test_vendor_lib/model/devices/beacon.h
new file mode 100644
index 0000000..faac5cc
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/beacon.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2016 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 "device.h"
+#include "stack/include/btm_ble_api.h"
+
+namespace test_vendor_lib {
+
+// A simple device that advertises periodically and is not connectable.
+class Beacon : public Device {
+ public:
+ Beacon();
+ virtual ~Beacon() = default;
+
+ static std::shared_ptr<Device> Create() {
+ return std::make_shared<Beacon>();
+ }
+
+ // Return a string representation of the type of device.
+ virtual std::string GetTypeString() const override;
+
+ // Return a string representation of the device.
+ virtual std::string ToString() const override;
+
+ // Set the address and advertising interval from string args.
+ virtual void Initialize(const std::vector<std::string>& args) override;
+
+ virtual void IncomingPacket(packets::LinkLayerPacketView packet) override;
+
+ virtual void TimerTick() override;
+
+ private:
+ static bool registered_;
+};
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/beacon_swarm.cc b/vendor_libs/test_vendor_lib/model/devices/beacon_swarm.cc
new file mode 100644
index 0000000..a065c36
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/beacon_swarm.cc
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2016 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 "beacon_swarm"
+
+#include "beacon_swarm.h"
+
+#include "model/setup/device_boutique.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+bool BeaconSwarm::registered_ = DeviceBoutique::Register(LOG_TAG, &BeaconSwarm::Create);
+
+BeaconSwarm::BeaconSwarm() {
+ advertising_interval_ms_ = std::chrono::milliseconds(1280);
+ properties_.SetLeAdvertisementType(BTM_BLE_NON_CONNECT_EVT);
+ properties_.SetLeAdvertisement({
+ 0x15, // Length
+ BTM_BLE_AD_TYPE_NAME_CMPL,
+ 'g',
+ 'D',
+ 'e',
+ 'v',
+ 'i',
+ 'c',
+ 'e',
+ '-',
+ 'b',
+ 'e',
+ 'a',
+ 'c',
+ 'o',
+ 'n',
+ '_',
+ 's',
+ 'w',
+ 'a',
+ 'r',
+ 'm',
+ 0x02, // Length
+ BTM_BLE_AD_TYPE_FLAG,
+ BTM_BLE_BREDR_NOT_SPT | BTM_BLE_GEN_DISC_FLAG,
+ });
+
+ properties_.SetLeScanResponse({0x06, // Length
+ BTM_BLE_AD_TYPE_NAME_SHORT, 'c', 'b', 'e', 'a', 'c'});
+}
+
+void BeaconSwarm::Initialize(const vector<std::string>& args) {
+ if (args.size() < 2) return;
+
+ Address addr;
+ if (Address::FromString(args[1], addr)) properties_.SetLeAddress(addr);
+
+ if (args.size() < 3) return;
+
+ SetAdvertisementInterval(std::chrono::milliseconds(std::stoi(args[2])));
+}
+
+void BeaconSwarm::TimerTick() {
+ Address beacon_addr = properties_.GetLeAddress();
+ uint8_t* low_order_byte = (uint8_t*)(&beacon_addr);
+ *low_order_byte += 1;
+ properties_.SetLeAddress(beacon_addr);
+ Beacon::TimerTick();
+}
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/beacon_swarm.h b/vendor_libs/test_vendor_lib/model/devices/beacon_swarm.h
new file mode 100644
index 0000000..e1bfd75
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/beacon_swarm.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2016 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 "beacon.h"
+
+namespace test_vendor_lib {
+
+// Pretend to be a lot of beacons by changing the advertising address.
+class BeaconSwarm : public Beacon {
+ public:
+ BeaconSwarm();
+ virtual ~BeaconSwarm() = default;
+
+ static std::shared_ptr<Device> Create() {
+ return std::make_shared<BeaconSwarm>();
+ }
+
+ // Return a string representation of the type of device.
+ virtual std::string GetTypeString() const override {
+ return "beacon_swarm";
+ }
+
+ // Set the address and advertising interval from string args.
+ virtual void Initialize(const std::vector<std::string>& args) override;
+
+ virtual void TimerTick() override;
+
+ private:
+ static bool registered_;
+};
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/broken_adv.cc b/vendor_libs/test_vendor_lib/model/devices/broken_adv.cc
new file mode 100644
index 0000000..c7d6822
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/broken_adv.cc
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2016 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 "broken_adv"
+
+#include "broken_adv.h"
+
+#include "model/setup/device_boutique.h"
+#include "osi/include/log.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+bool BrokenAdv::registered_ = DeviceBoutique::Register(LOG_TAG, &BrokenAdv::Create);
+
+BrokenAdv::BrokenAdv() {
+ advertising_interval_ms_ = std::chrono::milliseconds(1280);
+ properties_.SetLeAdvertisementType(BTM_BLE_NON_CONNECT_EVT);
+ constant_adv_data_ = {
+ 0x02, // Length
+ BTM_BLE_AD_TYPE_FLAG,
+ BTM_BLE_BREDR_NOT_SPT | BTM_BLE_GEN_DISC_FLAG,
+ 0x13, // Length
+ BTM_BLE_AD_TYPE_NAME_CMPL,
+ 'g',
+ 'D',
+ 'e',
+ 'v',
+ 'i',
+ 'c',
+ 'e',
+ '-',
+ 'b',
+ 'r',
+ 'o',
+ 'k',
+ 'e',
+ 'n',
+ '_',
+ 'a',
+ 'd',
+ 'v',
+ };
+ properties_.SetLeAdvertisement(constant_adv_data_);
+
+ properties_.SetLeScanResponse({0x0b, // Length
+ BTM_BLE_AD_TYPE_NAME_SHORT, 'b', 'r', 'o', 'k', 'e', 'n', 'n', 'e', 's', 's'});
+
+ properties_.SetExtendedInquiryData({0x07, // Length
+ BT_EIR_COMPLETE_LOCAL_NAME_TYPE, 'B', 'R', '0', 'K', '3', 'N'});
+ properties_.SetPageScanRepetitionMode(0);
+ page_scan_delay_ms_ = std::chrono::milliseconds(600);
+}
+
+void BrokenAdv::Initialize(const vector<std::string>& args) {
+ if (args.size() < 2) return;
+
+ Address addr;
+ if (Address::FromString(args[1], addr)) properties_.SetLeAddress(addr);
+
+ if (args.size() < 3) return;
+
+ SetAdvertisementInterval(std::chrono::milliseconds(std::stoi(args[2])));
+}
+
+// Mostly return the correct length
+static uint8_t random_length(size_t bytes_remaining) {
+ uint32_t randomness = rand();
+
+ switch ((randomness & 0xf000000) >> 24) {
+ case (0):
+ return bytes_remaining + (randomness & 0xff);
+ case (1):
+ return bytes_remaining - (randomness & 0xff);
+ case (2):
+ return bytes_remaining + (randomness & 0xf);
+ case (3):
+ return bytes_remaining - (randomness & 0xf);
+ case (5):
+ case (6):
+ return bytes_remaining + (randomness & 0x3);
+ case (7):
+ case (8):
+ return bytes_remaining - (randomness & 0x3);
+ default:
+ return bytes_remaining;
+ }
+}
+
+static size_t random_adv_type() {
+ uint32_t randomness = rand();
+
+ switch ((randomness & 0xf000000) >> 24) {
+ case (0):
+ return BTM_EIR_MANUFACTURER_SPECIFIC_TYPE;
+ case (1):
+ return (randomness & 0xff);
+ default:
+ return (randomness & 0x1f);
+ }
+}
+
+static size_t random_data_length(size_t length, size_t bytes_remaining) {
+ uint32_t randomness = rand();
+
+ switch ((randomness & 0xf000000) >> 24) {
+ case (0):
+ return bytes_remaining;
+ case (1):
+ return (length + (randomness & 0xff)) % bytes_remaining;
+ default:
+ return (length <= bytes_remaining ? length : bytes_remaining);
+ }
+}
+
+static void RandomizeAdvertisement(vector<uint8_t>& ad, size_t max) {
+ uint8_t length = random_length(max);
+ uint8_t data_length = random_data_length(length, max);
+
+ ad.push_back(random_adv_type());
+ ad.push_back(length);
+ for (size_t i = 0; i < data_length; i++) ad.push_back(rand() & 0xff);
+}
+
+void BrokenAdv::UpdateAdvertisement() {
+ std::vector<uint8_t> adv_data;
+ for (size_t i = 0; i < constant_adv_data_.size(); i++) adv_data.push_back(constant_adv_data_[i]);
+
+ RandomizeAdvertisement(adv_data, 31 - adv_data.size());
+ properties_.SetLeAdvertisement(adv_data);
+
+ adv_data.clear();
+ RandomizeAdvertisement(adv_data, 31);
+ properties_.SetLeScanResponse(adv_data);
+
+ Address le_addr = properties_.GetLeAddress();
+ uint8_t* low_order_byte = (uint8_t*)(&le_addr);
+ *low_order_byte += 1;
+ properties_.SetLeAddress(le_addr);
+}
+
+std::string BrokenAdv::ToString() const {
+ std::string str =
+ Device::ToString() + std::string(": Interval = ") + std::to_string(advertising_interval_ms_.count());
+ return str;
+}
+
+void BrokenAdv::UpdatePageScan() {
+ RandomizeAdvertisement(constant_scan_data_, 31);
+
+ Address page_addr = properties_.GetAddress();
+ uint8_t* low_order_byte = (uint8_t*)(&page_addr);
+ *low_order_byte += 1;
+ properties_.SetAddress(page_addr);
+}
+
+void BrokenAdv::TimerTick() {
+ UpdatePageScan();
+ UpdateAdvertisement();
+}
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/broken_adv.h b/vendor_libs/test_vendor_lib/model/devices/broken_adv.h
new file mode 100644
index 0000000..2431676
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/broken_adv.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2016 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 "device.h"
+
+namespace test_vendor_lib {
+
+class BrokenAdv : public Device {
+ public:
+ BrokenAdv();
+ ~BrokenAdv() = default;
+
+ static std::shared_ptr<Device> Create() {
+ return std::make_shared<BrokenAdv>();
+ }
+
+ // Initialize the device based on the values of |args|.
+ virtual void Initialize(const std::vector<std::string>& args) override;
+
+ // Return a string representation of the type of device.
+ virtual std::string GetTypeString() const override {
+ return "broken_adv";
+ }
+
+ // Return the string representation of the device.
+ virtual std::string ToString() const override;
+
+ // Use the timer tick to update advertisements.
+ void TimerTick() override;
+
+ // Change which advertisements are broken and the address of the device.
+ void UpdateAdvertisement();
+
+ // Change which data is broken and the address of the device.
+ void UpdatePageScan();
+
+ private:
+ std::vector<uint8_t> constant_adv_data_;
+ std::vector<uint8_t> constant_scan_data_;
+ static bool registered_;
+};
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/car_kit.cc b/vendor_libs/test_vendor_lib/model/devices/car_kit.cc
new file mode 100644
index 0000000..5f7fa4a
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/car_kit.cc
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2018 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 "car_kit"
+
+#include "car_kit.h"
+
+#include "osi/include/log.h"
+
+#include "model/setup/device_boutique.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+bool CarKit::registered_ = DeviceBoutique::Register(LOG_TAG, &CarKit::Create);
+
+CarKit::CarKit() : Device(kCarKitPropertiesFile) {
+ advertising_interval_ms_ = std::chrono::milliseconds(0);
+
+ page_scan_delay_ms_ = std::chrono::milliseconds(600);
+
+ // Stub in packet handling for now
+ link_layer_controller_.RegisterAclChannel([](std::shared_ptr<std::vector<uint8_t>>) {});
+ link_layer_controller_.RegisterEventChannel([](std::shared_ptr<std::vector<uint8_t>>) {});
+ link_layer_controller_.RegisterScoChannel([](std::shared_ptr<std::vector<uint8_t>>) {});
+ link_layer_controller_.RegisterRemoteChannel(
+ [this](std::shared_ptr<packets::LinkLayerPacketBuilder> packet, Phy::Type phy_type) {
+ CarKit::SendLinkLayerPacket(packet, phy_type);
+ });
+
+ properties_.SetPageScanRepetitionMode(0);
+ properties_.SetClassOfDevice(0x600420);
+ properties_.SetSupportedFeatures(0x8779ff9bfe8defff);
+ properties_.SetExtendedInquiryData({
+ 16, // length
+ 9, // Type: Device Name
+ 'g', 'D', 'e', 'v', 'i', 'c', 'e', '-', 'c', 'a', 'r', '_', 'k', 'i', 't',
+ 7, // length
+ 3, // Type: 16-bit UUIDs
+ 0x0e, // AVRC
+ 0x11,
+ 0x0B, // Audio Sink
+ 0x11,
+ 0x00, // PnP Information
+ 0x12,
+ });
+ properties_.SetName({
+ 'g',
+ 'D',
+ 'e',
+ 'v',
+ 'i',
+ 'c',
+ 'e',
+ '-',
+ 'C',
+ 'a',
+ 'r',
+ '_',
+ 'K',
+ 'i',
+ 't',
+ });
+}
+
+void CarKit::Initialize(const vector<std::string>& args) {
+ if (args.size() < 2) return;
+
+ Address addr;
+ if (Address::FromString(args[1], addr)) properties_.SetAddress(addr);
+ LOG_INFO(LOG_TAG, "%s SetAddress %s", ToString().c_str(), addr.ToString().c_str());
+
+ if (args.size() < 3) return;
+
+ properties_.SetClockOffset(std::stoi(args[2]));
+}
+
+void CarKit::TimerTick() {
+ link_layer_controller_.TimerTick();
+}
+
+void CarKit::IncomingPacket(packets::LinkLayerPacketView packet) {
+ LOG_WARN(LOG_TAG, "Incoming Packet");
+ link_layer_controller_.IncomingPacket(packet);
+}
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/car_kit.h b/vendor_libs/test_vendor_lib/model/devices/car_kit.h
new file mode 100644
index 0000000..94057ad
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/car_kit.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2018 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 "device.h"
+#include "model/controller/link_layer_controller.h"
+
+namespace {
+const std::string kCarKitPropertiesFile = "/etc/bluetooth/car_kit_controller_properties.json";
+} // namespace
+
+namespace test_vendor_lib {
+
+class CarKit : public Device {
+ public:
+ CarKit();
+ ~CarKit() = default;
+
+ static std::shared_ptr<CarKit> Create() {
+ return std::make_shared<CarKit>();
+ }
+
+ // Initialize the device based on the values of |args|.
+ virtual void Initialize(const std::vector<std::string>& args) override;
+
+ // Return a string representation of the type of device.
+ virtual std::string GetTypeString() const override {
+ return "car_kit";
+ }
+
+ virtual void IncomingPacket(packets::LinkLayerPacketView packet) override;
+
+ virtual void TimerTick() override;
+
+ private:
+ LinkLayerController link_layer_controller_{properties_};
+ static bool registered_;
+};
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/classic.cc b/vendor_libs/test_vendor_lib/model/devices/classic.cc
new file mode 100644
index 0000000..a8f8a99
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/classic.cc
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2016 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 "classic"
+
+#include "classic.h"
+#include "model/setup/device_boutique.h"
+#include "osi/include/log.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+bool Classic::registered_ = DeviceBoutique::Register(LOG_TAG, &Classic::Create);
+
+Classic::Classic() {
+ advertising_interval_ms_ = std::chrono::milliseconds(0);
+ properties_.SetClassOfDevice(0x30201);
+
+ properties_.SetExtendedInquiryData({0x10, // Length
+ BT_EIR_COMPLETE_LOCAL_NAME_TYPE, // Type
+ 'g', 'D', 'e', 'v', 'i', 'c', 'e', '-', 'c', 'l', 'a', 's', 's', 'i', 'c',
+ '\0'}); // End of data
+ properties_.SetPageScanRepetitionMode(0);
+ properties_.SetSupportedFeatures(0x87593F9bFE8FFEFF);
+
+ page_scan_delay_ms_ = std::chrono::milliseconds(600);
+}
+
+void Classic::Initialize(const vector<std::string>& args) {
+ if (args.size() < 2) return;
+
+ Address addr;
+ if (Address::FromString(args[1], addr)) properties_.SetAddress(addr);
+
+ if (args.size() < 3) return;
+
+ properties_.SetClockOffset(std::stoi(args[2]));
+}
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/classic.h b/vendor_libs/test_vendor_lib/model/devices/classic.h
new file mode 100644
index 0000000..16b466b
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/classic.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2016 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 "device.h"
+
+namespace test_vendor_lib {
+
+class Classic : public Device {
+ public:
+ Classic();
+ ~Classic() = default;
+
+ static std::shared_ptr<Device> Create() {
+ return std::make_shared<Classic>();
+ }
+
+ // Initialize the device based on the values of |args|.
+ virtual void Initialize(const std::vector<std::string>& args) override;
+
+ // Return a string representation of the type of device.
+ virtual std::string GetTypeString() const override {
+ return "classic";
+ }
+
+ private:
+ static bool registered_;
+};
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/device.cc b/vendor_libs/test_vendor_lib/model/devices/device.cc
new file mode 100644
index 0000000..52a37c1
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/device.cc
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2016 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 "device"
+
+#include <vector>
+
+#include "device.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+std::string Device::ToString() const {
+ std::string dev = GetTypeString() + "@" + properties_.GetAddress().ToString();
+
+ return dev;
+}
+
+void Device::RegisterPhyLayer(std::shared_ptr<PhyLayer> phy) {
+ phy_layers_[phy->GetType()].push_back(phy);
+}
+
+void Device::UnregisterPhyLayer(std::shared_ptr<PhyLayer> phy) {
+ for (auto phy_pair : phy_layers_) {
+ auto phy_list = std::get<1>(phy_pair);
+ for (size_t i = 0; i < phy_list.size(); i++) {
+ if (phy == phy_list[i]) {
+ phy_list.erase(phy_list.begin() + i);
+ }
+ }
+ }
+}
+
+bool Device::IsAdvertisementAvailable(std::chrono::milliseconds scan_time) const {
+ if (advertising_interval_ms_ == std::chrono::milliseconds(0)) return false;
+
+ std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
+
+ std::chrono::steady_clock::time_point last_interval =
+ ((now - time_stamp_) / advertising_interval_ms_) * advertising_interval_ms_ + time_stamp_;
+
+ std::chrono::steady_clock::time_point next_interval = last_interval + advertising_interval_ms_;
+
+ return ((now + scan_time) >= next_interval);
+}
+
+void Device::SendLinkLayerPacket(std::shared_ptr<packets::LinkLayerPacketBuilder> to_send, Phy::Type phy_type) {
+ auto phy_list = phy_layers_[phy_type];
+ for (auto phy : phy_list) {
+ phy->Send(to_send);
+ }
+}
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/device.h b/vendor_libs/test_vendor_lib/model/devices/device.h
new file mode 100644
index 0000000..18842cd
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/device.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2016 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 <chrono>
+#include <cstdint>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "model/devices/device_properties.h"
+#include "model/setup/phy_layer.h"
+#include "packets/link_layer/link_layer_packet_builder.h"
+#include "packets/link_layer/link_layer_packet_view.h"
+#include "types/address.h"
+
+#include "stack/include/btm_ble_api.h"
+
+namespace test_vendor_lib {
+
+// Represent a Bluetooth Device
+// - Provide Get*() and Set*() functions for device attributes.
+class Device {
+ public:
+ Device(const std::string properties_filename = "")
+ : time_stamp_(std::chrono::steady_clock::now()), properties_(properties_filename) {}
+ virtual ~Device() = default;
+
+ // Initialize the device based on the values of |args|.
+ virtual void Initialize(const std::vector<std::string>& args) = 0;
+
+ // Return a string representation of the type of device.
+ virtual std::string GetTypeString() const = 0;
+
+ // Return the string representation of the device.
+ virtual std::string ToString() const;
+
+ // Decide whether to accept a connection request
+ // May need to be extended to check peer address & type, and other
+ // connection parameters.
+ // Return true if the device accepts the connection request.
+ virtual bool LeConnect() {
+ return false;
+ }
+
+ // Set the advertisement interval in milliseconds.
+ void SetAdvertisementInterval(std::chrono::milliseconds ms) {
+ advertising_interval_ms_ = ms;
+ }
+
+ // Returns true if the host could see an advertisement in the next
+ // |scan_time| milliseconds.
+ virtual bool IsAdvertisementAvailable(std::chrono::milliseconds scan_time) const;
+
+ // Let the device know that time has passed.
+ virtual void TimerTick() {}
+
+ void RegisterPhyLayer(std::shared_ptr<PhyLayer> phy);
+
+ void UnregisterPhyLayer(std::shared_ptr<PhyLayer> phy);
+
+ virtual void IncomingPacket(packets::LinkLayerPacketView){};
+
+ virtual void SendLinkLayerPacket(std::shared_ptr<packets::LinkLayerPacketBuilder> packet, Phy::Type phy_type);
+
+ protected:
+ std::map<Phy::Type, std::vector<std::shared_ptr<PhyLayer>>> phy_layers_;
+
+ std::chrono::steady_clock::time_point time_stamp_;
+
+ // The time between page scans.
+ std::chrono::milliseconds page_scan_delay_ms_;
+
+ // The spec defines the advertising interval as a 16-bit value, but since it
+ // is never sent in packets, we use std::chrono::milliseconds.
+ std::chrono::milliseconds advertising_interval_ms_;
+
+ DeviceProperties properties_;
+};
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/device_properties.cc b/vendor_libs/test_vendor_lib/model/devices/device_properties.cc
new file mode 100644
index 0000000..164160a
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/device_properties.cc
@@ -0,0 +1,112 @@
+/*
+ * 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 "device_properties"
+
+#include "device_properties.h"
+
+#include <memory>
+
+#include <base/logging.h>
+#include "base/files/file_util.h"
+#include "base/json/json_reader.h"
+#include "base/values.h"
+
+#include "hci.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+using std::vector;
+
+namespace {
+// Functions used by JSONValueConverter to read stringified JSON.
+bool ParseUint8t(base::StringPiece value, uint8_t* field) {
+ *field = std::stoi(value.as_string());
+ return true;
+}
+
+bool ParseUint16t(base::StringPiece value, uint16_t* field) {
+ *field = std::stoi(value.as_string());
+ return true;
+}
+
+} // namespace
+
+namespace test_vendor_lib {
+
+DeviceProperties::DeviceProperties(const std::string& file_name)
+ : acl_data_packet_size_(1024), sco_data_packet_size_(255), num_acl_data_packets_(10), num_sco_data_packets_(10),
+ version_(static_cast<uint8_t>(hci::Version::V4_1)), revision_(0),
+ lmp_pal_version_(static_cast<uint8_t>(hci::Version::V4_1)), manufacturer_name_(0), lmp_pal_subversion_(0),
+ le_data_packet_length_(27), num_le_data_packets_(15), le_white_list_size_(15) {
+ std::string properties_raw;
+
+ CHECK(Address::FromString("BB:BB:BB:BB:BB:AD", address_));
+ CHECK(Address::FromString("BB:BB:BB:BB:AD:1E", le_address_));
+ name_ = {'D', 'e', 'f', 'a', 'u', 'l', 't'};
+
+ supported_codecs_ = {0}; // Only SBC is supported.
+ vendor_specific_codecs_ = {};
+
+ for (int i = 0; i < 64; i++) supported_commands_.push_back(0xff);
+
+ le_supported_features_ = 0x1f;
+ le_supported_states_ = 0x3ffffffffff;
+ le_vendor_cap_ = {};
+
+ if (file_name.size() == 0) {
+ return;
+ }
+ LOG_INFO(LOG_TAG, "Reading controller properties from %s.", file_name.c_str());
+ if (!base::ReadFileToString(base::FilePath(file_name), &properties_raw)) {
+ LOG_ERROR(LOG_TAG, "Error reading controller properties from file.");
+ return;
+ }
+
+ std::unique_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<DeviceProperties> converter;
+
+ if (!converter.Convert(properties_dictionary, this))
+ LOG_INFO(LOG_TAG, "Error converting JSON properties into Properties object.");
+}
+
+// static
+void DeviceProperties::RegisterJSONConverter(base::JSONValueConverter<DeviceProperties>* converter) {
+// TODO(dennischeng): Use RegisterIntField() here?
+#define REGISTER_UINT8_T(field_name, field) \
+ converter->RegisterCustomField<uint8_t>(field_name, &DeviceProperties::field, &ParseUint8t);
+#define REGISTER_UINT16_T(field_name, field) \
+ converter->RegisterCustomField<uint16_t>(field_name, &DeviceProperties::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_);
+#undef REGISTER_UINT8_T
+#undef REGISTER_UINT16_T
+}
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/device_properties.h b/vendor_libs/test_vendor_lib/model/devices/device_properties.h
new file mode 100644
index 0000000..6960553
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/device_properties.h
@@ -0,0 +1,286 @@
+/*
+ * 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 <string>
+#include <vector>
+
+#include "base/json/json_value_converter.h"
+#include "types/address.h"
+#include "types/class_of_device.h"
+
+namespace test_vendor_lib {
+
+class DeviceProperties {
+ public:
+ explicit DeviceProperties(const std::string& file_name = "");
+
+ // Access private configuration data
+
+ // Specification Version 4.2, Volume 2, Part E, Section 7.4.1
+ const std::vector<uint8_t>& GetVersionInformation() const;
+
+ // Specification Version 4.2, Volume 2, Part E, Section 7.4.2
+ const std::vector<uint8_t>& GetSupportedCommands() const {
+ return supported_commands_;
+ }
+
+ // Specification Version 4.2, Volume 2, Part E, Section 7.4.3
+ uint64_t GetSupportedFeatures() const {
+ return extended_features_[0];
+ }
+
+ void SetSupportedFeatures(uint64_t features) {
+ extended_features_[0] = features;
+ }
+
+ // Specification Version 4.2, Volume 2, Part E, Section 7.4.4
+ uint8_t GetExtendedFeaturesMaximumPageNumber() const {
+ return extended_features_.size() - 1;
+ }
+
+ uint64_t GetExtendedFeatures(uint8_t page_number) const {
+ CHECK(page_number < extended_features_.size());
+ return extended_features_[page_number];
+ }
+
+ // Specification Version 4.2, Volume 2, Part E, Section 7.4.5
+ uint16_t GetAclDataPacketSize() const {
+ return acl_data_packet_size_;
+ }
+
+ uint8_t GetSynchronousDataPacketSize() const {
+ return sco_data_packet_size_;
+ }
+
+ uint16_t GetTotalNumAclDataPackets() const {
+ return num_acl_data_packets_;
+ }
+
+ uint16_t GetTotalNumSynchronousDataPackets() const {
+ return num_sco_data_packets_;
+ }
+
+ const Address& GetAddress() const {
+ return address_;
+ }
+
+ void SetAddress(const Address& address) {
+ address_ = address;
+ }
+
+ // Specification Version 4.2, Volume 2, Part E, Section 7.4.8
+ const std::vector<uint8_t>& GetSupportedCodecs() const {
+ return supported_codecs_;
+ }
+
+ const std::vector<uint32_t>& GetVendorSpecificCodecs() const {
+ return vendor_specific_codecs_;
+ }
+
+ uint8_t GetVersion() const {
+ return version_;
+ }
+
+ uint16_t GetRevision() const {
+ return revision_;
+ }
+
+ uint8_t GetLmpPalVersion() const {
+ return lmp_pal_version_;
+ }
+
+ uint16_t GetLmpPalSubversion() const {
+ return lmp_pal_subversion_;
+ }
+
+ uint16_t GetManufacturerName() const {
+ return manufacturer_name_;
+ }
+
+ uint8_t GetAuthenticationEnable() const {
+ return authentication_enable_;
+ }
+
+ void SetAuthenticationEnable(uint8_t enable) {
+ authentication_enable_ = enable;
+ }
+
+ ClassOfDevice GetClassOfDevice() const {
+ return class_of_device_;
+ }
+
+ void SetClassOfDevice(uint8_t b0, uint8_t b1, uint8_t b2) {
+ class_of_device_.cod[0] = b0;
+ class_of_device_.cod[1] = b1;
+ class_of_device_.cod[2] = b2;
+ }
+
+ void SetClassOfDevice(uint32_t class_of_device) {
+ class_of_device_.cod[0] = class_of_device & 0xff;
+ class_of_device_.cod[1] = (class_of_device >> 8) & 0xff;
+ class_of_device_.cod[2] = (class_of_device >> 16) & 0xff;
+ }
+
+ void SetName(const std::vector<uint8_t>& name) {
+ name_ = name;
+ }
+
+ const std::vector<uint8_t>& GetName() const {
+ return name_;
+ }
+
+ void SetExtendedInquiryData(const std::vector<uint8_t>& eid) {
+ extended_inquiry_data_ = eid;
+ }
+
+ const std::vector<uint8_t>& GetExtendedInquiryData() const {
+ return extended_inquiry_data_;
+ }
+
+ uint8_t GetPageScanRepetitionMode() const {
+ return page_scan_repetition_mode_;
+ }
+
+ void SetPageScanRepetitionMode(uint8_t mode) {
+ page_scan_repetition_mode_ = mode;
+ }
+
+ uint16_t GetClockOffset() const {
+ return clock_offset_;
+ }
+
+ void SetClockOffset(uint16_t offset) {
+ clock_offset_ = offset;
+ }
+
+ // Low-Energy functions
+ const Address& GetLeAddress() const {
+ return le_address_;
+ }
+
+ void SetLeAddress(const Address& address) {
+ le_address_ = address;
+ }
+
+ uint8_t GetLeAddressType() const {
+ return le_address_type_;
+ }
+
+ void SetLeAddressType(uint8_t addr_type) {
+ le_address_type_ = addr_type;
+ }
+
+ uint8_t GetLeAdvertisementType() const {
+ return le_advertisement_type_;
+ }
+
+ void SetLeAdvertisementType(uint8_t ad_type) {
+ le_advertisement_type_ = ad_type;
+ }
+
+ void SetLeAdvertisement(const std::vector<uint8_t>& ad) {
+ le_advertisement_ = ad;
+ }
+
+ const std::vector<uint8_t>& GetLeAdvertisement() const {
+ return le_advertisement_;
+ }
+
+ void SetLeScanResponse(const std::vector<uint8_t>& response) {
+ le_scan_response_ = response;
+ }
+
+ const std::vector<uint8_t>& GetLeScanResponse() const {
+ return le_scan_response_;
+ }
+
+ // Specification Version 4.2, Volume 2, Part E, Section 7.8.2
+ uint16_t GetLeDataPacketLength() const {
+ return le_data_packet_length_;
+ }
+
+ uint8_t GetTotalNumLeDataPackets() const {
+ return num_le_data_packets_;
+ }
+
+ // Specification Version 4.2, Volume 2, Part E, Section 7.8.3
+ uint64_t GetLeSupportedFeatures() const {
+ return le_supported_features_;
+ }
+
+ void SetLeSupportedFeatures(uint64_t features) {
+ le_supported_features_ = features;
+ }
+
+ // Specification Version 4.2, Volume 2, Part E, Section 7.8.14
+ uint8_t GetLeWhiteListSize() const {
+ return le_white_list_size_;
+ }
+
+ // Specification Version 4.2, Volume 2, Part E, Section 7.8.27
+ uint64_t GetLeSupportedStates() const {
+ return le_supported_states_;
+ }
+
+ // Vendor-specific commands
+ const std::vector<uint8_t>& GetLeVendorCap() const {
+ return le_vendor_cap_;
+ }
+
+ static void RegisterJSONConverter(base::JSONValueConverter<DeviceProperties>* converter);
+
+ private:
+ // Classic
+ 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_;
+ uint64_t supported_features_;
+ uint8_t authentication_enable_;
+ std::vector<uint8_t> supported_codecs_;
+ std::vector<uint32_t> vendor_specific_codecs_;
+ std::vector<uint8_t> supported_commands_;
+ std::vector<uint64_t> extended_features_{{0x875b3fd8fe8ffeff, 0x07}};
+ ClassOfDevice class_of_device_{{0, 0, 0}};
+ std::vector<uint8_t> extended_inquiry_data_;
+ std::vector<uint8_t> name_;
+ Address address_;
+ uint8_t page_scan_repetition_mode_;
+ uint16_t clock_offset_;
+
+ // Low Energy
+ uint16_t le_data_packet_length_;
+ uint8_t num_le_data_packets_;
+ uint8_t le_white_list_size_;
+ uint64_t le_supported_features_{0x075b3fd8fe8ffeff};
+ uint64_t le_supported_states_;
+ std::vector<uint8_t> le_vendor_cap_;
+ Address le_address_;
+ uint8_t le_address_type_;
+ uint8_t le_advertisement_type_;
+ std::vector<uint8_t> le_advertisement_;
+ std::vector<uint8_t> le_scan_response_;
+};
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/h4_packetizer.cc b/vendor_libs/test_vendor_lib/model/devices/h4_packetizer.cc
new file mode 100644
index 0000000..49e8727
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/h4_packetizer.cc
@@ -0,0 +1,194 @@
+//
+// Copyright 2017 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 "h4_packetizer.h"
+
+#define LOG_TAG "h4_packetizer"
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <log/log.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+namespace test_vendor_lib {
+namespace hci {
+constexpr size_t H4Packetizer::COMMAND_PREAMBLE_SIZE;
+constexpr size_t H4Packetizer::COMMAND_LENGTH_OFFSET;
+constexpr size_t H4Packetizer::ACL_PREAMBLE_SIZE;
+constexpr size_t H4Packetizer::ACL_LENGTH_OFFSET;
+constexpr size_t H4Packetizer::SCO_PREAMBLE_SIZE;
+constexpr size_t H4Packetizer::SCO_LENGTH_OFFSET;
+constexpr size_t H4Packetizer::EVENT_PREAMBLE_SIZE;
+constexpr size_t H4Packetizer::EVENT_LENGTH_OFFSET;
+
+constexpr size_t H4Packetizer::PREAMBLE_SIZE_MAX;
+
+size_t H4Packetizer::HciGetPacketLengthForType(hci::PacketType type, const uint8_t* preamble) {
+ static const size_t packet_length_offset[static_cast<size_t>(hci::PacketType::EVENT) + 1] = {
+ 0,
+ H4Packetizer::COMMAND_LENGTH_OFFSET,
+ H4Packetizer::ACL_LENGTH_OFFSET,
+ H4Packetizer::SCO_LENGTH_OFFSET,
+ H4Packetizer::EVENT_LENGTH_OFFSET,
+ };
+
+ size_t offset = packet_length_offset[static_cast<size_t>(type)];
+ if (type != hci::PacketType::ACL) return preamble[offset];
+ return (((preamble[offset + 1]) << 8) | preamble[offset]);
+}
+
+H4Packetizer::H4Packetizer(int fd, PacketReadCallback command_cb, PacketReadCallback event_cb,
+ PacketReadCallback acl_cb, PacketReadCallback sco_cb)
+ : uart_fd_(fd), command_cb_(command_cb), event_cb_(event_cb), acl_cb_(acl_cb), sco_cb_(sco_cb) {}
+
+size_t H4Packetizer::Send(uint8_t type, const uint8_t* data, size_t length) {
+ struct iovec iov[] = {{&type, sizeof(type)}, {const_cast<uint8_t*>(data), length}};
+ ssize_t ret = 0;
+ do {
+ ret = TEMP_FAILURE_RETRY(writev(uart_fd_, iov, sizeof(iov) / sizeof(iov[0])));
+ } while (-1 == ret && EAGAIN == errno);
+
+ if (ret == -1) {
+ ALOGE("%s error writing to UART (%s)", __func__, strerror(errno));
+ } else if (ret < static_cast<ssize_t>(length + 1)) {
+ ALOGE("%s: %d / %d bytes written - something went wrong...", __func__, static_cast<int>(ret),
+ static_cast<int>(length + 1));
+ }
+ return ret;
+}
+
+void H4Packetizer::OnPacketReady() {
+ ALOGE("%s: before switch", __func__);
+ switch (hci_packet_type_) {
+ case hci::PacketType::COMMAND:
+ command_cb_(packet_);
+ break;
+ case hci::PacketType::ACL:
+ acl_cb_(packet_);
+ break;
+ case hci::PacketType::SCO:
+ sco_cb_(packet_);
+ break;
+ case hci::PacketType::EVENT:
+ event_cb_(packet_);
+ break;
+ default:
+ LOG_ALWAYS_FATAL("%s: Unimplemented packet type %d", __func__, static_cast<int>(hci_packet_type_));
+ }
+ // Get ready for the next type byte.
+ hci_packet_type_ = hci::PacketType::UNKNOWN;
+}
+
+void H4Packetizer::OnDataReady(int fd) {
+ if (hci_packet_type_ == hci::PacketType::UNKNOWN) {
+ uint8_t buffer[1] = {0};
+ ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, 1));
+ if (bytes_read != 1) {
+ if (bytes_read == 0) {
+ ALOGI("%s: Nothing ready, will retry!", __func__);
+ return;
+ } else if (bytes_read < 0) {
+ if (errno == EAGAIN) {
+ // No data, try again later.
+ return;
+ } else {
+ LOG_ALWAYS_FATAL("%s: Read packet type error: %s", __func__, strerror(errno));
+ }
+ } else {
+ LOG_ALWAYS_FATAL("%s: More bytes read than expected (%u)!", __func__, static_cast<unsigned int>(bytes_read));
+ }
+ }
+ hci_packet_type_ = static_cast<hci::PacketType>(buffer[0]);
+ if (hci_packet_type_ != hci::PacketType::ACL && hci_packet_type_ != hci::PacketType::SCO &&
+ hci_packet_type_ != hci::PacketType::COMMAND && hci_packet_type_ != hci::PacketType::EVENT) {
+ LOG_ALWAYS_FATAL("%s: Unimplemented packet type %d", __func__, static_cast<int>(hci_packet_type_));
+ }
+ } else {
+ static const size_t preamble_size[static_cast<size_t>(hci::PacketType::EVENT) + 1] = {
+ 0,
+ H4Packetizer::COMMAND_PREAMBLE_SIZE,
+ H4Packetizer::ACL_PREAMBLE_SIZE,
+ H4Packetizer::SCO_PREAMBLE_SIZE,
+ H4Packetizer::EVENT_PREAMBLE_SIZE,
+ };
+
+ switch (state_) {
+ case HCI_PREAMBLE: {
+ size_t preamble_bytes = preamble_size[static_cast<size_t>(hci_packet_type_)];
+ ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, preamble_ + bytes_read_, preamble_bytes - bytes_read_));
+ if (bytes_read == 0) {
+ ALOGE("%s: Will try again to read the header!", __func__);
+ return;
+ }
+ if (bytes_read < 0) {
+ // Ignore temporary failures.
+ if (errno == EAGAIN) {
+ return;
+ }
+ LOG_ALWAYS_FATAL("%s: Read header error: %s", __func__, strerror(errno));
+ }
+ bytes_read_ += bytes_read;
+ if (bytes_read_ == preamble_bytes) {
+ size_t packet_length = HciGetPacketLengthForType(hci_packet_type_, preamble_);
+ packet_.resize(preamble_bytes + packet_length);
+ memcpy(packet_.data(), preamble_, preamble_bytes);
+ ALOGI("%s: Read a preamble of size %d length %d %0x %0x %0x", __func__, static_cast<int>(bytes_read_),
+ static_cast<int>(packet_length), preamble_[0], preamble_[1], preamble_[2]);
+ bytes_remaining_ = packet_length;
+ if (bytes_remaining_ == 0) {
+ OnPacketReady();
+ state_ = HCI_PREAMBLE;
+ bytes_read_ = 0;
+ } else {
+ state_ = HCI_PAYLOAD;
+ bytes_read_ = 0;
+ }
+ }
+ break;
+ }
+
+ case HCI_PAYLOAD: {
+ size_t preamble_bytes = preamble_size[static_cast<size_t>(hci_packet_type_)];
+ ssize_t bytes_read =
+ TEMP_FAILURE_RETRY(read(fd, packet_.data() + preamble_bytes + bytes_read_, bytes_remaining_));
+ if (bytes_read == 0) {
+ ALOGI("%s: Will try again to read the payload!", __func__);
+ return;
+ }
+ if (bytes_read < 0) {
+ // Ignore temporary failures.
+ if (errno == EAGAIN) {
+ return;
+ }
+ LOG_ALWAYS_FATAL("%s: Read payload error: %s", __func__, strerror(errno));
+ }
+ bytes_remaining_ -= bytes_read;
+ bytes_read_ += bytes_read;
+ if (bytes_remaining_ == 0) {
+ OnPacketReady();
+ state_ = HCI_PREAMBLE;
+ bytes_read_ = 0;
+ }
+ break;
+ }
+ }
+ }
+}
+
+} // namespace hci
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/h4_packetizer.h b/vendor_libs/test_vendor_lib/model/devices/h4_packetizer.h
new file mode 100644
index 0000000..f81cf77
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/h4_packetizer.h
@@ -0,0 +1,81 @@
+//
+// Copyright 2017 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 <vector>
+
+#include "hci.h"
+#include "hci_protocol.h"
+
+namespace test_vendor_lib {
+namespace hci {
+
+using HciPacketReadyCallback = std::function<void(void)>;
+
+class H4Packetizer : public HciProtocol {
+ public:
+ H4Packetizer(int fd, PacketReadCallback command_cb, PacketReadCallback event_cb, PacketReadCallback acl_cb,
+ PacketReadCallback sco_cb);
+
+ size_t Send(uint8_t type, const uint8_t* data, size_t length);
+
+ void OnPacketReady();
+
+ void OnDataReady(int fd);
+
+ private:
+ int uart_fd_;
+
+ PacketReadCallback command_cb_;
+ PacketReadCallback event_cb_;
+ PacketReadCallback acl_cb_;
+ PacketReadCallback sco_cb_;
+
+ hci::PacketType hci_packet_type_{hci::PacketType::UNKNOWN};
+
+ // 2 bytes for opcode, 1 byte for parameter length (Volume 2, Part E, 5.4.1)
+ static constexpr size_t COMMAND_PREAMBLE_SIZE = 3;
+ static constexpr size_t COMMAND_LENGTH_OFFSET = 2;
+
+ // 2 bytes for handle, 2 bytes for data length (Volume 2, Part E, 5.4.2)
+ static constexpr size_t ACL_PREAMBLE_SIZE = 4;
+ static constexpr size_t ACL_LENGTH_OFFSET = 2;
+
+ // 2 bytes for handle, 1 byte for data length (Volume 2, Part E, 5.4.3)
+ static constexpr size_t SCO_PREAMBLE_SIZE = 3;
+ static constexpr size_t SCO_LENGTH_OFFSET = 2;
+
+ // 1 byte for event code, 1 byte for parameter length (Volume 2, Part
+ // E, 5.4.4)
+ static constexpr size_t EVENT_PREAMBLE_SIZE = 2;
+ static constexpr size_t EVENT_LENGTH_OFFSET = 1;
+
+ static constexpr size_t PREAMBLE_SIZE_MAX = ACL_PREAMBLE_SIZE;
+
+ size_t HciGetPacketLengthForType(hci::PacketType type, const uint8_t* preamble);
+
+ enum State { HCI_PREAMBLE, HCI_PAYLOAD };
+ State state_{HCI_PREAMBLE};
+ uint8_t preamble_[PREAMBLE_SIZE_MAX];
+ std::vector<uint8_t> packet_;
+ size_t bytes_remaining_{0};
+ size_t bytes_read_{0};
+};
+
+} // namespace hci
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/h4_protocol.cc b/vendor_libs/test_vendor_lib/model/devices/h4_protocol.cc
new file mode 100644
index 0000000..c4704ea
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/h4_protocol.cc
@@ -0,0 +1,106 @@
+//
+// Copyright 2017 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 "h4_protocol.h"
+
+#define LOG_TAG "hci-h4_protocol"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <log/log.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+namespace test_vendor_lib {
+namespace hci {
+
+H4Protocol::H4Protocol(int fd, PacketReadCallback command_cb, PacketReadCallback event_cb, PacketReadCallback acl_cb,
+ PacketReadCallback sco_cb)
+ : uart_fd_(fd), command_cb_(command_cb), event_cb_(event_cb), acl_cb_(acl_cb), sco_cb_(sco_cb),
+ hci_packetizer_([this]() {
+ ALOGI("in lambda");
+ this->OnPacketReady();
+ }) {}
+
+size_t H4Protocol::Send(uint8_t type, const uint8_t* data, size_t length) {
+ struct iovec iov[] = {{&type, sizeof(type)}, {const_cast<uint8_t*>(data), length}};
+ ssize_t ret = 0;
+ do {
+ ret = TEMP_FAILURE_RETRY(writev(uart_fd_, iov, sizeof(iov) / sizeof(iov[0])));
+ } while (-1 == ret && EAGAIN == errno);
+
+ if (ret == -1) {
+ ALOGE("%s error writing to UART (%s)", __func__, strerror(errno));
+ } else if (ret < static_cast<ssize_t>(length + 1)) {
+ ALOGE("%s: %d / %d bytes written - something went wrong...", __func__, static_cast<int>(ret),
+ static_cast<int>(length + 1));
+ }
+ return ret;
+}
+
+void H4Protocol::OnPacketReady() {
+ ALOGE("%s: before switch", __func__);
+ switch (hci_packet_type_) {
+ case hci::PacketType::COMMAND:
+ command_cb_(hci_packetizer_.GetPacket());
+ break;
+ case hci::PacketType::ACL:
+ acl_cb_(hci_packetizer_.GetPacket());
+ break;
+ case hci::PacketType::SCO:
+ sco_cb_(hci_packetizer_.GetPacket());
+ break;
+ case hci::PacketType::EVENT:
+ event_cb_(hci_packetizer_.GetPacket());
+ break;
+ default:
+ LOG_ALWAYS_FATAL("%s: Unimplemented packet type %d", __func__, static_cast<int>(hci_packet_type_));
+ }
+ // Get ready for the next type byte.
+ hci_packet_type_ = hci::PacketType::UNKNOWN;
+}
+
+void H4Protocol::OnDataReady(int fd) {
+ if (hci_packet_type_ == hci::PacketType::UNKNOWN) {
+ uint8_t buffer[1] = {0};
+ ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, 1));
+ if (bytes_read != 1) {
+ if (bytes_read == 0) {
+ ALOGI("%s: Nothing ready, will retry!", __func__);
+ return;
+ } else if (bytes_read < 0) {
+ if (errno == EAGAIN) {
+ // No data, try again later.
+ return;
+ } else {
+ LOG_ALWAYS_FATAL("%s: Read packet type error: %s", __func__, strerror(errno));
+ }
+ } else {
+ LOG_ALWAYS_FATAL("%s: More bytes read than expected (%u)!", __func__, static_cast<unsigned int>(bytes_read));
+ }
+ }
+ hci_packet_type_ = static_cast<hci::PacketType>(buffer[0]);
+ if (hci_packet_type_ != hci::PacketType::ACL && hci_packet_type_ != hci::PacketType::SCO &&
+ hci_packet_type_ != hci::PacketType::COMMAND && hci_packet_type_ != hci::PacketType::EVENT) {
+ LOG_ALWAYS_FATAL("%s: Unimplemented packet type %d", __func__, static_cast<int>(hci_packet_type_));
+ }
+ } else {
+ hci_packetizer_.OnDataReady(fd, hci_packet_type_);
+ }
+}
+
+} // namespace hci
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/h4_protocol.h b/vendor_libs/test_vendor_lib/model/devices/h4_protocol.h
new file mode 100644
index 0000000..5e261d5
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/h4_protocol.h
@@ -0,0 +1,49 @@
+//
+// Copyright 2017 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 "hci_protocol.h"
+#include "include/hci.h"
+
+namespace test_vendor_lib {
+namespace hci {
+
+class H4Protocol : public HciProtocol {
+ public:
+ H4Protocol(int fd, PacketReadCallback command_cb, PacketReadCallback event_cb, PacketReadCallback acl_cb,
+ PacketReadCallback sco_cb);
+
+ size_t Send(uint8_t type, const uint8_t* data, size_t length);
+
+ void OnPacketReady();
+
+ void OnDataReady(int fd);
+
+ private:
+ int uart_fd_;
+
+ PacketReadCallback command_cb_;
+ PacketReadCallback event_cb_;
+ PacketReadCallback acl_cb_;
+ PacketReadCallback sco_cb_;
+
+ hci::PacketType hci_packet_type_{hci::PacketType::UNKNOWN};
+ hci::HciPacketizer hci_packetizer_;
+};
+
+} // namespace hci
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/hci_packetizer.cc b/vendor_libs/test_vendor_lib/model/devices/hci_packetizer.cc
new file mode 100644
index 0000000..cca7780
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/hci_packetizer.cc
@@ -0,0 +1,129 @@
+//
+// Copyright 2017 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 "hci_packetizer.h"
+
+#define LOG_TAG "hci_packetizer"
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <log/log.h>
+#include <unistd.h>
+
+namespace test_vendor_lib {
+namespace hci {
+constexpr size_t HciPacketizer::COMMAND_PREAMBLE_SIZE;
+constexpr size_t HciPacketizer::COMMAND_LENGTH_OFFSET;
+constexpr size_t HciPacketizer::ACL_PREAMBLE_SIZE;
+constexpr size_t HciPacketizer::ACL_LENGTH_OFFSET;
+constexpr size_t HciPacketizer::SCO_PREAMBLE_SIZE;
+constexpr size_t HciPacketizer::SCO_LENGTH_OFFSET;
+constexpr size_t HciPacketizer::EVENT_PREAMBLE_SIZE;
+constexpr size_t HciPacketizer::EVENT_LENGTH_OFFSET;
+
+constexpr size_t HciPacketizer::PREAMBLE_SIZE_MAX;
+
+size_t HciPacketizer::HciGetPacketLengthForType(hci::PacketType type, const uint8_t* preamble) {
+ static const size_t packet_length_offset[static_cast<size_t>(hci::PacketType::EVENT) + 1] = {
+ 0,
+ HciPacketizer::COMMAND_LENGTH_OFFSET,
+ HciPacketizer::ACL_LENGTH_OFFSET,
+ HciPacketizer::SCO_LENGTH_OFFSET,
+ HciPacketizer::EVENT_LENGTH_OFFSET,
+ };
+
+ size_t offset = packet_length_offset[static_cast<size_t>(type)];
+ if (type != hci::PacketType::ACL) return preamble[offset];
+ return (((preamble[offset + 1]) << 8) | preamble[offset]);
+}
+
+const std::vector<uint8_t>& HciPacketizer::GetPacket() const {
+ return packet_;
+}
+
+void HciPacketizer::OnDataReady(int fd, hci::PacketType packet_type) {
+ static const size_t preamble_size[static_cast<size_t>(hci::PacketType::EVENT) + 1] = {
+ 0,
+ HciPacketizer::COMMAND_PREAMBLE_SIZE,
+ HciPacketizer::ACL_PREAMBLE_SIZE,
+ HciPacketizer::SCO_PREAMBLE_SIZE,
+ HciPacketizer::EVENT_PREAMBLE_SIZE,
+ };
+
+ switch (state_) {
+ case HCI_PREAMBLE: {
+ ssize_t bytes_read = TEMP_FAILURE_RETRY(
+ read(fd, preamble_ + bytes_read_, preamble_size[static_cast<uint8_t>(packet_type)] - bytes_read_));
+ if (bytes_read == 0) {
+ ALOGE("%s: Will try again to read the header!", __func__);
+ return;
+ }
+ if (bytes_read < 0) {
+ // Ignore temporary failures.
+ if (errno == EAGAIN) {
+ return;
+ }
+ LOG_ALWAYS_FATAL("%s: Read header error: %s", __func__, strerror(errno));
+ }
+ bytes_read_ += bytes_read;
+ if (bytes_read_ == preamble_size[static_cast<uint8_t>(packet_type)]) {
+ size_t packet_length = HciGetPacketLengthForType(packet_type, preamble_);
+ packet_.resize(preamble_size[static_cast<uint8_t>(packet_type)] + packet_length);
+ memcpy(packet_.data(), preamble_, preamble_size[static_cast<uint8_t>(packet_type)]);
+ ALOGI("%s: Read a preamble of size %d length %d %0x %0x %0x", __func__, static_cast<int>(bytes_read_),
+ static_cast<int>(packet_length), preamble_[0], preamble_[1], preamble_[2]);
+ bytes_remaining_ = packet_length;
+ if (bytes_remaining_ == 0) {
+ packet_ready_cb_();
+ state_ = HCI_PREAMBLE;
+ bytes_read_ = 0;
+ } else {
+ state_ = HCI_PAYLOAD;
+ bytes_read_ = 0;
+ }
+ }
+ break;
+ }
+
+ case HCI_PAYLOAD: {
+ ssize_t bytes_read = TEMP_FAILURE_RETRY(
+ read(fd, packet_.data() + preamble_size[static_cast<uint8_t>(packet_type)] + bytes_read_, bytes_remaining_));
+ if (bytes_read == 0) {
+ ALOGI("%s: Will try again to read the payload!", __func__);
+ return;
+ }
+ if (bytes_read < 0) {
+ // Ignore temporary failures.
+ if (errno == EAGAIN) {
+ return;
+ }
+ LOG_ALWAYS_FATAL("%s: Read payload error: %s", __func__, strerror(errno));
+ }
+ bytes_remaining_ -= bytes_read;
+ bytes_read_ += bytes_read;
+ if (bytes_remaining_ == 0) {
+ packet_ready_cb_();
+ state_ = HCI_PREAMBLE;
+ bytes_read_ = 0;
+ }
+ break;
+ }
+ }
+}
+
+} // namespace hci
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/hci_packetizer.h b/vendor_libs/test_vendor_lib/model/devices/hci_packetizer.h
new file mode 100644
index 0000000..4823008
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/hci_packetizer.h
@@ -0,0 +1,68 @@
+//
+// Copyright 2017 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 <vector>
+
+#include "include/hci.h"
+
+namespace test_vendor_lib {
+namespace hci {
+
+using HciPacketReadyCallback = std::function<void(void)>;
+
+class HciPacketizer {
+ public:
+ HciPacketizer(HciPacketReadyCallback packet_cb) : packet_ready_cb_(packet_cb){};
+ void OnDataReady(int fd, hci::PacketType packet_type);
+ const std::vector<uint8_t>& GetPacket() const;
+
+ private:
+ // 2 bytes for opcode, 1 byte for parameter length (Volume 2, Part E, 5.4.1)
+ static constexpr size_t COMMAND_PREAMBLE_SIZE = 3;
+ static constexpr size_t COMMAND_LENGTH_OFFSET = 2;
+
+ // 2 bytes for handle, 2 bytes for data length (Volume 2, Part E, 5.4.2)
+ static constexpr size_t ACL_PREAMBLE_SIZE = 4;
+ static constexpr size_t ACL_LENGTH_OFFSET = 2;
+
+ // 2 bytes for handle, 1 byte for data length (Volume 2, Part E, 5.4.3)
+ static constexpr size_t SCO_PREAMBLE_SIZE = 3;
+ static constexpr size_t SCO_LENGTH_OFFSET = 2;
+
+ // 1 byte for event code, 1 byte for parameter length (Volume 2, Part
+ // E, 5.4.4)
+ static constexpr size_t EVENT_PREAMBLE_SIZE = 2;
+ static constexpr size_t EVENT_LENGTH_OFFSET = 1;
+
+ static constexpr size_t PREAMBLE_SIZE_MAX = ACL_PREAMBLE_SIZE;
+
+ size_t HciGetPacketLengthForType(hci::PacketType type, const uint8_t* preamble);
+
+ protected:
+ enum State { HCI_PREAMBLE, HCI_PAYLOAD };
+ State state_{HCI_PREAMBLE};
+ uint8_t preamble_[PREAMBLE_SIZE_MAX];
+ std::vector<uint8_t> packet_;
+ size_t bytes_remaining_{0};
+ size_t bytes_read_{0};
+ HciPacketReadyCallback packet_ready_cb_;
+};
+
+} // namespace hci
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/hci_protocol.cc b/vendor_libs/test_vendor_lib/model/devices/hci_protocol.cc
new file mode 100644
index 0000000..e01bfa5
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/hci_protocol.cc
@@ -0,0 +1,53 @@
+//
+// Copyright 2017 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 "hci_protocol.h"
+
+#define LOG_TAG "hci-hci_protocol"
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <log/log.h>
+#include <unistd.h>
+
+namespace test_vendor_lib {
+namespace hci {
+
+size_t HciProtocol::WriteSafely(int fd, const uint8_t* data, size_t length) {
+ size_t transmitted_length = 0;
+ while (length > 0) {
+ ssize_t ret = TEMP_FAILURE_RETRY(write(fd, data + transmitted_length, length));
+
+ if (ret == -1) {
+ if (errno == EAGAIN) continue;
+ ALOGE("%s error writing to UART (%s)", __func__, strerror(errno));
+ break;
+
+ } else if (ret == 0) {
+ // Nothing written :(
+ ALOGE("%s zero bytes written - something went wrong...", __func__);
+ break;
+ }
+
+ transmitted_length += ret;
+ length -= ret;
+ }
+
+ return transmitted_length;
+}
+
+} // namespace hci
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/hci_protocol.h b/vendor_libs/test_vendor_lib/model/devices/hci_protocol.h
new file mode 100644
index 0000000..3aa7640
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/hci_protocol.h
@@ -0,0 +1,41 @@
+//
+// Copyright 2017 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 "hci.h"
+#include "hci_packetizer.h"
+
+namespace test_vendor_lib {
+namespace hci {
+
+using PacketReadCallback = std::function<void(const std::vector<uint8_t>&)>;
+
+// Implementation of HCI protocol bits common to different transports
+class HciProtocol {
+ public:
+ HciProtocol() = default;
+ virtual ~HciProtocol(){};
+
+ // Protocol-specific implementation of sending packets.
+ virtual size_t Send(uint8_t type, const uint8_t* data, size_t length) = 0;
+
+ protected:
+ static size_t WriteSafely(int fd, const uint8_t* data, size_t length);
+};
+
+} // namespace hci
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/hci_socket_device.cc b/vendor_libs/test_vendor_lib/model/devices/hci_socket_device.cc
new file mode 100644
index 0000000..e146fcc
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/hci_socket_device.cc
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2018 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_socket_device"
+
+#include "hci_socket_device.h"
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include "osi/include/log.h"
+
+#include "model/setup/device_boutique.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+HciSocketDevice::HciSocketDevice(int file_descriptor) : socket_file_descriptor_(file_descriptor) {
+ advertising_interval_ms_ = std::chrono::milliseconds(0);
+
+ page_scan_delay_ms_ = std::chrono::milliseconds(600);
+
+ properties_.SetPageScanRepetitionMode(0);
+ properties_.SetClassOfDevice(0x600420);
+ properties_.SetExtendedInquiryData({
+ 16, // length
+ 9, // Type: Device Name
+ 'g',
+ 'D',
+ 'e',
+ 'v',
+ 'i',
+ 'c',
+ 'e',
+ '-',
+ 'h',
+ 'c',
+ 'i',
+ '_',
+ 'n',
+ 'e',
+ 't',
+ });
+ properties_.SetName({
+ 'g',
+ 'D',
+ 'e',
+ 'v',
+ 'i',
+ 'c',
+ 'e',
+ '-',
+ 'H',
+ 'C',
+ 'I',
+ '_',
+ 'N',
+ 'e',
+ 't',
+ });
+
+ h4_ = hci::H4Packetizer(
+ socket_file_descriptor_,
+ [this](const std::vector<uint8_t>& raw_command) {
+ LOG_INFO(LOG_TAG, "Rx Command");
+ std::shared_ptr<std::vector<uint8_t>> packet_copy = std::make_shared<std::vector<uint8_t>>(raw_command);
+ HandleCommand(packet_copy);
+ },
+ [](const std::vector<uint8_t>&) { CHECK(false) << "Unexpected Event in HciSocketDevice!"; },
+ [this](const std::vector<uint8_t>& raw_acl) {
+ LOG_INFO(LOG_TAG, "Rx ACL");
+ std::shared_ptr<std::vector<uint8_t>> packet_copy = std::make_shared<std::vector<uint8_t>>(raw_acl);
+ HandleAcl(packet_copy);
+ },
+ [this](const std::vector<uint8_t>& raw_sco) {
+ LOG_INFO(LOG_TAG, "Rx SCO");
+ std::shared_ptr<std::vector<uint8_t>> packet_copy = std::make_shared<std::vector<uint8_t>>(raw_sco);
+ HandleSco(packet_copy);
+ });
+
+ RegisterEventChannel([this](std::shared_ptr<std::vector<uint8_t>> packet) {
+ LOG_INFO(LOG_TAG, "Tx Event");
+ SendHci(hci::PacketType::EVENT, packet);
+ });
+ RegisterAclChannel([this](std::shared_ptr<std::vector<uint8_t>> packet) {
+ LOG_INFO(LOG_TAG, "Tx ACL");
+ SendHci(hci::PacketType::ACL, packet);
+ });
+ RegisterScoChannel([this](std::shared_ptr<std::vector<uint8_t>> packet) {
+ LOG_INFO(LOG_TAG, "Tx SCO");
+ SendHci(hci::PacketType::SCO, packet);
+ });
+}
+
+void HciSocketDevice::TimerTick() {
+ LOG_INFO(LOG_TAG, "TimerTick fd = %d", socket_file_descriptor_);
+ h4_.OnDataReady(socket_file_descriptor_);
+ DualModeController::TimerTick();
+}
+
+void HciSocketDevice::SendHci(hci::PacketType packet_type, const std::shared_ptr<std::vector<uint8_t>> packet) {
+ if (socket_file_descriptor_ == -1) {
+ LOG_INFO(LOG_TAG, "socket_file_descriptor == -1");
+ return;
+ }
+ uint8_t type = static_cast<uint8_t>(packet_type);
+ int bytes_written;
+ bytes_written = write(socket_file_descriptor_, &type, sizeof(type));
+ if (bytes_written != sizeof(type)) {
+ LOG_INFO(LOG_TAG, "bytes_written %d != sizeof(type)", bytes_written);
+ }
+ bytes_written = write(socket_file_descriptor_, packet->data(), packet->size());
+ if (static_cast<size_t>(bytes_written) != packet->size()) {
+ LOG_INFO(LOG_TAG, "bytes_written %d != packet->size", bytes_written);
+ }
+}
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/hci_socket_device.h b/vendor_libs/test_vendor_lib/model/devices/hci_socket_device.h
new file mode 100644
index 0000000..11eddae
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/hci_socket_device.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2018 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 "model/controller/dual_mode_controller.h"
+#include "model/devices/h4_packetizer.h"
+
+namespace {
+const std::string kHciSocketDevicePropertiesFile = "/etc/bluetooth/hci_socket_device_controller_properties.json";
+} // namespace
+
+namespace test_vendor_lib {
+
+class HciSocketDevice : public DualModeController {
+ public:
+ HciSocketDevice(int socket_fd);
+ ~HciSocketDevice() = default;
+
+ static std::shared_ptr<HciSocketDevice> Create(int socket_fd) {
+ return std::make_shared<HciSocketDevice>(socket_fd);
+ }
+
+ virtual std::string GetTypeString() const override {
+ return "hci_socket_device";
+ }
+
+ virtual void TimerTick() override;
+
+ void SendHci(hci::PacketType packet_type, const std::shared_ptr<std::vector<uint8_t>> packet);
+
+ private:
+ int socket_file_descriptor_{-1};
+ hci::H4Packetizer h4_{socket_file_descriptor_, [](const std::vector<uint8_t>&) {}, [](const std::vector<uint8_t>&) {},
+ [](const std::vector<uint8_t>&) {}, [](const std::vector<uint8_t>&) {}};
+};
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/keyboard.cc b/vendor_libs/test_vendor_lib/model/devices/keyboard.cc
new file mode 100644
index 0000000..2cfc992
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/keyboard.cc
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2016 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 "keyboard"
+
+#include "keyboard.h"
+
+#include "model/setup/device_boutique.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+bool Keyboard::registered_ = DeviceBoutique::Register(LOG_TAG, &Keyboard::Create);
+
+Keyboard::Keyboard() {
+ properties_.SetLeAdvertisementType(BTM_BLE_CONNECT_EVT);
+ properties_.SetLeAdvertisement({0x11, // Length
+ BTM_BLE_AD_TYPE_NAME_CMPL,
+ 'g',
+ 'D',
+ 'e',
+ 'v',
+ 'i',
+ 'c',
+ 'e',
+ '-',
+ 'k',
+ 'e',
+ 'y',
+ 'b',
+ 'o',
+ 'a',
+ 'r',
+ 'd',
+ 0x03, // Length
+ 0x19,
+ 0xC1,
+ 0x03,
+ 0x03, // Length
+ 0x03,
+ 0x12,
+ 0x18,
+ 0x02, // Length
+ BTM_BLE_AD_TYPE_FLAG,
+ BTM_BLE_BREDR_NOT_SPT | BTM_BLE_GEN_DISC_FLAG});
+
+ properties_.SetLeScanResponse({0x04, // Length
+ BTM_BLE_AD_TYPE_NAME_SHORT, 'k', 'e', 'y'});
+}
+
+std::string Keyboard::GetTypeString() const {
+ return "keyboard";
+}
+
+void Keyboard::Initialize(const vector<std::string>& args) {
+ if (args.size() < 2) return;
+
+ Address addr;
+ if (Address::FromString(args[1], addr)) properties_.SetLeAddress(addr);
+
+ if (args.size() < 3) return;
+
+ SetAdvertisementInterval(std::chrono::milliseconds(std::stoi(args[2])));
+}
+
+void Keyboard::TimerTick() {
+ if (!connected_) {
+ Beacon::TimerTick();
+ }
+}
+
+void Keyboard::IncomingPacket(packets::LinkLayerPacketView packet) {
+ if (!connected_) {
+ Beacon::IncomingPacket(packet);
+ }
+}
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/keyboard.h b/vendor_libs/test_vendor_lib/model/devices/keyboard.h
new file mode 100644
index 0000000..871fa52
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/keyboard.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2016 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 "device.h"
+
+#include "beacon.h"
+
+namespace test_vendor_lib {
+
+class Keyboard : public Beacon {
+ public:
+ Keyboard();
+ virtual ~Keyboard() = default;
+
+ static std::shared_ptr<Device> Create() {
+ return std::make_shared<Keyboard>();
+ }
+
+ // Return a string representation of the type of device.
+ virtual std::string GetTypeString() const override;
+
+ // Initialize the device based on the values of |args|.
+ virtual void Initialize(const std::vector<std::string>& args) override;
+
+ virtual void IncomingPacket(packets::LinkLayerPacketView packet) override;
+
+ virtual void TimerTick() override;
+
+ private:
+ bool connected_{false};
+ static bool registered_;
+};
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.cc b/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.cc
new file mode 100644
index 0000000..9ccfd61
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.cc
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2018 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 "link_layer_socket_device"
+
+#include "link_layer_socket_device.h"
+
+#include <unistd.h>
+
+#include "osi/include/log.h"
+#include "packets/link_layer/link_layer_packet_builder.h"
+#include "packets/link_layer/link_layer_packet_view.h"
+#include "packets/packet_view.h"
+#include "packets/view.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+LinkLayerSocketDevice::LinkLayerSocketDevice(int socket_fd, Phy::Type phy_type)
+ : socket_(socket_fd), phy_type_(phy_type) {}
+
+void LinkLayerSocketDevice::TimerTick() {
+ if (bytes_left_ == 0) {
+ received_ = std::make_shared<std::vector<uint8_t>>(Link::kSizeBytes);
+ size_t bytes_received = socket_.TryReceive(Link::kSizeBytes, received_->data());
+ if (bytes_received == 0) {
+ return;
+ }
+ CHECK(bytes_received == Link::kSizeBytes) << "bytes_received == " << bytes_received;
+ packets::PacketView<true> size({packets::View(received_, 0, Link::kSizeBytes)});
+ bytes_left_ = size.begin().extract<uint32_t>();
+ received_->resize(Link::kSizeBytes + bytes_left_);
+ offset_ = Link::kSizeBytes;
+ }
+ size_t bytes_received = socket_.TryReceive(bytes_left_, received_->data() + offset_);
+ if (bytes_received == 0) {
+ return;
+ }
+ bytes_left_ -= bytes_received;
+ offset_ += bytes_received;
+ if (bytes_left_ == 0) {
+ SendLinkLayerPacket(packets::LinkLayerPacketBuilder::ReWrap(received_), phy_type_);
+ offset_ = 0;
+ received_.reset();
+ }
+}
+
+void LinkLayerSocketDevice::IncomingPacket(packets::LinkLayerPacketView packet) {
+ socket_.TrySend(packet);
+}
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.h b/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.h
new file mode 100644
index 0000000..d3bbb2e
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2018 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 "device.h"
+#include "include/link.h"
+#include "include/phy.h"
+#include "packets/link_layer/link_layer_packet_view.h"
+#include "polled_socket.h"
+
+namespace test_vendor_lib {
+
+class LinkLayerSocketDevice : public Device {
+ public:
+ LinkLayerSocketDevice(int socket_fd, Phy::Type phy_type);
+ LinkLayerSocketDevice(LinkLayerSocketDevice&& s) = default;
+ virtual ~LinkLayerSocketDevice() = default;
+
+ static std::shared_ptr<Device> Create(int socket_fd, Phy::Type phy_type) {
+ return std::make_shared<LinkLayerSocketDevice>(socket_fd, phy_type);
+ }
+
+ virtual std::string GetTypeString() const override {
+ return "link_layer_socket_device";
+ }
+
+ virtual void Initialize(const std::vector<std::string>&) override {}
+
+ virtual void IncomingPacket(packets::LinkLayerPacketView packet) override;
+
+ virtual void TimerTick() override;
+
+ private:
+ net::PolledSocket socket_;
+ Phy::Type phy_type_;
+ size_t bytes_left_{0};
+ size_t offset_;
+ std::shared_ptr<std::vector<uint8_t>> received_;
+ std::vector<packets::LinkLayerPacketView> packet_queue_;
+};
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/loopback.cc b/vendor_libs/test_vendor_lib/model/devices/loopback.cc
new file mode 100644
index 0000000..4d9078e
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/loopback.cc
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2016 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 "loopback"
+
+#include "loopback.h"
+
+#include "le_advertisement.h"
+#include "model/setup/device_boutique.h"
+#include "osi/include/log.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+bool Loopback::registered_ = DeviceBoutique::Register(LOG_TAG, &Loopback::Create);
+
+Loopback::Loopback() {
+ advertising_interval_ms_ = std::chrono::milliseconds(1280);
+ properties_.SetLeAdvertisementType(BTM_BLE_NON_CONNECT_EVT);
+ properties_.SetLeAdvertisement({0x11, // Length
+ BTM_BLE_AD_TYPE_NAME_CMPL,
+ 'g',
+ 'D',
+ 'e',
+ 'v',
+ 'i',
+ 'c',
+ 'e',
+ '-',
+ 'l',
+ 'o',
+ 'o',
+ 'p',
+ 'b',
+ 'a',
+ 'c',
+ 'k',
+ 0x02, // Length
+ BTM_BLE_AD_TYPE_FLAG,
+ BTM_BLE_BREDR_NOT_SPT | BTM_BLE_GEN_DISC_FLAG});
+
+ properties_.SetLeScanResponse({0x05, // Length
+ BTM_BLE_AD_TYPE_NAME_SHORT, 'l', 'o', 'o', 'p'});
+}
+
+std::string Loopback::GetTypeString() const {
+ return "loopback";
+}
+
+std::string Loopback::ToString() const {
+ std::string dev = GetTypeString() + "@" + properties_.GetLeAddress().ToString();
+
+ return dev;
+}
+
+void Loopback::Initialize(const vector<std::string>& args) {
+ if (args.size() < 2) return;
+
+ Address addr;
+ if (Address::FromString(args[1], addr)) properties_.SetLeAddress(addr);
+
+ if (args.size() < 3) return;
+
+ SetAdvertisementInterval(std::chrono::milliseconds(std::stoi(args[2])));
+}
+
+void Loopback::TimerTick() {}
+
+void Loopback::IncomingPacket(packets::LinkLayerPacketView packet) {
+ LOG_INFO(LOG_TAG, "Got a packet of type %d", static_cast<int>(packet.GetType()));
+ if (packet.GetDestinationAddress() == properties_.GetLeAddress() && packet.GetType() == Link::PacketType::LE_SCAN) {
+ LOG_INFO(LOG_TAG, "Got a scan");
+ std::unique_ptr<packets::LeAdvertisementBuilder> scan_response = packets::LeAdvertisementBuilder::Create(
+ LeAdvertisement::AddressType::PUBLIC, LeAdvertisement::AdvertisementType::SCAN_RESPONSE,
+ properties_.GetLeScanResponse());
+ std::shared_ptr<packets::LinkLayerPacketBuilder> to_send = packets::LinkLayerPacketBuilder::WrapLeScanResponse(
+ std::move(scan_response), properties_.GetLeAddress(), packet.GetSourceAddress());
+ std::vector<std::shared_ptr<PhyLayer>> le_phys = phy_layers_[Phy::Type::LOW_ENERGY];
+ for (auto phy : le_phys) {
+ LOG_INFO(LOG_TAG, "Sending a Scan Response on a Phy");
+ phy->Send(to_send);
+ }
+ }
+}
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/loopback.h b/vendor_libs/test_vendor_lib/model/devices/loopback.h
new file mode 100644
index 0000000..31dd1cd
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/loopback.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2016 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 "device.h"
+
+namespace test_vendor_lib {
+
+// A simple device that advertises periodically and is not connectable.
+class Loopback : public Device {
+ public:
+ Loopback();
+ virtual ~Loopback() = default;
+
+ static std::shared_ptr<Device> Create() {
+ return std::make_shared<Loopback>();
+ }
+
+ // Return a string representation of the type of device.
+ virtual std::string GetTypeString() const override;
+
+ // Return a string representation of the device.
+ virtual std::string ToString() const override;
+
+ // Set the address and advertising interval from string args.
+ virtual void Initialize(const std::vector<std::string>& args) override;
+
+ virtual void IncomingPacket(packets::LinkLayerPacketView packet) override;
+
+ virtual void TimerTick() override;
+
+ private:
+ static bool registered_;
+};
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/polled_socket.cc b/vendor_libs/test_vendor_lib/model/devices/polled_socket.cc
new file mode 100644
index 0000000..5719132
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/polled_socket.cc
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2018 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 "polled_socket"
+
+#include "polled_socket.h"
+
+#include <base/logging.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+
+#include "osi/include/log.h"
+
+namespace test_vendor_lib {
+namespace net {
+
+PolledSocket::PolledSocket(int file_descriptor) : file_descriptor_(file_descriptor) {}
+
+PolledSocket::PolledSocket(PolledSocket&& p) : file_descriptor_(p.file_descriptor_) {
+ p.file_descriptor_ = -1;
+}
+
+PolledSocket::~PolledSocket() {
+ CleanUp();
+}
+
+void PolledSocket::CleanUp() {
+ if (file_descriptor_ != -1) {
+ WHILE_EINTR(close(file_descriptor_));
+ }
+ file_descriptor_ = -1;
+}
+
+size_t PolledSocket::TrySend(packets::PacketView<true> packet) {
+ if (file_descriptor_ == -1) {
+ return 0;
+ }
+ // Could skip this copy if the packet is guaranteed to be contiguous.
+ std::vector<uint8_t> copy;
+ copy.reserve(packet.size());
+ for (const auto&& c : packet) {
+ copy.push_back(c);
+ }
+ int ret = write(file_descriptor_, copy.data(), copy.size());
+ if (ret == -1) {
+ ALOGW("%s error %s", __func__, strerror(errno));
+ return 0;
+ } else {
+ return static_cast<size_t>(ret);
+ }
+}
+
+/*
+void PolledSocket::TrySendVector(
+ const std::vector<std::vector<uint8_t>&>& raw_vectors) {
+if (file_descriptor_ < 0) {
+ return;
+}
+for (const std::vector<uint8_t>& v : raw_vectors) {
+ Send(v);
+}
+ std::vector<struct iovec> iovecs;
+ for (auto v : raw_vectors) {
+ struct iovec one_iovec;
+ one_iovec.iov_base = v.data();
+ one_iovec.iov_base = v.size();
+ iovecs.push_back(one_iovec);
+ }
+ int ret = writev(file_descriptor_, iovecs.data(), iovecs.size());
+ if (ret == -1) {
+ return 0;
+ } else {
+ return static_cast<size_t>(ret);
+ }
+}
+*/
+
+size_t PolledSocket::TryReceive(size_t num_bytes, uint8_t* data) {
+ if (file_descriptor_ == -1) return 0;
+ int ret;
+ WHILE_EINTR(ret = read(file_descriptor_, data, num_bytes));
+ if (ret < 0) {
+ if (errno == EAGAIN) {
+ return 0;
+ } else {
+ ALOGW("%s error %s", __func__, strerror(errno));
+ CleanUp();
+ return 0;
+ }
+ }
+ return ret;
+}
+
+} // namespace net
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/polled_socket.h b/vendor_libs/test_vendor_lib/model/devices/polled_socket.h
new file mode 100644
index 0000000..b697f56
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/polled_socket.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2018 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 <string>
+#include <vector>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "packets/packet_view.h"
+
+namespace test_vendor_lib {
+namespace net {
+
+#define WHILE_EINTR(fn) \
+ do { \
+ } while ((fn) == -1 && errno == EINTR)
+
+class PolledSocket {
+ public:
+ PolledSocket(int file_descriptor);
+ PolledSocket(PolledSocket&& p);
+ virtual ~PolledSocket();
+
+ size_t TrySend(packets::PacketView<true> packet);
+ // size_t TrySendVector(const std::vector<const std::vector<uint8_t>&>& data);
+ size_t TryReceive(size_t num_bytes, uint8_t* data);
+
+ private:
+ void CleanUp();
+ int file_descriptor_{-1};
+};
+
+} // namespace net
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.cc b/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.cc
new file mode 100644
index 0000000..787e2f7
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.cc
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2018 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 "remote_loopback_device"
+
+#include "remote_loopback_device.h"
+
+#include "model/setup/device_boutique.h"
+
+#include "osi/include/log.h"
+#include "packets/link_layer/link_layer_packet_builder.h"
+#include "packets/link_layer/link_layer_packet_view.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+using packets::LinkLayerPacketBuilder;
+using packets::LinkLayerPacketView;
+using packets::PageResponseBuilder;
+
+bool RemoteLoopbackDevice::registered_ = DeviceBoutique::Register(LOG_TAG, &RemoteLoopbackDevice::Create);
+
+RemoteLoopbackDevice::RemoteLoopbackDevice() {}
+
+std::string RemoteLoopbackDevice::ToString() const {
+ return GetTypeString() + " (no address)";
+}
+
+void RemoteLoopbackDevice::Initialize(const std::vector<std::string>& args) {
+ if (args.size() < 2) return;
+
+ Address addr;
+ if (Address::FromString(args[1], addr)) properties_.SetAddress(addr);
+}
+
+void RemoteLoopbackDevice::IncomingPacket(LinkLayerPacketView packet) {
+ // TODO: Check sender?
+ // TODO: Handle other packet types
+ Phy::Type phy_type = Phy::Type::BR_EDR;
+
+ Link::PacketType type = packet.GetType();
+ switch (type) {
+ case Link::PacketType::PAGE:
+ SendLinkLayerPacket(LinkLayerPacketBuilder::WrapPageResponse(
+ PageResponseBuilder::Create(true), packet.GetSourceAddress(), packet.GetSourceAddress()),
+ Phy::Type::BR_EDR);
+ break;
+ default: {
+ ALOGW("Resend = %d", static_cast<int>(packet.size()));
+ std::shared_ptr<std::vector<uint8_t>> extracted_packet = std::make_shared<std::vector<uint8_t>>();
+ extracted_packet->reserve(packet.size());
+ for (const auto byte : packet) {
+ extracted_packet->push_back(byte);
+ }
+
+ SendLinkLayerPacket(LinkLayerPacketBuilder::ReWrap(extracted_packet), phy_type);
+ }
+ }
+}
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.h b/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.h
new file mode 100644
index 0000000..5513677
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018 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 "device.h"
+#include "packets/link_layer/link_layer_packet_view.h"
+
+namespace test_vendor_lib {
+
+class RemoteLoopbackDevice : public Device {
+ public:
+ RemoteLoopbackDevice();
+ virtual ~RemoteLoopbackDevice() = default;
+
+ static std::shared_ptr<Device> Create() {
+ return std::make_shared<RemoteLoopbackDevice>();
+ }
+
+ virtual std::string GetTypeString() const override {
+ return "remote_loopback_device";
+ }
+
+ virtual std::string ToString() const override;
+
+ virtual void Initialize(const std::vector<std::string>& args) override;
+
+ virtual void IncomingPacket(packets::LinkLayerPacketView packet) override;
+
+ private:
+ static bool registered_;
+};
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/server_port_factory.cc b/vendor_libs/test_vendor_lib/model/devices/server_port_factory.cc
new file mode 100644
index 0000000..72008a6
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/server_port_factory.cc
@@ -0,0 +1,151 @@
+/*
+ * 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 "server_port_factory"
+
+#include "server_port_factory.h"
+
+#include <base/logging.h>
+
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+using std::vector;
+
+namespace test_vendor_lib {
+namespace net {
+
+ServerPortFactory::ServerPortFactory(int port, std::function<void(int fd)>& callback) {
+ port_ = port;
+ callback_ = callback;
+}
+
+int ServerPortFactory::SetUp(int port) {
+ struct sockaddr_in listen_address;
+ socklen_t sockaddr_in_size = sizeof(struct sockaddr_in);
+ memset(&listen_address, 0, sockaddr_in_size);
+
+ OSI_NO_INTR(listen_fd_ = socket(AF_INET, SOCK_STREAM, 0));
+ if (listen_fd_ < 0) {
+ LOG_INFO(LOG_TAG, "Error creating socket for test channel.");
+ return -1;
+ }
+
+ 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 -1;
+ }
+
+ if (listen(listen_fd_, 1) < 0) {
+ LOG_INFO(LOG_TAG, "Error listening for test channel.");
+ close(listen_fd_);
+ return -1;
+ }
+ return listen_fd_;
+}
+
+void ServerPortFactory::CleanUp() {
+ if (listen_fd_ == -1) {
+ return;
+ }
+ if (close(listen_fd_)) {
+ LOG_ERROR(LOG_TAG, "Error closing listen_fd_.");
+ }
+ listen_fd_ = -1;
+}
+
+int ServerPortFactory::Accept(int listen_fd_) {
+ int accept_fd = -1;
+ struct sockaddr_in test_channel_address;
+ socklen_t sockaddr_in_size = sizeof(struct sockaddr_in);
+ memset(&test_channel_address, 0, sockaddr_in_size);
+
+ OSI_NO_INTR(accept_fd = accept(listen_fd_, reinterpret_cast<sockaddr*>(&test_channel_address), &sockaddr_in_size));
+ if (accept_fd < 0) {
+ LOG_INFO(LOG_TAG, "Error accepting test channel connection errno=%d (%s).", errno, strerror(errno));
+
+ if (errno != EAGAIN && errno != EWOULDBLOCK) {
+ LOG_ERROR(LOG_TAG, "Closing listen_fd_ (won't try again).");
+ close(listen_fd_);
+ return -1;
+ }
+ }
+
+ LOG_INFO(LOG_TAG, "accept_fd = %d.", accept_fd);
+
+ return accept_fd;
+}
+
+void ServerPortFactory::OnCommandReady(int fd, std::function<void(void)> unwatch) {
+ uint8_t command_name_size = 0;
+ read(fd, &command_name_size, 1);
+ 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());
+
+ if (command_name == "CLOSE_TEST_CHANNEL" || command_name == "") {
+ LOG_INFO(LOG_TAG, "Test channel closed");
+ unwatch();
+ close(fd);
+ return;
+ }
+
+ uint8_t num_args = 0;
+ read(fd, &num_args, 1);
+ vector<std::string> args;
+ for (uint8_t i = 0; i < num_args; ++i) {
+ uint8_t arg_size = 0;
+ read(fd, &arg_size, 1);
+ vector<uint8_t> arg;
+ arg.resize(arg_size);
+ read(fd, &arg[0], arg_size);
+ args.push_back(std::string(arg.begin(), arg.end()));
+ }
+
+ command_handler_(command_name, args);
+}
+
+void ServerPortFactory::SendResponse(int fd, const std::string& response) const {
+ size_t size = response.size();
+ // Cap to 64K
+ if (size > 0xffff) {
+ size = 0xffff;
+ }
+ char size_buf[4] = {static_cast<uint8_t>(size & 0xff), static_cast<uint8_t>((size >> 8) & 0xff),
+ static_cast<uint8_t>((size >> 16) & 0xff), static_cast<uint8_t>((size >> 24) & 0xff)};
+ int written = write(fd, size_buf, 4);
+ CHECK(written == 4) << "What happened? written = " << written << "errno =" << errno;
+ written = write(fd, response.c_str(), size);
+ CHECK(written == static_cast<int>(size)) << "What happened? written = " << written << "errno =" << errno;
+}
+
+void ServerPortFactory::RegisterCommandHandler(
+ const std::function<void(const std::string&, const std::vector<std::string>&)>& callback) {
+ command_handler_ = callback;
+}
+
+} // namespace net
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/server_port_factory.h b/vendor_libs/test_vendor_lib/model/devices/server_port_factory.h
new file mode 100644
index 0000000..5f19c49
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/server_port_factory.h
@@ -0,0 +1,51 @@
+/*
+ * 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 <string>
+#include <vector>
+
+namespace test_vendor_lib {
+namespace net {
+
+// Starts a server and calls the registered lambda for each connection.
+class ServerPortFactory {
+ public:
+ // Opens a server port and sets the listen file descriptor.
+ ServerPortFactory(int port, std::function<void(int fd)>& on_connection);
+
+ // Closes the port (if succesfully opened in SetUp).
+ ~ServerPortFactory() {}
+
+ // Waits for a connection request and returns the file descriptor to watch.
+ // Returns -1 on an error.
+ void Accept(int listen_fd);
+
+ private:
+ std::function<void(int fd)> on_connection_;
+
+ int port;
+ int listen_fd_ = -1;
+
+ ServerPortFactory(const ServerPortFactory&) = delete;
+ ServerPortFactory& operator=(const ServerPortFactory&) = delete;
+};
+
+} // namespace net
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/sniffer.cc b/vendor_libs/test_vendor_lib/model/devices/sniffer.cc
new file mode 100644
index 0000000..903ecac
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/sniffer.cc
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2018 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 "sniffer"
+
+#include "sniffer.h"
+
+#include "osi/include/log.h"
+
+#include "model/setup/device_boutique.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+bool Sniffer::registered_ = DeviceBoutique::Register(LOG_TAG, &Sniffer::Create);
+
+Sniffer::Sniffer() {}
+
+void Sniffer::Initialize(const vector<std::string>& args) {
+ if (args.size() < 2) return;
+
+ if (Address::FromString(args[1], device_to_sniff_)) {
+ properties_.SetAddress(device_to_sniff_);
+ }
+
+ if (args.size() < 3) return;
+}
+
+void Sniffer::TimerTick() {}
+
+void Sniffer::IncomingPacket(packets::LinkLayerPacketView packet) {
+ Address source = packet.GetSourceAddress();
+ Address dest = packet.GetDestinationAddress();
+ bool match_source = device_to_sniff_ == source;
+ bool match_dest = device_to_sniff_ == dest;
+ if (!match_source && !match_dest) {
+ return;
+ }
+ LOG_INFO(LOG_TAG, "%s %s -> %s (Type %d)", (match_source ? (match_dest ? "<->" : "<--") : "-->"),
+ source.ToString().c_str(), dest.ToString().c_str(), static_cast<int>(packet.GetType()));
+}
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/sniffer.h b/vendor_libs/test_vendor_lib/model/devices/sniffer.h
new file mode 100644
index 0000000..3e0cfef
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/devices/sniffer.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2018 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 "device.h"
+#include "packets/link_layer/link_layer_packet_view.h"
+#include "types/address.h"
+
+namespace test_vendor_lib {
+
+class Sniffer : public Device {
+ public:
+ Sniffer();
+ ~Sniffer() = default;
+
+ static std::shared_ptr<Sniffer> Create() {
+ return std::make_shared<Sniffer>();
+ }
+
+ // Initialize the device based on the values of |args|.
+ virtual void Initialize(const std::vector<std::string>& args) override;
+
+ // Return a string representation of the type of device.
+ virtual std::string GetTypeString() const override {
+ return "sniffer";
+ }
+
+ virtual void IncomingPacket(packets::LinkLayerPacketView packet) override;
+
+ virtual void TimerTick() override;
+
+ private:
+ static bool registered_;
+ Address device_to_sniff_;
+};
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/setup/async_manager.cc b/vendor_libs/test_vendor_lib/model/setup/async_manager.cc
new file mode 100644
index 0000000..fb9b1ad
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/setup/async_manager.cc
@@ -0,0 +1,493 @@
+/*
+ * Copyright 2016 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 "async_manager"
+
+#include "async_manager.h"
+
+#include "osi/include/log.h"
+
+#include <algorithm>
+#include <atomic>
+#include <condition_variable>
+#include <mutex>
+#include <thread>
+#include <vector>
+#include "fcntl.h"
+#include "sys/select.h"
+#include "unistd.h"
+
+namespace test_vendor_lib {
+// Implementation of AsyncManager is divided between two classes, three if
+// AsyncManager itself is taken into account, but its only responsability
+// besides being a proxy for the other two classes is to provide a global
+// synchronization mechanism for callbacks and client code to use.
+
+// The watching of file descriptors is done through AsyncFdWatcher. Several
+// objects of this class may coexist simultaneosly as they share no state.
+// After construction of this objects nothing happens beyond some very simple
+// member initialization. When the first FD is set up for watching the object
+// starts a new thread which watches the given (and later provided) FDs using
+// select() inside a loop. A special FD (a pipe) is also watched which is
+// used to notify the thread of internal changes on the object state (like
+// the addition of new FDs to watch on). Every access to internal state is
+// synchronized using a single internal mutex. The thread is only stopped on
+// destruction of the object, by modifying a flag, which is the only member
+// variable accessed without acquiring the lock (because the notification to
+// the thread is done later by writing to a pipe which means the thread will
+// be notified regardless of what phase of the loop it is in that moment)
+
+// The scheduling of asynchronous tasks, periodic or not, is handled by the
+// AsyncTaskManager class. Like the one for FDs, this class shares no internal
+// state between different instances so it is safe to use several objects of
+// this class, also nothing interesting happens upon construction, but only
+// after a Task has been scheduled and access to internal state is synchronized
+// using a single internal mutex. When the first task is scheduled a thread
+// is started which monitors a queue of tasks. The queue is peeked to see
+// when the next task should be carried out and then the thread performs a
+// (absolute) timed wait on a condition variable. The wait ends because of a
+// time out or a notify on the cond var, the former means a task is due
+// for execution while the later means there has been a change in internal
+// state, like a task has been scheduled/canceled or the flag to stop has
+// been set. Setting and querying the stop flag or modifying the task queue
+// and subsequent notification on the cond var is done atomically (e.g while
+// holding the lock on the internal mutex) to ensure that the thread never
+// misses the notification, since notifying a cond var is not persistent as
+// writing on a pipe (if not done this way, the thread could query the
+// stopping flag and be put aside by the OS scheduler right after, then the
+// 'stop thread' procedure could run, setting the flag, notifying a cond
+// var that no one is waiting on and joining the thread, the thread then
+// resumes execution believing that it needs to continue and waits on the
+// cond var possibly forever if there are no tasks scheduled, efectively
+// causing a deadlock).
+
+// This number also states the maximum number of scheduled tasks we can handle
+// at a given time
+static const uint16_t kMaxTaskId = -1; /* 2^16 - 1, permisible ids are {1..2^16-1}*/
+static inline AsyncTaskId NextAsyncTaskId(const AsyncTaskId id) {
+ return (id == kMaxTaskId) ? 1 : id + 1;
+}
+// The buffer is only 10 bytes because the expected number of bytes
+// written on this socket is 1. It is possible that the thread is notified
+// more than once but highly unlikely, so a buffer of size 10 seems enough
+// and the reads are performed inside a while just in case it isn't. From
+// the thread routine's point of view it is the same to have been notified
+// just once or 100 times so it just tries to consume the entire buffer.
+// In the cases where an interrupt would cause read to return without
+// having read everything that was available a new iteration of the thread
+// loop will bring execution to this point almost immediately, so there is
+// no need to treat that case.
+static const int kNotificationBufferSize = 10;
+
+// Async File Descriptor Watcher Implementation:
+class AsyncManager::AsyncFdWatcher {
+ public:
+ int WatchFdForNonBlockingReads(int file_descriptor, const ReadCallback& on_read_fd_ready_callback) {
+ // add file descriptor and callback
+ {
+ std::unique_lock<std::mutex> guard(internal_mutex_);
+ watched_shared_fds_[file_descriptor] = on_read_fd_ready_callback;
+ }
+
+ // start the thread if not started yet
+ int started = tryStartThread();
+ if (started != 0) {
+ LOG_ERROR(LOG_TAG, "%s: Unable to start thread", __func__);
+ return started;
+ }
+
+ // notify the thread so that it knows of the new FD
+ notifyThread();
+
+ return 0;
+ }
+
+ void StopWatchingFileDescriptor(int file_descriptor) {
+ std::unique_lock<std::mutex> guard(internal_mutex_);
+ watched_shared_fds_.erase(file_descriptor);
+ }
+
+ AsyncFdWatcher() = default;
+
+ ~AsyncFdWatcher() = default;
+
+ int stopThread() {
+ if (!std::atomic_exchange(&running_, false)) {
+ return 0; // if not running already
+ }
+
+ notifyThread();
+
+ if (std::this_thread::get_id() != thread_.get_id()) {
+ thread_.join();
+ } else {
+ LOG_WARN(LOG_TAG, "%s: Starting thread stop from inside the reading thread itself", __func__);
+ }
+
+ {
+ std::unique_lock<std::mutex> guard(internal_mutex_);
+ watched_shared_fds_.clear();
+ }
+
+ return 0;
+ }
+
+ private:
+ AsyncFdWatcher(const AsyncFdWatcher&) = delete;
+ AsyncFdWatcher& operator=(const AsyncFdWatcher&) = delete;
+
+ // Make sure to call this with at least one file descriptor ready to be
+ // watched upon or the thread routine will return immediately
+ int tryStartThread() {
+ if (std::atomic_exchange(&running_, true)) {
+ return 0; // if already running
+ }
+ // set up the communication channel
+ int pipe_fds[2];
+ if (pipe2(pipe_fds, O_NONBLOCK)) {
+ LOG_ERROR(LOG_TAG,
+ "%s:Unable to establish a communication channel to the reading "
+ "thread",
+ __func__);
+ return -1;
+ }
+ notification_listen_fd_ = pipe_fds[0];
+ notification_write_fd_ = pipe_fds[1];
+
+ thread_ = std::thread([this]() { ThreadRoutine(); });
+ if (!thread_.joinable()) {
+ LOG_ERROR(LOG_TAG, "%s: Unable to start reading thread", __func__);
+ return -1;
+ }
+ return 0;
+ }
+
+ int notifyThread() {
+ char buffer = '0';
+ if (TEMP_FAILURE_RETRY(write(notification_write_fd_, &buffer, 1)) < 0) {
+ LOG_ERROR(LOG_TAG, "%s: Unable to send message to reading thread", __func__);
+ return -1;
+ }
+ return 0;
+ }
+
+ int setUpFileDescriptorSet(fd_set& read_fds) {
+ // add comm channel to the set
+ FD_SET(notification_listen_fd_, &read_fds);
+ int nfds = notification_listen_fd_;
+
+ // add watched FDs to the set
+ {
+ std::unique_lock<std::mutex> guard(internal_mutex_);
+ for (auto& fdp : watched_shared_fds_) {
+ FD_SET(fdp.first, &read_fds);
+ nfds = std::max(fdp.first, nfds);
+ }
+ }
+ return nfds;
+ }
+
+ // check the comm channel and read everything there
+ bool consumeThreadNotifications(fd_set& read_fds) {
+ if (FD_ISSET(notification_listen_fd_, &read_fds)) {
+ char buffer[kNotificationBufferSize];
+ while (TEMP_FAILURE_RETRY(read(notification_listen_fd_, buffer, kNotificationBufferSize)) ==
+ kNotificationBufferSize) {
+ }
+ return true;
+ }
+ return false;
+ }
+
+ // check all file descriptors and call callbacks if necesary
+ void runAppropriateCallbacks(fd_set& read_fds) {
+ // not a good idea to call a callback while holding the FD lock,
+ // nor to release the lock while traversing the map
+ std::vector<decltype(watched_shared_fds_)::value_type> fds;
+ {
+ std::unique_lock<std::mutex> guard(internal_mutex_);
+ for (auto& fdc : watched_shared_fds_) {
+ if (FD_ISSET(fdc.first, &read_fds)) {
+ fds.push_back(fdc);
+ }
+ }
+ }
+ for (auto& p : fds) {
+ p.second(p.first);
+ }
+ }
+
+ void ThreadRoutine() {
+ while (running_) {
+ fd_set read_fds;
+ FD_ZERO(&read_fds);
+ int nfds = setUpFileDescriptorSet(read_fds);
+
+ // wait until there is data available to read on some FD
+ int retval = select(nfds + 1, &read_fds, NULL, NULL, NULL);
+ if (retval <= 0) { // there was some error or a timeout
+ LOG_ERROR(LOG_TAG,
+ "%s: There was an error while waiting for data on the file "
+ "descriptors: %s",
+ __func__, strerror(errno));
+ continue;
+ }
+
+ consumeThreadNotifications(read_fds);
+
+ // Do not read if there was a call to stop running
+ if (!running_) {
+ break;
+ }
+
+ runAppropriateCallbacks(read_fds);
+ }
+ }
+
+ std::atomic_bool running_{false};
+ std::thread thread_;
+ std::mutex internal_mutex_;
+
+ std::map<int, ReadCallback> watched_shared_fds_;
+
+ // A pair of FD to send information to the reading thread
+ int notification_listen_fd_;
+ int notification_write_fd_;
+};
+
+// Async task manager implementation
+class AsyncManager::AsyncTaskManager {
+ public:
+ AsyncTaskId ExecAsync(std::chrono::milliseconds delay, const TaskCallback& callback) {
+ return scheduleTask(std::make_shared<Task>(std::chrono::steady_clock::now() + delay, callback));
+ }
+
+ AsyncTaskId ExecAsyncPeriodically(std::chrono::milliseconds delay, std::chrono::milliseconds period,
+ const TaskCallback& callback) {
+ return scheduleTask(std::make_shared<Task>(std::chrono::steady_clock::now() + delay, period, callback));
+ }
+
+ bool CancelAsyncTask(AsyncTaskId async_task_id) {
+ // remove task from queue (and task id asociation) while holding lock
+ std::unique_lock<std::mutex> guard(internal_mutex_);
+ if (tasks_by_id.count(async_task_id) == 0) {
+ return false;
+ }
+ task_queue_.erase(tasks_by_id[async_task_id]);
+ tasks_by_id.erase(async_task_id);
+ return true;
+ }
+
+ AsyncTaskManager() = default;
+
+ ~AsyncTaskManager() = default;
+
+ int stopThread() {
+ {
+ std::unique_lock<std::mutex> guard(internal_mutex_);
+ tasks_by_id.clear();
+ task_queue_.clear();
+ if (!running_) {
+ return 0;
+ }
+ running_ = false;
+ // notify the thread
+ internal_cond_var_.notify_one();
+ } // release the lock before joining a thread that is likely waiting for it
+ if (std::this_thread::get_id() != thread_.get_id()) {
+ thread_.join();
+ } else {
+ LOG_WARN(LOG_TAG, "%s: Starting thread stop from inside the task thread itself", __func__);
+ }
+ return 0;
+ }
+
+ private:
+ // Holds the data for each task
+ class Task {
+ public:
+ Task(std::chrono::steady_clock::time_point time, std::chrono::milliseconds period, const TaskCallback& callback)
+ : time(time), periodic(true), period(period), callback(callback), task_id(kInvalidTaskId) {}
+ Task(std::chrono::steady_clock::time_point time, const TaskCallback& callback)
+ : time(time), periodic(false), callback(callback), task_id(kInvalidTaskId) {}
+
+ // Operators needed to be in a collection
+ bool operator<(const Task& another) const {
+ return std::make_pair(time, task_id) < std::make_pair(another.time, another.task_id);
+ }
+
+ bool isPeriodic() const {
+ return periodic;
+ }
+
+ // These fields should no longer be public if the class ever becomes
+ // public or gets more complex
+ std::chrono::steady_clock::time_point time;
+ bool periodic;
+ std::chrono::milliseconds period;
+ TaskCallback callback;
+ AsyncTaskId task_id;
+ };
+
+ // A comparator class to put shared pointers to tasks in an ordered set
+ struct task_p_comparator {
+ bool operator()(const std::shared_ptr<Task>& t1, const std::shared_ptr<Task>& t2) const {
+ return *t1 < *t2;
+ }
+ };
+
+ AsyncTaskManager(const AsyncTaskManager&) = delete;
+ AsyncTaskManager& operator=(const AsyncTaskManager&) = delete;
+
+ AsyncTaskId scheduleTask(const std::shared_ptr<Task>& task) {
+ AsyncTaskId task_id = kInvalidTaskId;
+ {
+ std::unique_lock<std::mutex> guard(internal_mutex_);
+ // no more room for new tasks, we need a larger type for IDs
+ if (tasks_by_id.size() == kMaxTaskId) // TODO potentially type unsafe
+ return kInvalidTaskId;
+ do {
+ lastTaskId_ = NextAsyncTaskId(lastTaskId_);
+ } while (isTaskIdInUse(lastTaskId_));
+ task->task_id = lastTaskId_;
+ // add task to the queue and map
+ tasks_by_id[lastTaskId_] = task;
+ task_queue_.insert(task);
+ task_id = lastTaskId_;
+ }
+ // start thread if necessary
+ int started = tryStartThread();
+ if (started != 0) {
+ LOG_ERROR(LOG_TAG, "%s: Unable to start thread", __func__);
+ return kInvalidTaskId;
+ }
+ // notify the thread so that it knows of the new task
+ internal_cond_var_.notify_one();
+ // return task id
+ return task_id;
+ }
+
+ bool isTaskIdInUse(const AsyncTaskId& task_id) const {
+ return tasks_by_id.count(task_id) != 0;
+ }
+
+ int tryStartThread() {
+ // need the lock because of the running flag and the cond var
+ std::unique_lock<std::mutex> guard(internal_mutex_);
+ // check that the thread is not yet running
+ if (running_) {
+ return 0;
+ }
+ // start the thread
+ running_ = true;
+ thread_ = std::thread([this]() { ThreadRoutine(); });
+ if (!thread_.joinable()) {
+ LOG_ERROR(LOG_TAG, "%s: Unable to start task thread", __func__);
+ return -1;
+ }
+ return 0;
+ }
+
+ void ThreadRoutine() {
+ while (1) {
+ TaskCallback callback;
+ bool run_it = false;
+ {
+ std::unique_lock<std::mutex> guard(internal_mutex_);
+ if (!task_queue_.empty()) {
+ std::shared_ptr<Task> task_p = *(task_queue_.begin());
+ if (task_p->time < std::chrono::steady_clock::now()) {
+ run_it = true;
+ callback = task_p->callback;
+ task_queue_.erase(task_p); // need to remove and add again if
+ // periodic to update order
+ if (task_p->isPeriodic()) {
+ task_p->time += task_p->period;
+ task_queue_.insert(task_p);
+ } else {
+ tasks_by_id.erase(task_p->task_id);
+ }
+ }
+ }
+ }
+ if (run_it) {
+ callback();
+ }
+ {
+ std::unique_lock<std::mutex> guard(internal_mutex_);
+ // wait on condition variable with timeout just in time for next task if
+ // any
+ if (task_queue_.size() > 0) {
+ internal_cond_var_.wait_until(guard, (*task_queue_.begin())->time);
+ } else {
+ internal_cond_var_.wait(guard);
+ }
+ // check for termination right after being notified (and maybe before?)
+ if (!running_) break;
+ }
+ }
+ }
+
+ bool running_ = false;
+ std::thread thread_;
+ std::mutex internal_mutex_;
+ std::condition_variable internal_cond_var_;
+
+ AsyncTaskId lastTaskId_ = kInvalidTaskId;
+ std::map<AsyncTaskId, std::shared_ptr<Task> > tasks_by_id;
+ std::set<std::shared_ptr<Task>, task_p_comparator> task_queue_;
+};
+
+// Async Manager Implementation:
+AsyncManager::AsyncManager() : fdWatcher_p_(new AsyncFdWatcher()), taskManager_p_(new AsyncTaskManager()) {}
+
+AsyncManager::~AsyncManager() {
+ // Make sure the threads are stopped before destroying the object.
+ // The threads need to be stopped here and not in each internal class'
+ // destructor because unique_ptr's reset() first assigns nullptr to the
+ // pointer and only then calls the destructor, so any callback running
+ // on these threads would dereference a null pointer if they called a member
+ // function of this class.
+ fdWatcher_p_->stopThread();
+ taskManager_p_->stopThread();
+}
+
+int AsyncManager::WatchFdForNonBlockingReads(int file_descriptor, const ReadCallback& on_read_fd_ready_callback) {
+ return fdWatcher_p_->WatchFdForNonBlockingReads(file_descriptor, on_read_fd_ready_callback);
+}
+
+void AsyncManager::StopWatchingFileDescriptor(int file_descriptor) {
+ fdWatcher_p_->StopWatchingFileDescriptor(file_descriptor);
+}
+
+AsyncTaskId AsyncManager::ExecAsync(std::chrono::milliseconds delay, const TaskCallback& callback) {
+ return taskManager_p_->ExecAsync(delay, callback);
+}
+
+AsyncTaskId AsyncManager::ExecAsyncPeriodically(std::chrono::milliseconds delay, std::chrono::milliseconds period,
+ const TaskCallback& callback) {
+ return taskManager_p_->ExecAsyncPeriodically(delay, period, callback);
+}
+
+bool AsyncManager::CancelAsyncTask(AsyncTaskId async_task_id) {
+ return taskManager_p_->CancelAsyncTask(async_task_id);
+}
+
+void AsyncManager::Synchronize(const CriticalCallback& critical) {
+ std::unique_lock<std::mutex> guard(synchronization_mutex_);
+ critical();
+}
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/setup/async_manager.h b/vendor_libs/test_vendor_lib/model/setup/async_manager.h
new file mode 100644
index 0000000..e1ad888
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/setup/async_manager.h
@@ -0,0 +1,110 @@
+#ifndef TEST_VENDOR_LIB_ASYNC_MANAGER_H_
+#define TEST_VENDOR_LIB_ASYNC_MANAGER_H_
+
+#include <time.h>
+#include <cstdint>
+#include <map>
+#include <set>
+#include "errno.h"
+#include "stdio.h"
+
+#include <chrono>
+#include <functional>
+#include <memory>
+#include <mutex>
+#include <utility>
+
+namespace test_vendor_lib {
+
+using TaskCallback = std::function<void(void)>;
+using ReadCallback = std::function<void(int)>;
+using CriticalCallback = std::function<void(void)>;
+using AsyncTaskId = uint16_t;
+constexpr uint16_t kInvalidTaskId = 0;
+
+// Manages tasks that should be done in the future. It can watch file
+// descriptors to call a given callback when it is certain that a non-blocking
+// read is possible or can call a callback at a specific time (aproximately) and
+// (optionally) repeat the call periodically.
+// The class is thread safe in the sense that all its member functions can be
+// called simultaneously from different concurrent threads. The exception to
+// this rule is the class destructor, which is unsafe to call concurrently with
+// calls to other class member functions. This exception also has its own
+// exception: it is safe to destroy the object even if some of its callbacks may
+// call its member functions, because the destructor will make sure all callback
+// calling threads are stopped before actually destroying anything. Callbacks
+// that wait for file descriptor always run on the same thread, so there is no
+// need of additional synchronization between them. The same applies to task
+// callbacks since they also run on a thread of their own, however it is
+// possible for a read callback and a task callback to execute at the same time
+// (they are garanteed to run in different threads) so synchronization is needed
+// to access common state (other than the internal state of the AsyncManager
+// class). While not required, it is strongly recommended to use the
+// Synchronize(const CriticalCallback&) member function to execute code inside
+// critical sections. Callbacks passed to this method on the same AsyncManager
+// object from different threads are granted to *NOT* run concurrently.
+class AsyncManager {
+ public:
+ // Starts watching a file descriptor in a separate thread. The
+ // on_read_fd_ready_callback() will be asynchronously called when it is
+ // guaranteed that a call to read() on the FD will not block. No promise is
+ // made about when in the future the callback will be called, in particular,
+ // it is perfectly possible to have it called before this function returns. A
+ // return of 0 means success, an error code is returned otherwise.
+ int WatchFdForNonBlockingReads(int file_descriptor, const ReadCallback& on_read_fd_ready_callback);
+
+ // If the fd was not being watched before the call will be ignored.
+ void StopWatchingFileDescriptor(int file_descriptor);
+
+ // Schedules an action to occur in the future. Even if the delay given is not
+ // positive the callback will be called asynchronously.
+ AsyncTaskId ExecAsync(std::chrono::milliseconds delay, const TaskCallback& callback);
+
+ // Schedules an action to occur periodically in the future. If the delay given
+ // is not positive the callback will be asynchronously called once for each
+ // time in the past that it should have been called and then scheduled for
+ // future times.
+ AsyncTaskId ExecAsyncPeriodically(std::chrono::milliseconds delay, std::chrono::milliseconds period,
+ const TaskCallback& callback);
+
+ // Cancels the/every future ocurrence of the action specified by this id. It
+ // is guaranteed that the asociated callback will not be called after this
+ // method returns (it could be called during the execution of the method).
+ // The calling thread may block until the scheduling thread acknowledges the
+ // cancelation.
+ bool CancelAsyncTask(AsyncTaskId async_task_id);
+
+ // Execs the given code in a synchronized manner. It is guaranteed that code
+ // given on (possibly)concurrent calls to this member function on the same
+ // AsyncManager object will never be executed simultaneously. It is the
+ // class's user's resposability to ensure that no calls to Synchronize are
+ // made from inside a CriticalCallback, since that would cause a lock to be
+ // acquired twice with unpredictable results. It is strongly recommended to
+ // have very simple CriticalCallbacks, preferably using lambda expressions.
+ void Synchronize(const CriticalCallback&);
+
+ AsyncManager();
+
+ ~AsyncManager();
+
+ private:
+ // Implementation of the FD watching part of AsyncManager, extracted to its
+ // own class for clarity purposes.
+ class AsyncFdWatcher;
+
+ // Implementation of the asynchronous tasks part of AsyncManager, extracted to
+ // its own class for clarity purposes.
+ class AsyncTaskManager;
+
+ AsyncManager(const AsyncManager&) = delete;
+ AsyncManager& operator=(const AsyncManager&) = delete;
+
+ // Kept as pointers because we may want to support reseting either without
+ // destroying the other one
+ std::unique_ptr<AsyncFdWatcher> fdWatcher_p_;
+ std::unique_ptr<AsyncTaskManager> taskManager_p_;
+
+ std::mutex synchronization_mutex_;
+};
+} // namespace test_vendor_lib
+#endif // TEST_VENDOR_LIB_ASYNC_MANAGER_H_
diff --git a/vendor_libs/test_vendor_lib/model/setup/device_boutique.cc b/vendor_libs/test_vendor_lib/model/setup/device_boutique.cc
new file mode 100644
index 0000000..18de1b1
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/setup/device_boutique.cc
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2018 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 "device_boutique"
+
+#include "device_boutique.h"
+
+#include "base/logging.h"
+#include "osi/include/log.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+std::unordered_map<std::string, std::function<std::shared_ptr<Device>()>>& DeviceBoutique::GetMap() {
+ static std::unordered_map<std::string, std::function<std::shared_ptr<Device>()>> impl;
+ return impl;
+}
+
+// Register a constructor for a device type.
+bool DeviceBoutique::Register(const std::string& device_type,
+ const std::function<std::shared_ptr<Device>()> device_constructor) {
+ LOG_INFO(LOG_TAG, "Registering %s", device_type.c_str());
+ GetMap()[device_type] = device_constructor;
+ return true;
+}
+
+std::shared_ptr<Device> DeviceBoutique::Create(const vector<std::string>& args) {
+ CHECK(!args.empty());
+
+ if (GetMap().find(args[0]) == GetMap().end()) {
+ LOG_WARN(LOG_TAG, "No constructor registered for %s", args[0].c_str());
+ return std::shared_ptr<Device>(nullptr);
+ }
+
+ std::shared_ptr<Device> new_device = GetMap()[args[0]]();
+ if (new_device != nullptr) new_device->Initialize(args);
+
+ return new_device;
+}
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/setup/device_boutique.h b/vendor_libs/test_vendor_lib/model/setup/device_boutique.h
new file mode 100644
index 0000000..64137a0
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/setup/device_boutique.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2018 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 "model/devices/device.h"
+
+namespace test_vendor_lib {
+
+// Create customized devices from a centralized shop.
+class DeviceBoutique {
+ public:
+ DeviceBoutique();
+ virtual ~DeviceBoutique() = default;
+
+ // Register a constructor for a device type.
+ static bool Register(const std::string& device_type, const std::function<std::shared_ptr<Device>()> method);
+
+ // Call the constructor that matches arg[0], then call dev->Initialize(args).
+ static std::shared_ptr<Device> Create(const std::vector<std::string>& args);
+
+ template <typename D>
+ struct Registrar {
+ explicit Registrar(std::string const& name) {
+ DeviceBoutique::Register(name, &D::Create);
+ }
+ static Registrar<D> registrar_;
+ };
+
+ private:
+ static std::unordered_map<std::string, std::function<std::shared_ptr<Device>()>>& GetMap();
+};
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/setup/phy_layer.h b/vendor_libs/test_vendor_lib/model/setup/phy_layer.h
new file mode 100644
index 0000000..84e4cba
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/setup/phy_layer.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2018 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 "include/phy.h"
+#include "packets/link_layer/link_layer_packet_builder.h"
+#include "packets/link_layer/link_layer_packet_view.h"
+
+namespace test_vendor_lib {
+
+class PhyLayer {
+ public:
+ PhyLayer(Phy::Type phy_type, uint32_t id, const std::function<void(packets::LinkLayerPacketView)>& device_receive)
+ : phy_type_(phy_type), id_(id), transmit_to_device_(device_receive) {}
+
+ virtual void Send(const std::shared_ptr<packets::LinkLayerPacketBuilder> packet) = 0;
+
+ virtual void Receive(packets::LinkLayerPacketView packet) = 0;
+
+ virtual void TimerTick() = 0;
+
+ Phy::Type GetType() {
+ return phy_type_;
+ }
+
+ uint32_t GetId() {
+ return id_;
+ }
+
+ virtual ~PhyLayer() = default;
+
+ private:
+ Phy::Type phy_type_;
+ uint32_t id_;
+
+ protected:
+ const std::function<void(packets::LinkLayerPacketView)> transmit_to_device_;
+};
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.cc b/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.cc
new file mode 100644
index 0000000..182416a
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.cc
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2018 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 "phy_layer_factory"
+
+#include "phy_layer_factory.h"
+
+#include "base/logging.h"
+
+#include "osi/include/log.h"
+
+namespace test_vendor_lib {
+
+PhyLayerFactory::PhyLayerFactory(Phy::Type phy_type) : phy_type_(phy_type) {}
+
+Phy::Type PhyLayerFactory::GetType() {
+ return phy_type_;
+}
+
+std::shared_ptr<PhyLayer> PhyLayerFactory::GetPhyLayer(
+ const std::function<void(packets::LinkLayerPacketView)>& device_receive) {
+ std::shared_ptr<PhyLayer> new_phy =
+ std::make_shared<PhyLayerImpl>(phy_type_, next_id_++, device_receive, std::shared_ptr<PhyLayerFactory>(this));
+ phy_layers_.push_back(new_phy);
+ return new_phy;
+}
+
+void PhyLayerFactory::UnregisterPhyLayer(uint32_t id) {
+ for (auto it = phy_layers_.begin(); it != phy_layers_.end();) {
+ if ((*it)->GetId() == id) {
+ it = phy_layers_.erase(it);
+ } else {
+ it++;
+ }
+ }
+}
+
+void PhyLayerFactory::Send(const std::shared_ptr<packets::LinkLayerPacketBuilder> packet, uint32_t id) {
+ // Convert from a Builder to a View
+ std::shared_ptr<std::vector<uint8_t>> serialized_packet =
+ std::shared_ptr<std::vector<uint8_t>>(new std::vector<uint8_t>());
+ std::back_insert_iterator<std::vector<uint8_t>> itr(*serialized_packet);
+ serialized_packet->reserve(packet->size());
+ packet->Serialize(itr);
+ packets::LinkLayerPacketView packet_view = packets::LinkLayerPacketView::Create(serialized_packet);
+
+ for (const auto phy : phy_layers_) {
+ if (id != phy->GetId()) {
+ phy->Receive(packet_view);
+ }
+ }
+}
+
+void PhyLayerFactory::TimerTick() {
+ for (auto phy : phy_layers_) {
+ phy->TimerTick();
+ }
+}
+
+std::string PhyLayerFactory::ToString() const {
+ switch (phy_type_) {
+ case Phy::Type::LOW_ENERGY:
+ return "LOW_ENERGY";
+ break;
+ case Phy::Type::BR_EDR:
+ return "BR_EDR";
+ break;
+ default:
+ return "Unknown";
+ }
+}
+
+PhyLayerImpl::PhyLayerImpl(Phy::Type phy_type, uint32_t id,
+ const std::function<void(packets::LinkLayerPacketView)>& device_receive,
+ const std::shared_ptr<PhyLayerFactory>& factory)
+ : PhyLayer(phy_type, id, device_receive), factory_(factory) {}
+
+PhyLayerImpl::~PhyLayerImpl() {
+ factory_->UnregisterPhyLayer(GetId());
+ PhyLayer::~PhyLayer();
+}
+
+void PhyLayerImpl::Send(const std::shared_ptr<packets::LinkLayerPacketBuilder> packet) {
+ factory_->Send(packet, GetId());
+}
+
+void PhyLayerImpl::Receive(packets::LinkLayerPacketView packet) {
+ transmit_to_device_(packet);
+}
+
+void PhyLayerImpl::TimerTick() {}
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.h b/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.h
new file mode 100644
index 0000000..018ff78
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2018 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 <memory>
+#include <vector>
+
+#include "include/phy.h"
+#include "packets/link_layer/link_layer_packet_builder.h"
+#include "packets/link_layer/link_layer_packet_view.h"
+#include "phy_layer.h"
+
+namespace test_vendor_lib {
+
+class PhyLayerFactory {
+ friend class PhyLayerImpl;
+
+ public:
+ PhyLayerFactory(Phy::Type phy_type);
+
+ virtual ~PhyLayerFactory() = default;
+
+ Phy::Type GetType();
+
+ std::shared_ptr<PhyLayer> GetPhyLayer(const std::function<void(packets::LinkLayerPacketView)>& device_receive);
+
+ void UnregisterPhyLayer(uint32_t id);
+
+ virtual void TimerTick();
+
+ virtual std::string ToString() const;
+
+ protected:
+ virtual void Send(const std::shared_ptr<packets::LinkLayerPacketBuilder> packet, uint32_t id);
+
+ private:
+ Phy::Type phy_type_;
+ std::vector<std::shared_ptr<PhyLayer>> phy_layers_;
+ uint32_t next_id_{1};
+};
+
+class PhyLayerImpl : public PhyLayer {
+ public:
+ PhyLayerImpl(Phy::Type phy_type, uint32_t id, const std::function<void(packets::LinkLayerPacketView)>& device_receive,
+ const std::shared_ptr<PhyLayerFactory>& factory);
+ virtual ~PhyLayerImpl() override;
+
+ virtual void Send(const std::shared_ptr<packets::LinkLayerPacketBuilder> packet) override;
+ virtual void Receive(packets::LinkLayerPacketView packet) override;
+ virtual void TimerTick() override;
+
+ private:
+ std::shared_ptr<PhyLayerFactory> factory_;
+};
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/setup/test_channel_transport.cc b/vendor_libs/test_vendor_lib/model/setup/test_channel_transport.cc
new file mode 100644
index 0000000..d291896
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/setup/test_channel_transport.cc
@@ -0,0 +1,157 @@
+/*
+ * 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 "test_channel_transport.h"
+
+#include <base/logging.h>
+
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+int TestChannelTransport::SetUp(int port) {
+ struct sockaddr_in listen_address;
+ socklen_t sockaddr_in_size = sizeof(struct sockaddr_in);
+ memset(&listen_address, 0, sockaddr_in_size);
+
+ OSI_NO_INTR(listen_fd_ = socket(AF_INET, SOCK_STREAM, 0));
+ if (listen_fd_ < 0) {
+ LOG_INFO(LOG_TAG, "Error creating socket for test channel.");
+ return -1;
+ }
+
+ 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 -1;
+ }
+
+ if (listen(listen_fd_, 1) < 0) {
+ LOG_INFO(LOG_TAG, "Error listening for test channel.");
+ close(listen_fd_);
+ return -1;
+ }
+ return listen_fd_;
+}
+
+void TestChannelTransport::CleanUp() {
+ if (listen_fd_ == -1) {
+ return;
+ }
+ if (close(listen_fd_)) {
+ LOG_ERROR(LOG_TAG, "Error closing listen_fd_.");
+ }
+ listen_fd_ = -1;
+}
+
+int TestChannelTransport::Accept(int listen_fd_) {
+ int accept_fd = -1;
+
+ OSI_NO_INTR(accept_fd = accept(listen_fd_, NULL, NULL));
+
+ if (accept_fd < 0) {
+ LOG_INFO(LOG_TAG, "Error accepting test channel connection errno=%d (%s).", errno, strerror(errno));
+
+ if (errno != EAGAIN && errno != EWOULDBLOCK) {
+ LOG_ERROR(LOG_TAG, "Closing listen_fd_ (won't try again).");
+ close(listen_fd_);
+ return -1;
+ }
+ }
+
+ LOG_INFO(LOG_TAG, "accept_fd = %d.", accept_fd);
+
+ return accept_fd;
+}
+
+void TestChannelTransport::OnCommandReady(int fd, std::function<void(void)> unwatch) {
+ uint8_t command_name_size = 0;
+ int bytes_read = read(fd, &command_name_size, 1);
+ if (bytes_read != 1) {
+ LOG_INFO(LOG_TAG, "Unexpected (command_name_size) bytes_read: %d != %d", bytes_read, 1);
+ }
+ vector<uint8_t> command_name_raw;
+ command_name_raw.resize(command_name_size);
+ bytes_read = read(fd, &command_name_raw[0], command_name_size);
+ if (bytes_read != command_name_size) {
+ LOG_INFO(LOG_TAG, "Unexpected (command_name) bytes_read: %d != %d", bytes_read, command_name_size);
+ }
+ std::string command_name(command_name_raw.begin(), command_name_raw.end());
+
+ if (command_name == "CLOSE_TEST_CHANNEL" || command_name == "") {
+ LOG_INFO(LOG_TAG, "Test channel closed");
+ unwatch();
+ close(fd);
+ return;
+ }
+
+ uint8_t num_args = 0;
+ bytes_read = read(fd, &num_args, 1);
+ if (bytes_read != 1) {
+ LOG_INFO(LOG_TAG, "Unexpected (num_args) bytes_read: %d != %d", bytes_read, 1);
+ }
+ vector<std::string> args;
+ for (uint8_t i = 0; i < num_args; ++i) {
+ uint8_t arg_size = 0;
+ bytes_read = read(fd, &arg_size, 1);
+ if (bytes_read != 1) {
+ LOG_INFO(LOG_TAG, "Unexpected (arg_size) bytes_read: %d != %d", bytes_read, 1);
+ }
+ vector<uint8_t> arg;
+ arg.resize(arg_size);
+ bytes_read = read(fd, &arg[0], arg_size);
+ if (bytes_read != arg_size) {
+ LOG_INFO(LOG_TAG, "Unexpected (arg) bytes_read: %d != %d", bytes_read, arg_size);
+ }
+ args.push_back(std::string(arg.begin(), arg.end()));
+ }
+
+ command_handler_(command_name, args);
+}
+
+void TestChannelTransport::SendResponse(int fd, const std::string& response) const {
+ size_t size = response.size();
+ // Cap to 64K
+ if (size > 0xffff) {
+ size = 0xffff;
+ }
+ uint8_t size_buf[4] = {static_cast<uint8_t>(size & 0xff), static_cast<uint8_t>((size >> 8) & 0xff),
+ static_cast<uint8_t>((size >> 16) & 0xff), static_cast<uint8_t>((size >> 24) & 0xff)};
+ int written = write(fd, size_buf, 4);
+ CHECK(written == 4) << "What happened? written = " << written << "errno =" << errno;
+ written = write(fd, response.c_str(), size);
+ CHECK(written == static_cast<int>(size)) << "What happened? written = " << written << "errno =" << errno;
+}
+
+void TestChannelTransport::RegisterCommandHandler(
+ const std::function<void(const std::string&, const std::vector<std::string>&)>& callback) {
+ command_handler_ = callback;
+}
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/setup/test_channel_transport.h b/vendor_libs/test_vendor_lib/model/setup/test_channel_transport.h
new file mode 100644
index 0000000..e9b390f
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/setup/test_channel_transport.h
@@ -0,0 +1,65 @@
+/*
+ * 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 <string>
+#include <vector>
+
+//#include "base/files/scoped_file.h"
+
+namespace test_vendor_lib {
+
+// Manages communications between test channel and the controller. Mirrors the
+// HciTransport for the test channel.
+class TestChannelTransport {
+ public:
+ TestChannelTransport() {}
+
+ ~TestChannelTransport() {}
+
+ // Opens a port and returns the file descriptor for the socket.
+ // Returns -1 on an error.
+ int SetUp(int port);
+
+ // Closes the port (if succesfully opened in SetUp).
+ void CleanUp();
+
+ // Waits for a connection request from the test channel program and
+ // returns the file descriptor to watch for run-time parameters.
+ // Returns -1 on an error.
+ int Accept(int listen_fd);
+
+ // Sets the callback that fires when data is read in WatchFd().
+ void RegisterCommandHandler(const std::function<void(const std::string&, const std::vector<std::string>&)>& callback);
+
+ // Send data back to the test channel.
+ void SendResponse(int fd, const std::string&) const;
+
+ void OnCommandReady(int fd, std::function<void(void)> unwatch);
+
+ private:
+ std::function<void(const std::string&, const std::vector<std::string>&)> command_handler_;
+
+ int listen_fd_ = -1;
+
+ TestChannelTransport(const TestChannelTransport& cmdPckt) = delete;
+ TestChannelTransport& operator=(const TestChannelTransport& cmdPckt) = delete;
+};
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/setup/test_command_handler.cc b/vendor_libs/test_vendor_lib/model/setup/test_command_handler.cc
new file mode 100644
index 0000000..ad8689d
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/setup/test_command_handler.cc
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2018 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_command_handler"
+
+#include "test_command_handler.h"
+#include "device_boutique.h"
+#include "phy.h"
+
+#include <memory>
+
+#include <stdlib.h>
+
+#include <base/logging.h>
+#include "base/files/file_util.h"
+#include "base/json/json_reader.h"
+#include "base/values.h"
+
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+TestCommandHandler::TestCommandHandler(TestModel& test_model) : model_(test_model) {
+#define SET_HANDLER(command_name, method) \
+ active_commands_[command_name] = [this](const vector<std::string>& param) { method(param); };
+ SET_HANDLER("add", Add);
+ SET_HANDLER("add_remote", AddRemote);
+ SET_HANDLER("del", Del);
+ SET_HANDLER("add_phy", AddPhy);
+ SET_HANDLER("del_phy", DelPhy);
+ SET_HANDLER("add_device_to_phy", AddDeviceToPhy);
+ SET_HANDLER("del_device_from_phy", DelDeviceFromPhy);
+ SET_HANDLER("list", List);
+ SET_HANDLER("set_timer_period", SetTimerPeriod);
+ SET_HANDLER("start_timer", StartTimer);
+ SET_HANDLER("stop_timer", StopTimer);
+#undef SET_HANDLER
+}
+
+void TestCommandHandler::AddDefaults() {
+ // Add a phy for LE and one for BR/EDR
+ AddPhy({"LOW_ENERGY"});
+ AddPhy({"BR_EDR"});
+
+ // Add the controller to the Phys
+ AddDeviceToPhy({"0", "0"});
+ AddDeviceToPhy({"0", "1"});
+
+ // Add default test devices and add the devices to the phys
+ // Add({"beacon", "be:ac:10:00:00:01", "1000"});
+ // AddDeviceToPhy({"1", "0"});
+
+ // Add({"keyboard", "cc:1c:eb:0a:12:d1", "500"});
+ // AddDeviceToPhy({"2", "0"});
+
+ // Add({"classic", "c1:a5:51:c0:00:01", "22"});
+ // AddDeviceToPhy({"3", "1"});
+
+ // Add({"car_kit", "ca:12:1c:17:00:01", "238"});
+ // AddDeviceToPhy({"4", "1"});
+
+ // Add({"sniffer", "ca:12:1c:17:00:01"});
+ // AddDeviceToPhy({"5", "1"});
+
+ // Add({"sniffer", "3c:5a:b4:04:05:06"});
+ // AddDeviceToPhy({"1", "1"});
+ // Add({"remote_loopback_device", "10:0d:00:ba:c1:06"});
+ // AddDeviceToPhy({"2", "1"});
+ List({});
+
+ SetTimerPeriod({"10"});
+ StartTimer({});
+}
+
+void TestCommandHandler::HandleCommand(const std::string& name, const vector<std::string>& args) {
+ if (active_commands_.count(name) == 0) {
+ response_string_ = "Unhandled command: " + name;
+ send_response_(response_string_);
+ return;
+ }
+ active_commands_[name](args);
+}
+
+void TestCommandHandler::RegisterSendResponse(const std::function<void(const std::string&)> callback) {
+ send_response_ = callback;
+ send_response_("RegisterSendResponse called");
+}
+
+void TestCommandHandler::Add(const vector<std::string>& args) {
+ if (args.size() < 1) {
+ response_string_ = "TestCommandHandler 'add' takes an argument";
+ send_response_(response_string_);
+ return;
+ }
+ std::shared_ptr<Device> new_dev = DeviceBoutique::Create(args);
+
+ if (new_dev == NULL) {
+ response_string_ = "TestCommandHandler 'add' " + args[0] + " failed!";
+ send_response_(response_string_);
+ LOG_WARN(LOG_TAG, "%s", response_string_.c_str());
+ return;
+ }
+
+ LOG_INFO(LOG_TAG, "Add %s", new_dev->ToString().c_str());
+ size_t dev_index = model_.Add(new_dev);
+ response_string_ = std::to_string(dev_index) + std::string(":") + new_dev->ToString();
+ send_response_(response_string_);
+}
+
+void TestCommandHandler::AddRemote(const vector<std::string>& args) {
+ if (args.size() < 3) {
+ response_string_ = "TestCommandHandler usage: add_remote host port phy_type";
+ send_response_(response_string_);
+ return;
+ }
+
+ size_t port = std::stoi(args[1]);
+ Phy::Type phy_type = Phy::Type::BR_EDR;
+ if ("LOW_ENERGY" == args[2]) {
+ phy_type = Phy::Type::LOW_ENERGY;
+ }
+ if (port == 0 || port > 0xffff || args[0].size() < 2) {
+ response_string_ = "TestCommandHandler bad arguments to 'add_remote': ";
+ response_string_ += args[0];
+ response_string_ += "@";
+ response_string_ += args[1];
+ send_response_(response_string_);
+ return;
+ }
+
+ model_.AddRemote(args[0], port, phy_type);
+
+ response_string_ = args[0] + std::string("@") + std::to_string(port);
+ send_response_(response_string_);
+}
+
+void TestCommandHandler::Del(const vector<std::string>& args) {
+ size_t dev_index = std::stoi(args[0]);
+
+ model_.Del(dev_index);
+ response_string_ = "TestCommandHandler 'del' called with device at index " + std::to_string(dev_index);
+ send_response_(response_string_);
+}
+
+void TestCommandHandler::AddPhy(const vector<std::string>& args) {
+ if (args[0] == "LOW_ENERGY") {
+ std::shared_ptr<PhyLayerFactory> new_phy = std::make_shared<PhyLayerFactory>(Phy::Type::LOW_ENERGY);
+ model_.AddPhy(new_phy);
+ } else if (args[0] == "BR_EDR") {
+ std::shared_ptr<PhyLayerFactory> new_phy = std::make_shared<PhyLayerFactory>(Phy::Type::BR_EDR);
+ model_.AddPhy(new_phy);
+ } else {
+ response_string_ = "TestCommandHandler 'add_phy' with unrecognized type " + args[0];
+ send_response_(response_string_);
+ }
+}
+
+void TestCommandHandler::DelPhy(const vector<std::string>& args) {
+ size_t phy_index = std::stoi(args[0]);
+
+ model_.DelPhy(phy_index);
+ response_string_ = "TestCommandHandler 'del_phy' called with phy at index " + std::to_string(phy_index);
+ send_response_(response_string_);
+}
+
+void TestCommandHandler::AddDeviceToPhy(const vector<std::string>& args) {
+ if (args.size() != 2) {
+ response_string_ = "TestCommandHandler 'add_device_to_phy' takes two arguments";
+ send_response_(response_string_);
+ return;
+ }
+ size_t dev_index = std::stoi(args[0]);
+ size_t phy_index = std::stoi(args[1]);
+ model_.AddDeviceToPhy(dev_index, phy_index);
+ response_string_ = "TestCommandHandler 'add_device_to_phy' called with device " + std::to_string(dev_index) +
+ " and phy " + std::to_string(phy_index);
+ send_response_(response_string_);
+ return;
+}
+
+void TestCommandHandler::DelDeviceFromPhy(const vector<std::string>& args) {
+ if (args.size() != 2) {
+ response_string_ = "TestCommandHandler 'del_device_from_phy' takes two arguments";
+ send_response_(response_string_);
+ return;
+ }
+ size_t dev_index = std::stoi(args[0]);
+ size_t phy_index = std::stoi(args[1]);
+ model_.DelDeviceFromPhy(dev_index, phy_index);
+ response_string_ = "TestCommandHandler 'del_device_from_phy' called with device " + std::to_string(dev_index) +
+ " and phy " + std::to_string(phy_index);
+ send_response_(response_string_);
+ return;
+}
+
+void TestCommandHandler::List(const vector<std::string>& args) {
+ if (args.size() > 0) {
+ LOG_INFO(LOG_TAG, "Unused args: arg[0] = %s", args[0].c_str());
+ return;
+ }
+ send_response_(model_.List());
+}
+
+void TestCommandHandler::SetTimerPeriod(const vector<std::string>& args) {
+ if (args.size() != 1) {
+ LOG_INFO(LOG_TAG, "SetTimerPeriod takes 1 argument");
+ }
+ size_t period = std::stoi(args[0]);
+ model_.SetTimerPeriod(std::chrono::milliseconds(period));
+}
+
+void TestCommandHandler::StartTimer(const vector<std::string>& args) {
+ if (args.size() > 0) {
+ LOG_INFO(LOG_TAG, "Unused args: arg[0] = %s", args[0].c_str());
+ }
+ model_.StartTimer();
+}
+
+void TestCommandHandler::StopTimer(const vector<std::string>& args) {
+ if (args.size() > 0) {
+ LOG_INFO(LOG_TAG, "Unused args: arg[0] = %s", args[0].c_str());
+ }
+ model_.StopTimer();
+}
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/setup/test_command_handler.h b/vendor_libs/test_vendor_lib/model/setup/test_command_handler.h
new file mode 100644
index 0000000..409966a
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/setup/test_command_handler.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2018 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 <unistd.h>
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "model/devices/device.h"
+#include "phy_layer_factory.h"
+#include "test_channel_transport.h"
+#include "test_model.h"
+
+namespace test_vendor_lib {
+
+class TestCommandHandler {
+ public:
+ // Sets all of the methods to be used as callbacks in the HciHandler.
+ TestCommandHandler(TestModel& test_model);
+
+ ~TestCommandHandler() = default;
+
+ // Dispatches the action corresponding to the command specified by |name|.
+ void HandleCommand(const std::string& name, const std::vector<std::string>& args);
+
+ // Dispatches the action corresponding to the command specified by |name|.
+ void RegisterSendResponse(const std::function<void(const std::string&)> callback);
+
+ // Commands:
+
+ // Add a device
+ void Add(const std::vector<std::string>& args);
+
+ // Add a remote device
+ void AddRemote(const std::vector<std::string>& args);
+
+ // Remove devices by index
+ void Del(const std::vector<std::string>& args);
+
+ // Add phy
+ void AddPhy(const std::vector<std::string>& args);
+
+ // Remove phy by name
+ void DelPhy(const std::vector<std::string>& args);
+
+ // Add device to phy
+ void AddDeviceToPhy(const std::vector<std::string>& args);
+
+ // Remove device from phy
+ void DelDeviceFromPhy(const std::vector<std::string>& args);
+
+ // List the devices that the test knows about
+ void List(const std::vector<std::string>& args);
+
+ // Timer management functions
+ void SetTimerPeriod(const std::vector<std::string>& args);
+
+ void StartTimer(const std::vector<std::string>& args);
+
+ void StopTimer(const std::vector<std::string>& args);
+
+ // For manual testing
+ void AddDefaults();
+
+ private:
+ TestModel& model_;
+
+ std::string response_string_;
+
+ std::unordered_map<std::string, std::function<void(const std::vector<std::string>&)>> active_commands_;
+
+ std::function<void(const std::string&)> send_response_;
+
+ TestCommandHandler(const TestCommandHandler& cmdPckt) = delete;
+ TestCommandHandler& operator=(const TestCommandHandler& cmdPckt) = delete;
+};
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/setup/test_model.cc b/vendor_libs/test_vendor_lib/model/setup/test_model.cc
new file mode 100644
index 0000000..3572761
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/setup/test_model.cc
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2018 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_model"
+
+#include "test_model.h"
+
+// TODO: Remove when registration works
+#include "model/devices/beacon.h"
+#include "model/devices/beacon_swarm.h"
+#include "model/devices/car_kit.h"
+#include "model/devices/classic.h"
+#include "model/devices/keyboard.h"
+#include "model/devices/remote_loopback_device.h"
+#include "model/devices/sniffer.h"
+
+#include <memory>
+
+#include <stdlib.h>
+
+#include <base/logging.h>
+#include "base/files/file_util.h"
+#include "base/json/json_reader.h"
+#include "base/values.h"
+
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+#include "device_boutique.h"
+#include "include/phy.h"
+#include "model/devices/hci_socket_device.h"
+#include "model/devices/link_layer_socket_device.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+TestModel::TestModel(
+ std::function<AsyncTaskId(std::chrono::milliseconds, const TaskCallback&)> event_scheduler,
+
+ std::function<AsyncTaskId(std::chrono::milliseconds, std::chrono::milliseconds, const TaskCallback&)>
+ periodic_event_scheduler,
+
+ std::function<void(AsyncTaskId)> cancel, std::function<int(const std::string&, int)> connect_to_remote)
+ : schedule_task_(event_scheduler), schedule_periodic_task_(periodic_event_scheduler), cancel_task_(cancel),
+ connect_to_remote_(connect_to_remote) {
+ // TODO: Remove when registration works!
+ example_devices_.push_back(std::make_shared<Beacon>());
+ example_devices_.push_back(std::make_shared<BeaconSwarm>());
+ example_devices_.push_back(std::make_shared<Keyboard>());
+ example_devices_.push_back(std::make_shared<CarKit>());
+ example_devices_.push_back(std::make_shared<Classic>());
+ example_devices_.push_back(std::make_shared<Sniffer>());
+ example_devices_.push_back(std::make_shared<RemoteLoopbackDevice>());
+}
+
+void TestModel::SetTimerPeriod(std::chrono::milliseconds new_period) {
+ timer_period_ = new_period;
+
+ if (timer_tick_task_ == kInvalidTaskId) return;
+
+ // Restart the timer with the new period
+ StopTimer();
+ StartTimer();
+}
+
+void TestModel::StartTimer() {
+ LOG_INFO(LOG_TAG, "StartTimer()");
+ timer_tick_task_ =
+ schedule_periodic_task_(std::chrono::milliseconds(0), timer_period_, [this]() { TestModel::TimerTick(); });
+}
+
+void TestModel::StopTimer() {
+ LOG_INFO(LOG_TAG, "StopTimer()");
+ cancel_task_(timer_tick_task_);
+ timer_tick_task_ = kInvalidTaskId;
+}
+
+size_t TestModel::Add(std::shared_ptr<Device> new_dev) {
+ devices_.push_back(new_dev);
+ return devices_.size() - 1;
+}
+
+void TestModel::Del(size_t dev_index) {
+ if (dev_index >= devices_.size()) {
+ LOG_WARN(LOG_TAG, "del: index out of range!");
+ return;
+ }
+ devices_.erase(devices_.begin() + dev_index);
+}
+
+size_t TestModel::AddPhy(std::shared_ptr<PhyLayerFactory> new_phy) {
+ phys_.push_back(new_phy);
+ return phys_.size() - 1;
+}
+
+void TestModel::DelPhy(size_t phy_index) {
+ if (phy_index >= phys_.size()) {
+ LOG_WARN(LOG_TAG, "del_phy: index %d out of range: ", static_cast<int>(phy_index));
+ return;
+ }
+}
+
+void TestModel::AddDeviceToPhy(size_t dev_index, size_t phy_index) {
+ if (dev_index >= devices_.size()) {
+ LOG_WARN(LOG_TAG, "add_device_to_phy: device out of range: ");
+ return;
+ }
+ if (phy_index >= phys_.size()) {
+ LOG_WARN(LOG_TAG, "add_device_to_phy: phy out of range: ");
+ return;
+ }
+ std::shared_ptr<Device> dev = devices_[dev_index];
+ dev->RegisterPhyLayer(
+ phys_[phy_index]->GetPhyLayer([dev](packets::LinkLayerPacketView packet) { dev->IncomingPacket(packet); }));
+}
+
+void TestModel::DelDeviceFromPhy(size_t dev_index, size_t phy_index) {
+ if (dev_index >= devices_.size()) {
+ LOG_WARN(LOG_TAG, "del_device_from_phy: device out of range: ");
+ return;
+ }
+ if (phy_index >= phys_.size()) {
+ LOG_WARN(LOG_TAG, "del_device_from_phy: phy out of range: ");
+ return;
+ }
+}
+
+void TestModel::AddLinkLayerConnection(int socket_fd, Phy::Type phy_type) {
+ std::shared_ptr<Device> dev = LinkLayerSocketDevice::Create(socket_fd, phy_type);
+ int index = Add(dev);
+ for (size_t phy_index = 0; phy_index < phys_.size(); phy_index++) {
+ if (phy_type == phys_[phy_index]->GetType()) {
+ AddDeviceToPhy(index, phy_index);
+ }
+ }
+}
+
+void TestModel::IncomingLinkLayerConnection(int socket_fd) {
+ // TODO: Handle other phys
+ AddLinkLayerConnection(socket_fd, Phy::Type::BR_EDR);
+}
+
+void TestModel::AddRemote(const std::string& server, int port, Phy::Type phy_type) {
+ int socket_fd = connect_to_remote_(server, port);
+ if (socket_fd < 0) {
+ return;
+ }
+ AddLinkLayerConnection(socket_fd, phy_type);
+}
+
+void TestModel::IncomingHciConnection(int socket_fd) {
+ std::shared_ptr<HciSocketDevice> dev = HciSocketDevice::Create(socket_fd);
+ // TODO: Auto-increment addresses?
+ static int hci_devs = 0;
+ int index = Add(std::static_pointer_cast<Device>(dev));
+ std::string addr = "da:4c:10:de:17:0"; // Da HCI dev
+ CHECK(hci_devs < 10) << "Why do you need more than 9?";
+ addr += '0' + hci_devs++;
+ dev->Initialize({"IgnoredTypeName", addr});
+ // TODO: Add device to all phys? For now, just the first two.
+ for (size_t phy = 0; phy < 2 && phy < phys_.size(); phy++) {
+ AddDeviceToPhy(index, phy);
+ }
+ dev->RegisterTaskScheduler(schedule_task_);
+ dev->RegisterTaskCancel(cancel_task_);
+}
+
+const std::string& TestModel::List() {
+ list_string_ = "";
+ list_string_ += " Devices: \r\n";
+ for (size_t dev = 0; dev < devices_.size(); dev++) {
+ list_string_ += " " + std::to_string(dev) + ":";
+ list_string_ += devices_[dev]->ToString() + " \r\n";
+ }
+ list_string_ += " Phys: \r\n";
+ for (size_t phy = 0; phy < phys_.size(); phy++) {
+ list_string_ += " " + std::to_string(phy) + ":";
+ list_string_ += phys_[phy]->ToString() + " \r\n";
+ }
+ return list_string_;
+}
+
+void TestModel::TimerTick() {
+ for (size_t dev = 0; dev < devices_.size(); dev++) {
+ devices_[dev]->TimerTick();
+ }
+}
+
+void TestModel::Reset() {
+ StopTimer();
+ devices_.clear();
+ phys_.clear();
+}
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/setup/test_model.h b/vendor_libs/test_vendor_lib/model/setup/test_model.h
new file mode 100644
index 0000000..c799f3f
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/model/setup/test_model.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2018 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 <unistd.h>
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "async_manager.h"
+#include "model/devices/device.h"
+#include "phy_layer_factory.h"
+#include "test_channel_transport.h"
+
+namespace test_vendor_lib {
+
+class TestModel {
+ public:
+ TestModel(std::function<AsyncTaskId(std::chrono::milliseconds, const TaskCallback&)> evtScheduler,
+ std::function<AsyncTaskId(std::chrono::milliseconds, std::chrono::milliseconds, const TaskCallback&)>
+ periodicEvtScheduler,
+ std::function<void(AsyncTaskId)> cancel, std::function<int(const std::string&, int)> connect_to_remote);
+ ~TestModel() = default;
+
+ // Commands:
+
+ // Add a device, return its index
+ size_t Add(std::shared_ptr<Device> device);
+
+ // Remove devices by index
+ void Del(size_t device_index);
+
+ // Add phy, return its index
+ size_t AddPhy(std::shared_ptr<PhyLayerFactory> phy);
+
+ // Remove phy by index
+ void DelPhy(size_t phy_index);
+
+ // Add device to phy
+ void AddDeviceToPhy(size_t device_index, size_t phy_index);
+
+ // Remove device from phy
+ void DelDeviceFromPhy(size_t device_index, size_t phy_index);
+
+ // Handle incoming remote connections
+ void AddLinkLayerConnection(int socket_fd, Phy::Type phy_type);
+ void IncomingLinkLayerConnection(int socket_fd);
+ void IncomingHciConnection(int socket_fd);
+
+ // Connect to a remote device
+ void AddRemote(const std::string& server, int port, Phy::Type phy_type);
+
+ // Let devices know about the passage of time
+ void TimerTick();
+ void StartTimer();
+ void StopTimer();
+ void SetTimerPeriod(std::chrono::milliseconds new_period);
+
+ // List the devices that the test knows about
+ const std::string& List();
+
+ // Clear all devices and phys.
+ void Reset();
+
+ private:
+ std::vector<std::shared_ptr<PhyLayerFactory>> phys_;
+ std::vector<std::shared_ptr<Device>> devices_;
+ std::string list_string_;
+
+ // Callbacks to schedule tasks.
+ std::function<AsyncTaskId(std::chrono::milliseconds, const TaskCallback&)> schedule_task_;
+ std::function<AsyncTaskId(std::chrono::milliseconds, std::chrono::milliseconds, const TaskCallback&)>
+ schedule_periodic_task_;
+ std::function<void(AsyncTaskId)> cancel_task_;
+ std::function<int(const std::string&, int)> connect_to_remote_;
+
+ AsyncTaskId timer_tick_task_{kInvalidTaskId};
+ std::chrono::milliseconds timer_period_;
+
+ TestModel(TestModel& model) = delete;
+ TestModel& operator=(const TestModel& model) = delete;
+
+ std::vector<std::shared_ptr<Device>> example_devices_;
+};
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/Android.bp b/vendor_libs/test_vendor_lib/packets/Android.bp
new file mode 100644
index 0000000..8a73a64
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/Android.bp
@@ -0,0 +1,83 @@
+// packet library for libbt-rootcanal
+// ========================================================
+cc_library_static {
+ name: "libbt-rootcanal-packets",
+ defaults: [
+ "libchrome_support_defaults",
+ "clang_file_coverage",
+ ],
+ host_supported: true,
+ proprietary: true,
+ srcs: [
+ "iterator.cc",
+ "counted_builder.cc",
+ "packet_view.cc",
+ "raw_builder.cc",
+ "view.cc",
+ "hci/acl_packet_builder.cc",
+ "hci/acl_packet_view.cc",
+ "hci/command_packet_builder.cc",
+ "hci/command_packet_view.cc",
+ "hci/event_packet_builder.cc",
+ "hci/event_payload_builder.cc",
+ "hci/hci_packet_builder.cc",
+ "hci/le_meta_event_builder.cc",
+ "hci/sco_packet_builder.cc",
+ "hci/sco_packet_view.cc",
+ "link_layer/link_layer_packet_builder.cc",
+ "link_layer/link_layer_packet_view.cc",
+ ],
+ cflags: [
+ "-fvisibility=hidden",
+ ],
+ local_include_dirs: [
+ ".",
+ ],
+ export_include_dirs: ["."],
+ include_dirs: [
+ "system/bt/vendor_libs/test_vendor_lib/include",
+ "system/bt/vendor_libs/test_vendor_lib/",
+ "system/bt/",
+ ],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ ],
+}
+
+// Unit tests for the host
+// ========================================================
+cc_test_host {
+ name: "rootcanal-packets_test_host",
+ defaults: [
+ "libchrome_support_defaults",
+ "clang_file_coverage",
+ "clang_coverage_bin",
+ ],
+ srcs: [
+ "test/link_layer_packet_builder_test.cc",
+ "test/packet_builder_test.cc",
+ "test/packet_view_test.cc",
+ "hci/test/acl_builder_test.cc",
+ "hci/test/event_builder_test.cc",
+ ],
+ header_libs: [
+ "libbluetooth_headers",
+ ],
+ local_include_dirs: [
+ ".",
+ ],
+ include_dirs: [
+ "system/bt",
+ "system/bt/hci/include",
+ "system/bt/vendor_libs/test_vendor_lib",
+ "system/bt/vendor_libs/test_vendor_lib/include",
+ ],
+ shared_libs: [
+ "liblog",
+ ],
+ static_libs: [
+ "libbt-rootcanal-types",
+ "libbt-rootcanal-packets",
+ ],
+}
diff --git a/vendor_libs/test_vendor_lib/packets/base_packet_builder.h b/vendor_libs/test_vendor_lib/packets/base_packet_builder.h
new file mode 100644
index 0000000..92ae3a9
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/base_packet_builder.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2018 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 <forward_list>
+#include <iterator>
+#include <memory>
+#include <vector>
+
+namespace test_vendor_lib {
+namespace packets {
+
+// A little-endian PacketBuilder might contain a big-endian PacketBuilder,
+// so BasePacketBuilder provides a common base class.
+class BasePacketBuilder {
+ public:
+ virtual ~BasePacketBuilder() = default;
+
+ virtual size_t size() const = 0;
+
+ // Write to the vector with the given iterator.
+ virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const = 0;
+
+ protected:
+ BasePacketBuilder() = default;
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/counted_builder.cc b/vendor_libs/test_vendor_lib/packets/counted_builder.cc
new file mode 100644
index 0000000..10d3ceb
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/counted_builder.cc
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2018 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 "counted_builder.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+namespace packets {
+
+size_t CountedBuilder::size() const {
+ size_t payload_size = sizeof(uint8_t);
+ for (size_t i = 0; i < sub_builders_.size(); i++) {
+ payload_size += sub_builders_[i]->size();
+ }
+ return payload_size;
+}
+
+void CountedBuilder::Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const {
+ insert(static_cast<uint8_t>(sub_builders_.size()), it);
+ for (size_t i = 0; i < sub_builders_.size(); i++) {
+ sub_builders_[i]->Serialize(it);
+ }
+}
+
+void CountedBuilder::Add(std::unique_ptr<BasePacketBuilder> builder) {
+ sub_builders_.push_back(std::move(builder));
+}
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/counted_builder.h b/vendor_libs/test_vendor_lib/packets/counted_builder.h
new file mode 100644
index 0000000..fed88c5
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/counted_builder.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2018 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 <forward_list>
+#include <memory>
+#include <vector>
+
+#include "packets/base_packet_builder.h"
+#include "packets/packet_builder.h"
+#include "packets/raw_builder.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+class CountedBuilder : public RawBuilder {
+ public:
+ CountedBuilder() = default;
+ virtual ~CountedBuilder() = default;
+
+ virtual size_t size() const override;
+
+ virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override;
+
+ void Add(std::unique_ptr<BasePacketBuilder> builder);
+
+ private:
+ std::vector<std::unique_ptr<BasePacketBuilder>> sub_builders_;
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/acl_packet_builder.cc b/vendor_libs/test_vendor_lib/packets/hci/acl_packet_builder.cc
new file mode 100644
index 0000000..00b0ba8
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/hci/acl_packet_builder.cc
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2018 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 "packets/hci/acl_packet_builder.h"
+
+#include <base/logging.h>
+
+using std::vector;
+using test_vendor_lib::acl::BroadcastFlagsType;
+using test_vendor_lib::acl::PacketBoundaryFlagsType;
+
+namespace test_vendor_lib {
+namespace packets {
+
+AclPacketBuilder::AclPacketBuilder(uint16_t handle, PacketBoundaryFlagsType packet_boundary_flags,
+ BroadcastFlagsType broadcast_flags, std::unique_ptr<BasePacketBuilder> payload)
+ : handle_(handle), packet_boundary_flags_(packet_boundary_flags), broadcast_flags_(broadcast_flags),
+ payload_(std::move(payload)) {}
+
+std::unique_ptr<AclPacketBuilder> AclPacketBuilder::Create(uint16_t handle,
+ PacketBoundaryFlagsType packet_boundary_flags,
+ BroadcastFlagsType broadcast_flags,
+ std::unique_ptr<BasePacketBuilder> payload) {
+ return std::unique_ptr<AclPacketBuilder>(
+ new AclPacketBuilder(handle, packet_boundary_flags, broadcast_flags, std::move(payload)));
+}
+
+size_t AclPacketBuilder::size() const {
+ return 2 * sizeof(uint16_t) + payload_->size();
+}
+
+void AclPacketBuilder::Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const {
+ insert(static_cast<uint16_t>((handle_ & 0xfff) | (static_cast<uint16_t>(packet_boundary_flags_) << 12) |
+ (static_cast<uint16_t>(broadcast_flags_) << 14)),
+ it);
+ uint16_t payload_size = payload_->size();
+
+ CHECK(static_cast<size_t>(payload_size) == payload_->size())
+ << "Payload too large for an ACL packet: " << payload_->size();
+ insert(payload_size, it);
+ payload_->Serialize(it);
+}
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/acl_packet_builder.h b/vendor_libs/test_vendor_lib/packets/hci/acl_packet_builder.h
new file mode 100644
index 0000000..cd2a607
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/hci/acl_packet_builder.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2018 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 <base/logging.h>
+#include <cstdint>
+#include <memory>
+#include <vector>
+
+#include "include/acl.h"
+#include "packets/hci/hci_packet_builder.h"
+#include "packets/packet_builder.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+// ACL data packets are specified in the Bluetooth Core Specification Version
+// 4.2, Volume 2, Part E, Section 5.4.2
+class AclPacketBuilder : public HciPacketBuilder {
+ public:
+ virtual ~AclPacketBuilder() override = default;
+
+ static std::unique_ptr<AclPacketBuilder> Create(uint16_t handle, acl::PacketBoundaryFlagsType packet_boundary_flags,
+ acl::BroadcastFlagsType broadcast_flags,
+ std::unique_ptr<BasePacketBuilder> payload);
+
+ virtual size_t size() const override;
+ virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const;
+
+ private:
+ AclPacketBuilder(uint16_t handle, acl::PacketBoundaryFlagsType packet_boundary_flags,
+ acl::BroadcastFlagsType broadcast_flags, std::unique_ptr<BasePacketBuilder> payload);
+ AclPacketBuilder() = delete;
+ uint16_t handle_;
+ acl::PacketBoundaryFlagsType packet_boundary_flags_;
+ acl::BroadcastFlagsType broadcast_flags_;
+ std::unique_ptr<BasePacketBuilder> payload_;
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/acl_packet_view.cc b/vendor_libs/test_vendor_lib/packets/hci/acl_packet_view.cc
new file mode 100644
index 0000000..bfec835
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/hci/acl_packet_view.cc
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2018 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 "packets/hci/acl_packet_view.h"
+
+#include <base/logging.h>
+
+using std::vector;
+using test_vendor_lib::acl::BroadcastFlagsType;
+using test_vendor_lib::acl::PacketBoundaryFlagsType;
+
+namespace test_vendor_lib {
+namespace packets {
+
+AclPacketView::AclPacketView(std::shared_ptr<std::vector<uint8_t>> packet) : PacketView<true>(packet) {}
+
+AclPacketView::AclPacketView(PacketView<true> packet_view) : PacketView<true>(packet_view) {}
+
+AclPacketView AclPacketView::Create(std::shared_ptr<std::vector<uint8_t>> packet) {
+ return AclPacketView(packet);
+}
+
+AclPacketView AclPacketView::Create(PacketView<true> packet_view) {
+ return AclPacketView(packet_view);
+}
+
+uint16_t AclPacketView::GetHandle() const {
+ return begin().extract<uint16_t>() & 0xfff;
+}
+
+PacketBoundaryFlagsType AclPacketView::GetPacketBoundaryFlags() const {
+ return static_cast<PacketBoundaryFlagsType>(((begin() + 1).extract<uint8_t>() & 0x30) >> 4);
+}
+
+BroadcastFlagsType AclPacketView::GetBroadcastFlags() const {
+ return static_cast<BroadcastFlagsType>(((begin() + 1).extract<uint8_t>() & 0xc0) >> 6);
+}
+
+PacketView<true> AclPacketView::GetPayload() const {
+ uint16_t payload_size = (begin() + sizeof(uint16_t)).extract<uint16_t>();
+ CHECK(static_cast<uint16_t>(size() - 2 * sizeof(uint16_t)) == payload_size)
+ << "Malformed ACL packet payload_size " << payload_size << " + 4 != " << size();
+ return SubViewLittleEndian(2 * sizeof(uint16_t), size());
+}
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/acl_packet_view.h b/vendor_libs/test_vendor_lib/packets/hci/acl_packet_view.h
new file mode 100644
index 0000000..1e69cda
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/hci/acl_packet_view.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018 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 "include/acl.h"
+#include "packets/packet_view.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+// ACL data packets are specified in the Bluetooth Core Specification Version
+// 4.2, Volume 2, Part E, Section 5.4.2
+class AclPacketView : public PacketView<true> {
+ public:
+ virtual ~AclPacketView() override = default;
+
+ static AclPacketView Create(std::shared_ptr<std::vector<uint8_t>> packet);
+ static AclPacketView Create(PacketView<true> packet_view);
+
+ uint16_t GetHandle() const;
+ acl::PacketBoundaryFlagsType GetPacketBoundaryFlags() const;
+ acl::BroadcastFlagsType GetBroadcastFlags() const;
+ PacketView<true> GetPayload() const;
+
+ private:
+ AclPacketView(std::shared_ptr<std::vector<uint8_t>> packet);
+ AclPacketView(PacketView<true> packet_view);
+ AclPacketView() = delete;
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/command_packet_builder.cc b/vendor_libs/test_vendor_lib/packets/hci/command_packet_builder.cc
new file mode 100644
index 0000000..7074309
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/hci/command_packet_builder.cc
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018 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 "packets/hci/command_packet_builder.h"
+
+#include <base/logging.h>
+
+using std::vector;
+using test_vendor_lib::hci::OpCode;
+
+namespace test_vendor_lib {
+namespace packets {
+
+CommandPacketBuilder::CommandPacketBuilder(OpCode opcode, std::unique_ptr<BasePacketBuilder> payload)
+ : opcode_(opcode), payload_(std::move(payload)) {}
+
+size_t CommandPacketBuilder::size() const {
+ return sizeof(uint16_t) + sizeof(uint8_t) + payload_->size();
+}
+
+void CommandPacketBuilder::Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const {
+ insert(static_cast<uint16_t>(opcode_), it);
+ uint8_t payload_size = static_cast<uint8_t>(payload_->size());
+
+ CHECK(static_cast<size_t>(payload_size) == payload_->size())
+ << "Payload too large for a command packet: " << payload_->size();
+ insert(payload_size, it);
+ payload_->Serialize(it);
+}
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/command_packet_builder.h b/vendor_libs/test_vendor_lib/packets/hci/command_packet_builder.h
new file mode 100644
index 0000000..d8e86a0
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/hci/command_packet_builder.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2018 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 <base/logging.h>
+#include <cstdint>
+#include <memory>
+#include <vector>
+
+#include "include/hci.h"
+#include "packets/hci/hci_packet_builder.h"
+#include "packets/packet_builder.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+// ACL data packets are specified in the Bluetooth Core Specification Version
+// 4.2, Volume 2, Part E, Section 5.4.2
+class CommandPacketBuilder : public HciPacketBuilder {
+ public:
+ virtual ~CommandPacketBuilder() override = default;
+
+ static std::unique_ptr<CommandPacketBuilder> Create(hci::OpCode opcode, std::unique_ptr<BasePacketBuilder> payload);
+
+ virtual size_t size() const override;
+
+ virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const;
+
+ private:
+ CommandPacketBuilder(hci::OpCode opcode, std::unique_ptr<BasePacketBuilder> payload);
+ CommandPacketBuilder() = delete;
+ hci::OpCode opcode_;
+ std::unique_ptr<BasePacketBuilder> payload_;
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/command_packet_view.cc b/vendor_libs/test_vendor_lib/packets/hci/command_packet_view.cc
new file mode 100644
index 0000000..f0876c1
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/hci/command_packet_view.cc
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2018 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 "packets/hci/command_packet_view.h"
+
+#include <base/logging.h>
+
+using std::vector;
+
+namespace test_vendor_lib {
+namespace packets {
+
+CommandPacketView::CommandPacketView(std::shared_ptr<std::vector<uint8_t>> packet) : PacketView<true>(packet) {}
+
+CommandPacketView CommandPacketView::Create(std::shared_ptr<std::vector<uint8_t>> packet) {
+ return CommandPacketView(packet);
+}
+
+uint16_t CommandPacketView::GetOpcode() const {
+ return begin().extract<uint16_t>();
+}
+
+PacketView<true> CommandPacketView::GetPayload() const {
+ uint8_t payload_size = (begin() + sizeof(uint16_t)).extract<uint8_t>();
+ CHECK(static_cast<uint8_t>(size() - sizeof(uint16_t) - sizeof(uint8_t)) == payload_size)
+ << "Malformed Command packet payload_size " << payload_size << " + 2 != " << size();
+ return SubViewLittleEndian(sizeof(uint16_t) + sizeof(uint8_t), size());
+}
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/command_packet_view.h b/vendor_libs/test_vendor_lib/packets/hci/command_packet_view.h
new file mode 100644
index 0000000..6355c1e
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/hci/command_packet_view.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2018 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 "packets/packet_view.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+// Command packets are specified in the Bluetooth Core Specification Version
+// 4.2, Volume 2, Part E, Section 5.4.1
+class CommandPacketView : public PacketView<true> {
+ public:
+ virtual ~CommandPacketView() override = default;
+
+ static CommandPacketView Create(std::shared_ptr<std::vector<uint8_t>> packet);
+
+ uint16_t GetOpcode() const;
+
+ PacketView<true> GetPayload() const;
+
+ private:
+ CommandPacketView(std::shared_ptr<std::vector<uint8_t>> packet);
+ CommandPacketView() = delete;
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/event_packet_builder.cc b/vendor_libs/test_vendor_lib/packets/hci/event_packet_builder.cc
new file mode 100644
index 0000000..8d095a7
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/hci/event_packet_builder.cc
@@ -0,0 +1,811 @@
+/*
+ * Copyright 2018 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 "packets/hci/event_packet_builder.h"
+
+#include <base/logging.h>
+#include "hci.h"
+#include "packets/hci/le_meta_event_builder.h"
+
+using std::vector;
+using test_vendor_lib::hci::EventCode;
+using test_vendor_lib::hci::OpCode;
+using test_vendor_lib::hci::Status;
+
+namespace test_vendor_lib {
+namespace packets {
+
+EventPacketBuilder::EventPacketBuilder(EventCode event_code)
+ : event_code_(event_code), payload_(std::make_unique<RawBuilder>()) {}
+
+EventPacketBuilder::EventPacketBuilder(EventCode event_code, std::unique_ptr<RawBuilder> payload)
+ : event_code_(event_code), payload_(std::move(payload)) {}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.1
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateInquiryCompleteEvent(hci::Status status) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::INQUIRY_COMPLETE));
+ CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.14
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteEvent(
+ hci::OpCode command_opcode, const vector<uint8_t>& event_return_parameters) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::COMMAND_COMPLETE));
+
+ CHECK(evt_ptr->AddPayloadOctets1(1)); // num_hci_command_packets
+ CHECK(evt_ptr->AddPayloadOctets2(static_cast<uint16_t>(command_opcode)));
+ CHECK(evt_ptr->AddPayloadOctets(event_return_parameters));
+
+ return evt_ptr;
+}
+
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(hci::OpCode command_opcode,
+ hci::Status status) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::COMMAND_COMPLETE));
+
+ CHECK(evt_ptr->AddPayloadOctets1(1)); // num_hci_command_packets
+ CHECK(evt_ptr->AddPayloadOctets2(static_cast<uint16_t>(command_opcode)));
+ CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
+
+ return evt_ptr;
+}
+
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteStatusAndAddressEvent(
+ hci::OpCode command_opcode, hci::Status status, const Address& address) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::COMMAND_COMPLETE));
+
+ CHECK(evt_ptr->AddPayloadOctets1(1)); // num_hci_command_packets
+ CHECK(evt_ptr->AddPayloadOctets2(static_cast<uint16_t>(command_opcode)));
+ CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
+ CHECK(evt_ptr->AddPayloadAddress(address));
+
+ return evt_ptr;
+}
+
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteUnknownOpCodeEvent(
+ uint16_t command_opcode) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::COMMAND_COMPLETE));
+
+ CHECK(evt_ptr->AddPayloadOctets1(1)); // num_hci_command_packets
+ CHECK(evt_ptr->AddPayloadOctets2(static_cast<uint16_t>(command_opcode)));
+ CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(Status::UNKNOWN_COMMAND)));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.15
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandStatusEvent(hci::Status status,
+ hci::OpCode command_opcode) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::COMMAND_STATUS));
+
+ CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
+ CHECK(evt_ptr->AddPayloadOctets1(1)); // num_hci_command_packets
+ CHECK(evt_ptr->AddPayloadOctets2(static_cast<uint16_t>(command_opcode)));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.19
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateNumberOfCompletedPacketsEvent(
+ uint16_t handle, uint16_t num_completed_packets) {
+ std::unique_ptr<RawBuilder> payload = std::make_unique<CountedBuilder>();
+ std::unique_ptr<EventPacketBuilder> evt_ptr = std::unique_ptr<EventPacketBuilder>(
+ new EventPacketBuilder(EventCode::NUMBER_OF_COMPLETED_PACKETS, std::move(payload)));
+
+ evt_ptr->AddCompletedPackets(handle, num_completed_packets);
+
+ return evt_ptr;
+}
+
+void EventPacketBuilder::AddCompletedPackets(uint16_t handle, uint16_t num_completed_packets) {
+ CHECK(event_code_ == EventCode::NUMBER_OF_COMPLETED_PACKETS);
+
+ std::unique_ptr<RawBuilder> handle_pair = std::make_unique<RawBuilder>();
+ CHECK(handle_pair->AddOctets2(handle));
+ CHECK(handle_pair->AddOctets2(num_completed_packets));
+ AddBuilder(std::move(handle_pair));
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.10
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteDeleteStoredLinkKey(
+ hci::Status status, uint16_t num_keys_deleted) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::DELETE_STORED_LINK_KEY, status);
+
+ CHECK(evt_ptr->AddPayloadOctets2(num_keys_deleted));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.12
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteReadLocalName(
+ hci::Status status, const std::vector<uint8_t>& local_name) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::READ_LOCAL_NAME, status);
+
+ size_t len = local_name.size();
+ if (len > 247) {
+ len = 247;
+ }
+ CHECK(evt_ptr->AddPayloadOctets(len, local_name));
+ CHECK(evt_ptr->AddPayloadOctets1(0)); // Null terminated
+ for (size_t i = 0; i < 248 - len - 1; i++) CHECK(evt_ptr->AddPayloadOctets1(0xFF));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.23
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteReadAuthenticationEnable(
+ hci::Status status, uint8_t enable) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::READ_LOCAL_NAME, status);
+ CHECK(evt_ptr->AddPayloadOctets1(enable));
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.1
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteReadLocalVersionInformation(
+ hci::Status status, uint8_t hci_version, uint16_t hci_revision, uint8_t lmp_pal_version, uint16_t manufacturer_name,
+ uint16_t lmp_pal_subversion) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::READ_LOCAL_VERSION_INFORMATION, status);
+
+ CHECK(evt_ptr->AddPayloadOctets1(hci_version));
+ CHECK(evt_ptr->AddPayloadOctets2(hci_revision));
+ CHECK(evt_ptr->AddPayloadOctets1(lmp_pal_version));
+ CHECK(evt_ptr->AddPayloadOctets2(manufacturer_name));
+ CHECK(evt_ptr->AddPayloadOctets2(lmp_pal_subversion));
+
+ return evt_ptr;
+}
+
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateReadRemoteVersionInformationEvent(
+ hci::Status status, uint16_t connection_handle, uint8_t lmp_pal_version, uint16_t manufacturer_name,
+ uint16_t lmp_pal_subversion) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::READ_REMOTE_VERSION_INFORMATION_COMPLETE));
+
+ CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
+ CHECK(evt_ptr->AddPayloadOctets2(connection_handle));
+ CHECK(evt_ptr->AddPayloadOctets1(lmp_pal_version));
+ CHECK(evt_ptr->AddPayloadOctets2(manufacturer_name));
+ CHECK(evt_ptr->AddPayloadOctets2(lmp_pal_subversion));
+
+ return evt_ptr;
+}
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.2
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteReadLocalSupportedCommands(
+ hci::Status status, const vector<uint8_t>& supported_commands) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::READ_LOCAL_SUPPORTED_COMMANDS, status);
+
+ CHECK(evt_ptr->AddPayloadOctets(64, supported_commands));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.4
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteReadLocalExtendedFeatures(
+ hci::Status status, uint8_t page_number, uint8_t maximum_page_number, uint64_t extended_lmp_features) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::READ_LOCAL_EXTENDED_FEATURES, status);
+
+ CHECK(evt_ptr->AddPayloadOctets1(page_number));
+ CHECK(evt_ptr->AddPayloadOctets1(maximum_page_number));
+ CHECK(evt_ptr->AddPayloadOctets8(extended_lmp_features));
+
+ return evt_ptr;
+}
+
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateReadRemoteExtendedFeaturesEvent(
+ hci::Status status, uint16_t handle, uint8_t page_number, uint8_t maximum_page_number,
+ uint64_t extended_lmp_features) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::READ_REMOTE_EXTENDED_FEATURES_COMPLETE));
+
+ CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
+ CHECK(evt_ptr->AddPayloadOctets2(handle));
+ CHECK(evt_ptr->AddPayloadOctets1(page_number));
+ CHECK(evt_ptr->AddPayloadOctets1(maximum_page_number));
+ CHECK(evt_ptr->AddPayloadOctets8(extended_lmp_features));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.5
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteReadBufferSize(
+ hci::Status status, uint16_t hc_acl_data_packet_length, uint8_t hc_synchronous_data_packet_length,
+ uint16_t hc_total_num_acl_data_packets, uint16_t hc_total_synchronous_data_packets) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::READ_BUFFER_SIZE, status);
+
+ CHECK(evt_ptr->AddPayloadOctets2(hc_acl_data_packet_length));
+ CHECK(evt_ptr->AddPayloadOctets1(hc_synchronous_data_packet_length));
+ CHECK(evt_ptr->AddPayloadOctets2(hc_total_num_acl_data_packets));
+ CHECK(evt_ptr->AddPayloadOctets2(hc_total_synchronous_data_packets));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.6
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteReadBdAddr(hci::Status status,
+ const Address& address) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::READ_BD_ADDR, status);
+
+ CHECK(evt_ptr->AddPayloadAddress(address));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.8
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteReadLocalSupportedCodecs(
+ hci::Status status, const vector<uint8_t>& supported_codecs, const vector<uint32_t>& vendor_specific_codecs) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::READ_LOCAL_SUPPORTED_CODECS, status);
+
+ CHECK(evt_ptr->AddPayloadOctets1(supported_codecs.size()));
+ CHECK(evt_ptr->AddPayloadOctets(supported_codecs));
+ CHECK(evt_ptr->AddPayloadOctets1(vendor_specific_codecs.size()));
+ for (size_t i = 0; i < vendor_specific_codecs.size(); i++)
+ CHECK(evt_ptr->AddPayloadOctets4(vendor_specific_codecs[i]));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.6.1
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteReadLoopbackMode(hci::Status status,
+ hci::LoopbackMode mode) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::READ_LOOPBACK_MODE, status);
+ CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(mode)));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.2
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateInquiryResultEvent() {
+ std::unique_ptr<RawBuilder> payload = std::unique_ptr<RawBuilder>(new CountedBuilder());
+ std::unique_ptr<EventPacketBuilder> evt_ptr(new EventPacketBuilder(EventCode::INQUIRY_RESULT, std::move(payload)));
+
+ return evt_ptr;
+}
+
+bool EventPacketBuilder::AddInquiryResult(const Address& address, uint8_t page_scan_repetition_mode,
+ ClassOfDevice class_of_device, uint16_t clock_offset) {
+ CHECK(event_code_ == EventCode::INQUIRY_RESULT);
+
+ if (!CanAddPayloadOctets(14)) return false;
+
+ std::unique_ptr<RawBuilder> result = std::make_unique<RawBuilder>();
+
+ CHECK(result->AddAddress(address));
+ CHECK(result->AddOctets1(page_scan_repetition_mode));
+ CHECK(result->AddOctets2(0)); // Reserved
+ CHECK(result->AddOctets1(class_of_device.cod[0]));
+ CHECK(result->AddOctets1(class_of_device.cod[1]));
+ CHECK(result->AddOctets1(class_of_device.cod[2]));
+ CHECK(!(clock_offset & 0x8000));
+ CHECK(result->AddOctets2(clock_offset));
+ AddBuilder(std::move(result));
+ return true;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.3
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateConnectionCompleteEvent(
+ hci::Status status, uint16_t handle, const Address& address, hci::LinkType link_type, bool encryption_enabled) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::CONNECTION_COMPLETE));
+
+ CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
+ CHECK((handle & 0xf000) == 0); // Handles are 12-bit values.
+ CHECK(evt_ptr->AddPayloadOctets2(handle));
+ CHECK(evt_ptr->AddPayloadAddress(address));
+ CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(link_type)));
+ CHECK(evt_ptr->AddPayloadOctets1(encryption_enabled ? 1 : 0));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.4
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateConnectionRequestEvent(const Address& address,
+ ClassOfDevice class_of_device,
+ hci::LinkType link_type) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::CONNECTION_REQUEST));
+
+ CHECK(evt_ptr->AddPayloadAddress(address));
+ CHECK(evt_ptr->AddPayloadOctets1(class_of_device.cod[0]));
+ CHECK(evt_ptr->AddPayloadOctets1(class_of_device.cod[1]));
+ CHECK(evt_ptr->AddPayloadOctets1(class_of_device.cod[2]));
+ CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(link_type)));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.5
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateDisconnectionCompleteEvent(hci::Status status,
+ uint16_t handle,
+ uint8_t reason) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::DISCONNECTION_COMPLETE));
+
+ CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
+ CHECK((handle & 0xf000) == 0); // Handles are 12-bit values.
+ CHECK(evt_ptr->AddPayloadOctets2(handle));
+ CHECK(evt_ptr->AddPayloadOctets1(reason));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.6
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateAuthenticationCompleteEvent(hci::Status status,
+ uint16_t handle) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::AUTHENTICATION_COMPLETE));
+ CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
+ CHECK((handle & 0xf000) == 0); // Handles are 12-bit values.
+ CHECK(evt_ptr->AddPayloadOctets2(handle));
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.7
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateRemoteNameRequestCompleteEvent(
+ hci::Status status, const Address& address, const std::string& remote_name) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::REMOTE_NAME_REQUEST_COMPLETE));
+
+ CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
+ CHECK(evt_ptr->AddPayloadAddress(address));
+ for (size_t i = 0; i < remote_name.length(); i++) CHECK(evt_ptr->AddPayloadOctets1(remote_name[i]));
+ CHECK(evt_ptr->AddPayloadOctets1(0)); // Null terminated
+ for (size_t i = 0; i < 248 - remote_name.length() - 1; i++) CHECK(evt_ptr->AddPayloadOctets1(0xFF));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.23
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateLinkKeyRequestEvent(const Address& remote) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::LINK_KEY_REQUEST));
+ CHECK(evt_ptr->AddPayloadAddress(remote));
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.24
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateLinkKeyNotificationEvent(const Address& remote,
+ const std::vector<uint8_t>& key,
+ uint8_t key_type) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::LINK_KEY_NOTIFICATION));
+ CHECK(evt_ptr->AddPayloadAddress(remote));
+ CHECK(key.size() == 16);
+ CHECK(evt_ptr->AddPayloadOctets(key));
+ CHECK(evt_ptr->AddPayloadOctets1(key_type));
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.25
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateLoopbackCommandEvent(hci::OpCode opcode,
+ PacketView<true> payload) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::LOOPBACK_COMMAND));
+ CHECK(evt_ptr->AddPayloadOctets2(static_cast<uint16_t>(opcode)));
+ CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(payload.size())));
+ for (const auto& payload_byte : payload) // Fill the packet.
+ evt_ptr->AddPayloadOctets1(payload_byte);
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.28
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateReadClockOffsetEvent(hci::Status status, uint16_t handle,
+ uint16_t offset) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::READ_CLOCK_OFFSET_COMPLETE));
+ CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
+ CHECK(evt_ptr->AddPayloadOctets2(handle));
+ CHECK(evt_ptr->AddPayloadOctets2(offset));
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.29
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateConnectionPacketTypeChangedEvent(hci::Status status,
+ uint16_t handle,
+ uint16_t packet_type) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::CONNECTION_PACKET_TYPE_CHANGE));
+ CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
+ CHECK(evt_ptr->AddPayloadOctets2(handle));
+ CHECK(evt_ptr->AddPayloadOctets2(packet_type));
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.37
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateSniffSubratingEvent(const hci::Status status,
+ uint16_t handle) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::SNIFF_SUBRATING, status);
+
+ CHECK(evt_ptr->AddPayloadOctets2(handle));
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.38
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateExtendedInquiryResultEvent(
+ const Address& address, uint8_t page_scan_repetition_mode, ClassOfDevice class_of_device, uint16_t clock_offset,
+ uint8_t rssi, const vector<uint8_t>& extended_inquiry_response) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::EXTENDED_INQUIRY_RESULT));
+
+ CHECK(evt_ptr->AddPayloadOctets1(1)); // Always contains a single response
+
+ CHECK(evt_ptr->AddPayloadAddress(address));
+ CHECK(evt_ptr->AddPayloadOctets1(page_scan_repetition_mode));
+ CHECK(evt_ptr->AddPayloadOctets1(0)); // Reserved
+ CHECK(evt_ptr->AddPayloadOctets1(class_of_device.cod[0]));
+ CHECK(evt_ptr->AddPayloadOctets1(class_of_device.cod[1]));
+ CHECK(evt_ptr->AddPayloadOctets1(class_of_device.cod[2]));
+ CHECK(!(clock_offset & 0x8000));
+ CHECK(evt_ptr->AddPayloadOctets2(clock_offset));
+ CHECK(evt_ptr->AddPayloadOctets1(rssi));
+ CHECK(evt_ptr->AddPayloadOctets(extended_inquiry_response));
+ evt_ptr->AddPayloadOctets1(0x00); // End marker
+ while (evt_ptr->AddPayloadOctets1(0x00))
+ ; // Fill packet
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.40
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateIoCapabilityRequestEvent(const Address& peer) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::IO_CAPABILITY_REQUEST));
+
+ CHECK(evt_ptr->AddPayloadAddress(peer));
+ return evt_ptr;
+} // namespace packets
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.41
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateIoCapabilityResponseEvent(
+ const Address& peer, uint8_t io_capability, bool oob_data_present, uint8_t authentication_requirements) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::IO_CAPABILITY_RESPONSE));
+
+ CHECK(evt_ptr->AddPayloadAddress(peer));
+ CHECK(evt_ptr->AddPayloadOctets1(io_capability));
+ CHECK(evt_ptr->AddPayloadOctets1(oob_data_present));
+ CHECK(evt_ptr->AddPayloadOctets1(authentication_requirements));
+ return evt_ptr;
+} // namespace test_vendor_lib
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.42
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateUserConfirmationRequestEvent(const Address& peer,
+ uint32_t numeric_value) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::USER_CONFIRMATION_REQUEST));
+
+ CHECK(evt_ptr->AddPayloadAddress(peer));
+ CHECK(evt_ptr->AddPayloadOctets4(numeric_value));
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.43
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateUserPasskeyRequestEvent(const Address& peer) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::USER_PASSKEY_REQUEST));
+
+ CHECK(evt_ptr->AddPayloadAddress(peer));
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.44
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateRemoteOobDataRequestEvent(const Address& peer) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::REMOTE_OOB_DATA_REQUEST));
+
+ CHECK(evt_ptr->AddPayloadAddress(peer));
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.45
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateSimplePairingCompleteEvent(hci::Status status,
+ const Address& peer) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::SIMPLE_PAIRING_COMPLETE));
+
+ CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
+ CHECK(evt_ptr->AddPayloadAddress(peer));
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.48
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateUserPasskeyNotificationEvent(const Address& peer,
+ uint32_t passkey) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::USER_PASSKEY_NOTIFICATION));
+
+ CHECK(evt_ptr->AddPayloadAddress(peer));
+ CHECK(evt_ptr->AddPayloadOctets4(passkey));
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.49
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateKeypressNotificationEvent(const Address& peer,
+ uint8_t notification_type) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::KEYPRESS_NOTIFICATION));
+
+ CHECK(evt_ptr->AddPayloadAddress(peer));
+ CHECK(evt_ptr->AddPayloadOctets1(notification_type));
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.65.1
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateLeConnectionCompleteEvent(
+ hci::Status status, uint16_t handle, uint8_t role, uint8_t peer_address_type, const Address& peer,
+ uint16_t interval, uint16_t latency, uint16_t supervision_timeout) {
+ std::unique_ptr<RawBuilder> meta_evt = LeMetaEventBuilder::CreateLeConnectionCompleteEvent(
+ status, handle, role, peer_address_type, peer, interval, latency, supervision_timeout);
+
+ return std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::LE_META_EVENT, std::move(meta_evt)));
+}
+
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateLeEnhancedConnectionCompleteEvent(
+ hci::Status status, uint16_t handle, uint8_t role, uint8_t peer_address_type, const Address& peer,
+ const Address& local_private_address, const Address& peer_private_address, uint16_t interval, uint16_t latency,
+ uint16_t supervision_timeout) {
+ std::unique_ptr<RawBuilder> meta_evt = LeMetaEventBuilder::CreateLeEnhancedConnectionCompleteEvent(
+ status, handle, role, peer_address_type, peer, local_private_address, peer_private_address, interval, latency,
+ supervision_timeout);
+
+ return std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::LE_META_EVENT, std::move(meta_evt)));
+}
+
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateLeConnectionUpdateCompleteEvent(
+ hci::Status status, uint16_t handle, uint16_t interval, uint16_t latency, uint16_t supervision_timeout) {
+ std::unique_ptr<RawBuilder> meta_evt =
+ LeMetaEventBuilder::CreateLeConnectionUpdateCompleteEvent(status, handle, interval, latency, supervision_timeout);
+
+ return std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::LE_META_EVENT, std::move(meta_evt)));
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.65.2
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateLeAdvertisingReportEvent() {
+ std::unique_ptr<RawBuilder> meta_evt = LeMetaEventBuilder::CreateLeAdvertisingReportEvent();
+
+ return std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::LE_META_EVENT, std::move(meta_evt)));
+}
+
+bool EventPacketBuilder::AddLeAdvertisingReport(LeAdvertisement::AdvertisementType event_type,
+ LeAdvertisement::AddressType addr_type, const Address& addr,
+ const vector<uint8_t>& data, uint8_t rssi) {
+ CHECK(event_code_ == EventCode::LE_META_EVENT);
+
+ // Upcast the payload to add the next report.
+ LeMetaEventBuilder* meta_ptr = static_cast<LeMetaEventBuilder*>(payload_.get());
+ return meta_ptr->AddLeAdvertisingReport(event_type, addr_type, addr, data, rssi);
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.65.4
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateLeRemoteUsedFeaturesEvent(hci::Status status,
+ uint16_t handle,
+ uint64_t features) {
+ std::unique_ptr<RawBuilder> meta_evt = LeMetaEventBuilder::CreateLeRemoteUsedFeaturesEvent(status, handle, features);
+ return std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::LE_META_EVENT, std::move(meta_evt)));
+}
+
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateRemoteSupportedFeaturesEvent(hci::Status status,
+ uint16_t handle,
+ uint64_t features) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::READ_REMOTE_SUPPORTED_FEATURES_COMPLETE));
+
+ CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
+ CHECK(evt_ptr->AddPayloadOctets2(handle));
+ CHECK(evt_ptr->AddPayloadOctets8(features));
+
+ return evt_ptr;
+}
+
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteLinkKeyRequestReply(hci::Status status,
+ Address address) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::LINK_KEY_REQUEST_REPLY, status);
+
+ CHECK(evt_ptr->AddPayloadAddress(address));
+
+ return evt_ptr;
+}
+
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteLinkKeyRequestNegativeReply(
+ hci::Status status, Address address) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::LINK_KEY_REQUEST_NEGATIVE_REPLY, status);
+
+ CHECK(evt_ptr->AddPayloadAddress(address));
+
+ return evt_ptr;
+}
+
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteWriteLinkPolicySettings(hci::Status status,
+ uint16_t handle) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::WRITE_LINK_POLICY_SETTINGS, status);
+
+ CHECK(evt_ptr->AddPayloadOctets2(handle));
+
+ return evt_ptr;
+}
+
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteWriteLinkSupervisionTimeout(
+ hci::Status status, uint16_t handle) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::WRITE_LINK_SUPERVISION_TIMEOUT, status);
+
+ CHECK(evt_ptr->AddPayloadOctets2(handle));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.2
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteLeReadBufferSize(
+ hci::Status status, uint16_t hc_le_data_packet_length, uint8_t hc_total_num_le_data_packets) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::LE_READ_BUFFER_SIZE, status);
+
+ CHECK(evt_ptr->AddPayloadOctets2(hc_le_data_packet_length));
+ CHECK(evt_ptr->AddPayloadOctets1(hc_total_num_le_data_packets));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.3
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteLeReadLocalSupportedFeatures(
+ hci::Status status, uint64_t le_features) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::LE_READ_LOCAL_SUPPORTED_FEATURES, status);
+
+ CHECK(evt_ptr->AddPayloadOctets8(le_features));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.14
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteLeReadWhiteListSize(
+ hci::Status status, uint8_t white_list_size) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::LE_READ_WHITE_LIST_SIZE, status);
+
+ CHECK(evt_ptr->AddPayloadOctets8(white_list_size));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.23
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteLeRand(hci::Status status,
+ uint64_t random_val) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::LE_RAND, status);
+
+ CHECK(evt_ptr->AddPayloadOctets8(random_val));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.27
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteLeReadSupportedStates(hci::Status status,
+ uint64_t le_states) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::LE_READ_SUPPORTED_STATES, status);
+
+ CHECK(evt_ptr->AddPayloadOctets8(le_states));
+
+ return evt_ptr;
+}
+
+// Vendor-specific commands
+
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteLeGetVendorCapabilities(
+ hci::Status status, const vector<uint8_t>& vendor_cap) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::LE_GET_VENDOR_CAPABILITIES, status);
+
+ CHECK(evt_ptr->AddPayloadOctets(vendor_cap));
+
+ return evt_ptr;
+}
+
+std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateEncryptionChange(hci::Status status, uint16_t handle,
+ uint8_t encryption_enable) {
+ std::unique_ptr<EventPacketBuilder> evt_ptr =
+ std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::ENCRYPTION_CHANGE));
+
+ CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
+ CHECK(evt_ptr->AddPayloadOctets2(handle));
+ CHECK(evt_ptr->AddPayloadOctets1(encryption_enable));
+
+ return evt_ptr;
+}
+
+size_t EventPacketBuilder::size() const {
+ size_t header_size = 2; // Event code and payload size
+ return header_size + payload_->size();
+}
+
+void EventPacketBuilder::Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const {
+ insert(static_cast<uint8_t>(event_code_), it);
+ uint8_t payload_size = size() - 2; // Event code and payload size
+ CHECK(size() - 2 == static_cast<size_t>(payload_size)) << "Payload too large for an event: " << size();
+ insert(payload_size, it);
+ payload_->Serialize(it);
+}
+
+bool EventPacketBuilder::CanAddPayloadOctets(size_t octets) {
+ return payload_->CanAddOctets(octets);
+}
+
+bool EventPacketBuilder::AddPayloadOctets(size_t octets, const std::vector<uint8_t>& bytes) {
+ return payload_->AddOctets(octets, bytes);
+}
+
+bool EventPacketBuilder::AddPayloadOctets(const std::vector<uint8_t>& bytes) {
+ return payload_->AddOctets(bytes);
+}
+
+bool EventPacketBuilder::AddPayloadOctets1(uint8_t value) {
+ return payload_->AddOctets1(value);
+}
+
+bool EventPacketBuilder::AddPayloadOctets2(uint16_t value) {
+ return payload_->AddOctets2(value);
+}
+
+bool EventPacketBuilder::AddPayloadOctets3(uint32_t value) {
+ return payload_->AddOctets3(value);
+}
+
+bool EventPacketBuilder::AddPayloadOctets4(uint32_t value) {
+ return payload_->AddOctets4(value);
+}
+
+bool EventPacketBuilder::AddPayloadOctets6(uint64_t value) {
+ return payload_->AddOctets6(value);
+}
+
+bool EventPacketBuilder::AddPayloadOctets8(uint64_t value) {
+ return payload_->AddOctets8(value);
+}
+
+bool EventPacketBuilder::AddPayloadAddress(Address address) {
+ return payload_->AddAddress(address);
+}
+
+bool EventPacketBuilder::AddBuilder(std::unique_ptr<BasePacketBuilder> builder) {
+ // Upcast the payload to add the next builder.
+ CountedBuilder* temp_ptr = static_cast<CountedBuilder*>(payload_.get());
+ temp_ptr->Add(std::move(builder));
+ return true;
+}
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/event_packet_builder.h b/vendor_libs/test_vendor_lib/packets/hci/event_packet_builder.h
new file mode 100644
index 0000000..495e47a
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/hci/event_packet_builder.h
@@ -0,0 +1,328 @@
+/*
+ * Copyright 2018 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 <base/logging.h>
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "include/hci.h"
+#include "include/le_advertisement.h"
+#include "packets/counted_builder.h"
+#include "packets/hci/hci_packet_builder.h"
+#include "packets/packet_builder.h"
+#include "packets/packet_view.h"
+#include "packets/raw_builder.h"
+#include "types/address.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+// Event Packets are 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
+// - Parameter Total Length: 1 octet
+class EventPacketBuilder : public HciPacketBuilder {
+ public:
+ virtual ~EventPacketBuilder() override = default;
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.1
+ static std::unique_ptr<EventPacketBuilder> CreateInquiryCompleteEvent(hci::Status status);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.14
+ // This should only be used for testing to send non-standard packets
+ // Most code should use the more specific functions that follow
+ static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteEvent(
+ hci::OpCode command_opcode, const std::vector<uint8_t>& event_return_parameters);
+
+ static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteOnlyStatusEvent(hci::OpCode command_opcode,
+ hci::Status status);
+
+ static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteStatusAndAddressEvent(hci::OpCode command_opcode,
+ hci::Status status,
+ const Address& address);
+
+ static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteUnknownOpCodeEvent(uint16_t command_opcode);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.15
+ static std::unique_ptr<EventPacketBuilder> CreateCommandStatusEvent(hci::Status status, hci::OpCode command_opcode);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.19
+ static std::unique_ptr<EventPacketBuilder> CreateNumberOfCompletedPacketsEvent(uint16_t handle,
+ uint16_t num_completed_packets);
+
+ void AddCompletedPackets(uint16_t handle, uint16_t num_completed_packets);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.1.10
+ static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteLinkKeyRequestReply(hci::Status status,
+ Address address);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.1.11
+ static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteLinkKeyRequestNegativeReply(hci::Status status,
+ Address address);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.2.10
+ static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteWriteLinkPolicySettings(hci::Status status,
+ uint16_t handle);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.10
+ static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteDeleteStoredLinkKey(hci::Status status,
+ uint16_t num_keys_deleted);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.12
+ static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteReadLocalName(hci::Status status,
+ const std::vector<uint8_t>& local_name);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.23
+ static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteReadAuthenticationEnable(hci::Status status,
+ uint8_t enable);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.42
+ static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteWriteLinkSupervisionTimeout(hci::Status status,
+ uint16_t handle);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.1
+ static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteReadLocalVersionInformation(
+ hci::Status status, uint8_t hci_version, uint16_t hci_revision, uint8_t lmp_pal_version,
+ uint16_t manufacturer_name, uint16_t lmp_pal_subversion);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.2
+ static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteReadLocalSupportedCommands(
+ hci::Status status, const std::vector<uint8_t>& supported_commands);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.4
+ static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteReadLocalExtendedFeatures(
+ hci::Status status, uint8_t page_number, uint8_t maximum_page_number, uint64_t extended_lmp_features);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.5
+ static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteReadBufferSize(
+ hci::Status status, uint16_t hc_acl_data_packet_length, uint8_t hc_synchronous_data_packet_length,
+ uint16_t hc_total_num_acl_data_packets, uint16_t hc_total_synchronous_data_packets);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.6
+ static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteReadBdAddr(hci::Status status,
+ const Address& bt_address);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.8
+ static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteReadLocalSupportedCodecs(
+ hci::Status status, const std::vector<uint8_t>& supported_codecs,
+ const std::vector<uint32_t>& vendor_specific_codecs);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.6.1
+ static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteReadLoopbackMode(hci::Status status,
+ hci::LoopbackMode mode);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.2
+ static std::unique_ptr<EventPacketBuilder> CreateInquiryResultEvent();
+
+ // Returns true if the result can be added to the event packet.
+ bool AddInquiryResult(const Address& bt_address, uint8_t page_scan_repetition_mode, ClassOfDevice class_of_device,
+ uint16_t clock_offset);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.3
+ static std::unique_ptr<EventPacketBuilder> CreateConnectionCompleteEvent(hci::Status status, uint16_t handle,
+ const Address& address,
+ hci::LinkType link_type,
+ bool encryption_enabled);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.4
+ static std::unique_ptr<EventPacketBuilder> CreateConnectionRequestEvent(const Address& address,
+ ClassOfDevice class_of_device,
+ hci::LinkType link_type);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.5
+ static std::unique_ptr<EventPacketBuilder> CreateDisconnectionCompleteEvent(hci::Status status, uint16_t handle,
+ uint8_t reason);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.6
+ static std::unique_ptr<EventPacketBuilder> CreateAuthenticationCompleteEvent(hci::Status status, uint16_t handle);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.7
+ static std::unique_ptr<EventPacketBuilder> CreateRemoteNameRequestCompleteEvent(hci::Status status,
+ const Address& bt_address,
+ const std::string& name);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.11
+ static std::unique_ptr<EventPacketBuilder> CreateRemoteSupportedFeaturesEvent(hci::Status status, uint16_t handle,
+ uint64_t features);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.12
+ static std::unique_ptr<EventPacketBuilder> CreateReadRemoteVersionInformationEvent(hci::Status status,
+ uint16_t connection_handle,
+ uint8_t lmp_pal_version,
+ uint16_t manufacturer_name,
+ uint16_t lmp_pal_subversion);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.23
+ static std::unique_ptr<EventPacketBuilder> CreateLinkKeyRequestEvent(const Address& remote);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.24
+ static std::unique_ptr<EventPacketBuilder> CreateLinkKeyNotificationEvent(const Address& remote,
+ const std::vector<uint8_t>& key,
+ uint8_t key_type);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.25
+ static std::unique_ptr<EventPacketBuilder> CreateLoopbackCommandEvent(hci::OpCode opcode, PacketView<true> payload);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.28
+ static std::unique_ptr<EventPacketBuilder> CreateReadClockOffsetEvent(hci::Status status, uint16_t handle,
+ uint16_t packet_type);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.29
+ static std::unique_ptr<EventPacketBuilder> CreateConnectionPacketTypeChangedEvent(hci::Status status, uint16_t handle,
+ uint16_t offset);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.34
+ static std::unique_ptr<EventPacketBuilder> CreateReadRemoteExtendedFeaturesEvent(hci::Status status, uint16_t handle,
+ uint8_t page_number,
+ uint8_t maximum_page_number,
+ uint64_t extended_lmp_features);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.37
+ static std::unique_ptr<EventPacketBuilder> CreateSniffSubratingEvent(hci::Status status, uint16_t handle);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.38
+ static std::unique_ptr<EventPacketBuilder> CreateExtendedInquiryResultEvent(
+ const Address& bt_address, uint8_t page_scan_repetition_mode, ClassOfDevice class_of_device,
+ uint16_t clock_offset, uint8_t rssi, const std::vector<uint8_t>& extended_inquiry_response);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.40
+ static std::unique_ptr<EventPacketBuilder> CreateIoCapabilityRequestEvent(const Address& peer);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.41
+ static std::unique_ptr<EventPacketBuilder> CreateIoCapabilityResponseEvent(const Address& peer, uint8_t io_capability,
+ bool oob_data_present,
+ uint8_t authentication_requirements);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.42
+ static std::unique_ptr<EventPacketBuilder> CreateUserConfirmationRequestEvent(const Address& peer,
+ uint32_t numeric_value);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.43
+ static std::unique_ptr<EventPacketBuilder> CreateUserPasskeyRequestEvent(const Address& peer);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.44
+ static std::unique_ptr<EventPacketBuilder> CreateRemoteOobDataRequestEvent(const Address& peer);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.45
+ static std::unique_ptr<EventPacketBuilder> CreateSimplePairingCompleteEvent(hci::Status status, const Address& peer);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.48
+ static std::unique_ptr<EventPacketBuilder> CreateUserPasskeyNotificationEvent(const Address& peer, uint32_t passkey);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.49
+ static std::unique_ptr<EventPacketBuilder> CreateKeypressNotificationEvent(const Address& peer,
+ uint8_t notification_type);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
+ // 7.7.65.1
+ static std::unique_ptr<EventPacketBuilder> CreateLeConnectionCompleteEvent(hci::Status status, uint16_t handle,
+ uint8_t role, uint8_t peer_address_type,
+ const Address& peer, uint16_t interval,
+ uint16_t latency,
+ uint16_t supervision_timeout);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
+ // 7.7.65.2
+ static std::unique_ptr<EventPacketBuilder> CreateLeAdvertisingReportEvent();
+
+ // Returns true if the report can be added to the event packet.
+ bool AddLeAdvertisingReport(LeAdvertisement::AdvertisementType event_type, LeAdvertisement::AddressType addr_type,
+ const Address& addr, const std::vector<uint8_t>& data, uint8_t rssi);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
+ // 7.7.65.3
+ static std::unique_ptr<EventPacketBuilder> CreateLeConnectionUpdateCompleteEvent(hci::Status status, uint16_t handle,
+ uint16_t interval, uint16_t latency,
+ uint16_t supervision_timeout);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
+ // 7.7.65.4
+ static std::unique_ptr<EventPacketBuilder> CreateLeRemoteUsedFeaturesEvent(hci::Status status, uint16_t handle,
+ uint64_t features);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
+ // 7.7.65.10
+ static std::unique_ptr<EventPacketBuilder> CreateLeEnhancedConnectionCompleteEvent(
+ hci::Status status, uint16_t handle, uint8_t role, uint8_t peer_address_type, const Address& peer,
+ const Address& local_private_address, const Address& peer_private_address, uint16_t interval, uint16_t latency,
+ uint16_t supervision_timeout);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.2
+ static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteLeReadBufferSize(
+ hci::Status status, uint16_t hc_le_data_packet_length, uint8_t hc_total_num_le_data_packets);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.3
+ static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteLeReadLocalSupportedFeatures(hci::Status status,
+ uint64_t le_features);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.14
+ static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteLeReadWhiteListSize(hci::Status status,
+ uint8_t white_list_size);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.23
+ static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteLeRand(hci::Status status, uint64_t random_val);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.27
+ static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteLeReadSupportedStates(hci::Status status,
+ uint64_t le_states);
+
+ /*
+ static std::unique_ptr<EventPacketBuilder>
+ CreateLeStartEncryption(hci::Status status, uint8_t encryption_enable);
+*/
+ static std::unique_ptr<EventPacketBuilder> CreateEncryptionChange(hci::Status status, uint16_t handle,
+ uint8_t encryption_enable);
+
+ // Vendor-specific commands
+
+ static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteLeGetVendorCapabilities(
+ hci::Status status, const std::vector<uint8_t>& vendor_cap);
+
+ virtual size_t size() const override;
+
+ virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override;
+
+ bool CanAddPayloadOctets(size_t octets);
+
+ bool AddPayloadOctets(size_t octets, const std::vector<uint8_t>& bytes);
+
+ bool AddPayloadOctets(const std::vector<uint8_t>& bytes);
+
+ bool AddPayloadOctets1(uint8_t value);
+ bool AddPayloadOctets2(uint16_t value);
+ bool AddPayloadOctets3(uint32_t value);
+ bool AddPayloadOctets4(uint32_t value);
+ bool AddPayloadOctets6(uint64_t value);
+ bool AddPayloadOctets8(uint64_t value);
+
+ bool AddPayloadAddress(Address address);
+
+ bool AddBuilder(std::unique_ptr<BasePacketBuilder> builder);
+
+ private:
+ explicit EventPacketBuilder(hci::EventCode event_code);
+ explicit EventPacketBuilder(hci::EventCode event_code, std::unique_ptr<RawBuilder> payload);
+ hci::EventCode event_code_;
+ std::unique_ptr<RawBuilder> payload_;
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/event_payload_builder.cc b/vendor_libs/test_vendor_lib/packets/hci/event_payload_builder.cc
new file mode 100644
index 0000000..dd866a2
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/hci/event_payload_builder.cc
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2018 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 "event_payload_builder.h"
+
+#include <base/logging.h>
+#include <algorithm>
+
+using std::vector;
+
+namespace test_vendor_lib {
+namespace packets {
+
+EventPayloadBuilder::EventPayloadBuilder(size_t max_bytes) : max_bytes_(max_bytes) {}
+
+bool EventPayloadBuilder::AddPayloadOctets(size_t octets, const vector<uint8_t>& bytes) {
+ if (payload_.size() + octets > max_bytes_) return false;
+
+ if (octets != bytes.size()) return false;
+
+ payload_.insert(payload_.end(), bytes.begin(), bytes.end());
+
+ return true;
+}
+
+bool EventPayloadBuilder::AddPayloadOctets(const vector<uint8_t>& bytes) {
+ return AddPayloadOctets(bytes.size(), bytes);
+}
+
+bool EventPayloadBuilder::AddPayloadOctets(size_t octets, uint64_t value) {
+ vector<uint8_t> val_vector;
+
+ uint64_t v = value;
+
+ if (octets > sizeof(uint64_t)) return false;
+
+ for (size_t i = 0; i < octets; i++) {
+ val_vector.push_back(v & 0xff);
+ v = v >> 8;
+ }
+
+ if (v != 0) return false;
+
+ return AddPayloadOctets(octets, val_vector);
+}
+
+bool EventPayloadBuilder::AddPayloadAddress(const Address& address) {
+ if (payload_.size() + Address::kLength > max_bytes_) return false;
+
+ for (size_t i = 0; i < Address::kLength; i++) {
+ payload_.push_back(address.address[i]);
+ }
+ return true;
+}
+
+bool EventPayloadBuilder::AddPayloadOctets1(uint8_t value) {
+ return AddPayloadOctets(1, value);
+}
+
+bool EventPayloadBuilder::AddPayloadOctets2(uint16_t value) {
+ return AddPayloadOctets(2, value);
+}
+
+bool EventPayloadBuilder::AddPayloadOctets3(uint32_t value) {
+ return AddPayloadOctets(3, value);
+}
+
+bool EventPayloadBuilder::AddPayloadOctets4(uint32_t value) {
+ return AddPayloadOctets(4, value);
+}
+
+bool EventPayloadBuilder::AddPayloadOctets6(uint64_t value) {
+ return AddPayloadOctets(6, value);
+}
+
+bool EventPayloadBuilder::AddPayloadOctets8(uint64_t value) {
+ return AddPayloadOctets(8, value);
+}
+
+bool EventPayloadBuilder::CanAddPayloadOctets(size_t num_bytes) const {
+ return payload_.size() + num_bytes <= max_bytes_;
+}
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/event_payload_builder.h b/vendor_libs/test_vendor_lib/packets/hci/event_payload_builder.h
new file mode 100644
index 0000000..b656edf
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/hci/event_payload_builder.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2018 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 "packets/packet_builder.h"
+#include "types/address.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+class EventPayloadBuilder : public PacketBuilder<true> {
+ public:
+ EventPayloadBuilder() = default;
+ EventPayloadBuilder(size_t max_bytes);
+ virtual ~EventPayloadBuilder() = default;
+
+ virtual size_t size() const override;
+
+ virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const;
+
+ // Add |octets| bytes to the payload. Return true if:
+ // - the size of |bytes| is equal to |octets| and
+ // - the new size of the payload is still < |max_bytes_|
+ bool AddPayloadOctets(size_t octets, const std::vector<uint8_t>& bytes);
+
+ bool AddPayloadOctets(const std::vector<uint8_t>& bytes);
+
+ bool AddPayloadOctets1(uint8_t value);
+ bool AddPayloadOctets2(uint16_t value);
+ bool AddPayloadOctets3(uint32_t value);
+ bool AddPayloadOctets4(uint32_t value);
+ bool AddPayloadOctets6(uint64_t value);
+ bool AddPayloadOctets8(uint64_t value);
+
+ private:
+ // Add |octets| bytes to the payload. Return true if:
+ // - the value of |value| fits in |octets| bytes and
+ // - the new size of the payload is still < |max_bytes_|
+ bool AddPayloadOctets(size_t octets, uint64_t value);
+
+ // Add |address| to the payload. Return true if:
+ // - the new size of the payload is still < |max_bytes_|
+ bool AddPayloadAddress(const Address& address);
+
+ // Return true if |num_bytes| can be added to the payload.
+ bool CanAddPayloadOctets(size_t num_bytes) const;
+
+ size_t max_bytes_{255};
+
+ // Underlying containers for storing the actual packet
+ std::vector<uint8_t> payload_;
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/hci_packet_builder.cc b/vendor_libs/test_vendor_lib/packets/hci/hci_packet_builder.cc
new file mode 100644
index 0000000..1d5689b
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/hci/hci_packet_builder.cc
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2018 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 "packets/hci/hci_packet_builder.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+namespace packets {
+
+std::shared_ptr<std::vector<uint8_t>> HciPacketBuilder::ToVector() {
+ std::shared_ptr<std::vector<uint8_t>> to_return = std::make_shared<std::vector<uint8_t>>();
+ std::back_insert_iterator<std::vector<uint8_t>> it(*to_return);
+ Serialize(it);
+ return to_return;
+}
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/hci_packet_builder.h b/vendor_libs/test_vendor_lib/packets/hci/hci_packet_builder.h
new file mode 100644
index 0000000..d508696
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/hci/hci_packet_builder.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2018 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 "packets/packet_builder.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+// Base packet for HCI packets specified in the Bluetooth Core Specification
+// Version 4.2, Volume 2, Part E, Section 5.4
+class HciPacketBuilder : public PacketBuilder<true> {
+ public:
+ virtual ~HciPacketBuilder() override = default;
+
+ std::shared_ptr<std::vector<uint8_t>> ToVector();
+
+ protected:
+ HciPacketBuilder() = default;
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/le_meta_event_builder.cc b/vendor_libs/test_vendor_lib/packets/hci/le_meta_event_builder.cc
new file mode 100644
index 0000000..f0599a7
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/hci/le_meta_event_builder.cc
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2018 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 "packets/hci/le_meta_event_builder.h"
+
+#include <base/logging.h>
+
+using std::vector;
+using test_vendor_lib::hci::LeSubEventCode;
+using test_vendor_lib::hci::Status;
+
+namespace test_vendor_lib {
+namespace packets {
+
+LeMetaEventBuilder::LeMetaEventBuilder(LeSubEventCode sub_event_code)
+ : sub_event_code_(sub_event_code), payload_(std::make_unique<RawBuilder>()) {}
+
+LeMetaEventBuilder::LeMetaEventBuilder(LeSubEventCode sub_event_code, std::unique_ptr<RawBuilder> payload)
+ : sub_event_code_(sub_event_code), payload_(std::move(payload)) {}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.65.1
+std::unique_ptr<LeMetaEventBuilder> LeMetaEventBuilder::CreateLeConnectionCompleteEvent(
+ Status status, uint16_t handle, uint8_t role, uint8_t peer_address_type, const Address& peer, uint16_t interval,
+ uint16_t latency, uint16_t supervision_timeout) {
+ std::unique_ptr<LeMetaEventBuilder> evt_ptr =
+ std::unique_ptr<LeMetaEventBuilder>(new LeMetaEventBuilder(LeSubEventCode::CONNECTION_COMPLETE));
+
+ CHECK(evt_ptr->AddOctets1(static_cast<uint8_t>(status)));
+ CHECK(evt_ptr->AddOctets2(handle));
+ CHECK(evt_ptr->AddOctets1(role));
+ CHECK(evt_ptr->AddOctets1(peer_address_type));
+ CHECK(evt_ptr->AddAddress(peer));
+ CHECK(evt_ptr->AddOctets2(interval));
+ CHECK(evt_ptr->AddOctets2(latency));
+ CHECK(evt_ptr->AddOctets2(supervision_timeout));
+ CHECK(evt_ptr->AddOctets1(0x00)); // Master Clock Accuracy (unused for master)
+
+ return evt_ptr;
+}
+
+std::unique_ptr<LeMetaEventBuilder> LeMetaEventBuilder::CreateLeEnhancedConnectionCompleteEvent(
+ Status status, uint16_t handle, uint8_t role, uint8_t peer_address_type, const Address& peer,
+ const Address& local_private_address, const Address& peer_private_address, uint16_t interval, uint16_t latency,
+ uint16_t supervision_timeout) {
+ std::unique_ptr<LeMetaEventBuilder> evt_ptr =
+ std::unique_ptr<LeMetaEventBuilder>(new LeMetaEventBuilder(LeSubEventCode::ENHANCED_CONNECTION_COMPLETE));
+
+ CHECK(evt_ptr->AddOctets1(static_cast<uint8_t>(status)));
+ CHECK(evt_ptr->AddOctets2(handle));
+ CHECK(evt_ptr->AddOctets1(role));
+ CHECK(evt_ptr->AddOctets1(peer_address_type));
+ CHECK(evt_ptr->AddAddress(peer));
+ CHECK(evt_ptr->AddAddress(local_private_address));
+ CHECK(evt_ptr->AddAddress(peer_private_address));
+ CHECK(evt_ptr->AddOctets2(interval));
+ CHECK(evt_ptr->AddOctets2(latency));
+ CHECK(evt_ptr->AddOctets2(supervision_timeout));
+ CHECK(evt_ptr->AddOctets1(0x00)); // Master Clock Accuracy (unused for master)
+
+ return evt_ptr;
+}
+
+std::unique_ptr<LeMetaEventBuilder> LeMetaEventBuilder::CreateLeConnectionUpdateCompleteEvent(
+ Status status, uint16_t handle, uint16_t interval, uint16_t latency, uint16_t supervision_timeout) {
+ std::unique_ptr<LeMetaEventBuilder> evt_ptr =
+ std::unique_ptr<LeMetaEventBuilder>(new LeMetaEventBuilder(LeSubEventCode::CONNECTION_UPDATE_COMPLETE));
+
+ CHECK(evt_ptr->AddOctets1(static_cast<uint8_t>(status)));
+ CHECK(evt_ptr->AddOctets2(handle));
+ CHECK(evt_ptr->AddOctets2(interval));
+ CHECK(evt_ptr->AddOctets2(latency));
+ CHECK(evt_ptr->AddOctets2(supervision_timeout));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.65.2
+std::unique_ptr<LeMetaEventBuilder> LeMetaEventBuilder::CreateLeAdvertisingReportEvent() {
+ std::unique_ptr<LeMetaEventBuilder> evt_ptr = std::unique_ptr<LeMetaEventBuilder>(
+ new LeMetaEventBuilder(LeSubEventCode::ADVERTISING_REPORT, std::unique_ptr<RawBuilder>(new CountedBuilder())));
+
+ return evt_ptr;
+}
+
+bool LeMetaEventBuilder::AddLeAdvertisingReport(LeAdvertisement::AdvertisementType event_type,
+ LeAdvertisement::AddressType addr_type, const Address& addr,
+ const vector<uint8_t>& data, uint8_t rssi) {
+ if (!CanAddOctets(10 + data.size())) return false;
+
+ CHECK(sub_event_code_ == LeSubEventCode::ADVERTISING_REPORT);
+
+ std::unique_ptr<RawBuilder> ad = std::make_unique<RawBuilder>();
+
+ CHECK(ad->AddOctets1(static_cast<uint8_t>(event_type)));
+ CHECK(ad->AddOctets1(static_cast<uint8_t>(addr_type)));
+ CHECK(ad->AddAddress(addr));
+ CHECK(ad->AddOctets1(data.size()));
+ CHECK(ad->AddOctets(data));
+ CHECK(ad->AddOctets1(rssi));
+ AddBuilder(std::move(ad));
+ return true;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.65.4
+std::unique_ptr<LeMetaEventBuilder> LeMetaEventBuilder::CreateLeRemoteUsedFeaturesEvent(Status status, uint16_t handle,
+ uint64_t features) {
+ std::unique_ptr<LeMetaEventBuilder> evt_ptr =
+ std::unique_ptr<LeMetaEventBuilder>(new LeMetaEventBuilder(LeSubEventCode::READ_REMOTE_FEATURES_COMPLETE));
+
+ CHECK(evt_ptr->AddOctets1(static_cast<uint8_t>(status)));
+ CHECK(evt_ptr->AddOctets2(handle));
+ CHECK(evt_ptr->AddOctets8(features));
+
+ return evt_ptr;
+}
+
+size_t LeMetaEventBuilder::size() const {
+ return 1 + payload_->size(); // Add the sub_event_code
+}
+
+void LeMetaEventBuilder::Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const {
+ insert(static_cast<uint8_t>(sub_event_code_), it);
+ uint8_t payload_size = size() - sizeof(uint8_t);
+ CHECK(size() - sizeof(uint8_t) == static_cast<size_t>(payload_size)) << "Payload too large for an event: " << size();
+ payload_->Serialize(it);
+}
+
+bool LeMetaEventBuilder::AddBuilder(std::unique_ptr<BasePacketBuilder> builder) {
+ // Upcast the payload to add the next builder.
+ CountedBuilder* temp_ptr = static_cast<CountedBuilder*>(payload_.get());
+ temp_ptr->Add(std::move(builder));
+ return true;
+}
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/le_meta_event_builder.h b/vendor_libs/test_vendor_lib/packets/hci/le_meta_event_builder.h
new file mode 100644
index 0000000..b1d713d
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/hci/le_meta_event_builder.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2018 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 <base/logging.h>
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "include/hci.h"
+#include "include/le_advertisement.h"
+#include "packets/counted_builder.h"
+#include "packets/hci/hci_packet_builder.h"
+#include "packets/packet_builder.h"
+#include "packets/packet_view.h"
+#include "packets/raw_builder.h"
+#include "types/address.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+// LE Meta Event Packets are specified in the Bluetooth Core Specification
+// Version 4.2, Volume 2, Part E, Section 7.7.65. The first byte is the
+// Subevent_Code.
+class LeMetaEventBuilder : public RawBuilder {
+ public:
+ virtual ~LeMetaEventBuilder() override = default;
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
+ // 7.7.65.1
+ static std::unique_ptr<LeMetaEventBuilder> CreateLeConnectionCompleteEvent(hci::Status status, uint16_t handle,
+ uint8_t role, uint8_t peer_address_type,
+ const Address& peer, uint16_t interval,
+ uint16_t latency,
+ uint16_t supervision_timeout);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
+ // 7.7.65.2
+ static std::unique_ptr<LeMetaEventBuilder> CreateLeAdvertisingReportEvent();
+
+ // Returns true if the report can be added to the event packet.
+ bool AddLeAdvertisingReport(LeAdvertisement::AdvertisementType event_type, LeAdvertisement::AddressType addr_type,
+ const Address& addr, const std::vector<uint8_t>& data, uint8_t rssi);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
+ // 7.7.65.3
+ static std::unique_ptr<LeMetaEventBuilder> CreateLeConnectionUpdateCompleteEvent(hci::Status status, uint16_t handle,
+ uint16_t interval, uint16_t latency,
+ uint16_t supervision_timeout);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
+ // 7.7.65.4
+ static std::unique_ptr<LeMetaEventBuilder> CreateLeRemoteUsedFeaturesEvent(hci::Status status, uint16_t handle,
+ uint64_t features);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
+ // 7.7.65.10
+ static std::unique_ptr<LeMetaEventBuilder> CreateLeEnhancedConnectionCompleteEvent(
+ hci::Status status, uint16_t handle, uint8_t role, uint8_t peer_address_type, const Address& peer,
+ const Address& local_private_address, const Address& peer_private_address, uint16_t interval, uint16_t latency,
+ uint16_t supervision_timeout);
+
+ virtual size_t size() const override;
+
+ virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override;
+
+ bool AddBuilder(std::unique_ptr<BasePacketBuilder> builder);
+
+ private:
+ explicit LeMetaEventBuilder(hci::LeSubEventCode sub_event_code);
+ explicit LeMetaEventBuilder(hci::LeSubEventCode sub_event_code, std::unique_ptr<RawBuilder> payload);
+ hci::LeSubEventCode sub_event_code_;
+ std::unique_ptr<RawBuilder> payload_;
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/sco_packet_builder.cc b/vendor_libs/test_vendor_lib/packets/hci/sco_packet_builder.cc
new file mode 100644
index 0000000..57203ed
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/hci/sco_packet_builder.cc
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2018 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 "packets/hci/sco_packet_builder.h"
+
+#include <base/logging.h>
+
+using std::vector;
+using test_vendor_lib::sco::PacketStatusFlagsType;
+
+namespace test_vendor_lib {
+namespace packets {
+
+ScoPacketBuilder::ScoPacketBuilder(uint16_t handle, PacketStatusFlagsType packet_status_flags,
+ std::unique_ptr<BasePacketBuilder> payload)
+ : handle_(handle), packet_status_flags_(packet_status_flags), payload_(std::move(payload)) {}
+
+size_t ScoPacketBuilder::size() const {
+ return 2 * sizeof(uint16_t) + payload_->size();
+}
+
+void ScoPacketBuilder::Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const {
+ insert(static_cast<uint16_t>((handle_ & 0xfff) | (static_cast<uint16_t>(packet_status_flags_) << 12)), it);
+ uint8_t payload_size = payload_->size();
+
+ CHECK(static_cast<size_t>(payload_size) == payload_->size())
+ << "Payload too large for a SCO packet: " << payload_->size();
+ insert(payload_size, it);
+ payload_->Serialize(it);
+}
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/sco_packet_builder.h b/vendor_libs/test_vendor_lib/packets/hci/sco_packet_builder.h
new file mode 100644
index 0000000..a2d8561
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/hci/sco_packet_builder.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2018 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 <base/logging.h>
+#include <cstdint>
+#include <memory>
+#include <vector>
+
+#include "include/sco.h"
+#include "packets/hci/hci_packet_builder.h"
+#include "packets/packet_builder.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+// SCO data packets are specified in the Bluetooth Core Specification Version
+// 4.2, Volume 2, Part E, Section 5.4.3
+class ScoPacketBuilder : public HciPacketBuilder {
+ public:
+ virtual ~ScoPacketBuilder() override = default;
+
+ static std::unique_ptr<ScoPacketBuilder> Create(uint16_t handle, sco::PacketStatusFlagsType packet_status_flags,
+ std::unique_ptr<BasePacketBuilder> payload);
+
+ virtual size_t size() const override;
+
+ virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override;
+
+ private:
+ ScoPacketBuilder(uint16_t handle, sco::PacketStatusFlagsType packet_status_flags,
+ std::unique_ptr<BasePacketBuilder> payload);
+ ScoPacketBuilder() = delete;
+ uint16_t handle_;
+ sco::PacketStatusFlagsType packet_status_flags_;
+ std::unique_ptr<BasePacketBuilder> payload_;
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/sco_packet_view.cc b/vendor_libs/test_vendor_lib/packets/hci/sco_packet_view.cc
new file mode 100644
index 0000000..9516ef4
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/hci/sco_packet_view.cc
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2018 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 "packets/hci/sco_packet_view.h"
+
+#include <base/logging.h>
+
+using test_vendor_lib::sco::PacketStatusFlagsType;
+
+namespace test_vendor_lib {
+namespace packets {
+
+ScoPacketView::ScoPacketView(std::shared_ptr<std::vector<uint8_t>> packet) : PacketView<true>(packet) {}
+
+ScoPacketView ScoPacketView::Create(std::shared_ptr<std::vector<uint8_t>> packet) {
+ return ScoPacketView(packet);
+}
+
+uint16_t ScoPacketView::GetHandle() const {
+ return begin().extract<uint16_t>() & 0xfff;
+}
+
+PacketStatusFlagsType ScoPacketView::GetPacketStatusFlags() const {
+ return static_cast<PacketStatusFlagsType>(((begin() + 1).extract<uint8_t>() & 0x30) >> 4);
+}
+
+PacketView<true> ScoPacketView::GetPayload() const {
+ uint8_t payload_size = (begin() + sizeof(uint16_t)).extract<uint8_t>();
+ CHECK(static_cast<uint8_t>(size() - sizeof(uint16_t) - sizeof(uint8_t)) == payload_size)
+ << "Malformed SCO packet payload_size " << payload_size << " + 4 != " << size();
+ return SubViewLittleEndian(sizeof(uint16_t) + sizeof(uint8_t), size());
+}
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/sco_packet_view.h b/vendor_libs/test_vendor_lib/packets/hci/sco_packet_view.h
new file mode 100644
index 0000000..26b9489
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/hci/sco_packet_view.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2018 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 <base/logging.h>
+#include <cstdint>
+#include <memory>
+#include <vector>
+
+#include "include/sco.h"
+#include "packets/packet_view.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+// SCO data packets are specified in the Bluetooth Core Specification Version
+// 4.2, Volume 2, Part E, Section 5.4.3
+class ScoPacketView : public PacketView<true> {
+ public:
+ virtual ~ScoPacketView() override = default;
+
+ static ScoPacketView Create(std::shared_ptr<std::vector<uint8_t>> packet);
+
+ uint16_t GetHandle() const;
+ sco::PacketStatusFlagsType GetPacketStatusFlags() const;
+ PacketView<true> GetPayload() const;
+
+ private:
+ ScoPacketView(std::shared_ptr<std::vector<uint8_t>> packet);
+ ScoPacketView() = delete;
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/test/acl_builder_test.cc b/vendor_libs/test_vendor_lib/packets/hci/test/acl_builder_test.cc
new file mode 100644
index 0000000..fb34489
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/hci/test/acl_builder_test.cc
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2018 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 "packets/hci/acl_packet_builder.h"
+#include "packets/hci/acl_packet_view.h"
+#include "packets/raw_builder.h"
+
+#include <gtest/gtest.h>
+#include <forward_list>
+#include <memory>
+
+#include "types/address.h"
+
+using std::vector;
+using test_vendor_lib::acl::BroadcastFlagsType;
+using test_vendor_lib::acl::PacketBoundaryFlagsType;
+
+namespace {
+vector<uint8_t> count = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+};
+
+vector<uint8_t> information_request = {
+ 0xfe, 0x2e, 0x0a, 0x00, 0x06, 0x00, 0x01, 0x00, 0x0a, 0x02, 0x02, 0x00, 0x02, 0x00,
+};
+
+} // namespace
+
+namespace test_vendor_lib {
+namespace packets {
+
+class AclBuilderTest : public ::testing::Test {
+ public:
+ AclBuilderTest() = default;
+ ~AclBuilderTest() override = default;
+};
+
+TEST(AclBuilderTest, buildAclCountTest) {
+ uint16_t handle = 0x0102;
+ PacketBoundaryFlagsType packet_boundary_flags = PacketBoundaryFlagsType::FIRST_AUTOMATICALLY_FLUSHABLE;
+ BroadcastFlagsType broadcast_flags = BroadcastFlagsType::ACTIVE_SLAVE_BROADCAST;
+
+ std::unique_ptr<RawBuilder> count_payload = std::make_unique<RawBuilder>();
+ count_payload->AddOctets(count);
+ ASSERT_EQ(count.size(), count_payload->size());
+
+ std::unique_ptr<AclPacketBuilder> count_packet =
+ AclPacketBuilder::Create(handle, packet_boundary_flags, broadcast_flags, std::move(count_payload));
+
+ ASSERT_EQ(count.size() + 4, count_packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> count_packet_bytes = count_packet->ToVector();
+ AclPacketView count_packet_view = AclPacketView::Create(count_packet_bytes);
+
+ ASSERT_EQ(handle, count_packet_view.GetHandle());
+ ASSERT_EQ(packet_boundary_flags, count_packet_view.GetPacketBoundaryFlags());
+ ASSERT_EQ(broadcast_flags, count_packet_view.GetBroadcastFlags());
+ PacketView<true> count_view = count_packet_view.GetPayload();
+
+ ASSERT_EQ(count_view.size(), count.size());
+ for (size_t i = 0; i < count_view.size(); i++) {
+ ASSERT_EQ(count_view[i], count[i]);
+ }
+}
+
+TEST(AclBuilderTest, buildInformationRequest) {
+ uint16_t handle = 0x0efe;
+ PacketBoundaryFlagsType packet_boundary_flags = PacketBoundaryFlagsType::FIRST_AUTOMATICALLY_FLUSHABLE;
+ BroadcastFlagsType broadcast_flags = BroadcastFlagsType::POINT_TO_POINT;
+
+ std::vector<uint8_t> payload_bytes(information_request.begin() + 4, information_request.end());
+ std::unique_ptr<RawBuilder> payload = std::make_unique<RawBuilder>();
+ payload->AddOctets(payload_bytes);
+ ASSERT_EQ(payload_bytes.size(), payload->size());
+
+ std::unique_ptr<AclPacketBuilder> packet =
+ AclPacketBuilder::Create(handle, packet_boundary_flags, broadcast_flags, std::move(payload));
+
+ ASSERT_EQ(information_request.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = packet->ToVector();
+ AclPacketView packet_view = AclPacketView::Create(packet_bytes);
+
+ ASSERT_EQ(packet_bytes->size(), information_request.size());
+ for (size_t i = 0; i < packet_bytes->size(); i++) {
+ ASSERT_EQ((*packet_bytes)[i], information_request[i]);
+ }
+
+ ASSERT_EQ(handle, packet_view.GetHandle());
+ ASSERT_EQ(packet_boundary_flags, packet_view.GetPacketBoundaryFlags());
+ ASSERT_EQ(broadcast_flags, packet_view.GetBroadcastFlags());
+ PacketView<true> payload_view = packet_view.GetPayload();
+
+ ASSERT_EQ(payload_view.size(), payload_bytes.size());
+ for (size_t i = 0; i < payload_view.size(); i++) {
+ ASSERT_EQ(payload_view[i], payload_bytes[i]);
+ }
+
+ ASSERT_EQ(packet_view.size(), information_request.size());
+ for (size_t i = 0; i < packet_view.size(); i++) {
+ ASSERT_EQ(packet_view[i], information_request[i]);
+ }
+}
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/test/event_builder_test.cc b/vendor_libs/test_vendor_lib/packets/hci/test/event_builder_test.cc
new file mode 100644
index 0000000..8a11d45
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/hci/test/event_builder_test.cc
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2018 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 "packets/hci/event_packet_builder.h"
+
+#include <gtest/gtest.h>
+#include <forward_list>
+#include <memory>
+
+#include "types/address.h"
+
+using std::vector;
+
+namespace {
+vector<uint8_t> count = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+};
+
+} // namespace
+
+namespace test_vendor_lib {
+namespace packets {
+
+class EventBuilderTest : public ::testing::Test {
+ public:
+ EventBuilderTest() = default;
+ ~EventBuilderTest() override = default;
+};
+
+TEST(EventBuilderTest, buildLeAdvertisementSmallTest) {
+ LeAdvertisement::AdvertisementType adv_type = LeAdvertisement::AdvertisementType::ADV_SCAN_IND;
+ LeAdvertisement::AddressType addr_type = LeAdvertisement::AddressType::RANDOM;
+ std::unique_ptr<EventPacketBuilder> le_adv = EventPacketBuilder::CreateLeAdvertisingReportEvent();
+ Address addr({1, 2, 3, 4, 5, 6});
+ uint8_t rssi = -93;
+
+ std::vector<uint8_t> payload({0x23});
+ le_adv->AddLeAdvertisingReport(adv_type, addr_type, addr, {payload}, rssi);
+
+ uint8_t payload_size = payload.size();
+ uint8_t event_size = payload_size + sizeof(Address) + sizeof(rssi) + 5;
+ std::vector<uint8_t> expected({
+ 0x3e, // HCI LE Event
+ event_size,
+ 0x02, // LE Advertising subevent code
+ 0x01, // Number of responses
+ 0x02, // Event type is scannable undirected
+ 0x01, // Address type is random
+ 0x01, // Address
+ 0x02, // Address
+ 0x03, // Address
+ 0x04, // Address
+ 0x05, // Address
+ 0x06, // Address
+ payload_size, // Length of the data
+ });
+
+ expected.push_back(payload[0]);
+ expected.push_back(rssi);
+
+ ASSERT_EQ(expected.size(), le_adv->size());
+ ASSERT_EQ(expected, *le_adv->ToVector());
+}
+
+TEST(EventBuilderTest, buildLeAdvertisementTest) {
+ LeAdvertisement::AdvertisementType adv_type = LeAdvertisement::AdvertisementType::ADV_SCAN_IND;
+ LeAdvertisement::AddressType addr_type = LeAdvertisement::AddressType::RANDOM;
+ std::unique_ptr<EventPacketBuilder> le_adv = EventPacketBuilder::CreateLeAdvertisingReportEvent();
+ Address addr({1, 2, 3, 4, 5, 6});
+ uint8_t rssi = -93;
+
+ le_adv->AddLeAdvertisingReport(adv_type, addr_type, addr, count, rssi);
+
+ uint8_t count_size = static_cast<uint8_t>(count.size());
+ uint8_t event_size = count_size + sizeof(Address) + sizeof(rssi) + 5;
+ std::vector<uint8_t> expected({
+ 0x3e, // HCI LE Event
+ event_size,
+ 0x02, // LE Advertising subevent code
+ 0x01, // Number of responses
+ 0x02, // Event type is scannable undirected
+ 0x01, // Address type is random
+ 0x01, // Address
+ 0x02, // Address
+ 0x03, // Address
+ 0x04, // Address
+ 0x05, // Address
+ 0x06, // Address
+ count_size, // Length of the data
+ });
+
+ for (size_t i = 0; i < count.size(); i++) {
+ expected.push_back(count[i]);
+ }
+ expected.push_back(rssi);
+
+ std::shared_ptr<std::vector<uint8_t>> raw_adv = le_adv->ToVector();
+ ASSERT_EQ(expected, *raw_adv);
+}
+
+TEST(EventBuilderTest, buildNumberOfCompletedPackets) {
+ uint16_t handle = 0x0102;
+ uint16_t num_packets = 0x0304;
+
+ std::unique_ptr<EventPacketBuilder> event =
+ EventPacketBuilder::CreateNumberOfCompletedPacketsEvent(handle, num_packets);
+
+ uint8_t number_of_handles = 1;
+ uint8_t event_size = sizeof(uint8_t) + number_of_handles * 2 * sizeof(uint16_t);
+ std::vector<uint8_t> expected({
+ 0x13, // HCI Number Of Completed Packets Event code
+ event_size, number_of_handles, //
+ 0x02, 0x01, // handle
+ 0x04, 0x03, // count
+ });
+
+ std::shared_ptr<std::vector<uint8_t>> raw_event = event->ToVector();
+ ASSERT_EQ(expected, *raw_event);
+}
+
+TEST(EventBuilderTest, buildNumberOfCompletedPacketsMultiple) {
+ uint16_t handle = 0x0102;
+ uint16_t num_packets = 0x0304;
+ uint16_t handle2 = 0x0506;
+ uint16_t num_packets2 = 0x0708;
+
+ std::unique_ptr<EventPacketBuilder> event =
+ EventPacketBuilder::CreateNumberOfCompletedPacketsEvent(handle, num_packets);
+ event->AddCompletedPackets(handle2, num_packets2);
+
+ uint8_t number_of_handles = 2;
+ uint8_t event_size = sizeof(uint8_t) + number_of_handles * 2 * sizeof(uint16_t);
+ std::vector<uint8_t> expected({
+ 0x13, // HCI Number Of Completed Packets Event code
+ event_size, number_of_handles, //
+ 0x02, 0x01, // handle
+ 0x04, 0x03, // count
+ 0x06, 0x05, // handle
+ 0x08, 0x07, // count
+ });
+
+ std::shared_ptr<std::vector<uint8_t>> raw_event = event->ToVector();
+ ASSERT_EQ(expected, *raw_event);
+}
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/iterator.cc b/vendor_libs/test_vendor_lib/packets/iterator.cc
new file mode 100644
index 0000000..65173ee
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/iterator.cc
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2018 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 "iterator.h"
+
+#include <base/logging.h>
+
+namespace test_vendor_lib {
+namespace packets {
+
+template <bool little_endian>
+Iterator<little_endian>::Iterator(std::forward_list<View> data, size_t offset) {
+ data_ = data;
+ index_ = offset;
+ length_ = 0;
+ for (auto& view : data) {
+ length_ += view.size();
+ }
+}
+
+template <bool little_endian>
+Iterator<little_endian> Iterator<little_endian>::operator+(int offset) {
+ auto itr(*this);
+
+ return itr += offset;
+}
+
+template <bool little_endian>
+Iterator<little_endian>& Iterator<little_endian>::operator+=(int offset) {
+ index_ += offset;
+ return *this;
+}
+
+template <bool little_endian>
+Iterator<little_endian> Iterator<little_endian>::operator++(int) {
+ auto itr(*this);
+ index_++;
+ return itr;
+}
+
+template <bool little_endian>
+Iterator<little_endian>& Iterator<little_endian>::operator++() {
+ index_++;
+ return *this;
+}
+
+template <bool little_endian>
+Iterator<little_endian> Iterator<little_endian>::operator-(int offset) {
+ auto itr(*this);
+
+ return itr -= offset;
+}
+
+template <bool little_endian>
+int Iterator<little_endian>::operator-(Iterator<little_endian>& itr) {
+ return index_ - itr.index_;
+}
+
+template <bool little_endian>
+Iterator<little_endian>& Iterator<little_endian>::operator-=(int offset) {
+ index_ -= offset;
+
+ return *this;
+}
+
+template <bool little_endian>
+Iterator<little_endian> Iterator<little_endian>::operator--(int) {
+ auto itr(*this);
+ if (index_ != 0) index_--;
+
+ return itr;
+}
+
+template <bool little_endian>
+Iterator<little_endian>& Iterator<little_endian>::operator--() {
+ if (index_ != 0) index_--;
+
+ return *this;
+}
+
+template <bool little_endian>
+Iterator<little_endian>& Iterator<little_endian>::operator=(const Iterator<little_endian>& itr) {
+ data_ = itr.data_;
+ index_ = itr.index_;
+
+ return *this;
+}
+
+template <bool little_endian>
+bool Iterator<little_endian>::operator==(const Iterator<little_endian>& itr) const {
+ return index_ == itr.index_;
+}
+
+template <bool little_endian>
+bool Iterator<little_endian>::operator!=(const Iterator<little_endian>& itr) const {
+ return !(*this == itr);
+}
+
+template <bool little_endian>
+bool Iterator<little_endian>::operator<(const Iterator<little_endian>& itr) const {
+ return index_ < itr.index_;
+}
+
+template <bool little_endian>
+bool Iterator<little_endian>::operator>(const Iterator<little_endian>& itr) const {
+ return index_ > itr.index_;
+}
+
+template <bool little_endian>
+bool Iterator<little_endian>::operator<=(const Iterator<little_endian>& itr) const {
+ return index_ <= itr.index_;
+}
+
+template <bool little_endian>
+bool Iterator<little_endian>::operator>=(const Iterator<little_endian>& itr) const {
+ return index_ >= itr.index_;
+}
+
+template <bool little_endian>
+uint8_t Iterator<little_endian>::operator*() const {
+ CHECK(index_ < length_) << "Index " << index_ << " out of bounds: " << length_;
+ size_t index = index_;
+
+ for (auto view : data_) {
+ if (index < view.size()) {
+ return view[index];
+ }
+ index -= view.size();
+ }
+ CHECK(false) << "Out of fragments searching for Index " << index_;
+ return 0;
+}
+
+template <bool little_endian>
+size_t Iterator<little_endian>::NumBytesRemaining() const {
+ if (length_ > index_) {
+ return length_ - index_;
+ } else {
+ return 0;
+ }
+}
+
+// Explicit instantiations for both types of Iterators.
+template class Iterator<true>;
+template class Iterator<false>;
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/iterator.h b/vendor_libs/test_vendor_lib/packets/iterator.h
new file mode 100644
index 0000000..b84ce64
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/iterator.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2018 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 <forward_list>
+
+#include "types/address.h"
+#include "view.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+// Templated Iterator for endianness
+template <bool little_endian>
+class Iterator : public std::iterator<std::random_access_iterator_tag, uint8_t> {
+ public:
+ Iterator(std::forward_list<View> data, size_t offset);
+ Iterator(const Iterator& itr) = default;
+ virtual ~Iterator() = default;
+
+ // All addition and subtraction operators are unbounded.
+ Iterator operator+(int offset);
+ Iterator& operator+=(int offset);
+ Iterator operator++(int);
+ Iterator& operator++();
+
+ Iterator operator-(int offset);
+ int operator-(Iterator& itr);
+ Iterator& operator-=(int offset);
+ Iterator operator--(int);
+ Iterator& operator--();
+
+ Iterator& operator=(const Iterator& itr);
+
+ bool operator!=(const Iterator& itr) const;
+ bool operator==(const Iterator& itr) const;
+
+ bool operator<(const Iterator& itr) const;
+ bool operator>(const Iterator& itr) const;
+
+ bool operator<=(const Iterator& itr) const;
+ bool operator>=(const Iterator& itr) const;
+
+ uint8_t operator*() const;
+ uint8_t operator->() const;
+
+ size_t NumBytesRemaining() const;
+
+ // Get the next sizeof(FixedWidthPODType) bytes and return the filled type
+ template <typename FixedWidthPODType>
+ FixedWidthPODType extract() {
+ static_assert(std::is_pod<FixedWidthPODType>::value, "Iterator::extract requires an fixed type.");
+ FixedWidthPODType extracted_value;
+ uint8_t* value_ptr = (uint8_t*)&extracted_value;
+
+ for (size_t i = 0; i < sizeof(FixedWidthPODType); i++) {
+ size_t index = (little_endian ? i : sizeof(FixedWidthPODType) - i - 1);
+ value_ptr[index] = *((*this)++);
+ }
+ return extracted_value;
+ }
+
+ private:
+ std::forward_list<View> data_;
+ size_t index_;
+ size_t length_;
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/command_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/command_builder.h
new file mode 100644
index 0000000..15a4ab8
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/link_layer/command_builder.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2018 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 "base/logging.h"
+
+#include "packets/packet_builder.h"
+#include "packets/packet_view.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+class CommandBuilder : public PacketBuilder<true> {
+ public:
+ virtual ~CommandBuilder() = default;
+
+ static std::unique_ptr<CommandBuilder> Create(uint16_t opcode, PacketView<true> args) {
+ return std::unique_ptr<CommandBuilder>(new CommandBuilder(opcode, args));
+ }
+
+ virtual size_t size() const override {
+ return sizeof(opcode_) + args_.size();
+ }
+
+ protected:
+ virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+ insert(opcode_, it);
+ for (const auto&& byte : args_) {
+ insert(byte, it);
+ }
+ }
+
+ private:
+ explicit CommandBuilder(uint16_t opcode, PacketView<true> args) : opcode_(opcode), args_(args) {}
+ uint16_t opcode_;
+ PacketView<true> args_;
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/command_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/command_view.h
new file mode 100644
index 0000000..0aa5683
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/link_layer/command_view.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2018 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 <log/log.h>
+
+#include "packets/link_layer/link_layer_packet_view.h"
+#include "packets/packet_view.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+class CommandView : public PacketView<true> {
+ public:
+ CommandView(const CommandView&) = default;
+ virtual ~CommandView() = default;
+
+ static CommandView GetCommand(const LinkLayerPacketView& view) {
+ CHECK(view.GetType() == Link::PacketType::COMMAND);
+ return CommandView(view.GetPayload());
+ }
+
+ uint16_t GetOpcode() {
+ return begin().extract<uint16_t>();
+ }
+
+ Iterator<true> GetData() {
+ return begin() + sizeof(uint16_t);
+ }
+
+ private:
+ CommandView() = delete;
+ CommandView(const PacketView<true>& view) : PacketView(view) {}
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/disconnect_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/disconnect_builder.h
new file mode 100644
index 0000000..3c5a9f4
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/link_layer/disconnect_builder.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2018 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 "base/logging.h"
+
+#include "packets/packet_builder.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+class DisconnectBuilder : public PacketBuilder<true> {
+ public:
+ virtual ~DisconnectBuilder() = default;
+
+ static std::unique_ptr<DisconnectBuilder> Create(uint8_t reason) {
+ return std::unique_ptr<DisconnectBuilder>(new DisconnectBuilder(reason));
+ }
+
+ virtual size_t size() const override {
+ return sizeof(reason_);
+ }
+
+ protected:
+ virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+ *it++ = reason_;
+ }
+
+ private:
+ explicit DisconnectBuilder(uint8_t reason) : reason_(reason) {}
+ uint8_t reason_;
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/disconnect_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/disconnect_view.h
new file mode 100644
index 0000000..cdfcdc5
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/link_layer/disconnect_view.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2018 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 "packets/link_layer/link_layer_packet_view.h"
+#include "packets/packet_view.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+class DisconnectView : public PacketView<true> {
+ public:
+ DisconnectView(const DisconnectView&) = default;
+ virtual ~DisconnectView() = default;
+
+ static DisconnectView GetDisconnect(const LinkLayerPacketView& view) {
+ CHECK(view.GetType() == Link::PacketType::DISCONNECT);
+ return DisconnectView(view.GetPayload());
+ }
+
+ uint8_t GetReason() {
+ return at(0);
+ }
+
+ private:
+ DisconnectView() = delete;
+ DisconnectView(const PacketView<true>& view) : PacketView(view) {}
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/encrypt_connection_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/encrypt_connection_builder.h
new file mode 100644
index 0000000..329ecdb
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/link_layer/encrypt_connection_builder.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 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 "base/logging.h"
+
+#include "packets/packet_builder.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+class EncryptConnectionBuilder : public PacketBuilder<true> {
+ public:
+ virtual ~EncryptConnectionBuilder() = default;
+
+ static std::unique_ptr<EncryptConnectionBuilder> Create(const std::vector<uint8_t>& key) {
+ return std::unique_ptr<EncryptConnectionBuilder>(new EncryptConnectionBuilder(key));
+ }
+
+ virtual size_t size() const override {
+ return key_.size();
+ }
+
+ protected:
+ virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+ insert_vector(key_, it);
+ }
+
+ private:
+ explicit EncryptConnectionBuilder(const std::vector<uint8_t>& key) : key_(key.begin(), key.begin() + 16) {}
+ std::vector<uint8_t> key_;
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/encrypt_connection_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/encrypt_connection_view.h
new file mode 100644
index 0000000..665fe98
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/link_layer/encrypt_connection_view.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2018 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 "packets/link_layer/link_layer_packet_view.h"
+#include "packets/packet_view.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+class EncryptConnectionView : public PacketView<true> {
+ public:
+ EncryptConnectionView(const EncryptConnectionView&) = default;
+ virtual ~EncryptConnectionView() = default;
+
+ static EncryptConnectionView GetEncryptConnection(const LinkLayerPacketView& view) {
+ CHECK(view.GetType() == Link::PacketType::ENCRYPT_CONNECTION ||
+ view.GetType() == Link::PacketType::ENCRYPT_CONNECTION_RESPONSE);
+ return EncryptConnectionView(view.GetPayload());
+ }
+
+ Iterator<true> GetKey() {
+ return begin();
+ }
+
+ private:
+ EncryptConnectionView() = delete;
+ EncryptConnectionView(const PacketView<true>& view) : PacketView(view) {}
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_builder.h
new file mode 100644
index 0000000..6703316
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_builder.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2018 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 "base/logging.h"
+
+#include "inquiry.h"
+#include "packets/packet_builder.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+class InquiryBuilder : public PacketBuilder<true> {
+ public:
+ virtual ~InquiryBuilder() = default;
+
+ static std::unique_ptr<InquiryBuilder> Create(Inquiry::InquiryType inquiry_type) {
+ return std::unique_ptr<InquiryBuilder>(new InquiryBuilder(inquiry_type));
+ }
+
+ virtual size_t size() const override {
+ return sizeof(uint8_t);
+ }
+
+ protected:
+ virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+ insert(static_cast<uint8_t>(inquiry_type_), it);
+ }
+
+ private:
+ explicit InquiryBuilder(Inquiry::InquiryType inquiry_type) : inquiry_type_(inquiry_type) {}
+ Inquiry::InquiryType inquiry_type_;
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_response_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_response_builder.h
new file mode 100644
index 0000000..694fe71
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_response_builder.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2018 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 "base/logging.h"
+
+#include "include/inquiry.h"
+#include "packets/packet_builder.h"
+#include "types/class_of_device.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+class InquiryResponseBuilder : public PacketBuilder<true> {
+ public:
+ virtual ~InquiryResponseBuilder() = default;
+
+ static std::unique_ptr<InquiryResponseBuilder> CreateStandard(uint8_t page_scan_repetition_mode,
+ const ClassOfDevice& class_of_device,
+ uint16_t clock_offset) {
+ return std::unique_ptr<InquiryResponseBuilder>(new InquiryResponseBuilder(
+ Inquiry::InquiryType::STANDARD, page_scan_repetition_mode, class_of_device, clock_offset));
+ }
+ static std::unique_ptr<InquiryResponseBuilder> CreateRssi(uint8_t page_scan_repetition_mode,
+ const ClassOfDevice& class_of_device, uint16_t clock_offset,
+ uint8_t rssi) {
+ return std::unique_ptr<InquiryResponseBuilder>(new InquiryResponseBuilder(
+ Inquiry::InquiryType::RSSI, page_scan_repetition_mode, class_of_device, clock_offset, rssi));
+ }
+ static std::unique_ptr<InquiryResponseBuilder> CreateExtended(uint8_t page_scan_repetition_mode,
+ const ClassOfDevice& class_of_device,
+ uint16_t clock_offset, uint8_t rssi,
+ const std::vector<uint8_t>& extended_data) {
+ return std::unique_ptr<InquiryResponseBuilder>(new InquiryResponseBuilder(
+ Inquiry::InquiryType::EXTENDED, page_scan_repetition_mode, class_of_device, clock_offset, rssi, extended_data));
+ }
+
+ virtual size_t size() const override {
+ size_t inquiry_size =
+ sizeof(inquiry_type_) + sizeof(page_scan_repetition_mode_) + sizeof(class_of_device_) + sizeof(clock_offset_);
+ if (inquiry_type_ == Inquiry::InquiryType::STANDARD) {
+ return inquiry_size;
+ }
+ inquiry_size += sizeof(rssi_);
+ if (inquiry_type_ == Inquiry::InquiryType::RSSI) {
+ return inquiry_size;
+ }
+
+ return inquiry_size + extended_data_.size();
+ }
+
+ protected:
+ virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+ insert(static_cast<uint8_t>(inquiry_type_), it);
+ insert(page_scan_repetition_mode_, it);
+ insert_class_of_device(class_of_device_, it);
+ insert(clock_offset_, it);
+ if (inquiry_type_ == Inquiry::InquiryType::STANDARD) {
+ return;
+ }
+ insert(rssi_, it);
+ if (inquiry_type_ == Inquiry::InquiryType::RSSI) {
+ return;
+ }
+ insert_vector(extended_data_, it);
+ }
+
+ private:
+ Inquiry::InquiryType inquiry_type_;
+ uint8_t page_scan_repetition_mode_;
+ ClassOfDevice class_of_device_;
+ uint16_t clock_offset_;
+ uint8_t rssi_{0xff};
+ std::vector<uint8_t> extended_data_;
+ explicit InquiryResponseBuilder(Inquiry::InquiryType inquiry_type, uint8_t page_scan_repetition_mode,
+ const ClassOfDevice& class_of_device, uint16_t clock_offset)
+ : inquiry_type_(inquiry_type), page_scan_repetition_mode_(page_scan_repetition_mode),
+ class_of_device_(class_of_device), clock_offset_(clock_offset) {}
+ explicit InquiryResponseBuilder(Inquiry::InquiryType inquiry_type, uint8_t page_scan_repetition_mode,
+ const ClassOfDevice& class_of_device, uint16_t clock_offset, uint8_t rssi)
+ : inquiry_type_(inquiry_type), page_scan_repetition_mode_(page_scan_repetition_mode),
+ class_of_device_(class_of_device), clock_offset_(clock_offset), rssi_(rssi) {}
+ explicit InquiryResponseBuilder(Inquiry::InquiryType inquiry_type, uint8_t page_scan_repetition_mode,
+ const ClassOfDevice& class_of_device, uint16_t clock_offset, uint8_t rssi,
+ const std::vector<uint8_t>& extended_data)
+ : inquiry_type_(inquiry_type), page_scan_repetition_mode_(page_scan_repetition_mode),
+ class_of_device_(class_of_device), clock_offset_(clock_offset), rssi_(rssi), extended_data_(extended_data) {}
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_response_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_response_view.h
new file mode 100644
index 0000000..aac0585
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_response_view.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2018 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 "include/inquiry.h"
+#include "packets/link_layer/link_layer_packet_view.h"
+#include "packets/packet_view.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+class InquiryResponseView : public PacketView<true> {
+ public:
+ InquiryResponseView(const InquiryResponseView&) = default;
+ virtual ~InquiryResponseView() = default;
+
+ static InquiryResponseView GetInquiryResponse(const LinkLayerPacketView& view) {
+ CHECK(view.GetType() == Link::PacketType::INQUIRY_RESPONSE);
+ return InquiryResponseView(view.GetPayload());
+ }
+
+ Inquiry::InquiryType GetType() {
+ return static_cast<Inquiry::InquiryType>(at(0));
+ }
+
+ uint8_t GetPageScanRepetitionMode() {
+ return at(1);
+ }
+
+ ClassOfDevice GetClassOfDevice() {
+ size_t offset = 2 * sizeof(uint8_t);
+ return (begin() + offset).extract<ClassOfDevice>();
+ }
+
+ uint16_t GetClockOffset() {
+ size_t offset = 2 * sizeof(uint8_t) + 3;
+ return (begin() + offset).extract<uint16_t>();
+ }
+
+ uint8_t GetRssi() {
+ size_t offset = 2 * sizeof(uint8_t) + 3 + sizeof(uint16_t);
+ return at(offset);
+ }
+
+ Iterator<true> GetExtendedData() {
+ size_t offset = 2 * sizeof(uint8_t) + 3 + sizeof(uint16_t) + sizeof(uint8_t);
+ return begin() + offset;
+ }
+
+ private:
+ InquiryResponseView() = delete;
+ InquiryResponseView(const PacketView<true>& view) : PacketView(view) {}
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_view.h
new file mode 100644
index 0000000..eee861c
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_view.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2018 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 "inquiry.h"
+#include "packets/link_layer/link_layer_packet_view.h"
+#include "packets/packet_view.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+class InquiryView : public PacketView<true> {
+ public:
+ InquiryView(const InquiryView&) = default;
+ virtual ~InquiryView() = default;
+
+ static InquiryView GetInquiry(const LinkLayerPacketView& view) {
+ CHECK(view.GetType() == Link::PacketType::INQUIRY);
+ return InquiryView(view.GetPayload());
+ }
+
+ Inquiry::InquiryType GetType() {
+ return static_cast<Inquiry::InquiryType>(at(0));
+ }
+
+ private:
+ InquiryView() = delete;
+ InquiryView(const PacketView<true>& view) : PacketView(view) {}
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_builder.h
new file mode 100644
index 0000000..79efb50
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_builder.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2019 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 "base/logging.h"
+
+#include "packets/packet_builder.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+class IoCapabilityBuilder : public PacketBuilder<true> {
+ public:
+ virtual ~IoCapabilityBuilder() = default;
+
+ static std::unique_ptr<IoCapabilityBuilder> Create(uint8_t io_capability, uint8_t oob_data_present,
+ uint8_t authentication_requirements) {
+ return std::unique_ptr<IoCapabilityBuilder>(
+ new IoCapabilityBuilder(io_capability, oob_data_present, authentication_requirements));
+ }
+
+ virtual size_t size() const override {
+ return sizeof(io_capability_) + sizeof(oob_data_present_) + sizeof(authentication_requirements_);
+ }
+
+ protected:
+ virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+ insert(io_capability_, it);
+ insert(oob_data_present_, it);
+ insert(authentication_requirements_, it);
+ }
+
+ private:
+ explicit IoCapabilityBuilder(uint8_t io_capability, uint8_t oob_data_present, uint8_t authentication_requirements)
+ : io_capability_(io_capability), oob_data_present_(oob_data_present),
+ authentication_requirements_(authentication_requirements) {}
+ uint8_t io_capability_;
+ uint8_t oob_data_present_;
+ uint8_t authentication_requirements_;
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_negative_response_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_negative_response_builder.h
new file mode 100644
index 0000000..c9e7601
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_negative_response_builder.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 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 "base/logging.h"
+
+#include "packets/packet_builder.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+class IoCapabilityNegativeResponseBuilder : public PacketBuilder<true> {
+ public:
+ virtual ~IoCapabilityNegativeResponseBuilder() = default;
+
+ static std::unique_ptr<IoCapabilityNegativeResponseBuilder> Create(uint8_t reason) {
+ return std::unique_ptr<IoCapabilityNegativeResponseBuilder>(new IoCapabilityNegativeResponseBuilder(reason));
+ }
+
+ virtual size_t size() const override {
+ return sizeof(reason_);
+ }
+
+ protected:
+ virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+ insert(reason_, it);
+ }
+
+ private:
+ explicit IoCapabilityNegativeResponseBuilder(uint8_t reason) : reason_(reason) {}
+ uint8_t reason_;
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_negative_response_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_negative_response_view.h
new file mode 100644
index 0000000..27c888f
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_negative_response_view.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2018 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 "packets/link_layer/link_layer_packet_view.h"
+#include "packets/packet_view.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+class IoCapabilityNegativeResponseView : public PacketView<true> {
+ public:
+ IoCapabilityNegativeResponseView(const IoCapabilityNegativeResponseView&) = default;
+ virtual ~IoCapabilityNegativeResponseView() = default;
+
+ static IoCapabilityNegativeResponseView GetIoCapabilityNegativeResponse(const LinkLayerPacketView& view) {
+ CHECK(view.GetType() == Link::PacketType::IO_CAPABILITY_NEGATIVE_RESPONSE);
+ return IoCapabilityNegativeResponseView(view.GetPayload());
+ }
+
+ uint8_t GetReason() {
+ return at(0);
+ }
+
+ private:
+ IoCapabilityNegativeResponseView() = delete;
+ IoCapabilityNegativeResponseView(const PacketView<true>& view) : PacketView(view) {}
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_view.h
new file mode 100644
index 0000000..66c7564
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_view.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2018 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 "packets/link_layer/link_layer_packet_view.h"
+#include "packets/packet_view.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+class IoCapabilityView : public PacketView<true> {
+ public:
+ IoCapabilityView(const IoCapabilityView&) = default;
+ virtual ~IoCapabilityView() = default;
+
+ static IoCapabilityView GetIoCapability(const LinkLayerPacketView& view) {
+ CHECK(view.GetType() == Link::PacketType::IO_CAPABILITY_RESPONSE ||
+ view.GetType() == Link::PacketType::IO_CAPABILITY_REQUEST);
+ return IoCapabilityView(view.GetPayload());
+ }
+
+ uint8_t GetIoCapability() {
+ return at(0);
+ }
+ uint8_t GetOobDataPresent() {
+ return at(1);
+ }
+ uint8_t GetAuthenticationRequirements() {
+ return at(2);
+ }
+
+ private:
+ IoCapabilityView() = delete;
+ IoCapabilityView(const PacketView<true>& view) : PacketView(view) {}
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/le_advertisement_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/le_advertisement_builder.h
new file mode 100644
index 0000000..18b3167
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/link_layer/le_advertisement_builder.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2018 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 "base/logging.h"
+
+#include "include/le_advertisement.h"
+#include "packets/packet_builder.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+class LeAdvertisementBuilder : public PacketBuilder<true>, public LeAdvertisement {
+ public:
+ virtual ~LeAdvertisementBuilder() = default;
+
+ static std::unique_ptr<LeAdvertisementBuilder> Create(AddressType address_type, AdvertisementType advertisement_type,
+ const std::vector<uint8_t>& advertisement) {
+ return std::unique_ptr<LeAdvertisementBuilder>(
+ new LeAdvertisementBuilder(address_type, advertisement_type, advertisement));
+ }
+
+ virtual size_t size() const override {
+ return sizeof(address_type_) + sizeof(advertisement_type_) + advertisement_.size();
+ }
+
+ protected:
+ virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+ insert(static_cast<uint8_t>(address_type_), it);
+ insert(static_cast<uint8_t>(advertisement_type_), it);
+ insert_vector(advertisement_, it);
+ }
+
+ private:
+ LeAdvertisementBuilder() = delete;
+ explicit LeAdvertisementBuilder(AddressType address_type, AdvertisementType advertisement_type,
+ const std::vector<uint8_t>& advertisement)
+ : address_type_(address_type), advertisement_type_(advertisement_type), advertisement_(advertisement) {}
+ AddressType address_type_;
+ AdvertisementType advertisement_type_;
+ std::vector<uint8_t> advertisement_;
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/le_advertisement_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/le_advertisement_view.h
new file mode 100644
index 0000000..80e0367
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/link_layer/le_advertisement_view.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2018 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 <log/log.h>
+
+#include "include/link.h"
+#include "packets/link_layer/link_layer_packet_view.h"
+#include "packets/packet_view.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+class LeAdvertisementView : public PacketView<true>, public LeAdvertisement {
+ public:
+ LeAdvertisementView(const LeAdvertisementView&) = default;
+ virtual ~LeAdvertisementView() = default;
+
+ static LeAdvertisementView GetLeAdvertisementView(const LinkLayerPacketView& view) {
+ CHECK(view.GetType() == Link::PacketType::LE_ADVERTISEMENT || view.GetType() == Link::PacketType::LE_SCAN_RESPONSE);
+ return LeAdvertisementView(view.GetPayload());
+ }
+
+ AddressType GetAddressType() {
+ return static_cast<AddressType>(at(0));
+ }
+ AdvertisementType GetAdvertisementType() {
+ return static_cast<AdvertisementType>(at(1));
+ }
+ Iterator<true> GetData() {
+ return begin() + 2 * sizeof(uint8_t);
+ }
+
+ private:
+ LeAdvertisementView() = delete;
+ LeAdvertisementView(const PacketView<true>& view) : PacketView(view) {}
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_builder.cc b/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_builder.cc
new file mode 100644
index 0000000..426244f
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_builder.cc
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2018 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 "link_layer_packet_builder.h"
+#include "link_layer_packet_view.h"
+
+#include "base/logging.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+namespace packets {
+
+LinkLayerPacketBuilder::LinkLayerPacketBuilder(Link::PacketType type, const Address& source, const Address& dest)
+ : type_(type), source_addr_(source), dest_addr_(dest) {}
+
+LinkLayerPacketBuilder::LinkLayerPacketBuilder(Link::PacketType type, std::unique_ptr<PacketBuilder> packet,
+ const Address& source)
+ : type_(type), source_addr_(source), dest_addr_(Address::kEmpty), builder_(std::move(packet)) {}
+
+LinkLayerPacketBuilder::LinkLayerPacketBuilder(Link::PacketType type, std::unique_ptr<PacketBuilder> packet,
+ const Address& source, const Address& dest)
+ : type_(type), source_addr_(source), dest_addr_(dest), builder_(std::move(packet)) {}
+
+std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapAcl(std::unique_ptr<ViewForwarderBuilder> acl,
+ const Address& source, const Address& dest) {
+ return std::shared_ptr<LinkLayerPacketBuilder>(
+ new LinkLayerPacketBuilder(Link::PacketType::ACL, std::move(acl), source, dest));
+}
+
+std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapCommand(std::unique_ptr<CommandBuilder> command,
+ const Address& source,
+ const Address& dest) {
+ return std::shared_ptr<LinkLayerPacketBuilder>(
+ new LinkLayerPacketBuilder(Link::PacketType::COMMAND, std::move(command), source, dest));
+}
+
+std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapDisconnect(
+ std::unique_ptr<DisconnectBuilder> disconnect, const Address& source, const Address& dest) {
+ return std::shared_ptr<LinkLayerPacketBuilder>(
+ new LinkLayerPacketBuilder(Link::PacketType::DISCONNECT, std::move(disconnect), source, dest));
+}
+
+std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapEncryptConnection(
+ std::unique_ptr<EncryptConnectionBuilder> encrypt_connection, const Address& source, const Address& dest) {
+ return std::shared_ptr<LinkLayerPacketBuilder>(
+ new LinkLayerPacketBuilder(Link::PacketType::ENCRYPT_CONNECTION, std::move(encrypt_connection), source, dest));
+}
+
+std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapEncryptConnectionResponse(
+ std::unique_ptr<EncryptConnectionBuilder> encrypt_connection, const Address& source, const Address& dest) {
+ return std::shared_ptr<LinkLayerPacketBuilder>(new LinkLayerPacketBuilder(
+ Link::PacketType::ENCRYPT_CONNECTION_RESPONSE, std::move(encrypt_connection), source, dest));
+}
+
+std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapInquiry(std::unique_ptr<InquiryBuilder> inquiry,
+ const Address& source) {
+ return std::shared_ptr<LinkLayerPacketBuilder>(
+ new LinkLayerPacketBuilder(Link::PacketType::INQUIRY, std::move(inquiry), source));
+}
+
+std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapInquiryResponse(
+ std::unique_ptr<InquiryResponseBuilder> inquiry_response, const Address& source, const Address& dest) {
+ return std::shared_ptr<LinkLayerPacketBuilder>(
+ new LinkLayerPacketBuilder(Link::PacketType::INQUIRY_RESPONSE, std::move(inquiry_response), source, dest));
+}
+
+std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapIoCapabilityRequest(
+ std::unique_ptr<IoCapabilityBuilder> io_capability, const Address& source, const Address& dest) {
+ return std::shared_ptr<LinkLayerPacketBuilder>(
+ new LinkLayerPacketBuilder(Link::PacketType::IO_CAPABILITY_REQUEST, std::move(io_capability), source, dest));
+}
+
+std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapIoCapabilityResponse(
+ std::unique_ptr<IoCapabilityBuilder> io_capability, const Address& source, const Address& dest) {
+ return std::shared_ptr<LinkLayerPacketBuilder>(
+ new LinkLayerPacketBuilder(Link::PacketType::IO_CAPABILITY_RESPONSE, std::move(io_capability), source, dest));
+}
+
+std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapIoCapabilityNegativeResponse(
+ std::unique_ptr<IoCapabilityNegativeResponseBuilder> io_capability_negative_response, const Address& source,
+ const Address& dest) {
+ return std::shared_ptr<LinkLayerPacketBuilder>(new LinkLayerPacketBuilder(
+ Link::PacketType::IO_CAPABILITY_NEGATIVE_RESPONSE, std::move(io_capability_negative_response), source, dest));
+}
+
+std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapLeAdvertisement(
+ std::unique_ptr<LeAdvertisementBuilder> advertisement, const Address& source) {
+ return std::shared_ptr<LinkLayerPacketBuilder>(
+ new LinkLayerPacketBuilder(Link::PacketType::LE_ADVERTISEMENT, std::move(advertisement), source));
+}
+
+std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapLeScan(const Address& source, const Address& dest) {
+ return std::shared_ptr<LinkLayerPacketBuilder>(new LinkLayerPacketBuilder(Link::PacketType::LE_SCAN, source, dest));
+}
+
+std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapLeScanResponse(
+ std::unique_ptr<LeAdvertisementBuilder> scan_response, const Address& source, const Address& dest) {
+ return std::shared_ptr<LinkLayerPacketBuilder>(
+ new LinkLayerPacketBuilder(Link::PacketType::LE_SCAN_RESPONSE, std ::move(scan_response), source, dest));
+}
+
+std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapPage(std::unique_ptr<PageBuilder> page,
+ const Address& source, const Address& dest) {
+ return std::shared_ptr<LinkLayerPacketBuilder>(
+ new LinkLayerPacketBuilder(Link::PacketType::PAGE, std::move(page), source, dest));
+}
+
+std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapPageResponse(
+ std::unique_ptr<PageResponseBuilder> page_response, const Address& source, const Address& dest) {
+ return std::shared_ptr<LinkLayerPacketBuilder>(
+ new LinkLayerPacketBuilder(Link::PacketType::PAGE_RESPONSE, std::move(page_response), source, dest));
+}
+
+std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapResponse(std::unique_ptr<ResponseBuilder> response,
+ const Address& source,
+ const Address& dest) {
+ return std::shared_ptr<LinkLayerPacketBuilder>(
+ new LinkLayerPacketBuilder(Link::PacketType::RESPONSE, std::move(response), source, dest));
+}
+
+std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapSco(std::unique_ptr<ViewForwarderBuilder> sco,
+ const Address& source, const Address& dest) {
+ return std::shared_ptr<LinkLayerPacketBuilder>(
+ new LinkLayerPacketBuilder(Link::PacketType::SCO, std::move(sco), source, dest));
+}
+
+std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::ReWrap(
+ const std::shared_ptr<std::vector<uint8_t>> raw_packet) {
+ LinkLayerPacketView received = LinkLayerPacketView::Create(raw_packet);
+ Link::PacketType packet_type = received.GetType();
+ Address source = received.GetSourceAddress();
+ Address dest = received.GetDestinationAddress();
+ PacketView<true> payload = received.GetPayload();
+ std::unique_ptr<PacketBuilder> builder = ViewForwarderBuilder::Create(payload);
+ return std::shared_ptr<LinkLayerPacketBuilder>(
+ new LinkLayerPacketBuilder(packet_type, std::move(builder), source, dest));
+}
+
+size_t LinkLayerPacketBuilder::size() const {
+ size_t builder_size = (builder_ ? builder_->size() : 0);
+ return Link::kTypeBytes + Link::kSizeBytes + 2 * Address::kLength + builder_size;
+}
+
+void LinkLayerPacketBuilder::Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const {
+ insert(static_cast<uint32_t>(size() - Link::kSizeBytes), it);
+ insert(static_cast<uint8_t>(type_), it);
+ insert_address(source_addr_.address, it);
+ insert_address(dest_addr_.address, it);
+ if (builder_) {
+ builder_->Serialize(it);
+ }
+}
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_builder.h
new file mode 100644
index 0000000..a9d7741
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_builder.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2018 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 <string>
+#include <vector>
+
+#include "link.h"
+#include "packets/link_layer/command_builder.h"
+#include "packets/link_layer/disconnect_builder.h"
+#include "packets/link_layer/encrypt_connection_builder.h"
+#include "packets/link_layer/inquiry_builder.h"
+#include "packets/link_layer/inquiry_response_builder.h"
+#include "packets/link_layer/io_capability_builder.h"
+#include "packets/link_layer/io_capability_negative_response_builder.h"
+#include "packets/link_layer/le_advertisement_builder.h"
+#include "packets/link_layer/page_builder.h"
+#include "packets/link_layer/page_response_builder.h"
+#include "packets/link_layer/response_builder.h"
+#include "packets/link_layer/view_forwarder_builder.h"
+#include "packets/packet_builder.h"
+#include "types/address.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+// Link-layer packets are an abstraction of LMP PDUs.
+class LinkLayerPacketBuilder : PacketBuilder<true> {
+ public:
+ virtual ~LinkLayerPacketBuilder() = default;
+
+ static std::shared_ptr<LinkLayerPacketBuilder> WrapAcl(std::unique_ptr<ViewForwarderBuilder> acl,
+ const Address& source, const Address& dest);
+ static std::shared_ptr<LinkLayerPacketBuilder> WrapCommand(std::unique_ptr<CommandBuilder> command,
+ const Address& source, const Address& dest);
+ static std::shared_ptr<LinkLayerPacketBuilder> WrapDisconnect(std::unique_ptr<DisconnectBuilder> disconnect,
+ const Address& source, const Address& dest);
+ static std::shared_ptr<LinkLayerPacketBuilder> WrapEncryptConnection(
+ std::unique_ptr<EncryptConnectionBuilder> encrypt_connection, const Address& source, const Address& dest);
+ static std::shared_ptr<LinkLayerPacketBuilder> WrapEncryptConnectionResponse(
+ std::unique_ptr<EncryptConnectionBuilder> encrypt_connection, const Address& source, const Address& dest);
+ static std::shared_ptr<LinkLayerPacketBuilder> WrapInquiry(std::unique_ptr<InquiryBuilder> inquiry,
+ const Address& source);
+ static std::shared_ptr<LinkLayerPacketBuilder> WrapInquiryResponse(
+ std::unique_ptr<InquiryResponseBuilder> inquiry_response, const Address& source, const Address& dest);
+ static std::shared_ptr<LinkLayerPacketBuilder> WrapIoCapabilityRequest(
+ std::unique_ptr<IoCapabilityBuilder> io_capability, const Address& source, const Address& dest);
+ static std::shared_ptr<LinkLayerPacketBuilder> WrapIoCapabilityResponse(
+ std::unique_ptr<IoCapabilityBuilder> io_capability, const Address& source, const Address& dest);
+ static std::shared_ptr<LinkLayerPacketBuilder> WrapIoCapabilityNegativeResponse(
+ std::unique_ptr<IoCapabilityNegativeResponseBuilder> io_capability_negative_response, const Address& source,
+ const Address& dest);
+ static std::shared_ptr<LinkLayerPacketBuilder> WrapLeAdvertisement(
+ std::unique_ptr<LeAdvertisementBuilder> advertisement, const Address& source);
+ static std::shared_ptr<LinkLayerPacketBuilder> WrapLeScan(const Address& source, const Address& dest);
+ static std::shared_ptr<LinkLayerPacketBuilder> WrapLeScanResponse(
+ std::unique_ptr<LeAdvertisementBuilder> scan_response, const Address& source, const Address& dest);
+ static std::shared_ptr<LinkLayerPacketBuilder> WrapPage(std::unique_ptr<PageBuilder> page, const Address& source,
+ const Address& dest);
+ static std::shared_ptr<LinkLayerPacketBuilder> WrapPageResponse(std::unique_ptr<PageResponseBuilder> page_response,
+ const Address& source, const Address& dest);
+ static std::shared_ptr<LinkLayerPacketBuilder> WrapResponse(const std::unique_ptr<ResponseBuilder> response,
+ const Address& source, const Address& dest);
+ static std::shared_ptr<LinkLayerPacketBuilder> WrapSco(std::unique_ptr<ViewForwarderBuilder> sco,
+ const Address& source, const Address& dest);
+ static std::shared_ptr<LinkLayerPacketBuilder> ReWrap(const std::shared_ptr<std::vector<uint8_t>> raw_packet);
+
+ virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override;
+
+ virtual size_t size() const override;
+
+ private:
+ LinkLayerPacketBuilder(const LinkLayerPacketBuilder&) = delete;
+ LinkLayerPacketBuilder() = delete;
+ LinkLayerPacketBuilder(Link::PacketType type, const Address& source, const Address& dest);
+ LinkLayerPacketBuilder(Link::PacketType type, std::unique_ptr<PacketBuilder> builder, const Address& source,
+ const Address& dest);
+ LinkLayerPacketBuilder(Link::PacketType type, std::unique_ptr<PacketBuilder> builder, const Address& source);
+ Link::PacketType type_;
+ Address source_addr_;
+ Address dest_addr_;
+ std::unique_ptr<PacketBuilder> builder_;
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_view.cc b/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_view.cc
new file mode 100644
index 0000000..04518ca
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_view.cc
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2018 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 "link_layer_packet_view.h"
+#include "base/logging.h"
+
+namespace test_vendor_lib {
+constexpr size_t Link::kSizeBytes;
+constexpr size_t Link::kTypeBytes;
+
+namespace packets {
+LinkLayerPacketView::LinkLayerPacketView(std::shared_ptr<std::vector<uint8_t>> raw) : PacketView<true>(raw) {}
+
+LinkLayerPacketView LinkLayerPacketView::Create(std::shared_ptr<std::vector<uint8_t>> raw) {
+ CHECK(raw->size() >= Link::kSizeBytes + Link::kTypeBytes + 2 * Address::kLength);
+ return LinkLayerPacketView(raw);
+}
+
+Link::PacketType LinkLayerPacketView::GetType() const {
+ return static_cast<Link::PacketType>(at(Link::kSizeBytes));
+}
+
+Address LinkLayerPacketView::GetSourceAddress() const {
+ size_t offset = Link::kSizeBytes + Link::kTypeBytes;
+ return (begin() + offset).extract<Address>();
+}
+
+Address LinkLayerPacketView::GetDestinationAddress() const {
+ size_t offset = Link::kSizeBytes + Link::kTypeBytes + Address::kLength;
+ return (begin() + offset).extract<Address>();
+}
+
+PacketView<true> LinkLayerPacketView::GetPayload() const {
+ return SubViewLittleEndian(Link::kSizeBytes + Link::kTypeBytes + 2 * Address::kLength, size());
+}
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_view.h
new file mode 100644
index 0000000..bdbfaa7
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_view.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2018 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 <string>
+#include <vector>
+
+#include "include/link.h"
+#include "packets/packet_view.h"
+#include "types/address.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+// Link-layer packets are an abstraction of LMP PDUs.
+class LinkLayerPacketView : public PacketView<true> {
+ public:
+ LinkLayerPacketView(const LinkLayerPacketView&) = default;
+ virtual ~LinkLayerPacketView() = default;
+
+ static LinkLayerPacketView Create(std::shared_ptr<std::vector<uint8_t>> raw);
+
+ Link::PacketType GetType() const;
+ Address GetSourceAddress() const;
+ Address GetDestinationAddress() const;
+ PacketView<true> GetPayload() const;
+
+ private:
+ LinkLayerPacketView() = delete;
+ LinkLayerPacketView(std::shared_ptr<std::vector<uint8_t>> raw);
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/page_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/page_builder.h
new file mode 100644
index 0000000..0e18cb3
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/link_layer/page_builder.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2018 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 <base/logging.h>
+
+#include "packets/packet_builder.h"
+#include "types/class_of_device.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+class PageBuilder : public PacketBuilder<true> {
+ public:
+ virtual ~PageBuilder() = default;
+
+ static std::unique_ptr<PageBuilder> Create(const ClassOfDevice& class_of_device, uint8_t allow_role_switch) {
+ return std::unique_ptr<PageBuilder>(new PageBuilder(class_of_device, allow_role_switch));
+ }
+
+ virtual size_t size() const override {
+ return sizeof(class_of_device_) + sizeof(allow_role_switch_);
+ }
+
+ protected:
+ virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+ insert_class_of_device(class_of_device_, it);
+ insert(allow_role_switch_, it);
+ }
+
+ private:
+ explicit PageBuilder(const ClassOfDevice& class_of_device, uint8_t allow_role_switch)
+ : class_of_device_(class_of_device), allow_role_switch_(allow_role_switch) {}
+ ClassOfDevice class_of_device_;
+ uint8_t allow_role_switch_;
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/page_response_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/page_response_builder.h
new file mode 100644
index 0000000..78f9a80
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/link_layer/page_response_builder.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2018 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 "base/logging.h"
+
+#include "packets/packet_builder.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+class PageResponseBuilder : public PacketBuilder<true> {
+ public:
+ virtual ~PageResponseBuilder() = default;
+
+ static std::unique_ptr<PageResponseBuilder> Create(uint8_t try_role_switch) {
+ return std::unique_ptr<PageResponseBuilder>(new PageResponseBuilder(try_role_switch));
+ }
+
+ virtual size_t size() const override {
+ return sizeof(try_role_switch_);
+ }
+
+ protected:
+ virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+ insert(try_role_switch_, it);
+ }
+
+ private:
+ explicit PageResponseBuilder(uint8_t try_role_switch) : try_role_switch_(try_role_switch) {}
+ uint8_t try_role_switch_;
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/page_response_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/page_response_view.h
new file mode 100644
index 0000000..20f0b68
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/link_layer/page_response_view.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2018 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 "packets/link_layer/link_layer_packet_view.h"
+#include "packets/packet_view.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+class PageResponseView : public PacketView<true> {
+ public:
+ PageResponseView(const PageResponseView&) = default;
+ virtual ~PageResponseView() = default;
+
+ static PageResponseView GetPageResponse(const LinkLayerPacketView& view) {
+ CHECK(view.GetType() == Link::PacketType::PAGE_RESPONSE);
+ return PageResponseView(view.GetPayload());
+ }
+
+ uint8_t GetTryRoleSwitch() {
+ return at(0);
+ }
+
+ private:
+ PageResponseView() = delete;
+ PageResponseView(const PacketView<true>& view) : PacketView(view) {}
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/page_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/page_view.h
new file mode 100644
index 0000000..a26446d
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/link_layer/page_view.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2018 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 "packets/link_layer/link_layer_packet_view.h"
+#include "packets/packet_view.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+class PageView : public PacketView<true> {
+ public:
+ PageView(const PageView&) = default;
+ virtual ~PageView() = default;
+
+ static PageView GetPage(const LinkLayerPacketView& view) {
+ CHECK(view.GetType() == Link::PacketType::PAGE);
+ return PageView(view.GetPayload());
+ }
+
+ ClassOfDevice GetClassOfDevice() {
+ return begin().extract<ClassOfDevice>();
+ }
+
+ uint8_t GetAllowRoleSwitch() {
+ return at(3);
+ }
+
+ private:
+ PageView() = delete;
+ PageView(const PacketView<true>& view) : PacketView(view) {}
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/response_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/response_builder.h
new file mode 100644
index 0000000..18f765d
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/link_layer/response_builder.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2018 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 "packets/packet_builder.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+class ResponseBuilder : public PacketBuilder<true> {
+ public:
+ virtual ~ResponseBuilder() = default;
+
+ static std::unique_ptr<ResponseBuilder> Create(uint16_t opcode, const std::vector<uint64_t>& data) {
+ return std::unique_ptr<ResponseBuilder>(new ResponseBuilder(opcode, data));
+ }
+
+ virtual size_t size() const override {
+ return sizeof(opcode_) + data_.size() * sizeof(uint64_t);
+ }
+
+ protected:
+ virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+ insert(opcode_, it);
+ insert_vector(data_, it);
+ }
+
+ private:
+ explicit ResponseBuilder(uint16_t opcode, const std::vector<uint64_t> data) : opcode_(opcode), data_(data) {}
+ uint16_t opcode_;
+ std::vector<uint64_t> data_;
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/response_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/response_view.h
new file mode 100644
index 0000000..f1ff7c9
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/link_layer/response_view.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2018 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 <log/log.h>
+
+#include "packets/link_layer/link_layer_packet_view.h"
+#include "packets/packet_view.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+class ResponseView : public PacketView<true> {
+ public:
+ ResponseView(const ResponseView&) = default;
+ virtual ~ResponseView() = default;
+
+ static ResponseView GetResponse(const LinkLayerPacketView& view) {
+ CHECK(view.GetType() == Link::PacketType::RESPONSE);
+ return ResponseView(view.GetPayload());
+ }
+
+ uint16_t GetOpcode() {
+ return begin().extract<uint16_t>();
+ }
+
+ Iterator<true> GetResponseData() {
+ return begin() + sizeof(uint16_t);
+ }
+
+ private:
+ ResponseView() = delete;
+ ResponseView(const PacketView<true>& view) : PacketView(view) {}
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/view_forwarder_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/view_forwarder_builder.h
new file mode 100644
index 0000000..da0d827
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/link_layer/view_forwarder_builder.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2018 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 "base/logging.h"
+
+#include "packets/packet_builder.h"
+#include "packets/packet_view.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+class ViewForwarderBuilder : public PacketBuilder<true> {
+ public:
+ virtual ~ViewForwarderBuilder() = default;
+
+ static std::unique_ptr<ViewForwarderBuilder> Create(PacketView<true> view) {
+ return std::unique_ptr<ViewForwarderBuilder>(new ViewForwarderBuilder(view));
+ }
+
+ virtual size_t size() const override {
+ return view_.size();
+ }
+
+ virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+ for (size_t i = 0; i < view_.size(); i++) {
+ insert(view_[i], it);
+ }
+ }
+
+ private:
+ explicit ViewForwarderBuilder(PacketView<true> view) : view_(view) {}
+ PacketView<true> view_;
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/packet_builder.h b/vendor_libs/test_vendor_lib/packets/packet_builder.h
new file mode 100644
index 0000000..947b02a
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/packet_builder.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2018 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 <forward_list>
+#include <iterator>
+#include <memory>
+#include <vector>
+
+#include "base_packet_builder.h"
+#include "types/address.h"
+#include "types/class_of_device.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+// Abstract base class that is subclassed to build specifc packets.
+// The template parameter little_endian controls the generation of insert().
+template <bool little_endian>
+class PacketBuilder : public BasePacketBuilder {
+ public:
+ PacketBuilder() = default;
+ virtual ~PacketBuilder() = default;
+
+ // Classes which need fragmentation should define a function like this:
+ // std::forward_list<DerivedBuilder>& Fragment(size_t max_size);
+
+ protected:
+ // Write sizeof(FixedWidthIntegerType) bytes using the iterator
+ template <typename FixedWidthIntegerType,
+ typename std::enable_if<std::is_integral<FixedWidthIntegerType>::value, int>::type = 0>
+ void insert(FixedWidthIntegerType value, std::back_insert_iterator<std::vector<uint8_t>> it) const {
+ for (size_t i = 0; i < sizeof(FixedWidthIntegerType); i++) {
+ if (little_endian == true) {
+ *it = static_cast<uint8_t>(value >> (i * 8));
+ } else {
+ *it = static_cast<uint8_t>(value >> ((sizeof(FixedWidthIntegerType) - i - 1) * 8));
+ }
+ it++;
+ }
+ }
+
+ // Specialized insert that allows inserting enums without casting
+ template <typename Enum, typename std::enable_if<std::is_enum_v<Enum>, int>::type = 0>
+ inline void insert(Enum value, std::back_insert_iterator<std::vector<uint8_t>> it) const {
+ using enum_type = typename std::underlying_type_t<Enum>;
+ static_assert(std::is_unsigned_v<enum_type>, "Enum type is signed. Did you forget to specify the enum size?");
+ insert<enum_type>(static_cast<enum_type>(value), it);
+ }
+
+ // Write a vector of FixedWidthIntegerType using the iterator
+ template <typename FixedWidthIntegerType>
+ void insert_vector(const std::vector<FixedWidthIntegerType>& vec,
+ std::back_insert_iterator<std::vector<uint8_t>> it) const {
+ static_assert(std::is_integral<FixedWidthIntegerType>::value,
+ "PacketBuilder::insert requires an integral type vector.");
+ for (const auto& element : vec) {
+ insert(element, it);
+ }
+ }
+
+ void insert_address(const Address& addr, std::back_insert_iterator<std::vector<uint8_t>> it) const {
+ for (const auto& element : addr.address) {
+ insert(element, it);
+ }
+ }
+
+ void insert_class_of_device(const ClassOfDevice& cod, std::back_insert_iterator<std::vector<uint8_t>> it) const {
+ for (const auto& element : cod.cod) {
+ insert(element, it);
+ }
+ }
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/packet_view.cc b/vendor_libs/test_vendor_lib/packets/packet_view.cc
new file mode 100644
index 0000000..7ffe71a
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/packet_view.cc
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2018 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 "packet_view.h"
+
+#include <algorithm>
+
+#include <base/logging.h>
+
+namespace test_vendor_lib {
+namespace packets {
+
+template <bool little_endian>
+PacketView<little_endian>::PacketView(const std::forward_list<class View> fragments)
+ : fragments_(fragments), length_(0) {
+ for (auto fragment : fragments_) {
+ length_ += fragment.size();
+ }
+}
+
+template <bool little_endian>
+PacketView<little_endian>::PacketView(std::shared_ptr<std::vector<uint8_t>> packet)
+ : fragments_({View(packet, 0, packet->size())}), length_(packet->size()) {}
+
+template <bool little_endian>
+Iterator<little_endian> PacketView<little_endian>::begin() const {
+ return Iterator<little_endian>(this->fragments_, 0);
+}
+
+template <bool little_endian>
+Iterator<little_endian> PacketView<little_endian>::end() const {
+ return Iterator<little_endian>(this->fragments_, size());
+}
+
+template <bool little_endian>
+uint8_t PacketView<little_endian>::operator[](size_t index) const {
+ return at(index);
+}
+
+template <bool little_endian>
+uint8_t PacketView<little_endian>::at(size_t index) const {
+ CHECK(index < length_) << "Index " << index << " out of bounds";
+ for (const auto& fragment : fragments_) {
+ if (index < fragment.size()) {
+ return fragment[index];
+ }
+ index -= fragment.size();
+ }
+ CHECK(false) << "Out of fragments searching for Index " << index;
+ return 0;
+}
+
+template <bool little_endian>
+size_t PacketView<little_endian>::size() const {
+ return length_;
+}
+
+template <bool little_endian>
+std::forward_list<View> PacketView<little_endian>::SubViewList(size_t begin, size_t end) const {
+ CHECK(begin <= end) << "Begin " << begin << " is past end";
+ CHECK(end <= length_) << "End " << end << " is too large";
+ std::forward_list<View> view_list;
+ std::forward_list<View>::iterator it = view_list.before_begin();
+ size_t length = end - begin;
+ for (const auto& fragment : fragments_) {
+ if (begin >= fragment.size()) {
+ begin -= fragment.size();
+ } else {
+ View view(fragment, begin, begin + std::min(length, fragment.size() - begin));
+ length -= view.size();
+ it = view_list.insert_after(it, view);
+ begin = 0;
+ }
+ }
+ return view_list;
+}
+
+template <bool little_endian>
+PacketView<true> PacketView<little_endian>::SubViewLittleEndian(size_t begin, size_t end) const {
+ return PacketView<true>(SubViewList(begin, end));
+}
+
+template <bool little_endian>
+PacketView<false> PacketView<little_endian>::SubViewBigEndian(size_t begin, size_t end) const {
+ return PacketView<false>(SubViewList(begin, end));
+}
+
+// Explicit instantiations for both types of PacketViews.
+template class PacketView<true>;
+template class PacketView<false>;
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/packet_view.h b/vendor_libs/test_vendor_lib/packets/packet_view.h
new file mode 100644
index 0000000..16255fa
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/packet_view.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2018 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 <forward_list>
+
+#include "iterator.h"
+#include "view.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+// Abstract base class that is subclassed to provide type-specifc accessors.
+// Holds a shared pointer to the underlying data.
+// The template parameter little_endian controls the generation of extract().
+template <bool little_endian>
+class PacketView {
+ public:
+ PacketView(const std::forward_list<class View> fragments);
+ PacketView(const PacketView& PacketView) = default;
+ virtual ~PacketView() = default;
+
+ virtual Iterator<little_endian> begin() const;
+
+ virtual Iterator<little_endian> end() const;
+
+ uint8_t operator[](size_t i) const;
+
+ uint8_t at(size_t index) const;
+
+ size_t size() const;
+
+ PacketView<true> SubViewLittleEndian(size_t begin, size_t end) const;
+
+ PacketView<false> SubViewBigEndian(size_t begin, size_t end) const;
+
+ protected:
+ PacketView(std::shared_ptr<std::vector<uint8_t>> packet);
+
+ private:
+ std::forward_list<View> fragments_;
+ size_t length_;
+ PacketView<little_endian>() = delete;
+ std::forward_list<View> SubViewList(size_t begin, size_t end) const;
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/raw_builder.cc b/vendor_libs/test_vendor_lib/packets/raw_builder.cc
new file mode 100644
index 0000000..794fbb7
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/raw_builder.cc
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2018 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 "raw_builder.h"
+
+#include <base/logging.h>
+#include <algorithm>
+
+using std::vector;
+
+namespace test_vendor_lib {
+namespace packets {
+
+RawBuilder::RawBuilder(size_t max_bytes) : max_bytes_(max_bytes) {}
+
+bool RawBuilder::AddOctets(size_t octets, const vector<uint8_t>& bytes) {
+ if (payload_.size() + octets > max_bytes_) return false;
+
+ if (octets != bytes.size()) return false;
+
+ payload_.insert(payload_.end(), bytes.begin(), bytes.end());
+
+ return true;
+}
+
+bool RawBuilder::AddOctets(const vector<uint8_t>& bytes) {
+ return AddOctets(bytes.size(), bytes);
+}
+
+bool RawBuilder::AddOctets(size_t octets, uint64_t value) {
+ vector<uint8_t> val_vector;
+
+ uint64_t v = value;
+
+ if (octets > sizeof(uint64_t)) return false;
+
+ for (size_t i = 0; i < octets; i++) {
+ val_vector.push_back(v & 0xff);
+ v = v >> 8;
+ }
+
+ if (v != 0) return false;
+
+ return AddOctets(octets, val_vector);
+}
+
+bool RawBuilder::AddAddress(const Address& address) {
+ if (payload_.size() + Address::kLength > max_bytes_) return false;
+
+ for (size_t i = 0; i < Address::kLength; i++) {
+ payload_.push_back(address.address[i]);
+ }
+ return true;
+}
+
+bool RawBuilder::AddOctets1(uint8_t value) {
+ return AddOctets(1, value);
+}
+
+bool RawBuilder::AddOctets2(uint16_t value) {
+ return AddOctets(2, value);
+}
+
+bool RawBuilder::AddOctets3(uint32_t value) {
+ return AddOctets(3, value);
+}
+
+bool RawBuilder::AddOctets4(uint32_t value) {
+ return AddOctets(4, value);
+}
+
+bool RawBuilder::AddOctets6(uint64_t value) {
+ return AddOctets(6, value);
+}
+
+bool RawBuilder::AddOctets8(uint64_t value) {
+ return AddOctets(8, value);
+}
+
+bool RawBuilder::CanAddOctets(size_t num_bytes) const {
+ return payload_.size() + num_bytes <= max_bytes_;
+}
+
+void RawBuilder::Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const {
+ for (const auto& val : payload_) {
+ insert(val, it);
+ }
+}
+
+size_t RawBuilder::size() const {
+ return payload_.size();
+}
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/raw_builder.h b/vendor_libs/test_vendor_lib/packets/raw_builder.h
new file mode 100644
index 0000000..cbc7d6f
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/raw_builder.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2018 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 "packets/packet_builder.h"
+#include "types/address.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+class RawBuilder : public PacketBuilder<true> {
+ public:
+ RawBuilder() = default;
+ RawBuilder(size_t max_bytes);
+ virtual ~RawBuilder() = default;
+
+ virtual size_t size() const override;
+
+ virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const;
+
+ // Add |address| to the payload. Return true if:
+ // - the new size of the payload is still <= |max_bytes_|
+ bool AddAddress(const Address& address);
+
+ // Return true if |num_bytes| can be added to the payload.
+ bool CanAddOctets(size_t num_bytes) const;
+
+ // Add |octets| bytes to the payload. Return true if:
+ // - the size of |bytes| is equal to |octets| and
+ // - the new size of the payload is still <= |max_bytes_|
+ bool AddOctets(size_t octets, const std::vector<uint8_t>& bytes);
+
+ bool AddOctets(const std::vector<uint8_t>& bytes);
+
+ bool AddOctets1(uint8_t value);
+ bool AddOctets2(uint16_t value);
+ bool AddOctets3(uint32_t value);
+ bool AddOctets4(uint32_t value);
+ bool AddOctets6(uint64_t value);
+ bool AddOctets8(uint64_t value);
+
+ private:
+ // Add |octets| bytes to the payload. Return true if:
+ // - the value of |value| fits in |octets| bytes and
+ // - the new size of the payload is still <= |max_bytes_|
+ bool AddOctets(size_t octets, uint64_t value);
+
+ size_t max_bytes_{255};
+
+ // Underlying containers for storing the actual packet
+ std::vector<uint8_t> payload_;
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/test/counted_builder_test.cc b/vendor_libs/test_vendor_lib/packets/test/counted_builder_test.cc
new file mode 100644
index 0000000..bedc228
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/test/counted_builder_test.cc
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2018 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 "packets/counted_builder.h"
+
+#include <gtest/gtest.h>
+#include <forward_list>
+#include <memory>
+
+#include "types/address.h"
+
+using std::vector;
+
+namespace {
+vector<uint8_t> count = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+};
+
+} // namespace
+
+namespace test_vendor_lib {
+namespace packets {
+
+class CountedBuilderTest : public ::testing::Test {
+ public:
+ CountedBuilderTest() = default;
+ ~CountedBuilderTest() override = default;
+};
+
+TEST(CountedBuilderTest, buildCountTest) {
+ std::unique_ptr<CountedBuilder> count_builder = std::make_unique<CountedBuilder>();
+ ASSERT_EQ(1u, count_builder->size());
+ std::unique_ptr<RawBuilder> raw1 = std::make_unique<RawBuilder>();
+ std::unique_ptr<RawBuilder> raw2 = std::make_unique<RawBuilder>();
+ std::unique_ptr<RawBuilder> raw3 = std::make_unique<RawBuilder>();
+ std::unique_ptr<RawBuilder> raw4 = std::make_unique<RawBuilder>();
+ std::unique_ptr<RawBuilder> raw5 = std::make_unique<RawBuilder>();
+ std::unique_ptr<RawBuilder> raw6 = std::make_unique<RawBuilder>();
+ std::unique_ptr<RawBuilder> raw7 = std::make_unique<RawBuilder>();
+ raw1->AddOctets8(0x0706050403020100);
+ raw2->AddOctets4(0x0b0a0908);
+ raw3->AddOctets2(0x0d0c);
+ raw4->AddOctets1(0x0e);
+ raw5->AddOctets1(0x0f);
+ raw6->AddAddress(Address({0x10, 0x11, 0x12, 0x13, 0x14, 0x15}));
+ std::vector<uint8_t> count_subset(count.begin() + 0x16, count.end());
+ raw7->AddOctets(count_subset);
+
+ count_builder->Add(std::move(raw1));
+ count_builder->Add(std::move(raw2));
+ count_builder->Add(std::move(raw3));
+ count_builder->Add(std::move(raw4));
+ count_builder->Add(std::move(raw5));
+ count_builder->Add(std::move(raw6));
+ count_builder->Add(std::move(raw7));
+
+ ASSERT_EQ(count.size(), count_builder->size() - 1);
+
+ std::vector<uint8_t> packet;
+ std::back_insert_iterator<std::vector<uint8_t>> it(packet);
+
+ count_builder->Serialize(it);
+ ASSERT_EQ(7u, packet[0]);
+ std::vector<uint8_t> payload_packet(packet.begin() + 1, packet.end());
+
+ ASSERT_EQ(count, payload_packet);
+}
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/test/link_layer_packet_builder_test.cc b/vendor_libs/test_vendor_lib/packets/test/link_layer_packet_builder_test.cc
new file mode 100644
index 0000000..22ef70f
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/test/link_layer_packet_builder_test.cc
@@ -0,0 +1,514 @@
+/*
+ * Copyright 2018 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 "packets/link_layer/link_layer_packet_builder.h"
+
+#include <gtest/gtest.h>
+#include <forward_list>
+#include <memory>
+
+#include "link.h"
+#include "packets/link_layer/command_view.h"
+#include "packets/link_layer/disconnect_view.h"
+#include "packets/link_layer/encrypt_connection_view.h"
+#include "packets/link_layer/inquiry_response_view.h"
+#include "packets/link_layer/inquiry_view.h"
+#include "packets/link_layer/io_capability_negative_response_view.h"
+#include "packets/link_layer/io_capability_view.h"
+#include "packets/link_layer/le_advertisement_view.h"
+#include "packets/link_layer/page_response_view.h"
+#include "packets/link_layer/page_view.h"
+#include "packets/link_layer/response_view.h"
+
+#include "base/logging.h"
+
+using std::vector;
+
+namespace {
+vector<uint8_t> count = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+};
+
+} // namespace
+
+namespace test_vendor_lib {
+namespace packets {
+
+class LinkLayerPacketBuilderTest : public ::testing::Test {
+ public:
+ LinkLayerPacketBuilderTest() = default;
+ ~LinkLayerPacketBuilderTest() override = default;
+
+ Address source_{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ Address dest_{{0x11, 0x12, 0x13, 0x14, 0x15, 0x16}};
+};
+
+TEST_F(LinkLayerPacketBuilderTest, constructorTest) {
+ uint8_t reason = 0xf2;
+ auto disconnect = DisconnectBuilder::Create(reason);
+ ASSERT_EQ(disconnect->size(), sizeof(reason));
+ auto wrapped_disconnect = LinkLayerPacketBuilder::WrapDisconnect(std::move(disconnect), source_, dest_);
+
+ size_t wrapped_size = sizeof(uint8_t) + sizeof(uint32_t) + 2 * sizeof(Address) + sizeof(reason);
+ ASSERT_EQ(wrapped_disconnect->size(), wrapped_size);
+ std::vector<uint8_t> wrapped_vect;
+ std::back_insert_iterator<std::vector<uint8_t>> it(wrapped_vect);
+ wrapped_disconnect->Serialize(it);
+ ASSERT_EQ(wrapped_size, wrapped_vect.size());
+
+ std::vector<uint8_t> hand_wrapped_vect;
+ // Add the size
+ hand_wrapped_vect.push_back(sizeof(uint8_t) + 2 * sizeof(Address) + sizeof(reason));
+ hand_wrapped_vect.push_back(0);
+ hand_wrapped_vect.push_back(0);
+ hand_wrapped_vect.push_back(0);
+
+ hand_wrapped_vect.push_back(static_cast<uint8_t>(Link::PacketType::DISCONNECT));
+
+ for (auto byte : source_.address) {
+ hand_wrapped_vect.push_back(byte);
+ }
+ for (auto byte : dest_.address) {
+ hand_wrapped_vect.push_back(byte);
+ }
+ hand_wrapped_vect.push_back(reason);
+ ASSERT_EQ(wrapped_vect, hand_wrapped_vect);
+}
+
+TEST_F(LinkLayerPacketBuilderTest, disconnectTest) {
+ uint8_t reason = 0x32;
+ auto disconnect_builder = DisconnectBuilder::Create(reason);
+ auto wrapped_disconnect = LinkLayerPacketBuilder::WrapDisconnect(std::move(disconnect_builder), source_, dest_);
+ std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
+ std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
+ wrapped_disconnect->Serialize(it);
+
+ LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
+ ASSERT_EQ(view.size(), wrapped_disconnect->size());
+ ASSERT_EQ(view.GetType(), Link::PacketType::DISCONNECT);
+ ASSERT_EQ(source_, view.GetSourceAddress());
+ ASSERT_EQ(dest_, view.GetDestinationAddress());
+ DisconnectView disconnect = DisconnectView::GetDisconnect(view);
+ ASSERT_EQ(disconnect.GetReason(), reason);
+}
+
+TEST_F(LinkLayerPacketBuilderTest, encryptConnectionTest) {
+ std::vector<uint8_t> key = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+ auto encrypt_connection_builder = EncryptConnectionBuilder::Create(key);
+ auto wrapped_encrypt_connection =
+ LinkLayerPacketBuilder::WrapEncryptConnection(std::move(encrypt_connection_builder), source_, dest_);
+ std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
+ std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
+ wrapped_encrypt_connection->Serialize(it);
+
+ LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
+ ASSERT_EQ(view.size(), wrapped_encrypt_connection->size());
+ ASSERT_EQ(view.GetType(), Link::PacketType::ENCRYPT_CONNECTION);
+ ASSERT_EQ(source_, view.GetSourceAddress());
+ ASSERT_EQ(dest_, view.GetDestinationAddress());
+ EncryptConnectionView encrypt_connection = EncryptConnectionView::GetEncryptConnection(view);
+ auto key_itr = encrypt_connection.GetKey();
+ ASSERT_EQ(key_itr.NumBytesRemaining(), key.size());
+ for (size_t i = 0; i < key.size(); i++) {
+ ASSERT_EQ(key[i], key_itr.extract<uint8_t>());
+ }
+}
+
+TEST_F(LinkLayerPacketBuilderTest, encryptConnectionResponseTest) {
+ std::vector<uint8_t> key = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+ auto encrypt_connection_builder = EncryptConnectionBuilder::Create(key);
+ auto wrapped_encrypt_connection_response =
+ LinkLayerPacketBuilder::WrapEncryptConnectionResponse(std::move(encrypt_connection_builder), source_, dest_);
+ std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
+ std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
+ wrapped_encrypt_connection_response->Serialize(it);
+
+ LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
+ ASSERT_EQ(view.size(), wrapped_encrypt_connection_response->size());
+ ASSERT_EQ(view.GetType(), Link::PacketType::ENCRYPT_CONNECTION_RESPONSE);
+ ASSERT_EQ(source_, view.GetSourceAddress());
+ ASSERT_EQ(dest_, view.GetDestinationAddress());
+ EncryptConnectionView encrypt_connection = EncryptConnectionView::GetEncryptConnection(view);
+ auto key_itr = encrypt_connection.GetKey();
+ ASSERT_EQ(key_itr.NumBytesRemaining(), key.size());
+ for (size_t i = 0; i < key.size(); i++) {
+ ASSERT_EQ(key[i], key_itr.extract<uint8_t>());
+ }
+}
+
+TEST_F(LinkLayerPacketBuilderTest, inquiryTest) {
+ Inquiry::InquiryType inquiry_type = Inquiry::InquiryType::RSSI;
+ auto inquiry_builder = InquiryBuilder::Create(inquiry_type);
+ auto wrapped_inquiry = LinkLayerPacketBuilder::WrapInquiry(std::move(inquiry_builder), source_);
+ std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
+ std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
+ wrapped_inquiry->Serialize(it);
+
+ LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
+ ASSERT_EQ(view.size(), wrapped_inquiry->size());
+ ASSERT_EQ(view.GetType(), Link::PacketType::INQUIRY);
+ ASSERT_EQ(source_, view.GetSourceAddress());
+ ASSERT_EQ(Address::kEmpty, view.GetDestinationAddress());
+ ASSERT_EQ(InquiryView::GetInquiry(view).GetType(), inquiry_type);
+}
+
+TEST_F(LinkLayerPacketBuilderTest, standardInquiryResponseTest) {
+ uint8_t mode = 23;
+ ClassOfDevice class_of_device{{0x11, 0x22, 0x33}};
+ uint16_t offset = 0x3456;
+ auto inquiry_response_builder = InquiryResponseBuilder::CreateStandard(mode, class_of_device, offset);
+ auto wrapped_inquiry =
+ LinkLayerPacketBuilder::WrapInquiryResponse(std::move(inquiry_response_builder), source_, dest_);
+ std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
+ std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
+ wrapped_inquiry->Serialize(it);
+ ASSERT_EQ(packet_ptr->size(), 24u);
+
+ LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
+ ASSERT_EQ(view.size(), wrapped_inquiry->size());
+ ASSERT_EQ(view.GetType(), Link::PacketType::INQUIRY_RESPONSE);
+ ASSERT_EQ(source_, view.GetSourceAddress());
+ ASSERT_EQ(dest_, view.GetDestinationAddress());
+ ASSERT_EQ(view.GetPayload().size(), 7u);
+ InquiryResponseView inquiry_response = InquiryResponseView::GetInquiryResponse(view);
+ ASSERT_EQ(inquiry_response.GetClockOffset(), offset);
+ ASSERT_EQ(inquiry_response.GetType(), Inquiry::InquiryType::STANDARD);
+ ASSERT_EQ(inquiry_response.GetPageScanRepetitionMode(), mode);
+ ASSERT_EQ(inquiry_response.GetClassOfDevice(), class_of_device);
+ ASSERT_EQ(inquiry_response.GetClockOffset(), offset);
+}
+
+TEST_F(LinkLayerPacketBuilderTest, rssiInquiryResponseTest) {
+ uint8_t mode = 23;
+ ClassOfDevice class_of_device{{0x11, 0x22, 0x33}};
+ uint16_t offset = 0x3456;
+ uint8_t rssi = 0x78;
+ auto inquiry_response_builder = InquiryResponseBuilder::CreateRssi(mode, class_of_device, offset, rssi);
+ auto wrapped_inquiry =
+ LinkLayerPacketBuilder::WrapInquiryResponse(std::move(inquiry_response_builder), source_, dest_);
+ std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
+ std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
+ wrapped_inquiry->Serialize(it);
+
+ LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
+ ASSERT_EQ(view.size(), wrapped_inquiry->size());
+ ASSERT_EQ(view.GetType(), Link::PacketType::INQUIRY_RESPONSE);
+ ASSERT_EQ(source_, view.GetSourceAddress());
+ ASSERT_EQ(dest_, view.GetDestinationAddress());
+ InquiryResponseView inquiry_response = InquiryResponseView::GetInquiryResponse(view);
+ ASSERT_EQ(inquiry_response.GetClockOffset(), offset);
+ ASSERT_EQ(inquiry_response.GetType(), Inquiry::InquiryType::RSSI);
+ ASSERT_EQ(inquiry_response.GetPageScanRepetitionMode(), mode);
+ ASSERT_EQ(inquiry_response.GetClassOfDevice(), class_of_device);
+ ASSERT_EQ(inquiry_response.GetClockOffset(), offset);
+ ASSERT_EQ(inquiry_response.GetRssi(), rssi);
+}
+
+TEST_F(LinkLayerPacketBuilderTest, extendedInquiryResponseTest) {
+ uint8_t mode = 23;
+ ClassOfDevice class_of_device{{0x11, 0x22, 0x33}};
+ uint16_t offset = 0x3456;
+ uint8_t rssi = 0x78;
+ auto inquiry_response_builder = InquiryResponseBuilder::CreateExtended(mode, class_of_device, offset, rssi, count);
+ auto wrapped_inquiry =
+ LinkLayerPacketBuilder::WrapInquiryResponse(std::move(inquiry_response_builder), source_, dest_);
+ std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
+ std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
+ wrapped_inquiry->Serialize(it);
+
+ LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
+ ASSERT_EQ(view.size(), wrapped_inquiry->size());
+ ASSERT_EQ(view.GetType(), Link::PacketType::INQUIRY_RESPONSE);
+ ASSERT_EQ(source_, view.GetSourceAddress());
+ ASSERT_EQ(dest_, view.GetDestinationAddress());
+ InquiryResponseView inquiry_response = InquiryResponseView::GetInquiryResponse(view);
+ ASSERT_EQ(inquiry_response.GetClockOffset(), offset);
+ ASSERT_EQ(inquiry_response.GetType(), Inquiry::InquiryType::EXTENDED);
+ ASSERT_EQ(inquiry_response.GetPageScanRepetitionMode(), mode);
+ ASSERT_EQ(inquiry_response.GetClassOfDevice(), class_of_device);
+ ASSERT_EQ(inquiry_response.GetClockOffset(), offset);
+ ASSERT_EQ(inquiry_response.GetRssi(), rssi);
+ auto ext_it = inquiry_response.GetExtendedData();
+ ASSERT_EQ(ext_it.NumBytesRemaining(), count.size());
+ for (size_t i = 0; i < count.size(); i++) {
+ ASSERT_EQ(count[i], *(ext_it++));
+ }
+}
+
+TEST_F(LinkLayerPacketBuilderTest, ioCapabilityRequestTest) {
+ uint8_t io_cap = 0x2;
+ uint8_t oob_data_present = 0x1;
+ uint8_t authentication_requirements = 0x5;
+ auto io_capability_builder = IoCapabilityBuilder::Create(io_cap, oob_data_present, authentication_requirements);
+ auto wrapped_io_capability_request =
+ LinkLayerPacketBuilder::WrapIoCapabilityRequest(std::move(io_capability_builder), source_, dest_);
+ std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
+ std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
+ wrapped_io_capability_request->Serialize(it);
+
+ LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
+ ASSERT_EQ(view.size(), wrapped_io_capability_request->size());
+ ASSERT_EQ(view.GetType(), Link::PacketType::IO_CAPABILITY_REQUEST);
+ ASSERT_EQ(source_, view.GetSourceAddress());
+ ASSERT_EQ(dest_, view.GetDestinationAddress());
+ IoCapabilityView io_capability = IoCapabilityView::GetIoCapability(view);
+ ASSERT_EQ(io_capability.GetIoCapability(), io_cap);
+ ASSERT_EQ(io_capability.GetOobDataPresent(), oob_data_present);
+ ASSERT_EQ(io_capability.GetAuthenticationRequirements(), authentication_requirements);
+}
+
+TEST_F(LinkLayerPacketBuilderTest, ioCapabilityResponseTest) {
+ uint8_t io_cap = 0x2;
+ uint8_t oob_data_present = 0x1;
+ uint8_t authentication_requirements = 0x5;
+ auto io_capability_builder = IoCapabilityBuilder::Create(io_cap, oob_data_present, authentication_requirements);
+ auto wrapped_io_capability_response =
+ LinkLayerPacketBuilder::WrapIoCapabilityResponse(std::move(io_capability_builder), source_, dest_);
+ std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
+ std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
+ wrapped_io_capability_response->Serialize(it);
+
+ LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
+ ASSERT_EQ(view.size(), wrapped_io_capability_response->size());
+ ASSERT_EQ(view.GetType(), Link::PacketType::IO_CAPABILITY_RESPONSE);
+ ASSERT_EQ(source_, view.GetSourceAddress());
+ ASSERT_EQ(dest_, view.GetDestinationAddress());
+ IoCapabilityView io_capability = IoCapabilityView::GetIoCapability(view);
+ ASSERT_EQ(io_capability.GetIoCapability(), io_cap);
+ ASSERT_EQ(io_capability.GetOobDataPresent(), oob_data_present);
+ ASSERT_EQ(io_capability.GetAuthenticationRequirements(), authentication_requirements);
+}
+
+TEST_F(LinkLayerPacketBuilderTest, ioCapabilityNegativeResponseTest) {
+ uint8_t reason = 23;
+ auto io_capability_negative_response_builder = IoCapabilityNegativeResponseBuilder::Create(reason);
+ auto wrapped_io_capability_negative_response = LinkLayerPacketBuilder::WrapIoCapabilityNegativeResponse(
+ std::move(io_capability_negative_response_builder), source_, dest_);
+ std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
+ std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
+ wrapped_io_capability_negative_response->Serialize(it);
+
+ LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
+ ASSERT_EQ(view.size(), wrapped_io_capability_negative_response->size());
+ ASSERT_EQ(view.GetType(), Link::PacketType::IO_CAPABILITY_NEGATIVE_RESPONSE);
+ ASSERT_EQ(source_, view.GetSourceAddress());
+ ASSERT_EQ(dest_, view.GetDestinationAddress());
+ IoCapabilityNegativeResponseView io_capability_negative_response =
+ IoCapabilityNegativeResponseView::GetIoCapabilityNegativeResponse(view);
+ ASSERT_EQ(io_capability_negative_response.GetReason(), reason);
+}
+
+TEST_F(LinkLayerPacketBuilderTest, pageTest) {
+ uint8_t allow_role_switch = 1;
+ ClassOfDevice class_of_device{{0x11, 0x22, 0x33}};
+ auto page_builder = PageBuilder::Create(class_of_device, allow_role_switch);
+ auto wrapped_page = LinkLayerPacketBuilder::WrapPage(std::move(page_builder), source_, dest_);
+ std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
+ std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
+ wrapped_page->Serialize(it);
+
+ LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
+ ASSERT_EQ(view.size(), wrapped_page->size());
+ ASSERT_EQ(view.GetType(), Link::PacketType::PAGE);
+ ASSERT_EQ(source_, view.GetSourceAddress());
+ ASSERT_EQ(dest_, view.GetDestinationAddress());
+ PageView page = PageView::GetPage(view);
+ ASSERT_EQ(page.GetAllowRoleSwitch(), allow_role_switch);
+ ASSERT_EQ(page.GetClassOfDevice(), class_of_device);
+}
+
+TEST_F(LinkLayerPacketBuilderTest, pageResponseTest) {
+ uint8_t try_role_switch = 2;
+ auto page_response_builder = PageResponseBuilder::Create(try_role_switch);
+ auto wrapped_page_response =
+ LinkLayerPacketBuilder::WrapPageResponse(std::move(page_response_builder), source_, dest_);
+ std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
+ std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
+ wrapped_page_response->Serialize(it);
+
+ LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
+ ASSERT_EQ(view.size(), wrapped_page_response->size());
+ ASSERT_EQ(view.GetType(), Link::PacketType::PAGE_RESPONSE);
+ ASSERT_EQ(source_, view.GetSourceAddress());
+ ASSERT_EQ(dest_, view.GetDestinationAddress());
+ PageResponseView page_response = PageResponseView::GetPageResponse(view);
+ ASSERT_EQ(page_response.GetTryRoleSwitch(), try_role_switch);
+}
+
+TEST_F(LinkLayerPacketBuilderTest, responseTest) {
+ uint16_t opcode = 0x1234;
+ std::vector<uint64_t> data{
+ 0x7060504030201000, 0x7161514131211101, 0x7262524232221202, 0x7363534333231303,
+ 0x7464544434241404, 0x7565554535251505, 0x7666564636261606, 0x7767574737271707,
+ 0x7868584838281808, 0x7969594939291909, 0x7a6a5a4a3a2a1a0a, 0x7b6b5b4b3b2b1b0b,
+ 0x7c6c5c4c3c2c1c0c, 0x7d6d5d4d3d2d1d0d, 0x7e6e5e4e3e2e1e0e, 0x7f6f5f4f3f2f1f0f,
+ };
+ auto response_builder = ResponseBuilder::Create(opcode, data);
+ auto wrapped_response = LinkLayerPacketBuilder::WrapResponse(std::move(response_builder), source_, dest_);
+ std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
+ std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
+ wrapped_response->Serialize(it);
+
+ LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
+ ASSERT_EQ(view.size(), wrapped_response->size());
+ ASSERT_EQ(view.GetType(), Link::PacketType::RESPONSE);
+ ASSERT_EQ(source_, view.GetSourceAddress());
+ ASSERT_EQ(dest_, view.GetDestinationAddress());
+ ResponseView response = ResponseView::GetResponse(view);
+ ASSERT_EQ(opcode, response.GetOpcode());
+ auto data_it = response.GetResponseData();
+ ASSERT_EQ(data.size(), data_it.NumBytesRemaining() / sizeof(uint64_t));
+ ASSERT_EQ(0u, data_it.NumBytesRemaining() % sizeof(uint64_t));
+ for (size_t i = 0; i < data.size(); i++) {
+ ASSERT_EQ(data[i], data_it.extract<uint64_t>());
+ }
+}
+
+TEST_F(LinkLayerPacketBuilderTest, wrapAclTest) {
+ std::shared_ptr<std::vector<uint8_t>> count_shared = std::make_shared<std::vector<uint8_t>>(count);
+ View count_view(count_shared, 0, count_shared->size());
+ PacketView<true> count_packet_view({count_view});
+ auto builder = ViewForwarderBuilder::Create(count_packet_view);
+ auto wrapped_acl = LinkLayerPacketBuilder::WrapAcl(std::move(builder), source_, dest_);
+ std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
+ std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
+ wrapped_acl->Serialize(it);
+
+ LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
+ ASSERT_EQ(view.size(), wrapped_acl->size());
+ ASSERT_EQ(view.GetType(), Link::PacketType::ACL);
+ ASSERT_EQ(source_, view.GetSourceAddress());
+ ASSERT_EQ(dest_, view.GetDestinationAddress());
+ auto acl_view = view.GetPayload();
+ ASSERT_EQ(acl_view.size(), count_view.size());
+ for (size_t i = 0; i < count_view.size(); i++) {
+ ASSERT_EQ(acl_view[i], count_view[i]);
+ }
+}
+
+TEST_F(LinkLayerPacketBuilderTest, wrapCommandTest) {
+ uint16_t opcode = 0x0102;
+ std::shared_ptr<std::vector<uint8_t>> count_shared = std::make_shared<std::vector<uint8_t>>(count);
+ View count_view(count_shared, 0, count_shared->size());
+ PacketView<true> args({count_view});
+ auto builder = CommandBuilder::Create(opcode, args);
+ auto wrapped_command = LinkLayerPacketBuilder::WrapCommand(std::move(builder), source_, dest_);
+ std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
+ std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
+ wrapped_command->Serialize(it);
+
+ LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
+ ASSERT_EQ(view.size(), wrapped_command->size());
+ ASSERT_EQ(view.GetType(), Link::PacketType::COMMAND);
+ ASSERT_EQ(source_, view.GetSourceAddress());
+ ASSERT_EQ(dest_, view.GetDestinationAddress());
+ auto command_view = CommandView::GetCommand(view);
+ ASSERT_EQ(opcode, command_view.GetOpcode());
+ auto args_itr = command_view.GetData();
+ ASSERT_EQ(args_itr.NumBytesRemaining(), count.size());
+ for (size_t i = 0; i < count.size(); i++) {
+ ASSERT_EQ(*args_itr++, count[i]);
+ }
+}
+
+TEST_F(LinkLayerPacketBuilderTest, wrapLeAdvertisementTest) {
+ LeAdvertisement::AddressType address_type = LeAdvertisement::AddressType::RANDOM;
+ LeAdvertisement::AdvertisementType advertisement_type = LeAdvertisement::AdvertisementType::ADV_NONCONN_IND;
+ auto builder = LeAdvertisementBuilder::Create(address_type, advertisement_type, count);
+ auto wrapped_le_advertisement = LinkLayerPacketBuilder::WrapLeAdvertisement(std::move(builder), source_);
+ std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
+ std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
+ wrapped_le_advertisement->Serialize(it);
+
+ LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
+ ASSERT_EQ(view.size(), wrapped_le_advertisement->size());
+ ASSERT_EQ(view.GetType(), Link::PacketType::LE_ADVERTISEMENT);
+ ASSERT_EQ(source_, view.GetSourceAddress());
+ ASSERT_EQ(Address::kEmpty, view.GetDestinationAddress());
+ LeAdvertisementView le_advertisement_view = LeAdvertisementView::GetLeAdvertisementView(view);
+ ASSERT_EQ(address_type, le_advertisement_view.GetAddressType());
+ ASSERT_EQ(advertisement_type, le_advertisement_view.GetAdvertisementType());
+ auto le_advertisement_itr = le_advertisement_view.GetData();
+ ASSERT_EQ(le_advertisement_itr.NumBytesRemaining(), count.size());
+ for (size_t i = 0; i < count.size(); i++) {
+ ASSERT_EQ(*(le_advertisement_itr++), count[i]);
+ }
+}
+
+TEST_F(LinkLayerPacketBuilderTest, wrapLeScanTest) {
+ auto le_scan = LinkLayerPacketBuilder::WrapLeScan(source_, dest_);
+ std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
+ std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
+ le_scan->Serialize(it);
+
+ LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
+ ASSERT_EQ(view.size(), le_scan->size());
+ ASSERT_EQ(view.GetType(), Link::PacketType::LE_SCAN);
+ ASSERT_EQ(source_, view.GetSourceAddress());
+ ASSERT_EQ(dest_, view.GetDestinationAddress());
+ auto le_scan_view = view.GetPayload();
+ ASSERT_EQ(0u, le_scan_view.size());
+}
+
+TEST_F(LinkLayerPacketBuilderTest, wrapLeScanResponseTest) {
+ LeAdvertisement::AddressType address_type = LeAdvertisement::AddressType::PUBLIC_IDENTITY;
+ LeAdvertisement::AdvertisementType advertisement_type = LeAdvertisement::AdvertisementType::SCAN_RESPONSE;
+ auto builder = LeAdvertisementBuilder::Create(address_type, advertisement_type, count);
+ auto wrapped_scan_response = LinkLayerPacketBuilder::WrapLeScanResponse(std::move(builder), source_, dest_);
+ std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
+ std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
+ wrapped_scan_response->Serialize(it);
+
+ LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
+ ASSERT_EQ(view.size(), wrapped_scan_response->size());
+ ASSERT_EQ(view.GetType(), Link::PacketType::LE_SCAN_RESPONSE);
+ ASSERT_EQ(source_, view.GetSourceAddress());
+ ASSERT_EQ(dest_, view.GetDestinationAddress());
+ LeAdvertisementView le_advertisement_view = LeAdvertisementView::GetLeAdvertisementView(view);
+ ASSERT_EQ(address_type, le_advertisement_view.GetAddressType());
+ ASSERT_EQ(advertisement_type, le_advertisement_view.GetAdvertisementType());
+ auto scan_response_itr = le_advertisement_view.GetData();
+ ASSERT_EQ(scan_response_itr.NumBytesRemaining(), count.size());
+ for (size_t i = 0; i < count.size(); i++) {
+ ASSERT_EQ((*scan_response_itr++), count[i]);
+ }
+}
+
+TEST_F(LinkLayerPacketBuilderTest, wrapScoTest) {
+ std::shared_ptr<std::vector<uint8_t>> count_shared = std::make_shared<std::vector<uint8_t>>(count);
+ View count_view(count_shared, 0, count_shared->size());
+ PacketView<true> count_packet_view({count_view});
+ auto builder = ViewForwarderBuilder::Create(count_packet_view);
+ auto wrapped_sco = LinkLayerPacketBuilder::WrapSco(std::move(builder), source_, dest_);
+ std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
+ std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
+ wrapped_sco->Serialize(it);
+
+ LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
+ ASSERT_EQ(view.size(), wrapped_sco->size());
+ ASSERT_EQ(view.GetType(), Link::PacketType::SCO);
+ ASSERT_EQ(source_, view.GetSourceAddress());
+ ASSERT_EQ(dest_, view.GetDestinationAddress());
+ auto sco_view = view.GetPayload();
+ ASSERT_EQ(sco_view.size(), count.size());
+ for (size_t i = 0; i < count.size(); i++) {
+ ASSERT_EQ(sco_view[i], count[i]);
+ }
+}
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/test/packet_builder_test.cc b/vendor_libs/test_vendor_lib/packets/test/packet_builder_test.cc
new file mode 100644
index 0000000..6fab56d
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/test/packet_builder_test.cc
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2018 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 "packets/packet_builder.h"
+
+#include <gtest/gtest.h>
+#include <forward_list>
+#include <memory>
+
+using std::vector;
+
+namespace {
+vector<uint8_t> count_all = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+};
+
+vector<uint8_t> count_1 = {
+ 0x00,
+ 0x01,
+ 0x02,
+};
+
+vector<uint8_t> count_2 = {
+ 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+};
+
+vector<uint8_t> count_3 = {
+ 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+};
+} // namespace
+
+namespace test_vendor_lib {
+namespace packets {
+
+template <bool little_endian>
+class EndianBuilder : public PacketBuilder<little_endian> {
+ public:
+ EndianBuilder(uint8_t byte, uint16_t two_bytes, uint32_t four_bytes, uint64_t eight_bytes)
+ : byte_(byte), two_bytes_(two_bytes), four_bytes_(four_bytes), eight_bytes_(eight_bytes) {}
+ ~EndianBuilder() override = default;
+
+ size_t size() const override {
+ return sizeof(signature_) + sizeof(byte_) + sizeof(two_bytes_) + sizeof(four_bytes_) + sizeof(eight_bytes_);
+ }
+
+ virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
+ std::unique_ptr<std::vector<uint8_t>> packet = std::make_unique<std::vector<uint8_t>>();
+ packet->reserve(size());
+ std::back_insert_iterator<std::vector<uint8_t>> it(*packet);
+ Serialize(it);
+ return packet;
+ }
+
+ void Serialize(
+ std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+ PacketBuilder<little_endian>::insert(signature_, it);
+ PacketBuilder<little_endian>::insert(byte_, it);
+ PacketBuilder<little_endian>::insert(two_bytes_, it);
+ PacketBuilder<little_endian>::insert(four_bytes_, it);
+ PacketBuilder<little_endian>::insert(eight_bytes_, it);
+ }
+
+ private:
+ uint32_t signature_{(little_endian ? 0x03020100 : 0x00010203)};
+ uint8_t byte_;
+ uint16_t two_bytes_;
+ uint32_t four_bytes_;
+ uint64_t eight_bytes_;
+};
+
+class PacketBuilderEndianTest : public ::testing::Test {
+ public:
+ PacketBuilderEndianTest() = default;
+ ~PacketBuilderEndianTest() override = default;
+};
+
+TEST(PacketBuilderEndianTest, insertTest) {
+ EndianBuilder<true> little(0x04, 0x0605, 0x0a090807, 0x1211100f0e0d0c0b);
+ EndianBuilder<false> big(0x04, 0x0506, 0x0708090a, 0x0b0c0d0e0f101112);
+ ASSERT_EQ(*big.FinalPacket(), *little.FinalPacket());
+}
+
+template <typename T>
+class VectorBuilder : public PacketBuilder<true> {
+ public:
+ VectorBuilder(std::vector<uint64_t> vect) {
+ for (uint64_t element : vect) {
+ vect.push_back(static_cast<T>(element));
+ }
+ }
+ ~VectorBuilder() override = default;
+
+ size_t size() const override { return vect_.size() * sizeof(T); }
+
+ virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
+ std::unique_ptr<std::vector<uint8_t>> packet = std::make_unique<std::vector<uint8_t>>();
+ packet->reserve(size());
+ std::back_insert_iterator<std::vector<uint8_t>> it(*packet);
+ Serialize(it);
+ return packet;
+ }
+
+ void Serialize(
+ std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+ PacketBuilder<true>::insert_vector(vect_, it);
+ }
+
+ private:
+ std::vector<T> vect_;
+};
+
+template <typename T>
+class InsertElementsBuilder : public PacketBuilder<true> {
+ public:
+ InsertElementsBuilder(std::vector<uint64_t> vect) {
+ for (uint64_t element : vect) {
+ vect.push_back(static_cast<T>(element));
+ }
+ }
+ ~InsertElementsBuilder() override = default;
+
+ size_t size() const override { return vect_.size() * sizeof(T); }
+
+ virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
+ std::unique_ptr<std::vector<uint8_t>> packet = std::make_unique<std::vector<uint8_t>>();
+ packet->reserve(size());
+ std::back_insert_iterator<std::vector<uint8_t>> it(*packet);
+ Serialize(it);
+ return packet;
+ }
+
+ void Serialize(
+ std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+ for (T elem : vect_) {
+ PacketBuilder<true>::insert(elem, it);
+ }
+ }
+
+ private:
+ std::vector<T> vect_;
+};
+
+std::vector<uint64_t> vector_data{
+ 0x7060504030201000, 0x7161514131211101, 0x7262524232221202, 0x7363534333231303, 0x7464544434241404,
+ 0x7565554535251505, 0x7666564636261606, 0x7767574737271707, 0x7868584838281808,
+};
+
+template <typename T>
+class VectorBuilderTest : public ::testing::Test {
+ public:
+ VectorBuilderTest() = default;
+ ~VectorBuilderTest() override = default;
+
+ void SetUp() override {
+ packet_1_ = std::shared_ptr<VectorBuilder<T>>(new VectorBuilder<T>(vector_data));
+ packet_2_ = std::shared_ptr<InsertElementsBuilder<T>>(new InsertElementsBuilder<T>(vector_data));
+ }
+
+ void TearDown() override {
+ packet_1_.reset();
+ packet_2_.reset();
+ }
+
+ std::shared_ptr<VectorBuilder<T>> packet_1_;
+ std::shared_ptr<InsertElementsBuilder<T>> packet_2_;
+};
+
+using VectorBaseTypes = ::testing::Types<uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, int64_t>;
+TYPED_TEST_CASE(VectorBuilderTest, VectorBaseTypes);
+
+TYPED_TEST(VectorBuilderTest, insertVectorTest) {
+ ASSERT_EQ(*(this->packet_1_->FinalPacket()), *(this->packet_2_->FinalPacket()));
+}
+
+class NestedBuilder : public PacketBuilder<true> {
+ public:
+ ~NestedBuilder() override = default;
+
+ size_t size() const override {
+ size_t payload_size = (payload_ ? payload_->size() : 0);
+ return 1 + payload_size;
+ }
+
+ static std::unique_ptr<NestedBuilder> Create(uint8_t level) {
+ return std::unique_ptr<NestedBuilder>(new NestedBuilder(level));
+ }
+
+ static std::unique_ptr<NestedBuilder> CreateNested(std::unique_ptr<BasePacketBuilder> payload, uint8_t level) {
+ return std::unique_ptr<NestedBuilder>(new NestedBuilder(std::move(payload), level));
+ }
+
+ virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
+ std::unique_ptr<std::vector<uint8_t>> packet = std::make_unique<std::vector<uint8_t>>();
+ packet->reserve(size());
+ std::back_insert_iterator<std::vector<uint8_t>> it(*packet);
+ Serialize(it);
+ return packet;
+ }
+
+ void Serialize(
+ std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+ PacketBuilder<true>::insert(level_, it);
+ if (payload_) {
+ payload_->Serialize(it);
+ }
+ }
+
+ private:
+ std::unique_ptr<BasePacketBuilder> payload_;
+ uint8_t level_;
+
+ NestedBuilder(std::unique_ptr<BasePacketBuilder> inner, uint8_t level) : payload_(std::move(inner)), level_(level) {}
+ NestedBuilder(uint8_t level) : level_(level) {}
+};
+
+class BuilderBuilderTest : public ::testing::Test {};
+
+TEST(BuilderBuilderTest, nestingTest) {
+ std::unique_ptr<BasePacketBuilder> innermost = NestedBuilder::Create(0);
+ std::unique_ptr<BasePacketBuilder> number_1 = NestedBuilder::CreateNested(std::move(innermost), 1);
+ std::unique_ptr<BasePacketBuilder> number_2 = NestedBuilder::CreateNested(std::move(number_1), 2);
+ std::unique_ptr<BasePacketBuilder> number_3 = NestedBuilder::CreateNested(std::move(number_2), 3);
+ std::unique_ptr<BasePacketBuilder> number_4 = NestedBuilder::CreateNested(std::move(number_3), 4);
+ std::unique_ptr<NestedBuilder> number_5 = NestedBuilder::CreateNested(std::move(number_4), 5);
+
+ std::vector<uint8_t> count_down{5, 4, 3, 2, 1, 0};
+ ASSERT_EQ(*number_5->FinalPacket(), count_down);
+}
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/test/packet_view_test.cc b/vendor_libs/test_vendor_lib/packets/test/packet_view_test.cc
new file mode 100644
index 0000000..b234c20
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/test/packet_view_test.cc
@@ -0,0 +1,505 @@
+/*
+ * Copyright 2018 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 "packets/packet_view.h"
+
+#include <gtest/gtest.h>
+#include <forward_list>
+#include <memory>
+
+#include "types/address.h"
+
+using std::vector;
+
+namespace {
+vector<uint8_t> count_all = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+};
+
+vector<uint8_t> count_1 = {
+ 0x00,
+ 0x01,
+ 0x02,
+};
+
+vector<uint8_t> count_2 = {
+ 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+};
+
+vector<uint8_t> count_3 = {
+ 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+};
+} // namespace
+
+namespace test_vendor_lib {
+namespace packets {
+
+template <typename T>
+class IteratorTest : public ::testing::Test {
+ public:
+ IteratorTest() = default;
+ ~IteratorTest() override = default;
+
+ void SetUp() override {
+ packet = std::shared_ptr<T>(new T({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())}));
+ }
+
+ void TearDown() override { packet.reset(); }
+
+ std::shared_ptr<T> packet;
+};
+
+using PacketViewTypes = ::testing::Types<PacketView<true>, PacketView<false>>;
+TYPED_TEST_CASE(IteratorTest, PacketViewTypes);
+
+class IteratorExtractTest : public ::testing::Test {
+ public:
+ IteratorExtractTest() = default;
+ ~IteratorExtractTest() override = default;
+};
+
+template <typename T>
+class PacketViewTest : public IteratorTest<T> {
+ public:
+ PacketViewTest() = default;
+ ~PacketViewTest() override = default;
+};
+
+using PacketViewTypes = ::testing::Types<PacketView<true>, PacketView<false>>;
+TYPED_TEST_CASE(PacketViewTest, PacketViewTypes);
+
+class PacketViewMultiViewTest : public ::testing::Test {
+ public:
+ PacketViewMultiViewTest() = default;
+ ~PacketViewMultiViewTest() override = default;
+};
+
+class ViewTest : public ::testing::Test {
+ public:
+ ViewTest() = default;
+ ~ViewTest() override = default;
+};
+
+TEST(IteratorExtractTest, extractLeTest) {
+ PacketView<true> packet({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
+ auto general_case = packet.begin();
+
+ ASSERT_EQ(0x00, general_case.extract<uint8_t>());
+ ASSERT_EQ(0x0201, general_case.extract<uint16_t>());
+ ASSERT_EQ(0x06050403u, general_case.extract<uint32_t>());
+ ASSERT_EQ(0x0e0d0c0b0a090807u, general_case.extract<uint64_t>());
+ ASSERT_EQ(0x0f, general_case.extract<uint8_t>());
+ Address raw({0x10, 0x11, 0x12, 0x13, 0x14, 0x15});
+ ASSERT_EQ(raw, general_case.extract<Address>());
+ ASSERT_EQ(0x16, general_case.extract<uint8_t>());
+}
+
+TEST(IteratorExtractTest, extractBeTest) {
+ PacketView<false> packet({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
+ auto general_case = packet.begin();
+
+ ASSERT_EQ(0x00, general_case.extract<uint8_t>());
+ ASSERT_EQ(0x0102, general_case.extract<uint16_t>());
+ ASSERT_EQ(0x03040506u, general_case.extract<uint32_t>());
+ ASSERT_EQ(0x0708090a0b0c0d0eu, general_case.extract<uint64_t>());
+ ASSERT_EQ(0x0f, general_case.extract<uint8_t>());
+ Address raw({0x15, 0x14, 0x13, 0x12, 0x11, 0x10});
+ ASSERT_EQ(raw, general_case.extract<Address>());
+ ASSERT_EQ(0x16, general_case.extract<uint8_t>());
+}
+
+TYPED_TEST(IteratorTest, extractBoundsDeathTest) {
+ auto bounds_test = this->packet->end();
+
+ ASSERT_DEATH(bounds_test.template extract<uint8_t>(), "");
+ ASSERT_DEATH(bounds_test.template extract<uint16_t>(), "");
+ ASSERT_DEATH(bounds_test.template extract<uint32_t>(), "");
+ ASSERT_DEATH(bounds_test.template extract<uint64_t>(), "");
+}
+
+TYPED_TEST(IteratorTest, dereferenceDeathTest) {
+ auto dereference_test = this->packet->end();
+
+ ASSERT_DEATH(*dereference_test, "");
+ ASSERT_EQ(0x1f, *(dereference_test - 1));
+}
+
+TYPED_TEST(IteratorTest, plusEqTest) {
+ auto plus_eq = this->packet->begin();
+ for (size_t i = 0; i < count_all.size(); i += 2) {
+ ASSERT_EQ(count_all[i], *plus_eq) << "+= test: Dereferenced iterator does not equal expected at index " << i;
+ plus_eq += 2;
+ }
+}
+
+TYPED_TEST(IteratorTest, preIncrementTest) {
+ auto plus_plus = this->packet->begin();
+ for (size_t i = 0; i < count_all.size() - 1; i++) {
+ ASSERT_EQ(count_all[i + 1], *(++plus_plus)) << "Pre-increment test: Dereferenced iterator does not equal expected "
+ << "at index " << i;
+ }
+}
+
+TYPED_TEST(IteratorTest, postIncrementTest) {
+ auto plus_plus = this->packet->begin();
+ for (size_t i = 0; i < count_all.size(); i++) {
+ ASSERT_EQ(count_all[i], *(plus_plus++)) << "Post-increment test: Dereferenced iterator does not equal expected "
+ << "at index " << i;
+ }
+}
+
+TYPED_TEST(IteratorTest, additionTest) {
+ auto plus = this->packet->begin();
+ for (size_t i = 0; i < count_all.size(); i++) {
+ ASSERT_EQ(count_all[i], *plus) << "+ test: Dereferenced iterator does not equal expected at index " << i;
+ plus = plus + 1;
+ }
+}
+
+TYPED_TEST(IteratorTest, minusEqTest) {
+ auto minus_eq = this->packet->end();
+ minus_eq -= 1;
+ size_t index = count_all.size() - 1;
+ for (size_t i = 0; index > i; i++) {
+ ASSERT_EQ(count_all[index], *minus_eq)
+ << "-= test: Dereferenced iterator does not equal expected at index " << index;
+ index -= i;
+ minus_eq -= i;
+ }
+}
+
+TYPED_TEST(IteratorTest, preDecrementTest) {
+ auto minus_minus = this->packet->end();
+ for (size_t i = count_all.size(); i > 0; i--) {
+ ASSERT_EQ(count_all[i - 1], *(--minus_minus))
+ << "Pre-decrement test: Dereferenced iterator does not equal expected "
+ << "at index " << i;
+ }
+}
+
+TYPED_TEST(IteratorTest, postDecrementTest) {
+ auto minus_minus = this->packet->end();
+ minus_minus--;
+ for (size_t i = count_all.size() - 1; i > 0; i--) {
+ ASSERT_EQ(count_all[i], *(minus_minus--)) << "Post-decrement test: Dereferenced iterator does not equal expected "
+ << "at index " << i;
+ }
+}
+
+TYPED_TEST(IteratorTest, subtractionTest) {
+ auto minus = this->packet->end();
+ minus = minus - 1;
+ for (size_t i = count_all.size() - 1; i > 0; i--) {
+ ASSERT_EQ(count_all[i], *minus) << "- test: Dereferenced iterator does not equal expected at index " << i;
+ minus = minus - 1;
+ }
+}
+
+TYPED_TEST(IteratorTest, differenceTest) {
+ auto begin = this->packet->begin();
+ auto end = this->packet->end();
+ int difference = end - begin;
+ ASSERT_EQ(difference, static_cast<int>(count_all.size()));
+ int neg_difference = begin - end;
+ ASSERT_EQ(neg_difference, -static_cast<int>(count_all.size()));
+}
+
+TYPED_TEST(IteratorTest, equalityTest) {
+ auto begin = this->packet->begin();
+ auto end = this->packet->end();
+ auto begin_copy = this->packet->begin();
+ auto end_copy = this->packet->end();
+ ASSERT_EQ(begin_copy, begin);
+ ASSERT_EQ(end_copy, end);
+}
+
+TYPED_TEST(IteratorTest, comparisonsTest) {
+ auto begin = this->packet->begin();
+ auto end = this->packet->end();
+ auto begin_copy = this->packet->begin();
+ auto end_copy = this->packet->end();
+ ASSERT_EQ(begin_copy, begin);
+ ASSERT_EQ(end_copy, end);
+ ASSERT_NE(begin, end);
+ ASSERT_TRUE(begin < end);
+ ASSERT_FALSE(end < end);
+ ASSERT_FALSE(end < begin);
+ ASSERT_FALSE(begin > end);
+ ASSERT_FALSE(end > end);
+ ASSERT_TRUE(end > begin);
+ ASSERT_TRUE(begin <= end);
+ ASSERT_TRUE(end <= end);
+ ASSERT_FALSE(end <= begin);
+ ASSERT_FALSE(begin >= end);
+ ASSERT_TRUE(end >= end);
+ ASSERT_TRUE(end >= begin);
+}
+
+TYPED_TEST(PacketViewTest, getLengthTest) {
+ size_t length = this->packet->size();
+ ASSERT_EQ(length, count_all.size());
+}
+
+TYPED_TEST(PacketViewTest, getAtIndexTest) {
+ size_t past_end = this->packet->size();
+ ASSERT_DEATH(this->packet->at(past_end), "");
+ size_t working_index = 0x1f;
+ ASSERT_EQ(0x1f, this->packet->at(working_index));
+}
+
+TYPED_TEST(PacketViewTest, arrayOperatorTest) {
+ size_t past_end = this->packet->size();
+ ASSERT_DEATH((*(this->packet))[past_end], "");
+ size_t working_index = 0x1f;
+ ASSERT_EQ(0x1f, (*(this->packet))[working_index]);
+}
+
+TYPED_TEST(PacketViewTest, numBytesRemainingTest) {
+ auto all = this->packet->begin();
+ size_t remaining = all.NumBytesRemaining();
+ for (size_t n = remaining; n > 0; n--) {
+ ASSERT_EQ(remaining, all.NumBytesRemaining());
+ all++;
+ remaining--;
+ }
+ ASSERT_EQ(static_cast<size_t>(0), all.NumBytesRemaining());
+ ASSERT_DEATH(*(all++), "");
+ all++;
+ ASSERT_EQ(static_cast<size_t>(0), all.NumBytesRemaining());
+ ASSERT_DEATH(*(all++), "");
+}
+
+using SubViewTestParam = std::pair<size_t, size_t>;
+class SubViewBaseTest : public ::testing::TestWithParam<SubViewTestParam> {
+ public:
+ class SubPacketView : public PacketView<true> {
+ public:
+ using PacketView<true>::PacketView;
+ PacketView<true> Slice(size_t header, size_t tail) {
+ return PacketView<true>::SubViewLittleEndian(header, tail);
+ }
+ };
+};
+
+class SubViewPassTest : public SubViewBaseTest {};
+
+TEST_P(SubViewPassTest, subViewTest) {
+ auto header = GetParam().first;
+ auto tail = GetParam().second;
+ SubPacketView single_view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
+ SubPacketView multi_view({
+ View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
+ });
+
+ auto single_slice = single_view.Slice(header, tail);
+ auto multi_slice = multi_view.Slice(header, tail);
+
+ ASSERT_EQ(single_slice.size(), tail - header);
+ ASSERT_EQ(single_slice.size(), multi_slice.size());
+ for (size_t i = 0; i < single_slice.size(); i++) {
+ ASSERT_EQ(single_slice[i], multi_slice[i]);
+ }
+}
+
+static const size_t boundary_1 = count_1.size();
+static const size_t boundary_2 = count_1.size() + count_2.size();
+
+INSTANTIATE_TEST_CASE_P(
+ chopomatic, SubViewPassTest,
+ ::testing::Values(
+ // {begin, end} pairs for subsets into the PacketView
+ SubViewTestParam{0, 0}, SubViewTestParam{0, boundary_1}, SubViewTestParam{0, boundary_1 + 1},
+ SubViewTestParam{0, boundary_2}, SubViewTestParam{0, boundary_2 + 1}, SubViewTestParam{0, count_all.size()},
+ SubViewTestParam{boundary_1 - 1, boundary_1}, SubViewTestParam{boundary_1 - 1, boundary_1 + 1},
+ SubViewTestParam{boundary_1 - 1, boundary_2}, SubViewTestParam{boundary_1 - 1, boundary_2 + 1},
+ SubViewTestParam{boundary_1 - 1, count_all.size()}, SubViewTestParam{boundary_1, boundary_1},
+ SubViewTestParam{boundary_1, boundary_2}, SubViewTestParam{boundary_1, boundary_2 + 1},
+ SubViewTestParam{boundary_1, count_all.size()}, SubViewTestParam{boundary_2 - 1, boundary_2},
+ SubViewTestParam{boundary_2 - 1, boundary_2 + 1}, SubViewTestParam{boundary_2 - 1, count_all.size()},
+ SubViewTestParam{boundary_2, boundary_2}, SubViewTestParam{boundary_2, boundary_2 + 1},
+ SubViewTestParam{boundary_2, count_all.size()}, SubViewTestParam{count_all.size() - 1, count_all.size()},
+ SubViewTestParam{count_all.size(), count_all.size()}));
+
+class SubViewDeathTest : public SubViewBaseTest {};
+
+TEST_P(SubViewDeathTest, subViewDeathTest) {
+ auto header = GetParam().first;
+ auto tail = GetParam().second;
+ SubPacketView single_view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
+ SubPacketView multi_view({
+ View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
+ });
+
+ ASSERT_DEATH(auto single_slice = single_view.Slice(header, tail), "");
+ ASSERT_DEATH(auto multi_slice = multi_view.Slice(header, tail), "");
+}
+
+INSTANTIATE_TEST_CASE_P(chopomaticDeath, SubViewDeathTest,
+ ::testing::Values(
+ // {begin, end} pairs for subsets into the PacketView
+ SubViewTestParam{1, 0}, SubViewTestParam{count_all.size(), count_all.size() - 1},
+ SubViewTestParam{count_all.size(), count_all.size() + 1}));
+
+TEST(SubViewTest, simpleSubViewTest) {
+ PacketView<true> view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
+ PacketView<true> sub_1_view = view.SubViewLittleEndian(0, view.size());
+ PacketView<true> sub_2_view = sub_1_view.SubViewLittleEndian(0, sub_1_view.size());
+ PacketView<true> sub_3_view = sub_2_view.SubViewLittleEndian(0, sub_2_view.size());
+ PacketView<true> sub_4_view = sub_3_view.SubViewLittleEndian(0, sub_3_view.size());
+ ASSERT_EQ(sub_1_view.size(), view.size());
+ ASSERT_EQ(sub_2_view.size(), view.size());
+ ASSERT_EQ(sub_3_view.size(), view.size());
+ ASSERT_EQ(sub_4_view.size(), view.size());
+}
+
+TEST(SubViewTest, realSubViewTest) {
+ PacketView<true> view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
+ std::vector<PacketView<true>> sub_views{view};
+ for (size_t i = 1; i < 6; i++) {
+ size_t parent_size = sub_views[i - 1].size();
+ sub_views.push_back(sub_views[i - 1].SubViewLittleEndian(1, parent_size - 1));
+ ASSERT_EQ(sub_views[i][0], i);
+ ASSERT_EQ(sub_views[i].size(), parent_size - 2);
+ }
+}
+
+TEST(SubViewTest, subSubViewTest) {
+ PacketView<true> single_view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
+ PacketView<true> multi_view({
+ View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
+ });
+ ASSERT_EQ(single_view.size(), multi_view.size());
+ for (size_t i = 0; i < count_all.size() / 2; i++) {
+ PacketView<true> sub_single_view = single_view.SubViewLittleEndian(i, count_all.size() - i);
+ PacketView<true> sub_multi_view = multi_view.SubViewLittleEndian(i, count_all.size() - i);
+ ASSERT_EQ(count_all.size() - 2 * i, sub_single_view.size());
+ ASSERT_EQ(sub_single_view.size(), sub_multi_view.size());
+ for (size_t j = 0; j < sub_single_view.size() / 2; j++) {
+ PacketView<true> sub_sub_single_view = sub_single_view.SubViewLittleEndian(j, sub_single_view.size() - j);
+ PacketView<true> sub_sub_multi_view = sub_multi_view.SubViewLittleEndian(j, sub_multi_view.size() - j);
+ ASSERT_EQ(sub_single_view.size() - 2 * j, sub_sub_single_view.size());
+ ASSERT_EQ(sub_sub_single_view.size(), sub_sub_multi_view.size());
+ }
+ }
+}
+
+TEST(PacketViewMultiViewTest, sizeTest) {
+ PacketView<true> single_view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
+ PacketView<true> multi_view({
+ View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
+ });
+ ASSERT_EQ(single_view.size(), multi_view.size());
+}
+
+TEST(PacketViewMultiViewTest, dereferenceTestLittleEndian) {
+ PacketView<true> single_view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
+ PacketView<true> multi_view({
+ View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
+ });
+ auto single_itr = single_view.begin();
+ auto multi_itr = multi_view.begin();
+ for (size_t i = 0; i < single_view.size(); i++) {
+ ASSERT_EQ(*(single_itr++), *(multi_itr++));
+ }
+ ASSERT_DEATH(*multi_itr, "");
+}
+
+TEST(PacketViewMultiViewTest, dereferenceTestBigEndian) {
+ PacketView<false> single_view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
+ PacketView<false> multi_view({
+ View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
+ });
+ auto single_itr = single_view.begin();
+ auto multi_itr = multi_view.begin();
+ for (size_t i = 0; i < single_view.size(); i++) {
+ ASSERT_EQ(*(single_itr++), *(multi_itr++));
+ }
+ ASSERT_DEATH(*multi_itr, "");
+}
+
+TEST(PacketViewMultiViewTest, arrayOperatorTest) {
+ PacketView<true> single_view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
+ PacketView<true> multi_view({
+ View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
+ });
+ for (size_t i = 0; i < single_view.size(); i++) {
+ ASSERT_EQ(single_view[i], multi_view[i]);
+ }
+ ASSERT_DEATH(multi_view[single_view.size()], "");
+}
+
+TEST(ViewTest, arrayOperatorTest) {
+ View view_all(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size());
+ size_t past_end = view_all.size();
+ for (size_t i = 0; i < past_end; i++) {
+ ASSERT_EQ(view_all[i], count_all[i]);
+ }
+ ASSERT_DEATH(view_all[past_end], "");
+
+ size_t header_size = 2;
+ size_t tail_size = 3;
+ View view_subset(std::make_shared<const vector<uint8_t>>(count_all), header_size, count_all.size() - tail_size);
+ View view_subset2(view_all, header_size, count_all.size() - tail_size);
+ size_t subset_length = view_subset.size();
+ for (size_t i = 0; i < subset_length; i++) {
+ ASSERT_EQ(view_subset[i], count_all[header_size + i]);
+ ASSERT_EQ(view_subset[i], view_subset2[i]);
+ }
+ ASSERT_DEATH(view_subset[subset_length + 1], "");
+ ASSERT_DEATH(view_subset2[subset_length + 1], "");
+}
+
+TEST(ViewTest, earlySubSubViewTest) {
+ View view(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size());
+ View sub_1_view(view, view.size() - 3, view.size() - 1);
+ View sub_2_view(sub_1_view, 1, 2);
+ ASSERT_EQ(sub_1_view.size(), 2u);
+ ASSERT_EQ(sub_2_view.size(), 1u);
+}
+
+TEST(ViewTest, subSubViewTest) {
+ View view(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size());
+ std::vector<View> sub_views{view};
+ for (size_t i = 1; i < 6; i++) {
+ size_t parent_size = sub_views[i - 1].size();
+ sub_views.push_back({View(sub_views[i - 1], 1, parent_size - 1)});
+ ASSERT_EQ(sub_views[i][0], i);
+ ASSERT_EQ(sub_views[i].size(), parent_size - 2);
+ }
+}
+
+TEST(ViewTest, zeroSubViewTest) {
+ View view(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size());
+ View subview(view, view.size(), view.size() + 1);
+ ASSERT_EQ(subview.size(), 0u);
+}
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/test/raw_builder_test.cc b/vendor_libs/test_vendor_lib/packets/test/raw_builder_test.cc
new file mode 100644
index 0000000..a179b8b
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/test/raw_builder_test.cc
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2018 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 "packets/raw_builder.h"
+
+#include <gtest/gtest.h>
+#include <forward_list>
+#include <memory>
+
+#include "types/address.h"
+
+using std::vector;
+
+namespace {
+vector<uint8_t> count = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+};
+
+} // namespace
+
+namespace test_vendor_lib {
+namespace packets {
+
+class RawBuilderTest : public ::testing::Test {
+ public:
+ RawBuilderTest() = default;
+ ~RawBuilderTest() override = default;
+};
+
+TEST(RawBuilderTest, buildCountTest) {
+ std::unique_ptr<RawBuilder> count_builder = std::make_unique<RawBuilder>();
+ ASSERT_EQ(0u, count_builder->size());
+ count_builder->AddOctets8(0x0706050403020100);
+ count_builder->AddOctets4(0x0b0a0908);
+ count_builder->AddOctets2(0x0d0c);
+ count_builder->AddOctets1(0x0e);
+ count_builder->AddOctets1(0x0f);
+ count_builder->AddAddress(Address({0x10, 0x11, 0x12, 0x13, 0x14, 0x15}));
+ std::vector<uint8_t> count_subset(count.begin() + 0x16, count.end());
+ count_builder->AddOctets(count_subset);
+
+ ASSERT_EQ(count.size(), count_builder->size());
+
+ std::vector<uint8_t> packet;
+ std::back_insert_iterator<std::vector<uint8_t>> it(packet);
+
+ count_builder->Serialize(it);
+
+ ASSERT_EQ(count, packet);
+}
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/view.cc b/vendor_libs/test_vendor_lib/packets/view.cc
new file mode 100644
index 0000000..7dbd8bd
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/view.cc
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018 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 "view.h"
+
+#include <base/logging.h>
+
+namespace test_vendor_lib {
+namespace packets {
+
+View::View(std::shared_ptr<const std::vector<uint8_t>> data, size_t begin, size_t end)
+ : data_(data), begin_(begin < data_->size() ? begin : data_->size()),
+ end_(end < data_->size() ? end : data_->size()) {}
+
+View::View(const View& view, size_t begin, size_t end) : data_(view.data_) {
+ begin_ = (begin < view.size() ? begin : view.size());
+ begin_ += view.begin_;
+ end_ = (end < view.size() ? end : view.size());
+ end_ += view.begin_;
+}
+
+uint8_t View::operator[](size_t i) const {
+ CHECK(i + begin_ < end_) << "Out of bounds access at " << i;
+ return data_->operator[](i + begin_);
+}
+
+size_t View::size() const {
+ return end_ - begin_;
+}
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/view.h b/vendor_libs/test_vendor_lib/packets/view.h
new file mode 100644
index 0000000..ca38875
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/view.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2018 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>
+
+namespace test_vendor_lib {
+namespace packets {
+
+// Base class that holds a shared pointer to data with bounds.
+class View {
+ public:
+ View(std::shared_ptr<const std::vector<uint8_t>> data, size_t begin, size_t end);
+ View(const View& view, size_t begin, size_t end);
+ View(const View& view) = default;
+ virtual ~View() = default;
+
+ uint8_t operator[](size_t i) const;
+
+ size_t size() const;
+
+ private:
+ std::shared_ptr<const std::vector<uint8_t>> data_;
+ size_t begin_;
+ size_t end_;
+};
+
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/scripts/build_and_run.sh b/vendor_libs/test_vendor_lib/scripts/build_and_run.sh
index 34e0cfe..987a17f 100755
--- a/vendor_libs/test_vendor_lib/scripts/build_and_run.sh
+++ b/vendor_libs/test_vendor_lib/scripts/build_and_run.sh
@@ -108,7 +108,7 @@
adb push ${VENDOR_SYMBOLS_ABS}/${VENDOR_LIB} /vendor/lib
echo "Pushing controller properties."
- adb push ${TEST_VENDOR_LIB_ABS}/data/${CONTROLLER_PROPERTIES} /etc/bluetooth/
+ adb push ${TEST_VENDOR_LIB_ABS}/data/${CONTROLLER_PROPERTIES} /vendor/etc/bluetooth/
echo "Pushing libevent."
adb push ${DEVICE_TARGET_ABS}/${DEVICE}/system/lib/libevent.so /system/lib/
diff --git a/vendor_libs/test_vendor_lib/scripts/hci_socket.py b/vendor_libs/test_vendor_lib/scripts/hci_socket.py
new file mode 100644
index 0000000..0c425af
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/scripts/hci_socket.py
@@ -0,0 +1,441 @@
+#
+# 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 data to a port.
+
+This script provides a simple shell interface for sending data at run-time to a
+port.
+
+Usage:
+ 1. Choose a port to use. 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.
+
+ scapy is the tool we use to build packets in Python.
+
+ >>> d = HCI_Hdr(type=1) / HCI_Command_Hdr(opcode = 0x1004) /
+ Raw(load='\x01')
+ >>> print(d)
+ <HCI_Hdr type=Command |<HCI_Command_Hdr opcode=0x1004 |<Raw load='\x01'
+ |>>>
+ >>> raw(d)
+ '\x01\x04\x10\x01\x01'
+ >>> hexdump(d)
+ 0000 0104100101 .....
+
+
+ >>> pkt = HCI_Hdr('\x02\x02\x20\x0a\x00\x06\x00\x01\x00') /
+ L2CAP_CmdHdr(code=10, id=2, len=2) /L2CAP_InfoReq(type=2)
+ >>> pkt
+ <HCI_Hdr type=ACL Data |<HCI_ACL_Hdr handle=2 PB=0 BC=2 len=10 |<L2CAP_Hdr
+ len=6 cid=control |<L2CAP_CmdHdr code=info_req id=2 len=2 |<L2CAP_InfoReq
+ type=FEAT_MASK |>>>>>
+ >>> pkt = HCI_Hdr(type='ACL Data') / HCI_ACL_Hdr(handle=2, PB=0, BC=2,
+ len=10) / L2CAP_Hdr(len=6, cid='control') / L2CAP_CmdHdr(code='info_req',
+ id=2, len=2) / L2CAP_InfoReq(type='FEAT_MASK')
+ >>> raw(pkt)
+ '\x02\x02 \n\x00\x06\x00\x01\x00\n\x02\x02\x00\x02\x00'
+ >>> hexdump(pkt)
+ 0000 0202200A00060001000A0202000200 .. ............
+
+
+"""
+
+#!/usr/bin/env python
+
+import binascii
+import cmd
+import queue
+import random
+import socket
+import string
+import struct
+import sys
+from scapy.all import *
+""" Add some more SCAPY stuff"""
+
+
+class HCI_Cmd_Create_Connection(Packet):
+ name = 'Create Connection'
+ fields_desc = [
+ LEMACField('addr', None),
+ LEShortField('packet_type', 8),
+ ByteEnumField('page_scan_repetition_mode', 0, {
+ 0: 'R0',
+ 1: 'R1',
+ 2: 'R2'
+ }),
+ ByteEnumField('rsvd', 0, {0: 'Reserved'}),
+ LEShortField('clock_offset', 0),
+ ByteEnumField('allow_role_switch', 1, {
+ 0: 'false',
+ 1: 'true'
+ }),
+ ]
+
+
+class HCI_Cmd_Inquiry(Packet):
+ name = 'Inquiry'
+ fields_desc = [
+ X3BytesField('LAP', 0x9e8b0),
+ ByteField('length', 1),
+ ByteField('max_responses', 0),
+ ]
+
+
+bind_layers(HCI_Command_Hdr, HCI_Cmd_Inquiry, opcode=0x0401)
+bind_layers(HCI_Command_Hdr, HCI_Cmd_Create_Connection, opcode=0x0405)
+
+
+class HCI_Event_Inquiry_Result(Packet):
+ name = 'Inquiry Result'
+ fields_desc = [
+ ByteField('num_responses', 0),
+ LEMACField('addr', None),
+ ByteEnumField('page_scan_repetition_mode', 0, {
+ 0: 'R0',
+ 1: 'R1',
+ 2: 'R2'
+ }),
+ LEShortEnumField('rsvd', 0, {0: 'Reserved'}),
+ X3BytesField('class_of_device', 0),
+ LEShortField('clock_offset', 0),
+ ]
+
+
+class HCI_Event_Connection_Complete(Packet):
+ name = 'Connection Complete'
+ fields_desc = [
+ ByteField('status', 0),
+ LEShortField('handle', 0xffff),
+ LEMACField('addr', None),
+ ByteField('link_type', 1),
+ ByteField('encryption_mode', 0),
+ ]
+
+
+class HCI_Event_Remote_Name_Request_Complete(Packet):
+ name = 'Remote Name Request Complete'
+ fields_desc = [
+ ByteField('status', 0),
+ LEMACField('addr', None),
+ ]
+
+
+class HCI_Event_Read_Remote_Supported_Features_Complete(Packet):
+ name = 'Read Remote Supported Features Complete'
+ fields_desc = [
+ ByteField('status', 0),
+ LEShortField('handle', 0xffff),
+ XLELongField('features', 0x0123456789abcdef),
+ ]
+
+
+class HCI_Event_Read_Remote_Version_Information_Complete(Packet):
+ name = 'Read Remote Version Information Complete'
+ fields_desc = [
+ ByteField('status', 0),
+ LEShortField('handle', 0xffff),
+ ByteField('version', 0),
+ LEShortField('manufacturer_name', 0),
+ LEShortField('subversion', 0),
+ ]
+
+
+class HCI_Event_Read_Clock_Offset_Complete(Packet):
+ name = 'Read Clock Offset Complete'
+ fields_desc = [
+ ByteField('status', 0),
+ LEShortField('handle', 0xffff),
+ LEShortField('offset', 0xffff),
+ ]
+
+
+class HCI_Event_Read_Remote_Extended_Features_Complete(Packet):
+ name = 'Read Remote Supported Features Complete'
+ fields_desc = [
+ ByteField('status', 0),
+ LEShortField('handle', 0xffff),
+ ByteField('page_number', 0),
+ ByteField('max_page_number', 0),
+ XLELongField('features', 0x0123456789abcdef),
+ ]
+
+
+class HCI_Event_Extended_Inquiry_Result(Packet):
+ name = 'Extended Inquiry Result'
+ fields_desc = [
+ ByteField('num_responses', 1),
+ LEMACField('addr', None),
+ ByteEnumField('page_scan_repetition_mode', 0, {
+ 0: 'R0',
+ 1: 'R1',
+ 2: 'R2'
+ }),
+ ByteEnumField('rsvd', 0, {0: 'Reserved'}),
+ X3BytesField('class_of_device', 0),
+ LEShortField('clock_offset', 0),
+ SignedByteField('rssi', -20),
+ PacketListField('extended_inquiry_response', [], EIR_Hdr, 1),
+ ]
+
+
+bind_layers(HCI_Event_Hdr, HCI_Event_Inquiry_Result, code=0x02)
+bind_layers(HCI_Event_Hdr, HCI_Event_Connection_Complete, code=0x03)
+bind_layers(HCI_Event_Hdr, HCI_Event_Remote_Name_Request_Complete, code=0x07)
+bind_layers(
+ HCI_Event_Hdr, HCI_Event_Read_Remote_Supported_Features_Complete, code=0x0b)
+bind_layers(
+ HCI_Event_Hdr,
+ HCI_Event_Read_Remote_Version_Information_Complete,
+ code=0x0c)
+bind_layers(HCI_Event_Hdr, HCI_Event_Read_Clock_Offset_Complete, code=0x1c)
+bind_layers(
+ HCI_Event_Hdr, HCI_Event_Read_Remote_Extended_Features_Complete, code=0x23)
+bind_layers(HCI_Event_Hdr, HCI_Event_Extended_Inquiry_Result, code=0x2f)
+""" END SCAPY stuff"""
+
+
+class HCISocket(SuperSocket):
+ """Simple wrapper class for a socket object.
+
+ Attributes:
+ socket: The underlying socket created for the specified address and port.
+ """
+
+ def __init__(self, port):
+ self.done_ = False
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ s.connect(('localhost', port))
+ self.ins = self.outs = s
+ self.packets_ = queue.Queue()
+ self.rx_thread_ = threading.Thread(target=self.rx_thread_body)
+ self.rx_thread_.start()
+
+ def rx_bytes(self, size):
+ while not self.done_:
+ raw_bytes = b''
+ while len(raw_bytes) < size and not self.done_:
+ more_raw_bytes = self.ins.recv(min(size - len(raw_bytes), 2048))
+ if more_raw_bytes:
+ raw_bytes += more_raw_bytes
+ return raw_bytes
+
+ def rx_thread_body(self):
+ while not self.done_:
+ payload_length = 0
+ # Read the type
+ type_byte = self.rx_bytes(1)
+ if not type_byte:
+ continue
+ # Read the Header
+ header = b''
+ if type_byte == b'\x01': # Command
+ header = self.rx_bytes(3)
+ if not header:
+ continue
+ payload_length = header[2]
+ elif type_byte == b'\x02': # ACL
+ header = self.rx_bytes(4)
+ if not header:
+ continue
+ payload_length = header[3] << 8
+ payload_length |= header[2]
+ elif type_byte == b'\x03': # SCO
+ header = self.rx_bytes(3)
+ if not header:
+ continue
+ payload_length = header[2]
+ elif type_byte == b'\x04': # Event
+ header = self.rx_bytes(2)
+ if not header:
+ continue
+ payload_length = header[1]
+ else:
+ self.done_ = True
+ print('Rx: type_byte ' + hex(type_byte[0]))
+ # Read the Payload
+ payload = self.rx_bytes(payload_length) if payload_length != 0 else b''
+ packet_bytes = type_byte + header + payload
+ packet = HCI_Hdr(packet_bytes)
+ print('Rx: ' + packet.__repr__())
+ self.packets_.put(packet)
+
+ def get_packet(self):
+ if self.packets_.empty():
+ return False
+ return self.packets_.get()
+
+ def tell_rx_thread_to_quit(self):
+ self.done_ = True
+ self.rx_thread_.join()
+
+
+class HCIShell(cmd.Cmd):
+ """Shell for sending binary data to a port.
+
+ """
+
+ def __init__(self, hci):
+ cmd.Cmd.__init__(self)
+ self._hci = hci
+
+ def do_send(self, args):
+ """Arguments: dev_type_str Add a new device of type dev_type_str.
+
+ """
+ self._hci.send_binary(args.split())
+
+ def do_connect(self, args):
+ """Arguments: bluetooth_address xx:xx:xx:xx:xx:xx, timeout (seconds)
+
+ """
+ split_args = args.split()
+ address = split_args[0] if len(split_args) > 0 else 'NULL'
+ timeout = int(split_args[1]) if len(split_args) > 1 else 2
+ num_responses = 0
+ connect = HCI_Hdr(type='Command') / HCI_Command_Hdr(
+ opcode=0x0405) / HCI_Cmd_Create_Connection(addr=address)
+ self._hci.send(connect)
+ status = None
+ while status == None:
+ response = self._hci.get_packet()
+ if response == False:
+ continue
+ if response[HCI_Hdr].type == HCI_Hdr(
+ type='Event'
+ ).type and response[HCI_Event_Hdr].code == 0xf and response[
+ HCI_Event_Command_Status].opcode == connect[HCI_Command_Hdr].opcode:
+ status = response[HCI_Event_Command_Status].status
+ if status != HCI_Event_Command_Status(status='pending').status:
+ print('Connection failed with status = ' + str(status))
+ return
+
+ handle = None
+ while handle == None:
+ connection_complete = self._hci.get_packet()
+ if connection_complete == False:
+ continue
+ if (connection_complete[HCI_Hdr].type == HCI_Hdr(type='Event').type) and (
+ connection_complete[HCI_Event_Hdr].code == 0x3):
+ status = connection_complete[HCI_Event_Connection_Complete].status
+ if status != 0:
+ print('Connection complete with failed status = ' + str(status))
+ return
+ handle = connection_complete[HCI_Event_Connection_Complete].handle
+ print('Connection established with handle ' + str(handle))
+ connection_complete.show()
+ hexdump(connection_complete)
+
+ l2cap_done = False
+ while l2cap_done == None:
+ l2cap_req = self._hci.get_packet()
+ if l2cap_req == False:
+ continue
+ if (l2cap_req[HCI_Hdr].type == HCI_Hdr(type='ACL Data').type) and (
+ l2cap_req[L2CAP_Hdr].cid == L2CAP_Hdr(cid='control').cid) and (
+ l2cap_req[L2CAP_CmdHdr].code == L2CAP_CmdHdr(code='info_req').code
+ ) and (l2cap_req[L2CAP_InfoReq].type == L2CAP_InfoReq(
+ type='FEAT_MASK').type):
+ print('Send Features packet' + HCI_Hdr(type='ACL Data') / HCI_ACL_Hdr(
+ handle=l2cap_req[HCI_ACL_Hdr].handle, PB=0, BC=2, len=16) /
+ L2CAP_Hdr(len=12, cid='control') /
+ L2CAP_CmdHdr(code='info_resp', id=146, len=8) / L2CAP_InfoResp(
+ type=l2cap_req[L2CAP_InfoResp].type,
+ result='success',
+ data=b'\xb8\x00\x00\x00').__repr__())
+ self._hci.send(
+ HCI_Hdr(type='ACL Data') / HCI_ACL_Hdr(
+ handle=l2cap_req[HCI_ACL_Hdr].handle, PB=0, BC=2, len=16) /
+ L2CAP_Hdr(len=12, cid='control') / L2CAP_CmdHdr(
+ code='info_resp', id=146, len=8) / L2CAP_InfoResp(
+ type=l2cap_req[L2CAP_InfoResp].type,
+ result='success',
+ data=b'\xb8\x00\x00\x00'))
+
+ def do_le_scan(self, args):
+ """Arguments: enable (0 or 1), filter duplicates (0 or 1) Print the scan responses from reachable devices
+
+ """
+ split_args = args.split()
+ enable = int(split_args[0]) if len(split_args) > 0 else 1
+ filter_dups = int(split_args[1]) if len(split_args) > 1 else 1
+ set_scan_enable = HCI_Hdr(type=1) / HCI_Command_Hdr(
+ opcode=0x200c) / HCI_Cmd_LE_Set_Scan_Enable(
+ enable=enable, filter_dups=filter_dups)
+ print('Tx: ' + set_scan_enable.__repr__())
+ self._hci.send(set_scan_enable)
+
+ def do_scan(self, args):
+ """Arguments: timeout (seconds), max_results Print the scan responses from reachable devices
+
+ """
+ split_args = args.split()
+ scan_time = int(split_args[0]) if len(split_args) > 0 else 0
+ max_responses = int(split_args[1]) if len(split_args) > 1 else 0
+ num_responses = 0
+ inquiry = HCI_Hdr(type='Command') / HCI_Command_Hdr(
+ opcode=0x0401) / HCI_Cmd_Inquiry(
+ length=scan_time, max_responses=max_responses)
+ print('Tx: ' + inquiry.__repr__())
+ self._hci.send(inquiry)
+
+ def do_quit(self, args):
+ """Arguments: None.
+
+ Exits.
+ """
+ self._hci.tell_rx_thread_to_quit()
+ self._hci.close()
+ print('Goodbye.')
+ return True
+
+ def do_help(self, args):
+ """Arguments: [dev_num [attr]] List the commands available, optionally filtered by device and attr.
+
+ """
+ if (len(args) == 0):
+ cmd.Cmd.do_help(self, args)
+
+
+def main(argv):
+ if len(argv) != 2:
+ print('Usage: python hci_socket.py [port]')
+ return
+ try:
+ port = int(argv[1])
+ except ValueError:
+ print('Error parsing port.')
+ else:
+ try:
+ hci = HCISocket(port)
+ except socket.error as e:
+ print('Error connecting to socket: %s' % e)
+ except:
+ print('Error creating (check arguments).')
+ else:
+ hci_shell = HCIShell(hci)
+ hci_shell.prompt = '$ '
+ hci_shell.cmdloop('Welcome to the RootCanal HCI Console \n' +
+ 'Type \'help\' for more information.')
+
+
+if __name__ == '__main__':
+ main(sys.argv)
diff --git a/vendor_libs/test_vendor_lib/scripts/link_layer_socket.py b/vendor_libs/test_vendor_lib/scripts/link_layer_socket.py
new file mode 100644
index 0000000..c7b3045
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/scripts/link_layer_socket.py
@@ -0,0 +1,192 @@
+#
+# 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 data to a port.
+
+This script provides a simple shell interface for sending data at run-time to a
+port.
+
+Usage:
+ 1. Choose a port to use. 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.
+
+ scapy is the tool we use to build packets in Python.
+
+ >>> d = HCI_Hdr(type=1) / HCI_Command_Hdr(opcode = 0x1004) /
+ Raw(load='\x01')
+ >>> print(d)
+ <HCI_Hdr type=Command |<HCI_Command_Hdr opcode=0x1004 |<Raw load='\x01'
+ |>>>
+ >>> raw(d)
+ '\x01\x04\x10\x01\x01'
+ >>> hexdump(d)
+ 0000 0104100101 .....
+
+
+ >>> pkt = HCI_Hdr('\x02\x02\x20\x0a\x00\x06\x00\x01\x00') /
+ L2CAP_CmdHdr(code=10, id=2, len=2) /L2CAP_InfoReq(type=2)
+ >>> pkt
+ <HCI_Hdr type=ACL Data |<HCI_ACL_Hdr handle=2 PB=0 BC=2 len=10 |<L2CAP_Hdr
+ len=6 cid=control |<L2CAP_CmdHdr code=info_req id=2 len=2 |<L2CAP_InfoReq
+ type=FEAT_MASK |>>>>>
+ >>> pkt = HCI_Hdr(type='ACL Data') / HCI_ACL_Hdr(handle=2, PB=0, BC=2,
+ len=10) / L2CAP_Hdr(len=6, cid='control') / L2CAP_CmdHdr(code='info_req',
+ id=2, len=2) / L2CAP_InfoReq(type='FEAT_MASK')
+ >>> raw(pkt)
+ '\x02\x02 \n\x00\x06\x00\x01\x00\n\x02\x02\x00\x02\x00'
+ >>> hexdump(pkt)
+ 0000 0202200A00060001000A0202000200 .. ............
+
+
+"""
+
+#!/usr/bin/env python
+
+import binascii
+import cmd
+import queue
+import random
+import socket
+import string
+import struct
+import sys
+
+class LinkLayerSocket(object):
+ """Simple wrapper class for a socket object.
+
+ Attributes:
+ socket: The underlying socket created for the specified address and port.
+ """
+
+ def __init__(self, port):
+ print('port = ' + port)
+ self.done_ = False
+ self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self._socket.connect(('localhost', port))
+ # Should it be a non-blocking socket?
+ # self._socket.setblocking(0)
+ self.packets_ = queue.Queue()
+ self.rx_thread_ = threading.Thread(target=self.rx_thread_body)
+ self.rx_thread_.start()
+
+ def rx_bytes(self, size):
+ while not self.done_:
+ raw_bytes = b''
+ while len(raw_bytes) < size and not self.done_:
+ more_raw_bytes = self._socket.recv(min(size - len(raw_bytes), 2048))
+ if more_raw_bytes:
+ raw_bytes += more_raw_bytes
+ return raw_bytes
+
+ def rx_thread_body(self):
+ while not self.done_:
+ payload_length = 0
+ # Read the size (4B), the type (1B), and the addresses (2*6B)
+ header = self.rx_bytes(17)
+ if not header:
+ continue
+ payload_length = header[0]
+ payload_length |= header[1] << 8
+ payload_length |= header[2] << 16
+ payload_length |= header[3] << 24
+ print('Rx: type_byte ' + hex(header[4]))
+ print('Rx: from ' + hex(header[5]) + ':' + hex(header[6]) + ':' + hex(header[7]) + ':' + hex(header[8]) + ':' + hex(header[9]) + ':' + hex(header[10]))
+ print('Rx: to ' + hex(header[11]) + ':' + hex(header[12]) + ':' + hex(header[13]) + ':' + hex(header[14]) + ':' + hex(header[15]) + ':' + hex(header[16]))
+ # Read the Payload
+ payload = self.rx_bytes(payload_length) if payload_length != 0 else b''
+ packet_bytes = header + payload
+ self.packets_.put(packet_bytes)
+
+ def get_packet(self):
+ if self.packets_.empty():
+ return False
+ return self.packets_.get()
+
+ def send_binary(self, args):
+ joined_args = ''.join(arg for arg in args)
+ print(joined_args)
+ packet = binascii.a2b_hex(joined_args)
+ if self._done:
+ return
+ self._connection.send(packet)
+
+ def tell_rx_thread_to_quit(self):
+ self.done_ = True
+ self.rx_thread_.join()
+
+
+class LinkLayerShell(cmd.Cmd):
+ """Shell for sending binary data to a port.
+
+ """
+
+ def __init__(self, link_layer):
+ cmd.Cmd.__init__(self)
+ self._link_layer = link_layer
+
+ def do_send(self, args):
+ """Arguments: binary representation of a packet.
+
+ """
+ self._link_layer.send_binary(args.split())
+
+ def do_quit(self, args):
+ """Arguments: None.
+
+ Exits.
+ """
+ self._link_layer.tell_rx_thread_to_quit()
+ self._link_layer.close()
+ print('Goodbye.')
+ return True
+
+ def do_help(self, args):
+ """Arguments: [dev_num [attr]] List the commands available, optionally filtered by device and attr.
+
+ """
+ if (len(args) == 0):
+ cmd.Cmd.do_help(self, args)
+
+
+def main(argv):
+ if len(argv) != 2:
+ print('Usage: python link_layer_socket.py [port]')
+ return
+ try:
+ port = int(argv[1])
+ except ValueError:
+ print('Error parsing port.')
+ else:
+ try:
+ link_layer = LinkLayerSocket(port)
+ except socket.error as e:
+ print('Error connecting to socket: %s' % e)
+ except:
+ print('Error creating (check arguments).')
+ else:
+ link_layer_shell = LinkLayerShell(link_layer)
+ link_layer_shell.prompt = '$ '
+ link_layer_shell.cmdloop('Welcome to the RootCanal LinkLayer Console \n' +
+ 'Type \'help\' for more information.')
+
+
+if __name__ == '__main__':
+ main(sys.argv)
diff --git a/vendor_libs/test_vendor_lib/scripts/send_simple_commands.py b/vendor_libs/test_vendor_lib/scripts/send_simple_commands.py
new file mode 100644
index 0000000..cadeab3
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/scripts/send_simple_commands.py
@@ -0,0 +1,220 @@
+#
+# 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 data to a port.
+
+This script provides a simple shell interface for sending data at run-time to a
+port.
+
+Usage:
+ 1. Choose a port to use. 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.
+
+ scapy is the tool we use to build packets in Python.
+
+ >>> d = HCI_Hdr(type=1) / HCI_Command_Hdr(opcode = 0x1004) /
+ Raw(load='\x01')
+ >>> print(d)
+ <HCI_Hdr type=Command |<HCI_Command_Hdr opcode=0x1004 |<Raw load='\x01'
+ |>>>
+ >>> raw(d)
+ '\x01\x04\x10\x01\x01'
+ >>> hexdump(d)
+ 0000 0104100101 .....
+
+
+ >>> pkt = HCI_Hdr('\x02\x02\x20\x0a\x00\x06\x00\x01\x00') /
+ L2CAP_CmdHdr(code=10, id=2, len=2) /L2CAP_InfoReq(type=2)
+ >>> pkt
+ <HCI_Hdr type=ACL Data |<HCI_ACL_Hdr handle=2 PB=0 BC=2 len=10 |<L2CAP_Hdr
+ len=6 cid=control |<L2CAP_CmdHdr code=info_req id=2 len=2 |<L2CAP_InfoReq
+ type=FEAT_MASK |>>>>>
+ >>> pkt = HCI_Hdr(type="ACL Data") / HCI_ACL_Hdr(handle=2, PB=0, BC=2,
+ len=10) / L2CAP_Hdr(len=6, cid="control") / L2CAP_CmdHdr(code="info_req",
+ id=2, len=2) / L2CAP_InfoReq(type="FEAT_MASK")
+ >>> raw(pkt)
+ '\x02\x02 \n\x00\x06\x00\x01\x00\n\x02\x02\x00\x02\x00'
+ >>> hexdump(pkt)
+ 0000 0202200A00060001000A0202000200 .. ............
+
+
+"""
+
+#!/usr/bin/env python
+
+import binascii
+import cmd
+import random
+import socket
+import string
+import struct
+import sys
+from scapy.all import *
+
+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))
+ self._socket.setblocking(0)
+
+ def close(self):
+ self._socket.close()
+
+ def send(self, data):
+ self._socket.sendall(data)
+
+ def receive(self, size):
+ return self._socket.recv(size)
+
+
+class RawPort(object):
+ """Checks outgoing commands and sends them once verified.
+
+ Attributes:
+ connection: The connection to the HCI port.
+ """
+
+ def __init__(self, port):
+ self._connection = Connection(port)
+ self._closed = False
+
+ def close(self):
+ self._connection.close()
+ self._closed = True
+
+ def send_binary(self, args):
+ joined_args = ''.join(arg for arg in args)
+ print(joined_args)
+ packet = binascii.a2b_hex(joined_args)
+ if self._closed:
+ return
+ self._connection.send(packet)
+ received = self.receive_response()
+ received_bytes = bytearray(received)
+ print(raw(received_bytes))
+
+ def receive_response(self):
+ if self._closed:
+ return
+ size_chars = self._connection.receive(4)
+ if not size_chars:
+ print('Debug: No response')
+ return False
+ size_bytes = bytearray(size_chars)
+ response_size = 0
+ for i in range(0, len(size_chars) - 1):
+ response_size |= ord(size_chars[i]) << (8 * i)
+ response = self._connection.receive(response_size)
+ return response
+
+ 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 RawPortShell(cmd.Cmd):
+ """Shell for sending binary data to a port.
+
+ """
+
+ def __init__(self, raw_port):
+ cmd.Cmd.__init__(self)
+ self._raw_port = raw_port
+
+ def do_send(self, args):
+ """Arguments: dev_type_str Add a new device of type dev_type_str.
+
+ """
+ self._raw_port.send_binary(args.split())
+
+ def do_quit(self, args):
+ """Arguments: None.
+
+ Exits.
+ """
+ self._raw_port.close()
+ print('Goodbye.')
+ return True
+
+ def do_help(self, args):
+ """Arguments: [dev_num [attr]] List the commands available, optionally filtered by device and attr.
+
+ """
+ if (len(args) == 0):
+ cmd.Cmd.do_help(self, args)
+
+
+def main(argv):
+ if len(argv) != 2:
+ print('Usage: python raw_port.py [port]')
+ return
+ try:
+ port = int(argv[1])
+ except ValueError:
+ print('Error parsing port.')
+ else:
+ try:
+ raw_port = RawPort(port)
+ except (socket.error, e):
+ print('Error connecting to socket: %s' % e)
+ except:
+ print('Error creating (check arguments).')
+ else:
+ raw_port_shell = RawPortShell(raw_port)
+ raw_port_shell.prompt = '$ '
+ raw_port_shell.cmdloop('Welcome to the RootCanal Console \n' +
+ 'Type \'help\' for more information.')
+
+
+if __name__ == '__main__':
+ main(sys.argv)
diff --git a/vendor_libs/test_vendor_lib/scripts/simple_link_layer_socket.py b/vendor_libs/test_vendor_lib/scripts/simple_link_layer_socket.py
new file mode 100644
index 0000000..982aee2
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/scripts/simple_link_layer_socket.py
@@ -0,0 +1,197 @@
+#
+# Copyright 2018 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 data to a port.
+
+This script provides a simple shell interface for sending data at run-time to a
+port.
+
+Usage:
+ 1. Choose a port to use. 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.
+
+
+ length type source dest addr_type adv_type EIR Data
+
+ adv public connectable Name (TATA)
+send 18000000 07 010203040506 000000000000 00 00 050954415441
+ 020106
+
+ length adv source dest public non-conn Name (TETE)
+send 18000000 07 010203040507 000000000000 00 03 050954455445
+ 020106
+
+ length scan_rsp source dest public scan_rsp Name (TFTF)
+send 18000000 09 010203040506 4de24c67454b 00 04 050954465446
+ 020106
+
+"""
+
+#!/usr/bin/env python
+
+import binascii
+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))
+ self._socket.setblocking(0)
+
+ def close(self):
+ self._socket.close()
+
+ def send(self, data):
+ self._socket.sendall(data)
+
+ def receive(self, size):
+ return self._socket.recv(size)
+
+
+class RawPort(object):
+ """Checks outgoing commands and sends them once verified.
+
+ Attributes:
+ connection: The connection to the HCI port.
+ """
+
+ def __init__(self, port):
+ self._connection = Connection(port)
+ self._closed = False
+
+ def close(self):
+ self._connection.close()
+ self._closed = True
+
+ def send_binary(self, args):
+ joined_args = ''.join(arg for arg in args)
+ print(joined_args)
+ packet = binascii.a2b_hex(joined_args)
+ if self._closed:
+ return
+ self._connection.send(packet)
+
+ def receive_response(self):
+ if self._closed:
+ return
+ size_chars = self._connection.receive(4)
+ if not size_chars:
+ print('Debug: No response')
+ return False
+ size_bytes = bytearray(size_chars)
+ response_size = 0
+ for i in range(0, len(size_chars) - 1):
+ response_size |= ord(size_chars[i]) << (8 * i)
+ response = self._connection.receive(response_size)
+ return response
+
+ 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 RawPortShell(cmd.Cmd):
+ """Shell for sending binary data to a port."""
+
+ def __init__(self, raw_port):
+ cmd.Cmd.__init__(self)
+ self._raw_port = raw_port
+
+ def do_send(self, args):
+ """Arguments: dev_type_str Add a new device of type dev_type_str."""
+ self._raw_port.send_binary(args.split())
+
+ def do_quit(self, args):
+ """Arguments: None.
+
+ Exits.
+ """
+ self._raw_port.close()
+ print('Goodbye.')
+ return True
+
+ def do_help(self, args):
+ """Arguments: [dev_num [attr]] List the commands available, optionally filtered by device and attr."""
+ if (len(args) == 0):
+ cmd.Cmd.do_help(self, args)
+
+
+def main(argv):
+ if len(argv) != 2:
+ print('Usage: python raw_port.py [port]')
+ return
+ try:
+ port = int(argv[1])
+ except ValueError:
+ print('Error parsing port.')
+ else:
+ try:
+ raw_port = RawPort(port)
+ except (socket.error, e):
+ print('Error connecting to socket: %s' % e)
+ except:
+ print('Error creating (check arguments).')
+ else:
+ raw_port_shell = RawPortShell(raw_port)
+ raw_port_shell.prompt = '$ '
+ raw_port_shell.cmdloop('Welcome to the RootCanal Console \n' +
+ 'Type \'help\' for more information.')
+
+
+if __name__ == '__main__':
+ main(sys.argv)
diff --git a/vendor_libs/test_vendor_lib/scripts/simple_stack.py b/vendor_libs/test_vendor_lib/scripts/simple_stack.py
new file mode 100644
index 0000000..4f42bf2
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/scripts/simple_stack.py
@@ -0,0 +1,238 @@
+#
+# 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 data to a port.
+
+This script provides a simple shell interface for sending data at run-time to a
+port.
+
+Usage:
+ 1. Choose a port to use. 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.
+
+ scapy is the tool we use to build packets in Python.
+
+ >>> d = HCI_Hdr(type=1) / HCI_Command_Hdr(opcode = 0x1004) /
+ Raw(load='\x01')
+ >>> print(d)
+ <HCI_Hdr type=Command |<HCI_Command_Hdr opcode=0x1004 |<Raw load='\x01'
+ |>>>
+ >>> raw(d)
+ '\x01\x04\x10\x01\x01'
+ >>> hexdump(d)
+ 0000 0104100101 .....
+
+
+ >>> pkt = HCI_Hdr('\x02\x02\x20\x0a\x00\x06\x00\x01\x00') /
+ L2CAP_CmdHdr(code=10, id=2, len=2) /L2CAP_InfoReq(type=2)
+ >>> pkt
+ <HCI_Hdr type=ACL Data |<HCI_ACL_Hdr handle=2 PB=0 BC=2 len=10 |<L2CAP_Hdr
+ len=6 cid=control |<L2CAP_CmdHdr code=info_req id=2 len=2 |<L2CAP_InfoReq
+ type=FEAT_MASK |>>>>>
+ >>> pkt = HCI_Hdr(type="ACL Data") / HCI_ACL_Hdr(handle=2, PB=0, BC=2,
+ len=10) / L2CAP_Hdr(len=6, cid="control") / L2CAP_CmdHdr(code="info_req",
+ id=2, len=2) / L2CAP_InfoReq(type="FEAT_MASK")
+ >>> raw(pkt)
+ '\x02\x02 \n\x00\x06\x00\x01\x00\n\x02\x02\x00\x02\x00'
+ >>> hexdump(pkt)
+ 0000 0202200A00060001000A0202000200 .. ............
+
+
+"""
+
+#!/usr/bin/env python
+
+import binascii
+import cmd
+import random
+import socket
+import string
+import struct
+import sys
+from scapy.all import *
+""" Add some more SCAPY stuff"""
+
+
+class HCI_Cmd_Connect(Packet):
+ name = "Connect"
+ fields_desc = [
+ ByteEnumField("filter", 0, {0: "address"}),
+ LEShortField("packet_type", 8),
+ ByteEnumField("page_scan_repetition_mode", 0, {
+ 0: "R0",
+ 1: "R1",
+ 2: "R2"
+ }),
+ ByteEnumField("page_scan_repetition_mode", 0, {0: "Reserved"}),
+ LEShortField("clock_offset", 0),
+ ByteEnumField("allow_role_switch", 0, {
+ 0: "false",
+ 1: "true"
+ }),
+ ]
+
+
+class HCI_Cmd_Inquiry(Packet):
+ name = "Inquiry"
+ fields_desc = [
+ XByteField("LAP0", 0),
+ XByteField("LAP1", 0x8B),
+ XByteField("LAP2", 0x9E),
+ ByteField("length", 1),
+ ByteField("max_responses", 0),
+ ]
+
+
+""" END SCAPY stuff"""
+
+
+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)
+
+ def receive(self, size):
+ return self._socket.recv(size)
+
+
+class RawPort(object):
+ """Converts outgoing packets to binary and sends them.
+
+ Attributes:
+ connection: The connection to the HCI port.
+ """
+
+ def __init__(self, port):
+ self._connection = Connection(port)
+
+ def close(self):
+ self._connection.close()
+
+ def send_binary(self, args):
+ joined_args = "".join(arg for arg in args)
+ print(joined_args)
+ packet = binascii.a2b_hex(joined_args)
+ self._connection.send(packet)
+
+ def receive_response(self):
+ ready_to_read, ready_to_write, in_error = \
+ select.select(
+ [ self._connection._socket ],
+ [ ],
+ [ self._connection._socket ],
+ 1.5)
+ if len(in_error) > 0:
+ print("Error")
+ return False
+ if len(ready_to_read) > 0:
+ print("Ready to Read")
+ type_str = self._connection.receive(512)
+ print(len(type_str))
+ print(type_str)
+ return type_str
+ print("Returning false at the end")
+ return False
+
+
+class RawPortShell(cmd.Cmd):
+ """Shell for sending binary data to a port.
+
+ """
+
+ def __init__(self, raw_port):
+ cmd.Cmd.__init__(self)
+ self._raw_port = raw_port
+
+ def do_send(self, args):
+ """Arguments: dev_type_str Add a new device of type dev_type_str.
+
+ """
+ self._raw_port.send_binary(args.split())
+
+ def do_scan(self, args):
+ """Arguments: timeout (seconds) Print the scan responses from reachable devices
+
+ """
+ self._raw_port.send_binary(args.split())
+
+ def do_quit(self, args):
+ """Arguments: None.
+
+ Exits.
+ """
+ self._raw_port.close()
+ print("Goodbye.")
+ return True
+
+ def do_help(self, args):
+ """Arguments: [dev_num [attr]] List the commands available, optionally filtered by device and attr.
+
+ """
+ if (len(args) == 0):
+ cmd.Cmd.do_help(self, args)
+
+ def postcmd(self, stop, line):
+ """Called after each command stop : whether we will stop after this command line : the previous input line Return True to stop, False to continue
+
+ """
+ if stop:
+ return True
+ response = self._raw_port.receive_response()
+ print(response)
+ return False
+
+
+def main(argv):
+ if len(argv) != 2:
+ print("Usage: python raw_port.py [port]")
+ return
+ try:
+ port = int(argv[1])
+ except ValueError:
+ print("Error parsing port.")
+ else:
+ try:
+ raw_port = RawPort(port)
+ except (socket.error, e):
+ print("Error connecting to socket: %s" % e)
+ except:
+ print("Error creating (check arguments).")
+ else:
+ raw_port_shell = RawPortShell(raw_port)
+ raw_port_shell.prompt = "$ "
+ raw_port_shell.cmdloop("Welcome to the RootCanal Console \n" +
+ 'Type \'help\' for more information.')
+
+
+if __name__ == "__main__":
+ main(sys.argv)
diff --git a/vendor_libs/test_vendor_lib/scripts/test_channel.py b/vendor_libs/test_vendor_lib/scripts/test_channel.py
index 06b0410..15f5f1f 100644
--- a/vendor_libs/test_vendor_lib/scripts/test_channel.py
+++ b/vendor_libs/test_vendor_lib/scripts/test_channel.py
@@ -13,7 +13,6 @@
# 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
@@ -47,15 +46,18 @@
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.
@@ -73,25 +75,25 @@
def send(self, data):
self._socket.sendall(data)
+ def receive(self, size):
+ return self._socket.recv(size)
+
+
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.
+ 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
+ self._closed = False
def close(self):
self._connection.close()
+ self._closed = True
def send_command(self, name, args):
name_size = len(name)
@@ -100,7 +102,25 @@
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
+ if self._closed:
+ return
self._connection.send(command)
+ if name != 'CLOSE_TEST_CHANNEL':
+ print self.receive_response()
+
+ def receive_response(self):
+ if self._closed:
+ return
+ size_chars = self._connection.receive(4)
+ size_bytes = bytearray(size_chars)
+ if not size_chars:
+ print 'No response, assuming that the connection is broken'
+ return False
+ response_size = 0
+ for i in range(0, len(size_chars) - 1):
+ response_size |= ord(size_chars[i]) << (8 * i)
+ response = self._connection.receive(response_size)
+ return response
def lint_command(self, name, args, name_size, args_size):
assert name_size == len(name) and args_size == len(args)
@@ -117,39 +137,6 @@
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.
@@ -164,48 +151,72 @@
"""
def __init__(self, test_channel):
- print 'Type \'help\' for more information.'
cmd.Cmd.__init__(self)
self._test_channel = test_channel
def do_add(self, args):
- """
- Arguments: dev_type_str
- Add a new device of type dev_type_str.
+ """Arguments: dev_type_str Add a new device of type dev_type_str.
+
"""
self._test_channel.send_command('add', args.split())
def do_del(self, args):
- """
- Arguments: device index
- Delete the device with the specified index.
+ """Arguments: device index Delete the device with the specified index.
+
"""
self._test_channel.send_command('del', args.split())
- def do_get(self, args):
+ def do_add_phy(self, args):
+ """Arguments: dev_type_str Add a new device of type dev_type_str.
+
"""
- Arguments: dev_num attr_str
- Get the value of the attribute attr_str from device dev_num.
+ self._test_channel.send_command('add_phy', args.split())
+
+ def do_del_phy(self, args):
+ """Arguments: phy index Delete the phy with the specified index.
+
+ """
+ self._test_channel.send_command('del_phy', args.split())
+
+ def do_add_device_to_phy(self, args):
+ """Arguments: device index phy index Add a new device of type dev_type_str.
+
+ """
+ self._test_channel.send_command('add_device_to_phy', args.split())
+
+ def do_del_device_from_phy(self, args):
+ """Arguments: phy index Delete the phy with the specified index.
+
+ """
+ self._test_channel.send_command('del_device_from_phy', args.split())
+
+ def do_add_remote(self, args):
+ """Arguments: dev_type_str Connect to a remote device at arg1@arg2.
+
+ """
+ self._test_channel.send_command('add_remote', args.split())
+
+ def do_get(self, args):
+ """Arguments: dev_num attr_str Get the value of the attribute attr_str from device dev_num.
+
"""
self._test_channel.send_command('get', args.split())
def do_set(self, args):
- """
- Arguments: dev_num attr_str val
- Set the value of the attribute attr_str from device dev_num equal to val.
+ """Arguments: dev_num attr_str val Set the value of the attribute attr_str from device dev_num equal to val.
+
"""
self._test_channel.send_command('set', args.split())
def do_list(self, args):
- """
- Arguments: [dev_num [attr]]
- List the devices from the controller, optionally filtered by device and attr.
+ """Arguments: [dev_num [attr]] List the devices from the controller, optionally filtered by device and attr.
+
"""
self._test_channel.send_command('list', args.split())
def do_quit(self, args):
- """
- Arguments: None.
+ """Arguments: None.
+
Exits the test channel.
"""
self._test_channel.send_command('CLOSE_TEST_CHANNEL', [])
@@ -214,13 +225,35 @@
return True
def do_help(self, args):
+ """Arguments: [dev_num [attr]] List the commands available, optionally filtered by device and attr.
+
"""
- Arguments: [dev_num [attr]]
- List the commands available, optionally filtered by device and attr.
- """
- self._test_channel.send_command('help', args.split())
if (len(args) == 0):
cmd.Cmd.do_help(self, args)
+ else:
+ self._test_channel.send_command('help', args.split())
+
+ def preloop(self):
+ """Clear out the buffer
+
+ """
+ response = self._test_channel.receive_response()
+
+ #def postcmd(self, stop, line):
+ #"""
+ #Called after each command
+ #stop : whether we will stop after this command
+ #line : the previous input line
+ #Return True to stop, False to continue
+ #"""
+ #if stop:
+ #return True
+ #response = self._test_channel.receive_response()
+ #if not response:
+ #return True
+ #print response
+ #return False
+
def main(argv):
if len(argv) != 2:
@@ -240,7 +273,9 @@
else:
test_channel_shell = TestChannelShell(test_channel)
test_channel_shell.prompt = '$ '
- test_channel_shell.cmdloop()
+ test_channel_shell.cmdloop('Welcome to the RootCanal Console \n' +
+ 'Type \'help\' for more information.')
+
if __name__ == '__main__':
main(sys.argv)
diff --git a/vendor_libs/test_vendor_lib/src/acl_packet.cc b/vendor_libs/test_vendor_lib/src/acl_packet.cc
deleted file mode 100644
index 47aa8be..0000000
--- a/vendor_libs/test_vendor_lib/src/acl_packet.cc
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2017 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 "acl_packet"
-
-#include "acl_packet.h"
-
-#include "base/logging.h"
-#include "osi/include/log.h"
-#include "stack/include/hcidefs.h"
-
-using std::vector;
-
-namespace test_vendor_lib {
-
-AclPacket::AclPacket(uint16_t channel,
- AclPacket::PacketBoundaryFlags packet_boundary,
- AclPacket::BroadcastFlags broadcast)
- : raw_packet_({static_cast<uint8_t>(channel & 0xff),
- static_cast<uint8_t>(((channel >> 8) & 0x0f) |
- ((packet_boundary & 0x3) << 4) |
- (broadcast & 0x3) << 6),
- 0x00, 0x00}) {}
-
-void AclPacket::AddPayloadOctets(size_t octets, const vector<uint8_t>& bytes) {
- CHECK(bytes.size() == octets);
-
- raw_packet_.insert(raw_packet_.end(), bytes.begin(), bytes.end());
-
- raw_packet_[2] =
- static_cast<uint8_t>((raw_packet_.size() - kHeaderSize) & 0xff);
- raw_packet_[3] =
- static_cast<uint8_t>(((raw_packet_.size() - kHeaderSize) >> 8) & 0xff);
-}
-
-void AclPacket::AddPayloadOctets(size_t octets, uint64_t value) {
- vector<uint8_t> val_vector;
-
- uint64_t v = value;
-
- CHECK(octets <= sizeof(uint64_t));
-
- for (size_t i = 0; i < octets; i++) {
- val_vector.push_back(v & 0xff);
- v = v >> 8;
- }
-
- CHECK(v == 0);
-
- AddPayloadOctets(octets, val_vector);
-}
-
-size_t AclPacket::GetPacketSize() const { return raw_packet_.size(); }
-
-const std::vector<uint8_t>& AclPacket::GetPacket() const { return raw_packet_; }
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/async_manager.cc b/vendor_libs/test_vendor_lib/src/async_manager.cc
deleted file mode 100644
index 0e30af7..0000000
--- a/vendor_libs/test_vendor_lib/src/async_manager.cc
+++ /dev/null
@@ -1,520 +0,0 @@
-/*
- * Copyright 2016 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 "async_manager"
-
-#include "async_manager.h"
-
-#include "osi/include/log.h"
-
-#include <algorithm>
-#include <atomic>
-#include <condition_variable>
-#include <mutex>
-#include <thread>
-#include <vector>
-#include "fcntl.h"
-#include "sys/select.h"
-#include "unistd.h"
-
-namespace test_vendor_lib {
-// Implementation of AsyncManager is divided between two classes, three if
-// AsyncManager itself is taken into account, but its only responsability
-// besides being a proxy for the other two classes is to provide a global
-// synchronization mechanism for callbacks and client code to use.
-
-// The watching of file descriptors is done through AsyncFdWatcher. Several
-// objects of this class may coexist simultaneosly as they share no state.
-// After construction of this objects nothing happens beyond some very simple
-// member initialization. When the first FD is set up for watching the object
-// starts a new thread which watches the given (and later provided) FDs using
-// select() inside a loop. A special FD (a pipe) is also watched which is
-// used to notify the thread of internal changes on the object state (like
-// the addition of new FDs to watch on). Every access to internal state is
-// synchronized using a single internal mutex. The thread is only stopped on
-// destruction of the object, by modifying a flag, which is the only member
-// variable accessed without acquiring the lock (because the notification to
-// the thread is done later by writing to a pipe which means the thread will
-// be notified regardless of what phase of the loop it is in that moment)
-
-// The scheduling of asynchronous tasks, periodic or not, is handled by the
-// AsyncTaskManager class. Like the one for FDs, this class shares no internal
-// state between different instances so it is safe to use several objects of
-// this class, also nothing interesting happens upon construction, but only
-// after a Task has been scheduled and access to internal state is synchronized
-// using a single internal mutex. When the first task is scheduled a thread
-// is started which monitors a queue of tasks. The queue is peeked to see
-// when the next task should be carried out and then the thread performs a
-// (absolute) timed wait on a condition variable. The wait ends because of a
-// time out or a notify on the cond var, the former means a task is due
-// for execution while the later means there has been a change in internal
-// state, like a task has been scheduled/canceled or the flag to stop has
-// been set. Setting and querying the stop flag or modifying the task queue
-// and subsequent notification on the cond var is done atomically (e.g while
-// holding the lock on the internal mutex) to ensure that the thread never
-// misses the notification, since notifying a cond var is not persistent as
-// writing on a pipe (if not done this way, the thread could query the
-// stopping flag and be put aside by the OS scheduler right after, then the
-// 'stop thread' procedure could run, setting the flag, notifying a cond
-// var that no one is waiting on and joining the thread, the thread then
-// resumes execution believing that it needs to continue and waits on the
-// cond var possibly forever if there are no tasks scheduled, efectively
-// causing a deadlock).
-
-// This number also states the maximum number of scheduled tasks we can handle
-// at a given time
-static const uint16_t kMaxTaskId =
- -1; /* 2^16 - 1, permisible ids are {1..2^16-1}*/
-static inline AsyncTaskId NextAsyncTaskId(const AsyncTaskId id) {
- return (id == kMaxTaskId) ? 1 : id + 1;
-}
-// The buffer is only 10 bytes because the expected number of bytes
-// written on this socket is 1. It is possible that the thread is notified
-// more than once but highly unlikely, so a buffer of size 10 seems enough
-// and the reads are performed inside a while just in case it isn't. From
-// the thread routine's point of view it is the same to have been notified
-// just once or 100 times so it just tries to consume the entire buffer.
-// In the cases where an interrupt would cause read to return without
-// having read everything that was available a new iteration of the thread
-// loop will bring execution to this point almost immediately, so there is
-// no need to treat that case.
-static const int kNotificationBufferSize = 10;
-
-// Async File Descriptor Watcher Implementation:
-class AsyncManager::AsyncFdWatcher {
- public:
- int WatchFdForNonBlockingReads(
- int file_descriptor, const ReadCallback& on_read_fd_ready_callback) {
- // add file descriptor and callback
- {
- std::unique_lock<std::mutex> guard(internal_mutex_);
- watched_shared_fds_[file_descriptor] = on_read_fd_ready_callback;
- }
-
- // start the thread if not started yet
- int started = tryStartThread();
- if (started != 0) {
- LOG_ERROR(LOG_TAG, "%s: Unable to start thread", __func__);
- return started;
- }
-
- // notify the thread so that it knows of the new FD
- notifyThread();
-
- return 0;
- }
-
- void StopWatchingFileDescriptor(int file_descriptor) {
- std::unique_lock<std::mutex> guard(internal_mutex_);
- watched_shared_fds_.erase(file_descriptor);
- }
-
- AsyncFdWatcher() = default;
-
- ~AsyncFdWatcher() = default;
-
- int stopThread() {
- if (!std::atomic_exchange(&running_, false)) {
- return 0; // if not running already
- }
-
- notifyThread();
-
- if (std::this_thread::get_id() != thread_.get_id()) {
- thread_.join();
- } else {
- LOG_WARN(LOG_TAG,
- "%s: Starting thread stop from inside the reading thread itself",
- __func__);
- }
-
- {
- std::unique_lock<std::mutex> guard(internal_mutex_);
- watched_shared_fds_.clear();
- }
-
- return 0;
- }
-
- private:
- AsyncFdWatcher(const AsyncFdWatcher&) = delete;
- AsyncFdWatcher& operator=(const AsyncFdWatcher&) = delete;
-
- // Make sure to call this with at least one file descriptor ready to be
- // watched upon or the thread routine will return immediately
- int tryStartThread() {
- if (std::atomic_exchange(&running_, true)) {
- return 0; // if already running
- }
- // set up the communication channel
- int pipe_fds[2];
- if (pipe2(pipe_fds, O_NONBLOCK)) {
- LOG_ERROR(LOG_TAG,
- "%s:Unable to establish a communication channel to the reading "
- "thread",
- __func__);
- return -1;
- }
- notification_listen_fd_ = pipe_fds[0];
- notification_write_fd_ = pipe_fds[1];
-
- thread_ = std::thread([this]() { ThreadRoutine(); });
- if (!thread_.joinable()) {
- LOG_ERROR(LOG_TAG, "%s: Unable to start reading thread", __func__);
- return -1;
- }
- return 0;
- }
-
- int notifyThread() {
- char buffer = '0';
- if (TEMP_FAILURE_RETRY(write(notification_write_fd_, &buffer, 1)) < 0) {
- LOG_ERROR(LOG_TAG, "%s: Unable to send message to reading thread",
- __func__);
- return -1;
- }
- return 0;
- }
-
- int setUpFileDescriptorSet(fd_set& read_fds) {
- // add comm channel to the set
- FD_SET(notification_listen_fd_, &read_fds);
- int nfds = notification_listen_fd_;
-
- // add watched FDs to the set
- {
- std::unique_lock<std::mutex> guard(internal_mutex_);
- for (auto& fdp : watched_shared_fds_) {
- FD_SET(fdp.first, &read_fds);
- nfds = std::max(fdp.first, nfds);
- }
- }
- return nfds;
- }
-
- // check the comm channel and read everything there
- bool consumeThreadNotifications(fd_set& read_fds) {
- if (FD_ISSET(notification_listen_fd_, &read_fds)) {
- char buffer[kNotificationBufferSize];
- while (TEMP_FAILURE_RETRY(read(notification_listen_fd_, buffer,
- kNotificationBufferSize)) ==
- kNotificationBufferSize) {
- }
- return true;
- }
- return false;
- }
-
- // check all file descriptors and call callbacks if necesary
- void runAppropriateCallbacks(fd_set& read_fds) {
- // not a good idea to call a callback while holding the FD lock,
- // nor to release the lock while traversing the map
- std::vector<decltype(watched_shared_fds_)::value_type> fds;
- {
- std::unique_lock<std::mutex> guard(internal_mutex_);
- for (auto& fdc : watched_shared_fds_) {
- if (FD_ISSET(fdc.first, &read_fds)) {
- fds.push_back(fdc);
- }
- }
- }
- for (auto& p : fds) {
- p.second(p.first);
- }
- }
-
- void ThreadRoutine() {
- while (running_) {
- fd_set read_fds;
- FD_ZERO(&read_fds);
- int nfds = setUpFileDescriptorSet(read_fds);
-
- // wait until there is data available to read on some FD
- int retval = select(nfds + 1, &read_fds, NULL, NULL, NULL);
- if (retval <= 0) { // there was some error or a timeout
- LOG_ERROR(LOG_TAG,
- "%s: There was an error while waiting for data on the file "
- "descriptors",
- __func__);
- continue;
- }
-
- consumeThreadNotifications(read_fds);
-
- // Do not read if there was a call to stop running
- if (!running_) {
- break;
- }
-
- runAppropriateCallbacks(read_fds);
- }
- }
-
- std::atomic_bool running_{false};
- std::thread thread_;
- std::mutex internal_mutex_;
-
- std::map<int, ReadCallback> watched_shared_fds_;
-
- // A pair of FD to send information to the reading thread
- int notification_listen_fd_;
- int notification_write_fd_;
-};
-
-// Async task manager implementation
-class AsyncManager::AsyncTaskManager {
- public:
- AsyncTaskId ExecAsync(std::chrono::milliseconds delay,
- const TaskCallback& callback) {
- return scheduleTask(std::make_shared<Task>(
- std::chrono::steady_clock::now() + delay, callback));
- }
-
- AsyncTaskId ExecAsyncPeriodically(std::chrono::milliseconds delay,
- std::chrono::milliseconds period,
- const TaskCallback& callback) {
- return scheduleTask(std::make_shared<Task>(
- std::chrono::steady_clock::now() + delay, period, callback));
- }
-
- bool CancelAsyncTask(AsyncTaskId async_task_id) {
- // remove task from queue (and task id asociation) while holding lock
- std::unique_lock<std::mutex> guard(internal_mutex_);
- if (tasks_by_id.count(async_task_id) == 0) {
- return false;
- }
- task_queue_.erase(tasks_by_id[async_task_id]);
- tasks_by_id.erase(async_task_id);
- return true;
- }
-
- AsyncTaskManager() = default;
-
- ~AsyncTaskManager() = default;
-
- int stopThread() {
- {
- std::unique_lock<std::mutex> guard(internal_mutex_);
- tasks_by_id.clear();
- task_queue_.clear();
- if (!running_) {
- return 0;
- }
- running_ = false;
- // notify the thread
- internal_cond_var_.notify_one();
- } // release the lock before joining a thread that is likely waiting for it
- if (std::this_thread::get_id() != thread_.get_id()) {
- thread_.join();
- } else {
- LOG_WARN(LOG_TAG,
- "%s: Starting thread stop from inside the task thread itself",
- __func__);
- }
- return 0;
- }
-
- private:
- // Holds the data for each task
- class Task {
- public:
- Task(std::chrono::steady_clock::time_point time,
- std::chrono::milliseconds period, const TaskCallback& callback)
- : time(time),
- periodic(true),
- period(period),
- callback(callback),
- task_id(kInvalidTaskId) {}
- Task(std::chrono::steady_clock::time_point time,
- const TaskCallback& callback)
- : time(time),
- periodic(false),
- callback(callback),
- task_id(kInvalidTaskId) {}
-
- // Operators needed to be in a collection
- bool operator<(const Task& another) const {
- return std::make_pair(time, task_id) <
- std::make_pair(another.time, another.task_id);
- }
-
- bool isPeriodic() const { return periodic; }
-
- // These fields should no longer be public if the class ever becomes
- // public or gets more complex
- std::chrono::steady_clock::time_point time;
- bool periodic;
- std::chrono::milliseconds period;
- TaskCallback callback;
- AsyncTaskId task_id;
- };
-
- // A comparator class to put shared pointers to tasks in an ordered set
- struct task_p_comparator {
- bool operator()(const std::shared_ptr<Task>& t1,
- const std::shared_ptr<Task>& t2) const {
- return *t1 < *t2;
- }
- };
-
- AsyncTaskManager(const AsyncTaskManager&) = delete;
- AsyncTaskManager& operator=(const AsyncTaskManager&) = delete;
-
- AsyncTaskId scheduleTask(const std::shared_ptr<Task>& task) {
- AsyncTaskId task_id = kInvalidTaskId;
- {
- std::unique_lock<std::mutex> guard(internal_mutex_);
- // no more room for new tasks, we need a larger type for IDs
- if (tasks_by_id.size() == kMaxTaskId) // TODO potentially type unsafe
- return kInvalidTaskId;
- do {
- lastTaskId_ = NextAsyncTaskId(lastTaskId_);
- } while (isTaskIdInUse(lastTaskId_));
- task->task_id = lastTaskId_;
- // add task to the queue and map
- tasks_by_id[lastTaskId_] = task;
- task_queue_.insert(task);
- task_id = lastTaskId_;
- }
- // start thread if necessary
- int started = tryStartThread();
- if (started != 0) {
- LOG_ERROR(LOG_TAG, "%s: Unable to start thread", __func__);
- return kInvalidTaskId;
- }
- // notify the thread so that it knows of the new task
- internal_cond_var_.notify_one();
- // return task id
- return task_id;
- }
-
- bool isTaskIdInUse(const AsyncTaskId& task_id) const {
- return tasks_by_id.count(task_id) != 0;
- }
-
- int tryStartThread() {
- // need the lock because of the running flag and the cond var
- std::unique_lock<std::mutex> guard(internal_mutex_);
- // check that the thread is not yet running
- if (running_) {
- return 0;
- }
- // start the thread
- running_ = true;
- thread_ = std::thread([this]() { ThreadRoutine(); });
- if (!thread_.joinable()) {
- LOG_ERROR(LOG_TAG, "%s: Unable to start task thread", __func__);
- return -1;
- }
- return 0;
- }
-
- void ThreadRoutine() {
- while (1) {
- TaskCallback callback;
- bool run_it = false;
- {
- std::unique_lock<std::mutex> guard(internal_mutex_);
- if (!task_queue_.empty()) {
- std::shared_ptr<Task> task_p = *(task_queue_.begin());
- if (task_p->time < std::chrono::steady_clock::now()) {
- run_it = true;
- callback = task_p->callback;
- task_queue_.erase(task_p); // need to remove and add again if
- // periodic to update order
- if (task_p->isPeriodic()) {
- task_p->time += task_p->period;
- task_queue_.insert(task_p);
- } else {
- tasks_by_id.erase(task_p->task_id);
- }
- }
- }
- }
- if (run_it) {
- callback();
- }
- {
- std::unique_lock<std::mutex> guard(internal_mutex_);
- // wait on condition variable with timeout just in time for next task if
- // any
- if (task_queue_.size() > 0) {
- internal_cond_var_.wait_until(guard, (*task_queue_.begin())->time);
- } else {
- internal_cond_var_.wait(guard);
- }
- // check for termination right after being notified (and maybe before?)
- if (!running_) break;
- }
- }
- }
-
- bool running_ = false;
- std::thread thread_;
- std::mutex internal_mutex_;
- std::condition_variable internal_cond_var_;
-
- AsyncTaskId lastTaskId_ = kInvalidTaskId;
- std::map<AsyncTaskId, std::shared_ptr<Task> > tasks_by_id;
- std::set<std::shared_ptr<Task>, task_p_comparator> task_queue_;
-};
-
-// Async Manager Implementation:
-AsyncManager::AsyncManager()
- : fdWatcher_p_(new AsyncFdWatcher()),
- taskManager_p_(new AsyncTaskManager()) {}
-
-AsyncManager::~AsyncManager() {
- // Make sure the threads are stopped before destroying the object.
- // The threads need to be stopped here and not in each internal class'
- // destructor because unique_ptr's reset() first assigns nullptr to the
- // pointer and only then calls the destructor, so any callback running
- // on these threads would dereference a null pointer if they called a member
- // function of this class.
- fdWatcher_p_->stopThread();
- taskManager_p_->stopThread();
-}
-
-int AsyncManager::WatchFdForNonBlockingReads(
- int file_descriptor, const ReadCallback& on_read_fd_ready_callback) {
- return fdWatcher_p_->WatchFdForNonBlockingReads(file_descriptor,
- on_read_fd_ready_callback);
-}
-
-void AsyncManager::StopWatchingFileDescriptor(int file_descriptor) {
- fdWatcher_p_->StopWatchingFileDescriptor(file_descriptor);
-}
-
-AsyncTaskId AsyncManager::ExecAsync(std::chrono::milliseconds delay,
- const TaskCallback& callback) {
- return taskManager_p_->ExecAsync(delay, callback);
-}
-
-AsyncTaskId AsyncManager::ExecAsyncPeriodically(
- std::chrono::milliseconds delay, std::chrono::milliseconds period,
- const TaskCallback& callback) {
- return taskManager_p_->ExecAsyncPeriodically(delay, period, callback);
-}
-
-bool AsyncManager::CancelAsyncTask(AsyncTaskId async_task_id) {
- return taskManager_p_->CancelAsyncTask(async_task_id);
-}
-
-void AsyncManager::Synchronize(const CriticalCallback& critical) {
- std::unique_lock<std::mutex> guard(synchronization_mutex_);
- critical();
-}
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/beacon.cc b/vendor_libs/test_vendor_lib/src/beacon.cc
deleted file mode 100644
index 0ca4507..0000000
--- a/vendor_libs/test_vendor_lib/src/beacon.cc
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2016 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 "beacon"
-
-#include "beacon.h"
-#include "stack/include/hcidefs.h"
-
-using std::vector;
-
-namespace test_vendor_lib {
-Beacon::Beacon() {
- advertising_interval_ms_ = std::chrono::milliseconds(1280);
- advertising_type_ = BTM_BLE_NON_CONNECT_EVT;
- adv_data_ = {0x0F, // Length
- BTM_BLE_AD_TYPE_NAME_CMPL,
- 'g',
- 'D',
- 'e',
- 'v',
- 'i',
- 'c',
- 'e',
- '-',
- 'b',
- 'e',
- 'a',
- 'c',
- 'o',
- 'n',
- 0x02, // Length
- BTM_BLE_AD_TYPE_FLAG,
- BTM_BLE_BREDR_NOT_SPT | BTM_BLE_GEN_DISC_FLAG};
-
- scan_data_ = {0x05, // Length
- BTM_BLE_AD_TYPE_NAME_SHORT,
- 'b',
- 'e',
- 'a',
- 'c'};
-}
-
-void Beacon::Initialize(const vector<std::string>& args) {
- if (args.size() < 2) return;
-
- BtAddress addr;
- if (addr.FromString(args[1])) SetBtAddress(addr);
-
- if (args.size() < 3) return;
-
- SetAdvertisementInterval(std::chrono::milliseconds(std::stoi(args[2])));
-}
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/beacon_swarm.cc b/vendor_libs/test_vendor_lib/src/beacon_swarm.cc
deleted file mode 100644
index 2f4eed1..0000000
--- a/vendor_libs/test_vendor_lib/src/beacon_swarm.cc
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2016 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 "beacon_swarm"
-
-#include "beacon_swarm.h"
-#include "stack/include/hcidefs.h"
-
-using std::vector;
-
-namespace test_vendor_lib {
-BeaconSwarm::BeaconSwarm() {
- advertising_interval_ms_ = std::chrono::milliseconds(1280);
- advertising_type_ = BTM_BLE_NON_CONNECT_EVT;
- adv_data_ = {0x02, // Length
- BTM_BLE_AD_TYPE_FLAG,
- BTM_BLE_BREDR_NOT_SPT | BTM_BLE_GEN_DISC_FLAG,
- 0x15,
- BTM_BLE_AD_TYPE_NAME_CMPL,
- 'g',
- 'D',
- 'e',
- 'v',
- 'i',
- 'c',
- 'e',
- '-',
- 'b',
- 'e',
- 'a',
- 'c',
- 'o',
- 'n',
- '_',
- 's',
- 'w',
- 'a',
- 'r',
- 'm'};
-
- scan_response_present_ = true;
- scan_data_ = {0x06, // Length
- BTM_BLE_AD_TYPE_NAME_SHORT,
- 'c',
- 'b',
- 'e',
- 'a',
- 'c'};
-}
-
-void BeaconSwarm::Initialize(const vector<std::string>& args) {
- if (args.size() < 2) return;
-
- BtAddress addr;
- if (addr.FromString(args[1])) SetBtAddress(addr);
-
- if (args.size() < 3) return;
-
- SetAdvertisementInterval(std::chrono::milliseconds(std::stoi(args[2])));
-}
-
-void BeaconSwarm::TimerTick() {
- std::vector<uint8_t> beacon_addr;
- GetBtAddress().ToVector(beacon_addr);
- beacon_addr[0]++;
- BtAddress next_addr;
- next_addr.FromVector(beacon_addr);
-
- SetBtAddress(next_addr);
-}
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/broken_adv.cc b/vendor_libs/test_vendor_lib/src/broken_adv.cc
deleted file mode 100644
index 92f47fa..0000000
--- a/vendor_libs/test_vendor_lib/src/broken_adv.cc
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright 2016 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 "broken_adv"
-
-#include "broken_adv.h"
-
-#include "osi/include/log.h"
-#include "stack/include/hcidefs.h"
-
-using std::vector;
-
-namespace test_vendor_lib {
-
-BrokenAdv::BrokenAdv() {
- advertising_interval_ms_ = std::chrono::milliseconds(1280);
- advertising_type_ = BTM_BLE_NON_CONNECT_EVT;
- adv_data_ = {
- 0x02, // Length
- BTM_BLE_AD_TYPE_FLAG,
- BTM_BLE_BREDR_NOT_SPT | BTM_BLE_GEN_DISC_FLAG,
- 0x13, // Length
- BTM_BLE_AD_TYPE_NAME_CMPL,
- 'g',
- 'D',
- 'e',
- 'v',
- 'i',
- 'c',
- 'e',
- '-',
- 'b',
- 'r',
- 'o',
- 'k',
- 'e',
- 'n',
- '_',
- 'a',
- 'd',
- 'v',
- };
-
- constant_adv_data_ = adv_data_;
-
- scan_response_present_ = true;
- scan_data_ = {0x0b, // Length
- BTM_BLE_AD_TYPE_NAME_SHORT,
- 'b',
- 'r',
- 'o',
- 'k',
- 'e',
- 'n',
- 'n',
- 'e',
- 's',
- 's'};
-
- extended_inquiry_data_ = {0x07, // Length
- BT_EIR_COMPLETE_LOCAL_NAME_TYPE,
- 'B',
- 'R',
- '0',
- 'K',
- '3',
- 'N'};
- page_scan_repetition_mode_ = 0;
- page_scan_delay_ms_ = std::chrono::milliseconds(600);
-}
-
-void BrokenAdv::Initialize(const vector<std::string>& args) {
- if (args.size() < 2) return;
-
- BtAddress addr;
- if (addr.FromString(args[1])) SetBtAddress(addr);
-
- if (args.size() < 3) return;
-
- SetAdvertisementInterval(std::chrono::milliseconds(std::stoi(args[2])));
-}
-
-// Mostly return the correct length
-static uint8_t random_length(size_t bytes_remaining) {
- uint32_t randomness = rand();
-
- switch ((randomness & 0xf000000) >> 24) {
- case (0):
- return bytes_remaining + (randomness & 0xff);
- case (1):
- return bytes_remaining - (randomness & 0xff);
- case (2):
- return bytes_remaining + (randomness & 0xf);
- case (3):
- return bytes_remaining - (randomness & 0xf);
- case (5):
- case (6):
- return bytes_remaining + (randomness & 0x3);
- case (7):
- case (8):
- return bytes_remaining - (randomness & 0x3);
- default:
- return bytes_remaining;
- }
-}
-
-static size_t random_adv_type() {
- uint32_t randomness = rand();
-
- switch ((randomness & 0xf000000) >> 24) {
- case (0):
- return BTM_EIR_MANUFACTURER_SPECIFIC_TYPE;
- case (1):
- return (randomness & 0xff);
- default:
- return (randomness & 0x1f);
- }
-}
-
-static size_t random_data_length(size_t length, size_t bytes_remaining) {
- uint32_t randomness = rand();
-
- switch ((randomness & 0xf000000) >> 24) {
- case (0):
- return bytes_remaining;
- case (1):
- return (length + (randomness & 0xff)) % bytes_remaining;
- default:
- return (length <= bytes_remaining ? length : bytes_remaining);
- }
-}
-
-static void RandomizeAdvertisement(vector<uint8_t>& ad, size_t max) {
- uint8_t length = random_length(max);
- uint8_t data_length = random_data_length(length, max);
-
- ad.push_back(random_adv_type());
- ad.push_back(length);
- for (size_t i = 0; i < data_length; i++) ad.push_back(rand() & 0xff);
-}
-
-void BrokenAdv::UpdateAdvertisement() {
- adv_data_.clear();
- for (size_t i = 0; i < constant_adv_data_.size(); i++)
- adv_data_.push_back(constant_adv_data_[i]);
-
- RandomizeAdvertisement(adv_data_, 31 - adv_data_.size());
-
- RandomizeAdvertisement(scan_data_, 31);
-
- std::vector<uint8_t> curr_addr;
- BtAddress next_addr;
- GetBtAddress().ToVector(curr_addr);
- curr_addr[0]++;
- next_addr.FromVector(curr_addr);
-
- SetBtAddress(next_addr);
-}
-
-std::string BrokenAdv::ToString() const {
- std::string str = Device::ToString() + std::string(": Interval = ") +
- std::to_string(advertising_interval_ms_.count());
- return str;
-}
-
-void BrokenAdv::UpdatePageScan() {
- std::vector<uint8_t> broken_addr;
- RandomizeAdvertisement(scan_data_, 31);
-
- BtAddress next_addr;
- GetBtAddress().ToVector(broken_addr);
- broken_addr[1]++;
- next_addr.FromVector(broken_addr);
-
- SetBtAddress(next_addr);
-}
-
-void BrokenAdv::TimerTick() {
- UpdatePageScan();
- UpdateAdvertisement();
-}
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/bt_address.cc b/vendor_libs/test_vendor_lib/src/bt_address.cc
deleted file mode 100644
index e9d6790..0000000
--- a/vendor_libs/test_vendor_lib/src/bt_address.cc
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright 2016 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 "bt_address.h"
-#include <iomanip>
-#include <vector>
-using std::vector;
-
-#include <base/logging.h>
-
-namespace test_vendor_lib {
-
-bool BtAddress::IsValid(const std::string& addr) {
- if (addr.length() < kStringLength) return false;
-
- for (size_t i = 0; i < kStringLength; i++) {
- if (i % 3 == 2) { // Every third character must be ':'
- if (addr[i] != ':') return false;
- } else { // The rest must be hexadecimal digits
- if (!isxdigit(addr[i])) return false;
- }
- }
- return true;
-}
-
-bool BtAddress::FromString(const std::string& str) {
- std::string tok;
- std::istringstream iss(str);
-
- if (!IsValid(str)) return false;
-
- address_ = 0;
- for (size_t i = 0; i < kOctets; i++) {
- getline(iss, tok, ':');
- uint64_t octet = std::stoi(tok, nullptr, 16);
- address_ |= (octet << (8 * ((kOctets - 1) - i)));
- }
- return true;
-}
-
-bool BtAddress::FromVector(const vector<uint8_t>& octets) {
- if (octets.size() < kOctets) return false;
-
- address_ = 0;
- for (size_t i = 0; i < kOctets; i++) {
- uint64_t to_shift = octets[i];
- address_ |= to_shift << (8 * i);
- }
- return true;
-}
-
-void BtAddress::ToVector(vector<uint8_t>& octets) const {
- for (size_t i = 0; i < kOctets; i++) {
- octets.push_back(address_ >> (8 * i));
- }
-}
-
-std::string BtAddress::ToString() const {
- std::stringstream ss;
-
- ss << std::hex << std::setfill('0') << std::setw(2);
- for (size_t i = 0; i < kOctets; i++) {
- uint64_t octet = (address_ >> (8 * ((kOctets - 1) - i))) & 0xff;
- ss << std::hex << std::setfill('0') << std::setw(2) << octet;
- if (i != kOctets - 1) ss << std::string(":");
- }
-
- return ss.str();
-}
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/classic.cc b/vendor_libs/test_vendor_lib/src/classic.cc
deleted file mode 100644
index b878b5f..0000000
--- a/vendor_libs/test_vendor_lib/src/classic.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2016 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 "classic"
-
-#include "classic.h"
-#include "osi/include/log.h"
-#include "stack/include/hcidefs.h"
-
-using std::vector;
-
-namespace test_vendor_lib {
-
-Classic::Classic() {
- advertising_interval_ms_ = std::chrono::milliseconds(0);
- device_class_ = 0x30201;
-
- extended_inquiry_data_ = {0x10, // Length
- BT_EIR_COMPLETE_LOCAL_NAME_TYPE,
- 'g',
- 'D',
- 'e',
- 'v',
- 'i',
- 'c',
- 'e',
- '-',
- 'c',
- 'l',
- 'a',
- 's',
- 's',
- 'i',
- 'c'};
- page_scan_repetition_mode_ = 0;
- page_scan_delay_ms_ = std::chrono::milliseconds(600);
-}
-
-void Classic::Initialize(const vector<std::string>& args) {
- if (args.size() < 2) return;
-
- BtAddress addr;
- if (addr.FromString(args[1])) SetBtAddress(addr);
-
- if (args.size() < 3) return;
-
- SetClockOffset(std::stoi(args[2]));
-}
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/command_packet.cc b/vendor_libs/test_vendor_lib/src/command_packet.cc
deleted file mode 100644
index 9b44c98..0000000
--- a/vendor_libs/test_vendor_lib/src/command_packet.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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 "command_packet.h"
-
-#include "hci/include/hci_hal.h"
-#include "osi/include/log.h"
-#include "stack/include/hcidefs.h"
-
-using std::vector;
-
-namespace test_vendor_lib {
-
-CommandPacket::CommandPacket(vector<uint8_t> header)
- : Packet(DATA_TYPE_COMMAND, std::move(header)) {}
-
-CommandPacket::CommandPacket(uint16_t opcode)
- : Packet(DATA_TYPE_COMMAND, {static_cast<uint8_t>(opcode),
- static_cast<uint8_t>(opcode >> 8)}) {}
-
-CommandPacket::CommandPacket(vector<uint8_t> header, vector<uint8_t> payload)
- : Packet(DATA_TYPE_COMMAND, std::move(header)) {
- AddPayloadOctets(payload.size(), std::move(payload));
-}
-
-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
diff --git a/vendor_libs/test_vendor_lib/src/connection.cc b/vendor_libs/test_vendor_lib/src/connection.cc
deleted file mode 100644
index 5bdc20f..0000000
--- a/vendor_libs/test_vendor_lib/src/connection.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2016 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 "connection"
-
-#include "connection.h"
-
-#include "base/logging.h"
-
-#include "osi/include/log.h"
-
-using std::vector;
-
-namespace test_vendor_lib {
-
-// Add an action from the controller.
-void Connection::AddAction(const TaskCallback& task) { actions_.push(task); }
-
-// Model the quality of the downstream connection
-void Connection::SendToDevice() {
- while (actions_.size() > 0) {
- // Execute the first action
- actions_.front()();
- actions_.pop();
- }
-}
-
-// Add a message from the device to the controller.
-void Connection::AddMessage(const vector<uint8_t>& data) {
- messages_.push(data);
-}
-
-// Model the quality of the upstream connection
-bool Connection::ReceiveFromDevice(vector<uint8_t>& data) {
- if (messages_.size() > 0) {
- data = messages_.front();
- messages_.pop();
-
- return true;
- }
- return false;
-}
-
-const std::string Connection::ToString() {
- return "connection " + std::to_string(handle_) + " to " + dev_->ToString();
-}
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/device.cc b/vendor_libs/test_vendor_lib/src/device.cc
deleted file mode 100644
index 86d18c0..0000000
--- a/vendor_libs/test_vendor_lib/src/device.cc
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2016 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 "device"
-
-#include <vector>
-
-#include "device.h"
-
-using std::vector;
-
-namespace test_vendor_lib {
-
-std::string Device::ToString() const {
- std::string dev = "(" + GetTypeString() + ")" + "@" + address_.ToString();
-
- return dev;
-}
-
-bool Device::IsAdvertisementAvailable(
- std::chrono::milliseconds scan_time) const {
- if (advertising_interval_ms_ == std::chrono::milliseconds(0)) return false;
-
- std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
-
- std::chrono::steady_clock::time_point last_interval =
- ((now - time_stamp_) / advertising_interval_ms_) *
- advertising_interval_ms_ +
- time_stamp_;
-
- std::chrono::steady_clock::time_point next_interval =
- last_interval + advertising_interval_ms_;
-
- return ((now + scan_time) >= next_interval);
-}
-
-bool Device::IsPageScanAvailable() const { return true; }
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/device_factory.cc b/vendor_libs/test_vendor_lib/src/device_factory.cc
deleted file mode 100644
index 3e23dee..0000000
--- a/vendor_libs/test_vendor_lib/src/device_factory.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2016 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 "device_factory"
-
-#include "device_factory.h"
-#include "beacon.h"
-#include "beacon_swarm.h"
-#include "broken_adv.h"
-#include "classic.h"
-#include "device.h"
-#include "keyboard.h"
-
-#include "base/logging.h"
-
-using std::vector;
-
-namespace test_vendor_lib {
-
-std::shared_ptr<Device> DeviceFactory::Create(const vector<std::string>& args) {
- CHECK(!args.empty());
-
- std::shared_ptr<Device> new_device = nullptr;
-
- if (args[0] == "beacon") new_device = std::make_shared<Beacon>();
- if (args[0] == "beacon_swarm") new_device = std::make_shared<BeaconSwarm>();
- if (args[0] == "broken_adv") new_device = std::make_shared<BrokenAdv>();
- if (args[0] == "classic") new_device = std::make_shared<Classic>();
- if (args[0] == "keyboard") new_device = std::make_shared<Keyboard>();
-
- if (new_device != nullptr) new_device->Initialize(args);
-
- return new_device;
-}
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/device_properties.cc b/vendor_libs/test_vendor_lib/src/device_properties.cc
deleted file mode 100644
index 672dd65..0000000
--- a/vendor_libs/test_vendor_lib/src/device_properties.cc
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * 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 "device_properties"
-
-#include "device_properties.h"
-
-#include <memory>
-
-#include <base/logging.h>
-#include "base/files/file_util.h"
-#include "base/json/json_reader.h"
-#include "base/values.h"
-
-#include "osi/include/log.h"
-#include "osi/include/osi.h"
-#include "stack/include/hcidefs.h"
-
-using std::vector;
-
-namespace {
-// Functions used by JSONValueConverter to read stringified JSON.
-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;
-}
-
-} // namespace
-
-namespace test_vendor_lib {
-
-DeviceProperties::DeviceProperties(const std::string& file_name)
- : acl_data_packet_size_(1024),
- sco_data_packet_size_(255),
- num_acl_data_packets_(10),
- num_sco_data_packets_(10),
- version_(HCI_PROTO_VERSION_4_1),
- revision_(0),
- lmp_pal_version_(7), /* 4.1 */
- manufacturer_name_(0),
- lmp_pal_subversion_(0),
- le_data_packet_length_(27),
- num_le_data_packets_(15),
- le_white_list_size_(15) {
- std::string properties_raw;
-
- local_extended_features_ = {0xffffffffffffffff, 0x7};
-
- CHECK(address_.FromString("01:02:03:04:05:06"));
- local_name_ = "DefaultName";
-
- supported_codecs_ = {1};
- vendor_specific_codecs_ = {};
-
- for (int i = 0; i < 64; i++) local_supported_commands_.push_back(0xff);
-
- le_supported_features_ = 0x1f;
- le_supported_states_ = 0x3ffffffffff;
- le_vendor_cap_ = {};
-
- LOG_INFO(LOG_TAG, "Reading controller properties from %s.",
- file_name.c_str());
- if (!base::ReadFileToString(base::FilePath(file_name), &properties_raw)) {
- LOG_ERROR(LOG_TAG, "Error reading controller properties from file.");
- return;
- }
-
- std::unique_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<DeviceProperties> converter;
-
- if (!converter.Convert(properties_dictionary, this))
- LOG_INFO(LOG_TAG,
- "Error converting JSON properties into Properties object.");
-}
-
-// static
-void DeviceProperties::RegisterJSONConverter(
- base::JSONValueConverter<DeviceProperties>* converter) {
-// TODO(dennischeng): Use RegisterIntField() here?
-#define REGISTER_UINT8_T(field_name, field) \
- converter->RegisterCustomField<uint8_t>( \
- field_name, &DeviceProperties::field, &ParseUint8t);
-#define REGISTER_UINT16_T(field_name, field) \
- converter->RegisterCustomField<uint16_t>( \
- field_name, &DeviceProperties::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_);
-#undef REGISTER_UINT8_T
-#undef REGISTER_UINT16_T
-}
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/dual_mode_controller.cc b/vendor_libs/test_vendor_lib/src/dual_mode_controller.cc
deleted file mode 100644
index bc80866..0000000
--- a/vendor_libs/test_vendor_lib/src/dual_mode_controller.cc
+++ /dev/null
@@ -1,921 +0,0 @@
-/*
- * 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 "dual_mode_controller.h"
-#include "device_factory.h"
-
-#include <memory>
-
-#include <base/logging.h>
-#include "base/files/file_util.h"
-#include "base/json/json_reader.h"
-#include "base/values.h"
-
-#include "osi/include/log.h"
-#include "osi/include/osi.h"
-#include "stack/include/hcidefs.h"
-
-using std::vector;
-
-namespace {
-
-// Included in certain events to indicate success (specific to the event
-// context).
-const uint8_t kSuccessStatus = 0;
-
-const uint8_t kUnknownHciCommand = 1;
-
-// The location of the config file loaded to populate controller attributes.
-const std::string kControllerPropertiesFile =
- "/etc/bluetooth/controller_properties.json";
-
-void LogCommand(const char* command) {
- LOG_INFO(LOG_TAG, "Controller performing command: %s", command);
-}
-
-} // namespace
-
-namespace test_vendor_lib {
-
-void DualModeController::AddControllerEvent(std::chrono::milliseconds delay,
- const TaskCallback& task) {
- controller_events_.push_back(schedule_task_(delay, task));
-}
-
-void DualModeController::AddConnectionAction(const TaskCallback& task,
- uint16_t handle) {
- for (size_t i = 0; i < connections_.size(); i++)
- if (*connections_[i] == handle) connections_[i]->AddAction(task);
-}
-
-void DualModeController::SendCommandCompleteSuccess(
- uint16_t command_opcode) const {
- send_event_(EventPacket::CreateCommandCompleteOnlyStatusEvent(
- command_opcode, kSuccessStatus));
-}
-
-void DualModeController::SendCommandCompleteOnlyStatus(uint16_t command_opcode,
- uint8_t status) const {
- send_event_(EventPacket::CreateCommandCompleteOnlyStatusEvent(command_opcode,
- status));
-}
-
-void DualModeController::SendCommandStatus(uint8_t status,
- uint16_t command_opcode) const {
- send_event_(EventPacket::CreateCommandStatusEvent(status, command_opcode));
-}
-
-void DualModeController::SendCommandStatusSuccess(
- uint16_t command_opcode) const {
- SendCommandStatus(kSuccessStatus, command_opcode);
-}
-
-DualModeController::DualModeController()
- : state_(kStandby), properties_(kControllerPropertiesFile) {
- devices_ = {};
-
- vector<std::string> beacon = {"beacon", "be:ac:10:00:00:01", "1000"};
- TestChannelAdd(beacon);
-
- vector<std::string> classic = {std::string("classic"),
- std::string("c1:a5:51:c0:00:01")};
- TestChannelAdd(classic);
-
- vector<std::string> keyboard = {std::string("keyboard"),
- std::string("cc:1c:eb:0a:12:d1"),
- std::string("500")};
- TestChannelAdd(keyboard);
-
- le_scan_enable_ = 0;
- le_connect_ = false;
-
- loopback_mode_ = 0;
-
-#define SET_HANDLER(opcode, method) \
- active_hci_commands_[opcode] = [this](const vector<uint8_t>& param) { \
- method(param); \
- };
- 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_SUPPORTED_CODECS, HciReadLocalSupportedCodecs);
- 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);
- SET_HANDLER(HCI_BLE_SET_EVENT_MASK, HciLeSetEventMask);
- SET_HANDLER(HCI_BLE_READ_BUFFER_SIZE, HciLeReadBufferSize);
- SET_HANDLER(HCI_BLE_READ_LOCAL_SPT_FEAT, HciLeReadLocalSupportedFeatures);
- SET_HANDLER(HCI_BLE_WRITE_RANDOM_ADDR, HciLeSetRandomAddress);
- SET_HANDLER(HCI_BLE_WRITE_ADV_DATA, HciLeSetAdvertisingData);
- SET_HANDLER(HCI_BLE_WRITE_ADV_PARAMS, HciLeSetAdvertisingParameters);
- SET_HANDLER(HCI_BLE_WRITE_SCAN_PARAMS, HciLeSetScanParameters);
- SET_HANDLER(HCI_BLE_WRITE_SCAN_ENABLE, HciLeSetScanEnable);
- SET_HANDLER(HCI_BLE_CREATE_LL_CONN, HciLeCreateConnection);
- SET_HANDLER(HCI_BLE_CREATE_CONN_CANCEL, HciLeConnectionCancel);
- SET_HANDLER(HCI_BLE_READ_WHITE_LIST_SIZE, HciLeReadWhiteListSize);
- SET_HANDLER(HCI_BLE_RAND, HciLeRand);
- SET_HANDLER(HCI_BLE_READ_SUPPORTED_STATES, HciLeReadSupportedStates);
- SET_HANDLER((HCI_GRP_VENDOR_SPECIFIC | 0x27), HciBleVendorSleepMode);
- SET_HANDLER(HCI_BLE_VENDOR_CAP_OCF, HciBleVendorCap);
- SET_HANDLER(HCI_BLE_MULTI_ADV_OCF, HciBleVendorMultiAdv);
- SET_HANDLER((HCI_GRP_VENDOR_SPECIFIC | 0x155), HciBleVendor155);
- SET_HANDLER(HCI_BLE_ADV_FILTER_OCF, HciBleAdvertisingFilter);
- SET_HANDLER(HCI_BLE_ENERGY_INFO_OCF, HciBleEnergyInfo);
- SET_HANDLER(HCI_BLE_EXTENDED_SCAN_PARAMS_OCF, HciBleExtendedScanParams);
- // Testing Commands
- SET_HANDLER(HCI_READ_LOOPBACK_MODE, HciReadLoopbackMode);
- SET_HANDLER(HCI_WRITE_LOOPBACK_MODE, HciWriteLoopbackMode);
-#undef SET_HANDLER
-
-#define SET_TEST_HANDLER(command_name, method) \
- active_test_channel_commands_[command_name] = \
- [this](const vector<std::string>& param) { method(param); };
- SET_TEST_HANDLER("add", TestChannelAdd);
- SET_TEST_HANDLER("del", TestChannelDel);
- SET_TEST_HANDLER("list", TestChannelList);
-#undef SET_TEST_HANDLER
-}
-
-void DualModeController::RegisterTaskScheduler(
- std::function<AsyncTaskId(std::chrono::milliseconds, const TaskCallback&)>
- oneshotScheduler) {
- schedule_task_ = oneshotScheduler;
-}
-
-void DualModeController::RegisterPeriodicTaskScheduler(
- std::function<AsyncTaskId(std::chrono::milliseconds,
- std::chrono::milliseconds, const TaskCallback&)>
- periodicScheduler) {
- schedule_periodic_task_ = periodicScheduler;
-}
-
-void DualModeController::RegisterTaskCancel(
- std::function<void(AsyncTaskId)> task_cancel) {
- cancel_task_ = task_cancel;
-}
-
-void DualModeController::HandleTestChannelCommand(
- const std::string& name, const vector<std::string>& args) {
- if (active_test_channel_commands_.count(name) == 0) return;
- active_test_channel_commands_[name](args);
-}
-
-void DualModeController::HandleAcl(std::unique_ptr<AclPacket> acl_packet) {
- if (loopback_mode_ == HCI_LOOPBACK_MODE_LOCAL) {
- uint16_t channel = acl_packet->GetChannel();
- send_acl_(std::move(acl_packet));
- send_event_(EventPacket::CreateNumberOfCompletedPacketsEvent(channel, 1));
- return;
- }
-}
-
-void DualModeController::HandleSco(std::unique_ptr<ScoPacket> sco_packet) {
- if (loopback_mode_ == HCI_LOOPBACK_MODE_LOCAL) {
- uint16_t channel = sco_packet->GetChannel();
- send_sco_(std::move(sco_packet));
- send_event_(EventPacket::CreateNumberOfCompletedPacketsEvent(channel, 1));
- return;
- }
-}
-
-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());
-
- if (loopback_mode_ == HCI_LOOPBACK_MODE_LOCAL &&
- // Loopback exceptions.
- opcode != HCI_RESET && opcode != HCI_SET_HC_TO_HOST_FLOW_CTRL &&
- opcode != HCI_HOST_BUFFER_SIZE && opcode != HCI_HOST_NUM_PACKETS_DONE &&
- opcode != HCI_READ_BUFFER_SIZE && opcode != HCI_READ_LOOPBACK_MODE &&
- opcode != HCI_WRITE_LOOPBACK_MODE) {
- send_event_(EventPacket::CreateLoopbackCommandEvent(
- opcode, command_packet->GetPayload()));
- } else if (active_hci_commands_.count(opcode) > 0) {
- active_hci_commands_[opcode](command_packet->GetPayload());
- } else {
- SendCommandCompleteOnlyStatus(opcode, kUnknownHciCommand);
- }
-}
-
-void DualModeController::RegisterEventChannel(
- const std::function<void(std::unique_ptr<EventPacket>)>& callback) {
- send_event_ = callback;
-}
-
-void DualModeController::RegisterAclChannel(
- const std::function<void(std::unique_ptr<AclPacket>)>& callback) {
- send_acl_ = callback;
-}
-
-void DualModeController::RegisterScoChannel(
- const std::function<void(std::unique_ptr<ScoPacket>)>& callback) {
- send_sco_ = callback;
-}
-
-void DualModeController::HandleTimerTick() {
- if (state_ == kInquiry) PageScan();
- if (le_scan_enable_ || le_connect_) LeScan();
- Connections();
- for (size_t dev = 0; dev < devices_.size(); dev++) devices_[dev]->TimerTick();
-}
-
-void DualModeController::SetTimerPeriod(std::chrono::milliseconds new_period) {
- timer_period_ = new_period;
-
- if (timer_tick_task_ == kInvalidTaskId) return;
-
- // Restart the timer with the new period
- StopTimer();
- StartTimer();
-}
-
-static uint8_t GetRssi(size_t dev) {
- // TODO: Model rssi somehow
- return -((dev * 16) % 127);
-}
-
-static uint8_t LeGetHandle() {
- static int handle = 0;
- return handle++;
-}
-
-static uint8_t LeGetConnInterval() { return 1; }
-
-static uint8_t LeGetConnLatency() { return 2; }
-
-static uint8_t LeGetSupervisionTimeout() { return 3; }
-
-void DualModeController::Connections() {
- for (size_t i = 0; i < connections_.size(); i++) {
- if (connections_[i]->Connected()) {
- connections_[i]->SendToDevice();
- vector<uint8_t> data;
- connections_[i]->ReceiveFromDevice(data);
- // HandleConnectionData(data);
- }
- }
-}
-
-void DualModeController::LeScan() {
- std::unique_ptr<EventPacket> le_adverts =
- EventPacket::CreateLeAdvertisingReportEvent();
- vector<uint8_t> ad;
- for (size_t dev = 0; dev < devices_.size(); dev++) {
- uint8_t adv_type;
- const BtAddress addr = devices_[dev]->GetBtAddress();
- uint8_t addr_type = devices_[dev]->GetAddressType();
- ad.clear();
-
- // Listen for Advertisements
- if (devices_[dev]->IsAdvertisementAvailable(
- std::chrono::milliseconds(le_scan_window_))) {
- ad = devices_[dev]->GetAdvertisement();
- adv_type = devices_[dev]->GetAdvertisementType();
- if (le_scan_enable_ && !le_adverts->AddLeAdvertisingReport(
- adv_type, addr_type, addr, ad, GetRssi(dev))) {
- send_event_(std::move(le_adverts));
- le_adverts = EventPacket::CreateLeAdvertisingReportEvent();
- CHECK(le_adverts->AddLeAdvertisingReport(adv_type, addr_type, addr, ad,
- GetRssi(dev)));
- }
-
- // Connect
- if (le_connect_ && (adv_type == BTM_BLE_CONNECT_EVT ||
- adv_type == BTM_BLE_CONNECT_DIR_EVT)) {
- LOG_INFO(LOG_TAG, "Connecting to device %d", static_cast<int>(dev));
- if (peer_address_ == addr && peer_address_type_ == addr_type &&
- devices_[dev]->LeConnect()) {
- uint16_t handle = LeGetHandle();
- std::unique_ptr<EventPacket> event =
- EventPacket::CreateLeConnectionCompleteEvent(
- kSuccessStatus, handle, HCI_ROLE_MASTER, addr_type, addr,
- LeGetConnInterval(), LeGetConnLatency(),
- LeGetSupervisionTimeout());
- send_event_(std::move(event));
- le_connect_ = false;
-
- connections_.push_back(
- std::make_shared<Connection>(devices_[dev], handle));
- }
-
- // TODO: Handle the white list (if (InWhiteList(dev)))
- }
-
- // Active scanning
- if (le_scan_enable_ && le_scan_type_ == 1) {
- ad.clear();
- if (devices_[dev]->HasScanResponse()) {
- ad = devices_[dev]->GetScanResponse();
- if (!le_adverts->AddLeAdvertisingReport(
- BTM_BLE_SCAN_RSP_EVT, addr_type, addr, ad, GetRssi(dev))) {
- send_event_(std::move(le_adverts));
- le_adverts = EventPacket::CreateLeAdvertisingReportEvent();
- CHECK(le_adverts->AddLeAdvertisingReport(
- BTM_BLE_SCAN_RSP_EVT, addr_type, addr, ad, GetRssi(dev)));
- }
- }
- }
- }
- }
-
- if (le_scan_enable_) send_event_(std::move(le_adverts));
-}
-
-void DualModeController::PageScan() {
- // Inquiry modes for specifiying inquiry result formats.
- static const uint8_t kStandardInquiry = 0x00;
- static const uint8_t kRssiInquiry = 0x01;
- static const uint8_t kExtendedOrRssiInquiry = 0x02;
-
- switch (inquiry_mode_) {
- case (kStandardInquiry): {
- std::unique_ptr<EventPacket> inquiry_result =
- EventPacket::CreateInquiryResultEvent();
- for (size_t dev = 0; dev < devices_.size(); dev++)
- // Scan for devices
- if (devices_[dev]->IsPageScanAvailable()) {
- bool result_added = inquiry_result->AddInquiryResult(
- devices_[dev]->GetBtAddress(),
- devices_[dev]->GetPageScanRepetitionMode(),
- devices_[dev]->GetDeviceClass(), devices_[dev]->GetClockOffset());
- if (!result_added) {
- send_event_(std::move(inquiry_result));
- inquiry_result = EventPacket::CreateInquiryResultEvent();
- result_added = inquiry_result->AddInquiryResult(
- devices_[dev]->GetBtAddress(),
- devices_[dev]->GetPageScanRepetitionMode(),
- devices_[dev]->GetDeviceClass(),
- devices_[dev]->GetClockOffset());
- CHECK(result_added);
- }
- }
- } break;
-
- case (kRssiInquiry):
- LOG_INFO(LOG_TAG, "RSSI Inquiry Mode currently not supported.");
- break;
-
- case (kExtendedOrRssiInquiry):
- for (size_t dev = 0; dev < devices_.size(); dev++)
- if (devices_[dev]->IsPageScanAvailable()) {
- send_event_(EventPacket::CreateExtendedInquiryResultEvent(
- devices_[dev]->GetBtAddress(),
- devices_[dev]->GetPageScanRepetitionMode(),
- devices_[dev]->GetDeviceClass(), devices_[dev]->GetClockOffset(),
- GetRssi(dev), devices_[dev]->GetExtendedInquiryData()));
- }
- break;
- }
-}
-
-void DualModeController::StartTimer() {
- LOG_ERROR(LOG_TAG, "StartTimer");
- timer_tick_task_ = schedule_periodic_task_(
- std::chrono::milliseconds(0), timer_period_,
- [this]() { DualModeController::HandleTimerTick(); });
-}
-
-void DualModeController::StopTimer() {
- LOG_ERROR(LOG_TAG, "StopTimer");
- cancel_task_(timer_tick_task_);
- timer_tick_task_ = kInvalidTaskId;
-}
-
-void DualModeController::SetEventDelay(int64_t delay) {
- if (delay < 0) delay = 0;
-}
-
-void DualModeController::TestChannelAdd(const vector<std::string>& args) {
- LogCommand("TestChannel 'add'");
-
- std::shared_ptr<Device> new_dev = DeviceFactory::Create(args);
-
- if (new_dev == NULL) {
- LOG_ERROR(LOG_TAG, "TestChannel 'add' failed!");
- return;
- }
-
- devices_.push_back(new_dev);
-}
-
-void DualModeController::TestChannelDel(const vector<std::string>& args) {
- LogCommand("TestChannel 'del'");
-
- size_t dev_index = std::stoi(args[0]);
-
- if (dev_index >= devices_.size()) {
- LOG_INFO(LOG_TAG, "TestChannel 'del': index %d out of range!",
- static_cast<int>(dev_index));
- } else {
- devices_.erase(devices_.begin() + dev_index);
- }
-}
-
-void DualModeController::TestChannelList(
- UNUSED_ATTR const vector<std::string>& args) const {
- LogCommand("TestChannel 'list'");
- LOG_INFO(LOG_TAG, "Devices:");
- for (size_t dev = 0; dev < devices_.size(); dev++) {
- LOG_INFO(LOG_TAG, "%d:", static_cast<int>(dev));
- devices_[dev]->ToString();
- }
-}
-
-void DualModeController::HciReset(const vector<uint8_t>& args) {
- LogCommand("Reset");
- CHECK(args[0] == 0); // No arguments
- state_ = kStandby;
- if (timer_tick_task_ != kInvalidTaskId) {
- LOG_INFO(LOG_TAG, "The timer was already running!");
- StopTimer();
- }
- LOG_INFO(LOG_TAG, "Starting timer.");
- StartTimer();
-
- SendCommandCompleteSuccess(HCI_RESET);
-}
-
-void DualModeController::HciReadBufferSize(const vector<uint8_t>& args) {
- LogCommand("Read Buffer Size");
- CHECK(args[0] == 0); // No arguments
- std::unique_ptr<EventPacket> command_complete =
- EventPacket::CreateCommandCompleteReadBufferSize(
- kSuccessStatus, properties_.GetAclDataPacketSize(),
- properties_.GetSynchronousDataPacketSize(),
- properties_.GetTotalNumAclDataPackets(),
- properties_.GetTotalNumSynchronousDataPackets());
-
- send_event_(std::move(command_complete));
-}
-
-void DualModeController::HciHostBufferSize(const vector<uint8_t>& args) {
- LogCommand("Host Buffer Size");
- CHECK(args[0] == 7); // No arguments
- SendCommandCompleteSuccess(HCI_HOST_BUFFER_SIZE);
-}
-
-void DualModeController::HciReadLocalVersionInformation(
- const vector<uint8_t>& args) {
- LogCommand("Read Local Version Information");
- CHECK(args[0] == 0); // No arguments
- std::unique_ptr<EventPacket> command_complete =
- EventPacket::CreateCommandCompleteReadLocalVersionInformation(
- kSuccessStatus, properties_.GetVersion(), properties_.GetRevision(),
- properties_.GetLmpPalVersion(), properties_.GetManufacturerName(),
- properties_.GetLmpPalSubversion());
- send_event_(std::move(command_complete));
-}
-
-void DualModeController::HciReadBdAddr(const vector<uint8_t>& args) {
- CHECK(args[0] == 0); // No arguments
- std::unique_ptr<EventPacket> command_complete =
- EventPacket::CreateCommandCompleteReadBdAddr(kSuccessStatus,
- properties_.GetAddress());
- send_event_(std::move(command_complete));
-}
-
-void DualModeController::HciReadLocalSupportedCommands(
- const vector<uint8_t>& args) {
- LogCommand("Read Local Supported Commands");
- CHECK(args[0] == 0); // No arguments
- std::unique_ptr<EventPacket> command_complete =
- EventPacket::CreateCommandCompleteReadLocalSupportedCommands(
- kSuccessStatus, properties_.GetLocalSupportedCommands());
- send_event_(std::move(command_complete));
-}
-
-void DualModeController::HciReadLocalSupportedCodecs(
- const vector<uint8_t>& args) {
- LogCommand("Read Local Supported Codecs");
- CHECK(args[0] == 0); // No arguments
- std::unique_ptr<EventPacket> command_complete =
- EventPacket::CreateCommandCompleteReadLocalSupportedCodecs(
- kSuccessStatus, properties_.GetSupportedCodecs(),
- properties_.GetVendorSpecificCodecs());
- send_event_(std::move(command_complete));
-}
-
-void DualModeController::HciReadLocalExtendedFeatures(
- const vector<uint8_t>& args) {
- LogCommand("Read Local Extended Features");
- CHECK(args.size() == 2);
- std::unique_ptr<EventPacket> command_complete =
- EventPacket::CreateCommandCompleteReadLocalExtendedFeatures(
- kSuccessStatus, args[1],
- properties_.GetLocalExtendedFeaturesMaximumPageNumber(),
- properties_.GetLocalExtendedFeatures(args[1]));
- send_event_(std::move(command_complete));
-}
-
-void DualModeController::HciWriteSimplePairingMode(
- UNUSED_ATTR const vector<uint8_t>& args) {
- LogCommand("Write Simple Pairing Mode");
- SendCommandCompleteSuccess(HCI_WRITE_SIMPLE_PAIRING_MODE);
-}
-
-void DualModeController::HciWriteLeHostSupport(
- UNUSED_ATTR const vector<uint8_t>& args) {
- LogCommand("Write Le Host Support");
- SendCommandCompleteSuccess(HCI_WRITE_LE_HOST_SUPPORT);
-}
-
-void DualModeController::HciSetEventMask(
- UNUSED_ATTR const vector<uint8_t>& args) {
- LogCommand("Set Event Mask");
- SendCommandCompleteSuccess(HCI_SET_EVENT_MASK);
-}
-
-void DualModeController::HciWriteInquiryMode(const vector<uint8_t>& args) {
- LogCommand("Write Inquiry Mode");
- CHECK(args.size() == 2);
- inquiry_mode_ = args[1];
- SendCommandCompleteSuccess(HCI_WRITE_INQUIRY_MODE);
-}
-
-void DualModeController::HciWritePageScanType(
- UNUSED_ATTR const vector<uint8_t>& args) {
- LogCommand("Write Page Scan Type");
- SendCommandCompleteSuccess(HCI_WRITE_PAGESCAN_TYPE);
-}
-
-void DualModeController::HciWriteInquiryScanType(
- UNUSED_ATTR const vector<uint8_t>& args) {
- LogCommand("Write Inquiry Scan Type");
- SendCommandCompleteSuccess(HCI_WRITE_INQSCAN_TYPE);
-}
-
-void DualModeController::HciWriteClassOfDevice(
- UNUSED_ATTR const vector<uint8_t>& args) {
- LogCommand("Write Class Of Device");
- SendCommandCompleteSuccess(HCI_WRITE_CLASS_OF_DEVICE);
-}
-
-void DualModeController::HciWritePageTimeout(
- UNUSED_ATTR const vector<uint8_t>& args) {
- LogCommand("Write Page Timeout");
- SendCommandCompleteSuccess(HCI_WRITE_PAGE_TOUT);
-}
-
-void DualModeController::HciWriteDefaultLinkPolicySettings(
- UNUSED_ATTR const vector<uint8_t>& args) {
- LogCommand("Write Default Link Policy Settings");
- SendCommandCompleteSuccess(HCI_WRITE_DEF_POLICY_SETTINGS);
-}
-
-void DualModeController::HciReadLocalName(
- UNUSED_ATTR const vector<uint8_t>& args) {
- LogCommand("Get Local Name");
- std::unique_ptr<EventPacket> command_complete =
- EventPacket::CreateCommandCompleteReadLocalName(
- kSuccessStatus, properties_.GetLocalName());
- send_event_(std::move(command_complete));
-}
-
-void DualModeController::HciWriteLocalName(
- UNUSED_ATTR const vector<uint8_t>& args) {
- LogCommand("Write Local Name");
- SendCommandCompleteSuccess(HCI_CHANGE_LOCAL_NAME);
-}
-
-void DualModeController::HciWriteExtendedInquiryResponse(
- UNUSED_ATTR const vector<uint8_t>& args) {
- LogCommand("Write Extended Inquiry Response");
- SendCommandCompleteSuccess(HCI_WRITE_EXT_INQ_RESPONSE);
-}
-
-void DualModeController::HciWriteVoiceSetting(
- UNUSED_ATTR const vector<uint8_t>& args) {
- LogCommand("Write Voice Setting");
- SendCommandCompleteSuccess(HCI_WRITE_VOICE_SETTINGS);
-}
-
-void DualModeController::HciWriteCurrentIacLap(
- UNUSED_ATTR const vector<uint8_t>& args) {
- LogCommand("Write Current IAC LAP");
- SendCommandCompleteSuccess(HCI_WRITE_CURRENT_IAC_LAP);
-}
-
-void DualModeController::HciWriteInquiryScanActivity(
- UNUSED_ATTR const vector<uint8_t>& args) {
- LogCommand("Write Inquiry Scan Activity");
- SendCommandCompleteSuccess(HCI_WRITE_INQUIRYSCAN_CFG);
-}
-
-void DualModeController::HciWriteScanEnable(
- UNUSED_ATTR const vector<uint8_t>& args) {
- LogCommand("Write Scan Enable");
- SendCommandCompleteSuccess(HCI_WRITE_SCAN_ENABLE);
-}
-
-void DualModeController::HciSetEventFilter(
- UNUSED_ATTR const vector<uint8_t>& args) {
- LogCommand("Set Event Filter");
- SendCommandCompleteSuccess(HCI_SET_EVENT_FILTER);
-}
-
-void DualModeController::HciInquiry(const vector<uint8_t>& args) {
- LogCommand("Inquiry");
- CHECK(args.size() == 6);
- state_ = kInquiry;
- SendCommandStatusSuccess(HCI_INQUIRY);
- inquiry_lap_[0] = args[1];
- inquiry_lap_[1] = args[2];
- inquiry_lap_[2] = args[3];
-
- AddControllerEvent(std::chrono::milliseconds(args[4] * 1280),
- [this]() { DualModeController::InquiryTimeout(); });
-
- if (args[5] > 0) {
- inquiry_responses_limited_ = true;
- inquiry_num_responses_ = args[5];
- }
-}
-
-void DualModeController::HciInquiryCancel(
- UNUSED_ATTR const vector<uint8_t>& args) {
- LogCommand("Inquiry Cancel");
- CHECK(state_ == kInquiry);
- state_ = kStandby;
- SendCommandCompleteSuccess(HCI_INQUIRY_CANCEL);
-}
-
-void DualModeController::InquiryTimeout() {
- LOG_INFO(LOG_TAG, "InquiryTimer fired");
- if (state_ == kInquiry) {
- state_ = kStandby;
- inquiry_responses_limited_ = false;
- send_event_(EventPacket::CreateInquiryCompleteEvent(kSuccessStatus));
- }
-}
-
-void DualModeController::HciDeleteStoredLinkKey(
- UNUSED_ATTR const 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. */
- uint16_t deleted_keys = 1;
-
- send_event_(EventPacket::CreateCommandCompleteDeleteStoredLinkKey(
- kSuccessStatus, deleted_keys));
-}
-
-void DualModeController::HciRemoteNameRequest(
- UNUSED_ATTR const vector<uint8_t>& args) {
- LogCommand("Remote Name Request");
- SendCommandStatusSuccess(HCI_RMT_NAME_REQUEST);
-}
-
-void DualModeController::HciLeSetEventMask(const vector<uint8_t>& args) {
- LogCommand("LE SetEventMask");
- le_event_mask_ = args;
- SendCommandCompleteSuccess(HCI_BLE_SET_EVENT_MASK);
-}
-
-void DualModeController::HciLeReadBufferSize(
- UNUSED_ATTR const vector<uint8_t>& args) {
- std::unique_ptr<EventPacket> command_complete =
- EventPacket::CreateCommandCompleteLeReadBufferSize(
- kSuccessStatus, properties_.GetLeDataPacketLength(),
- properties_.GetTotalNumLeDataPackets());
- send_event_(std::move(command_complete));
-}
-
-void DualModeController::HciLeReadLocalSupportedFeatures(
- UNUSED_ATTR const vector<uint8_t>& args) {
- std::unique_ptr<EventPacket> command_complete =
- EventPacket::CreateCommandCompleteLeReadLocalSupportedFeatures(
- kSuccessStatus, properties_.GetLeLocalSupportedFeatures());
- send_event_(std::move(command_complete));
-}
-
-void DualModeController::HciLeSetRandomAddress(const vector<uint8_t>& args) {
- LogCommand("LE SetRandomAddress");
- CHECK(args.size() == 7);
- vector<uint8_t> new_addr = {args[1], args[2], args[3],
- args[4], args[5], args[6]};
- CHECK(le_random_address_.FromVector(new_addr));
- SendCommandCompleteSuccess(HCI_BLE_WRITE_RANDOM_ADDR);
-}
-
-void DualModeController::HciLeSetAdvertisingParameters(
- UNUSED_ATTR const vector<uint8_t>& args) {
- LogCommand("LE SetAdvertisingParameters");
- SendCommandCompleteSuccess(HCI_BLE_WRITE_ADV_PARAMS);
-}
-
-void DualModeController::HciLeSetAdvertisingData(
- UNUSED_ATTR const vector<uint8_t>& args) {
- LogCommand("LE SetAdvertisingData");
- SendCommandCompleteSuccess(HCI_BLE_WRITE_ADV_DATA);
-}
-
-void DualModeController::HciLeSetScanParameters(const vector<uint8_t>& args) {
- LogCommand("LE SetScanParameters");
- CHECK(args.size() == 8);
- le_scan_type_ = args[1];
- le_scan_interval_ = args[2] | (args[3] << 8);
- le_scan_window_ = args[4] | (args[5] << 8);
- own_address_type_ = args[6];
- scanning_filter_policy_ = args[7];
- SendCommandCompleteSuccess(HCI_BLE_WRITE_SCAN_PARAMS);
-}
-
-void DualModeController::HciLeSetScanEnable(const vector<uint8_t>& args) {
- LogCommand("LE SetScanEnable");
- CHECK(args.size() == 3);
- le_scan_enable_ = args[1];
- filter_duplicates_ = args[2];
- SendCommandCompleteSuccess(HCI_BLE_WRITE_SCAN_ENABLE);
-}
-
-void DualModeController::HciLeCreateConnection(const vector<uint8_t>& args) {
- LogCommand("LE CreateConnection");
- le_connect_ = true;
- le_scan_interval_ = args[1] | (args[2] << 8);
- le_scan_window_ = args[3] | (args[4] << 8);
- initiator_filter_policy_ = args[5];
-
- if (initiator_filter_policy_ == 0) { // White list not used
- peer_address_type_ = args[6];
- vector<uint8_t> peer_addr = {args[7], args[8], args[9],
- args[10], args[11], args[12]};
- peer_address_.FromVector(peer_addr);
- }
-
- SendCommandStatusSuccess(HCI_BLE_CREATE_LL_CONN);
-}
-
-void DualModeController::HciLeConnectionCancel(const vector<uint8_t>& args) {
- LogCommand("LE ConnectionCancel");
- CHECK(args[0] == 0); // No arguments
- le_connect_ = false;
- SendCommandStatusSuccess(HCI_BLE_CREATE_CONN_CANCEL);
-}
-
-void DualModeController::HciLeReadWhiteListSize(const vector<uint8_t>& args) {
- LogCommand("LE ReadWhiteListSize");
- CHECK(args[0] == 0); // No arguments
- std::unique_ptr<EventPacket> command_complete =
- EventPacket::CreateCommandCompleteLeReadWhiteListSize(
- kSuccessStatus, properties_.GetLeWhiteListSize());
- send_event_(std::move(command_complete));
-}
-
-void DualModeController::HciLeReadRemoteUsedFeaturesB(uint16_t handle) {
- uint64_t features;
- LogCommand("LE ReadRemoteUsedFeatures Bottom half");
-
- for (size_t i = 0; i < connections_.size(); i++)
- if (*connections_[i] == handle)
- // TODO:
- // features = connections_[i]->GetDevice()->GetUsedFeatures();
- features = 0xffffffffffffffff;
-
- std::unique_ptr<EventPacket> event =
- EventPacket::CreateLeRemoteUsedFeaturesEvent(kSuccessStatus, handle,
- features);
- send_event_(std::move(event));
-}
-
-void DualModeController::HciLeReadRemoteUsedFeatures(
- const vector<uint8_t>& args) {
- LogCommand("LE ReadRemoteUsedFeatures");
- CHECK(args.size() == 3);
-
- uint16_t handle = args[1] | (args[2] << 8);
-
- AddConnectionAction(
- [this, handle]() {
- DualModeController::HciLeReadRemoteUsedFeaturesB(handle);
- },
- handle);
-
- SendCommandStatusSuccess(HCI_BLE_READ_REMOTE_FEAT);
-}
-
-void DualModeController::HciLeRand(UNUSED_ATTR const vector<uint8_t>& args) {
- uint64_t random_val = rand();
- std::unique_ptr<EventPacket> command_complete =
- EventPacket::CreateCommandCompleteLeRand(kSuccessStatus, random_val);
- send_event_(std::move(command_complete));
-}
-
-void DualModeController::HciLeReadSupportedStates(
- UNUSED_ATTR const vector<uint8_t>& args) {
- std::unique_ptr<EventPacket> command_complete =
- EventPacket::CreateCommandCompleteLeReadSupportedStates(
- kSuccessStatus, properties_.GetLeSupportedStates());
- send_event_(std::move(command_complete));
-}
-
-void DualModeController::HciBleVendorSleepMode(
- UNUSED_ATTR const vector<uint8_t>& args) {
- SendCommandCompleteOnlyStatus(HCI_GRP_VENDOR_SPECIFIC | 0x27,
- kUnknownHciCommand);
-}
-
-void DualModeController::HciBleVendorCap(
- UNUSED_ATTR const vector<uint8_t>& args) {
- vector<uint8_t> caps = properties_.GetLeVendorCap();
- if (caps.size() == 0) {
- SendCommandCompleteOnlyStatus(HCI_BLE_VENDOR_CAP_OCF, kUnknownHciCommand);
- return;
- }
-
- std::unique_ptr<EventPacket> command_complete =
- EventPacket::CreateCommandCompleteLeVendorCap(
- kSuccessStatus, properties_.GetLeVendorCap());
- send_event_(std::move(command_complete));
-}
-
-void DualModeController::HciBleVendorMultiAdv(
- UNUSED_ATTR const vector<uint8_t>& args) {
- SendCommandCompleteOnlyStatus(HCI_BLE_MULTI_ADV_OCF, kUnknownHciCommand);
-}
-
-void DualModeController::HciBleVendor155(
- UNUSED_ATTR const vector<uint8_t>& args) {
- SendCommandCompleteOnlyStatus(HCI_GRP_VENDOR_SPECIFIC | 0x155,
- kUnknownHciCommand);
-}
-
-void DualModeController::HciBleAdvertisingFilter(
- UNUSED_ATTR const vector<uint8_t>& args) {
- SendCommandCompleteOnlyStatus(HCI_BLE_ADV_FILTER_OCF, kUnknownHciCommand);
-}
-
-void DualModeController::HciBleEnergyInfo(
- UNUSED_ATTR const vector<uint8_t>& args) {
- SendCommandCompleteOnlyStatus(HCI_BLE_ENERGY_INFO_OCF, kUnknownHciCommand);
-}
-
-void DualModeController::HciBleExtendedScanParams(
- UNUSED_ATTR const vector<uint8_t>& args) {
- SendCommandCompleteOnlyStatus(HCI_BLE_EXTENDED_SCAN_PARAMS_OCF,
- kUnknownHciCommand);
-}
-
-void DualModeController::HciReadLoopbackMode(const vector<uint8_t>& args) {
- CHECK(args[0] == 0); // No arguments
- std::unique_ptr<EventPacket> command_complete =
- EventPacket::CreateCommandCompleteReadLoopbackMode(kSuccessStatus,
- loopback_mode_);
- send_event_(std::move(command_complete));
-}
-
-void DualModeController::HciWriteLoopbackMode(const vector<uint8_t>& args) {
- CHECK(args[0] == 1);
- loopback_mode_ = args[1];
- // ACL channel
- uint16_t acl_handle = 0x123;
- send_event_(EventPacket::CreateConnectionCompleteEvent(
- kSuccessStatus, acl_handle, properties_.GetAddress(), HCI_LINK_TYPE_ACL,
- false));
- // SCO channel
- uint16_t sco_handle = 0x345;
- send_event_(EventPacket::CreateConnectionCompleteEvent(
- kSuccessStatus, sco_handle, properties_.GetAddress(), HCI_LINK_TYPE_SCO,
- false));
- SendCommandCompleteSuccess(HCI_WRITE_LOOPBACK_MODE);
-}
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/event_packet.cc b/vendor_libs/test_vendor_lib/src/event_packet.cc
deleted file mode 100644
index 482b47f..0000000
--- a/vendor_libs/test_vendor_lib/src/event_packet.cc
+++ /dev/null
@@ -1,461 +0,0 @@
-/*
- * 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"
-
-#include "event_packet.h"
-
-#include "osi/include/log.h"
-#include "stack/include/hcidefs.h"
-
-using std::vector;
-
-namespace test_vendor_lib {
-
-EventPacket::EventPacket(uint8_t event_code)
- : Packet(DATA_TYPE_EVENT, {event_code}) {}
-
-uint8_t EventPacket::GetEventCode() const { return GetHeader()[0]; }
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.1
-std::unique_ptr<EventPacket> EventPacket::CreateInquiryCompleteEvent(
- uint8_t status) {
- std::unique_ptr<EventPacket> evt_ptr =
- std::unique_ptr<EventPacket>(new EventPacket(HCI_INQUIRY_COMP_EVT));
- CHECK(evt_ptr->AddPayloadOctets1(status));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.14
-std::unique_ptr<EventPacket> EventPacket::CreateCommandCompleteEvent(
- uint16_t command_opcode, const vector<uint8_t>& event_return_parameters) {
- std::unique_ptr<EventPacket> evt_ptr =
- std::unique_ptr<EventPacket>(new EventPacket(HCI_COMMAND_COMPLETE_EVT));
-
- CHECK(evt_ptr->AddPayloadOctets1(1)); // num_hci_command_packets
- CHECK(evt_ptr->AddPayloadOctets2(command_opcode));
- CHECK(evt_ptr->AddPayloadOctets(event_return_parameters.size(),
- event_return_parameters));
-
- return evt_ptr;
-}
-
-std::unique_ptr<EventPacket> EventPacket::CreateCommandCompleteOnlyStatusEvent(
- uint16_t command_opcode, uint8_t status) {
- std::unique_ptr<EventPacket> evt_ptr =
- std::unique_ptr<EventPacket>(new EventPacket(HCI_COMMAND_COMPLETE_EVT));
-
- CHECK(evt_ptr->AddPayloadOctets1(1)); // num_hci_command_packets
- CHECK(evt_ptr->AddPayloadOctets2(command_opcode));
- CHECK(evt_ptr->AddPayloadOctets1(status));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.15
-std::unique_ptr<EventPacket> EventPacket::CreateCommandStatusEvent(
- uint8_t status, uint16_t command_opcode) {
- std::unique_ptr<EventPacket> evt_ptr =
- std::unique_ptr<EventPacket>(new EventPacket(HCI_COMMAND_STATUS_EVT));
-
- CHECK(evt_ptr->AddPayloadOctets1(status));
- CHECK(evt_ptr->AddPayloadOctets1(1)); // num_hci_command_packets
- CHECK(evt_ptr->AddPayloadOctets2(command_opcode));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.19
-std::unique_ptr<EventPacket> EventPacket::CreateNumberOfCompletedPacketsEvent(
- uint16_t handle, uint16_t num_completed_packets) {
- std::unique_ptr<EventPacket> evt_ptr = std::unique_ptr<EventPacket>(
- new EventPacket(HCI_NUM_COMPL_DATA_PKTS_EVT));
-
- CHECK(evt_ptr->AddPayloadOctets1(0)); // Number of handles.
- evt_ptr->AddCompletedPackets(handle, num_completed_packets);
-
- return evt_ptr;
-}
-
-void EventPacket::AddCompletedPackets(uint16_t handle,
- uint16_t num_completed_packets) {
- CHECK(AddPayloadOctets2(handle));
- CHECK(AddPayloadOctets2(num_completed_packets));
- CHECK(IncrementPayloadCounter(1)); // Increment the number of handles.
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.10
-std::unique_ptr<EventPacket>
-EventPacket::CreateCommandCompleteDeleteStoredLinkKey(
- uint8_t status, uint16_t num_keys_deleted) {
- std::unique_ptr<EventPacket> evt_ptr =
- EventPacket::CreateCommandCompleteOnlyStatusEvent(
- HCI_DELETE_STORED_LINK_KEY, status);
-
- CHECK(evt_ptr->AddPayloadOctets2(num_keys_deleted));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.12
-std::unique_ptr<EventPacket> EventPacket::CreateCommandCompleteReadLocalName(
- uint8_t status, const std::string& local_name) {
- std::unique_ptr<EventPacket> evt_ptr =
- EventPacket::CreateCommandCompleteOnlyStatusEvent(HCI_READ_LOCAL_NAME,
- status);
-
- for (size_t i = 0; i < local_name.length(); i++)
- CHECK(evt_ptr->AddPayloadOctets1(local_name[i]));
- CHECK(evt_ptr->AddPayloadOctets1(0)); // Null terminated
- for (size_t i = 0; i < 248 - local_name.length() - 1; i++)
- CHECK(evt_ptr->AddPayloadOctets1(0xFF));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.1
-std::unique_ptr<EventPacket>
-EventPacket::CreateCommandCompleteReadLocalVersionInformation(
- uint8_t status, uint8_t hci_version, uint16_t hci_revision,
- uint8_t lmp_pal_version, uint16_t manufacturer_name,
- uint16_t lmp_pal_subversion) {
- std::unique_ptr<EventPacket> evt_ptr =
- EventPacket::CreateCommandCompleteOnlyStatusEvent(
- HCI_READ_LOCAL_VERSION_INFO, status);
-
- CHECK(evt_ptr->AddPayloadOctets1(hci_version));
- CHECK(evt_ptr->AddPayloadOctets2(hci_revision));
- CHECK(evt_ptr->AddPayloadOctets1(lmp_pal_version));
- CHECK(evt_ptr->AddPayloadOctets2(manufacturer_name));
- CHECK(evt_ptr->AddPayloadOctets2(lmp_pal_subversion));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.2
-std::unique_ptr<EventPacket>
-EventPacket::CreateCommandCompleteReadLocalSupportedCommands(
- uint8_t status, const vector<uint8_t>& supported_commands) {
- std::unique_ptr<EventPacket> evt_ptr =
- EventPacket::CreateCommandCompleteOnlyStatusEvent(
- HCI_READ_LOCAL_SUPPORTED_CMDS, status);
-
- CHECK(evt_ptr->AddPayloadOctets(64, supported_commands));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.4
-std::unique_ptr<EventPacket>
-EventPacket::CreateCommandCompleteReadLocalExtendedFeatures(
- uint8_t status, uint8_t page_number, uint8_t maximum_page_number,
- uint64_t extended_lmp_features) {
- std::unique_ptr<EventPacket> evt_ptr =
- EventPacket::CreateCommandCompleteOnlyStatusEvent(
- HCI_READ_LOCAL_EXT_FEATURES, status);
-
- CHECK(evt_ptr->AddPayloadOctets1(page_number));
- CHECK(evt_ptr->AddPayloadOctets1(maximum_page_number));
- CHECK(evt_ptr->AddPayloadOctets8(extended_lmp_features));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.5
-std::unique_ptr<EventPacket> EventPacket::CreateCommandCompleteReadBufferSize(
- uint8_t status, uint16_t hc_acl_data_packet_length,
- uint8_t hc_synchronous_data_packet_length,
- uint16_t hc_total_num_acl_data_packets,
- uint16_t hc_total_synchronous_data_packets) {
- std::unique_ptr<EventPacket> evt_ptr =
- EventPacket::CreateCommandCompleteOnlyStatusEvent(HCI_READ_BUFFER_SIZE,
- status);
-
- CHECK(evt_ptr->AddPayloadOctets2(hc_acl_data_packet_length));
- CHECK(evt_ptr->AddPayloadOctets1(hc_synchronous_data_packet_length));
- CHECK(evt_ptr->AddPayloadOctets2(hc_total_num_acl_data_packets));
- CHECK(evt_ptr->AddPayloadOctets2(hc_total_synchronous_data_packets));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.6
-std::unique_ptr<EventPacket> EventPacket::CreateCommandCompleteReadBdAddr(
- uint8_t status, const BtAddress& address) {
- std::unique_ptr<EventPacket> evt_ptr =
- EventPacket::CreateCommandCompleteOnlyStatusEvent(HCI_READ_BD_ADDR,
- status);
-
- CHECK(evt_ptr->AddPayloadBtAddress(address));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.8
-std::unique_ptr<EventPacket>
-EventPacket::CreateCommandCompleteReadLocalSupportedCodecs(
- uint8_t status, const vector<uint8_t>& supported_codecs,
- const vector<uint32_t>& vendor_specific_codecs) {
- std::unique_ptr<EventPacket> evt_ptr =
- EventPacket::CreateCommandCompleteOnlyStatusEvent(
- HCI_READ_LOCAL_SUPPORTED_CODECS, status);
-
- CHECK(evt_ptr->AddPayloadOctets(supported_codecs.size(), supported_codecs));
- for (size_t i = 0; i < vendor_specific_codecs.size(); i++)
- CHECK(evt_ptr->AddPayloadOctets4(vendor_specific_codecs[i]));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.6.1
-std::unique_ptr<EventPacket> EventPacket::CreateCommandCompleteReadLoopbackMode(
- uint8_t status, uint8_t mode) {
- std::unique_ptr<EventPacket> evt_ptr =
- EventPacket::CreateCommandCompleteOnlyStatusEvent(HCI_READ_LOOPBACK_MODE,
- status);
- CHECK(evt_ptr->AddPayloadOctets1(mode));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.2
-std::unique_ptr<EventPacket> EventPacket::CreateInquiryResultEvent() {
- std::unique_ptr<EventPacket> evt_ptr =
- std::unique_ptr<EventPacket>(new EventPacket(HCI_INQUIRY_RESULT_EVT));
-
- CHECK(evt_ptr->AddPayloadOctets1(0)); // Start with no responses
- return evt_ptr;
-}
-
-bool EventPacket::AddInquiryResult(const BtAddress& address,
- uint8_t page_scan_repetition_mode,
- uint32_t class_of_device,
- uint16_t clock_offset) {
- CHECK(GetEventCode() == HCI_INQUIRY_RESULT_EVT);
-
- if (!CanAddPayloadOctets(14)) return false;
-
- CHECK(IncrementPayloadCounter(1)); // Increment the number of responses
-
- CHECK(AddPayloadBtAddress(address));
- CHECK(AddPayloadOctets1(page_scan_repetition_mode));
- CHECK(AddPayloadOctets2(kReservedZero));
- CHECK(AddPayloadOctets3(class_of_device));
- CHECK(!(clock_offset & 0x8000));
- CHECK(AddPayloadOctets2(clock_offset));
- return true;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.3
-std::unique_ptr<EventPacket> EventPacket::CreateConnectionCompleteEvent(
- uint8_t status, uint16_t handle, const BtAddress& address,
- uint8_t link_type, bool encryption_enabled) {
- std::unique_ptr<EventPacket> evt_ptr =
- std::unique_ptr<EventPacket>(new EventPacket(HCI_CONNECTION_COMP_EVT));
-
- CHECK(evt_ptr->AddPayloadOctets1(status));
- CHECK((handle & 0xf000) == 0); // Handles are 12-bit values.
- CHECK(evt_ptr->AddPayloadOctets2(handle));
- CHECK(evt_ptr->AddPayloadBtAddress(address));
- CHECK(evt_ptr->AddPayloadOctets1(link_type));
- CHECK(evt_ptr->AddPayloadOctets1(encryption_enabled ? 1 : 0));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.25
-std::unique_ptr<EventPacket> EventPacket::CreateLoopbackCommandEvent(
- uint16_t opcode, const vector<uint8_t>& payload) {
- std::unique_ptr<EventPacket> evt_ptr =
- std::unique_ptr<EventPacket>(new EventPacket(HCI_LOOPBACK_COMMAND_EVT));
- CHECK(evt_ptr->AddPayloadOctets2(opcode));
- for (const auto& payload_byte : payload) // Fill the packet.
- evt_ptr->AddPayloadOctets1(payload_byte);
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.38
-std::unique_ptr<EventPacket> EventPacket::CreateExtendedInquiryResultEvent(
- const BtAddress& address, uint8_t page_scan_repetition_mode,
- uint32_t class_of_device, uint16_t clock_offset, uint8_t rssi,
- const vector<uint8_t>& extended_inquiry_response) {
- std::unique_ptr<EventPacket> evt_ptr = std::unique_ptr<EventPacket>(
- new EventPacket(HCI_EXTENDED_INQUIRY_RESULT_EVT));
-
- CHECK(evt_ptr->AddPayloadOctets1(1)); // Always contains a single response
-
- CHECK(evt_ptr->AddPayloadBtAddress(address));
- CHECK(evt_ptr->AddPayloadOctets1(page_scan_repetition_mode));
- CHECK(evt_ptr->AddPayloadOctets1(kReservedZero));
- CHECK(evt_ptr->AddPayloadOctets3(class_of_device));
- CHECK(!(clock_offset & 0x8000));
- CHECK(evt_ptr->AddPayloadOctets2(clock_offset));
- CHECK(evt_ptr->AddPayloadOctets1(rssi));
- CHECK(evt_ptr->AddPayloadOctets(extended_inquiry_response.size(),
- extended_inquiry_response));
- while (evt_ptr->AddPayloadOctets1(0xff))
- ; // Fill packet
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.65.1
-std::unique_ptr<EventPacket> EventPacket::CreateLeConnectionCompleteEvent(
- uint8_t status, uint16_t handle, uint8_t role, uint8_t peer_address_type,
- const BtAddress& peer, uint16_t interval, uint16_t latency,
- uint16_t supervision_timeout) {
- std::unique_ptr<EventPacket> evt_ptr =
- std::unique_ptr<EventPacket>(new EventPacket(HCI_BLE_EVENT));
-
- CHECK(evt_ptr->AddPayloadOctets1(HCI_BLE_CONN_COMPLETE_EVT));
- CHECK(evt_ptr->AddPayloadOctets1(status));
- CHECK(evt_ptr->AddPayloadOctets2(handle));
- CHECK(evt_ptr->AddPayloadOctets1(role));
- CHECK(evt_ptr->AddPayloadOctets1(peer_address_type));
- CHECK(evt_ptr->AddPayloadBtAddress(peer));
- CHECK(evt_ptr->AddPayloadOctets2(interval));
- CHECK(evt_ptr->AddPayloadOctets2(latency));
- CHECK(evt_ptr->AddPayloadOctets2(supervision_timeout));
- CHECK(evt_ptr->AddPayloadOctets1(
- 0x00)); // Master Clock Accuracy (unused for master)
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.65.2
-std::unique_ptr<EventPacket> EventPacket::CreateLeAdvertisingReportEvent() {
- std::unique_ptr<EventPacket> evt_ptr =
- std::unique_ptr<EventPacket>(new EventPacket(HCI_BLE_EVENT));
-
- CHECK(evt_ptr->AddPayloadOctets1(HCI_BLE_ADV_PKT_RPT_EVT));
-
- CHECK(evt_ptr->AddPayloadOctets1(0)); // Start with an empty report
-
- return evt_ptr;
-}
-
-bool EventPacket::AddLeAdvertisingReport(uint8_t event_type, uint8_t addr_type,
- const BtAddress& addr,
- const vector<uint8_t>& data,
- uint8_t rssi) {
- if (!CanAddPayloadOctets(10 + data.size())) return false;
-
- CHECK(GetEventCode() == HCI_BLE_EVENT);
-
- CHECK(IncrementPayloadCounter(2)); // Increment the number of responses
-
- CHECK(AddPayloadOctets1(event_type));
- CHECK(AddPayloadOctets1(addr_type));
- CHECK(AddPayloadBtAddress(addr));
- CHECK(AddPayloadOctets1(data.size()));
- CHECK(AddPayloadOctets(data.size(), data));
- CHECK(AddPayloadOctets1(rssi));
- return true;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.65.4
-std::unique_ptr<EventPacket> EventPacket::CreateLeRemoteUsedFeaturesEvent(
- uint8_t status, uint16_t handle, uint64_t features) {
- std::unique_ptr<EventPacket> evt_ptr =
- std::unique_ptr<EventPacket>(new EventPacket(HCI_BLE_EVENT));
-
- CHECK(evt_ptr->AddPayloadOctets1(HCI_BLE_READ_REMOTE_FEAT_CMPL_EVT));
-
- CHECK(evt_ptr->AddPayloadOctets1(status));
- CHECK(evt_ptr->AddPayloadOctets2(handle));
- CHECK(evt_ptr->AddPayloadOctets8(features));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.2
-std::unique_ptr<EventPacket> EventPacket::CreateCommandCompleteLeReadBufferSize(
- uint8_t status, uint16_t hc_le_data_packet_length,
- uint8_t hc_total_num_le_data_packets) {
- std::unique_ptr<EventPacket> evt_ptr =
- EventPacket::CreateCommandCompleteOnlyStatusEvent(
- HCI_BLE_READ_BUFFER_SIZE, status);
-
- CHECK(evt_ptr->AddPayloadOctets2(hc_le_data_packet_length));
- CHECK(evt_ptr->AddPayloadOctets1(hc_total_num_le_data_packets));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.3
-std::unique_ptr<EventPacket>
-EventPacket::CreateCommandCompleteLeReadLocalSupportedFeatures(
- uint8_t status, uint64_t le_features) {
- std::unique_ptr<EventPacket> evt_ptr =
- EventPacket::CreateCommandCompleteOnlyStatusEvent(
- HCI_BLE_READ_LOCAL_SPT_FEAT, status);
-
- CHECK(evt_ptr->AddPayloadOctets8(le_features));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.14
-std::unique_ptr<EventPacket>
-EventPacket::CreateCommandCompleteLeReadWhiteListSize(uint8_t status,
- uint8_t white_list_size) {
- std::unique_ptr<EventPacket> evt_ptr =
- EventPacket::CreateCommandCompleteOnlyStatusEvent(
- HCI_BLE_READ_WHITE_LIST_SIZE, status);
-
- CHECK(evt_ptr->AddPayloadOctets8(white_list_size));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.23
-std::unique_ptr<EventPacket> EventPacket::CreateCommandCompleteLeRand(
- uint8_t status, uint64_t random_val) {
- std::unique_ptr<EventPacket> evt_ptr =
- EventPacket::CreateCommandCompleteOnlyStatusEvent(HCI_BLE_RAND, status);
-
- CHECK(evt_ptr->AddPayloadOctets8(random_val));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.27
-std::unique_ptr<EventPacket>
-EventPacket::CreateCommandCompleteLeReadSupportedStates(uint8_t status,
- uint64_t le_states) {
- std::unique_ptr<EventPacket> evt_ptr =
- EventPacket::CreateCommandCompleteOnlyStatusEvent(
- HCI_BLE_READ_SUPPORTED_STATES, status);
-
- CHECK(evt_ptr->AddPayloadOctets8(le_states));
-
- return evt_ptr;
-}
-
-// Vendor-specific commands (see hcidefs.h)
-
-std::unique_ptr<EventPacket> EventPacket::CreateCommandCompleteLeVendorCap(
- uint8_t status, const vector<uint8_t>& vendor_cap) {
- std::unique_ptr<EventPacket> evt_ptr =
- EventPacket::CreateCommandCompleteOnlyStatusEvent(HCI_BLE_VENDOR_CAP_OCF,
- status);
-
- CHECK(evt_ptr->AddPayloadOctets(vendor_cap.size(), vendor_cap));
-
- return evt_ptr;
-}
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/hci_packet.cc b/vendor_libs/test_vendor_lib/src/hci_packet.cc
deleted file mode 100644
index 219c187..0000000
--- a/vendor_libs/test_vendor_lib/src/hci_packet.cc
+++ /dev/null
@@ -1,125 +0,0 @@
-#include "hci_packet.h"
-
-namespace test_vendor_lib {
-
-// Iterator Functions
-Iterator::Iterator(std::shared_ptr<HciPacket> packet, size_t i) {
- hci_packet_ = packet;
- index_ = i;
-}
-
-Iterator::Iterator(const Iterator& itr) { *this = itr; }
-
-Iterator::operator bool() const { return hci_packet_ != nullptr; }
-
-Iterator Iterator::operator+(size_t offset) {
- auto itr(*this);
-
- return itr += offset;
-}
-
-Iterator& Iterator::operator+=(size_t offset) {
- size_t new_offset = index_ + offset;
- index_ = new_offset >= hci_packet_->get_length() ? hci_packet_->get_length()
- : new_offset;
- return *this;
-}
-
-Iterator Iterator::operator++(int) {
- auto itr(*this);
- index_++;
-
- if (index_ >= hci_packet_->get_length()) index_ = hci_packet_->get_length();
-
- return itr;
-}
-
-Iterator& Iterator::operator++() {
- index_++;
-
- if (index_ >= hci_packet_->get_length()) index_ = hci_packet_->get_length();
-
- return *this;
-}
-
-Iterator Iterator::operator-(size_t offset) {
- auto itr(*this);
-
- return itr -= offset;
-}
-
-int Iterator::operator-(Iterator& itr) { return index_ - itr.index_; }
-
-Iterator& Iterator::operator-=(size_t offset) {
- index_ = offset > index_ ? 0 : index_ - offset;
-
- return *this;
-}
-
-Iterator Iterator::operator--(int) {
- auto itr(*this);
- if (index_ != 0) index_--;
-
- return itr;
-}
-
-Iterator& Iterator::operator--() {
- if (index_ != 0) index_--;
-
- return *this;
-}
-
-Iterator& Iterator::operator=(const Iterator& itr) {
- hci_packet_ = itr.hci_packet_;
- index_ = itr.index_;
-
- return *this;
-}
-
-bool Iterator::operator==(Iterator& itr) {
- return ((hci_packet_ == itr.hci_packet_) && (index_ == itr.index_));
-}
-
-bool Iterator::operator!=(Iterator& itr) { return !(*this == itr); }
-
-bool Iterator::operator<(Iterator& itr) {
- return ((hci_packet_ == itr.hci_packet_) && (index_ < itr.index_));
-}
-
-bool Iterator::operator>(Iterator& itr) {
- return ((hci_packet_ == itr.hci_packet_) && (index_ > itr.index_));
-}
-
-bool Iterator::operator<=(Iterator& itr) {
- return ((hci_packet_ == itr.hci_packet_) && (index_ <= itr.index_));
-}
-
-bool Iterator::operator>=(Iterator& itr) {
- return ((hci_packet_ == itr.hci_packet_) && (index_ >= itr.index_));
-}
-
-uint8_t& Iterator::operator*() const {
- CHECK(index_ != hci_packet_->get_length());
-
- return hci_packet_->get_at_index(index_);
-}
-
-uint8_t* Iterator::operator->() const {
- return &hci_packet_->get_at_index(index_);
-}
-
-// BtPacket Functions
-Iterator HciPacket::get_begin() {
- Iterator itr(shared_from_this(), 0);
-
- return itr;
-}
-
-Iterator HciPacket::get_end() {
- Iterator itr(shared_from_this(), get_length());
-
- return itr;
-}
-
-uint8_t HciPacket::operator[](size_t i) { return get_at_index(i); }
-}; // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/keyboard.cc b/vendor_libs/test_vendor_lib/src/keyboard.cc
deleted file mode 100644
index 74caf41..0000000
--- a/vendor_libs/test_vendor_lib/src/keyboard.cc
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright 2016 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 "keyboard"
-
-#include "keyboard.h"
-
-using std::vector;
-
-namespace test_vendor_lib {
-Keyboard::Keyboard() {
- advertising_type_ = BTM_BLE_CONNECT_EVT;
- adv_data_ = {0x11, // Length
- BTM_BLE_AD_TYPE_NAME_CMPL,
- 'g',
- 'D',
- 'e',
- 'v',
- 'i',
- 'c',
- 'e',
- '-',
- 'k',
- 'e',
- 'y',
- 'b',
- 'o',
- 'a',
- 'r',
- 'd',
- 0x03, // Length
- 0x19,
- 0xC1,
- 0x03,
- 0x03, // Length
- 0x03,
- 0x12,
- 0x18,
- 0x02, // Length
- BTM_BLE_AD_TYPE_FLAG,
- BTM_BLE_BREDR_NOT_SPT | BTM_BLE_GEN_DISC_FLAG};
-
- scan_data_ = {0x04, // Length
- BTM_BLE_AD_TYPE_NAME_SHORT, 'k', 'e', 'y'};
-}
-
-std::string Keyboard::GetTypeString() const { return "keyboard"; }
-
-void Keyboard::Initialize(const vector<std::string>& args) {
- if (args.size() < 2) return;
-
- BtAddress addr;
- if (addr.FromString(args[1])) SetBtAddress(addr);
-
- if (args.size() < 3) return;
-
- SetAdvertisementInterval(std::chrono::milliseconds(std::stoi(args[2])));
-}
-
-bool Keyboard::LeConnect() { return true; }
-
-bool Keyboard::IsPageScanAvailable() const { return false; }
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/l2cap_packet.cc b/vendor_libs/test_vendor_lib/src/l2cap_packet.cc
deleted file mode 100644
index ad17b48..0000000
--- a/vendor_libs/test_vendor_lib/src/l2cap_packet.cc
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * Copyright 2017 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 "l2cap_packet"
-
-#include "l2cap_packet.h"
-
-#include <algorithm>
-
-#include "osi/include/log.h"
-
-namespace test_vendor_lib {
-
-const size_t kL2capHeaderLength = 4;
-const size_t kSduFirstHeaderLength = 8;
-const size_t kSduStandardHeaderLength = 6;
-const size_t kFcsBytes = 2;
-const uint16_t kSduTxSeqBits = 0x007E;
-const uint8_t kSduFirstReqseq = 0x40;
-const uint8_t kSduContinuationReqseq = 0xC0;
-const uint8_t kSduEndReqseq = 0x80;
-
-std::shared_ptr<L2capPacket> L2capPacket::assemble(
- const std::vector<std::shared_ptr<L2capSdu> >& sdu_packets) {
- std::shared_ptr<L2capPacket> built_l2cap_packet(new L2capPacket());
- uint16_t l2cap_payload_length = 0;
- uint16_t first_packet_channel_id = 0;
- uint16_t total_expected_l2cap_length;
- uint8_t txseq_start;
-
- if (sdu_packets.size() == 0) {
- LOG_DEBUG(LOG_TAG, "%s: No SDU received.", __func__);
- return nullptr;
- }
- if (sdu_packets.size() == 1 &&
- !L2capSdu::is_complete_l2cap(*sdu_packets[0])) {
- LOG_DEBUG(LOG_TAG, "%s: Unsegmented SDU has incorrect SAR bits.", __func__);
- return nullptr;
- }
-
- first_packet_channel_id = sdu_packets[0]->get_channel_id();
-
- built_l2cap_packet->l2cap_packet_.resize(kL2capHeaderLength);
-
- for (size_t i = 0; i < sdu_packets.size(); i++) {
- uint16_t payload_length = sdu_packets[i]->get_payload_length();
-
- // TODO(jruthe): Remove these checks when ACL packets have been
- // implemented. Once those are done, that will be the only way to create
- // L2capSdu objects and these checks will be moved there instead.
- //
- // Check the integrity of the packet length, if it is zero, it is invalid.
- // The maximum size of a single, segmented L2CAP payload is 1016 bytes.
- if ((payload_length <= 0) ||
- (payload_length != sdu_packets[i]->get_vector_size() - 4)) {
- LOG_DEBUG(LOG_TAG, "%s: SDU payload length incorrect.", __func__);
- return nullptr;
- }
-
- uint16_t fcs_check = sdu_packets[i]->get_fcs();
-
- if (sdu_packets[i]->calculate_fcs() != fcs_check) {
- LOG_DEBUG(LOG_TAG, "%s: SDU fcs is incorrect.", __func__);
- return nullptr;
- }
-
- uint16_t controls = sdu_packets[i]->get_controls();
-
- if (sdu_packets[i]->get_channel_id() != first_packet_channel_id) {
- LOG_DEBUG(LOG_TAG, "%s: SDU CID does not match expected.", __func__);
- return nullptr;
- }
-
- if (i == 0) txseq_start = controls & kSduTxSeqBits;
-
- // Bluetooth Specification version 4.2 volume 3 part A 3.3.2:
- // If there is only a single SDU, the first two bits of the control must be
- // set to 00b, representing an unsegmented SDU. If the SDU is segmented,
- // there is a begin and an end. The first segment must have the first two
- // control bits set to 01b and the ending segment must have them set to 10b.
- // Meanwhile all segments in between the start and end must have the bits
- // set to 11b.
- size_t starting_index;
- uint8_t txseq = controls & kSduTxSeqBits;
- if (sdu_packets.size() > 1 && i == 0 &&
- !L2capSdu::is_starting_sdu(*sdu_packets[i])) {
- LOG_DEBUG(LOG_TAG, "%s: First segmented SDU has incorrect SAR bits.",
- __func__);
- return nullptr;
- }
- if (i != 0 && L2capSdu::is_starting_sdu(*sdu_packets[i])) {
- LOG_DEBUG(LOG_TAG,
- "%s: SAR bits set to first segmented SDU on "
- "non-starting SDU.",
- __func__);
- return nullptr;
- }
- if (txseq != (txseq_start + (static_cast<uint8_t>(i) << 1))) {
- LOG_DEBUG(LOG_TAG, "%s: TxSeq incorrect.", __func__);
- return nullptr;
- }
- if (sdu_packets.size() > 1 && i == sdu_packets.size() - 1 &&
- !L2capSdu::is_ending_sdu(*sdu_packets[i])) {
- LOG_DEBUG(LOG_TAG, "%s: Final segmented SDU has incorrect SAR bits.",
- __func__);
- return nullptr;
- }
-
- // Subtract the control and fcs from every SDU payload length.
- l2cap_payload_length += (payload_length - 4);
-
- if (L2capSdu::is_starting_sdu(*sdu_packets[i])) {
- starting_index = kSduFirstHeaderLength;
- total_expected_l2cap_length = sdu_packets[i]->get_total_l2cap_length();
-
- // Subtract the additional two bytes from the first packet of a segmented
- // SDU.
- l2cap_payload_length -= 2;
- } else {
- starting_index = kSduStandardHeaderLength;
- }
-
- Iterator payload_begin = sdu_packets[i]->get_begin() + starting_index;
- Iterator payload_end = sdu_packets[i]->get_end() - kFcsBytes;
-
- built_l2cap_packet->l2cap_packet_.insert(
- built_l2cap_packet->l2cap_packet_.end(), payload_begin, payload_end);
- }
-
- if (l2cap_payload_length != total_expected_l2cap_length &&
- sdu_packets.size() > 1) {
- LOG_DEBUG(LOG_TAG, "%s: Total expected L2CAP payload length incorrect.",
- __func__);
- return nullptr;
- }
-
- built_l2cap_packet->l2cap_packet_[0] = l2cap_payload_length & 0xFF;
- built_l2cap_packet->l2cap_packet_[1] = (l2cap_payload_length & 0xFF00) >> 8;
- built_l2cap_packet->l2cap_packet_[2] = first_packet_channel_id & 0xFF;
- built_l2cap_packet->l2cap_packet_[3] =
- (first_packet_channel_id & 0xFF00) >> 8;
-
- return built_l2cap_packet;
-} // Assemble
-
-uint16_t L2capPacket::get_l2cap_cid() const {
- return ((l2cap_packet_[3] << 8) | l2cap_packet_[2]);
-}
-
-std::vector<std::shared_ptr<L2capSdu> > L2capPacket::fragment(
- uint16_t maximum_sdu_size, uint8_t txseq, uint8_t reqseq) {
- std::vector<std::shared_ptr<L2capSdu> > sdu;
- if (!check_l2cap_packet()) return sdu;
-
- std::vector<uint8_t> current_sdu;
-
- Iterator current_iter = get_begin() + kL2capHeaderLength;
- Iterator end_iter = get_end();
-
- size_t number_of_packets = ceil((l2cap_packet_.size() - kL2capHeaderLength) /
- static_cast<float>(maximum_sdu_size));
-
- if (number_of_packets == 0) {
- current_sdu.resize(kSduStandardHeaderLength);
-
- set_sdu_header_length(current_sdu, kL2capHeaderLength);
-
- set_sdu_cid(current_sdu, get_l2cap_cid());
-
- reqseq = (reqseq & 0xF0) >> 4;
- set_sdu_control_bytes(current_sdu, txseq, reqseq);
-
- sdu.push_back(L2capSdu::L2capSduBuilder(current_sdu));
-
- return sdu;
- }
-
- uint16_t header_length = 0x0000;
-
- if (number_of_packets == 1) {
- current_sdu.clear();
- current_sdu.resize(kSduStandardHeaderLength);
-
- header_length = ((l2cap_packet_[1] & 0xFF) << 8) | l2cap_packet_[0];
- header_length += kL2capHeaderLength;
- set_sdu_header_length(current_sdu, header_length);
-
- set_sdu_cid(current_sdu, get_l2cap_cid());
-
- set_sdu_control_bytes(current_sdu, txseq, 0x00);
-
- current_sdu.insert(current_sdu.end(), current_iter, end_iter);
-
- sdu.push_back(L2capSdu::L2capSduBuilder(current_sdu));
-
- return sdu;
- }
-
- Iterator next_iter =
- current_iter + (maximum_sdu_size - (kSduFirstHeaderLength + 2));
-
- sdu.reserve(number_of_packets);
- sdu.clear();
-
- for (size_t i = 0; i <= number_of_packets; i++) {
- if (i == 0) {
- current_sdu.resize(kSduFirstHeaderLength);
-
- header_length = maximum_sdu_size - kL2capHeaderLength;
-
- reqseq = reqseq | kSduFirstReqseq;
-
- set_total_sdu_length(current_sdu, l2cap_packet_.size() - 4);
- } else {
- current_sdu.resize(kSduStandardHeaderLength);
-
- header_length = (next_iter - current_iter) + kL2capHeaderLength;
-
- reqseq = reqseq & 0x0F;
-
- if (i < number_of_packets) {
- reqseq |= kSduContinuationReqseq;
- } else {
- reqseq |= kSduEndReqseq;
- }
- }
- set_sdu_header_length(current_sdu, header_length);
-
- set_sdu_cid(current_sdu, get_l2cap_cid());
-
- set_sdu_control_bytes(current_sdu, txseq, reqseq);
- txseq += 2;
-
- // Txseq has a maximum of 0x3F. If it exceeds that, it restarts at 0x00.
- if (txseq > 0x3F) txseq = 0x00;
-
- current_sdu.insert(current_sdu.end(), current_iter, next_iter);
- current_iter = next_iter;
-
- next_iter = current_iter + (maximum_sdu_size - kSduFirstHeaderLength);
-
- sdu.push_back(L2capSdu::L2capSduBuilder(std::move(current_sdu)));
- }
-
- return sdu;
-} // fragment
-
-void L2capPacket::set_sdu_header_length(std::vector<uint8_t>& sdu,
- uint16_t length) {
- sdu[0] = length & 0xFF;
- sdu[1] = (length & 0xFF00) >> 8;
-}
-
-void L2capPacket::set_total_sdu_length(std::vector<uint8_t>& sdu,
- uint16_t total_sdu_length) {
- sdu[6] = total_sdu_length & 0xFF;
- sdu[7] = (total_sdu_length & 0xFF00) >> 8;
-}
-
-void L2capPacket::set_sdu_cid(std::vector<uint8_t>& sdu, uint16_t cid) {
- sdu[2] = cid & 0xFF;
- sdu[3] = (cid & 0xFF00) >> 8;
-}
-
-void L2capPacket::set_sdu_control_bytes(std::vector<uint8_t>& sdu,
- uint8_t txseq, uint8_t reqseq) {
- sdu[4] = txseq;
- sdu[5] = reqseq;
-}
-
-bool L2capPacket::check_l2cap_packet() const {
- uint16_t payload_length = ((l2cap_packet_[1] & 0xFF) << 8) | l2cap_packet_[0];
-
- if (l2cap_packet_.size() < 4) return false;
- if (payload_length != (l2cap_packet_.size() - 4)) return false;
-
- return true;
-}
-
-// HciPacket Functions
-size_t L2capPacket::get_length() { return l2cap_packet_.size(); }
-
-uint8_t& L2capPacket::get_at_index(size_t index) {
- return l2cap_packet_[index];
-}
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/l2cap_sdu.cc b/vendor_libs/test_vendor_lib/src/l2cap_sdu.cc
deleted file mode 100644
index a93c1ad..0000000
--- a/vendor_libs/test_vendor_lib/src/l2cap_sdu.cc
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright 2017 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 "l2cap_sdu.h"
-
-#include <base/logging.h>
-
-namespace test_vendor_lib {
-
-const uint16_t kSduSarBits = 0xe000;
-
-// Define the LFSR table of precalculated values defined by the
-// Bluetooth specification version 4.2 volume 3 part A section 3.3.5.
-const uint16_t L2capSdu::lfsr_table_[256] = {
- 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, 0xc601,
- 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440, 0xcc01, 0x0cc0,
- 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, 0x0a00, 0xcac1, 0xcb81,
- 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841, 0xd801, 0x18c0, 0x1980, 0xd941,
- 0x1b00, 0xdbc1, 0xda81, 0x1a40, 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01,
- 0x1dc0, 0x1c80, 0xdc41, 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0,
- 0x1680, 0xd641, 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081,
- 0x1040, 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
- 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441, 0x3c00,
- 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, 0xfa01, 0x3ac0,
- 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, 0x2800, 0xe8c1, 0xe981,
- 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, 0xee01, 0x2ec0, 0x2f80, 0xef41,
- 0x2d00, 0xedc1, 0xec81, 0x2c40, 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700,
- 0xe7c1, 0xe681, 0x2640, 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0,
- 0x2080, 0xe041, 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281,
- 0x6240, 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
- 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, 0xaa01,
- 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, 0x7800, 0xb8c1,
- 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, 0xbe01, 0x7ec0, 0x7f80,
- 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, 0xb401, 0x74c0, 0x7580, 0xb541,
- 0x7700, 0xb7c1, 0xb681, 0x7640, 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101,
- 0x71c0, 0x7080, 0xb041, 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0,
- 0x5280, 0x9241, 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481,
- 0x5440, 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
- 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841, 0x8801,
- 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, 0x4e00, 0x8ec1,
- 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41, 0x4400, 0x84c1, 0x8581,
- 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, 0x8201, 0x42c0, 0x4380, 0x8341,
- 0x4100, 0x81c1, 0x8081, 0x4040,
-}; // lfsr_table
-
-L2capSdu::L2capSdu(std::vector<uint8_t>&& create_from) {
- sdu_data_ = create_from;
-}
-
-std::shared_ptr<L2capSdu> L2capSdu::L2capSduConstructor(
- std::vector<uint8_t> create_from) {
- L2capSdu packet(std::move(create_from));
-
- return std::make_shared<L2capSdu>(packet);
-}
-
-std::shared_ptr<L2capSdu> L2capSdu::L2capSduBuilder(
- std::vector<uint8_t> create_from) {
- L2capSdu packet(std::move(create_from));
-
- packet.sdu_data_.resize(packet.sdu_data_.size() + 2, 0x00);
-
- uint16_t fcs = packet.calculate_fcs();
-
- packet.sdu_data_[packet.sdu_data_.size() - 2] = fcs & 0xFF;
- packet.sdu_data_[packet.sdu_data_.size() - 1] = (fcs & 0xFF00) >> 8;
-
- return std::make_shared<L2capSdu>(packet);
-}
-
-uint16_t L2capSdu::convert_from_little_endian(
- const unsigned int starting_index) const {
- uint16_t convert = sdu_data_[starting_index + 1];
- convert = convert << 8;
- convert = convert | sdu_data_[starting_index];
-
- return convert;
-}
-
-uint16_t L2capSdu::calculate_fcs() const {
- // Starting state as directed by Bluetooth specification version 4.2 volume 3
- // part A 3.3.5.
- uint16_t lfsr = 0x0000;
-
- for (size_t i = 0; i < sdu_data_.size() - 2; i++) {
- uint8_t current_byte = sdu_data_[i];
- lfsr = ((lfsr >> 8) & 0xff) ^ lfsr_table_[(lfsr & 0xff) ^ current_byte];
- }
- return lfsr;
-}
-
-uint16_t L2capSdu::get_payload_length() const {
- return convert_from_little_endian(0);
-}
-
-uint16_t L2capSdu::get_fcs() const {
- return convert_from_little_endian(sdu_data_.size() - 2);
-}
-
-uint16_t L2capSdu::get_controls() const {
- return convert_from_little_endian(4);
-}
-
-uint16_t L2capSdu::get_total_l2cap_length() const {
- return convert_from_little_endian(6);
-}
-
-uint16_t L2capSdu::get_channel_id() const {
- return convert_from_little_endian(2);
-}
-
-size_t L2capSdu::get_vector_size() const { return sdu_data_.size(); }
-
-bool L2capSdu::is_complete_l2cap(const L2capSdu& sdu) {
- uint16_t sar_bits = (sdu.get_controls() & kSduSarBits);
-
- return (sar_bits == 0x0000);
-}
-
-bool L2capSdu::is_starting_sdu(const L2capSdu& sdu) {
- uint16_t sar_bits = (sdu.get_controls() & kSduSarBits);
-
- return (sar_bits == 0x4000);
-}
-
-bool L2capSdu::is_ending_sdu(const L2capSdu& sdu) {
- uint16_t sar_bits = (sdu.get_controls() & kSduSarBits);
-
- return (sar_bits == 0x8000);
-}
-
-// HciPacket functions.
-size_t L2capSdu::get_length() { return sdu_data_.size(); }
-uint8_t& L2capSdu::get_at_index(size_t index) { return sdu_data_[index]; }
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/packet.cc b/vendor_libs/test_vendor_lib/src/packet.cc
deleted file mode 100644
index 49f7272..0000000
--- a/vendor_libs/test_vendor_lib/src/packet.cc
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * 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 "packet.h"
-
-#include <algorithm>
-
-#include <base/logging.h>
-#include "osi/include/log.h"
-
-using std::vector;
-
-namespace test_vendor_lib {
-
-Packet::Packet(serial_data_type_t type, vector<uint8_t> header)
- : type_(type), header_(std::move(header)) {
- payload_ = {0};
-}
-
-bool Packet::AddPayloadOctets(size_t octets, const vector<uint8_t>& bytes) {
- if (GetPayloadSize() + octets > kMaxPayloadOctets) return false;
-
- if (octets != bytes.size()) return false;
-
- payload_.insert(payload_.end(), bytes.begin(), bytes.end());
- payload_[0] = payload_.size() - 1;
-
- return true;
-}
-
-bool Packet::AddPayloadOctets(size_t octets, uint64_t value) {
- vector<uint8_t> val_vector;
-
- uint64_t v = value;
-
- if (octets > sizeof(uint64_t)) return false;
-
- for (size_t i = 0; i < octets; i++) {
- val_vector.push_back(v & 0xff);
- v = v >> 8;
- }
-
- if (v != 0) return false;
-
- return AddPayloadOctets(octets, val_vector);
-}
-
-bool Packet::AddPayloadBtAddress(const BtAddress& address) {
- if (GetPayloadSize() + BtAddress::kOctets > kMaxPayloadOctets) return false;
-
- address.ToVector(payload_);
-
- payload_[0] = payload_.size() - 1;
-
- return true;
-}
-
-bool Packet::IncrementPayloadCounter(size_t index) {
- if (payload_.size() < index - 1) return false;
-
- payload_[index]++;
- return true;
-}
-
-bool Packet::IncrementPayloadCounter(size_t index, uint8_t max_val) {
- if (payload_.size() < index - 1) return false;
-
- if (payload_[index] + 1 > max_val) return false;
-
- payload_[index]++;
- return true;
-}
-
-const 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 vector<uint8_t>& Packet::GetPayload() const { return payload_; }
-
-size_t Packet::GetPayloadSize() const { return payload_.size(); }
-
-serial_data_type_t Packet::GetType() const { return type_; }
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/packet_stream.cc b/vendor_libs/test_vendor_lib/src/packet_stream.cc
deleted file mode 100644
index 224283c..0000000
--- a/vendor_libs/test_vendor_lib/src/packet_stream.cc
+++ /dev/null
@@ -1,129 +0,0 @@
-//
-// 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 "packet_stream.h"
-
-#include <base/logging.h>
-
-#include <errno.h>
-#include <unistd.h>
-
-#include "osi/include/log.h"
-
-using std::vector;
-
-namespace test_vendor_lib {
-
-std::unique_ptr<CommandPacket> PacketStream::ReceiveCommand(int fd) const {
- vector<uint8_t> header;
- vector<uint8_t> params_size;
- 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(params_size, 1, fd)) {
- LOG_ERROR(LOG_TAG, "Error: receiving params size.");
- return std::unique_ptr<CommandPacket>(nullptr);
- }
-
- if (!ReceiveAll(payload, params_size[0], fd)) {
- LOG_ERROR(LOG_TAG, "Error: receiving command payload.");
- return std::unique_ptr<CommandPacket>(nullptr);
- }
- return std::unique_ptr<CommandPacket>(new CommandPacket(header, payload));
-}
-
-serial_data_type_t PacketStream::ReceivePacketType(int fd) const {
- 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(std::unique_ptr<EventPacket> event, int fd) const {
- if (event->GetPayload()[0] != event->GetPayloadSize() - 1)
- LOG_WARN(LOG_TAG, "Malformed event: 0x%04X, payload size %zu, reported %u",
- event->GetEventCode(), event->GetPacketSize(),
- event->GetPayload()[0]);
-
- 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 {
- // 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(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 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
diff --git a/vendor_libs/test_vendor_lib/src/sco_packet.cc b/vendor_libs/test_vendor_lib/src/sco_packet.cc
deleted file mode 100644
index 465d8ff..0000000
--- a/vendor_libs/test_vendor_lib/src/sco_packet.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2017 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 "sco_packet"
-
-#include "sco_packet.h"
-
-#include "stack/include/hcidefs.h"
-
-using std::vector;
-
-namespace test_vendor_lib {
-
-ScoPacket::ScoPacket(uint16_t channel,
- ScoPacket::PacketStatusFlags packet_status)
- : Packet(DATA_TYPE_SCO,
- {static_cast<uint8_t>(channel & 0xff),
- static_cast<uint8_t>(((channel >> 8) & 0x0f) |
- (packet_status & 0x3 << 4))}) {}
-
-uint16_t ScoPacket::GetChannel() const {
- return (GetHeader()[0] | (GetHeader()[1] << 8)) & 0xfff;
-}
-
-ScoPacket::PacketStatusFlags ScoPacket::GetPacketStatusFlags() const {
- return static_cast<ScoPacket::PacketStatusFlags>((GetHeader()[1] >> 4) & 0x3);
-}
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/test_channel_transport.cc b/vendor_libs/test_vendor_lib/src/test_channel_transport.cc
deleted file mode 100644
index 0d9bc2e..0000000
--- a/vendor_libs/test_vendor_lib/src/test_channel_transport.cc
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * 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 "test_channel_transport.h"
-
-#include <base/logging.h>
-
-#include "osi/include/log.h"
-#include "osi/include/osi.h"
-
-#include <netinet/in.h>
-#include <sys/socket.h>
-
-using std::vector;
-
-namespace test_vendor_lib {
-
-int TestChannelTransport::SetUp(int port) {
- struct sockaddr_in listen_address;
- socklen_t sockaddr_in_size = sizeof(struct sockaddr_in);
- memset(&listen_address, 0, sockaddr_in_size);
-
- OSI_NO_INTR(listen_fd_ = socket(AF_INET, SOCK_STREAM, 0));
- if (listen_fd_ < 0) {
- LOG_INFO(LOG_TAG, "Error creating socket for test channel.");
- return -1;
- }
-
- 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 -1;
- }
-
- if (listen(listen_fd_, 1) < 0) {
- LOG_INFO(LOG_TAG, "Error listening for test channel.");
- close(listen_fd_);
- return -1;
- }
- return listen_fd_;
-}
-
-void TestChannelTransport::CleanUp() {
- if (listen_fd_ == -1) {
- return;
- }
- if (close(listen_fd_)) {
- LOG_ERROR(LOG_TAG, "Error closing listen_fd_.");
- }
- listen_fd_ = -1;
-}
-
-int TestChannelTransport::Accept(int listen_fd_) {
- int accept_fd = -1;
- struct sockaddr_in test_channel_address;
- socklen_t sockaddr_in_size = sizeof(struct sockaddr_in);
- memset(&test_channel_address, 0, sockaddr_in_size);
-
- OSI_NO_INTR(accept_fd =
- accept(listen_fd_,
- reinterpret_cast<sockaddr*>(&test_channel_address),
- &sockaddr_in_size));
- if (accept_fd < 0) {
- LOG_INFO(LOG_TAG, "Error accepting test channel connection errno=%d (%s).",
- errno, strerror(errno));
-
- if (errno != EAGAIN && errno != EWOULDBLOCK) {
- LOG_ERROR(LOG_TAG, "Closing listen_fd_ (won't try again).");
- close(listen_fd_);
- return -1;
- }
- }
-
- LOG_INFO(LOG_TAG, "accept_fd = %d.", accept_fd);
-
- return accept_fd;
-}
-
-void TestChannelTransport::OnCommandReady(int fd,
- std::function<void(void)> unwatch) {
- uint8_t command_name_size = 0;
- read(fd, &command_name_size, 1);
- 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" || command_name == "") {
- LOG_INFO(LOG_TAG, "Test channel closed");
- unwatch();
- close(fd);
- return;
- }
-
- uint8_t num_args = 0;
- read(fd, &num_args, 1);
- LOG_INFO(LOG_TAG, "num_args: %d", num_args);
- vector<std::string> args;
- for (uint8_t i = 0; i < num_args; ++i) {
- uint8_t arg_size = 0;
- read(fd, &arg_size, 1);
- 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 %zu: %s", i, args[i].data());
-
- command_handler_(command_name, args);
-}
-
-void TestChannelTransport::RegisterCommandHandler(
- const std::function<void(const std::string&, const vector<std::string>&)>&
- callback) {
- command_handler_ = callback;
-}
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/test/async_manager_unittest.cc b/vendor_libs/test_vendor_lib/test/async_manager_unittest.cc
index 97b7331..fe2b95a 100644
--- a/vendor_libs/test_vendor_lib/test/async_manager_unittest.cc
+++ b/vendor_libs/test_vendor_lib/test/async_manager_unittest.cc
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "async_manager.h"
+#include "model/setup/async_manager.h"
#include <gtest/gtest.h>
#include <cstdint>
#include <cstring>
@@ -48,8 +48,7 @@
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(kPort);
int reuse_flag = 1;
- EXPECT_FALSE(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse_flag,
- sizeof(reuse_flag)) < 0);
+ EXPECT_FALSE(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse_flag, sizeof(reuse_flag)) < 0);
EXPECT_FALSE(bind(fd, (sockaddr*)&serv_addr, sizeof(serv_addr)) < 0);
listen(fd, 1);
@@ -87,8 +86,7 @@
async_manager_.WatchFdForNonBlockingReads(socket_fd_, [this](int fd) {
int connection_fd = AcceptConnection(fd);
- async_manager_.WatchFdForNonBlockingReads(
- connection_fd, [this](int fd) { ReadIncomingMessage(fd); });
+ async_manager_.WatchFdForNonBlockingReads(connection_fd, [this](int fd) { ReadIncomingMessage(fd); });
});
}
@@ -112,8 +110,7 @@
serv_addr.sin_addr.s_addr = *(reinterpret_cast<in_addr_t*>(server->h_addr));
serv_addr.sin_port = htons(kPort);
- int result =
- connect(socket_cli_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
+ int result = connect(socket_cli_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
EXPECT_FALSE(result < 0);
return socket_cli_fd;
diff --git a/vendor_libs/test_vendor_lib/test/bt_address_unittest.cc b/vendor_libs/test_vendor_lib/test/bt_address_unittest.cc
deleted file mode 100644
index 0cf3760..0000000
--- a/vendor_libs/test_vendor_lib/test/bt_address_unittest.cc
+++ /dev/null
@@ -1,194 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2016 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 <gtest/gtest.h>
-#include <string>
-#include <vector>
-using std::vector;
-
-#include "bt_address.h"
-
-namespace {
-const std::string kTestAddr1 = "12:34:56:78:9a:bc";
-const std::string kTestAddr2 = "cb:a9:87:65:43:21";
-const std::string kTestAddr3 = "cb:a9:56:78:9a:bc";
-const std::string kUpperMask = "ff:ff:00:00:00:00";
-const std::string kLowerMask = "00:00:ff:ff:ff:ff";
-const std::string kZeros = "00:00:00:00:00:00";
-const vector<uint8_t> kZeros_octets = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-const vector<uint8_t> kTestAddr1_octets = {0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12};
-} // namespace
-
-namespace test_vendor_lib {
-
-class BtAddressTest : public ::testing::Test {
- public:
- BtAddressTest() {}
- ~BtAddressTest() {}
-};
-
-TEST_F(BtAddressTest, IsValid) {
- EXPECT_FALSE(BtAddress::IsValid(""));
- EXPECT_FALSE(BtAddress::IsValid("000000000000"));
- EXPECT_FALSE(BtAddress::IsValid("00:00:00:00:0000"));
- EXPECT_FALSE(BtAddress::IsValid("00:00:00:00:00:0"));
- EXPECT_FALSE(BtAddress::IsValid("00:00:00:00:00:0;"));
- EXPECT_FALSE(BtAddress::IsValid("00:00:000:00:00:0;"));
- EXPECT_TRUE(BtAddress::IsValid("00:00:00:00:00:00"));
- EXPECT_FALSE(BtAddress::IsValid("aB:cD:eF:Gh:iJ:Kl"));
- EXPECT_TRUE(BtAddress::IsValid(kTestAddr1));
- EXPECT_TRUE(BtAddress::IsValid(kTestAddr2));
- EXPECT_TRUE(BtAddress::IsValid(kTestAddr3));
-}
-
-TEST_F(BtAddressTest, test_comparisons) {
- BtAddress btaddr1;
- BtAddress btaddr1_copy;
- BtAddress btaddr2;
-
- EXPECT_TRUE(btaddr1.FromString(kTestAddr1));
- EXPECT_TRUE(btaddr1_copy.FromString(kTestAddr1));
- EXPECT_TRUE(btaddr2.FromString(kTestAddr2));
-
- EXPECT_TRUE(btaddr1 == btaddr1_copy);
- EXPECT_FALSE(btaddr1 == btaddr2);
-
- EXPECT_FALSE(btaddr1 != btaddr1_copy);
- EXPECT_TRUE(btaddr1 != btaddr2);
-
- EXPECT_FALSE(btaddr1 < btaddr1_copy);
- EXPECT_TRUE(btaddr1 < btaddr2);
- EXPECT_FALSE(btaddr2 < btaddr1);
-
- EXPECT_FALSE(btaddr1 > btaddr1_copy);
- EXPECT_FALSE(btaddr1 > btaddr2);
- EXPECT_TRUE(btaddr2 > btaddr1);
-
- EXPECT_TRUE(btaddr1 <= btaddr1_copy);
- EXPECT_TRUE(btaddr1 <= btaddr2);
- EXPECT_FALSE(btaddr2 <= btaddr1);
-
- EXPECT_TRUE(btaddr1 >= btaddr1_copy);
- EXPECT_FALSE(btaddr1 >= btaddr2);
- EXPECT_TRUE(btaddr2 >= btaddr1);
-}
-
-TEST_F(BtAddressTest, test_assignment) {
- BtAddress btaddr1;
- BtAddress btaddr2;
- BtAddress btaddr3;
-
- EXPECT_TRUE(btaddr1.FromString(kTestAddr1));
- EXPECT_TRUE(btaddr2.FromString(kTestAddr2));
- EXPECT_TRUE(btaddr3.FromString(kTestAddr3));
-
- EXPECT_TRUE(btaddr1 != btaddr2);
- EXPECT_TRUE(btaddr2 != btaddr3);
- EXPECT_TRUE(btaddr1 != btaddr3);
-
- btaddr1 = btaddr2;
- EXPECT_TRUE(btaddr1 == btaddr2);
- EXPECT_TRUE(btaddr2 != btaddr3);
- EXPECT_TRUE(btaddr1 != btaddr3);
-
- btaddr3 = btaddr2;
- EXPECT_TRUE(btaddr1 == btaddr2);
- EXPECT_TRUE(btaddr2 == btaddr3);
- EXPECT_TRUE(btaddr1 == btaddr3);
-}
-
-TEST_F(BtAddressTest, test_bitoperations) {
- BtAddress btaddr1;
- BtAddress btaddr2;
- BtAddress btaddr3;
- BtAddress btaddr_lowmask;
- BtAddress btaddr_upmask;
-
- EXPECT_TRUE(btaddr1.FromString(kTestAddr1));
- EXPECT_TRUE(btaddr2.FromString(kTestAddr2));
- EXPECT_TRUE(btaddr3.FromString(kTestAddr3));
- EXPECT_TRUE(btaddr_lowmask.FromString(kLowerMask));
- EXPECT_TRUE(btaddr_upmask.FromString(kUpperMask));
-
- EXPECT_TRUE(btaddr1 != btaddr2);
- EXPECT_TRUE(btaddr2 != btaddr3);
- btaddr1 &= btaddr_lowmask;
- btaddr2 &= btaddr_upmask;
- btaddr1 |= btaddr2;
- EXPECT_TRUE(btaddr1 == btaddr3);
-}
-
-TEST_F(BtAddressTest, FromString) {
- BtAddress btaddrA;
- BtAddress btaddrB;
- BtAddress btaddrC;
- EXPECT_TRUE(btaddrA.FromString(kTestAddr1));
- EXPECT_TRUE(btaddrA != btaddrB);
- EXPECT_TRUE(btaddrC == btaddrB);
- EXPECT_TRUE(btaddrB.FromString(kTestAddr1));
- EXPECT_TRUE(btaddrC.FromString(kTestAddr1));
- EXPECT_TRUE(btaddrA == btaddrB);
- EXPECT_TRUE(btaddrC == btaddrB);
-}
-
-TEST_F(BtAddressTest, FromVector) {
- BtAddress btaddr1;
- EXPECT_TRUE(btaddr1.FromString(kTestAddr1));
- BtAddress btaddrA;
- BtAddress btaddrB;
- EXPECT_TRUE(btaddrA.FromVector(kTestAddr1_octets));
- EXPECT_TRUE(btaddrA != btaddrB);
- EXPECT_TRUE(btaddrB.FromVector(kTestAddr1_octets));
- EXPECT_TRUE(btaddrA == btaddrB);
- EXPECT_TRUE(btaddr1 == btaddrB);
-}
-
-TEST_F(BtAddressTest, ToVector) {
- BtAddress btaddr1;
- BtAddress btaddr1_copy;
- BtAddress btaddr2;
- vector<uint8_t> octets1;
- vector<uint8_t> octets1_copy;
- vector<uint8_t> octets2;
- EXPECT_TRUE(btaddr1.FromString(kTestAddr1));
- EXPECT_TRUE(btaddr1_copy.FromString(kTestAddr1));
- EXPECT_TRUE(btaddr2.FromString(kTestAddr2));
- EXPECT_TRUE(btaddr1 == btaddr1_copy);
- EXPECT_TRUE(btaddr1 != btaddr2);
- btaddr1.ToVector(octets1);
- btaddr2.ToVector(octets2);
- btaddr1_copy.ToVector(octets1_copy);
- EXPECT_TRUE(octets1 != octets2);
- EXPECT_TRUE(octets1 == octets1_copy);
- EXPECT_TRUE(octets1.size() == BtAddress::kOctets);
- btaddr1.ToVector(octets1);
- EXPECT_TRUE(octets1.size() == (2 * BtAddress::kOctets));
-}
-
-TEST_F(BtAddressTest, ToString) {
- BtAddress btaddr_zeros;
- BtAddress btaddr1;
- EXPECT_TRUE(btaddr_zeros.FromString(kZeros));
- EXPECT_TRUE(btaddr1.FromString(kTestAddr1));
- EXPECT_TRUE(btaddr_zeros.ToString() == kZeros);
- EXPECT_TRUE(btaddr1.ToString() == kTestAddr1);
- EXPECT_TRUE(btaddr_zeros.ToString() != kTestAddr1);
- EXPECT_TRUE(btaddr1.ToString() != kZeros);
-}
-
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/test/iterator_test.cc b/vendor_libs/test_vendor_lib/test/iterator_test.cc
index 92a6d70..b65b60f 100644
--- a/vendor_libs/test_vendor_lib/test/iterator_test.cc
+++ b/vendor_libs/test_vendor_lib/test/iterator_test.cc
@@ -29,22 +29,30 @@
static std::shared_ptr<TestPacket> make_new_packet(vector<uint8_t> v) {
return std::shared_ptr<TestPacket>(new TestPacket(v));
}
- size_t get_length() { return test_vector_.size(); }
- uint8_t& get_at_index(size_t index) { return test_vector_[index]; }
+ size_t get_length() {
+ return test_vector_.size();
+ }
+ uint8_t& get_at_index(size_t index) {
+ return test_vector_[index];
+ }
private:
- TestPacket(vector<uint8_t> v) { test_vector_ = v; }
+ TestPacket(vector<uint8_t> v) {
+ test_vector_ = v;
+ }
vector<uint8_t> test_vector_;
};
class IteratorTest : public ::testing::Test {
public:
IteratorTest() = default;
- ~IteratorTest() = default;
+ ~IteratorTest() override = default;
- void SetUp() { packet = TestPacket::make_new_packet(complete_l2cap_packet); }
+ void SetUp() override {
+ packet = TestPacket::make_new_packet(complete_l2cap_packet);
+ }
- void TearDown() { packet.reset(); }
+ void TearDown() override { packet.reset(); }
std::shared_ptr<TestPacket> packet;
};
@@ -77,8 +85,7 @@
Iterator plus_eq = packet->get_begin();
for (size_t i = 0; i < complete_l2cap_packet.size(); i += 2) {
ASSERT_EQ(complete_l2cap_packet[i], *plus_eq)
- << "+= test: Dereferenced iterator does not equal expected at index "
- << i;
+ << "+= test: Dereferenced iterator does not equal expected at index " << i;
plus_eq += 2;
}
}
@@ -105,8 +112,7 @@
Iterator plus = packet->get_begin();
for (size_t i = 0; i < complete_l2cap_packet.size(); i++) {
ASSERT_EQ(complete_l2cap_packet[i], *plus)
- << "+ test: Dereferenced iterator does not equal expected at index "
- << i;
+ << "+ test: Dereferenced iterator does not equal expected at index " << i;
plus = plus + static_cast<size_t>(1);
}
}
@@ -116,8 +122,7 @@
minus_eq -= 1;
for (size_t i = complete_l2cap_packet.size() - 1; i > 0; i -= 2) {
ASSERT_EQ(complete_l2cap_packet[i], *minus_eq)
- << "-= test: Dereferenced iterator does not equal expected at index "
- << i;
+ << "-= test: Dereferenced iterator does not equal expected at index " << i;
minus_eq -= 2;
}
}
@@ -146,8 +151,7 @@
minus = minus - static_cast<size_t>(1);
for (size_t i = complete_l2cap_packet.size() - 1; i > 0; i--) {
ASSERT_EQ(complete_l2cap_packet[i], *minus)
- << "- test: Dereferenced iterator does not equal expected at index "
- << i;
+ << "- test: Dereferenced iterator does not equal expected at index " << i;
minus = minus - static_cast<size_t>(1);
}
}
@@ -157,8 +161,7 @@
plus_eq--;
for (size_t i = 0; i < 100; i++) {
plus_eq += i;
- ASSERT_EQ(packet->get_end(), plus_eq)
- << "+= test: Iterator exceeded the upper bound set by get_length()";
+ ASSERT_EQ(packet->get_end(), plus_eq) << "+= test: Iterator exceeded the upper bound set by get_length()";
}
}
@@ -166,9 +169,8 @@
Iterator plus_plus = packet->get_end();
plus_plus--;
for (size_t i = 0; i < 100; i++) {
- ASSERT_EQ(packet->get_end(), ++plus_plus)
- << "Pre-increment test: Iterator exceeded the upper bound set "
- "by get_length()";
+ ASSERT_EQ(packet->get_end(), ++plus_plus) << "Pre-increment test: Iterator exceeded the upper bound set "
+ "by get_length()";
}
}
@@ -176,9 +178,8 @@
Iterator plus_plus = packet->get_end();
plus_plus--;
for (size_t i = 0; i < 100; i++) {
- ASSERT_EQ(packet->get_end(), plus_plus++)
- << "Post-increment test: Iterator exceeded the upper bound set "
- "by get_length()";
+ ASSERT_EQ(packet->get_end(), plus_plus++) << "Post-increment test: Iterator exceeded the upper bound set "
+ "by get_length()";
}
}
@@ -187,8 +188,7 @@
plus--;
for (size_t i = 0; i < 100; i++) {
plus = plus + static_cast<size_t>(i);
- ASSERT_EQ(packet->get_end(), plus)
- << "+ test: Iterator exceeded the upper bound set by get_length()";
+ ASSERT_EQ(packet->get_end(), plus) << "+ test: Iterator exceeded the upper bound set by get_length()";
}
}
@@ -196,9 +196,8 @@
Iterator minus_eq = packet->get_begin();
for (size_t i = 0; i < 100; i++) {
minus_eq -= i;
- ASSERT_EQ(complete_l2cap_packet[0], *minus_eq)
- << "-= test: Iterator is less than the lower bound set by "
- "packet->get_begin()";
+ ASSERT_EQ(complete_l2cap_packet[0], *minus_eq) << "-= test: Iterator is less than the lower bound set by "
+ "packet->get_begin()";
}
}
@@ -224,9 +223,8 @@
Iterator minus = packet->get_begin();
for (size_t i = 0; i < 100; i++) {
minus = minus - static_cast<size_t>(i);
- ASSERT_EQ(complete_l2cap_packet[0], *minus)
- << "- test: Iterator is less than the lower bound set "
- "by packet->get_begin()";
+ ASSERT_EQ(complete_l2cap_packet[0], *minus) << "- test: Iterator is less than the lower bound set "
+ "by packet->get_begin()";
}
}
}; // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/test/l2cap_sdu_test.cc b/vendor_libs/test_vendor_lib/test/l2cap_sdu_test.cc
index 2e6df2c..7aa0ec6 100644
--- a/vendor_libs/test_vendor_lib/test/l2cap_sdu_test.cc
+++ b/vendor_libs/test_vendor_lib/test/l2cap_sdu_test.cc
@@ -25,30 +25,21 @@
namespace test_vendor_lib {
-std::shared_ptr<L2capSdu> packet_1 =
- L2capSdu::L2capSduConstructor(l2cap_test_packet_1);
-std::shared_ptr<L2capSdu> packet_2 =
- L2capSdu::L2capSduConstructor(l2cap_test_packet_2);
-std::shared_ptr<L2capSdu> packet_3 =
- L2capSdu::L2capSduConstructor(l2cap_test_packet_3);
-std::shared_ptr<L2capSdu> packet_4 =
- L2capSdu::L2capSduConstructor(l2cap_test_packet_4);
-std::shared_ptr<L2capSdu> packet_5 =
- L2capSdu::L2capSduConstructor(l2cap_test_packet_5);
-std::shared_ptr<L2capSdu> packet_6 =
- L2capSdu::L2capSduConstructor(l2cap_test_packet_6);
-std::shared_ptr<L2capSdu> packet_7 =
- L2capSdu::L2capSduConstructor(l2cap_test_packet_7);
-std::shared_ptr<L2capSdu> packet_8 =
- L2capSdu::L2capSduConstructor(l2cap_test_packet_8);
-std::shared_ptr<L2capSdu> packet_9 =
- L2capSdu::L2capSduConstructor(l2cap_test_packet_9);
+std::shared_ptr<L2capSdu> packet_1 = L2capSdu::L2capSduConstructor(l2cap_test_packet_1);
+std::shared_ptr<L2capSdu> packet_2 = L2capSdu::L2capSduConstructor(l2cap_test_packet_2);
+std::shared_ptr<L2capSdu> packet_3 = L2capSdu::L2capSduConstructor(l2cap_test_packet_3);
+std::shared_ptr<L2capSdu> packet_4 = L2capSdu::L2capSduConstructor(l2cap_test_packet_4);
+std::shared_ptr<L2capSdu> packet_5 = L2capSdu::L2capSduConstructor(l2cap_test_packet_5);
+std::shared_ptr<L2capSdu> packet_6 = L2capSdu::L2capSduConstructor(l2cap_test_packet_6);
+std::shared_ptr<L2capSdu> packet_7 = L2capSdu::L2capSduConstructor(l2cap_test_packet_7);
+std::shared_ptr<L2capSdu> packet_8 = L2capSdu::L2capSduConstructor(l2cap_test_packet_8);
+std::shared_ptr<L2capSdu> packet_9 = L2capSdu::L2capSduConstructor(l2cap_test_packet_9);
class L2capSduTest : public ::testing::Test {
public:
L2capSduTest(){};
- ~L2capSduTest() = default;
+ ~L2capSduTest() override = default;
}; // L2capSduTest
diff --git a/vendor_libs/test_vendor_lib/test/l2cap_test.cc b/vendor_libs/test_vendor_lib/test/l2cap_test.cc
index f4eea71..b218287 100644
--- a/vendor_libs/test_vendor_lib/test/l2cap_test.cc
+++ b/vendor_libs/test_vendor_lib/test/l2cap_test.cc
@@ -30,13 +30,19 @@
class TestPacket : public HciPacket {
public:
- TestPacket(const std::vector<uint8_t>& packet) { complete_packet_ = packet; }
+ TestPacket(const std::vector<uint8_t>& packet) {
+ complete_packet_ = packet;
+ }
TestPacket() = default;
private:
std::vector<uint8_t> complete_packet_;
- size_t get_length() { return complete_packet_.size(); }
- uint8_t& get_at_index(size_t index) { return complete_packet_[index]; }
+ size_t get_length() {
+ return complete_packet_.size();
+ }
+ uint8_t& get_at_index(size_t index) {
+ return complete_packet_[index];
+ }
};
class L2capTest : public ::testing::Test {
@@ -47,8 +53,7 @@
return L2capSdu::L2capSduBuilder(sdu);
}
- void compare_packets(shared_ptr<HciPacket> expected,
- shared_ptr<HciPacket> received) {
+ void compare_packets(shared_ptr<HciPacket> expected, shared_ptr<HciPacket> received) {
Iterator expected_begin = expected->get_begin();
Iterator expected_end = expected->get_end();
@@ -337,11 +342,10 @@
sdu = l2cap_expected->fragment(16, 0x02, 0x41);
l2cap_received = L2capPacket::assemble(sdu);
- ASSERT_NE(l2cap_received, nullptr)
- << "packet reassembly failed after fragment" << std::endl
- << "Test1: Small Segment request" << std::endl
- << "sdu used: good_sdu" << std::endl
- << "function call: fragment(16, 0x02, 0x41)" << std::endl;
+ ASSERT_NE(l2cap_received, nullptr) << "packet reassembly failed after fragment" << std::endl
+ << "Test1: Small Segment request" << std::endl
+ << "sdu used: good_sdu" << std::endl
+ << "function call: fragment(16, 0x02, 0x41)" << std::endl;
compare_packets(l2cap_expected, l2cap_received);
@@ -374,11 +378,10 @@
sdu = l2cap_expected->fragment(1024, 0x02, 0x41);
l2cap_received = L2capPacket::assemble(sdu);
- ASSERT_NE(l2cap_received, nullptr)
- << "packet reassembly failed after fragment" << std::endl
- << "Test2: Large Segment request" << std::endl
- << "sdu used: l2cap_test_packet[1-9]" << std::endl
- << "function call: fragment(1024, 0x02, 0x41)" << std::endl;
+ ASSERT_NE(l2cap_received, nullptr) << "packet reassembly failed after fragment" << std::endl
+ << "Test2: Large Segment request" << std::endl
+ << "sdu used: l2cap_test_packet[1-9]" << std::endl
+ << "function call: fragment(1024, 0x02, 0x41)" << std::endl;
compare_packets(l2cap_expected, l2cap_received);
@@ -405,11 +408,10 @@
sdu = l2cap_expected->fragment(24, 0x08, 0x41);
l2cap_received = L2capPacket::assemble(sdu);
- ASSERT_NE(l2cap_received, nullptr)
- << "packet reassembly failed after fragment" << std::endl
- << "Test3: Non-zero starting TxSeq" << std::endl
- << "sdu used: good_sdu" << std::endl
- << "function call: fragment(24, 0x08, 0x41)" << std::endl;
+ ASSERT_NE(l2cap_received, nullptr) << "packet reassembly failed after fragment" << std::endl
+ << "Test3: Non-zero starting TxSeq" << std::endl
+ << "sdu used: good_sdu" << std::endl
+ << "function call: fragment(24, 0x08, 0x41)" << std::endl;
compare_packets(l2cap_expected, l2cap_received);
@@ -435,11 +437,10 @@
sdu = l2cap_expected->fragment(16, 0x02, 0x41);
l2cap_received = L2capPacket::assemble(sdu);
- ASSERT_NE(l2cap_received, nullptr)
- << "packet reassembly failed after fragment" << std::endl
- << "Test4: Packet with no payload" << std::endl
- << "sdu used: empty_sdu_payload" << std::endl
- << "function call: fragment(16, 0x02, 0x41)" << std::endl;
+ ASSERT_NE(l2cap_received, nullptr) << "packet reassembly failed after fragment" << std::endl
+ << "Test4: Packet with no payload" << std::endl
+ << "sdu used: empty_sdu_payload" << std::endl
+ << "function call: fragment(16, 0x02, 0x41)" << std::endl;
compare_packets(l2cap_expected, l2cap_received);
@@ -466,11 +467,10 @@
sdu = l2cap_expected->fragment(256, 0x02, 0x41);
l2cap_received = L2capPacket::assemble(sdu);
- ASSERT_NE(l2cap_received, nullptr)
- << "packet reassembly failed after fragment" << std::endl
- << "Test5: Segment size > Payload" << std::endl
- << "sdu used: good_sdu" << std::endl
- << "function call: fragment(256, 0x02, 0x41)" << std::endl;
+ ASSERT_NE(l2cap_received, nullptr) << "packet reassembly failed after fragment" << std::endl
+ << "Test5: Segment size > Payload" << std::endl
+ << "sdu used: good_sdu" << std::endl
+ << "function call: fragment(256, 0x02, 0x41)" << std::endl;
compare_packets(l2cap_expected, l2cap_received);
@@ -502,11 +502,10 @@
sdu = l2cap_expected->fragment(512, 0x02, 0x41);
l2cap_received = L2capPacket::assemble(sdu);
- ASSERT_NE(l2cap_received, nullptr)
- << "packet reassembly failed after fragment" << std::endl
- << "Test6: Small Segment request on large packet" << std::endl
- << "sdu used: l2cap_test_packet_[1-9]" << std::endl
- << "function call: fragment(64, 0x02, 0x41)" << std::endl;
+ ASSERT_NE(l2cap_received, nullptr) << "packet reassembly failed after fragment" << std::endl
+ << "Test6: Small Segment request on large packet" << std::endl
+ << "sdu used: l2cap_test_packet_[1-9]" << std::endl
+ << "function call: fragment(64, 0x02, 0x41)" << std::endl;
compare_packets(l2cap_expected, l2cap_received);
diff --git a/vendor_libs/test_vendor_lib/test/link_layer_socket_device_test.cc b/vendor_libs/test_vendor_lib/test/link_layer_socket_device_test.cc
new file mode 100644
index 0000000..0ddd2fc
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/test/link_layer_socket_device_test.cc
@@ -0,0 +1,306 @@
+/*
+ * Copyright 2016 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 "model/devices/link_layer_socket_device.h"
+
+#include <gtest/gtest.h>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "include/link.h"
+#include "model/setup/async_manager.h"
+#include "packets/link_layer/command_view.h"
+#include "packets/link_layer/link_layer_packet_builder.h"
+#include "packets/link_layer/link_layer_packet_view.h"
+
+std::vector<uint8_t> count = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+};
+
+using test_vendor_lib::packets::CommandBuilder;
+using test_vendor_lib::packets::CommandView;
+using test_vendor_lib::packets::LinkLayerPacketBuilder;
+using test_vendor_lib::packets::LinkLayerPacketView;
+using test_vendor_lib::packets::PacketView;
+using test_vendor_lib::packets::View;
+
+static const size_t kMaxConnections = 300;
+
+namespace test_vendor_lib {
+
+class LinkLayerSocketDeviceTest : public ::testing::Test {
+ public:
+ static const uint16_t kPort = 6123;
+
+ protected:
+ class MockPhyLayer : public PhyLayer {
+ public:
+ MockPhyLayer(const std::function<void(std::shared_ptr<LinkLayerPacketBuilder>)>& on_receive)
+ : PhyLayer(Phy::Type::LOW_ENERGY, 0, [](LinkLayerPacketView) {}), on_receive_(on_receive) {}
+ void Send(const std::shared_ptr<LinkLayerPacketBuilder> packet) override {
+ on_receive_(packet);
+ }
+ void Receive(LinkLayerPacketView) override {}
+ void TimerTick() override {}
+
+ private:
+ std::function<void(std::shared_ptr<LinkLayerPacketBuilder>)> on_receive_;
+ };
+
+ int StartServer() {
+ struct sockaddr_in serv_addr;
+ int fd = socket(AF_INET, SOCK_STREAM, 0);
+ EXPECT_FALSE(fd < 0);
+
+ memset(&serv_addr, 0, sizeof(serv_addr));
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_addr.s_addr = INADDR_ANY;
+ serv_addr.sin_port = htons(kPort);
+ int reuse_flag = 1;
+ EXPECT_FALSE(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse_flag, sizeof(reuse_flag)) < 0);
+ EXPECT_FALSE(bind(fd, (sockaddr*)&serv_addr, sizeof(serv_addr)) < 0);
+
+ listen(fd, 1);
+ return fd;
+ }
+
+ int AcceptConnection(int fd) {
+ return accept(fd, NULL, NULL);
+ }
+
+ void ValidatePacket(size_t index, bool at_server, std::shared_ptr<LinkLayerPacketBuilder> received) {
+ /* Convert the Builder into a View */
+ std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
+ std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
+ received->Serialize(it);
+ LinkLayerPacketView received_view = LinkLayerPacketView::Create(packet_ptr);
+
+ /* Validate received packet */
+ ASSERT_EQ(received_view.GetSourceAddress(), source_);
+ ASSERT_EQ(received_view.GetDestinationAddress(), dest_);
+ ASSERT_EQ(Link::PacketType::COMMAND, received_view.GetType());
+ CommandView command_view = CommandView::GetCommand(received_view);
+ if (at_server) {
+ ASSERT_EQ(client_opcodes_[index], command_view.GetOpcode());
+ } else {
+ ASSERT_EQ(server_opcodes_[index], command_view.GetOpcode());
+ }
+ auto args_itr = command_view.GetData();
+ ASSERT_EQ(args_itr.NumBytesRemaining(), count.size());
+ for (size_t i = 0; i < count.size(); i++) {
+ ASSERT_EQ(*args_itr++, count[i]);
+ }
+ if (at_server) {
+ validated_client_packets_[index]++;
+ } else {
+ validated_server_packets_[index]++;
+ }
+ }
+
+ void SetUp() override {
+ servers_.reserve(kMaxConnections);
+ clients_.reserve(kMaxConnections);
+ socket_fd_ = StartServer();
+
+ async_manager_.WatchFdForNonBlockingReads(socket_fd_, [this](int fd) {
+ int connection_fd = AcceptConnection(fd);
+ ASSERT_GE(connection_fd, 0);
+ size_t index = servers_.size();
+ servers_.emplace_back(connection_fd, Phy::Type::LOW_ENERGY);
+ ASSERT_EQ(servers_.size() - 1, index) << "Race condition";
+ std::shared_ptr<MockPhyLayer> mock_phy = std::make_shared<MockPhyLayer>(
+ [this, index](std::shared_ptr<LinkLayerPacketBuilder> received) { ValidatePacket(index, true, received); });
+ servers_[index].RegisterPhyLayer(mock_phy);
+ });
+ }
+
+ void TearDown() override {
+ async_manager_.StopWatchingFileDescriptor(socket_fd_);
+ close(socket_fd_);
+ }
+
+ int ConnectClient() {
+ int socket_cli_fd = socket(AF_INET, SOCK_STREAM, 0);
+ EXPECT_FALSE(socket_cli_fd < 0);
+
+ struct hostent* server;
+ server = gethostbyname("localhost");
+ EXPECT_FALSE(server == NULL);
+
+ struct sockaddr_in serv_addr;
+ memset((void*)&serv_addr, 0, sizeof(serv_addr));
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_addr.s_addr = INADDR_ANY;
+ serv_addr.sin_port = htons(kPort);
+
+ int result = connect(socket_cli_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
+ EXPECT_FALSE(result < 0);
+
+ EXPECT_GE(socket_cli_fd, 0);
+
+ return socket_cli_fd;
+ }
+
+ void ValidateConnection(size_t pair_id) {
+ ASSERT_GT(clients_.size(), pair_id);
+ ASSERT_GT(servers_.size(), pair_id);
+ }
+
+ size_t CreateConnection() {
+ int fd = ConnectClient();
+ size_t index = clients_.size();
+ clients_.emplace_back(fd, Phy::Type::LOW_ENERGY);
+ std::shared_ptr<MockPhyLayer> mock_phy = std::make_shared<MockPhyLayer>(
+ [this, index](std::shared_ptr<LinkLayerPacketBuilder> received) { ValidatePacket(index, false, received); });
+ clients_[index].RegisterPhyLayer(mock_phy);
+ for (size_t timeout = 10; timeout > 0 && clients_.size() > servers_.size(); timeout--) {
+ sleep(0); // Wait for server to be created
+ }
+ ValidateConnection(index);
+ return index;
+ }
+
+ LinkLayerPacketView NextPacket() {
+ std::shared_ptr<std::vector<uint8_t>> count_shared = std::make_shared<std::vector<uint8_t>>(count);
+ View count_view(count_shared, 0, count_shared->size());
+ PacketView<true> args({count_view});
+ auto builder = CommandBuilder::Create(packet_id_++, args);
+ auto wrapped_command = LinkLayerPacketBuilder::WrapCommand(std::move(builder), source_, dest_);
+ std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
+ std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
+ wrapped_command->Serialize(it);
+ LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
+ return view;
+ }
+
+ void SendFromClient(size_t pair_id) {
+ ASSERT_GT(clients_.size(), pair_id);
+ LinkLayerPacketView view = NextPacket();
+ client_opcodes_[pair_id] = CommandView::GetCommand(view).GetOpcode();
+ clients_[pair_id].IncomingPacket(view);
+ }
+
+ void SendFromServer(size_t pair_id) {
+ ASSERT_GT(servers_.size(), pair_id);
+ LinkLayerPacketView view = NextPacket();
+ server_opcodes_[pair_id] = CommandView::GetCommand(view).GetOpcode();
+ servers_[pair_id].IncomingPacket(view);
+ }
+
+ void ReadFromClient(size_t pair_id) {
+ ASSERT_GT(clients_.size(), pair_id);
+ size_t validated_packets = validated_server_packets_[pair_id];
+ for (size_t tries = 0; tries < 10 && validated_server_packets_[pair_id] == validated_packets; tries++) {
+ clients_[pair_id].TimerTick();
+ }
+ ASSERT_EQ(validated_server_packets_[pair_id], validated_packets + 1);
+ }
+
+ void ReadFromServer(size_t pair_id) {
+ ASSERT_GT(servers_.size(), pair_id);
+ size_t validated_packets = validated_client_packets_[pair_id];
+ for (size_t tries = 0; tries < 10 && validated_client_packets_[pair_id] == validated_packets; tries++) {
+ servers_[pair_id].TimerTick();
+ }
+ ASSERT_EQ(validated_client_packets_[pair_id], validated_packets + 1);
+ }
+
+ private:
+ uint16_t packet_id_{1};
+ AsyncManager async_manager_;
+ int socket_fd_;
+ std::vector<LinkLayerSocketDevice> servers_;
+ std::vector<LinkLayerSocketDevice> clients_;
+ uint16_t server_opcodes_[kMaxConnections]{0};
+ uint16_t client_opcodes_[kMaxConnections]{0};
+ size_t validated_server_packets_[kMaxConnections]{0};
+ size_t validated_client_packets_[kMaxConnections]{0};
+ Address source_{{1, 2, 3, 4, 5, 6}};
+ Address dest_{{6, 5, 4, 3, 2, 1}};
+};
+
+TEST_F(LinkLayerSocketDeviceTest, TestClientFirst) {
+ size_t pair_id = CreateConnection();
+ ASSERT_EQ(pair_id, 0u);
+ ValidateConnection(pair_id);
+
+ SendFromClient(pair_id);
+ ReadFromServer(pair_id);
+}
+
+TEST_F(LinkLayerSocketDeviceTest, TestServerFirst) {
+ size_t pair_id = CreateConnection();
+ ASSERT_EQ(pair_id, 0u);
+
+ SendFromServer(pair_id);
+ ReadFromClient(pair_id);
+}
+
+TEST_F(LinkLayerSocketDeviceTest, TestMultiplePackets) {
+ static const int num_packets = 30;
+ size_t pair_id = CreateConnection();
+ ASSERT_EQ(pair_id, 0u);
+ for (int i = 0; i < num_packets; i++) {
+ SendFromClient(pair_id);
+ SendFromServer(pair_id);
+ ReadFromServer(pair_id);
+ ReadFromClient(pair_id);
+ }
+}
+
+TEST_F(LinkLayerSocketDeviceTest, TestMultipleConnectionsFromServer) {
+ static size_t last_pair_id = -1;
+ size_t pair_id;
+ for (size_t i = 0; i < kMaxConnections; i++) {
+ pair_id = CreateConnection();
+ ASSERT_EQ(pair_id, last_pair_id + 1);
+ last_pair_id = pair_id;
+ SendFromServer(pair_id);
+ ReadFromClient(pair_id);
+ }
+}
+
+TEST_F(LinkLayerSocketDeviceTest, TestMultipleConnectionsFromClient) {
+ for (size_t i = 0; i < kMaxConnections; i++) {
+ size_t pair_id = CreateConnection();
+ ASSERT_EQ(pair_id, i);
+ SendFromClient(pair_id);
+ ReadFromServer(pair_id);
+ }
+}
+
+TEST_F(LinkLayerSocketDeviceTest, TestMultipleConnections) {
+ for (size_t i = 0; i < kMaxConnections; i++) {
+ size_t pair_id = CreateConnection();
+ ASSERT_EQ(pair_id, i);
+ SendFromClient(pair_id);
+ SendFromServer(pair_id);
+ ReadFromClient(pair_id);
+ ReadFromServer(pair_id);
+ }
+}
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/test/packet_builder_test.cc b/vendor_libs/test_vendor_lib/test/packet_builder_test.cc
new file mode 100644
index 0000000..6fab56d
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/test/packet_builder_test.cc
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2018 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 "packets/packet_builder.h"
+
+#include <gtest/gtest.h>
+#include <forward_list>
+#include <memory>
+
+using std::vector;
+
+namespace {
+vector<uint8_t> count_all = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+};
+
+vector<uint8_t> count_1 = {
+ 0x00,
+ 0x01,
+ 0x02,
+};
+
+vector<uint8_t> count_2 = {
+ 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+};
+
+vector<uint8_t> count_3 = {
+ 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+};
+} // namespace
+
+namespace test_vendor_lib {
+namespace packets {
+
+template <bool little_endian>
+class EndianBuilder : public PacketBuilder<little_endian> {
+ public:
+ EndianBuilder(uint8_t byte, uint16_t two_bytes, uint32_t four_bytes, uint64_t eight_bytes)
+ : byte_(byte), two_bytes_(two_bytes), four_bytes_(four_bytes), eight_bytes_(eight_bytes) {}
+ ~EndianBuilder() override = default;
+
+ size_t size() const override {
+ return sizeof(signature_) + sizeof(byte_) + sizeof(two_bytes_) + sizeof(four_bytes_) + sizeof(eight_bytes_);
+ }
+
+ virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
+ std::unique_ptr<std::vector<uint8_t>> packet = std::make_unique<std::vector<uint8_t>>();
+ packet->reserve(size());
+ std::back_insert_iterator<std::vector<uint8_t>> it(*packet);
+ Serialize(it);
+ return packet;
+ }
+
+ void Serialize(
+ std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+ PacketBuilder<little_endian>::insert(signature_, it);
+ PacketBuilder<little_endian>::insert(byte_, it);
+ PacketBuilder<little_endian>::insert(two_bytes_, it);
+ PacketBuilder<little_endian>::insert(four_bytes_, it);
+ PacketBuilder<little_endian>::insert(eight_bytes_, it);
+ }
+
+ private:
+ uint32_t signature_{(little_endian ? 0x03020100 : 0x00010203)};
+ uint8_t byte_;
+ uint16_t two_bytes_;
+ uint32_t four_bytes_;
+ uint64_t eight_bytes_;
+};
+
+class PacketBuilderEndianTest : public ::testing::Test {
+ public:
+ PacketBuilderEndianTest() = default;
+ ~PacketBuilderEndianTest() override = default;
+};
+
+TEST(PacketBuilderEndianTest, insertTest) {
+ EndianBuilder<true> little(0x04, 0x0605, 0x0a090807, 0x1211100f0e0d0c0b);
+ EndianBuilder<false> big(0x04, 0x0506, 0x0708090a, 0x0b0c0d0e0f101112);
+ ASSERT_EQ(*big.FinalPacket(), *little.FinalPacket());
+}
+
+template <typename T>
+class VectorBuilder : public PacketBuilder<true> {
+ public:
+ VectorBuilder(std::vector<uint64_t> vect) {
+ for (uint64_t element : vect) {
+ vect.push_back(static_cast<T>(element));
+ }
+ }
+ ~VectorBuilder() override = default;
+
+ size_t size() const override { return vect_.size() * sizeof(T); }
+
+ virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
+ std::unique_ptr<std::vector<uint8_t>> packet = std::make_unique<std::vector<uint8_t>>();
+ packet->reserve(size());
+ std::back_insert_iterator<std::vector<uint8_t>> it(*packet);
+ Serialize(it);
+ return packet;
+ }
+
+ void Serialize(
+ std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+ PacketBuilder<true>::insert_vector(vect_, it);
+ }
+
+ private:
+ std::vector<T> vect_;
+};
+
+template <typename T>
+class InsertElementsBuilder : public PacketBuilder<true> {
+ public:
+ InsertElementsBuilder(std::vector<uint64_t> vect) {
+ for (uint64_t element : vect) {
+ vect.push_back(static_cast<T>(element));
+ }
+ }
+ ~InsertElementsBuilder() override = default;
+
+ size_t size() const override { return vect_.size() * sizeof(T); }
+
+ virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
+ std::unique_ptr<std::vector<uint8_t>> packet = std::make_unique<std::vector<uint8_t>>();
+ packet->reserve(size());
+ std::back_insert_iterator<std::vector<uint8_t>> it(*packet);
+ Serialize(it);
+ return packet;
+ }
+
+ void Serialize(
+ std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+ for (T elem : vect_) {
+ PacketBuilder<true>::insert(elem, it);
+ }
+ }
+
+ private:
+ std::vector<T> vect_;
+};
+
+std::vector<uint64_t> vector_data{
+ 0x7060504030201000, 0x7161514131211101, 0x7262524232221202, 0x7363534333231303, 0x7464544434241404,
+ 0x7565554535251505, 0x7666564636261606, 0x7767574737271707, 0x7868584838281808,
+};
+
+template <typename T>
+class VectorBuilderTest : public ::testing::Test {
+ public:
+ VectorBuilderTest() = default;
+ ~VectorBuilderTest() override = default;
+
+ void SetUp() override {
+ packet_1_ = std::shared_ptr<VectorBuilder<T>>(new VectorBuilder<T>(vector_data));
+ packet_2_ = std::shared_ptr<InsertElementsBuilder<T>>(new InsertElementsBuilder<T>(vector_data));
+ }
+
+ void TearDown() override {
+ packet_1_.reset();
+ packet_2_.reset();
+ }
+
+ std::shared_ptr<VectorBuilder<T>> packet_1_;
+ std::shared_ptr<InsertElementsBuilder<T>> packet_2_;
+};
+
+using VectorBaseTypes = ::testing::Types<uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, int64_t>;
+TYPED_TEST_CASE(VectorBuilderTest, VectorBaseTypes);
+
+TYPED_TEST(VectorBuilderTest, insertVectorTest) {
+ ASSERT_EQ(*(this->packet_1_->FinalPacket()), *(this->packet_2_->FinalPacket()));
+}
+
+class NestedBuilder : public PacketBuilder<true> {
+ public:
+ ~NestedBuilder() override = default;
+
+ size_t size() const override {
+ size_t payload_size = (payload_ ? payload_->size() : 0);
+ return 1 + payload_size;
+ }
+
+ static std::unique_ptr<NestedBuilder> Create(uint8_t level) {
+ return std::unique_ptr<NestedBuilder>(new NestedBuilder(level));
+ }
+
+ static std::unique_ptr<NestedBuilder> CreateNested(std::unique_ptr<BasePacketBuilder> payload, uint8_t level) {
+ return std::unique_ptr<NestedBuilder>(new NestedBuilder(std::move(payload), level));
+ }
+
+ virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
+ std::unique_ptr<std::vector<uint8_t>> packet = std::make_unique<std::vector<uint8_t>>();
+ packet->reserve(size());
+ std::back_insert_iterator<std::vector<uint8_t>> it(*packet);
+ Serialize(it);
+ return packet;
+ }
+
+ void Serialize(
+ std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+ PacketBuilder<true>::insert(level_, it);
+ if (payload_) {
+ payload_->Serialize(it);
+ }
+ }
+
+ private:
+ std::unique_ptr<BasePacketBuilder> payload_;
+ uint8_t level_;
+
+ NestedBuilder(std::unique_ptr<BasePacketBuilder> inner, uint8_t level) : payload_(std::move(inner)), level_(level) {}
+ NestedBuilder(uint8_t level) : level_(level) {}
+};
+
+class BuilderBuilderTest : public ::testing::Test {};
+
+TEST(BuilderBuilderTest, nestingTest) {
+ std::unique_ptr<BasePacketBuilder> innermost = NestedBuilder::Create(0);
+ std::unique_ptr<BasePacketBuilder> number_1 = NestedBuilder::CreateNested(std::move(innermost), 1);
+ std::unique_ptr<BasePacketBuilder> number_2 = NestedBuilder::CreateNested(std::move(number_1), 2);
+ std::unique_ptr<BasePacketBuilder> number_3 = NestedBuilder::CreateNested(std::move(number_2), 3);
+ std::unique_ptr<BasePacketBuilder> number_4 = NestedBuilder::CreateNested(std::move(number_3), 4);
+ std::unique_ptr<NestedBuilder> number_5 = NestedBuilder::CreateNested(std::move(number_4), 5);
+
+ std::vector<uint8_t> count_down{5, 4, 3, 2, 1, 0};
+ ASSERT_EQ(*number_5->FinalPacket(), count_down);
+}
+} // namespace packets
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/test/packet_stream_unittest.cc b/vendor_libs/test_vendor_lib/test/packet_stream_unittest.cc
index 3908b9e..7481235 100644
--- a/vendor_libs/test_vendor_lib/test/packet_stream_unittest.cc
+++ b/vendor_libs/test_vendor_lib/test/packet_stream_unittest.cc
@@ -48,7 +48,7 @@
CheckSocketpairInit();
}
- ~PacketStreamTest() {
+ ~PacketStreamTest() override {
close(socketpair_fds_[0]);
close(socketpair_fds_[1]);
}
@@ -69,8 +69,7 @@
write(socketpair_fds_[1], &packet[1], packet.size());
// Read the command packet.
- std::unique_ptr<CommandPacket> command =
- packet_stream_.ReceiveCommand(socketpair_fds_[0]);
+ std::unique_ptr<CommandPacket> command = packet_stream_.ReceiveCommand(socketpair_fds_[0]);
const vector<uint8_t> received_payload = command->GetPayload();
@@ -81,8 +80,7 @@
EXPECT_EQ(opcode, command->GetOpcode());
EXPECT_EQ(static_cast<size_t>(payload_size + 1), command->GetPayloadSize());
EXPECT_EQ(payload_size, received_payload[0]);
- for (int i = 0; i < payload_size; ++i)
- EXPECT_EQ(packet[4 + i], received_payload[i + 1]);
+ for (int i = 0; i < payload_size; ++i) EXPECT_EQ(packet[4 + i], received_payload[i + 1]);
}
void CheckedSendEvent(std::unique_ptr<EventPacket> event) {
@@ -108,10 +106,8 @@
EXPECT_EQ(expected_size, sizeof(event_header) + return_parameters_size + 1);
EXPECT_EQ(DATA_TYPE_EVENT, event_header[0]);
EXPECT_EQ(expected_code, event_header[1]);
- EXPECT_EQ(expected_payload_size,
- static_cast<size_t>(return_parameters_size) + 1);
- for (int i = 0; i < return_parameters_size; ++i)
- EXPECT_EQ(expected_payload[i + 1], return_parameters[i]);
+ EXPECT_EQ(expected_payload_size, static_cast<size_t>(return_parameters_size) + 1);
+ for (int i = 0; i < return_parameters_size; ++i) EXPECT_EQ(expected_payload[i + 1], return_parameters[i]);
}
protected:
@@ -147,8 +143,7 @@
TEST_F(PacketStreamTest, SendEvent) {
const vector<uint8_t> return_parameters = {0};
- CheckedSendEvent(
- EventPacket::CreateCommandCompleteEvent(HCI_RESET, return_parameters));
+ CheckedSendEvent(EventPacket::CreateCommandCompleteEvent(HCI_RESET, return_parameters));
}
} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/test/polled_socket_test.cc b/vendor_libs/test_vendor_lib/test/polled_socket_test.cc
new file mode 100644
index 0000000..268093e
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/test/polled_socket_test.cc
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2018 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 "polled_socket.h"
+
+#include <gtest/gtest.h>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace test_vendor_lib {
+namespace net {
+
+class PolledSocketTest : public ::testing::Test {
+ public:
+ static const uint16_t kPort = 6124;
+ static const size_t kBufferSize = 16;
+
+ protected:
+ void SetUp() override {
+ server_.Initialize(kPort);
+ client_.SetServerName("localhost");
+ client_.Initialize(kPort);
+ }
+
+ void TearDown() override {}
+
+ void ConnectClient() {}
+
+ PolledSocketServer server_;
+ PolledSocketClient client_;
+
+ private:
+ std::vector<uint8_t> server_buffer_;
+ std::vector<uint8_t> client_buffer_;
+};
+
+TEST_F(PolledSocketTest, SetUpTearDown) {}
+
+TEST_F(PolledSocketTest, TestOneConnection) {
+ std::vector<uint8_t> tx_buf = {'1', '2', '3'};
+ std::vector<uint8_t> rx_buf(10);
+
+ client_.Send(tx_buf);
+ server_.Receive(3, rx_buf.data());
+ client_.Send(tx_buf);
+ server_.Receive(3, rx_buf.data());
+ EXPECT_EQ(rx_buf.size(), tx_buf.size());
+}
+
+#if 0
+TEST_F(PolledSocketTest, TestRepeatedConnections) {
+ static const int num_connections = 300;
+ for (int i = 0; i < num_connections; i++) {
+ int socket_cli_fd = ConnectClient();
+ WriteFromClient(socket_cli_fd);
+ AwaitServerResponse(socket_cli_fd);
+ close(socket_cli_fd);
+ }
+}
+
+TEST_F(PolledSocketTest, TestMultipleConnections) {
+ static const int num_connections = 300;
+ int socket_cli_fd[num_connections];
+ for (int i = 0; i < num_connections; i++) {
+ socket_cli_fd[i] = ConnectClient();
+ EXPECT_TRUE(socket_cli_fd[i] > 0);
+ WriteFromClient(socket_cli_fd[i]);
+ }
+ for (int i = 0; i < num_connections; i++) {
+ AwaitServerResponse(socket_cli_fd[i]);
+ close(socket_cli_fd[i]);
+ }
+}
+
+#endif
+} // namespace net
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/test/security_manager_unittest.cc b/vendor_libs/test_vendor_lib/test/security_manager_unittest.cc
new file mode 100644
index 0000000..13aab3c
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/test/security_manager_unittest.cc
@@ -0,0 +1,166 @@
+/******************************************************************************
+ *
+ * Copyright 2017 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 <gtest/gtest.h>
+#include <string>
+#include <vector>
+using std::vector;
+
+#include "model/controller/security_manager.h"
+
+namespace {
+const std::string kTestAddr1 = "12:34:56:78:9a:bc";
+const std::string kTestAddr2 = "cb:a9:87:65:43:21";
+const std::string kTestAddr3 = "cb:a9:56:78:9a:bc";
+const std::string kTestAddr4 = "12:34:56:78:9a:bc";
+const vector<uint8_t> kZeros_octets = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+const vector<uint8_t> kTestAddr1_octets = {0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12};
+const vector<uint8_t> kTestKey = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10};
+} // namespace
+
+namespace test_vendor_lib {
+
+class SecurityManagerTest : public ::testing::Test {
+ public:
+ SecurityManagerTest() {}
+ ~SecurityManagerTest() override {}
+};
+
+TEST_F(SecurityManagerTest, WriteKey) {
+ Address btaddr1;
+ Address btaddr2;
+ Address btaddr3;
+ Address btaddr4;
+ SecurityManager sm(3);
+
+ Address::FromString(kTestAddr1, btaddr1);
+ Address::FromString(kTestAddr2, btaddr2);
+ Address::FromString(kTestAddr3, btaddr3);
+ Address::FromString(kTestAddr4, btaddr4);
+
+ EXPECT_EQ(1, sm.WriteKey(btaddr1, kTestKey));
+ EXPECT_EQ(1, sm.WriteKey(btaddr2, kTestKey));
+ EXPECT_EQ(1, sm.WriteKey(btaddr3, kTestKey));
+ // Key storage is full.
+ EXPECT_EQ(0, sm.WriteKey(btaddr4, kTestKey));
+}
+
+TEST_F(SecurityManagerTest, ReadKey) {
+ Address btaddr1;
+ Address btaddr2;
+ Address btaddr3;
+ SecurityManager sm(3);
+
+ Address::FromString(kTestAddr1, btaddr1);
+ Address::FromString(kTestAddr2, btaddr2);
+ Address::FromString(kTestAddr3, btaddr3);
+
+ sm.WriteKey(btaddr1, kTestKey);
+ sm.WriteKey(btaddr2, kTestKey);
+
+ EXPECT_EQ(1, sm.ReadKey(btaddr1));
+ EXPECT_EQ(1, sm.ReadKey(btaddr2));
+ EXPECT_EQ(0, sm.ReadKey(btaddr3));
+}
+
+TEST_F(SecurityManagerTest, ReadAllKeys) {
+ Address btaddr1;
+ Address btaddr2;
+ SecurityManager sm(3);
+
+ EXPECT_EQ(0, sm.ReadAllKeys());
+
+ Address::FromString(kTestAddr1, btaddr1);
+ Address::FromString(kTestAddr2, btaddr1);
+ Address::FromString(kTestAddr3, btaddr1);
+
+ sm.WriteKey(btaddr1, kTestKey);
+
+ EXPECT_EQ(1, sm.ReadAllKeys());
+
+ sm.WriteKey(btaddr2, kTestKey);
+
+ EXPECT_EQ(2, sm.ReadAllKeys());
+}
+
+TEST_F(SecurityManagerTest, DeleteKey) {
+ Address btaddr1;
+ Address btaddr2;
+ Address btaddr3;
+ SecurityManager sm(3);
+
+ Address::FromString(kTestAddr1, btaddr1);
+ Address::FromString(kTestAddr2, btaddr2);
+ Address::FromString(kTestAddr3, btaddr3);
+
+ EXPECT_EQ(0, sm.DeleteKey(btaddr2));
+
+ sm.WriteKey(btaddr1, kTestKey);
+
+ EXPECT_EQ(1, sm.ReadAllKeys());
+
+ EXPECT_EQ(1, sm.DeleteKey(btaddr1));
+
+ EXPECT_EQ(0, sm.ReadAllKeys());
+
+ sm.WriteKey(btaddr1, kTestKey);
+ sm.WriteKey(btaddr2, kTestKey);
+
+ EXPECT_EQ(2, sm.ReadAllKeys());
+
+ EXPECT_EQ(1, sm.DeleteKey(btaddr2));
+
+ EXPECT_EQ(1, sm.ReadAllKeys());
+
+ EXPECT_EQ(0, sm.DeleteKey(btaddr2));
+
+ EXPECT_EQ(1, sm.ReadAllKeys());
+}
+
+TEST_F(SecurityManagerTest, DeleteAllKeys) {
+ Address btaddr1;
+ Address btaddr2;
+ Address btaddr3;
+ SecurityManager sm(3);
+
+ Address::FromString(kTestAddr1, btaddr1);
+ Address::FromString(kTestAddr2, btaddr2);
+ Address::FromString(kTestAddr3, btaddr3);
+
+ EXPECT_EQ(0, sm.DeleteAllKeys());
+
+ sm.WriteKey(btaddr1, kTestKey);
+
+ EXPECT_EQ(1, sm.ReadAllKeys());
+
+ EXPECT_EQ(1, sm.DeleteAllKeys());
+
+ EXPECT_EQ(0, sm.ReadAllKeys());
+
+ sm.WriteKey(btaddr1, kTestKey);
+ sm.WriteKey(btaddr2, kTestKey);
+
+ EXPECT_EQ(2, sm.ReadAllKeys());
+
+ EXPECT_EQ(2, sm.DeleteAllKeys());
+
+ EXPECT_EQ(0, sm.ReadAllKeys());
+}
+
+} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/types/Android.bp b/vendor_libs/test_vendor_lib/types/Android.bp
new file mode 100644
index 0000000..07198e9
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/types/Android.bp
@@ -0,0 +1,41 @@
+// Bluetooth types
+cc_library_headers {
+ name: "libbt-rootcanal-types-header",
+ export_include_dirs: ["./"],
+ vendor_available: true,
+ host_supported: true,
+}
+
+cc_library_static {
+ name: "libbt-rootcanal-types",
+ vendor_available: true,
+ defaults: ["fluoride_types_defaults"],
+ cflags: [
+ /* we export all classes, so change default visibility, instead of having EXPORT_SYMBOL on each class*/
+ "-fvisibility=default",
+ ],
+ host_supported: true,
+ srcs: [
+ "class_of_device.cc",
+ "address.cc",
+ "bluetooth/uuid.cc",
+ ],
+ header_libs: ["libbt-rootcanal-types-header"],
+ export_header_lib_headers: ["libbt-rootcanal-types-header"],
+}
+
+// ========================================================
+cc_test {
+ name: "rootcanal-test_types",
+ test_suites: ["device-tests"],
+ defaults: ["fluoride_defaults"],
+ host_supported: true,
+ srcs: [
+ "test/class_of_device_unittest.cc",
+ "test/address_unittest.cc",
+ "test/bluetooth/uuid_unittest.cc",
+ ],
+ static_libs: [
+ "libbt-rootcanal-types",
+ ],
+}
diff --git a/vendor_libs/test_vendor_lib/types/BUILD.gn b/vendor_libs/test_vendor_lib/types/BUILD.gn
new file mode 100644
index 0000000..68f76e3
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/types/BUILD.gn
@@ -0,0 +1,62 @@
+#
+# Copyright 2017 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("types") {
+ cflags = [
+ "-fvisibility=default",
+ ]
+
+ sources = [
+ "bluetooth/uuid.cc",
+ "le_address.cc",
+ "address.cc",
+ ]
+
+ include_dirs = [
+ "//",
+ ]
+
+ deps = [
+ "//third_party/libchrome:base",
+ ]
+}
+
+executable("types_unittests") {
+ testonly = true
+ sources = [
+ "test/address_unittest.cc",
+ "test/bluetooth/uuid_unittest.cc",
+ ]
+
+ include_dirs = [
+ "//",
+ ]
+
+ libs = [
+ "-ldl",
+ "-lpthread",
+ "-lresolv",
+ "-lrt",
+ "-lz",
+ "-latomic",
+ ]
+
+ deps = [
+ "//types",
+ "//third_party/googletest:gmock_main",
+ "//third_party/libchrome:base",
+ ]
+}
diff --git a/vendor_libs/test_vendor_lib/types/address.cc b/vendor_libs/test_vendor_lib/types/address.cc
new file mode 100644
index 0000000..b3c1db4
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/types/address.cc
@@ -0,0 +1,71 @@
+/******************************************************************************
+ *
+ * Copyright 2017 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 "address.h"
+
+#include <base/strings/string_split.h>
+#include <base/strings/stringprintf.h>
+#include <stdint.h>
+#include <algorithm>
+#include <vector>
+
+static_assert(sizeof(Address) == 6, "Address must be 6 bytes long!");
+
+const Address Address::kAny{{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}};
+const Address Address::kEmpty{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
+
+Address::Address(const uint8_t (&addr)[6]) {
+ std::copy(addr, addr + kLength, address);
+};
+
+std::string Address::ToString() const {
+ return base::StringPrintf("%02x:%02x:%02x:%02x:%02x:%02x", address[5], address[4], address[3], address[2], address[1],
+ address[0]);
+}
+
+bool Address::FromString(const std::string& from, Address& to) {
+ Address new_addr;
+ if (from.length() != 17) return false;
+
+ std::vector<std::string> byte_tokens = base::SplitString(from, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+
+ if (byte_tokens.size() != 6) return false;
+
+ for (int i = 0; i < 6; i++) {
+ const auto& token = byte_tokens[i];
+
+ if (token.length() != 2) return false;
+
+ char* temp = nullptr;
+ new_addr.address[5 - i] = strtol(token.c_str(), &temp, 16);
+ if (*temp != '\0') return false;
+ }
+
+ to = new_addr;
+ return true;
+}
+
+size_t Address::FromOctets(const uint8_t* from) {
+ std::copy(from, from + kLength, address);
+ return kLength;
+};
+
+bool Address::IsValidAddress(const std::string& address) {
+ Address tmp;
+ return Address::FromString(address, tmp);
+}
diff --git a/vendor_libs/test_vendor_lib/types/address.h b/vendor_libs/test_vendor_lib/types/address.h
new file mode 100644
index 0000000..1aa8c97
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/types/address.h
@@ -0,0 +1,76 @@
+/******************************************************************************
+ *
+ * Copyright 2017 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>
+
+/** Bluetooth Address */
+class Address final {
+ public:
+ static constexpr unsigned int kLength = 6;
+
+ uint8_t address[kLength];
+
+ Address() = default;
+ Address(const uint8_t (&addr)[6]);
+
+ bool operator<(const Address& rhs) const {
+ return (std::memcmp(address, rhs.address, sizeof(address)) < 0);
+ }
+ bool operator==(const Address& rhs) const {
+ return (std::memcmp(address, rhs.address, sizeof(address)) == 0);
+ }
+ bool operator>(const Address& rhs) const {
+ return (rhs < *this);
+ }
+ bool operator<=(const Address& rhs) const {
+ return !(*this > rhs);
+ }
+ bool operator>=(const Address& rhs) const {
+ return !(*this < rhs);
+ }
+ bool operator!=(const Address& rhs) const {
+ return !(*this == rhs);
+ }
+
+ bool IsEmpty() const {
+ return *this == kEmpty;
+ }
+
+ std::string ToString() const;
+
+ // Converts |string| to Address and places it in |to|. If |from| does
+ // not represent a Bluetooth address, |to| is not modified and this function
+ // returns false. Otherwise, it returns true.
+ static bool FromString(const std::string& from, Address& to);
+
+ // Copies |from| raw Bluetooth address octets to the local object.
+ // Returns the number of copied octets - should be always Address::kLength
+ size_t FromOctets(const uint8_t* from);
+
+ static bool IsValidAddress(const std::string& address);
+
+ static const Address kEmpty; // 00:00:00:00:00:00
+ static const Address kAny; // FF:FF:FF:FF:FF:FF
+};
+
+inline std::ostream& operator<<(std::ostream& os, const Address& a) {
+ os << a.ToString();
+ return os;
+}
diff --git a/vendor_libs/test_vendor_lib/types/bluetooth/uuid.cc b/vendor_libs/test_vendor_lib/types/bluetooth/uuid.cc
new file mode 100644
index 0000000..7739f41
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/types/bluetooth/uuid.cc
@@ -0,0 +1,174 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2017 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 "uuid.h"
+
+#include <base/rand_util.h>
+#include <base/strings/stringprintf.h>
+#include <algorithm>
+
+namespace bluetooth {
+
+static_assert(sizeof(Uuid) == 16, "Uuid must be 16 bytes long!");
+
+using UUID128Bit = Uuid::UUID128Bit;
+
+const Uuid Uuid::kEmpty = Uuid::From128BitBE(UUID128Bit{{0x00}});
+
+namespace {
+constexpr Uuid kBase = Uuid::From128BitBE(
+ UUID128Bit{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}});
+} // namespace
+
+size_t Uuid::GetShortestRepresentationSize() const {
+ if (memcmp(uu.data() + kNumBytes32, kBase.uu.data() + kNumBytes32, kNumBytes128 - kNumBytes32) != 0) {
+ return kNumBytes128;
+ }
+
+ if (uu[0] == 0 && uu[1] == 0) return kNumBytes16;
+
+ return kNumBytes32;
+}
+
+bool Uuid::Is16Bit() const {
+ return GetShortestRepresentationSize() == kNumBytes16;
+}
+
+uint16_t Uuid::As16Bit() const {
+ return (((uint16_t)uu[2]) << 8) + uu[3];
+}
+
+uint32_t Uuid::As32Bit() const {
+ return (((uint32_t)uu[0]) << 24) + (((uint32_t)uu[1]) << 16) + (((uint32_t)uu[2]) << 8) + uu[3];
+}
+
+Uuid Uuid::FromString(const std::string& uuid, bool* is_valid) {
+ if (is_valid) *is_valid = false;
+ Uuid ret = kBase;
+
+ if (uuid.empty()) return ret;
+
+ uint8_t* p = ret.uu.data();
+ if (uuid.size() == kString128BitLen) {
+ if (uuid[8] != '-' || uuid[13] != '-' || uuid[18] != '-' || uuid[23] != '-') {
+ return ret;
+ }
+
+ int c;
+ int rc = sscanf(uuid.c_str(),
+ "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx"
+ "-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%n",
+ &p[0], &p[1], &p[2], &p[3], &p[4], &p[5], &p[6], &p[7], &p[8], &p[9], &p[10], &p[11], &p[12],
+ &p[13], &p[14], &p[15], &c);
+ if (rc != 16) return ret;
+ if (c != kString128BitLen) return ret;
+
+ if (is_valid) *is_valid = true;
+ } else if (uuid.size() == 8) {
+ int c;
+ int rc = sscanf(uuid.c_str(), "%02hhx%02hhx%02hhx%02hhx%n", &p[0], &p[1], &p[2], &p[3], &c);
+ if (rc != 4) return ret;
+ if (c != 8) return ret;
+
+ if (is_valid) *is_valid = true;
+ } else if (uuid.size() == 4) {
+ int c;
+ int rc = sscanf(uuid.c_str(), "%02hhx%02hhx%n", &p[2], &p[3], &c);
+ if (rc != 2) return ret;
+ if (c != 4) return ret;
+
+ if (is_valid) *is_valid = true;
+ }
+
+ return ret;
+}
+
+Uuid Uuid::From16Bit(uint16_t uuid16) {
+ Uuid u = kBase;
+
+ u.uu[2] = (uint8_t)((0xFF00 & uuid16) >> 8);
+ u.uu[3] = (uint8_t)(0x00FF & uuid16);
+ return u;
+}
+
+Uuid Uuid::From32Bit(uint32_t uuid32) {
+ Uuid u = kBase;
+
+ u.uu[0] = (uint8_t)((0xFF000000 & uuid32) >> 24);
+ u.uu[1] = (uint8_t)((0x00FF0000 & uuid32) >> 16);
+ u.uu[2] = (uint8_t)((0x0000FF00 & uuid32) >> 8);
+ u.uu[3] = (uint8_t)(0x000000FF & uuid32);
+ return u;
+}
+
+Uuid Uuid::From128BitBE(const uint8_t* uuid) {
+ UUID128Bit tmp;
+ memcpy(tmp.data(), uuid, kNumBytes128);
+ return From128BitBE(tmp);
+}
+
+Uuid Uuid::From128BitLE(const UUID128Bit& uuid) {
+ Uuid u;
+ std::reverse_copy(uuid.data(), uuid.data() + kNumBytes128, u.uu.begin());
+ return u;
+}
+
+Uuid Uuid::From128BitLE(const uint8_t* uuid) {
+ UUID128Bit tmp;
+ memcpy(tmp.data(), uuid, kNumBytes128);
+ return From128BitLE(tmp);
+}
+
+const UUID128Bit Uuid::To128BitLE() const {
+ UUID128Bit le;
+ std::reverse_copy(uu.data(), uu.data() + kNumBytes128, le.begin());
+ return le;
+}
+
+const UUID128Bit& Uuid::To128BitBE() const {
+ return uu;
+}
+
+Uuid Uuid::GetRandom() {
+ Uuid uuid;
+ base::RandBytes(uuid.uu.data(), uuid.uu.size());
+ return uuid;
+}
+
+bool Uuid::IsEmpty() const {
+ return *this == kEmpty;
+}
+
+bool Uuid::operator<(const Uuid& rhs) const {
+ return std::lexicographical_compare(uu.begin(), uu.end(), rhs.uu.begin(), rhs.uu.end());
+}
+
+bool Uuid::operator==(const Uuid& rhs) const {
+ return uu == rhs.uu;
+}
+
+bool Uuid::operator!=(const Uuid& rhs) const {
+ return uu != rhs.uu;
+}
+
+std::string Uuid::ToString() const {
+ return base::StringPrintf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", uu[0], uu[1], uu[2],
+ uu[3], uu[4], uu[5], uu[6], uu[7], uu[8], uu[9], uu[10], uu[11], uu[12], uu[13], uu[14],
+ uu[15]);
+}
+} // namespace bluetooth
\ No newline at end of file
diff --git a/vendor_libs/test_vendor_lib/types/bluetooth/uuid.h b/vendor_libs/test_vendor_lib/types/bluetooth/uuid.h
new file mode 100644
index 0000000..58a7da2
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/types/bluetooth/uuid.h
@@ -0,0 +1,139 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2017 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 <stdint.h>
+#include <array>
+#include <string>
+
+namespace bluetooth {
+
+// This class is representing Bluetooth UUIDs across whole stack.
+// Here are some general endianness rules:
+// 1. UUID is internally kept as as Big Endian.
+// 2. Bytes representing UUID coming from upper layers, Java or Binder, are Big
+// Endian.
+// 3. Bytes representing UUID coming from lower layer, HCI packets, are Little
+// Endian.
+// 4. UUID in storage is always string.
+class Uuid final {
+ public:
+ static constexpr size_t kNumBytes128 = 16;
+ static constexpr size_t kNumBytes32 = 4;
+ static constexpr size_t kNumBytes16 = 2;
+
+ static constexpr size_t kString128BitLen = 36;
+
+ static const Uuid kEmpty; // 00000000-0000-0000-0000-000000000000
+
+ using UUID128Bit = std::array<uint8_t, kNumBytes128>;
+
+ Uuid() = default;
+
+ // Creates and returns a random 128-bit UUID.
+ static Uuid GetRandom();
+
+ // Returns the shortest possible representation of this UUID in bytes. Either
+ // kNumBytes16, kNumBytes32, or kNumBytes128
+ size_t GetShortestRepresentationSize() const;
+
+ // Returns true if this UUID can be represented as 16 bit.
+ bool Is16Bit() const;
+
+ // Returns 16 bit Little Endian representation of this UUID. Use
+ // GetShortestRepresentationSize() or Is16Bit() before using this method.
+ uint16_t As16Bit() const;
+
+ // Returns 32 bit Little Endian representation of this UUID. Use
+ // GetShortestRepresentationSize() before using this method.
+ uint32_t As32Bit() const;
+
+ // Converts string representing 128, 32, or 16 bit UUID in
+ // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, xxxxxxxx, or xxxx format to UUID. If
+ // set, optional is_valid parameter will be set to true if conversion is
+ // successfull, false otherwise.
+ static Uuid FromString(const std::string& uuid, bool* is_valid = nullptr);
+
+ // Converts 16bit Little Endian representation of UUID to UUID
+ static Uuid From16Bit(uint16_t uuid16bit);
+
+ // Converts 32bit Little Endian representation of UUID to UUID
+ static Uuid From32Bit(uint32_t uuid32bit);
+
+ // Converts 128 bit Big Endian array representing UUID to UUID.
+ static constexpr Uuid From128BitBE(const UUID128Bit& uuid) {
+ Uuid u(uuid);
+ return u;
+ }
+
+ // Converts 128 bit Big Endian array representing UUID to UUID. |uuid| points
+ // to beginning of array.
+ static Uuid From128BitBE(const uint8_t* uuid);
+
+ // Converts 128 bit Little Endian array representing UUID to UUID.
+ static Uuid From128BitLE(const UUID128Bit& uuid);
+
+ // Converts 128 bit Little Endian array representing UUID to UUID. |uuid|
+ // points to beginning of array.
+ static Uuid From128BitLE(const uint8_t* uuid);
+
+ // Returns 128 bit Little Endian representation of this UUID
+ const UUID128Bit To128BitLE() const;
+
+ // Returns 128 bit Big Endian representation of this UUID
+ const UUID128Bit& To128BitBE() const;
+
+ // Returns string representing this UUID in
+ // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format, lowercase.
+ std::string ToString() const;
+
+ // Returns true if this UUID is equal to kEmpty
+ bool IsEmpty() const;
+
+ bool operator<(const Uuid& rhs) const;
+ bool operator==(const Uuid& rhs) const;
+ bool operator!=(const Uuid& rhs) const;
+
+ private:
+ constexpr Uuid(const UUID128Bit& val) : uu{val} {};
+
+ // Network-byte-ordered ID (Big Endian).
+ UUID128Bit uu;
+};
+} // namespace bluetooth
+
+inline std::ostream& operator<<(std::ostream& os, const bluetooth::Uuid& a) {
+ os << a.ToString();
+ return os;
+}
+
+// Custom std::hash specialization so that bluetooth::UUID can be used as a key
+// in std::unordered_map.
+namespace std {
+
+template <>
+struct hash<bluetooth::Uuid> {
+ std::size_t operator()(const bluetooth::Uuid& key) const {
+ const auto& uuid_bytes = key.To128BitBE();
+ std::hash<std::string> hash_fn;
+ return hash_fn(std::string(reinterpret_cast<const char*>(uuid_bytes.data()), uuid_bytes.size()));
+ }
+};
+
+} // namespace std
diff --git a/vendor_libs/test_vendor_lib/types/class_of_device.cc b/vendor_libs/test_vendor_lib/types/class_of_device.cc
new file mode 100644
index 0000000..c5f1c3f
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/types/class_of_device.cc
@@ -0,0 +1,75 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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 "class_of_device.h"
+
+#include <base/strings/string_split.h>
+#include <base/strings/stringprintf.h>
+#include <stdint.h>
+#include <algorithm>
+#include <vector>
+
+static_assert(sizeof(ClassOfDevice) == ClassOfDevice::kLength, "ClassOfDevice must be 3 bytes long!");
+
+ClassOfDevice::ClassOfDevice(const uint8_t (&class_of_device)[kLength]) {
+ std::copy(class_of_device, class_of_device + kLength, cod);
+};
+
+std::string ClassOfDevice::ToString() const {
+ return base::StringPrintf("%03x-%01x-%02x", (static_cast<uint16_t>(cod[2]) << 4) | cod[1] >> 4, cod[1] & 0x0f,
+ cod[0]);
+}
+
+bool ClassOfDevice::FromString(const std::string& from, ClassOfDevice& to) {
+ ClassOfDevice new_cod;
+ if (from.length() != 8) return false;
+
+ std::vector<std::string> byte_tokens = base::SplitString(from, "-", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+
+ if (byte_tokens.size() != 3) return false;
+ if (byte_tokens[0].length() != 3) return false;
+ if (byte_tokens[1].length() != 1) return false;
+ if (byte_tokens[2].length() != 2) return false;
+
+ uint16_t values[3];
+
+ for (size_t i = 0; i < kLength; i++) {
+ const auto& token = byte_tokens[i];
+
+ char* temp = nullptr;
+ values[i] = strtol(token.c_str(), &temp, 16);
+ if (*temp != '\0') return false;
+ }
+
+ new_cod.cod[0] = values[2];
+ new_cod.cod[1] = values[1] | ((values[0] & 0xf) << 4);
+ new_cod.cod[2] = values[0] >> 4;
+
+ to = new_cod;
+ return true;
+}
+
+size_t ClassOfDevice::FromOctets(const uint8_t* from) {
+ std::copy(from, from + kLength, cod);
+ return kLength;
+};
+
+bool ClassOfDevice::IsValid(const std::string& cod) {
+ ClassOfDevice tmp;
+ return ClassOfDevice::FromString(cod, tmp);
+}
diff --git a/vendor_libs/test_vendor_lib/types/class_of_device.h b/vendor_libs/test_vendor_lib/types/class_of_device.h
new file mode 100644
index 0000000..8c2ab37
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/types/class_of_device.h
@@ -0,0 +1,54 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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>
+
+/** Bluetooth Class of Device */
+class ClassOfDevice final {
+ public:
+ static constexpr unsigned int kLength = 3;
+
+ uint8_t cod[kLength];
+
+ ClassOfDevice() = default;
+ ClassOfDevice(const uint8_t (&class_of_device)[kLength]);
+
+ bool operator==(const ClassOfDevice& rhs) const {
+ return (std::memcmp(cod, rhs.cod, sizeof(cod)) == 0);
+ }
+
+ std::string ToString() const;
+
+ // Converts |string| to ClassOfDevice and places it in |to|. If |from| does
+ // not represent a Class of Device, |to| is not modified and this function
+ // returns false. Otherwise, it returns true.
+ static bool FromString(const std::string& from, ClassOfDevice& to);
+
+ // Copies |from| raw Class of Device octets to the local object.
+ // Returns the number of copied octets (always ClassOfDevice::kLength)
+ size_t FromOctets(const uint8_t* from);
+
+ static bool IsValid(const std::string& class_of_device);
+};
+
+inline std::ostream& operator<<(std::ostream& os, const ClassOfDevice& c) {
+ os << c.ToString();
+ return os;
+}
diff --git a/vendor_libs/test_vendor_lib/types/test/address_unittest.cc b/vendor_libs/test_vendor_lib/types/test/address_unittest.cc
new file mode 100644
index 0000000..65fd26d
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/types/test/address_unittest.cc
@@ -0,0 +1,197 @@
+/******************************************************************************
+ *
+ * Copyright 2017 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 <gtest/gtest.h>
+
+#include "address.h"
+
+static const char* test_addr = "bc:9a:78:56:34:12";
+static const char* test_addr2 = "21:43:65:87:a9:cb";
+
+TEST(AddressUnittest, test_constructor_array) {
+ Address bdaddr({0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc});
+
+ ASSERT_EQ(0x12, bdaddr.address[0]);
+ ASSERT_EQ(0x34, bdaddr.address[1]);
+ ASSERT_EQ(0x56, bdaddr.address[2]);
+ ASSERT_EQ(0x78, bdaddr.address[3]);
+ ASSERT_EQ(0x9A, bdaddr.address[4]);
+ ASSERT_EQ(0xBC, bdaddr.address[5]);
+
+ std::string ret = bdaddr.ToString();
+
+ ASSERT_STREQ(test_addr, ret.c_str());
+}
+
+TEST(AddressUnittest, test_is_empty) {
+ Address empty;
+ Address::FromString("00:00:00:00:00:00", empty);
+ ASSERT_TRUE(empty.IsEmpty());
+
+ Address not_empty;
+ Address::FromString("00:00:00:00:00:01", not_empty);
+ ASSERT_FALSE(not_empty.IsEmpty());
+}
+
+TEST(AddressUnittest, test_to_from_str) {
+ Address bdaddr;
+ Address::FromString(test_addr, bdaddr);
+
+ ASSERT_EQ(0x12, bdaddr.address[0]);
+ ASSERT_EQ(0x34, bdaddr.address[1]);
+ ASSERT_EQ(0x56, bdaddr.address[2]);
+ ASSERT_EQ(0x78, bdaddr.address[3]);
+ ASSERT_EQ(0x9A, bdaddr.address[4]);
+ ASSERT_EQ(0xBC, bdaddr.address[5]);
+
+ std::string ret = bdaddr.ToString();
+
+ ASSERT_STREQ(test_addr, ret.c_str());
+}
+
+TEST(AddressUnittest, test_from_octets) {
+ static const uint8_t test_addr_array[] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc};
+
+ Address bdaddr;
+ size_t expected_result = Address::kLength;
+ ASSERT_EQ(expected_result, bdaddr.FromOctets(test_addr_array));
+
+ ASSERT_EQ(0x12, bdaddr.address[0]);
+ ASSERT_EQ(0x34, bdaddr.address[1]);
+ ASSERT_EQ(0x56, bdaddr.address[2]);
+ ASSERT_EQ(0x78, bdaddr.address[3]);
+ ASSERT_EQ(0x9A, bdaddr.address[4]);
+ ASSERT_EQ(0xBC, bdaddr.address[5]);
+
+ std::string ret = bdaddr.ToString();
+
+ ASSERT_STREQ(test_addr, ret.c_str());
+}
+
+TEST(AddressTest, test_equals) {
+ Address bdaddr1;
+ Address bdaddr2;
+ Address bdaddr3;
+ Address::FromString(test_addr, bdaddr1);
+ Address::FromString(test_addr, bdaddr2);
+ EXPECT_TRUE(bdaddr1 == bdaddr2);
+ EXPECT_FALSE(bdaddr1 != bdaddr2);
+ EXPECT_TRUE(bdaddr1 == bdaddr1);
+ EXPECT_FALSE(bdaddr1 != bdaddr1);
+
+ Address::FromString(test_addr2, bdaddr3);
+ EXPECT_FALSE(bdaddr2 == bdaddr3);
+ EXPECT_TRUE(bdaddr2 != bdaddr3);
+}
+
+TEST(AddressTest, test_less_than) {
+ Address bdaddr1;
+ Address bdaddr2;
+ Address bdaddr3;
+ Address::FromString(test_addr, bdaddr1);
+ Address::FromString(test_addr, bdaddr2);
+ EXPECT_FALSE(bdaddr1 < bdaddr2);
+ EXPECT_FALSE(bdaddr1 < bdaddr1);
+
+ Address::FromString(test_addr2, bdaddr3);
+ EXPECT_TRUE(bdaddr2 < bdaddr3);
+ EXPECT_FALSE(bdaddr3 < bdaddr2);
+}
+
+TEST(AddressTest, test_more_than) {
+ Address bdaddr1;
+ Address bdaddr2;
+ Address bdaddr3;
+ Address::FromString(test_addr, bdaddr1);
+ Address::FromString(test_addr, bdaddr2);
+ EXPECT_FALSE(bdaddr1 > bdaddr2);
+ EXPECT_FALSE(bdaddr1 > bdaddr1);
+
+ Address::FromString(test_addr2, bdaddr3);
+ EXPECT_FALSE(bdaddr2 > bdaddr3);
+ EXPECT_TRUE(bdaddr3 > bdaddr2);
+}
+
+TEST(AddressTest, test_less_than_or_equal) {
+ Address bdaddr1;
+ Address bdaddr2;
+ Address bdaddr3;
+ Address::FromString(test_addr, bdaddr1);
+ Address::FromString(test_addr, bdaddr2);
+ EXPECT_TRUE(bdaddr1 <= bdaddr2);
+ EXPECT_TRUE(bdaddr1 <= bdaddr1);
+
+ Address::FromString(test_addr2, bdaddr3);
+ EXPECT_TRUE(bdaddr2 <= bdaddr3);
+ EXPECT_FALSE(bdaddr3 <= bdaddr2);
+}
+
+TEST(AddressTest, test_more_than_or_equal) {
+ Address bdaddr1;
+ Address bdaddr2;
+ Address bdaddr3;
+ Address::FromString(test_addr, bdaddr1);
+ Address::FromString(test_addr, bdaddr2);
+ EXPECT_TRUE(bdaddr1 >= bdaddr2);
+ EXPECT_TRUE(bdaddr1 >= bdaddr1);
+
+ Address::FromString(test_addr2, bdaddr3);
+ EXPECT_FALSE(bdaddr2 >= bdaddr3);
+ EXPECT_TRUE(bdaddr3 >= bdaddr2);
+}
+
+TEST(AddressTest, test_copy) {
+ Address bdaddr1;
+ Address bdaddr2;
+ Address::FromString(test_addr, bdaddr1);
+ bdaddr2 = bdaddr1;
+
+ EXPECT_TRUE(bdaddr1 == bdaddr2);
+}
+
+TEST(AddressTest, IsValidAddress) {
+ EXPECT_FALSE(Address::IsValidAddress(""));
+ EXPECT_FALSE(Address::IsValidAddress("000000000000"));
+ EXPECT_FALSE(Address::IsValidAddress("00:00:00:00:0000"));
+ EXPECT_FALSE(Address::IsValidAddress("00:00:00:00:00:0"));
+ EXPECT_FALSE(Address::IsValidAddress("00:00:00:00:00:0;"));
+ EXPECT_TRUE(Address::IsValidAddress("00:00:00:00:00:00"));
+ EXPECT_TRUE(Address::IsValidAddress("AB:cd:00:00:00:00"));
+ EXPECT_FALSE(Address::IsValidAddress("aB:cD:eF:Gh:iJ:Kl"));
+}
+
+TEST(AddressTest, BdAddrFromString) {
+ Address addr;
+ memset(&addr, 0, sizeof(addr));
+
+ EXPECT_TRUE(Address::FromString("00:00:00:00:00:00", addr));
+ const Address result0 = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
+ EXPECT_EQ(0, memcmp(&addr, &result0, sizeof(addr)));
+
+ EXPECT_TRUE(Address::FromString("ab:01:4C:d5:21:9f", addr));
+ const Address result1 = {{0x9f, 0x21, 0xd5, 0x4c, 0x01, 0xab}};
+ EXPECT_EQ(0, memcmp(&addr, &result1, sizeof(addr)));
+}
+
+TEST(AddressTest, BdAddrFromStringToStringEquivalent) {
+ std::string address = "c1:c2:c3:d1:d2:d3";
+ Address addr;
+
+ EXPECT_TRUE(Address::FromString(address, addr));
+ EXPECT_EQ(addr.ToString(), address);
+}
diff --git a/vendor_libs/test_vendor_lib/types/test/bluetooth/uuid_unittest.cc b/vendor_libs/test_vendor_lib/types/test/bluetooth/uuid_unittest.cc
new file mode 100644
index 0000000..be2ef10
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/types/test/bluetooth/uuid_unittest.cc
@@ -0,0 +1,155 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2017 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 <bluetooth/uuid.h>
+#include <gtest/gtest.h>
+
+using bluetooth::Uuid;
+
+static const Uuid ONES = Uuid::From128BitBE(
+ Uuid::UUID128Bit{{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}});
+
+static const Uuid SEQUENTIAL = Uuid::From128BitBE(
+ Uuid::UUID128Bit{{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89}});
+
+constexpr Uuid kBase = Uuid::From128BitBE(
+ Uuid::UUID128Bit{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}});
+
+TEST(UuidTest, IsEmpty) {
+ EXPECT_TRUE(Uuid::kEmpty.IsEmpty());
+ EXPECT_FALSE(kBase.IsEmpty());
+}
+
+TEST(UuidTest, GetShortestRepresentationSize) {
+ EXPECT_TRUE(Uuid::kNumBytes16 == kBase.GetShortestRepresentationSize());
+ EXPECT_TRUE(Uuid::kNumBytes32 == Uuid::From32Bit(0x01234567).GetShortestRepresentationSize());
+ EXPECT_TRUE(Uuid::kNumBytes128 == Uuid::kEmpty.GetShortestRepresentationSize());
+}
+
+TEST(UuidTest, As16Bit) {
+ // Even though this is is not 16bit UUID, we should be able to get proper bits
+ EXPECT_EQ((uint16_t)0x1111, ONES.As16Bit());
+ EXPECT_EQ((uint16_t)0x4567, SEQUENTIAL.As16Bit());
+ EXPECT_EQ((uint16_t)0x0000, kBase.As16Bit());
+}
+
+TEST(UuidTest, As32Bit) {
+ // Even though this is is not 32bit UUID, we should be able to get proper bits
+ EXPECT_EQ((uint32_t)0x11111111, ONES.As32Bit());
+ EXPECT_EQ((uint32_t)0x01234567, SEQUENTIAL.As32Bit());
+ EXPECT_EQ((uint32_t)0x00000000, kBase.As32Bit());
+ EXPECT_EQ((uint32_t)0x12345678, Uuid::From32Bit(0x12345678).As32Bit());
+}
+
+TEST(UuidTest, Is16Bit) {
+ EXPECT_FALSE(ONES.Is16Bit());
+ EXPECT_FALSE(SEQUENTIAL.Is16Bit());
+ EXPECT_TRUE(kBase.Is16Bit());
+ EXPECT_TRUE(Uuid::FromString("1ae8").Is16Bit());
+}
+
+TEST(UuidTest, From16Bit) {
+ EXPECT_EQ(Uuid::From16Bit(0x0000), kBase);
+
+ const uint8_t u2[] = {0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb};
+ Uuid uuid = Uuid::From16Bit(0x0001);
+ EXPECT_TRUE(memcmp(&uuid, u2, sizeof(u2)) == 0);
+
+ const uint8_t u3[] = {0x00, 0x00, 0x55, 0x3e, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb};
+ uuid = Uuid::From16Bit(0x553e);
+ EXPECT_TRUE(memcmp(&uuid, u3, sizeof(u3)) == 0);
+
+ const uint8_t u4[] = {0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb};
+ uuid = Uuid::From16Bit(0xffff);
+ EXPECT_TRUE(memcmp(&uuid, u4, sizeof(u4)) == 0);
+}
+
+TEST(UuidTest, From32Bit) {
+ EXPECT_EQ(Uuid::From32Bit(0x00000000), kBase);
+
+ const uint8_t u2[] = {0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb};
+ Uuid uuid = Uuid::From32Bit(0x00000001);
+ EXPECT_TRUE(memcmp(&uuid, u2, sizeof(u2)) == 0);
+
+ const uint8_t u3[] = {0x33, 0x44, 0x55, 0x3e, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb};
+ uuid = Uuid::From32Bit(0x3344553e);
+ EXPECT_TRUE(memcmp(&uuid, u3, sizeof(u3)) == 0);
+
+ const uint8_t u4[] = {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb};
+ uuid = Uuid::From32Bit(0xffffffff);
+ EXPECT_TRUE(memcmp(&uuid, u4, sizeof(u4)) == 0);
+}
+
+TEST(UuidTest, ToString) {
+ const std::string UUID_BASE_STR = "00000000-0000-1000-8000-00805f9b34fb";
+ const std::string UUID_EMP_STR = "00000000-0000-0000-0000-000000000000";
+ const std::string UUID_ONES_STR = "11111111-1111-1111-1111-111111111111";
+ const std::string UUID_SEQ_STR = "01234567-89ab-cdef-abcd-ef0123456789";
+
+ EXPECT_EQ(UUID_BASE_STR, kBase.ToString());
+ EXPECT_EQ(UUID_EMP_STR, Uuid::kEmpty.ToString());
+ EXPECT_EQ(UUID_ONES_STR, ONES.ToString());
+ EXPECT_EQ(UUID_SEQ_STR, SEQUENTIAL.ToString());
+
+ Uuid uuid = Uuid::From32Bit(0x12345678);
+ EXPECT_EQ("12345678-0000-1000-8000-00805f9b34fb", uuid.ToString());
+}
+
+TEST(BtifStorageTest, test_string_to_uuid) {
+ const uint8_t u1[] = {0xe3, 0x9c, 0x62, 0x85, 0x86, 0x7f, 0x4b, 0x1d, 0x9d, 0xb0, 0x35, 0xfb, 0xd9, 0xae, 0xbf, 0x22};
+ bool is_valid = false;
+ Uuid uuid = Uuid::FromString("e39c6285-867f-4b1d-9db0-35fbd9aebf22", &is_valid);
+ EXPECT_TRUE(is_valid);
+ EXPECT_TRUE(memcmp(&uuid, u1, sizeof(u1)) == 0);
+
+ const uint8_t u2[] = {0x00, 0x00, 0x1a, 0xe8, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb};
+ is_valid = false;
+ uuid = Uuid::FromString("1Ae8", &is_valid);
+ EXPECT_TRUE(is_valid);
+ EXPECT_TRUE(memcmp(&uuid, u2, sizeof(u2)) == 0);
+
+ const uint8_t u3[] = {0x12, 0x34, 0x11, 0x28, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb};
+ is_valid = false;
+ uuid = Uuid::FromString("12341128", &is_valid);
+ EXPECT_TRUE(is_valid);
+ EXPECT_TRUE(memcmp(&uuid, u3, sizeof(u3)) == 0);
+}
+
+TEST(BtifStorageTest, test_string_to_uuid_invalid) {
+ bool is_valid = false;
+ Uuid uuid = Uuid::FromString("This is not a UUID", &is_valid);
+ EXPECT_FALSE(is_valid);
+
+ uuid = Uuid::FromString("11212", &is_valid);
+ EXPECT_FALSE(is_valid);
+
+ uuid = Uuid::FromString("1121 ", &is_valid);
+ EXPECT_FALSE(is_valid);
+
+ uuid = Uuid::FromString("AGFE", &is_valid);
+ EXPECT_FALSE(is_valid);
+
+ uuid = Uuid::FromString("ABFG", &is_valid);
+ EXPECT_FALSE(is_valid);
+
+ uuid = Uuid::FromString("e39c6285867f14b1d9db035fbd9aebf22", &is_valid);
+ EXPECT_FALSE(is_valid);
+
+ uuid = Uuid::FromString("12234567-89ab-cdef-abcd-ef01234567ZZ", &is_valid);
+ EXPECT_FALSE(is_valid);
+}
diff --git a/vendor_libs/test_vendor_lib/types/test/class_of_device_unittest.cc b/vendor_libs/test_vendor_lib/types/test/class_of_device_unittest.cc
new file mode 100644
index 0000000..5d652a5
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/types/test/class_of_device_unittest.cc
@@ -0,0 +1,96 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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 <gtest/gtest.h>
+
+#include "class_of_device.h"
+
+static const char* test_class = "efc-d-ab";
+static const uint8_t test_bytes[]{0xab, 0xcd, 0xef};
+
+TEST(ClassOfDeviceUnittest, test_constructor_array) {
+ ClassOfDevice cod(test_bytes);
+
+ ASSERT_EQ(test_bytes[0], cod.cod[0]);
+ ASSERT_EQ(test_bytes[1], cod.cod[1]);
+ ASSERT_EQ(test_bytes[2], cod.cod[2]);
+
+ std::string ret = cod.ToString();
+
+ ASSERT_STREQ(test_class, ret.c_str());
+}
+
+TEST(ClassOfDeviceUnittest, test_to_from_str) {
+ ClassOfDevice cod;
+ ClassOfDevice::FromString(test_class, cod);
+
+ ASSERT_EQ(test_bytes[0], cod.cod[0]);
+ ASSERT_EQ(test_bytes[1], cod.cod[1]);
+ ASSERT_EQ(test_bytes[2], cod.cod[2]);
+
+ std::string ret = cod.ToString();
+
+ ASSERT_STREQ(test_class, ret.c_str());
+}
+
+TEST(ClassOfDeviceUnittest, test_from_octets) {
+ ClassOfDevice cod;
+ size_t expected_result = ClassOfDevice::kLength;
+ ASSERT_EQ(expected_result, cod.FromOctets(test_bytes));
+
+ ASSERT_EQ(test_bytes[0], cod.cod[0]);
+ ASSERT_EQ(test_bytes[1], cod.cod[1]);
+ ASSERT_EQ(test_bytes[2], cod.cod[2]);
+
+ std::string ret = cod.ToString();
+
+ ASSERT_STREQ(test_class, ret.c_str());
+}
+
+TEST(ClassOfDeviceTest, test_copy) {
+ ClassOfDevice cod1;
+ ClassOfDevice cod2;
+ ClassOfDevice::FromString(test_class, cod1);
+ cod2 = cod1;
+
+ ASSERT_EQ(cod1.cod[0], cod2.cod[0]);
+ ASSERT_EQ(cod1.cod[1], cod2.cod[1]);
+ ASSERT_EQ(cod1.cod[2], cod2.cod[2]);
+}
+
+TEST(ClassOfDeviceTest, IsValid) {
+ EXPECT_FALSE(ClassOfDevice::IsValid(""));
+ EXPECT_FALSE(ClassOfDevice::IsValid("000000"));
+ EXPECT_FALSE(ClassOfDevice::IsValid("00-00-00"));
+ EXPECT_FALSE(ClassOfDevice::IsValid("000-0-0"));
+ EXPECT_TRUE(ClassOfDevice::IsValid("000-0-00"));
+ EXPECT_TRUE(ClassOfDevice::IsValid("ABc-d-00"));
+ EXPECT_TRUE(ClassOfDevice::IsValid("aBc-D-eF"));
+}
+
+TEST(ClassOfDeviceTest, classOfDeviceFromString) {
+ ClassOfDevice cod;
+
+ EXPECT_TRUE(ClassOfDevice::FromString("000-0-00", cod));
+ const ClassOfDevice result0 = {{0x00, 0x00, 0x00}};
+ EXPECT_EQ(0, memcmp(&cod, &result0, sizeof(cod)));
+
+ EXPECT_TRUE(ClassOfDevice::FromString("ab2-1-4C", cod));
+ const ClassOfDevice result1 = {{0x4c, 0x21, 0xab}};
+ EXPECT_EQ(0, memcmp(&cod, &result1, sizeof(cod)));
+}