Merge "Fix Stack-buffer-over-flow while accessing remote device name"
diff --git a/.gitignore b/.gitignore
index 5acc85a..d26e74c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,6 @@
target/
Cargo.lock
tags
+cscope.out
+cscope.files
+*.sw?
diff --git a/BUILD.gn b/BUILD.gn
index 109bf71..ca2855f 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -32,7 +32,8 @@
group("bluetooth") {
deps = [
"//bt/main:bluetooth",
- "//bt/service:bluetoothtbd",
+ "//bt/main:bluetooth-static",
+ #"//bt/service:bluetoothtbd",
]
}
@@ -104,19 +105,22 @@
"-Wno-final-dtor-non-final-class",
]
- cflags_cc = [ "-std=c++17" ]
+ cflags_cc = [
+ "-std=c++17",
+ ]
defines = [
"HAS_NO_BDROID_BUILDCFG",
"OS_GENERIC",
"OS_LINUX_GENERIC",
+ "TARGET_FLOSS",
"EXPORT_SYMBOL=__attribute__((visibility(\"default\")))",
"FALLTHROUGH_INTENDED=[[clang::fallthrough]]",
]
# If not configured as a dynamic library, default to static library
if (!(defined(use.bt_dynlib) && use.bt_dynlib)) {
- defines = [
+ defines += [
"STATIC_LIBBLUETOOTH",
]
}
diff --git a/Cargo.toml b/Cargo.toml
index 2b60ccb..134dd9f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,46 +13,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-[package]
-name = "bt_shim_ffi"
-version = "0.0.1"
-edition = "2018"
+[workspace]
-[dependencies]
-# BT dependencies
-bt_common = { path = "gd/rust/common" }
-bt_facade_helpers = { path = "gd/rust/facade" }
-bt_hal = { path = "gd/rust/hal" }
-bt_hci = { path = "gd/rust/hci" }
-bt_main = { path = "gd/rust/main" }
-bt_packets = { path = "gd/rust/packets" }
-
-# All external dependencies. Keep all versions at build/rust/Cargo.toml
-bindgen = "0.51"
-bytes = "1.0"
-cxx = { version = "0.5.9", features = ["c++17"] }
-env_logger = "0.8"
-futures = "0.3"
-grpcio = { version = "0.7", features = ["protobuf", "protobuf-codec", "openssl"] }
-grpcio-sys = { version = "*", features = ["openssl"] }
-lazy_static = "1.4"
-log = "0.4"
-nix = "0.19"
-num-derive = "0.3"
-num-traits = "0.2"
-paste = "1.0"
-proc-macro2 = "1.0.24"
-protobuf = "2.0"
-protoc-grpcio = "2.0"
-protoc-rust = "2.0"
-quote = "1.0.8"
-thiserror = "1.0"
-syn = { version = "1.0.58", features = ['default', 'full'] }
-tokio = { version = "1.0", features = ['bytes', 'fs', 'io-util', 'libc', 'macros', 'memchr', 'mio', 'net', 'num_cpus', 'rt', 'rt-multi-thread', 'sync', 'time', 'tokio-macros'] }
-tokio-stream = "0.1"
-walkdir = "2.2"
-
-
-[lib]
-path = "gd/rust/shim/src/lib.rs"
-crate-type = ["staticlib"]
+members = [
+ "gd/rust/shim",
+ "gd/rust/topshim",
+ "gd/rust/linux/mgmt",
+ "gd/rust/linux/service",
+ "gd/rust/linux/client",
+]
diff --git a/README.md b/README.md
index 30b97d0..c7a6bcc 100644
--- a/README.md
+++ b/README.md
@@ -49,12 +49,24 @@
via a package manager. You may have to build these from source and install them
to your local environment.
-TODO(abhishekpandit) - Provide a pre-packaged option for these or proper build
-instructions from source.
-
* libchrome
* modp_b64
-* tinyxml2
+
+We provide a script to produce debian packages for those components, please
+follow the instructions in build/dpkg/README.txt.
+
+The googletest packages provided by Debian/Ubuntu (libgmock-dev and
+libgtest-dev) do not provide pkg-config files, so you can build your own
+googletest using the steps below:
+
+```
+$ git clone https://github.com/google/googletest.git -b release-1.10.0
+$ cd googletest # Main directory of the cloned repository.
+$ mkdir build # Create a directory to hold the build output.
+$ cd build
+$ cmake .. # Generate native build scripts for GoogleTest.
+$ sudo make install -DCMAKE_INSTALL_PREFIX=/usr
+```
### Stage your build environment
diff --git a/audio_a2dp_hw/Android.bp b/audio_a2dp_hw/Android.bp
index 708e1a6..9207acf 100644
--- a/audio_a2dp_hw/Android.bp
+++ b/audio_a2dp_hw/Android.bp
@@ -18,7 +18,6 @@
}
// Audio A2DP shared library for target
-// ========================================================
cc_library {
name: "audio.a2dp.default",
defaults: ["audio_a2dp_hw_defaults"],
@@ -44,7 +43,6 @@
}
// Audio A2DP library unit tests for target and host
-// ========================================================
cc_test {
name: "net_test_audio_a2dp_hw",
test_suites: ["device-tests"],
diff --git a/audio_bluetooth_hw/stream_apis.cc b/audio_bluetooth_hw/stream_apis.cc
index d809b57..aafe547 100644
--- a/audio_bluetooth_hw/stream_apis.cc
+++ b/audio_bluetooth_hw/stream_apis.cc
@@ -127,6 +127,53 @@
}
}
+void in_calculate_starving_delay_ms(const BluetoothStreamIn* in,
+ int64_t* frames, int64_t* time) {
+ // 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;
+ uint64_t delay_report_ms = 0;
+ // dispersed_bytes is the total number of bytes received by the Bluetooth
+ // stack from a remote headset
+ uint64_t dispersed_bytes = 0;
+ struct timespec dispersed_timestamp = {};
+
+ std::unique_lock<std::mutex> lock(in->mutex_);
+ in->bluetooth_input_.GetPresentationPosition(
+ &delay_report_ns, &dispersed_bytes, &dispersed_timestamp);
+ delay_report_ms = delay_report_ns / 1000000;
+
+ const uint64_t latency_frames = delay_report_ms * in->sample_rate_ / 1000;
+ *frames = dispersed_bytes / audio_stream_in_frame_size(&in->stream_in_);
+
+ LOG(VERBOSE) << __func__ << ": state=" << in->bluetooth_input_.GetState()
+ << ", delay=" << delay_report_ms
+ << "ms, data=" << dispersed_bytes
+ << " bytes, timestamp=" << dispersed_timestamp.tv_sec << "."
+ << StringPrintf("%09ld", dispersed_timestamp.tv_nsec) << "s";
+
+ if (in->frames_presented_ < *frames) {
+ // Was audio HAL reset?! The stack counter is obsoleted.
+ *frames = in->frames_presented_;
+ } else if ((in->frames_presented_ - *frames) > latency_frames) {
+ // Is the Bluetooth input reset ?! Its counter was reset but could not be
+ // used.
+ *frames = in->frames_presented_;
+ }
+ // suppose frames would be queued in the headset buffer for delay_report
+ // period, so those frames in buffers should not be included in the number
+ // of presented frames at the timestamp.
+ if (*frames > latency_frames) {
+ *frames -= latency_frames;
+ } else {
+ *frames = 0;
+ }
+
+ *time = (dispersed_timestamp.tv_sec * 1000000000LL +
+ dispersed_timestamp.tv_nsec) /
+ 1000;
+}
+
} // namespace
std::ostream& operator<<(std::ostream& os, const BluetoothStreamState& state) {
@@ -294,8 +341,12 @@
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->frames_rendered_ = 0;
+ if (out->bluetooth_output_.GetState() == BluetoothStreamState::STARTED) {
+ out->bluetooth_output_.Suspend();
+ out->bluetooth_output_.SetState(BluetoothStreamState::DISABLED);
+ } else if (out->bluetooth_output_.GetState() !=
+ BluetoothStreamState::DISABLED) {
out->bluetooth_output_.Stop();
}
} else {
@@ -451,6 +502,10 @@
if (stream->resume(stream)) {
LOG(ERROR) << __func__ << ": state=" << out->bluetooth_output_.GetState()
<< " failed to resume";
+ if (out->bluetooth_output_.GetState() == BluetoothStreamState::DISABLED) {
+ // drop data for cases of A2dpSuspended=true / closing=true
+ totalWritten = bytes;
+ }
usleep(kBluetoothDefaultOutputBufferMs * 1000);
return totalWritten;
}
@@ -719,9 +774,368 @@
size_t adev_get_input_buffer_size(const struct audio_hw_device* dev,
const struct audio_config* config) {
+ /* TODO: Adjust this value */
+ LOG(VERBOSE) << __func__;
return 320;
}
+static uint32_t in_get_sample_rate(const struct audio_stream* stream) {
+ const auto* in = reinterpret_cast<const BluetoothStreamIn*>(stream);
+
+ return in->sample_rate_;
+}
+
+static int in_set_sample_rate(struct audio_stream* stream, uint32_t rate) {
+ const auto* in = reinterpret_cast<const BluetoothStreamIn*>(stream);
+
+ LOG(VERBOSE) << __func__ << ": state=" << in->bluetooth_input_.GetState()
+ << ", sample_rate=" << in->sample_rate_;
+ return (rate == in->sample_rate_ ? 0 : -ENOSYS);
+}
+
+static size_t in_get_buffer_size(const struct audio_stream* stream) {
+ const auto* in = reinterpret_cast<const BluetoothStreamIn*>(stream);
+ size_t buffer_size =
+ in->frames_count_ * audio_stream_in_frame_size(&in->stream_in_);
+ LOG(VERBOSE) << __func__ << ": state=" << in->bluetooth_input_.GetState()
+ << ", buffer_size=" << buffer_size;
+ return buffer_size;
+}
+
+static audio_channel_mask_t in_get_channels(const struct audio_stream* stream) {
+ const auto* in = reinterpret_cast<const BluetoothStreamIn*>(stream);
+ audio_config_t audio_cfg;
+ if (in->bluetooth_input_.LoadAudioConfig(&audio_cfg)) {
+ LOG(VERBOSE) << __func__ << ": state=" << in->bluetooth_input_.GetState()
+ << " audio_cfg=" << audio_cfg;
+ return audio_cfg.channel_mask;
+ } else {
+ LOG(WARNING) << __func__ << ": state=" << in->bluetooth_input_.GetState()
+ << ", channels=" << StringPrintf("%#x", in->channel_mask_)
+ << " failure";
+ return in->channel_mask_;
+ }
+}
+
+static audio_format_t in_get_format(const struct audio_stream* stream) {
+ const auto* in = reinterpret_cast<const BluetoothStreamIn*>(stream);
+ audio_config_t audio_cfg;
+ if (in->bluetooth_input_.LoadAudioConfig(&audio_cfg)) {
+ LOG(VERBOSE) << __func__ << ": state=" << in->bluetooth_input_.GetState()
+ << " audio_cfg=" << audio_cfg;
+ return audio_cfg.format;
+ } else {
+ LOG(WARNING) << __func__ << ": state=" << in->bluetooth_input_.GetState()
+ << ", format=" << in->format_ << " failure";
+ return in->format_;
+ }
+}
+
+static int in_set_format(struct audio_stream* stream, audio_format_t format) {
+ const auto* in = reinterpret_cast<const BluetoothStreamIn*>(stream);
+ LOG(VERBOSE) << __func__ << ": state=" << in->bluetooth_input_.GetState()
+ << ", format=" << in->format_;
+ return (format == in->format_ ? 0 : -ENOSYS);
+}
+
+static bool in_state_transition_timeout(BluetoothStreamIn* in,
+ std::unique_lock<std::mutex>& lock,
+ const BluetoothStreamState& state,
+ uint16_t timeout_ms) {
+ /* Don't loose suspend request, AF will not retry */
+ while (in->bluetooth_input_.GetState() == state) {
+ lock.unlock();
+ usleep(1000);
+ lock.lock();
+
+ /* Don't block AF forever */
+ if (--timeout_ms <= 0) {
+ LOG(WARNING) << __func__
+ << ", can't suspend - stucked in suspending"
+ " state";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static int in_standby(struct audio_stream* stream) {
+ auto* in = reinterpret_cast<BluetoothStreamIn*>(stream);
+ std::unique_lock<std::mutex> lock(in->mutex_);
+ int retval = 0;
+
+ LOG(VERBOSE) << __func__ << ": state=" << in->bluetooth_input_.GetState()
+ << " being standby (suspend)";
+
+ /* Give some time to start up */
+ if (!in_state_transition_timeout(in, lock, BluetoothStreamState::STARTING,
+ kBluetoothDefaultInputStateTimeoutMs)) {
+ LOG(ERROR) << __func__ << ": state=" << in->bluetooth_input_.GetState()
+ << " NOT ready to by standby";
+ return retval;
+ }
+
+ if (in->bluetooth_input_.GetState() == BluetoothStreamState::STARTED) {
+ retval = (in->bluetooth_input_.Suspend() ? 0 : -EIO);
+ } else if (in->bluetooth_input_.GetState() !=
+ BluetoothStreamState::SUSPENDING) {
+ LOG(DEBUG) << __func__ << ": state=" << in->bluetooth_input_.GetState()
+ << " standby already";
+ return retval;
+ }
+
+ /* Give some time to suspend */
+ if (!in_state_transition_timeout(in, lock, BluetoothStreamState::SUSPENDING,
+ kBluetoothDefaultInputStateTimeoutMs)) {
+ LOG(ERROR) << __func__ << ": state=" << in->bluetooth_input_.GetState()
+ << " NOT ready to by standby";
+ return 0;
+ }
+
+ LOG(VERBOSE) << __func__ << ": state=" << in->bluetooth_input_.GetState()
+ << " standby (suspend) retval=" << retval;
+
+ return retval;
+}
+
+static int in_dump(const struct audio_stream* stream, int fd) {
+ const auto* in = reinterpret_cast<const BluetoothStreamIn*>(stream);
+ LOG(VERBOSE) << __func__ << ": state=" << in->bluetooth_input_.GetState();
+
+ return 0;
+}
+
+static int in_set_parameters(struct audio_stream* stream, const char* kvpairs) {
+ auto* in = reinterpret_cast<BluetoothStreamIn*>(stream);
+ std::unique_lock<std::mutex> lock(in->mutex_);
+ int retval = 0;
+
+ LOG(INFO) << __func__
+ << ": NOT HANDLED! state=" << in->bluetooth_input_.GetState()
+ << ", kvpairs=[" << kvpairs << "]";
+
+ std::unordered_map<std::string, std::string> params =
+ ParseAudioParams(kvpairs);
+
+ if (params.empty()) return retval;
+
+ LOG(INFO) << __func__ << ": ParamsMap=[" << GetAudioParamString(params)
+ << "]";
+
+ return retval;
+}
+
+static char* in_get_parameters(const struct audio_stream* stream,
+ const char* keys) {
+ const auto* in = reinterpret_cast<const BluetoothStreamIn*>(stream);
+ std::unique_lock<std::mutex> lock(in->mutex_);
+
+ LOG(VERBOSE) << __func__
+ << ": NOT HANDLED! state=" << in->bluetooth_input_.GetState()
+ << ", keys=[" << keys << "]";
+
+ std::unordered_map<std::string, std::string> params = ParseAudioParams(keys);
+ if (params.empty()) return strdup("");
+
+ audio_config_t audio_cfg;
+ if (in->bluetooth_input_.LoadAudioConfig(&audio_cfg)) {
+ LOG(VERBOSE) << __func__ << ": state=" << in->bluetooth_input_.GetState()
+ << " audio_cfg=" << audio_cfg;
+ } else {
+ LOG(ERROR) << __func__ << ": state=" << in->bluetooth_input_.GetState()
+ << " failed to get audio config";
+ }
+
+ std::unordered_map<std::string, std::string> return_params;
+
+ /* TODO: Implement parameter getter */
+
+ std::string result;
+ for (const auto& ptr : return_params) {
+ result += ptr.first + "=" + ptr.second + ";";
+ }
+
+ return strdup(result.c_str());
+}
+
+static int in_add_audio_effect(const struct audio_stream* stream,
+ effect_handle_t effect) {
+ const auto* in = reinterpret_cast<const BluetoothStreamIn*>(stream);
+ LOG(VERBOSE) << __func__ << ": state=" << in->bluetooth_input_.GetState()
+ << ", effect=" << effect;
+ return 0;
+}
+
+static int in_remove_audio_effect(const struct audio_stream* stream,
+ effect_handle_t effect) {
+ const auto* in = reinterpret_cast<const BluetoothStreamIn*>(stream);
+ LOG(VERBOSE) << __func__ << ": state=" << in->bluetooth_input_.GetState()
+ << ", effect=" << effect;
+ return 0;
+}
+
+static int in_set_gain(struct audio_stream_in* stream, float gain) {
+ const auto* in = reinterpret_cast<const BluetoothStreamIn*>(stream);
+ LOG(VERBOSE) << __func__
+ << ": NOT HANDLED! state=" << in->bluetooth_input_.GetState();
+
+ return 0;
+}
+
+static ssize_t in_read(struct audio_stream_in* stream, void* buffer,
+ size_t bytes) {
+ auto* in = reinterpret_cast<BluetoothStreamIn*>(stream);
+ std::unique_lock<std::mutex> lock(in->mutex_);
+ size_t totalRead = 0;
+
+ /* Give some time to start up */
+ if (!in_state_transition_timeout(in, lock, BluetoothStreamState::STARTING,
+ kBluetoothDefaultInputStateTimeoutMs))
+ return -EBUSY;
+
+ if (in->bluetooth_input_.GetState() != BluetoothStreamState::STARTED) {
+ LOG(INFO) << __func__ << ": state=" << in->bluetooth_input_.GetState()
+ << " first time bytes=" << bytes;
+
+ int retval = 0;
+ LOG(VERBOSE) << __func__ << ": state=" << in->bluetooth_input_.GetState()
+ << ", starting";
+ if (in->bluetooth_input_.GetState() == BluetoothStreamState::STANDBY) {
+ retval = (in->bluetooth_input_.Start() ? 0 : -EIO);
+ } else if (in->bluetooth_input_.GetState() ==
+ BluetoothStreamState::SUSPENDING) {
+ LOG(WARNING) << __func__ << ": state=" << in->bluetooth_input_.GetState()
+ << " NOT ready to start?!";
+ retval = -EBUSY;
+ } else if (in->bluetooth_input_.GetState() ==
+ BluetoothStreamState::DISABLED) {
+ LOG(WARNING) << __func__ << ": state=" << in->bluetooth_input_.GetState()
+ << " NOT allow to start?!";
+ retval = -EINVAL;
+ } else {
+ LOG(DEBUG) << __func__ << ": state=" << in->bluetooth_input_.GetState()
+ << " started already";
+ }
+ LOG(VERBOSE) << __func__ << ": state=" << in->bluetooth_input_.GetState()
+ << ", starting (start) retval=" << retval;
+
+ if (retval) {
+ LOG(ERROR) << __func__ << ": state=" << in->bluetooth_input_.GetState()
+ << " failed to start";
+ return retval;
+ }
+ }
+
+ lock.unlock();
+ totalRead = in->bluetooth_input_.ReadData(buffer, bytes);
+ lock.lock();
+
+ struct timespec ts = {.tv_sec = 0, .tv_nsec = 0};
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ in->last_read_time_us_ = (ts.tv_sec * 1000000000LL + ts.tv_nsec) / 1000;
+
+ const size_t frames = totalRead / audio_stream_in_frame_size(stream);
+ in->frames_presented_ += frames;
+
+ return totalRead;
+}
+
+static uint32_t in_get_input_frames_lost(struct audio_stream_in* stream) {
+ const auto* in = reinterpret_cast<const BluetoothStreamIn*>(stream);
+ LOG(VERBOSE) << __func__
+ << ": NOT HANDLED! state=" << in->bluetooth_input_.GetState();
+
+ return 0;
+}
+
+static int in_get_capture_position(const struct audio_stream_in* stream,
+ int64_t* frames, int64_t* time) {
+ if (stream == NULL || frames == NULL || time == NULL) {
+ return -EINVAL;
+ }
+ const auto* in = reinterpret_cast<const BluetoothStreamIn*>(stream);
+
+ if (in->bluetooth_input_.GetState() == BluetoothStreamState::STANDBY) {
+ LOG(WARNING) << __func__ << ": state= " << in->bluetooth_input_.GetState();
+ return -ENOSYS;
+ }
+
+ in_calculate_starving_delay_ms(in, frames, time);
+
+ return 0;
+}
+
+static int in_start(const struct audio_stream_in* stream) {
+ const auto* in = reinterpret_cast<const BluetoothStreamIn*>(stream);
+ LOG(VERBOSE) << __func__
+ << ": NOT HANDLED! state=" << in->bluetooth_input_.GetState();
+
+ return 0;
+}
+
+static int in_stop(const struct audio_stream_in* stream) {
+ const auto* in = reinterpret_cast<const BluetoothStreamIn*>(stream);
+ LOG(VERBOSE) << __func__
+ << ": NOT HANDLED! state=" << in->bluetooth_input_.GetState();
+
+ return 0;
+}
+
+static int in_create_mmap_buffer(const struct audio_stream_in* stream,
+ int32_t min_size_frames,
+ struct audio_mmap_buffer_info* info) {
+ const auto* in = reinterpret_cast<const BluetoothStreamIn*>(stream);
+ LOG(VERBOSE) << __func__
+ << ": NOT HANDLED! state=" << in->bluetooth_input_.GetState();
+
+ return -ENOSYS;
+}
+
+static int in_get_mmap_position(const struct audio_stream_in* stream,
+ struct audio_mmap_position* position) {
+ const auto* in = reinterpret_cast<const BluetoothStreamIn*>(stream);
+ LOG(VERBOSE) << __func__
+ << ": NOT HANDLED! state=" << in->bluetooth_input_.GetState();
+
+ return -ENOSYS;
+}
+
+static int in_get_active_microphones(
+ const struct audio_stream_in* stream,
+ struct audio_microphone_characteristic_t* mic_array, size_t* mic_count) {
+ const auto* in = reinterpret_cast<const BluetoothStreamIn*>(stream);
+ LOG(VERBOSE) << __func__
+ << ": NOT HANDLED! state=" << in->bluetooth_input_.GetState();
+
+ return -ENOSYS;
+}
+
+static int in_set_microphone_direction(const struct audio_stream_in* stream,
+ audio_microphone_direction_t direction) {
+ const auto* in = reinterpret_cast<const BluetoothStreamIn*>(stream);
+ LOG(VERBOSE) << __func__
+ << ": NOT HANDLED! state=" << in->bluetooth_input_.GetState();
+
+ return -ENOSYS;
+}
+
+static int in_set_microphone_field_dimension(
+ const struct audio_stream_in* stream, float zoom) {
+ const auto* in = reinterpret_cast<const BluetoothStreamIn*>(stream);
+ LOG(VERBOSE) << __func__
+ << ": NOT HANDLED! state=" << in->bluetooth_input_.GetState();
+
+ return -ENOSYS;
+}
+
+static void in_update_sink_metadata(struct audio_stream_in* stream,
+ const struct sink_metadata* sink_metadata) {
+ const auto* in = reinterpret_cast<const BluetoothStreamIn*>(stream);
+ LOG(VERBOSE) << __func__
+ << ": NOT HANDLED! state=" << in->bluetooth_input_.GetState();
+}
+
int adev_open_input_stream(struct audio_hw_device* dev,
audio_io_handle_t handle, audio_devices_t devices,
struct audio_config* config,
@@ -729,8 +1143,75 @@
audio_input_flags_t flags __unused,
const char* address __unused,
audio_source_t source __unused) {
- return -EINVAL;
+ *stream_in = nullptr;
+ auto* in = new BluetoothStreamIn{};
+ if (!in->bluetooth_input_.SetUp(devices)) {
+ delete in;
+ return -EINVAL;
+ }
+
+ LOG(INFO) << __func__ << ": device=" << StringPrintf("%#x", devices);
+
+ in->stream_in_.common.get_sample_rate = in_get_sample_rate;
+ in->stream_in_.common.set_sample_rate = in_set_sample_rate;
+ in->stream_in_.common.get_buffer_size = in_get_buffer_size;
+ in->stream_in_.common.get_channels = in_get_channels;
+ in->stream_in_.common.get_format = in_get_format;
+ in->stream_in_.common.set_format = in_set_format;
+ in->stream_in_.common.standby = in_standby;
+ in->stream_in_.common.dump = in_dump;
+ in->stream_in_.common.set_parameters = in_set_parameters;
+ in->stream_in_.common.get_parameters = in_get_parameters;
+ in->stream_in_.common.add_audio_effect = in_add_audio_effect;
+ in->stream_in_.common.remove_audio_effect = in_remove_audio_effect;
+ in->stream_in_.set_gain = in_set_gain;
+ in->stream_in_.read = in_read;
+ in->stream_in_.get_input_frames_lost = in_get_input_frames_lost;
+ in->stream_in_.get_capture_position = in_get_capture_position;
+ in->stream_in_.start = in_start;
+ in->stream_in_.stop = in_stop;
+ in->stream_in_.create_mmap_buffer = in_create_mmap_buffer;
+ in->stream_in_.get_mmap_position = in_get_mmap_position;
+ in->stream_in_.get_active_microphones = in_get_active_microphones;
+ in->stream_in_.set_microphone_direction = in_set_microphone_direction;
+ in->stream_in_.set_microphone_field_dimension =
+ in_set_microphone_field_dimension;
+ in->stream_in_.update_sink_metadata = in_update_sink_metadata;
+
+ if (!in->bluetooth_input_.LoadAudioConfig(config)) {
+ LOG(ERROR) << __func__ << ": state=" << in->bluetooth_input_.GetState()
+ << " failed to get audio config";
+ return -EINVAL;
+ }
+
+ in->sample_rate_ = config->sample_rate;
+ in->channel_mask_ = config->channel_mask;
+ in->format_ = config->format;
+ // frame is number of samples per channel
+ in->frames_count_ =
+ samples_per_ticks(kBluetoothDefaultInputBufferMs, in->sample_rate_, 1);
+ in->frames_presented_ = 0;
+
+ *stream_in = &in->stream_in_;
+ LOG(INFO) << __func__ << ": state=" << in->bluetooth_input_.GetState()
+ << ", sample_rate=" << in->sample_rate_
+ << ", channels=" << StringPrintf("%#x", in->channel_mask_)
+ << ", format=" << in->format_ << ", frames=" << in->frames_count_;
+
+ return 0;
}
void adev_close_input_stream(struct audio_hw_device* dev,
- struct audio_stream_in* stream_in) {}
+ struct audio_stream_in* stream) {
+ auto* in = reinterpret_cast<BluetoothStreamIn*>(stream);
+
+ if (in->bluetooth_input_.GetState() != BluetoothStreamState::DISABLED) {
+ in->bluetooth_input_.Stop();
+ }
+
+ in->bluetooth_input_.TearDown();
+ LOG(VERBOSE) << __func__ << ": state=" << in->bluetooth_input_.GetState()
+ << ", stopped";
+
+ delete in;
+}
diff --git a/audio_bluetooth_hw/stream_apis.h b/audio_bluetooth_hw/stream_apis.h
index 7b51663..55512d7 100644
--- a/audio_bluetooth_hw/stream_apis.h
+++ b/audio_bluetooth_hw/stream_apis.h
@@ -27,6 +27,7 @@
AUDIO_FORMAT_PCM_16_BIT;
constexpr unsigned int kBluetoothDefaultInputBufferMs = 20;
+constexpr unsigned int kBluetoothDefaultInputStateTimeoutMs = 20;
constexpr unsigned int kBluetoothDefaultOutputBufferMs = 10;
constexpr audio_channel_mask_t kBluetoothDefaultOutputChannelModeMask =
@@ -75,6 +76,24 @@
std::list<BluetoothStreamOut*>(0);
};
+struct BluetoothStreamIn {
+ // Must be the first member so it can be cast from audio_stream
+ // or audio_stream_in pointer
+ audio_stream_in stream_in_;
+ ::android::bluetooth::audio::BluetoothAudioPortIn bluetooth_input_;
+ int64_t last_read_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 read 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,
diff --git a/audio_hal_interface/Android.bp b/audio_hal_interface/Android.bp
index 8df759a..874303a 100644
--- a/audio_hal_interface/Android.bp
+++ b/audio_hal_interface/Android.bp
@@ -1,5 +1,4 @@
// Bluetooth Audio library for target
-// ========================================================
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
@@ -56,7 +55,6 @@
}
// Bluetooth Audio client interface library unit tests for target and host
-// ========================================================
cc_test {
name: "bluetooth-test-audio-hal-interface",
defaults: ["fluoride_defaults"],
diff --git a/audio_hal_interface/a2dp_encoding.cc b/audio_hal_interface/a2dp_encoding.cc
index ee9db34..ca07cc4 100644
--- a/audio_hal_interface/a2dp_encoding.cc
+++ b/audio_hal_interface/a2dp_encoding.cc
@@ -19,6 +19,7 @@
#include "client_interface.h"
#include "codec_status.h"
+#include "a2dp_sbc_constants.h"
#include "btif_a2dp_source.h"
#include "btif_av.h"
#include "btif_av_co.h"
@@ -127,6 +128,7 @@
void StopRequest() override {
if (btif_av_get_peer_sep() == AVDT_TSEP_SNK &&
!btif_av_stream_started_ready()) {
+ btif_av_clear_remote_suspend_flag();
return;
}
LOG(INFO) << __func__ << ": handling";
@@ -281,7 +283,11 @@
} else {
codec_config->peerMtu = peer_param.peer_mtu;
}
- if (codec_config->peerMtu > MAX_3MBPS_AVDTP_MTU) {
+ if (current_codec.codec_type == BTAV_A2DP_CODEC_INDEX_SOURCE_SBC &&
+ codec_config->config.sbcConfig().maxBitpool <=
+ A2DP_SBC_BITPOOL_MIDDLE_QUALITY) {
+ codec_config->peerMtu = MAX_2MBPS_AVDTP_MTU;
+ } else if (codec_config->peerMtu > MAX_3MBPS_AVDTP_MTU) {
codec_config->peerMtu = MAX_3MBPS_AVDTP_MTU;
}
LOG(INFO) << __func__ << ": CodecConfiguration=" << toString(*codec_config);
diff --git a/audio_hearing_aid_hw/Android.bp b/audio_hearing_aid_hw/Android.bp
index 4598077..de0f96b 100644
--- a/audio_hearing_aid_hw/Android.bp
+++ b/audio_hearing_aid_hw/Android.bp
@@ -16,7 +16,6 @@
}
// Audio A2DP shared library for target
-// ========================================================
cc_library {
name: "audio.hearing_aid.default",
defaults: ["audio_hearing_aid_hw_defaults"],
@@ -32,7 +31,6 @@
}
// Audio A2DP library unit tests for target and host
-// ========================================================
cc_test {
name: "net_test_audio_hearing_aid_hw",
test_suites: ["device-tests"],
diff --git a/blueberry/controllers/android_bt_target_device.py b/blueberry/controllers/android_bt_target_device.py
new file mode 100644
index 0000000..9e7aebf
--- /dev/null
+++ b/blueberry/controllers/android_bt_target_device.py
@@ -0,0 +1,515 @@
+"""Controller class for an android bt device with git_master-bds-dev build.
+
+The config for this derived_bt_target_device in mobileharness is:
+- name: android_bt_target_device
+ devices:
+ - type: MiscTestbedSubDevice
+ dimensions:
+ mobly_type: DerivedBtDevice
+ properties:
+ ModuleName: android_bt_target_device
+ ClassName: AndroidBtTargetDevice
+ Params:
+ config:
+ device_id: phone_serial_number
+ audio_params:
+ channel: 2
+ duration: 50
+ music_file: "music.wav"
+ sample_rate: 44100
+"""
+
+import logging
+import os
+import time
+
+from mobly import asserts
+from mobly.controllers.android_device import AndroidDevice
+from mobly.signals import ControllerError
+# Internal import
+from blueberry.utils import bt_constants
+from blueberry.utils.android_bluetooth_decorator import AndroidBluetoothDecorator
+import blueberry.utils.bt_test_utils as btutils
+
+ADB_FILE = "rec.pcm"
+ADB_PATH = "/sdcard/Music/"
+WAVE_FILE_TEMPLATE = "recorded_audio_%s.wav"
+DEFAULT_WAIT_TIME = 3.0
+
+# A MediaBrowserService implemented in the SL4A app to intercept Media keys and
+# commands.
+BLUETOOTH_SL4A_AUDIO_SRC_MBS = "BluetoothSL4AAudioSrcMBS"
+
+A2DP_HFP_PROFILES = [
+ bt_constants.BluetoothProfile.A2DP_SINK,
+ bt_constants.BluetoothProfile.HEADSET_CLIENT
+]
+
+
+class AndroidBtTargetDevice(object):
+ """Implements an android device as a hfp and a2dp sink device.
+
+ With git_master-bds-dev build, the android device can act as a bluetooth
+ hfp and a2dp sink device.
+ """
+
+ def __init__(self, config):
+ """Initializes an android hfp device."""
+ logging.info("Initializes the android hfp device")
+ self.pri_ad = None
+ self.sec_ad = None
+ self.serial = config.get("device_id", None)
+ self.audio_params = config.get("audio_params", None)
+
+ if self.serial:
+ # self._ad for accessing the device at the end of the test
+ self._ad = AndroidDevice(self.serial)
+ self.aud = adb_ui_device.AdbUiDevice(self._ad)
+ self.pri_ad = AndroidBluetoothDecorator(self._ad)
+ self.pri_ad.init_setup()
+ self.pri_ad.sl4a_setup()
+ self.sl4a = self._ad.services.sl4a
+ self.mac_address = self.sl4a.bluetoothGetLocalAddress()
+
+ if self.audio_params:
+ self._initialize_audio_params()
+ self.avrcp_ready = False
+
+ def __getattr__(self, name):
+ return getattr(self.pri_ad, name)
+
+ def _disable_profiles(self):
+ if self.sec_ad is None:
+ raise MissingBtClientDeviceError("Please provide sec_ad forsetting"
+ "profiles")
+ self.set_profiles_policy_off(self.sec_ad, A2DP_HFP_PROFILES)
+
+ def _initialize_audio_params(self):
+ self.audio_capture_path = os.path.join(self._ad.log_path, "audio_capture")
+ os.makedirs(self.audio_capture_path)
+ self.adb_path = os.path.join(ADB_PATH, ADB_FILE)
+ self.wave_file_template = os.path.join(self.audio_capture_path,
+ WAVE_FILE_TEMPLATE)
+ self.wave_file_number = 0
+
+ def _verify_pri_ad(self):
+ if not self.pri_ad:
+ raise ControllerError("No be target device")
+
+ def clean_up(self):
+ """Resets Bluetooth and stops all services when the device is destroyed."""
+ self.deactivate_ble_pairing_mode()
+ self.factory_reset_bluetooth()
+ self._ad.services.stop_all()
+
+ def a2dp_sink_connect(self):
+ """Establishes the hft connection between self.pri_ad and self.sec_ad."""
+ self._verify_pri_ad()
+ connected = self.pri_ad.a2dp_sink_connect(self.sec_ad)
+ asserts.assert_true(
+ connected, "The a2dp sink connection between {} and {} failed".format(
+ self.serial, self.sec_ad.serial))
+ self.log.info("The a2dp sink connection between %s and %s succeeded",
+ self.serial, self.sec_ad.serial)
+ return True
+
+ def activate_pairing_mode(self):
+ """Makes the android hfp device discoverable over Bluetooth."""
+ self.log.info("Activating the pairing mode of the android target device")
+ self.pri_ad.activate_pairing_mode()
+
+ def activate_ble_pairing_mode(self):
+ """Activates BLE pairing mode on an AndroidBtTargetDevice."""
+ self.pri_ad.activate_ble_pairing_mode()
+
+ def deactivate_ble_pairing_mode(self):
+ """Deactivates BLE pairing mode on an AndroidBtTargetDevice."""
+ self.pri_ad.deactivate_ble_pairing_mode()
+
+ def add_pri_ad_device(self, pri_ad):
+ """Adds primary android device as bt target device.
+
+ The primary android device should have been initialized with
+ android_bluetooth_decorator.
+
+ Args:
+ pri_ad: the primary android device as bt target device.
+ """
+ self._ad = pri_ad
+ self.pri_ad = pri_ad
+ self.sl4a = self._ad.services.sl4a
+ self.mac_address = self.sl4a.bluetoothGetLocalAddress()
+ self.log = self.pri_ad.log
+ self.serial = self.pri_ad.serial
+ self.log.info(
+ "Adds primary android device with id %s for the bluetooth"
+ "connection", pri_ad.serial)
+ if self.audio_params:
+ self._initialize_audio_params()
+
+ def add_sec_ad_device(self, sec_ad):
+ """Adds second android device for bluetooth connection.
+
+ The second android device should have sl4a service acitvated.
+
+ Args:
+ sec_ad: the second android device for bluetooth connection.
+ """
+ self.log.info(
+ "Adds second android device with id %s for the bluetooth"
+ "connection", sec_ad.serial)
+ self.sec_ad = sec_ad
+ self.sec_ad_mac_address = self.sec_ad.sl4a.bluetoothGetLocalAddress()
+
+ def answer_phone_call(self):
+ """Answers an incoming phone call."""
+ if not self.is_hfp_connected():
+ self.hfp_connect()
+ # Make sure the device is in ringing state.
+ if not self.wait_for_call_state(
+ bt_constants.CALL_STATE_RINGING, bt_constants.CALL_STATE_TIMEOUT_SEC):
+ raise ControllerError(
+ "Timed out after %ds waiting for the device %s to be ringing state "
+ "before anwsering the incoming phone call." %
+ (bt_constants.CALL_STATE_TIMEOUT_SEC, self.serial))
+ self.log.info("Answers the incoming phone call from hf phone %s for %s",
+ self.mac_address, self.sec_ad_mac_address)
+ return self.sl4a.bluetoothHfpClientAcceptCall(self.sec_ad_mac_address)
+
+ def call_volume_down(self):
+ """Lowers the volume."""
+ current_volume = self.mbs.getVoiceCallVolume()
+ if current_volume > 0:
+ change_volume = current_volume - 1
+ self.log.debug("Set voice call volume from %d to %d." %
+ (current_volume, change_volume))
+ self.mbs.setVoiceCallVolume(change_volume)
+
+ def call_volume_up(self):
+ """Raises the volume."""
+ current_volume = self.mbs.getVoiceCallVolume()
+ if current_volume < self.mbs.getVoiceCallMaxVolume():
+ change_volume = current_volume + 1
+ self.log.debug("Set voice call volume from %d to %d." %
+ (current_volume, change_volume))
+ self.mbs.setVoiceCallVolume(change_volume)
+
+ def disconnect_all(self):
+ self._disable_profiles()
+
+ def factory_reset_bluetooth(self):
+ """Factory resets Bluetooth on the android hfp device."""
+ self.log.info("Factory resets Bluetooth on the android target device")
+ self.pri_ad.factory_reset_bluetooth()
+
+ def get_bluetooth_mac_address(self):
+ """Gets Bluetooth mac address of this android_bt_device."""
+ self.log.info("Getting Bluetooth mac address for AndroidBtTargetDevice.")
+ mac_address = self.sl4a.bluetoothGetLocalAddress()
+ self.log.info("Bluetooth mac address of AndroidBtTargetDevice: %s",
+ mac_address)
+ return mac_address
+
+ def get_audio_params(self):
+ """Gets audio params from the android_bt_target_device."""
+ return self.audio_params
+
+ def get_new_wave_file_path(self):
+ """Gets a new wave file path for the audio capture."""
+ wave_file_path = self.wave_file_template % self.wave_file_number
+ while os.path.exists(wave_file_path):
+ self.wave_file_number += 1
+ wave_file_path = self.wave_file_template % self.wave_file_number
+ return wave_file_path
+
+ def get_unread_messages(self) -> None:
+ """Gets unread messages from the connected device (MSE)."""
+ self.sl4a.mapGetUnreadMessages(self.sec_ad_mac_address)
+
+ def hangup_phone_call(self):
+ """Hangs up an ongoing phone call."""
+ if not self.is_hfp_connected():
+ self.hfp_connect()
+ self.log.info("Hangs up the phone call from hf phone %s for %s",
+ self.mac_address, self.sec_ad_mac_address)
+ return self.sl4a.bluetoothHfpClientTerminateAllCalls(
+ self.sec_ad_mac_address)
+
+ def hfp_connect(self):
+ """Establishes the hft connection between self.pri_ad and self.sec_ad."""
+ self._verify_pri_ad()
+ connected = self.pri_ad.hfp_connect(self.sec_ad)
+ asserts.assert_true(
+ connected, "The hfp connection between {} and {} failed".format(
+ self.serial, self.sec_ad.serial))
+ self.log.info("The hfp connection between %s and %s succeed", self.serial,
+ self.sec_ad.serial)
+ return connected
+
+ def init_ambs_for_avrcp(self):
+ """Initializes media browser service for avrcp.
+
+ This is required to be done before running any of the passthrough
+ commands.
+
+ Steps:
+ 1. Starts up the AvrcpMediaBrowserService on the A2dp source phone. This
+ MediaBrowserService is part of the SL4A app.
+ 2. Switch the playback state to be paused.
+ 3. Connects a MediaBrowser to the A2dp sink's A2dpMediaBrowserService.
+
+ Returns:
+ True: if it is avrcp ready after the initialization.
+ False: if it is still not avrcp ready after the initialization.
+
+ Raises:
+ Signals.ControllerError: raise if AvrcpMediaBrowserService on the A2dp
+ source phone fails to be started.
+ """
+ if self.is_avrcp_ready():
+ return True
+ if not self.is_a2dp_sink_connected():
+ self.a2dp_sink_connect()
+
+ self.sec_ad.log.info("Starting AvrcpMediaBrowserService")
+ self.sec_ad.sl4a.bluetoothMediaPhoneSL4AMBSStart()
+
+ time.sleep(DEFAULT_WAIT_TIME)
+
+ # Check if the media session "BluetoothSL4AAudioSrcMBS" is active on sec_ad.
+ active_sessions = self.sec_ad.sl4a.bluetoothMediaGetActiveMediaSessions()
+ if BLUETOOTH_SL4A_AUDIO_SRC_MBS not in active_sessions:
+ raise ControllerError("Failed to start AvrcpMediaBrowserService.")
+
+ self.log.info("Connecting to A2dp media browser service")
+ self.sl4a.bluetoothMediaConnectToCarMBS()
+
+ # TODO(user) Wait for an event back instead of sleep
+ time.sleep(DEFAULT_WAIT_TIME)
+ self.avrcp_ready = True
+ return self.avrcp_ready
+
+ def is_avrcp_ready(self):
+ """Checks if the pri_ad and sec_ad are ready for avrcp."""
+ self._verify_pri_ad()
+ if self.avrcp_ready:
+ return True
+ active_sessions = self.sl4a.bluetoothMediaGetActiveMediaSessions()
+ if not active_sessions:
+ self.log.info("The device is not avrcp ready")
+ self.avrcp_ready = False
+ else:
+ self.log.info("The device is avrcp ready")
+ self.avrcp_ready = True
+ return self.avrcp_ready
+
+ def is_hfp_connected(self):
+ """Checks if the pri_ad and sec_ad are hfp connected."""
+ self._verify_pri_ad()
+ if self.sec_ad is None:
+ raise MissingBtClientDeviceError("The sec_ad was not added")
+ return self.sl4a.bluetoothHfpClientGetConnectionStatus(
+ self.sec_ad_mac_address)
+
+ def is_a2dp_sink_connected(self):
+ """Checks if the pri_ad and sec_ad are hfp connected."""
+ self._verify_pri_ad()
+ if self.sec_ad is None:
+ raise MissingBtClientDeviceError("The sec_ad was not added")
+ return self.sl4a.bluetoothA2dpSinkGetConnectionStatus(
+ self.sec_ad_mac_address)
+
+ def last_number_dial(self):
+ """Redials last outgoing phone number."""
+ if not self.is_hfp_connected():
+ self.hfp_connect()
+ self.log.info("Redials last number from hf phone %s for %s",
+ self.mac_address, self.sec_ad_mac_address)
+ self.sl4a.bluetoothHfpClientDial(self.sec_ad_mac_address, None)
+
+ def map_connect(self):
+ """Establishes the map connection between self.pri_ad and self.sec_ad."""
+ self._verify_pri_ad()
+ connected = self.pri_ad.map_connect(self.sec_ad)
+ asserts.assert_true(
+ connected, "The map connection between {} and {} failed".format(
+ self.serial, self.sec_ad.serial))
+ self.log.info("The map connection between %s and %s succeed", self.serial,
+ self.sec_ad.serial)
+
+ def map_disconnect(self) -> None:
+ """Initiates a map disconnection to the connected device.
+
+ Raises:
+ BluetoothProfileConnectionError: raised if failed to disconnect.
+ """
+ self._verify_pri_ad()
+ if not self.pri_ad.map_disconnect(self.sec_ad_mac_address):
+ raise BluetoothProfileConnectionError(
+ 'Failed to terminate the MAP connection with the device "%s".' %
+ self.sec_ad_mac_address)
+
+ def pbap_connect(self):
+ """Establishes the pbap connection between self.pri_ad and self.sec_ad."""
+ connected = self.pri_ad.pbap_connect(self.sec_ad)
+ asserts.assert_true(
+ connected, "The pbap connection between {} and {} failed".format(
+ self.serial, self.sec_ad.serial))
+ self.log.info("The pbap connection between %s and %s succeed", self.serial,
+ self.sec_ad.serial)
+
+ def pause(self):
+ """Sends Avrcp pause command."""
+ self.send_media_passthrough_cmd(bt_constants.CMD_MEDIA_PAUSE, self.sec_ad)
+
+ def play(self):
+ """Sends Avrcp play command."""
+ self.send_media_passthrough_cmd(bt_constants.CMD_MEDIA_PLAY, self.sec_ad)
+
+ def power_on(self):
+ """Turns the Bluetooth on the android bt garget device."""
+ self.log.info("Turns on the bluetooth")
+ return self.sl4a.bluetoothToggleState(True)
+
+ def power_off(self):
+ """Turns the Bluetooth off the android bt garget device."""
+ self.log.info("Turns off the bluetooth")
+ return self.sl4a.bluetoothToggleState(False)
+
+ def route_call_audio(self, connect=False):
+ """Routes call audio during a call."""
+ if not self.is_hfp_connected():
+ self.hfp_connect()
+ self.log.info(
+ "Routes call audio during a call from hf phone %s for %s "
+ "audio connection %s after routing", self.mac_address,
+ self.sec_ad_mac_address, connect)
+ if connect:
+ self.sl4a.bluetoothHfpClientConnectAudio(self.sec_ad_mac_address)
+ else:
+ self.sl4a.bluetoothHfpClientDisconnectAudio(self.sec_ad_mac_address)
+
+ def reject_phone_call(self):
+ """Rejects an incoming phone call."""
+ if not self.is_hfp_connected():
+ self.hfp_connect()
+ # Make sure the device is in ringing state.
+ if not self.wait_for_call_state(
+ bt_constants.CALL_STATE_RINGING, bt_constants.CALL_STATE_TIMEOUT_SEC):
+ raise ControllerError(
+ "Timed out after %ds waiting for the device %s to be ringing state "
+ "before rejecting the incoming phone call." %
+ (bt_constants.CALL_STATE_TIMEOUT_SEC, self.serial))
+ self.log.info("Rejects the incoming phone call from hf phone %s for %s",
+ self.mac_address, self.sec_ad_mac_address)
+ return self.sl4a.bluetoothHfpClientRejectCall(self.sec_ad_mac_address)
+
+ def set_audio_params(self, audio_params):
+ """Sets audio params to the android_bt_target_device."""
+ self.audio_params = audio_params
+
+ def track_previous(self):
+ """Sends Avrcp skip prev command."""
+ self.send_media_passthrough_cmd(
+ bt_constants.CMD_MEDIA_SKIP_PREV, self.sec_ad)
+
+ def track_next(self):
+ """Sends Avrcp skip next command."""
+ self.send_media_passthrough_cmd(
+ bt_constants.CMD_MEDIA_SKIP_NEXT, self.sec_ad)
+
+ def start_audio_capture(self):
+ """Starts the audio capture over adb."""
+ if self.audio_params is None:
+ raise MissingAudioParamsError("Missing audio params for captureing audio")
+ if not self.is_a2dp_sink_connected():
+ self.a2dp_sink_connect()
+ cmd = "ap2f --usage 1 --start --duration {} --target {}".format(
+ self.audio_params["duration"], self.adb_path)
+ self.log.info("Starts capturing audio with adb shell command %s", cmd)
+ self.adb.shell(cmd)
+
+ def stop_audio_capture(self):
+ """Stops the audio capture and stores it in wave file.
+
+ Returns:
+ File name of the recorded file.
+
+ Raises:
+ MissingAudioParamsError: when self.audio_params is None
+ """
+ if self.audio_params is None:
+ raise MissingAudioParamsError("Missing audio params for captureing audio")
+ if not self.is_a2dp_sink_connected():
+ self.a2dp_sink_connect()
+ adb_pull_args = [self.adb_path, self.audio_capture_path]
+ self.log.info("start adb -s %s pull %s", self.serial, adb_pull_args)
+ self._ad.adb.pull(adb_pull_args)
+ pcm_file_path = os.path.join(self.audio_capture_path, ADB_FILE)
+ self.log.info("delete the recored file %s", self.adb_path)
+ self._ad.adb.shell("rm {}".format(self.adb_path))
+ wave_file_path = self.get_new_wave_file_path()
+ self.log.info("convert pcm file %s to wav file %s", pcm_file_path,
+ wave_file_path)
+ btutils.convert_pcm_to_wav(pcm_file_path, wave_file_path, self.audio_params)
+ return wave_file_path
+
+ def stop_all_services(self):
+ """Stops all services for the pri_ad device."""
+ self.log.info("Stops all services on the android bt target device")
+ self._ad.services.stop_all()
+
+ def stop_ambs_for_avrcp(self):
+ """Stops media browser service for avrcp."""
+ if self.is_avrcp_ready():
+ self.log.info("Stops avrcp connection")
+ self.sec_ad.sl4a.bluetoothMediaPhoneSL4AMBSStop()
+ self.avrcp_ready = False
+
+ def stop_voice_dial(self):
+ """Stops voice dial."""
+ if not self.is_hfp_connected():
+ self.hfp_connect()
+ self.log.info("Stops voice dial from hf phone %s for %s", self.mac_address,
+ self.sec_ad_mac_address)
+ if self.is_hfp_connected():
+ self.sl4a.bluetoothHfpClientStopVoiceRecognition(
+ self.sec_ad_mac_address)
+
+ def take_bug_report(self,
+ test_name=None,
+ begin_time=None,
+ timeout=300,
+ destination=None):
+ """Wrapper method to capture bugreport on the android bt target device."""
+ self._ad.take_bug_report(test_name, begin_time, timeout, destination)
+
+ def voice_dial(self):
+ """Triggers voice dial."""
+ if not self.is_hfp_connected():
+ self.hfp_connect()
+ self.log.info("Triggers voice dial from hf phone %s for %s",
+ self.mac_address, self.sec_ad_mac_address)
+ if self.is_hfp_connected():
+ self.sl4a.bluetoothHfpClientStartVoiceRecognition(
+ self.sec_ad_mac_address)
+
+ def log_type(self):
+ """Gets the log type of Android bt target device.
+
+ Returns:
+ A string, the log type of Android bt target device.
+ """
+ return bt_constants.LogType.BLUETOOTH_DEVICE_SIMULATOR
+
+
+class BluetoothProfileConnectionError(Exception):
+ """Error for Bluetooth Profile connection problems."""
+
+
+class MissingBtClientDeviceError(Exception):
+ """Error for missing required bluetooth client device."""
+
+
+class MissingAudioParamsError(Exception):
+ """Error for missing the audio params."""
diff --git a/blueberry/controllers/bt_stub.py b/blueberry/controllers/bt_stub.py
new file mode 100644
index 0000000..0cd024e
--- /dev/null
+++ b/blueberry/controllers/bt_stub.py
@@ -0,0 +1,294 @@
+"""Bluetooth stub class.
+
+This controller offers no direct control to any device. It simply prompts the
+user to perform a certain action on the device it is standing in for. For use
+in test scripts where no controller for the DUT exists.
+"""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import six
+
+
+class BtStub(object):
+ """Stub for when controller class does not exist for a Bluetooth device.
+
+ This class will simulate semi-automation by prompting user to manually
+ perform actions on the Bluetooth device.
+ """
+
+ # Connection Commands
+ def power_off(self):
+ """Prompt the user to power off the Bluetooth device."""
+ six.moves.input("Power Off Bluetooth device, then press enter.")
+
+ def power_on(self):
+ """Prompt the user to power on the Bluetooth device."""
+ six.moves.input("Power ON Bluetooth device, then press enter.")
+
+ def activate_pairing_mode(self):
+ """Prompt the user to put the Bluetooth device into pairing mode."""
+ six.moves.input("Put Bluetooth device into pairing mode,"
+ "then press enter.")
+
+ def get_bluetooth_mac_address(self):
+ """Prompt the user to input the Bluetooth MAC address for this device.
+
+ Returns:
+ mac_address (str): the string received from user input.
+ """
+ mac_address = six.moves.input("Enter BT MAC address, then press enter.")
+ return mac_address
+
+ def set_device_name(self, device_name):
+ """Prompt the user to set the device name (Carkit Only).
+
+ Args:
+ device_name: String of device name to be set.
+
+ Returns: None
+ """
+ six.moves.input("Device name is: %s", device_name)
+
+ def factory_reset_bluetooth(self):
+ """Prompt the user to factory reset Bluetooth on the device."""
+ six.moves.input("Factory reset Bluetooth on the Bluetooth device, "
+ "then press enter.")
+
+ # A2DP: Bluetooth stereo streaming protocol methods.
+ def is_audio_playing(self):
+ """Prompt the user to indicate if the audio is playing.
+
+ Returns:
+ A Bool, true is audio is playing, false if not.
+ """
+ audio_playing = six.moves.input("Indicate if audio is playing: "
+ "true/false.")
+ return bool(audio_playing)
+
+ # AVRCP Commands
+ def volume_up(self):
+ """Prompt the user to raise the volume on the Bluetooth device."""
+ six.moves.input("Press the Volume Up Button on the Bluetooth device, "
+ "then press enter.")
+
+ def volume_down(self):
+ """Prompt the user to lower the volume on the Bluetooth device."""
+ six.moves.input("Press the Volume Down Button on the Bluetooth device, "
+ "then press enter.")
+
+ def track_next(self):
+ """Prompt the user to skip the track on the Bluetooth device."""
+ six.moves.input("Press the Skip Track Button on the Bluetooth device, "
+ "then press enter.")
+
+ def track_previous(self):
+ """Prompt the user to rewind the track on the Bluetooth device."""
+ six.moves.input("Press the Rewind Track Button on the Bluetooth device, "
+ "then press enter.")
+
+ def play(self):
+ """Prompt the user to press play on the Bluetooth device."""
+ six.moves.input("Press the Play Button on the Bluetooth device, "
+ "then press enter.")
+
+ def pause(self):
+ """Prompt the user to press pause on the Bluetooth device."""
+ six.moves.input("Press the Pause Button on the Bluetooth device, "
+ "then press enter.")
+
+ def repeat(self):
+ """Prompt the user to set the repeat option on the device."""
+ six.moves.input("Press the Repeat Button on the Bluetooth device, "
+ "then press enter.")
+
+ def fast_forward(self):
+ """Prompt the user to press the fast forward option/button on the device.
+
+ Returns: None
+ """
+ six.moves.input("Press the Fast Forward Button on the Bluetooth device, "
+ "then press enter.")
+
+ def rewind(self):
+ """Prompt the user to press Rewind option on the device.
+
+ Returns: None
+ """
+ six.moves.input("Press the Rewind option on the Bluetooth device, "
+ "then press enter.")
+
+ # TODO(user): browse_media_content may need more work in terms of input
+ # params and value(s) returned
+ def browse_media_content(self, directory=""):
+ """Prompt the user to enter to the paired device media folders.
+
+ Args:
+ directory: A path to the directory to browse to.
+
+ Returns:
+ List - empty
+ """
+ six.moves.input("Navigate to directory: %s", directory)
+ return []
+
+ def delete_song(self, file_path=""):
+ """Prompt the user to delete a song.
+
+ Args:
+ file_path (optional): A file path to the song to be deleted.
+
+ Returns: None
+ """
+ six.moves.input("Delete a song %s", file_path)
+
+ def shuffle_song(self):
+ """Prompt the user to shuffle a playlist.
+
+ Returns: None
+ """
+ six.moves.input("Shuffle a playlist")
+
+ # HFP (Hands Free Phone protocol) Commands
+ def call_volume_up(self):
+ """Prompt the user to press the volume up button on an active call.
+
+ Returns: None
+ """
+ six.moves.input("Press the volume up button for an active call.")
+
+ def call_volume_down(self):
+ """Prompt the user to press the volume down button on an active call.
+
+ Returns: None
+ """
+ six.moves.input("Press the volume down button for an active call.")
+
+ def answer_phone_call(self):
+ """Prompt the user to press the button to answer a phone call..
+
+ Returns: None
+ """
+ six.moves.input("Press the button to answer the phone call.")
+
+ def hangup_phone_call(self):
+ """Prompt the user to press the button to hang up on an active phone call.
+
+ Returns: None
+ """
+ six.moves.input("Press the button to hang up on the phone call.")
+
+ def call_contact(self, name):
+ """Prompt the user to select a contact from the phonebook and call.
+
+ Args:
+ name: string name of contact to call
+
+ Returns: None
+ """
+ six.moves.input("Select contact, %s, to call.", name)
+
+ def call_number(self, phone_number):
+ """Prompt the user to dial a phone number and call.
+
+ Args:
+ phone_number: string of phone number to dial and call
+
+ Returns: None
+ """
+ six.moves.input("Dial phone number and initiate a call. %s", phone_number)
+
+ def swap_call(self):
+ """Prompt the user to push the button to swap.
+
+ Function swaps between the primary and secondary calls. One call will
+ be active and the other will be on hold.
+
+ Returns: None
+ """
+ six.moves.input("Press the button to swap calls.")
+
+ def merge_call(self):
+ """Prompt the user to push the button to merge calls.
+
+ Merges calls between the primary and secondary calls into a conference
+ call.
+
+ Returns: None
+ """
+ six.moves.input("Press the button to merge calls into a conference call.")
+
+ def hold_call(self):
+ """Prompt the user to put the primary call on hold.
+
+ Primary call will be on hold, while the secondary call becomes active.
+
+ Returns: None
+ """
+ six.moves.input("Press the hold button to put primary call on hold.")
+
+ def mute_call(self):
+ """Prompt the user to mute the ongoing active call.
+
+ Returns: None
+ """
+ six.moves.input("Press Mute button on active call.")
+
+ def unmute_call(self):
+ """Prompt the user to unmute the ongoing active call.
+
+ Returns: None
+ """
+ six.moves.input("Press the Unmute button on an active call.")
+
+ def reject_phone_call(self):
+ """Prompt the user to reject an incoming call.
+
+ Returns: None
+ """
+ six.moves.input("Press the Reject button to reject an incoming call.")
+
+ def answer_voip_call(self):
+ """Prompt the user to press the button to answer a VOIP call.
+
+ Returns: None
+ """
+ six.moves.input("Press the Answer button on an incoming VOIP phone call.")
+
+ def hangup_voip_call(self):
+ """Prompt the user to press the button to hangup on the active VOIP call.
+
+ Returns: None
+ """
+ six.moves.input("Press the hangup button on the active VOIP call.")
+
+ def reject_voip_call(self):
+ """Prompt the user to press the Reject button on the incoming VOIP call.
+
+ Returns: None
+ """
+ six.moves.input("Press the Reject button on the incoming VOIP call.")
+
+ def voice_dial(self):
+ """Prompt user to initiate a voice dial from the phone.
+
+ Returns: None
+ """
+ six.moves.input("Initiate a voice dial.")
+
+ def last_number_dial(self):
+ """Prompt user to iniate a call to the last number dialed.
+
+ Returns: None
+ """
+ six.moves.input("Initiate a call to the last number dialed.")
+
+ # TODO(user): does this method need a input parameter?
+ def route_call_audio(self):
+ """Prompt user to route a call from AG to HF, and vice versa.
+
+ Returns: None
+ """
+ six.moves.input("Reroute call audio.")
diff --git a/blueberry/controllers/derived_bt_device.py b/blueberry/controllers/derived_bt_device.py
new file mode 100644
index 0000000..37fafc1
--- /dev/null
+++ b/blueberry/controllers/derived_bt_device.py
@@ -0,0 +1,116 @@
+# Copyright 2019 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Controller class for a Bluetooth Device.
+
+This controller will instantiate derived classes from BtDevice and the
+module/class specified via strings in configs dictionary.
+
+The idea is to allow vendors to run blueberry tests with their controller class
+through this controller module, eliminating the need to edit the test classes
+themselves.
+"""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import importlib
+import logging
+import yaml
+
+MOBLY_CONTROLLER_CONFIG_NAME = "DerivedBtDevice"
+MOBLY_CONTROLLER_CONFIG_MODULE_KEY = "ModuleName"
+MOBLY_CONTROLLER_CONFIG_CLASS_KEY = "ClassName"
+MOBLY_CONTROLLER_CONFIG_PARAMS_KEY = "Params"
+
+
+def create(configs):
+ """Creates DerivedBtDevice controller objects.
+
+ For each config dict in configs:
+ Import desired controller class from config, compose DerivedBtDevice class
+ from that class and BtDevice, instantiate with params from config.
+
+ Args:
+ configs (list): A list of dicts, each representing a configuration for a
+ Bluetooth device. Each dict should be of the format:
+ {"ModuleName": <name of module in blueberry.controllers>,
+ "ClassName": <name of class to derive controller from>,
+ "Params": <kwargs in dict form to instantiate class with>}
+
+ Returns:
+ A list with DerivedBtDevice objects.
+ """
+ return [_create_bt_device_class(config) for config in configs]
+
+
+def _create_bt_device_class(config):
+ """Created new device class from associated device controller from config."""
+ module = importlib.import_module(
+ "blueberry.controllers.%s" %
+ config[MOBLY_CONTROLLER_CONFIG_MODULE_KEY])
+ logging.info("Creating DerivedBtDevice from %r", config)
+ cls = getattr(module, config[MOBLY_CONTROLLER_CONFIG_CLASS_KEY])
+ params = yaml.safe_load("%s" %
+ config.get(MOBLY_CONTROLLER_CONFIG_PARAMS_KEY, {}))
+ new_class = type(MOBLY_CONTROLLER_CONFIG_NAME, (cls, BtDevice), params)
+ new_class_inst = new_class(**params)
+ return new_class_inst
+
+
+def destroy(derived_bt_devices):
+ """Cleans up DerivedBtDevice objects."""
+ for device in derived_bt_devices:
+ # Execute cleanup if the controller class has the method "clean_up".
+ if hasattr(device, "clean_up"):
+ device.clean_up()
+ del derived_bt_devices
+
+
+class BtDevice(object):
+ """Base class for all Bluetooth Devices.
+
+ Provides additional necessary functionality for use within blueberry.
+ """
+
+ def __init__(self):
+ """Initializes a derived bt base class."""
+ self._user_params = {}
+
+ def setup(self):
+ """For devices that need extra setup."""
+
+ def set_user_params(self, params):
+ """Intended for passing mobly user_params into a derived device class.
+
+ Args:
+ params: Mobly user params.
+ """
+ self._user_params = params
+
+ def get_user_params(self):
+ """Return saved user_params.
+
+ Returns:
+ user_params.
+ """
+ return self._user_params
+
+ def factory_reset_bluetooth(self) -> None:
+ """Factory resets Bluetooth on an BT Device."""
+ raise NotImplementedError
+
+ def activate_pairing_mode(self) -> None:
+ """Activates pairing mode on an AndroidDevice."""
+ raise NotImplementedError
diff --git a/blueberry/controllers/grpc_bt_sync_mock.py b/blueberry/controllers/grpc_bt_sync_mock.py
new file mode 100644
index 0000000..d3e00e8
--- /dev/null
+++ b/blueberry/controllers/grpc_bt_sync_mock.py
@@ -0,0 +1,81 @@
+"""A generic gRPC mock device controller.
+
+Example MH testbed config for Hostside:
+- name: GrpcBtSyncStub-1
+ devices:
+ - type: MiscTestbedSubDevice
+ dimensions:
+ mobly_type: DerivedBtDevice
+ properties:
+ ModuleName: grpc_bt_sync_mock
+ ClassName: GrpcBtSyncMock
+ Params:
+ config:
+ mac_address: FE:ED:BE:EF:CA:FE
+ dimensions:
+ device: GrpcBtSyncStub
+"""
+import subprocess
+
+from absl import flags
+from absl import logging
+import grpc
+
+# Internal import
+from blueberry.grpc.proto import blueberry_device_controller_pb2
+from blueberry.grpc.proto import blueberry_device_controller_pb2_grpc
+
+FLAGS = flags.FLAGS
+flags.DEFINE_string('server', 'dns:///[::1]:10000', 'server address')
+
+
+class GrpcBtSyncMock(object):
+ """Generic GRPC device controller."""
+
+ def __init__(self, config):
+ """Initialize GRPC object."""
+ super(GrpcBtSyncMock, self).__init__()
+ self.mac_address = config['mac_address']
+
+ def __del__(self):
+ self.server_proc.terminate()
+ del self.channel_creds
+ del self.channel
+ del self.stub
+
+ def setup(self):
+ """Setup the gRPC server that the sync mock will respond to."""
+ server_path = self.get_user_params()['mh_files']['grpc_server'][0]
+ logging.info('Start gRPC server: %s', server_path)
+ self.server_proc = subprocess.Popen([server_path],
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ universal_newlines=True,
+ bufsize=0)
+
+ self.channel_creds = loas2.loas2_channel_credentials()
+ self.channel = grpc.secure_channel(FLAGS.server, self.channel_creds)
+ grpc.channel_ready_future(self.channel).result()
+ self.stub = blueberry_device_controller_pb2_grpc.BlueberryDeviceControllerStub(
+ self.channel)
+
+ def init_setup(self):
+ logging.info('init setup TO BE IMPLEMENTED')
+
+ def set_target(self, bt_device):
+ self._target_device = bt_device
+
+ def pair_and_connect_bluetooth(self, target_mac_address):
+ """Pair and connect to a peripheral Bluetooth device."""
+ request = blueberry_device_controller_pb2.TargetMacAddress(
+ mac_address=target_mac_address)
+ try:
+ response = self.stub.PairAndConnectBluetooth(request)
+ logging.info('pair and connect bluetooth response: %s', response)
+ if response.error:
+ print('error handler TO BE IMPLEMENTED')
+ else:
+ return response.pairing_time_sec, response.connection_time_sec
+ except grpc.RpcError as rpc_error:
+ print(rpc_error)
diff --git a/blueberry/controllers/grpc_bt_target_mock.py b/blueberry/controllers/grpc_bt_target_mock.py
new file mode 100644
index 0000000..85f6b51
--- /dev/null
+++ b/blueberry/controllers/grpc_bt_target_mock.py
@@ -0,0 +1,78 @@
+"""gRPC mock target for testing purposes.
+
+Example MH testbed config for Hostside:
+- name: GrpcBtTargetStub-1
+ devices:
+ - type: MiscTestbedSubDevice
+ dimensions:
+ mobly_type: DerivedBtDevice
+ properties:
+ ModuleName: grpc_bt_target_mock
+ ClassName: GrpcBtTargetMock
+ Params:
+ config:
+ mac_address: FE:ED:BE:EF:CA:FE
+ dimensions:
+ device: GrpcBtTargetStub
+"""
+import subprocess
+
+from absl import flags
+from absl import logging
+import grpc
+
+# Internal import
+from blueberry.grpc.proto import blueberry_device_controller_pb2
+from blueberry.grpc.proto import blueberry_device_controller_pb2_grpc
+
+FLAGS = flags.FLAGS
+
+
+class GrpcBtTargetMock(object):
+ """BT Mock Target for testing the GRPC interface."""
+
+ def __init__(self, config):
+ """Initialize GRPC object."""
+ super(GrpcBtTargetMock, self).__init__()
+ self.mac_address = config['mac_address']
+
+ def __del__(self):
+ self.server_proc.terminate()
+ del self.channel_creds
+ del self.channel
+ del self.stub
+
+ def setup(self):
+ """Setup the gRPC server that the target mock will respond to."""
+ server_path = self.get_user_params()['mh_files']['grpc_server'][0]
+ logging.info('Start gRPC server: %s', server_path)
+ self.server_proc = subprocess.Popen([server_path],
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ universal_newlines=True,
+ bufsize=0)
+
+ self.channel_creds = loas2.loas2_channel_credentials()
+ self.channel = grpc.secure_channel(FLAGS.server, self.channel_creds)
+ grpc.channel_ready_future(self.channel).result()
+ self.stub = blueberry_device_controller_pb2_grpc.BlueberryDeviceControllerStub(
+ self.channel)
+
+ def activate_pairing_mode(self):
+ logging.info('activate pairing mode TO BE IMPLEMENTED')
+ request = blueberry_device_controller_pb2.DiscoverableMode(mode=True)
+ try:
+ response = self.stub.SetDiscoverableMode(request)
+ logging.info('set discoverageble response: %s', response)
+ return 0
+ except grpc.RpcError as rpc_error:
+ print(rpc_error)
+ return -1
+
+ def factory_reset_bluetooth(self):
+ logging.info('factory reset TO BE IMPLEMENTED')
+
+ def get_bluetooth_mac_address(self):
+ logging.info('mac_address: %s', self.mac_address)
+ return self.mac_address
diff --git a/blueberry/decorators/android_bluetooth_client_decorator.py b/blueberry/decorators/android_bluetooth_client_decorator.py
new file mode 100644
index 0000000..f9834ea
--- /dev/null
+++ b/blueberry/decorators/android_bluetooth_client_decorator.py
@@ -0,0 +1,48 @@
+"""A Bluetooth Client Decorator util for an Android Device.
+
+This utility allows the user to decorate an device with a custom decorator from
+the blueberry/decorators directory.
+"""
+
+from __future__ import absolute_import
+from __future__ import division
+
+from __future__ import print_function
+
+import importlib
+import re
+from mobly.controllers.android_device import AndroidDevice
+
+
+def decorate(ad, decorator):
+ """Utility to decorate an AndroidDevice.
+
+ Args:
+ ad: Device, must be of type AndroidDevice.
+ decorator: String, class name of the decorator to use.
+ Returns:
+ AndroidDevice object.
+ """
+
+ if not isinstance(ad, AndroidDevice):
+ raise TypeError('Must apply AndroidBluetoothClientDecorator to an '
+ 'AndroidDevice')
+ decorator_module = camel_to_snake(decorator)
+ module = importlib.import_module(
+ 'blueberry.decorators.%s' % decorator_module)
+ cls = getattr(module, decorator)
+ ad = cls(ad)
+
+ return ad
+
+
+def camel_to_snake(cls_name):
+ """Utility to convert a class name from camel case to snake case.
+
+ Args:
+ cls_name: string
+ Returns:
+ string
+ """
+ s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', cls_name)
+ return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
diff --git a/blueberry/decorators/android_bluetooth_client_test_decorator.py b/blueberry/decorators/android_bluetooth_client_test_decorator.py
new file mode 100644
index 0000000..769579e
--- /dev/null
+++ b/blueberry/decorators/android_bluetooth_client_test_decorator.py
@@ -0,0 +1,25 @@
+"""An example Bluetooth Client Decorator.
+"""
+
+from __future__ import absolute_import
+from __future__ import division
+
+from __future__ import print_function
+
+from mobly.controllers.android_device import AndroidDevice
+
+
+class AndroidBluetoothClientTestDecorator(AndroidDevice):
+ """A class used to test Blueberry's BT Client Profile decoration."""
+
+ def __init__(self, ad):
+ self._ad = ad
+ if not isinstance(self._ad, AndroidDevice):
+ raise TypeError('Must apply AndroidBluetoothClientTestDecorator to an '
+ 'AndroidDevice')
+
+ def __getattr__(self, name):
+ return getattr(self._ad, name)
+
+ def test_decoration(self):
+ return 'I make this device fancy!'
diff --git a/blueberry/grpc/blueberry_device_controller.py b/blueberry/grpc/blueberry_device_controller.py
new file mode 100644
index 0000000..c99a204
--- /dev/null
+++ b/blueberry/grpc/blueberry_device_controller.py
@@ -0,0 +1,40 @@
+"""Blueberry gRPC device controller.
+
+This is a server to act as a mock device for testing the Blueberry gRPC
+interface.
+"""
+
+from concurrent import futures
+from absl import app
+from absl import flags
+
+import grpc
+
+# Internal import
+from blueberry.grpc import blueberry_device_controller_service
+from blueberry.grpc.proto import blueberry_device_controller_pb2_grpc
+
+
+_HOST = '[::]'
+
+FLAGS = flags.FLAGS
+flags.DEFINE_integer('port', 10000, 'port to listen on')
+flags.DEFINE_integer('threads', 10, 'number of worker threads in thread pool')
+
+
+def main(unused_argv):
+ server = grpc.server(
+ futures.ThreadPoolExecutor(max_workers=FLAGS.threads),
+ ports=(FLAGS.port,)) # pytype: disable=wrong-keyword-args
+ servicer = (
+ blueberry_device_controller_service.BlueberryDeviceControllerServicer())
+ blueberry_device_controller_pb2_grpc.add_BlueberryDeviceControllerServicer_to_server(
+ servicer, server)
+ server_creds = loas2.loas2_server_credentials()
+ server.add_secure_port(f'{_HOST}:{FLAGS.port}', server_creds)
+ server.start()
+ server.wait_for_termination()
+
+
+if __name__ == '__main__':
+ app.run(main)
diff --git a/blueberry/grpc/blueberry_device_controller_service.py b/blueberry/grpc/blueberry_device_controller_service.py
new file mode 100644
index 0000000..a17d7db
--- /dev/null
+++ b/blueberry/grpc/blueberry_device_controller_service.py
@@ -0,0 +1,37 @@
+"""Blueberry gRPC Mock Service.
+
+This is simple mock service that is used to verify the implementation of the
+Blueberry gRPC device controller interface.
+"""
+
+from blueberry.grpc.proto import blueberry_device_controller_pb2
+from blueberry.grpc.proto import blueberry_device_controller_pb2_grpc
+
+
+class BlueberryDeviceControllerServicer(
+ blueberry_device_controller_pb2_grpc.BlueberryDeviceControllerServicer):
+ """A BlueberryTest gRPC server."""
+
+ def __init__(self, *args, **kwargs):
+ super(BlueberryDeviceControllerServicer, self).__init__(*args, **kwargs)
+ self._error = "testing 123"
+
+ def SetDiscoverableMode(self, request, servicer_context):
+ """Sets the device's discoverable mode.
+
+ Args:
+ request: a blueberry_test_server_pb2.DiscoverableMode object containing
+ the "mode" to set the device to.
+ servicer_context: A grpc.ServicerContext for use during service of the
+ RPC.
+
+ Returns:
+ A blueberry_test_server_pb2.DiscoverableResult
+ """
+ return blueberry_device_controller_pb2.DiscoverableResult(
+ result=True,
+ error=self._error)
+
+ def PairAndConnectBluetooth(self, request, servicer_context):
+ return blueberry_device_controller_pb2.PairAndConnectBluetoothResult(
+ pairing_time_sec=0.1, connection_time_sec=0.2, error=None)
diff --git a/blueberry/grpc/blueberry_test_client.py b/blueberry/grpc/blueberry_test_client.py
new file mode 100644
index 0000000..1fe8eb1
--- /dev/null
+++ b/blueberry/grpc/blueberry_test_client.py
@@ -0,0 +1,46 @@
+"""Blueberry Test Client.
+
+Simple gRPC client to test the Blueberry Mock server.
+"""
+
+from absl import app
+from absl import flags
+
+import grpc
+
+# Internal import
+from blueberry.grpc.proto import blueberry_device_controller_pb2
+from blueberry.grpc.proto import blueberry_device_controller_pb2_grpc
+
+FLAGS = flags.FLAGS
+flags.DEFINE_string('server', 'dns:///[::1]:10000', 'server address')
+
+
+def _UpdateDiscoveryMode(stub, request):
+ try:
+ print('try SetDiscoverableMode')
+ response = stub.SetDiscoverableMode(request)
+ print('complete response')
+ print(response)
+ return 0
+ except grpc.RpcError as rpc_error:
+ print(rpc_error)
+ return -1
+
+
+def main(unused_argv):
+ channel_creds = loas2.loas2_channel_credentials()
+ with grpc.secure_channel(FLAGS.server, channel_creds) as channel:
+ grpc.channel_ready_future(channel).result()
+ stub = blueberry_device_controller_pb2_grpc.BlueberryDeviceControllerStub(
+ channel)
+
+ print('request grpc')
+ request = blueberry_device_controller_pb2.DiscoverableMode(
+ mode=True)
+ print('Call _UpdateDiscoveryMode')
+ return _UpdateDiscoveryMode(stub, request)
+
+
+if __name__ == '__main__':
+ app.run(main)
diff --git a/blueberry/grpc/proto/blueberry_device_controller.proto b/blueberry/grpc/proto/blueberry_device_controller.proto
new file mode 100644
index 0000000..d3f3906
--- /dev/null
+++ b/blueberry/grpc/proto/blueberry_device_controller.proto
@@ -0,0 +1,36 @@
+syntax = "proto3";
+
+package wearables.qa.blueberry.grpc;
+
+option java_multiple_files = true;
+option jspb_use_correct_proto2_semantics = true;
+
+message DiscoverableMode {
+ bool mode = 1; // True to set discoverable on, False to set discoverable off.
+}
+
+message DiscoverableResult {
+ bool result = 1; // True if successful, False if unsuccessful.
+ string error = 2; // Error message if unsuccessful.
+}
+
+message TargetMacAddress {
+ string mac_address = 1; // Mac Address of target device.
+}
+
+message PairAndConnectBluetoothResult {
+ double pairing_time_sec =
+ 1; // The time it takes in seconds to pair the devices.
+ double connection_time_sec =
+ 2; // The time it takes in seconds to connect the devices.
+ string error = 3; // Error message if unsuccessful.
+}
+
+service BlueberryDeviceController {
+ // Returns the result from a request to set device to discoverable.
+ rpc SetDiscoverableMode(DiscoverableMode) returns (DiscoverableResult) {}
+
+ // Returns the result from a request to connect to a target device.
+ rpc PairAndConnectBluetooth(TargetMacAddress)
+ returns (PairAndConnectBluetoothResult) {}
+}
diff --git a/blueberry/sample_testbed.yaml b/blueberry/sample_testbed.yaml
new file mode 100644
index 0000000..99da384
--- /dev/null
+++ b/blueberry/sample_testbed.yaml
@@ -0,0 +1,10 @@
+TestBeds:
+ - Name: SampleTestBed
+ Controllers:
+ AndroidDevice:
+ - serial: 94GAZ00A5C
+ phone_number: 12341234
+ DerivedBtDevice:
+ - ModuleName: iclever_hb01
+ ClassName: IcleverHb01
+ Params: '{"config":{"mac_address":"C4:45:67:02:94:F0","fifo_id":"AH06IVJP","arduino_port":"1"}}'
diff --git a/blueberry/tests/a2dp/bluetooth_a2dp_test.py b/blueberry/tests/a2dp/bluetooth_a2dp_test.py
new file mode 100644
index 0000000..9b578be
--- /dev/null
+++ b/blueberry/tests/a2dp/bluetooth_a2dp_test.py
@@ -0,0 +1,221 @@
+# Lint as: python3
+"""Tests for Bluetooth A2DP audio streamming."""
+
+import time
+
+from mobly import asserts
+from mobly import test_runner
+from mobly import signals
+
+from blueberry.controllers import android_bt_target_device
+from blueberry.utils import blueberry_base_test
+from blueberry.utils import bt_audio_utils
+from blueberry.utils import bt_constants
+from blueberry.utils import bt_test_utils
+
+# Number of seconds for A2DP audio check.
+A2DP_AUDIO_CHECK_TIMEOUT_SEC = 3
+
+# Number of seconds for duration of reference audio.
+REFERENCE_AUDIO_DURATION_SEC = 1.0
+
+# Default threshold of the mean opinion score (MOS).
+MOS_THRESHOLD = 4.5
+
+# The audio parameters for creating a sine wave.
+AUDIO_PARAMS = {
+ 'file_path': '/sdcard/Music',
+ 'frequency': 480,
+ 'channel': 2,
+ 'sample_rate': 48000,
+ 'sample_format': 16,
+ 'duration_sec': 60
+}
+
+
+class BluetoothA2dpTest(blueberry_base_test.BlueberryBaseTest):
+ """Test class for Bluetooth A2DP test.
+
+ This test uses a fixed frequency sine wave to be the reference audio, makes a
+ DUT play this audio and then starts audio capture from a connected Bluetooth
+ sink device, measures mean opinion score (MOS) of the recorded audio and
+ compares the MOS with a threshold to detemine the test result.
+ """
+
+ def setup_class(self):
+ """Standard Mobly setup class."""
+ super(BluetoothA2dpTest, self).setup_class()
+
+ # Threshold of the MOS to determine a test result. Default value is 4.5.
+ self.threshold = float(self.user_params.get('mos_threshold', MOS_THRESHOLD))
+
+ self.phone = self.android_devices[0]
+ self.phone.init_setup()
+ self.phone.sl4a_setup()
+
+ # Generates a sine wave to be reference audio in comparison, and push it to
+ # the phone storage.
+ self.audio_file_on_device, self.audio_file_on_host = (
+ bt_audio_utils.generate_sine_wave_to_device(
+ self.phone,
+ AUDIO_PARAMS['file_path'],
+ AUDIO_PARAMS['frequency'],
+ AUDIO_PARAMS['channel'],
+ AUDIO_PARAMS['sample_rate'],
+ AUDIO_PARAMS['sample_format'],
+ AUDIO_PARAMS['duration_sec'])
+ )
+
+ # Trims the audio to 1 second duration for reference.
+ self.reference_audio_file = bt_audio_utils.trim_audio(
+ audio_file=self.audio_file_on_host,
+ duration_sec=REFERENCE_AUDIO_DURATION_SEC)
+
+ self.derived_bt_device = self.derived_bt_devices[0]
+ self.derived_bt_device.factory_reset_bluetooth()
+ self.derived_bt_device.activate_pairing_mode()
+ self.mac_address = self.derived_bt_device.get_bluetooth_mac_address()
+ self.phone.pair_and_connect_bluetooth(self.mac_address)
+
+ # Sleep until the connection stabilizes.
+ time.sleep(3)
+
+ # Adds the phone to be the secondary device in the android-to-android case.
+ if isinstance(self.derived_bt_device,
+ android_bt_target_device.AndroidBtTargetDevice):
+ self.derived_bt_device.add_sec_ad_device(self.phone)
+
+ def assert_a2dp_expected_status(self, is_playing, fail_msg):
+ """Asserts that A2DP audio is in the expected status.
+
+ Args:
+ is_playing: bool, True if A2DP audio is playing as expected.
+ fail_msg: string, a message explaining the details of test failure.
+ """
+ bt_test_utils.wait_until(
+ timeout_sec=A2DP_AUDIO_CHECK_TIMEOUT_SEC,
+ condition_func=self.phone.mbs.btIsA2dpPlaying,
+ func_args=[self.mac_address],
+ expected_value=is_playing,
+ exception=signals.TestFailure(fail_msg))
+
+ def test_play_a2dp_audio(self):
+ """Test for playing A2DP audio through Bluetooth."""
+
+ # Plays media audio from the phone.
+ audio_file_url = 'file://' + self.audio_file_on_device
+ if not self.phone.sl4a.mediaPlayOpen(audio_file_url):
+ raise signals.TestError(
+ 'Failed to open and play "%s" on the phone "%s".' %
+ (self.audio_file_on_device, self.phone.serial))
+ self.phone.sl4a.mediaPlayStart()
+
+ # Starts audio capture for Bluetooth audio stream.
+ self.derived_bt_device.start_audio_capture()
+
+ # Stops audio capture and generates an recorded audio file.
+ recorded_audio_file = self.derived_bt_device.stop_audio_capture()
+ self.phone.sl4a.mediaPlayStop()
+ self.phone.sl4a.mediaPlayClose()
+
+ # Measures MOS for the recorded audio.
+ mos = bt_audio_utils.measure_audio_mos(recorded_audio_file,
+ self.reference_audio_file)
+
+ # Asserts that the measured MOS should be more than the threshold.
+ asserts.assert_true(
+ mos >= self.threshold,
+ 'MOS of the recorded audio "%.3f" is lower than the threshold "%.3f".' %
+ (mos, self.threshold))
+
+ def test_resume_a2dp_audio_after_phone_call_ended(self):
+ """Test for resuming A2DP audio after a phone call ended.
+
+ Tests that A2DP audio can be paused when receiving a incoming phone call,
+ and resumed after this phone call ended.
+ """
+ # Checks if two android device exist.
+ if len(self.android_devices) < 2:
+ raise signals.TestError('This test requires two android devices.')
+ pri_phone = self.phone
+ sec_phone = self.android_devices[1]
+ sec_phone.init_setup()
+ pri_number = pri_phone.dimensions.get('phone_number')
+ if not pri_number:
+ raise signals.TestError('Please set the dimension "phone_number" to the '
+ 'primary phone.')
+ sec_number = sec_phone.dimensions.get('phone_number')
+ if not sec_number:
+ raise signals.TestError('Please set the dimension "phone_number" to the '
+ 'secondary phone.')
+
+ # Plays media audio from the phone.
+ audio_file_url = 'file://' + self.audio_file_on_device
+ if not self.phone.sl4a.mediaPlayOpen(audio_file_url):
+ raise signals.TestError(
+ 'Failed to open and play "%s" on the phone "%s".' %
+ (self.audio_file_on_device, self.phone.serial))
+ self.phone.sl4a.mediaPlayStart()
+
+ # Checks if A2DP audio is playing.
+ self.assert_a2dp_expected_status(
+ is_playing=True,
+ fail_msg='A2DP audio is not playing.')
+
+ try:
+ # Makes a incoming phone call.
+ sec_phone.sl4a.telecomCallNumber(pri_number)
+ sec_phone.log.info('Made a phone call to device "%s".' % pri_phone.serial)
+ pri_phone.log.info('Waiting for the incoming call from device "%s"...'
+ % sec_phone.serial)
+
+ is_ringing = pri_phone.wait_for_call_state(
+ bt_constants.CALL_STATE_RINGING,
+ bt_constants.CALL_STATE_TIMEOUT_SEC)
+ if not is_ringing:
+ raise signals.TestError(
+ 'Timed out after %ds waiting for the incoming call from device '
+ '"%s".' % (bt_constants.CALL_STATE_TIMEOUT_SEC, sec_phone.serial))
+
+ # Checks if A2DP audio is paused.
+ self.assert_a2dp_expected_status(
+ is_playing=False,
+ fail_msg='A2DP audio is not paused when receiving a phone call.')
+ finally:
+ # Ends the incoming phone call.
+ sec_phone.sl4a.telecomEndCall()
+ sec_phone.log.info('Ended the phone call.')
+ is_idle = pri_phone.wait_for_call_state(
+ bt_constants.CALL_STATE_IDLE,
+ bt_constants.CALL_STATE_TIMEOUT_SEC)
+ if not is_idle:
+ raise signals.TestError(
+ 'Timed out after %ds waiting for the phone call to be ended.' %
+ bt_constants.CALL_STATE_TIMEOUT_SEC)
+
+ # Checks if A2DP audio is resumed.
+ self.assert_a2dp_expected_status(
+ is_playing=True,
+ fail_msg='A2DP audio is not resumed when the phone call is ended.')
+
+ # Starts audio capture for Bluetooth audio stream.
+ self.derived_bt_device.start_audio_capture()
+
+ # Stops audio capture and generates an recorded audio file.
+ recorded_audio_file = self.derived_bt_device.stop_audio_capture()
+ pri_phone.sl4a.mediaPlayStop()
+ pri_phone.sl4a.mediaPlayClose()
+
+ # Measures MOS for the recorded audio.
+ mos = bt_audio_utils.measure_audio_mos(recorded_audio_file,
+ self.reference_audio_file)
+
+ # Asserts that the measured MOS should be more than the threshold.
+ asserts.assert_true(
+ mos >= self.threshold,
+ 'MOS of the recorded audio "%.3f" is lower than the threshold "%.3f".' %
+ (mos, self.threshold))
+
+
+if __name__ == '__main__':
+ test_runner.main()
diff --git a/blueberry/tests/audio_capture/bluetooth_audio_capture_test.py b/blueberry/tests/audio_capture/bluetooth_audio_capture_test.py
new file mode 100644
index 0000000..74e8705
--- /dev/null
+++ b/blueberry/tests/audio_capture/bluetooth_audio_capture_test.py
@@ -0,0 +1,93 @@
+# Lint as: python3
+"""Tests for testing audio capture in android bt target controller.
+
+ location of the controller:
+ blueberry.controllers.android_bt_target_device
+ Before the test, the music file should be copied to the location of the
+ pri_phone. The a2dp sink phone should be with the android build that can
+ support a2dp sink profile (for example, the git_master-bds-dev).
+"""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import logging
+import time
+
+from mobly import asserts
+from mobly import test_runner
+from blueberry.utils import blueberry_base_test
+from blueberry.utils import bt_test_utils
+
+MUSIC_FILE = '1khz.wav'
+
+
+class BluetoothAudioCaptureTest(blueberry_base_test.BlueberryBaseTest):
+
+ def setup_class(self):
+ """Standard Mobly setup class."""
+ super(BluetoothAudioCaptureTest, self).setup_class()
+ self.derived_bt_device = self.derived_bt_devices[0]
+ for device in self.android_devices:
+ device.init_setup()
+ device.sl4a_setup()
+ self.pri_phone = self.android_devices[0]
+ self.mac_address = self.derived_bt_device.get_bluetooth_mac_address()
+ self.derived_bt_device.activate_pairing_mode()
+ self.pri_phone.sl4a.bluetoothDiscoverAndBond(self.mac_address)
+ self.pri_phone.wait_for_connection_success(self.mac_address)
+ # Gives more time for the pairing between the pri_phone and the
+ # derived_bt_device (the android bt target device)
+ time.sleep(3)
+ self.derived_bt_device.add_sec_ad_device(self.pri_phone)
+ self.derived_bt_device.disconnect_all()
+ self.duration = self.derived_bt_device.audio_params['duration']
+ self.recorded_duration = 0
+
+ def setup_test(self):
+ """Setup for bluetooth latency test."""
+ logging.info('Setup Test for audio capture test')
+ super(BluetoothAudioCaptureTest, self).setup_test()
+ asserts.assert_true(self.derived_bt_device.a2dp_sink_connect(),
+ 'Failed to establish A2dp Sink connection')
+
+ def test_audio_capture(self):
+ """Tests the audio capture for the android bt target device."""
+
+ music_file = self.derived_bt_device.audio_params.get(
+ 'music_file', MUSIC_FILE)
+ music_file = 'file:///sdcard/Music/{}'.format(music_file)
+ self.pri_phone.sl4a.mediaPlayOpen(music_file)
+ self.pri_phone.sl4a.mediaPlaySetLooping()
+ self.pri_phone.sl4a.mediaPlayStart()
+ time.sleep(3)
+ self.pri_phone.log.info(self.pri_phone.sl4a.mediaPlayGetInfo())
+ self.derived_bt_device.start_audio_capture()
+ time.sleep(self.duration)
+ audio_captured = self.derived_bt_device.stop_audio_capture()
+ self.pri_phone.sl4a.mediaPlayStop()
+ self.pri_phone.sl4a.mediaPlayClose()
+ self.derived_bt_device.log.info('Audio play and record stopped')
+ self.recorded_duration = bt_test_utils.get_duration_seconds(audio_captured)
+ self.derived_bt_device.log.info(
+ 'The capture duration is %s s and the recorded duration is %s s',
+ self.duration, self.recorded_duration)
+
+ def teardown_class(self):
+ logging.info('Factory resetting Bluetooth on devices.')
+ self.pri_phone.factory_reset_bluetooth()
+ self.derived_bt_device.factory_reset_bluetooth()
+ super(BluetoothAudioCaptureTest, self).teardown_class()
+ self.derived_bt_device.stop_all_services()
+ self.record_data({
+ 'Test Name': 'test_audio_capture',
+ 'sponge_properties': {
+ 'duration': self.duration,
+ 'recorded duration': self.recorded_duration
+ }
+ })
+
+
+if __name__ == '__main__':
+ test_runner.main()
diff --git a/blueberry/tests/avrcp/bluetooth_avrcp_test.py b/blueberry/tests/avrcp/bluetooth_avrcp_test.py
new file mode 100644
index 0000000..484fcd9
--- /dev/null
+++ b/blueberry/tests/avrcp/bluetooth_avrcp_test.py
@@ -0,0 +1,349 @@
+# Lint as: python3
+"""Tests for AVRCP basic functionality."""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import time
+
+from mobly import test_runner
+from mobly import signals
+from mobly.controllers.android_device_lib import adb
+from blueberry.controllers import android_bt_target_device
+from blueberry.utils import blueberry_base_test
+from blueberry.utils import bt_constants
+
+# The audio source path of BluetoothMediaPlayback in the SL4A app.
+ANDROID_MEDIA_PATH = '/sdcard/Music/test'
+
+# Timeout for track change and playback state update in second.
+MEDIA_UPDATE_TIMEOUT_SEC = 3
+
+
+class BluetoothAvrcpTest(blueberry_base_test.BlueberryBaseTest):
+ """Test Class for Bluetooth AVRCP.
+
+ This test requires two or more audio files exist in path "/sdcard/Music/test"
+ on the primary device, and device controllers need to have the following APIs:
+ 1. play()
+ 2. pause()
+ 3. track_previous()
+ 4. track_next()
+ """
+
+ def setup_class(self):
+ """Standard Mobly setup class."""
+ super(BluetoothAvrcpTest, self).setup_class()
+
+ for device in self.android_devices:
+ device.init_setup()
+ device.sl4a_setup()
+
+ # The device which role is AVRCP Target (TG).
+ self.pri_device = self.android_devices[0]
+
+ if len(self.android_devices) > 1 and not self.derived_bt_devices:
+ self.derived_bt_device = self.android_devices[1]
+ else:
+ self.derived_bt_device = self.derived_bt_devices[0]
+
+ # Check if the derived bt device is android bt target device.
+ self.is_android_bt_target_device = isinstance(
+ self.derived_bt_device, android_bt_target_device.AndroidBtTargetDevice)
+
+ # Check if the audio files exist on the primary device.
+ try:
+ self.audio_files = self.pri_device.adb.shell(
+ 'ls %s' % ANDROID_MEDIA_PATH).decode().split('\n')[:-1]
+ if len(self.audio_files) < 2:
+ raise signals.TestError(
+ 'Please push two or more audio files to %s on the primary device '
+ '"%s".' % (ANDROID_MEDIA_PATH, self.pri_device.serial))
+ except adb.AdbError as error:
+ if 'No such file or directory' in str(error):
+ raise signals.TestError(
+ 'No directory "%s" found on the primary device "%s".' %
+ (ANDROID_MEDIA_PATH, self.pri_device.serial))
+ raise error
+
+ self.mac_address = self.derived_bt_device.get_bluetooth_mac_address()
+ self.derived_bt_device.activate_pairing_mode()
+ self.pri_device.set_target(self.derived_bt_device)
+ self.pri_device.pair_and_connect_bluetooth(self.mac_address)
+ self.pri_device.allow_extra_permissions()
+ # Gives more time for the pairing between two devices.
+ time.sleep(3)
+
+ if self.is_android_bt_target_device:
+ self.derived_bt_device.add_sec_ad_device(self.pri_device)
+
+ # Starts BluetoothSL4AAudioSrcMBS on the phone.
+ if self.is_android_bt_target_device:
+ self.derived_bt_device.init_ambs_for_avrcp()
+ else:
+ self.pri_device.sl4a.bluetoothMediaPhoneSL4AMBSStart()
+ # Waits for BluetoothSL4AAudioSrcMBS to be active.
+ time.sleep(1)
+ # Changes the playback state to Playing in order to other Media passthrough
+ # commands can work.
+ self.pri_device.sl4a.bluetoothMediaHandleMediaCommandOnPhone(
+ bt_constants.CMD_MEDIA_PLAY)
+
+ # Collects media metadata of all tracks.
+ self.tracks = []
+ for _ in range(len(self.audio_files)):
+ self.tracks.append(self.pri_device.get_current_track_info())
+ self.pri_device.sl4a.bluetoothMediaHandleMediaCommandOnPhone(
+ bt_constants.CMD_MEDIA_SKIP_NEXT)
+ self.pri_device.log.info('Tracks: %s' % self.tracks)
+
+ # Sets Playback state to Paused as default.
+ self.pri_device.sl4a.bluetoothMediaHandleMediaCommandOnPhone(
+ bt_constants.CMD_MEDIA_PAUSE)
+
+ def teardown_class(self):
+ """Teardown class for bluetooth avrcp media play test."""
+ super(BluetoothAvrcpTest, self).teardown_class()
+ # Stops BluetoothSL4AAudioSrcMBS after all test methods finish.
+ if self.is_android_bt_target_device:
+ self.derived_bt_device.stop_ambs_for_avrcp()
+ else:
+ self.pri_device.sl4a.bluetoothMediaPhoneSL4AMBSStop()
+
+ def teardown_test(self):
+ """Teardown test for bluetooth avrcp media play test."""
+ super(BluetoothAvrcpTest, self).teardown_test()
+ # Sets Playback state to Paused after a test method finishes.
+ self.pri_device.sl4a.bluetoothMediaHandleMediaCommandOnPhone(
+ bt_constants.CMD_MEDIA_PAUSE)
+
+ def wait_for_media_info_sync(self):
+ """Waits for sync Media information between two sides.
+
+ Waits for sync the current playback state and Now playing track info from
+ the android bt target device to the phone.
+ """
+ # Check if Playback state is sync.
+ expected_state = self.pri_device.get_current_playback_state()
+ self.derived_bt_device.verify_playback_state_changed(
+ expected_state=expected_state,
+ exception=signals.TestError(
+ 'Playback state is not equivalent between two sides. '
+ '"%s" != "%s"' %
+ (self.derived_bt_device.get_current_playback_state(),
+ expected_state)))
+
+ # Check if Now Playing track is sync.
+ expected_track = self.pri_device.get_current_track_info()
+ self.derived_bt_device.verify_current_track_changed(
+ expected_track=expected_track,
+ exception=signals.TestError(
+ 'Now Playing track is not equivalent between two sides. '
+ '"%s" != "%s"' %
+ (self.derived_bt_device.get_current_track_info(), expected_track)))
+
+ def execute_media_play_pause_test_logic(self, command_sender, test_command):
+ """Executes the test logic of the media command "play" or "pause".
+
+ Steps:
+ 1. Correct the playback state if needed.
+ 2. Send a media passthrough command.
+ 3. Verify that the playback state is changed from AVRCP TG and CT.
+
+ Args:
+ command_sender: a device controller sending the command.
+ test_command: string, the media passthrough command for testing, either
+ "play" or "pause".
+
+ Raises:
+ signals.TestError: raised if the test command is invalid.
+ """
+ # Checks if the test command is valid.
+ if test_command not in [bt_constants.CMD_MEDIA_PLAY,
+ bt_constants.CMD_MEDIA_PAUSE]:
+ raise signals.TestError(
+ 'Command "%s" is invalid. The test command should be "%s" or "%s".' %
+ (test_command, bt_constants.CMD_MEDIA_PLAY,
+ bt_constants.CMD_MEDIA_PAUSE))
+
+ # Make sure the playback state is playing if testing the command "pause".
+ if (self.pri_device.get_current_playback_state() !=
+ bt_constants.STATE_PLAYING and
+ test_command == bt_constants.CMD_MEDIA_PAUSE):
+ self.pri_device.sl4a.bluetoothMediaHandleMediaCommandOnPhone(
+ bt_constants.CMD_MEDIA_PLAY)
+
+ # Makes sure Media info is the same between two sides.
+ if self.is_android_bt_target_device:
+ self.wait_for_media_info_sync()
+ self.pri_device.log.info(
+ 'Current playback state: %s' %
+ self.pri_device.get_current_playback_state())
+
+ expected_state = None
+ if test_command == bt_constants.CMD_MEDIA_PLAY:
+ command_sender.play()
+ expected_state = bt_constants.STATE_PLAYING
+ elif test_command == bt_constants.CMD_MEDIA_PAUSE:
+ command_sender.pause()
+ expected_state = bt_constants.STATE_PAUSED
+
+ # Verify that the playback state is changed.
+ self.pri_device.log.info('Expected playback state: %s' % expected_state)
+ device_check_list = [self.pri_device]
+ # Check the playback state from the android bt target device.
+ if self.is_android_bt_target_device:
+ device_check_list.append(self.derived_bt_device)
+ for device in device_check_list:
+ device.verify_playback_state_changed(
+ expected_state=expected_state,
+ exception=signals.TestFailure(
+ 'Playback state is not changed to "%s" from the device "%s". '
+ 'Current state: %s' %
+ (expected_state, device.serial,
+ device.get_current_playback_state())))
+
+ def execute_skip_next_prev_test_logic(self, command_sender, test_command):
+ """Executes the test logic of the media command "skipNext" or "skipPrev".
+
+ Steps:
+ 1. Correct the Now Playing track if needed.
+ 2. Send a media passthrough command.
+ 3. Verify that the Now Playing track is changed from AVRCP TG and CT.
+
+ Args:
+ command_sender: a device controller sending the command.
+ test_command: string, the media passthrough command for testing, either
+ "skipNext" or "skipPrev".
+
+ Raises:
+ signals.TestError: raised if the test command is invalid.
+ """
+ # Checks if the test command is valid.
+ if test_command not in [bt_constants.CMD_MEDIA_SKIP_NEXT,
+ bt_constants.CMD_MEDIA_SKIP_PREV]:
+ raise signals.TestError(
+ 'Command "%s" is invalid. The test command should be "%s" or "%s".' %
+ (test_command, bt_constants.CMD_MEDIA_SKIP_NEXT,
+ bt_constants.CMD_MEDIA_SKIP_PREV))
+
+ # Make sure the track index is not 0 if testing the command "skipPrev".
+ if (self.tracks.index(self.pri_device.get_current_track_info()) == 0
+ and test_command == bt_constants.CMD_MEDIA_SKIP_PREV):
+ self.pri_device.sl4a.bluetoothMediaHandleMediaCommandOnPhone(
+ bt_constants.CMD_MEDIA_SKIP_NEXT)
+
+ # Makes sure Media info is the same between two sides.
+ if self.is_android_bt_target_device:
+ self.wait_for_media_info_sync()
+ current_track = self.pri_device.get_current_track_info()
+ current_index = self.tracks.index(current_track)
+ self.pri_device.log.info('Current track: %s' % current_track)
+
+ expected_track = None
+ if test_command == bt_constants.CMD_MEDIA_SKIP_NEXT:
+ command_sender.track_next()
+ # It will return to the first track by skipNext if now playing is the last
+ # track.
+ if current_index + 1 == len(self.tracks):
+ expected_track = self.tracks[0]
+ else:
+ expected_track = self.tracks[current_index + 1]
+ elif test_command == bt_constants.CMD_MEDIA_SKIP_PREV:
+ command_sender.track_previous()
+ expected_track = self.tracks[current_index - 1]
+
+ # Verify that the now playing track is changed.
+ self.pri_device.log.info('Expected track: %s' % expected_track)
+ device_check_list = [self.pri_device]
+ # Check the playback state from the android bt target device.
+ if self.is_android_bt_target_device:
+ device_check_list.append(self.derived_bt_device)
+ for device in device_check_list:
+ device.verify_current_track_changed(
+ expected_track=expected_track,
+ exception=signals.TestFailure(
+ 'Now Playing track is not changed to "%s" from the device "%s". '
+ 'Current track: %s' %
+ (expected_track, device.serial, device.get_current_track_info())))
+
+ def test_media_pause(self):
+ """Tests the media pause from AVRCP Controller."""
+ self.execute_media_play_pause_test_logic(
+ command_sender=self.derived_bt_device,
+ test_command=bt_constants.CMD_MEDIA_PAUSE)
+
+ def test_media_play(self):
+ """Tests the media play from AVRCP Controller."""
+ self.execute_media_play_pause_test_logic(
+ command_sender=self.derived_bt_device,
+ test_command=bt_constants.CMD_MEDIA_PLAY)
+
+ def test_media_skip_prev(self):
+ """Tests the media skip prev from AVRCP Controller."""
+ self.execute_skip_next_prev_test_logic(
+ command_sender=self.derived_bt_device,
+ test_command=bt_constants.CMD_MEDIA_SKIP_PREV)
+
+ def test_media_skip_next(self):
+ """Tests the media skip next from AVRCP Controller."""
+ self.execute_skip_next_prev_test_logic(
+ command_sender=self.derived_bt_device,
+ test_command=bt_constants.CMD_MEDIA_SKIP_NEXT)
+
+ def test_media_pause_from_phone(self):
+ """Tests the media pause from AVRCP Target.
+
+ Tests that Playback state of AVRCP Controller will be changed to paused when
+ AVRCP Target sends the command "pause".
+ """
+ if not self.is_android_bt_target_device:
+ signals.TestError('The test requires an android bt target device.')
+
+ self.execute_media_play_pause_test_logic(
+ command_sender=self.pri_device,
+ test_command=bt_constants.CMD_MEDIA_PAUSE)
+
+ def test_media_play_from_phone(self):
+ """Tests the media play from AVRCP Target.
+
+ Tests that Playback state of AVRCP Controller will be changed to playing
+ when AVRCP Target sends the command "play".
+ """
+ if not self.is_android_bt_target_device:
+ signals.TestError('The test requires an android bt target device.')
+
+ self.execute_media_play_pause_test_logic(
+ command_sender=self.pri_device,
+ test_command=bt_constants.CMD_MEDIA_PLAY)
+
+ def test_media_skip_prev_from_phone(self):
+ """Tests the media skip prev from AVRCP Target.
+
+ Tests that Now Playing track of AVRCP Controller will be changed to the
+ previous track when AVRCP Target sends the command "skipPrev".
+ """
+ if not self.is_android_bt_target_device:
+ signals.TestError('The test requires an android bt target device.')
+
+ self.execute_skip_next_prev_test_logic(
+ command_sender=self.pri_device,
+ test_command=bt_constants.CMD_MEDIA_SKIP_PREV)
+
+ def test_media_skip_next_from_phone(self):
+ """Tests the media skip next from AVRCP Target.
+
+ Tests that Now Playing track of AVRCP Controller will be changed to the next
+ track when AVRCP Target sends the command "skipNext".
+ """
+ if not self.is_android_bt_target_device:
+ signals.TestError('The test requires an android bt target device.')
+
+ self.execute_skip_next_prev_test_logic(
+ command_sender=self.pri_device,
+ test_command=bt_constants.CMD_MEDIA_SKIP_NEXT)
+
+
+if __name__ == '__main__':
+ test_runner.main()
diff --git a/blueberry/tests/connectivity/bluetooth_connection_test.py b/blueberry/tests/connectivity/bluetooth_connection_test.py
new file mode 100644
index 0000000..767af38
--- /dev/null
+++ b/blueberry/tests/connectivity/bluetooth_connection_test.py
@@ -0,0 +1,96 @@
+"""Tests for Bluetooth connection with Android device and a Bluetooth device."""
+
+import time
+
+from mobly import test_runner
+from blueberry.utils import blueberry_base_test
+
+# Connection state change sleep time in seconds.
+CONNECTION_STATE_CHANGE_SLEEP_SEC = 5
+
+
+class BluetoothConnectionTest(blueberry_base_test.BlueberryBaseTest):
+ """Test Class for Bluetooth connection testing.
+
+ Attributes:
+ primary_device: A primary device under test.
+ derived_bt_device: A Bluetooth device which is used to connected to the
+ primary device in the test.
+ """
+
+ def setup_class(self):
+ super().setup_class()
+ self.primary_device = self.android_devices[0]
+ self.primary_device.init_setup()
+
+ self.derived_bt_device = self.derived_bt_devices[0]
+ self.derived_bt_device.factory_reset_bluetooth()
+ self.mac_address = self.derived_bt_device.get_bluetooth_mac_address()
+ self.derived_bt_device.activate_pairing_mode()
+ self.primary_device.pair_and_connect_bluetooth(self.mac_address)
+
+ def setup_test(self):
+ super().setup_test()
+ # Checks if A2DP and HSP profiles are connected.
+ self.wait_for_a2dp_and_hsp_connection_state(connected=True)
+ # Buffer between tests.
+ time.sleep(CONNECTION_STATE_CHANGE_SLEEP_SEC)
+
+ def wait_for_a2dp_and_hsp_connection_state(self, connected):
+ """Asserts that A2DP and HSP connections are in the expected state.
+
+ Args:
+ connected: bool, True if the expected state is connected else False.
+ """
+ self.primary_device.wait_for_a2dp_connection_state(self.mac_address,
+ connected)
+ self.primary_device.wait_for_hsp_connection_state(self.mac_address,
+ connected)
+
+ def test_disconnect_and_connect(self):
+ """Test for DUT disconnecting and then connecting to the remote device."""
+ self.primary_device.log.info('Disconnecting the device "%s"...' %
+ self.mac_address)
+ self.primary_device.disconnect_bluetooth(self.mac_address)
+ self.wait_for_a2dp_and_hsp_connection_state(connected=False)
+ # Buffer time for connection state change.
+ time.sleep(CONNECTION_STATE_CHANGE_SLEEP_SEC)
+ self.primary_device.log.info('Connecting the device "%s"...' %
+ self.mac_address)
+ self.primary_device.connect_bluetooth(self.mac_address)
+ self.wait_for_a2dp_and_hsp_connection_state(connected=True)
+
+ def test_reconnect_when_enabling_bluetooth(self):
+ """Test for DUT reconnecting to the remote device when Bluetooth enabled."""
+ self.primary_device.log.info('Turning off Bluetooth...')
+ self.primary_device.sl4a.bluetoothToggleState(False)
+ self.primary_device.wait_for_bluetooth_toggle_state(enabled=False)
+ self.primary_device.wait_for_disconnection_success(self.mac_address)
+ time.sleep(CONNECTION_STATE_CHANGE_SLEEP_SEC)
+ self.primary_device.log.info('Turning on Bluetooth...')
+ self.primary_device.sl4a.bluetoothToggleState(True)
+ self.primary_device.wait_for_bluetooth_toggle_state(enabled=True)
+ self.primary_device.wait_for_connection_success(self.mac_address)
+ self.wait_for_a2dp_and_hsp_connection_state(connected=True)
+
+ def test_reconnect_when_connected_device_powered_on(self):
+ """Test for the remote device reconnecting to DUT.
+
+ Tests that DUT can be disconnected when the remoted device is powerd off,
+ and then reconnected when the remote device is powered on.
+ """
+ self.primary_device.log.info(
+ 'The connected device "%s" is being powered off...' % self.mac_address)
+ self.derived_bt_device.power_off()
+ self.primary_device.wait_for_disconnection_success(self.mac_address)
+ self.wait_for_a2dp_and_hsp_connection_state(connected=False)
+ time.sleep(CONNECTION_STATE_CHANGE_SLEEP_SEC)
+ self.derived_bt_device.power_on()
+ self.primary_device.log.info(
+ 'The connected device "%s" is being powered on...' % self.mac_address)
+ self.primary_device.wait_for_connection_success(self.mac_address)
+ self.wait_for_a2dp_and_hsp_connection_state(connected=True)
+
+
+if __name__ == '__main__':
+ test_runner.main()
diff --git a/blueberry/tests/connectivity/bluetooth_latency_test.py b/blueberry/tests/connectivity/bluetooth_latency_test.py
new file mode 100644
index 0000000..0facbdc
--- /dev/null
+++ b/blueberry/tests/connectivity/bluetooth_latency_test.py
@@ -0,0 +1,132 @@
+# Lint as: python3
+"""Tests for blueberry.tests.bluetooth.bluetooth_latency."""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import logging
+import math
+import random
+import string
+import time
+
+from mobly import asserts
+from mobly import test_runner
+from mobly.signals import TestAbortClass
+# Internal import
+from blueberry.utils import blueberry_base_test
+from blueberry.utils import bt_test_utils
+from blueberry.utils import metrics_utils
+# Internal import
+
+
+class BluetoothLatencyTest(blueberry_base_test.BlueberryBaseTest):
+
+ @retry.logged_retry_on_exception(
+ retry_intervals=retry.FuzzedExponentialIntervals(
+ initial_delay_sec=2, factor=5, num_retries=5, max_delay_sec=300))
+ def _measure_latency(self):
+ """Measures the latency of data transfer over RFCOMM.
+
+ Sends data from the client device that is read by the server device.
+ Calculates the latency of the transfer.
+
+ Returns:
+ The latency of the transfer milliseconds.
+ """
+
+ # Generates a random message to transfer
+ message = (''.join(
+ random.choice(string.ascii_letters + string.digits) for _ in range(6)))
+ start_time = time.time()
+ write_read_successful = bt_test_utils.write_read_verify_data_sl4a(
+ self.phone, self.derived_bt_device, message, False)
+ end_time = time.time()
+ asserts.assert_true(write_read_successful, 'Failed to send/receive message')
+ return (end_time - start_time) * 1000
+
+ def setup_class(self):
+ """Standard Mobly setup class."""
+ super(BluetoothLatencyTest, self).setup_class()
+ if len(self.android_devices) < 2:
+ raise TestAbortClass(
+ 'Not enough android phones detected (need at least two)')
+ self.phone = self.android_devices[0]
+ self.phone.init_setup()
+ self.phone.sl4a_setup()
+
+ # We treat the secondary phone as a derived_bt_device in order for the
+ # generic script to work with this android phone properly. Data will be sent
+ # from first phone to the second phone.
+ self.derived_bt_device = self.android_devices[1]
+ self.derived_bt_device.init_setup()
+ self.derived_bt_device.sl4a_setup()
+ self.set_btsnooplogmode_full(self.phone)
+ self.set_btsnooplogmode_full(self.derived_bt_device)
+
+ self.metrics = (
+ metrics_utils.BluetoothMetricLogger(
+ metrics_pb2.BluetoothDataTestResult()))
+ self.metrics.add_primary_device_metrics(self.phone)
+ self.metrics.add_connected_device_metrics(self.derived_bt_device)
+
+ self.data_transfer_type = metrics_pb2.BluetoothDataTestResult.RFCOMM
+ self.iterations = int(self.user_params.get('iterations', 300))
+ logging.info('Running Bluetooth latency test %s times.', self.iterations)
+ logging.info('Successfully found required devices.')
+
+ def setup_test(self):
+ """Setup for bluetooth latency test."""
+ logging.info('Setup Test for test_bluetooth_latency')
+ super(BluetoothLatencyTest, self).setup_test()
+ asserts.assert_true(self.phone.connect_with_rfcomm(self.derived_bt_device),
+ 'Failed to establish RFCOMM connection')
+
+ def test_bluetooth_latency(self):
+ """Tests the latency for a data transfer over RFCOMM."""
+
+ metrics = {}
+ latency_list = []
+
+ for _ in range(self.iterations):
+ latency_list.append(self._measure_latency())
+
+ metrics['data_transfer_protocol'] = self.data_transfer_type
+ metrics['data_latency_min_millis'] = int(min(latency_list))
+ metrics['data_latency_max_millis'] = int(max(latency_list))
+ metrics['data_latency_avg_millis'] = int(
+ math.fsum(latency_list) / float(len(latency_list)))
+ logging.info('Latency: %s', metrics)
+
+ asserts.assert_true(metrics['data_latency_min_millis'] > 0,
+ 'Minimum latency must be greater than 0!')
+ self.metrics.add_test_metrics(metrics)
+ for metric in metrics:
+ self.record_data({
+ 'Test Name': 'test_bluetooth_latency',
+ 'sponge_properties': {
+ metric: metrics[metric],
+ }
+ })
+
+ def teardown_class(self):
+ logging.info('Factory resetting Bluetooth on devices.')
+ self.phone.sl4a.bluetoothSocketConnStop()
+ self.derived_bt_device.sl4a.bluetoothSocketConnStop()
+ self.phone.factory_reset_bluetooth()
+ self.derived_bt_device.factory_reset_bluetooth()
+ super(BluetoothLatencyTest, self).teardown_class()
+ self.record_data({
+ 'Test Name': 'test_bluetooth_latency',
+ 'sponge_properties': {
+ 'proto_ascii':
+ self.metrics.proto_message_to_ascii(),
+ 'primary_device_build':
+ self.phone.get_device_info()['android_release_id']
+ }
+ })
+
+
+if __name__ == '__main__':
+ test_runner.main()
diff --git a/blueberry/tests/connectivity/bluetooth_pairing_test.py b/blueberry/tests/connectivity/bluetooth_pairing_test.py
new file mode 100644
index 0000000..f3c1770
--- /dev/null
+++ b/blueberry/tests/connectivity/bluetooth_pairing_test.py
@@ -0,0 +1,81 @@
+"""Tests for blueberry.tests.bluetooth_pairing."""
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import logging
+
+from mobly import test_runner
+from blueberry.utils import blueberry_base_test
+
+
+class BluetoothPairingTest(blueberry_base_test.BlueberryBaseTest):
+ """Test Class for Bluetooth Pairing Test.
+
+ Test will reset the bluetooth settings on the phone and attempt to pair
+ with the derived_bt_device specified in the configuration file.
+ """
+
+ def setup_class(self):
+ """Standard Mobly setup class."""
+ super(BluetoothPairingTest, self).setup_class()
+ # Adds a use case that derived_bt_device initiates a pairing request to
+ # primary_device. Enable this case if allow_pairing_reverse is 1.
+ self.allow_pairing_reverse = int(self.user_params.get(
+ 'allow_pairing_reverse', 0))
+
+ if self.android_devices:
+ self.primary_device = self.android_devices[0]
+ self.primary_device.init_setup()
+ self.primary_device.sl4a_setup()
+
+ if len(self.android_devices) > 1 and not self.derived_bt_devices:
+ # In the case of pairing phone to phone, we need to treat the
+ # secondary phone as a derived_bt_device in order for the generic script
+ # to work with this android phone properly.
+ self.derived_bt_device = self.android_devices[1]
+ self.derived_bt_device.init_setup()
+ self.derived_bt_device.sl4a_setup()
+ else:
+ self.derived_bt_device = self.derived_bt_devices[0]
+ self.derived_bt_device.factory_reset_bluetooth()
+ else:
+ # In the case of pairing mock to mock, at least 2 derived_bt_device is
+ # required. The first derived_bt_device is treated as primary_device.
+ self.primary_device = self.derived_bt_devices[0]
+ self.primary_device.init_setup()
+ self.derived_bt_device = self.derived_bt_devices[1]
+ self.derived_bt_device.factory_reset_bluetooth()
+
+ def setup_test(self):
+ """Setup for pairing test."""
+ logging.info('Setup Test for test_pair_and_bond')
+ super(BluetoothPairingTest, self).setup_test()
+
+ def test_pair_and_bond(self):
+ """Test for pairing and bonding a phone with a bluetooth device.
+
+ Initiates pairing from the phone and checks for 20 seconds that
+ the device is connected.
+ """
+ device_list = [(self.primary_device, self.derived_bt_device)]
+ if self.allow_pairing_reverse:
+ device_list.append((self.derived_bt_device, self.primary_device))
+ for initiator, receiver in device_list:
+ # get mac address of device to pair with
+ mac_address = receiver.get_bluetooth_mac_address()
+ logging.info('Receiver BT MAC Address: %s', mac_address)
+ # put device into pairing mode
+ receiver.activate_pairing_mode()
+ # initiate pairing from initiator
+ initiator.set_target(receiver)
+ initiator.pair_and_connect_bluetooth(mac_address)
+ if self.allow_pairing_reverse and initiator != self.derived_bt_device:
+ logging.info('===== Reversing Pairing =====')
+ # Resets Bluetooth status for two sides.
+ initiator.factory_reset_bluetooth()
+ receiver.factory_reset_bluetooth()
+
+
+if __name__ == '__main__':
+ test_runner.main()
diff --git a/blueberry/tests/connectivity/bluetooth_throughput_test.py b/blueberry/tests/connectivity/bluetooth_throughput_test.py
new file mode 100644
index 0000000..79ac2e2
--- /dev/null
+++ b/blueberry/tests/connectivity/bluetooth_throughput_test.py
@@ -0,0 +1,196 @@
+# Lint as: python3
+"""Tests for blueberry.tests.bluetooth.bluetooth_throughput."""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import logging
+import math
+
+from mobly import asserts
+from mobly import test_runner
+from mobly.controllers.android_device_lib.jsonrpc_client_base import ApiError
+from mobly.signals import TestAbortClass
+# Internal import
+from blueberry.utils import blueberry_base_test
+from blueberry.utils import metrics_utils
+# Internal import
+
+
+class BluetoothThroughputTest(blueberry_base_test.BlueberryBaseTest):
+
+ @retry.logged_retry_on_exception(
+ retry_intervals=retry.FuzzedExponentialIntervals(
+ initial_delay_sec=2, factor=5, num_retries=5, max_delay_sec=300))
+ def _measure_throughput(self, num_of_buffers, buffer_size):
+ """Measures the throughput of a data transfer.
+
+ Sends data from the client device that is read by the server device.
+ Calculates the throughput for the transfer.
+
+ Args:
+ num_of_buffers: An integer value designating the number of buffers
+ to be sent.
+ buffer_size: An integer value designating the size of each buffer,
+ in bytes.
+
+ Returns:
+ The throughput of the transfer in bytes per second.
+ """
+
+ # TODO(user): Need to fix throughput send/receive methods
+ (self.phone.sl4a
+ .bluetoothConnectionThroughputSend(num_of_buffers, buffer_size))
+
+ throughput = (self.derived_bt_device.sl4a
+ .bluetoothConnectionThroughputRead(num_of_buffers,
+ buffer_size))
+ return throughput
+
+ def _throughput_test(self, buffer_size, test_name):
+ logging.info('throughput test with buffer_size: %d and testname: %s',
+ buffer_size, test_name)
+ metrics = {}
+ throughput_list = []
+ num_of_buffers = 1
+ for _ in range(self.iterations):
+ throughput = self._measure_throughput(num_of_buffers, buffer_size)
+ logging.info('Throughput: %d bytes-per-sec', throughput)
+ throughput_list.append(throughput)
+
+ metrics['data_transfer_protocol'] = self.data_transfer_type
+ metrics['data_packet_size'] = buffer_size
+ metrics['data_throughput_min_bytes_per_second'] = int(
+ min(throughput_list))
+ metrics['data_throughput_max_bytes_per_second'] = int(
+ max(throughput_list))
+ metrics['data_throughput_avg_bytes_per_second'] = int(
+ math.fsum(throughput_list) / float(len(throughput_list)))
+
+ logging.info('Throughput at large buffer: %s', metrics)
+
+ asserts.assert_true(metrics['data_throughput_min_bytes_per_second'] > 0,
+ 'Minimum throughput must be greater than 0!')
+
+ self.metrics.add_test_metrics(metrics)
+ for metric in metrics:
+ self.record_data({
+ 'Test Name': test_name,
+ 'sponge_properties': {
+ metric: metrics[metric],
+ }
+ })
+ self.record_data({
+ 'Test Name': test_name,
+ 'sponge_properties': {
+ 'proto_ascii':
+ self.metrics.proto_message_to_ascii(),
+ 'primary_device_build':
+ self.phone.get_device_info()['android_release_id']
+ }
+ })
+
+ def setup_class(self):
+ """Standard Mobly setup class."""
+ super(BluetoothThroughputTest, self).setup_class()
+ if len(self.android_devices) < 2:
+ raise TestAbortClass(
+ 'Not enough android phones detected (need at least two)')
+ self.phone = self.android_devices[0]
+
+ # We treat the secondary phone as a derived_bt_device in order for the
+ # generic script to work with this android phone properly. Data will be sent
+ # from first phone to the second phone.
+ self.derived_bt_device = self.android_devices[1]
+ self.phone.init_setup()
+ self.derived_bt_device.init_setup()
+ self.phone.sl4a_setup()
+ self.derived_bt_device.sl4a_setup()
+ self.set_btsnooplogmode_full(self.phone)
+ self.set_btsnooplogmode_full(self.derived_bt_device)
+
+ self.metrics = (
+ metrics_utils.BluetoothMetricLogger(
+ metrics_pb2.BluetoothDataTestResult()))
+ self.metrics.add_primary_device_metrics(self.phone)
+ self.metrics.add_connected_device_metrics(self.derived_bt_device)
+
+ self.data_transfer_type = metrics_pb2.BluetoothDataTestResult.RFCOMM
+ self.iterations = int(self.user_params.get('iterations', 300))
+ logging.info('Running Bluetooth throughput test %s times.', self.iterations)
+ logging.info('Successfully found required devices.')
+
+ def setup_test(self):
+ """Setup for bluetooth latency test."""
+ logging.info('Setup Test for test_bluetooth_throughput')
+ super(BluetoothThroughputTest, self).setup_test()
+ asserts.assert_true(self.phone.connect_with_rfcomm(self.derived_bt_device),
+ 'Failed to establish RFCOMM connection')
+
+ def test_bluetooth_throughput_large_buffer(self):
+ """Tests the throughput with large buffer size.
+
+ Tests the throughput over a series of data transfers with large buffer size.
+ """
+ large_buffer_size = 300
+ test_name = 'test_bluetooth_throughput_large_buffer'
+ self._throughput_test(large_buffer_size, test_name)
+
+ def test_bluetooth_throughput_medium_buffer(self):
+ """Tests the throughput with medium buffer size.
+
+ Tests the throughput over a series of data transfers with medium buffer
+ size.
+ """
+ medium_buffer_size = 100
+ test_name = 'test_bluetooth_throughput_medium_buffer'
+ self._throughput_test(medium_buffer_size, test_name)
+
+ def test_bluetooth_throughput_small_buffer(self):
+ """Tests the throughput with small buffer size.
+
+ Tests the throughput over a series of data transfers with small buffer size.
+ """
+ small_buffer_size = 10
+ test_name = 'test_bluetooth_throughput_small_buffer'
+ self._throughput_test(small_buffer_size, test_name)
+
+ def test_maximum_buffer_size(self):
+ """Calculates the maximum allowed buffer size for one packet."""
+ current_buffer_size = 300
+ throughput = -1
+ num_of_buffers = 1
+ while True:
+ logging.info('Trying buffer size %d', current_buffer_size)
+ try:
+ throughput = self._measure_throughput(
+ num_of_buffers, current_buffer_size)
+ logging.info('The throughput is %d at buffer size of %d', throughput,
+ current_buffer_size)
+ except ApiError:
+ maximum_buffer_size = current_buffer_size - 1
+ logging.info('Max buffer size: %d bytes', maximum_buffer_size)
+ logging.info('Max throughput: %d bytes-per-second', throughput)
+ self.record_data({
+ 'Test Name': 'test_maximum_buffer_size',
+ 'sponge_properties': {
+ 'maximum_buffer_size': maximum_buffer_size
+ }
+ })
+ return True
+ current_buffer_size += 1
+
+ def teardown_test(self):
+ self.phone.sl4a.bluetoothSocketConnStop()
+ self.derived_bt_device.sl4a.bluetoothSocketConnStop()
+
+ def teardown_class(self):
+ self.phone.factory_reset_bluetooth()
+ self.derived_bt_device.factory_reset_bluetooth()
+ logging.info('Factory resetting Bluetooth on devices.')
+ super(BluetoothThroughputTest, self).teardown_class()
+
+
+if __name__ == '__main__':
+ test_runner.main()
diff --git a/blueberry/tests/gd/cert/cert_self_test.py b/blueberry/tests/gd/cert/cert_self_test.py
new file mode 100644
index 0000000..edfe10b
--- /dev/null
+++ b/blueberry/tests/gd/cert/cert_self_test.py
@@ -0,0 +1,280 @@
+#!/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 mobly import asserts
+from mobly import signals
+from mobly import test_runner
+from mobly import base_test
+
+from cert.metadata import metadata
+from cert.cert_self_test_lib import *
+
+
+class CertSelfTest(base_test.BaseTestClass):
+
+ def setup_test(self):
+ return True
+
+ def teardown_test(self):
+ return True
+
+ def test_assert_occurs_at_least_passes(self):
+ test_assert_occurs_at_least_passes_core()
+
+ def test_assert_occurs_passes(self):
+ test_assert_occurs_passes_core()
+
+ def test_assert_occurs_fails(self):
+ test_assert_occurs_fails_core()
+
+ def test_assert_occurs_at_most_passes(self):
+ test_assert_occurs_at_most_passes_core()
+
+ def test_assert_occurs_at_most_fails(self):
+ test_assert_occurs_at_most_fails_core()
+
+ def test_skip_a_test(self):
+ test_skip_a_test_core()
+
+ def test_nested_packets(self):
+ test_nested_packets_core()
+
+ def test_l2cap_config_options(self):
+ test_l2cap_config_options_core()
+
+ def test_assertThat_boolean_success(self):
+ test_assertThat_boolean_success_core()
+
+ def test_assertThat_boolean_falseIsTrue(self):
+ test_assertThat_boolean_falseIsTrue_core()
+
+ def test_assertThat_boolean_trueIsFalse(self):
+ test_assertThat_boolean_trueIsFalse_core()
+
+ def test_assertThat_object_success(self):
+ test_assertThat_object_success_core()
+
+ def test_assertThat_object_isEqualToFails(self):
+ test_assertThat_object_isEqualToFails_core()
+
+ def test_assertThat_object_isNotEqualToFails(self):
+ test_assertThat_object_isNotEqualToFails_core()
+
+ def test_assertThat_object_isNoneFails(self):
+ test_assertThat_object_isNoneFails_core()
+
+ def test_assertThat_object_isNotNoneFails(self):
+ test_assertThat_object_isNotNoneFails_core()
+
+ def test_assertThat_eventStream_emits_passes(self):
+ test_assertThat_eventStream_emits_passes_core()
+
+ def test_assertThat_eventStream_emits_then_passes(self):
+ test_assertThat_eventStream_emits_then_passes_core()
+
+ def test_assertThat_eventStream_emits_fails(self):
+ test_assertThat_eventStream_emits_fails_core()
+
+ def test_assertThat_eventStream_emits_then_fails(self):
+ test_assertThat_eventStream_emits_then_fails_core()
+
+ def test_assertThat_eventStream_emitsInOrder_passes(self):
+ test_assertThat_eventStream_emitsInOrder_passes_core()
+
+ def test_assertThat_eventStream_emitsInAnyOrder_passes(self):
+ test_assertThat_eventStream_emitsInAnyOrder_passes_core()
+
+ def test_assertThat_eventStream_emitsInOrder_fails(self):
+ test_assertThat_eventStream_emitsInOrder_fails_core()
+
+ def test_assertThat_eventStream_emitsInAnyOrder_fails(self):
+ test_assertThat_eventStream_emitsInAnyOrder_fails_core()
+
+ def test_assertThat_emitsNone_passes(self):
+ test_assertThat_emitsNone_passes_core()
+
+ def test_assertThat_emitsNone_passes_after_1_second(self):
+ test_assertThat_emitsNone_passes_after_1_second_core()
+
+ def test_assertThat_emitsNone_fails(self):
+ test_assertThat_emitsNone_fails_core()
+
+ def test_assertThat_emitsNone_zero_passes(self):
+ test_assertThat_emitsNone_zero_passes_core()
+
+ def test_assertThat_emitsNone_zero_passes_after_one_second(self):
+ test_assertThat_emitsNone_zero_passes_after_one_second_core()
+
+ def test_assertThat_emitsNone_zero_fails(self):
+ test_assertThat_emitsNone_zero_fails_core()
+
+ def test_filtering_event_stream_none_filter_function(self):
+ test_filtering_event_stream_none_filter_function_core()
+
+ def test_metadata_empty(self):
+
+ @metadata()
+ def simple_pass_test(arg):
+ pass
+
+ try:
+ simple_pass_test(1)
+ except signals.TestFailure:
+ pass
+ except Exception as e:
+ asserts.fail("@metadata() should only raise signals.TestFailure, "
+ "but raised %s with msg %s instead" % (e.__class__.__name__, str(e)))
+ else:
+ asserts.fail("@metadata() should not work")
+
+ def test_metadata_empty_no_function_call(self):
+
+ @metadata
+ def simple_pass_test(arg):
+ pass
+
+ try:
+ simple_pass_test(1)
+ except signals.TestFailure:
+ pass
+ except Exception as e:
+ asserts.fail("@metadata should only raise signals.TestFailure, "
+ "but raised %s with msg %s instead" % (e.__class__.__name__, str(e)))
+ else:
+ asserts.fail("@metadata should not work")
+
+ def test_metadata_pts_missing_id(self):
+
+ @metadata(pts_test_name="Hello world")
+ def simple_pass_test(arg):
+ pass
+
+ try:
+ simple_pass_test(1)
+ except signals.TestFailure:
+ pass
+ except Exception as e:
+ asserts.fail("should only raise signals.TestFailure, "
+ "but raised %s with msg %s instead" % (e.__class__.__name__, str(e)))
+ else:
+ asserts.fail("missing pts_test_id should not work")
+
+ def test_metadata_pts_missing_name(self):
+
+ @metadata(pts_test_id="A/B/C")
+ def simple_pass_test(arg):
+ pass
+
+ try:
+ simple_pass_test(1)
+ except signals.TestFailure:
+ pass
+ except Exception as e:
+ asserts.fail("should only raise signals.TestFailure, "
+ "but raised %s with msg %s instead" % (e.__class__.__name__, str(e)))
+ else:
+ asserts.fail("missing pts_test_name should not work")
+
+ def test_metadata_pts_test_id_and_description(self):
+
+ @metadata(pts_test_id="A/B/C", pts_test_name="Hello world")
+ def simple_pass_test(arg):
+ pass
+
+ try:
+ simple_pass_test(1)
+ except signals.TestPass as e:
+ asserts.assert_true("pts_test_id" in e.extras, msg=("pts_test_id not in extra: %s" % str(e.extras)))
+ asserts.assert_equal(e.extras["pts_test_id"], "A/B/C")
+ asserts.assert_true("pts_test_name" in e.extras, msg=("pts_test_name not in extra: %s" % str(e.extras)))
+ asserts.assert_equal(e.extras["pts_test_name"], "Hello world")
+ else:
+ asserts.fail("Must throw an exception using @metadata decorator")
+
+ def test_metadata_test_with_exception_stacktrace(self):
+
+ @metadata(pts_test_id="A/B/C", pts_test_name="Hello world")
+ def simple_fail_test(failure_argument):
+ raise ValueError(failure_argument)
+
+ try:
+ simple_fail_test("BEEFBEEF")
+ except signals.TestError as e:
+ asserts.assert_true("pts_test_id" in e.extras, msg=("pts_test_id not in extra: %s" % str(e.extras)))
+ asserts.assert_equal(e.extras["pts_test_id"], "A/B/C")
+ asserts.assert_true("pts_test_name" in e.extras, msg=("pts_test_name not in extra: %s" % str(e.extras)))
+ asserts.assert_equal(e.extras["pts_test_name"], "Hello world")
+ trace_str = traceback.format_exc()
+ asserts.assert_true(
+ "raise ValueError(failure_argument)" in trace_str,
+ msg="Failed test method not in error stack trace: %s" % trace_str)
+ else:
+ asserts.fail("Must throw an exception using @metadata decorator")
+
+ def test_fluent_behavior_simple(self):
+ test_fluent_behavior_simple_core()
+
+ def test_fluent_behavior__then_single__captures_one(self):
+ test_fluent_behavior__then_single__captures_one_core()
+
+ def test_fluent_behavior__then_times__captures_all(self):
+ test_fluent_behavior__then_times__captures_all_core()
+
+ def test_fluent_behavior__always__captures_all(self):
+ test_fluent_behavior__always__captures_all_core()
+
+ def test_fluent_behavior__matcher__captures_relevant(self):
+ test_fluent_behavior__matcher__captures_relevant_core()
+
+ def test_fluent_behavior__then_repeated__captures_relevant(self):
+ test_fluent_behavior__then_repeated__captures_relevant_core()
+
+ def test_fluent_behavior__fallback__captures_relevant(self):
+ test_fluent_behavior__fallback__captures_relevant_core()
+
+ def test_fluent_behavior__default_unhandled_crash(self):
+ test_fluent_behavior__default_unhandled_crash_core()
+
+ def test_fluent_behavior__set_default_works(self):
+ test_fluent_behavior__set_default_works_core()
+
+ def test_fluent_behavior__wait_until_done(self):
+ test_fluent_behavior__wait_until_done_core()
+
+ def test_fluent_behavior__wait_until_done_different_lambda(self):
+ test_fluent_behavior__wait_until_done_different_lambda_core()
+
+ def test_fluent_behavior__wait_until_done_anything(self):
+ test_fluent_behavior__wait_until_done_anything_core()
+
+ def test_fluent_behavior__wait_until_done_not_happened(self):
+ test_fluent_behavior__wait_until_done_not_happened_core()
+
+ def test_fluent_behavior__wait_until_done_with_default(self):
+ test_fluent_behavior__wait_until_done_with_default_core()
+
+ def test_fluent_behavior__wait_until_done_two_events_AA(self):
+ test_fluent_behavior__wait_until_done_two_events_AA_core()
+
+ def test_fluent_behavior__wait_until_done_two_events_AB(self):
+ test_fluent_behavior__wait_until_done_two_events_AB_core()
+
+ def test_fluent_behavior__wait_until_done_only_one_event_is_done(self):
+ test_fluent_behavior__wait_until_done_only_one_event_is_done_core()
+
+
+if __name__ == '__main__':
+ test_runner.main()
diff --git a/blueberry/tests/gd/host_config.yaml b/blueberry/tests/gd/host_config.yaml
new file mode 100644
index 0000000..7749837
--- /dev/null
+++ b/blueberry/tests/gd/host_config.yaml
@@ -0,0 +1,32 @@
+_description: Bluetooth cert testing
+TestBeds:
+ - _description: Host only cert testbed
+ Name: HostOnlyCert
+ rootcanal:
+ test_port: '6401'
+ hci_port: '6402'
+ link_layer_port: '6403'
+ GdDevice:
+ - grpc_port: '8998'
+ grpc_root_server_port: '8996'
+ signal_port: '8994'
+ label: cert
+ Name: Cert Device
+ cmd:
+ - "$GD_ROOT/bluetooth_stack_with_facade"
+ - "--grpc-port=$(grpc_port)"
+ - "--root-server-port=$(grpc_root_server_port)"
+ - "--rootcanal-port=$(rootcanal_port)"
+ - "--signal-port=$(signal_port)"
+ - grpc_port: '8999'
+ grpc_root_server_port: '8997'
+ signal_port: '8995'
+ label: dut
+ Name: DUT Device
+ cmd:
+ - "$GD_ROOT/bluetooth_stack_with_facade"
+ - "--grpc-port=$(grpc_port)"
+ - "--root-server-port=$(grpc_root_server_port)"
+ - "--rootcanal-port=$(rootcanal_port)"
+ - "--signal-port=$(signal_port)"
+logpath: "/tmp/logs"
diff --git a/blueberry/tests/map/bluetooth_map_test.py b/blueberry/tests/map/bluetooth_map_test.py
new file mode 100644
index 0000000..11bee4e
--- /dev/null
+++ b/blueberry/tests/map/bluetooth_map_test.py
@@ -0,0 +1,148 @@
+"""Tests for blueberry.map.bluetooth_map."""
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import queue
+import time
+
+from mobly import test_runner
+from mobly import signals
+from mobly import utils
+
+from blueberry.controllers import android_bt_target_device
+from blueberry.utils import blueberry_base_test
+
+_SMS_MSG_EVENT = 'SmsReceived'
+_MAP_MSG_EVENT = 'MapMessageReceived'
+
+_EVENT_TIMEOUT_SEC = 180
+_TEXT_LENGTH = 10
+_TEXT_COUNT = 5
+
+
+class BluetoothMapTest(blueberry_base_test.BlueberryBaseTest):
+ """Test Class for Bluetooth MAP Test."""
+
+ def setup_class(self):
+ """Standard Mobly setup class."""
+ super().setup_class()
+ for device in self.android_devices:
+ device.init_setup()
+ device.sl4a_setup()
+
+ # Primary phone which role is Message Server Equipment (MSE).
+ self.pri_phone = self.android_devices[0]
+ self.pri_phone.sl4a.smsStartTrackingIncomingSmsMessage()
+ self.pri_number = self.pri_phone.dimensions['phone_number']
+
+ # Secondary phone which is used to send SMS messages to primary phone.
+ self.sec_phone = self.android_devices[1]
+
+ # Bluetooth carkit which role is Message Client Equipment (MCE).
+ self.derived_bt_device = self.derived_bt_devices[0]
+
+ mac_address = self.derived_bt_device.get_bluetooth_mac_address()
+ self.derived_bt_device.activate_pairing_mode()
+ self.pri_phone.pair_and_connect_bluetooth(mac_address)
+ # Sleep to make the connection to be steady.
+ time.sleep(5)
+
+ if isinstance(
+ self.derived_bt_device, android_bt_target_device.AndroidBtTargetDevice):
+ # Allow sl4a to receive the intent with ACTION_MESSAGE_RECEIVED.
+ self.derived_bt_device.adb.shell(
+ 'pm grant com.googlecode.android_scripting '
+ 'android.permission.RECEIVE_SMS')
+ # Connect derived bt device to primary phone via MAP MCE profile.
+ self.derived_bt_device.add_sec_ad_device(self.pri_phone)
+
+ def teardown_test(self):
+ """Standard Mobly teardown test.
+
+ Disconnects the MAP connection after a test completes.
+ """
+ super().teardown_test()
+ self.derived_bt_device.map_disconnect()
+
+ def _wait_for_message_on_mce(self, text):
+ """Waits for that MCE gets an event with specific message.
+
+ Args:
+ text: String, Text of the message.
+
+ Raises:
+ TestFailure: Raised if timed out.
+ """
+ try:
+ self.derived_bt_device.ed.wait_for_event(
+ _MAP_MSG_EVENT, lambda e: e['data'] == text, _EVENT_TIMEOUT_SEC)
+ self.derived_bt_device.log.info(
+ 'Successfully got the unread message: %s' % text)
+ except queue.Empty:
+ raise signals.TestFailure(
+ 'Timed out after %ds waiting for "%s" event with the message: %s' %
+ (_EVENT_TIMEOUT_SEC, _MAP_MSG_EVENT, text))
+
+ def _wait_for_message_on_mse(self, text):
+ """Waits for that MSE gets an event with specific message.
+
+ This method is used to make sure that MSE has received the test message.
+
+ Args:
+ text: String, Text of the message.
+
+ Raises:
+ TestError: Raised if timed out.
+ """
+ try:
+ self.pri_phone.ed.wait_for_event(
+ _SMS_MSG_EVENT, lambda e: e['data']['Text'] == text,
+ _EVENT_TIMEOUT_SEC)
+ self.pri_phone.log.info(
+ 'Successfully received the incoming message: %s' % text)
+ except queue.Empty:
+ raise signals.TestError(
+ 'Timed out after %ds waiting for "%s" event with the message: %s' %
+ (_EVENT_TIMEOUT_SEC, _SMS_MSG_EVENT, text))
+
+ def _create_message_on_mse(self, text):
+ """Creates a new incoming message on MSE.
+
+ Args:
+ text: String, Text of the message.
+ """
+ self.sec_phone.sl4a.smsSendTextMessage(self.pri_number, text, False)
+ self._wait_for_message_on_mse(text)
+
+ def test_get_existing_unread_messages(self):
+ """Test for the feature of getting existing unread messages on MCE.
+
+ Tests MCE can list existing messages of MSE.
+ """
+ text_list = []
+ # Creates 5 SMS messages on MSE before establishing connection.
+ for _ in range(_TEXT_COUNT):
+ text = utils.rand_ascii_str(_TEXT_LENGTH)
+ self._create_message_on_mse(text)
+ text_list.append(text)
+ self.derived_bt_device.map_connect()
+ # Gets the unread messages of MSE and checks if they are downloaded
+ # successfully on MCE.
+ self.derived_bt_device.get_unread_messages()
+ for text in text_list:
+ self._wait_for_message_on_mce(text)
+
+ def test_receive_unread_message(self):
+ """Test for the feature of receiving unread message on MCE.
+
+ Tests MCE can get an unread message when MSE receives an incoming message.
+ """
+ self.derived_bt_device.map_connect()
+ text = utils.rand_ascii_str(_TEXT_LENGTH)
+ self._create_message_on_mse(text)
+ self._wait_for_message_on_mce(text)
+
+
+if __name__ == '__main__':
+ test_runner.main()
diff --git a/blueberry/tests/pan/bluetooth_pan_test.py b/blueberry/tests/pan/bluetooth_pan_test.py
new file mode 100644
index 0000000..062da8e
--- /dev/null
+++ b/blueberry/tests/pan/bluetooth_pan_test.py
@@ -0,0 +1,325 @@
+"""Tests for Bluetooth PAN profile functionalities."""
+
+import contextlib
+import time
+
+from mobly import test_runner
+from mobly import signals
+from mobly.controllers.android_device_lib import jsonrpc_client_base
+from blueberry.utils import blueberry_base_test
+from blueberry.utils import bt_test_utils
+
+# Timeout to wait for NAP service connection to be specific state in second.
+CONNECTION_TIMEOUT_SECS = 20
+
+# Interval time between ping requests in second.
+PING_INTERVAL_TIME_SEC = 2
+
+# Timeout to wait for ping success in second.
+PING_TIMEOUT_SEC = 60
+
+# A URL is used to verify internet by ping request.
+TEST_URL = 'http://www.google.com'
+
+# A string representing SIM State is ready.
+SIM_STATE_READY = 'READY'
+
+
+class BluetoothPanTest(blueberry_base_test.BlueberryBaseTest):
+ """Test class for Bluetooth PAN(Personal Area Networking) profile.
+
+ Test internet connection sharing via Bluetooth between two Android devices.
+ One device which is referred to as NAP(Network Access Point) uses Bluetooth
+ tethering to share internet connection with another device which is referred
+ to as PANU(Personal Area Networking User).
+ """
+
+ def setup_class(self):
+ """Standard Mobly setup class."""
+ super(BluetoothPanTest, self).setup_class()
+ # Number of attempts to initiate connection. 5 attempts as default.
+ self.pan_connect_attempts = self.user_params.get('pan_connect_attempts', 5)
+
+ for device in self.android_devices:
+ device.init_setup()
+ device.sl4a_setup()
+ device.mac_address = device.get_bluetooth_mac_address()
+
+ # Check if the device has inserted a SIM card.
+ if device.sl4a.telephonyGetSimState() != SIM_STATE_READY:
+ raise signals.TestError('SIM card is not ready on Device "%s".' %
+ device.serial)
+
+ self.primary_device = self.android_devices[0]
+ self.secondary_device = self.android_devices[1]
+
+ def teardown_test(self):
+ """Standard Mobly teardown test.
+
+ Reset every devices when a test finished.
+ """
+ super(BluetoothPanTest, self).teardown_test()
+ # Revert debug tags.
+ for device in self.android_devices:
+ device.debug_tag = device.serial
+ device.factory_reset_bluetooth()
+
+ def wait_for_nap_service_connection(
+ self,
+ device,
+ connected_mac_addr,
+ state_connected=True):
+ """Waits for NAP service connection to be expected state.
+
+ Args:
+ device: AndroidDevice, A device is used to check this connection.
+ connected_mac_addr: String, Bluetooth Mac address is needed to be checked.
+ state_connected: Bool, NAP service connection is established as expected
+ if True, else terminated as expected.
+
+ Raises:
+ TestFailure: Raised if NAP service connection is not expected state.
+ """
+ def is_device_connected():
+ """Returns True if connected else False."""
+ connected_devices = (device.sl4a.
+ bluetoothPanGetConnectedDevices())
+ # Check if the Bluetooth mac address is in the connected device list.
+ return connected_mac_addr in [d['address'] for d in connected_devices]
+
+ bt_test_utils.wait_until(
+ timeout_sec=CONNECTION_TIMEOUT_SECS,
+ condition_func=is_device_connected,
+ func_args=[],
+ expected_value=state_connected,
+ exception=signals.TestFailure(
+ 'NAP service connection failed to be %s in %ds.' %
+ ('established' if state_connected else 'terminated',
+ CONNECTION_TIMEOUT_SECS)))
+
+ def initiate_nap_service_connection(
+ self,
+ initiator_device,
+ connected_mac_addr):
+ """Initiates NAP service connection.
+
+ Args:
+ initiator_device: AndroidDevice, A device intiating connection.
+ connected_mac_addr: String, Bluetooth Mac address of connected device.
+
+ Raises:
+ TestFailure: Raised if NAP service connection fails to be established.
+ """
+ count = 0
+ for _ in range(self.pan_connect_attempts):
+ count += 1
+ try:
+ initiator_device.sl4a.bluetoothConnectBonded(connected_mac_addr)
+ self.wait_for_nap_service_connection(
+ device=initiator_device,
+ connected_mac_addr=connected_mac_addr,
+ state_connected=True)
+ return
+ except signals.TestFailure:
+ if count == self.pan_connect_attempts:
+ raise signals.TestFailure(
+ 'NAP service connection still failed to be established '
+ 'after retried %d times.' %
+ self.pan_connect_attempts)
+
+ def terminate_nap_service_connection(
+ self,
+ initiator_device,
+ connected_mac_addr):
+ """Terminates NAP service connection.
+
+ Args:
+ initiator_device: AndroidDevice, A device intiating disconnection.
+ connected_mac_addr: String, Bluetooth Mac address of connected device.
+ """
+ initiator_device.log.info('Terminate NAP service connection.')
+ initiator_device.sl4a.bluetoothDisconnectConnected(connected_mac_addr)
+ self.wait_for_nap_service_connection(
+ device=initiator_device,
+ connected_mac_addr=connected_mac_addr,
+ state_connected=False)
+
+ @contextlib.contextmanager
+ def establish_nap_service_connection(self, nap_device, panu_device):
+ """Establishes NAP service connection between both Android devices.
+
+ The context is used to form a basic network connection between devices
+ before executing a test.
+
+ Steps:
+ 1. Disable Mobile data to avoid internet access on PANU device.
+ 2. Make sure Mobile data available on NAP device.
+ 3. Enable Bluetooth from PANU device.
+ 4. Enable Bluetooth tethering on NAP device.
+ 5. Initiate a connection from PANU device.
+ 6. Check if PANU device has internet access via the connection.
+
+ Args:
+ nap_device: AndroidDevice, A device sharing internet connection via
+ Bluetooth tethering.
+ panu_device: AndroidDevice, A device gaining internet access via
+ Bluetooth tethering.
+
+ Yields:
+ None, the context just execute a pre procedure for PAN testing.
+
+ Raises:
+ signals.TestError: raised if a step fails.
+ signals.TestFailure: raised if PANU device fails to access internet.
+ """
+ nap_device.debug_tag = 'NAP'
+ panu_device.debug_tag = 'PANU'
+ try:
+ # Disable Mobile data to avoid internet access on PANU device.
+ panu_device.log.info('Disabling Mobile data...')
+ panu_device.sl4a.setMobileDataEnabled(False)
+ self.verify_internet(
+ allow_access=False,
+ device=panu_device,
+ exception=signals.TestError(
+ 'PANU device "%s" still connected to internet when Mobile data '
+ 'had been disabled.' % panu_device.serial))
+
+ # Make sure NAP device has Mobile data for internet sharing.
+ nap_device.log.info('Enabling Mobile data...')
+ nap_device.sl4a.setMobileDataEnabled(True)
+ self.verify_internet(
+ allow_access=True,
+ device=nap_device,
+ exception=signals.TestError(
+ 'NAP device "%s" did not have internet access when Mobile data '
+ 'had been enabled.' % nap_device.serial))
+
+ # Enable Bluetooth tethering from NAP device.
+ nap_device.set_bluetooth_tethering(status_enabled=True)
+ # Wait until Bluetooth tethering stabilizes. This waiting time avoids PANU
+ # device initiates a connection to NAP device immediately when NAP device
+ # enables Bluetooth tethering.
+ time.sleep(5)
+
+ nap_device.activate_pairing_mode()
+ panu_device.log.info('Pair to NAP device "%s".' % nap_device.serial)
+ panu_device.pair_and_connect_bluetooth(nap_device.mac_address)
+
+ # Initiate a connection to NAP device.
+ panu_device.log.info('Initiate a connection to NAP device "%s".' %
+ nap_device.serial)
+ self.initiate_nap_service_connection(
+ initiator_device=panu_device,
+ connected_mac_addr=nap_device.mac_address)
+
+ # Check if PANU device can access internet via NAP service connection.
+ self.verify_internet(
+ allow_access=True,
+ device=panu_device,
+ exception=signals.TestFailure(
+ 'PANU device "%s" failed to access internet via NAP service '
+ 'connection.' % panu_device.serial))
+ yield
+ finally:
+ # Disable Bluetooth tethering from NAP device.
+ nap_device.set_bluetooth_tethering(status_enabled=False)
+ panu_device.sl4a.setMobileDataEnabled(True)
+
+ def verify_internet(self, allow_access, device, exception):
+ """Verifies that internet is in expected state.
+
+ Continuously make ping request to a URL for internet verification.
+
+ Args:
+ allow_access: Bool, Device can have internet access as expected if True,
+ else no internet access as expected.
+ device: AndroidDevice, Device to be check internet state.
+ exception: Exception, Raised if internet is not in expected state.
+ """
+ device.log.info('Verify that internet %s be used.' %
+ ('can' if allow_access else 'can not'))
+
+ def http_ping():
+ """Returns True if http ping success else False."""
+ try:
+ return bool(device.sl4a.httpPing(TEST_URL))
+ except jsonrpc_client_base.ApiError as e:
+ # ApiError is raised by httpPing() when no internet.
+ device.log.debug(str(e))
+ return False
+
+ bt_test_utils.wait_until(
+ timeout_sec=PING_TIMEOUT_SEC,
+ condition_func=http_ping,
+ func_args=[],
+ expected_value=allow_access,
+ exception=exception,
+ interval_sec=PING_INTERVAL_TIME_SEC)
+
+ def test_gain_internet_and_terminate_nap_connection(self):
+ """Test that DUT can access internet and terminate NAP service connection.
+
+ In this test case, primary device is PANU and secondary device is NAP. While
+ a connection has established between both devices, PANU should be able to
+ use internet and terminate the connection to disable internet access.
+
+ Steps:
+ 1. Establish NAP service connection between both devices.
+ 2. Terminal the connection from PANU device.
+ 3. Verify that PANU device cannot access internet.
+ """
+ with self.establish_nap_service_connection(
+ nap_device=self.secondary_device,
+ panu_device=self.primary_device):
+
+ # Terminate the connection from DUT.
+ self.terminate_nap_service_connection(
+ initiator_device=self.primary_device,
+ connected_mac_addr=self.secondary_device.mac_address)
+
+ # Verify that PANU device cannot access internet.
+ self.verify_internet(
+ allow_access=False,
+ device=self.primary_device,
+ exception=signals.TestFailure(
+ 'PANU device "%s" can still access internet when it had '
+ 'terminated NAP service connection.' %
+ self.primary_device.serial))
+
+ def test_share_internet_and_disable_bluetooth_tethering(self):
+ """Test that DUT can share internet and stop internet sharing.
+
+ In this test case, primary device is NAP and secondary device is PANU. While
+ a connection has established between both devices, NAP should be able to
+ share internet and disable Bluetooth thethering to stop internet sharing.
+
+ Steps:
+ 1. Establish NAP service connection between both devices.
+ 3. Disable Bluetooth tethering from NAP device.
+ 4. Verify that PANU device cannot access internet.
+ """
+ with self.establish_nap_service_connection(
+ nap_device=self.primary_device,
+ panu_device=self.secondary_device):
+
+ # Disable Bluetooth tethering from DUT and check if the nap connection is
+ # terminated.
+ self.primary_device.set_bluetooth_tethering(status_enabled=False)
+ self.wait_for_nap_service_connection(
+ device=self.primary_device,
+ connected_mac_addr=self.secondary_device.mac_address,
+ state_connected=False)
+
+ # Verify that PANU device cannot access internet.
+ self.verify_internet(
+ allow_access=False,
+ device=self.secondary_device,
+ exception=signals.TestFailure(
+ 'PANU device "%s" can still access internet when it had '
+ 'terminated NAP service connection.' %
+ self.secondary_device.serial))
+
+
+if __name__ == '__main__':
+ test_runner.main()
diff --git a/blueberry/tests/pbap/bluetooth_pbap_test.py b/blueberry/tests/pbap/bluetooth_pbap_test.py
new file mode 100644
index 0000000..9c7c032
--- /dev/null
+++ b/blueberry/tests/pbap/bluetooth_pbap_test.py
@@ -0,0 +1,401 @@
+"""Tests for blueberry.pbap.bluetooth_pbap."""
+
+import os
+import random
+import time
+
+from mobly import asserts
+from mobly import test_runner
+from mobly import signals
+from mobly import utils
+
+from mobly.controllers import android_device
+
+from blueberry.utils import blueberry_base_test
+from blueberry.utils import bt_constants
+from blueberry.utils import bt_test_utils
+
+# The path is used to place the created vcf files.
+STORAGE_PATH = '/storage/emulated/0'
+
+# URI for contacts database.
+CONTACTS_URI = 'content://com.android.contacts/data/phones'
+
+# Number of seconds to wait for contacts and call logs update.
+WAITING_TIMEOUT_SEC = 60
+
+# Number of contacts and call logs to be tested.
+TEST_DATA_COUNT = 1000
+
+# Permissions for Contacts app.
+PERMISSION_LIST = [
+ 'android.permission.READ_CONTACTS',
+ 'android.permission.WRITE_CONTACTS',
+]
+
+
+class BluetoothPbapTest(blueberry_base_test.BlueberryBaseTest):
+ """Test Class for Bluetooth PBAP Test."""
+
+ def setup_class(self):
+ """Standard Mobly setup class."""
+ super(BluetoothPbapTest, self).setup_class()
+
+ # Bluetooth carkit which role is Phone Book Client Equipment (PCE).
+ self.derived_bt_device = self.derived_bt_devices[0]
+
+ # Primary phone which role is Phone Book Server Equipment (PSE).
+ self.pri_phone = self.android_devices[0]
+ self.pri_phone.init_setup()
+ self.pri_phone.sl4a_setup()
+ self.derived_bt_device.add_sec_ad_device(self.pri_phone)
+
+ # Grant the permissions to Contacts app.
+ for device in [self.pri_phone, self.derived_bt_device]:
+ required_permissions = PERMISSION_LIST
+ # App requires READ_EXTERNAL_STORAGE to read contacts if SDK < 30.
+ if int(device.build_info['build_version_sdk']) < 30:
+ required_permissions.append('android.permission.READ_EXTERNAL_STORAGE')
+ for permission in required_permissions:
+ device.adb.shell('pm grant com.google.android.contacts %s' % permission)
+ self.pse_mac_address = self.pri_phone.get_bluetooth_mac_address()
+ mac_address = self.derived_bt_device.get_bluetooth_mac_address()
+ self.derived_bt_device.activate_pairing_mode()
+ self.pri_phone.pair_and_connect_bluetooth(mac_address)
+ # Sleep until the connection stabilizes.
+ time.sleep(5)
+
+ # Allow permission access for PBAP profile.
+ self.pri_phone.sl4a.bluetoothChangeProfileAccessPermission(
+ mac_address,
+ bt_constants.BluetoothProfile.PBAP.value,
+ bt_constants.BluetoothAccessLevel.ACCESS_ALLOWED.value)
+
+ def setup_test(self):
+ super(BluetoothPbapTest, self).setup_test()
+ # Make sure PBAP is not connected before running tests.
+ self._terminate_pbap_connection()
+
+ def _import_vcf_to_pse(self, file_name, expected_contact_count):
+ """Imports the vcf file to PSE."""
+ # Open ImportVcardActivity and click "OK" in the pop-up dialog, then
+ # PickActivity will be launched and browses the existing vcf files.
+ self.pri_phone.adb.shell(
+ 'am start com.google.android.contacts/'
+ 'com.google.android.apps.contacts.vcard.ImportVCardActivity')
+ self.pri_phone.aud(text='OK').click()
+
+ # Check if the vcf file appears in the PickActivity.
+ if not self.pri_phone.aud(text=file_name).exists():
+ raise android_device.DeviceError(
+ self.pri_phone,
+ 'No file name matches "%s" in PickActivity.' % file_name)
+
+ # TODO(user): Remove the check of code name for S build.
+ if (self.pri_phone.build_info['build_version_codename'] != 'S' and
+ int(self.pri_phone.build_info['build_version_sdk']) <= 30):
+ # Since `adb shell input tap` cannot work in PickActivity before R build,
+ # send TAB and ENETER Key events to select and import the vcf file.
+ if self.pri_phone.aud(content_desc='Grid view').exists():
+ # Switch Grid mode since ENTER Key event cannot work in List mode on
+ # git_rvc-d2-release branch.
+ self.pri_phone.aud(content_desc='Grid view').click()
+ self.pri_phone.aud.send_key_code('KEYCODE_TAB')
+ self.pri_phone.aud.send_key_code('KEYCODE_ENTER')
+ else:
+ self.pri_phone.aud(text=file_name).click()
+ self.pri_phone.log.info('Importing "%s"...' % file_name)
+ current_count = self._wait_and_get_contact_count(
+ self.pri_phone, expected_contact_count, WAITING_TIMEOUT_SEC)
+ if current_count != expected_contact_count:
+ raise android_device.DeviceError(
+ self.pri_phone,
+ 'Failed to import %d contact(s) within %ds. Actual count: %d' %
+ (expected_contact_count, WAITING_TIMEOUT_SEC, current_count))
+ self.pri_phone.log.info(
+ 'Successfully added %d contact(s).' % current_count)
+
+ def _generate_contacts_on_pse(self,
+ num_of_contacts,
+ first_name=None,
+ last_name=None,
+ phone_number=None):
+ """Generates contacts to be tested on PSE."""
+ vcf_file = bt_test_utils.create_vcf_from_vcard(
+ output_path=self.pri_phone.log_path,
+ num_of_contacts=num_of_contacts,
+ first_name=first_name,
+ last_name=last_name,
+ phone_number=phone_number)
+ self.pri_phone.adb.push([vcf_file, STORAGE_PATH])
+ # For R build, since the pushed vcf file probably not found when importing
+ # contacts, do a media scan to recognize the file.
+ if int(self.pri_phone.build_info['build_version_sdk']) > 29:
+ self.pri_phone.adb.shell('content call --uri content://media/ --method '
+ 'scan_volume --arg external_primary')
+ file_name = vcf_file.split('/')[-1]
+ self._import_vcf_to_pse(file_name, num_of_contacts)
+ self.pri_phone.adb.shell(
+ 'rm -rf %s' % os.path.join(STORAGE_PATH, file_name))
+
+ def _generate_call_logs_on_pse(self, call_log_type, num_of_call_logs):
+ """Generates call logs to be tested on PSE."""
+ self.pri_phone.log.info('Putting %d call log(s) which type are "%s"...' %
+ (num_of_call_logs, call_log_type))
+ for _ in range(num_of_call_logs):
+ self.pri_phone.sl4a.callLogsPut(dict(
+ type=call_log_type,
+ number='8809%d' % random.randrange(int(10e8)),
+ time=int(1000 * float(self.pri_phone.adb.shell('date +%s.%N')))))
+ current_count = self._wait_and_get_call_log_count(
+ self.pri_phone,
+ call_log_type,
+ num_of_call_logs,
+ WAITING_TIMEOUT_SEC)
+ if current_count != num_of_call_logs:
+ raise android_device.DeviceError(
+ self.pri_phone,
+ 'Failed to generate %d call log(s) within %ds. '
+ 'Actual count: %d, Call log type: %s' %
+ (num_of_call_logs, WAITING_TIMEOUT_SEC, current_count, call_log_type))
+ self.pri_phone.log.info(
+ 'Successfully added %d call log(s).' % current_count)
+
+ def _wait_and_get_contact_count(self,
+ device,
+ expected_contact_count,
+ timeout_sec):
+ """Waits for contact update for a period time and returns contact count.
+
+ This method should be used when a device imports some new contacts. It can
+ wait some time for contact update until expectation or timeout and then
+ return contact count.
+
+ Args:
+ device: AndroidDevice, Mobly Android controller class.
+ expected_contact_count: Int, Number of contacts as expected.
+ timeout_sec: Int, Number of seconds to wait for contact update.
+
+ Returns:
+ current_count: Int, number of the existing contacts on the device.
+ """
+ start_time = time.time()
+ end_time = start_time + timeout_sec
+ current_count = 0
+ while time.time() < end_time:
+ current_count = device.sl4a.contactsGetCount()
+ if current_count == expected_contact_count:
+ break
+ # Interval between attempts to get contacts.
+ time.sleep(1)
+ if current_count != expected_contact_count:
+ device.log.warning(
+ 'Failed to get expected contact count: %d. '
+ 'Actual contact count: %d.' %
+ (expected_contact_count, current_count))
+ return current_count
+
+ def _wait_and_get_call_log_count(self,
+ device,
+ call_log_type,
+ expected_call_log_count,
+ timeout_sec):
+ """Waits for call log update for a period time and returns call log count.
+
+ This method should be used when a device adds some new call logs. It can
+ wait some time for call log update until expectation or timeout and then
+ return call log count.
+
+ Args:
+ device: AndroidDevice, Mobly Android controller class.
+ call_log_type: String, Type of the call logs.
+ expected_call_log_count: Int, Number of call logs as expected.
+ timeout_sec: Int, Number of seconds to wait for call log update.
+
+ Returns:
+ current_count: Int, number of the existing call logs on the device.
+ """
+ start_time = time.time()
+ end_time = start_time + timeout_sec
+ current_count = 0
+ while time.time() < end_time:
+ current_count = len(device.sl4a.callLogsGet(call_log_type))
+ if current_count == expected_call_log_count:
+ break
+ # Interval between attempts to get call logs.
+ time.sleep(1)
+ if current_count != expected_call_log_count:
+ device.log.warning(
+ 'Failed to get expected call log count: %d. '
+ 'Actual call log count: %d.' %
+ (expected_call_log_count, current_count))
+ return current_count
+
+ def _terminate_pbap_connection(self):
+ status = self.derived_bt_device.sl4a.bluetoothPbapClientGetConnectionStatus(
+ self.pse_mac_address)
+ if status == bt_constants.BluetoothConnectionStatus.STATE_DISCONNECTED:
+ return
+ self.derived_bt_device.log.info('Disconnecting PBAP...')
+ self.derived_bt_device.sl4a.bluetoothPbapClientDisconnect(
+ self.pse_mac_address)
+ # Buffer for the connection status check.
+ time.sleep(3)
+ status = self.derived_bt_device.sl4a.bluetoothPbapClientGetConnectionStatus(
+ self.pse_mac_address)
+ if status != bt_constants.BluetoothConnectionStatus.STATE_DISCONNECTED:
+ raise signals.TestError('PBAP connection failed to be terminated.')
+ self.derived_bt_device.log.info('Successfully disconnected PBAP.')
+
+ def test_download_contacts(self):
+ """Test for the feature of downloading contacts.
+
+ Tests that PCE can download contacts from PSE.
+ """
+ # Make sure no any contacts exist on the devices.
+ for device in [self.pri_phone, self.derived_bt_device]:
+ device.sl4a.contactsEraseAll()
+
+ # Add contacts to PSE.
+ self._generate_contacts_on_pse(TEST_DATA_COUNT)
+
+ # When PCE is connected to PSE, it will download PSE's contacts.
+ self.derived_bt_device.pbap_connect()
+ self.derived_bt_device.log.info('Downloading contacts from PSE...')
+ current_count = self._wait_and_get_contact_count(
+ self.derived_bt_device, TEST_DATA_COUNT, WAITING_TIMEOUT_SEC)
+ self.derived_bt_device.log.info(
+ 'Successfully downloaded %d contact(s).' % current_count)
+
+ asserts.assert_true(
+ current_count == TEST_DATA_COUNT,
+ 'PCE failed to download %d contact(s) within %ds, '
+ 'actually downloaded %d contact(s).' %
+ (TEST_DATA_COUNT, WAITING_TIMEOUT_SEC, current_count))
+
+ def test_download_call_logs(self):
+ """Test for the feature of downloading call logs.
+
+ Tests that PCE can download incoming/outgoing/missed call logs from PSE.
+ """
+ # Make sure no any call logs exist on the devices.
+ for device in [self.pri_phone, self.derived_bt_device]:
+ device.sl4a.callLogsEraseAll()
+
+ call_log_types = [
+ bt_constants.INCOMING_CALL_LOG_TYPE,
+ bt_constants.OUTGOING_CALL_LOG_TYPE,
+ bt_constants.MISSED_CALL_LOG_TYPE,
+ ]
+ for call_log_type in call_log_types:
+ # Add call logs to PSE.
+ self._generate_call_logs_on_pse(call_log_type, TEST_DATA_COUNT)
+
+ # When PCE is connected to PSE, it will download PSE's contacts.
+ self.derived_bt_device.pbap_connect()
+ self.derived_bt_device.log.info('Downloading call logs...')
+
+ for call_log_type in call_log_types:
+ current_count = self._wait_and_get_call_log_count(
+ self.derived_bt_device,
+ call_log_type,
+ TEST_DATA_COUNT,
+ WAITING_TIMEOUT_SEC)
+ self.derived_bt_device.log.info(
+ 'Successfully downloaded %d call log(s) which type are "%s".' %
+ (current_count, call_log_type))
+
+ asserts.assert_true(
+ current_count == TEST_DATA_COUNT,
+ 'PCE failed to download %d call log(s) which type are "%s" within %ds'
+ ', actually downloaded %d call log(s).' %
+ (TEST_DATA_COUNT, call_log_type, WAITING_TIMEOUT_SEC, current_count))
+
+ def test_show_caller_name(self):
+ """Test for caller name of the incoming phone call is correct on PCE.
+
+ Tests that caller name matches contact name which is downloaded via PBAP.
+ """
+ # Checks if two android devices exist.
+ if len(self.android_devices) < 2:
+ raise signals.TestError('This test requires two Android devices.')
+ primary_phone = self.pri_phone
+ secondary_phone = self.android_devices[1]
+ secondary_phone.init_setup()
+ for phone in [primary_phone, secondary_phone]:
+ # Checks if SIM state is loaded for every devices.
+ if not phone.is_sim_state_loaded():
+ raise signals.TestError(f'Please insert a SIM Card to the phone '
+ f'"{phone.serial}".')
+ # Checks if phone_number is provided in the support dimensions.
+ phone.phone_number = phone.dimensions.get('phone_number')
+ if not phone.phone_number:
+ raise signals.TestError(f'Please add "phone_number" to support '
+ f'dimensions of the phone "{phone.serial}".')
+ # Make sure no any contacts exist on the devices.
+ for device in [primary_phone, self.derived_bt_device]:
+ device.sl4a.contactsEraseAll()
+ # Generate a contact name randomly.
+ first_name = utils.rand_ascii_str(4)
+ last_name = utils.rand_ascii_str(4)
+ full_name = f'{first_name} {last_name}'
+ primary_phone.log.info('Creating a contact "%s"...', full_name)
+ self._generate_contacts_on_pse(
+ num_of_contacts=1,
+ first_name=first_name,
+ last_name=last_name,
+ phone_number=secondary_phone.phone_number)
+ self.derived_bt_device.log.info('Connecting to PSE...')
+ self.derived_bt_device.pbap_connect()
+ self.derived_bt_device.log.info('Downloading contacts from PSE...')
+ current_count = self._wait_and_get_contact_count(
+ device=self.derived_bt_device,
+ expected_contact_count=1,
+ timeout_sec=WAITING_TIMEOUT_SEC)
+ self.derived_bt_device.log.info('Successfully downloaded %d contact(s).',
+ current_count)
+ asserts.assert_equal(
+ first=current_count,
+ second=1,
+ msg=f'Failed to download the contact "{full_name}".')
+ secondary_phone.sl4a.telecomCallNumber(primary_phone.phone_number)
+ secondary_phone.log.info('Made a phone call to device "%s".',
+ primary_phone.serial)
+ primary_phone.log.info('Waiting for the incoming call from device "%s"...',
+ secondary_phone.serial)
+ is_ringing = primary_phone.wait_for_call_state(
+ bt_constants.CALL_STATE_RINGING,
+ bt_constants.CALL_STATE_TIMEOUT_SEC)
+ if not is_ringing:
+ raise signals.TestError(
+ f'Timed out after {bt_constants.CALL_STATE_TIMEOUT_SEC}s waiting for '
+ f'the incoming call from device "{secondary_phone.serial}".')
+ try:
+ self.derived_bt_device.aud.open_notification()
+ target_node_match_dict = {
+ 'resource_id': 'android:id/line1',
+ 'child': {
+ 'resource_id': 'android:id/title'
+ }
+ }
+ hfp_address = primary_phone.get_bluetooth_mac_address()
+ target_node = self.derived_bt_device.aud(
+ sibling=target_node_match_dict,
+ text=f'Incoming call via HFP {hfp_address}')
+ caller_name = target_node.get_attribute_value('text')
+ message = (f'Caller name is incorrect. Actual: {caller_name}, '
+ f'Correct: {full_name}')
+ # Asserts that caller name of the incoming phone call is correct in the
+ # notification bar.
+ asserts.assert_equal(
+ first=caller_name,
+ second=full_name,
+ msg=message)
+ finally:
+ # Recovery actions.
+ self.derived_bt_device.aud.close_notification()
+ secondary_phone.sl4a.telecomEndCall()
+
+
+if __name__ == '__main__':
+ test_runner.main()
diff --git a/blueberry/tests/pbat/bluetooth_acceptance_suite.py b/blueberry/tests/pbat/bluetooth_acceptance_suite.py
new file mode 100644
index 0000000..faa1151
--- /dev/null
+++ b/blueberry/tests/pbat/bluetooth_acceptance_suite.py
@@ -0,0 +1,71 @@
+"""Suite collecting bluetooth test classes for acceptance testing."""
+
+import logging
+
+from mobly import test_runner_suite
+
+from blueberry.tests.a2dp import bluetooth_a2dp_test
+from blueberry.tests.avrcp import bluetooth_avrcp_test
+from blueberry.tests.connectivity import ble_pairing_test
+from blueberry.tests.connectivity import bluetooth_pairing_test
+from blueberry.tests.hfp import bluetooth_hfp_test
+from blueberry.tests.map import bluetooth_map_test
+from blueberry.tests.opp import bluetooth_opp_test
+from blueberry.tests.pan import bluetooth_pan_test
+from blueberry.tests.pbap import bluetooth_pbap_test
+
+# Test classes for the Bluetooth acceptance suite.
+TEST_CLASSES = [
+ bluetooth_pairing_test.BluetoothPairingTest,
+ ble_pairing_test.BlePairingTest,
+ bluetooth_a2dp_test.BluetoothA2dpTest,
+ bluetooth_avrcp_test.BluetoothAvrcpTest,
+ bluetooth_hfp_test.BluetoothHfpTest,
+ bluetooth_map_test.BluetoothMapTest,
+ bluetooth_pbap_test.BluetoothPbapTest,
+ bluetooth_opp_test.BluetoothOppTest,
+ bluetooth_pan_test.BluetoothPanTest
+]
+
+
+class BluetoothAcceptanceSuite(mobly_g3_suite.BaseSuite):
+ """Bluetooth Acceptance Suite.
+
+ Usage of Test selector:
+ Add the parameter "acceptance_test_selector" in the Mobly configuration, it's
+ value is like "test_method_1,test_method_2,...". If this parameter is not
+ used, all tests will be running.
+ """
+
+ def setup_suite(self, config):
+ selected_tests = None
+ selector = config.user_params.get('acceptance_test_selector')
+ if selector:
+ selected_tests = selector.split(',')
+ logging.info('Selected tests: %s', ' '.join(selected_tests))
+ # Enable all Bluetooth logging in the first test.
+ first_test_config = config.copy()
+ first_test_config.user_params.update({
+ 'enable_all_bluetooth_logging': 1,
+ })
+ for index, clazz in enumerate(TEST_CLASSES):
+ if selected_tests:
+ matched_tests = None
+ # Gets the same elements between selected_tests and dir(clazz).
+ matched_tests = list(set(selected_tests) & set(dir(clazz)))
+ # Adds the test class if it contains the selected tests.
+ if matched_tests:
+ self.add_test_class(
+ clazz=clazz,
+ config=first_test_config if index == 0 else config,
+ tests=matched_tests)
+ logging.info('Added the tests of "%s": %s', clazz.__name__,
+ ' '.join(matched_tests))
+ else:
+ self.add_test_class(
+ clazz=clazz,
+ config=first_test_config if index == 0 else config)
+
+
+if __name__ == '__main__':
+ mobly_g3_suite.main()
diff --git a/blueberry/utils/android_bluetooth_decorator.py b/blueberry/utils/android_bluetooth_decorator.py
new file mode 100644
index 0000000..c570897
--- /dev/null
+++ b/blueberry/utils/android_bluetooth_decorator.py
@@ -0,0 +1,1729 @@
+# Lint as: python3
+"""AndroidBluetoothDecorator class.
+
+This decorator is used for giving an AndroidDevice Bluetooth-specific
+functionality.
+"""
+
+import datetime
+import logging
+import os
+import queue
+import random
+import re
+import string
+import time
+from typing import Dict, Any, Text, Optional, Tuple, Sequence, Union
+from mobly import asserts
+from mobly import logger as mobly_logger
+from mobly import signals
+from mobly import utils
+from mobly.controllers.android_device import AndroidDevice
+from mobly.controllers.android_device_lib import adb
+from mobly.controllers.android_device_lib import jsonrpc_client_base
+from mobly.controllers.android_device_lib.services import sl4a_service
+# Internal import
+from blueberry.controllers.derived_bt_device import BtDevice
+from blueberry.utils import bt_constants
+from blueberry.utils import bt_test_utils
+from blueberry.utils.bt_constants import AvrcpEvent
+from blueberry.utils.bt_constants import BluetoothConnectionPolicy
+from blueberry.utils.bt_constants import BluetoothConnectionStatus
+from blueberry.utils.bt_constants import BluetoothProfile
+from blueberry.utils.bt_constants import CallLogType
+from blueberry.utils.bt_constants import CallState
+
+
+# Map for media passthrough commands and the corresponding events.
+MEDIA_CMD_MAP = {
+ bt_constants.CMD_MEDIA_PAUSE: bt_constants.EVENT_PAUSE_RECEIVED,
+ bt_constants.CMD_MEDIA_PLAY: bt_constants.EVENT_PLAY_RECEIVED,
+ bt_constants.CMD_MEDIA_SKIP_PREV: bt_constants.EVENT_SKIP_PREV_RECEIVED,
+ bt_constants.CMD_MEDIA_SKIP_NEXT: bt_constants.EVENT_SKIP_NEXT_RECEIVED
+}
+
+# Timeout for track change and playback state update in second.
+MEDIA_UPDATE_TIMEOUT_SEC = 3
+
+# Timeout for the event of Media passthrough commands in second.
+MEDIA_EVENT_TIMEOUT_SEC = 1
+
+BT_CONNECTION_WAITING_TIME_SECONDS = 10
+
+ADB_WAITING_TIME_SECONDS = 1
+
+# Common timeout for toggle status in seconds.
+COMMON_TIMEOUT_SECONDS = 5
+
+# Local constant
+_DATETIME_FMT = '%m-%d %H:%M:%S.%f'
+
+# Interval time between ping requests in second.
+PING_INTERVAL_TIME_SEC = 2
+
+# Timeout to wait for ping success in second.
+PING_TIMEOUT_SEC = 60
+
+# A URL is used to verify internet by ping request.
+TEST_URL = 'http://www.google.com'
+
+
+class DiscoveryError(signals.ControllerError):
+ """Exception raised for Bluetooth device discovery failures."""
+ pass
+
+
+class AndroidBluetoothDecorator(AndroidDevice):
+ """Decorates an AndroidDevice with Bluetooth-specific functionality."""
+
+ def __init__(self, ad: AndroidDevice):
+ self._ad = ad
+ self._user_params = None
+ if not self._ad or not isinstance(self._ad, AndroidDevice):
+ raise TypeError('Must apply AndroidBluetoothDecorator to an '
+ 'AndroidDevice')
+ self.ble_advertise_callback = None
+ self.regex_logcat_time = re.compile(
+ r'(?P<datetime>[\d]{2}-[\d]{2} [\d]{2}:[\d]{2}:[\d]{2}.[\d]{3})'
+ r'[ ]+\d+.*')
+ self._regex_bt_crash = re.compile(
+ r'Bluetooth crashed (?P<num_bt_crashes>\d+) times')
+
+ def __getattr__(self, name: Any) -> Any:
+ return getattr(self._ad, name)
+
+ def _is_device_connected(self, mac_address):
+ """Wrapper method to help with unit testability of this class."""
+ return self._ad.sl4a.bluetoothIsDeviceConnected(mac_address)
+
+ def _is_profile_connected(self, mac_address, profile):
+ """Checks if the profile is connected."""
+ status = None
+ pri_ad = self._ad
+ if profile == BluetoothProfile.HEADSET_CLIENT:
+ status = pri_ad.sl4a.bluetoothHfpClientGetConnectionStatus(mac_address)
+ elif profile == BluetoothProfile.A2DP_SINK:
+ status = pri_ad.sl4a.bluetoothA2dpSinkGetConnectionStatus(mac_address)
+ elif profile == BluetoothProfile.PBAP_CLIENT:
+ status = pri_ad.sl4a.bluetoothPbapClientGetConnectionStatus(mac_address)
+ elif profile == BluetoothProfile.MAP_MCE:
+ connected_devices = self._ad.sl4a.bluetoothMapClientGetConnectedDevices()
+ return any(
+ mac_address in device['address'] for device in connected_devices)
+ else:
+ pri_ad.log.warning(
+ 'The connection check for profile %s is not supported '
+ 'yet', profile)
+ return False
+ return status == BluetoothConnectionStatus.STATE_CONNECTED
+
+ def _get_bluetooth_le_state(self):
+ """Wrapper method to help with unit testability of this class."""
+ return self._ad.sl4a.bluetoothGetLeState
+
+ def _generate_id_by_size(self, size):
+ """Generate string of random ascii letters and digits.
+
+ Args:
+ size: required size of string.
+
+ Returns:
+ String of random chars.
+ """
+ return ''.join(
+ random.choice(string.ascii_letters + string.digits)
+ for _ in range(size))
+
+ def _wait_for_bluetooth_manager_state(self,
+ state=None,
+ timeout=10,
+ threshold=5):
+ """Waits for Bluetooth normalized state or normalized explicit state.
+
+ Args:
+ state: expected Bluetooth state
+ timeout: max timeout threshold
+ threshold: list len of bt state
+ Returns:
+ True if successful, false if unsuccessful.
+ """
+ all_states = []
+ start_time = time.time()
+ while time.time() < start_time + timeout:
+ all_states.append(self._get_bluetooth_le_state())
+ if len(all_states) >= threshold:
+ # for any normalized state
+ if state is None:
+ if len(all_states[-threshold:]) == 1:
+ logging.info('State normalized %s', all_states[-threshold:])
+ return True
+ else:
+ # explicit check against normalized state
+ if state in all_states[-threshold:]:
+ return True
+ time.sleep(0.5)
+ logging.error(
+ 'Bluetooth state fails to normalize' if state is None else
+ 'Failed to match bluetooth state, current state {} expected state {}'
+ .format(self._get_bluetooth_le_state(), state))
+ return False
+
+ def init_setup(self) -> None:
+ """Sets up android device for bluetooth tests."""
+ self._ad.services.register('sl4a', sl4a_service.Sl4aService)
+ self._ad.load_snippet('mbs', 'com.google.android.mobly.snippet.bundled')
+ self._ad.adb.shell('setenforce 0')
+
+ # Adds 2 seconds waiting time to see it can fix the NullPointerException
+ # when executing the following sl4a.bluetoothStartPairingHelper method.
+ time.sleep(2)
+ self._ad.sl4a.bluetoothStartPairingHelper()
+ self.factory_reset_bluetooth()
+
+ def sl4a_setup(self) -> None:
+ """A common setup routine for android device sl4a function.
+
+ Things this method setup:
+ 1. Set Bluetooth local name to random string of size 4
+ 2. Disable BLE background scanning.
+ """
+
+ sl4a = self._ad.sl4a
+ sl4a.bluetoothStartConnectionStateChangeMonitor('')
+ setup_result = sl4a.bluetoothSetLocalName(self._generate_id_by_size(4))
+ if not setup_result:
+ self.log.error('Failed to set device name.')
+ return
+ sl4a.bluetoothDisableBLE()
+ bonded_devices = sl4a.bluetoothGetBondedDevices()
+ for b in bonded_devices:
+ self.log.info('Removing bond for device {}'.format(b['address']))
+ sl4a.bluetoothUnbond(b['address'])
+
+ def set_user_params(self, params: Dict[str, Any]) -> None:
+ self._user_params = params
+
+ def get_user_params(self) -> Dict[str, Any]:
+ return self._user_params
+
+ def is_sim_state_loaded(self) -> bool:
+ """Checks if SIM state is loaded.
+
+ Returns:
+ True if SIM state is loaded else False.
+ """
+ state = self._ad.adb.shell('getprop gsm.sim.state').decode().strip()
+ return state == 'LOADED'
+
+ def is_package_installed(self, package_name: str) -> bool:
+ """Checks if a package is installed.
+
+ Args:
+ package_name: string, a package to be checked.
+
+ Returns:
+ True if the package is installed else False.
+ """
+ # The package is installed if result is 1, not installed if result is 0.
+ result = int(self._ad.adb.shell('pm list packages | grep -i %s$ | wc -l' %
+ package_name))
+ return bool(result)
+
+ def connect_with_rfcomm(self, other_ad: AndroidDevice) -> bool:
+ """Establishes an RFCOMM connection with other android device.
+
+ Connects this android device (as a client) to the other android device
+ (as a server).
+
+ Args:
+ other_ad: the Android device accepting the connection from this device.
+
+ Returns:
+ True if connection was successful, False if unsuccessful.
+ """
+ server_address = other_ad.sl4a.bluetoothGetLocalAddress()
+ logging.info('Pairing and connecting devices')
+ if not self._ad.sl4a.bluetoothDiscoverAndBond(server_address):
+ logging.info('Failed to pair and connect devices')
+ return False
+
+ # Create RFCOMM connection
+ logging.info('establishing RFCOMM connection')
+ return self.orchestrate_rfcomm_connection(other_ad)
+
+ def orchestrate_rfcomm_connection(
+ self,
+ other_ad: AndroidDevice,
+ accept_timeout_ms: int = bt_constants.DEFAULT_RFCOMM_TIMEOUT_MS,
+ uuid: Optional[Text] = None) -> bool:
+ """Sets up the RFCOMM connection to another android device.
+
+ It sets up the connection with a Bluetooth Socket connection with other
+ device.
+
+ Args:
+ other_ad: the Android device accepting the connection from this device.
+ accept_timeout_ms: the timeout in ms for the connection.
+ uuid: universally unique identifier.
+
+ Returns:
+ True if connection was successful, False if unsuccessful.
+ """
+ if uuid is None:
+ uuid = bt_constants.BT_RFCOMM_UUIDS['default_uuid']
+ other_ad.sl4a.bluetoothStartPairingHelper()
+ self._ad.sl4a.bluetoothStartPairingHelper()
+ other_ad.sl4a.bluetoothSocketConnBeginAcceptThreadUuid(uuid,
+ accept_timeout_ms)
+ self._ad.sl4a.bluetoothSocketConnBeginConnectThreadUuid(
+ other_ad.sl4a.bluetoothGetLocalAddress(), uuid)
+
+ end_time = time.time() + bt_constants.BT_DEFAULT_TIMEOUT_SECONDS
+ test_result = True
+
+ while time.time() < end_time:
+ number_socket_connections = len(
+ other_ad.sl4a.bluetoothSocketConnActiveConnections())
+ connected = number_socket_connections > 0
+ if connected:
+ test_result = True
+ other_ad.log.info('Bluetooth socket Client Connection Active')
+ break
+ else:
+ test_result = False
+ time.sleep(1)
+ if not test_result:
+ other_ad.log.error('Failed to establish a Bluetooth socket connection')
+ return False
+ return True
+
+ def wait_for_discovery_success(
+ self,
+ mac_address: str,
+ timeout: float = 30) -> float:
+ """Waits for a device to be discovered by AndroidDevice.
+
+ Args:
+ mac_address: The Bluetooth mac address of the peripheral device.
+ timeout: Number of seconds to wait for device discovery.
+
+ Returns:
+ discovery_time: The time it takes to pair in seconds.
+
+ Raises:
+ DiscoveryError
+ """
+ start_time = time.time()
+ try:
+ self._ad.ed.wait_for_event('Discovery%s' % mac_address,
+ lambda x: x['data']['Status'], timeout)
+ discovery_time = time.time() - start_time
+ return discovery_time
+
+ except queue.Empty:
+ raise DiscoveryError('Failed to discover device %s after %d seconds' %
+ (mac_address, timeout))
+
+ def wait_for_pairing_success(
+ self,
+ mac_address: str,
+ timeout: float = 30) -> float:
+ """Waits for a device to pair with the AndroidDevice.
+
+ Args:
+ mac_address: The Bluetooth mac address of the peripheral device.
+ timeout: Number of seconds to wait for the devices to pair.
+
+ Returns:
+ pairing_time: The time it takes to pair in seconds.
+
+ Raises:
+ ControllerError
+ """
+ start_time = time.time()
+ try:
+ self._ad.ed.wait_for_event('Bond%s' % mac_address,
+ lambda x: x['data']['Status'], timeout)
+ pairing_time = time.time() - start_time
+ return pairing_time
+
+ except queue.Empty:
+ raise signals.ControllerError(
+ 'Failed to bond with device %s after %d seconds' %
+ (mac_address, timeout))
+
+ def wait_for_connection_success(
+ self,
+ mac_address: str,
+ timeout: int = 30) -> float:
+ """Waits for a device to connect with the AndroidDevice.
+
+ Args:
+ mac_address: The Bluetooth mac address of the peripheral device.
+ timeout: Number of seconds to wait for the devices to connect.
+
+ Returns:
+ connection_time: The time it takes to connect in seconds.
+
+ Raises:
+ ControllerError
+ """
+ start_time = time.time()
+ end_time = start_time + timeout
+ while time.time() < end_time:
+ if self._is_device_connected(mac_address):
+ connection_time = (time.time() - start_time)
+ logging.info('Connected device %s in %d seconds', mac_address,
+ connection_time)
+ return connection_time
+
+ raise signals.ControllerError(
+ 'Failed to connect device within %d seconds.' % timeout)
+
+ def factory_reset_bluetooth(self) -> None:
+ """Factory resets Bluetooth on an AndroidDevice."""
+
+ logging.info('Factory resetting Bluetooth for AndroidDevice.')
+ self._ad.sl4a.bluetoothToggleState(True)
+ paired_devices = self._ad.mbs.btGetPairedDevices()
+ for device in paired_devices:
+ self._ad.sl4a.bluetoothUnbond(device['Address'])
+ self._ad.sl4a.bluetoothFactoryReset()
+ self._wait_for_bluetooth_manager_state()
+ self._ad.sl4a.bluetoothToggleState(True)
+
+ def get_device_info(self) -> Dict[str, Any]:
+ """Gets the configuration info of an AndroidDevice.
+
+ Returns:
+ dict, A dictionary mapping metric keys to their respective values.
+ """
+
+ device_info = {
+ 'device_class':
+ 'AndroidDevice',
+ 'device_model':
+ self._ad.device_info['model'],
+ 'hardware_version':
+ self._ad.adb.getprop('ro.boot.hardware.revision'),
+ 'software_version':
+ self._ad.build_info['build_id'],
+ 'android_build_type':
+ self._ad.build_info['build_type'],
+ 'android_build_number':
+ self._ad.adb.getprop('ro.build.version.incremental'),
+ 'android_release_id':
+ self._ad.build_info['build_id']
+ }
+
+ return device_info
+
+ def pair_and_connect_bluetooth(
+ self,
+ mac_address: str,
+ attempts: int = 3,
+ enable_pairing_retry: bool = True) -> Tuple[float, float]:
+ """Pairs and connects an AndroidDevice with a peripheral Bluetooth device.
+
+ Ensures that an AndroidDevice is paired and connected to a peripheral
+ device. If the devices are already connected, does nothing. If
+ the devices are paired but not connected, connects the devices. If the
+ devices are neither paired nor connected, this method pairs and connects the
+ devices.
+
+ Suggests to use the retry mechanism on Discovery because it sometimes fail
+ even if the devices are testing in shielding. In order to avoid the remote
+ device may not respond a incoming pairing request causing to bonding failure
+ , it suggests to retry pairing too.
+
+ Args:
+ mac_address: The Bluetooth mac address of the peripheral device.
+ attempts: Number of attempts to discover and pair the peripheral device.
+ enable_pairing_retry: Bool to control whether the retry mechanism is used
+ on bonding failure, it's enabled if True.
+
+ Returns:
+ pairing_time: The time, in seconds, it takes to pair the devices.
+ connection_time: The time, in seconds, it takes to connect the
+ devices after pairing is completed.
+
+ Raises:
+ DiscoveryError: Raised if failed to discover the peripheral device.
+ ControllerError: Raised if failed to bond the peripheral device.
+ """
+
+ connected = self._is_device_connected(mac_address)
+ pairing_time = 0
+ connection_time = 0
+ if connected:
+ logging.info('Device %s already paired and connected', mac_address)
+ return pairing_time, connection_time
+
+ paired_devices = [device['address'] for device in
+ self._ad.sl4a.bluetoothGetBondedDevices()]
+ if mac_address in paired_devices:
+ self._ad.sl4a.bluetoothConnectBonded(mac_address)
+ return pairing_time, self.wait_for_connection_success(mac_address)
+
+ logging.info('Initiate pairing to the device "%s".', mac_address)
+ for i in range(attempts):
+ self._ad.sl4a.bluetoothDiscoverAndBond(mac_address)
+ try:
+ self.wait_for_discovery_success(mac_address)
+ pairing_time = self.wait_for_pairing_success(mac_address)
+ break
+ except DiscoveryError:
+ if i + 1 < attempts:
+ logging.error(
+ 'Failed to find the device "%s" on Attempt %d. '
+ 'Retrying discovery...', mac_address, i + 1)
+ continue
+ raise DiscoveryError('Failed to find the device "%s".' % mac_address)
+ except signals.ControllerError:
+ if i + 1 < attempts and enable_pairing_retry:
+ logging.error(
+ 'Failed to bond the device "%s" on Attempt %d. '
+ 'Retrying pairing...', mac_address, i + 1)
+ continue
+ raise signals.ControllerError('Failed to bond the device "%s".' %
+ mac_address)
+
+ connection_time = self.wait_for_connection_success(mac_address)
+ return pairing_time, connection_time
+
+ def disconnect_bluetooth(
+ self,
+ mac_address: str,
+ timeout: float = 30) -> float:
+ """Disconnects Bluetooth between an AndroidDevice and peripheral device.
+
+ Args:
+ mac_address: The Bluetooth mac address of the peripheral device.
+ timeout: Number of seconds to wait for the devices to disconnect the
+ peripheral device.
+
+ Returns:
+ disconnection_time: The time, in seconds, it takes to disconnect the
+ peripheral device.
+
+ Raises:
+ ControllerError: Raised if failed to disconnect the peripheral device.
+ """
+ if not self._is_device_connected(mac_address):
+ logging.info('Device %s already disconnected', mac_address)
+ return 0
+
+ self._ad.sl4a.bluetoothDisconnectConnected(mac_address)
+ start_time = time.time()
+ end_time = time.time() + timeout
+ while time.time() < end_time:
+ connected = self._is_device_connected(mac_address)
+ if not connected:
+ logging.info('Device %s disconnected successfully.', mac_address)
+ return time.time() - start_time
+
+ raise signals.ControllerError(
+ 'Failed to disconnect device within %d seconds.' % timeout)
+
+ def connect_bluetooth(self, mac_address: str, timeout: float = 30) -> float:
+ """Connects Bluetooth between an AndroidDevice and peripheral device.
+
+ Args:
+ mac_address: The Bluetooth mac address of the peripheral device.
+ timeout: Number of seconds to wait for the devices to connect the
+ peripheral device.
+
+ Returns:
+ connection_time: The time, in seconds, it takes to connect the
+ peripheral device.
+
+ Raises:
+ ControllerError: Raised if failed to connect the peripheral device.
+ """
+ if self._is_device_connected(mac_address):
+ logging.info('Device %s already connected', mac_address)
+ return 0
+
+ self._ad.sl4a.bluetoothConnectBonded(mac_address)
+ connect_time = self.wait_for_connection_success(mac_address)
+
+ return connect_time
+
+ def activate_pairing_mode(self) -> None:
+ """Activates pairing mode on an AndroidDevice."""
+ logging.info('Activating pairing mode on AndroidDevice.')
+ self._ad.sl4a.bluetoothMakeDiscoverable()
+ self._ad.sl4a.bluetoothStartPairingHelper()
+
+ def activate_ble_pairing_mode(self) -> None:
+ """Activates BLE pairing mode on an AndroidDevice."""
+ self.ble_advertise_callback = self._ad.sl4a.bleGenBleAdvertiseCallback()
+ self._ad.sl4a.bleSetAdvertiseDataIncludeDeviceName(True)
+ # Sets advertise mode to low latency.
+ self._ad.sl4a.bleSetAdvertiseSettingsAdvertiseMode(
+ bt_constants.BleAdvertiseSettingsMode.LOW_LATENCY)
+ self._ad.sl4a.bleSetAdvertiseSettingsIsConnectable(True)
+ # Sets TX power level to High.
+ self._ad.sl4a.bleSetAdvertiseSettingsTxPowerLevel(
+ bt_constants.BleAdvertiseSettingsTxPower.HIGH)
+ advertise_data = self._ad.sl4a.bleBuildAdvertiseData()
+ advertise_settings = self._ad.sl4a.bleBuildAdvertiseSettings()
+ logging.info('Activating BLE pairing mode on AndroidDevice.')
+ self._ad.sl4a.bleStartBleAdvertising(
+ self.ble_advertise_callback, advertise_data, advertise_settings)
+
+ def deactivate_ble_pairing_mode(self) -> None:
+ """Deactivates BLE pairing mode on an AndroidDevice."""
+ if not self.ble_advertise_callback:
+ self._ad.log.debug('BLE pairing mode is not activated.')
+ return
+ logging.info('Deactivating BLE pairing mode on AndroidDevice.')
+ self._ad.sl4a.bleStopBleAdvertising(self.ble_advertise_callback)
+ self.ble_advertise_callback = None
+
+ def get_bluetooth_mac_address(self) -> str:
+ """Gets Bluetooth mac address of an AndroidDevice."""
+ logging.info('Getting Bluetooth mac address for AndroidDevice.')
+ mac_address = self._ad.sl4a.bluetoothGetLocalAddress()
+ logging.info('Bluetooth mac address of AndroidDevice: %s', mac_address)
+ return mac_address
+
+ def scan_and_get_ble_device_address(
+ self,
+ device_name: str,
+ timeout_sec: float = 30) -> str:
+ """Searchs a BLE device by BLE scanner and returns it's BLE mac address.
+
+ Args:
+ device_name: string, the name of BLE device.
+ timeout_sec: int, number of seconds to wait for finding the advertisement.
+
+ Returns:
+ String of the BLE mac address.
+
+ Raises:
+ ControllerError: Raised if failed to get the BLE device address
+ """
+ filter_list = self._ad.sl4a.bleGenFilterList()
+ scan_settings = self._ad.sl4a.bleBuildScanSetting()
+ scan_callback = self._ad.sl4a.bleGenScanCallback()
+ self._ad.sl4a.bleSetScanFilterDeviceName(device_name)
+ self._ad.sl4a.bleBuildScanFilter(filter_list)
+ self._ad.sl4a.bleStartBleScan(filter_list, scan_settings, scan_callback)
+ try:
+ event = self._ad.ed.pop_event(
+ 'BleScan%sonScanResults' % scan_callback, timeout_sec)
+ except queue.Empty:
+ raise signals.ControllerError(
+ 'Timed out %ds after waiting for phone finding BLE device: %s.' %
+ (timeout_sec, device_name))
+ finally:
+ self._ad.sl4a.bleStopBleScan(scan_callback)
+ return event['data']['Result']['deviceInfo']['address']
+
+ def get_device_name(self) -> str:
+ """Gets Bluetooth device name of an AndroidDevice."""
+ logging.info('Getting Bluetooth device name for AndroidDevice.')
+ device_name = self._ad.sl4a.bluetoothGetLocalName()
+ logging.info('Bluetooth device name of AndroidDevice: %s', device_name)
+ return device_name
+
+ def is_bluetooth_sco_on(self) -> bool:
+ """Checks whether communications use Bluetooth SCO."""
+ cmd = 'dumpsys bluetooth_manager | grep "isBluetoothScoOn"'
+ get_status = self._ad.adb.shell(cmd)
+ if isinstance(get_status, bytes):
+ get_status = get_status.decode()
+ return 'true' in get_status
+
+ def connect_with_profile(
+ self,
+ snd_ad_mac_address: str,
+ profile: BluetoothProfile) -> bool:
+ """Connects with the profile.
+
+ The connection can only be completed after the bluetooth devices are paired.
+ To connected with the profile, the bluetooth connection policy is set to
+ forbidden first and then set to allowed. The paired bluetooth devices will
+ start to make connection. The connection time could be long. The waitting
+ time is set to BT_CONNECTION_WAITING_TIME_SECONDS (currently 10 seconds).
+
+ Args:
+ snd_ad_mac_address: the mac address of the device accepting connection.
+ profile: the profiles to be set
+
+ Returns:
+ The profile connection succeed/fail
+ """
+ if profile == BluetoothProfile.MAP_MCE:
+ self._ad.sl4a.bluetoothMapClientConnect(snd_ad_mac_address)
+ elif profile == BluetoothProfile.PBAP_CLIENT:
+ self.set_profile_policy(
+ snd_ad_mac_address, profile,
+ BluetoothConnectionPolicy.CONNECTION_POLICY_ALLOWED)
+ self._ad.sl4a.bluetoothPbapClientConnect(snd_ad_mac_address)
+ else:
+ self.set_profile_policy(
+ snd_ad_mac_address, profile,
+ BluetoothConnectionPolicy.CONNECTION_POLICY_FORBIDDEN)
+ self.set_profile_policy(
+ snd_ad_mac_address, profile,
+ BluetoothConnectionPolicy.CONNECTION_POLICY_ALLOWED)
+ self._ad.sl4a.bluetoothConnectBonded(snd_ad_mac_address)
+ time.sleep(BT_CONNECTION_WAITING_TIME_SECONDS)
+ is_connected = self._is_profile_connected(snd_ad_mac_address, profile)
+ self.log.info('The connection between %s and %s for profile %s succeed: %s',
+ self.serial, snd_ad_mac_address, profile, is_connected)
+ return is_connected
+
+ def connect_to_snd_with_profile(
+ self,
+ snd_ad: AndroidDevice,
+ profile: BluetoothProfile,
+ attempts: int = 5) -> bool:
+ """Connects pri android device to snd android device with profile.
+
+ Args:
+ snd_ad: android device accepting connection
+ profile: the profile to be connected
+ attempts: Number of attempts to try until failure.
+
+ Returns:
+ Boolean of connecting result
+ """
+ pri_ad = self._ad
+ curr_attempts = 0
+ snd_ad_mac_address = snd_ad.sl4a.bluetoothGetLocalAddress()
+ if not self.is_bt_paired(snd_ad_mac_address):
+ self.log.error('Devices %s and %s not paired before connecting',
+ self.serial, snd_ad.serial)
+ return False
+ while curr_attempts < attempts:
+ curr_attempts += 1
+ self.log.info('Connection of profile %s at curr attempt %d (total %d)',
+ profile, curr_attempts, attempts)
+ if self.connect_with_profile(snd_ad_mac_address, profile):
+ self.log.info('Connection between devices %s and %s succeeds at %d try',
+ pri_ad.serial, snd_ad.serial, curr_attempts)
+ return True
+ self.log.error('Connection of profile %s failed after %d attempts', profile,
+ attempts)
+ return False
+
+ def is_bt_paired(self, mac_address: str) -> bool:
+ """Check if the bluetooth device with mac_address is paired to ad.
+
+ Args:
+ mac_address: the mac address of the bluetooth device for pairing
+
+ Returns:
+ True if they are paired
+ """
+ bonded_info = self._ad.sl4a.bluetoothGetBondedDevices()
+ return mac_address in [info['address'] for info in bonded_info]
+
+ def is_a2dp_sink_connected(self, mac_address: str) -> bool:
+ """Checks if the Android device connects to a A2DP sink device.
+
+ Args:
+ mac_address: String, Bluetooth MAC address of the A2DP sink device.
+
+ Returns:
+ True if connected else False.
+ """
+ connected_devices = self._ad.sl4a.bluetoothA2dpGetConnectedDevices()
+ return mac_address in [d['address'] for d in connected_devices]
+
+ def hfp_connect(self, ag_ad: AndroidDevice) -> bool:
+ """Hfp connecting hf android device to ag android device.
+
+ The android device should support the Headset Client profile. For example,
+ the android device with git_master-bds-dev build.
+
+ Args:
+ ag_ad: Audio Gateway (ag) android device
+
+ Returns:
+ Boolean of connecting result
+ """
+ return self.connect_to_snd_with_profile(ag_ad,
+ BluetoothProfile.HEADSET_CLIENT)
+
+ def a2dp_sink_connect(self, src_ad: AndroidDevice) -> bool:
+ """Connects pri android device to secondary android device.
+
+ The android device should support the A2dp Sink profile. For example, the
+ android device with git_master-bds-dev build.
+
+ Args:
+ src_ad: A2dp source android device
+
+ Returns:
+ Boolean of connecting result
+ """
+ return self.connect_to_snd_with_profile(src_ad, BluetoothProfile.A2DP_SINK)
+
+ def map_connect(self, map_ad: AndroidDevice) -> bool:
+ """Connects primary device to secondary device via MAP MCE profile.
+
+ The primary device should support the MAP MCE profile. For example,
+ the android device with git_master-bds-dev build.
+
+ Args:
+ map_ad: AndroidDevice, a android device supporting MAP profile.
+
+ Returns:
+ Boolean of connecting result
+ """
+ return self.connect_to_snd_with_profile(map_ad,
+ BluetoothProfile.MAP_MCE)
+
+ def map_disconnect(self, bluetooth_address: str) -> bool:
+ """Disconnects a MAP MSE device with specified Bluetooth MAC address.
+
+ Args:
+ bluetooth_address: a connected device's bluetooth address.
+
+ Returns:
+ True if the device is disconnected else False.
+ """
+ self._ad.sl4a.bluetoothMapClientDisconnect(bluetooth_address)
+ return bt_test_utils.wait_until(
+ timeout_sec=COMMON_TIMEOUT_SECONDS,
+ condition_func=self._is_profile_connected,
+ func_args=[bluetooth_address, BluetoothProfile.MAP_MCE],
+ expected_value=False)
+
+ def pbap_connect(self, pbap_ad: AndroidDevice) -> bool:
+ """Connects primary device to secondary device via PBAP client profile.
+
+ The primary device should support the PBAP client profile. For example,
+ the android device with git_master-bds-dev build.
+
+ Args:
+ pbap_ad: AndroidDevice, a android device supporting PBAP profile.
+
+ Returns:
+ Boolean of connecting result
+ """
+ return self.connect_to_snd_with_profile(pbap_ad,
+ BluetoothProfile.PBAP_CLIENT)
+
+ def set_bluetooth_tethering(self, status_enabled: bool) -> None:
+ """Sets Bluetooth tethering to be specific status.
+
+ Args:
+ status_enabled: Bool, Bluetooth tethering will be set to enable if True,
+ else disable.
+ """
+ if self._ad.sl4a.bluetoothPanIsTetheringOn() == status_enabled:
+ self._ad.log.info('Already %s Bluetooth tethering.' %
+ ('enabled' if status_enabled else 'disabled'))
+ return
+
+ self._ad.log.info('%s Bluetooth tethering.' %
+ ('Enable' if status_enabled else 'Disable'))
+ self._ad.sl4a.bluetoothPanSetBluetoothTethering(status_enabled)
+
+ bt_test_utils.wait_until(
+ timeout_sec=COMMON_TIMEOUT_SECONDS,
+ condition_func=self._ad.sl4a.bluetoothPanIsTetheringOn,
+ func_args=[],
+ expected_value=status_enabled,
+ exception=signals.ControllerError(
+ 'Failed to %s Bluetooth tethering.' %
+ ('enable' if status_enabled else 'disable')))
+
+ def set_profile_policy(
+ self,
+ snd_ad_mac_address: str,
+ profile: BluetoothProfile,
+ policy: BluetoothConnectionPolicy) -> None:
+ """Sets policy of the profile car related profiles to OFF.
+
+ This avoids autoconnect being triggered randomly. The use of this function
+ is encouraged when you're testing individual profiles in isolation.
+
+ Args:
+ snd_ad_mac_address: the mac address of the device accepting connection.
+ profile: the profiles to be set
+ policy: the policy value to be set
+ """
+ pri_ad = self._ad
+ pri_ad_local_name = pri_ad.sl4a.bluetoothGetLocalName()
+ pri_ad.log.info('Sets profile %s on %s for %s to policy %s', profile,
+ pri_ad_local_name, snd_ad_mac_address, policy)
+ if profile == BluetoothProfile.A2DP:
+ pri_ad.sl4a.bluetoothA2dpSetPriority(snd_ad_mac_address, policy.value)
+ elif profile == BluetoothProfile.A2DP_SINK:
+ pri_ad.sl4a.bluetoothA2dpSinkSetPriority(snd_ad_mac_address, policy.value)
+ elif profile == BluetoothProfile.HEADSET_CLIENT:
+ pri_ad.sl4a.bluetoothHfpClientSetPriority(snd_ad_mac_address,
+ policy.value)
+ elif profile == BluetoothProfile.PBAP_CLIENT:
+ pri_ad.sl4a.bluetoothPbapClientSetPriority(snd_ad_mac_address,
+ policy.value)
+ elif profile == BluetoothProfile.HID_HOST:
+ pri_ad.sl4a.bluetoothHidSetPriority(snd_ad_mac_address, policy.value)
+ else:
+ pri_ad.log.error('Profile %s not yet supported for policy settings',
+ profile)
+
+ def set_profiles_policy(
+ self,
+ snd_ad: AndroidDevice,
+ profile_list: Sequence[BluetoothProfile],
+ policy: BluetoothConnectionPolicy) -> None:
+ """Sets the policy of said profile(s) on pri_ad for snd_ad.
+
+ Args:
+ snd_ad: android device accepting connection
+ profile_list: list of the profiles to be set
+ policy: the policy to be set
+ """
+ mac_address = snd_ad.sl4a.bluetoothGetLocalAddress()
+ for profile in profile_list:
+ self.set_profile_policy(mac_address, profile, policy)
+
+ def set_profiles_policy_off(
+ self,
+ snd_ad: AndroidDevice,
+ profile_list: Sequence[BluetoothProfile]) -> None:
+ """Sets policy of the profiles to OFF.
+
+ This avoids autoconnect being triggered randomly. The use of this function
+ is encouraged when you're testing individual profiles in isolation
+
+ Args:
+ snd_ad: android device accepting connection
+ profile_list: list of the profiles to be turned off
+ """
+ self.set_profiles_policy(
+ snd_ad, profile_list,
+ BluetoothConnectionPolicy.CONNECTION_POLICY_FORBIDDEN)
+
+ def wait_for_call_state(
+ self,
+ call_state: Union[int, CallState],
+ timeout_sec: float,
+ wait_interval: int = 3) -> bool:
+ """Waits for call state of the device to be changed.
+
+ Args:
+ call_state: int, the expected call state. Call state values are:
+ 0: IDLE
+ 1: RINGING
+ 2: OFFHOOK
+ timeout_sec: int, number of seconds of expiration time
+ wait_interval: int, number of seconds of waiting in each cycle
+
+ Returns:
+ True if the call state has been changed else False.
+ """
+ # TODO(user): Force external call to use CallState instead of int
+ if isinstance(call_state, CallState):
+ call_state = call_state.value
+ expiration_time = time.time() + timeout_sec
+ which_cycle = 1
+ while time.time() < expiration_time:
+ # Waits for the call state change in every cycle.
+ time.sleep(wait_interval)
+ self._ad.log.info(
+ 'in cycle %d of waiting for call state %d', which_cycle, call_state)
+ if call_state == self._ad.mbs.getTelephonyCallState():
+ return True
+ self._ad.log.info('The call state did not change to %d before timeout',
+ call_state)
+ return False
+
+ def play_audio_file_with_google_play_music(self) -> None:
+ """Plays an audio file on an AndroidDevice with Google Play Music app.
+
+ Returns:
+ None
+ """
+ try:
+ self._ad.aud.add_watcher('LOGIN').when(text='SKIP').click(text='SKIP')
+ self._ad.aud.add_watcher('NETWORK').when(text='Server error').click(
+ text='OK')
+ self._ad.aud.add_watcher('MENU').when(text='Settings').click(
+ text='Listen Now')
+ except adb_ui.Error:
+ logging.info('The watcher has been added.')
+ self._ad.sl4a.appLaunch('com.google.android.music')
+ if self._ad.aud(text='No Music available').exists(10):
+ self._ad.reboot()
+ self._ad.sl4a.appLaunch('com.google.android.music')
+ self._ad.aud(
+ resource_id='com.google.android.music:id/li_thumbnail_frame').click()
+ time.sleep(6) # Wait for audio playback to reach steady state
+
+ def add_call_log(
+ self,
+ call_log_type: Union[int, CallLogType],
+ phone_number: str,
+ call_time: int) -> None:
+ """Add call number and time to specified log.
+
+ Args:
+ call_log_type: int, number of call log type. Call log type values are:
+ 1: Incoming call
+ 2: Outgoing call
+ 3: Missed call
+ phone_number: string, phone number to be added in call log.
+ call_time: int, call time to be added in call log.
+
+ Returns:
+ None
+ """
+ # TODO(user): Force external call to use CallLogType instead of int
+ if isinstance(call_log_type, CallLogType):
+ call_log_type = call_log_type.value
+ new_call_log = {}
+ new_call_log['type'] = str(call_log_type)
+ new_call_log['number'] = phone_number
+ new_call_log['time'] = str(call_time)
+ self._ad.sl4a.callLogsPut(new_call_log)
+
+ def get_call_volume(self) -> int:
+ """Gets current call volume of an AndroidDevice when Bluetooth SCO On.
+
+ Returns:
+ An integer specifying the number of current call volume level.
+ """
+ cmd = 'dumpsys audio | grep "STREAM_BLUETOOTH_SCO" | tail -1'
+ out = self._ad.adb.shell(cmd).decode()
+ # TODO(user): Should we handle the case that re.search(...) return None
+ # below?
+ pattern = r'(?<=SCO index:)[\d]+'
+ return int(re.search(pattern, out).group())
+
+ def make_phone_call(
+ self,
+ callee: AndroidDevice,
+ timeout_sec: float = 30) -> None:
+ """Make a phone call to callee and check if callee is ringing.
+
+ Args:
+ callee: AndroidDevice, The callee in the phone call.
+ timeout_sec: int, number of seconds to wait for the callee ringing.
+
+ Raises:
+ TestError
+ """
+ self._ad.sl4a.telecomCallNumber(callee.dimensions['phone_number'])
+ is_ringing = callee.wait_for_call_state(bt_constants.CALL_STATE_RINGING,
+ timeout_sec)
+ if not is_ringing:
+ raise signals.TestError(
+ 'Timed out after %ds waiting for call state: RINGING' % timeout_sec)
+
+ def wait_for_disconnection_success(
+ self,
+ mac_address: str,
+ timeout: float = 30) -> float:
+ """Waits for a device to connect with the AndroidDevice.
+
+ Args:
+ mac_address: The Bluetooth mac address of the peripheral device.
+ timeout: Number of seconds to wait for the devices to connect.
+
+ Returns:
+ connection_time: The time it takes to connect in seconds.
+
+ Raises:
+ ControllerError
+ """
+ start_time = time.time()
+ end_time = start_time + timeout
+ while time.time() < end_time:
+ if not self._ad.sl4a.bluetoothIsDeviceConnected(mac_address):
+ disconnection_time = (time.time() - start_time)
+ logging.info('Disconnected device %s in %d seconds', mac_address,
+ disconnection_time)
+ return disconnection_time
+
+ raise signals.ControllerError(
+ 'Failed to disconnect device within %d seconds.' % timeout)
+
+ def first_pair_and_connect_bluetooth(self, bt_device: BtDevice) -> None:
+ """Pairs and connects an AndroidDevice with a Bluetooth device.
+
+ This method does factory reset bluetooth first and then pairs and connects
+ the devices.
+
+ Args:
+ bt_device: The peripheral Bluetooth device or an AndroidDevice.
+
+ Returns:
+ None
+ """
+ bt_device.factory_reset_bluetooth()
+ mac_address = bt_device.get_bluetooth_mac_address()
+ bt_device.activate_pairing_mode()
+ self.pair_and_connect_bluetooth(mac_address)
+
+ def get_device_time(self) -> str:
+ """Get device epoch time and transfer to logcat timestamp format.
+
+ Returns:
+ String of the device time.
+ """
+ return self._ad.adb.shell(
+ 'date +"%m-%d %H:%M:%S.000"').decode().splitlines()[0]
+
+ def logcat_filter(
+ self,
+ start_time: str,
+ text_filter: str = '') -> str:
+ """Returns logcat after a given time.
+
+ This method calls from the android_device logcat service file and filters
+ all logcat line prior to the start_time.
+
+ Args:
+ start_time: start time in string format of _DATETIME_FMT.
+ text_filter: only return logcat lines that include this string.
+
+ Returns:
+ A logcat output.
+
+ Raises:
+ ValueError Exception if start_time is invalid format.
+ """
+ try:
+ start_time_conv = datetime.datetime.strptime(start_time, _DATETIME_FMT)
+ except ValueError as ex:
+ logging.error('Invalid time format!')
+ raise ex
+ logcat_response = ''
+ with open(self._ad.adb_logcat_file_path, 'r', errors='replace') \
+ as logcat_file:
+ post_start_time = False
+ for line in logcat_file:
+ match = self.regex_logcat_time.match(line)
+ if match:
+ if (datetime.datetime.strptime(
+ match.group('datetime'), _DATETIME_FMT) >= start_time_conv):
+ post_start_time = True
+ if post_start_time and line.find(text_filter) >= 0:
+ logcat_response += line
+ return logcat_response
+
+ def logcat_filter_message(
+ self,
+ current_time: str,
+ text: str = '') -> str:
+ """DEPRECATED Builds the logcat command.
+
+ This method builds the logcat command to check for a specified log
+ message after the specified time. If text=None, the logcat returned will be
+ unfiltered.
+
+ Args:
+ current_time: time cutoff for grepping for the specified
+ message, format = ('%m-%d %H:%M:%S.000').
+ text: text to search for.
+
+ Returns:
+ The response of the logcat filter.
+ """
+ return self.logcat_filter(current_time, text)
+
+ def send_media_passthrough_cmd(
+ self,
+ command: str,
+ event_receiver: Optional[AndroidDevice] = None) -> None:
+ """Sends a media passthrough command.
+
+ Args:
+ command: string, media passthrough command.
+ event_receiver: AndroidDevice, a device which starts
+ BluetoothSL4AAudioSrcMBS.
+
+ Raises:
+ signals.ControllerError: raised if the event is not received.
+ """
+ self._ad.log.info('Sending Media Passthough: %s' % command)
+ self._ad.sl4a.bluetoothMediaPassthrough(command)
+ try:
+ if not event_receiver:
+ event_receiver = self._ad
+ event_receiver.ed.pop_event(MEDIA_CMD_MAP[command],
+ MEDIA_EVENT_TIMEOUT_SEC)
+ except queue.Empty:
+ raise signals.ControllerError(
+ 'Device "%s" failed to receive the event "%s" '
+ 'when the command "%s" was sent.' %
+ (event_receiver.serial, MEDIA_CMD_MAP[command], command))
+
+ def pause(self) -> None:
+ """Sends the AVRCP command "pause"."""
+ self.send_media_passthrough_cmd(bt_constants.CMD_MEDIA_PAUSE)
+
+ def play(self) -> None:
+ """Sends the AVRCP command "play"."""
+ self.send_media_passthrough_cmd(bt_constants.CMD_MEDIA_PLAY)
+
+ def track_previous(self) -> None:
+ """Sends the AVRCP command "skipPrev"."""
+ self.send_media_passthrough_cmd(bt_constants.CMD_MEDIA_SKIP_PREV)
+
+ def track_next(self) -> None:
+ """Sends the AVRCP command "skipNext"."""
+ self.send_media_passthrough_cmd(bt_constants.CMD_MEDIA_SKIP_NEXT)
+
+ def get_current_track_info(self) -> Dict[str, Any]:
+ """Returns Dict (Media metadata) representing the current track."""
+ return self._ad.sl4a.bluetoothMediaGetCurrentMediaMetaData()
+
+ def get_current_playback_state(self) -> int:
+ """Returns Integer representing the current playback state."""
+ return self._ad.sl4a.bluetoothMediaGetCurrentPlaybackState()['state']
+
+ def verify_playback_state_changed(
+ self,
+ expected_state: str,
+ exception: Optional[Exception] = None) -> bool:
+ """Verifies the playback state is changed to be the expected state.
+
+ Args:
+ expected_state: string, the changed state as expected.
+ exception: Exception, raised when the state is not changed if needed.
+ """
+ bt_test_utils.wait_until(
+ timeout_sec=MEDIA_UPDATE_TIMEOUT_SEC,
+ condition_func=self.get_current_playback_state,
+ func_args=[],
+ expected_value=expected_state,
+ exception=exception)
+
+ def verify_current_track_changed(
+ self,
+ expected_track: str,
+ exception: Optional[Exception] = None) -> bool:
+ """Verifies the Now playing track is changed to be the expected track.
+
+ Args:
+ expected_track: string, the changed track as expected.
+ exception: Exception, raised when the track is not changed if needed.
+ """
+ bt_test_utils.wait_until(
+ timeout_sec=MEDIA_UPDATE_TIMEOUT_SEC,
+ condition_func=self.get_current_track_info,
+ func_args=[],
+ expected_value=expected_track,
+ exception=exception)
+
+ def verify_avrcp_event(
+ self,
+ event_name: AvrcpEvent,
+ check_time: str,
+ timeout_sec: float = 20) -> bool:
+ """Verifies that an AVRCP event was received by an AndroidDevice.
+
+ Checks logcat to verify that an AVRCP event was received after a given
+ time.
+
+ Args:
+ event_name: enum, AVRCP event name. Currently supports play, pause,
+ track_previous, and track_next.
+ check_time: string, The earliest desired cutoff time to check the logcat.
+ Must be in format '%m-%d %H:%M:%S.000'. Use
+ datetime.datetime.now().strftime('%m-%d %H:%M:%S.%f') to get current time
+ in this format.
+ timeout_sec: int, Number of seconds to wait for the specified AVRCP event
+ be found in logcat.
+
+ Raises:
+ TestError
+
+ Returns:
+ True if the event was received.
+ """
+ avrcp_events = [
+ 'State:NOT_PLAYING->PLAYING', 'State:PLAYING->NOT_PLAYING',
+ 'sendMediaKeyEvent: keyEvent=76', 'sendMediaKeyEvent: keyEvent=75'
+ ]
+ if event_name.value not in avrcp_events:
+ raise signals.TestError('An unexpected AVRCP event is specified.')
+
+ end_time = time.time() + timeout_sec
+ while time.time() < end_time:
+ if self.logcat_filter_message(check_time, event_name.value):
+ logging.info('%s event received successfully.', event_name)
+ return True
+ time.sleep(1)
+ logging.error('AndroidDevice failed to receive %s event.', event_name)
+ logging.info('Logcat:\n%s', self.logcat_filter_message(check_time))
+ return False
+
+ def add_google_account(self, retries: int = 5) -> bool:
+ """Login Google account.
+
+ Args:
+ retries: int, the number of retries.
+
+ Returns:
+ True if account is added successfully.
+
+ Raises:
+ TestError
+ """
+ for _ in range(retries):
+ output = self._ad.adb.shell(
+ 'am instrument -w -e account "%s" -e password '
+ '"%s" -e sync true -e wait-for-checkin false '
+ 'com.google.android.tradefed.account/.AddAccount' %
+ (self._ad.dimensions['google_account'],
+ self._ad.dimensions['google_account_password'])).decode()
+ if 'result=SUCCESS' in output:
+ logging.info('Google account is added successfully')
+ time.sleep(3) # Wait for account to steady state
+ return True
+ raise signals.TestError('Failed to add google account: %s' % output)
+
+ def remove_google_account(self, retries: int = 5) -> bool:
+ """Remove Google account.
+
+ Args:
+ retries: int, the number of retries.
+
+ Returns:
+ True if account is removed successfully.
+
+ Raises:
+ TestError
+ """
+ for _ in range(retries):
+ output = self._ad.adb.shell(
+ 'am instrument -w com.google.android.tradefed.account/.RemoveAccounts'
+ ).decode()
+ if 'result=SUCCESS' in output:
+ logging.info('Google account is removed successfully')
+ return True
+ time.sleep(1) # Buffer between retries.
+ raise signals.TestError('Failed to remove google account: %s' % output)
+
+ def make_hangouts_voice_call(self, callee: AndroidDevice) -> None:
+ """Make Hangouts VOIP voice call.
+
+ Args:
+ callee: Android Device, the android device of callee.
+
+ Returns:
+ None
+ """
+ try:
+ self._ad.aud.add_watcher('SETUP').when(text='SKIP').click(text='SKIP')
+ self._ad.aud.add_watcher('REMINDER').when(text='Got it').click(
+ text='Got it')
+ except adb_ui.Error:
+ # TODO(user): Need to figure out the logic here why use info in
+ # exception catch block instead of warning/error
+ logging.info('The watcher has been added.')
+ self._ad.sl4a.appLaunch('com.google.android.talk')
+ callee.sl4a.appLaunch('com.google.android.talk')
+ # Make voice call to callee
+ try:
+ # Click the callee icon
+ self._ad.aud(resource_id='com.google.android.talk:id/avatarView').click()
+ except adb_ui.Error:
+ # Press BACK key twice and re-launch Hangouts if it is not in main page
+ for _ in range(2):
+ self._ad.aud.send_key_code(4)
+ self._ad.sl4a.appLaunch('com.google.android.talk')
+ self._ad.aud(resource_id='com.google.android.talk:id/avatarView').click()
+ # Click the button to make a voice call
+ self._ad.aud(content_desc='Call').click()
+ # Answer by callee
+ if callee.aud(text='Answer').exists(5):
+ callee.aud(text='Answer').click()
+ else:
+ callee.aud(content_desc='Join voice call').click()
+
+ def hang_up_hangouts_call(self) -> None:
+ """Hang up Hangouts VOIP voice call.
+
+ Returns:
+ None
+ """
+ # Click the in call icon to show the end call button
+ self._ad.aud(
+ resource_id='com.google.android.talk:id/in_call_main_avatar').click()
+ # Click the button to hang up call
+ self._ad.aud(content_desc='Hang up').click()
+ time.sleep(3) # Wait for VoIP call state to reach idle state
+
+ def detect_and_pull_ssrdump(self, ramdump_type: str = 'ramdump_bt') -> bool:
+ """Detect and pull RAMDUMP log.
+
+ Args:
+ ramdump_type: str, the partial of file names to search for in ramdump
+ files path. 'ramdump_bt' is used for searching Bluetooth ramdump log
+ files.
+
+ Returns:
+ True if there is a file with file name matching the ramdump type.
+ """
+ files = self._ad.adb.shell('ls %s' % bt_constants.RAMDUMP_PATH).decode()
+ if ramdump_type in files:
+ logging.info('RAMDUMP is found.')
+ log_name_timestamp = mobly_logger.get_log_file_timestamp()
+ destination = os.path.join(self._ad.log_path, 'RamdumpLogs',
+ log_name_timestamp)
+ utils.create_dir(destination)
+ self._ad.adb.pull([bt_constants.RAMDUMP_PATH, destination])
+ return True
+ return False
+
+ def get_bt_num_of_crashes(self) -> int:
+ """Get number of Bluetooth crash times from bluetooth_manager.
+
+ Returns:
+ Number of Bluetooth crashed times.
+ """
+ out = self._regex_bt_crash.search(
+ self._ad.adb.shell('dumpsys bluetooth_manager').decode())
+ # TODO(user): Need to consider the case "out=None" when miss in
+ # matching
+ return int(out.group('num_bt_crashes'))
+
+ def clean_ssrdump(self) -> None:
+ """Clean RAMDUMP log.
+
+ Returns:
+ None
+ """
+ self._ad.adb.shell('rm -rf %s/*' % bt_constants.RAMDUMP_PATH)
+
+ def set_target(self, bt_device: BtDevice) -> None:
+ """Allows for use to get target device object for target interaction."""
+ self._target_device = bt_device
+
+ def wait_for_hsp_connection_state(self,
+ mac_address: str,
+ connected: bool,
+ timeout_sec: float = 30) -> bool:
+ """Waits for HSP connection to be in a expected state on Android device.
+
+ Args:
+ mac_address: The Bluetooth mac address of the peripheral device.
+ connected: True if HSP connection state is connected as expected.
+ timeout_sec: Number of seconds to wait for HSP connection state change.
+ """
+ expected_state = BluetoothConnectionStatus.STATE_DISCONNECTED
+ if connected:
+ expected_state = BluetoothConnectionStatus.STATE_CONNECTED
+ bt_test_utils.wait_until(
+ timeout_sec=timeout_sec,
+ condition_func=self._ad.sl4a.bluetoothHspGetConnectionStatus,
+ func_args=[mac_address],
+ expected_value=expected_state,
+ exception=signals.TestError(
+ 'Failed to %s the device "%s" within %d seconds via HSP.' %
+ ('connect' if connected else 'disconnect', mac_address,
+ timeout_sec)))
+
+ def wait_for_bluetooth_toggle_state(self,
+ enabled: bool = True,
+ timeout_sec: float = 30) -> bool:
+ """Waits for Bluetooth to be in an expected state.
+
+ Args:
+ enabled: True if Bluetooth status is enabled as expected.
+ timeout_sec: Number of seconds to wait for Bluetooth to be in the expected
+ state.
+ """
+ bt_test_utils.wait_until(
+ timeout_sec=timeout_sec,
+ condition_func=self._ad.mbs.btIsEnabled,
+ func_args=[],
+ expected_value=enabled,
+ exception=signals.TestError(
+ 'Bluetooth is not %s within %d seconds on the device "%s".' %
+ ('enabled' if enabled else 'disabled', timeout_sec,
+ self._ad.serial)))
+
+ def wait_for_a2dp_connection_state(self,
+ mac_address: str,
+ connected: bool,
+ timeout_sec: float = 30) -> bool:
+ """Waits for A2DP connection to be in a expected state on Android device.
+
+ Args:
+ mac_address: The Bluetooth mac address of the peripheral device.
+ connected: True if A2DP connection state is connected as expected.
+ timeout_sec: Number of seconds to wait for A2DP connection state change.
+ """
+ bt_test_utils.wait_until(
+ timeout_sec=timeout_sec,
+ condition_func=self.is_a2dp_sink_connected,
+ func_args=[mac_address],
+ expected_value=connected,
+ exception=signals.TestError(
+ 'Failed to %s the device "%s" within %d seconds via A2DP.' %
+ ('connect' if connected else 'disconnect', mac_address,
+ timeout_sec)))
+
+ def wait_for_nap_service_connection(
+ self,
+ connected_mac_addr: str,
+ state_connected: bool,
+ exception: Exception) -> bool:
+ """Waits for NAP service connection to be expected state.
+
+ Args:
+ connected_mac_addr: String, Bluetooth Mac address is needed to be checked.
+ state_connected: Bool, NAP service connection is established as expected
+ if True, else terminated as expected.
+ exception: Exception, Raised if NAP service connection is not expected
+ state.
+
+ Raises:
+ exception: Raised if NAP service connection is not expected state.
+ """
+ def is_device_connected():
+ """Returns True if connected else False."""
+ connected_devices = self._ad.sl4a.bluetoothPanGetConnectedDevices()
+ # Check if the Bluetooth mac address is in the connected device list.
+ return connected_mac_addr in [d['address'] for d in connected_devices]
+
+ bt_test_utils.wait_until(
+ timeout_sec=bt_constants.NAP_CONNECTION_TIMEOUT_SECS,
+ condition_func=is_device_connected,
+ func_args=[],
+ expected_value=state_connected,
+ exception=exception)
+
+ def verify_internet(self,
+ allow_access: bool,
+ exception: Exception,
+ test_url: str = TEST_URL,
+ interval_sec: int = PING_INTERVAL_TIME_SEC,
+ timeout_sec: float = PING_TIMEOUT_SEC) -> bool:
+ """Verifies that internet is in expected state.
+
+ Continuously make ping request to a URL for internet verification.
+
+ Args:
+ allow_access: Bool, Device can have internet access as expected if True,
+ else no internet access as expected.
+ exception: Exception, Raised if internet is not in expected state.
+ test_url: String, A URL is used to verify internet by ping request.
+ interval_sec: Int, Interval time between ping requests in second.
+ timeout_sec: Int, Number of seconds to wait for ping success if
+ allow_access is True else wait for ping failure if allow_access is
+ False.
+
+ Raises:
+ exception: Raised if internet is not in expected state.
+ """
+ self._ad.log.info('Verify that internet %s be used.' %
+ ('can' if allow_access else 'can not'))
+
+ def http_ping():
+ """Returns True if http ping success else False."""
+ try:
+ return bool(self._ad.sl4a.httpPing(test_url))
+ except jsonrpc_client_base.ApiError as e:
+ # ApiError is raised by httpPing() when no internet.
+ self._ad.log.debug(str(e))
+ return False
+
+ bt_test_utils.wait_until(
+ timeout_sec=timeout_sec,
+ condition_func=http_ping,
+ func_args=[],
+ expected_value=allow_access,
+ exception=exception,
+ interval_sec=interval_sec)
+
+ def allow_extra_permissions(self) -> None:
+ """A method to allow extra permissions.
+
+ This method has no any logics. It is used to skip the operation when it is
+ called if a test is not Wear OS use case.
+ """
+
+ def goto_bluetooth_device_details(self) -> None:
+ """Goes to bluetooth device detail page."""
+ self._ad.adb.shell('am force-stop com.android.settings')
+ self._ad.adb.shell('am start -a android.settings.BLUETOOTH_SETTINGS')
+ self._ad.aud(
+ resource_id='com.android.settings:id/settings_button').click()
+
+ def bluetooth_ui_forget_device(self) -> None:
+ """Clicks the forget device button."""
+ self.goto_bluetooth_device_details()
+ self._ad.aud(resource_id='com.android.settings:id/button1').click()
+
+ def bluetooth_ui_disconnect_device(self) -> None:
+ """Clicks the disconnect device button."""
+ self.goto_bluetooth_device_details()
+ self._ad.aud(resource_id='com.android.settings:id/button2').click()
+
+ def _find_bt_device_details_ui_switch(self, switch_name: str):
+ """Returns the UI node for a BT switch.
+
+ Args:
+ switch_name: each switch button name in bluetooth connect device detail
+ page. switch name like 'Phone calls', 'Media audio', etc.
+
+ Returns:
+ adb_ui_device.XML node UI element of the BT each option switch button.
+ """
+ switch_button_name = ('Phone calls',
+ 'Media audio',
+ 'Contact sharing',
+ 'Text Messages'
+ )
+ if switch_name not in switch_button_name:
+ raise ValueError(f'Unknown switch name {switch_name}.')
+ self.goto_bluetooth_device_details()
+ text_node = adb_ui.wait_and_get_xml_node(
+ self._ad, timeout=10, text=switch_name)
+ text_grandparent_node = text_node.parentNode.parentNode
+ switch_node = adb_ui.Selector(
+ resource_id='android:id/switch_widget').find_node(text_grandparent_node)
+ return switch_node
+
+ def get_bt_device_details_ui_switch_state(self, switch_name: str) -> bool:
+ """Gets bluetooth each option switch button state value.
+
+ Args:
+ switch_name: each switch button name in bluetooth connect device detail
+ page.
+
+ Returns:
+ State True or False.
+ """
+ switch_node = self._find_bt_device_details_ui_switch(switch_name)
+ current_state = switch_node.attributes['checked'].value == 'true'
+ return current_state
+
+ def set_bt_device_details_ui_switch_state(
+ self, switch_name: str,
+ target_state: bool) -> None:
+ """Sets and checks the BT each option button is the target enable state.
+
+ Args:
+ switch_name: each switch button name in bluetooth connect device detail
+ page.
+ target_state: The desired state expected from the switch. If the state of
+ the switch already meet expectation, no action will be taken.
+ """
+ if self.get_bt_device_details_ui_switch_state(switch_name) == target_state:
+ return
+ switch_node = self._find_bt_device_details_ui_switch(switch_name)
+ x, y = adb_ui.find_point_in_bounds(switch_node.attributes['bounds'].value)
+ self._ad.aud.click(x, y)
+
+ def get_bt_quick_setting_switch_state(self) -> bool:
+ """Gets bluetooth quick settings switch button state value."""
+ self._ad.open_notification()
+ switch_node = self._ad_aud(class_name='android.widget.Switch', index='1')
+ current_state = switch_node.attributes['content-desc'].value == 'Bluetooth.'
+ return current_state
+
+ def assert_bt_device_details_state(self, target_state: bool) -> None:
+ """Asserts the Bluetooth connection state.
+
+ Asserts the BT each option button in device detail,
+ BT quick setting state and BT manager service from log are at the target
+ state.
+
+ Args:
+ target_state: BT each option button, quick setting and bluetooth manager
+ service target state.
+
+ """
+ for switch_name in ['Phone calls', 'Media audio']:
+ asserts.assert_equal(
+ self._ad.get_bt_device_details_ui_switch_state(switch_name),
+ target_state,
+ f'The BT Media calls switch button state is not {target_state}.')
+ asserts.assert_equal(self._ad.is_service_running(), target_state,
+ f'The BT service state is not {target_state}.')
+ asserts.assert_equal(
+ self._ad.get_bt_quick_setting_switch_state(), target_state,
+ f'The BT each switch button state is not {target_state}.')
+
+ def is_service_running(
+ self,
+ mac_address: str,
+ timeout_sec: float) -> bool:
+ """Checks bluetooth profile state.
+
+ Check bluetooth headset/a2dp profile connection
+ status from bluetooth manager log.
+
+ Args:
+ mac_address: The Bluetooth mac address of the peripheral device.
+ timeout_sec: Number of seconds to wait for the specified message
+ be found in bluetooth manager log.
+
+ Returns:
+ True: If pattern match with bluetooth_manager_log.
+ """
+ pattern_headset = (r'\sm\w+e:\sC\w+d')
+ pattern_a2dp = (r'StateMachine:.*state=Connected')
+ output_headset = self._ad.adb.shell(
+ 'dumpsys bluetooth_manager | egrep -A20 "Profile: HeadsetService"'
+ ).decode()
+ output_a2dp = self._ad.adb.shell(
+ 'dumpsys bluetooth_manager | egrep -A30 "Profile: A2dpService"').decode(
+ )
+ service_type = {
+ 'a2dp': ((pattern_a2dp), (output_a2dp)),
+ 'headset': ((pattern_headset), (output_headset))
+ }
+ start_time = time.time()
+ end_time = start_time + timeout_sec
+ while start_time < end_time:
+ try:
+ match = service_type
+ if match and mac_address in service_type:
+ return True
+ except adb.AdbError as e:
+ logging.exception(e)
+ time.sleep(ADB_WAITING_TIME_SECONDS)
+ return False
+
+ def browse_internet(self, url: str = 'www.google.com') -> None:
+ """Browses internet by Chrome.
+
+ Args:
+ url: web address.
+
+ Raises:
+ signals.TestError: raised if it failed to browse internet by Chrome.
+ """
+ browse_url = (
+ 'am start -n com.android.chrome/com.google.android.apps.chrome.Main -d'
+ ' %s' % url
+ )
+ self._ad.adb.shell(browse_url)
+ self._ad.aud.add_watcher('Welcome').when(
+ text='Accept & continue').click(text='Accept & continue')
+ self._ad.aud.add_watcher('sync page').when(
+ text='No thanks').click(text='No thanks')
+ if self._ad.aud(text='No internet').exists():
+ raise signals.TestError('No connect internet.')
+
+ def connect_wifi_from_other_device_hotspot(
+ self, wifi_hotspot_device: AndroidDevice) -> None:
+ """Turns on 2.4G Wifi hotspot from the other android device and connect on the android device.
+
+ Args:
+ wifi_hotspot_device: Android device, turn on 2.4G Wifi hotspot.
+ """
+ # Turn on 2.4G Wifi hotspot on the secondary phone.
+ wifi_hotspot_device.sl4a.wifiSetWifiApConfiguration(
+ bt_constants.WIFI_HOTSPOT_2_4G)
+ wifi_hotspot_device.sl4a.connectivityStartTethering(0, False)
+ # Connect the 2.4G Wifi on the primary phone.
+ self._ad.mbs.wifiEnable()
+ self._ad.mbs.wifiConnectSimple(
+ bt_constants.WIFI_HOTSPOT_2_4G['SSID'],
+ bt_constants.WIFI_HOTSPOT_2_4G['password'])
diff --git a/blueberry/utils/arduino_base.py b/blueberry/utils/arduino_base.py
new file mode 100644
index 0000000..37c9146
--- /dev/null
+++ b/blueberry/utils/arduino_base.py
@@ -0,0 +1,78 @@
+"""Base class for Blueberry controllers using Arduino board.
+
+This module uses pyserial library to communicate with Arduino UNO board.
+
+About Arduino code, please refer to the code of following Arduino project:
+Internal link
+"""
+
+import time
+from mobly.signals import ControllerError
+import serial
+
+
+class ArduinoBase(object):
+ """Implements an Arduino base class.
+
+ Attributes:
+ serial: serial object, a serial object which is used to communicate with
+ Arduino board.
+ """
+
+ def __init__(self, config):
+ """Initializes an Arduino base class."""
+ self._verify_config(config)
+ self.serial = serial.Serial(config['arduino_port'], 9600)
+ self.serial.timeout = 30
+ # Buffer between calling serial.Serial() and serial.Serial.write().
+ time.sleep(2)
+
+ def _verify_config(self, config):
+ """Checks the device config's required config parameters.
+
+ Args:
+ config: dict, Mobly controller config for ArduinoBass. The config should
+ include the key "arduino_port" whose value is a string representing
+ Arduino board name. e.g. /dev/ttyACM0.
+ """
+ if 'arduino_port' not in config:
+ raise ControllerError('Please provide an Arduino board port for the'
+ ' ArduinoBase in Mobile Harness config')
+
+ def _send_string_to_arduino(self, tx_string):
+ """Sends a particular string to communicate with Arduino.
+
+ The method requires that Arduino code can read string which is received from
+ a python serial object and then send the same string to the serial object.
+
+ An example of Arduino code:
+ String kRxString = "";
+ void setup() {
+ ...
+ }
+ void loop() {
+ if (Serial.available() > 0) {
+ kRxString = Serial.readString();
+ ...
+ Serial.write(kRxString.c_str());
+ }
+ }
+
+ Args:
+ tx_string: string, is used to be sent to Arduino port for making the
+ controlled device perform action. After Arduino receives the string, it
+ will send a response which is the same string.
+
+ Returns:
+ The time it takes for waiting a response, in seconds.
+
+ Raises:
+ ControllerError: raised if not received a response from Arduino.
+ """
+ self.serial.write(str.encode(tx_string))
+ start_time = time.time()
+ rx_string = self.serial.read_until(tx_string, len(tx_string)).decode()
+ if rx_string == tx_string:
+ return time.time() - start_time
+ raise ControllerError('Timed out after %ds waiting for the string "%s" from'
+ ' Arduino.' % (self.serial.timeout, tx_string))
diff --git a/blueberry/utils/blueberry_base_test.py b/blueberry/utils/blueberry_base_test.py
new file mode 100644
index 0000000..abe19cd
--- /dev/null
+++ b/blueberry/utils/blueberry_base_test.py
@@ -0,0 +1,244 @@
+"""Base test class for Blueberry."""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import re
+
+from mobly import base_test
+from mobly import signals
+from mobly.controllers import android_device
+from mobly.controllers.android_device_lib import adb
+
+# Internal import
+# Internal import
+# Internal import
+# Internal import
+from blueberry.controllers import derived_bt_device
+from blueberry.decorators import android_bluetooth_client_decorator
+from blueberry.utils.android_bluetooth_decorator import AndroidBluetoothDecorator
+
+
+class BlueberryBaseTest(base_test.BaseTestClass):
+ """Base test class for all Blueberry tests to inherit from.
+
+ This class assists with device setup for device logging and other pre test
+ setup required for Bluetooth tests.
+ """
+
+ def setup_generated_tests(self):
+ """Generates multiple the same tests for pilot run.
+
+ This is used to let developers can easily pilot run their tests many times,
+ help them to check test stability and reliability. If need to use this,
+ please add a flag called "test_iterations" to TestParams in Mobly test
+ configuration and its value is number of test methods to be generated. The
+ naming rule of test method on Sponge is such as the following example:
+ test_send_file_via_bluetooth_opp_1_of_50
+ test_send_file_via_bluetooth_opp_2_of_50
+ test_send_file_via_bluetooth_opp_3_of_50
+ ...
+ test_send_file_via_bluetooth_opp_50_of_50
+
+ Don't use "test_case_selector" when using "test_iterations", and please use
+ "test_method_selector" to replace it.
+ """
+ test_iterations = int(self.user_params.get('test_iterations', 0))
+ if test_iterations < 2:
+ return
+
+ test_method_selector = self.user_params.get('test_method_selector', 'all')
+ existing_test_names = self.get_existing_test_names()
+
+ selected_test_names = None
+ if test_method_selector == 'all':
+ selected_test_names = existing_test_names
+ else:
+ selected_test_names = test_method_selector.split(' ')
+ # Check if selected test methods exist in the test class.
+ for test_name in selected_test_names:
+ if test_name not in existing_test_names:
+ raise base_test.Error('%s does not have test method "%s".' %
+ (self.TAG, test_name))
+
+ for test_name in selected_test_names:
+ test_method = getattr(self.__class__, test_name)
+ # List of (<new test name>, <test method>).
+ test_arg_sets = [('%s_%s_of_%s' % (test_name, i + 1, test_iterations),
+ test_method) for i in range(test_iterations)]
+ # pylint: disable=cell-var-from-loop
+ self.generate_tests(
+ test_logic=lambda _, test: test(self),
+ name_func=lambda name, _: name,
+ arg_sets=test_arg_sets)
+
+ # Delete origin test methods in order to avoid below situation:
+ # test_send_file_via_bluetooth_opp <-- origin test method
+ # test_send_file_via_bluetooth_opp_1_of_50
+ # test_send_file_via_bluetooth_opp_2_of_50
+ for test_name in existing_test_names:
+ delattr(self.__class__, test_name)
+
+ def setup_class(self):
+ """Setup class is called before running any tests."""
+ super(BlueberryBaseTest, self).setup_class()
+ self.capture_bugreport_on_fail = int(self.user_params.get(
+ 'capture_bugreport_on_fail', 0))
+ self.ignore_device_setup_failures = int(self.user_params.get(
+ 'ignore_device_setup_failures', 0))
+ self.enable_bluetooth_verbose_logging = int(self.user_params.get(
+ 'enable_bluetooth_verbose_logging', 0))
+ self.enable_hci_snoop_logging = int(self.user_params.get(
+ 'enable_hci_snoop_logging', 0))
+ self.increase_logger_buffers = int(self.user_params.get(
+ 'increase_logger_buffers', 0))
+ self.enable_all_bluetooth_logging = int(self.user_params.get(
+ 'enable_all_bluetooth_logging', 0))
+
+ # base test should include the test between primary device with Bluetooth
+ # peripheral device.
+ self.android_devices = self.register_controller(
+ android_device, required=False)
+
+ # In the case of no android_device assigned, at least 2 derived_bt_device
+ # is required.
+ if self.android_devices is None:
+ self.derived_bt_devices = self.register_controller(
+ module=derived_bt_device, min_number=2)
+ else:
+ self.derived_bt_devices = self.register_controller(
+ module=derived_bt_device, required=False)
+
+ if self.derived_bt_devices is None:
+ self.derived_bt_devices = []
+ else:
+ for derived_device in self.derived_bt_devices:
+ derived_device.set_user_params(self.user_params)
+ derived_device.setup()
+
+ self.android_ui_devices = {}
+ # Create a dictionary of Android UI Devices
+ for device in self.android_devices:
+ self.android_ui_devices[device.serial] = AdbUiDevice(device)
+ mobly_config = {'aud': self.android_ui_devices[device.serial]}
+ device.load_config(mobly_config)
+ need_restart_bluetooth = False
+ if (self.enable_bluetooth_verbose_logging or
+ self.enable_all_bluetooth_logging):
+ if self.set_bt_trc_level_verbose(device):
+ need_restart_bluetooth = True
+ if self.enable_hci_snoop_logging or self.enable_all_bluetooth_logging:
+ if self.set_btsnooplogmode_full(device):
+ need_restart_bluetooth = True
+ if self.increase_logger_buffers or self.enable_all_bluetooth_logging:
+ self.set_logger_buffer_size_16m(device)
+
+ # Restarts Bluetooth to take BT VERBOSE and HCI Snoop logging effect.
+ if need_restart_bluetooth:
+ device.log.info('Restarting Bluetooth by airplane mode...')
+ self.restart_bluetooth_by_airplane_mode(device)
+ self.android_devices = [AndroidBluetoothDecorator(device)
+ for device in self.android_devices]
+ for device in self.android_devices:
+ device.set_user_params(self.user_params)
+
+ self.client_decorators = self.user_params.get('sync_decorator', [])
+ if self.client_decorators:
+ self.client_decorators = self.client_decorators.split(',')
+
+ self.target_decorators = self.user_params.get('target_decorator', [])
+ if self.target_decorators:
+ self.target_decorators = self.target_decorators.split(',')
+
+ for decorator in self.client_decorators:
+ self.android_devices[0] = android_bluetooth_client_decorator.decorate(
+ self.android_devices[0], decorator)
+
+ for num_devices in range(1, len(self.android_devices)):
+ for decorator in self.target_decorators:
+ self.android_devices[
+ num_devices] = android_bluetooth_client_decorator.decorate(
+ self.android_devices[num_devices], decorator)
+
+ def on_fail(self, record):
+ """This method is called when a test failure."""
+ # Capture bugreports on fail if enabled.
+ if self.capture_bugreport_on_fail:
+ devices = self.android_devices
+ # Also capture bugreport of AndroidBtTargetDevice.
+ for d in self.derived_bt_devices:
+ if hasattr(d, 'take_bug_report'):
+ devices = devices + [d]
+ android_device.take_bug_reports(
+ devices,
+ record.test_name,
+ record.begin_time,
+ destination=self.current_test_info.output_path)
+
+ def set_logger_buffer_size_16m(self, device):
+ """Sets all logger sizes per log buffer to 16M."""
+ device.log.info('Setting all logger sizes per log buffer to 16M...')
+ # Logger buffer info:
+ # https://developer.android.com/studio/command-line/logcat#alternativeBuffers
+ logger_buffers = ['main', 'system', 'crash', 'radio', 'events', 'kernel']
+ for buffer in logger_buffers: # pylint: disable=redefined-builtin
+ device.adb.shell('logcat -b %s -G 16M' % buffer)
+ buffer_size = device.adb.shell('logcat -b %s -g' % buffer)
+ if isinstance(buffer_size, bytes):
+ buffer_size = buffer_size.decode()
+ if 'ring buffer is 16' in buffer_size:
+ device.log.info('Successfully set "%s" buffer size to 16M.' % buffer)
+ else:
+ msg = 'Failed to set "%s" buffer size to 16M.' % buffer
+ if not self.ignore_device_setup_failures:
+ raise signals.TestError(msg)
+ device.log.warning(msg)
+
+ def set_bt_trc_level_verbose(self, device):
+ """Modifies etc/bluetooth/bt_stack.conf to enable Bluetooth VERBOSE log."""
+ device.log.info('Enabling Bluetooth VERBOSE logging...')
+ bt_stack_conf = device.adb.shell('cat etc/bluetooth/bt_stack.conf')
+ if isinstance(bt_stack_conf, bytes):
+ bt_stack_conf = bt_stack_conf.decode()
+ # Check if 19 trace level settings are set to 6(VERBOSE). E.g. TRC_HCI=6.
+ if len(re.findall('TRC.*=[6]', bt_stack_conf)) == 19:
+ device.log.info('Bluetooth VERBOSE logging has already enabled.')
+ return False
+ # Suggest to use AndroidDeviceSettingsDecorator to disable verity and then
+ # reboot (b/140277443).
+ disable_verity_check(device)
+ device.adb.remount()
+ try:
+ device.adb.shell(r'sed -i "s/\(TRC.*=\)2/\16/g;s/#\(LoggingV=--v=\)0/\13'
+ '/" etc/bluetooth/bt_stack.conf')
+ device.log.info('Successfully enabled Bluetooth VERBOSE Logging.')
+ return True
+ except adb.AdbError:
+ msg = 'Failed to enable Bluetooth VERBOSE Logging.'
+ if not self.ignore_device_setup_failures:
+ raise signals.TestError(msg)
+ device.log.warning(msg)
+ return False
+
+ def set_btsnooplogmode_full(self, device):
+ """Enables bluetooth snoop logging."""
+ device.log.info('Enabling Bluetooth HCI Snoop logging...')
+ device.adb.shell('setprop persist.bluetooth.btsnooplogmode full')
+ out = device.adb.shell('getprop persist.bluetooth.btsnooplogmode')
+ if isinstance(out, bytes):
+ out = out.decode()
+ # The expected output is "full/n".
+ if 'full' in out:
+ device.log.info('Successfully enabled Bluetooth HCI Snoop Logging.')
+ return True
+ msg = 'Failed to enable Bluetooth HCI Snoop Logging.'
+ if not self.ignore_device_setup_failures:
+ raise signals.TestError(msg)
+ device.log.warning(msg)
+ return False
+
+ def restart_bluetooth_by_airplane_mode(self, device):
+ """Restarts bluetooth by airplane mode."""
+ enable_airplane_mode(device, 3)
+ disable_airplane_mode(device, 3)
diff --git a/blueberry/utils/bt_audio_utils.py b/blueberry/utils/bt_audio_utils.py
new file mode 100644
index 0000000..a4c2e8e
--- /dev/null
+++ b/blueberry/utils/bt_audio_utils.py
@@ -0,0 +1,229 @@
+# Lint as: python3
+"""Utils for bluetooth audio testing."""
+
+import logging as log
+import os
+import numpy as np
+from scipy import signal as scipy_signal
+from scipy.io import wavfile
+# Internal import
+# Internal import
+
+
+def generate_sine_wave_to_device(
+ device,
+ pushed_file_path='/sdcard/Music',
+ frequency=480,
+ channel=2,
+ sample_rate=48000,
+ sample_format=16,
+ duration_sec=10):
+ """Generates a fixed frequency sine wave file and push it to the device.
+
+ Generates a sine wave to the Mobly device directory and push it to the device
+ storage. The output file name format is such as the example:
+ sine_480hz_2ch_48000rate_16bit_10sec.wav
+
+ Args:
+ device: AndroidDevice, Mobly Android controller class.
+ pushed_file_path: string, the wave file path which is pushed to the device
+ storage. E.g. /sdcard/Music
+ frequency: int, fixed frequency in Hz.
+ channel: int, number of channels.
+ sample_rate: int, sampling rate in Hz.
+ sample_format: int, sampling format in bit.
+ duration_sec: int, audio duration in second.
+
+ Returns:
+ device_storage_path: string, the wave file on the device storage.
+ mobly_directory_path: string, the wave file on the Mobly device directory.
+ """
+ file_name = 'sine_%dhz_%dch_%drate_%dbit_%dsec.wav' % (
+ frequency, channel, sample_rate, sample_format, duration_sec)
+ mobly_directory_path = os.path.join(device.log_path, file_name)
+ os.system('%s -n -c %d -r %d -b %d %s synth %d sine %d' %
+ (audio_processor.AudioProcessor.SOX, channel, sample_rate,
+ sample_format, mobly_directory_path, duration_sec, frequency))
+ device.adb.push([mobly_directory_path, pushed_file_path])
+ device_storage_path = os.path.join(pushed_file_path, file_name)
+ return device_storage_path, mobly_directory_path
+
+
+def measure_audio_mos(recorded_audio_file, reference_audio_file):
+ """Measures mean opinion score (MOS) of a recorded audio.
+
+ This function uses the module of A/V Analysis Service to measure MOS:
+ Internal reference
+
+ Args:
+ recorded_audio_file: string, the recorded audio file to be measured.
+ reference_audio_file: string, the reference audio file for comparison.
+
+ Returns:
+ Float which is the mean opinion score of the recorded audio.
+ """
+ results = audio_calculator.AudioAnalyzer().Analyze(reference_audio_file,
+ recorded_audio_file)
+ # Returns 0.0 if the results fails to be generated.
+ if not results:
+ log.warning('Failed to generate the audio analysis results.')
+ return 0.0
+ return results[0].mos
+
+
+def measure_fundamental_frequency(signal, sample_rate):
+ """Measures fundamental frequency of a signal.
+
+ Args:
+ signal: An 1-D array representing the signal data.
+ sample_rate: int, sample rate of the signal.
+
+ Returns:
+ Float representing the fundamental frequency.
+ """
+ return sample_rate * (np.argmax(np.abs(np.fft.rfft(signal))) / len(signal))
+
+
+def measure_rms(signal):
+ """Measures Root Mean Square (RMS) of a signal.
+
+ Args:
+ signal: An 1-D array representing the signal data.
+
+ Returns:
+ Float representing the root mean square.
+ """
+ return np.sqrt(np.mean(np.absolute(signal)**2))
+
+
+def measure_thdn(signal, sample_rate, q, frequency=None):
+ """Measures Total Harmonic Distortion + Noise (THD+N) of a signal.
+
+ Args:
+ signal: An 1-D array representing the signal data.
+ sample_rate: int, sample rate of the signal.
+ q: float, quality factor for the notch filter.
+ frequency: float, fundamental frequency of the signal. All other frequencies
+ are noise. If not specified, will be calculated using FFT.
+
+ Returns:
+ Float representing THD+N ratio calculated from the ratio of RMS of pure
+ harmonics and noise signal to RMS of original signal.
+ """
+ # Normalizes the signal.
+ signal -= np.mean(signal)
+ # Gets Blackman-Harris window from the signal.
+ window = signal * scipy_signal.blackmanharris(len(signal))
+ # Finds the fundamental frequency to remove if not specified.
+ if not frequency:
+ frequency = measure_fundamental_frequency(window, sample_rate)
+ # Creates a notch filter to get noise from the signal.
+ wo = frequency / (sample_rate / 2)
+ b, a = scipy_signal.iirnotch(wo, q)
+ noise = scipy_signal.lfilter(b, a, window)
+ return measure_rms(noise) / measure_rms(window)
+
+
+def measure_audio_thdn_per_window(
+ audio_file,
+ thdn_threshold,
+ step_size,
+ window_size,
+ q,
+ frequency=None):
+ """Measures Total Harmonic Distortion + Noise (THD+N) of an audio file.
+
+ This function is used to capture audio glitches from a recorded audio file,
+ and the audio file shall record a fixed frequency sine wave.
+
+ Args:
+ audio_file: A .wav file to be measured.
+ thdn_threshold: float, a THD+N threshold used to compare with the measured
+ THD+N for every windows. If THD+N of a window is greater than the
+ threshold, will record this to results.
+ step_size: int, number of samples to move the window by for each analysis.
+ window_size: int, number of samples to analyze each time.
+ q: float, quality factor for the notch filter.
+ frequency: float, fundamental frequency of the signal. All other frequencies
+ are noise. If not specified, will be calculated using FFT.
+
+ Returns:
+ List containing each result of channels. Like the following structure:
+ ```
+ [
+ [ # result of channel 1
+ {
+ "thd+n": <float>, # THD+N of a window
+ "start_time": <float>, # start time of a window
+ "end_time": <float>, # end time of a window
+ },
+ ...,
+ ],
+ [...,] # result of channel 2
+ ...,
+ ]
+ ```
+ """
+ if step_size <= 0:
+ raise ValueError('step_size shall be greater than 0.')
+ if window_size <= 0:
+ raise ValueError('window_size shall be greater than 0.')
+ sample_rate, wave_data = wavfile.read(audio_file)
+ wave_data = wave_data.astype('float64')
+ # Collects the result for each channels.
+ results = []
+ for signal in wave_data.transpose():
+ current_position = 0
+ channel_result = []
+ while current_position + window_size < len(signal):
+ window = signal[current_position:current_position + window_size]
+ thdn = measure_thdn(
+ signal=window,
+ sample_rate=sample_rate,
+ q=q,
+ frequency=frequency)
+ start_time = current_position / sample_rate
+ end_time = (current_position + window_size) / sample_rate
+ if thdn > thdn_threshold:
+ channel_result.append({
+ 'thd+n': thdn,
+ 'start_time': start_time,
+ 'end_time': end_time
+ })
+ current_position += step_size
+ results.append(channel_result)
+ return results
+
+
+def trim_audio(audio_file: str,
+ duration_sec: float,
+ start_time_sec: float = 0.0) -> str:
+ """Trims an audio file with a specific start time and duration.
+
+ Generates a output file and its name is such as below format:
+ `<input file name>_<start time sec>-<duration sec>.<input file type>`
+
+ Args:
+ audio_file: string, an audio file to be trimed.
+ duration_sec: float, the duration of the output file in seconds.
+ start_time_sec: float, the start time of the audio file to be trimmed in
+ seconds. Default value is 0.0 second if not specified.
+
+ Returns:
+ String, the output file of the same path of the origin file.
+ """
+ file_path, file_name = os.path.split(audio_file)
+ file_name, file_ext = os.path.splitext(file_name)
+ output_file_name = '%s_%s-%s%s' % (
+ file_name,
+ start_time_sec,
+ (start_time_sec + duration_sec),
+ file_ext)
+ output_file = os.path.join(file_path, output_file_name)
+ processor = audio_processor.AudioProcessor()
+ processor.TrimAudio(
+ input_file=audio_file,
+ output_file=output_file,
+ duration=duration_sec,
+ start=start_time_sec)
+ return output_file
diff --git a/blueberry/utils/bt_constants.py b/blueberry/utils/bt_constants.py
new file mode 100644
index 0000000..6a94e83
--- /dev/null
+++ b/blueberry/utils/bt_constants.py
@@ -0,0 +1,191 @@
+# Lint as: python3
+"""Constants used for bluetooth test."""
+
+import enum
+
+
+### Generic Constants Begin ###
+BT_DEFAULT_TIMEOUT_SECONDS = 15
+DEFAULT_RFCOMM_TIMEOUT_MS = 10000
+CALL_STATE_IDLE = 0
+CALL_STATE_RINGING = 1
+CALL_STATE_OFFHOOK = 2
+CALL_STATE_TIMEOUT_SEC = 30
+NAP_CONNECTION_TIMEOUT_SECS = 20
+
+# Call log types.
+INCOMING_CALL_LOG_TYPE = '1'
+OUTGOING_CALL_LOG_TYPE = '2'
+MISSED_CALL_LOG_TYPE = '3'
+
+# Passthrough Commands sent to the RPC Server.
+CMD_MEDIA_PLAY = 'play'
+CMD_MEDIA_PAUSE = 'pause'
+CMD_MEDIA_SKIP_NEXT = 'skipNext'
+CMD_MEDIA_SKIP_PREV = 'skipPrev'
+
+# Events dispatched from the RPC Server.
+EVENT_PLAY_RECEIVED = 'playReceived'
+EVENT_PAUSE_RECEIVED = 'pauseReceived'
+EVENT_SKIP_NEXT_RECEIVED = 'skipNextReceived'
+EVENT_SKIP_PREV_RECEIVED = 'skipPrevReceived'
+
+# A playback state indicating the media session is currently paused.
+STATE_PAUSED = 2
+STATE_PLAYING = 3
+
+# File path
+RAMDUMP_PATH = 'data/vendor/ssrdump'
+
+# UiAutoHelper package name.
+UIAUTO_HELPER_PACKAGE_NAME = 'com.google.android.uiautohelper'
+
+# Test Runner for Android instrumentation test.
+ANDROIDX_TEST_RUNNER = 'androidx.test.runner.AndroidJUnitRunner'
+
+# Wifi hotspot setting
+WIFI_HOTSPOT_2_4G = {'SSID': 'pqmBT', 'password': 'password', 'apBand': 0}
+
+
+class AvrcpEvent(enum.Enum):
+ """Enumeration of AVRCP event types."""
+ PLAY = 'State:NOT_PLAYING->PLAYING'
+ PAUSE = 'State:PLAYING->NOT_PLAYING'
+ TRACK_PREVIOUS = 'sendMediaKeyEvent: keyEvent=76'
+ TRACK_NEXT = 'sendMediaKeyEvent: keyEvent=75'
+
+# Bluetooth RFCOMM UUIDs as defined by the SIG
+BT_RFCOMM_UUIDS = {
+ 'default_uuid': '457807c0-4897-11df-9879-0800200c9a66',
+ 'base_uuid': '00000000-0000-1000-8000-00805F9B34FB',
+ 'sdp': '00000001-0000-1000-8000-00805F9B34FB',
+ 'udp': '00000002-0000-1000-8000-00805F9B34FB',
+ 'rfcomm': '00000003-0000-1000-8000-00805F9B34FB',
+ 'tcp': '00000004-0000-1000-8000-00805F9B34FB',
+ 'tcs_bin': '00000005-0000-1000-8000-00805F9B34FB',
+ 'tcs_at': '00000006-0000-1000-8000-00805F9B34FB',
+ 'att': '00000007-0000-1000-8000-00805F9B34FB',
+ 'obex': '00000008-0000-1000-8000-00805F9B34FB',
+ 'ip': '00000009-0000-1000-8000-00805F9B34FB',
+ 'ftp': '0000000A-0000-1000-8000-00805F9B34FB',
+ 'http': '0000000C-0000-1000-8000-00805F9B34FB',
+ 'wsp': '0000000E-0000-1000-8000-00805F9B34FB',
+ 'bnep': '0000000F-0000-1000-8000-00805F9B34FB',
+ 'upnp': '00000010-0000-1000-8000-00805F9B34FB',
+ 'hidp': '00000011-0000-1000-8000-00805F9B34FB',
+ 'hardcopy_control_channel': '00000012-0000-1000-8000-00805F9B34FB',
+ 'hardcopy_data_channel': '00000014-0000-1000-8000-00805F9B34FB',
+ 'hardcopy_notification': '00000016-0000-1000-8000-00805F9B34FB',
+ 'avctp': '00000017-0000-1000-8000-00805F9B34FB',
+ 'avdtp': '00000019-0000-1000-8000-00805F9B34FB',
+ 'cmtp': '0000001B-0000-1000-8000-00805F9B34FB',
+ 'mcap_control_channel': '0000001E-0000-1000-8000-00805F9B34FB',
+ 'mcap_data_channel': '0000001F-0000-1000-8000-00805F9B34FB',
+ 'l2cap': '00000100-0000-1000-8000-00805F9B34FB'
+}
+
+
+class BluetoothAccessLevel(enum.IntEnum):
+ """Enum class for bluetooth profile access levels."""
+ ACCESS_ALLOWED = 1
+ ACCESS_DENIED = 2
+
+
+class BluetoothProfile(enum.IntEnum):
+ """Enum class for bluetooth profile types.
+
+ Should be kept in sync with
+ //frameworks/base/core/java/android/bluetooth/BluetoothProfile.java
+ """
+
+ HEADSET = 1
+ A2DP = 2
+ HEALTH = 3
+ HID_HOST = 4
+ PAN = 5
+ PBAP = 6
+ GATT = 7
+ GATT_SERVER = 8
+ MAP = 9
+ SAP = 10
+ A2DP_SINK = 11
+ AVRCP_CONTROLLER = 12
+ AVRCP = 13
+ HEADSET_CLIENT = 16
+ PBAP_CLIENT = 17
+ MAP_MCE = 18
+ HID_DEVICE = 19
+ OPP = 20
+ HEARING_AID = 21
+
+
+class BluetoothConnectionPolicy(enum.IntEnum):
+ """Enum class for bluetooth bluetooth connection policy.
+
+ bluetooth connection policy as defined in
+ //frameworks/base/core/java/android/bluetooth/BluetoothProfile.java
+ """
+ CONNECTION_POLICY_UNKNOWN = -1
+ CONNECTION_POLICY_FORBIDDEN = 0
+ CONNECTION_POLICY_ALLOWED = 100
+
+
+class BluetoothConnectionStatus(enum.IntEnum):
+ """Enum class for bluetooth connection status.
+
+ Bluetooth connection status as defined in
+ //frameworks/base/core/java/android/bluetooth/BluetoothProfile.java
+ """
+ STATE_DISCONNECTED = 0
+ STATE_CONNECTING = 1
+ STATE_CONNECTED = 2
+ STATE_DISCONNECTING = 3
+
+
+class BluetoothPriorityLevel(enum.IntEnum):
+ """Enum class for bluetooth priority level.
+
+ Priority levels as defined in
+ //frameworks/base/core/java/android/bluetooth/BluetoothProfile.java
+ """
+
+ PRIORITY_AUTO_CONNECT = 1000
+ PRIORITY_ON = 100
+ PRIORITY_OFF = 0
+ PRIORITY_UNDEFINED = -1
+
+
+class BleAdvertiseSettingsMode(enum.IntEnum):
+ """Enum class for BLE advertise settings mode."""
+ LOW_POWER = 0
+ BALANCED = 1
+ LOW_LATENCY = 2
+
+
+class BleAdvertiseSettingsTxPower(enum.IntEnum):
+ """Enum class for BLE advertise settings tx power."""
+ ULTRA_LOW = 0
+ LOW = 1
+ MEDIUM = 2
+ HIGH = 3
+
+
+class LogType(enum.Enum):
+ """Enumeration of device log type."""
+ DEFAULT_VALUE = 'GENERIC'
+ BLUETOOTH_DEVICE_SIMULATOR = 'BDS'
+ ICLEVER_HB01 = 'GENERIC'
+
+
+class CallState(enum.IntEnum):
+ """Enum class for phone call state."""
+ IDLE = 0
+ RINGING = 1
+ OFFHOOK = 2
+
+
+class CallLogType(enum.IntEnum):
+ """Enum class for phone call log type."""
+ INCOMING_CALL = 1
+ OUTGOING_CALL = 2
+ MISSED_CALL = 3
diff --git a/blueberry/utils/bt_test_utils.py b/blueberry/utils/bt_test_utils.py
new file mode 100644
index 0000000..e9d6ec0
--- /dev/null
+++ b/blueberry/utils/bt_test_utils.py
@@ -0,0 +1,200 @@
+# Lint as: python3
+"""Utils for blue tooth tests.
+
+Partly ported from acts/framework/acts/test_utils/bt/bt_test_utils.py
+"""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import logging as log
+import os
+import random
+import string
+import time
+import wave
+
+
+def convert_pcm_to_wav(pcm_file_path, wave_file_path, audio_params):
+ """Converts raw pcm data into wave file.
+
+ Args:
+ pcm_file_path: File path of origin pcm file.
+ wave_file_path: File path of converted wave file.
+ audio_params: A dict with audio configuration.
+ """
+ with open(pcm_file_path, 'rb') as pcm_file:
+ frames = pcm_file.read()
+ write_record_file(wave_file_path, audio_params, frames)
+
+
+def create_vcf_from_vcard(output_path: str,
+ num_of_contacts: int,
+ first_name: str = None,
+ last_name: str = None,
+ phone_number: int = None) -> str:
+ """Creates a vcf file from vCard.
+
+ Args:
+ output_path: Path of the output vcf file.
+ num_of_contacts: Number of contacts to be generated.
+ first_name: First name of the contacts.
+ last_name: Last name of the contacts.
+ phone_number: Phone number of the contacts.
+
+ Returns:
+ vcf_file_path: Path of the output vcf file. E.g.
+ "/<output_path>/contacts_<time>.vcf".
+ """
+ file_name = f'contacts_{int(time.time())}.vcf'
+ vcf_file_path = os.path.join(output_path, file_name)
+ with open(vcf_file_path, 'w+') as f:
+ for i in range(num_of_contacts):
+ lines = []
+ if first_name is None:
+ first_name = 'Person'
+ vcard_last_name = last_name
+ if last_name is None:
+ vcard_last_name = i
+ vcard_phone_number = phone_number
+ if phone_number is None:
+ vcard_phone_number = random.randrange(int(10e10))
+ lines.append('BEGIN:VCARD\n')
+ lines.append('VERSION:2.1\n')
+ lines.append(f'N:{vcard_last_name};{first_name};;;\n')
+ lines.append(f'FN:{first_name} {vcard_last_name}\n')
+ lines.append(f'TEL;CELL:{vcard_phone_number}\n')
+ lines.append(f'EMAIL;PREF:{first_name}{vcard_last_name}@gmail.com\n')
+ lines.append('END:VCARD\n')
+ f.write(''.join(lines))
+ return vcf_file_path
+
+
+def generate_id_by_size(size,
+ chars=(string.ascii_lowercase + string.ascii_uppercase +
+ string.digits)):
+ """Generate random ascii characters of input size and input char types.
+
+ Args:
+ size: Input size of string.
+ chars: (Optional) Chars to use in generating a random string.
+
+ Returns:
+ String of random input chars at the input size.
+ """
+ return ''.join(random.choice(chars) for _ in range(size))
+
+
+def get_duration_seconds(wav_file_path):
+ """Get duration of most recently recorded file.
+
+ Args:
+ wav_file_path: path of the wave file.
+
+ Returns:
+ duration (float): duration of recorded file in seconds.
+ """
+ f = wave.open(wav_file_path, 'r')
+ frames = f.getnframes()
+ rate = f.getframerate()
+ duration = (frames / float(rate))
+ f.close()
+ return duration
+
+
+def wait_until(timeout_sec,
+ condition_func,
+ func_args,
+ expected_value,
+ exception=None,
+ interval_sec=0.5):
+ """Waits until a function returns a expected value or timeout is reached.
+
+ Example usage:
+ ```
+ def is_bluetooth_enabled(device) -> bool:
+ do something and return something...
+
+ # Waits and checks if Bluetooth is turned on.
+ bt_test_utils.wait_until(
+ timeout_sec=10,
+ condition_func=is_bluetooth_enabled,
+ func_args=[dut],
+ expected_value=True,
+ exception=signals.TestFailure('Failed to turn on Bluetooth.'),
+ interval_sec=1)
+ ```
+
+ Args:
+ timeout_sec: float, max waiting time in seconds.
+ condition_func: function, when the condiction function returns the expected
+ value, the waiting mechanism will be interrupted.
+ func_args: tuple or list, the arguments for the condition function.
+ expected_value: a expected value that the condition function returns.
+ exception: Exception, an exception will be raised when timed out if needed.
+ interval_sec: float, interval time between calls of the condition function
+ in seconds.
+
+ Returns:
+ True if the function returns the expected value else False.
+ """
+ start_time = time.time()
+ end_time = start_time + timeout_sec
+ while time.time() < end_time:
+ if condition_func(*func_args) == expected_value:
+ return True
+ time.sleep(interval_sec)
+ args_string = ', '.join(list(map(str, func_args)))
+ log.warning('Timed out after %.1fs waiting for "%s(%s)" to be "%s".',
+ timeout_sec, condition_func.__name__, args_string, expected_value)
+ if exception:
+ raise exception
+ return False
+
+
+def write_read_verify_data_sl4a(client_ad, server_ad, msg, binary=False):
+ """Verify that the client wrote data to the server Android device correctly.
+
+ Args:
+ client_ad: the Android device to perform the write.
+ server_ad: the Android device to read the data written.
+ msg: the message to write.
+ binary: if the msg arg is binary or not.
+
+ Returns:
+ True if the data written matches the data read, false if not.
+ """
+ client_ad.log.info('Write message %s.', msg)
+ if binary:
+ client_ad.sl4a.bluetoothSocketConnWriteBinary(msg)
+ else:
+ client_ad.sl4a.bluetoothSocketConnWrite(msg)
+ server_ad.log.info('Read message %s.', msg)
+ if binary:
+ read_msg = server_ad.sl4a.bluetoothSocketConnReadBinary().rstrip('\r\n')
+ else:
+ read_msg = server_ad.sl4a.bluetoothSocketConnRead()
+ log.info('Verify message.')
+ if msg != read_msg:
+ log.error('Mismatch! Read: %s, Expected: %s', read_msg, msg)
+ return False
+ log.info('Matched! Read: %s, Expected: %s', read_msg, msg)
+ return True
+
+
+def write_record_file(file_name, audio_params, frames):
+ """Writes the recorded audio into the file.
+
+ Args:
+ file_name: The file name for writing the recorded audio.
+ audio_params: A dict with audio configuration.
+ frames: Recorded audio frames.
+ """
+ log.debug('writing frame to %s', file_name)
+ wf = wave.open(file_name, 'wb')
+ wf.setnchannels(audio_params['channel'])
+ wf.setsampwidth(audio_params.get('sample_width', 1))
+ wf.setframerate(audio_params['sample_rate'])
+ wf.writeframes(frames)
+ wf.close()
diff --git a/blueberry/utils/command_line_runner/run_bluetooth_tests.py b/blueberry/utils/command_line_runner/run_bluetooth_tests.py
new file mode 100644
index 0000000..3a186b8
--- /dev/null
+++ b/blueberry/utils/command_line_runner/run_bluetooth_tests.py
@@ -0,0 +1,248 @@
+"""Command-line test runner script for running Bluetooth tests.
+
+This module allows users to initiate Bluetooth test targets and run them against
+specified DUTs (devices-under-test) using a simple command line interface.
+"""
+
+from __future__ import absolute_import
+from __future__ import division
+
+from __future__ import print_function
+
+import base64
+
+from absl import app
+from absl import flags
+from absl import logging
+
+# Internal import
+# Internal import
+# Internal import
+# Internal import
+# Internal import
+
+FLAGS = flags.FLAGS
+
+flags.DEFINE_multi_string('bt_test', None, 'Bluetooth test to run.')
+flags.DEFINE_multi_string('bt_dut', None,
+ 'Bluetooth device to allocate for tests.')
+
+
+# Valid config keys for the --bt_test command line flag.
+BT_TEST_CONFIG_KEYS = {'target'}
+
+# Valid config keys for the --bt_dut (device-under-test) command line flag.
+BT_DUT_CONFIG_KEYS = {'hardware'}
+
+TEST_FLAGS = ('--notest_loasd --test_output=streamed '
+ '--test_arg=--param_dut_config=%s')
+
+
+class Error(Exception):
+ """Base class for module exceptions."""
+ pass
+
+
+class TestConfigError(Error):
+ """Raised when --bt_test config flags are specified incorrectly."""
+ pass
+
+
+class DutConfigError(Error):
+ """Raised when --bt_dut config flags are specified incorrectly."""
+ pass
+
+
+def validate_bt_test_flags(flag_value):
+ """Validates the format of specified --bt_test flags.
+
+ Args:
+ flag_value: string, the config flag value for a given --bt_test flag.
+
+ Returns:
+ bool, True if --bt_test flags have been specified correctly.
+ """
+ if not flag_value:
+ logging.error('No tests specified! Please specify at least one '
+ 'test using the --bt_test flag.')
+ return False
+ for test in flag_value:
+ config_args = test.split(',')
+ for config_arg in config_args:
+ if config_arg.split('=')[0] not in BT_TEST_CONFIG_KEYS:
+ logging.error('--bt_test config key "%s" is invalid!',
+ config_arg.split('=')[0])
+ return False
+ return True
+
+
+def validate_bt_dut_flags(flag_value):
+ """Validates the format of specified --bt_dut flags.
+
+ Args:
+ flag_value: string, the config flag value for a given --bt_dut flag.
+
+ Returns:
+ bool, True if --bt_dut flags have been specified correctly.
+ """
+ if not flag_value:
+ logging.error('No DUTs specified! Please specify at least one '
+ 'DUT using the --bt_dut flag.')
+ return False
+ for dut in flag_value:
+ config_args = dut.split(',')
+ for config_arg in config_args:
+ if config_arg.split('=')[0] not in BT_DUT_CONFIG_KEYS:
+ logging.error('--bt_dut config key "%s" is invalid!',
+ config_arg.split('=')[0])
+ return False
+ return True
+
+flags.register_validator(
+ 'bt_test', validate_bt_test_flags,
+ ('Invalid --bt_test configuration specified!'
+ ' Valid configuration fields include: %s')
+ % BT_TEST_CONFIG_KEYS)
+
+
+flags.register_validator(
+ 'bt_dut', validate_bt_dut_flags,
+ ('Invalid --bt_dut configuration specified!'
+ ' Valid configuration fields include: %s')
+ % BT_DUT_CONFIG_KEYS)
+
+
+def parse_flag_value(flag_value):
+ """Parses a config flag value string into a dict.
+
+ Example input: 'target=//tests:bluetooth_pairing_test'
+ Example output: {'target': '//tests:bluetooth_pairing_test'}
+
+ Args:
+ flag_value: string, the config flag value for a given flag.
+
+ Returns:
+ dict, A dict object representation of a config flag value.
+ """
+ config_dict = {}
+ config_args = flag_value.split(',')
+ for config_arg in config_args:
+ config_dict[config_arg.split('=')[0]] = config_arg.split('=')[1]
+ return config_dict
+
+
+def get_device_type(gateway_stub, dut_config_dict):
+ """Determines a device type based on a device query.
+
+ Args:
+ gateway_stub: An RPC2 stub object.
+ dut_config_dict: dict, A dict of device config args.
+
+ Returns:
+ string, The MobileHarness device type.
+
+ Raises:
+ DutConfigError: If --bt_dut flag(s) are incorrectly specified.
+ """
+ device_query_filter = device_query_pb2.DeviceQueryFilter()
+ device_query_filter.type_regex.append('AndroidRealDevice')
+ for dut_config_key in dut_config_dict:
+ dimension_filter = device_query_filter.dimension_filter.add()
+ dimension_filter.name = dut_config_key
+ dimension_filter.value_regex = dut_config_dict[dut_config_key]
+ request = gateway_service_pb2.QueryDeviceRequest(
+ device_query_filter=device_query_filter)
+ response = gateway_stub.QueryDevice(request)
+ if response.device_query_result.device_info:
+ return 'AndroidRealDevice'
+
+ device_query_filter.ClearField('type_regex')
+ device_query_filter.type_regex.append('TestbedDevice')
+ request = gateway_service_pb2.QueryDeviceRequest(
+ device_query_filter=device_query_filter)
+ response = gateway_stub.QueryDevice(request)
+ if response.device_query_result.device_info:
+ return 'TestbedDevice'
+
+ raise DutConfigError('Invalid --bt_dut config specified: %s' %
+ dut_config_dict)
+
+
+def generate_dut_configs(gateway_stub):
+ """Generates a unicode string specifying the desired DUT configurations.
+
+ Args:
+ gateway_stub: An RPC2 stub object.
+
+ Returns:
+ string, Unicode string specifying DUT configurations.
+
+ Raises:
+ DutConfigError: If --bt_dut flag(s) are incorrectly specified.
+ """
+ dut_list = job_config_pb2.JobConfig().DeviceList()
+ dut_config_dict_list = [parse_flag_value(value) for value in FLAGS.bt_dut]
+
+ for dut_config_dict in dut_config_dict_list:
+ dut_config_dict['pool'] = 'bluetooth-iop'
+ dut = job_config_pb2.JobConfig().SubDeviceSpec()
+ if 'hardware' not in dut_config_dict:
+ raise DutConfigError('Must specify hardware name for bt_dut: %s' %
+ dut_config_dict)
+ dut.type = get_device_type(gateway_stub, dut_config_dict)
+ for config_key in dut_config_dict:
+ dut.dimensions.content[config_key] = dut_config_dict[config_key]
+ dut_list.sub_device_spec.append(dut)
+ logging.info(base64.b64encode(dut_list.SerializeToString()).decode('utf-8'))
+ return base64.b64encode(dut_list.SerializeToString()).decode('utf-8')
+
+
+def generate_blaze_targets(session_config, gateway_stub):
+ """Generates and appends blaze test targets to a MobileHarness session.
+
+ Args:
+ session_config: The SessionConfig object to append blaze test targets to.
+ gateway_stub: An RPC2 stub object.
+
+ Raises:
+ TestConfigError: If --bt_test flag(s) are incorrectly specified.
+ """
+ test_config_dict_list = [parse_flag_value(value) for value in FLAGS.bt_test]
+
+ for test_config_dict in test_config_dict_list:
+ target = setting_pb2.BlazeTarget()
+ if 'target' not in test_config_dict:
+ raise TestConfigError('Must specify a target for bt_test: %s' %
+ test_config_dict)
+ target.target_name = test_config_dict['target']
+ target.test_flags = TEST_FLAGS % generate_dut_configs(gateway_stub)
+ session_config.blaze_target.append(target)
+
+
+def run_session():
+ """Runs a configured test session.
+
+ Returns:
+ A RunSessionResponse object.
+ """
+ session_config = setting_pb2.SessionConfig()
+ channel = rpcutil.GetNewChannel('blade:mobileharness-gateway')
+ gateway_stub = gateway_service_pb2.GatewayService.NewRPC2Stub(channel=channel)
+ generate_blaze_targets(session_config, gateway_stub)
+ request = gateway_service_pb2.RunSessionRequest()
+ request.session_config.CopyFrom(session_config)
+ response = gateway_stub.RunSession(request)
+ logging.info('Sponge link: %s', response.sponge)
+ logging.info('Session ID: %s', response.session_id)
+ return response
+
+
+def main(argv):
+ logging.use_python_logging()
+ del argv
+ run_session()
+
+if __name__ == '__main__':
+ flags.mark_flag_as_required('bt_test')
+ flags.mark_flag_as_required('bt_dut')
+ app.run(main)
diff --git a/blueberry/utils/metrics_utils.py b/blueberry/utils/metrics_utils.py
new file mode 100644
index 0000000..b62b9e9
--- /dev/null
+++ b/blueberry/utils/metrics_utils.py
@@ -0,0 +1,111 @@
+"""Metrics reporting module for Blueberry using protobuf.
+
+Internal reference
+"""
+
+from __future__ import absolute_import
+from __future__ import division
+
+from __future__ import print_function
+
+import base64
+import logging
+import time
+
+# Internal import
+
+
+class BluetoothMetricLogger(object):
+ """A class used for gathering metrics from tests and devices.
+
+ This class provides methods to allow test writers to easily export metrics
+ from their tests as protobuf messages.
+
+ Attributes:
+ _metrics: The Bluetooth test proto message to add metrics to.
+ """
+
+ def __init__(self, bluetooth_test_proto_message):
+ self._metrics = bluetooth_test_proto_message
+ self._start_time = int(time.time())
+
+ def add_primary_device_metrics(self, device):
+ """Adds primary device metrics to the test proto message.
+
+ Args:
+ device: The Bluetooth device object to gather device metrics from.
+ """
+ device_message = self._metrics.configuration_data.primary_device
+ message_fields = device_message.DESCRIPTOR.fields_by_name.keys()
+ try:
+ device_metrics_dict = device.get_device_info()
+ except AttributeError:
+ logging.info(
+ 'Must implement get_device_info method for this controller in order to upload device metrics.'
+ )
+ return
+
+ for metric in device_metrics_dict:
+ if metric in message_fields:
+ setattr(device_message, metric, device_metrics_dict[metric])
+ else:
+ logging.info('%s is not a valid metric field.', metric)
+
+ def add_connected_device_metrics(self, device):
+ """Adds connected device metrics to the test proto message.
+
+ Args:
+ device: The Bluetooth device object to gather device metrics from.
+ """
+ device_message = self._metrics.configuration_data.connected_device
+ message_fields = device_message.DESCRIPTOR.fields_by_name.keys()
+ try:
+ device_metrics_dict = device.get_device_info()
+ except AttributeError:
+ logging.info(
+ 'Must implement get_device_info method for this controller in order to upload device metrics.'
+ )
+ return
+
+ for metric in device_metrics_dict:
+ if metric in message_fields:
+ setattr(device_message, metric, device_metrics_dict[metric])
+ else:
+ logging.warning('%s is not a valid metric field.', metric)
+
+ def add_test_metrics(self, test_metrics_dict):
+ """Adds test metrics to the test proto message.
+
+ Args:
+ test_metrics_dict: A dictionary of metrics to add to the test proto
+ message. Metric will only be added if the key exists as a field in the
+ test proto message.
+ """
+ if hasattr(self._metrics, 'configuration_data'):
+ self._metrics.configuration_data.test_date_time = self._start_time
+ message_fields = self._metrics.DESCRIPTOR.fields_by_name.keys()
+ for metric in test_metrics_dict:
+ if metric in message_fields:
+ metric_value = test_metrics_dict[metric]
+ if isinstance(metric_value, (list, tuple)):
+ getattr(self._metrics, metric).extend(metric_value)
+ else:
+ setattr(self._metrics, metric, metric_value)
+ else:
+ logging.warning('%s is not a valid metric field.', metric)
+
+ def proto_message_to_base64(self):
+ """Converts a proto message to a base64 string.
+
+ Returns:
+ string, Message formatted as a base64 string.
+ """
+ return base64.b64encode(self._metrics.SerializeToString()).decode('utf-8')
+
+ def proto_message_to_ascii(self):
+ """Converts a proto message to an ASCII string.
+
+ Returns:
+ string, Message formatted as an ASCII string. Useful for debugging.
+ """
+ return text_format.MessageToString(self._metrics)
diff --git a/bta/Android.bp b/bta/Android.bp
index c7a17d6..a70ceff 100644
--- a/bta/Android.bp
+++ b/bta/Android.bp
@@ -40,7 +40,6 @@
}
// BTA static library for target
-// ========================================================
cc_library_static {
name: "libbt-bta",
defaults: ["fluoride_bta_defaults"],
@@ -123,7 +122,6 @@
}
// bta unit tests for target
-// ========================================================
cc_test {
name: "net_test_bta",
defaults: ["fluoride_bta_defaults"],
@@ -160,8 +158,20 @@
host_supported: true,
include_dirs: [
"system/bt",
+ "system/bt/gd",
+ ],
+ generated_headers: [
+ "BluetoothGeneratedBundlerSchema_h_bfbs",
+ "BluetoothGeneratedDumpsysDataSchema_h",
+ "BluetoothGeneratedPackets_h",
],
srcs: [
+ ":TestCommonMainHandler",
+ ":TestMockBtif",
+ ":TestMockDevice",
+ ":TestMockMainShim",
+ ":TestMockStack",
+ ":TestStubOsi",
"dm/bta_dm_act.cc",
"dm/bta_dm_cfg.cc",
"dm/bta_dm_ci.cc",
@@ -176,6 +186,7 @@
"gatt/database.cc",
"gatt/database_builder.cc",
"hh/bta_hh_act.cc",
+ "hh/bta_hh_api.cc",
"hh/bta_hh_cfg.cc",
"hh/bta_hh_le.cc",
"hh/bta_hh_main.cc",
@@ -183,39 +194,11 @@
"sys/bta_sys_conn.cc",
"sys/bta_sys_main.cc",
"test/bta_dm_test.cc",
- "test/common/fake_osi.cc",
- "test/common/mock_btif_co_bta_dm_co.cc",
- "test/common/mock_btif_co_bta_hh_co.cc",
- "test/common/mock_btif_debug_conn.cc",
- "test/common/mock_btif_dm.cc",
- "test/common/mock_btif_stack_manager.cc",
- "test/common/mock_btif_storage.cc",
- "test/common/mock_device_controller.cc",
- "test/common/mock_device_interop.cc",
- "test/common/mock_main_shim_acl.cc",
- "test/common/mock_main_shim_btm_api.cc",
- "test/common/mock_shim.cc",
- "test/common/mock_stack_acl.cc",
- "test/common/mock_stack_btm.cc",
- "test/common/mock_stack_btm_ble.cc",
- "test/common/mock_stack_btm_dev.cc",
- "test/common/mock_stack_btm_pm.cc",
- "test/common/mock_stack_btm_sco.cc",
- "test/common/mock_stack_btm_sec.cc",
- "test/common/mock_stack_crypto_toolbox_aes_cmac.cc",
- "test/common/mock_stack_gap_ble.cc",
- "test/common/mock_stack_btm_main.cc",
- "test/common/mock_stack_gatt.cc",
- "test/common/mock_stack_gatt_attr.cc",
- "test/common/mock_stack_gatt_connection_manager.cc",
- "test/common/mock_stack_hidh.cc",
- "test/common/mock_stack_l2cap.cc",
- "test/common/mock_stack_l2cap_ble.cc",
- "test/common/mock_stack_sdp.cc",
- "test/common/mock_stack_srvc_dis.cc",
+ "test/bta_gatt_test.cc",
],
shared_libs: [
"libcrypto",
+ "libflatbuffers-cpp",
"liblog",
"libprotobuf-cpp-lite",
],
@@ -229,7 +212,6 @@
}
// bta hf client add record tests for target
-// ========================================================
cc_test {
name: "net_test_hf_client_add_record",
defaults: ["fluoride_defaults"],
@@ -260,7 +242,6 @@
// bta unit tests for host
-// ========================================================
cc_test {
name: "bluetooth_vc_test",
test_suites: ["device-tests"],
diff --git a/bta/BUILD.gn b/bta/BUILD.gn
index b8b32ea..64bd53c 100644
--- a/bta/BUILD.gn
+++ b/bta/BUILD.gn
@@ -83,6 +83,8 @@
"sys/bta_sys_conn.cc",
"sys/bta_sys_main.cc",
"sys/utl.cc",
+ "vc/device.cc",
+ "vc/vc.cc",
]
include_dirs = [
diff --git a/bta/ag/bta_ag_int.h b/bta/ag/bta_ag_int.h
index ef20008..6640808 100644
--- a/bta/ag/bta_ag_int.h
+++ b/bta/ag/bta_ag_int.h
@@ -296,7 +296,7 @@
/*****************************************************************************
* Function prototypes
****************************************************************************/
-bool bta_ag_hdl_event(BT_HDR* p_msg);
+bool bta_ag_hdl_event(BT_HDR_RIGID* p_msg);
/* API functions */
extern void bta_ag_api_enable(tBTA_AG_CBACK* p_cback);
diff --git a/bta/ag/bta_ag_main.cc b/bta/ag/bta_ag_main.cc
index b87cbfd..583102f 100644
--- a/bta/ag/bta_ag_main.cc
+++ b/bta/ag/bta_ag_main.cc
@@ -760,7 +760,7 @@
* @param p_msg event message
* @return True to free p_msg, or False if p_msg is freed within this function
*/
-bool bta_ag_hdl_event(BT_HDR* p_msg) {
+bool bta_ag_hdl_event(BT_HDR_RIGID* p_msg) {
switch (p_msg->event) {
case BTA_AG_RING_TIMEOUT_EVT:
case BTA_AG_SVC_TIMEOUT_EVT:
diff --git a/bta/ag/bta_ag_sdp.cc b/bta/ag/bta_ag_sdp.cc
index d6beb6a..ad2a02a 100644
--- a/bta/ag/bta_ag_sdp.cc
+++ b/bta/ag/bta_ag_sdp.cc
@@ -50,12 +50,12 @@
#endif
/* declare sdp callback functions */
-void bta_ag_sdp_cback_1(uint16_t status);
-void bta_ag_sdp_cback_2(uint16_t status);
-void bta_ag_sdp_cback_3(uint16_t status);
-void bta_ag_sdp_cback_4(uint16_t status);
-void bta_ag_sdp_cback_5(uint16_t status);
-void bta_ag_sdp_cback_6(uint16_t status);
+void bta_ag_sdp_cback_1(tSDP_RESULT);
+void bta_ag_sdp_cback_2(tSDP_RESULT);
+void bta_ag_sdp_cback_3(tSDP_RESULT);
+void bta_ag_sdp_cback_4(tSDP_RESULT);
+void bta_ag_sdp_cback_5(tSDP_RESULT);
+void bta_ag_sdp_cback_6(tSDP_RESULT);
/* SDP callback function table */
typedef tSDP_DISC_CMPL_CB* tBTA_AG_SDP_CBACK;
@@ -102,12 +102,12 @@
* Returns void
*
******************************************************************************/
-void bta_ag_sdp_cback_1(uint16_t status) { bta_ag_sdp_cback(status, 1); }
-void bta_ag_sdp_cback_2(uint16_t status) { bta_ag_sdp_cback(status, 2); }
-void bta_ag_sdp_cback_3(uint16_t status) { bta_ag_sdp_cback(status, 3); }
-void bta_ag_sdp_cback_4(uint16_t status) { bta_ag_sdp_cback(status, 4); }
-void bta_ag_sdp_cback_5(uint16_t status) { bta_ag_sdp_cback(status, 5); }
-void bta_ag_sdp_cback_6(uint16_t status) { bta_ag_sdp_cback(status, 6); }
+void bta_ag_sdp_cback_1(tSDP_STATUS status) { bta_ag_sdp_cback(status, 1); }
+void bta_ag_sdp_cback_2(tSDP_STATUS status) { bta_ag_sdp_cback(status, 2); }
+void bta_ag_sdp_cback_3(tSDP_STATUS status) { bta_ag_sdp_cback(status, 3); }
+void bta_ag_sdp_cback_4(tSDP_STATUS status) { bta_ag_sdp_cback(status, 4); }
+void bta_ag_sdp_cback_5(tSDP_STATUS status) { bta_ag_sdp_cback(status, 5); }
+void bta_ag_sdp_cback_6(tSDP_STATUS status) { bta_ag_sdp_cback(status, 6); }
/******************************************************************************
*
diff --git a/bta/av/bta_av_aact.cc b/bta/av/bta_av_aact.cc
index c6ce6a8..e93c076 100644
--- a/bta/av/bta_av_aact.cc
+++ b/bta/av/bta_av_aact.cc
@@ -82,8 +82,6 @@
/* ACL quota we are letting FW use for A2DP Offload Tx. */
#define BTA_AV_A2DP_OFFLOAD_XMIT_QUOTA 4
-#define BTIF_A2DP_MAX_BITPOOL_MQ 35
-
static void bta_av_offload_codec_builder(tBTA_AV_SCB* p_scb,
tBT_A2DP_OFFLOAD* p_a2dp_offload);
@@ -134,7 +132,7 @@
BTA_AV_AVDT_RPT_CONN_EVT, /* AVDT_REPORT_CONN_EVT */
BTA_AV_AVDT_RPT_CONN_EVT, /* AVDT_REPORT_DISCONN_EVT */
BTA_AV_AVDT_DELAY_RPT_EVT, /* AVDT_DELAY_REPORT_EVT */
- 0 /* AVDT_DELAY_REPORT_CFM_EVT */
+ BTA_AV_AVDT_DELAY_RPT_CFM_EVT, /* AVDT_DELAY_REPORT_CFM_EVT */
};
static const uint16_t bta_av_stream_evt_fail[] = {
@@ -159,7 +157,7 @@
BTA_AV_AVDT_RPT_CONN_EVT, /* AVDT_REPORT_CONN_EVT */
BTA_AV_AVDT_RPT_CONN_EVT, /* AVDT_REPORT_DISCONN_EVT */
BTA_AV_AVDT_DELAY_RPT_EVT, /* AVDT_DELAY_REPORT_EVT */
- 0 /* AVDT_DELAY_REPORT_CFM_EVT */
+ BTA_AV_AVDT_DELAY_RPT_CFM_EVT, /* AVDT_DELAY_REPORT_CFM_EVT */
};
/***********************************************
@@ -860,6 +858,8 @@
p_scb->num_disc_snks = 0;
p_scb->coll_mask = 0;
alarm_cancel(p_scb->avrc_ct_timer);
+ alarm_cancel(p_scb->link_signalling_timer);
+ alarm_cancel(p_scb->accept_signalling_timer);
/* TODO(eisenbach): RE-IMPLEMENT USING VSC OR HAL EXTENSION
vendor_get_interface()->send_command(
@@ -935,7 +935,7 @@
/* Clear collision mask */
p_scb->coll_mask = 0;
- alarm_cancel(bta_av_cb.accept_signalling_timer);
+ alarm_cancel(p_scb->accept_signalling_timer);
/* if no codec parameters in configuration, fail */
if ((p_evt_cfg->num_codec == 0) ||
@@ -1001,7 +1001,8 @@
APPL_TRACE_API("%s: conn_lcb: 0x%x peer_addr: %s", __func__,
bta_av_cb.conn_lcb, p_scb->PeerAddress().ToString().c_str());
- alarm_cancel(bta_av_cb.link_signalling_timer);
+ alarm_cancel(p_scb->link_signalling_timer);
+ alarm_cancel(p_scb->accept_signalling_timer);
alarm_cancel(p_scb->avrc_ct_timer);
// conn_lcb is the index bitmask of all used LCBs, and since LCB and SCB use
@@ -1091,7 +1092,7 @@
AVDT_ConfigRsp(p_scb->avdt_handle, p_scb->avdt_label,
p_data->ci_setconfig.err_code, p_data->ci_setconfig.category);
- alarm_cancel(bta_av_cb.link_signalling_timer);
+ alarm_cancel(p_scb->link_signalling_timer);
if (p_data->ci_setconfig.err_code == AVDT_SUCCESS) {
p_scb->wait = BTA_AV_WAIT_ACP_CAPS_ON;
@@ -1316,7 +1317,7 @@
if (p_scb->co_started) {
bta_av_str_stopped(p_scb, NULL);
}
- alarm_cancel(bta_av_cb.link_signalling_timer);
+ alarm_cancel(p_scb->link_signalling_timer);
/* close stream */
p_scb->started = false;
@@ -2183,7 +2184,7 @@
bool initiator = false;
bool suspend = false;
uint8_t new_role = p_scb->role;
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
tHCI_ROLE cur_role;
uint8_t local_tsep = p_scb->seps[p_scb->sep_idx].tsep;
@@ -3156,7 +3157,7 @@
case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
codec_type = BTA_AV_CODEC_TYPE_SBC;
if (A2DP_GetMaxBitpoolSbc(p_scb->cfg.codec_info) <=
- BTIF_A2DP_MAX_BITPOOL_MQ) {
+ A2DP_SBC_BITPOOL_MIDDLE_QUALITY) {
APPL_TRACE_WARNING("%s: Restricting streaming MTU size for MQ Bitpool",
__func__);
mtu = MAX_2MBPS_AVDTP_MTU;
diff --git a/bta/av/bta_av_act.cc b/bta/av/bta_av_act.cc
index bcd1aa3..dcbb18a 100644
--- a/bta/av/bta_av_act.cc
+++ b/bta/av/bta_av_act.cc
@@ -183,7 +183,7 @@
*
******************************************************************************/
static void bta_av_avrc_sdp_cback(UNUSED_ATTR uint16_t status) {
- BT_HDR* p_msg = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ BT_HDR_RIGID* p_msg = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
p_msg->event = BTA_AV_SDP_AVRC_DISC_EVT;
@@ -1291,7 +1291,7 @@
*
******************************************************************************/
void bta_av_disable(tBTA_AV_CB* p_cb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
bool disabling_in_progress = false;
uint16_t xx;
@@ -1305,6 +1305,12 @@
* expect BTA_AV_DEREG_COMP_EVT when deregister is complete */
for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) {
if (p_cb->p_scb[xx] != NULL) {
+ // Free signalling timers
+ alarm_free(p_cb->p_scb[xx]->link_signalling_timer);
+ p_cb->p_scb[xx]->link_signalling_timer = NULL;
+ alarm_free(p_cb->p_scb[xx]->accept_signalling_timer);
+ p_cb->p_scb[xx]->accept_signalling_timer = NULL;
+
hdr.layer_specific = xx + 1;
bta_av_api_deregister((tBTA_AV_DATA*)&hdr);
disabling_in_progress = true;
@@ -1315,10 +1321,6 @@
// no needed to setup this disabling flag.
p_cb->disabling = disabling_in_progress;
- alarm_free(p_cb->link_signalling_timer);
- p_cb->link_signalling_timer = NULL;
- alarm_free(p_cb->accept_signalling_timer);
- p_cb->accept_signalling_timer = NULL;
}
/*******************************************************************************
@@ -1331,8 +1333,10 @@
*
******************************************************************************/
void bta_av_api_disconnect(tBTA_AV_DATA* p_data) {
- AVDT_DisconnectReq(p_data->api_discnt.bd_addr, bta_av_conn_cback);
- alarm_cancel(bta_av_cb.link_signalling_timer);
+ tBTA_AV_SCB* p_scb =
+ bta_av_hndl_to_scb(p_data->api_discnt.hdr.layer_specific);
+ AVDT_DisconnectReq(p_scb->PeerAddress(), bta_av_conn_cback);
+ alarm_cancel(p_scb->link_signalling_timer);
}
/**
@@ -1450,21 +1454,30 @@
* The following function shall send the event and start the
* recurring timer
*/
- bta_av_signalling_timer(NULL);
+ if (!p_scb->link_signalling_timer) {
+ p_scb->link_signalling_timer = alarm_new("link_signalling_timer");
+ }
+ BT_HDR hdr;
+ hdr.layer_specific = p_scb->hndl;
+ bta_av_signalling_timer((tBTA_AV_DATA*)&hdr);
APPL_TRACE_DEBUG("%s: Re-start timer for AVDTP service", __func__);
bta_sys_conn_open(BTA_ID_AV, p_scb->app_id, p_scb->PeerAddress());
/* Possible collision : need to avoid outgoing processing while the
* timer is running */
p_scb->coll_mask = BTA_AV_COLL_INC_TMR;
+ if (!p_scb->accept_signalling_timer) {
+ p_scb->accept_signalling_timer = alarm_new("accept_signalling_timer");
+ }
alarm_set_on_mloop(
- p_cb->accept_signalling_timer, BTA_AV_ACCEPT_SIGNALLING_TIMEOUT_MS,
+ p_scb->accept_signalling_timer, BTA_AV_ACCEPT_SIGNALLING_TIMEOUT_MS,
bta_av_accept_signalling_timer_cback, UINT_TO_PTR(xx));
}
}
}
else if (event == BTA_AR_AVDT_CONN_EVT) {
- alarm_cancel(bta_av_cb.link_signalling_timer);
+ uint8_t scb_index = p_data->str_msg.scb_index;
+ alarm_cancel(p_cb->p_scb[scb_index]->link_signalling_timer);
}
else {
/* disconnected. */
@@ -1511,6 +1524,9 @@
*
******************************************************************************/
void bta_av_signalling_timer(UNUSED_ATTR tBTA_AV_DATA* p_data) {
+ tBTA_AV_HNDL hndl = p_data->hdr.layer_specific;
+ tBTA_AV_SCB* p_scb = bta_av_hndl_to_scb(hndl);
+
tBTA_AV_CB* p_cb = &bta_av_cb;
int xx;
uint8_t mask;
@@ -1527,9 +1543,10 @@
if (mask & p_cb->conn_lcb) {
/* this entry is used. check if it is connected */
if (!p_lcb->conn_msk) {
- bta_sys_start_timer(p_cb->link_signalling_timer,
+ APPL_TRACE_DEBUG("%s hndl 0x%x", __func__, p_scb->hndl);
+ bta_sys_start_timer(p_scb->link_signalling_timer,
BTA_AV_SIGNALLING_TIMEOUT_MS,
- BTA_AV_SIGNALLING_TIMER_EVT, 0);
+ BTA_AV_SIGNALLING_TIMER_EVT, hndl);
tBTA_AV_PEND pend;
pend.bd_addr = p_lcb->addr;
tBTA_AV bta_av_data;
@@ -1574,7 +1591,7 @@
/* We are still doing SDP. Run the timer again. */
p_scb->coll_mask |= BTA_AV_COLL_INC_TMR;
- alarm_set_on_mloop(p_cb->accept_signalling_timer,
+ alarm_set_on_mloop(p_scb->accept_signalling_timer,
BTA_AV_ACCEPT_SIGNALLING_TIMEOUT_MS,
bta_av_accept_signalling_timer_cback,
UINT_TO_PTR(inx));
diff --git a/bta/av/bta_av_api.cc b/bta/av/bta_av_api.cc
index cf3bb50..23362e4 100644
--- a/bta/av/bta_av_api.cc
+++ b/bta/av/bta_av_api.cc
@@ -76,7 +76,7 @@
*
******************************************************************************/
void BTA_AvDisable(void) {
- BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
bta_sys_deregister(BTA_ID_AV);
p_buf->event = BTA_AV_API_DISABLE_EVT;
@@ -126,7 +126,7 @@
*
******************************************************************************/
void BTA_AvDeregister(tBTA_AV_HNDL hndl) {
- BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
p_buf->layer_specific = hndl;
p_buf->event = BTA_AV_API_DEREGISTER_EVT;
@@ -176,7 +176,7 @@
void BTA_AvClose(tBTA_AV_HNDL handle) {
LOG_INFO("%s: bta_handle:0x%x", __func__, handle);
- BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
p_buf->event = BTA_AV_API_CLOSE_EVT;
p_buf->layer_specific = handle;
@@ -193,14 +193,14 @@
* Returns void
*
******************************************************************************/
-void BTA_AvDisconnect(const RawAddress& bd_addr) {
- LOG_INFO("%s: peer %s", __func__, bd_addr.ToString().c_str());
+void BTA_AvDisconnect(tBTA_AV_HNDL handle) {
+ LOG_INFO("%s: bta_handle=0x%x", __func__, handle);
tBTA_AV_API_DISCNT* p_buf =
(tBTA_AV_API_DISCNT*)osi_malloc(sizeof(tBTA_AV_API_DISCNT));
p_buf->hdr.event = BTA_AV_API_DISCONNECT_EVT;
- p_buf->bd_addr = bd_addr;
+ p_buf->hdr.layer_specific = handle;
bta_sys_sendmsg(p_buf);
}
@@ -217,7 +217,7 @@
void BTA_AvStart(tBTA_AV_HNDL handle) {
LOG_INFO("Starting audio/video stream data transfer bta_handle:%hhu", handle);
- BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
p_buf->event = BTA_AV_API_START_EVT;
p_buf->layer_specific = handle;
@@ -237,7 +237,7 @@
void BTA_AvOffloadStart(tBTA_AV_HNDL hndl) {
LOG_INFO("%s: bta_handle=0x%x", __func__, hndl);
- BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
p_buf->event = BTA_AV_API_OFFLOAD_START_EVT;
p_buf->layer_specific = hndl;
diff --git a/bta/av/bta_av_ci.cc b/bta/av/bta_av_ci.cc
index 8a19924..b191e82 100644
--- a/bta/av/bta_av_ci.cc
+++ b/bta/av/bta_av_ci.cc
@@ -41,7 +41,7 @@
*
******************************************************************************/
void bta_av_ci_src_data_ready(tBTA_AV_CHNL chnl) {
- BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
p_buf->layer_specific = chnl;
p_buf->event = BTA_AV_CI_SRC_DATA_READY_EVT;
diff --git a/bta/av/bta_av_int.h b/bta/av/bta_av_int.h
index a450b97..2f49a77 100644
--- a/bta/av/bta_av_int.h
+++ b/bta/av/bta_av_int.h
@@ -90,6 +90,7 @@
BTA_AV_AVDT_DISCONNECT_EVT,
BTA_AV_ROLE_CHANGE_EVT,
BTA_AV_AVDT_DELAY_RPT_EVT,
+ BTA_AV_AVDT_DELAY_RPT_CFM_EVT,
BTA_AV_ACP_CONNECT_EVT,
BTA_AV_API_OFFLOAD_START_EVT,
BTA_AV_API_OFFLOAD_START_RSP_EVT,
@@ -219,14 +220,14 @@
/* data type for BTA_AV_API_ENABLE_EVT */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
tBTA_AV_CBACK* p_cback;
tBTA_AV_FEAT features;
} tBTA_AV_API_ENABLE;
/* data type for BTA_AV_API_REGISTER_EVT */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
char p_service_name[BTA_SERVICE_NAME_LEN + 1];
uint8_t app_id;
tBTA_AV_SINK_DATA_CBACK* p_app_sink_data_cback;
@@ -254,7 +255,7 @@
/* data type for BTA_AV_API_OPEN_EVT */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
RawAddress bd_addr;
bool use_rc;
tBTA_AV_RS_RES switch_res;
@@ -263,7 +264,7 @@
/* data type for BTA_AV_API_STOP_EVT */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
bool suspend;
bool flush;
bool reconfig_stop; // True if the stream is stopped for reconfiguration
@@ -271,20 +272,19 @@
/* data type for BTA_AV_API_DISCONNECT_EVT */
typedef struct {
- BT_HDR hdr;
- RawAddress bd_addr;
+ BT_HDR_RIGID hdr;
} tBTA_AV_API_DISCNT;
/* data type for BTA_AV_API_PROTECT_REQ_EVT */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
uint8_t* p_data;
uint16_t len;
} tBTA_AV_API_PROTECT_REQ;
/* data type for BTA_AV_API_PROTECT_RSP_EVT */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
uint8_t* p_data;
uint16_t len;
uint8_t error_code;
@@ -292,27 +292,31 @@
/* data type for BTA_AV_API_REMOTE_CMD_EVT */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
tAVRC_MSG_PASS msg;
uint8_t label;
} tBTA_AV_API_REMOTE_CMD;
/* data type for BTA_AV_API_VENDOR_CMD_EVT and RSP */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
tAVRC_MSG_VENDOR msg;
uint8_t label;
} tBTA_AV_API_VENDOR;
/* data type for BTA_AV_API_RC_OPEN_EVT */
-typedef struct { BT_HDR hdr; } tBTA_AV_API_OPEN_RC;
+typedef struct {
+ BT_HDR_RIGID hdr;
+} tBTA_AV_API_OPEN_RC;
/* data type for BTA_AV_API_RC_CLOSE_EVT */
-typedef struct { BT_HDR hdr; } tBTA_AV_API_CLOSE_RC;
+typedef struct {
+ BT_HDR_RIGID hdr;
+} tBTA_AV_API_CLOSE_RC;
/* data type for BTA_AV_API_META_RSP_EVT */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
bool is_rsp;
uint8_t label;
tBTA_AV_CODE rsp_code;
@@ -321,7 +325,7 @@
/* data type for BTA_AV_API_RECONFIG_EVT */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
uint8_t codec_info[AVDT_CODEC_SIZE]; /* codec configuration */
uint8_t* p_protect_info;
uint8_t num_protect;
@@ -331,7 +335,7 @@
/* data type for BTA_AV_CI_SETCONFIG_OK_EVT and BTA_AV_CI_SETCONFIG_FAIL_EVT */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
tBTA_AV_HNDL hndl;
uint8_t err_code;
uint8_t category;
@@ -343,7 +347,7 @@
/* data type for all stream events from AVDTP */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
AvdtpSepConfig cfg; /* configuration/capabilities parameters */
tAVDT_CTRL msg; /* AVDTP callback message parameters */
RawAddress bd_addr; /* bd address */
@@ -355,7 +359,7 @@
/* data type for BTA_AV_AVRC_MSG_EVT */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
tAVRC_MSG msg;
uint8_t handle;
uint8_t label;
@@ -364,33 +368,33 @@
/* data type for BTA_AV_AVRC_OPEN_EVT, BTA_AV_AVRC_CLOSE_EVT */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
RawAddress peer_addr;
uint8_t handle;
} tBTA_AV_RC_CONN_CHG;
/* data type for BTA_AV_CONN_CHG_EVT */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
RawAddress peer_addr;
bool is_up;
} tBTA_AV_CONN_CHG;
/* data type for BTA_AV_ROLE_CHANGE_EVT */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
uint8_t new_role;
uint8_t hci_status;
} tBTA_AV_ROLE_RES;
/* data type for BTA_AV_SDP_DISC_OK_EVT */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
} tBTA_AV_SDP_RES;
/* data type for BTA_AV_API_OFFLOAD_RSP_EVT */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
tBTA_AV_STATUS status;
} tBTA_AV_API_STATUS_RSP;
@@ -419,7 +423,7 @@
/* union of all event datatypes */
union tBTA_AV_DATA {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
tBTA_AV_API_ENABLE api_enable;
tBTA_AV_API_REG api_reg;
tBTA_AV_API_OPEN api_open;
@@ -487,6 +491,9 @@
tAVDT_SEP_INFO sep_info[BTA_AV_NUM_SEPS]; /* stream discovery results */
AvdtpSepConfig cfg; /* local SEP configuration */
alarm_t* avrc_ct_timer; /* delay timer for AVRC CT */
+ alarm_t* link_signalling_timer;
+ alarm_t*
+ accept_signalling_timer; /* timer to monitor signalling when accepting */
uint16_t l2c_cid; /* L2CAP channel ID */
uint16_t stream_mtu; /* MTU of stream */
uint8_t media_type; /* Media type: AVDT_MEDIA_TYPE_* */
@@ -612,9 +619,6 @@
tBTA_AV_CBACK* p_cback; /* application callback function */
tBTA_AV_RCB rcb[BTA_AV_NUM_RCB]; /* RCB control block */
tBTA_AV_LCB lcb[BTA_AV_NUM_LINKS + 1]; /* link control block */
- alarm_t* link_signalling_timer;
- alarm_t*
- accept_signalling_timer; /* timer to monitor signalling when accepting */
uint32_t sdp_a2dp_handle; /* SDP record handle for audio src */
uint32_t sdp_a2dp_snk_handle; /* SDP record handle for audio snk */
tBTA_AV_FEAT features; /* features mask */
@@ -711,7 +715,7 @@
tBTA_AV_DATA* p_data);
extern void bta_av_ssm_execute(tBTA_AV_SCB* p_scb, uint16_t event,
tBTA_AV_DATA* p_data);
-extern bool bta_av_hdl_event(BT_HDR* p_msg);
+extern bool bta_av_hdl_event(BT_HDR_RIGID* p_msg);
extern const char* bta_av_evt_code(uint16_t evt_code);
extern bool bta_av_switch_if_needed(tBTA_AV_SCB* p_scb);
extern bool bta_av_link_role_ok(tBTA_AV_SCB* p_scb, uint8_t bits);
diff --git a/bta/av/bta_av_main.cc b/bta/av/bta_av_main.cc
index 0ef5a76..8871718 100644
--- a/bta/av/bta_av_main.cc
+++ b/bta/av/bta_av_main.cc
@@ -160,14 +160,6 @@
bta_av_cb.rc_acp_handle = BTA_AV_RC_HANDLE_NONE;
- /*
- * TODO: The "disable" event handling is missing - there we need
- * to alarm_free() the alarms below.
- */
- bta_av_cb.link_signalling_timer = alarm_new("bta_av.link_signalling_timer");
- bta_av_cb.accept_signalling_timer =
- alarm_new("bta_av.accept_signalling_timer");
-
/* store parameters */
bta_av_cb.p_cback = p_data->api_enable.p_cback;
bta_av_cb.features = p_data->api_enable.features;
@@ -1212,7 +1204,7 @@
* Returns bool
*
******************************************************************************/
-bool bta_av_hdl_event(BT_HDR* p_msg) {
+bool bta_av_hdl_event(BT_HDR_RIGID* p_msg) {
if (p_msg->event > BTA_AV_LAST_EVT) {
return true; /* to free p_msg */
}
@@ -1402,14 +1394,6 @@
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",
- alarm_is_scheduled(bta_av_cb.link_signalling_timer)
- ? "Scheduled"
- : "Not scheduled");
- dprintf(fd, " Accept signalling timer: %s\n",
- alarm_is_scheduled(bta_av_cb.accept_signalling_timer)
- ? "Scheduled"
- : "Not scheduled");
dprintf(fd, " SDP A2DP source handle: %d\n", bta_av_cb.sdp_a2dp_handle);
dprintf(fd, " SDP A2DP sink handle: %d\n", bta_av_cb.sdp_a2dp_snk_handle);
dprintf(fd, " Features: 0x%x\n", bta_av_cb.features);
@@ -1468,6 +1452,13 @@
p_scb->open_api.use_rc ? "true" : "false");
dprintf(fd, " Switch result: %d\n", p_scb->open_api.switch_res);
dprintf(fd, " Initiator UUID: 0x%x\n", p_scb->open_api.uuid);
+ dprintf(fd, " Link signalling timer: %s\n",
+ alarm_is_scheduled(p_scb->link_signalling_timer) ? "Scheduled"
+ : "Not scheduled");
+ dprintf(fd, " Accept signalling timer: %s\n",
+ alarm_is_scheduled(p_scb->accept_signalling_timer)
+ ? "Scheduled"
+ : "Not scheduled");
// TODO: Print p_scb->sep_info[], cfg, avrc_ct_timer, current_codec ?
dprintf(fd, " L2CAP Channel ID: %d\n", p_scb->l2c_cid);
dprintf(fd, " Stream MTU: %d\n", p_scb->stream_mtu);
diff --git a/bta/dm/bta_dm_act.cc b/bta/dm/bta_dm_act.cc
index b9d8e39..0b4c493 100644
--- a/bta/dm/bta_dm_act.cc
+++ b/bta/dm/bta_dm_act.cc
@@ -68,7 +68,7 @@
static void bta_dm_remname_cback(void* p);
static void bta_dm_find_services(const RawAddress& bd_addr);
static void bta_dm_discover_next_device(void);
-static void bta_dm_sdp_callback(uint16_t sdp_status);
+static void bta_dm_sdp_callback(tSDP_STATUS sdp_status);
static uint8_t bta_dm_pin_cback(const RawAddress& bd_addr, DEV_CLASS dev_class,
BD_NAME bd_name, bool min_16_digit);
static uint8_t bta_dm_new_link_key_cback(const RawAddress& bd_addr,
@@ -85,7 +85,7 @@
uint8_t app_id, const RawAddress& peer_addr);
/* Extended Inquiry Response */
-static uint8_t bta_dm_sp_cback(tBTM_SP_EVT event, tBTM_SP_EVT_DATA* p_data);
+static tBTM_STATUS bta_dm_sp_cback(tBTM_SP_EVT event, tBTM_SP_EVT_DATA* p_data);
static void bta_dm_set_eir(char* local_name);
@@ -113,7 +113,7 @@
static void bta_dm_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data);
extern tBTA_DM_CONTRL_STATE bta_dm_pm_obtain_controller_state(void);
#if (BLE_VND_INCLUDED == TRUE)
-static void bta_dm_ctrl_features_rd_cmpl_cback(tBTM_STATUS result);
+static void bta_dm_ctrl_features_rd_cmpl_cback(tHCI_STATUS result);
#endif
#ifndef BTA_DM_BLE_ADV_CHNL_MAP
@@ -1214,7 +1214,7 @@
// Piggy back the SCN over result field
if (scn_found) {
p_msg->disc_result.result.disc_res.result =
- (3 + bta_dm_search_cb.peer_scn);
+ static_cast<tBTA_STATUS>((3 + bta_dm_search_cb.peer_scn));
p_msg->disc_result.result.disc_res.services |= BTA_USER_SERVICE_MASK;
APPL_TRACE_EVENT(" Piggy back the SCN over result field SCN=%d",
@@ -1741,12 +1741,12 @@
* Returns void
*
******************************************************************************/
-static void bta_dm_sdp_callback(uint16_t sdp_status) {
+static void bta_dm_sdp_callback(tSDP_STATUS sdp_status) {
tBTA_DM_SDP_RESULT* p_msg =
(tBTA_DM_SDP_RESULT*)osi_malloc(sizeof(tBTA_DM_SDP_RESULT));
p_msg->hdr.event = BTA_DM_SDP_RESULT_EVT;
- p_msg->sdp_result = sdp_status;
+ p_msg->sdp_result = static_cast<uint16_t>(sdp_status);
bta_sys_sendmsg(p_msg);
}
@@ -2108,7 +2108,8 @@
* Returns void
*
******************************************************************************/
-static uint8_t bta_dm_sp_cback(tBTM_SP_EVT event, tBTM_SP_EVT_DATA* p_data) {
+static tBTM_STATUS bta_dm_sp_cback(tBTM_SP_EVT event,
+ tBTM_SP_EVT_DATA* p_data) {
tBTM_STATUS status = BTM_CMD_STARTED;
tBTA_DM_SEC sec_event;
tBTA_DM_SEC_EVT pin_evt = BTA_DM_SP_KEY_NOTIF_EVT;
@@ -2219,7 +2220,8 @@
case BTM_SP_LOC_OOB_EVT:
#ifdef BTIF_DM_OOB_TEST
- btif_dm_proc_loc_oob((bool)(p_data->loc_oob.status == BTM_SUCCESS),
+ btif_dm_proc_loc_oob(BT_TRANSPORT_BR_EDR,
+ (bool)(p_data->loc_oob.status == BTM_SUCCESS),
p_data->loc_oob.c, p_data->loc_oob.r);
#endif
break;
@@ -3674,8 +3676,8 @@
tBTM_BLE_RX_TIME_MS rx_time,
tBTM_BLE_IDLE_TIME_MS idle_time,
tBTM_BLE_ENERGY_USED energy_used,
- tBTM_STATUS status) {
- tBTA_STATUS st = (status == BTM_SUCCESS) ? BTA_SUCCESS : BTA_FAILURE;
+ tHCI_STATUS status) {
+ tBTA_STATUS st = (status == HCI_SUCCESS) ? BTA_SUCCESS : BTA_FAILURE;
tBTA_DM_CONTRL_STATE ctrl_state = 0;
if (BTA_SUCCESS == st) ctrl_state = bta_dm_pm_obtain_controller_state();
@@ -3690,8 +3692,8 @@
tBTA_BLE_ENERGY_INFO_CBACK* p_energy_info_cback) {
bta_dm_cb.p_energy_info_cback = p_energy_info_cback;
tBTM_STATUS btm_status = BTM_BleGetEnergyInfo(bta_ble_energy_info_cmpl);
- if (BTM_CMD_STARTED != btm_status)
- bta_ble_energy_info_cmpl(0, 0, 0, 0, btm_status);
+ if (btm_status != BTM_CMD_STARTED)
+ bta_ble_energy_info_cmpl(0, 0, 0, 0, HCI_ERR_UNSPECIFIED);
}
#ifndef BTA_DM_GATT_CLOSE_DELAY_TOUT
@@ -3877,7 +3879,7 @@
break;
case BTA_GATTC_CLOSE_EVT:
- APPL_TRACE_DEBUG("BTA_GATTC_CLOSE_EVT reason = %d", p_data->close.reason);
+ LOG_DEBUG("BTA_GATTC_CLOSE_EVT reason = %d", p_data->close.reason);
/* in case of disconnect before search is completed */
if ((bta_dm_search_cb.state != BTA_DM_SEARCH_IDLE) &&
(bta_dm_search_cb.state != BTA_DM_SEARCH_ACTIVE) &&
@@ -3902,9 +3904,9 @@
* Parameters:
*
******************************************************************************/
-static void bta_dm_ctrl_features_rd_cmpl_cback(tBTM_STATUS result) {
+static void bta_dm_ctrl_features_rd_cmpl_cback(tHCI_STATUS result) {
APPL_TRACE_DEBUG("%s status = %d ", __func__, result);
- if (result == BTM_SUCCESS) {
+ if (result == HCI_SUCCESS) {
if (bta_dm_cb.p_sec_cback)
bta_dm_cb.p_sec_cback(BTA_DM_LE_FEATURES_READ, NULL);
} else {
diff --git a/bta/dm/bta_dm_api.cc b/bta/dm/bta_dm_api.cc
index 8e86c76..2611ebf 100644
--- a/bta/dm/bta_dm_api.cc
+++ b/bta/dm/bta_dm_api.cc
@@ -359,7 +359,7 @@
* Returns BTA_SUCCESS if record set sucessfully, otherwise error code.
*
******************************************************************************/
-tBTA_STATUS BTA_DmSetLocalDiRecord(tBTA_DI_RECORD* p_device_info,
+tBTA_STATUS BTA_DmSetLocalDiRecord(tSDP_DI_RECORD* p_device_info,
uint32_t* p_handle) {
tBTA_STATUS status = BTA_FAILURE;
diff --git a/bta/dm/bta_dm_int.h b/bta/dm/bta_dm_int.h
index cd19afc..6e433d2 100644
--- a/bta/dm/bta_dm_int.h
+++ b/bta/dm/bta_dm_int.h
@@ -71,14 +71,14 @@
/* data type for BTA_DM_API_SEARCH_EVT */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
tBTA_SERVICE_MASK services;
tBTA_DM_SEARCH_CBACK* p_cback;
} tBTA_DM_API_SEARCH;
/* data type for BTA_DM_API_DISCOVER_EVT */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
RawAddress bd_addr;
tBTA_DM_SEARCH_CBACK* p_cback;
tBT_TRANSPORT transport;
@@ -92,7 +92,7 @@
} tBTA_DM_API_PIN_REPLY;
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
RawAddress bd_addr;
tBTM_IO_CAP io_cap;
tBTM_OOB_DATA oob_data;
@@ -108,25 +108,25 @@
/* data type for BTA_DM_REMT_NAME_EVT */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
tBTA_DM_SEARCH result;
} tBTA_DM_REM_NAME;
/* data type for tBTA_DM_DISC_RESULT */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
tBTA_DM_SEARCH result;
} tBTA_DM_DISC_RESULT;
/* data type for BTA_DM_INQUIRY_CMPL_EVT */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
uint8_t num;
} tBTA_DM_INQUIRY_CMPL;
/* data type for BTA_DM_SDP_RESULT_EVT */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
uint16_t sdp_result;
} tBTA_DM_SDP_RESULT;
@@ -142,14 +142,14 @@
} tBTA_DM_API_ADD_DEVICE;
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
bool enable;
} tBTA_DM_API_BLE_FEATURE;
/* union of all data types */
typedef union {
/* GKI event buffer header */
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
tBTA_DM_API_SEARCH search;
@@ -468,7 +468,7 @@
/* DI control block */
extern tBTA_DM_DI_CB bta_dm_di_cb;
-extern bool bta_dm_search_sm_execute(BT_HDR* p_msg);
+extern bool bta_dm_search_sm_execute(BT_HDR_RIGID* p_msg);
extern void bta_dm_search_sm_disable(void);
extern void bta_dm_enable(tBTA_DM_SEC_CBACK*);
diff --git a/bta/dm/bta_dm_main.cc b/bta/dm/bta_dm_main.cc
index 02f04ce..4708500 100644
--- a/bta/dm/bta_dm_main.cc
+++ b/bta/dm/bta_dm_main.cc
@@ -59,7 +59,7 @@
* Returns void
*
******************************************************************************/
-bool bta_dm_search_sm_execute(BT_HDR* p_msg) {
+bool bta_dm_search_sm_execute(BT_HDR_RIGID* p_msg) {
APPL_TRACE_EVENT("bta_dm_search_sm_execute state:%d, event:0x%x",
bta_dm_search_cb.state, p_msg->event);
diff --git a/bta/gatt/bta_gattc_act.cc b/bta/gatt/bta_gattc_act.cc
index ee9f460..54f9074 100644
--- a/bta/gatt/bta_gattc_act.cc
+++ b/bta/gatt/bta_gattc_act.cc
@@ -34,6 +34,7 @@
#include "bta/hh/bta_hh_int.h"
#include "btif/include/btif_debug_conn.h"
#include "device/include/controller.h"
+#include "main/shim/dumpsys.h"
#include "osi/include/log.h"
#include "osi/include/osi.h" // UNUSED_ATTR
#include "stack/include/btm_ble_api_types.h"
@@ -69,6 +70,8 @@
static void bta_gattc_conn_update_cback(tGATT_IF gatt_if, uint16_t conn_id,
uint16_t interval, uint16_t latency,
uint16_t timeout, tGATT_STATUS status);
+static void bta_gattc_init_bk_conn(const tBTA_GATTC_API_OPEN* p_data,
+ tBTA_GATTC_RCB* p_clreg);
static tGATT_CBACK bta_gattc_cl_cback = {
.p_conn_cb = bta_gattc_conn_cback,
@@ -152,7 +155,7 @@
}
/** start an application interface */
-void bta_gattc_start_if(uint8_t client_if) {
+static void bta_gattc_start_if(uint8_t client_if) {
if (!bta_gattc_cl_get_regcb(client_if)) {
LOG(ERROR) << "Unable to start app.: Unknown client_if=" << +client_if;
return;
@@ -176,7 +179,8 @@
for (uint8_t i = 0; i < BTA_GATTC_CL_MAX; i++) {
if (!bta_gattc_cb.cl_rcb[i].in_use) {
if ((bta_gattc_cb.cl_rcb[i].client_if = GATT_Register(
- app_uuid, &bta_gattc_cl_cback, eatt_suppport)) == 0) {
+ app_uuid, "GattClient", &bta_gattc_cl_cback, eatt_suppport)) ==
+ 0) {
LOG(ERROR) << "Register with GATT stack failed.";
status = GATT_ERROR;
} else {
@@ -236,7 +240,7 @@
p_clreg->dereg_pending = true;
- BT_HDR buf;
+ BT_HDR_RIGID buf;
buf.event = BTA_GATTC_API_CLOSE_EVT;
buf.layer_specific = bta_gattc_cb.clcb[i].bta_conn_id;
bta_gattc_close(&bta_gattc_cb.clcb[i], (tBTA_GATTC_DATA*)&buf);
@@ -244,8 +248,8 @@
}
/** process connect API request */
-void bta_gattc_process_api_open(tBTA_GATTC_DATA* p_msg) {
- uint16_t event = ((BT_HDR*)p_msg)->event;
+void bta_gattc_process_api_open(const tBTA_GATTC_DATA* p_msg) {
+ uint16_t event = ((BT_HDR_RIGID*)p_msg)->event;
tBTA_GATTC_RCB* p_clreg = bta_gattc_cl_get_regcb(p_msg->api_conn.client_if);
if (!p_clreg) {
@@ -274,10 +278,10 @@
}
/** process connect API request */
-void bta_gattc_process_api_open_cancel(tBTA_GATTC_DATA* p_msg) {
+void bta_gattc_process_api_open_cancel(const tBTA_GATTC_DATA* p_msg) {
CHECK(p_msg != nullptr);
- uint16_t event = ((BT_HDR*)p_msg)->event;
+ uint16_t event = ((BT_HDR_RIGID*)p_msg)->event;
if (!p_msg->api_cancel_conn.is_direct) {
LOG_DEBUG("Cancel GATT client background connection");
@@ -307,7 +311,8 @@
}
/** process encryption complete message */
-void bta_gattc_process_enc_cmpl(tGATT_IF client_if, const RawAddress& bda) {
+static void bta_gattc_process_enc_cmpl(tGATT_IF client_if,
+ const RawAddress& bda) {
tBTA_GATTC_RCB* p_clreg = bta_gattc_cl_get_regcb(client_if);
if (!p_clreg || !p_clreg->p_cback) return;
@@ -322,7 +327,7 @@
}
void bta_gattc_cancel_open_error(tBTA_GATTC_CLCB* p_clcb,
- UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
+ UNUSED_ATTR const tBTA_GATTC_DATA* p_data) {
tBTA_GATTC cb_data;
cb_data.status = GATT_ERROR;
@@ -332,7 +337,7 @@
}
void bta_gattc_open_error(tBTA_GATTC_CLCB* p_clcb,
- UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
+ UNUSED_ATTR const tBTA_GATTC_DATA* p_data) {
LOG(ERROR) << "Connection already opened. wrong state";
bta_gattc_send_open_cback(p_clcb->p_rcb, GATT_SUCCESS, p_clcb->bda,
@@ -340,7 +345,7 @@
}
void bta_gattc_open_fail(tBTA_GATTC_CLCB* p_clcb,
- UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
+ UNUSED_ATTR const tBTA_GATTC_DATA* p_data) {
LOG(WARNING) << __func__ << ": Cannot establish Connection. conn_id="
<< loghex(p_clcb->bta_conn_id) << ". Return GATT_ERROR("
<< +GATT_ERROR << ")";
@@ -352,7 +357,7 @@
}
/** Process API connection function */
-void bta_gattc_open(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+void bta_gattc_open(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data) {
tBTA_GATTC_DATA gattc_data;
/* open/hold a connection */
@@ -377,9 +382,10 @@
}
/** Process API Open for a background connection */
-void bta_gattc_init_bk_conn(tBTA_GATTC_API_OPEN* p_data,
- tBTA_GATTC_RCB* p_clreg) {
+static void bta_gattc_init_bk_conn(const tBTA_GATTC_API_OPEN* p_data,
+ tBTA_GATTC_RCB* p_clreg) {
if (!bta_gattc_mark_bg_conn(p_data->client_if, p_data->remote_bda, true)) {
+ LOG_WARN("Unable to find space for acceptlist connection mask");
bta_gattc_send_open_cback(p_clreg, GATT_NO_RESOURCES, p_data->remote_bda,
GATT_INVALID_CONN_ID, BT_TRANSPORT_LE, 0);
return;
@@ -396,25 +402,35 @@
}
uint16_t conn_id;
- /* if is not a connected remote device */
if (!GATT_GetConnIdIfConnected(p_data->client_if, p_data->remote_bda,
&conn_id, p_data->transport)) {
+ LOG_WARN("Not a connected remote device");
return;
}
tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_alloc_clcb(
p_data->client_if, p_data->remote_bda, BT_TRANSPORT_LE);
- if (!p_clcb) return;
+ if (!p_clcb) {
+ LOG_WARN("Unable to find connection link for device:%s",
+ PRIVATE_ADDRESS(p_data->remote_bda));
+ return;
+ }
- tBTA_GATTC_DATA gattc_data;
- gattc_data.hdr.layer_specific = p_clcb->bta_conn_id = conn_id;
+ p_clcb->bta_conn_id = conn_id;
+ tBTA_GATTC_DATA gattc_data = {
+ .hdr =
+ {
+ .layer_specific = conn_id,
+ },
+ };
/* open connection */
- bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CONN_EVT, &gattc_data);
+ bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CONN_EVT,
+ static_cast<const tBTA_GATTC_DATA*>(&gattc_data));
}
/** Process API Cancel Open for a background connection */
-void bta_gattc_cancel_bk_conn(tBTA_GATTC_API_CANCEL_OPEN* p_data) {
+void bta_gattc_cancel_bk_conn(const tBTA_GATTC_API_CANCEL_OPEN* p_data) {
tBTA_GATTC_RCB* p_clreg;
tBTA_GATTC cb_data;
cb_data.status = GATT_ERROR;
@@ -435,7 +451,7 @@
}
void bta_gattc_cancel_open_ok(tBTA_GATTC_CLCB* p_clcb,
- UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
+ UNUSED_ATTR const tBTA_GATTC_DATA* p_data) {
tBTA_GATTC cb_data;
if (p_clcb->p_rcb->p_cback) {
@@ -446,7 +462,8 @@
bta_gattc_clcb_dealloc(p_clcb);
}
-void bta_gattc_cancel_open(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+void bta_gattc_cancel_open(tBTA_GATTC_CLCB* p_clcb,
+ const tBTA_GATTC_DATA* p_data) {
tBTA_GATTC cb_data;
if (GATT_CancelConnect(p_clcb->p_rcb->client_if,
@@ -461,7 +478,7 @@
}
/** receive connection callback from stack */
-void bta_gattc_conn(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+void bta_gattc_conn(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data) {
tGATT_IF gatt_if;
VLOG(1) << __func__ << ": server cache state=" << +p_clcb->p_srcb->state;
@@ -521,7 +538,8 @@
}
/** close a connection */
-void bta_gattc_close_fail(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+void bta_gattc_close_fail(tBTA_GATTC_CLCB* p_clcb,
+ const tBTA_GATTC_DATA* p_data) {
tBTA_GATTC cb_data;
if (p_clcb->p_rcb->p_cback) {
@@ -539,16 +557,19 @@
}
/** close a GATTC connection */
-void bta_gattc_close(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+void bta_gattc_close(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data) {
tBTA_GATTC_CBACK* p_cback = p_clcb->p_rcb->p_cback;
tBTA_GATTC_RCB* p_clreg = p_clcb->p_rcb;
- tBTA_GATTC cb_data;
-
- cb_data.close.client_if = p_clcb->p_rcb->client_if;
- cb_data.close.conn_id = p_clcb->bta_conn_id;
- cb_data.close.reason = 0;
- cb_data.close.remote_bda = p_clcb->bda;
- cb_data.close.status = GATT_SUCCESS;
+ tBTA_GATTC cb_data = {
+ .close =
+ {
+ .client_if = p_clcb->p_rcb->client_if,
+ .conn_id = p_clcb->bta_conn_id,
+ .reason = GATT_CONN_OK,
+ .remote_bda = p_clcb->bda,
+ .status = GATT_SUCCESS,
+ },
+ };
if (p_clcb->transport == BT_TRANSPORT_BR_EDR)
bta_sys_conn_close(BTA_ID_GATTC, BTA_ALL_APP_ID, p_clcb->bda);
@@ -590,7 +611,8 @@
}
/** close a GATTC connection while in discovery state */
-void bta_gattc_disc_close(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+void bta_gattc_disc_close(tBTA_GATTC_CLCB* p_clcb,
+ const tBTA_GATTC_DATA* p_data) {
VLOG(1) << __func__
<< ": Discovery cancel conn_id=" << loghex(p_clcb->bta_conn_id);
@@ -609,7 +631,7 @@
}
/** when a SRCB start discovery, tell all related clcb and set the state */
-void bta_gattc_set_discover_st(tBTA_GATTC_SERV* p_srcb) {
+static void bta_gattc_set_discover_st(tBTA_GATTC_SERV* p_srcb) {
uint8_t i;
for (i = 0; i < BTA_GATTC_CLCB_MAX; i++) {
@@ -626,13 +648,13 @@
* set status to be discovery cancel for current discovery.
*/
void bta_gattc_restart_discover(tBTA_GATTC_CLCB* p_clcb,
- UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
+ UNUSED_ATTR const tBTA_GATTC_DATA* p_data) {
p_clcb->status = GATT_CANCEL;
p_clcb->auto_update = BTA_GATTC_DISC_WAITING;
}
/** Configure MTU size on the GATT connection */
-void bta_gattc_cfg_mtu(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+void bta_gattc_cfg_mtu(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data) {
if (!bta_gattc_enqueue(p_clcb, p_data)) return;
tGATT_STATUS status =
@@ -664,7 +686,7 @@
/** Start a discovery on server */
void bta_gattc_start_discover(tBTA_GATTC_CLCB* p_clcb,
- UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
+ UNUSED_ATTR const tBTA_GATTC_DATA* p_data) {
VLOG(1) << __func__ << ": conn_id:" << loghex(p_clcb->bta_conn_id)
<< " p_clcb->p_srcb->state:" << +p_clcb->p_srcb->state;
@@ -710,8 +732,8 @@
/** discovery on server is finished */
void bta_gattc_disc_cmpl(tBTA_GATTC_CLCB* p_clcb,
- UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
- tBTA_GATTC_DATA* p_q_cmd = p_clcb->p_q_cmd;
+ UNUSED_ATTR const tBTA_GATTC_DATA* p_data) {
+ const tBTA_GATTC_DATA* p_q_cmd = p_clcb->p_q_cmd;
VLOG(1) << __func__ << ": conn_id=" << loghex(p_clcb->bta_conn_id);
@@ -761,7 +783,7 @@
}
/** Read an attribute */
-void bta_gattc_read(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+void bta_gattc_read(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data) {
if (!bta_gattc_enqueue(p_clcb, p_data)) return;
tGATT_STATUS status;
@@ -793,7 +815,8 @@
}
/** read multiple */
-void bta_gattc_read_multi(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+void bta_gattc_read_multi(tBTA_GATTC_CLCB* p_clcb,
+ const tBTA_GATTC_DATA* p_data) {
if (!bta_gattc_enqueue(p_clcb, p_data)) return;
tGATT_READ_PARAM read_param;
@@ -817,7 +840,7 @@
}
/** Write an attribute */
-void bta_gattc_write(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+void bta_gattc_write(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data) {
if (!bta_gattc_enqueue(p_clcb, p_data)) return;
tGATT_STATUS status = GATT_SUCCESS;
@@ -846,7 +869,7 @@
}
/** send execute write */
-void bta_gattc_execute(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+void bta_gattc_execute(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data) {
if (!bta_gattc_enqueue(p_clcb, p_data)) return;
tGATT_STATUS status =
@@ -861,7 +884,7 @@
}
/** send handle value confirmation */
-void bta_gattc_confirm(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+void bta_gattc_confirm(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data) {
uint16_t cid = p_data->api_confirm.cid;
if (GATTC_SendHandleValueConfirm(p_data->api_confirm.hdr.layer_specific,
@@ -877,7 +900,8 @@
}
/** read complete */
-void bta_gattc_read_cmpl(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_OP_CMPL* p_data) {
+static void bta_gattc_read_cmpl(tBTA_GATTC_CLCB* p_clcb,
+ const tBTA_GATTC_OP_CMPL* p_data) {
GATT_READ_OP_CB cb = p_clcb->p_q_cmd->api_read.read_cb;
void* my_cb_data = p_clcb->p_q_cmd->api_read.read_cb_data;
@@ -897,7 +921,8 @@
}
/** write complete */
-void bta_gattc_write_cmpl(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_OP_CMPL* p_data) {
+static void bta_gattc_write_cmpl(tBTA_GATTC_CLCB* p_clcb,
+ const tBTA_GATTC_OP_CMPL* p_data) {
GATT_WRITE_OP_CB cb = p_clcb->p_q_cmd->api_write.write_cb;
void* my_cb_data = p_clcb->p_q_cmd->api_write.write_cb_data;
@@ -910,7 +935,8 @@
}
/** execute write complete */
-void bta_gattc_exec_cmpl(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_OP_CMPL* p_data) {
+static void bta_gattc_exec_cmpl(tBTA_GATTC_CLCB* p_clcb,
+ const tBTA_GATTC_OP_CMPL* p_data) {
tBTA_GATTC cb_data;
osi_free_and_reset((void**)&p_clcb->p_q_cmd);
@@ -924,8 +950,8 @@
}
/** configure MTU operation complete */
-void bta_gattc_cfg_mtu_cmpl(tBTA_GATTC_CLCB* p_clcb,
- tBTA_GATTC_OP_CMPL* p_data) {
+static void bta_gattc_cfg_mtu_cmpl(tBTA_GATTC_CLCB* p_clcb,
+ const tBTA_GATTC_OP_CMPL* p_data) {
GATT_CONFIGURE_MTU_OP_CB cb = p_clcb->p_q_cmd->api_mtu.mtu_cb;
void* my_cb_data = p_clcb->p_q_cmd->api_mtu.mtu_cb_data;
tBTA_GATTC cb_data;
@@ -949,27 +975,32 @@
}
/** operation completed */
-void bta_gattc_op_cmpl(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
- uint8_t op = (uint8_t)p_data->op_cmpl.op_code;
- uint8_t mapped_op = 0;
-
- VLOG(1) << __func__ << ": op:" << +op;
-
- if (op == GATTC_OPTYPE_INDICATION || op == GATTC_OPTYPE_NOTIFICATION) {
- LOG(ERROR) << "unexpected operation, ignored";
+void bta_gattc_op_cmpl(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data) {
+ if (p_clcb->p_q_cmd == NULL) {
+ LOG_ERROR("No pending command gatt client command");
return;
}
- if (op < GATTC_OPTYPE_READ) return;
+ const tGATTC_OPTYPE op = p_data->op_cmpl.op_code;
+ switch (op) {
+ case GATTC_OPTYPE_READ:
+ case GATTC_OPTYPE_WRITE:
+ case GATTC_OPTYPE_EXE_WRITE:
+ case GATTC_OPTYPE_CONFIG:
+ break;
- if (p_clcb->p_q_cmd == NULL) {
- LOG(ERROR) << "No pending command";
- return;
+ case GATTC_OPTYPE_NONE:
+ case GATTC_OPTYPE_DISCOVERY:
+ case GATTC_OPTYPE_NOTIFICATION:
+ case GATTC_OPTYPE_INDICATION:
+ default:
+ LOG(ERROR) << "unexpected operation, ignored";
+ return;
}
if (p_clcb->p_q_cmd->hdr.event !=
bta_gattc_opcode_to_int_evt[op - GATTC_OPTYPE_READ]) {
- mapped_op =
+ uint8_t mapped_op =
p_clcb->p_q_cmd->hdr.event - BTA_GATTC_API_READ_EVT + GATTC_OPTYPE_READ;
if (mapped_op > GATTC_OPTYPE_INDICATION) mapped_op = 0;
@@ -987,7 +1018,8 @@
p_clcb->p_srcb->srvc_hdl_chg && op != GATTC_OPTYPE_CONFIG) {
VLOG(1) << "Discard all responses when service change indication is "
"received.";
- p_data->op_cmpl.status = GATT_ERROR;
+ // TODO Fix constness
+ const_cast<tBTA_GATTC_DATA*>(p_data)->op_cmpl.status = GATT_ERROR;
}
/* service handle change void the response, discard it */
@@ -1028,7 +1060,7 @@
}
/** start a search in the local server cache */
-void bta_gattc_search(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+void bta_gattc_search(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data) {
tGATT_STATUS status = GATT_INTERNAL_ERROR;
tBTA_GATTC cb_data;
VLOG(1) << __func__ << ": conn_id=" << loghex(p_clcb->bta_conn_id);
@@ -1046,13 +1078,13 @@
/** enqueue a command into control block, usually because discovery operation is
* busy */
-void bta_gattc_q_cmd(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+void bta_gattc_q_cmd(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data) {
bta_gattc_enqueue(p_clcb, p_data);
}
/** report API call failure back to apps */
void bta_gattc_fail(tBTA_GATTC_CLCB* p_clcb,
- UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
+ UNUSED_ATTR const tBTA_GATTC_DATA* p_data) {
if (p_clcb->status == GATT_SUCCESS) {
LOG(ERROR) << "operation not supported at current state " << +p_clcb->state;
}
@@ -1088,14 +1120,14 @@
tBT_TRANSPORT transport) {
if (connected) {
LOG_INFO("Connected att_id:%hhu transport:%s reason:%s", gattc_if,
- BtTransportText(transport).c_str(),
+ bt_transport_text(transport).c_str(),
gatt_disconnection_reason_text(reason).c_str());
- btif_debug_conn_state(bdaddr, BTIF_DEBUG_CONNECTED, GATT_CONN_UNKNOWN);
+ btif_debug_conn_state(bdaddr, BTIF_DEBUG_CONNECTED, GATT_CONN_OK);
} else {
LOG_INFO("Disconnected att_id:%hhu transport:%s reason:%s", gattc_if,
- BtTransportText(transport).c_str(),
+ bt_transport_text(transport).c_str(),
gatt_disconnection_reason_text(reason).c_str());
- btif_debug_conn_state(bdaddr, BTIF_DEBUG_DISCONNECTED, GATT_CONN_UNKNOWN);
+ btif_debug_conn_state(bdaddr, BTIF_DEBUG_DISCONNECTED, GATT_CONN_OK);
}
tBTA_GATTC_DATA* p_buf =
@@ -1163,12 +1195,12 @@
}
/** process service change indication */
-bool bta_gattc_process_srvc_chg_ind(uint16_t conn_id, tBTA_GATTC_RCB* p_clrcb,
- tBTA_GATTC_SERV* p_srcb,
- tBTA_GATTC_CLCB* p_clcb,
- tBTA_GATTC_NOTIFY* p_notify,
- tGATT_VALUE* att_value) {
-
+static bool bta_gattc_process_srvc_chg_ind(uint16_t conn_id,
+ tBTA_GATTC_RCB* p_clrcb,
+ tBTA_GATTC_SERV* p_srcb,
+ tBTA_GATTC_CLCB* p_clcb,
+ tBTA_GATTC_NOTIFY* p_notify,
+ tGATT_VALUE* att_value) {
Uuid gattp_uuid = Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER);
Uuid srvc_chg_uuid = Uuid::From16Bit(GATT_UUID_GATT_SRV_CHGD);
@@ -1241,9 +1273,9 @@
}
/** process all non-service change indication/notification */
-void bta_gattc_proc_other_indication(tBTA_GATTC_CLCB* p_clcb, uint8_t op,
- tGATT_CL_COMPLETE* p_data,
- tBTA_GATTC_NOTIFY* p_notify) {
+static void bta_gattc_proc_other_indication(tBTA_GATTC_CLCB* p_clcb, uint8_t op,
+ tGATT_CL_COMPLETE* p_data,
+ tBTA_GATTC_NOTIFY* p_notify) {
VLOG(1) << __func__
<< StringPrintf(
": check p_data->att_value.handle=%d p_data->handle=%d",
@@ -1264,8 +1296,8 @@
}
/** process indication/notification */
-void bta_gattc_process_indicate(uint16_t conn_id, tGATTC_OPTYPE op,
- tGATT_CL_COMPLETE* p_data) {
+static void bta_gattc_process_indicate(uint16_t conn_id, tGATTC_OPTYPE op,
+ tGATT_CL_COMPLETE* p_data) {
uint16_t handle = p_data->att_value.handle;
tBTA_GATTC_NOTIFY notify;
RawAddress remote_bda;
diff --git a/bta/gatt/bta_gattc_api.cc b/bta/gatt/bta_gattc_api.cc
index 185261f..6009223 100644
--- a/bta/gatt/bta_gattc_api.cc
+++ b/bta/gatt/bta_gattc_api.cc
@@ -127,18 +127,23 @@
void BTA_GATTC_Open(tGATT_IF client_if, const RawAddress& remote_bda,
bool is_direct, tBT_TRANSPORT transport, bool opportunistic,
uint8_t initiating_phys) {
- tBTA_GATTC_API_OPEN* p_buf =
- (tBTA_GATTC_API_OPEN*)osi_malloc(sizeof(tBTA_GATTC_API_OPEN));
+ tBTA_GATTC_DATA data = {
+ .api_conn =
+ {
+ .hdr =
+ {
+ .event = BTA_GATTC_API_OPEN_EVT,
+ },
+ .remote_bda = remote_bda,
+ .client_if = client_if,
+ .is_direct = is_direct,
+ .transport = transport,
+ .initiating_phys = initiating_phys,
+ .opportunistic = opportunistic,
+ },
+ };
- p_buf->hdr.event = BTA_GATTC_API_OPEN_EVT;
- p_buf->client_if = client_if;
- p_buf->is_direct = is_direct;
- p_buf->transport = transport;
- p_buf->initiating_phys = initiating_phys;
- p_buf->opportunistic = opportunistic;
- p_buf->remote_bda = remote_bda;
-
- bta_sys_sendmsg(p_buf);
+ post_on_bt_main([data]() { bta_gattc_process_api_open(&data); });
}
/*******************************************************************************
@@ -181,7 +186,7 @@
*
******************************************************************************/
void BTA_GATTC_Close(uint16_t conn_id) {
- BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
p_buf->event = BTA_GATTC_API_CLOSE_EVT;
p_buf->layer_specific = conn_id;
diff --git a/bta/gatt/bta_gattc_cache.cc b/bta/gatt/bta_gattc_cache.cc
index 50ee389..9f5582a 100644
--- a/bta/gatt/bta_gattc_cache.cc
+++ b/bta/gatt/bta_gattc_cache.cc
@@ -61,10 +61,10 @@
tBTA_GATTC_SERV* p_srvc_cb);
static void bta_gattc_read_db_hash_cmpl(tBTA_GATTC_CLCB* p_clcb,
- tBTA_GATTC_OP_CMPL* p_data);
+ const tBTA_GATTC_OP_CMPL* p_data);
static void bta_gattc_read_ext_prop_desc_cmpl(tBTA_GATTC_CLCB* p_clcb,
- tBTA_GATTC_OP_CMPL* p_data);
+ const tBTA_GATTC_OP_CMPL* p_data);
// define the max retry count for DATABASE_OUT_OF_SYNC
#define BTA_GATTC_DISCOVER_RETRY_COUNT 2
@@ -95,22 +95,22 @@
/* debug function to display the server cache */
static void bta_gattc_display_cache_server(const Database& database) {
- LOG(INFO) << "<================Start Server Cache =============>";
+ LOG(INFO) << "<=--------------=Start Server Cache =-----------=>";
std::istringstream iss(database.ToString());
for (std::string line; std::getline(iss, line);) {
LOG(INFO) << line;
}
- LOG(INFO) << "<================End Server Cache =============>";
+ LOG(INFO) << "<=--------------=End Server Cache =-----------=>";
}
/** debug function to display the exploration list */
static void bta_gattc_display_explore_record(const DatabaseBuilder& database) {
- LOG(INFO) << "<================Start Explore Queue =============>";
+ 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 =============>";
+ LOG(INFO) << "<=--------------= End Explore Queue =-----------=>";
}
#endif /* BTA_GATT_DEBUG == TRUE */
@@ -175,7 +175,7 @@
p_clcb->request_during_discovery =
BTA_GATTC_DISCOVER_REQ_READ_EXT_PROP_DESC;
- if (p_srvc_cb->read_multiple_not_supported) {
+ if (p_srvc_cb->read_multiple_not_supported || descriptors.size() == 1) {
tGATT_READ_PARAM read_param{
.by_handle = {.handle = descriptors.front(),
.auth_req = GATT_AUTH_REQ_NONE}};
@@ -268,7 +268,7 @@
}
/* Process the discovery result from sdp */
-void bta_gattc_sdp_callback(uint16_t sdp_status, void* user_data) {
+void bta_gattc_sdp_callback(tSDP_STATUS 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);
@@ -367,7 +367,7 @@
/** operation completed */
void bta_gattc_op_cmpl_during_discovery(tBTA_GATTC_CLCB* p_clcb,
- tBTA_GATTC_DATA* p_data) {
+ const tBTA_GATTC_DATA* p_data) {
// Currently, there are two cases needed to be handled.
// 1. Read ext prop descriptor value after service discovery
// 2. Read db hash before starting service discovery
@@ -643,7 +643,7 @@
/* handle response of reading database hash */
static void bta_gattc_read_db_hash_cmpl(tBTA_GATTC_CLCB* p_clcb,
- tBTA_GATTC_OP_CMPL* p_data) {
+ const tBTA_GATTC_OP_CMPL* p_data) {
uint8_t op = (uint8_t)p_data->op_code;
if (op != GATTC_OPTYPE_READ) {
VLOG(1) << __func__ << ": op = " << +p_data->hdr.layer_specific;
@@ -680,8 +680,8 @@
}
/* handle response of reading extended properties descriptor */
-static void bta_gattc_read_ext_prop_desc_cmpl(tBTA_GATTC_CLCB* p_clcb,
- tBTA_GATTC_OP_CMPL* p_data) {
+static void bta_gattc_read_ext_prop_desc_cmpl(
+ tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_OP_CMPL* p_data) {
uint8_t op = (uint8_t)p_data->op_code;
if (op != GATTC_OPTYPE_READ) {
VLOG(1) << __func__ << ": op = " << +p_data->hdr.layer_specific;
diff --git a/bta/gatt/bta_gattc_int.h b/bta/gatt/bta_gattc_int.h
index 6b2b8d8..8f52e58 100644
--- a/bta/gatt/bta_gattc_int.h
+++ b/bta/gatt/bta_gattc_int.h
@@ -75,8 +75,6 @@
#define BTA_GATTC_KNOWN_SR_MAX 255
#endif
-#define BTA_GATTC_CONN_MAX GATT_MAX_PHY_CHANNEL
-
#ifndef BTA_GATTC_CLCB_MAX
#define BTA_GATTC_CLCB_MAX GATT_CL_MAX_LCB
#endif
@@ -85,7 +83,7 @@
/* internal strucutre for GATTC register API */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
RawAddress remote_bda;
tGATT_IF client_if;
bool is_direct;
@@ -97,7 +95,7 @@
typedef tBTA_GATTC_API_OPEN tBTA_GATTC_API_CANCEL_OPEN;
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
tGATT_AUTH_REQ auth_req;
// read by handle data
@@ -114,7 +112,7 @@
} tBTA_GATTC_API_READ;
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
tGATT_AUTH_REQ auth_req;
uint16_t handle;
tGATT_WRITE_TYPE write_type;
@@ -126,45 +124,43 @@
} tBTA_GATTC_API_WRITE;
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
bool is_execute;
} tBTA_GATTC_API_EXEC;
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
uint16_t cid;
} tBTA_GATTC_API_CONFIRM;
-typedef tGATT_CL_COMPLETE tBTA_GATTC_CMPL;
-
typedef struct {
- BT_HDR hdr;
- uint8_t op_code;
+ BT_HDR_RIGID hdr;
+ tGATTC_OPTYPE op_code;
tGATT_STATUS status;
- tBTA_GATTC_CMPL* p_cmpl;
+ tGATT_CL_COMPLETE* p_cmpl;
} tBTA_GATTC_OP_CMPL;
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
bluetooth::Uuid* p_srvc_uuid;
} tBTA_GATTC_API_SEARCH;
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
tGATT_AUTH_REQ auth_req;
uint8_t num_attr;
uint16_t handles[GATT_MAX_READ_MULTI_HANDLES];
} tBTA_GATTC_API_READ_MULTI;
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
uint16_t mtu;
GATT_CONFIGURE_MTU_OP_CB mtu_cb;
void* mtu_cb_data;
} tBTA_GATTC_API_CFG_MTU;
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
RawAddress remote_bda;
tGATT_IF client_if;
uint8_t role;
@@ -173,7 +169,7 @@
} tBTA_GATTC_INT_CONN;
typedef union {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
tBTA_GATTC_API_OPEN api_conn;
tBTA_GATTC_API_CANCEL_OPEN api_cancel_conn;
tBTA_GATTC_API_READ api_read;
@@ -254,7 +250,7 @@
tBT_TRANSPORT transport; /* channel transport */
tBTA_GATTC_RCB* p_rcb; /* pointer to the registration CB */
tBTA_GATTC_SERV* p_srcb; /* server cache CB */
- tBTA_GATTC_DATA* p_q_cmd; /* command in queue waiting for execution */
+ const tBTA_GATTC_DATA* p_q_cmd; /* command in queue waiting for execution */
// request during discover state
#define BTA_GATTC_DISCOVER_REQ_NONE 0
@@ -305,7 +301,7 @@
typedef struct {
uint8_t state;
- tBTA_GATTC_CONN conn_track[BTA_GATTC_CONN_MAX];
+ tBTA_GATTC_CONN conn_track[GATT_MAX_PHY_CHANNEL];
tBTA_GATTC_BG_TCK bg_track[BTA_GATTC_KNOWN_SR_MAX];
tBTA_GATTC_RCB cl_rcb[BTA_GATTC_CL_MAX];
@@ -323,73 +319,84 @@
/*****************************************************************************
* Function prototypes
****************************************************************************/
-extern bool bta_gattc_hdl_event(BT_HDR* p_msg);
+extern bool bta_gattc_hdl_event(BT_HDR_RIGID* p_msg);
extern bool bta_gattc_sm_execute(tBTA_GATTC_CLCB* p_clcb, uint16_t event,
- tBTA_GATTC_DATA* p_data);
+ const tBTA_GATTC_DATA* p_data);
/* function processed outside SM */
extern void bta_gattc_disable();
extern void bta_gattc_register(const bluetooth::Uuid& app_uuid,
tBTA_GATTC_CBACK* p_data,
BtaAppRegisterCallback cb, bool eatt_support);
-extern void bta_gattc_process_api_open(tBTA_GATTC_DATA* p_msg);
-extern void bta_gattc_process_api_open_cancel(tBTA_GATTC_DATA* p_msg);
+extern void bta_gattc_process_api_open(const tBTA_GATTC_DATA* p_msg);
+extern void bta_gattc_process_api_open_cancel(const tBTA_GATTC_DATA* p_msg);
extern void bta_gattc_deregister(tBTA_GATTC_RCB* p_clreg);
/* function within state machine */
-extern void bta_gattc_open(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_open(tBTA_GATTC_CLCB* p_clcb,
+ const tBTA_GATTC_DATA* p_data);
extern void bta_gattc_open_fail(tBTA_GATTC_CLCB* p_clcb,
- tBTA_GATTC_DATA* p_data);
+ const tBTA_GATTC_DATA* p_data);
extern void bta_gattc_open_error(tBTA_GATTC_CLCB* p_clcb,
- tBTA_GATTC_DATA* p_data);
+ const tBTA_GATTC_DATA* p_data);
extern void bta_gattc_cancel_open(tBTA_GATTC_CLCB* p_clcb,
- tBTA_GATTC_DATA* p_data);
+ const tBTA_GATTC_DATA* p_data);
extern void bta_gattc_cancel_open_ok(tBTA_GATTC_CLCB* p_clcb,
- tBTA_GATTC_DATA* p_data);
+ const tBTA_GATTC_DATA* p_data);
extern void bta_gattc_cancel_open_error(tBTA_GATTC_CLCB* p_clcb,
- tBTA_GATTC_DATA* p_data);
+ const tBTA_GATTC_DATA* p_data);
-extern void bta_gattc_conn(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_conn(tBTA_GATTC_CLCB* p_clcb,
+ const tBTA_GATTC_DATA* p_data);
-extern void bta_gattc_close(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_close(tBTA_GATTC_CLCB* p_clcb,
+ const tBTA_GATTC_DATA* p_data);
extern void bta_gattc_close_fail(tBTA_GATTC_CLCB* p_clcb,
- tBTA_GATTC_DATA* p_data);
+ const tBTA_GATTC_DATA* p_data);
extern void bta_gattc_disc_close(tBTA_GATTC_CLCB* p_clcb,
- tBTA_GATTC_DATA* p_data);
+ const tBTA_GATTC_DATA* p_data);
extern void bta_gattc_start_discover(tBTA_GATTC_CLCB* p_clcb,
- tBTA_GATTC_DATA* p_data);
+ const tBTA_GATTC_DATA* p_data);
extern void bta_gattc_start_discover_internal(tBTA_GATTC_CLCB* p_clcb);
extern void bta_gattc_disc_cmpl(tBTA_GATTC_CLCB* p_clcb,
- tBTA_GATTC_DATA* p_data);
-extern void bta_gattc_read(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
-extern void bta_gattc_write(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
-extern void bta_gattc_op_cmpl(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
-extern void bta_gattc_q_cmd(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
-extern void bta_gattc_search(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
-extern void bta_gattc_fail(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
-extern void bta_gattc_confirm(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
-extern void bta_gattc_execute(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+ const tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_read(tBTA_GATTC_CLCB* p_clcb,
+ const tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_write(tBTA_GATTC_CLCB* p_clcb,
+ const tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_op_cmpl(tBTA_GATTC_CLCB* p_clcb,
+ const tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_q_cmd(tBTA_GATTC_CLCB* p_clcb,
+ const tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_search(tBTA_GATTC_CLCB* p_clcb,
+ const tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_fail(tBTA_GATTC_CLCB* p_clcb,
+ const tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_confirm(tBTA_GATTC_CLCB* p_clcb,
+ const tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_execute(tBTA_GATTC_CLCB* p_clcb,
+ const tBTA_GATTC_DATA* p_data);
extern void bta_gattc_read_multi(tBTA_GATTC_CLCB* p_clcb,
- tBTA_GATTC_DATA* p_data);
-extern void bta_gattc_ci_open(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+ const tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_ci_open(tBTA_GATTC_CLCB* p_clcb,
+ const tBTA_GATTC_DATA* p_data);
extern void bta_gattc_ci_close(tBTA_GATTC_CLCB* p_clcb,
- tBTA_GATTC_DATA* p_data);
+ const tBTA_GATTC_DATA* p_data);
extern void bta_gattc_op_cmpl_during_discovery(tBTA_GATTC_CLCB* p_clcb,
- tBTA_GATTC_DATA* p_data);
+ const tBTA_GATTC_DATA* p_data);
extern void bta_gattc_restart_discover(tBTA_GATTC_CLCB* p_clcb,
- tBTA_GATTC_DATA* p_msg);
-extern void bta_gattc_init_bk_conn(tBTA_GATTC_API_OPEN* p_data,
- tBTA_GATTC_RCB* p_clreg);
-extern void bta_gattc_cancel_bk_conn(tBTA_GATTC_API_CANCEL_OPEN* p_data);
+ const tBTA_GATTC_DATA* p_msg);
+extern void bta_gattc_cancel_bk_conn(const tBTA_GATTC_API_CANCEL_OPEN* p_data);
extern void bta_gattc_send_open_cback(tBTA_GATTC_RCB* p_clreg,
tGATT_STATUS status,
const RawAddress& remote_bda,
uint16_t conn_id, tBT_TRANSPORT transport,
uint16_t mtu);
extern void bta_gattc_process_api_refresh(const RawAddress& remote_bda);
-extern void bta_gattc_cfg_mtu(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_cfg_mtu(tBTA_GATTC_CLCB* p_clcb,
+ const tBTA_GATTC_DATA* p_data);
extern void bta_gattc_listen(tBTA_GATTC_DATA* p_msg);
extern void bta_gattc_broadcast(tBTA_GATTC_DATA* p_msg);
@@ -412,7 +419,8 @@
extern tBTA_GATTC_CLCB* bta_gattc_find_int_conn_clcb(tBTA_GATTC_DATA* p_msg);
extern tBTA_GATTC_CLCB* bta_gattc_find_int_disconn_clcb(tBTA_GATTC_DATA* p_msg);
-extern bool bta_gattc_enqueue(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+extern bool bta_gattc_enqueue(tBTA_GATTC_CLCB* p_clcb,
+ const tBTA_GATTC_DATA* p_data);
extern bool bta_gattc_check_notif_registry(tBTA_GATTC_RCB* p_clreg,
tBTA_GATTC_SERV* p_srcb,
diff --git a/bta/gatt/bta_gattc_main.cc b/bta/gatt/bta_gattc_main.cc
index afcf271..b93881e 100644
--- a/bta/gatt/bta_gattc_main.cc
+++ b/bta/gatt/bta_gattc_main.cc
@@ -65,7 +65,7 @@
};
/* type for action functions */
typedef void (*tBTA_GATTC_ACTION)(tBTA_GATTC_CLCB* p_clcb,
- tBTA_GATTC_DATA* p_data);
+ const tBTA_GATTC_DATA* p_data);
/* action function list */
const tBTA_GATTC_ACTION bta_gattc_action[] = {
@@ -296,7 +296,7 @@
*
******************************************************************************/
bool bta_gattc_sm_execute(tBTA_GATTC_CLCB* p_clcb, uint16_t event,
- tBTA_GATTC_DATA* p_data) {
+ const tBTA_GATTC_DATA* p_data) {
tBTA_GATTC_ST_TBL state_table;
uint8_t action;
int i;
@@ -361,7 +361,7 @@
* Returns bool
*
******************************************************************************/
-bool bta_gattc_hdl_event(BT_HDR* p_msg) {
+bool bta_gattc_hdl_event(BT_HDR_RIGID* p_msg) {
tBTA_GATTC_CLCB* p_clcb = NULL;
bool rt = true;
#if (BTA_GATT_DEBUG == TRUE)
@@ -386,8 +386,8 @@
p_clcb = bta_gattc_find_clcb_by_conn_id(p_msg->layer_specific);
if (p_clcb != NULL) {
- rt =
- bta_gattc_sm_execute(p_clcb, p_msg->event, (tBTA_GATTC_DATA*)p_msg);
+ rt = bta_gattc_sm_execute(p_clcb, p_msg->event,
+ (const tBTA_GATTC_DATA*)p_msg);
} else {
VLOG(1) << "Ignore unknown conn ID: " << +p_msg->layer_specific;
}
diff --git a/bta/gatt/bta_gattc_utils.cc b/bta/gatt/bta_gattc_utils.cc
index e8439c7..2da0739 100644
--- a/bta/gatt/bta_gattc_utils.cc
+++ b/bta/gatt/bta_gattc_utils.cc
@@ -322,7 +322,7 @@
* Returns success or failure.
*
******************************************************************************/
-bool bta_gattc_enqueue(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+bool bta_gattc_enqueue(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data) {
if (p_clcb->p_q_cmd == NULL) {
p_clcb->p_q_cmd = p_data;
return true;
@@ -526,7 +526,7 @@
uint8_t i_conn = 0;
tBTA_GATTC_CONN* p_conn = &bta_gattc_cb.conn_track[0];
- for (i_conn = 0; i_conn < BTA_GATTC_CONN_MAX; i_conn++, p_conn++) {
+ for (i_conn = 0; i_conn < GATT_MAX_PHY_CHANNEL; i_conn++, p_conn++) {
if (!p_conn->in_use) {
#if (BTA_GATT_DEBUG == TRUE)
VLOG(1) << __func__ << ": found conn_track:" << +i_conn << " available";
@@ -552,7 +552,7 @@
uint8_t i_conn = 0;
tBTA_GATTC_CONN* p_conn = &bta_gattc_cb.conn_track[0];
- for (i_conn = 0; i_conn < BTA_GATTC_CONN_MAX; i_conn++, p_conn++) {
+ for (i_conn = 0; i_conn < GATT_MAX_PHY_CHANNEL; i_conn++, p_conn++) {
if (p_conn->in_use && remote_bda == p_conn->remote_bda) {
#if (BTA_GATT_DEBUG == TRUE)
VLOG(1) << __func__ << ": found conn_track:" << +i_conn << " matched";
diff --git a/bta/gatt/bta_gatts_act.cc b/bta/gatt/bta_gatts_act.cc
index eb2837b..504b8a9 100644
--- a/bta/gatt/bta_gatts_act.cc
+++ b/bta/gatt/bta_gatts_act.cc
@@ -209,7 +209,7 @@
p_cb->rcb[first_unuse].p_cback = p_msg->api_reg.p_cback;
p_cb->rcb[first_unuse].app_uuid = p_msg->api_reg.app_uuid;
cb_data.reg_oper.server_if = p_cb->rcb[first_unuse].gatt_if =
- GATT_Register(p_msg->api_reg.app_uuid, &bta_gatts_cback,
+ GATT_Register(p_msg->api_reg.app_uuid, "GattServer", &bta_gatts_cback,
p_msg->api_reg.eatt_support);
if (!p_cb->rcb[first_unuse].gatt_if) {
status = GATT_NO_RESOURCES;
@@ -593,9 +593,9 @@
<< ", conn_id=" << loghex(conn_id) << " connected=" << connected;
if (connected)
- btif_debug_conn_state(bdaddr, BTIF_DEBUG_CONNECTED, GATT_CONN_UNKNOWN);
+ btif_debug_conn_state(bdaddr, BTIF_DEBUG_CONNECTED, GATT_CONN_OK);
else
- btif_debug_conn_state(bdaddr, BTIF_DEBUG_DISCONNECTED, GATT_CONN_UNKNOWN);
+ btif_debug_conn_state(bdaddr, BTIF_DEBUG_DISCONNECTED, GATT_CONN_OK);
p_reg = bta_gatts_find_app_rcb_by_app_if(gatt_if);
diff --git a/bta/gatt/bta_gatts_api.cc b/bta/gatt/bta_gatts_api.cc
index 6403034..5e49a7c 100644
--- a/bta/gatt/bta_gatts_api.cc
+++ b/bta/gatt/bta_gatts_api.cc
@@ -61,7 +61,7 @@
return;
}
- BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
p_buf->event = BTA_GATTS_API_DISABLE_EVT;
bta_sys_sendmsg(p_buf);
bta_sys_deregister(BTA_ID_GATTS);
@@ -193,7 +193,7 @@
*
******************************************************************************/
void BTA_GATTS_DeleteService(uint16_t service_id) {
- BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
p_buf->event = BTA_GATTS_API_DEL_SRVC_EVT;
p_buf->layer_specific = service_id;
@@ -213,7 +213,7 @@
*
******************************************************************************/
void BTA_GATTS_StopService(uint16_t service_id) {
- BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
p_buf->event = BTA_GATTS_API_STOP_SRVC_EVT;
p_buf->layer_specific = service_id;
@@ -355,7 +355,7 @@
*
******************************************************************************/
void BTA_GATTS_Close(uint16_t conn_id) {
- BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
p_buf->event = BTA_GATTS_API_CLOSE_EVT;
p_buf->layer_specific = conn_id;
diff --git a/bta/gatt/bta_gatts_int.h b/bta/gatt/bta_gatts_int.h
index 42a3a66..25cdf49 100644
--- a/bta/gatt/bta_gatts_int.h
+++ b/bta/gatt/bta_gatts_int.h
@@ -61,28 +61,28 @@
/* internal strucutre for GATTC register API */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
bluetooth::Uuid app_uuid;
tBTA_GATTS_CBACK* p_cback;
bool eatt_support;
} tBTA_GATTS_API_REG;
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
tGATT_IF server_if;
} tBTA_GATTS_INT_START_IF;
typedef tBTA_GATTS_INT_START_IF tBTA_GATTS_API_DEREG;
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
tGATT_IF server_if;
btgatt_db_element_t* service;
uint16_t count;
} tBTA_GATTS_API_ADD_SERVICE;
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
uint16_t attr_id;
uint16_t len;
bool need_confirm;
@@ -90,19 +90,19 @@
} tBTA_GATTS_API_INDICATION;
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
uint32_t trans_id;
tGATT_STATUS status;
tGATTS_RSP* p_rsp;
} tBTA_GATTS_API_RSP;
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
tBT_TRANSPORT transport;
} tBTA_GATTS_API_START;
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
RawAddress remote_bda;
tGATT_IF server_if;
bool is_direct;
@@ -113,7 +113,7 @@
typedef tBTA_GATTS_API_OPEN tBTA_GATTS_API_CANCEL_OPEN;
typedef union {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
tBTA_GATTS_API_REG api_reg;
tBTA_GATTS_API_DEREG api_dereg;
tBTA_GATTS_API_ADD_SERVICE api_add_service;
@@ -159,7 +159,7 @@
/*****************************************************************************
* Function prototypes
****************************************************************************/
-extern bool bta_gatts_hdl_event(BT_HDR* p_msg);
+extern bool bta_gatts_hdl_event(BT_HDR_RIGID* p_msg);
extern void bta_gatts_api_disable(tBTA_GATTS_CB* p_cb);
extern void bta_gatts_api_enable(tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_data);
diff --git a/bta/gatt/bta_gatts_main.cc b/bta/gatt/bta_gatts_main.cc
index 555582a..497f315 100644
--- a/bta/gatt/bta_gatts_main.cc
+++ b/bta/gatt/bta_gatts_main.cc
@@ -39,7 +39,7 @@
* Returns void
*
******************************************************************************/
-bool bta_gatts_hdl_event(BT_HDR* p_msg) {
+bool bta_gatts_hdl_event(BT_HDR_RIGID* p_msg) {
tBTA_GATTS_CB* p_cb = &bta_gatts_cb;
switch (p_msg->event) {
diff --git a/bta/hd/bta_hd_api.cc b/bta/hd/bta_hd_api.cc
index d012770..4b33cd3 100644
--- a/bta/hd/bta_hd_api.cc
+++ b/bta/hd/bta_hd_api.cc
@@ -79,7 +79,7 @@
bta_sys_deregister(BTA_ID_HD);
- BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
p_buf->event = BTA_HD_API_DISABLE_EVT;
bta_sys_sendmsg(p_buf);
}
@@ -152,7 +152,7 @@
extern void BTA_HdUnregisterApp(void) {
APPL_TRACE_API("%s", __func__);
- BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
p_buf->event = BTA_HD_API_UNREGISTER_APP_EVT;
bta_sys_sendmsg(p_buf);
@@ -203,7 +203,7 @@
extern void BTA_HdVirtualCableUnplug(void) {
APPL_TRACE_API("%s", __func__);
- BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
p_buf->event = BTA_HD_API_VC_UNPLUG_EVT;
bta_sys_sendmsg(p_buf);
@@ -242,7 +242,7 @@
******************************************************************************/
extern void BTA_HdDisconnect(void) {
APPL_TRACE_API("%s", __func__);
- BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
p_buf->event = BTA_HD_API_DISCONNECT_EVT;
bta_sys_sendmsg(p_buf);
diff --git a/bta/hd/bta_hd_int.h b/bta/hd/bta_hd_int.h
index a433ebd..67f282b 100644
--- a/bta/hd/bta_hd_int.h
+++ b/bta/hd/bta_hd_int.h
@@ -63,7 +63,7 @@
#define BTA_HD_INVALID_EVT (BTA_HD_API_DISABLE_EVT + 1)
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
tBTA_HD_CBACK* p_cback;
} tBTA_HD_API_ENABLE;
@@ -80,7 +80,7 @@
#define BTA_HD_STATE_REMOVING 0x05
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
char name[BTA_HD_APP_NAME_LEN];
char description[BTA_HD_APP_DESCRIPTION_LEN];
char provider[BTA_HD_APP_PROVIDER_LEN];
@@ -95,7 +95,7 @@
#define BTA_HD_REPORT_LEN HID_DEV_MTU_SIZE
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
bool use_intr;
uint8_t type;
uint8_t id;
@@ -104,18 +104,18 @@
} tBTA_HD_SEND_REPORT;
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
RawAddress addr;
} tBTA_HD_DEVICE_CTRL;
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
uint8_t error;
} tBTA_HD_REPORT_ERR;
/* union of all event data types */
typedef union {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
tBTA_HD_API_ENABLE api_enable;
tBTA_HD_REGISTER_APP register_app;
tBTA_HD_SEND_REPORT send_report;
@@ -124,7 +124,7 @@
} tBTA_HD_DATA;
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
RawAddress addr;
uint32_t data;
BT_HDR* p_data;
@@ -150,7 +150,7 @@
/*****************************************************************************
* Function prototypes
****************************************************************************/
-extern bool bta_hd_hdl_event(BT_HDR* p_msg);
+extern bool bta_hd_hdl_event(BT_HDR_RIGID* p_msg);
extern void bta_hd_api_enable(tBTA_HD_DATA* p_data);
extern void bta_hd_api_disable(void);
diff --git a/bta/hd/bta_hd_main.cc b/bta/hd/bta_hd_main.cc
index 0f90db8..022f8fe 100644
--- a/bta/hd/bta_hd_main.cc
+++ b/bta/hd/bta_hd_main.cc
@@ -176,7 +176,7 @@
* Returns void
*
******************************************************************************/
-bool bta_hd_hdl_event(BT_HDR* p_msg) {
+bool bta_hd_hdl_event(BT_HDR_RIGID* p_msg) {
APPL_TRACE_API("%s: p_msg->event=%d", __func__, p_msg->event);
switch (p_msg->event) {
diff --git a/bta/hf_client/bta_hf_client_api.cc b/bta/hf_client/bta_hf_client_api.cc
index 7981356..5308365 100644
--- a/bta/hf_client/bta_hf_client_api.cc
+++ b/bta/hf_client/bta_hf_client_api.cc
@@ -111,7 +111,7 @@
*
******************************************************************************/
void BTA_HfClientClose(uint16_t handle) {
- BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
p_buf->event = BTA_HF_CLIENT_API_CLOSE_EVT;
p_buf->layer_specific = handle;
@@ -131,7 +131,7 @@
*
******************************************************************************/
void BTA_HfClientAudioOpen(uint16_t handle) {
- BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
p_buf->event = BTA_HF_CLIENT_API_AUDIO_OPEN_EVT;
p_buf->layer_specific = handle;
@@ -151,7 +151,7 @@
*
******************************************************************************/
void BTA_HfClientAudioClose(uint16_t handle) {
- BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
p_buf->event = BTA_HF_CLIENT_API_AUDIO_CLOSE_EVT;
p_buf->layer_specific = handle;
diff --git a/bta/hf_client/bta_hf_client_int.h b/bta/hf_client/bta_hf_client_int.h
index 9727f48..8354ead 100755
--- a/bta/hf_client/bta_hf_client_int.h
+++ b/bta/hf_client/bta_hf_client_int.h
@@ -111,26 +111,26 @@
****************************************************************************/
/* data type for BTA_HF_CLIENT_API_OPEN_EVT */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
RawAddress bd_addr;
uint16_t* handle;
} tBTA_HF_CLIENT_API_OPEN;
/* data type for BTA_HF_CLIENT_DISC_RESULT_EVT */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
uint16_t status;
} tBTA_HF_CLIENT_DISC_RESULT;
/* data type for RFCOMM events */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
uint16_t port_handle;
} tBTA_HF_CLIENT_RFC;
/* generic purpose data type for other events */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
bool bool_val;
uint8_t uint8_val;
uint32_t uint32_val1;
@@ -140,7 +140,7 @@
/* union of all event datatypes */
typedef union {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
tBTA_HF_CLIENT_API_OPEN api_open;
tBTA_HF_CLIENT_DISC_RESULT disc_result;
tBTA_HF_CLIENT_RFC rfc;
@@ -217,7 +217,7 @@
const RawAddress& bd_addr);
extern tBTA_HF_CLIENT_CB* bta_hf_client_find_cb_by_rfc_handle(uint16_t handle);
extern tBTA_HF_CLIENT_CB* bta_hf_client_find_cb_by_sco_handle(uint16_t handle);
-extern bool bta_hf_client_hdl_event(BT_HDR* p_msg);
+extern bool bta_hf_client_hdl_event(BT_HDR_RIGID* p_msg);
extern void bta_hf_client_sm_execute(uint16_t event,
tBTA_HF_CLIENT_DATA* p_data);
extern void bta_hf_client_slc_seq(tBTA_HF_CLIENT_CB* client_cb, bool error);
diff --git a/bta/hf_client/bta_hf_client_main.cc b/bta/hf_client/bta_hf_client_main.cc
index c4b33cf..902af13 100644
--- a/bta/hf_client/bta_hf_client_main.cc
+++ b/bta/hf_client/bta_hf_client_main.cc
@@ -675,7 +675,7 @@
* Returns bool
*
******************************************************************************/
-bool bta_hf_client_hdl_event(BT_HDR* p_msg) {
+bool bta_hf_client_hdl_event(BT_HDR_RIGID* p_msg) {
APPL_TRACE_DEBUG("%s: %s (0x%x)", __func__,
bta_hf_client_evt_str(p_msg->event), p_msg->event);
bta_hf_client_sm_execute(p_msg->event, (tBTA_HF_CLIENT_DATA*)p_msg);
diff --git a/bta/hf_client/bta_hf_client_sco.cc b/bta/hf_client/bta_hf_client_sco.cc
index 7e2947c..ee906ec 100644
--- a/bta/hf_client/bta_hf_client_sco.cc
+++ b/bta/hf_client/bta_hf_client_sco.cc
@@ -182,7 +182,7 @@
return;
}
- BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
p_buf->event = BTA_HF_CLIENT_SCO_OPEN_EVT;
p_buf->layer_specific = client_cb->handle;
bta_sys_sendmsg(p_buf);
@@ -207,7 +207,7 @@
return;
}
- BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
p_buf->event = BTA_HF_CLIENT_SCO_CLOSE_EVT;
p_buf->layer_specific = client_cb->handle;
bta_sys_sendmsg(p_buf);
diff --git a/bta/hf_client/bta_hf_client_sdp.cc b/bta/hf_client/bta_hf_client_sdp.cc
index 2ed7191..db33481 100755
--- a/bta/hf_client/bta_hf_client_sdp.cc
+++ b/bta/hf_client/bta_hf_client_sdp.cc
@@ -56,7 +56,7 @@
* Returns void
*
******************************************************************************/
-static void bta_hf_client_sdp_cback(uint16_t status, void* data) {
+static void bta_hf_client_sdp_cback(tSDP_STATUS status, void* data) {
uint16_t event;
tBTA_HF_CLIENT_DISC_RESULT* p_buf = (tBTA_HF_CLIENT_DISC_RESULT*)osi_malloc(
sizeof(tBTA_HF_CLIENT_DISC_RESULT));
diff --git a/bta/hh/bta_hh_act.cc b/bta/hh/bta_hh_act.cc
index ec3e0d5..20c2cf5 100644
--- a/bta/hh/bta_hh_act.cc
+++ b/bta/hh/bta_hh_act.cc
@@ -59,10 +59,8 @@
uint8_t event, uint32_t data, BT_HDR* pdata);
static tBTA_HH_STATUS bta_hh_get_trans_status(uint32_t result);
-#if (BTA_HH_DEBUG == TRUE)
static const char* bta_hh_get_w4_event(uint16_t event);
static const char* bta_hh_hid_event_name(uint16_t event);
-#endif
/*****************************************************************************
* Action Functions
@@ -77,7 +75,7 @@
* Returns void
*
******************************************************************************/
-void bta_hh_api_enable(tBTA_HH_DATA* p_data) {
+void bta_hh_api_enable(const tBTA_HH_DATA* p_data) {
tBTA_HH_STATUS status = BTA_HH_ERR;
uint8_t xx;
@@ -193,10 +191,8 @@
/* security is required for the connection, add attr_mask bit*/
attr_mask |= HID_SEC_REQUIRED;
-#if (BTA_HH_DEBUG == TRUE)
APPL_TRACE_EVENT("%s: p_cb: %d result 0x%02x, attr_mask 0x%02x, handle %x",
__func__, p_cb, result, attr_mask, p_cb->hid_handle);
-#endif
/* check to see type of device is supported , and should not been added
* before */
@@ -251,14 +247,12 @@
* Returns void
*
******************************************************************************/
-static void bta_hh_di_sdp_cback(uint16_t result) {
+static void bta_hh_di_sdp_cback(tSDP_RESULT result) {
tBTA_HH_DEV_CB* p_cb = bta_hh_cb.p_cur;
tBTA_HH_STATUS status = BTA_HH_ERR_SDP;
tSDP_DI_GET_RECORD di_rec;
tHID_STATUS ret;
-#if (BTA_HH_DEBUG == TRUE)
APPL_TRACE_EVENT("%s: p_cb: %d result 0x%02x", __func__, p_cb, result);
-#endif
/* if DI record does not exist on remote device, vendor_id in
* tBTA_HH_DEV_DSCP_INFO will be set to 0xffff and we will allow the
@@ -286,10 +280,8 @@
if (ret == HID_SUCCESS) {
status = BTA_HH_OK;
} else {
-#if (BTA_HH_DEBUG == TRUE)
APPL_TRACE_DEBUG("%s: HID_HostGetSDPRecord failed: Status 0x%2x",
__func__, ret);
-#endif
}
}
@@ -315,14 +307,15 @@
* Returns void
*
******************************************************************************/
-void bta_hh_start_sdp(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+void bta_hh_start_sdp(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) {
tBTA_HH_STATUS status = BTA_HH_ERR_SDP;
uint8_t hdl;
p_cb->mode = p_data->api_conn.mode;
bta_hh_cb.p_cur = p_cb;
- if (bta_hh_is_le_device(p_cb, p_data->api_conn.bd_addr)) {
+ if (BTM_UseLeLink(p_data->api_conn.bd_addr)) {
+ p_cb->is_le_device = true;
bta_hh_le_open_conn(p_cb, p_data->api_conn.bd_addr);
return;
}
@@ -330,9 +323,7 @@
/* if previously virtually cabled device, skip SDP */
if (p_cb->app_id) {
status = BTA_HH_OK;
-#if (BTA_HH_DEBUG == TRUE)
APPL_TRACE_DEBUG("%s: skip SDP for known devices", __func__);
-#endif
if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE) {
if (HID_HostAddDev(p_cb->addr, p_cb->attr_mask, &hdl) == HID_SUCCESS) {
/* update device CB with newly register device handle */
@@ -360,10 +351,8 @@
if (SDP_DiDiscover(p_data->api_conn.bd_addr, bta_hh_cb.p_disc_db,
p_bta_hh_cfg->sdp_db_size,
bta_hh_di_sdp_cback) != SDP_SUCCESS) {
-#if (BTA_HH_DEBUG == TRUE)
APPL_TRACE_DEBUG("%s: SDP_DiDiscover failed: Status 0x%2X", __func__,
status);
-#endif
status = BTA_HH_ERR_SDP;
osi_free_and_reset((void**)&bta_hh_cb.p_disc_db);
} else {
@@ -400,13 +389,13 @@
* Returns void
*
******************************************************************************/
-void bta_hh_sdp_cmpl(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+void bta_hh_sdp_cmpl(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) {
+ CHECK(p_data != nullptr);
+
tBTA_HH_CONN conn_dat;
tBTA_HH_STATUS status = p_data->status;
-#if (BTA_HH_DEBUG == TRUE)
APPL_TRACE_DEBUG("%s: status 0x%2X", __func__, p_data->status);
-#endif
/* initialize call back data */
memset((void*)&conn_dat, 0, sizeof(tBTA_HH_CONN));
@@ -431,10 +420,8 @@
APPL_TRACE_DEBUG("%s: connection already in progress", __func__);
return;
} else {
-#if (BTA_HH_DEBUG == TRUE)
APPL_TRACE_DEBUG("%s: HID_HostOpenDev failed: Status 0x%2X", __func__,
ret);
-#endif
/* open fail, remove device from management device list */
HID_HostRemoveDev(p_cb->hid_handle);
status = BTA_HH_ERR;
@@ -468,9 +455,7 @@
/* clean up device control block */
bta_hh_clean_up_kdev(p_cb);
}
-#if (BTA_HH_DEBUG == TRUE)
bta_hh_trace_dev_db();
-#endif
}
p_cb->incoming_conn = false;
p_cb->incoming_hid_handle = BTA_HH_INVALID_HANDLE;
@@ -487,7 +472,8 @@
* Returns void
*
******************************************************************************/
-void bta_hh_api_disc_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+extern void btif_hh_remove_device(RawAddress bd_addr);
+void bta_hh_api_disc_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) {
CHECK(p_cb != nullptr);
if (p_cb->is_le_device) {
@@ -495,8 +481,6 @@
PRIVATE_ADDRESS(p_cb->addr));
bta_hh_le_api_disc_act(p_cb);
- BTM_LogHistory(kBtmLogTag, p_cb->addr, "Closed",
- base::StringPrintf("le local initiated"));
} else {
const uint8_t hid_handle =
@@ -516,9 +500,6 @@
.handle = hid_handle},
};
(*bta_hh_cb.p_cback)(BTA_HH_CLOSE_EVT, &bta_hh);
- BTM_LogHistory(kBtmLogTag, p_cb->addr, "Closed",
- base::StringPrintf("classic local reason %s",
- hid_status_text(status).c_str()));
}
}
@@ -532,7 +513,7 @@
* Returns void
*
******************************************************************************/
-void bta_hh_open_cmpl_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+void bta_hh_open_cmpl_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) {
tBTA_HH_CONN conn;
uint8_t dev_handle =
p_data ? (uint8_t)p_data->hid_cback.hdr.layer_specific : p_cb->hid_handle;
@@ -555,7 +536,7 @@
BTM_LogHistory(kBtmLogTag, p_cb->addr, "Opened",
base::StringPrintf(
"%s initiator:%s", (p_cb->is_le_device) ? "le" : "classic",
- (p_cb->incoming_conn) ? "local" : "remote"));
+ (p_cb->incoming_conn) ? "remote" : "local"));
if (!p_cb->is_le_device)
{
@@ -592,15 +573,13 @@
* Returns void
*
******************************************************************************/
-void bta_hh_open_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+void bta_hh_open_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) {
tBTA_HH_API_CONN conn_data;
uint8_t dev_handle =
p_data ? (uint8_t)p_data->hid_cback.hdr.layer_specific : p_cb->hid_handle;
-#if (BTA_HH_DEBUG == TRUE)
APPL_TRACE_EVENT("%s: Device[%d] connected", __func__, dev_handle);
-#endif
/* SDP has been done */
if (p_cb->app_id != 0) {
@@ -632,7 +611,7 @@
* Returns void
*
******************************************************************************/
-void bta_hh_data_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+void bta_hh_data_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) {
BT_HDR* pdata = p_data->hid_cback.p_data;
uint8_t* p_rpt = (uint8_t*)(pdata + 1) + pdata->offset;
@@ -653,11 +632,9 @@
* Returns void
*
******************************************************************************/
-void bta_hh_handsk_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
-#if (BTA_HH_DEBUG == TRUE)
+void bta_hh_handsk_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) {
APPL_TRACE_DEBUG("HANDSHAKE received for: event = %s data= %d",
bta_hh_get_w4_event(p_cb->w4_evt), p_data->hid_cback.data);
-#endif
tBTA_HH bta_hh;
memset(&bta_hh, 0, sizeof(tBTA_HH));
@@ -702,9 +679,7 @@
bta_hh.conn.handle = p_cb->hid_handle;
bta_hh.conn.bda = p_cb->addr;
(*bta_hh_cb.p_cback)(p_cb->w4_evt, &bta_hh);
-#if (BTA_HH_DEBUG == TRUE)
bta_hh_trace_dev_db();
-#endif
p_cb->w4_evt = 0;
break;
@@ -728,15 +703,13 @@
* Returns void
*
******************************************************************************/
-void bta_hh_ctrl_dat_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+void bta_hh_ctrl_dat_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) {
BT_HDR* pdata = p_data->hid_cback.p_data;
uint8_t* data = (uint8_t*)(pdata + 1) + pdata->offset;
tBTA_HH_HSDATA hs_data;
-#if (BTA_HH_DEBUG == TRUE)
APPL_TRACE_DEBUG("Ctrl DATA received w4: event[%s]",
bta_hh_get_w4_event(p_cb->w4_evt));
-#endif
if (pdata->len == 0) {
android_errorWriteLog(0x534e4554, "116108738");
p_cb->w4_evt = 0;
@@ -760,12 +733,10 @@
hs_data.rsp_data.proto_mode = ((*data) == HID_PAR_PROTOCOL_REPORT)
? BTA_HH_PROTO_RPT_MODE
: BTA_HH_PROTO_BOOT_MODE;
-#if (BTA_HH_DEBUG == TRUE)
APPL_TRACE_DEBUG("GET_PROTOCOL Mode = [%s]",
(hs_data.rsp_data.proto_mode == BTA_HH_PROTO_RPT_MODE)
? "Report"
: "Boot");
-#endif
break;
/* should not expect control DATA for SET_ transaction */
case BTA_HH_SET_PROTO_EVT:
@@ -775,10 +746,8 @@
case BTA_HH_SET_IDLE_EVT:
FALLTHROUGH_INTENDED; /* FALLTHROUGH */
default:
-#if (BTA_HH_DEBUG == TRUE)
APPL_TRACE_DEBUG("invalid transaction type for DATA payload: 4_evt[%s]",
bta_hh_get_w4_event(p_cb->w4_evt));
-#endif
break;
}
@@ -803,7 +772,7 @@
* Returns void
*
******************************************************************************/
-void bta_hh_open_failure(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+void bta_hh_open_failure(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) {
tBTA_HH_CONN conn_dat;
uint32_t reason = p_data->hid_cback.data; /* Reason for closing (32-bit) */
@@ -817,9 +786,7 @@
/* Report OPEN fail event */
(*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH*)&conn_dat);
-#if (BTA_HH_DEBUG == TRUE)
bta_hh_trace_dev_db();
-#endif
/* clean up control block, but retain SDP info and device handle */
p_cb->vp = false;
p_cb->w4_evt = 0;
@@ -844,13 +811,15 @@
* Returns void
*
******************************************************************************/
-void bta_hh_close_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+void bta_hh_close_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) {
tBTA_HH_CONN conn_dat;
tBTA_HH_CBDATA disc_dat = {BTA_HH_OK, 0};
- uint32_t reason = p_data->hid_cback.data; /* Reason for closing (32-bit) */
- // TODO Fix use proper types
- tHID_STATUS hid_status = static_cast<tHID_STATUS>(reason);
+ uint32_t reason = p_data->hid_cback.data; /* Reason for closing (32-bit) */
+ const bool l2cap_conn_fail = reason & HID_L2CAP_CONN_FAIL;
+ const bool l2cap_req_fail = reason & HID_L2CAP_REQ_FAIL;
+ const bool l2cap_cfg_fail = reason & HID_L2CAP_CFG_FAIL;
+ const tHID_STATUS hid_status = static_cast<tHID_STATUS>(reason & 0xff);
/* if HID_HDEV_EVT_VC_UNPLUG was received, report BTA_HH_VC_UNPLUG_EVT */
uint16_t event = p_cb->vp ? BTA_HH_VC_UNPLUG_EVT : BTA_HH_CLOSE_EVT;
@@ -858,6 +827,16 @@
disc_dat.handle = p_cb->hid_handle;
disc_dat.status = to_bta_hh_status(p_data->hid_cback.data);
+ std::string overlay_fail =
+ base::StringPrintf("%s %s %s", (l2cap_conn_fail) ? "l2cap_conn_fail" : "",
+ (l2cap_req_fail) ? "l2cap_req_fail" : "",
+ (l2cap_cfg_fail) ? "l2cap_cfg_fail" : "");
+ BTM_LogHistory(kBtmLogTag, p_cb->addr, "Closed",
+ base::StringPrintf("%s reason %s %s",
+ (p_cb->is_le_device) ? "le" : "classic",
+ hid_status_text(hid_status).c_str(),
+ overlay_fail.c_str()));
+
/* Check reason for closing */
if ((reason & (HID_L2CAP_CONN_FAIL |
HID_L2CAP_REQ_FAIL)) || /* Failure to initialize connection
@@ -876,18 +855,11 @@
/* Report OPEN fail event */
(*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH*)&conn_dat);
-#if (BTA_HH_DEBUG == TRUE)
bta_hh_trace_dev_db();
-#endif
return;
}
/* otherwise report CLOSE/VC_UNPLUG event */
else {
- BTM_LogHistory(kBtmLogTag, p_cb->addr, "Closed",
- base::StringPrintf("%s reason %s",
- (p_cb->is_le_device) ? "le" : "classic",
- hid_status_text(hid_status).c_str()));
-
/* finaliza device driver */
bta_hh_co_close(p_cb->hid_handle, p_cb->app_id);
/* inform role manager */
@@ -905,9 +877,7 @@
bta_hh_clean_up_kdev(p_cb);
}
-#if (BTA_HH_DEBUG == TRUE)
bta_hh_trace_dev_db();
-#endif
}
/* clean up control block, but retain SDP info and device handle */
@@ -933,7 +903,7 @@
*
******************************************************************************/
void bta_hh_get_dscp_act(tBTA_HH_DEV_CB* p_cb,
- UNUSED_ATTR tBTA_HH_DATA* p_data) {
+ UNUSED_ATTR const tBTA_HH_DATA* p_data) {
if (p_cb->is_le_device) {
bta_hh_le_get_dscp_act(p_cb);
} else
@@ -950,8 +920,8 @@
* Returns void
*
******************************************************************************/
-void bta_hh_maint_dev_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
- tBTA_HH_MAINT_DEV* p_dev_info = &p_data->api_maintdev;
+void bta_hh_maint_dev_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) {
+ const tBTA_HH_MAINT_DEV* p_dev_info = &p_data->api_maintdev;
tBTA_HH_DEV_INFO dev_info;
uint8_t dev_handle;
@@ -963,7 +933,8 @@
dev_info.bda = p_dev_info->bda;
/* initialize callback data */
if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE) {
- if (bta_hh_is_le_device(p_cb, p_data->api_conn.bd_addr)) {
+ if (BTM_UseLeLink(p_data->api_conn.bd_addr)) {
+ p_cb->is_le_device = true;
dev_info.handle = bta_hh_le_add_device(p_cb, p_dev_info);
if (dev_info.handle != BTA_HH_INVALID_HANDLE)
dev_info.status = BTA_HH_OK;
@@ -993,9 +964,7 @@
dev_info.handle = p_cb->hid_handle;
dev_info.status = BTA_HH_OK;
}
-#if (BTA_HH_DEBUG == TRUE)
bta_hh_trace_dev_db();
-#endif
break;
case BTA_HH_RMV_DEV_EVT: /* remove device */
@@ -1033,10 +1002,20 @@
* Returns void
*
******************************************************************************/
-void bta_hh_write_dev_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+static uint8_t convert_api_sndcmd_param(const tBTA_HH_CMD_DATA& api_sndcmd) {
+ uint8_t api_sndcmd_param = api_sndcmd.param;
+ if (api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL) {
+ api_sndcmd_param = (api_sndcmd.param == BTA_HH_PROTO_RPT_MODE)
+ ? HID_PAR_PROTOCOL_REPORT
+ : HID_PAR_PROTOCOL_BOOT_MODE;
+ }
+ return api_sndcmd_param;
+}
+
+void bta_hh_write_dev_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) {
tBTA_HH_CBDATA cbdata = {BTA_HH_OK, 0};
- uint16_t event = (p_data->api_sndcmd.t_type - BTA_HH_FST_BTE_TRANS_EVT) +
- BTA_HH_FST_TRANS_CB_EVT;
+ uint16_t event =
+ (p_data->api_sndcmd.t_type - HID_TRANS_GET_REPORT) + BTA_HH_GET_RPT_EVT;
if (p_cb->is_le_device)
bta_hh_le_write_dev_act(p_cb, p_data);
@@ -1046,15 +1025,11 @@
cbdata.handle = p_cb->hid_handle;
/* match up BTE/BTA report/boot mode def */
- if (p_data->api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL) {
- p_data->api_sndcmd.param =
- (p_data->api_sndcmd.param == BTA_HH_PROTO_RPT_MODE)
- ? HID_PAR_PROTOCOL_REPORT
- : HID_PAR_PROTOCOL_BOOT_MODE;
- }
+ const uint8_t api_sndcmd_param =
+ convert_api_sndcmd_param(p_data->api_sndcmd);
if (HID_HostWriteDev(p_cb->hid_handle, p_data->api_sndcmd.t_type,
- p_data->api_sndcmd.param, p_data->api_sndcmd.data,
+ api_sndcmd_param, p_data->api_sndcmd.data,
p_data->api_sndcmd.rpt_id,
p_data->api_sndcmd.p_data) != HID_SUCCESS) {
APPL_TRACE_ERROR("HID_HostWriteDev Error ");
@@ -1063,7 +1038,7 @@
if (p_data->api_sndcmd.t_type != HID_TRANS_CONTROL &&
p_data->api_sndcmd.t_type != HID_TRANS_DATA)
(*bta_hh_cb.p_cback)(event, (tBTA_HH*)&cbdata);
- else if (p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG)
+ else if (api_sndcmd_param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG)
(*bta_hh_cb.p_cback)(BTA_HH_VC_UNPLUG_EVT, (tBTA_HH*)&cbdata);
} else {
switch (p_data->api_sndcmd.t_type) {
@@ -1086,7 +1061,7 @@
case HID_TRANS_CONTROL:
/* no handshake event will be generated */
/* if VC_UNPLUG is issued, set flag */
- if (p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG)
+ if (api_sndcmd_param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG)
p_cb->vp = true;
break;
@@ -1103,9 +1078,9 @@
/* inform PM for mode change */
bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr);
bta_sys_idle(BTA_ID_HH, p_cb->app_id, p_cb->addr);
- } else if (p_data->api_sndcmd.param == BTA_HH_CTRL_SUSPEND) {
+ } else if (api_sndcmd_param == BTA_HH_CTRL_SUSPEND) {
bta_sys_sco_close(BTA_ID_HH, p_cb->app_id, p_cb->addr);
- } else if (p_data->api_sndcmd.param == BTA_HH_CTRL_EXIT_SUSPEND) {
+ } else if (api_sndcmd_param == BTA_HH_CTRL_EXIT_SUSPEND) {
bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr);
}
}
@@ -1131,10 +1106,8 @@
uint16_t sm_event = BTA_HH_INVALID_EVT;
uint8_t xx = 0;
-#if (BTA_HH_DEBUG == TRUE)
APPL_TRACE_DEBUG("%s::HID_event [%s]", __func__,
bta_hh_hid_event_name(event));
-#endif
switch (event) {
case HID_HDEV_EVT_OPEN:
@@ -1210,7 +1183,6 @@
* Debug Functions
****************************************************************************/
-#if (BTA_HH_DEBUG == TRUE)
static const char* bta_hh_get_w4_event(uint16_t event) {
switch (event) {
case BTA_HH_GET_RPT_EVT:
@@ -1256,4 +1228,3 @@
return "Unknown HID event";
}
}
-#endif
diff --git a/bta/hh/bta_hh_api.cc b/bta/hh/bta_hh_api.cc
index bd9994a..7472504 100644
--- a/bta/hh/bta_hh_api.cc
+++ b/bta/hh/bta_hh_api.cc
@@ -34,6 +34,7 @@
#include "bta/sys/bta_sys.h"
#include "osi/include/allocator.h"
#include "osi/include/osi.h" // UNUSED_ATTR
+#include "stack/include/btu.h"
#include "types/raw_address.h"
/*****************************************************************************
@@ -56,16 +57,22 @@
*
******************************************************************************/
void BTA_HhEnable(tBTA_HH_CBACK* p_cback) {
- tBTA_HH_API_ENABLE* p_buf =
- (tBTA_HH_API_ENABLE*)osi_calloc(sizeof(tBTA_HH_API_ENABLE));
-
/* register with BTA system manager */
bta_sys_register(BTA_ID_HH, &bta_hh_reg);
- p_buf->hdr.event = BTA_HH_API_ENABLE_EVT;
- p_buf->p_cback = p_cback;
-
- bta_sys_sendmsg(p_buf);
+ post_on_bt_main([p_cback]() {
+ tBTA_HH_DATA data = {
+ .api_enable =
+ {
+ .hdr =
+ {
+ .event = BTA_HH_API_ENABLE_EVT,
+ },
+ .p_cback = p_cback,
+ },
+ };
+ bta_hh_api_enable(&data);
+ });
}
/*******************************************************************************
@@ -79,12 +86,9 @@
*
******************************************************************************/
void BTA_HhDisable(void) {
- BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
-
bta_sys_deregister(BTA_ID_HH);
- p_buf->event = BTA_HH_API_DISABLE_EVT;
- bta_sys_sendmsg(p_buf);
+ post_on_bt_main([]() { bta_hh_api_disable(); });
}
/*******************************************************************************
diff --git a/bta/hh/bta_hh_int.h b/bta/hh/bta_hh_int.h
index dc85c4a..dc0db90 100644
--- a/bta/hh/bta_hh_int.h
+++ b/bta/hh/bta_hh_int.h
@@ -33,11 +33,8 @@
#include "bta/sys/bta_sys.h"
#include "stack/include/bt_types.h"
-/* can be moved to bta_api.h */
-#define BTA_HH_MAX_RPT_CHARS 8
-
/* state machine events, these events are handled by the state machine */
-enum {
+enum tBTA_HH_INT_EVT : uint16_t {
BTA_HH_API_OPEN_EVT = BTA_SYS_EVT_START(BTA_ID_HH),
BTA_HH_API_CLOSE_EVT,
BTA_HH_INT_OPEN_EVT,
@@ -60,19 +57,10 @@
BTA_HH_API_ENABLE_EVT,
BTA_HH_API_DISABLE_EVT,
BTA_HH_DISC_CMPL_EVT
-};
-typedef uint16_t tBTA_HH_INT_EVT; /* HID host internal events */
+}; /* HID host internal events */
#define BTA_HH_INVALID_EVT (BTA_HH_DISC_CMPL_EVT + 1)
-/* event used to map between BTE event and BTA event */
-#define BTA_HH_FST_TRANS_CB_EVT BTA_HH_GET_RPT_EVT
-#define BTA_HH_FST_BTE_TRANS_EVT HID_TRANS_GET_REPORT
-
-/* sub event code used for device maintainence API call */
-#define BTA_HH_ADD_DEV 0
-#define BTA_HH_REMOVE_DEV 1
-
/* state machine states */
enum {
BTA_HH_NULL_ST,
@@ -88,7 +76,7 @@
/* data structure used to send a command/data to HID device */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
uint8_t t_type;
uint8_t param;
uint8_t rpt_id;
@@ -98,27 +86,27 @@
/* data type for BTA_HH_API_ENABLE_EVT */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
uint8_t service_name[BTA_SERVICE_NAME_LEN + 1];
tBTA_HH_CBACK* p_cback;
} tBTA_HH_API_ENABLE;
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
RawAddress bd_addr;
tBTA_HH_PROTO_MODE mode;
} tBTA_HH_API_CONN;
/* internal event data from BTE HID callback */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
RawAddress addr;
uint32_t data;
BT_HDR* p_data;
} tBTA_HH_CBACK_DATA;
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
RawAddress bda;
uint16_t attr_mask;
uint16_t sub_event;
@@ -128,22 +116,20 @@
} tBTA_HH_MAINT_DEV;
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
uint16_t conn_id;
- tBTA_GATT_REASON reason; /* disconnect reason code, not useful when connect
- event is reported */
-
+ tGATT_DISCONN_REASON reason;
} tBTA_HH_LE_CLOSE;
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
uint16_t scan_int;
uint16_t scan_win;
} tBTA_HH_SCPP_UPDATE;
/* union of all event data types */
typedef union {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
tBTA_HH_API_ENABLE api_enable;
tBTA_HH_API_CONN api_conn;
tBTA_HH_CMD_DATA api_sndcmd;
@@ -215,7 +201,6 @@
bool in_use; /* control block currently in use */
bool incoming_conn; /* is incoming connection? */
uint8_t incoming_hid_handle; /* temporary handle for incoming connection? */
- bool opened; /* true if device successfully opened HID connection */
tBTA_HH_PROTO_MODE mode; /* protocol mode */
tBTA_HH_STATE state; /* CB state */
@@ -226,39 +211,25 @@
uint8_t disc_active;
tBTA_HH_STATUS status;
- tBTA_GATT_REASON reason;
+ tBTM_STATUS btm_status;
bool is_le_device;
tBTA_HH_LE_HID_SRVC hid_srvc;
uint16_t conn_id;
bool in_bg_conn;
uint8_t clt_cfg_idx;
- uint16_t scan_refresh_char_handle;
bool scps_supported;
#define BTA_HH_LE_SCPS_NOTIFY_NONE 0
#define BTA_HH_LE_SCPS_NOTIFY_SPT 0x01
#define BTA_HH_LE_SCPS_NOTIFY_ENB 0x02
uint8_t scps_notify; /* scan refresh supported/notification enabled */
-
bool security_pending;
} tBTA_HH_DEV_CB;
-/* key board parsing control block */
-typedef struct {
- bool mod_key[4]; /* ctrl, shift(upper), Alt, GUI */
- bool num_lock;
- bool caps_lock;
- uint8_t last_report[BTA_HH_MAX_RPT_CHARS];
-} tBTA_HH_KB_CB;
-
/******************************************************************************
* Main Control Block
******************************************************************************/
typedef struct {
- tBTA_HH_KB_CB kb_cb; /* key board control block,
- suppose BTA will connect
- to only one keyboard at
- the same time */
tBTA_HH_DEV_CB kdev[BTA_HH_MAX_DEVICE]; /* device control block */
tBTA_HH_DEV_CB* p_cur; /* current device control
block idx, used in sdp */
@@ -269,7 +240,6 @@
tGATT_IF gatt_if;
tBTA_HH_CBACK* p_cback; /* Application callbacks */
tSDP_DISCOVERY_DB* p_disc_db;
- uint8_t trace_level; /* tracing level */
uint8_t cnt_num; /* connected device number */
bool w4_disable; /* w4 disable flag */
} tBTA_HH_CB;
@@ -282,37 +252,41 @@
/*****************************************************************************
* Function prototypes
****************************************************************************/
-extern bool bta_hh_hdl_event(BT_HDR* p_msg);
+extern bool bta_hh_hdl_event(BT_HDR_RIGID* p_msg);
extern void bta_hh_sm_execute(tBTA_HH_DEV_CB* p_cb, uint16_t event,
- tBTA_HH_DATA* p_data);
+ const tBTA_HH_DATA* p_data);
/* action functions */
-extern void bta_hh_api_disc_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
-extern void bta_hh_open_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
-extern void bta_hh_close_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
-extern void bta_hh_data_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
-extern void bta_hh_ctrl_dat_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
-extern void bta_hh_start_sdp(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
-extern void bta_hh_sdp_cmpl(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
-extern void bta_hh_write_dev_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
-extern void bta_hh_get_dscp_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
-extern void bta_hh_handsk_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
-extern void bta_hh_maint_dev_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
-extern void bta_hh_open_cmpl_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
-extern void bta_hh_open_failure(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_api_disc_act(tBTA_HH_DEV_CB* p_cb,
+ const tBTA_HH_DATA* p_data);
+extern void bta_hh_open_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data);
+extern void bta_hh_close_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data);
+extern void bta_hh_data_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data);
+extern void bta_hh_ctrl_dat_act(tBTA_HH_DEV_CB* p_cb,
+ const tBTA_HH_DATA* p_data);
+extern void bta_hh_start_sdp(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data);
+extern void bta_hh_sdp_cmpl(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data);
+extern void bta_hh_write_dev_act(tBTA_HH_DEV_CB* p_cb,
+ const tBTA_HH_DATA* p_data);
+extern void bta_hh_get_dscp_act(tBTA_HH_DEV_CB* p_cb,
+ const tBTA_HH_DATA* p_data);
+extern void bta_hh_handsk_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data);
+extern void bta_hh_maint_dev_act(tBTA_HH_DEV_CB* p_cb,
+ const tBTA_HH_DATA* p_data);
+extern void bta_hh_open_cmpl_act(tBTA_HH_DEV_CB* p_cb,
+ const tBTA_HH_DATA* p_data);
+extern void bta_hh_open_failure(tBTA_HH_DEV_CB* p_cb,
+ const tBTA_HH_DATA* p_data);
/* utility functions */
extern uint8_t bta_hh_find_cb(const RawAddress& bda);
-extern void bta_hh_parse_keybd_rpt(tBTA_HH_BOOT_RPT* p_kb_data,
- uint8_t* p_report, uint16_t report_len);
-extern void bta_hh_parse_mice_rpt(tBTA_HH_BOOT_RPT* p_kb_data,
- uint8_t* p_report, uint16_t report_len);
+extern tBTA_HH_DEV_CB* bta_hh_get_cb(const RawAddress& bda);
extern bool bta_hh_tod_spt(tBTA_HH_DEV_CB* p_cb, uint8_t sub_class);
extern void bta_hh_clean_up_kdev(tBTA_HH_DEV_CB* p_cb);
extern void bta_hh_add_device_to_list(tBTA_HH_DEV_CB* p_cb, uint8_t handle,
uint16_t attr_mask,
- tHID_DEV_DSCP_INFO* p_dscp_info,
+ const tHID_DEV_DSCP_INFO* p_dscp_info,
uint8_t sub_class, uint16_t max_latency,
uint16_t min_tout, uint8_t app_id);
extern void bta_hh_update_di_info(tBTA_HH_DEV_CB* p_cb, uint16_t vendor_id,
@@ -323,7 +297,7 @@
extern uint8_t bta_hh_dev_handle_to_cb_idx(uint8_t dev_handle);
/* action functions used outside state machine */
-extern void bta_hh_api_enable(tBTA_HH_DATA* p_data);
+extern void bta_hh_api_enable(const tBTA_HH_DATA* p_data);
extern void bta_hh_api_disable(void);
extern void bta_hh_disc_cmpl(void);
@@ -335,25 +309,28 @@
extern void bta_hh_le_enable(void);
extern bool bta_hh_le_is_hh_gatt_if(tGATT_IF client_if);
extern void bta_hh_le_deregister(void);
-extern bool bta_hh_is_le_device(tBTA_HH_DEV_CB* p_cb,
- const RawAddress& remote_bda);
extern void bta_hh_le_open_conn(tBTA_HH_DEV_CB* p_cb,
const RawAddress& remote_bda);
extern void bta_hh_le_api_disc_act(tBTA_HH_DEV_CB* p_cb);
extern void bta_hh_le_get_dscp_act(tBTA_HH_DEV_CB* p_cb);
-extern void bta_hh_le_write_dev_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_le_write_dev_act(tBTA_HH_DEV_CB* p_cb,
+ const tBTA_HH_DATA* p_data);
extern uint8_t bta_hh_le_add_device(tBTA_HH_DEV_CB* p_cb,
- tBTA_HH_MAINT_DEV* p_dev_info);
+ const tBTA_HH_MAINT_DEV* p_dev_info);
extern void bta_hh_le_remove_dev_bg_conn(tBTA_HH_DEV_CB* p_cb);
-extern void bta_hh_le_open_fail(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
-extern void bta_hh_gatt_open(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
-extern void bta_hh_gatt_close(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
-extern void bta_hh_start_security(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_buf);
+extern void bta_hh_le_open_fail(tBTA_HH_DEV_CB* p_cb,
+ const tBTA_HH_DATA* p_data);
+extern void bta_hh_gatt_open(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data);
+extern void bta_hh_gatt_close(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data);
+extern void bta_hh_start_security(tBTA_HH_DEV_CB* p_cb,
+ const tBTA_HH_DATA* p_buf);
-extern void bta_hh_start_security(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_buf);
-extern void bta_hh_security_cmpl(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_buf);
+extern void bta_hh_start_security(tBTA_HH_DEV_CB* p_cb,
+ const tBTA_HH_DATA* p_buf);
+extern void bta_hh_security_cmpl(tBTA_HH_DEV_CB* p_cb,
+ const tBTA_HH_DATA* p_buf);
extern void bta_hh_le_notify_enc_cmpl(tBTA_HH_DEV_CB* p_cb,
- tBTA_HH_DATA* p_data);
+ const tBTA_HH_DATA* p_data);
#if (BTA_HH_DEBUG == TRUE)
extern void bta_hh_trace_dev_db(void);
diff --git a/bta/hh/bta_hh_le.cc b/bta/hh/bta_hh_le.cc
old mode 100755
new mode 100644
index 35df4fa..5928c54
--- a/bta/hh/bta_hh_le.cc
+++ b/bta/hh/bta_hh_le.cc
@@ -28,27 +28,42 @@
#include "bta/include/bta_hh_co.h"
#include "device/include/interop.h"
#include "main/shim/dumpsys.h"
+#include "main/shim/shim.h"
#include "osi/include/log.h"
-#include "osi/include/osi.h"
-#include "stack/btm/btm_sec.h"
-#include "stack/include/l2c_api.h"
-#include "stack/include/srvc_api.h"
+#include "osi/include/osi.h" // ARRAY_SIZE
+#include "stack/btm/btm_sec.h" // BTM_
+#include "stack/include/btu.h" // post_on_bt_main
+#include "stack/include/l2c_api.h" // L2CA_
+#include "stack/include/srvc_api.h" // tDIS_VALUE
#include "types/bluetooth/uuid.h"
#include "types/raw_address.h"
using bluetooth::Uuid;
using std::vector;
+namespace {
+
#ifndef BTA_HH_LE_RECONN
-#define BTA_HH_LE_RECONN TRUE
+constexpr bool kBTA_HH_LE_RECONN = true;
+#else
+constexpr bool kBTA_HH_LE_RECONN = false;
#endif
+} // namespace
+
#define BTA_HH_APP_ID_LE 0xff
#define BTA_HH_LE_PROTO_BOOT_MODE 0x00
#define BTA_HH_LE_PROTO_REPORT_MODE 0x01
#define BTA_LE_HID_RTP_UUID_MAX 5
+
+namespace {
+
+constexpr char kBtmLogTag[] = "HIDH";
+
+}
+
static const uint16_t bta_hh_uuid_to_rtp_type[BTA_LE_HID_RTP_UUID_MAX][2] = {
{GATT_UUID_HID_REPORT, BTA_HH_RPTT_INPUT},
{GATT_UUID_HID_BT_KB_INPUT, BTA_HH_RPTT_INPUT},
@@ -62,7 +77,6 @@
tBTA_HH_RPT_CACHE_ENTRY* p_rpt_cache,
uint8_t num_rpt);
-#if (BTA_HH_DEBUG == TRUE)
static const char* bta_hh_le_rpt_name[4] = {"UNKNOWN", "INPUT", "OUTPUT",
"FEATURE"};
@@ -142,7 +156,6 @@
}
}
-#endif
/*******************************************************************************
*
* Function bta_hh_le_enable
@@ -208,21 +221,6 @@
******************************************************************************/
void bta_hh_le_deregister(void) { BTA_GATTC_AppDeregister(bta_hh_cb.gatt_if); }
-/*******************************************************************************
- *
- * Function bta_hh_is_le_device
- *
- * Description Check to see if the remote device is a LE only device
- *
- * Parameters:
- *
- ******************************************************************************/
-bool bta_hh_is_le_device(tBTA_HH_DEV_CB* p_cb, const RawAddress& remote_bda) {
- p_cb->is_le_device = BTM_UseLeLink(remote_bda);
-
- return p_cb->is_le_device;
-}
-
/******************************************************************************
*
* Function bta_hh_le_get_le_cb
@@ -370,10 +368,8 @@
tBTA_HH_LE_RPT* p_rpt = p_head;
uint8_t i;
-#if (BTA_HH_DEBUG == TRUE)
APPL_TRACE_DEBUG("bta_hh_le_find_rpt_by_idtype: r_type: %d rpt_id: %d",
r_type, rpt_id);
-#endif
for (i = 0; i < BTA_HH_LE_RPT_MAX; i++, p_rpt++) {
if (p_rpt->in_use && p_rpt->rpt_id == rpt_id && r_type == p_rpt->rpt_type) {
@@ -516,9 +512,7 @@
if (p_rpt->rpt_type > BTA_HH_RPTT_FEATURE) /* invalid report type */
p_rpt->rpt_type = BTA_HH_RPTT_RESRV;
-#if (BTA_HH_DEBUG == TRUE)
APPL_TRACE_DEBUG("%s: report ID: %d", __func__, p_rpt->rpt_id);
-#endif
tBTA_HH_RPT_CACHE_ENTRY rpt_entry;
rpt_entry.rpt_id = p_rpt->rpt_id;
rpt_entry.rpt_type = p_rpt->rpt_type;
@@ -550,10 +544,8 @@
bool register_ba) {
tBTA_HH_LE_RPT* p_rpt = &p_dev_cb->hid_srvc.report[0];
-#if (BTA_HH_DEBUG == TRUE)
APPL_TRACE_DEBUG("%s: bta_hh_le_register_input_notif mode: %d", __func__,
proto_mode);
-#endif
for (int i = 0; i < BTA_HH_LE_RPT_MAX; i++, p_rpt++) {
if (p_rpt->rpt_type == BTA_HH_RPTT_INPUT) {
@@ -639,17 +631,13 @@
******************************************************************************/
static void bta_hh_le_open_cmpl(tBTA_HH_DEV_CB* p_cb) {
if (p_cb->disc_active == BTA_HH_LE_DISC_NONE) {
-#if (BTA_HH_DEBUG == TRUE)
bta_hh_le_hid_report_dbg(p_cb);
-#endif
bta_hh_le_register_input_notif(p_cb, p_cb->mode, true);
bta_hh_sm_execute(p_cb, BTA_HH_OPEN_CMPL_EVT, NULL);
-#if (BTA_HH_LE_RECONN == TRUE)
- if (p_cb->status == BTA_HH_OK) {
+ if (kBTA_HH_LE_RECONN && p_cb->status == BTA_HH_OK) {
bta_hh_le_add_dev_bg_conn(p_cb, true);
}
-#endif
}
}
@@ -850,12 +838,10 @@
p_dev_cb->mode = hs_data.rsp_data.proto_mode;
}
-#if (BTA_HH_DEBUG == TRUE)
APPL_TRACE_DEBUG("LE GET_PROTOCOL Mode = [%s]",
(hs_data.rsp_data.proto_mode == BTA_HH_PROTO_RPT_MODE)
? "Report"
: "Boot");
-#endif
p_dev_cb->w4_evt = 0;
(*bta_hh_cb.p_cback)(BTA_HH_GET_PROTO_EVT, (tBTA_HH*)&hs_data);
@@ -908,12 +894,10 @@
p_cb->disc_active &= ~BTA_HH_LE_DISC_DIS;
/* plug in the PnP info for this device */
if (p_dis_value->attr_mask & DIS_ATTR_PNP_ID_BIT) {
-#if (BTA_HH_DEBUG == TRUE)
APPL_TRACE_DEBUG(
"Plug in PnP info: product_id = %02x, vendor_id = %04x, version = %04x",
p_dis_value->pnp_id.product_id, p_dis_value->pnp_id.vendor_id,
p_dis_value->pnp_id.product_version);
-#endif
p_cb->dscp_info.product_id = p_dis_value->pnp_id.product_id;
p_cb->dscp_info.vendor_id = p_dis_value->pnp_id.vendor_id;
p_cb->dscp_info.version = p_dis_value->pnp_id.product_version;
@@ -962,17 +946,15 @@
UNUSED_ATTR tBT_TRANSPORT transport,
UNUSED_ATTR void* p_ref_data,
tBTM_STATUS result) {
- uint8_t idx = bta_hh_find_cb(*bd_addr);
- tBTA_HH_DEV_CB* p_dev_cb;
-
- if (idx != BTA_HH_IDX_INVALID)
- p_dev_cb = &bta_hh_cb.kdev[idx];
- else {
- APPL_TRACE_ERROR("unexpected encryption callback, ignore");
+ tBTA_HH_DEV_CB* p_dev_cb = bta_hh_get_cb(*bd_addr);
+ if (p_dev_cb == nullptr) {
+ LOG_ERROR("unexpected encryption callback, ignore");
return;
}
+
+ // TODO Collapse the duplicated status values
p_dev_cb->status = (result == BTM_SUCCESS) ? BTA_HH_OK : BTA_HH_ERR_SEC;
- p_dev_cb->reason = result;
+ p_dev_cb->btm_status = result;
bta_hh_sm_execute(p_dev_cb, BTA_HH_ENC_CMPL_EVT, NULL);
}
@@ -989,7 +971,7 @@
*
******************************************************************************/
void bta_hh_security_cmpl(tBTA_HH_DEV_CB* p_cb,
- UNUSED_ATTR tBTA_HH_DATA* p_buf) {
+ UNUSED_ATTR const tBTA_HH_DATA* p_buf) {
APPL_TRACE_DEBUG("%s", __func__);
if (p_cb->status == BTA_HH_OK) {
if (!p_cb->hid_srvc.in_use) {
@@ -1017,9 +999,11 @@
bta_hh_le_pri_service_discovery(p_cb);
}
} else {
- APPL_TRACE_ERROR("%s() - encryption failed; status=0x%04x, reason=0x%04x",
- __func__, p_cb->status, p_cb->reason);
- if (!(p_cb->status == BTA_HH_ERR_SEC && p_cb->reason == BTM_ERR_PROCESSING))
+ LOG_ERROR("Encryption failed status:%s btm_status:%s",
+ bta_hh_status_text(p_cb->status).c_str(),
+ btm_status_text(p_cb->btm_status).c_str());
+ if (!(p_cb->status == BTA_HH_ERR_SEC &&
+ p_cb->btm_status == BTM_ERR_PROCESSING))
bta_hh_le_api_disc_act(p_cb);
}
}
@@ -1033,7 +1017,8 @@
* Returns
*
******************************************************************************/
-void bta_hh_le_notify_enc_cmpl(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_buf) {
+void bta_hh_le_notify_enc_cmpl(tBTA_HH_DEV_CB* p_cb,
+ const tBTA_HH_DATA* p_buf) {
if (p_cb == NULL || !p_cb->security_pending || p_buf == NULL ||
p_buf->le_enc_cmpl.client_if != bta_hh_cb.gatt_if) {
return;
@@ -1072,7 +1057,7 @@
*
******************************************************************************/
void bta_hh_start_security(tBTA_HH_DEV_CB* p_cb,
- UNUSED_ATTR tBTA_HH_DATA* p_buf) {
+ UNUSED_ATTR const tBTA_HH_DATA* p_buf) {
if (BTM_SecIsSecurityPending(p_cb->addr)) {
/* if security collision happened, wait for encryption done */
p_cb->security_pending = true;
@@ -1108,9 +1093,9 @@
* Parameters:
*
******************************************************************************/
-void bta_hh_gatt_open(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_buf) {
- tBTA_GATTC_OPEN* p_data = &p_buf->le_open;
- uint8_t* p2;
+void bta_hh_gatt_open(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_buf) {
+ const tBTA_GATTC_OPEN* p_data = &p_buf->le_open;
+ const uint8_t* p2;
/* if received invalid callback data , ignore it */
if (p_cb == NULL || p_data == NULL) return;
@@ -1137,10 +1122,8 @@
BtaGattQueue::Clean(p_cb->conn_id);
-#if (BTA_HH_DEBUG == TRUE)
APPL_TRACE_DEBUG("hid_handle = %2x conn_id = %04x cb_index = %d",
p_cb->hid_handle, p_cb->conn_id, p_cb->index);
-#endif
bta_hh_sm_execute(p_cb, BTA_HH_START_ENC_EVT, NULL);
@@ -1156,28 +1139,36 @@
*
* Function bta_hh_le_close
*
- * Description This function process the GATT close event and post it as a
- * BTA HH internal event
- *
- * Parameters:
+ * Description This function converts the GATT close event and post it as a
+ * BTA HH internal event.
*
******************************************************************************/
-static void bta_hh_le_close(tBTA_GATTC_CLOSE* p_data) {
- tBTA_HH_DEV_CB* p_dev_cb = bta_hh_le_find_dev_cb_by_bda(p_data->remote_bda);
- uint16_t sm_event = BTA_HH_GATT_CLOSE_EVT;
-
- if (p_dev_cb != NULL) {
- tBTA_HH_LE_CLOSE* p_buf =
- (tBTA_HH_LE_CLOSE*)osi_malloc(sizeof(tBTA_HH_LE_CLOSE));
- p_buf->hdr.event = sm_event;
- p_buf->hdr.layer_specific = (uint16_t)p_dev_cb->hid_handle;
- p_buf->conn_id = p_data->conn_id;
- p_buf->reason = p_data->reason;
-
- p_dev_cb->conn_id = GATT_INVALID_CONN_ID;
- p_dev_cb->security_pending = false;
- bta_sys_sendmsg(p_buf);
+static void bta_hh_le_close(const tBTA_GATTC_CLOSE& gattc_data) {
+ tBTA_HH_DEV_CB* p_cb = bta_hh_le_find_dev_cb_by_bda(gattc_data.remote_bda);
+ if (p_cb == nullptr) {
+ LOG_WARN("Received close event with unknown device:%s",
+ PRIVATE_ADDRESS(gattc_data.remote_bda));
+ return;
}
+ p_cb->conn_id = GATT_INVALID_CONN_ID;
+ p_cb->security_pending = false;
+
+ post_on_bt_main([=]() {
+ const tBTA_HH_DATA data = {
+ .le_close =
+ {
+ .conn_id = gattc_data.conn_id,
+ .reason = gattc_data.reason,
+ .hdr =
+ {
+ .event = BTA_HH_GATT_CLOSE_EVT,
+ .layer_specific =
+ static_cast<uint16_t>(p_cb->hid_handle),
+ },
+ },
+ };
+ bta_hh_sm_execute(p_cb, BTA_HH_GATT_CLOSE_EVT, &data);
+ });
}
/*******************************************************************************
@@ -1273,10 +1264,8 @@
STREAM_TO_UINT16(p_dev_cb->hid_srvc.ext_rpt_ref, pp);
-#if (BTA_HH_DEBUG == TRUE)
APPL_TRACE_DEBUG("%s: External Report Reference UUID 0x%04x", __func__,
p_dev_cb->hid_srvc.ext_rpt_ref);
-#endif
}
static void read_report_ref_desc_cb(uint16_t conn_id, tGATT_STATUS status,
@@ -1488,11 +1477,9 @@
APPL_TRACE_DEBUG("%s: have HID service inst_id= %d", __func__,
p_dev_cb->hid_srvc.srvc_inst_id);
} else if (service.uuid == Uuid::From16Bit(UUID_SERVCLASS_SCAN_PARAM)) {
- p_dev_cb->scan_refresh_char_handle = 0;
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;
if (charac.properties & GATT_CHAR_PROP_BIT_NOTIFY)
p_dev_cb->scps_notify |= BTA_HH_LE_SCPS_NOTIFY_SPT;
@@ -1601,27 +1588,44 @@
* Returns void
*
******************************************************************************/
-void bta_hh_le_open_fail(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
- tBTA_HH_CONN conn_dat;
+void bta_hh_le_open_fail(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) {
+ const tBTA_HH_LE_CLOSE* le_close = &p_data->le_close;
+
+ BTM_LogHistory(kBtmLogTag, p_cb->addr, "Open failed",
+ base::StringPrintf(
+ "%s reason %s", (p_cb->is_le_device) ? "le" : "classic",
+ gatt_disconnection_reason_text(le_close->reason).c_str()));
+ LOG_WARN("Open failed for device:%s", PRIVATE_ADDRESS(p_cb->addr));
/* open failure in the middle of service discovery, clear all services */
if (p_cb->disc_active & BTA_HH_LE_DISC_HIDS) {
bta_hh_clear_service_cache(p_cb);
}
- p_cb->disc_active = BTA_HH_LE_DISC_NONE;
- /* Failure in opening connection or GATT discovery failure */
- conn_dat.handle = p_cb->hid_handle;
- conn_dat.bda = p_cb->addr;
- conn_dat.le_hid = true;
- conn_dat.scps_supported = p_cb->scps_supported;
- conn_dat.status = p_cb->status;
- if (p_data->le_close.reason != GATT_CONN_OK) {
- conn_dat.status = BTA_HH_ERR;
+ if (bluetooth::shim::is_gd_acl_enabled() && p_cb->is_le_device) {
+ LOG_DEBUG("gd_acl: Re-adding HID device to acceptlist");
+ // gd removes from bg list after failed connection
+ // Correct the cached state to allow re-add to acceptlist.
+ p_cb->in_bg_conn = false;
+ bta_hh_le_add_dev_bg_conn(p_cb, false);
}
+ p_cb->disc_active = BTA_HH_LE_DISC_NONE;
+ /* Failure in opening connection or GATT discovery failure */
+ tBTA_HH data = {
+ .conn =
+ {
+ .handle = p_cb->hid_handle,
+ .bda = p_cb->addr,
+ .le_hid = true,
+ .scps_supported = p_cb->scps_supported,
+ .status = (le_close->reason != GATT_CONN_OK) ? BTA_HH_ERR
+ : p_cb->status,
+ },
+ };
+
/* Report OPEN fail event */
- (*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH*)&conn_dat);
+ (*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, &data);
}
/*******************************************************************************
@@ -1634,8 +1638,13 @@
* Returns void
*
******************************************************************************/
-void bta_hh_gatt_close(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
- tBTA_HH_CBDATA disc_dat = {BTA_HH_OK, 0};
+void bta_hh_gatt_close(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) {
+ const tBTA_HH_LE_CLOSE* le_close = &p_data->le_close;
+
+ BTM_LogHistory(kBtmLogTag, p_cb->addr, "Closed",
+ base::StringPrintf(
+ "%s reason %s", (p_cb->is_le_device) ? "le" : "classic",
+ gatt_disconnection_reason_text(le_close->reason).c_str()));
/* deregister all notification */
bta_hh_le_deregister_input_notif(p_cb);
@@ -1644,23 +1653,46 @@
/* update total conn number */
bta_hh_cb.cnt_num--;
- disc_dat.handle = p_cb->hid_handle;
- disc_dat.status = p_cb->status;
-
+ tBTA_HH_CBDATA disc_dat = {
+ .status = p_cb->status,
+ .handle = p_cb->hid_handle,
+ };
(*bta_hh_cb.p_cback)(BTA_HH_CLOSE_EVT, (tBTA_HH*)&disc_dat);
/* if no connection is active and HH disable is signaled, disable service */
if (bta_hh_cb.cnt_num == 0 && bta_hh_cb.w4_disable) {
bta_hh_disc_cmpl();
- } else {
-#if (BTA_HH_LE_RECONN == TRUE)
- if (p_data->le_close.reason == HCI_ERR_CONNECTION_TOUT) {
- bta_hh_le_add_dev_bg_conn(p_cb, false);
- }
-#endif
- }
+ } else if (bluetooth::shim::is_gd_acl_enabled()) {
+ switch (le_close->reason) {
+ case GATT_CONN_FAILED_ESTABLISHMENT:
+ case GATT_CONN_TERMINATE_PEER_USER:
+ case GATT_CONN_TIMEOUT:
+ LOG_DEBUG(
+ "gd_acl: add into acceptlist for reconnection device:%s reason:%s",
+ PRIVATE_ADDRESS(p_cb->addr),
+ gatt_disconnection_reason_text(le_close->reason).c_str());
+ // gd removes from bg list after successful connection
+ // Correct the cached state to allow re-add to acceptlist.
+ p_cb->in_bg_conn = false;
+ bta_hh_le_add_dev_bg_conn(p_cb, false);
+ break;
- return;
+ case BTA_GATT_CONN_NONE:
+ case GATT_CONN_L2C_FAILURE:
+ case GATT_CONN_LMP_TIMEOUT:
+ case GATT_CONN_OK:
+ case GATT_CONN_TERMINATE_LOCAL_HOST:
+ default:
+ LOG_DEBUG(
+ "gd_acl: SKIP add into acceptlist for reconnection device:%s "
+ "reason:%s",
+ PRIVATE_ADDRESS(p_cb->addr),
+ gatt_disconnection_reason_text(le_close->reason).c_str());
+ break;
+ }
+ } else if (kBTA_HH_LE_RECONN && le_close->reason == HCI_ERR_CONNECTION_TOUT) {
+ bta_hh_le_add_dev_bg_conn(p_cb, false);
+ }
}
/*******************************************************************************
@@ -1793,9 +1825,7 @@
if (cb_evt == 0) return;
-#if (BTA_HH_DEBUG == TRUE)
APPL_TRACE_DEBUG("bta_hh_le_write_cmpl w4_evt: %d", p_dev_cb->w4_evt);
-#endif
const gatt::Characteristic* p_char =
BTA_GATTC_GetCharacteristic(conn_id, handle);
@@ -1886,7 +1916,7 @@
* Returns void
*
******************************************************************************/
-void bta_hh_le_write_dev_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+void bta_hh_le_write_dev_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) {
switch (p_data->api_sndcmd.t_type) {
case HID_TRANS_SET_PROTOCOL:
p_cb->w4_evt = BTA_HH_SET_PROTO_EVT;
@@ -1969,8 +1999,15 @@
/* add device into BG connection to accept remote initiated connection */
BTA_GATTC_Open(bta_hh_cb.gatt_if, p_cb->addr, false, false);
p_cb->in_bg_conn = true;
+ } else if (bluetooth::shim::is_gd_acl_enabled()) {
+ // Let the lower layers manage acceptlist and do not cache
+ // at the higher layer
+ p_cb->in_bg_conn = true;
+ BTA_GATTC_Open(bta_hh_cb.gatt_if, p_cb->addr, false, false);
+ } else {
+ LOG_WARN("Unable to add device into bg in_bg_conn:%u to_add:%u",
+ p_cb->in_bg_conn, to_add);
}
- return;
}
/*******************************************************************************
@@ -1985,7 +2022,7 @@
*
******************************************************************************/
uint8_t bta_hh_le_add_device(tBTA_HH_DEV_CB* p_cb,
- tBTA_HH_MAINT_DEV* p_dev_info) {
+ const tBTA_HH_MAINT_DEV* p_dev_info) {
p_cb->hid_handle = bta_hh_le_get_le_dev_hdl(p_cb->index);
if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE) return BTA_HH_INVALID_HANDLE;
bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle)] = p_cb->index;
@@ -2041,9 +2078,8 @@
******************************************************************************/
static void bta_hh_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
tBTA_HH_DEV_CB* p_dev_cb;
-#if (BTA_HH_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hh_gattc_callback event = %d", event);
-#endif
+ APPL_TRACE_DEBUG("bta_hh_gattc_callback event:%s",
+ gatt_client_event_text(event).c_str());
if (p_data == NULL) return;
switch (event) {
@@ -2061,7 +2097,7 @@
break;
case BTA_GATTC_CLOSE_EVT: /* 5 */
- bta_hh_le_close(&p_data->close);
+ bta_hh_le_close(p_data->close);
break;
case BTA_GATTC_SEARCH_CMPL_EVT: /* 6 */
diff --git a/bta/hh/bta_hh_main.cc b/bta/hh/bta_hh_main.cc
index be4adb7..f704fe6 100644
--- a/bta/hh/bta_hh_main.cc
+++ b/bta/hh/bta_hh_main.cc
@@ -43,7 +43,7 @@
static const char* bta_hh_state_code(tBTA_HH_STATE state_code);
static void bta_hh_better_state_machine(tBTA_HH_DEV_CB* p_cb, uint16_t event,
- tBTA_HH_DATA* p_data) {
+ const tBTA_HH_DATA* p_data) {
switch (p_cb->state) {
case BTA_HH_IDLE_ST:
switch (event) {
@@ -185,11 +185,11 @@
*
******************************************************************************/
void bta_hh_sm_execute(tBTA_HH_DEV_CB* p_cb, uint16_t event,
- tBTA_HH_DATA* p_data) {
+ const tBTA_HH_DATA* p_data) {
tBTA_HH cback_data;
tBTA_HH_EVT cback_event = 0;
tBTA_HH_STATE in_state;
- uint16_t debug_event = event;
+ tBTA_HH_INT_EVT debug_event = static_cast<tBTA_HH_INT_EVT>(event);
memset(&cback_data, 0, sizeof(tBTA_HH));
@@ -221,8 +221,8 @@
}
break;
case BTA_HH_API_WRITE_DEV_EVT:
- cback_event = (p_data->api_sndcmd.t_type - BTA_HH_FST_BTE_TRANS_EVT) +
- BTA_HH_FST_TRANS_CB_EVT;
+ cback_event = (p_data->api_sndcmd.t_type - HID_TRANS_GET_REPORT) +
+ BTA_HH_GET_RPT_EVT;
osi_free_and_reset((void**)&p_data->api_sndcmd.p_data);
if (p_data->api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL ||
p_data->api_sndcmd.t_type == HID_TRANS_SET_REPORT ||
@@ -282,15 +282,13 @@
bta_hh_better_state_machine(p_cb, event, p_data);
if (in_state != p_cb->state) {
- APPL_TRACE_DEBUG("HH State Change: [%s] -> [%s] after Event [%s]",
- bta_hh_state_code(in_state),
- bta_hh_state_code(p_cb->state),
- bta_hh_evt_code(debug_event));
+ LOG_DEBUG("HHID State Change: [%s] -> [%s] after Event [%s]",
+ bta_hh_state_code(in_state), bta_hh_state_code(p_cb->state),
+ bta_hh_evt_code(debug_event));
}
}
-
- return;
}
+
/*******************************************************************************
*
* Function bta_hh_hdl_event
@@ -301,7 +299,7 @@
* Returns void
*
******************************************************************************/
-bool bta_hh_hdl_event(BT_HDR* p_msg) {
+bool bta_hh_hdl_event(BT_HDR_RIGID* p_msg) {
uint8_t index = BTA_HH_IDX_INVALID;
tBTA_HH_DEV_CB* p_cb = NULL;
diff --git a/bta/hh/bta_hh_utils.cc b/bta/hh/bta_hh_utils.cc
index 1a467c1..1310b03 100644
--- a/bta/hh/bta_hh_utils.cc
+++ b/bta/hh/bta_hh_utils.cc
@@ -27,6 +27,7 @@
#include "device/include/interop.h"
#include "osi/include/osi.h"
#include "stack/include/acl_api.h"
+#include "stack/include/btm_client_interface.h"
#include "types/raw_address.h"
/* if SSR max latency is not defined by remote device, set the default value
@@ -36,19 +37,12 @@
/*****************************************************************************
* Constants
****************************************************************************/
-#define BTA_HH_KB_CTRL_MASK 0x11
-#define BTA_HH_KB_SHIFT_MASK 0x22
-#define BTA_HH_KB_ALT_MASK 0x44
-#define BTA_HH_KB_GUI_MASK 0x88
-#define BTA_HH_KB_CAPS_LOCK 0x39 /* caps lock */
-#define BTA_HH_KB_NUM_LOCK 0x53 /* num lock */
+namespace {
-#define BTA_HH_MAX_RPT_CHARS 8
+constexpr uint16_t kSsrMaxLatency = 18; /* slots * 0.625ms */
-static const uint8_t bta_hh_mod_key_mask[BTA_HH_MOD_MAX_KEY] = {
- BTA_HH_KB_CTRL_MASK, BTA_HH_KB_SHIFT_MASK, BTA_HH_KB_ALT_MASK,
- BTA_HH_KB_GUI_MASK};
+} // namespace
/*******************************************************************************
*
@@ -99,6 +93,14 @@
return xx;
}
+tBTA_HH_DEV_CB* bta_hh_get_cb(const RawAddress& bda) {
+ uint8_t idx = bta_hh_find_cb(bda);
+ if (idx == BTA_HH_IDX_INVALID) {
+ return nullptr;
+ }
+ return &bta_hh_cb.kdev[idx];
+}
+
/*******************************************************************************
*
* Function bta_hh_clean_up_kdev
@@ -165,7 +167,7 @@
******************************************************************************/
void bta_hh_add_device_to_list(tBTA_HH_DEV_CB* p_cb, uint8_t handle,
uint16_t attr_mask,
- tHID_DEV_DSCP_INFO* p_dscp_info,
+ const tHID_DEV_DSCP_INFO* p_dscp_info,
uint8_t sub_class, uint16_t ssr_max_latency,
uint16_t ssr_min_tout, uint8_t app_id) {
#if (BTA_HH_DEBUG == TRUE)
@@ -224,140 +226,6 @@
return false;
}
-/*******************************************************************************
- *
- * Function bta_hh_parse_keybd_rpt
- *
- * Description This utility function parse a boot mode keyboard report.
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hh_parse_keybd_rpt(tBTA_HH_BOOT_RPT* p_kb_data, uint8_t* p_report,
- uint16_t report_len) {
- tBTA_HH_KB_CB* p_kb = &bta_hh_cb.kb_cb;
- tBTA_HH_KEYBD_RPT* p_data = &p_kb_data->data_rpt.keybd_rpt;
-
- uint8_t this_char, ctl_shift;
- uint16_t xx, yy, key_idx = 0;
- uint8_t this_report[BTA_HH_MAX_RPT_CHARS];
-
-#if (BTA_HH_DEBUG == TRUE)
- APPL_TRACE_DEBUG("bta_hh_parse_keybd_rpt: (report=%p, report_len=%d) called",
- p_report, report_len);
-#endif
-
- if (report_len < 2) return;
-
- ctl_shift = *p_report++;
- report_len--;
-
- if (report_len > BTA_HH_MAX_RPT_CHARS) report_len = BTA_HH_MAX_RPT_CHARS;
-
- memset(this_report, 0, BTA_HH_MAX_RPT_CHARS);
- memset(p_data, 0, sizeof(tBTA_HH_KEYBD_RPT));
- memcpy(this_report, p_report, report_len);
-
- /* Take care of shift, control, GUI and alt, modifier keys */
- for (xx = 0; xx < BTA_HH_MOD_MAX_KEY; xx++) {
- if (ctl_shift & bta_hh_mod_key_mask[xx]) {
- APPL_TRACE_DEBUG("Mod Key[%02x] pressed", bta_hh_mod_key_mask[xx]);
- p_kb->mod_key[xx] = true;
- } else if (p_kb->mod_key[xx]) {
- p_kb->mod_key[xx] = false;
- }
- /* control key flag is set */
- p_data->mod_key[xx] = p_kb->mod_key[xx];
- }
-
- /***************************************************************************/
- /* First step is to remove all characters we saw in the last report */
- /***************************************************************************/
- for (xx = 0; xx < report_len; xx++) {
- for (yy = 0; yy < BTA_HH_MAX_RPT_CHARS; yy++) {
- if (this_report[xx] == p_kb->last_report[yy]) {
- this_report[xx] = 0;
- }
- }
- }
- /***************************************************************************/
- /* Now, process all the characters in the report, up to 6 keycodes */
- /***************************************************************************/
- for (xx = 0; xx < report_len; xx++) {
-#if (BTA_HH_DEBUG == TRUE)
- APPL_TRACE_DEBUG("this_char = %02x", this_report[xx]);
-#endif
- this_char = this_report[xx];
- if (this_char == 0) continue;
- /* take the key code as the report data */
- if (this_report[xx] == BTA_HH_KB_CAPS_LOCK)
- p_kb->caps_lock = p_kb->caps_lock ? false : true;
- else if (this_report[xx] == BTA_HH_KB_NUM_LOCK)
- p_kb->num_lock = p_kb->num_lock ? false : true;
- else
- p_data->this_char[key_idx++] = this_char;
-
-#if (BTA_HH_DEBUG == TRUE)
- APPL_TRACE_DEBUG("found keycode %02x ", this_report[xx]);
-#endif
- p_data->caps_lock = p_kb->caps_lock;
- p_data->num_lock = p_kb->num_lock;
- }
-
- memset(p_kb->last_report, 0, BTA_HH_MAX_RPT_CHARS);
- memcpy(p_kb->last_report, p_report, report_len);
-
- return;
-}
-
-/*******************************************************************************
- *
- * Function bta_hh_parse_mice_rpt
- *
- * Description This utility function parse a boot mode mouse report.
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_hh_parse_mice_rpt(tBTA_HH_BOOT_RPT* p_mice_data, uint8_t* p_report,
- uint16_t report_len) {
- tBTA_HH_MICE_RPT* p_data = &p_mice_data->data_rpt.mice_rpt;
-#if (BTA_HH_DEBUG == TRUE)
- uint8_t xx;
-
- APPL_TRACE_DEBUG(
- "bta_hh_parse_mice_rpt: bta_keybd_rpt_rcvd(report=%p, \
- report_len=%d) called",
- p_report, report_len);
-#endif
-
- if (report_len < 3) return;
-
- if (report_len > BTA_HH_MAX_RPT_CHARS) report_len = BTA_HH_MAX_RPT_CHARS;
-
-#if (BTA_HH_DEBUG == TRUE)
- for (xx = 0; xx < report_len; xx++) {
- APPL_TRACE_DEBUG("this_char = %02x", p_report[xx]);
- }
-#endif
-
- /* only first bytes lower 3 bits valid */
- p_data->mouse_button = (p_report[0] & 0x07);
-
- /* x displacement */
- p_data->delta_x = p_report[1];
-
- /* y displacement */
- p_data->delta_y = p_report[2];
-
-#if (BTA_HH_DEBUG == TRUE)
- APPL_TRACE_DEBUG("mice button: 0x%2x", p_data->mouse_button);
- APPL_TRACE_DEBUG("mice move: x = %d y = %d", p_data->delta_x,
- p_data->delta_y);
-#endif
-
- return;
-}
/*******************************************************************************
*
@@ -371,52 +239,52 @@
tBTA_HH_STATUS bta_hh_read_ssr_param(const RawAddress& bd_addr,
uint16_t* p_max_ssr_lat,
uint16_t* p_min_ssr_tout) {
- tBTA_HH_STATUS status = BTA_HH_ERR;
- tBTA_HH_CB* p_cb = &bta_hh_cb;
- uint8_t i;
- uint16_t ssr_max_latency;
- for (i = 0; i < BTA_HH_MAX_KNOWN; i++) {
- if (p_cb->kdev[i].addr == bd_addr) {
- /* if remote device does not have HIDSSRHostMaxLatency attribute in SDP,
- set SSR max latency default value here. */
- if (p_cb->kdev[i].dscp_info.ssr_max_latency == HID_SSR_PARAM_INVALID) {
- /* The default is calculated as half of link supervision timeout.*/
-
- BTM_GetLinkSuperTout(p_cb->kdev[i].addr, &ssr_max_latency);
- ssr_max_latency = BTA_HH_GET_DEF_SSR_MAX_LAT(ssr_max_latency);
-
- /* per 1.1 spec, if the newly calculated max latency is greater than
- BTA_HH_SSR_MAX_LATENCY_DEF which is 500ms, use
- BTA_HH_SSR_MAX_LATENCY_DEF */
- if (ssr_max_latency > BTA_HH_SSR_MAX_LATENCY_DEF)
- ssr_max_latency = BTA_HH_SSR_MAX_LATENCY_DEF;
-
- char remote_name[BTM_MAX_REM_BD_NAME_LEN] = "";
- if (btif_storage_get_stored_remote_name(bd_addr, remote_name)) {
- if (interop_match_name(INTEROP_HID_HOST_LIMIT_SNIFF_INTERVAL,
- remote_name)) {
- if (ssr_max_latency > 18 /* slots * 0.625ms */) {
- ssr_max_latency = 18;
- }
- }
- }
-
- *p_max_ssr_lat = ssr_max_latency;
- } else
- *p_max_ssr_lat = p_cb->kdev[i].dscp_info.ssr_max_latency;
-
- if (p_cb->kdev[i].dscp_info.ssr_min_tout == HID_SSR_PARAM_INVALID)
- *p_min_ssr_tout = BTA_HH_SSR_MIN_TOUT_DEF;
- else
- *p_min_ssr_tout = p_cb->kdev[i].dscp_info.ssr_min_tout;
-
- status = BTA_HH_OK;
-
- break;
- }
+ tBTA_HH_DEV_CB* p_cb = bta_hh_get_cb(bd_addr);
+ if (p_cb == nullptr) {
+ LOG_WARN("Unable to find device:%s", PRIVATE_ADDRESS(bd_addr));
+ return BTA_HH_ERR;
}
- return status;
+ /* if remote device does not have HIDSSRHostMaxLatency attribute in SDP,
+ set SSR max latency default value here. */
+ if (p_cb->dscp_info.ssr_max_latency == HID_SSR_PARAM_INVALID) {
+ /* The default is calculated as half of link supervision timeout.*/
+
+ uint16_t ssr_max_latency;
+ if (get_btm_client_interface().link_controller.BTM_GetLinkSuperTout(
+ p_cb->addr, &ssr_max_latency) != BTM_SUCCESS) {
+ LOG_WARN("Unable to get supervision timeout for peer:%s",
+ PRIVATE_ADDRESS(p_cb->addr));
+ return BTA_HH_ERR;
+ }
+ ssr_max_latency = BTA_HH_GET_DEF_SSR_MAX_LAT(ssr_max_latency);
+
+ /* per 1.1 spec, if the newly calculated max latency is greater than
+ BTA_HH_SSR_MAX_LATENCY_DEF which is 500ms, use
+ BTA_HH_SSR_MAX_LATENCY_DEF */
+ if (ssr_max_latency > BTA_HH_SSR_MAX_LATENCY_DEF)
+ ssr_max_latency = BTA_HH_SSR_MAX_LATENCY_DEF;
+
+ char remote_name[BTM_MAX_REM_BD_NAME_LEN] = "";
+ if (btif_storage_get_stored_remote_name(bd_addr, remote_name)) {
+ if (interop_match_name(INTEROP_HID_HOST_LIMIT_SNIFF_INTERVAL,
+ remote_name)) {
+ if (ssr_max_latency > kSsrMaxLatency /* slots * 0.625ms */) {
+ ssr_max_latency = kSsrMaxLatency;
+ }
+ }
+ }
+
+ *p_max_ssr_lat = ssr_max_latency;
+ } else
+ *p_max_ssr_lat = p_cb->dscp_info.ssr_max_latency;
+
+ if (p_cb->dscp_info.ssr_min_tout == HID_SSR_PARAM_INVALID)
+ *p_min_ssr_tout = BTA_HH_SSR_MIN_TOUT_DEF;
+ else
+ *p_min_ssr_tout = p_cb->dscp_info.ssr_min_tout;
+
+ return BTA_HH_OK;
}
/*******************************************************************************
diff --git a/bta/include/bta_api.h b/bta/include/bta_api.h
index 6289546..3007479 100644
--- a/bta/include/bta_api.h
+++ b/bta/include/bta_api.h
@@ -46,14 +46,14 @@
****************************************************************************/
/* Status Return Value */
-#define BTA_SUCCESS 0 /* Successful operation. */
-#define BTA_FAILURE 1 /* Generic failure. */
-#define BTA_PENDING 2 /* API cannot be completed right now */
-#define BTA_BUSY 3
-#define BTA_NO_RESOURCES 4
-#define BTA_WRONG_MODE 5
-
-typedef uint8_t tBTA_STATUS;
+typedef enum : uint8_t {
+ BTA_SUCCESS = 0, /* Successful operation. */
+ BTA_FAILURE = 1, /* Generic failure. */
+ BTA_PENDING = 2, /* API cannot be completed right now */
+ BTA_BUSY = 3,
+ BTA_NO_RESOURCES = 4,
+ BTA_WRONG_MODE = 5,
+} tBTA_STATUS;
/*
* Service ID
@@ -627,12 +627,6 @@
/* Device Identification (DI) data structure
*/
-/* Used to set the DI record */
-typedef tSDP_DI_RECORD tBTA_DI_RECORD;
-/* Used to get the DI record */
-typedef tSDP_DI_GET_RECORD tBTA_DI_GET_RECORD;
-/* SDP discovery database */
-typedef tSDP_DISCOVERY_DB tBTA_DISCOVERY_DB;
#ifndef BTA_DI_NUM_MAX
#define BTA_DI_NUM_MAX 3
@@ -910,7 +904,7 @@
* Returns BTA_SUCCESS if record set sucessfully, otherwise error code.
*
******************************************************************************/
-extern tBTA_STATUS BTA_DmSetLocalDiRecord(tBTA_DI_RECORD* p_device_info,
+extern tBTA_STATUS BTA_DmSetLocalDiRecord(tSDP_DI_RECORD* p_device_info,
uint32_t* p_handle);
/*******************************************************************************
diff --git a/bta/include/bta_av_api.h b/bta/include/bta_av_api.h
index 808a1a2..4591bba 100644
--- a/bta/include/bta_av_api.h
+++ b/bta/include/bta_av_api.h
@@ -486,7 +486,7 @@
* Returns void
*
******************************************************************************/
-void BTA_AvDisconnect(const RawAddress& bd_addr);
+void BTA_AvDisconnect(tBTA_AV_HNDL handle);
/*******************************************************************************
*
diff --git a/bta/include/bta_gatt_api.h b/bta/include/bta_gatt_api.h
index 503026a..7027741 100644
--- a/bta/include/bta_gatt_api.h
+++ b/bta/include/bta_gatt_api.h
@@ -70,44 +70,33 @@
BTA_GATTC_CONN_UPDATE_EVT = 26, /* Connection parameters update event */
} tBTA_GATTC_EVT;
-inline std::string GattClientEventText(tBTA_GATTC_EVT event) {
+#define CASE_RETURN_TEXT(code) \
+ case code: \
+ return #code
+
+inline std::string gatt_client_event_text(const tBTA_GATTC_EVT& event) {
switch (event) {
- case BTA_GATTC_DEREG_EVT:
- return std::string("deregistered");
- case BTA_GATTC_OPEN_EVT:
- return std::string("opened");
- case BTA_GATTC_CLOSE_EVT:
- return std::string("closed");
- case BTA_GATTC_SEARCH_CMPL_EVT:
- return std::string("discovery completed");
- case BTA_GATTC_SEARCH_RES_EVT:
- return std::string("discovery result");
- case BTA_GATTC_SRVC_DISC_DONE_EVT:
- return std::string("discovery done");
- case BTA_GATTC_NOTIF_EVT:
- return std::string("attribute notification");
- case BTA_GATTC_EXEC_EVT:
- return std::string("execute write completed");
- case BTA_GATTC_ACL_EVT:
- return std::string("ACL up event");
- case BTA_GATTC_CANCEL_OPEN_EVT:
- return std::string("cancel open event");
- case BTA_GATTC_SRVC_CHG_EVT:
- return std::string("service changed");
- case BTA_GATTC_ENC_CMPL_CB_EVT:
- return std::string("encryption complete");
- case BTA_GATTC_CFG_MTU_EVT:
- return std::string("configure MTU complete");
- case BTA_GATTC_CONGEST_EVT:
- return std::string("congestion");
- case BTA_GATTC_PHY_UPDATE_EVT:
- return std::string("PHY change");
- case BTA_GATTC_CONN_UPDATE_EVT:
- return std::string("connection parameters update");
+ CASE_RETURN_TEXT(BTA_GATTC_DEREG_EVT);
+ CASE_RETURN_TEXT(BTA_GATTC_OPEN_EVT);
+ CASE_RETURN_TEXT(BTA_GATTC_CLOSE_EVT);
+ CASE_RETURN_TEXT(BTA_GATTC_SEARCH_CMPL_EVT);
+ CASE_RETURN_TEXT(BTA_GATTC_SEARCH_RES_EVT);
+ CASE_RETURN_TEXT(BTA_GATTC_SRVC_DISC_DONE_EVT);
+ CASE_RETURN_TEXT(BTA_GATTC_NOTIF_EVT);
+ CASE_RETURN_TEXT(BTA_GATTC_EXEC_EVT);
+ CASE_RETURN_TEXT(BTA_GATTC_ACL_EVT);
+ CASE_RETURN_TEXT(BTA_GATTC_CANCEL_OPEN_EVT);
+ CASE_RETURN_TEXT(BTA_GATTC_SRVC_CHG_EVT);
+ CASE_RETURN_TEXT(BTA_GATTC_ENC_CMPL_CB_EVT);
+ CASE_RETURN_TEXT(BTA_GATTC_CFG_MTU_EVT);
+ CASE_RETURN_TEXT(BTA_GATTC_CONGEST_EVT);
+ CASE_RETURN_TEXT(BTA_GATTC_PHY_UPDATE_EVT);
+ CASE_RETURN_TEXT(BTA_GATTC_CONN_UPDATE_EVT);
default:
- return std::string("unknown");
+ return std::string("UNKNOWN[%hhu]", event);
}
}
+#undef CASE_RETURN_TEXT
typedef struct {
uint16_t unit; /* as UUIUD defined by SIG */
@@ -130,14 +119,9 @@
uint8_t* p_value;
} tBTA_GATT_UNFMT;
-#define BTA_GATT_CONN_NONE 0x0101 /* 0x0101 no connection to cancel */
-typedef uint16_t tBTA_GATT_REASON;
-
-#define BTA_GATTC_MULTI_MAX GATT_MAX_READ_MULTI_HANDLES
-
typedef struct {
uint8_t num_attr;
- uint16_t handles[BTA_GATTC_MULTI_MAX];
+ uint16_t handles[GATT_MAX_READ_MULTI_HANDLES];
} tBTA_GATTC_MULTI;
/* callback data structure */
@@ -195,8 +179,7 @@
tGATT_STATUS status;
tGATT_IF client_if;
RawAddress remote_bda;
- tBTA_GATT_REASON reason; /* disconnect reason code, not useful when connect
- event is reported */
+ tGATT_DISCONN_REASON reason;
} tBTA_GATTC_CLOSE;
typedef struct {
diff --git a/bta/jv/bta_jv_act.cc b/bta/jv/bta_jv_act.cc
index c122441..13fa899 100644
--- a/bta/jv/bta_jv_act.cc
+++ b/bta/jv/bta_jv_act.cc
@@ -719,11 +719,11 @@
* Returns void
*
******************************************************************************/
-static void bta_jv_start_discovery_cback(uint16_t result, void* user_data) {
+static void bta_jv_start_discovery_cback(tSDP_RESULT result, void* user_data) {
tBTA_JV_STATUS status;
uint32_t* p_rfcomm_slot_id = static_cast<uint32_t*>(user_data);
- VLOG(2) << __func__ << ": res=" << loghex(result);
+ VLOG(2) << __func__ << ": res=" << loghex(static_cast<uint16_t>(result));
bta_jv_cb.sdp_active = BTA_JV_SDP_ACT_NONE;
if (bta_jv_cb.p_dm_cback) {
diff --git a/bta/pan/bta_pan_act.cc b/bta/pan/bta_pan_act.cc
index 5e64405..3543ea1 100644
--- a/bta/pan/bta_pan_act.cc
+++ b/bta/pan/bta_pan_act.cc
@@ -145,7 +145,7 @@
if (p_scb == NULL) return;
if (result == PAN_TX_FLOW_ON) {
- BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
p_buf->layer_specific = handle;
p_buf->event = BTA_PAN_BNEP_FLOW_ENABLE_EVT;
bta_sys_sendmsg(p_buf);
@@ -196,7 +196,7 @@
((tBTA_PAN_DATA_PARAMS*)p_new_buf)->forward = forward;
fixed_queue_enqueue(p_scb->data_queue, p_new_buf);
- BT_HDR* p_event = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ BT_HDR_RIGID* p_event = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
p_event->layer_specific = handle;
p_event->event = BTA_PAN_RX_FROM_BNEP_READY_EVT;
bta_sys_sendmsg(p_event);
diff --git a/bta/pan/bta_pan_api.cc b/bta/pan/bta_pan_api.cc
index 0959926..a119125 100644
--- a/bta/pan/bta_pan_api.cc
+++ b/bta/pan/bta_pan_api.cc
@@ -77,7 +77,7 @@
*
******************************************************************************/
void BTA_PanDisable(void) {
- BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
bta_sys_deregister(BTA_ID_PAN);
p_buf->event = BTA_PAN_API_DISABLE_EVT;
@@ -157,7 +157,7 @@
*
******************************************************************************/
void BTA_PanClose(uint16_t handle) {
- BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
p_buf->event = BTA_PAN_API_CLOSE_EVT;
p_buf->layer_specific = handle;
diff --git a/bta/pan/bta_pan_ci.cc b/bta/pan/bta_pan_ci.cc
index 4a5dfd5..4365fe7 100644
--- a/bta/pan/bta_pan_ci.cc
+++ b/bta/pan/bta_pan_ci.cc
@@ -67,7 +67,7 @@
*
******************************************************************************/
void bta_pan_ci_rx_ready(uint16_t handle) {
- BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
p_buf->layer_specific = handle;
p_buf->event = BTA_PAN_CI_RX_READY_EVT;
diff --git a/bta/pan/bta_pan_int.h b/bta/pan/bta_pan_int.h
index fbc0dc4..5227071 100644
--- a/bta/pan/bta_pan_int.h
+++ b/bta/pan/bta_pan_int.h
@@ -67,13 +67,13 @@
/* data type for BTA_PAN_API_ENABLE_EVT */
typedef struct {
- BT_HDR hdr; /* Event header */
+ BT_HDR_RIGID hdr; /* Event header */
tBTA_PAN_CBACK* p_cback; /* PAN callback function */
} tBTA_PAN_API_ENABLE;
/* data type for BTA_PAN_API_REG_ROLE_EVT */
typedef struct {
- BT_HDR hdr; /* Event header */
+ BT_HDR_RIGID hdr; /* Event header */
char user_name[BTA_SERVICE_NAME_LEN + 1]; /* Service name */
char nap_name[BTA_SERVICE_NAME_LEN + 1]; /* Service name */
tBTA_PAN_ROLE role;
@@ -83,7 +83,7 @@
/* data type for BTA_PAN_API_OPEN_EVT */
typedef struct {
- BT_HDR hdr; /* Event header */
+ BT_HDR_RIGID hdr; /* Event header */
tBTA_PAN_ROLE local_role; /* local role */
tBTA_PAN_ROLE peer_role; /* peer role */
RawAddress bd_addr; /* peer bdaddr */
@@ -91,20 +91,20 @@
/* data type for BTA_PAN_CI_TX_FLOW_EVT */
typedef struct {
- BT_HDR hdr; /* Event header */
+ BT_HDR_RIGID hdr; /* Event header */
bool enable; /* Flow control setting */
} tBTA_PAN_CI_TX_FLOW;
/* data type for BTA_PAN_CONN_OPEN_EVT */
typedef struct {
- BT_HDR hdr; /* Event header */
+ BT_HDR_RIGID hdr; /* Event header */
tPAN_RESULT result;
} tBTA_PAN_CONN;
/* union of all data types */
typedef union {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
tBTA_PAN_API_ENABLE api_enable;
tBTA_PAN_API_SET_ROLE api_set_role;
tBTA_PAN_API_OPEN api_open;
@@ -141,7 +141,7 @@
/* pan data param */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
RawAddress src;
RawAddress dst;
uint16_t protocol;
@@ -164,7 +164,7 @@
extern void bta_pan_scb_dealloc(tBTA_PAN_SCB* p_scb);
extern uint8_t bta_pan_scb_to_idx(tBTA_PAN_SCB* p_scb);
extern tBTA_PAN_SCB* bta_pan_scb_by_handle(uint16_t handle);
-extern bool bta_pan_hdl_event(BT_HDR* p_msg);
+extern bool bta_pan_hdl_event(BT_HDR_RIGID* p_msg);
/* action functions */
extern void bta_pan_enable(tBTA_PAN_DATA* p_data);
diff --git a/bta/pan/bta_pan_main.cc b/bta/pan/bta_pan_main.cc
index 76869f8..779a8a2 100644
--- a/bta/pan/bta_pan_main.cc
+++ b/bta/pan/bta_pan_main.cc
@@ -307,7 +307,7 @@
* Returns void
*
******************************************************************************/
-bool bta_pan_hdl_event(BT_HDR* p_msg) {
+bool bta_pan_hdl_event(BT_HDR_RIGID* p_msg) {
tBTA_PAN_SCB* p_scb;
bool freebuf = true;
diff --git a/bta/sdp/bta_sdp_act.cc b/bta/sdp/bta_sdp_act.cc
index 9444cdf..296f84f 100644
--- a/bta/sdp/bta_sdp_act.cc
+++ b/bta/sdp/bta_sdp_act.cc
@@ -367,7 +367,7 @@
}
/** Callback from btm after search is completed */
-static void bta_sdp_search_cback(uint16_t result, void* user_data) {
+static void bta_sdp_search_cback(tSDP_RESULT result, void* user_data) {
tBTA_SDP_STATUS status = BTA_SDP_FAILURE;
int count = 0;
APPL_TRACE_DEBUG("%s() - res: 0x%x", __func__, result);
diff --git a/bta/sys/bta_sys.h b/bta/sys/bta_sys.h
index 445e8b2..fa3c03a 100644
--- a/bta/sys/bta_sys.h
+++ b/bta/sys/bta_sys.h
@@ -41,7 +41,10 @@
typedef bool(tBTA_SYS_VS_EVT_HDLR)(uint16_t evt, void* p);
/* event handler function type */
-typedef bool(tBTA_SYS_EVT_HDLR)(BT_HDR* p_msg);
+typedef bool(tBTA_SYS_EVT_HDLR)(BT_HDR_RIGID* p_msg);
+static_assert(
+ sizeof(BT_HDR) == sizeof(BT_HDR_RIGID),
+ "Rigid replacement should be same size struct with flexible member");
/* disable function type */
typedef void(tBTA_SYS_DISABLE)(void);
@@ -97,19 +100,21 @@
inline std::string BtaIdSysText(tBTA_SYS_ID sys_id) {
switch (sys_id) {
- case BTA_ID_DM_SEARCH:
+ case BTA_ID_DM_SEARCH: // 2
return std::string("Scanner");
- case BTA_ID_AG:
+ case BTA_ID_AG: // 5
return std::string("Audio gateway");
- case BTA_ID_PAN:
+ case BTA_ID_PAN: // 14
return std::string("PAN Personal area network");
- case BTA_ID_AV:
+ case BTA_ID_AV: // 18
return std::string("Advanced audio/video");
- case BTA_ID_HD:
+ case BTA_ID_HD: // 20
return std::string("HID Human interface device");
- case BTA_ID_GATTC:
+ case BTA_ID_HH: // 23
+ return std::string("HID Human interface host");
+ case BTA_ID_GATTC: // 31
return std::string("GATT client");
- case BTA_ID_GATTS:
+ case BTA_ID_GATTS: // 32
return std::string("GATT server");
default:
return std::string("Unknown");
diff --git a/bta/sys/bta_sys_main.cc b/bta/sys/bta_sys_main.cc
index 178d03a..9448606 100644
--- a/bta/sys/bta_sys_main.cc
+++ b/bta/sys/bta_sys_main.cc
@@ -82,7 +82,7 @@
* Returns void
*
******************************************************************************/
-static void bta_sys_event(BT_HDR* p_msg) {
+static void bta_sys_event(BT_HDR_RIGID* p_msg) {
uint8_t id;
bool freebuf = true;
@@ -163,7 +163,8 @@
******************************************************************************/
void bta_sys_sendmsg(void* p_msg) {
if (do_in_main_thread(
- FROM_HERE, base::Bind(&bta_sys_event, static_cast<BT_HDR*>(p_msg))) !=
+ FROM_HERE,
+ base::Bind(&bta_sys_event, static_cast<BT_HDR_RIGID*>(p_msg))) !=
BT_STATUS_SUCCESS) {
LOG(ERROR) << __func__ << ": do_in_main_thread failed";
}
@@ -171,7 +172,8 @@
void bta_sys_sendmsg_delayed(void* p_msg, const base::TimeDelta& delay) {
if (do_in_main_thread_delayed(
- FROM_HERE, base::Bind(&bta_sys_event, static_cast<BT_HDR*>(p_msg)),
+ FROM_HERE,
+ base::Bind(&bta_sys_event, static_cast<BT_HDR_RIGID*>(p_msg)),
delay) != BT_STATUS_SUCCESS) {
LOG(ERROR) << __func__ << ": do_in_main_thread_delayed failed";
}
@@ -189,7 +191,7 @@
******************************************************************************/
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));
+ BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
p_buf->event = event;
p_buf->layer_specific = layer_specific;
diff --git a/bta/test/bta_dm_test.cc b/bta/test/bta_dm_test.cc
index e95b2b2..d440a5c 100644
--- a/bta/test/bta_dm_test.cc
+++ b/bta/test/bta_dm_test.cc
@@ -26,23 +26,11 @@
std::map<std::string, int> mock_function_count_map;
-bt_status_t do_in_main_thread_delayed(const base::Location& from_here,
- base::OnceClosure task,
- const base::TimeDelta& delay) {
- return BT_STATUS_SUCCESS;
-}
-
-bt_status_t do_in_main_thread(const base::Location& from_here,
- base::OnceClosure task) {
- return BT_STATUS_SUCCESS;
-}
-
void LogMsg(uint32_t trace_set_mask, const char* fmt_str, ...) {}
namespace base {
class MessageLoop;
} // namespace base
-bluetooth::common::MessageLoopThread* get_main_thread() { return nullptr; }
namespace {
constexpr uint8_t kUnusedTimer = BTA_ID_MAX;
diff --git a/bta/test/bta_gatt_test.cc b/bta/test/bta_gatt_test.cc
new file mode 100644
index 0000000..a95ae46
--- /dev/null
+++ b/bta/test/bta_gatt_test.cc
@@ -0,0 +1,295 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.h>
+
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <string>
+
+#include "bta/gatt/bta_gattc_int.h"
+#include "common/message_loop_thread.h"
+#include "stack/gatt/gatt_int.h"
+
+// TODO put this in common place
+extern std::map<std::string, int> mock_function_count_map;
+
+namespace param {
+struct {
+ uint16_t conn_id;
+ tGATT_STATUS status;
+ uint16_t handle;
+ uint16_t len;
+ uint8_t* value;
+ void* data;
+} bta_gatt_read_complete_callback;
+} // namespace param
+void bta_gatt_read_complete_callback(uint16_t conn_id, tGATT_STATUS status,
+ uint16_t handle, uint16_t len,
+ uint8_t* value, void* data) {
+ param::bta_gatt_read_complete_callback.conn_id = conn_id;
+ param::bta_gatt_read_complete_callback.status = status;
+ param::bta_gatt_read_complete_callback.handle = handle;
+ param::bta_gatt_read_complete_callback.len = len;
+ param::bta_gatt_read_complete_callback.value = value;
+ param::bta_gatt_read_complete_callback.data = data;
+}
+
+namespace param {
+struct {
+ uint16_t conn_id;
+ tGATT_STATUS status;
+ uint16_t handle;
+ void* data;
+} bta_gatt_write_complete_callback;
+} // namespace param
+
+void bta_gatt_write_complete_callback(uint16_t conn_id, tGATT_STATUS status,
+ uint16_t handle, void* data) {
+ param::bta_gatt_write_complete_callback.conn_id = conn_id;
+ param::bta_gatt_write_complete_callback.status = status;
+ param::bta_gatt_write_complete_callback.handle = handle;
+ param::bta_gatt_write_complete_callback.data = data;
+}
+
+namespace param {
+struct {
+ uint16_t conn_id;
+ tGATT_STATUS status;
+ void* data;
+} bta_gatt_configure_mtu_complete_callback;
+} // namespace param
+
+void bta_gatt_configure_mtu_complete_callback(uint16_t conn_id,
+ tGATT_STATUS status, void* data) {
+ param::bta_gatt_configure_mtu_complete_callback.conn_id = conn_id;
+ param::bta_gatt_configure_mtu_complete_callback.status = status;
+ param::bta_gatt_configure_mtu_complete_callback.data = data;
+}
+
+namespace param {
+struct {
+ tBTA_GATTC_EVT event;
+ tBTA_GATTC* p_data;
+} bta_gattc_event_complete_callback;
+} // namespace param
+
+void bta_gattc_event_complete_callback(tBTA_GATTC_EVT event,
+ tBTA_GATTC* p_data) {
+ param::bta_gattc_event_complete_callback.event = event;
+ param::bta_gattc_event_complete_callback.p_data = p_data;
+}
+
+class BtaGattTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ mock_function_count_map.clear();
+ param::bta_gatt_read_complete_callback = {};
+ param::bta_gatt_write_complete_callback = {};
+ param::bta_gatt_configure_mtu_complete_callback = {};
+ param::bta_gattc_event_complete_callback = {};
+ }
+
+ void TearDown() override {}
+
+ tBTA_GATTC_RCB app_control_block = {
+ .p_cback = bta_gattc_event_complete_callback,
+ };
+
+ tGATT_CL_COMPLETE gatt_cl_complete = {
+ .att_value =
+ {
+ .conn_id = 1,
+ .handle = 2,
+ .offset = 3,
+ .auth_req = GATT_AUTH_REQ_NONE,
+ .value = {10, 11, 12, 13},
+ .len = 4, // length of value above
+ },
+ };
+
+ tBTA_GATTC_SERV service_control_block = {
+ .mtu = 456,
+ };
+ tBTA_GATTC_DATA command_queue;
+
+ tBTA_GATTC_CLCB client_channel_control_block = {
+ .p_q_cmd = &command_queue,
+ .p_rcb = &app_control_block,
+ .p_srcb = &service_control_block,
+ .bta_conn_id = 456,
+ };
+};
+
+TEST_F(BtaGattTest, bta_gattc_op_cmpl_read) {
+ command_queue = {
+ .api_read = // tBTA_GATTC_API_READ
+ {
+ .hdr =
+ {
+ .event = BTA_GATTC_API_READ_EVT,
+ },
+ .handle = 123,
+ .read_cb = bta_gatt_read_complete_callback,
+ .read_cb_data = static_cast<void*>(this),
+ },
+ };
+
+ client_channel_control_block.p_q_cmd = &command_queue;
+
+ tBTA_GATTC_DATA data = {
+ .op_cmpl =
+ {
+ .op_code = GATTC_OPTYPE_READ,
+ .status = GATT_OUT_OF_RANGE,
+ .p_cmpl = &gatt_cl_complete,
+ },
+ };
+
+ bta_gattc_op_cmpl(&client_channel_control_block, &data);
+ ASSERT_EQ(1, mock_function_count_map["osi_free_and_reset"]);
+ ASSERT_EQ(456, param::bta_gatt_read_complete_callback.conn_id);
+ ASSERT_EQ(GATT_OUT_OF_RANGE, param::bta_gatt_read_complete_callback.status);
+ ASSERT_EQ(123, param::bta_gatt_read_complete_callback.handle);
+ ASSERT_EQ(4, param::bta_gatt_read_complete_callback.len);
+ ASSERT_EQ(10, param::bta_gatt_read_complete_callback.value[0]);
+ ASSERT_EQ(this, param::bta_gatt_read_complete_callback.data);
+}
+
+TEST_F(BtaGattTest, bta_gattc_op_cmpl_write) {
+ command_queue = {
+ .api_write = // tBTA_GATTC_API_WRITE
+ {
+ .hdr =
+ {
+ .event = BTA_GATTC_API_WRITE_EVT,
+ },
+ .handle = 123,
+ .write_cb = bta_gatt_write_complete_callback,
+ .write_cb_data = static_cast<void*>(this),
+ },
+ };
+
+ client_channel_control_block.p_q_cmd = &command_queue;
+
+ tBTA_GATTC_DATA data = {
+ .op_cmpl =
+ {
+ .op_code = GATTC_OPTYPE_WRITE,
+ .status = GATT_OUT_OF_RANGE,
+ .p_cmpl = &gatt_cl_complete,
+ },
+ };
+
+ bta_gattc_op_cmpl(&client_channel_control_block, &data);
+ ASSERT_EQ(1, mock_function_count_map["osi_free_and_reset"]);
+ ASSERT_EQ(456, param::bta_gatt_write_complete_callback.conn_id);
+ ASSERT_EQ(2, param::bta_gatt_write_complete_callback.handle);
+ ASSERT_EQ(GATT_OUT_OF_RANGE, param::bta_gatt_write_complete_callback.status);
+ ASSERT_EQ(this, param::bta_gatt_write_complete_callback.data);
+}
+
+TEST_F(BtaGattTest, bta_gattc_op_cmpl_config) {
+ command_queue = {
+ .api_mtu = // tBTA_GATTC_API_CFG_MTU
+ {
+ .hdr =
+ {
+ .event = BTA_GATTC_API_CFG_MTU_EVT,
+ },
+ .mtu_cb = bta_gatt_configure_mtu_complete_callback,
+ .mtu_cb_data = static_cast<void*>(this),
+ },
+ };
+
+ client_channel_control_block.p_q_cmd = &command_queue;
+
+ tBTA_GATTC_DATA data = {
+ .op_cmpl =
+ {
+ .op_code = GATTC_OPTYPE_CONFIG,
+ .status = GATT_PRC_IN_PROGRESS,
+ },
+ };
+
+ bta_gattc_op_cmpl(&client_channel_control_block, &data);
+ ASSERT_EQ(1, mock_function_count_map["osi_free_and_reset"]);
+ ASSERT_EQ(456, param::bta_gatt_configure_mtu_complete_callback.conn_id);
+
+ ASSERT_EQ(GATT_PRC_IN_PROGRESS,
+ param::bta_gatt_configure_mtu_complete_callback.status);
+ ASSERT_EQ(this, param::bta_gatt_configure_mtu_complete_callback.data);
+}
+
+TEST_F(BtaGattTest, bta_gattc_op_cmpl_execute) {
+ command_queue = {
+ .api_exec = // tBTA_GATTC_API_EXEC
+ {
+ .hdr =
+ {
+ .event = BTA_GATTC_API_EXEC_EVT,
+ },
+ },
+ };
+
+ client_channel_control_block.p_q_cmd = &command_queue;
+
+ tBTA_GATTC_DATA data = {
+ .op_cmpl =
+ {
+ .op_code = GATTC_OPTYPE_EXE_WRITE,
+ },
+ };
+
+ bta_gattc_op_cmpl(&client_channel_control_block, &data);
+ ASSERT_EQ(BTA_GATTC_EXEC_EVT, param::bta_gattc_event_complete_callback.event);
+ ASSERT_EQ(1, mock_function_count_map["osi_free_and_reset"]);
+}
+
+TEST_F(BtaGattTest, bta_gattc_op_cmpl_read_interrupted) {
+ command_queue = {
+ .api_read = // tBTA_GATTC_API_READ
+ {
+ .hdr =
+ {
+ .event = BTA_GATTC_API_READ_EVT,
+ },
+ .handle = 123,
+ .read_cb = bta_gatt_read_complete_callback,
+ .read_cb_data = static_cast<void*>(this),
+ },
+ };
+
+ client_channel_control_block.p_q_cmd = &command_queue;
+
+ // Create interrupt condition
+ client_channel_control_block.auto_update = BTA_GATTC_DISC_WAITING;
+ client_channel_control_block.p_srcb->srvc_hdl_chg = 1;
+
+ tBTA_GATTC_DATA data = {
+ .op_cmpl =
+ {
+ .op_code = GATTC_OPTYPE_READ,
+ .status = GATT_OUT_OF_RANGE,
+ .p_cmpl = &gatt_cl_complete,
+ },
+ };
+
+ bta_gattc_op_cmpl(&client_channel_control_block, &data);
+ ASSERT_EQ(GATT_ERROR, param::bta_gatt_read_complete_callback.status);
+}
diff --git a/bta/test/common/mock_btif_dm.cc b/bta/test/common/mock_btif_dm.cc
deleted file mode 100644
index e2fbc32..0000000
--- a/bta/test/common/mock_btif_dm.cc
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:51
- */
-
-#include <cstdint>
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-#include "bta/include/bta_api.h"
-#include "include/hardware/bluetooth.h"
-#include "internal_include/bte_appl.h"
-#include "types/raw_address.h"
-
-struct uid_set_t;
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-bool btif_dm_pairing_is_busy() {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool check_cod(const RawAddress* remote_bdaddr, uint32_t cod) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool check_cod_hid(const RawAddress* remote_bdaddr) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool check_sdp_bl(const RawAddress* remote_bdaddr) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bt_status_t btif_dm_get_adapter_property(bt_property_t* prop) {
- mock_function_count_map[__func__]++;
- return BT_STATUS_SUCCESS;
-}
-bt_status_t btif_in_execute_service_request(tBTA_SERVICE_ID service_id,
- bool b_enable) {
- mock_function_count_map[__func__]++;
- return BT_STATUS_SUCCESS;
-}
-uint16_t btif_dm_get_connection_state(const RawAddress* bd_addr) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-void BTIF_dm_disable() { mock_function_count_map[__func__]++; }
-void BTIF_dm_enable() { mock_function_count_map[__func__]++; }
-void BTIF_dm_on_hw_error() { mock_function_count_map[__func__]++; }
-void BTIF_dm_report_inquiry_status_change(uint8_t status) {
- mock_function_count_map[__func__]++;
-}
-void bte_dm_evt(tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data) {
- mock_function_count_map[__func__]++;
-}
-void btif_ble_receiver_test(uint8_t rx_freq) {
- mock_function_count_map[__func__]++;
-}
-void btif_ble_test_end() { mock_function_count_map[__func__]++; }
-void btif_ble_transmitter_test(uint8_t tx_freq, uint8_t test_data_len,
- uint8_t packet_payload) {
- mock_function_count_map[__func__]++;
-}
-void btif_debug_bond_event_dump(int fd) { mock_function_count_map[__func__]++; }
-void btif_dm_ble_sec_req_evt(tBTA_DM_BLE_SEC_REQ* p_ble_req, bool is_consent) {
- mock_function_count_map[__func__]++;
-}
-void btif_dm_cancel_bond(const RawAddress bd_addr) {
- mock_function_count_map[__func__]++;
-}
-void btif_dm_cancel_discovery(void) { mock_function_count_map[__func__]++; }
-void btif_dm_cleanup(void) { mock_function_count_map[__func__]++; }
-void btif_dm_create_bond(const RawAddress bd_addr, int transport) {
- mock_function_count_map[__func__]++;
-}
-void btif_dm_create_bond_out_of_band(const RawAddress bd_addr, int transport,
- const bt_oob_data_t p192_data,
- const bt_oob_data_t p256_data) {
- mock_function_count_map[__func__]++;
-}
-void btif_dm_enable_service(tBTA_SERVICE_ID service_id, bool enable) {
- mock_function_count_map[__func__]++;
-}
-void btif_dm_get_ble_local_keys(tBTA_DM_BLE_LOCAL_KEY_MASK* p_key_mask,
- Octet16* p_er,
- tBTA_BLE_LOCAL_ID_KEYS* p_id_keys) {
- mock_function_count_map[__func__]++;
-}
-void btif_dm_get_remote_services(RawAddress remote_addr, const int transport) {
- mock_function_count_map[__func__]++;
-}
-void btif_dm_hh_open_failed(RawAddress* bdaddr) {
- mock_function_count_map[__func__]++;
-}
-void btif_dm_init(uid_set_t* set) { mock_function_count_map[__func__]++; }
-void btif_dm_load_ble_local_keys(void) { mock_function_count_map[__func__]++; }
-void btif_dm_on_disable() { mock_function_count_map[__func__]++; }
-void btif_dm_pin_reply(const RawAddress bd_addr, uint8_t accept,
- uint8_t pin_len, bt_pin_code_t pin_code) {
- mock_function_count_map[__func__]++;
-}
-void btif_dm_proc_io_req(tBTM_AUTH_REQ* p_auth_req, bool is_orig) {
- mock_function_count_map[__func__]++;
-}
-void btif_dm_proc_io_rsp(UNUSED_ATTR const RawAddress& bd_addr,
- tBTM_IO_CAP io_cap, UNUSED_ATTR tBTM_OOB_DATA oob_data,
- tBTM_AUTH_REQ auth_req) {
- mock_function_count_map[__func__]++;
-}
-void btif_dm_read_energy_info() { mock_function_count_map[__func__]++; }
-void btif_dm_remove_ble_bonding_keys(void) {
- mock_function_count_map[__func__]++;
-}
-void btif_dm_remove_bond(const RawAddress bd_addr) {
- mock_function_count_map[__func__]++;
-}
-void btif_dm_save_ble_bonding_keys(RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
-}
-void btif_dm_set_oob_for_io_req(tBTM_OOB_DATA* p_has_oob_data) {
- mock_function_count_map[__func__]++;
-}
-void btif_dm_set_oob_for_le_io_req(const RawAddress& bd_addr,
- tBTM_OOB_DATA* p_has_oob_data,
- tBTM_LE_AUTH_REQ* p_auth_req) {
- mock_function_count_map[__func__]++;
-}
-void btif_dm_ssp_reply(const RawAddress bd_addr, bt_ssp_variant_t variant,
- uint8_t accept) {
- mock_function_count_map[__func__]++;
-}
-void btif_dm_start_discovery(void) { mock_function_count_map[__func__]++; }
-void btif_dm_update_ble_remote_properties(const RawAddress& bd_addr,
- BD_NAME bd_name,
- tBT_DEVICE_TYPE dev_type) {
- mock_function_count_map[__func__]++;
-}
-
-bool btif_dm_get_smp_config(tBTE_APPL_CFG* p_cfg) {
- mock_function_count_map[__func__]++;
- return true;
-}
-
-bool btif_dm_proc_rmt_oob(const RawAddress& bd_addr, Octet16* p_c,
- Octet16* p_r) {
- mock_function_count_map[__func__]++;
- return false;
-}
-
-void btif_dm_proc_loc_oob(bool valid, const Octet16& c, const Octet16& r) {
- mock_function_count_map[__func__]++;
-}
diff --git a/bta/test/common/mock_device_controller.cc b/bta/test/common/mock_device_controller.cc
deleted file mode 100644
index 7b0cbbc..0000000
--- a/bta/test/common/mock_device_controller.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:8
- */
-
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-#include "device/include/controller.h"
-#include "hci/include/hci_layer.h"
-#include "hci/include/hci_packet_factory.h"
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-const controller_t* controller_get_interface() {
- mock_function_count_map[__func__]++;
- return nullptr;
-}
-const controller_t* controller_get_test_interface(
- const hci_t* hci_interface,
- const hci_packet_factory_t* packet_factory_interface,
- const hci_packet_parser_t* packet_parser_interface) {
- mock_function_count_map[__func__]++;
- return nullptr;
-}
diff --git a/bta/test/common/mock_main_shim_acl.cc b/bta/test/common/mock_main_shim_acl.cc
deleted file mode 100644
index 84a54f0..0000000
--- a/bta/test/common/mock_main_shim_acl.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:7
- */
-
-#include <cstdint>
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-#include "main/shim/acl_api.h"
-#include "types/ble_address_with_type.h"
-#include "types/raw_address.h"
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-void bluetooth::shim::ACL_CreateClassicConnection(
- const RawAddress& raw_address) {
- mock_function_count_map[__func__]++;
-}
-void bluetooth::shim::ACL_CancelClassicConnection(
- const RawAddress& raw_address) {
- mock_function_count_map[__func__]++;
-}
-bool bluetooth::shim::ACL_AcceptLeConnectionFrom(
- const tBLE_BD_ADDR& legacy_address_with_type) {
- mock_function_count_map[__func__]++;
- return true;
-}
-void bluetooth::shim::ACL_IgnoreLeConnectionFrom(
- const tBLE_BD_ADDR& legacy_address_with_type) {
- mock_function_count_map[__func__]++;
-}
-void bluetooth::shim::ACL_IgnoreAllLeConnections() {
- mock_function_count_map[__func__]++;
-}
-void bluetooth::shim::ACL_ConfigureLePrivacy(bool is_le_privacy_enabled) {
- mock_function_count_map[__func__]++;
-}
-void bluetooth::shim::ACL_Disconnect(uint16_t handle, bool is_classic,
- tHCI_STATUS reason) {
- mock_function_count_map[__func__]++;
-}
-void bluetooth::shim::ACL_Shutdown() { mock_function_count_map[__func__]++; }
-void bluetooth::shim::ACL_WriteData(uint16_t handle, const BT_HDR* p_buf) {
- mock_function_count_map[__func__]++;
-}
diff --git a/bta/test/common/mock_shim.cc b/bta/test/common/mock_shim.cc
deleted file mode 100644
index 828da52..0000000
--- a/bta/test/common/mock_shim.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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_shim"
-
-#include "gd/common/init_flags.h"
-#include "main/shim/shim.h"
-
-future_t* IdleModuleStartUp() { return kReturnImmediate; }
-
-future_t* ShimModuleStartUp() { return kReturnImmediate; }
-
-future_t* GeneralShutDown() { return kReturnImmediate; }
-
-bool bluetooth::shim::is_gd_advertising_enabled() { return false; }
-
-bool bluetooth::shim::is_gd_scanning_enabled() { return false; }
-
-bool bluetooth::shim::is_gd_security_enabled() { return false; }
-
-bool bluetooth::shim::is_gd_acl_enabled() { return false; }
-
-bool bluetooth::shim::is_gd_link_policy_enabled() { return false; }
-
-bool bluetooth::shim::is_gd_hci_enabled() { return false; }
-
-bool bluetooth::shim::is_gd_controller_enabled() { return false; }
-
-bool bluetooth::shim::is_gd_l2cap_enabled() { return false; }
-
-bool bluetooth::shim::is_gd_shim_enabled() {
- return bluetooth::common::init_flags::gd_core_is_enabled();
-}
-
-bool bluetooth::shim::is_any_gd_enabled() { return false; }
-
-bool bluetooth::shim::is_gd_stack_started_up() { return false; }
diff --git a/bta/test/common/mock_stack_acl.cc b/bta/test/common/mock_stack_acl.cc
deleted file mode 100644
index b0975b1..0000000
--- a/bta/test/common/mock_stack_acl.cc
+++ /dev/null
@@ -1,452 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:127
- */
-
-#include <cstdint>
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-#include "stack/acl/acl.h"
-#include "stack/include/acl_api.h"
-#include "stack/include/hci_error_code.h"
-#include "types/bt_transport.h"
-#include "types/hci_role.h"
-#include "types/raw_address.h"
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-bool IsEprAvailable(const tACL_CONN& p_acl) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool ACL_SupportTransparentSynchronousData(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_BLE_IS_RESOLVE_BDA(const RawAddress& x) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_IsAclConnectionUp(const RawAddress& remote_bda,
- tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_IsAclConnectionUpAndHandleValid(const RawAddress& remote_bda,
- tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_IsAclConnectionUpFromHandle(uint16_t hci_handle) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_IsBleConnection(uint16_t hci_handle) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_IsPhy2mSupported(const RawAddress& remote_bda,
- tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_ReadRemoteConnectionAddr(const RawAddress& pseudo_addr,
- RawAddress& conn_addr,
- tBLE_ADDR_TYPE* p_addr_type) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_ReadRemoteVersion(const RawAddress& addr, uint8_t* lmp_version,
- uint16_t* manufacturer, uint16_t* lmp_sub_version) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool acl_create_le_connection(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool acl_create_le_connection_with_id(uint8_t id, const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool acl_is_role_switch_allowed() {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool acl_is_switch_role_idle(const RawAddress& bd_addr,
- tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool acl_peer_supports_ble_2m_phy(uint16_t hci_handle) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool acl_peer_supports_ble_coded_phy(uint16_t hci_handle) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool acl_peer_supports_ble_connection_parameters_request(
- const RawAddress& remote_bda) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool acl_peer_supports_ble_packet_extension(uint16_t hci_handle) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool acl_peer_supports_sniff_subrating(const RawAddress& remote_bda) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool acl_refresh_remote_address(const RawAddress& identity_address,
- tBLE_ADDR_TYPE identity_address_type,
- const RawAddress& bda, tBLE_ADDR_TYPE rra_type,
- const RawAddress& rpa) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool acl_set_peer_le_features_from_handle(uint16_t hci_handle,
- const uint8_t* p) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool sco_peer_supports_esco_2m_phy(const RawAddress& remote_bda) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool sco_peer_supports_esco_3m_phy(const RawAddress& remote_bda) {
- mock_function_count_map[__func__]++;
- return false;
-}
-const RawAddress acl_address_from_handle(uint16_t handle) {
- mock_function_count_map[__func__]++;
- return RawAddress::kEmpty;
-}
-void acl_send_data_packet_br_edr([[maybe_unused]] const RawAddress& bd_addr,
- BT_HDR* p_buf) {
- mock_function_count_map[__func__]++;
-}
-void acl_create_classic_connection(const RawAddress& bd_addr,
- bool there_are_high_priority_channels,
- bool is_bonding) {
- mock_function_count_map[__func__]++;
-}
-tACL_CONN* acl_get_connection_from_address(const RawAddress& bd_addr,
- tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return nullptr;
-}
-tACL_CONN* acl_get_connection_from_handle(uint16_t handle) {
- mock_function_count_map[__func__]++;
- return nullptr;
-}
-tBTM_STATUS BTM_GetLinkSuperTout(const RawAddress& remote_bda,
- uint16_t* p_timeout) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_GetRole(const RawAddress& remote_bd_addr, tHCI_ROLE* p_role) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_ReadFailedContactCounter(const RawAddress& remote_bda,
- tBTM_CMPL_CB* p_cb) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_ReadRSSI(const RawAddress& remote_bda, tBTM_CMPL_CB* p_cb) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_ReadTxPower(const RawAddress& remote_bda,
- tBT_TRANSPORT transport, tBTM_CMPL_CB* p_cb) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_SetLinkSuperTout(const RawAddress& remote_bda,
- uint16_t timeout) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_SwitchRoleToCentral(const RawAddress& remote_bd_addr) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS btm_remove_acl(const RawAddress& bd_addr, tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-uint16_t BTM_GetHCIConnHandle(const RawAddress& remote_bda,
- tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint16_t BTM_GetMaxPacketSize(const RawAddress& addr) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint16_t mock_stack_acl_num_links = 0;
-uint16_t BTM_GetNumAclLinks(void) {
- mock_function_count_map[__func__]++;
- return mock_stack_acl_num_links;
-}
-uint16_t acl_get_supported_packet_types() {
- mock_function_count_map[__func__]++;
- return 0;
-}
-tHCI_REASON btm_get_acl_disc_reason_code(void) {
- mock_function_count_map[__func__]++;
- return HCI_SUCCESS;
-}
-uint8_t BTM_GetPeerSCA(const RawAddress& remote_bda, tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint8_t BTM_SetTraceLevel(uint8_t new_level) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint8_t acl_link_role_from_handle(uint16_t handle) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint8_t btm_handle_to_acl_index(uint16_t hci_handle) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint8_t* BTM_ReadRemoteFeatures(const RawAddress& addr) {
- mock_function_count_map[__func__]++;
- return nullptr;
-}
-void ACL_RegisterClient(struct acl_client_callback_s* callbacks) {
- mock_function_count_map[__func__]++;
-}
-void ACL_UnregisterClient(struct acl_client_callback_s* callbacks) {
- mock_function_count_map[__func__]++;
-}
-void BTM_ReadConnectionAddr(const RawAddress& remote_bda,
- RawAddress& local_conn_addr,
- tBLE_ADDR_TYPE* p_addr_type) {
- mock_function_count_map[__func__]++;
-}
-void BTM_RequestPeerSCA(const RawAddress& remote_bda, tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
-}
-void BTM_acl_after_controller_started(const controller_t* controller) {
- mock_function_count_map[__func__]++;
-}
-void BTM_block_role_switch_for(const RawAddress& peer_addr) {
- mock_function_count_map[__func__]++;
-}
-void BTM_block_sniff_mode_for(const RawAddress& peer_addr) {
- mock_function_count_map[__func__]++;
-}
-void BTM_default_block_role_switch() { mock_function_count_map[__func__]++; }
-void BTM_default_unblock_role_switch() { mock_function_count_map[__func__]++; }
-void BTM_unblock_role_switch_for(const RawAddress& peer_addr) {
- mock_function_count_map[__func__]++;
-}
-void BTM_unblock_sniff_mode_for(const RawAddress& peer_addr) {
- mock_function_count_map[__func__]++;
-}
-void acl_accept_connection_request(const RawAddress& bd_addr, uint8_t role) {
- mock_function_count_map[__func__]++;
-}
-void acl_disconnect_after_role_switch(uint16_t conn_handle,
- tHCI_STATUS reason) {
- mock_function_count_map[__func__]++;
-}
-void acl_disconnect_from_handle(uint16_t handle, tHCI_STATUS reason) {
- mock_function_count_map[__func__]++;
-}
-void acl_link_segments_xmitted(BT_HDR* p_msg) {
- mock_function_count_map[__func__]++;
-}
-void acl_packets_completed(uint16_t handle, uint16_t credits) {
- mock_function_count_map[__func__]++;
-}
-void acl_process_extended_features(uint16_t handle, uint8_t current_page_number,
- uint8_t max_page_number, uint64_t features) {
- mock_function_count_map[__func__]++;
-}
-void acl_process_num_completed_pkts(uint8_t* p, uint8_t evt_len) {
- mock_function_count_map[__func__]++;
-}
-void acl_rcv_acl_data(BT_HDR* p_msg) { mock_function_count_map[__func__]++; }
-void acl_reject_connection_request(const RawAddress& bd_addr, uint8_t reason) {
- mock_function_count_map[__func__]++;
-}
-void acl_send_data_packet_ble(const RawAddress& bd_addr, BT_HDR* p_buf) {
- mock_function_count_map[__func__]++;
-}
-void acl_set_disconnect_reason(tHCI_STATUS acl_disc_reason) {
- mock_function_count_map[__func__]++;
-}
-void acl_write_automatic_flush_timeout(const RawAddress& bd_addr,
- uint16_t flush_timeout_in_ticks) {
- mock_function_count_map[__func__]++;
-}
-void btm_acl_chk_peer_pkt_type_support(tACL_CONN* p, uint16_t* p_pkt_type) {
- mock_function_count_map[__func__]++;
-}
-void btm_acl_connected(const RawAddress& bda, uint16_t handle,
- tHCI_STATUS status, uint8_t enc_mode) {
- mock_function_count_map[__func__]++;
-}
-void btm_acl_connection_request(const RawAddress& bda, uint8_t* dc) {
- mock_function_count_map[__func__]++;
-}
-void btm_acl_created(const RawAddress& bda, uint16_t hci_handle,
- tHCI_ROLE link_role, tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
-}
-void btm_acl_device_down(void) { mock_function_count_map[__func__]++; }
-void btm_acl_disconnected(tHCI_STATUS status, uint16_t handle,
- tHCI_REASON reason) {
- mock_function_count_map[__func__]++;
-}
-void btm_acl_encrypt_change(uint16_t handle, uint8_t status,
- uint8_t encr_enable) {
- mock_function_count_map[__func__]++;
-}
-void btm_acl_notif_conn_collision(const RawAddress& bda) {
- mock_function_count_map[__func__]++;
-}
-void btm_acl_paging(BT_HDR* p, const RawAddress& bda) {
- mock_function_count_map[__func__]++;
-}
-void btm_acl_process_sca_cmpl_pkt(uint8_t len, uint8_t* data) {
- mock_function_count_map[__func__]++;
-}
-void btm_acl_removed(uint16_t handle) { mock_function_count_map[__func__]++; }
-void btm_acl_reset_paging(void) { mock_function_count_map[__func__]++; }
-void btm_acl_resubmit_page(void) { mock_function_count_map[__func__]++; }
-void btm_acl_role_changed(tHCI_STATUS hci_status, const RawAddress& bd_addr,
- tHCI_ROLE new_role) {
- mock_function_count_map[__func__]++;
-}
-void btm_acl_set_paging(bool value) { mock_function_count_map[__func__]++; }
-void btm_acl_update_conn_addr(uint16_t handle, const RawAddress& address) {
- mock_function_count_map[__func__]++;
-}
-void btm_acl_update_inquiry_status(uint8_t status) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_refresh_local_resolvable_private_addr(
- const RawAddress& pseudo_addr, const RawAddress& local_rpa) {
- mock_function_count_map[__func__]++;
-}
-void btm_cont_rswitch_from_handle(uint16_t hci_handle) {
- mock_function_count_map[__func__]++;
-}
-void btm_establish_continue_from_address(const RawAddress& bda,
- tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
-}
-void btm_process_remote_ext_features(tACL_CONN* p_acl_cb,
- uint8_t num_read_pages) {
- mock_function_count_map[__func__]++;
-}
-void btm_process_remote_version_complete(uint8_t status, uint16_t handle,
- uint8_t lmp_version,
- uint16_t manufacturer,
- uint16_t lmp_subversion) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_automatic_flush_timeout_complete(uint8_t* p) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_failed_contact_counter_complete(uint8_t* p) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_failed_contact_counter_timeout(UNUSED_ATTR void* data) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_link_quality_complete(uint8_t* p) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_link_quality_timeout(UNUSED_ATTR void* data) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_remote_ext_features(uint16_t handle, uint8_t page_number) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_remote_ext_features_complete(uint16_t handle, uint8_t page_num,
- uint8_t max_page,
- uint8_t* features) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_remote_ext_features_complete_raw(uint8_t* p, uint8_t evt_len) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_remote_ext_features_failed(uint8_t status, uint16_t handle) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_remote_features_complete(uint16_t handle, uint8_t* features) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_remote_features_complete_raw(uint8_t* p) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_remote_version_complete(tHCI_STATUS status, uint16_t handle,
- uint8_t lmp_version,
- uint16_t manufacturer,
- uint16_t lmp_subversion) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_remote_version_complete_raw(uint8_t* p) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_rssi_complete(uint8_t* p) { mock_function_count_map[__func__]++; }
-void btm_read_rssi_timeout(UNUSED_ATTR void* data) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_tx_power_complete(uint8_t* p, bool is_ble) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_tx_power_timeout(UNUSED_ATTR void* data) {
- mock_function_count_map[__func__]++;
-}
-void btm_rejectlist_role_change_device(const RawAddress& bd_addr,
- uint8_t hci_status) {
- mock_function_count_map[__func__]++;
-}
-void btm_set_link_policy(tACL_CONN* conn, tLINK_POLICY policy) {
- mock_function_count_map[__func__]++;
-}
-void btm_set_packet_types_from_address(const RawAddress& bd_addr,
- uint16_t pkt_types) {
- mock_function_count_map[__func__]++;
-}
-void hci_btm_set_link_supervision_timeout(tACL_CONN& link, uint16_t timeout) {
- mock_function_count_map[__func__]++;
-}
-void on_acl_br_edr_connected(const RawAddress& bda, uint16_t handle,
- uint8_t enc_mode) {
- mock_function_count_map[__func__]++;
-}
-void on_acl_br_edr_failed(const RawAddress& bda, tHCI_STATUS status) {
- mock_function_count_map[__func__]++;
-}
diff --git a/bta/test/common/mock_stack_btm.cc b/bta/test/common/mock_stack_btm.cc
deleted file mode 100644
index 3f8d1ca..0000000
--- a/bta/test/common/mock_stack_btm.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- */
-
-#include "stack/include/btm_ble_api_types.h"
-#include "stack/include/btm_client_interface.h"
-#include "types/raw_address.h"
-
-bool BTM_HasEirService(const uint32_t* p_eir_uuid, uint16_t uuid16) {
- return false;
-}
-tBTM_INQ_INFO* BTM_InqDbFirst(void) { return nullptr; }
-tBTM_INQ_INFO* BTM_InqDbNext(tBTM_INQ_INFO* p_cur) { return nullptr; }
-tBTM_INQ_INFO* BTM_InqDbRead(const RawAddress& p_bda) { return nullptr; }
-tBTM_STATUS BTM_CancelRemoteDeviceName(void) { return BTM_SUCCESS; }
-tBTM_STATUS BTM_ClearInqDb(const RawAddress* p_bda) { return BTM_SUCCESS; }
-tBTM_STATUS BTM_ReadLocalDeviceNameFromController(
- tBTM_CMPL_CB* p_rln_cmpl_cback) {
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_ReadRemoteDeviceName(const RawAddress& remote_bda,
- tBTM_CMPL_CB* p_cb,
- tBT_TRANSPORT transport) {
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_SetConnectability(uint16_t page_mode) { return BTM_SUCCESS; }
-tBTM_STATUS BTM_SetDeviceClass(DEV_CLASS dev_class) { return BTM_SUCCESS; }
-tBTM_STATUS BTM_SetLocalDeviceName(char* p_name) { return BTM_SUCCESS; }
-tBTM_STATUS BTM_StartInquiry(tBTM_INQ_RESULTS_CB* p_results_cb,
- tBTM_CMPL_CB* p_cmpl_cb) {
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_WriteEIR(BT_HDR* p_buff) { return BTM_SUCCESS; }
-tBTM_STATUS BTM_SetDiscoverability(uint16_t inq_mode) { return BTM_SUCCESS; }
-tBTM_STATUS BTM_BleGetEnergyInfo(tBTM_BLE_ENERGY_INFO_CBACK* p_ener_cback) {
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_BleObserve(bool start, uint8_t duration,
- tBTM_INQ_RESULTS_CB* p_results_cb,
- tBTM_CMPL_CB* p_cmpl_cb) {
- return BTM_SUCCESS;
-}
-uint16_t BTM_IsInquiryActive(void) { return 0; }
-uint8_t BTM_GetEirSupportedServices(uint32_t* p_eir_uuid, uint8_t** p,
- uint8_t max_num_uuid16,
- uint8_t* p_num_uuid16) {
- return 0;
-}
-void BTM_AddEirService(uint32_t* p_eir_uuid, uint16_t uuid16) {}
-void BTM_BleReadControllerFeatures(tBTM_BLE_CTRL_FEATURES_CBACK* p_vsc_cback) {}
-void BTM_CancelInquiry(void) {}
-void BTM_RemoveEirService(uint32_t* p_eir_uuid, uint16_t uuid16) {}
-void BTM_WritePageTimeout(uint16_t timeout) {}
-bool BTM_BleConfigPrivacy(bool enable) { return false; }
-bool BTM_IsDeviceUp() { return false; }
-bool BTM_is_sniff_allowed_for(const RawAddress& peer_addr) { return false; }
-void btm_ble_adv_init() {}
-tBTM_STATUS BTM_ReadLocalDeviceName(char** p_name) { return BTM_SUCCESS; }
-uint8_t BTM_GetAcceptlistSize() { return 0; }
-
-struct btm_client_interface_s btm_client_interface = {};
-
-struct btm_client_interface_s& get_btm_client_interface() {
- return btm_client_interface;
-}
diff --git a/bta/test/common/mock_stack_btm_ble.cc b/bta/test/common/mock_stack_btm_ble.cc
deleted file mode 100644
index a39c780..0000000
--- a/bta/test/common/mock_stack_btm_ble.cc
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:50
- */
-
-#include <base/bind.h>
-#include <base/callback.h>
-#include <cstdint>
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-#include "stack/btm/btm_ble_int_types.h"
-#include "stack/btm/btm_int_types.h"
-#include "stack/btm/security_device_record.h"
-#include "stack/include/bt_types.h"
-#include "stack/include/btm_api_types.h"
-#include "stack/include/btm_ble_api_types.h"
-#include "stack/include/l2cdefs.h"
-#include "types/raw_address.h"
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-void btm_ble_reset_id(void) { mock_function_count_map[__func__]++; }
-bool BTM_BleDataSignature(const RawAddress& bd_addr, uint8_t* p_text,
- uint16_t len, BLE_SIGNATURE signature) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_BleVerifySignature(const RawAddress& bd_addr, uint8_t* p_orig,
- uint16_t len, uint32_t counter, uint8_t* p_comp) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_ReadConnectedTransportAddress(RawAddress* remote_bda,
- tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_UseLeLink(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool btm_ble_get_acl_remote_addr(uint16_t hci_handle, RawAddress& conn_addr,
- tBLE_ADDR_TYPE* p_addr_type) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool btm_ble_get_enc_key_type(const RawAddress& bd_addr, uint8_t* p_key_types) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool btm_get_local_div(const RawAddress& bd_addr, uint16_t* p_div) {
- mock_function_count_map[__func__]++;
- return false;
-}
-namespace {
-Octet16 octet16;
-}
-
-const Octet16& BTM_GetDeviceDHK() {
- mock_function_count_map[__func__]++;
- return octet16;
-}
-const Octet16& BTM_GetDeviceEncRoot() {
- mock_function_count_map[__func__]++;
- return octet16;
-}
-const Octet16& BTM_GetDeviceIDRoot() {
- mock_function_count_map[__func__]++;
- return octet16;
-}
-tBTM_SEC_ACTION btm_ble_determine_security_act(bool is_originator,
- const RawAddress& bdaddr,
- uint16_t security_required) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_SetBleDataLength(const RawAddress& bd_addr,
- uint16_t tx_pdu_length) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS btm_ble_set_encryption(const RawAddress& bd_addr,
- tBTM_BLE_SEC_ACT sec_act,
- uint8_t link_role) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS btm_ble_start_encrypt(const RawAddress& bda, bool use_stk,
- Octet16* p_stk) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-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) {
- mock_function_count_map[__func__]++;
- return L2CAP_LE_RESULT_CONN_OK;
-}
-uint8_t btm_ble_br_keys_req(tBTM_SEC_DEV_REC* p_dev_rec,
- tBTM_LE_IO_REQ* p_data) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint8_t btm_ble_io_capabilities_req(tBTM_SEC_DEV_REC* p_dev_rec,
- tBTM_LE_IO_REQ* p_data) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint8_t btm_ble_read_sec_key_size(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-tSMP_STATUS btm_proc_smp_cback(tSMP_EVT event, const RawAddress& bd_addr,
- tSMP_EVT_DATA* p_data) {
- mock_function_count_map[__func__]++;
- return SMP_SUCCESS;
-}
-void BTM_BleConfirmReply(const RawAddress& bd_addr, uint8_t res) {
- mock_function_count_map[__func__]++;
-}
-void BTM_BleLoadLocalKeys(uint8_t key_type, tBTM_BLE_LOCAL_KEYS* p_key) {
- mock_function_count_map[__func__]++;
-}
-void BTM_BleOobDataReply(const RawAddress& bd_addr, uint8_t res, uint8_t len,
- uint8_t* p_data) {
- mock_function_count_map[__func__]++;
-}
-void BTM_BlePasskeyReply(const RawAddress& bd_addr, uint8_t res,
- uint32_t passkey) {
- mock_function_count_map[__func__]++;
-}
-void BTM_BleReadPhy(
- const RawAddress& bd_addr,
- base::Callback<void(uint8_t tx_phy, uint8_t rx_phy, uint8_t status)> cb) {
- mock_function_count_map[__func__]++;
-}
-void BTM_BleReceiverTest(uint8_t rx_freq, tBTM_CMPL_CB* p_cmd_cmpl_cback) {
- mock_function_count_map[__func__]++;
-}
-void BTM_BleSecureConnectionOobDataReply(const RawAddress& bd_addr,
- uint8_t* p_c, uint8_t* p_r) {
- mock_function_count_map[__func__]++;
-}
-void BTM_BleSetPhy(const RawAddress& bd_addr, uint8_t tx_phys, uint8_t rx_phys,
- uint16_t phy_options) {
- mock_function_count_map[__func__]++;
-}
-void BTM_BleSetPrefConnParams(const RawAddress& bd_addr, uint16_t min_conn_int,
- uint16_t max_conn_int,
- uint16_t peripheral_latency,
- uint16_t supervision_tout) {
- mock_function_count_map[__func__]++;
-}
-void BTM_BleTestEnd(tBTM_CMPL_CB* p_cmd_cmpl_cback) {
- mock_function_count_map[__func__]++;
-}
-void BTM_BleTransmitterTest(uint8_t tx_freq, uint8_t test_data_len,
- uint8_t packet_payload,
- tBTM_CMPL_CB* p_cmd_cmpl_cback) {
- mock_function_count_map[__func__]++;
-}
-void BTM_ReadDevInfo(const RawAddress& remote_bda, tBT_DEVICE_TYPE* p_dev_type,
- tBLE_ADDR_TYPE* p_addr_type) {
- mock_function_count_map[__func__]++;
-}
-void BTM_SecAddBleDevice(const RawAddress& bd_addr, tBT_DEVICE_TYPE dev_type,
- tBLE_ADDR_TYPE addr_type) {
- mock_function_count_map[__func__]++;
-}
-void BTM_SecAddBleKey(const RawAddress& bd_addr, tBTM_LE_KEY_VALUE* p_le_key,
- tBTM_LE_KEY_TYPE key_type) {
- mock_function_count_map[__func__]++;
-}
-void BTM_SecurityGrant(const RawAddress& bd_addr, uint8_t res) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_connected(const RawAddress& bda, uint16_t handle, uint8_t enc_mode,
- uint8_t role, tBLE_ADDR_TYPE addr_type,
- bool addr_matched) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_connected_from_address_with_type(
- const tBLE_BD_ADDR& address_with_type, uint16_t handle, uint8_t enc_mode,
- uint8_t role, bool addr_matched) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_increment_sign_ctr(const RawAddress& bd_addr, bool is_local) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_link_encrypted(const RawAddress& bd_addr, uint8_t encr_enable) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_link_sec_check(const RawAddress& bd_addr,
- tBTM_LE_AUTH_REQ auth_req,
- tBTM_BLE_SEC_REQ_ACT* p_sec_req_act) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_ltk_request(uint16_t handle, uint8_t rand[8], uint16_t ediv) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_ltk_request_reply(const RawAddress& bda, bool use_stk,
- const Octet16& stk) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_rand_enc_complete(uint8_t* p, uint16_t op_code,
- tBTM_RAND_ENC_CB* p_enc_cplt_cback) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_set_random_address(const RawAddress& random_bda) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_test_command_complete(uint8_t* p) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_update_sec_key_size(const RawAddress& bd_addr,
- uint8_t enc_key_size) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_save_le_key(const RawAddress& bd_addr, tBTM_LE_KEY_TYPE key_type,
- tBTM_LE_KEY_VALUE* p_keys, bool pass_to_application) {
- mock_function_count_map[__func__]++;
-}
-void doNothing(uint8_t* data, uint16_t len) {
- mock_function_count_map[__func__]++;
-}
-void read_phy_cb(
- base::Callback<void(uint8_t tx_phy, uint8_t rx_phy, uint8_t status)> cb,
- uint8_t* data, uint16_t len) {
- mock_function_count_map[__func__]++;
-}
diff --git a/bta/test/common/mock_stack_btm_dev.cc b/bta/test/common/mock_stack_btm_dev.cc
deleted file mode 100644
index 692fcfd..0000000
--- a/bta/test/common/mock_stack_btm_dev.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:12
- */
-
-#include <cstdint>
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-#include "stack/btm/security_device_record.h"
-#include "stack/include/bt_types.h"
-#include "types/raw_address.h"
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-bool BTM_SecAddDevice(const RawAddress& bd_addr, DEV_CLASS dev_class,
- BD_NAME bd_name, uint8_t* features, LinkKey* p_link_key,
- uint8_t key_type, uint8_t pin_length) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_SecDeleteDevice(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return false;
-}
-void wipe_secrets_and_remove(tBTM_SEC_DEV_REC* p_dev_rec) {
- mock_function_count_map[__func__]++;
-}
-char* BTM_SecReadDevName(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return nullptr;
-}
-void BTM_SecClearSecurityFlags(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
-}
diff --git a/bta/test/common/mock_stack_btm_main.cc b/bta/test/common/mock_stack_btm_main.cc
deleted file mode 100644
index e614cc3..0000000
--- a/bta/test/common/mock_stack_btm_main.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:7
- */
-
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-#include <memory>
-#include <string>
-#include "bt_target.h"
-#include "bt_types.h"
-#include "main/shim/dumpsys.h"
-#include "stack/btm/btm_int_types.h"
-#include "stack/include/btm_client_interface.h"
-#include "stack_config.h"
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-void BTM_LogHistory(const std::string& tag, const RawAddress& bd_addr,
- const std::string& msg) {
- mock_function_count_map[__func__]++;
-}
-void BTM_LogHistory(const std::string& tag, const RawAddress& bd_addr,
- const std::string& msg, const std::string& extra) {
- mock_function_count_map[__func__]++;
-}
-void BTM_LogHistory(const std::string& tag, const tBLE_BD_ADDR& ble_bd_addr,
- const std::string& msg) {
- mock_function_count_map[__func__]++;
-}
-void BTM_LogHistory(const std::string& tag, const tBLE_BD_ADDR& ble_bd_addr,
- const std::string& msg, const std::string& extra) {
- mock_function_count_map[__func__]++;
-}
-void btm_free(void) { mock_function_count_map[__func__]++; }
-void btm_init(void) { mock_function_count_map[__func__]++; }
diff --git a/bta/test/common/mock_stack_btm_pm.cc b/bta/test/common/mock_stack_btm_pm.cc
deleted file mode 100644
index 62a9f4f..0000000
--- a/bta/test/common/mock_stack_btm_pm.cc
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:17
- */
-
-#include <cstdint>
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-#include "stack/include/btm_api_types.h"
-#include "stack/include/btm_status.h"
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-bool BTM_ReadPowerMode(const RawAddress& remote_bda, tBTM_PM_MODE* p_mode) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_SetLinkPolicyActiveMode(const RawAddress& remote_bda) {
- mock_function_count_map[__func__]++;
- return false;
-}
-tBTM_CONTRL_STATE BTM_PM_ReadControllerState(void) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-tBTM_STATUS BTM_PmRegister(uint8_t mask, uint8_t* p_pm_id,
- tBTM_PM_STATUS_CBACK* p_cb) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_SetPowerMode(uint8_t pm_id, const RawAddress& remote_bda,
- const tBTM_PM_PWR_MD* p_mode) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_SetSsrParams(const RawAddress& remote_bda, uint16_t max_lat,
- uint16_t min_rmt_to, uint16_t min_loc_to) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-void BTM_PM_OnConnected(uint16_t handle, const RawAddress& remote_bda) {
- mock_function_count_map[__func__]++;
-}
-void BTM_PM_OnDisconnected(uint16_t handle) {
- mock_function_count_map[__func__]++;
-}
-void btm_pm_on_mode_change(tHCI_STATUS status, uint16_t handle,
- tHCI_MODE current_mode, uint16_t interval) {
- mock_function_count_map[__func__]++;
-}
-void btm_pm_on_sniff_subrating(tHCI_STATUS status, uint16_t handle,
- uint16_t maximum_transmit_latency,
- uint16_t maximum_receive_latency,
- uint16_t minimum_remote_timeout,
- uint16_t minimum_local_timeout) {
- mock_function_count_map[__func__]++;
-}
-void btm_pm_proc_cmd_status(tHCI_STATUS status) {
- mock_function_count_map[__func__]++;
-}
-void btm_pm_proc_mode_change(tHCI_STATUS hci_status, uint16_t hci_handle,
- tHCI_MODE hci_mode, uint16_t interval) {
- mock_function_count_map[__func__]++;
-}
-void btm_pm_proc_ssr_evt(uint8_t* p, UNUSED_ATTR uint16_t evt_len) {
- mock_function_count_map[__func__]++;
-}
-void btm_pm_reset(void) { mock_function_count_map[__func__]++; }
-void process_ssr_event(tHCI_STATUS status, uint16_t handle,
- UNUSED_ATTR uint16_t max_tx_lat, uint16_t max_rx_lat) {
- mock_function_count_map[__func__]++;
-}
diff --git a/bta/test/common/mock_stack_btm_sco.cc b/bta/test/common/mock_stack_btm_sco.cc
deleted file mode 100644
index c09cdee..0000000
--- a/bta/test/common/mock_stack_btm_sco.cc
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:23
- */
-
-#include <cstdint>
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-#include "stack/include/btm_api_types.h"
-#include "stack/include/btm_status.h"
-#include "stack/include/hci_error_code.h"
-#include "types/raw_address.h"
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-bool BTM_IsScoActiveByBdaddr(const RawAddress& remote_bda) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool btm_is_sco_active(uint16_t handle) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool btm_sco_removed(uint16_t hci_handle, tHCI_REASON reason) {
- mock_function_count_map[__func__]++;
- return false;
-}
-const RawAddress* BTM_ReadScoBdAddr(uint16_t sco_inx) {
- mock_function_count_map[__func__]++;
- return nullptr;
-}
-tBTM_STATUS BTM_ChangeEScoLinkParms(uint16_t sco_inx,
- tBTM_CHG_ESCO_PARAMS* p_parms) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-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) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_RegForEScoEvts(uint16_t sco_inx,
- tBTM_ESCO_CBACK* p_esco_cback) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_RemoveSco(uint16_t sco_inx) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_SetEScoMode(enh_esco_params_t* p_parms) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-uint8_t BTM_GetNumScoLinks(void) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-void BTM_EScoConnRsp(uint16_t sco_inx, uint8_t hci_status,
- enh_esco_params_t* p_parms) {
- mock_function_count_map[__func__]++;
-}
-void BTM_RemoveSco(const RawAddress& bda) {
- mock_function_count_map[__func__]++;
-}
-void btm_esco_proc_conn_chg(uint8_t status, uint16_t handle,
- uint8_t tx_interval, uint8_t retrans_window,
- uint16_t rx_pkt_len, uint16_t tx_pkt_len) {
- mock_function_count_map[__func__]++;
-}
-void btm_route_sco_data(BT_HDR* p_msg) { mock_function_count_map[__func__]++; }
-void btm_sco_acl_removed(const RawAddress* bda) {
- mock_function_count_map[__func__]++;
-}
-void btm_sco_chk_pend_rolechange(uint16_t hci_handle) {
- mock_function_count_map[__func__]++;
-}
-void btm_sco_chk_pend_unpark(tHCI_STATUS hci_status, uint16_t hci_handle) {
- mock_function_count_map[__func__]++;
-}
-void btm_sco_conn_req(const RawAddress& bda, const DEV_CLASS& dev_class,
- uint8_t link_type) {
- mock_function_count_map[__func__]++;
-}
-void btm_sco_connected(tHCI_STATUS hci_status, const RawAddress& bda,
- uint16_t hci_handle, tBTM_ESCO_DATA* p_esco_data) {
- mock_function_count_map[__func__]++;
-}
-void btm_sco_disc_chk_pend_for_modechange(uint16_t hci_handle) {
- mock_function_count_map[__func__]++;
-}
-void btm_sco_on_disconnected(uint16_t hci_handle, tHCI_REASON reason) {
- mock_function_count_map[__func__]++;
-}
diff --git a/bta/test/common/mock_stack_btm_sec.cc b/bta/test/common/mock_stack_btm_sec.cc
deleted file mode 100644
index 4c68bfc..0000000
--- a/bta/test/common/mock_stack_btm_sec.cc
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:66
- */
-
-#include <cstdint>
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-#include "stack/btm/security_device_record.h"
-#include "stack/include/btm_status.h"
-#include "stack/include/hci_error_code.h"
-#include "stack/include/security_client_callbacks.h"
-#include "types/bt_transport.h"
-#include "types/raw_address.h"
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-bool BTM_BothEndsSupportSecureConnections(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_GetSecurityFlags(const RawAddress& bd_addr, uint8_t* p_sec_flags) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_GetSecurityFlagsByTransport(const RawAddress& bd_addr,
- uint8_t* p_sec_flags,
- tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_IsAuthenticated(const RawAddress& bd_addr, tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_IsEncrypted(const RawAddress& bd_addr, tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_IsLinkKeyAuthed(const RawAddress& bd_addr, tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_IsLinkKeyKnown(const RawAddress& bd_addr, tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_PeerSupportsSecureConnections(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_SecAddRmtNameNotifyCallback(tBTM_RMT_NAME_CALLBACK* p_callback) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_SecDeleteRmtNameNotifyCallback(tBTM_RMT_NAME_CALLBACK* p_callback) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_SecIsSecurityPending(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_SecRegister(const tBTM_APPL_INFO* p_cb_info) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_SetSecurityLevel(bool is_originator, const char* p_name,
- uint8_t service_id, uint16_t sec_level, uint16_t psm,
- uint32_t mx_proto_id, uint32_t mx_chan_id) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool btm_sec_is_a_bonded_dev(const RawAddress& bda) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool is_sec_state_equal(void* data, void* context) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool is_state_getting_name(void* data, void* context) {
- mock_function_count_map[__func__]++;
- return false;
-}
-const uint8_t* btm_get_dev_class(const RawAddress& bda) {
- mock_function_count_map[__func__]++;
- return nullptr;
-}
-tBTM_LINK_KEY_TYPE BTM_SecGetDeviceLinkKeyType(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-tBTM_SEC_DEV_REC* btm_sec_find_dev_by_sec_state(uint8_t state) {
- mock_function_count_map[__func__]++;
- return nullptr;
-}
-tBTM_SEC_SERV_REC* btm_sec_find_first_serv(bool is_originator, uint16_t psm) {
- mock_function_count_map[__func__]++;
- return nullptr;
-}
-tBTM_STATUS BTM_SecBond(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type,
- tBT_TRANSPORT transport, int device_type,
- uint8_t pin_len, uint8_t* p_pin) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_SecBondCancel(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_SetEncryption(const RawAddress& bd_addr,
- tBT_TRANSPORT transport,
- tBTM_SEC_CALLBACK* p_callback, void* p_ref_data,
- tBTM_BLE_SEC_ACT sec_act) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS btm_sec_bond_by_transport(const RawAddress& bd_addr,
- tBT_TRANSPORT transport, uint8_t pin_len,
- uint8_t* p_pin) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS btm_sec_disconnect(uint16_t handle, tHCI_STATUS reason) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS btm_sec_execute_procedure(tBTM_SEC_DEV_REC* p_dev_rec) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS btm_sec_l2cap_access_req(const RawAddress& bd_addr, uint16_t psm,
- bool is_originator,
- tBTM_SEC_CALLBACK* p_callback,
- void* p_ref_data) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS btm_sec_l2cap_access_req_by_requirement(
- const RawAddress& bd_addr, uint16_t security_required, bool is_originator,
- tBTM_SEC_CALLBACK* p_callback, void* p_ref_data) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS btm_sec_mx_access_request(const RawAddress& bd_addr,
- bool is_originator,
- uint16_t security_required,
- tBTM_SEC_CALLBACK* p_callback,
- void* p_ref_data) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-uint16_t BTM_GetClockOffset(const RawAddress& remote_bda) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint8_t BTM_SecClrService(uint8_t service_id) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint8_t BTM_SecClrServiceByPsm(uint16_t psm) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-void BTM_ConfirmReqReply(tBTM_STATUS res, const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
-}
-void BTM_PINCodeReply(const RawAddress& bd_addr, uint8_t res, uint8_t pin_len,
- uint8_t* p_pin) {
- mock_function_count_map[__func__]++;
-}
-void BTM_PasskeyReqReply(tBTM_STATUS res, const RawAddress& bd_addr,
- uint32_t passkey) {
- mock_function_count_map[__func__]++;
-}
-void BTM_ReadLocalOobData(void) { mock_function_count_map[__func__]++; }
-void BTM_RemoteOobDataReply(tBTM_STATUS res, const RawAddress& bd_addr,
- const Octet16& c, const Octet16& r) {
- mock_function_count_map[__func__]++;
-}
-void BTM_SetPinType(uint8_t pin_type, PIN_CODE pin_code, uint8_t pin_code_len) {
- mock_function_count_map[__func__]++;
-}
-void NotifyBondingCanceled(tBTM_STATUS btm_status) {
- mock_function_count_map[__func__]++;
-}
-void btm_create_conn_cancel_complete(uint8_t* p) {
- mock_function_count_map[__func__]++;
-}
-void btm_inq_stop_on_ssp(void) {}
-void btm_io_capabilities_req(const RawAddress& p) {
- mock_function_count_map[__func__]++;
-}
-void btm_io_capabilities_rsp(uint8_t* p) {
- mock_function_count_map[__func__]++;
-}
-void btm_proc_sp_req_evt(tBTM_SP_EVT event, uint8_t* p) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_local_oob_complete(uint8_t* p) {
- mock_function_count_map[__func__]++;
-}
-void btm_rem_oob_req(uint8_t* p) { mock_function_count_map[__func__]++; }
-void btm_sec_abort_access_req(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_auth_complete(uint16_t handle, tHCI_STATUS status) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_check_pending_reqs(void) { mock_function_count_map[__func__]++; }
-void btm_sec_clear_ble_keys(tBTM_SEC_DEV_REC* p_dev_rec) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_conn_req(const RawAddress& bda, uint8_t* dc) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_connected(const RawAddress& bda, uint16_t handle,
- tHCI_STATUS status, uint8_t enc_mode) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_dev_rec_cback_event(tBTM_SEC_DEV_REC* p_dev_rec,
- tBTM_STATUS btm_status, bool is_le_transport) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_dev_reset(void) { mock_function_count_map[__func__]++; }
-void btm_sec_disconnected(uint16_t handle, tHCI_STATUS reason) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_encrypt_change(uint16_t handle, tHCI_STATUS status,
- uint8_t encr_enable) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_link_key_notification(const RawAddress& p_bda,
- const Octet16& link_key, uint8_t key_type) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_link_key_request(uint8_t* p_event) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_pin_code_request(uint8_t* p_event) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_rmt_host_support_feat_evt(uint8_t* p) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_rmt_name_request_complete(const RawAddress* p_bd_addr,
- uint8_t* p_bd_name, tHCI_STATUS status) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_set_peer_sec_caps(uint16_t hci_handle, bool ssp_supported,
- bool sc_supported,
- bool hci_role_switch_supported) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_update_clock_offset(uint16_t handle, uint16_t clock_offset) {
- mock_function_count_map[__func__]++;
-}
-void btm_simple_pair_complete(uint8_t* p) {
- mock_function_count_map[__func__]++;
-}
diff --git a/bta/test/common/mock_stack_gatt.cc b/bta/test/common/mock_stack_gatt.cc
deleted file mode 100644
index 6ae3c8e..0000000
--- a/bta/test/common/mock_stack_gatt.cc
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:27
- */
-
-#include <cstdint>
-#include <map>
-#include <string>
-
-#include "stack/gatt/gatt_int.h"
-#include "stack/include/gatt_api.h"
-#include "types/bluetooth/uuid.h"
-#include "types/bt_transport.h"
-#include "types/raw_address.h"
-
-using namespace bluetooth;
-
-extern std::map<std::string, int> mock_function_count_map;
-tGATT_HDL_LIST_ELEM elem; // gatt_add_an_item_to_list
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-bool GATTS_DeleteService(tGATT_IF gatt_if, Uuid* p_svc_uuid,
- uint16_t svc_inst) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool GATTS_NVRegister(tGATT_APPL_INFO* p_cb_info) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool GATT_CancelConnect(tGATT_IF gatt_if, const RawAddress& bd_addr,
- bool is_direct) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool GATT_Connect(tGATT_IF gatt_if, const RawAddress& bd_addr, bool is_direct,
- tBT_TRANSPORT transport, bool opportunistic) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool GATT_Connect(tGATT_IF gatt_if, const RawAddress& bd_addr, bool is_direct,
- tBT_TRANSPORT transport, bool opportunistic,
- uint8_t initiating_phys) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool GATT_GetConnIdIfConnected(tGATT_IF gatt_if, const RawAddress& bd_addr,
- uint16_t* p_conn_id, tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool GATT_GetConnectionInfor(uint16_t conn_id, tGATT_IF* p_gatt_if,
- RawAddress& bd_addr, tBT_TRANSPORT* p_transport) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool is_active_service(const Uuid& app_uuid128, Uuid* p_svc_uuid,
- uint16_t start_handle) {
- mock_function_count_map[__func__]++;
- return false;
-}
-tGATT_HDL_LIST_ELEM& gatt_add_an_item_to_list(uint16_t s_handle) {
- mock_function_count_map[__func__]++;
- return elem;
-}
-tGATT_IF GATT_Register(const Uuid& app_uuid128, tGATT_CBACK* p_cb_info,
- bool eatt_support) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-tGATT_STATUS GATTC_ConfigureMTU(uint16_t conn_id, uint16_t mtu) {
- mock_function_count_map[__func__]++;
- return GATT_SUCCESS;
-}
-tGATT_STATUS GATTC_Discover(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
- uint16_t start_handle, uint16_t end_handle) {
- mock_function_count_map[__func__]++;
- return GATT_SUCCESS;
-}
-tGATT_STATUS GATTC_Discover(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
- uint16_t start_handle, uint16_t end_handle,
- const Uuid& uuid) {
- mock_function_count_map[__func__]++;
- return GATT_SUCCESS;
-}
-tGATT_STATUS GATTC_ExecuteWrite(uint16_t conn_id, bool is_execute) {
- mock_function_count_map[__func__]++;
- return GATT_SUCCESS;
-}
-tGATT_STATUS GATTC_Read(uint16_t conn_id, tGATT_READ_TYPE type,
- tGATT_READ_PARAM* p_read) {
- mock_function_count_map[__func__]++;
- return GATT_SUCCESS;
-}
-tGATT_STATUS GATTC_SendHandleValueConfirm(uint16_t conn_id, uint16_t cid) {
- mock_function_count_map[__func__]++;
- return GATT_SUCCESS;
-}
-tGATT_STATUS GATTC_Write(uint16_t conn_id, tGATT_WRITE_TYPE type,
- tGATT_VALUE* p_write) {
- mock_function_count_map[__func__]++;
- return GATT_SUCCESS;
-}
-tGATT_STATUS GATTS_AddService(tGATT_IF gatt_if, btgatt_db_element_t* service,
- int count) {
- mock_function_count_map[__func__]++;
- return GATT_SUCCESS;
-}
-tGATT_STATUS GATTS_HandleValueIndication(uint16_t conn_id, uint16_t attr_handle,
- uint16_t val_len, uint8_t* p_val) {
- mock_function_count_map[__func__]++;
- return GATT_SUCCESS;
-}
-tGATT_STATUS GATTS_HandleValueNotification(uint16_t conn_id,
- uint16_t attr_handle,
- uint16_t val_len, uint8_t* p_val) {
- mock_function_count_map[__func__]++;
- return GATT_SUCCESS;
-}
-tGATT_STATUS GATTS_SendRsp(uint16_t conn_id, uint32_t trans_id,
- tGATT_STATUS status, tGATTS_RSP* p_msg) {
- mock_function_count_map[__func__]++;
- return GATT_SUCCESS;
-}
-tGATT_STATUS GATT_Disconnect(uint16_t conn_id) {
- mock_function_count_map[__func__]++;
- return GATT_SUCCESS;
-}
-void GATTS_AddHandleRange(tGATTS_HNDL_RANGE* p_hndl_range) {
- mock_function_count_map[__func__]++;
-}
-void GATTS_StopService(uint16_t service_handle) {
- mock_function_count_map[__func__]++;
-}
-void GATT_Deregister(tGATT_IF gatt_if) { mock_function_count_map[__func__]++; }
-void GATT_SetIdleTimeout(const RawAddress& bd_addr, uint16_t idle_tout,
- tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
-}
-void GATT_StartIf(tGATT_IF gatt_if) { mock_function_count_map[__func__]++; }
diff --git a/bta/test/common/mock_stack_hidh.cc b/bta/test/common/mock_stack_hidh.cc
deleted file mode 100644
index 79cbcc4..0000000
--- a/bta/test/common/mock_stack_hidh.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:11
- */
-
-#include <cstdint>
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-#include "stack/include/hiddefs.h"
-#include "stack/include/hidh_api.h"
-#include "stack/include/sdp_api.h"
-#include "types/raw_address.h"
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-tHID_STATUS HID_HostAddDev(const RawAddress& addr, uint16_t attr_mask,
- uint8_t* handle) {
- mock_function_count_map[__func__]++;
- return HID_SUCCESS;
-}
-tHID_STATUS HID_HostCloseDev(uint8_t dev_handle) {
- mock_function_count_map[__func__]++;
- return HID_SUCCESS;
-}
-tHID_STATUS HID_HostDeregister(void) {
- mock_function_count_map[__func__]++;
- return HID_SUCCESS;
-}
-tHID_STATUS HID_HostGetSDPRecord(const RawAddress& addr,
- tSDP_DISCOVERY_DB* p_db, uint32_t db_len,
- tHID_HOST_SDP_CALLBACK* sdp_cback) {
- mock_function_count_map[__func__]++;
- return HID_SUCCESS;
-}
-tHID_STATUS HID_HostOpenDev(uint8_t dev_handle) {
- mock_function_count_map[__func__]++;
- return HID_SUCCESS;
-}
-tHID_STATUS HID_HostRegister(tHID_HOST_DEV_CALLBACK* dev_cback) {
- mock_function_count_map[__func__]++;
- return HID_SUCCESS;
-}
-tHID_STATUS HID_HostRemoveDev(uint8_t dev_handle) {
- mock_function_count_map[__func__]++;
- return HID_SUCCESS;
-}
-tHID_STATUS HID_HostWriteDev(uint8_t dev_handle, uint8_t t_type, uint8_t param,
- uint16_t data, uint8_t report_id, BT_HDR* pbuf) {
- mock_function_count_map[__func__]++;
- return HID_SUCCESS;
-}
-uint8_t HID_HostSetTraceLevel(uint8_t new_level) {
- mock_function_count_map[__func__]++;
- return HID_SUCCESS;
-}
-void HID_HostInit(void) { mock_function_count_map[__func__]++; }
-void hidh_get_str_attr(tSDP_DISC_REC* p_rec, uint16_t attr_id, uint16_t max_len,
- char* str) {
- mock_function_count_map[__func__]++;
-}
diff --git a/bta/test/common/mock_stack_l2cap.cc b/bta/test/common/mock_stack_l2cap.cc
deleted file mode 100644
index bc21b66..0000000
--- a/bta/test/common/mock_stack_l2cap.cc
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- */
-
-#include <cstdint>
-#include <string>
-
-#include "btm_sec.h"
-#include "main/shim/l2c_api.h"
-#include "main/shim/shim.h"
-#include "osi/include/log.h"
-#include "stack/include/l2c_api.h"
-#include "stack/l2cap/l2c_int.h"
-
-tBT_TRANSPORT l2c_get_transport_from_fixed_cid(uint16_t fixed_cid) {
- if (fixed_cid >= L2CAP_ATT_CID && fixed_cid <= L2CAP_SMP_CID)
- return BT_TRANSPORT_LE;
- return BT_TRANSPORT_BR_EDR;
-}
-
-uint16_t L2CA_Register2(uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info,
- bool enable_snoop, tL2CAP_ERTM_INFO* p_ertm_info,
- uint16_t my_mtu, uint16_t required_remote_mtu,
- uint16_t sec_level) {
- auto ret = L2CA_Register(psm, p_cb_info, enable_snoop, p_ertm_info, my_mtu,
- required_remote_mtu, sec_level);
- BTM_SetSecurityLevel(false, "", 0, sec_level, psm, 0, 0);
- return ret;
-}
-
-uint16_t L2CA_Register(uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info,
- bool enable_snoop, tL2CAP_ERTM_INFO* p_ertm_info,
- uint16_t my_mtu, uint16_t required_remote_mtu,
- uint16_t sec_level) {
- return 0;
-}
-
-void L2CA_Deregister(uint16_t psm) {}
-
-uint16_t L2CA_AllocateLePSM(void) { return 0; }
-
-void L2CA_FreeLePSM(uint16_t psm) {}
-
-uint16_t L2CA_ConnectReq2(uint16_t psm, const RawAddress& p_bd_addr,
- uint16_t sec_level) {
- return 0;
-}
-
-uint16_t L2CA_ConnectReq(uint16_t psm, const RawAddress& p_bd_addr) {
- return 0;
-}
-
-uint16_t L2CA_RegisterLECoc(uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info,
- uint16_t sec_level, tL2CAP_LE_CFG_INFO cfg) {
- return 0;
-}
-
-void L2CA_DeregisterLECoc(uint16_t psm) {}
-
-uint16_t L2CA_ConnectLECocReq(uint16_t psm, const RawAddress& p_bd_addr,
- tL2CAP_LE_CFG_INFO* p_cfg, uint16_t sec_level) {
- return 0;
-}
-
-bool L2CA_GetPeerLECocConfig(uint16_t lcid, tL2CAP_LE_CFG_INFO* peer_cfg) {
- return false;
-}
-
-bool L2CA_ConnectCreditBasedRsp(const RawAddress& p_bd_addr, uint8_t id,
- std::vector<uint16_t>& accepted_lcids,
- uint16_t result, tL2CAP_LE_CFG_INFO* p_cfg) {
- return false;
-}
-
-std::vector<uint16_t> L2CA_ConnectCreditBasedReq(uint16_t psm,
- const RawAddress& p_bd_addr,
- tL2CAP_LE_CFG_INFO* p_cfg) {
- return std::vector<uint16_t>();
-}
-
-bool L2CA_ReconfigCreditBasedConnsReq(const RawAddress& bda,
- std::vector<uint16_t>& lcids,
- tL2CAP_LE_CFG_INFO* p_cfg) {
- return false;
-}
-
-bool L2CA_DisconnectReq(uint16_t cid) { return false; }
-
-bool L2CA_DisconnectLECocReq(uint16_t cid) { return false; }
-
-bool L2CA_GetRemoteCid(uint16_t lcid, uint16_t* rcid) { return false; }
-
-bool L2CA_SetIdleTimeoutByBdAddr(const RawAddress& bd_addr, uint16_t timeout,
- tBT_TRANSPORT transport) {
- return false;
-}
-uint8_t L2CA_SetTraceLevel(uint8_t new_level) { return 0; }
-
-bool L2CA_SetAclPriority(const RawAddress& bd_addr, tL2CAP_PRIORITY priority) {
- return false;
-}
-
-bool L2CA_SetTxPriority(uint16_t cid, tL2CAP_CHNL_PRIORITY priority) {
- return false;
-}
-
-bool L2CA_GetPeerFeatures(const RawAddress& bd_addr, uint32_t* p_ext_feat,
- uint8_t* p_chnl_mask) {
- return false;
-}
-
-bool L2CA_RegisterFixedChannel(uint16_t fixed_cid,
- tL2CAP_FIXED_CHNL_REG* p_freg) {
- return false;
-}
-
-bool L2CA_ConnectFixedChnl(uint16_t fixed_cid, const RawAddress& rem_bda) {
- return false;
-}
-
-uint16_t L2CA_SendFixedChnlData(uint16_t fixed_cid, const RawAddress& rem_bda,
- BT_HDR* p_buf) {
- return 0;
-}
-
-bool L2CA_RemoveFixedChnl(uint16_t fixed_cid, const RawAddress& rem_bda) {
- return false;
-}
-
-bool L2CA_SetLeGattTimeout(const RawAddress& rem_bda, uint16_t idle_tout) {
- return false;
-}
-
-uint8_t L2CA_DataWrite(uint16_t cid, BT_HDR* p_data) { return 0; }
-
-uint8_t L2CA_LECocDataWrite(uint16_t cid, BT_HDR* p_data) { return 0; }
-
-bool L2CA_SetChnlFlushability(uint16_t cid, bool is_flushable) { return false; }
-
-uint16_t L2CA_FlushChannel(uint16_t lcid, uint16_t num_to_flush) { return 0; }
-
-bool L2CA_IsLinkEstablished(const RawAddress& bd_addr,
- tBT_TRANSPORT transport) {
- return false;
-}
diff --git a/bta/test/common/mock_stack_l2cap_ble.cc b/bta/test/common/mock_stack_l2cap_ble.cc
deleted file mode 100644
index 70590f2..0000000
--- a/bta/test/common/mock_stack_l2cap_ble.cc
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:22
- */
-
-#include <cstdint>
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-#include "stack/l2cap/l2c_int.h"
-#include "types/hci_role.h"
-#include "types/raw_address.h"
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-bool L2CA_EnableUpdateBleConnParams(const RawAddress& rem_bda, bool enable) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_UpdateBleConnParams(const RawAddress& rem_bda, uint16_t min_int,
- uint16_t max_int, uint16_t latency,
- uint16_t timeout, uint16_t min_ce_len,
- uint16_t max_ce_len) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool 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) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool l2cble_conn_comp_from_address_with_type(
- uint16_t handle, uint8_t role, const tBLE_BD_ADDR& address_with_type,
- uint16_t conn_interval, uint16_t conn_latency, uint16_t conn_timeout) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool l2cble_create_conn(tL2C_LCB* p_lcb) {
- mock_function_count_map[__func__]++;
- return false;
-}
-hci_role_t L2CA_GetBleConnRole(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return HCI_ROLE_CENTRAL;
-}
-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) {
- mock_function_count_map[__func__]++;
- return L2CAP_LE_RESULT_CONN_OK;
-}
-void L2CA_AdjustConnectionIntervals(uint16_t* min_interval,
- uint16_t* max_interval,
- uint16_t floor_interval) {
- mock_function_count_map[__func__]++;
-}
-void l2c_ble_link_adjust_allocation(void) {
- mock_function_count_map[__func__]++;
-}
-void l2c_link_processs_ble_num_bufs(uint16_t num_lm_ble_bufs) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_credit_based_conn_req(tL2C_CCB* p_ccb) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_credit_based_conn_res(tL2C_CCB* p_ccb, uint16_t result) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_notify_le_connection(const RawAddress& bda) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_process_conn_update_evt(uint16_t handle, uint8_t status,
- uint16_t interval, uint16_t latency,
- uint16_t timeout) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_process_data_length_change_event(uint16_t handle,
- uint16_t tx_data_len,
- uint16_t rx_data_len) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_process_rc_param_request_evt(uint16_t handle, uint16_t int_min,
- uint16_t int_max, uint16_t latency,
- uint16_t timeout) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_sec_comp(const RawAddress* bda, tBT_TRANSPORT transport,
- void* p_ref_data, uint8_t status) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_send_flow_control_credit(tL2C_CCB* p_ccb, uint16_t credit_value) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_send_peer_disc_req(tL2C_CCB* p_ccb) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_update_data_length(tL2C_LCB* p_lcb) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_use_preferred_conn_params(const RawAddress& bda) {
- mock_function_count_map[__func__]++;
-}
diff --git a/bta/test/common/mock_stack_sdp.cc b/bta/test/common/mock_stack_sdp.cc
deleted file mode 100644
index ef39c63..0000000
--- a/bta/test/common/mock_stack_sdp.cc
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- */
-
-#include <string.h>
-
-#include "bt_target.h"
-
-#include "sdp_api.h"
-
-#include "osi/include/osi.h"
-
-using bluetooth::Uuid;
-
-bool SDP_InitDiscoveryDb(tSDP_DISCOVERY_DB* p_db, uint32_t len,
- uint16_t num_uuid, const Uuid* p_uuid_list,
- uint16_t num_attr, uint16_t* p_attr_list) {
- return false;
-}
-
-bool SDP_CancelServiceSearch(tSDP_DISCOVERY_DB* p_db) { return false; }
-
-bool SDP_ServiceSearchRequest(const RawAddress& p_bd_addr,
- tSDP_DISCOVERY_DB* p_db,
- tSDP_DISC_CMPL_CB* p_cb) {
- return false;
-}
-
-bool SDP_ServiceSearchAttributeRequest(const RawAddress& p_bd_addr,
- tSDP_DISCOVERY_DB* p_db,
- tSDP_DISC_CMPL_CB* p_cb) {
- return false;
-}
-bool SDP_ServiceSearchAttributeRequest2(const RawAddress& p_bd_addr,
- tSDP_DISCOVERY_DB* p_db,
- tSDP_DISC_CMPL_CB2* p_cb2,
- void* user_data) {
- return false;
-}
-
-tSDP_DISC_ATTR* SDP_FindAttributeInRec(tSDP_DISC_REC* p_rec, uint16_t attr_id) {
- return (NULL);
-}
-
-bool SDP_FindServiceUUIDInRec(tSDP_DISC_REC* p_rec, Uuid* p_uuid) {
- return false;
-}
-
-bool SDP_FindServiceUUIDInRec_128bit(tSDP_DISC_REC* p_rec, Uuid* p_uuid) {
- return false;
-}
-
-tSDP_DISC_REC* SDP_FindServiceInDb(tSDP_DISCOVERY_DB* p_db,
- uint16_t service_uuid,
- tSDP_DISC_REC* p_start_rec) {
- return (NULL);
-}
-
-tSDP_DISC_REC* SDP_FindServiceInDb_128bit(tSDP_DISCOVERY_DB* p_db,
- tSDP_DISC_REC* p_start_rec) {
- return (NULL);
-}
-
-tSDP_DISC_REC* SDP_FindServiceUUIDInDb(tSDP_DISCOVERY_DB* p_db,
- const Uuid& uuid,
- tSDP_DISC_REC* p_start_rec) {
- return (NULL);
-}
-
-bool SDP_FindProtocolListElemInRec(tSDP_DISC_REC* p_rec, uint16_t layer_uuid,
- tSDP_PROTOCOL_ELEM* p_elem) {
- return (false);
-}
-
-bool SDP_FindProfileVersionInRec(tSDP_DISC_REC* p_rec, uint16_t profile_uuid,
- uint16_t* p_version) {
- return (false);
-}
-
-uint16_t SDP_DiDiscover(const RawAddress& remote_device,
- tSDP_DISCOVERY_DB* p_db, uint32_t len,
- tSDP_DISC_CMPL_CB* p_cb) {
- return 0;
-}
-
-uint8_t SDP_GetNumDiRecords(tSDP_DISCOVERY_DB* p_db) { return 0; }
-
-uint16_t SDP_GetDiRecord(uint8_t get_record_index,
- tSDP_DI_GET_RECORD* p_device_info,
- tSDP_DISCOVERY_DB* p_db) {
- return 0;
-}
-uint16_t SDP_SetLocalDiRecord(tSDP_DI_RECORD* p_device_info,
- uint32_t* p_handle) {
- return 0;
-}
-uint8_t SDP_SetTraceLevel(uint8_t new_level) { return 0; }
diff --git a/bta/vc/devices.h b/bta/vc/devices.h
index b406329..71dc6c9 100644
--- a/bta/vc/devices.h
+++ b/bta/vc/devices.h
@@ -17,13 +17,14 @@
#pragma once
-#include <hardware/bt_vc.h>
-
+#include <cstdint>
#include <unordered_set>
#include <vector>
-#include "bta_gatt_api.h"
-#include "types.h"
+#include "bta/include/bta_gatt_api.h"
+#include "bta/vc/types.h"
+#include "include/hardware/bt_vc.h"
+#include "types/raw_address.h"
namespace bluetooth {
namespace vc {
diff --git a/bta/vc/vc.cc b/bta/vc/vc.cc
index 97b8266..eca4e3e 100644
--- a/bta/vc/vc.cc
+++ b/bta/vc/vc.cc
@@ -16,7 +16,6 @@
*/
#include <base/bind.h>
-#include <base/bind_helpers.h>
#include <base/logging.h>
#include <base/strings/string_number_conversions.h>
#include <hardware/bt_vc.h>
@@ -24,6 +23,7 @@
#include <string>
#include <vector>
+#include "bind_helpers.h"
#include "bta_gatt_api.h"
#include "bta_gatt_queue.h"
#include "bta_vc_api.h"
@@ -344,7 +344,8 @@
}
void OnGattDisconnected(uint16_t connection_id, tGATT_IF /*client_if*/,
- RawAddress remote_bda, tBTA_GATT_REASON /*reason*/) {
+ RawAddress remote_bda,
+ tGATT_DISCONN_REASON /*reason*/) {
VolumeControlDevice* device =
volume_control_devices_.FindByConnId(connection_id);
if (!device) {
diff --git a/bta/vc/vc_test.cc b/bta/vc/vc_test.cc
index 30eef87..dadea57 100644
--- a/bta/vc/vc_test.cc
+++ b/bta/vc/vc_test.cc
@@ -16,10 +16,10 @@
*/
#include <base/bind.h>
-#include <base/bind_helpers.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include "bind_helpers.h"
#include "bta_gatt_api_mock.h"
#include "bta_gatt_queue_mock.h"
#include "bta_vc_api.h"
@@ -344,7 +344,7 @@
.conn_id = conn_id,
.client_if = gatt_if,
.remote_bda = address,
- .reason = HCI_ERR_PEER_USER,
+ .reason = GATT_CONN_TERMINATE_PEER_USER,
};
gatt_callback(BTA_GATTC_CLOSE_EVT, (tBTA_GATTC*)&event_data);
diff --git a/btcore/Android.bp b/btcore/Android.bp
index fc2cd4e..b9fc1ac 100644
--- a/btcore/Android.bp
+++ b/btcore/Android.bp
@@ -1,5 +1,4 @@
// libbtcore static library for target and host
-// ========================================================
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
@@ -36,7 +35,6 @@
// Note: It's good to get the tests compiled both for the host and the target so
// we get to test with both Bionic libc and glibc
// libbtcore unit tests for target and host
-// ========================================================
cc_test {
name: "net_test_btcore",
test_suites: ["device-tests"],
diff --git a/btcore/include/module.h b/btcore/include/module.h
index 38bc81b..a6f5fd2 100644
--- a/btcore/include/module.h
+++ b/btcore/include/module.h
@@ -29,12 +29,12 @@
#define BTCORE_MAX_MODULE_DEPENDENCIES 10
typedef struct {
- const char* name;
- module_lifecycle_fn init;
- module_lifecycle_fn start_up;
- module_lifecycle_fn shut_down;
- module_lifecycle_fn clean_up;
- const char* dependencies[BTCORE_MAX_MODULE_DEPENDENCIES];
+ const char* name{nullptr};
+ module_lifecycle_fn init{nullptr};
+ module_lifecycle_fn start_up{nullptr};
+ module_lifecycle_fn shut_down{nullptr};
+ module_lifecycle_fn clean_up{nullptr};
+ const char* dependencies[BTCORE_MAX_MODULE_DEPENDENCIES]{nullptr};
} module_t;
// Prepares module management. Must be called before doing anything with
diff --git a/btif/Android.bp b/btif/Android.bp
index 7fc2b24..01c90cb 100644
--- a/btif/Android.bp
+++ b/btif/Android.bp
@@ -1,5 +1,4 @@
// Common variables
-// ========================================================
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
@@ -36,7 +35,6 @@
]
// libbtif static library for target
-// ========================================================
cc_library_static {
name: "libbtif",
defaults: ["fluoride_defaults"],
@@ -139,7 +137,6 @@
}
// btif unit tests for target
-// ========================================================
cc_test {
name: "net_test_btif",
defaults: ["fluoride_defaults"],
@@ -195,7 +192,6 @@
}
// btif profile queue unit tests for target
-// ========================================================
cc_test {
name: "net_test_btif_profile_queue",
defaults: ["fluoride_defaults"],
@@ -218,7 +214,6 @@
}
// btif rc unit tests for target
-// ========================================================
cc_test {
name: "net_test_btif_rc",
defaults: ["fluoride_defaults"],
@@ -254,7 +249,6 @@
}
// btif config cache unit tests for target
-// ========================================================
cc_test {
name: "net_test_btif_config_cache",
defaults: ["fluoride_defaults"],
@@ -283,7 +277,6 @@
}
// btif hf client service tests for target
-// ========================================================
cc_test {
name: "net_test_btif_hf_client_service",
defaults: ["fluoride_defaults"],
@@ -305,7 +298,6 @@
}
// Cycle stack test
-// ========================================================
cc_test {
name: "net_test_btif_stack",
host_supported: true,
@@ -317,7 +309,6 @@
"system/bt/bta/dm",
"system/bt/bta/include",
"system/bt/bta/sys",
- "system/bt/btcore/include",
"system/bt/btif/avrcp",
"system/bt/btif/co",
"system/bt/btif/include",
@@ -341,8 +332,10 @@
],
srcs: [
":LibBluetoothSources",
+ ":TestCommonMainHandler",
":TestMockAndroidHardware",
":TestMockBta",
+ ":TestMockBtu",
":TestMockBtcore",
":TestMockCommon",
":TestMockFrameworks",
@@ -353,6 +346,12 @@
":TestMockUdrv",
"test/btif_stack_test.cc",
],
+ generated_headers: [
+ "BluetoothGeneratedBundlerSchema_h_bfbs",
+ "BluetoothGeneratedDumpsysDataSchema_h",
+ "BluetoothGeneratedDumpsysTestData_h",
+ "BluetoothGeneratedPackets_h",
+ ],
header_libs: ["libbluetooth_headers"],
shared_libs: [
"android.hardware.bluetooth.a2dp@1.0",
@@ -360,6 +359,7 @@
"android.hardware.bluetooth.audio@2.1",
"libcrypto",
"libcutils",
+ "libflatbuffers-cpp",
"libhidlbase",
"liblog",
"libtinyxml2",
diff --git a/btif/BUILD.gn b/btif/BUILD.gn
index df326e5..9d1bc6c 100644
--- a/btif/BUILD.gn
+++ b/btif/BUILD.gn
@@ -42,6 +42,7 @@
"src/btif_a2dp_control.cc",
"src/btif_a2dp_sink.cc",
"src/btif_a2dp_source.cc",
+ "src/btif_activity_attribution.cc",
"src/btif_av.cc",
# TODO(abps) - Move this abstraction elsewhere
diff --git a/btif/co/bta_hh_co.cc b/btif/co/bta_hh_co.cc
index b91bb3a..c5aba44 100644
--- a/btif/co/bta_hh_co.cc
+++ b/btif/co/bta_hh_co.cc
@@ -229,7 +229,6 @@
******************************************************************************/
static void* btif_hh_poll_event_thread(void* arg) {
btif_hh_device_t* p_dev = (btif_hh_device_t*)arg;
- 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
@@ -241,7 +240,10 @@
p_dev->hh_poll_thread_id = -1;
return 0;
}
+ p_dev->pid = gettid();
pthread_setname_np(pthread_self(), BT_HH_THREAD);
+ LOG_DEBUG("Host hid polling thread created name:%s pid:%d fd:%d",
+ BT_HH_THREAD, p_dev->pid, p_dev->fd);
pfds[0].fd = p_dev->fd;
pfds[0].events = POLLIN;
@@ -265,6 +267,7 @@
}
p_dev->hh_poll_thread_id = -1;
+ p_dev->pid = -1;
return 0;
}
diff --git a/btif/include/btif_common.h b/btif/include/btif_common.h
index 7412638..51effde 100644
--- a/btif/include/btif_common.h
+++ b/btif/include/btif_common.h
@@ -138,7 +138,7 @@
/* this type handles all btif context switches between BTU and HAL */
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
tBTIF_CBACK* p_cb; /* context switch callback */
/* parameters passed to callback */
@@ -208,7 +208,7 @@
uint32_t cod, bt_ssp_variant_t pairing_variant,
uint32_t pass_key);
void invoke_oob_data_request_cb(tBT_TRANSPORT t, bool valid, Octet16 c,
- Octet16 r);
+ Octet16 r, RawAddress raw_address);
void invoke_bond_state_changed_cb(bt_status_t status, RawAddress bd_addr,
bt_bond_state_t state);
void invoke_acl_state_changed_cb(bt_status_t status, RawAddress bd_addr,
diff --git a/btif/include/btif_dm.h b/btif/include/btif_dm.h
index 98ff8d0..6c2a594 100644
--- a/btif/include/btif_dm.h
+++ b/btif/include/btif_dm.h
@@ -59,7 +59,8 @@
tBTM_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, const Octet16& c, const Octet16& r);
+void btif_dm_proc_loc_oob(tBT_TRANSPORT transport, bool is_valid,
+ const Octet16& c, const Octet16& r);
bool btif_dm_proc_rmt_oob(const RawAddress& bd_addr, Octet16* p_c,
Octet16* p_r);
void btif_dm_generate_local_oob_data(tBT_TRANSPORT transport);
diff --git a/btif/include/btif_hh.h b/btif/include/btif_hh.h
index 2f78128..1d4bc93 100644
--- a/btif/include/btif_hh.h
+++ b/btif/include/btif_hh.h
@@ -75,6 +75,7 @@
}
#undef CASE_RETURN_TEXT
+// Shared with uhid polling thread
typedef struct {
bthh_connection_state_t dev_status;
uint8_t dev_handle;
@@ -85,6 +86,7 @@
int fd;
bool ready_for_data;
pthread_t hh_poll_thread_id;
+ pid_t pid{-1};
uint8_t hh_keep_polling;
alarm_t* vup_timer;
fixed_queue_t* get_rpt_id_queue;
diff --git a/btif/include/btif_storage.h b/btif/include/btif_storage.h
index f19733e..7e970ec 100644
--- a/btif/include/btif_storage.h
+++ b/btif/include/btif_storage.h
@@ -242,6 +242,12 @@
/** Remove client supported features */
void btif_storage_remove_gatt_cl_supp_feat(const RawAddress& bd_addr);
+/** Stores information about GATT server supported features */
+void btif_storage_set_gatt_sr_supp_feat(const RawAddress& addr, uint8_t feat);
+
+/** Gets information about GATT server supported features */
+uint8_t btif_storage_get_sr_supp_feat(const RawAddress& bd_addr);
+
/** Store last server database hash for remote client */
void btif_storage_set_gatt_cl_db_hash(const RawAddress& bd_addr, Octet16 hash);
diff --git a/btif/src/bluetooth.cc b/btif/src/bluetooth.cc
index 3a7b7d8..7a267a3 100644
--- a/btif/src/bluetooth.cc
+++ b/btif/src/bluetooth.cc
@@ -526,14 +526,14 @@
static bt_os_callouts_t* wakelock_os_callouts_saved = nullptr;
static int acquire_wake_lock_cb(const char* lock_name) {
- return do_in_main_thread(
+ return do_in_jni_thread(
FROM_HERE, base::Bind(base::IgnoreResult(
wakelock_os_callouts_saved->acquire_wake_lock),
lock_name));
}
static int release_wake_lock_cb(const char* lock_name) {
- return do_in_main_thread(
+ return do_in_jni_thread(
FROM_HERE, base::Bind(base::IgnoreResult(
wakelock_os_callouts_saved->release_wake_lock),
lock_name));
@@ -739,9 +739,19 @@
}
void invoke_oob_data_request_cb(tBT_TRANSPORT t, bool valid, Octet16 c,
- Octet16 r) {
+ Octet16 r, RawAddress raw_address) {
LOG_INFO("%s", __func__);
- bt_oob_data_t oob_data;
+ bt_oob_data_t oob_data = {};
+
+ // Set the local address
+ int j = 5;
+ for (int i = 0; i < 6; i++) {
+ oob_data.address[i] = raw_address.address[j];
+ j--;
+ }
+ // Set type always public
+ oob_data.address[6] = 0;
+
// Each value (for C and R) is 16 octets in length
bool c_empty = true;
for (int i = 0; i < 16; i++) {
diff --git a/btif/src/btif_a2dp_sink.cc b/btif/src/btif_a2dp_sink.cc
index 32fe82b..fa02a86 100644
--- a/btif/src/btif_a2dp_sink.cc
+++ b/btif/src/btif_a2dp_sink.cc
@@ -70,12 +70,12 @@
};
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
uint8_t codec_info[AVDT_CODEC_SIZE];
} tBTIF_MEDIA_SINK_DECODER_UPDATE;
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
btif_a2dp_sink_focus_state_t focus_state;
} tBTIF_MEDIA_SINK_FOCUS_UPDATE;
@@ -136,7 +136,7 @@
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_command_ready(BT_HDR_RIGID* 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();
@@ -348,7 +348,7 @@
return btif_a2dp_sink_cb.channel_count;
}
-static void btif_a2dp_sink_command_ready(BT_HDR* p_msg) {
+static void btif_a2dp_sink_command_ready(BT_HDR_RIGID* p_msg) {
LOG_VERBOSE("%s: event %d %s", __func__, p_msg->event,
dump_media_event(p_msg->event));
@@ -398,12 +398,14 @@
p_buf->hdr.event = BTIF_MEDIA_SINK_DECODER_UPDATE;
btif_a2dp_sink_cb.worker_thread.DoInThread(
- FROM_HERE, base::BindOnce(btif_a2dp_sink_command_ready, (BT_HDR*)p_buf));
+ FROM_HERE,
+ base::BindOnce(btif_a2dp_sink_command_ready, (BT_HDR_RIGID*)p_buf));
}
void btif_a2dp_sink_on_idle() {
LOG_INFO("%s", __func__);
- BT_HDR* p_buf = reinterpret_cast<BT_HDR*>(osi_malloc(sizeof(BT_HDR)));
+ BT_HDR_RIGID* p_buf =
+ reinterpret_cast<BT_HDR_RIGID*>(osi_malloc(sizeof(BT_HDR_RIGID)));
p_buf->event = BTIF_MEDIA_SINK_SUSPEND;
btif_a2dp_sink_cb.worker_thread.DoInThread(
FROM_HERE, base::BindOnce(btif_a2dp_sink_command_ready, p_buf));
@@ -415,7 +417,8 @@
void btif_a2dp_sink_on_stopped(UNUSED_ATTR tBTA_AV_SUSPEND* p_av_suspend) {
LOG_INFO("%s", __func__);
- BT_HDR* p_buf = reinterpret_cast<BT_HDR*>(osi_malloc(sizeof(BT_HDR)));
+ BT_HDR_RIGID* p_buf =
+ reinterpret_cast<BT_HDR_RIGID*>(osi_malloc(sizeof(BT_HDR_RIGID)));
p_buf->event = BTIF_MEDIA_SINK_SUSPEND;
btif_a2dp_sink_cb.worker_thread.DoInThread(
FROM_HERE, base::BindOnce(btif_a2dp_sink_command_ready, p_buf));
@@ -426,7 +429,8 @@
void btif_a2dp_sink_on_suspended(UNUSED_ATTR tBTA_AV_SUSPEND* p_av_suspend) {
LOG_INFO("%s", __func__);
- BT_HDR* p_buf = reinterpret_cast<BT_HDR*>(osi_malloc(sizeof(BT_HDR)));
+ BT_HDR_RIGID* p_buf =
+ reinterpret_cast<BT_HDR_RIGID*>(osi_malloc(sizeof(BT_HDR_RIGID)));
p_buf->event = BTIF_MEDIA_SINK_SUSPEND;
btif_a2dp_sink_cb.worker_thread.DoInThread(
FROM_HERE, base::BindOnce(btif_a2dp_sink_command_ready, p_buf));
@@ -438,7 +442,8 @@
bool btif_a2dp_sink_on_start() {
LOG_INFO("%s", __func__);
- BT_HDR* p_buf = reinterpret_cast<BT_HDR*>(osi_malloc(sizeof(BT_HDR)));
+ BT_HDR_RIGID* p_buf =
+ reinterpret_cast<BT_HDR_RIGID*>(osi_malloc(sizeof(BT_HDR_RIGID)));
p_buf->event = BTIF_MEDIA_SINK_START;
btif_a2dp_sink_cb.worker_thread.DoInThread(
FROM_HERE, base::BindOnce(btif_a2dp_sink_command_ready, p_buf));
@@ -681,7 +686,8 @@
return;
}
- BT_HDR* p_buf = reinterpret_cast<BT_HDR*>(osi_malloc(sizeof(BT_HDR)));
+ BT_HDR_RIGID* p_buf =
+ reinterpret_cast<BT_HDR_RIGID*>(osi_malloc(sizeof(BT_HDR_RIGID)));
p_buf->event = BTIF_MEDIA_SINK_AUDIO_RX_FLUSH;
btif_a2dp_sink_cb.worker_thread.DoInThread(
FROM_HERE, base::BindOnce(btif_a2dp_sink_command_ready, p_buf));
@@ -699,7 +705,8 @@
p_buf->focus_state = state;
p_buf->hdr.event = BTIF_MEDIA_SINK_SET_FOCUS_STATE;
btif_a2dp_sink_cb.worker_thread.DoInThread(
- FROM_HERE, base::BindOnce(btif_a2dp_sink_command_ready, (BT_HDR*)p_buf));
+ FROM_HERE,
+ base::BindOnce(btif_a2dp_sink_command_ready, (BT_HDR_RIGID*)p_buf));
}
static void btif_a2dp_sink_set_focus_state_event(
@@ -728,7 +735,8 @@
static void btif_a2dp_sink_clear_track_event_req() {
LOG_INFO("%s", __func__);
- BT_HDR* p_buf = reinterpret_cast<BT_HDR*>(osi_malloc(sizeof(BT_HDR)));
+ BT_HDR_RIGID* p_buf =
+ reinterpret_cast<BT_HDR_RIGID*>(osi_malloc(sizeof(BT_HDR_RIGID)));
p_buf->event = BTIF_MEDIA_SINK_CLEAR_TRACK;
btif_a2dp_sink_cb.worker_thread.DoInThread(
diff --git a/btif/src/btif_av.cc b/btif/src/btif_av.cc
index bc41190..71e8461 100644
--- a/btif/src/btif_av.cc
+++ b/btif/src/btif_av.cc
@@ -536,6 +536,7 @@
std::set<RawAddress> silenced_peers_;
RawAddress active_peer_;
std::map<uint8_t, tBTA_AV_HNDL> peer_id2bta_handle_;
+ std::mutex mutex_;
};
class BtifAvSink {
@@ -654,6 +655,7 @@
std::map<RawAddress, BtifAvPeer*> peers_;
RawAddress active_peer_;
std::map<uint8_t, tBTA_AV_HNDL> peer_id2bta_handle_;
+ std::mutex mutex_;
};
/*****************************************************************************
@@ -1041,6 +1043,7 @@
BtifAvPeer* BtifAvSource::FindOrCreatePeer(const RawAddress& peer_address,
tBTA_AV_HNDL bta_handle) {
+ std::unique_lock<std::mutex> lock(mutex_);
BTIF_TRACE_DEBUG("%s: peer_address=%s bta_handle=0x%x", __PRETTY_FUNCTION__,
peer_address.ToString().c_str(), bta_handle);
@@ -1145,6 +1148,7 @@
}
void BtifAvSource::DeregisterAllBtaHandles() {
+ std::unique_lock<std::mutex> lock(mutex_);
for (auto it : peer_id2bta_handle_) {
tBTA_AV_HNDL bta_handle = it.second;
BTA_AvDeregister(bta_handle);
@@ -1154,6 +1158,7 @@
void BtifAvSource::BtaHandleRegistered(uint8_t peer_id,
tBTA_AV_HNDL bta_handle) {
+ std::unique_lock<std::mutex> lock(mutex_);
peer_id2bta_handle_.insert(std::make_pair(peer_id, bta_handle));
// Set the BTA Handle for the Peer (if exists)
@@ -1246,6 +1251,7 @@
BtifAvPeer* BtifAvSink::FindOrCreatePeer(const RawAddress& peer_address,
tBTA_AV_HNDL bta_handle) {
+ std::unique_lock<std::mutex> lock(mutex_);
BTIF_TRACE_DEBUG("%s: peer_address=%s bta_handle=0x%x", __PRETTY_FUNCTION__,
peer_address.ToString().c_str(), bta_handle);
@@ -1353,6 +1359,7 @@
}
void BtifAvSink::DeregisterAllBtaHandles() {
+ std::unique_lock<std::mutex> lock(mutex_);
for (auto it : peer_id2bta_handle_) {
tBTA_AV_HNDL bta_handle = it.second;
BTA_AvDeregister(bta_handle);
@@ -1361,6 +1368,7 @@
}
void BtifAvSink::BtaHandleRegistered(uint8_t peer_id, tBTA_AV_HNDL bta_handle) {
+ std::unique_lock<std::mutex> lock(mutex_);
peer_id2bta_handle_.insert(std::make_pair(peer_id, bta_handle));
// Set the BTA Handle for the Peer (if exists)
@@ -3231,6 +3239,11 @@
BTA_AV_FEAT_METADATA | BTA_AV_FEAT_VENDOR |
BTA_AV_FEAT_ADV_CTRL | BTA_AV_FEAT_RCTG |
BTA_AV_FEAT_BROWSE | BTA_AV_FEAT_COVER_ARTWORK;
+
+ if (delay_reporting_enabled()) {
+ features |= BTA_AV_FEAT_DELAY_RPT;
+ }
+
BTA_AvEnable(features, bta_av_sink_callback);
btif_av_sink.RegisterAllBtaHandles();
return BT_STATUS_SUCCESS;
@@ -3282,16 +3295,19 @@
}
void btif_av_clear_remote_suspend_flag(void) {
- BtifAvPeer* peer = btif_av_find_active_peer();
- if (peer == nullptr) {
- BTIF_TRACE_WARNING("%s: No active peer found", __func__);
- return;
- }
-
- BTIF_TRACE_DEBUG("%s: Peer %s : flags=%s are cleared", __func__,
- peer->PeerAddress().ToString().c_str(),
- peer->FlagsToString().c_str());
- peer->ClearFlags(BtifAvPeer::kFlagRemoteSuspend);
+ auto clear_remote_suspend_flag = []() {
+ BtifAvPeer* peer = btif_av_find_active_peer();
+ if (peer == nullptr) {
+ BTIF_TRACE_WARNING("%s: No active peer found", __func__);
+ return;
+ }
+ BTIF_TRACE_DEBUG("%s: Peer %s : flags=%s are cleared", __func__,
+ peer->PeerAddress().ToString().c_str(),
+ peer->FlagsToString().c_str());
+ peer->ClearFlags(BtifAvPeer::kFlagRemoteSuspend);
+ };
+ // switch to main thread to prevent a race condition of accessing peers
+ do_in_main_thread(FROM_HERE, base::Bind(clear_remote_suspend_flag));
}
bool btif_av_is_peer_edr(const RawAddress& peer_address) {
diff --git a/btif/src/btif_ble_scanner.cc b/btif/src/btif_ble_scanner.cc
index badae4e..313d7e1 100644
--- a/btif/src/btif_ble_scanner.cc
+++ b/btif/src/btif_ble_scanner.cc
@@ -288,7 +288,7 @@
jni_thread_wrapper(FROM_HERE, std::move(cb))));
}
- void SetScanParameters(int scan_interval, int scan_window,
+ void SetScanParameters(int scanner_id, int scan_interval, int scan_window,
Callback cb) override {
do_in_main_thread(
FROM_HERE, base::Bind(&BTM_BleSetScanParams, scan_interval, scan_window,
diff --git a/btif/src/btif_bqr.cc b/btif/src/btif_bqr.cc
index 7896ea2..c437b2c 100644
--- a/btif/src/btif_bqr.cc
+++ b/btif/src/btif_bqr.cc
@@ -17,7 +17,9 @@
#include <base/logging.h>
#include <errno.h>
#include <fcntl.h>
+#ifdef OS_ANDROID
#include <statslog.h>
+#endif
#include <stdio.h>
#include <sys/stat.h>
@@ -395,6 +397,7 @@
p_bqr_event->bqr_link_quality_event_.no_rx_count,
p_bqr_event->bqr_link_quality_event_.nak_count);
+#ifdef OS_ANDROID
int ret = android::util::stats_write(
android::util::BLUETOOTH_QUALITY_REPORT_REPORTED,
p_bqr_event->bqr_link_quality_event_.quality_report_id,
@@ -420,6 +423,9 @@
LOG(WARNING) << __func__ << ": failed to log BQR event to statsd, error "
<< ret;
}
+#else
+ // TODO(abps) Metrics for non-Android build
+#endif
kpBqrEventQueue->Enqueue(p_bqr_event.release());
}
diff --git a/btif/src/btif_config.cc b/btif/src/btif_config.cc
index 95e9baa..1762e72 100644
--- a/btif/src/btif_config.cc
+++ b/btif/src/btif_config.cc
@@ -73,7 +73,11 @@
using bluetooth::common::MetricIdAllocator;
// TODO(armansito): Find a better way than searching by a hardcoded path.
-#if defined(OS_GENERIC)
+#if defined(TARGET_FLOSS)
+static const char* CONFIG_FILE_PATH = "/var/lib/bluetooth/bt_config.conf";
+static const char* CONFIG_BACKUP_PATH = "/var/lib/bluetooth/bt_config.bak";
+static const char* CONFIG_LEGACY_FILE_PATH = "/var/lib/bluetooth/bt_config.xml";
+#elif defined(OS_GENERIC)
static const char* CONFIG_FILE_PATH = "bt_config.conf";
static const char* CONFIG_BACKUP_PATH = "bt_config.bak";
static const char* CONFIG_LEGACY_FILE_PATH = "bt_config.xml";
diff --git a/btif/src/btif_core.cc b/btif/src/btif_core.cc
index fe1499d..560edfe 100644
--- a/btif/src/btif_core.cc
+++ b/btif/src/btif_core.cc
@@ -69,7 +69,9 @@
#ifndef BTE_DID_CONF_FILE
// TODO(armansito): Find a better way than searching by a hardcoded path.
-#if defined(OS_GENERIC)
+#if defined(TARGET_FLOSS)
+#define BTE_DID_CONF_FILE "/var/lib/bluetooth/bt_did.conf"
+#elif defined(OS_GENERIC)
#define BTE_DID_CONF_FILE "bt_did.conf"
#else // !defined(OS_GENERIC)
#define BTE_DID_CONF_FILE "/etc/bluetooth/bt_did.conf"
diff --git a/btif/src/btif_dm.cc b/btif/src/btif_dm.cc
index 9b67e34..e6e39ce 100644
--- a/btif/src/btif_dm.cc
+++ b/btif/src/btif_dm.cc
@@ -215,7 +215,7 @@
static void btif_dm_ble_sc_oob_req_evt(tBTA_DM_SP_RMT_OOB* req_oob_type);
static void bte_scan_filt_param_cfg_evt(uint8_t action_type, uint8_t avbl_space,
- uint8_t ref_value, uint8_t status);
+ uint8_t ref_value, uint8_t btm_status);
static char* btif_get_default_local_name();
@@ -480,14 +480,16 @@
uint8_t lmp_ver = 0;
uint16_t lmp_subver = 0;
uint16_t mfct_set = 0;
- bool version_info_valid = false;
bt_remote_version_t info;
bt_status_t status;
- version_info_valid =
+ CHECK(p_bd != nullptr);
+
+ const bool version_info_valid =
BTM_ReadRemoteVersion(*p_bd, &lmp_ver, &mfct_set, &lmp_subver);
- LOG_INFO("remote version info [%s]: %x, %x, %x", p_bd->ToString().c_str(),
+ LOG_INFO("Remote version info valid:%s [%s]: %x, %x, %x",
+ logbool(version_info_valid).c_str(), PRIVATE_ADDRESS((*p_bd)),
lmp_ver, mfct_set, lmp_subver);
if (version_info_valid) {
@@ -687,7 +689,11 @@
int dev_type;
/* Remote properties update */
- if (!btif_get_device_type(p_pin_req->bd_addr, &dev_type)) {
+ if (BTM_GetPeerDeviceTypeFromFeatures(p_pin_req->bd_addr) ==
+ BT_DEVICE_TYPE_DUMO) {
+ dev_type = BT_DEVICE_TYPE_DUMO;
+ } else if (!btif_get_device_type(p_pin_req->bd_addr, &dev_type)) {
+ // Failed to get device type, defaulting to BR/EDR.
dev_type = BT_DEVICE_TYPE_BREDR;
}
btif_update_remote_properties(p_pin_req->bd_addr, p_pin_req->bd_name,
@@ -775,7 +781,11 @@
BTIF_TRACE_DEBUG("%s", __func__);
/* Remote properties update */
- if (!btif_get_device_type(p_ssp_cfm_req->bd_addr, &dev_type)) {
+ if (BTM_GetPeerDeviceTypeFromFeatures(p_ssp_cfm_req->bd_addr) ==
+ BT_DEVICE_TYPE_DUMO) {
+ dev_type = BT_DEVICE_TYPE_DUMO;
+ } else if (!btif_get_device_type(p_ssp_cfm_req->bd_addr, &dev_type)) {
+ // Failed to get device type, defaulting to BR/EDR.
dev_type = BT_DEVICE_TYPE_BREDR;
}
btif_update_remote_properties(p_ssp_cfm_req->bd_addr, p_ssp_cfm_req->bd_name,
@@ -851,7 +861,11 @@
BTIF_TRACE_DEBUG("%s", __func__);
/* Remote properties update */
- if (!btif_get_device_type(p_ssp_key_notif->bd_addr, &dev_type)) {
+ if (BTM_GetPeerDeviceTypeFromFeatures(p_ssp_key_notif->bd_addr) ==
+ BT_DEVICE_TYPE_DUMO) {
+ dev_type = BT_DEVICE_TYPE_DUMO;
+ } else if (!btif_get_device_type(p_ssp_key_notif->bd_addr, &dev_type)) {
+ // Failed to get device type, defaulting to BR/EDR.
dev_type = BT_DEVICE_TYPE_BREDR;
}
btif_update_remote_properties(
@@ -943,8 +957,15 @@
if (!bluetooth::shim::is_gd_security_enabled()) {
btif_storage_set_remote_addr_type(&bd_addr, p_auth_cmpl->addr_type);
}
+
+ int dev_type;
+ if (BTM_GetPeerDeviceTypeFromFeatures(bd_addr) == BT_DEVICE_TYPE_DUMO) {
+ dev_type = BT_DEVICE_TYPE_DUMO;
+ } else {
+ dev_type = p_auth_cmpl->dev_type;
+ }
btif_update_remote_properties(p_auth_cmpl->bd_addr, p_auth_cmpl->bd_name,
- NULL, p_auth_cmpl->dev_type);
+ NULL, dev_type);
pairing_cb.timeout_retries = 0;
status = BT_STATUS_SUCCESS;
state = BT_BOND_STATE_BONDED;
@@ -1211,8 +1232,11 @@
} break;
case BTA_DM_INQ_CMPL_EVT: {
- BTM_BleAdvFilterParamSetup(BTM_BLE_SCAN_COND_DELETE, 0, nullptr,
- base::Bind(&bte_scan_filt_param_cfg_evt, 0));
+ BTM_BleAdvFilterParamSetup(BTM_BLE_SCAN_COND_DELETE,
+ static_cast<tBTM_BLE_PF_FILT_INDEX>(0),
+ nullptr,
+ base::Bind(&bte_scan_filt_param_cfg_evt,
+ btm_status_value(BTM_SUCCESS)));
} break;
case BTA_DM_DISC_CMPL_EVT: {
invoke_discovery_state_changed_cb(BT_DISCOVERY_STOPPED);
@@ -1231,7 +1255,8 @@
btgatt_filt_param_setup_t adv_filt_param;
memset(&adv_filt_param, 0, sizeof(btgatt_filt_param_setup_t));
BTM_BleAdvFilterParamSetup(BTM_BLE_SCAN_COND_DELETE, 0, nullptr,
- base::Bind(&bte_scan_filt_param_cfg_evt, 0));
+ base::Bind(&bte_scan_filt_param_cfg_evt,
+ btm_status_value(BTM_SUCCESS)));
invoke_discovery_state_changed_cb(BT_DISCOVERY_STOPPED);
}
} break;
@@ -1778,12 +1803,13 @@
/* Scan filter param config event */
static void bte_scan_filt_param_cfg_evt(uint8_t ref_value, uint8_t avbl_space,
- uint8_t action_type, uint8_t status) {
+ uint8_t action_type,
+ uint8_t btm_status) {
/* This event occurs on calling BTA_DmBleCfgFilterCondition internally,
** and that is why there is no HAL callback
*/
- if (BTA_SUCCESS != status) {
- BTIF_TRACE_ERROR("%s, %d", __func__, status);
+ if (btm_status != btm_status_value(BTM_SUCCESS)) {
+ BTIF_TRACE_ERROR("%s, %d", __func__, btm_status);
} else {
BTIF_TRACE_DEBUG("%s", __func__);
}
@@ -1806,8 +1832,9 @@
BTIF_TRACE_EVENT("%s", __func__);
/* Cleanup anything remaining on index 0 */
- BTM_BleAdvFilterParamSetup(BTM_BLE_SCAN_COND_DELETE, 0, nullptr,
- base::Bind(&bte_scan_filt_param_cfg_evt, 0));
+ BTM_BleAdvFilterParamSetup(
+ BTM_BLE_SCAN_COND_DELETE, static_cast<tBTM_BLE_PF_FILT_INDEX>(0), nullptr,
+ base::Bind(&bte_scan_filt_param_cfg_evt, btm_status_value(BTM_SUCCESS)));
auto adv_filt_param = std::make_unique<btgatt_filt_param_setup_t>();
/* Add an allow-all filter on index 0*/
@@ -1817,9 +1844,10 @@
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;
- BTM_BleAdvFilterParamSetup(BTM_BLE_SCAN_COND_ADD, 0,
- std::move(adv_filt_param),
- base::Bind(&bte_scan_filt_param_cfg_evt, 0));
+ BTM_BleAdvFilterParamSetup(
+ BTM_BLE_SCAN_COND_ADD, static_cast<tBTM_BLE_PF_FILT_INDEX>(0),
+ std::move(adv_filt_param),
+ base::Bind(&bte_scan_filt_param_cfg_evt, btm_status_value(BTM_SUCCESS)));
/* Will be enabled to true once inquiry busy level has been received */
btif_dm_inquiry_in_progress = false;
@@ -2264,17 +2292,18 @@
*
******************************************************************************/
void btif_dm_generate_local_oob_data(tBT_TRANSPORT transport) {
+ LOG_DEBUG("Transport %s", bt_transport_text(transport).c_str());
if (transport == BT_TRANSPORT_BR_EDR) {
BTM_ReadLocalOobData();
} else if (transport == BT_TRANSPORT_LE) {
- // TODO(184377951): Call LE Implementation (not yet implemented?)
- } else {
- BTIF_TRACE_ERROR("Bad transport type! %d", transport);
+ SMP_CrLocScOobData(base::BindOnce(&btif_dm_proc_loc_oob));
}
}
-void btif_dm_proc_loc_oob(bool valid, const Octet16& c, const Octet16& r) {
- invoke_oob_data_request_cb(BT_TRANSPORT_BR_EDR, valid, c, r);
+void btif_dm_proc_loc_oob(tBT_TRANSPORT transport, bool is_valid,
+ const Octet16& c, const Octet16& r) {
+ invoke_oob_data_request_cb(transport, is_valid, c, r,
+ *controller_get_interface()->get_address());
}
/*******************************************************************************
diff --git a/btif/src/btif_gatt_client.cc b/btif/src/btif_gatt_client.cc
index 507f37a..9fb09c6 100644
--- a/btif/src/btif_gatt_client.cc
+++ b/btif/src/btif_gatt_client.cc
@@ -234,7 +234,7 @@
static void bta_gattc_cback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
LOG_DEBUG(" gatt client callback event:%s [%d]",
- GattClientEventText(event).c_str(), event);
+ gatt_client_event_text(event).c_str(), event);
bt_status_t status =
btif_transfer_context(btif_gattc_upstreams_evt, (uint16_t)event,
(char*)p_data, sizeof(tBTA_GATTC), NULL);
diff --git a/btif/src/btif_gatt_test.cc b/btif/src/btif_gatt_test.cc
index 697c6ed..02216c7 100644
--- a/btif/src/btif_gatt_test.cc
+++ b/btif/src/btif_gatt_test.cc
@@ -180,8 +180,9 @@
if (params->u1) {
std::array<uint8_t, Uuid::kNumBytes128> tmp;
tmp.fill(0xAE);
- test_cb.gatt_if = GATT_Register(bluetooth::Uuid::From128BitBE(tmp),
- &btif_test_callbacks, false);
+ test_cb.gatt_if =
+ GATT_Register(bluetooth::Uuid::From128BitBE(tmp),
+ std::string("GattTest"), &btif_test_callbacks, false);
GATT_StartIf(test_cb.gatt_if);
} else {
GATT_Deregister(test_cb.gatt_if);
diff --git a/btif/src/btif_gatt_util.cc b/btif/src/btif_gatt_util.cc
index 132fead..e6bbf38 100644
--- a/btif/src/btif_gatt_util.cc
+++ b/btif/src/btif_gatt_util.cc
@@ -59,7 +59,6 @@
* Encrypted link map handling
******************************************************************************/
-#if (BLE_DELAY_REQUEST_ENC == FALSE)
static bool btif_gatt_is_link_encrypted(const RawAddress& bd_addr) {
return BTM_IsEncrypted(bd_addr, BT_TRANSPORT_BR_EDR) ||
BTM_IsEncrypted(bd_addr, BT_TRANSPORT_LE);
@@ -72,9 +71,7 @@
BTIF_TRACE_WARNING("%s() - Encryption failed (%d)", __func__, result);
}
}
-#endif
-#if (BLE_DELAY_REQUEST_ENC == FALSE)
void btif_gatt_check_encrypted_link(RawAddress bd_addr,
tBT_TRANSPORT transport_link) {
tBTM_LE_PENC_KEYS key;
@@ -84,15 +81,11 @@
!btif_gatt_is_link_encrypted(bd_addr)) {
LOG_DEBUG("Checking gatt link peer:%s transport:%s",
PRIVATE_ADDRESS(bd_addr),
- BtTransportText(transport_link).c_str());
+ bt_transport_text(transport_link).c_str());
BTA_DmSetEncryption(bd_addr, transport_link, &btif_gatt_set_encryption_cb,
BTM_BLE_SEC_ENCRYPT);
}
}
-#else
-void btif_gatt_check_encrypted_link(UNUSED_ATTR RawAddress bd_addr,
- UNUSED_ATTR tBT_TRANSPORT transport_link) {}
-#endif
void btif_gatt_move_track_adv_data(btgatt_track_adv_info_t* p_dest,
btgatt_track_adv_info_t* p_src) {
diff --git a/btif/src/btif_hh.cc b/btif/src/btif_hh.cc
index ef55826..0d00a6f 100644
--- a/btif/src/btif_hh.cc
+++ b/btif/src/btif_hh.cc
@@ -432,7 +432,7 @@
if (p_added_dev->bd_addr == bd_addr) {
BTA_HhRemoveDev(p_added_dev->dev_handle);
btif_storage_remove_hid_info(p_added_dev->bd_addr);
- memset(&(p_added_dev->bd_addr), 0, 6);
+ p_added_dev->bd_addr = RawAddress::kEmpty;
p_added_dev->dev_handle = BTA_HH_INVALID_HANDLE;
break;
}
@@ -1146,13 +1146,13 @@
******************************************************************************/
static void btif_hh_handle_evt(uint16_t event, char* p_param) {
+ CHECK(p_param != nullptr);
RawAddress* bd_addr = (RawAddress*)p_param;
- BTIF_TRACE_EVENT("%s: event=%d", __func__, event);
- int ret;
switch (event) {
case BTIF_HH_CONNECT_REQ_EVT: {
- ret = btif_hh_connect(bd_addr);
- if (ret == BT_STATUS_SUCCESS) {
+ LOG_DEBUG("Connect request received remote:%s",
+ PRIVATE_ADDRESS((*bd_addr)));
+ if (btif_hh_connect(bd_addr) == BT_STATUS_SUCCESS) {
HAL_CBACK(bt_hh_callbacks, connection_state_cb, bd_addr,
BTHH_CONN_STATE_CONNECTING);
} else
@@ -1161,19 +1161,25 @@
} break;
case BTIF_HH_DISCONNECT_REQ_EVT: {
- BTIF_TRACE_EVENT("%s: event=%d", __func__, event);
+ LOG_DEBUG("Disconnect request received remote:%s",
+ PRIVATE_ADDRESS((*bd_addr)));
btif_hh_disconnect(bd_addr);
HAL_CBACK(bt_hh_callbacks, connection_state_cb, bd_addr,
BTHH_CONN_STATE_DISCONNECTING);
} break;
case BTIF_HH_VUP_REQ_EVT: {
- BTIF_TRACE_EVENT("%s: event=%d", __func__, event);
- ret = btif_hh_virtual_unplug(bd_addr);
+ LOG_DEBUG("Virtual unplug request received remote:%s",
+ PRIVATE_ADDRESS((*bd_addr)));
+ if (btif_hh_virtual_unplug(bd_addr) != BT_STATUS_SUCCESS) {
+ LOG_WARN("Unable to virtual unplug device remote:%s",
+ PRIVATE_ADDRESS((*bd_addr)));
+ }
} break;
default: {
- BTIF_TRACE_WARNING("%s : Unknown event 0x%x", __func__, event);
+ LOG_WARN("Unknown event received:%d remote:%s", event,
+ PRIVATE_ADDRESS((*bd_addr)));
} break;
}
}
diff --git a/btif/src/btif_rc.cc b/btif/src/btif_rc.cc
index 99079cf..44ba06d 100644
--- a/btif/src/btif_rc.cc
+++ b/btif/src/btif_rc.cc
@@ -667,6 +667,7 @@
BTIF_TRACE_ERROR("%s: Connect failed with error code: %d", __func__,
p_rc_open->status);
p_dev->rc_connected = false;
+ return;
}
// check if already some RC is connected
@@ -4955,8 +4956,7 @@
memcpy(avrc_cmd.play_item.uid, uid, AVRC_UID_SIZE);
avrc_cmd.play_item.uid_counter = uid_counter;
- return build_and_send_browsing_cmd(&avrc_cmd, p_dev);
- // return build_and_send_vendor_cmd(&avrc_cmd, AVRC_CMD_CTRL, p_dev);
+ return build_and_send_vendor_cmd(&avrc_cmd, AVRC_CMD_CTRL, p_dev);
}
/***************************************************************************
diff --git a/btif/src/btif_sock_l2cap.cc b/btif/src/btif_sock_l2cap.cc
index e373144..a5a9857 100644
--- a/btif/src/btif_sock_l2cap.cc
+++ b/btif/src/btif_sock_l2cap.cc
@@ -624,6 +624,7 @@
sock->id);
BTA_JvL2capClose(sock->handle);
btsock_l2cap_free_l(sock);
+ return;
}
}
}
diff --git a/btif/src/btif_storage.cc b/btif/src/btif_storage.cc
index 90234bc..8a20518 100644
--- a/btif/src/btif_storage.cc
+++ b/btif/src/btif_storage.cc
@@ -83,6 +83,7 @@
#define BTIF_STORAGE_KEY_ADAPTER_DISC_TIMEOUT "DiscoveryTimeout"
#define BTIF_STORAGE_KEY_GATT_CLIENT_SUPPORTED "GattClientSupportedFeatures"
#define BTIF_STORAGE_KEY_GATT_CLIENT_DB_HASH "GattClientDatabaseHash"
+#define BTIF_STORAGE_KEY_GATT_SERVER_SUPPORTED "GattServerSupportedFeatures"
/* This is a local property to add a device found */
#define BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP 0xFF
@@ -855,6 +856,9 @@
if (btif_config_exist(bdstr, BTIF_STORAGE_KEY_GATT_CLIENT_DB_HASH)) {
ret &= btif_config_remove(bdstr, BTIF_STORAGE_KEY_GATT_CLIENT_DB_HASH);
}
+ if (btif_config_exist(bdstr, BTIF_STORAGE_KEY_GATT_SERVER_SUPPORTED)) {
+ ret &= btif_config_remove(bdstr, BTIF_STORAGE_KEY_GATT_SERVER_SUPPORTED);
+ }
/* write bonded info immediately */
btif_config_flush();
@@ -1660,6 +1664,34 @@
return true;
}
+/** Stores information about GATT server supported features */
+void btif_storage_set_gatt_sr_supp_feat(const RawAddress& addr, uint8_t feat) {
+ do_in_jni_thread(
+ FROM_HERE, Bind(
+ [](const RawAddress& addr, uint8_t feat) {
+ std::string bdstr = addr.ToString();
+ VLOG(2)
+ << "GATT server supported features for: " << bdstr
+ << " features: " << +feat;
+ btif_config_set_int(
+ bdstr, BTIF_STORAGE_KEY_GATT_SERVER_SUPPORTED, feat);
+ btif_config_save();
+ },
+ addr, feat));
+}
+
+/** Gets information about GATT server supported features */
+uint8_t btif_storage_get_sr_supp_feat(const RawAddress& bd_addr) {
+ auto name = bd_addr.ToString();
+
+ int value = 0;
+ btif_config_get_int(name, BTIF_STORAGE_KEY_GATT_SERVER_SUPPORTED, &value);
+ BTIF_TRACE_DEBUG("Remote device: %s GATT server supported features 0x%02x",
+ name.c_str(), value);
+
+ return value;
+}
+
/*******************************************************************************
*
* Function btif_storage_is_restricted_device
diff --git a/btif/test/btif_stack_test.cc b/btif/test/btif_stack_test.cc
index 0d99b47..8b3cfae 100644
--- a/btif/test/btif_stack_test.cc
+++ b/btif/test/btif_stack_test.cc
@@ -26,6 +26,7 @@
#include "bta/include/bta_ag_api.h" // tBTA_AG_RES_DATA::kEmpty
#include "hci/include/hci_layer.h" // hci_t
+#include "test/mock/mock_hci_layer.h"
std::map<std::string, int> mock_function_count_map;
@@ -166,7 +167,6 @@
.transmit_command_futured = transmit_command_futured,
.transmit_downward = transmit_downward,
};
-const hci_t* hci_layer_get_interface() { return &mock_hci; }
bool is_bluetooth_uid() { return false; }
const tBTA_AG_RES_DATA tBTA_AG_RES_DATA::kEmpty = {};
@@ -181,7 +181,10 @@
class StackCycleTest : public ::testing::Test {
protected:
- void SetUp() override { stack_manager_ = stack_manager_get_interface(); }
+ void SetUp() override {
+ test::mock::hci_layer::hci_layer_get_interface.hci = &mock_hci;
+ stack_manager_ = stack_manager_get_interface();
+ }
void TearDown() override { stack_manager_ = nullptr; }
const stack_manager_t* stack_manager_{nullptr};
diff --git a/build.py b/build.py
index 131cbb2..808c808 100755
--- a/build.py
+++ b/build.py
@@ -61,11 +61,21 @@
'tools', # Build the host tools (i.e. packetgen)
'rust', # Build only the rust components + copy artifacts to output dir
'main', # Build the main C++ codebase
- 'test', # Build and run the unit tests
+ 'test', # Run the unit tests
'clean', # Clean up output directory
'all', # All targets except test and clean
]
+HOST_TESTS = [
+ 'bluetooth_test_common',
+ 'bluetoothtbd_test',
+ 'net_test_avrcp',
+ 'net_test_btcore',
+ 'net_test_types',
+ 'net_test_btm_iso',
+ 'net_test_btpackets',
+]
+
class UseFlags():
@@ -110,6 +120,7 @@
self.jobs = self.args.jobs
if not self.jobs:
self.jobs = multiprocessing.cpu_count()
+ print("Number of jobs = {}".format(self.jobs))
# Normalize all directories
self.output_dir = os.path.abspath(self.args.output)
@@ -123,7 +134,13 @@
if hasattr(self.args, 'target') and self.args.target:
self.target = self.args.target
- self.use = UseFlags(self.args.use if self.args.use else [])
+ target_use = self.args.use if self.args.use else []
+
+ # Unless set, always build test code
+ if not self.args.notest:
+ target_use.append('test')
+
+ self.use = UseFlags(target_use)
# Validate platform directory
assert os.path.isdir(self.platform_dir), 'Platform dir does not exist'
@@ -137,6 +154,18 @@
self.configure_environ()
+ def _generate_rustflags(self):
+ """ Rustflags to include for the build.
+ """
+ rust_flags = [
+ '-L',
+ '{}/out/Default/'.format(self.output_dir),
+ '-C',
+ 'link-arg=-Wl,--allow-multiple-definition',
+ ]
+
+ return ' '.join(rust_flags)
+
def configure_environ(self):
""" Configure environment variables for GN and Cargo.
"""
@@ -150,6 +179,8 @@
# Configure Rust env variables
self.env['CARGO_TARGET_DIR'] = self.output_dir
self.env['CARGO_HOME'] = os.path.join(self.output_dir, 'cargo_home')
+ self.env['RUSTFLAGS'] = self._generate_rustflags()
+ self.env['CXX_ROOT_PATH'] = os.path.join(self.platform_dir, 'bt')
# Configure some GN variables
if self.use_board:
@@ -364,7 +395,15 @@
def _target_test(self):
""" Runs the host tests.
"""
- raise Exception('Not yet implemented')
+ # Rust tests first
+ self.run_command('test', ['cargo', 'test'], cwd=os.path.join(self.platform_dir, 'bt'), env=self.env)
+
+ # Host tests second based on host test list
+ for t in HOST_TESTS:
+ self.run_command(
+ 'test', [os.path.join(self.output_dir, 'out/Default', t)],
+ cwd=os.path.join(self.output_dir),
+ env=self.env)
def _target_clean(self):
""" Delete the output directory entirely.
@@ -376,8 +415,8 @@
"""
self._target_prepare()
self._target_tools()
- self._target_rust()
self._target_main()
+ self._target_rust()
def build(self):
""" Builds according to self.target
@@ -393,8 +432,6 @@
elif self.target == 'main':
self._target_main()
elif self.target == 'test':
- self.use.set_flag('test')
- self._target_all()
self._target_test()
elif self.target == 'clean':
self._target_clean()
@@ -406,14 +443,15 @@
parser = argparse.ArgumentParser(description='Simple build for host.')
parser.add_argument('--output', help='Output directory for the build.', required=True)
parser.add_argument('--platform-dir', help='Directory where platform2 is staged.', required=True)
- parser.add_argument('--clang', help='Use clang compiler.', default=False, action="store_true")
+ parser.add_argument('--clang', help='Use clang compiler.', default=False, action='store_true')
parser.add_argument('--use', help='Set a specific use flag.')
+ parser.add_argument('--notest', help="Don't compile test code.", default=False, action='store_true')
parser.add_argument('--target', help='Run specific build target')
parser.add_argument('--sysroot', help='Set a specific sysroot path', default='/')
parser.add_argument('--libdir', help='Libdir - default = usr/lib64', default='usr/lib64')
parser.add_argument('--use-board', help='Use a built x86 board for dependencies. Provide path.')
parser.add_argument('--jobs', help='Number of jobs to run', default=0, type=int)
- parser.add_argument('--vendored-rust', help='Use vendored rust crates', default=False, action="store_true")
+ parser.add_argument('--vendored-rust', help='Use vendored rust crates', default=False, action='store_true')
parser.add_argument('--verbose', help='Verbose logs for build.')
args = parser.parse_args()
diff --git a/build/dpkg/README.txt b/build/dpkg/README.txt
new file mode 100644
index 0000000..7850796
--- /dev/null
+++ b/build/dpkg/README.txt
@@ -0,0 +1,25 @@
+This directory contains scripts to build Debian packages as dependencies for
+building Fluoride on Linux.
+
+To generate the Debian packages, you need:
+
+* Debian 10 (Buster)
+* gn, get binary from https://chrome-infra-packages.appspot.com/dl/gn/gn/linux-amd64/+/latest
+* apt-get install git debmake
+* Other build dependencies are package dependent, you will get error message
+ mentioning the list of missing packages
+
+Steps to build debian packages (modp_b64 first):
+```
+$ cd build/dpkg/modp_b64
+$ ./gen-src-pkg /tmp/modp_b64
+```
+
+If the above succeeded, there will be a .deb file in /tmp/modp_b64. You can
+install this binary package locally like:
+```
+$ sudo dpkg -i /tmp/modp_b64/modp-b64_0.0.1-1_amd64.deb
+```
+
+After installing modp_b64, you can do the same steps with libchrome in
+build/dpkg/libchrome.
diff --git a/build/dpkg/libchrome-822064/debian/README.Debian b/build/dpkg/libchrome-822064/debian/README.Debian
new file mode 100644
index 0000000..773bbf3
--- /dev/null
+++ b/build/dpkg/libchrome-822064/debian/README.Debian
@@ -0,0 +1 @@
+libchrome for Debian
diff --git a/build/dpkg/libchrome-822064/debian/changelog b/build/dpkg/libchrome-822064/debian/changelog
new file mode 100644
index 0000000..113a5e7
--- /dev/null
+++ b/build/dpkg/libchrome-822064/debian/changelog
@@ -0,0 +1,5 @@
+libchrome (822064-1) buster; urgency=low
+
+ * Initial release.
+
+ -- Sonny Sasaka <sonnysasaka@chromium.org> Fri, 30 Apr 2021 19:41:40 +0000
diff --git a/build/dpkg/libchrome-822064/debian/compat b/build/dpkg/libchrome-822064/debian/compat
new file mode 100644
index 0000000..f599e28
--- /dev/null
+++ b/build/dpkg/libchrome-822064/debian/compat
@@ -0,0 +1 @@
+10
diff --git a/build/dpkg/libchrome-822064/debian/control b/build/dpkg/libchrome-822064/debian/control
new file mode 100644
index 0000000..b11c23f
--- /dev/null
+++ b/build/dpkg/libchrome-822064/debian/control
@@ -0,0 +1,28 @@
+Source: libchrome
+Section: libs
+Priority: optional
+Maintainer: Sonny Sasaka <sonnysasaka@chromium.org>
+Standards-Version: 4.1.4
+Homepage: https://chromium.googlesource.com/aosp/platform/external/libchrome/
+Build-Depends:
+ debhelper (>=11~),
+ clang,
+ python3,
+ pkg-config,
+ ninja-build,
+ libglib2.0-dev,
+ libevent-dev,
+ libnss3-dev,
+ libdbus-1-dev,
+ libprotobuf-dev,
+ googletest,
+ libre2-dev,
+ libdouble-conversion-dev,
+ libssl-dev,
+ libabsl-dev
+
+Package: libchrome
+Architecture: any
+Multi-Arch: foreign
+Depends: ${misc:Depends}, ${shlibs:Depends}
+Description: Chromium's base library
diff --git a/build/dpkg/libchrome-822064/debian/install_headers.sh b/build/dpkg/libchrome-822064/debian/install_headers.sh
new file mode 100755
index 0000000..7157b14
--- /dev/null
+++ b/build/dpkg/libchrome-822064/debian/install_headers.sh
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+destdir="$1"
+
+header_dirs=(
+ base
+ base/allocator
+ base/containers
+ base/debug
+ base/files
+ base/hash
+ base/i18n
+ base/json
+ base/memory
+ base/message_loop
+ base/metrics
+ base/numerics
+ base/posix
+ base/process
+ base/ranges
+ base/strings
+ base/synchronization
+ base/system
+ base/task
+ base/task/common
+ base/task/sequence_manager
+ base/task/thread_pool
+ base/test
+ base/third_party/icu
+ base/third_party/nspr
+ base/third_party/valgrind
+ base/threading
+ base/time
+ base/timer
+ base/trace_event
+ base/trace_event/common
+ build
+ components/policy
+ components/policy/core/common
+ testing/gmock/include/gmock
+ testing/gtest/include/gtest
+ dbus
+ third_party/abseil-cpp/absl/types
+ )
+
+# Install header files.
+for d in "${header_dirs[@]}" ; do
+ mkdir -p "${destdir}/usr/include/libchrome/${d}"
+ cp libchrome/"${d}"/*.h "${destdir}/usr/include/libchrome/${d}"
+done
diff --git a/build/dpkg/libchrome-822064/debian/libchrome.install b/build/dpkg/libchrome-822064/debian/libchrome.install
new file mode 100644
index 0000000..9d381c1
--- /dev/null
+++ b/build/dpkg/libchrome-822064/debian/libchrome.install
@@ -0,0 +1,4 @@
+out/Release/lib/libbase*.so /usr/lib
+out/Release/libbase*.a /usr/lib
+out/Release/obj/libchrome/libchrome*.pc /usr/lib/pkgconfig
+usr/include /usr
diff --git a/build/dpkg/libchrome-822064/debian/patches/0001-Add-missing-includes.patch b/build/dpkg/libchrome-822064/debian/patches/0001-Add-missing-includes.patch
new file mode 100644
index 0000000..a2f2b4b
--- /dev/null
+++ b/build/dpkg/libchrome-822064/debian/patches/0001-Add-missing-includes.patch
@@ -0,0 +1,37 @@
+From 50a4636886c958717213856132fcbb57c3b8ea2a Mon Sep 17 00:00:00 2001
+From: Sonny Sasaka <sonnysasaka@chromium.org>
+Date: Fri, 19 Mar 2021 16:18:07 -0700
+Subject: [PATCH] Add missing includes
+
+---
+ base/hash/md5.cc | 1 +
+ crypto/p224_spake.cc | 1 +
+ 2 files changed, 2 insertions(+)
+
+diff --git a/libchrome/base/hash/md5.cc b/libchrome/base/hash/md5.cc
+index bdb9990a9..ef8954eaf 100644
+--- a/libchrome/base/hash/md5.cc
++++ b/libchrome/base/hash/md5.cc
+@@ -24,6 +24,7 @@
+ #include "base/hash/md5.h"
+
+ #include <stddef.h>
++#include <string.h>
+
+ namespace {
+
+diff --git a/libchrome/crypto/p224_spake.cc b/libchrome/crypto/p224_spake.cc
+index 157410537..de0af5466 100644
+--- a/libchrome/crypto/p224_spake.cc
++++ b/libchrome/crypto/p224_spake.cc
+@@ -8,6 +8,7 @@
+ #include <crypto/p224_spake.h>
+
+ #include <algorithm>
++#include <string.h>
+
+ #include <base/logging.h>
+ #include <crypto/p224.h>
+--
+2.20.1
+
diff --git a/build/dpkg/libchrome-822064/debian/patches/0001-Remove-absl-from-pkgconfig.patch b/build/dpkg/libchrome-822064/debian/patches/0001-Remove-absl-from-pkgconfig.patch
new file mode 100644
index 0000000..73b8c48
--- /dev/null
+++ b/build/dpkg/libchrome-822064/debian/patches/0001-Remove-absl-from-pkgconfig.patch
@@ -0,0 +1,33 @@
+From 9c93da57cc206ce3d301786b7ef733197ee92939 Mon Sep 17 00:00:00 2001
+From: Sonny Sasaka <sonnysasaka@chromium.org>
+Date: Fri, 30 Apr 2021 17:49:14 -0700
+Subject: [PATCH] Remove absl from pkgconfig
+
+Change-Id: Ia54bb1c58056b1d7adab668e77ef98ffb15f41c6
+---
+ BUILD.gn | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/libchrome/BUILD.gn b/libchrome/BUILD.gn
+index 402ed4c725..7778aa0163 100644
+--- a/libchrome/BUILD.gn
++++ b/libchrome/BUILD.gn
+@@ -90,7 +90,6 @@ libbase_sublibs = [
+ "modp_b64",
+ ]
+ pkg_deps = [
+- "absl",
+ "glib-2.0",
+ "libevent",
+ ]
+@@ -460,7 +459,6 @@ if (use.dbus) {
+ name = "base-dbus"
+ deps = [ ":base-core" ]
+ pkg_deps = [
+- "absl",
+ "dbus-1",
+ ]
+ if (use.fuzzer) {
+--
+2.31.0
+
diff --git a/build/dpkg/libchrome-822064/debian/patches/0001-rebase_path-for-write_args.patch b/build/dpkg/libchrome-822064/debian/patches/0001-rebase_path-for-write_args.patch
new file mode 100644
index 0000000..9b359c0
--- /dev/null
+++ b/build/dpkg/libchrome-822064/debian/patches/0001-rebase_path-for-write_args.patch
@@ -0,0 +1,34 @@
+From 6875449497baf026fb8228668930a715ffcc7082 Mon Sep 17 00:00:00 2001
+From: Sonny Sasaka <sonnysasaka@chromium.org>
+Date: Fri, 19 Mar 2021 16:56:59 -0700
+Subject: [PATCH] rebase_path for write_args
+
+---
+ BUILD.gn | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/libchrome/BUILD.gn b/libchrome/BUILD.gn
+index a846d8f52..66ac10a55 100644
+--- a/libchrome/BUILD.gn
++++ b/libchrome/BUILD.gn
+@@ -556,7 +556,7 @@ action("base") {
+
+ script = "//common-mk/write_args.py"
+ outputs = [ "${root_out_dir}/lib/lib${target_name}.so" ]
+- args = [ "--output" ] + outputs + [ "--" ] + [
++ args = [ "--output" ] + rebase_path(outputs) + [ "--" ] + [
+ "GROUP",
+ "(",
+ "AS_NEEDED",
+@@ -618,7 +618,7 @@ action("base-test") {
+
+ script = "//common-mk/write_args.py"
+ outputs = [ "${root_out_dir}/lib${target_name}.a" ]
+- args = [ "--output" ] + outputs + [ "--" ] + [
++ args = [ "--output" ] + rebase_path(outputs) + [ "--" ] + [
+ "GROUP",
+ "(",
+ "AS_NEEDED",
+--
+2.20.1
+
diff --git a/build/dpkg/libchrome-822064/debian/patches/series b/build/dpkg/libchrome-822064/debian/patches/series
new file mode 100644
index 0000000..9128588
--- /dev/null
+++ b/build/dpkg/libchrome-822064/debian/patches/series
@@ -0,0 +1,3 @@
+0001-Add-missing-includes.patch
+0001-rebase_path-for-write_args.patch
+0001-Remove-absl-from-pkgconfig.patch
diff --git a/build/dpkg/libchrome-822064/debian/rules b/build/dpkg/libchrome-822064/debian/rules
new file mode 100755
index 0000000..7d23a54
--- /dev/null
+++ b/build/dpkg/libchrome-822064/debian/rules
@@ -0,0 +1,38 @@
+#!/usr/bin/make -f
+
+# gn args
+defines =
+defines += pkg_config=\"pkg-config\"
+defines += libbase_ver=\"822064\"
+defines += platform2_root=\"$(shell pwd)/\"
+defines += platform_subdir=\"libchrome\"
+defines += cxx=\"clang++\"
+defines += cc=\"clang\"
+defines += ar=\"ar\"
+defines += external_cxxflags=[\"-I/usr/src/googletest/googletest/include\", \"-I/usr/src/googletest/googlemock/include\"]
+defines += external_ldflags=[\"-latomic\", \"-labsl_base\", \"-labsl_bad_variant_access\"]
+defines += enable_werror=false
+defines += libdir=\"/usr/lib\"
+defines += use={mojo=false asan=false coverage=false crypto=true dbus=true fuzzer=false timers=true cros_host=false profiling=false tcmalloc=false}
+
+# handle parallel build options
+njobs=1
+ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
+njobs=$(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
+endif
+
+%:
+ dh $@ --parallel
+
+override_dh_auto_build-arch:
+ gn gen out/Release --args="$(defines)"
+ ninja -j$(njobs) -C out/Release
+
+override_dh_auto_clean:
+ rm -rf out
+ find . -name \*.pyc -execdir rm -f {} \;
+ dh_auto_clean
+
+override_dh_auto_install-arch:
+ dh_auto_install
+ debian/install_headers.sh debian/tmp
diff --git a/build/dpkg/libchrome-822064/gen-src-pkg.sh b/build/dpkg/libchrome-822064/gen-src-pkg.sh
new file mode 100755
index 0000000..cbb5dce
--- /dev/null
+++ b/build/dpkg/libchrome-822064/gen-src-pkg.sh
@@ -0,0 +1,60 @@
+#!/bin/bash
+# Generates Debian source and binary packages of libchrome.
+
+if [ -z "$1" ]; then
+ echo "Usage: gen-src-pkg.sh <output-dir>"
+ exit 1
+fi
+
+outdir="$1"
+pkgdir=libchrome-822064
+origtar=libchrome_822064.orig.tar.gz
+scriptdir="$( cd "$( dirname "$0" )" && pwd )"
+branch=release-R91-13904.B
+
+tmpdir=$(mktemp -d)
+echo Generating source package in "${tmpdir}".
+
+# Download platform2 source.
+cd "${tmpdir}"
+git clone --branch "${branch}" https://chromium.googlesource.com/chromiumos/platform2 || exit 1
+mkdir "${pkgdir}"
+cd "${pkgdir}"
+# Trim platform2, only common-mk is needed.
+cp -a ../platform2/{common-mk,.gn} .
+
+# Download libchrome source and apply Chrome OS's patches.
+git clone --branch "${branch}" https://chromium.googlesource.com/aosp/platform/external/libchrome || exit 1
+cd libchrome
+rm -rf .git
+while read -r patch; do
+ patch -p1 < "libchrome_tools/patches/${patch}"
+done < <(grep -E '^[^#]' "libchrome_tools/patches/patches")
+
+# Clean up temporary platform2 checkout.
+cd ../..
+rm -rf platform2
+
+# Debian requires creating .orig.tar.gz.
+tar czf "${origtar}" "${pkgdir}"
+
+# Debianize the source.
+cd "${pkgdir}"
+yes | debmake || exit 1
+cp -aT "${scriptdir}/debian/" "${tmpdir}/${pkgdir}/debian/"
+
+# Build source package and binary package.
+cd "${tmpdir}/${pkgdir}"
+dpkg-buildpackage --no-sign || exit 1
+
+# Copy the results to output dir.
+cd "${tmpdir}"
+mkdir -p "${outdir}/src"
+cp *.dsc *.orig.tar.gz *.debian.tar.xz "${outdir}/src"
+cp *.deb "${outdir}"
+cd /
+
+echo Removing temporary directory "${tmpdir}".
+rm -rf "${tmpdir}"
+
+echo Done. Check out Debian source package in "${outdir}".
diff --git a/build/dpkg/libchrome/debian/README.Debian b/build/dpkg/libchrome/debian/README.Debian
new file mode 100644
index 0000000..773bbf3
--- /dev/null
+++ b/build/dpkg/libchrome/debian/README.Debian
@@ -0,0 +1 @@
+libchrome for Debian
diff --git a/build/dpkg/libchrome/debian/changelog b/build/dpkg/libchrome/debian/changelog
new file mode 100644
index 0000000..3cdedf6
--- /dev/null
+++ b/build/dpkg/libchrome/debian/changelog
@@ -0,0 +1,5 @@
+libchrome (780652-1) buster; urgency=low
+
+ * Initial release.
+
+ -- Sonny Sasaka <sonnysasaka@chromium.org> Fri, 19 Mar 2021 19:41:40 +0000
diff --git a/build/dpkg/libchrome/debian/compat b/build/dpkg/libchrome/debian/compat
new file mode 100644
index 0000000..f599e28
--- /dev/null
+++ b/build/dpkg/libchrome/debian/compat
@@ -0,0 +1 @@
+10
diff --git a/build/dpkg/libchrome/debian/control b/build/dpkg/libchrome/debian/control
new file mode 100644
index 0000000..d804b4d
--- /dev/null
+++ b/build/dpkg/libchrome/debian/control
@@ -0,0 +1,27 @@
+Source: libchrome
+Section: libs
+Priority: optional
+Maintainer: Sonny Sasaka <sonnysasaka@chromium.org>
+Standards-Version: 4.1.4
+Homepage: https://chromium.googlesource.com/aosp/platform/external/libchrome/
+Build-Depends:
+ debhelper (>=11~),
+ clang,
+ python3,
+ pkg-config,
+ ninja-build,
+ libglib2.0-dev,
+ libevent-dev,
+ libnss3-dev,
+ libdbus-1-dev,
+ libprotobuf-dev,
+ googletest,
+ libre2-dev,
+ libdouble-conversion-dev,
+ libssl-dev
+
+Package: libchrome
+Architecture: any
+Multi-Arch: foreign
+Depends: ${misc:Depends}, ${shlibs:Depends}
+Description: Chromium's base library
diff --git a/build/dpkg/libchrome/debian/install_headers.sh b/build/dpkg/libchrome/debian/install_headers.sh
new file mode 100755
index 0000000..19cb5ef
--- /dev/null
+++ b/build/dpkg/libchrome/debian/install_headers.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+destdir="$1"
+
+header_dirs=(
+ base
+ base/allocator
+ base/containers
+ base/debug
+ base/files
+ base/hash
+ base/i18n
+ base/json
+ base/memory
+ base/message_loop
+ base/metrics
+ base/numerics
+ base/posix
+ base/process
+ base/strings
+ base/synchronization
+ base/system
+ base/task
+ base/task/common
+ base/task/sequence_manager
+ base/task/thread_pool
+ base/test
+ base/third_party/icu
+ base/third_party/nspr
+ base/third_party/valgrind
+ base/threading
+ base/time
+ base/timer
+ base/trace_event
+ base/trace_event/common
+ build
+ components/policy
+ components/policy/core/common
+ testing/gmock/include/gmock
+ testing/gtest/include/gtest
+ dbus
+ )
+
+# Install header files.
+for d in "${header_dirs[@]}" ; do
+ mkdir -p "${destdir}/usr/include/libchrome/${d}"
+ cp libchrome/"${d}"/*.h "${destdir}/usr/include/libchrome/${d}"
+done
diff --git a/build/dpkg/libchrome/debian/libchrome.install b/build/dpkg/libchrome/debian/libchrome.install
new file mode 100644
index 0000000..9d381c1
--- /dev/null
+++ b/build/dpkg/libchrome/debian/libchrome.install
@@ -0,0 +1,4 @@
+out/Release/lib/libbase*.so /usr/lib
+out/Release/libbase*.a /usr/lib
+out/Release/obj/libchrome/libchrome*.pc /usr/lib/pkgconfig
+usr/include /usr
diff --git a/build/dpkg/libchrome/debian/patches/0001-Add-missing-includes.patch b/build/dpkg/libchrome/debian/patches/0001-Add-missing-includes.patch
new file mode 100644
index 0000000..a2f2b4b
--- /dev/null
+++ b/build/dpkg/libchrome/debian/patches/0001-Add-missing-includes.patch
@@ -0,0 +1,37 @@
+From 50a4636886c958717213856132fcbb57c3b8ea2a Mon Sep 17 00:00:00 2001
+From: Sonny Sasaka <sonnysasaka@chromium.org>
+Date: Fri, 19 Mar 2021 16:18:07 -0700
+Subject: [PATCH] Add missing includes
+
+---
+ base/hash/md5.cc | 1 +
+ crypto/p224_spake.cc | 1 +
+ 2 files changed, 2 insertions(+)
+
+diff --git a/libchrome/base/hash/md5.cc b/libchrome/base/hash/md5.cc
+index bdb9990a9..ef8954eaf 100644
+--- a/libchrome/base/hash/md5.cc
++++ b/libchrome/base/hash/md5.cc
+@@ -24,6 +24,7 @@
+ #include "base/hash/md5.h"
+
+ #include <stddef.h>
++#include <string.h>
+
+ namespace {
+
+diff --git a/libchrome/crypto/p224_spake.cc b/libchrome/crypto/p224_spake.cc
+index 157410537..de0af5466 100644
+--- a/libchrome/crypto/p224_spake.cc
++++ b/libchrome/crypto/p224_spake.cc
+@@ -8,6 +8,7 @@
+ #include <crypto/p224_spake.h>
+
+ #include <algorithm>
++#include <string.h>
+
+ #include <base/logging.h>
+ #include <crypto/p224.h>
+--
+2.20.1
+
diff --git a/build/dpkg/libchrome/debian/patches/0001-common-mk-rebase_path-output-location-of-generate-pc.patch b/build/dpkg/libchrome/debian/patches/0001-common-mk-rebase_path-output-location-of-generate-pc.patch
new file mode 100644
index 0000000..418efcc
--- /dev/null
+++ b/build/dpkg/libchrome/debian/patches/0001-common-mk-rebase_path-output-location-of-generate-pc.patch
@@ -0,0 +1,36 @@
+From 04fa5e1ade08696b5a2cc3b65bf0fd26c43251c7 Mon Sep 17 00:00:00 2001
+From: Sonny Sasaka <sonnysasaka@chromium.org>
+Date: Fri, 19 Mar 2021 11:17:43 -0700
+Subject: [PATCH] common-mk: rebase_path output location of generate-pc.py
+
+Without rebase_path, the generate-pc.py would be called like
+`generate-pc.py --output //out/Release` if the output is inside the
+source directory and this gn path isn't recognized as a generic
+filesystem path.
+
+BUG=b:183216216
+TEST=with modp_b64, call
+$ gn gen out/Release --args=...
+$ ninja
+
+Change-Id: Ic9d9b3d01d52d483e3d81ca2e8d514b47900f5bb
+---
+ common-mk/pkg_config.gni | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/common-mk/pkg_config.gni b/common-mk/pkg_config.gni
+index 24e2cf1401..b2c58845d4 100644
+--- a/common-mk/pkg_config.gni
++++ b/common-mk/pkg_config.gni
+@@ -84,7 +84,7 @@ template("generate_pkg_config") {
+ outputs = [ "${target_out_dir}/${output_name}.pc" ]
+
+ script = "//common-mk/generate-pc.py"
+- args = [ "--output" ] + outputs + [ "--name=" + name ]
++ args = [ "--output" ] + rebase_path(outputs) + [ "--name=" + name ]
+ if (defined(description)) {
+ args += [ "--description=" + description ]
+ }
+--
+2.29.2
+
diff --git a/build/dpkg/libchrome/debian/patches/0001-rebase_path-for-write_args.patch b/build/dpkg/libchrome/debian/patches/0001-rebase_path-for-write_args.patch
new file mode 100644
index 0000000..9b359c0
--- /dev/null
+++ b/build/dpkg/libchrome/debian/patches/0001-rebase_path-for-write_args.patch
@@ -0,0 +1,34 @@
+From 6875449497baf026fb8228668930a715ffcc7082 Mon Sep 17 00:00:00 2001
+From: Sonny Sasaka <sonnysasaka@chromium.org>
+Date: Fri, 19 Mar 2021 16:56:59 -0700
+Subject: [PATCH] rebase_path for write_args
+
+---
+ BUILD.gn | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/libchrome/BUILD.gn b/libchrome/BUILD.gn
+index a846d8f52..66ac10a55 100644
+--- a/libchrome/BUILD.gn
++++ b/libchrome/BUILD.gn
+@@ -556,7 +556,7 @@ action("base") {
+
+ script = "//common-mk/write_args.py"
+ outputs = [ "${root_out_dir}/lib/lib${target_name}.so" ]
+- args = [ "--output" ] + outputs + [ "--" ] + [
++ args = [ "--output" ] + rebase_path(outputs) + [ "--" ] + [
+ "GROUP",
+ "(",
+ "AS_NEEDED",
+@@ -618,7 +618,7 @@ action("base-test") {
+
+ script = "//common-mk/write_args.py"
+ outputs = [ "${root_out_dir}/lib${target_name}.a" ]
+- args = [ "--output" ] + outputs + [ "--" ] + [
++ args = [ "--output" ] + rebase_path(outputs) + [ "--" ] + [
+ "GROUP",
+ "(",
+ "AS_NEEDED",
+--
+2.20.1
+
diff --git a/build/dpkg/libchrome/debian/patches/series b/build/dpkg/libchrome/debian/patches/series
new file mode 100644
index 0000000..5a26f7b
--- /dev/null
+++ b/build/dpkg/libchrome/debian/patches/series
@@ -0,0 +1,3 @@
+0001-common-mk-rebase_path-output-location-of-generate-pc.patch
+0001-Add-missing-includes.patch
+0001-rebase_path-for-write_args.patch
diff --git a/build/dpkg/libchrome/debian/rules b/build/dpkg/libchrome/debian/rules
new file mode 100755
index 0000000..6ac1783
--- /dev/null
+++ b/build/dpkg/libchrome/debian/rules
@@ -0,0 +1,38 @@
+#!/usr/bin/make -f
+
+# gn args
+defines =
+defines += pkg_config=\"pkg-config\"
+defines += libbase_ver=\"780652\"
+defines += platform2_root=\"$(shell pwd)/\"
+defines += platform_subdir=\"libchrome\"
+defines += cxx=\"clang++\"
+defines += cc=\"clang\"
+defines += ar=\"ar\"
+defines += external_cxxflags=[\"-I/usr/src/googletest/googletest/include\", \"-I/usr/src/googletest/googlemock/include\"]
+defines += external_ldflags=[\"-latomic\"]
+defines += enable_werror=false
+defines += libdir=\"/usr/lib\"
+defines += use={mojo=false asan=false coverage=false crypto=true dbus=true fuzzer=false timers=true cros_host=false profiling=false tcmalloc=false}
+
+# handle parallel build options
+njobs=1
+ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
+njobs=$(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
+endif
+
+%:
+ dh $@ --parallel
+
+override_dh_auto_build-arch:
+ gn gen out/Release --args="$(defines)"
+ ninja -j$(njobs) -C out/Release
+
+override_dh_auto_clean:
+ rm -rf out
+ find . -name \*.pyc -execdir rm -f {} \;
+ dh_auto_clean
+
+override_dh_auto_install-arch:
+ dh_auto_install
+ debian/install_headers.sh debian/tmp
diff --git a/build/dpkg/libchrome/gen-src-pkg.sh b/build/dpkg/libchrome/gen-src-pkg.sh
new file mode 100755
index 0000000..3cee0e4
--- /dev/null
+++ b/build/dpkg/libchrome/gen-src-pkg.sh
@@ -0,0 +1,60 @@
+#!/bin/bash
+# Generates Debian source and binary packages of libchrome.
+
+if [ -z "$1" ]; then
+ echo "Usage: gen-src-pkg.sh <output-dir>"
+ exit 1
+fi
+
+outdir="$1"
+pkgdir=libchrome-780652
+origtar=libchrome_780652.orig.tar.gz
+scriptdir="$( cd "$( dirname "$0" )" && pwd )"
+branch=release-R90-13816.B
+
+tmpdir=$(mktemp -d)
+echo Generating source package in "${tmpdir}".
+
+# Download platform2 source.
+cd "${tmpdir}"
+git clone --branch "${branch}" https://chromium.googlesource.com/chromiumos/platform2 || exit 1
+mkdir "${pkgdir}"
+cd "${pkgdir}"
+# Trim platform2, only common-mk is needed.
+cp -a ../platform2/{common-mk,.gn} .
+
+# Download libchrome source and apply Chrome OS's patches.
+git clone --branch "${branch}" https://chromium.googlesource.com/aosp/platform/external/libchrome || exit 1
+cd libchrome
+rm -rf .git
+while read -r patch; do
+ patch -p1 < "libchrome_tools/patches/${patch}"
+done < <(grep -E '^[^#]' "libchrome_tools/patches/patches")
+
+# Clean up temporary platform2 checkout.
+cd ../..
+rm -rf platform2
+
+# Debian requires creating .orig.tar.gz.
+tar czf "${origtar}" "${pkgdir}"
+
+# Debianize the source.
+cd "${pkgdir}"
+yes | debmake || exit 1
+cp -aT "${scriptdir}/debian/" "${tmpdir}/${pkgdir}/debian/"
+
+# Build source package and binary package.
+cd "${tmpdir}/${pkgdir}"
+dpkg-buildpackage --no-sign || exit 1
+
+# Copy the results to output dir.
+cd "${tmpdir}"
+mkdir -p "${outdir}/src"
+cp *.dsc *.orig.tar.gz *.debian.tar.xz "${outdir}/src"
+cp *.deb "${outdir}"
+cd /
+
+echo Removing temporary directory "${tmpdir}".
+rm -rf "${tmpdir}"
+
+echo Done. Check out Debian source package in "${outdir}".
diff --git a/build/dpkg/modp_b64/debian/README.Debian b/build/dpkg/modp_b64/debian/README.Debian
new file mode 100644
index 0000000..2fb99bd
--- /dev/null
+++ b/build/dpkg/modp_b64/debian/README.Debian
@@ -0,0 +1 @@
+modp-b64 for Debian
diff --git a/build/dpkg/modp_b64/debian/changelog b/build/dpkg/modp_b64/debian/changelog
new file mode 100644
index 0000000..034c8ef
--- /dev/null
+++ b/build/dpkg/modp_b64/debian/changelog
@@ -0,0 +1,5 @@
+modp-b64 (0.0.1-1) buster; urgency=low
+
+ * Initial release.
+
+ -- Sonny Sasaka <sonnysasaka@chromium.org> Fri, 19 Mar 2021 19:41:40 +0000
diff --git a/build/dpkg/modp_b64/debian/compat b/build/dpkg/modp_b64/debian/compat
new file mode 100644
index 0000000..f599e28
--- /dev/null
+++ b/build/dpkg/modp_b64/debian/compat
@@ -0,0 +1 @@
+10
diff --git a/build/dpkg/modp_b64/debian/control b/build/dpkg/modp_b64/debian/control
new file mode 100644
index 0000000..a1ef0d9
--- /dev/null
+++ b/build/dpkg/modp_b64/debian/control
@@ -0,0 +1,18 @@
+Source: modp-b64
+Section: libs
+Priority: optional
+Maintainer: Sonny Sasaka <sonnysasaka@chromium.org>
+Standards-Version: 4.1.4
+Homepage: https://chromium.googlesource.com/aosp/platform/external/modp_b64/
+Build-Depends:
+ debhelper (>=11~),
+ clang,
+ python3,
+ pkg-config,
+ ninja-build,
+
+Package: modp-b64
+Architecture: any
+Multi-Arch: foreign
+Depends: ${misc:Depends}, ${shlibs:Depends}
+Description: modp base64 decoder
diff --git a/build/dpkg/modp_b64/debian/modp-b64.install b/build/dpkg/modp_b64/debian/modp-b64.install
new file mode 100644
index 0000000..3bd2802
--- /dev/null
+++ b/build/dpkg/modp_b64/debian/modp-b64.install
@@ -0,0 +1,3 @@
+modp_b64/modp_b64 /usr/include
+out/Release/libmodp_b64.a /usr/lib
+out/Release/obj/modp_b64/libmodp_b64.pc /usr/lib/pkgconfig
diff --git a/build/dpkg/modp_b64/debian/patches/0001-common-mk-rebase_path-output-location-of-generate-pc.patch b/build/dpkg/modp_b64/debian/patches/0001-common-mk-rebase_path-output-location-of-generate-pc.patch
new file mode 100644
index 0000000..418efcc
--- /dev/null
+++ b/build/dpkg/modp_b64/debian/patches/0001-common-mk-rebase_path-output-location-of-generate-pc.patch
@@ -0,0 +1,36 @@
+From 04fa5e1ade08696b5a2cc3b65bf0fd26c43251c7 Mon Sep 17 00:00:00 2001
+From: Sonny Sasaka <sonnysasaka@chromium.org>
+Date: Fri, 19 Mar 2021 11:17:43 -0700
+Subject: [PATCH] common-mk: rebase_path output location of generate-pc.py
+
+Without rebase_path, the generate-pc.py would be called like
+`generate-pc.py --output //out/Release` if the output is inside the
+source directory and this gn path isn't recognized as a generic
+filesystem path.
+
+BUG=b:183216216
+TEST=with modp_b64, call
+$ gn gen out/Release --args=...
+$ ninja
+
+Change-Id: Ic9d9b3d01d52d483e3d81ca2e8d514b47900f5bb
+---
+ common-mk/pkg_config.gni | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/common-mk/pkg_config.gni b/common-mk/pkg_config.gni
+index 24e2cf1401..b2c58845d4 100644
+--- a/common-mk/pkg_config.gni
++++ b/common-mk/pkg_config.gni
+@@ -84,7 +84,7 @@ template("generate_pkg_config") {
+ outputs = [ "${target_out_dir}/${output_name}.pc" ]
+
+ script = "//common-mk/generate-pc.py"
+- args = [ "--output" ] + outputs + [ "--name=" + name ]
++ args = [ "--output" ] + rebase_path(outputs) + [ "--name=" + name ]
+ if (defined(description)) {
+ args += [ "--description=" + description ]
+ }
+--
+2.29.2
+
diff --git a/build/dpkg/modp_b64/debian/patches/series b/build/dpkg/modp_b64/debian/patches/series
new file mode 100644
index 0000000..27086fc
--- /dev/null
+++ b/build/dpkg/modp_b64/debian/patches/series
@@ -0,0 +1 @@
+0001-common-mk-rebase_path-output-location-of-generate-pc.patch
diff --git a/build/dpkg/modp_b64/debian/rules b/build/dpkg/modp_b64/debian/rules
new file mode 100755
index 0000000..1bb93ae
--- /dev/null
+++ b/build/dpkg/modp_b64/debian/rules
@@ -0,0 +1,31 @@
+#!/usr/bin/make -f
+
+# gn args
+defines =
+defines += pkg_config=\"pkg-config\"
+defines += platform2_root=\"$(shell pwd)/\"
+defines += platform_subdir=\"modp_b64\"
+defines += cxx=\"clang++\"
+defines += cc=\"clang\"
+defines += ar=\"ar\"
+defines += enable_werror=false
+defines += libdir=\"/usr/lib\"
+defines += use={mojo=false asan=false coverage=false crypto=true dbus=true fuzzer=false timers=true cros_host=false profiling=false tcmalloc=false}
+
+# handle parallel build options
+njobs=1
+ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
+njobs=$(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
+endif
+
+%:
+ dh $@
+
+override_dh_auto_build-arch:
+ gn gen out/Release --args="$(defines)"
+ ninja -j$(njobs) -C out/Release
+
+override_dh_auto_clean:
+ rm -rf out
+ find . -name \*.pyc -execdir rm -f {} \;
+ dh_auto_clean
diff --git a/build/dpkg/modp_b64/gen-src-pkg.sh b/build/dpkg/modp_b64/gen-src-pkg.sh
new file mode 100755
index 0000000..cc22f67
--- /dev/null
+++ b/build/dpkg/modp_b64/gen-src-pkg.sh
@@ -0,0 +1,57 @@
+#!/bin/bash
+# Generates Debian source and binary packages of modp_b64.
+
+if [ -z "$1" ]; then
+ echo "Usage: gen-src-pkg.sh <output-dir>"
+ exit 1
+fi
+
+outdir="$1"
+pkgdir=modp-b64-0.0.1
+origtar=modp-b64_0.0.1.orig.tar.gz
+scriptdir="$( cd "$( dirname "$0" )" && pwd )"
+branch=release-R90-13816.B
+
+tmpdir=$(mktemp -d)
+echo Generating source package in "${tmpdir}".
+
+# Download platform2 source.
+cd "${tmpdir}"
+git clone --branch "${branch}" https://chromium.googlesource.com/chromiumos/platform2 || exit 1
+mkdir "${pkgdir}"
+cd "${pkgdir}"
+# Trim platform2, only common-mk is needed.
+cp -a ../platform2/{common-mk,.gn} .
+
+# Download modp_b64 source.
+git clone --branch "${branch}" https://chromium.googlesource.com/aosp/platform/external/modp_b64 || exit 1
+cd modp_b64
+rm -rf .git
+
+# Clean up temporary platform2 checkout.
+cd ../..
+rm -rf platform2
+
+# Debian requires creating .orig.tar.gz.
+tar czf "${origtar}" "${pkgdir}"
+
+# Debianize the source.
+cd "${pkgdir}"
+yes | debmake || exit 1
+cp -aT "${scriptdir}/debian/" "${tmpdir}/${pkgdir}/debian/"
+
+# Build source package and binary package.
+cd "${tmpdir}/${pkgdir}"
+dpkg-buildpackage --no-sign || exit 1
+
+# Copy the results to output dir.
+cd "${tmpdir}"
+mkdir -p "${outdir}/src"
+cp *.dsc *.orig.tar.gz *.debian.tar.xz "${outdir}/src"
+cp *.deb "${outdir}"
+cd /
+
+echo Removing temporary directory "${tmpdir}".
+rm -rf "${tmpdir}"
+
+echo Done. Check out Debian source package in "${outdir}".
diff --git a/build/install_deps.sh b/build/install_deps.sh
index 2f994e1..4826b38 100755
--- a/build/install_deps.sh
+++ b/build/install_deps.sh
@@ -47,11 +47,12 @@
fi
sudo apt-get -y install $CLANG_PACKAGE libevent-dev libc++-dev libc++abi-dev \
- ninja-build
- gn_path=`which gn`
- if [ -z $gn_path ]; then
- gnsha1=$(curl $GNSHA1_URL | base64 -d)
- wget -O gn http://storage.googleapis.com/chromium-gn/$gnsha1
- chmod a+x ./gn
- sudo mv ./gn /usr/bin/
- fi
+ ninja-build libflatbuffers-dev libtinyxml2-dev
+
+gn_path=`which gn`
+if [ -z $gn_path ]; then
+ gnsha1=$(curl $GNSHA1_URL | base64 -d)
+ wget -O gn http://storage.googleapis.com/chromium-gn/$gnsha1
+ chmod a+x ./gn
+ sudo mv ./gn /usr/bin/
+fi
diff --git a/common/metrics.cc b/common/metrics.cc
index 1849612..9214dcb 100644
--- a/common/metrics.cc
+++ b/common/metrics.cc
@@ -904,17 +904,15 @@
void LogBluetoothHalCrashReason(const RawAddress& address, uint32_t error_code,
uint32_t vendor_error_code) {
std::string obfuscated_id;
- int metric_id = 0;
if (!address.IsEmpty()) {
obfuscated_id = AddressObfuscator::GetInstance()->Obfuscate(address);
- metric_id = MetricIdAllocator::GetInstance().AllocateId(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_HAL_CRASH_REASON_REPORTED, metric_id,
+ android::util::BLUETOOTH_HAL_CRASH_REASON_REPORTED, 0,
obfuscated_id_field, error_code, vendor_error_code);
if (ret < 0) {
LOG(WARNING) << __func__ << ": failed for " << address << ", error_code "
diff --git a/common/metrics_linux.cc b/common/metrics_linux.cc
index aa01cbc..f363827 100644
--- a/common/metrics_linux.cc
+++ b/common/metrics_linux.cc
@@ -111,6 +111,12 @@
int num_dropped_encoded_frames,
int num_dropped_encoded_bytes) {}
+void LogA2dpPlaybackEvent(const RawAddress& address, int playback_state,
+ int audio_coding_mode) {}
+
+void LogBluetoothHalCrashReason(const RawAddress& address, uint32_t error_code,
+ uint32_t vendor_error_code) {}
+
void LogReadRssiResult(const RawAddress& address, uint16_t handle,
uint32_t cmd_status, int8_t rssi) {}
diff --git a/common/once_timer_unittest.cc b/common/once_timer_unittest.cc
index d0fa238..720474e 100644
--- a/common/once_timer_unittest.cc
+++ b/common/once_timer_unittest.cc
@@ -15,11 +15,11 @@
*/
#include <base/bind.h>
-#include <base/bind_helpers.h>
#include <base/logging.h>
#include <gtest/gtest.h>
#include <future>
+#include "bind_helpers.h"
#include "message_loop_thread.h"
#include "once_timer.h"
diff --git a/common/repeating_timer_unittest.cc b/common/repeating_timer_unittest.cc
index 50520cd..7bf4bbc 100644
--- a/common/repeating_timer_unittest.cc
+++ b/common/repeating_timer_unittest.cc
@@ -15,11 +15,11 @@
*/
#include <base/bind.h>
-#include <base/bind_helpers.h>
#include <base/logging.h>
#include <gtest/gtest.h>
#include <future>
+#include "bind_helpers.h"
#include "message_loop_thread.h"
#include "repeating_timer.h"
diff --git a/common/stop_watch_legacy.cc b/common/stop_watch_legacy.cc
index 0327568..110748e 100644
--- a/common/stop_watch_legacy.cc
+++ b/common/stop_watch_legacy.cc
@@ -29,10 +29,10 @@
namespace common {
static const int LOG_BUFFER_LENGTH = 10;
-static std::array<std::string, LOG_BUFFER_LENGTH> stopwatch_logs;
+static std::array<StopWatchLog, LOG_BUFFER_LENGTH> stopwatch_logs;
static int current_buffer_index;
-void StopWatchLegacy::RecordLog(std::string log) {
+void StopWatchLegacy::RecordLog(StopWatchLog log) {
if (current_buffer_index >= LOG_BUFFER_LENGTH) {
current_buffer_index = 0;
}
@@ -41,44 +41,49 @@
}
void StopWatchLegacy::DumpStopWatchLog() {
- LOG_INFO("=====================================");
+ LOG_INFO("=-----------------------------------=");
LOG_INFO("bluetooth stopwatch log history:");
for (int i = 0; i < LOG_BUFFER_LENGTH; i++) {
if (current_buffer_index >= LOG_BUFFER_LENGTH) {
current_buffer_index = 0;
}
- if (stopwatch_logs[current_buffer_index].empty()) {
+ if (stopwatch_logs[current_buffer_index].message.empty()) {
break;
}
- LOG_INFO("%s", stopwatch_logs[current_buffer_index].c_str());
+ std::stringstream ss;
+ auto now = stopwatch_logs[current_buffer_index].timestamp;
+ auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(
+ now.time_since_epoch()) %
+ 1000;
+ auto now_time_t = std::chrono::system_clock::to_time_t(now);
+ ss << std::put_time(std::localtime(&now_time_t), "%Y-%m-%d %H:%M:%S");
+ ss << '.' << std::setfill('0') << std::setw(3) << millis.count();
+ std::string start_timestamp = ss.str();
+ LOG_INFO("%s: %s: took %zu us", start_timestamp.c_str(),
+ stopwatch_logs[current_buffer_index].message.c_str(),
+ static_cast<size_t>(
+ std::chrono::duration_cast<std::chrono::microseconds>(
+ stopwatch_logs[current_buffer_index].end_timestamp -
+ stopwatch_logs[current_buffer_index].start_timestamp)
+ .count()));
current_buffer_index++;
}
- LOG_INFO("=====================================");
+ LOG_INFO("=-----------------------------------=");
}
StopWatchLegacy::StopWatchLegacy(std::string text)
: text_(std::move(text)),
- start_time_(std::chrono::high_resolution_clock::now()) {
- std::stringstream ss;
- auto now = std::chrono::system_clock::now();
- auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(
- now.time_since_epoch()) %
- 1000;
- auto now_time_t = std::chrono::system_clock::to_time_t(now);
- ss << std::put_time(std::localtime(&now_time_t), "%Y-%m-%d %H:%M:%S");
- ss << '.' << std::setfill('0') << std::setw(3) << millis.count();
- start_timestamp_ = ss.str();
-
- RecordLog(start_timestamp_ + ": " + text_);
-}
+ timestamp_(std::chrono::system_clock::now()),
+ start_timestamp_(std::chrono::high_resolution_clock::now()) {}
StopWatchLegacy::~StopWatchLegacy() {
- RecordLog(start_timestamp_ + ": " + text_ + ": took " +
- std::to_string(static_cast<size_t>(
- std::chrono::duration_cast<std::chrono::microseconds>(
- std::chrono::high_resolution_clock::now() - start_time_)
- .count())) +
- " us");
+ StopWatchLog sw_log;
+ sw_log.timestamp = timestamp_;
+ sw_log.start_timestamp = start_timestamp_;
+ sw_log.end_timestamp = std::chrono::high_resolution_clock::now();
+ sw_log.message = std::move(text_);
+
+ RecordLog(std::move(sw_log));
}
} // namespace common
diff --git a/common/stop_watch_legacy.h b/common/stop_watch_legacy.h
index b5cdc3d..2573d99 100644
--- a/common/stop_watch_legacy.h
+++ b/common/stop_watch_legacy.h
@@ -22,6 +22,13 @@
namespace bluetooth {
namespace common {
+typedef struct {
+ std::chrono::system_clock::time_point timestamp;
+ std::chrono::high_resolution_clock::time_point start_timestamp;
+ std::chrono::high_resolution_clock::time_point end_timestamp;
+ std::string message;
+} StopWatchLog;
+
class StopWatchLegacy {
public:
static void DumpStopWatchLog(void);
@@ -30,9 +37,9 @@
private:
std::string text_;
- std::chrono::time_point<std::chrono::high_resolution_clock> start_time_;
- std::string start_timestamp_;
- void RecordLog(std::string log);
+ std::chrono::system_clock::time_point timestamp_;
+ std::chrono::high_resolution_clock::time_point start_timestamp_;
+ void RecordLog(StopWatchLog log);
};
} // namespace common
diff --git a/conf/Android.bp b/conf/Android.bp
index 9fe5ab1..15d3a8b 100644
--- a/conf/Android.bp
+++ b/conf/Android.bp
@@ -1,5 +1,4 @@
// Bluetooth bt_stack.conf config file
-// ========================================================
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
@@ -16,7 +15,6 @@
}
// Bluetooth bt_did.conf config file
-// ========================================================
prebuilt_etc {
name: "bt_did.conf",
src: "bt_did.conf",
diff --git a/device/Android.bp b/device/Android.bp
index 52db733..4c80258 100644
--- a/device/Android.bp
+++ b/device/Android.bp
@@ -1,5 +1,4 @@
// Bluetooth device static library for target
-// ========================================================
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
@@ -34,7 +33,6 @@
}
// Bluetooth device unit tests for target
-// ========================================================
cc_test {
name: "net_test_device",
test_suites: ["device-tests"],
diff --git a/device/BUILD.gn b/device/BUILD.gn
index b0c0261..27abaaa 100644
--- a/device/BUILD.gn
+++ b/device/BUILD.gn
@@ -35,6 +35,7 @@
deps = [
"//bt/gd/rust/shim:init_flags_bridge_header",
+ "//bt/gd/rust/shim:libbluetooth_rust_interop",
"//bt/gd/rust/shim:message_loop_thread_bridge_header",
]
}
diff --git a/device/include/controller.h b/device/include/controller.h
index c3194c8..4d1fdf4 100644
--- a/device/include/controller.h
+++ b/device/include/controller.h
@@ -101,6 +101,7 @@
uint16_t (*get_ble_default_data_packet_length)(void);
uint16_t (*get_ble_maximum_tx_data_length)(void);
+ uint16_t (*get_ble_maximum_tx_time)(void);
uint16_t (*get_ble_maxium_advertising_data_length)(void);
uint8_t (*get_ble_number_of_supported_advertising_sets)(void);
uint8_t (*get_ble_periodic_advertiser_list_size)(void);
diff --git a/device/src/controller.cc b/device/src/controller.cc
index 0cc8667..d312e36 100644
--- a/device/src/controller.cc
+++ b/device/src/controller.cc
@@ -665,6 +665,12 @@
return ble_supported_max_tx_octets;
}
+static uint16_t get_ble_maximum_tx_time(void) {
+ CHECK(readable);
+ CHECK(ble_supported);
+ return ble_supported_max_tx_time;
+}
+
static uint16_t get_ble_maxium_advertising_data_length(void) {
CHECK(readable);
CHECK(ble_supported);
@@ -799,6 +805,7 @@
get_ble_suggested_default_data_length,
get_ble_maximum_tx_data_length,
+ get_ble_maximum_tx_time,
get_ble_maxium_advertising_data_length,
get_ble_number_of_supported_advertising_sets,
get_ble_periodic_advertiser_list_size,
diff --git a/embdrv/sbc/decoder/Android.bp b/embdrv/sbc/decoder/Android.bp
index a3e13ce..bfeb2e9 100644
--- a/embdrv/sbc/decoder/Android.bp
+++ b/embdrv/sbc/decoder/Android.bp
@@ -1,5 +1,4 @@
// Bluetooth SBC decoder static library for target
-// ========================================================
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
diff --git a/gd/Android.bp b/gd/Android.bp
index 942c615..c9985a8 100644
--- a/gd/Android.bp
+++ b/gd/Android.bp
@@ -119,6 +119,7 @@
target: {
linux: {
srcs: [
+ ":BluetoothBtaaSources_linux_generic",
":BluetoothOsSources_linux_generic",
],
},
@@ -139,15 +140,13 @@
"android.hardware.bluetooth@1.0",
"android.hardware.bluetooth@1.1",
"android.system.suspend.control-V1-ndk",
+ "android.system.suspend@1.0",
"libbinder_ndk",
"libcutils",
"libhidlbase",
"libutils",
"libstatslog",
],
- static_libs: [
- "libbt-platform-protos-lite",
- ],
},
},
srcs: [
@@ -179,7 +178,6 @@
"libflatbuffers-cpp",
"libgrpc++",
"libgrpc_wrap",
- "libstatslog",
],
static_libs: [
"libbluetooth-protos",
@@ -263,10 +261,12 @@
"android.hardware.bluetooth@1.0",
"android.hardware.bluetooth@1.1",
"android.system.suspend.control-V1-ndk",
+ "android.system.suspend@1.0",
"libbinder_ndk",
"libhidlbase",
"libutils",
"libcutils",
+ "libstatslog",
],
},
host: {
@@ -282,6 +282,88 @@
}
cc_test {
+ name: "bluetooth_test_gd_unit",
+ test_suites: ["device-tests"],
+ defaults: [
+ "gd_defaults",
+ "gd_clang_coverage_bin",
+ ],
+ host_supported: true,
+ test_options: {
+ unit_test: true,
+ },
+ target: {
+ linux: {
+ srcs: [
+ ":BluetoothOsTestSources_linux_generic",
+ ],
+ },
+ host: {
+ srcs: [
+ ":BluetoothHalTestSources_hci_host",
+ ":BluetoothOsTestSources_host",
+ ],
+ },
+ android: {
+ srcs: [
+ ":BluetoothHalTestSources_hci_android_hidl",
+ ":BluetoothOsTestSources_android",
+ ],
+ shared_libs: [
+ "android.hardware.bluetooth@1.0",
+ "android.hardware.bluetooth@1.1",
+ "android.system.suspend.control-V1-ndk",
+ "android.system.suspend@1.0",
+ "libbinder_ndk",
+ "libhidlbase",
+ "libutils",
+ "libcutils",
+ "libstatslog",
+ ],
+ },
+ },
+ srcs: [
+ "module_unittest.cc",
+ "stack_manager_unittest.cc",
+ ":BluetoothCommonTestSources",
+ ":BluetoothCryptoToolboxTestSources",
+ ":BluetoothDumpsysTestSources",
+ ":BluetoothHalTestSources",
+ ":BluetoothHciUnitTestSources",
+ ":BluetoothL2capUnitTestSources",
+ ":BluetoothPacketTestSources",
+ ":BluetoothShimTestSources",
+ ":BluetoothSecurityUnitTestSources",
+ ":BluetoothStorageUnitTestSources",
+ ],
+ generated_headers: [
+ "BluetoothGeneratedBundlerSchema_h_bfbs",
+ "BluetoothGeneratedDumpsysBundledSchema_h",
+ "BluetoothGeneratedDumpsysBundledTestSchema_h",
+ "BluetoothGeneratedDumpsysDataSchema_h",
+ "BluetoothGeneratedDumpsysTestData_h",
+ "BluetoothGeneratedPackets_h",
+ ],
+ static_libs: [
+ "libbluetooth-protos",
+ "libbluetooth_gd",
+ "libc++fs",
+ "libflatbuffers-cpp",
+ "libgmock",
+ "libbluetooth_rust_interop",
+ ],
+ shared_libs: [
+ "libchrome",
+ "libcrypto",
+ "libgrpc++",
+ "libgrpc_wrap",
+ ],
+ sanitize: {
+ address: true,
+ },
+}
+
+cc_test {
name: "bluetooth_test_gd",
test_suites: ["device-tests"],
defaults: [
@@ -313,10 +395,12 @@
"android.hardware.bluetooth@1.0",
"android.hardware.bluetooth@1.1",
"android.system.suspend.control-V1-ndk",
+ "android.system.suspend@1.0",
"libbinder_ndk",
"libhidlbase",
"libutils",
"libcutils",
+ "libstatslog",
],
},
},
@@ -334,7 +418,6 @@
":BluetoothNeighborTestSources",
":BluetoothPacketTestSources",
":BluetoothSecurityTestSources",
- ":BluetoothShimTestSources",
":BluetoothStorageTestSources",
],
generated_headers: [
@@ -389,12 +472,10 @@
},
static_libs: [
"libchrome",
- "libbt-platform-protos-lite",
],
shared_libs: [
"libgrpc++",
"libgrpc_wrap",
- "libstatslog",
],
target: {
android: {
@@ -448,6 +529,7 @@
"libcutils",
"libhidlbase",
"libutils",
+ "libstatslog",
],
},
},
@@ -577,18 +659,22 @@
],
cmd: "$(location flatc) -I system/bt/gd -b --schema -o $(genDir) $(in) ",
srcs: [
+ "btaa/activity_attribution.fbs",
"common/init_flags.fbs",
"dumpsys_data.fbs",
"hci/hci_acl_manager.fbs",
"l2cap/classic/l2cap_classic_module.fbs",
"shim/dumpsys.fbs",
+ "os/wakelock_manager.fbs",
],
out: [
+ "activity_attribution.bfbs",
"init_flags.bfbs",
"dumpsys.bfbs",
"dumpsys_data.bfbs",
"hci_acl_manager.bfbs",
"l2cap_classic_module.bfbs",
+ "wakelock_manager.bfbs",
],
}
@@ -599,18 +685,22 @@
],
cmd: "$(location flatc) -I system/bt/gd -o $(genDir) --cpp $(in) ",
srcs: [
+ "btaa/activity_attribution.fbs",
"common/init_flags.fbs",
"dumpsys_data.fbs",
"hci/hci_acl_manager.fbs",
"l2cap/classic/l2cap_classic_module.fbs",
"shim/dumpsys.fbs",
+ "os/wakelock_manager.fbs",
],
out: [
+ "activity_attribution_generated.h",
"dumpsys_data_generated.h",
"dumpsys_generated.h",
"hci_acl_manager_generated.h",
"init_flags_generated.h",
"l2cap_classic_module_generated.h",
+ "wakelock_manager_generated.h",
],
}
diff --git a/gd/Android.mk b/gd/Android.mk
index 5b8957f..61c9907 100644
--- a/gd/Android.mk
+++ b/gd/Android.mk
@@ -32,7 +32,6 @@
$(HOST_OUT_SHARED_LIBRARIES)/libz-host.so \
$(HOST_OUT_SHARED_LIBRARIES)/libprotobuf-cpp-full.so \
$(HOST_OUT_SHARED_LIBRARIES)/libunwindstack.so \
- $(HOST_OUT_SHARED_LIBRARIES)/libdexfile_support.so \
$(HOST_OUT_SHARED_LIBRARIES)/liblzma.so \
$(HOST_OUT_SHARED_LIBRARIES)/libbacktrace.so
@@ -98,6 +97,7 @@
$(hide) $(SOONG_ZIP) -d -o $@ -C $(dir $@)bluetooth_cert_tests -D $(dir $@)bluetooth_cert_tests \
-P acts_framework \
-C $(dir $@)acts/tools/test/connectivity/acts/framework -D $(dir $@)acts/tools/test/connectivity/acts/framework \
+ -P blueberry -C system/bt/blueberry -D system/bt/blueberry \
-P llvm_binutils -C $(LLVM_PREBUILTS_BASE)/linux-x86/$(LLVM_PREBUILTS_VERSION) \
-f $(LLVM_PREBUILTS_BASE)/linux-x86/$(LLVM_PREBUILTS_VERSION)/bin/llvm-cov \
-f $(LLVM_PREBUILTS_BASE)/linux-x86/$(LLVM_PREBUILTS_VERSION)/bin/llvm-profdata \
diff --git a/gd/BUILD.gn b/gd/BUILD.gn
index 6abddb1..67310e3 100644
--- a/gd/BUILD.gn
+++ b/gd/BUILD.gn
@@ -28,6 +28,7 @@
defines = [
"OS_LINUX_GENERIC",
"OS_GENERIC",
+ "TARGET_FLOSS",
]
libs = [
@@ -61,16 +62,18 @@
include_dirs = [ "." ]
configs += [ ":gd_defaults" ]
deps = [
+ "//bt/gd/rust/topshim:libbluetooth_topshim",
+ "//bt/gd/rust/shim:libbluetooth_rust_interop",
"//bt/gd:BluetoothGeneratedPackets_h",
"//bt/gd/att:BluetoothAttSources",
"//bt/gd/common:BluetoothCommonSources",
"//bt/gd/crypto_toolbox:BluetoothCryptoToolboxSources",
"//bt/gd/dumpsys:BluetoothDumpsysSources",
+ "//bt/gd/btaa:BluetoothBtaaSources_linux",
"//bt/gd/hal:BluetoothHalSources",
- "//bt/gd/hal:BluetoothHalSources_hci_rootcanal",
+ "//bt/gd/hal:BluetoothHalSources_hci_host",
"//bt/gd/l2cap:BluetoothL2capSources",
"//bt/gd/neighbor:BluetoothNeighborSources",
- "//bt/gd/rust/shim:libbluetooth_rust_interop",
"//bt/gd/security:BluetoothSecuritySources",
"//bt/gd/shim:BluetoothShimSources",
"//bt/gd/storage:BluetoothStorageSources",
@@ -79,20 +82,24 @@
flatbuffer("BluetoothGeneratedDumpsysDataSchema_h") {
sources = [
+ "btaa/activity_attribution.fbs",
"common/init_flags.fbs",
"dumpsys_data.fbs",
"hci/hci_acl_manager.fbs",
"l2cap/classic/l2cap_classic_module.fbs",
+ "os/wakelock_manager.fbs",
"shim/dumpsys.fbs",
]
}
bt_flatc_binary_schema("BluetoothGeneratedDumpsysBinarySchema_bfbs") {
sources = [
+ "btaa/activity_attribution.fbs",
"common/init_flags.fbs",
"dumpsys_data.fbs",
"hci/hci_acl_manager.fbs",
"l2cap/classic/l2cap_classic_module.fbs",
+ "os/wakelock_manager.fbs",
"shim/dumpsys.fbs",
]
diff --git a/gd/btaa/Android.bp b/gd/btaa/Android.bp
index b77a824..2aea7ee 100644
--- a/gd/btaa/Android.bp
+++ b/gd/btaa/Android.bp
@@ -20,3 +20,13 @@
"host/activity_attribution.cc",
],
}
+
+filegroup {
+ name: "BluetoothBtaaSources_linux_generic",
+ srcs: [
+ "linux_generic/attribution_processor.cc",
+ "linux_generic/cmd_evt_classification.cc",
+ "linux_generic/hci_processor.cc",
+ "linux_generic/wakelock_processor.cc",
+ ],
+}
diff --git a/gd/btaa/BUILD.gn b/gd/btaa/BUILD.gn
new file mode 100644
index 0000000..342a4e3
--- /dev/null
+++ b/gd/btaa/BUILD.gn
@@ -0,0 +1,22 @@
+#
+# Copyright 2021 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+source_set("BluetoothBtaaSources_linux") {
+ sources = [ "linux/activity_attribution.cc" ]
+
+ configs += [ "//bt/gd:gd_defaults" ]
+ deps = [ "//bt/gd:gd_default_deps" ]
+}
diff --git a/gd/btaa/activity_attribution.fbs b/gd/btaa/activity_attribution.fbs
new file mode 100644
index 0000000..9ff18cd
--- /dev/null
+++ b/gd/btaa/activity_attribution.fbs
@@ -0,0 +1,29 @@
+namespace bluetooth.activity_attribution;
+
+attribute "privacy";
+
+table WakeupEntry {
+ wakeup_time:string;
+ activity:string;
+ address:string;
+}
+
+table DeviceActivityAggregationEntry {
+ address:string;
+ activity:string;
+ wakeup_count:int;
+ byte_count:int;
+ wakelock_duration_ms:int;
+ creation_time:string;
+}
+
+table ActivityAttributionData {
+ title_wakeup:string;
+ num_wakeup:int;
+ wakeup_attribution:[WakeupEntry];
+ title_activity:string;
+ num_device_activity:int;
+ device_activity_aggregation:[DeviceActivityAggregationEntry];
+}
+
+root_type ActivityAttributionData;
\ No newline at end of file
diff --git a/gd/btaa/activity_attribution.h b/gd/btaa/activity_attribution.h
index bc0ba4f..9bba347 100644
--- a/gd/btaa/activity_attribution.h
+++ b/gd/btaa/activity_attribution.h
@@ -23,14 +23,17 @@
namespace bluetooth {
namespace activity_attribution {
-enum class Activity : uint8_t { UNKNOWN = 0, ADVERTISE, CONNECT, CONTROL, SCAN, HFP, VENDOR };
+enum class Activity : uint8_t { UNKNOWN = 0, ACL, ADVERTISE, CONNECT, CONTROL, HFP, ISO, SCAN, VENDOR };
+
+using CreationTime = std::chrono::time_point<std::chrono::system_clock>;
struct BtaaAggregationEntry {
hci::Address address;
Activity activity;
uint16_t wakeup_count;
uint32_t byte_count;
- uint32_t wakelock_duration;
+ uint32_t wakelock_duration_ms;
+ CreationTime creation_time;
};
class ActivityAttributionCallback {
@@ -50,6 +53,9 @@
~ActivityAttribution() = default;
void Capture(const hal::HciPacket& packet, hal::SnoopLogger::PacketType type);
+ void OnWakelockAcquired();
+ void OnWakelockReleased();
+ void OnWakeup();
void RegisterActivityAttributionCallback(ActivityAttributionCallback* callback);
static const ModuleFactory Factory;
@@ -59,6 +65,7 @@
void ListDependencies(ModuleList* list) override;
void Start() override;
void Stop() override;
+ DumpsysDataFinisher GetDumpsysData(flatbuffers::FlatBufferBuilder* builder) const override; // Module
private:
struct impl;
diff --git a/gd/btaa/android/activity_attribution.cc b/gd/btaa/android/activity_attribution.cc
index 6ae0704..3b72feb 100644
--- a/gd/btaa/android/activity_attribution.cc
+++ b/gd/btaa/android/activity_attribution.cc
@@ -17,12 +17,16 @@
#define LOG_TAG "btaa"
#include "btaa/activity_attribution.h"
+#include "activity_attribution_generated.h"
#include <aidl/android/system/suspend/BnSuspendCallback.h>
#include <aidl/android/system/suspend/BnWakelockCallback.h>
#include <aidl/android/system/suspend/ISuspendControlService.h>
#include <android/binder_manager.h>
+#include "btaa/attribution_processor.h"
+#include "btaa/hci_processor.h"
+#include "btaa/wakelock_processor.h"
#include "module.h"
#include "os/log.h"
@@ -39,14 +43,18 @@
const ModuleFactory ActivityAttribution::Factory = ModuleFactory([]() { return new ActivityAttribution(); });
static const std::string kBtWakelockName("hal_bluetooth_lock");
+static const std::string kBtWakeupReason("hs_uart_wakeup");
+static const size_t kHciAclHeaderSize = 4;
struct wakelock_callback : public BnWakelockCallback {
wakelock_callback(ActivityAttribution* module) : module_(module) {}
Status notifyAcquired() override {
+ module_->OnWakelockAcquired();
return Status::ok();
}
Status notifyReleased() override {
+ module_->OnWakelockReleased();
return Status::ok();
}
@@ -57,6 +65,12 @@
wakeup_callback(ActivityAttribution* module) : module_(module) {}
Status notifyWakeup(bool success, const std::vector<std::string>& wakeup_reasons) override {
+ for (auto& wakeup_reason : wakeup_reasons) {
+ if (wakeup_reason.find(kBtWakeupReason) != std::string::npos) {
+ module_->OnWakeup();
+ break;
+ }
+ }
return Status::ok();
}
@@ -89,13 +103,40 @@
}
}
- void on_hci_packet(hal::HciPacket packet, hal::SnoopLogger::PacketType type, uint16_t length) {}
+ void on_hci_packet(hal::HciPacket packet, hal::SnoopLogger::PacketType type, uint16_t length) {
+ attribution_processor_.OnBtaaPackets(std::move(hci_processor_.OnHciPacket(std::move(packet), type, length)));
+ }
+
+ void on_wakelock_acquired() {
+ wakelock_processor_.OnWakelockAcquired();
+ }
+
+ void on_wakelock_released() {
+ uint32_t wakelock_duration_ms = 0;
+
+ wakelock_duration_ms = wakelock_processor_.OnWakelockReleased();
+ if (wakelock_duration_ms != 0) {
+ attribution_processor_.OnWakelockReleased(wakelock_duration_ms);
+ }
+ }
+
+ void on_wakeup() {
+ attribution_processor_.OnWakeup();
+ }
void register_callback(ActivityAttributionCallback* callback) {
callback_ = callback;
}
+ void Dump(
+ std::promise<flatbuffers::Offset<ActivityAttributionData>> promise, flatbuffers::FlatBufferBuilder* fb_builder) {
+ attribution_processor_.Dump(std::move(promise), fb_builder);
+ }
+
ActivityAttributionCallback* callback_;
+ AttributionProcessor attribution_processor_;
+ HciProcessor hci_processor_;
+ WakelockProcessor wakelock_processor_;
};
void ActivityAttribution::Capture(const hal::HciPacket& packet, hal::SnoopLogger::PacketType type) {
@@ -110,7 +151,7 @@
case hal::SnoopLogger::PacketType::ACL:
case hal::SnoopLogger::PacketType::SCO:
case hal::SnoopLogger::PacketType::ISO:
- truncate_length = 0;
+ truncate_length = kHciAclHeaderSize;
break;
}
@@ -122,6 +163,18 @@
CallOn(pimpl_.get(), &impl::on_hci_packet, truncate_packet, type, original_length);
}
+void ActivityAttribution::OnWakelockAcquired() {
+ CallOn(pimpl_.get(), &impl::on_wakelock_acquired);
+}
+
+void ActivityAttribution::OnWakelockReleased() {
+ CallOn(pimpl_.get(), &impl::on_wakelock_released);
+}
+
+void ActivityAttribution::OnWakeup() {
+ CallOn(pimpl_.get(), &impl::on_wakeup);
+}
+
void ActivityAttribution::RegisterActivityAttributionCallback(ActivityAttributionCallback* callback) {
CallOn(pimpl_.get(), &impl::register_callback, callback);
}
@@ -140,5 +193,19 @@
pimpl_.reset();
}
+DumpsysDataFinisher ActivityAttribution::GetDumpsysData(flatbuffers::FlatBufferBuilder* fb_builder) const {
+ ASSERT(fb_builder != nullptr);
+
+ std::promise<flatbuffers::Offset<ActivityAttributionData>> promise;
+ auto future = promise.get_future();
+ pimpl_->Dump(std::move(promise), fb_builder);
+
+ auto dumpsys_data = future.get();
+
+ return [dumpsys_data](DumpsysDataBuilder* dumpsys_builder) {
+ dumpsys_builder->add_activity_attribution_dumpsys_data(dumpsys_data);
+ };
+}
+
} // namespace activity_attribution
} // namespace bluetooth
diff --git a/gd/btaa/attribution_processor.h b/gd/btaa/attribution_processor.h
new file mode 100644
index 0000000..11bbc9c
--- /dev/null
+++ b/gd/btaa/attribution_processor.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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 <unordered_map>
+
+#include "hci_processor.h"
+
+namespace bluetooth {
+namespace activity_attribution {
+
+static constexpr size_t kWakeupAggregatorSize = 200;
+
+struct AddressActivityKey {
+ hci::Address address;
+ Activity activity;
+
+ bool operator==(const AddressActivityKey& other) const {
+ return (address == other.address && activity == other.activity);
+ }
+};
+
+struct AddressActivityKeyHasher {
+ std::size_t operator()(const AddressActivityKey& key) const {
+ return (
+ (std::hash<std::string>()(key.address.ToString()) ^
+ (std::hash<unsigned char>()(static_cast<unsigned char>(key.activity)))));
+ }
+};
+
+struct WakeupDescriptor {
+ Activity activity_;
+ const hci::Address address_;
+ WakeupDescriptor(Activity activity, const hci::Address address) : activity_(activity), address_(address) {}
+ virtual ~WakeupDescriptor() {}
+};
+
+class AttributionProcessor {
+ public:
+ void OnBtaaPackets(std::vector<BtaaHciPacket> btaa_packets);
+ void OnWakelockReleased(uint32_t duration_ms);
+ void OnWakeup();
+ void Dump(
+ std::promise<flatbuffers::Offset<ActivityAttributionData>> promise, flatbuffers::FlatBufferBuilder* fb_builder);
+
+ private:
+ bool wakeup_ = false;
+ std::unordered_map<AddressActivityKey, BtaaAggregationEntry, AddressActivityKeyHasher> btaa_aggregator_;
+ std::unordered_map<AddressActivityKey, BtaaAggregationEntry, AddressActivityKeyHasher> wakelock_duration_aggregator_;
+ common::TimestampedCircularBuffer<WakeupDescriptor> wakeup_aggregator_ =
+ common::TimestampedCircularBuffer<WakeupDescriptor>(kWakeupAggregatorSize);
+ const char* ActivityToString(Activity activity);
+};
+
+} // namespace activity_attribution
+} // namespace bluetooth
diff --git a/gd/btaa/cmd_evt_classification.h b/gd/btaa/cmd_evt_classification.h
new file mode 100644
index 0000000..1aae6c2
--- /dev/null
+++ b/gd/btaa/cmd_evt_classification.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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 "btaa/activity_attribution.h"
+#include "hci/hci_packets.h"
+
+namespace bluetooth {
+namespace activity_attribution {
+
+struct CmdEvtActivityClassification {
+ Activity activity;
+ uint16_t connection_handle_pos;
+ uint16_t address_pos;
+};
+
+CmdEvtActivityClassification lookup_cmd(hci::OpCode opcode);
+CmdEvtActivityClassification lookup_event(hci::EventCode event_code);
+CmdEvtActivityClassification lookup_le_event(hci::SubeventCode subevent_code);
+
+} // namespace activity_attribution
+} // namespace bluetooth
diff --git a/gd/btaa/hci_processor.h b/gd/btaa/hci_processor.h
new file mode 100644
index 0000000..47fbc68
--- /dev/null
+++ b/gd/btaa/hci_processor.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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 "btaa/activity_attribution.h"
+#include "btaa/cmd_evt_classification.h"
+#include "hal/snoop_logger.h"
+#include "hci/address.h"
+
+namespace bluetooth {
+namespace activity_attribution {
+
+struct BtaaHciPacket {
+ Activity activity;
+ hci::Address address;
+ uint16_t byte_count;
+
+ BtaaHciPacket() {}
+ BtaaHciPacket(Activity activity, hci::Address address, uint16_t byte_count)
+ : activity(activity), address(address), byte_count(byte_count) {}
+};
+
+class DeviceParser {
+ public:
+ void match_handle_with_address(uint16_t connection_handle, hci::Address& address);
+
+ private:
+ std::map<uint16_t, hci::Address> connection_lookup_table_;
+};
+
+struct PendingCommand {
+ hci::OpCode opcode;
+ BtaaHciPacket btaa_hci_packet;
+};
+
+class HciProcessor {
+ public:
+ std::vector<BtaaHciPacket> OnHciPacket(hal::HciPacket packet, hal::SnoopLogger::PacketType type, uint16_t length);
+
+ private:
+ void process_le_event(std::vector<BtaaHciPacket>& btaa_hci_packets, int16_t byte_count, hci::EventView& event);
+ void process_special_event(
+ std::vector<BtaaHciPacket>& btaa_hci_packets,
+ hci::EventCode event_code,
+ uint16_t byte_count,
+ hci::EventView& event);
+ void process_command(
+ std::vector<BtaaHciPacket>& btaa_hci_packets,
+ packet::PacketView<packet::kLittleEndian>& packet_view,
+ uint16_t byte_count);
+ void process_event(
+ std::vector<BtaaHciPacket>& btaa_hci_packets,
+ packet::PacketView<packet::kLittleEndian>& packet_view,
+ uint16_t byte_count);
+ void process_acl(
+ std::vector<BtaaHciPacket>& btaa_hci_packets,
+ packet::PacketView<packet::kLittleEndian>& packet_view,
+ uint16_t byte_count);
+ void process_sco(
+ std::vector<BtaaHciPacket>& btaa_hci_packets,
+ packet::PacketView<packet::kLittleEndian>& packet_view,
+ uint16_t byte_count);
+ void process_iso(
+ std::vector<BtaaHciPacket>& btaa_hci_packets,
+ packet::PacketView<packet::kLittleEndian>& packet_view,
+ uint16_t byte_count);
+
+ DeviceParser device_parser_;
+ PendingCommand pending_command_;
+};
+
+} // namespace activity_attribution
+} // namespace bluetooth
diff --git a/gd/btaa/host/activity_attribution.cc b/gd/btaa/host/activity_attribution.cc
index e9f4134..a2f7d70 100644
--- a/gd/btaa/host/activity_attribution.cc
+++ b/gd/btaa/host/activity_attribution.cc
@@ -23,8 +23,13 @@
struct ActivityAttribution::impl {};
-void ActivityAttribution::RegisterActivityAttributionCallback(
- ActivityAttributionCallback* callback) {}
+void ActivityAttribution::OnWakelockAcquired() {}
+
+void ActivityAttribution::OnWakelockReleased() {}
+
+void ActivityAttribution::OnWakeup() {}
+
+void ActivityAttribution::RegisterActivityAttributionCallback(ActivityAttributionCallback* callback) {}
std::string ActivityAttribution::ToString() const {
return "Btaa Module";
@@ -38,5 +43,9 @@
const ModuleFactory ActivityAttribution::Factory = ModuleFactory([]() { return new ActivityAttribution(); });
+DumpsysDataFinisher EmptyDumpsysDataFinisher = [](DumpsysDataBuilder* dumpsys_data_builder) {};
+DumpsysDataFinisher ActivityAttribution::GetDumpsysData(flatbuffers::FlatBufferBuilder* builder) const {
+ return EmptyDumpsysDataFinisher;
+}
} // namespace activity_attribution
} // namespace bluetooth
diff --git a/gd/btaa/linux/activity_attribution.cc b/gd/btaa/linux/activity_attribution.cc
new file mode 100644
index 0000000..dd6a7db
--- /dev/null
+++ b/gd/btaa/linux/activity_attribution.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "btaa/activity_attribution.h"
+
+// TODO: Implement for Linux.
+namespace bluetooth {
+namespace activity_attribution {
+
+const ModuleFactory ActivityAttribution::Factory = ModuleFactory([]() { return new ActivityAttribution(); });
+
+struct ActivityAttribution::impl {
+ impl(ActivityAttribution* module) {}
+
+ void on_hci_packet(hal::HciPacket packet, hal::SnoopLogger::PacketType type, uint16_t length) {}
+
+ void register_callback(ActivityAttributionCallback* callback) {}
+};
+
+void ActivityAttribution::Capture(const hal::HciPacket& packet, hal::SnoopLogger::PacketType type) {}
+
+void ActivityAttribution::RegisterActivityAttributionCallback(ActivityAttributionCallback* callback) {}
+
+std::string ActivityAttribution::ToString() const {
+ return "Btaa Module";
+}
+
+void ActivityAttribution::ListDependencies(ModuleList* list) {}
+
+void ActivityAttribution::Start() {}
+
+void ActivityAttribution::Stop() {}
+
+DumpsysDataFinisher EmptyDumpsysDataFinisher = [](DumpsysDataBuilder* dumpsys_data_builder) {};
+DumpsysDataFinisher ActivityAttribution::GetDumpsysData(flatbuffers::FlatBufferBuilder* builder) const {
+ return EmptyDumpsysDataFinisher;
+}
+
+} // namespace activity_attribution
+} // namespace bluetooth
diff --git a/gd/btaa/linux_generic/attribution_processor.cc b/gd/btaa/linux_generic/attribution_processor.cc
new file mode 100644
index 0000000..a55243a
--- /dev/null
+++ b/gd/btaa/linux_generic/attribution_processor.cc
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "btaa/attribution_processor.h"
+#include "common/strings.h"
+
+#include "os/log.h"
+
+namespace bluetooth {
+namespace activity_attribution {
+
+constexpr char kActivityAttributionTimeFormat[] = "%Y-%m-%d %H:%M:%S";
+// A device-activity aggregation entry expires after two days (172800 seconds)
+static const int kDurationToKeepDeviceActivityEntrySecs = 172800;
+// A transient device-activity aggregation entry is defined as an entry with very few Byte count
+// (200 Bytes, this is about the size of 5 advertising packets) over a period of time (15 minutes)
+static const int kByteCountTransientDeviceActivityEntry = 200;
+static const int kDurationTransientDeviceActivityEntrySecs = 900;
+static const int kMapSizeTrimDownAggregationEntry = 200;
+
+void AttributionProcessor::OnBtaaPackets(std::vector<BtaaHciPacket> btaa_packets) {
+ AddressActivityKey key;
+
+ for (auto& btaa_packet : btaa_packets) {
+ key.address = btaa_packet.address;
+ key.activity = btaa_packet.activity;
+
+ if (wakelock_duration_aggregator_.find(key) == wakelock_duration_aggregator_.end()) {
+ wakelock_duration_aggregator_[key] = {};
+ }
+ wakelock_duration_aggregator_[key].byte_count += btaa_packet.byte_count;
+
+ if (wakeup_) {
+ wakelock_duration_aggregator_[key].wakeup_count += 1;
+ wakeup_aggregator_.Push(std::move(WakeupDescriptor(btaa_packet.activity, btaa_packet.address)));
+ }
+ }
+ wakeup_ = false;
+}
+
+void AttributionProcessor::OnWakelockReleased(uint32_t duration_ms) {
+ uint32_t total_byte_count = 0;
+ uint32_t ms_per_byte = 0;
+
+ for (auto& it : wakelock_duration_aggregator_) {
+ total_byte_count += it.second.byte_count;
+ }
+
+ if (total_byte_count == 0) {
+ return;
+ }
+
+ ms_per_byte = duration_ms / total_byte_count;
+ auto cur_time = std::chrono::system_clock::now();
+ for (auto& it : wakelock_duration_aggregator_) {
+ it.second.wakelock_duration_ms = ms_per_byte * it.second.byte_count;
+ if (btaa_aggregator_.find(it.first) == btaa_aggregator_.end()) {
+ btaa_aggregator_[it.first] = {};
+ btaa_aggregator_[it.first].creation_time = cur_time;
+ }
+
+ auto elapsed_time_sec =
+ std::chrono::duration_cast<std::chrono::seconds>(cur_time - btaa_aggregator_[it.first].creation_time).count();
+ if (elapsed_time_sec > kDurationToKeepDeviceActivityEntrySecs) {
+ btaa_aggregator_[it.first].wakeup_count = 0;
+ btaa_aggregator_[it.first].byte_count = 0;
+ btaa_aggregator_[it.first].wakelock_duration_ms = 0;
+ btaa_aggregator_[it.first].creation_time = cur_time;
+ }
+
+ btaa_aggregator_[it.first].wakeup_count += it.second.wakeup_count;
+ btaa_aggregator_[it.first].byte_count += it.second.byte_count;
+ btaa_aggregator_[it.first].wakelock_duration_ms += it.second.wakelock_duration_ms;
+ }
+ wakelock_duration_aggregator_.clear();
+
+ if (btaa_aggregator_.size() < kMapSizeTrimDownAggregationEntry) {
+ return;
+ }
+ // Trim down the transient entries in the aggregator to avoid that it overgrows
+ for (auto& it : btaa_aggregator_) {
+ auto elapsed_time_sec =
+ std::chrono::duration_cast<std::chrono::seconds>(cur_time - it.second.creation_time).count();
+ if (elapsed_time_sec > kDurationTransientDeviceActivityEntrySecs &&
+ it.second.byte_count < kByteCountTransientDeviceActivityEntry) {
+ btaa_aggregator_.erase(it.first);
+ }
+ }
+}
+
+void AttributionProcessor::OnWakeup() {
+ if (wakeup_) {
+ LOG_INFO("Previous wakeup notification is not consumed.");
+ }
+ wakeup_ = true;
+}
+
+void AttributionProcessor::Dump(
+ std::promise<flatbuffers::Offset<ActivityAttributionData>> promise, flatbuffers::FlatBufferBuilder* fb_builder) {
+ // Dump wakeup attribution data
+ auto title_wakeup = fb_builder->CreateString("----- Wakeup Attribution Dumpsys -----");
+ std::vector<common::TimestampedEntry<WakeupDescriptor>> wakeup_aggregator = wakeup_aggregator_.Pull();
+ std::vector<flatbuffers::Offset<WakeupEntry>> wakeup_entry_offsets;
+ for (auto& it : wakeup_aggregator) {
+ WakeupEntryBuilder wakeup_entry_builder(*fb_builder);
+ std::chrono::milliseconds duration(it.timestamp);
+ std::chrono::time_point<std::chrono::system_clock> wakeup_time(duration);
+ wakeup_entry_builder.add_wakeup_time(fb_builder->CreateString(
+ bluetooth::common::StringFormatTimeWithMilliseconds(kActivityAttributionTimeFormat, wakeup_time).c_str()));
+ wakeup_entry_builder.add_activity(fb_builder->CreateString((ActivityToString(it.entry.activity_))));
+ wakeup_entry_builder.add_address(fb_builder->CreateString(it.entry.address_.ToString()));
+ wakeup_entry_offsets.push_back(wakeup_entry_builder.Finish());
+ }
+ auto wakeup_entries = fb_builder->CreateVector(wakeup_entry_offsets);
+
+ // Dump device-based activity aggregation data
+ auto title_device_activity = fb_builder->CreateString("----- Device-based Activity Attribution Dumpsys -----");
+ std::vector<flatbuffers::Offset<DeviceActivityAggregationEntry>> aggregation_entry_offsets;
+ for (auto& it : btaa_aggregator_) {
+ DeviceActivityAggregationEntryBuilder device_entry_builder(*fb_builder);
+ device_entry_builder.add_address(fb_builder->CreateString(it.first.address.ToString()));
+ device_entry_builder.add_activity(fb_builder->CreateString((ActivityToString(it.first.activity))));
+ device_entry_builder.add_wakeup_count(it.second.wakeup_count);
+ device_entry_builder.add_byte_count(it.second.byte_count);
+ device_entry_builder.add_wakelock_duration_ms(it.second.wakelock_duration_ms);
+ device_entry_builder.add_creation_time(fb_builder->CreateString(
+ bluetooth::common::StringFormatTimeWithMilliseconds(kActivityAttributionTimeFormat, it.second.creation_time)
+ .c_str()));
+ aggregation_entry_offsets.push_back(device_entry_builder.Finish());
+ }
+ auto aggregation_entries = fb_builder->CreateVector(aggregation_entry_offsets);
+
+ ActivityAttributionDataBuilder builder(*fb_builder);
+ builder.add_title_wakeup(title_wakeup);
+ builder.add_num_wakeup(wakeup_aggregator.size());
+ builder.add_wakeup_attribution(wakeup_entries);
+ builder.add_title_activity(title_device_activity);
+ builder.add_num_device_activity(btaa_aggregator_.size());
+ builder.add_device_activity_aggregation(aggregation_entries);
+ btaa_aggregator_.clear();
+
+ flatbuffers::Offset<ActivityAttributionData> dumpsys_data = builder.Finish();
+ promise.set_value(dumpsys_data);
+}
+
+#ifndef CASE_RETURN_TEXT
+#define CASE_RETURN_TEXT(code) \
+ case code: \
+ return #code
+#endif
+
+const char* AttributionProcessor::ActivityToString(Activity activity) {
+ switch (activity) {
+ CASE_RETURN_TEXT(Activity::ACL);
+ CASE_RETURN_TEXT(Activity::ADVERTISE);
+ CASE_RETURN_TEXT(Activity::CONNECT);
+ CASE_RETURN_TEXT(Activity::CONTROL);
+ CASE_RETURN_TEXT(Activity::HFP);
+ CASE_RETURN_TEXT(Activity::ISO);
+ CASE_RETURN_TEXT(Activity::SCAN);
+ CASE_RETURN_TEXT(Activity::VENDOR);
+ default:
+ return "UNKNOWN";
+ }
+}
+
+} // namespace activity_attribution
+} // namespace bluetooth
diff --git a/gd/btaa/linux_generic/cmd_evt_classification.cc b/gd/btaa/linux_generic/cmd_evt_classification.cc
new file mode 100644
index 0000000..a8b6151
--- /dev/null
+++ b/gd/btaa/linux_generic/cmd_evt_classification.cc
@@ -0,0 +1,465 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "btaa/cmd_evt_classification.h"
+
+namespace bluetooth {
+namespace activity_attribution {
+
+CmdEvtActivityClassification lookup_cmd(hci::OpCode opcode) {
+ CmdEvtActivityClassification classification = {};
+ switch (opcode) {
+ case hci::OpCode::INQUIRY:
+ case hci::OpCode::INQUIRY_CANCEL:
+ case hci::OpCode::PERIODIC_INQUIRY_MODE:
+ case hci::OpCode::EXIT_PERIODIC_INQUIRY_MODE:
+ classification = {.activity = Activity::SCAN, .connection_handle_pos = 0, .address_pos = 0};
+ break;
+
+ case hci::OpCode::CREATE_CONNECTION:
+ case hci::OpCode::CREATE_CONNECTION_CANCEL:
+ case hci::OpCode::ACCEPT_CONNECTION_REQUEST:
+ case hci::OpCode::LINK_KEY_REQUEST_REPLY:
+ case hci::OpCode::LINK_KEY_REQUEST_NEGATIVE_REPLY:
+ case hci::OpCode::PIN_CODE_REQUEST_REPLY:
+ case hci::OpCode::PIN_CODE_REQUEST_NEGATIVE_REPLY:
+ case hci::OpCode::REJECT_CONNECTION_REQUEST:
+ case hci::OpCode::REMOTE_NAME_REQUEST:
+ case hci::OpCode::REMOTE_NAME_REQUEST_CANCEL:
+ case hci::OpCode::ACCEPT_SYNCHRONOUS_CONNECTION:
+ case hci::OpCode::REJECT_SYNCHRONOUS_CONNECTION:
+ case hci::OpCode::IO_CAPABILITY_REQUEST_REPLY:
+ case hci::OpCode::USER_CONFIRMATION_REQUEST_REPLY:
+ case hci::OpCode::USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY:
+ case hci::OpCode::USER_PASSKEY_REQUEST_REPLY:
+ case hci::OpCode::USER_PASSKEY_REQUEST_NEGATIVE_REPLY:
+ case hci::OpCode::REMOTE_OOB_DATA_REQUEST_REPLY:
+ case hci::OpCode::REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY:
+ case hci::OpCode::IO_CAPABILITY_REQUEST_NEGATIVE_REPLY:
+ case hci::OpCode::ENHANCED_ACCEPT_SYNCHRONOUS_CONNECTION:
+ case hci::OpCode::REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY:
+ case hci::OpCode::SWITCH_ROLE:
+ case hci::OpCode::READ_STORED_LINK_KEY:
+ classification = {.activity = Activity::CONNECT, .connection_handle_pos = 0, .address_pos = 3};
+ break;
+
+ case hci::OpCode::CENTRAL_LINK_KEY:
+ case hci::OpCode::READ_DEFAULT_LINK_POLICY_SETTINGS:
+ case hci::OpCode::WRITE_DEFAULT_LINK_POLICY_SETTINGS:
+ case hci::OpCode::WRITE_SCAN_ENABLE:
+ case hci::OpCode::READ_PAGE_SCAN_ACTIVITY:
+ case hci::OpCode::WRITE_PAGE_SCAN_ACTIVITY:
+ case hci::OpCode::READ_PAGE_SCAN_TYPE:
+ case hci::OpCode::WRITE_PAGE_SCAN_TYPE:
+ case hci::OpCode::READ_SIMPLE_PAIRING_MODE:
+ case hci::OpCode::WRITE_SIMPLE_PAIRING_MODE:
+ case hci::OpCode::READ_SCAN_ENABLE:
+ case hci::OpCode::LE_CREATE_CONNECTION_CANCEL:
+ case hci::OpCode::LE_READ_CONNECT_LIST_SIZE:
+ case hci::OpCode::LE_CLEAR_CONNECT_LIST:
+ case hci::OpCode::SEND_KEYPRESS_NOTIFICATION:
+ case hci::OpCode::LE_CLEAR_RESOLVING_LIST:
+ case hci::OpCode::LE_READ_RESOLVING_LIST_SIZE:
+ case hci::OpCode::LE_SET_HOST_CHANNEL_CLASSIFICATION:
+ classification = {.activity = Activity::CONNECT, .connection_handle_pos = 0, .address_pos = 0};
+ break;
+
+ case hci::OpCode::DISCONNECT:
+ case hci::OpCode::CHANGE_CONNECTION_PACKET_TYPE:
+ case hci::OpCode::AUTHENTICATION_REQUESTED:
+ case hci::OpCode::SET_CONNECTION_ENCRYPTION:
+ case hci::OpCode::CHANGE_CONNECTION_LINK_KEY:
+ case hci::OpCode::READ_REMOTE_SUPPORTED_FEATURES:
+ case hci::OpCode::READ_REMOTE_EXTENDED_FEATURES:
+ case hci::OpCode::READ_REMOTE_VERSION_INFORMATION:
+ case hci::OpCode::READ_CLOCK_OFFSET:
+ case hci::OpCode::READ_LMP_HANDLE:
+ case hci::OpCode::SETUP_SYNCHRONOUS_CONNECTION:
+ case hci::OpCode::ENHANCED_SETUP_SYNCHRONOUS_CONNECTION:
+ case hci::OpCode::HOLD_MODE:
+ case hci::OpCode::SNIFF_MODE:
+ case hci::OpCode::EXIT_SNIFF_MODE:
+ case hci::OpCode::QOS_SETUP:
+ case hci::OpCode::ROLE_DISCOVERY:
+ case hci::OpCode::READ_LINK_POLICY_SETTINGS:
+ case hci::OpCode::WRITE_LINK_POLICY_SETTINGS:
+ case hci::OpCode::FLOW_SPECIFICATION:
+ case hci::OpCode::SNIFF_SUBRATING:
+ case hci::OpCode::FLUSH:
+ case hci::OpCode::READ_AUTOMATIC_FLUSH_TIMEOUT:
+ case hci::OpCode::WRITE_AUTOMATIC_FLUSH_TIMEOUT:
+ case hci::OpCode::READ_LINK_SUPERVISION_TIMEOUT:
+ case hci::OpCode::WRITE_LINK_SUPERVISION_TIMEOUT:
+ case hci::OpCode::REFRESH_ENCRYPTION_KEY:
+ case hci::OpCode::READ_FAILED_CONTACT_COUNTER:
+ case hci::OpCode::RESET_FAILED_CONTACT_COUNTER:
+ case hci::OpCode::READ_LINK_QUALITY:
+ case hci::OpCode::READ_RSSI:
+ case hci::OpCode::READ_AFH_CHANNEL_MAP:
+ case hci::OpCode::READ_CLOCK:
+ case hci::OpCode::READ_ENCRYPTION_KEY_SIZE:
+ // 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,
+ case hci::OpCode::ENHANCED_FLUSH:
+ case hci::OpCode::LE_CONNECTION_UPDATE:
+ case hci::OpCode::LE_START_ENCRYPTION:
+ case hci::OpCode::LE_LONG_TERM_KEY_REQUEST_REPLY:
+ case hci::OpCode::LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY:
+ case hci::OpCode::LE_READ_PHY:
+ case hci::OpCode::LE_SET_PHY:
+ case hci::OpCode::LE_READ_REMOTE_FEATURES:
+ case hci::OpCode::LE_REMOTE_CONNECTION_PARAMETER_REQUEST_REPLY:
+ case hci::OpCode::LE_REMOTE_CONNECTION_PARAMETER_REQUEST_NEGATIVE_REPLY:
+ case hci::OpCode::LE_SET_DATA_LENGTH:
+ classification = {.activity = Activity::CONNECT, .connection_handle_pos = 3, .address_pos = 0};
+ break;
+
+ case hci::OpCode::SET_EVENT_MASK:
+ case hci::OpCode::RESET:
+ case hci::OpCode::SET_EVENT_FILTER:
+ case hci::OpCode::READ_PIN_TYPE:
+ case hci::OpCode::WRITE_PIN_TYPE:
+ case hci::OpCode::WRITE_LOCAL_NAME:
+ case hci::OpCode::READ_LOCAL_NAME:
+ case hci::OpCode::READ_CONNECTION_ACCEPT_TIMEOUT:
+ case hci::OpCode::WRITE_CONNECTION_ACCEPT_TIMEOUT:
+ case hci::OpCode::READ_PAGE_TIMEOUT:
+ case hci::OpCode::WRITE_PAGE_TIMEOUT:
+ case hci::OpCode::READ_AUTHENTICATION_ENABLE:
+ case hci::OpCode::WRITE_AUTHENTICATION_ENABLE:
+ case hci::OpCode::READ_CLASS_OF_DEVICE:
+ case hci::OpCode::WRITE_CLASS_OF_DEVICE:
+ case hci::OpCode::READ_VOICE_SETTING:
+ case hci::OpCode::WRITE_VOICE_SETTING:
+ case hci::OpCode::READ_NUM_BROADCAST_RETRANSMITS:
+ case hci::OpCode::WRITE_NUM_BROADCAST_RETRANSMITS:
+ case hci::OpCode::READ_HOLD_MODE_ACTIVITY:
+ case hci::OpCode::WRITE_HOLD_MODE_ACTIVITY:
+ case hci::OpCode::READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE:
+ case hci::OpCode::WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE:
+ case hci::OpCode::SET_CONTROLLER_TO_HOST_FLOW_CONTROL:
+ case hci::OpCode::HOST_BUFFER_SIZE:
+ case hci::OpCode::HOST_NUM_COMPLETED_PACKETS:
+ case hci::OpCode::READ_NUMBER_OF_SUPPORTED_IAC:
+ case hci::OpCode::READ_CURRENT_IAC_LAP:
+ case hci::OpCode::WRITE_CURRENT_IAC_LAP:
+ case hci::OpCode::SET_AFH_HOST_CHANNEL_CLASSIFICATION:
+ case hci::OpCode::READ_AFH_CHANNEL_ASSESSMENT_MODE:
+ case hci::OpCode::WRITE_AFH_CHANNEL_ASSESSMENT_MODE:
+ case hci::OpCode::READ_LE_HOST_SUPPORT:
+ case hci::OpCode::WRITE_LE_HOST_SUPPORT:
+ case hci::OpCode::READ_SECURE_CONNECTIONS_HOST_SUPPORT:
+ case hci::OpCode::WRITE_SECURE_CONNECTIONS_HOST_SUPPORT:
+ case hci::OpCode::READ_LOCAL_OOB_EXTENDED_DATA:
+ case hci::OpCode::SET_ECOSYSTEM_BASE_INTERVAL:
+ case hci::OpCode::CONFIGURE_DATA_PATH:
+ case hci::OpCode::READ_LOCAL_VERSION_INFORMATION:
+ case hci::OpCode::READ_LOCAL_SUPPORTED_COMMANDS:
+ case hci::OpCode::READ_LOCAL_SUPPORTED_FEATURES:
+ case hci::OpCode::READ_LOCAL_EXTENDED_FEATURES:
+ case hci::OpCode::READ_BUFFER_SIZE:
+ case hci::OpCode::READ_BD_ADDR:
+ case hci::OpCode::READ_DATA_BLOCK_SIZE:
+ case hci::OpCode::READ_LOCAL_SUPPORTED_CODECS_V1:
+ case hci::OpCode::READ_LOCAL_SUPPORTED_CODECS_V2:
+ case hci::OpCode::READ_LOCAL_SUPPORTED_CODEC_CAPABILITIES:
+ case hci::OpCode::READ_LOCAL_SUPPORTED_CONTROLLER_DELAY:
+ case hci::OpCode::READ_LOCAL_OOB_DATA:
+ case hci::OpCode::LE_GENERATE_DHKEY_COMMAND:
+ case hci::OpCode::LE_MODIFY_SLEEP_CLOCK_ACCURACY:
+ case hci::OpCode::LE_READ_BUFFER_SIZE_V2:
+ case hci::OpCode::LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH:
+ case hci::OpCode::LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH:
+ case hci::OpCode::LE_READ_LOCAL_P_256_PUBLIC_KEY_COMMAND:
+ case hci::OpCode::LE_GENERATE_DHKEY_COMMAND_V1:
+ case hci::OpCode::LE_SET_EVENT_MASK:
+ case hci::OpCode::LE_READ_BUFFER_SIZE_V1:
+ case hci::OpCode::LE_READ_LOCAL_SUPPORTED_FEATURES:
+ case hci::OpCode::LE_SET_RANDOM_ADDRESS:
+ case hci::OpCode::LE_READ_TRANSMIT_POWER:
+ case hci::OpCode::LE_READ_RF_PATH_COMPENSATION_POWER:
+ case hci::OpCode::LE_WRITE_RF_PATH_COMPENSATION_POWER:
+ case hci::OpCode::LE_SET_DEFAULT_PHY:
+ case hci::OpCode::LE_ENCRYPT:
+ case hci::OpCode::LE_RAND:
+ case hci::OpCode::LE_SET_ADDRESS_RESOLUTION_ENABLE:
+ case hci::OpCode::LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT:
+ case hci::OpCode::LE_READ_MAXIMUM_DATA_LENGTH:
+ case hci::OpCode::LE_READ_SUPPORTED_STATES:
+ classification = {.activity = Activity::CONTROL, .connection_handle_pos = 0, .address_pos = 0};
+ break;
+
+ case hci::OpCode::DELETE_STORED_LINK_KEY:
+ classification = {.activity = Activity::CONTROL, .connection_handle_pos = 0, .address_pos = 3};
+ break;
+ case hci::OpCode::READ_TRANSMIT_POWER_LEVEL:
+ classification = {.activity = Activity::CONTROL, .connection_handle_pos = 3, .address_pos = 0};
+ break;
+
+ case hci::OpCode::READ_INQUIRY_SCAN_ACTIVITY:
+ case hci::OpCode::WRITE_INQUIRY_SCAN_ACTIVITY:
+ case hci::OpCode::READ_INQUIRY_SCAN_TYPE:
+ case hci::OpCode::WRITE_INQUIRY_SCAN_TYPE:
+ case hci::OpCode::READ_INQUIRY_MODE:
+ case hci::OpCode::WRITE_INQUIRY_MODE:
+ case hci::OpCode::READ_EXTENDED_INQUIRY_RESPONSE:
+ case hci::OpCode::WRITE_EXTENDED_INQUIRY_RESPONSE:
+ case hci::OpCode::LE_SET_CIG_PARAMETERS:
+ case hci::OpCode::LE_CREATE_CIS:
+ case hci::OpCode::LE_REMOVE_CIG:
+ case hci::OpCode::LE_ACCEPT_CIS_REQUEST:
+ case hci::OpCode::LE_REJECT_CIS_REQUEST:
+ case hci::OpCode::LE_CREATE_BIG:
+ case hci::OpCode::LE_TERMINATE_BIG:
+ case hci::OpCode::LE_BIG_CREATE_SYNC:
+ case hci::OpCode::LE_BIG_TERMINATE_SYNC:
+ case hci::OpCode::LE_REQUEST_PEER_SCA:
+ case hci::OpCode::LE_SETUP_ISO_DATA_PATH:
+ case hci::OpCode::LE_REMOVE_ISO_DATA_PATH:
+ case hci::OpCode::LE_SET_HOST_FEATURE:
+ case hci::OpCode::LE_READ_ISO_LINK_QUALITY:
+ case hci::OpCode::LE_ENHANCED_READ_TRANSMIT_POWER_LEVEL:
+ case hci::OpCode::LE_READ_REMOTE_TRANSMIT_POWER_LEVEL:
+ case hci::OpCode::LE_SET_PATH_LOSS_REPORTING_PARAMETERS:
+ case hci::OpCode::LE_SET_PATH_LOSS_REPORTING_ENABLE:
+ case hci::OpCode::LE_SET_TRANSMIT_POWER_REPORTING_ENABLE:
+ case hci::OpCode::LE_GET_VENDOR_CAPABILITIES:
+ case hci::OpCode::LE_MULTI_ADVT:
+ case hci::OpCode::LE_BATCH_SCAN:
+ case hci::OpCode::LE_ADV_FILTER:
+ case hci::OpCode::LE_ENERGY_INFO:
+ case hci::OpCode::LE_EXTENDED_SCAN_PARAMS:
+ case hci::OpCode::CONTROLLER_DEBUG_INFO:
+ case hci::OpCode::CONTROLLER_A2DP_OPCODE:
+ case hci::OpCode::CONTROLLER_BQR:
+ case hci::OpCode::READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL:
+ case hci::OpCode::WRITE_INQUIRY_TRANSMIT_POWER_LEVEL:
+ case hci::OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS:
+ case hci::OpCode::LE_SET_EXTENDED_SCAN_ENABLE:
+ case hci::OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL:
+ case hci::OpCode::LE_SET_SCAN_PARAMETERS:
+ case hci::OpCode::LE_SET_SCAN_ENABLE:
+ case hci::OpCode::LE_SET_DEFAULT_PERIODIC_ADVERTISING_SYNC_TRANSFER_PARAMETERS:
+ case hci::OpCode::LE_SET_PERIODIC_ADVERTISING_RECEIVE_ENABLE:
+ case hci::OpCode::LE_CLEAR_PERIODIC_ADVERTISING_LIST:
+ case hci::OpCode::LE_READ_PERIODIC_ADVERTISING_LIST_SIZE:
+ case hci::OpCode::LE_PERIODIC_ADVERTISING_TERMINATE_SYNC:
+ classification = {.activity = Activity::SCAN, .connection_handle_pos = 0, .address_pos = 0};
+ break;
+
+ case hci::OpCode::LE_READ_ADVERTISING_PHYSICAL_CHANNEL_TX_POWER:
+ case hci::OpCode::LE_SET_ADVERTISING_DATA:
+ case hci::OpCode::LE_SET_SCAN_RESPONSE_DATA:
+ case hci::OpCode::LE_SET_ADVERTISING_ENABLE:
+ case hci::OpCode::LE_SET_EXTENDED_ADVERTISING_DATA:
+ case hci::OpCode::LE_SET_EXTENDED_ADVERTISING_SCAN_RESPONSE:
+ case hci::OpCode::LE_SET_EXTENDED_ADVERTISING_ENABLE:
+ case hci::OpCode::LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH:
+ case hci::OpCode::LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS:
+ case hci::OpCode::LE_REMOVE_ADVERTISING_SET:
+ case hci::OpCode::LE_CLEAR_ADVERTISING_SETS:
+ case hci::OpCode::LE_SET_PERIODIC_ADVERTISING_PARAM:
+ case hci::OpCode::LE_SET_PERIODIC_ADVERTISING_DATA:
+ case hci::OpCode::LE_SET_PERIODIC_ADVERTISING_ENABLE:
+ case hci::OpCode::LE_SET_EXTENDED_ADVERTISING_RANDOM_ADDRESS:
+ classification = {.activity = Activity::ADVERTISE, .connection_handle_pos = 0, .address_pos = 0};
+ break;
+
+ case hci::OpCode::LE_SET_ADVERTISING_PARAMETERS:
+ classification = {.activity = Activity::SCAN, .connection_handle_pos = 0, .address_pos = 10};
+ break;
+ case hci::OpCode::LE_CREATE_CONNECTION:
+ classification = {.activity = Activity::CONNECT, .connection_handle_pos = 0, .address_pos = 9};
+ break;
+ case hci::OpCode::LE_ADD_DEVICE_TO_CONNECT_LIST:
+ case hci::OpCode::LE_READ_CHANNEL_MAP:
+ classification = {.activity = Activity::CONNECT, .connection_handle_pos = 4, .address_pos = 0};
+ break;
+
+ case hci::OpCode::LE_REMOVE_DEVICE_FROM_CONNECT_LIST:
+ case hci::OpCode::LE_ADD_DEVICE_TO_RESOLVING_LIST:
+ case hci::OpCode::LE_REMOVE_DEVICE_FROM_RESOLVING_LIST:
+ case hci::OpCode::LE_READ_PEER_RESOLVABLE_ADDRESS:
+ case hci::OpCode::LE_READ_LOCAL_RESOLVABLE_ADDRESS:
+ case hci::OpCode::LE_SET_PRIVACY_MODE:
+ classification = {.activity = Activity::CONNECT, .connection_handle_pos = 0, .address_pos = 4};
+ break;
+
+ case hci::OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS:
+ classification = {.activity = Activity::ADVERTISE, .connection_handle_pos = 0, .address_pos = 15};
+ break;
+ case hci::OpCode::LE_EXTENDED_CREATE_CONNECTION:
+ classification = {.activity = Activity::CONNECT, .connection_handle_pos = 0, .address_pos = 6};
+ break;
+ case hci::OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC:
+ classification = {.activity = Activity::SCAN, .connection_handle_pos = 0, .address_pos = 6};
+ break;
+ case hci::OpCode::LE_ADD_DEVICE_TO_PERIODIC_ADVERTISING_LIST:
+ case hci::OpCode::LE_REMOVE_DEVICE_FROM_PERIODIC_ADVERTISING_LIST:
+ classification = {.activity = Activity::SCAN, .connection_handle_pos = 0, .address_pos = 4};
+ break;
+ case hci::OpCode::LE_PERIODIC_ADVERTISING_SYNC_TRANSFER:
+ case hci::OpCode::LE_PERIODIC_ADVERTISING_SET_INFO_TRANSFER:
+ case hci::OpCode::LE_SET_PERIODIC_ADVERTISING_SYNC_TRANSFER_PARAMETERS:
+ classification = {.activity = Activity::SCAN, .connection_handle_pos = 3, .address_pos = 0};
+ break;
+
+ default:
+ classification = {.activity = Activity::UNKNOWN, .connection_handle_pos = 0, .address_pos = 0};
+ break;
+ }
+ return classification;
+}
+
+CmdEvtActivityClassification lookup_event(hci::EventCode event_code) {
+ CmdEvtActivityClassification classification = {};
+ switch (event_code) {
+ case hci::EventCode::INQUIRY_COMPLETE:
+ classification = {.activity = Activity::SCAN, .connection_handle_pos = 0, .address_pos = 0};
+ break;
+ case hci::EventCode::CONNECTION_COMPLETE:
+ case hci::EventCode::SYNCHRONOUS_CONNECTION_COMPLETE:
+ classification = {.activity = Activity::CONNECT, .connection_handle_pos = 3, .address_pos = 5};
+ break;
+
+ case hci::EventCode::CONNECTION_REQUEST:
+ case hci::EventCode::PIN_CODE_REQUEST:
+ case hci::EventCode::LINK_KEY_REQUEST:
+ case hci::EventCode::LINK_KEY_NOTIFICATION:
+ case hci::EventCode::USER_PASSKEY_NOTIFICATION:
+ case hci::EventCode::KEYPRESS_NOTIFICATION:
+ case hci::EventCode::REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION:
+ case hci::EventCode::IO_CAPABILITY_REQUEST:
+ case hci::EventCode::IO_CAPABILITY_RESPONSE:
+ case hci::EventCode::USER_CONFIRMATION_REQUEST:
+ case hci::EventCode::USER_PASSKEY_REQUEST:
+ case hci::EventCode::REMOTE_OOB_DATA_REQUEST:
+ classification = {.activity = Activity::CONNECT, .connection_handle_pos = 0, .address_pos = 2};
+ break;
+
+ case hci::EventCode::DISCONNECTION_COMPLETE:
+ case hci::EventCode::AUTHENTICATION_COMPLETE:
+ case hci::EventCode::ENCRYPTION_CHANGE:
+ case hci::EventCode::ENCRYPTION_KEY_REFRESH_COMPLETE:
+ case hci::EventCode::LINK_SUPERVISION_TIMEOUT_CHANGED:
+ case hci::EventCode::CHANGE_CONNECTION_LINK_KEY_COMPLETE:
+ case hci::EventCode::CENTRAL_LINK_KEY_COMPLETE:
+ case hci::EventCode::READ_REMOTE_SUPPORTED_FEATURES_COMPLETE:
+ case hci::EventCode::READ_REMOTE_VERSION_INFORMATION_COMPLETE:
+ case hci::EventCode::QOS_SETUP_COMPLETE:
+ case hci::EventCode::MODE_CHANGE:
+ case hci::EventCode::READ_CLOCK_OFFSET_COMPLETE:
+ case hci::EventCode::CONNECTION_PACKET_TYPE_CHANGED:
+ case hci::EventCode::FLOW_SPECIFICATION_COMPLETE:
+ case hci::EventCode::READ_REMOTE_EXTENDED_FEATURES_COMPLETE:
+ case hci::EventCode::SYNCHRONOUS_CONNECTION_CHANGED:
+ case hci::EventCode::SNIFF_SUBRATING:
+ classification = {.activity = Activity::CONNECT, .connection_handle_pos = 3, .address_pos = 0};
+ break;
+
+ case hci::EventCode::REMOTE_NAME_REQUEST_COMPLETE:
+ case hci::EventCode::EXTENDED_INQUIRY_RESULT:
+ classification = {.activity = Activity::SCAN, .connection_handle_pos = 0, .address_pos = 3};
+ break;
+ case hci::EventCode::FLUSH_OCCURRED:
+ case hci::EventCode::MAX_SLOTS_CHANGE:
+ case hci::EventCode::QOS_VIOLATION:
+ case hci::EventCode::ENHANCED_FLUSH_COMPLETE:
+ classification = {.activity = Activity::CONNECT, .connection_handle_pos = 2, .address_pos = 0};
+ break;
+ case hci::EventCode::ROLE_CHANGE:
+ case hci::EventCode::SIMPLE_PAIRING_COMPLETE:
+ classification = {.activity = Activity::CONNECT, .connection_handle_pos = 0, .address_pos = 3};
+ break;
+ case hci::EventCode::PAGE_SCAN_REPETITION_MODE_CHANGE:
+ classification = {.activity = Activity::SCAN, .connection_handle_pos = 0, .address_pos = 2};
+ break;
+
+ default:
+ classification = {.activity = Activity::UNKNOWN, .connection_handle_pos = 0, .address_pos = 0};
+ }
+ return classification;
+}
+
+CmdEvtActivityClassification lookup_le_event(hci::SubeventCode subevent_code) {
+ CmdEvtActivityClassification classification = {};
+ switch (subevent_code) {
+ case hci::SubeventCode::CONNECTION_COMPLETE:
+ case hci::SubeventCode::ENHANCED_CONNECTION_COMPLETE:
+ classification = {.activity = Activity::CONNECT, .connection_handle_pos = 4, .address_pos = 7};
+ break;
+
+ case hci::SubeventCode::CONNECTION_UPDATE_COMPLETE:
+ case hci::SubeventCode::READ_REMOTE_FEATURES_COMPLETE:
+ case hci::SubeventCode::PHY_UPDATE_COMPLETE:
+ case hci::SubeventCode::CTE_REQUEST_FAILED:
+ case hci::SubeventCode::TRANSMIT_POWER_REPORTING:
+ classification = {.activity = Activity::CONNECT, .connection_handle_pos = 4, .address_pos = 0};
+ break;
+
+ case hci::SubeventCode::LONG_TERM_KEY_REQUEST:
+ case hci::SubeventCode::REMOTE_CONNECTION_PARAMETER_REQUEST:
+ case hci::SubeventCode::DATA_LENGTH_CHANGE:
+ case hci::SubeventCode::CHANNEL_SELECTION_ALGORITHM:
+ case hci::SubeventCode::CONNECTION_IQ_REPORT:
+ case hci::SubeventCode::PATH_LOSS_THRESHOLD:
+ classification = {.activity = Activity::CONNECT, .connection_handle_pos = 3, .address_pos = 0};
+ break;
+
+ case hci::SubeventCode::READ_LOCAL_P256_PUBLIC_KEY_COMPLETE:
+ case hci::SubeventCode::GENERATE_DHKEY_COMPLETE:
+ classification = {.activity = Activity::CONTROL, .connection_handle_pos = 0, .address_pos = 0};
+ break;
+
+ case hci::SubeventCode::PERIODIC_ADVERTISING_SYNC_ESTABLISHED:
+ case hci::SubeventCode::PERIODIC_ADVERTISING_REPORT:
+ case hci::SubeventCode::PERIODIC_ADVERTISING_SYNC_LOST:
+ case hci::SubeventCode::ADVERTISING_SET_TERMINATED:
+ classification = {.activity = Activity::ADVERTISE, .connection_handle_pos = 0, .address_pos = 0};
+ break;
+
+ case hci::SubeventCode::SCAN_TIMEOUT:
+ case hci::SubeventCode::BIG_INFO_ADVERTISING_REPORT:
+ case hci::SubeventCode::CONNECTIONLESS_IQ_REPORT:
+ case hci::SubeventCode::CREATE_BIG_COMPLETE:
+ case hci::SubeventCode::TERMINATE_BIG_COMPLETE:
+ case hci::SubeventCode::BIG_SYNC_ESTABLISHED:
+ case hci::SubeventCode::BIG_SYNC_LOST:
+ case hci::SubeventCode::REQUEST_PEER_SCA_COMPLETE:
+ classification = {.activity = Activity::SCAN, .connection_handle_pos = 0, .address_pos = 0};
+ break;
+
+ case hci::SubeventCode::SCAN_REQUEST_RECEIVED:
+ classification = {.activity = Activity::ADVERTISE, .connection_handle_pos = 0, .address_pos = 5};
+ break;
+
+ case hci::SubeventCode::PERIODIC_ADVERTISING_SYNC_TRANSFER_RECEIVED:
+ case hci::SubeventCode::CIS_ESTABLISHED:
+ case hci::SubeventCode::CIS_REQUEST:
+ classification = {.activity = Activity::SCAN, .connection_handle_pos = 4, .address_pos = 0};
+ break;
+
+ default:
+ classification = {.activity = Activity::UNKNOWN, .connection_handle_pos = 0, .address_pos = 0};
+ }
+ return classification;
+}
+
+} // namespace activity_attribution
+} // namespace bluetooth
diff --git a/gd/btaa/linux_generic/hci_processor.cc b/gd/btaa/linux_generic/hci_processor.cc
new file mode 100644
index 0000000..60c5969
--- /dev/null
+++ b/gd/btaa/linux_generic/hci_processor.cc
@@ -0,0 +1,268 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "btaa/hci_processor.h"
+
+#include "os/log.h"
+
+namespace bluetooth {
+namespace activity_attribution {
+
+void DeviceParser::match_handle_with_address(uint16_t connection_handle, hci::Address& address) {
+ if (connection_handle && !address.IsEmpty()) {
+ connection_lookup_table_[connection_handle] = address;
+ } else if (connection_handle) {
+ if (connection_lookup_table_.find(connection_handle) != connection_lookup_table_.end()) {
+ address = connection_lookup_table_[connection_handle];
+ }
+ }
+}
+
+void HciProcessor::process_le_event(
+ std::vector<BtaaHciPacket>& btaa_hci_packets, int16_t byte_count, hci::EventView& event) {
+ uint16_t connection_handle_value = 0;
+ hci::Address address_value;
+
+ auto le_packet_view = hci::LeMetaEventView::Create(event);
+ if (!le_packet_view.IsValid()) {
+ return;
+ }
+
+ auto subevent_code = le_packet_view.GetSubeventCode();
+ auto le_event_info = lookup_le_event(subevent_code);
+
+ if (le_event_info.activity != Activity::UNKNOWN) {
+ // lookup_le_event returns all simple classic event which does not require additional processing.
+ if (le_event_info.connection_handle_pos) {
+ auto connection_handle_it = event.begin() + le_event_info.connection_handle_pos;
+ connection_handle_value = connection_handle_it.extract<uint16_t>();
+ }
+ if (le_event_info.address_pos) {
+ auto address_value_it = event.begin() + le_event_info.address_pos;
+ address_value = address_value_it.extract<hci::Address>();
+ }
+ device_parser_.match_handle_with_address(connection_handle_value, address_value);
+ btaa_hci_packets.push_back(BtaaHciPacket(le_event_info.activity, address_value, byte_count));
+ }
+}
+
+void HciProcessor::process_special_event(
+ std::vector<BtaaHciPacket>& btaa_hci_packets,
+ hci::EventCode event_code,
+ uint16_t byte_count,
+ hci::EventView& event) {
+ uint16_t avg_byte_count;
+ hci::Address address_value;
+
+ switch (event_code) {
+ case hci::EventCode::INQUIRY_RESULT:
+ case hci::EventCode::INQUIRY_RESULT_WITH_RSSI: {
+ auto packet_view = hci::InquiryResultView::Create(event);
+ if (!packet_view.IsValid()) {
+ return;
+ }
+ auto inquiry_results = packet_view.GetInquiryResults();
+ avg_byte_count = byte_count / inquiry_results.size();
+ for (auto& inquiry_result : inquiry_results) {
+ btaa_hci_packets.push_back(BtaaHciPacket(Activity::SCAN, inquiry_result.bd_addr_, avg_byte_count));
+ }
+ } break;
+
+ case hci::EventCode::NUMBER_OF_COMPLETED_PACKETS: {
+ auto packet_view = hci::NumberOfCompletedPacketsView::Create(event);
+ if (!packet_view.IsValid()) {
+ return;
+ }
+ auto completed_packets = packet_view.GetCompletedPackets();
+ avg_byte_count = byte_count / completed_packets.size();
+ for (auto& completed_packet : completed_packets) {
+ device_parser_.match_handle_with_address(completed_packet.connection_handle_, address_value);
+ btaa_hci_packets.push_back(BtaaHciPacket(Activity::CONNECT, address_value, avg_byte_count));
+ }
+ } break;
+
+ case hci::EventCode::RETURN_LINK_KEYS: {
+ auto packet_view = hci::ReturnLinkKeysView::Create(event);
+ if (!packet_view.IsValid()) {
+ return;
+ }
+ auto keys_and_addresses = packet_view.GetKeys();
+ avg_byte_count = byte_count / keys_and_addresses.size();
+ for (auto& key_and_address : keys_and_addresses) {
+ btaa_hci_packets.push_back(BtaaHciPacket(Activity::CONNECT, key_and_address.address_, avg_byte_count));
+ }
+ } break;
+
+ default: {
+ btaa_hci_packets.push_back(BtaaHciPacket(Activity::UNKNOWN, address_value, byte_count));
+ } break;
+ }
+}
+
+void HciProcessor::process_command(
+ std::vector<BtaaHciPacket>& btaa_hci_packets,
+ packet::PacketView<packet::kLittleEndian>& packet_view,
+ uint16_t byte_count) {
+ hci::CommandView command = hci::CommandView::Create(packet_view);
+ if (!command.IsValid()) {
+ return;
+ }
+
+ uint16_t connection_handle_value = 0;
+ hci::Address address_value;
+ auto opcode = command.GetOpCode();
+ auto cmd_info = lookup_cmd(opcode);
+
+ if (cmd_info.connection_handle_pos) {
+ auto connection_handle_it = command.begin() + cmd_info.connection_handle_pos;
+ connection_handle_value = connection_handle_it.extract<uint16_t>();
+ }
+ if (cmd_info.address_pos) {
+ auto address_value_it = command.begin() + cmd_info.address_pos;
+ address_value = address_value_it.extract<hci::Address>();
+ }
+ device_parser_.match_handle_with_address(connection_handle_value, address_value);
+ pending_command_.btaa_hci_packet = BtaaHciPacket(cmd_info.activity, address_value, byte_count);
+
+ pending_command_.opcode = opcode;
+}
+
+void HciProcessor::process_event(
+ std::vector<BtaaHciPacket>& btaa_hci_packets,
+ packet::PacketView<packet::kLittleEndian>& packet_view,
+ uint16_t byte_count) {
+ hci::EventView event = hci::EventView::Create(packet_view);
+ if (!event.IsValid()) {
+ return;
+ }
+
+ uint16_t connection_handle_value = 0;
+ hci::Address address_value;
+ auto event_code = event.GetEventCode();
+ auto event_info = lookup_event(event_code);
+
+ if (event_info.activity != Activity::UNKNOWN) {
+ // lookup_event returns all simple classic event which does not require additional processing.
+ if (event_info.connection_handle_pos) {
+ auto connection_handle_it = event.begin() + event_info.connection_handle_pos;
+ connection_handle_value = connection_handle_it.extract<uint16_t>();
+ }
+ if (event_info.address_pos) {
+ auto address_value_it = event.begin() + event_info.address_pos;
+ address_value = address_value_it.extract<hci::Address>();
+ }
+ device_parser_.match_handle_with_address(connection_handle_value, address_value);
+ btaa_hci_packets.push_back(BtaaHciPacket(event_info.activity, address_value, byte_count));
+ } else {
+ // The event requires additional processing.
+ switch (event_code) {
+ case hci::EventCode::COMMAND_COMPLETE: {
+ auto packet_view = hci::CommandCompleteView::Create(event);
+ if (packet_view.IsValid() && packet_view.GetCommandOpCode() == pending_command_.opcode) {
+ pending_command_.btaa_hci_packet.byte_count += byte_count;
+ btaa_hci_packets.push_back(std::move(pending_command_.btaa_hci_packet));
+ } else {
+ btaa_hci_packets.push_back(BtaaHciPacket(Activity::UNKNOWN, address_value, byte_count));
+ }
+ } break;
+ case hci::EventCode::COMMAND_STATUS: {
+ auto packet_view = hci::CommandStatusView::Create(event);
+ if (packet_view.IsValid() && packet_view.GetCommandOpCode() == pending_command_.opcode) {
+ pending_command_.btaa_hci_packet.byte_count += byte_count;
+ btaa_hci_packets.push_back(std::move(pending_command_.btaa_hci_packet));
+ } else {
+ btaa_hci_packets.push_back(BtaaHciPacket(Activity::UNKNOWN, address_value, byte_count));
+ }
+ break;
+ }
+ case hci::EventCode::LE_META_EVENT:
+ process_le_event(btaa_hci_packets, byte_count, event);
+ break;
+ case hci::EventCode::VENDOR_SPECIFIC:
+ btaa_hci_packets.push_back(BtaaHciPacket(Activity::VENDOR, address_value, byte_count));
+ break;
+ default:
+ process_special_event(btaa_hci_packets, event_code, byte_count, event);
+ break;
+ }
+ }
+}
+
+void HciProcessor::process_acl(
+ std::vector<BtaaHciPacket>& btaa_hci_packets,
+ packet::PacketView<packet::kLittleEndian>& packet_view,
+ uint16_t byte_count) {
+ hci::AclView acl = hci::AclView::Create(packet_view);
+ auto connection_handle = acl.begin();
+ // Connection handle is extracted from the 12 least significant bit.
+ uint16_t connection_handle_value = connection_handle.extract<uint16_t>() & 0xfff;
+ hci::Address address_value;
+ device_parser_.match_handle_with_address(connection_handle_value, address_value);
+ btaa_hci_packets.push_back(BtaaHciPacket(Activity::ACL, address_value, byte_count));
+}
+
+void HciProcessor::process_sco(
+ std::vector<BtaaHciPacket>& btaa_hci_packets,
+ packet::PacketView<packet::kLittleEndian>& packet_view,
+ uint16_t byte_count) {
+ hci::ScoView sco = hci::ScoView::Create(packet_view);
+ auto connection_handle = sco.begin();
+ // Connection handle is extracted from the 12 least significant bit.
+ uint16_t connection_handle_value = connection_handle.extract<uint16_t>() & 0xfff;
+ hci::Address address_value;
+ device_parser_.match_handle_with_address(connection_handle_value, address_value);
+ btaa_hci_packets.push_back(BtaaHciPacket(Activity::HFP, address_value, byte_count));
+}
+
+void HciProcessor::process_iso(
+ std::vector<BtaaHciPacket>& btaa_hci_packets,
+ packet::PacketView<packet::kLittleEndian>& packet_view,
+ uint16_t byte_count) {
+ hci::IsoView iso = hci::IsoView::Create(packet_view);
+ auto connection_handle = iso.begin();
+ // Connection handle is extracted from the 12 least significant bit.
+ uint16_t connection_handle_value = connection_handle.extract<uint16_t>() & 0xfff;
+ hci::Address address_value;
+ device_parser_.match_handle_with_address(connection_handle_value, address_value);
+ btaa_hci_packets.push_back(BtaaHciPacket(Activity::ISO, address_value, byte_count));
+}
+
+std::vector<BtaaHciPacket> HciProcessor::OnHciPacket(
+ hal::HciPacket packet, hal::SnoopLogger::PacketType type, uint16_t length) {
+ std::vector<BtaaHciPacket> btaa_hci_packets;
+ auto packet_view = packet::PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>(packet));
+ switch (type) {
+ case hal::SnoopLogger::PacketType::CMD:
+ process_command(btaa_hci_packets, packet_view, length);
+ break;
+ case hal::SnoopLogger::PacketType::EVT:
+ process_event(btaa_hci_packets, packet_view, length);
+ break;
+ case hal::SnoopLogger::PacketType::ACL:
+ process_acl(btaa_hci_packets, packet_view, length);
+ break;
+ case hal::SnoopLogger::PacketType::SCO:
+ process_sco(btaa_hci_packets, packet_view, length);
+ break;
+ case hal::SnoopLogger::PacketType::ISO:
+ process_iso(btaa_hci_packets, packet_view, length);
+ break;
+ }
+ return btaa_hci_packets;
+}
+
+} // namespace activity_attribution
+} // namespace bluetooth
diff --git a/gd/btaa/linux_generic/wakelock_processor.cc b/gd/btaa/linux_generic/wakelock_processor.cc
new file mode 100644
index 0000000..bd3b3ed
--- /dev/null
+++ b/gd/btaa/linux_generic/wakelock_processor.cc
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "btaa/wakelock_processor.h"
+
+#include "os/log.h"
+
+namespace bluetooth {
+namespace activity_attribution {
+
+static const int kWakelockMaxDurationMs(10000);
+
+WakelockProcessor::WakelockProcessor() {
+ wakelock_net_count_ = 0;
+ wakelock_acquired_time_ = {};
+}
+
+uint32_t WakelockProcessor::OnWakelockReleased() {
+ auto cur_time = std::chrono::system_clock::now();
+ uint32_t wakelock_duration_ms = 0;
+
+ if (wakelock_net_count_ == 0) {
+ LOG_INFO("Release a never acquired wakelock, ignored.");
+ } else {
+ wakelock_net_count_--;
+ if (wakelock_net_count_ == 0) {
+ wakelock_duration_ms = static_cast<uint32_t>(
+ std::chrono::duration_cast<std::chrono::milliseconds>(cur_time - wakelock_acquired_time_).count());
+ wakelock_acquired_time_ = {};
+ }
+ }
+
+ return wakelock_duration_ms;
+}
+
+void WakelockProcessor::OnWakelockAcquired() {
+ auto cur_time = std::chrono::system_clock::now();
+
+ if (wakelock_net_count_ == 0) {
+ if (wakelock_acquired_time_.time_since_epoch().count()) {
+ LOG_INFO("Previous wakelock acquired time is not consumed, dropped.");
+ }
+ wakelock_acquired_time_ = cur_time;
+ } else if (cur_time - wakelock_acquired_time_ > std::chrono::milliseconds(kWakelockMaxDurationMs)) {
+ LOG_INFO("Wakelock held for too long, likely we missed a release notification. Resetting wakelock stats.");
+ wakelock_net_count_ = 0;
+ wakelock_acquired_time_ = cur_time;
+ }
+
+ wakelock_net_count_++;
+}
+
+} // namespace activity_attribution
+} // namespace bluetooth
diff --git a/gd/shim/only_include_this_file_into_legacy_stack___ever.h b/gd/btaa/wakelock_processor.h
similarity index 60%
copy from gd/shim/only_include_this_file_into_legacy_stack___ever.h
copy to gd/btaa/wakelock_processor.h
index 5658ce8..8b700d2 100644
--- a/gd/shim/only_include_this_file_into_legacy_stack___ever.h
+++ b/gd/btaa/wakelock_processor.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 The Android Open Source Project
+ * Copyright 2020 The Android Open 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,16 +16,23 @@
#pragma once
-/**
- * This common file provides the only visibility from the legacy stack into GD stack.
- *
- * Only interfaces or APIs should be exported.
- *
- * Only common data structures should be used to pass data between the stacks.
- *
- */
+#include <chrono>
+#include <cstdint>
+
namespace bluetooth {
-namespace shim {
-class Dumpsys;
-} // namespace shim
+namespace activity_attribution {
+
+class WakelockProcessor {
+ public:
+ WakelockProcessor();
+
+ uint32_t OnWakelockReleased();
+ void OnWakelockAcquired();
+
+ private:
+ std::chrono::time_point<std::chrono::system_clock> wakelock_acquired_time_;
+ uint8_t wakelock_net_count_;
+};
+
+} // namespace activity_attribution
} // namespace bluetooth
diff --git a/gd/cert/gd_base_test.py b/gd/cert/gd_base_test.py
index b382e6a..6ed7f7d 100644
--- a/gd/cert/gd_base_test.py
+++ b/gd/cert/gd_base_test.py
@@ -64,6 +64,7 @@
self.rootcanal_running = self.info['rootcanal_running']
self.rootcanal_logpath = self.info['rootcanal_logpath']
self.rootcanal_process = self.info['rootcanal_process']
+ self.rootcanal_logger = self.info['rootcanal_logger']
if 'rootcanal' in self.controller_configs:
asserts.assert_true(self.info['rootcanal_exist'],
@@ -77,7 +78,6 @@
msg="Cannot start root-canal at " + str(self.info['rootcanal']))
asserts.assert_true(self.info['is_subprocess_alive'], msg="root-canal stopped immediately after running")
- self.rootcanal_logger = self.info['rootcanal_logger']
self.controller_configs = self.info['controller_configs']
# Parse and construct GD device objects
diff --git a/gd/cert/gd_base_test_lib.py b/gd/cert/gd_base_test_lib.py
index 19b83f1..0cc3fac 100644
--- a/gd/cert/gd_base_test_lib.py
+++ b/gd/cert/gd_base_test_lib.py
@@ -42,6 +42,9 @@
# Start root-canal if needed
info['rootcanal_running'] = False
+ info['rootcanal_logpath'] = None
+ info['rootcanal_process'] = None
+ info['rootcanal_logger'] = None
if 'rootcanal' in info['controller_configs']:
info['rootcanal_running'] = True
# Get root canal binary
diff --git a/gd/cert/run b/gd/cert/run
index e1183a9..e666c5f 100755
--- a/gd/cert/run
+++ b/gd/cert/run
@@ -324,7 +324,6 @@
cp {$HOST_LIB,$DEST_LIB_DIR}/libz-host.so
cp {$HOST_LIB,$DEST_LIB_DIR}/libprotobuf-cpp-full.so
cp {$HOST_LIB,$DEST_LIB_DIR}/libunwindstack.so
- cp {$HOST_LIB,$DEST_LIB_DIR}/libdexfile_support.so
cp {$HOST_LIB,$DEST_LIB_DIR}/liblzma.so
cp {$HOST_LIB,$DEST_LIB_DIR}/libbacktrace.so
diff --git a/gd/common/Android.bp b/gd/common/Android.bp
index ff2492a..27d559a 100644
--- a/gd/common/Android.bp
+++ b/gd/common/Android.bp
@@ -14,7 +14,6 @@
"metric_id_manager.cc",
"strings.cc",
"stop_watch.cc",
- "metrics.cc",
],
}
diff --git a/gd/common/BUILD.gn b/gd/common/BUILD.gn
index 17d9660..fb4dad9 100644
--- a/gd/common/BUILD.gn
+++ b/gd/common/BUILD.gn
@@ -17,8 +17,7 @@
source_set("BluetoothCommonSources") {
sources = [
"init_flags.cc",
- "metric_id_manager.cc"
- "metrics_linux.cc",
+ "metric_id_manager.cc",
"stop_watch.cc",
"strings.cc",
]
@@ -26,6 +25,6 @@
configs += [ "//bt/gd:gd_defaults" ]
deps = [
"//bt/gd:gd_default_deps",
- "//bt/third_party/proto_logging/stats:libbt-platform-protos"
+ "//bt:libbt-platform-protos-lite",
]
}
diff --git a/gd/common/bind.h b/gd/common/bind.h
index e65d830..e46d3d2 100644
--- a/gd/common/bind.h
+++ b/gd/common/bind.h
@@ -24,7 +24,12 @@
using base::Bind;
using base::BindOnce;
using base::IgnoreResult;
+#if defined(BASE_VER) && BASE_VER >= 860220
+// TODO(b/189293646): find a way to avoid base::internal.
+using base::internal::MakeUnboundRunType;
+#else
using base::MakeUnboundRunType;
+#endif
using base::Owned;
using base::Passed;
using base::RetainedRef;
diff --git a/gd/common/circular_buffer.h b/gd/common/circular_buffer.h
index 1914fa0..46d6972 100644
--- a/gd/common/circular_buffer.h
+++ b/gd/common/circular_buffer.h
@@ -18,6 +18,7 @@
#include <cstddef>
#include <iterator>
+#include <memory>
#include <mutex>
#include <queue>
diff --git a/gd/common/stop_watch.cc b/gd/common/stop_watch.cc
index b3033a7..e5e003a 100644
--- a/gd/common/stop_watch.cc
+++ b/gd/common/stop_watch.cc
@@ -29,10 +29,10 @@
namespace common {
static const int LOG_BUFFER_LENGTH = 10;
-static std::array<std::string, LOG_BUFFER_LENGTH> stopwatch_logs;
+static std::array<StopWatchLog, LOG_BUFFER_LENGTH> stopwatch_logs;
static int current_buffer_index;
-void StopWatch::RecordLog(std::string log) {
+void StopWatch::RecordLog(StopWatchLog log) {
if (current_buffer_index >= LOG_BUFFER_LENGTH) {
current_buffer_index = 0;
}
@@ -41,41 +41,50 @@
}
void StopWatch::DumpStopWatchLog() {
- LOG_INFO("=====================================");
+ LOG_INFO("=-----------------------------------=");
LOG_INFO("bluetooth stopwatch log history:");
for (int i = 0; i < LOG_BUFFER_LENGTH; i++) {
if (current_buffer_index >= LOG_BUFFER_LENGTH) {
current_buffer_index = 0;
}
- if (stopwatch_logs[current_buffer_index].empty()) {
+ if (stopwatch_logs[current_buffer_index].message.empty()) {
break;
}
- LOG_DEBUG("%s", stopwatch_logs[current_buffer_index].c_str());
+ std::stringstream ss;
+ auto now = stopwatch_logs[current_buffer_index].timestamp;
+ auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(
+ now.time_since_epoch()) %
+ 1000;
+ auto now_time_t = std::chrono::system_clock::to_time_t(now);
+ ss << std::put_time(std::localtime(&now_time_t), "%Y-%m-%d %H:%M:%S");
+ ss << '.' << std::setfill('0') << std::setw(3) << millis.count();
+ std::string start_timestamp = ss.str();
+ LOG_INFO(
+ "%s: %s: took %zu us",
+ start_timestamp.c_str(),
+ stopwatch_logs[current_buffer_index].message.c_str(),
+ static_cast<size_t>(std::chrono::duration_cast<std::chrono::microseconds>(
+ stopwatch_logs[current_buffer_index].end_timestamp -
+ stopwatch_logs[current_buffer_index].start_timestamp)
+ .count()));
current_buffer_index++;
}
- LOG_INFO("=====================================");
+ LOG_INFO("=-----------------------------------=");
}
StopWatch::StopWatch(std::string text)
- : text_(std::move(text)), start_time_(std::chrono::high_resolution_clock::now()) {
- std::stringstream ss;
- auto now = std::chrono::system_clock::now();
- auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
- auto now_time_t = std::chrono::system_clock::to_time_t(now);
- ss << std::put_time(std::localtime(&now_time_t), "%Y-%m-%d %H:%M:%S");
- ss << '.' << std::setfill('0') << std::setw(3) << millis.count();
- start_timestamp_ = ss.str();
-
- RecordLog(start_timestamp_ + ": " + text_);
-}
+ : text_(std::move(text)),
+ timestamp_(std::chrono::system_clock::now()),
+ start_timestamp_(std::chrono::high_resolution_clock::now()) {}
StopWatch::~StopWatch() {
- RecordLog(
- start_timestamp_ + ": " + text_ + ": took " +
- std::to_string(static_cast<size_t>(
- std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - start_time_)
- .count())) +
- " us");
+ StopWatchLog sw_log;
+ sw_log.timestamp = timestamp_;
+ sw_log.start_timestamp = start_timestamp_;
+ sw_log.end_timestamp = std::chrono::high_resolution_clock::now();
+ sw_log.message = std::move(text_);
+
+ RecordLog(std::move(sw_log));
}
} // namespace common
diff --git a/gd/common/stop_watch.h b/gd/common/stop_watch.h
index 646b8ae..4d7d544 100644
--- a/gd/common/stop_watch.h
+++ b/gd/common/stop_watch.h
@@ -22,6 +22,13 @@
namespace bluetooth {
namespace common {
+typedef struct {
+ std::chrono::system_clock::time_point timestamp;
+ std::chrono::high_resolution_clock::time_point start_timestamp;
+ std::chrono::high_resolution_clock::time_point end_timestamp;
+ std::string message;
+} StopWatchLog;
+
class StopWatch {
public:
static void DumpStopWatchLog(void);
@@ -30,9 +37,9 @@
private:
std::string text_;
- std::chrono::time_point<std::chrono::high_resolution_clock> start_time_;
- std::string start_timestamp_;
- void RecordLog(std::string log);
+ std::chrono::system_clock::time_point timestamp_;
+ std::chrono::high_resolution_clock::time_point start_timestamp_;
+ void RecordLog(StopWatchLog log);
};
} // namespace common
diff --git a/gd/common/strings.h b/gd/common/strings.h
index a110cf4..c80d01e 100644
--- a/gd/common/strings.h
+++ b/gd/common/strings.h
@@ -16,6 +16,7 @@
#pragma once
+#include <limits.h>
#include <string.h>
#include <charconv>
#include <iomanip>
diff --git a/gd/docs/architecture/style_guide.md b/gd/docs/architecture/style_guide.md
index 1711dc7..08d377b 100644
--- a/gd/docs/architecture/style_guide.md
+++ b/gd/docs/architecture/style_guide.md
@@ -113,8 +113,10 @@
* hci_hal_android_hidl.cc: implementation of hci_hal.h using Android HIDL
* hci_hal_android_hidl_test.cc: unit tests for the Android HIDL
implementation
- * hci_hal_host.cc: implementation of hci_hal.h using root-canal
- emulator or linux Bluetooth HCI socket
+ * hci_hal_host.cc: implementation of hci_hal.h using linux Bluetooth HCI
+ socket
+ * hci_hal_host_rootcanal.cc: implementation of hci_hal.h using root-canal
+ emulator
* hci_hal_host_test.cc: unit tests for the socket based HAL (root-canal)
emulator implementation
* facade.proto: gRPC automation interface definition for this layer
diff --git a/gd/dumpsys/Android.bp b/gd/dumpsys/Android.bp
index 4ad6376..74b32dd 100644
--- a/gd/dumpsys/Android.bp
+++ b/gd/dumpsys/Android.bp
@@ -127,7 +127,7 @@
}
cc_test {
- name: "bluetooth_flatbuffer_test",
+ name: "bluetooth_flatbuffer_tests",
test_suites: ["device-tests"],
host_supported: true,
test_options: {
diff --git a/gd/dumpsys_data.fbs b/gd/dumpsys_data.fbs
index 5c3c76b..87f1461 100644
--- a/gd/dumpsys_data.fbs
+++ b/gd/dumpsys_data.fbs
@@ -1,8 +1,10 @@
// Top level module dumpsys data schema
+include "btaa/activity_attribution.fbs";
include "common/init_flags.fbs";
include "l2cap/classic/l2cap_classic_module.fbs";
include "hci/hci_acl_manager.fbs";
include "module_unittest.fbs";
+include "os/wakelock_manager.fbs";
include "shim/dumpsys.fbs";
namespace bluetooth;
@@ -12,10 +14,12 @@
table DumpsysData {
title:string;
init_flags:common.InitFlagsData (privacy:"Any");
+ wakelock_manager_data:bluetooth.os.WakelockManagerData (privacy:"Any");
shim_dumpsys_data:bluetooth.shim.DumpsysModuleData (privacy:"Any");
l2cap_classic_dumpsys_data:bluetooth.l2cap.classic.L2capClassicModuleData (privacy:"Any");
hci_acl_manager_dumpsys_data:bluetooth.hci.AclManagerData (privacy:"Any");
module_unittest_data:bluetooth.ModuleUnitTestData; // private
+ activity_attribution_dumpsys_data:bluetooth.activity_attribution.ActivityAttributionData (privacy:"Any");
}
root_type DumpsysData;
diff --git a/gd/hal/Android.bp b/gd/hal/Android.bp
index 1e7c18d..978b4ca 100644
--- a/gd/hal/Android.bp
+++ b/gd/hal/Android.bp
@@ -24,7 +24,7 @@
filegroup {
name: "BluetoothHalSources_hci_host",
srcs: [
- "hci_hal_host.cc",
+ "hci_hal_host_rootcanal.cc",
],
}
diff --git a/gd/hal/BUILD.gn b/gd/hal/BUILD.gn
index 1752241..9ed814a 100644
--- a/gd/hal/BUILD.gn
+++ b/gd/hal/BUILD.gn
@@ -21,8 +21,8 @@
deps = [ "//bt/gd:gd_default_deps" ]
}
-source_set("BluetoothHalSources_hci_rootcanal") {
- sources = [ "hci_hal_host_rootcanal.cc" ]
+source_set("BluetoothHalSources_hci_host") {
+ sources = [ "hci_hal_host.cc" ]
configs += [ "//bt/gd:gd_defaults" ]
deps = [ "//bt/gd:gd_default_deps" ]
diff --git a/gd/hal/cert/simple_hal_test.py b/gd/hal/cert/simple_hal_test.py
index c2224ee..3d96265 100644
--- a/gd/hal/cert/simple_hal_test.py
+++ b/gd/hal/cert/simple_hal_test.py
@@ -14,128 +14,21 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from datetime import timedelta
-
from cert.gd_base_test import GdBaseTestClass
-from cert.event_stream import EventStream
-from cert.truth import assertThat
-from cert.py_hal import PyHal
-from cert.matchers import HciMatchers
-from cert.captures import HciCaptures
-from google.protobuf import empty_pb2
-from facade import rootservice_pb2 as facade_rootservice_pb2
-from hal import hal_facade_pb2 as hal_facade_pb2
-from bluetooth_packets_python3 import hci_packets
-import bluetooth_packets_python3 as bt_packets
-from bluetooth_packets_python3.hci_packets import AclBuilder
-from bluetooth_packets_python3 import RawBuilder
+from hal.cert.simple_hal_test_lib import SimpleHalTestBase
_GRPC_TIMEOUT = 10
-class SimpleHalTest(GdBaseTestClass):
+class SimpleHalTest(GdBaseTestClass, SimpleHalTestBase):
def setup_class(self):
- super().setup_class(dut_module='HAL', cert_module='HAL')
+ GdBaseTestClass.setup_class(self, dut_module='HAL', cert_module='HAL')
def setup_test(self):
- super().setup_test()
-
- self.dut_hal = PyHal(self.dut)
- self.cert_hal = PyHal(self.cert)
-
- self.dut_hal.reset()
- self.cert_hal.reset()
+ GdBaseTestClass.setup_test(self)
+ SimpleHalTestBase.setup_test(self, self.dut, self.cert)
def teardown_test(self):
- self.dut_hal.close()
- self.cert_hal.close()
- super().teardown_test()
-
- def test_stream_events(self):
- self.dut_hal.send_hci_command(
- hci_packets.LeAddDeviceToConnectListBuilder(hci_packets.ConnectListAddressType.RANDOM, '0C:05:04:03:02:01'))
-
- assertThat(self.dut_hal.get_hci_event_stream()).emits(
- HciMatchers.Exactly(hci_packets.LeAddDeviceToConnectListCompleteBuilder(1, hci_packets.ErrorCode.SUCCESS)))
-
- def test_loopback_hci_command(self):
- self.dut_hal.send_hci_command(hci_packets.WriteLoopbackModeBuilder(hci_packets.LoopbackMode.ENABLE_LOCAL))
-
- command = hci_packets.LeAddDeviceToConnectListBuilder(hci_packets.ConnectListAddressType.RANDOM,
- '0C:05:04:03:02:01')
- self.dut_hal.send_hci_command(command)
-
- assertThat(self.dut_hal.get_hci_event_stream()).emits(HciMatchers.LoopbackOf(command))
-
- def test_inquiry_from_dut(self):
- self.cert_hal.send_hci_command(hci_packets.WriteScanEnableBuilder(hci_packets.ScanEnable.INQUIRY_AND_PAGE_SCAN))
-
- lap = hci_packets.Lap()
- lap.lap = 0x33
- self.dut_hal.send_hci_command(hci_packets.InquiryBuilder(lap, 0x30, 0xff))
-
- assertThat(self.dut_hal.get_hci_event_stream()).emits(lambda packet: b'\x02\x0f' in packet.payload
- # Expecting an HCI Event (code 0x02, length 0x0f)
- )
-
- def test_le_ad_scan_cert_advertises(self):
- self.dut_hal.set_random_le_address('0D:05:04:03:02:01')
-
- self.dut_hal.set_scan_parameters()
- self.dut_hal.start_scanning()
-
- advertisement = self.cert_hal.create_advertisement(
- 0,
- '0C:05:04:03:02:01',
- min_interval=512,
- max_interval=768,
- peer_address='A6:A5:A4:A3:A2:A1',
- tx_power=0x7f,
- sid=1)
- advertisement.set_data(b'Im_A_Cert')
- advertisement.start()
-
- assertThat(self.dut_hal.get_hci_event_stream()).emits(lambda packet: b'Im_A_Cert' in packet.payload)
-
- advertisement.stop()
-
- self.dut_hal.stop_scanning()
-
- def test_le_connection_dut_advertises(self):
- self.cert_hal.set_random_le_address('0C:05:04:03:02:01')
- self.cert_hal.initiate_le_connection('0D:05:04:03:02:01')
-
- # DUT Advertises
- advertisement = self.dut_hal.create_advertisement(0, '0D:05:04:03:02:01')
- advertisement.set_data(b'Im_The_DUT')
- advertisement.set_scan_response(b'Im_The_D')
- advertisement.start()
-
- cert_acl = self.cert_hal.complete_le_connection()
- dut_acl = self.dut_hal.complete_le_connection()
-
- dut_acl.send_first(b'Just SomeAclData')
- cert_acl.send_first(b'Just SomeMoreAclData')
-
- assertThat(self.cert_hal.get_acl_stream()).emits(lambda packet: b'SomeAclData' in packet.payload)
- assertThat(self.dut_hal.get_acl_stream()).emits(lambda packet: b'SomeMoreAclData' in packet.payload)
-
- def test_le_connect_list_connection_cert_advertises(self):
- self.dut_hal.set_random_le_address('0D:05:04:03:02:01')
- self.dut_hal.add_to_connect_list('0C:05:04:03:02:01')
- self.dut_hal.initiate_le_connection_by_connect_list('BA:D5:A4:A3:A2:A1')
-
- advertisement = self.cert_hal.create_advertisement(
- 1,
- '0C:05:04:03:02:01',
- min_interval=512,
- max_interval=768,
- peer_address='A6:A5:A4:A3:A2:A1',
- tx_power=0x7F,
- sid=0)
- advertisement.set_data(b'Im_A_Cert')
- advertisement.start()
-
- assertThat(self.cert_hal.get_hci_event_stream()).emits(HciMatchers.LeConnectionComplete())
- assertThat(self.dut_hal.get_hci_event_stream()).emits(HciMatchers.LeConnectionComplete())
+ SimpleHalTestBase.teardown_test(self)
+ GdBaseTestClass.teardown_test(self)
diff --git a/gd/hal/cert/simple_hal_test_lib.py b/gd/hal/cert/simple_hal_test_lib.py
new file mode 100644
index 0000000..9ccef7a
--- /dev/null
+++ b/gd/hal/cert/simple_hal_test_lib.py
@@ -0,0 +1,134 @@
+#!/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 datetime import timedelta
+
+from cert.event_stream import EventStream
+from cert.truth import assertThat
+from cert.py_hal import PyHal
+from cert.matchers import HciMatchers
+from cert.captures import HciCaptures
+from google.protobuf import empty_pb2
+from facade import rootservice_pb2 as facade_rootservice_pb2
+from hal import hal_facade_pb2 as hal_facade_pb2
+from bluetooth_packets_python3 import hci_packets
+import bluetooth_packets_python3 as bt_packets
+from bluetooth_packets_python3.hci_packets import AclBuilder
+from bluetooth_packets_python3 import RawBuilder
+
+_GRPC_TIMEOUT = 10
+
+
+class SimpleHalTestBase():
+
+ def setup_test(self, dut, cert):
+ self.dut_hal = PyHal(dut)
+ self.cert_hal = PyHal(cert)
+
+ self.dut_hal.reset()
+ self.cert_hal.reset()
+
+ def teardown_test(self):
+ self.dut_hal.close()
+ self.cert_hal.close()
+
+ def test_stream_events(self):
+ self.dut_hal.send_hci_command(
+ hci_packets.LeAddDeviceToConnectListBuilder(hci_packets.ConnectListAddressType.RANDOM, '0C:05:04:03:02:01'))
+
+ assertThat(self.dut_hal.get_hci_event_stream()).emits(
+ HciMatchers.Exactly(hci_packets.LeAddDeviceToConnectListCompleteBuilder(1, hci_packets.ErrorCode.SUCCESS)))
+
+ def test_loopback_hci_command(self):
+ self.dut_hal.send_hci_command(hci_packets.WriteLoopbackModeBuilder(hci_packets.LoopbackMode.ENABLE_LOCAL))
+
+ command = hci_packets.LeAddDeviceToConnectListBuilder(hci_packets.ConnectListAddressType.RANDOM,
+ '0C:05:04:03:02:01')
+ self.dut_hal.send_hci_command(command)
+
+ assertThat(self.dut_hal.get_hci_event_stream()).emits(HciMatchers.LoopbackOf(command))
+
+ def test_inquiry_from_dut(self):
+ self.cert_hal.send_hci_command(hci_packets.WriteScanEnableBuilder(hci_packets.ScanEnable.INQUIRY_AND_PAGE_SCAN))
+
+ lap = hci_packets.Lap()
+ lap.lap = 0x33
+ self.dut_hal.send_hci_command(hci_packets.InquiryBuilder(lap, 0x30, 0xff))
+
+ assertThat(self.dut_hal.get_hci_event_stream()).emits(lambda packet: b'\x02\x0f' in packet.payload
+ # Expecting an HCI Event (code 0x02, length 0x0f)
+ )
+
+ def test_le_ad_scan_cert_advertises(self):
+ self.dut_hal.set_random_le_address('0D:05:04:03:02:01')
+
+ self.dut_hal.set_scan_parameters()
+ self.dut_hal.start_scanning()
+
+ advertisement = self.cert_hal.create_advertisement(
+ 0,
+ '0C:05:04:03:02:01',
+ min_interval=512,
+ max_interval=768,
+ peer_address='A6:A5:A4:A3:A2:A1',
+ tx_power=0x7f,
+ sid=1)
+ advertisement.set_data(b'Im_A_Cert')
+ advertisement.start()
+
+ assertThat(self.dut_hal.get_hci_event_stream()).emits(lambda packet: b'Im_A_Cert' in packet.payload)
+
+ advertisement.stop()
+
+ self.dut_hal.stop_scanning()
+
+ def test_le_connection_dut_advertises(self):
+ self.cert_hal.set_random_le_address('0C:05:04:03:02:01')
+ self.cert_hal.initiate_le_connection('0D:05:04:03:02:01')
+
+ # DUT Advertises
+ advertisement = self.dut_hal.create_advertisement(0, '0D:05:04:03:02:01')
+ advertisement.set_data(b'Im_The_DUT')
+ advertisement.set_scan_response(b'Im_The_D')
+ advertisement.start()
+
+ cert_acl = self.cert_hal.complete_le_connection()
+ dut_acl = self.dut_hal.complete_le_connection()
+
+ dut_acl.send_first(b'Just SomeAclData')
+ cert_acl.send_first(b'Just SomeMoreAclData')
+
+ assertThat(self.cert_hal.get_acl_stream()).emits(lambda packet: b'SomeAclData' in packet.payload)
+ assertThat(self.dut_hal.get_acl_stream()).emits(lambda packet: b'SomeMoreAclData' in packet.payload)
+
+ def test_le_connect_list_connection_cert_advertises(self):
+ self.dut_hal.set_random_le_address('0D:05:04:03:02:01')
+ self.dut_hal.add_to_connect_list('0C:05:04:03:02:01')
+ self.dut_hal.initiate_le_connection_by_connect_list('BA:D5:A4:A3:A2:A1')
+
+ advertisement = self.cert_hal.create_advertisement(
+ 1,
+ '0C:05:04:03:02:01',
+ min_interval=512,
+ max_interval=768,
+ peer_address='A6:A5:A4:A3:A2:A1',
+ tx_power=0x7F,
+ sid=0)
+ advertisement.set_data(b'Im_A_Cert')
+ advertisement.start()
+
+ assertThat(self.cert_hal.get_hci_event_stream()).emits(HciMatchers.LeConnectionComplete())
+ assertThat(self.dut_hal.get_hci_event_stream()).emits(HciMatchers.LeConnectionComplete())
diff --git a/gd/hal/hci_hal_android_hidl.cc b/gd/hal/hci_hal_android_hidl.cc
index d7a983a..0195237 100644
--- a/gd/hal/hci_hal_android_hidl.cc
+++ b/gd/hal/hci_hal_android_hidl.cc
@@ -241,6 +241,10 @@
bt_hci_1_1_ = nullptr;
}
+ std::string ToString() const override {
+ return std::string("HciHalHidl");
+ }
+
private:
android::sp<InternalHciCallbacks> callbacks_;
android::sp<IBluetoothHci_1_0> bt_hci_;
diff --git a/gd/hal/hci_hal_host.cc b/gd/hal/hci_hal_host.cc
index 4069e96..b41fbd4 100644
--- a/gd/hal/hci_hal_host.cc
+++ b/gd/hal/hci_hal_host.cc
@@ -17,6 +17,7 @@
#include "hal/hci_hal_host.h"
#include <netdb.h>
+#include <netinet/in.h>
#include <poll.h>
#include <sys/socket.h>
#include <sys/types.h>
@@ -49,7 +50,6 @@
constexpr uint8_t kHciIsoHeaderSize = 4;
constexpr int kBufSize = 1024 + 4 + 1; // DeviceProperties::acl_data_packet_size_ + ACL header + H4 header
-#ifdef USE_LINUX_HCI_SOCKET
constexpr uint8_t BTPROTO_HCI = 1;
constexpr uint16_t HCI_CHANNEL_USER = 1;
constexpr uint16_t HCI_CHANNEL_CONTROL = 3;
@@ -196,51 +196,7 @@
LOG_INFO("HCI device ready");
return socket_fd;
}
-#else
-// Connect to root canal socket
-int ConnectToSocket() {
- auto* config = bluetooth::hal::HciHalHostRootcanalConfig::Get();
- const std::string& server = config->GetServerAddress();
- int port = config->GetPort();
-
- 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;
}
-#endif
-} // namespace
namespace bluetooth {
namespace hal {
@@ -341,6 +297,10 @@
LOG_INFO("HAL is closed");
}
+ std::string ToString() const override {
+ return std::string("HciHalHost");
+ }
+
private:
// Held when APIs are called, NOT to be held during callbacks
std::mutex api_mutex_;
@@ -391,7 +351,7 @@
uint8_t buf[kBufSize] = {};
ssize_t received_size;
- RUN_NO_INTR(received_size = recv(sock_fd_, buf, kH4HeaderSize, 0));
+ RUN_NO_INTR(received_size = read(sock_fd_, buf, kBufSize));
ASSERT_LOG(received_size != -1, "Can't receive from socket: %s", strerror(errno));
if (received_size == 0) {
LOG_WARN("Can't read H4 header. EOF received");
@@ -400,15 +360,10 @@
}
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");
-
+ ASSERT_LOG(
+ received_size >= kH4HeaderSize + kHciEvtHeaderSize, "Received bad HCI_EVT packet size: %zu", received_size);
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));
+ ssize_t payload_size = received_size - (kH4HeaderSize + kHciEvtHeaderSize);
ASSERT_LOG(
payload_size == hci_evt_parameter_total_length,
"malformed HCI event total parameter size received: %zu != %d",
@@ -429,14 +384,10 @@
}
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");
-
+ ASSERT_LOG(
+ received_size >= kH4HeaderSize + kHciAclHeaderSize, "Received bad HCI_ACL packet size: %zu", received_size);
+ int payload_size = received_size - (kH4HeaderSize + kHciAclHeaderSize);
uint16_t hci_acl_data_total_length = (buf[4] << 8) + 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",
@@ -458,15 +409,15 @@
}
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");
-
+ ASSERT_LOG(
+ received_size >= kH4HeaderSize + kHciScoHeaderSize, "Received bad HCI_SCO packet size: %zu", received_size);
+ int payload_size = received_size - (kH4HeaderSize + kHciScoHeaderSize);
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");
+ ASSERT_LOG(
+ payload_size == hci_sco_data_total_length,
+ "malformed SCO length received: %d != %d",
+ payload_size,
+ hci_sco_data_total_length);
HciPacket receivedHciPacket;
receivedHciPacket.assign(buf + kH4HeaderSize, buf + kH4HeaderSize + kHciScoHeaderSize + payload_size);
@@ -482,15 +433,15 @@
}
if (buf[0] == kH4Iso) {
- RUN_NO_INTR(received_size = recv(sock_fd_, buf + kH4HeaderSize, kHciIsoHeaderSize, 0));
- ASSERT_LOG(received_size != -1, "Can't receive from socket: %s", strerror(errno));
- ASSERT_LOG(received_size == kHciIsoHeaderSize, "malformed ISO header received");
-
+ ASSERT_LOG(
+ received_size >= kH4HeaderSize + kHciIsoHeaderSize, "Received bad HCI_ISO packet size: %zu", received_size);
+ int payload_size = received_size - (kH4HeaderSize + kHciIsoHeaderSize);
uint16_t hci_iso_data_total_length = ((buf[4] & 0x3f) << 8) + buf[3];
- int payload_size;
- RUN_NO_INTR(payload_size = recv(sock_fd_, buf + kH4HeaderSize + kHciIsoHeaderSize, hci_iso_data_total_length, 0));
- ASSERT_LOG(payload_size != -1, "Can't receive from socket: %s", strerror(errno));
- ASSERT_LOG(payload_size == hci_iso_data_total_length, "malformed ISO packet received: size mismatch");
+ ASSERT_LOG(
+ payload_size == hci_iso_data_total_length,
+ "malformed ISO length received: %d != %d",
+ payload_size,
+ hci_iso_data_total_length);
HciPacket receivedHciPacket;
receivedHciPacket.assign(buf + kH4HeaderSize, buf + kH4HeaderSize + kHciIsoHeaderSize + payload_size);
diff --git a/gd/hal/hci_hal_host_rootcanal.cc b/gd/hal/hci_hal_host_rootcanal.cc
new file mode 100644
index 0000000..b05ae61
--- /dev/null
+++ b/gd/hal/hci_hal_host_rootcanal.cc
@@ -0,0 +1,369 @@
+/*
+ * 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.h"
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <poll.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <chrono>
+#include <csignal>
+#include <mutex>
+#include <queue>
+
+#include "hal/hci_hal.h"
+#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 kH4Iso = 0x05;
+
+constexpr uint8_t kH4HeaderSize = 1;
+constexpr uint8_t kHciAclHeaderSize = 4;
+constexpr uint8_t kHciScoHeaderSize = 3;
+constexpr uint8_t kHciEvtHeaderSize = 2;
+constexpr uint8_t kHciIsoHeaderSize = 4;
+constexpr int kBufSize = 1024 + 4 + 1; // DeviceProperties::acl_data_packet_size_ + ACL header + H4 header
+
+int ConnectToSocket() {
+ auto* config = bluetooth::hal::HciHalHostRootcanalConfig::Get();
+ const std::string& server = config->GetServerAddress();
+ int port = config->GetPort();
+
+ 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 {
+
+class HciHalHost : public HciHal {
+ public:
+ void registerIncomingPacketCallback(HciHalCallbacks* callback) override {
+ std::lock_guard<std::mutex> lock(api_mutex_);
+ LOG_INFO("%s before", __func__);
+ {
+ std::lock_guard<std::mutex> incoming_packet_callback_lock(incoming_packet_callback_mutex_);
+ ASSERT(incoming_packet_callback_ == nullptr && callback != nullptr);
+ incoming_packet_callback_ = callback;
+ }
+ LOG_INFO("%s after", __func__);
+ }
+
+ void unregisterIncomingPacketCallback() override {
+ std::lock_guard<std::mutex> lock(api_mutex_);
+ LOG_INFO("%s before", __func__);
+ {
+ std::lock_guard<std::mutex> incoming_packet_callback_lock(incoming_packet_callback_mutex_);
+ incoming_packet_callback_ = nullptr;
+ }
+ LOG_INFO("%s after", __func__);
+ }
+
+ void sendHciCommand(HciPacket command) override {
+ std::lock_guard<std::mutex> lock(api_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_fd(packet);
+ }
+
+ void sendAclData(HciPacket data) override {
+ std::lock_guard<std::mutex> lock(api_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_fd(packet);
+ }
+
+ void sendScoData(HciPacket data) override {
+ std::lock_guard<std::mutex> lock(api_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_fd(packet);
+ }
+
+ void sendIsoData(HciPacket data) override {
+ std::lock_guard<std::mutex> lock(api_mutex_);
+ ASSERT(sock_fd_ != INVALID_FD);
+ std::vector<uint8_t> packet = std::move(data);
+ btsnoop_logger_->Capture(packet, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::ISO);
+ packet.insert(packet.cbegin(), kH4Iso);
+ write_to_fd(packet);
+ }
+
+ protected:
+ void ListDependencies(ModuleList* list) override {
+ list->add<SnoopLogger>();
+ }
+
+ void Start() override {
+ std::lock_guard<std::mutex> lock(api_mutex_);
+ ASSERT(sock_fd_ == INVALID_FD);
+ sock_fd_ = ConnectToSocket();
+ ASSERT(sock_fd_ != INVALID_FD);
+ reactable_ = hci_incoming_thread_.GetReactor()->Register(
+ sock_fd_, common::Bind(&HciHalHost::incoming_packet_received, common::Unretained(this)), common::Closure());
+ btsnoop_logger_ = GetDependency<SnoopLogger>();
+ LOG_INFO("HAL opened successfully");
+ }
+
+ void Stop() override {
+ std::lock_guard<std::mutex> lock(api_mutex_);
+ LOG_INFO("HAL is closing");
+ if (reactable_ != nullptr) {
+ hci_incoming_thread_.GetReactor()->Unregister(reactable_);
+ LOG_INFO("HAL is stopping, start waiting for last callback");
+ // Wait up to 1 second for the last incoming packet callback to finish
+ hci_incoming_thread_.GetReactor()->WaitForUnregisteredReactable(std::chrono::milliseconds(1000));
+ LOG_INFO("HAL is stopping, finished waiting for last callback");
+ ASSERT(sock_fd_ != INVALID_FD);
+ }
+ reactable_ = nullptr;
+ {
+ std::lock_guard<std::mutex> incoming_packet_callback_lock(incoming_packet_callback_mutex_);
+ incoming_packet_callback_ = nullptr;
+ }
+ ::close(sock_fd_);
+ sock_fd_ = INVALID_FD;
+ LOG_INFO("HAL is closed");
+ }
+
+ std::string ToString() const override {
+ return std::string("HciHalHost");
+ }
+
+ private:
+ // Held when APIs are called, NOT to be held during callbacks
+ std::mutex api_mutex_;
+ HciHalCallbacks* incoming_packet_callback_ = nullptr;
+ std::mutex incoming_packet_callback_mutex_;
+ 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_ = nullptr;
+
+ void write_to_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_,
+ common::Bind(&HciHalHost::incoming_packet_received, common::Unretained(this)),
+ common::Bind(&HciHalHost::send_packet_ready, common::Unretained(this)));
+ }
+ }
+
+ void send_packet_ready() {
+ std::lock_guard<std::mutex> lock(this->api_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_,
+ common::Bind(&HciHalHost::incoming_packet_received, common::Unretained(this)),
+ common::Closure());
+ }
+ }
+
+ void incoming_packet_received() {
+ {
+ std::lock_guard<std::mutex> incoming_packet_callback_lock(incoming_packet_callback_mutex_);
+ if (incoming_packet_callback_ == nullptr) {
+ LOG_INFO("Dropping a packet");
+ return;
+ }
+ }
+ 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. EOF received");
+ 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);
+ {
+ std::lock_guard<std::mutex> incoming_packet_callback_lock(incoming_packet_callback_mutex_);
+ if (incoming_packet_callback_ == nullptr) {
+ LOG_INFO("Dropping an event after processing");
+ return;
+ }
+ 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] << 8) + 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);
+ {
+ std::lock_guard<std::mutex> incoming_packet_callback_lock(incoming_packet_callback_mutex_);
+ if (incoming_packet_callback_ == nullptr) {
+ LOG_INFO("Dropping an ACL packet after processing");
+ return;
+ }
+ 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);
+ {
+ std::lock_guard<std::mutex> incoming_packet_callback_lock(incoming_packet_callback_mutex_);
+ if (incoming_packet_callback_ == nullptr) {
+ LOG_INFO("Dropping a SCO packet after processing");
+ return;
+ }
+ incoming_packet_callback_->scoDataReceived(receivedHciPacket);
+ }
+ }
+
+ if (buf[0] == kH4Iso) {
+ RUN_NO_INTR(received_size = recv(sock_fd_, buf + kH4HeaderSize, kHciIsoHeaderSize, 0));
+ ASSERT_LOG(received_size != -1, "Can't receive from socket: %s", strerror(errno));
+ ASSERT_LOG(received_size == kHciIsoHeaderSize, "malformed ISO header received");
+
+ uint16_t hci_iso_data_total_length = ((buf[4] & 0x3f) << 8) + buf[3];
+ int payload_size;
+ RUN_NO_INTR(payload_size = recv(sock_fd_, buf + kH4HeaderSize + kHciIsoHeaderSize, hci_iso_data_total_length, 0));
+ ASSERT_LOG(payload_size != -1, "Can't receive from socket: %s", strerror(errno));
+ ASSERT_LOG(payload_size == hci_iso_data_total_length, "malformed ISO packet received: size mismatch");
+
+ HciPacket receivedHciPacket;
+ receivedHciPacket.assign(buf + kH4HeaderSize, buf + kH4HeaderSize + kHciIsoHeaderSize + payload_size);
+ btsnoop_logger_->Capture(receivedHciPacket, SnoopLogger::Direction::INCOMING, SnoopLogger::PacketType::ISO);
+ {
+ std::lock_guard<std::mutex> incoming_packet_callback_lock(incoming_packet_callback_mutex_);
+ if (incoming_packet_callback_ == nullptr) {
+ LOG_INFO("Dropping a ISO packet after processing");
+ return;
+ }
+ incoming_packet_callback_->isoDataReceived(receivedHciPacket);
+ }
+ }
+ memset(buf, 0, kBufSize);
+ }
+};
+
+const ModuleFactory HciHal::Factory = ModuleFactory([]() { return new HciHalHost(); });
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/gd/hal/snoop_logger.h b/gd/hal/snoop_logger.h
index b83484a..a332e3d 100644
--- a/gd/hal/snoop_logger.h
+++ b/gd/hal/snoop_logger.h
@@ -87,6 +87,9 @@
void Start() override;
void Stop() override;
DumpsysDataFinisher GetDumpsysData(flatbuffers::FlatBufferBuilder* builder) const override;
+ std::string ToString() const override {
+ return std::string("SnoopLogger");
+ }
// Visible for testing
SnoopLogger(
diff --git a/gd/hal/snoop_logger_test.cc b/gd/hal/snoop_logger_test.cc
index fbb1fba..dcfe92d 100644
--- a/gd/hal/snoop_logger_test.cc
+++ b/gd/hal/snoop_logger_test.cc
@@ -61,6 +61,10 @@
size_t max_packets_per_file,
const std::string& btsnoop_mode)
: SnoopLogger(std::move(snoop_log_path), std::move(snooz_log_path), max_packets_per_file, btsnoop_mode) {}
+
+ std::string ToString() const override {
+ return std::string("TestSnoopLoggerModule");
+ }
};
class SnoopLoggerModuleTest : public Test {
@@ -295,4 +299,4 @@
sizeof(SnoopLogger::FileHeaderType) + (sizeof(SnoopLogger::PacketHeaderType) + kInformationRequest.size()) * 10);
}
-} // namespace testing
\ No newline at end of file
+} // namespace testing
diff --git a/gd/hci/Android.bp b/gd/hci/Android.bp
index 0bf48a47..d25a589 100644
--- a/gd/hci/Android.bp
+++ b/gd/hci/Android.bp
@@ -20,30 +20,38 @@
"class_of_device.cc",
"controller.cc",
"hci_layer.cc",
+ "hci_metrics_logging.cc",
"le_address_manager.cc",
"le_advertising_manager.cc",
"le_scanning_manager.cc",
"link_key.cc",
"uuid.cc",
+ "vendor_specific_event_manager.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothHciUnitTestSources",
+ srcs: [
+ "acl_builder_test.cc",
+ "address_unittest.cc",
+ "address_with_type_test.cc",
+ "class_of_device_unittest.cc",
+ "hci_packets_test.cc",
+ "uuid_unittest.cc",
],
}
filegroup {
name: "BluetoothHciTestSources",
srcs: [
- "acl_builder_test.cc",
"acl_manager/round_robin_scheduler_test.cc",
"acl_manager_test.cc",
- "address_unittest.cc",
- "address_with_type_test.cc",
- "class_of_device_unittest.cc",
"controller_test.cc",
"hci_layer_test.cc",
- "hci_packets_test.cc",
"le_address_manager_test.cc",
"le_advertising_manager_test.cc",
"le_scanning_manager_test.cc",
- "uuid_unittest.cc",
],
}
diff --git a/gd/hci/BUILD.gn b/gd/hci/BUILD.gn
index c9d10f8..c424bbf 100644
--- a/gd/hci/BUILD.gn
+++ b/gd/hci/BUILD.gn
@@ -25,16 +25,21 @@
"class_of_device.cc",
"controller.cc",
"hci_layer.cc",
+ "hci_metrics_logging.cc",
"le_address_manager.cc",
"le_advertising_manager.cc",
"le_scanning_manager.cc",
"link_key.cc",
"uuid.cc",
+ "vendor_specific_event_manager.cc",
]
include_dirs = [ "//bt/gd" ]
- deps = [ "//bt/gd:gd_default_deps" ]
+ deps = [
+ "//bt:libbt-platform-protos-lite",
+ "//bt/gd:gd_default_deps",
+ ]
configs += [ "//bt:target_defaults" ]
}
diff --git a/gd/hci/acl_manager.cc b/gd/hci/acl_manager.cc
index 05d0a1b..9017c3a 100644
--- a/gd/hci/acl_manager.cc
+++ b/gd/hci/acl_manager.cc
@@ -159,8 +159,8 @@
CallOn(pimpl_->classic_impl_, &classic_impl::create_connection, address);
}
-void AclManager::CreateLeConnection(AddressWithType address_with_type) {
- CallOn(pimpl_->le_impl_, &le_impl::create_le_connection, address_with_type, true);
+void AclManager::CreateLeConnection(AddressWithType address_with_type, bool is_direct) {
+ CallOn(pimpl_->le_impl_, &le_impl::create_le_connection, address_with_type, true, is_direct);
}
void AclManager::SetLeSuggestedDefaultDataParameters(uint16_t octets, uint16_t time) {
diff --git a/gd/hci/acl_manager.h b/gd/hci/acl_manager.h
index ec21671..48dac95 100644
--- a/gd/hci/acl_manager.h
+++ b/gd/hci/acl_manager.h
@@ -76,7 +76,7 @@
virtual void CreateConnection(Address address);
// Generates OnLeConnectSuccess if connected, or OnLeConnectFail otherwise
- virtual void CreateLeConnection(AddressWithType address_with_type);
+ virtual void CreateLeConnection(AddressWithType address_with_type, bool is_direct);
// Ask the controller for specific data parameters
virtual void SetLeSuggestedDefaultDataParameters(uint16_t octets, uint16_t time);
diff --git a/gd/hci/acl_manager/classic_acl_connection.cc b/gd/hci/acl_manager/classic_acl_connection.cc
index 52b24ba..26326e7 100644
--- a/gd/hci/acl_manager/classic_acl_connection.cc
+++ b/gd/hci/acl_manager/classic_acl_connection.cc
@@ -15,8 +15,11 @@
*/
#include "hci/acl_manager/classic_acl_connection.h"
-
#include "hci/acl_manager/event_checkers.h"
+#include "hci/address.h"
+#include "os/metrics.h"
+
+using bluetooth::hci::Address;
namespace bluetooth {
namespace hci {
@@ -24,8 +27,9 @@
class AclConnectionTracker : public ConnectionManagementCallbacks {
public:
- AclConnectionTracker(AclConnectionInterface* acl_connection_interface)
- : acl_connection_interface_(acl_connection_interface) {}
+ AclConnectionTracker(
+ AclConnectionInterface* acl_connection_interface, const Address& address, uint16_t connection_handle)
+ : acl_connection_interface_(acl_connection_interface), address_(address), connection_handle_(connection_handle) {}
~AclConnectionTracker() {
// If callbacks were registered, they should have been delivered.
ASSERT(client_callbacks_ == nullptr || queued_callbacks_.empty());
@@ -104,13 +108,17 @@
SAVE_OR_CALL(OnReadAutomaticFlushTimeoutComplete, flush_timeout)
}
void OnReadTransmitPowerLevelComplete(uint8_t transmit_power_level) override {
+ bluetooth::os::LogMetricReadTxPowerLevelResult(
+ address_, connection_handle_, static_cast<uint8_t>(ErrorCode::SUCCESS), transmit_power_level);
SAVE_OR_CALL(OnReadTransmitPowerLevelComplete, transmit_power_level)
}
void OnReadLinkSupervisionTimeoutComplete(uint16_t link_supervision_timeout) override {
SAVE_OR_CALL(OnReadLinkSupervisionTimeoutComplete, link_supervision_timeout)
}
void OnReadFailedContactCounterComplete(uint16_t failed_contact_counter) override {
- SAVE_OR_CALL(OnReadFailedContactCounterComplete, failed_contact_counter)
+ bluetooth::os::LogMetricReadFailedContactCounterResult(
+ address_, connection_handle_, static_cast<uint8_t>(ErrorCode::SUCCESS), failed_contact_counter);
+ SAVE_OR_CALL(OnReadFailedContactCounterComplete, failed_contact_counter);
}
void OnReadLinkQualityComplete(uint8_t link_quality) override {
SAVE_OR_CALL(OnReadLinkQualityComplete, link_quality)
@@ -119,7 +127,9 @@
SAVE_OR_CALL(OnReadAfhChannelMapComplete, afh_mode, afh_channel_map)
}
void OnReadRssiComplete(uint8_t rssi) override {
- SAVE_OR_CALL(OnReadRssiComplete, rssi)
+ bluetooth::os::LogMetricReadRssiResult(
+ address_, connection_handle_, static_cast<uint8_t>(ErrorCode::SUCCESS), rssi);
+ SAVE_OR_CALL(OnReadRssiComplete, rssi);
}
void OnReadClockComplete(uint32_t clock, uint16_t accuracy) override {
SAVE_OR_CALL(OnReadClockComplete, clock, accuracy)
@@ -132,8 +142,13 @@
}
void OnReadRemoteVersionInformationComplete(
hci::ErrorCode hci_status, uint8_t lmp_version, uint16_t manufacturer_name, uint16_t sub_version) override {
+ bluetooth::os::LogMetricRemoteVersionInfo(
+ connection_handle_, static_cast<uint8_t>(hci_status), lmp_version, manufacturer_name, sub_version);
SAVE_OR_CALL(OnReadRemoteVersionInformationComplete, hci_status, lmp_version, manufacturer_name, sub_version);
}
+ void OnReadRemoteSupportedFeaturesComplete(uint64_t features) override {
+ SAVE_OR_CALL(OnReadRemoteSupportedFeaturesComplete, features);
+ }
void OnReadRemoteExtendedFeaturesComplete(uint8_t page_number, uint8_t max_page_number, uint64_t features) override {
SAVE_OR_CALL(OnReadRemoteExtendedFeaturesComplete, page_number, max_page_number, features);
}
@@ -301,11 +316,17 @@
os::Handler* client_handler_ = nullptr;
ConnectionManagementCallbacks* client_callbacks_ = nullptr;
std::list<common::OnceClosure> queued_callbacks_;
+ Address address_;
+ uint16_t connection_handle_;
};
struct ClassicAclConnection::impl {
- impl(AclConnectionInterface* acl_connection_interface, std::shared_ptr<Queue> queue)
- : tracker(acl_connection_interface), queue_(std::move(queue)) {}
+ impl(
+ AclConnectionInterface* acl_connection_interface,
+ std::shared_ptr<Queue> queue,
+ const Address& address,
+ uint16_t connection_handle)
+ : tracker(acl_connection_interface, address, connection_handle), queue_(std::move(queue)) {}
ConnectionManagementCallbacks* GetEventCallbacks() {
ASSERT(!callbacks_given_);
callbacks_given_ = true;
@@ -324,7 +345,7 @@
AclConnectionInterface* acl_connection_interface, uint16_t handle,
Address address)
: AclConnection(queue->GetUpEnd(), handle), acl_connection_interface_(acl_connection_interface), address_(address) {
- pimpl_ = new ClassicAclConnection::impl(acl_connection_interface, std::move(queue));
+ pimpl_ = new ClassicAclConnection::impl(acl_connection_interface, std::move(queue), address, handle);
}
ClassicAclConnection::~ClassicAclConnection() {
diff --git a/gd/hci/acl_manager/classic_acl_connection.h b/gd/hci/acl_manager/classic_acl_connection.h
index 4e7b733..b2526cb 100644
--- a/gd/hci/acl_manager/classic_acl_connection.h
+++ b/gd/hci/acl_manager/classic_acl_connection.h
@@ -76,7 +76,11 @@
private:
AclConnectionInterface* acl_connection_interface_;
+
+ protected:
Address address_;
+
+ private:
struct impl;
struct impl* pimpl_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(ClassicAclConnection);
diff --git a/gd/hci/acl_manager/classic_impl.h b/gd/hci/acl_manager/classic_impl.h
index 33e3185..19d1380 100644
--- a/gd/hci/acl_manager/classic_impl.h
+++ b/gd/hci/acl_manager/classic_impl.h
@@ -180,6 +180,10 @@
client_handler_->CallOn(
client_callbacks_, &ConnectionCallbacks::HACK_OnEscoConnectRequest, address, request.GetClassOfDevice());
return;
+
+ case ConnectionRequestLinkType::UNKNOWN:
+ LOG_ERROR("Request has unknown ConnectionRequestLinkType.");
+ return;
}
incoming_connecting_address_ = address;
@@ -273,7 +277,16 @@
connection->locally_initiated_ = locally_initiated;
auto& connection_proxy = conn_pair.first->second;
connection_proxy.connection_management_callbacks_ = connection->GetEventCallbacks();
- connection_proxy.connection_management_callbacks_->OnRoleChange(hci::ErrorCode::SUCCESS, current_role);
+ if (delayed_role_change_ != nullptr) {
+ if (delayed_role_change_->GetBdAddr() == address) {
+ LOG_INFO("Sending delayed role change for %s", delayed_role_change_->GetBdAddr().ToString().c_str());
+ connection_proxy.connection_management_callbacks_->OnRoleChange(
+ delayed_role_change_->GetStatus(), delayed_role_change_->GetNewRole());
+ }
+ delayed_role_change_ = nullptr;
+ } else {
+ connection_proxy.connection_management_callbacks_->OnRoleChange(hci::ErrorCode::SUCCESS, current_role);
+ }
client_handler_->Post(common::BindOnce(&ConnectionCallbacks::OnConnectSuccess,
common::Unretained(client_callbacks_), std::move(connection)));
while (!pending_outgoing_connections_.empty()) {
@@ -499,14 +512,26 @@
LOG_ERROR("Received on_role_change with invalid packet");
return;
}
+ bool sent = false;
auto hci_status = role_change_view.GetStatus();
Address bd_addr = role_change_view.GetBdAddr();
Role new_role = role_change_view.GetNewRole();
for (auto& connection_pair : acl_connections_) {
if (connection_pair.second.address_with_type_.GetAddress() == bd_addr) {
connection_pair.second.connection_management_callbacks_->OnRoleChange(hci_status, new_role);
+ sent = true;
}
}
+ if (!sent) {
+ if (delayed_role_change_ != nullptr) {
+ LOG_WARN("Second delayed role change (@%s dropped)", delayed_role_change_->GetBdAddr().ToString().c_str());
+ }
+ LOG_INFO(
+ "Role change for %s with no matching connection (new role: %s)",
+ role_change_view.GetBdAddr().ToString().c_str(),
+ RoleText(role_change_view.GetNewRole()).c_str());
+ delayed_role_change_ = std::make_unique<RoleChangeView>(role_change_view);
+ }
}
void on_flow_specification_complete(EventView packet) {
@@ -574,7 +599,7 @@
ASSERT(!crash_on_unknown_handle_);
return;
}
- callbacks->OnReadRemoteExtendedFeaturesComplete(0, 1, view.GetLmpFeatures());
+ callbacks->OnReadRemoteSupportedFeaturesComplete(view.GetLmpFeatures());
}
void on_read_remote_extended_features_complete(EventView packet) {
@@ -665,6 +690,7 @@
Address incoming_connecting_address_{Address::kEmpty};
common::Callback<bool(Address, ClassOfDevice)> should_accept_connection_;
std::queue<std::pair<Address, std::unique_ptr<CreateConnectionBuilder>>> pending_outgoing_connections_;
+ std::unique_ptr<RoleChangeView> delayed_role_change_ = nullptr;
std::unique_ptr<security::SecurityManager> security_manager_;
bool crash_on_unknown_handle_ = false;
diff --git a/gd/hci/acl_manager/connection_management_callbacks.h b/gd/hci/acl_manager/connection_management_callbacks.h
index 4308f39..1b2eea2 100644
--- a/gd/hci/acl_manager/connection_management_callbacks.h
+++ b/gd/hci/acl_manager/connection_management_callbacks.h
@@ -87,6 +87,8 @@
// Invoked when controller sends Read Remote Version Information Complete
virtual void OnReadRemoteVersionInformationComplete(
hci::ErrorCode hci_status, uint8_t lmp_version, uint16_t manufacturer_name, uint16_t sub_version) = 0;
+ // Invoked when controller sends Read Remote Supported Features Complete
+ virtual void OnReadRemoteSupportedFeaturesComplete(uint64_t features) = 0;
// Invoked when controller sends Read Remote Extended Features Complete
virtual void OnReadRemoteExtendedFeaturesComplete(
uint8_t page_number, uint8_t max_page_number, uint64_t features) = 0;
diff --git a/gd/hci/acl_manager/le_acl_connection.cc b/gd/hci/acl_manager/le_acl_connection.cc
index bade58e..9333204 100644
--- a/gd/hci/acl_manager/le_acl_connection.cc
+++ b/gd/hci/acl_manager/le_acl_connection.cc
@@ -16,6 +16,7 @@
#include "hci/acl_manager/le_acl_connection.h"
#include "hci/acl_manager/le_connection_management_callbacks.h"
+#include "os/metrics.h"
namespace bluetooth {
namespace hci {
@@ -23,8 +24,8 @@
class LeAclConnectionTracker : public LeConnectionManagementCallbacks {
public:
- LeAclConnectionTracker(LeAclConnectionInterface* le_acl_connection_interface)
- : le_acl_connection_interface_(le_acl_connection_interface) {}
+ LeAclConnectionTracker(LeAclConnectionInterface* le_acl_connection_interface, uint16_t connection_handle)
+ : le_acl_connection_interface_(le_acl_connection_interface), connection_handle_(connection_handle) {}
~LeAclConnectionTracker() {
ASSERT(queued_callbacks_.empty());
}
@@ -58,6 +59,8 @@
void OnReadRemoteVersionInformationComplete(
hci::ErrorCode hci_status, uint8_t lmp_version, uint16_t manufacturer_name, uint16_t sub_version) {
+ bluetooth::os::LogMetricRemoteVersionInfo(
+ connection_handle_, static_cast<uint8_t>(hci_status), lmp_version, manufacturer_name, sub_version);
SAVE_OR_CALL(OnReadRemoteVersionInformationComplete, hci_status, lmp_version, manufacturer_name, sub_version);
}
void OnPhyUpdate(hci::ErrorCode hci_status, uint8_t tx_phy, uint8_t rx_phy) override {
@@ -76,11 +79,12 @@
os::Handler* client_handler_ = nullptr;
LeConnectionManagementCallbacks* client_callbacks_ = nullptr;
std::list<common::OnceClosure> queued_callbacks_;
+ uint16_t connection_handle_;
};
struct LeAclConnection::impl {
- impl(LeAclConnectionInterface* le_acl_connection_interface, std::shared_ptr<Queue> queue)
- : queue_(std::move(queue)), tracker(le_acl_connection_interface) {}
+ impl(LeAclConnectionInterface* le_acl_connection_interface, std::shared_ptr<Queue> queue, uint16_t connection_handle)
+ : queue_(std::move(queue)), tracker(le_acl_connection_interface, connection_handle) {}
LeConnectionManagementCallbacks* GetEventCallbacks() {
ASSERT(!callbacks_given_);
callbacks_given_ = true;
@@ -107,7 +111,7 @@
local_address_(local_address),
remote_address_(remote_address),
role_(role) {
- pimpl_ = new LeAclConnection::impl(le_acl_connection_interface, std::move(queue));
+ pimpl_ = new LeAclConnection::impl(le_acl_connection_interface, std::move(queue), handle);
}
LeAclConnection::~LeAclConnection() {
diff --git a/gd/hci/acl_manager/le_impl.h b/gd/hci/acl_manager/le_impl.h
index d5eaabd..96bd7f7 100644
--- a/gd/hci/acl_manager/le_impl.h
+++ b/gd/hci/acl_manager/le_impl.h
@@ -32,6 +32,18 @@
using common::BindOnce;
+constexpr uint16_t kScanIntervalFast = 0x0060; /* 30 ~ 60 ms (use 60) = 96 *0.625 */
+constexpr uint16_t kScanWindowFast = 0x0030; /* 30 ms = 48 *0.625 */
+constexpr uint16_t kScanWindow2mFast = 0x0018; /* 15 ms = 24 *0.625 */
+constexpr uint16_t kScanWindowCodedFast = 0x0018; /* 15 ms = 24 *0.625 */
+constexpr uint16_t kScanIntervalSlow = 0x0800; /* 1.28 s = 2048 *0.625 */
+constexpr uint16_t kScanWindowSlow = 0x0030; /* 30 ms = 48 *0.625 */
+constexpr std::chrono::milliseconds kCreateConnectionTimeoutMs = std::chrono::milliseconds(30 * 1000);
+constexpr uint8_t PHY_LE_NO_PACKET = 0x00;
+constexpr uint8_t PHY_LE_1M = 0x01;
+constexpr uint8_t PHY_LE_2M = 0x02;
+constexpr uint8_t PHY_LE_CODED = 0x04;
+
struct le_acl_connection {
le_acl_connection(AddressWithType remote_address, AclConnection::QueueDownEnd* queue_down_end, os::Handler* handler)
: assembler_(remote_address, queue_down_end, handler), remote_address_(remote_address) {}
@@ -129,6 +141,10 @@
} else {
connecting_le_.erase(connecting_addr_with_type);
}
+ if (create_connection_timeout_alarms_.find(address_with_type) != create_connection_timeout_alarms_.end()) {
+ create_connection_timeout_alarms_.at(address_with_type).Cancel();
+ create_connection_timeout_alarms_.erase(address_with_type);
+ }
}
void on_le_connection_complete(LeMetaEventView packet) {
@@ -141,8 +157,7 @@
AddressWithType remote_address(address, peer_address_type);
AddressWithType local_address = le_address_manager_->GetCurrentAddress();
on_common_le_connection_complete(remote_address);
- if (status == ErrorCode::UNKNOWN_CONNECTION &&
- canceled_connections_.find(remote_address) != canceled_connections_.end()) {
+ if (status == ErrorCode::UNKNOWN_CONNECTION && pause_connection) {
// connection canceled by LeAddressManager.OnPause(), will auto reconnect by LeAddressManager.OnResume()
return;
} else {
@@ -200,8 +215,7 @@
remote_address = AddressWithType(peer_resolvable_address, AddressType::RANDOM_DEVICE_ADDRESS);
}
on_common_le_connection_complete(remote_address);
- if (status == ErrorCode::UNKNOWN_CONNECTION &&
- canceled_connections_.find(remote_address) != canceled_connections_.end()) {
+ if (status == ErrorCode::UNKNOWN_CONNECTION && pause_connection) {
// connection canceled by LeAddressManager.OnPause(), will auto reconnect by LeAddressManager.OnResume()
return;
} else {
@@ -295,8 +309,7 @@
hci::ErrorCode hci_status, uint16_t handle, uint8_t version, uint16_t manufacturer_name, uint16_t sub_version) {
auto callbacks = get_callbacks(handle);
if (callbacks == nullptr) {
- LOG_WARN("Can't find connection 0x%hx", handle);
- ASSERT(!crash_on_unknown_handle_);
+ LOG_INFO("No le connection registered for 0x%hx", handle);
return;
}
callbacks->OnReadRemoteVersionInformationComplete(hci_status, version, manufacturer_name, sub_version);
@@ -399,11 +412,23 @@
}
}
- void create_le_connection(AddressWithType address_with_type, bool add_to_connect_list) {
+ void create_le_connection(AddressWithType address_with_type, bool add_to_connect_list, bool is_direct) {
// TODO: Configure default LE connection parameters?
-
if (add_to_connect_list) {
add_device_to_connect_list(address_with_type);
+ if (is_direct) {
+ direct_connections_.insert(address_with_type);
+ if (create_connection_timeout_alarms_.find(address_with_type) == create_connection_timeout_alarms_.end()) {
+ create_connection_timeout_alarms_.emplace(
+ std::piecewise_construct,
+ std::forward_as_tuple(address_with_type.GetAddress(), address_with_type.GetAddressType()),
+ std::forward_as_tuple(handler_));
+ create_connection_timeout_alarms_.at(address_with_type)
+ .Schedule(
+ common::BindOnce(&le_impl::on_create_connection_timeout, common::Unretained(this), address_with_type),
+ kCreateConnectionTimeoutMs);
+ }
+ }
}
if (!address_manager_registered) {
@@ -426,8 +451,17 @@
return;
}
- uint16_t le_scan_interval = 0x0060;
- uint16_t le_scan_window = 0x0030;
+ uint16_t le_scan_interval = kScanIntervalSlow;
+ uint16_t le_scan_window = kScanWindowSlow;
+ uint16_t le_scan_window_2m = kScanWindowSlow;
+ uint16_t le_scan_window_coded = kScanWindowSlow;
+ // If there is any direct connection in the connection list, use the fast parameter
+ if (!direct_connections_.empty()) {
+ le_scan_interval = kScanIntervalFast;
+ le_scan_window = kScanWindowFast;
+ le_scan_window_2m = kScanWindow2mFast;
+ le_scan_window_coded = kScanWindowCodedFast;
+ }
InitiatorFilterPolicy initiator_filter_policy = InitiatorFilterPolicy::USE_CONNECT_LIST;
OwnAddressType own_address_type =
static_cast<OwnAddressType>(le_address_manager_->GetCurrentAddress().GetAddressType());
@@ -444,20 +478,54 @@
}
if (controller_->IsSupported(OpCode::LE_EXTENDED_CREATE_CONNECTION)) {
- LeCreateConnPhyScanParameters tmp;
- tmp.scan_interval_ = le_scan_interval;
- tmp.scan_window_ = le_scan_window;
- tmp.conn_interval_min_ = conn_interval_min;
- tmp.conn_interval_max_ = conn_interval_max;
- tmp.conn_latency_ = conn_latency;
- tmp.supervision_timeout_ = supervision_timeout;
- tmp.min_ce_length_ = 0x00;
- tmp.max_ce_length_ = 0x00;
+ uint8_t initiating_phys = PHY_LE_1M;
+ std::vector<LeCreateConnPhyScanParameters> parameters = {};
+ LeCreateConnPhyScanParameters scan_parameters;
+ scan_parameters.scan_interval_ = le_scan_interval;
+ scan_parameters.scan_window_ = le_scan_window;
+ scan_parameters.conn_interval_min_ = conn_interval_min;
+ scan_parameters.conn_interval_max_ = conn_interval_max;
+ scan_parameters.conn_latency_ = conn_latency;
+ scan_parameters.supervision_timeout_ = supervision_timeout;
+ scan_parameters.min_ce_length_ = 0x00;
+ scan_parameters.max_ce_length_ = 0x00;
+ parameters.push_back(scan_parameters);
+
+ if (controller_->SupportsBle2mPhy()) {
+ LeCreateConnPhyScanParameters scan_parameters_2m;
+ scan_parameters_2m.scan_interval_ = le_scan_interval;
+ scan_parameters_2m.scan_window_ = le_scan_window_2m;
+ scan_parameters_2m.conn_interval_min_ = conn_interval_min;
+ scan_parameters_2m.conn_interval_max_ = conn_interval_max;
+ scan_parameters_2m.conn_latency_ = conn_latency;
+ scan_parameters_2m.supervision_timeout_ = supervision_timeout;
+ scan_parameters_2m.min_ce_length_ = 0x00;
+ scan_parameters_2m.max_ce_length_ = 0x00;
+ parameters.push_back(scan_parameters_2m);
+ initiating_phys |= PHY_LE_2M;
+ }
+ if (controller_->SupportsBleCodedPhy()) {
+ LeCreateConnPhyScanParameters scan_parameters_coded;
+ scan_parameters_coded.scan_interval_ = le_scan_interval;
+ scan_parameters_coded.scan_window_ = le_scan_window_coded;
+ scan_parameters_coded.conn_interval_min_ = conn_interval_min;
+ scan_parameters_coded.conn_interval_max_ = conn_interval_max;
+ scan_parameters_coded.conn_latency_ = conn_latency;
+ scan_parameters_coded.supervision_timeout_ = supervision_timeout;
+ scan_parameters_coded.min_ce_length_ = 0x00;
+ scan_parameters_coded.max_ce_length_ = 0x00;
+ parameters.push_back(scan_parameters_coded);
+ initiating_phys |= PHY_LE_CODED;
+ }
le_acl_connection_interface_->EnqueueCommand(
- LeExtendedCreateConnectionBuilder::Create(initiator_filter_policy, own_address_type,
- address_with_type.GetAddressType(), address_with_type.GetAddress(),
- 0x01 /* 1M PHY ONLY */, {tmp}),
+ LeExtendedCreateConnectionBuilder::Create(
+ initiator_filter_policy,
+ own_address_type,
+ address_with_type.GetAddressType(),
+ address_with_type.GetAddress(),
+ initiating_phys,
+ parameters),
handler_->BindOnce([](CommandStatusView status) {
ASSERT(status.IsValid());
ASSERT(status.GetCommandOpCode() == OpCode::LE_EXTENDED_CREATE_CONNECTION);
@@ -475,6 +543,15 @@
}
}
+ void on_create_connection_timeout(AddressWithType address_with_type) {
+ LOG_INFO("on_create_connection_timeout, address: %s", address_with_type.ToString().c_str());
+ if (create_connection_timeout_alarms_.find(address_with_type) != create_connection_timeout_alarms_.end()) {
+ create_connection_timeout_alarms_.at(address_with_type).Cancel();
+ create_connection_timeout_alarms_.erase(address_with_type);
+ cancel_connect(address_with_type);
+ }
+ }
+
void cancel_connect(AddressWithType address_with_type) {
// the connection will be canceled by LeAddressManager.OnPause()
remove_device_from_connect_list(address_with_type);
@@ -488,6 +565,7 @@
void remove_device_from_connect_list(AddressWithType address_with_type) {
AddressType address_type = address_with_type.GetAddressType();
+ direct_connections_.erase(address_with_type);
if (!address_manager_registered) {
le_address_manager_->Register(this);
address_manager_registered = true;
@@ -595,6 +673,7 @@
le_acl_connection_interface_->EnqueueCommand(
LeCreateConnectionCancelBuilder::Create(),
handler_->BindOnce(&le_impl::on_create_connection_cancel_complete, common::Unretained(this)));
+ le_address_manager_->AckPause(this);
}
void on_create_connection_cancel_complete(CommandCompleteView view) {
@@ -605,7 +684,6 @@
std::string error_code = ErrorCodeText(status);
LOG_WARN("Received on_create_connection_cancel_complete with error code %s", error_code.c_str());
}
- le_address_manager_->AckPause(this);
}
void check_for_unregister() {
@@ -621,7 +699,7 @@
void OnResume() override {
pause_connection = false;
if (!canceled_connections_.empty()) {
- create_le_connection(*canceled_connections_.begin(), false);
+ create_le_connection(*canceled_connections_.begin(), false, false);
}
canceled_connections_.clear();
le_address_manager_->AckResume(this);
@@ -660,10 +738,12 @@
std::map<uint16_t, le_acl_connection> le_acl_connections_;
std::set<AddressWithType> connecting_le_;
std::set<AddressWithType> canceled_connections_;
+ std::set<AddressWithType> direct_connections_;
bool address_manager_registered = false;
bool ready_to_unregister = false;
bool pause_connection = false;
bool crash_on_unknown_handle_ = false;
+ std::map<AddressWithType, os::Alarm> create_connection_timeout_alarms_;
};
} // namespace acl_manager
diff --git a/gd/hci/acl_manager/round_robin_scheduler.cc b/gd/hci/acl_manager/round_robin_scheduler.cc
index 4790708..9da0a60 100644
--- a/gd/hci/acl_manager/round_robin_scheduler.cc
+++ b/gd/hci/acl_manager/round_robin_scheduler.cc
@@ -138,8 +138,10 @@
ConnectionType connection_type = acl_queue_handler->second.connection_type_;
size_t mtu = connection_type == ConnectionType::CLASSIC ? hci_mtu_ : le_hci_mtu_;
- // TODO(b/178752129): Make A2DP and Hearing Aid audio packets flushable
- PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::FIRST_NON_AUTOMATICALLY_FLUSHABLE;
+ PacketBoundaryFlag packet_boundary_flag = (packet->IsFlushable())
+ ? PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE
+ : PacketBoundaryFlag::FIRST_NON_AUTOMATICALLY_FLUSHABLE;
+
int acl_priority = acl_queue_handler->second.high_priority_ ? 1 : 0;
if (packet->size() <= mtu) {
fragments_to_send_.push(
diff --git a/gd/hci/acl_manager_mock.h b/gd/hci/acl_manager_mock.h
index aad072c..7349e2f 100644
--- a/gd/hci/acl_manager_mock.h
+++ b/gd/hci/acl_manager_mock.h
@@ -72,7 +72,7 @@
MOCK_METHOD(void, RegisterCallbacks, (ConnectionCallbacks * callbacks, os::Handler* handler), (override));
MOCK_METHOD(void, RegisterLeCallbacks, (LeConnectionCallbacks * callbacks, os::Handler* handler), (override));
MOCK_METHOD(void, CreateConnection, (Address address), (override));
- MOCK_METHOD(void, CreateLeConnection, (AddressWithType address_with_type), (override));
+ MOCK_METHOD(void, CreateLeConnection, (AddressWithType address_with_type, bool is_direct), (override));
MOCK_METHOD(void, CancelConnect, (Address address), (override));
MOCK_METHOD(
void,
diff --git a/gd/hci/acl_manager_test.cc b/gd/hci/acl_manager_test.cc
index fea1849..8056dd1 100644
--- a/gd/hci/acl_manager_test.cc
+++ b/gd/hci/acl_manager_test.cc
@@ -44,6 +44,10 @@
using packet::RawBuilder;
constexpr std::chrono::seconds kTimeout = std::chrono::seconds(2);
+constexpr uint16_t kScanIntervalFast = 0x0060;
+constexpr uint16_t kScanWindowFast = 0x0030;
+constexpr uint16_t kScanIntervalSlow = 0x0800;
+constexpr uint16_t kScanWindowSlow = 0x0030;
const AddressWithType empty_address_with_type = hci::AddressWithType();
PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
@@ -120,7 +124,7 @@
std::unique_ptr<CommandBuilder> command,
common::ContextualOnceCallback<void(CommandStatusView)> on_status) override {
command_queue_.push(std::move(command));
- command_status_callbacks.push_front(std::move(on_status));
+ command_status_callbacks.push_back(std::move(on_status));
if (command_promise_ != nullptr) {
command_promise_->set_value();
command_promise_.reset();
@@ -131,7 +135,7 @@
std::unique_ptr<CommandBuilder> command,
common::ContextualOnceCallback<void(CommandCompleteView)> on_complete) override {
command_queue_.push(std::move(command));
- command_complete_callbacks.push_front(std::move(on_complete));
+ command_complete_callbacks.push_back(std::move(on_complete));
if (command_promise_ != nullptr) {
command_promise_->set_value();
command_promise_.reset();
@@ -520,6 +524,7 @@
MOCK_METHOD4(
OnReadRemoteVersionInformationComplete,
void(hci::ErrorCode hci_status, uint8_t lmp_version, uint16_t manufacturer_name, uint16_t sub_version));
+ MOCK_METHOD1(OnReadRemoteSupportedFeaturesComplete, void(uint64_t features));
MOCK_METHOD3(
OnReadRemoteExtendedFeaturesComplete, void(uint8_t page_number, uint8_t max_page_number, uint64_t features));
} mock_connection_management_callbacks_;
@@ -592,7 +597,7 @@
remote_with_type_ = AddressWithType(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
test_hci_layer_->SetCommandFuture();
- acl_manager_->CreateLeConnection(remote_with_type_);
+ acl_manager_->CreateLeConnection(remote_with_type_, true);
test_hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_CONNECT_LIST);
test_hci_layer_->IncomingEvent(LeAddDeviceToConnectListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
test_hci_layer_->SetCommandFuture();
@@ -681,7 +686,7 @@
TEST_F(AclManagerTest, invoke_registered_callback_le_connection_complete_fail) {
AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
test_hci_layer_->SetCommandFuture();
- acl_manager_->CreateLeConnection(remote_with_type);
+ acl_manager_->CreateLeConnection(remote_with_type, true);
test_hci_layer_->GetLastCommand(OpCode::LE_ADD_DEVICE_TO_CONNECT_LIST);
test_hci_layer_->IncomingEvent(LeAddDeviceToConnectListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
test_hci_layer_->SetCommandFuture();
@@ -723,7 +728,7 @@
TEST_F(AclManagerTest, cancel_le_connection) {
AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
test_hci_layer_->SetCommandFuture();
- acl_manager_->CreateLeConnection(remote_with_type);
+ acl_manager_->CreateLeConnection(remote_with_type, true);
test_hci_layer_->GetLastCommand(OpCode::LE_ADD_DEVICE_TO_CONNECT_LIST);
test_hci_layer_->IncomingEvent(LeAddDeviceToConnectListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
test_hci_layer_->SetCommandFuture();
@@ -758,6 +763,70 @@
test_hci_layer_->IncomingEvent(LeRemoveDeviceFromConnectListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
}
+TEST_F(AclManagerTest, create_connection_with_fast_mode) {
+ AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
+ test_hci_layer_->SetCommandFuture();
+ acl_manager_->CreateLeConnection(remote_with_type, true);
+ test_hci_layer_->GetLastCommand(OpCode::LE_ADD_DEVICE_TO_CONNECT_LIST);
+ test_hci_layer_->IncomingEvent(LeAddDeviceToConnectListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+ test_hci_layer_->SetCommandFuture();
+ auto packet = test_hci_layer_->GetLastCommand(OpCode::LE_CREATE_CONNECTION);
+ auto command_view =
+ LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create(AclCommandView::Create(packet)));
+ ASSERT_TRUE(command_view.IsValid());
+ ASSERT_EQ(command_view.GetLeScanInterval(), kScanIntervalFast);
+ ASSERT_EQ(command_view.GetLeScanWindow(), kScanWindowFast);
+ test_hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
+ auto first_connection = GetLeConnectionFuture();
+ test_hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
+ ErrorCode::SUCCESS,
+ 0x00,
+ Role::PERIPHERAL,
+ AddressType::PUBLIC_DEVICE_ADDRESS,
+ remote,
+ 0x0100,
+ 0x0010,
+ 0x0C80,
+ ClockAccuracy::PPM_30));
+ test_hci_layer_->SetCommandFuture();
+ test_hci_layer_->GetCommand(OpCode::LE_REMOVE_DEVICE_FROM_CONNECT_LIST);
+ test_hci_layer_->IncomingEvent(LeRemoveDeviceFromConnectListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+ auto first_connection_status = first_connection.wait_for(kTimeout);
+ ASSERT_EQ(first_connection_status, std::future_status::ready);
+}
+
+TEST_F(AclManagerTest, create_connection_with_slow_mode) {
+ AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
+ test_hci_layer_->SetCommandFuture();
+ acl_manager_->CreateLeConnection(remote_with_type, false);
+ test_hci_layer_->GetLastCommand(OpCode::LE_ADD_DEVICE_TO_CONNECT_LIST);
+ test_hci_layer_->IncomingEvent(LeAddDeviceToConnectListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+ test_hci_layer_->SetCommandFuture();
+ auto packet = test_hci_layer_->GetLastCommand(OpCode::LE_CREATE_CONNECTION);
+ auto command_view =
+ LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create(AclCommandView::Create(packet)));
+ ASSERT_TRUE(command_view.IsValid());
+ ASSERT_EQ(command_view.GetLeScanInterval(), kScanIntervalSlow);
+ ASSERT_EQ(command_view.GetLeScanWindow(), kScanWindowSlow);
+ test_hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
+ auto first_connection = GetLeConnectionFuture();
+ test_hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
+ ErrorCode::SUCCESS,
+ 0x00,
+ Role::PERIPHERAL,
+ AddressType::PUBLIC_DEVICE_ADDRESS,
+ remote,
+ 0x0100,
+ 0x0010,
+ 0x0C80,
+ ClockAccuracy::PPM_30));
+ test_hci_layer_->SetCommandFuture();
+ test_hci_layer_->GetCommand(OpCode::LE_REMOVE_DEVICE_FROM_CONNECT_LIST);
+ test_hci_layer_->IncomingEvent(LeRemoveDeviceFromConnectListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+ auto first_connection_status = first_connection.wait_for(kTimeout);
+ ASSERT_EQ(first_connection_status, std::future_status::ready);
+}
+
TEST_F(AclManagerWithLeConnectionTest, acl_send_data_one_le_connection) {
ASSERT_EQ(connection_->GetRemoteAddress(), remote_with_type_);
ASSERT_EQ(connection_->GetHandle(), handle_);
@@ -1276,7 +1345,7 @@
TEST_F(AclManagerWithResolvableAddressTest, create_connection_cancel_fail) {
auto remote_with_type_ = AddressWithType(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
test_hci_layer_->SetCommandFuture();
- acl_manager_->CreateLeConnection(remote_with_type_);
+ acl_manager_->CreateLeConnection(remote_with_type_, true);
// Set random address
test_hci_layer_->GetLastCommand(OpCode::LE_SET_RANDOM_ADDRESS);
@@ -1301,7 +1370,7 @@
// create another connection
test_hci_layer_->SetCommandFuture();
- acl_manager_->CreateLeConnection(remote_with_type2);
+ acl_manager_->CreateLeConnection(remote_with_type2, true);
// cancel previous connection
test_hci_layer_->GetLastCommand(OpCode::LE_CREATE_CONNECTION_CANCEL);
@@ -1382,7 +1451,7 @@
TEST_F(AclManagerLifeCycleTest, unregister_le_before_connection_complete) {
AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
test_hci_layer_->SetCommandFuture();
- acl_manager_->CreateLeConnection(remote_with_type);
+ acl_manager_->CreateLeConnection(remote_with_type, true);
test_hci_layer_->GetLastCommand(OpCode::LE_ADD_DEVICE_TO_CONNECT_LIST);
test_hci_layer_->IncomingEvent(LeAddDeviceToConnectListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
@@ -1424,7 +1493,7 @@
TEST_F(AclManagerLifeCycleTest, unregister_le_before_enhanced_connection_complete) {
AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
test_hci_layer_->SetCommandFuture();
- acl_manager_->CreateLeConnection(remote_with_type);
+ acl_manager_->CreateLeConnection(remote_with_type, true);
test_hci_layer_->GetLastCommand(OpCode::LE_ADD_DEVICE_TO_CONNECT_LIST);
test_hci_layer_->IncomingEvent(LeAddDeviceToConnectListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
diff --git a/gd/hci/cert/acl_manager_test.py b/gd/hci/cert/acl_manager_test.py
index 3e33ebb..b87aa33 100644
--- a/gd/hci/cert/acl_manager_test.py
+++ b/gd/hci/cert/acl_manager_test.py
@@ -15,86 +15,31 @@
# limitations under the License.
from cert.gd_base_test import GdBaseTestClass
-from cert.truth import assertThat
-from neighbor.facade import facade_pb2 as neighbor_facade
-from bluetooth_packets_python3 import hci_packets
-from cert.py_hci import PyHci
-from cert.py_acl_manager import PyAclManager
+from hci.cert.acl_manager_test_lib import AclManagerTestBase
-class AclManagerTest(GdBaseTestClass):
+class AclManagerTest(GdBaseTestClass, AclManagerTestBase):
def setup_class(self):
- super().setup_class(dut_module='HCI_INTERFACES', cert_module='HCI')
+ GdBaseTestClass.setup_class(self, dut_module='HCI_INTERFACES', cert_module='HCI')
# todo: move into GdBaseTestClass, based on modules inited
def setup_test(self):
- super().setup_test()
- self.cert_hci = PyHci(self.cert, acl_streaming=True)
- self.dut_acl_manager = PyAclManager(self.dut)
+ GdBaseTestClass.setup_test(self)
+ AclManagerTestBase.setup_test(self, self.dut, self.cert)
def teardown_test(self):
- self.cert_hci.close()
- super().teardown_test()
+ AclManagerTestBase.teardown_test(self)
+ GdBaseTestClass.teardown_test(self)
def test_dut_connects(self):
- self.cert_hci.enable_inquiry_and_page_scan()
- cert_address = self.cert_hci.read_own_address()
-
- self.dut_acl_manager.initiate_connection(cert_address)
- cert_acl = self.cert_hci.accept_connection()
- with self.dut_acl_manager.complete_outgoing_connection() as dut_acl:
- cert_acl.send_first(b'\x26\x00\x07\x00This is just SomeAclData from the Cert')
- dut_acl.send(b'\x29\x00\x07\x00This is just SomeMoreAclData from the DUT')
-
- assertThat(cert_acl).emits(lambda packet: b'SomeMoreAclData' in packet.payload)
- assertThat(dut_acl).emits(lambda packet: b'SomeAclData' in packet.payload)
+ AclManagerTestBase.test_dut_connects(self)
def test_cert_connects(self):
- dut_address = self.dut.hci_controller.GetMacAddressSimple()
- self.dut.neighbor.EnablePageScan(neighbor_facade.EnableMsg(enabled=True))
-
- self.dut_acl_manager.listen_for_an_incoming_connection()
- self.cert_hci.initiate_connection(dut_address)
- with self.dut_acl_manager.complete_incoming_connection() as dut_acl:
- cert_acl = self.cert_hci.complete_connection()
-
- dut_acl.send(b'\x29\x00\x07\x00This is just SomeMoreAclData from the DUT')
-
- cert_acl.send_first(b'\x26\x00\x07\x00This is just SomeAclData from the Cert')
-
- assertThat(cert_acl).emits(lambda packet: b'SomeMoreAclData' in packet.payload)
- assertThat(dut_acl).emits(lambda packet: b'SomeAclData' in packet.payload)
+ AclManagerTestBase.test_cert_connects(self)
def test_cert_connects_disconnects(self):
- dut_address = self.dut.hci_controller.GetMacAddressSimple()
- self.dut.neighbor.EnablePageScan(neighbor_facade.EnableMsg(enabled=True))
-
- self.dut_acl_manager.listen_for_an_incoming_connection()
- self.cert_hci.initiate_connection(dut_address)
- with self.dut_acl_manager.complete_incoming_connection() as dut_acl:
- cert_acl = self.cert_hci.complete_connection()
-
- dut_acl.send(b'\x29\x00\x07\x00This is just SomeMoreAclData from the DUT')
-
- cert_acl.send_first(b'\x26\x00\x07\x00This is just SomeAclData from the Cert')
-
- assertThat(cert_acl).emits(lambda packet: b'SomeMoreAclData' in packet.payload)
- assertThat(dut_acl).emits(lambda packet: b'SomeAclData' in packet.payload)
-
- dut_acl.disconnect(hci_packets.DisconnectReason.REMOTE_USER_TERMINATED_CONNECTION)
- dut_acl.wait_for_disconnection_complete()
+ AclManagerTestBase.test_cert_connects_disconnects(self)
def test_recombination_l2cap_packet(self):
- self.cert_hci.enable_inquiry_and_page_scan()
- cert_address = self.cert_hci.read_own_address()
-
- self.dut_acl_manager.initiate_connection(cert_address)
- cert_acl = self.cert_hci.accept_connection()
- with self.dut_acl_manager.complete_outgoing_connection() as dut_acl:
- cert_acl.send_first(b'\x06\x00\x07\x00Hello')
- cert_acl.send_continuing(b'!')
- cert_acl.send_first(b'\xe8\x03\x07\x00' + b'Hello' * 200)
-
- assertThat(dut_acl).emits(lambda packet: b'Hello!' in packet.payload,
- lambda packet: b'Hello' * 200 in packet.payload).inOrder()
+ AclManagerTestBase.test_recombination_l2cap_packet(self)
diff --git a/gd/hci/cert/acl_manager_test_lib.py b/gd/hci/cert/acl_manager_test_lib.py
new file mode 100644
index 0000000..dcc8f70
--- /dev/null
+++ b/gd/hci/cert/acl_manager_test_lib.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python3
+#
+# Copyright 2020 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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 cert.truth import assertThat
+from neighbor.facade import facade_pb2 as neighbor_facade
+from bluetooth_packets_python3 import hci_packets
+from cert.py_hci import PyHci
+from cert.py_acl_manager import PyAclManager
+
+
+class AclManagerTestBase():
+
+ # todo: move into GdBaseTestClass, based on modules inited
+ def setup_test(self, dut, cert):
+ self.cert_hci = PyHci(cert, acl_streaming=True)
+ self.dut_acl_manager = PyAclManager(dut)
+
+ def teardown_test(self):
+ self.cert_hci.close()
+
+ def test_dut_connects(self):
+ self.cert_hci.enable_inquiry_and_page_scan()
+ cert_address = self.cert_hci.read_own_address()
+
+ self.dut_acl_manager.initiate_connection(cert_address)
+ cert_acl = self.cert_hci.accept_connection()
+ with self.dut_acl_manager.complete_outgoing_connection() as dut_acl:
+ cert_acl.send_first(b'\x26\x00\x07\x00This is just SomeAclData from the Cert')
+ dut_acl.send(b'\x29\x00\x07\x00This is just SomeMoreAclData from the DUT')
+
+ assertThat(cert_acl).emits(lambda packet: b'SomeMoreAclData' in packet.payload)
+ assertThat(dut_acl).emits(lambda packet: b'SomeAclData' in packet.payload)
+
+ def test_cert_connects(self):
+ dut_address = self.dut.hci_controller.GetMacAddressSimple()
+ self.dut.neighbor.EnablePageScan(neighbor_facade.EnableMsg(enabled=True))
+
+ self.dut_acl_manager.listen_for_an_incoming_connection()
+ self.cert_hci.initiate_connection(dut_address)
+ with self.dut_acl_manager.complete_incoming_connection() as dut_acl:
+ cert_acl = self.cert_hci.complete_connection()
+
+ dut_acl.send(b'\x29\x00\x07\x00This is just SomeMoreAclData from the DUT')
+
+ cert_acl.send_first(b'\x26\x00\x07\x00This is just SomeAclData from the Cert')
+
+ assertThat(cert_acl).emits(lambda packet: b'SomeMoreAclData' in packet.payload)
+ assertThat(dut_acl).emits(lambda packet: b'SomeAclData' in packet.payload)
+
+ def test_cert_connects_disconnects(self):
+ dut_address = self.dut.hci_controller.GetMacAddressSimple()
+ self.dut.neighbor.EnablePageScan(neighbor_facade.EnableMsg(enabled=True))
+
+ self.dut_acl_manager.listen_for_an_incoming_connection()
+ self.cert_hci.initiate_connection(dut_address)
+ with self.dut_acl_manager.complete_incoming_connection() as dut_acl:
+ cert_acl = self.cert_hci.complete_connection()
+
+ dut_acl.send(b'\x29\x00\x07\x00This is just SomeMoreAclData from the DUT')
+
+ cert_acl.send_first(b'\x26\x00\x07\x00This is just SomeAclData from the Cert')
+
+ assertThat(cert_acl).emits(lambda packet: b'SomeMoreAclData' in packet.payload)
+ assertThat(dut_acl).emits(lambda packet: b'SomeAclData' in packet.payload)
+
+ dut_acl.disconnect(hci_packets.DisconnectReason.REMOTE_USER_TERMINATED_CONNECTION)
+ dut_acl.wait_for_disconnection_complete()
+
+ def test_recombination_l2cap_packet(self):
+ self.cert_hci.enable_inquiry_and_page_scan()
+ cert_address = self.cert_hci.read_own_address()
+
+ self.dut_acl_manager.initiate_connection(cert_address)
+ cert_acl = self.cert_hci.accept_connection()
+ with self.dut_acl_manager.complete_outgoing_connection() as dut_acl:
+ cert_acl.send_first(b'\x06\x00\x07\x00Hello')
+ cert_acl.send_continuing(b'!')
+ cert_acl.send_first(b'\xe8\x03\x07\x00' + b'Hello' * 200)
+
+ assertThat(dut_acl).emits(lambda packet: b'Hello!' in packet.payload,
+ lambda packet: b'Hello' * 200 in packet.payload).inOrder()
diff --git a/gd/hci/cert/controller_test.py b/gd/hci/cert/controller_test.py
index 20fe937..676b76d 100644
--- a/gd/hci/cert/controller_test.py
+++ b/gd/hci/cert/controller_test.py
@@ -14,32 +14,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import time
-
from cert.gd_base_test import GdBaseTestClass
-from cert.truth import assertThat
-from google.protobuf import empty_pb2 as empty_proto
-from facade import rootservice_pb2 as facade_rootservice
-from hci.facade import controller_facade_pb2 as controller_facade
+from hci.cert.controller_test_lib import ControllerTestBase
-class ControllerTest(GdBaseTestClass):
+class ControllerTest(GdBaseTestClass, ControllerTestBase):
def setup_class(self):
- super().setup_class(dut_module='HCI_INTERFACES', cert_module='HCI_INTERFACES')
+ GdBaseTestClass.setup_class(self, dut_module='HCI_INTERFACES', cert_module='HCI_INTERFACES')
def test_get_addresses(self):
- cert_address = self.cert.hci_controller.GetMacAddressSimple()
- dut_address = self.dut.hci_controller.GetMacAddressSimple()
-
- assertThat(cert_address).isNotEqualTo(dut_address)
- time.sleep(1) # This shouldn't be needed b/149120542
+ ControllerTestBase.test_get_addresses(self, self.dut, self.cert)
def test_write_local_name(self):
- self.dut.hci_controller.WriteLocalName(controller_facade.NameMsg(name=b'ImTheDUT'))
- self.cert.hci_controller.WriteLocalName(controller_facade.NameMsg(name=b'ImTheCert'))
- cert_name = self.cert.hci_controller.GetLocalNameSimple()
- dut_name = self.dut.hci_controller.GetLocalNameSimple()
-
- assertThat(dut_name).isEqualTo(b'ImTheDUT')
- assertThat(cert_name).isEqualTo(b'ImTheCert')
+ ControllerTestBase.test_write_local_name(self, self.dut, self.cert)
diff --git a/gd/hci/cert/controller_test_lib.py b/gd/hci/cert/controller_test_lib.py
new file mode 100644
index 0000000..e3116f4
--- /dev/null
+++ b/gd/hci/cert/controller_test_lib.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python3
+#
+# Copyright 2020 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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 time
+
+from cert.truth import assertThat
+from google.protobuf import empty_pb2 as empty_proto
+from facade import rootservice_pb2 as facade_rootservice
+from hci.facade import controller_facade_pb2 as controller_facade
+
+
+class ControllerTestBase():
+
+ def test_get_addresses(self, dut, cert):
+ cert_address = cert.hci_controller.GetMacAddressSimple()
+ dut_address = dut.hci_controller.GetMacAddressSimple()
+
+ assertThat(cert_address).isNotEqualTo(dut_address)
+ time.sleep(1) # This shouldn't be needed b/149120542
+
+ def test_write_local_name(self, dut, cert):
+ dut.hci_controller.WriteLocalName(controller_facade.NameMsg(name=b'ImTheDUT'))
+ cert.hci_controller.WriteLocalName(controller_facade.NameMsg(name=b'ImTheCert'))
+ cert_name = cert.hci_controller.GetLocalNameSimple()
+ dut_name = dut.hci_controller.GetLocalNameSimple()
+
+ assertThat(dut_name).isEqualTo(b'ImTheDUT')
+ assertThat(cert_name).isEqualTo(b'ImTheCert')
diff --git a/gd/hci/cert/direct_hci_test.py b/gd/hci/cert/direct_hci_test.py
index ee67e88..8e79c27 100644
--- a/gd/hci/cert/direct_hci_test.py
+++ b/gd/hci/cert/direct_hci_test.py
@@ -14,284 +14,19 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from datetime import timedelta
-import logging
-
-from cert.captures import HalCaptures, HciCaptures
from cert.gd_base_test import GdBaseTestClass
-from cert.matchers import HciMatchers
-from cert.py_hal import PyHal
-from cert.py_hci import PyHci
-from cert.truth import assertThat
-from hci.facade import hci_facade_pb2 as hci_facade
-from facade import common_pb2 as common
-from bluetooth_packets_python3.hci_packets import EventCode
-from bluetooth_packets_python3.hci_packets import LoopbackMode
-from bluetooth_packets_python3.hci_packets import WriteLoopbackModeBuilder
-from bluetooth_packets_python3.hci_packets import ReadLocalNameBuilder
-from bluetooth_packets_python3.hci_packets import WriteScanEnableBuilder
-from bluetooth_packets_python3.hci_packets import ScanEnable
-from bluetooth_packets_python3.hci_packets import InquiryBuilder
-from bluetooth_packets_python3.hci_packets import SubeventCode
-from bluetooth_packets_python3.hci_packets import LeSetRandomAddressBuilder
-from bluetooth_packets_python3.hci_packets import PhyScanParameters
-from bluetooth_packets_python3.hci_packets import LeScanType
-from bluetooth_packets_python3.hci_packets import LeSetExtendedScanParametersBuilder
-from bluetooth_packets_python3.hci_packets import OwnAddressType
-from bluetooth_packets_python3.hci_packets import LeScanningFilterPolicy
-from bluetooth_packets_python3.hci_packets import Enable
-from bluetooth_packets_python3.hci_packets import FilterDuplicates
-from bluetooth_packets_python3.hci_packets import LeSetExtendedAdvertisingLegacyParametersBuilder
-from bluetooth_packets_python3.hci_packets import LegacyAdvertisingProperties
-from bluetooth_packets_python3.hci_packets import PeerAddressType
-from bluetooth_packets_python3.hci_packets import AdvertisingFilterPolicy
-from bluetooth_packets_python3.hci_packets import LeSetExtendedAdvertisingRandomAddressBuilder
-from bluetooth_packets_python3.hci_packets import GapData
-from bluetooth_packets_python3.hci_packets import GapDataType
-from bluetooth_packets_python3.hci_packets import LeSetExtendedAdvertisingDataBuilder
-from bluetooth_packets_python3.hci_packets import Operation
-from bluetooth_packets_python3.hci_packets import FragmentPreference
-from bluetooth_packets_python3.hci_packets import LeSetExtendedAdvertisingScanResponseBuilder
-from bluetooth_packets_python3.hci_packets import LeSetExtendedAdvertisingEnableBuilder
-from bluetooth_packets_python3.hci_packets import LeSetExtendedScanEnableBuilder
-from bluetooth_packets_python3.hci_packets import EnabledSet
-from bluetooth_packets_python3.hci_packets import LeCreateConnPhyScanParameters
-from bluetooth_packets_python3.hci_packets import LeExtendedCreateConnectionBuilder
-from bluetooth_packets_python3.hci_packets import InitiatorFilterPolicy
-from bluetooth_packets_python3.hci_packets import AddressType
-from bluetooth_packets_python3.hci_packets import BroadcastFlag
-from bluetooth_packets_python3.hci_packets import ConnectListAddressType
-from bluetooth_packets_python3.hci_packets import LeAddDeviceToConnectListBuilder
-from bluetooth_packets_python3.hci_packets import LeSetRandomAddressBuilder
-from bluetooth_packets_python3.hci_packets import LeReadRemoteFeaturesBuilder
-from bluetooth_packets_python3.hci_packets import WritePageTimeoutBuilder
-from bluetooth_packets_python3.hci_packets import ReadBdAddrBuilder
-from bluetooth_packets_python3.hci_packets import CreateConnectionBuilder
-from bluetooth_packets_python3.hci_packets import PageScanRepetitionMode
-from bluetooth_packets_python3.hci_packets import ClockOffsetValid
-from bluetooth_packets_python3.hci_packets import CreateConnectionRoleSwitch
-from bluetooth_packets_python3.hci_packets import AcceptConnectionRequestBuilder
-from bluetooth_packets_python3.hci_packets import AcceptConnectionRequestRole
-from bluetooth_packets_python3.hci_packets import PacketBoundaryFlag
-from bluetooth_packets_python3.hci_packets import ResetBuilder
-from bluetooth_packets_python3.hci_packets import Lap
-from bluetooth_packets_python3.hci_packets import OpCode
-from bluetooth_packets_python3.hci_packets import AclBuilder
-from bluetooth_packets_python3 import RawBuilder
+from hci.cert.direct_hci_test_lib import DirectHciTestBase
-class DirectHciTest(GdBaseTestClass):
+class DirectHciTest(GdBaseTestClass, DirectHciTestBase):
def setup_class(self):
- super().setup_class(dut_module='HCI', cert_module='HAL')
+ GdBaseTestClass.setup_class(self, dut_module='HCI', cert_module='HAL')
def setup_test(self):
- super().setup_test()
- self.dut_hci = PyHci(self.dut, acl_streaming=True)
- self.cert_hal = PyHal(self.cert)
- self.cert_hal.send_hci_command(ResetBuilder())
+ GdBaseTestClass.setup_test(self)
+ DirectHciTestBase.setup_test(self, self.dut, self.cert)
def teardown_test(self):
- self.dut_hci.close()
- self.cert_hal.close()
- super().teardown_test()
-
- def enqueue_acl_data(self, handle, pb_flag, b_flag, data):
- acl = AclBuilder(handle, pb_flag, b_flag, RawBuilder(data))
- self.dut.hci.SendAcl(common.Data(payload=bytes(acl.Serialize())))
-
- def test_local_hci_cmd_and_event(self):
- # Loopback mode responds with ACL and SCO connection complete
- self.dut_hci.register_for_events(EventCode.LOOPBACK_COMMAND)
- self.dut_hci.send_command(WriteLoopbackModeBuilder(LoopbackMode.ENABLE_LOCAL))
-
- self.dut_hci.send_command(ReadLocalNameBuilder())
- assertThat(self.dut_hci.get_event_stream()).emits(HciMatchers.LoopbackOf(ReadLocalNameBuilder()))
-
- def test_inquiry_from_dut(self):
- self.dut_hci.register_for_events(EventCode.INQUIRY_RESULT)
-
- self.cert_hal.enable_inquiry_and_page_scan()
- lap = Lap()
- lap.lap = 0x33
- self.dut_hci.send_command(InquiryBuilder(lap, 0x30, 0xff))
- assertThat(self.dut_hci.get_event_stream()).emits(HciMatchers.EventWithCode(EventCode.INQUIRY_RESULT))
-
- def test_le_ad_scan_cert_advertises(self):
- self.dut_hci.register_for_le_events(SubeventCode.EXTENDED_ADVERTISING_REPORT, SubeventCode.ADVERTISING_REPORT)
-
- # DUT Scans
- self.dut_hci.send_command(LeSetRandomAddressBuilder('0D:05:04:03:02:01'))
- phy_scan_params = PhyScanParameters()
- phy_scan_params.le_scan_interval = 6553
- phy_scan_params.le_scan_window = 6553
- phy_scan_params.le_scan_type = LeScanType.ACTIVE
-
- self.dut_hci.send_command(
- LeSetExtendedScanParametersBuilder(OwnAddressType.RANDOM_DEVICE_ADDRESS, LeScanningFilterPolicy.ACCEPT_ALL,
- 1, [phy_scan_params]))
- self.dut_hci.send_command(LeSetExtendedScanEnableBuilder(Enable.ENABLED, FilterDuplicates.DISABLED, 0, 0))
-
- # CERT Advertises
- advertising_handle = 0
- self.cert_hal.send_hci_command(
- LeSetExtendedAdvertisingLegacyParametersBuilder(
- advertising_handle,
- LegacyAdvertisingProperties.ADV_IND,
- 512,
- 768,
- 7,
- OwnAddressType.RANDOM_DEVICE_ADDRESS,
- PeerAddressType.PUBLIC_DEVICE_OR_IDENTITY_ADDRESS,
- 'A6:A5:A4:A3:A2:A1',
- AdvertisingFilterPolicy.ALL_DEVICES,
- 0xF7,
- 1, # SID
- Enable.DISABLED # Scan request notification
- ))
-
- self.cert_hal.send_hci_command(
- LeSetExtendedAdvertisingRandomAddressBuilder(advertising_handle, '0C:05:04:03:02:01'))
- gap_name = GapData()
- gap_name.data_type = GapDataType.COMPLETE_LOCAL_NAME
- gap_name.data = list(bytes(b'Im_A_Cert'))
-
- self.cert_hal.send_hci_command(
- LeSetExtendedAdvertisingDataBuilder(advertising_handle, Operation.COMPLETE_ADVERTISEMENT,
- FragmentPreference.CONTROLLER_SHOULD_NOT, [gap_name]))
-
- gap_short_name = GapData()
- gap_short_name.data_type = GapDataType.SHORTENED_LOCAL_NAME
- gap_short_name.data = list(bytes(b'Im_A_C'))
-
- self.cert_hal.send_hci_command(
- LeSetExtendedAdvertisingScanResponseBuilder(advertising_handle, Operation.COMPLETE_ADVERTISEMENT,
- FragmentPreference.CONTROLLER_SHOULD_NOT, [gap_short_name]))
-
- enabled_set = EnabledSet()
- enabled_set.advertising_handle = 0
- enabled_set.duration = 0
- enabled_set.max_extended_advertising_events = 0
- self.cert_hal.send_hci_command(LeSetExtendedAdvertisingEnableBuilder(Enable.ENABLED, [enabled_set]))
-
- assertThat(self.dut_hci.get_le_event_stream()).emits(lambda packet: b'Im_A_Cert' in packet.payload)
-
- self.cert_hal.send_hci_command(LeSetExtendedAdvertisingEnableBuilder(Enable.DISABLED, [enabled_set]))
- self.dut_hci.send_command(LeSetExtendedScanEnableBuilder(Enable.DISABLED, FilterDuplicates.DISABLED, 0, 0))
-
- def _verify_le_connection_complete(self):
- cert_conn_complete_capture = HalCaptures.LeConnectionCompleteCapture()
- assertThat(self.cert_hal.get_hci_event_stream()).emits(cert_conn_complete_capture)
- cert_handle = cert_conn_complete_capture.get().GetConnectionHandle()
-
- dut_conn_complete_capture = HciCaptures.LeConnectionCompleteCapture()
- assertThat(self.dut_hci.get_le_event_stream()).emits(dut_conn_complete_capture)
- dut_handle = dut_conn_complete_capture.get().GetConnectionHandle()
-
- return (dut_handle, cert_handle)
-
- @staticmethod
- def _create_phy_scan_params():
- phy_scan_params = LeCreateConnPhyScanParameters()
- phy_scan_params.scan_interval = 0x60
- phy_scan_params.scan_window = 0x30
- phy_scan_params.conn_interval_min = 0x18
- phy_scan_params.conn_interval_max = 0x28
- phy_scan_params.conn_latency = 0
- phy_scan_params.supervision_timeout = 0x1f4
- phy_scan_params.min_ce_length = 0
- phy_scan_params.max_ce_length = 0
- return phy_scan_params
-
- def test_le_connection_dut_advertises(self):
- self.dut_hci.register_for_le_events(SubeventCode.CONNECTION_COMPLETE, SubeventCode.ADVERTISING_SET_TERMINATED,
- SubeventCode.ENHANCED_CONNECTION_COMPLETE,
- SubeventCode.READ_REMOTE_FEATURES_COMPLETE)
- # Cert Connects
- self.cert_hal.send_hci_command(LeSetRandomAddressBuilder('0C:05:04:03:02:01'))
- phy_scan_params = DirectHciTest._create_phy_scan_params()
- self.cert_hal.send_hci_command(
- LeExtendedCreateConnectionBuilder(InitiatorFilterPolicy.USE_PEER_ADDRESS,
- OwnAddressType.RANDOM_DEVICE_ADDRESS, AddressType.RANDOM_DEVICE_ADDRESS,
- '0D:05:04:03:02:01', 1, [phy_scan_params]))
-
- advertisement = self.dut_hci.create_advertisement(0, '0D:05:04:03:02:01')
- advertisement.set_data(b'Im_The_DUT')
- advertisement.set_scan_response(b'Im_The_D')
- advertisement.start()
-
- (dut_handle, cert_handle) = self._verify_le_connection_complete()
-
- self.dut_hci.send_command(LeReadRemoteFeaturesBuilder(dut_handle))
- assertThat(self.dut_hci.get_le_event_stream()).emits(
- lambda packet: packet.payload[0] == int(EventCode.LE_META_EVENT) and packet.payload[2] == int(SubeventCode.READ_REMOTE_FEATURES_COMPLETE)
- )
-
- # Send ACL Data
- self.enqueue_acl_data(dut_handle, PacketBoundaryFlag.FIRST_NON_AUTOMATICALLY_FLUSHABLE,
- BroadcastFlag.POINT_TO_POINT, bytes(b'Just SomeAclData'))
- self.cert_hal.send_acl_first(cert_handle, bytes(b'Just SomeMoreAclData'))
-
- assertThat(self.cert_hal.get_acl_stream()).emits(
- lambda packet: logging.debug(packet.payload) or b'SomeAclData' in packet.payload)
- assertThat(self.dut_hci.get_raw_acl_stream()).emits(
- lambda packet: logging.debug(packet.payload) or b'SomeMoreAclData' in packet.payload)
-
- def test_le_connect_list_connection_cert_advertises(self):
- self.dut_hci.register_for_le_events(SubeventCode.CONNECTION_COMPLETE, SubeventCode.ENHANCED_CONNECTION_COMPLETE)
- # DUT Connects
- self.dut_hci.send_command(LeSetRandomAddressBuilder('0D:05:04:03:02:01'))
- self.dut_hci.send_command(LeAddDeviceToConnectListBuilder(ConnectListAddressType.RANDOM, '0C:05:04:03:02:01'))
- phy_scan_params = DirectHciTest._create_phy_scan_params()
- self.dut_hci.send_command(
- LeExtendedCreateConnectionBuilder(InitiatorFilterPolicy.USE_CONNECT_LIST,
- OwnAddressType.RANDOM_DEVICE_ADDRESS, AddressType.RANDOM_DEVICE_ADDRESS,
- 'BA:D5:A4:A3:A2:A1', 1, [phy_scan_params]))
-
- advertisement = self.cert_hal.create_advertisement(
- 1,
- '0C:05:04:03:02:01',
- min_interval=512,
- max_interval=768,
- peer_address='A6:A5:A4:A3:A2:A1',
- tx_power=0x7f,
- sid=0)
- advertisement.set_data(b'Im_A_Cert')
- advertisement.start()
-
- # LeConnectionComplete
- self._verify_le_connection_complete()
-
- def test_connection_dut_connects(self):
- self.dut_hci.send_command(WritePageTimeoutBuilder(0x4000))
-
- self.cert_hal.enable_inquiry_and_page_scan()
- address = self.cert_hal.read_own_address()
-
- self.dut_hci.initiate_connection(address)
- cert_acl = self.cert_hal.accept_connection()
- dut_acl = self.dut_hci.complete_connection()
-
- # Send ACL Data
- dut_acl.send_first(b'Just SomeAclData')
- cert_acl.send_first(b'Just SomeMoreAclData')
-
- assertThat(self.cert_hal.get_acl_stream()).emits(lambda packet: b'SomeAclData' in packet.payload)
- assertThat(self.dut_hci.get_raw_acl_stream()).emits(lambda packet: b'SomeMoreAclData' in packet.payload)
-
- def test_connection_cert_connects(self):
- self.cert_hal.send_hci_command(WritePageTimeoutBuilder(0x4000))
-
- self.dut_hci.enable_inquiry_and_page_scan()
- address = self.dut_hci.read_own_address()
-
- self.cert_hal.initiate_connection(address)
- dut_acl = self.dut_hci.accept_connection()
- cert_acl = self.cert_hal.complete_connection()
-
- # Send ACL Data
- dut_acl.send_first(b'This is just SomeAclData')
- cert_acl.send_first(b'This is just SomeMoreAclData')
-
- assertThat(self.cert_hal.get_acl_stream()).emits(lambda packet: b'SomeAclData' in packet.payload)
- assertThat(self.dut_hci.get_raw_acl_stream()).emits(lambda packet: b'SomeMoreAclData' in packet.payload)
+ DirectHciTestBase.teardown_test(self)
+ GdBaseTestClass.teardown_test(self)
diff --git a/gd/hci/cert/direct_hci_test_lib.py b/gd/hci/cert/direct_hci_test_lib.py
new file mode 100644
index 0000000..cd6c210
--- /dev/null
+++ b/gd/hci/cert/direct_hci_test_lib.py
@@ -0,0 +1,291 @@
+#!/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 datetime import timedelta
+import logging
+
+from cert.captures import HalCaptures, HciCaptures
+from cert.matchers import HciMatchers
+from cert.py_hal import PyHal
+from cert.py_hci import PyHci
+from cert.truth import assertThat
+from hci.facade import hci_facade_pb2 as hci_facade
+from facade import common_pb2 as common
+from bluetooth_packets_python3.hci_packets import EventCode
+from bluetooth_packets_python3.hci_packets import LoopbackMode
+from bluetooth_packets_python3.hci_packets import WriteLoopbackModeBuilder
+from bluetooth_packets_python3.hci_packets import ReadLocalNameBuilder
+from bluetooth_packets_python3.hci_packets import WriteScanEnableBuilder
+from bluetooth_packets_python3.hci_packets import ScanEnable
+from bluetooth_packets_python3.hci_packets import InquiryBuilder
+from bluetooth_packets_python3.hci_packets import SubeventCode
+from bluetooth_packets_python3.hci_packets import LeSetRandomAddressBuilder
+from bluetooth_packets_python3.hci_packets import PhyScanParameters
+from bluetooth_packets_python3.hci_packets import LeScanType
+from bluetooth_packets_python3.hci_packets import LeSetExtendedScanParametersBuilder
+from bluetooth_packets_python3.hci_packets import OwnAddressType
+from bluetooth_packets_python3.hci_packets import LeScanningFilterPolicy
+from bluetooth_packets_python3.hci_packets import Enable
+from bluetooth_packets_python3.hci_packets import FilterDuplicates
+from bluetooth_packets_python3.hci_packets import LeSetExtendedAdvertisingLegacyParametersBuilder
+from bluetooth_packets_python3.hci_packets import LegacyAdvertisingProperties
+from bluetooth_packets_python3.hci_packets import PeerAddressType
+from bluetooth_packets_python3.hci_packets import AdvertisingFilterPolicy
+from bluetooth_packets_python3.hci_packets import LeSetExtendedAdvertisingRandomAddressBuilder
+from bluetooth_packets_python3.hci_packets import GapData
+from bluetooth_packets_python3.hci_packets import GapDataType
+from bluetooth_packets_python3.hci_packets import LeSetExtendedAdvertisingDataBuilder
+from bluetooth_packets_python3.hci_packets import Operation
+from bluetooth_packets_python3.hci_packets import FragmentPreference
+from bluetooth_packets_python3.hci_packets import LeSetExtendedAdvertisingScanResponseBuilder
+from bluetooth_packets_python3.hci_packets import LeSetExtendedAdvertisingEnableBuilder
+from bluetooth_packets_python3.hci_packets import LeSetExtendedScanEnableBuilder
+from bluetooth_packets_python3.hci_packets import EnabledSet
+from bluetooth_packets_python3.hci_packets import LeCreateConnPhyScanParameters
+from bluetooth_packets_python3.hci_packets import LeExtendedCreateConnectionBuilder
+from bluetooth_packets_python3.hci_packets import InitiatorFilterPolicy
+from bluetooth_packets_python3.hci_packets import AddressType
+from bluetooth_packets_python3.hci_packets import BroadcastFlag
+from bluetooth_packets_python3.hci_packets import ConnectListAddressType
+from bluetooth_packets_python3.hci_packets import LeAddDeviceToConnectListBuilder
+from bluetooth_packets_python3.hci_packets import LeSetRandomAddressBuilder
+from bluetooth_packets_python3.hci_packets import LeReadRemoteFeaturesBuilder
+from bluetooth_packets_python3.hci_packets import WritePageTimeoutBuilder
+from bluetooth_packets_python3.hci_packets import ReadBdAddrBuilder
+from bluetooth_packets_python3.hci_packets import CreateConnectionBuilder
+from bluetooth_packets_python3.hci_packets import PageScanRepetitionMode
+from bluetooth_packets_python3.hci_packets import ClockOffsetValid
+from bluetooth_packets_python3.hci_packets import CreateConnectionRoleSwitch
+from bluetooth_packets_python3.hci_packets import AcceptConnectionRequestBuilder
+from bluetooth_packets_python3.hci_packets import AcceptConnectionRequestRole
+from bluetooth_packets_python3.hci_packets import PacketBoundaryFlag
+from bluetooth_packets_python3.hci_packets import ResetBuilder
+from bluetooth_packets_python3.hci_packets import Lap
+from bluetooth_packets_python3.hci_packets import OpCode
+from bluetooth_packets_python3.hci_packets import AclBuilder
+from bluetooth_packets_python3 import RawBuilder
+
+
+class DirectHciTestBase():
+
+ def setup_test(self, dut, cert):
+ self.dut_hci = PyHci(dut, acl_streaming=True)
+ self.cert_hal = PyHal(cert)
+ self.cert_hal.send_hci_command(ResetBuilder())
+
+ def teardown_test(self):
+ self.dut_hci.close()
+ self.cert_hal.close()
+
+ def enqueue_acl_data(self, handle, pb_flag, b_flag, data):
+ acl = AclBuilder(handle, pb_flag, b_flag, RawBuilder(data))
+ self.dut.hci.SendAcl(common.Data(payload=bytes(acl.Serialize())))
+
+ def test_local_hci_cmd_and_event(self):
+ # Loopback mode responds with ACL and SCO connection complete
+ self.dut_hci.register_for_events(EventCode.LOOPBACK_COMMAND)
+ self.dut_hci.send_command(WriteLoopbackModeBuilder(LoopbackMode.ENABLE_LOCAL))
+
+ self.dut_hci.send_command(ReadLocalNameBuilder())
+ assertThat(self.dut_hci.get_event_stream()).emits(HciMatchers.LoopbackOf(ReadLocalNameBuilder()))
+
+ def test_inquiry_from_dut(self):
+ self.dut_hci.register_for_events(EventCode.INQUIRY_RESULT)
+
+ self.cert_hal.enable_inquiry_and_page_scan()
+ lap = Lap()
+ lap.lap = 0x33
+ self.dut_hci.send_command(InquiryBuilder(lap, 0x30, 0xff))
+ assertThat(self.dut_hci.get_event_stream()).emits(HciMatchers.EventWithCode(EventCode.INQUIRY_RESULT))
+
+ def test_le_ad_scan_cert_advertises(self):
+ self.dut_hci.register_for_le_events(SubeventCode.EXTENDED_ADVERTISING_REPORT, SubeventCode.ADVERTISING_REPORT)
+
+ # DUT Scans
+ self.dut_hci.send_command(LeSetRandomAddressBuilder('0D:05:04:03:02:01'))
+ phy_scan_params = PhyScanParameters()
+ phy_scan_params.le_scan_interval = 6553
+ phy_scan_params.le_scan_window = 6553
+ phy_scan_params.le_scan_type = LeScanType.ACTIVE
+
+ self.dut_hci.send_command(
+ LeSetExtendedScanParametersBuilder(OwnAddressType.RANDOM_DEVICE_ADDRESS, LeScanningFilterPolicy.ACCEPT_ALL,
+ 1, [phy_scan_params]))
+ self.dut_hci.send_command(LeSetExtendedScanEnableBuilder(Enable.ENABLED, FilterDuplicates.DISABLED, 0, 0))
+
+ # CERT Advertises
+ advertising_handle = 0
+ self.cert_hal.send_hci_command(
+ LeSetExtendedAdvertisingLegacyParametersBuilder(
+ advertising_handle,
+ LegacyAdvertisingProperties.ADV_IND,
+ 512,
+ 768,
+ 7,
+ OwnAddressType.RANDOM_DEVICE_ADDRESS,
+ PeerAddressType.PUBLIC_DEVICE_OR_IDENTITY_ADDRESS,
+ 'A6:A5:A4:A3:A2:A1',
+ AdvertisingFilterPolicy.ALL_DEVICES,
+ 0xF7,
+ 1, # SID
+ Enable.DISABLED # Scan request notification
+ ))
+
+ self.cert_hal.send_hci_command(
+ LeSetExtendedAdvertisingRandomAddressBuilder(advertising_handle, '0C:05:04:03:02:01'))
+ gap_name = GapData()
+ gap_name.data_type = GapDataType.COMPLETE_LOCAL_NAME
+ gap_name.data = list(bytes(b'Im_A_Cert'))
+
+ self.cert_hal.send_hci_command(
+ LeSetExtendedAdvertisingDataBuilder(advertising_handle, Operation.COMPLETE_ADVERTISEMENT,
+ FragmentPreference.CONTROLLER_SHOULD_NOT, [gap_name]))
+
+ gap_short_name = GapData()
+ gap_short_name.data_type = GapDataType.SHORTENED_LOCAL_NAME
+ gap_short_name.data = list(bytes(b'Im_A_C'))
+
+ self.cert_hal.send_hci_command(
+ LeSetExtendedAdvertisingScanResponseBuilder(advertising_handle, Operation.COMPLETE_ADVERTISEMENT,
+ FragmentPreference.CONTROLLER_SHOULD_NOT, [gap_short_name]))
+
+ enabled_set = EnabledSet()
+ enabled_set.advertising_handle = 0
+ enabled_set.duration = 0
+ enabled_set.max_extended_advertising_events = 0
+ self.cert_hal.send_hci_command(LeSetExtendedAdvertisingEnableBuilder(Enable.ENABLED, [enabled_set]))
+
+ assertThat(self.dut_hci.get_le_event_stream()).emits(lambda packet: b'Im_A_Cert' in packet.payload)
+
+ self.cert_hal.send_hci_command(LeSetExtendedAdvertisingEnableBuilder(Enable.DISABLED, [enabled_set]))
+ self.dut_hci.send_command(LeSetExtendedScanEnableBuilder(Enable.DISABLED, FilterDuplicates.DISABLED, 0, 0))
+
+ def _verify_le_connection_complete(self):
+ cert_conn_complete_capture = HalCaptures.LeConnectionCompleteCapture()
+ assertThat(self.cert_hal.get_hci_event_stream()).emits(cert_conn_complete_capture)
+ cert_handle = cert_conn_complete_capture.get().GetConnectionHandle()
+
+ dut_conn_complete_capture = HciCaptures.LeConnectionCompleteCapture()
+ assertThat(self.dut_hci.get_le_event_stream()).emits(dut_conn_complete_capture)
+ dut_handle = dut_conn_complete_capture.get().GetConnectionHandle()
+
+ return (dut_handle, cert_handle)
+
+ @staticmethod
+ def _create_phy_scan_params():
+ phy_scan_params = LeCreateConnPhyScanParameters()
+ phy_scan_params.scan_interval = 0x60
+ phy_scan_params.scan_window = 0x30
+ phy_scan_params.conn_interval_min = 0x18
+ phy_scan_params.conn_interval_max = 0x28
+ phy_scan_params.conn_latency = 0
+ phy_scan_params.supervision_timeout = 0x1f4
+ phy_scan_params.min_ce_length = 0
+ phy_scan_params.max_ce_length = 0
+ return phy_scan_params
+
+ def test_le_connection_dut_advertises(self):
+ self.dut_hci.register_for_le_events(SubeventCode.CONNECTION_COMPLETE, SubeventCode.ADVERTISING_SET_TERMINATED,
+ SubeventCode.ENHANCED_CONNECTION_COMPLETE,
+ SubeventCode.READ_REMOTE_FEATURES_COMPLETE)
+ # Cert Connects
+ self.cert_hal.send_hci_command(LeSetRandomAddressBuilder('0C:05:04:03:02:01'))
+ phy_scan_params = DirectHciTestBase._create_phy_scan_params()
+ self.cert_hal.send_hci_command(
+ LeExtendedCreateConnectionBuilder(InitiatorFilterPolicy.USE_PEER_ADDRESS,
+ OwnAddressType.RANDOM_DEVICE_ADDRESS, AddressType.RANDOM_DEVICE_ADDRESS,
+ '0D:05:04:03:02:01', 1, [phy_scan_params]))
+
+ advertisement = self.dut_hci.create_advertisement(0, '0D:05:04:03:02:01')
+ advertisement.set_data(b'Im_The_DUT')
+ advertisement.set_scan_response(b'Im_The_D')
+ advertisement.start()
+
+ (dut_handle, cert_handle) = self._verify_le_connection_complete()
+
+ self.dut_hci.send_command(LeReadRemoteFeaturesBuilder(dut_handle))
+ assertThat(self.dut_hci.get_le_event_stream()).emits(
+ lambda packet: packet.payload[0] == int(EventCode.LE_META_EVENT) and packet.payload[2] == int(SubeventCode.READ_REMOTE_FEATURES_COMPLETE)
+ )
+
+ # Send ACL Data
+ self.enqueue_acl_data(dut_handle, PacketBoundaryFlag.FIRST_NON_AUTOMATICALLY_FLUSHABLE,
+ BroadcastFlag.POINT_TO_POINT, bytes(b'Just SomeAclData'))
+ self.cert_hal.send_acl_first(cert_handle, bytes(b'Just SomeMoreAclData'))
+
+ assertThat(self.cert_hal.get_acl_stream()).emits(
+ lambda packet: logging.debug(packet.payload) or b'SomeAclData' in packet.payload)
+ assertThat(self.dut_hci.get_raw_acl_stream()).emits(
+ lambda packet: logging.debug(packet.payload) or b'SomeMoreAclData' in packet.payload)
+
+ def test_le_connect_list_connection_cert_advertises(self):
+ self.dut_hci.register_for_le_events(SubeventCode.CONNECTION_COMPLETE, SubeventCode.ENHANCED_CONNECTION_COMPLETE)
+ # DUT Connects
+ self.dut_hci.send_command(LeSetRandomAddressBuilder('0D:05:04:03:02:01'))
+ self.dut_hci.send_command(LeAddDeviceToConnectListBuilder(ConnectListAddressType.RANDOM, '0C:05:04:03:02:01'))
+ phy_scan_params = DirectHciTestBase._create_phy_scan_params()
+ self.dut_hci.send_command(
+ LeExtendedCreateConnectionBuilder(InitiatorFilterPolicy.USE_CONNECT_LIST,
+ OwnAddressType.RANDOM_DEVICE_ADDRESS, AddressType.RANDOM_DEVICE_ADDRESS,
+ 'BA:D5:A4:A3:A2:A1', 1, [phy_scan_params]))
+
+ advertisement = self.cert_hal.create_advertisement(
+ 1,
+ '0C:05:04:03:02:01',
+ min_interval=512,
+ max_interval=768,
+ peer_address='A6:A5:A4:A3:A2:A1',
+ tx_power=0x7f,
+ sid=0)
+ advertisement.set_data(b'Im_A_Cert')
+ advertisement.start()
+
+ # LeConnectionComplete
+ self._verify_le_connection_complete()
+
+ def test_connection_dut_connects(self):
+ self.dut_hci.send_command(WritePageTimeoutBuilder(0x4000))
+
+ self.cert_hal.enable_inquiry_and_page_scan()
+ address = self.cert_hal.read_own_address()
+
+ self.dut_hci.initiate_connection(address)
+ cert_acl = self.cert_hal.accept_connection()
+ dut_acl = self.dut_hci.complete_connection()
+
+ # Send ACL Data
+ dut_acl.send_first(b'Just SomeAclData')
+ cert_acl.send_first(b'Just SomeMoreAclData')
+
+ assertThat(self.cert_hal.get_acl_stream()).emits(lambda packet: b'SomeAclData' in packet.payload)
+ assertThat(self.dut_hci.get_raw_acl_stream()).emits(lambda packet: b'SomeMoreAclData' in packet.payload)
+
+ def test_connection_cert_connects(self):
+ self.cert_hal.send_hci_command(WritePageTimeoutBuilder(0x4000))
+
+ self.dut_hci.enable_inquiry_and_page_scan()
+ address = self.dut_hci.read_own_address()
+
+ self.cert_hal.initiate_connection(address)
+ dut_acl = self.dut_hci.accept_connection()
+ cert_acl = self.cert_hal.complete_connection()
+
+ # Send ACL Data
+ dut_acl.send_first(b'This is just SomeAclData')
+ cert_acl.send_first(b'This is just SomeMoreAclData')
+
+ assertThat(self.cert_hal.get_acl_stream()).emits(lambda packet: b'SomeAclData' in packet.payload)
+ assertThat(self.dut_hci.get_raw_acl_stream()).emits(lambda packet: b'SomeMoreAclData' in packet.payload)
diff --git a/gd/hci/cert/le_acl_manager_test.py b/gd/hci/cert/le_acl_manager_test.py
index aa3d75e..d710860 100644
--- a/gd/hci/cert/le_acl_manager_test.py
+++ b/gd/hci/cert/le_acl_manager_test.py
@@ -14,279 +14,19 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from cert.closable import safeClose
from cert.gd_base_test import GdBaseTestClass
-from cert.event_stream import EventStream
-from cert.truth import assertThat
-from cert.py_le_acl_manager import PyLeAclManager
-from google.protobuf import empty_pb2 as empty_proto
-from facade import common_pb2 as common
-from hci.facade import le_acl_manager_facade_pb2 as le_acl_manager_facade
-from hci.facade import le_advertising_manager_facade_pb2 as le_advertising_facade
-from hci.facade import le_initiator_address_facade_pb2 as le_initiator_address_facade
-from hci.facade import hci_facade_pb2 as hci_facade
-import bluetooth_packets_python3 as bt_packets
-from bluetooth_packets_python3 import hci_packets
-from bluetooth_packets_python3 import RawBuilder
+from hci.cert.le_acl_manager_test_lib import LeAclManagerTestBase
-class LeAclManagerTest(GdBaseTestClass):
+class LeAclManagerTest(GdBaseTestClass, LeAclManagerTestBase):
def setup_class(self):
- super().setup_class(dut_module='HCI_INTERFACES', cert_module='HCI')
+ GdBaseTestClass.setup_class(self, dut_module='HCI_INTERFACES', cert_module='HCI')
def setup_test(self):
- super().setup_test()
- self.dut_le_acl_manager = PyLeAclManager(self.dut)
- self.cert_hci_le_event_stream = EventStream(self.cert.hci.StreamLeSubevents(empty_proto.Empty()))
- self.cert_acl_data_stream = EventStream(self.cert.hci.StreamAcl(empty_proto.Empty()))
+ GdBaseTestClass.setup_test(self)
+ LeAclManagerTestBase.setup_test(self, self.dut, self.cert)
def teardown_test(self):
- safeClose(self.cert_hci_le_event_stream)
- safeClose(self.cert_acl_data_stream)
- safeClose(self.dut_le_acl_manager)
- super().teardown_test()
-
- def set_privacy_policy_static(self):
- self.dut_address = b'd0:05:04:03:02:01'
- private_policy = le_initiator_address_facade.PrivacyPolicy(
- address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
- address_with_type=common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=bytes(self.dut_address)), type=common.RANDOM_DEVICE_ADDRESS))
- self.dut.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(private_policy)
-
- def register_for_event(self, event_code):
- msg = hci_facade.EventRequest(code=int(event_code))
- self.cert.hci.RequestEvent(msg)
-
- def register_for_le_event(self, event_code):
- msg = hci_facade.EventRequest(code=int(event_code))
- self.cert.hci.RequestLeSubevent(msg)
-
- def enqueue_hci_command(self, command):
- cmd_bytes = bytes(command.Serialize())
- cmd = common.Data(payload=cmd_bytes)
- self.cert.hci.SendCommand(cmd)
-
- def enqueue_acl_data(self, handle, pb_flag, b_flag, data):
- acl = hci_packets.AclBuilder(handle, pb_flag, b_flag, RawBuilder(data))
- self.cert.hci.SendAcl(common.Data(payload=bytes(acl.Serialize())))
-
- def dut_connects(self, check_address):
- self.register_for_le_event(hci_packets.SubeventCode.CONNECTION_COMPLETE)
- self.register_for_le_event(hci_packets.SubeventCode.ENHANCED_CONNECTION_COMPLETE)
-
- # Cert Advertises
- advertising_handle = 0
- self.enqueue_hci_command(
- hci_packets.LeSetExtendedAdvertisingLegacyParametersBuilder(
- advertising_handle,
- hci_packets.LegacyAdvertisingProperties.ADV_IND,
- 400,
- 450,
- 7,
- hci_packets.OwnAddressType.RANDOM_DEVICE_ADDRESS,
- hci_packets.PeerAddressType.PUBLIC_DEVICE_OR_IDENTITY_ADDRESS,
- '00:00:00:00:00:00',
- hci_packets.AdvertisingFilterPolicy.ALL_DEVICES,
- 0xF8,
- 1, #SID
- hci_packets.Enable.DISABLED # Scan request notification
- ))
-
- self.enqueue_hci_command(
- hci_packets.LeSetExtendedAdvertisingRandomAddressBuilder(advertising_handle, '0C:05:04:03:02:01'))
-
- gap_name = hci_packets.GapData()
- gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
- gap_name.data = list(bytes(b'Im_A_Cert'))
-
- self.enqueue_hci_command(
- hci_packets.LeSetExtendedAdvertisingDataBuilder(
- advertising_handle, hci_packets.Operation.COMPLETE_ADVERTISEMENT,
- hci_packets.FragmentPreference.CONTROLLER_SHOULD_NOT, [gap_name]))
-
- gap_short_name = hci_packets.GapData()
- gap_short_name.data_type = hci_packets.GapDataType.SHORTENED_LOCAL_NAME
- gap_short_name.data = list(bytes(b'Im_A_C'))
-
- self.enqueue_hci_command(
- hci_packets.LeSetExtendedAdvertisingScanResponseBuilder(
- advertising_handle, hci_packets.Operation.COMPLETE_ADVERTISEMENT,
- hci_packets.FragmentPreference.CONTROLLER_SHOULD_NOT, [gap_short_name]))
-
- enabled_set = hci_packets.EnabledSet()
- enabled_set.advertising_handle = advertising_handle
- enabled_set.duration = 0
- enabled_set.max_extended_advertising_events = 0
- self.enqueue_hci_command(
- hci_packets.LeSetExtendedAdvertisingEnableBuilder(hci_packets.Enable.ENABLED, [enabled_set]))
-
- self.dut_le_acl = self.dut_le_acl_manager.connect_to_remote(
- remote_addr=common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=bytes('0C:05:04:03:02:01', 'utf8')),
- type=int(hci_packets.AddressType.RANDOM_DEVICE_ADDRESS)))
-
- # Cert gets ConnectionComplete with a handle and sends ACL data
- handle = 0xfff
- address = hci_packets.Address()
-
- def get_handle(packet):
- packet_bytes = packet.payload
- nonlocal handle
- nonlocal address
- if b'\x3e\x13\x01\x00' in packet_bytes:
- cc_view = hci_packets.LeConnectionCompleteView(
- hci_packets.LeMetaEventView(
- hci_packets.EventView(bt_packets.PacketViewLittleEndian(list(packet_bytes)))))
- handle = cc_view.GetConnectionHandle()
- address = cc_view.GetPeerAddress()
- return True
- if b'\x3e\x13\x0A\x00' in packet_bytes:
- cc_view = hci_packets.LeEnhancedConnectionCompleteView(
- hci_packets.LeMetaEventView(
- hci_packets.EventView(bt_packets.PacketViewLittleEndian(list(packet_bytes)))))
- handle = cc_view.GetConnectionHandle()
- address = cc_view.GetPeerResolvablePrivateAddress()
- return True
- return False
-
- self.cert_hci_le_event_stream.assert_event_occurs(get_handle)
- self.cert_handle = handle
- dut_address_from_complete = address
- if check_address:
- assertThat(dut_address_from_complete).isEqualTo(self.dut_address.decode())
-
- def send_receive_and_check(self):
- self.enqueue_acl_data(self.cert_handle, hci_packets.PacketBoundaryFlag.FIRST_NON_AUTOMATICALLY_FLUSHABLE,
- hci_packets.BroadcastFlag.POINT_TO_POINT,
- bytes(b'\x19\x00\x07\x00SomeAclData from the Cert'))
-
- self.dut_le_acl.send(b'\x1C\x00\x07\x00SomeMoreAclData from the DUT')
- self.cert_acl_data_stream.assert_event_occurs(lambda packet: b'SomeMoreAclData' in packet.payload)
- assertThat(self.dut_le_acl).emits(lambda packet: b'SomeAclData' in packet.payload)
-
- def test_dut_connects(self):
- self.set_privacy_policy_static()
- self.dut_connects(check_address=True)
- self.send_receive_and_check()
-
- def test_dut_connects_resolvable_address(self):
- privacy_policy = le_initiator_address_facade.PrivacyPolicy(
- address_policy=le_initiator_address_facade.AddressPolicy.USE_RESOLVABLE_ADDRESS,
- rotation_irk=b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f',
- minimum_rotation_time=7 * 60 * 1000,
- maximum_rotation_time=15 * 60 * 1000)
- self.dut.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(privacy_policy)
- self.dut_connects(check_address=False)
- self.send_receive_and_check()
-
- def test_dut_connects_non_resolvable_address(self):
- privacy_policy = le_initiator_address_facade.PrivacyPolicy(
- address_policy=le_initiator_address_facade.AddressPolicy.USE_NON_RESOLVABLE_ADDRESS,
- rotation_irk=b'\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f',
- minimum_rotation_time=8 * 60 * 1000,
- maximum_rotation_time=14 * 60 * 1000)
- self.dut.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(privacy_policy)
- self.dut_connects(check_address=False)
- self.send_receive_and_check()
-
- def test_dut_connects_public_address(self):
- self.dut.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(
- le_initiator_address_facade.PrivacyPolicy(
- address_policy=le_initiator_address_facade.AddressPolicy.USE_PUBLIC_ADDRESS))
- self.dut_connects(check_address=False)
- self.send_receive_and_check()
-
- def test_dut_connects_public_address_cancelled(self):
- self.dut.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(
- le_initiator_address_facade.PrivacyPolicy(
- address_policy=le_initiator_address_facade.AddressPolicy.USE_PUBLIC_ADDRESS))
- self.dut_connects(check_address=False)
- self.send_receive_and_check()
-
- def test_cert_connects(self):
- self.set_privacy_policy_static()
- self.register_for_le_event(hci_packets.SubeventCode.CONNECTION_COMPLETE)
-
- self.dut_le_acl_manager.listen_for_incoming_connections()
-
- # DUT Advertises
- gap_name = hci_packets.GapData()
- gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
- gap_name.data = list(bytes(b'Im_The_DUT'))
- gap_data = le_advertising_facade.GapDataMsg(data=bytes(gap_name.Serialize()))
- config = le_advertising_facade.AdvertisingConfig(
- advertisement=[gap_data],
- interval_min=512,
- interval_max=768,
- advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
- own_address_type=common.USE_RANDOM_DEVICE_ADDRESS,
- peer_address_type=common.PUBLIC_DEVICE_OR_IDENTITY_ADDRESS,
- peer_address=common.BluetoothAddress(address=bytes(b'A6:A5:A4:A3:A2:A1')),
- channel_map=7,
- filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
- request = le_advertising_facade.CreateAdvertiserRequest(config=config)
-
- self.dut.hci_le_advertising_manager.CreateAdvertiser(request)
-
- # Cert Connects
- self.enqueue_hci_command(hci_packets.LeSetRandomAddressBuilder('0C:05:04:03:02:01'))
- phy_scan_params = hci_packets.LeCreateConnPhyScanParameters()
- phy_scan_params.scan_interval = 0x60
- phy_scan_params.scan_window = 0x30
- phy_scan_params.conn_interval_min = 0x18
- phy_scan_params.conn_interval_max = 0x28
- phy_scan_params.conn_latency = 0
- phy_scan_params.supervision_timeout = 0x1f4
- phy_scan_params.min_ce_length = 0
- phy_scan_params.max_ce_length = 0
- self.enqueue_hci_command(
- hci_packets.LeExtendedCreateConnectionBuilder(hci_packets.InitiatorFilterPolicy.USE_PEER_ADDRESS,
- hci_packets.OwnAddressType.RANDOM_DEVICE_ADDRESS,
- hci_packets.AddressType.RANDOM_DEVICE_ADDRESS,
- self.dut_address.decode(), 1, [phy_scan_params]))
-
- # Cert gets ConnectionComplete with a handle and sends ACL data
- handle = 0xfff
-
- def get_handle(packet):
- packet_bytes = packet.payload
- nonlocal handle
- if b'\x3e\x13\x01\x00' in packet_bytes:
- cc_view = hci_packets.LeConnectionCompleteView(
- hci_packets.LeMetaEventView(
- hci_packets.EventView(bt_packets.PacketViewLittleEndian(list(packet_bytes)))))
- handle = cc_view.GetConnectionHandle()
- return True
- if b'\x3e\x13\x0A\x00' in packet_bytes:
- cc_view = hci_packets.LeEnhancedConnectionCompleteView(
- hci_packets.LeMetaEventView(
- hci_packets.EventView(bt_packets.PacketViewLittleEndian(list(packet_bytes)))))
- handle = cc_view.GetConnectionHandle()
- return True
- return False
-
- self.cert_hci_le_event_stream.assert_event_occurs(get_handle)
- self.cert_handle = handle
-
- self.enqueue_acl_data(self.cert_handle, hci_packets.PacketBoundaryFlag.FIRST_NON_AUTOMATICALLY_FLUSHABLE,
- hci_packets.BroadcastFlag.POINT_TO_POINT,
- bytes(b'\x19\x00\x07\x00SomeAclData from the Cert'))
-
- # DUT gets a connection complete event and sends and receives
- handle = 0xfff
- self.dut_le_acl = self.dut_le_acl_manager.complete_incoming_connection()
-
- self.send_receive_and_check()
-
- def test_recombination_l2cap_packet(self):
- self.set_privacy_policy_static()
- self.dut_connects(check_address=True)
-
- self.enqueue_acl_data(self.cert_handle, hci_packets.PacketBoundaryFlag.FIRST_NON_AUTOMATICALLY_FLUSHABLE,
- hci_packets.BroadcastFlag.POINT_TO_POINT, bytes(b'\x06\x00\x07\x00Hello'))
- self.enqueue_acl_data(self.cert_handle, hci_packets.PacketBoundaryFlag.CONTINUING_FRAGMENT,
- hci_packets.BroadcastFlag.POINT_TO_POINT, bytes(b'!'))
-
- assertThat(self.dut_le_acl).emits(lambda packet: b'Hello!' in packet.payload)
+ LeAclManagerTestBase.teardown_test(self)
+ GdBaseTestClass.teardown_test(self)
diff --git a/gd/hci/cert/le_acl_manager_test_lib.py b/gd/hci/cert/le_acl_manager_test_lib.py
new file mode 100644
index 0000000..39f148b
--- /dev/null
+++ b/gd/hci/cert/le_acl_manager_test_lib.py
@@ -0,0 +1,286 @@
+#!/usr/bin/env python3
+#
+# Copyright 2020 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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 cert.closable import safeClose
+from cert.event_stream import EventStream
+from cert.truth import assertThat
+from cert.py_le_acl_manager import PyLeAclManager
+from google.protobuf import empty_pb2 as empty_proto
+from facade import common_pb2 as common
+from hci.facade import le_acl_manager_facade_pb2 as le_acl_manager_facade
+from hci.facade import le_advertising_manager_facade_pb2 as le_advertising_facade
+from hci.facade import le_initiator_address_facade_pb2 as le_initiator_address_facade
+from hci.facade import hci_facade_pb2 as hci_facade
+import bluetooth_packets_python3 as bt_packets
+from bluetooth_packets_python3 import hci_packets
+from bluetooth_packets_python3 import RawBuilder
+
+
+class LeAclManagerTestBase():
+
+ def setup_test(self, dut, cert):
+ self.dut_le_acl_manager = PyLeAclManager(dut)
+ self.cert_hci_le_event_stream = EventStream(cert.hci.StreamLeSubevents(empty_proto.Empty()))
+ self.cert_acl_data_stream = EventStream(cert.hci.StreamAcl(empty_proto.Empty()))
+
+ def teardown_test(self):
+ safeClose(self.cert_hci_le_event_stream)
+ safeClose(self.cert_acl_data_stream)
+ safeClose(self.dut_le_acl_manager)
+
+ def set_privacy_policy_static(self):
+ self.dut_address = b'd0:05:04:03:02:01'
+ private_policy = le_initiator_address_facade.PrivacyPolicy(
+ address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
+ address_with_type=common.BluetoothAddressWithType(
+ address=common.BluetoothAddress(address=bytes(self.dut_address)), type=common.RANDOM_DEVICE_ADDRESS))
+ self.dut.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(private_policy)
+
+ def register_for_event(self, event_code):
+ msg = hci_facade.EventRequest(code=int(event_code))
+ self.cert.hci.RequestEvent(msg)
+
+ def register_for_le_event(self, event_code):
+ msg = hci_facade.EventRequest(code=int(event_code))
+ self.cert.hci.RequestLeSubevent(msg)
+
+ def enqueue_hci_command(self, command):
+ cmd_bytes = bytes(command.Serialize())
+ cmd = common.Data(payload=cmd_bytes)
+ self.cert.hci.SendCommand(cmd)
+
+ def enqueue_acl_data(self, handle, pb_flag, b_flag, data):
+ acl = hci_packets.AclBuilder(handle, pb_flag, b_flag, RawBuilder(data))
+ self.cert.hci.SendAcl(common.Data(payload=bytes(acl.Serialize())))
+
+ def dut_connects(self, check_address):
+ self.register_for_le_event(hci_packets.SubeventCode.CONNECTION_COMPLETE)
+ self.register_for_le_event(hci_packets.SubeventCode.ENHANCED_CONNECTION_COMPLETE)
+
+ # Cert Advertises
+ advertising_handle = 0
+ self.enqueue_hci_command(
+ hci_packets.LeSetExtendedAdvertisingLegacyParametersBuilder(
+ advertising_handle,
+ hci_packets.LegacyAdvertisingProperties.ADV_IND,
+ 400,
+ 450,
+ 7,
+ hci_packets.OwnAddressType.RANDOM_DEVICE_ADDRESS,
+ hci_packets.PeerAddressType.PUBLIC_DEVICE_OR_IDENTITY_ADDRESS,
+ '00:00:00:00:00:00',
+ hci_packets.AdvertisingFilterPolicy.ALL_DEVICES,
+ 0xF8,
+ 1, #SID
+ hci_packets.Enable.DISABLED # Scan request notification
+ ))
+
+ self.enqueue_hci_command(
+ hci_packets.LeSetExtendedAdvertisingRandomAddressBuilder(advertising_handle, '0C:05:04:03:02:01'))
+
+ gap_name = hci_packets.GapData()
+ gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
+ gap_name.data = list(bytes(b'Im_A_Cert'))
+
+ self.enqueue_hci_command(
+ hci_packets.LeSetExtendedAdvertisingDataBuilder(
+ advertising_handle, hci_packets.Operation.COMPLETE_ADVERTISEMENT,
+ hci_packets.FragmentPreference.CONTROLLER_SHOULD_NOT, [gap_name]))
+
+ gap_short_name = hci_packets.GapData()
+ gap_short_name.data_type = hci_packets.GapDataType.SHORTENED_LOCAL_NAME
+ gap_short_name.data = list(bytes(b'Im_A_C'))
+
+ self.enqueue_hci_command(
+ hci_packets.LeSetExtendedAdvertisingScanResponseBuilder(
+ advertising_handle, hci_packets.Operation.COMPLETE_ADVERTISEMENT,
+ hci_packets.FragmentPreference.CONTROLLER_SHOULD_NOT, [gap_short_name]))
+
+ enabled_set = hci_packets.EnabledSet()
+ enabled_set.advertising_handle = advertising_handle
+ enabled_set.duration = 0
+ enabled_set.max_extended_advertising_events = 0
+ self.enqueue_hci_command(
+ hci_packets.LeSetExtendedAdvertisingEnableBuilder(hci_packets.Enable.ENABLED, [enabled_set]))
+
+ self.dut_le_acl = self.dut_le_acl_manager.connect_to_remote(
+ remote_addr=common.BluetoothAddressWithType(
+ address=common.BluetoothAddress(address=bytes('0C:05:04:03:02:01', 'utf8')),
+ type=int(hci_packets.AddressType.RANDOM_DEVICE_ADDRESS)))
+
+ # Cert gets ConnectionComplete with a handle and sends ACL data
+ handle = 0xfff
+ address = hci_packets.Address()
+
+ def get_handle(packet):
+ packet_bytes = packet.payload
+ nonlocal handle
+ nonlocal address
+ if b'\x3e\x13\x01\x00' in packet_bytes:
+ cc_view = hci_packets.LeConnectionCompleteView(
+ hci_packets.LeMetaEventView(
+ hci_packets.EventView(bt_packets.PacketViewLittleEndian(list(packet_bytes)))))
+ handle = cc_view.GetConnectionHandle()
+ address = cc_view.GetPeerAddress()
+ return True
+ if b'\x3e\x13\x0A\x00' in packet_bytes:
+ cc_view = hci_packets.LeEnhancedConnectionCompleteView(
+ hci_packets.LeMetaEventView(
+ hci_packets.EventView(bt_packets.PacketViewLittleEndian(list(packet_bytes)))))
+ handle = cc_view.GetConnectionHandle()
+ address = cc_view.GetPeerResolvablePrivateAddress()
+ return True
+ return False
+
+ self.cert_hci_le_event_stream.assert_event_occurs(get_handle)
+ self.cert_handle = handle
+ dut_address_from_complete = address
+ if check_address:
+ assertThat(dut_address_from_complete).isEqualTo(self.dut_address.decode())
+
+ def send_receive_and_check(self):
+ self.enqueue_acl_data(self.cert_handle, hci_packets.PacketBoundaryFlag.FIRST_NON_AUTOMATICALLY_FLUSHABLE,
+ hci_packets.BroadcastFlag.POINT_TO_POINT,
+ bytes(b'\x19\x00\x07\x00SomeAclData from the Cert'))
+
+ self.dut_le_acl.send(b'\x1C\x00\x07\x00SomeMoreAclData from the DUT')
+ self.cert_acl_data_stream.assert_event_occurs(lambda packet: b'SomeMoreAclData' in packet.payload)
+ assertThat(self.dut_le_acl).emits(lambda packet: b'SomeAclData' in packet.payload)
+
+ def test_dut_connects(self):
+ self.set_privacy_policy_static()
+ self.dut_connects(check_address=True)
+ self.send_receive_and_check()
+
+ def test_dut_connects_resolvable_address(self):
+ privacy_policy = le_initiator_address_facade.PrivacyPolicy(
+ address_policy=le_initiator_address_facade.AddressPolicy.USE_RESOLVABLE_ADDRESS,
+ rotation_irk=b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f',
+ minimum_rotation_time=7 * 60 * 1000,
+ maximum_rotation_time=15 * 60 * 1000)
+ self.dut.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(privacy_policy)
+ self.dut_connects(check_address=False)
+ self.send_receive_and_check()
+
+ def test_dut_connects_non_resolvable_address(self):
+ privacy_policy = le_initiator_address_facade.PrivacyPolicy(
+ address_policy=le_initiator_address_facade.AddressPolicy.USE_NON_RESOLVABLE_ADDRESS,
+ rotation_irk=b'\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f',
+ minimum_rotation_time=8 * 60 * 1000,
+ maximum_rotation_time=14 * 60 * 1000)
+ self.dut.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(privacy_policy)
+ self.dut_connects(check_address=False)
+ self.send_receive_and_check()
+
+ def test_dut_connects_public_address(self):
+ self.dut.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(
+ le_initiator_address_facade.PrivacyPolicy(
+ address_policy=le_initiator_address_facade.AddressPolicy.USE_PUBLIC_ADDRESS))
+ self.dut_connects(check_address=False)
+ self.send_receive_and_check()
+
+ def test_dut_connects_public_address_cancelled(self):
+ self.dut.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(
+ le_initiator_address_facade.PrivacyPolicy(
+ address_policy=le_initiator_address_facade.AddressPolicy.USE_PUBLIC_ADDRESS))
+ self.dut_connects(check_address=False)
+ self.send_receive_and_check()
+
+ def test_cert_connects(self):
+ self.set_privacy_policy_static()
+ self.register_for_le_event(hci_packets.SubeventCode.CONNECTION_COMPLETE)
+
+ self.dut_le_acl_manager.listen_for_incoming_connections()
+
+ # DUT Advertises
+ gap_name = hci_packets.GapData()
+ gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
+ gap_name.data = list(bytes(b'Im_The_DUT'))
+ gap_data = le_advertising_facade.GapDataMsg(data=bytes(gap_name.Serialize()))
+ config = le_advertising_facade.AdvertisingConfig(
+ advertisement=[gap_data],
+ interval_min=512,
+ interval_max=768,
+ advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
+ own_address_type=common.USE_RANDOM_DEVICE_ADDRESS,
+ peer_address_type=common.PUBLIC_DEVICE_OR_IDENTITY_ADDRESS,
+ peer_address=common.BluetoothAddress(address=bytes(b'A6:A5:A4:A3:A2:A1')),
+ channel_map=7,
+ filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
+ request = le_advertising_facade.CreateAdvertiserRequest(config=config)
+
+ self.dut.hci_le_advertising_manager.CreateAdvertiser(request)
+
+ # Cert Connects
+ self.enqueue_hci_command(hci_packets.LeSetRandomAddressBuilder('0C:05:04:03:02:01'))
+ phy_scan_params = hci_packets.LeCreateConnPhyScanParameters()
+ phy_scan_params.scan_interval = 0x60
+ phy_scan_params.scan_window = 0x30
+ phy_scan_params.conn_interval_min = 0x18
+ phy_scan_params.conn_interval_max = 0x28
+ phy_scan_params.conn_latency = 0
+ phy_scan_params.supervision_timeout = 0x1f4
+ phy_scan_params.min_ce_length = 0
+ phy_scan_params.max_ce_length = 0
+ self.enqueue_hci_command(
+ hci_packets.LeExtendedCreateConnectionBuilder(hci_packets.InitiatorFilterPolicy.USE_PEER_ADDRESS,
+ hci_packets.OwnAddressType.RANDOM_DEVICE_ADDRESS,
+ hci_packets.AddressType.RANDOM_DEVICE_ADDRESS,
+ self.dut_address.decode(), 1, [phy_scan_params]))
+
+ # Cert gets ConnectionComplete with a handle and sends ACL data
+ handle = 0xfff
+
+ def get_handle(packet):
+ packet_bytes = packet.payload
+ nonlocal handle
+ if b'\x3e\x13\x01\x00' in packet_bytes:
+ cc_view = hci_packets.LeConnectionCompleteView(
+ hci_packets.LeMetaEventView(
+ hci_packets.EventView(bt_packets.PacketViewLittleEndian(list(packet_bytes)))))
+ handle = cc_view.GetConnectionHandle()
+ return True
+ if b'\x3e\x13\x0A\x00' in packet_bytes:
+ cc_view = hci_packets.LeEnhancedConnectionCompleteView(
+ hci_packets.LeMetaEventView(
+ hci_packets.EventView(bt_packets.PacketViewLittleEndian(list(packet_bytes)))))
+ handle = cc_view.GetConnectionHandle()
+ return True
+ return False
+
+ self.cert_hci_le_event_stream.assert_event_occurs(get_handle)
+ self.cert_handle = handle
+
+ self.enqueue_acl_data(self.cert_handle, hci_packets.PacketBoundaryFlag.FIRST_NON_AUTOMATICALLY_FLUSHABLE,
+ hci_packets.BroadcastFlag.POINT_TO_POINT,
+ bytes(b'\x19\x00\x07\x00SomeAclData from the Cert'))
+
+ # DUT gets a connection complete event and sends and receives
+ handle = 0xfff
+ self.dut_le_acl = self.dut_le_acl_manager.complete_incoming_connection()
+
+ self.send_receive_and_check()
+
+ def test_recombination_l2cap_packet(self):
+ self.set_privacy_policy_static()
+ self.dut_connects(check_address=True)
+
+ self.enqueue_acl_data(self.cert_handle, hci_packets.PacketBoundaryFlag.FIRST_NON_AUTOMATICALLY_FLUSHABLE,
+ hci_packets.BroadcastFlag.POINT_TO_POINT, bytes(b'\x06\x00\x07\x00Hello'))
+ self.enqueue_acl_data(self.cert_handle, hci_packets.PacketBoundaryFlag.CONTINUING_FRAGMENT,
+ hci_packets.BroadcastFlag.POINT_TO_POINT, bytes(b'!'))
+
+ assertThat(self.dut_le_acl).emits(lambda packet: b'Hello!' in packet.payload)
diff --git a/gd/hci/cert/le_advertising_manager_test.py b/gd/hci/cert/le_advertising_manager_test.py
index aef3710..40a56ad 100644
--- a/gd/hci/cert/le_advertising_manager_test.py
+++ b/gd/hci/cert/le_advertising_manager_test.py
@@ -14,74 +14,19 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import os
-import sys
-import logging
-
from cert.gd_base_test import GdBaseTestClass
-from cert.event_stream import EventStream
-from google.protobuf import empty_pb2 as empty_proto
-from facade import rootservice_pb2 as facade_rootservice
-from hci.facade import hci_facade_pb2 as hci_facade
-from hci.facade import \
- le_advertising_manager_facade_pb2 as le_advertising_facade
-from bluetooth_packets_python3 import hci_packets
-from facade import common_pb2 as common
-from cert.py_hci import PyHci
-from cert.truth import assertThat
+from hci.cert.le_advertising_manager_test_lib import LeAdvertisingManagerTestBase
-class LeAdvertisingManagerTest(GdBaseTestClass):
+class LeAdvertisingManagerTest(GdBaseTestClass, LeAdvertisingManagerTestBase):
def setup_class(self):
- super().setup_class(dut_module='HCI_INTERFACES', cert_module='HCI')
+ GdBaseTestClass.setup_class(self, dut_module='HCI_INTERFACES', cert_module='HCI')
def setup_test(self):
- super().setup_test()
- self.cert_hci = PyHci(self.cert, acl_streaming=True)
+ GdBaseTestClass.setup_test(self)
+ LeAdvertisingManagerTestBase.setup_test(self, self.cert)
def teardown_test(self):
- self.cert_hci.close()
- super().teardown_test()
-
- def test_le_ad_scan_dut_advertises(self):
- self.cert_hci.register_for_le_events(hci_packets.SubeventCode.ADVERTISING_REPORT,
- hci_packets.SubeventCode.EXTENDED_ADVERTISING_REPORT)
-
- # CERT Scans
- self.cert_hci.send_command(hci_packets.LeSetRandomAddressBuilder('0C:05:04:03:02:01'))
- scan_parameters = hci_packets.PhyScanParameters()
- scan_parameters.le_scan_type = hci_packets.LeScanType.ACTIVE
- scan_parameters.le_scan_interval = 40
- scan_parameters.le_scan_window = 20
- self.cert_hci.send_command(
- hci_packets.LeSetExtendedScanParametersBuilder(hci_packets.OwnAddressType.RANDOM_DEVICE_ADDRESS,
- hci_packets.LeScanningFilterPolicy.ACCEPT_ALL, 1,
- [scan_parameters]))
- self.cert_hci.send_command(
- hci_packets.LeSetExtendedScanEnableBuilder(hci_packets.Enable.ENABLED,
- hci_packets.FilterDuplicates.DISABLED, 0, 0))
-
- # DUT Advertises
- gap_name = hci_packets.GapData()
- gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
- gap_name.data = list(bytes(b'Im_The_DUT'))
- gap_data = le_advertising_facade.GapDataMsg(data=bytes(gap_name.Serialize()))
- config = le_advertising_facade.AdvertisingConfig(
- advertisement=[gap_data],
- interval_min=512,
- interval_max=768,
- advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
- own_address_type=common.USE_RANDOM_DEVICE_ADDRESS,
- channel_map=7,
- filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
- request = le_advertising_facade.CreateAdvertiserRequest(config=config)
-
- create_response = self.dut.hci_le_advertising_manager.CreateAdvertiser(request)
-
- assertThat(self.cert_hci.get_le_event_stream()).emits(lambda packet: b'Im_The_DUT' in packet.payload)
-
- remove_request = le_advertising_facade.RemoveAdvertiserRequest(advertiser_id=create_response.advertiser_id)
- self.dut.hci_le_advertising_manager.RemoveAdvertiser(remove_request)
- self.cert_hci.send_command(
- hci_packets.LeSetScanEnableBuilder(hci_packets.Enable.DISABLED, hci_packets.Enable.DISABLED))
+ LeAdvertisingManagerTestBase.teardown_test(self)
+ GdBaseTestClass.teardown_test(self)
diff --git a/gd/hci/cert/le_advertising_manager_test_lib.py b/gd/hci/cert/le_advertising_manager_test_lib.py
new file mode 100644
index 0000000..eee1c9c
--- /dev/null
+++ b/gd/hci/cert/le_advertising_manager_test_lib.py
@@ -0,0 +1,81 @@
+#!/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 os
+import sys
+import logging
+
+from cert.event_stream import EventStream
+from google.protobuf import empty_pb2 as empty_proto
+from facade import rootservice_pb2 as facade_rootservice
+from hci.facade import hci_facade_pb2 as hci_facade
+from hci.facade import \
+ le_advertising_manager_facade_pb2 as le_advertising_facade
+from bluetooth_packets_python3 import hci_packets
+from facade import common_pb2 as common
+from cert.py_hci import PyHci
+from cert.truth import assertThat
+
+
+class LeAdvertisingManagerTestBase():
+
+ def setup_test(self, cert):
+ self.cert_hci = PyHci(cert, acl_streaming=True)
+
+ def teardown_test(self):
+ self.cert_hci.close()
+
+ def test_le_ad_scan_dut_advertises(self):
+ self.cert_hci.register_for_le_events(hci_packets.SubeventCode.ADVERTISING_REPORT,
+ hci_packets.SubeventCode.EXTENDED_ADVERTISING_REPORT)
+
+ # CERT Scans
+ self.cert_hci.send_command(hci_packets.LeSetRandomAddressBuilder('0C:05:04:03:02:01'))
+ scan_parameters = hci_packets.PhyScanParameters()
+ scan_parameters.le_scan_type = hci_packets.LeScanType.ACTIVE
+ scan_parameters.le_scan_interval = 40
+ scan_parameters.le_scan_window = 20
+ self.cert_hci.send_command(
+ hci_packets.LeSetExtendedScanParametersBuilder(hci_packets.OwnAddressType.RANDOM_DEVICE_ADDRESS,
+ hci_packets.LeScanningFilterPolicy.ACCEPT_ALL, 1,
+ [scan_parameters]))
+ self.cert_hci.send_command(
+ hci_packets.LeSetExtendedScanEnableBuilder(hci_packets.Enable.ENABLED,
+ hci_packets.FilterDuplicates.DISABLED, 0, 0))
+
+ # DUT Advertises
+ gap_name = hci_packets.GapData()
+ gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
+ gap_name.data = list(bytes(b'Im_The_DUT'))
+ gap_data = le_advertising_facade.GapDataMsg(data=bytes(gap_name.Serialize()))
+ config = le_advertising_facade.AdvertisingConfig(
+ advertisement=[gap_data],
+ interval_min=512,
+ interval_max=768,
+ advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
+ own_address_type=common.USE_RANDOM_DEVICE_ADDRESS,
+ channel_map=7,
+ filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
+ request = le_advertising_facade.CreateAdvertiserRequest(config=config)
+
+ create_response = self.dut.hci_le_advertising_manager.CreateAdvertiser(request)
+
+ assertThat(self.cert_hci.get_le_event_stream()).emits(lambda packet: b'Im_The_DUT' in packet.payload)
+
+ remove_request = le_advertising_facade.RemoveAdvertiserRequest(advertiser_id=create_response.advertiser_id)
+ self.dut.hci_le_advertising_manager.RemoveAdvertiser(remove_request)
+ self.cert_hci.send_command(
+ hci_packets.LeSetScanEnableBuilder(hci_packets.Enable.DISABLED, hci_packets.Enable.DISABLED))
diff --git a/gd/hci/cert/le_scanning_manager_test.py b/gd/hci/cert/le_scanning_manager_test.py
index b91118e..d9c7e64 100644
--- a/gd/hci/cert/le_scanning_manager_test.py
+++ b/gd/hci/cert/le_scanning_manager_test.py
@@ -14,84 +14,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import os
-import sys
-import logging
-
from cert.gd_base_test import GdBaseTestClass
-from cert.event_stream import EventStream
-from google.protobuf import empty_pb2 as empty_proto
-from facade import rootservice_pb2 as facade_rootservice
-from hci.facade import hci_facade_pb2 as hci_facade
-from hci.facade import le_scanning_manager_facade_pb2 as le_scanning_facade
-from hci.facade import le_advertising_manager_facade_pb2 as le_advertising_facade
-from hci.facade import le_initiator_address_facade_pb2 as le_initiator_address_facade
-from bluetooth_packets_python3 import hci_packets
-from facade import common_pb2 as common
+from hci.cert.le_scanning_manager_test_lib import LeScanningManagerTestBase
-class LeScanningManagerTest(GdBaseTestClass):
+class LeScanningManagerTest(GdBaseTestClass, LeScanningManagerTestBase):
def setup_class(self):
- super().setup_class(dut_module='HCI_INTERFACES', cert_module='HCI_INTERFACES')
-
- def register_for_event(self, event_code):
- msg = hci_facade.EventCodeMsg(code=int(event_code))
- self.cert.hci.RegisterEventHandler(msg)
-
- def register_for_le_event(self, event_code):
- msg = hci_facade.LeSubeventCodeMsg(code=int(event_code))
- self.cert.hci.RegisterLeEventHandler(msg)
-
- def enqueue_hci_command(self, command, expect_complete):
- cmd_bytes = bytes(command.Serialize())
- cmd = common.Data(payload=cmd_bytes)
- if (expect_complete):
- self.cert.hci.EnqueueCommandWithComplete(cmd)
- else:
- self.cert.hci.EnqueueCommandWithStatus(cmd)
-
- def test_le_ad_scan_dut_scans(self):
- privacy_policy = le_initiator_address_facade.PrivacyPolicy(
- address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
- address_with_type=common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=bytes(b'D0:05:04:03:02:01')),
- type=common.RANDOM_DEVICE_ADDRESS),
- rotation_irk=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
- minimum_rotation_time=0,
- maximum_rotation_time=0)
- self.dut.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(privacy_policy)
- cert_privacy_policy = le_initiator_address_facade.PrivacyPolicy(
- address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
- address_with_type=common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=bytes(b'C0:05:04:03:02:01')),
- type=common.RANDOM_DEVICE_ADDRESS),
- rotation_irk=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
- minimum_rotation_time=0,
- maximum_rotation_time=0)
- self.cert.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(cert_privacy_policy)
- with EventStream(
- # DUT Scans
- self.dut.hci_le_scanning_manager.StartScan(empty_proto.Empty())) as advertising_event_stream:
-
- # CERT Advertises
- gap_name = hci_packets.GapData()
- gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
- gap_name.data = list(bytes(b'Im_The_CERT!'))
- gap_data = le_advertising_facade.GapDataMsg(data=bytes(gap_name.Serialize()))
- config = le_advertising_facade.AdvertisingConfig(
- advertisement=[gap_data],
- interval_min=512,
- interval_max=768,
- advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
- own_address_type=common.USE_RANDOM_DEVICE_ADDRESS,
- channel_map=7,
- filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
- request = le_advertising_facade.CreateAdvertiserRequest(config=config)
-
- create_response = self.cert.hci_le_advertising_manager.CreateAdvertiser(request)
-
- advertising_event_stream.assert_event_occurs(lambda packet: b'Im_The_CERT' in packet.event)
-
- remove_request = le_advertising_facade.RemoveAdvertiserRequest(advertiser_id=create_response.advertiser_id)
- self.cert.hci_le_advertising_manager.RemoveAdvertiser(remove_request)
+ GdBaseTestClass.setup_class(self, dut_module='HCI_INTERFACES', cert_module='HCI_INTERFACES')
diff --git a/gd/hci/cert/le_scanning_manager_test_lib.py b/gd/hci/cert/le_scanning_manager_test_lib.py
new file mode 100644
index 0000000..642e41c
--- /dev/null
+++ b/gd/hci/cert/le_scanning_manager_test_lib.py
@@ -0,0 +1,93 @@
+#!/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 os
+import sys
+import logging
+
+from cert.event_stream import EventStream
+from google.protobuf import empty_pb2 as empty_proto
+from facade import rootservice_pb2 as facade_rootservice
+from hci.facade import hci_facade_pb2 as hci_facade
+from hci.facade import le_scanning_manager_facade_pb2 as le_scanning_facade
+from hci.facade import le_advertising_manager_facade_pb2 as le_advertising_facade
+from hci.facade import le_initiator_address_facade_pb2 as le_initiator_address_facade
+from bluetooth_packets_python3 import hci_packets
+from facade import common_pb2 as common
+
+
+class LeScanningManagerTestBase():
+
+ def register_for_event(self, event_code):
+ msg = hci_facade.EventCodeMsg(code=int(event_code))
+ self.cert.hci.RegisterEventHandler(msg)
+
+ def register_for_le_event(self, event_code):
+ msg = hci_facade.LeSubeventCodeMsg(code=int(event_code))
+ self.cert.hci.RegisterLeEventHandler(msg)
+
+ def enqueue_hci_command(self, command, expect_complete):
+ cmd_bytes = bytes(command.Serialize())
+ cmd = common.Data(payload=cmd_bytes)
+ if (expect_complete):
+ self.cert.hci.EnqueueCommandWithComplete(cmd)
+ else:
+ self.cert.hci.EnqueueCommandWithStatus(cmd)
+
+ def test_le_ad_scan_dut_scans(self):
+ privacy_policy = le_initiator_address_facade.PrivacyPolicy(
+ address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
+ address_with_type=common.BluetoothAddressWithType(
+ address=common.BluetoothAddress(address=bytes(b'D0:05:04:03:02:01')),
+ type=common.RANDOM_DEVICE_ADDRESS),
+ rotation_irk=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
+ minimum_rotation_time=0,
+ maximum_rotation_time=0)
+ self.dut.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(privacy_policy)
+ cert_privacy_policy = le_initiator_address_facade.PrivacyPolicy(
+ address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
+ address_with_type=common.BluetoothAddressWithType(
+ address=common.BluetoothAddress(address=bytes(b'C0:05:04:03:02:01')),
+ type=common.RANDOM_DEVICE_ADDRESS),
+ rotation_irk=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
+ minimum_rotation_time=0,
+ maximum_rotation_time=0)
+ self.cert.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(cert_privacy_policy)
+ with EventStream(
+ # DUT Scans
+ self.dut.hci_le_scanning_manager.StartScan(empty_proto.Empty())) as advertising_event_stream:
+
+ # CERT Advertises
+ gap_name = hci_packets.GapData()
+ gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
+ gap_name.data = list(bytes(b'Im_The_CERT!'))
+ gap_data = le_advertising_facade.GapDataMsg(data=bytes(gap_name.Serialize()))
+ config = le_advertising_facade.AdvertisingConfig(
+ advertisement=[gap_data],
+ interval_min=512,
+ interval_max=768,
+ advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
+ own_address_type=common.USE_RANDOM_DEVICE_ADDRESS,
+ channel_map=7,
+ filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
+ request = le_advertising_facade.CreateAdvertiserRequest(config=config)
+
+ create_response = self.cert.hci_le_advertising_manager.CreateAdvertiser(request)
+
+ advertising_event_stream.assert_event_occurs(lambda packet: b'Im_The_CERT' in packet.event)
+
+ remove_request = le_advertising_facade.RemoveAdvertiserRequest(advertiser_id=create_response.advertiser_id)
+ self.cert.hci_le_advertising_manager.RemoveAdvertiser(remove_request)
diff --git a/gd/hci/cert/le_scanning_with_security_test.py b/gd/hci/cert/le_scanning_with_security_test.py
index e481357..c5e1cf2 100644
--- a/gd/hci/cert/le_scanning_with_security_test.py
+++ b/gd/hci/cert/le_scanning_with_security_test.py
@@ -15,72 +15,10 @@
# limitations under the License.
from cert.gd_base_test import GdBaseTestClass
-from cert.event_stream import EventStream
-from cert.truth import assertThat
-from google.protobuf import empty_pb2 as empty_proto
-from hci.facade import hci_facade_pb2 as hci_facade
-from hci.facade import le_advertising_manager_facade_pb2 as le_advertising_facade
-from hci.facade import le_initiator_address_facade_pb2 as le_initiator_address_facade
-from bluetooth_packets_python3 import hci_packets
-from facade import common_pb2 as common
+from hci.cert.le_scanning_with_security_test_lib import LeScanningWithSecurityTestBase
-class LeScanningWithSecurityTest(GdBaseTestClass):
+class LeScanningWithSecurityTest(GdBaseTestClass, LeScanningWithSecurityTestBase):
def setup_class(self):
- super().setup_class(dut_module='SECURITY', cert_module='HCI_INTERFACES')
-
- def register_for_event(self, event_code):
- msg = hci_facade.EventCodeMsg(code=int(event_code))
- self.cert.hci.RegisterEventHandler(msg)
-
- def register_for_le_event(self, event_code):
- msg = hci_facade.LeSubeventCodeMsg(code=int(event_code))
- self.cert.hci.RegisterLeEventHandler(msg)
-
- def enqueue_hci_command(self, command, expect_complete):
- cmd_bytes = bytes(command.Serialize())
- cmd = common.Data(command=cmd_bytes)
- if (expect_complete):
- self.cert.hci.EnqueueCommandWithComplete(cmd)
- else:
- self.cert.hci.EnqueueCommandWithStatus(cmd)
-
- def test_le_ad_scan_dut_scans(self):
- """
- Verify that the IUT address policy is correctly initiated by SecurityManager, and we can start a scan.
- """
- cert_privacy_policy = le_initiator_address_facade.PrivacyPolicy(
- address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
- address_with_type=common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=bytes(b'C0:05:04:03:02:01')),
- type=common.RANDOM_DEVICE_ADDRESS),
- rotation_irk=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
- minimum_rotation_time=0,
- maximum_rotation_time=0)
- self.cert.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(cert_privacy_policy)
- with EventStream(
- # DUT Scans
- self.dut.hci_le_scanning_manager.StartScan(empty_proto.Empty())) as advertising_event_stream:
-
- # CERT Advertises
- gap_name = hci_packets.GapData()
- gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
- gap_name.data = list(bytes(b'Im_The_CERT!'))
- gap_data = le_advertising_facade.GapDataMsg(data=bytes(gap_name.Serialize()))
- config = le_advertising_facade.AdvertisingConfig(
- advertisement=[gap_data],
- interval_min=512,
- interval_max=768,
- advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
- own_address_type=common.USE_RANDOM_DEVICE_ADDRESS,
- channel_map=7,
- filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
- request = le_advertising_facade.CreateAdvertiserRequest(config=config)
-
- create_response = self.cert.hci_le_advertising_manager.CreateAdvertiser(request)
-
- assertThat(advertising_event_stream).emits(lambda packet: b'Im_The_CERT' in packet.event)
-
- remove_request = le_advertising_facade.RemoveAdvertiserRequest(advertiser_id=create_response.advertiser_id)
- self.cert.hci_le_advertising_manager.RemoveAdvertiser(remove_request)
+ GdBaseTestClass.setup_class(self, dut_module='SECURITY', cert_module='HCI_INTERFACES')
diff --git a/gd/hci/cert/le_scanning_with_security_test_lib.py b/gd/hci/cert/le_scanning_with_security_test_lib.py
new file mode 100644
index 0000000..4e1eef3
--- /dev/null
+++ b/gd/hci/cert/le_scanning_with_security_test_lib.py
@@ -0,0 +1,82 @@
+#!/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 cert.event_stream import EventStream
+from cert.truth import assertThat
+from google.protobuf import empty_pb2 as empty_proto
+from hci.facade import hci_facade_pb2 as hci_facade
+from hci.facade import le_advertising_manager_facade_pb2 as le_advertising_facade
+from hci.facade import le_initiator_address_facade_pb2 as le_initiator_address_facade
+from bluetooth_packets_python3 import hci_packets
+from facade import common_pb2 as common
+
+
+class LeScanningWithSecurityTestBase():
+
+ def register_for_event(self, event_code):
+ msg = hci_facade.EventCodeMsg(code=int(event_code))
+ self.cert.hci.RegisterEventHandler(msg)
+
+ def register_for_le_event(self, event_code):
+ msg = hci_facade.LeSubeventCodeMsg(code=int(event_code))
+ self.cert.hci.RegisterLeEventHandler(msg)
+
+ def enqueue_hci_command(self, command, expect_complete):
+ cmd_bytes = bytes(command.Serialize())
+ cmd = common.Data(command=cmd_bytes)
+ if (expect_complete):
+ self.cert.hci.EnqueueCommandWithComplete(cmd)
+ else:
+ self.cert.hci.EnqueueCommandWithStatus(cmd)
+
+ def test_le_ad_scan_dut_scans(self):
+ """
+ Verify that the IUT address policy is correctly initiated by SecurityManager, and we can start a scan.
+ """
+ cert_privacy_policy = le_initiator_address_facade.PrivacyPolicy(
+ address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
+ address_with_type=common.BluetoothAddressWithType(
+ address=common.BluetoothAddress(address=bytes(b'C0:05:04:03:02:01')),
+ type=common.RANDOM_DEVICE_ADDRESS),
+ rotation_irk=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
+ minimum_rotation_time=0,
+ maximum_rotation_time=0)
+ self.cert.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(cert_privacy_policy)
+ with EventStream(
+ # DUT Scans
+ self.dut.hci_le_scanning_manager.StartScan(empty_proto.Empty())) as advertising_event_stream:
+
+ # CERT Advertises
+ gap_name = hci_packets.GapData()
+ gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
+ gap_name.data = list(bytes(b'Im_The_CERT!'))
+ gap_data = le_advertising_facade.GapDataMsg(data=bytes(gap_name.Serialize()))
+ config = le_advertising_facade.AdvertisingConfig(
+ advertisement=[gap_data],
+ interval_min=512,
+ interval_max=768,
+ advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
+ own_address_type=common.USE_RANDOM_DEVICE_ADDRESS,
+ channel_map=7,
+ filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
+ request = le_advertising_facade.CreateAdvertiserRequest(config=config)
+
+ create_response = self.cert.hci_le_advertising_manager.CreateAdvertiser(request)
+
+ assertThat(advertising_event_stream).emits(lambda packet: b'Im_The_CERT' in packet.event)
+
+ remove_request = le_advertising_facade.RemoveAdvertiserRequest(advertiser_id=create_response.advertiser_id)
+ self.cert.hci_le_advertising_manager.RemoveAdvertiser(remove_request)
diff --git a/gd/hci/controller.cc b/gd/hci/controller.cc
index 623a0be..cc5c760 100644
--- a/gd/hci/controller.cc
+++ b/gd/hci/controller.cc
@@ -43,10 +43,6 @@
le_set_event_mask(kDefaultLeEventMask);
set_event_mask(kDefaultEventMask);
write_le_host_support(Enable::ENABLED);
- // SSP is managed by security layer once enabled
- if (!common::init_flags::gd_security_is_enabled()) {
- write_simple_pairing_mode(Enable::ENABLED);
- }
hci_->EnqueueCommand(ReadLocalNameBuilder::Create(),
handler->BindOnceOn(this, &Controller::impl::read_local_name_complete_handler));
hci_->EnqueueCommand(ReadLocalVersionInformationBuilder::Create(),
@@ -54,6 +50,14 @@
hci_->EnqueueCommand(ReadLocalSupportedCommandsBuilder::Create(),
handler->BindOnceOn(this, &Controller::impl::read_local_supported_commands_complete_handler));
+ hci_->EnqueueCommand(
+ LeReadLocalSupportedFeaturesBuilder::Create(),
+ handler->BindOnceOn(this, &Controller::impl::le_read_local_supported_features_handler));
+
+ hci_->EnqueueCommand(
+ LeReadSupportedStatesBuilder::Create(),
+ handler->BindOnceOn(this, &Controller::impl::le_read_supported_states_handler));
+
// Wait for all extended features read
std::promise<void> features_promise;
auto features_future = features_promise.get_future();
@@ -75,52 +79,79 @@
handler->BindOnceOn(this, &Controller::impl::le_read_buffer_size_handler));
}
- hci_->EnqueueCommand(LeReadLocalSupportedFeaturesBuilder::Create(),
- handler->BindOnceOn(this, &Controller::impl::le_read_local_supported_features_handler));
-
- hci_->EnqueueCommand(LeReadSupportedStatesBuilder::Create(),
- handler->BindOnceOn(this, &Controller::impl::le_read_supported_states_handler));
-
hci_->EnqueueCommand(
LeReadConnectListSizeBuilder::Create(),
handler->BindOnceOn(this, &Controller::impl::le_read_connect_list_size_handler));
- hci_->EnqueueCommand(
- LeReadResolvingListSizeBuilder::Create(),
- handler->BindOnceOn(this, &Controller::impl::le_read_resolving_list_size_handler));
+ if (is_supported(OpCode::LE_READ_RESOLVING_LIST_SIZE) && module_.SupportsBlePrivacy()) {
+ hci_->EnqueueCommand(
+ LeReadResolvingListSizeBuilder::Create(),
+ handler->BindOnceOn(this, &Controller::impl::le_read_resolving_list_size_handler));
+ } else {
+ LOG_INFO("LE_READ_RESOLVING_LIST_SIZE not supported, defaulting to 0");
+ le_resolving_list_size_ = 0;
+ }
- if (is_supported(OpCode::LE_READ_MAXIMUM_DATA_LENGTH)) {
+ if (is_supported(OpCode::LE_READ_MAXIMUM_DATA_LENGTH) && module_.SupportsBlePacketExtension()) {
hci_->EnqueueCommand(LeReadMaximumDataLengthBuilder::Create(),
handler->BindOnceOn(this, &Controller::impl::le_read_maximum_data_length_handler));
} else {
+ LOG_INFO("LE_READ_MAXIMUM_DATA_LENGTH not supported, defaulting to 0");
le_maximum_data_length_.supported_max_rx_octets_ = 0;
le_maximum_data_length_.supported_max_rx_time_ = 0;
le_maximum_data_length_.supported_max_tx_octets_ = 0;
le_maximum_data_length_.supported_max_tx_time_ = 0;
}
- if (is_supported(OpCode::LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH)) {
+
+ // SSP is managed by security layer once enabled
+ if (!common::init_flags::gd_security_is_enabled()) {
+ write_simple_pairing_mode(Enable::ENABLED);
+ if (module_.SupportsSecureConnections()) {
+ hci_->EnqueueCommand(
+ WriteSecureConnectionsHostSupportBuilder::Create(Enable::ENABLED),
+ handler->BindOnceOn(this, &Controller::impl::write_secure_connections_host_support_complete_handler));
+ }
+ }
+ if (is_supported(OpCode::LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH) && module_.SupportsBlePacketExtension()) {
hci_->EnqueueCommand(
LeReadSuggestedDefaultDataLengthBuilder::Create(),
handler->BindOnceOn(this, &Controller::impl::le_read_suggested_default_data_length_handler));
+ } else {
+ LOG_INFO("LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH not supported, defaulting to 27 (0x1B)");
+ le_suggested_default_data_length_ = 27;
}
- if (is_supported(OpCode::LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH)) {
+
+ if (is_supported(OpCode::LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH) && module_.SupportsBleExtendedAdvertising()) {
hci_->EnqueueCommand(
LeReadMaximumAdvertisingDataLengthBuilder::Create(),
handler->BindOnceOn(this, &Controller::impl::le_read_maximum_advertising_data_length_handler));
} else {
+ LOG_INFO("LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH not supported, defaulting to 31 (0x1F)");
le_maximum_advertising_data_length_ = 31;
}
- if (is_supported(OpCode::LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS)) {
+
+ if (is_supported(OpCode::LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS) &&
+ module_.SupportsBleExtendedAdvertising()) {
hci_->EnqueueCommand(
LeReadNumberOfSupportedAdvertisingSetsBuilder::Create(),
handler->BindOnceOn(this, &Controller::impl::le_read_number_of_supported_advertising_sets_handler));
} else {
+ LOG_INFO("LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS not supported, defaulting to 1");
le_number_supported_advertising_sets_ = 1;
}
- if (is_supported(OpCode::LE_READ_PERIODIC_ADVERTISING_LIST_SIZE)) {
+
+ if (is_supported(OpCode::LE_READ_PERIODIC_ADVERTISING_LIST_SIZE) && module_.SupportsBlePeriodicAdvertising()) {
hci_->EnqueueCommand(
LeReadPeriodicAdvertiserListSizeBuilder::Create(),
handler->BindOnceOn(this, &Controller::impl::le_read_periodic_advertiser_list_size_handler));
+ } else {
+ LOG_INFO("LE_READ_PERIODIC_ADVERTISING_LIST_SIZE not supported, defaulting to 0");
+ le_periodic_advertiser_list_size_ = 0;
+ }
+ if (is_supported(OpCode::LE_SET_HOST_FEATURE)) {
+ hci_->EnqueueCommand(
+ LeSetHostFeatureBuilder::Create(LeHostFeatureBits::CONNECTED_ISO_STREAM_HOST_SUPPORT, Enable::ENABLED),
+ handler->BindOnceOn(this, &Controller::impl::le_set_host_feature_handler));
}
hci_->EnqueueCommand(LeGetVendorCapabilitiesBuilder::Create(),
@@ -189,6 +220,13 @@
acl_monitor_credits_callback_ = {};
}
+ void write_secure_connections_host_support_complete_handler(CommandCompleteView view) {
+ auto complete_view = WriteSecureConnectionsHostSupportCompleteView::Create(view);
+ ASSERT(complete_view.IsValid());
+ ErrorCode status = complete_view.GetStatus();
+ ASSERT_LOG(status == ErrorCode::SUCCESS, "Status 0x%02hhx, %s", status, ErrorCodeText(status).c_str());
+ }
+
void read_local_name_complete_handler(CommandCompleteView view) {
auto complete_view = ReadLocalNameCompleteView::Create(view);
ASSERT(complete_view.IsValid());
@@ -293,6 +331,13 @@
}
}
+ void le_set_host_feature_handler(CommandCompleteView view) {
+ auto complete_view = LeSetHostFeatureCompleteView::Create(view);
+ ASSERT(complete_view.IsValid());
+ ErrorCode status = complete_view.GetStatus();
+ ASSERT_LOG(status == ErrorCode::SUCCESS, "Status 0x%02hhx, %s", status, ErrorCodeText(status).c_str());
+ }
+
void le_read_local_supported_features_handler(CommandCompleteView view) {
auto complete_view = LeReadLocalSupportedFeaturesCompleteView::Create(view);
ASSERT(complete_view.IsValid());
@@ -645,6 +690,7 @@
OP_CODE_MAPPING(WRITE_SIMPLE_PAIRING_DEBUG_MODE)
OP_CODE_MAPPING(REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY)
OP_CODE_MAPPING(SEND_KEYPRESS_NOTIFICATION)
+ OP_CODE_MAPPING(SET_EVENT_MASK_PAGE_2)
OP_CODE_MAPPING(IO_CAPABILITY_REQUEST_NEGATIVE_REPLY)
OP_CODE_MAPPING(REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY)
OP_CODE_MAPPING(READ_ENCRYPTION_KEY_SIZE)
diff --git a/gd/hci/controller.h b/gd/hci/controller.h
index e2cb9a3..7a4d1c3 100644
--- a/gd/hci/controller.h
+++ b/gd/hci/controller.h
@@ -159,7 +159,7 @@
static const ModuleFactory Factory;
static constexpr uint64_t kDefaultEventMask = 0x3dbfffffffffffff;
- static constexpr uint64_t kDefaultLeEventMask = 0x0000000000021e7f;
+ static constexpr uint64_t kDefaultLeEventMask = 0x0000000041021e7f;
protected:
void ListDependencies(ModuleList* list) override;
diff --git a/gd/hci/controller_test.cc b/gd/hci/controller_test.cc
index c4da73c..75f6db1 100644
--- a/gd/hci/controller_test.cc
+++ b/gd/hci/controller_test.cc
@@ -307,7 +307,9 @@
ASSERT_EQ(controller_->GetLeBufferSize().total_num_le_packets_, 0x08);
ASSERT_EQ(controller_->GetLeSupportedStates(), 0x001f123456789abe);
ASSERT_EQ(controller_->GetLeMaximumDataLength().supported_max_tx_octets_, 0x12);
+ ASSERT_EQ(controller_->GetLeMaximumDataLength().supported_max_tx_time_, 0x34);
ASSERT_EQ(controller_->GetLeMaximumDataLength().supported_max_rx_octets_, 0x56);
+ ASSERT_EQ(controller_->GetLeMaximumDataLength().supported_max_rx_time_, 0x78);
ASSERT_EQ(controller_->GetLeMaximumAdvertisingDataLength(), 0x0672);
ASSERT_EQ(controller_->GetLeNumberOfSupportedAdverisingSets(), 0xF0);
}
diff --git a/gd/hci/facade/acl_manager_facade.cc b/gd/hci/facade/acl_manager_facade.cc
index 374d388..384426e 100644
--- a/gd/hci/facade/acl_manager_facade.cc
+++ b/gd/hci/facade/acl_manager_facade.cc
@@ -529,6 +529,9 @@
manufacturer_name,
sub_version);
}
+ void OnReadRemoteSupportedFeaturesComplete(uint64_t features) override {
+ LOG_INFO("OnReadRemoteSupportedFeaturesComplete features:0x%lx", static_cast<unsigned long>(features));
+ }
void OnReadRemoteExtendedFeaturesComplete(
uint8_t page_number, uint8_t max_page_number, uint64_t features) override {
LOG_INFO(
diff --git a/gd/hci/facade/le_acl_manager_facade.cc b/gd/hci/facade/le_acl_manager_facade.cc
index c8d386c..ffc0dc1 100644
--- a/gd/hci/facade/le_acl_manager_facade.cc
+++ b/gd/hci/facade/le_acl_manager_facade.cc
@@ -66,7 +66,7 @@
Address peer_address;
ASSERT(Address::FromString(request->address().address(), peer_address));
AddressWithType peer(peer_address, static_cast<AddressType>(request->type()));
- acl_manager_->CreateLeConnection(peer);
+ acl_manager_->CreateLeConnection(peer, /* is_direct */ true);
if (per_connection_events_.size() > current_connection_request_) {
return ::grpc::Status(::grpc::StatusCode::RESOURCE_EXHAUSTED, "Only one outstanding request is supported");
}
diff --git a/gd/hci/facade/le_scanning_manager_facade.cc b/gd/hci/facade/le_scanning_manager_facade.cc
index 448ec89..b1151e6 100644
--- a/gd/hci/facade/le_scanning_manager_facade.cc
+++ b/gd/hci/facade/le_scanning_manager_facade.cc
@@ -61,6 +61,7 @@
}
void OnScannerRegistered(const bluetooth::hci::Uuid app_uuid, ScannerId scanner_id, ScanningStatus status){};
+ void OnSetScannerParameterComplete(ScannerId scanner_id, ScanningStatus status){};
void OnScanResult(
uint16_t event_type,
uint8_t address_type,
@@ -88,8 +89,9 @@
le_report_msg.set_event(std::string(bytes.begin(), bytes.end()));
pending_events_.OnIncomingEvent(std::move(le_report_msg));
};
- void OnTrackAdvFoundLost(){};
+ void OnTrackAdvFoundLost(AdvertisingFilterOnFoundOnLostInfo on_found_on_lost_info){};
void OnBatchScanReports(int client_if, int status, int report_format, int num_records, std::vector<uint8_t> data){};
+ void OnBatchScanThresholdCrossed(int client_if){};
void OnTimeout(){};
void OnFilterEnable(Enable enable, uint8_t status){};
void OnFilterParamSetup(uint8_t available_spaces, ApcfAction action, uint8_t status){};
diff --git a/gd/hci/hci_layer.cc b/gd/hci/hci_layer.cc
index 11ab966..ac5ea35 100644
--- a/gd/hci/hci_layer.cc
+++ b/gd/hci/hci_layer.cc
@@ -18,9 +18,12 @@
#include "common/bind.h"
#include "common/init_flags.h"
+#include "hci/hci_metrics_logging.h"
#include "os/alarm.h"
+#include "os/metrics.h"
#include "os/queue.h"
#include "packet/packet_builder.h"
+#include "storage/storage_module.h"
namespace bluetooth {
namespace hci {
@@ -50,6 +53,7 @@
}
static void abort_after_time_out(OpCode op_code) {
+ bluetooth::os::LogMetricHciTimeoutEvent(static_cast<uint32_t>(op_code));
ASSERT_LOG(false, "Done waiting for debug information after HCI timeout (%s)", OpCodeText(op_code).c_str());
}
@@ -64,6 +68,8 @@
: command(move(command_packet)), waiting_for_status_(true), on_status(move(on_status_function)) {}
unique_ptr<CommandBuilder> command;
+ unique_ptr<CommandView> command_view;
+
bool waiting_for_status_;
ContextualOnceCallback<void(CommandStatusView)> on_status;
ContextualOnceCallback<void(CommandCompleteView)> on_complete;
@@ -217,6 +223,9 @@
auto cmd_view = CommandView::Create(PacketView<kLittleEndian>(bytes));
ASSERT(cmd_view.IsValid());
OpCode op_code = cmd_view.GetOpCode();
+ command_queue_.front().command_view = std::make_unique<CommandView>(std::move(cmd_view));
+ log_link_layer_connection_command_status(command_queue_.front().command_view, ErrorCode::STATUS_UNKNOWN);
+ log_classic_pairing_command_status(command_queue_.front().command_view, ErrorCode::STATUS_UNKNOWN);
waiting_command_ = op_code;
command_credits_ = 0; // Only allow one outstanding command
if (hci_timeout_alarm_ != nullptr) {
@@ -269,13 +278,15 @@
}
void handle_root_inflammation(uint8_t vse_error_reason) {
+ LOG_ERROR("Received a Root Inflammation Event vendor reason 0x%02hhx, scheduling an abort",
+ vse_error_reason);
+ bluetooth::os::LogMetricBluetoothHalCrashReason(Address::kEmpty, 0, vse_error_reason);
// Add Logging for crash reason
if (hci_timeout_alarm_ != nullptr) {
hci_timeout_alarm_->Cancel();
delete hci_timeout_alarm_;
hci_timeout_alarm_ = nullptr;
}
- LOG_ERROR("Received a Root Inflammation Event, scheduling an abort");
if (hci_abort_alarm_ == nullptr) {
hci_abort_alarm_ = new Alarm(module_.GetHandler());
hci_abort_alarm_->Schedule(BindOnce(&abort_after_root_inflammation, vse_error_reason), kHciTimeoutRestartMs);
@@ -286,21 +297,25 @@
void on_hci_event(EventView event) {
ASSERT(event.IsValid());
+ log_hci_event(command_queue_.front().command_view, event, module_.GetDependency<storage::StorageModule>());
EventCode event_code = event.GetEventCode();
// Root Inflamation is a special case, since it aborts here
if (event_code == EventCode::VENDOR_SPECIFIC) {
- auto inflammation = BqrRootInflammationEventView::Create(
- BqrLinkQualityEventView::Create(BqrEventView::Create(VendorSpecificEventView::Create(event))));
- if (inflammation.IsValid()) {
- handle_root_inflammation(inflammation.GetVendorSpecificErrorCode());
- return;
+ auto view = VendorSpecificEventView::Create(event);
+ ASSERT(view.IsValid());
+ if (view.GetSubeventCode() == VseSubeventCode::BQR_EVENT) {
+ auto bqr_quality_view = BqrLinkQualityEventView::Create(BqrEventView::Create(view));
+ auto inflammation = BqrRootInflammationEventView::Create(bqr_quality_view);
+ if (bqr_quality_view.IsValid() && inflammation.IsValid()) {
+ handle_root_inflammation(inflammation.GetVendorSpecificErrorCode());
+ return;
+ }
}
}
- ASSERT_LOG(
- event_handlers_.find(event_code) != event_handlers_.end(),
- "Unhandled event of type 0x%02hhx (%s)",
- event_code,
- EventCodeText(event_code).c_str());
+ if (event_handlers_.find(event_code) == event_handlers_.end()) {
+ LOG_WARN("Unhandled event of type 0x%02hhx (%s)", event_code, EventCodeText(event_code).c_str());
+ return;
+ }
event_handlers_[event_code].Invoke(event);
}
@@ -308,11 +323,10 @@
LeMetaEventView meta_event_view = LeMetaEventView::Create(event);
ASSERT(meta_event_view.IsValid());
SubeventCode subevent_code = meta_event_view.GetSubeventCode();
- ASSERT_LOG(
- subevent_handlers_.find(subevent_code) != subevent_handlers_.end(),
- "Unhandled le subevent of type 0x%02hhx (%s)",
- subevent_code,
- SubeventCodeText(subevent_code).c_str());
+ if (subevent_handlers_.find(subevent_code) == subevent_handlers_.end()) {
+ LOG_WARN("Unhandled le subevent of type 0x%02hhx (%s)", subevent_code, SubeventCodeText(subevent_code).c_str());
+ return;
+ }
subevent_handlers_[subevent_code].Invoke(meta_event_view);
}
@@ -513,6 +527,7 @@
void HciLayer::ListDependencies(ModuleList* list) {
list->add<hal::HciHal>();
+ list->add<storage::StorageModule>();
}
void HciLayer::Start() {
diff --git a/gd/hci/hci_layer_test.cc b/gd/hci/hci_layer_test.cc
index c96fa48..745b71a 100644
--- a/gd/hci/hci_layer_test.cc
+++ b/gd/hci/hci_layer_test.cc
@@ -90,7 +90,7 @@
}
void sendAclData(hal::HciPacket data) override {
- outgoing_acl_.push_front(std::move(data));
+ outgoing_acl_.push_back(std::move(data));
if (sent_acl_promise_ != nullptr) {
auto promise = std::move(sent_acl_promise_);
sent_acl_promise_.reset();
@@ -99,11 +99,11 @@
}
void sendScoData(hal::HciPacket data) override {
- outgoing_sco_.push_front(std::move(data));
+ outgoing_sco_.push_back(std::move(data));
}
void sendIsoData(hal::HciPacket data) override {
- outgoing_iso_.push_front(std::move(data));
+ outgoing_iso_.push_back(std::move(data));
if (sent_iso_promise_ != nullptr) {
auto promise = std::move(sent_iso_promise_);
sent_iso_promise_.reset();
@@ -164,6 +164,10 @@
void ListDependencies(ModuleList*) {}
+ std::string ToString() const override {
+ return std::string("TestHciHal");
+ }
+
static const ModuleFactory Factory;
private:
@@ -290,6 +294,10 @@
list->add<HciLayer>();
}
+ std::string ToString() const override {
+ return std::string("DependsOnHci");
+ }
+
static const ModuleFactory Factory;
private:
diff --git a/gd/hci/hci_metrics_logging.cc b/gd/hci/hci_metrics_logging.cc
new file mode 100644
index 0000000..00fb9a2
--- /dev/null
+++ b/gd/hci/hci_metrics_logging.cc
@@ -0,0 +1,877 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/proto_logging/stats/enums/bluetooth/enums.pb.h>
+#include <frameworks/proto_logging/stats/enums/bluetooth/hci/enums.pb.h>
+
+#include "common/strings.h"
+#include "hci/hci_metrics_logging.h"
+#include "os/metrics.h"
+#include "storage/device.h"
+
+namespace bluetooth {
+namespace hci {
+
+void log_hci_event(
+ std::unique_ptr<CommandView>& command_view, EventView event_view, storage::StorageModule* storage_module) {
+ ASSERT(event_view.IsValid());
+ EventCode event_code = event_view.GetEventCode();
+ switch (event_code) {
+ case EventCode::COMMAND_COMPLETE: {
+ ASSERT(command_view->IsValid());
+ log_link_layer_connection_command_complete(event_view, command_view);
+ log_classic_pairing_command_complete(event_view, command_view);
+ break;
+ }
+ case EventCode::COMMAND_STATUS: {
+ ASSERT(command_view->IsValid());
+ CommandStatusView response_view = CommandStatusView::Create(event_view);
+ ASSERT(response_view.IsValid());
+ log_link_layer_connection_command_status(command_view, response_view.GetStatus());
+ log_classic_pairing_command_status(command_view, response_view.GetStatus());
+ break;
+ }
+ case EventCode::LE_META_EVENT: {
+ LeMetaEventView le_meta_event_view = LeMetaEventView::Create(event_view);
+ ASSERT(le_meta_event_view.IsValid());
+ log_link_layer_connection_event_le_meta(le_meta_event_view);
+ break;
+ }
+ default:
+ log_link_layer_connection_other_hci_event(event_view, storage_module);
+ log_classic_pairing_other_hci_event(event_view);
+ }
+}
+void log_link_layer_connection_command_status(std::unique_ptr<CommandView>& command_view, ErrorCode status) {
+ // get op_code
+ ASSERT(command_view->IsValid());
+ OpCode op_code = command_view->GetOpCode();
+
+ // init parameters to log
+ Address address = Address::kEmpty;
+ uint32_t connection_handle = bluetooth::os::kUnknownConnectionHandle;
+ uint16_t reason = static_cast<uint16_t>(ErrorCode::UNKNOWN_HCI_COMMAND);
+ static uint16_t kUnknownBleEvt = android::bluetooth::hci::BLE_EVT_UNKNOWN;
+ uint16_t event_code = android::bluetooth::hci::EVT_COMMAND_STATUS;
+ android::bluetooth::DirectionEnum direction = android::bluetooth::DIRECTION_UNKNOWN;
+ uint16_t link_type = android::bluetooth::LINK_TYPE_UNKNOWN;
+
+ // get ConnectionManagementCommandView
+ ConnectionManagementCommandView connection_management_command_view =
+ ConnectionManagementCommandView::Create(AclCommandView::Create(*command_view));
+ ASSERT(connection_management_command_view.IsValid());
+ switch (op_code) {
+ case OpCode::CREATE_CONNECTION: {
+ auto create_connection_view = CreateConnectionView::Create(std::move(connection_management_command_view));
+ ASSERT(create_connection_view.IsValid());
+ address = create_connection_view.GetBdAddr();
+ direction = android::bluetooth::DIRECTION_OUTGOING;
+ link_type = android::bluetooth::LINK_TYPE_ACL;
+ break;
+ }
+ case OpCode::CREATE_CONNECTION_CANCEL: {
+ auto create_connection_cancel_view =
+ CreateConnectionCancelView::Create(std::move(connection_management_command_view));
+ ASSERT(create_connection_cancel_view.IsValid());
+ address = create_connection_cancel_view.GetBdAddr();
+ direction = android::bluetooth::DIRECTION_OUTGOING;
+ link_type = android::bluetooth::LINK_TYPE_ACL;
+ break;
+ }
+ case OpCode::DISCONNECT: {
+ auto disconnect_view = DisconnectView::Create(std::move(connection_management_command_view));
+ ASSERT(disconnect_view.IsValid());
+ connection_handle = disconnect_view.GetConnectionHandle();
+ reason = static_cast<uint16_t>(disconnect_view.GetReason());
+ break;
+ }
+ case OpCode::SETUP_SYNCHRONOUS_CONNECTION: {
+ auto setup_synchronous_connection_view = SetupSynchronousConnectionView::Create(
+ ScoConnectionCommandView::Create(std::move(connection_management_command_view)));
+ ASSERT(setup_synchronous_connection_view.IsValid());
+ connection_handle = setup_synchronous_connection_view.GetConnectionHandle();
+ direction = android::bluetooth::DIRECTION_OUTGOING;
+ break;
+ }
+ case OpCode::ENHANCED_SETUP_SYNCHRONOUS_CONNECTION: {
+ auto enhanced_setup_synchronous_connection_view = EnhancedSetupSynchronousConnectionView::Create(
+ ScoConnectionCommandView::Create(std::move(connection_management_command_view)));
+ ASSERT(enhanced_setup_synchronous_connection_view.IsValid());
+ connection_handle = enhanced_setup_synchronous_connection_view.GetConnectionHandle();
+ direction = android::bluetooth::DIRECTION_OUTGOING;
+ break;
+ }
+ case OpCode::ACCEPT_CONNECTION_REQUEST: {
+ auto accept_connection_request_view =
+ AcceptConnectionRequestView::Create(std::move(connection_management_command_view));
+ ASSERT(accept_connection_request_view.IsValid());
+ address = accept_connection_request_view.GetBdAddr();
+ direction = android::bluetooth::DIRECTION_INCOMING;
+ break;
+ }
+ case OpCode::ACCEPT_SYNCHRONOUS_CONNECTION: {
+ auto accept_synchronous_connection_view = AcceptSynchronousConnectionView::Create(
+ ScoConnectionCommandView::Create(std::move(connection_management_command_view)));
+ ASSERT(accept_synchronous_connection_view.IsValid());
+ address = accept_synchronous_connection_view.GetBdAddr();
+ direction = android::bluetooth::DIRECTION_INCOMING;
+ break;
+ }
+ case OpCode::ENHANCED_ACCEPT_SYNCHRONOUS_CONNECTION: {
+ auto enhanced_accept_synchronous_connection_view = EnhancedAcceptSynchronousConnectionView::Create(
+ ScoConnectionCommandView::Create(std::move(connection_management_command_view)));
+ ASSERT(enhanced_accept_synchronous_connection_view.IsValid());
+ address = enhanced_accept_synchronous_connection_view.GetBdAddr();
+ direction = android::bluetooth::DIRECTION_INCOMING;
+ break;
+ }
+ case OpCode::REJECT_CONNECTION_REQUEST: {
+ auto reject_connection_request_view =
+ RejectConnectionRequestView::Create(std::move(connection_management_command_view));
+ ASSERT(reject_connection_request_view.IsValid());
+ address = reject_connection_request_view.GetBdAddr();
+ reason = static_cast<uint16_t>(reject_connection_request_view.GetReason());
+ direction = android::bluetooth::DIRECTION_INCOMING;
+ break;
+ }
+ case OpCode::REJECT_SYNCHRONOUS_CONNECTION: {
+ auto reject_synchronous_connection_view = RejectSynchronousConnectionView::Create(
+ ScoConnectionCommandView::Create(std::move(connection_management_command_view)));
+ ASSERT(reject_synchronous_connection_view.IsValid());
+ address = reject_synchronous_connection_view.GetBdAddr();
+ reason = static_cast<uint16_t>(reject_synchronous_connection_view.GetReason());
+ direction = android::bluetooth::DIRECTION_INCOMING;
+ break;
+ }
+ case OpCode::LE_CREATE_CONNECTION: {
+ auto le_create_connection_view = LeCreateConnectionView::Create(
+ LeConnectionManagementCommandView::Create(std::move(connection_management_command_view)));
+ ASSERT(le_create_connection_view.IsValid());
+ uint8_t initiator_filter_policy = static_cast<uint8_t>(le_create_connection_view.GetInitiatorFilterPolicy());
+ if (initiator_filter_policy != 0x00 && status == ErrorCode::SUCCESS) {
+ return;
+ }
+ address = le_create_connection_view.GetPeerAddress();
+ direction = android::bluetooth::DIRECTION_INCOMING;
+ link_type = android::bluetooth::LINK_TYPE_ACL;
+ break;
+ }
+ case OpCode::LE_EXTENDED_CREATE_CONNECTION: {
+ auto le_extended_create_connection_view = LeExtendedCreateConnectionView::Create(
+ LeConnectionManagementCommandView::Create(std::move(connection_management_command_view)));
+ ASSERT(le_extended_create_connection_view.IsValid());
+ uint8_t initiator_filter_policy =
+ static_cast<uint8_t>(le_extended_create_connection_view.GetInitiatorFilterPolicy());
+ if (initiator_filter_policy != 0x00 && status == ErrorCode::SUCCESS) {
+ return;
+ }
+ address = le_extended_create_connection_view.GetPeerAddress();
+ direction = android::bluetooth::DIRECTION_OUTGOING;
+ link_type = android::bluetooth::LINK_TYPE_ACL;
+ break;
+ }
+ case OpCode::LE_CREATE_CONNECTION_CANCEL: {
+ auto le_create_connection_cancel_view = LeCreateConnectionCancelView::Create(
+ LeConnectionManagementCommandView::Create(std::move(connection_management_command_view)));
+ ASSERT(le_create_connection_cancel_view.IsValid());
+ if (status == ErrorCode::SUCCESS) {
+ return;
+ }
+ direction = android::bluetooth::DIRECTION_OUTGOING;
+ link_type = android::bluetooth::LINK_TYPE_ACL;
+ break;
+ }
+ case OpCode::LE_CLEAR_CONNECT_LIST: {
+ auto le_clear_connect_list_view = LeClearConnectListView::Create(
+ LeConnectionManagementCommandView::Create(std::move(connection_management_command_view)));
+ ASSERT(le_clear_connect_list_view.IsValid());
+ direction = android::bluetooth::DIRECTION_INCOMING;
+ link_type = android::bluetooth::LINK_TYPE_ACL;
+ break;
+ }
+ case OpCode::LE_ADD_DEVICE_TO_CONNECT_LIST: {
+ auto le_add_device_to_connect_list_view = LeAddDeviceToConnectListView::Create(
+ LeConnectionManagementCommandView::Create(std::move(connection_management_command_view)));
+ ASSERT(le_add_device_to_connect_list_view.IsValid());
+ address = le_add_device_to_connect_list_view.GetAddress();
+ direction = android::bluetooth::DIRECTION_INCOMING;
+ link_type = android::bluetooth::LINK_TYPE_ACL;
+ break;
+ }
+ case OpCode::LE_REMOVE_DEVICE_FROM_CONNECT_LIST: {
+ auto le_remove_device_from_connect_list_view = LeRemoveDeviceFromConnectListView::Create(
+ LeConnectionManagementCommandView::Create(std::move(connection_management_command_view)));
+ ASSERT(le_remove_device_from_connect_list_view.IsValid());
+ address = le_remove_device_from_connect_list_view.GetAddress();
+ direction = android::bluetooth::DIRECTION_INCOMING;
+ link_type = android::bluetooth::LINK_TYPE_ACL;
+ break;
+ }
+ default:
+ return;
+ }
+ os::LogMetricLinkLayerConnectionEvent(
+ &address,
+ connection_handle,
+ direction,
+ link_type,
+ static_cast<uint32_t>(op_code),
+ static_cast<uint16_t>(event_code),
+ kUnknownBleEvt,
+ static_cast<uint16_t>(status),
+ static_cast<uint16_t>(reason));
+}
+
+void log_link_layer_connection_command_complete(EventView event_view, std::unique_ptr<CommandView>& command_view) {
+ CommandCompleteView command_complete_view = CommandCompleteView::Create(std::move(event_view));
+ ASSERT(command_complete_view.IsValid());
+ OpCode op_code = command_complete_view.GetCommandOpCode();
+
+ // init parameters to log
+ Address address = Address::kEmpty;
+ uint32_t connection_handle = bluetooth::os::kUnknownConnectionHandle;
+ ErrorCode status = ErrorCode::UNKNOWN_HCI_COMMAND;
+ ErrorCode reason = ErrorCode::UNKNOWN_HCI_COMMAND;
+ static uint16_t kUnknownBleEvt = android::bluetooth::hci::BLE_EVT_UNKNOWN;
+ uint16_t event_code = android::bluetooth::hci::EVT_COMMAND_COMPLETE;
+ android::bluetooth::DirectionEnum direction = android::bluetooth::DIRECTION_UNKNOWN;
+ uint16_t link_type = android::bluetooth::LINK_TYPE_UNKNOWN;
+
+ // get ConnectionManagementCommandView
+ ConnectionManagementCommandView connection_management_command_view =
+ ConnectionManagementCommandView::Create(AclCommandView::Create(*command_view));
+ ASSERT(connection_management_command_view.IsValid());
+
+ switch (op_code) {
+ case OpCode::LE_CLEAR_CONNECT_LIST: {
+ auto le_clear_connect_list_view = LeClearConnectListView::Create(
+ LeConnectionManagementCommandView::Create(std::move(connection_management_command_view)));
+ ASSERT(le_clear_connect_list_view.IsValid());
+ direction = android::bluetooth::DIRECTION_INCOMING;
+ link_type = android::bluetooth::LINK_TYPE_ACL;
+ break;
+ }
+ case OpCode::LE_ADD_DEVICE_TO_CONNECT_LIST: {
+ auto le_add_device_to_connect_list_view = LeAddDeviceToConnectListView::Create(
+ LeConnectionManagementCommandView::Create(std::move(connection_management_command_view)));
+ ASSERT(le_add_device_to_connect_list_view.IsValid());
+ address = le_add_device_to_connect_list_view.GetAddress();
+ direction = android::bluetooth::DIRECTION_INCOMING;
+ link_type = android::bluetooth::LINK_TYPE_ACL;
+ break;
+ }
+ case OpCode::LE_REMOVE_DEVICE_FROM_CONNECT_LIST: {
+ auto le_remove_device_from_connect_list_view = LeRemoveDeviceFromConnectListView::Create(
+ LeConnectionManagementCommandView::Create(std::move(connection_management_command_view)));
+ ASSERT(le_remove_device_from_connect_list_view.IsValid());
+ address = le_remove_device_from_connect_list_view.GetAddress();
+ direction = android::bluetooth::DIRECTION_INCOMING;
+ link_type = android::bluetooth::LINK_TYPE_ACL;
+ break;
+ }
+ case OpCode::CREATE_CONNECTION_CANCEL: {
+ auto create_connection_cancel_complete_view =
+ CreateConnectionCancelCompleteView::Create(std::move(command_complete_view));
+ ASSERT(create_connection_cancel_complete_view.IsValid());
+ address = create_connection_cancel_complete_view.GetBdAddr();
+ direction = android::bluetooth::DIRECTION_OUTGOING;
+ link_type = android::bluetooth::LINK_TYPE_ACL;
+ status = create_connection_cancel_complete_view.GetStatus();
+ break;
+ }
+ case OpCode::LE_CREATE_CONNECTION_CANCEL: {
+ auto le_create_connection_cancel_complete_view =
+ LeCreateConnectionCancelCompleteView::Create(std::move(command_complete_view));
+ ASSERT(le_create_connection_cancel_complete_view.IsValid());
+ direction = android::bluetooth::DIRECTION_OUTGOING;
+ link_type = android::bluetooth::LINK_TYPE_ACL;
+ status = le_create_connection_cancel_complete_view.GetStatus();
+ break;
+ }
+ default:
+ return;
+ }
+ os::LogMetricLinkLayerConnectionEvent(
+ &address,
+ connection_handle,
+ direction,
+ link_type,
+ static_cast<uint32_t>(op_code),
+ static_cast<uint16_t>(event_code),
+ kUnknownBleEvt,
+ static_cast<uint16_t>(status),
+ static_cast<uint16_t>(reason));
+}
+
+void log_link_layer_connection_other_hci_event(EventView packet, storage::StorageModule* storage_module) {
+ EventCode event_code = packet.GetEventCode();
+ Address address = Address::kEmpty;
+ uint32_t connection_handle = bluetooth::os::kUnknownConnectionHandle;
+ android::bluetooth::DirectionEnum direction = android::bluetooth::DIRECTION_UNKNOWN;
+ uint16_t link_type = android::bluetooth::LINK_TYPE_UNKNOWN;
+ ErrorCode status = ErrorCode::UNKNOWN_HCI_COMMAND;
+ ErrorCode reason = ErrorCode::UNKNOWN_HCI_COMMAND;
+ uint32_t cmd = android::bluetooth::hci::CMD_UNKNOWN;
+ switch (event_code) {
+ case EventCode::CONNECTION_COMPLETE: {
+ auto connection_complete_view = ConnectionCompleteView::Create(std::move(packet));
+ ASSERT(connection_complete_view.IsValid());
+ address = connection_complete_view.GetBdAddr();
+ connection_handle = connection_complete_view.GetConnectionHandle();
+ link_type = static_cast<uint16_t>(connection_complete_view.GetLinkType());
+ status = connection_complete_view.GetStatus();
+
+ // besides log link layer connection events, also log remote device manufacturer info
+ log_remote_device_information(address, connection_handle, status, storage_module);
+ break;
+ }
+ case EventCode::CONNECTION_REQUEST: {
+ auto connection_request_view = ConnectionRequestView::Create(std::move(packet));
+ ASSERT(connection_request_view.IsValid());
+ address = connection_request_view.GetBdAddr();
+ link_type = static_cast<uint16_t>(connection_request_view.GetLinkType());
+ direction = android::bluetooth::DIRECTION_INCOMING;
+ break;
+ }
+ case EventCode::DISCONNECTION_COMPLETE: {
+ auto disconnection_complete_view = DisconnectionCompleteView::Create(std::move(packet));
+ ASSERT(disconnection_complete_view.IsValid());
+ status = disconnection_complete_view.GetStatus();
+ connection_handle = disconnection_complete_view.GetConnectionHandle();
+ reason = disconnection_complete_view.GetReason();
+ break;
+ }
+ case EventCode::SYNCHRONOUS_CONNECTION_COMPLETE: {
+ auto synchronous_connection_complete_view = SynchronousConnectionCompleteView::Create(std::move(packet));
+ ASSERT(synchronous_connection_complete_view.IsValid());
+ connection_handle = synchronous_connection_complete_view.GetConnectionHandle();
+ address = synchronous_connection_complete_view.GetBdAddr();
+ link_type = static_cast<uint16_t>(synchronous_connection_complete_view.GetLinkType());
+ status = synchronous_connection_complete_view.GetStatus();
+ break;
+ }
+ case EventCode::SYNCHRONOUS_CONNECTION_CHANGED: {
+ auto synchronous_connection_changed_view = SynchronousConnectionChangedView::Create(std::move(packet));
+ ASSERT(synchronous_connection_changed_view.IsValid());
+ status = synchronous_connection_changed_view.GetStatus();
+ connection_handle = synchronous_connection_changed_view.GetConnectionHandle();
+ break;
+ }
+ default:
+ return;
+ }
+ os::LogMetricLinkLayerConnectionEvent(
+ &address,
+ connection_handle,
+ direction,
+ link_type,
+ static_cast<uint32_t>(cmd),
+ static_cast<uint16_t>(event_code),
+ android::bluetooth::hci::BLE_EVT_UNKNOWN,
+ static_cast<uint16_t>(status),
+ static_cast<uint16_t>(reason));
+}
+
+void log_link_layer_connection_event_le_meta(LeMetaEventView le_meta_event_view) {
+ SubeventCode leEvt = le_meta_event_view.GetSubeventCode();
+ auto le_connection_complete_view = LeConnectionCompleteView::Create(std::move(le_meta_event_view));
+ if (!le_connection_complete_view.IsValid()) {
+ // function is called for all le meta events. Only need to process le connection complete.
+ return;
+ }
+ ASSERT(le_connection_complete_view.IsValid());
+ // init parameters to log
+ EventCode event_code = EventCode::LE_META_EVENT;
+ Address address = le_connection_complete_view.GetPeerAddress();
+ uint32_t connection_handle = le_connection_complete_view.GetConnectionHandle();
+ android::bluetooth::DirectionEnum direction = android::bluetooth::DIRECTION_UNKNOWN;
+ uint16_t link_type = android::bluetooth::LINK_TYPE_ACL;
+ ErrorCode status = le_connection_complete_view.GetStatus();
+ ErrorCode reason = ErrorCode::UNKNOWN_HCI_COMMAND;
+ uint32_t cmd = android::bluetooth::hci::CMD_UNKNOWN;
+
+ os::LogMetricLinkLayerConnectionEvent(
+ &address,
+ connection_handle,
+ direction,
+ link_type,
+ static_cast<uint32_t>(cmd),
+ static_cast<uint16_t>(event_code),
+ static_cast<uint16_t>(leEvt),
+ static_cast<uint16_t>(status),
+ static_cast<uint16_t>(reason));
+}
+
+void log_classic_pairing_other_hci_event(EventView packet) {
+ EventCode event_code = packet.GetEventCode();
+ Address address = Address::kEmpty;
+ uint32_t cmd = android::bluetooth::hci::CMD_UNKNOWN;
+ ErrorCode status = ErrorCode::UNKNOWN_HCI_COMMAND;
+ ErrorCode reason = ErrorCode::UNKNOWN_HCI_COMMAND;
+ uint32_t connection_handle = bluetooth::os::kUnknownConnectionHandle;
+ int64_t value = 0;
+
+ switch (event_code) {
+ case EventCode::IO_CAPABILITY_REQUEST: {
+ IoCapabilityRequestView io_capability_request_view = IoCapabilityRequestView::Create(std::move(packet));
+ ASSERT(io_capability_request_view.IsValid());
+ address = io_capability_request_view.GetBdAddr();
+ break;
+ }
+ case EventCode::IO_CAPABILITY_RESPONSE: {
+ IoCapabilityResponseView io_capability_response_view = IoCapabilityResponseView::Create(std::move(packet));
+ ASSERT(io_capability_response_view.IsValid());
+ address = io_capability_response_view.GetBdAddr();
+ break;
+ }
+ case EventCode::LINK_KEY_REQUEST: {
+ LinkKeyRequestView link_key_request_view = LinkKeyRequestView::Create(std::move(packet));
+ ASSERT(link_key_request_view.IsValid());
+ address = link_key_request_view.GetBdAddr();
+ break;
+ }
+ case EventCode::LINK_KEY_NOTIFICATION: {
+ LinkKeyNotificationView link_key_notification_view = LinkKeyNotificationView::Create(std::move(packet));
+ ASSERT(link_key_notification_view.IsValid());
+ address = link_key_notification_view.GetBdAddr();
+ break;
+ }
+ case EventCode::USER_PASSKEY_REQUEST: {
+ UserPasskeyRequestView user_passkey_request_view = UserPasskeyRequestView::Create(std::move(packet));
+ ASSERT(user_passkey_request_view.IsValid());
+ address = user_passkey_request_view.GetBdAddr();
+ break;
+ }
+ case EventCode::USER_PASSKEY_NOTIFICATION: {
+ UserPasskeyNotificationView user_passkey_notification_view = UserPasskeyNotificationView::Create(std::move(packet));
+ ASSERT(user_passkey_notification_view.IsValid());
+ address = user_passkey_notification_view.GetBdAddr();
+ break;
+ }
+ case EventCode::USER_CONFIRMATION_REQUEST: {
+ UserConfirmationRequestView user_confirmation_request_view = UserConfirmationRequestView::Create(std::move(packet));
+ ASSERT(user_confirmation_request_view.IsValid());
+ address = user_confirmation_request_view.GetBdAddr();
+ break;
+ }
+ case EventCode::KEYPRESS_NOTIFICATION: {
+ KeypressNotificationView keypress_notification_view = KeypressNotificationView::Create(std::move(packet));
+ ASSERT(keypress_notification_view.IsValid());
+ address = keypress_notification_view.GetBdAddr();
+ break;
+ }
+ case EventCode::REMOTE_OOB_DATA_REQUEST: {
+ RemoteOobDataRequestView remote_oob_data_request_view = RemoteOobDataRequestView::Create(std::move(packet));
+ ASSERT(remote_oob_data_request_view.IsValid());
+ address = remote_oob_data_request_view.GetBdAddr();
+ break;
+ }
+ case EventCode::SIMPLE_PAIRING_COMPLETE: {
+ SimplePairingCompleteView simple_pairing_complete_view = SimplePairingCompleteView::Create(std::move(packet));
+ ASSERT(simple_pairing_complete_view.IsValid());
+ address = simple_pairing_complete_view.GetBdAddr();
+ status = simple_pairing_complete_view.GetStatus();
+ break;
+ }
+ case EventCode::REMOTE_NAME_REQUEST_COMPLETE: {
+ RemoteNameRequestCompleteView remote_name_request_complete_view = RemoteNameRequestCompleteView::Create(std::move(packet));
+ ASSERT(remote_name_request_complete_view.IsValid());
+ address = remote_name_request_complete_view.GetBdAddr();
+ status = remote_name_request_complete_view.GetStatus();
+ break;
+ }
+ case EventCode::AUTHENTICATION_COMPLETE: {
+ AuthenticationCompleteView authentication_complete_view = AuthenticationCompleteView::Create(std::move(packet));
+ ASSERT(authentication_complete_view.IsValid());
+ status = authentication_complete_view.GetStatus();
+ connection_handle = authentication_complete_view.GetConnectionHandle();
+ break;
+ }
+ case EventCode::ENCRYPTION_CHANGE: {
+ EncryptionChangeView encryption_change_view = EncryptionChangeView::Create(std::move(packet));
+ ASSERT(encryption_change_view.IsValid());
+ status = encryption_change_view.GetStatus();
+ connection_handle = encryption_change_view.GetConnectionHandle();
+ value = static_cast<int64_t>(encryption_change_view.GetEncryptionEnabled());
+ break;
+ }
+ default:
+ return;
+ }
+ os::LogMetricClassicPairingEvent(
+ address,
+ connection_handle,
+ static_cast<uint32_t>(cmd),
+ static_cast<uint16_t>(event_code),
+ static_cast<uint16_t>(status),
+ static_cast<uint16_t>(reason),
+ value);
+}
+
+void log_classic_pairing_command_status(std::unique_ptr<CommandView>& command_view, ErrorCode status) {
+ // get op_code
+ ASSERT(command_view->IsValid());
+ OpCode op_code = command_view->GetOpCode();
+
+ // init parameters
+ Address address = Address::kEmpty;
+ ErrorCode reason = ErrorCode::UNKNOWN_HCI_COMMAND;
+ uint32_t connection_handle = bluetooth::os::kUnknownConnectionHandle;
+ int64_t value = 0;
+ uint16_t event_code = android::bluetooth::hci::EVT_COMMAND_STATUS;
+
+ // create SecurityCommandView
+ SecurityCommandView security_command_view = SecurityCommandView::Create(*command_view);
+ ASSERT(security_command_view.IsValid());
+
+ // create ConnectionManagementCommandView
+ ConnectionManagementCommandView connection_management_command_view =
+ ConnectionManagementCommandView::Create(AclCommandView::Create(*command_view));
+ ASSERT(connection_management_command_view.IsValid());
+
+ // create DiscoveryCommandView
+ DiscoveryCommandView discovery_command_view = DiscoveryCommandView::Create(*command_view);
+ ASSERT(discovery_command_view.IsValid());
+
+ switch (op_code) {
+ case OpCode::READ_LOCAL_OOB_DATA: {
+ ReadLocalOobDataView read_local_oob_data_view = ReadLocalOobDataView::Create(std::move(security_command_view));
+ ASSERT(read_local_oob_data_view.IsValid());
+ break;
+ }
+ case OpCode::WRITE_SIMPLE_PAIRING_MODE: {
+ WriteSimplePairingModeView write_simple_pairing_mode_view
+ = WriteSimplePairingModeView::Create(std::move(security_command_view));
+ ASSERT(write_simple_pairing_mode_view.IsValid());
+ value = static_cast<int64_t>(write_simple_pairing_mode_view.GetSimplePairingMode());
+ break;
+ }
+ case OpCode::WRITE_SECURE_CONNECTIONS_HOST_SUPPORT: {
+ WriteSecureConnectionsHostSupportView write_secure_connections_host_support_view
+ = WriteSecureConnectionsHostSupportView::Create(std::move(security_command_view));
+ ASSERT(write_secure_connections_host_support_view.IsValid());
+ value = static_cast<int64_t>(write_secure_connections_host_support_view.GetSecureConnectionsHostSupport());
+ break;
+ }
+ case OpCode::AUTHENTICATION_REQUESTED: {
+ AuthenticationRequestedView authentication_requested_view
+ = AuthenticationRequestedView::Create(std::move(connection_management_command_view));
+ ASSERT(authentication_requested_view.IsValid());
+ connection_handle = authentication_requested_view.GetConnectionHandle();
+ break;
+ }
+ case OpCode::SET_CONNECTION_ENCRYPTION: {
+ SetConnectionEncryptionView set_connection_encryption_view
+ = SetConnectionEncryptionView::Create(std::move(connection_management_command_view));
+ ASSERT(set_connection_encryption_view.IsValid());
+ connection_handle = set_connection_encryption_view.GetConnectionHandle();
+ value = static_cast<int64_t>(set_connection_encryption_view.GetEncryptionEnable());
+ break;
+ }
+ case OpCode::DELETE_STORED_LINK_KEY: {
+ DeleteStoredLinkKeyView delete_stored_link_key_view
+ = DeleteStoredLinkKeyView::Create(std::move(security_command_view));
+ ASSERT(delete_stored_link_key_view.IsValid());
+ address = delete_stored_link_key_view.GetBdAddr();
+ value = static_cast<int64_t>(delete_stored_link_key_view.GetDeleteAllFlag());
+ break;
+ }
+ case OpCode::REMOTE_NAME_REQUEST: {
+ RemoteNameRequestView remote_name_request_view = RemoteNameRequestView::Create(std::move(discovery_command_view));
+ ASSERT(remote_name_request_view.IsValid());
+ address = remote_name_request_view.GetBdAddr();
+ break;
+ }
+ case OpCode::REMOTE_NAME_REQUEST_CANCEL: {
+ RemoteNameRequestCancelView remote_name_request_cancel_view
+ = RemoteNameRequestCancelView::Create(std::move(discovery_command_view));
+ ASSERT(remote_name_request_cancel_view.IsValid());
+ address = remote_name_request_cancel_view.GetBdAddr();
+ break;
+ }
+ case OpCode::LINK_KEY_REQUEST_REPLY: {
+ LinkKeyRequestReplyView link_key_request_reply_view
+ = LinkKeyRequestReplyView::Create(std::move(security_command_view));
+ ASSERT(link_key_request_reply_view.IsValid());
+ address = link_key_request_reply_view.GetBdAddr();
+ break;
+ }
+ case OpCode::LINK_KEY_REQUEST_NEGATIVE_REPLY: {
+ LinkKeyRequestNegativeReplyView link_key_request_negative_reply_view
+ = LinkKeyRequestNegativeReplyView::Create(std::move(security_command_view));
+ ASSERT(link_key_request_negative_reply_view.IsValid());
+ address = link_key_request_negative_reply_view.GetBdAddr();
+ break;
+ }
+ case OpCode::IO_CAPABILITY_REQUEST_REPLY: {
+ IoCapabilityRequestReplyView io_capability_request_reply_view
+ = IoCapabilityRequestReplyView::Create(std::move(security_command_view));
+ ASSERT(io_capability_request_reply_view.IsValid());
+ address = io_capability_request_reply_view.GetBdAddr();
+ break;
+ }
+ case OpCode::USER_CONFIRMATION_REQUEST_REPLY: {
+ UserConfirmationRequestReplyView user_confirmation_request_reply
+ = UserConfirmationRequestReplyView::Create(std::move(security_command_view));
+ ASSERT(user_confirmation_request_reply.IsValid());
+ address = user_confirmation_request_reply.GetBdAddr();
+ break;
+ }
+ case OpCode::USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY: {
+ UserConfirmationRequestNegativeReplyView user_confirmation_request_negative_reply
+ = UserConfirmationRequestNegativeReplyView::Create(std::move(security_command_view));
+ ASSERT(user_confirmation_request_negative_reply.IsValid());
+ address = user_confirmation_request_negative_reply.GetBdAddr();
+ break;
+ }
+ case OpCode::USER_PASSKEY_REQUEST_REPLY: {
+ UserPasskeyRequestReplyView user_passkey_request_reply
+ = UserPasskeyRequestReplyView::Create(std::move(security_command_view));
+ ASSERT(user_passkey_request_reply.IsValid());
+ address = user_passkey_request_reply.GetBdAddr();
+ break;
+ }
+ case OpCode::USER_PASSKEY_REQUEST_NEGATIVE_REPLY: {
+ UserPasskeyRequestNegativeReplyView user_passkey_request_negative_reply
+ = UserPasskeyRequestNegativeReplyView::Create(std::move(security_command_view));
+ ASSERT(user_passkey_request_negative_reply.IsValid());
+ address = user_passkey_request_negative_reply.GetBdAddr();
+ break;
+ }
+ case OpCode::REMOTE_OOB_DATA_REQUEST_REPLY: {
+ RemoteOobDataRequestReplyView remote_oob_data_request_reply_view
+ = RemoteOobDataRequestReplyView::Create(std::move(security_command_view));
+ ASSERT(remote_oob_data_request_reply_view.IsValid());
+ address = remote_oob_data_request_reply_view.GetBdAddr();
+ break;
+ }
+ case OpCode::REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY: {
+ RemoteOobDataRequestNegativeReplyView remote_oob_data_request_negative_reply_view
+ = RemoteOobDataRequestNegativeReplyView::Create(std::move(security_command_view));
+ ASSERT(remote_oob_data_request_negative_reply_view.IsValid());
+ address = remote_oob_data_request_negative_reply_view.GetBdAddr();
+ break;
+ }
+ case OpCode::IO_CAPABILITY_REQUEST_NEGATIVE_REPLY: {
+ IoCapabilityRequestNegativeReplyView io_capability_request_negative_reply_view
+ = IoCapabilityRequestNegativeReplyView::Create(std::move(security_command_view));
+ ASSERT(io_capability_request_negative_reply_view.IsValid());
+ address = io_capability_request_negative_reply_view.GetBdAddr();
+ reason = io_capability_request_negative_reply_view.GetReason();
+ break;
+ }
+ default:
+ return;
+ }
+ os::LogMetricClassicPairingEvent(
+ address,
+ connection_handle,
+ static_cast<uint32_t>(op_code),
+ static_cast<uint16_t>(event_code),
+ static_cast<uint16_t>(status),
+ static_cast<uint16_t>(reason),
+ value);
+}
+
+void log_classic_pairing_command_complete(EventView event_view, std::unique_ptr<CommandView>& command_view) {
+
+ // get op_code
+ CommandCompleteView command_complete_view = CommandCompleteView::Create(std::move(event_view));
+ ASSERT(command_complete_view.IsValid());
+ OpCode op_code = command_complete_view.GetCommandOpCode();
+
+ // init parameters
+ Address address = Address::kEmpty;
+ ErrorCode status = ErrorCode::UNKNOWN_HCI_COMMAND;
+ ErrorCode reason = ErrorCode::UNKNOWN_HCI_COMMAND;
+ uint32_t connection_handle = bluetooth::os::kUnknownConnectionHandle;
+ int64_t value = 0;
+ EventCode event_code = EventCode::COMMAND_COMPLETE;
+
+ // get ConnectionManagementCommandView
+ ConnectionManagementCommandView connection_management_command_view =
+ ConnectionManagementCommandView::Create(AclCommandView::Create(*command_view));
+ ASSERT(connection_management_command_view.IsValid());
+
+ // create SecurityCommandView
+ SecurityCommandView security_command_view = SecurityCommandView::Create(*command_view);
+ ASSERT(security_command_view.IsValid());
+
+ switch (op_code) {
+ case OpCode::DELETE_STORED_LINK_KEY: {
+ auto delete_stored_link_key_complete_view = DeleteStoredLinkKeyCompleteView::Create(std::move(command_complete_view));
+ ASSERT(delete_stored_link_key_complete_view.IsValid());
+ status = delete_stored_link_key_complete_view.GetStatus();
+ break;
+ }
+ case OpCode::READ_LOCAL_OOB_DATA: {
+ auto read_local_oob_data_complete_view = ReadLocalOobDataCompleteView::Create(std::move(command_complete_view));
+ ASSERT(read_local_oob_data_complete_view.IsValid());
+ status = read_local_oob_data_complete_view.GetStatus();
+ break;
+ }
+ case OpCode::WRITE_SIMPLE_PAIRING_MODE: {
+ auto write_simple_pairing_mode_complete_view = WriteSimplePairingModeCompleteView::Create(std::move(command_complete_view));
+ ASSERT(write_simple_pairing_mode_complete_view.IsValid());
+ status = write_simple_pairing_mode_complete_view.GetStatus();
+ break;
+ }
+ case OpCode::WRITE_SECURE_CONNECTIONS_HOST_SUPPORT: {
+ auto write_secure_connections_host_support_complete_view = WriteSecureConnectionsHostSupportCompleteView::Create(std::move(command_complete_view));
+ ASSERT(write_secure_connections_host_support_complete_view.IsValid());
+ status = write_secure_connections_host_support_complete_view.GetStatus();
+ break;
+ }
+ case OpCode::READ_ENCRYPTION_KEY_SIZE: {
+ auto read_encryption_key_size_complete_view = ReadEncryptionKeySizeCompleteView::Create(std::move(command_complete_view));
+ ASSERT(read_encryption_key_size_complete_view.IsValid());
+ status = read_encryption_key_size_complete_view.GetStatus();
+ connection_handle = read_encryption_key_size_complete_view.GetConnectionHandle();
+ value = read_encryption_key_size_complete_view.GetKeySize();
+ break;
+ }
+ case OpCode::LINK_KEY_REQUEST_REPLY: {
+ auto link_key_request_reply_complete_view = LinkKeyRequestReplyCompleteView::Create(std::move(command_complete_view));
+ ASSERT(link_key_request_reply_complete_view.IsValid());
+ status = link_key_request_reply_complete_view.GetStatus();
+ auto link_key_request_reply_view = LinkKeyRequestReplyView::Create(std::move(security_command_view));
+ ASSERT(link_key_request_reply_view.IsValid());
+ address = link_key_request_reply_view.GetBdAddr();
+ break;
+ }
+ case OpCode::LINK_KEY_REQUEST_NEGATIVE_REPLY: {
+ auto link_key_request_negative_reply_complete_view = LinkKeyRequestNegativeReplyCompleteView::Create(std::move(command_complete_view));
+ ASSERT(link_key_request_negative_reply_complete_view.IsValid());
+ status = link_key_request_negative_reply_complete_view.GetStatus();
+ auto link_key_request_negative_reply_view = LinkKeyRequestNegativeReplyView::Create(std::move(security_command_view));
+ ASSERT(link_key_request_negative_reply_view.IsValid());
+ address = link_key_request_negative_reply_view.GetBdAddr();
+ break;
+ }
+ case OpCode::IO_CAPABILITY_REQUEST_REPLY: {
+ auto io_capability_request_reply_complete_view = IoCapabilityRequestReplyCompleteView::Create(std::move(command_complete_view));
+ ASSERT(io_capability_request_reply_complete_view.IsValid());
+ status = io_capability_request_reply_complete_view.GetStatus();
+ auto io_capability_request_reply_view = IoCapabilityRequestReplyView::Create(std::move(security_command_view));
+ ASSERT(io_capability_request_reply_view.IsValid());
+ address = io_capability_request_reply_view.GetBdAddr();
+ break;
+ }
+ case OpCode::IO_CAPABILITY_REQUEST_NEGATIVE_REPLY: {
+ auto io_capability_request_negative_reply_complete_view = IoCapabilityRequestNegativeReplyCompleteView::Create(std::move(command_complete_view));
+ ASSERT(io_capability_request_negative_reply_complete_view.IsValid());
+ status = io_capability_request_negative_reply_complete_view.GetStatus();
+ auto io_capability_request_negative_reply_view = IoCapabilityRequestNegativeReplyView::Create(std::move(security_command_view));
+ ASSERT(io_capability_request_negative_reply_view.IsValid());
+ address = io_capability_request_negative_reply_view.GetBdAddr();
+ break;
+ }
+ case OpCode::USER_CONFIRMATION_REQUEST_REPLY: {
+ auto user_confirmation_request_reply_complete_view = UserConfirmationRequestReplyCompleteView::Create(std::move(command_complete_view));
+ ASSERT(user_confirmation_request_reply_complete_view.IsValid());
+ status = user_confirmation_request_reply_complete_view.GetStatus();
+ auto user_confirmation_request_reply_view = UserConfirmationRequestReplyView::Create(std::move(security_command_view));
+ ASSERT(user_confirmation_request_reply_view.IsValid());
+ address = user_confirmation_request_reply_view.GetBdAddr();
+ break;
+ }
+ case OpCode::USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY: {
+ auto user_confirmation_request_negative_reply_complete_view = UserConfirmationRequestNegativeReplyCompleteView::Create(std::move(command_complete_view));
+ ASSERT(user_confirmation_request_negative_reply_complete_view.IsValid());
+ status = user_confirmation_request_negative_reply_complete_view.GetStatus();
+ auto user_confirmation_request_negative_reply_view = UserConfirmationRequestNegativeReplyView::Create(std::move(security_command_view));
+ ASSERT(user_confirmation_request_negative_reply_view.IsValid());
+ address = user_confirmation_request_negative_reply_view.GetBdAddr();
+ break;
+ }
+ case OpCode::USER_PASSKEY_REQUEST_REPLY: {
+ auto user_passkey_request_reply_complete_view = UserPasskeyRequestReplyCompleteView::Create(std::move(command_complete_view));
+ ASSERT(user_passkey_request_reply_complete_view.IsValid());
+ status = user_passkey_request_reply_complete_view.GetStatus();
+ auto user_passkey_request_reply_view = UserPasskeyRequestReplyView::Create(std::move(security_command_view));
+ ASSERT(user_passkey_request_reply_view.IsValid());
+ address = user_passkey_request_reply_view.GetBdAddr();
+ break;
+ }
+ case OpCode::USER_PASSKEY_REQUEST_NEGATIVE_REPLY: {
+ auto user_passkey_request_negative_reply_complete_view = UserPasskeyRequestNegativeReplyCompleteView::Create(std::move(command_complete_view));
+ ASSERT(user_passkey_request_negative_reply_complete_view.IsValid());
+ status = user_passkey_request_negative_reply_complete_view.GetStatus();
+ auto user_passkey_request_negative_reply_view = UserPasskeyRequestNegativeReplyView::Create(std::move(security_command_view));
+ ASSERT(user_passkey_request_negative_reply_view.IsValid());
+ address = user_passkey_request_negative_reply_view.GetBdAddr();
+ break;
+ }
+ case OpCode::REMOTE_OOB_DATA_REQUEST_REPLY: {
+ auto remote_oob_data_request_reply_complete_view = RemoteOobDataRequestReplyCompleteView::Create(std::move(command_complete_view));
+ ASSERT(remote_oob_data_request_reply_complete_view.IsValid());
+ status = remote_oob_data_request_reply_complete_view.GetStatus();
+ auto remote_oob_data_request_reply_view = RemoteOobDataRequestReplyView::Create(std::move(security_command_view));
+ ASSERT(remote_oob_data_request_reply_view.IsValid());
+ address = remote_oob_data_request_reply_view.GetBdAddr();
+ break;
+ }
+ case OpCode::REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY: {
+ auto remote_oob_data_request_negative_reply_complete_view = RemoteOobDataRequestNegativeReplyCompleteView::Create(std::move(command_complete_view));
+ ASSERT(remote_oob_data_request_negative_reply_complete_view.IsValid());
+ status = remote_oob_data_request_negative_reply_complete_view.GetStatus();
+ auto remote_oob_data_request_negative_reply_view = RemoteOobDataRequestNegativeReplyView::Create(std::move(security_command_view));
+ ASSERT(remote_oob_data_request_negative_reply_view.IsValid());
+ address = remote_oob_data_request_negative_reply_view.GetBdAddr();
+ break;
+ }
+ default:
+ return;
+ }
+ os::LogMetricClassicPairingEvent(
+ address,
+ connection_handle,
+ static_cast<uint32_t>(op_code),
+ static_cast<uint16_t>(event_code),
+ static_cast<uint16_t>(status),
+ static_cast<uint16_t>(reason),
+ value);
+}
+
+void log_remote_device_information(
+ const Address& address, uint32_t connection_handle, ErrorCode status, storage::StorageModule* storage_module) {
+ if (address.IsEmpty()) {
+ return;
+ }
+ const storage::Device device = storage_module->GetDeviceByLegacyKey(address);
+ // log ManufacturerInfo
+ std::stringstream sdp_di_vendor_id_source;
+ // [N - native]::SDP::[DIP - Device ID Profile]
+ sdp_di_vendor_id_source << "N:SDP::DIP::" << common::ToHexString(device.GetSdpDiVendorIdSource().value_or(0)).c_str();
+ os::LogMetricManufacturerInfo(
+ address,
+ android::bluetooth::DeviceInfoSrcEnum::DEVICE_INFO_INTERNAL,
+ sdp_di_vendor_id_source.str(),
+ common::ToHexString(device.GetSdpDiManufacturer().value_or(0)).c_str(),
+ common::ToHexString(device.GetSdpDiModel().value_or(0)).c_str(),
+ common::ToHexString(device.GetSdpDiHardwareVersion().value_or(0)).c_str(),
+ "");
+
+ // log RemoteVersionInfo
+ os::LogMetricRemoteVersionInfo(
+ connection_handle,
+ static_cast<uint16_t>(status),
+ device.GetLmpVersion().value_or(-1),
+ device.GetManufacturerCode().value_or(-1),
+ device.GetLmpSubVersion().value_or(-1));
+}
+
+} // namespace hci
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/hci/hci_metrics_logging.h b/gd/hci/hci_metrics_logging.h
new file mode 100644
index 0000000..c1f9c28
--- /dev/null
+++ b/gd/hci/hci_metrics_logging.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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/hci_packets.h"
+#include "storage/storage_module.h"
+
+namespace bluetooth {
+namespace hci {
+void log_hci_event(
+ std::unique_ptr<CommandView>& command_view, EventView packet, storage::StorageModule* storage_module);
+void log_link_layer_connection_command_status(std::unique_ptr<CommandView>& command_view, ErrorCode status);
+void log_link_layer_connection_command_complete(EventView event, std::unique_ptr<CommandView>& command_view);
+void log_link_layer_connection_event_le_meta(LeMetaEventView le_meta_event_view);
+void log_link_layer_connection_other_hci_event(EventView packet, storage::StorageModule* storage_module);
+
+void log_classic_pairing_command_status(std::unique_ptr<CommandView>& command_view, ErrorCode status);
+void log_classic_pairing_command_complete(EventView event, std::unique_ptr<CommandView>& command_view);
+void log_classic_pairing_other_hci_event(EventView packet);
+
+void log_remote_device_information(
+ const Address& address, uint32_t connection_handle, ErrorCode status, storage::StorageModule* storage_module);
+} // namespace hci
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/hci/hci_packets.pdl b/gd/hci/hci_packets.pdl
index 3f10c20..f740312 100644
--- a/gd/hci/hci_packets.pdl
+++ b/gd/hci/hci_packets.pdl
@@ -226,6 +226,9 @@
ENHANCED_FLUSH = 0x0C5F,
SEND_KEYPRESS_NOTIFICATION = 0x0C60,
+ // Allow stacks to disable AMP events
+ SET_EVENT_MASK_PAGE_2 = 0x0C63,
+
READ_LE_HOST_SUPPORT = 0x0C6C,
WRITE_LE_HOST_SUPPORT = 0x0C6D,
@@ -515,6 +518,7 @@
SEND_KEYPRESS_NOTIFICATION = 202,
IO_CAPABILITY_REQUEST_NEGATIVE_REPLY = 203,
READ_ENCRYPTION_KEY_SIZE = 204,
+ SET_EVENT_MASK_PAGE_2 = 222,
READ_DATA_BLOCK_SIZE = 232,
READ_LE_HOST_SUPPORT = 245,
WRITE_LE_HOST_SUPPORT = 246,
@@ -779,6 +783,7 @@
}
enum ErrorCode: 8 {
+ STATUS_UNKNOWN = 0xFF,
SUCCESS = 0x00,
UNKNOWN_HCI_COMMAND = 0x01,
UNKNOWN_CONNECTION = 0x02,
@@ -4264,8 +4269,12 @@
_reserved_ : 4,
}
+enum LeHostFeatureBits : 8 {
+ CONNECTED_ISO_STREAM_HOST_SUPPORT = 32,
+}
+
packet LeSetHostFeature : Command (op_code = LE_SET_HOST_FEATURE) {
- bit_number : 8,
+ bit_number : LeHostFeatureBits,
bit_value: Enable,
}
@@ -4501,7 +4510,8 @@
READ_RESULT_PARAMETERS = 0x04,
}
-packet LeBatchScan : VendorCommand (op_code = LE_BATCH_SCAN) {
+// https://source.android.com/devices/bluetooth/hci_requirements#batching-of-scan-results
+packet LeBatchScan : LeScanningCommand (op_code = LE_BATCH_SCAN) {
batch_scan_opcode : BatchScanOpcode,
_body_,
}
@@ -4546,8 +4556,24 @@
packet LeBatchScanSetScanParametersComplete : LeBatchScanComplete (batch_scan_opcode = SET_SCAN_PARAMETERS) {
}
-packet LeBatchScanReadTruncatedResultParameters : LeBatchScan (batch_scan_opcode = READ_RESULT_PARAMETERS) {
- _fixed_ = 0x01 : 8,
+enum BatchScanDataRead : 8 {
+ TRUNCATED_MODE_DATA = 0x01,
+ FULL_MODE_DATA = 0x02,
+}
+
+packet LeBatchScanReadResultParameters : LeBatchScan (batch_scan_opcode = READ_RESULT_PARAMETERS) {
+ batch_scan_data_read : BatchScanDataRead,
+}
+
+packet LeBatchScanReadResultParametersCompleteRaw : LeBatchScanComplete (batch_scan_opcode = READ_RESULT_PARAMETERS) {
+ batch_scan_data_read : BatchScanDataRead,
+ num_of_records : 8,
+ raw_data : 8[],
+}
+
+packet LeBatchScanReadResultParametersComplete : LeBatchScanComplete (batch_scan_opcode = READ_RESULT_PARAMETERS) {
+ batch_scan_data_read : BatchScanDataRead,
+ _body_,
}
struct TruncatedResult {
@@ -4558,12 +4584,7 @@
timestamp : 16,
}
-packet LeBatchScanReadTruncatedResultParametersComplete : LeBatchScanComplete (batch_scan_opcode = READ_RESULT_PARAMETERS) {
- _fixed_ = 0x01 : 8,
-}
-
-packet LeBatchScanReadFullResultParameters : LeBatchScan (batch_scan_opcode = READ_RESULT_PARAMETERS) {
- _fixed_ = 0x02 : 8,
+packet LeBatchScanReadTruncatedResultParametersComplete : LeBatchScanReadResultParametersComplete (batch_scan_data_read = TRUNCATED_MODE_DATA) {
_count_(results) : 8,
results : TruncatedResult[],
}
@@ -4580,8 +4601,7 @@
scan_response : 8[],
}
-packet LeBatchScanReadFullResultParametersComplete : LeBatchScanComplete (batch_scan_opcode = READ_RESULT_PARAMETERS) {
- _fixed_ = 0x02 : 8,
+packet LeBatchScanReadFullResultParametersComplete : LeBatchScanReadResultParametersComplete (batch_scan_data_read = FULL_MODE_DATA) {
_count_(results) : 8,
results : FullResult[],
}
@@ -4849,6 +4869,7 @@
}
enum ConnectionRequestLinkType : 8 {
+ UNKNOWN = 0xFF,
SCO = 0x00,
ACL = 0x01,
ESCO = 0x02,
@@ -5611,6 +5632,33 @@
_payload_,
}
+packet StorageThresholdBreachEvent : VendorSpecificEvent (subevent_code = BLE_THRESHOLD) {
+}
+
+enum AdvtInfoPresent : 8 {
+ ADVT_INFO_PRESENT = 0x00,
+ NO_ADVT_INFO_PRESENT = 0x01,
+}
+
+packet LEAdvertisementTrackingEvent : VendorSpecificEvent (subevent_code = BLE_TRACKING) {
+ apcf_filter_index : 8,
+ advertiser_state : 8,
+ advt_info_present : AdvtInfoPresent,
+ advertiser_address : Address,
+ advertiser_address_type : 8,
+ _body_,
+}
+
+packet LEAdvertisementTrackingWithInfoEvent : LEAdvertisementTrackingEvent {
+ tx_power : 8,
+ rssi : 8,
+ timestamp : 16,
+ _size_(adv_packet) : 8,
+ adv_packet : 8[],
+ _size_(scan_response) : 8,
+ scan_response : 8[],
+}
+
enum QualityReportId : 8 {
MONITOR_MODE = 0x01,
APPROACH_LSTO = 0x02,
diff --git a/gd/hci/le_address_manager_test.cc b/gd/hci/le_address_manager_test.cc
index febff37..237a30c 100644
--- a/gd/hci/le_address_manager_test.cc
+++ b/gd/hci/le_address_manager_test.cc
@@ -48,7 +48,7 @@
common::ContextualOnceCallback<void(CommandCompleteView)> on_complete) override {
std::lock_guard<std::mutex> lock(mutex_);
command_queue_.push(std::move(command));
- command_complete_callbacks.push_front(std::move(on_complete));
+ command_complete_callbacks.push_back(std::move(on_complete));
if (command_promise_ != nullptr) {
command_promise_->set_value();
command_promise_.reset();
diff --git a/gd/hci/le_advertising_manager.cc b/gd/hci/le_advertising_manager.cc
index aa18b9b..934e847 100644
--- a/gd/hci/le_advertising_manager.cc
+++ b/gd/hci/le_advertising_manager.cc
@@ -25,6 +25,7 @@
#include "module.h"
#include "os/handler.h"
#include "os/log.h"
+#include "os/system_properties.h"
namespace bluetooth {
namespace hci {
@@ -116,9 +117,15 @@
advertising_api_type_ = AdvertisingApiType::ANDROID_HCI;
} else {
advertising_api_type_ = AdvertisingApiType::LEGACY;
- hci_layer_->EnqueueCommand(
- LeReadAdvertisingPhysicalChannelTxPowerBuilder::Create(),
- handler->BindOnceOn(this, &impl::on_read_advertising_physical_channel_tx_power));
+ int vendor_version = os::GetAndroidVendorReleaseVersion();
+ if (vendor_version != 0 && vendor_version <= 11 && os::IsRootCanalEnabled()) {
+ LOG_INFO("LeReadAdvertisingPhysicalChannelTxPower is not supported on Android R RootCanal, default to 0");
+ le_physical_channel_tx_power_ = 0;
+ } else {
+ hci_layer_->EnqueueCommand(
+ LeReadAdvertisingPhysicalChannelTxPowerBuilder::Create(),
+ handler->BindOnceOn(this, &impl::on_read_advertising_physical_channel_tx_power));
+ }
}
}
@@ -251,7 +258,13 @@
set_data(id, true, config.scan_response);
}
set_data(id, false, config.advertisement);
- advertising_sets_[id].current_address = le_address_manager_->GetAnotherAddress();
+ auto address_policy = le_address_manager_->GetAddressPolicy();
+ if (address_policy == LeAddressManager::AddressPolicy::USE_NON_RESOLVABLE_ADDRESS ||
+ address_policy == LeAddressManager::AddressPolicy::USE_RESOLVABLE_ADDRESS) {
+ advertising_sets_[id].current_address = le_address_manager_->GetAnotherAddress();
+ } else {
+ advertising_sets_[id].current_address = le_address_manager_->GetCurrentAddress();
+ }
le_advertising_interface_->EnqueueCommand(
hci::LeMultiAdvtSetRandomAddrBuilder::Create(advertising_sets_[id].current_address.GetAddress(), id),
module_handler_->BindOnce(impl::check_status<LeMultiAdvtCompleteView>));
@@ -429,6 +442,7 @@
void set_parameters(AdvertiserId advertiser_id, ExtendedAdvertisingConfig config) {
advertising_sets_[advertiser_id].connectable = config.connectable;
+ advertising_sets_[advertiser_id].tx_power = config.tx_power;
switch (advertising_api_type_) {
case (AdvertisingApiType::LEGACY): {
@@ -547,6 +561,14 @@
data.insert(data.begin(), gap_data);
}
+ // Find and fill TX Power with the correct value.
+ for (auto& gap_data : data) {
+ if (gap_data.data_type_ == GapDataType::TX_POWER_LEVEL) {
+ gap_data.data_[0] = advertising_sets_[advertiser_id].tx_power;
+ break;
+ }
+ }
+
switch (advertising_api_type_) {
case (AdvertisingApiType::LEGACY): {
if (set_scan_rsp) {
diff --git a/gd/hci/le_scanning_manager.cc b/gd/hci/le_scanning_manager.cc
index cd3c499..a8e532f 100644
--- a/gd/hci/le_scanning_manager.cc
+++ b/gd/hci/le_scanning_manager.cc
@@ -23,6 +23,7 @@
#include "hci/hci_packets.h"
#include "hci/le_scanning_interface.h"
#include "hci/le_scanning_manager.h"
+#include "hci/vendor_specific_event_manager.h"
#include "module.h"
#include "os/handler.h"
#include "os/log.h"
@@ -132,6 +133,72 @@
std::list<Item> items;
};
+class NullScanningCallback : public ScanningCallback {
+ void OnScannerRegistered(const bluetooth::hci::Uuid app_uuid, ScannerId scanner_id, ScanningStatus status) {
+ LOG_INFO("OnScannerRegistered in NullScanningCallback");
+ }
+ void OnSetScannerParameterComplete(ScannerId scanner_id, ScanningStatus status) {
+ LOG_INFO("OnSetScannerParameterComplete in NullScanningCallback");
+ }
+ void OnScanResult(
+ uint16_t event_type,
+ uint8_t address_type,
+ Address address,
+ uint8_t primary_phy,
+ uint8_t secondary_phy,
+ uint8_t advertising_sid,
+ int8_t tx_power,
+ int8_t rssi,
+ uint16_t periodic_advertising_interval,
+ std::vector<uint8_t> advertising_data) {
+ LOG_INFO("OnScanResult in NullScanningCallback");
+ }
+ void OnTrackAdvFoundLost(AdvertisingFilterOnFoundOnLostInfo on_found_on_lost_info) {
+ LOG_INFO("OnTrackAdvFoundLost in NullScanningCallback");
+ }
+ void OnBatchScanReports(int client_if, int status, int report_format, int num_records, std::vector<uint8_t> data) {
+ LOG_INFO("OnBatchScanReports in NullScanningCallback");
+ }
+ void OnBatchScanThresholdCrossed(int client_if) {
+ LOG_INFO("OnBatchScanThresholdCrossed in NullScanningCallback");
+ }
+ void OnTimeout() {
+ LOG_INFO("OnTimeout in NullScanningCallback");
+ }
+ void OnFilterEnable(Enable enable, uint8_t status) {
+ LOG_INFO("OnFilterEnable in NullScanningCallback");
+ }
+ void OnFilterParamSetup(uint8_t available_spaces, ApcfAction action, uint8_t status) {
+ LOG_INFO("OnFilterParamSetup in NullScanningCallback");
+ }
+ void OnFilterConfigCallback(
+ ApcfFilterType filter_type, uint8_t available_spaces, ApcfAction action, uint8_t status) {
+ LOG_INFO("OnFilterConfigCallback in NullScanningCallback");
+ }
+};
+
+enum class BatchScanState {
+ ERROR_STATE = 0,
+ ENABLE_CALLED = 1,
+ ENABLED_STATE = 2,
+ DISABLE_CALLED = 3,
+ DISABLED_STATE = 4,
+};
+
+#define BTM_BLE_BATCH_SCAN_MODE_DISABLE 0
+#define BTM_BLE_BATCH_SCAN_MODE_PASS 1
+#define BTM_BLE_BATCH_SCAN_MODE_ACTI 2
+#define BTM_BLE_BATCH_SCAN_MODE_PASS_ACTI 3
+
+struct BatchScanConfig {
+ BatchScanState current_state;
+ BatchScanMode scan_mode;
+ uint32_t scan_interval;
+ uint32_t scan_window;
+ BatchScanDiscardRule discard_rule;
+ ScannerId ref_value;
+};
+
struct LeScanningManager::impl : public bluetooth::hci::LeAddressManagerCallback {
impl(Module* module) : module_(module), le_scanning_interface_(nullptr) {}
@@ -141,11 +208,16 @@
}
}
- void start(os::Handler* handler, hci::HciLayer* hci_layer, hci::Controller* controller,
- hci::AclManager* acl_manager) {
+ void start(
+ os::Handler* handler,
+ hci::HciLayer* hci_layer,
+ hci::Controller* controller,
+ hci::AclManager* acl_manager,
+ hci::VendorSpecificEventManager* vendor_specific_event_manager) {
module_handler_ = handler;
hci_layer_ = hci_layer;
controller_ = controller;
+ vendor_specific_event_manager_ = vendor_specific_event_manager;
le_address_manager_ = acl_manager->GetLeAddressManager();
le_scanning_interface_ = hci_layer_->GetLeScanningInterface(
module_handler_->BindOn(this, &LeScanningManager::impl::handle_scan_results));
@@ -159,14 +231,37 @@
api_type_ = ScanApiType::LEGACY;
}
is_filter_support_ = controller_->IsSupported(OpCode::LE_ADV_FILTER);
+ is_batch_scan_support_ = controller->IsSupported(OpCode::LE_BATCH_SCAN);
+ if (is_batch_scan_support_) {
+ vendor_specific_event_manager_->RegisterEventHandler(
+ VseSubeventCode::BLE_THRESHOLD, handler->BindOn(this, &LeScanningManager::impl::on_storage_threshold_breach));
+ vendor_specific_event_manager_->RegisterEventHandler(
+ VseSubeventCode::BLE_TRACKING, handler->BindOn(this, &LeScanningManager::impl::on_advertisement_tracking));
+ }
scanners_ = std::vector<Scanner>(kMaxAppNum + 1);
for (size_t i = 0; i < scanners_.size(); i++) {
scanners_[i].app_uuid = Uuid::kEmpty;
scanners_[i].in_use = false;
}
+ batch_scan_config_.current_state = BatchScanState::DISABLED_STATE;
+ batch_scan_config_.ref_value = kInvalidScannerId;
configure_scan();
}
+ void stop() {
+ for (auto subevent_code : LeScanningEvents) {
+ hci_layer_->UnregisterLeEventHandler(subevent_code);
+ }
+ if (is_batch_scan_support_) {
+ // TODO implete vse module
+ // hci_layer_->UnregisterVesEventHandler(VseSubeventCode::BLE_THRESHOLD);
+ // hci_layer_->UnregisterVesEventHandler(VseSubeventCode::BLE_TRACKING);
+ }
+ batch_scan_config_.current_state = BatchScanState::DISABLED_STATE;
+ batch_scan_config_.ref_value = kInvalidScannerId;
+ scanning_callbacks_ = &null_scanning_callback_;
+ }
+
void handle_scan_results(LeMetaEventView event) {
switch (event.GetSubeventCode()) {
case hci::SubeventCode::ADVERTISING_REPORT:
@@ -179,9 +274,7 @@
handle_extended_advertising_report(LeExtendedAdvertisingReportView::Create(event));
break;
case hci::SubeventCode::SCAN_TIMEOUT:
- if (scanning_callbacks_ != nullptr) {
- scanning_callbacks_->OnTimeout();
- }
+ scanning_callbacks_->OnTimeout();
break;
default:
LOG_ALWAYS_FATAL("Unknown advertising subevent %s", hci::SubeventCodeText(event.GetSubeventCode()).c_str());
@@ -207,10 +300,6 @@
}
void handle_advertising_report(LeAdvertisingReportView event_view) {
- if (scanning_callbacks_ == nullptr) {
- LOG_INFO("Dropping advertising event (no registered handler)");
- return;
- }
if (!event_view.IsValid()) {
LOG_INFO("Dropping invalid advertising event");
return;
@@ -269,10 +358,6 @@
}
void handle_directed_advertising_report(LeDirectedAdvertisingReportView event_view) {
- if (scanning_callbacks_ == nullptr) {
- LOG_INFO("Dropping advertising event (no registered handler)");
- return;
- }
if (!event_view.IsValid()) {
LOG_INFO("Dropping invalid advertising event");
return;
@@ -288,10 +373,6 @@
}
void handle_extended_advertising_report(LeExtendedAdvertisingReportView event_view) {
- if (scanning_callbacks_ == nullptr) {
- LOG_INFO("Dropping advertising event (no registered handler)");
- return;
- }
if (!event_view.IsValid()) {
LOG_INFO("Dropping invalid advertising event");
return;
@@ -334,7 +415,25 @@
bool is_scannable = event_type & (1 << kScannableBit);
bool is_scan_response = event_type & (1 << kScanResponseBit);
bool is_legacy = event_type & (1 << kLegacyBit);
- // TODO handle anonymous advertisement (0xFF)
+
+ if (address_type == (uint8_t)DirectAdvertisingAddressType::NO_ADDRESS) {
+ scanning_callbacks_->OnScanResult(
+ event_type,
+ address_type,
+ address,
+ primary_phy,
+ secondary_phy,
+ advertising_sid,
+ tx_power,
+ rssi,
+ periodic_advertising_interval,
+ advertising_data);
+ return;
+ } else if (address == Address::kEmpty) {
+ LOG_WARN("Receive non-anonymous advertising report with empty address, skip!");
+ return;
+ }
+
AddressWithType address_with_type(address, (AddressType)address_type);
if (is_legacy && is_scan_response && !advertising_cache_.Exist(address_with_type)) {
@@ -390,22 +489,23 @@
switch (api_type_) {
case ScanApiType::EXTENDED:
- le_scanning_interface_->EnqueueCommand(hci::LeSetExtendedScanParametersBuilder::Create(
- own_address_type_, filter_policy_, phys_in_use, parameter_vector),
- module_handler_->BindOnce(impl::check_status));
+ le_scanning_interface_->EnqueueCommand(
+ hci::LeSetExtendedScanParametersBuilder::Create(
+ own_address_type_, filter_policy_, phys_in_use, parameter_vector),
+ module_handler_->BindOnceOn(this, &impl::on_set_scan_parameter_complete));
break;
case ScanApiType::ANDROID_HCI:
le_scanning_interface_->EnqueueCommand(
- hci::LeExtendedScanParamsBuilder::Create(LeScanType::ACTIVE, interval_ms_, window_ms_, own_address_type_,
- filter_policy_),
- module_handler_->BindOnce(impl::check_status));
+ hci::LeExtendedScanParamsBuilder::Create(
+ LeScanType::ACTIVE, interval_ms_, window_ms_, own_address_type_, filter_policy_),
+ module_handler_->BindOnceOn(this, &impl::on_set_scan_parameter_complete));
break;
case ScanApiType::LEGACY:
le_scanning_interface_->EnqueueCommand(
- hci::LeSetScanParametersBuilder::Create(LeScanType::ACTIVE, interval_ms_, window_ms_, own_address_type_,
- filter_policy_),
- module_handler_->BindOnce(impl::check_status));
+ hci::LeSetScanParametersBuilder::Create(
+ LeScanType::ACTIVE, interval_ms_, window_ms_, own_address_type_, filter_policy_),
+ module_handler_->BindOnceOn(this, &impl::on_set_scan_parameter_complete));
break;
}
}
@@ -489,6 +589,10 @@
}
void stop_scan() {
+ if (!is_scanning_) {
+ LOG_INFO("Scanning already stopped, return!");
+ return;
+ }
is_scanning_ = false;
switch (api_type_) {
@@ -507,7 +611,7 @@
}
}
- void set_scan_parameters(LeScanType scan_type, uint16_t scan_interval, uint16_t scan_window) {
+ void set_scan_parameters(ScannerId scanner_id, LeScanType scan_type, uint16_t scan_interval, uint16_t scan_window) {
uint32_t max_scan_interval = kLeScanIntervalMax;
uint32_t max_scan_window = kLeScanWindowMax;
if (api_type_ == ScanApiType::EXTENDED) {
@@ -517,19 +621,26 @@
if (scan_type != LeScanType::ACTIVE && scan_type != LeScanType::PASSIVE) {
LOG_ERROR("Invalid scan type");
+ scanning_callbacks_->OnSetScannerParameterComplete(
+ scanner_id, ScanningCallback::ScanningStatus::ILLEGAL_PARAMETER);
return;
}
if (scan_interval > max_scan_interval || scan_interval < kLeScanIntervalMin) {
LOG_ERROR("Invalid scan_interval %d", scan_interval);
+ scanning_callbacks_->OnSetScannerParameterComplete(
+ scanner_id, ScanningCallback::ScanningStatus::ILLEGAL_PARAMETER);
return;
}
if (scan_window > max_scan_window || scan_window < kLeScanWindowMin) {
LOG_ERROR("Invalid scan_window %d", scan_window);
+ scanning_callbacks_->OnSetScannerParameterComplete(
+ scanner_id, ScanningCallback::ScanningStatus::ILLEGAL_PARAMETER);
return;
}
le_scan_type_ = scan_type;
interval_ms_ = scan_interval;
window_ms_ = scan_window;
+ scanning_callbacks_->OnSetScannerParameterComplete(scanner_id, ScanningCallback::SUCCESS);
}
void scan_filter_enable(bool enable) {
@@ -754,10 +865,194 @@
module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete));
}
+ void batch_scan_set_storage_parameter(
+ uint8_t batch_scan_full_max,
+ uint8_t batch_scan_truncated_max,
+ uint8_t batch_scan_notify_threshold,
+ ScannerId scanner_id) {
+ if (!is_batch_scan_support_) {
+ LOG_WARN("Batch scan is not supported");
+ return;
+ }
+ // scanner id for OnBatchScanThresholdCrossed
+ batch_scan_config_.ref_value = scanner_id;
+
+ if (batch_scan_config_.current_state == BatchScanState::ERROR_STATE ||
+ batch_scan_config_.current_state == BatchScanState::DISABLED_STATE ||
+ batch_scan_config_.current_state == BatchScanState::DISABLE_CALLED) {
+ batch_scan_config_.current_state = BatchScanState::ENABLE_CALLED;
+ le_scanning_interface_->EnqueueCommand(
+ LeBatchScanEnableBuilder::Create(Enable::ENABLED),
+ module_handler_->BindOnceOn(this, &impl::on_batch_scan_enable_complete));
+ }
+
+ le_scanning_interface_->EnqueueCommand(
+ LeBatchScanSetStorageParametersBuilder::Create(
+ batch_scan_full_max, batch_scan_truncated_max, batch_scan_notify_threshold),
+ module_handler_->BindOnceOn(this, &impl::on_batch_scan_complete));
+ }
+
+ void batch_scan_enable(
+ BatchScanMode scan_mode,
+ uint32_t duty_cycle_scan_window_slots,
+ uint32_t duty_cycle_scan_interval_slots,
+ BatchScanDiscardRule batch_scan_discard_rule) {
+ if (!is_batch_scan_support_) {
+ LOG_WARN("Batch scan is not supported");
+ return;
+ }
+
+ if (batch_scan_config_.current_state == BatchScanState::ERROR_STATE ||
+ batch_scan_config_.current_state == BatchScanState::DISABLED_STATE ||
+ batch_scan_config_.current_state == BatchScanState::DISABLE_CALLED) {
+ batch_scan_config_.current_state = BatchScanState::ENABLE_CALLED;
+ le_scanning_interface_->EnqueueCommand(
+ LeBatchScanEnableBuilder::Create(Enable::ENABLED),
+ module_handler_->BindOnceOn(this, &impl::on_batch_scan_enable_complete));
+ }
+
+ batch_scan_config_.scan_mode = scan_mode;
+ batch_scan_config_.scan_interval = duty_cycle_scan_interval_slots;
+ batch_scan_config_.scan_window = duty_cycle_scan_window_slots;
+ batch_scan_config_.discard_rule = batch_scan_discard_rule;
+ /* This command starts batch scanning, if enabled */
+ batch_scan_set_scan_parameter(
+ scan_mode, duty_cycle_scan_window_slots, duty_cycle_scan_interval_slots, batch_scan_discard_rule);
+ }
+
+ void batch_scan_disable() {
+ if (!is_batch_scan_support_) {
+ LOG_WARN("Batch scan is not supported");
+ return;
+ }
+ batch_scan_config_.current_state = BatchScanState::DISABLE_CALLED;
+ batch_scan_set_scan_parameter(
+ BatchScanMode::DISABLE,
+ batch_scan_config_.scan_window,
+ batch_scan_config_.scan_interval,
+ batch_scan_config_.discard_rule);
+ }
+
+ void batch_scan_set_scan_parameter(
+ BatchScanMode scan_mode,
+ uint32_t duty_cycle_scan_window_slots,
+ uint32_t duty_cycle_scan_interval_slots,
+ BatchScanDiscardRule batch_scan_discard_rule) {
+ if (!is_batch_scan_support_) {
+ LOG_WARN("Batch scan is not supported");
+ return;
+ }
+ AdvertisingAddressType own_address_type = AdvertisingAddressType::PUBLIC_ADDRESS;
+ if (own_address_type_ == OwnAddressType::RANDOM_DEVICE_ADDRESS ||
+ own_address_type_ == OwnAddressType::RESOLVABLE_OR_RANDOM_ADDRESS) {
+ own_address_type = AdvertisingAddressType::RANDOM_ADDRESS;
+ }
+ uint8_t truncated_mode_enabled = 0x00;
+ uint8_t full_mode_enabled = 0x00;
+ if (scan_mode == BatchScanMode::TRUNCATED || scan_mode == BatchScanMode::TRUNCATED_AND_FULL) {
+ truncated_mode_enabled = 0x01;
+ }
+ if (scan_mode == BatchScanMode::FULL || scan_mode == BatchScanMode::TRUNCATED_AND_FULL) {
+ full_mode_enabled = 0x01;
+ }
+
+ if (scan_mode == BatchScanMode::DISABLE) {
+ le_scanning_interface_->EnqueueCommand(
+ LeBatchScanSetScanParametersBuilder::Create(
+ truncated_mode_enabled,
+ full_mode_enabled,
+ duty_cycle_scan_window_slots,
+ duty_cycle_scan_interval_slots,
+ own_address_type,
+ batch_scan_discard_rule),
+ module_handler_->BindOnceOn(this, &impl::on_batch_scan_disable_complete));
+ } else {
+ le_scanning_interface_->EnqueueCommand(
+ LeBatchScanSetScanParametersBuilder::Create(
+ truncated_mode_enabled,
+ full_mode_enabled,
+ duty_cycle_scan_window_slots,
+ duty_cycle_scan_interval_slots,
+ own_address_type,
+ batch_scan_discard_rule),
+ module_handler_->BindOnceOn(this, &impl::on_batch_scan_complete));
+ }
+ }
+
+ void batch_scan_read_results(ScannerId scanner_id, uint16_t total_num_of_records, BatchScanMode scan_mode) {
+ if (!is_batch_scan_support_) {
+ LOG_WARN("Batch scan is not supported");
+ int status = static_cast<int>(ErrorCode::UNSUPORTED_FEATURE_OR_PARAMETER_VALUE);
+ scanning_callbacks_->OnBatchScanReports(scanner_id, status, 0, 0, {});
+ return;
+ }
+
+ if (scan_mode != BatchScanMode::FULL && scan_mode != BatchScanMode::TRUNCATED) {
+ LOG_WARN("Invalid scan mode %d", (uint16_t)scan_mode);
+ int status = static_cast<int>(ErrorCode::INVALID_HCI_COMMAND_PARAMETERS);
+ scanning_callbacks_->OnBatchScanReports(scanner_id, status, 0, 0, {});
+ return;
+ }
+
+ if (batch_scan_result_cache_.find(scanner_id) == batch_scan_result_cache_.end()) {
+ std::vector<uint8_t> empty_data = {};
+ batch_scan_result_cache_.emplace(scanner_id, empty_data);
+ }
+
+ le_scanning_interface_->EnqueueCommand(
+ LeBatchScanReadResultParametersBuilder::Create(static_cast<BatchScanDataRead>(scan_mode)),
+ module_handler_->BindOnceOn(this, &impl::on_batch_scan_read_result_complete, scanner_id, total_num_of_records));
+ }
+
+ void track_advertiser(ScannerId scanner_id) {
+ if (!is_batch_scan_support_) {
+ LOG_WARN("Batch scan is not supported");
+ AdvertisingFilterOnFoundOnLostInfo on_found_on_lost_info = {};
+ on_found_on_lost_info.scanner_id = scanner_id;
+ on_found_on_lost_info.advertiser_info_present = AdvtInfoPresent::NO_ADVT_INFO_PRESENT;
+ scanning_callbacks_->OnTrackAdvFoundLost(on_found_on_lost_info);
+ return;
+ }
+ tracker_id = scanner_id;
+ }
+
void register_scanning_callback(ScanningCallback* scanning_callbacks) {
scanning_callbacks_ = scanning_callbacks;
}
+ void on_set_scan_parameter_complete(CommandCompleteView view) {
+ switch (view.GetCommandOpCode()) {
+ case (OpCode::LE_SET_SCAN_PARAMETERS): {
+ auto status_view = LeSetScanParametersCompleteView::Create(view);
+ ASSERT(status_view.IsValid());
+ if (status_view.GetStatus() != ErrorCode::SUCCESS) {
+ LOG_INFO(
+ "Receive set scan parameter complete with error code %s", ErrorCodeText(status_view.GetStatus()).c_str());
+ }
+ } break;
+ case (OpCode::LE_EXTENDED_SCAN_PARAMS): {
+ auto status_view = LeExtendedScanParamsCompleteView::Create(view);
+ ASSERT(status_view.IsValid());
+ if (status_view.GetStatus() != ErrorCode::SUCCESS) {
+ LOG_INFO(
+ "Receive extended scan parameter complete with error code %s",
+ ErrorCodeText(status_view.GetStatus()).c_str());
+ }
+ } break;
+ case (OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS): {
+ auto status_view = LeSetExtendedScanParametersCompleteView::Create(view);
+ ASSERT(status_view.IsValid());
+ if (status_view.GetStatus() != ErrorCode::SUCCESS) {
+ LOG_INFO(
+ "Receive set extended scan parameter complete with error code %s",
+ ErrorCodeText(status_view.GetStatus()).c_str());
+ }
+ } break;
+ default:
+ LOG_ALWAYS_FATAL("Unhandled event %s", OpCodeText(view.GetCommandOpCode()).c_str());
+ }
+ }
+
void on_advertising_filter_complete(CommandCompleteView view) {
ASSERT(view.IsValid());
auto status_view = LeAdvFilterCompleteView::Create(view);
@@ -841,6 +1136,108 @@
}
}
+ void on_batch_scan_complete(CommandCompleteView view) {
+ ASSERT(view.IsValid());
+ auto status_view = LeBatchScanCompleteView::Create(view);
+ ASSERT(status_view.IsValid());
+ if (status_view.GetStatus() != ErrorCode::SUCCESS) {
+ LOG_INFO(
+ "Got a Command complete %s, status %s, batch_scan_opcode %s",
+ OpCodeText(view.GetCommandOpCode()).c_str(),
+ ErrorCodeText(status_view.GetStatus()).c_str(),
+ BatchScanOpcodeText(status_view.GetBatchScanOpcode()).c_str());
+ }
+ }
+
+ void on_batch_scan_enable_complete(CommandCompleteView view) {
+ ASSERT(view.IsValid());
+ auto status_view = LeBatchScanCompleteView::Create(view);
+ ASSERT(status_view.IsValid());
+ auto complete_view = LeBatchScanEnableCompleteView::Create(status_view);
+ ASSERT(complete_view.IsValid());
+ if (status_view.GetStatus() != ErrorCode::SUCCESS) {
+ LOG_INFO("Got batch scan enable complete, status %s", ErrorCodeText(status_view.GetStatus()).c_str());
+ batch_scan_config_.current_state = BatchScanState::ERROR_STATE;
+ } else {
+ batch_scan_config_.current_state = BatchScanState::ENABLED_STATE;
+ }
+ }
+
+ void on_batch_scan_disable_complete(CommandCompleteView view) {
+ ASSERT(view.IsValid());
+ auto status_view = LeBatchScanCompleteView::Create(view);
+ ASSERT(status_view.IsValid());
+ auto complete_view = LeBatchScanSetScanParametersCompleteView::Create(status_view);
+ ASSERT(complete_view.IsValid());
+ ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS);
+ batch_scan_config_.current_state = BatchScanState::DISABLED_STATE;
+ }
+
+ void on_batch_scan_read_result_complete(
+ ScannerId scanner_id, uint16_t total_num_of_records, CommandCompleteView view) {
+ ASSERT(view.IsValid());
+ auto status_view = LeBatchScanCompleteView::Create(view);
+ ASSERT(status_view.IsValid());
+ auto complete_view = LeBatchScanReadResultParametersCompleteRawView::Create(status_view);
+ ASSERT(complete_view.IsValid());
+ if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+ LOG_INFO("Got batch scan read result complete, status %s", ErrorCodeText(status_view.GetStatus()).c_str());
+ }
+ uint8_t num_of_records = complete_view.GetNumOfRecords();
+ auto report_format = complete_view.GetBatchScanDataRead();
+ if (num_of_records == 0) {
+ scanning_callbacks_->OnBatchScanReports(
+ scanner_id, 0x00, (int)report_format, total_num_of_records, batch_scan_result_cache_[scanner_id]);
+ batch_scan_result_cache_.erase(scanner_id);
+ } else {
+ auto raw_data = complete_view.GetRawData();
+ batch_scan_result_cache_[scanner_id].insert(
+ batch_scan_result_cache_[scanner_id].end(), raw_data.begin(), raw_data.end());
+ total_num_of_records += num_of_records;
+ batch_scan_read_results(scanner_id, total_num_of_records, static_cast<BatchScanMode>(report_format));
+ }
+ }
+
+ void on_storage_threshold_breach(VendorSpecificEventView event) {
+ if (batch_scan_config_.ref_value == kInvalidScannerId) {
+ LOG_WARN("storage threshold was not set !!");
+ return;
+ }
+ scanning_callbacks_->OnBatchScanThresholdCrossed(static_cast<int>(batch_scan_config_.ref_value));
+ }
+
+ void on_advertisement_tracking(VendorSpecificEventView event) {
+ if (tracker_id == kInvalidScannerId) {
+ LOG_WARN("Advertisement track is not register");
+ return;
+ }
+ auto view = LEAdvertisementTrackingEventView::Create(event);
+ ASSERT(view.IsValid());
+ AdvertisingFilterOnFoundOnLostInfo on_found_on_lost_info = {};
+ on_found_on_lost_info.scanner_id = tracker_id;
+ on_found_on_lost_info.filter_index = view.GetApcfFilterIndex();
+ on_found_on_lost_info.advertiser_state = view.GetAdvertiserState();
+ on_found_on_lost_info.advertiser_address = view.GetAdvertiserAddress();
+ on_found_on_lost_info.advertiser_address_type = view.GetAdvertiserAddressType();
+ on_found_on_lost_info.advertiser_info_present = view.GetAdvtInfoPresent();
+ /* Extract the adv info details */
+ if (on_found_on_lost_info.advertiser_info_present == AdvtInfoPresent::ADVT_INFO_PRESENT) {
+ auto info_view = LEAdvertisementTrackingWithInfoEventView::Create(view);
+ ASSERT(info_view.IsValid());
+ on_found_on_lost_info.tx_power = info_view.GetTxPower();
+ on_found_on_lost_info.rssi = info_view.GetRssi();
+ on_found_on_lost_info.time_stamp = info_view.GetTimestamp();
+ auto adv_data = info_view.GetAdvPacket();
+ on_found_on_lost_info.adv_packet.reserve(adv_data.size());
+ on_found_on_lost_info.adv_packet.insert(on_found_on_lost_info.adv_packet.end(), adv_data.begin(), adv_data.end());
+ auto scan_rsp_data = info_view.GetScanResponse();
+ on_found_on_lost_info.scan_response.reserve(scan_rsp_data.size());
+ on_found_on_lost_info.scan_response.insert(
+ on_found_on_lost_info.scan_response.end(), scan_rsp_data.begin(), scan_rsp_data.end());
+ }
+ scanning_callbacks_->OnTrackAdvFoundLost(on_found_on_lost_info);
+ }
+
void OnPause() override {
paused_ = true;
scan_on_resume_ = is_scanning_;
@@ -866,49 +1263,46 @@
os::Handler* module_handler_;
hci::HciLayer* hci_layer_;
hci::Controller* controller_;
+ hci::VendorSpecificEventManager* vendor_specific_event_manager_;
hci::LeScanningInterface* le_scanning_interface_;
hci::LeAddressManager* le_address_manager_;
bool address_manager_registered_ = false;
- ScanningCallback* scanning_callbacks_ = nullptr;
+ NullScanningCallback null_scanning_callback_;
+ ScanningCallback* scanning_callbacks_ = &null_scanning_callback_;
std::vector<Scanner> scanners_;
bool is_scanning_ = false;
bool scan_on_resume_ = false;
bool paused_ = false;
AdvertisingCache advertising_cache_;
bool is_filter_support_ = false;
+ bool is_batch_scan_support_ = false;
LeScanType le_scan_type_ = LeScanType::ACTIVE;
uint32_t interval_ms_{1000};
uint16_t window_ms_{1000};
OwnAddressType own_address_type_{OwnAddressType::PUBLIC_DEVICE_ADDRESS};
LeScanningFilterPolicy filter_policy_{LeScanningFilterPolicy::ACCEPT_ALL};
+ BatchScanConfig batch_scan_config_;
+ std::map<ScannerId, std::vector<uint8_t>> batch_scan_result_cache_;
+ ScannerId tracker_id = kInvalidScannerId;
static void check_status(CommandCompleteView view) {
switch (view.GetCommandOpCode()) {
case (OpCode::LE_SET_SCAN_ENABLE): {
auto status_view = LeSetScanEnableCompleteView::Create(view);
ASSERT(status_view.IsValid());
- ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS);
+ ASSERT_LOG(
+ status_view.GetStatus() == ErrorCode::SUCCESS,
+ "Receive set scan enable with error code %s",
+ ErrorCodeText(status_view.GetStatus()).c_str());
} break;
case (OpCode::LE_SET_EXTENDED_SCAN_ENABLE): {
auto status_view = LeSetExtendedScanEnableCompleteView::Create(view);
ASSERT(status_view.IsValid());
- ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS);
- } break;
- case (OpCode::LE_SET_SCAN_PARAMETERS): {
- auto status_view = LeSetScanParametersCompleteView::Create(view);
- ASSERT(status_view.IsValid());
- ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS);
- } break;
- case (OpCode::LE_EXTENDED_SCAN_PARAMS): {
- auto status_view = LeExtendedScanParamsCompleteView::Create(view);
- ASSERT(status_view.IsValid());
- ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS);
- } break;
- case (OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS): {
- auto status_view = LeSetExtendedScanParametersCompleteView::Create(view);
- ASSERT(status_view.IsValid());
- ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS);
+ ASSERT_LOG(
+ status_view.GetStatus() == ErrorCode::SUCCESS,
+ "Receive set extended scan enable with error code %s",
+ ErrorCodeText(status_view.GetStatus()).c_str());
} break;
default:
LOG_ALWAYS_FATAL("Unhandled event %s", OpCodeText(view.GetCommandOpCode()).c_str());
@@ -922,16 +1316,22 @@
void LeScanningManager::ListDependencies(ModuleList* list) {
list->add<hci::HciLayer>();
+ list->add<hci::VendorSpecificEventManager>();
list->add<hci::Controller>();
list->add<hci::AclManager>();
}
void LeScanningManager::Start() {
- pimpl_->start(GetHandler(), GetDependency<hci::HciLayer>(), GetDependency<hci::Controller>(),
- GetDependency<AclManager>());
+ pimpl_->start(
+ GetHandler(),
+ GetDependency<hci::HciLayer>(),
+ GetDependency<hci::Controller>(),
+ GetDependency<AclManager>(),
+ GetDependency<VendorSpecificEventManager>());
}
void LeScanningManager::Stop() {
+ pimpl_->stop();
pimpl_.reset();
}
@@ -951,8 +1351,9 @@
CallOn(pimpl_.get(), &impl::scan, start);
}
-void LeScanningManager::SetScanParameters(LeScanType scan_type, uint16_t scan_interval, uint16_t scan_window) {
- CallOn(pimpl_.get(), &impl::set_scan_parameters, scan_type, scan_interval, scan_window);
+void LeScanningManager::SetScanParameters(
+ ScannerId scanner_id, LeScanType scan_type, uint16_t scan_interval, uint16_t scan_window) {
+ CallOn(pimpl_.get(), &impl::set_scan_parameters, scanner_id, scan_type, scan_interval, scan_window);
}
void LeScanningManager::ScanFilterEnable(bool enable) {
@@ -969,6 +1370,46 @@
CallOn(pimpl_.get(), &impl::scan_filter_add, filter_index, filters);
}
+void LeScanningManager::BatchScanConifgStorage(
+ uint8_t batch_scan_full_max,
+ uint8_t batch_scan_truncated_max,
+ uint8_t batch_scan_notify_threshold,
+ ScannerId scanner_id) {
+ CallOn(
+ pimpl_.get(),
+ &impl::batch_scan_set_storage_parameter,
+ batch_scan_full_max,
+ batch_scan_truncated_max,
+ batch_scan_notify_threshold,
+ scanner_id);
+}
+
+void LeScanningManager::BatchScanEnable(
+ BatchScanMode scan_mode,
+ uint32_t duty_cycle_scan_window_slots,
+ uint32_t duty_cycle_scan_interval_slots,
+ BatchScanDiscardRule batch_scan_discard_rule) {
+ CallOn(
+ pimpl_.get(),
+ &impl::batch_scan_enable,
+ scan_mode,
+ duty_cycle_scan_window_slots,
+ duty_cycle_scan_interval_slots,
+ batch_scan_discard_rule);
+}
+
+void LeScanningManager::BatchScanDisable() {
+ CallOn(pimpl_.get(), &impl::batch_scan_disable);
+}
+
+void LeScanningManager::BatchScanReadReport(ScannerId scanner_id, BatchScanMode scan_mode) {
+ CallOn(pimpl_.get(), &impl::batch_scan_read_results, scanner_id, 0, scan_mode);
+}
+
+void LeScanningManager::TrackAdvertiser(ScannerId scanner_id) {
+ CallOn(pimpl_.get(), &impl::track_advertiser, scanner_id);
+}
+
void LeScanningManager::RegisterScanningCallback(ScanningCallback* scanning_callback) {
CallOn(pimpl_.get(), &impl::register_scanning_callback, scanning_callback);
}
diff --git a/gd/hci/le_scanning_manager.h b/gd/hci/le_scanning_manager.h
index 751b7be..35c619b 100644
--- a/gd/hci/le_scanning_manager.h
+++ b/gd/hci/le_scanning_manager.h
@@ -28,17 +28,34 @@
using ScannerId = uint8_t;
+class AdvertisingFilterOnFoundOnLostInfo {
+ public:
+ uint8_t scanner_id;
+ uint8_t filter_index;
+ uint8_t advertiser_state;
+ AdvtInfoPresent advertiser_info_present;
+ Address advertiser_address;
+ uint8_t advertiser_address_type;
+ uint8_t tx_power;
+ int8_t rssi;
+ uint16_t time_stamp;
+ std::vector<uint8_t> adv_packet;
+ std::vector<uint8_t> scan_response;
+};
+
class ScanningCallback {
public:
enum ScanningStatus {
SUCCESS,
NO_RESOURCES = 0x80,
INTERNAL_ERROR = 0x85,
+ ILLEGAL_PARAMETER = 0x87,
};
virtual ~ScanningCallback() = default;
virtual void OnScannerRegistered(
const bluetooth::hci::Uuid app_uuid, ScannerId scanner_id, ScanningStatus status) = 0;
+ virtual void OnSetScannerParameterComplete(ScannerId scanner_id, ScanningStatus status) = 0;
virtual void OnScanResult(
uint16_t event_type,
uint8_t address_type,
@@ -50,9 +67,10 @@
int8_t rssi,
uint16_t periodic_advertising_interval,
std::vector<uint8_t> advertising_data) = 0;
- virtual void OnTrackAdvFoundLost() = 0;
+ virtual void OnTrackAdvFoundLost(AdvertisingFilterOnFoundOnLostInfo on_found_on_lost_info) = 0;
virtual void OnBatchScanReports(
int client_if, int status, int report_format, int num_records, std::vector<uint8_t> data) = 0;
+ virtual void OnBatchScanThresholdCrossed(int client_if) = 0;
virtual void OnTimeout() = 0;
virtual void OnFilterEnable(Enable enable, uint8_t status) = 0;
virtual void OnFilterParamSetup(uint8_t available_spaces, ApcfAction action, uint8_t status) = 0;
@@ -88,12 +106,20 @@
uint16_t num_of_tracking_entries;
};
+enum class BatchScanMode : uint8_t {
+ DISABLE = 0,
+ TRUNCATED = 1,
+ FULL = 2,
+ TRUNCATED_AND_FULL = 3,
+};
+
class LeScanningManager : public bluetooth::Module {
public:
static constexpr uint8_t kMaxAppNum = 32;
static constexpr uint8_t kAdvertisingDataInfoNotPresent = 0xff;
static constexpr uint8_t kTxPowerInformationNotPresent = 0x7f;
static constexpr uint8_t kNotPeriodicAdvertisement = 0x00;
+ static constexpr ScannerId kInvalidScannerId = 0xFF;
LeScanningManager();
void RegisterScanner(const Uuid app_uuid);
@@ -102,7 +128,7 @@
void Scan(bool start);
- void SetScanParameters(LeScanType scan_type, uint16_t scan_interval, uint16_t scan_window);
+ void SetScanParameters(ScannerId scanner_id, LeScanType scan_type, uint16_t scan_interval, uint16_t scan_window);
/* Scan filter */
void ScanFilterEnable(bool enable);
@@ -112,6 +138,22 @@
void ScanFilterAdd(uint8_t filter_index, std::vector<AdvertisingPacketContentFilterCommand> filters);
+ /*Batch Scan*/
+ void BatchScanConifgStorage(
+ uint8_t batch_scan_full_max,
+ uint8_t batch_scan_truncated_max,
+ uint8_t batch_scan_notify_threshold,
+ ScannerId scanner_id);
+ void BatchScanEnable(
+ BatchScanMode scan_mode,
+ uint32_t duty_cycle_scan_window_slots,
+ uint32_t duty_cycle_scan_interval_slots,
+ BatchScanDiscardRule batch_scan_discard_rule);
+ void BatchScanDisable();
+ void BatchScanReadReport(ScannerId scanner_id, BatchScanMode scan_mode);
+
+ void TrackAdvertiser(ScannerId scanner_id);
+
void RegisterScanningCallback(ScanningCallback* scanning_callback);
static const ModuleFactory Factory;
diff --git a/gd/hci/le_scanning_manager_test.cc b/gd/hci/le_scanning_manager_test.cc
index 63958db..f5e6449 100644
--- a/gd/hci/le_scanning_manager_test.cc
+++ b/gd/hci/le_scanning_manager_test.cc
@@ -72,7 +72,7 @@
std::unique_ptr<CommandBuilder> command,
common::ContextualOnceCallback<void(CommandStatusView)> on_status) override {
command_queue_.push(std::move(command));
- command_status_callbacks.push_front(std::move(on_status));
+ command_status_callbacks.push_back(std::move(on_status));
if (command_promise_ != nullptr) {
command_promise_->set_value();
command_promise_.reset();
@@ -83,7 +83,7 @@
std::unique_ptr<CommandBuilder> command,
common::ContextualOnceCallback<void(CommandCompleteView)> on_complete) override {
command_queue_.push(std::move(command));
- command_complete_callbacks.push_front(std::move(on_complete));
+ command_complete_callbacks.push_back(std::move(on_complete));
if (command_promise_ != nullptr) {
command_promise_->set_value();
command_promise_.reset();
@@ -118,11 +118,19 @@
registered_events_[event_code] = event_handler;
}
+ void UnregisterEventHandler(EventCode event_code) override {
+ registered_events_.erase(event_code);
+ }
+
void RegisterLeEventHandler(SubeventCode subevent_code,
common::ContextualCallback<void(LeMetaEventView)> event_handler) override {
registered_le_events_[subevent_code] = event_handler;
}
+ void UnregisterLeEventHandler(SubeventCode subevent_code) override {
+ registered_le_events_.erase(subevent_code);
+ }
+
void IncomingEvent(std::unique_ptr<EventBuilder> event_builder) {
auto packet = GetPacketView(std::move(event_builder));
EventView event = EventView::Create(packet);
@@ -146,6 +154,7 @@
void CommandCompleteCallback(EventView event) {
CommandCompleteView complete_view = CommandCompleteView::Create(event);
ASSERT_TRUE(complete_view.IsValid());
+ ASSERT_NE(command_complete_callbacks.size(), 0);
std::move(command_complete_callbacks.front()).Invoke(complete_view);
command_complete_callbacks.pop_front();
}
@@ -153,6 +162,7 @@
void CommandStatusCallback(EventView event) {
CommandStatusView status_view = CommandStatusView::Create(event);
ASSERT_TRUE(status_view.IsValid());
+ ASSERT_NE(command_status_callbacks.size(), 0);
std::move(command_status_callbacks.front()).Invoke(status_view);
command_status_callbacks.pop_front();
}
@@ -235,6 +245,9 @@
if (is_filter_support_) {
test_controller_->AddSupported(OpCode::LE_ADV_FILTER);
}
+ if (is_batch_scan_support_) {
+ test_controller_->AddSupported(OpCode::LE_BATCH_SCAN);
+ }
test_acl_manager_ = new TestAclManager;
fake_registry_.InjectTestModule(&HciLayer::Factory, test_hci_layer_);
fake_registry_.InjectTestModule(&Controller::Factory, test_controller_);
@@ -287,6 +300,7 @@
OnScannerRegistered,
(const bluetooth::hci::Uuid app_uuid, ScannerId scanner_id, ScanningStatus status),
(override));
+ MOCK_METHOD(void, OnSetScannerParameterComplete, (ScannerId scanner_id, ScanningStatus status), (override));
MOCK_METHOD(
void,
OnScanResult,
@@ -301,12 +315,17 @@
uint16_t periodic_advertising_interval,
std::vector<uint8_t> advertising_data),
(override));
- MOCK_METHOD(void, OnTrackAdvFoundLost, (), (override));
+ MOCK_METHOD(
+ void,
+ OnTrackAdvFoundLost,
+ (bluetooth::hci::AdvertisingFilterOnFoundOnLostInfo on_found_on_lost_info),
+ (override));
MOCK_METHOD(
void,
OnBatchScanReports,
(int client_if, int status, int report_format, int num_records, std::vector<uint8_t> data),
(override));
+ MOCK_METHOD(void, OnBatchScanThresholdCrossed, (int client_if), (override));
MOCK_METHOD(void, OnTimeout, (), (override));
MOCK_METHOD(void, OnFilterEnable, (Enable enable, uint8_t status), (override));
MOCK_METHOD(void, OnFilterParamSetup, (uint8_t available_spaces, ApcfAction action, uint8_t status), (override));
@@ -320,6 +339,7 @@
OpCode param_opcode_{OpCode::LE_SET_ADVERTISING_PARAMETERS};
OpCode enable_opcode_{OpCode::LE_SET_SCAN_ENABLE};
bool is_filter_support_ = false;
+ bool is_batch_scan_support_ = false;
};
class LeAndroidHciScanningManagerTest : public LeScanningManagerTest {
@@ -327,6 +347,7 @@
void SetUp() override {
param_opcode_ = OpCode::LE_EXTENDED_SCAN_PARAMS;
is_filter_support_ = true;
+ is_batch_scan_support_ = true;
LeScanningManagerTest::SetUp();
test_controller_->AddSupported(OpCode::LE_ADV_FILTER);
}
@@ -441,11 +462,51 @@
filters.push_back(filter);
le_scanning_manager->ScanFilterAdd(0x01, filters);
EXPECT_CALL(mock_callbacks_, OnFilterConfigCallback);
+ auto result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100)));
+ ASSERT_EQ(std::future_status::ready, result);
test_hci_layer_->IncomingEvent(
LeAdvFilterBroadcasterAddressCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, ApcfAction::ADD, 0x0a));
sync_client_handler();
}
+TEST_F(LeAndroidHciScanningManagerTest, read_batch_scan_result) {
+ // Enable batch scan feature
+ auto next_command_future = test_hci_layer_->GetCommandFuture();
+ le_scanning_manager->BatchScanConifgStorage(100, 0, 95, 0x00);
+ auto result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100)));
+ ASSERT_EQ(std::future_status::ready, result);
+ test_hci_layer_->IncomingEvent(LeBatchScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
+ test_hci_layer_->IncomingEvent(
+ LeBatchScanSetStorageParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
+
+ // Enable batch scan
+ next_command_future = test_hci_layer_->GetCommandFuture();
+ le_scanning_manager->BatchScanEnable(BatchScanMode::FULL, 2400, 2400, BatchScanDiscardRule::OLDEST);
+ result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100)));
+ ASSERT_EQ(std::future_status::ready, result);
+ test_hci_layer_->IncomingEvent(LeBatchScanSetScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
+
+ // Read batch scan data
+ next_command_future = test_hci_layer_->GetCommandFuture();
+ le_scanning_manager->BatchScanReadReport(0x01, BatchScanMode::FULL);
+ result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100)));
+ ASSERT_EQ(std::future_status::ready, result);
+
+ EXPECT_CALL(mock_callbacks_, OnBatchScanReports);
+ std::vector<uint8_t> raw_data = {0x5c, 0x1f, 0xa2, 0xc3, 0x63, 0x5d, 0x01, 0xf5, 0xb3, 0x5e, 0x00, 0x0c, 0x02,
+ 0x01, 0x02, 0x05, 0x09, 0x6d, 0x76, 0x38, 0x76, 0x02, 0x0a, 0xf5, 0x00};
+ next_command_future = test_hci_layer_->GetCommandFuture();
+ // We will send read command while num_of_record != 0
+ test_hci_layer_->IncomingEvent(LeBatchScanReadResultParametersCompleteRawBuilder::Create(
+ uint8_t{1}, ErrorCode::SUCCESS, BatchScanDataRead::FULL_MODE_DATA, 1, raw_data));
+ result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100)));
+ ASSERT_EQ(std::future_status::ready, result);
+
+ // OnBatchScanReports will be trigger when num_of_record == 0
+ test_hci_layer_->IncomingEvent(LeBatchScanReadResultParametersCompleteRawBuilder::Create(
+ uint8_t{1}, ErrorCode::SUCCESS, BatchScanDataRead::FULL_MODE_DATA, 0, {}));
+}
+
TEST_F(LeExtendedScanningManagerTest, start_scan_test) {
auto next_command_future = test_hci_layer_->GetCommandFuture();
le_scanning_manager->Scan(true);
diff --git a/gd/hci/vendor_specific_event_manager.cc b/gd/hci/vendor_specific_event_manager.cc
new file mode 100644
index 0000000..914a913
--- /dev/null
+++ b/gd/hci/vendor_specific_event_manager.cc
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/vendor_specific_event_manager.h"
+
+#include "hci/controller.h"
+#include "hci/hci_layer.h"
+#include "hci/hci_packets.h"
+
+namespace bluetooth {
+namespace hci {
+
+const ModuleFactory VendorSpecificEventManager::Factory =
+ ModuleFactory([]() { return new VendorSpecificEventManager(); });
+
+struct VendorSpecificEventManager::impl {
+ impl(Module* module) : module_(module){};
+
+ ~impl() {}
+
+ void start(os::Handler* handler, hci::HciLayer* hci_layer, hci::Controller* controller) {
+ module_handler_ = handler;
+ hci_layer_ = hci_layer;
+ controller_ = controller;
+ hci_layer_->RegisterEventHandler(
+ EventCode::VENDOR_SPECIFIC, handler->BindOn(this, &VendorSpecificEventManager::impl::on_vendor_specific_event));
+ vendor_capabilities_ = controller->GetVendorCapabilities();
+ }
+
+ void stop() {}
+
+ void register_event(VseSubeventCode event, common::ContextualCallback<void(VendorSpecificEventView)> handler) {
+ ASSERT_LOG(
+ subevent_handlers_.count(event) == 0,
+ "Can not register a second handler for %02hhx (%s)",
+ event,
+ VseSubeventCodeText(event).c_str());
+ subevent_handlers_[event] = handler;
+ }
+
+ void unregister_event(VseSubeventCode event) {
+ subevent_handlers_.erase(subevent_handlers_.find(event));
+ }
+
+ bool check_event_supported(VseSubeventCode event) {
+ switch (event) {
+ case (VseSubeventCode::BLE_THRESHOLD): {
+ if (vendor_capabilities_.total_scan_results_storage_ > 0) {
+ return true;
+ }
+ } break;
+ case (VseSubeventCode::BLE_TRACKING): {
+ if (vendor_capabilities_.total_num_of_advt_tracked_ > 0) {
+ return true;
+ }
+ } break;
+ case (VseSubeventCode::DEBUG_INFO): {
+ return vendor_capabilities_.debug_logging_supported_;
+ } break;
+ case (VseSubeventCode::BQR_EVENT): {
+ return vendor_capabilities_.bluetooth_quality_report_support_;
+ } break;
+ default:
+ LOG_WARN("Unhandled event %s", VseSubeventCodeText(event).c_str());
+ }
+ return false;
+ }
+
+ void on_vendor_specific_event(EventView event_view) {
+ auto vendor_specific_event_view = VendorSpecificEventView::Create(event_view);
+ ASSERT(vendor_specific_event_view.IsValid());
+ VseSubeventCode vse_subevent_code = vendor_specific_event_view.GetSubeventCode();
+ if (subevent_handlers_.find(vse_subevent_code) == subevent_handlers_.end()) {
+ LOG_WARN("Unhandled vendor specific event of type 0x%02hhx", vse_subevent_code);
+ return;
+ }
+ subevent_handlers_[vse_subevent_code].Invoke(vendor_specific_event_view);
+ }
+
+ Module* module_;
+ os::Handler* module_handler_;
+ hci::HciLayer* hci_layer_;
+ hci::Controller* controller_;
+ VendorCapabilities vendor_capabilities_;
+ std::map<VseSubeventCode, common::ContextualCallback<void(VendorSpecificEventView)>> subevent_handlers_;
+};
+
+VendorSpecificEventManager::VendorSpecificEventManager() {
+ pimpl_ = std::make_unique<impl>(this);
+}
+
+void VendorSpecificEventManager::ListDependencies(ModuleList* list) {
+ list->add<hci::HciLayer>();
+ list->add<hci::Controller>();
+}
+
+void VendorSpecificEventManager::Start() {
+ pimpl_->start(GetHandler(), GetDependency<hci::HciLayer>(), GetDependency<hci::Controller>());
+}
+
+void VendorSpecificEventManager::Stop() {
+ pimpl_->stop();
+ pimpl_.reset();
+}
+
+std::string VendorSpecificEventManager::ToString() const {
+ return "Vendor Specific Event Manager";
+}
+
+void VendorSpecificEventManager::RegisterEventHandler(
+ VseSubeventCode event, common::ContextualCallback<void(VendorSpecificEventView)> handler) {
+ CallOn(pimpl_.get(), &impl::register_event, event, handler);
+}
+
+void VendorSpecificEventManager::UnregisterEventHandler(VseSubeventCode event) {
+ CallOn(pimpl_.get(), &impl::unregister_event, event);
+}
+
+} // namespace hci
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/hci/vendor_specific_event_manager.h b/gd/hci/vendor_specific_event_manager.h
new file mode 100644
index 0000000..a0535aa
--- /dev/null
+++ b/gd/hci/vendor_specific_event_manager.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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/hci_packets.h"
+#include "module.h"
+
+namespace bluetooth {
+namespace hci {
+
+class VendorSpecificEventManager : public bluetooth::Module {
+ public:
+ VendorSpecificEventManager();
+
+ void RegisterEventHandler(VseSubeventCode event, common::ContextualCallback<void(VendorSpecificEventView)> handler);
+
+ void UnregisterEventHandler(VseSubeventCode event);
+
+ static const ModuleFactory Factory;
+
+ protected:
+ void ListDependencies(ModuleList* list) override;
+
+ void Start() override;
+
+ void Stop() override;
+
+ std::string ToString() const override;
+
+ private:
+ struct impl;
+ std::unique_ptr<impl> pimpl_;
+ DISALLOW_COPY_AND_ASSIGN(VendorSpecificEventManager);
+};
+
+} // namespace hci
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/iso/cert/le_iso_test.py b/gd/iso/cert/le_iso_test.py
index c1d3d65..f803144 100644
--- a/gd/iso/cert/le_iso_test.py
+++ b/gd/iso/cert/le_iso_test.py
@@ -13,274 +13,19 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import time
-import logging
-
-from bluetooth_packets_python3 import hci_packets
-from cert.event_stream import EventStream
from cert.gd_base_test import GdBaseTestClass
-from cert.matchers import HciMatchers, IsoMatchers, L2capMatchers
-from cert.metadata import metadata
-from cert.py_hci import PyHci
-from cert.py_l2cap import PyLeL2cap
-from cert.py_le_iso import PyLeIso
-from cert.py_le_iso import CisTestParameters
-from cert.truth import assertThat
-from datetime import timedelta
-from facade import common_pb2 as common
-from hci.facade import controller_facade_pb2 as controller_facade
-from hci.facade import le_advertising_manager_facade_pb2 as le_advertising_facade
-from hci.facade import le_initiator_address_facade_pb2 as le_initiator_address_facade
-from google.protobuf import empty_pb2 as empty_proto
-from neighbor.facade import facade_pb2 as neighbor_facade
-from l2cap.le.cert.cert_le_l2cap import CertLeL2cap
-from iso.cert.cert_le_iso import CertLeIso
-
-import time
-from bluetooth_packets_python3.hci_packets import OpCode
+from iso.cert.le_iso_test_lib import LeIsoTestBase
-class LeIsoTest(GdBaseTestClass):
- """
- Collection of tests that each sample results from
- different (unique) combinations of io capabilities, authentication requirements, and oob data.
- """
+class LeIsoTest(GdBaseTestClass, LeIsoTestBase):
def setup_class(self):
- super().setup_class(dut_module='L2CAP', cert_module='HCI_INTERFACES')
+ GdBaseTestClass.setup_class(self, dut_module='L2CAP', cert_module='HCI_INTERFACES')
def setup_test(self):
- super().setup_test()
-
- self.dut_l2cap = PyLeL2cap(self.dut)
- self.cert_l2cap = CertLeL2cap(self.cert)
- self.dut_address = common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=bytes(b'D0:05:04:03:02:01')), type=common.RANDOM_DEVICE_ADDRESS)
- self.cert_address = common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=bytes(b'C0:11:FF:AA:33:22')), type=common.RANDOM_DEVICE_ADDRESS)
- dut_privacy_policy = le_initiator_address_facade.PrivacyPolicy(
- address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
- address_with_type=self.dut_address,
- rotation_irk=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
- minimum_rotation_time=0,
- maximum_rotation_time=0)
- self.dut_l2cap._device.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(dut_privacy_policy)
- privacy_policy = le_initiator_address_facade.PrivacyPolicy(
- address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
- address_with_type=self.cert_address,
- rotation_irk=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
- minimum_rotation_time=0,
- maximum_rotation_time=0)
- self.cert_l2cap._device.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(privacy_policy)
-
- self.dut_iso = PyLeIso(self.dut)
- self.cert_iso = CertLeIso(self.cert)
+ GdBaseTestClass.setup_test(self)
+ LeIsoTestBase.setup_test(self, self.dut, self.cert)
def teardown_test(self):
- self.dut_iso.close()
- self.cert_iso.close()
-
- self.cert_l2cap.close()
- self.dut_l2cap.close()
- super().teardown_test()
-
- #cert becomes central of connection, dut peripheral
- def _setup_link_from_cert(self):
- # DUT Advertises
- gap_name = hci_packets.GapData()
- gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
- gap_name.data = list(bytes(b'Im_The_DUT'))
- gap_data = le_advertising_facade.GapDataMsg(data=bytes(gap_name.Serialize()))
- config = le_advertising_facade.AdvertisingConfig(
- advertisement=[gap_data],
- interval_min=512,
- interval_max=768,
- advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
- own_address_type=common.USE_RANDOM_DEVICE_ADDRESS,
- channel_map=7,
- filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
- request = le_advertising_facade.CreateAdvertiserRequest(config=config)
- create_response = self.dut.hci_le_advertising_manager.CreateAdvertiser(request)
- self.cert_l2cap.connect_le_acl(self.dut_address)
-
- def _setup_cis_from_cert(self, cig_id, sdu_interval_m_to_s, sdu_interval_s_to_m, ft_m_to_s, ft_s_to_m, iso_interval,
- peripherals_clock_accuracy, packing, framing, max_transport_latency_m_to_s,
- max_transport_latency_s_to_m, cis_configs):
- self.cert_iso.le_set_cig_parameters_test(cig_id, sdu_interval_m_to_s, sdu_interval_s_to_m, ft_m_to_s, ft_s_to_m,
- iso_interval, peripherals_clock_accuracy, packing, framing,
- max_transport_latency_m_to_s, max_transport_latency_s_to_m,
- cis_configs)
-
- cis_handles = self.cert_iso.wait_le_set_cig_parameters_complete()
-
- cis_handle = cis_handles[0]
-
- acl_connection_handle = self.cert_l2cap._le_acl.handle
- self.cert_iso.le_cretate_cis([(cis_handle, acl_connection_handle)])
- dut_cis_stream = self.dut_iso.wait_le_cis_established()
- cert_cis_stream = self.cert_iso.wait_le_cis_established()
- return (dut_cis_stream, cert_cis_stream)
-
- @metadata(
- pts_test_id="IAL/CIS/UNF/SLA/BV-01-C",
- pts_test_name="connected isochronous stream, unframed data, peripheral role")
- def test_iso_cis_unf_sla_bv_01_c(self):
- """
- Verify that the IUT can send an SDU with length ≤ the Isochronous PDU length.
- """
- cig_id = 0x01
- sdu_interval_m_to_s = 0
- sdu_interval_s_to_m = 0x186a
- ft_m_to_s = 0
- ft_s_to_m = 1
- iso_interval = 0x0A
- peripherals_clock_accuracy = 0
- packing = 0
- framing = 0
- max_transport_latency_m_to_s = 0
- max_transport_latency_s_to_m = 0
- cis_configs = [
- CisTestParameters(
- cis_id=0x01,
- nse=2,
- max_sdu_m_to_s=100,
- max_sdu_s_to_m=100,
- max_pdu_m_to_s=100,
- max_pdu_s_to_m=100,
- phy_m_to_s=0x02,
- phy_s_to_m=0x00,
- bn_m_to_s=0,
- bn_s_to_m=2,
- )
- ]
-
- self._setup_link_from_cert()
- (dut_cis_stream, cert_cis_stream) = self._setup_cis_from_cert(
- cig_id, sdu_interval_m_to_s, sdu_interval_s_to_m, ft_m_to_s, ft_s_to_m, iso_interval,
- peripherals_clock_accuracy, packing, framing, max_transport_latency_m_to_s, max_transport_latency_s_to_m,
- cis_configs)
- dut_cis_stream.send(b'abcdefgh' * 10)
- assertThat(cert_cis_stream).emits(IsoMatchers.Data(b'abcdefgh' * 10))
-
- @metadata(
- pts_test_id="IAL/CIS/UNF/SLA/BV-25-C",
- pts_test_name="connected isochronous stream, unframed data, peripheral role")
- def test_iso_cis_unf_sla_bv_25_c(self):
- """
- Verify that the IUT can send an SDU with length ≤ the Isochronous PDU length.
- """
- cig_id = 0x01
- sdu_interval_m_to_s = 0x7530
- sdu_interval_s_to_m = 0x7530
- ft_m_to_s = 3
- ft_s_to_m = 2
- iso_interval = 0x18
- peripherals_clock_accuracy = 0
- packing = 0
- framing = 0
- max_transport_latency_m_to_s = 0
- max_transport_latency_s_to_m = 0
- cis_configs = [
- CisTestParameters(
- cis_id=0x01,
- nse=5,
- max_sdu_m_to_s=100,
- max_sdu_s_to_m=100,
- max_pdu_m_to_s=100,
- max_pdu_s_to_m=100,
- phy_m_to_s=0x02,
- phy_s_to_m=0x00,
- bn_m_to_s=3,
- bn_s_to_m=1,
- )
- ]
-
- self._setup_link_from_cert()
- (dut_cis_stream, cert_cis_stream) = self._setup_cis_from_cert(
- cig_id, sdu_interval_m_to_s, sdu_interval_s_to_m, ft_m_to_s, ft_s_to_m, iso_interval,
- peripherals_clock_accuracy, packing, framing, max_transport_latency_m_to_s, max_transport_latency_s_to_m,
- cis_configs)
- dut_cis_stream.send(b'abcdefgh' * 10)
- assertThat(cert_cis_stream).emits(IsoMatchers.Data(b'abcdefgh' * 10))
-
- @metadata(
- pts_test_id="IAL/CIS/FRA/SLA/BV-03-C",
- pts_test_name="connected isochronous stream, framed data, peripheral role")
- def test_iso_cis_fra_sla_bv_03_c(self):
- """
- Verify that the IUT can send an SDU with length ≤ the Isochronous PDU length.
- """
- cig_id = 0x01
- sdu_interval_m_to_s = 0x0000
- sdu_interval_s_to_m = 0x4e30
- ft_m_to_s = 0
- ft_s_to_m = 2
- iso_interval = 0x14
- peripherals_clock_accuracy = 0
- packing = 0
- framing = 1
- max_transport_latency_m_to_s = 0
- max_transport_latency_s_to_m = 0
- cis_configs = [
- CisTestParameters(
- cis_id=0x01,
- nse=4,
- max_sdu_m_to_s=100,
- max_sdu_s_to_m=100,
- max_pdu_m_to_s=100,
- max_pdu_s_to_m=100,
- phy_m_to_s=0x02,
- phy_s_to_m=0x00,
- bn_m_to_s=0,
- bn_s_to_m=2,
- )
- ]
-
- self._setup_link_from_cert()
- (dut_cis_stream, cert_cis_stream) = self._setup_cis_from_cert(
- cig_id, sdu_interval_m_to_s, sdu_interval_s_to_m, ft_m_to_s, ft_s_to_m, iso_interval,
- peripherals_clock_accuracy, packing, framing, max_transport_latency_m_to_s, max_transport_latency_s_to_m,
- cis_configs)
- dut_cis_stream.send(b'abcdefgh' * 10)
- assertThat(cert_cis_stream).emits(IsoMatchers.Data(b'abcdefgh' * 10))
-
- @metadata(
- pts_test_id="IAL/CIS/FRA/SLA/BV-26-C",
- pts_test_name="connected isochronous stream, framed data, peripheral role")
- def test_iso_cis_fra_sla_bv_26_c(self):
- """
- Verify that the IUT can send an SDU with length ≤ the Isochronous PDU length.
- """
- cig_id = 0x01
- sdu_interval_m_to_s = 0x14D5
- sdu_interval_s_to_m = 0x14D5
- ft_m_to_s = 1
- ft_s_to_m = 1
- iso_interval = 0x08
- peripherals_clock_accuracy = 0
- packing = 0
- framing = 1
- max_transport_latency_m_to_s = 0
- max_transport_latency_s_to_m = 0
- cis_configs = [
- CisTestParameters(
- cis_id=0x01,
- nse=2,
- max_sdu_m_to_s=100,
- max_sdu_s_to_m=100,
- max_pdu_m_to_s=100,
- max_pdu_s_to_m=100,
- phy_m_to_s=0x02,
- phy_s_to_m=0x00,
- bn_m_to_s=1,
- bn_s_to_m=1,
- )
- ]
-
- self._setup_link_from_cert()
- (dut_cis_stream, cert_cis_stream) = self._setup_cis_from_cert(
- cig_id, sdu_interval_m_to_s, sdu_interval_s_to_m, ft_m_to_s, ft_s_to_m, iso_interval,
- peripherals_clock_accuracy, packing, framing, max_transport_latency_m_to_s, max_transport_latency_s_to_m,
- cis_configs)
- dut_cis_stream.send(b'abcdefgh' * 10)
- assertThat(cert_cis_stream).emits(IsoMatchers.Data(b'abcdefgh' * 10))
+ LeIsoTestBase.teardown_test(self)
+ GdBaseTestClass.teardown_test(self)
diff --git a/gd/iso/cert/le_iso_test_lib.py b/gd/iso/cert/le_iso_test_lib.py
new file mode 100644
index 0000000..3fa93be
--- /dev/null
+++ b/gd/iso/cert/le_iso_test_lib.py
@@ -0,0 +1,282 @@
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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 time
+import logging
+
+from bluetooth_packets_python3 import hci_packets
+from cert.event_stream import EventStream
+from cert.matchers import HciMatchers, IsoMatchers, L2capMatchers
+from cert.metadata import metadata
+from cert.py_hci import PyHci
+from cert.py_l2cap import PyLeL2cap
+from cert.py_le_iso import PyLeIso
+from cert.py_le_iso import CisTestParameters
+from cert.truth import assertThat
+from datetime import timedelta
+from facade import common_pb2 as common
+from hci.facade import controller_facade_pb2 as controller_facade
+from hci.facade import le_advertising_manager_facade_pb2 as le_advertising_facade
+from hci.facade import le_initiator_address_facade_pb2 as le_initiator_address_facade
+from google.protobuf import empty_pb2 as empty_proto
+from neighbor.facade import facade_pb2 as neighbor_facade
+from l2cap.le.cert.cert_le_l2cap import CertLeL2cap
+from iso.cert.cert_le_iso import CertLeIso
+
+import time
+from bluetooth_packets_python3.hci_packets import OpCode
+
+
+class LeIsoTestBase():
+ """
+ Collection of tests that each sample results from
+ different (unique) combinations of io capabilities, authentication requirements, and oob data.
+ """
+
+ def setup_test(self, dut, cert):
+ self.dut = dut
+ self.cert = cert
+
+ self.dut_l2cap = PyLeL2cap(self.dut)
+ self.cert_l2cap = CertLeL2cap(self.cert)
+ self.dut_address = common.BluetoothAddressWithType(
+ address=common.BluetoothAddress(address=bytes(b'D0:05:04:03:02:01')), type=common.RANDOM_DEVICE_ADDRESS)
+ self.cert_address = common.BluetoothAddressWithType(
+ address=common.BluetoothAddress(address=bytes(b'C0:11:FF:AA:33:22')), type=common.RANDOM_DEVICE_ADDRESS)
+ dut_privacy_policy = le_initiator_address_facade.PrivacyPolicy(
+ address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
+ address_with_type=self.dut_address,
+ rotation_irk=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
+ minimum_rotation_time=0,
+ maximum_rotation_time=0)
+ self.dut_l2cap._device.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(dut_privacy_policy)
+ privacy_policy = le_initiator_address_facade.PrivacyPolicy(
+ address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
+ address_with_type=self.cert_address,
+ rotation_irk=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
+ minimum_rotation_time=0,
+ maximum_rotation_time=0)
+ self.cert_l2cap._device.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(privacy_policy)
+
+ self.dut_iso = PyLeIso(self.dut)
+ self.cert_iso = CertLeIso(self.cert)
+
+ def teardown_test(self):
+ self.dut_iso.close()
+ self.cert_iso.close()
+
+ self.cert_l2cap.close()
+ self.dut_l2cap.close()
+
+ #cert becomes central of connection, dut peripheral
+ def _setup_link_from_cert(self):
+ # DUT Advertises
+ gap_name = hci_packets.GapData()
+ gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
+ gap_name.data = list(bytes(b'Im_The_DUT'))
+ gap_data = le_advertising_facade.GapDataMsg(data=bytes(gap_name.Serialize()))
+ config = le_advertising_facade.AdvertisingConfig(
+ advertisement=[gap_data],
+ interval_min=512,
+ interval_max=768,
+ advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
+ own_address_type=common.USE_RANDOM_DEVICE_ADDRESS,
+ channel_map=7,
+ filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
+ request = le_advertising_facade.CreateAdvertiserRequest(config=config)
+ create_response = self.dut.hci_le_advertising_manager.CreateAdvertiser(request)
+ self.cert_l2cap.connect_le_acl(self.dut_address)
+
+ def _setup_cis_from_cert(self, cig_id, sdu_interval_m_to_s, sdu_interval_s_to_m, ft_m_to_s, ft_s_to_m, iso_interval,
+ peripherals_clock_accuracy, packing, framing, max_transport_latency_m_to_s,
+ max_transport_latency_s_to_m, cis_configs):
+ self.cert_iso.le_set_cig_parameters_test(cig_id, sdu_interval_m_to_s, sdu_interval_s_to_m, ft_m_to_s, ft_s_to_m,
+ iso_interval, peripherals_clock_accuracy, packing, framing,
+ max_transport_latency_m_to_s, max_transport_latency_s_to_m,
+ cis_configs)
+
+ cis_handles = self.cert_iso.wait_le_set_cig_parameters_complete()
+
+ cis_handle = cis_handles[0]
+
+ acl_connection_handle = self.cert_l2cap._le_acl.handle
+ self.cert_iso.le_cretate_cis([(cis_handle, acl_connection_handle)])
+ dut_cis_stream = self.dut_iso.wait_le_cis_established()
+ cert_cis_stream = self.cert_iso.wait_le_cis_established()
+ return (dut_cis_stream, cert_cis_stream)
+
+ @metadata(
+ pts_test_id="IAL/CIS/UNF/SLA/BV-01-C",
+ pts_test_name="connected isochronous stream, unframed data, peripheral role")
+ def test_iso_cis_unf_sla_bv_01_c(self):
+ """
+ Verify that the IUT can send an SDU with length ≤ the Isochronous PDU length.
+ """
+ cig_id = 0x01
+ sdu_interval_m_to_s = 0
+ sdu_interval_s_to_m = 0x186a
+ ft_m_to_s = 0
+ ft_s_to_m = 1
+ iso_interval = 0x0A
+ peripherals_clock_accuracy = 0
+ packing = 0
+ framing = 0
+ max_transport_latency_m_to_s = 0
+ max_transport_latency_s_to_m = 0
+ cis_configs = [
+ CisTestParameters(
+ cis_id=0x01,
+ nse=2,
+ max_sdu_m_to_s=100,
+ max_sdu_s_to_m=100,
+ max_pdu_m_to_s=100,
+ max_pdu_s_to_m=100,
+ phy_m_to_s=0x02,
+ phy_s_to_m=0x00,
+ bn_m_to_s=0,
+ bn_s_to_m=2,
+ )
+ ]
+
+ self._setup_link_from_cert()
+ (dut_cis_stream, cert_cis_stream) = self._setup_cis_from_cert(
+ cig_id, sdu_interval_m_to_s, sdu_interval_s_to_m, ft_m_to_s, ft_s_to_m, iso_interval,
+ peripherals_clock_accuracy, packing, framing, max_transport_latency_m_to_s, max_transport_latency_s_to_m,
+ cis_configs)
+ dut_cis_stream.send(b'abcdefgh' * 10)
+ assertThat(cert_cis_stream).emits(IsoMatchers.Data(b'abcdefgh' * 10))
+
+ @metadata(
+ pts_test_id="IAL/CIS/UNF/SLA/BV-25-C",
+ pts_test_name="connected isochronous stream, unframed data, peripheral role")
+ def test_iso_cis_unf_sla_bv_25_c(self):
+ """
+ Verify that the IUT can send an SDU with length ≤ the Isochronous PDU length.
+ """
+ cig_id = 0x01
+ sdu_interval_m_to_s = 0x7530
+ sdu_interval_s_to_m = 0x7530
+ ft_m_to_s = 3
+ ft_s_to_m = 2
+ iso_interval = 0x18
+ peripherals_clock_accuracy = 0
+ packing = 0
+ framing = 0
+ max_transport_latency_m_to_s = 0
+ max_transport_latency_s_to_m = 0
+ cis_configs = [
+ CisTestParameters(
+ cis_id=0x01,
+ nse=5,
+ max_sdu_m_to_s=100,
+ max_sdu_s_to_m=100,
+ max_pdu_m_to_s=100,
+ max_pdu_s_to_m=100,
+ phy_m_to_s=0x02,
+ phy_s_to_m=0x00,
+ bn_m_to_s=3,
+ bn_s_to_m=1,
+ )
+ ]
+
+ self._setup_link_from_cert()
+ (dut_cis_stream, cert_cis_stream) = self._setup_cis_from_cert(
+ cig_id, sdu_interval_m_to_s, sdu_interval_s_to_m, ft_m_to_s, ft_s_to_m, iso_interval,
+ peripherals_clock_accuracy, packing, framing, max_transport_latency_m_to_s, max_transport_latency_s_to_m,
+ cis_configs)
+ dut_cis_stream.send(b'abcdefgh' * 10)
+ assertThat(cert_cis_stream).emits(IsoMatchers.Data(b'abcdefgh' * 10))
+
+ @metadata(
+ pts_test_id="IAL/CIS/FRA/SLA/BV-03-C",
+ pts_test_name="connected isochronous stream, framed data, peripheral role")
+ def test_iso_cis_fra_sla_bv_03_c(self):
+ """
+ Verify that the IUT can send an SDU with length ≤ the Isochronous PDU length.
+ """
+ cig_id = 0x01
+ sdu_interval_m_to_s = 0x0000
+ sdu_interval_s_to_m = 0x4e30
+ ft_m_to_s = 0
+ ft_s_to_m = 2
+ iso_interval = 0x14
+ peripherals_clock_accuracy = 0
+ packing = 0
+ framing = 1
+ max_transport_latency_m_to_s = 0
+ max_transport_latency_s_to_m = 0
+ cis_configs = [
+ CisTestParameters(
+ cis_id=0x01,
+ nse=4,
+ max_sdu_m_to_s=100,
+ max_sdu_s_to_m=100,
+ max_pdu_m_to_s=100,
+ max_pdu_s_to_m=100,
+ phy_m_to_s=0x02,
+ phy_s_to_m=0x00,
+ bn_m_to_s=0,
+ bn_s_to_m=2,
+ )
+ ]
+
+ self._setup_link_from_cert()
+ (dut_cis_stream, cert_cis_stream) = self._setup_cis_from_cert(
+ cig_id, sdu_interval_m_to_s, sdu_interval_s_to_m, ft_m_to_s, ft_s_to_m, iso_interval,
+ peripherals_clock_accuracy, packing, framing, max_transport_latency_m_to_s, max_transport_latency_s_to_m,
+ cis_configs)
+ dut_cis_stream.send(b'abcdefgh' * 10)
+ assertThat(cert_cis_stream).emits(IsoMatchers.Data(b'abcdefgh' * 10))
+
+ @metadata(
+ pts_test_id="IAL/CIS/FRA/SLA/BV-26-C",
+ pts_test_name="connected isochronous stream, framed data, peripheral role")
+ def test_iso_cis_fra_sla_bv_26_c(self):
+ """
+ Verify that the IUT can send an SDU with length ≤ the Isochronous PDU length.
+ """
+ cig_id = 0x01
+ sdu_interval_m_to_s = 0x14D5
+ sdu_interval_s_to_m = 0x14D5
+ ft_m_to_s = 1
+ ft_s_to_m = 1
+ iso_interval = 0x08
+ peripherals_clock_accuracy = 0
+ packing = 0
+ framing = 1
+ max_transport_latency_m_to_s = 0
+ max_transport_latency_s_to_m = 0
+ cis_configs = [
+ CisTestParameters(
+ cis_id=0x01,
+ nse=2,
+ max_sdu_m_to_s=100,
+ max_sdu_s_to_m=100,
+ max_pdu_m_to_s=100,
+ max_pdu_s_to_m=100,
+ phy_m_to_s=0x02,
+ phy_s_to_m=0x00,
+ bn_m_to_s=1,
+ bn_s_to_m=1,
+ )
+ ]
+
+ self._setup_link_from_cert()
+ (dut_cis_stream, cert_cis_stream) = self._setup_cis_from_cert(
+ cig_id, sdu_interval_m_to_s, sdu_interval_s_to_m, ft_m_to_s, ft_s_to_m, iso_interval,
+ peripherals_clock_accuracy, packing, framing, max_transport_latency_m_to_s, max_transport_latency_s_to_m,
+ cis_configs)
+ dut_cis_stream.send(b'abcdefgh' * 10)
+ assertThat(cert_cis_stream).emits(IsoMatchers.Data(b'abcdefgh' * 10))
diff --git a/gd/l2cap/Android.bp b/gd/l2cap/Android.bp
index 1385222..bdec3a6 100644
--- a/gd/l2cap/Android.bp
+++ b/gd/l2cap/Android.bp
@@ -69,11 +69,17 @@
"internal/receiver_test.cc",
"internal/scheduler_fifo_test.cc",
"internal/sender_test.cc",
- "l2cap_packet_test.cc",
"le/internal/dynamic_channel_service_manager_test.cc",
"le/internal/fixed_channel_impl_test.cc",
"le/internal/fixed_channel_service_manager_test.cc",
"le/internal/link_manager_test.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothL2capUnitTestSources",
+ srcs: [
+ "l2cap_packet_test.cc",
"signal_id_test.cc",
],
}
diff --git a/gd/l2cap/classic/cert/l2cap_performance_test.py b/gd/l2cap/classic/cert/l2cap_performance_test.py
index 9c387ee..70a8477 100644
--- a/gd/l2cap/classic/cert/l2cap_performance_test.py
+++ b/gd/l2cap/classic/cert/l2cap_performance_test.py
@@ -13,175 +13,19 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from datetime import datetime, timedelta
-
-from bluetooth_packets_python3 import RawBuilder
-from cert.matchers import L2capMatchers
-from cert.truth import assertThat
-from cert.performance_test_logger import PerformanceTestLogger
-from l2cap.classic.cert.cert_l2cap import CertL2cap
-from l2cap.classic.cert.l2cap_test import L2capTestBase
-from l2cap.classic.facade_pb2 import RetransmissionFlowControlMode
-from bluetooth_packets_python3.l2cap_packets import FcsType
-from bluetooth_packets_python3.l2cap_packets import SupervisoryFunction
+from cert.gd_base_test import GdBaseTestClass
+from l2cap.classic.cert.l2cap_performance_test_lib import L2capPerformanceTestBase
-class L2capPerformanceTest(L2capTestBase):
+class L2capPerformanceTest(GdBaseTestClass, L2capPerformanceTestBase):
+
+ def setup_class(self):
+ GdBaseTestClass.setup_class(self, dut_module='L2CAP', cert_module='HCI_INTERFACES')
def setup_test(self):
- super().setup_test()
- self.performance_test_logger = PerformanceTestLogger()
+ GdBaseTestClass.setup_test(self)
+ L2capPerformanceTestBase.setup_test(self, self.dut, self.cert)
def teardown_test(self):
- super().teardown_test()
-
- def _basic_mode_tx(self, mtu, packets):
- """
- Send the specified number of packets and return the time interval in ms.
- """
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_channel_from_cert()
- self.performance_test_logger.start_interval("TX")
- for _ in range(packets):
- dut_channel.send(b'a' * mtu)
- assertThat(cert_channel).emits(
- L2capMatchers.Data(b'a' * mtu), at_least_times=packets, timeout=timedelta(seconds=60))
- self.performance_test_logger.end_interval("TX")
-
- duration = self.performance_test_logger.get_duration_of_intervals("TX")[0]
- self.log.info("Duration: %s" % str(duration))
-
- return duration
-
- def _basic_mode_tx_fixed_interval(self, mtu, interval=timedelta(seconds=10), batch_size=20):
- """
- Send packets as much as possible over a certain interval, and return the
- number of packets sent
- """
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_channel_from_cert()
- start_time = datetime.now()
- end_time = start_time + interval
- packets_sent = 0
- while datetime.now() < end_time:
- for _ in range(batch_size):
- dut_channel.send(b'a' * mtu)
- packets_sent += batch_size
- assertThat(cert_channel).emits(L2capMatchers.Data(b'a' * mtu), at_least_times=batch_size)
-
- return packets_sent
-
- def _basic_mode_rx(self, mtu, packets):
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_channel_from_cert()
- self.performance_test_logger.start_interval("RX")
- data = b"a" * mtu
- data_packet = RawBuilder([x for x in data])
- for _ in range(packets):
- cert_channel.send(data_packet)
- assertThat(dut_channel).emits(
- L2capMatchers.PacketPayloadRawData(data), at_least_times=packets, timeout=timedelta(seconds=60))
- self.performance_test_logger.end_interval("RX")
-
- duration = self.performance_test_logger.get_duration_of_intervals("RX")[0]
- self.log.info("Duration: %s" % str(duration))
-
- def _ertm_mode_tx(self, mtu, packets, tx_window_size=10):
- """
- Send the specified number of packets and return the time interval in ms.
- """
- # Make sure that number of packets is a multiple of tx_window_size
- packets = packets // tx_window_size * tx_window_size
- # For ERTM TX test, we have to do it sequentially because cert needs to ack
- self._setup_link_from_cert()
-
- config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=tx_window_size)
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM,
- fcs=FcsType.NO_FCS,
- req_config_options=config,
- rsp_config_options=config)
-
- self.performance_test_logger.start_interval("TX")
- for i in range(packets):
- dut_channel.send(b'a' * mtu)
- if i % tx_window_size == tx_window_size - 1:
- assertThat(cert_channel).emits(L2capMatchers.IFrame(payload=b'a' * mtu), at_least_times=tx_window_size)
- cert_channel.send_s_frame(req_seq=(i + 1) % 64, s=SupervisoryFunction.RECEIVER_READY)
-
- self.performance_test_logger.end_interval("TX")
-
- duration = self.performance_test_logger.get_duration_of_intervals("TX")[0]
- self.log.info("Duration: %s" % str(duration))
-
- return duration
-
- def _ertm_mode_rx(self, mtu, packets, tx_window_size=10):
- # Make sure that number of packets is a multiple of tx_window_size
- packets = packets // tx_window_size * tx_window_size
-
- self._setup_link_from_cert()
-
- config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=tx_window_size)
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM,
- fcs=FcsType.NO_FCS,
- req_config_options=config,
- rsp_config_options=config)
-
- data = b"a" * mtu
- data_packet = RawBuilder([x for x in data])
- self.performance_test_logger.start_interval("RX")
- for i in range(packets):
- cert_channel.send_i_frame(tx_seq=i % 64, req_seq=0, payload=data_packet)
- if i % tx_window_size == (tx_window_size - 1):
- assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=(i + 1) % 64))
- self.performance_test_logger.end_interval("RX")
-
- duration = self.performance_test_logger.get_duration_of_intervals("RX")[0]
- self.log.info("Duration: %s" % str(duration))
-
- def test_basic_mode_tx_672_100(self):
- duration = self._basic_mode_tx(672, 100)
- assertThat(duration).isWithin(timedelta(seconds=2))
-
- def test_basic_mode_tx_100_100(self):
- duration = self._basic_mode_tx(100, 100)
- assertThat(duration).isWithin(timedelta(seconds=2))
-
- def test_ertm_mode_tx_672_100(self):
- duration = self._ertm_mode_tx(672, 100)
- assertThat(duration).isWithin(timedelta(seconds=5))
-
- def test_basic_mode_rx_672_100(self):
- self._basic_mode_rx(672, 100)
-
- def test_ertm_mode_rx_672_100(self):
- self._ertm_mode_rx(672, 100)
-
- def test_basic_mode_end_to_end_latency(self):
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_channel_from_cert()
-
- data = b"a" * 100
- data_packet = RawBuilder([x for x in data])
- for i in range(100):
- self.performance_test_logger.start_interval("RX")
- cert_channel.send(data_packet)
- assertThat(dut_channel).emits(L2capMatchers.PacketPayloadRawData(data))
- self.performance_test_logger.end_interval("RX")
- duration = self.performance_test_logger.get_duration_of_intervals("RX")
- mean = sum(duration, timedelta()) / len(duration)
- self.log.info("Mean: %s" % str(mean))
-
- def test_basic_mode_number_of_packets_10_seconds_672(self):
- number_packets = self._basic_mode_tx_fixed_interval(672)
- # Requiring that 500 packets (20ms period on average) are sent
- self.log.info("Packets sent: %d" % number_packets)
- assertThat(number_packets > 500).isTrue()
+ L2capPerformanceTestBase.teardown_test(self)
+ GdBaseTestClass.teardown_test(self)
diff --git a/gd/l2cap/classic/cert/l2cap_performance_test_lib.py b/gd/l2cap/classic/cert/l2cap_performance_test_lib.py
new file mode 100644
index 0000000..5b0aa23
--- /dev/null
+++ b/gd/l2cap/classic/cert/l2cap_performance_test_lib.py
@@ -0,0 +1,187 @@
+#
+# Copyright 2020 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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 datetime import datetime, timedelta
+
+from bluetooth_packets_python3 import RawBuilder
+from cert.matchers import L2capMatchers
+from cert.truth import assertThat
+from cert.performance_test_logger import PerformanceTestLogger
+from l2cap.classic.cert.cert_l2cap import CertL2cap
+from l2cap.classic.cert.l2cap_test_lib import GeneralL2capTestBase
+from l2cap.classic.facade_pb2 import RetransmissionFlowControlMode
+from bluetooth_packets_python3.l2cap_packets import FcsType
+from bluetooth_packets_python3.l2cap_packets import SupervisoryFunction
+
+
+class L2capPerformanceTestBase(GeneralL2capTestBase):
+
+ def setup_test(self, dut, cert):
+ GeneralL2capTestBase.setup_test(self, dut, cert)
+ self.performance_test_logger = PerformanceTestLogger()
+
+ def teardown_test(self):
+ GeneralL2capTestBase.teardown_test(self)
+
+ def _basic_mode_tx(self, mtu, packets):
+ """
+ Send the specified number of packets and return the time interval in ms.
+ """
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert()
+ self.performance_test_logger.start_interval("TX")
+ for _ in range(packets):
+ dut_channel.send(b'a' * mtu)
+ assertThat(cert_channel).emits(
+ L2capMatchers.Data(b'a' * mtu), at_least_times=packets, timeout=timedelta(seconds=60))
+ self.performance_test_logger.end_interval("TX")
+
+ duration = self.performance_test_logger.get_duration_of_intervals("TX")[0]
+ self.log.info("Duration: %s" % str(duration))
+
+ return duration
+
+ def _basic_mode_tx_fixed_interval(self, mtu, interval=timedelta(seconds=10), batch_size=20):
+ """
+ Send packets as much as possible over a certain interval, and return the
+ number of packets sent
+ """
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert()
+ start_time = datetime.now()
+ end_time = start_time + interval
+ packets_sent = 0
+ while datetime.now() < end_time:
+ for _ in range(batch_size):
+ dut_channel.send(b'a' * mtu)
+ packets_sent += batch_size
+ assertThat(cert_channel).emits(L2capMatchers.Data(b'a' * mtu), at_least_times=batch_size)
+
+ return packets_sent
+
+ def _basic_mode_rx(self, mtu, packets):
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert()
+ self.performance_test_logger.start_interval("RX")
+ data = b"a" * mtu
+ data_packet = RawBuilder([x for x in data])
+ for _ in range(packets):
+ cert_channel.send(data_packet)
+ assertThat(dut_channel).emits(
+ L2capMatchers.PacketPayloadRawData(data), at_least_times=packets, timeout=timedelta(seconds=60))
+ self.performance_test_logger.end_interval("RX")
+
+ duration = self.performance_test_logger.get_duration_of_intervals("RX")[0]
+ self.log.info("Duration: %s" % str(duration))
+
+ def _ertm_mode_tx(self, mtu, packets, tx_window_size=10):
+ """
+ Send the specified number of packets and return the time interval in ms.
+ """
+ # Make sure that number of packets is a multiple of tx_window_size
+ packets = packets // tx_window_size * tx_window_size
+ # For ERTM TX test, we have to do it sequentially because cert needs to ack
+ self._setup_link_from_cert()
+
+ config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=tx_window_size)
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM,
+ fcs=FcsType.NO_FCS,
+ req_config_options=config,
+ rsp_config_options=config)
+
+ self.performance_test_logger.start_interval("TX")
+ for i in range(packets):
+ dut_channel.send(b'a' * mtu)
+ if i % tx_window_size == tx_window_size - 1:
+ assertThat(cert_channel).emits(L2capMatchers.IFrame(payload=b'a' * mtu), at_least_times=tx_window_size)
+ cert_channel.send_s_frame(req_seq=(i + 1) % 64, s=SupervisoryFunction.RECEIVER_READY)
+
+ self.performance_test_logger.end_interval("TX")
+
+ duration = self.performance_test_logger.get_duration_of_intervals("TX")[0]
+ self.log.info("Duration: %s" % str(duration))
+
+ return duration
+
+ def _ertm_mode_rx(self, mtu, packets, tx_window_size=10):
+ # Make sure that number of packets is a multiple of tx_window_size
+ packets = packets // tx_window_size * tx_window_size
+
+ self._setup_link_from_cert()
+
+ config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=tx_window_size)
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM,
+ fcs=FcsType.NO_FCS,
+ req_config_options=config,
+ rsp_config_options=config)
+
+ data = b"a" * mtu
+ data_packet = RawBuilder([x for x in data])
+ self.performance_test_logger.start_interval("RX")
+ for i in range(packets):
+ cert_channel.send_i_frame(tx_seq=i % 64, req_seq=0, payload=data_packet)
+ if i % tx_window_size == (tx_window_size - 1):
+ assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=(i + 1) % 64))
+ self.performance_test_logger.end_interval("RX")
+
+ duration = self.performance_test_logger.get_duration_of_intervals("RX")[0]
+ self.log.info("Duration: %s" % str(duration))
+
+ def test_basic_mode_tx_672_100(self):
+ duration = self._basic_mode_tx(672, 100)
+ assertThat(duration).isWithin(timedelta(seconds=2))
+
+ def test_basic_mode_tx_100_100(self):
+ duration = self._basic_mode_tx(100, 100)
+ assertThat(duration).isWithin(timedelta(seconds=2))
+
+ def test_ertm_mode_tx_672_100(self):
+ duration = self._ertm_mode_tx(672, 100)
+ assertThat(duration).isWithin(timedelta(seconds=5))
+
+ def test_basic_mode_rx_672_100(self):
+ self._basic_mode_rx(672, 100)
+
+ def test_ertm_mode_rx_672_100(self):
+ self._ertm_mode_rx(672, 100)
+
+ def test_basic_mode_end_to_end_latency(self):
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert()
+
+ data = b"a" * 100
+ data_packet = RawBuilder([x for x in data])
+ for i in range(100):
+ self.performance_test_logger.start_interval("RX")
+ cert_channel.send(data_packet)
+ assertThat(dut_channel).emits(L2capMatchers.PacketPayloadRawData(data))
+ self.performance_test_logger.end_interval("RX")
+ duration = self.performance_test_logger.get_duration_of_intervals("RX")
+ mean = sum(duration, timedelta()) / len(duration)
+ self.log.info("Mean: %s" % str(mean))
+
+ def test_basic_mode_number_of_packets_10_seconds_672(self):
+ number_packets = self._basic_mode_tx_fixed_interval(672)
+ # Requiring that 500 packets (20ms period on average) are sent
+ self.log.info("Packets sent: %d" % number_packets)
+ assertThat(number_packets > 500).isTrue()
diff --git a/gd/l2cap/classic/cert/l2cap_test.py b/gd/l2cap/classic/cert/l2cap_test.py
index 081ee7b..b795734 100644
--- a/gd/l2cap/classic/cert/l2cap_test.py
+++ b/gd/l2cap/classic/cert/l2cap_test.py
@@ -13,1276 +13,19 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from datetime import timedelta
-
-from mobly import asserts
-
-from bluetooth_packets_python3 import l2cap_packets
-from bluetooth_packets_python3 import RawBuilder
-from bluetooth_packets_python3.l2cap_packets import FcsType
-from bluetooth_packets_python3.l2cap_packets import Final
-from bluetooth_packets_python3.l2cap_packets import Poll
-from bluetooth_packets_python3.l2cap_packets import SegmentationAndReassembly
-from bluetooth_packets_python3.l2cap_packets import SupervisoryFunction
-from cert.behavior import when, anything, wait_until
-from cert.event_stream import EventStream
from cert.gd_base_test import GdBaseTestClass
-from cert.matchers import L2capMatchers
-from cert.metadata import metadata
-from cert.py_l2cap import PyL2cap
-from cert.truth import assertThat
-from facade import common_pb2
-from google.protobuf import empty_pb2 as empty_proto
-from l2cap.classic.cert.cert_l2cap import CertL2cap
-from l2cap.classic.facade_pb2 import RetransmissionFlowControlMode
-from neighbor.facade import facade_pb2 as neighbor_facade
-
-# Assemble a sample packet.
-SAMPLE_PACKET_DATA = b"\x19\x26\x08\x17"
-SAMPLE_PACKET = RawBuilder([x for x in SAMPLE_PACKET_DATA])
+from l2cap.classic.cert.l2cap_test_lib import L2capTestBase
-class L2capTestBase(GdBaseTestClass):
+class L2capTest(GdBaseTestClass, L2capTestBase):
def setup_class(self):
- super().setup_class(dut_module='L2CAP', cert_module='HCI_INTERFACES')
+ GdBaseTestClass.setup_class(self, dut_module='L2CAP', cert_module='HCI_INTERFACES')
def setup_test(self):
- super().setup_test()
-
- self.dut_address = self.dut.hci_controller.GetMacAddressSimple()
- cert_address = common_pb2.BluetoothAddress(
- address=self.cert.controller_read_only_property.ReadLocalAddress(empty_proto.Empty()).address)
-
- self.dut_l2cap = PyL2cap(self.dut, cert_address)
- self.cert_l2cap = CertL2cap(self.cert)
+ GdBaseTestClass.setup_test(self)
+ L2capTestBase.setup_test(self, self.dut, self.cert)
def teardown_test(self):
- self.cert_l2cap.close()
- self.dut_l2cap.close()
- super().teardown_test()
-
- def _setup_link_from_cert(self):
- self.dut.neighbor.EnablePageScan(neighbor_facade.EnableMsg(enabled=True))
- self.cert_l2cap.connect_acl(self.dut_address)
-
- def _open_unconfigured_channel_from_cert(self,
- signal_id=1,
- scid=0x0101,
- psm=0x33,
- mode=RetransmissionFlowControlMode.BASIC,
- fcs=None):
-
- dut_channel = self.dut_l2cap.register_dynamic_channel(psm, mode)
- cert_channel = self.cert_l2cap.open_channel(signal_id, psm, scid, fcs=fcs)
-
- return (dut_channel, cert_channel)
-
- def _open_channel_from_cert(self,
- signal_id=1,
- scid=0x0101,
- psm=0x33,
- mode=RetransmissionFlowControlMode.BASIC,
- fcs=None,
- req_config_options=None,
- rsp_config_options=None):
- request_matcher = L2capMatchers.ConfigurationRequestView(scid)
- if rsp_config_options is not None:
- when(self.cert_l2cap).on_config_req(request_matcher).then().send_configuration_response(
- options=rsp_config_options)
- if rsp_config_options is None and fcs is not None:
- when(self.cert_l2cap).on_config_req(request_matcher).then().send_configuration_response(
- options=CertL2cap.config_option_ertm(fcs=fcs))
-
- (dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert(signal_id, scid, psm, mode, fcs)
- if req_config_options is None:
- req_config_options = CertL2cap.config_option_ertm(
- fcs=fcs) if mode == RetransmissionFlowControlMode.ERTM else []
-
- cert_channel.send_configure_request(req_config_options)
-
- cert_channel.verify_configuration_response()
-
- wait_until(self.cert_l2cap).on_config_req(request_matcher).times(1)
-
- assertThat(cert_channel.is_configured()).isTrue()
-
- return (dut_channel, cert_channel)
-
- def _open_channel_from_dut(self, psm=0x33, mode=RetransmissionFlowControlMode.BASIC):
- dut_channel_future = self.dut_l2cap.connect_dynamic_channel_to_cert(psm, mode)
- cert_channel = self.cert_l2cap.verify_and_respond_open_channel_from_remote(psm)
- dut_channel = dut_channel_future.get_channel()
-
- cert_channel.verify_configuration_request_and_respond()
- outgoing_config = []
- if mode == RetransmissionFlowControlMode.ERTM:
- outgoing_config = CertL2cap.config_option_ertm()
- cert_channel.send_configure_request(outgoing_config)
- cert_channel.verify_configuration_response()
-
- return (dut_channel, cert_channel)
-
-
-class L2capTest(L2capTestBase):
-
- def test_connect_dynamic_channel_and_send_data(self):
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_channel_from_cert()
-
- dut_channel.send(b'abc')
- assertThat(cert_channel).emits(L2capMatchers.Data(b'abc'))
-
- def test_receive_packet_from_unknown_channel(self):
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(scid=0x41, psm=0x33)
-
- i_frame = l2cap_packets.EnhancedInformationFrameBuilder(
- 0x99, 0, Final.NOT_SET, 1, l2cap_packets.SegmentationAndReassembly.UNSEGMENTED, SAMPLE_PACKET)
- self.cert_l2cap.send_acl(i_frame)
- assertThat(cert_channel).emitsNone(L2capMatchers.SFrame(req_seq=4), timeout=timedelta(seconds=1))
-
- def test_open_two_channels(self):
- self._setup_link_from_cert()
-
- self._open_channel_from_cert(signal_id=1, scid=0x41, psm=0x41)
- self._open_channel_from_cert(signal_id=2, scid=0x43, psm=0x43)
-
- def test_connect_and_send_data_ertm_no_segmentation(self):
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
-
- dut_channel.send(b'abc' * 34)
- assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0, payload=b'abc' * 34))
-
- cert_channel.send_i_frame(tx_seq=0, req_seq=1, payload=SAMPLE_PACKET)
- # todo verify received?
-
- @metadata(pts_test_id="L2CAP/COS/CED/BV-01-C", pts_test_name="Request Connection")
- def test_basic_operation_request_connection(self):
- """
- Verify that the IUT is able to request the connection establishment for
- an L2CAP data channel and initiate the configuration procedure.
- """
- self._setup_link_from_cert()
- (dut_channel, cert_channel) = self._open_channel_from_dut()
-
- @metadata(pts_test_id="L2CAP/COS/CED/BV-03-C", pts_test_name="Send data")
- def test_send_data(self):
- """
- Verify that the IUT is able to send DATA
- """
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_channel_from_cert()
- dut_channel.send(b'hello')
- assertThat(cert_channel).emits(L2capMatchers.Data(b'hello'))
-
- @metadata(pts_test_id="L2CAP/COS/CED/BV-04-C", pts_test_name="Disconnect")
- def test_disconnect(self):
- """
- Verify that the IUT is able to disconnect the data channel
- """
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_channel_from_cert()
- dut_channel.close_channel()
- cert_channel.verify_disconnect_request()
-
- @metadata(pts_test_id="L2CAP/COS/CED/BV-05-C", pts_test_name="Accept connection")
- def test_accept_connection(self):
- """
- Also verify that DUT can send 48 bytes PDU (minimal MTU)
- """
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_channel_from_cert()
- dut_channel.send(b'a' * 48)
- assertThat(cert_channel).emits(L2capMatchers.Data(b'a' * 48))
-
- @metadata(pts_test_id="L2CAP/COS/CED/BV-07-C", pts_test_name="Accept Disconnect")
- def test_accept_disconnect(self):
- """
- Verify that the IUT is able to respond to the request to disconnect the
- data channel
- """
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_channel_from_cert()
- cert_channel.disconnect_and_verify()
-
- @metadata(pts_test_id="L2CAP/COS/CED/BV-08-C", pts_test_name="Disconnect on Timeout")
- def test_disconnect_on_timeout(self):
- """
- Verify that the IUT disconnects the data channel and shuts down this
- channel if no response occurs
- """
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert()
-
- assertThat(self.cert_l2cap.get_control_channel()).emitsNone(L2capMatchers.ConfigurationResponse())
- # TODO: Verify that IUT sends disconnect request (not mandated)
-
- @metadata(pts_test_id="L2CAP/COS/CED/BV-09-C", pts_test_name="Receive Multi-Command Packet")
- def test_receive_multi_command_packet(self):
- """
- Verify that the IUT is able to receive more than one signaling command in one L2CAP
- packet.
- """
- self._setup_link_from_cert()
-
- psm = 0x33
- self.dut_l2cap.connect_dynamic_channel_to_cert(psm)
- self.cert_l2cap.verify_and_respond_open_channel_from_remote_and_send_config_req(psm)
-
- assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.ConfigurationResponse())
-
- @metadata(pts_test_id="L2CAP/COS/CED/BV-11-C", pts_test_name="Configure MTU size")
- def test_configure_mtu_size(self):
- """
- Verify that the IUT is able to configure the supported MTU size
- """
- self._setup_link_from_cert()
- (dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert()
- cert_channel.send_configure_request(CertL2cap.config_option_mtu_explicit(672))
- cert_channel.verify_configuration_request_and_respond()
- # TODO: Probably remove verify_configuration_request_and_respond
-
- @metadata(pts_test_id="L2CAP/COS/CFD/BV-01-C", pts_test_name="Continuation Flag")
- def test_continuation_flag(self):
- """
- Verify the IUT is able to receive configuration requests that have the
- continuation flag set
- """
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert()
-
- # Send configuration request with CONTINUE
- mtu_opt = l2cap_packets.MtuConfigurationOption()
- mtu_opt.mtu = 0x1234
- cert_channel.send_configure_request([mtu_opt], 2, l2cap_packets.Continuation.CONTINUE)
-
- flush_timeout_option = l2cap_packets.FlushTimeoutConfigurationOption()
- flush_timeout_option.flush_timeout = 65535
- cert_channel.send_configure_request([flush_timeout_option], 3, l2cap_packets.Continuation.END)
-
- assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.ConfigurationResponse(), at_least_times=2)
-
- @metadata(pts_test_id="L2CAP/COS/CFD/BV-02-C", pts_test_name="Negotiation with Reject")
- def test_retry_config_after_rejection(self):
- """
- Verify that the IUT is able to perform negotiation while the Lower
- Tester rejects the proposed configuration parameter values
- """
- self._setup_link_from_cert()
- scid = 0x41
- when(self.cert_l2cap).on_config_req(
- L2capMatchers.ConfigurationRequestView(scid)).then().send_configuration_response(
- result=l2cap_packets.ConfigurationResponseResult.UNACCEPTABLE_PARAMETERS,
- options=CertL2cap.config_option_mtu_explicit(200)).send_configuration_response(options=[])
- (dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert(scid=scid)
-
- assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.ConfigurationRequest(), at_least_times=2)
-
- @metadata(pts_test_id="L2CAP/COS/CFD/BV-03-C", pts_test_name="Send Requested Options")
- def test_send_requested_options(self):
- """
- Verify that the IUT can receive a configuration request with no options
- and send the requested options to the Lower Tester
- """
- self._setup_link_from_cert()
- (dut_channel, cert_channel) = self._open_channel_from_cert(scid=0x41, psm=0x33)
-
- # TODO(hsz) implement me!
-
- @metadata(pts_test_id="L2CAP/COS/CFD/BV-08-C", pts_test_name="Non-blocking Config Response")
- def test_non_blocking_config_response(self):
- """
- Verify that the IUT does not block transmitting L2CAP_ConfigRsp while
- waiting for L2CAP_ConfigRsp from the Lower Tester
- """
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert()
-
- cert_channel.send_configure_request([])
- cert_channel.verify_configuration_response()
- cert_channel.verify_configuration_request_and_respond()
-
- # TODO(hsz) implement me!
-
- @metadata(pts_test_id="L2CAP/COS/CFD/BV-09-C", pts_test_name="Mandatory 48 Byte MTU")
- def test_mandatory_48_byte_mtu(self):
- """
- Verify that the IUT can support mandatory 48 byte MTU
- """
- self._setup_link_from_cert()
- (dut_channel,
- cert_channel) = self._open_channel_from_cert(req_config_options=CertL2cap.config_option_mtu_explicit(48))
-
- dut_channel.send(b"a" * 44)
- assertThat(cert_channel).emits(L2capMatchers.Data(b"a" * 44))
-
- @metadata(pts_test_id="L2CAP/COS/CFD/BV-11-C", pts_test_name="Negotiation of Unsupported Parameter")
- def test_negotiation_of_unsupported_parameter(self):
- """
- Verify that the IUT can negotiate when the Lower Tester proposes an unsupported configuration
- parameter value.
- """
- self._setup_link_from_cert()
- (dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert()
-
- cert_channel.send_configure_request(CertL2cap.config_option_mtu_explicit(20))
- # Invalid because minimum is 48
-
- cert_channel.verify_configuration_response(l2cap_packets.ConfigurationResponseResult.UNACCEPTABLE_PARAMETERS)
-
- @metadata(pts_test_id="L2CAP/COS/CFD/BV-12-C", pts_test_name="Unknown Option Response")
- def test_config_unknown_options_with_hint(self):
- """
- Verify that the IUT can give the appropriate error code when the Lower
- Tester proposes any number of unknown options that are optional
- NOTE: In GD stack, ExtendedWindowSizeOption in unsupported
- """
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert()
-
- unknown_opt_hint = l2cap_packets.ExtendedWindowSizeOption()
- unknown_opt_hint.max_window_size = 20
- unknown_opt_hint.is_hint = l2cap_packets.ConfigurationOptionIsHint.OPTION_IS_A_HINT
-
- for i in range(10):
- cert_channel.send_configure_request([unknown_opt_hint] * i)
- cert_channel.verify_configuration_response(l2cap_packets.ConfigurationResponseResult.SUCCESS)
-
- @metadata(pts_test_id="L2CAP/COS/CFD/BV-14-C", pts_test_name="Unknown Mandatory Options Request")
- def test_unknown_mandatory_options_request(self):
- """
- Verify that the IUT can give the appropriate error code when the Lower
- Tester proposes any number of unknown options where at least one is
- mandatory.
- Note: GD stack doesn't support extended window size. For other stacks,
- we may need to use some other config option
- """
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert(scid=0x41, psm=0x33)
-
- unknown_opt = l2cap_packets.ExtendedWindowSizeOption()
- unknown_opt.max_window_size = 20
-
- unknown_opt_hint = l2cap_packets.ExtendedWindowSizeOption()
- unknown_opt_hint.max_window_size = 20
- unknown_opt_hint.is_hint = l2cap_packets.ConfigurationOptionIsHint.OPTION_IS_A_HINT
-
- configuration_option_attempts = [[unknown_opt], [unknown_opt, unknown_opt_hint], [
- unknown_opt, unknown_opt, unknown_opt
- ], [unknown_opt, unknown_opt_hint, unknown_opt_hint,
- unknown_opt], [unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt], [
- unknown_opt, unknown_opt_hint, unknown_opt_hint, unknown_opt, unknown_opt_hint, unknown_opt_hint
- ], [unknown_opt, unknown_opt, unknown_opt, unknown_opt, unknown_opt, unknown_opt, unknown_opt], [
- unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt_hint,
- unknown_opt_hint, unknown_opt_hint, unknown_opt
- ], [
- unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt_hint,
- unknown_opt_hint, unknown_opt_hint, unknown_opt, unknown_opt
- ], [
- unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt_hint,
- unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt
- ]]
-
- for option_list in configuration_option_attempts:
- cert_channel.send_configure_request(option_list)
- cert_channel.verify_configuration_response(l2cap_packets.ConfigurationResponseResult.UNKNOWN_OPTIONS)
-
- @metadata(pts_test_id="L2CAP/COS/ECH/BV-01-C", pts_test_name="Respond to Echo Request")
- def test_respond_to_echo_request(self):
- """
- Verify that the IUT responds to an echo request.
- """
- self._setup_link_from_cert()
- echo_request = l2cap_packets.EchoRequestBuilder(100, RawBuilder([1, 2, 3]))
- self.cert_l2cap.get_control_channel().send(echo_request)
-
- assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.EchoResponse())
-
- @metadata(pts_test_id="L2CAP/COS/CED/BI-01-C", pts_test_name="Reject Unknown Command")
- def test_reject_unknown_command(self):
- """
- Verify that the IUT rejects an unknown signaling command
- """
- self._setup_link_from_cert()
-
- # Command code ff, Signal id 01, size 0000
- invalid_command_packet = RawBuilder([0xff, 0x01, 0x00, 0x00])
- self.cert_l2cap.get_control_channel().send(invalid_command_packet)
-
- assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.CommandReject())
-
- @metadata(pts_test_id="L2CAP/COS/IEX/BV-01-C", pts_test_name="Query for 1.2 Features")
- def test_query_for_1_2_features(self):
- """
- Verify that the IUT transmits an information request command to solicit
- if the remote device supports Specification 1.2 features.
- """
- self._setup_link_from_cert()
- assertThat(self.cert_l2cap.get_control_channel()).emits(
- L2capMatchers.InformationRequestWithType(
- l2cap_packets.InformationRequestInfoType.EXTENDED_FEATURES_SUPPORTED))
-
- @metadata(pts_test_id="L2CAP/COS/IEX/BV-02-C", pts_test_name="Respond with 1.2 Features")
- def test_respond_with_1_2_features(self):
- """
- Verify that the IUT responds to an information request command
- soliciting for Specification 1.2 features
- """
- self._setup_link_from_cert()
- control_channel = self.cert_l2cap.get_control_channel()
-
- control_channel.send_extended_features_request()
-
- assertThat(control_channel).emits(L2capMatchers.InformationResponseExtendedFeatures())
-
- @metadata(
- pts_test_id="L2CAP/EXF/BV-01-C",
- pts_test_name="Extended Features Information Response for "
- "Enhanced Retransmission Mode")
- def test_extended_feature_info_response_ertm(self):
- """
- Verify the IUT can format an Information Response for the information
- type of Extended Features that correctly identifies that Enhanced
- Retransmission Mode is locally supported
- """
- self._setup_link_from_cert()
- control_channel = self.cert_l2cap.get_control_channel()
-
- control_channel.send_extended_features_request()
-
- assertThat(control_channel).emits(L2capMatchers.InformationResponseExtendedFeatures(supports_ertm=True))
-
- @metadata(
- pts_test_id="L2CAP/EXF/BV-02-C", pts_test_name="Extended Features Information Response for "
- "Streaming Mode")
- def test_extended_feature_info_response_streaming(self):
- """
- Verify the IUT can format an Information Response for the information
- type of Extended Features that correctly identifies that Streaming Mode
- is locally supported
- """
- asserts.skip("Streaming not supported")
- self._setup_link_from_cert()
- control_channel = self.cert_l2cap.get_control_channel()
-
- control_channel.send_extended_features_request()
-
- assertThat(control_channel).emits(L2capMatchers.InformationResponseExtendedFeatures(supports_streaming=True))
-
- @metadata(pts_test_id="L2CAP/EXF/BV-03-C", pts_test_name="Extended Features Information Response for FCS " "Option")
- def test_extended_feature_info_response_fcs(self):
- """
- Verify the IUT can format an Information Response for the information
- type of Extended Features that correctly identifies that the FCS Option
- is locally supported.
-
- Note: This is not mandated by L2CAP Spec
- """
- self._setup_link_from_cert()
- control_channel = self.cert_l2cap.get_control_channel()
-
- control_channel.send_extended_features_request()
-
- assertThat(control_channel).emits(L2capMatchers.InformationResponseExtendedFeatures(supports_fcs=True))
-
- @metadata(
- pts_test_id="L2CAP/EXF/BV-05-C", pts_test_name="Extended Features Information Response for Fixed "
- "Channels")
- def test_extended_feature_info_response_fixed_channels(self):
- """
- Verify the IUT can format an Information Response for the information
- type of Extended Features that correctly identifies that the Fixed
- Channels option is locally supported
-
- Note: This is not mandated by L2CAP Spec
- """
- self._setup_link_from_cert()
- control_channel = self.cert_l2cap.get_control_channel()
-
- control_channel.send_extended_features_request()
-
- assertThat(control_channel).emits(
- L2capMatchers.InformationResponseExtendedFeatures(supports_fixed_channels=True))
-
- @metadata(pts_test_id="L2CAP/FIX/BV-01-C", pts_test_name="Fixed Channels Supported Information Request")
- def test_fixed_channels_supported_information_request(self):
- """
- Verify that the IUT can send an Information Request for the information
- type of Fixed Channels Supported.
- """
- self._setup_link_from_cert()
- assertThat(self.cert_l2cap.get_control_channel()).emits(
- L2capMatchers.InformationRequestWithType(l2cap_packets.InformationRequestInfoType.FIXED_CHANNELS_SUPPORTED))
-
- @metadata(pts_test_id="L2CAP/FOC/BV-01-C", pts_test_name="IUT Initiated Configuration of the FCS Option")
- def test_config_channel_not_use_FCS(self):
- """
- Verify the IUT can configure a channel to not use FCS in I/S-frames.
- """
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
-
- dut_channel.send(b'abc')
- assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0, payload=b'abc'))
-
- @metadata(pts_test_id="L2CAP/FOC/BV-02-C", pts_test_name="Lower Tester Explicitly Requests FCS should be " "Used")
- def test_explicitly_request_use_FCS(self):
- """
- Verify the IUT will include the FCS in I/S-frames if the Lower Tester
- explicitly requests that FCS should be used
- """
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.DEFAULT)
-
- dut_channel.send(b'abc')
- assertThat(cert_channel).emits(L2capMatchers.IFrameWithFcs(payload=b"abc"))
-
- @metadata(pts_test_id="L2CAP/FOC/BV-03-C", pts_test_name="Lower Tester Implicitly Requests FCS should be " "Used")
- def test_implicitly_request_use_FCS(self):
- """
- Verify the IUT will include the FCS in I/S-frames if the Lower Tester
- implicitly requests that FCS should be used.
- """
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM,
- fcs=FcsType.DEFAULT,
- req_config_options=CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS))
-
- dut_channel.send(b'abc')
- assertThat(cert_channel).emits(L2capMatchers.IFrameWithFcs(payload=b"abc"))
-
- @metadata(pts_test_id="L2CAP/OFS/BV-01-C", pts_test_name="Sending I-Frames without FCS for ERTM")
- def test_sending_i_frames_without_fcs_for_ertm(self):
- """
- Verify the IUT does not include the FCS in I-frames.
- """
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
-
- dut_channel.send(b'abc')
- assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0, payload=b"abc"))
-
- @metadata(pts_test_id="L2CAP/OFS/BV-02-C", pts_test_name="Receiving I-Frames without FCS for ERTM")
- def test_receiving_i_frames_without_fcs_for_ertm(self):
- """
- Verify the IUT can handle I-frames that do not contain the FCS.
- """
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
-
- cert_channel.send_i_frame(tx_seq=0, req_seq=0, payload=SAMPLE_PACKET)
- assertThat(dut_channel).emits(L2capMatchers.PacketPayloadRawData(SAMPLE_PACKET_DATA))
-
- @metadata(pts_test_id="L2CAP/OFS/BV-05-C", pts_test_name="Sending I-Frames with FCS for ERTM")
- def test_sending_i_frames_with_fcs_for_ertm(self):
- """
- Verify the IUT does include the FCS in I-frames.
- """
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.DEFAULT)
-
- dut_channel.send(b'abc')
- assertThat(cert_channel).emits(L2capMatchers.IFrameWithFcs(tx_seq=0, payload=b"abc"))
-
- @metadata(pts_test_id="L2CAP/OFS/BV-06-C", pts_test_name="Receiving I-Frames with FCS for ERTM")
- def test_receiving_i_frames_with_fcs_for_ertm(self):
- """
- Verify the IUT can handle I-frames that do contain the FCS.
- """
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.DEFAULT)
-
- cert_channel.send_i_frame(tx_seq=0, req_seq=0, payload=SAMPLE_PACKET, fcs=FcsType.DEFAULT)
- assertThat(dut_channel).emits(L2capMatchers.PacketPayloadRawData(SAMPLE_PACKET_DATA))
-
- @metadata(pts_test_id="L2CAP/ERM/BV-01-C", pts_test_name="Transmit I-frames")
- def test_transmit_i_frames(self):
- """
- Verify the IUT can send correctly formatted sequential I-frames with
- valid values for the enhanced control fields (SAR, F-bit, ReqSeq,
- TxSeq)
- """
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
-
- dut_channel.send(b'abc')
- assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0, payload=b"abc"))
-
- cert_channel.send_i_frame(tx_seq=0, req_seq=1, payload=SAMPLE_PACKET)
-
- dut_channel.send(b'abc')
- assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=1, payload=b"abc"))
-
- cert_channel.send_i_frame(tx_seq=1, req_seq=2, payload=SAMPLE_PACKET)
-
- dut_channel.send(b'abc')
- assertThat(cert_channel).emits(L2capMatchers.PartialData(b"abc"))
-
- cert_channel.send_i_frame(tx_seq=2, req_seq=3, payload=SAMPLE_PACKET)
-
- @metadata(pts_test_id="L2CAP/ERM/BV-02-C", pts_test_name="Receive I-Frames")
- def test_receive_i_frames(self):
- """
- Verify the IUT can receive in-sequence valid I-frames and deliver L2CAP
- SDUs to the Upper Tester
- """
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
-
- for i in range(3):
- cert_channel.send_i_frame(tx_seq=i, req_seq=0, payload=SAMPLE_PACKET)
- assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=i + 1))
-
- cert_channel.send_i_frame(tx_seq=3, req_seq=0, sar=SegmentationAndReassembly.START, payload=SAMPLE_PACKET)
- assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=4))
-
- cert_channel.send_i_frame(
- tx_seq=4, req_seq=0, sar=SegmentationAndReassembly.CONTINUATION, payload=SAMPLE_PACKET)
- assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=5))
-
- cert_channel.send_i_frame(tx_seq=5, req_seq=0, sar=SegmentationAndReassembly.END, payload=SAMPLE_PACKET)
- assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=6))
-
- @metadata(pts_test_id="L2CAP/ERM/BV-03-C", pts_test_name="Acknowledging Received I-Frames")
- def test_acknowledging_received_i_frames(self):
- """
- Verify the IUT sends S-frame [RR] with the Poll bit not set to
- acknowledge data received from the Lower Tester
- """
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
-
- for i in range(3):
- cert_channel.send_i_frame(tx_seq=i, req_seq=0, payload=SAMPLE_PACKET)
- assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=i + 1))
-
- assertThat(cert_channel).emitsNone(L2capMatchers.SFrame(req_seq=4), timeout=timedelta(seconds=1))
-
- @metadata(
- pts_test_id="L2CAP/ERM/BV-05-C",
- pts_test_name="Resume Transmitting I-Frames when an S-Frame [RR] "
- "is Received")
- def test_resume_transmitting_when_received_rr(self):
- """
- Verify the IUT will cease transmission of I-frames when the negotiated
- TxWindow is full. Verify the IUT will resume transmission of I-frames
- when an S-frame [RR] is received that acknowledges previously sent
- I-frames
- """
- self._setup_link_from_cert()
-
- config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=1)
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
-
- dut_channel.send(b'abc')
- dut_channel.send(b'def')
-
- assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0, payload=b'abc'))
- assertThat(cert_channel).emitsNone(L2capMatchers.IFrame(tx_seq=1, payload=b'def'))
-
- cert_channel.send_s_frame(req_seq=1, f=Final.POLL_RESPONSE)
- assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=1))
-
- @metadata(
- pts_test_id="L2CAP/ERM/BV-06-C", pts_test_name="Resume Transmitting I-Frames when an I-Frame is "
- "Received")
- def test_resume_transmitting_when_acknowledge_previously_sent(self):
- """
- Verify the IUT will cease transmission of I-frames when the negotiated
- TxWindow is full. Verify the IUT will resume transmission of I-frames
- when an I-frame is received that acknowledges previously sent I-frames
- """
- self._setup_link_from_cert()
-
- config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=1)
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
-
- dut_channel.send(b'abc')
- dut_channel.send(b'def')
-
- assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0, payload=b'abc'))
- assertThat(cert_channel).emitsNone(
- L2capMatchers.IFrame(tx_seq=1, payload=b'abc'), timeout=timedelta(seconds=0.5))
-
- cert_channel.send_i_frame(tx_seq=0, req_seq=1, payload=SAMPLE_PACKET)
-
- assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=1, payload=b'def'))
-
- cert_channel.send_i_frame(tx_seq=1, req_seq=2, payload=SAMPLE_PACKET)
-
- @metadata(pts_test_id="L2CAP/ERM/BV-07-C", pts_test_name="Send S-Frame [RNR]")
- def test_send_s_frame_rnr(self):
- """
- Verify the IUT sends an S-frame [RNR] when it detects local busy condition
- NOTE: In GD stack, we enter local busy condition if client doesn't dequeue
- and packets are accumulating in buffer
- """
- self._setup_link_from_cert()
-
- config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=10)
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM,
- fcs=FcsType.NO_FCS,
- req_config_options=config,
- rsp_config_options=config)
-
- dut_channel.send(b'abc')
- assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0, payload=b'abc'))
- cert_channel.send_i_frame(tx_seq=0, req_seq=1, payload=SAMPLE_PACKET)
-
- dut_channel.set_traffic_paused(True)
-
- # Allow 1 additional packet in channel queue buffer
- buffer_size = self.dut_l2cap.get_channel_queue_buffer_size() + 1
-
- for i in range(buffer_size):
- cert_channel.send_i_frame(tx_seq=i + 1, req_seq=1, payload=SAMPLE_PACKET)
- assertThat(cert_channel).emits(L2capMatchers.SFrame(s=l2cap_packets.SupervisoryFunction.RECEIVER_READY))
-
- cert_channel.send_i_frame(tx_seq=buffer_size + 1, req_seq=1, payload=SAMPLE_PACKET)
- assertThat(cert_channel).emits(L2capMatchers.SFrame(s=l2cap_packets.SupervisoryFunction.RECEIVER_NOT_READY))
-
- @metadata(pts_test_id="L2CAP/ERM/BV-08-C", pts_test_name="Send S-Frame [RR] with Poll Bit Set")
- def test_transmit_s_frame_rr_with_poll_bit_set(self):
- """
- Verify the IUT sends an S-frame [RR] with the Poll bit set when its
- retransmission timer expires.
- """
- self._setup_link_from_cert()
-
- config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, retransmission_time_out=1500)
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM,
- fcs=FcsType.NO_FCS,
- req_config_options=config,
- rsp_config_options=config)
-
- dut_channel.send(b'abc')
- assertThat(cert_channel).emits(L2capMatchers.SFrame(p=l2cap_packets.Poll.POLL))
-
- @metadata(pts_test_id="L2CAP/ERM/BV-09-C", pts_test_name="Send S-Frame [RR] with Final Bit Set")
- def test_transmit_s_frame_rr_with_final_bit_set(self):
- """
- Verify the IUT responds with an S-frame [RR] with the Final bit set
- after receiving an S-frame [RR] with the Poll bit set
- """
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
-
- cert_channel.send_s_frame(req_seq=0, p=Poll.POLL)
- assertThat(cert_channel).emits(L2capMatchers.SFrame(f=Final.POLL_RESPONSE))
-
- @metadata(pts_test_id="L2CAP/ERM/BV-10-C", pts_test_name="Retransmit S-Frame [RR] with Final Bit Set")
- def test_retransmit_s_frame_rr_with_poll_bit_set(self):
- """
- Verify the IUT will retransmit the S-frame [RR] with the Poll bit set
- when the Monitor Timer expires
- """
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
- dut_channel.send(b'abc')
-
- assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0, payload=b'abc'))
- assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=0, p=Poll.POLL, f=Final.NOT_SET))
- cert_channel.send_s_frame(req_seq=1, f=Final.POLL_RESPONSE)
-
- @metadata(pts_test_id="L2CAP/ERM/BV-11-C", pts_test_name="S-Frame Transmissions Exceed MaxTransmit")
- def test_s_frame_transmissions_exceed_max_transmit(self):
- """
- Verify the IUT will close the channel when the Monitor Timer expires.
- """
- self._setup_link_from_cert()
-
- config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=1, max_transmit=1, monitor_time_out=10)
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
-
- dut_channel.send(b'abc')
- cert_channel.verify_disconnect_request()
-
- @metadata(pts_test_id="L2CAP/ERM/BV-12-C", pts_test_name="I-Frame Transmissions Exceed MaxTransmit")
- def test_i_frame_transmissions_exceed_max_transmit(self):
- """
- Verify the IUT will close the channel when it receives an S-frame [RR]
- with the final bit set that does not acknowledge the previous I-frame
- sent by the IUT
- """
- self._setup_link_from_cert()
-
- config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=1, max_transmit=1)
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
-
- dut_channel.send(b'abc')
- assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0), L2capMatchers.SFrame(p=Poll.POLL)).inOrder()
-
- cert_channel.send_s_frame(req_seq=0, f=Final.POLL_RESPONSE)
- cert_channel.verify_disconnect_request()
-
- @metadata(pts_test_id="L2CAP/ERM/BV-13-C", pts_test_name="Respond to S-Frame [REJ]")
- def test_respond_to_rej(self):
- """
- Verify the IUT retransmits I-frames starting from the sequence number
- specified in the S-frame [REJ]
- """
- self._setup_link_from_cert()
-
- config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=2, max_transmit=2)
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
-
- dut_channel.send(b'abc')
- dut_channel.send(b'abc')
- assertThat(cert_channel).emits(
- L2capMatchers.IFrame(tx_seq=0, payload=b'abc'), L2capMatchers.IFrame(tx_seq=1, payload=b'abc')).inOrder()
-
- cert_channel.send_s_frame(req_seq=0, s=SupervisoryFunction.REJECT)
-
- assertThat(cert_channel).emits(
- L2capMatchers.IFrame(tx_seq=0, payload=b'abc'), L2capMatchers.IFrame(tx_seq=1, payload=b'abc')).inOrder()
-
- @metadata(pts_test_id="L2CAP/ERM/BV-14-C", pts_test_name="Respond to S-Frame [SREJ] POLL Bit Set")
- def test_respond_to_srej_p_set(self):
- """
- Verify the IUT responds with the correct I-frame when sent an SREJ
- frame. Verify that the IUT processes the acknowledgment of previously
- unacknowledged I-frames
- """
- self._setup_link_from_cert()
-
- config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, max_transmit=2, tx_window_size=3)
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
-
- for _ in range(4):
- dut_channel.send(b'abc')
- assertThat(cert_channel).emits(
- L2capMatchers.IFrame(tx_seq=0, payload=b'abc'), L2capMatchers.IFrame(tx_seq=1, payload=b'abc'),
- L2capMatchers.IFrame(tx_seq=2, payload=b'abc')).inOrder()
-
- cert_channel.send_s_frame(req_seq=1, p=Poll.POLL, s=SupervisoryFunction.SELECT_REJECT)
-
- assertThat(cert_channel).emits(
- L2capMatchers.IFrame(tx_seq=1, payload=b'abc', f=Final.POLL_RESPONSE),
- L2capMatchers.IFrame(tx_seq=3, payload=b'abc')).inOrder()
-
- @metadata(pts_test_id="L2CAP/ERM/BV-15-C", pts_test_name="Respond to S-Frame [SREJ] POLL Bit Clear")
- def test_respond_to_srej_p_clear(self):
- """
- Verify the IUT responds with the correct I-frame when sent an SREJ frame
- """
- self._setup_link_from_cert()
-
- config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, max_transmit=2, tx_window_size=3)
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
-
- for _ in range(4):
- dut_channel.send(b'abc')
- assertThat(cert_channel).emits(
- L2capMatchers.IFrame(tx_seq=0, payload=b'abc'), L2capMatchers.IFrame(tx_seq=1, payload=b'abc'),
- L2capMatchers.IFrame(tx_seq=2, payload=b'abc')).inOrder()
-
- cert_channel.send_s_frame(req_seq=1, s=SupervisoryFunction.SELECT_REJECT)
- assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=1, payload=b'abc', f=Final.NOT_SET))
- cert_channel.send_s_frame(req_seq=3, s=SupervisoryFunction.RECEIVER_READY)
- assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=3, payload=b'abc', f=Final.NOT_SET))
-
- @metadata(pts_test_id="L2CAP/ERM/BV-16-C", pts_test_name="Send S-Frame [REJ]")
- def test_send_s_frame_rej(self):
- """
- Verify the IUT can send an S-Frame [REJ] after receiving out of sequence
- I-Frames
- """
- self._setup_link_from_cert()
- tx_window_size = 4
-
- config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=tx_window_size)
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
-
- cert_channel.send_i_frame(tx_seq=0, req_seq=0, f=Final.NOT_SET, payload=SAMPLE_PACKET)
- cert_channel.send_i_frame(tx_seq=2, req_seq=0, f=Final.NOT_SET, payload=SAMPLE_PACKET)
-
- assertThat(cert_channel).emits(
- L2capMatchers.SFrame(req_seq=1, f=Final.NOT_SET, s=SupervisoryFunction.REJECT, p=Poll.NOT_SET))
-
- for i in range(1, tx_window_size):
- cert_channel.send_i_frame(tx_seq=i, req_seq=0, f=Final.NOT_SET, payload=SAMPLE_PACKET)
- assertThat(cert_channel).emits(
- L2capMatchers.SFrame(req_seq=i + 1, f=Final.NOT_SET, s=SupervisoryFunction.RECEIVER_READY))
-
- @metadata(pts_test_id="L2CAP/ERM/BV-18-C", pts_test_name="Receive S-Frame [RR] Final Bit = 1")
- def test_receive_s_frame_rr_final_bit_set(self):
- """
- Verify the IUT will retransmit any previously sent I-frames
- unacknowledged by receipt of an S-Frame [RR] with the Final Bit set
- """
- self._setup_link_from_cert()
-
- config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, retransmission_time_out=1500)
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
-
- dut_channel.send(b'abc')
-
- assertThat(cert_channel).emits(L2capMatchers.SFrame(p=l2cap_packets.Poll.POLL))
-
- cert_channel.send_s_frame(req_seq=0, f=Final.POLL_RESPONSE)
- assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0))
-
- @metadata(pts_test_id="L2CAP/ERM/BV-19-C", pts_test_name="Receive I-Frame Final Bit = 1")
- def test_receive_i_frame_final_bit_set(self):
- """
- Verify the IUT will retransmit any previously sent I-frames
- unacknowledged by receipt of an I-frame with the final bit set
- """
- self._setup_link_from_cert()
-
- config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, retransmission_time_out=1500)
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
-
- dut_channel.send(b'abc')
- assertThat(cert_channel).emits(L2capMatchers.SFrame(p=Poll.POLL))
-
- cert_channel.send_i_frame(tx_seq=0, req_seq=0, f=Final.POLL_RESPONSE, payload=SAMPLE_PACKET)
- assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0))
-
- @metadata(pts_test_id="L2CAP/ERM/BV-20-C", pts_test_name="Enter Remote Busy Condition")
- def test_receive_rnr(self):
- """
- Verify the IUT will not retransmit any I-frames when it receives a
- remote busy indication from the Lower Tester (S-frame [RNR])
- """
- self._setup_link_from_cert()
-
- config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, retransmission_time_out=1500)
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
-
- dut_channel.send(b'abc')
- assertThat(cert_channel).emits(L2capMatchers.SFrame(p=l2cap_packets.Poll.POLL))
-
- cert_channel.send_s_frame(req_seq=0, s=SupervisoryFunction.RECEIVER_NOT_READY, f=Final.POLL_RESPONSE)
- assertThat(cert_channel).emitsNone(L2capMatchers.IFrame(tx_seq=0))
-
- @metadata(pts_test_id="L2CAP/ERM/BV-22-C", pts_test_name="Exit Local Busy Condition")
- def test_exit_local_busy_condition(self):
- """
- Verify the IUT sends an S-frame [RR] Poll = 1 when the local busy condition is cleared
- NOTE: In GD stack, we enter local busy condition if client doesn't dequeue
- and packets are accumulating in buffer
- """
- self._setup_link_from_cert()
-
- config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=10)
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM,
- fcs=FcsType.NO_FCS,
- req_config_options=config,
- rsp_config_options=config)
-
- dut_channel.send(b'abc')
- assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0, payload=b'abc'))
- cert_channel.send_i_frame(tx_seq=0, req_seq=1, payload=SAMPLE_PACKET)
-
- dut_channel.set_traffic_paused(True)
-
- # Allow 1 additional packet in channel queue buffer
- buffer_size = self.dut_l2cap.get_channel_queue_buffer_size() + 1
-
- for i in range(buffer_size):
- cert_channel.send_i_frame(tx_seq=i + 1, req_seq=1, payload=SAMPLE_PACKET)
- assertThat(cert_channel).emits(L2capMatchers.SFrame(s=l2cap_packets.SupervisoryFunction.RECEIVER_READY))
-
- cert_channel.send_i_frame(tx_seq=buffer_size + 1, req_seq=1, payload=SAMPLE_PACKET)
- assertThat(cert_channel).emits(L2capMatchers.SFrame(s=l2cap_packets.SupervisoryFunction.RECEIVER_NOT_READY))
-
- dut_channel.set_traffic_paused(False)
- assertThat(cert_channel).emits(
- L2capMatchers.SFrame(s=l2cap_packets.SupervisoryFunction.RECEIVER_READY, p=l2cap_packets.Poll.POLL))
- cert_channel.send_s_frame(1, f=l2cap_packets.Final.POLL_RESPONSE)
-
- @metadata(pts_test_id="L2CAP/ERM/BV-23-C", pts_test_name="Transmit I-Frames using SAR")
- def test_transmit_i_frames_using_sar(self):
- """
- Verify the IUT can send correctly formatted sequential I-frames with
- valid values for the enhanced control fields (SAR, F-bit, ReqSeq,
- TxSeq) when performing SAR.
- """
- self._setup_link_from_cert()
-
- config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, mps=11)
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
-
- dut_channel.send(b'abcabcabc')
- # First IFrame should contain SDU size after control field
- assertThat(cert_channel).emits(
- L2capMatchers.IFrameStart(tx_seq=0, payload=b'abc'), L2capMatchers.IFrame(tx_seq=1, payload=b'abc'),
- L2capMatchers.IFrame(tx_seq=2, payload=b'abc')).inOrder()
-
- cert_channel.send_s_frame(req_seq=3, s=SupervisoryFunction.RECEIVER_READY)
-
- dut_channel.send(b'defdefdef')
- # First IFrame should contain SDU size after control field
- assertThat(cert_channel).emits(
- L2capMatchers.IFrameStart(tx_seq=3, payload=b'def'), L2capMatchers.IFrame(tx_seq=4, payload=b'def'),
- L2capMatchers.IFrame(tx_seq=5, payload=b'def')).inOrder()
-
- @metadata(pts_test_id="L2CAP/ERM/BI-01-C", pts_test_name="S-Frame [REJ] Lost or Corrupted")
- def test_sent_rej_lost(self):
- """
- Verify the IUT can handle receipt of an S-=frame [RR] Poll = 1 if the
- S-frame [REJ] sent from the IUT is lost
- """
- self._setup_link_from_cert()
- ertm_tx_window_size = 5
-
- config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=ertm_tx_window_size)
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
-
- cert_channel.send_i_frame(tx_seq=0, req_seq=0, payload=SAMPLE_PACKET)
- assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=1))
-
- cert_channel.send_i_frame(tx_seq=ertm_tx_window_size - 1, req_seq=0, payload=SAMPLE_PACKET)
- assertThat(cert_channel).emits(L2capMatchers.SFrame(s=SupervisoryFunction.REJECT))
-
- cert_channel.send_s_frame(req_seq=0, p=Poll.POLL)
-
- assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=1, f=l2cap_packets.Final.POLL_RESPONSE))
- for i in range(1, ertm_tx_window_size):
- cert_channel.send_i_frame(tx_seq=i, req_seq=0, payload=SAMPLE_PACKET)
- assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=i + 1))
-
- @metadata(pts_test_id="L2CAP/ERM/BI-03-C", pts_test_name="Handle Duplicate S-Frame [SREJ]")
- def test_handle_duplicate_srej(self):
- """
- Verify the IUT will only retransmit the requested I-frame once after
- receiving a duplicate SREJ
- """
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
-
- dut_channel.send(b'abc')
- dut_channel.send(b'abc')
- assertThat(cert_channel).emits(
- L2capMatchers.IFrame(tx_seq=0), L2capMatchers.IFrame(tx_seq=1),
- L2capMatchers.SFrame(p=Poll.POLL)).inOrder()
-
- cert_channel.send_s_frame(req_seq=0, s=SupervisoryFunction.SELECT_REJECT)
- assertThat(cert_channel).emitsNone(timeout=timedelta(seconds=0.5))
-
- cert_channel.send_s_frame(req_seq=0, s=SupervisoryFunction.SELECT_REJECT, f=Final.POLL_RESPONSE)
- assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0))
-
- @metadata(
- pts_test_id="L2CAP/ERM/BI-04-C",
- pts_test_name="Handle Receipt of S-Frame [REJ] and S-Frame "
- "[RR, F=1] that Both Require Retransmission of the "
- "Same I-Frames")
- def test_handle_receipt_rej_and_rr_with_f_set(self):
- """
- Verify the IUT will only retransmit the requested I-frames once after
- receiving an S-frame [REJ] followed by an S-frame [RR] with the Final
- bit set that indicates the same I-frames should be retransmitted
- """
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
-
- dut_channel.send(b'abc')
- dut_channel.send(b'abc')
- assertThat(cert_channel).emits(
- L2capMatchers.IFrame(tx_seq=0),
- L2capMatchers.IFrame(tx_seq=1),
- L2capMatchers.SFrame(p=l2cap_packets.Poll.POLL)).inOrder()
-
- cert_channel.send_s_frame(req_seq=0, s=SupervisoryFunction.REJECT)
- assertThat(cert_channel).emitsNone(timeout=timedelta(seconds=0.5))
-
- # Send RR with F set
- cert_channel.send_s_frame(req_seq=0, s=SupervisoryFunction.REJECT, f=Final.POLL_RESPONSE)
- assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0))
- assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=1))
-
- @metadata(
- pts_test_id="L2CAP/ERM/BI-05-C",
- pts_test_name="Handle receipt of S-Frame [REJ] and I-Frame [F=1] "
- "that Both Require Retransmission of the Same "
- "I-Frames")
- def test_handle_rej_and_i_frame_with_f_set(self):
- """
- Verify the IUT will only retransmit the requested I-frames once after
- receiving an S-frame [REJ] followed by an I-frame with the Final bit
- set that indicates the same I-frames should be retransmitted
- """
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
-
- dut_channel.send(b'abc')
- dut_channel.send(b'abc')
- assertThat(cert_channel).emits(
- L2capMatchers.IFrame(tx_seq=0),
- L2capMatchers.IFrame(tx_seq=1),
- L2capMatchers.SFrame(p=l2cap_packets.Poll.POLL)).inOrder()
-
- # Send SREJ with F not set
- cert_channel.send_s_frame(req_seq=0, s=SupervisoryFunction.SELECT_REJECT)
- assertThat(cert_channel).emitsNone(timeout=timedelta(seconds=0.5))
-
- cert_channel.send_i_frame(tx_seq=0, req_seq=0, f=Final.POLL_RESPONSE, payload=SAMPLE_PACKET)
-
- assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0))
- assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=1))
-
- @metadata(
- pts_test_id="L2CAP/CMC/BV-01-C", pts_test_name="IUT Initiated Configuration of Enhanced "
- "Retransmission Mode")
- def test_initiated_configuration_request_ertm(self):
- """
- Verify the IUT can send a Configuration Request command containing the
- F&EC option that specifies Enhanced Retransmission Mode
- """
- self._setup_link_from_cert()
-
- self._open_unconfigured_channel_from_cert(scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM)
-
- assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.ConfigurationRequestWithErtm())
-
- @metadata(
- pts_test_id="L2CAP/CMC/BV-02-C",
- pts_test_name="Lower Tester Initiated Configuration of Enhanced "
- "Retransmission Mode")
- def test_respond_configuration_request_ertm(self):
- """
- Verify the IUT can accept a Configuration Request from the Lower Tester
- containing an F&EC option that specifies Enhanced Retransmission Mode
- """
- self._setup_link_from_cert()
-
- self._open_channel_from_dut(psm=0x33, mode=RetransmissionFlowControlMode.ERTM)
-
- @metadata(
- pts_test_id="L2CAP/CMC/BV-12-C",
- pts_test_name="ERTM Not Supported by Lower Tester for Mandatory "
- "ERTM channel")
- def test_respond_not_support_ertm_when_using_mandatory_ertm(self):
- """
- The IUT is initiating connection of an L2CAP channel that mandates use
- of ERTM. Verify the IUT will not attempt to configure the connection to
- ERTM if the Lower Tester has not indicated support for ERTM in the
- Information Response [Extended Features]
- """
- self._setup_link_from_cert()
- self.cert_l2cap.claim_ertm_unsupported()
- dut_channel_future = self.dut_l2cap.connect_dynamic_channel_to_cert(
- psm=0x33, mode=RetransmissionFlowControlMode.ERTM)
- assertThat(self.cert_l2cap.get_control_channel()).emitsNone(L2capMatchers.ConnectionRequest(0x33))
-
- @metadata(
- pts_test_id="L2CAP/CMC/BI-01-C",
- pts_test_name="Failed Configuration of Enhanced Retransmission "
- "Mode when use of the Mode is Mandatory]")
- def test_config_respond_basic_mode_when_using_mandatory_ertm(self):
- """
- When creating a connection for a PSM that mandates the use of ERTM
- verify the IUT can handle receipt (close the channel in accordance with
- the specification) of a Configure Response indicating the peer L2CAP
- entity doesn’t wish to use Enhanced Retransmission Mode (Configure
- Response Result = Reject Unacceptable Parameters)
- """
-
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_channel_from_cert(
- mode=RetransmissionFlowControlMode.ERTM,
- req_config_options=CertL2cap.config_option_ertm(),
- rsp_config_options=CertL2cap.config_option_basic_explicit())
-
- cert_channel.verify_disconnect_request()
-
- @metadata(
- pts_test_id="L2CAP/CMC/BI-02-C",
- pts_test_name="Configuration Mode mismatch when use of Enhanced "
- "Retransmission Mode is Mandatory")
- def test_config_request_basic_mode_when_using_mandatory_ertm(self):
- """
- When creating a connection for a PSM that mandates the use of ERTM,
- verify the IUT will close the channel if the Lower Tester attempts to
- configure Basic Mode.
- """
- self._setup_link_from_cert()
-
- (dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert(mode=RetransmissionFlowControlMode.ERTM)
- cert_channel.send_configure_request(CertL2cap.config_option_basic_explicit())
- cert_channel.verify_disconnect_request()
-
- def test_initiate_connection_for_security(self):
- """
- This will test the PyL2cap API for initiating a connection for security
- via the security api
- """
- self.dut.neighbor.EnablePageScan(neighbor_facade.EnableMsg(enabled=True))
- self.cert.neighbor.EnablePageScan(neighbor_facade.EnableMsg(enabled=True))
- self.dut_l2cap.initiate_connection_for_security()
- self.cert_l2cap.accept_incoming_connection()
- self.dut_l2cap.verify_security_connection()
+ L2capTestBase.teardown_test(self)
+ GdBaseTestClass.teardown_test(self)
diff --git a/gd/l2cap/classic/cert/l2cap_test_lib.py b/gd/l2cap/classic/cert/l2cap_test_lib.py
new file mode 100644
index 0000000..7c1ec22
--- /dev/null
+++ b/gd/l2cap/classic/cert/l2cap_test_lib.py
@@ -0,0 +1,1284 @@
+#
+# 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 datetime import timedelta
+
+from mobly import asserts
+
+from bluetooth_packets_python3 import l2cap_packets
+from bluetooth_packets_python3 import RawBuilder
+from bluetooth_packets_python3.l2cap_packets import FcsType
+from bluetooth_packets_python3.l2cap_packets import Final
+from bluetooth_packets_python3.l2cap_packets import Poll
+from bluetooth_packets_python3.l2cap_packets import SegmentationAndReassembly
+from bluetooth_packets_python3.l2cap_packets import SupervisoryFunction
+from cert.behavior import when, anything, wait_until
+from cert.event_stream import EventStream
+from cert.matchers import L2capMatchers
+from cert.metadata import metadata
+from cert.py_l2cap import PyL2cap
+from cert.truth import assertThat
+from facade import common_pb2
+from google.protobuf import empty_pb2 as empty_proto
+from l2cap.classic.cert.cert_l2cap import CertL2cap
+from l2cap.classic.facade_pb2 import RetransmissionFlowControlMode
+from neighbor.facade import facade_pb2 as neighbor_facade
+
+# Assemble a sample packet.
+SAMPLE_PACKET_DATA = b"\x19\x26\x08\x17"
+SAMPLE_PACKET = RawBuilder([x for x in SAMPLE_PACKET_DATA])
+
+
+class GeneralL2capTestBase():
+
+ def setup_test(self, dut, cert):
+ self.dut = dut
+ self.cert = cert
+
+ self.dut_address = self.dut.hci_controller.GetMacAddressSimple()
+ cert_address = common_pb2.BluetoothAddress(
+ address=self.cert.controller_read_only_property.ReadLocalAddress(empty_proto.Empty()).address)
+
+ self.dut_l2cap = PyL2cap(self.dut, cert_address)
+ self.cert_l2cap = CertL2cap(self.cert)
+
+ def teardown_test(self):
+ self.cert_l2cap.close()
+ self.dut_l2cap.close()
+
+ def _setup_link_from_cert(self):
+ self.dut.neighbor.EnablePageScan(neighbor_facade.EnableMsg(enabled=True))
+ self.cert_l2cap.connect_acl(self.dut_address)
+
+ def _open_unconfigured_channel_from_cert(self,
+ signal_id=1,
+ scid=0x0101,
+ psm=0x33,
+ mode=RetransmissionFlowControlMode.BASIC,
+ fcs=None):
+
+ dut_channel = self.dut_l2cap.register_dynamic_channel(psm, mode)
+ cert_channel = self.cert_l2cap.open_channel(signal_id, psm, scid, fcs=fcs)
+
+ return (dut_channel, cert_channel)
+
+ def _open_channel_from_cert(self,
+ signal_id=1,
+ scid=0x0101,
+ psm=0x33,
+ mode=RetransmissionFlowControlMode.BASIC,
+ fcs=None,
+ req_config_options=None,
+ rsp_config_options=None):
+ request_matcher = L2capMatchers.ConfigurationRequestView(scid)
+ if rsp_config_options is not None:
+ when(self.cert_l2cap).on_config_req(request_matcher).then().send_configuration_response(
+ options=rsp_config_options)
+ if rsp_config_options is None and fcs is not None:
+ when(self.cert_l2cap).on_config_req(request_matcher).then().send_configuration_response(
+ options=CertL2cap.config_option_ertm(fcs=fcs))
+
+ (dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert(signal_id, scid, psm, mode, fcs)
+ if req_config_options is None:
+ req_config_options = CertL2cap.config_option_ertm(
+ fcs=fcs) if mode == RetransmissionFlowControlMode.ERTM else []
+
+ cert_channel.send_configure_request(req_config_options)
+
+ cert_channel.verify_configuration_response()
+
+ wait_until(self.cert_l2cap).on_config_req(request_matcher).times(1)
+
+ assertThat(cert_channel.is_configured()).isTrue()
+
+ return (dut_channel, cert_channel)
+
+ def _open_channel_from_dut(self, psm=0x33, mode=RetransmissionFlowControlMode.BASIC):
+ dut_channel_future = self.dut_l2cap.connect_dynamic_channel_to_cert(psm, mode)
+ cert_channel = self.cert_l2cap.verify_and_respond_open_channel_from_remote(psm)
+ dut_channel = dut_channel_future.get_channel()
+
+ cert_channel.verify_configuration_request_and_respond()
+ outgoing_config = []
+ if mode == RetransmissionFlowControlMode.ERTM:
+ outgoing_config = CertL2cap.config_option_ertm()
+ cert_channel.send_configure_request(outgoing_config)
+ cert_channel.verify_configuration_response()
+
+ return (dut_channel, cert_channel)
+
+
+class L2capTestBase(GeneralL2capTestBase):
+
+ def test_connect_dynamic_channel_and_send_data(self):
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert()
+
+ dut_channel.send(b'abc')
+ assertThat(cert_channel).emits(L2capMatchers.Data(b'abc'))
+
+ def test_receive_packet_from_unknown_channel(self):
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(scid=0x41, psm=0x33)
+
+ i_frame = l2cap_packets.EnhancedInformationFrameBuilder(
+ 0x99, 0, Final.NOT_SET, 1, l2cap_packets.SegmentationAndReassembly.UNSEGMENTED, SAMPLE_PACKET)
+ self.cert_l2cap.send_acl(i_frame)
+ assertThat(cert_channel).emitsNone(L2capMatchers.SFrame(req_seq=4), timeout=timedelta(seconds=1))
+
+ def test_open_two_channels(self):
+ self._setup_link_from_cert()
+
+ self._open_channel_from_cert(signal_id=1, scid=0x41, psm=0x41)
+ self._open_channel_from_cert(signal_id=2, scid=0x43, psm=0x43)
+
+ def test_connect_and_send_data_ertm_no_segmentation(self):
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
+
+ dut_channel.send(b'abc' * 34)
+ assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0, payload=b'abc' * 34))
+
+ cert_channel.send_i_frame(tx_seq=0, req_seq=1, payload=SAMPLE_PACKET)
+ # todo verify received?
+
+ @metadata(pts_test_id="L2CAP/COS/CED/BV-01-C", pts_test_name="Request Connection")
+ def test_basic_operation_request_connection(self):
+ """
+ Verify that the IUT is able to request the connection establishment for
+ an L2CAP data channel and initiate the configuration procedure.
+ """
+ self._setup_link_from_cert()
+ (dut_channel, cert_channel) = self._open_channel_from_dut()
+
+ @metadata(pts_test_id="L2CAP/COS/CED/BV-03-C", pts_test_name="Send data")
+ def test_send_data(self):
+ """
+ Verify that the IUT is able to send DATA
+ """
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert()
+ dut_channel.send(b'hello')
+ assertThat(cert_channel).emits(L2capMatchers.Data(b'hello'))
+
+ @metadata(pts_test_id="L2CAP/COS/CED/BV-04-C", pts_test_name="Disconnect")
+ def test_disconnect(self):
+ """
+ Verify that the IUT is able to disconnect the data channel
+ """
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert()
+ dut_channel.close_channel()
+ cert_channel.verify_disconnect_request()
+
+ @metadata(pts_test_id="L2CAP/COS/CED/BV-05-C", pts_test_name="Accept connection")
+ def test_accept_connection(self):
+ """
+ Also verify that DUT can send 48 bytes PDU (minimal MTU)
+ """
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert()
+ dut_channel.send(b'a' * 48)
+ assertThat(cert_channel).emits(L2capMatchers.Data(b'a' * 48))
+
+ @metadata(pts_test_id="L2CAP/COS/CED/BV-07-C", pts_test_name="Accept Disconnect")
+ def test_accept_disconnect(self):
+ """
+ Verify that the IUT is able to respond to the request to disconnect the
+ data channel
+ """
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert()
+ cert_channel.disconnect_and_verify()
+
+ @metadata(pts_test_id="L2CAP/COS/CED/BV-08-C", pts_test_name="Disconnect on Timeout")
+ def test_disconnect_on_timeout(self):
+ """
+ Verify that the IUT disconnects the data channel and shuts down this
+ channel if no response occurs
+ """
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert()
+
+ assertThat(self.cert_l2cap.get_control_channel()).emitsNone(L2capMatchers.ConfigurationResponse())
+ # TODO: Verify that IUT sends disconnect request (not mandated)
+
+ @metadata(pts_test_id="L2CAP/COS/CED/BV-09-C", pts_test_name="Receive Multi-Command Packet")
+ def test_receive_multi_command_packet(self):
+ """
+ Verify that the IUT is able to receive more than one signaling command in one L2CAP
+ packet.
+ """
+ self._setup_link_from_cert()
+
+ psm = 0x33
+ self.dut_l2cap.connect_dynamic_channel_to_cert(psm)
+ self.cert_l2cap.verify_and_respond_open_channel_from_remote_and_send_config_req(psm)
+
+ assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.ConfigurationResponse())
+
+ @metadata(pts_test_id="L2CAP/COS/CED/BV-11-C", pts_test_name="Configure MTU size")
+ def test_configure_mtu_size(self):
+ """
+ Verify that the IUT is able to configure the supported MTU size
+ """
+ self._setup_link_from_cert()
+ (dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert()
+ cert_channel.send_configure_request(CertL2cap.config_option_mtu_explicit(672))
+ cert_channel.verify_configuration_request_and_respond()
+ # TODO: Probably remove verify_configuration_request_and_respond
+
+ @metadata(pts_test_id="L2CAP/COS/CFD/BV-01-C", pts_test_name="Continuation Flag")
+ def test_continuation_flag(self):
+ """
+ Verify the IUT is able to receive configuration requests that have the
+ continuation flag set
+ """
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert()
+
+ # Send configuration request with CONTINUE
+ mtu_opt = l2cap_packets.MtuConfigurationOption()
+ mtu_opt.mtu = 0x1234
+ cert_channel.send_configure_request([mtu_opt], 2, l2cap_packets.Continuation.CONTINUE)
+
+ flush_timeout_option = l2cap_packets.FlushTimeoutConfigurationOption()
+ flush_timeout_option.flush_timeout = 65535
+ cert_channel.send_configure_request([flush_timeout_option], 3, l2cap_packets.Continuation.END)
+
+ assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.ConfigurationResponse(), at_least_times=2)
+
+ @metadata(pts_test_id="L2CAP/COS/CFD/BV-02-C", pts_test_name="Negotiation with Reject")
+ def test_retry_config_after_rejection(self):
+ """
+ Verify that the IUT is able to perform negotiation while the Lower
+ Tester rejects the proposed configuration parameter values
+ """
+ self._setup_link_from_cert()
+ scid = 0x41
+ when(self.cert_l2cap).on_config_req(
+ L2capMatchers.ConfigurationRequestView(scid)).then().send_configuration_response(
+ result=l2cap_packets.ConfigurationResponseResult.UNACCEPTABLE_PARAMETERS,
+ options=CertL2cap.config_option_mtu_explicit(200)).send_configuration_response(options=[])
+ (dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert(scid=scid)
+
+ assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.ConfigurationRequest(), at_least_times=2)
+
+ @metadata(pts_test_id="L2CAP/COS/CFD/BV-03-C", pts_test_name="Send Requested Options")
+ def test_send_requested_options(self):
+ """
+ Verify that the IUT can receive a configuration request with no options
+ and send the requested options to the Lower Tester
+ """
+ self._setup_link_from_cert()
+ (dut_channel, cert_channel) = self._open_channel_from_cert(scid=0x41, psm=0x33)
+
+ # TODO(hsz) implement me!
+
+ @metadata(pts_test_id="L2CAP/COS/CFD/BV-08-C", pts_test_name="Non-blocking Config Response")
+ def test_non_blocking_config_response(self):
+ """
+ Verify that the IUT does not block transmitting L2CAP_ConfigRsp while
+ waiting for L2CAP_ConfigRsp from the Lower Tester
+ """
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert()
+
+ cert_channel.send_configure_request([])
+ cert_channel.verify_configuration_response()
+ cert_channel.verify_configuration_request_and_respond()
+
+ # TODO(hsz) implement me!
+
+ @metadata(pts_test_id="L2CAP/COS/CFD/BV-09-C", pts_test_name="Mandatory 48 Byte MTU")
+ def test_mandatory_48_byte_mtu(self):
+ """
+ Verify that the IUT can support mandatory 48 byte MTU
+ """
+ self._setup_link_from_cert()
+ (dut_channel,
+ cert_channel) = self._open_channel_from_cert(req_config_options=CertL2cap.config_option_mtu_explicit(48))
+
+ dut_channel.send(b"a" * 44)
+ assertThat(cert_channel).emits(L2capMatchers.Data(b"a" * 44))
+
+ @metadata(pts_test_id="L2CAP/COS/CFD/BV-11-C", pts_test_name="Negotiation of Unsupported Parameter")
+ def test_negotiation_of_unsupported_parameter(self):
+ """
+ Verify that the IUT can negotiate when the Lower Tester proposes an unsupported configuration
+ parameter value.
+ """
+ self._setup_link_from_cert()
+ (dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert()
+
+ cert_channel.send_configure_request(CertL2cap.config_option_mtu_explicit(20))
+ # Invalid because minimum is 48
+
+ cert_channel.verify_configuration_response(l2cap_packets.ConfigurationResponseResult.UNACCEPTABLE_PARAMETERS)
+
+ @metadata(pts_test_id="L2CAP/COS/CFD/BV-12-C", pts_test_name="Unknown Option Response")
+ def test_config_unknown_options_with_hint(self):
+ """
+ Verify that the IUT can give the appropriate error code when the Lower
+ Tester proposes any number of unknown options that are optional
+ NOTE: In GD stack, ExtendedWindowSizeOption in unsupported
+ """
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert()
+
+ unknown_opt_hint = l2cap_packets.ExtendedWindowSizeOption()
+ unknown_opt_hint.max_window_size = 20
+ unknown_opt_hint.is_hint = l2cap_packets.ConfigurationOptionIsHint.OPTION_IS_A_HINT
+
+ for i in range(10):
+ cert_channel.send_configure_request([unknown_opt_hint] * i)
+ cert_channel.verify_configuration_response(l2cap_packets.ConfigurationResponseResult.SUCCESS)
+
+ @metadata(pts_test_id="L2CAP/COS/CFD/BV-14-C", pts_test_name="Unknown Mandatory Options Request")
+ def test_unknown_mandatory_options_request(self):
+ """
+ Verify that the IUT can give the appropriate error code when the Lower
+ Tester proposes any number of unknown options where at least one is
+ mandatory.
+ Note: GD stack doesn't support extended window size. For other stacks,
+ we may need to use some other config option
+ """
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert(scid=0x41, psm=0x33)
+
+ unknown_opt = l2cap_packets.ExtendedWindowSizeOption()
+ unknown_opt.max_window_size = 20
+
+ unknown_opt_hint = l2cap_packets.ExtendedWindowSizeOption()
+ unknown_opt_hint.max_window_size = 20
+ unknown_opt_hint.is_hint = l2cap_packets.ConfigurationOptionIsHint.OPTION_IS_A_HINT
+
+ configuration_option_attempts = [[unknown_opt], [unknown_opt, unknown_opt_hint], [
+ unknown_opt, unknown_opt, unknown_opt
+ ], [unknown_opt, unknown_opt_hint, unknown_opt_hint,
+ unknown_opt], [unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt], [
+ unknown_opt, unknown_opt_hint, unknown_opt_hint, unknown_opt, unknown_opt_hint, unknown_opt_hint
+ ], [unknown_opt, unknown_opt, unknown_opt, unknown_opt, unknown_opt, unknown_opt, unknown_opt], [
+ unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt_hint,
+ unknown_opt_hint, unknown_opt_hint, unknown_opt
+ ], [
+ unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt_hint,
+ unknown_opt_hint, unknown_opt_hint, unknown_opt, unknown_opt
+ ], [
+ unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt_hint,
+ unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt
+ ]]
+
+ for option_list in configuration_option_attempts:
+ cert_channel.send_configure_request(option_list)
+ cert_channel.verify_configuration_response(l2cap_packets.ConfigurationResponseResult.UNKNOWN_OPTIONS)
+
+ @metadata(pts_test_id="L2CAP/COS/ECH/BV-01-C", pts_test_name="Respond to Echo Request")
+ def test_respond_to_echo_request(self):
+ """
+ Verify that the IUT responds to an echo request.
+ """
+ self._setup_link_from_cert()
+ echo_request = l2cap_packets.EchoRequestBuilder(100, RawBuilder([1, 2, 3]))
+ self.cert_l2cap.get_control_channel().send(echo_request)
+
+ assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.EchoResponse())
+
+ @metadata(pts_test_id="L2CAP/COS/CED/BI-01-C", pts_test_name="Reject Unknown Command")
+ def test_reject_unknown_command(self):
+ """
+ Verify that the IUT rejects an unknown signaling command
+ """
+ self._setup_link_from_cert()
+
+ # Command code ff, Signal id 01, size 0000
+ invalid_command_packet = RawBuilder([0xff, 0x01, 0x00, 0x00])
+ self.cert_l2cap.get_control_channel().send(invalid_command_packet)
+
+ assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.CommandReject())
+
+ @metadata(pts_test_id="L2CAP/COS/IEX/BV-01-C", pts_test_name="Query for 1.2 Features")
+ def test_query_for_1_2_features(self):
+ """
+ Verify that the IUT transmits an information request command to solicit
+ if the remote device supports Specification 1.2 features.
+ """
+ self._setup_link_from_cert()
+ assertThat(self.cert_l2cap.get_control_channel()).emits(
+ L2capMatchers.InformationRequestWithType(
+ l2cap_packets.InformationRequestInfoType.EXTENDED_FEATURES_SUPPORTED))
+
+ @metadata(pts_test_id="L2CAP/COS/IEX/BV-02-C", pts_test_name="Respond with 1.2 Features")
+ def test_respond_with_1_2_features(self):
+ """
+ Verify that the IUT responds to an information request command
+ soliciting for Specification 1.2 features
+ """
+ self._setup_link_from_cert()
+ control_channel = self.cert_l2cap.get_control_channel()
+
+ control_channel.send_extended_features_request()
+
+ assertThat(control_channel).emits(L2capMatchers.InformationResponseExtendedFeatures())
+
+ @metadata(
+ pts_test_id="L2CAP/EXF/BV-01-C",
+ pts_test_name="Extended Features Information Response for "
+ "Enhanced Retransmission Mode")
+ def test_extended_feature_info_response_ertm(self):
+ """
+ Verify the IUT can format an Information Response for the information
+ type of Extended Features that correctly identifies that Enhanced
+ Retransmission Mode is locally supported
+ """
+ self._setup_link_from_cert()
+ control_channel = self.cert_l2cap.get_control_channel()
+
+ control_channel.send_extended_features_request()
+
+ assertThat(control_channel).emits(L2capMatchers.InformationResponseExtendedFeatures(supports_ertm=True))
+
+ @metadata(
+ pts_test_id="L2CAP/EXF/BV-02-C", pts_test_name="Extended Features Information Response for "
+ "Streaming Mode")
+ def test_extended_feature_info_response_streaming(self):
+ """
+ Verify the IUT can format an Information Response for the information
+ type of Extended Features that correctly identifies that Streaming Mode
+ is locally supported
+ """
+ asserts.skip("Streaming not supported")
+ self._setup_link_from_cert()
+ control_channel = self.cert_l2cap.get_control_channel()
+
+ control_channel.send_extended_features_request()
+
+ assertThat(control_channel).emits(L2capMatchers.InformationResponseExtendedFeatures(supports_streaming=True))
+
+ @metadata(pts_test_id="L2CAP/EXF/BV-03-C", pts_test_name="Extended Features Information Response for FCS " "Option")
+ def test_extended_feature_info_response_fcs(self):
+ """
+ Verify the IUT can format an Information Response for the information
+ type of Extended Features that correctly identifies that the FCS Option
+ is locally supported.
+
+ Note: This is not mandated by L2CAP Spec
+ """
+ self._setup_link_from_cert()
+ control_channel = self.cert_l2cap.get_control_channel()
+
+ control_channel.send_extended_features_request()
+
+ assertThat(control_channel).emits(L2capMatchers.InformationResponseExtendedFeatures(supports_fcs=True))
+
+ @metadata(
+ pts_test_id="L2CAP/EXF/BV-05-C", pts_test_name="Extended Features Information Response for Fixed "
+ "Channels")
+ def test_extended_feature_info_response_fixed_channels(self):
+ """
+ Verify the IUT can format an Information Response for the information
+ type of Extended Features that correctly identifies that the Fixed
+ Channels option is locally supported
+
+ Note: This is not mandated by L2CAP Spec
+ """
+ self._setup_link_from_cert()
+ control_channel = self.cert_l2cap.get_control_channel()
+
+ control_channel.send_extended_features_request()
+
+ assertThat(control_channel).emits(
+ L2capMatchers.InformationResponseExtendedFeatures(supports_fixed_channels=True))
+
+ @metadata(pts_test_id="L2CAP/FIX/BV-01-C", pts_test_name="Fixed Channels Supported Information Request")
+ def test_fixed_channels_supported_information_request(self):
+ """
+ Verify that the IUT can send an Information Request for the information
+ type of Fixed Channels Supported.
+ """
+ self._setup_link_from_cert()
+ assertThat(self.cert_l2cap.get_control_channel()).emits(
+ L2capMatchers.InformationRequestWithType(l2cap_packets.InformationRequestInfoType.FIXED_CHANNELS_SUPPORTED))
+
+ @metadata(pts_test_id="L2CAP/FOC/BV-01-C", pts_test_name="IUT Initiated Configuration of the FCS Option")
+ def test_config_channel_not_use_FCS(self):
+ """
+ Verify the IUT can configure a channel to not use FCS in I/S-frames.
+ """
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
+
+ dut_channel.send(b'abc')
+ assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0, payload=b'abc'))
+
+ @metadata(pts_test_id="L2CAP/FOC/BV-02-C", pts_test_name="Lower Tester Explicitly Requests FCS should be " "Used")
+ def test_explicitly_request_use_FCS(self):
+ """
+ Verify the IUT will include the FCS in I/S-frames if the Lower Tester
+ explicitly requests that FCS should be used
+ """
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.DEFAULT)
+
+ dut_channel.send(b'abc')
+ assertThat(cert_channel).emits(L2capMatchers.IFrameWithFcs(payload=b"abc"))
+
+ @metadata(pts_test_id="L2CAP/FOC/BV-03-C", pts_test_name="Lower Tester Implicitly Requests FCS should be " "Used")
+ def test_implicitly_request_use_FCS(self):
+ """
+ Verify the IUT will include the FCS in I/S-frames if the Lower Tester
+ implicitly requests that FCS should be used.
+ """
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM,
+ fcs=FcsType.DEFAULT,
+ req_config_options=CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS))
+
+ dut_channel.send(b'abc')
+ assertThat(cert_channel).emits(L2capMatchers.IFrameWithFcs(payload=b"abc"))
+
+ @metadata(pts_test_id="L2CAP/OFS/BV-01-C", pts_test_name="Sending I-Frames without FCS for ERTM")
+ def test_sending_i_frames_without_fcs_for_ertm(self):
+ """
+ Verify the IUT does not include the FCS in I-frames.
+ """
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
+
+ dut_channel.send(b'abc')
+ assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0, payload=b"abc"))
+
+ @metadata(pts_test_id="L2CAP/OFS/BV-02-C", pts_test_name="Receiving I-Frames without FCS for ERTM")
+ def test_receiving_i_frames_without_fcs_for_ertm(self):
+ """
+ Verify the IUT can handle I-frames that do not contain the FCS.
+ """
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
+
+ cert_channel.send_i_frame(tx_seq=0, req_seq=0, payload=SAMPLE_PACKET)
+ assertThat(dut_channel).emits(L2capMatchers.PacketPayloadRawData(SAMPLE_PACKET_DATA))
+
+ @metadata(pts_test_id="L2CAP/OFS/BV-05-C", pts_test_name="Sending I-Frames with FCS for ERTM")
+ def test_sending_i_frames_with_fcs_for_ertm(self):
+ """
+ Verify the IUT does include the FCS in I-frames.
+ """
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.DEFAULT)
+
+ dut_channel.send(b'abc')
+ assertThat(cert_channel).emits(L2capMatchers.IFrameWithFcs(tx_seq=0, payload=b"abc"))
+
+ @metadata(pts_test_id="L2CAP/OFS/BV-06-C", pts_test_name="Receiving I-Frames with FCS for ERTM")
+ def test_receiving_i_frames_with_fcs_for_ertm(self):
+ """
+ Verify the IUT can handle I-frames that do contain the FCS.
+ """
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.DEFAULT)
+
+ cert_channel.send_i_frame(tx_seq=0, req_seq=0, payload=SAMPLE_PACKET, fcs=FcsType.DEFAULT)
+ assertThat(dut_channel).emits(L2capMatchers.PacketPayloadRawData(SAMPLE_PACKET_DATA))
+
+ @metadata(pts_test_id="L2CAP/ERM/BV-01-C", pts_test_name="Transmit I-frames")
+ def test_transmit_i_frames(self):
+ """
+ Verify the IUT can send correctly formatted sequential I-frames with
+ valid values for the enhanced control fields (SAR, F-bit, ReqSeq,
+ TxSeq)
+ """
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
+
+ dut_channel.send(b'abc')
+ assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0, payload=b"abc"))
+
+ cert_channel.send_i_frame(tx_seq=0, req_seq=1, payload=SAMPLE_PACKET)
+
+ dut_channel.send(b'abc')
+ assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=1, payload=b"abc"))
+
+ cert_channel.send_i_frame(tx_seq=1, req_seq=2, payload=SAMPLE_PACKET)
+
+ dut_channel.send(b'abc')
+ assertThat(cert_channel).emits(L2capMatchers.PartialData(b"abc"))
+
+ cert_channel.send_i_frame(tx_seq=2, req_seq=3, payload=SAMPLE_PACKET)
+
+ @metadata(pts_test_id="L2CAP/ERM/BV-02-C", pts_test_name="Receive I-Frames")
+ def test_receive_i_frames(self):
+ """
+ Verify the IUT can receive in-sequence valid I-frames and deliver L2CAP
+ SDUs to the Upper Tester
+ """
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
+
+ for i in range(3):
+ cert_channel.send_i_frame(tx_seq=i, req_seq=0, payload=SAMPLE_PACKET)
+ assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=i + 1))
+
+ cert_channel.send_i_frame(tx_seq=3, req_seq=0, sar=SegmentationAndReassembly.START, payload=SAMPLE_PACKET)
+ assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=4))
+
+ cert_channel.send_i_frame(
+ tx_seq=4, req_seq=0, sar=SegmentationAndReassembly.CONTINUATION, payload=SAMPLE_PACKET)
+ assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=5))
+
+ cert_channel.send_i_frame(tx_seq=5, req_seq=0, sar=SegmentationAndReassembly.END, payload=SAMPLE_PACKET)
+ assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=6))
+
+ @metadata(pts_test_id="L2CAP/ERM/BV-03-C", pts_test_name="Acknowledging Received I-Frames")
+ def test_acknowledging_received_i_frames(self):
+ """
+ Verify the IUT sends S-frame [RR] with the Poll bit not set to
+ acknowledge data received from the Lower Tester
+ """
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
+
+ for i in range(3):
+ cert_channel.send_i_frame(tx_seq=i, req_seq=0, payload=SAMPLE_PACKET)
+ assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=i + 1))
+
+ assertThat(cert_channel).emitsNone(L2capMatchers.SFrame(req_seq=4), timeout=timedelta(seconds=1))
+
+ @metadata(
+ pts_test_id="L2CAP/ERM/BV-05-C",
+ pts_test_name="Resume Transmitting I-Frames when an S-Frame [RR] "
+ "is Received")
+ def test_resume_transmitting_when_received_rr(self):
+ """
+ Verify the IUT will cease transmission of I-frames when the negotiated
+ TxWindow is full. Verify the IUT will resume transmission of I-frames
+ when an S-frame [RR] is received that acknowledges previously sent
+ I-frames
+ """
+ self._setup_link_from_cert()
+
+ config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=1)
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
+
+ dut_channel.send(b'abc')
+ dut_channel.send(b'def')
+
+ assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0, payload=b'abc'))
+ assertThat(cert_channel).emitsNone(L2capMatchers.IFrame(tx_seq=1, payload=b'def'))
+
+ cert_channel.send_s_frame(req_seq=1, f=Final.POLL_RESPONSE)
+ assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=1))
+
+ @metadata(
+ pts_test_id="L2CAP/ERM/BV-06-C", pts_test_name="Resume Transmitting I-Frames when an I-Frame is "
+ "Received")
+ def test_resume_transmitting_when_acknowledge_previously_sent(self):
+ """
+ Verify the IUT will cease transmission of I-frames when the negotiated
+ TxWindow is full. Verify the IUT will resume transmission of I-frames
+ when an I-frame is received that acknowledges previously sent I-frames
+ """
+ self._setup_link_from_cert()
+
+ config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=1)
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
+
+ dut_channel.send(b'abc')
+ dut_channel.send(b'def')
+
+ assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0, payload=b'abc'))
+ assertThat(cert_channel).emitsNone(
+ L2capMatchers.IFrame(tx_seq=1, payload=b'abc'), timeout=timedelta(seconds=0.5))
+
+ cert_channel.send_i_frame(tx_seq=0, req_seq=1, payload=SAMPLE_PACKET)
+
+ assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=1, payload=b'def'))
+
+ cert_channel.send_i_frame(tx_seq=1, req_seq=2, payload=SAMPLE_PACKET)
+
+ @metadata(pts_test_id="L2CAP/ERM/BV-07-C", pts_test_name="Send S-Frame [RNR]")
+ def test_send_s_frame_rnr(self):
+ """
+ Verify the IUT sends an S-frame [RNR] when it detects local busy condition
+ NOTE: In GD stack, we enter local busy condition if client doesn't dequeue
+ and packets are accumulating in buffer
+ """
+ self._setup_link_from_cert()
+
+ config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=10)
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM,
+ fcs=FcsType.NO_FCS,
+ req_config_options=config,
+ rsp_config_options=config)
+
+ dut_channel.send(b'abc')
+ assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0, payload=b'abc'))
+ cert_channel.send_i_frame(tx_seq=0, req_seq=1, payload=SAMPLE_PACKET)
+
+ dut_channel.set_traffic_paused(True)
+
+ # Allow 1 additional packet in channel queue buffer
+ buffer_size = self.dut_l2cap.get_channel_queue_buffer_size() + 1
+
+ for i in range(buffer_size):
+ cert_channel.send_i_frame(tx_seq=i + 1, req_seq=1, payload=SAMPLE_PACKET)
+ assertThat(cert_channel).emits(L2capMatchers.SFrame(s=l2cap_packets.SupervisoryFunction.RECEIVER_READY))
+
+ cert_channel.send_i_frame(tx_seq=buffer_size + 1, req_seq=1, payload=SAMPLE_PACKET)
+ assertThat(cert_channel).emits(L2capMatchers.SFrame(s=l2cap_packets.SupervisoryFunction.RECEIVER_NOT_READY))
+
+ @metadata(pts_test_id="L2CAP/ERM/BV-08-C", pts_test_name="Send S-Frame [RR] with Poll Bit Set")
+ def test_transmit_s_frame_rr_with_poll_bit_set(self):
+ """
+ Verify the IUT sends an S-frame [RR] with the Poll bit set when its
+ retransmission timer expires.
+ """
+ self._setup_link_from_cert()
+
+ config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, retransmission_time_out=1500)
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM,
+ fcs=FcsType.NO_FCS,
+ req_config_options=config,
+ rsp_config_options=config)
+
+ dut_channel.send(b'abc')
+ assertThat(cert_channel).emits(L2capMatchers.SFrame(p=l2cap_packets.Poll.POLL))
+
+ @metadata(pts_test_id="L2CAP/ERM/BV-09-C", pts_test_name="Send S-Frame [RR] with Final Bit Set")
+ def test_transmit_s_frame_rr_with_final_bit_set(self):
+ """
+ Verify the IUT responds with an S-frame [RR] with the Final bit set
+ after receiving an S-frame [RR] with the Poll bit set
+ """
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
+
+ cert_channel.send_s_frame(req_seq=0, p=Poll.POLL)
+ assertThat(cert_channel).emits(L2capMatchers.SFrame(f=Final.POLL_RESPONSE))
+
+ @metadata(pts_test_id="L2CAP/ERM/BV-10-C", pts_test_name="Retransmit S-Frame [RR] with Final Bit Set")
+ def test_retransmit_s_frame_rr_with_poll_bit_set(self):
+ """
+ Verify the IUT will retransmit the S-frame [RR] with the Poll bit set
+ when the Monitor Timer expires
+ """
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
+ dut_channel.send(b'abc')
+
+ assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0, payload=b'abc'))
+ assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=0, p=Poll.POLL, f=Final.NOT_SET))
+ cert_channel.send_s_frame(req_seq=1, f=Final.POLL_RESPONSE)
+
+ @metadata(pts_test_id="L2CAP/ERM/BV-11-C", pts_test_name="S-Frame Transmissions Exceed MaxTransmit")
+ def test_s_frame_transmissions_exceed_max_transmit(self):
+ """
+ Verify the IUT will close the channel when the Monitor Timer expires.
+ """
+ self._setup_link_from_cert()
+
+ config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=1, max_transmit=1, monitor_time_out=10)
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
+
+ dut_channel.send(b'abc')
+ cert_channel.verify_disconnect_request()
+
+ @metadata(pts_test_id="L2CAP/ERM/BV-12-C", pts_test_name="I-Frame Transmissions Exceed MaxTransmit")
+ def test_i_frame_transmissions_exceed_max_transmit(self):
+ """
+ Verify the IUT will close the channel when it receives an S-frame [RR]
+ with the final bit set that does not acknowledge the previous I-frame
+ sent by the IUT
+ """
+ self._setup_link_from_cert()
+
+ config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=1, max_transmit=1)
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
+
+ dut_channel.send(b'abc')
+ assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0), L2capMatchers.SFrame(p=Poll.POLL)).inOrder()
+
+ cert_channel.send_s_frame(req_seq=0, f=Final.POLL_RESPONSE)
+ cert_channel.verify_disconnect_request()
+
+ @metadata(pts_test_id="L2CAP/ERM/BV-13-C", pts_test_name="Respond to S-Frame [REJ]")
+ def test_respond_to_rej(self):
+ """
+ Verify the IUT retransmits I-frames starting from the sequence number
+ specified in the S-frame [REJ]
+ """
+ self._setup_link_from_cert()
+
+ config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=2, max_transmit=2)
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
+
+ dut_channel.send(b'abc')
+ dut_channel.send(b'abc')
+ assertThat(cert_channel).emits(
+ L2capMatchers.IFrame(tx_seq=0, payload=b'abc'), L2capMatchers.IFrame(tx_seq=1, payload=b'abc')).inOrder()
+
+ cert_channel.send_s_frame(req_seq=0, s=SupervisoryFunction.REJECT)
+
+ assertThat(cert_channel).emits(
+ L2capMatchers.IFrame(tx_seq=0, payload=b'abc'), L2capMatchers.IFrame(tx_seq=1, payload=b'abc')).inOrder()
+
+ @metadata(pts_test_id="L2CAP/ERM/BV-14-C", pts_test_name="Respond to S-Frame [SREJ] POLL Bit Set")
+ def test_respond_to_srej_p_set(self):
+ """
+ Verify the IUT responds with the correct I-frame when sent an SREJ
+ frame. Verify that the IUT processes the acknowledgment of previously
+ unacknowledged I-frames
+ """
+ self._setup_link_from_cert()
+
+ config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, max_transmit=2, tx_window_size=3)
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
+
+ for _ in range(4):
+ dut_channel.send(b'abc')
+ assertThat(cert_channel).emits(
+ L2capMatchers.IFrame(tx_seq=0, payload=b'abc'), L2capMatchers.IFrame(tx_seq=1, payload=b'abc'),
+ L2capMatchers.IFrame(tx_seq=2, payload=b'abc')).inOrder()
+
+ cert_channel.send_s_frame(req_seq=1, p=Poll.POLL, s=SupervisoryFunction.SELECT_REJECT)
+
+ assertThat(cert_channel).emits(
+ L2capMatchers.IFrame(tx_seq=1, payload=b'abc', f=Final.POLL_RESPONSE),
+ L2capMatchers.IFrame(tx_seq=3, payload=b'abc')).inOrder()
+
+ @metadata(pts_test_id="L2CAP/ERM/BV-15-C", pts_test_name="Respond to S-Frame [SREJ] POLL Bit Clear")
+ def test_respond_to_srej_p_clear(self):
+ """
+ Verify the IUT responds with the correct I-frame when sent an SREJ frame
+ """
+ self._setup_link_from_cert()
+
+ config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, max_transmit=2, tx_window_size=3)
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
+
+ for _ in range(4):
+ dut_channel.send(b'abc')
+ assertThat(cert_channel).emits(
+ L2capMatchers.IFrame(tx_seq=0, payload=b'abc'), L2capMatchers.IFrame(tx_seq=1, payload=b'abc'),
+ L2capMatchers.IFrame(tx_seq=2, payload=b'abc')).inOrder()
+
+ cert_channel.send_s_frame(req_seq=1, s=SupervisoryFunction.SELECT_REJECT)
+ assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=1, payload=b'abc', f=Final.NOT_SET))
+ cert_channel.send_s_frame(req_seq=3, s=SupervisoryFunction.RECEIVER_READY)
+ assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=3, payload=b'abc', f=Final.NOT_SET))
+
+ @metadata(pts_test_id="L2CAP/ERM/BV-16-C", pts_test_name="Send S-Frame [REJ]")
+ def test_send_s_frame_rej(self):
+ """
+ Verify the IUT can send an S-Frame [REJ] after receiving out of sequence
+ I-Frames
+ """
+ self._setup_link_from_cert()
+ tx_window_size = 4
+
+ config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=tx_window_size)
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
+
+ cert_channel.send_i_frame(tx_seq=0, req_seq=0, f=Final.NOT_SET, payload=SAMPLE_PACKET)
+ cert_channel.send_i_frame(tx_seq=2, req_seq=0, f=Final.NOT_SET, payload=SAMPLE_PACKET)
+
+ assertThat(cert_channel).emits(
+ L2capMatchers.SFrame(req_seq=1, f=Final.NOT_SET, s=SupervisoryFunction.REJECT, p=Poll.NOT_SET))
+
+ for i in range(1, tx_window_size):
+ cert_channel.send_i_frame(tx_seq=i, req_seq=0, f=Final.NOT_SET, payload=SAMPLE_PACKET)
+ assertThat(cert_channel).emits(
+ L2capMatchers.SFrame(req_seq=i + 1, f=Final.NOT_SET, s=SupervisoryFunction.RECEIVER_READY))
+
+ @metadata(pts_test_id="L2CAP/ERM/BV-18-C", pts_test_name="Receive S-Frame [RR] Final Bit = 1")
+ def test_receive_s_frame_rr_final_bit_set(self):
+ """
+ Verify the IUT will retransmit any previously sent I-frames
+ unacknowledged by receipt of an S-Frame [RR] with the Final Bit set
+ """
+ self._setup_link_from_cert()
+
+ config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, retransmission_time_out=1500)
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
+
+ dut_channel.send(b'abc')
+
+ assertThat(cert_channel).emits(L2capMatchers.SFrame(p=l2cap_packets.Poll.POLL))
+
+ cert_channel.send_s_frame(req_seq=0, f=Final.POLL_RESPONSE)
+ assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0))
+
+ @metadata(pts_test_id="L2CAP/ERM/BV-19-C", pts_test_name="Receive I-Frame Final Bit = 1")
+ def test_receive_i_frame_final_bit_set(self):
+ """
+ Verify the IUT will retransmit any previously sent I-frames
+ unacknowledged by receipt of an I-frame with the final bit set
+ """
+ self._setup_link_from_cert()
+
+ config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, retransmission_time_out=1500)
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
+
+ dut_channel.send(b'abc')
+ assertThat(cert_channel).emits(L2capMatchers.SFrame(p=Poll.POLL))
+
+ cert_channel.send_i_frame(tx_seq=0, req_seq=0, f=Final.POLL_RESPONSE, payload=SAMPLE_PACKET)
+ assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0))
+
+ @metadata(pts_test_id="L2CAP/ERM/BV-20-C", pts_test_name="Enter Remote Busy Condition")
+ def test_receive_rnr(self):
+ """
+ Verify the IUT will not retransmit any I-frames when it receives a
+ remote busy indication from the Lower Tester (S-frame [RNR])
+ """
+ self._setup_link_from_cert()
+
+ config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, retransmission_time_out=1500)
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
+
+ dut_channel.send(b'abc')
+ assertThat(cert_channel).emits(L2capMatchers.SFrame(p=l2cap_packets.Poll.POLL))
+
+ cert_channel.send_s_frame(req_seq=0, s=SupervisoryFunction.RECEIVER_NOT_READY, f=Final.POLL_RESPONSE)
+ assertThat(cert_channel).emitsNone(L2capMatchers.IFrame(tx_seq=0))
+
+ @metadata(pts_test_id="L2CAP/ERM/BV-22-C", pts_test_name="Exit Local Busy Condition")
+ def test_exit_local_busy_condition(self):
+ """
+ Verify the IUT sends an S-frame [RR] Poll = 1 when the local busy condition is cleared
+ NOTE: In GD stack, we enter local busy condition if client doesn't dequeue
+ and packets are accumulating in buffer
+ """
+ self._setup_link_from_cert()
+
+ config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=10)
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM,
+ fcs=FcsType.NO_FCS,
+ req_config_options=config,
+ rsp_config_options=config)
+
+ dut_channel.send(b'abc')
+ assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0, payload=b'abc'))
+ cert_channel.send_i_frame(tx_seq=0, req_seq=1, payload=SAMPLE_PACKET)
+
+ dut_channel.set_traffic_paused(True)
+
+ # Allow 1 additional packet in channel queue buffer
+ buffer_size = self.dut_l2cap.get_channel_queue_buffer_size() + 1
+
+ for i in range(buffer_size):
+ cert_channel.send_i_frame(tx_seq=i + 1, req_seq=1, payload=SAMPLE_PACKET)
+ assertThat(cert_channel).emits(L2capMatchers.SFrame(s=l2cap_packets.SupervisoryFunction.RECEIVER_READY))
+
+ cert_channel.send_i_frame(tx_seq=buffer_size + 1, req_seq=1, payload=SAMPLE_PACKET)
+ assertThat(cert_channel).emits(L2capMatchers.SFrame(s=l2cap_packets.SupervisoryFunction.RECEIVER_NOT_READY))
+
+ dut_channel.set_traffic_paused(False)
+ assertThat(cert_channel).emits(
+ L2capMatchers.SFrame(s=l2cap_packets.SupervisoryFunction.RECEIVER_READY, p=l2cap_packets.Poll.POLL))
+ cert_channel.send_s_frame(1, f=l2cap_packets.Final.POLL_RESPONSE)
+
+ @metadata(pts_test_id="L2CAP/ERM/BV-23-C", pts_test_name="Transmit I-Frames using SAR")
+ def test_transmit_i_frames_using_sar(self):
+ """
+ Verify the IUT can send correctly formatted sequential I-frames with
+ valid values for the enhanced control fields (SAR, F-bit, ReqSeq,
+ TxSeq) when performing SAR.
+ """
+ self._setup_link_from_cert()
+
+ config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, mps=11)
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
+
+ dut_channel.send(b'abcabcabc')
+ # First IFrame should contain SDU size after control field
+ assertThat(cert_channel).emits(
+ L2capMatchers.IFrameStart(tx_seq=0, payload=b'abc'), L2capMatchers.IFrame(tx_seq=1, payload=b'abc'),
+ L2capMatchers.IFrame(tx_seq=2, payload=b'abc')).inOrder()
+
+ cert_channel.send_s_frame(req_seq=3, s=SupervisoryFunction.RECEIVER_READY)
+
+ dut_channel.send(b'defdefdef')
+ # First IFrame should contain SDU size after control field
+ assertThat(cert_channel).emits(
+ L2capMatchers.IFrameStart(tx_seq=3, payload=b'def'), L2capMatchers.IFrame(tx_seq=4, payload=b'def'),
+ L2capMatchers.IFrame(tx_seq=5, payload=b'def')).inOrder()
+
+ @metadata(pts_test_id="L2CAP/ERM/BI-01-C", pts_test_name="S-Frame [REJ] Lost or Corrupted")
+ def test_sent_rej_lost(self):
+ """
+ Verify the IUT can handle receipt of an S-=frame [RR] Poll = 1 if the
+ S-frame [REJ] sent from the IUT is lost
+ """
+ self._setup_link_from_cert()
+ ertm_tx_window_size = 5
+
+ config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=ertm_tx_window_size)
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
+
+ cert_channel.send_i_frame(tx_seq=0, req_seq=0, payload=SAMPLE_PACKET)
+ assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=1))
+
+ cert_channel.send_i_frame(tx_seq=ertm_tx_window_size - 1, req_seq=0, payload=SAMPLE_PACKET)
+ assertThat(cert_channel).emits(L2capMatchers.SFrame(s=SupervisoryFunction.REJECT))
+
+ cert_channel.send_s_frame(req_seq=0, p=Poll.POLL)
+
+ assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=1, f=l2cap_packets.Final.POLL_RESPONSE))
+ for i in range(1, ertm_tx_window_size):
+ cert_channel.send_i_frame(tx_seq=i, req_seq=0, payload=SAMPLE_PACKET)
+ assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=i + 1))
+
+ @metadata(pts_test_id="L2CAP/ERM/BI-03-C", pts_test_name="Handle Duplicate S-Frame [SREJ]")
+ def test_handle_duplicate_srej(self):
+ """
+ Verify the IUT will only retransmit the requested I-frame once after
+ receiving a duplicate SREJ
+ """
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
+
+ dut_channel.send(b'abc')
+ dut_channel.send(b'abc')
+ assertThat(cert_channel).emits(
+ L2capMatchers.IFrame(tx_seq=0), L2capMatchers.IFrame(tx_seq=1),
+ L2capMatchers.SFrame(p=Poll.POLL)).inOrder()
+
+ cert_channel.send_s_frame(req_seq=0, s=SupervisoryFunction.SELECT_REJECT)
+ assertThat(cert_channel).emitsNone(timeout=timedelta(seconds=0.5))
+
+ cert_channel.send_s_frame(req_seq=0, s=SupervisoryFunction.SELECT_REJECT, f=Final.POLL_RESPONSE)
+ assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0))
+
+ @metadata(
+ pts_test_id="L2CAP/ERM/BI-04-C",
+ pts_test_name="Handle Receipt of S-Frame [REJ] and S-Frame "
+ "[RR, F=1] that Both Require Retransmission of the "
+ "Same I-Frames")
+ def test_handle_receipt_rej_and_rr_with_f_set(self):
+ """
+ Verify the IUT will only retransmit the requested I-frames once after
+ receiving an S-frame [REJ] followed by an S-frame [RR] with the Final
+ bit set that indicates the same I-frames should be retransmitted
+ """
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
+
+ dut_channel.send(b'abc')
+ dut_channel.send(b'abc')
+ assertThat(cert_channel).emits(
+ L2capMatchers.IFrame(tx_seq=0),
+ L2capMatchers.IFrame(tx_seq=1),
+ L2capMatchers.SFrame(p=l2cap_packets.Poll.POLL)).inOrder()
+
+ cert_channel.send_s_frame(req_seq=0, s=SupervisoryFunction.REJECT)
+ assertThat(cert_channel).emitsNone(timeout=timedelta(seconds=0.5))
+
+ # Send RR with F set
+ cert_channel.send_s_frame(req_seq=0, s=SupervisoryFunction.REJECT, f=Final.POLL_RESPONSE)
+ assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0))
+ assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=1))
+
+ @metadata(
+ pts_test_id="L2CAP/ERM/BI-05-C",
+ pts_test_name="Handle receipt of S-Frame [REJ] and I-Frame [F=1] "
+ "that Both Require Retransmission of the Same "
+ "I-Frames")
+ def test_handle_rej_and_i_frame_with_f_set(self):
+ """
+ Verify the IUT will only retransmit the requested I-frames once after
+ receiving an S-frame [REJ] followed by an I-frame with the Final bit
+ set that indicates the same I-frames should be retransmitted
+ """
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
+
+ dut_channel.send(b'abc')
+ dut_channel.send(b'abc')
+ assertThat(cert_channel).emits(
+ L2capMatchers.IFrame(tx_seq=0),
+ L2capMatchers.IFrame(tx_seq=1),
+ L2capMatchers.SFrame(p=l2cap_packets.Poll.POLL)).inOrder()
+
+ # Send SREJ with F not set
+ cert_channel.send_s_frame(req_seq=0, s=SupervisoryFunction.SELECT_REJECT)
+ assertThat(cert_channel).emitsNone(timeout=timedelta(seconds=0.5))
+
+ cert_channel.send_i_frame(tx_seq=0, req_seq=0, f=Final.POLL_RESPONSE, payload=SAMPLE_PACKET)
+
+ assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0))
+ assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=1))
+
+ @metadata(
+ pts_test_id="L2CAP/CMC/BV-01-C", pts_test_name="IUT Initiated Configuration of Enhanced "
+ "Retransmission Mode")
+ def test_initiated_configuration_request_ertm(self):
+ """
+ Verify the IUT can send a Configuration Request command containing the
+ F&EC option that specifies Enhanced Retransmission Mode
+ """
+ self._setup_link_from_cert()
+
+ self._open_unconfigured_channel_from_cert(scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM)
+
+ assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.ConfigurationRequestWithErtm())
+
+ @metadata(
+ pts_test_id="L2CAP/CMC/BV-02-C",
+ pts_test_name="Lower Tester Initiated Configuration of Enhanced "
+ "Retransmission Mode")
+ def test_respond_configuration_request_ertm(self):
+ """
+ Verify the IUT can accept a Configuration Request from the Lower Tester
+ containing an F&EC option that specifies Enhanced Retransmission Mode
+ """
+ self._setup_link_from_cert()
+
+ self._open_channel_from_dut(psm=0x33, mode=RetransmissionFlowControlMode.ERTM)
+
+ @metadata(
+ pts_test_id="L2CAP/CMC/BV-12-C",
+ pts_test_name="ERTM Not Supported by Lower Tester for Mandatory "
+ "ERTM channel")
+ def test_respond_not_support_ertm_when_using_mandatory_ertm(self):
+ """
+ The IUT is initiating connection of an L2CAP channel that mandates use
+ of ERTM. Verify the IUT will not attempt to configure the connection to
+ ERTM if the Lower Tester has not indicated support for ERTM in the
+ Information Response [Extended Features]
+ """
+ self._setup_link_from_cert()
+ self.cert_l2cap.claim_ertm_unsupported()
+ dut_channel_future = self.dut_l2cap.connect_dynamic_channel_to_cert(
+ psm=0x33, mode=RetransmissionFlowControlMode.ERTM)
+ assertThat(self.cert_l2cap.get_control_channel()).emitsNone(L2capMatchers.ConnectionRequest(0x33))
+
+ @metadata(
+ pts_test_id="L2CAP/CMC/BI-01-C",
+ pts_test_name="Failed Configuration of Enhanced Retransmission "
+ "Mode when use of the Mode is Mandatory]")
+ def test_config_respond_basic_mode_when_using_mandatory_ertm(self):
+ """
+ When creating a connection for a PSM that mandates the use of ERTM
+ verify the IUT can handle receipt (close the channel in accordance with
+ the specification) of a Configure Response indicating the peer L2CAP
+ entity doesn’t wish to use Enhanced Retransmission Mode (Configure
+ Response Result = Reject Unacceptable Parameters)
+ """
+
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_channel_from_cert(
+ mode=RetransmissionFlowControlMode.ERTM,
+ req_config_options=CertL2cap.config_option_ertm(),
+ rsp_config_options=CertL2cap.config_option_basic_explicit())
+
+ cert_channel.verify_disconnect_request()
+
+ @metadata(
+ pts_test_id="L2CAP/CMC/BI-02-C",
+ pts_test_name="Configuration Mode mismatch when use of Enhanced "
+ "Retransmission Mode is Mandatory")
+ def test_config_request_basic_mode_when_using_mandatory_ertm(self):
+ """
+ When creating a connection for a PSM that mandates the use of ERTM,
+ verify the IUT will close the channel if the Lower Tester attempts to
+ configure Basic Mode.
+ """
+ self._setup_link_from_cert()
+
+ (dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert(mode=RetransmissionFlowControlMode.ERTM)
+ cert_channel.send_configure_request(CertL2cap.config_option_basic_explicit())
+ cert_channel.verify_disconnect_request()
+
+ def test_initiate_connection_for_security(self):
+ """
+ This will test the PyL2cap API for initiating a connection for security
+ via the security api
+ """
+ self.dut.neighbor.EnablePageScan(neighbor_facade.EnableMsg(enabled=True))
+ self.cert.neighbor.EnablePageScan(neighbor_facade.EnableMsg(enabled=True))
+ self.dut_l2cap.initiate_connection_for_security()
+ self.cert_l2cap.accept_incoming_connection()
+ self.dut_l2cap.verify_security_connection()
diff --git a/gd/l2cap/classic/internal/link.cc b/gd/l2cap/classic/internal/link.cc
index 5167cc1..e6d4f0d 100644
--- a/gd/l2cap/classic/internal/link.cc
+++ b/gd/l2cap/classic/internal/link.cc
@@ -439,9 +439,14 @@
link_manager_->OnReadRemoteVersionInformation(
hci_status, GetDevice().GetAddress(), lmp_version, manufacturer_name, sub_version);
}
+void Link::OnReadRemoteSupportedFeaturesComplete(uint64_t features) {
+ LOG_INFO("page_number:%hhu features:0x%lx", static_cast<uint8_t>(0), static_cast<unsigned long>(features));
+ link_manager_->OnReadRemoteSupportedFeatures(GetDevice().GetAddress(), features);
+}
+
void Link::OnReadRemoteExtendedFeaturesComplete(uint8_t page_number, uint8_t max_page_number, uint64_t features) {
LOG_INFO(
- "page_number:%hhu max_page_number:%hhu sub_version:0x%lx",
+ "page_number:%hhu max_page_number:%hhu features:0x%lx",
page_number,
max_page_number,
static_cast<unsigned long>(features));
diff --git a/gd/l2cap/classic/internal/link.h b/gd/l2cap/classic/internal/link.h
index 6121b4f..a5b17a9 100644
--- a/gd/l2cap/classic/internal/link.h
+++ b/gd/l2cap/classic/internal/link.h
@@ -184,6 +184,7 @@
void OnDisconnection(hci::ErrorCode reason) override;
void OnReadRemoteVersionInformationComplete(
hci::ErrorCode hci_status, uint8_t lmp_version, uint16_t manufacturer_name, uint16_t sub_version);
+ void OnReadRemoteSupportedFeaturesComplete(uint64_t features);
void OnReadRemoteExtendedFeaturesComplete(uint8_t page_number, uint8_t max_page_number, uint64_t features);
struct EncryptionChangeListener {
diff --git a/gd/l2cap/classic/internal/link_manager.cc b/gd/l2cap/classic/internal/link_manager.cc
index cda9395..f8ff461 100644
--- a/gd/l2cap/classic/internal/link_manager.cc
+++ b/gd/l2cap/classic/internal/link_manager.cc
@@ -379,6 +379,13 @@
}
}
+void LinkManager::OnReadRemoteSupportedFeatures(hci::Address device, uint64_t features) {
+ if (link_property_callback_handler_ != nullptr) {
+ link_property_callback_handler_->CallOn(
+ link_property_listener_, &LinkPropertyListener::OnReadRemoteSupportedFeatures, device, features);
+ }
+}
+
void LinkManager::OnReadRemoteExtendedFeatures(
hci::Address device, uint8_t page_number, uint8_t max_page_number, uint64_t features) {
if (link_property_callback_handler_ != nullptr) {
diff --git a/gd/l2cap/classic/internal/link_manager.h b/gd/l2cap/classic/internal/link_manager.h
index 19feefc..a81b0f5 100644
--- a/gd/l2cap/classic/internal/link_manager.h
+++ b/gd/l2cap/classic/internal/link_manager.h
@@ -79,6 +79,7 @@
uint8_t lmp_version,
uint16_t manufacturer_name,
uint16_t sub_version);
+ void OnReadRemoteSupportedFeatures(hci::Address device, uint64_t features);
void OnReadRemoteExtendedFeatures(
hci::Address device, uint8_t page_number, uint8_t max_page_number, uint64_t features);
void OnRoleChange(hci::ErrorCode hci_status, hci::Address remote, hci::Role role);
diff --git a/gd/l2cap/classic/link_property_listener.h b/gd/l2cap/classic/link_property_listener.h
index afff663..2885074 100644
--- a/gd/l2cap/classic/link_property_listener.h
+++ b/gd/l2cap/classic/link_property_listener.h
@@ -53,6 +53,11 @@
uint16_t sub_version) {}
/**
+ * Invoked when received remote features and remote supported features for a given link
+ */
+ virtual void OnReadRemoteSupportedFeatures(hci::Address remote, uint64_t features) {}
+
+ /**
* Invoked when received remote features and remote extended features for a given link
*/
virtual void OnReadRemoteExtendedFeatures(
diff --git a/gd/l2cap/le/cert/dual_l2cap_test.py b/gd/l2cap/le/cert/dual_l2cap_test.py
index 00e6392..7a36b42 100644
--- a/gd/l2cap/le/cert/dual_l2cap_test.py
+++ b/gd/l2cap/le/cert/dual_l2cap_test.py
@@ -14,174 +14,18 @@
# limitations under the License.
from cert.gd_base_test import GdBaseTestClass
-from cert.truth import assertThat
-from cert.py_l2cap import PyLeL2cap, PyL2cap
-from cert.matchers import L2capMatchers
-from cert.metadata import metadata
-from facade import common_pb2 as common
-from google.protobuf import empty_pb2 as empty_proto
-from hci.facade import le_acl_manager_facade_pb2 as le_acl_manager_facade
-from hci.facade import le_advertising_manager_facade_pb2 as le_advertising_facade
-from hci.facade import le_initiator_address_facade_pb2 as le_initiator_address_facade
-import bluetooth_packets_python3 as bt_packets
-from bluetooth_packets_python3 import hci_packets, l2cap_packets
-from l2cap.classic.cert.cert_l2cap import CertL2cap
-from l2cap.le.cert.cert_le_l2cap import CertLeL2cap
-from neighbor.facade import facade_pb2 as neighbor_facade
-
-# Assemble a sample packet.
-SAMPLE_PACKET = bt_packets.RawBuilder([0x19, 0x26, 0x08, 0x17])
+from l2cap.le.cert.dual_l2cap_test_lib import DualL2capTestBase
-class DualL2capTest(GdBaseTestClass):
+class DualL2capTest(GdBaseTestClass, DualL2capTestBase):
def setup_class(self):
- super().setup_class(dut_module='L2CAP', cert_module='HCI_INTERFACES')
+ GdBaseTestClass.setup_class(self, dut_module='L2CAP', cert_module='HCI_INTERFACES')
def setup_test(self):
- super().setup_test()
-
- self.dut_address = self.dut.hci_controller.GetMacAddressSimple()
- cert_address = common.BluetoothAddress(
- address=self.cert.controller_read_only_property.ReadLocalAddress(empty_proto.Empty()).address)
-
- self.dut_l2cap = PyL2cap(self.dut, cert_address)
- self.cert_l2cap = CertL2cap(self.cert)
- self.dut_le_l2cap = PyLeL2cap(self.dut)
- self.cert_le_l2cap = CertLeL2cap(self.cert)
- self.dut_le_address = common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=bytes(b'D0:05:04:03:02:01')), type=common.RANDOM_DEVICE_ADDRESS)
- self.cert_address = common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=bytes(b'C0:11:FF:AA:33:22')), type=common.RANDOM_DEVICE_ADDRESS)
- dut_privacy_policy = le_initiator_address_facade.PrivacyPolicy(
- address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
- address_with_type=self.dut_le_address,
- rotation_irk=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
- minimum_rotation_time=0,
- maximum_rotation_time=0)
- self.dut_l2cap._device.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(dut_privacy_policy)
- privacy_policy = le_initiator_address_facade.PrivacyPolicy(
- address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
- address_with_type=self.cert_address,
- rotation_irk=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
- minimum_rotation_time=0,
- maximum_rotation_time=0)
- self.cert_le_l2cap._device.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(privacy_policy)
+ GdBaseTestClass.setup_test(self)
+ DualL2capTestBase.setup_test(self, self.dut, self.cert)
def teardown_test(self):
- self.cert_le_l2cap.close()
- self.dut_le_l2cap.close()
- self.cert_l2cap.close()
- self.dut_l2cap.close()
- super().teardown_test()
-
- def _setup_acl_link_from_cert(self):
- self.dut.neighbor.EnablePageScan(neighbor_facade.EnableMsg(enabled=True))
- self.cert_l2cap.connect_acl(self.dut_address)
-
- def _setup_le_link_from_cert(self):
- # DUT Advertises
- gap_name = hci_packets.GapData()
- gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
- gap_name.data = list(bytes(b'Im_The_DUT'))
- gap_data = le_advertising_facade.GapDataMsg(data=bytes(gap_name.Serialize()))
- config = le_advertising_facade.AdvertisingConfig(
- advertisement=[gap_data],
- interval_min=512,
- interval_max=768,
- advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
- own_address_type=common.USE_RANDOM_DEVICE_ADDRESS,
- channel_map=7,
- filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
- request = le_advertising_facade.CreateAdvertiserRequest(config=config)
- create_response = self.dut.hci_le_advertising_manager.CreateAdvertiser(request)
- self.cert_le_l2cap.connect_le_acl(self.dut_le_address)
-
- def _open_le_coc_from_dut(self, psm=0x33, our_scid=None):
- response_future = self.dut_le_l2cap.connect_coc_to_cert(self.cert_address, psm)
- cert_channel = self.cert_le_l2cap.verify_and_respond_open_channel_from_remote(psm=psm, our_scid=our_scid)
- dut_channel = response_future.get_channel()
- return (dut_channel, cert_channel)
-
- def _open_channel_from_dut(self, psm=0x33, our_scid=None):
- dut_channel_future = self.dut_l2cap.connect_dynamic_channel_to_cert(psm)
- cert_channel = self.cert_l2cap.verify_and_respond_open_channel_from_remote(psm=psm, scid=our_scid)
- dut_channel = dut_channel_future.get_channel()
-
- cert_channel.verify_configuration_request_and_respond()
- cert_channel.send_configure_request([])
- cert_channel.verify_configuration_response()
-
- return (dut_channel, cert_channel)
-
- def _open_unconfigured_channel_from_cert(self, signal_id=1, scid=0x0101, psm=0x33):
-
- dut_channel = self.dut_l2cap.register_dynamic_channel(psm)
- cert_channel = self.cert_l2cap.open_channel(signal_id, psm, scid)
-
- return (dut_channel, cert_channel)
-
- def _open_channel_from_cert(self, signal_id=1, scid=0x0101, psm=0x33):
- (dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert(signal_id, scid, psm)
- cert_channel.verify_configuration_request_and_respond()
- cert_channel.send_configure_request([])
- cert_channel.verify_configuration_response()
-
- return (dut_channel, cert_channel)
-
- def _open_le_coc_from_cert(self, signal_id=1, scid=0x0101, psm=0x35, mtu=1000, mps=100, initial_credit=6):
-
- dut_channel = self.dut_le_l2cap.register_coc(self.cert_address, psm)
- cert_channel = self.cert_le_l2cap.open_channel(signal_id, psm, scid, mtu, mps, initial_credit)
-
- return (dut_channel, cert_channel)
-
- @metadata(pts_test_id="L2CAP/LE/CID/BV-01-C", pts_test_name="Receiving DCID over BR/EDR and LE")
- def test_receiving_dcid_over_bredr_and_le(self):
- """
- Test that the L2CAP entity can receive the same DCID in L2CAP connect responses on both the
- BR/EDR and LE links.
- """
- self._setup_acl_link_from_cert()
- # TODO: We should let LE use public address, same as classic link.
- # TODO: Update AclManager::impl::create_le_connection
- self._setup_le_link_from_cert()
- (dut_channel, cert_channel) = self._open_channel_from_dut(0x33, 0x70)
- (le_dut_channel, le_cert_channel) = self._open_le_coc_from_dut(0x35, 0x70)
-
- dut_channel.send(b'abc')
- assertThat(cert_channel).emits(L2capMatchers.Data(b'abc'))
-
- le_dut_channel.send(b'hello')
- assertThat(le_cert_channel).emits(L2capMatchers.FirstLeIFrame(b'hello', sdu_size=5))
-
- le_cert_channel.send_first_le_i_frame(4, SAMPLE_PACKET)
- assertThat(le_dut_channel).emits(L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17'))
-
- cert_channel.disconnect_and_verify()
- le_cert_channel.disconnect_and_verify()
-
- @metadata(pts_test_id="L2CAP/LE/CID/BV-02-C", pts_test_name="Receiving SCID over BR/EDR and LE")
- def test_receiving_scid_over_bredr_and_le(self):
- """
- Test that the L2CAP entity can receive the same SCID in L2CAP connect requests on both the
- BR/EDR and LE links.
- """
- self._setup_acl_link_from_cert()
- # TODO: We should let LE use public address, same as classic link.
- # TODO: Update AclManager::impl::create_le_connection
- self._setup_le_link_from_cert()
- (dut_channel, cert_channel) = self._open_channel_from_cert(0x33, 0x70)
- (le_dut_channel, le_cert_channel) = self._open_le_coc_from_cert(0x35, 0x70)
-
- dut_channel.send(b'abc')
- assertThat(cert_channel).emits(L2capMatchers.Data(b'abc'))
-
- le_dut_channel.send(b'hello')
- assertThat(le_cert_channel).emits(L2capMatchers.FirstLeIFrame(b'hello', sdu_size=5))
-
- le_cert_channel.send_first_le_i_frame(4, SAMPLE_PACKET)
- assertThat(le_dut_channel).emits(L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17'))
-
- cert_channel.disconnect_and_verify()
- le_cert_channel.disconnect_and_verify()
+ DualL2capTestBase.teardown_test(self)
+ GdBaseTestClass.teardown_test(self)
diff --git a/gd/l2cap/le/cert/dual_l2cap_test_lib.py b/gd/l2cap/le/cert/dual_l2cap_test_lib.py
new file mode 100644
index 0000000..139b47a
--- /dev/null
+++ b/gd/l2cap/le/cert/dual_l2cap_test_lib.py
@@ -0,0 +1,183 @@
+#
+# Copyright 2020 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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 cert.truth import assertThat
+from cert.py_l2cap import PyLeL2cap, PyL2cap
+from cert.matchers import L2capMatchers
+from cert.metadata import metadata
+from facade import common_pb2 as common
+from google.protobuf import empty_pb2 as empty_proto
+from hci.facade import le_acl_manager_facade_pb2 as le_acl_manager_facade
+from hci.facade import le_advertising_manager_facade_pb2 as le_advertising_facade
+from hci.facade import le_initiator_address_facade_pb2 as le_initiator_address_facade
+import bluetooth_packets_python3 as bt_packets
+from bluetooth_packets_python3 import hci_packets, l2cap_packets
+from l2cap.classic.cert.cert_l2cap import CertL2cap
+from l2cap.le.cert.cert_le_l2cap import CertLeL2cap
+from neighbor.facade import facade_pb2 as neighbor_facade
+
+# Assemble a sample packet.
+SAMPLE_PACKET = bt_packets.RawBuilder([0x19, 0x26, 0x08, 0x17])
+
+
+class DualL2capTestBase():
+
+ def setup_test(self, dut, cert):
+ self.dut = dut
+ self.cert = cert
+
+ self.dut_address = self.dut.hci_controller.GetMacAddressSimple()
+ cert_address = common.BluetoothAddress(
+ address=self.cert.controller_read_only_property.ReadLocalAddress(empty_proto.Empty()).address)
+
+ self.dut_l2cap = PyL2cap(self.dut, cert_address)
+ self.cert_l2cap = CertL2cap(self.cert)
+ self.dut_le_l2cap = PyLeL2cap(self.dut)
+ self.cert_le_l2cap = CertLeL2cap(self.cert)
+ self.dut_le_address = common.BluetoothAddressWithType(
+ address=common.BluetoothAddress(address=bytes(b'D0:05:04:03:02:01')), type=common.RANDOM_DEVICE_ADDRESS)
+ self.cert_address = common.BluetoothAddressWithType(
+ address=common.BluetoothAddress(address=bytes(b'C0:11:FF:AA:33:22')), type=common.RANDOM_DEVICE_ADDRESS)
+ dut_privacy_policy = le_initiator_address_facade.PrivacyPolicy(
+ address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
+ address_with_type=self.dut_le_address,
+ rotation_irk=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
+ minimum_rotation_time=0,
+ maximum_rotation_time=0)
+ self.dut_l2cap._device.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(dut_privacy_policy)
+ privacy_policy = le_initiator_address_facade.PrivacyPolicy(
+ address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
+ address_with_type=self.cert_address,
+ rotation_irk=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
+ minimum_rotation_time=0,
+ maximum_rotation_time=0)
+ self.cert_le_l2cap._device.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(privacy_policy)
+
+ def teardown_test(self):
+ self.cert_le_l2cap.close()
+ self.dut_le_l2cap.close()
+ self.cert_l2cap.close()
+ self.dut_l2cap.close()
+
+ def _setup_acl_link_from_cert(self):
+ self.dut.neighbor.EnablePageScan(neighbor_facade.EnableMsg(enabled=True))
+ self.cert_l2cap.connect_acl(self.dut_address)
+
+ def _setup_le_link_from_cert(self):
+ # DUT Advertises
+ gap_name = hci_packets.GapData()
+ gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
+ gap_name.data = list(bytes(b'Im_The_DUT'))
+ gap_data = le_advertising_facade.GapDataMsg(data=bytes(gap_name.Serialize()))
+ config = le_advertising_facade.AdvertisingConfig(
+ advertisement=[gap_data],
+ interval_min=512,
+ interval_max=768,
+ advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
+ own_address_type=common.USE_RANDOM_DEVICE_ADDRESS,
+ channel_map=7,
+ filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
+ request = le_advertising_facade.CreateAdvertiserRequest(config=config)
+ create_response = self.dut.hci_le_advertising_manager.CreateAdvertiser(request)
+ self.cert_le_l2cap.connect_le_acl(self.dut_le_address)
+
+ def _open_le_coc_from_dut(self, psm=0x33, our_scid=None):
+ response_future = self.dut_le_l2cap.connect_coc_to_cert(self.cert_address, psm)
+ cert_channel = self.cert_le_l2cap.verify_and_respond_open_channel_from_remote(psm=psm, our_scid=our_scid)
+ dut_channel = response_future.get_channel()
+ return (dut_channel, cert_channel)
+
+ def _open_channel_from_dut(self, psm=0x33, our_scid=None):
+ dut_channel_future = self.dut_l2cap.connect_dynamic_channel_to_cert(psm)
+ cert_channel = self.cert_l2cap.verify_and_respond_open_channel_from_remote(psm=psm, scid=our_scid)
+ dut_channel = dut_channel_future.get_channel()
+
+ cert_channel.verify_configuration_request_and_respond()
+ cert_channel.send_configure_request([])
+ cert_channel.verify_configuration_response()
+
+ return (dut_channel, cert_channel)
+
+ def _open_unconfigured_channel_from_cert(self, signal_id=1, scid=0x0101, psm=0x33):
+
+ dut_channel = self.dut_l2cap.register_dynamic_channel(psm)
+ cert_channel = self.cert_l2cap.open_channel(signal_id, psm, scid)
+
+ return (dut_channel, cert_channel)
+
+ def _open_channel_from_cert(self, signal_id=1, scid=0x0101, psm=0x33):
+ (dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert(signal_id, scid, psm)
+ cert_channel.verify_configuration_request_and_respond()
+ cert_channel.send_configure_request([])
+ cert_channel.verify_configuration_response()
+
+ return (dut_channel, cert_channel)
+
+ def _open_le_coc_from_cert(self, signal_id=1, scid=0x0101, psm=0x35, mtu=1000, mps=100, initial_credit=6):
+
+ dut_channel = self.dut_le_l2cap.register_coc(self.cert_address, psm)
+ cert_channel = self.cert_le_l2cap.open_channel(signal_id, psm, scid, mtu, mps, initial_credit)
+
+ return (dut_channel, cert_channel)
+
+ @metadata(pts_test_id="L2CAP/LE/CID/BV-01-C", pts_test_name="Receiving DCID over BR/EDR and LE")
+ def test_receiving_dcid_over_bredr_and_le(self):
+ """
+ Test that the L2CAP entity can receive the same DCID in L2CAP connect responses on both the
+ BR/EDR and LE links.
+ """
+ self._setup_acl_link_from_cert()
+ # TODO: We should let LE use public address, same as classic link.
+ # TODO: Update AclManager::impl::create_le_connection
+ self._setup_le_link_from_cert()
+ (dut_channel, cert_channel) = self._open_channel_from_dut(0x33, 0x70)
+ (le_dut_channel, le_cert_channel) = self._open_le_coc_from_dut(0x35, 0x70)
+
+ dut_channel.send(b'abc')
+ assertThat(cert_channel).emits(L2capMatchers.Data(b'abc'))
+
+ le_dut_channel.send(b'hello')
+ assertThat(le_cert_channel).emits(L2capMatchers.FirstLeIFrame(b'hello', sdu_size=5))
+
+ le_cert_channel.send_first_le_i_frame(4, SAMPLE_PACKET)
+ assertThat(le_dut_channel).emits(L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17'))
+
+ cert_channel.disconnect_and_verify()
+ le_cert_channel.disconnect_and_verify()
+
+ @metadata(pts_test_id="L2CAP/LE/CID/BV-02-C", pts_test_name="Receiving SCID over BR/EDR and LE")
+ def test_receiving_scid_over_bredr_and_le(self):
+ """
+ Test that the L2CAP entity can receive the same SCID in L2CAP connect requests on both the
+ BR/EDR and LE links.
+ """
+ self._setup_acl_link_from_cert()
+ # TODO: We should let LE use public address, same as classic link.
+ # TODO: Update AclManager::impl::create_le_connection
+ self._setup_le_link_from_cert()
+ (dut_channel, cert_channel) = self._open_channel_from_cert(0x33, 0x70)
+ (le_dut_channel, le_cert_channel) = self._open_le_coc_from_cert(0x35, 0x70)
+
+ dut_channel.send(b'abc')
+ assertThat(cert_channel).emits(L2capMatchers.Data(b'abc'))
+
+ le_dut_channel.send(b'hello')
+ assertThat(le_cert_channel).emits(L2capMatchers.FirstLeIFrame(b'hello', sdu_size=5))
+
+ le_cert_channel.send_first_le_i_frame(4, SAMPLE_PACKET)
+ assertThat(le_dut_channel).emits(L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17'))
+
+ cert_channel.disconnect_and_verify()
+ le_cert_channel.disconnect_and_verify()
diff --git a/gd/l2cap/le/cert/le_l2cap_test.py b/gd/l2cap/le/cert/le_l2cap_test.py
index 80f3aed..a5c8607 100644
--- a/gd/l2cap/le/cert/le_l2cap_test.py
+++ b/gd/l2cap/le/cert/le_l2cap_test.py
@@ -14,558 +14,18 @@
# limitations under the License.
from cert.gd_base_test import GdBaseTestClass
-from cert.truth import assertThat
-from cert.py_l2cap import PyLeL2cap
-from cert.matchers import L2capMatchers
-from cert.metadata import metadata
-from facade import common_pb2 as common
-from google.protobuf import empty_pb2 as empty_proto
-from hci.facade import le_acl_manager_facade_pb2 as le_acl_manager_facade
-from hci.facade import le_advertising_manager_facade_pb2 as le_advertising_facade
-from hci.facade import le_initiator_address_facade_pb2 as le_initiator_address_facade
-import bluetooth_packets_python3 as bt_packets
-from bluetooth_packets_python3 import hci_packets, l2cap_packets
-from bluetooth_packets_python3.l2cap_packets import LeCreditBasedConnectionResponseResult
-from l2cap.le.cert.cert_le_l2cap import CertLeL2cap
-from l2cap.le.facade_pb2 import SecurityLevel
-
-# Assemble a sample packet.
-SAMPLE_PACKET = bt_packets.RawBuilder([0x19, 0x26, 0x08, 0x17])
+from l2cap.le.cert.le_l2cap_test_lib import LeL2capTestBase
-class LeL2capTest(GdBaseTestClass):
+class LeL2capTest(GdBaseTestClass, LeL2capTestBase):
def setup_class(self):
- super().setup_class(dut_module='L2CAP', cert_module='HCI_INTERFACES')
+ GdBaseTestClass.setup_class(self, dut_module='L2CAP', cert_module='HCI_INTERFACES')
def setup_test(self):
- super().setup_test()
-
- self.dut_l2cap = PyLeL2cap(self.dut)
- self.cert_l2cap = CertLeL2cap(self.cert)
- self.dut_address = common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=bytes(b'D0:05:04:03:02:01')), type=common.RANDOM_DEVICE_ADDRESS)
- self.cert_address = common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=bytes(b'C0:11:FF:AA:33:22')), type=common.RANDOM_DEVICE_ADDRESS)
- dut_privacy_policy = le_initiator_address_facade.PrivacyPolicy(
- address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
- address_with_type=self.dut_address,
- rotation_irk=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
- minimum_rotation_time=0,
- maximum_rotation_time=0)
- self.dut_l2cap._device.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(dut_privacy_policy)
- privacy_policy = le_initiator_address_facade.PrivacyPolicy(
- address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
- address_with_type=self.cert_address,
- rotation_irk=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
- minimum_rotation_time=0,
- maximum_rotation_time=0)
- self.cert_l2cap._device.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(privacy_policy)
+ GdBaseTestClass.setup_test(self)
+ LeL2capTestBase.setup_test(self, self.dut, self.cert)
def teardown_test(self):
- self.cert_l2cap.close()
- self.dut_l2cap.close()
- super().teardown_test()
-
- def _setup_link_from_cert(self):
- # DUT Advertises
- gap_name = hci_packets.GapData()
- gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
- gap_name.data = list(bytes(b'Im_The_DUT'))
- gap_data = le_advertising_facade.GapDataMsg(data=bytes(gap_name.Serialize()))
- config = le_advertising_facade.AdvertisingConfig(
- advertisement=[gap_data],
- interval_min=512,
- interval_max=768,
- advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
- own_address_type=common.USE_RANDOM_DEVICE_ADDRESS,
- channel_map=7,
- filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
- request = le_advertising_facade.CreateAdvertiserRequest(config=config)
- create_response = self.dut.hci_le_advertising_manager.CreateAdvertiser(request)
- self.cert_l2cap.connect_le_acl(self.dut_address)
-
- def _set_link_from_dut_and_open_channel(self,
- signal_id=1,
- scid=0x0101,
- psm=0x33,
- mtu=1000,
- mps=100,
- initial_credit=6):
- # Cert Advertises
- gap_name = hci_packets.GapData()
- gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
- gap_name.data = list(bytes(b'Im_The_DUT'))
- gap_data = le_advertising_facade.GapDataMsg(data=bytes(gap_name.Serialize()))
- config = le_advertising_facade.AdvertisingConfig(
- advertisement=[gap_data],
- interval_min=512,
- interval_max=768,
- advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
- own_address_type=common.USE_RANDOM_DEVICE_ADDRESS,
- channel_map=7,
- filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
- request = le_advertising_facade.CreateAdvertiserRequest(config=config)
- create_response = self.cert.hci_le_advertising_manager.CreateAdvertiser(request)
- response_future = self.dut_l2cap.connect_coc_to_cert(self.cert_address, psm)
- self.cert_l2cap.wait_for_connection()
- # TODO: Currently we can only connect by using Dynamic channel API. Use fixed channel instead.
- cert_channel = self.cert_l2cap.verify_and_respond_open_channel_from_remote(psm)
- dut_channel = response_future.get_channel()
- return (dut_channel, cert_channel)
-
- def _open_channel_from_cert(self, signal_id=1, scid=0x0101, psm=0x33, mtu=1000, mps=100, initial_credit=6):
-
- dut_channel = self.dut_l2cap.register_coc(self.cert_address, psm)
- cert_channel = self.cert_l2cap.open_channel(signal_id, psm, scid, mtu, mps, initial_credit)
-
- return (dut_channel, cert_channel)
-
- def _open_channel_from_dut(self, psm=0x33):
- response_future = self.dut_l2cap.connect_coc_to_cert(self.cert_address, psm)
- cert_channel = self.cert_l2cap.verify_and_respond_open_channel_from_remote(psm)
- dut_channel = response_future.get_channel()
- return (dut_channel, cert_channel)
-
- def _open_fixed_channel(self, cid=4):
- dut_channel = self.dut_l2cap.get_fixed_channel(cid)
- cert_channel = self.cert_l2cap.open_fixed_channel(cid)
- return (dut_channel, cert_channel)
-
- def test_fixed_channel_send(self):
- self.dut_l2cap.enable_fixed_channel(4)
- self._setup_link_from_cert()
- (dut_channel, cert_channel) = self._open_fixed_channel(4)
- dut_channel.send(b'hello' * 40)
- assertThat(cert_channel).emits(L2capMatchers.Data(b'hello' * 40))
-
- def test_fixed_channel_receive(self):
- self.dut_l2cap.enable_fixed_channel(4)
- self._setup_link_from_cert()
- (dut_channel, cert_channel) = self._open_fixed_channel(4)
- cert_channel.send(SAMPLE_PACKET)
- assertThat(dut_channel).emits(L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17'))
-
- def test_connect_from_dut_and_open_dynamic_channel(self):
- """
- Internal test for GD stack only
- """
- self._set_link_from_dut_and_open_channel()
-
- @metadata(pts_test_id="L2CAP/LE/CPU/BV-01-C", pts_test_name="Send Connection Parameter Update Request")
- def test_send_connection_parameter_update_request(self):
- """
- Verify that the IUT is able to send the connection parameter update Request to Lower Tester when acting as a peripheral device.
- NOTE: This is an optional feature. Also if both LL central and peripheral supports 4.1+ connection parameter update, this should happen in LL only, not L2CAP
- NOTE: Currently we need to establish at least one dynamic channel to allow update.
- """
- self._setup_link_from_cert()
- self._open_channel_from_dut()
- self.dut_l2cap.update_connection_parameter()
- assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.LeConnectionParameterUpdateRequest())
-
- @metadata(pts_test_id="L2CAP/LE/CPU/BV-02-C", pts_test_name="Accept Connection Parameter Update Request")
- def test_accept_connection_parameter_update_request(self):
- """
- Verify that the IUT is able to receive and handle a request for connection parameter update when acting as a central device.
- NOTE: Currently we need to establish at least one dynamic channel to allow update.
- """
- self._set_link_from_dut_and_open_channel()
- self.cert_l2cap.get_control_channel().send(
- l2cap_packets.ConnectionParameterUpdateRequestBuilder(2, 0x10, 0x10, 0x0a, 0x64))
- assertThat(self.cert_l2cap.get_control_channel()).emits(
- L2capMatchers.LeConnectionParameterUpdateResponse(
- l2cap_packets.ConnectionParameterUpdateResponseResult.ACCEPTED))
-
- @metadata(pts_test_id="L2CAP/LE/CPU/BI-01-C", pts_test_name="Reject Connection Parameter Update Parameters")
- def test_reject_connection_parameter_update_parameters(self):
- """
- Verify that the IUT is able to reject a request for connection parameter update with illegal parameters.
- NOTE: Currently we need to establish at least one dynamic channel to allow update.
- """
- self._set_link_from_dut_and_open_channel()
- self.cert_l2cap.get_control_channel().send(
- l2cap_packets.ConnectionParameterUpdateRequestBuilder(2, 0x10, 0x10, 512, 0x64))
- assertThat(self.cert_l2cap.get_control_channel()).emits(
- L2capMatchers.LeConnectionParameterUpdateResponse(
- l2cap_packets.ConnectionParameterUpdateResponseResult.REJECTED))
-
- @metadata(pts_test_id="L2CAP/LE/CPU/BI-02-C", pts_test_name="Reject Connection Parameter Update Request")
- def test_reject_connection_parameter_update_request(self):
- """
- Verify that the IUT is able to reject a request for connection parameter update in peripheral mode.
- """
- self._setup_link_from_cert()
- self.cert_l2cap.get_control_channel().send(
- l2cap_packets.ConnectionParameterUpdateRequestBuilder(2, 0x10, 0x10, 0x0a, 0x64))
- assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.LeCommandReject())
-
- @metadata(pts_test_id="L2CAP/COS/CFC/BV-01-C", pts_test_name="Segmentation")
- def test_segmentation(self):
- """
- Verify that the IUT can send data segments which are larger than the LE frame size.
- """
- self._setup_link_from_cert()
- (dut_channel, cert_channel) = self._open_channel_from_cert(mtu=1000, mps=102)
- dut_channel.send(b'hello' * 20 + b'world')
- # The first LeInformation packet contains 2 bytes of SDU size.
- # The packet is divided into first 100 bytes from 'hellohello....'
- # and remaining 5 bytes 'world'
- assertThat(cert_channel).emits(
- L2capMatchers.FirstLeIFrame(b'hello' * 20, sdu_size=105), L2capMatchers.Data(b'world')).inOrder()
-
- @metadata(pts_test_id="L2CAP/COS/CFC/BV-02-C", pts_test_name="No Segmentation")
- def test_no_segmentation(self):
- """
- Verify that the IUT can send data segments which do not require segmentation.
- """
- self._setup_link_from_cert()
- (dut_channel, cert_channel) = self._open_channel_from_cert(mtu=1000, mps=202)
- dut_channel.send(b'hello' * 40)
- assertThat(cert_channel).emits(L2capMatchers.FirstLeIFrame(b'hello' * 40, sdu_size=200))
-
- def test_no_segmentation_dut_is_central(self):
- """
- L2CAP/COS/CFC/BV-02-C
- """
- (dut_channel, cert_channel) = self._set_link_from_dut_and_open_channel()
- dut_channel.send(b'hello' * 40)
- assertThat(cert_channel).emits(L2capMatchers.FirstLeIFrame(b'hello' * 40, sdu_size=200))
-
- @metadata(pts_test_id="L2CAP/COS/CFC/BV-03-C", pts_test_name="Reassembling")
- def test_reassembling(self):
- """
- Verify that the IUT can correctly reassemble data received from the Lower Tester which is greater than the IUT LE-frame size.
- """
- self._setup_link_from_cert()
- (dut_channel, cert_channel) = self._open_channel_from_cert()
- sdu_size_for_two_sample_packet = 8
- cert_channel.send_first_le_i_frame(sdu_size_for_two_sample_packet, SAMPLE_PACKET)
- cert_channel.send(SAMPLE_PACKET)
- assertThat(dut_channel).emits(L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17' * 2))
-
- @metadata(pts_test_id="L2CAP/COS/CFC/BV-04-C", pts_test_name="Data Receiving")
- def test_data_receiving(self):
- """
- Verify that the IUT can receive unsegmented data correctly.
- """
- self._setup_link_from_cert()
- (dut_channel, cert_channel) = self._open_channel_from_cert()
- cert_channel.send_first_le_i_frame(4, SAMPLE_PACKET)
- assertThat(dut_channel).emits(L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17'))
-
- def test_data_receiving_dut_is_central(self):
- """
- L2CAP/COS/CFC/BV-04-C
- """
- (dut_channel, cert_channel) = self._set_link_from_dut_and_open_channel()
- cert_channel.send_first_le_i_frame(4, SAMPLE_PACKET)
- assertThat(dut_channel).emits(L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17'))
-
- @metadata(pts_test_id="L2CAP/COS/CFC/BV-05-C", pts_test_name="Multiple Channels with Interleaved Data Streams")
- def test_multiple_channels_with_interleaved_data_streams(self):
- """
- Verify that an IUT can create multiple channels and receives data streams on the channels when the streams are interleaved.
- """
- self._setup_link_from_cert()
- (dut_channel_x, cert_channel_x) = self._open_channel_from_cert(signal_id=1, scid=0x0103, psm=0x33)
- (dut_channel_y, cert_channel_y) = self._open_channel_from_cert(signal_id=2, scid=0x0105, psm=0x35)
- (dut_channel_z, cert_channel_z) = self._open_channel_from_cert(signal_id=3, scid=0x0107, psm=0x37)
- cert_channel_y.send_first_le_i_frame(4, SAMPLE_PACKET)
- cert_channel_z.send_first_le_i_frame(4, SAMPLE_PACKET)
- cert_channel_y.send_first_le_i_frame(4, SAMPLE_PACKET)
- cert_channel_z.send_first_le_i_frame(4, SAMPLE_PACKET)
- cert_channel_y.send_first_le_i_frame(4, SAMPLE_PACKET)
- # TODO: We should assert two events in order, but it got stuck
- assertThat(dut_channel_y).emits(L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17'), at_least_times=3)
- assertThat(dut_channel_z).emits(
- L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17'),
- L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17')).inOrder()
- cert_channel_z.send_first_le_i_frame(4, SAMPLE_PACKET)
- assertThat(dut_channel_z).emits(L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17'))
-
- @metadata(pts_test_id="L2CAP/LE/REJ/BI-01-C", pts_test_name="Reject Unknown Command in LE Signaling Channel")
- def test_reject_unknown_command_in_le_sigling_channel(self):
- """
- Verify that the IUT is able to reject unknown command.
- """
- self._setup_link_from_cert()
- self.cert_l2cap.get_control_channel().send(
- l2cap_packets.InformationRequestBuilder(
- 2, l2cap_packets.InformationRequestInfoType.EXTENDED_FEATURES_SUPPORTED))
- assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.LeCommandReject())
-
- @metadata(pts_test_id="L2CAP/LE/REJ/BI-02-C", pts_test_name="Command Reject – Reserved PDU Codes")
- def test_command_reject_reserved_pdu_codes(self):
- """
- Verify that an IUT receiving a PDU with a reserved command code sends a command reject.
- """
- self._setup_link_from_cert()
- self.cert_l2cap.get_control_channel().send(l2cap_packets.MoveChannelRequestBuilder(2, 0, 0))
- assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.LeCommandReject())
-
- @metadata(pts_test_id="L2CAP/LE/CFC/BV-01-C", pts_test_name="LE Credit Based Connection Request - Legacy Peer")
- def test_le_credit_based_connection_request_legacy_peer(self):
- """
- Verify that an IUT sending an LE Credit Based Connection Request to a legacy peer and receiving a Command Reject does not establish the channel.
- """
- self._setup_link_from_cert()
- response_future = self.dut_l2cap.connect_coc_to_cert(self.cert_address, psm=0x33)
- self.cert_l2cap.verify_and_reject_open_channel_from_remote(psm=0x33)
- assertThat(response_future.get_status()).isNotEqualTo(LeCreditBasedConnectionResponseResult.SUCCESS)
-
- @metadata(
- pts_test_id="L2CAP/LE/CFC/BV-02-C", pts_test_name="LE Credit Based Connection Request on Supported LE_PSM")
- def test_le_credit_based_connection_request_on_supported_le_psm(self):
- """
- Verify that an IUT sending an LE Credit Based Connection Request to a peer will establish the channel upon receiving the LE Credit Based Connection Response.
- """
- self._setup_link_from_cert()
- (dut_channel, cert_channel) = self._open_channel_from_dut()
- cert_channel.send_first_le_i_frame(4, SAMPLE_PACKET)
- assertThat(dut_channel).emits(L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17'))
-
- @metadata(
- pts_test_id="L2CAP/LE/CFC/BV-03-C", pts_test_name="LE Credit Based Connection Response on Supported LE_PSM")
- def test_credit_based_connection_response_on_supported_le_psm(self):
- """
- Verify that an IUT receiving a valid LE Credit Based Connection Request from a peer will send an LE Credit Based Connection Response and establish the channel.
- """
- self._setup_link_from_cert()
- (dut_channel, cert_channel) = self._open_channel_from_cert()
- dut_channel.send(b'hello')
- assertThat(cert_channel).emits(L2capMatchers.FirstLeIFrame(b'hello', sdu_size=5))
-
- @metadata(
- pts_test_id="L2CAP/LE/CFC/BV-04-C", pts_test_name="LE Credit Based Connection Request on an Unsupported LE_PSM")
- def test_credit_based_connection_request_on_an_unsupported_le_psm(self):
- """
- Verify that an IUT sending an LE Credit Based Connection Request on an unsupported LE_PSM will not establish a channel upon receiving an LE Credit Based Connection Response refusing the connection.
- """
- self._setup_link_from_cert()
- response_future = self.dut_l2cap.connect_coc_to_cert(self.cert_address, psm=0x33)
- self.cert_l2cap.verify_and_respond_open_channel_from_remote(
- psm=0x33, result=LeCreditBasedConnectionResponseResult.LE_PSM_NOT_SUPPORTED)
- assertThat(response_future.get_status()).isEqualTo(LeCreditBasedConnectionResponseResult.LE_PSM_NOT_SUPPORTED)
-
- @metadata(
- pts_test_id="L2CAP/LE/CFC/BV-05-C", pts_test_name="LE Credit Based Connection Request - unsupported LE_PSM")
- def test_credit_based_connection_request_unsupported_le_psm(self):
- """
- Verify that an IUT receiving an LE Credit Based Connection Request on an unsupported LE_PSM will respond with an LE Credit Based Connection Response refusing the connection.
- """
- self._setup_link_from_cert()
- self.cert_l2cap.get_control_channel().send(
- l2cap_packets.LeCreditBasedConnectionRequestBuilder(1, 0x34, 0x0101, 2000, 1000, 1000))
- assertThat(self.cert_l2cap.get_control_channel()).emits(
- L2capMatchers.CreditBasedConnectionResponse(
- result=LeCreditBasedConnectionResponseResult.LE_PSM_NOT_SUPPORTED))
-
- @metadata(pts_test_id="L2CAP/LE/CFC/BV-06-C", pts_test_name="Credit Exchange – Receiving Incremental Credits")
- def test_credit_exchange_receiving_incremental_credits(self):
- """
- Verify the IUT handles flow control correctly, by handling the LE Flow Control Credit sent by the peer.
- """
- self._setup_link_from_cert()
- (dut_channel, cert_channel) = self._open_channel_from_cert(initial_credit=0)
- for _ in range(4):
- dut_channel.send(b'hello')
- cert_channel.send_credits(1)
- assertThat(cert_channel).emits(L2capMatchers.FirstLeIFrame(b'hello', sdu_size=5))
- cert_channel.send_credits(1)
- assertThat(cert_channel).emits(L2capMatchers.FirstLeIFrame(b'hello', sdu_size=5))
- cert_channel.send_credits(2)
- assertThat(cert_channel).emits(
- L2capMatchers.FirstLeIFrame(b'hello', sdu_size=5), L2capMatchers.FirstLeIFrame(b'hello', sdu_size=5))
-
- @metadata(pts_test_id="L2CAP/LE/CFC/BV-07-C", pts_test_name="Credit Exchange – Sending Credits")
- def test_credit_exchange_sending_credits(self):
- """
- Verify that the IUT sends LE Flow Control Credit to the peer.
- """
- self._setup_link_from_cert()
- (dut_channel, cert_channel) = self._open_channel_from_cert()
- credits = cert_channel.credits_left()
- # Note: DUT only needs to send credit when ALL credits are consumed.
- # Here we enforce that DUT sends credit after receiving 3 packets, to
- # test without sending too many packets (may take too long).
- # This behavior is not expected for all Bluetooth stacks.
- for _ in range(min(credits + 1, 3)):
- cert_channel.send_first_le_i_frame(4, SAMPLE_PACKET)
- self.cert_l2cap.verify_le_flow_control_credit(cert_channel)
-
- @metadata(pts_test_id="L2CAP/LE/CFC/BV-08-C", pts_test_name="Disconnection Request")
- def test_disconnection_request(self):
- """
- Verify that the IUT can disconnect the channel.
- """
- self._setup_link_from_cert()
- (dut_channel, cert_channel) = self._open_channel_from_cert()
- dut_channel.close_channel()
- cert_channel.verify_disconnect_request()
-
- @metadata(pts_test_id="L2CAP/LE/CFC/BV-09-C", pts_test_name="Disconnection Response")
- def test_disconnection_response(self):
- """
- Verify that the IUT responds correctly to reception of a Disconnection Request.
- """
- self._setup_link_from_cert()
- (dut_channel, cert_channel) = self._open_channel_from_cert()
- cert_channel.disconnect_and_verify()
-
- @metadata(pts_test_id="L2CAP/LE/CFC/BV-10-C", pts_test_name="Security - Insufficient Authentication – Initiator")
- def test_security_insufficient_authentication_initiator(self):
- """
- Verify that the IUT does not establish the channel upon receipt of an LE Credit Based Connection Response indicating the connection was refused with Result “0x0005 – Connection Refused – Insufficient Authentication".
- """
- self._setup_link_from_cert()
- response_future = self.dut_l2cap.connect_coc_to_cert(self.cert_address, psm=0x33)
- self.cert_l2cap.verify_and_respond_open_channel_from_remote(
- psm=0x33, result=LeCreditBasedConnectionResponseResult.INSUFFICIENT_AUTHENTICATION)
- assertThat(response_future.get_status()).isEqualTo(
- LeCreditBasedConnectionResponseResult.INSUFFICIENT_AUTHENTICATION)
-
- @metadata(pts_test_id="L2CAP/LE/CFC/BV-11-C", pts_test_name="Security - Insufficient Authentication – Responder")
- def test_security_insufficient_authentication_responder(self):
- """
- Verify that an IUT refuses to create a connection upon reception of an LE Credit Based Connection
-Request which fails to satisfy authentication requirements.
- """
- self._setup_link_from_cert()
- psm = 0x33
- self.dut_l2cap.register_coc(self.cert_address, psm, SecurityLevel.AUTHENTICATED_PAIRING_WITH_ENCRYPTION)
- self.cert_l2cap.open_channel_with_expected_result(
- psm, LeCreditBasedConnectionResponseResult.INSUFFICIENT_AUTHENTICATION)
-
- @metadata(pts_test_id="L2CAP/LE/CFC/BV-12-C", pts_test_name="Security - Insufficient Authorization – Initiator")
- def test_security_insufficient_authorization_initiator(self):
- """
- Verify that the IUT does not establish the channel upon receipt of an LE Credit Based Connection Response indicating the connection was refused with Result “0x0006 – Connection Refused – Insufficient Authorization”.
- """
- self._setup_link_from_cert()
- response_future = self.dut_l2cap.connect_coc_to_cert(self.cert_address, psm=0x33)
- self.cert_l2cap.verify_and_respond_open_channel_from_remote(
- psm=0x33, result=LeCreditBasedConnectionResponseResult.INSUFFICIENT_AUTHORIZATION)
- assertThat(response_future.get_status()).isEqualTo(
- LeCreditBasedConnectionResponseResult.INSUFFICIENT_AUTHORIZATION)
-
- @metadata(pts_test_id="L2CAP/LE/CFC/BV-13-C", pts_test_name="Security - Insufficient Authorization – Responder")
- def test_security_insufficient_authorization_responder(self):
- """
- Verify that an IUT refuses to create a connection upon reception of an LE Credit Based Connection
- Request which fails to satisfy authentication requirements.
- """
- self._setup_link_from_cert()
- psm = 0x33
- self.dut_l2cap.register_coc(self.cert_address, psm, SecurityLevel.AUTHORIZATION)
- self.cert_l2cap.open_channel_with_expected_result(
- psm, LeCreditBasedConnectionResponseResult.INSUFFICIENT_AUTHORIZATION)
-
- @metadata(pts_test_id="L2CAP/LE/CFC/BV-14-C", pts_test_name="Security - Insufficient Key Size – Initiator")
- def test_security_insufficient_key_size_initiator(self):
- """
- Verify that the IUT does not establish the channel upon receipt of an
- LE Credit Based Connection Response indicating the connection was
- refused with Result "0x0007 – Connection Refused – Insufficient
- Encryption Key Size".
- """
- self._setup_link_from_cert()
- response_future = self.dut_l2cap.connect_coc_to_cert(self.cert_address, psm=0x33)
- self.cert_l2cap.verify_and_respond_open_channel_from_remote(
- psm=0x33, result=LeCreditBasedConnectionResponseResult.INSUFFICIENT_ENCRYPTION_KEY_SIZE)
- assertThat(response_future.get_status()).isEqualTo(
- LeCreditBasedConnectionResponseResult.INSUFFICIENT_ENCRYPTION_KEY_SIZE)
-
- @metadata(
- pts_test_id="L2CAP/LE/CFC/BV-15-C", pts_test_name="Security - Insufficient Encryption Key Size – Responder")
- def test_security_insufficient_encryption_key_size_responder(self):
- """
- Verify that an IUT refuses to create a connection upon receipt of an LE Credit Based Connection
- Request which fails to satisfy Encryption Key Size requirements.
- """
- self._setup_link_from_cert()
- psm = 0x33
- self.dut_l2cap.register_coc(self.cert_address, psm, SecurityLevel.AUTHENTICATED_PAIRING_WITH_128_BIT_KEY)
- self.cert_l2cap.open_channel_with_expected_result(
- psm, LeCreditBasedConnectionResponseResult.INSUFFICIENT_ENCRYPTION_KEY_SIZE)
-
- @metadata(
- pts_test_id="L2CAP/LE/CFC/BV-16-C",
- pts_test_name="LE Credit Based Connection Request - refuse due to insufficient resources - Initiator")
- def test_le_connection_request_insufficient_resources_initiator(self):
- """
- Verify that an IUT sending an LE Credit Based Connection Request does
- not establish the channel upon receiving an LE Credit Based Connection
- Response refusing the connection with result "0x0004 – Connection
- refused – no resources available".
- """
- self._setup_link_from_cert()
- response_future = self.dut_l2cap.connect_coc_to_cert(self.cert_address, psm=0x33)
- self.cert_l2cap.verify_and_respond_open_channel_from_remote(
- psm=0x33, result=LeCreditBasedConnectionResponseResult.NO_RESOURCES_AVAILABLE)
- assertThat(response_future.get_status()).isEqualTo(LeCreditBasedConnectionResponseResult.NO_RESOURCES_AVAILABLE)
-
- @metadata(
- pts_test_id="L2CAP/LE/CFC/BV-18-C",
- pts_test_name="LE Credit Based Connection Request - refused due to Invalid Source CID - Initiator")
- def test_request_refused_due_to_invalid_source_cid_initiator(self):
- """
- Verify that an IUT sending an LE Credit Based Connection Request does not establish the channel upon receiving an LE Credit Based Connection Response refusing the connection with result "0x0009 – Connection refused – Invalid Source CID".
- """
- self._setup_link_from_cert()
- response_future = self.dut_l2cap.connect_coc_to_cert(self.cert_address, psm=0x33)
- self.cert_l2cap.verify_and_respond_open_channel_from_remote(
- psm=0x33, result=LeCreditBasedConnectionResponseResult.INVALID_SOURCE_CID)
- assertThat(response_future.get_status()).isEqualTo(LeCreditBasedConnectionResponseResult.INVALID_SOURCE_CID)
-
- @metadata(
- pts_test_id="L2CAP/LE/CFC/BV-19-C",
- pts_test_name="LE Credit Based Connection Request - refused due to source CID already allocated - Initiator")
- def test_request_refused_due_to_source_cid_already_allocated_initiator(self):
- """
- Verify that an IUT sending an LE Credit Based Connection Request does not establish the channel upon receiving an LE Credit Based Connection Response refusing the connection with result "0x000A – Connection refused – Source CID already allocated".
- """
- self._setup_link_from_cert()
- response_future = self.dut_l2cap.connect_coc_to_cert(self.cert_address, psm=0x33)
- self.cert_l2cap.verify_and_respond_open_channel_from_remote(
- psm=0x33, result=LeCreditBasedConnectionResponseResult.SOURCE_CID_ALREADY_ALLOCATED)
- assertThat(response_future.get_status()).isEqualTo(
- LeCreditBasedConnectionResponseResult.SOURCE_CID_ALREADY_ALLOCATED)
-
- @metadata(
- pts_test_id="L2CAP/LE/CFC/BV-20-C",
- pts_test_name="LE Credit Based Connection Response - refused due to Source CID already allocated - Responder")
- def test_request_refused_due_to_source_cid_already_allocated_responder(self):
- """
- Verify that an IUT receiving an LE Credit Based Connection Request for a second channel will refuse the connection with result "0x000A - Connection refused – Source CID already allocated" if it receives a Source CID which is already in use.
- """
- self._setup_link_from_cert()
- (dut_channel, cert_channel) = self._open_channel_from_cert(psm=0x33, scid=0x0101)
- self.dut_l2cap.register_coc(self.cert_address, psm=0x35)
- self.cert_l2cap.get_control_channel().send(
- l2cap_packets.LeCreditBasedConnectionRequestBuilder(2, 0x35, 0x0101, 1000, 1000, 1000))
- assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.CreditBasedConnectionResponseUsedCid())
-
- @metadata(
- pts_test_id="L2CAP/LE/CFC/BV-21-C",
- pts_test_name="LE Credit Based Connection Request - refused due to Unacceptable Parameters - Initiator")
- def test_request_refused_due_to_unacceptable_parameters_initiator(self):
- """
- Verify that an IUT sending an LE Credit Based Connection Request does not establish the channel upon receiving an LE Credit Based Connection Response refusing the connection with result "0x000B – Connection refused – Unacceptable Parameters".
- """
- self._setup_link_from_cert()
- response_future = self.dut_l2cap.connect_coc_to_cert(self.cert_address, psm=0x33)
- self.cert_l2cap.verify_and_respond_open_channel_from_remote(
- psm=0x33, result=LeCreditBasedConnectionResponseResult.UNACCEPTABLE_PARAMETERS)
- assertThat(response_future.get_status()).isEqualTo(
- LeCreditBasedConnectionResponseResult.UNACCEPTABLE_PARAMETERS)
-
- @metadata(pts_test_id="L2CAP/LE/CFC/BI-01-C", pts_test_name="Credit Exchange – Exceed Initial Credits")
- def test_credit_exchange_exceed_initial_credits(self):
- """
- Verify that the IUT disconnects the LE Data Channel when the credit count exceeds 65535.
- """
- self._setup_link_from_cert()
- (dut_channel, cert_channel) = self._open_channel_from_cert()
- cert_channel.send_credits(65535)
- cert_channel.verify_disconnect_request()
+ LeL2capTestBase.teardown_test(self)
+ GdBaseTestClass.teardown_test(self)
diff --git a/gd/l2cap/le/cert/le_l2cap_test_lib.py b/gd/l2cap/le/cert/le_l2cap_test_lib.py
new file mode 100644
index 0000000..8d34e16
--- /dev/null
+++ b/gd/l2cap/le/cert/le_l2cap_test_lib.py
@@ -0,0 +1,570 @@
+#
+# Copyright 2020 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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 cert.truth import assertThat
+from cert.py_l2cap import PyLeL2cap
+from cert.matchers import L2capMatchers
+from cert.metadata import metadata
+from facade import common_pb2 as common
+from google.protobuf import empty_pb2 as empty_proto
+from hci.facade import le_acl_manager_facade_pb2 as le_acl_manager_facade
+from hci.facade import le_advertising_manager_facade_pb2 as le_advertising_facade
+from hci.facade import le_initiator_address_facade_pb2 as le_initiator_address_facade
+import bluetooth_packets_python3 as bt_packets
+from bluetooth_packets_python3 import hci_packets, l2cap_packets
+from bluetooth_packets_python3.l2cap_packets import LeCreditBasedConnectionResponseResult
+from l2cap.le.cert.cert_le_l2cap import CertLeL2cap
+from l2cap.le.facade_pb2 import SecurityLevel
+
+# Assemble a sample packet.
+SAMPLE_PACKET = bt_packets.RawBuilder([0x19, 0x26, 0x08, 0x17])
+
+
+class LeL2capTestBase():
+
+ def setup_class(self):
+ GdBaseTestClass.setup_class(self, dut_module='L2CAP', cert_module='HCI_INTERFACES')
+
+ def setup_test(self, dut, cert):
+ self.dut = dut
+ self.cert = cert
+
+ self.dut_l2cap = PyLeL2cap(self.dut)
+ self.cert_l2cap = CertLeL2cap(self.cert)
+ self.dut_address = common.BluetoothAddressWithType(
+ address=common.BluetoothAddress(address=bytes(b'D0:05:04:03:02:01')), type=common.RANDOM_DEVICE_ADDRESS)
+ self.cert_address = common.BluetoothAddressWithType(
+ address=common.BluetoothAddress(address=bytes(b'C0:11:FF:AA:33:22')), type=common.RANDOM_DEVICE_ADDRESS)
+ dut_privacy_policy = le_initiator_address_facade.PrivacyPolicy(
+ address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
+ address_with_type=self.dut_address,
+ rotation_irk=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
+ minimum_rotation_time=0,
+ maximum_rotation_time=0)
+ self.dut_l2cap._device.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(dut_privacy_policy)
+ privacy_policy = le_initiator_address_facade.PrivacyPolicy(
+ address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
+ address_with_type=self.cert_address,
+ rotation_irk=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
+ minimum_rotation_time=0,
+ maximum_rotation_time=0)
+ self.cert_l2cap._device.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(privacy_policy)
+
+ def teardown_test(self):
+ self.cert_l2cap.close()
+ self.dut_l2cap.close()
+
+ def _setup_link_from_cert(self):
+ # DUT Advertises
+ gap_name = hci_packets.GapData()
+ gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
+ gap_name.data = list(bytes(b'Im_The_DUT'))
+ gap_data = le_advertising_facade.GapDataMsg(data=bytes(gap_name.Serialize()))
+ config = le_advertising_facade.AdvertisingConfig(
+ advertisement=[gap_data],
+ interval_min=512,
+ interval_max=768,
+ advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
+ own_address_type=common.USE_RANDOM_DEVICE_ADDRESS,
+ channel_map=7,
+ filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
+ request = le_advertising_facade.CreateAdvertiserRequest(config=config)
+ create_response = self.dut.hci_le_advertising_manager.CreateAdvertiser(request)
+ self.cert_l2cap.connect_le_acl(self.dut_address)
+
+ def _set_link_from_dut_and_open_channel(self,
+ signal_id=1,
+ scid=0x0101,
+ psm=0x33,
+ mtu=1000,
+ mps=100,
+ initial_credit=6):
+ # Cert Advertises
+ gap_name = hci_packets.GapData()
+ gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
+ gap_name.data = list(bytes(b'Im_The_DUT'))
+ gap_data = le_advertising_facade.GapDataMsg(data=bytes(gap_name.Serialize()))
+ config = le_advertising_facade.AdvertisingConfig(
+ advertisement=[gap_data],
+ interval_min=512,
+ interval_max=768,
+ advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
+ own_address_type=common.USE_RANDOM_DEVICE_ADDRESS,
+ channel_map=7,
+ filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
+ request = le_advertising_facade.CreateAdvertiserRequest(config=config)
+ create_response = self.cert.hci_le_advertising_manager.CreateAdvertiser(request)
+ response_future = self.dut_l2cap.connect_coc_to_cert(self.cert_address, psm)
+ self.cert_l2cap.wait_for_connection()
+ # TODO: Currently we can only connect by using Dynamic channel API. Use fixed channel instead.
+ cert_channel = self.cert_l2cap.verify_and_respond_open_channel_from_remote(psm)
+ dut_channel = response_future.get_channel()
+ return (dut_channel, cert_channel)
+
+ def _open_channel_from_cert(self, signal_id=1, scid=0x0101, psm=0x33, mtu=1000, mps=100, initial_credit=6):
+
+ dut_channel = self.dut_l2cap.register_coc(self.cert_address, psm)
+ cert_channel = self.cert_l2cap.open_channel(signal_id, psm, scid, mtu, mps, initial_credit)
+
+ return (dut_channel, cert_channel)
+
+ def _open_channel_from_dut(self, psm=0x33):
+ response_future = self.dut_l2cap.connect_coc_to_cert(self.cert_address, psm)
+ cert_channel = self.cert_l2cap.verify_and_respond_open_channel_from_remote(psm)
+ dut_channel = response_future.get_channel()
+ return (dut_channel, cert_channel)
+
+ def _open_fixed_channel(self, cid=4):
+ dut_channel = self.dut_l2cap.get_fixed_channel(cid)
+ cert_channel = self.cert_l2cap.open_fixed_channel(cid)
+ return (dut_channel, cert_channel)
+
+ def test_fixed_channel_send(self):
+ self.dut_l2cap.enable_fixed_channel(4)
+ self._setup_link_from_cert()
+ (dut_channel, cert_channel) = self._open_fixed_channel(4)
+ dut_channel.send(b'hello' * 40)
+ assertThat(cert_channel).emits(L2capMatchers.Data(b'hello' * 40))
+
+ def test_fixed_channel_receive(self):
+ self.dut_l2cap.enable_fixed_channel(4)
+ self._setup_link_from_cert()
+ (dut_channel, cert_channel) = self._open_fixed_channel(4)
+ cert_channel.send(SAMPLE_PACKET)
+ assertThat(dut_channel).emits(L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17'))
+
+ def test_connect_from_dut_and_open_dynamic_channel(self):
+ """
+ Internal test for GD stack only
+ """
+ self._set_link_from_dut_and_open_channel()
+
+ @metadata(pts_test_id="L2CAP/LE/CPU/BV-01-C", pts_test_name="Send Connection Parameter Update Request")
+ def test_send_connection_parameter_update_request(self):
+ """
+ Verify that the IUT is able to send the connection parameter update Request to Lower Tester when acting as a peripheral device.
+ NOTE: This is an optional feature. Also if both LL central and peripheral supports 4.1+ connection parameter update, this should happen in LL only, not L2CAP
+ NOTE: Currently we need to establish at least one dynamic channel to allow update.
+ """
+ self._setup_link_from_cert()
+ self._open_channel_from_dut()
+ self.dut_l2cap.update_connection_parameter()
+ assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.LeConnectionParameterUpdateRequest())
+
+ @metadata(pts_test_id="L2CAP/LE/CPU/BV-02-C", pts_test_name="Accept Connection Parameter Update Request")
+ def test_accept_connection_parameter_update_request(self):
+ """
+ Verify that the IUT is able to receive and handle a request for connection parameter update when acting as a central device.
+ NOTE: Currently we need to establish at least one dynamic channel to allow update.
+ """
+ self._set_link_from_dut_and_open_channel()
+ self.cert_l2cap.get_control_channel().send(
+ l2cap_packets.ConnectionParameterUpdateRequestBuilder(2, 0x10, 0x10, 0x0a, 0x64))
+ assertThat(self.cert_l2cap.get_control_channel()).emits(
+ L2capMatchers.LeConnectionParameterUpdateResponse(
+ l2cap_packets.ConnectionParameterUpdateResponseResult.ACCEPTED))
+
+ @metadata(pts_test_id="L2CAP/LE/CPU/BI-01-C", pts_test_name="Reject Connection Parameter Update Parameters")
+ def test_reject_connection_parameter_update_parameters(self):
+ """
+ Verify that the IUT is able to reject a request for connection parameter update with illegal parameters.
+ NOTE: Currently we need to establish at least one dynamic channel to allow update.
+ """
+ self._set_link_from_dut_and_open_channel()
+ self.cert_l2cap.get_control_channel().send(
+ l2cap_packets.ConnectionParameterUpdateRequestBuilder(2, 0x10, 0x10, 512, 0x64))
+ assertThat(self.cert_l2cap.get_control_channel()).emits(
+ L2capMatchers.LeConnectionParameterUpdateResponse(
+ l2cap_packets.ConnectionParameterUpdateResponseResult.REJECTED))
+
+ @metadata(pts_test_id="L2CAP/LE/CPU/BI-02-C", pts_test_name="Reject Connection Parameter Update Request")
+ def test_reject_connection_parameter_update_request(self):
+ """
+ Verify that the IUT is able to reject a request for connection parameter update in peripheral mode.
+ """
+ self._setup_link_from_cert()
+ self.cert_l2cap.get_control_channel().send(
+ l2cap_packets.ConnectionParameterUpdateRequestBuilder(2, 0x10, 0x10, 0x0a, 0x64))
+ assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.LeCommandReject())
+
+ @metadata(pts_test_id="L2CAP/COS/CFC/BV-01-C", pts_test_name="Segmentation")
+ def test_segmentation(self):
+ """
+ Verify that the IUT can send data segments which are larger than the LE frame size.
+ """
+ self._setup_link_from_cert()
+ (dut_channel, cert_channel) = self._open_channel_from_cert(mtu=1000, mps=102)
+ dut_channel.send(b'hello' * 20 + b'world')
+ # The first LeInformation packet contains 2 bytes of SDU size.
+ # The packet is divided into first 100 bytes from 'hellohello....'
+ # and remaining 5 bytes 'world'
+ assertThat(cert_channel).emits(
+ L2capMatchers.FirstLeIFrame(b'hello' * 20, sdu_size=105), L2capMatchers.Data(b'world')).inOrder()
+
+ @metadata(pts_test_id="L2CAP/COS/CFC/BV-02-C", pts_test_name="No Segmentation")
+ def test_no_segmentation(self):
+ """
+ Verify that the IUT can send data segments which do not require segmentation.
+ """
+ self._setup_link_from_cert()
+ (dut_channel, cert_channel) = self._open_channel_from_cert(mtu=1000, mps=202)
+ dut_channel.send(b'hello' * 40)
+ assertThat(cert_channel).emits(L2capMatchers.FirstLeIFrame(b'hello' * 40, sdu_size=200))
+
+ def test_no_segmentation_dut_is_central(self):
+ """
+ L2CAP/COS/CFC/BV-02-C
+ """
+ (dut_channel, cert_channel) = self._set_link_from_dut_and_open_channel()
+ dut_channel.send(b'hello' * 40)
+ assertThat(cert_channel).emits(L2capMatchers.FirstLeIFrame(b'hello' * 40, sdu_size=200))
+
+ @metadata(pts_test_id="L2CAP/COS/CFC/BV-03-C", pts_test_name="Reassembling")
+ def test_reassembling(self):
+ """
+ Verify that the IUT can correctly reassemble data received from the Lower Tester which is greater than the IUT LE-frame size.
+ """
+ self._setup_link_from_cert()
+ (dut_channel, cert_channel) = self._open_channel_from_cert()
+ sdu_size_for_two_sample_packet = 8
+ cert_channel.send_first_le_i_frame(sdu_size_for_two_sample_packet, SAMPLE_PACKET)
+ cert_channel.send(SAMPLE_PACKET)
+ assertThat(dut_channel).emits(L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17' * 2))
+
+ @metadata(pts_test_id="L2CAP/COS/CFC/BV-04-C", pts_test_name="Data Receiving")
+ def test_data_receiving(self):
+ """
+ Verify that the IUT can receive unsegmented data correctly.
+ """
+ self._setup_link_from_cert()
+ (dut_channel, cert_channel) = self._open_channel_from_cert()
+ cert_channel.send_first_le_i_frame(4, SAMPLE_PACKET)
+ assertThat(dut_channel).emits(L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17'))
+
+ def test_data_receiving_dut_is_central(self):
+ """
+ L2CAP/COS/CFC/BV-04-C
+ """
+ (dut_channel, cert_channel) = self._set_link_from_dut_and_open_channel()
+ cert_channel.send_first_le_i_frame(4, SAMPLE_PACKET)
+ assertThat(dut_channel).emits(L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17'))
+
+ @metadata(pts_test_id="L2CAP/COS/CFC/BV-05-C", pts_test_name="Multiple Channels with Interleaved Data Streams")
+ def test_multiple_channels_with_interleaved_data_streams(self):
+ """
+ Verify that an IUT can create multiple channels and receives data streams on the channels when the streams are interleaved.
+ """
+ self._setup_link_from_cert()
+ (dut_channel_x, cert_channel_x) = self._open_channel_from_cert(signal_id=1, scid=0x0103, psm=0x33)
+ (dut_channel_y, cert_channel_y) = self._open_channel_from_cert(signal_id=2, scid=0x0105, psm=0x35)
+ (dut_channel_z, cert_channel_z) = self._open_channel_from_cert(signal_id=3, scid=0x0107, psm=0x37)
+ cert_channel_y.send_first_le_i_frame(4, SAMPLE_PACKET)
+ cert_channel_z.send_first_le_i_frame(4, SAMPLE_PACKET)
+ cert_channel_y.send_first_le_i_frame(4, SAMPLE_PACKET)
+ cert_channel_z.send_first_le_i_frame(4, SAMPLE_PACKET)
+ cert_channel_y.send_first_le_i_frame(4, SAMPLE_PACKET)
+ # TODO: We should assert two events in order, but it got stuck
+ assertThat(dut_channel_y).emits(L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17'), at_least_times=3)
+ assertThat(dut_channel_z).emits(
+ L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17'),
+ L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17')).inOrder()
+ cert_channel_z.send_first_le_i_frame(4, SAMPLE_PACKET)
+ assertThat(dut_channel_z).emits(L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17'))
+
+ @metadata(pts_test_id="L2CAP/LE/REJ/BI-01-C", pts_test_name="Reject Unknown Command in LE Signaling Channel")
+ def test_reject_unknown_command_in_le_sigling_channel(self):
+ """
+ Verify that the IUT is able to reject unknown command.
+ """
+ self._setup_link_from_cert()
+ self.cert_l2cap.get_control_channel().send(
+ l2cap_packets.InformationRequestBuilder(
+ 2, l2cap_packets.InformationRequestInfoType.EXTENDED_FEATURES_SUPPORTED))
+ assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.LeCommandReject())
+
+ @metadata(pts_test_id="L2CAP/LE/REJ/BI-02-C", pts_test_name="Command Reject – Reserved PDU Codes")
+ def test_command_reject_reserved_pdu_codes(self):
+ """
+ Verify that an IUT receiving a PDU with a reserved command code sends a command reject.
+ """
+ self._setup_link_from_cert()
+ self.cert_l2cap.get_control_channel().send(l2cap_packets.MoveChannelRequestBuilder(2, 0, 0))
+ assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.LeCommandReject())
+
+ @metadata(pts_test_id="L2CAP/LE/CFC/BV-01-C", pts_test_name="LE Credit Based Connection Request - Legacy Peer")
+ def test_le_credit_based_connection_request_legacy_peer(self):
+ """
+ Verify that an IUT sending an LE Credit Based Connection Request to a legacy peer and receiving a Command Reject does not establish the channel.
+ """
+ self._setup_link_from_cert()
+ response_future = self.dut_l2cap.connect_coc_to_cert(self.cert_address, psm=0x33)
+ self.cert_l2cap.verify_and_reject_open_channel_from_remote(psm=0x33)
+ assertThat(response_future.get_status()).isNotEqualTo(LeCreditBasedConnectionResponseResult.SUCCESS)
+
+ @metadata(
+ pts_test_id="L2CAP/LE/CFC/BV-02-C", pts_test_name="LE Credit Based Connection Request on Supported LE_PSM")
+ def test_le_credit_based_connection_request_on_supported_le_psm(self):
+ """
+ Verify that an IUT sending an LE Credit Based Connection Request to a peer will establish the channel upon receiving the LE Credit Based Connection Response.
+ """
+ self._setup_link_from_cert()
+ (dut_channel, cert_channel) = self._open_channel_from_dut()
+ cert_channel.send_first_le_i_frame(4, SAMPLE_PACKET)
+ assertThat(dut_channel).emits(L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17'))
+
+ @metadata(
+ pts_test_id="L2CAP/LE/CFC/BV-03-C", pts_test_name="LE Credit Based Connection Response on Supported LE_PSM")
+ def test_credit_based_connection_response_on_supported_le_psm(self):
+ """
+ Verify that an IUT receiving a valid LE Credit Based Connection Request from a peer will send an LE Credit Based Connection Response and establish the channel.
+ """
+ self._setup_link_from_cert()
+ (dut_channel, cert_channel) = self._open_channel_from_cert()
+ dut_channel.send(b'hello')
+ assertThat(cert_channel).emits(L2capMatchers.FirstLeIFrame(b'hello', sdu_size=5))
+
+ @metadata(
+ pts_test_id="L2CAP/LE/CFC/BV-04-C", pts_test_name="LE Credit Based Connection Request on an Unsupported LE_PSM")
+ def test_credit_based_connection_request_on_an_unsupported_le_psm(self):
+ """
+ Verify that an IUT sending an LE Credit Based Connection Request on an unsupported LE_PSM will not establish a channel upon receiving an LE Credit Based Connection Response refusing the connection.
+ """
+ self._setup_link_from_cert()
+ response_future = self.dut_l2cap.connect_coc_to_cert(self.cert_address, psm=0x33)
+ self.cert_l2cap.verify_and_respond_open_channel_from_remote(
+ psm=0x33, result=LeCreditBasedConnectionResponseResult.LE_PSM_NOT_SUPPORTED)
+ assertThat(response_future.get_status()).isEqualTo(LeCreditBasedConnectionResponseResult.LE_PSM_NOT_SUPPORTED)
+
+ @metadata(
+ pts_test_id="L2CAP/LE/CFC/BV-05-C", pts_test_name="LE Credit Based Connection Request - unsupported LE_PSM")
+ def test_credit_based_connection_request_unsupported_le_psm(self):
+ """
+ Verify that an IUT receiving an LE Credit Based Connection Request on an unsupported LE_PSM will respond with an LE Credit Based Connection Response refusing the connection.
+ """
+ self._setup_link_from_cert()
+ self.cert_l2cap.get_control_channel().send(
+ l2cap_packets.LeCreditBasedConnectionRequestBuilder(1, 0x34, 0x0101, 2000, 1000, 1000))
+ assertThat(self.cert_l2cap.get_control_channel()).emits(
+ L2capMatchers.CreditBasedConnectionResponse(
+ result=LeCreditBasedConnectionResponseResult.LE_PSM_NOT_SUPPORTED))
+
+ @metadata(pts_test_id="L2CAP/LE/CFC/BV-06-C", pts_test_name="Credit Exchange – Receiving Incremental Credits")
+ def test_credit_exchange_receiving_incremental_credits(self):
+ """
+ Verify the IUT handles flow control correctly, by handling the LE Flow Control Credit sent by the peer.
+ """
+ self._setup_link_from_cert()
+ (dut_channel, cert_channel) = self._open_channel_from_cert(initial_credit=0)
+ for _ in range(4):
+ dut_channel.send(b'hello')
+ cert_channel.send_credits(1)
+ assertThat(cert_channel).emits(L2capMatchers.FirstLeIFrame(b'hello', sdu_size=5))
+ cert_channel.send_credits(1)
+ assertThat(cert_channel).emits(L2capMatchers.FirstLeIFrame(b'hello', sdu_size=5))
+ cert_channel.send_credits(2)
+ assertThat(cert_channel).emits(
+ L2capMatchers.FirstLeIFrame(b'hello', sdu_size=5), L2capMatchers.FirstLeIFrame(b'hello', sdu_size=5))
+
+ @metadata(pts_test_id="L2CAP/LE/CFC/BV-07-C", pts_test_name="Credit Exchange – Sending Credits")
+ def test_credit_exchange_sending_credits(self):
+ """
+ Verify that the IUT sends LE Flow Control Credit to the peer.
+ """
+ self._setup_link_from_cert()
+ (dut_channel, cert_channel) = self._open_channel_from_cert()
+ credits = cert_channel.credits_left()
+ # Note: DUT only needs to send credit when ALL credits are consumed.
+ # Here we enforce that DUT sends credit after receiving 3 packets, to
+ # test without sending too many packets (may take too long).
+ # This behavior is not expected for all Bluetooth stacks.
+ for _ in range(min(credits + 1, 3)):
+ cert_channel.send_first_le_i_frame(4, SAMPLE_PACKET)
+ self.cert_l2cap.verify_le_flow_control_credit(cert_channel)
+
+ @metadata(pts_test_id="L2CAP/LE/CFC/BV-08-C", pts_test_name="Disconnection Request")
+ def test_disconnection_request(self):
+ """
+ Verify that the IUT can disconnect the channel.
+ """
+ self._setup_link_from_cert()
+ (dut_channel, cert_channel) = self._open_channel_from_cert()
+ dut_channel.close_channel()
+ cert_channel.verify_disconnect_request()
+
+ @metadata(pts_test_id="L2CAP/LE/CFC/BV-09-C", pts_test_name="Disconnection Response")
+ def test_disconnection_response(self):
+ """
+ Verify that the IUT responds correctly to reception of a Disconnection Request.
+ """
+ self._setup_link_from_cert()
+ (dut_channel, cert_channel) = self._open_channel_from_cert()
+ cert_channel.disconnect_and_verify()
+
+ @metadata(pts_test_id="L2CAP/LE/CFC/BV-10-C", pts_test_name="Security - Insufficient Authentication – Initiator")
+ def test_security_insufficient_authentication_initiator(self):
+ """
+ Verify that the IUT does not establish the channel upon receipt of an LE Credit Based Connection Response indicating the connection was refused with Result “0x0005 – Connection Refused – Insufficient Authentication".
+ """
+ self._setup_link_from_cert()
+ response_future = self.dut_l2cap.connect_coc_to_cert(self.cert_address, psm=0x33)
+ self.cert_l2cap.verify_and_respond_open_channel_from_remote(
+ psm=0x33, result=LeCreditBasedConnectionResponseResult.INSUFFICIENT_AUTHENTICATION)
+ assertThat(response_future.get_status()).isEqualTo(
+ LeCreditBasedConnectionResponseResult.INSUFFICIENT_AUTHENTICATION)
+
+ @metadata(pts_test_id="L2CAP/LE/CFC/BV-11-C", pts_test_name="Security - Insufficient Authentication – Responder")
+ def test_security_insufficient_authentication_responder(self):
+ """
+ Verify that an IUT refuses to create a connection upon reception of an LE Credit Based Connection
+Request which fails to satisfy authentication requirements.
+ """
+ self._setup_link_from_cert()
+ psm = 0x33
+ self.dut_l2cap.register_coc(self.cert_address, psm, SecurityLevel.AUTHENTICATED_PAIRING_WITH_ENCRYPTION)
+ self.cert_l2cap.open_channel_with_expected_result(
+ psm, LeCreditBasedConnectionResponseResult.INSUFFICIENT_AUTHENTICATION)
+
+ @metadata(pts_test_id="L2CAP/LE/CFC/BV-12-C", pts_test_name="Security - Insufficient Authorization – Initiator")
+ def test_security_insufficient_authorization_initiator(self):
+ """
+ Verify that the IUT does not establish the channel upon receipt of an LE Credit Based Connection Response indicating the connection was refused with Result “0x0006 – Connection Refused – Insufficient Authorization”.
+ """
+ self._setup_link_from_cert()
+ response_future = self.dut_l2cap.connect_coc_to_cert(self.cert_address, psm=0x33)
+ self.cert_l2cap.verify_and_respond_open_channel_from_remote(
+ psm=0x33, result=LeCreditBasedConnectionResponseResult.INSUFFICIENT_AUTHORIZATION)
+ assertThat(response_future.get_status()).isEqualTo(
+ LeCreditBasedConnectionResponseResult.INSUFFICIENT_AUTHORIZATION)
+
+ @metadata(pts_test_id="L2CAP/LE/CFC/BV-13-C", pts_test_name="Security - Insufficient Authorization – Responder")
+ def test_security_insufficient_authorization_responder(self):
+ """
+ Verify that an IUT refuses to create a connection upon reception of an LE Credit Based Connection
+ Request which fails to satisfy authentication requirements.
+ """
+ self._setup_link_from_cert()
+ psm = 0x33
+ self.dut_l2cap.register_coc(self.cert_address, psm, SecurityLevel.AUTHORIZATION)
+ self.cert_l2cap.open_channel_with_expected_result(
+ psm, LeCreditBasedConnectionResponseResult.INSUFFICIENT_AUTHORIZATION)
+
+ @metadata(pts_test_id="L2CAP/LE/CFC/BV-14-C", pts_test_name="Security - Insufficient Key Size – Initiator")
+ def test_security_insufficient_key_size_initiator(self):
+ """
+ Verify that the IUT does not establish the channel upon receipt of an
+ LE Credit Based Connection Response indicating the connection was
+ refused with Result "0x0007 – Connection Refused – Insufficient
+ Encryption Key Size".
+ """
+ self._setup_link_from_cert()
+ response_future = self.dut_l2cap.connect_coc_to_cert(self.cert_address, psm=0x33)
+ self.cert_l2cap.verify_and_respond_open_channel_from_remote(
+ psm=0x33, result=LeCreditBasedConnectionResponseResult.INSUFFICIENT_ENCRYPTION_KEY_SIZE)
+ assertThat(response_future.get_status()).isEqualTo(
+ LeCreditBasedConnectionResponseResult.INSUFFICIENT_ENCRYPTION_KEY_SIZE)
+
+ @metadata(
+ pts_test_id="L2CAP/LE/CFC/BV-15-C", pts_test_name="Security - Insufficient Encryption Key Size – Responder")
+ def test_security_insufficient_encryption_key_size_responder(self):
+ """
+ Verify that an IUT refuses to create a connection upon receipt of an LE Credit Based Connection
+ Request which fails to satisfy Encryption Key Size requirements.
+ """
+ self._setup_link_from_cert()
+ psm = 0x33
+ self.dut_l2cap.register_coc(self.cert_address, psm, SecurityLevel.AUTHENTICATED_PAIRING_WITH_128_BIT_KEY)
+ self.cert_l2cap.open_channel_with_expected_result(
+ psm, LeCreditBasedConnectionResponseResult.INSUFFICIENT_ENCRYPTION_KEY_SIZE)
+
+ @metadata(
+ pts_test_id="L2CAP/LE/CFC/BV-16-C",
+ pts_test_name="LE Credit Based Connection Request - refuse due to insufficient resources - Initiator")
+ def test_le_connection_request_insufficient_resources_initiator(self):
+ """
+ Verify that an IUT sending an LE Credit Based Connection Request does
+ not establish the channel upon receiving an LE Credit Based Connection
+ Response refusing the connection with result "0x0004 – Connection
+ refused – no resources available".
+ """
+ self._setup_link_from_cert()
+ response_future = self.dut_l2cap.connect_coc_to_cert(self.cert_address, psm=0x33)
+ self.cert_l2cap.verify_and_respond_open_channel_from_remote(
+ psm=0x33, result=LeCreditBasedConnectionResponseResult.NO_RESOURCES_AVAILABLE)
+ assertThat(response_future.get_status()).isEqualTo(LeCreditBasedConnectionResponseResult.NO_RESOURCES_AVAILABLE)
+
+ @metadata(
+ pts_test_id="L2CAP/LE/CFC/BV-18-C",
+ pts_test_name="LE Credit Based Connection Request - refused due to Invalid Source CID - Initiator")
+ def test_request_refused_due_to_invalid_source_cid_initiator(self):
+ """
+ Verify that an IUT sending an LE Credit Based Connection Request does not establish the channel upon receiving an LE Credit Based Connection Response refusing the connection with result "0x0009 – Connection refused – Invalid Source CID".
+ """
+ self._setup_link_from_cert()
+ response_future = self.dut_l2cap.connect_coc_to_cert(self.cert_address, psm=0x33)
+ self.cert_l2cap.verify_and_respond_open_channel_from_remote(
+ psm=0x33, result=LeCreditBasedConnectionResponseResult.INVALID_SOURCE_CID)
+ assertThat(response_future.get_status()).isEqualTo(LeCreditBasedConnectionResponseResult.INVALID_SOURCE_CID)
+
+ @metadata(
+ pts_test_id="L2CAP/LE/CFC/BV-19-C",
+ pts_test_name="LE Credit Based Connection Request - refused due to source CID already allocated - Initiator")
+ def test_request_refused_due_to_source_cid_already_allocated_initiator(self):
+ """
+ Verify that an IUT sending an LE Credit Based Connection Request does not establish the channel upon receiving an LE Credit Based Connection Response refusing the connection with result "0x000A – Connection refused – Source CID already allocated".
+ """
+ self._setup_link_from_cert()
+ response_future = self.dut_l2cap.connect_coc_to_cert(self.cert_address, psm=0x33)
+ self.cert_l2cap.verify_and_respond_open_channel_from_remote(
+ psm=0x33, result=LeCreditBasedConnectionResponseResult.SOURCE_CID_ALREADY_ALLOCATED)
+ assertThat(response_future.get_status()).isEqualTo(
+ LeCreditBasedConnectionResponseResult.SOURCE_CID_ALREADY_ALLOCATED)
+
+ @metadata(
+ pts_test_id="L2CAP/LE/CFC/BV-20-C",
+ pts_test_name="LE Credit Based Connection Response - refused due to Source CID already allocated - Responder")
+ def test_request_refused_due_to_source_cid_already_allocated_responder(self):
+ """
+ Verify that an IUT receiving an LE Credit Based Connection Request for a second channel will refuse the connection with result "0x000A - Connection refused – Source CID already allocated" if it receives a Source CID which is already in use.
+ """
+ self._setup_link_from_cert()
+ (dut_channel, cert_channel) = self._open_channel_from_cert(psm=0x33, scid=0x0101)
+ self.dut_l2cap.register_coc(self.cert_address, psm=0x35)
+ self.cert_l2cap.get_control_channel().send(
+ l2cap_packets.LeCreditBasedConnectionRequestBuilder(2, 0x35, 0x0101, 1000, 1000, 1000))
+ assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.CreditBasedConnectionResponseUsedCid())
+
+ @metadata(
+ pts_test_id="L2CAP/LE/CFC/BV-21-C",
+ pts_test_name="LE Credit Based Connection Request - refused due to Unacceptable Parameters - Initiator")
+ def test_request_refused_due_to_unacceptable_parameters_initiator(self):
+ """
+ Verify that an IUT sending an LE Credit Based Connection Request does not establish the channel upon receiving an LE Credit Based Connection Response refusing the connection with result "0x000B – Connection refused – Unacceptable Parameters".
+ """
+ self._setup_link_from_cert()
+ response_future = self.dut_l2cap.connect_coc_to_cert(self.cert_address, psm=0x33)
+ self.cert_l2cap.verify_and_respond_open_channel_from_remote(
+ psm=0x33, result=LeCreditBasedConnectionResponseResult.UNACCEPTABLE_PARAMETERS)
+ assertThat(response_future.get_status()).isEqualTo(
+ LeCreditBasedConnectionResponseResult.UNACCEPTABLE_PARAMETERS)
+
+ @metadata(pts_test_id="L2CAP/LE/CFC/BI-01-C", pts_test_name="Credit Exchange – Exceed Initial Credits")
+ def test_credit_exchange_exceed_initial_credits(self):
+ """
+ Verify that the IUT disconnects the LE Data Channel when the credit count exceeds 65535.
+ """
+ self._setup_link_from_cert()
+ (dut_channel, cert_channel) = self._open_channel_from_cert()
+ cert_channel.send_credits(65535)
+ cert_channel.verify_disconnect_request()
diff --git a/gd/l2cap/le/internal/link_manager.cc b/gd/l2cap/le/internal/link_manager.cc
index b41832d..f2677a3 100644
--- a/gd/l2cap/le/internal/link_manager.cc
+++ b/gd/l2cap/le/internal/link_manager.cc
@@ -80,14 +80,14 @@
}
pending_link->second.pending_fixed_channel_connections_.push_back(std::move(pending_fixed_channel_connection));
// Then create new ACL connection
- acl_manager_->CreateLeConnection(address_with_type);
+ acl_manager_->CreateLeConnection(address_with_type, /* is_direct */ true);
}
void LinkManager::ConnectDynamicChannelServices(
hci::AddressWithType device, Link::PendingDynamicChannelConnection pending_dynamic_channel_connection, Psm psm) {
auto* link = GetLink(device);
if (link == nullptr) {
- acl_manager_->CreateLeConnection(device);
+ acl_manager_->CreateLeConnection(device, /* is_direct */ true);
pending_dynamic_channels_[device].push_back(std::make_pair(psm, std::move(pending_dynamic_channel_connection)));
return;
}
diff --git a/gd/l2cap/le/internal/link_manager_test.cc b/gd/l2cap/le/internal/link_manager_test.cc
index 806ec99..c7585f7 100644
--- a/gd/l2cap/le/internal/link_manager_test.cc
+++ b/gd/l2cap/le/internal/link_manager_test.cc
@@ -116,7 +116,7 @@
EXPECT_CALL(mock_le_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
// Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
- EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type)).Times(1);
+ EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type, true)).Times(1);
LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
.handler_ = user_handler_,
.on_fail_callback_ = common::BindOnce([](FixedChannelManager::ConnectionResult result) { FAIL(); })};
@@ -223,7 +223,7 @@
EXPECT_CALL(mock_le_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
// Step 2: Connect to fixed channel without any service registered will result in failure
- EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type)).Times(0);
+ EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type, true)).Times(0);
FixedChannelManager::ConnectionResult my_result;
LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
.handler_ = user_handler_,
@@ -262,7 +262,7 @@
EXPECT_CALL(mock_le_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
// Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
- EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type)).Times(1);
+ EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type, true)).Times(1);
FixedChannelManager::ConnectionResult my_result;
LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
.handler_ = user_handler_,
@@ -311,7 +311,7 @@
EXPECT_CALL(mock_le_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
// Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
- EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type)).Times(1);
+ EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type, true)).Times(1);
LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
.handler_ = user_handler_,
.on_fail_callback_ = common::BindOnce([](FixedChannelManager::ConnectionResult result) { FAIL(); })};
@@ -407,7 +407,7 @@
EXPECT_CALL(mock_le_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
// Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
- EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type)).Times(1);
+ EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type, true)).Times(1);
LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
.handler_ = user_handler_,
.on_fail_callback_ = common::BindOnce([](FixedChannelManager::ConnectionResult result) { FAIL(); })};
@@ -505,7 +505,7 @@
EXPECT_CALL(mock_le_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
// Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
- EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type)).Times(1);
+ EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type, true)).Times(1);
LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
.handler_ = user_handler_,
.on_fail_callback_ = common::BindOnce([](FixedChannelManager::ConnectionResult result) { FAIL(); })};
diff --git a/gd/module.cc b/gd/module.cc
index 9116d4d..1805822 100644
--- a/gd/module.cc
+++ b/gd/module.cc
@@ -13,12 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#define LOG_TAG "BtGdModule"
#include "module.h"
+#include "common/init_flags.h"
#include "dumpsys/init_flags.h"
+#include "os/wakelock_manager.h"
using ::bluetooth::os::Handler;
using ::bluetooth::os::Thread;
+using ::bluetooth::os::WakelockManager;
namespace bluetooth {
@@ -27,10 +31,6 @@
ModuleFactory::ModuleFactory(std::function<Module*()> ctor) : ctor_(ctor) {
}
-std::string Module::ToString() const {
- return "Module";
-}
-
Handler* Module::GetHandler() const {
ASSERT_LOG(handler_ != nullptr, "Can't get handler when it's not started");
return handler_;
@@ -82,16 +82,21 @@
return started_instance->second;
}
+ LOG_DEBUG("Constructing next module");
Module* instance = module->ctor_();
last_instance_ = "starting " + instance->ToString();
set_registry_and_handler(instance, thread);
+ LOG_DEBUG("Starting dependencies of %s", instance->ToString().c_str());
instance->ListDependencies(&instance->dependencies_);
Start(&instance->dependencies_, thread);
+ LOG_DEBUG("Finished starting dependencies and calling Start() of %s", instance->ToString().c_str());
+
instance->Start();
start_order_.push_back(module);
started_modules_[module] = instance;
+ LOG_DEBUG("Started %s", instance->ToString().c_str());
return instance;
}
@@ -136,6 +141,7 @@
auto title = builder.CreateString(title_);
auto init_flags_offset = dumpsys::InitFlags::Dump(&builder);
+ auto wakelock_offset = WakelockManager::Get().GetDumpsysData(&builder);
std::queue<DumpsysDataFinisher> queue;
for (auto it = module_registry_.start_order_.rbegin(); it != module_registry_.start_order_.rend(); it++) {
@@ -147,6 +153,7 @@
DumpsysDataBuilder data_builder(builder);
data_builder.add_title(title);
data_builder.add_init_flags(init_flags_offset);
+ data_builder.add_wakelock_manager_data(wakelock_offset);
while (!queue.empty()) {
queue.front()(&data_builder);
diff --git a/gd/module.h b/gd/module.h
index 16d806d..083d7b8 100644
--- a/gd/module.h
+++ b/gd/module.h
@@ -92,7 +92,7 @@
// Get relevant state data from the module
virtual DumpsysDataFinisher GetDumpsysData(flatbuffers::FlatBufferBuilder* builder) const;
- virtual std::string ToString() const;
+ virtual std::string ToString() const = 0;
::bluetooth::os::Handler* GetHandler() const;
diff --git a/gd/module_unittest.cc b/gd/module_unittest.cc
index b0b35db..f940016 100644
--- a/gd/module_unittest.cc
+++ b/gd/module_unittest.cc
@@ -23,6 +23,7 @@
#include <functional>
#include <future>
+#include <string>
using ::bluetooth::os::Thread;
@@ -65,6 +66,10 @@
// A module is not considered stopped until after Stop() finishes
EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleNoDependency>());
}
+
+ std::string ToString() const override {
+ return std::string("TestModuleNoDependency");
+ }
};
const ModuleFactory TestModuleNoDependency::Factory = ModuleFactory([]() {
@@ -96,6 +101,10 @@
// A module is not considered stopped until after Stop() finishes
EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleOneDependency>());
}
+
+ std::string ToString() const override {
+ return std::string("TestModuleOneDependency");
+ }
};
const ModuleFactory TestModuleOneDependency::Factory = ModuleFactory([]() {
@@ -120,6 +129,10 @@
// A module is not considered stopped until after Stop() finishes
EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleNoDependencyTwo>());
}
+
+ std::string ToString() const override {
+ return std::string("TestModuleNoDependencyTwo");
+ }
};
const ModuleFactory TestModuleNoDependencyTwo::Factory = ModuleFactory([]() {
@@ -151,6 +164,10 @@
// A module is not considered stopped until after Stop() finishes
EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleTwoDependencies>());
}
+
+ std::string ToString() const override {
+ return std::string("TestModuleTwoDependencies");
+ }
};
const ModuleFactory TestModuleTwoDependencies::Factory = ModuleFactory([]() {
@@ -185,6 +202,10 @@
EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleDumpState>());
}
+ std::string ToString() const override {
+ return std::string("TestModuleDumpState");
+ }
+
DumpsysDataFinisher GetDumpsysData(flatbuffers::FlatBufferBuilder* fb_builder) const override {
auto string = fb_builder->CreateString(test_string_.c_str());
diff --git a/gd/neighbor/cert/neighbor_test.py b/gd/neighbor/cert/neighbor_test.py
index 6b744ba..9328b46 100644
--- a/gd/neighbor/cert/neighbor_test.py
+++ b/gd/neighbor/cert/neighbor_test.py
@@ -13,86 +13,19 @@
# WITHOUT 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 datetime import timedelta
-
from cert.gd_base_test import GdBaseTestClass
-from cert.matchers import HciMatchers, NeighborMatchers
-from cert.py_hci import PyHci
-from cert.truth import assertThat
-from neighbor.cert.py_neighbor import PyNeighbor
-from neighbor.facade import facade_pb2 as neighbor_facade
-from bluetooth_packets_python3 import hci_packets
-from bluetooth_packets_python3.hci_packets import OpCode
+from neighbor.cert.neighbor_test_lib import NeighborTestBase
-class NeighborTest(GdBaseTestClass):
+class NeighborTest(GdBaseTestClass, NeighborTestBase):
def setup_class(self):
- super().setup_class(dut_module='HCI_INTERFACES', cert_module='HCI')
+ GdBaseTestClass.setup_class(self, dut_module='HCI_INTERFACES', cert_module='HCI')
def setup_test(self):
- super().setup_test()
- self.cert_hci = PyHci(self.cert, acl_streaming=True)
- self.cert_hci.send_command(hci_packets.WriteScanEnableBuilder(hci_packets.ScanEnable.INQUIRY_AND_PAGE_SCAN))
- self.cert_name = b'Im_A_Cert'
- self.cert_address = self.cert_hci.read_own_address()
- self.cert_name += b'@' + self.cert_address.encode('utf8')
- self.dut_neighbor = PyNeighbor(self.dut)
+ GdBaseTestClass.setup_test(self)
+ NeighborTestBase.setup_test(self, self.dut, self.cert)
def teardown_test(self):
- self.cert_hci.close()
- super().teardown_test()
-
- def _set_name(self):
- padded_name = self.cert_name
- while len(padded_name) < 248:
- padded_name = padded_name + b'\0'
- self.cert_hci.send_command(hci_packets.WriteLocalNameBuilder(padded_name))
-
- assertThat(self.cert_hci.get_event_stream()).emits(HciMatchers.CommandComplete(OpCode.WRITE_LOCAL_NAME))
-
- def test_inquiry_from_dut(self):
- inquiry_msg = neighbor_facade.InquiryMsg(
- inquiry_mode=neighbor_facade.DiscoverabilityMode.GENERAL,
- result_mode=neighbor_facade.ResultMode.STANDARD,
- length_1_28s=3,
- max_results=0)
- session = self.dut_neighbor.set_inquiry_mode(inquiry_msg)
- self.cert_hci.send_command(hci_packets.WriteScanEnableBuilder(hci_packets.ScanEnable.INQUIRY_AND_PAGE_SCAN))
- assertThat(session).emits(NeighborMatchers.InquiryResult(self.cert_address), timeout=timedelta(seconds=10))
-
- def test_inquiry_rssi_from_dut(self):
- inquiry_msg = neighbor_facade.InquiryMsg(
- inquiry_mode=neighbor_facade.DiscoverabilityMode.GENERAL,
- result_mode=neighbor_facade.ResultMode.RSSI,
- length_1_28s=6,
- max_results=0)
- session = self.dut_neighbor.set_inquiry_mode(inquiry_msg)
- self.cert_hci.send_command(hci_packets.WriteScanEnableBuilder(hci_packets.ScanEnable.INQUIRY_AND_PAGE_SCAN))
- assertThat(session).emits(
- NeighborMatchers.InquiryResultwithRssi(self.cert_address), timeout=timedelta(seconds=10))
-
- def test_inquiry_extended_from_dut(self):
- self._set_name()
- gap_name = hci_packets.GapData()
- gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
- gap_name.data = list(bytes(self.cert_name))
- gap_data = list([gap_name])
-
- self.cert_hci.send_command(
- hci_packets.WriteExtendedInquiryResponseBuilder(hci_packets.FecRequired.NOT_REQUIRED, gap_data))
- inquiry_msg = neighbor_facade.InquiryMsg(
- inquiry_mode=neighbor_facade.DiscoverabilityMode.GENERAL,
- result_mode=neighbor_facade.ResultMode.EXTENDED,
- length_1_28s=8,
- max_results=0)
- session = self.dut_neighbor.set_inquiry_mode(inquiry_msg)
- self.cert_hci.send_command(hci_packets.WriteScanEnableBuilder(hci_packets.ScanEnable.INQUIRY_AND_PAGE_SCAN))
- assertThat(session).emits(
- NeighborMatchers.ExtendedInquiryResult(self.cert_address), timeout=timedelta(seconds=10))
-
- def test_remote_name(self):
- self._set_name()
- session = self.dut_neighbor.get_remote_name(self.cert_address)
- session.verify_name(self.cert_name)
+ NeighborTestBase.teardown_test(self)
+ GdBaseTestClass.teardown_test(self)
diff --git a/gd/neighbor/cert/neighbor_test_lib.py b/gd/neighbor/cert/neighbor_test_lib.py
new file mode 100644
index 0000000..e4b50f8
--- /dev/null
+++ b/gd/neighbor/cert/neighbor_test_lib.py
@@ -0,0 +1,92 @@
+#!/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 datetime import timedelta
+
+from cert.matchers import HciMatchers, NeighborMatchers
+from cert.py_hci import PyHci
+from cert.truth import assertThat
+from neighbor.cert.py_neighbor import PyNeighbor
+from neighbor.facade import facade_pb2 as neighbor_facade
+from bluetooth_packets_python3 import hci_packets
+from bluetooth_packets_python3.hci_packets import OpCode
+
+
+class NeighborTestBase():
+
+ def setup_test(self, dut, cert):
+ self.cert_hci = PyHci(cert, acl_streaming=True)
+ self.cert_hci.send_command(hci_packets.WriteScanEnableBuilder(hci_packets.ScanEnable.INQUIRY_AND_PAGE_SCAN))
+ self.cert_name = b'Im_A_Cert'
+ self.cert_address = self.cert_hci.read_own_address()
+ self.cert_name += b'@' + self.cert_address.encode('utf8')
+ self.dut_neighbor = PyNeighbor(dut)
+
+ def teardown_test(self):
+ self.cert_hci.close()
+
+ def _set_name(self):
+ padded_name = self.cert_name
+ while len(padded_name) < 248:
+ padded_name = padded_name + b'\0'
+ self.cert_hci.send_command(hci_packets.WriteLocalNameBuilder(padded_name))
+
+ assertThat(self.cert_hci.get_event_stream()).emits(HciMatchers.CommandComplete(OpCode.WRITE_LOCAL_NAME))
+
+ def test_inquiry_from_dut(self):
+ inquiry_msg = neighbor_facade.InquiryMsg(
+ inquiry_mode=neighbor_facade.DiscoverabilityMode.GENERAL,
+ result_mode=neighbor_facade.ResultMode.STANDARD,
+ length_1_28s=3,
+ max_results=0)
+ session = self.dut_neighbor.set_inquiry_mode(inquiry_msg)
+ self.cert_hci.send_command(hci_packets.WriteScanEnableBuilder(hci_packets.ScanEnable.INQUIRY_AND_PAGE_SCAN))
+ assertThat(session).emits(NeighborMatchers.InquiryResult(self.cert_address), timeout=timedelta(seconds=10))
+
+ def test_inquiry_rssi_from_dut(self):
+ inquiry_msg = neighbor_facade.InquiryMsg(
+ inquiry_mode=neighbor_facade.DiscoverabilityMode.GENERAL,
+ result_mode=neighbor_facade.ResultMode.RSSI,
+ length_1_28s=6,
+ max_results=0)
+ session = self.dut_neighbor.set_inquiry_mode(inquiry_msg)
+ self.cert_hci.send_command(hci_packets.WriteScanEnableBuilder(hci_packets.ScanEnable.INQUIRY_AND_PAGE_SCAN))
+ assertThat(session).emits(
+ NeighborMatchers.InquiryResultwithRssi(self.cert_address), timeout=timedelta(seconds=10))
+
+ def test_inquiry_extended_from_dut(self):
+ self._set_name()
+ gap_name = hci_packets.GapData()
+ gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
+ gap_name.data = list(bytes(self.cert_name))
+ gap_data = list([gap_name])
+
+ self.cert_hci.send_command(
+ hci_packets.WriteExtendedInquiryResponseBuilder(hci_packets.FecRequired.NOT_REQUIRED, gap_data))
+ inquiry_msg = neighbor_facade.InquiryMsg(
+ inquiry_mode=neighbor_facade.DiscoverabilityMode.GENERAL,
+ result_mode=neighbor_facade.ResultMode.EXTENDED,
+ length_1_28s=8,
+ max_results=0)
+ session = self.dut_neighbor.set_inquiry_mode(inquiry_msg)
+ self.cert_hci.send_command(hci_packets.WriteScanEnableBuilder(hci_packets.ScanEnable.INQUIRY_AND_PAGE_SCAN))
+ assertThat(session).emits(
+ NeighborMatchers.ExtendedInquiryResult(self.cert_address), timeout=timedelta(seconds=10))
+
+ def test_remote_name(self):
+ self._set_name()
+ session = self.dut_neighbor.get_remote_name(self.cert_address)
+ session.verify_name(self.cert_name)
diff --git a/gd/neighbor/connectability.h b/gd/neighbor/connectability.h
index 8cdd643..777dfce 100644
--- a/gd/neighbor/connectability.h
+++ b/gd/neighbor/connectability.h
@@ -37,6 +37,9 @@
void ListDependencies(ModuleList* list) override;
void Start() override;
void Stop() override;
+ std::string ToString() const override {
+ return std::string("ConnectabilityModule");
+ }
private:
struct impl;
diff --git a/gd/neighbor/discoverability.h b/gd/neighbor/discoverability.h
index 124716c..9932662 100644
--- a/gd/neighbor/discoverability.h
+++ b/gd/neighbor/discoverability.h
@@ -16,6 +16,7 @@
#pragma once
#include <memory>
+#include <string>
#include "module.h"
@@ -40,6 +41,9 @@
void ListDependencies(ModuleList* list) override;
void Start() override;
void Stop() override;
+ std::string ToString() const override {
+ return std::string("DiscoverabilityModule");
+ }
private:
struct impl;
diff --git a/gd/neighbor/inquiry.h b/gd/neighbor/inquiry.h
index 6896fc2..c671278 100644
--- a/gd/neighbor/inquiry.h
+++ b/gd/neighbor/inquiry.h
@@ -73,6 +73,9 @@
void ListDependencies(ModuleList* list) override;
void Start() override;
void Stop() override;
+ std::string ToString() const override {
+ return std::string("InquiryModule");
+ }
private:
struct impl;
diff --git a/gd/neighbor/name.h b/gd/neighbor/name.h
index 779ae74..3136e9c 100644
--- a/gd/neighbor/name.h
+++ b/gd/neighbor/name.h
@@ -51,6 +51,9 @@
void ListDependencies(ModuleList* list) override;
void Start() override;
void Stop() override;
+ std::string ToString() const override {
+ return std::string("NameModule");
+ }
private:
struct impl;
diff --git a/gd/neighbor/name_db.h b/gd/neighbor/name_db.h
index cc707a1..03e87fa 100644
--- a/gd/neighbor/name_db.h
+++ b/gd/neighbor/name_db.h
@@ -46,6 +46,9 @@
void ListDependencies(ModuleList* list) override;
void Start() override;
void Stop() override;
+ std::string ToString() const override {
+ return std::string("NameDb");
+ }
private:
struct impl;
diff --git a/gd/neighbor/page.h b/gd/neighbor/page.h
index 075217b..224b642 100644
--- a/gd/neighbor/page.h
+++ b/gd/neighbor/page.h
@@ -49,6 +49,9 @@
void ListDependencies(ModuleList* list) override;
void Start() override;
void Stop() override;
+ std::string ToString() const override {
+ return std::string("Page");
+ }
private:
struct impl;
diff --git a/gd/neighbor/scan.h b/gd/neighbor/scan.h
index b6499d3..83d73cf 100644
--- a/gd/neighbor/scan.h
+++ b/gd/neighbor/scan.h
@@ -41,6 +41,9 @@
void ListDependencies(ModuleList* list) override;
void Start() override;
void Stop() override;
+ std::string ToString() const override {
+ return std::string("Scan");
+ }
private:
struct impl;
diff --git a/gd/os/Android.bp b/gd/os/Android.bp
index 775ed89..fb4c50c 100644
--- a/gd/os/Android.bp
+++ b/gd/os/Android.bp
@@ -10,8 +10,10 @@
filegroup {
name: "BluetoothOsSources_android",
srcs: [
+ "android/metrics.cc",
"android/parameter_provider.cc",
"android/system_properties.cc",
+ "android/wakelock_native.cc",
],
}
@@ -19,14 +21,17 @@
name: "BluetoothOsTestSources_android",
srcs: [
"android/system_properties_test.cc",
+ "android/wakelock_native_test.cc",
],
}
filegroup {
name: "BluetoothOsSources_host",
srcs: [
+ "host/metrics.cc",
"host/parameter_provider.cc",
"host/system_properties.cc",
+ "host/wakelock_native.cc",
],
}
@@ -48,6 +53,7 @@
"linux_generic/repeating_alarm.cc",
"linux_generic/reactive_semaphore.cc",
"linux_generic/thread.cc",
+ "linux_generic/wakelock_manager.cc",
],
}
@@ -61,6 +67,7 @@
"linux_generic/reactor_unittest.cc",
"linux_generic/repeating_alarm_unittest.cc",
"linux_generic/thread_unittest.cc",
+ "linux_generic/wakelock_manager_unittest.cc",
],
}
diff --git a/gd/os/BUILD.gn b/gd/os/BUILD.gn
index 3ed05ff..3e1403d 100644
--- a/gd/os/BUILD.gn
+++ b/gd/os/BUILD.gn
@@ -14,11 +14,14 @@
source_set("BluetoothOsSources_linux") {
sources = [
+ "linux/metrics.cc",
"linux/parameter_provider.cc",
"linux/system_properties.cc",
+ "linux/wakelock_native.cc",
]
configs += [ "//bt/gd:gd_defaults" ]
+ deps = [ "//bt:libbt-platform-protos-lite" ]
}
source_set("BluetoothOsSources_linux_generic") {
@@ -30,8 +33,9 @@
"linux_generic/reactor.cc",
"linux_generic/repeating_alarm.cc",
"linux_generic/thread.cc",
+ "linux_generic/wakelock_manager.cc",
]
configs += [ "//bt/gd:gd_defaults" ]
- deps = [ ":BluetoothOsSources_linux" ]
+ deps = [ ":BluetoothOsSources_linux", "//bt/gd:gd_default_deps" ]
}
diff --git a/gd/common/metrics.cc b/gd/os/android/metrics.cc
similarity index 86%
rename from gd/common/metrics.cc
rename to gd/os/android/metrics.cc
index 0a170fc..5260819 100644
--- a/gd/common/metrics.cc
+++ b/gd/os/android/metrics.cc
@@ -22,13 +22,14 @@
#include "common/metric_id_manager.h"
#include "common/strings.h"
-#include "metrics.h"
#include "os/log.h"
+#include "os/metrics.h"
namespace bluetooth {
-namespace common {
+namespace os {
+using bluetooth::common::MetricIdManager;
using bluetooth::hci::Address;
/**
@@ -66,14 +67,14 @@
LOG_WARN(
"Failed to log status %s , reason %s, from cmd %s, event %s, ble_event %s, for %s, handle %d, type %s, "
"error %d",
- ToHexString(cmd_status).c_str(),
- ToHexString(reason_code).c_str(),
- ToHexString(hci_cmd).c_str(),
- ToHexString(hci_event).c_str(),
- ToHexString(hci_ble_event).c_str(),
+ common::ToHexString(cmd_status).c_str(),
+ common::ToHexString(reason_code).c_str(),
+ common::ToHexString(hci_cmd).c_str(),
+ common::ToHexString(hci_event).c_str(),
+ common::ToHexString(hci_ble_event).c_str(),
address ? address->ToString().c_str() : "(NULL)",
connection_handle,
- ToHexString(link_type).c_str(),
+ common::ToHexString(link_type).c_str(),
ret);
}
}
@@ -81,7 +82,7 @@
void LogMetricHciTimeoutEvent(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_WARN("Failed for opcode %s, error %d", ToHexString(hci_cmd).c_str(), ret);
+ LOG_WARN("Failed for opcode %s, error %d", common::ToHexString(hci_cmd).c_str(), ret);
}
}
@@ -93,10 +94,10 @@
LOG_WARN(
"Failed for handle %d, status %s, version %s, manufacturer_name %s, subversion %s, error %d",
handle,
- ToHexString(status).c_str(),
- ToHexString(version).c_str(),
- ToHexString(manufacturer_name).c_str(),
- ToHexString(subversion).c_str(),
+ common::ToHexString(status).c_str(),
+ common::ToHexString(version).c_str(),
+ common::ToHexString(manufacturer_name).c_str(),
+ common::ToHexString(subversion).c_str(),
ret);
}
}
@@ -187,7 +188,7 @@
"Failed for %s, handle %d, status %s, rssi %d dBm, error %d",
address.ToString().c_str(),
handle,
- ToHexString(cmd_status).c_str(),
+ common::ToHexString(cmd_status).c_str(),
rssi,
ret);
}
@@ -211,7 +212,7 @@
"Failed for %s, handle %d, status %s, failed_contact_counter %d packets, error %d",
address.ToString().c_str(),
handle,
- ToHexString(cmd_status).c_str(),
+ common::ToHexString(cmd_status).c_str(),
failed_contact_counter,
ret);
}
@@ -235,7 +236,7 @@
"Failed for %s, handle %d, status %s, transmit_power_level %d packets, error %d",
address.ToString().c_str(),
handle,
- ToHexString(cmd_status).c_str(),
+ common::ToHexString(cmd_status).c_str(),
transmit_power_level,
ret);
}
@@ -253,9 +254,9 @@
LOG_WARN(
"Failed for %s, smp_cmd %s, direction %d, smp_fail_reason %s, error %d",
address.ToString().c_str(),
- ToHexString(smp_cmd).c_str(),
+ common::ToHexString(smp_cmd).c_str(),
direction,
- ToHexString(smp_fail_reason).c_str(),
+ common::ToHexString(smp_fail_reason).c_str(),
ret);
}
}
@@ -288,10 +289,10 @@
"reason %s, event_value %s, error %d",
address.ToString().c_str(),
handle,
- ToHexString(hci_cmd).c_str(),
- ToHexString(hci_event).c_str(),
- ToHexString(cmd_status).c_str(),
- ToHexString(reason_code).c_str(),
+ common::ToHexString(hci_cmd).c_str(),
+ common::ToHexString(hci_event).c_str(),
+ common::ToHexString(cmd_status).c_str(),
+ common::ToHexString(reason_code).c_str(),
std::to_string(event_value).c_str(),
ret);
}
@@ -319,8 +320,8 @@
LOG_WARN(
"Failed for %s, protocol_uuid %s, attribute_id %s, error %d",
address.ToString().c_str(),
- ToHexString(protocol_uuid).c_str(),
- ToHexString(attribute_id).c_str(),
+ common::ToHexString(protocol_uuid).c_str(),
+ common::ToHexString(attribute_id).c_str(),
ret);
}
}
@@ -405,6 +406,25 @@
}
}
-} // namespace common
+void LogMetricBluetoothHalCrashReason(
+ const Address& address,
+ uint32_t error_code,
+ uint32_t vendor_error_code) {
+ int ret = android::util::stats_write(
+ android::util::BLUETOOTH_HAL_CRASH_REASON_REPORTED,
+ 0 /* metric_id */,
+ byteField,
+ error_code,
+ vendor_error_code);
+ if (ret < 0) {
+ LOG_WARN(
+ "Failed for %s, error_code %s, vendor_error_code %s, error %d",
+ address.ToString().c_str(),
+ common::ToHexString(error_code).c_str(),
+ common::ToHexString(vendor_error_code).c_str(),
+ ret);
+ }
+}
+} // namespace os
} // namespace bluetooth
diff --git a/gd/os/android/system_properties.cc b/gd/os/android/system_properties.cc
index a53c1bf..b1ca6aa 100644
--- a/gd/os/android/system_properties.cc
+++ b/gd/os/android/system_properties.cc
@@ -19,7 +19,9 @@
#include <cutils/properties.h>
#include <array>
+#include <cctype>
+#include "common/strings.h"
#include "os/log.h"
namespace bluetooth {
@@ -47,5 +49,56 @@
return true;
}
+bool IsRootCanalEnabled() {
+ auto value = GetSystemProperty("ro.vendor.build.fingerprint");
+ if (value.has_value()) {
+ LOG_INFO("ro.vendor.build.fingerprint='%s', length=%zu", value->c_str(), value->length());
+ } else {
+ LOG_INFO("ro.vendor.build.fingerprint is not found");
+ }
+ // aosp_cf_x86_64_phone is just one platform that currently runs root canal
+ // When other platforms appears, or there is a better signal, add them here
+ if (value->find("generic/aosp_cf_x86_64_phone") == std::string::npos) {
+ LOG_INFO("Not on generic/aosp_cf_x86_64_phone and hence not root canal");
+ return false;
+ }
+ return true;
+}
+
+int GetAndroidVendorReleaseVersion() {
+ auto value = GetSystemProperty("ro.vendor.build.version.release_or_codename");
+ if (!value) {
+ LOG_INFO("ro.vendor.build.version.release_or_codename does not exist");
+ return 0;
+ }
+ LOG_INFO("ro.vendor.build.version.release_or_codename='%s', length=%zu", value->c_str(), value->length());
+ auto int_value = common::Int64FromString(*value);
+ if (int_value) {
+ return static_cast<int>(*int_value);
+ }
+ LOG_INFO("value '%s' cannot be parsed to int", value->c_str());
+ if (value->empty()) {
+ LOG_INFO("value '%s' is empty", value->c_str());
+ return 0;
+ }
+ if (value->length() > 1) {
+ LOG_INFO("value '%s' length is %zu, which is > 1", value->c_str(), value->length());
+ }
+ char release_code = toupper(value->at(0));
+ switch (release_code) {
+ case 'S':
+ return 11;
+ case 'R':
+ return 10;
+ case 'P':
+ return 9;
+ case 'O':
+ return 8;
+ default:
+ // Treble not enabled before Android O
+ return 0;
+ }
+}
+
} // namespace os
} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/os/android/wakelock_native.cc b/gd/os/android/wakelock_native.cc
new file mode 100644
index 0000000..d575282
--- /dev/null
+++ b/gd/os/android/wakelock_native.cc
@@ -0,0 +1,118 @@
+/******************************************************************************
+ *
+ * Copyright 2021 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 "BtGdWakelockNative"
+
+#include "os/internal/wakelock_native.h"
+
+#include <android/system/suspend/1.0/ISystemSuspend.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <cerrno>
+#include <string>
+
+#include "os/log.h"
+
+namespace bluetooth {
+namespace os {
+namespace internal {
+
+using android::sp;
+using android::system::suspend::V1_0::ISystemSuspend;
+using android::system::suspend::V1_0::IWakeLock;
+using android::system::suspend::V1_0::WakeLockType;
+
+struct WakelockNative::Impl {
+ sp<ISystemSuspend> suspend_service = nullptr;
+ sp<IWakeLock> current_wakelock = nullptr;
+
+ class SystemSuspendDeathRecipient : public ::android::hardware::hidl_death_recipient {
+ public:
+ explicit SystemSuspendDeathRecipient(WakelockNative::Impl* impl) : impl_(impl) {}
+ void serviceDied(uint64_t /*cookie*/, const android::wp<::android::hidl::base::V1_0::IBase>& /*who*/) override {
+ LOG_ERROR("ISystemSuspend HAL service died!");
+ impl_->suspend_service = nullptr;
+ }
+
+ private:
+ WakelockNative::Impl* impl_ = nullptr;
+ };
+ sp<SystemSuspendDeathRecipient> suspend_death_recipient;
+};
+
+void WakelockNative::Initialize() {
+ LOG_INFO("Initializing native wake locks");
+ pimpl_->suspend_service = ISystemSuspend::getService();
+ ASSERT_LOG(pimpl_->suspend_service, "Cannot get ISystemSuspend service");
+ pimpl_->suspend_death_recipient = new Impl::SystemSuspendDeathRecipient(pimpl_.get());
+ pimpl_->suspend_service->linkToDeath(pimpl_->suspend_death_recipient, 0 /* cookie */);
+}
+
+WakelockNative::StatusCode WakelockNative::Acquire(const std::string& lock_name) {
+ if (!pimpl_->suspend_service) {
+ LOG_ERROR("lock not acquired, ISystemService is not available");
+ return StatusCode::NATIVE_SERVICE_NOT_AVAILABLE;
+ }
+
+ if (pimpl_->current_wakelock) {
+ LOG_INFO("wakelock is already acquired");
+ return StatusCode::SUCCESS;
+ }
+
+ pimpl_->current_wakelock = pimpl_->suspend_service->acquireWakeLock(WakeLockType::PARTIAL, lock_name);
+ if (!pimpl_->current_wakelock) {
+ LOG_ERROR("wake lock not acquired: %s", strerror(errno));
+ return StatusCode::NATIVE_API_ERROR;
+ }
+
+ return StatusCode::SUCCESS;
+}
+
+WakelockNative::StatusCode WakelockNative::Release(const std::string& lock_name) {
+ if (!pimpl_->current_wakelock) {
+ LOG_WARN("no lock is currently acquired");
+ return StatusCode::SUCCESS;
+ }
+ pimpl_->current_wakelock->release();
+ pimpl_->current_wakelock.clear();
+ return StatusCode::SUCCESS;
+}
+
+void WakelockNative::CleanUp() {
+ LOG_INFO("Cleaning up native wake locks");
+ if (pimpl_->current_wakelock) {
+ LOG_INFO("releasing current wakelock during clean up");
+ pimpl_->current_wakelock->release();
+ pimpl_->current_wakelock.clear();
+ }
+ if (pimpl_->suspend_service) {
+ LOG_INFO("Unlink death recipient");
+ pimpl_->suspend_service->unlinkToDeath(pimpl_->suspend_death_recipient);
+ pimpl_->suspend_death_recipient.clear();
+ pimpl_->suspend_service.clear();
+ }
+}
+
+WakelockNative::WakelockNative() : pimpl_(std::make_unique<Impl>()) {}
+
+WakelockNative::~WakelockNative() = default;
+
+} // namespace internal
+} // namespace os
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/os/android/wakelock_native_test.cc b/gd/os/android/wakelock_native_test.cc
new file mode 100644
index 0000000..66be722
--- /dev/null
+++ b/gd/os/android/wakelock_native_test.cc
@@ -0,0 +1,273 @@
+/******************************************************************************
+ *
+ * Copyright 2020 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 "os/internal/wakelock_native.h"
+
+#include <aidl/android/system/suspend/BnSuspendCallback.h>
+#include <aidl/android/system/suspend/BnWakelockCallback.h>
+#include <aidl/android/system/suspend/ISuspendControlService.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_interface_utils.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <gtest/gtest.h>
+
+#include <chrono>
+#include <future>
+#include <memory>
+#include <mutex>
+
+namespace testing {
+
+using aidl::android::system::suspend::BnSuspendCallback;
+using aidl::android::system::suspend::BnWakelockCallback;
+using aidl::android::system::suspend::ISuspendControlService;
+using bluetooth::os::internal::WakelockNative;
+using ndk::ScopedAStatus;
+using ndk::SharedRefBase;
+using ndk::SpAIBinder;
+
+static const std::string kTestWakelockName = "BtWakelockNativeTestLock";
+
+static std::recursive_mutex mutex;
+static std::unique_ptr<std::promise<void>> acquire_promise = nullptr;
+static std::unique_ptr<std::promise<void>> release_promise = nullptr;
+
+class PromiseFutureContext {
+ public:
+ static void FulfilPromise(std::unique_ptr<std::promise<void>>& promise) {
+ std::lock_guard<std::recursive_mutex> lock_guard(mutex);
+ if (promise != nullptr) {
+ promise->set_value();
+ promise = nullptr;
+ }
+ }
+
+ explicit PromiseFutureContext(std::unique_ptr<std::promise<void>>& promise, bool expect_fulfillment)
+ : promise_(promise), expect_fulfillment_(expect_fulfillment) {
+ std::lock_guard<std::recursive_mutex> lock_guard(mutex);
+ EXPECT_EQ(promise_, nullptr);
+ promise_ = std::make_unique<std::promise<void>>();
+ future_ = promise->get_future();
+ }
+
+ ~PromiseFutureContext() {
+ auto future_status = future_.wait_for(std::chrono::seconds(2));
+ if (expect_fulfillment_) {
+ EXPECT_EQ(future_status, std::future_status::ready);
+ } else {
+ EXPECT_NE(future_status, std::future_status::ready);
+ }
+ std::lock_guard<std::recursive_mutex> lock_guard(mutex);
+ promise_ = nullptr;
+ }
+
+ private:
+ std::unique_ptr<std::promise<void>>& promise_;
+ bool expect_fulfillment_ = true;
+ std::future<void> future_;
+};
+
+class WakelockCallback : public BnWakelockCallback {
+ public:
+ ScopedAStatus notifyAcquired() override {
+ std::lock_guard<std::recursive_mutex> lock_guard(mutex);
+ net_acquired_count++;
+ fprintf(stderr, "notifyAcquired, count = %d\n", net_acquired_count);
+ PromiseFutureContext::FulfilPromise(acquire_promise);
+ return ScopedAStatus::ok();
+ }
+ ScopedAStatus notifyReleased() override {
+ std::lock_guard<std::recursive_mutex> lock_guard(mutex);
+ net_acquired_count--;
+ fprintf(stderr, "notifyReleased, count = %d\n", net_acquired_count);
+ PromiseFutureContext::FulfilPromise(release_promise);
+ return ScopedAStatus::ok();
+ }
+
+ int net_acquired_count = 0;
+};
+
+class SuspendCallback : public BnSuspendCallback {
+ public:
+ ScopedAStatus notifyWakeup(bool success, const std::vector<std::string>& wakeup_reasons) override {
+ std::lock_guard<std::recursive_mutex> lock_guard(mutex);
+ fprintf(stderr, "notifyWakeup\n");
+ return ScopedAStatus::ok();
+ }
+};
+
+// There is no way to unregister these callbacks besides when this process dies
+// Hence, we want to have only one copy of these callbacks per process
+static std::shared_ptr<SuspendCallback> suspend_callback = nullptr;
+static std::shared_ptr<WakelockCallback> control_callback = nullptr;
+
+class WakelockNativeTest : public Test {
+ protected:
+ void SetUp() override {
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+
+ WakelockNative::Get().Initialize();
+
+ auto binder_raw = AServiceManager_getService("suspend_control");
+ ASSERT_NE(binder_raw, nullptr);
+ binder.set(binder_raw);
+ control_service_ = ISuspendControlService::fromBinder(binder);
+ if (control_service_ == nullptr) {
+ FAIL() << "Fail to obtain suspend_control";
+ }
+
+ if (suspend_callback == nullptr) {
+ suspend_callback = SharedRefBase::make<SuspendCallback>();
+ bool is_registered = false;
+ ScopedAStatus status = control_service_->registerCallback(suspend_callback, &is_registered);
+ if (!is_registered || !status.isOk()) {
+ FAIL() << "Fail to register suspend callback";
+ }
+ }
+
+ if (control_callback == nullptr) {
+ control_callback = SharedRefBase::make<WakelockCallback>();
+ bool is_registered = false;
+ ScopedAStatus status =
+ control_service_->registerWakelockCallback(control_callback, kTestWakelockName, &is_registered);
+ if (!is_registered || !status.isOk()) {
+ FAIL() << "Fail to register wakeup callback";
+ }
+ }
+ control_callback->net_acquired_count = 0;
+ }
+
+ void TearDown() override {
+ control_service_ = nullptr;
+ binder.set(nullptr);
+ WakelockNative::Get().CleanUp();
+ }
+
+ SpAIBinder binder;
+ std::shared_ptr<ISuspendControlService> control_service_ = nullptr;
+};
+
+TEST_F(WakelockNativeTest, test_acquire_and_release_wakelocks) {
+ ASSERT_EQ(control_callback->net_acquired_count, 0);
+
+ {
+ PromiseFutureContext context(acquire_promise, true);
+ auto status = WakelockNative::Get().Acquire(kTestWakelockName);
+ ASSERT_EQ(status, WakelockNative::StatusCode::SUCCESS);
+ }
+ ASSERT_EQ(control_callback->net_acquired_count, 1);
+
+ {
+ PromiseFutureContext context(release_promise, true);
+ auto status = WakelockNative::Get().Release(kTestWakelockName);
+ ASSERT_EQ(status, WakelockNative::StatusCode::SUCCESS);
+ }
+ ASSERT_EQ(control_callback->net_acquired_count, 0);
+}
+
+TEST_F(WakelockNativeTest, test_acquire_and_release_wakelocks_repeated_acquire) {
+ ASSERT_EQ(control_callback->net_acquired_count, 0);
+
+ {
+ PromiseFutureContext context(acquire_promise, true);
+ auto status = WakelockNative::Get().Acquire(kTestWakelockName);
+ ASSERT_EQ(status, WakelockNative::StatusCode::SUCCESS);
+ }
+ ASSERT_EQ(control_callback->net_acquired_count, 1);
+
+ {
+ PromiseFutureContext context(acquire_promise, false);
+ auto status = WakelockNative::Get().Acquire(kTestWakelockName);
+ ASSERT_EQ(status, WakelockNative::StatusCode::SUCCESS);
+ }
+ ASSERT_EQ(control_callback->net_acquired_count, 1);
+
+ {
+ PromiseFutureContext context(release_promise, true);
+ auto status = WakelockNative::Get().Release(kTestWakelockName);
+ ASSERT_EQ(status, WakelockNative::StatusCode::SUCCESS);
+ }
+ ASSERT_EQ(control_callback->net_acquired_count, 0);
+}
+
+TEST_F(WakelockNativeTest, test_acquire_and_release_wakelocks_repeated_release) {
+ ASSERT_EQ(control_callback->net_acquired_count, 0);
+
+ {
+ PromiseFutureContext context(acquire_promise, true);
+ auto status = WakelockNative::Get().Acquire(kTestWakelockName);
+ ASSERT_EQ(status, WakelockNative::StatusCode::SUCCESS);
+ }
+ ASSERT_EQ(control_callback->net_acquired_count, 1);
+
+ {
+ PromiseFutureContext context(release_promise, true);
+ auto status = WakelockNative::Get().Release(kTestWakelockName);
+ ASSERT_EQ(status, WakelockNative::StatusCode::SUCCESS);
+ }
+ ASSERT_EQ(control_callback->net_acquired_count, 0);
+
+ {
+ PromiseFutureContext context(release_promise, false);
+ auto status = WakelockNative::Get().Release(kTestWakelockName);
+ ASSERT_EQ(status, WakelockNative::StatusCode::SUCCESS);
+ }
+ ASSERT_EQ(control_callback->net_acquired_count, 0);
+}
+
+TEST_F(WakelockNativeTest, test_acquire_and_release_wakelocks_in_a_loop) {
+ ASSERT_EQ(control_callback->net_acquired_count, 0);
+
+ for (int i = 0; i < 10; ++i) {
+ {
+ PromiseFutureContext context(acquire_promise, true);
+ auto status = WakelockNative::Get().Acquire(kTestWakelockName);
+ ASSERT_EQ(status, WakelockNative::StatusCode::SUCCESS);
+ }
+ ASSERT_EQ(control_callback->net_acquired_count, 1);
+
+ {
+ PromiseFutureContext context(release_promise, true);
+ auto status = WakelockNative::Get().Release(kTestWakelockName);
+ ASSERT_EQ(status, WakelockNative::StatusCode::SUCCESS);
+ }
+ ASSERT_EQ(control_callback->net_acquired_count, 0);
+ }
+}
+
+TEST_F(WakelockNativeTest, test_clean_up) {
+ WakelockNative::Get().Initialize();
+ ASSERT_EQ(control_callback->net_acquired_count, 0);
+
+ {
+ PromiseFutureContext context(acquire_promise, true);
+ auto status = WakelockNative::Get().Acquire(kTestWakelockName);
+ ASSERT_EQ(status, WakelockNative::StatusCode::SUCCESS);
+ }
+ ASSERT_EQ(control_callback->net_acquired_count, 1);
+
+ {
+ PromiseFutureContext context(release_promise, true);
+ WakelockNative::Get().CleanUp();
+ }
+ ASSERT_EQ(control_callback->net_acquired_count, 0);
+}
+
+} // namespace testing
\ No newline at end of file
diff --git a/gd/common/metrics_linux.cc b/gd/os/host/metrics.cc
similarity index 91%
rename from gd/common/metrics_linux.cc
rename to gd/os/host/metrics.cc
index b5b3f8f..925466d 100644
--- a/gd/common/metrics_linux.cc
+++ b/gd/os/host/metrics.cc
@@ -16,13 +16,11 @@
*
******************************************************************************/
-#include "metrics.h"
-
+#include "os/metrics.h"
#include "os/log.h"
namespace bluetooth {
-
-namespace common {
+namespace os {
using bluetooth::hci::Address;
@@ -99,6 +97,10 @@
void LogMetricSmpPairingEvent(
const Address& address, uint8_t smp_cmd, android::bluetooth::DirectionEnum direction, uint8_t smp_fail_reason) {}
-} // namespace common
+void LogMetricA2dpPlaybackEvent(const Address& address, int playback_state, int audio_coding_mode) {}
+void LogMetricBluetoothHalCrashReason(
+ const Address& address, uint32_t error_code, uint32_t vendor_error_code) {}
+
+} // namespace os
} // namespace bluetooth
diff --git a/gd/os/host/system_properties.cc b/gd/os/host/system_properties.cc
index 0b78686..db9f159 100644
--- a/gd/os/host/system_properties.cc
+++ b/gd/os/host/system_properties.cc
@@ -48,5 +48,13 @@
properties.clear();
}
+bool IsRootCanalEnabled() {
+ return false;
+}
+
+int GetAndroidVendorReleaseVersion() {
+ return 0;
+}
+
} // namespace os
} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/os/host/wakelock_native.cc b/gd/os/host/wakelock_native.cc
new file mode 100644
index 0000000..f173cf4
--- /dev/null
+++ b/gd/os/host/wakelock_native.cc
@@ -0,0 +1,53 @@
+/******************************************************************************
+ *
+ * Copyright 2021 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 "BtGdWakelockNative"
+
+#include "os/internal/wakelock_native.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace os {
+namespace internal {
+
+struct WakelockNative::Impl {};
+
+void WakelockNative::Initialize() {
+ LOG_INFO("Host native wakelock is not implemented");
+}
+
+WakelockNative::StatusCode WakelockNative::Acquire(const std::string& lock_name) {
+ LOG_INFO("Host native wakelock is not implemented");
+ return StatusCode::SUCCESS;
+}
+
+WakelockNative::StatusCode WakelockNative::Release(const std::string& lock_name) {
+ LOG_INFO("Host native wakelock is not implemented");
+ return StatusCode::SUCCESS;
+}
+void WakelockNative::CleanUp() {
+ LOG_INFO("Host native wakelock is not implemented");
+}
+
+WakelockNative::WakelockNative() : pimpl_(std::make_unique<Impl>()) {}
+
+WakelockNative::~WakelockNative() = default;
+
+} // namespace internal
+} // namespace os
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/os/internal/wakelock_native.h b/gd/os/internal/wakelock_native.h
new file mode 100644
index 0000000..acbd6ce
--- /dev/null
+++ b/gd/os/internal/wakelock_native.h
@@ -0,0 +1,51 @@
+/******************************************************************************
+ *
+ * Copyright 2021 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>
+
+namespace bluetooth {
+namespace os {
+namespace internal {
+
+// DO NOT USE OUTSIDE os/
+// Native wakelock APIs implemented by each architecture, not public APIs
+class WakelockNative {
+ public:
+ static WakelockNative& Get() {
+ static WakelockNative instance;
+ return instance;
+ }
+ enum StatusCode : uint8_t { SUCCESS = 0, NATIVE_SERVICE_NOT_AVAILABLE = 1, NATIVE_API_ERROR = 2 };
+ void Initialize();
+ StatusCode Acquire(const std::string& lock_name);
+ StatusCode Release(const std::string& lock_name);
+ void CleanUp();
+
+ ~WakelockNative();
+
+ private:
+ WakelockNative();
+ struct Impl;
+ std::unique_ptr<Impl> pimpl_;
+};
+
+} // namespace internal
+} // namespace os
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/common/metrics_linux.cc b/gd/os/linux/metrics.cc
similarity index 91%
copy from gd/common/metrics_linux.cc
copy to gd/os/linux/metrics.cc
index b5b3f8f..925466d 100644
--- a/gd/common/metrics_linux.cc
+++ b/gd/os/linux/metrics.cc
@@ -16,13 +16,11 @@
*
******************************************************************************/
-#include "metrics.h"
-
+#include "os/metrics.h"
#include "os/log.h"
namespace bluetooth {
-
-namespace common {
+namespace os {
using bluetooth::hci::Address;
@@ -99,6 +97,10 @@
void LogMetricSmpPairingEvent(
const Address& address, uint8_t smp_cmd, android::bluetooth::DirectionEnum direction, uint8_t smp_fail_reason) {}
-} // namespace common
+void LogMetricA2dpPlaybackEvent(const Address& address, int playback_state, int audio_coding_mode) {}
+void LogMetricBluetoothHalCrashReason(
+ const Address& address, uint32_t error_code, uint32_t vendor_error_code) {}
+
+} // namespace os
} // namespace bluetooth
diff --git a/gd/os/linux/parameter_provider.cc b/gd/os/linux/parameter_provider.cc
index f4e9175..4d10175 100644
--- a/gd/os/linux/parameter_provider.cc
+++ b/gd/os/linux/parameter_provider.cc
@@ -31,6 +31,7 @@
std::mutex parameter_mutex;
std::string config_file_path;
std::string snoop_log_file_path;
+std::string snooz_log_file_path;
} // namespace
// Write to $PWD/bt_stack.conf if $PWD can be found, otherwise, write to $HOME/bt_stack.conf
@@ -41,7 +42,7 @@
return config_file_path;
}
}
- return "/etc/systembt/bt_config.conf";
+ return "/var/lib/bluetooth/bt_config.conf";
}
void ParameterProvider::OverrideConfigFilePath(const std::string& path) {
@@ -57,7 +58,7 @@
}
}
- return "/etc/systembt/btsnoop_hci.log";
+ return "/var/log/bluetooth/btsnoop_hci.log";
}
void ParameterProvider::OverrideSnoopLogFilePath(const std::string& path) {
@@ -65,5 +66,15 @@
snoop_log_file_path = path;
}
+std::string ParameterProvider::SnoozLogFilePath() {
+ {
+ std::lock_guard<std::mutex> lock(parameter_mutex);
+ if (!snooz_log_file_path.empty()) {
+ return snooz_log_file_path;
+ }
+ }
+ return "/var/log/bluetooth/btsnooz_hci.log";
+}
+
} // namespace os
} // namespace bluetooth
diff --git a/gd/os/linux/system_properties.cc b/gd/os/linux/system_properties.cc
index 0b78686..db9f159 100644
--- a/gd/os/linux/system_properties.cc
+++ b/gd/os/linux/system_properties.cc
@@ -48,5 +48,13 @@
properties.clear();
}
+bool IsRootCanalEnabled() {
+ return false;
+}
+
+int GetAndroidVendorReleaseVersion() {
+ return 0;
+}
+
} // namespace os
} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/os/linux/wakelock_native.cc b/gd/os/linux/wakelock_native.cc
new file mode 100644
index 0000000..b98d75c
--- /dev/null
+++ b/gd/os/linux/wakelock_native.cc
@@ -0,0 +1,53 @@
+/******************************************************************************
+ *
+ * Copyright 2021 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 "BtGdWakelockNative"
+
+#include "os/internal/wakelock_native.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace os {
+namespace internal {
+
+struct WakelockNative::Impl {};
+
+void WakelockNative::Initialize() {
+ LOG_INFO("Linux native wakelock is not implemented");
+}
+
+WakelockNative::StatusCode WakelockNative::Acquire(const std::string& lock_name) {
+ LOG_INFO("Linux native wakelock is not implemented");
+ return StatusCode::SUCCESS;
+}
+
+WakelockNative::StatusCode WakelockNative::Release(const std::string& lock_name) {
+ LOG_INFO("Linux native wakelock is not implemented");
+ return StatusCode::SUCCESS;
+}
+void WakelockNative::CleanUp() {
+ LOG_INFO("Linux native wakelock is not implemented");
+}
+
+WakelockNative::WakelockNative() : pimpl_(std::make_unique<Impl>()) {}
+
+WakelockNative::~WakelockNative() = default;
+
+} // namespace internal
+} // namespace os
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/os/linux_generic/wakelock_manager.cc b/gd/os/linux_generic/wakelock_manager.cc
new file mode 100644
index 0000000..ea7b99a
--- /dev/null
+++ b/gd/os/linux_generic/wakelock_manager.cc
@@ -0,0 +1,274 @@
+/******************************************************************************
+ *
+ * Copyright 2021 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 "BtGdWakelock"
+
+#include "os/wakelock_manager.h"
+
+#include <cerrno>
+#include <mutex>
+
+#include "os/internal/wakelock_native.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace os {
+
+using internal::WakelockNative;
+using StatusCode = WakelockNative::StatusCode;
+
+uint64_t now_ms() {
+ struct timespec ts = {};
+ if (clock_gettime(CLOCK_BOOTTIME, &ts) == -1) {
+ LOG_ERROR("unable to get current time: %s", strerror(errno));
+ return 0;
+ }
+ return (ts.tv_sec * 1000LL) + (ts.tv_nsec / 1000000LL);
+}
+
+const std::string WakelockManager::kBtWakelockId = "bluetooth_gd_timer";
+
+// Wakelock statistics for the "bluetooth_timer"
+struct WakelockManager::Stats {
+ bool is_acquired = false;
+ size_t acquired_count = 0;
+ size_t released_count = 0;
+ size_t acquired_errors = 0;
+ size_t released_errors = 0;
+ uint64_t min_acquired_interval_ms = 0;
+ uint64_t max_acquired_interval_ms = 0;
+ uint64_t last_acquired_interval_ms = 0;
+ uint64_t total_acquired_interval_ms = 0;
+ uint64_t last_acquired_timestamp_ms = 0;
+ uint64_t last_released_timestamp_ms = 0;
+ uint64_t last_reset_timestamp_ms = now_ms();
+ StatusCode last_acquired_error = StatusCode::SUCCESS;
+ StatusCode last_released_error = StatusCode::SUCCESS;
+
+ void Reset() {
+ is_acquired = false;
+ acquired_count = 0;
+ released_count = 0;
+ acquired_errors = 0;
+ released_errors = 0;
+ min_acquired_interval_ms = 0;
+ max_acquired_interval_ms = 0;
+ last_acquired_interval_ms = 0;
+ total_acquired_interval_ms = 0;
+ last_acquired_timestamp_ms = 0;
+ last_released_timestamp_ms = 0;
+ last_reset_timestamp_ms = now_ms();
+ last_acquired_error = StatusCode::SUCCESS;
+ last_released_error = StatusCode::SUCCESS;
+ }
+
+ // Update the Bluetooth acquire wakelock statistics.
+ //
+ // This function should be called every time when the wakelock is acquired.
+ // |acquired_status| is the status code that was return when the wakelock was
+ // acquired.
+ void UpdateAcquiredStats(StatusCode acquired_status) {
+ const uint64_t just_now_ms = now_ms();
+ if (acquired_status != StatusCode::SUCCESS) {
+ acquired_errors++;
+ last_acquired_error = acquired_status;
+ }
+
+ if (is_acquired) {
+ return;
+ }
+
+ is_acquired = true;
+ acquired_count++;
+ last_acquired_timestamp_ms = just_now_ms;
+ }
+
+ // Update the Bluetooth release wakelock statistics.
+ //
+ // This function should be called every time when the wakelock is released.
+ // |released_status| is the status code that was return when the wakelock was
+ // released.
+ void UpdateReleasedStats(StatusCode released_status) {
+ const uint64_t just_now_ms = now_ms();
+ if (released_status != StatusCode::SUCCESS) {
+ released_errors++;
+ last_released_error = released_status;
+ }
+
+ if (!is_acquired) {
+ return;
+ }
+
+ is_acquired = false;
+ released_count++;
+ last_released_timestamp_ms = just_now_ms;
+
+ // Compute the acquired interval and update the statistics
+ uint64_t delta_ms = just_now_ms - last_acquired_timestamp_ms;
+ if (delta_ms < min_acquired_interval_ms || released_count == 1) {
+ min_acquired_interval_ms = delta_ms;
+ }
+ if (delta_ms > max_acquired_interval_ms) {
+ max_acquired_interval_ms = delta_ms;
+ }
+ last_acquired_interval_ms = delta_ms;
+ total_acquired_interval_ms += delta_ms;
+ }
+
+ flatbuffers::Offset<WakelockManagerData> GetDumpsysData(
+ flatbuffers::FlatBufferBuilder* fb_builder, bool is_native) const {
+ const uint64_t just_now_ms = now_ms();
+ // Compute the last acquired interval if the wakelock is still acquired
+ uint64_t delta_ms = 0;
+ uint64_t last_interval_ms = last_acquired_interval_ms;
+ uint64_t min_interval_ms = min_acquired_interval_ms;
+ uint64_t max_interval_ms = max_acquired_interval_ms;
+ uint64_t avg_interval_ms = 0;
+
+ if (is_acquired) {
+ delta_ms = just_now_ms - 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;
+ }
+ uint64_t total_interval_ms = total_acquired_interval_ms + delta_ms;
+
+ if (acquired_count > 0) {
+ avg_interval_ms = total_interval_ms / acquired_count;
+ }
+
+ WakelockManagerDataBuilder builder(*fb_builder);
+ builder.add_title(fb_builder->CreateString("Bluetooth Wakelock Statistics"));
+ builder.add_is_acquired(is_acquired);
+ builder.add_is_native(is_native);
+ builder.add_acquired_count(acquired_count);
+ builder.add_released_count(released_count);
+ builder.add_acquired_error_count(acquired_errors);
+ builder.add_released_error_count(released_errors);
+ builder.add_last_acquire_error_code(last_acquired_error);
+ builder.add_last_release_error_code(last_released_error);
+ builder.add_last_acquired_timestamp_millis(last_interval_ms);
+ builder.add_last_released_timestamp_millis(last_released_timestamp_ms);
+ builder.add_last_interval_millis(last_acquired_interval_ms);
+ builder.add_max_interval_millis(max_interval_ms);
+ builder.add_min_interval_millis(min_interval_ms);
+ builder.add_avg_interval_millis(avg_interval_ms);
+ builder.add_total_interval_millis(total_interval_ms);
+ builder.add_total_time_since_reset_millis(just_now_ms - last_reset_timestamp_ms);
+ return builder.Finish();
+ }
+};
+
+void WakelockManager::SetOsCallouts(OsCallouts* callouts, Handler* handler) {
+ std::lock_guard<std::recursive_mutex> lock_guard(mutex_);
+ if (initialized_) {
+ LOG_WARN("Setting OS callouts after initialization can lead to wakelock leak!");
+ }
+ os_callouts_ = callouts;
+ os_callouts_handler_ = handler;
+ is_native_ = (os_callouts_ == nullptr);
+ if (is_native_) {
+ ASSERT_LOG(os_callouts_handler_ != nullptr, "handler must not be null when callout is not null");
+ }
+ LOG_INFO("set to %s", is_native_ ? "native" : "non-native");
+}
+
+bool WakelockManager::Acquire() {
+ std::lock_guard<std::recursive_mutex> lock_guard(mutex_);
+ if (!initialized_) {
+ if (is_native_) {
+ WakelockNative::Get().Initialize();
+ }
+ initialized_ = true;
+ }
+
+ StatusCode status;
+ if (is_native_) {
+ status = WakelockNative::Get().Acquire(kBtWakelockId);
+ } else {
+ os_callouts_handler_->CallOn(os_callouts_, &OsCallouts::AcquireCallout, kBtWakelockId);
+ status = StatusCode::SUCCESS;
+ }
+
+ pstats_->UpdateAcquiredStats(status);
+
+ if (status != StatusCode::SUCCESS) {
+ LOG_ERROR("unable to acquire wake lock, error code: %u", status);
+ }
+
+ return status == StatusCode ::SUCCESS;
+}
+
+bool WakelockManager::Release() {
+ std::lock_guard<std::recursive_mutex> lock_guard(mutex_);
+ if (!initialized_) {
+ if (is_native_) {
+ WakelockNative::Get().Initialize();
+ }
+ initialized_ = true;
+ }
+
+ StatusCode status;
+ if (is_native_) {
+ status = WakelockNative::Get().Release(kBtWakelockId);
+ } else {
+ os_callouts_handler_->CallOn(os_callouts_, &OsCallouts::ReleaseCallout, kBtWakelockId);
+ status = StatusCode ::SUCCESS;
+ }
+
+ pstats_->UpdateReleasedStats(status);
+
+ if (status != StatusCode::SUCCESS) {
+ LOG_ERROR("unable to release wake lock, error code: %u", status);
+ }
+
+ return status == StatusCode ::SUCCESS;
+}
+
+void WakelockManager::CleanUp() {
+ std::lock_guard<std::recursive_mutex> lock_guard(mutex_);
+ if (!initialized_) {
+ LOG_ERROR("Already uninitialized");
+ return;
+ }
+ if (pstats_->is_acquired) {
+ LOG_ERROR("Releasing wake lock as part of cleanup");
+ Release();
+ }
+ if (is_native_) {
+ WakelockNative::Get().CleanUp();
+ }
+ pstats_->Reset();
+ initialized_ = false;
+}
+
+flatbuffers::Offset<WakelockManagerData> WakelockManager::GetDumpsysData(flatbuffers::FlatBufferBuilder* fb_builder) {
+ std::lock_guard<std::recursive_mutex> lock_guard(mutex_);
+ return pstats_->GetDumpsysData(fb_builder, is_native_);
+}
+
+WakelockManager::WakelockManager() : pstats_(std::make_unique<Stats>()) {}
+
+WakelockManager::~WakelockManager() = default;
+
+} // namespace os
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/os/linux_generic/wakelock_manager_unittest.cc b/gd/os/linux_generic/wakelock_manager_unittest.cc
new file mode 100644
index 0000000..0ae9704
--- /dev/null
+++ b/gd/os/linux_generic/wakelock_manager_unittest.cc
@@ -0,0 +1,192 @@
+/******************************************************************************
+ *
+ * Copyright 2020 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 <optional>
+#include <unordered_map>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "flatbuffers/flatbuffers.h"
+
+#include "common/bind.h"
+#include "os/handler.h"
+#include "os/thread.h"
+#include "os/wakelock_manager.h"
+#include "wakelock_manager_generated.h"
+
+namespace testing {
+
+using bluetooth::os::FinishWakelockManagerDataBuffer;
+using bluetooth::os::GetWakelockManagerData;
+using bluetooth::os::Handler;
+using bluetooth::os::Thread;
+using bluetooth::os::WakelockManager;
+using bluetooth::os::WakelockManagerData;
+using bluetooth::os::WakelockManagerDataBuilder;
+
+class TestOsCallouts : public WakelockManager::OsCallouts {
+ public:
+ void AcquireCallout(const std::string& lock_name) override {
+ auto iter = acquired_lock_counts.find(lock_name);
+ if (iter == acquired_lock_counts.end()) {
+ acquired_lock_counts[lock_name] = 0;
+ }
+ acquired_lock_counts[lock_name] += 1;
+ }
+
+ void ReleaseCallout(const std::string& lock_name) override {
+ auto iter = acquired_lock_counts.find(lock_name);
+ if (iter == acquired_lock_counts.end()) {
+ acquired_lock_counts[lock_name] = 0;
+ }
+ acquired_lock_counts[lock_name] -= 1;
+ }
+
+ std::optional<int> GetNetAcquiredCount(const std::string& lock_name) const {
+ auto iter = acquired_lock_counts.find(lock_name);
+ if (iter == acquired_lock_counts.end()) {
+ return std::nullopt;
+ }
+ return iter->second;
+ }
+
+ // how many times each lock is acquired, net, can go negative
+ std::unordered_map<std::string, int> acquired_lock_counts;
+};
+
+class WakelockManagerTest : public Test {
+ protected:
+ void SetUp() override {
+ thread_ = new Thread("test_thread", Thread::Priority::NORMAL);
+ handler_ = new Handler(thread_);
+ }
+ void TearDown() override {
+ handler_->Clear();
+ delete handler_;
+ delete thread_;
+ }
+
+ void SyncHandler() {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ handler_->Post(
+ bluetooth::common::BindOnce(&std::promise<void>::set_value, bluetooth::common::Unretained(&promise)));
+ auto future_status = future.wait_for(std::chrono::seconds(1));
+ ASSERT_EQ(future_status, std::future_status::ready);
+ }
+
+ Handler* handler_;
+ Thread* thread_;
+};
+
+TEST_F(WakelockManagerTest, test_set_os_callouts_repeated_acquire) {
+ TestOsCallouts os_callouts;
+ WakelockManager::Get().SetOsCallouts(&os_callouts, handler_);
+
+ // Initially, no wakelock is acquired
+ ASSERT_TRUE(os_callouts.acquired_lock_counts.empty());
+ ASSERT_FALSE(os_callouts.GetNetAcquiredCount(WakelockManager::kBtWakelockId));
+
+ WakelockManager::Get().Acquire();
+ SyncHandler();
+ ASSERT_EQ(os_callouts.acquired_lock_counts.size(), 1);
+ ASSERT_THAT(os_callouts.GetNetAcquiredCount(WakelockManager::kBtWakelockId), Optional(Eq(1)));
+
+ WakelockManager::Get().Acquire();
+ SyncHandler();
+ ASSERT_EQ(os_callouts.acquired_lock_counts.size(), 1);
+ ASSERT_THAT(os_callouts.GetNetAcquiredCount(WakelockManager::kBtWakelockId), Optional(Eq(2)));
+
+ WakelockManager::Get().Release();
+ SyncHandler();
+ ASSERT_THAT(os_callouts.GetNetAcquiredCount(WakelockManager::kBtWakelockId), Optional(Eq(1)));
+
+ WakelockManager::Get().CleanUp();
+ SyncHandler();
+}
+
+TEST_F(WakelockManagerTest, test_set_os_callouts_repeated_release) {
+ TestOsCallouts os_callouts;
+ WakelockManager::Get().SetOsCallouts(&os_callouts, handler_);
+
+ // Initially, no wakelock is acquired
+ ASSERT_TRUE(os_callouts.acquired_lock_counts.empty());
+ ASSERT_FALSE(os_callouts.GetNetAcquiredCount(WakelockManager::kBtWakelockId));
+
+ WakelockManager::Get().Acquire();
+ SyncHandler();
+ ASSERT_EQ(os_callouts.acquired_lock_counts.size(), 1);
+ ASSERT_THAT(os_callouts.GetNetAcquiredCount(WakelockManager::kBtWakelockId), Optional(Eq(1)));
+
+ WakelockManager::Get().Release();
+ SyncHandler();
+ ASSERT_EQ(os_callouts.acquired_lock_counts.size(), 1);
+ ASSERT_THAT(os_callouts.GetNetAcquiredCount(WakelockManager::kBtWakelockId), Optional(Eq(0)));
+
+ // OS callouts allow pass through for repeated release calls
+ WakelockManager::Get().Release();
+ SyncHandler();
+ ASSERT_THAT(os_callouts.GetNetAcquiredCount(WakelockManager::kBtWakelockId), Optional(Eq(-1)));
+
+ WakelockManager::Get().CleanUp();
+ SyncHandler();
+}
+
+TEST_F(WakelockManagerTest, test_with_os_callouts_in_a_loop_and_dump) {
+ TestOsCallouts os_callouts;
+ WakelockManager::Get().SetOsCallouts(&os_callouts, handler_);
+
+ // Initially, no wakelock is acquired
+ ASSERT_TRUE(os_callouts.acquired_lock_counts.empty());
+ ASSERT_FALSE(os_callouts.GetNetAcquiredCount(WakelockManager::kBtWakelockId));
+
+ for (size_t i = 0; i < 1000; i++) {
+ WakelockManager::Get().Acquire();
+ SyncHandler();
+ ASSERT_EQ(os_callouts.acquired_lock_counts.size(), 1);
+ ASSERT_THAT(os_callouts.GetNetAcquiredCount(WakelockManager::kBtWakelockId), Optional(Eq(1)));
+ WakelockManager::Get().Release();
+ SyncHandler();
+ ASSERT_THAT(os_callouts.GetNetAcquiredCount(WakelockManager::kBtWakelockId), Optional(Eq(0)));
+ }
+
+ {
+ flatbuffers::FlatBufferBuilder builder(1024);
+ auto offset = WakelockManager::Get().GetDumpsysData(&builder);
+ FinishWakelockManagerDataBuffer(builder, offset);
+ auto data = GetWakelockManagerData(builder.GetBufferPointer());
+
+ ASSERT_EQ(data->acquired_count(), 1000);
+ ASSERT_EQ(data->released_count(), 1000);
+ }
+
+ WakelockManager::Get().CleanUp();
+ SyncHandler();
+
+ {
+ flatbuffers::FlatBufferBuilder builder(1024);
+ auto offset = WakelockManager::Get().GetDumpsysData(&builder);
+ FinishWakelockManagerDataBuffer(builder, offset);
+ auto data = GetWakelockManagerData(builder.GetBufferPointer());
+
+ ASSERT_EQ(data->acquired_count(), 0);
+ ASSERT_EQ(data->released_count(), 0);
+ }
+}
+
+} // namespace testing
diff --git a/gd/os/log.h b/gd/os/log.h
index 312de3d..8e80e9e 100644
--- a/gd/os/log.h
+++ b/gd/os/log.h
@@ -84,8 +84,18 @@
#define LOG_INFO(...)
#define LOG_WARN(...)
#else
-#define LOG_VERBOSE(...) LOGWRAPPER(__VA_ARGS__)
-#define LOG_DEBUG(...) LOGWRAPPER(__VA_ARGS__)
+#define LOG_VERBOSE(fmt, args...) \
+ do { \
+ if (bluetooth::common::InitFlags::IsDebugLoggingEnabledForTag(LOG_TAG)) { \
+ LOGWRAPPER(fmt, ##args); \
+ } \
+ } while (false)
+#define LOG_DEBUG(fmt, args...) \
+ do { \
+ if (bluetooth::common::InitFlags::IsDebugLoggingEnabledForTag(LOG_TAG)) { \
+ LOGWRAPPER(fmt, ##args); \
+ } \
+ } while (false)
#define LOG_INFO(...) LOGWRAPPER(__VA_ARGS__)
#define LOG_WARN(...) LOGWRAPPER(__VA_ARGS__)
#endif /* FUZZ_TARGET */
diff --git a/gd/common/metrics.h b/gd/os/metrics.h
similarity index 95%
rename from gd/common/metrics.h
rename to gd/os/metrics.h
index 1ffe148..6f8ec57 100644
--- a/gd/common/metrics.h
+++ b/gd/os/metrics.h
@@ -25,7 +25,7 @@
namespace bluetooth {
-namespace common {
+namespace os {
/**
* Unknown connection handle for metrics purpose
*/
@@ -251,6 +251,18 @@
const std::string& model,
const std::string& hardware_version,
const std::string& software_version);
-} // namespace common
+
+/**
+ * Logs when received Bluetooth HAL crash reason report.
+ *
+ * @param address current connected address.
+ * @param error_code the crash reason from bluetooth hal
+ * @param vendor_error_code the vendor crash reason from bluetooth firmware
+ */
+void LogMetricBluetoothHalCrashReason(
+ const hci::Address& address,
+ uint32_t error_code,
+ uint32_t vendor_error_code);
+} // namespace os
} // namespace bluetooth
diff --git a/gd/os/system_properties.h b/gd/os/system_properties.h
index e7a14a3..f5a82b8 100644
--- a/gd/os/system_properties.h
+++ b/gd/os/system_properties.h
@@ -33,5 +33,12 @@
// Clear system properties for host only
void ClearSystemPropertiesForHost();
+// Check if the vendor image is using root canal simulated Bluetooth stack
+bool IsRootCanalEnabled();
+
+// Get Android Vendor Image release version in numeric value (e.g. Android R is 11), return 0 if not on Android or
+// version not available
+int GetAndroidVendorReleaseVersion();
+
} // namespace os
} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/os/wakelock_manager.fbs b/gd/os/wakelock_manager.fbs
new file mode 100644
index 0000000..7b85e28
--- /dev/null
+++ b/gd/os/wakelock_manager.fbs
@@ -0,0 +1,26 @@
+
+namespace bluetooth.os;
+
+attribute "privacy";
+
+table WakelockManagerData {
+ title:string;
+ is_acquired:bool;
+ is_native:bool;
+ acquired_count:int;
+ released_count:int;
+ acquired_error_count:int;
+ released_error_count:int;
+ last_acquire_error_code:int;
+ last_release_error_code:int;
+ last_acquired_timestamp_millis:int64;
+ last_released_timestamp_millis:int64;
+ last_interval_millis:int64;
+ max_interval_millis:int64;
+ min_interval_millis:int64;
+ avg_interval_millis:int64;
+ total_interval_millis:int64;
+ total_time_since_reset_millis:int64;
+}
+
+root_type WakelockManagerData;
diff --git a/gd/os/wakelock_manager.h b/gd/os/wakelock_manager.h
new file mode 100644
index 0000000..77645c3
--- /dev/null
+++ b/gd/os/wakelock_manager.h
@@ -0,0 +1,94 @@
+/******************************************************************************
+ *
+ * Copyright 2021 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 <string>
+
+#include <flatbuffers/flatbuffers.h>
+
+#include "handler.h"
+#include "wakelock_manager_generated.h"
+
+namespace bluetooth {
+namespace os {
+
+class WakelockManager {
+ public:
+ static const std::string kBtWakelockId;
+
+ static WakelockManager& Get() {
+ static WakelockManager instance;
+ return instance;
+ }
+
+ // The set of functions required by GD to grab wake locks. A caller with a custom wakelock implementation should
+ // implement this class and passed into the stack through SetCallouts()
+ class OsCallouts {
+ public:
+ virtual ~OsCallouts() = default;
+ virtual void AcquireCallout(const std::string& lock_name) = 0;
+ virtual void ReleaseCallout(const std::string& lock_name) = 0;
+ };
+
+ // Set the Bluetooth OS callouts to |callouts|.
+ //
+ // This function should be called when native kernel wakelock are not used directly.
+ // If this function is not called, or |callouts| is nullptr, then native kernel wakelock will be used.
+ // When |callouts| are used, the callbacks are going to be invoked asynchronously to avoid being blocked by upper
+ // layer delays. Therefore, a handler is needed and the callout result will be ignored.
+ //
+ // This method must be called before calling Acquire() or Release()
+ void SetOsCallouts(OsCallouts* callouts, Handler* handler);
+
+ // Acquire the Bluetooth wakelock.
+ // Return true on success, otherwise false.
+ // The function is thread safe.
+ bool Acquire();
+
+ // Release the Bluetooth wakelock.
+ // Return true on success, otherwise false.
+ // The function is thread safe.
+ bool Release();
+
+ // Cleanup the wakelock internal runtime state.
+ // This will NOT clean up the callouts
+ void CleanUp();
+
+ // Dump wakelock-related debug info to a flat buffer defined in wakelock_manager.fbs
+ flatbuffers::Offset<WakelockManagerData> GetDumpsysData(flatbuffers::FlatBufferBuilder* fb_builder);
+
+ ~WakelockManager();
+
+ private:
+ WakelockManager();
+
+ std::recursive_mutex mutex_;
+ bool initialized_ = false;
+ OsCallouts* os_callouts_ = nullptr;
+ Handler* os_callouts_handler_ = nullptr;
+ bool is_native_ = true;
+
+ struct Stats;
+ std::unique_ptr<Stats> pstats_;
+};
+
+} // namespace os
+} // namespace bluetooth
diff --git a/gd/packet/base_packet_builder.h b/gd/packet/base_packet_builder.h
index f093385..cf24dc1 100644
--- a/gd/packet/base_packet_builder.h
+++ b/gd/packet/base_packet_builder.h
@@ -38,8 +38,18 @@
// Write to the vector with the given iterator.
virtual void Serialize(BitInserter& it) const = 0;
+ void SetFlushable(bool is_flushable) {
+ is_flushable_ = is_flushable;
+ }
+ bool IsFlushable() const {
+ return is_flushable_;
+ }
+
protected:
BasePacketBuilder() = default;
+
+ private:
+ bool is_flushable_{false};
};
} // namespace packet
diff --git a/gd/packet/parser/gen_cpp.cc b/gd/packet/parser/gen_cpp.cc
index 3aabeeb..ce3cf0e 100644
--- a/gd/packet/parser/gen_cpp.cc
+++ b/gd/packet/parser/gen_cpp.cc
@@ -33,7 +33,7 @@
const std::filesystem::path& input_file_relative_path,
std::vector<std::string>* token) {
std::filesystem::path gen_namespace = root_namespace / input_file_relative_path;
- std::string gen_namespace_str = gen_namespace;
+ std::string gen_namespace_str = gen_namespace.u8string();
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 = {};
diff --git a/gd/packet/parser/main.cc b/gd/packet/parser/main.cc
index 5fd2cc4..4e0441d 100644
--- a/gd/packet/parser/main.cc
+++ b/gd/packet/parser/main.cc
@@ -31,8 +31,9 @@
#include "language_y.h"
-void yylex_init(void**);
-void yylex_destroy(void*);
+
+int yylex_init(void**);
+int yylex_destroy(void*);
void yyset_debug(int, void*);
void yyset_in(FILE*, void*);
diff --git a/gd/rust/chromeos/examples/dbus/floss.conf b/gd/rust/chromeos/examples/dbus/floss.conf
new file mode 100644
index 0000000..f0b76e4
--- /dev/null
+++ b/gd/rust/chromeos/examples/dbus/floss.conf
@@ -0,0 +1,39 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+
+<busconfig>
+ <!-- ../system.conf have denied everything, so we just punch some holes -->
+
+ <policy user="root">
+ <allow own="org.chromium.bluetooth"/>
+ <allow own="org.chromium.bluetooth.Manager"/>
+
+ <allow send_destination="org.chromium.bluetooth"/>
+ <allow send_interface="org.freedesktop.DBus.ObjectManager"/>
+ <allow send_interface="org.freedesktop.DBus.Properties"/>
+
+ <allow send_destination="org.chromium.bluetooth.Manager"/>
+ <allow send_interface="org.chromium.bluetooth.Manager"/>
+ </policy>
+
+ <policy user="bluetooth">
+ <allow own="org.chromium.bluetooth"/>
+ <allow own="org.chromium.bluetooth.Manager"/>
+
+ <allow send_destination="org.chromium.bluetooth"/>
+ <allow send_interface="org.freedesktop.DBus.ObjectManager"/>
+ <allow send_interface="org.freedesktop.DBus.Properties"/>
+
+ <allow send_destination="org.chromium.bluetooth.Manager"/>
+ <allow send_interface="org.chromium.bluetooth.Manager"/>
+ </policy>
+
+ <policy user="chronos">
+ <allow send_destination="org.chromium.bluetooth"/>
+ </policy>
+
+ <policy context="default">
+ <deny send_destination="org.chromium.bluetooth"/>
+ <deny send_destination="org.chromium.bluetooth.Manager"/>
+ </policy>
+</busconfig>
\ No newline at end of file
diff --git a/gd/rust/chromeos/examples/upstart/bluetoothd.conf b/gd/rust/chromeos/examples/upstart/bluetoothd.conf
new file mode 100644
index 0000000..cb53a20
--- /dev/null
+++ b/gd/rust/chromeos/examples/upstart/bluetoothd.conf
@@ -0,0 +1,34 @@
+description "Start the bluetooth daemon"
+author "chromium-os-dev@chromium.org"
+
+start on started system-services
+stop on stopping system-services
+
+limit memlock unlimited unlimited
+
+env BLUETOOTH_LIBDIR=/var/lib/bluetooth
+env BLUETOOTH_RUNDIR=/var/run/bluetooth
+env BLUETOOTH_DAEMON_OPTION=""
+env BLUETOOTH_WANT_FILE=/var/lib/misc/bluetooth-daemon.current
+
+pre-start script
+ mkdir -p -m 0750 ${BLUETOOTH_LIBDIR}
+ chown -R bluetooth:bluetooth ${BLUETOOTH_LIBDIR}
+ mkdir -p -m 0750 ${BLUETOOTH_RUNDIR}
+ chown -R bluetooth:bluetooth ${BLUETOOTH_RUNDIR}
+
+ # Make sure file exists before accessing it
+ mkdir -p "$(dirname $BLUETOOTH_WANT_FILE)"
+ touch "$BLUETOOTH_WANT_FILE"
+
+ # Check if we want to start bluez. If "floss" is wanted instead, exit early
+ # without starting bluez.
+ want_daemon="$(cat $BLUETOOTH_WANT_FILE)"
+ if [ "$want_daemon" = "floss" ]; then
+ exit 1
+ fi
+end script
+
+respawn
+
+exec /usr/bin/start_bluetoothd.sh
\ No newline at end of file
diff --git a/gd/rust/chromeos/examples/upstart/btadapterd.conf b/gd/rust/chromeos/examples/upstart/btadapterd.conf
new file mode 100644
index 0000000..36ef68f
--- /dev/null
+++ b/gd/rust/chromeos/examples/upstart/btadapterd.conf
@@ -0,0 +1,17 @@
+description "Bluetooth Adapter"
+author "ChromeOS BT <chromeos-bt-team@google.com>"
+
+# Limit respawning in case of crashloop
+respawn limit 10 5
+respawn
+
+import HCI
+instance $HCI
+
+post-stop script
+ rm /var/run/bluetooth/bluetooth${HCI}.pid
+end script
+
+script
+ exec runuser -u bluetooth -- /usr/bin/btadapterd --hci=$HCI
+end script
\ No newline at end of file
diff --git a/gd/rust/chromeos/examples/upstart/btmanagerd.conf b/gd/rust/chromeos/examples/upstart/btmanagerd.conf
new file mode 100644
index 0000000..0004a90
--- /dev/null
+++ b/gd/rust/chromeos/examples/upstart/btmanagerd.conf
@@ -0,0 +1,7 @@
+description "Start the bluetooth manager daemon"
+author "chromium-os-dev@chromium.org"
+
+start on started system-services
+stop on stopping system-services
+
+exec btmanagerd
\ No newline at end of file
diff --git a/gd/rust/common/Cargo.toml b/gd/rust/common/Cargo.toml
index 33a4039..22de79a 100644
--- a/gd/rust/common/Cargo.toml
+++ b/gd/rust/common/Cargo.toml
@@ -25,7 +25,7 @@
lazy_static = "*"
log = "*"
nix = "*"
-tokio = { version = "*", features = ['bytes', 'net'] }
+tokio = { version = "*", features = ['bytes', 'macros', 'net', 'rt-multi-thread', 'time'] }
# Proc Macro dependency
paste = "*"
diff --git a/gd/rust/common/src/time.rs b/gd/rust/common/src/time.rs
index 1acc805..5e63bf8 100644
--- a/gd/rust/common/src/time.rs
+++ b/gd/rust/common/src/time.rs
@@ -32,9 +32,13 @@
/// Completes when the alarm has expired
pub async fn expired(&mut self) {
- drop(self.fd.readable().await.unwrap());
+ let mut read_ready = self.fd.readable().await.unwrap();
+ read_ready.clear_ready();
+ drop(read_ready);
// Will not block, since we have confirmed it is readable
- self.fd.get_ref().wait().unwrap();
+ if self.fd.get_ref().get().unwrap().is_some() {
+ self.fd.get_ref().wait().unwrap();
+ }
}
}
@@ -60,9 +64,13 @@
impl Interval {
/// Call this to get the future for the next tick of the interval
pub async fn tick(&mut self) {
- drop(self.fd.readable().await.unwrap());
+ let mut read_ready = self.fd.readable().await.unwrap();
+ read_ready.clear_ready();
+ drop(read_ready);
// Will not block, since we have confirmed it is readable
- self.fd.get_ref().wait().unwrap();
+ if self.fd.get_ref().get().unwrap().is_some() {
+ self.fd.get_ref().wait().unwrap();
+ }
}
}
@@ -95,6 +103,49 @@
}
#[test]
+ fn alarm_cancel_after_expired() {
+ let runtime = tokio::runtime::Runtime::new().unwrap();
+ runtime.block_on(async {
+ let mut alarm = Alarm::new();
+ alarm.reset(Duration::from_millis(10));
+ tokio::time::sleep(Duration::from_millis(30)).await;
+ alarm.cancel();
+
+ for _ in 0..10 {
+ let ready_in_10_ms = async {
+ tokio::time::sleep(Duration::from_millis(10)).await;
+ };
+
+ tokio::select! {
+ _ = alarm.expired() => (),
+ _ = ready_in_10_ms => (),
+ }
+ }
+ });
+ }
+
+ #[test]
+ fn alarm_clear_ready_after_expired() {
+ // After an alarm expired, we need to make sure we clear ready from AsyncFdReadyGuard.
+ // Otherwise it's still ready and select! won't work.
+ let runtime = tokio::runtime::Runtime::new().unwrap();
+ runtime.block_on(async {
+ let timer = Instant::now();
+ let mut alarm = Alarm::new();
+ alarm.reset(Duration::from_millis(10));
+ alarm.expired().await;
+ let ready_in_10_ms = async {
+ tokio::time::sleep(Duration::from_millis(10)).await;
+ };
+ tokio::select! {
+ _ = alarm.expired() => (),
+ _ = ready_in_10_ms => (),
+ }
+ assert_near!(timer.elapsed().as_millis(), 20, 3);
+ });
+ }
+
+ #[test]
fn interval_schedule_and_then_drop() {
let runtime = tokio::runtime::Runtime::new().unwrap();
runtime.block_on(async {
diff --git a/gd/rust/facade/Cargo.toml b/gd/rust/facade/Cargo.toml
index ee8f2ad..6758875 100644
--- a/gd/rust/facade/Cargo.toml
+++ b/gd/rust/facade/Cargo.toml
@@ -14,7 +14,7 @@
# limitations under the License.
[package]
-name = "bt_facade_helpers"
+name = "bluetooth_with_facades"
version = "0.0.1"
edition = "2018"
@@ -32,6 +32,17 @@
protobuf = "*"
tokio = "*"
+# Binary-only deps
+clap = "*"
+lazy_static = "*"
+nix = "*"
+bt_common = { path = "../common" }
+
+
+[[bin]]
+name = "bluetooth_with_facades"
+path = "src/main.rs"
+
[lib]
-path = "helpers/lib.rs"
+path = "src/lib.rs"
crate-type = ["rlib"]
diff --git a/gd/rust/facade/helpers/Cargo.toml b/gd/rust/facade/helpers/Cargo.toml
new file mode 100644
index 0000000..ceaa0f4
--- /dev/null
+++ b/gd/rust/facade/helpers/Cargo.toml
@@ -0,0 +1,38 @@
+#
+# Copyright 2021 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.
+
+[package]
+name = "bt_facade_helpers"
+version = "0.0.1"
+edition = "2018"
+
+[dependencies]
+# GD bluetooth deps
+bt_facade_proto = { path = "../../facade_proto" }
+bt_packets = { path = "../../packets" }
+
+# External deps
+bytes = "*"
+cxx = "*"
+futures = "*"
+grpcio = "*"
+log = "*"
+protobuf = "*"
+tokio = "*"
+
+[lib]
+path = "lib.rs"
+crate-type = ["rlib"]
+
diff --git a/gd/rust/hal/Cargo.toml b/gd/rust/hal/Cargo.toml
index 9963e7a..fe909e8 100644
--- a/gd/rust/hal/Cargo.toml
+++ b/gd/rust/hal/Cargo.toml
@@ -21,7 +21,7 @@
[dependencies]
# BT dependencies
bt_common = { path = "../common" }
-bt_facade_helpers = { path = "../facade" }
+bt_facade_helpers = { path = "../facade/helpers" }
bt_facade_proto = { path = "../facade_proto" }
bt_packets = { path = "../packets" }
gddi = { path = "../gddi" }
diff --git a/gd/rust/hci/Cargo.toml b/gd/rust/hci/Cargo.toml
index 14ccc92..48e08a9 100644
--- a/gd/rust/hci/Cargo.toml
+++ b/gd/rust/hci/Cargo.toml
@@ -23,7 +23,7 @@
bt_common = { path = "../common" }
bt_hci_custom_types = { path = "custom_types" }
bt_hal = { path = "../hal" }
-bt_facade_helpers = { path = "../facade" }
+bt_facade_helpers = { path = "../facade/helpers" }
bt_facade_proto = { path = "../facade_proto" }
bt_packets = { path = "../packets" }
gddi = { path = "../gddi" }
diff --git a/gd/rust/hci/src/controller.rs b/gd/rust/hci/src/controller.rs
index 7e07d80..69213cb 100644
--- a/gd/rust/hci/src/controller.rs
+++ b/gd/rust/hci/src/controller.rs
@@ -2,15 +2,16 @@
use crate::{Address, CommandSender};
use bt_packets::hci::{
- Enable, ErrorCode, LeMaximumDataLength, LeReadBufferSizeV1Builder, LeReadBufferSizeV2Builder,
- LeReadConnectListSizeBuilder, LeReadLocalSupportedFeaturesBuilder,
+ Enable, ErrorCode, LeHostFeatureBits, LeMaximumDataLength, LeReadBufferSizeV1Builder,
+ LeReadBufferSizeV2Builder, LeReadConnectListSizeBuilder, LeReadLocalSupportedFeaturesBuilder,
LeReadMaximumAdvertisingDataLengthBuilder, LeReadMaximumDataLengthBuilder,
LeReadNumberOfSupportedAdvertisingSetsBuilder, LeReadPeriodicAdvertiserListSizeBuilder,
LeReadResolvingListSizeBuilder, LeReadSuggestedDefaultDataLengthBuilder,
- LeReadSupportedStatesBuilder, LeSetEventMaskBuilder, LocalVersionInformation, OpCode,
- OpCodeIndex, ReadBdAddrBuilder, ReadBufferSizeBuilder, ReadLocalExtendedFeaturesBuilder,
- ReadLocalNameBuilder, ReadLocalSupportedCommandsBuilder, ReadLocalVersionInformationBuilder,
- SetEventMaskBuilder, WriteLeHostSupportBuilder, WriteSimplePairingModeBuilder,
+ LeReadSupportedStatesBuilder, LeSetEventMaskBuilder, LeSetHostFeatureBuilder,
+ LocalVersionInformation, OpCode, OpCodeIndex, ReadBdAddrBuilder, ReadBufferSizeBuilder,
+ ReadLocalExtendedFeaturesBuilder, ReadLocalNameBuilder, ReadLocalSupportedCommandsBuilder,
+ ReadLocalVersionInformationBuilder, SetEventMaskBuilder, WriteLeHostSupportBuilder,
+ WriteSimplePairingModeBuilder,
};
use gddi::{module, provides, Stoppable};
use num_traits::ToPrimitive;
@@ -35,7 +36,7 @@
#[provides]
async fn provide_controller(mut hci: CommandSender) -> Arc<ControllerExports> {
- assert_success!(hci.send(LeSetEventMaskBuilder { le_event_mask: 0x0000000000021e7f }));
+ assert_success!(hci.send(LeSetEventMaskBuilder { le_event_mask: 0x0000000041021e7f }));
assert_success!(hci.send(SetEventMaskBuilder { event_mask: 0x3dbfffffffffffff }));
assert_success!(
hci.send(WriteSimplePairingModeBuilder { simple_pairing_mode: Enable::Enabled })
@@ -142,6 +143,13 @@
0
};
+ if commands.is_supported(OpCode::LeSetHostFeature) {
+ assert_success!(hci.send(LeSetHostFeatureBuilder {
+ bit_number: LeHostFeatureBits::ConnectedIsoStreamHostSupport,
+ bit_value: Enable::Enabled
+ }));
+ }
+
let address = assert_success!(hci.send(ReadBdAddrBuilder {})).get_bd_addr();
Arc::new(ControllerExports {
diff --git a/gd/rust/linux/client/Cargo.toml b/gd/rust/linux/client/Cargo.toml
new file mode 100644
index 0000000..92a9bc4
--- /dev/null
+++ b/gd/rust/linux/client/Cargo.toml
@@ -0,0 +1,27 @@
+[package]
+name = "client"
+version = "0.1.0"
+edition = "2018"
+
+[dependencies]
+rustyline = "8.0"
+bt_topshim = { path = "../../topshim" }
+btstack = { path = "../stack" }
+
+dbus = "0.9.2"
+dbus-crossroads = "0.3.0"
+dbus-tokio = "0.7.3"
+
+dbus_projection = { path = "../dbus_projection" }
+dbus_macros = { path = "../dbus_projection/dbus_macros" }
+
+futures = "0.3.13"
+num-traits = "*"
+tokio = { version = "1", features = ['bytes', 'fs', 'io-util', 'libc', 'macros', 'memchr', 'mio', 'net', 'num_cpus', 'rt', 'rt-multi-thread', 'sync', 'time', 'tokio-macros'] }
+
+[build-dependencies]
+pkg-config = "0.3.19"
+
+[[bin]]
+name = "btclient"
+path = "src/main.rs"
diff --git a/gd/rust/linux/client/src/command_handler.rs b/gd/rust/linux/client/src/command_handler.rs
new file mode 100644
index 0000000..51e7bc2
--- /dev/null
+++ b/gd/rust/linux/client/src/command_handler.rs
@@ -0,0 +1,53 @@
+use btstack::bluetooth::{BluetoothDevice, BluetoothTransport, IBluetooth};
+
+use num_traits::cast::FromPrimitive;
+
+use std::sync::{Arc, Mutex};
+
+use crate::console_yellow;
+use crate::print_info;
+
+/// Handles string command entered from command line.
+pub struct CommandHandler<T: IBluetooth> {
+ bluetooth: Arc<Mutex<Box<T>>>,
+}
+
+impl<T: IBluetooth> CommandHandler<T> {
+ pub fn new(bluetooth: Arc<Mutex<Box<T>>>) -> CommandHandler<T> {
+ CommandHandler { bluetooth }
+ }
+
+ pub fn cmd_enable(&self, _cmd: String) {
+ self.bluetooth.lock().unwrap().enable();
+ }
+
+ pub fn cmd_disable(&self, _cmd: String) {
+ self.bluetooth.lock().unwrap().disable();
+ }
+
+ pub fn cmd_get_address(&self, _cmd: String) {
+ let addr = self.bluetooth.lock().unwrap().get_address();
+ print_info!("Local address = {}", addr);
+ }
+
+ pub fn cmd_start_discovery(&self, _cmd: String) {
+ self.bluetooth.lock().unwrap().start_discovery();
+ }
+
+ pub fn cmd_cancel_discovery(&self, _cmd: String) {
+ self.bluetooth.lock().unwrap().cancel_discovery();
+ }
+
+ pub fn cmd_create_bond(&self, cmd: String) {
+ let s = cmd.split(' ').collect::<Vec<&str>>();
+ if s.len() < 2 {
+ println!("usage: create_bond <addr>");
+ return;
+ }
+ let device = BluetoothDevice { address: String::from(s[1]), name: String::from("") };
+ self.bluetooth
+ .lock()
+ .unwrap()
+ .create_bond(device, BluetoothTransport::from_i32(0).unwrap());
+ }
+}
diff --git a/gd/rust/linux/client/src/console.rs b/gd/rust/linux/client/src/console.rs
new file mode 100644
index 0000000..ff4d74f
--- /dev/null
+++ b/gd/rust/linux/client/src/console.rs
@@ -0,0 +1,25 @@
+//! Convenient functions to print messages to console.
+
+#[macro_export]
+macro_rules! console_blue {
+ ( $text:expr ) => {
+ format!("\x1b[1;34m{}\x1b[0m", $text).as_str()
+ };
+}
+
+#[macro_export]
+macro_rules! console_yellow {
+ ( $text:expr ) => {
+ format!("\x1b[1;33m{}\x1b[0m", $text).as_str()
+ };
+}
+
+#[macro_export]
+macro_rules! print_info {
+ ( $($arg:tt)* ) => {
+ {
+ print!("{}: ", console_yellow!("btclient:info"));
+ println!($($arg)*);
+ }
+ };
+}
diff --git a/gd/rust/linux/client/src/dbus_arg.rs b/gd/rust/linux/client/src/dbus_arg.rs
new file mode 100644
index 0000000..d1724aa
--- /dev/null
+++ b/gd/rust/linux/client/src/dbus_arg.rs
@@ -0,0 +1,3 @@
+use dbus_macros::generate_dbus_arg;
+
+generate_dbus_arg!();
diff --git a/gd/rust/linux/client/src/dbus_iface.rs b/gd/rust/linux/client/src/dbus_iface.rs
new file mode 100644
index 0000000..54e2772
--- /dev/null
+++ b/gd/rust/linux/client/src/dbus_iface.rs
@@ -0,0 +1,150 @@
+//! D-Bus proxy implementations of the APIs.
+
+use btstack::bluetooth::{BluetoothDevice, BluetoothTransport, IBluetooth, IBluetoothCallback};
+use btstack::RPCProxy;
+
+use dbus::arg::{AppendAll, RefArg};
+use dbus::nonblock::SyncConnection;
+
+use dbus_crossroads::Crossroads;
+
+use dbus_projection::{impl_dbus_arg_enum, DisconnectWatcher};
+
+use dbus_macros::{dbus_method, dbus_propmap, generate_dbus_exporter};
+
+use num_traits::{FromPrimitive, ToPrimitive};
+
+use std::sync::{Arc, Mutex};
+
+use crate::dbus_arg::{DBusArg, DBusArgError, RefArgToRust};
+
+impl_dbus_arg_enum!(BluetoothTransport);
+
+#[dbus_propmap(BluetoothDevice)]
+pub struct BluetoothDeviceDBus {
+ address: String,
+}
+
+pub(crate) struct BluetoothDBus {
+ conn: Arc<SyncConnection>,
+ cr: Arc<Mutex<Crossroads>>,
+}
+
+impl BluetoothDBus {
+ pub(crate) fn new(conn: Arc<SyncConnection>, cr: Arc<Mutex<Crossroads>>) -> BluetoothDBus {
+ BluetoothDBus { conn: conn.clone(), cr: cr }
+ }
+
+ fn create_proxy(&self) -> dbus::nonblock::Proxy<Arc<SyncConnection>> {
+ let conn = self.conn.clone();
+ // TODO: Adapter path should have hci number, e.g. /org/chromium/bluetooth/adapter/hci0.
+ dbus::nonblock::Proxy::new(
+ "org.chromium.bluetooth",
+ "/org/chromium/bluetooth/adapter",
+ std::time::Duration::from_secs(2),
+ conn,
+ )
+ }
+
+ fn method<A: AppendAll, T: 'static + dbus::arg::Arg + for<'z> dbus::arg::Get<'z>>(
+ &self,
+ member: &str,
+ args: A,
+ ) -> T {
+ let proxy = self.create_proxy();
+ // We know that all APIs return immediately, so we can block on it for simplicity.
+ let (ret,): (T,) = futures::executor::block_on(async {
+ proxy.method_call("org.chromium.bluetooth.Bluetooth", member, args).await
+ })
+ .unwrap();
+
+ return ret;
+ }
+
+ fn method_noreturn<A: AppendAll>(&self, member: &str, args: A) {
+ let proxy = self.create_proxy();
+ // We know that all APIs return immediately, so we can block on it for simplicity.
+ let _: () = futures::executor::block_on(async {
+ proxy.method_call("org.chromium.bluetooth.Bluetooth", member, args).await
+ })
+ .unwrap();
+ }
+}
+
+#[allow(dead_code)]
+struct IBluetoothCallbackDBus {}
+
+impl RPCProxy for IBluetoothCallbackDBus {
+ // Dummy implementations just to satisfy impl RPCProxy requirements.
+ fn register_disconnect(&mut self, _f: Box<dyn Fn() + Send>) {}
+ fn get_object_id(&self) -> String {
+ String::from("")
+ }
+}
+
+#[generate_dbus_exporter(
+ export_bluetooth_callback_dbus_obj,
+ "org.chromium.bluetooth.BluetoothCallback"
+)]
+impl IBluetoothCallback for IBluetoothCallbackDBus {
+ #[dbus_method("OnBluetoothStateChanged")]
+ fn on_bluetooth_state_changed(&self, prev_state: u32, new_state: u32) {}
+
+ #[dbus_method("OnBluetoothAddressChanged")]
+ fn on_bluetooth_address_changed(&self, addr: String) {}
+
+ #[dbus_method("OnDeviceFound")]
+ fn on_device_found(&self, remote_device: BluetoothDevice) {}
+
+ #[dbus_method("OnDiscoveringChanged")]
+ fn on_discovering_changed(&self, discovering: bool) {}
+}
+
+// TODO: These are boilerplate codes, consider creating a macro to generate.
+impl IBluetooth for BluetoothDBus {
+ fn register_callback(&mut self, callback: Box<dyn IBluetoothCallback + Send>) {
+ let path_string = callback.get_object_id();
+ let path = dbus::Path::new(path_string.clone()).unwrap();
+ export_bluetooth_callback_dbus_obj(
+ path_string,
+ self.conn.clone(),
+ &mut self.cr.lock().unwrap(),
+ Arc::new(Mutex::new(callback)),
+ Arc::new(Mutex::new(DisconnectWatcher::new())),
+ );
+
+ self.method_noreturn("RegisterCallback", (path,))
+ }
+
+ fn enable(&mut self) -> bool {
+ // Not implemented by server
+ true
+ }
+
+ fn disable(&mut self) -> bool {
+ // Not implemented by server
+ true
+ }
+
+ fn get_address(&self) -> String {
+ self.method("GetAddress", ())
+ }
+
+ fn start_discovery(&self) -> bool {
+ self.method("StartDiscovery", ())
+ }
+
+ fn cancel_discovery(&self) -> bool {
+ self.method("CancelDiscovery", ())
+ }
+
+ fn create_bond(&self, device: BluetoothDevice, transport: BluetoothTransport) -> bool {
+ self.method(
+ "CreateBond",
+ (
+ BluetoothDevice::to_dbus(device).unwrap(),
+ BluetoothTransport::to_dbus(transport).unwrap(),
+ ),
+ )
+ }
+}
diff --git a/gd/rust/linux/client/src/editor.rs b/gd/rust/linux/client/src/editor.rs
new file mode 100644
index 0000000..b7ede2c
--- /dev/null
+++ b/gd/rust/linux/client/src/editor.rs
@@ -0,0 +1,66 @@
+//! Tools to work with rustyline readline() library.
+
+use futures::Future;
+
+use rustyline::{Config, Editor};
+
+use std::pin::Pin;
+use std::sync::{Arc, Mutex};
+use std::task::{Context, Poll};
+
+use crate::console_blue;
+
+/// A future that does async readline().
+///
+/// async readline() is implemented by spawning a thread for the blocking readline(). While this
+/// readline() thread is blocked, it yields back to executor and will wake the executor up when the
+/// blocked thread has proceeded and got input from readline().
+pub struct AsyncReadline {
+ rl: Arc<Mutex<Editor<()>>>,
+ result: Arc<Mutex<Option<rustyline::Result<String>>>>,
+}
+
+impl Future for AsyncReadline {
+ type Output = rustyline::Result<String>;
+
+ fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<rustyline::Result<String>> {
+ let option = self.result.lock().unwrap().take();
+ if let Some(res) = option {
+ return Poll::Ready(res);
+ }
+
+ let waker = cx.waker().clone();
+ let result_clone = self.result.clone();
+ let rl = self.rl.clone();
+ std::thread::spawn(move || {
+ let readline = rl.lock().unwrap().readline(console_blue!("bluetooth> "));
+ *result_clone.lock().unwrap() = Some(readline);
+ waker.wake();
+ });
+
+ Poll::Pending
+ }
+}
+
+/// Wrapper of rustyline editor that supports async readline().
+pub struct AsyncEditor {
+ rl: Arc<Mutex<Editor<()>>>,
+}
+
+impl AsyncEditor {
+ /// Creates new async rustyline editor.
+ pub fn new() -> AsyncEditor {
+ let builder = Config::builder().auto_add_history(true).history_ignore_dups(true);
+ let config = builder.build();
+ let rl = rustyline::Editor::<()>::with_config(config);
+ AsyncEditor { rl: Arc::new(Mutex::new(rl)) }
+ }
+
+ /// Does async readline().
+ ///
+ /// Returns a future that will do the readline() when await-ed. This does not block the thread
+ /// but rather yields to the executor while waiting for a command to be entered.
+ pub fn readline(&self) -> AsyncReadline {
+ AsyncReadline { rl: self.rl.clone(), result: Arc::new(Mutex::new(None)) }
+ }
+}
diff --git a/gd/rust/linux/client/src/main.rs b/gd/rust/linux/client/src/main.rs
new file mode 100644
index 0000000..c3fc15b
--- /dev/null
+++ b/gd/rust/linux/client/src/main.rs
@@ -0,0 +1,141 @@
+use bt_topshim::topstack;
+
+use btstack::bluetooth::{BluetoothDevice, IBluetooth, IBluetoothCallback};
+use btstack::RPCProxy;
+
+use dbus::channel::MatchingReceiver;
+
+use dbus::message::MatchRule;
+
+use dbus::nonblock::SyncConnection;
+
+use std::sync::{Arc, Mutex};
+
+use crate::command_handler::CommandHandler;
+use crate::dbus_iface::BluetoothDBus;
+use crate::editor::AsyncEditor;
+
+use dbus_crossroads::Crossroads;
+
+mod command_handler;
+mod console;
+mod dbus_arg;
+mod dbus_iface;
+mod editor;
+
+struct BtCallback {
+ objpath: String,
+}
+
+impl IBluetoothCallback for BtCallback {
+ fn on_bluetooth_state_changed(&self, prev_state: u32, new_state: u32) {
+ print_info!("Adapter state changed from {} to {}", prev_state, new_state);
+ }
+
+ fn on_bluetooth_address_changed(&self, addr: String) {
+ print_info!("Address changed to {}", addr);
+ }
+
+ fn on_device_found(&self, remote_device: BluetoothDevice) {
+ print_info!("Found device: {:?}", remote_device);
+ }
+
+ fn on_discovering_changed(&self, discovering: bool) {
+ print_info!("Discovering: {}", discovering);
+ }
+}
+
+impl RPCProxy for BtCallback {
+ fn register_disconnect(&mut self, _f: Box<dyn Fn() + Send>) {}
+
+ fn get_object_id(&self) -> String {
+ self.objpath.clone()
+ }
+}
+
+struct API<T: IBluetooth> {
+ bluetooth: Arc<Mutex<Box<T>>>,
+}
+
+// This creates the API implementations over D-Bus.
+fn create_api_dbus(conn: Arc<SyncConnection>, cr: Arc<Mutex<Crossroads>>) -> API<BluetoothDBus> {
+ let bluetooth = Arc::new(Mutex::new(Box::new(BluetoothDBus::new(conn.clone(), cr))));
+
+ API { bluetooth }
+}
+
+/// Runs a command line program that interacts with a Bluetooth stack.
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ // TODO: Process command line arguments.
+
+ topstack::get_runtime().block_on(async move {
+ // Connect to D-Bus system bus.
+ let (resource, conn) = dbus_tokio::connection::new_system_sync()?;
+
+ // The `resource` is a task that should be spawned onto a tokio compatible
+ // reactor ASAP. If the resource ever finishes, we lost connection to D-Bus.
+ topstack::get_runtime().spawn(async {
+ let err = resource.await;
+ panic!("Lost connection to D-Bus: {}", err);
+ });
+
+ // Sets up Crossroads for receiving callbacks.
+ let cr = Arc::new(Mutex::new(Crossroads::new()));
+ cr.lock().unwrap().set_async_support(Some((
+ conn.clone(),
+ Box::new(|x| {
+ topstack::get_runtime().spawn(x);
+ }),
+ )));
+ let cr_clone = cr.clone();
+ conn.start_receive(
+ MatchRule::new_method_call(),
+ Box::new(move |msg, conn| {
+ cr_clone.lock().unwrap().handle_message(msg, conn).unwrap();
+ true
+ }),
+ );
+
+ let api = create_api_dbus(conn, cr);
+
+ api.bluetooth.lock().unwrap().register_callback(Box::new(BtCallback {
+ objpath: String::from("/org/chromium/bluetooth/client/bluetooth_callback"),
+ }));
+
+ let handler = CommandHandler::<BluetoothDBus>::new(api.bluetooth.clone());
+
+ let handle_cmd = move |cmd: String| match cmd.split(' ').collect::<Vec<&str>>()[0] {
+ "enable" => handler.cmd_enable(cmd),
+ "disable" => handler.cmd_disable(cmd),
+ "get_address" => handler.cmd_get_address(cmd),
+ "start_discovery" => handler.cmd_start_discovery(cmd),
+ "cancel_discovery" => handler.cmd_cancel_discovery(cmd),
+ "create_bond" => handler.cmd_create_bond(cmd),
+
+ // Ignore empty commands.
+ "" => {}
+
+ // TODO: Print help.
+ _ => print_info!("Command \"{}\" not recognized", cmd),
+ };
+
+ let editor = AsyncEditor::new();
+
+ loop {
+ let result = editor.readline().await;
+ match result {
+ Err(_err) => break,
+ Ok(line) => {
+ if line.eq("quit") {
+ break;
+ }
+ handle_cmd(line.clone());
+ }
+ }
+ }
+
+ print_info!("Client exiting");
+
+ Result::Ok(())
+ })
+}
diff --git a/gd/rust/linux/dbus_projection/Cargo.toml b/gd/rust/linux/dbus_projection/Cargo.toml
new file mode 100644
index 0000000..166d928
--- /dev/null
+++ b/gd/rust/linux/dbus_projection/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+name = "dbus_projection"
+version = "0.1.0"
+edition = "2018"
+
+[dependencies]
+dbus = "0.9.2"
diff --git a/gd/rust/linux/dbus_projection/dbus_macros/Cargo.toml b/gd/rust/linux/dbus_projection/dbus_macros/Cargo.toml
new file mode 100644
index 0000000..84585d8
--- /dev/null
+++ b/gd/rust/linux/dbus_projection/dbus_macros/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "dbus_macros"
+version = "0.1.0"
+edition = "2018"
+
+[lib]
+proc-macro = true
+
+[dependencies]
+syn = "1.0"
+quote = "1.0"
+proc-macro2 = "1.0"
diff --git a/gd/rust/linux/dbus_projection/dbus_macros/src/lib.rs b/gd/rust/linux/dbus_projection/dbus_macros/src/lib.rs
new file mode 100644
index 0000000..66925f1
--- /dev/null
+++ b/gd/rust/linux/dbus_projection/dbus_macros/src/lib.rs
@@ -0,0 +1,648 @@
+extern crate proc_macro;
+
+use quote::{format_ident, quote, ToTokens};
+
+use std::fs::File;
+use std::io::Write;
+use std::path::Path;
+
+use syn::parse::Parser;
+use syn::punctuated::Punctuated;
+use syn::token::Comma;
+use syn::{Expr, FnArg, ImplItem, ItemImpl, ItemStruct, Meta, Pat, ReturnType, Type};
+
+use crate::proc_macro::TokenStream;
+
+fn debug_output_to_file(gen: &proc_macro2::TokenStream, filename: String) {
+ let path = Path::new(filename.as_str());
+ let mut file = File::create(&path).unwrap();
+ file.write_all(gen.to_string().as_bytes()).unwrap();
+}
+
+/// Marks a method to be projected to a D-Bus method and specifies the D-Bus method name.
+#[proc_macro_attribute]
+pub fn dbus_method(_attr: TokenStream, item: TokenStream) -> TokenStream {
+ let ori_item: proc_macro2::TokenStream = item.clone().into();
+ let gen = quote! {
+ #[allow(unused_variables)]
+ #ori_item
+ };
+ gen.into()
+}
+
+/// Generates a function to export a Rust object to D-Bus.
+#[proc_macro_attribute]
+pub fn generate_dbus_exporter(attr: TokenStream, item: TokenStream) -> TokenStream {
+ let ori_item: proc_macro2::TokenStream = item.clone().into();
+
+ let args = Punctuated::<Expr, Comma>::parse_separated_nonempty.parse(attr.clone()).unwrap();
+
+ let fn_ident = if let Expr::Path(p) = &args[0] {
+ p.path.get_ident().unwrap()
+ } else {
+ panic!("function name must be specified");
+ };
+
+ let dbus_iface_name = if let Expr::Lit(lit) = &args[1] {
+ lit
+ } else {
+ panic!("D-Bus interface name must be specified");
+ };
+
+ let ast: ItemImpl = syn::parse(item.clone()).unwrap();
+ let api_iface_ident = ast.trait_.unwrap().1.to_token_stream();
+
+ let mut register_methods = quote! {};
+
+ let obj_type = quote! { std::sync::Arc<std::sync::Mutex<Box<T>>> };
+
+ for item in ast.items {
+ if let ImplItem::Method(method) = item {
+ if method.attrs.len() != 1 {
+ continue;
+ }
+
+ let attr = &method.attrs[0];
+ if !attr.path.get_ident().unwrap().to_string().eq("dbus_method") {
+ continue;
+ }
+
+ let attr_args = attr.parse_meta().unwrap();
+ let dbus_method_name = if let Meta::List(meta_list) = attr_args {
+ Some(meta_list.nested[0].clone())
+ } else {
+ None
+ };
+
+ if dbus_method_name.is_none() {
+ continue;
+ }
+
+ let method_name = method.sig.ident;
+
+ let mut arg_names = quote! {};
+ let mut method_args = quote! {};
+ let mut make_args = quote! {};
+ let mut dbus_input_vars = quote! {};
+ let mut dbus_input_types = quote! {};
+
+ for input in method.sig.inputs {
+ if let FnArg::Typed(ref typed) = input {
+ let arg_type = &typed.ty;
+ if let Pat::Ident(pat_ident) = &*typed.pat {
+ let ident = pat_ident.ident.clone();
+ let mut dbus_input_ident = ident.to_string();
+ dbus_input_ident.push_str("_");
+ let dbus_input_arg = format_ident!("{}", dbus_input_ident);
+ let ident_string = ident.to_string();
+
+ arg_names = quote! {
+ #arg_names #ident_string,
+ };
+
+ method_args = quote! {
+ #method_args #ident,
+ };
+
+ dbus_input_vars = quote! {
+ #dbus_input_vars #dbus_input_arg,
+ };
+
+ dbus_input_types = quote! {
+ #dbus_input_types
+ <#arg_type as DBusArg>::DBusType,
+ };
+
+ make_args = quote! {
+ #make_args
+ let #ident = <#arg_type as DBusArg>::from_dbus(
+ #dbus_input_arg,
+ conn_clone.clone(),
+ ctx.message().sender().unwrap().into_static(),
+ dc_watcher_clone.clone(),
+ );
+
+ if let Result::Err(e) = #ident {
+ return Err(dbus_crossroads::MethodErr::invalid_arg(
+ e.to_string().as_str()
+ ));
+ }
+
+ let #ident = #ident.unwrap();
+ };
+ }
+ }
+ }
+
+ let dbus_input_args = quote! {
+ (#dbus_input_vars): (#dbus_input_types)
+ };
+
+ let mut output_names = quote! {};
+ let mut output_type = quote! {};
+ let mut ret = quote! {Ok(())};
+ if let ReturnType::Type(_, t) = method.sig.output {
+ output_type = quote! {#t,};
+ ret = quote! {Ok((ret,))};
+ output_names = quote! { "out", };
+ }
+
+ register_methods = quote! {
+ #register_methods
+
+ let conn_clone = conn.clone();
+ let dc_watcher_clone = disconnect_watcher.clone();
+ let handle_method = move |ctx: &mut dbus_crossroads::Context,
+ obj: &mut #obj_type,
+ #dbus_input_args |
+ -> Result<(#output_type), dbus_crossroads::MethodErr> {
+ #make_args
+ let ret = obj.lock().unwrap().#method_name(#method_args);
+ #ret
+ };
+ ibuilder.method(
+ #dbus_method_name,
+ (#arg_names),
+ (#output_names),
+ handle_method,
+ );
+ };
+ }
+ }
+
+ let gen = quote! {
+ #ori_item
+
+ pub fn #fn_ident<T: 'static + #api_iface_ident + Send + ?Sized>(
+ path: String,
+ conn: std::sync::Arc<SyncConnection>,
+ cr: &mut dbus_crossroads::Crossroads,
+ obj: #obj_type,
+ disconnect_watcher: std::sync::Arc<std::sync::Mutex<dbus_projection::DisconnectWatcher>>,
+ ) {
+ fn get_iface_token<T: #api_iface_ident + Send + ?Sized>(
+ conn: std::sync::Arc<SyncConnection>,
+ cr: &mut dbus_crossroads::Crossroads,
+ disconnect_watcher: std::sync::Arc<std::sync::Mutex<dbus_projection::DisconnectWatcher>>,
+ ) -> dbus_crossroads::IfaceToken<#obj_type> {
+ cr.register(#dbus_iface_name, |ibuilder| {
+ #register_methods
+ })
+ }
+
+ let iface_token = get_iface_token(conn, cr, disconnect_watcher);
+ cr.insert(path, &[iface_token], obj);
+ }
+ };
+
+ // TODO: Have a switch to turn on/off this debug.
+ debug_output_to_file(&gen, format!("/tmp/out-{}.rs", fn_ident.to_string()));
+
+ gen.into()
+}
+
+fn copy_without_attributes(item: &TokenStream) -> TokenStream {
+ let mut ast: ItemStruct = syn::parse(item.clone()).unwrap();
+ for field in &mut ast.fields {
+ field.attrs.clear();
+ }
+
+ let gen = quote! {
+ #ast
+ };
+
+ gen.into()
+}
+
+/// Generates a DBusArg implementation to transform Rust plain structs to a D-Bus data structure.
+// TODO: Support more data types of struct fields (currently only supports integers and enums).
+#[proc_macro_attribute]
+pub fn dbus_propmap(attr: TokenStream, item: TokenStream) -> TokenStream {
+ let ori_item: proc_macro2::TokenStream = copy_without_attributes(&item).into();
+
+ let ast: ItemStruct = syn::parse(item.clone()).unwrap();
+
+ let args = Punctuated::<Expr, Comma>::parse_separated_nonempty.parse(attr.clone()).unwrap();
+ let struct_ident =
+ if let Expr::Path(p) = &args[0] { p.path.get_ident().unwrap().clone() } else { ast.ident };
+
+ let struct_str = struct_ident.to_string();
+
+ let mut make_fields = quote! {};
+ let mut field_idents = quote! {};
+
+ let mut insert_map_fields = quote! {};
+ for field in ast.fields {
+ let field_ident = field.ident;
+
+ if field_ident.is_none() {
+ continue;
+ }
+
+ let field_str = field_ident.as_ref().unwrap().clone().to_string();
+
+ let field_type_str = if let Type::Path(t) = field.ty {
+ t.path.get_ident().unwrap().to_string()
+ } else {
+ String::from("")
+ };
+
+ let field_type_ident = format_ident!("{}", field_type_str);
+
+ field_idents = quote! {
+ #field_idents #field_ident,
+ };
+
+ let make_field = quote! {
+ match #field_ident.arg_type() {
+ dbus::arg::ArgType::Variant => {}
+ _ => {
+ return Err(Box::new(DBusArgError::new(String::from(format!(
+ "{}.{} must be a variant",
+ #struct_str, #field_str
+ )))));
+ }
+ };
+ let #field_ident = <<#field_type_ident as DBusArg>::DBusType as RefArgToRust>::ref_arg_to_rust(
+ #field_ident,
+ format!("{}.{}", #struct_str, #field_str),
+ )?;
+ let #field_ident = #field_type_ident::from_dbus(
+ #field_ident,
+ conn__.clone(),
+ remote__.clone(),
+ disconnect_watcher__.clone(),
+ )?;
+ };
+
+ make_fields = quote! {
+ #make_fields
+
+ let #field_ident = match data__.get(#field_str) {
+ Some(data) => data,
+ None => {
+ return Err(Box::new(DBusArgError::new(String::from(format!(
+ "{}.{} is required",
+ #struct_str, #field_str
+ )))));
+ }
+ };
+ #make_field
+ };
+
+ insert_map_fields = quote! {
+ #insert_map_fields
+ let field_data__ = DBusArg::to_dbus(data__.#field_ident)?;
+ map__.insert(String::from(#field_str), dbus::arg::Variant(Box::new(field_data__)));
+ };
+ }
+
+ let gen = quote! {
+ #[allow(dead_code)]
+ #ori_item
+
+ impl DBusArg for #struct_ident {
+ type DBusType = dbus::arg::PropMap;
+
+ fn from_dbus(
+ data__: dbus::arg::PropMap,
+ conn__: std::sync::Arc<SyncConnection>,
+ remote__: dbus::strings::BusName<'static>,
+ disconnect_watcher__: std::sync::Arc<std::sync::Mutex<dbus_projection::DisconnectWatcher>>,
+ ) -> Result<#struct_ident, Box<dyn std::error::Error>> {
+ #make_fields
+
+ return Ok(#struct_ident {
+ #field_idents
+ ..Default::default()
+ });
+ }
+
+ fn to_dbus(data__: #struct_ident) -> Result<dbus::arg::PropMap, Box<dyn std::error::Error>> {
+ let mut map__: dbus::arg::PropMap = std::collections::HashMap::new();
+ #insert_map_fields
+ return Ok(map__);
+ }
+ }
+ };
+
+ // TODO: Have a switch to turn this debug off/on.
+ debug_output_to_file(&gen, format!("/tmp/out-{}.rs", struct_ident.to_string()));
+
+ gen.into()
+}
+
+/// Generates a DBusArg implementation of a Remote RPC proxy object.
+#[proc_macro_attribute]
+pub fn dbus_proxy_obj(attr: TokenStream, item: TokenStream) -> TokenStream {
+ let ori_item: proc_macro2::TokenStream = item.clone().into();
+
+ let args = Punctuated::<Expr, Comma>::parse_separated_nonempty.parse(attr.clone()).unwrap();
+
+ let struct_ident = if let Expr::Path(p) = &args[0] {
+ p.path.get_ident().unwrap()
+ } else {
+ panic!("struct name must be specified");
+ };
+
+ let dbus_iface_name = if let Expr::Lit(lit) = &args[1] {
+ lit
+ } else {
+ panic!("D-Bus interface name must be specified");
+ };
+
+ let mut method_impls = quote! {};
+
+ let ast: ItemImpl = syn::parse(item.clone()).unwrap();
+ let self_ty = ast.self_ty;
+ let trait_ = ast.trait_.unwrap().1;
+
+ for item in ast.items {
+ if let ImplItem::Method(method) = item {
+ if method.attrs.len() != 1 {
+ continue;
+ }
+
+ let attr = &method.attrs[0];
+ if !attr.path.get_ident().unwrap().to_string().eq("dbus_method") {
+ continue;
+ }
+
+ let attr_args = attr.parse_meta().unwrap();
+ let dbus_method_name = if let Meta::List(meta_list) = attr_args {
+ Some(meta_list.nested[0].clone())
+ } else {
+ None
+ };
+
+ if dbus_method_name.is_none() {
+ continue;
+ }
+
+ let method_sig = method.sig.clone();
+
+ let mut method_args = quote! {};
+
+ for input in method.sig.inputs {
+ if let FnArg::Typed(ref typed) = input {
+ if let Pat::Ident(pat_ident) = &*typed.pat {
+ let ident = pat_ident.ident.clone();
+
+ method_args = quote! {
+ #method_args DBusArg::to_dbus(#ident).unwrap(),
+ };
+ }
+ }
+ }
+
+ method_impls = quote! {
+ #method_impls
+ #[allow(unused_variables)]
+ #method_sig {
+ let remote__ = self.remote.clone();
+ let objpath__ = self.objpath.clone();
+ let conn__ = self.conn.clone();
+ bt_topshim::topstack::get_runtime().spawn(async move {
+ let proxy = dbus::nonblock::Proxy::new(
+ remote__,
+ objpath__,
+ std::time::Duration::from_secs(2),
+ conn__,
+ );
+ let future: dbus::nonblock::MethodReply<()> = proxy.method_call(
+ #dbus_iface_name,
+ #dbus_method_name,
+ (#method_args),
+ );
+ let _result = future.await;
+ });
+ }
+ };
+ }
+ }
+
+ let gen = quote! {
+ #ori_item
+
+ impl RPCProxy for #self_ty {
+ fn register_disconnect(&mut self, _disconnect_callback: Box<dyn Fn() + Send>) {}
+ fn get_object_id(&self) -> String {
+ String::from("")
+ }
+ }
+
+ struct #struct_ident {
+ conn: std::sync::Arc<SyncConnection>,
+ remote: dbus::strings::BusName<'static>,
+ objpath: Path<'static>,
+ disconnect_watcher: std::sync::Arc<std::sync::Mutex<DisconnectWatcher>>,
+ }
+
+ impl #trait_ for #struct_ident {
+ #method_impls
+ }
+
+ impl RPCProxy for #struct_ident {
+ fn register_disconnect(&mut self, disconnect_callback: Box<dyn Fn() + Send>) {
+ self.disconnect_watcher.lock().unwrap().add(self.remote.clone(), disconnect_callback);
+ }
+
+ fn get_object_id(&self) -> String {
+ self.objpath.to_string().clone()
+ }
+ }
+
+ impl DBusArg for Box<dyn #trait_ + Send> {
+ type DBusType = Path<'static>;
+
+ fn from_dbus(
+ objpath__: Path<'static>,
+ conn__: std::sync::Arc<SyncConnection>,
+ remote__: dbus::strings::BusName<'static>,
+ disconnect_watcher__: std::sync::Arc<std::sync::Mutex<DisconnectWatcher>>,
+ ) -> Result<Box<dyn #trait_ + Send>, Box<dyn std::error::Error>> {
+ Ok(Box::new(#struct_ident {
+ conn: conn__,
+ remote: remote__,
+ objpath: objpath__,
+ disconnect_watcher: disconnect_watcher__,
+ }))
+ }
+
+ fn to_dbus(_data: Box<dyn #trait_ + Send>) -> Result<Path<'static>, Box<dyn std::error::Error>> {
+ // This impl represents a remote DBus object, so `to_dbus` does not make sense.
+ panic!("not implemented");
+ }
+ }
+ };
+
+ // TODO: Have a switch to turn this debug off/on.
+ debug_output_to_file(&gen, format!("/tmp/out-{}.rs", struct_ident.to_string()));
+
+ gen.into()
+}
+
+/// Generates the definition of `DBusArg` trait required for D-Bus projection.
+///
+/// Due to Rust orphan rule, `DBusArg` trait needs to be defined locally in the crate that wants to
+/// use D-Bus projection. Providing `DBusArg` as a public trait won't let other crates implement
+/// it for structs defined in foreign crates. As a workaround, this macro is provided to generate
+/// `DBusArg` trait definition.
+#[proc_macro]
+pub fn generate_dbus_arg(_item: TokenStream) -> TokenStream {
+ let gen = quote! {
+ use dbus::arg::PropMap;
+ use dbus::nonblock::SyncConnection;
+ use dbus::strings::BusName;
+ use dbus_projection::DisconnectWatcher;
+
+ use std::error::Error;
+ use std::fmt;
+ use std::sync::{Arc, Mutex};
+
+ #[derive(Debug)]
+ pub(crate) struct DBusArgError {
+ message: String,
+ }
+
+ impl DBusArgError {
+ pub fn new(message: String) -> DBusArgError {
+ DBusArgError { message }
+ }
+ }
+
+ impl fmt::Display for DBusArgError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}", self.message)
+ }
+ }
+
+ impl Error for DBusArgError {}
+
+ pub(crate) trait RefArgToRust {
+ type RustType;
+ fn ref_arg_to_rust<U: 'static + dbus::arg::RefArg + ?Sized>(
+ arg: &U,
+ name: String,
+ ) -> Result<Self::RustType, Box<dyn Error>>;
+ }
+
+ impl<T: 'static + Clone + DirectDBus> RefArgToRust for T {
+ type RustType = T;
+ fn ref_arg_to_rust<U: 'static + dbus::arg::RefArg + ?Sized>(
+ arg: &U,
+ name: String,
+ ) -> Result<Self::RustType, Box<dyn Error>> {
+ let arg = arg.as_static_inner(0).unwrap();
+ let any = arg.as_any();
+ if !any.is::<<Self as DBusArg>::DBusType>() {
+ return Err(Box::new(DBusArgError::new(String::from(format!(
+ "{} type does not match: expected {}, found {}",
+ name,
+ std::any::type_name::<<Self as DBusArg>::DBusType>(),
+ arg.arg_type().as_str(),
+ )))));
+ }
+ let arg = (*any.downcast_ref::<<Self as DBusArg>::DBusType>().unwrap()).clone();
+ return Ok(arg);
+ }
+ }
+
+ impl RefArgToRust for dbus::arg::PropMap {
+ type RustType = dbus::arg::PropMap;
+ fn ref_arg_to_rust<U: 'static + dbus::arg::RefArg + ?Sized>(
+ arg: &U,
+ _name: String,
+ ) -> Result<Self::RustType, Box<dyn Error>> {
+ let mut map: dbus::arg::PropMap = std::collections::HashMap::new();
+ let mut outer_iter = arg.as_iter().unwrap();
+ let mut iter = outer_iter.next().unwrap().as_iter().unwrap();
+ let mut key = iter.next();
+ let mut val = iter.next();
+ while !key.is_none() && !val.is_none() {
+ let k = key.unwrap().as_str().unwrap().to_string();
+ let v = dbus::arg::Variant(val.unwrap().box_clone());
+ map.insert(k, v);
+ key = iter.next();
+ val = iter.next();
+ }
+ return Ok(map);
+ }
+ }
+
+ pub(crate) trait DBusArg {
+ type DBusType;
+
+ fn from_dbus(
+ x: Self::DBusType,
+ conn: Arc<SyncConnection>,
+ remote: BusName<'static>,
+ disconnect_watcher: Arc<Mutex<DisconnectWatcher>>,
+ ) -> Result<Self, Box<dyn Error>>
+ where
+ Self: Sized;
+
+ fn to_dbus(x: Self) -> Result<Self::DBusType, Box<dyn Error>>;
+ }
+
+ // Types that implement dbus::arg::Append do not need any conversion.
+ pub(crate) trait DirectDBus {}
+ impl DirectDBus for bool {}
+ impl DirectDBus for i32 {}
+ impl DirectDBus for u32 {}
+ impl DirectDBus for String {}
+ impl<T: DirectDBus> DBusArg for T {
+ type DBusType = T;
+
+ fn from_dbus(
+ data: T,
+ _conn: Arc<SyncConnection>,
+ _remote: BusName<'static>,
+ _disconnect_watcher: Arc<Mutex<DisconnectWatcher>>,
+ ) -> Result<T, Box<dyn Error>> {
+ return Ok(data);
+ }
+
+ fn to_dbus(data: T) -> Result<T, Box<dyn Error>> {
+ return Ok(data);
+ }
+ }
+
+ impl<T: DBusArg> DBusArg for Vec<T> {
+ type DBusType = Vec<T::DBusType>;
+
+ fn from_dbus(
+ data: Vec<T::DBusType>,
+ conn: Arc<SyncConnection>,
+ remote: BusName<'static>,
+ disconnect_watcher: Arc<Mutex<DisconnectWatcher>>,
+ ) -> Result<Vec<T>, Box<dyn Error>> {
+ let mut list: Vec<T> = vec![];
+ for prop in data {
+ let t = T::from_dbus(
+ prop,
+ conn.clone(),
+ remote.clone(),
+ disconnect_watcher.clone(),
+ )?;
+ list.push(t);
+ }
+ Ok(list)
+ }
+
+ fn to_dbus(data: Vec<T>) -> Result<Vec<T::DBusType>, Box<dyn Error>> {
+ let mut list: Vec<T::DBusType> = vec![];
+ for item in data {
+ let t = T::to_dbus(item)?;
+ list.push(t);
+ }
+ Ok(list)
+ }
+ }
+ };
+
+ // TODO: Have a switch to turn this debug off/on.
+ debug_output_to_file(&gen, format!("/tmp/out-generate_dbus_arg.rs"));
+
+ gen.into()
+}
diff --git a/gd/rust/linux/dbus_projection/src/lib.rs b/gd/rust/linux/dbus_projection/src/lib.rs
new file mode 100644
index 0000000..8111fc8
--- /dev/null
+++ b/gd/rust/linux/dbus_projection/src/lib.rs
@@ -0,0 +1,102 @@
+//! This crate provides tools to automatically project generic API to D-Bus RPC.
+//!
+//! For D-Bus projection to work automatically, the API needs to follow certain restrictions.
+
+use dbus::channel::MatchingReceiver;
+use dbus::message::MatchRule;
+use dbus::nonblock::SyncConnection;
+use dbus::strings::BusName;
+
+use std::collections::HashMap;
+use std::sync::{Arc, Mutex};
+
+/// A D-Bus "NameOwnerChanged" handler that continuously monitors client disconnects.
+pub struct DisconnectWatcher {
+ callbacks: Arc<Mutex<HashMap<BusName<'static>, Vec<Box<dyn Fn() + Send>>>>>,
+}
+
+impl DisconnectWatcher {
+ /// Creates a new DisconnectWatcher with empty callbacks.
+ pub fn new() -> DisconnectWatcher {
+ DisconnectWatcher { callbacks: Arc::new(Mutex::new(HashMap::new())) }
+ }
+}
+
+impl DisconnectWatcher {
+ /// Adds a client address to be monitored for disconnect events.
+ pub fn add(&mut self, address: BusName<'static>, callback: Box<dyn Fn() + Send>) {
+ if !self.callbacks.lock().unwrap().contains_key(&address) {
+ self.callbacks.lock().unwrap().insert(address.clone(), vec![]);
+ }
+
+ (*self.callbacks.lock().unwrap().get_mut(&address).unwrap()).push(callback);
+ }
+
+ /// Sets up the D-Bus handler that monitors client disconnects.
+ pub async fn setup_watch(&mut self, conn: Arc<SyncConnection>) {
+ let mr = MatchRule::new_signal("org.freedesktop.DBus", "NameOwnerChanged");
+
+ conn.add_match_no_cb(&mr.match_str()).await.unwrap();
+ let callbacks_map = self.callbacks.clone();
+ conn.start_receive(
+ mr,
+ Box::new(move |msg, _conn| {
+ // The args are "address", "old address", "new address".
+ // https://dbus.freedesktop.org/doc/dbus-specification.html#bus-messages-name-owner-changed
+ let (addr, old, new) = msg.get3::<String, String, String>();
+
+ if addr.is_none() || old.is_none() || new.is_none() {
+ return true;
+ }
+
+ if old.unwrap().eq("") || !new.unwrap().eq("") {
+ return true;
+ }
+
+ // If old address exists but new address is empty, that means that client is
+ // disconnected. So call the registered callbacks to be notified of this client
+ // disconnect.
+ let addr = BusName::new(addr.unwrap()).unwrap().into_static();
+ if !callbacks_map.lock().unwrap().contains_key(&addr) {
+ return true;
+ }
+
+ for callback in &callbacks_map.lock().unwrap()[&addr] {
+ callback();
+ }
+
+ callbacks_map.lock().unwrap().remove(&addr);
+
+ true
+ }),
+ );
+ }
+}
+
+#[macro_export]
+macro_rules! impl_dbus_arg_enum {
+ ($enum_type:ty) => {
+ impl DBusArg for $enum_type {
+ type DBusType = i32;
+ fn from_dbus(
+ data: i32,
+ _conn: Arc<SyncConnection>,
+ _remote: dbus::strings::BusName<'static>,
+ _disconnect_watcher: Arc<std::sync::Mutex<dbus_projection::DisconnectWatcher>>,
+ ) -> Result<$enum_type, Box<dyn std::error::Error>> {
+ match <$enum_type>::from_i32(data) {
+ Some(x) => Ok(x),
+ None => Err(Box::new(DBusArgError::new(String::from(format!(
+ "error converting {} to {}",
+ data,
+ stringify!($enum_type)
+ ))))),
+ }
+ }
+
+ fn to_dbus(data: $enum_type) -> Result<i32, Box<dyn std::error::Error>> {
+ return Ok(data.to_i32().unwrap());
+ }
+ }
+ };
+}
diff --git a/gd/rust/linux/mgmt/Cargo.toml b/gd/rust/linux/mgmt/Cargo.toml
new file mode 100644
index 0000000..4b3128b
--- /dev/null
+++ b/gd/rust/linux/mgmt/Cargo.toml
@@ -0,0 +1,25 @@
+[package]
+name = "manager_service"
+version = "0.0.1"
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+
+# bt deps
+bt_common = { path = "../../common" }
+
+# external deps
+dbus = "0.9.2"
+dbus-tokio = "0.7.3"
+dbus-crossroads = "0.3.0"
+inotify = "*"
+log = "0.4.14"
+nix = "*"
+regex = "1.5"
+serde_json = "1.0"
+tokio = { version = "1.0", features = ["fs", "macros", "rt-multi-thread", "sync"] }
+
+[[bin]]
+name = "btmanagerd"
diff --git a/gd/rust/linux/mgmt/src/bin/btmanagerd/config_util.rs b/gd/rust/linux/mgmt/src/bin/btmanagerd/config_util.rs
new file mode 100644
index 0000000..130e974
--- /dev/null
+++ b/gd/rust/linux/mgmt/src/bin/btmanagerd/config_util.rs
@@ -0,0 +1,182 @@
+use serde_json::{Map, Value};
+
+// Directory for Bluetooth hci devices
+pub const HCI_DEVICES_DIR: &str = "/sys/class/bluetooth";
+
+// File to store the Bluetooth daemon to use (bluez or floss)
+const BLUETOOTH_DAEMON_CURRENT: &str = "/var/lib/misc/bluetooth-daemon.current";
+
+// File to store the config for BluetoothManager
+const BTMANAGERD_CONF: &str = "/var/lib/bluetooth/btmanagerd.json";
+
+pub fn is_floss_enabled() -> bool {
+ match std::fs::read(BLUETOOTH_DAEMON_CURRENT) {
+ Ok(v) => {
+ let content = std::str::from_utf8(&v);
+ match content {
+ Ok(version) => version.contains("floss"),
+ Err(_) => false,
+ }
+ }
+ Err(_) => false,
+ }
+}
+
+pub fn write_floss_enabled(enabled: bool) -> bool {
+ std::fs::write(
+ BLUETOOTH_DAEMON_CURRENT,
+ match enabled {
+ true => "floss",
+ _ => "bluez",
+ },
+ )
+ .is_ok()
+}
+
+pub fn read_config() -> std::io::Result<String> {
+ std::fs::read_to_string(BTMANAGERD_CONF)
+}
+
+/// Returns whether hci N is enabled in config; defaults to true.
+pub fn is_hci_n_enabled(n: i32) -> bool {
+ match read_config().ok().and_then(|config| is_hci_n_enabled_internal(config, n)) {
+ Some(v) => v,
+ _ => true,
+ }
+}
+
+fn is_hci_n_enabled_internal(config: String, n: i32) -> Option<bool> {
+ serde_json::from_str::<Value>(config.as_str())
+ .ok()?
+ .get(format!("hci{}", n))?
+ .as_object()?
+ .get("enabled")?
+ .as_bool()
+}
+
+// When we initialize BluetoothManager, we need to make sure the file is a well-formatted json.
+pub fn fix_config_file_format() -> bool {
+ match read_config() {
+ Ok(s) => match serde_json::from_str::<Value>(s.as_str()) {
+ Ok(_) => true,
+ _ => std::fs::write(BTMANAGERD_CONF, "{}").is_ok(),
+ },
+ _ => std::fs::write(BTMANAGERD_CONF, "{}").is_ok(),
+ }
+}
+
+pub fn modify_hci_n_enabled(n: i32, enabled: bool) -> bool {
+ if !fix_config_file_format() {
+ false
+ } else {
+ match read_config()
+ .ok()
+ .and_then(|config| modify_hci_n_enabled_internal(config, n, enabled))
+ {
+ Some(s) => std::fs::write(BTMANAGERD_CONF, s).is_ok(),
+ _ => false,
+ }
+ }
+}
+
+fn modify_hci_n_enabled_internal(config: String, n: i32, enabled: bool) -> Option<String> {
+ let hci_interface = format!("hci{}", n);
+ let mut o = serde_json::from_str::<Value>(config.as_str()).ok()?;
+ match o.get_mut(hci_interface.clone()) {
+ Some(section) => {
+ section.as_object_mut()?.insert("enabled".to_string(), Value::Bool(enabled));
+ serde_json::ser::to_string_pretty(&o).ok()
+ }
+ _ => {
+ let mut entry_map = Map::new();
+ entry_map.insert("enabled".to_string(), Value::Bool(enabled));
+ o.as_object_mut()?.insert(hci_interface, Value::Object(entry_map));
+ serde_json::ser::to_string_pretty(&o).ok()
+ }
+ }
+}
+
+pub fn list_hci_devices() -> Vec<i32> {
+ hci_devices_string_to_int(list_hci_devices_string())
+}
+
+fn list_hci_devices_string() -> Vec<String> {
+ match std::fs::read_dir(HCI_DEVICES_DIR) {
+ Ok(entries) => entries
+ .map(|e| e.unwrap().path().file_name().unwrap().to_str().unwrap().to_string())
+ .collect::<Vec<_>>(),
+ _ => Vec::new(),
+ }
+}
+
+fn hci_devices_string_to_int(devices: Vec<String>) -> Vec<i32> {
+ devices
+ .into_iter()
+ .filter_map(|e| if e.starts_with("hci") { e[3..].parse::<i32>().ok() } else { None })
+ .collect()
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ fn is_hci_n_enabled_internal_wrapper(config: String, n: i32) -> bool {
+ is_hci_n_enabled_internal(config, n).or(Some(true)).unwrap()
+ }
+
+ #[test]
+ fn parse_hci0_enabled() {
+ assert_eq!(
+ is_hci_n_enabled_internal_wrapper("{\"hci0\":\n{\"enabled\": true}}".to_string(), 0),
+ true
+ );
+ }
+
+ #[test]
+ fn modify_hci0_enabled() {
+ let modified_string =
+ modify_hci_n_enabled_internal("{\"hci0\":\n{\"enabled\": false}}".to_string(), 0, true)
+ .unwrap();
+ assert_eq!(is_hci_n_enabled_internal_wrapper(modified_string, 0), true);
+ }
+
+ #[test]
+ fn modify_hci0_enabled_from_empty() {
+ let modified_string = modify_hci_n_enabled_internal("{}".to_string(), 0, true).unwrap();
+ assert_eq!(is_hci_n_enabled_internal_wrapper(modified_string, 0), true);
+ }
+
+ #[test]
+ fn parse_hci0_not_enabled() {
+ assert_eq!(
+ is_hci_n_enabled_internal_wrapper("{\"hci0\":\n{\"enabled\": false}}".to_string(), 0),
+ false
+ );
+ }
+
+ #[test]
+ fn parse_hci1_not_present() {
+ assert_eq!(
+ is_hci_n_enabled_internal_wrapper("{\"hci0\":\n{\"enabled\": true}}".to_string(), 1),
+ true
+ );
+ }
+
+ #[test]
+ fn test_hci_devices_string_to_int_none() {
+ assert_eq!(hci_devices_string_to_int(vec!["somethingelse".to_string()]), Vec::<i32>::new());
+ }
+
+ #[test]
+ fn test_hci_devices_string_to_int_one() {
+ assert_eq!(hci_devices_string_to_int(vec!["hci0".to_string()]), vec![0]);
+ }
+
+ #[test]
+ fn test_hci_devices_string_to_int_two() {
+ assert_eq!(
+ hci_devices_string_to_int(vec!["hci0".to_string(), "hci1".to_string()]),
+ vec![0, 1]
+ );
+ }
+}
diff --git a/gd/rust/linux/mgmt/src/bin/btmanagerd/dbus_callback_util.rs b/gd/rust/linux/mgmt/src/bin/btmanagerd/dbus_callback_util.rs
new file mode 100644
index 0000000..7ab45db
--- /dev/null
+++ b/gd/rust/linux/mgmt/src/bin/btmanagerd/dbus_callback_util.rs
@@ -0,0 +1,71 @@
+use dbus::nonblock::{Proxy, SyncConnection};
+use std::sync::Arc;
+use std::time::Duration;
+use tokio::sync::Mutex;
+
+#[derive(Clone)]
+pub struct DbusCallbackUtil {
+ dbus_connection: Arc<SyncConnection>,
+ state_change_observers: Arc<Mutex<Vec<String>>>,
+ hci_device_change_observer: Arc<Mutex<Vec<String>>>,
+}
+
+impl DbusCallbackUtil {
+ pub fn new(
+ dbus_connection: Arc<SyncConnection>,
+ state_change_observers: Arc<Mutex<Vec<String>>>,
+ hci_device_change_observer: Arc<Mutex<Vec<String>>>,
+ ) -> Self {
+ DbusCallbackUtil {
+ dbus_connection: dbus_connection,
+ state_change_observers: state_change_observers,
+ hci_device_change_observer: hci_device_change_observer,
+ }
+ }
+
+ pub async fn send_hci_device_change_callback(
+ &self,
+ hci_device: i32,
+ present: bool,
+ ) -> Result<(), Box<dyn std::error::Error>> {
+ for path in &*self.hci_device_change_observer.lock().await {
+ let proxy = Proxy::new(
+ "org.chromium.bluetooth.Manager",
+ path,
+ Duration::from_secs(2),
+ self.dbus_connection.clone(),
+ );
+ proxy
+ .method_call(
+ "org.chromium.bluetooth.Manager",
+ "HciDeviceChangeCallback",
+ (hci_device, present),
+ )
+ .await?;
+ }
+ Ok(())
+ }
+
+ pub async fn send_adapter_state_change_callback(
+ &self,
+ hci_device: i32,
+ state: i32,
+ ) -> Result<(), Box<dyn std::error::Error>> {
+ for path in &*self.state_change_observers.lock().await {
+ let proxy = Proxy::new(
+ "org.chromium.bluetooth.Manager",
+ path,
+ Duration::from_secs(2),
+ self.dbus_connection.clone(),
+ );
+ proxy
+ .method_call(
+ "org.chromium.bluetooth.Manager",
+ "AdapterStateChangeCallback",
+ (hci_device, state),
+ )
+ .await?;
+ }
+ Ok(())
+ }
+}
diff --git a/gd/rust/linux/mgmt/src/bin/btmanagerd/main.rs b/gd/rust/linux/mgmt/src/bin/btmanagerd/main.rs
new file mode 100644
index 0000000..9c9a68a
--- /dev/null
+++ b/gd/rust/linux/mgmt/src/bin/btmanagerd/main.rs
@@ -0,0 +1,289 @@
+mod config_util;
+mod dbus_callback_util;
+mod state_machine;
+
+use dbus::channel::MatchingReceiver;
+use dbus::message::MatchRule;
+use dbus::nonblock::SyncConnection;
+use dbus_crossroads::Crossroads;
+use dbus_tokio::connection;
+use log::{error, info, warn};
+use log::{Level, LevelFilter, Metadata, Record, SetLoggerError};
+use std::process::Command;
+use std::sync::atomic::{AtomicBool, Ordering};
+use std::sync::Arc;
+use tokio::sync::Mutex;
+
+struct SimpleLogger;
+
+impl log::Log for SimpleLogger {
+ fn enabled(&self, metadata: &Metadata) -> bool {
+ true || metadata.level() <= Level::Info
+ }
+
+ fn log(&self, record: &Record) {
+ if self.enabled(record.metadata()) {
+ println!("{} - {}", record.level(), record.args());
+ }
+ }
+
+ fn flush(&self) {}
+}
+
+static LOGGER: SimpleLogger = SimpleLogger;
+
+const BLUEZ_INIT_TARGET: &str = "bluetoothd";
+
+#[derive(Clone)]
+struct ManagerContext {
+ proxy: state_machine::StateMachineProxy,
+ floss_enabled: Arc<AtomicBool>,
+ dbus_connection: Arc<SyncConnection>,
+ state_change_observer: Arc<Mutex<Vec<String>>>,
+ hci_device_change_observer: Arc<Mutex<Vec<String>>>,
+}
+
+#[tokio::main]
+pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
+ log::set_logger(&LOGGER).map(|()| log::set_max_level(LevelFilter::Debug)).unwrap();
+
+ // Initialize config util
+ config_util::fix_config_file_format();
+
+ // Connect to the D-Bus system bus (this is blocking, unfortunately).
+ let (resource, conn) = connection::new_system_sync()?;
+
+ let context = state_machine::start_new_state_machine_context();
+ let proxy = context.get_proxy();
+ let state_change_observer = Arc::new(Mutex::new(Vec::new()));
+ let hci_device_change_observer = Arc::new(Mutex::new(Vec::new()));
+ let manager_context = ManagerContext {
+ proxy: proxy,
+ floss_enabled: Arc::new(AtomicBool::new(config_util::is_floss_enabled())),
+ dbus_connection: conn.clone(),
+ state_change_observer: state_change_observer.clone(),
+ hci_device_change_observer: hci_device_change_observer.clone(),
+ };
+
+ let dbus_callback_util = dbus_callback_util::DbusCallbackUtil::new(
+ conn.clone(),
+ state_change_observer.clone(),
+ hci_device_change_observer.clone(),
+ );
+
+ // The resource is a task that should be spawned onto a tokio compatible
+ // reactor ASAP. If the resource ever finishes, you lost connection to D-Bus.
+ tokio::spawn(async {
+ let err = resource.await;
+ panic!("Lost connection to D-Bus: {}", err);
+ });
+
+ // Let's request a name on the bus, so that clients can find us.
+ conn.request_name("org.chromium.bluetooth.Manager", false, true, false).await?;
+
+ // Create a new crossroads instance.
+ // The instance is configured so that introspection and properties interfaces
+ // are added by default on object path additions.
+ let mut cr = Crossroads::new();
+
+ // Enable async support for the crossroads instance.
+ cr.set_async_support(Some((
+ conn.clone(),
+ Box::new(|x| {
+ tokio::spawn(x);
+ }),
+ )));
+
+ let iface_token = cr.register("org.chromium.bluetooth.Manager", |b| {
+ b.method_with_cr_async(
+ "Start",
+ ("hci_interface",),
+ (),
+ |mut ctx, cr, (hci_interface,): (i32,)| {
+ if !config_util::modify_hci_n_enabled(hci_interface, true) {
+ error!("Config is not successfully modified");
+ }
+ let proxy = cr.data_mut::<ManagerContext>(ctx.path()).unwrap().proxy.clone();
+ async move {
+ let result = proxy.start_bluetooth(hci_interface).await;
+ match result {
+ Ok(()) => ctx.reply(Ok(())),
+ Err(_) => ctx.reply(Err(dbus_crossroads::MethodErr::failed(
+ "cannot start Bluetooth",
+ ))),
+ }
+ }
+ },
+ );
+ b.method_with_cr_async(
+ "Stop",
+ ("hci_interface",),
+ (),
+ |mut ctx, cr, (hci_interface,): (i32,)| {
+ let proxy = cr.data_mut::<ManagerContext>(ctx.path()).unwrap().proxy.clone();
+ if !config_util::modify_hci_n_enabled(hci_interface, false) {
+ error!("Config is not successfully modified");
+ }
+ async move {
+ let result = proxy.stop_bluetooth(hci_interface).await;
+ match result {
+ Ok(()) => ctx.reply(Ok(())),
+ Err(_) => ctx.reply(Err(dbus_crossroads::MethodErr::failed(
+ "cannot stop Bluetooth",
+ ))),
+ }
+ }
+ },
+ );
+ b.method_with_cr_async("GetState", (), ("result",), |mut ctx, cr, ()| {
+ let proxy = cr.data_mut::<ManagerContext>(ctx.path()).unwrap().proxy.clone();
+ async move {
+ let state = proxy.get_state().await;
+ let result = state_machine::state_to_i32(state);
+ ctx.reply(Ok((result,)))
+ }
+ });
+ // Register AdapterStateChangeCallback(int hci_device, int state) on specified object_path
+ b.method_with_cr_async(
+ "RegisterStateChangeObserver",
+ ("object_path",),
+ (),
+ |mut ctx, cr, (object_path,): (String,)| {
+ let manager_context = cr.data_mut::<ManagerContext>(ctx.path()).unwrap().clone();
+ async move {
+ manager_context.state_change_observer.lock().await.push(object_path.clone());
+ ctx.reply(Ok(()))
+ }
+ },
+ );
+ b.method_with_cr_async(
+ "UnregisterStateChangeObserver",
+ ("object_path",),
+ (),
+ |mut ctx, cr, (object_path,): (String,)| {
+ let manager_context = cr.data_mut::<ManagerContext>(ctx.path()).unwrap().clone();
+ async move {
+ let mut observers = manager_context.state_change_observer.lock().await;
+ match observers.iter().position(|x| *x == object_path) {
+ Some(index) => {
+ observers.remove(index);
+ ctx.reply(Ok(()))
+ }
+ _ => ctx.reply(Err(dbus_crossroads::MethodErr::failed(&format!(
+ "cannot unregister {}",
+ object_path
+ )))),
+ }
+ }
+ },
+ );
+ b.method_with_cr_async("GetFlossEnabled", (), ("result",), |mut ctx, cr, ()| {
+ let enabled = cr
+ .data_mut::<ManagerContext>(ctx.path())
+ .unwrap()
+ .clone()
+ .floss_enabled
+ .load(Ordering::Relaxed);
+
+ async move { ctx.reply(Ok((enabled,))) }
+ });
+ b.method_with_cr_async(
+ "SetFlossEnabled",
+ ("enabled",),
+ (),
+ |mut ctx, cr, (enabled,): (bool,)| {
+ let prev = cr
+ .data_mut::<ManagerContext>(ctx.path())
+ .unwrap()
+ .clone()
+ .floss_enabled
+ .swap(enabled, Ordering::Relaxed);
+ config_util::write_floss_enabled(enabled);
+ let proxy = cr.data_mut::<ManagerContext>(ctx.path()).unwrap().proxy.clone();
+
+ async move {
+ if prev != enabled && enabled {
+ Command::new("initctl")
+ .args(&["stop", BLUEZ_INIT_TARGET])
+ .output()
+ .expect("failed to stop bluetoothd");
+ // TODO: Implement multi-hci case
+ let default_device = config_util::list_hci_devices()[0];
+ if config_util::is_hci_n_enabled(default_device) {
+ let _ = proxy.start_bluetooth(default_device).await;
+ }
+ } else if prev != enabled {
+ // TODO: Implement multi-hci case
+ let default_device = config_util::list_hci_devices()[0];
+ let _ = proxy.stop_bluetooth(default_device).await;
+ Command::new("initctl")
+ .args(&["start", BLUEZ_INIT_TARGET])
+ .output()
+ .expect("failed to start bluetoothd");
+ }
+ ctx.reply(Ok(()))
+ }
+ },
+ );
+ b.method_with_cr_async("ListHciDevices", (), ("devices",), |mut ctx, _cr, ()| {
+ let devices = config_util::list_hci_devices();
+ async move { ctx.reply(Ok((devices,))) }
+ });
+ // Register AdapterStateChangeCallback(int hci_device, int state) on specified object_path
+ b.method_with_cr_async(
+ "RegisterHciDeviceChangeObserver",
+ ("object_path",),
+ (),
+ |mut ctx, cr, (object_path,): (String,)| {
+ let manager_context = cr.data_mut::<ManagerContext>(ctx.path()).unwrap().clone();
+ async move {
+ manager_context.hci_device_change_observer.lock().await.push(object_path);
+ ctx.reply(Ok(()))
+ }
+ },
+ );
+ b.method_with_cr_async(
+ "UnregisterHciDeviceChangeObserver",
+ ("object_path",),
+ (),
+ |mut ctx, cr, (object_path,): (String,)| {
+ let manager_context = cr.data_mut::<ManagerContext>(ctx.path()).unwrap().clone();
+ async move {
+ let mut observers = manager_context.hci_device_change_observer.lock().await;
+ match observers.iter().position(|x| *x == object_path) {
+ Some(index) => {
+ observers.remove(index);
+ ctx.reply(Ok(()))
+ }
+ _ => ctx.reply(Err(dbus_crossroads::MethodErr::failed(&format!(
+ "cannot unregister {}",
+ object_path
+ )))),
+ }
+ }
+ },
+ );
+ });
+
+ // Let's add the "/org/chromium/bluetooth/Manager" path, which implements the org.chromium.bluetooth.Manager interface,
+ // to the crossroads instance.
+ cr.insert("/org/chromium/bluetooth/Manager", &[iface_token], manager_context);
+
+ // We add the Crossroads instance to the connection so that incoming method calls will be handled.
+ conn.start_receive(
+ MatchRule::new_method_call(),
+ Box::new(move |msg, conn| {
+ cr.handle_message(msg, conn).unwrap();
+ true
+ }),
+ );
+
+ tokio::spawn(async move {
+ state_machine::mainloop(context, dbus_callback_util).await;
+ });
+
+ std::future::pending::<()>().await;
+
+ // Run forever.
+ unreachable!()
+}
diff --git a/gd/rust/linux/mgmt/src/bin/btmanagerd/state_machine.rs b/gd/rust/linux/mgmt/src/bin/btmanagerd/state_machine.rs
new file mode 100644
index 0000000..2599c27
--- /dev/null
+++ b/gd/rust/linux/mgmt/src/bin/btmanagerd/state_machine.rs
@@ -0,0 +1,687 @@
+use bt_common::time::Alarm;
+use log::{debug, error, info, warn};
+use nix::sys::signal::{self, Signal};
+use nix::unistd::Pid;
+use regex::Regex;
+use std::process::{Child, Command, Stdio};
+use std::sync::Arc;
+use std::time::Duration;
+use tokio::io::unix::AsyncFd;
+use tokio::sync::mpsc::error::SendTimeoutError;
+use tokio::sync::{mpsc, Mutex};
+
+// Directory for Bluetooth pid file
+pub const PID_DIR: &str = "/var/run/bluetooth";
+
+#[derive(Debug, PartialEq, Copy, Clone)]
+#[repr(i32)]
+pub enum State {
+ Off = 0, // Bluetooth is not running
+ TurningOn = 1, // We are not notified that the Bluetooth is running
+ On = 2, // Bluetooth is running
+ TurningOff = 3, // We are not notified that the Bluetooth is stopped
+}
+
+impl From<State> for i32 {
+ fn from(item: State) -> i32 {
+ item as i32
+ }
+}
+
+pub fn state_to_i32(state: State) -> i32 {
+ i32::from(state)
+}
+
+#[derive(Debug)]
+pub enum StateMachineActions {
+ StartBluetooth(i32),
+ StopBluetooth(i32),
+ BluetoothStarted(i32, i32), // PID and HCI
+ BluetoothStopped(),
+}
+
+pub struct StateMachineContext<PM> {
+ tx: mpsc::Sender<StateMachineActions>,
+ rx: mpsc::Receiver<StateMachineActions>,
+ state_machine: ManagerStateMachine<PM>,
+}
+
+impl<PM> StateMachineContext<PM> {
+ fn new(state_machine: ManagerStateMachine<PM>) -> StateMachineContext<PM>
+ where
+ PM: ProcessManager + Send,
+ {
+ let (tx, rx) = mpsc::channel::<StateMachineActions>(10);
+ StateMachineContext { tx: tx, rx: rx, state_machine: state_machine }
+ }
+
+ pub fn get_proxy(&self) -> StateMachineProxy {
+ StateMachineProxy { tx: self.tx.clone(), state: self.state_machine.state.clone() }
+ }
+}
+
+pub fn start_new_state_machine_context() -> StateMachineContext<UpstartInvoker> {
+ StateMachineContext::new(ManagerStateMachine::new_upstart())
+}
+
+#[derive(Clone)]
+pub struct StateMachineProxy {
+ tx: mpsc::Sender<StateMachineActions>,
+ state: Arc<Mutex<State>>,
+}
+
+const TX_SEND_TIMEOUT_DURATION: Duration = Duration::from_secs(3);
+const COMMAND_TIMEOUT_DURATION: Duration = Duration::from_secs(3);
+
+impl StateMachineProxy {
+ pub async fn start_bluetooth(
+ &self,
+ hci_interface: i32,
+ ) -> Result<(), SendTimeoutError<StateMachineActions>> {
+ self.tx
+ .send_timeout(
+ StateMachineActions::StartBluetooth(hci_interface),
+ TX_SEND_TIMEOUT_DURATION,
+ )
+ .await
+ }
+
+ pub async fn stop_bluetooth(
+ &self,
+ hci_interface: i32,
+ ) -> Result<(), SendTimeoutError<StateMachineActions>> {
+ self.tx
+ .send_timeout(
+ StateMachineActions::StopBluetooth(hci_interface),
+ TX_SEND_TIMEOUT_DURATION,
+ )
+ .await
+ }
+
+ pub async fn get_state(&self) -> State {
+ *self.state.lock().await
+ }
+}
+
+fn pid_inotify_async_fd() -> AsyncFd<inotify::Inotify> {
+ let mut pid_detector = inotify::Inotify::init().expect("cannot use inotify");
+ pid_detector
+ .add_watch(PID_DIR, inotify::WatchMask::CREATE | inotify::WatchMask::DELETE)
+ .expect("failed to add watch");
+ AsyncFd::new(pid_detector).expect("failed to add async fd")
+}
+
+fn get_hci_interface_from_pid_file_name(path: &str) -> Option<i32> {
+ let re = Regex::new(r"bluetooth([0-9]+).pid").unwrap();
+ re.captures(path)?.get(1)?.as_str().parse().ok()
+}
+
+fn hci_devices_inotify_async_fd() -> AsyncFd<inotify::Inotify> {
+ let mut detector = inotify::Inotify::init().expect("cannot use inotify");
+ detector
+ .add_watch(
+ crate::config_util::HCI_DEVICES_DIR,
+ inotify::WatchMask::CREATE | inotify::WatchMask::DELETE,
+ )
+ .expect("failed to add watch");
+ AsyncFd::new(detector).expect("failed to add async fd")
+}
+
+fn get_hci_interface_from_device(path: &str) -> Option<i32> {
+ let re = Regex::new(r"hci([0-9]+)").unwrap();
+ re.captures(path)?.get(1)?.as_str().parse().ok()
+}
+
+pub async fn mainloop<PM>(
+ mut context: StateMachineContext<PM>,
+ dbus_callback_util: crate::dbus_callback_util::DbusCallbackUtil,
+) where
+ PM: ProcessManager + Send,
+{
+ let mut command_timeout = Alarm::new();
+ let mut pid_async_fd = pid_inotify_async_fd();
+ let mut hci_devices_async_fd = hci_devices_inotify_async_fd();
+ loop {
+ tokio::select! {
+ Some(action) = context.rx.recv() => {
+ match action {
+ StateMachineActions::StartBluetooth(i) => {
+ match context.state_machine.action_start_bluetooth(i).await {
+ true => {
+ command_timeout.reset(COMMAND_TIMEOUT_DURATION);
+ },
+ false => command_timeout.cancel(),
+ }
+ },
+ StateMachineActions::StopBluetooth(i) => {
+ match context.state_machine.action_stop_bluetooth(i).await {
+ true => {
+ command_timeout.reset(COMMAND_TIMEOUT_DURATION);
+ },
+ false => command_timeout.cancel(),
+ }
+ },
+ StateMachineActions::BluetoothStarted(pid, hci) => {
+ match context.state_machine.action_on_bluetooth_started(pid, hci).await {
+ true => {
+ command_timeout.cancel();
+ }
+ false => error!("unexpected BluetoothStarted pid{} hci{}", pid, hci),
+ }
+ },
+ StateMachineActions::BluetoothStopped() => {
+ match context.state_machine.action_on_bluetooth_stopped().await {
+ true => {
+ command_timeout.cancel();
+ }
+ false => {
+ command_timeout.reset(COMMAND_TIMEOUT_DURATION);
+ }
+ }
+ },
+ }
+ },
+ expired = command_timeout.expired() => {
+ info!("expired {:?}", *context.state_machine.state.lock().await);
+ let timeout_action = context.state_machine.action_on_command_timeout().await;
+ match timeout_action {
+ StateMachineTimeoutActions::Noop => (),
+ _ => command_timeout.reset(COMMAND_TIMEOUT_DURATION),
+ }
+ },
+ r = pid_async_fd.readable_mut() => {
+ let mut fd_ready = r.unwrap();
+ let mut buffer: [u8; 1024] = [0; 1024];
+ match fd_ready.try_io(|inner| inner.get_mut().read_events(&mut buffer)) {
+ Ok(Ok(events)) => {
+ for event in events {
+ debug!("got some events from pid {:?}", event.mask);
+ match (event.mask, event.name) {
+ (inotify::EventMask::CREATE, Some(oss)) => {
+ let path = std::path::Path::new(PID_DIR).join(oss);
+ let file_name = oss.to_str().unwrap_or("invalid file");
+ match (get_hci_interface_from_pid_file_name(file_name), tokio::fs::read(path).await.ok()) {
+ (Some(hci), Some(s)) => {
+ let pid = String::from_utf8(s).expect("invalid pid file").parse::<i32>().unwrap_or(0);
+ let _ = context.tx.send_timeout(StateMachineActions::BluetoothStarted(pid, hci), TX_SEND_TIMEOUT_DURATION).await.unwrap();
+ },
+ (hci, s) => warn!("invalid file hci={:?} pid_file={:?}", hci, s),
+ }
+ },
+ (inotify::EventMask::DELETE, Some(oss)) => {
+ let file_name = oss.to_str().unwrap_or("invalid file");
+ if let Some(hci) = get_hci_interface_from_pid_file_name(file_name) {
+ context.tx.send_timeout(StateMachineActions::BluetoothStopped(), TX_SEND_TIMEOUT_DURATION).await.unwrap();
+ }
+ },
+ _ => debug!("Ignored event {:?}", event.mask)
+ }
+ }
+ },
+ Err(_) | Ok(Err(_)) => panic!("why can't we read while the asyncfd is ready?"),
+ }
+ fd_ready.clear_ready();
+ drop(fd_ready);
+ },
+ r = hci_devices_async_fd.readable_mut() => {
+ let mut fd_ready = r.unwrap();
+ let mut buffer: [u8; 1024] = [0; 1024];
+ match fd_ready.try_io(|inner| inner.get_mut().read_events(&mut buffer)) {
+ Ok(Ok(events)) => {
+ for event in events {
+ match (event.mask, event.name) {
+ (inotify::EventMask::CREATE, Some(oss)) => {
+ match get_hci_interface_from_device(oss.to_str().unwrap_or("invalid hci device")) {
+ Some(hci) => {
+ dbus_callback_util.send_hci_device_change_callback(hci, true).await;
+ },
+ _ => (),
+ }
+ },
+ (inotify::EventMask::DELETE, Some(oss)) => {
+ match get_hci_interface_from_device(oss.to_str().unwrap_or("invalid hci device")) {
+ Some(hci) => {
+ dbus_callback_util.send_hci_device_change_callback(hci, false).await;
+ },
+ _ => (),
+ }
+ },
+ _ => debug!("Ignored event {:?}", event.mask)
+ }
+ }
+ },
+ Err(_) | Ok(Err(_)) => panic!("why can't we read while the asyncfd is ready?"),
+ }
+ fd_ready.clear_ready();
+ drop(fd_ready);
+ },
+ }
+ }
+}
+
+pub trait ProcessManager {
+ fn start(&mut self, hci_interface: String);
+ fn stop(&mut self, hci_interface: String);
+}
+
+pub struct NativeSubprocess {
+ process_container: Option<Child>,
+ bluetooth_pid: u32,
+}
+
+impl NativeSubprocess {
+ pub fn new() -> NativeSubprocess {
+ NativeSubprocess { process_container: None, bluetooth_pid: 0 }
+ }
+}
+
+impl ProcessManager for NativeSubprocess {
+ fn start(&mut self, hci_interface: String) {
+ let new_process = Command::new("/usr/bin/btadapterd")
+ .arg(format!("HCI={}", hci_interface))
+ .stdout(Stdio::piped())
+ .spawn()
+ .expect("cannot open");
+ self.bluetooth_pid = new_process.id();
+ self.process_container = Some(new_process);
+ }
+ fn stop(&mut self, _hci_interface: String) {
+ match self.process_container {
+ Some(ref mut _p) => {
+ signal::kill(Pid::from_raw(self.bluetooth_pid as i32), Signal::SIGTERM).unwrap();
+ self.process_container = None;
+ }
+ None => {
+ warn!("Process doesn't exist");
+ }
+ }
+ }
+}
+
+pub struct UpstartInvoker {}
+
+impl UpstartInvoker {
+ pub fn new() -> UpstartInvoker {
+ UpstartInvoker {}
+ }
+}
+
+impl ProcessManager for UpstartInvoker {
+ fn start(&mut self, hci_interface: String) {
+ Command::new("initctl")
+ .args(&["start", "btadapterd", format!("HCI={}", hci_interface).as_str()])
+ .output()
+ .expect("failed to start bluetooth");
+ }
+
+ fn stop(&mut self, hci_interface: String) {
+ Command::new("initctl")
+ .args(&["stop", "btadapterd", format!("HCI={}", hci_interface).as_str()])
+ .output()
+ .expect("failed to stop bluetooth");
+ }
+}
+
+struct ManagerStateMachine<PM> {
+ state: Arc<Mutex<State>>,
+ process_manager: PM,
+ hci_interface: i32,
+ bluetooth_pid: i32,
+}
+
+impl ManagerStateMachine<NativeSubprocess> {
+ pub fn new_native() -> ManagerStateMachine<NativeSubprocess> {
+ ManagerStateMachine::new(NativeSubprocess::new())
+ }
+}
+
+impl ManagerStateMachine<UpstartInvoker> {
+ pub fn new_upstart() -> ManagerStateMachine<UpstartInvoker> {
+ ManagerStateMachine::new(UpstartInvoker::new())
+ }
+}
+
+#[derive(Debug, PartialEq)]
+enum StateMachineTimeoutActions {
+ RetryStart,
+ RetryStop,
+ Noop,
+}
+
+impl<PM> ManagerStateMachine<PM>
+where
+ PM: ProcessManager + Send,
+{
+ pub fn new(process_manager: PM) -> ManagerStateMachine<PM> {
+ ManagerStateMachine {
+ state: Arc::new(Mutex::new(State::Off)),
+ process_manager: process_manager,
+ hci_interface: 0,
+ bluetooth_pid: 0,
+ }
+ }
+
+ /// Returns true if we are starting bluetooth process.
+ pub async fn action_start_bluetooth(&mut self, hci_interface: i32) -> bool {
+ let mut state = self.state.lock().await;
+ match *state {
+ State::Off => {
+ *state = State::TurningOn;
+ self.hci_interface = hci_interface;
+ self.process_manager.start(format!("{}", hci_interface));
+ true
+ }
+ // Otherwise no op
+ _ => false,
+ }
+ }
+
+ /// Returns true if we are stopping bluetooth process.
+ pub async fn action_stop_bluetooth(&mut self, hci_interface: i32) -> bool {
+ if self.hci_interface != hci_interface {
+ warn!(
+ "We are running hci{} but attempting to stop hci{}",
+ self.hci_interface, hci_interface
+ );
+ return false;
+ }
+
+ let mut state = self.state.lock().await;
+ match *state {
+ State::On => {
+ *state = State::TurningOff;
+ self.process_manager.stop(self.hci_interface.to_string());
+ true
+ }
+ State::TurningOn => {
+ *state = State::Off;
+ self.process_manager.stop(self.hci_interface.to_string());
+ false
+ }
+ // Otherwise no op
+ _ => false,
+ }
+ }
+
+ /// Returns true if the event is expected.
+ pub async fn action_on_bluetooth_started(&mut self, pid: i32, hci_interface: i32) -> bool {
+ let mut state = self.state.lock().await;
+ if self.hci_interface != hci_interface {
+ warn!(
+ "We should start hci{} but hci{} is started; capturing that process",
+ self.hci_interface, hci_interface
+ );
+ self.hci_interface = hci_interface;
+ }
+ if *state != State::TurningOn {
+ warn!("Unexpected Bluetooth started");
+ }
+ *state = State::On;
+ self.bluetooth_pid = pid;
+ true
+ }
+
+ /// Returns true if the event is expected.
+ /// If unexpected, Bluetooth probably crashed;
+ /// start the timer for restart timeout
+ pub async fn action_on_bluetooth_stopped(&mut self) -> bool {
+ let mut state = self.state.lock().await;
+
+ match *state {
+ State::TurningOff => {
+ *state = State::Off;
+ true
+ }
+ State::On => {
+ warn!("Bluetooth stopped unexpectedly, try restarting");
+ *state = State::TurningOn;
+ self.process_manager.start(format!("{}", self.hci_interface));
+ false
+ }
+ State::TurningOn | State::Off => {
+ // Unexpected
+ panic!("unexpected bluetooth shutdown");
+ }
+ }
+ }
+
+ /// Triggered on Bluetooth start/stop timeout. Return the actions that the
+ /// state machine has taken, for the external context to reset the timer.
+ pub async fn action_on_command_timeout(&mut self) -> StateMachineTimeoutActions {
+ let mut state = self.state.lock().await;
+ match *state {
+ State::TurningOn => {
+ info!("Restarting bluetooth");
+ *state = State::TurningOn;
+ self.process_manager.stop(format! {"{}", self.hci_interface});
+ self.process_manager.start(format! {"{}", self.hci_interface});
+ StateMachineTimeoutActions::RetryStart
+ }
+ State::TurningOff => {
+ info!("Killing bluetooth");
+ self.process_manager.stop(format! {"{}", self.hci_interface});
+ StateMachineTimeoutActions::RetryStop
+ }
+ _ => StateMachineTimeoutActions::Noop,
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use std::collections::VecDeque;
+
+ #[derive(Debug, PartialEq)]
+ enum ExecutedCommand {
+ Start,
+ Stop,
+ }
+
+ struct MockProcessManager {
+ last_command: VecDeque<ExecutedCommand>,
+ }
+
+ impl MockProcessManager {
+ fn new() -> MockProcessManager {
+ MockProcessManager { last_command: VecDeque::new() }
+ }
+
+ fn expect_start(&mut self) {
+ self.last_command.push_back(ExecutedCommand::Start);
+ }
+
+ fn expect_stop(&mut self) {
+ self.last_command.push_back(ExecutedCommand::Stop);
+ }
+ }
+
+ impl ProcessManager for MockProcessManager {
+ fn start(&mut self, _: String) {
+ let start = self.last_command.pop_front().expect("Should expect start event");
+ assert_eq!(start, ExecutedCommand::Start);
+ }
+
+ fn stop(&mut self, _: String) {
+ let stop = self.last_command.pop_front().expect("Should expect stop event");
+ assert_eq!(stop, ExecutedCommand::Stop);
+ }
+ }
+
+ impl Drop for MockProcessManager {
+ fn drop(&mut self) {
+ assert_eq!(self.last_command.len(), 0);
+ }
+ }
+
+ #[test]
+ fn initial_state_is_off() {
+ tokio::runtime::Runtime::new().unwrap().block_on(async {
+ let process_manager = MockProcessManager::new();
+ let state_machine = ManagerStateMachine::new(process_manager);
+ assert_eq!(*state_machine.state.lock().await, State::Off);
+ })
+ }
+
+ #[test]
+ fn off_turnoff_should_noop() {
+ tokio::runtime::Runtime::new().unwrap().block_on(async {
+ let process_manager = MockProcessManager::new();
+ let mut state_machine = ManagerStateMachine::new(process_manager);
+ state_machine.action_stop_bluetooth(0).await;
+ assert_eq!(*state_machine.state.lock().await, State::Off);
+ })
+ }
+
+ #[test]
+ fn off_turnon_should_turningon() {
+ tokio::runtime::Runtime::new().unwrap().block_on(async {
+ let mut process_manager = MockProcessManager::new();
+ // Expect to send start command
+ process_manager.expect_start();
+ let mut state_machine = ManagerStateMachine::new(process_manager);
+ state_machine.action_start_bluetooth(0).await;
+ assert_eq!(*state_machine.state.lock().await, State::TurningOn);
+ })
+ }
+
+ #[test]
+ fn turningon_turnon_again_noop() {
+ tokio::runtime::Runtime::new().unwrap().block_on(async {
+ let mut process_manager = MockProcessManager::new();
+ // Expect to send start command just once
+ process_manager.expect_start();
+ let mut state_machine = ManagerStateMachine::new(process_manager);
+ state_machine.action_start_bluetooth(0).await;
+ assert_eq!(state_machine.action_start_bluetooth(0).await, false);
+ })
+ }
+
+ #[test]
+ fn turningon_bluetooth_started() {
+ tokio::runtime::Runtime::new().unwrap().block_on(async {
+ let mut process_manager = MockProcessManager::new();
+ process_manager.expect_start();
+ let mut state_machine = ManagerStateMachine::new(process_manager);
+ state_machine.action_start_bluetooth(0).await;
+ state_machine.action_on_bluetooth_started(0, 0).await;
+ assert_eq!(*state_machine.state.lock().await, State::On);
+ })
+ }
+
+ #[test]
+ fn turningon_timeout() {
+ tokio::runtime::Runtime::new().unwrap().block_on(async {
+ let mut process_manager = MockProcessManager::new();
+ process_manager.expect_start();
+ process_manager.expect_stop();
+ process_manager.expect_start(); // start bluetooth again
+ let mut state_machine = ManagerStateMachine::new(process_manager);
+ state_machine.action_start_bluetooth(0).await;
+ assert_eq!(
+ state_machine.action_on_command_timeout().await,
+ StateMachineTimeoutActions::RetryStart
+ );
+ assert_eq!(*state_machine.state.lock().await, State::TurningOn);
+ })
+ }
+
+ #[test]
+ fn turningon_turnoff_should_turningoff_and_send_command() {
+ tokio::runtime::Runtime::new().unwrap().block_on(async {
+ let mut process_manager = MockProcessManager::new();
+ process_manager.expect_start();
+ // Expect to send stop command
+ process_manager.expect_stop();
+ let mut state_machine = ManagerStateMachine::new(process_manager);
+ state_machine.action_start_bluetooth(0).await;
+ state_machine.action_stop_bluetooth(0).await;
+ assert_eq!(*state_machine.state.lock().await, State::Off);
+ })
+ }
+
+ #[test]
+ fn on_turnoff_should_turningoff_and_send_command() {
+ tokio::runtime::Runtime::new().unwrap().block_on(async {
+ let mut process_manager = MockProcessManager::new();
+ process_manager.expect_start();
+ // Expect to send stop command
+ process_manager.expect_stop();
+ let mut state_machine = ManagerStateMachine::new(process_manager);
+ state_machine.action_start_bluetooth(0).await;
+ state_machine.action_on_bluetooth_started(0, 0).await;
+ state_machine.action_stop_bluetooth(0).await;
+ assert_eq!(*state_machine.state.lock().await, State::TurningOff);
+ })
+ }
+
+ #[test]
+ fn on_bluetooth_stopped() {
+ tokio::runtime::Runtime::new().unwrap().block_on(async {
+ let mut process_manager = MockProcessManager::new();
+ process_manager.expect_start();
+ // Expect to start again
+ process_manager.expect_start();
+ let mut state_machine = ManagerStateMachine::new(process_manager);
+ state_machine.action_start_bluetooth(0).await;
+ state_machine.action_on_bluetooth_started(0, 0).await;
+ assert_eq!(state_machine.action_on_bluetooth_stopped().await, false);
+ assert_eq!(*state_machine.state.lock().await, State::TurningOn);
+ })
+ }
+
+ #[test]
+ fn turningoff_bluetooth_down_should_off() {
+ tokio::runtime::Runtime::new().unwrap().block_on(async {
+ let mut process_manager = MockProcessManager::new();
+ process_manager.expect_start();
+ process_manager.expect_stop();
+ let mut state_machine = ManagerStateMachine::new(process_manager);
+ state_machine.action_start_bluetooth(0).await;
+ state_machine.action_on_bluetooth_started(0, 0).await;
+ state_machine.action_stop_bluetooth(0).await;
+ state_machine.action_on_bluetooth_stopped().await;
+ assert_eq!(*state_machine.state.lock().await, State::Off);
+ })
+ }
+
+ #[test]
+ fn restart_bluetooth() {
+ tokio::runtime::Runtime::new().unwrap().block_on(async {
+ let mut process_manager = MockProcessManager::new();
+ process_manager.expect_start();
+ process_manager.expect_stop();
+ process_manager.expect_start();
+ let mut state_machine = ManagerStateMachine::new(process_manager);
+ state_machine.action_start_bluetooth(0).await;
+ state_machine.action_on_bluetooth_started(0, 0).await;
+ state_machine.action_stop_bluetooth(0).await;
+ state_machine.action_on_bluetooth_stopped().await;
+ state_machine.action_start_bluetooth(0).await;
+ state_machine.action_on_bluetooth_started(0, 0).await;
+ assert_eq!(*state_machine.state.lock().await, State::On);
+ })
+ }
+
+ #[test]
+ fn path_to_hci_interface() {
+ assert_eq!(
+ get_hci_interface_from_pid_file_name("/var/run/bluetooth/bluetooth0.pid"),
+ Some(0)
+ );
+ assert_eq!(
+ get_hci_interface_from_pid_file_name("/var/run/bluetooth/bluetooth1.pid"),
+ Some(1)
+ );
+ assert_eq!(
+ get_hci_interface_from_pid_file_name("/var/run/bluetooth/bluetooth10.pid"),
+ Some(10)
+ );
+ assert_eq!(get_hci_interface_from_pid_file_name("/var/run/bluetooth/garbage"), None);
+
+ assert_eq!(get_hci_interface_from_device("/sys/class/bluetooth/hci0"), Some(0));
+ assert_eq!(get_hci_interface_from_device("/sys/class/bluetooth/hci1"), Some(1));
+ assert_eq!(get_hci_interface_from_device("/sys/class/bluetooth/hci10"), Some(10));
+ assert_eq!(get_hci_interface_from_device("/sys/class/bluetooth/eth0"), None);
+ }
+}
diff --git a/gd/rust/linux/mgmt/test/btmanagerd_test.py b/gd/rust/linux/mgmt/test/btmanagerd_test.py
new file mode 100644
index 0000000..d909ae6
--- /dev/null
+++ b/gd/rust/linux/mgmt/test/btmanagerd_test.py
@@ -0,0 +1,122 @@
+#!/usr/bin/python3
+
+#%%
+
+import dbus
+import dbus.service
+import dbus.mainloop.glib
+import time
+import unittest
+
+HCI_DEVICES_DIR = "/sys/class/bluetooth"
+
+# File to store the Bluetooth daemon to use (bluez or floss)
+BLUETOOTH_DAEMON_CURRENT = "/var/lib/misc/bluetooth-daemon.current"
+
+# File to store the config for BluetoothManager
+BTMANAGERD_CONF = "/var/lib/bluetooth/btmanagerd.json"
+
+# D-BUS bus name
+BUS_NAME = "org.chromium.bluetooth.Manager"
+
+# D-Bus Bluetooth Manager object path
+MANAGER_OBJECT_PATH = "/org/chromium/bluetooth/Manager"
+
+# D-Bus Bluetooth Manager interface name
+MANAGER_INTERFACE_NAME = "org.chromium.bluetooth.Manager"
+
+# D-Bus Bluetooth Manager client (this test) object path
+CLIENT_OBJECT_PATH = "/test_client"
+
+
+def use_floss():
+ with open(BLUETOOTH_DAEMON_CURRENT, "w") as f:
+ f.write("floss")
+
+def use_bluez():
+ with open(BLUETOOTH_DAEMON_CURRENT, "w") as f:
+ f.write("floss")
+
+class BtmanagerdTest(unittest.TestCase):
+
+ def setUp(self):
+ self.bus = dbus.SystemBus()
+ self.manager_object = self.bus.get_object(BUS_NAME, MANAGER_OBJECT_PATH)
+ self.client_object = self.bus.get_object(BUS_NAME, CLIENT_OBJECT_PATH)
+ self.manager_object.Stop(0, dbus_interface=MANAGER_INTERFACE_NAME)
+ time.sleep(2.5)
+ self.assertEqual(self._get_state(), 0)
+
+ def _start_hci(self, hci=0):
+ self.manager_object.Start(hci, dbus_interface=MANAGER_INTERFACE_NAME)
+ time.sleep(2.5)
+
+ def _stop_hci(self, hci=0):
+ self.manager_object.Stop(hci, dbus_interface=MANAGER_INTERFACE_NAME)
+ time.sleep(2.5)
+
+ def _get_state(self):
+ return self.manager_object.GetState(dbus_interface=MANAGER_INTERFACE_NAME)
+
+ def _register_hci_device_change_observer(self):
+ return self.manager_object.RegisterStateChangeObserver(self.client_object_path, dbus_interface=MANAGER_INTERFACE_NAME)
+
+ def _unregister_hci_device_change_observer(self):
+ return self.manager_object.UnregisterHciDeviceChangeObserver(self.client_object_path, dbus_interface=MANAGER_INTERFACE_NAME)
+
+ def _get_floss_enabled(self):
+ return self.manager_object.GetFlossEnabled(dbus_interface=MANAGER_INTERFACE_NAME)
+
+ def _set_floss_enabled(self, enabled=True):
+ return self.manager_object.SetFlossEnabled(enabled, dbus_interface=MANAGER_INTERFACE_NAME)
+
+ def _list_hci_devices(self):
+ return self.manager_object.ListHciDevices(dbus_interface=MANAGER_INTERFACE_NAME)
+
+ def _register_hci_device_change_observer(self):
+ return self.manager_object.RegisterHciDeviceChangeObserver(self.client_object_path, dbus_interface=MANAGER_INTERFACE_NAME)
+
+ def _unregister_hci_device_change_observer(self):
+ return self.manager_object.UnregisterHciDeviceChangeObserver(self.client_object_path, dbus_interface=MANAGER_INTERFACE_NAME)
+
+ def test_list_hci_devices(self):
+ self.assertTrue(len(self._list_hci_devices()) > 0)
+
+ def test_floss_enabled(self):
+ self.assertTrue(self._get_floss_enabled())
+
+ def test_disable_floss(self):
+ self._set_floss_enabled(False)
+ self.assertFalse(self._get_floss_enabled())
+ with open(BLUETOOTH_DAEMON_CURRENT, "r") as f:
+ self.assertEqual(f.read(), "bluez")
+
+ self._set_floss_enabled(True)
+ self.assertTrue(self._get_floss_enabled())
+
+ def test_start(self):
+ self._start_hci()
+ self.assertEqual(self._get_state(), 2)
+
+ def test_astart_and_start(self):
+ self._start_hci()
+ self._start_hci()
+ self.assertEqual(self._get_state(), 2)
+
+ def test_stop(self):
+ self._start_hci()
+ self._stop_hci()
+ self.assertEqual(self._get_state(), 0)
+
+ def test_stop_and_stop(self):
+ self._start_hci()
+ self._stop_hci()
+ self._stop_hci()
+ self.assertEqual(self._get_state(), 0)
+
+
+# %%
+if __name__ == '__main__':
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+ use_floss()
+ unittest.main()
diff --git a/gd/rust/linux/service/Cargo.toml b/gd/rust/linux/service/Cargo.toml
new file mode 100644
index 0000000..5fc9e6f
--- /dev/null
+++ b/gd/rust/linux/service/Cargo.toml
@@ -0,0 +1,26 @@
+[package]
+name = "btadapterd"
+version = "0.1.0"
+edition = "2018"
+
+[dependencies]
+bt_topshim = { path = "../../topshim" }
+bt_shim = { path = "../../shim" }
+btstack = { path = "../stack" }
+dbus_projection = { path = "../dbus_projection" }
+dbus_macros = { path = "../dbus_projection/dbus_macros" }
+
+dbus = "0.9.2"
+dbus-crossroads = "0.3.0"
+dbus-tokio = "0.7.3"
+futures = "0.3.13"
+num-traits = "*"
+tokio = { version = "1", features = ['bytes', 'fs', 'io-util', 'libc', 'macros', 'memchr', 'mio', 'net', 'num_cpus', 'rt', 'rt-multi-thread', 'sync', 'time', 'tokio-macros'] }
+
+[build-dependencies]
+pkg-config = "0.3.19"
+
+[[bin]]
+name = "btadapterd"
+path = "src/main.rs"
+build = "build.rs"
diff --git a/gd/rust/linux/service/build.rs b/gd/rust/linux/service/build.rs
new file mode 100644
index 0000000..41f4083
--- /dev/null
+++ b/gd/rust/linux/service/build.rs
@@ -0,0 +1,27 @@
+use pkg_config::Config;
+
+fn main() {
+ let target_dir = std::env::var_os("CARGO_TARGET_DIR").unwrap();
+
+ // The main linking point with c++ code is the libbluetooth-static.a
+ // These includes all the symbols built via C++ but doesn't include other
+ // links (i.e. pkg-config)
+ println!("cargo:rustc-link-lib=static=bluetooth-static");
+ println!("cargo:rustc-link-search=native={}", target_dir.into_string().unwrap());
+
+ // A few dynamic links
+ println!("cargo:rustc-link-lib=dylib=flatbuffers");
+ println!("cargo:rustc-link-lib=dylib=protobuf");
+ println!("cargo:rustc-link-lib=dylib=resolv");
+
+ // Clang requires -lc++ instead of -lstdc++
+ println!("cargo:rustc-link-lib=c++");
+
+ // A few more dependencies from pkg-config. These aren't included as part of
+ // the libbluetooth-static.a
+ Config::new().probe("libchrome").unwrap();
+ Config::new().probe("libmodp_b64").unwrap();
+ Config::new().probe("tinyxml2").unwrap();
+
+ println!("cargo:rerun-if-changed=build.rs");
+}
diff --git a/gd/rust/linux/service/src/dbus_arg.rs b/gd/rust/linux/service/src/dbus_arg.rs
new file mode 100644
index 0000000..d1724aa
--- /dev/null
+++ b/gd/rust/linux/service/src/dbus_arg.rs
@@ -0,0 +1,3 @@
+use dbus_macros::generate_dbus_arg;
+
+generate_dbus_arg!();
diff --git a/gd/rust/linux/service/src/iface_bluetooth.rs b/gd/rust/linux/service/src/iface_bluetooth.rs
new file mode 100644
index 0000000..22bb6a2
--- /dev/null
+++ b/gd/rust/linux/service/src/iface_bluetooth.rs
@@ -0,0 +1,82 @@
+extern crate bt_shim;
+
+use btstack::bluetooth::{BluetoothDevice, BluetoothTransport, IBluetooth, IBluetoothCallback};
+use btstack::RPCProxy;
+
+use dbus::arg::RefArg;
+
+use dbus::nonblock::SyncConnection;
+use dbus::strings::Path;
+
+use dbus_macros::{dbus_method, dbus_propmap, dbus_proxy_obj, generate_dbus_exporter};
+
+use dbus_projection::impl_dbus_arg_enum;
+use dbus_projection::DisconnectWatcher;
+
+use num_traits::cast::{FromPrimitive, ToPrimitive};
+
+use std::sync::Arc;
+
+use crate::dbus_arg::{DBusArg, DBusArgError, RefArgToRust};
+
+#[dbus_propmap(BluetoothDevice)]
+pub struct BluetoothDeviceDBus {
+ address: String,
+}
+
+#[allow(dead_code)]
+struct BluetoothCallbackDBus {}
+
+#[dbus_proxy_obj(BluetoothCallback, "org.chromium.bluetooth.BluetoothCallback")]
+impl IBluetoothCallback for BluetoothCallbackDBus {
+ #[dbus_method("OnBluetoothStateChanged")]
+ fn on_bluetooth_state_changed(&self, prev_state: u32, new_state: u32) {}
+ #[dbus_method("OnBluetoothAddressChanged")]
+ fn on_bluetooth_address_changed(&self, addr: String) {}
+ #[dbus_method("OnDeviceFound")]
+ fn on_device_found(&self, remote_device: BluetoothDevice) {}
+ #[dbus_method("OnDiscoveringChanged")]
+ fn on_discovering_changed(&self, discovering: bool) {}
+}
+
+impl_dbus_arg_enum!(BluetoothTransport);
+
+#[allow(dead_code)]
+struct IBluetoothDBus {}
+
+#[generate_dbus_exporter(export_bluetooth_dbus_obj, "org.chromium.bluetooth.Bluetooth")]
+impl IBluetooth for IBluetoothDBus {
+ #[dbus_method("RegisterCallback")]
+ fn register_callback(&mut self, callback: Box<dyn IBluetoothCallback + Send>) {}
+
+ // Not exposed over D-Bus. The stack is automatically enabled when the daemon starts.
+ fn enable(&mut self) -> bool {
+ false
+ }
+
+ // Not exposed over D-Bus. The stack is automatically disabled when the daemon exits.
+ // TODO(b/189495858): Handle shutdown properly when SIGTERM is received.
+ fn disable(&mut self) -> bool {
+ false
+ }
+
+ #[dbus_method("GetAddress")]
+ fn get_address(&self) -> String {
+ String::from("")
+ }
+
+ #[dbus_method("StartDiscovery")]
+ fn start_discovery(&self) -> bool {
+ true
+ }
+
+ #[dbus_method("CancelDiscovery")]
+ fn cancel_discovery(&self) -> bool {
+ true
+ }
+
+ #[dbus_method("CreateBond")]
+ fn create_bond(&self, _device: BluetoothDevice, _transport: BluetoothTransport) -> bool {
+ true
+ }
+}
diff --git a/gd/rust/linux/service/src/iface_bluetooth_gatt.rs b/gd/rust/linux/service/src/iface_bluetooth_gatt.rs
new file mode 100644
index 0000000..1a21b8e
--- /dev/null
+++ b/gd/rust/linux/service/src/iface_bluetooth_gatt.rs
@@ -0,0 +1,66 @@
+use btstack::bluetooth_gatt::{
+ IBluetoothGatt, IScannerCallback, RSSISettings, ScanFilter, ScanSettings, ScanType,
+};
+use btstack::RPCProxy;
+
+use dbus::arg::RefArg;
+
+use dbus::nonblock::SyncConnection;
+use dbus::strings::Path;
+
+use dbus_macros::{dbus_method, dbus_propmap, dbus_proxy_obj, generate_dbus_exporter};
+
+use dbus_projection::impl_dbus_arg_enum;
+use dbus_projection::DisconnectWatcher;
+
+use num_traits::cast::{FromPrimitive, ToPrimitive};
+
+use std::sync::Arc;
+
+use crate::dbus_arg::{DBusArg, DBusArgError, RefArgToRust};
+
+#[allow(dead_code)]
+struct ScannerCallbackDBus {}
+
+#[dbus_proxy_obj(ScannerCallback, "org.chromium.bluetooth.ScannerCallback")]
+impl IScannerCallback for ScannerCallbackDBus {
+ #[dbus_method("OnScannerRegistered")]
+ fn on_scanner_registered(&self, _status: i32, _scanner_id: i32) {}
+}
+
+#[dbus_propmap(RSSISettings)]
+pub struct RSSISettingsDBus {
+ low_threshold: i32,
+ high_threshold: i32,
+}
+
+#[dbus_propmap(ScanSettings)]
+struct ScanSettingsDBus {
+ interval: i32,
+ window: i32,
+ scan_type: ScanType,
+ rssi_settings: RSSISettings,
+}
+
+impl_dbus_arg_enum!(ScanType);
+
+#[dbus_propmap(ScanFilter)]
+struct ScanFilterDBus {}
+
+#[allow(dead_code)]
+struct IBluetoothGattDBus {}
+
+#[generate_dbus_exporter(export_bluetooth_gatt_dbus_obj, "org.chromium.bluetooth.BluetoothGatt")]
+impl IBluetoothGatt for IBluetoothGattDBus {
+ #[dbus_method("RegisterScanner")]
+ fn register_scanner(&self, callback: Box<dyn IScannerCallback + Send>) {}
+
+ #[dbus_method("UnregisterScanner")]
+ fn unregister_scanner(&self, scanner_id: i32) {}
+
+ #[dbus_method("StartScan")]
+ fn start_scan(&self, scanner_id: i32, settings: ScanSettings, filters: Vec<ScanFilter>) {}
+
+ #[dbus_method("StopScan")]
+ fn stop_scan(&self, scanner_id: i32) {}
+}
diff --git a/gd/rust/linux/service/src/main.rs b/gd/rust/linux/service/src/main.rs
new file mode 100644
index 0000000..7740864
--- /dev/null
+++ b/gd/rust/linux/service/src/main.rs
@@ -0,0 +1,106 @@
+use bt_topshim::btif::get_btinterface;
+use bt_topshim::topstack;
+
+use dbus::channel::MatchingReceiver;
+use dbus::message::MatchRule;
+
+use dbus_crossroads::Crossroads;
+
+use dbus_projection::DisconnectWatcher;
+
+use dbus_tokio::connection;
+
+use futures::future;
+
+use btstack::bluetooth::get_bt_dispatcher;
+use btstack::bluetooth::{Bluetooth, IBluetooth};
+use btstack::bluetooth_gatt::BluetoothGatt;
+use btstack::Stack;
+
+use std::error::Error;
+use std::sync::{Arc, Mutex};
+
+mod dbus_arg;
+mod iface_bluetooth;
+mod iface_bluetooth_gatt;
+
+const DBUS_SERVICE_NAME: &str = "org.chromium.bluetooth";
+const OBJECT_BLUETOOTH: &str = "/org/chromium/bluetooth/adapter";
+const OBJECT_BLUETOOTH_GATT: &str = "/org/chromium/bluetooth/gatt";
+
+/// Runs the Bluetooth daemon serving D-Bus IPC.
+fn main() -> Result<(), Box<dyn Error>> {
+ let (tx, rx) = Stack::create_channel();
+
+ let intf = Arc::new(Mutex::new(get_btinterface().unwrap()));
+ let bluetooth = Arc::new(Mutex::new(Box::new(Bluetooth::new(tx.clone(), intf.clone()))));
+ let bluetooth_gatt = Arc::new(Mutex::new(Box::new(BluetoothGatt::new(intf.clone()))));
+
+ // Args don't include arg[0] which is the binary name
+ let all_args = std::env::args().collect::<Vec<String>>();
+ let args = all_args[1..].to_vec();
+ intf.lock().unwrap().initialize(get_bt_dispatcher(tx), args);
+
+ bluetooth.lock().unwrap().init_profiles();
+ bluetooth.lock().unwrap().enable();
+
+ topstack::get_runtime().block_on(async {
+ // Connect to D-Bus system bus.
+ let (resource, conn) = connection::new_system_sync()?;
+
+ // The `resource` is a task that should be spawned onto a tokio compatible
+ // reactor ASAP. If the resource ever finishes, we lost connection to D-Bus.
+ topstack::get_runtime().spawn(async {
+ let err = resource.await;
+ panic!("Lost connection to D-Bus: {}", err);
+ });
+
+ // Request a service name and quit if not able to.
+ conn.request_name(DBUS_SERVICE_NAME, false, true, false).await?;
+
+ // Prepare D-Bus interfaces.
+ let mut cr = Crossroads::new();
+ cr.set_async_support(Some((
+ conn.clone(),
+ Box::new(|x| {
+ topstack::get_runtime().spawn(x);
+ }),
+ )));
+
+ // Run the stack main dispatch loop.
+ topstack::get_runtime().spawn(Stack::dispatch(rx, bluetooth.clone()));
+
+ // Set up the disconnect watcher to monitor client disconnects.
+ let disconnect_watcher = Arc::new(Mutex::new(DisconnectWatcher::new()));
+ disconnect_watcher.lock().unwrap().setup_watch(conn.clone()).await;
+
+ // Register D-Bus method handlers of IBluetooth.
+ iface_bluetooth::export_bluetooth_dbus_obj(
+ String::from(OBJECT_BLUETOOTH),
+ conn.clone(),
+ &mut cr,
+ bluetooth,
+ disconnect_watcher.clone(),
+ );
+ // Register D-Bus method handlers of IBluetoothGatt.
+ iface_bluetooth_gatt::export_bluetooth_gatt_dbus_obj(
+ String::from(OBJECT_BLUETOOTH_GATT),
+ conn.clone(),
+ &mut cr,
+ bluetooth_gatt,
+ disconnect_watcher.clone(),
+ );
+
+ conn.start_receive(
+ MatchRule::new_method_call(),
+ Box::new(move |msg, conn| {
+ cr.handle_message(msg, conn).unwrap();
+ true
+ }),
+ );
+
+ // Serve clients forever.
+ future::pending::<()>().await;
+ unreachable!()
+ })
+}
diff --git a/gd/rust/linux/stack/Cargo.toml b/gd/rust/linux/stack/Cargo.toml
new file mode 100644
index 0000000..65987e8
--- /dev/null
+++ b/gd/rust/linux/stack/Cargo.toml
@@ -0,0 +1,20 @@
+[package]
+name = "btstack"
+version = "0.1.0"
+edition = "2018"
+
+[dependencies]
+bt_topshim = { path = "../../topshim" }
+bt_shim = { path = "../../shim" }
+
+btif_macros = { path = "btif_macros" }
+
+dbus = "0.9.2"
+
+num-traits = "*"
+num-derive = "*"
+
+tokio = { version = "1", features = ['bytes', 'fs', 'io-util', 'libc', 'macros', 'memchr', 'mio', 'net', 'num_cpus', 'rt', 'rt-multi-thread', 'sync', 'time', 'tokio-macros'] }
+
+[lib]
+path = "src/lib.rs"
diff --git a/gd/rust/linux/stack/btif_macros/Cargo.toml b/gd/rust/linux/stack/btif_macros/Cargo.toml
new file mode 100644
index 0000000..1810867
--- /dev/null
+++ b/gd/rust/linux/stack/btif_macros/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "btif_macros"
+version = "0.1.0"
+edition = "2018"
+
+[lib]
+proc-macro = true
+
+[dependencies]
+syn = "1.0"
+quote = "1.0"
+proc-macro2 = "1.0"
diff --git a/gd/rust/linux/stack/btif_macros/src/lib.rs b/gd/rust/linux/stack/btif_macros/src/lib.rs
new file mode 100644
index 0000000..549c609
--- /dev/null
+++ b/gd/rust/linux/stack/btif_macros/src/lib.rs
@@ -0,0 +1,126 @@
+extern crate proc_macro;
+
+use quote::quote;
+
+use std::fs::File;
+use std::io::Write;
+use std::path::Path;
+
+use syn::parse::Parser;
+use syn::punctuated::Punctuated;
+use syn::token::Comma;
+use syn::{Expr, FnArg, ItemTrait, Meta, Pat, TraitItem};
+
+use crate::proc_macro::TokenStream;
+
+fn debug_output_to_file(gen: &proc_macro2::TokenStream, filename: String) {
+ let path = Path::new(filename.as_str());
+ let mut file = File::create(&path).unwrap();
+ file.write_all(gen.to_string().as_bytes()).unwrap();
+}
+
+/// Associates a function with a btif callback message.
+#[proc_macro_attribute]
+pub fn btif_callback(_attr: TokenStream, item: TokenStream) -> TokenStream {
+ let ori_item: proc_macro2::TokenStream = item.clone().into();
+ let gen = quote! {
+ #ori_item
+ };
+ gen.into()
+}
+
+/// Generates a dispatcher from a message to a function.
+#[proc_macro_attribute]
+pub fn btif_callbacks_dispatcher(attr: TokenStream, item: TokenStream) -> TokenStream {
+ let args = Punctuated::<Expr, Comma>::parse_separated_nonempty.parse(attr.clone()).unwrap();
+
+ let struct_ident = if let Expr::Path(p) = &args[0] {
+ p.path.get_ident().unwrap()
+ } else {
+ panic!("struct name must be specified");
+ };
+
+ let fn_ident = if let Expr::Path(p) = &args[1] {
+ p.path.get_ident().unwrap()
+ } else {
+ panic!("function name must be specified");
+ };
+
+ let callbacks_struct_ident = if let Expr::Path(p) = &args[2] {
+ p.path.get_ident().unwrap()
+ } else {
+ panic!("callbacks struct ident must be specified");
+ };
+
+ let mut dispatch_arms = quote! {};
+
+ let ast: ItemTrait = syn::parse(item.clone()).unwrap();
+
+ let mut fn_names = quote! {};
+ for attr in ast.items {
+ if let TraitItem::Method(m) = attr {
+ if m.attrs.len() != 1 {
+ continue;
+ }
+
+ let attr = &m.attrs[0];
+ if !attr.path.get_ident().unwrap().to_string().eq("btif_callback") {
+ continue;
+ }
+
+ let attr_args = attr.parse_meta().unwrap();
+ let btif_callback = if let Meta::List(meta_list) = attr_args {
+ Some(meta_list.nested[0].clone())
+ } else {
+ None
+ };
+
+ if btif_callback.is_none() {
+ continue;
+ }
+
+ let mut arg_names = quote! {};
+ for input in m.sig.inputs {
+ if let FnArg::Typed(t) = input {
+ if let Pat::Ident(i) = *t.pat {
+ let attr_name = i.ident;
+ arg_names = quote! { #arg_names #attr_name, };
+ }
+ }
+ }
+ let method_ident = m.sig.ident;
+
+ fn_names = quote! {
+ #fn_names
+ #method_ident,
+ };
+
+ dispatch_arms = quote! {
+ #dispatch_arms
+ #callbacks_struct_ident::#btif_callback(#arg_names) => {
+ self.#method_ident(#arg_names);
+ }
+ };
+ }
+ }
+
+ let ori_item = proc_macro2::TokenStream::from(item.clone());
+
+ let gen = quote! {
+ #ori_item
+ impl #struct_ident {
+ pub(crate) fn #fn_ident(&mut self, cb: #callbacks_struct_ident) {
+ match cb {
+ #dispatch_arms
+
+ _ => println!("Unhandled callback arm {:?}", cb),
+ }
+ }
+ }
+ };
+
+ // TODO: Have a simple framework to turn on/off macro-generated code debug.
+ debug_output_to_file(&gen, format!("/tmp/out-{}.rs", fn_ident.to_string()));
+
+ gen.into()
+}
diff --git a/gd/rust/linux/stack/src/bluetooth.rs b/gd/rust/linux/stack/src/bluetooth.rs
new file mode 100644
index 0000000..7cf04e5
--- /dev/null
+++ b/gd/rust/linux/stack/src/bluetooth.rs
@@ -0,0 +1,322 @@
+//! Anything related to the adapter API (IBluetooth).
+
+use bt_topshim::btif::{
+ BaseCallbacks, BaseCallbacksDispatcher, BluetoothInterface, BtBondState, BtDiscoveryState,
+ BtProperty, BtPropertyType, BtSspVariant, BtState, BtStatus, BtTransport, RawAddress,
+};
+use bt_topshim::profiles::hid_host::{HHCallbacksDispatcher, HidHost};
+use bt_topshim::topstack;
+
+use btif_macros::{btif_callback, btif_callbacks_dispatcher};
+
+use num_traits::cast::ToPrimitive;
+
+use std::sync::Arc;
+use std::sync::Mutex;
+
+use tokio::sync::mpsc::Sender;
+
+use crate::{BDAddr, Message, RPCProxy};
+
+/// Defines the adapter API.
+pub trait IBluetooth {
+ /// Adds a callback from a client who wishes to observe adapter events.
+ fn register_callback(&mut self, callback: Box<dyn IBluetoothCallback + Send>);
+
+ /// Enables the adapter.
+ ///
+ /// Returns true if the request is accepted.
+ fn enable(&mut self) -> bool;
+
+ /// Disables the adapter.
+ ///
+ /// Returns true if the request is accepted.
+ fn disable(&mut self) -> bool;
+
+ /// Returns the Bluetooth address of the local adapter.
+ fn get_address(&self) -> String;
+
+ /// Starts BREDR Inquiry.
+ fn start_discovery(&self) -> bool;
+
+ /// Cancels BREDR Inquiry.
+ fn cancel_discovery(&self) -> bool;
+
+ /// Initiates pairing to a remote device. Triggers connection if not already started.
+ fn create_bond(&self, device: BluetoothDevice, transport: BluetoothTransport) -> bool;
+}
+
+#[derive(Debug, FromPrimitive, ToPrimitive)]
+#[repr(i32)]
+pub enum BluetoothTransport {
+ Auto = 0,
+ Bredr = 1,
+ Le = 2,
+}
+
+#[derive(Debug, Default)]
+pub struct BluetoothDevice {
+ pub address: String,
+ pub name: String,
+}
+
+impl BluetoothDevice {
+ pub(crate) fn from_properties(properties: &Vec<BtProperty>) -> BluetoothDevice {
+ let mut address = String::from("");
+ let mut name = String::from("");
+
+ for prop in properties {
+ match prop.prop_type {
+ BtPropertyType::BdAddr => {
+ if let Some(addr) = BDAddr::from_byte_vec(&prop.val) {
+ address = addr.to_string();
+ }
+ }
+ BtPropertyType::BdName => {
+ name = String::from_utf8(prop.val.clone()).unwrap();
+ }
+ _ => {}
+ }
+ }
+
+ BluetoothDevice { address, name }
+ }
+}
+
+/// The interface for adapter callbacks registered through `IBluetooth::register_callback`.
+pub trait IBluetoothCallback: RPCProxy {
+ /// When any of the adapter states is changed.
+ fn on_bluetooth_state_changed(&self, prev_state: u32, new_state: u32);
+
+ /// When any of the adapter local address is changed.
+ fn on_bluetooth_address_changed(&self, addr: String);
+
+ /// When a device is found via discovery.
+ fn on_device_found(&self, remote_device: BluetoothDevice);
+
+ /// When the discovery state is changed.
+ fn on_discovering_changed(&self, discovering: bool);
+}
+
+/// Implementation of the adapter API.
+pub struct Bluetooth {
+ intf: Arc<Mutex<BluetoothInterface>>,
+ state: BtState,
+ callbacks: Vec<(u32, Box<dyn IBluetoothCallback + Send>)>,
+ callbacks_last_id: u32,
+ tx: Sender<Message>,
+ local_address: Option<BDAddr>,
+ hh: Option<HidHost>,
+}
+
+impl Bluetooth {
+ /// Constructs the IBluetooth implementation.
+ pub fn new(tx: Sender<Message>, intf: Arc<Mutex<BluetoothInterface>>) -> Bluetooth {
+ Bluetooth {
+ tx,
+ intf,
+ state: BtState::Off,
+ callbacks: vec![],
+ callbacks_last_id: 0,
+ local_address: None,
+ hh: None,
+ }
+ }
+
+ pub fn init_profiles(&mut self) {
+ self.hh = Some(HidHost::new(&self.intf.lock().unwrap()));
+ self.hh.as_mut().unwrap().initialize(HHCallbacksDispatcher {
+ dispatch: Box::new(move |_cb| {
+ // TODO("Implement the callbacks");
+ println!("received HH callback");
+ }),
+ });
+ }
+
+ fn update_local_address(&mut self, raw: &Vec<u8>) {
+ self.local_address = BDAddr::from_byte_vec(raw);
+
+ self.for_all_callbacks(|callback| {
+ callback.on_bluetooth_address_changed(self.local_address.unwrap().to_string());
+ });
+ }
+
+ fn for_all_callbacks<F: Fn(&Box<dyn IBluetoothCallback + Send>)>(&self, f: F) {
+ for callback in &self.callbacks {
+ f(&callback.1);
+ }
+ }
+
+ pub(crate) fn callback_disconnected(&mut self, id: u32) {
+ self.callbacks.retain(|x| x.0 != id);
+ }
+}
+
+#[btif_callbacks_dispatcher(Bluetooth, dispatch_base_callbacks, BaseCallbacks)]
+pub(crate) trait BtifBluetoothCallbacks {
+ #[btif_callback(AdapterState)]
+ fn adapter_state_changed(&mut self, state: BtState);
+
+ #[btif_callback(AdapterProperties)]
+ fn adapter_properties_changed(
+ &mut self,
+ status: BtStatus,
+ num_properties: i32,
+ properties: Vec<BtProperty>,
+ );
+
+ #[btif_callback(DeviceFound)]
+ fn device_found(&mut self, n: i32, properties: Vec<BtProperty>);
+
+ #[btif_callback(DiscoveryState)]
+ fn discovery_state(&mut self, state: BtDiscoveryState);
+
+ #[btif_callback(SspRequest)]
+ fn ssp_request(
+ &mut self,
+ remote_addr: RawAddress,
+ remote_name: String,
+ cod: u32,
+ variant: BtSspVariant,
+ passkey: u32,
+ );
+
+ #[btif_callback(BondState)]
+ fn bond_state(&mut self, status: BtStatus, addr: RawAddress, bond_state: BtBondState);
+}
+
+pub fn get_bt_dispatcher(tx: Sender<Message>) -> BaseCallbacksDispatcher {
+ BaseCallbacksDispatcher {
+ dispatch: Box::new(move |cb| {
+ let txl = tx.clone();
+ topstack::get_runtime().spawn(async move {
+ let _ = txl.send(Message::Base(cb)).await;
+ });
+ }),
+ }
+}
+
+impl BtifBluetoothCallbacks for Bluetooth {
+ fn adapter_state_changed(&mut self, state: BtState) {
+ self.for_all_callbacks(|callback| {
+ callback
+ .on_bluetooth_state_changed(self.state.to_u32().unwrap(), state.to_u32().unwrap())
+ });
+
+ self.state = state;
+ }
+
+ #[allow(unused_variables)]
+ fn adapter_properties_changed(
+ &mut self,
+ status: BtStatus,
+ num_properties: i32,
+ properties: Vec<BtProperty>,
+ ) {
+ if status != BtStatus::Success {
+ return;
+ }
+
+ for prop in properties {
+ match prop.prop_type {
+ BtPropertyType::BdAddr => {
+ self.update_local_address(&prop.val);
+ }
+ _ => {}
+ }
+ }
+ }
+
+ fn device_found(&mut self, _n: i32, properties: Vec<BtProperty>) {
+ self.for_all_callbacks(|callback| {
+ callback.on_device_found(BluetoothDevice::from_properties(&properties));
+ });
+ }
+
+ fn discovery_state(&mut self, state: BtDiscoveryState) {
+ self.for_all_callbacks(|callback| {
+ callback.on_discovering_changed(state == BtDiscoveryState::Started);
+ });
+ }
+
+ fn ssp_request(
+ &mut self,
+ remote_addr: RawAddress,
+ _remote_name: String,
+ _cod: u32,
+ variant: BtSspVariant,
+ passkey: u32,
+ ) {
+ // Immediately accept the pairing.
+ // TODO: Delegate the pairing confirmation to agent.
+ // TODO: Implement other pairing confirmations (passkey, passcode, etc);
+ self.intf.lock().unwrap().ssp_reply(&remote_addr, variant, 1, passkey);
+ }
+
+ fn bond_state(&mut self, _status: BtStatus, mut addr: RawAddress, bond_state: BtBondState) {
+ if bond_state == BtBondState::Bonded {
+ // We are assuming that peer is a HID device and automatically connect to that profile.
+ // TODO: Only connect to enabled profiles on that device.
+ self.hh.as_ref().unwrap().connect(&mut addr);
+ }
+ }
+}
+
+// TODO: Add unit tests for this implementation
+impl IBluetooth for Bluetooth {
+ fn register_callback(&mut self, mut callback: Box<dyn IBluetoothCallback + Send>) {
+ let tx = self.tx.clone();
+
+ // TODO: Refactor into a separate wrap-around id generator.
+ self.callbacks_last_id += 1;
+ let id = self.callbacks_last_id;
+
+ callback.register_disconnect(Box::new(move || {
+ let tx = tx.clone();
+ topstack::get_runtime().spawn(async move {
+ let _result = tx.send(Message::BluetoothCallbackDisconnected(id)).await;
+ });
+ }));
+
+ self.callbacks.push((id, callback))
+ }
+
+ fn enable(&mut self) -> bool {
+ self.intf.lock().unwrap().enable() == 0
+ }
+
+ fn disable(&mut self) -> bool {
+ self.intf.lock().unwrap().disable() == 0
+ }
+
+ fn get_address(&self) -> String {
+ match self.local_address {
+ None => String::from(""),
+ Some(addr) => addr.to_string(),
+ }
+ }
+
+ fn start_discovery(&self) -> bool {
+ self.intf.lock().unwrap().start_discovery() == 0
+ }
+
+ fn cancel_discovery(&self) -> bool {
+ self.intf.lock().unwrap().cancel_discovery() == 0
+ }
+
+ fn create_bond(&self, device: BluetoothDevice, transport: BluetoothTransport) -> bool {
+ let addr = BDAddr::from_string(device.address.clone());
+
+ if addr.is_none() {
+ println!("address {} is not valid", device.address);
+ return false;
+ }
+
+ let address = unsafe { RawAddress::new(&addr.unwrap().val) };
+ self.intf
+ .lock()
+ .unwrap()
+ .create_bond(&address, BtTransport::from(transport.to_i32().unwrap()))
+ == 0
+ }
+}
diff --git a/gd/rust/linux/stack/src/bluetooth_gatt.rs b/gd/rust/linux/stack/src/bluetooth_gatt.rs
new file mode 100644
index 0000000..4252768
--- /dev/null
+++ b/gd/rust/linux/stack/src/bluetooth_gatt.rs
@@ -0,0 +1,86 @@
+//! Anything related to the GATT API (IBluetoothGatt).
+
+use bt_topshim::btif::BluetoothInterface;
+
+use std::sync::{Arc, Mutex};
+
+/// Defines the GATT API.
+pub trait IBluetoothGatt {
+ fn register_scanner(&self, callback: Box<dyn IScannerCallback + Send>);
+
+ fn unregister_scanner(&self, scanner_id: i32);
+
+ fn start_scan(&self, scanner_id: i32, settings: ScanSettings, filters: Vec<ScanFilter>);
+ fn stop_scan(&self, scanner_id: i32);
+}
+
+/// Interface for scanner callbacks to clients, passed to `IBluetoothGatt::register_scanner`.
+pub trait IScannerCallback {
+ /// When the `register_scanner` request is done.
+ fn on_scanner_registered(&self, status: i32, scanner_id: i32);
+}
+
+#[derive(Debug, FromPrimitive, ToPrimitive)]
+#[repr(i32)]
+/// Scan type configuration.
+pub enum ScanType {
+ Active = 0,
+ Passive = 1,
+}
+
+impl Default for ScanType {
+ fn default() -> Self {
+ ScanType::Active
+ }
+}
+
+/// Represents RSSI configurations for hardware offloaded scanning.
+// TODO: This is still a placeholder struct, not yet complete.
+#[derive(Debug, Default)]
+pub struct RSSISettings {
+ pub low_threshold: i32,
+ pub high_threshold: i32,
+}
+
+/// Represents scanning configurations to be passed to `IBluetoothGatt::start_scan`.
+#[derive(Debug, Default)]
+pub struct ScanSettings {
+ pub interval: i32,
+ pub window: i32,
+ pub scan_type: ScanType,
+ pub rssi_settings: RSSISettings,
+}
+
+/// Represents a scan filter to be passed to `IBluetoothGatt::start_scan`.
+#[derive(Debug, Default)]
+pub struct ScanFilter {}
+
+/// Implementation of the GATT API (IBluetoothGatt).
+pub struct BluetoothGatt {
+ _intf: Arc<Mutex<BluetoothInterface>>,
+}
+
+impl BluetoothGatt {
+ /// Constructs a new IBluetoothGatt implementation.
+ pub fn new(intf: Arc<Mutex<BluetoothInterface>>) -> BluetoothGatt {
+ BluetoothGatt { _intf: intf }
+ }
+}
+
+impl IBluetoothGatt for BluetoothGatt {
+ fn register_scanner(&self, _callback: Box<dyn IScannerCallback + Send>) {
+ // TODO: implement
+ }
+
+ fn unregister_scanner(&self, _scanner_id: i32) {
+ // TODO: implement
+ }
+
+ fn start_scan(&self, _scanner_id: i32, _settings: ScanSettings, _filters: Vec<ScanFilter>) {
+ // TODO: implement
+ }
+
+ fn stop_scan(&self, _scanner_id: i32) {
+ // TODO: implement
+ }
+}
diff --git a/gd/rust/linux/stack/src/lib.rs b/gd/rust/linux/stack/src/lib.rs
new file mode 100644
index 0000000..489f31a
--- /dev/null
+++ b/gd/rust/linux/stack/src/lib.rs
@@ -0,0 +1,133 @@
+//! Fluoride/GD Bluetooth stack.
+//!
+//! This crate provides the API implementation of the Fluoride/GD Bluetooth stack, independent of
+//! any RPC projection.
+
+#[macro_use]
+extern crate num_derive;
+
+pub mod bluetooth;
+pub mod bluetooth_gatt;
+
+use bt_topshim::btif::BaseCallbacks;
+
+use std::convert::TryInto;
+use std::fmt::{Debug, Formatter, Result};
+use std::sync::{Arc, Mutex};
+
+use tokio::sync::mpsc::channel;
+use tokio::sync::mpsc::{Receiver, Sender};
+
+use crate::bluetooth::Bluetooth;
+
+/// Represents a Bluetooth address.
+// TODO: Add support for LE random addresses.
+#[derive(Copy, Clone)]
+pub struct BDAddr {
+ val: [u8; 6],
+}
+
+impl Debug for BDAddr {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ f.write_fmt(format_args!(
+ "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
+ self.val[0], self.val[1], self.val[2], self.val[3], self.val[4], self.val[5]
+ ))
+ }
+}
+
+impl Default for BDAddr {
+ fn default() -> Self {
+ Self { val: [0; 6] }
+ }
+}
+
+impl ToString for BDAddr {
+ fn to_string(&self) -> String {
+ String::from(format!(
+ "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
+ self.val[0], self.val[1], self.val[2], self.val[3], self.val[4], self.val[5]
+ ))
+ }
+}
+
+impl BDAddr {
+ /// Constructs a BDAddr from a vector of 6 bytes.
+ fn from_byte_vec(raw_addr: &Vec<u8>) -> Option<BDAddr> {
+ if let Ok(val) = raw_addr.clone().try_into() {
+ return Some(BDAddr { val });
+ }
+ None
+ }
+
+ fn from_string(addr_str: String) -> Option<BDAddr> {
+ let s = addr_str.split(':').collect::<Vec<&str>>();
+
+ if s.len() != 6 {
+ return None;
+ }
+
+ let mut raw: [u8; 6] = [0; 6];
+ for i in 0..s.len() {
+ raw[i] = match u8::from_str_radix(s[i], 16) {
+ Ok(res) => res,
+ Err(_) => {
+ return None;
+ }
+ };
+ }
+
+ Some(BDAddr { val: raw })
+ }
+}
+
+/// Message types that are sent to the stack main dispatch loop.
+pub enum Message {
+ Base(BaseCallbacks),
+ BluetoothCallbackDisconnected(u32),
+}
+
+/// Umbrella class for the Bluetooth stack.
+pub struct Stack {}
+
+impl Stack {
+ /// Creates an mpsc channel for passing messages to the main dispatch loop.
+ pub fn create_channel() -> (Sender<Message>, Receiver<Message>) {
+ channel::<Message>(1)
+ }
+
+ /// Runs the main dispatch loop.
+ pub async fn dispatch(mut rx: Receiver<Message>, bluetooth: Arc<Mutex<Box<Bluetooth>>>) {
+ loop {
+ let m = rx.recv().await;
+
+ if m.is_none() {
+ eprintln!("Message dispatch loop quit");
+ break;
+ }
+
+ match m.unwrap() {
+ Message::Base(b) => {
+ bluetooth.lock().unwrap().dispatch_base_callbacks(b);
+ }
+
+ Message::BluetoothCallbackDisconnected(id) => {
+ bluetooth.lock().unwrap().callback_disconnected(id);
+ }
+ }
+ }
+ }
+}
+
+/// Signifies that the object may be a proxy to a remote RPC object.
+///
+/// An object that implements RPCProxy trait signifies that the object may be a proxy to a remote
+/// RPC object. Therefore the object may be disconnected and thus should implement
+/// `register_disconnect` to let others observe the disconnection event.
+pub trait RPCProxy {
+ /// Registers disconnect observer that will be notified when the remote object is disconnected.
+ fn register_disconnect(&mut self, f: Box<dyn Fn() + Send>);
+
+ /// Returns the ID of the object. For example this would be an object path in D-Bus RPC.
+ fn get_object_id(&self) -> String;
+}
diff --git a/gd/rust/shim/Cargo.toml b/gd/rust/shim/Cargo.toml
new file mode 100644
index 0000000..a43eb41
--- /dev/null
+++ b/gd/rust/shim/Cargo.toml
@@ -0,0 +1,56 @@
+#
+# Copyright 2021 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.
+
+[package]
+name = "bt_shim"
+version = "0.0.1"
+edition = "2018"
+
+[dependencies]
+# BT dependencies
+bt_common = { path = "../common" }
+bt_facade_helpers = { path = "../facade/helpers" }
+bt_hal = { path = "../hal" }
+bt_hci = { path = "../hci" }
+bt_main = { path = "../main" }
+bt_packets = { path = "../packets" }
+
+# All external dependencies. Keep all versions at build/rust/Cargo.toml
+bindgen = "0.57"
+bytes = "1.0"
+cxx = { version = "=1.0.42", features = ["c++17"] }
+env_logger = "0.8"
+futures = "0.3"
+grpcio = { version = "0.8", features = ["protobuf", "protobuf-codec", "openssl"] }
+grpcio-sys = { version = "*", features = ["openssl"] }
+lazy_static = "1.4"
+log = "0.4"
+nix = "0.19"
+num-derive = "0.3"
+num-traits = "0.2"
+paste = "1.0"
+proc-macro2 = "1.0.24"
+protobuf = "2.0"
+protoc-grpcio = "2.0"
+protoc-rust = "2.0"
+quote = "1.0.8"
+thiserror = "1.0"
+syn = { version = "1.0.58", features = ['default', 'full'] }
+tokio = { version = "1.0", features = ['bytes', 'fs', 'io-util', 'libc', 'macros', 'memchr', 'mio', 'net', 'num_cpus', 'rt', 'rt-multi-thread', 'sync', 'time', 'tokio-macros'] }
+tokio-stream = "0.1"
+walkdir = "2.2"
+
+[lib]
+path = "src/lib.rs"
diff --git a/gd/rust/shim/src/bridge.rs b/gd/rust/shim/src/bridge.rs
index 96b35cc..aa231b9 100644
--- a/gd/rust/shim/src/bridge.rs
+++ b/gd/rust/shim/src/bridge.rs
@@ -21,11 +21,13 @@
// HCI
fn hci_set_acl_callback(hci: &mut Hci, callback: UniquePtr<u8SliceCallback>);
+ fn hci_set_iso_callback(hci: &mut Hci, callback: UniquePtr<u8SliceCallback>);
fn hci_set_evt_callback(hci: &mut Hci, callback: UniquePtr<u8SliceCallback>);
fn hci_set_le_evt_callback(hci: &mut Hci, callback: UniquePtr<u8SliceCallback>);
fn hci_send_command(hci: &mut Hci, data: &[u8], callback: UniquePtr<u8SliceOnceCallback>);
fn hci_send_acl(hci: &mut Hci, data: &[u8]);
+ fn hci_send_iso(hci: &mut Hci, data: &[u8]);
fn hci_register_event(hci: &mut Hci, event: u8);
fn hci_register_le_event(hci: &mut Hci, subevent: u8);
@@ -87,6 +89,7 @@
fn controller_get_iso_buffer_length(c: &Controller) -> u16;
fn controller_get_le_suggested_default_data_length(c: &Controller) -> u16;
fn controller_get_le_maximum_tx_data_length(c: &Controller) -> u16;
+ fn controller_get_le_maximum_tx_time(c: &Controller) -> u16;
fn controller_get_le_max_advertising_data_length(c: &Controller) -> u16;
fn controller_get_le_supported_advertising_sets(c: &Controller) -> u8;
fn controller_get_le_periodic_advertiser_list_size(c: &Controller) -> u8;
diff --git a/gd/rust/shim/src/controller.rs b/gd/rust/shim/src/controller.rs
index fbb46e1..de01bfd 100644
--- a/gd/rust/shim/src/controller.rs
+++ b/gd/rust/shim/src/controller.rs
@@ -140,6 +140,10 @@
c.le_max_data_length.supported_max_tx_octets
}
+pub fn controller_get_le_maximum_tx_time(c: &Controller) -> u16 {
+ c.le_max_data_length.supported_max_tx_time
+}
+
pub fn controller_get_address(c: &Controller) -> String {
c.address.to_string()
}
diff --git a/gd/rust/shim/src/hci.rs b/gd/rust/shim/src/hci.rs
index e0764c8..3c96ed4 100644
--- a/gd/rust/shim/src/hci.rs
+++ b/gd/rust/shim/src/hci.rs
@@ -3,7 +3,7 @@
use crate::bridge::ffi;
use bt_facade_helpers::U8SliceRunnable;
use bt_hci::facade::HciFacadeService;
-use bt_packets::hci::{AclPacket, CommandPacket, Packet};
+use bt_packets::hci::{AclPacket, CommandPacket, IsoPacket, Packet};
use std::sync::Arc;
use tokio::runtime::Runtime;
@@ -62,6 +62,18 @@
}
}
+pub fn hci_send_iso(hci: &mut Hci, data: &[u8]) {
+ match IsoPacket::parse(data) {
+ Ok(packet) => {
+ let tx = hci.internal.iso_tx.clone();
+ hci.rt.spawn(async move {
+ tx.send(packet).await.unwrap();
+ });
+ }
+ Err(e) => panic!("could not parse iso: {:?} {:02x?}", e, data),
+ }
+}
+
pub fn hci_register_event(hci: &mut Hci, event: u8) {
let mut hci_facade = hci.internal.clone();
hci.rt.spawn(async move {
@@ -80,6 +92,10 @@
hci.internal.acl_rx.stream_runnable(&hci.rt, CallbackWrapper { cb });
}
+pub fn hci_set_iso_callback(hci: &mut Hci, cb: cxx::UniquePtr<ffi::u8SliceCallback>) {
+ hci.internal.iso_rx.stream_runnable(&hci.rt, CallbackWrapper { cb });
+}
+
pub fn hci_set_evt_callback(hci: &mut Hci, cb: cxx::UniquePtr<ffi::u8SliceCallback>) {
hci.internal.evt_rx.stream_runnable(&hci.rt, CallbackWrapper { cb });
}
diff --git a/gd/rust/topshim/BUILD.gn b/gd/rust/topshim/BUILD.gn
new file mode 100644
index 0000000..fc42a6c
--- /dev/null
+++ b/gd/rust/topshim/BUILD.gn
@@ -0,0 +1,63 @@
+#
+# Copyright 2021 Google
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import("//common-mk/cxxbridge.gni")
+
+config("rust_topshim_config") {
+ include_dirs = [
+ "//bt/gd/rust/topshim"
+ ]
+}
+
+cxxbridge_header("btif_bridge_header") {
+ sources = [
+ "src/btif.rs",
+ "src/profiles/a2dp.rs"
+ ]
+ all_dependent_configs = [ ":rust_topshim_config" ]
+ deps = [":cxxlibheader"]
+}
+
+cxxbridge_cc("btif_bridge_code") {
+ sources = [
+ "src/btif.rs",
+ "src/profiles/a2dp.rs"
+ ]
+ deps = [":btif_bridge_header"]
+ configs = [ "//bt/gd:gd_defaults" ]
+}
+
+source_set("btif_cxx_bridge_code") {
+ sources = [
+ "btif/btif_shim.cc",
+ "btav/btav_shim.cc"
+ ]
+
+ deps = [":btif_bridge_header"]
+ configs += ["//bt/gd:gd_defaults"]
+}
+
+cxxbridge_libheader("cxxlibheader") {
+ deps = []
+}
+
+static_library("libbluetooth_topshim") {
+ deps = [
+ ":btif_bridge_code",
+ ":btif_cxx_bridge_code",
+ ":cxxlibheader",
+ ]
+}
diff --git a/gd/rust/topshim/Cargo.toml b/gd/rust/topshim/Cargo.toml
new file mode 100644
index 0000000..28221b3
--- /dev/null
+++ b/gd/rust/topshim/Cargo.toml
@@ -0,0 +1,46 @@
+#
+# Copyright 2021 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.
+
+[package]
+name = "bt_topshim"
+version = "0.0.1"
+edition = "2018"
+
+[dependencies]
+# BT dependencies
+bt_common = { path = "../common" }
+bt_facade_helpers = { path = "../facade/helpers" }
+bt_hal = { path = "../hal" }
+bt_hci = { path = "../hci" }
+bt_main = { path = "../main" }
+bt_packets = { path = "../packets" }
+topshim_macros = { path = "macros" }
+
+cxx = "*"
+lazy_static = "*"
+proc-macro2 = "*"
+num-derive = "*"
+num-traits = "*"
+tokio = { version = "*", features = ['bytes', 'fs', 'io-util', 'libc', 'macros', 'memchr', 'mio', 'net', 'num_cpus', 'rt', 'rt-multi-thread', 'sync', 'time', 'tokio-macros'] }
+tokio-stream = "*"
+bitflags ="*"
+
+[build-dependencies]
+bindgen = "0.57"
+pkg-config = "0.3"
+
+[lib]
+path = "src/lib.rs"
+build = "build.rs"
diff --git a/gd/rust/topshim/bindings/wrapper.h b/gd/rust/topshim/bindings/wrapper.h
new file mode 100644
index 0000000..f535180
--- /dev/null
+++ b/gd/rust/topshim/bindings/wrapper.h
@@ -0,0 +1,10 @@
+#pragma once
+
+// Base
+#include "btcore/include/hal_util.h"
+#include "include/hardware/bluetooth.h"
+
+// Profiles
+
+// Hid host profile
+#include "include/hardware/bt_hh.h"
diff --git a/gd/rust/topshim/btav/btav_shim.cc b/gd/rust/topshim/btav/btav_shim.cc
new file mode 100644
index 0000000..fa48c39
--- /dev/null
+++ b/gd/rust/topshim/btav/btav_shim.cc
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "gd/rust/topshim/btav/btav_shim.h"
+#include "include/hardware/bluetooth.h"
+
+#include "rust/cxx.h"
+#include "src/profiles/a2dp.rs.h"
+
+namespace bluetooth {
+namespace topshim {
+namespace rust {
+namespace internal {
+static A2dpIntf* g_a2dpif;
+
+namespace rusty = ::bluetooth::topshim::rust;
+
+static RustRawAddress to_rust_address(const RawAddress& address) {
+ RustRawAddress raddr;
+ std::copy(std::begin(address.address), std::end(address.address), std::begin(raddr.address));
+ return raddr;
+}
+
+static RawAddress from_rust_address(const RustRawAddress& raddr) {
+ RawAddress addr;
+ addr.FromOctets(raddr.address.data());
+ return addr;
+}
+
+static A2dpCodecConfig to_rust_codec_config(const btav_a2dp_codec_config_t& config) {
+ A2dpCodecConfig rconfig = {.codec_type = static_cast<uint8_t>(config.codec_type),
+ .codec_priority = config.codec_priority,
+ .sample_rate = static_cast<uint8_t>(config.sample_rate),
+ .bits_per_sample = static_cast<uint8_t>(config.bits_per_sample),
+ .channel_mode = static_cast<uint8_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 rconfig;
+}
+
+static btav_a2dp_codec_config_t from_rust_codec_config(const A2dpCodecConfig& rconfig) {
+ btav_a2dp_codec_config_t config = {
+ .codec_type = static_cast<btav_a2dp_codec_index_t>(rconfig.codec_type),
+ .codec_priority = static_cast<btav_a2dp_codec_priority_t>(rconfig.codec_priority),
+ .sample_rate = static_cast<btav_a2dp_codec_sample_rate_t>(rconfig.sample_rate),
+ .bits_per_sample = static_cast<btav_a2dp_codec_bits_per_sample_t>(rconfig.bits_per_sample),
+ .channel_mode = static_cast<btav_a2dp_codec_channel_mode_t>(rconfig.channel_mode),
+ .codec_specific_1 = rconfig.codec_specific_1,
+ .codec_specific_2 = rconfig.codec_specific_2,
+ .codec_specific_3 = rconfig.codec_specific_3,
+ .codec_specific_4 = rconfig.codec_specific_4,
+ };
+ return config;
+}
+
+static ::rust::Vec<A2dpCodecConfig> to_rust_codec_config_vec(const std::vector<btav_a2dp_codec_config_t>& configs) {
+ ::rust::Vec<A2dpCodecConfig> rconfigs;
+
+ for (btav_a2dp_codec_config_t c : configs) {
+ rconfigs.push_back(to_rust_codec_config(c));
+ }
+ return rconfigs;
+}
+
+static void connection_state_cb(const RawAddress& bd_addr, btav_connection_state_t state) {
+ RustRawAddress addr = to_rust_address(bd_addr);
+ rusty::connection_state_callback(addr, state);
+}
+static void audio_state_cb(const RawAddress& bd_addr, btav_audio_state_t state) {
+ RustRawAddress addr = to_rust_address(bd_addr);
+ rusty::audio_state_callback(addr, state);
+}
+static void audio_config_cb(
+ 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) {
+ RustRawAddress addr = to_rust_address(bd_addr);
+ A2dpCodecConfig cfg = to_rust_codec_config(codec_config);
+ ::rust::Vec<A2dpCodecConfig> lcaps = to_rust_codec_config_vec(codecs_local_capabilities);
+ ::rust::Vec<A2dpCodecConfig> scaps = to_rust_codec_config_vec(codecs_selectable_capabilities);
+ rusty::audio_config_callback(addr, cfg, lcaps, scaps);
+}
+static bool mandatory_codec_preferred_cb(const RawAddress& bd_addr) {
+ RustRawAddress addr = to_rust_address(bd_addr);
+ rusty::mandatory_codec_preferred_callback(addr);
+ return true;
+}
+
+btav_source_callbacks_t g_callbacks = {
+ sizeof(btav_source_callbacks_t),
+ connection_state_cb,
+ audio_state_cb,
+ audio_config_cb,
+ mandatory_codec_preferred_cb,
+};
+} // namespace internal
+
+A2dpIntf::~A2dpIntf() {
+ // TODO
+}
+
+std::unique_ptr<A2dpIntf> GetA2dpProfile(const unsigned char* btif) {
+ if (internal::g_a2dpif) std::abort();
+
+ const bt_interface_t* btif_ = reinterpret_cast<const bt_interface_t*>(btif);
+
+ auto a2dpif = std::make_unique<A2dpIntf>(
+ reinterpret_cast<const btav_source_interface_t*>(btif_->get_profile_interface("a2dp")));
+ internal::g_a2dpif = a2dpif.get();
+ return a2dpif;
+}
+
+int A2dpIntf::init() {
+ std::vector<btav_a2dp_codec_config_t> a;
+ std::vector<btav_a2dp_codec_config_t> b;
+
+ return intf_->init(&internal::g_callbacks, 1, a, b);
+}
+
+int A2dpIntf::connect(RustRawAddress bt_addr) {
+ RawAddress addr = internal::from_rust_address(bt_addr);
+ return intf_->connect(addr);
+}
+int A2dpIntf::disconnect(RustRawAddress bt_addr) {
+ RawAddress addr = internal::from_rust_address(bt_addr);
+ return intf_->disconnect(addr);
+}
+int A2dpIntf::set_silence_device(RustRawAddress bt_addr, bool silent) {
+ RawAddress addr = internal::from_rust_address(bt_addr);
+ return intf_->set_silence_device(addr, silent);
+}
+int A2dpIntf::set_active_device(RustRawAddress bt_addr) {
+ RawAddress addr = internal::from_rust_address(bt_addr);
+ return intf_->set_active_device(addr);
+}
+int A2dpIntf::config_codec(RustRawAddress bt_addr, ::rust::Vec<A2dpCodecConfig> codec_preferences) {
+ RawAddress addr = internal::from_rust_address(bt_addr);
+ std::vector<btav_a2dp_codec_config_t> prefs;
+ for (int i = 0; i < codec_preferences.size(); ++i) {
+ prefs.push_back(internal::from_rust_codec_config(codec_preferences[i]));
+ }
+ return intf_->config_codec(addr, prefs);
+}
+
+} // namespace rust
+} // namespace topshim
+} // namespace bluetooth
diff --git a/gd/rust/topshim/btav/btav_shim.h b/gd/rust/topshim/btav/btav_shim.h
new file mode 100644
index 0000000..3fc4afc
--- /dev/null
+++ b/gd/rust/topshim/btav/btav_shim.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GD_RUST_TOPSHIM_BTAV_BTAV_SHIM_H
+#define GD_RUST_TOPSHIM_BTAV_BTAV_SHIM_H
+
+#include "include/hardware/bt_av.h"
+
+#include "rust/cxx.h"
+
+namespace bluetooth {
+namespace topshim {
+namespace rust {
+
+struct A2dpCodecConfig;
+struct RustRawAddress;
+
+class A2dpIntf {
+ public:
+ A2dpIntf(const btav_source_interface_t* intf) : intf_(intf){};
+ ~A2dpIntf();
+
+ int init();
+ int connect(RustRawAddress bt_addr);
+ int disconnect(RustRawAddress bt_addr);
+ int set_silence_device(RustRawAddress bt_addr, bool silent);
+ int set_active_device(RustRawAddress bt_addr);
+ int config_codec(RustRawAddress bt_addr, ::rust::Vec<A2dpCodecConfig> codec_preferences);
+ void cleanup();
+
+ private:
+ const btav_source_interface_t* intf_;
+};
+
+std::unique_ptr<A2dpIntf> GetA2dpProfile(const unsigned char* btif);
+
+} // namespace rust
+} // namespace topshim
+} // namespace bluetooth
+
+#endif // GD_RUST_TOPSHIM_BTAV_BTAV_SHIM_H
diff --git a/gd/rust/topshim/btif/btif_shim.cc b/gd/rust/topshim/btif/btif_shim.cc
new file mode 100644
index 0000000..e9f53fa
--- /dev/null
+++ b/gd/rust/topshim/btif/btif_shim.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "gd/rust/topshim/btif/btif_shim.h"
+
+#include <algorithm>
+#include <cstdlib>
+#include <cstring>
+#include <memory>
+
+#include "rust/cxx.h"
+#include "src/btif.rs.h"
+
+namespace bluetooth {
+namespace topshim {
+namespace rust {
+
+InitFlags::InitFlags() {}
+InitFlags::~InitFlags() {
+ if (flags_) {
+ for (int i = 0; flags_[i] != nullptr; ++i) {
+ std::free(const_cast<void*>(static_cast<const void*>(flags_[i])));
+ }
+
+ std::free(const_cast<void*>(static_cast<const void*>(flags_)));
+ }
+}
+
+void InitFlags::Convert(::rust::Vec<::rust::String>& initFlags) {
+ // Allocate number of flags + 1 (last entry must be null to signify end)
+ // Must be calloc so our cleanup correctly frees everything
+ flags_ = static_cast<const char**>(std::calloc(initFlags.size() + 1, sizeof(char*)));
+ if (!flags_) return;
+
+ for (int i = 0; i < initFlags.size(); ++i) {
+ flags_[i] = strndup(initFlags[i].data(), initFlags[i].size());
+ if (!flags_[i]) {
+ return;
+ }
+ }
+}
+
+std::unique_ptr<InitFlags> ConvertFlags(::rust::Vec<::rust::String> flags) {
+ auto ret = std::make_unique<InitFlags>();
+ ret->Convert(flags);
+
+ return ret;
+}
+
+} // namespace rust
+} // namespace topshim
+} // namespace bluetooth
diff --git a/gd/rust/topshim/btif/btif_shim.h b/gd/rust/topshim/btif/btif_shim.h
new file mode 100644
index 0000000..c1a2684
--- /dev/null
+++ b/gd/rust/topshim/btif/btif_shim.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GD_RUST_TOPSHIM_BTIF_BTIF_SHIM_H
+#define GD_RUST_TOPSHIM_BTIF_BTIF_SHIM_H
+
+#include <memory>
+
+#include "rust/cxx.h"
+
+namespace bluetooth {
+namespace topshim {
+namespace rust {
+
+class InitFlags {
+ public:
+ InitFlags();
+ ~InitFlags();
+
+ void Convert(::rust::Vec<::rust::String>& flags);
+ const char** GetFlagsPtr() const {
+ return flags_;
+ }
+
+ private:
+ const char** flags_;
+};
+
+std::unique_ptr<InitFlags> ConvertFlags(::rust::Vec<::rust::String> flags);
+
+} // namespace rust
+} // namespace topshim
+} // namespace bluetooth
+
+#endif // GD_RUST_TOPSHIM_BTIF_BTIF_SHIM_H
diff --git a/gd/rust/topshim/build.rs b/gd/rust/topshim/build.rs
new file mode 100644
index 0000000..69f0b2d
--- /dev/null
+++ b/gd/rust/topshim/build.rs
@@ -0,0 +1,56 @@
+extern crate bindgen;
+
+use pkg_config::Config;
+use std::env;
+use std::path::PathBuf;
+
+fn main() {
+ // Re-run build if any of these change
+ println!("cargo:rerun-if-changed=bindings/wrapper.h");
+ println!("cargo:rerun-if-changed=build.rs");
+
+ // We need to configure libchrome and libmodp_b64 settings as well
+ let libchrome = Config::new().probe("libchrome").unwrap();
+ let libchrome_paths = libchrome
+ .include_paths
+ .iter()
+ .map(|p| format!("-I{}", p.to_str().unwrap()))
+ .collect::<Vec<String>>();
+
+ let search_root = env::var("CXX_ROOT_PATH").unwrap();
+ let paths = vec!["/", "/include", "/include/hardware", "/types"];
+
+ let bt_searches =
+ paths.iter().map(|tail| format!("-I{}{}", search_root, tail)).collect::<Vec<String>>();
+
+ // "-x" and "c++" must be separate due to a bug
+ let clang_args: Vec<&str> = vec!["-x", "c++", "-std=c++17"];
+
+ // The bindgen::Builder is the main entry point
+ // to bindgen, and lets you build up options for
+ // the resulting bindings.
+ let bindings = bindgen::Builder::default()
+ .clang_args(bt_searches)
+ .clang_args(libchrome_paths)
+ .clang_args(clang_args)
+ .enable_cxx_namespaces()
+ .whitelist_type("(bt_|bthh_).*")
+ .whitelist_function("(bt_|bthh_).*")
+ .whitelist_function("hal_util_.*")
+ // We must opaque out std:: in order to prevent bindgen from choking
+ .opaque_type("std::.*")
+ // Whitelist std::string though because we use it a lot
+ .whitelist_type("std::string")
+ .rustfmt_bindings(true)
+ .derive_debug(true)
+ .derive_partialeq(true)
+ .derive_eq(true)
+ .derive_default(true)
+ .header("bindings/wrapper.h")
+ .generate()
+ .expect("Unable to generate bindings");
+
+ // Write the bindings to the $OUT_DIR/bindings.rs file.
+ let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
+ bindings.write_to_file(out_path.join("bindings.rs")).expect("Couldn't write bindings!");
+}
diff --git a/gd/rust/topshim/macros/Cargo.toml b/gd/rust/topshim/macros/Cargo.toml
new file mode 100644
index 0000000..4278e14
--- /dev/null
+++ b/gd/rust/topshim/macros/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "topshim_macros"
+version = "0.1.0"
+edition = "2018"
+
+[lib]
+proc-macro = true
+
+[dependencies]
+syn = "1.0"
+quote = "1.0"
+proc-macro2 = "1.0"
diff --git a/gd/rust/topshim/macros/src/lib.rs b/gd/rust/topshim/macros/src/lib.rs
new file mode 100644
index 0000000..7e74735
--- /dev/null
+++ b/gd/rust/topshim/macros/src/lib.rs
@@ -0,0 +1,111 @@
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+use quote::{format_ident, quote};
+use syn::parse::{Parse, ParseStream, Result};
+use syn::{parse_macro_input, Block, Ident, Path, Stmt, Token, Type};
+
+/// Parsed structure for callback variant
+struct CbVariant {
+ dispatcher: Type,
+ fn_pair: (Ident, Path),
+ arg_pairs: Vec<(Type, Type)>,
+ stmts: Vec<Stmt>,
+}
+
+impl Parse for CbVariant {
+ fn parse(input: ParseStream) -> Result<Self> {
+ // First thing should be the dispatcher
+ let dispatcher: Type = input.parse()?;
+ input.parse::<Token![,]>()?;
+
+ // Name and return type are parsed
+ let name: Ident = input.parse()?;
+ input.parse::<Token![->]>()?;
+ let rpath: Path = input.parse()?;
+
+ let mut arg_pairs: Vec<(Type, Type)> = Vec::new();
+ let mut stmts: Vec<Stmt> = Vec::new();
+
+ while input.peek(Token![,]) {
+ // Discard the comma
+ input.parse::<Token![,]>()?;
+
+ // Check if we're expecting the final Block
+ if input.peek(syn::token::Brace) {
+ let block: Block = input.parse()?;
+ stmts.extend(block.stmts);
+
+ break;
+ }
+
+ // Grab the next type argument
+ let start_type: Type = input.parse()?;
+
+ if input.peek(Token![->]) {
+ // Discard ->
+ input.parse::<Token![->]>()?;
+
+ let end_type: Type = input.parse()?;
+
+ arg_pairs.push((start_type, end_type))
+ } else {
+ arg_pairs.push((start_type.clone(), start_type));
+ }
+ }
+
+ // If the parse stream isn't empty or a comma, we have an error
+ if !input.is_empty() || !input.peek(Token![,]) {
+ ()
+ }
+
+ Ok(CbVariant { dispatcher, fn_pair: (name, rpath), arg_pairs, stmts })
+ }
+}
+
+#[proc_macro]
+/// Implement C function to convert callback into enum variant.
+///
+/// Expected syntax:
+/// cb_variant(DispatcherType, function_name -> EnumType::Variant, args..., {
+/// // Statements (maybe converting types)
+/// // Args in order will be _0, _1, etc.
+/// })
+pub fn cb_variant(input: TokenStream) -> TokenStream {
+ let parsed_cptr = parse_macro_input!(input as CbVariant);
+
+ let dispatcher = parsed_cptr.dispatcher;
+ let (ident, rpath) = parsed_cptr.fn_pair;
+
+ let mut params = proc_macro2::TokenStream::new();
+ let mut args = proc_macro2::TokenStream::new();
+ for (i, (start, end)) in parsed_cptr.arg_pairs.iter().enumerate() {
+ let ident = format_ident!("_{}", i);
+ params.extend(quote! { #ident: #start, });
+
+ // Argument needs an into translation if it doesn't match the start
+ if start != end {
+ args.extend(quote! { #end::from(#ident), });
+ } else {
+ args.extend(quote! {#ident,});
+ }
+ }
+
+ let mut stmts = proc_macro2::TokenStream::new();
+ for stmt in parsed_cptr.stmts {
+ stmts.extend(quote! { #stmt });
+ }
+
+ let tokens = quote! {
+ #[no_mangle]
+ extern "C" fn #ident(#params) {
+ #stmts
+
+ unsafe {
+ (get_dispatchers().lock().unwrap().get::<#dispatcher>().unwrap().clone().lock().unwrap().dispatch)(#rpath(#args));
+ }
+ }
+ };
+
+ TokenStream::from(tokens)
+}
diff --git a/gd/rust/topshim/src/bindings.rs b/gd/rust/topshim/src/bindings.rs
new file mode 100644
index 0000000..a38a13a
--- /dev/null
+++ b/gd/rust/topshim/src/bindings.rs
@@ -0,0 +1,5 @@
+#![allow(non_upper_case_globals)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+
+include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
diff --git a/gd/rust/topshim/src/btif.rs b/gd/rust/topshim/src/btif.rs
new file mode 100644
index 0000000..680436d
--- /dev/null
+++ b/gd/rust/topshim/src/btif.rs
@@ -0,0 +1,534 @@
+//! Bluetooth interface shim
+//!
+//! This is a shim interface for calling the C++ bluetooth interface via Rust.
+//!
+
+use crate::bindings::root as bindings;
+use crate::topstack::get_dispatchers;
+use num_traits::cast::{FromPrimitive, ToPrimitive};
+use std::sync::{Arc, Mutex};
+use std::vec::Vec;
+use topshim_macros::cb_variant;
+
+#[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
+#[repr(u32)]
+pub enum BtState {
+ Off = 0,
+ On,
+}
+
+impl From<bindings::bt_state_t> for BtState {
+ fn from(item: bindings::bt_state_t) -> Self {
+ BtState::from_u32(item).unwrap_or_else(|| BtState::Off)
+ }
+}
+
+#[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
+#[repr(u32)]
+pub enum BtTransport {
+ Invalid = 0,
+ Bredr,
+ Le,
+}
+
+impl From<i32> for BtTransport {
+ fn from(item: i32) -> Self {
+ BtTransport::from_i32(item).unwrap_or_else(|| BtTransport::Invalid)
+ }
+}
+
+impl From<BtTransport> for i32 {
+ fn from(item: BtTransport) -> Self {
+ item.to_i32().unwrap_or_else(|| 0)
+ }
+}
+
+#[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
+#[repr(u32)]
+pub enum BtSspVariant {
+ PasskeyConfirmation = 0,
+ PasskeyEntry,
+ Consent,
+ PasskeyNotification,
+}
+
+impl From<bindings::bt_ssp_variant_t> for BtSspVariant {
+ fn from(item: bindings::bt_ssp_variant_t) -> Self {
+ BtSspVariant::from_u32(item).unwrap_or_else(|| BtSspVariant::PasskeyConfirmation)
+ }
+}
+
+impl From<BtSspVariant> for bindings::bt_ssp_variant_t {
+ fn from(item: BtSspVariant) -> Self {
+ item.to_u32().unwrap_or_else(|| 0)
+ }
+}
+
+#[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
+#[repr(u32)]
+pub enum BtBondState {
+ Unknown = 0,
+ Bonding,
+ Bonded,
+}
+
+impl From<bindings::bt_bond_state_t> for BtBondState {
+ fn from(item: bindings::bt_bond_state_t) -> Self {
+ BtBondState::from_u32(item).unwrap_or_else(|| BtBondState::Unknown)
+ }
+}
+
+#[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
+#[repr(u32)]
+pub enum BtAclState {
+ Connected = 0,
+ Disconnected,
+}
+
+impl From<bindings::bt_acl_state_t> for BtAclState {
+ fn from(item: bindings::bt_acl_state_t) -> Self {
+ BtAclState::from_u32(item).unwrap_or_else(|| BtAclState::Disconnected)
+ }
+}
+
+#[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
+#[repr(u32)]
+pub enum BtDeviceType {
+ Bredr,
+ Ble,
+ Dual,
+}
+
+#[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
+#[repr(u32)]
+pub enum BtPropertyType {
+ BdName = 0x1,
+ BdAddr,
+ Uuids,
+ ClassOfDevice,
+ TypeOfDevice,
+ ServiceRecord,
+ AdapterScanMode,
+ AdapterBondedDevices,
+ AdapterDiscoveryTimeout,
+ RemoteFriendlyName,
+ RemoteRssi,
+ RemoteVersionInfo,
+ LocalLeFeatures,
+ LocalIoCaps,
+ LocalIoCapsBle,
+ DynamicAudioBuffer,
+
+ Unknown = 0xFE,
+ RemoteDeviceTimestamp = 0xFF,
+}
+
+impl From<u32> for BtPropertyType {
+ fn from(item: u32) -> Self {
+ BtPropertyType::from_u32(item).unwrap_or_else(|| BtPropertyType::Unknown)
+ }
+}
+
+impl From<BtPropertyType> for u32 {
+ fn from(item: BtPropertyType) -> Self {
+ item.to_u32().unwrap_or_else(|| 0)
+ }
+}
+
+#[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
+#[repr(i32)]
+pub enum BtDiscoveryState {
+ Stopped = 0x0,
+ Started,
+}
+
+impl From<u32> for BtDiscoveryState {
+ fn from(item: u32) -> Self {
+ BtDiscoveryState::from_u32(item).unwrap_or_else(|| BtDiscoveryState::Stopped)
+ }
+}
+
+#[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
+#[repr(u32)]
+pub enum BtStatus {
+ Success = 0,
+ Fail,
+ NotReady,
+ NoMemory,
+ Busy,
+ Done,
+ Unsupported,
+ InvalidParam,
+ Unhandled,
+ AuthFailure,
+ RemoteDeviceDown,
+ AuthRejected,
+ JniEnvironmentError,
+ JniThreadAttachError,
+ WakeLockError,
+
+ // Any statuses that couldn't be cleanly converted
+ Unknown = 0xff,
+}
+
+impl From<bindings::bt_status_t> for BtStatus {
+ fn from(item: bindings::bt_status_t) -> Self {
+ match BtStatus::from_u32(item) {
+ Some(x) => x,
+ _ => BtStatus::Unknown,
+ }
+ }
+}
+
+#[derive(Debug, Clone)]
+pub struct BtProperty {
+ pub prop_type: BtPropertyType,
+ pub len: i32,
+ pub val: Vec<u8>,
+}
+
+fn convert_properties(count: i32, props: *const bindings::bt_property_t) -> Vec<BtProperty> {
+ let mut ret: Vec<BtProperty> = Vec::new();
+
+ for i in 0..isize::from_i32(count).unwrap() {
+ let prop: *const bindings::bt_property_t = unsafe { props.offset(i) };
+ let converted = BtProperty::from(unsafe { *prop });
+
+ ret.push(converted)
+ }
+
+ ret
+}
+
+impl From<bindings::bt_property_t> for BtProperty {
+ fn from(item: bindings::bt_property_t) -> Self {
+ let slice: &[u8] =
+ unsafe { std::slice::from_raw_parts(item.val as *mut u8, item.len as usize) };
+ let mut val = Vec::new();
+ val.extend_from_slice(slice);
+
+ BtProperty { prop_type: BtPropertyType::from(item.type_), len: item.len, val }
+ }
+}
+
+impl From<BtProperty> for bindings::bt_property_t {
+ fn from(item: BtProperty) -> Self {
+ // This is probably very unsafe
+ let mut foo = item.clone();
+ bindings::bt_property_t {
+ type_: item.prop_type.to_u32().unwrap(),
+ len: foo.val.len() as i32,
+ val: foo.val.as_mut_ptr() as *mut std::os::raw::c_void,
+ }
+ }
+}
+
+impl From<bindings::bt_bdname_t> for String {
+ fn from(item: bindings::bt_bdname_t) -> Self {
+ std::str::from_utf8(&item.name).unwrap().to_string()
+ }
+}
+
+pub type BtHciErrorCode = u8;
+
+pub type BtPinCode = bindings::bt_pin_code_t;
+
+pub enum SupportedProfiles {
+ HidHost,
+ A2dp,
+}
+
+impl From<SupportedProfiles> for Vec<u8> {
+ fn from(item: SupportedProfiles) -> Self {
+ match item {
+ SupportedProfiles::HidHost => "hidhost".bytes().collect::<Vec<u8>>(),
+ SupportedProfiles::A2dp => "a2dp".bytes().collect::<Vec<u8>>(),
+ }
+ }
+}
+
+#[cxx::bridge(namespace = bluetooth::topshim::rust)]
+mod ffi {
+ unsafe extern "C++" {
+ include!("btif/btif_shim.h");
+
+ // For converting init flags from Vec<String> to const char **
+ type InitFlags;
+
+ // Convert flgas into an InitFlags object
+ fn ConvertFlags(flags: Vec<String>) -> UniquePtr<InitFlags>;
+ fn GetFlagsPtr(self: &InitFlags) -> *mut *const c_char;
+ }
+}
+
+// Export the raw address type directly from the bindings
+pub type RawAddress = bindings::RawAddress;
+
+#[derive(Debug)]
+pub enum BaseCallbacks {
+ AdapterState(BtState),
+ AdapterProperties(BtStatus, i32, Vec<BtProperty>),
+ RemoteDeviceProperties(BtStatus, RawAddress, i32, Vec<BtProperty>),
+ DeviceFound(i32, Vec<BtProperty>),
+ DiscoveryState(BtDiscoveryState),
+ PinRequest(RawAddress, String, u32, bool),
+ SspRequest(RawAddress, String, u32, BtSspVariant, u32),
+ BondState(BtStatus, RawAddress, BtBondState),
+ AclState(BtStatus, RawAddress, BtAclState, BtHciErrorCode),
+ // Unimplemented so far:
+ // thread_evt_cb
+ // dut_mode_recv_cb
+ // le_test_mode_cb
+ // energy_info_cb
+ // link_quality_report_cb
+ // generate_local_oob_data_cb
+}
+
+pub struct BaseCallbacksDispatcher {
+ pub dispatch: Box<dyn Fn(BaseCallbacks) + Send>,
+}
+
+type BaseCb = Arc<Mutex<BaseCallbacksDispatcher>>;
+
+cb_variant!(BaseCb, adapter_state_cb -> BaseCallbacks::AdapterState, u32 -> BtState);
+cb_variant!(BaseCb, adapter_properties_cb -> BaseCallbacks::AdapterProperties,
+u32 -> BtStatus, i32, *mut bindings::bt_property_t, {
+ let _2 = convert_properties(_1, _2);
+});
+cb_variant!(BaseCb, remote_device_properties_cb -> BaseCallbacks::RemoteDeviceProperties,
+u32 -> BtStatus, *mut RawAddress -> RawAddress, i32, *mut bindings::bt_property_t, {
+ let _1 = unsafe {*_1};
+ let _3 = convert_properties(_2, _3);
+});
+cb_variant!(BaseCb, device_found_cb -> BaseCallbacks::DeviceFound,
+i32, *mut bindings::bt_property_t, {
+ let _1 = convert_properties(_0, _1);
+});
+cb_variant!(BaseCb, discovery_state_cb -> BaseCallbacks::DiscoveryState,
+ bindings::bt_discovery_state_t -> BtDiscoveryState);
+cb_variant!(BaseCb, pin_request_cb -> BaseCallbacks::PinRequest,
+*mut RawAddress, *mut bindings::bt_bdname_t, u32, bool, {
+ let _0 = unsafe { *_0 };
+ let _1 = String::from(unsafe{*_1});
+});
+cb_variant!(BaseCb, ssp_request_cb -> BaseCallbacks::SspRequest,
+*mut RawAddress, *mut bindings::bt_bdname_t, u32, bindings::bt_ssp_variant_t -> BtSspVariant, u32, {
+ let _0 = unsafe {*_0};
+ let _1 = String::from(unsafe{*_1});
+});
+cb_variant!(BaseCb, bond_state_cb -> BaseCallbacks::BondState,
+u32 -> BtStatus, *mut RawAddress, bindings::bt_bond_state_t -> BtBondState, {
+ let _1 = unsafe {*_1};
+});
+cb_variant!(BaseCb, acl_state_cb -> BaseCallbacks::AclState,
+u32 -> BtStatus, *mut RawAddress, bindings::bt_acl_state_t -> BtAclState, bindings::bt_hci_error_code_t -> BtHciErrorCode, {
+ let _1 = unsafe { *_1 };
+});
+
+struct RawInterfaceWrapper {
+ pub raw: *const bindings::bt_interface_t,
+}
+
+unsafe impl Send for RawInterfaceWrapper {}
+
+pub struct BluetoothInterface {
+ internal: RawInterfaceWrapper,
+ pub is_init: bool,
+ // Need to take ownership of callbacks so it doesn't get freed after init
+ callbacks: Option<Box<bindings::bt_callbacks_t>>,
+}
+
+#[macro_export]
+macro_rules! ccall {
+ ($self:ident,$fn_name:ident) => {
+ unsafe {
+ ((*$self.internal.raw).$fn_name.unwrap())()
+ }
+ };
+ ($self:ident,$fn_name:ident, $($args:expr),*) => {
+ unsafe {
+ ((*$self.internal.raw).$fn_name.unwrap())($($args),*)
+ }
+ }
+}
+
+impl BluetoothInterface {
+ pub fn is_initialized(&self) -> bool {
+ self.is_init
+ }
+
+ pub fn initialize(
+ &mut self,
+ callbacks: BaseCallbacksDispatcher,
+ init_flags: Vec<String>,
+ ) -> bool {
+ // Init flags need to be converted from string to null terminated bytes
+ let converted: cxx::UniquePtr<ffi::InitFlags> = ffi::ConvertFlags(init_flags);
+ let flags = (*converted).GetFlagsPtr();
+
+ if get_dispatchers().lock().unwrap().set::<BaseCb>(Arc::new(Mutex::new(callbacks))) {
+ panic!("Tried to set dispatcher for BaseCallbacks but it already existed");
+ }
+
+ // Fill up callbacks struct to pass to init function (will be copied so
+ // no need to worry about ownership)
+ let mut callbacks = Box::new(bindings::bt_callbacks_t {
+ size: 16 * 8,
+ adapter_state_changed_cb: Some(adapter_state_cb),
+ adapter_properties_cb: Some(adapter_properties_cb),
+ remote_device_properties_cb: Some(remote_device_properties_cb),
+ device_found_cb: Some(device_found_cb),
+ discovery_state_changed_cb: Some(discovery_state_cb),
+ pin_request_cb: Some(pin_request_cb),
+ ssp_request_cb: Some(ssp_request_cb),
+ bond_state_changed_cb: Some(bond_state_cb),
+ acl_state_changed_cb: Some(acl_state_cb),
+ thread_evt_cb: None,
+ dut_mode_recv_cb: None,
+ le_test_mode_cb: None,
+ energy_info_cb: None,
+ link_quality_report_cb: None,
+ generate_local_oob_data_cb: None,
+ });
+
+ let rawcb: *mut bindings::bt_callbacks_t = &mut *callbacks;
+
+ let (guest_mode, is_common_criteria_mode, config_compare_result, is_atv) =
+ (false, false, 0, false);
+
+ let init = ccall!(
+ self,
+ init,
+ rawcb,
+ guest_mode,
+ is_common_criteria_mode,
+ config_compare_result,
+ flags,
+ is_atv
+ );
+
+ self.is_init = init == 0;
+ self.callbacks = Some(callbacks);
+
+ return self.is_init;
+ }
+
+ pub fn cleanup(&self) {
+ ccall!(self, cleanup)
+ }
+
+ pub fn enable(&self) -> i32 {
+ ccall!(self, enable)
+ }
+
+ pub fn disable(&self) -> i32 {
+ ccall!(self, disable)
+ }
+
+ pub fn get_adapter_properties(&self) -> i32 {
+ ccall!(self, get_adapter_properties)
+ }
+
+ pub fn get_adapter_property(&self, prop: BtPropertyType) -> i32 {
+ let converted_type = bindings::bt_property_type_t::from(prop);
+ ccall!(self, get_adapter_property, converted_type)
+ }
+
+ pub fn set_adapter_property(&self, prop: BtProperty) -> i32 {
+ let converted_prop = bindings::bt_property_t::from(prop);
+ ccall!(self, set_adapter_property, &converted_prop)
+ }
+
+ pub fn get_remote_device_properties(&self, addr: &mut RawAddress) -> i32 {
+ ccall!(self, get_remote_device_properties, addr)
+ }
+
+ pub fn get_remote_device_property(
+ &self,
+ addr: &mut RawAddress,
+ prop_type: BtPropertyType,
+ ) -> i32 {
+ let converted_type = bindings::bt_property_type_t::from(prop_type);
+ ccall!(self, get_remote_device_property, addr, converted_type)
+ }
+
+ pub fn set_remote_device_property(&self, addr: &mut RawAddress, prop: BtProperty) -> i32 {
+ let converted_prop = bindings::bt_property_t::from(prop);
+ ccall!(self, set_remote_device_property, addr, &converted_prop)
+ }
+
+ pub fn start_discovery(&self) -> i32 {
+ ccall!(self, start_discovery)
+ }
+
+ pub fn cancel_discovery(&self) -> i32 {
+ ccall!(self, cancel_discovery)
+ }
+
+ pub fn create_bond(&self, addr: &RawAddress, transport: BtTransport) -> i32 {
+ let ctransport: i32 = transport.into();
+ ccall!(self, create_bond, addr, ctransport)
+ }
+
+ pub fn remove_bond(&self, addr: &RawAddress) -> i32 {
+ ccall!(self, remove_bond, addr)
+ }
+
+ pub fn cancel_bond(&self, addr: &RawAddress) -> i32 {
+ ccall!(self, cancel_bond, addr)
+ }
+
+ pub fn get_connection_state(&self, addr: &RawAddress) -> i32 {
+ ccall!(self, get_connection_state, addr)
+ }
+
+ pub fn pin_reply(
+ &self,
+ addr: &RawAddress,
+ accept: u8,
+ pin_len: u8,
+ pin_code: &mut BtPinCode,
+ ) -> i32 {
+ ccall!(self, pin_reply, addr, accept, pin_len, pin_code)
+ }
+
+ pub fn ssp_reply(
+ &self,
+ addr: &RawAddress,
+ variant: BtSspVariant,
+ accept: u8,
+ passkey: u32,
+ ) -> i32 {
+ let cvariant = bindings::bt_ssp_variant_t::from(variant);
+ ccall!(self, ssp_reply, addr, cvariant, accept, passkey)
+ }
+
+ pub(crate) fn get_profile_interface(
+ &self,
+ profile: SupportedProfiles,
+ ) -> *const std::os::raw::c_void {
+ let cprofile = Vec::<u8>::from(profile);
+ ccall!(self, get_profile_interface, cprofile.as_slice().as_ptr() as *const i8)
+ }
+
+ pub(crate) fn as_raw_ptr(&self) -> *const u8 {
+ self.internal.raw as *const u8
+ }
+}
+
+pub fn get_btinterface() -> Option<BluetoothInterface> {
+ let mut ret: Option<BluetoothInterface> = None;
+ let mut ifptr: *const bindings::bt_interface_t = std::ptr::null();
+
+ unsafe {
+ if bindings::hal_util_load_bt_library(&mut ifptr) == 0 {
+ ret = Some(BluetoothInterface {
+ internal: RawInterfaceWrapper { raw: ifptr },
+ is_init: false,
+ callbacks: None,
+ });
+ }
+ }
+
+ ret
+}
diff --git a/gd/rust/topshim/src/lib.rs b/gd/rust/topshim/src/lib.rs
new file mode 100644
index 0000000..a28f2aa
--- /dev/null
+++ b/gd/rust/topshim/src/lib.rs
@@ -0,0 +1,12 @@
+//! The main entry point for Rust to C++.
+#[macro_use]
+extern crate lazy_static;
+#[macro_use]
+extern crate num_derive;
+#[macro_use]
+extern crate bitflags;
+
+pub mod bindings;
+pub mod btif;
+pub mod profiles;
+pub mod topstack;
diff --git a/gd/rust/topshim/src/profiles/a2dp.rs b/gd/rust/topshim/src/profiles/a2dp.rs
new file mode 100644
index 0000000..b73482b
--- /dev/null
+++ b/gd/rust/topshim/src/profiles/a2dp.rs
@@ -0,0 +1,223 @@
+use crate::btif::BluetoothInterface;
+use crate::topstack::get_dispatchers;
+
+use num_traits::cast::FromPrimitive;
+use std::sync::{Arc, Mutex};
+use topshim_macros::cb_variant;
+
+#[derive(Debug, FromPrimitive, PartialEq, PartialOrd)]
+#[repr(u32)]
+pub enum BtavConnectionState {
+ Disconnected = 0,
+ Connecting,
+ Connected,
+ Disconnecting,
+}
+
+impl From<u32> for BtavConnectionState {
+ fn from(item: u32) -> Self {
+ BtavConnectionState::from_u32(item).unwrap()
+ }
+}
+
+#[derive(Debug, FromPrimitive, PartialEq, PartialOrd)]
+#[repr(u32)]
+pub enum BtavAudioState {
+ RemoteSuspend = 0,
+ Stopped,
+ Started,
+}
+
+impl From<u32> for BtavAudioState {
+ fn from(item: u32) -> Self {
+ BtavAudioState::from_u32(item).unwrap()
+ }
+}
+
+#[derive(Debug, FromPrimitive, PartialEq, PartialOrd)]
+#[repr(u32)]
+pub enum A2dpCodecIndex {
+ SrcSbc = 0,
+ SrcAac,
+ SrcAptx,
+ SrcAptxHD,
+ SrcLdac,
+ SinkSbc,
+ SinkAac,
+ SinkLdac,
+ Max,
+}
+
+impl A2dpCodecIndex {
+ pub const SRC_MIN: A2dpCodecIndex = A2dpCodecIndex::SrcSbc;
+ pub const SRC_MAX: A2dpCodecIndex = A2dpCodecIndex::SinkSbc;
+ pub const SINK_MIN: A2dpCodecIndex = A2dpCodecIndex::SinkSbc;
+ pub const SINK_MAX: A2dpCodecIndex = A2dpCodecIndex::Max;
+ pub const MAX: A2dpCodecIndex = A2dpCodecIndex::Max;
+ pub const MIN: A2dpCodecIndex = A2dpCodecIndex::SrcSbc;
+}
+
+impl From<u32> for A2dpCodecIndex {
+ fn from(item: u32) -> Self {
+ A2dpCodecIndex::from_u32(item).unwrap_or_else(|| A2dpCodecIndex::MIN)
+ }
+}
+
+#[derive(Debug, FromPrimitive, PartialEq, PartialOrd)]
+#[repr(i32)]
+pub enum A2dpCodecPriority {
+ Disabled = -1,
+ Default = 0,
+ Highest = 1000_000,
+}
+
+impl From<i32> for A2dpCodecPriority {
+ fn from(item: i32) -> Self {
+ A2dpCodecPriority::from_i32(item).unwrap_or_else(|| A2dpCodecPriority::Default)
+ }
+}
+
+bitflags! {
+ struct A2dpCodecSampleRate: u32 {
+ const RATE_NONE = 0x0;
+ const RATE_44100 = 0x01;
+ const RATE_48000 = 0x02;
+ const RATE_88200 = 0x04;
+ const RATE_96000 = 0x08;
+ const RATE_176400 = 0x10;
+ const RATE_192000 = 0x20;
+ const RATE_16000 = 0x40;
+ const RATE_24000 = 0x80;
+ }
+}
+
+bitflags! {
+ struct A2dpCodecBitsPerSample: u8 {
+ const SAMPLE_NONE = 0x0;
+ const SAMPLE_16 = 0x01;
+ const SAMPLE_24 = 0x02;
+ const SAMPLE_32 = 0x04;
+ }
+}
+
+bitflags! {
+ struct A2dpCodecChannelMode: u8 {
+ const MODE_NONE = 0x0;
+ const MODE_MONO = 0x01;
+ const MODE_STEREO = 0x02;
+ }
+}
+
+#[cxx::bridge(namespace = bluetooth::topshim::rust)]
+pub mod ffi {
+ #[derive(Debug)]
+ pub struct RustRawAddress {
+ address: [u8; 6],
+ }
+
+ #[derive(Debug)]
+ pub struct A2dpCodecConfig {
+ codec_type: u8,
+ codec_priority: i32,
+ sample_rate: u32,
+ bits_per_sample: u8,
+ channel_mode: u8,
+ codec_specific_1: i64,
+ codec_specific_2: i64,
+ codec_specific_3: i64,
+ codec_specific_4: i64,
+ }
+
+ unsafe extern "C++" {
+ include!("btav/btav_shim.h");
+
+ type A2dpIntf;
+
+ unsafe fn GetA2dpProfile(btif: *const u8) -> UniquePtr<A2dpIntf>;
+
+ fn init(self: Pin<&mut A2dpIntf>) -> i32;
+ fn connect(self: Pin<&mut A2dpIntf>, bt_addr: RustRawAddress) -> i32;
+ fn disconnect(self: Pin<&mut A2dpIntf>, bt_addr: RustRawAddress) -> i32;
+ fn set_silence_device(
+ self: Pin<&mut A2dpIntf>,
+ bt_addr: RustRawAddress,
+ silent: bool,
+ ) -> i32;
+ fn set_active_device(self: Pin<&mut A2dpIntf>, bt_addr: RustRawAddress) -> i32;
+ fn config_codec(
+ self: Pin<&mut A2dpIntf>,
+ bt_addr: RustRawAddress,
+ codec_preferences: Vec<A2dpCodecConfig>,
+ ) -> i32;
+ fn cleanup(self: Pin<&mut A2dpIntf>);
+
+ }
+ extern "Rust" {
+ fn connection_state_callback(addr: RustRawAddress, state: u32);
+ fn audio_state_callback(addr: RustRawAddress, state: u32);
+ fn audio_config_callback(
+ addr: RustRawAddress,
+ codec_config: A2dpCodecConfig,
+ codecs_local_capabilities: Vec<A2dpCodecConfig>,
+ codecs_selectable_capabilities: Vec<A2dpCodecConfig>,
+ );
+ fn mandatory_codec_preferred_callback(addr: RustRawAddress);
+ }
+}
+
+pub type RawAddress = ffi::RustRawAddress;
+pub type A2dpCodecConfig = ffi::A2dpCodecConfig;
+
+#[derive(Debug)]
+pub enum A2dpCallbacks {
+ ConnectionState(RawAddress, BtavConnectionState),
+ AudioState(RawAddress, BtavAudioState),
+ AudioConfig(RawAddress, A2dpCodecConfig, Vec<A2dpCodecConfig>, Vec<A2dpCodecConfig>),
+ MandatoryCodecPreferred(RawAddress),
+}
+
+pub struct A2dpCallbacksDispatcher {
+ pub dispatch: Box<dyn Fn(A2dpCallbacks) + Send>,
+}
+
+type A2dpCb = Arc<Mutex<A2dpCallbacksDispatcher>>;
+
+cb_variant!(A2dpCb, connection_state_callback -> A2dpCallbacks::ConnectionState, RawAddress, u32 -> BtavConnectionState);
+
+cb_variant!(A2dpCb, audio_state_callback -> A2dpCallbacks::AudioState, RawAddress, u32 -> BtavAudioState);
+
+cb_variant!(A2dpCb, mandatory_codec_preferred_callback -> A2dpCallbacks::MandatoryCodecPreferred, RawAddress);
+
+cb_variant!(A2dpCb, audio_config_callback -> A2dpCallbacks::AudioConfig, RawAddress, A2dpCodecConfig, Vec<A2dpCodecConfig>, Vec<A2dpCodecConfig>);
+
+pub struct A2dp {
+ internal: cxx::UniquePtr<ffi::A2dpIntf>,
+ is_init: bool,
+}
+
+// For *const u8 opaque btif
+unsafe impl Send for A2dp {}
+
+impl A2dp {
+ pub fn new(intf: &BluetoothInterface) -> A2dp {
+ let mut a2dpif: cxx::UniquePtr<ffi::A2dpIntf>;
+ unsafe {
+ a2dpif = ffi::GetA2dpProfile(intf.as_raw_ptr());
+ }
+
+ A2dp { internal: a2dpif, is_init: false }
+ }
+
+ pub fn initialize(&mut self, callbacks: A2dpCallbacksDispatcher) -> bool {
+ if get_dispatchers().lock().unwrap().set::<A2dpCb>(Arc::new(Mutex::new(callbacks))) {
+ panic!("Tried to set dispatcher for A2dp callbacks while it already exists");
+ }
+ self.internal.pin_mut().init();
+ true
+ }
+
+ pub fn connect(mut self) -> bool {
+ // TODO(hychao)
+ true
+ }
+}
diff --git a/gd/rust/topshim/src/profiles/hid_host.rs b/gd/rust/topshim/src/profiles/hid_host.rs
new file mode 100644
index 0000000..5c22295
--- /dev/null
+++ b/gd/rust/topshim/src/profiles/hid_host.rs
@@ -0,0 +1,278 @@
+use crate::bindings::root as bindings;
+use crate::btif::{BluetoothInterface, RawAddress, SupportedProfiles};
+use crate::ccall;
+use crate::profiles::hid_host::bindings::bthh_interface_t;
+use crate::topstack::get_dispatchers;
+
+use num_traits::cast::{FromPrimitive, ToPrimitive};
+use std::sync::{Arc, Mutex};
+use topshim_macros::cb_variant;
+
+#[derive(Debug, FromPrimitive, PartialEq, PartialOrd)]
+#[repr(u32)]
+pub enum BthhConnectionState {
+ Connected = 0,
+ Connecting,
+ Disconnected,
+ Disconnecting,
+ Unknown = 0xff,
+}
+
+impl From<bindings::bthh_connection_state_t> for BthhConnectionState {
+ fn from(item: bindings::bthh_connection_state_t) -> Self {
+ BthhConnectionState::from_u32(item).unwrap_or_else(|| BthhConnectionState::Unknown)
+ }
+}
+
+#[derive(Debug, FromPrimitive, PartialEq, PartialOrd)]
+#[repr(u32)]
+pub enum BthhStatus {
+ Ok = 0,
+ HsHidNotReady,
+ HsInvalidRptId,
+ HsTransNotSpt,
+ HsInvalidParam,
+ HsError,
+ Error,
+ ErrSdp,
+ ErrProto,
+ ErrDbFull,
+ ErrTodUnspt,
+ ErrNoRes,
+ ErrAuthFailed,
+ ErrHdl,
+
+ Unknown,
+}
+
+impl From<bindings::bthh_status_t> for BthhStatus {
+ fn from(item: bindings::bthh_status_t) -> Self {
+ BthhStatus::from_u32(item).unwrap_or_else(|| BthhStatus::Unknown)
+ }
+}
+
+pub type BthhHidInfo = bindings::bthh_hid_info_t;
+
+#[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
+#[repr(u32)]
+pub enum BthhProtocolMode {
+ ReportMode = 0,
+ BootMode = 1,
+ UnsupportedMode = 0xff,
+}
+
+impl From<bindings::bthh_protocol_mode_t> for BthhProtocolMode {
+ fn from(item: bindings::bthh_protocol_mode_t) -> Self {
+ BthhProtocolMode::from_u32(item).unwrap_or_else(|| BthhProtocolMode::UnsupportedMode)
+ }
+}
+
+impl From<BthhProtocolMode> for bindings::bthh_protocol_mode_t {
+ fn from(item: BthhProtocolMode) -> Self {
+ item.to_u32().unwrap()
+ }
+}
+
+#[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
+#[repr(u32)]
+pub enum BthhReportType {
+ InputReport = 1,
+ OutputReport = 2,
+ FeatureReport = 3,
+}
+
+impl From<BthhReportType> for bindings::bthh_report_type_t {
+ fn from(item: BthhReportType) -> Self {
+ item.to_u32().unwrap()
+ }
+}
+
+fn convert_report(count: i32, raw: *mut u8) -> Vec<u8> {
+ let mut v: Vec<u8> = Vec::new();
+ for i in 0..isize::from_i32(count).unwrap() {
+ let p: *const u8 = unsafe { raw.offset(i) };
+ v.push(unsafe { *p });
+ }
+
+ return v;
+}
+
+pub enum HHCallbacks {
+ ConnectionState(RawAddress, BthhConnectionState),
+ VirtualUnplug(RawAddress, BthhStatus),
+ HidInfo(RawAddress, BthhHidInfo),
+ ProtocolMode(RawAddress, BthhStatus, BthhProtocolMode),
+ IdleTime(RawAddress, BthhStatus, i32),
+ GetReport(RawAddress, BthhStatus, Vec<u8>, i32),
+ Handshake(RawAddress, BthhStatus),
+}
+
+pub struct HHCallbacksDispatcher {
+ pub dispatch: Box<dyn Fn(HHCallbacks) + Send>,
+}
+
+type HHCb = Arc<Mutex<HHCallbacksDispatcher>>;
+
+cb_variant!(HHCb, connection_state_cb -> HHCallbacks::ConnectionState,
+*mut RawAddress, bindings::bthh_connection_state_t -> BthhConnectionState, {
+ let _0 = unsafe {*_0};
+});
+cb_variant!(HHCb, virtual_unplug_cb -> HHCallbacks::VirtualUnplug,
+*mut RawAddress, bindings::bthh_status_t -> BthhStatus, {
+ let _0 = unsafe {*_0};
+});
+cb_variant!(HHCb, hid_info_cb -> HHCallbacks::HidInfo,
+*mut RawAddress, bindings::bthh_hid_info_t -> BthhHidInfo, {
+ let _0 = unsafe {*_0};
+});
+cb_variant!(HHCb, protocol_mode_cb -> HHCallbacks::ProtocolMode,
+*mut RawAddress, bindings::bthh_status_t -> BthhStatus,
+bindings::bthh_protocol_mode_t -> BthhProtocolMode, {
+ let _0 = unsafe {*_0};
+});
+cb_variant!(HHCb, idle_time_cb -> HHCallbacks::IdleTime,
+*mut RawAddress, bindings::bthh_status_t -> BthhStatus, i32, {
+ let _0 = unsafe {*_0};
+});
+cb_variant!(HHCb, get_report_cb -> HHCallbacks::GetReport,
+*mut RawAddress, bindings::bthh_status_t -> BthhStatus, *mut u8, i32, {
+ let _0 = unsafe {*_0};
+ let _2 = convert_report(_3, _2);
+});
+cb_variant!(HHCb, handshake_cb -> HHCallbacks::Handshake,
+*mut RawAddress, bindings::bthh_status_t -> BthhStatus, {
+ let _0 = unsafe{*_0};
+});
+
+struct RawHHWrapper {
+ raw: *const bindings::bthh_interface_t,
+}
+
+// Pointers unsafe due to ownership but this is a static pointer so Send is ok
+unsafe impl Send for RawHHWrapper {}
+
+pub struct HidHost {
+ internal: RawHHWrapper,
+ is_init: bool,
+ // Keep callback object in memory (underlying code doesn't make copy)
+ callbacks: Option<Box<bindings::bthh_callbacks_t>>,
+}
+
+impl HidHost {
+ pub fn new(intf: &BluetoothInterface) -> HidHost {
+ let r = intf.get_profile_interface(SupportedProfiles::HidHost);
+ HidHost {
+ internal: RawHHWrapper { raw: r as *const bthh_interface_t },
+ is_init: false,
+ callbacks: None,
+ }
+ }
+
+ pub fn is_initialized(&self) -> bool {
+ self.is_init
+ }
+
+ pub fn initialize(&mut self, callbacks: HHCallbacksDispatcher) -> bool {
+ // Register dispatcher
+ if get_dispatchers().lock().unwrap().set::<HHCb>(Arc::new(Mutex::new(callbacks))) {
+ panic!("Tried to set dispatcher for HHCallbacks but it already existed");
+ }
+
+ let mut callbacks = Box::new(bindings::bthh_callbacks_t {
+ size: 8 * 8,
+ connection_state_cb: Some(connection_state_cb),
+ hid_info_cb: Some(hid_info_cb),
+ protocol_mode_cb: Some(protocol_mode_cb),
+ idle_time_cb: Some(idle_time_cb),
+ get_report_cb: Some(get_report_cb),
+ virtual_unplug_cb: Some(virtual_unplug_cb),
+ handshake_cb: Some(handshake_cb),
+ });
+
+ let rawcb = &mut *callbacks;
+
+ let init = ccall!(self, init, rawcb);
+ self.is_init = BthhStatus::from(init) == BthhStatus::Ok;
+ self.callbacks = Some(callbacks);
+
+ return self.is_init;
+ }
+
+ pub fn connect(&self, addr: &mut RawAddress) -> BthhStatus {
+ BthhStatus::from(ccall!(self, connect, addr))
+ }
+
+ pub fn disconnect(&self, addr: &mut RawAddress) -> BthhStatus {
+ BthhStatus::from(ccall!(self, disconnect, addr))
+ }
+
+ pub fn virtual_unplug(&self, addr: &mut RawAddress) -> BthhStatus {
+ BthhStatus::from(ccall!(self, virtual_unplug, addr))
+ }
+
+ pub fn set_info(&self, addr: &mut RawAddress, info: BthhHidInfo) -> BthhStatus {
+ BthhStatus::from(ccall!(self, set_info, addr, info))
+ }
+
+ pub fn get_protocol(&self, addr: &mut RawAddress, mode: BthhProtocolMode) -> BthhStatus {
+ BthhStatus::from(ccall!(
+ self,
+ get_protocol,
+ addr,
+ bindings::bthh_protocol_mode_t::from(mode)
+ ))
+ }
+
+ pub fn set_protocol(&self, addr: &mut RawAddress, mode: BthhProtocolMode) -> BthhStatus {
+ BthhStatus::from(ccall!(
+ self,
+ set_protocol,
+ addr,
+ bindings::bthh_protocol_mode_t::from(mode)
+ ))
+ }
+
+ pub fn get_idle_time(&self, addr: &mut RawAddress) -> BthhStatus {
+ BthhStatus::from(ccall!(self, get_idle_time, addr))
+ }
+
+ pub fn set_idle_time(&self, addr: &mut RawAddress, idle_time: u8) -> BthhStatus {
+ BthhStatus::from(ccall!(self, set_idle_time, addr, idle_time))
+ }
+
+ pub fn get_report(
+ &self,
+ addr: &mut RawAddress,
+ report_type: BthhReportType,
+ report_id: u8,
+ buffer_size: i32,
+ ) -> BthhStatus {
+ BthhStatus::from(ccall!(
+ self,
+ get_report,
+ addr,
+ bindings::bthh_report_type_t::from(report_type),
+ report_id,
+ buffer_size
+ ))
+ }
+
+ pub fn set_report(
+ &self,
+ addr: &mut RawAddress,
+ report_type: BthhReportType,
+ report: &mut [u8],
+ ) -> BthhStatus {
+ BthhStatus::from(ccall!(
+ self,
+ set_report,
+ addr,
+ bindings::bthh_report_type_t::from(report_type),
+ report.as_mut_ptr() as *mut i8
+ ))
+ }
+
+ pub fn cleanup(&self) {
+ ccall!(self, cleanup)
+ }
+}
diff --git a/gd/rust/topshim/src/profiles/mod.rs b/gd/rust/topshim/src/profiles/mod.rs
new file mode 100644
index 0000000..f738b64
--- /dev/null
+++ b/gd/rust/topshim/src/profiles/mod.rs
@@ -0,0 +1,2 @@
+pub mod a2dp;
+pub mod hid_host;
diff --git a/gd/rust/topshim/src/topstack.rs b/gd/rust/topshim/src/topstack.rs
new file mode 100644
index 0000000..7553863
--- /dev/null
+++ b/gd/rust/topshim/src/topstack.rs
@@ -0,0 +1,56 @@
+//! Stack on top of the Bluetooth interface shim
+//!
+//! Helpers for dealing with the stack on top of the Bluetooth interface.
+
+use std::any::{Any, TypeId};
+use std::collections::HashMap;
+use std::sync::{Arc, Mutex};
+use tokio::runtime::{Builder, Runtime};
+
+lazy_static! {
+ // Shared runtime for topshim handlers. All async tasks will get run by this
+ // runtime and this will properly serialize all spawned tasks.
+ pub static ref RUNTIME: Arc<Runtime> = Arc::new(
+ Builder::new_multi_thread()
+ .worker_threads(1)
+ .max_blocking_threads(1)
+ .enable_all()
+ .build()
+ .unwrap()
+ );
+}
+
+pub fn get_runtime() -> Arc<Runtime> {
+ RUNTIME.clone()
+}
+
+lazy_static! {
+ static ref CB_DISPATCHER: Arc<Mutex<DispatchContainer>> =
+ Arc::new(Mutex::new(DispatchContainer { instances: HashMap::new() }));
+}
+
+type InstanceBox = Box<dyn Any + Send + Sync>;
+
+pub struct DispatchContainer {
+ instances: HashMap<TypeId, InstanceBox>,
+}
+
+impl DispatchContainer {
+ pub fn get<T: 'static + Clone + Send + Sync>(&self) -> Option<T> {
+ let typeid = TypeId::of::<T>();
+
+ if let Some(value) = self.instances.get(&typeid) {
+ return Some(value.downcast_ref::<T>().unwrap().clone());
+ }
+
+ None
+ }
+
+ pub fn set<T: 'static + Clone + Send + Sync>(&mut self, obj: T) -> bool {
+ self.instances.insert(TypeId::of::<T>(), Box::new(obj)).is_some()
+ }
+}
+
+pub fn get_dispatchers() -> Arc<Mutex<DispatchContainer>> {
+ CB_DISPATCHER.clone()
+}
diff --git a/gd/security/Android.bp b/gd/security/Android.bp
index 1a74364..17ab2b9 100644
--- a/gd/security/Android.bp
+++ b/gd/security/Android.bp
@@ -28,11 +28,17 @@
}
filegroup {
- name: "BluetoothSecurityTestSources",
+ name: "BluetoothSecurityUnitTestSources",
srcs: [
"ecc/multipoint_test.cc",
- "pairing_handler_le_unittest.cc",
"test/ecdh_keys_test.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothSecurityTestSources",
+ srcs: [
+ "pairing_handler_le_unittest.cc",
"test/fake_l2cap_test.cc",
"test/pairing_handler_le_pair_test.cc",
":BluetoothSecurityChannelTestSources",
diff --git a/gd/security/cert/le_security_test.py b/gd/security/cert/le_security_test.py
index 7a0719b..2c2cee2 100644
--- a/gd/security/cert/le_security_test.py
+++ b/gd/security/cert/le_security_test.py
@@ -13,1085 +13,19 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import time
-
-from bluetooth_packets_python3 import hci_packets
-from bluetooth_packets_python3 import security_packets
-from cert.event_stream import EventStream
from cert.gd_base_test import GdBaseTestClass
-from cert.matchers import HciMatchers
-from cert.matchers import SecurityMatchers
-from cert.metadata import metadata
-from cert.py_hci import PyHci
-from cert.py_le_security import PyLeSecurity
-from cert.truth import assertThat
-from datetime import timedelta
-from facade import common_pb2 as common
-from hci.facade import controller_facade_pb2 as controller_facade
-from hci.facade import le_advertising_manager_facade_pb2 as le_advertising_facade
-from hci.facade import le_initiator_address_facade_pb2 as le_initiator_address_facade
-from google.protobuf import empty_pb2 as empty_proto
-from neighbor.facade import facade_pb2 as neighbor_facade
-from security.cert.cert_security import CertSecurity
-from security.facade_pb2 import AuthenticationRequirements
-from security.facade_pb2 import BondMsgType
-from security.facade_pb2 import OobDataMessage
-from security.facade_pb2 import UiCallbackMsg
-from security.facade_pb2 import UiCallbackType
-from security.facade_pb2 import UiMsgType
-from security.facade_pb2 import LeAuthRequirementsMessage
-from security.facade_pb2 import LeIoCapabilityMessage
-from security.facade_pb2 import LeOobDataPresentMessage
-from security.facade_pb2 import LeMaximumEncryptionKeySizeMessage
-
-import time
-from bluetooth_packets_python3.hci_packets import OpCode
-from bluetooth_packets_python3.security_packets import PairingFailedReason
-
-from mobly import asserts
-
-LeIoCapabilities = LeIoCapabilityMessage.LeIoCapabilities
-LeOobDataFlag = LeOobDataPresentMessage.LeOobDataFlag
-
-DISPLAY_ONLY = LeIoCapabilityMessage(capabilities=LeIoCapabilities.DISPLAY_ONLY)
-KEYBOARD_ONLY = LeIoCapabilityMessage(capabilities=LeIoCapabilities.KEYBOARD_ONLY)
-NO_INPUT_NO_OUTPUT = LeIoCapabilityMessage(capabilities=LeIoCapabilities.NO_INPUT_NO_OUTPUT)
-KEYBOARD_DISPLAY = LeIoCapabilityMessage(capabilities=LeIoCapabilities.KEYBOARD_DISPLAY)
-
-OOB_NOT_PRESENT = LeOobDataPresentMessage(data_present=LeOobDataFlag.NOT_PRESENT)
-OOB_PRESENT = LeOobDataPresentMessage(data_present=LeOobDataFlag.PRESENT)
+from security.cert.le_security_test_lib import LeSecurityTestBase
-class LeSecurityTest(GdBaseTestClass):
- """
- Collection of tests that each sample results from
- different (unique) combinations of io capabilities, authentication requirements, and oob data.
- """
+class LeSecurityTest(GdBaseTestClass, LeSecurityTestBase):
def setup_class(self):
- super().setup_class(dut_module='SECURITY', cert_module='SECURITY')
+ GdBaseTestClass.setup_class(self, dut_module='SECURITY', cert_module='SECURITY')
def setup_test(self):
- super().setup_test()
-
- self.dut_security = PyLeSecurity(self.dut)
- self.cert_security = PyLeSecurity(self.cert)
- self.dut_hci = PyHci(self.dut)
-
- raw_addr = self.dut.hci_controller.GetMacAddress(empty_proto.Empty()).address
-
- self.dut_address = common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=raw_addr), type=common.PUBLIC_DEVICE_ADDRESS)
- privacy_policy = le_initiator_address_facade.PrivacyPolicy(
- address_policy=le_initiator_address_facade.AddressPolicy.USE_PUBLIC_ADDRESS,
- address_with_type=self.dut_address)
- self.dut.security.SetLeInitiatorAddressPolicy(privacy_policy)
- self.cert_address = common.BluetoothAddressWithType(
- address=common.BluetoothAddress(
- address=self.cert.hci_controller.GetMacAddress(empty_proto.Empty()).address),
- type=common.PUBLIC_DEVICE_ADDRESS)
- cert_privacy_policy = le_initiator_address_facade.PrivacyPolicy(
- address_policy=le_initiator_address_facade.AddressPolicy.USE_PUBLIC_ADDRESS,
- address_with_type=self.cert_address)
- self.cert.security.SetLeInitiatorAddressPolicy(cert_privacy_policy)
-
- asserts.skip("Unhandled race condition - Flaky test")
+ GdBaseTestClass.setup_test(self)
+ LeSecurityTestBase.setup_test(self, self.dut, self.cert)
def teardown_test(self):
- self.dut_hci.close()
- self.dut_security.close()
- self.cert_security.close()
- super().teardown_test()
-
- def _prepare_cert_for_connection(self):
- # DUT Advertises
- gap_name = hci_packets.GapData()
- gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
- gap_name.data = list(bytes(b'Im_The_CERT'))
- gap_data = le_advertising_facade.GapDataMsg(data=bytes(gap_name.Serialize()))
- config = le_advertising_facade.AdvertisingConfig(
- advertisement=[gap_data],
- interval_min=512,
- interval_max=768,
- advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
- own_address_type=common.USE_PUBLIC_DEVICE_ADDRESS,
- channel_map=7,
- filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
- request = le_advertising_facade.CreateAdvertiserRequest(config=config)
- create_response = self.cert.hci_le_advertising_manager.CreateAdvertiser(request)
-
- def _prepare_dut_for_connection(self):
- # DUT Advertises
- gap_name = hci_packets.GapData()
- gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
- gap_name.data = list(bytes(b'Im_The_DUT'))
- gap_data = le_advertising_facade.GapDataMsg(data=bytes(gap_name.Serialize()))
- config = le_advertising_facade.AdvertisingConfig(
- advertisement=[gap_data],
- interval_min=512,
- interval_max=768,
- advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
- own_address_type=common.USE_PUBLIC_DEVICE_ADDRESS,
- channel_map=7,
- filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
- request = le_advertising_facade.CreateAdvertiserRequest(config=config)
- create_response = self.dut.hci_le_advertising_manager.CreateAdvertiser(request)
-
- @metadata(pts_test_id="SM/MAS/PROT/BV-01-C", pts_test_name="SMP Time Out – IUT Initiator")
- def test_le_smp_timeout_iut_initiator(self):
- """
- Verify that the IUT handles the lack of pairing response after 30 seconds when acting as initiator.
- """
- self._prepare_cert_for_connection()
- self.dut.security.CreateBondLe(self.cert_address)
- assertThat(self.dut_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_BOND_FAILED, self.cert_address), timeout=timedelta(seconds=35))
-
- @metadata(pts_test_id="SM/SLA/PROT/BV-02-C", pts_test_name="SMP Time Out – IUT Responder")
- def test_le_smp_timeout_iut_responder(self):
- """
- Verify that the IUT handles the lack of pairing response after 30 seconds when acting as initiator.
- """
- self.cert.security.SetLeIoCapability(KEYBOARD_ONLY)
- self.dut.security.SetLeIoCapability(DISPLAY_ONLY)
-
- self._prepare_dut_for_connection()
-
- # 1. Lower Tester transmits Pairing Request.
- self.cert.security.CreateBondLe(self.dut_address)
-
- assertThat(self.dut_security.get_ui_stream()).emits(
- SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address), timeout=timedelta(seconds=35))
-
- # 2. IUT responds with Pairing Response.
- self.dut.security.SendUiCallback(
- UiCallbackMsg(
- message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.cert_address))
-
- # 3. In phase 2, Lower Tester does not issue the expected Pairing Confirm.
-
- # Here the cert receives DISPLAY_PASSKEY_ENTRY. By not replying to it we make sure Pairing Confirm is never sent
- assertThat(self.cert_security.get_ui_stream()).emits(
- SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PASSKEY_ENTRY, self.dut_address), timeout=timedelta(seconds=5))
-
- # 4. IUT times out 30 seconds after issued Pairing Response and reports the failure to the Upper Tester.
- assertThat(self.dut_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_BOND_FAILED, self.cert_address), timeout=timedelta(seconds=35))
-
- # 5. After additionally (at least) 10 seconds the Lower Tester issues the expected Pairing Confirm.
- # 6. The IUT closes the connection before receiving the delayed response or does not respond to it when it is received.
- #TODO:
- #assertThat(self.dut_hci.get_event_stream()).emits(HciMatchers.Disconnect())
-
- @metadata(pts_test_id="SM/MAS/JW/BV-01-C", pts_test_name="Just Works IUT Initiator – Success")
- def test_just_works_iut_initiator(self):
- """
- Verify that the IUT performs the Just Works pairing procedure correctly as central, initiator when both sides do not require MITM protection.
- """
- self._prepare_cert_for_connection()
-
- self.dut.security.SetLeIoCapability(KEYBOARD_ONLY)
- self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.dut_security.SetLeAuthRequirements()
-
- self.cert.security.SetLeIoCapability(DISPLAY_ONLY)
- self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.cert_security.SetLeAuthRequirements()
-
- # 1. IUT transmits Pairing Request command with:
- # a. IO capability set to any IO capability
- # b. OOB data flag set to 0x00 (OOB Authentication data not present)
- # c. AuthReq Bonding Flags set to ‘00’ and the MITM flag set to ‘0’ and all the reserved bits are set to ‘0’
- self.dut.security.CreateBondLe(self.cert_address)
-
- assertThat(self.cert_security.get_ui_stream()).emits(
- SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address))
-
- # 2. Lower Tester responds with a Pairing Response command, with:
- # a. IO capability set to “KeyboardDisplay”
- # b. OOB data flag set to 0x00 (OOB Authentication data not present)
- # c. AuthReq Bonding Flags set to ‘00’, and the MITM flag set to ‘0’ and all the reserved bits are set to ‘0’
- self.cert.security.SendUiCallback(
- UiCallbackMsg(
- message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.dut_address))
-
- # 3. IUT and Lower Tester perform phase 2 of the just works pairing procedure and establish an encrypted link with the key generated in phase 2.
- assertThat(self.dut_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address))
-
- @metadata(pts_test_id="SM/SLA/JW/BV-02-C", pts_test_name="Just Works IUT Responder – Success")
- def test_just_works_iut_responder(self):
- """
- Verify that the IUT is able to perform the Just Works pairing procedure correctly when acting as peripheral, responder.
- """
- self._prepare_dut_for_connection()
-
- self.dut.security.SetLeIoCapability(KEYBOARD_ONLY)
- self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.dut_security.SetLeAuthRequirements()
-
- self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT)
- self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.cert_security.SetLeAuthRequirements()
-
- # 1. Lower Tester transmits Pairing Request command with:
- # a. IO capability set to “NoInputNoOutput”
- # b. OOB data flag set to 0x00 (OOB Authentication data not present)
- # c. MITM flag set to ‘0’ and all reserved bits are set to ‘0’
- self.cert.security.CreateBondLe(self.dut_address)
-
- assertThat(self.dut_security.get_ui_stream()).emits(
- SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address))
-
- # 2. IUT responds with a Pairing Response command, with:
- # a. IO capability set to any IO capability
- # b. OOB data flag set to 0x00 (OOB Authentication data not present)
- self.dut.security.SendUiCallback(
- UiCallbackMsg(
- message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.cert_address))
-
- # IUT and Lower Tester perform phase 2 of the just works pairing and establish an encrypted link with the generated STK.
- assertThat(self.dut_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address))
-
- @metadata(
- pts_test_id="SM/SLA/JW/BI-03-C", pts_test_name="Just Works IUT Responder – Handle AuthReq flag RFU correctly")
- def test_just_works_iut_responder_auth_req_rfu(self):
- """
- Verify that the IUT is able to perform the Just Works pairing procedure when receiving additional bits set in the AuthReq flag. Reserved For Future Use bits are correctly handled when acting as peripheral, responder.
- """
- self._prepare_dut_for_connection()
-
- self.dut.security.SetLeIoCapability(KEYBOARD_DISPLAY)
- self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.dut_security.SetLeAuthRequirements()
-
- self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT)
- self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1, reserved_bits=2)
-
- # 1. Lower Tester transmits Pairing Request command with:
- # a. IO Capability set to ”NoInputNoOutput”
- # b. OOB data flag set to 0x00 (OOB Authentication data not present)
- # c. MITM set to ‘0’ and all reserved bits are set to ‘1’
- self.cert.security.CreateBondLe(self.dut_address)
-
- assertThat(self.dut_security.get_ui_stream()).emits(
- SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address))
-
- # 2. IUT responds with a Pairing Response command, with:
- # a. IO capability set to any IO capability
- # b. OOB data flag set to 0x00 (OOB Authentication data not present)
- # c. All reserved bits are set to ‘0’
- self.dut.security.SendUiCallback(
- UiCallbackMsg(
- message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.cert_address))
-
- # 3. IUT and Lower Tester perform phase 2 of the just works pairing and establish an encrypted link with the generated STK.
- assertThat(self.dut_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address))
-
- @metadata(
- pts_test_id="SM/MAS/JW/BI-04-C", pts_test_name="Just Works IUT Initiator – Handle AuthReq flag RFU correctly")
- def test_just_works_iut_initiator_auth_req_rfu(self):
- """
- Verify that the IUT is able to perform the Just Works pairing procedure when receiving additional bits set in the AuthReq flag. Reserved For Future Use bits are correctly handled when acting as central, initiator.
- """
- self._prepare_cert_for_connection()
-
- self.dut.security.SetLeIoCapability(KEYBOARD_DISPLAY)
- self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.dut_security.SetLeAuthRequirements()
-
- self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT)
- self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1, reserved_bits=3)
-
- # 1. IUT transmits a Pairing Request command with:
- # a. IO Capability set to any IO Capability
- # b. OOB data flag set to 0x00 (OOB Authentication data not present)
- # c. All reserved bits are set to ‘0’. For the purposes of this test the Secure Connections bit and the Keypress bits in the AuthReq bonding flag set by the IUT are ignored by the Lower Tester.
- self.dut.security.CreateBondLe(self.cert_address)
-
- assertThat(self.cert_security.get_ui_stream()).emits(
- SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address))
-
- # 2. Lower Tester responds with a Pairing Response command, with:
- # a. IO Capability set to “NoInputNoOutput”
- # b. OOB data flag set to 0x00 (OOB Authentication data not present)
- # c. AuthReq bonding flag set to the value indicated in the IXIT [7] for ‘Bonding Flags’ and the MITM flag set to ‘0’ and all reserved bits are set to ‘1’. The SC and Keypress bits in the AuthReq bonding flag are set to 0 by the Lower Tester for this test.
- self.cert.security.SendUiCallback(
- UiCallbackMsg(
- message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.dut_address))
-
- # 3. IUT and Lower Tester perform phase 2 of the just works pairing and establish an encrypted link with the generated STK.
- assertThat(self.dut_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address))
-
- @metadata(
- pts_test_id="SM/MAS/SCJW/BV-01-C", pts_test_name="Just Works, IUT Initiator, Secure Connections – Success")
- def test_just_works_iut_initiator_secure_connections(self):
- """
- Verify that the IUT supporting LE Secure Connections performs the Just Works or Numeric Comparison pairing procedure correctly as initiator.
- """
- self._prepare_cert_for_connection()
-
- self.dut.security.SetLeIoCapability(KEYBOARD_ONLY)
- self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.dut_security.SetLeAuthRequirements(secure_connections=1)
-
- self.cert.security.SetLeIoCapability(DISPLAY_ONLY)
- self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.cert_security.SetLeAuthRequirements(secure_connections=1)
-
- # 1. IUT transmits Pairing Request command with:
- # a. IO capability set to any IO capability
- # b. OOB data flag set to 0x00 (OOB Authentication data not present)
- # c. AuthReq Bonding Flags set to ‘00’, the MITM flag set to either ‘0’ for Just Works or '1' for Numeric Comparison, Secure Connections flag set to '1' and all the reserved bits are set to ‘0’
- self.dut.security.CreateBondLe(self.cert_address)
-
- assertThat(self.cert_security.get_ui_stream()).emits(
- SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address))
-
- # 2. Lower Tester responds with a Pairing Response command, with:
- # a. IO capability set to “KeyboardDisplay”
- # b. OOB data flag set to 0x00 (OOB Authentication data not present)
- # c. AuthReq Bonding Flags set to ‘00’, the MITM flag set to ‘0’, Secure Connections flag set to '1' and all the reserved bits are set to ‘0’
- self.cert.security.SendUiCallback(
- UiCallbackMsg(
- message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.dut_address))
-
- # 3. IUT and Lower Tester perform phase 2 of the Just Works or Numeric Comparison pairing procedure according to the MITM flag and IO capabilities, and establish an encrypted link with the LTK generated in phase 2.
- assertThat(self.dut_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address))
-
- @metadata(
- pts_test_id="SM/SLA/SCJW/BV-02-C", pts_test_name="Just Works, IUT Responder, Secure Connections – Success")
- def test_just_works_iut_responder_secure_connections(self):
- """
- Verify that the IUT supporting LE Secure Connections is able to perform the Just Works or Numeric Comparison pairing procedure correctly when acting as responder.
- """
- self._prepare_dut_for_connection()
-
- self.dut.security.SetLeIoCapability(KEYBOARD_ONLY)
- self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.dut_security.SetLeAuthRequirements(secure_connections=1)
-
- self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT)
- self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.cert_security.SetLeAuthRequirements(secure_connections=1)
-
- # 1. Lower Tester transmits Pairing Request command with:
- # a. IO capability set to “NoInputNoOutput”
- # b. OOB data flag set to 0x00 (OOB Authentication data not present)
- # c. AuthReq Bonding Flags set to ‘00’, MITM flag set to ‘0’, Secure Connections flag set to '1' and all reserved bits are set to ‘0’
- self.cert.security.CreateBondLe(self.dut_address)
-
- assertThat(self.dut_security.get_ui_stream()).emits(
- SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address))
-
- # 2. IUT responds with a Pairing Response command, with:
- # a. IO capability set to any IO capability
- # b. AuthReq Bonding Flags set to ‘00’, MITM flag set to either ‘0’ for Just Works or '1' for Numeric Comparison, Secure Connections flag set to '1' and all reserved bits are set to ‘0’
- self.dut.security.SendUiCallback(
- UiCallbackMsg(
- message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.cert_address))
-
- # 3. UT and Lower Tester perform phase 2 of the Just Works or Numeric Comparison pairing procedure according to the MITM flag and IO capabilities, and establish an encrypted link with the LTK generated in phase 2.
- assertThat(self.dut_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address))
-
- @metadata(
- pts_test_id="SM/SLA/SCJW/BV-03-C",
- pts_test_name="Just Works, IUT Responder, Secure Connections – Handle AuthReq Flag RFU Correctly")
- def test_just_works_iut_responder_secure_connections_auth_req_rfu(self):
- """
- Verify that the IUT is able to perform the Just Works pairing procedure when receiving additional bits set in the AuthReq flag. Reserved For Future Use bits are correctly handled when acting as peripheral, responder.
- """
- self._prepare_dut_for_connection()
-
- self.dut.security.SetLeIoCapability(KEYBOARD_DISPLAY)
- self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.dut_security.SetLeAuthRequirements(secure_connections=1)
-
- self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT)
- self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1, reserved_bits=3)
-
- # 1. Lower Tester transmits Pairing Request command with:
- # a. IO Capability set to ”NoInputNoOutput”
- # b. OOB data flag set to 0x00 (OOB Authentication data not present)
- # c. MITM set to ‘0’ and all reserved bits are set to a random value.
- self.cert.security.CreateBondLe(self.dut_address)
-
- assertThat(self.dut_security.get_ui_stream()).emits(
- SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address))
-
- # 2. IUT responds with a Pairing Response command, with:
- # a. IO capability set to any IO capability
- # b. OOB data flag set to 0x00 (OOB Authentication data not present)
- # c. All reserved bits are set to ‘0’
- self.dut.security.SendUiCallback(
- UiCallbackMsg(
- message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.cert_address))
-
- # 3. IUT and Lower Tester perform phase 2 of the Just Works pairing and establish an encrypted link with the generated LTK.
- assertThat(self.dut_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address))
-
- @metadata(
- pts_test_id="SM/MAS/SCJW/BV-04-C",
- pts_test_name="Just Works, IUT Initiator, Secure Connections – Handle AuthReq Flag RFU Correctly")
- def test_just_works_iut_initiator_secure_connections_auth_req_rfu(self):
- """
- Verify that the IUT is able to perform the Just Works pairing procedure when receiving additional bits set in the AuthReq flag. Reserved For Future Use bits are correctly handled when acting as central, initiator.
- """
- self._prepare_cert_for_connection()
-
- self.dut.security.SetLeIoCapability(KEYBOARD_DISPLAY)
- self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.dut_security.SetLeAuthRequirements(secure_connections=1)
-
- self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT)
- self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1, reserved_bits=3)
-
- # 1. IUT transmits a Pairing Request command with:
- # a. IO Capability set to any IO Capability
- # b. OOB data flag set to 0x00 (OOB Authentication data not present)
- # c. All reserved bits are set to ‘0’.
- self.dut.security.CreateBondLe(self.cert_address)
-
- assertThat(self.cert_security.get_ui_stream()).emits(
- SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address))
-
- # 2. Lower Tester responds with a Pairing Response command, with:
- # a. IO Capability set to “NoInputNoOutput”
- # b. OOB data flag set to 0x00 (OOB Authentication data not present)
- # c. AuthReq bonding flag set to the value indicated in the IXIT [7] for ‘Bonding Flags’ and the MITM flag set to ‘0’ and all reserved bits are set to a random value.
- self.cert.security.SendUiCallback(
- UiCallbackMsg(
- message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.dut_address))
-
- # 3. IUT and Lower Tester perform phase 2 of the Just Works pairing and establish an encrypted link with the generated LTK.
- assertThat(self.dut_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address))
-
- @metadata(
- pts_test_id="SM/MAS/EKS/BV-01-C",
- pts_test_name="IUT initiator, Lower Tester Maximum Encryption Key Size = Min_Encryption_Key_Length")
- def test_min_encryption_key_size_equal_to_max_iut_initiator(self):
- """
- Verify that the IUT uses correct key size during encryption as initiator.
- """
- self._prepare_cert_for_connection()
-
- self.dut.security.SetLeIoCapability(KEYBOARD_DISPLAY)
- self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.dut_security.SetLeAuthRequirements(secure_connections=1)
- self.dut.security.SetLeMaximumEncryptionKeySize(
- LeMaximumEncryptionKeySizeMessage(maximum_encryption_key_size=0x10))
-
- self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT)
- self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1)
- self.cert.security.SetLeMaximumEncryptionKeySize(
- LeMaximumEncryptionKeySizeMessage(maximum_encryption_key_size=0x07))
-
- # 1. IUT transmits a Pairing Request
- self.dut.security.CreateBondLe(self.cert_address)
-
- assertThat(self.cert_security.get_ui_stream()).emits(
- SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address))
-
- # 2. Lower Tester responds with Pairing Response command with Maximum Encryption Key Size field set to Min_Encryption_Key_Length’.
- self.cert.security.SendUiCallback(
- UiCallbackMsg(
- message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.dut_address))
-
- # 3. IUT and Lower Tester perform phase 2 of the LE pairing and establish an encrypted link with the key generated in phase 2.
- assertThat(self.dut_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address))
-
- @metadata(
- pts_test_id="SM/SLA/EKS/BV-02-C",
- pts_test_name="IUT Responder, Lower Tester Maximum Encryption Key Size = Min_Encryption_Key_Length")
- def test_min_encryption_key_size_equal_to_max_iut_responder(self):
- """
- Verify that the IUT uses correct key size during encryption as responder.
- """
- self._prepare_dut_for_connection()
-
- self.dut.security.SetLeIoCapability(KEYBOARD_ONLY)
- self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.dut_security.SetLeAuthRequirements()
- self.dut.security.SetLeMaximumEncryptionKeySize(
- LeMaximumEncryptionKeySizeMessage(maximum_encryption_key_size=0x07))
-
- self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT)
- self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.cert_security.SetLeAuthRequirements()
- self.cert.security.SetLeMaximumEncryptionKeySize(
- LeMaximumEncryptionKeySizeMessage(maximum_encryption_key_size=0x10))
-
- # 1. Lower Tester initiates Pairing Request command with Maximum Encryption Key Size field set to Min_Encryption_Key_Length’.
- self.cert.security.CreateBondLe(self.dut_address)
-
- assertThat(self.dut_security.get_ui_stream()).emits(
- SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address))
-
- # 2. IUT responds with Pairing Response command.
- self.dut.security.SendUiCallback(
- UiCallbackMsg(
- message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.cert_address))
-
- #3. IUT and Lower Tester perform phase 2 of the LE pairing and establish an encrypted link with the key generated in phase 2.
- assertThat(self.dut_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address))
-
- @metadata(
- pts_test_id="SM/MAS/EKS/BI-01-C",
- pts_test_name="IUT initiator, Lower Tester Maximum Encryption Key Size < Min_Encryption_Key_Length")
- def test_min_encryption_key_size_less_than_min_iut_initiator(self):
- """
- Verify that the IUT checks that the resultant encryption key size is not smaller than the minimum key size.
- """
- self._prepare_cert_for_connection()
-
- self.dut.security.SetLeIoCapability(KEYBOARD_DISPLAY)
- self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.dut_security.SetLeAuthRequirements(secure_connections=1)
- self.dut.security.SetLeMaximumEncryptionKeySize(
- LeMaximumEncryptionKeySizeMessage(maximum_encryption_key_size=0x10))
-
- self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT)
- self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1)
- self.cert.security.SetLeMaximumEncryptionKeySize(
- LeMaximumEncryptionKeySizeMessage(maximum_encryption_key_size=0x06))
-
- # 1. IUT transmits a Pairing Request
- self.dut.security.CreateBondLe(self.cert_address)
-
- assertThat(self.cert_security.get_ui_stream()).emits(
- SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address))
-
- # 2. Lower Tester responds with Pairing Response command with Maximum Encryption Key Size field set to Min_Encryption_Key_Length-1’.
- self.cert.security.SendUiCallback(
- UiCallbackMsg(
- message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.dut_address))
-
- # 3. IUT transmits the Pairing Failed command.
- assertThat(self.dut_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_BOND_FAILED, self.cert_address,
- int(PairingFailedReason.ENCRYPTION_KEY_SIZE)))
-
- @metadata(
- pts_test_id="SM/SLA/EKS/BI-02-C",
- pts_test_name="IUT Responder, Lower Tester Maximum Encryption Key Size < Min_Encryption_Key_Length")
- def test_min_encryption_key_size_less_than_min_iut_responder(self):
- """
- Verify that the IUT uses correct key size during encryption as responder.
- """
- self._prepare_dut_for_connection()
-
- self.dut.security.SetLeIoCapability(KEYBOARD_ONLY)
- self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.dut_security.SetLeAuthRequirements()
- self.dut.security.SetLeMaximumEncryptionKeySize(
- LeMaximumEncryptionKeySizeMessage(maximum_encryption_key_size=0x06))
-
- self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT)
- self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.cert_security.SetLeAuthRequirements()
- self.cert.security.SetLeMaximumEncryptionKeySize(
- LeMaximumEncryptionKeySizeMessage(maximum_encryption_key_size=0x10))
-
- # 1. Lower Tester initiates Pairing Request command with Maximum Encryption Key Size field set to Min_Encryption_Key_Length-1.
- self.cert.security.CreateBondLe(self.dut_address)
-
- assertThat(self.dut_security.get_ui_stream()).emits(
- SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address))
-
- self.dut.security.SendUiCallback(
- UiCallbackMsg(
- message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.cert_address))
-
- #3. IUT transmits the Pairing Failed command.
- assertThat(self.cert_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_BOND_FAILED, self.dut_address,
- int(PairingFailedReason.ENCRYPTION_KEY_SIZE)))
-
- @metadata(
- pts_test_id="SM/MAS/SCPK/BV-01-C", pts_test_name="Passkey Entry, IUT Initiator, Secure Connections – Success")
- def test_passkey_entry_iut_initiator_secure_connections(self):
- """
- Verify that the IUT supporting LE Secure Connections performs the Passkey Entry pairing procedure correctly as central, initiator.
- """
- self._prepare_cert_for_connection()
-
- self.dut.security.SetLeIoCapability(DISPLAY_ONLY)
- self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.dut_security.SetLeAuthRequirements(secure_connections=1)
-
- self.cert.security.SetLeIoCapability(KEYBOARD_ONLY)
- self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1)
-
- # 1. IUT transmits Pairing Request command with:
- # a. IO capability set to “DisplayOnly” or “KeyboardOnly”
- # b. OOB data flag set to 0x00 (OOB Authentication data not present)
- # c. AuthReq bonding flag set to ‘00’, the MITM flag set to ‘0’ and Secure Connections flag set to '1'. Keypress bit is set to '1' if supported
- self.dut.security.CreateBondLe(self.cert_address)
-
- assertThat(self.cert_security.get_ui_stream()).emits(
- SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address))
-
- # 2. Lower Tester responds with a Pairing Response command, with:
- # a. IO capability set to “KeyboardOnly”
- # b. OOB data flag set to 0x00 (OOB Authentication data not present)
- # c. AuthReq bonding flag set to ‘00’, the MITM flag set to ‘1’, Secure Connections flag set to '1' and all reserved bits are set to ‘0’. Keypress bit is set to '1' if supported by the IUT.
- self.cert.security.SendUiCallback(
- UiCallbackMsg(
- message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.dut_address))
-
- assertThat(self.cert_security.get_ui_stream()).emits(
- SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PASSKEY_ENTRY, self.dut_address))
-
- # 3. During the phase 2 pairing, the IUT displays the 6-digit passkey while the Lower Tester prompts user to enter the 6-digit passkey. If the IUT’s IO capabilities are “KeyboardOnly” the passkey is not displayed and both IUT and Lower Tester enter the same 6-digit passkey. If Keypress bit is set, pairing keypress notifications are sent by the Lower Tester.
- passkey = self.dut_security.wait_for_ui_event_passkey()
-
- if passkey == 0:
- print("Passkey did not arrive into test")
-
- # 4. IUT and Lower Tester use the same 6-digit passkey.
- self.cert.security.SendUiCallback(
- UiCallbackMsg(
- message_type=UiCallbackType.PASSKEY, numeric_value=passkey, unique_id=1, address=self.dut_address))
-
- # 5. IUT and Lower Tester perform phase 2 of the Passkey Entry pairing procedure and establish an encrypted link with the LTK generated in phase 2.
- assertThat(self.dut_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address), timeout=timedelta(seconds=10))
-
- @metadata(
- pts_test_id="SM/SLA/SCPK/BV-02-C", pts_test_name="Passkey Entry, IUT Responder, Secure Connections – Success")
- def test_passkey_entry_iut_responder_secure_connections(self):
- """
- Verify that the IUT supporting LE Secure Connections is able to perform the Passkey Entry pairing procedure correctly when acting as peripheral, responder.
- """
- self._prepare_dut_for_connection()
-
- self.dut.security.SetLeIoCapability(DISPLAY_ONLY)
- self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.dut_security.SetLeAuthRequirements(secure_connections=1)
-
- self.cert.security.SetLeIoCapability(KEYBOARD_DISPLAY)
- self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1)
-
- # 1. Lower Tester transmits Pairing Request command with:
- # a. IO capability set to “KeyboardDisplay”
- # b. OOB data flag set to 0x00 (OOB Authentication data not present)
- # c. AuthReq bonding flag set to the value indicated in the IXIT [7] for ‘Bonding Flags’, and the MITM flag set to ‘1’ Secure Connections flag set to '1' and all reserved bits are set to ‘0’
- self.cert.security.CreateBondLe(self.dut_address)
-
- assertThat(self.dut_security.get_ui_stream()).emits(
- SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address))
-
- # 2. IUT responds with a Pairing Response command, with:
- # a. IO capability set to “KeyboardOnly” or “KeyboardDisplay” or “DisplayYesNo” or “DisplayOnly”
- # b. Secure Connections flag set to '1'. Keypress bit is set to '1' if supported by IUT
- self.dut.security.SendUiCallback(
- UiCallbackMsg(
- message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.cert_address))
-
- # 3. During the phase 2 passkey pairing process, Lower Tester displays the 6-digit passkey while the IUT prompts user to enter the 6-digit passkey. If the IO capabilities of the IUT are “DisplayYesNo” or “DisplayOnly” the IUT displays the 6-digit passkey while the Lower Tester enters the 6-digit passkey. If Keypress bit is set, pairing keypress notifications are send by the IUT
- passkey = self.dut_security.wait_for_ui_event_passkey()
-
- if passkey == 0:
- print("Passkey did not arrive into test")
-
- assertThat(self.cert_security.get_ui_stream()).emits(
- SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PASSKEY_ENTRY, self.dut_address))
-
- # 4. IUT and Lower Tester use the same pre-defined 6-digit passkey.
- self.cert.security.SendUiCallback(
- UiCallbackMsg(
- message_type=UiCallbackType.PASSKEY, numeric_value=passkey, unique_id=1, address=self.dut_address))
-
- # 5. IUT and Lower Tester perform phase 2 of the LE pairing and establish an encrypted link with the LTK generated in phase 2.
- assertThat(self.dut_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address), timeout=timedelta(seconds=10))
-
- @metadata(
- pts_test_id="SM/SLA/SCPK/BV-03-C",
- pts_test_name="Passkey Entry, IUT Responder, Secure Connections – Handle AuthReq Flag RFU Correctly")
- def test_passkey_entry_iut_responder_secure_connections_auth_req_rfu(self):
- """
- Verify that the IUT supporting LE Secure Connections is able to perform the Passkey Entry pairing procedure when receiving additional bits set in the AuthReq flag. Reserved For Future Use bits are correctly handled when acting as peripheral, responder.
- """
- self._prepare_dut_for_connection()
-
- self.dut.security.SetLeIoCapability(KEYBOARD_ONLY)
- self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.dut_security.SetLeAuthRequirements(secure_connections=1)
-
- self.cert.security.SetLeIoCapability(DISPLAY_ONLY)
- self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1, reserved_bits=3)
-
- # 1. Lower Tester transmits Pairing Request command with:
- # a. IO Capability set to ”KeyboardOnly”
- # b. OOB data flag set to 0x00 (OOB Authentication data not present)
- # c. MITM set to ‘1’ and all reserved bits are set to a random value
- self.cert.security.CreateBondLe(self.dut_address)
-
- assertThat(self.dut_security.get_ui_stream()).emits(
- SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address))
-
- # 2. IUT responds with a Pairing Response command, with:
- # a. IO Capability set to “KeyboardOnly” or “DisplayOnly”
- # b. OOB data flag set to 0x00 (OOB Authentication data not present)
- # c. All reserved bits are set to ‘0’
- self.dut.security.SendUiCallback(
- UiCallbackMsg(
- message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.cert_address))
-
- passkey = self.cert_security.wait_for_ui_event_passkey()
-
- if passkey == 0:
- print("Passkey did not arrive into test")
-
- assertThat(self.dut_security.get_ui_stream()).emits(
- SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PASSKEY_ENTRY, self.cert_address))
-
- self.dut.security.SendUiCallback(
- UiCallbackMsg(
- message_type=UiCallbackType.PASSKEY, numeric_value=passkey, unique_id=1, address=self.cert_address))
-
- # 3. IUT and Lower Tester perform phase 2 of the Passkey Entry pairing and establish an encrypted link with the generated LTK.
- assertThat(self.dut_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address), timeout=timedelta(seconds=10))
-
- @metadata(
- pts_test_id="SM/MAS/SCPK/BV-04-C",
- pts_test_name="Passkey Entry, IUT Initiator, Secure Connections – Handle AuthReq Flag RFU Correctly")
- def test_passkey_entry_iut_initiator_secure_connections_auth_req_rfu(self):
- """
- Verify that the IUT supporting LE Secure Connections is able to perform the Passkey Entry pairing procedure when receiving additional bits set in the AuthReq flag. Reserved For Future Use bits are correctly handled when acting as central, initiator.
- """
- self._prepare_cert_for_connection()
-
- self.dut.security.SetLeIoCapability(KEYBOARD_DISPLAY)
- self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.dut_security.SetLeAuthRequirements(secure_connections=1)
-
- self.cert.security.SetLeIoCapability(KEYBOARD_ONLY)
- self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
- self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1, reserved_bits=3)
-
- # 1. IUT transmits a Pairing Request command with:
- # a. IO Capability set to “DisplayOnly” or “DisplayYesNo” or “KeyboardOnly” or “KeyboardDisplay”
- # b. OOB data flag set to 0x00 (OOB Authentication data not present)
- # c. All reserved bits are set to ‘0’.
- self.dut.security.CreateBondLe(self.cert_address)
-
- assertThat(self.cert_security.get_ui_stream()).emits(
- SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address))
-
- # 2. Lower Tester responds with a Pairing Response command, with:
- # a. IO Capability set to “KeyboardOnly”
- # b. OOB data flag set to 0x00 (OOB Authentication data not present)
- # c. AuthReq bonding flag set to the value indicated in the IXIT [7] for ‘Bonding Flags’ and the MITM flag set to ‘1’ and all reserved bits are set to a random value.
- self.cert.security.SendUiCallback(
- UiCallbackMsg(
- message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.dut_address))
-
- assertThat(self.cert_security.get_ui_stream()).emits(
- SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PASSKEY_ENTRY, self.dut_address))
-
- passkey = self.dut_security.wait_for_ui_event_passkey()
-
- self.cert.security.SendUiCallback(
- UiCallbackMsg(
- message_type=UiCallbackType.PASSKEY, numeric_value=passkey, unique_id=1, address=self.dut_address))
-
- # 3. IUT and Lower Tester perform phase 2 of the Just Works pairing and establish an encrypted link with the generated LTK.
- assertThat(self.dut_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address), timeout=timedelta(seconds=10))
-
- @metadata(
- pts_test_id="SM/MAS/SCOB/BV-01-C", pts_test_name="Out of Band, IUT Initiator, Secure Connections – Success")
- def test_out_of_band_iut_initiator_secure_connections(self):
- """
- Verify that the IUT supporting LE Secure Connections performs the Out-of-Band pairing procedure correctly as central, initiator.
- """
-
- oob_combinations = [(OOB_NOT_PRESENT, OOB_PRESENT), (OOB_PRESENT, OOB_NOT_PRESENT), (OOB_PRESENT, OOB_PRESENT)]
-
- for (dut_oob_flag, cert_oob_flag) in oob_combinations:
- print("oob flag combination dut: " + str(dut_oob_flag) + ", cert: " + str(cert_oob_flag))
-
- self._prepare_cert_for_connection()
-
- if dut_oob_flag == LeOobDataFlag.PRESENT:
- oobdata = self.cert.security.GetLeOutOfBandData(empty_proto.Empty())
- self.dut.security.SetOutOfBandData(
- OobDataMessage(
- address=self.cert_address,
- confirmation_value=oobdata.confirmation_value,
- random_value=oobdata.random_value))
-
- if cert_oob_flag == LeOobDataFlag.PRESENT:
- oobdata = self.dut.security.GetLeOutOfBandData(empty_proto.Empty())
- self.cert.security.SetOutOfBandData(
- OobDataMessage(
- address=self.dut_address,
- confirmation_value=oobdata.confirmation_value,
- random_value=oobdata.random_value))
-
- self.dut.security.SetLeIoCapability(KEYBOARD_ONLY)
- self.dut.security.SetLeOobDataPresent(dut_oob_flag)
- self.dut_security.SetLeAuthRequirements(bond=1, mitm=1, secure_connections=1)
-
- self.cert.security.SetLeIoCapability(DISPLAY_ONLY)
- self.cert.security.SetLeOobDataPresent(cert_oob_flag)
- self.cert_security.SetLeAuthRequirements(bond=1, mitm=1, secure_connections=1)
-
- # 1. IUT transmits a Pairing Request command with OOB data flag set to either 0x00 or 0x01, and Secure Connections flag set to '1'.
- self.dut.security.CreateBondLe(self.cert_address)
-
- assertThat(self.cert_security.get_ui_stream()).emits(
- SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address))
-
- # 2. Lower Tester responds with a Pairing Response command with Secure Connections flag set to '1' and OOB data flag set to either 0x00 or 0x01.
- self.cert.security.SendUiCallback(
- UiCallbackMsg(
- message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.dut_address))
-
- # 3. IUT uses the 128-bit value generated by the Lower Tester as the confirm value. Similarly, the Lower Tester uses the 128-bit value generated by the IUT as the confirm value.
-
- # 4. IUT and Lower Tester perform phase 2 of the pairing process and establish an encrypted link with an LTK generated using the OOB data in phase 2.
- assertThat(self.dut_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address), timeout=timedelta(seconds=10))
-
- assertThat(self.cert_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.dut_address), timeout=timedelta(seconds=10))
-
- self.dut.security.RemoveBond(self.cert_address)
- self.cert.security.RemoveBond(self.dut_address)
-
- assertThat(self.dut_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_UNBONDED, self.cert_address))
-
- self.dut_security.wait_device_disconnect(self.cert_address)
- self.cert_security.wait_device_disconnect(self.dut_address)
-
- @metadata(
- pts_test_id="SM/SLA/SCOB/BV-02-C", pts_test_name="Out of Band, IUT Responder, Secure Connections – Success")
- def test_out_of_band_iut_responder_secure_connections(self):
- """
- Verify that the IUT supporting LE Secure Connections is able to perform the Out-of-Band pairing procedure correctly when acting as peripheral, responder.
- """
-
- oob_combinations = [(OOB_NOT_PRESENT, OOB_PRESENT), (OOB_PRESENT, OOB_NOT_PRESENT), (OOB_PRESENT, OOB_PRESENT)]
-
- for (dut_oob_flag, cert_oob_flag) in oob_combinations:
- print("oob flag combination dut: " + str(dut_oob_flag) + ", cert: " + str(cert_oob_flag))
-
- self._prepare_dut_for_connection()
-
- if dut_oob_flag == LeOobDataFlag.PRESENT:
- oobdata = self.cert.security.GetLeOutOfBandData(empty_proto.Empty())
- self.dut.security.SetOutOfBandData(
- OobDataMessage(
- address=self.cert_address,
- confirmation_value=oobdata.confirmation_value,
- random_value=oobdata.random_value))
-
- if cert_oob_flag == LeOobDataFlag.PRESENT:
- oobdata = self.dut.security.GetLeOutOfBandData(empty_proto.Empty())
- self.cert.security.SetOutOfBandData(
- OobDataMessage(
- address=self.dut_address,
- confirmation_value=oobdata.confirmation_value,
- random_value=oobdata.random_value))
-
- self.dut.security.SetLeIoCapability(KEYBOARD_ONLY)
- self.dut.security.SetLeOobDataPresent(dut_oob_flag)
- self.dut_security.SetLeAuthRequirements(bond=1, mitm=1, secure_connections=1)
-
- self.cert.security.SetLeIoCapability(DISPLAY_ONLY)
- self.cert.security.SetLeOobDataPresent(cert_oob_flag)
- self.cert_security.SetLeAuthRequirements(bond=1, mitm=1, secure_connections=1)
-
- # 1. Lower Tester transmits a Pairing Request command with OOB data flag set to either 0x00 or 0x01, and Secure Connections flag set to '1'.
- self.cert.security.CreateBondLe(self.dut_address)
-
- assertThat(self.dut_security.get_ui_stream()).emits(
- SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address))
-
- # 2. IUT responds with a Pairing Response command with Secure Connections flag set to '1' and OOB data flag set to either 0x00 or 0x01.
- self.dut.security.SendUiCallback(
- UiCallbackMsg(
- message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.cert_address))
-
- # 3. IUT uses the 128-bit value generated by the Lower Tester as the confirm value. Similarly, the Lower Tester uses the 128-bit value generated by the IUT as the confirm value.
-
- # 4. IUT and Lower Tester perform phase 2 of the pairing process and establish an encrypted link with an LTK generated using the OOB data in phase 2.
- assertThat(self.cert_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.dut_address), timeout=timedelta(seconds=10))
-
- assertThat(self.dut_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address), timeout=timedelta(seconds=10))
-
- self.cert.security.RemoveBond(self.dut_address)
- self.dut.security.RemoveBond(self.cert_address)
-
- assertThat(self.dut_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_UNBONDED, self.cert_address))
-
- self.cert_security.wait_device_disconnect(self.dut_address)
- self.dut_security.wait_device_disconnect(self.cert_address)
-
- @metadata(
- pts_test_id="SM/SLA/SCOB/BV-03-C",
- pts_test_name="Out of Band, IUT Responder, Secure Connections – Handle AuthReq Flag RFU Correctly")
- def test_out_of_band_iut_responder_secure_connections_auth_req_rfu(self):
- """
- Verify that the IUT supporting LE Secure Connections is able to perform the Out-of-Band pairing procedure when receiving additional bits set in the AuthReq flag. Reserved For Future Use bits are correctly handled when acting as peripheral, responder.
- """
-
- reserved_bits_combinations = [1, 2, 3]
-
- for reserved_bits in reserved_bits_combinations:
- print("reserved bits in cert dut: " + str(reserved_bits))
-
- self._prepare_dut_for_connection()
-
- oobdata = self.cert.security.GetLeOutOfBandData(empty_proto.Empty())
- self.dut.security.SetOutOfBandData(
- OobDataMessage(
- address=self.cert_address,
- confirmation_value=oobdata.confirmation_value,
- random_value=oobdata.random_value))
-
- oobdata = self.dut.security.GetLeOutOfBandData(empty_proto.Empty())
- self.cert.security.SetOutOfBandData(
- OobDataMessage(
- address=self.dut_address,
- confirmation_value=oobdata.confirmation_value,
- random_value=oobdata.random_value))
-
- self.dut.security.SetLeIoCapability(KEYBOARD_ONLY)
- self.dut.security.SetLeOobDataPresent(OOB_PRESENT)
- self.dut_security.SetLeAuthRequirements(bond=1, mitm=0, secure_connections=1)
-
- self.cert.security.SetLeIoCapability(DISPLAY_ONLY)
- self.cert.security.SetLeOobDataPresent(OOB_PRESENT)
- self.cert_security.SetLeAuthRequirements(bond=1, mitm=1, secure_connections=1, reserved_bits=reserved_bits)
-
- # 1. Lower Tester transmits Pairing Request command with:
- # a. IO Capability set to any IO capability
- # b. OOB data flag set to 0x01 (OOB Authentication data from remote device present)
- # c. MITM set to ‘0’, Secure Connections flag is set to '1', and all reserved bits are set to a random value.
- self.cert.security.CreateBondLe(self.dut_address)
-
- assertThat(self.dut_security.get_ui_stream()).emits(
- SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address))
-
- # 2. IUT responds with a Pairing Response command, with:
- # a. IO Capability set to any IO capability
- # b. OOB data flag set to 0x01 (OOB Authentication data present)
- # c. Secure Connections flag is set to '1', All reserved bits are set to ‘0’
- self.dut.security.SendUiCallback(
- UiCallbackMsg(
- message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.cert_address))
-
- # 3. IUT and Lower Tester perform phase 2 of the OOB authenticated pairing and establish an encrypted link with the generated LTK.
-
- assertThat(self.cert_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.dut_address), timeout=timedelta(seconds=10))
-
- assertThat(self.dut_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address), timeout=timedelta(seconds=10))
-
- self.cert.security.RemoveBond(self.dut_address)
- self.dut.security.RemoveBond(self.cert_address)
-
- assertThat(self.dut_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_UNBONDED, self.cert_address))
-
- self.dut_security.wait_device_disconnect(self.cert_address)
- self.cert_security.wait_device_disconnect(self.dut_address)
-
- @metadata(
- pts_test_id="SM/MAS/SCOB/BV-04-C",
- pts_test_name="Out of Band, IUT Initiator, Secure Connections – Handle AuthReq Flag RFU Correctly")
- def test_out_of_band_iut_initiator_secure_connections_auth_req_rfu(self):
- """
- Verify that the IUT supporting LE Secure Connections is able to perform the Out-of-Band pairing procedure when receiving additional bits set in the AuthReq flag. Reserved For Future Use bits are correctly handled when acting as central, initiator.
- """
-
- reserved_bits_combinations = [1, 2, 3]
-
- for reserved_bits in reserved_bits_combinations:
- print("reserved bits in cert dut: " + str(reserved_bits))
-
- self._prepare_cert_for_connection()
-
- oobdata = self.cert.security.GetLeOutOfBandData(empty_proto.Empty())
- self.dut.security.SetOutOfBandData(
- OobDataMessage(
- address=self.cert_address,
- confirmation_value=oobdata.confirmation_value,
- random_value=oobdata.random_value))
-
- oobdata = self.dut.security.GetLeOutOfBandData(empty_proto.Empty())
- self.cert.security.SetOutOfBandData(
- OobDataMessage(
- address=self.dut_address,
- confirmation_value=oobdata.confirmation_value,
- random_value=oobdata.random_value))
-
- self.dut.security.SetLeIoCapability(KEYBOARD_ONLY)
- self.dut.security.SetLeOobDataPresent(OOB_PRESENT)
- self.dut_security.SetLeAuthRequirements(bond=1, mitm=0, secure_connections=1, reserved_bits=0)
-
- self.cert.security.SetLeIoCapability(DISPLAY_ONLY)
- self.cert.security.SetLeOobDataPresent(OOB_PRESENT)
- self.cert_security.SetLeAuthRequirements(bond=1, mitm=1, secure_connections=1, reserved_bits=reserved_bits)
-
- # 1. IUT transmits Pairing Request command with:
- # a. IO Capability set to any IO capability
- # b. OOB data flag set to 0x01 (OOB Authentication data present)
- # c. MITM set to ‘0’, Secure Connections flag is set to '1', and all reserved bits are set to ‘0’
- self.dut.security.CreateBondLe(self.cert_address)
-
- assertThat(self.cert_security.get_ui_stream()).emits(
- SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address))
-
- # 2. Lower Tester responds with a Pairing Response command, with:
- # a. IO Capability set to any IO capability
- # b. OOB data flag set to 0x01 (OOB Authentication data present)
- # c. Secure Connections flag is set to '1', and all reserved bits are set to a random value.
- self.cert.security.SendUiCallback(
- UiCallbackMsg(
- message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.dut_address))
-
- # 3. IUT and Lower Tester perform phase 2 of the OOB authenticated pairing and establish an encrypted link with the generated LTK.
-
- assertThat(self.dut_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address), timeout=timedelta(seconds=10))
-
- assertThat(self.cert_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.dut_address), timeout=timedelta(seconds=10))
-
- self.dut.security.RemoveBond(self.cert_address)
- self.cert.security.RemoveBond(self.dut_address)
-
- assertThat(self.dut_security.get_bond_stream()).emits(
- SecurityMatchers.BondMsg(BondMsgType.DEVICE_UNBONDED, self.cert_address))
-
- self.dut_security.wait_device_disconnect(self.cert_address)
- self.cert_security.wait_device_disconnect(self.dut_address)
+ LeSecurityTestBase.teardown_test(self)
+ GdBaseTestClass.teardown_test(self)
diff --git a/gd/security/cert/le_security_test_lib.py b/gd/security/cert/le_security_test_lib.py
new file mode 100644
index 0000000..789963b
--- /dev/null
+++ b/gd/security/cert/le_security_test_lib.py
@@ -0,0 +1,1092 @@
+#
+# 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 time
+
+from bluetooth_packets_python3 import hci_packets
+from bluetooth_packets_python3 import security_packets
+from cert.event_stream import EventStream
+from cert.matchers import HciMatchers
+from cert.matchers import SecurityMatchers
+from cert.metadata import metadata
+from cert.py_hci import PyHci
+from cert.py_le_security import PyLeSecurity
+from cert.truth import assertThat
+from datetime import timedelta
+from facade import common_pb2 as common
+from hci.facade import controller_facade_pb2 as controller_facade
+from hci.facade import le_advertising_manager_facade_pb2 as le_advertising_facade
+from hci.facade import le_initiator_address_facade_pb2 as le_initiator_address_facade
+from google.protobuf import empty_pb2 as empty_proto
+from neighbor.facade import facade_pb2 as neighbor_facade
+from security.cert.cert_security import CertSecurity
+from security.facade_pb2 import AuthenticationRequirements
+from security.facade_pb2 import BondMsgType
+from security.facade_pb2 import OobDataMessage
+from security.facade_pb2 import UiCallbackMsg
+from security.facade_pb2 import UiCallbackType
+from security.facade_pb2 import UiMsgType
+from security.facade_pb2 import LeAuthRequirementsMessage
+from security.facade_pb2 import LeIoCapabilityMessage
+from security.facade_pb2 import LeOobDataPresentMessage
+from security.facade_pb2 import LeMaximumEncryptionKeySizeMessage
+
+from bluetooth_packets_python3.hci_packets import OpCode
+from bluetooth_packets_python3.security_packets import PairingFailedReason
+
+from mobly import asserts
+
+LeIoCapabilities = LeIoCapabilityMessage.LeIoCapabilities
+LeOobDataFlag = LeOobDataPresentMessage.LeOobDataFlag
+
+DISPLAY_ONLY = LeIoCapabilityMessage(capabilities=LeIoCapabilities.DISPLAY_ONLY)
+KEYBOARD_ONLY = LeIoCapabilityMessage(capabilities=LeIoCapabilities.KEYBOARD_ONLY)
+NO_INPUT_NO_OUTPUT = LeIoCapabilityMessage(capabilities=LeIoCapabilities.NO_INPUT_NO_OUTPUT)
+KEYBOARD_DISPLAY = LeIoCapabilityMessage(capabilities=LeIoCapabilities.KEYBOARD_DISPLAY)
+
+OOB_NOT_PRESENT = LeOobDataPresentMessage(data_present=LeOobDataFlag.NOT_PRESENT)
+OOB_PRESENT = LeOobDataPresentMessage(data_present=LeOobDataFlag.PRESENT)
+
+
+class LeSecurityTestBase():
+ """
+ Collection of tests that each sample results from
+ different (unique) combinations of io capabilities, authentication requirements, and oob data.
+ """
+
+ def setup_test(self, dut, cert):
+ self.dut = dut
+ self.cert = cert
+
+ self.dut_security = PyLeSecurity(self.dut)
+ self.cert_security = PyLeSecurity(self.cert)
+ self.dut_hci = PyHci(self.dut)
+
+ raw_addr = self.dut.hci_controller.GetMacAddress(empty_proto.Empty()).address
+
+ self.dut_address = common.BluetoothAddressWithType(
+ address=common.BluetoothAddress(address=raw_addr), type=common.PUBLIC_DEVICE_ADDRESS)
+ privacy_policy = le_initiator_address_facade.PrivacyPolicy(
+ address_policy=le_initiator_address_facade.AddressPolicy.USE_PUBLIC_ADDRESS,
+ address_with_type=self.dut_address)
+ self.dut.security.SetLeInitiatorAddressPolicy(privacy_policy)
+ self.cert_address = common.BluetoothAddressWithType(
+ address=common.BluetoothAddress(
+ address=self.cert.hci_controller.GetMacAddress(empty_proto.Empty()).address),
+ type=common.PUBLIC_DEVICE_ADDRESS)
+ cert_privacy_policy = le_initiator_address_facade.PrivacyPolicy(
+ address_policy=le_initiator_address_facade.AddressPolicy.USE_PUBLIC_ADDRESS,
+ address_with_type=self.cert_address)
+ self.cert.security.SetLeInitiatorAddressPolicy(cert_privacy_policy)
+
+ asserts.skip("Unhandled race condition - Flaky test")
+
+ def teardown_test(self):
+ self.dut_hci.close()
+ self.dut_security.close()
+ self.cert_security.close()
+
+ def _prepare_cert_for_connection(self):
+ # DUT Advertises
+ gap_name = hci_packets.GapData()
+ gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
+ gap_name.data = list(bytes(b'Im_The_CERT'))
+ gap_data = le_advertising_facade.GapDataMsg(data=bytes(gap_name.Serialize()))
+ config = le_advertising_facade.AdvertisingConfig(
+ advertisement=[gap_data],
+ interval_min=512,
+ interval_max=768,
+ advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
+ own_address_type=common.USE_PUBLIC_DEVICE_ADDRESS,
+ channel_map=7,
+ filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
+ request = le_advertising_facade.CreateAdvertiserRequest(config=config)
+ create_response = self.cert.hci_le_advertising_manager.CreateAdvertiser(request)
+
+ def _prepare_dut_for_connection(self):
+ # DUT Advertises
+ gap_name = hci_packets.GapData()
+ gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
+ gap_name.data = list(bytes(b'Im_The_DUT'))
+ gap_data = le_advertising_facade.GapDataMsg(data=bytes(gap_name.Serialize()))
+ config = le_advertising_facade.AdvertisingConfig(
+ advertisement=[gap_data],
+ interval_min=512,
+ interval_max=768,
+ advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
+ own_address_type=common.USE_PUBLIC_DEVICE_ADDRESS,
+ channel_map=7,
+ filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
+ request = le_advertising_facade.CreateAdvertiserRequest(config=config)
+ create_response = self.dut.hci_le_advertising_manager.CreateAdvertiser(request)
+
+ @metadata(pts_test_id="SM/MAS/PROT/BV-01-C", pts_test_name="SMP Time Out – IUT Initiator")
+ def test_le_smp_timeout_iut_initiator(self):
+ """
+ Verify that the IUT handles the lack of pairing response after 30 seconds when acting as initiator.
+ """
+ self._prepare_cert_for_connection()
+ self.dut.security.CreateBondLe(self.cert_address)
+ assertThat(self.dut_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_BOND_FAILED, self.cert_address), timeout=timedelta(seconds=35))
+
+ @metadata(pts_test_id="SM/SLA/PROT/BV-02-C", pts_test_name="SMP Time Out – IUT Responder")
+ def test_le_smp_timeout_iut_responder(self):
+ """
+ Verify that the IUT handles the lack of pairing response after 30 seconds when acting as initiator.
+ """
+ self.cert.security.SetLeIoCapability(KEYBOARD_ONLY)
+ self.dut.security.SetLeIoCapability(DISPLAY_ONLY)
+
+ self._prepare_dut_for_connection()
+
+ # 1. Lower Tester transmits Pairing Request.
+ self.cert.security.CreateBondLe(self.dut_address)
+
+ assertThat(self.dut_security.get_ui_stream()).emits(
+ SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address), timeout=timedelta(seconds=35))
+
+ # 2. IUT responds with Pairing Response.
+ self.dut.security.SendUiCallback(
+ UiCallbackMsg(
+ message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.cert_address))
+
+ # 3. In phase 2, Lower Tester does not issue the expected Pairing Confirm.
+
+ # Here the cert receives DISPLAY_PASSKEY_ENTRY. By not replying to it we make sure Pairing Confirm is never sent
+ assertThat(self.cert_security.get_ui_stream()).emits(
+ SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PASSKEY_ENTRY, self.dut_address), timeout=timedelta(seconds=5))
+
+ # 4. IUT times out 30 seconds after issued Pairing Response and reports the failure to the Upper Tester.
+ assertThat(self.dut_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_BOND_FAILED, self.cert_address), timeout=timedelta(seconds=35))
+
+ # 5. After additionally (at least) 10 seconds the Lower Tester issues the expected Pairing Confirm.
+ # 6. The IUT closes the connection before receiving the delayed response or does not respond to it when it is received.
+ #TODO:
+ #assertThat(self.dut_hci.get_event_stream()).emits(HciMatchers.Disconnect())
+
+ @metadata(pts_test_id="SM/MAS/JW/BV-01-C", pts_test_name="Just Works IUT Initiator – Success")
+ def test_just_works_iut_initiator(self):
+ """
+ Verify that the IUT performs the Just Works pairing procedure correctly as central, initiator when both sides do not require MITM protection.
+ """
+ self._prepare_cert_for_connection()
+
+ self.dut.security.SetLeIoCapability(KEYBOARD_ONLY)
+ self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.dut_security.SetLeAuthRequirements()
+
+ self.cert.security.SetLeIoCapability(DISPLAY_ONLY)
+ self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.cert_security.SetLeAuthRequirements()
+
+ # 1. IUT transmits Pairing Request command with:
+ # a. IO capability set to any IO capability
+ # b. OOB data flag set to 0x00 (OOB Authentication data not present)
+ # c. AuthReq Bonding Flags set to ‘00’ and the MITM flag set to ‘0’ and all the reserved bits are set to ‘0’
+ self.dut.security.CreateBondLe(self.cert_address)
+
+ assertThat(self.cert_security.get_ui_stream()).emits(
+ SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address))
+
+ # 2. Lower Tester responds with a Pairing Response command, with:
+ # a. IO capability set to “KeyboardDisplay”
+ # b. OOB data flag set to 0x00 (OOB Authentication data not present)
+ # c. AuthReq Bonding Flags set to ‘00’, and the MITM flag set to ‘0’ and all the reserved bits are set to ‘0’
+ self.cert.security.SendUiCallback(
+ UiCallbackMsg(
+ message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.dut_address))
+
+ # 3. IUT and Lower Tester perform phase 2 of the just works pairing procedure and establish an encrypted link with the key generated in phase 2.
+ assertThat(self.dut_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address))
+
+ @metadata(pts_test_id="SM/SLA/JW/BV-02-C", pts_test_name="Just Works IUT Responder – Success")
+ def test_just_works_iut_responder(self):
+ """
+ Verify that the IUT is able to perform the Just Works pairing procedure correctly when acting as peripheral, responder.
+ """
+ self._prepare_dut_for_connection()
+
+ self.dut.security.SetLeIoCapability(KEYBOARD_ONLY)
+ self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.dut_security.SetLeAuthRequirements()
+
+ self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT)
+ self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.cert_security.SetLeAuthRequirements()
+
+ # 1. Lower Tester transmits Pairing Request command with:
+ # a. IO capability set to “NoInputNoOutput”
+ # b. OOB data flag set to 0x00 (OOB Authentication data not present)
+ # c. MITM flag set to ‘0’ and all reserved bits are set to ‘0’
+ self.cert.security.CreateBondLe(self.dut_address)
+
+ assertThat(self.dut_security.get_ui_stream()).emits(
+ SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address))
+
+ # 2. IUT responds with a Pairing Response command, with:
+ # a. IO capability set to any IO capability
+ # b. OOB data flag set to 0x00 (OOB Authentication data not present)
+ self.dut.security.SendUiCallback(
+ UiCallbackMsg(
+ message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.cert_address))
+
+ # IUT and Lower Tester perform phase 2 of the just works pairing and establish an encrypted link with the generated STK.
+ assertThat(self.dut_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address))
+
+ @metadata(
+ pts_test_id="SM/SLA/JW/BI-03-C", pts_test_name="Just Works IUT Responder – Handle AuthReq flag RFU correctly")
+ def test_just_works_iut_responder_auth_req_rfu(self):
+ """
+ Verify that the IUT is able to perform the Just Works pairing procedure when receiving additional bits set in the AuthReq flag. Reserved For Future Use bits are correctly handled when acting as peripheral, responder.
+ """
+ self._prepare_dut_for_connection()
+
+ self.dut.security.SetLeIoCapability(KEYBOARD_DISPLAY)
+ self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.dut_security.SetLeAuthRequirements()
+
+ self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT)
+ self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1, reserved_bits=2)
+
+ # 1. Lower Tester transmits Pairing Request command with:
+ # a. IO Capability set to ”NoInputNoOutput”
+ # b. OOB data flag set to 0x00 (OOB Authentication data not present)
+ # c. MITM set to ‘0’ and all reserved bits are set to ‘1’
+ self.cert.security.CreateBondLe(self.dut_address)
+
+ assertThat(self.dut_security.get_ui_stream()).emits(
+ SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address))
+
+ # 2. IUT responds with a Pairing Response command, with:
+ # a. IO capability set to any IO capability
+ # b. OOB data flag set to 0x00 (OOB Authentication data not present)
+ # c. All reserved bits are set to ‘0’
+ self.dut.security.SendUiCallback(
+ UiCallbackMsg(
+ message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.cert_address))
+
+ # 3. IUT and Lower Tester perform phase 2 of the just works pairing and establish an encrypted link with the generated STK.
+ assertThat(self.dut_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address))
+
+ @metadata(
+ pts_test_id="SM/MAS/JW/BI-04-C", pts_test_name="Just Works IUT Initiator – Handle AuthReq flag RFU correctly")
+ def test_just_works_iut_initiator_auth_req_rfu(self):
+ """
+ Verify that the IUT is able to perform the Just Works pairing procedure when receiving additional bits set in the AuthReq flag. Reserved For Future Use bits are correctly handled when acting as central, initiator.
+ """
+ self._prepare_cert_for_connection()
+
+ self.dut.security.SetLeIoCapability(KEYBOARD_DISPLAY)
+ self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.dut_security.SetLeAuthRequirements()
+
+ self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT)
+ self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1, reserved_bits=3)
+
+ # 1. IUT transmits a Pairing Request command with:
+ # a. IO Capability set to any IO Capability
+ # b. OOB data flag set to 0x00 (OOB Authentication data not present)
+ # c. All reserved bits are set to ‘0’. For the purposes of this test the Secure Connections bit and the Keypress bits in the AuthReq bonding flag set by the IUT are ignored by the Lower Tester.
+ self.dut.security.CreateBondLe(self.cert_address)
+
+ assertThat(self.cert_security.get_ui_stream()).emits(
+ SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address))
+
+ # 2. Lower Tester responds with a Pairing Response command, with:
+ # a. IO Capability set to “NoInputNoOutput”
+ # b. OOB data flag set to 0x00 (OOB Authentication data not present)
+ # c. AuthReq bonding flag set to the value indicated in the IXIT [7] for ‘Bonding Flags’ and the MITM flag set to ‘0’ and all reserved bits are set to ‘1’. The SC and Keypress bits in the AuthReq bonding flag are set to 0 by the Lower Tester for this test.
+ self.cert.security.SendUiCallback(
+ UiCallbackMsg(
+ message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.dut_address))
+
+ # 3. IUT and Lower Tester perform phase 2 of the just works pairing and establish an encrypted link with the generated STK.
+ assertThat(self.dut_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address))
+
+ @metadata(
+ pts_test_id="SM/MAS/SCJW/BV-01-C", pts_test_name="Just Works, IUT Initiator, Secure Connections – Success")
+ def test_just_works_iut_initiator_secure_connections(self):
+ """
+ Verify that the IUT supporting LE Secure Connections performs the Just Works or Numeric Comparison pairing procedure correctly as initiator.
+ """
+ self._prepare_cert_for_connection()
+
+ self.dut.security.SetLeIoCapability(KEYBOARD_ONLY)
+ self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.dut_security.SetLeAuthRequirements(secure_connections=1)
+
+ self.cert.security.SetLeIoCapability(DISPLAY_ONLY)
+ self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.cert_security.SetLeAuthRequirements(secure_connections=1)
+
+ # 1. IUT transmits Pairing Request command with:
+ # a. IO capability set to any IO capability
+ # b. OOB data flag set to 0x00 (OOB Authentication data not present)
+ # c. AuthReq Bonding Flags set to ‘00’, the MITM flag set to either ‘0’ for Just Works or '1' for Numeric Comparison, Secure Connections flag set to '1' and all the reserved bits are set to ‘0’
+ self.dut.security.CreateBondLe(self.cert_address)
+
+ assertThat(self.cert_security.get_ui_stream()).emits(
+ SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address))
+
+ # 2. Lower Tester responds with a Pairing Response command, with:
+ # a. IO capability set to “KeyboardDisplay”
+ # b. OOB data flag set to 0x00 (OOB Authentication data not present)
+ # c. AuthReq Bonding Flags set to ‘00’, the MITM flag set to ‘0’, Secure Connections flag set to '1' and all the reserved bits are set to ‘0’
+ self.cert.security.SendUiCallback(
+ UiCallbackMsg(
+ message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.dut_address))
+
+ # 3. IUT and Lower Tester perform phase 2 of the Just Works or Numeric Comparison pairing procedure according to the MITM flag and IO capabilities, and establish an encrypted link with the LTK generated in phase 2.
+ assertThat(self.dut_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address))
+
+ @metadata(
+ pts_test_id="SM/SLA/SCJW/BV-02-C", pts_test_name="Just Works, IUT Responder, Secure Connections – Success")
+ def test_just_works_iut_responder_secure_connections(self):
+ """
+ Verify that the IUT supporting LE Secure Connections is able to perform the Just Works or Numeric Comparison pairing procedure correctly when acting as responder.
+ """
+ self._prepare_dut_for_connection()
+
+ self.dut.security.SetLeIoCapability(KEYBOARD_ONLY)
+ self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.dut_security.SetLeAuthRequirements(secure_connections=1)
+
+ self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT)
+ self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.cert_security.SetLeAuthRequirements(secure_connections=1)
+
+ # 1. Lower Tester transmits Pairing Request command with:
+ # a. IO capability set to “NoInputNoOutput”
+ # b. OOB data flag set to 0x00 (OOB Authentication data not present)
+ # c. AuthReq Bonding Flags set to ‘00’, MITM flag set to ‘0’, Secure Connections flag set to '1' and all reserved bits are set to ‘0’
+ self.cert.security.CreateBondLe(self.dut_address)
+
+ assertThat(self.dut_security.get_ui_stream()).emits(
+ SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address))
+
+ # 2. IUT responds with a Pairing Response command, with:
+ # a. IO capability set to any IO capability
+ # b. AuthReq Bonding Flags set to ‘00’, MITM flag set to either ‘0’ for Just Works or '1' for Numeric Comparison, Secure Connections flag set to '1' and all reserved bits are set to ‘0’
+ self.dut.security.SendUiCallback(
+ UiCallbackMsg(
+ message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.cert_address))
+
+ # 3. UT and Lower Tester perform phase 2 of the Just Works or Numeric Comparison pairing procedure according to the MITM flag and IO capabilities, and establish an encrypted link with the LTK generated in phase 2.
+ assertThat(self.dut_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address))
+
+ @metadata(
+ pts_test_id="SM/SLA/SCJW/BV-03-C",
+ pts_test_name="Just Works, IUT Responder, Secure Connections – Handle AuthReq Flag RFU Correctly")
+ def test_just_works_iut_responder_secure_connections_auth_req_rfu(self):
+ """
+ Verify that the IUT is able to perform the Just Works pairing procedure when receiving additional bits set in the AuthReq flag. Reserved For Future Use bits are correctly handled when acting as peripheral, responder.
+ """
+ self._prepare_dut_for_connection()
+
+ self.dut.security.SetLeIoCapability(KEYBOARD_DISPLAY)
+ self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.dut_security.SetLeAuthRequirements(secure_connections=1)
+
+ self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT)
+ self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1, reserved_bits=3)
+
+ # 1. Lower Tester transmits Pairing Request command with:
+ # a. IO Capability set to ”NoInputNoOutput”
+ # b. OOB data flag set to 0x00 (OOB Authentication data not present)
+ # c. MITM set to ‘0’ and all reserved bits are set to a random value.
+ self.cert.security.CreateBondLe(self.dut_address)
+
+ assertThat(self.dut_security.get_ui_stream()).emits(
+ SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address))
+
+ # 2. IUT responds with a Pairing Response command, with:
+ # a. IO capability set to any IO capability
+ # b. OOB data flag set to 0x00 (OOB Authentication data not present)
+ # c. All reserved bits are set to ‘0’
+ self.dut.security.SendUiCallback(
+ UiCallbackMsg(
+ message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.cert_address))
+
+ # 3. IUT and Lower Tester perform phase 2 of the Just Works pairing and establish an encrypted link with the generated LTK.
+ assertThat(self.dut_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address))
+
+ @metadata(
+ pts_test_id="SM/MAS/SCJW/BV-04-C",
+ pts_test_name="Just Works, IUT Initiator, Secure Connections – Handle AuthReq Flag RFU Correctly")
+ def test_just_works_iut_initiator_secure_connections_auth_req_rfu(self):
+ """
+ Verify that the IUT is able to perform the Just Works pairing procedure when receiving additional bits set in the AuthReq flag. Reserved For Future Use bits are correctly handled when acting as central, initiator.
+ """
+ self._prepare_cert_for_connection()
+
+ self.dut.security.SetLeIoCapability(KEYBOARD_DISPLAY)
+ self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.dut_security.SetLeAuthRequirements(secure_connections=1)
+
+ self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT)
+ self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1, reserved_bits=3)
+
+ # 1. IUT transmits a Pairing Request command with:
+ # a. IO Capability set to any IO Capability
+ # b. OOB data flag set to 0x00 (OOB Authentication data not present)
+ # c. All reserved bits are set to ‘0’.
+ self.dut.security.CreateBondLe(self.cert_address)
+
+ assertThat(self.cert_security.get_ui_stream()).emits(
+ SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address))
+
+ # 2. Lower Tester responds with a Pairing Response command, with:
+ # a. IO Capability set to “NoInputNoOutput”
+ # b. OOB data flag set to 0x00 (OOB Authentication data not present)
+ # c. AuthReq bonding flag set to the value indicated in the IXIT [7] for ‘Bonding Flags’ and the MITM flag set to ‘0’ and all reserved bits are set to a random value.
+ self.cert.security.SendUiCallback(
+ UiCallbackMsg(
+ message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.dut_address))
+
+ # 3. IUT and Lower Tester perform phase 2 of the Just Works pairing and establish an encrypted link with the generated LTK.
+ assertThat(self.dut_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address))
+
+ @metadata(
+ pts_test_id="SM/MAS/EKS/BV-01-C",
+ pts_test_name="IUT initiator, Lower Tester Maximum Encryption Key Size = Min_Encryption_Key_Length")
+ def test_min_encryption_key_size_equal_to_max_iut_initiator(self):
+ """
+ Verify that the IUT uses correct key size during encryption as initiator.
+ """
+ self._prepare_cert_for_connection()
+
+ self.dut.security.SetLeIoCapability(KEYBOARD_DISPLAY)
+ self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.dut_security.SetLeAuthRequirements(secure_connections=1)
+ self.dut.security.SetLeMaximumEncryptionKeySize(
+ LeMaximumEncryptionKeySizeMessage(maximum_encryption_key_size=0x10))
+
+ self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT)
+ self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1)
+ self.cert.security.SetLeMaximumEncryptionKeySize(
+ LeMaximumEncryptionKeySizeMessage(maximum_encryption_key_size=0x07))
+
+ # 1. IUT transmits a Pairing Request
+ self.dut.security.CreateBondLe(self.cert_address)
+
+ assertThat(self.cert_security.get_ui_stream()).emits(
+ SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address))
+
+ # 2. Lower Tester responds with Pairing Response command with Maximum Encryption Key Size field set to Min_Encryption_Key_Length’.
+ self.cert.security.SendUiCallback(
+ UiCallbackMsg(
+ message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.dut_address))
+
+ # 3. IUT and Lower Tester perform phase 2 of the LE pairing and establish an encrypted link with the key generated in phase 2.
+ assertThat(self.dut_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address))
+
+ @metadata(
+ pts_test_id="SM/SLA/EKS/BV-02-C",
+ pts_test_name="IUT Responder, Lower Tester Maximum Encryption Key Size = Min_Encryption_Key_Length")
+ def test_min_encryption_key_size_equal_to_max_iut_responder(self):
+ """
+ Verify that the IUT uses correct key size during encryption as responder.
+ """
+ self._prepare_dut_for_connection()
+
+ self.dut.security.SetLeIoCapability(KEYBOARD_ONLY)
+ self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.dut_security.SetLeAuthRequirements()
+ self.dut.security.SetLeMaximumEncryptionKeySize(
+ LeMaximumEncryptionKeySizeMessage(maximum_encryption_key_size=0x07))
+
+ self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT)
+ self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.cert_security.SetLeAuthRequirements()
+ self.cert.security.SetLeMaximumEncryptionKeySize(
+ LeMaximumEncryptionKeySizeMessage(maximum_encryption_key_size=0x10))
+
+ # 1. Lower Tester initiates Pairing Request command with Maximum Encryption Key Size field set to Min_Encryption_Key_Length’.
+ self.cert.security.CreateBondLe(self.dut_address)
+
+ assertThat(self.dut_security.get_ui_stream()).emits(
+ SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address))
+
+ # 2. IUT responds with Pairing Response command.
+ self.dut.security.SendUiCallback(
+ UiCallbackMsg(
+ message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.cert_address))
+
+ #3. IUT and Lower Tester perform phase 2 of the LE pairing and establish an encrypted link with the key generated in phase 2.
+ assertThat(self.dut_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address))
+
+ @metadata(
+ pts_test_id="SM/MAS/EKS/BI-01-C",
+ pts_test_name="IUT initiator, Lower Tester Maximum Encryption Key Size < Min_Encryption_Key_Length")
+ def test_min_encryption_key_size_less_than_min_iut_initiator(self):
+ """
+ Verify that the IUT checks that the resultant encryption key size is not smaller than the minimum key size.
+ """
+ self._prepare_cert_for_connection()
+
+ self.dut.security.SetLeIoCapability(KEYBOARD_DISPLAY)
+ self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.dut_security.SetLeAuthRequirements(secure_connections=1)
+ self.dut.security.SetLeMaximumEncryptionKeySize(
+ LeMaximumEncryptionKeySizeMessage(maximum_encryption_key_size=0x10))
+
+ self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT)
+ self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1)
+ self.cert.security.SetLeMaximumEncryptionKeySize(
+ LeMaximumEncryptionKeySizeMessage(maximum_encryption_key_size=0x06))
+
+ # 1. IUT transmits a Pairing Request
+ self.dut.security.CreateBondLe(self.cert_address)
+
+ assertThat(self.cert_security.get_ui_stream()).emits(
+ SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address))
+
+ # 2. Lower Tester responds with Pairing Response command with Maximum Encryption Key Size field set to Min_Encryption_Key_Length-1’.
+ self.cert.security.SendUiCallback(
+ UiCallbackMsg(
+ message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.dut_address))
+
+ # 3. IUT transmits the Pairing Failed command.
+ assertThat(self.dut_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_BOND_FAILED, self.cert_address,
+ int(PairingFailedReason.ENCRYPTION_KEY_SIZE)))
+
+ @metadata(
+ pts_test_id="SM/SLA/EKS/BI-02-C",
+ pts_test_name="IUT Responder, Lower Tester Maximum Encryption Key Size < Min_Encryption_Key_Length")
+ def test_min_encryption_key_size_less_than_min_iut_responder(self):
+ """
+ Verify that the IUT uses correct key size during encryption as responder.
+ """
+ self._prepare_dut_for_connection()
+
+ self.dut.security.SetLeIoCapability(KEYBOARD_ONLY)
+ self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.dut_security.SetLeAuthRequirements()
+ self.dut.security.SetLeMaximumEncryptionKeySize(
+ LeMaximumEncryptionKeySizeMessage(maximum_encryption_key_size=0x06))
+
+ self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT)
+ self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.cert_security.SetLeAuthRequirements()
+ self.cert.security.SetLeMaximumEncryptionKeySize(
+ LeMaximumEncryptionKeySizeMessage(maximum_encryption_key_size=0x10))
+
+ # 1. Lower Tester initiates Pairing Request command with Maximum Encryption Key Size field set to Min_Encryption_Key_Length-1.
+ self.cert.security.CreateBondLe(self.dut_address)
+
+ assertThat(self.dut_security.get_ui_stream()).emits(
+ SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address))
+
+ self.dut.security.SendUiCallback(
+ UiCallbackMsg(
+ message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.cert_address))
+
+ #3. IUT transmits the Pairing Failed command.
+ assertThat(self.cert_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_BOND_FAILED, self.dut_address,
+ int(PairingFailedReason.ENCRYPTION_KEY_SIZE)))
+
+ @metadata(
+ pts_test_id="SM/MAS/SCPK/BV-01-C", pts_test_name="Passkey Entry, IUT Initiator, Secure Connections – Success")
+ def test_passkey_entry_iut_initiator_secure_connections(self):
+ """
+ Verify that the IUT supporting LE Secure Connections performs the Passkey Entry pairing procedure correctly as central, initiator.
+ """
+ self._prepare_cert_for_connection()
+
+ self.dut.security.SetLeIoCapability(DISPLAY_ONLY)
+ self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.dut_security.SetLeAuthRequirements(secure_connections=1)
+
+ self.cert.security.SetLeIoCapability(KEYBOARD_ONLY)
+ self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1)
+
+ # 1. IUT transmits Pairing Request command with:
+ # a. IO capability set to “DisplayOnly” or “KeyboardOnly”
+ # b. OOB data flag set to 0x00 (OOB Authentication data not present)
+ # c. AuthReq bonding flag set to ‘00’, the MITM flag set to ‘0’ and Secure Connections flag set to '1'. Keypress bit is set to '1' if supported
+ self.dut.security.CreateBondLe(self.cert_address)
+
+ assertThat(self.cert_security.get_ui_stream()).emits(
+ SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address))
+
+ # 2. Lower Tester responds with a Pairing Response command, with:
+ # a. IO capability set to “KeyboardOnly”
+ # b. OOB data flag set to 0x00 (OOB Authentication data not present)
+ # c. AuthReq bonding flag set to ‘00’, the MITM flag set to ‘1’, Secure Connections flag set to '1' and all reserved bits are set to ‘0’. Keypress bit is set to '1' if supported by the IUT.
+ self.cert.security.SendUiCallback(
+ UiCallbackMsg(
+ message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.dut_address))
+
+ assertThat(self.cert_security.get_ui_stream()).emits(
+ SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PASSKEY_ENTRY, self.dut_address))
+
+ # 3. During the phase 2 pairing, the IUT displays the 6-digit passkey while the Lower Tester prompts user to enter the 6-digit passkey. If the IUT’s IO capabilities are “KeyboardOnly” the passkey is not displayed and both IUT and Lower Tester enter the same 6-digit passkey. If Keypress bit is set, pairing keypress notifications are sent by the Lower Tester.
+ passkey = self.dut_security.wait_for_ui_event_passkey()
+
+ if passkey == 0:
+ print("Passkey did not arrive into test")
+
+ # 4. IUT and Lower Tester use the same 6-digit passkey.
+ self.cert.security.SendUiCallback(
+ UiCallbackMsg(
+ message_type=UiCallbackType.PASSKEY, numeric_value=passkey, unique_id=1, address=self.dut_address))
+
+ # 5. IUT and Lower Tester perform phase 2 of the Passkey Entry pairing procedure and establish an encrypted link with the LTK generated in phase 2.
+ assertThat(self.dut_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address), timeout=timedelta(seconds=10))
+
+ @metadata(
+ pts_test_id="SM/SLA/SCPK/BV-02-C", pts_test_name="Passkey Entry, IUT Responder, Secure Connections – Success")
+ def test_passkey_entry_iut_responder_secure_connections(self):
+ """
+ Verify that the IUT supporting LE Secure Connections is able to perform the Passkey Entry pairing procedure correctly when acting as peripheral, responder.
+ """
+ self._prepare_dut_for_connection()
+
+ self.dut.security.SetLeIoCapability(DISPLAY_ONLY)
+ self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.dut_security.SetLeAuthRequirements(secure_connections=1)
+
+ self.cert.security.SetLeIoCapability(KEYBOARD_DISPLAY)
+ self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1)
+
+ # 1. Lower Tester transmits Pairing Request command with:
+ # a. IO capability set to “KeyboardDisplay”
+ # b. OOB data flag set to 0x00 (OOB Authentication data not present)
+ # c. AuthReq bonding flag set to the value indicated in the IXIT [7] for ‘Bonding Flags’, and the MITM flag set to ‘1’ Secure Connections flag set to '1' and all reserved bits are set to ‘0’
+ self.cert.security.CreateBondLe(self.dut_address)
+
+ assertThat(self.dut_security.get_ui_stream()).emits(
+ SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address))
+
+ # 2. IUT responds with a Pairing Response command, with:
+ # a. IO capability set to “KeyboardOnly” or “KeyboardDisplay” or “DisplayYesNo” or “DisplayOnly”
+ # b. Secure Connections flag set to '1'. Keypress bit is set to '1' if supported by IUT
+ self.dut.security.SendUiCallback(
+ UiCallbackMsg(
+ message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.cert_address))
+
+ # 3. During the phase 2 passkey pairing process, Lower Tester displays the 6-digit passkey while the IUT prompts user to enter the 6-digit passkey. If the IO capabilities of the IUT are “DisplayYesNo” or “DisplayOnly” the IUT displays the 6-digit passkey while the Lower Tester enters the 6-digit passkey. If Keypress bit is set, pairing keypress notifications are send by the IUT
+ passkey = self.dut_security.wait_for_ui_event_passkey()
+
+ if passkey == 0:
+ print("Passkey did not arrive into test")
+
+ assertThat(self.cert_security.get_ui_stream()).emits(
+ SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PASSKEY_ENTRY, self.dut_address))
+
+ # 4. IUT and Lower Tester use the same pre-defined 6-digit passkey.
+ self.cert.security.SendUiCallback(
+ UiCallbackMsg(
+ message_type=UiCallbackType.PASSKEY, numeric_value=passkey, unique_id=1, address=self.dut_address))
+
+ # 5. IUT and Lower Tester perform phase 2 of the LE pairing and establish an encrypted link with the LTK generated in phase 2.
+ assertThat(self.dut_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address), timeout=timedelta(seconds=10))
+
+ @metadata(
+ pts_test_id="SM/SLA/SCPK/BV-03-C",
+ pts_test_name="Passkey Entry, IUT Responder, Secure Connections – Handle AuthReq Flag RFU Correctly")
+ def test_passkey_entry_iut_responder_secure_connections_auth_req_rfu(self):
+ """
+ Verify that the IUT supporting LE Secure Connections is able to perform the Passkey Entry pairing procedure when receiving additional bits set in the AuthReq flag. Reserved For Future Use bits are correctly handled when acting as peripheral, responder.
+ """
+ self._prepare_dut_for_connection()
+
+ self.dut.security.SetLeIoCapability(KEYBOARD_ONLY)
+ self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.dut_security.SetLeAuthRequirements(secure_connections=1)
+
+ self.cert.security.SetLeIoCapability(DISPLAY_ONLY)
+ self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1, reserved_bits=3)
+
+ # 1. Lower Tester transmits Pairing Request command with:
+ # a. IO Capability set to ”KeyboardOnly”
+ # b. OOB data flag set to 0x00 (OOB Authentication data not present)
+ # c. MITM set to ‘1’ and all reserved bits are set to a random value
+ self.cert.security.CreateBondLe(self.dut_address)
+
+ assertThat(self.dut_security.get_ui_stream()).emits(
+ SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address))
+
+ # 2. IUT responds with a Pairing Response command, with:
+ # a. IO Capability set to “KeyboardOnly” or “DisplayOnly”
+ # b. OOB data flag set to 0x00 (OOB Authentication data not present)
+ # c. All reserved bits are set to ‘0’
+ self.dut.security.SendUiCallback(
+ UiCallbackMsg(
+ message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.cert_address))
+
+ passkey = self.cert_security.wait_for_ui_event_passkey()
+
+ if passkey == 0:
+ print("Passkey did not arrive into test")
+
+ assertThat(self.dut_security.get_ui_stream()).emits(
+ SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PASSKEY_ENTRY, self.cert_address))
+
+ self.dut.security.SendUiCallback(
+ UiCallbackMsg(
+ message_type=UiCallbackType.PASSKEY, numeric_value=passkey, unique_id=1, address=self.cert_address))
+
+ # 3. IUT and Lower Tester perform phase 2 of the Passkey Entry pairing and establish an encrypted link with the generated LTK.
+ assertThat(self.dut_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address), timeout=timedelta(seconds=10))
+
+ @metadata(
+ pts_test_id="SM/MAS/SCPK/BV-04-C",
+ pts_test_name="Passkey Entry, IUT Initiator, Secure Connections – Handle AuthReq Flag RFU Correctly")
+ def test_passkey_entry_iut_initiator_secure_connections_auth_req_rfu(self):
+ """
+ Verify that the IUT supporting LE Secure Connections is able to perform the Passkey Entry pairing procedure when receiving additional bits set in the AuthReq flag. Reserved For Future Use bits are correctly handled when acting as central, initiator.
+ """
+ self._prepare_cert_for_connection()
+
+ self.dut.security.SetLeIoCapability(KEYBOARD_DISPLAY)
+ self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.dut_security.SetLeAuthRequirements(secure_connections=1)
+
+ self.cert.security.SetLeIoCapability(KEYBOARD_ONLY)
+ self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
+ self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1, reserved_bits=3)
+
+ # 1. IUT transmits a Pairing Request command with:
+ # a. IO Capability set to “DisplayOnly” or “DisplayYesNo” or “KeyboardOnly” or “KeyboardDisplay”
+ # b. OOB data flag set to 0x00 (OOB Authentication data not present)
+ # c. All reserved bits are set to ‘0’.
+ self.dut.security.CreateBondLe(self.cert_address)
+
+ assertThat(self.cert_security.get_ui_stream()).emits(
+ SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address))
+
+ # 2. Lower Tester responds with a Pairing Response command, with:
+ # a. IO Capability set to “KeyboardOnly”
+ # b. OOB data flag set to 0x00 (OOB Authentication data not present)
+ # c. AuthReq bonding flag set to the value indicated in the IXIT [7] for ‘Bonding Flags’ and the MITM flag set to ‘1’ and all reserved bits are set to a random value.
+ self.cert.security.SendUiCallback(
+ UiCallbackMsg(
+ message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.dut_address))
+
+ assertThat(self.cert_security.get_ui_stream()).emits(
+ SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PASSKEY_ENTRY, self.dut_address))
+
+ passkey = self.dut_security.wait_for_ui_event_passkey()
+
+ self.cert.security.SendUiCallback(
+ UiCallbackMsg(
+ message_type=UiCallbackType.PASSKEY, numeric_value=passkey, unique_id=1, address=self.dut_address))
+
+ # 3. IUT and Lower Tester perform phase 2 of the Just Works pairing and establish an encrypted link with the generated LTK.
+ assertThat(self.dut_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address), timeout=timedelta(seconds=10))
+
+ @metadata(
+ pts_test_id="SM/MAS/SCOB/BV-01-C", pts_test_name="Out of Band, IUT Initiator, Secure Connections – Success")
+ def test_out_of_band_iut_initiator_secure_connections(self):
+ """
+ Verify that the IUT supporting LE Secure Connections performs the Out-of-Band pairing procedure correctly as central, initiator.
+ """
+
+ oob_combinations = [(OOB_NOT_PRESENT, OOB_PRESENT), (OOB_PRESENT, OOB_NOT_PRESENT), (OOB_PRESENT, OOB_PRESENT)]
+
+ for (dut_oob_flag, cert_oob_flag) in oob_combinations:
+ print("oob flag combination dut: " + str(dut_oob_flag) + ", cert: " + str(cert_oob_flag))
+
+ self._prepare_cert_for_connection()
+
+ if dut_oob_flag == LeOobDataFlag.PRESENT:
+ oobdata = self.cert.security.GetLeOutOfBandData(empty_proto.Empty())
+ self.dut.security.SetOutOfBandData(
+ OobDataMessage(
+ address=self.cert_address,
+ confirmation_value=oobdata.confirmation_value,
+ random_value=oobdata.random_value))
+
+ if cert_oob_flag == LeOobDataFlag.PRESENT:
+ oobdata = self.dut.security.GetLeOutOfBandData(empty_proto.Empty())
+ self.cert.security.SetOutOfBandData(
+ OobDataMessage(
+ address=self.dut_address,
+ confirmation_value=oobdata.confirmation_value,
+ random_value=oobdata.random_value))
+
+ self.dut.security.SetLeIoCapability(KEYBOARD_ONLY)
+ self.dut.security.SetLeOobDataPresent(dut_oob_flag)
+ self.dut_security.SetLeAuthRequirements(bond=1, mitm=1, secure_connections=1)
+
+ self.cert.security.SetLeIoCapability(DISPLAY_ONLY)
+ self.cert.security.SetLeOobDataPresent(cert_oob_flag)
+ self.cert_security.SetLeAuthRequirements(bond=1, mitm=1, secure_connections=1)
+
+ # 1. IUT transmits a Pairing Request command with OOB data flag set to either 0x00 or 0x01, and Secure Connections flag set to '1'.
+ self.dut.security.CreateBondLe(self.cert_address)
+
+ assertThat(self.cert_security.get_ui_stream()).emits(
+ SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address))
+
+ # 2. Lower Tester responds with a Pairing Response command with Secure Connections flag set to '1' and OOB data flag set to either 0x00 or 0x01.
+ self.cert.security.SendUiCallback(
+ UiCallbackMsg(
+ message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.dut_address))
+
+ # 3. IUT uses the 128-bit value generated by the Lower Tester as the confirm value. Similarly, the Lower Tester uses the 128-bit value generated by the IUT as the confirm value.
+
+ # 4. IUT and Lower Tester perform phase 2 of the pairing process and establish an encrypted link with an LTK generated using the OOB data in phase 2.
+ assertThat(self.dut_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address), timeout=timedelta(seconds=10))
+
+ assertThat(self.cert_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.dut_address), timeout=timedelta(seconds=10))
+
+ self.dut.security.RemoveBond(self.cert_address)
+ self.cert.security.RemoveBond(self.dut_address)
+
+ assertThat(self.dut_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_UNBONDED, self.cert_address))
+
+ self.dut_security.wait_device_disconnect(self.cert_address)
+ self.cert_security.wait_device_disconnect(self.dut_address)
+
+ @metadata(
+ pts_test_id="SM/SLA/SCOB/BV-02-C", pts_test_name="Out of Band, IUT Responder, Secure Connections – Success")
+ def test_out_of_band_iut_responder_secure_connections(self):
+ """
+ Verify that the IUT supporting LE Secure Connections is able to perform the Out-of-Band pairing procedure correctly when acting as peripheral, responder.
+ """
+
+ oob_combinations = [(OOB_NOT_PRESENT, OOB_PRESENT), (OOB_PRESENT, OOB_NOT_PRESENT), (OOB_PRESENT, OOB_PRESENT)]
+
+ for (dut_oob_flag, cert_oob_flag) in oob_combinations:
+ print("oob flag combination dut: " + str(dut_oob_flag) + ", cert: " + str(cert_oob_flag))
+
+ self._prepare_dut_for_connection()
+
+ if dut_oob_flag == LeOobDataFlag.PRESENT:
+ oobdata = self.cert.security.GetLeOutOfBandData(empty_proto.Empty())
+ self.dut.security.SetOutOfBandData(
+ OobDataMessage(
+ address=self.cert_address,
+ confirmation_value=oobdata.confirmation_value,
+ random_value=oobdata.random_value))
+
+ if cert_oob_flag == LeOobDataFlag.PRESENT:
+ oobdata = self.dut.security.GetLeOutOfBandData(empty_proto.Empty())
+ self.cert.security.SetOutOfBandData(
+ OobDataMessage(
+ address=self.dut_address,
+ confirmation_value=oobdata.confirmation_value,
+ random_value=oobdata.random_value))
+
+ self.dut.security.SetLeIoCapability(KEYBOARD_ONLY)
+ self.dut.security.SetLeOobDataPresent(dut_oob_flag)
+ self.dut_security.SetLeAuthRequirements(bond=1, mitm=1, secure_connections=1)
+
+ self.cert.security.SetLeIoCapability(DISPLAY_ONLY)
+ self.cert.security.SetLeOobDataPresent(cert_oob_flag)
+ self.cert_security.SetLeAuthRequirements(bond=1, mitm=1, secure_connections=1)
+
+ # 1. Lower Tester transmits a Pairing Request command with OOB data flag set to either 0x00 or 0x01, and Secure Connections flag set to '1'.
+ self.cert.security.CreateBondLe(self.dut_address)
+
+ assertThat(self.dut_security.get_ui_stream()).emits(
+ SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address))
+
+ # 2. IUT responds with a Pairing Response command with Secure Connections flag set to '1' and OOB data flag set to either 0x00 or 0x01.
+ self.dut.security.SendUiCallback(
+ UiCallbackMsg(
+ message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.cert_address))
+
+ # 3. IUT uses the 128-bit value generated by the Lower Tester as the confirm value. Similarly, the Lower Tester uses the 128-bit value generated by the IUT as the confirm value.
+
+ # 4. IUT and Lower Tester perform phase 2 of the pairing process and establish an encrypted link with an LTK generated using the OOB data in phase 2.
+ assertThat(self.cert_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.dut_address), timeout=timedelta(seconds=10))
+
+ assertThat(self.dut_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address), timeout=timedelta(seconds=10))
+
+ self.cert.security.RemoveBond(self.dut_address)
+ self.dut.security.RemoveBond(self.cert_address)
+
+ assertThat(self.dut_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_UNBONDED, self.cert_address))
+
+ self.cert_security.wait_device_disconnect(self.dut_address)
+ self.dut_security.wait_device_disconnect(self.cert_address)
+
+ @metadata(
+ pts_test_id="SM/SLA/SCOB/BV-03-C",
+ pts_test_name="Out of Band, IUT Responder, Secure Connections – Handle AuthReq Flag RFU Correctly")
+ def test_out_of_band_iut_responder_secure_connections_auth_req_rfu(self):
+ """
+ Verify that the IUT supporting LE Secure Connections is able to perform the Out-of-Band pairing procedure when receiving additional bits set in the AuthReq flag. Reserved For Future Use bits are correctly handled when acting as peripheral, responder.
+ """
+
+ reserved_bits_combinations = [1, 2, 3]
+
+ for reserved_bits in reserved_bits_combinations:
+ print("reserved bits in cert dut: " + str(reserved_bits))
+
+ self._prepare_dut_for_connection()
+
+ oobdata = self.cert.security.GetLeOutOfBandData(empty_proto.Empty())
+ self.dut.security.SetOutOfBandData(
+ OobDataMessage(
+ address=self.cert_address,
+ confirmation_value=oobdata.confirmation_value,
+ random_value=oobdata.random_value))
+
+ oobdata = self.dut.security.GetLeOutOfBandData(empty_proto.Empty())
+ self.cert.security.SetOutOfBandData(
+ OobDataMessage(
+ address=self.dut_address,
+ confirmation_value=oobdata.confirmation_value,
+ random_value=oobdata.random_value))
+
+ self.dut.security.SetLeIoCapability(KEYBOARD_ONLY)
+ self.dut.security.SetLeOobDataPresent(OOB_PRESENT)
+ self.dut_security.SetLeAuthRequirements(bond=1, mitm=0, secure_connections=1)
+
+ self.cert.security.SetLeIoCapability(DISPLAY_ONLY)
+ self.cert.security.SetLeOobDataPresent(OOB_PRESENT)
+ self.cert_security.SetLeAuthRequirements(bond=1, mitm=1, secure_connections=1, reserved_bits=reserved_bits)
+
+ # 1. Lower Tester transmits Pairing Request command with:
+ # a. IO Capability set to any IO capability
+ # b. OOB data flag set to 0x01 (OOB Authentication data from remote device present)
+ # c. MITM set to ‘0’, Secure Connections flag is set to '1', and all reserved bits are set to a random value.
+ self.cert.security.CreateBondLe(self.dut_address)
+
+ assertThat(self.dut_security.get_ui_stream()).emits(
+ SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address))
+
+ # 2. IUT responds with a Pairing Response command, with:
+ # a. IO Capability set to any IO capability
+ # b. OOB data flag set to 0x01 (OOB Authentication data present)
+ # c. Secure Connections flag is set to '1', All reserved bits are set to ‘0’
+ self.dut.security.SendUiCallback(
+ UiCallbackMsg(
+ message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.cert_address))
+
+ # 3. IUT and Lower Tester perform phase 2 of the OOB authenticated pairing and establish an encrypted link with the generated LTK.
+
+ assertThat(self.cert_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.dut_address), timeout=timedelta(seconds=10))
+
+ assertThat(self.dut_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address), timeout=timedelta(seconds=10))
+
+ self.cert.security.RemoveBond(self.dut_address)
+ self.dut.security.RemoveBond(self.cert_address)
+
+ assertThat(self.dut_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_UNBONDED, self.cert_address))
+
+ self.dut_security.wait_device_disconnect(self.cert_address)
+ self.cert_security.wait_device_disconnect(self.dut_address)
+
+ @metadata(
+ pts_test_id="SM/MAS/SCOB/BV-04-C",
+ pts_test_name="Out of Band, IUT Initiator, Secure Connections – Handle AuthReq Flag RFU Correctly")
+ def test_out_of_band_iut_initiator_secure_connections_auth_req_rfu(self):
+ """
+ Verify that the IUT supporting LE Secure Connections is able to perform the Out-of-Band pairing procedure when receiving additional bits set in the AuthReq flag. Reserved For Future Use bits are correctly handled when acting as central, initiator.
+ """
+
+ reserved_bits_combinations = [1, 2, 3]
+
+ for reserved_bits in reserved_bits_combinations:
+ print("reserved bits in cert dut: " + str(reserved_bits))
+
+ self._prepare_cert_for_connection()
+
+ oobdata = self.cert.security.GetLeOutOfBandData(empty_proto.Empty())
+ self.dut.security.SetOutOfBandData(
+ OobDataMessage(
+ address=self.cert_address,
+ confirmation_value=oobdata.confirmation_value,
+ random_value=oobdata.random_value))
+
+ oobdata = self.dut.security.GetLeOutOfBandData(empty_proto.Empty())
+ self.cert.security.SetOutOfBandData(
+ OobDataMessage(
+ address=self.dut_address,
+ confirmation_value=oobdata.confirmation_value,
+ random_value=oobdata.random_value))
+
+ self.dut.security.SetLeIoCapability(KEYBOARD_ONLY)
+ self.dut.security.SetLeOobDataPresent(OOB_PRESENT)
+ self.dut_security.SetLeAuthRequirements(bond=1, mitm=0, secure_connections=1, reserved_bits=0)
+
+ self.cert.security.SetLeIoCapability(DISPLAY_ONLY)
+ self.cert.security.SetLeOobDataPresent(OOB_PRESENT)
+ self.cert_security.SetLeAuthRequirements(bond=1, mitm=1, secure_connections=1, reserved_bits=reserved_bits)
+
+ # 1. IUT transmits Pairing Request command with:
+ # a. IO Capability set to any IO capability
+ # b. OOB data flag set to 0x01 (OOB Authentication data present)
+ # c. MITM set to ‘0’, Secure Connections flag is set to '1', and all reserved bits are set to ‘0’
+ self.dut.security.CreateBondLe(self.cert_address)
+
+ assertThat(self.cert_security.get_ui_stream()).emits(
+ SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address))
+
+ # 2. Lower Tester responds with a Pairing Response command, with:
+ # a. IO Capability set to any IO capability
+ # b. OOB data flag set to 0x01 (OOB Authentication data present)
+ # c. Secure Connections flag is set to '1', and all reserved bits are set to a random value.
+ self.cert.security.SendUiCallback(
+ UiCallbackMsg(
+ message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.dut_address))
+
+ # 3. IUT and Lower Tester perform phase 2 of the OOB authenticated pairing and establish an encrypted link with the generated LTK.
+
+ assertThat(self.dut_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address), timeout=timedelta(seconds=10))
+
+ assertThat(self.cert_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.dut_address), timeout=timedelta(seconds=10))
+
+ self.dut.security.RemoveBond(self.cert_address)
+ self.cert.security.RemoveBond(self.dut_address)
+
+ assertThat(self.dut_security.get_bond_stream()).emits(
+ SecurityMatchers.BondMsg(BondMsgType.DEVICE_UNBONDED, self.cert_address))
+
+ self.dut_security.wait_device_disconnect(self.cert_address)
+ self.cert_security.wait_device_disconnect(self.dut_address)
diff --git a/gd/security/cert/security_test.py b/gd/security/cert/security_test.py
index 28e04c9..93337ba 100644
--- a/gd/security/cert/security_test.py
+++ b/gd/security/cert/security_test.py
@@ -13,535 +13,19 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import logging
-import time
-
-from bluetooth_packets_python3 import hci_packets
-from cert.event_stream import EventStream
from cert.gd_base_test import GdBaseTestClass
-from cert.py_security import PySecurity
-from cert.truth import assertThat
-from facade import common_pb2 as common
-from google.protobuf import empty_pb2 as empty_proto
-from hci.facade import controller_facade_pb2 as controller_facade
-from hci.facade import le_initiator_address_facade_pb2 as le_initiator_address_facade
-from l2cap.classic.facade_pb2 import ClassicSecurityPolicy
-from neighbor.facade import facade_pb2 as neighbor_facade
-from security.cert.cert_security import CertSecurity
-from security.facade_pb2 import AuthenticationRequirements
-from security.facade_pb2 import BondMsgType
-from security.facade_pb2 import IoCapabilities
-from security.facade_pb2 import OobDataPresent
-from security.facade_pb2 import UiMsgType
+from security.cert.security_test_lib import SecurityTestBase
-class SecurityTest(GdBaseTestClass):
- """
- Collection of tests that each sample results from
- different (unique) combinations of io capabilities, authentication requirements, and oob data.
- """
-
- _io_capabilities_name_lookup = {
- IoCapabilities.DISPLAY_ONLY: "DISPLAY_ONLY",
- IoCapabilities.DISPLAY_YES_NO_IO_CAP: "DISPLAY_YES_NO_IO_CAP",
- #IoCapabilities.KEYBOARD_ONLY:"KEYBOARD_ONLY",
- IoCapabilities.NO_INPUT_NO_OUTPUT: "NO_INPUT_NO_OUTPUT",
- }
-
- _auth_reqs_name_lookup = {
- AuthenticationRequirements.NO_BONDING: "NO_BONDING",
- AuthenticationRequirements.NO_BONDING_MITM_PROTECTION: "NO_BONDING_MITM_PROTECTION",
- AuthenticationRequirements.DEDICATED_BONDING: "DEDICATED_BONDING",
- AuthenticationRequirements.DEDICATED_BONDING_MITM_PROTECTION: "DEDICATED_BONDING_MITM_PROTECTION",
- AuthenticationRequirements.GENERAL_BONDING: "GENERAL_BONDING",
- AuthenticationRequirements.GENERAL_BONDING_MITM_PROTECTION: "GENERAL_BONDING_MITM_PROTECTION",
- }
-
- # Possible IO Capabilities
- io_capabilities = (
- IoCapabilities.DISPLAY_ONLY,
- IoCapabilities.DISPLAY_YES_NO_IO_CAP,
- # TODO(optedoblivion): Uncomment when Passkey Entry is implemented in ClassicPairingHandler
- #IoCapabilities.KEYBOARD_ONLY,
- IoCapabilities.NO_INPUT_NO_OUTPUT)
-
- # Possible Authentication Requirements
- auth_reqs = (AuthenticationRequirements.NO_BONDING, AuthenticationRequirements.NO_BONDING_MITM_PROTECTION,
- AuthenticationRequirements.DEDICATED_BONDING,
- AuthenticationRequirements.DEDICATED_BONDING_MITM_PROTECTION,
- AuthenticationRequirements.GENERAL_BONDING, AuthenticationRequirements.GENERAL_BONDING_MITM_PROTECTION)
-
- # Possible Out-of-Band data options
- oob_present = (
- OobDataPresent.NOT_PRESENT,
- # TODO(optedoblivion): Uncomment when OOB is implemented in root canal
- #"P192_PRESENT",
- #"P256_PRESENT",
- #"P192_AND_256_PRESENT"
- )
-
- mitm_auth_reqs = (AuthenticationRequirements.DEDICATED_BONDING_MITM_PROTECTION,
- AuthenticationRequirements.GENERAL_BONDING_MITM_PROTECTION,
- AuthenticationRequirements.NO_BONDING_MITM_PROTECTION)
+class SecurityTest(GdBaseTestClass, SecurityTestBase):
def setup_class(self):
- super().setup_class(dut_module='SECURITY', cert_module='L2CAP')
+ GdBaseTestClass.setup_class(self, dut_module='SECURITY', cert_module='L2CAP')
def setup_test(self):
- super().setup_test()
-
- self.dut.neighbor.EnablePageScan(neighbor_facade.EnableMsg(enabled=True))
- self.cert.neighbor.EnablePageScan(neighbor_facade.EnableMsg(enabled=True))
-
- self.dut.name = b'DUT Device'
- self.dut.address = self.dut.hci_controller.GetMacAddress(empty_proto.Empty()).address
- self.cert.name = b'Cert Device'
- self.cert.address = self.cert.hci_controller.GetMacAddress(empty_proto.Empty()).address
-
- # TODO(optedoblivion): Make this happen in PySecurity or GdDevice
- self.dut.hci_controller.WriteLocalName(controller_facade.NameMsg(name=self.dut.name))
- self.cert.hci_controller.WriteLocalName(controller_facade.NameMsg(name=self.cert.name))
-
- self.dut_security = PySecurity(self.dut)
- self.cert_security = CertSecurity(self.cert)
-
- self.dut_address = common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=bytes(b'DD:05:04:03:02:01')), type=common.RANDOM_DEVICE_ADDRESS)
- privacy_policy = le_initiator_address_facade.PrivacyPolicy(
- address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
- address_with_type=self.dut_address)
- self.dut.security.SetLeInitiatorAddressPolicy(privacy_policy)
+ GdBaseTestClass.setup_test(self)
+ SecurityTestBase.setup_test(self, self.dut, self.cert)
def teardown_test(self):
- self.dut_security.close()
- self.cert_security.close()
- super().teardown_test()
-
- # Initiates the numeric comparison test
- def _run_ssp_numeric_comparison(self, initiator, responder, init_ui_response, resp_ui_response,
- expected_init_ui_event, expected_resp_ui_event, expected_init_bond_event,
- expected_resp_bond_event):
- initiator.enable_secure_simple_pairing()
- responder.enable_secure_simple_pairing()
- initiator.create_bond(responder.get_address(), common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
- self._verify_ssp_numeric_comparison(initiator, responder, init_ui_response, resp_ui_response,
- expected_init_ui_event, expected_resp_ui_event, expected_init_bond_event,
- expected_resp_bond_event)
-
- # Verifies the events for the numeric comparion test
- def _verify_ssp_numeric_comparison(self, initiator, responder, init_ui_response, resp_ui_response,
- expected_init_ui_event, expected_resp_ui_event, expected_init_bond_event,
- expected_resp_bond_event):
- responder.accept_pairing(initiator.get_address(), resp_ui_response)
- initiator.on_user_input(responder.get_address(), init_ui_response, expected_init_ui_event)
- initiator.wait_for_bond_event(expected_init_bond_event)
- responder.wait_for_bond_event(expected_resp_bond_event)
-
- def _run_ssp_oob(self, initiator, responder, init_ui_response, resp_ui_response, expected_init_ui_event,
- expected_resp_ui_event, expected_init_bond_event, expected_resp_bond_event, p192_oob_data,
- p256_oob_data):
- initiator.enable_secure_simple_pairing()
- responder.enable_secure_simple_pairing()
- initiator.create_bond_out_of_band(responder.get_address(),
- common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS, p192_oob_data,
- p256_oob_data)
- self._verify_ssp_oob(initiator, responder, init_ui_response, resp_ui_response, expected_init_ui_event,
- expected_resp_ui_event, expected_init_bond_event, expected_resp_bond_event, p192_oob_data,
- p256_oob_data)
-
- # Verifies the events for the numeric comparion test
- def _verify_ssp_oob(self, initiator, responder, init_ui_response, resp_ui_response, expected_init_ui_event,
- expected_resp_ui_event, expected_init_bond_event, expected_resp_bond_event, p192_oob_data,
- p256_oob_data):
- responder.accept_oob_pairing(initiator.get_address())
- initiator.on_user_input(responder.get_address(), init_ui_response, expected_init_ui_event)
- initiator.wait_for_bond_event(expected_init_bond_event)
- responder.wait_for_bond_event(expected_resp_bond_event)
-
- def _run_ssp_passkey(self, initiator, responder, expected_init_bond_event, expected_resp_bond_event):
- initiator.enable_secure_simple_pairing()
- responder.enable_secure_simple_pairing()
- initiator.create_bond(responder.get_address(), common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
- self._verify_ssp_passkey(initiator, responder, expected_init_bond_event, expected_resp_bond_event)
-
- def _verify_ssp_passkey(self, initiator, responder, expected_init_bond_event, expected_resp_bond_event):
- responder.send_io_caps(initiator.get_address())
- passkey = initiator.wait_for_passkey(responder.get_address())
- responder.input_passkey(initiator.get_address(), passkey)
- initiator.wait_for_bond_event(expected_init_bond_event)
- responder.wait_for_bond_event(expected_resp_bond_event)
-
- def _run_pin(self, initiator, responder, expected_init_bond_event, expected_resp_bond_event):
- initiator.create_bond(responder.get_address(), common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
- self._verify_pin(initiator, responder, expected_init_bond_event, expected_resp_bond_event)
-
- def _verify_pin(self, initiator, responder, expected_init_bond_event, expected_resp_bond_event):
- pin = b'123456789A'
- logging.info("pin: %s" % pin)
- initiator.input_pin(responder.get_address(), pin)
- responder.input_pin(initiator.get_address(), pin)
- initiator.wait_for_bond_event(expected_init_bond_event)
- responder.wait_for_bond_event(expected_resp_bond_event)
-
- def test_setup_teardown(self):
- """
- Make sure our setup and teardown is sane
- """
- pass
-
- # no_input_no_output + no_input_no_output is JustWorks no confirmation
- def test_dut_initiated_no_input_no_output_no_input_no_output_twice_bond_and_enforce(self):
- # Arrange
- self.dut_security.set_io_capabilities(IoCapabilities.NO_INPUT_NO_OUTPUT)
- self.dut_security.set_authentication_requirements(AuthenticationRequirements.DEDICATED_BONDING)
- self.cert_security.set_io_capabilities(IoCapabilities.NO_INPUT_NO_OUTPUT)
- self.cert_security.set_authentication_requirements(AuthenticationRequirements.DEDICATED_BONDING)
-
- # Act and Assert
- self._run_ssp_numeric_comparison(
- initiator=self.dut_security,
- responder=self.cert_security,
- init_ui_response=True,
- resp_ui_response=True,
- expected_init_ui_event=None,
- expected_resp_ui_event=None,
- expected_init_bond_event=BondMsgType.DEVICE_BONDED,
- expected_resp_bond_event=None)
-
- self.dut_security.enforce_security_policy(self.cert.address,
- common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS,
- ClassicSecurityPolicy.ENCRYPTED_TRANSPORT)
-
- # TODO: We verify enforcement when we make sure EncryptionChange is received on DUT
-
- # no_input_no_output + no_input_no_output is JustWorks no confirmation
- def test_dut_initiated_no_input_no_output_no_input_no_output_twice_with_remove_bond(self):
- # Arrange
- self.dut_security.set_io_capabilities(IoCapabilities.NO_INPUT_NO_OUTPUT)
- self.dut_security.set_authentication_requirements(AuthenticationRequirements.DEDICATED_BONDING)
- self.cert_security.set_io_capabilities(IoCapabilities.NO_INPUT_NO_OUTPUT)
- self.cert_security.set_authentication_requirements(AuthenticationRequirements.DEDICATED_BONDING)
-
- # Act and Assert
- self._run_ssp_numeric_comparison(
- initiator=self.dut_security,
- responder=self.cert_security,
- init_ui_response=True,
- resp_ui_response=True,
- expected_init_ui_event=None,
- expected_resp_ui_event=None,
- expected_init_bond_event=BondMsgType.DEVICE_BONDED,
- expected_resp_bond_event=None)
-
- self.dut_security.remove_bond(self.cert.address, common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
- self.cert_security.remove_bond(self.cert.address, common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
- self.dut_security.wait_for_bond_event(BondMsgType.DEVICE_UNBONDED)
- self.cert_security.wait_for_bond_event(BondMsgType.DEVICE_UNBONDED)
-
- self.dut_security.wait_for_disconnect_event()
- self.cert_security.wait_for_disconnect_event()
-
- # Act and Assert
- self._run_ssp_numeric_comparison(
- initiator=self.dut_security,
- responder=self.cert_security,
- init_ui_response=True,
- resp_ui_response=True,
- expected_init_ui_event=None,
- expected_resp_ui_event=None,
- expected_init_bond_event=BondMsgType.DEVICE_BONDED,
- expected_resp_bond_event=None)
-
- self.dut_security.remove_bond(self.cert.address, common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
- self.cert_security.remove_bond(self.cert.address, common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
- self.dut_security.wait_for_bond_event(BondMsgType.DEVICE_UNBONDED)
- self.cert_security.wait_for_bond_event(BondMsgType.DEVICE_UNBONDED)
-
- self.dut_security.wait_for_disconnect_event()
- self.cert_security.wait_for_disconnect_event()
-
- def test_successful_dut_initiated_ssp_numeric_comparison(self):
- test_count = len(self.io_capabilities) * len(self.auth_reqs) * len(self.oob_present) * len(
- self.io_capabilities) * len(self.auth_reqs) * len(self.oob_present)
- logging.info("Loading %d test combinations" % test_count)
- i = 0
- for dut_io_capability in self.io_capabilities:
- for dut_auth_reqs in self.auth_reqs:
- for dut_oob_present in self.oob_present:
- for cert_io_capability in self.io_capabilities:
- for cert_auth_reqs in self.auth_reqs:
- for cert_oob_present in self.oob_present:
- i = i + 1
- logging.info("")
- logging.info("===================================================")
- logging.info("Running test %d of %d" % (i, test_count))
- logging.info("DUT Test Config: %s ; %s ; %s " % (self._io_capabilities_name_lookup.get(
- dut_io_capability, "ERROR"), self._auth_reqs_name_lookup.get(
- dut_auth_reqs, "ERROR"), dut_oob_present))
- logging.info(
- "CERT Test Config: %s ; %s ; %s " %
- (self._io_capabilities_name_lookup.get(cert_io_capability, "ERROR"),
- self._auth_reqs_name_lookup.get(cert_auth_reqs, "ERROR"), cert_oob_present))
- logging.info("===================================================")
- logging.info("")
- self.dut_security.set_io_capabilities(dut_io_capability)
- self.dut_security.set_authentication_requirements(dut_auth_reqs)
- self.cert_security.set_io_capabilities(cert_io_capability)
- self.cert_security.set_authentication_requirements(cert_auth_reqs)
- init_ui_response = True
- resp_ui_response = True
- expected_init_ui_event = None # None is auto accept
- expected_resp_ui_event = None # None is auto accept
- expected_init_bond_event = BondMsgType.DEVICE_BONDED
- expected_resp_bond_event = None
- if dut_io_capability == IoCapabilities.DISPLAY_ONLY:
- if cert_io_capability == IoCapabilities.DISPLAY_YES_NO_IO_CAP:
- expected_resp_ui_event = UiMsgType.DISPLAY_YES_NO_WITH_VALUE
- if dut_auth_reqs in self.mitm_auth_reqs or cert_auth_reqs in self.mitm_auth_reqs:
- expected_init_bond_event = BondMsgType.DEVICE_BOND_FAILED
- elif cert_io_capability == IoCapabilities.KEYBOARD_ONLY:
- expected_resp_ui_event = UiMsgType.DISPLAY_PASSKEY_ENTRY
- elif cert_io_capability == IoCapabilities.DISPLAY_ONLY:
- if dut_auth_reqs in self.mitm_auth_reqs or cert_auth_reqs in self.mitm_auth_reqs:
- expected_init_bond_event = BondMsgType.DEVICE_BOND_FAILED
- elif cert_io_capability == IoCapabilities.NO_INPUT_NO_OUTPUT:
- if dut_auth_reqs in self.mitm_auth_reqs or cert_auth_reqs in self.mitm_auth_reqs:
- expected_init_bond_event = BondMsgType.DEVICE_BOND_FAILED
- elif dut_io_capability == IoCapabilities.DISPLAY_YES_NO_IO_CAP:
- expected_init_ui_event = UiMsgType.DISPLAY_YES_NO_WITH_VALUE
- if cert_io_capability == IoCapabilities.DISPLAY_YES_NO_IO_CAP:
- expected_resp_ui_event = UiMsgType.DISPLAY_YES_NO_WITH_VALUE
- elif cert_io_capability == IoCapabilities.KEYBOARD_ONLY:
- expected_init_ui_event = UiMsgType.DISPLAY_PASSKEY
- expected_resp_ui_event = UiMsgType.DISPLAY_PASSKEY_ENTRY
- elif cert_io_capability == IoCapabilities.NO_INPUT_NO_OUTPUT:
- expected_init_ui_event = UiMsgType.DISPLAY_YES_NO # No value
- elif dut_io_capability == IoCapabilities.KEYBOARD_ONLY:
- expected_init_ui_event = UiMsgType.DISPLAY_PASSKEY_ENTRY
- if cert_io_capability == IoCapabilities.DISPLAY_ONLY:
- expected_resp_ui_event = UiMsgType.DISPLAY_PASSKEY
- elif cert_io_capability == IoCapabilities.DISPLAY_YES_NO_IO_CAP:
- expected_resp_ui_event = UiMsgType.DISPLAY_PASSKEY_ENTRY
- elif cert_io_capability == IoCapabilities.KEYBOARD_ONLY:
- expected_resp_ui_event = UiMsgType.DISPLAY_PASSKEY_ENTRY
- elif cert_io_capability == IoCapabilities.NO_INPUT_NO_OUTPUT:
- if dut_auth_reqs in self.mitm_auth_reqs or cert_auth_reqs in self.mitm_auth_reqs:
- expected_init_bond_event = BondMsgType.DEVICE_BOND_FAILED
- elif dut_io_capability == IoCapabilities.NO_INPUT_NO_OUTPUT:
- if cert_io_capability == IoCapabilities.DISPLAY_YES_NO_IO_CAP:
- expected_resp_ui_event = UiMsgType.DISPLAY_YES_NO # No value
-
- if dut_auth_reqs in self.mitm_auth_reqs or cert_auth_reqs in self.mitm_auth_reqs:
- expected_init_bond_event = BondMsgType.DEVICE_BOND_FAILED
-
- if cert_oob_present == OobDataPresent.NOT_PRESENT:
- self._run_ssp_numeric_comparison(
- initiator=self.dut_security,
- responder=self.cert_security,
- init_ui_response=init_ui_response,
- resp_ui_response=resp_ui_response,
- expected_init_ui_event=expected_init_ui_event,
- expected_resp_ui_event=expected_resp_ui_event,
- expected_init_bond_event=expected_init_bond_event,
- expected_resp_bond_event=expected_resp_bond_event)
- else:
- logging.error("Code path not yet implemented")
- assertThat(False).isTrue()
-
- self.dut_security.remove_bond(self.cert_security.get_address(),
- common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
- self.cert_security.remove_bond(self.dut_security.get_address(),
- common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
-
- self.dut_security.wait_for_bond_event(BondMsgType.DEVICE_UNBONDED)
- self.cert_security.wait_for_bond_event(BondMsgType.DEVICE_UNBONDED)
-
- self.dut_security.wait_for_disconnect_event()
- self.cert_security.wait_for_disconnect_event()
-
- def test_enable_secure_simple_pairing(self):
- self.dut_security.enable_secure_simple_pairing()
- self.cert_security.enable_secure_simple_pairing()
-
- def test_enable_secure_connections(self):
- self.dut_security.enable_secure_simple_pairing()
- self.cert_security.enable_secure_simple_pairing()
- self.dut_security.enable_secure_connections()
- self.cert_security.enable_secure_connections()
-
- def test_get_oob_data_from_dut_controller_p192_present(self):
- oob_data = self.dut_security.get_oob_data_from_controller(OobDataPresent.P192_PRESENT)
- assertThat(len(oob_data)).isEqualTo(4)
- has192C = not all([i == 0 for i in oob_data[0]])
- has192R = not all([i == 0 for i in oob_data[1]])
- has256C = not all([i == 0 for i in oob_data[2]])
- has256R = not all([i == 0 for i in oob_data[3]])
- assertThat(has192C).isTrue()
- assertThat(has192R).isTrue()
- assertThat(has256C).isFalse()
- assertThat(has256R).isFalse()
-
- def test_get_oob_data_from_cert_controller_not_present(self):
- oob_data = self.cert_security.get_oob_data_from_controller(OobDataPresent.NOT_PRESENT)
- assertThat(len(oob_data)).isEqualTo(4)
- has192C = not all([i == 0 for i in oob_data[0]])
- has192R = not all([i == 0 for i in oob_data[1]])
- has256C = not all([i == 0 for i in oob_data[2]])
- has256R = not all([i == 0 for i in oob_data[3]])
- assertThat(has192C).isFalse()
- assertThat(has192R).isFalse()
- assertThat(has256C).isFalse()
- assertThat(has256R).isFalse()
-
- def test_get_oob_data_from_cert_controller_p192_present_no_secure_connections(self):
- oob_data = self.cert_security.get_oob_data_from_controller(OobDataPresent.P192_PRESENT)
- assertThat(len(oob_data)).isEqualTo(4)
- has192C = not all([i == 0 for i in oob_data[0]])
- has192R = not all([i == 0 for i in oob_data[1]])
- has256C = not all([i == 0 for i in oob_data[2]])
- has256R = not all([i == 0 for i in oob_data[3]])
- assertThat(has192C).isTrue()
- assertThat(has192R).isTrue()
- assertThat(has256C).isFalse()
- assertThat(has256R).isFalse()
-
- def test_get_oob_data_from_cert_controller_p192_present(self):
- self.cert_security.enable_secure_simple_pairing()
- self.cert_security.enable_secure_connections()
- oob_data = self.cert_security.get_oob_data_from_controller(OobDataPresent.P192_PRESENT)
- assertThat(len(oob_data)).isEqualTo(4)
- has192C = not all([i == 0 for i in oob_data[0]])
- has192R = not all([i == 0 for i in oob_data[1]])
- has256C = not all([i == 0 for i in oob_data[2]])
- has256R = not all([i == 0 for i in oob_data[3]])
- assertThat(has192C).isTrue()
- assertThat(has192R).isTrue()
- assertThat(has256C).isFalse()
- assertThat(has256R).isFalse()
-
- def test_get_oob_data_from_cert_controller_p256_present(self):
- self.cert_security.enable_secure_simple_pairing()
- self.cert_security.enable_secure_connections()
- oob_data = self.cert_security.get_oob_data_from_controller(OobDataPresent.P256_PRESENT)
- assertThat(len(oob_data)).isEqualTo(4)
- has192C = not all([i == 0 for i in oob_data[0]])
- has192R = not all([i == 0 for i in oob_data[1]])
- has256C = not all([i == 0 for i in oob_data[2]])
- has256R = not all([i == 0 for i in oob_data[3]])
- assertThat(has192C).isFalse()
- assertThat(has192R).isFalse()
- assertThat(has256C).isTrue()
- assertThat(has256R).isTrue()
-
- def test_get_oob_data_from_cert_controller_p192_and_p256_present(self):
- self.cert_security.enable_secure_simple_pairing()
- self.cert_security.enable_secure_connections()
- oob_data = self.cert_security.get_oob_data_from_controller(OobDataPresent.P192_AND_256_PRESENT)
- assertThat(len(oob_data)).isEqualTo(4)
- has192C = not all([i == 0 for i in oob_data[0]])
- has192R = not all([i == 0 for i in oob_data[1]])
- has256C = not all([i == 0 for i in oob_data[2]])
- has256R = not all([i == 0 for i in oob_data[3]])
- assertThat(has192C).isTrue()
- assertThat(has192R).isTrue()
- assertThat(has256C).isTrue()
- assertThat(has256R).isTrue()
-
- def test_successful_dut_initiated_ssp_oob(self):
- dut_io_capability = IoCapabilities.NO_INPUT_NO_OUTPUT
- cert_io_capability = IoCapabilities.NO_INPUT_NO_OUTPUT
- dut_auth_reqs = AuthenticationRequirements.DEDICATED_BONDING_MITM_PROTECTION
- cert_auth_reqs = AuthenticationRequirements.DEDICATED_BONDING_MITM_PROTECTION
- cert_oob_present = OobDataPresent.P192_PRESENT
- self.dut_security.enable_secure_simple_pairing()
- self.dut_security.enable_secure_connections()
- self.cert_security.enable_secure_simple_pairing()
- self.cert_security.enable_secure_connections()
- self.dut_security.set_io_capabilities(dut_io_capability)
- self.dut_security.set_authentication_requirements(dut_auth_reqs)
- self.cert_security.set_io_capabilities(cert_io_capability)
- self.cert_security.set_authentication_requirements(cert_auth_reqs)
- init_ui_response = True
- resp_ui_response = True
- expected_init_ui_event = None # None is auto accept
- expected_resp_ui_event = None # None is auto accept
- expected_init_bond_event = BondMsgType.DEVICE_BONDED
- expected_resp_bond_event = None
- # get_oob_data returns a tuple of bytes (p192c,p192r,p256c,p256r)
- local_oob_data = self.cert_security.get_oob_data_from_controller(cert_oob_present)
- p192_oob_data = local_oob_data[0:2]
- p256_oob_data = local_oob_data[2:4]
- self._run_ssp_oob(
- initiator=self.dut_security,
- responder=self.cert_security,
- init_ui_response=init_ui_response,
- resp_ui_response=resp_ui_response,
- expected_init_ui_event=expected_init_ui_event,
- expected_resp_ui_event=expected_resp_ui_event,
- expected_init_bond_event=expected_init_bond_event,
- expected_resp_bond_event=expected_resp_bond_event,
- p192_oob_data=p192_oob_data,
- p256_oob_data=p256_oob_data)
- self.dut_security.remove_bond(self.cert_security.get_address(),
- common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
- self.cert_security.remove_bond(self.dut_security.get_address(),
- common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
- self.dut_security.wait_for_bond_event(BondMsgType.DEVICE_UNBONDED)
- self.cert_security.wait_for_bond_event(BondMsgType.DEVICE_UNBONDED)
- self.dut_security.wait_for_disconnect_event()
- self.cert_security.wait_for_disconnect_event()
-
- def test_successful_dut_initiated_ssp_keyboard(self):
- dut_io_capability = IoCapabilities.DISPLAY_YES_NO_IO_CAP
- dut_auth_reqs = AuthenticationRequirements.DEDICATED_BONDING_MITM_PROTECTION
- dut_oob_present = OobDataPresent.NOT_PRESENT
- cert_io_capability = IoCapabilities.KEYBOARD_ONLY
- cert_auth_reqs = AuthenticationRequirements.DEDICATED_BONDING_MITM_PROTECTION
- cert_oob_present = OobDataPresent.NOT_PRESENT
- self.dut_security.set_io_capabilities(dut_io_capability)
- self.dut_security.set_authentication_requirements(dut_auth_reqs)
- self.cert_security.set_io_capabilities(cert_io_capability)
- self.cert_security.set_authentication_requirements(cert_auth_reqs)
-
- self._run_ssp_passkey(
- initiator=self.dut_security,
- responder=self.cert_security,
- expected_init_bond_event=BondMsgType.DEVICE_BONDED,
- expected_resp_bond_event=BondMsgType.DEVICE_BONDED)
-
- self.dut_security.remove_bond(self.cert_security.get_address(),
- common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
- self.cert_security.remove_bond(self.dut_security.get_address(),
- common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
-
- self.dut_security.wait_for_bond_event(BondMsgType.DEVICE_UNBONDED)
- self.cert_security.wait_for_bond_event(BondMsgType.DEVICE_UNBONDED)
-
- self.dut_security.wait_for_disconnect_event()
- self.cert_security.wait_for_disconnect_event()
-
- def test_successful_dut_initiated_pin(self):
- self.dut_security.set_io_capabilities(IoCapabilities.DISPLAY_YES_NO_IO_CAP)
- self.dut_security.set_authentication_requirements(AuthenticationRequirements.DEDICATED_BONDING)
-
- self._run_pin(
- initiator=self.dut_security,
- responder=self.cert_security,
- expected_init_bond_event=BondMsgType.DEVICE_BONDED,
- expected_resp_bond_event=BondMsgType.DEVICE_BONDED)
-
- self.dut_security.remove_bond(self.cert_security.get_address(),
- common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
- self.cert_security.remove_bond(self.dut_security.get_address(),
- common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
-
- self.dut_security.wait_for_bond_event(BondMsgType.DEVICE_UNBONDED)
- self.cert_security.wait_for_bond_event(BondMsgType.DEVICE_UNBONDED)
-
- self.dut_security.wait_for_disconnect_event()
- self.cert_security.wait_for_disconnect_event()
-
- def test_make_sure_oob_data_different(self):
- oob_data = self.dut_security.get_oob_data_from_controller(OobDataPresent.P192_PRESENT)
- oob_data2 = self.dut_security.get_oob_data_from_controller(OobDataPresent.P192_PRESENT)
- assertThat(oob_data).isNotEqualTo(oob_data2)
+ SecurityTestBase.teardown_test(self)
+ GdBaseTestClass.teardown_test(self)
diff --git a/gd/security/cert/security_test_lib.py b/gd/security/cert/security_test_lib.py
new file mode 100644
index 0000000..c9ed926
--- /dev/null
+++ b/gd/security/cert/security_test_lib.py
@@ -0,0 +1,543 @@
+#
+# 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 time
+
+from bluetooth_packets_python3 import hci_packets
+from cert.event_stream import EventStream
+from cert.py_security import PySecurity
+from cert.truth import assertThat
+from facade import common_pb2 as common
+from google.protobuf import empty_pb2 as empty_proto
+from hci.facade import controller_facade_pb2 as controller_facade
+from hci.facade import le_initiator_address_facade_pb2 as le_initiator_address_facade
+from l2cap.classic.facade_pb2 import ClassicSecurityPolicy
+from neighbor.facade import facade_pb2 as neighbor_facade
+from security.cert.cert_security import CertSecurity
+from security.facade_pb2 import AuthenticationRequirements
+from security.facade_pb2 import BondMsgType
+from security.facade_pb2 import IoCapabilities
+from security.facade_pb2 import OobDataPresent
+from security.facade_pb2 import UiMsgType
+
+
+class SecurityTestBase():
+ """
+ Collection of tests that each sample results from
+ different (unique) combinations of io capabilities, authentication requirements, and oob data.
+ """
+
+ _io_capabilities_name_lookup = {
+ IoCapabilities.DISPLAY_ONLY: "DISPLAY_ONLY",
+ IoCapabilities.DISPLAY_YES_NO_IO_CAP: "DISPLAY_YES_NO_IO_CAP",
+ #IoCapabilities.KEYBOARD_ONLY:"KEYBOARD_ONLY",
+ IoCapabilities.NO_INPUT_NO_OUTPUT: "NO_INPUT_NO_OUTPUT",
+ }
+
+ _auth_reqs_name_lookup = {
+ AuthenticationRequirements.NO_BONDING: "NO_BONDING",
+ AuthenticationRequirements.NO_BONDING_MITM_PROTECTION: "NO_BONDING_MITM_PROTECTION",
+ AuthenticationRequirements.DEDICATED_BONDING: "DEDICATED_BONDING",
+ AuthenticationRequirements.DEDICATED_BONDING_MITM_PROTECTION: "DEDICATED_BONDING_MITM_PROTECTION",
+ AuthenticationRequirements.GENERAL_BONDING: "GENERAL_BONDING",
+ AuthenticationRequirements.GENERAL_BONDING_MITM_PROTECTION: "GENERAL_BONDING_MITM_PROTECTION",
+ }
+
+ # Possible IO Capabilities
+ io_capabilities = (
+ IoCapabilities.DISPLAY_ONLY,
+ IoCapabilities.DISPLAY_YES_NO_IO_CAP,
+ # TODO(optedoblivion): Uncomment when Passkey Entry is implemented in ClassicPairingHandler
+ #IoCapabilities.KEYBOARD_ONLY,
+ IoCapabilities.NO_INPUT_NO_OUTPUT)
+
+ # Possible Authentication Requirements
+ auth_reqs = (AuthenticationRequirements.NO_BONDING, AuthenticationRequirements.NO_BONDING_MITM_PROTECTION,
+ AuthenticationRequirements.DEDICATED_BONDING,
+ AuthenticationRequirements.DEDICATED_BONDING_MITM_PROTECTION,
+ AuthenticationRequirements.GENERAL_BONDING, AuthenticationRequirements.GENERAL_BONDING_MITM_PROTECTION)
+
+ # Possible Out-of-Band data options
+ oob_present = (
+ OobDataPresent.NOT_PRESENT,
+ # TODO(optedoblivion): Uncomment when OOB is implemented in root canal
+ #"P192_PRESENT",
+ #"P256_PRESENT",
+ #"P192_AND_256_PRESENT"
+ )
+
+ mitm_auth_reqs = (AuthenticationRequirements.DEDICATED_BONDING_MITM_PROTECTION,
+ AuthenticationRequirements.GENERAL_BONDING_MITM_PROTECTION,
+ AuthenticationRequirements.NO_BONDING_MITM_PROTECTION)
+
+ def setup_test(self, dut, cert):
+ self.dut = dut
+ self.cert = cert
+
+ self.dut.neighbor.EnablePageScan(neighbor_facade.EnableMsg(enabled=True))
+ self.cert.neighbor.EnablePageScan(neighbor_facade.EnableMsg(enabled=True))
+
+ self.dut.name = b'DUT Device'
+ self.dut.address = self.dut.hci_controller.GetMacAddress(empty_proto.Empty()).address
+ self.cert.name = b'Cert Device'
+ self.cert.address = self.cert.hci_controller.GetMacAddress(empty_proto.Empty()).address
+
+ # TODO(optedoblivion): Make this happen in PySecurity or GdDevice
+ self.dut.hci_controller.WriteLocalName(controller_facade.NameMsg(name=self.dut.name))
+ self.cert.hci_controller.WriteLocalName(controller_facade.NameMsg(name=self.cert.name))
+
+ self.dut_security = PySecurity(self.dut)
+ self.cert_security = CertSecurity(self.cert)
+
+ self.dut_address = common.BluetoothAddressWithType(
+ address=common.BluetoothAddress(address=bytes(b'DD:05:04:03:02:01')), type=common.RANDOM_DEVICE_ADDRESS)
+ privacy_policy = le_initiator_address_facade.PrivacyPolicy(
+ address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
+ address_with_type=self.dut_address)
+ self.dut.security.SetLeInitiatorAddressPolicy(privacy_policy)
+
+ def teardown_test(self):
+ self.dut_security.close()
+ self.cert_security.close()
+
+ # Initiates the numeric comparison test
+ def _run_ssp_numeric_comparison(self, initiator, responder, init_ui_response, resp_ui_response,
+ expected_init_ui_event, expected_resp_ui_event, expected_init_bond_event,
+ expected_resp_bond_event):
+ initiator.enable_secure_simple_pairing()
+ responder.enable_secure_simple_pairing()
+ initiator.create_bond(responder.get_address(), common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
+ self._verify_ssp_numeric_comparison(initiator, responder, init_ui_response, resp_ui_response,
+ expected_init_ui_event, expected_resp_ui_event, expected_init_bond_event,
+ expected_resp_bond_event)
+
+ # Verifies the events for the numeric comparion test
+ def _verify_ssp_numeric_comparison(self, initiator, responder, init_ui_response, resp_ui_response,
+ expected_init_ui_event, expected_resp_ui_event, expected_init_bond_event,
+ expected_resp_bond_event):
+ responder.accept_pairing(initiator.get_address(), resp_ui_response)
+ initiator.on_user_input(responder.get_address(), init_ui_response, expected_init_ui_event)
+ initiator.wait_for_bond_event(expected_init_bond_event)
+ responder.wait_for_bond_event(expected_resp_bond_event)
+
+ def _run_ssp_oob(self, initiator, responder, init_ui_response, resp_ui_response, expected_init_ui_event,
+ expected_resp_ui_event, expected_init_bond_event, expected_resp_bond_event, p192_oob_data,
+ p256_oob_data):
+ initiator.enable_secure_simple_pairing()
+ responder.enable_secure_simple_pairing()
+ initiator.create_bond_out_of_band(responder.get_address(),
+ common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS, p192_oob_data,
+ p256_oob_data)
+ self._verify_ssp_oob(initiator, responder, init_ui_response, resp_ui_response, expected_init_ui_event,
+ expected_resp_ui_event, expected_init_bond_event, expected_resp_bond_event, p192_oob_data,
+ p256_oob_data)
+
+ # Verifies the events for the numeric comparion test
+ def _verify_ssp_oob(self, initiator, responder, init_ui_response, resp_ui_response, expected_init_ui_event,
+ expected_resp_ui_event, expected_init_bond_event, expected_resp_bond_event, p192_oob_data,
+ p256_oob_data):
+ responder.accept_oob_pairing(initiator.get_address())
+ initiator.on_user_input(responder.get_address(), init_ui_response, expected_init_ui_event)
+ initiator.wait_for_bond_event(expected_init_bond_event)
+ responder.wait_for_bond_event(expected_resp_bond_event)
+
+ def _run_ssp_passkey(self, initiator, responder, expected_init_bond_event, expected_resp_bond_event):
+ initiator.enable_secure_simple_pairing()
+ responder.enable_secure_simple_pairing()
+ initiator.create_bond(responder.get_address(), common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
+ self._verify_ssp_passkey(initiator, responder, expected_init_bond_event, expected_resp_bond_event)
+
+ def _verify_ssp_passkey(self, initiator, responder, expected_init_bond_event, expected_resp_bond_event):
+ responder.send_io_caps(initiator.get_address())
+ passkey = initiator.wait_for_passkey(responder.get_address())
+ responder.input_passkey(initiator.get_address(), passkey)
+ initiator.wait_for_bond_event(expected_init_bond_event)
+ responder.wait_for_bond_event(expected_resp_bond_event)
+
+ def _run_pin(self, initiator, responder, expected_init_bond_event, expected_resp_bond_event):
+ initiator.create_bond(responder.get_address(), common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
+ self._verify_pin(initiator, responder, expected_init_bond_event, expected_resp_bond_event)
+
+ def _verify_pin(self, initiator, responder, expected_init_bond_event, expected_resp_bond_event):
+ pin = b'123456789A'
+ logging.info("pin: %s" % pin)
+ initiator.input_pin(responder.get_address(), pin)
+ responder.input_pin(initiator.get_address(), pin)
+ initiator.wait_for_bond_event(expected_init_bond_event)
+ responder.wait_for_bond_event(expected_resp_bond_event)
+
+ def test_setup_teardown(self):
+ """
+ Make sure our setup and teardown is sane
+ """
+ pass
+
+ # no_input_no_output + no_input_no_output is JustWorks no confirmation
+ def test_dut_initiated_no_input_no_output_no_input_no_output_twice_bond_and_enforce(self):
+ # Arrange
+ self.dut_security.set_io_capabilities(IoCapabilities.NO_INPUT_NO_OUTPUT)
+ self.dut_security.set_authentication_requirements(AuthenticationRequirements.DEDICATED_BONDING)
+ self.cert_security.set_io_capabilities(IoCapabilities.NO_INPUT_NO_OUTPUT)
+ self.cert_security.set_authentication_requirements(AuthenticationRequirements.DEDICATED_BONDING)
+
+ # Act and Assert
+ self._run_ssp_numeric_comparison(
+ initiator=self.dut_security,
+ responder=self.cert_security,
+ init_ui_response=True,
+ resp_ui_response=True,
+ expected_init_ui_event=None,
+ expected_resp_ui_event=None,
+ expected_init_bond_event=BondMsgType.DEVICE_BONDED,
+ expected_resp_bond_event=None)
+
+ self.dut_security.enforce_security_policy(self.cert.address,
+ common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS,
+ ClassicSecurityPolicy.ENCRYPTED_TRANSPORT)
+
+ # TODO: We verify enforcement when we make sure EncryptionChange is received on DUT
+
+ # no_input_no_output + no_input_no_output is JustWorks no confirmation
+ def test_dut_initiated_no_input_no_output_no_input_no_output_twice_with_remove_bond(self):
+ # Arrange
+ self.dut_security.set_io_capabilities(IoCapabilities.NO_INPUT_NO_OUTPUT)
+ self.dut_security.set_authentication_requirements(AuthenticationRequirements.DEDICATED_BONDING)
+ self.cert_security.set_io_capabilities(IoCapabilities.NO_INPUT_NO_OUTPUT)
+ self.cert_security.set_authentication_requirements(AuthenticationRequirements.DEDICATED_BONDING)
+
+ # Act and Assert
+ self._run_ssp_numeric_comparison(
+ initiator=self.dut_security,
+ responder=self.cert_security,
+ init_ui_response=True,
+ resp_ui_response=True,
+ expected_init_ui_event=None,
+ expected_resp_ui_event=None,
+ expected_init_bond_event=BondMsgType.DEVICE_BONDED,
+ expected_resp_bond_event=None)
+
+ self.dut_security.remove_bond(self.cert.address, common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
+ self.cert_security.remove_bond(self.cert.address, common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
+ self.dut_security.wait_for_bond_event(BondMsgType.DEVICE_UNBONDED)
+ self.cert_security.wait_for_bond_event(BondMsgType.DEVICE_UNBONDED)
+
+ self.dut_security.wait_for_disconnect_event()
+ self.cert_security.wait_for_disconnect_event()
+
+ # Act and Assert
+ self._run_ssp_numeric_comparison(
+ initiator=self.dut_security,
+ responder=self.cert_security,
+ init_ui_response=True,
+ resp_ui_response=True,
+ expected_init_ui_event=None,
+ expected_resp_ui_event=None,
+ expected_init_bond_event=BondMsgType.DEVICE_BONDED,
+ expected_resp_bond_event=None)
+
+ self.dut_security.remove_bond(self.cert.address, common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
+ self.cert_security.remove_bond(self.cert.address, common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
+ self.dut_security.wait_for_bond_event(BondMsgType.DEVICE_UNBONDED)
+ self.cert_security.wait_for_bond_event(BondMsgType.DEVICE_UNBONDED)
+
+ self.dut_security.wait_for_disconnect_event()
+ self.cert_security.wait_for_disconnect_event()
+
+ def test_successful_dut_initiated_ssp_numeric_comparison(self):
+ test_count = len(self.io_capabilities) * len(self.auth_reqs) * len(self.oob_present) * len(
+ self.io_capabilities) * len(self.auth_reqs) * len(self.oob_present)
+ logging.info("Loading %d test combinations" % test_count)
+ i = 0
+ for dut_io_capability in self.io_capabilities:
+ for dut_auth_reqs in self.auth_reqs:
+ for dut_oob_present in self.oob_present:
+ for cert_io_capability in self.io_capabilities:
+ for cert_auth_reqs in self.auth_reqs:
+ for cert_oob_present in self.oob_present:
+ i = i + 1
+ logging.info("")
+ logging.info("===================================================")
+ logging.info("Running test %d of %d" % (i, test_count))
+ logging.info("DUT Test Config: %s ; %s ; %s " % (self._io_capabilities_name_lookup.get(
+ dut_io_capability, "ERROR"), self._auth_reqs_name_lookup.get(
+ dut_auth_reqs, "ERROR"), dut_oob_present))
+ logging.info(
+ "CERT Test Config: %s ; %s ; %s " %
+ (self._io_capabilities_name_lookup.get(cert_io_capability, "ERROR"),
+ self._auth_reqs_name_lookup.get(cert_auth_reqs, "ERROR"), cert_oob_present))
+ logging.info("===================================================")
+ logging.info("")
+ self.dut_security.set_io_capabilities(dut_io_capability)
+ self.dut_security.set_authentication_requirements(dut_auth_reqs)
+ self.cert_security.set_io_capabilities(cert_io_capability)
+ self.cert_security.set_authentication_requirements(cert_auth_reqs)
+ init_ui_response = True
+ resp_ui_response = True
+ expected_init_ui_event = None # None is auto accept
+ expected_resp_ui_event = None # None is auto accept
+ expected_init_bond_event = BondMsgType.DEVICE_BONDED
+ expected_resp_bond_event = None
+ if dut_io_capability == IoCapabilities.DISPLAY_ONLY:
+ if cert_io_capability == IoCapabilities.DISPLAY_YES_NO_IO_CAP:
+ expected_resp_ui_event = UiMsgType.DISPLAY_YES_NO_WITH_VALUE
+ if dut_auth_reqs in self.mitm_auth_reqs or cert_auth_reqs in self.mitm_auth_reqs:
+ expected_init_bond_event = BondMsgType.DEVICE_BOND_FAILED
+ elif cert_io_capability == IoCapabilities.KEYBOARD_ONLY:
+ expected_resp_ui_event = UiMsgType.DISPLAY_PASSKEY_ENTRY
+ elif cert_io_capability == IoCapabilities.DISPLAY_ONLY:
+ if dut_auth_reqs in self.mitm_auth_reqs or cert_auth_reqs in self.mitm_auth_reqs:
+ expected_init_bond_event = BondMsgType.DEVICE_BOND_FAILED
+ elif cert_io_capability == IoCapabilities.NO_INPUT_NO_OUTPUT:
+ if dut_auth_reqs in self.mitm_auth_reqs or cert_auth_reqs in self.mitm_auth_reqs:
+ expected_init_bond_event = BondMsgType.DEVICE_BOND_FAILED
+ elif dut_io_capability == IoCapabilities.DISPLAY_YES_NO_IO_CAP:
+ expected_init_ui_event = UiMsgType.DISPLAY_YES_NO_WITH_VALUE
+ if cert_io_capability == IoCapabilities.DISPLAY_YES_NO_IO_CAP:
+ expected_resp_ui_event = UiMsgType.DISPLAY_YES_NO_WITH_VALUE
+ elif cert_io_capability == IoCapabilities.KEYBOARD_ONLY:
+ expected_init_ui_event = UiMsgType.DISPLAY_PASSKEY
+ expected_resp_ui_event = UiMsgType.DISPLAY_PASSKEY_ENTRY
+ elif cert_io_capability == IoCapabilities.NO_INPUT_NO_OUTPUT:
+ expected_init_ui_event = UiMsgType.DISPLAY_YES_NO # No value
+ elif dut_io_capability == IoCapabilities.KEYBOARD_ONLY:
+ expected_init_ui_event = UiMsgType.DISPLAY_PASSKEY_ENTRY
+ if cert_io_capability == IoCapabilities.DISPLAY_ONLY:
+ expected_resp_ui_event = UiMsgType.DISPLAY_PASSKEY
+ elif cert_io_capability == IoCapabilities.DISPLAY_YES_NO_IO_CAP:
+ expected_resp_ui_event = UiMsgType.DISPLAY_PASSKEY_ENTRY
+ elif cert_io_capability == IoCapabilities.KEYBOARD_ONLY:
+ expected_resp_ui_event = UiMsgType.DISPLAY_PASSKEY_ENTRY
+ elif cert_io_capability == IoCapabilities.NO_INPUT_NO_OUTPUT:
+ if dut_auth_reqs in self.mitm_auth_reqs or cert_auth_reqs in self.mitm_auth_reqs:
+ expected_init_bond_event = BondMsgType.DEVICE_BOND_FAILED
+ elif dut_io_capability == IoCapabilities.NO_INPUT_NO_OUTPUT:
+ if cert_io_capability == IoCapabilities.DISPLAY_YES_NO_IO_CAP:
+ expected_resp_ui_event = UiMsgType.DISPLAY_YES_NO # No value
+
+ if dut_auth_reqs in self.mitm_auth_reqs or cert_auth_reqs in self.mitm_auth_reqs:
+ expected_init_bond_event = BondMsgType.DEVICE_BOND_FAILED
+
+ if cert_oob_present == OobDataPresent.NOT_PRESENT:
+ self._run_ssp_numeric_comparison(
+ initiator=self.dut_security,
+ responder=self.cert_security,
+ init_ui_response=init_ui_response,
+ resp_ui_response=resp_ui_response,
+ expected_init_ui_event=expected_init_ui_event,
+ expected_resp_ui_event=expected_resp_ui_event,
+ expected_init_bond_event=expected_init_bond_event,
+ expected_resp_bond_event=expected_resp_bond_event)
+ else:
+ logging.error("Code path not yet implemented")
+ assertThat(False).isTrue()
+
+ self.dut_security.remove_bond(self.cert_security.get_address(),
+ common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
+ self.cert_security.remove_bond(self.dut_security.get_address(),
+ common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
+
+ self.dut_security.wait_for_bond_event(BondMsgType.DEVICE_UNBONDED)
+ self.cert_security.wait_for_bond_event(BondMsgType.DEVICE_UNBONDED)
+
+ self.dut_security.wait_for_disconnect_event()
+ self.cert_security.wait_for_disconnect_event()
+
+ def test_enable_secure_simple_pairing(self):
+ self.dut_security.enable_secure_simple_pairing()
+ self.cert_security.enable_secure_simple_pairing()
+
+ def test_enable_secure_connections(self):
+ self.dut_security.enable_secure_simple_pairing()
+ self.cert_security.enable_secure_simple_pairing()
+ self.dut_security.enable_secure_connections()
+ self.cert_security.enable_secure_connections()
+
+ def test_get_oob_data_from_dut_controller_p192_present(self):
+ oob_data = self.dut_security.get_oob_data_from_controller(OobDataPresent.P192_PRESENT)
+ assertThat(len(oob_data)).isEqualTo(4)
+ has192C = not all([i == 0 for i in oob_data[0]])
+ has192R = not all([i == 0 for i in oob_data[1]])
+ has256C = not all([i == 0 for i in oob_data[2]])
+ has256R = not all([i == 0 for i in oob_data[3]])
+ assertThat(has192C).isTrue()
+ assertThat(has192R).isTrue()
+ assertThat(has256C).isFalse()
+ assertThat(has256R).isFalse()
+
+ def test_get_oob_data_from_cert_controller_not_present(self):
+ oob_data = self.cert_security.get_oob_data_from_controller(OobDataPresent.NOT_PRESENT)
+ assertThat(len(oob_data)).isEqualTo(4)
+ has192C = not all([i == 0 for i in oob_data[0]])
+ has192R = not all([i == 0 for i in oob_data[1]])
+ has256C = not all([i == 0 for i in oob_data[2]])
+ has256R = not all([i == 0 for i in oob_data[3]])
+ assertThat(has192C).isFalse()
+ assertThat(has192R).isFalse()
+ assertThat(has256C).isFalse()
+ assertThat(has256R).isFalse()
+
+ def test_get_oob_data_from_cert_controller_p192_present_no_secure_connections(self):
+ oob_data = self.cert_security.get_oob_data_from_controller(OobDataPresent.P192_PRESENT)
+ assertThat(len(oob_data)).isEqualTo(4)
+ has192C = not all([i == 0 for i in oob_data[0]])
+ has192R = not all([i == 0 for i in oob_data[1]])
+ has256C = not all([i == 0 for i in oob_data[2]])
+ has256R = not all([i == 0 for i in oob_data[3]])
+ assertThat(has192C).isTrue()
+ assertThat(has192R).isTrue()
+ assertThat(has256C).isFalse()
+ assertThat(has256R).isFalse()
+
+ def test_get_oob_data_from_cert_controller_p192_present(self):
+ self.cert_security.enable_secure_simple_pairing()
+ self.cert_security.enable_secure_connections()
+ oob_data = self.cert_security.get_oob_data_from_controller(OobDataPresent.P192_PRESENT)
+ assertThat(len(oob_data)).isEqualTo(4)
+ has192C = not all([i == 0 for i in oob_data[0]])
+ has192R = not all([i == 0 for i in oob_data[1]])
+ has256C = not all([i == 0 for i in oob_data[2]])
+ has256R = not all([i == 0 for i in oob_data[3]])
+ assertThat(has192C).isTrue()
+ assertThat(has192R).isTrue()
+ assertThat(has256C).isFalse()
+ assertThat(has256R).isFalse()
+
+ def test_get_oob_data_from_cert_controller_p256_present(self):
+ self.cert_security.enable_secure_simple_pairing()
+ self.cert_security.enable_secure_connections()
+ oob_data = self.cert_security.get_oob_data_from_controller(OobDataPresent.P256_PRESENT)
+ assertThat(len(oob_data)).isEqualTo(4)
+ has192C = not all([i == 0 for i in oob_data[0]])
+ has192R = not all([i == 0 for i in oob_data[1]])
+ has256C = not all([i == 0 for i in oob_data[2]])
+ has256R = not all([i == 0 for i in oob_data[3]])
+ assertThat(has192C).isFalse()
+ assertThat(has192R).isFalse()
+ assertThat(has256C).isTrue()
+ assertThat(has256R).isTrue()
+
+ def test_get_oob_data_from_cert_controller_p192_and_p256_present(self):
+ self.cert_security.enable_secure_simple_pairing()
+ self.cert_security.enable_secure_connections()
+ oob_data = self.cert_security.get_oob_data_from_controller(OobDataPresent.P192_AND_256_PRESENT)
+ assertThat(len(oob_data)).isEqualTo(4)
+ has192C = not all([i == 0 for i in oob_data[0]])
+ has192R = not all([i == 0 for i in oob_data[1]])
+ has256C = not all([i == 0 for i in oob_data[2]])
+ has256R = not all([i == 0 for i in oob_data[3]])
+ assertThat(has192C).isTrue()
+ assertThat(has192R).isTrue()
+ assertThat(has256C).isTrue()
+ assertThat(has256R).isTrue()
+
+ def test_successful_dut_initiated_ssp_oob(self):
+ dut_io_capability = IoCapabilities.NO_INPUT_NO_OUTPUT
+ cert_io_capability = IoCapabilities.NO_INPUT_NO_OUTPUT
+ dut_auth_reqs = AuthenticationRequirements.DEDICATED_BONDING_MITM_PROTECTION
+ cert_auth_reqs = AuthenticationRequirements.DEDICATED_BONDING_MITM_PROTECTION
+ cert_oob_present = OobDataPresent.P192_PRESENT
+ self.dut_security.enable_secure_simple_pairing()
+ self.dut_security.enable_secure_connections()
+ self.cert_security.enable_secure_simple_pairing()
+ self.cert_security.enable_secure_connections()
+ self.dut_security.set_io_capabilities(dut_io_capability)
+ self.dut_security.set_authentication_requirements(dut_auth_reqs)
+ self.cert_security.set_io_capabilities(cert_io_capability)
+ self.cert_security.set_authentication_requirements(cert_auth_reqs)
+ init_ui_response = True
+ resp_ui_response = True
+ expected_init_ui_event = None # None is auto accept
+ expected_resp_ui_event = None # None is auto accept
+ expected_init_bond_event = BondMsgType.DEVICE_BONDED
+ expected_resp_bond_event = None
+ # get_oob_data returns a tuple of bytes (p192c,p192r,p256c,p256r)
+ local_oob_data = self.cert_security.get_oob_data_from_controller(cert_oob_present)
+ p192_oob_data = local_oob_data[0:2]
+ p256_oob_data = local_oob_data[2:4]
+ self._run_ssp_oob(
+ initiator=self.dut_security,
+ responder=self.cert_security,
+ init_ui_response=init_ui_response,
+ resp_ui_response=resp_ui_response,
+ expected_init_ui_event=expected_init_ui_event,
+ expected_resp_ui_event=expected_resp_ui_event,
+ expected_init_bond_event=expected_init_bond_event,
+ expected_resp_bond_event=expected_resp_bond_event,
+ p192_oob_data=p192_oob_data,
+ p256_oob_data=p256_oob_data)
+ self.dut_security.remove_bond(self.cert_security.get_address(),
+ common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
+ self.cert_security.remove_bond(self.dut_security.get_address(),
+ common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
+ self.dut_security.wait_for_bond_event(BondMsgType.DEVICE_UNBONDED)
+ self.cert_security.wait_for_bond_event(BondMsgType.DEVICE_UNBONDED)
+ self.dut_security.wait_for_disconnect_event()
+ self.cert_security.wait_for_disconnect_event()
+
+ def test_successful_dut_initiated_ssp_keyboard(self):
+ dut_io_capability = IoCapabilities.DISPLAY_YES_NO_IO_CAP
+ dut_auth_reqs = AuthenticationRequirements.DEDICATED_BONDING_MITM_PROTECTION
+ dut_oob_present = OobDataPresent.NOT_PRESENT
+ cert_io_capability = IoCapabilities.KEYBOARD_ONLY
+ cert_auth_reqs = AuthenticationRequirements.DEDICATED_BONDING_MITM_PROTECTION
+ cert_oob_present = OobDataPresent.NOT_PRESENT
+ self.dut_security.set_io_capabilities(dut_io_capability)
+ self.dut_security.set_authentication_requirements(dut_auth_reqs)
+ self.cert_security.set_io_capabilities(cert_io_capability)
+ self.cert_security.set_authentication_requirements(cert_auth_reqs)
+
+ self._run_ssp_passkey(
+ initiator=self.dut_security,
+ responder=self.cert_security,
+ expected_init_bond_event=BondMsgType.DEVICE_BONDED,
+ expected_resp_bond_event=BondMsgType.DEVICE_BONDED)
+
+ self.dut_security.remove_bond(self.cert_security.get_address(),
+ common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
+ self.cert_security.remove_bond(self.dut_security.get_address(),
+ common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
+
+ self.dut_security.wait_for_bond_event(BondMsgType.DEVICE_UNBONDED)
+ self.cert_security.wait_for_bond_event(BondMsgType.DEVICE_UNBONDED)
+
+ self.dut_security.wait_for_disconnect_event()
+ self.cert_security.wait_for_disconnect_event()
+
+ def test_successful_dut_initiated_pin(self):
+ self.dut_security.set_io_capabilities(IoCapabilities.DISPLAY_YES_NO_IO_CAP)
+ self.dut_security.set_authentication_requirements(AuthenticationRequirements.DEDICATED_BONDING)
+
+ self._run_pin(
+ initiator=self.dut_security,
+ responder=self.cert_security,
+ expected_init_bond_event=BondMsgType.DEVICE_BONDED,
+ expected_resp_bond_event=BondMsgType.DEVICE_BONDED)
+
+ self.dut_security.remove_bond(self.cert_security.get_address(),
+ common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
+ self.cert_security.remove_bond(self.dut_security.get_address(),
+ common.BluetoothAddressTypeEnum.PUBLIC_DEVICE_ADDRESS)
+
+ self.dut_security.wait_for_bond_event(BondMsgType.DEVICE_UNBONDED)
+ self.cert_security.wait_for_bond_event(BondMsgType.DEVICE_UNBONDED)
+
+ self.dut_security.wait_for_disconnect_event()
+ self.cert_security.wait_for_disconnect_event()
+
+ def test_make_sure_oob_data_different(self):
+ oob_data = self.dut_security.get_oob_data_from_controller(OobDataPresent.P192_PRESENT)
+ oob_data2 = self.dut_security.get_oob_data_from_controller(OobDataPresent.P192_PRESENT)
+ assertThat(oob_data).isNotEqualTo(oob_data2)
diff --git a/gd/security/ecdh_keys.h b/gd/security/ecdh_keys.h
index 8ec25a8..f9c4302 100644
--- a/gd/security/ecdh_keys.h
+++ b/gd/security/ecdh_keys.h
@@ -17,6 +17,7 @@
******************************************************************************/
#pragma once
+#include <stdint.h>
#include <array>
namespace bluetooth {
diff --git a/gd/security/record/security_record_storage_test.cc b/gd/security/record/security_record_storage_test.cc
index 0d1d253..bd1b748 100644
--- a/gd/security/record/security_record_storage_test.cc
+++ b/gd/security/record/security_record_storage_test.cc
@@ -25,7 +25,7 @@
namespace record {
namespace {
-class SecurityRecordStorageTest : public ::testing::Test {
+class DISABLED_SecurityRecordStorageTest : public ::testing::Test {
protected:
void SetUp() override {
// Make Fake storage module
@@ -55,9 +55,9 @@
record::SecurityRecordStorage* record_storage_;
};
-TEST_F(SecurityRecordStorageTest, setup_teardown) {}
+TEST_F(DISABLED_SecurityRecordStorageTest, setup_teardown) {}
-TEST_F(SecurityRecordStorageTest, store_security_record) {
+TEST_F(DISABLED_SecurityRecordStorageTest, store_security_record) {
hci::AddressWithType remote(
hci::Address({0x01, 0x02, 0x03, 0x04, 0x05, 0x06}), hci::AddressType::PUBLIC_DEVICE_ADDRESS);
std::array<uint8_t, 16> link_key = {
@@ -78,7 +78,7 @@
}
}
-TEST_F(SecurityRecordStorageTest, store_le_security_record) {
+TEST_F(DISABLED_SecurityRecordStorageTest, store_le_security_record) {
hci::AddressWithType identity_address(
hci::Address({0x01, 0x02, 0x03, 0x04, 0x05, 0x06}), hci::AddressType::RANDOM_DEVICE_ADDRESS);
std::array<uint8_t, 16> remote_ltk{
@@ -118,7 +118,7 @@
ASSERT_EQ(device.Le().GetPeerSignatureResolvingKeys(), "000000000883ae44d6779e901d25cdd7b6f4578502");
}
-TEST_F(SecurityRecordStorageTest, load_security_record) {
+TEST_F(DISABLED_SecurityRecordStorageTest, load_security_record) {
hci::AddressWithType remote(
hci::Address({0x01, 0x02, 0x03, 0x04, 0x05, 0x06}), hci::AddressType::PUBLIC_DEVICE_ADDRESS);
std::array<uint8_t, 16> link_key = {
@@ -151,7 +151,7 @@
}
}
-TEST_F(SecurityRecordStorageTest, dont_save_temporary_records) {
+TEST_F(DISABLED_SecurityRecordStorageTest, dont_save_temporary_records) {
hci::AddressWithType remote(
hci::Address({0x01, 0x02, 0x03, 0x04, 0x05, 0x06}), hci::AddressType::PUBLIC_DEVICE_ADDRESS);
std::array<uint8_t, 16> link_key = {
@@ -172,7 +172,7 @@
ASSERT_EQ(record_set.size(), 0);
}
-TEST_F(SecurityRecordStorageTest, test_remove) {
+TEST_F(DISABLED_SecurityRecordStorageTest, test_remove) {
hci::AddressWithType remote(
hci::Address({0x01, 0x02, 0x03, 0x04, 0x05, 0x06}), hci::AddressType::PUBLIC_DEVICE_ADDRESS);
std::array<uint8_t, 16> link_key = {
diff --git a/gd/security/test/fake_name_db.h b/gd/security/test/fake_name_db.h
index b168155..9a34094 100644
--- a/gd/security/test/fake_name_db.h
+++ b/gd/security/test/fake_name_db.h
@@ -28,6 +28,9 @@
void ListDependencies(ModuleList* list) override {}
void Start() override {}
void Stop() override {}
+ std::string ToString() const override {
+ return std::string("FakeNameDbModule");
+ }
void ReadRemoteNameRequest(
hci::Address address, neighbor::ReadRemoteNameDbCallback callback, os::Handler* handler) override {
diff --git a/gd/shim/cert/shim_test.py b/gd/shim/cert/shim_test.py
index bc2fca6..f0679ab 100644
--- a/gd/shim/cert/shim_test.py
+++ b/gd/shim/cert/shim_test.py
@@ -14,24 +14,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import os
-import sys
-import logging
-
-from cert.event_stream import EventStream
from cert.gd_base_test import GdBaseTestClass
-from cert.truth import assertThat
-from facade import common_pb2 as common
-from facade import rootservice_pb2 as facade_rootservice
-from google.protobuf import empty_pb2 as empty_proto
-from shim.facade import facade_pb2 as shim_facade
+from shim.cert.shim_test_lib import ShimTestBase
-class ShimTest(GdBaseTestClass):
+class ShimTest(GdBaseTestClass, ShimTestBase):
def setup_class(self):
- super().setup_class(dut_module='SHIM', cert_module='SHIM')
+ GdBaseTestClass.setup_class(self, dut_module='SHIM', cert_module='SHIM')
def test_dumpsys(self):
- result = self.cert.shim.Dump(empty_proto.Empty())
- result = self.dut.shim.Dump(empty_proto.Empty())
+ ShimTestBase.test_dumpsys(self, self.dut, self.cert)
diff --git a/gd/shim/cert/shim_test_lib.py b/gd/shim/cert/shim_test_lib.py
new file mode 100644
index 0000000..024dc39
--- /dev/null
+++ b/gd/shim/cert/shim_test_lib.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python3
+#
+# Copyright 2020 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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 os
+import sys
+import logging
+
+from cert.event_stream import EventStream
+from cert.truth import assertThat
+from facade import common_pb2 as common
+from facade import rootservice_pb2 as facade_rootservice
+from google.protobuf import empty_pb2 as empty_proto
+from shim.facade import facade_pb2 as shim_facade
+
+
+class ShimTestBase():
+
+ def test_dumpsys(self, dut, cert):
+ result = cert.shim.Dump(empty_proto.Empty())
+ result = dut.shim.Dump(empty_proto.Empty())
diff --git a/gd/shim/cert/stack_test.py b/gd/shim/cert/stack_test.py
index 3daecc0..a43f091 100644
--- a/gd/shim/cert/stack_test.py
+++ b/gd/shim/cert/stack_test.py
@@ -14,16 +14,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import os
-import sys
-
from cert.gd_base_test import GdBaseTestClass
+from shim.cert.stack_test_lib import StackTestBase
-class StackTest(GdBaseTestClass):
+class StackTest(GdBaseTestClass, StackTestBase):
def setup_class(self):
super().setup_class(dut_module='SHIM', cert_module='SHIM')
-
- def test_test(self):
- return True
diff --git a/gd/shim/cert/stack_test_lib.py b/gd/shim/cert/stack_test_lib.py
new file mode 100644
index 0000000..485cda4
--- /dev/null
+++ b/gd/shim/cert/stack_test_lib.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python3
+#
+# Copyright 2020 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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 os
+import sys
+
+
+class StackTestBase():
+
+ def test_test(self):
+ return True
diff --git a/gd/stack_manager.cc b/gd/stack_manager.cc
index 8c017ba..3366c7b 100644
--- a/gd/stack_manager.cc
+++ b/gd/stack_manager.cc
@@ -17,35 +17,43 @@
#include "stack_manager.h"
#include <fcntl.h>
+#include <stdio.h>
#include <unistd.h>
#include <chrono>
#include <future>
#include <queue>
#include "common/bind.h"
-#include "hal/hci_hal.h"
#include "module.h"
#include "os/handler.h"
#include "os/log.h"
#include "os/thread.h"
+#include "os/wakelock_manager.h"
using ::bluetooth::os::Handler;
using ::bluetooth::os::Thread;
+using ::bluetooth::os::WakelockManager;
namespace bluetooth {
-constexpr char bluetooth_pid_file[] = "/var/run/bluetooth";
+// Assume we are hci0 for now
+constexpr char bluetooth_pid_file[] = "/var/run/bluetooth/bluetooth0.pid";
void StackManager::StartUp(ModuleList* modules, Thread* stack_thread) {
management_thread_ = new Thread("management_thread", Thread::Priority::NORMAL);
handler_ = new Handler(management_thread_);
+ WakelockManager::Get().Acquire();
+
std::promise<void> promise;
auto future = promise.get_future();
handler_->Post(common::BindOnce(&StackManager::handle_start_up, common::Unretained(this), modules, stack_thread,
std::move(promise)));
auto init_status = future.wait_for(std::chrono::seconds(3));
+
+ WakelockManager::Get().Release();
+
ASSERT_LOG(
init_status == std::future_status::ready,
"Can't start stack, last instance: %s",
@@ -53,7 +61,7 @@
pid_fd_ = open(bluetooth_pid_file, O_WRONLY | O_CREAT, 0644);
pid_t my_pid = getpid();
- write(pid_fd_, &my_pid, sizeof(pid_t));
+ dprintf(pid_fd_, "%d\n", my_pid);
LOG_INFO("init complete");
}
@@ -64,11 +72,17 @@
}
void StackManager::ShutDown() {
+ WakelockManager::Get().Acquire();
+
std::promise<void> promise;
auto future = promise.get_future();
handler_->Post(common::BindOnce(&StackManager::handle_shut_down, common::Unretained(this), std::move(promise)));
auto stop_status = future.wait_for(std::chrono::seconds(5));
+
+ WakelockManager::Get().Release();
+ WakelockManager::Get().CleanUp();
+
ASSERT_LOG(
stop_status == std::future_status::ready,
"Can't stop stack, last instance: %s",
diff --git a/gd/stack_manager.h b/gd/stack_manager.h
index 5a9fa28..985bd0b 100644
--- a/gd/stack_manager.h
+++ b/gd/stack_manager.h
@@ -32,6 +32,11 @@
return static_cast<T*>(registry_.Get(&T::Factory));
}
+ template <class T>
+ bool IsStarted() const {
+ return registry_.IsStarted(&T::Factory);
+ }
+
private:
os::Thread* management_thread_ = nullptr;
os::Handler* handler_ = nullptr;
diff --git a/gd/stack_manager_unittest.cc b/gd/stack_manager_unittest.cc
index e79a94f..b82fe16 100644
--- a/gd/stack_manager_unittest.cc
+++ b/gd/stack_manager_unittest.cc
@@ -38,6 +38,9 @@
void ListDependencies(ModuleList* list) override {}
void Start() override {}
void Stop() override {}
+ std::string ToString() const override {
+ return std::string("TestModuleDep");
+ }
};
const ModuleFactory TestModuleNoDependency::Factory = ModuleFactory([]() { return new TestModuleNoDependency(); });
diff --git a/gd/storage/Android.bp b/gd/storage/Android.bp
index ce900a6..6644da1 100644
--- a/gd/storage/Android.bp
+++ b/gd/storage/Android.bp
@@ -24,7 +24,7 @@
}
filegroup {
- name: "BluetoothStorageTestSources",
+ name: "BluetoothStorageUnitTestSources",
srcs: [
"adapter_config_test.cc",
"classic_device_test.cc",
@@ -34,6 +34,12 @@
"le_device_test.cc",
"legacy_config_file_test.cc",
"mutation_test.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothStorageTestSources",
+ srcs: [
"storage_module_test.cc",
],
}
diff --git a/gd/storage/device.h b/gd/storage/device.h
index 7aba3df..e610f57 100644
--- a/gd/storage/device.h
+++ b/gd/storage/device.h
@@ -185,6 +185,11 @@
GENERATE_PROPERTY_GETTER_SETTER_REMOVER(ManufacturerCode, uint16_t, "Manufacturer");
GENERATE_PROPERTY_GETTER_SETTER_REMOVER(LmpVersion, uint8_t, "LmpVer");
GENERATE_PROPERTY_GETTER_SETTER_REMOVER(LmpSubVersion, uint16_t, "LmpSubVer");
+ GENERATE_PROPERTY_GETTER_SETTER_REMOVER(SdpDiManufacturer, uint16_t, "SdpDiManufacturer");
+ GENERATE_PROPERTY_GETTER_SETTER_REMOVER(SdpDiModel, uint16_t, "SdpDiModel");
+ GENERATE_PROPERTY_GETTER_SETTER_REMOVER(SdpDiHardwareVersion, uint16_t, "SdpDiHardwareVersion");
+ GENERATE_PROPERTY_GETTER_SETTER_REMOVER(SdpDiVendorIdSource, uint16_t, "SdpDiVendorIdSource");
+
GENERATE_PROPERTY_GETTER_SETTER_REMOVER(MetricsId, int, "MetricsId");
GENERATE_PROPERTY_GETTER_SETTER_REMOVER(PinLength, int, "PinLength");
// unix timestamp in seconds from epoch
diff --git a/gd/storage/device_test.cc b/gd/storage/device_test.cc
index a7b41a7..0706403 100644
--- a/gd/storage/device_test.cc
+++ b/gd/storage/device_test.cc
@@ -30,6 +30,7 @@
using bluetooth::storage::Device;
using bluetooth::storage::Mutation;
using ::testing::Eq;
+using ::testing::MatchesRegex;
using ::testing::Optional;
using ::testing::StrEq;
@@ -146,8 +147,8 @@
Address address = {{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
Device device(&config, &memory_only_config, address, Device::ConfigKeyAddressType::LEGACY_KEY_ADDRESS);
ASSERT_FALSE(device.GetDeviceType());
- ASSERT_DEATH({ device.Le(); }, "device_type == DeviceType::LE || device_type == DeviceType::DUAL");
- ASSERT_DEATH({ device.Classic(); }, "device_type == DeviceType::BR_EDR || device_type == DeviceType::DUAL");
+ ASSERT_DEATH({ device.Le(); }, MatchesRegex(".*"));
+ ASSERT_DEATH({ device.Classic(); }, MatchesRegex(".*"));
// classic
{
diff --git a/gd/storage/storage_module.cc b/gd/storage/storage_module.cc
index b862251..6b4e9bc 100644
--- a/gd/storage/storage_module.cc
+++ b/gd/storage/storage_module.cc
@@ -175,7 +175,7 @@
config->SetProperty(kInfoSection, kTimeCreatedProperty, ss.str());
}
config->FixDeviceTypeInconsistencies();
- config->SetPersistentConfigChangedCallback([this] { this->SaveDelayed(); });
+ config->SetPersistentConfigChangedCallback([this] { this->CallOn(this, &StorageModule::SaveDelayed); });
// TODO (b/158035889) Migrate metrics module to GD
pimpl_ = std::make_unique<impl>(GetHandler(), std::move(config.value()), temp_devices_capacity_);
SaveDelayed();
diff --git a/hci/Android.bp b/hci/Android.bp
index 1ec3014..1dd872c 100644
--- a/hci/Android.bp
+++ b/hci/Android.bp
@@ -18,7 +18,6 @@
}
// HCI static library for target
-// ========================================================
cc_library_static {
name: "libbt-hci",
defaults: ["libbt-hci_defaults"],
@@ -59,7 +58,6 @@
}
// HCI unit tests for target
-// ========================================================
cc_test {
name: "net_test_hci",
test_suites: ["device-tests"],
@@ -98,7 +96,6 @@
}
// HCI native unit tests for target
-// ========================================================
cc_test {
name: "net_test_hci_native",
test_suites: ["device-tests"],
diff --git a/include/abstract_message_loop.h b/include/abstract_message_loop.h
index 9816e0d..dff65b1 100644
--- a/include/abstract_message_loop.h
+++ b/include/abstract_message_loop.h
@@ -21,7 +21,11 @@
* the old libchrome version so use the basic messageloop where that's required.
* Elsewhere, use the SingleThreadTaskExecutor instead.
*/
+#if BASE_VER >= 822064
+#include <base/task/current_thread.h>
+#else
#include <base/message_loop/message_loop_current.h>
+#endif
#include <base/message_loop/message_pump.h>
#include <base/task/single_thread_task_executor.h>
#include <base/test/task_environment.h>
diff --git a/include/bind_helpers.h b/include/bind_helpers.h
new file mode 100644
index 0000000..c92d8f7
--- /dev/null
+++ b/include/bind_helpers.h
@@ -0,0 +1,22 @@
+//
+// Copyright 2021 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
+
+#if defined(BASE_VER) && BASE_VER >= 860220
+#include <base/callback_helpers.h>
+#else
+#include <base/bind_helpers.h>
+#endif
diff --git a/include/hardware/ble_scanner.h b/include/hardware/ble_scanner.h
index c426425..5d6e945 100644
--- a/include/hardware/ble_scanner.h
+++ b/include/hardware/ble_scanner.h
@@ -52,6 +52,23 @@
track_adv_event_callback track_adv_event_cb;
} btgatt_scanner_callbacks_t;
+class AdvertisingTrackInfo {
+ public:
+ uint8_t scanner_id;
+ uint8_t filter_index;
+ uint8_t advertiser_state;
+ uint8_t advertiser_info_present;
+ RawAddress advertiser_address;
+ uint8_t advertiser_address_type;
+ uint8_t tx_power;
+ int8_t rssi;
+ uint16_t time_stamp;
+ uint8_t adv_packet_len;
+ std::vector<uint8_t> adv_packet;
+ uint8_t scan_response_len;
+ std::vector<uint8_t> scan_response;
+};
+
/**
* LE Scanning related callbacks invoked from from the Bluetooth native stack
* All callbacks are invoked on the JNI thread
@@ -61,6 +78,8 @@
virtual ~ScanningCallbacks() = default;
virtual void OnScannerRegistered(const bluetooth::Uuid app_uuid,
uint8_t scannerId, uint8_t status) = 0;
+ virtual void OnSetScannerParameterComplete(uint8_t scannerId,
+ uint8_t status) = 0;
virtual void OnScanResult(uint16_t event_type, uint8_t addr_type,
RawAddress bda, uint8_t primary_phy,
uint8_t secondary_phy, uint8_t advertising_sid,
@@ -68,10 +87,11 @@
uint16_t periodic_adv_int,
std::vector<uint8_t> adv_data) = 0;
virtual void OnTrackAdvFoundLost(
- btgatt_track_adv_info_t* p_adv_track_info) = 0;
+ AdvertisingTrackInfo advertising_track_info) = 0;
virtual void OnBatchScanReports(int client_if, int status, int report_format,
int num_records,
std::vector<uint8_t> data) = 0;
+ virtual void OnBatchScanThresholdCrossed(int client_if) = 0;
};
class BleScannerInterface {
@@ -121,8 +141,8 @@
virtual void ScanFilterEnable(bool enable, EnableCallback cb) = 0;
/** Sets the LE scan interval and window in units of N*0.625 msec */
- virtual void SetScanParameters(int scan_interval, int scan_window,
- Callback cb) = 0;
+ virtual void SetScanParameters(int scanner_id, int scan_interval,
+ int scan_window, Callback cb) = 0;
/* Configure the batchscan storage */
virtual void BatchscanConfigStorage(int client_if, int batch_scan_full_max,
diff --git a/include/hardware/bluetooth.h b/include/hardware/bluetooth.h
index dc9dff4..63f47e2 100644
--- a/include/hardware/bluetooth.h
+++ b/include/hardware/bluetooth.h
@@ -355,13 +355,6 @@
uint8_t le_appearance[2]; /* For the appearance of the device */
} bt_oob_data_t;
-/** Bundle that can contain 1 or both of P192 and P256 */
-// typedef struct {
-// uint8_t address[7]; /* Bluetooth Device Address (6) plus Address Type
-// (1) */ bt_oob_data_t p192_data; /* P192 Data or NULL */ bt_oob_data_t
-// p256_data; /* P256 Data or NULL */
-//} bt_oob_data_bundle_t;
-
/** Bluetooth Device Type */
typedef enum {
BT_DEVICE_DEVTYPE_BREDR = 0x1,
diff --git a/include/hardware/bt_activity_attribution.h b/include/hardware/bt_activity_attribution.h
index 74e4404..4804270 100644
--- a/include/hardware/bt_activity_attribution.h
+++ b/include/hardware/bt_activity_attribution.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_INCLUDE_BT_ACTIVITY_ATTRIBUTION_H
#define ANDROID_INCLUDE_BT_ACTIVITY_ATTRIBUTION_H
+#include <vector>
+
#include "raw_address.h"
namespace bluetooth {
@@ -26,12 +28,14 @@
public:
enum class Activity : uint8_t {
UNKNOWN = 0,
+ ACL,
ADVERTISE,
CONNECT,
CONTROL,
- SCAN,
HFP,
- VENDOR
+ ISO,
+ SCAN,
+ VENDOR,
};
struct BtaaAggregationEntry {
diff --git a/include/hardware/bt_common_types.h b/include/hardware/bt_common_types.h
index 6064986..ee607e4 100644
--- a/include/hardware/bt_common_types.h
+++ b/include/hardware/bt_common_types.h
@@ -101,6 +101,7 @@
uint16_t company_mask;
std::vector<uint8_t> data;
std::vector<uint8_t> data_mask;
+ std::array<uint8_t, 16> irk; // 128 bit/16 octet IRK
};
#endif /* ANDROID_INCLUDE_BT_COMMON_TYPES_H */
diff --git a/include/hardware/bt_hh.h b/include/hardware/bt_hh.h
index b87b129..06272d2 100644
--- a/include/hardware/bt_hh.h
+++ b/include/hardware/bt_hh.h
@@ -18,6 +18,7 @@
#define ANDROID_INCLUDE_BT_HH_H
#include <stdint.h>
+#include <string>
__BEGIN_DECLS
@@ -26,17 +27,32 @@
/* HH connection states */
typedef enum {
BTHH_CONN_STATE_CONNECTED = 0,
- BTHH_CONN_STATE_CONNECTING,
- BTHH_CONN_STATE_DISCONNECTED,
- BTHH_CONN_STATE_DISCONNECTING,
- BTHH_CONN_STATE_FAILED_MOUSE_FROM_HOST,
- BTHH_CONN_STATE_FAILED_KBD_FROM_HOST,
- BTHH_CONN_STATE_FAILED_TOO_MANY_DEVICES,
- BTHH_CONN_STATE_FAILED_NO_BTHID_DRIVER,
- BTHH_CONN_STATE_FAILED_GENERIC,
- BTHH_CONN_STATE_UNKNOWN
+ BTHH_CONN_STATE_CONNECTING = 1,
+ BTHH_CONN_STATE_DISCONNECTED = 2,
+ BTHH_CONN_STATE_DISCONNECTING = 3,
+ BTHH_CONN_STATE_UNKNOWN = 0xff,
} bthh_connection_state_t;
+__END_DECLS
+#define CASE_RETURN_TEXT(code) \
+ case code: \
+ return #code
+
+inline std::string bthh_connection_state_text(
+ const bthh_connection_state_t& state) {
+ switch (state) {
+ CASE_RETURN_TEXT(BTHH_CONN_STATE_CONNECTED);
+ CASE_RETURN_TEXT(BTHH_CONN_STATE_CONNECTING);
+ CASE_RETURN_TEXT(BTHH_CONN_STATE_DISCONNECTED);
+ CASE_RETURN_TEXT(BTHH_CONN_STATE_DISCONNECTING);
+ CASE_RETURN_TEXT(BTHH_CONN_STATE_UNKNOWN);
+ default:
+ return std::string("UNKNOWN[%u]", state);
+ }
+}
+#undef CASE_RETURN_TEXT
+__BEGIN_DECLS
+
typedef enum {
BTHH_OK = 0,
BTHH_HS_HID_NOT_READY, /* handshake error : device not ready */
diff --git a/include/notreached.h b/include/notreached.h
new file mode 100644
index 0000000..1bc8497
--- /dev/null
+++ b/include/notreached.h
@@ -0,0 +1,24 @@
+//
+// Copyright 2021 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
+
+// On all old libchrome, NOTREACHED is available via logging.h
+// After 822064, this was moved into base/notreached.h
+#if defined(BASE_VER) && BASE_VER >= 822064
+#include <base/notreached.h>
+#else
+#include <base/logging.h>
+#endif
diff --git a/internal_include/bt_target.h b/internal_include/bt_target.h
index b0c06f1..12f04d4 100644
--- a/internal_include/bt_target.h
+++ b/internal_include/bt_target.h
@@ -571,12 +571,6 @@
* ATT/GATT Protocol/Profile Settings
*
*****************************************************************************/
-#ifndef BLE_DELAY_REQUEST_ENC
-/* This flag is to work around IPHONE problem, We need to wait for iPhone ready
- before send encryption request to iPhone */
-#define BLE_DELAY_REQUEST_ENC FALSE
-#endif
-
#ifndef GATT_MAX_SR_PROFILES
#define GATT_MAX_SR_PROFILES 32 /* max is 32 */
#endif
@@ -832,6 +826,11 @@
#define AVDT_PROTECT_SIZE 90
#endif
+/* Default sink delay value in ms. */
+#ifndef AVDT_SINK_DELAY_MS
+#define AVDT_SINK_DELAY_MS 300
+#endif
+
/******************************************************************************
*
* PAN
diff --git a/internal_include/bte.h b/internal_include/bte.h
index 754cf53..7839bab 100644
--- a/internal_include/bte.h
+++ b/internal_include/bte.h
@@ -98,7 +98,7 @@
#define BTE_HCISU_USERIAL_OK 1
typedef void(tUSERIAL_MSG_CBACK)(int status);
typedef struct tHCISU_USERIAL_MSG_tag {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
tUSERIAL_MSG_CBACK* p_cback;
uint8_t port; /* port number */
uint8_t op;
diff --git a/main/Android.bp b/main/Android.bp
index 251e2e3..629f7d2 100644
--- a/main/Android.bp
+++ b/main/Android.bp
@@ -1,5 +1,4 @@
// Bluetooth main HW module / shared library for target
-// ========================================================
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
@@ -137,6 +136,7 @@
android: {
shared_libs: [
"android.system.suspend.control-V1-ndk",
+ "android.system.suspend@1.0",
"libaaudio",
"libfmq",
],
@@ -216,6 +216,12 @@
"system/bt/stack/include",
],
srcs: [
+ ":TestCommonMainHandler",
+ ":TestMockBta",
+ ":TestMockBtif",
+ ":TestMockLegacyHciCommands",
+ ":TestMockMainShimEntry",
+ ":TestMockStack",
"shim/acl_api.cc",
"shim/acl.cc",
"shim/acl_legacy_interface.cc",
@@ -233,25 +239,6 @@
"shim/metrics_api.cc",
"shim/shim.cc",
"shim/stack.cc",
- "test/common/mock_acl_ble.cc",
- "test/common/mock_acl_btm_pm.cc",
- "test/common/mock_bta_dm_act.cc",
- "test/common/mock_btif_core.cc",
- "test/common/mock_btif_dm.cc",
- "test/common/mock_btm_ble_gap.cc",
- "test/common/mock_btm_dev.cc",
- "test/common/mock_btm_inq.cc",
- "test/common/mock_btm_main.cc",
- "test/common/mock_btm_sec.cc",
- "test/common/mock_btu_task.cc",
- "test/common/mock_entry.cc",
- "test/common/mock_gatt_main.cc",
- "test/common/mock_hcic_hcicmds.cc",
- "test/common/mock_l2cap_l2c_ble.cc",
- "test/common/mock_l2cap_l2c_link.cc",
- "test/common/mock_stack_acl.cc",
- "test/common/mock_stack_btm_ble.cc",
- "test/common/mock_stack_btm_sco.cc",
"test/main_shim_test.cc",
],
static_libs: [
diff --git a/main/BUILD.gn b/main/BUILD.gn
index b411211..9604f59 100644
--- a/main/BUILD.gn
+++ b/main/BUILD.gn
@@ -18,6 +18,24 @@
include_dirs = [ "../include" ]
}
+# Complete static library for linking with Rust
+static_library("bluetooth-static") {
+ complete_static_lib = true
+
+ sources = [
+ "//bt/service/hal/bluetooth_interface.cc",
+ "//bt/service/logging_helpers.cc",
+ ]
+
+ configs += [
+ "//bt:target_defaults"
+ ]
+
+ deps = [
+ ":bluetooth",
+ ]
+}
+
# Configure libbluetooth as either dynamic or static library
if (defined(use.bt_dynlib) && use.bt_dynlib) {
lib_type = "shared_library"
@@ -26,11 +44,9 @@
}
target(lib_type, "bluetooth") {
- # HAL layer
- sources = [ "//bt/btif/src/bluetooth.cc" ]
- # platform specific
- sources += [
+ # Platform specific
+ sources = [
"bte_conf.cc",
"bte_init_cpp_logging.cc",
"bte_logmsg.cc",
diff --git a/main/bte_conf.cc b/main/bte_conf.cc
index 6353266..4634cce 100644
--- a/main/bte_conf.cc
+++ b/main/bte_conf.cc
@@ -48,7 +48,7 @@
break;
}
- tBTA_DI_RECORD record;
+ tSDP_DI_RECORD record;
record.vendor =
config_get_int(*config, section_name, "vendorId", LMP_COMPID_GOOGLE);
record.vendor_id_source = config_get_int(
diff --git a/main/shim/BUILD.gn b/main/shim/BUILD.gn
index 7b286cb..5e64858 100644
--- a/main/shim/BUILD.gn
+++ b/main/shim/BUILD.gn
@@ -19,6 +19,7 @@
"acl.cc",
"acl_api.cc",
"acl_legacy_interface.cc",
+ "activity_attribution.cc",
"btm.cc",
"btm_api.cc",
"config.cc",
@@ -55,6 +56,7 @@
"//bt/gd/os:BluetoothOsSources_linux_generic",
"//bt/gd/packet:BluetoothPacketSources",
"//bt/gd/rust/shim:libbluetooth_rust_interop",
+ "//bt/gd/rust/topshim:libbluetooth_topshim",
"//bt/osi",
"//bt/stack",
"//bt/types",
diff --git a/main/shim/acl.cc b/main/shim/acl.cc
index b6c1c51..2e50446 100644
--- a/main/shim/acl.cc
+++ b/main/shim/acl.cc
@@ -29,6 +29,7 @@
#include <memory>
#include <string>
+#include "btif/include/btif_hh.h"
#include "device/include/controller.h"
#include "gd/common/bidi_queue.h"
#include "gd/common/bind.h"
@@ -237,12 +238,14 @@
} // namespace
-#define TRY_POSTING_ON_MAIN(cb, ...) \
- if (cb == nullptr) { \
- LOG_WARN("Dropping ACL event with no callback"); \
- } else { \
- do_in_main_thread(FROM_HERE, base::Bind(cb, ##__VA_ARGS__)); \
- }
+#define TRY_POSTING_ON_MAIN(cb, ...) \
+ do { \
+ if (cb == nullptr) { \
+ LOG_WARN("Dropping ACL event with no callback"); \
+ } else { \
+ do_in_main_thread(FROM_HERE, base::Bind(cb, ##__VA_ARGS__)); \
+ } \
+ } while (0)
constexpr HciHandle kInvalidHciHandle = 0xffff;
@@ -297,7 +300,14 @@
BT_HDR* p_buf = MakeLegacyBtHdrPacket(std::move(packet), preamble);
ASSERT_LOG(p_buf != nullptr,
"Unable to allocate BT_HDR legacy packet handle:%04x", handle_);
- TRY_POSTING_ON_MAIN(send_data_upwards_, p_buf);
+ if (send_data_upwards_ == nullptr) {
+ LOG_WARN("Dropping ACL data with no callback");
+ osi_free(p_buf);
+ } else if (do_in_main_thread(FROM_HERE,
+ base::Bind(send_data_upwards_, p_buf)) !=
+ BT_STATUS_SUCCESS) {
+ osi_free(p_buf);
+ }
}
virtual void InitiateDisconnect(hci::DisconnectReason reason) = 0;
@@ -511,6 +521,17 @@
manufacturer_name, sub_version);
}
+ void OnReadRemoteSupportedFeaturesComplete(uint64_t features) override {
+ TRY_POSTING_ON_MAIN(interface_.on_read_remote_supported_features_complete,
+ handle_, features);
+
+ if (features & ((uint64_t(1) << 63))) {
+ connection_->ReadRemoteExtendedFeatures(1);
+ return;
+ }
+ LOG_DEBUG("Device does not support extended features");
+ }
+
void OnReadRemoteExtendedFeaturesComplete(uint8_t page_number,
uint8_t max_page_number,
uint64_t features) override {
@@ -763,8 +784,42 @@
handle_to_classic_connection_map_[handle]->SetConnectionEncryption(enable);
}
+ void disconnect_classic(uint16_t handle, tHCI_STATUS reason) {
+ auto connection = handle_to_classic_connection_map_.find(handle);
+ if (connection != handle_to_classic_connection_map_.end()) {
+ auto remote_address = connection->second->GetRemoteAddress();
+ connection->second->InitiateDisconnect(
+ ToDisconnectReasonFromLegacy(reason));
+ LOG_DEBUG("Disconnection initiated classic remote:%s handle:%hu",
+ PRIVATE_ADDRESS(remote_address), handle);
+ BTM_LogHistory(kBtmLogTag, ToRawAddress(remote_address),
+ "Disconnection initiated", "classic");
+ } else {
+ LOG_WARN("Unable to disconnect unknown classic connection handle:0x%04x",
+ handle);
+ }
+ }
+
+ void disconnect_le(uint16_t handle, tHCI_STATUS reason) {
+ auto connection = handle_to_le_connection_map_.find(handle);
+ if (connection != handle_to_le_connection_map_.end()) {
+ auto remote_address_with_type =
+ connection->second->GetRemoteAddressWithType();
+ connection->second->InitiateDisconnect(
+ ToDisconnectReasonFromLegacy(reason));
+ LOG_DEBUG("Disconnection initiated le remote:%s handle:%hu",
+ PRIVATE_ADDRESS(remote_address_with_type), handle);
+ BTM_LogHistory(kBtmLogTag,
+ ToLegacyAddressWithType(remote_address_with_type),
+ "Disconnection initiated", "Le");
+ } else {
+ LOG_WARN("Unable to disconnect unknown le connection handle:0x%04x",
+ handle);
+ }
+ }
+
void accept_le_connection_from(const hci::AddressWithType& address_with_type,
- std::promise<bool> promise) {
+ bool is_direct, std::promise<bool> promise) {
if (shadow_acceptlist_.IsFull()) {
LOG_ERROR("Acceptlist is full preventing new Le connection");
promise.set_value(false);
@@ -772,7 +827,7 @@
}
shadow_acceptlist_.Add(address_with_type);
promise.set_value(true);
- GetAclManager()->CreateLeConnection(address_with_type);
+ GetAclManager()->CreateLeConnection(address_with_type, is_direct);
LOG_DEBUG("Allow Le connection from remote:%s",
PRIVATE_ADDRESS(address_with_type));
BTM_LogHistory(kBtmLogTag, ToLegacyAddressWithType(address_with_type),
@@ -805,9 +860,10 @@
for (auto& entry : history) {
LOG_DEBUG("%s", entry.c_str());
}
- LOG_DEBUG("Shadow le accept list size:%hhu",
- controller_get_interface()->get_ble_acceptlist_size());
const auto acceptlist = shadow_acceptlist_.GetCopy();
+ LOG_DEBUG("Shadow le accept list size:%-3zu controller_max_size:%hhu",
+ acceptlist.size(),
+ controller_get_interface()->get_ble_acceptlist_size());
for (auto& entry : acceptlist) {
LOG_DEBUG("acceptlist:%s", entry.ToString().c_str());
}
@@ -820,10 +876,12 @@
for (auto& entry : history) {
LOG_DUMPSYS(fd, "%s", entry.c_str());
}
- LOG_DUMPSYS(fd, "Shadow le accept list size:%hhu",
+ auto acceptlist = shadow_acceptlist_.GetCopy();
+ LOG_DUMPSYS(fd,
+ "Shadow le accept list size:%-3zu controller_max_size:%hhu",
+ acceptlist.size(),
controller_get_interface()->get_ble_acceptlist_size());
unsigned cnt = 0;
- auto acceptlist = shadow_acceptlist_.GetCopy();
for (auto& entry : acceptlist) {
LOG_DUMPSYS(fd, "%03u le acceptlist:%s", ++cnt, entry.ToString().c_str());
}
@@ -862,43 +920,45 @@
shim::Stack::GetInstance()->GetAcl()->DumpConnectionHistory(fd);
for (int i = 0; i < MAX_L2CAP_LINKS; i++) {
- const tACL_CONN& acl_conn = acl_cb.acl_db[i];
- if (!acl_conn.in_use) continue;
+ const tACL_CONN& link = acl_cb.acl_db[i];
+ if (!link.in_use) continue;
- LOG_DUMPSYS(fd, " peer_le_features valid:%s data:%s",
- common::ToString(acl_conn.peer_le_features_valid).c_str(),
- bd_features_text(acl_conn.peer_le_features).c_str());
- for (int j = 0; j < HCI_EXT_FEATURES_PAGE_MAX + 1; j++) {
- LOG_DUMPSYS(fd, " peer_lmp_features[%d] valid:%s data:%s", j,
- common::ToString(acl_conn.peer_lmp_feature_valid[j]).c_str(),
- bd_features_text(acl_conn.peer_lmp_feature_pages[j]).c_str());
- }
- LOG_DUMPSYS(fd, " sniff_subrating:%s",
- common::ToString(HCI_SNIFF_SUB_RATE_SUPPORTED(
- acl_conn.peer_lmp_feature_pages[0]))
- .c_str());
-
- LOG_DUMPSYS(fd, "remote_addr:%s", acl_conn.remote_addr.ToString().c_str());
- LOG_DUMPSYS(fd, " handle:0x%04x", acl_conn.hci_handle);
- LOG_DUMPSYS(fd, " [le] active_remote_addr:%s",
- acl_conn.active_remote_addr.ToString().c_str());
- LOG_DUMPSYS(fd, " [le] conn_addr:%s",
- acl_conn.conn_addr.ToString().c_str());
- LOG_DUMPSYS(fd, " link_up_issued:%s",
- (acl_conn.link_up_issued) ? "true" : "false");
- LOG_DUMPSYS(fd, " transport:%s",
- BtTransportText(acl_conn.transport).c_str());
- LOG_DUMPSYS(fd, " flush_timeout:0x%04x",
- acl_conn.flush_timeout_in_ticks);
- LOG_DUMPSYS(
- fd, " [classic] link_policy:%s",
- link_policy_text(static_cast<tLINK_POLICY>(acl_conn.link_policy))
- .c_str());
+ LOG_DUMPSYS(fd, "remote_addr:%s handle:0x%04x transport:%s",
+ link.remote_addr.ToString().c_str(), link.hci_handle,
+ bt_transport_text(link.transport).c_str());
+ LOG_DUMPSYS(fd, " link_up_issued:%5s",
+ (link.link_up_issued) ? "true" : "false");
+ LOG_DUMPSYS(fd, " flush_timeout:0x%04x", link.flush_timeout_in_ticks);
LOG_DUMPSYS(fd, " link_supervision_timeout:%.3f sec",
- ticks_to_seconds(acl_conn.link_super_tout));
- LOG_DUMPSYS(fd, " pkt_types_mask:0x%04x", acl_conn.pkt_types_mask);
- LOG_DUMPSYS(fd, " disconnect_reason:0x%02x", acl_conn.disconnect_reason);
- LOG_DUMPSYS(fd, " role:%s", RoleText(acl_conn.link_role).c_str());
+ ticks_to_seconds(link.link_super_tout));
+ LOG_DUMPSYS(fd, " disconnect_reason:0x%02x", link.disconnect_reason);
+
+ if (link.is_transport_br_edr()) {
+ for (int j = 0; j < HCI_EXT_FEATURES_PAGE_MAX + 1; j++) {
+ LOG_DUMPSYS(fd, " peer_lmp_features[%d] valid:%s data:%s", j,
+ common::ToString(link.peer_lmp_feature_valid[j]).c_str(),
+ bd_features_text(link.peer_lmp_feature_pages[j]).c_str());
+ }
+ LOG_DUMPSYS(fd, " [classic] link_policy:%s",
+ link_policy_text(static_cast<tLINK_POLICY>(link.link_policy))
+ .c_str());
+ LOG_DUMPSYS(fd, " [classic] sniff_subrating:%s",
+ common::ToString(HCI_SNIFF_SUB_RATE_SUPPORTED(
+ link.peer_lmp_feature_pages[0]))
+ .c_str());
+
+ LOG_DUMPSYS(fd, " pkt_types_mask:0x%04x", link.pkt_types_mask);
+ LOG_DUMPSYS(fd, " role:%s", RoleText(link.link_role).c_str());
+ } else if (link.is_transport_ble()) {
+ LOG_DUMPSYS(fd, " [le] peer_features valid:%s data:%s",
+ common::ToString(link.peer_le_features_valid).c_str(),
+ bd_features_text(link.peer_le_features).c_str());
+
+ LOG_DUMPSYS(fd, " [le] active_remote_addr:%s",
+ link.active_remote_addr.ToString().c_str());
+ LOG_DUMPSYS(fd, " [le] conn_addr:%s",
+ link.conn_addr.ToString().c_str());
+ }
}
}
#undef DUMPSYS_TAG
@@ -906,6 +966,34 @@
using Record = common::TimestampedEntry<std::string>;
const std::string kTimeFormat("%Y-%m-%d %H:%M:%S");
+#define DUMPSYS_TAG "shim::legacy::hid"
+extern btif_hh_cb_t btif_hh_cb;
+
+void DumpsysHid(int fd) {
+ LOG_DUMPSYS_TITLE(fd, DUMPSYS_TAG);
+ LOG_DUMPSYS(fd, "status:%s num_devices:%u",
+ btif_hh_status_text(btif_hh_cb.status).c_str(),
+ btif_hh_cb.device_num);
+ LOG_DUMPSYS(fd, "status:%s", btif_hh_status_text(btif_hh_cb.status).c_str());
+ for (unsigned i = 0; i < BTIF_HH_MAX_HID; i++) {
+ const btif_hh_device_t* p_dev = &btif_hh_cb.devices[i];
+ if (p_dev->bd_addr != RawAddress::kEmpty) {
+ LOG_DUMPSYS(fd, " %u: addr:%s fd:%d state:%s ready:%s thread_id:%d", i,
+ PRIVATE_ADDRESS(p_dev->bd_addr), p_dev->fd,
+ bthh_connection_state_text(p_dev->dev_status).c_str(),
+ (p_dev->ready_for_data) ? ("T") : ("F"),
+ static_cast<int>(p_dev->hh_poll_thread_id));
+ }
+ }
+ for (unsigned i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
+ const btif_hh_added_device_t* p_dev = &btif_hh_cb.added_devices[i];
+ if (p_dev->bd_addr != RawAddress::kEmpty) {
+ LOG_DUMPSYS(fd, " %u: addr:%s", i, PRIVATE_ADDRESS(p_dev->bd_addr));
+ }
+ }
+}
+#undef DUMPSYS_TAG
+
#define DUMPSYS_TAG "shim::legacy::btm"
void DumpsysBtm(int fd) {
LOG_DUMPSYS_TITLE(fd, DUMPSYS_TAG);
@@ -939,13 +1027,13 @@
node = list_next(node)) {
tBTM_SEC_DEV_REC* p_dev_rec =
static_cast<tBTM_SEC_DEV_REC*>(list_node(node));
-
LOG_DUMPSYS(fd, "%03u %s", ++cnt, p_dev_rec->ToString().c_str());
}
}
#undef DUMPSYS_TAG
void shim::legacy::Acl::Dump(int fd) const {
+ DumpsysHid(fd);
DumpsysRecord(fd);
DumpsysAcl(fd);
DumpsysL2cap(fd);
@@ -1055,9 +1143,10 @@
}
void shim::legacy::Acl::AcceptLeConnectionFrom(
- const hci::AddressWithType& address_with_type, std::promise<bool> promise) {
+ const hci::AddressWithType& address_with_type, bool is_direct,
+ std::promise<bool> promise) {
handler_->CallOn(pimpl_.get(), &Acl::impl::accept_le_connection_from,
- address_with_type, std::move(promise));
+ address_with_type, is_direct, std::move(promise));
}
void shim::legacy::Acl::IgnoreLeConnectionFrom(
@@ -1232,6 +1321,10 @@
RawAddress peer_rpa = RawAddress::kEmpty; /* TODO enhanced */
uint8_t peer_addr_type = 0; /* TODO public */
+ // Once an le connection has successfully been established
+ // the device address is removed from the controller accept list.
+ pimpl_->shadow_acceptlist_.Remove(address_with_type);
+
TRY_POSTING_ON_MAIN(
acl_interface_.connection.le.on_connected, legacy_address_with_type,
handle, ToLegacyRole(connection_role), conn_interval, conn_latency,
@@ -1285,38 +1378,14 @@
}
void shim::legacy::Acl::DisconnectClassic(uint16_t handle, tHCI_STATUS reason) {
- auto connection = pimpl_->handle_to_classic_connection_map_.find(handle);
- if (connection != pimpl_->handle_to_classic_connection_map_.end()) {
- auto remote_address = connection->second->GetRemoteAddress();
- connection->second->InitiateDisconnect(
- ToDisconnectReasonFromLegacy(reason));
- LOG_DEBUG("Disconnection initiated classic remote:%s handle:%hu",
- PRIVATE_ADDRESS(remote_address), handle);
- BTM_LogHistory(kBtmLogTag, ToRawAddress(remote_address),
- "Disconnection initiated", "classic");
- } else {
- LOG_WARN("Unable to disconnect unknown classic connection handle:0x%04x",
- handle);
- }
+ handler_->CallOn(pimpl_.get(), &Acl::impl::disconnect_classic, handle,
+ reason);
}
void shim::legacy::Acl::DisconnectLe(uint16_t handle, tHCI_STATUS reason) {
- auto connection = pimpl_->handle_to_le_connection_map_.find(handle);
- if (connection != pimpl_->handle_to_le_connection_map_.end()) {
- auto remote_address_with_type =
- connection->second->GetRemoteAddressWithType();
- connection->second->InitiateDisconnect(
- ToDisconnectReasonFromLegacy(reason));
- LOG_DEBUG("Disconnection initiated le remote:%s handle:%hu",
- PRIVATE_ADDRESS(remote_address_with_type), handle);
- BTM_LogHistory(kBtmLogTag,
- ToLegacyAddressWithType(remote_address_with_type),
- "Disconnection initiated", "Le");
- } else {
- LOG_WARN("Unable to disconnect unknown le connection handle:0x%04x",
- handle);
- }
+ handler_->CallOn(pimpl_.get(), &Acl::impl::disconnect_le, handle, reason);
}
+
bool shim::legacy::Acl::HoldMode(uint16_t hci_handle, uint16_t max_interval,
uint16_t min_interval) {
handler_->CallOn(pimpl_.get(), &Acl::impl::HoldMode, hci_handle, max_interval,
diff --git a/main/shim/acl.h b/main/shim/acl.h
index a5b6c64..bb62b2a 100644
--- a/main/shim/acl.h
+++ b/main/shim/acl.h
@@ -67,6 +67,7 @@
void CreateClassicConnection(const hci::Address& address) override;
void CancelClassicConnection(const hci::Address& address) override;
void AcceptLeConnectionFrom(const hci::AddressWithType& address_with_type,
+ bool is_direct,
std::promise<bool> promise) override;
void IgnoreLeConnectionFrom(
const hci::AddressWithType& address_with_type) override;
diff --git a/main/shim/acl_api.cc b/main/shim/acl_api.cc
index 12b2a18..c105a69 100644
--- a/main/shim/acl_api.cc
+++ b/main/shim/acl_api.cc
@@ -39,11 +39,11 @@
}
bool bluetooth::shim::ACL_AcceptLeConnectionFrom(
- const tBLE_BD_ADDR& legacy_address_with_type) {
+ const tBLE_BD_ADDR& legacy_address_with_type, bool is_direct) {
std::promise<bool> promise;
auto future = promise.get_future();
Stack::GetInstance()->GetAcl()->AcceptLeConnectionFrom(
- ToAddressWithTypeFromLegacy(legacy_address_with_type),
+ ToAddressWithTypeFromLegacy(legacy_address_with_type), is_direct,
std::move(promise));
return future.get();
}
@@ -54,11 +54,12 @@
ToAddressWithTypeFromLegacy(legacy_address_with_type));
}
-void bluetooth::shim::ACL_WriteData(uint16_t handle, const BT_HDR* p_buf) {
- std::unique_ptr<bluetooth::packet::RawBuilder> packet =
- MakeUniquePacket(p_buf->data + p_buf->offset + HCI_DATA_PREAMBLE_SIZE,
- p_buf->len - HCI_DATA_PREAMBLE_SIZE);
+void bluetooth::shim::ACL_WriteData(uint16_t handle, BT_HDR* p_buf) {
+ std::unique_ptr<bluetooth::packet::RawBuilder> packet = MakeUniquePacket(
+ p_buf->data + p_buf->offset + HCI_DATA_PREAMBLE_SIZE,
+ p_buf->len - HCI_DATA_PREAMBLE_SIZE, IsPacketFlushable(p_buf));
Stack::GetInstance()->GetAcl()->WriteData(handle, std::move(packet));
+ osi_free(p_buf);
}
void bluetooth::shim::ACL_ConfigureLePrivacy(bool is_le_privacy_enabled) {
@@ -102,4 +103,4 @@
Stack::GetInstance()->GetAcl()->GetConnectionLocalAddress(pseudo_addr);
conn_addr = ToRawAddress(local_address.GetAddress());
*p_addr_type = static_cast<uint8_t>(local_address.GetAddressType());
-}
\ No newline at end of file
+}
diff --git a/main/shim/acl_api.h b/main/shim/acl_api.h
index 3e9f24b..008f970 100644
--- a/main/shim/acl_api.h
+++ b/main/shim/acl_api.h
@@ -26,11 +26,12 @@
void ACL_CreateClassicConnection(const RawAddress& raw_address);
void ACL_CancelClassicConnection(const RawAddress& raw_address);
-bool ACL_AcceptLeConnectionFrom(const tBLE_BD_ADDR& legacy_address_with_type);
+bool ACL_AcceptLeConnectionFrom(const tBLE_BD_ADDR& legacy_address_with_type,
+ bool is_direct);
void ACL_IgnoreLeConnectionFrom(const tBLE_BD_ADDR& legacy_address_with_type);
void ACL_Disconnect(uint16_t handle, bool is_classic, tHCI_STATUS reason);
-void ACL_WriteData(uint16_t handle, const BT_HDR* p_buf);
+void ACL_WriteData(uint16_t handle, BT_HDR* p_buf);
void ACL_ConfigureLePrivacy(bool is_le_privacy_enabled);
void ACL_Shutdown();
void ACL_IgnoreAllLeConnections();
diff --git a/main/shim/acl_legacy_interface.cc b/main/shim/acl_legacy_interface.cc
index 089e2f8..4c43890 100644
--- a/main/shim/acl_legacy_interface.cc
+++ b/main/shim/acl_legacy_interface.cc
@@ -64,6 +64,8 @@
.link.classic.on_read_link_supervision_timeout_complete = nullptr,
.link.classic.on_read_remote_version_information_complete =
btm_read_remote_version_complete,
+ .link.classic.on_read_remote_supported_features_complete =
+ acl_process_supported_features,
.link.classic.on_read_remote_extended_features_complete =
acl_process_extended_features,
.link.classic.on_read_rssi_complete = nullptr,
diff --git a/main/shim/acl_legacy_interface.h b/main/shim/acl_legacy_interface.h
index 049caa2..85dcbd0 100644
--- a/main/shim/acl_legacy_interface.h
+++ b/main/shim/acl_legacy_interface.h
@@ -91,6 +91,8 @@
void (*on_read_link_quality_complete)(uint8_t link_quality);
void (*on_read_link_supervision_timeout_complete)(
uint16_t link_supervision_timeout);
+ void (*on_read_remote_supported_features_complete)(uint16_t handle,
+ uint64_t features);
void (*on_read_remote_extended_features_complete)(uint16_t handle,
uint8_t current_page_number,
uint8_t max_page_number,
diff --git a/main/shim/activity_attribution.cc b/main/shim/activity_attribution.cc
index 3b07196..5b51fa9 100644
--- a/main/shim/activity_attribution.cc
+++ b/main/shim/activity_attribution.cc
@@ -62,7 +62,7 @@
ActivityAttributionCallbacks::BtaaAggregationEntry entry{
bluetooth::ToRawAddress(it.address),
(ActivityAttributionCallbacks::Activity)it.activity, it.wakeup_count,
- it.byte_count, it.wakelock_duration};
+ it.byte_count, it.wakelock_duration_ms};
callback_logs.push_back(entry);
}
do_in_jni_thread(
diff --git a/main/shim/btm.cc b/main/shim/btm.cc
index b1466b8..c4f6c16 100644
--- a/main/shim/btm.cc
+++ b/main/shim/btm.cc
@@ -107,6 +107,9 @@
const bluetooth::hci::Uuid app_uuid, bluetooth::hci::ScannerId scanner_id,
ScanningStatus status){};
+void Btm::ScanningCallbacks::OnSetScannerParameterComplete(
+ bluetooth::hci::ScannerId scanner_id, ScanningStatus status){};
+
void Btm::ScanningCallbacks::OnScanResult(
uint16_t event_type, uint8_t address_type, bluetooth::hci::Address address,
uint8_t primary_phy, uint8_t secondary_phy, uint8_t advertising_sid,
@@ -130,11 +133,14 @@
advertising_data.size(), &advertising_data[0]);
}
-void Btm::ScanningCallbacks::OnTrackAdvFoundLost(){};
+void Btm::ScanningCallbacks::OnTrackAdvFoundLost(
+ bluetooth::hci::AdvertisingFilterOnFoundOnLostInfo on_found_on_lost_info){};
void Btm::ScanningCallbacks::OnBatchScanReports(int client_if, int status,
int report_format,
int num_records,
std::vector<uint8_t> data){};
+
+void Btm::ScanningCallbacks::OnBatchScanThresholdCrossed(int client_if){};
void Btm::ScanningCallbacks::OnTimeout(){};
void Btm::ScanningCallbacks::OnFilterEnable(bluetooth::hci::Enable enable,
uint8_t status){};
diff --git a/main/shim/btm.h b/main/shim/btm.h
index 9f6f710..05b2f95 100644
--- a/main/shim/btm.h
+++ b/main/shim/btm.h
@@ -68,7 +68,7 @@
static constexpr uint8_t kPhyConnectionLeCoded = 0x03;
using LegacyInquiryCompleteCallback =
- std::function<void(uint16_t status, uint8_t inquiry_mode)>;
+ std::function<void(tBTM_STATUS status, uint8_t inquiry_mode)>;
using DiscoverabilityState = struct {
int mode;
@@ -79,35 +79,11 @@
using HACK_ScoDisconnectCallback = std::function<void(uint16_t, uint8_t)>;
+using BtmStatus = tBTM_STATUS;
+
namespace bluetooth {
namespace shim {
-using BtmStatus = enum : uint8_t {
- BTM_SUCCESS = 0, /* Command succeeded */
- BTM_CMD_STARTED = 1, /* Command started OK. */
- BTM_BUSY = 2, /* Device busy with another command */
- BTM_NO_RESOURCES = 3, /* No resources to issue command */
- BTM_MODE_UNSUPPORTED = 4, /* Request for 1 or more unsupported modes */
- BTM_ILLEGAL_VALUE = 5, /* Illegal parameter value */
- BTM_WRONG_MODE = 6, /* Device in wrong mode for request */
- BTM_UNKNOWN_ADDR = 7, /* Unknown remote BD address */
- BTM_DEVICE_TIMEOUT = 8, /* Device timeout */
- BTM_BAD_VALUE_RET = 9, /* A bad value was received from HCI */
- BTM_ERR_PROCESSING = 10, /* Generic error */
- BTM_NOT_AUTHORIZED = 11, /* Authorization failed */
- BTM_DEV_RESET = 12, /* Device has been reset */
- BTM_CMD_STORED = 13, /* request is stored in control block */
- BTM_ILLEGAL_ACTION = 14, /* state machine gets illegal command */
- BTM_DELAY_CHECK = 15, /* delay the check on encryption */
- BTM_SCO_BAD_LENGTH = 16, /* Bad SCO over HCI data length */
- BTM_SUCCESS_NO_SECURITY = 17, /* security passed, no security set */
- BTM_FAILED_ON_SECURITY = 18, /* security failed */
- BTM_REPEATED_ATTEMPTS = 19, /* repeated attempts for LE security requests */
- BTM_MODE4_LEVEL4_NOT_SUPPORTED = 20, /* Secure Connections Only Mode can't be
- supported */
- BTM_DEV_RESTRICT_LISTED = 21, /* The device is restrict listed */
-};
-
class Btm {
public:
// |handler| is used to run timer tasks and scan callbacks
@@ -239,15 +215,19 @@
void OnScannerRegistered(const bluetooth::hci::Uuid app_uuid,
bluetooth::hci::ScannerId scanner_id,
ScanningStatus status);
+ void OnSetScannerParameterComplete(bluetooth::hci::ScannerId scanner_id,
+ ScanningStatus status);
void OnScanResult(uint16_t event_type, uint8_t address_type,
bluetooth::hci::Address address, uint8_t primary_phy,
uint8_t secondary_phy, uint8_t advertising_sid,
int8_t tx_power, int8_t rssi,
uint16_t periodic_advertising_interval,
std::vector<uint8_t> advertising_data);
- void OnTrackAdvFoundLost();
+ void OnTrackAdvFoundLost(bluetooth::hci::AdvertisingFilterOnFoundOnLostInfo
+ on_found_on_lost_info);
void OnBatchScanReports(int client_if, int status, int report_format,
int num_records, std::vector<uint8_t> data);
+ void OnBatchScanThresholdCrossed(int client_if);
void OnTimeout();
void OnFilterEnable(bluetooth::hci::Enable enable, uint8_t status);
void OnFilterParamSetup(uint8_t available_spaces,
diff --git a/main/shim/btm_api.cc b/main/shim/btm_api.cc
index 556f196..f757664 100644
--- a/main/shim/btm_api.cc
+++ b/main/shim/btm_api.cc
@@ -548,7 +548,7 @@
uint8_t classic_mode = inqparms.mode & 0x0f;
if (!Stack::GetInstance()->GetBtm()->StartInquiry(
classic_mode, inqparms.duration, 0,
- [](uint16_t status, uint8_t inquiry_mode) {
+ [](tBTM_STATUS status, uint8_t inquiry_mode) {
LOG_INFO("%s Inquiry is complete status:%hd inquiry_mode:%hhd",
__func__, status, inquiry_mode);
btm_cb.btm_inq_vars.inqparms.mode &= ~(inquiry_mode);
@@ -877,6 +877,7 @@
tBTM_STATUS bluetooth::shim::BTM_WriteEIR(BT_HDR* p_buff) {
LOG_INFO("UNIMPLEMENTED %s", __func__);
CHECK(p_buff != nullptr);
+ osi_free(p_buff);
return BTM_NO_RESOURCES;
}
diff --git a/main/shim/btm_api.h b/main/shim/btm_api.h
index 58e3bf9..be5521e 100644
--- a/main/shim/btm_api.h
+++ b/main/shim/btm_api.h
@@ -1691,6 +1691,23 @@
/*******************************************************************************
*
+ * Function BTM_GetPeerDeviceTypeFromFeatures
+ *
+ * Description This function is called to retrieve the peer device type
+ * by referencing the remote features.
+ *
+ * Parameters: bd_addr - address of the peer
+ *
+ * Returns BT_DEVICE_TYPE_DUMO if both BR/EDR and BLE transports are
+ * supported by the peer,
+ * BT_DEVICE_TYPE_BREDR if only BR/EDR transport is supported,
+ * BT_DEVICE_TYPE_BLE if only BLE transport is supported.
+ *
+ ******************************************************************************/
+tBT_DEVICE_TYPE BTM_GetPeerDeviceTypeFromFeatures(const RawAddress& bd_addr);
+
+/*******************************************************************************
+ *
* Function BTM_SecReadDevName
*
* Description Looks for the device name in the security database for the
diff --git a/main/shim/controller.cc b/main/shim/controller.cc
index 91dcee4..6cc0897 100644
--- a/main/shim/controller.cc
+++ b/main/shim/controller.cc
@@ -270,6 +270,17 @@
}
}
+static uint16_t get_le_maximum_tx_time(void) {
+ if (gd_rust_is_enabled()) {
+ return bluetooth::shim::rust::controller_get_le_maximum_tx_time(
+ **bluetooth::shim::Stack::GetInstance()->GetRustController());
+ } else {
+ ::bluetooth::hci::LeMaximumDataLength le_maximum_data_length =
+ GetController()->GetLeMaximumDataLength();
+ return le_maximum_data_length.supported_max_tx_time_;
+ }
+}
+
FORWARD_GETTER_IF_RUST(uint16_t, get_le_max_advertising_data_length,
GetController()->GetLeMaximumAdvertisingDataLength())
FORWARD_GETTER_IF_RUST(uint8_t, get_le_supported_advertising_sets,
@@ -362,6 +373,7 @@
get_iso_packet_size,
get_le_suggested_default_data_length,
get_le_maximum_tx_data_length,
+ get_le_maximum_tx_time,
get_le_max_advertising_data_length,
get_le_supported_advertising_sets,
get_le_periodic_advertiser_list_size,
diff --git a/main/shim/dumpsys.cc b/main/shim/dumpsys.cc
index f01baf4..b251caa 100644
--- a/main/shim/dumpsys.cc
+++ b/main/shim/dumpsys.cc
@@ -23,36 +23,41 @@
#include "shim/dumpsys.h"
namespace {
+
constexpr char kModuleName[] = "shim::legacy::dumpsys";
-static std::unordered_map<const void*, bluetooth::shim::DumpsysFunction>*
- dumpsys_functions_{nullptr};
+static std::unordered_map<const void*, bluetooth::shim::DumpsysFunction>
+ dumpsys_functions_;
+
} // namespace
void bluetooth::shim::RegisterDumpsysFunction(const void* token,
DumpsysFunction func) {
- dumpsys_functions_ =
- new std::unordered_map<const void*, bluetooth::shim::DumpsysFunction>();
- CHECK(dumpsys_functions_->find(token) == dumpsys_functions_->end());
- dumpsys_functions_->insert({token, func});
+ CHECK(dumpsys_functions_.find(token) == dumpsys_functions_.end());
+ dumpsys_functions_.insert({token, func});
}
void bluetooth::shim::UnregisterDumpsysFunction(const void* token) {
- CHECK(dumpsys_functions_->find(token) != dumpsys_functions_->end());
- dumpsys_functions_->erase(token);
+ CHECK(dumpsys_functions_.find(token) != dumpsys_functions_.end());
+ dumpsys_functions_.erase(token);
}
void bluetooth::shim::Dump(int fd, const char** args) {
- if (dumpsys_functions_ == nullptr) {
+ if (dumpsys_functions_.empty()) {
dprintf(fd, "%s No registered dumpsys shim legacy targets\n", kModuleName);
} else {
dprintf(fd, "%s Dumping shim legacy targets:%zd\n", kModuleName,
- dumpsys_functions_->size());
- for (auto& dumpsys : *dumpsys_functions_) {
+ dumpsys_functions_.size());
+ for (auto& dumpsys : dumpsys_functions_) {
dumpsys.second(fd);
}
}
if (bluetooth::shim::is_gd_stack_started_up()) {
- bluetooth::shim::GetDumpsys()->Dump(fd, args);
+ if (bluetooth::shim::is_gd_dumpsys_module_started()) {
+ bluetooth::shim::GetDumpsys()->Dump(fd, args);
+ } else {
+ dprintf(fd, "%s NOTE: gd dumpsys module not loaded or started\n",
+ kModuleName);
+ }
} else {
dprintf(fd, "%s gd stack is enabled but not started\n", kModuleName);
}
diff --git a/main/shim/entry.cc b/main/shim/entry.cc
index 3cf49d1..a0d07e3 100644
--- a/main/shim/entry.cc
+++ b/main/shim/entry.cc
@@ -19,6 +19,7 @@
#include "gd/hci/hci_layer.h"
#include "gd/hci/le_advertising_manager.h"
#include "gd/hci/le_scanning_manager.h"
+#include "gd/hci/vendor_specific_event_manager.h"
#include "gd/neighbor/connectability.h"
#include "gd/neighbor/discoverability.h"
#include "gd/neighbor/inquiry.h"
@@ -125,6 +126,12 @@
->GetInstance<hci::AclManager>();
}
+hci::VendorSpecificEventManager* GetVendorSpecificEventManager() {
+ return Stack::GetInstance()
+ ->GetStackManager()
+ ->GetInstance<hci::VendorSpecificEventManager>();
+}
+
activity_attribution::ActivityAttribution* GetActivityAttribution() {
return Stack::GetInstance()
->GetStackManager()
diff --git a/main/shim/entry.h b/main/shim/entry.h
index 1ba72d1..714c95c 100644
--- a/main/shim/entry.h
+++ b/main/shim/entry.h
@@ -29,7 +29,6 @@
* interfaces may be made here
*/
-#include "gd/shim/only_include_this_file_into_legacy_stack___ever.h"
#include "osi/include/future.h"
namespace bluetooth {
@@ -52,6 +51,7 @@
class AclManager;
class LeAdvertisingManager;
class LeScanningManager;
+class VendorSpecificEventManager;
}
namespace l2cap {
@@ -71,6 +71,7 @@
}
namespace shim {
+class Dumpsys;
/* This returns a handler that might be used in shim to receive callbacks from
* within the stack. */
@@ -90,6 +91,7 @@
bluetooth::security::SecurityModule* GetSecurityModule();
storage::StorageModule* GetStorage();
hci::AclManager* GetAclManager();
+hci::VendorSpecificEventManager* GetVendorSpecificEventManager();
activity_attribution::ActivityAttribution* GetActivityAttribution();
} // namespace shim
diff --git a/main/shim/hci_layer.cc b/main/shim/hci_layer.cc
index a45551f..e88ddbc 100644
--- a/main/shim/hci_layer.cc
+++ b/main/shim/hci_layer.cc
@@ -28,6 +28,7 @@
#include "hci/hci_packets.h"
#include "hci/include/packet_fragmenter.h"
#include "hci/le_acl_connection_interface.h"
+#include "hci/vendor_specific_event_manager.h"
#include "main/shim/hci_layer.h"
#include "main/shim/shim.h"
#include "main/shim/stack.h"
@@ -107,8 +108,8 @@
case bluetooth::hci::EventCode::KEYPRESS_NOTIFICATION:
case bluetooth::hci::EventCode::REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION:
case bluetooth::hci::EventCode::NUMBER_OF_COMPLETED_DATA_BLOCKS:
- case bluetooth::hci::EventCode::VENDOR_SPECIFIC:
return true;
+ case bluetooth::hci::EventCode::VENDOR_SPECIFIC:
case bluetooth::hci::EventCode::LE_META_EVENT: // Private to hci
return false;
}
@@ -165,9 +166,12 @@
case bluetooth::hci::EventCode::COMMAND_STATUS:
case bluetooth::hci::EventCode::PAGE_SCAN_REPETITION_MODE_CHANGE:
case bluetooth::hci::EventCode::MAX_SLOTS_CHANGE:
+ case bluetooth::hci::EventCode::LE_META_EVENT:
+ return bluetooth::shim::is_gd_hci_enabled() ||
+ bluetooth::shim::is_gd_acl_enabled() ||
+ bluetooth::shim::is_gd_l2cap_enabled();
case bluetooth::hci::EventCode::DISCONNECTION_COMPLETE:
case bluetooth::hci::EventCode::READ_REMOTE_VERSION_INFORMATION_COMPLETE:
- case bluetooth::hci::EventCode::LE_META_EVENT:
return bluetooth::shim::is_gd_acl_enabled() ||
bluetooth::shim::is_gd_l2cap_enabled();
default:
@@ -292,8 +296,13 @@
bluetooth::common::BidiQueueEnd<bluetooth::hci::AclBuilder,
bluetooth::hci::AclView>* hci_queue_end =
nullptr;
+bluetooth::common::BidiQueueEnd<bluetooth::hci::IsoBuilder,
+ bluetooth::hci::IsoView>* hci_iso_queue_end =
+ nullptr;
static bluetooth::os::EnqueueBuffer<bluetooth::hci::AclBuilder>* pending_data =
nullptr;
+static bluetooth::os::EnqueueBuffer<bluetooth::hci::IsoBuilder>*
+ pending_iso_data = nullptr;
static std::unique_ptr<bluetooth::packet::RawBuilder> MakeUniquePacket(
const uint8_t* data, size_t len) {
@@ -336,12 +345,22 @@
&le_meta_event_view));
}
+static void vendor_specific_event_callback(
+ bluetooth::hci::VendorSpecificEventView vendor_specific_event_view) {
+ if (!send_data_upwards) {
+ return;
+ }
+ send_data_upwards.Run(
+ FROM_HERE,
+ WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_EVT, &vendor_specific_event_view));
+}
+
void OnTransmitPacketCommandComplete(command_complete_cb complete_callback,
void* context,
bluetooth::hci::CommandCompleteView view) {
LOG_DEBUG("Received cmd complete for %s",
bluetooth::hci::OpCodeText(view.GetCommandOpCode()).c_str());
- std::vector<const uint8_t> data(view.begin(), view.end());
+ std::vector<uint8_t> data(view.begin(), view.end());
BT_HDR* response = WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_EVT, &view);
complete_callback(response, context);
}
@@ -413,6 +432,26 @@
bluetooth::shim::GetGdShimHandler());
}
+static void transmit_iso_fragment(const uint8_t* stream, size_t length) {
+ uint16_t handle_with_flags;
+ STREAM_TO_UINT16(handle_with_flags, stream);
+ auto pb_flag = static_cast<bluetooth::hci::IsoPacketBoundaryFlag>(
+ handle_with_flags >> 12 & 0b11);
+ auto ts_flag =
+ static_cast<bluetooth::hci::TimeStampFlag>(handle_with_flags >> 14);
+ uint16_t handle = handle_with_flags & 0xEFF;
+ length -= 2;
+ // skip data total length
+ stream += 2;
+ length -= 2;
+ auto payload = MakeUniquePacket(stream, length);
+ auto iso_packet = bluetooth::hci::IsoBuilder::Create(handle, pb_flag, ts_flag,
+ std::move(payload));
+
+ pending_iso_data->Enqueue(std::move(iso_packet),
+ bluetooth::shim::GetGdShimHandler());
+}
+
static void register_event(bluetooth::hci::EventCode event_code) {
auto handler = bluetooth::shim::GetGdShimHandler();
bluetooth::shim::GetHciLayer()->RegisterEventHandler(
@@ -442,6 +481,23 @@
packet_fragmenter->reassemble_and_dispatch(data);
}
+static void iso_data_callback() {
+ if (hci_iso_queue_end == nullptr) {
+ return;
+ }
+ auto packet = hci_iso_queue_end->TryDequeue();
+ ASSERT(packet != nullptr);
+ if (!packet->IsValid()) {
+ LOG_INFO("Dropping invalid packet of size %zu", packet->size());
+ return;
+ }
+ if (!send_data_upwards) {
+ return;
+ }
+ auto data = WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_ISO, packet.get());
+ packet_fragmenter->reassemble_and_dispatch(data);
+}
+
static void register_for_acl() {
hci_queue_end = bluetooth::shim::GetHciLayer()->GetAclQueueEnd();
@@ -458,12 +514,27 @@
hci_queue_end);
}
+static void register_for_iso() {
+ hci_iso_queue_end = bluetooth::shim::GetHciLayer()->GetIsoQueueEnd();
+ hci_iso_queue_end->RegisterDequeue(
+ bluetooth::shim::GetGdShimHandler(),
+ bluetooth::common::Bind(iso_data_callback));
+ pending_iso_data =
+ new bluetooth::os::EnqueueBuffer<bluetooth::hci::IsoBuilder>(
+ hci_iso_queue_end);
+}
+
static void on_shutting_down() {
if (pending_data != nullptr) {
pending_data->Clear();
delete pending_data;
pending_data = nullptr;
}
+ if (pending_iso_data != nullptr) {
+ pending_iso_data->Clear();
+ delete pending_iso_data;
+ pending_iso_data = nullptr;
+ }
if (hci_queue_end != nullptr) {
if (!bluetooth::shim::is_gd_advertising_enabled() &&
!bluetooth::shim::is_gd_l2cap_enabled()) {
@@ -487,6 +558,11 @@
}
hci_queue_end = nullptr;
}
+
+ if (hci_iso_queue_end != nullptr) {
+ hci_iso_queue_end->UnregisterDequeue();
+ hci_iso_queue_end = nullptr;
+ }
}
} // namespace cpp
@@ -520,6 +596,14 @@
packet_fragmenter->reassemble_and_dispatch(legacy_data);
}
+static void on_iso(::rust::Slice<const uint8_t> data) {
+ if (!send_data_upwards) {
+ return;
+ }
+ auto legacy_data = WrapRustPacketAndCopy(MSG_HC_TO_STACK_HCI_ISO, &data);
+ packet_fragmenter->reassemble_and_dispatch(legacy_data);
+}
+
static void on_event(::rust::Slice<const uint8_t> data) {
if (!send_data_upwards) {
return;
@@ -582,6 +666,12 @@
::rust::Slice(stream, length));
}
+static void transmit_iso_fragment(const uint8_t* stream, size_t length) {
+ bluetooth::shim::rust::hci_send_iso(
+ **bluetooth::shim::Stack::Stack::GetInstance()->GetRustHci(),
+ ::rust::Slice(stream, length));
+}
+
static void register_event(bluetooth::hci::EventCode event_code) {
bluetooth::shim::rust::hci_register_event(
**bluetooth::shim::Stack::GetInstance()->GetRustHci(),
@@ -609,6 +699,12 @@
std::make_unique<u8SliceCallback>(Bind(rust::on_acl)));
}
+static void register_for_iso() {
+ bluetooth::shim::rust::hci_set_iso_callback(
+ **bluetooth::shim::Stack::GetInstance()->GetRustHci(),
+ std::make_unique<u8SliceCallback>(Bind(rust::on_iso)));
+}
+
static void on_shutting_down() {}
} // namespace rust
@@ -648,19 +744,31 @@
}
static void transmit_fragment(BT_HDR* packet, bool send_transmit_finished) {
+ uint16_t event = packet->event & MSG_EVT_MASK;
+
// HCI command packets are freed on a different thread when the matching
// event is received. Check packet->event before sending to avoid a race.
bool free_after_transmit =
- (packet->event & MSG_EVT_MASK) != MSG_STACK_TO_HC_HCI_CMD &&
- send_transmit_finished;
+ event != MSG_STACK_TO_HC_HCI_CMD && send_transmit_finished;
- const uint8_t* stream = packet->data + packet->offset;
- size_t length = packet->len;
- if (bluetooth::common::init_flags::gd_rust_is_enabled()) {
- rust::transmit_fragment(stream, length);
- } else {
- cpp::transmit_fragment(stream, length);
+ if (event == MSG_STACK_TO_HC_HCI_ACL) {
+ const uint8_t* stream = packet->data + packet->offset;
+ size_t length = packet->len;
+ if (bluetooth::common::init_flags::gd_rust_is_enabled()) {
+ rust::transmit_fragment(stream, length);
+ } else {
+ cpp::transmit_fragment(stream, length);
+ }
+ } else if (event == MSG_STACK_TO_HC_HCI_ISO) {
+ const uint8_t* stream = packet->data + packet->offset;
+ size_t length = packet->len;
+ if (bluetooth::common::init_flags::gd_rust_is_enabled()) {
+ rust::transmit_iso_fragment(stream, length);
+ } else {
+ cpp::transmit_iso_fragment(stream, length);
+ }
}
+
if (free_after_transmit) {
osi_free(packet);
}
@@ -755,6 +863,18 @@
}
}
+ // TODO handle BQR event in GD
+ auto handler = bluetooth::shim::GetGdShimHandler();
+ bluetooth::shim::GetVendorSpecificEventManager()->RegisterEventHandler(
+ bluetooth::hci::VseSubeventCode::BQR_EVENT,
+ handler->Bind(cpp::vendor_specific_event_callback));
+
+ if (bluetooth::common::init_flags::gd_rust_is_enabled()) {
+ ::rust::register_for_iso();
+ } else {
+ cpp::register_for_iso();
+ }
+
if (bluetooth::shim::is_gd_acl_enabled()) {
return;
}
diff --git a/main/shim/helpers.h b/main/shim/helpers.h
index 82d83c4..4f94507 100644
--- a/main/shim/helpers.h
+++ b/main/shim/helpers.h
@@ -50,8 +50,8 @@
return ret;
}
-inline hci::AddressWithType ToAddressWithType(const RawAddress& legacy_address,
- tBLE_ADDR_TYPE legacy_type) {
+inline hci::AddressWithType ToAddressWithType(
+ const RawAddress& legacy_address, const tBLE_ADDR_TYPE& legacy_type) {
hci::Address address = ToGdAddress(legacy_address);
hci::AddressType type;
@@ -104,11 +104,12 @@
}
inline std::unique_ptr<bluetooth::packet::RawBuilder> MakeUniquePacket(
- const uint8_t* data, size_t len) {
+ const uint8_t* data, size_t len, bool is_flushable) {
bluetooth::packet::RawBuilder builder;
std::vector<uint8_t> bytes(data, data + len);
auto payload = std::make_unique<bluetooth::packet::RawBuilder>();
payload->AddOctets(bytes);
+ payload->SetFlushable(is_flushable);
return payload;
}
@@ -130,7 +131,7 @@
return to_hci_role(static_cast<uint8_t>(role));
}
-inline hci::Role ToHciRole(hci_role_t role) {
+inline hci::Role ToHciRole(const hci_role_t& role) {
switch (role) {
case HCI_ROLE_CENTRAL:
return hci::Role::CENTRAL;
@@ -141,7 +142,7 @@
}
}
-inline tHCI_STATUS ToLegacyHciErrorCode(hci::ErrorCode reason) {
+inline tHCI_STATUS ToLegacyHciErrorCode(const hci::ErrorCode& reason) {
switch (reason) {
case hci::ErrorCode::SUCCESS:
return HCI_SUCCESS;
@@ -225,19 +226,28 @@
case hci::ErrorCode::CONTROLLER_BUSY:
return static_cast<tHCI_STATUS>(hci::ErrorCode::CONTROLLER_BUSY);
case hci::ErrorCode::CONNECTION_FAILED_ESTABLISHMENT:
- return static_cast<tHCI_STATUS>(
- hci::ErrorCode::CONNECTION_FAILED_ESTABLISHMENT);
+ return HCI_ERR_CONN_FAILED_ESTABLISHMENT;
+ case hci::ErrorCode::STATUS_UNKNOWN:
+ return HCI_ERR_UNDEFINED;
+ default:
+ return static_cast<tHCI_REASON>(reason);
}
}
-inline tHCI_MODE ToLegacyHciMode(hci::Mode mode) {
+inline tHCI_MODE ToLegacyHciMode(const hci::Mode& mode) {
return static_cast<tHCI_MODE>(mode);
}
-inline hci::DisconnectReason ToDisconnectReasonFromLegacy(tHCI_STATUS reason) {
+inline hci::DisconnectReason ToDisconnectReasonFromLegacy(
+ const tHCI_STATUS& reason) {
return static_cast<hci::DisconnectReason>(reason);
}
+inline bool IsPacketFlushable(const BT_HDR* p_buf) {
+ ASSERT(p_buf != nullptr);
+ return ToPacketData<const HciDataPreamble>(p_buf)->IsFlushable();
+}
+
namespace debug {
inline void DumpBtHdr(const BT_HDR* p_buf, const char* token) {
diff --git a/main/shim/l2c_api.cc b/main/shim/l2c_api.cc
index f6b1cc2..3707844 100644
--- a/main/shim/l2c_api.cc
+++ b/main/shim/l2c_api.cc
@@ -60,6 +60,9 @@
namespace {
uint16_t classic_cid_token_counter_ = 0x41;
+constexpr uint64_t kBrEdrNotSupportedMask = 0x0000002000000000; // Bit 37
+constexpr uint64_t kLeSupportedControllerMask = 0x0000004000000000; // Bit 38
+constexpr uint64_t kLeSupportedHostMask = 0x0000000000000002; // Bit 1
std::unordered_map<uint16_t /* token */, uint16_t /* psm */>
classic_cid_token_to_channel_map_;
@@ -225,9 +228,12 @@
static_cast<BT_HDR*>(osi_calloc(packet_vector.size() + sizeof(BT_HDR)));
std::copy(packet_vector.begin(), packet_vector.end(), buffer->data);
buffer->len = packet_vector.size();
- do_in_main_thread(FROM_HERE,
- base::Bind(appl_info_.pL2CA_DataInd_Cb, cid_token,
- base::Unretained(buffer)));
+ if (do_in_main_thread(FROM_HERE,
+ base::Bind(appl_info_.pL2CA_DataInd_Cb, cid_token,
+ base::Unretained(buffer))) !=
+ BT_STATUS_SUCCESS) {
+ osi_free(buffer);
+ }
}
void on_outgoing_connection_fail(
@@ -366,6 +372,9 @@
uint8_t raw_remote_features[8];
bool version_info_received = false;
bool role_switch_supported = false;
+ bool br_edr_supported = false;
+ bool le_supported_controller = false;
+ bool le_supported_host = false;
bool ssp_supported = false;
bool sc_supported = false;
bool received_page_0 = false;
@@ -406,15 +415,21 @@
if (page_number == 0) {
entry.received_page_0 = true;
if (features & 0x20) entry.role_switch_supported = true;
+ entry.br_edr_supported = !(features & kBrEdrNotSupportedMask);
+ entry.le_supported_controller = features & kLeSupportedControllerMask;
std::memcpy(entry.raw_remote_features, &features, 8);
}
if (page_number == 1) {
entry.received_page_1 = true;
if (features & 0x01) entry.ssp_supported = true;
+ entry.le_supported_host = features & kLeSupportedHostMask;
}
if (entry.received_page_0 && entry.received_page_1) {
+ const bool le_supported =
+ entry.le_supported_controller && entry.le_supported_host;
btm_sec_set_peer_sec_caps(address_to_handle_[remote], entry.ssp_supported,
- false, entry.role_switch_supported);
+ false, entry.role_switch_supported,
+ entry.br_edr_supported, le_supported);
}
}
@@ -613,7 +628,7 @@
void Enforce(bluetooth::hci::AddressWithType remote,
bluetooth::l2cap::le::SecurityPolicy policy,
ResultCallback result_callback) override {
- tBTM_BLE_SEC_ACT sec_act = 0;
+ tBTM_BLE_SEC_ACT sec_act = BTM_BLE_SEC_NONE;
switch (policy) {
case bluetooth::l2cap::le::SecurityPolicy::
NO_SECURITY_WHATSOEVER_PLAINTEXT_TRANSPORT_OK:
@@ -762,18 +777,23 @@
uint8_t L2CA_DataWrite(uint16_t cid, BT_HDR* p_data) {
if (classic_cid_token_to_channel_map_.count(cid) == 0) {
LOG(ERROR) << __func__ << "Invalid cid: " << cid;
+ osi_free(p_data);
return 0;
}
auto psm = classic_cid_token_to_channel_map_[cid];
if (classic_dynamic_channel_helper_map_.count(psm) == 0) {
LOG(ERROR) << __func__ << "Not registered psm: " << psm;
+ osi_free(p_data);
return 0;
}
auto len = p_data->len;
auto* data = p_data->data + p_data->offset;
- return classic_dynamic_channel_helper_map_[psm]->send(
- cid, MakeUniquePacket(data, len)) *
- len;
+ uint8_t sent_length =
+ classic_dynamic_channel_helper_map_[psm]->send(
+ cid, MakeUniquePacket(data, len, IsPacketFlushable(p_data))) *
+ len;
+ osi_free(p_data);
+ return sent_length;
}
bool L2CA_ReconfigCreditBasedConnsReq(const RawAddress& bd_addr,
@@ -1000,12 +1020,16 @@
BT_HDR* p_buf) {
if (cid != kAttCid && cid != kSmpCid) {
LOG(ERROR) << "Invalid cid " << cid;
+ osi_free(p_buf);
return L2CAP_DW_FAILED;
}
auto* helper = &le_fixed_channel_helper_.find(cid)->second;
auto len = p_buf->len;
auto* data = p_buf->data + p_buf->offset;
- bool sent = helper->send(ToGdAddress(rem_bda), MakeUniquePacket(data, len));
+ bool sent =
+ helper->send(ToGdAddress(rem_bda),
+ MakeUniquePacket(data, len, IsPacketFlushable(p_buf)));
+ osi_free(p_buf);
return sent ? L2CAP_DW_SUCCESS : L2CAP_DW_FAILED;
}
@@ -1392,9 +1416,12 @@
static_cast<BT_HDR*>(osi_calloc(packet_vector.size() + sizeof(BT_HDR)));
std::copy(packet_vector.begin(), packet_vector.end(), buffer->data);
buffer->len = packet_vector.size();
- do_in_main_thread(FROM_HERE,
- base::Bind(appl_info_.pL2CA_DataInd_Cb, cid_token,
- base::Unretained(buffer)));
+ if (do_in_main_thread(FROM_HERE,
+ base::Bind(appl_info_.pL2CA_DataInd_Cb, cid_token,
+ base::Unretained(buffer))) !=
+ BT_STATUS_SUCCESS) {
+ osi_free(buffer);
+ }
}
void on_outgoing_connection_fail(
@@ -1540,18 +1567,23 @@
uint8_t L2CA_LECocDataWrite(uint16_t cid, BT_HDR* p_data) {
if (le_cid_token_to_channel_map_.count(cid) == 0) {
LOG(ERROR) << __func__ << "Invalid cid: " << cid;
+ osi_free(p_data);
return 0;
}
auto psm = le_cid_token_to_channel_map_[cid];
if (le_dynamic_channel_helper_map_.count(psm) == 0) {
LOG(ERROR) << __func__ << "Not registered psm: " << psm;
- return false;
+ osi_free(p_data);
+ return 0;
}
auto len = p_data->len;
auto* data = p_data->data + p_data->offset;
- return le_dynamic_channel_helper_map_[psm]->send(
- cid, MakeUniquePacket(data, len)) *
- len;
+ uint8_t sent_length =
+ le_dynamic_channel_helper_map_[psm]->send(
+ cid, MakeUniquePacket(data, len, IsPacketFlushable(p_data))) *
+ len;
+ osi_free(p_data);
+ return sent_length;
}
void L2CA_SwitchRoleToCentral(const RawAddress& addr) {
diff --git a/main/shim/le_scanning_manager.cc b/main/shim/le_scanning_manager.cc
index b8a4304..13023bd 100644
--- a/main/shim/le_scanning_manager.cc
+++ b/main/shim/le_scanning_manager.cc
@@ -32,6 +32,7 @@
#include "gd/storage/storage_module.h"
#include "main/shim/entry.h"
#include "main/shim/helpers.h"
+#include "main/shim/shim.h"
#include "advertise_data_parser.h"
#include "stack/btm/btm_int_types.h"
@@ -55,6 +56,7 @@
~BleScannerInterfaceImpl() override{};
void Init() {
+ LOG_INFO("init BleScannerInterfaceImpl");
bluetooth::shim::GetScanning()->RegisterScanningCallback(this);
}
@@ -90,7 +92,7 @@
if (filt_param != nullptr) {
if (filt_param && filt_param->dely_mode == 1) {
- // TODO refactor BTM_BleTrackAdvertiser
+ bluetooth::shim::GetScanning()->TrackAdvertiser(client_if);
}
advertising_filter_parameter.feature_selection = filt_param->feat_seln;
advertising_filter_parameter.list_logic_type =
@@ -117,7 +119,8 @@
bluetooth::shim::GetScanning()->ScanFilterParameterSetup(
apcf_action, filter_index, advertising_filter_parameter);
// TODO refactor callback mechanism
- do_in_jni_thread(FROM_HERE, base::Bind(cb, 0, 0, 0));
+ do_in_jni_thread(FROM_HERE,
+ base::Bind(cb, 0, 0, btm_status_value(BTM_SUCCESS)));
}
/** Configure a scan filter condition */
@@ -135,7 +138,8 @@
new_filters.push_back(command);
}
bluetooth::shim::GetScanning()->ScanFilterAdd(filter_index, new_filters);
- do_in_jni_thread(FROM_HERE, base::Bind(cb, 0, 0, 0, 0));
+ do_in_jni_thread(FROM_HERE,
+ base::Bind(cb, 0, 0, 0, btm_status_value(BTM_SUCCESS)));
}
/** Clear all scan filter conditions for specific filter index*/
@@ -150,17 +154,18 @@
bluetooth::shim::GetScanning()->ScanFilterEnable(enable);
uint8_t action = enable ? 1 : 0;
- do_in_jni_thread(FROM_HERE, base::Bind(cb, action, 0));
+ do_in_jni_thread(FROM_HERE,
+ base::Bind(cb, action, btm_status_value(BTM_SUCCESS)));
}
/** Sets the LE scan interval and window in units of N*0.625 msec */
- void SetScanParameters(int scan_interval, int scan_window, Callback cb) {
+ void SetScanParameters(int scanner_id, int scan_interval, int scan_window,
+ Callback cb) {
LOG(INFO) << __func__ << " in shim layer";
// use active scan
auto scan_type = static_cast<bluetooth::hci::LeScanType>(0x01);
- bluetooth::shim::GetScanning()->SetScanParameters(scan_type, scan_interval,
- scan_window);
- do_in_jni_thread(FROM_HERE, base::Bind(cb, 0));
+ bluetooth::shim::GetScanning()->SetScanParameters(
+ scanner_id, scan_type, scan_interval, scan_window);
}
/* Configure the batchscan storage */
@@ -168,6 +173,10 @@
int batch_scan_trunc_max,
int batch_scan_notify_threshold, Callback cb) {
LOG(INFO) << __func__ << " in shim layer";
+ bluetooth::shim::GetScanning()->BatchScanConifgStorage(
+ batch_scan_full_max, batch_scan_trunc_max, batch_scan_notify_threshold,
+ client_if);
+ do_in_jni_thread(FROM_HERE, base::Bind(cb, btm_status_value(BTM_SUCCESS)));
}
/* Enable batchscan */
@@ -175,16 +184,30 @@
int scan_window, int addr_type, int discard_rule,
Callback cb) {
LOG(INFO) << __func__ << " in shim layer";
+ auto batch_scan_mode =
+ static_cast<bluetooth::hci::BatchScanMode>(scan_mode);
+ auto batch_scan_discard_rule =
+ static_cast<bluetooth::hci::BatchScanDiscardRule>(discard_rule);
+ bluetooth::shim::GetScanning()->BatchScanEnable(
+ batch_scan_mode, scan_window, scan_interval, batch_scan_discard_rule);
+ do_in_jni_thread(FROM_HERE, base::Bind(cb, btm_status_value(BTM_SUCCESS)));
}
/* Disable batchscan */
virtual void BatchscanDisable(Callback cb) {
LOG(INFO) << __func__ << " in shim layer";
+ bluetooth::shim::GetScanning()->BatchScanDisable();
+ do_in_jni_thread(FROM_HERE, base::Bind(cb, btm_status_value(BTM_SUCCESS)));
}
/* Read out batchscan reports */
void BatchscanReadReports(int client_if, int scan_mode) {
LOG(INFO) << __func__ << " in shim layer";
+ auto batch_scan_mode =
+ static_cast<bluetooth::hci::BatchScanMode>(scan_mode);
+ auto scanner_id = static_cast<bluetooth::hci::ScannerId>(client_if);
+ bluetooth::shim::GetScanning()->BatchScanReadReport(scanner_id,
+ batch_scan_mode);
}
void StartSync(uint8_t sid, RawAddress address, uint16_t skip,
@@ -214,6 +237,14 @@
scanner_id, status));
}
+ void OnSetScannerParameterComplete(bluetooth::hci::ScannerId scanner_id,
+ ScanningStatus status) {
+ do_in_jni_thread(
+ FROM_HERE,
+ base::Bind(&ScanningCallbacks::OnSetScannerParameterComplete,
+ base::Unretained(scanning_callbacks_), scanner_id, status));
+ }
+
void OnScanResult(uint16_t event_type, uint8_t address_type,
bluetooth::hci::Address address, uint8_t primary_phy,
uint8_t secondary_phy, uint8_t advertising_sid,
@@ -243,10 +274,58 @@
advertising_data);
}
- void OnTrackAdvFoundLost() {}
+ void OnTrackAdvFoundLost(bluetooth::hci::AdvertisingFilterOnFoundOnLostInfo
+ on_found_on_lost_info) {
+ AdvertisingTrackInfo track_info = {};
+ RawAddress raw_address =
+ ToRawAddress(on_found_on_lost_info.advertiser_address);
+ track_info.advertiser_address = raw_address;
+ track_info.advertiser_address_type =
+ on_found_on_lost_info.advertiser_address_type;
+ track_info.scanner_id = on_found_on_lost_info.scanner_id;
+ track_info.filter_index = on_found_on_lost_info.filter_index;
+ track_info.advertiser_state = on_found_on_lost_info.advertiser_state;
+ track_info.advertiser_info_present =
+ static_cast<uint8_t>(on_found_on_lost_info.advertiser_info_present);
+ if (on_found_on_lost_info.advertiser_info_present ==
+ bluetooth::hci::AdvtInfoPresent::ADVT_INFO_PRESENT) {
+ track_info.tx_power = on_found_on_lost_info.tx_power;
+ track_info.rssi = on_found_on_lost_info.rssi;
+ track_info.time_stamp = on_found_on_lost_info.time_stamp;
+ auto adv_data = on_found_on_lost_info.adv_packet;
+ track_info.adv_packet_len = (uint8_t)adv_data.size();
+ track_info.adv_packet.reserve(adv_data.size());
+ track_info.adv_packet.insert(track_info.adv_packet.end(),
+ adv_data.begin(), adv_data.end());
+ auto scan_rsp_data = on_found_on_lost_info.scan_response;
+ track_info.scan_response_len = (uint8_t)scan_rsp_data.size();
+ track_info.scan_response.reserve(adv_data.size());
+ track_info.scan_response.insert(track_info.scan_response.end(),
+ scan_rsp_data.begin(),
+ scan_rsp_data.end());
+ }
+ do_in_jni_thread(
+ FROM_HERE,
+ base::BindOnce(&ScanningCallbacks::OnTrackAdvFoundLost,
+ base::Unretained(scanning_callbacks_), track_info));
+ }
void OnBatchScanReports(int client_if, int status, int report_format,
- int num_records, std::vector<uint8_t> data) {}
+ int num_records, std::vector<uint8_t> data) {
+ do_in_jni_thread(
+ FROM_HERE,
+ base::BindOnce(&ScanningCallbacks::OnBatchScanReports,
+ base::Unretained(scanning_callbacks_), client_if, status,
+ report_format, num_records, data));
+ }
+
+ void OnBatchScanThresholdCrossed(int client_if) {
+ do_in_jni_thread(
+ FROM_HERE,
+ base::BindOnce(&ScanningCallbacks::OnBatchScanThresholdCrossed,
+ base::Unretained(scanning_callbacks_), client_if));
+ }
+
void OnTimeout() {}
void OnFilterEnable(bluetooth::hci::Enable enable, uint8_t status){};
@@ -380,7 +459,10 @@
}
}
}
-
+ if (!bluetooth::shim::is_gd_stack_started_up()) {
+ LOG_WARN("Gd stack is stopped, return");
+ return;
+ }
auto* storage_module = bluetooth::shim::GetStorage();
bluetooth::hci::Address address = ToGdAddress(bd_addr);
@@ -436,4 +518,4 @@
void bluetooth::shim::init_scanning_manager() {
bt_le_scanner_instance->Init();
-}
\ No newline at end of file
+}
diff --git a/main/shim/link_connection_interface.h b/main/shim/link_connection_interface.h
index 1c140b6..f38f9e2 100644
--- a/main/shim/link_connection_interface.h
+++ b/main/shim/link_connection_interface.h
@@ -35,7 +35,7 @@
virtual void CancelClassicConnection(
const bluetooth::hci::Address& address) = 0;
virtual void AcceptLeConnectionFrom(
- const bluetooth::hci::AddressWithType& address_with_type,
+ const bluetooth::hci::AddressWithType& address_with_type, bool is_direct,
std::promise<bool>) = 0;
virtual void IgnoreLeConnectionFrom(
const bluetooth::hci::AddressWithType& address_with_type) = 0;
diff --git a/main/shim/link_policy.cc b/main/shim/link_policy.cc
index fc26073..048fee5 100644
--- a/main/shim/link_policy.cc
+++ b/main/shim/link_policy.cc
@@ -34,9 +34,6 @@
#include "stack/include/hci_error_code.h"
#include "stack/include/hcidefs.h"
-void btsnd_hcic_switch_role(const RawAddress& bd_addr,
- uint8_t role); // TODO remove
-
bt_status_t do_in_main_thread(const base::Location& from_here,
base::OnceClosure task);
diff --git a/main/shim/metric_id_api.h b/main/shim/metric_id_api.h
index e1645e7..c8726ea 100644
--- a/main/shim/metric_id_api.h
+++ b/main/shim/metric_id_api.h
@@ -16,6 +16,7 @@
#pragma once
+#include <functional>
#include <unordered_map>
#include "types/raw_address.h"
diff --git a/main/shim/metrics_api.cc b/main/shim/metrics_api.cc
index 2c33f07..2660e23 100644
--- a/main/shim/metrics_api.cc
+++ b/main/shim/metrics_api.cc
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-#include "gd/common/metrics.h"
-#include "gd/hci/address.h"
-#include "main/shim/helpers.h"
#include "main/shim/metrics_api.h"
+#include "gd/hci/address.h"
+#include "gd/os/metrics.h"
+#include "main/shim/helpers.h"
#include "types/raw_address.h"
using bluetooth::hci::Address;
@@ -33,7 +33,7 @@
if (raw_address != nullptr) {
address = bluetooth::ToGdAddress(*raw_address);
}
- bluetooth::common::LogMetricLinkLayerConnectionEvent(
+ bluetooth::os::LogMetricLinkLayerConnectionEvent(
raw_address == nullptr ? nullptr : &address, connection_handle, direction,
link_type, hci_cmd, hci_event, hci_ble_event, cmd_status, reason_code);
}
@@ -42,7 +42,7 @@
uint64_t encoding_interval_millis,
int num_missing_pcm_bytes) {
Address address = bluetooth::ToGdAddress(raw_address);
- bluetooth::common::LogMetricA2dpAudioUnderrunEvent(
+ bluetooth::os::LogMetricA2dpAudioUnderrunEvent(
address, encoding_interval_millis, num_missing_pcm_bytes);
}
@@ -52,7 +52,7 @@
int num_dropped_encoded_frames,
int num_dropped_encoded_bytes) {
Address address = bluetooth::ToGdAddress(raw_address);
- bluetooth::common::LogMetricA2dpAudioOverrunEvent(
+ bluetooth::os::LogMetricA2dpAudioOverrunEvent(
address, encoding_interval_millis, num_dropped_buffers,
num_dropped_encoded_frames, num_dropped_encoded_bytes);
}
@@ -60,14 +60,14 @@
void LogMetricA2dpPlaybackEvent(const RawAddress& raw_address,
int playback_state, int audio_coding_mode) {
Address address = bluetooth::ToGdAddress(raw_address);
- bluetooth::common::LogMetricA2dpPlaybackEvent(address, playback_state,
- audio_coding_mode);
+ bluetooth::os::LogMetricA2dpPlaybackEvent(address, playback_state,
+ audio_coding_mode);
}
void LogMetricReadRssiResult(const RawAddress& raw_address, uint16_t handle,
uint32_t cmd_status, int8_t rssi) {
Address address = bluetooth::ToGdAddress(raw_address);
- bluetooth::common::LogMetricReadRssiResult(address, handle, cmd_status, rssi);
+ bluetooth::os::LogMetricReadRssiResult(address, handle, cmd_status, rssi);
}
void LogMetricReadFailedContactCounterResult(const RawAddress& raw_address,
@@ -75,7 +75,7 @@
uint32_t cmd_status,
int32_t failed_contact_counter) {
Address address = bluetooth::ToGdAddress(raw_address);
- bluetooth::common::LogMetricReadFailedContactCounterResult(
+ bluetooth::os::LogMetricReadFailedContactCounterResult(
address, handle, cmd_status, failed_contact_counter);
}
@@ -83,16 +83,16 @@
uint16_t handle, uint32_t cmd_status,
int32_t transmit_power_level) {
Address address = bluetooth::ToGdAddress(raw_address);
- bluetooth::common::LogMetricReadTxPowerLevelResult(address, handle, cmd_status,
- transmit_power_level);
+ bluetooth::os::LogMetricReadTxPowerLevelResult(address, handle, cmd_status,
+ transmit_power_level);
}
void LogMetricSmpPairingEvent(const RawAddress& raw_address, uint8_t smp_cmd,
android::bluetooth::DirectionEnum direction,
uint8_t smp_fail_reason) {
Address address = bluetooth::ToGdAddress(raw_address);
- bluetooth::common::LogMetricSmpPairingEvent(address, smp_cmd, direction,
- smp_fail_reason);
+ bluetooth::os::LogMetricSmpPairingEvent(address, smp_cmd, direction,
+ smp_fail_reason);
}
void LogMetricClassicPairingEvent(const RawAddress& raw_address,
@@ -100,17 +100,17 @@
uint16_t hci_event, uint16_t cmd_status,
uint16_t reason_code, int64_t event_value) {
Address address = bluetooth::ToGdAddress(raw_address);
- bluetooth::common::LogMetricClassicPairingEvent(address, handle, hci_cmd,
- hci_event, cmd_status, reason_code,
- event_value);
+ bluetooth::os::LogMetricClassicPairingEvent(address, handle, hci_cmd,
+ hci_event, cmd_status,
+ reason_code, event_value);
}
void LogMetricSdpAttribute(const RawAddress& raw_address,
uint16_t protocol_uuid, uint16_t attribute_id,
size_t attribute_size, const char* attribute_value) {
Address address = bluetooth::ToGdAddress(raw_address);
- bluetooth::common::LogMetricSdpAttribute(address, protocol_uuid, attribute_id,
- attribute_size, attribute_value);
+ bluetooth::os::LogMetricSdpAttribute(address, protocol_uuid, attribute_id,
+ attribute_size, attribute_value);
}
void LogMetricSocketConnectionState(
@@ -119,8 +119,9 @@
int64_t tx_bytes, int64_t rx_bytes, int uid, int server_port,
android::bluetooth::SocketRoleEnum socket_role) {
Address address = bluetooth::ToGdAddress(raw_address);
- bluetooth::common::LogMetricSocketConnectionState(
- address, port, type, connection_state, tx_bytes, rx_bytes, uid, server_port, socket_role);
+ bluetooth::os::LogMetricSocketConnectionState(
+ address, port, type, connection_state, tx_bytes, rx_bytes, uid,
+ server_port, socket_role);
}
void LogMetricManufacturerInfo(
@@ -130,9 +131,9 @@
const std::string& model, const std::string& hardware_version,
const std::string& software_version) {
Address address = bluetooth::ToGdAddress(raw_address);
- bluetooth::common::LogMetricManufacturerInfo(address, source_type, source_name,
- manufacturer, model, hardware_version,
- software_version);
+ bluetooth::os::LogMetricManufacturerInfo(address, source_type, source_name,
+ manufacturer, model,
+ hardware_version, software_version);
}
} // namespace shim
} // namespace bluetooth
\ No newline at end of file
diff --git a/main/shim/shim.cc b/main/shim/shim.cc
index 090de6f..f89d6e1 100644
--- a/main/shim/shim.cc
+++ b/main/shim/shim.cc
@@ -98,6 +98,10 @@
return bluetooth::shim::Stack::GetInstance()->IsRunning();
}
+bool bluetooth::shim::is_gd_dumpsys_module_started() {
+ return bluetooth::shim::Stack::GetInstance()->IsDumpsysModuleStarted();
+}
+
bool bluetooth::shim::is_gd_btaa_enabled() {
return bluetooth::common::init_flags::btaa_hci_is_enabled();
}
diff --git a/main/shim/shim.h b/main/shim/shim.h
index 2510017..dd993c0 100644
--- a/main/shim/shim.h
+++ b/main/shim/shim.h
@@ -64,5 +64,12 @@
*/
bool is_gd_stack_started_up();
+/**
+ * Checks if the dumpsys module has been started.
+ *
+ * @return true if specified module has started, false otherwise.
+ */
+bool is_gd_dumpsys_module_started();
+
} // namespace shim
} // namespace bluetooth
diff --git a/main/shim/stack.cc b/main/shim/stack.cc
index 9337a67..e4cd6fd 100644
--- a/main/shim/stack.cc
+++ b/main/shim/stack.cc
@@ -27,6 +27,7 @@
#include "gd/hci/hci_layer.h"
#include "gd/hci/le_advertising_manager.h"
#include "gd/hci/le_scanning_manager.h"
+#include "gd/hci/vendor_specific_event_manager.h"
#include "gd/l2cap/classic/l2cap_classic_module.h"
#include "gd/l2cap/le/l2cap_le_module.h"
#include "gd/neighbor/connectability.h"
@@ -98,6 +99,7 @@
modules.add<hci::HciLayer>();
modules.add<storage::StorageModule>();
modules.add<shim::Dumpsys>();
+ modules.add<hci::VendorSpecificEventManager>();
}
if (common::init_flags::gd_controller_is_enabled()) {
modules.add<hci::Controller>();
@@ -232,6 +234,12 @@
return &stack_manager_;
}
+const StackManager* Stack::GetStackManager() const {
+ std::lock_guard<std::recursive_mutex> lock(mutex_);
+ ASSERT(is_running_);
+ return &stack_manager_;
+}
+
legacy::Acl* Stack::GetAcl() {
std::lock_guard<std::recursive_mutex> lock(mutex_);
ASSERT(is_running_);
@@ -258,5 +266,10 @@
return stack_handler_;
}
+bool Stack::IsDumpsysModuleStarted() const {
+ std::lock_guard<std::recursive_mutex> lock(mutex_);
+ return GetStackManager()->IsStarted<Dumpsys>();
+}
+
} // namespace shim
} // namespace bluetooth
diff --git a/main/shim/stack.h b/main/shim/stack.h
index 948d13b..b105866 100644
--- a/main/shim/stack.h
+++ b/main/shim/stack.h
@@ -48,8 +48,11 @@
void Stop();
bool IsRunning();
+ bool IsDumpsysModuleStarted() const;
StackManager* GetStackManager();
+ const StackManager* GetStackManager() const;
+
legacy::Acl* GetAcl();
LinkPolicyInterface* LinkPolicy();
@@ -64,7 +67,7 @@
DISALLOW_COPY_AND_ASSIGN(Stack);
private:
- std::recursive_mutex mutex_;
+ mutable std::recursive_mutex mutex_;
StackManager stack_manager_;
bool is_running_ = false;
os::Thread* stack_thread_ = nullptr;
diff --git a/main/stack_config.cc b/main/stack_config.cc
index c6dbe4d..de40cdf 100644
--- a/main/stack_config.cc
+++ b/main/stack_config.cc
@@ -41,7 +41,9 @@
static future_t* init() {
// TODO(armansito): Find a better way than searching by a hardcoded path.
-#if defined(OS_GENERIC)
+#if defined(TARGET_FLOSS)
+ const char* path = "/var/lib/bluetooth/bt_stack.conf";
+#elif defined(OS_GENERIC)
const char* path = "bt_stack.conf";
#else // !defined(OS_GENERIC)
const char* path = "/etc/bluetooth/bt_stack.conf";
diff --git a/main/test/common/mock_activity_attribution.cc b/main/test/common/mock_activity_attribution.cc
deleted file mode 100644
index 49dc396..0000000
--- a/main/test/common/mock_activity_attribution.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 "btif/include/btif_activity_attribution.h"
-#include "main/shim/activity_attribution.h"
-#include "main/shim/shim.h"
-
-ActivityAttributionInterface*
-bluetooth::activity_attribution::get_activity_attribution_instance() {
- return nullptr;
-}
-
-ActivityAttributionInterface*
-bluetooth::shim::get_activity_attribution_instance() {
- return nullptr;
-}
-
-const bluetooth::ModuleFactory
- bluetooth::activity_attribution::ActivityAttribution::Factory =
- bluetooth::ModuleFactory([]() { return nullptr; });
diff --git a/main/test/common/mock_bta_dm_act.cc b/main/test/common/mock_bta_dm_act.cc
deleted file mode 100644
index 227641a..0000000
--- a/main/test/common/mock_bta_dm_act.cc
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:53
- */
-
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-#include "bta/dm/bta_dm_int.h"
-#include "types/raw_address.h"
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-void BTA_dm_acl_down(const RawAddress bd_addr, tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
-}
-void BTA_dm_acl_up(const RawAddress bd_addr, tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
-}
-void BTA_dm_notify_remote_features_complete(const RawAddress bd_addr) {
- mock_function_count_map[__func__]++;
-}
-
-void BTA_dm_on_hw_off() { mock_function_count_map[__func__]++; }
-void BTA_dm_on_hw_on() { mock_function_count_map[__func__]++; }
-void BTA_dm_report_role_change(const RawAddress bd_addr, uint8_t new_role,
- tHCI_STATUS hci_status) {
- mock_function_count_map[__func__]++;
-}
-void bta_dm_add_device(std::unique_ptr<tBTA_DM_API_ADD_DEVICE> msg) {
- mock_function_count_map[__func__]++;
-}
-void bta_dm_bond(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type,
- tBT_TRANSPORT transport, int device_type) {
- mock_function_count_map[__func__]++;
-}
-void bta_dm_bond_cancel(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
-}
-void bta_dm_ci_rmt_oob_act(std::unique_ptr<tBTA_DM_CI_RMT_OOB> msg) {
- mock_function_count_map[__func__]++;
-}
-void bta_dm_close_acl(const RawAddress& bd_addr, bool remove_dev,
- tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
-}
-void bta_dm_confirm(const RawAddress& bd_addr, bool accept) {
- mock_function_count_map[__func__]++;
-}
-void bta_dm_deinit_cb(void) { mock_function_count_map[__func__]++; }
-void bta_dm_disable() { mock_function_count_map[__func__]++; }
-void bta_dm_disc_result(tBTA_DM_MSG* p_data) {
- mock_function_count_map[__func__]++;
-}
-void bta_dm_disc_rmt_name(tBTA_DM_MSG* p_data) {
- mock_function_count_map[__func__]++;
-}
-void bta_dm_discover(tBTA_DM_MSG* p_data) {
- mock_function_count_map[__func__]++;
-}
-void bta_dm_free_sdp_db() { mock_function_count_map[__func__]++; }
-void bta_dm_init_cb(void) { mock_function_count_map[__func__]++; }
-void bta_dm_inq_cmpl(uint8_t num) { mock_function_count_map[__func__]++; }
-void bta_dm_pin_reply(std::unique_ptr<tBTA_DM_API_PIN_REPLY> msg) {
- mock_function_count_map[__func__]++;
-}
-void bta_dm_process_remove_device(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
-}
-void bta_dm_queue_disc(tBTA_DM_MSG* p_data) {
- mock_function_count_map[__func__]++;
-}
-void bta_dm_queue_search(tBTA_DM_MSG* p_data) {
- mock_function_count_map[__func__]++;
-}
-void bta_dm_remove_device(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
-}
-void bta_dm_rmt_name(tBTA_DM_MSG* p_data) {
- mock_function_count_map[__func__]++;
-}
-void bta_dm_sdp_result(tBTA_DM_MSG* p_data) {
- mock_function_count_map[__func__]++;
-}
-void bta_dm_search_cancel() { mock_function_count_map[__func__]++; }
-void bta_dm_search_cancel_cmpl() { mock_function_count_map[__func__]++; }
-void bta_dm_search_cancel_notify() { mock_function_count_map[__func__]++; }
-void bta_dm_search_clear_queue() { mock_function_count_map[__func__]++; }
-void bta_dm_search_cmpl() { mock_function_count_map[__func__]++; }
-void bta_dm_search_result(tBTA_DM_MSG* p_data) {
- mock_function_count_map[__func__]++;
-}
-void bta_dm_search_start(tBTA_DM_MSG* p_data) {
- mock_function_count_map[__func__]++;
-}
-void bta_dm_set_dev_name(const std::vector<uint8_t>& name) {
- mock_function_count_map[__func__]++;
-}
diff --git a/main/test/common/mock_btm_ble_gap.cc b/main/test/common/mock_btm_ble_gap.cc
deleted file mode 100644
index 22e18a6..0000000
--- a/main/test/common/mock_btm_ble_gap.cc
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:47
- */
-
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-#include <base/bind.h>
-#include <base/strings/string_number_conversions.h>
-#include <cstdint>
-#include <list>
-#include <memory>
-#include <vector>
-#include "common/time_util.h"
-#include "device/include/controller.h"
-#include "main/shim/acl_api.h"
-#include "main/shim/btm_api.h"
-#include "main/shim/shim.h"
-#include "osi/include/log.h"
-#include "stack/btm/btm_ble_int.h"
-#include "stack/btm/btm_ble_int_types.h"
-#include "stack/btm/btm_dev.h"
-#include "stack/btm/btm_int_types.h"
-#include "stack/gatt/gatt_int.h"
-#include "stack/include/acl_api.h"
-#include "stack/include/advertise_data_parser.h"
-#include "stack/include/bt_types.h"
-#include "stack/include/btm_api_types.h"
-#include "stack/include/gap_api.h"
-#include "stack/include/hci_error_code.h"
-#include "stack/include/hcimsgs.h"
-#include "stack/include/inq_hci_link_interface.h"
-#include "types/raw_address.h"
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-bool BTM_BleConfigPrivacy(bool privacy_mode) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_BleLocalPrivacyEnabled(void) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool btm_ble_cancel_remote_name(const RawAddress& remote_bda) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool btm_ble_clear_topology_mask(tBTM_BLE_STATE_MASK request_state_mask) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool btm_ble_set_topology_mask(tBTM_BLE_STATE_MASK request_state_mask) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool btm_ble_topology_check(tBTM_BLE_STATE_MASK request_state_mask) {
- mock_function_count_map[__func__]++;
- return false;
-}
-tBTM_STATUS BTM_BleObserve(bool start, uint8_t duration,
- tBTM_INQ_RESULTS_CB* p_results_cb,
- tBTM_CMPL_CB* p_cmpl_cb) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS btm_ble_read_remote_name(const RawAddress& remote_bda,
- tBTM_CMPL_CB* p_cb) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS btm_ble_set_connectability(uint16_t combined_mode) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS btm_ble_set_discoverability(uint16_t combined_mode) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS btm_ble_start_adv(void) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS btm_ble_start_inquiry(uint8_t duration) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS btm_ble_stop_adv(void) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-uint16_t BTM_BleReadConnectability() {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint16_t BTM_BleReadDiscoverability() {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint8_t BTM_BleMaxMultiAdvInstanceCount(void) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-void BTM_BleGetDynamicAudioBuffer(
- tBTM_BT_DYNAMIC_AUDIO_BUFFER_CB p_dynamic_audio_buffer_cb[]) {
- mock_function_count_map[__func__]++;
-}
-void BTM_BleGetVendorCapabilities(tBTM_BLE_VSC_CB* p_cmn_vsc_cb) {
- mock_function_count_map[__func__]++;
-}
-void BTM_BleSetScanParams(uint32_t scan_interval, uint32_t scan_window,
- tBLE_SCAN_MODE scan_mode,
- base::Callback<void(uint8_t)> cb) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_decrement_link_topology_mask(uint8_t link_role) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_dir_adv_tout(void) { mock_function_count_map[__func__]++; }
-void btm_ble_free() { mock_function_count_map[__func__]++; }
-void btm_ble_increment_link_topology_mask(uint8_t link_role) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_init(void) { mock_function_count_map[__func__]++; }
-void btm_ble_process_adv_addr(RawAddress& bda, uint8_t* addr_type) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_process_adv_pkt(uint8_t data_len, uint8_t* data) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_process_adv_pkt_cont(uint16_t evt_type, uint8_t addr_type,
- const RawAddress& bda, uint8_t primary_phy,
- uint8_t secondary_phy,
- uint8_t advertising_sid, int8_t tx_power,
- int8_t rssi, uint16_t periodic_adv_int,
- uint8_t data_len, uint8_t* data) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_process_adv_pkt_cont_for_inquiry(
- uint16_t evt_type, uint8_t addr_type, const RawAddress& bda,
- uint8_t primary_phy, uint8_t secondary_phy, uint8_t advertising_sid,
- int8_t tx_power, int8_t rssi, uint16_t periodic_adv_int,
- std::vector<uint8_t> advertising_data) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_process_ext_adv_pkt(uint8_t data_len, uint8_t* data) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_process_phy_update_pkt(uint8_t len, uint8_t* data) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_read_remote_features_complete(uint8_t* p) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_read_remote_name_cmpl(bool status, const RawAddress& bda,
- uint16_t length, char* p_name) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_set_adv_flag(uint16_t connect_mode, uint16_t disc_mode) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_start_scan() { mock_function_count_map[__func__]++; }
-void btm_ble_stop_inquiry(void) { mock_function_count_map[__func__]++; }
-void btm_ble_stop_scan(void) { mock_function_count_map[__func__]++; }
-void btm_ble_update_dmt_flag_bits(uint8_t* adv_flag_value,
- const uint16_t connect_mode,
- const uint16_t disc_mode) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_update_inq_result(tINQ_DB_ENT* p_i, uint8_t addr_type,
- const RawAddress& bda, uint16_t evt_type,
- uint8_t primary_phy, uint8_t secondary_phy,
- uint8_t advertising_sid, int8_t tx_power,
- int8_t rssi, uint16_t periodic_adv_int,
- std::vector<uint8_t> const& data) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_update_mode_operation(uint8_t link_role, const RawAddress* bd_addr,
- tHCI_STATUS status) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_write_adv_enable_complete(uint8_t* p) {
- mock_function_count_map[__func__]++;
-}
-void btm_clear_all_pending_le_entry(void) {
- mock_function_count_map[__func__]++;
-}
-void btm_send_hci_set_scan_params(uint8_t scan_type, uint16_t scan_int,
- uint16_t scan_win, uint8_t addr_type_own,
- uint8_t scan_filter_policy) {
- mock_function_count_map[__func__]++;
-}
diff --git a/main/test/common/mock_btm_dev.cc b/main/test/common/mock_btm_dev.cc
deleted file mode 100644
index 85e8b10..0000000
--- a/main/test/common/mock_btm_dev.cc
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:16
- */
-
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "bt_common.h"
-#include "bt_types.h"
-#include "btm_api.h"
-#include "btu.h"
-#include "device/include/controller.h"
-#include "hcidefs.h"
-#include "hcimsgs.h"
-#include "l2c_api.h"
-#include "main/shim/btm_api.h"
-#include "main/shim/shim.h"
-#include "stack/btm/btm_dev.h"
-#include "stack/include/acl_api.h"
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-bool BTM_SecAddDevice(const RawAddress& bd_addr, DEV_CLASS dev_class,
- BD_NAME bd_name, uint8_t* features, LinkKey* p_link_key,
- uint8_t key_type, uint8_t pin_length) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_SecDeleteDevice(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool btm_dev_support_role_switch(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool btm_set_bond_type_dev(const RawAddress& bd_addr,
- tBTM_SEC_DEV_REC::tBTM_BOND_TYPE bond_type) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool is_address_equal(void* data, void* context) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool is_handle_equal(void* data, void* context) {
- mock_function_count_map[__func__]++;
- return false;
-}
-char* BTM_SecReadDevName(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return nullptr;
-}
-tBTM_SEC_DEV_REC* btm_find_dev(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return nullptr;
-}
-tBTM_SEC_DEV_REC* btm_find_dev_by_handle(uint16_t handle) {
- mock_function_count_map[__func__]++;
- return nullptr;
-}
-tBTM_SEC_DEV_REC* btm_find_or_alloc_dev(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return nullptr;
-}
-tBTM_SEC_DEV_REC* btm_sec_alloc_dev(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return nullptr;
-}
-tBTM_SEC_DEV_REC* btm_sec_allocate_dev_rec(void) {
- mock_function_count_map[__func__]++;
- return nullptr;
-}
-tBTM_SEC_DEV_REC::tBTM_BOND_TYPE btm_get_bond_type_dev(
- const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return tBTM_SEC_DEV_REC::BOND_TYPE_UNKNOWN;
-}
-void BTM_SecClearSecurityFlags(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
-}
-void btm_consolidate_dev(tBTM_SEC_DEV_REC* p_target_rec) {
- mock_function_count_map[__func__]++;
-}
-void wipe_secrets_and_remove(tBTM_SEC_DEV_REC* p_dev_rec) {
- mock_function_count_map[__func__]++;
-}
diff --git a/main/test/common/mock_btm_main.cc b/main/test/common/mock_btm_main.cc
deleted file mode 100644
index e614cc3..0000000
--- a/main/test/common/mock_btm_main.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:7
- */
-
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-#include <memory>
-#include <string>
-#include "bt_target.h"
-#include "bt_types.h"
-#include "main/shim/dumpsys.h"
-#include "stack/btm/btm_int_types.h"
-#include "stack/include/btm_client_interface.h"
-#include "stack_config.h"
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-void BTM_LogHistory(const std::string& tag, const RawAddress& bd_addr,
- const std::string& msg) {
- mock_function_count_map[__func__]++;
-}
-void BTM_LogHistory(const std::string& tag, const RawAddress& bd_addr,
- const std::string& msg, const std::string& extra) {
- mock_function_count_map[__func__]++;
-}
-void BTM_LogHistory(const std::string& tag, const tBLE_BD_ADDR& ble_bd_addr,
- const std::string& msg) {
- mock_function_count_map[__func__]++;
-}
-void BTM_LogHistory(const std::string& tag, const tBLE_BD_ADDR& ble_bd_addr,
- const std::string& msg, const std::string& extra) {
- mock_function_count_map[__func__]++;
-}
-void btm_free(void) { mock_function_count_map[__func__]++; }
-void btm_init(void) { mock_function_count_map[__func__]++; }
diff --git a/main/test/common/mock_btm_sec.cc b/main/test/common/mock_btm_sec.cc
deleted file mode 100644
index 763fdfe..0000000
--- a/main/test/common/mock_btm_sec.cc
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:66
- */
-
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-#include <base/strings/stringprintf.h>
-#include <frameworks/proto_logging/stats/enums/bluetooth/enums.pb.h>
-#include <frameworks/proto_logging/stats/enums/bluetooth/hci/enums.pb.h>
-#include <string.h>
-#include "bt_types.h"
-#include "btif/include/btif_storage.h"
-#include "common/metrics.h"
-#include "common/time_util.h"
-#include "device/include/controller.h"
-#include "hcimsgs.h"
-#include "l2c_api.h"
-#include "main/shim/btm_api.h"
-#include "main/shim/dumpsys.h"
-#include "main/shim/shim.h"
-#include "osi/include/log.h"
-#include "osi/include/osi.h"
-#include "stack/btm/btm_dev.h"
-#include "stack/btm/btm_sec.h"
-#include "stack/include/acl_api.h"
-#include "stack/include/acl_hci_link_interface.h"
-#include "stack/include/btm_status.h"
-#include "stack/include/l2cap_security_interface.h"
-#include "stack/smp/smp_int.h"
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-bool BTM_BothEndsSupportSecureConnections(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_GetSecurityFlags(const RawAddress& bd_addr, uint8_t* p_sec_flags) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_GetSecurityFlagsByTransport(const RawAddress& bd_addr,
- uint8_t* p_sec_flags,
- tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_IsAuthenticated(const RawAddress& bd_addr, tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_IsEncrypted(const RawAddress& bd_addr, tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_IsLinkKeyAuthed(const RawAddress& bd_addr, tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_IsLinkKeyKnown(const RawAddress& bd_addr, tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_PeerSupportsSecureConnections(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_SecAddRmtNameNotifyCallback(tBTM_RMT_NAME_CALLBACK* p_callback) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_SecDeleteRmtNameNotifyCallback(tBTM_RMT_NAME_CALLBACK* p_callback) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_SecIsSecurityPending(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_SecRegister(const tBTM_APPL_INFO* p_cb_info) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_SetSecurityLevel(bool is_originator, const char* p_name,
- uint8_t service_id, uint16_t sec_level, uint16_t psm,
- uint32_t mx_proto_id, uint32_t mx_chan_id) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool btm_sec_is_a_bonded_dev(const RawAddress& bda) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool is_sec_state_equal(void* data, void* context) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool is_state_getting_name(void* data, void* context) {
- mock_function_count_map[__func__]++;
- return false;
-}
-const uint8_t* btm_get_dev_class(const RawAddress& bda) {
- mock_function_count_map[__func__]++;
- return nullptr;
-}
-tBTM_LINK_KEY_TYPE BTM_SecGetDeviceLinkKeyType(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-tBTM_SEC_DEV_REC* btm_sec_find_dev_by_sec_state(uint8_t state) {
- mock_function_count_map[__func__]++;
- return nullptr;
-}
-tBTM_SEC_SERV_REC* btm_sec_find_first_serv(bool is_originator, uint16_t psm) {
- mock_function_count_map[__func__]++;
- return nullptr;
-}
-tBTM_STATUS BTM_SecBond(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type,
- tBT_TRANSPORT transport, int device_type,
- uint8_t pin_len, uint8_t* p_pin) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_SecBondCancel(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_SetEncryption(const RawAddress& bd_addr,
- tBT_TRANSPORT transport,
- tBTM_SEC_CALLBACK* p_callback, void* p_ref_data,
- tBTM_BLE_SEC_ACT sec_act) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS btm_sec_bond_by_transport(const RawAddress& bd_addr,
- tBT_TRANSPORT transport, uint8_t pin_len,
- uint8_t* p_pin) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS btm_sec_disconnect(uint16_t handle, tHCI_STATUS reason) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS btm_sec_execute_procedure(tBTM_SEC_DEV_REC* p_dev_rec) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS btm_sec_l2cap_access_req(const RawAddress& bd_addr, uint16_t psm,
- bool is_originator,
- tBTM_SEC_CALLBACK* p_callback,
- void* p_ref_data) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS btm_sec_l2cap_access_req_by_requirement(
- const RawAddress& bd_addr, uint16_t security_required, bool is_originator,
- tBTM_SEC_CALLBACK* p_callback, void* p_ref_data) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS btm_sec_mx_access_request(const RawAddress& bd_addr,
- bool is_originator,
- uint16_t security_required,
- tBTM_SEC_CALLBACK* p_callback,
- void* p_ref_data) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-uint16_t BTM_GetClockOffset(const RawAddress& remote_bda) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint8_t BTM_SecClrService(uint8_t service_id) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint8_t BTM_SecClrServiceByPsm(uint16_t psm) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-void BTM_ConfirmReqReply(tBTM_STATUS res, const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
-}
-void BTM_PINCodeReply(const RawAddress& bd_addr, uint8_t res, uint8_t pin_len,
- uint8_t* p_pin) {
- mock_function_count_map[__func__]++;
-}
-void BTM_PasskeyReqReply(tBTM_STATUS res, const RawAddress& bd_addr,
- uint32_t passkey) {
- mock_function_count_map[__func__]++;
-}
-void BTM_ReadLocalOobData(void) { mock_function_count_map[__func__]++; }
-void BTM_RemoteOobDataReply(tBTM_STATUS res, const RawAddress& bd_addr,
- const Octet16& c, const Octet16& r) {
- mock_function_count_map[__func__]++;
-}
-void BTM_SetPinType(uint8_t pin_type, PIN_CODE pin_code, uint8_t pin_code_len) {
- mock_function_count_map[__func__]++;
-}
-void NotifyBondingCanceled(tBTM_STATUS btm_status) {
- mock_function_count_map[__func__]++;
-}
-void btm_create_conn_cancel_complete(uint8_t* p) {
- mock_function_count_map[__func__]++;
-}
-void btm_io_capabilities_req(const RawAddress& p) {
- mock_function_count_map[__func__]++;
-}
-void btm_io_capabilities_rsp(uint8_t* p) {
- mock_function_count_map[__func__]++;
-}
-void btm_proc_sp_req_evt(tBTM_SP_EVT event, uint8_t* p) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_local_oob_complete(uint8_t* p) {
- mock_function_count_map[__func__]++;
-}
-void btm_rem_oob_req(uint8_t* p) { mock_function_count_map[__func__]++; }
-void btm_sec_abort_access_req(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_auth_complete(uint16_t handle, tHCI_STATUS status) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_check_pending_reqs(void) { mock_function_count_map[__func__]++; }
-void btm_sec_clear_ble_keys(tBTM_SEC_DEV_REC* p_dev_rec) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_conn_req(const RawAddress& bda, uint8_t* dc) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_connected(const RawAddress& bda, uint16_t handle,
- tHCI_STATUS status, uint8_t enc_mode) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_dev_rec_cback_event(tBTM_SEC_DEV_REC* p_dev_rec,
- tBTM_STATUS btm_status, bool is_le_transport) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_dev_reset(void) { mock_function_count_map[__func__]++; }
-void btm_sec_disconnected(uint16_t handle, tHCI_REASON reason) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_encrypt_change(uint16_t handle, tHCI_STATUS status,
- uint8_t encr_enable) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_link_key_notification(const RawAddress& p_bda,
- const Octet16& link_key, uint8_t key_type) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_link_key_request(uint8_t* p_event) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_pin_code_request(uint8_t* p_event) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_rmt_host_support_feat_evt(uint8_t* p) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_rmt_name_request_complete(const RawAddress* p_bd_addr,
- uint8_t* p_bd_name, tHCI_STATUS status) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_set_peer_sec_caps(uint16_t hci_handle, bool ssp_supported,
- bool sc_supported,
- bool hci_role_switch_supported) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_update_clock_offset(uint16_t handle, uint16_t clock_offset) {
- mock_function_count_map[__func__]++;
-}
-void btm_simple_pair_complete(uint8_t* p) {
- mock_function_count_map[__func__]++;
-}
diff --git a/main/test/common/mock_btu_task.cc b/main/test/common/mock_btu_task.cc
deleted file mode 100644
index 672fd8c..0000000
--- a/main/test/common/mock_btu_task.cc
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:7
- */
-
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-#include <base/bind.h>
-#include <base/logging.h>
-#include <base/run_loop.h>
-#include <base/threading/thread.h>
-#include <pthread.h>
-#include <stdio.h>
-#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 "btm_iso_api.h"
-#include "common/message_loop_thread.h"
-#include "osi/include/log.h"
-#include "osi/include/osi.h"
-#include "stack/include/acl_hci_link_interface.h"
-#include "stack/include/btu.h"
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-bluetooth::common::MessageLoopThread* get_main_thread() {
- mock_function_count_map[__func__]++;
- return nullptr;
-}
-bt_status_t do_in_main_thread(const base::Location& from_here,
- base::OnceClosure task) {
- mock_function_count_map[__func__]++;
- return BT_STATUS_SUCCESS;
-}
-bt_status_t do_in_main_thread_delayed(const base::Location& from_here,
- base::OnceClosure task,
- const base::TimeDelta& delay) {
- mock_function_count_map[__func__]++;
- return BT_STATUS_SUCCESS;
-}
-void btu_hci_msg_process(BT_HDR* p_msg) { mock_function_count_map[__func__]++; }
-void main_thread_shut_down() { mock_function_count_map[__func__]++; }
-void main_thread_start_up() { mock_function_count_map[__func__]++; }
-void post_on_bt_main(std::function<void()> closure) {
- mock_function_count_map[__func__]++;
-}
diff --git a/main/test/common/mock_gatt_main.cc b/main/test/common/mock_gatt_main.cc
deleted file mode 100644
index 4756039..0000000
--- a/main/test/common/mock_gatt_main.cc
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:23
- */
-
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-#include "bt_common.h"
-#include "bt_target.h"
-#include "device/include/interop.h"
-#include "l2c_api.h"
-#include "osi/include/osi.h"
-#include "stack/btm/btm_ble_int.h"
-#include "stack/btm/btm_dev.h"
-#include "stack/btm/btm_sec.h"
-#include "stack/gatt/gatt_int.h"
-#include "stack/include/l2cap_acl_interface.h"
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-bool gatt_act_connect(tGATT_REG* p_reg, const RawAddress& bd_addr,
- tBT_TRANSPORT transport, int8_t initiating_phys) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool gatt_connect(const RawAddress& rem_bda, tGATT_TCB* p_tcb,
- tBT_TRANSPORT transport, uint8_t initiating_phys,
- tGATT_IF gatt_if) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool gatt_disconnect(tGATT_TCB* p_tcb) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool gatt_update_app_hold_link_status(tGATT_IF gatt_if, tGATT_TCB* p_tcb,
- bool is_add) {
- mock_function_count_map[__func__]++;
- return false;
-}
-tGATT_CH_STATE gatt_get_ch_state(tGATT_TCB* p_tcb) {
- mock_function_count_map[__func__]++;
- return GATT_CH_CLOSE;
-}
-void gatt_add_a_bonded_dev_for_srv_chg(const RawAddress& bda) {
- mock_function_count_map[__func__]++;
-}
-void gatt_chk_srv_chg(tGATTS_SRV_CHG* p_srv_chg_clt) {
- mock_function_count_map[__func__]++;
-}
-void gatt_data_process(tGATT_TCB& tcb, uint16_t cid, BT_HDR* p_buf) {
- mock_function_count_map[__func__]++;
-}
-void gatt_find_in_device_record(const RawAddress& bd_addr,
- tBLE_BD_ADDR* address_with_type) {
- mock_function_count_map[__func__]++;
-}
-void gatt_free(void) { mock_function_count_map[__func__]++; }
-void gatt_init(void) { mock_function_count_map[__func__]++; }
-void gatt_init_srv_chg(void) { mock_function_count_map[__func__]++; }
-void gatt_l2cif_config_cfm_cback(uint16_t lcid, uint16_t initiator,
- tL2CAP_CFG_INFO* p_cfg) {
- mock_function_count_map[__func__]++;
-}
-void gatt_l2cif_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
- mock_function_count_map[__func__]++;
-}
-void gatt_l2cif_disconnect_ind_cback(uint16_t lcid, bool ack_needed) {
- mock_function_count_map[__func__]++;
-}
-void gatt_notify_conn_update(const RawAddress&, uint16_t interval,
- uint16_t latency, uint16_t timeout,
- tHCI_STATUS status) {
- mock_function_count_map[__func__]++;
-}
-void gatt_notify_phy_updated(tGATT_STATUS status, uint16_t handle,
- uint8_t tx_phy, uint8_t rx_phy) {
- mock_function_count_map[__func__]++;
-}
-void gatt_proc_srv_chg(void) { mock_function_count_map[__func__]++; }
-void gatt_send_srv_chg_ind(const RawAddress& peer_bda) {
- mock_function_count_map[__func__]++;
-}
-void gatt_set_ch_state(tGATT_TCB* p_tcb, tGATT_CH_STATE ch_state) {
- mock_function_count_map[__func__]++;
-}
-void gatt_update_app_use_link_flag(tGATT_IF gatt_if, tGATT_TCB* p_tcb,
- bool is_add, bool check_acl_link) {
- mock_function_count_map[__func__]++;
-}
diff --git a/main/test/common/mock_l2cap_l2c_ble.cc b/main/test/common/mock_l2cap_l2c_ble.cc
deleted file mode 100644
index 44ae6e2..0000000
--- a/main/test/common/mock_l2cap_l2c_ble.cc
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:26
- */
-
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-#include <base/logging.h>
-#include "bt_target.h"
-#include "device/include/controller.h"
-#include "hcimsgs.h"
-#include "main/shim/shim.h"
-#include "osi/include/log.h"
-#include "osi/include/osi.h"
-#include "stack/btm/btm_dev.h"
-#include "stack/btm/btm_sec.h"
-#include "stack/include/acl_api.h"
-#include "stack/include/l2c_api.h"
-#include "stack/include/l2cdefs.h"
-#include "stack/l2cap/l2c_int.h"
-#include "stack_config.h"
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-bool L2CA_EnableUpdateBleConnParams(const RawAddress& rem_bda, bool enable) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_UpdateBleConnParams(const RawAddress& rem_bda, uint16_t min_int,
- uint16_t max_int, uint16_t latency,
- uint16_t timeout) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_UpdateBleConnParams(const RawAddress& rem_bda, uint16_t min_int,
- uint16_t max_int, uint16_t latency,
- uint16_t timeout, uint16_t min_ce_len,
- uint16_t max_ce_len) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool 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) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool l2cble_conn_comp_from_address_with_type(
- uint16_t handle, uint8_t role, const tBLE_BD_ADDR& address_with_type,
- uint16_t conn_interval, uint16_t conn_latency, uint16_t conn_timeout) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool l2cble_create_conn(tL2C_LCB* p_lcb) {
- mock_function_count_map[__func__]++;
- return false;
-}
-hci_role_t L2CA_GetBleConnRole(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return HCI_ROLE_CENTRAL;
-}
-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) {
- mock_function_count_map[__func__]++;
- return L2CAP_LE_RESULT_CONN_OK;
-}
-uint16_t L2CA_GetDisconnectReason(const RawAddress& remote_bda,
- tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-void L2CA_AdjustConnectionIntervals(uint16_t* min_interval,
- uint16_t* max_interval,
- uint16_t floor_interval) {
- mock_function_count_map[__func__]++;
-}
-void L2CA_SetLeFixedChannelTxDataLength(const RawAddress& remote_bda,
- uint16_t fix_cid, uint16_t tx_mtu) {
- mock_function_count_map[__func__]++;
-}
-void l2c_ble_link_adjust_allocation(void) {
- mock_function_count_map[__func__]++;
-}
-void l2c_link_processs_ble_num_bufs(uint16_t num_lm_ble_bufs) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_credit_based_conn_req(tL2C_CCB* p_ccb) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_credit_based_conn_res(tL2C_CCB* p_ccb, uint16_t result) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_notify_le_connection(const RawAddress& bda) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_process_conn_update_evt(uint16_t handle, uint8_t status,
- uint16_t interval, uint16_t latency,
- uint16_t timeout) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_process_data_length_change_event(uint16_t handle,
- uint16_t tx_data_len,
- uint16_t rx_data_len) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_sec_comp(const RawAddress* bda, tBT_TRANSPORT transport,
- void* p_ref_data, uint8_t status) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_send_flow_control_credit(tL2C_CCB* p_ccb, uint16_t credit_value) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_send_peer_disc_req(tL2C_CCB* p_ccb) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_set_fixed_channel_tx_data_length(const RawAddress& remote_bda,
- uint16_t fix_cid,
- uint16_t tx_mtu) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_update_data_length(tL2C_LCB* p_lcb) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_use_preferred_conn_params(const RawAddress& bda) {
- mock_function_count_map[__func__]++;
-}
diff --git a/main/test/common/mock_stack_acl.cc b/main/test/common/mock_stack_acl.cc
deleted file mode 100644
index 4f02cfb..0000000
--- a/main/test/common/mock_stack_acl.cc
+++ /dev/null
@@ -1,439 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:127
- */
-
-#include <cstdint>
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-#include "stack/acl/acl.h"
-#include "stack/include/acl_api.h"
-#include "stack/include/hci_error_code.h"
-#include "types/bt_transport.h"
-#include "types/raw_address.h"
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-bool IsEprAvailable(const tACL_CONN& p_acl) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool ACL_SupportTransparentSynchronousData(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_BLE_IS_RESOLVE_BDA(const RawAddress& x) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_IsAclConnectionUp(const RawAddress& remote_bda,
- tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_IsAclConnectionUpAndHandleValid(const RawAddress& remote_bda,
- tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_IsAclConnectionUpFromHandle(uint16_t hci_handle) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_IsBleConnection(uint16_t hci_handle) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_ReadRemoteConnectionAddr(const RawAddress& pseudo_addr,
- RawAddress& conn_addr,
- tBLE_ADDR_TYPE* p_addr_type) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_ReadRemoteVersion(const RawAddress& addr, uint8_t* lmp_version,
- uint16_t* manufacturer, uint16_t* lmp_sub_version) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool acl_create_le_connection(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool acl_create_le_connection_with_id(uint8_t id, const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool acl_is_role_switch_allowed() {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool acl_is_switch_role_idle(const RawAddress& bd_addr,
- tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool acl_peer_supports_ble_2m_phy(uint16_t hci_handle) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool acl_peer_supports_ble_coded_phy(uint16_t hci_handle) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool acl_peer_supports_ble_connection_parameters_request(
- const RawAddress& remote_bda) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool acl_peer_supports_ble_packet_extension(uint16_t hci_handle) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool acl_peer_supports_sniff_subrating(const RawAddress& remote_bda) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool acl_refresh_remote_address(const RawAddress& identity_address,
- tBLE_ADDR_TYPE identity_address_type,
- const RawAddress& bda, tBLE_ADDR_TYPE rra_type,
- const RawAddress& rpa) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool acl_set_peer_le_features_from_handle(uint16_t hci_handle,
- const uint8_t* p) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool sco_peer_supports_esco_2m_phy(const RawAddress& remote_bda) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool sco_peer_supports_esco_3m_phy(const RawAddress& remote_bda) {
- mock_function_count_map[__func__]++;
- return false;
-}
-const RawAddress acl_address_from_handle(uint16_t handle) {
- mock_function_count_map[__func__]++;
- return RawAddress::kEmpty;
-}
-void acl_send_data_packet_br_edr([[maybe_unused]] const RawAddress& bd_addr,
- BT_HDR* p_buf) {
- mock_function_count_map[__func__]++;
-}
-void acl_create_classic_connection(const RawAddress& bd_addr,
- bool there_are_high_priority_channels,
- bool is_bonding) {
- mock_function_count_map[__func__]++;
-}
-tACL_CONN* acl_get_connection_from_address(const RawAddress& bd_addr,
- tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return nullptr;
-}
-tACL_CONN* acl_get_connection_from_handle(uint16_t handle) {
- mock_function_count_map[__func__]++;
- return nullptr;
-}
-tBTM_STATUS BTM_GetLinkSuperTout(const RawAddress& remote_bda,
- uint16_t* p_timeout) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_GetRole(const RawAddress& remote_bd_addr, tHCI_ROLE* p_role) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_ReadFailedContactCounter(const RawAddress& remote_bda,
- tBTM_CMPL_CB* p_cb) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_ReadRSSI(const RawAddress& remote_bda, tBTM_CMPL_CB* p_cb) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_ReadTxPower(const RawAddress& remote_bda,
- tBT_TRANSPORT transport, tBTM_CMPL_CB* p_cb) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_SetLinkSuperTout(const RawAddress& remote_bda,
- uint16_t timeout) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_SwitchRoleToCentral(const RawAddress& remote_bd_addr) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS btm_remove_acl(const RawAddress& bd_addr, tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-uint16_t BTM_GetHCIConnHandle(const RawAddress& remote_bda,
- tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint16_t BTM_GetMaxPacketSize(const RawAddress& addr) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint16_t mock_stack_acl_num_links = 0;
-uint16_t BTM_GetNumAclLinks(void) {
- mock_function_count_map[__func__]++;
- return mock_stack_acl_num_links;
-}
-uint16_t acl_get_supported_packet_types() {
- mock_function_count_map[__func__]++;
- return 0;
-}
-tHCI_REASON btm_get_acl_disc_reason_code(void) {
- mock_function_count_map[__func__]++;
- return HCI_SUCCESS;
-}
-uint8_t BTM_SetTraceLevel(uint8_t new_level) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint8_t acl_link_role_from_handle(uint16_t handle) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint8_t btm_handle_to_acl_index(uint16_t hci_handle) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint8_t* BTM_ReadRemoteFeatures(const RawAddress& addr) {
- mock_function_count_map[__func__]++;
- return nullptr;
-}
-void ACL_RegisterClient(struct acl_client_callback_s* callbacks) {
- mock_function_count_map[__func__]++;
-}
-void ACL_UnregisterClient(struct acl_client_callback_s* callbacks) {
- mock_function_count_map[__func__]++;
-}
-void BTM_ReadConnectionAddr(const RawAddress& remote_bda,
- RawAddress& local_conn_addr,
- tBLE_ADDR_TYPE* p_addr_type) {
- mock_function_count_map[__func__]++;
-}
-void BTM_acl_after_controller_started(const controller_t* controller) {
- mock_function_count_map[__func__]++;
-}
-void BTM_block_role_switch_for(const RawAddress& peer_addr) {
- mock_function_count_map[__func__]++;
-}
-void BTM_block_sniff_mode_for(const RawAddress& peer_addr) {
- mock_function_count_map[__func__]++;
-}
-void BTM_default_block_role_switch() { mock_function_count_map[__func__]++; }
-void BTM_default_unblock_role_switch() { mock_function_count_map[__func__]++; }
-void BTM_unblock_role_switch_for(const RawAddress& peer_addr) {
- mock_function_count_map[__func__]++;
-}
-void BTM_unblock_sniff_mode_for(const RawAddress& peer_addr) {
- mock_function_count_map[__func__]++;
-}
-void acl_accept_connection_request(const RawAddress& bd_addr, uint8_t role) {
- mock_function_count_map[__func__]++;
-}
-void acl_disconnect_after_role_switch(uint16_t conn_handle,
- tHCI_STATUS reason) {
- mock_function_count_map[__func__]++;
-}
-void acl_disconnect_from_handle(uint16_t handle, tHCI_STATUS reason) {
- mock_function_count_map[__func__]++;
-}
-void acl_link_segments_xmitted(BT_HDR* p_msg) {
- mock_function_count_map[__func__]++;
-}
-void acl_packets_completed(uint16_t handle, uint16_t credits) {
- mock_function_count_map[__func__]++;
-}
-void acl_process_extended_features(uint16_t handle, uint8_t current_page_number,
- uint8_t max_page_number, uint64_t features) {
- mock_function_count_map[__func__]++;
-}
-void acl_process_num_completed_pkts(uint8_t* p, uint8_t evt_len) {
- mock_function_count_map[__func__]++;
-}
-void acl_rcv_acl_data(BT_HDR* p_msg) { mock_function_count_map[__func__]++; }
-void acl_reject_connection_request(const RawAddress& bd_addr, uint8_t reason) {
- mock_function_count_map[__func__]++;
-}
-void acl_send_data_packet_ble(const RawAddress& bd_addr, BT_HDR* p_buf) {
- mock_function_count_map[__func__]++;
-}
-void acl_set_disconnect_reason(tHCI_STATUS acl_disc_reason) {
- mock_function_count_map[__func__]++;
-}
-void acl_write_automatic_flush_timeout(const RawAddress& bd_addr,
- uint16_t flush_timeout_in_ticks) {
- mock_function_count_map[__func__]++;
-}
-void btm_acl_chk_peer_pkt_type_support(tACL_CONN* p, uint16_t* p_pkt_type) {
- mock_function_count_map[__func__]++;
-}
-void btm_acl_connected(const RawAddress& bda, uint16_t handle,
- tHCI_STATUS status, uint8_t enc_mode) {
- mock_function_count_map[__func__]++;
-}
-void btm_acl_connection_request(const RawAddress& bda, uint8_t* dc) {
- mock_function_count_map[__func__]++;
-}
-void btm_acl_created(const RawAddress& bda, uint16_t hci_handle,
- tHCI_ROLE link_role, tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
-}
-void btm_acl_device_down(void) { mock_function_count_map[__func__]++; }
-void btm_acl_disconnected(tHCI_STATUS status, uint16_t handle,
- tHCI_REASON reason) {
- mock_function_count_map[__func__]++;
-}
-void btm_acl_encrypt_change(uint16_t handle, uint8_t status,
- uint8_t encr_enable) {
- mock_function_count_map[__func__]++;
-}
-void btm_acl_notif_conn_collision(const RawAddress& bda) {
- mock_function_count_map[__func__]++;
-}
-void btm_acl_paging(BT_HDR* p, const RawAddress& bda) {
- mock_function_count_map[__func__]++;
-}
-void btm_acl_process_sca_cmpl_pkt(uint8_t len, uint8_t* data) {
- mock_function_count_map[__func__]++;
-}
-void btm_acl_removed(uint16_t handle) { mock_function_count_map[__func__]++; }
-void btm_acl_reset_paging(void) { mock_function_count_map[__func__]++; }
-void btm_acl_resubmit_page(void) { mock_function_count_map[__func__]++; }
-void btm_acl_role_changed(tHCI_STATUS hci_status, const RawAddress& bd_addr,
- tHCI_ROLE new_role) {
- mock_function_count_map[__func__]++;
-}
-void btm_acl_set_paging(bool value) { mock_function_count_map[__func__]++; }
-void btm_acl_update_conn_addr(uint16_t handle, const RawAddress& address) {
- mock_function_count_map[__func__]++;
-}
-void btm_acl_update_inquiry_status(uint8_t status) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_refresh_local_resolvable_private_addr(
- const RawAddress& pseudo_addr, const RawAddress& local_rpa) {
- mock_function_count_map[__func__]++;
-}
-void btm_cont_rswitch_from_handle(uint16_t hci_handle) {
- mock_function_count_map[__func__]++;
-}
-void btm_establish_continue_from_address(const RawAddress& bda,
- tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
-}
-void btm_process_remote_ext_features(tACL_CONN* p_acl_cb,
- uint8_t num_read_pages) {
- mock_function_count_map[__func__]++;
-}
-void btm_process_remote_version_complete(uint8_t status, uint16_t handle,
- uint8_t lmp_version,
- uint16_t manufacturer,
- uint16_t lmp_subversion) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_automatic_flush_timeout_complete(uint8_t* p) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_failed_contact_counter_complete(uint8_t* p) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_failed_contact_counter_timeout(UNUSED_ATTR void* data) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_link_quality_complete(uint8_t* p) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_link_quality_timeout(UNUSED_ATTR void* data) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_remote_ext_features(uint16_t handle, uint8_t page_number) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_remote_ext_features_complete(uint16_t handle, uint8_t page_num,
- uint8_t max_page,
- uint8_t* features) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_remote_ext_features_complete_raw(uint8_t* p, uint8_t evt_len) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_remote_ext_features_failed(uint8_t status, uint16_t handle) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_remote_features_complete(uint16_t handle, uint8_t* features) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_remote_features_complete_raw(uint8_t* p) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_remote_version_complete(tHCI_STATUS status, uint16_t handle,
- uint8_t lmp_version,
- uint16_t manufacturer,
- uint16_t lmp_subversion) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_remote_version_complete_raw(uint8_t* p) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_rssi_complete(uint8_t* p) { mock_function_count_map[__func__]++; }
-void btm_read_rssi_timeout(UNUSED_ATTR void* data) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_tx_power_complete(uint8_t* p, bool is_ble) {
- mock_function_count_map[__func__]++;
-}
-void btm_read_tx_power_timeout(UNUSED_ATTR void* data) {
- mock_function_count_map[__func__]++;
-}
-void btm_rejectlist_role_change_device(const RawAddress& bd_addr,
- uint8_t hci_status) {
- mock_function_count_map[__func__]++;
-}
-void btm_set_link_policy(tACL_CONN* conn, tLINK_POLICY policy) {
- mock_function_count_map[__func__]++;
-}
-void btm_set_packet_types_from_address(const RawAddress& bd_addr,
- uint16_t pkt_types) {
- mock_function_count_map[__func__]++;
-}
-void hci_btm_set_link_supervision_timeout(tACL_CONN& link, uint16_t timeout) {
- mock_function_count_map[__func__]++;
-}
-void on_acl_br_edr_connected(const RawAddress& bda, uint16_t handle,
- uint8_t enc_mode) {
- mock_function_count_map[__func__]++;
-}
-void on_acl_br_edr_failed(const RawAddress& bda, tHCI_STATUS status) {
- mock_function_count_map[__func__]++;
-}
diff --git a/main/test/common/mock_stack_btm_ble.cc b/main/test/common/mock_stack_btm_ble.cc
deleted file mode 100644
index a39c780..0000000
--- a/main/test/common/mock_stack_btm_ble.cc
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:50
- */
-
-#include <base/bind.h>
-#include <base/callback.h>
-#include <cstdint>
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-#include "stack/btm/btm_ble_int_types.h"
-#include "stack/btm/btm_int_types.h"
-#include "stack/btm/security_device_record.h"
-#include "stack/include/bt_types.h"
-#include "stack/include/btm_api_types.h"
-#include "stack/include/btm_ble_api_types.h"
-#include "stack/include/l2cdefs.h"
-#include "types/raw_address.h"
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-void btm_ble_reset_id(void) { mock_function_count_map[__func__]++; }
-bool BTM_BleDataSignature(const RawAddress& bd_addr, uint8_t* p_text,
- uint16_t len, BLE_SIGNATURE signature) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_BleVerifySignature(const RawAddress& bd_addr, uint8_t* p_orig,
- uint16_t len, uint32_t counter, uint8_t* p_comp) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_ReadConnectedTransportAddress(RawAddress* remote_bda,
- tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool BTM_UseLeLink(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool btm_ble_get_acl_remote_addr(uint16_t hci_handle, RawAddress& conn_addr,
- tBLE_ADDR_TYPE* p_addr_type) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool btm_ble_get_enc_key_type(const RawAddress& bd_addr, uint8_t* p_key_types) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool btm_get_local_div(const RawAddress& bd_addr, uint16_t* p_div) {
- mock_function_count_map[__func__]++;
- return false;
-}
-namespace {
-Octet16 octet16;
-}
-
-const Octet16& BTM_GetDeviceDHK() {
- mock_function_count_map[__func__]++;
- return octet16;
-}
-const Octet16& BTM_GetDeviceEncRoot() {
- mock_function_count_map[__func__]++;
- return octet16;
-}
-const Octet16& BTM_GetDeviceIDRoot() {
- mock_function_count_map[__func__]++;
- return octet16;
-}
-tBTM_SEC_ACTION btm_ble_determine_security_act(bool is_originator,
- const RawAddress& bdaddr,
- uint16_t security_required) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_SetBleDataLength(const RawAddress& bd_addr,
- uint16_t tx_pdu_length) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS btm_ble_set_encryption(const RawAddress& bd_addr,
- tBTM_BLE_SEC_ACT sec_act,
- uint8_t link_role) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS btm_ble_start_encrypt(const RawAddress& bda, bool use_stk,
- Octet16* p_stk) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-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) {
- mock_function_count_map[__func__]++;
- return L2CAP_LE_RESULT_CONN_OK;
-}
-uint8_t btm_ble_br_keys_req(tBTM_SEC_DEV_REC* p_dev_rec,
- tBTM_LE_IO_REQ* p_data) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint8_t btm_ble_io_capabilities_req(tBTM_SEC_DEV_REC* p_dev_rec,
- tBTM_LE_IO_REQ* p_data) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint8_t btm_ble_read_sec_key_size(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-tSMP_STATUS btm_proc_smp_cback(tSMP_EVT event, const RawAddress& bd_addr,
- tSMP_EVT_DATA* p_data) {
- mock_function_count_map[__func__]++;
- return SMP_SUCCESS;
-}
-void BTM_BleConfirmReply(const RawAddress& bd_addr, uint8_t res) {
- mock_function_count_map[__func__]++;
-}
-void BTM_BleLoadLocalKeys(uint8_t key_type, tBTM_BLE_LOCAL_KEYS* p_key) {
- mock_function_count_map[__func__]++;
-}
-void BTM_BleOobDataReply(const RawAddress& bd_addr, uint8_t res, uint8_t len,
- uint8_t* p_data) {
- mock_function_count_map[__func__]++;
-}
-void BTM_BlePasskeyReply(const RawAddress& bd_addr, uint8_t res,
- uint32_t passkey) {
- mock_function_count_map[__func__]++;
-}
-void BTM_BleReadPhy(
- const RawAddress& bd_addr,
- base::Callback<void(uint8_t tx_phy, uint8_t rx_phy, uint8_t status)> cb) {
- mock_function_count_map[__func__]++;
-}
-void BTM_BleReceiverTest(uint8_t rx_freq, tBTM_CMPL_CB* p_cmd_cmpl_cback) {
- mock_function_count_map[__func__]++;
-}
-void BTM_BleSecureConnectionOobDataReply(const RawAddress& bd_addr,
- uint8_t* p_c, uint8_t* p_r) {
- mock_function_count_map[__func__]++;
-}
-void BTM_BleSetPhy(const RawAddress& bd_addr, uint8_t tx_phys, uint8_t rx_phys,
- uint16_t phy_options) {
- mock_function_count_map[__func__]++;
-}
-void BTM_BleSetPrefConnParams(const RawAddress& bd_addr, uint16_t min_conn_int,
- uint16_t max_conn_int,
- uint16_t peripheral_latency,
- uint16_t supervision_tout) {
- mock_function_count_map[__func__]++;
-}
-void BTM_BleTestEnd(tBTM_CMPL_CB* p_cmd_cmpl_cback) {
- mock_function_count_map[__func__]++;
-}
-void BTM_BleTransmitterTest(uint8_t tx_freq, uint8_t test_data_len,
- uint8_t packet_payload,
- tBTM_CMPL_CB* p_cmd_cmpl_cback) {
- mock_function_count_map[__func__]++;
-}
-void BTM_ReadDevInfo(const RawAddress& remote_bda, tBT_DEVICE_TYPE* p_dev_type,
- tBLE_ADDR_TYPE* p_addr_type) {
- mock_function_count_map[__func__]++;
-}
-void BTM_SecAddBleDevice(const RawAddress& bd_addr, tBT_DEVICE_TYPE dev_type,
- tBLE_ADDR_TYPE addr_type) {
- mock_function_count_map[__func__]++;
-}
-void BTM_SecAddBleKey(const RawAddress& bd_addr, tBTM_LE_KEY_VALUE* p_le_key,
- tBTM_LE_KEY_TYPE key_type) {
- mock_function_count_map[__func__]++;
-}
-void BTM_SecurityGrant(const RawAddress& bd_addr, uint8_t res) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_connected(const RawAddress& bda, uint16_t handle, uint8_t enc_mode,
- uint8_t role, tBLE_ADDR_TYPE addr_type,
- bool addr_matched) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_connected_from_address_with_type(
- const tBLE_BD_ADDR& address_with_type, uint16_t handle, uint8_t enc_mode,
- uint8_t role, bool addr_matched) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_increment_sign_ctr(const RawAddress& bd_addr, bool is_local) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_link_encrypted(const RawAddress& bd_addr, uint8_t encr_enable) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_link_sec_check(const RawAddress& bd_addr,
- tBTM_LE_AUTH_REQ auth_req,
- tBTM_BLE_SEC_REQ_ACT* p_sec_req_act) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_ltk_request(uint16_t handle, uint8_t rand[8], uint16_t ediv) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_ltk_request_reply(const RawAddress& bda, bool use_stk,
- const Octet16& stk) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_rand_enc_complete(uint8_t* p, uint16_t op_code,
- tBTM_RAND_ENC_CB* p_enc_cplt_cback) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_set_random_address(const RawAddress& random_bda) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_test_command_complete(uint8_t* p) {
- mock_function_count_map[__func__]++;
-}
-void btm_ble_update_sec_key_size(const RawAddress& bd_addr,
- uint8_t enc_key_size) {
- mock_function_count_map[__func__]++;
-}
-void btm_sec_save_le_key(const RawAddress& bd_addr, tBTM_LE_KEY_TYPE key_type,
- tBTM_LE_KEY_VALUE* p_keys, bool pass_to_application) {
- mock_function_count_map[__func__]++;
-}
-void doNothing(uint8_t* data, uint16_t len) {
- mock_function_count_map[__func__]++;
-}
-void read_phy_cb(
- base::Callback<void(uint8_t tx_phy, uint8_t rx_phy, uint8_t status)> cb,
- uint8_t* data, uint16_t len) {
- mock_function_count_map[__func__]++;
-}
diff --git a/main/test/common/mock_stack_btm_sco.cc b/main/test/common/mock_stack_btm_sco.cc
deleted file mode 100644
index 1542c5d..0000000
--- a/main/test/common/mock_stack_btm_sco.cc
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:23
- */
-
-#include <cstdint>
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-#include "stack/include/btm_api_types.h"
-#include "stack/include/btm_status.h"
-#include "stack/include/hci_error_code.h"
-#include "types/class_of_device.h"
-#include "types/raw_address.h"
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-bool BTM_IsScoActiveByBdaddr(const RawAddress& remote_bda) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool btm_is_sco_active(uint16_t handle) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool btm_sco_removed(uint16_t hci_handle, tHCI_REASON reason) {
- mock_function_count_map[__func__]++;
- return false;
-}
-const RawAddress* BTM_ReadScoBdAddr(uint16_t sco_inx) {
- mock_function_count_map[__func__]++;
- return nullptr;
-}
-tBTM_STATUS BTM_ChangeEScoLinkParms(uint16_t sco_inx,
- tBTM_CHG_ESCO_PARAMS* p_parms) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-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) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_RegForEScoEvts(uint16_t sco_inx,
- tBTM_ESCO_CBACK* p_esco_cback) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_RemoveSco(uint16_t sco_inx) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_SetEScoMode(enh_esco_params_t* p_parms) {
- mock_function_count_map[__func__]++;
- return BTM_SUCCESS;
-}
-uint8_t BTM_GetNumScoLinks(void) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-void BTM_EScoConnRsp(uint16_t sco_inx, uint8_t hci_status,
- enh_esco_params_t* p_parms) {
- mock_function_count_map[__func__]++;
-}
-void BTM_RemoveSco(const RawAddress& bda) {
- mock_function_count_map[__func__]++;
-}
-void btm_esco_proc_conn_chg(uint8_t status, uint16_t handle,
- uint8_t tx_interval, uint8_t retrans_window,
- uint16_t rx_pkt_len, uint16_t tx_pkt_len) {
- mock_function_count_map[__func__]++;
-}
-void btm_route_sco_data(BT_HDR* p_msg) { mock_function_count_map[__func__]++; }
-void btm_sco_acl_removed(const RawAddress* bda) {
- mock_function_count_map[__func__]++;
-}
-void btm_sco_chk_pend_rolechange(uint16_t hci_handle) {
- mock_function_count_map[__func__]++;
-}
-void btm_sco_chk_pend_unpark(tHCI_STATUS hci_status, uint16_t hci_handle) {
- mock_function_count_map[__func__]++;
-}
-void btm_sco_conn_req(const RawAddress& bda, const DEV_CLASS& dev_class,
- uint8_t link_type) {
- mock_function_count_map[__func__]++;
-}
-void btm_sco_connected(tHCI_STATUS hci_status, const RawAddress& bda,
- uint16_t hci_handle, tBTM_ESCO_DATA* p_esco_data) {
- mock_function_count_map[__func__]++;
-}
-void btm_sco_disc_chk_pend_for_modechange(uint16_t hci_handle) {
- mock_function_count_map[__func__]++;
-}
-void btm_sco_on_esco_connect_request(
- const RawAddress& bda, const bluetooth::types::ClassOfDevice& cod) {
- mock_function_count_map[__func__]++;
-}
-void btm_sco_on_sco_connect_request(
- const RawAddress& bda, const bluetooth::types::ClassOfDevice& cod) {
- mock_function_count_map[__func__]++;
-}
-void btm_sco_on_disconnected(uint16_t hci_handle, tHCI_REASON reason) {
- mock_function_count_map[__func__]++;
-}
diff --git a/main/test/main_shim_test.cc b/main/test/main_shim_test.cc
index 58e4798..d4a481c 100644
--- a/main/test/main_shim_test.cc
+++ b/main/test/main_shim_test.cc
@@ -16,33 +16,157 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <condition_variable>
+#include <future>
#include <map>
+#include <thread>
+#include "btif/include/btif_hh.h"
+#include "device/include/controller.h"
#include "gd/btaa/activity_attribution.h"
#include "gd/hal/hci_hal.h"
#include "gd/hci/acl_manager_mock.h"
#include "gd/hci/controller_mock.h"
#include "gd/module.h"
#include "gd/os/mock_queue.h"
+#include "gd/os/queue.h"
+#include "gd/packet/packet_view.h"
+#include "hci/acl_manager.h"
+#include "hci/acl_manager/classic_acl_connection.h"
+#include "hci/acl_manager/connection_callbacks.h"
+#include "hci/acl_manager/connection_management_callbacks.h"
+#include "hci/acl_manager/le_acl_connection.h"
+#include "hci/acl_manager/le_connection_callbacks.h"
+#include "hci/acl_manager/le_connection_management_callbacks.h"
#include "hci/include/hci_layer.h"
#include "hci/include/hci_packet_factory.h"
#include "hci/include/hci_packet_parser.h"
#include "hci/include/packet_fragmenter.h"
#include "include/hardware/bt_activity_attribution.h"
#include "main/shim/acl.h"
+#include "main/shim/acl_legacy_interface.h"
+#include "main/shim/helpers.h"
#include "os/handler.h"
#include "os/thread.h"
#include "stack/btm/btm_int_types.h"
#include "stack/include/btu.h"
#include "stack/l2cap/l2c_int.h"
+#include "test/common/main_handler.h"
+#include "test/mock/mock_main_shim_entry.h"
using namespace bluetooth;
using namespace testing;
-std::map<std::string, int> mock_function_count_map;
+namespace test = bluetooth::hci::testing;
+const uint8_t kMaxLeAcceptlistSize = 16;
+std::map<std::string, int> mock_function_count_map;
tL2C_CB l2cb;
tBTM_CB btm_cb;
+btif_hh_cb_t btif_hh_cb;
+
+namespace {
+std::map<std::string, std::promise<uint16_t>> mock_function_handle_promise_map;
+}
+
+uint8_t mock_get_ble_acceptlist_size() { return 123; }
+
+struct controller_t mock_controller {
+ .get_ble_acceptlist_size = mock_get_ble_acceptlist_size,
+};
+
+const controller_t* controller_get_interface() { return &mock_controller; }
+
+void mock_on_send_data_upwards(BT_HDR*) { mock_function_count_map[__func__]++; }
+
+void mock_on_packets_completed(uint16_t handle, uint16_t num_packets) {
+ mock_function_count_map[__func__]++;
+}
+
+void mock_connection_classic_on_connected(const RawAddress& bda,
+ uint16_t handle, uint8_t enc_mode) {
+ mock_function_count_map[__func__]++;
+}
+
+void mock_connection_classic_on_failed(const RawAddress& bda,
+ tHCI_STATUS status) {
+ mock_function_count_map[__func__]++;
+}
+
+void mock_connection_classic_on_disconnected(tHCI_STATUS status,
+ uint16_t handle,
+ tHCI_STATUS reason) {
+ mock_function_count_map[__func__]++;
+ ASSERT_TRUE(mock_function_handle_promise_map.find(__func__) !=
+ mock_function_handle_promise_map.end());
+ mock_function_handle_promise_map[__func__].set_value(handle);
+}
+void mock_connection_le_on_connected(
+ const tBLE_BD_ADDR& address_with_type, uint16_t handle, tHCI_ROLE role,
+ uint16_t conn_interval, uint16_t conn_latency, uint16_t conn_timeout,
+ const RawAddress& local_rpa, const RawAddress& peer_rpa,
+ uint8_t peer_addr_type) {
+ mock_function_count_map[__func__]++;
+}
+void mock_connection_le_on_failed(const tBLE_BD_ADDR& address_with_type,
+ uint16_t handle, bool enhanced,
+ tHCI_STATUS status) {
+ mock_function_count_map[__func__]++;
+}
+void mock_connection_le_on_disconnected(tHCI_STATUS status, uint16_t handle,
+ tHCI_STATUS reason) {
+ mock_function_count_map[__func__]++;
+}
+
+const shim::legacy::acl_interface_t GetMockAclInterface() {
+ shim::legacy::acl_interface_t acl_interface{
+ .on_send_data_upwards = mock_on_send_data_upwards,
+ .on_packets_completed = mock_on_packets_completed,
+
+ .connection.classic.on_connected = mock_connection_classic_on_connected,
+ .connection.classic.on_failed = mock_connection_classic_on_failed,
+ .connection.classic.on_disconnected =
+ mock_connection_classic_on_disconnected,
+
+ .connection.le.on_connected = mock_connection_le_on_connected,
+ .connection.le.on_failed = mock_connection_le_on_failed,
+ .connection.le.on_disconnected = mock_connection_le_on_disconnected,
+
+ .connection.sco.on_esco_connect_request = nullptr,
+ .connection.sco.on_sco_connect_request = nullptr,
+ .connection.sco.on_disconnected = nullptr,
+
+ .link.classic.on_authentication_complete = nullptr,
+ .link.classic.on_central_link_key_complete = nullptr,
+ .link.classic.on_change_connection_link_key_complete = nullptr,
+ .link.classic.on_encryption_change = nullptr,
+ .link.classic.on_flow_specification_complete = nullptr,
+ .link.classic.on_flush_occurred = nullptr,
+ .link.classic.on_mode_change = nullptr,
+ .link.classic.on_packet_type_changed = nullptr,
+ .link.classic.on_qos_setup_complete = nullptr,
+ .link.classic.on_read_afh_channel_map_complete = nullptr,
+ .link.classic.on_read_automatic_flush_timeout_complete = nullptr,
+ .link.classic.on_sniff_subrating = nullptr,
+ .link.classic.on_read_clock_complete = nullptr,
+ .link.classic.on_read_clock_offset_complete = nullptr,
+ .link.classic.on_read_failed_contact_counter_complete = nullptr,
+ .link.classic.on_read_link_policy_settings_complete = nullptr,
+ .link.classic.on_read_link_quality_complete = nullptr,
+ .link.classic.on_read_link_supervision_timeout_complete = nullptr,
+ .link.classic.on_read_remote_version_information_complete = nullptr,
+ .link.classic.on_read_remote_extended_features_complete = nullptr,
+ .link.classic.on_read_rssi_complete = nullptr,
+ .link.classic.on_read_transmit_power_level_complete = nullptr,
+ .link.classic.on_role_change = nullptr,
+ .link.classic.on_role_discovery_complete = nullptr,
+
+ .link.le.on_connection_update = nullptr,
+ .link.le.on_data_length_change = nullptr,
+ .link.le.on_read_remote_version_information_complete = nullptr,
+ };
+ return acl_interface;
+}
const hci_packet_factory_t* hci_packet_factory_get_interface() {
return nullptr;
@@ -52,25 +176,79 @@
const packet_fragmenter_t* packet_fragmenter_get_interface() { return nullptr; }
void LogMsg(uint32_t trace_set_mask, const char* fmt_str, ...) {}
+template <typename T>
+class MockEnQueue : public os::IQueueEnqueue<T> {
+ using EnqueueCallback = base::Callback<std::unique_ptr<T>()>;
+
+ void RegisterEnqueue(os::Handler* handler,
+ EnqueueCallback callback) override {}
+ void UnregisterEnqueue() override {}
+};
+
+template <typename T>
+class MockDeQueue : public os::IQueueDequeue<T> {
+ using DequeueCallback = base::Callback<void()>;
+
+ void RegisterDequeue(os::Handler* handler,
+ DequeueCallback callback) override {}
+ void UnregisterDequeue() override {}
+ std::unique_ptr<T> TryDequeue() override { return nullptr; }
+};
+
+class MockClassicAclConnection
+ : public bluetooth::hci::acl_manager::ClassicAclConnection {
+ public:
+ MockClassicAclConnection(const hci::Address& address, uint16_t handle) {
+ address_ = address; // ClassicAclConnection
+ handle_ = handle; // AclConnection
+ }
+
+ void RegisterCallbacks(
+ hci::acl_manager::ConnectionManagementCallbacks* callbacks,
+ os::Handler* handler) override {
+ callbacks_ = callbacks;
+ handler_ = handler;
+ }
+
+ // Returns the bidi queue for this mock connection
+ AclConnection::QueueUpEnd* GetAclQueueEnd() const override {
+ return &mock_acl_queue_;
+ }
+
+ mutable common::BidiQueueEnd<hci::BasePacketBuilder,
+ packet::PacketView<hci::kLittleEndian>>
+ mock_acl_queue_{&tx_, &rx_};
+
+ MockEnQueue<hci::BasePacketBuilder> tx_;
+ MockDeQueue<packet::PacketView<hci::kLittleEndian>> rx_;
+
+ bool ReadRemoteVersionInformation() override { return true; }
+ bool ReadRemoteSupportedFeatures() override { return true; }
+
+ bool Disconnect(hci::DisconnectReason reason) override {
+ disconnect_cnt_++;
+ disconnect_promise_.set_value(handle_);
+ return true;
+ }
+
+ std::promise<uint16_t> disconnect_promise_;
+
+ hci::acl_manager::ConnectionManagementCallbacks* callbacks_{nullptr};
+ os::Handler* handler_{nullptr};
+
+ int disconnect_cnt_{0};
+};
+
namespace bluetooth {
namespace shim {
void init_activity_attribution() {}
namespace testing {
extern os::Handler* mock_handler_;
-} // namespace testing
+} // namespace testing
} // namespace shim
-namespace hci {
-namespace testing {
-
-extern MockController* mock_controller_;
-extern MockAclManager* mock_acl_manager_;
-
-} // namespace testing
-} // namespace hci
-
namespace activity_attribution {
ActivityAttributionInterface* get_activity_attribution_instance() {
return nullptr;
@@ -90,41 +268,153 @@
public:
protected:
void SetUp() override {
- thread_ = new os::Thread("thread", os::Thread::Priority::NORMAL);
+ main_thread_start_up();
+
+ thread_ = new os::Thread("acl_thread", os::Thread::Priority::NORMAL);
handler_ = new os::Handler(thread_);
- hci::testing::mock_acl_manager_ = new hci::testing::MockAclManager();
- hci::testing::mock_controller_ = new hci::testing::MockController();
+ /* extern */ test::mock_controller_ =
+ new bluetooth::hci::testing::MockController();
+ /* extern */ test::mock_acl_manager_ =
+ new bluetooth::hci::testing::MockAclManager();
}
void TearDown() override {
- delete hci::testing::mock_controller_;
- delete hci::testing::mock_acl_manager_;
+ delete test::mock_controller_;
+ test::mock_controller_ = nullptr;
+ delete test::mock_acl_manager_;
+ test::mock_acl_manager_ = nullptr;
handler_->Clear();
delete handler_;
delete thread_;
+
+ main_thread_shut_down();
}
os::Thread* thread_{nullptr};
os::Handler* handler_{nullptr};
+
+ // Convenience method to create ACL objects
+ std::unique_ptr<shim::legacy::Acl> MakeAcl() {
+ EXPECT_CALL(*test::mock_acl_manager_, RegisterCallbacks(_, _)).Times(1);
+ EXPECT_CALL(*test::mock_acl_manager_, RegisterLeCallbacks(_, _)).Times(1);
+ EXPECT_CALL(*test::mock_controller_,
+ RegisterCompletedMonitorAclPacketsCallback(_))
+ .Times(1);
+ EXPECT_CALL(*test::mock_acl_manager_, HACK_SetScoDisconnectCallback(_))
+ .Times(1);
+ EXPECT_CALL(*test::mock_controller_,
+ UnregisterCompletedMonitorAclPacketsCallback)
+ .Times(1);
+ return std::make_unique<shim::legacy::Acl>(handler_, GetMockAclInterface(),
+ kMaxLeAcceptlistSize);
+ }
};
TEST_F(MainShimTest, Nop) {}
TEST_F(MainShimTest, Acl_Lifecycle) {
- EXPECT_CALL(*hci::testing::mock_acl_manager_, RegisterCallbacks(_, _))
- .Times(1);
- EXPECT_CALL(*hci::testing::mock_acl_manager_, RegisterLeCallbacks(_, _))
- .Times(1);
- EXPECT_CALL(*hci::testing::mock_controller_,
- RegisterCompletedMonitorAclPacketsCallback(_))
- .Times(1);
- EXPECT_CALL(*hci::testing::mock_acl_manager_,
- HACK_SetScoDisconnectCallback(_))
- .Times(1);
- EXPECT_CALL(*hci::testing::mock_controller_,
- UnregisterCompletedMonitorAclPacketsCallback)
- .Times(1);
+ auto acl = MakeAcl();
+ acl.reset();
+ acl = MakeAcl();
+}
- auto acl = std::make_unique<shim::legacy::Acl>(
- handler_, shim::legacy::GetAclInterface(), 16);
+TEST_F(MainShimTest, helpers) {
+ uint8_t reason = 0;
+ do {
+ hci::ErrorCode gd_error_code = static_cast<hci::ErrorCode>(reason);
+ tHCI_STATUS legacy_code = ToLegacyHciErrorCode(gd_error_code);
+ ASSERT_EQ(reason,
+ static_cast<uint8_t>(ToLegacyHciErrorCode(gd_error_code)));
+ ASSERT_EQ(reason, static_cast<uint8_t>(legacy_code));
+ } while (++reason != 0);
+}
+
+TEST_F(MainShimTest, connect_and_disconnect) {
+ hci::Address address({0x11, 0x22, 0x33, 0x44, 0x55, 0x66});
+
+ auto acl = MakeAcl();
+
+ // Create connection
+ EXPECT_CALL(*test::mock_acl_manager_, CreateConnection(_)).Times(1);
+ acl->CreateClassicConnection(address);
+
+ // Respond with a mock connection created
+ auto connection = std::make_unique<MockClassicAclConnection>(address, 123);
+ ASSERT_EQ(123, connection->GetHandle());
+ ASSERT_EQ(hci::Address({0x11, 0x22, 0x33, 0x44, 0x55, 0x66}),
+ connection->GetAddress());
+ MockClassicAclConnection* raw_connection = connection.get();
+
+ acl->OnConnectSuccess(std::move(connection));
+ ASSERT_EQ(nullptr, connection);
+
+ // Specify local disconnect request
+ auto tx_disconnect_future = raw_connection->disconnect_promise_.get_future();
+ acl->DisconnectClassic(123, HCI_SUCCESS);
+
+ // Wait for disconnect to be received
+ uint16_t result = tx_disconnect_future.get();
+ ASSERT_EQ(123, result);
+
+ // Now emulate the remote disconnect response
+ auto handle_promise = std::promise<uint16_t>();
+ auto rx_disconnect_future = handle_promise.get_future();
+ mock_function_handle_promise_map["mock_connection_classic_on_disconnected"] =
+ std::move(handle_promise);
+ raw_connection->callbacks_->OnDisconnection(hci::ErrorCode::SUCCESS);
+
+ result = rx_disconnect_future.get();
+ ASSERT_EQ(123, result);
+
+ // *Our* task completing indicates reactor is done
+ std::promise<void> done;
+ auto future = done.get_future();
+ handler_->Call([](std::promise<void> done) { done.set_value(); },
+ std::move(done));
+ future.wait();
+}
+
+TEST_F(MainShimTest, is_flushable) {
+ {
+ BT_HDR* bt_hdr =
+ (BT_HDR*)calloc(1, sizeof(BT_HDR) + sizeof(HciDataPreamble));
+
+ ASSERT_TRUE(!IsPacketFlushable(bt_hdr));
+ HciDataPreamble* hci = ToPacketData<HciDataPreamble>(bt_hdr);
+ hci->SetFlushable();
+ ASSERT_TRUE(IsPacketFlushable(bt_hdr));
+
+ free(bt_hdr);
+ }
+
+ {
+ size_t offset = 1024;
+ BT_HDR* bt_hdr =
+ (BT_HDR*)calloc(1, sizeof(BT_HDR) + sizeof(HciDataPreamble) + offset);
+ bt_hdr->offset = offset;
+
+ ASSERT_TRUE(!IsPacketFlushable(bt_hdr));
+ HciDataPreamble* hci = ToPacketData<HciDataPreamble>(bt_hdr);
+ hci->SetFlushable();
+ ASSERT_TRUE(IsPacketFlushable(bt_hdr));
+
+ free(bt_hdr);
+ }
+
+ {
+ size_t offset = 1024;
+ BT_HDR* bt_hdr =
+ (BT_HDR*)calloc(1, sizeof(BT_HDR) + sizeof(HciDataPreamble) + offset);
+
+ uint8_t* p = ToPacketData<uint8_t>(bt_hdr, L2CAP_SEND_CMD_OFFSET);
+ UINT16_TO_STREAM(
+ p, 0x123 | (L2CAP_PKT_START_NON_FLUSHABLE << L2CAP_PKT_TYPE_SHIFT));
+ ASSERT_TRUE(!IsPacketFlushable(bt_hdr));
+
+ p = ToPacketData<uint8_t>(bt_hdr, L2CAP_SEND_CMD_OFFSET);
+ UINT16_TO_STREAM(p, 0x123 | (L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT));
+ ASSERT_TRUE(IsPacketFlushable(bt_hdr));
+
+ free(bt_hdr);
+ }
}
diff --git a/osi/Android.bp b/osi/Android.bp
index 7a979cf..e017bd6 100644
--- a/osi/Android.bp
+++ b/osi/Android.bp
@@ -20,7 +20,6 @@
}
// Static libraries required by other modules
-// ========================================================
cc_test_library {
name: "libosi-AllocationTestHarness",
defaults: ["fluoride_osi_defaults"],
@@ -46,7 +45,6 @@
}
// libosi static library for target
-// ========================================================
cc_library_static {
name: "libosi",
defaults: ["fluoride_osi_defaults"],
@@ -95,7 +93,6 @@
}
// libosi unit tests for target and host
-// ========================================================
cc_test {
name: "net_test_osi",
test_suites: ["device-tests"],
diff --git a/osi/include/compat.h b/osi/include/compat.h
index 95fe037..1d19a59 100644
--- a/osi/include/compat.h
+++ b/osi/include/compat.h
@@ -26,7 +26,7 @@
#include <unistd.h>
/* Get thread identification. */
-pid_t gettid(void);
+pid_t gettid(void) throw();
/* Copy src to string dst of size siz. */
size_t strlcpy(char* dst, const char* src, size_t siz);
diff --git a/osi/src/compat.cc b/osi/src/compat.cc
index 069964c..e5b41a5 100644
--- a/osi/src/compat.cc
+++ b/osi/src/compat.cc
@@ -35,7 +35,7 @@
#include "osi/include/osi.h"
#if __GLIBC__
-pid_t gettid(void) { return syscall(SYS_gettid); }
+pid_t gettid(void) throw() { return syscall(SYS_gettid); }
#endif
/* These functions from bionic
diff --git a/service/Android.bp b/service/Android.bp
index 130b653..b2f23ed 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -21,7 +21,6 @@
}
// Source variables
-// ========================================================
btserviceDaemonSrc = [
"a2dp_sink.cc",
"a2dp_source.cc",
@@ -66,7 +65,6 @@
]
// Main unit test sources. These get built for host and target.
-// ========================================================
btserviceBaseTestSrc = [
"hal/fake_bluetooth_av_interface.cc",
"hal/fake_bluetooth_gatt_interface.cc",
@@ -85,7 +83,6 @@
]
// Native system service for target
-// ========================================================
cc_binary {
name: "bluetoothtbd",
defaults: ["fluoride_service_defaults"],
@@ -112,7 +109,6 @@
// Native system service unit tests for target and host
-// ========================================================
cc_test {
name: "bluetoothtbd_test",
test_suites: ["device-tests"],
@@ -175,7 +171,6 @@
}
// Native system service CLI for target
-// ========================================================
cc_binary {
name: "bluetooth-cli",
defaults: ["fluoride_defaults"],
@@ -190,7 +185,6 @@
}
// Heart Rate GATT service example for target
-// ========================================================
cc_binary {
name: "bt-example-hr-server",
defaults: ["fluoride_defaults"],
diff --git a/service/BUILD.gn b/service/BUILD.gn
index f4b4f09..83f92d3 100644
--- a/service/BUILD.gn
+++ b/service/BUILD.gn
@@ -63,6 +63,8 @@
sources = [
"ipc/ipc_handler_linux.cc",
"ipc/linux_ipc_host.cc",
+ "ipc/dbus/ipc_handler_dbus.cc",
+ "ipc/dbus/bluetooth_adapter.cc",
]
deps = [
@@ -74,7 +76,7 @@
configs += [ ":service_config" ]
}
-source_set("service") {
+static_library("service") {
sources = [
"common/bluetooth/a2dp_codec_config.cc",
"common/bluetooth/adapter_state.cc",
@@ -91,8 +93,6 @@
"common/bluetooth/scan_settings.cc",
"common/bluetooth/service.cc",
"common/bluetooth/util/atomic_string.cc",
- "ipc/dbus/bluetooth_adapter.cc",
- "ipc/dbus/ipc_handler_dbus.cc",
]
deps = [
@@ -125,6 +125,10 @@
"ssl",
"crypto",
]
+
+ lib_dirs = [
+ "${root_out_dir}/rust"
+ ]
}
if (use.test) {
@@ -155,6 +159,7 @@
deps = [
":service_base_test_src",
":service_daemon_src",
+ ":service_linux_src",
"//bt/service/common:libbluetooth_common",
]
diff --git a/service/a2dp_sink.cc b/service/a2dp_sink.cc
index 4d59c7c..e23c588 100644
--- a/service/a2dp_sink.cc
+++ b/service/a2dp_sink.cc
@@ -138,7 +138,6 @@
}
// A2dpSinkFactory implementation
-// ========================================================
A2dpSinkFactory::A2dpSinkFactory() = default;
A2dpSinkFactory::~A2dpSinkFactory() = default;
diff --git a/service/a2dp_source.cc b/service/a2dp_source.cc
index d39f202..827cf51 100644
--- a/service/a2dp_source.cc
+++ b/service/a2dp_source.cc
@@ -207,7 +207,6 @@
}
// A2dpSourceFactory implementation
-// ========================================================
A2dpSourceFactory::A2dpSourceFactory() = default;
A2dpSourceFactory::~A2dpSourceFactory() = default;
diff --git a/service/adapter.cc b/service/adapter.cc
index 65e58e8..4f324a5 100644
--- a/service/adapter.cc
+++ b/service/adapter.cc
@@ -25,6 +25,7 @@
#include <base/observer_list.h>
#include "abstract_observer_list.h"
+#include "notreached.h"
#include "service/a2dp_sink.h"
#include "service/a2dp_source.h"
#include "service/avrcp_control.h"
diff --git a/service/avrcp_control.cc b/service/avrcp_control.cc
index 18dc2aa..96460ce 100644
--- a/service/avrcp_control.cc
+++ b/service/avrcp_control.cc
@@ -24,6 +24,7 @@
#include <base/memory/ptr_util.h>
#include <base/strings/string_number_conversions.h>
+#include "notreached.h"
#include "service/logging_helpers.h"
#include "stack/include/avrc_defs.h"
@@ -213,7 +214,6 @@
}
// AvrcpControlFactory implementation
-// ========================================================
AvrcpControlFactory::AvrcpControlFactory() = default;
AvrcpControlFactory::~AvrcpControlFactory() = default;
diff --git a/service/avrcp_target.cc b/service/avrcp_target.cc
index 264945a..1ba9b21 100644
--- a/service/avrcp_target.cc
+++ b/service/avrcp_target.cc
@@ -365,7 +365,6 @@
}
// AvrcpTargetFactory implementation
-// ========================================================
AvrcpTargetFactory::AvrcpTargetFactory() = default;
AvrcpTargetFactory::~AvrcpTargetFactory() = default;
diff --git a/service/client/main.cc b/service/client/main.cc
index 6458b2d..b4ab06e 100644
--- a/service/client/main.cc
+++ b/service/client/main.cc
@@ -44,6 +44,8 @@
#include <bluetooth/scan_settings.h>
#include <bluetooth/uuid.h>
+#include "notreached.h"
+
using namespace std;
using android::sp;
diff --git a/service/gatt_client.cc b/service/gatt_client.cc
index 2c09fa5..e091948 100644
--- a/service/gatt_client.cc
+++ b/service/gatt_client.cc
@@ -24,7 +24,6 @@
namespace bluetooth {
// GattClient implementation
-// ========================================================
GattClient::GattClient(const Uuid& uuid, int client_id)
: app_identifier_(uuid), client_id_(client_id) {}
@@ -43,7 +42,6 @@
int GattClient::GetInstanceId() const { return client_id_; }
// GattClientFactory implementation
-// ========================================================
GattClientFactory::GattClientFactory() {
hal::BluetoothGattInterface::Get()->AddClientObserver(this);
diff --git a/service/gatt_server.cc b/service/gatt_server.cc
index ac2996b..701679f 100644
--- a/service/gatt_server.cc
+++ b/service/gatt_server.cc
@@ -27,7 +27,6 @@
namespace bluetooth {
// GattServer implementation
-// ========================================================
GattServer::GattServer(const Uuid& uuid, int server_id)
: app_identifier_(uuid), server_id_(server_id), delegate_(nullptr) {}
@@ -566,7 +565,6 @@
}
// GattServerFactory implementation
-// ========================================================
GattServerFactory::GattServerFactory() {
hal::BluetoothGattInterface::Get()->AddServerObserver(this);
diff --git a/service/gatt_server_old.cc b/service/gatt_server_old.cc
index d72be58..a460943 100644
--- a/service/gatt_server_old.cc
+++ b/service/gatt_server_old.cc
@@ -23,7 +23,6 @@
#include <unistd.h>
#include <base/bind.h>
-#include <base/bind_helpers.h>
#include <base/callback.h>
#include <algorithm>
#include <array>
@@ -40,6 +39,8 @@
#include <hardware/bluetooth.h>
#include <hardware/bt_gatt.h>
+#include "bind_helpers.h"
+
#include "service/hal/bluetooth_interface.h"
#include "service/logging_helpers.h"
diff --git a/service/ipc/binder/remote_callback_list.h b/service/ipc/binder/remote_callback_list.h
index 8c1f6ac..e25e550 100644
--- a/service/ipc/binder/remote_callback_list.h
+++ b/service/ipc/binder/remote_callback_list.h
@@ -96,7 +96,6 @@
};
// Template Implementation details below
-// ========================================================
using android::IBinder;
using android::IInterface;
diff --git a/service/ipc/binder/remote_callback_map.h b/service/ipc/binder/remote_callback_map.h
index b07de44..7f31b53 100644
--- a/service/ipc/binder/remote_callback_map.h
+++ b/service/ipc/binder/remote_callback_map.h
@@ -109,7 +109,6 @@
};
// Template Implementation details below
-// ========================================================
using android::IBinder;
using android::IInterface;
diff --git a/service/low_energy_advertiser.cc b/service/low_energy_advertiser.cc
index 7bc5f25..7b0e22a 100644
--- a/service/low_energy_advertiser.cc
+++ b/service/low_energy_advertiser.cc
@@ -22,10 +22,11 @@
#include "stack/include/hcidefs.h"
#include <base/bind.h>
-#include <base/bind_helpers.h>
#include <base/callback.h>
#include <base/logging.h>
+#include "bind_helpers.h"
+
using std::lock_guard;
using std::mutex;
@@ -118,7 +119,6 @@
} // namespace
// LowEnergyAdvertiser implementation
-// ========================================================
LowEnergyAdvertiser::LowEnergyAdvertiser(const Uuid& uuid, int advertiser_id)
: app_identifier_(uuid),
@@ -286,7 +286,6 @@
}
// LowEnergyAdvertiserFactory implementation
-// ========================================================
LowEnergyAdvertiserFactory::LowEnergyAdvertiserFactory() {}
diff --git a/service/low_energy_client.cc b/service/low_energy_client.cc
index bbc130f..bbed569 100644
--- a/service/low_energy_client.cc
+++ b/service/low_energy_client.cc
@@ -32,7 +32,6 @@
namespace bluetooth {
// LowEnergyClient implementation
-// ========================================================
LowEnergyClient::LowEnergyClient(Adapter& adapter, const Uuid& uuid,
int client_id)
@@ -196,7 +195,6 @@
}
// LowEnergyClientFactory implementation
-// ========================================================
LowEnergyClientFactory::LowEnergyClientFactory(Adapter& adapter)
: adapter_(adapter) {
diff --git a/service/low_energy_scanner.cc b/service/low_energy_scanner.cc
index fe65a7a..1fcf3a2 100644
--- a/service/low_energy_scanner.cc
+++ b/service/low_energy_scanner.cc
@@ -64,7 +64,6 @@
} // namespace
// LowEnergyScanner implementation
-// ========================================================
LowEnergyScanner::LowEnergyScanner(Adapter& adapter, const Uuid& uuid,
int scanner_id)
@@ -159,7 +158,6 @@
}
// LowEnergyScannerFactory implementation
-// ========================================================
LowEnergyScannerFactory::LowEnergyScannerFactory(Adapter& adapter)
: adapter_(adapter) {
diff --git a/service/test/low_energy_scanner_unittest.cc b/service/test/low_energy_scanner_unittest.cc
index 53fc293..4743b63 100644
--- a/service/test/low_energy_scanner_unittest.cc
+++ b/service/test/low_energy_scanner_unittest.cc
@@ -52,8 +52,8 @@
FilterParamSetupCallback cb));
MOCK_METHOD2(ScanFilterClear, void(int filt_index, FilterConfigCallback cb));
MOCK_METHOD2(ScanFilterEnable, void(bool enable, EnableCallback cb));
- MOCK_METHOD3(SetScanParameters,
- void(int scan_interval, int scan_window, Callback cb));
+ MOCK_METHOD4(SetScanParameters, void(int scanner_id, int scan_interval,
+ int scan_window, Callback cb));
MOCK_METHOD5(BatchscanConfigStorage,
void(int client_if, int batch_scan_full_max,
diff --git a/stack/Android.bp b/stack/Android.bp
index 82a0de0..b157d4c 100644
--- a/stack/Android.bp
+++ b/stack/Android.bp
@@ -25,7 +25,6 @@
}
// Bluetooth stack static library for target
-// ========================================================
cc_library_static {
name: "libbt-stack",
defaults: ["fluoride_defaults"],
@@ -207,6 +206,7 @@
shared_libs: [
"libcutils",
"liblog",
+ "libcrypto",
],
required: [
"libldacBT_enc",
@@ -216,7 +216,6 @@
}
// Bluetooth stack unit tests for target
-// ========================================================
cc_test {
name: "net_test_stack",
defaults: ["fluoride_defaults"],
@@ -334,7 +333,6 @@
}
// Bluetooth stack smp unit tests for target
-// ========================================================
cc_test {
name: "net_test_stack_smp",
defaults: ["fluoride_defaults"],
@@ -365,6 +363,7 @@
],
shared_libs: [
"libcutils",
+ "libcrypto",
],
static_libs: [
"liblog",
@@ -374,7 +373,6 @@
}
// Bluetooth stack multi-advertising unit tests for target
-// ========================================================
cc_test {
name: "net_test_stack_multi_adv",
defaults: ["fluoride_defaults"],
@@ -409,7 +407,6 @@
}
// Bluetooth stack advertise data parsing unit tests for target
-// =============================================================
cc_test {
name: "net_test_stack_ad_parser",
defaults: ["fluoride_defaults"],
@@ -428,7 +425,6 @@
}
// Bluetooth stack connection multiplexing
-// ========================================================
cc_test {
name: "net_test_gatt_conn_multiplexing",
defaults: ["fluoride_defaults"],
@@ -479,7 +475,6 @@
],
srcs: [
"gatt/gatt_utils.cc",
- "test/common/mock_acl.cc",
"test/common/mock_eatt.cc",
"test/common/mock_gatt_layer.cc",
"test/common/mock_main_shim.cc",
@@ -506,6 +501,56 @@
}
cc_test {
+ name: "net_test_stack_avdtp",
+ defaults: ["fluoride_defaults"],
+ test_suites: ["device-tests"],
+ host_supported: true,
+ test_options: {
+ unit_test: true,
+ },
+ include_dirs: [
+ "external/libldac/inc",
+ "system/bt",
+ "system/bt/stack/include",
+ "system/bt/utils/include",
+ ],
+ srcs: [
+ "test/stack_avdtp_test.cc",
+ "avdt/avdt_ad.cc",
+ "avdt/avdt_api.cc",
+ "avdt/avdt_ccb.cc",
+ "avdt/avdt_ccb_act.cc",
+ "avdt/avdt_l2c.cc",
+ "avdt/avdt_scb.cc",
+ "avdt/avdt_scb_act.cc",
+ "test/common/mock_btu_layer.cc",
+ "test/common/mock_stack_avdt_msg.cc",
+ ":TestMockStackL2cap",
+ ":TestMockStackAcl",
+ ":TestMockStackA2dp",
+ ":TestMockBta",
+ ":TestMockDevice",
+ ],
+ shared_libs: [
+ "libcrypto",
+ "libcutils",
+ "libprotobuf-cpp-lite",
+ ],
+ static_libs: [
+ "libbt-common",
+ "libbt-protos-lite",
+ "liblog",
+ "libosi",
+ "libosi-AllocationTestHarness",
+ ],
+ sanitize: {
+ address: true,
+ cfi: true,
+ misc_undefined: ["bounds"],
+ },
+}
+
+cc_test {
name: "net_test_stack_a2dp_native",
defaults: ["fluoride_defaults"],
test_suites: ["device-tests"],
@@ -558,7 +603,6 @@
"gatt/gatt_db.cc",
"gatt/gatt_sr_hash.cc",
"gatt/gatt_utils.cc",
- "test/common/mock_acl.cc",
"test/common/mock_eatt.cc",
"test/common/mock_gatt_layer.cc",
"test/common/mock_main_shim.cc",
@@ -685,9 +729,30 @@
],
include_dirs: [
"system/bt",
+ "system/bt/gd",
"system/bt/vnd/ble",
],
+ generated_headers: [
+ "BluetoothGeneratedBundlerSchema_h_bfbs",
+ "BluetoothGeneratedDumpsysDataSchema_h",
+ "BluetoothGeneratedPackets_h",
+ ],
srcs: crypto_toolbox_srcs + [
+ ":BluetoothBtaaSources_host",
+ ":BluetoothHalSources_hci_host",
+ ":BluetoothOsSources_host",
+ ":TestCommonMainHandler",
+ ":TestMockBta",
+ ":TestMockBtif",
+ ":TestMockDevice",
+ ":TestMockLegacyHciCommands",
+ ":TestMockMainBte",
+ ":TestMockMainShim",
+ ":TestMockStackBtu",
+ ":TestMockStackGap",
+ ":TestMockStackGatt",
+ ":TestMockStackSmp",
+ ":TestStackL2cap",
"acl/acl.cc",
"acl/ble_acl.cc",
"acl/btm_acl.cc",
@@ -714,33 +779,49 @@
"btm/btm_sec.cc",
"metrics/stack_metrics_logging.cc",
"test/btm/stack_btm_test.cc",
- "test/common/mock_bta_dm_act.cc",
- "test/common/mock_bta_sys_conn.cc",
- "test/common/mock_btif_bqr.cc",
- "test/common/mock_btif_dm.cc",
- "test/common/mock_btif_storage.cc",
- "test/common/mock_btu_hcif.cc",
- "test/common/mock_gap_gap_ble.cc",
- "test/common/mock_gatt_connection_manager.cc",
- "test/common/mock_gatt_gatt_auth.cc",
- "test/common/mock_gatt_main.cc",
- "test/common/mock_hci_packet_parser.cc",
- "test/common/mock_hcic_hciblecmds.cc",
- "test/common/mock_hcic_hcicmds.cc",
- "test/common/mock_l2cap_l2c_api.cc",
- "test/common/mock_l2cap_l2c_ble.cc",
- "test/common/mock_l2cap_l2c_link.cc",
- "test/common/mock_l2cap_l2c_main.cc",
- "test/common/mock_l2cap_l2c_utils.cc",
- "test/common/mock_main_bte_main.cc",
- "test/common/mock_main_shim.cc",
- "test/common/mock_main_shim_acl_api.cc",
- "test/common/mock_main_shim_l2c_api.cc",
- "test/common/mock_main_shim_btm_api.cc",
- "test/common/mock_main_shim_controller.cc",
- "test/common/mock_main_shim_link_policy.cc",
- "test/common/mock_smp_smp_act.cc",
- "test/common/mock_smp_smp_api.cc",
+ "test/btm/peer_packet_types_test.cc",
+ ],
+ static_libs: [
+ "libbt-common",
+ "libbt-protos-lite",
+ "libbtdevice",
+ "libgmock",
+ "liblog",
+ "libosi",
+ ],
+ shared_libs: [
+ "libcrypto",
+ "libflatbuffers-cpp",
+ "libprotobuf-cpp-lite",
+ ],
+ sanitize: {
+ address: true,
+ all_undefined: true,
+ cfi: true,
+ integer_overflow: true,
+ scs: true,
+ diag: {
+ undefined : true
+ },
+ },
+}
+
+cc_test {
+ name: "net_test_stack_hci",
+ test_suites: ["device-tests"],
+ host_supported: true,
+ defaults: ["fluoride_defaults"],
+ local_include_dirs: [
+ "include",
+ "btm",
+ "test/common",
+ ],
+ include_dirs: [
+ "system/bt",
+ "system/bt/vnd/ble",
+ ],
+ srcs: crypto_toolbox_srcs + [
+ "test/hci/stack_hci_test.cc",
],
static_libs: [
"libbt-common",
@@ -766,3 +847,181 @@
},
},
}
+
+cc_test {
+ name: "net_test_stack_hid",
+ test_suites: ["device-tests"],
+ host_supported: true,
+ defaults: ["fluoride_defaults"],
+ local_include_dirs: [
+ "include",
+ "test/common",
+ ],
+ include_dirs: [
+ "system/bt",
+ ],
+ srcs: crypto_toolbox_srcs + [
+ ":TestStackL2cap",
+ ":TestStackSdp",
+ ":TestStackBtm",
+ ":TestStubLegacyTrace",
+ "hid/hidd_api.cc",
+ "hid/hidd_conn.cc",
+ "hid/hidh_api.cc",
+ "hid/hidh_conn.cc",
+ "test/hid/stack_hid_test.cc",
+ ],
+ static_libs: [
+ "libbt-common",
+ "libbt-protos-lite",
+ "libbtdevice",
+ "libbte",
+ "libgmock",
+ "liblog",
+ "libosi",
+ ],
+ shared_libs: [
+ "libcrypto",
+ "libprotobuf-cpp-lite",
+ ],
+ sanitize: {
+ address: true,
+ all_undefined: true,
+ cfi: true,
+ integer_overflow: true,
+ scs: true,
+ diag: {
+ undefined : true
+ },
+ },
+}
+
+cc_test {
+ name: "net_test_stack_btu",
+ test_suites: ["device-tests"],
+ host_supported: true,
+ defaults: ["fluoride_defaults"],
+ local_include_dirs: [
+ "include",
+ "test/common",
+ ],
+ include_dirs: [
+ "system/bt",
+ "system/bt/gd",
+ ],
+ generated_headers: [
+ "BluetoothGeneratedBundlerSchema_h_bfbs",
+ "BluetoothGeneratedDumpsysDataSchema_h",
+ "BluetoothGeneratedPackets_h",
+ ],
+ srcs: [
+ ":TestMockBta",
+ ":TestMockBtif",
+ ":TestMockHci",
+ ":TestMockLegacyHciCommands",
+ ":TestMockMainShim",
+ ":TestMockStackAcl",
+ ":TestMockStackSmp",
+ ":TestStackBtm",
+ ":TestStackL2cap",
+ ":TestMockStackMetrics",
+ "btu/btu_hcif.cc",
+ "btu/btu_task.cc",
+ "test/stack_btu_test.cc",
+ ],
+ static_libs: [
+ "libbt-common",
+ "libbt-protos-lite",
+ "libbtdevice",
+ "libgmock",
+ "liblog",
+ "libosi",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ "libcrypto",
+ "libflatbuffers-cpp",
+ "libprotobuf-cpp-lite",
+ ],
+ sanitize: {
+ address: true,
+ all_undefined: true,
+ cfi: true,
+ integer_overflow: true,
+ scs: true,
+ diag: {
+ undefined : true
+ },
+ },
+}
+
+cc_test {
+ name: "net_test_stack_gatt",
+ test_suites: ["device-tests"],
+ host_supported: true,
+ defaults: ["fluoride_defaults"],
+ local_include_dirs: [
+ "include",
+ "test/common",
+ ],
+ include_dirs: [
+ "system/bt",
+ "system/bt/gd",
+ "system/bt/utils/include",
+ ],
+ generated_headers: [
+ "BluetoothGeneratedBundlerSchema_h_bfbs",
+ "BluetoothGeneratedDumpsysDataSchema_h",
+ "BluetoothGeneratedPackets_h",
+ ],
+ srcs: [
+ ":TestMockBta",
+ ":TestMockBtif",
+ ":TestMockHci",
+ ":TestMockLegacyHciCommands",
+ ":TestMockMainShim",
+ ":TestMockStackAcl",
+ ":TestMockStackCryptotoolbox",
+ ":TestMockStackSmp",
+ ":TestStackBtm",
+ ":TestStackL2cap",
+ ":TestStackSdp",
+ "eatt/eatt.cc",
+ "gatt/att_protocol.cc",
+ "gatt/connection_manager.cc",
+ "gatt/gatt_api.cc",
+ "gatt/gatt_attr.cc",
+ "gatt/gatt_auth.cc",
+ "gatt/gatt_cl.cc",
+ "gatt/gatt_db.cc",
+ "gatt/gatt_main.cc",
+ "gatt/gatt_sr.cc",
+ "gatt/gatt_sr_hash.cc",
+ "gatt/gatt_utils.cc",
+ "test/gatt/stack_gatt_test.cc",
+ ],
+ static_libs: [
+ "libbt-common",
+ "libbt-protos-lite",
+ "libbtdevice",
+ "libgmock",
+ "liblog",
+ "libosi",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ "libcrypto",
+ "libflatbuffers-cpp",
+ "libprotobuf-cpp-lite",
+ ],
+ sanitize: {
+ address: true,
+ all_undefined: true,
+ cfi: true,
+ integer_overflow: true,
+ scs: true,
+ diag: {
+ undefined : true
+ },
+ },
+}
diff --git a/stack/a2dp/a2dp_api.cc b/stack/a2dp/a2dp_api.cc
index 8723735..fb3abf1 100644
--- a/stack/a2dp/a2dp_api.cc
+++ b/stack/a2dp/a2dp_api.cc
@@ -62,7 +62,7 @@
* Returns Nothing.
*
*****************************************************************************/
-static void a2dp_sdp_cback(uint16_t status) {
+static void a2dp_sdp_cback(tSDP_STATUS status) {
tSDP_DISC_REC* p_rec = NULL;
tSDP_DISC_ATTR* p_attr;
bool found = false;
diff --git a/stack/a2dp/a2dp_sbc_encoder.cc b/stack/a2dp/a2dp_sbc_encoder.cc
index 3fe9bd6..2de3fad 100644
--- a/stack/a2dp/a2dp_sbc_encoder.cc
+++ b/stack/a2dp/a2dp_sbc_encoder.cc
@@ -903,6 +903,23 @@
A2dpCodecConfig::debug_codec_dump(fd);
+ uint8_t codec_info[AVDT_CODEC_SIZE];
+ if (copyOutOtaCodecConfig(codec_info)) {
+ dprintf(fd,
+ " Block length : %d\n",
+ A2DP_GetNumberOfBlocksSbc(codec_info));
+ dprintf(fd,
+ " Number of subbands : %d\n",
+ A2DP_GetNumberOfSubbandsSbc(codec_info));
+ dprintf(fd,
+ " Allocation method : %d\n",
+ A2DP_GetAllocationMethodCodeSbc(codec_info));
+ dprintf(
+ fd,
+ " Bitpool (min/max) : %d / %d\n",
+ A2DP_GetMinBitpoolSbc(codec_info), A2DP_GetMaxBitpoolSbc(codec_info));
+ }
+
dprintf(fd,
" Packet counts (expected/dropped) : %zu / "
"%zu\n",
diff --git a/stack/acl/acl.cc b/stack/acl/acl.cc
index 6613a64..3c8025d 100644
--- a/stack/acl/acl.cc
+++ b/stack/acl/acl.cc
@@ -47,26 +47,3 @@
switch_role_state_ = BTM_ACL_SWKEY_STATE_IDLE;
sca = 0;
}
-
-// When the local device initiates an le ACL disconnect the address
-// should not be re-added to the acceptlist.
-void tACL_CB::AddToIgnoreAutoConnectAfterDisconnect(const RawAddress& bd_addr) {
- if (!ignore_auto_connect_after_disconnect_set_.insert(bd_addr).second) {
- LOG_WARN(
- "Unexpectedly found device address already in ignore auto connect "
- "device:%s",
- PRIVATE_ADDRESS(bd_addr));
- }
-}
-
-// A check and clear mechanism used to determine if the address should be
-// re-added to the acceptlist after an le ACL disconnect is received from a
-// peer.
-bool tACL_CB::CheckAndClearIgnoreAutoConnectAfterDisconnect(
- const RawAddress& bd_addr) {
- return (ignore_auto_connect_after_disconnect_set_.erase(bd_addr) > 0);
-}
-
-void tACL_CB::ClearAllIgnoreAutoConnectAfterDisconnect() {
- ignore_auto_connect_after_disconnect_set_.clear();
-}
diff --git a/stack/acl/acl.h b/stack/acl/acl.h
index 6534064..086669b 100644
--- a/stack/acl/acl.h
+++ b/stack/acl/acl.h
@@ -231,12 +231,7 @@
tHCI_ROLE link_role;
uint8_t switch_role_failed_attempts;
- struct {
- uint8_t lmp_version{0};
- uint16_t lmp_subversion{0};
- uint16_t manufacturer{0};
- bool valid{false};
- } remote_version_info;
+ tREMOTE_VERSION_INFO remote_version_info;
#define BTM_SEC_RS_NOT_PENDING 0 /* Role Switch not in progress */
#define BTM_SEC_RS_PENDING 1 /* Role Switch in progress */
@@ -417,12 +412,4 @@
}
return cnt;
}
-
- private:
- std::unordered_set<RawAddress> ignore_auto_connect_after_disconnect_set_;
-
- public:
- void AddToIgnoreAutoConnectAfterDisconnect(const RawAddress& bd_addr);
- bool CheckAndClearIgnoreAutoConnectAfterDisconnect(const RawAddress& bd_addr);
- void ClearAllIgnoreAutoConnectAfterDisconnect();
};
diff --git a/stack/acl/ble_acl.cc b/stack/acl/ble_acl.cc
index 5ec27ad..a2ae6c1 100644
--- a/stack/acl/ble_acl.cc
+++ b/stack/acl/ble_acl.cc
@@ -126,6 +126,13 @@
uint16_t conn_interval, uint16_t conn_latency, uint16_t conn_timeout,
const RawAddress& local_rpa, const RawAddress& peer_rpa,
uint8_t peer_addr_type) {
+ if (!connection_manager::remove_unconditional_from_shim(
+ address_with_type.bda)) {
+ LOG_WARN(
+ "Unable to remove from legacy connection manager accept list addr:%s",
+ PRIVATE_ADDRESS(address_with_type.bda));
+ }
+
tBLE_BD_ADDR resolved_address_with_type;
const bool is_in_security_db = maybe_resolve_received_address(
address_with_type, &resolved_address_with_type);
diff --git a/stack/acl/btm_acl.cc b/stack/acl/btm_acl.cc
index b690840..02c5988 100644
--- a/stack/acl/btm_acl.cc
+++ b/stack/acl/btm_acl.cc
@@ -49,6 +49,7 @@
#include "main/shim/shim.h"
#include "osi/include/log.h"
#include "stack/acl/acl.h"
+#include "stack/acl/peer_packet_types.h"
#include "stack/btm/btm_dev.h"
#include "stack/btm/btm_int_types.h"
#include "stack/btm/btm_sec.h"
@@ -66,6 +67,9 @@
#include "types/hci_role.h"
#include "types/raw_address.h"
+void BTM_update_version_info(const RawAddress& bd_addr,
+ const remote_version_info& remote_version_info);
+
void gatt_find_in_device_record(const RawAddress& bd_addr,
tBLE_BD_ADDR* address_with_type);
void l2c_link_hci_conn_comp(tHCI_STATUS status, uint16_t handle,
@@ -79,7 +83,8 @@
tACL_CONN* acl_allocate_connection();
tACL_CONN* acl_get_connection_from_handle(uint16_t handle);
tACL_CONN* btm_bda_to_acl(const RawAddress& bda, tBT_TRANSPORT transport);
- tBTM_STATUS btm_set_packet_types(tACL_CONN* p, uint16_t pkt_types);
+ bool change_connection_packet_types(tACL_CONN& link,
+ const uint16_t new_packet_type_bitmask);
void btm_establish_continue(tACL_CONN* p_acl_cb);
void btm_read_remote_features(uint16_t handle);
void btm_set_default_link_policy(tLINK_POLICY settings);
@@ -91,9 +96,14 @@
}
};
+struct RoleChangeView {
+ tHCI_ROLE new_role = HCI_ROLE_UNKNOWN;
+ RawAddress bd_addr;
+};
+
namespace {
StackAclBtmAcl internal_;
-
+std::unique_ptr<RoleChangeView> delayed_role_change_ = nullptr;
const bluetooth::legacy::hci::Interface& GetLegacyHciInterface() {
return bluetooth::legacy::hci::GetInterface();
}
@@ -126,10 +136,8 @@
controller_get_interface()->supports_encryption_pause();
}
-static void btm_acl_chk_peer_pkt_type_support(tACL_CONN* p,
- uint16_t* p_pkt_type);
static void btm_process_remote_ext_features(tACL_CONN* p_acl_cb,
- uint8_t num_read_pages);
+ uint8_t max_page_number);
static void btm_read_failed_contact_counter_timeout(void* data);
static void btm_read_remote_ext_features(uint16_t handle, uint8_t page_number);
static void btm_read_rssi_timeout(void* data);
@@ -366,7 +374,7 @@
"Unable to create duplicate acl when one already exists handle:%hu"
" role:%s transport:%s",
hci_handle, RoleText(link_role).c_str(),
- BtTransportText(transport).c_str());
+ bt_transport_text(transport).c_str());
return;
}
@@ -390,7 +398,7 @@
LOG_DEBUG(
"Created new ACL connection peer:%s role:%s handle:0x%04x transport:%s",
PRIVATE_ADDRESS(bda), RoleText(p_acl->link_role).c_str(), hci_handle,
- BtTransportText(transport).c_str());
+ bt_transport_text(transport).c_str());
btm_set_link_policy(p_acl, btm_cb.acl_cb_.DefaultLinkPolicy());
if (transport == BT_TRANSPORT_LE) {
@@ -781,6 +789,9 @@
p_acl_cb->remote_version_info.manufacturer = manufacturer;
p_acl_cb->remote_version_info.lmp_subversion = lmp_subversion;
p_acl_cb->remote_version_info.valid = true;
+ BTM_update_version_info(p_acl_cb->RemoteAddress(),
+ p_acl_cb->remote_version_info);
+
bluetooth::common::LogRemoteVersionInfo(handle, status, lmp_version,
manufacturer, lmp_subversion);
} else {
@@ -827,10 +838,9 @@
*
******************************************************************************/
void btm_process_remote_ext_features(tACL_CONN* p_acl_cb,
- uint8_t num_read_pages) {
+ uint8_t max_page_number) {
CHECK(p_acl_cb != nullptr);
- if (!p_acl_cb->peer_lmp_feature_valid[0] ||
- !p_acl_cb->peer_lmp_feature_valid[1]) {
+ if (!p_acl_cb->peer_lmp_feature_valid[max_page_number]) {
LOG_WARN(
"Checking remote features but remote feature read is "
"incomplete");
@@ -842,9 +852,14 @@
HCI_SC_HOST_SUPPORTED(p_acl_cb->peer_lmp_feature_pages[1]);
bool role_switch_supported =
HCI_SWITCH_SUPPORTED(p_acl_cb->peer_lmp_feature_pages[0]);
+ bool br_edr_supported =
+ !HCI_BREDR_NOT_SPT_SUPPORTED(p_acl_cb->peer_lmp_feature_pages[0]);
+ bool le_supported =
+ HCI_LE_SPT_SUPPORTED(p_acl_cb->peer_lmp_feature_pages[0]) &&
+ HCI_LE_HOST_SUPPORTED(p_acl_cb->peer_lmp_feature_pages[1]);
btm_sec_set_peer_sec_caps(p_acl_cb->hci_handle, ssp_supported,
- secure_connections_supported,
- role_switch_supported);
+ secure_connections_supported, role_switch_supported,
+ br_edr_supported, le_supported);
}
/*******************************************************************************
@@ -951,7 +966,7 @@
/* Remote controller has no extended features. Process remote controller
supported features (features page 0). */
- btm_process_remote_ext_features(p_acl_cb, 1);
+ btm_process_remote_ext_features(p_acl_cb, 0);
/* Continue with HCI connection establishment */
internal_.btm_establish_continue(p_acl_cb);
@@ -1028,7 +1043,7 @@
LOG_DEBUG("BTM reached last remote extended features page (%d)", page_num);
/* Process the pages */
- btm_process_remote_ext_features(p_acl_cb, (uint8_t)(page_num + 1));
+ btm_process_remote_ext_features(p_acl_cb, max_page);
/* Continue with HCI connection establishment */
internal_.btm_establish_continue(p_acl_cb);
@@ -1054,7 +1069,7 @@
}
/* Process supported features only */
- btm_process_remote_ext_features(p_acl_cb, 1);
+ btm_process_remote_ext_features(p_acl_cb, 0);
/* Continue HCI connection establishment */
internal_.btm_establish_continue(p_acl_cb);
@@ -1071,16 +1086,24 @@
* Returns void
*
******************************************************************************/
-void StackAclBtmAcl::btm_establish_continue(tACL_CONN* p_acl_cb) {
- if (p_acl_cb->transport == BT_TRANSPORT_BR_EDR) {
+void StackAclBtmAcl::btm_establish_continue(tACL_CONN* p_acl) {
+ CHECK(p_acl != nullptr);
+
+ if (p_acl->is_transport_br_edr()) {
/* For now there are a some devices that do not like sending */
/* commands events and data at the same time. */
/* Set the packet types to the default allowed by the device */
- internal_.btm_set_packet_types(p_acl_cb,
- btm_cb.acl_cb_.DefaultPacketTypes());
- btm_set_link_policy(p_acl_cb, btm_cb.acl_cb_.DefaultLinkPolicy());
+ const uint16_t default_packet_type_mask =
+ btm_cb.acl_cb_.DefaultPacketTypes();
+ if (!internal_.change_connection_packet_types(*p_acl,
+ default_packet_type_mask)) {
+ LOG_ERROR("Unable to change connection packet type types:%04x address:%s",
+ default_packet_type_mask,
+ PRIVATE_ADDRESS(p_acl->RemoteAddress()));
+ }
+ btm_set_link_policy(p_acl, btm_cb.acl_cb_.DefaultLinkPolicy());
}
- NotifyAclLinkUp(*p_acl_cb);
+ NotifyAclLinkUp(*p_acl);
}
void btm_establish_continue_from_address(const RawAddress& bda,
@@ -1104,14 +1127,15 @@
******************************************************************************/
tBTM_STATUS BTM_GetLinkSuperTout(const RawAddress& remote_bda,
uint16_t* p_timeout) {
- tACL_CONN* p = internal_.btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
- if (p != (tACL_CONN*)NULL) {
- *p_timeout = p->link_super_tout;
- return (BTM_SUCCESS);
+ CHECK(p_timeout != nullptr);
+ const tACL_CONN* p_acl =
+ internal_.btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
+ if (p_acl == nullptr) {
+ LOG_WARN("Unable to find active acl");
+ return BTM_UNKNOWN_ADDR;
}
- LOG_WARN("Unable to find active acl");
- /* If here, no BD Addr found */
- return (BTM_UNKNOWN_ADDR);
+ *p_timeout = p_acl->link_super_tout;
+ return BTM_SUCCESS;
}
/*******************************************************************************
@@ -1125,31 +1149,28 @@
******************************************************************************/
tBTM_STATUS BTM_SetLinkSuperTout(const RawAddress& remote_bda,
uint16_t timeout) {
- tACL_CONN* p = internal_.btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
- if (p != (tACL_CONN*)NULL) {
- p->link_super_tout = timeout;
-
- /* Only send if current role is Central; 2.0 spec requires this */
- if (p->link_role == HCI_ROLE_CENTRAL) {
- LOG_DEBUG("Setting supervison timeout:%.2fms bd_addr:%s",
- supervision_timeout_to_seconds(timeout),
- PRIVATE_ADDRESS(remote_bda));
-
- btsnd_hcic_write_link_super_tout(LOCAL_BR_EDR_CONTROLLER_ID,
- p->hci_handle, timeout);
- return (BTM_CMD_STARTED);
- } else {
- LOG_WARN(
- "Role is peripheral so unable to set supervison timeout:%.2fms "
- "bd_addr:%s",
- supervision_timeout_to_seconds(timeout), PRIVATE_ADDRESS(remote_bda));
- return (BTM_SUCCESS);
- }
+ tACL_CONN* p_acl = internal_.btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
+ if (p_acl == nullptr) {
+ LOG_WARN("Unable to find active acl");
+ return BTM_UNKNOWN_ADDR;
}
- LOG_WARN("Unable to find active acl");
- /* If here, no BD Addr found */
- return (BTM_UNKNOWN_ADDR);
+ /* Only send if current role is Central; 2.0 spec requires this */
+ if (p_acl->link_role == HCI_ROLE_CENTRAL) {
+ p_acl->link_super_tout = timeout;
+ btsnd_hcic_write_link_super_tout(LOCAL_BR_EDR_CONTROLLER_ID,
+ p_acl->hci_handle, timeout);
+ LOG_DEBUG("Set supervision timeout:%.2fms bd_addr:%s",
+ supervision_timeout_to_seconds(timeout),
+ PRIVATE_ADDRESS(remote_bda));
+ return BTM_CMD_STARTED;
+ } else {
+ LOG_WARN(
+ "Role is peripheral so unable to set supervision timeout:%.2fms "
+ "bd_addr:%s",
+ supervision_timeout_to_seconds(timeout), PRIVATE_ADDRESS(remote_bda));
+ return BTM_SUCCESS;
+ }
}
bool BTM_IsAclConnectionUp(const RawAddress& remote_bda,
@@ -1369,6 +1390,13 @@
tHCI_ROLE new_role) {
tACL_CONN* p_acl = internal_.btm_bda_to_acl(bd_addr, BT_TRANSPORT_BR_EDR);
if (p_acl == nullptr) {
+ // If we get a role change before connection complete, we cache the new
+ // role here and then propagate it when ACL Link is created.
+ RoleChangeView role_change;
+ role_change.new_role = new_role;
+ role_change.bd_addr = bd_addr;
+ delayed_role_change_ =
+ std::make_unique<RoleChangeView>(std::move(role_change));
LOG_WARN("Unable to find active acl");
return;
}
@@ -1436,7 +1464,7 @@
/*******************************************************************************
*
- * Function btm_set_packet_types
+ * Function change_connection_packet_types
*
* Description This function sets the packet types used for a specific
* ACL connection. It is called internally by btm_acl_created
@@ -1445,26 +1473,44 @@
* Returns status of the operation
*
******************************************************************************/
-tBTM_STATUS StackAclBtmAcl::btm_set_packet_types(tACL_CONN* p,
- uint16_t pkt_types) {
- uint16_t temp_pkt_types;
- /* Save in the ACL control blocks, types that we support */
- temp_pkt_types = (pkt_types & BTM_ACL_SUPPORTED_PKTS_MASK &
- btm_cb.acl_cb_.btm_acl_pkt_types_supported);
+bool StackAclBtmAcl::change_connection_packet_types(
+ tACL_CONN& link, const uint16_t new_packet_type_mask) {
+ // Start with the default configured packet types
+ const uint16_t default_packet_type_mask = btm_cb.acl_cb_.DefaultPacketTypes();
+
+ uint16_t packet_type_mask =
+ default_packet_type_mask &
+ (new_packet_type_mask & BTM_ACL_SUPPORTED_PKTS_MASK);
/* OR in any exception packet types if at least 2.0 version of spec */
- temp_pkt_types |= ((pkt_types & BTM_ACL_EXCEPTION_PKTS_MASK) |
- (btm_cb.acl_cb_.btm_acl_pkt_types_supported &
- BTM_ACL_EXCEPTION_PKTS_MASK));
+ packet_type_mask |=
+ ((new_packet_type_mask & BTM_ACL_EXCEPTION_PKTS_MASK) |
+ (BTM_ACL_EXCEPTION_PKTS_MASK & default_packet_type_mask));
/* Exclude packet types not supported by the peer */
- btm_acl_chk_peer_pkt_type_support(p, &temp_pkt_types);
+ if (link.peer_lmp_feature_valid[0]) {
+ PeerPacketTypes peer_packet_types(link.peer_lmp_feature_pages[0]);
+ packet_type_mask &= peer_packet_types.acl.supported;
+ packet_type_mask |= peer_packet_types.acl.unsupported;
+ } else {
+ LOG_INFO(
+ "Unable to include remote supported packet types as read feature "
+ "incomplete");
+ LOG_INFO("TIP: Maybe wait until read feature complete beforehand");
+ }
- LOG_DEBUG("Setting link packet types:0x%04x", pkt_types);
- btsnd_hcic_change_conn_type(p->hci_handle, temp_pkt_types);
- p->pkt_types_mask = temp_pkt_types;
+ if (packet_type_mask == 0) {
+ LOG_WARN("Unable to send controller illegal change packet mask:0x%04x",
+ packet_type_mask);
+ return false;
+ }
- return (BTM_CMD_STARTED);
+ link.pkt_types_mask = packet_type_mask;
+ bluetooth::legacy::hci::GetInterface().ChangeConnectionPacketType(
+ link.Handle(), link.pkt_types_mask);
+ LOG_DEBUG("Started change connection packet type:0x%04x address:%s",
+ link.pkt_types_mask, PRIVATE_ADDRESS(link.RemoteAddress()));
+ return true;
}
void btm_set_packet_types_from_address(const RawAddress& bd_addr,
@@ -1475,9 +1521,9 @@
return;
}
- tBTM_STATUS status = internal_.btm_set_packet_types(p_acl, pkt_types);
- if (status != BTM_CMD_STARTED) {
- LOG_ERROR("Unable to set packet types from address");
+ if (!internal_.change_connection_packet_types(*p_acl, pkt_types)) {
+ LOG_ERROR("Unable to change connection packet type types:%04x address:%s",
+ pkt_types, PRIVATE_ADDRESS(bd_addr));
}
}
@@ -2036,7 +2082,7 @@
if (p_acl->Handle() == HCI_INVALID_HANDLE) {
LOG_WARN("Cannot remove unknown acl bd_addr:%s transport:%s",
- PRIVATE_ADDRESS(bd_addr), BtTransportText(transport).c_str());
+ PRIVATE_ADDRESS(bd_addr), bt_transport_text(transport).c_str());
return BTM_UNKNOWN_ADDR;
}
@@ -2044,7 +2090,7 @@
LOG_DEBUG(
"Delay disconnect until role switch is complete bd_addr:%s "
"transport:%s",
- PRIVATE_ADDRESS(bd_addr), BtTransportText(transport).c_str());
+ PRIVATE_ADDRESS(bd_addr), bt_transport_text(transport).c_str());
p_acl->rs_disc_pending = BTM_SEC_DISC_PENDING;
return BTM_SUCCESS;
}
@@ -2151,6 +2197,16 @@
*
******************************************************************************/
void btm_acl_paging(BT_HDR* p, const RawAddress& bda) {
+ // This function is called by the device initiating the connection.
+ // If no role change is requested from the remote device, we want
+ // to classify the connection initiator as the central device.
+ if (delayed_role_change_ == nullptr) {
+ RoleChangeView role_change;
+ role_change.bd_addr = bda;
+ role_change.new_role = HCI_ROLE_CENTRAL;
+ delayed_role_change_ =
+ std::make_unique<RoleChangeView>(std::move(role_change));
+ }
if (!BTM_IsAclConnectionUp(bda, BT_TRANSPORT_BR_EDR)) {
VLOG(1) << "connecting_bda: " << btm_cb.connecting_bda;
if (btm_cb.paging && bda == btm_cb.connecting_bda) {
@@ -2181,55 +2237,6 @@
do_in_main_thread(FROM_HERE, base::Bind(bta_sys_notify_collision, bda));
}
-/*******************************************************************************
- *
- * Function btm_acl_chk_peer_pkt_type_support
- *
- * Description Check if peer supports requested packets
- *
- ******************************************************************************/
-void btm_acl_chk_peer_pkt_type_support(tACL_CONN* p, uint16_t* p_pkt_type) {
- if (!p->peer_lmp_feature_valid[0]) {
- LOG_ERROR("Remote feature reads are incomplete");
- *p_pkt_type = 0;
- return;
- }
-
- /* 3 and 5 slot packets? */
- if (!HCI_3_SLOT_PACKETS_SUPPORTED(p->peer_lmp_feature_pages[0]))
- *p_pkt_type &= ~(HCI_PKT_TYPES_MASK_DH3 + HCI_PKT_TYPES_MASK_DM3);
-
- if (!HCI_5_SLOT_PACKETS_SUPPORTED(p->peer_lmp_feature_pages[0]))
- *p_pkt_type &= ~(HCI_PKT_TYPES_MASK_DH5 + HCI_PKT_TYPES_MASK_DM5);
-
- /* 2 and 3 MPS support? */
- if (!HCI_EDR_ACL_2MPS_SUPPORTED(p->peer_lmp_feature_pages[0]))
- /* Not supported. Add 'not_supported' mask for all 2MPS packet types */
- *p_pkt_type |= (HCI_PKT_TYPES_MASK_NO_2_DH1 + HCI_PKT_TYPES_MASK_NO_2_DH3 +
- HCI_PKT_TYPES_MASK_NO_2_DH5);
-
- if (!HCI_EDR_ACL_3MPS_SUPPORTED(p->peer_lmp_feature_pages[0]))
- /* Not supported. Add 'not_supported' mask for all 3MPS packet types */
- *p_pkt_type |= (HCI_PKT_TYPES_MASK_NO_3_DH1 + HCI_PKT_TYPES_MASK_NO_3_DH3 +
- HCI_PKT_TYPES_MASK_NO_3_DH5);
-
- /* EDR 3 and 5 slot support? */
- if (HCI_EDR_ACL_2MPS_SUPPORTED(p->peer_lmp_feature_pages[0]) ||
- HCI_EDR_ACL_3MPS_SUPPORTED(p->peer_lmp_feature_pages[0])) {
- if (!HCI_3_SLOT_EDR_ACL_SUPPORTED(p->peer_lmp_feature_pages[0]))
- /* Not supported. Add 'not_supported' mask for all 3-slot EDR packet types
- */
- *p_pkt_type |=
- (HCI_PKT_TYPES_MASK_NO_2_DH3 + HCI_PKT_TYPES_MASK_NO_3_DH3);
-
- if (!HCI_5_SLOT_EDR_ACL_SUPPORTED(p->peer_lmp_feature_pages[0]))
- /* Not supported. Add 'not_supported' mask for all 5-slot EDR packet types
- */
- *p_pkt_type |=
- (HCI_PKT_TYPES_MASK_NO_2_DH5 + HCI_PKT_TYPES_MASK_NO_3_DH5);
- }
-}
-
bool BTM_BLE_IS_RESOLVE_BDA(const RawAddress& x) {
return ((x.address)[0] & BLE_RESOLVE_ADDR_MASK) == BLE_RESOLVE_ADDR_MSB;
}
@@ -2540,7 +2547,13 @@
void on_acl_br_edr_connected(const RawAddress& bda, uint16_t handle,
uint8_t enc_mode) {
- btm_sec_connected(bda, handle, HCI_SUCCESS, enc_mode);
+ if (delayed_role_change_ != nullptr && delayed_role_change_->bd_addr == bda) {
+ btm_sec_connected(bda, handle, HCI_SUCCESS, enc_mode,
+ delayed_role_change_->new_role);
+ } else {
+ btm_sec_connected(bda, handle, HCI_SUCCESS, enc_mode);
+ }
+ delayed_role_change_ = nullptr;
btm_acl_set_paging(false);
l2c_link_hci_conn_comp(HCI_SUCCESS, handle, bda);
constexpr uint16_t link_supervision_timeout = 8000;
@@ -2566,8 +2579,13 @@
void on_acl_br_edr_failed(const RawAddress& bda, tHCI_STATUS status) {
ASSERT_LOG(status != HCI_SUCCESS,
"Successful connection entering failing code path");
-
- btm_sec_connected(bda, HCI_INVALID_HANDLE, status, false);
+ if (delayed_role_change_ != nullptr && delayed_role_change_->bd_addr == bda) {
+ btm_sec_connected(bda, HCI_INVALID_HANDLE, status, false,
+ delayed_role_change_->new_role);
+ } else {
+ btm_sec_connected(bda, HCI_INVALID_HANDLE, status, false);
+ }
+ delayed_role_change_ = nullptr;
btm_acl_set_paging(false);
l2c_link_hci_conn_comp(status, HCI_INVALID_HANDLE, bda);
}
@@ -2692,12 +2710,13 @@
constexpr uint16_t kDataPacketEventBle =
(BT_EVT_TO_LM_HCI_ACL | LOCAL_BLE_CONTROLLER_ID);
-void acl_send_data_packet_br_edr([[maybe_unused]] const RawAddress& bd_addr,
- BT_HDR* p_buf) {
+void acl_send_data_packet_br_edr(const RawAddress& bd_addr, BT_HDR* p_buf) {
if (bluetooth::shim::is_gd_acl_enabled()) {
tACL_CONN* p_acl = internal_.btm_bda_to_acl(bd_addr, BT_TRANSPORT_BR_EDR);
if (p_acl == nullptr) {
- LOG_WARN("Acl br_edr data write for unknown device");
+ LOG_WARN("Acl br_edr data write for unknown device:%s",
+ PRIVATE_ADDRESS(bd_addr));
+ osi_free(p_buf);
return;
}
return bluetooth::shim::ACL_WriteData(p_acl->hci_handle, p_buf);
@@ -2709,7 +2728,9 @@
if (bluetooth::shim::is_gd_acl_enabled()) {
tACL_CONN* p_acl = internal_.btm_bda_to_acl(bd_addr, BT_TRANSPORT_LE);
if (p_acl == nullptr) {
- LOG_WARN("Acl le data write for unknown device");
+ LOG_WARN("Acl le data write for unknown device:%s",
+ PRIVATE_ADDRESS(bd_addr));
+ osi_free(p_buf);
return;
}
return bluetooth::shim::ACL_WriteData(p_acl->hci_handle, p_buf);
@@ -2744,7 +2765,8 @@
gatt_find_in_device_record(bd_addr, &address_with_type);
LOG_DEBUG("Creating le connection to:%s",
address_with_type.ToString().c_str());
- bluetooth::shim::ACL_AcceptLeConnectionFrom(address_with_type);
+ bluetooth::shim::ACL_AcceptLeConnectionFrom(address_with_type,
+ /* is_direct */ true);
return true;
}
return connection_manager::direct_connect_add(id, bd_addr);
@@ -2781,6 +2803,8 @@
void acl_packets_completed(uint16_t handle, uint16_t credits) {
l2c_packets_completed(handle, credits);
+ bluetooth::hci::IsoManager::GetInstance()->HandleGdNumComplDataPkts(handle,
+ credits);
}
static void acl_parse_num_completed_pkts(uint8_t* p, uint8_t evt_len) {
@@ -2816,8 +2840,43 @@
bluetooth::hci::IsoManager::GetInstance()->HandleNumComplDataPkts(p, evt_len);
}
+void acl_process_supported_features(uint16_t handle, uint64_t features) {
+ ASSERT_LOG(bluetooth::shim::is_gd_acl_enabled(),
+ "Should only be called when gd_acl enabled");
+
+ tACL_CONN* p_acl = internal_.acl_get_connection_from_handle(handle);
+ if (p_acl == nullptr) {
+ LOG_WARN("Unable to find active acl");
+ return;
+ }
+ const uint8_t current_page_number = 0;
+
+ memcpy(p_acl->peer_lmp_feature_pages[current_page_number],
+ (uint8_t*)&features, sizeof(uint64_t));
+ p_acl->peer_lmp_feature_valid[current_page_number] = true;
+
+ LOG_DEBUG(
+ "Copied supported feature pages handle:%hu current_page_number:%hhu "
+ "features:%s",
+ handle, current_page_number,
+ bd_features_text(p_acl->peer_lmp_feature_pages[current_page_number])
+ .c_str());
+
+ if ((HCI_LMP_EXTENDED_SUPPORTED(p_acl->peer_lmp_feature_pages[0])) &&
+ (controller_get_interface()
+ ->supports_reading_remote_extended_features())) {
+ LOG_DEBUG("Waiting for remote extended feature response to arrive");
+ } else {
+ LOG_DEBUG("No more remote features outstanding so notify upper layer");
+ NotifyAclFeaturesReadComplete(*p_acl, current_page_number);
+ }
+}
+
void acl_process_extended_features(uint16_t handle, uint8_t current_page_number,
uint8_t max_page_number, uint64_t features) {
+ ASSERT_LOG(bluetooth::shim::is_gd_acl_enabled(),
+ "Should only be called when gd_acl enabled");
+
if (current_page_number > HCI_EXT_FEATURES_PAGE_MAX) {
LOG_WARN("Unable to process current_page_number:%hhu", current_page_number);
return;
@@ -2862,16 +2921,34 @@
return HCI_LMP_TRANSPNT_SUPPORTED(p_acl->peer_lmp_feature_pages[0]);
}
-void acl_add_to_ignore_auto_connect_after_disconnect(
- const RawAddress& bd_addr) {
- btm_cb.acl_cb_.AddToIgnoreAutoConnectAfterDisconnect(bd_addr);
-}
+/**
+ * Confusingly, immutable device features are stored in the
+ * ephemeral connection data structure while connection security
+ * is stored in the device record.
+ *
+ * This HACK allows legacy security protocols to work as intended under
+ * those conditions.
+ */
+void HACK_acl_check_sm4(tBTM_SEC_DEV_REC& record) {
+ // Return if we already know this info
+ if ((record.sm4 & BTM_SM4_TRUE) != BTM_SM4_UNKNOWN) return;
-bool acl_check_and_clear_ignore_auto_connect_after_disconnect(
- const RawAddress& bd_addr) {
- return btm_cb.acl_cb_.CheckAndClearIgnoreAutoConnectAfterDisconnect(bd_addr);
-}
+ tACL_CONN* p_acl =
+ internal_.btm_bda_to_acl(record.RemoteAddress(), BT_TRANSPORT_BR_EDR);
+ if (p_acl == nullptr) {
+ LOG_WARN("Unable to find active acl for authentication device:%s",
+ PRIVATE_ADDRESS(record.RemoteAddress()));
+ }
-void acl_clear_all_ignore_auto_connect_after_disconnect() {
- btm_cb.acl_cb_.ClearAllIgnoreAutoConnectAfterDisconnect();
+ // If we have not received the SSP feature record
+ // we have to wait
+ if (!p_acl->peer_lmp_feature_valid[1]) {
+ LOG_WARN(
+ "Authentication started without extended feature page 1 request "
+ "response");
+ return;
+ }
+ record.sm4 = (HCI_SSP_HOST_SUPPORTED(p_acl->peer_lmp_feature_pages[1]))
+ ? BTM_SM4_TRUE
+ : BTM_SM4_KNOWN;
}
diff --git a/stack/acl/peer_packet_types.h b/stack/acl/peer_packet_types.h
new file mode 100644
index 0000000..a16a18b
--- /dev/null
+++ b/stack/acl/peer_packet_types.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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"
+#include "stack/include/hcidefs.h"
+
+/**
+ * Create a bitmask of packet types from the remote feature
+ */
+class PeerPacketTypes {
+ public:
+ struct {
+ uint16_t supported{0};
+ uint16_t unsupported{0};
+ } acl, sco;
+
+ PeerPacketTypes(const BD_FEATURES& features) {
+ /* 3 and 5 slot packets? */
+ if (HCI_3_SLOT_PACKETS_SUPPORTED(features))
+ acl.supported |= (HCI_PKT_TYPES_MASK_DH3 | HCI_PKT_TYPES_MASK_DM3);
+
+ if (HCI_5_SLOT_PACKETS_SUPPORTED(features))
+ acl.supported |= HCI_PKT_TYPES_MASK_DH5 | HCI_PKT_TYPES_MASK_DM5;
+
+ /* 2 and 3 MPS support? */
+ if (!HCI_EDR_ACL_2MPS_SUPPORTED(features))
+ /* Not supported. Add 'not_supported' mask for all 2MPS packet types */
+ acl.unsupported |=
+ (HCI_PKT_TYPES_MASK_NO_2_DH1 | HCI_PKT_TYPES_MASK_NO_2_DH3 |
+ HCI_PKT_TYPES_MASK_NO_2_DH5);
+
+ if (!HCI_EDR_ACL_3MPS_SUPPORTED(features))
+ /* Not supported. Add 'not_supported' mask for all 3MPS packet types */
+ acl.unsupported |=
+ (HCI_PKT_TYPES_MASK_NO_3_DH1 | HCI_PKT_TYPES_MASK_NO_3_DH3 |
+ HCI_PKT_TYPES_MASK_NO_3_DH5);
+
+ /* EDR 3 and 5 slot support? */
+ if (HCI_EDR_ACL_2MPS_SUPPORTED(features) ||
+ HCI_EDR_ACL_3MPS_SUPPORTED(features)) {
+ if (!HCI_3_SLOT_EDR_ACL_SUPPORTED(features))
+ /* Not supported. Add 'not_supported' mask for all 3-slot EDR packet
+ * types
+ */
+ acl.unsupported |=
+ (HCI_PKT_TYPES_MASK_NO_2_DH3 | HCI_PKT_TYPES_MASK_NO_3_DH3);
+
+ if (!HCI_5_SLOT_EDR_ACL_SUPPORTED(features))
+ /* Not supported. Add 'not_supported' mask for all 5-slot EDR packet
+ * types
+ */
+ acl.unsupported |=
+ (HCI_PKT_TYPES_MASK_NO_2_DH5 | HCI_PKT_TYPES_MASK_NO_3_DH5);
+ }
+ }
+};
diff --git a/stack/avct/avct_int.h b/stack/avct/avct_int.h
index 54f89be..3377d1e 100644
--- a/stack/avct/avct_int.h
+++ b/stack/avct/avct_int.h
@@ -66,7 +66,6 @@
uint8_t allocated; /* 0, not allocated. index+1, otherwise. */
uint8_t state; /* The state machine state */
uint8_t ch_state; /* L2CAP channel state */
- uint8_t ch_flags; /* L2CAP configuration flags */
} tAVCT_SCB;
/* link control block type */
@@ -77,7 +76,6 @@
uint8_t allocated; /* 0, not allocated. index+1, otherwise. */
uint8_t state; /* The state machine state */
uint8_t ch_state; /* L2CAP channel state */
- uint8_t ch_flags; /* L2CAP configuration flags */
BT_HDR* p_rx_msg; /* Message being reassembled */
uint16_t conflict_lcid; /* L2CAP channel LCID */
RawAddress peer_addr; /* BD address of peer */
@@ -93,7 +91,6 @@
uint8_t allocated; /* 0, not allocated. index+1, otherwise. */
uint8_t state; /* The state machine state */
uint8_t ch_state; /* L2CAP channel state */
- uint8_t ch_flags; /* L2CAP configuration flags */
BT_HDR* p_tx_msg; /* Message to be sent - in case the browsing channel is not
open when MsgReg is called */
uint8_t ch_close; /* CCB index+1, if CCB initiated channel close */
diff --git a/stack/avdt/avdt_int.h b/stack/avdt/avdt_int.h
index ce5a0db..fcbdcac 100644
--- a/stack/avdt/avdt_int.h
+++ b/stack/avdt/avdt_int.h
@@ -234,6 +234,7 @@
AVDT_SCB_SND_SETCONFIG_REQ,
AVDT_SCB_SND_SETCONFIG_REJ,
AVDT_SCB_SND_SETCONFIG_RSP,
+ AVDT_SCB_SND_SNK_DELAY_RPT_REQ,
AVDT_SCB_SND_TC_CLOSE,
AVDT_SCB_CB_ERR,
AVDT_SCB_CONG_STATE,
@@ -496,6 +497,7 @@
uint8_t curr_evt; // current event; set only by the state machine
bool cong; // True if the media transport channel is congested
uint8_t close_code; // Error code received in close response
+ bool curr_stream; // True if the SCB is the current stream, False otherwise
private:
uint8_t scb_handle_; // Unique handle for this AvdtpScb entry
@@ -910,6 +912,7 @@
extern void avdt_scb_snd_setconfig_req(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
extern void avdt_scb_snd_setconfig_rej(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
extern void avdt_scb_snd_setconfig_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_snk_delay_rpt_req(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
extern void avdt_scb_snd_tc_close(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
extern void avdt_scb_cb_err(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
extern void avdt_scb_cong_state(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data);
diff --git a/stack/avdt/avdt_scb.cc b/stack/avdt/avdt_scb.cc
index c1c0de4..6f6cf97 100644
--- a/stack/avdt/avdt_scb.cc
+++ b/stack/avdt/avdt_scb.cc
@@ -112,6 +112,7 @@
avdt_scb_snd_setconfig_req,
avdt_scb_snd_setconfig_rej,
avdt_scb_snd_setconfig_rsp,
+ avdt_scb_snd_snk_delay_rpt_req,
avdt_scb_snd_tc_close,
avdt_scb_cb_err,
avdt_scb_cong_state,
@@ -158,7 +159,7 @@
/* API_GETCONFIG_RSP_EVT */
{AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* API_SETCONFIG_RSP_EVT */
- {AVDT_SCB_SND_SETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ {AVDT_SCB_SND_SETCONFIG_RSP, AVDT_SCB_SND_SNK_DELAY_RPT_REQ, AVDT_SCB_CONF_ST},
/* API_SETCONFIG_REJ_EVT */
{AVDT_SCB_SND_SETCONFIG_REJ, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* API_OPEN_RSP_EVT */
@@ -758,7 +759,6 @@
void avdt_scb_event(AvdtpScb* p_scb, uint8_t event, tAVDT_SCB_EVT* p_data) {
tAVDT_SCB_ST_TBL state_table;
uint8_t action;
- int i;
#if (AVDT_DEBUG == TRUE)
AVDT_TRACE_EVENT(
@@ -766,6 +766,36 @@
__func__, avdt_scb_to_hdl(p_scb), event, avdt_scb_evt_str[event],
avdt_scb_st_str[p_scb->state], p_scb, p_scb->stream_config.scb_index);
#endif
+
+ /* Check that we only send AVDT_SCB_API_WRITE_REQ_EVT to the active stream
+ * device */
+ uint8_t num_st_streams = 0;
+ int ccb_index = -1;
+ int scb_index = -1;
+
+ for (int i = 0; i < AVDT_NUM_LINKS; i++) {
+ for (int j = 0; j < AVDT_NUM_SEPS; j++) {
+ AvdtpScb* p_avdt_scb = &avdtp_cb.ccb[i].scb[j];
+ if (p_avdt_scb->allocated &&
+ avdt_scb_st_tbl[p_avdt_scb->state] == avdt_scb_st_stream) {
+ num_st_streams++;
+ ccb_index = i;
+ scb_index = j;
+ } else {
+ p_avdt_scb->curr_stream = false;
+ }
+ }
+ }
+
+ if (num_st_streams == 1) {
+ avdtp_cb.ccb[ccb_index].scb[scb_index].curr_stream = true;
+ } else if (num_st_streams > 1 && !p_scb->curr_stream &&
+ event == AVDT_SCB_API_WRITE_REQ_EVT) {
+ AVDT_TRACE_ERROR("%s: ignore AVDT_SCB_API_WRITE_REQ_EVT", __func__);
+ avdt_scb_free_pkt(p_scb, p_data);
+ return;
+ }
+
/* set current event */
p_scb->curr_evt = event;
@@ -778,7 +808,7 @@
}
/* execute action functions */
- for (i = 0; i < AVDT_SCB_ACTIONS; i++) {
+ for (int i = 0; i < AVDT_SCB_ACTIONS; i++) {
action = state_table[event][i];
if (action != AVDT_SCB_IGNORE) {
(*avdtp_cb.p_scb_act[action])(p_scb, p_data);
diff --git a/stack/avdt/avdt_scb_act.cc b/stack/avdt/avdt_scb_act.cc
index 704a665..123a266 100644
--- a/stack/avdt/avdt_scb_act.cc
+++ b/stack/avdt/avdt_scb_act.cc
@@ -644,11 +644,42 @@
/*******************************************************************************
*
+ * Function avdt_scb_snd_snk_delay_rpt_req
+ *
+ * Description This function sends the delay report request once it is sink
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_snd_snk_delay_rpt_req(AvdtpScb* p_scb,
+ UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
+ if (p_scb->p_ccb == NULL) {
+ return;
+ }
+
+ // In sink mode, report a fixed delay value when this device is the sink
+ // side. Delay value in this function is in unit of 1/10ms.
+ if (p_scb->stream_config.tsep != AVDT_TSEP_SNK) {
+ return;
+ }
+
+ tAVDT_SCB_EVT evt;
+ evt.apidelay.hdr.seid = p_scb->peer_seid;
+ evt.apidelay.delay = AVDT_SINK_DELAY_MS * 10;
+ avdt_scb_event(p_scb, AVDT_SCB_API_DELAY_RPT_REQ_EVT, &evt);
+}
+
+/*******************************************************************************
+ *
* Function avdt_scb_hdl_setconfig_rsp
*
* Description This function sends the SCB an AVDT_SCB_API_OPEN_REQ_EVT
* to initiate sending of an open command message.
*
+ * This function sends the SCB an AVDT_SCB_API_DELAY_RPT_REQ_EVT
+ * to initiate sending of delay report command message only
+ * when the endpoint takes sink role.
+ *
* Returns Nothing.
*
******************************************************************************/
@@ -660,6 +691,10 @@
/* save configuration */
p_scb->curr_cfg = p_scb->req_cfg;
+ // In sink mode, report delay value when this device initiates the connection.
+ // Delay reporting is sent before open request (i.e., in configured state).
+ avdt_scb_snd_snk_delay_rpt_req(p_scb, p_data);
+
/* initiate open */
single.seid = p_scb->peer_seid;
tAVDT_SCB_EVT avdt_scb_evt;
@@ -805,8 +840,10 @@
*
******************************************************************************/
void avdt_scb_snd_delay_rpt_req(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
- avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_DELAY_RPT,
- (tAVDT_MSG*)&p_data->apidelay);
+ if (p_scb->stream_config.cfg.psc_mask & AVDT_PSC_DELAY_RPT) {
+ avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_DELAY_RPT,
+ (tAVDT_MSG*)&p_data->apidelay);
+ }
}
/*******************************************************************************
diff --git a/stack/avrc/avrc_api.cc b/stack/avrc/avrc_api.cc
index fac9dbe..432cae0 100644
--- a/stack/avrc/avrc_api.cc
+++ b/stack/avrc/avrc_api.cc
@@ -633,9 +633,10 @@
tAVRC_MSG_VENDOR* p_msg = &msg.vendor;
if (cr == AVCT_CMD && (p_pkt->layer_specific & AVCT_DATA_CTRL &&
- AVRC_PACKET_LEN < sizeof(p_pkt->len))) {
- /* Ignore the invalid AV/C command frame */
- p_drop_msg = "dropped - too long AV/C cmd frame size";
+ p_pkt->len > AVRC_PACKET_LEN)) {
+ android_errorWriteLog(0x534e4554, "177611958");
+ AVRC_TRACE_WARNING("%s: Command length %d too long: must be at most %d",
+ __func__, p_pkt->len, AVRC_PACKET_LEN);
osi_free(p_pkt);
return;
}
diff --git a/stack/avrc/avrc_sdp.cc b/stack/avrc/avrc_sdp.cc
index 42c6cbe..a07b036 100644
--- a/stack/avrc/avrc_sdp.cc
+++ b/stack/avrc/avrc_sdp.cc
@@ -54,7 +54,7 @@
* Returns Nothing.
*
*****************************************************************************/
-static void avrc_sdp_cback(uint16_t status) {
+static void avrc_sdp_cback(tSDP_STATUS status) {
AVRC_TRACE_API("%s status: %d", __func__, status);
/* reset service_uuid, so can start another find service */
diff --git a/stack/btm/btm_ble.cc b/stack/btm/btm_ble.cc
index 9c1e104..9ccc8d9 100644
--- a/stack/btm/btm_ble.cc
+++ b/stack/btm/btm_ble.cc
@@ -685,6 +685,12 @@
return BTM_ILLEGAL_VALUE;
}
+ tx_pdu_length = std::min<uint16_t>(
+ tx_pdu_length,
+ controller_get_interface()->get_ble_maximum_tx_data_length());
+ tx_time = std::min<uint16_t>(
+ tx_time, controller_get_interface()->get_ble_maximum_tx_time());
+
btsnd_hcic_ble_set_data_length(hci_handle, tx_pdu_length, tx_time);
return BTM_SUCCESS;
@@ -1778,7 +1784,7 @@
if (p_dev_rec == NULL) {
BTM_TRACE_ERROR("%s: p_dev_rec is NULL", __func__);
android_errorWriteLog(0x534e4554, "120612744");
- return 0;
+ return BTM_SUCCESS;
}
BTM_TRACE_DEBUG(
"evt=SMP_COMPLT_EVT before update sec_level=0x%x sec_flags=0x%x",
diff --git a/stack/btm/btm_ble_adv_filter.cc b/stack/btm/btm_ble_adv_filter.cc
index 46b14d7..6600d18 100644
--- a/stack/btm/btm_ble_adv_filter.cc
+++ b/stack/btm/btm_ble_adv_filter.cc
@@ -22,6 +22,7 @@
#include "bt_types.h"
#include "btm_ble_api.h"
+#include "btm_dev.h"
#include "btm_int.h"
#include "btu.h"
#include "device/include/controller.h"
@@ -36,7 +37,8 @@
#include <vector>
#include <base/bind.h>
-#include <base/bind_helpers.h>
+
+#include "bind_helpers.h"
extern tBTM_CB btm_cb;
@@ -86,6 +88,14 @@
return cmn_ble_vsc_cb.filter_support != 0 && cmn_ble_vsc_cb.max_filter != 0;
}
+static bool is_empty_128bit(const std::array<uint8_t, 16> data) {
+ int i, len = 16;
+ for (i = 0; i < len; i++) {
+ if (data[i] != (uint8_t)0) return false;
+ }
+ return true;
+}
+
/*******************************************************************************
*
* Function btm_ble_ocf_to_condtype
@@ -149,8 +159,10 @@
return;
}
+ tBTM_STATUS btm_status = (status == 0) ? BTM_SUCCESS : BTM_ERR_PROCESSING;
+
if (op_subcode == BTM_BLE_META_PF_FEAT_SEL) {
- cb.Run(num_avail, action, status);
+ cb.Run(num_avail, action, btm_status);
return;
}
@@ -168,7 +180,7 @@
/* send ADV PF operation complete */
btm_ble_adv_filt_cb.op_type = 0;
- cb.Run(num_avail, action, status);
+ cb.Run(num_avail, action, btm_status);
}
/*******************************************************************************
@@ -533,7 +545,7 @@
len += Uuid::kNumBytes128;
} else {
BTM_TRACE_ERROR("illegal UUID length: %d", uuid_len);
- cb.Run(0, BTM_BLE_PF_CONFIG, 1 /*BTA_FAILURE*/);
+ cb.Run(0, BTM_BLE_PF_CONFIG, BTM_ILLEGAL_VALUE);
return;
}
@@ -561,11 +573,24 @@
memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
}
+/*
+ * Used to remove device records for devices setting scan filters with address,
+ * type and IRK. Flow:
+ * - ScanFilter comes in with IRK.
+ * - Check IRK for empty, if empty ignore setting to resolving list.
+ * - Otherwise we set it to the resolving list via BTM_SecAddBleKey.
+ * - Then on clear we need to check if the device is paired and if it isn't we
+ * remove it referencing this map.
+ *
+ */
+static std::unordered_map<tBTM_BLE_PF_FILT_INDEX, RawAddress>
+ remove_me_later_map;
+
void BTM_LE_PF_set(tBTM_BLE_PF_FILT_INDEX filt_index,
std::vector<ApcfCommand> commands,
tBTM_BLE_PF_CFG_CBACK cb) {
if (!is_filtering_supported()) {
- cb.Run(0, BTM_BLE_PF_ENABLE, 1 /* BTA_FAILURE */);
+ cb.Run(0, BTM_BLE_PF_ENABLE, BTM_MODE_UNSUPPORTED);
return;
}
@@ -587,6 +612,48 @@
BTM_LE_PF_addr_filter(action, filt_index, target_addr,
base::DoNothing());
+ if (!is_empty_128bit(cmd.irk)) {
+ // Save index and addr
+ auto entry = remove_me_later_map.find(filt_index);
+ if (entry != remove_me_later_map.end()) {
+ LOG_WARN("Replacing existing filter index entry with new address");
+ // If device is not bonded, then try removing the device
+ // If the device doesn't get removed then it is currently connected
+ // (may be pairing?) If we do delete the device we want to erase the
+ // filter index so we can replace it If the device is bonded, we
+ // want to erase the filter index so we don't delete it in the later
+ // BTM_LE_PF_clear call.
+ if (!btm_sec_is_a_bonded_dev(entry->second)) {
+ if (!BTM_SecDeleteDevice(entry->second)) {
+ LOG_WARN("Unable to remove device, still connected.");
+ return;
+ }
+ }
+ remove_me_later_map.erase(filt_index);
+ }
+ if (btm_find_dev(cmd.address) != nullptr) {
+ // Unless the user tries to bond with a device in between the
+ // scanner app starting a scan, then crashing, then being restarted
+ // and we get to this same point with the same filt_index (whose
+ // value is managed by the Java layer) then we might have a device
+ // record here, in which case something else is managing the device
+ // and we do not want to interfere with that experience.
+ LOG_WARN("Address record already exists...this is unexpected...");
+ return;
+ }
+ // Allocate a new "temporary" device record
+ btm_sec_alloc_dev(cmd.address);
+ remove_me_later_map.emplace(filt_index, cmd.address);
+ // Set the IRK
+ tBTM_LE_PID_KEYS pid_keys;
+ pid_keys.irk = cmd.irk;
+ pid_keys.identity_addr_type = cmd.addr_type;
+ pid_keys.identity_addr = cmd.address;
+ // Add it to the union to pass to SecAddBleKey
+ tBTM_LE_KEY_VALUE le_key;
+ le_key.pid_key = pid_keys;
+ BTM_SecAddBleKey(cmd.address, &le_key, BTM_LE_KEY_PID);
+ }
break;
}
@@ -624,7 +691,7 @@
break;
}
}
- cb.Run(0, 0, 0);
+ cb.Run(0, 0, BTM_SUCCESS);
}
/**
@@ -633,7 +700,7 @@
void BTM_LE_PF_clear(tBTM_BLE_PF_FILT_INDEX filt_index,
tBTM_BLE_PF_CFG_CBACK cb) {
if (!is_filtering_supported()) {
- cb.Run(0, BTM_BLE_PF_ENABLE, 1 /* BTA_FAILURE */);
+ cb.Run(0, BTM_BLE_PF_ENABLE, BTM_MODE_UNSUPPORTED);
return;
}
@@ -663,6 +730,15 @@
/* clear service data filter */
BTM_LE_PF_srvc_data_pattern(BTM_BLE_SCAN_COND_CLEAR, filt_index, {}, {},
fDoNothing);
+
+ // If we have an entry, lets remove the device if it isn't bonded
+ auto entry = remove_me_later_map.find(filt_index);
+ if (entry != remove_me_later_map.end()) {
+ auto entry = remove_me_later_map.find(filt_index);
+ if (!btm_sec_is_a_bonded_dev(entry->second)) {
+ BTM_SecDeleteDevice(entry->second);
+ }
+ }
}
uint8_t len = BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_PF_FEAT_SEL_LEN;
@@ -710,7 +786,7 @@
uint8_t param[len], *p;
if (!is_filtering_supported()) {
- cb.Run(0, BTM_BLE_PF_ENABLE, 1 /* BTA_FAILURE */);
+ cb.Run(0, BTM_BLE_PF_ENABLE, btm_status_value(BTM_MODE_UNSUPPORTED));
return;
}
@@ -722,7 +798,7 @@
p_bda_filter = btm_ble_find_addr_filter_counter(nullptr);
if (NULL == p_bda_filter) {
BTM_TRACE_ERROR("BD Address not found!");
- cb.Run(0, BTM_BLE_PF_ENABLE, 1 /* BTA_FAILURE */);
+ cb.Run(0, BTM_BLE_PF_ENABLE, btm_status_value(BTM_UNKNOWN_ADDR));
return;
}
@@ -812,7 +888,8 @@
return;
}
- p_stat_cback.Run(action, status);
+ tBTM_STATUS btm_status = (status == 0) ? BTM_SUCCESS : BTM_ERR_PROCESSING;
+ p_stat_cback.Run(action, btm_status);
}
/*******************************************************************************
@@ -828,7 +905,9 @@
void BTM_BleEnableDisableFilterFeature(uint8_t enable,
tBTM_BLE_PF_STATUS_CBACK p_stat_cback) {
if (!is_filtering_supported()) {
- if (p_stat_cback) p_stat_cback.Run(BTM_BLE_PF_ENABLE, 1 /* BTA_FAILURE */);
+ if (p_stat_cback)
+ p_stat_cback.Run(BTM_BLE_PF_ENABLE,
+ BTM_MODE_UNSUPPORTED /* BTA_FAILURE */);
return;
}
diff --git a/stack/btm/btm_ble_batchscan.cc b/stack/btm/btm_ble_batchscan.cc
index 63282e6..6c0530a 100644
--- a/stack/btm/btm_ble_batchscan.cc
+++ b/stack/btm/btm_ble_batchscan.cc
@@ -104,6 +104,7 @@
adv_data.p_adv_pkt_data =
static_cast<uint8_t*>(osi_malloc(adv_data.adv_pkt_len));
memcpy(adv_data.p_adv_pkt_data, p, adv_data.adv_pkt_len);
+ p += adv_data.adv_pkt_len;
}
STREAM_TO_UINT8(adv_data.scan_rsp_len, p);
@@ -276,7 +277,7 @@
num_records);
if (num_records == 0) {
- cb.Run(status, report_format, num_records_all, data_all);
+ cb.Run(BTM_SUCCESS, report_format, num_records_all, data_all);
return;
}
diff --git a/stack/btm/btm_ble_bgconn.cc b/stack/btm/btm_ble_bgconn.cc
index 8a65eee..ab67c2a 100644
--- a/stack/btm/btm_ble_bgconn.cc
+++ b/stack/btm/btm_ble_bgconn.cc
@@ -90,38 +90,37 @@
}
static void acceptlist_add_command_complete(uint8_t* p_data, uint16_t evt_len) {
- if (evt_len > sizeof(uint8_t)) {
- uint8_t status;
- STREAM_TO_UINT8(status, p_data);
- acceptlist_command_complete(static_cast<tHCI_STATUS>(status),
- kAcceptlistAdd);
- } else {
+ if (evt_len < sizeof(uint8_t)) {
LOG_ERROR("Received bogus acceptlist add complete length:%hu", evt_len);
+ return;
}
+ uint8_t status;
+ STREAM_TO_UINT8(status, p_data);
+ acceptlist_command_complete(static_cast<tHCI_STATUS>(status), kAcceptlistAdd);
}
static void acceptlist_remove_command_complete(uint8_t* p_data,
uint16_t evt_len) {
- if (evt_len > sizeof(uint8_t)) {
- uint8_t status;
- STREAM_TO_UINT8(status, p_data);
- acceptlist_command_complete(static_cast<tHCI_STATUS>(status),
- kAcceptlistRemove);
- } else {
+ if (evt_len < sizeof(uint8_t)) {
LOG_ERROR("Received bogus acceptlist remove complete length:%hu", evt_len);
+ return;
}
+ uint8_t status;
+ STREAM_TO_UINT8(status, p_data);
+ acceptlist_command_complete(static_cast<tHCI_STATUS>(status),
+ kAcceptlistRemove);
}
static void acceptlist_clear_command_complete(uint8_t* p_data,
uint16_t evt_len) {
- if (evt_len > sizeof(uint8_t)) {
- uint8_t status;
- STREAM_TO_UINT8(status, p_data);
- acceptlist_command_complete(static_cast<tHCI_STATUS>(status),
- kAcceptlistClear);
- } else {
+ if (evt_len < sizeof(uint8_t)) {
LOG_ERROR("Received bogus acceptlist remove complete length:%hu", evt_len);
+ return;
}
+ uint8_t status;
+ STREAM_TO_UINT8(status, p_data);
+ acceptlist_command_complete(static_cast<tHCI_STATUS>(status),
+ kAcceptlistClear);
}
/** This function is to stop auto connection procedure */
@@ -534,14 +533,9 @@
}
if (bluetooth::shim::is_gd_acl_enabled()) {
- if (acl_check_and_clear_ignore_auto_connect_after_disconnect(address)) {
- LOG_WARN(
- "Unexpectedly found device address already in ignore auto connect "
- "device:%s",
- PRIVATE_ADDRESS(address));
- }
return bluetooth::shim::ACL_AcceptLeConnectionFrom(
- convert_to_address_with_type(address, btm_find_dev(address)));
+ convert_to_address_with_type(address, btm_find_dev(address)),
+ /* is_direct */ false);
}
if (background_connections_count() ==
@@ -588,7 +582,6 @@
}
if (bluetooth::shim::is_gd_acl_enabled()) {
- acl_clear_all_ignore_auto_connect_after_disconnect();
bluetooth::shim::ACL_IgnoreAllLeConnections();
return;
}
diff --git a/stack/btm/btm_ble_cont_energy.cc b/stack/btm/btm_ble_cont_energy.cc
index 00519b0..e23d63c 100644
--- a/stack/btm/btm_ble_cont_energy.cc
+++ b/stack/btm/btm_ble_cont_energy.cc
@@ -46,7 +46,6 @@
static void btm_ble_cont_energy_cmpl_cback(tBTM_VSC_CMPL* p_params) {
uint8_t* p = p_params->p_param_buf;
uint16_t len = p_params->param_len;
- uint8_t status = 0;
uint32_t total_tx_time = 0, total_rx_time = 0, total_idle_time = 0,
total_energy_used = 0;
@@ -55,7 +54,9 @@
return;
}
- STREAM_TO_UINT8(status, p);
+ uint8_t raw_status;
+ STREAM_TO_UINT8(raw_status, p);
+ tHCI_STATUS status = to_hci_status_code(raw_status);
STREAM_TO_UINT32(total_tx_time, p);
STREAM_TO_UINT32(total_rx_time, p);
STREAM_TO_UINT32(total_idle_time, p);
@@ -67,7 +68,8 @@
if (NULL != ble_energy_info_cb.p_ener_cback)
ble_energy_info_cb.p_ener_cback(total_tx_time, total_rx_time,
- total_idle_time, total_energy_used, status);
+ total_idle_time, total_energy_used,
+ static_cast<tHCI_STATUS>(status));
return;
}
diff --git a/stack/btm/btm_ble_gap.cc b/stack/btm/btm_ble_gap.cc
index 49674079..a9f9d1a 100644
--- a/stack/btm/btm_ble_gap.cc
+++ b/stack/btm/btm_ble_gap.cc
@@ -522,8 +522,6 @@
******************************************************************************/
static void btm_ble_vendor_capability_vsc_cmpl_cback(
tBTM_VSC_CMPL* p_vcs_cplt_params) {
- uint8_t status = 0xFF;
- uint8_t* p;
BTM_TRACE_DEBUG("%s", __func__);
@@ -531,8 +529,10 @@
CHECK(p_vcs_cplt_params->opcode == HCI_BLE_VENDOR_CAP);
CHECK(p_vcs_cplt_params->param_len > 0);
- p = p_vcs_cplt_params->p_param_buf;
- STREAM_TO_UINT8(status, p);
+ const uint8_t* p = p_vcs_cplt_params->p_param_buf;
+ uint8_t raw_status;
+ STREAM_TO_UINT8(raw_status, p);
+ tHCI_STATUS status = to_hci_status_code(raw_status);
if (status != HCI_SUCCESS) {
BTM_TRACE_DEBUG("%s: Status = 0x%02x (0 is success)", __func__, status);
@@ -604,7 +604,7 @@
if (btm_cb.cmn_ble_vsc_cb.tot_scan_results_strg > 0) btm_ble_batchscan_init();
if (p_ctrl_le_feature_rd_cmpl_cback != NULL)
- p_ctrl_le_feature_rd_cmpl_cback(status);
+ p_ctrl_le_feature_rd_cmpl_cback(static_cast<tHCI_STATUS>(status));
}
#endif /* (BLE_VND_INCLUDED == TRUE) */
@@ -1527,6 +1527,10 @@
dev_class[1] = BTM_COD_MAJOR_AUDIO;
dev_class[2] = BTM_COD_MINOR_UNCLASSIFIED;
break;
+ case BTM_BLE_APPEARANCE_WEARABLE_AUDIO_DEVICE_EARBUD:
+ dev_class[1] = BTM_COD_MAJOR_AUDIO;
+ dev_class[2] = BTM_COD_MINOR_WEARABLE_HEADSET;
+ break;
case BTM_BLE_APPEARANCE_GENERIC_BARCODE_SCANNER:
case BTM_BLE_APPEARANCE_HID_BARCODE_SCANNER:
case BTM_BLE_APPEARANCE_GENERIC_HID:
@@ -2496,18 +2500,7 @@
if (bd_addr != nullptr) {
const RawAddress bda(*bd_addr);
if (bluetooth::shim::is_gd_acl_enabled()) {
- if (acl_check_and_clear_ignore_auto_connect_after_disconnect(bda)) {
- LOG_DEBUG(
- "Local disconnect initiated so skipping re-add to acceptlist "
- "device:%s",
- PRIVATE_ADDRESS(bda));
- } else {
- if (!bluetooth::shim::ACL_AcceptLeConnectionFrom(
- convert_to_address_with_type(bda, btm_find_dev(bda)))) {
- LOG_ERROR("Unable to add to acceptlist as it is full:%s",
- PRIVATE_ADDRESS(bda));
- }
- }
+ LOG_DEBUG("gd_acl enabled so skip background connection logic");
} else {
btm_ble_bgconn_cancel_if_disconnected(bda);
}
diff --git a/stack/btm/btm_ble_int.h b/stack/btm/btm_ble_int.h
index aec86ca..e5ac28d 100644
--- a/stack/btm/btm_ble_int.h
+++ b/stack/btm/btm_ble_int.h
@@ -64,8 +64,8 @@
tBTM_BLE_SEC_REQ_ACT* p_sec_req_act);
extern void btm_ble_ltk_request_reply(const RawAddress& bda, bool use_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_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,
tBTM_BLE_SEC_ACT sec_act,
uint8_t link_role);
diff --git a/stack/btm/btm_ble_multi_adv.cc b/stack/btm/btm_ble_multi_adv.cc
index ce8f7ba..a7361f5 100644
--- a/stack/btm/btm_ble_multi_adv.cc
+++ b/stack/btm/btm_ble_multi_adv.cc
@@ -31,13 +31,14 @@
#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>
+#include "bind_helpers.h"
+
using base::Bind;
using base::TimeDelta;
using base::TimeTicks;
diff --git a/stack/btm/btm_dev.cc b/stack/btm/btm_dev.cc
index c64ca19..f1de18e 100644
--- a/stack/btm/btm_dev.cc
+++ b/stack/btm/btm_dev.cc
@@ -63,13 +63,13 @@
bool BTM_SecAddDevice(const RawAddress& bd_addr, DEV_CLASS dev_class,
BD_NAME bd_name, uint8_t* features, LinkKey* p_link_key,
uint8_t key_type, uint8_t pin_length) {
- BTM_TRACE_API("%s: link key type:%x", __func__, key_type);
-
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
if (!p_dev_rec) {
p_dev_rec = btm_sec_allocate_dev_rec();
- BTM_TRACE_API("%s: allocated p_dev_rec=%p, bd_addr=%s", __func__, p_dev_rec,
- bd_addr.ToString().c_str());
+ LOG_DEBUG(
+ "Caching new record from config file device:%s link_key_type:%x "
+ "name:%s",
+ PRIVATE_ADDRESS(bd_addr), key_type, bd_name);
p_dev_rec->bd_addr = bd_addr;
p_dev_rec->hci_handle = BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_BR_EDR);
@@ -78,6 +78,10 @@
/* update conn params, use default value for background connection params */
memset(&p_dev_rec->conn_params, 0xff, sizeof(tBTM_LE_CONN_PRAMS));
} else {
+ LOG_DEBUG(
+ "Caching existing record from config file device:%s link_key_type:%x",
+ PRIVATE_ADDRESS(bd_addr), key_type);
+
/* "Bump" timestamp for existing record */
p_dev_rec->timestamp = btm_cb.dev_rec_count++;
@@ -95,13 +99,15 @@
memset(p_dev_rec->sec_bd_name, 0, sizeof(tBTM_BD_NAME));
if (bd_name && bd_name[0]) {
+ LOG_DEBUG(" Remote name known for device:%s name:%s",
+ PRIVATE_ADDRESS(bd_addr), bd_name);
p_dev_rec->sec_flags |= BTM_SEC_NAME_KNOWN;
strlcpy((char*)p_dev_rec->sec_bd_name, (char*)bd_name,
BTM_MAX_REM_BD_NAME_LEN + 1);
}
if (p_link_key) {
- VLOG(2) << __func__ << ": BDA: " << bd_addr;
+ LOG_DEBUG(" Link key known for device:%s", PRIVATE_ADDRESS(bd_addr));
p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_KNOWN;
p_dev_rec->link_key = *p_link_key;
p_dev_rec->link_key_type = key_type;
diff --git a/stack/btm/btm_int_types.h b/stack/btm/btm_int_types.h
index d347d2e..0622ddd 100644
--- a/stack/btm/btm_int_types.h
+++ b/stack/btm/btm_int_types.h
@@ -34,15 +34,6 @@
#include "stack/include/btm_ble_api_types.h"
#include "stack/include/security_client_callbacks.h"
-#define BTM_SEC_IS_SM4(sm) ((bool)(BTM_SM4_TRUE == ((sm)&BTM_SM4_TRUE)))
-#define BTM_SEC_IS_SM4_LEGACY(sm) ((bool)(BTM_SM4_KNOWN == ((sm)&BTM_SM4_TRUE)))
-#define BTM_SEC_IS_SM4_UNKNOWN(sm) \
- ((bool)(BTM_SM4_UNKNOWN == ((sm)&BTM_SM4_TRUE)))
-
-#define BTM_SEC_LE_MASK \
- (BTM_SEC_LE_AUTHENTICATED | BTM_SEC_LE_ENCRYPTED | \
- BTM_SEC_LE_LINK_KEY_KNOWN | BTM_SEC_LE_LINK_KEY_AUTHED)
-
#define BTM_MAX_SCN_ 31 // PORT_MAX_RFC_PORTS system/bt/stack/include/rfcdefs.h
constexpr size_t kMaxLogSize = 255;
@@ -135,7 +126,7 @@
/* Define the Device Management control structure
*/
-typedef struct {
+typedef struct tBTM_DEVCB {
tBTM_VS_EVT_CB* p_vend_spec_cb[BTM_MAX_VSE_CALLBACKS]; /* Register for vendor
specific events */
@@ -211,7 +202,7 @@
}
} tBTM_DEVCB;
-typedef struct {
+typedef struct tBTM_CB {
tBTM_CFG cfg; /* Device configuration */
/*****************************************************
diff --git a/stack/btm/btm_iso.cc b/stack/btm/btm_iso.cc
index 8ba9bb2..3b9e2a1 100644
--- a/stack/btm/btm_iso.cc
+++ b/stack/btm/btm_iso.cc
@@ -122,6 +122,11 @@
pimpl_->iso_impl_->handle_num_completed_pkts(p, evt_len);
}
+void IsoManager::HandleGdNumComplDataPkts(uint16_t handle, uint16_t credits) {
+ if (pimpl_->IsRunning())
+ pimpl_->iso_impl_->handle_gd_num_completed_pkts(handle, credits);
+}
+
void IsoManager::HandleHciEvent(uint8_t sub_code, uint8_t* params,
uint16_t length) {
if (pimpl_->IsRunning())
diff --git a/stack/btm/btm_iso_impl.h b/stack/btm/btm_iso_impl.h
index c0b6a1c..e784775 100644
--- a/stack/btm/btm_iso_impl.h
+++ b/stack/btm/btm_iso_impl.h
@@ -22,8 +22,8 @@
#include <set>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "bind_helpers.h"
#include "bt_types.h"
#include "btm_iso_api.h"
#include "btu.h"
@@ -234,7 +234,12 @@
STREAM_TO_UINT16(conn_handle, stream);
iso_base* iso = GetIsoIfKnown(conn_handle);
- LOG_ASSERT(iso != nullptr) << "Invalid connection handle: " << +conn_handle;
+ if (iso == nullptr) {
+ /* That can happen when ACL has been disconnected while ISO patch was
+ * creating */
+ LOG(WARNING) << __func__ << "Invalid connection handle: " << +conn_handle;
+ return;
+ }
if (status == HCI_SUCCESS) iso->state_flags |= kStateFlagHasDataPathSet;
if (iso->state_flags & kStateFlagIsBroadcast) {
@@ -274,7 +279,12 @@
STREAM_TO_UINT16(conn_handle, stream);
iso_base* iso = GetIsoIfKnown(conn_handle);
- LOG_ASSERT(iso != nullptr) << "Invalid connection handle: " << +conn_handle;
+ if (iso == nullptr) {
+ /* That could happen when ACL has been disconnected while removing data
+ * path */
+ LOG(WARNING) << __func__ << "Invalid connection handle: " << +conn_handle;
+ return;
+ }
if (status == HCI_SUCCESS) iso->state_flags &= ~kStateFlagHasDataPathSet;
@@ -321,7 +331,12 @@
STREAM_TO_UINT16(conn_handle, stream);
iso_base* iso = GetIsoIfKnown(conn_handle);
- LOG_ASSERT(iso != nullptr) << "Invalid connection handle: " << +conn_handle;
+ if (iso == nullptr) {
+ /* That could happen when ACL has been disconnected while waiting on the
+ * read respose */
+ LOG(WARNING) << __func__ << "Invalid connection handle: " << +conn_handle;
+ return;
+ }
STREAM_TO_UINT32(txUnackedPackets, stream);
STREAM_TO_UINT32(txFlushedPackets, stream);
@@ -490,6 +505,14 @@
}
}
+ void handle_gd_num_completed_pkts(uint16_t handle, uint16_t credits) {
+ if ((conn_hdl_to_cis_map_.find(handle) == conn_hdl_to_cis_map_.end()) &&
+ (conn_hdl_to_bis_map_.find(handle) == conn_hdl_to_bis_map_.end()))
+ return;
+
+ iso_credits_ += credits;
+ }
+
void process_create_big_cmpl_pkt(uint8_t len, uint8_t* data) {
struct big_create_cmpl_evt evt;
diff --git a/stack/btm/btm_sec.cc b/stack/btm/btm_sec.cc
index 2899404..eca14b7 100644
--- a/stack/btm/btm_sec.cc
+++ b/stack/btm/btm_sec.cc
@@ -44,6 +44,7 @@
#include "osi/include/log.h"
#include "osi/include/osi.h"
#include "stack/btm/btm_dev.h"
+#include "stack/btm/security_device_record.h"
#include "stack/include/acl_api.h"
#include "stack/include/acl_hci_link_interface.h"
#include "stack/include/btm_status.h"
@@ -61,6 +62,15 @@
#define BTM_SEC_MAX_COLLISION_DELAY (5000)
+#define BTM_SEC_IS_SM4(sm) ((bool)(BTM_SM4_TRUE == ((sm)&BTM_SM4_TRUE)))
+#define BTM_SEC_IS_SM4_LEGACY(sm) ((bool)(BTM_SM4_KNOWN == ((sm)&BTM_SM4_TRUE)))
+#define BTM_SEC_IS_SM4_UNKNOWN(sm) \
+ ((bool)(BTM_SM4_UNKNOWN == ((sm)&BTM_SM4_TRUE)))
+
+#define BTM_SEC_LE_MASK \
+ (BTM_SEC_LE_AUTHENTICATED | BTM_SEC_LE_ENCRYPTED | \
+ BTM_SEC_LE_LINK_KEY_KNOWN | BTM_SEC_LE_LINK_KEY_AUTHED)
+
void btm_inq_stop_on_ssp(void);
extern void btm_ble_advertiser_notify_terminated_legacy(
uint8_t status, uint16_t connection_handle);
@@ -69,6 +79,7 @@
extern void bta_dm_remove_device(const RawAddress& bd_addr);
extern void bta_dm_process_remove_device(const RawAddress& bd_addr);
extern void btm_inq_clear_ssp(void);
+extern void HACK_acl_check_sm4(tBTM_SEC_DEV_REC& p_dev_rec);
/*******************************************************************************
* L O C A L F U N C T I O N P R O T O T Y P E S *
@@ -459,9 +470,7 @@
/* clear out the old setting, just in case it exists */
{
p_srec->security_flags &=
- ~(BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_MITM |
- BTM_SEC_FORCE_CENTRAL | BTM_SEC_ATTEMPT_CENTRAL |
- BTM_SEC_FORCE_PERIPHERAL | BTM_SEC_ATTEMPT_PERIPHERAL);
+ ~(BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_MITM);
}
/* Parameter validation. Originator should not set requirements for
@@ -489,8 +498,6 @@
{
p_srec->security_flags &=
~(BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_MITM |
- BTM_SEC_FORCE_CENTRAL | BTM_SEC_ATTEMPT_CENTRAL |
- BTM_SEC_FORCE_PERIPHERAL | BTM_SEC_ATTEMPT_PERIPHERAL |
BTM_SEC_IN_MIN_16_DIGIT_PIN);
}
@@ -776,7 +783,7 @@
p_dev_rec->is_originator = true;
BTM_LogHistory(kBtmLogTag, bd_addr, "Bonding initiated",
- BtTransportText(transport));
+ bt_transport_text(transport));
if (transport == BT_TRANSPORT_LE) {
btm_ble_init_pseudo_addr(p_dev_rec, bd_addr);
@@ -1046,7 +1053,7 @@
p_ref_data, sec_act);
}
- tBTM_STATUS rc = 0;
+ tBTM_STATUS rc = BTM_SUCCESS;
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
if (!p_dev_rec ||
@@ -1370,6 +1377,40 @@
return (p_dev_rec->SupportsSecureConnections());
}
+/*******************************************************************************
+ *
+ * Function BTM_GetPeerDeviceTypeFromFeatures
+ *
+ * Description This function is called to retrieve the peer device type
+ * by referencing the remote features.
+ *
+ * Parameters: bd_addr - address of the peer
+ *
+ * Returns BT_DEVICE_TYPE_DUMO if both BR/EDR and BLE transports are
+ * supported by the peer,
+ * BT_DEVICE_TYPE_BREDR if only BR/EDR transport is supported,
+ * BT_DEVICE_TYPE_BLE if only BLE transport is supported.
+ *
+ ******************************************************************************/
+tBT_DEVICE_TYPE BTM_GetPeerDeviceTypeFromFeatures(const RawAddress& bd_addr) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+ if (p_dev_rec == nullptr) {
+ LOG_WARN("Unknown BDA:%s", PRIVATE_ADDRESS(bd_addr));
+ } else {
+ if (p_dev_rec->remote_supports_ble && p_dev_rec->remote_supports_bredr) {
+ return BT_DEVICE_TYPE_DUMO;
+ } else if (p_dev_rec->remote_supports_bredr) {
+ return BT_DEVICE_TYPE_BREDR;
+ } else if (p_dev_rec->remote_supports_ble) {
+ return BT_DEVICE_TYPE_BLE;
+ } else {
+ LOG_WARN("Device features does not support BR/EDR and BLE:%s",
+ PRIVATE_ADDRESS(bd_addr));
+ }
+ }
+ return BT_DEVICE_TYPE_BREDR;
+}
+
/************************************************************************
* I N T E R N A L F U N C T I O N S
************************************************************************/
@@ -1562,9 +1603,9 @@
}
} else if (!(BTM_SM4_KNOWN & p_dev_rec->sm4)) {
/* the remote features are not known yet */
- BTM_TRACE_DEBUG("%s: (%s) remote features unknown!!sec_flags:0x%02x",
- __func__, (is_originator) ? "initiator" : "acceptor",
- p_dev_rec->sec_flags);
+ LOG_DEBUG(
+ "Remote features have not yet been received sec_flags:0x%02x %s",
+ p_dev_rec->sec_flags, (is_originator) ? "initiator" : "acceptor");
p_dev_rec->sm4 |= BTM_SM4_REQ_PEND;
return (BTM_CMD_STARTED);
@@ -1634,7 +1675,7 @@
BTM_TRACE_DEBUG("%s: p_dev_rec=%p, clearing callback. old p_callback=%p",
__func__, p_dev_rec, p_dev_rec->p_callback);
p_dev_rec->p_callback = NULL;
- (*p_callback)(&bd_addr, transport, p_dev_rec->p_ref_data, (uint8_t)rc);
+ (*p_callback)(&bd_addr, transport, p_dev_rec->p_ref_data, rc);
}
return (rc);
@@ -1798,7 +1839,7 @@
{
if (p_callback) {
LOG_DEBUG("Notifying client that security access has been granted");
- (*p_callback)(&bd_addr, transport, p_ref_data, (uint8_t)rc);
+ (*p_callback)(&bd_addr, transport, p_ref_data, rc);
}
}
return rc;
@@ -1867,7 +1908,7 @@
if (rc != BTM_CMD_STARTED) {
if (p_callback) {
p_dev_rec->p_callback = NULL;
- (*p_callback)(&bd_addr, transport, p_ref_data, (uint8_t)rc);
+ (*p_callback)(&bd_addr, transport, p_ref_data, rc);
}
}
@@ -2364,7 +2405,7 @@
/* There is no next procedure or start of procedure failed, notify the waiting
* layer */
- btm_sec_dev_rec_cback_event(p_dev_rec, status, false);
+ btm_sec_dev_rec_cback_event(p_dev_rec, btm_status, false);
}
/*******************************************************************************
@@ -2877,7 +2918,7 @@
if ((*btm_cb.api.p_sp_callback)(BTM_SP_RMT_OOB_EVT,
(tBTM_SP_EVT_DATA*)&evt_data) ==
BTM_NOT_AUTHORIZED) {
- BTM_RemoteOobDataReply(true, p_bda, c, r);
+ BTM_RemoteOobDataReply(static_cast<tBTM_STATUS>(true), p_bda, c, r);
}
return;
}
@@ -3120,7 +3161,7 @@
// Encryption is required to start SM over BR/EDR
// indicate that this is encryption after authentication
BTM_SetEncryption(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR, NULL, NULL,
- 0);
+ BTM_BLE_SEC_NONE);
}
}
l2cu_start_post_bond_timer(p_dev_rec->hci_handle);
@@ -3149,7 +3190,7 @@
}
/* Authentication succeeded, execute the next security procedure, if any */
- uint8_t btm_status = btm_sec_execute_procedure(p_dev_rec);
+ tBTM_STATUS btm_status = btm_sec_execute_procedure(p_dev_rec);
/* If there is no next procedure, or procedure failed to start, notify the
* caller */
@@ -3342,31 +3383,23 @@
*
******************************************************************************/
void btm_sec_connected(const RawAddress& bda, uint16_t handle,
- tHCI_STATUS status, uint8_t enc_mode) {
+ tHCI_STATUS status, uint8_t enc_mode,
+ tHCI_ROLE assigned_role) {
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bda);
- uint8_t res;
+ tBTM_STATUS res;
bool is_pairing_device = false;
bool addr_matched;
uint8_t bit_shift = 0;
btm_acl_resubmit_page();
- if (p_dev_rec) {
- VLOG(2) << __func__ << ": Security Manager: in state: "
- << btm_pair_state_descr(btm_cb.pairing_state)
- << " handle:" << handle
- << " status:" << loghex(static_cast<uint16_t>(status))
- << " enc_mode:" << loghex(enc_mode) << " bda:" << bda
- << " RName:" << p_dev_rec->sec_bd_name;
- } else {
- VLOG(2) << __func__ << ": Security Manager: in state: "
- << btm_pair_state_descr(btm_cb.pairing_state)
- << " handle:" << handle
- << " status:" << loghex(static_cast<uint16_t>(status))
- << " enc_mode:" << loghex(enc_mode) << " bda:" << bda;
- }
-
if (!p_dev_rec) {
+ LOG_DEBUG(
+ "Connected to new device state:%s handle:0x%04x status:%s "
+ "enc_mode:%hhu bda:%s",
+ btm_pair_state_descr(btm_cb.pairing_state), handle,
+ hci_status_code_text(status).c_str(), enc_mode, PRIVATE_ADDRESS(bda));
+
if (status == HCI_SUCCESS) {
p_dev_rec = btm_sec_alloc_dev(bda);
LOG_DEBUG("Allocated new device record for new connection peer:%s",
@@ -3387,6 +3420,13 @@
}
} else /* Update the timestamp for this device */
{
+ LOG_DEBUG(
+ "Connected to known device state:%s handle:0x%04x status:%s "
+ "enc_mode:%hhu bda:%s RName:%s",
+ btm_pair_state_descr(btm_cb.pairing_state), handle,
+ hci_status_code_text(status).c_str(), enc_mode, PRIVATE_ADDRESS(bda),
+ p_dev_rec->sec_bd_name);
+
bit_shift = (handle == p_dev_rec->ble_hci_handle) ? 8 : 0;
p_dev_rec->timestamp = btm_cb.dev_rec_count++;
if (p_dev_rec->sm4 & BTM_SM4_CONN_PEND) {
@@ -3555,14 +3595,15 @@
p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE;
/* remember flag before it is initialized */
+ bool is_pair_flags_we_started_dd = false;
if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
- res = true;
+ is_pair_flags_we_started_dd = true;
else
- res = false;
+ is_pair_flags_we_started_dd = false;
btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
- if (res) {
+ if (is_pair_flags_we_started_dd) {
/* Let l2cap start bond timer */
l2cu_update_lcb_4_bonding(p_dev_rec->bd_addr, true);
}
@@ -3571,7 +3612,7 @@
}
p_dev_rec->hci_handle = handle;
- btm_acl_created(bda, handle, HCI_ROLE_PERIPHERAL, BT_TRANSPORT_BR_EDR);
+ btm_acl_created(bda, handle, assigned_role, BT_TRANSPORT_BR_EDR);
/* role may not be correct here, it will be updated by l2cap, but we need to
*/
@@ -3742,7 +3783,7 @@
if (p_dev_rec->sec_state == BTM_SEC_STATE_DISCONNECTING_BOTH) {
LOG_DEBUG("Waiting for other transport to disconnect current:%s",
- BtTransportText(transport).c_str());
+ bt_transport_text(transport).c_str());
p_dev_rec->sec_state = (transport == BT_TRANSPORT_LE)
? BTM_SEC_STATE_DISCONNECTING
: BTM_SEC_STATE_DISCONNECTING_BLE;
@@ -3760,7 +3801,7 @@
BTM_ERR_PROCESSING);
LOG_DEBUG("Cleaned up pending security state device:%s transport:%s",
PRIVATE_ADDRESS(p_dev_rec->bd_addr),
- BtTransportText(transport).c_str());
+ bt_transport_text(transport).c_str());
}
}
@@ -4211,18 +4252,31 @@
*
******************************************************************************/
tBTM_STATUS btm_sec_execute_procedure(tBTM_SEC_DEV_REC* p_dev_rec) {
- BTM_TRACE_EVENT(
- "btm_sec_execute_procedure: Required:0x%x Flags:0x%x State:%d",
- p_dev_rec->security_required, p_dev_rec->sec_flags, p_dev_rec->sec_state);
+ CHECK(p_dev_rec != nullptr);
+ LOG_DEBUG(
+ "security_required:0x%x security_flags:0x%x security_state:%s[%hhu]",
+ p_dev_rec->security_required, p_dev_rec->sec_flags,
+ security_state_text(static_cast<tSECURITY_STATE>(p_dev_rec->sec_state))
+ .c_str(),
+ p_dev_rec->sec_state);
- /* There is a chance that we are getting name. Wait until done. */
- if (p_dev_rec->sec_state != 0) return (BTM_CMD_STARTED);
+ if (p_dev_rec->sec_state != BTM_SEC_STATE_IDLE) {
+ LOG_DEBUG(
+ "Security state is idle indicating remote name request is outstanding");
+ return (BTM_CMD_STARTED);
+ }
+
+ if (!bluetooth::shim::is_gd_acl_enabled()) {
+ // Load the SM4 values //
+ HACK_acl_check_sm4(*p_dev_rec);
+ }
/* If any security is required, get the name first */
if (!(p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) &&
(p_dev_rec->hci_handle != HCI_INVALID_HANDLE)) {
- BTM_TRACE_EVENT("Security Manager: Start get name");
+ LOG_DEBUG("Security Manager: Start get name");
if (!btm_sec_start_get_name(p_dev_rec)) {
+ LOG_WARN("Unable to start remote name request");
return (BTM_NO_RESOURCES);
}
return (BTM_CMD_STARTED);
@@ -4246,7 +4300,7 @@
* authenticated connections, hence we cannot distinguish here.
*/
- BTM_TRACE_EVENT("Security Manager: Start authentication");
+ LOG_DEBUG("Security Manager: Start authentication");
/*
* If we do have a link-key, but we end up here because we need an
@@ -4270,6 +4324,8 @@
btm_sec_start_authentication(p_dev_rec);
return (BTM_CMD_STARTED);
+ } else {
+ LOG_DEBUG("Authentication not required");
}
/* If connection is not encrypted and encryption is required */
@@ -4285,6 +4341,8 @@
btsnd_hcic_set_conn_encrypt(p_dev_rec->hci_handle, true);
p_dev_rec->sec_state = BTM_SEC_STATE_ENCRYPTING;
return (BTM_CMD_STARTED);
+ } else {
+ LOG_DEBUG("Encryption not required");
}
if ((p_dev_rec->security_required & BTM_SEC_MODE4_LEVEL4) &&
@@ -4296,10 +4354,9 @@
}
/* All required security procedures already established */
- p_dev_rec->security_required &= ~(
- BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_IN_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT |
- BTM_SEC_IN_ENCRYPT | BTM_SEC_FORCE_CENTRAL | BTM_SEC_ATTEMPT_CENTRAL |
- BTM_SEC_FORCE_PERIPHERAL | BTM_SEC_ATTEMPT_PERIPHERAL);
+ p_dev_rec->security_required &=
+ ~(BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_IN_AUTHENTICATE |
+ BTM_SEC_OUT_ENCRYPT | BTM_SEC_IN_ENCRYPT);
BTM_TRACE_EVENT("Security Manager: access granted");
@@ -4585,7 +4642,7 @@
p_e->p_callback = p_callback;
p_e->p_ref_data = p_ref_data;
p_e->transport = BT_TRANSPORT_BR_EDR;
- p_e->sec_act = 0;
+ p_e->sec_act = BTM_BLE_SEC_NONE;
p_e->bd_addr = bd_addr;
BTM_TRACE_EVENT(
@@ -4683,7 +4740,7 @@
uint8_t encr_enable) {
if (fixed_queue_is_empty(btm_cb.sec_pending_q)) return;
- uint8_t res = encr_enable ? BTM_SUCCESS : BTM_ERR_PROCESSING;
+ const tBTM_STATUS res = encr_enable ? BTM_SUCCESS : BTM_ERR_PROCESSING;
list_t* list = fixed_queue_get_list(btm_cb.sec_pending_q);
for (const list_node_t* node = list_begin(list); node != list_end(list);) {
tBTM_SEC_QUEUE_ENTRY* p_e = (tBTM_SEC_QUEUE_ENTRY*)list_node(node);
@@ -4811,7 +4868,8 @@
******************************************************************************/
void btm_sec_set_peer_sec_caps(uint16_t hci_handle, bool ssp_supported,
bool sc_supported,
- bool hci_role_switch_supported) {
+ bool hci_role_switch_supported,
+ bool br_edr_supported, bool le_supported) {
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(hci_handle);
if (p_dev_rec == nullptr) return;
@@ -4851,6 +4909,9 @@
/* Request for remaining Security Features (if any) */
l2cu_resubmit_pending_sec_req(&p_dev_rec->bd_addr);
}
+
+ p_dev_rec->remote_supports_bredr = br_edr_supported;
+ p_dev_rec->remote_supports_ble = le_supported;
}
// Return DEV_CLASS (uint8_t[3]) of bda. If record doesn't exist, create one.
@@ -4858,3 +4919,11 @@
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_or_alloc_dev(bda);
return p_dev_rec->dev_class;
}
+
+void BTM_update_version_info(const RawAddress& bd_addr,
+ const remote_version_info& remote_version_info) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+ if (p_dev_rec == NULL) return;
+
+ p_dev_rec->remote_version_info = remote_version_info;
+}
diff --git a/stack/btm/btm_sec.h b/stack/btm/btm_sec.h
index 065c4dc..2c012f3 100644
--- a/stack/btm/btm_sec.h
+++ b/stack/btm/btm_sec.h
@@ -22,11 +22,13 @@
*
******************************************************************************/
+#pragma once
#include <cstdint>
#include "stack/btm/security_device_record.h"
#include "stack/include/btm_api_types.h"
#include "stack/include/hci_error_code.h"
#include "stack/include/security_client_callbacks.h"
+#include "types/hci_role.h"
#define BTM_SEC_MAX_COLLISION_DELAY (5000)
@@ -624,7 +626,8 @@
*
******************************************************************************/
void btm_sec_connected(const RawAddress& bda, uint16_t handle,
- tHCI_STATUS status, uint8_t enc_mode);
+ tHCI_STATUS status, uint8_t enc_mode,
+ tHCI_ROLE assigned_role = HCI_ROLE_PERIPHERAL);
/*******************************************************************************
*
@@ -739,7 +742,7 @@
* Parameters: void
*
******************************************************************************/
-void btm_sec_dev_rec_cback_event(tBTM_SEC_DEV_REC* p_dev_rec, uint8_t res,
+void btm_sec_dev_rec_cback_event(tBTM_SEC_DEV_REC* p_dev_rec, tBTM_STATUS res,
bool is_le_transport);
/*******************************************************************************
@@ -778,7 +781,8 @@
******************************************************************************/
void btm_sec_set_peer_sec_caps(uint16_t hci_handle, bool ssp_supported,
bool sc_supported,
- bool hci_role_switch_supported);
+ bool hci_role_switch_supported,
+ bool br_edr_supported, bool le_supported);
// Return DEV_CLASS (uint8_t[3]) of bda. If record doesn't exist, create one.
const uint8_t* btm_get_dev_class(const RawAddress& bda);
diff --git a/stack/btm/security_device_record.h b/stack/btm/security_device_record.h
index 36692b5..56d8108 100644
--- a/stack/btm/security_device_record.h
+++ b/stack/btm/security_device_record.h
@@ -27,6 +27,7 @@
#include "main/shim/dumpsys.h"
#include "osi/include/alarm.h"
#include "stack/include/btm_api_types.h"
+#include "types/hci_role.h"
#include "types/raw_address.h"
typedef char tBTM_LOC_BD_NAME[BTM_MAX_LOC_BD_NAME_LEN + 1];
@@ -188,6 +189,10 @@
be cleared on \ btm_acl_created */
} tBTM_SM4_BIT;
+inline std::string class_of_device_text(const DEV_CLASS& cod) {
+ return base::StringPrintf("0x%02x%02x%02x", cod[2], cod[1], cod[0]);
+}
+
/*
* Define structure for Security Device Record.
* A record exists for each device authenticated with this device
@@ -223,7 +228,8 @@
uint8_t pin_len, uint8_t* p_pin);
friend void btm_sec_auth_complete(uint16_t handle, tHCI_STATUS status);
friend void btm_sec_connected(const RawAddress& bda, uint16_t handle,
- tHCI_STATUS status, uint8_t enc_mode);
+ tHCI_STATUS status, uint8_t enc_mode,
+ tHCI_ROLE);
friend void btm_sec_encrypt_change(uint16_t handle, tHCI_STATUS status,
uint8_t encr_enable);
friend void btm_sec_link_key_notification(const RawAddress& p_bda,
@@ -367,7 +373,9 @@
bool remote_supports_secure_connections;
friend void btm_sec_set_peer_sec_caps(uint16_t hci_handle, bool ssp_supported,
bool sc_supported,
- bool hci_role_switch_supported);
+ bool hci_role_switch_supported,
+ bool br_edr_supported,
+ bool le_supported);
public:
bool SupportsSecureConnections() const {
@@ -379,6 +387,8 @@
/* HCI_IO_CAPABILITY_REQUEST_EVT from the peer before */
/* it knows peer's support for Secure Connections */
bool remote_supports_hci_role_switch = false;
+ bool remote_supports_bredr;
+ bool remote_supports_ble;
bool remote_feature_received = false;
uint16_t ble_hci_handle; /* use in DUMO connection */
@@ -416,10 +426,14 @@
tBTM_SEC_BLE ble;
tBTM_LE_CONN_PRAMS conn_params;
+ tREMOTE_VERSION_INFO remote_version_info;
+
std::string ToString() const {
return base::StringPrintf(
- "%s %6s name:\"%s\" supports_SC:%s", PRIVATE_ADDRESS(bd_addr),
- DeviceTypeText(device_type).c_str(), sec_bd_name,
- logbool(remote_supports_secure_connections).c_str());
+ "%s %6s cod:%s remote_info:%-14s sm4:0x%02x SecureConn:%c name:\"%s\"",
+ PRIVATE_ADDRESS(bd_addr), DeviceTypeText(device_type).c_str(),
+ class_of_device_text(dev_class).c_str(),
+ remote_version_info.ToString().c_str(), sm4,
+ (remote_supports_secure_connections) ? 'T' : 'F', sec_bd_name);
}
};
diff --git a/stack/btu/btu_task.cc b/stack/btu/btu_task.cc
index 8a76a77..5e83e4d 100644
--- a/stack/btu/btu_task.cc
+++ b/stack/btu/btu_task.cc
@@ -110,8 +110,9 @@
static void do_post_on_bt_main(BtMainClosure closure) { closure(); }
void post_on_bt_main(BtMainClosure closure) {
- ASSERT(do_in_main_thread(FROM_HERE,
- base::Bind(do_post_on_bt_main, std::move(closure))));
+ ASSERT(do_in_main_thread(
+ FROM_HERE, base::Bind(do_post_on_bt_main, std::move(closure))) ==
+ BT_STATUS_SUCCESS);
}
void main_thread_start_up() {
diff --git a/stack/eatt/eatt_impl.h b/stack/eatt/eatt_impl.h
index 25799ab..ad106b1 100644
--- a/stack/eatt/eatt_impl.h
+++ b/stack/eatt/eatt_impl.h
@@ -19,7 +19,7 @@
#include <queue>
#include "acl_api.h"
-#include "base/bind_helpers.h"
+#include "bind_helpers.h"
#include "bt_types.h"
#include "device/include/controller.h"
#include "eatt.h"
@@ -32,6 +32,8 @@
namespace bluetooth {
namespace eatt {
+#define BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK 0x01
+
class eatt_device {
public:
RawAddress bda_;
@@ -269,9 +271,7 @@
}
bool is_eatt_supported_by_peer(const RawAddress& bd_addr) {
- /* For now on the list we have only devices which does support eatt */
- eatt_device* eatt_dev = find_device_by_address(bd_addr);
- return eatt_dev ? true : false;
+ return gatt_profile_get_eatt_support(bd_addr);
}
eatt_device* find_device_by_address(const RawAddress& bd_addr) {
@@ -313,7 +313,7 @@
<< +connecting_cids.size();
for (uint16_t cid : connecting_cids) {
- LOG(INFO) << " /n/t cid: " << loghex(cid);
+ LOG(INFO) << " \t cid: " << loghex(cid);
auto chan = std::make_shared<EattChannel>(eatt_dev->bda_, cid, 0,
eatt_dev->rx_mtu_);
@@ -567,7 +567,9 @@
<< bd_addr;
}
- void eatt_is_supported_cb(const RawAddress& bd_addr, bool is_eatt_supported) {
+ void supported_features_cb(const RawAddress& bd_addr, uint8_t features) {
+ bool is_eatt_supported = features & BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK;
+
LOG(INFO) << __func__ << " " << bd_addr
<< " is_eatt_supported = " << int(is_eatt_supported);
if (!is_eatt_supported) return;
@@ -582,7 +584,16 @@
LOG(INFO) << __func__ << " " << bd_addr;
eatt_device* eatt_dev = find_device_by_address(bd_addr);
- if (!eatt_dev) return;
+ if (!eatt_dev) {
+ LOG(WARNING) << __func__ << " no eatt device found";
+ return;
+ }
+
+ if (!eatt_dev->eatt_tcb_) {
+ LOG_ASSERT(eatt_dev->eatt_channels.size() == 0);
+ LOG(WARNING) << __func__ << " no eatt channels found";
+ return;
+ }
auto iter = eatt_dev->eatt_channels.begin();
while (iter != eatt_dev->eatt_channels.end()) {
@@ -626,9 +637,9 @@
return;
}
- /* For new device, first check if EATT is supported. */
- if (gatt_profile_get_eatt_support(
- bd_addr, base::BindOnce(&eatt_impl::eatt_is_supported_cb,
+ /* For new device, first read GATT server supported features. */
+ if (gatt_cl_read_sr_supp_feat_req(
+ bd_addr, base::BindOnce(&eatt_impl::supported_features_cb,
base::Unretained(this))) == false) {
LOG(INFO) << __func__ << "Eatt is not supported. Checked for device "
<< bd_addr;
diff --git a/stack/gap/gap_ble.cc b/stack/gap/gap_ble.cc
index e065488..f6b047c 100644
--- a/stack/gap/gap_ble.cc
+++ b/stack/gap/gap_ble.cc
@@ -412,7 +412,7 @@
Uuid app_uuid = Uuid::From128BitBE(tmp);
gatt_attr.fill({});
- gatt_if = GATT_Register(app_uuid, &gap_cback, false);
+ gatt_if = GATT_Register(app_uuid, "Gap", &gap_cback, false);
GATT_StartIf(gatt_if);
diff --git a/stack/gatt/att_protocol.cc b/stack/gatt/att_protocol.cc
index 0d564bd..87da319 100644
--- a/stack/gatt/att_protocol.cc
+++ b/stack/gatt/att_protocol.cc
@@ -437,7 +437,7 @@
LOG_DEBUG(
"Sending ATT command to l2cap cid:0x%04x eatt_channels:%u transport:%s",
- p_clcb->cid, tcb.eatt, BtTransportText(tcb.transport).c_str());
+ p_clcb->cid, tcb.eatt, bt_transport_text(tcb.transport).c_str());
tGATT_STATUS att_ret = attp_send_msg_to_l2cap(tcb, p_clcb->cid, p_cmd);
if (att_ret != GATT_CONGESTED && att_ret != GATT_SUCCESS) {
LOG_WARN("Unable to send ATT command to l2cap layer");
diff --git a/stack/gatt/connection_manager.cc b/stack/gatt/connection_manager.cc
index 2d71d63..4c01d13 100644
--- a/stack/gatt/connection_manager.cc
+++ b/stack/gatt/connection_manager.cc
@@ -133,6 +133,17 @@
return true;
}
+/** Removes the registrations for connection for given device.
+ * but does not change the controller acceptlist. Used for
+ * shim purposes.
+ * Returns true if anything was removed, false otherwise */
+bool remove_unconditional_from_shim(const RawAddress& address) {
+ auto it = bgconn_dev.find(address);
+ if (it == bgconn_dev.end()) return false;
+ 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 */
diff --git a/stack/gatt/connection_manager.h b/stack/gatt/connection_manager.h
index 4d8295e..b5c39d3 100644
--- a/stack/gatt/connection_manager.h
+++ b/stack/gatt/connection_manager.h
@@ -41,6 +41,7 @@
extern bool background_connect_remove(tAPP_ID app_id,
const RawAddress& address);
extern bool remove_unconditional(const RawAddress& address);
+extern bool remove_unconditional_from_shim(const RawAddress& address);
extern void reset(bool after_reset);
diff --git a/stack/gatt/gatt_api.cc b/stack/gatt/gatt_api.cc
index 1edb9a6..9f350d8 100644
--- a/stack/gatt/gatt_api.cc
+++ b/stack/gatt/gatt_api.cc
@@ -23,9 +23,10 @@
******************************************************************************/
#include "bt_target.h"
+#include <string>
+
#include <base/strings/string_number_conversions.h>
#include <stdio.h>
-#include <string.h>
#include "bt_common.h"
#include "device/include/controller.h"
#include "gatt_api.h"
@@ -986,7 +987,8 @@
* with GATT
*
******************************************************************************/
-tGATT_IF GATT_Register(const Uuid& app_uuid128, tGATT_CBACK* p_cb_info, bool eatt_support) {
+tGATT_IF GATT_Register(const Uuid& app_uuid128, std::string name,
+ tGATT_CBACK* p_cb_info, bool eatt_support) {
tGATT_REG* p_reg;
uint8_t i_gatt_if = 0;
tGATT_IF gatt_if = 0;
@@ -1003,16 +1005,17 @@
for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS;
i_gatt_if++, p_reg++) {
if (!p_reg->in_use) {
- memset(p_reg, 0, sizeof(tGATT_REG));
+ *p_reg = {};
i_gatt_if++; /* one based number */
p_reg->app_uuid128 = app_uuid128;
gatt_if = p_reg->gatt_if = (tGATT_IF)i_gatt_if;
p_reg->app_cb = *p_cb_info;
p_reg->in_use = true;
p_reg->eatt_support = eatt_support;
- LOG(INFO) << __func__ << ": Allocated gatt_if=" << +gatt_if
- << " eatt_support=" << std::boolalpha << eatt_support
- << std::noboolalpha << " " << app_uuid128;
+ p_reg->name = name;
+ LOG_INFO("Allocated name:%s uuid:%s gatt_if:%hhu eatt_support:%u",
+ name.c_str(), app_uuid128.ToString().c_str(), gatt_if,
+ eatt_support);
return gatt_if;
}
}
@@ -1087,7 +1090,7 @@
connection_manager::on_app_deregistered(gatt_if);
- memset(p_reg, 0, sizeof(tGATT_REG));
+ *p_reg = {};
}
/*******************************************************************************
@@ -1121,8 +1124,8 @@
p_tcb = gatt_find_tcb_by_addr(bda, transport);
if (p_reg->app_cb.p_conn_cb && p_tcb) {
conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
- (*p_reg->app_cb.p_conn_cb)(gatt_if, bda, conn_id, true,
- GATT_CONN_UNKNOWN, transport);
+ (*p_reg->app_cb.p_conn_cb)(gatt_if, bda, conn_id, true, GATT_CONN_OK,
+ transport);
}
start_idx = ++found_idx;
}
diff --git a/stack/gatt/gatt_attr.cc b/stack/gatt/gatt_attr.cc
index 06af587..21058de 100644
--- a/stack/gatt/gatt_attr.cc
+++ b/stack/gatt/gatt_attr.cc
@@ -29,6 +29,7 @@
#include "bt_target.h"
#include "bt_utils.h"
#include "btif/include/btif_storage.h"
+#include "eatt/eatt.h"
#include "gatt_api.h"
#include "gatt_int.h"
#include "gd/common/init_flags.h"
@@ -47,11 +48,12 @@
#define BLE_GATT_CL_ANDROID_SUP_FEAT \
(BLE_GATT_CL_SUP_FEAT_EATT_BITMASK | BLE_GATT_CL_SUP_FEAT_MULTI_NOTIF_BITMASK)
-using gatt_eatt_support_cb = base::OnceCallback<void(const RawAddress&, bool)>;
+using gatt_sr_supported_feat_cb =
+ base::OnceCallback<void(const RawAddress&, uint8_t)>;
typedef struct {
uint16_t op_uuid;
- gatt_eatt_support_cb cb;
+ gatt_sr_supported_feat_cb cb;
} gatt_op_cb_data;
static std::map<uint16_t, gatt_op_cb_data> OngoingOps;
@@ -370,8 +372,8 @@
tmp.fill(0x81);
/* Create a GATT profile service */
- gatt_cb.gatt_if =
- GATT_Register(Uuid::From128BitBE(tmp), &gatt_profile_cback, false);
+ gatt_cb.gatt_if = GATT_Register(Uuid::From128BitBE(tmp), "GattProfileDb",
+ &gatt_profile_cback, false);
GATT_StartIf(gatt_cb.gatt_if);
Uuid service_uuid = Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER);
@@ -502,19 +504,6 @@
gatt_cl_start_config_ccc(p_clcb);
}
-static void gatt_attr_send_is_eatt_cb(uint16_t conn_id, gatt_op_cb_data* cb,
- bool eatt_supported) {
- tGATT_IF gatt_if;
- RawAddress bd_addr;
- tBT_TRANSPORT transport;
-
- GATT_GetConnectionInfor(conn_id, &gatt_if, bd_addr, &transport);
-
- std::move(cb->cb).Run(bd_addr, eatt_supported);
-
- cb->op_uuid = 0;
-}
-
static bool gatt_svc_read_cl_supp_feat_req(uint16_t conn_id,
gatt_op_cb_data* cb) {
tGATT_READ_PARAM param;
@@ -572,7 +561,8 @@
tGATT_CL_COMPLETE* p_data) {
auto iter = OngoingOps.find(conn_id);
- VLOG(1) << __func__ << " opcode: " << loghex(op) << " status: " << status
+ VLOG(1) << __func__ << " opcode: " << loghex(static_cast<uint8_t>(op))
+ << " status: " << status
<< " conn id: " << loghex(static_cast<uint8_t>(conn_id));
if (op != GATTC_OPTYPE_READ) return;
@@ -584,6 +574,7 @@
gatt_op_cb_data* operation_callback_data = &iter->second;
uint16_t cl_op_uuid = operation_callback_data->op_uuid;
+ operation_callback_data->op_uuid = 0;
uint8_t* pp = p_data->att_value.value;
@@ -591,24 +582,24 @@
switch (cl_op_uuid) {
case GATT_UUID_SERVER_SUP_FEAT: {
- uint8_t supported_feat_mask = 0;
+ uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
+ tGATT_TCB& tcb = gatt_cb.tcb[tcb_idx];
/* Check if EATT is supported */
if (status == GATT_SUCCESS) {
- STREAM_TO_UINT8(supported_feat_mask, pp);
+ STREAM_TO_UINT8(tcb.sr_supp_feat, pp);
+ btif_storage_set_gatt_sr_supp_feat(tcb.peer_bda, tcb.sr_supp_feat);
}
- /* Notify user if eatt is supported */
- bool eatt_supported =
- supported_feat_mask & BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK;
- gatt_attr_send_is_eatt_cb(conn_id, operation_callback_data,
- eatt_supported);
+ /* Notify user about the supported features */
+ std::move(operation_callback_data->cb)
+ .Run(tcb.peer_bda, tcb.sr_supp_feat);
/* If server supports EATT lets try to find handle for the
* client supported features characteristic, where we could write
* our supported features as a client.
*/
- if (eatt_supported) {
+ if (tcb.sr_supp_feat & BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK) {
/* If read succeed, return here */
if (gatt_svc_read_cl_supp_feat_req(conn_id, operation_callback_data))
return;
@@ -716,19 +707,46 @@
/*******************************************************************************
*
- * Function gatt_svc_read_supp_feat_req
+ * Function gatt_cl_init_sr_status
+ *
+ * Description Restore status for trusted GATT Server device
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void gatt_cl_init_sr_status(tGATT_TCB& tcb) {
+ tcb.sr_supp_feat = btif_storage_get_sr_supp_feat(tcb.peer_bda);
+
+ if (tcb.sr_supp_feat & BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK)
+ bluetooth::eatt::EattExtension::AddFromStorage(tcb.peer_bda);
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_cl_read_sr_supp_feat_req
*
* Description Read remote device supported GATT feature mask.
*
* Returns bool
*
******************************************************************************/
-static bool gatt_svc_read_supp_feat_req(
- const RawAddress& peer_bda, uint16_t conn_id,
- base::OnceCallback<void(const RawAddress&, bool)> cb) {
+bool gatt_cl_read_sr_supp_feat_req(
+ const RawAddress& peer_bda,
+ base::OnceCallback<void(const RawAddress&, uint8_t)> cb) {
+ tGATT_PROFILE_CLCB* p_clcb;
tGATT_READ_PARAM param;
- tGATT_PROFILE_CLCB* p_clcb = gatt_profile_find_clcb_by_conn_id(conn_id);
+ uint16_t conn_id;
+ if (!cb) return false;
+
+ VLOG(1) << __func__ << " BDA: " << peer_bda
+ << " read gatt supported features";
+
+ GATT_GetConnIdIfConnected(gatt_cb.gatt_if, peer_bda, &conn_id,
+ BT_TRANSPORT_LE);
+ if (conn_id == GATT_INVALID_CONN_ID) return false;
+
+ p_clcb = gatt_profile_find_clcb_by_conn_id(conn_id);
if (!p_clcb) {
p_clcb = gatt_profile_clcb_alloc(conn_id, peer_bda, BT_TRANSPORT_LE);
}
@@ -772,18 +790,13 @@
*
* Description Check if EATT is supported with remote device.
*
- * Returns false in case read could not be sent.
+ * Returns if EATT is supported.
*
******************************************************************************/
-bool gatt_profile_get_eatt_support(
- const RawAddress& remote_bda,
- base::OnceCallback<void(const RawAddress&, bool)> cb) {
+bool gatt_profile_get_eatt_support(const RawAddress& remote_bda) {
uint16_t conn_id;
- if (!cb) return false;
-
- VLOG(1) << __func__ << " BDA: " << remote_bda
- << " read gatt supported features";
+ VLOG(1) << __func__ << " BDA: " << remote_bda << " read GATT support";
GATT_GetConnIdIfConnected(gatt_cb.gatt_if, remote_bda, &conn_id,
BT_TRANSPORT_LE);
@@ -791,7 +804,10 @@
/* This read is important only when connected */
if (conn_id == GATT_INVALID_CONN_ID) return false;
- return gatt_svc_read_supp_feat_req(remote_bda, conn_id, std::move(cb));
+ /* Get tcb info */
+ uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
+ tGATT_TCB& tcb = gatt_cb.tcb[tcb_idx];
+ return tcb.sr_supp_feat & BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK;
}
/*******************************************************************************
diff --git a/stack/gatt/gatt_auth.cc b/stack/gatt/gatt_auth.cc
index c3aed25..c27ba61 100644
--- a/stack/gatt/gatt_auth.cc
+++ b/stack/gatt/gatt_auth.cc
@@ -27,12 +27,12 @@
#include <string.h>
#include "bt_common.h"
-#include "btm_int.h"
#include "gatt_api.h"
#include "gatt_int.h"
#include "osi/include/osi.h"
#include "stack/btm/btm_ble_int.h"
#include "stack/btm/btm_ble_int_types.h"
+#include "stack/btm/btm_int.h"
#include "stack/btm/btm_sec.h"
using base::StringPrintf;
diff --git a/stack/gatt/gatt_cl.cc b/stack/gatt/gatt_cl.cc
index b70a880..aef2d2e 100644
--- a/stack/gatt/gatt_cl.cc
+++ b/stack/gatt/gatt_cl.cc
@@ -29,11 +29,11 @@
#include "bt_common.h"
#include "bt_target.h"
#include "bt_utils.h"
-#include "eatt.h"
#include "gatt_int.h"
#include "l2c_api.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
+#include "stack/eatt/eatt.h"
#define GATT_WRITE_LONG_HDR_SIZE 5 /* 1 opcode + 2 handle + 2 offset */
#define GATT_READ_CHAR_VALUE_HDL (GATT_READ_CHAR_VALUE | 0x80)
@@ -626,9 +626,9 @@
tGATT_STATUS encrypt_status;
uint8_t* p = p_data;
uint8_t i;
- uint8_t event = (op_code == GATT_HANDLE_VALUE_IND)
- ? GATTC_OPTYPE_INDICATION
- : GATTC_OPTYPE_NOTIFICATION;
+ tGATTC_OPTYPE event = (op_code == GATT_HANDLE_VALUE_IND)
+ ? GATTC_OPTYPE_INDICATION
+ : GATTC_OPTYPE_NOTIFICATION;
VLOG(1) << __func__;
diff --git a/stack/gatt/gatt_db.cc b/stack/gatt/gatt_db.cc
index 477e261..f7d18e4 100644
--- a/stack/gatt/gatt_db.cc
+++ b/stack/gatt/gatt_db.cc
@@ -311,23 +311,6 @@
}
}
-#if (BLE_DELAY_REQUEST_ENC == TRUE)
- uint8_t flag = 0;
- if (BTM_GetSecurityFlags(tcb.peer_bda, &flag)) {
- if ((tcb.att_lcid == L2CAP_ATT_CID) && (status == GATT_PENDING) &&
- (type.As16Bit() == GATT_UUID_GAP_DEVICE_NAME)) {
- if ((flag & (BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_FLAG_ENCRYPTED)) ==
- BTM_SEC_LINK_KEY_KNOWN) {
- tHCI_ROLE role = HCI_ROLE_UNKNOWN;
- BTM_GetRole(tcb.peer_bda, &role);
- if (role == HCI_ROLE_CENTRAL) {
- btm_ble_set_encryption(tcb.peer_bda, BTM_BLE_SEC_ENCRYPT,
- HCI_ROLE_CENTRAL);
- }
- }
- }
- }
-#endif
return status;
}
diff --git a/stack/gatt/gatt_int.h b/stack/gatt/gatt_int.h
index dd031f8..b7278bf 100644
--- a/stack/gatt/gatt_int.h
+++ b/stack/gatt/gatt_int.h
@@ -41,14 +41,35 @@
#define GATT_TRANS_ID_MAX 0x0fffffff /* 4 MSB is reserved */
/* security action for GATT write and read request */
-#define GATT_SEC_NONE 0
-#define GATT_SEC_OK 1
-#define GATT_SEC_SIGN_DATA 2 /* compute the signature for the write cmd */
-#define GATT_SEC_ENCRYPT 3 /* encrypt the link with current key */
-#define GATT_SEC_ENCRYPT_NO_MITM 4 /* unauthenticated encryption or better */
-#define GATT_SEC_ENCRYPT_MITM 5 /* authenticated encryption */
-#define GATT_SEC_ENC_PENDING 6 /* wait for link encryption pending */
-typedef uint8_t tGATT_SEC_ACTION;
+typedef enum : uint8_t {
+ GATT_SEC_NONE = 0,
+ GATT_SEC_OK = 1,
+ GATT_SEC_SIGN_DATA = 2, /* compute the signature for the write cmd */
+ GATT_SEC_ENCRYPT = 3, /* encrypt the link with current key */
+ GATT_SEC_ENCRYPT_NO_MITM = 4, /* unauthenticated encryption or better */
+ GATT_SEC_ENCRYPT_MITM = 5, /* authenticated encryption */
+ GATT_SEC_ENC_PENDING = 6, /* wait for link encryption pending */
+} tGATT_SEC_ACTION;
+
+#define CASE_RETURN_TEXT(code) \
+ case code: \
+ return #code
+
+inline std::string gatt_security_action_text(const tGATT_SEC_ACTION& action) {
+ switch (action) {
+ CASE_RETURN_TEXT(GATT_SEC_NONE);
+ CASE_RETURN_TEXT(GATT_SEC_OK);
+ CASE_RETURN_TEXT(GATT_SEC_SIGN_DATA);
+ CASE_RETURN_TEXT(GATT_SEC_ENCRYPT);
+ CASE_RETURN_TEXT(GATT_SEC_ENCRYPT_NO_MITM);
+ CASE_RETURN_TEXT(GATT_SEC_ENCRYPT_MITM);
+ CASE_RETURN_TEXT(GATT_SEC_ENC_PENDING);
+ default:
+ return std::string("UNKNOWN[%hhu]", action);
+ }
+}
+
+#undef CASE_RETURN_TEXT
#define GATT_INDEX_INVALID 0xff
@@ -167,11 +188,12 @@
typedef struct {
bluetooth::Uuid app_uuid128;
- tGATT_CBACK app_cb;
- tGATT_IF gatt_if; /* one based */
- bool in_use;
- uint8_t listening; /* if adv for all has been enabled */
- bool eatt_support;
+ tGATT_CBACK app_cb{};
+ tGATT_IF gatt_if{0}; /* one based */
+ bool in_use{false};
+ uint8_t listening{0}; /* if adv for all has been enabled */
+ bool eatt_support{false};
+ std::string name;
} tGATT_REG;
struct tGATT_CLCB;
@@ -214,6 +236,23 @@
GATT_CH_OPEN = 4,
} tGATT_CH_STATE;
+#define CASE_RETURN_TEXT(code) \
+ case code: \
+ return #code
+
+inline std::string gatt_channel_state_text(const tGATT_CH_STATE& state) {
+ switch (state) {
+ CASE_RETURN_TEXT(GATT_CH_CLOSE);
+ CASE_RETURN_TEXT(GATT_CH_CLOSING);
+ CASE_RETURN_TEXT(GATT_CH_CONN);
+ CASE_RETURN_TEXT(GATT_CH_CFG);
+ CASE_RETURN_TEXT(GATT_CH_OPEN);
+ default:
+ return std::string("UNKNOWN[%hhu]", state);
+ }
+}
+#undef CASE_RETURN_TEXT
+
#define GATT_GATT_START_HANDLE 1
#define GATT_GAP_START_HANDLE 20
#define GATT_APP_START_HANDLE 40
@@ -258,7 +297,6 @@
uint16_t payload_size;
tGATT_CH_STATE ch_state;
- uint8_t ch_flags;
std::unordered_set<uint8_t> app_hold_link;
@@ -279,6 +317,8 @@
// TODO(hylo): support byte array data
/* Client supported feature*/
uint8_t cl_supp_feat;
+ /* Server supported features */
+ uint8_t sr_supp_feat;
/* Use for server. if false, should handle database out of sync. */
bool is_robust_cache_change_aware;
@@ -305,7 +345,7 @@
uint16_t counter; /* used as offset, attribute length, num of prepare write */
uint16_t start_offset;
tGATT_AUTH_REQ auth_req; /* authentication requirement */
- uint8_t operation; /* one logic channel can have one operation active */
+ tGATTC_OPTYPE operation; /* one logic channel can have one operation active */
uint8_t op_subtype; /* operation subtype */
tGATT_STATUS status; /* operation status */
bool first_read_blob_after_read;
@@ -421,9 +461,11 @@
/* from gatt_attr.cc */
extern uint16_t gatt_profile_find_conn_id_by_bd_addr(const RawAddress& bda);
-extern bool gatt_profile_get_eatt_support(
- const RawAddress& remote_bda,
- base::OnceCallback<void(const RawAddress&, bool)> cb);
+extern bool gatt_profile_get_eatt_support(const RawAddress& remote_bda);
+extern void gatt_cl_init_sr_status(tGATT_TCB& tcb);
+extern bool gatt_cl_read_sr_supp_feat_req(
+ const RawAddress& peer_bda,
+ base::OnceCallback<void(const RawAddress&, uint8_t)> cb);
extern bool gatt_sr_is_cl_change_aware(tGATT_TCB& tcb);
extern void gatt_sr_init_cl_status(tGATT_TCB& tcb);
diff --git a/stack/gatt/gatt_main.cc b/stack/gatt/gatt_main.cc
index 322653b..164a86f 100644
--- a/stack/gatt/gatt_main.cc
+++ b/stack/gatt/gatt_main.cc
@@ -26,15 +26,15 @@
#include "bt_common.h"
#include "bt_utils.h"
-#include "btif_storage.h"
-#include "btm_ble_int.h"
+#include "btif/include/btif_storage.h"
#include "connection_manager.h"
#include "device/include/interop.h"
-#include "eatt.h"
#include "l2c_api.h"
#include "osi/include/osi.h"
+#include "stack/btm/btm_ble_int.h"
#include "stack/btm/btm_dev.h"
#include "stack/btm/btm_sec.h"
+#include "stack/eatt/eatt.h"
#include "stack/gatt/gatt_int.h"
#include "stack/include/l2cap_acl_interface.h"
@@ -167,8 +167,10 @@
}
gatt_cb.hdl_list_info->clear();
+ delete gatt_cb.hdl_list_info;
gatt_cb.hdl_list_info = nullptr;
gatt_cb.srv_list_info->clear();
+ delete gatt_cb.srv_list_info;
gatt_cb.srv_list_info = nullptr;
EattExtension::GetInstance()->Stop();
diff --git a/stack/gatt/gatt_sr.cc b/stack/gatt/gatt_sr.cc
index e637eb2..d9b2ef0 100644
--- a/stack/gatt/gatt_sr.cc
+++ b/stack/gatt/gatt_sr.cc
@@ -28,9 +28,9 @@
#include "gatt_int.h"
#include "l2c_api.h"
-#include "l2c_int.h"
#include "osi/include/log.h"
#include "stack/eatt/eatt.h"
+#include "stack/l2cap/l2c_int.h"
#define GATT_MTU_REQ_MIN_LEN 2
using base::StringPrintf;
@@ -849,9 +849,9 @@
* Returns void
*
******************************************************************************/
-void gatts_process_read_by_type_req(tGATT_TCB& tcb, uint16_t cid,
- uint8_t op_code, uint16_t len,
- uint8_t* p_data) {
+static void gatts_process_read_by_type_req(tGATT_TCB& tcb, uint16_t cid,
+ uint8_t op_code, uint16_t len,
+ uint8_t* p_data) {
Uuid uuid = Uuid::kEmpty;
uint16_t s_hdl = 0, e_hdl = 0, err_hdl = 0;
tGATT_STATUS reason =
diff --git a/stack/gatt/gatt_sr_hash.cc b/stack/gatt/gatt_sr_hash.cc
index b5aa68a..c664d14 100644
--- a/stack/gatt/gatt_sr_hash.cc
+++ b/stack/gatt/gatt_sr_hash.cc
@@ -19,8 +19,8 @@
#include <base/strings/string_number_conversions.h>
#include <list>
-#include "crypto_toolbox/crypto_toolbox.h"
#include "gatt_int.h"
+#include "stack/crypto_toolbox/crypto_toolbox.h"
using bluetooth::Uuid;
diff --git a/stack/gatt/gatt_utils.cc b/stack/gatt/gatt_utils.cc
index 6de437f..64822e1 100644
--- a/stack/gatt/gatt_utils.cc
+++ b/stack/gatt/gatt_utils.cc
@@ -446,6 +446,7 @@
p_tcb->peer_bda = bda;
p_tcb->eatt = 0;
gatt_sr_init_cl_status(*p_tcb);
+ gatt_cl_init_sr_status(*p_tcb);
return p_tcb;
}
@@ -1480,7 +1481,7 @@
tGATT_CL_COMPLETE cb_data;
tGATT_CMPL_CBACK* p_cmpl_cb =
(p_clcb->p_reg) ? p_clcb->p_reg->app_cb.p_cmpl_cb : NULL;
- uint8_t op = p_clcb->operation;
+ tGATTC_OPTYPE op = p_clcb->operation;
tGATT_DISC_TYPE disc_type = GATT_DISC_MAX;
tGATT_DISC_CMPL_CB* p_disc_cmpl_cb =
(p_clcb->p_reg) ? p_clcb->p_reg->app_cb.p_disc_cmpl_cb : NULL;
@@ -1613,8 +1614,5 @@
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);
if (p_tcb) gatt_update_app_use_link_flag(gatt_if, p_tcb, false, false);
- if (bluetooth::shim::is_gd_acl_enabled()) {
- acl_add_to_ignore_auto_connect_after_disconnect(bd_addr);
- }
return connection_manager::background_connect_remove(gatt_if, bd_addr);
}
diff --git a/stack/hid/hid_conn.h b/stack/hid/hid_conn.h
index 7595d78..e92d491 100644
--- a/stack/hid/hid_conn.h
+++ b/stack/hid/hid_conn.h
@@ -27,18 +27,39 @@
#include "osi/include/alarm.h"
+typedef enum : uint8_t {
+ HID_CONN_STATE_UNUSED = 0,
+ HID_CONN_STATE_CONNECTING_CTRL = 1,
+ HID_CONN_STATE_CONNECTING_INTR = 2,
+ HID_CONN_STATE_CONFIG = 3,
+ HID_CONN_STATE_CONNECTED = 4,
+ HID_CONN_STATE_DISCONNECTING = 5,
+ HID_CONN_STATE_SECURITY = 6,
+} tHID_CONN_STATE;
+
/* Define the HID Connection Block
*/
typedef struct hid_conn {
-#define HID_CONN_STATE_UNUSED (0)
-#define HID_CONN_STATE_CONNECTING_CTRL (1)
-#define HID_CONN_STATE_CONNECTING_INTR (2)
-#define HID_CONN_STATE_CONFIG (3)
-#define HID_CONN_STATE_CONNECTED (4)
-#define HID_CONN_STATE_DISCONNECTING (5)
-#define HID_CONN_STATE_SECURITY (6)
+ tHID_CONN_STATE conn_state;
- uint8_t conn_state;
+#define CASE_RETURN_TEXT(code) \
+ case code: \
+ return #code
+
+ static inline std::string state_text(const tHID_CONN_STATE& state) {
+ switch (state) {
+ CASE_RETURN_TEXT(HID_CONN_STATE_UNUSED);
+ CASE_RETURN_TEXT(HID_CONN_STATE_CONNECTING_CTRL);
+ CASE_RETURN_TEXT(HID_CONN_STATE_CONNECTING_INTR);
+ CASE_RETURN_TEXT(HID_CONN_STATE_CONFIG);
+ CASE_RETURN_TEXT(HID_CONN_STATE_CONNECTED);
+ CASE_RETURN_TEXT(HID_CONN_STATE_DISCONNECTING);
+ CASE_RETURN_TEXT(HID_CONN_STATE_SECURITY);
+ default:
+ return std::string("UNKNOWN[%hhu]", state);
+ }
+ }
+#undef CASE_RETURN_TEXT
#define HID_CONN_FLAGS_IS_ORIG (0x01)
#define HID_CONN_FLAGS_CONGESTED (0x20)
diff --git a/stack/hid/hidd_conn.cc b/stack/hid/hidd_conn.cc
index 1d4e8ef..da6b46d 100644
--- a/stack/hid/hidd_conn.cc
+++ b/stack/hid/hidd_conn.cc
@@ -62,9 +62,7 @@
*
******************************************************************************/
static void hidd_check_config_done() {
- tHID_CONN* p_hcon;
-
- p_hcon = &hd_cb.device.conn;
+ tHID_CONN* p_hcon = &hd_cb.device.conn;
if (p_hcon->conn_state == HID_CONN_STATE_CONFIG) {
p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
@@ -92,7 +90,6 @@
******************************************************************************/
static void hidd_l2cif_connect_ind(const RawAddress& bd_addr, uint16_t cid,
uint16_t psm, uint8_t id) {
- tHID_CONN* p_hcon;
tHID_DEV_DEV_CTB* p_dev;
bool accept = TRUE; // accept by default
@@ -108,7 +105,7 @@
return;
}
- p_hcon = &hd_cb.device.conn;
+ tHID_CONN* p_hcon = &hd_cb.device.conn;
switch (psm) {
case HID_PSM_INTERRUPT:
@@ -231,11 +228,9 @@
*
******************************************************************************/
static void hidd_l2cif_config_ind(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) {
- tHID_CONN* p_hcon;
-
HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid);
- p_hcon = &hd_cb.device.conn;
+ tHID_CONN* p_hcon = &hd_cb.device.conn;
if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) {
HIDD_TRACE_WARNING("%s: unknown cid", __func__);
@@ -261,11 +256,10 @@
tL2CAP_CFG_INFO* p_cfg) {
hidd_l2cif_config_ind(cid, p_cfg);
- tHID_CONN* p_hcon;
HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid);
- p_hcon = &hd_cb.device.conn;
+ tHID_CONN* p_hcon = &hd_cb.device.conn;
if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) {
HIDD_TRACE_WARNING("%s: unknown cid", __func__);
@@ -306,11 +300,10 @@
*
******************************************************************************/
static void hidd_l2cif_disconnect_ind(uint16_t cid, bool ack_needed) {
- tHID_CONN* p_hcon;
HIDD_TRACE_EVENT("%s: cid=%04x ack_needed=%d", __func__, cid, ack_needed);
- p_hcon = &hd_cb.device.conn;
+ tHID_CONN* p_hcon = &hd_cb.device.conn;
if (p_hcon->conn_state == HID_CONN_STATE_UNUSED ||
(p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
@@ -345,11 +338,10 @@
static void hidd_l2cif_disconnect(uint16_t cid) {
L2CA_DisconnectReq(cid);
- tHID_CONN* p_hcon;
HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid);
- p_hcon = &hd_cb.device.conn;
+ tHID_CONN* p_hcon = &hd_cb.device.conn;
if (p_hcon->conn_state == HID_CONN_STATE_UNUSED ||
(p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
@@ -393,11 +385,10 @@
*
******************************************************************************/
static void hidd_l2cif_cong_ind(uint16_t cid, bool congested) {
- tHID_CONN* p_hcon;
HIDD_TRACE_EVENT("%s: cid=%04x congested=%d", __func__, cid, congested);
- p_hcon = &hd_cb.device.conn;
+ tHID_CONN* p_hcon = &hd_cb.device.conn;
if (p_hcon->conn_state == HID_CONN_STATE_UNUSED ||
(p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
@@ -422,7 +413,6 @@
*
******************************************************************************/
static void hidd_l2cif_data_ind(uint16_t cid, BT_HDR* p_msg) {
- tHID_CONN* p_hcon;
uint8_t* p_data = (uint8_t*)(p_msg + 1) + p_msg->offset;
uint8_t msg_type, param;
bool err = FALSE;
@@ -435,7 +425,7 @@
return;
}
- p_hcon = &hd_cb.device.conn;
+ tHID_CONN* p_hcon = &hd_cb.device.conn;
if (p_hcon->conn_state == HID_CONN_STATE_UNUSED ||
(p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
@@ -660,7 +650,6 @@
*
******************************************************************************/
tHID_STATUS hidd_conn_disconnect(void) {
- tHID_CONN* p_hcon;
HIDD_TRACE_API("%s", __func__);
@@ -670,7 +659,7 @@
hd_cb.pending_data = NULL;
}
- p_hcon = &hd_cb.device.conn;
+ tHID_CONN* p_hcon = &hd_cb.device.conn;
if ((p_hcon->ctrl_cid != 0) || (p_hcon->intr_cid != 0)) {
p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
@@ -704,7 +693,6 @@
tHID_STATUS hidd_conn_send_data(uint8_t channel, uint8_t msg_type,
uint8_t param, uint8_t data, uint16_t len,
uint8_t* p_data) {
- tHID_CONN* p_hcon;
BT_HDR* p_buf;
uint8_t* p_out;
uint16_t cid;
@@ -713,7 +701,7 @@
HIDD_TRACE_VERBOSE("%s: channel(%d), msg_type(%d), len(%d)", __func__,
channel, msg_type, len);
- p_hcon = &hd_cb.device.conn;
+ tHID_CONN* p_hcon = &hd_cb.device.conn;
if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) {
return HID_ERR_CONGESTED;
diff --git a/stack/hid/hidd_int.h b/stack/hid/hidd_int.h
index 0981dcc..400b769 100644
--- a/stack/hid/hidd_int.h
+++ b/stack/hid/hidd_int.h
@@ -26,9 +26,12 @@
#ifndef HIDD_INT_H
#define HIDD_INT_H
-#include "hid_conn.h"
-#include "hidd_api.h"
-#include "l2c_api.h"
+#include <cstdint>
+
+#include "stack/hid/hid_conn.h"
+#include "stack/include/hidd_api.h"
+#include "stack/include/l2c_api.h" // tL2CAP_CFG_INFO && FLOW_SPEC
+#include "types/raw_address.h"
enum { HIDD_DEV_NO_CONN, HIDD_DEV_CONNECTED };
diff --git a/stack/hid/hidh_api.cc b/stack/hid/hidh_api.cc
index 1499abe..49ee928 100644
--- a/stack/hid/hidh_api.cc
+++ b/stack/hid/hidh_api.cc
@@ -40,7 +40,7 @@
tHID_HOST_CTB hh_cb;
-static void hidh_search_callback(uint16_t sdp_result);
+static void hidh_search_callback(tSDP_RESULT sdp_result);
/*******************************************************************************
*
@@ -88,7 +88,7 @@
str[0] = '\0';
}
-static void hidh_search_callback(uint16_t sdp_result) {
+static void hidh_search_callback(tSDP_RESULT sdp_result) {
tSDP_DISCOVERY_DB* p_db = hh_cb.p_sdp_db;
tSDP_DISC_REC* p_rec;
tSDP_DISC_ATTR *p_attr, *p_subattr1, *p_subattr2, *p_repdesc;
diff --git a/stack/hid/hidh_conn.cc b/stack/hid/hidh_conn.cc
index 31a30a4..87ded1c 100644
--- a/stack/hid/hidh_conn.cc
+++ b/stack/hid/hidh_conn.cc
@@ -22,6 +22,7 @@
*
******************************************************************************/
+#include <base/strings/stringprintf.h>
#include <string.h>
#include "bt_common.h"
@@ -40,6 +41,12 @@
#include "osi/include/osi.h"
#include "stack/btm/btm_sec.h"
#include "stack/include/acl_api.h"
+#include "stack/include/btm_api.h" // BTM_LogHistory
+
+namespace {
+constexpr char kBtmLogTag[] = "HIDH";
+constexpr uint8_t kHID_HOST_MAX_DEVICES = HID_HOST_MAX_DEVICES;
+}
static uint8_t find_conn_by_cid(uint16_t cid);
static void hidh_conn_retry(uint8_t dhandle);
@@ -109,7 +116,7 @@
return (HID_ERR_L2CAP_FAILED);
}
- for (xx = 0; xx < HID_HOST_MAX_DEVICES; xx++) {
+ for (xx = 0; xx < kHID_HOST_MAX_DEVICES; xx++) {
hh_cb.devices[xx].in_use = false;
hh_cb.devices[xx].conn.conn_state = HID_CONN_STATE_UNUSED;
}
@@ -141,6 +148,9 @@
hidh_l2cif_disconnect(p_hcon->intr_cid);
else if (p_hcon->ctrl_cid)
hidh_l2cif_disconnect(p_hcon->ctrl_cid);
+
+ BTM_LogHistory(kBtmLogTag, hh_cb.devices[dhandle].addr, "Disconnecting",
+ "local initiated");
} else {
p_hcon->conn_state = HID_CONN_STATE_UNUSED;
}
@@ -161,10 +171,8 @@
static void hidh_l2cif_connect_ind(const RawAddress& bd_addr,
uint16_t l2cap_cid, uint16_t psm,
uint8_t l2cap_id) {
- tHID_CONN* p_hcon;
bool bAccept = true;
- uint8_t i = HID_HOST_MAX_DEVICES;
- tHID_HOST_DEV_CTB* p_dev;
+ uint8_t i = kHID_HOST_MAX_DEVICES;
HIDH_TRACE_EVENT("HID-Host Rcvd L2CAP conn ind, PSM: 0x%04x CID 0x%x", psm,
l2cap_cid);
@@ -175,8 +183,13 @@
return;
}
- p_hcon = &hh_cb.devices[i].conn;
- p_dev = &hh_cb.devices[i];
+ tHID_CONN* p_hcon = &hh_cb.devices[i].conn;
+
+ BTM_LogHistory(
+ kBtmLogTag, hh_cb.devices[i].addr, "Connect request",
+ base::StringPrintf("%s state:%s",
+ (psm == HID_PSM_CONTROL) ? "control" : "interrupt",
+ hid_conn::state_text(p_hcon->conn_state).c_str()));
/* Check we are in the correct state for this */
if (psm == HID_PSM_INTERRUPT) {
@@ -216,6 +229,8 @@
disc_reason (from
HID_ERR_AUTH_FAILED) */
p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
+ BTM_LogHistory(kBtmLogTag, hh_cb.devices[i].addr, "Connecting",
+ "waiting for interrupt channel");
return;
}
@@ -256,6 +271,12 @@
static void hidh_on_l2cap_error(uint16_t l2cap_cid, uint16_t result) {
auto dhandle = find_conn_by_cid(l2cap_cid);
+ if (dhandle == kHID_HOST_MAX_DEVICES) {
+ LOG_WARN("Received error for unknown device cid:0x%04x reason:%s",
+ l2cap_cid,
+ hci_reason_code_text(to_hci_reason_code(result)).c_str());
+ return;
+ }
hidh_conn_disconnect(dhandle);
@@ -298,7 +319,7 @@
/* Find CCB based on CID, and verify we are in a state to accept this message
*/
dhandle = find_conn_by_cid(l2cap_cid);
- if (dhandle < HID_HOST_MAX_DEVICES) {
+ if (dhandle < kHID_HOST_MAX_DEVICES) {
p_dev = &hh_cb.devices[dhandle];
p_hcon = &hh_cb.devices[dhandle].conn;
}
@@ -331,7 +352,11 @@
} else {
p_hcon->conn_state = HID_CONN_STATE_CONFIG;
}
-
+ BTM_LogHistory(
+ kBtmLogTag, hh_cb.devices[dhandle].addr, "Configuring",
+ base::StringPrintf("control:0x%04x interrupt:0x%04x state:%s",
+ p_hcon->ctrl_cid, p_hcon->intr_cid,
+ hid_conn::state_text(p_hcon->conn_state).c_str()));
return;
}
@@ -351,7 +376,7 @@
/* Find CCB based on CID */
dhandle = find_conn_by_cid(l2cap_cid);
- if (dhandle < HID_HOST_MAX_DEVICES) {
+ if (dhandle < kHID_HOST_MAX_DEVICES) {
p_hcon = &hh_cb.devices[dhandle].conn;
}
@@ -392,7 +417,7 @@
/* Find CCB based on CID */
dhandle = find_conn_by_cid(l2cap_cid);
- if (dhandle < HID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn;
+ if (dhandle < kHID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn;
if (p_hcon == NULL) {
HIDH_TRACE_WARNING("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x%x",
@@ -414,6 +439,7 @@
HIDH_TRACE_WARNING("HID-Host INTR Originate failed");
reason = HID_L2CAP_REQ_FAIL;
p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+ BTM_LogHistory(kBtmLogTag, hh_cb.devices[dhandle].addr, "Failed");
hidh_conn_disconnect(dhandle);
hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
reason, NULL);
@@ -422,6 +448,8 @@
/* Transition to the next appropriate state, waiting for connection
* confirm on interrupt channel. */
p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
+ BTM_LogHistory(kBtmLogTag, hh_cb.devices[dhandle].addr, "Connecting",
+ "interrupt channel");
}
}
}
@@ -436,6 +464,11 @@
hh_cb.devices[dhandle].state = HID_DEV_CONNECTED;
hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_OPEN, 0,
NULL);
+ BTM_LogHistory(
+ kBtmLogTag, hh_cb.devices[dhandle].addr, "Connected",
+ base::StringPrintf("control:0x%04x interrupt:0x%04x state:%s",
+ p_hcon->ctrl_cid, p_hcon->intr_cid,
+ hid_conn::state_text(p_hcon->conn_state).c_str()));
}
}
@@ -457,7 +490,7 @@
/* Find CCB based on CID */
dhandle = find_conn_by_cid(l2cap_cid);
- if (dhandle < HID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn;
+ if (dhandle < kHID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn;
if (p_hcon == NULL) {
HIDH_TRACE_WARNING("HID-Host Rcvd L2CAP disc, unknown CID: 0x%x",
@@ -468,6 +501,11 @@
HIDH_TRACE_EVENT("HID-Host Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
+ BTM_LogHistory(
+ kBtmLogTag, hh_cb.devices[dhandle].addr, "Disconnecting",
+ base::StringPrintf("%s channel", (l2cap_cid == p_hcon->ctrl_cid)
+ ? "control"
+ : "interrupt"));
if (l2cap_cid == p_hcon->ctrl_cid)
p_hcon->ctrl_cid = 0;
@@ -522,7 +560,7 @@
/* Find CCB based on CID */
const uint8_t dhandle = find_conn_by_cid(l2cap_cid);
- if (dhandle == HID_HOST_MAX_DEVICES) {
+ if (dhandle == kHID_HOST_MAX_DEVICES) {
LOG_WARN("HID-Host Rcvd L2CAP disc cfm, unknown CID: 0x%x", l2cap_cid);
return;
}
@@ -535,12 +573,14 @@
if (p_hcon->ctrl_cid) {
HIDH_TRACE_EVENT("HID-Host Initiating L2CAP Ctrl disconnection");
L2CA_DisconnectReq(p_hcon->ctrl_cid);
+ p_hcon->ctrl_cid = 0;
}
}
if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {
hh_cb.devices[dhandle].state = HID_DEV_NO_CONN;
p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+ BTM_LogHistory(kBtmLogTag, hh_cb.devices[dhandle].addr, "Disconnected");
hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
p_hcon->disc_reason, NULL);
}
@@ -561,7 +601,7 @@
/* Find CCB based on CID */
dhandle = find_conn_by_cid(l2cap_cid);
- if (dhandle < HID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn;
+ if (dhandle < kHID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn;
if (p_hcon == NULL) {
HIDH_TRACE_WARNING(
@@ -606,7 +646,7 @@
/* Find CCB based on CID */
dhandle = find_conn_by_cid(l2cap_cid);
- if (dhandle < HID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn;
+ if (dhandle < kHID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn;
if (p_hcon == NULL) {
HIDH_TRACE_WARNING("HID-Host Rcvd L2CAP data, unknown CID: 0x%x",
@@ -833,6 +873,8 @@
/* Transition to the next appropriate state, waiting for connection confirm
* on control channel. */
p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_CTRL;
+ BTM_LogHistory(kBtmLogTag, hh_cb.devices[dhandle].addr, "Connecting",
+ "control channel");
}
return (HID_SUCCESS);
@@ -842,15 +884,16 @@
*
* Function find_conn_by_cid
*
- * Description This function finds a connection control block based on CID
+ * Description This function finds a connection control block based on CID.
*
- * Returns address of control block, or NULL if not found
+ * Returns index of control block, or kHID_HOST_MAX_DEVICES if not
+ * found.
*
******************************************************************************/
static uint8_t find_conn_by_cid(uint16_t cid) {
uint8_t xx;
- for (xx = 0; xx < HID_HOST_MAX_DEVICES; xx++) {
+ for (xx = 0; xx < kHID_HOST_MAX_DEVICES; xx++) {
if ((hh_cb.devices[xx].in_use) &&
(hh_cb.devices[xx].conn.conn_state != HID_CONN_STATE_UNUSED) &&
((hh_cb.devices[xx].conn.ctrl_cid == cid) ||
diff --git a/stack/hid/hidh_int.h b/stack/hid/hidh_int.h
index 2a0df78..fe9a3c8 100644
--- a/stack/hid/hidh_int.h
+++ b/stack/hid/hidh_int.h
@@ -25,9 +25,12 @@
#ifndef HIDH_INT_H
#define HIDH_INT_H
-#include "hid_conn.h"
-#include "hidh_api.h"
-#include "l2c_api.h"
+#include <cstdint>
+
+#include "stack/hid/hid_conn.h"
+#include "stack/include/hidh_api.h"
+#include "stack/include/l2c_api.h" // tL2CAP_CFG_INFO
+#include "types/raw_address.h"
enum { HID_DEV_NO_CONN, HID_DEV_CONNECTED };
@@ -38,7 +41,6 @@
reconn_initiate;
0x04- sdp_disable; */
uint8_t state; /* Device state if in HOST-KNOWN mode */
- uint8_t conn_substate;
uint8_t conn_tries; /* Remembers the number of connection attempts while
CONNECTING */
diff --git a/stack/include/a2dp_sbc_constants.h b/stack/include/a2dp_sbc_constants.h
index 87b9eb9..7426688 100644
--- a/stack/include/a2dp_sbc_constants.h
+++ b/stack/include/a2dp_sbc_constants.h
@@ -61,6 +61,7 @@
#define A2DP_SBC_IE_MIN_BITPOOL 2
#define A2DP_SBC_IE_MAX_BITPOOL 250
+#define A2DP_SBC_BITPOOL_MIDDLE_QUALITY 35
/* for media payload header */
#define A2DP_SBC_HDR_F_MSK 0x80
diff --git a/stack/include/acl_api.h b/stack/include/acl_api.h
index b4829d8..d7ecaef 100644
--- a/stack/include/acl_api.h
+++ b/stack/include/acl_api.h
@@ -309,8 +309,3 @@
void ACL_RegisterClient(struct acl_client_callback_s* callbacks);
void ACL_UnregisterClient(struct acl_client_callback_s* callbacks);
bool ACL_SupportTransparentSynchronousData(const RawAddress& bd_addr);
-
-void acl_add_to_ignore_auto_connect_after_disconnect(const RawAddress& bd_addr);
-bool acl_check_and_clear_ignore_auto_connect_after_disconnect(
- const RawAddress& bd_addr);
-void acl_clear_all_ignore_auto_connect_after_disconnect();
diff --git a/stack/include/acl_hci_link_interface.h b/stack/include/acl_hci_link_interface.h
index b134288..ffeec79 100644
--- a/stack/include/acl_hci_link_interface.h
+++ b/stack/include/acl_hci_link_interface.h
@@ -68,6 +68,7 @@
void acl_link_segments_xmitted(BT_HDR* p_msg);
void acl_process_num_completed_pkts(uint8_t* p, uint8_t evt_len);
void acl_packets_completed(uint16_t handle, uint16_t num_packets);
+void acl_process_supported_features(uint16_t handle, uint64_t features);
void acl_process_extended_features(uint16_t handle, uint8_t current_page_number,
uint8_t max_page_number, uint64_t features);
void btm_pm_on_mode_change(tHCI_STATUS status, uint16_t handle,
diff --git a/stack/include/bt_types.h b/stack/include/bt_types.h
index cf438e9..6091811 100644
--- a/stack/include/bt_types.h
+++ b/stack/include/bt_types.h
@@ -101,6 +101,17 @@
// and will not trigger various flexible member compilation issues.
} BT_HDR_RIGID;
+#ifdef __cplusplus
+template <typename T>
+T* ToPacketData(BT_HDR* bt_hdr, size_t offset = 0) {
+ return reinterpret_cast<T*>(bt_hdr->data + bt_hdr->offset + offset);
+}
+template <typename T>
+const T* ToPacketData(const BT_HDR* bt_hdr, size_t offset = 0) {
+ return reinterpret_cast<const T*>(bt_hdr->data + bt_hdr->offset + offset);
+}
+#endif // __cplusplus
+
#define BT_HDR_SIZE (sizeof(BT_HDR))
enum {
@@ -537,7 +548,7 @@
case BT_DEVICE_TYPE_BLE:
return std::string("BLE");
case BT_DEVICE_TYPE_DUMO:
- return std::string("BR_EDR and BLE");
+ return std::string("DUAL");
default:
return std::string("Unknown");
}
diff --git a/stack/include/btm_api.h b/stack/include/btm_api.h
index 008f870..eaac9c9 100644
--- a/stack/include/btm_api.h
+++ b/stack/include/btm_api.h
@@ -668,6 +668,24 @@
/*******************************************************************************
*
+ * Function BTM_GetPeerDeviceTypeFromFeatures
+ *
+ * Description This function is called to retrieve the peer device type
+ * by referencing the remote features.
+ *
+ * Parameters: bd_addr - address of the peer
+ *
+ * Returns BT_DEVICE_TYPE_DUMO if both BR/EDR and BLE transports are
+ * supported by the peer,
+ * BT_DEVICE_TYPE_BREDR if only BR/EDR transport is supported,
+ * BT_DEVICE_TYPE_BLE if only BLE transport is supported.
+ *
+ ******************************************************************************/
+extern tBT_DEVICE_TYPE BTM_GetPeerDeviceTypeFromFeatures(
+ const RawAddress& bd_addr);
+
+/*******************************************************************************
+ *
* Function BTM_SecReadDevName
*
* Description Looks for the device name in the security database for the
diff --git a/stack/include/btm_api_types.h b/stack/include/btm_api_types.h
index 2aa65a0..82a1824 100644
--- a/stack/include/btm_api_types.h
+++ b/stack/include/btm_api_types.h
@@ -74,6 +74,7 @@
/* 0x00 is used as unclassified for all minor device classes */
#define BTM_COD_MINOR_UNCLASSIFIED 0x00
+#define BTM_COD_MINOR_WEARABLE_HEADSET 0x04
#define BTM_COD_MINOR_CONFM_HANDSFREE 0x08
#define BTM_COD_MINOR_CAR_AUDIO 0x20
#define BTM_COD_MINOR_SET_TOP_BOX 0x24
@@ -270,12 +271,13 @@
/* 0x0A */
#define BTM_EIR_TX_POWER_LEVEL_TYPE HCI_EIR_TX_POWER_LEVEL_TYPE
-#define BTM_BLE_SEC_NONE 0
-/* encrypt the link using current key */
-#define BTM_BLE_SEC_ENCRYPT 1
-#define BTM_BLE_SEC_ENCRYPT_NO_MITM 2
-#define BTM_BLE_SEC_ENCRYPT_MITM 3
-typedef uint8_t tBTM_BLE_SEC_ACT;
+typedef enum : uint8_t {
+ BTM_BLE_SEC_NONE = 0,
+ /* encrypt the link using current key */
+ BTM_BLE_SEC_ENCRYPT = 1,
+ BTM_BLE_SEC_ENCRYPT_NO_MITM = 2,
+ BTM_BLE_SEC_ENCRYPT_MITM = 3,
+} tBTM_BLE_SEC_ACT;
/*******************************************************************************
* BTM Services MACROS handle array of uint32_t bits for more than 32 services
@@ -727,7 +729,8 @@
/* Simple Pairing Events. Called by the stack when Simple Pairing related
* events occur.
*/
-typedef uint8_t(tBTM_SP_CALLBACK)(tBTM_SP_EVT event, tBTM_SP_EVT_DATA* p_data);
+typedef tBTM_STATUS(tBTM_SP_CALLBACK)(tBTM_SP_EVT event,
+ tBTM_SP_EVT_DATA* p_data);
typedef void(tBTM_MKEY_CALLBACK)(const RawAddress& bd_addr, uint8_t status,
uint8_t key_flag);
@@ -770,11 +773,9 @@
#define BTM_LE_SC_OOB_REQ_EVT SMP_SC_OOB_REQ_EVT
/* SC OOB local data set is created (as result of SMP_CrLocScOobData(...)) */
#define BTM_LE_SC_LOC_OOB_EVT SMP_SC_LOC_OOB_DATA_UP_EVT
-/* SMP over BR keys request event */
-#define BTM_LE_BR_KEYS_REQ_EVT SMP_BR_KEYS_REQ_EVT
/* SMP complete event */
#define BTM_LE_COMPLT_EVT SMP_COMPLT_EVT
-#define BTM_LE_LAST_FROM_SMP BTM_LE_BR_KEYS_REQ_EVT
+#define BTM_LE_LAST_FROM_SMP SMP_BR_KEYS_REQ_EVT
/* KEY update event */
#define BTM_LE_KEY_EVT (BTM_LE_LAST_FROM_SMP + 1)
#define BTM_LE_CONSENT_REQ_EVT SMP_CONSENT_REQ_EVT
@@ -970,4 +971,17 @@
// Bluetooth Quality Report - Report receiver
typedef void(tBTM_BT_QUALITY_REPORT_RECEIVER)(uint8_t len, uint8_t* p_stream);
+struct tREMOTE_VERSION_INFO {
+ uint8_t lmp_version{0};
+ uint16_t lmp_subversion{0};
+ uint16_t manufacturer{0};
+ bool valid{false};
+ std::string ToString() const {
+ return (valid) ? base::StringPrintf("%02hhu-%05hu-%05hu", lmp_version,
+ lmp_subversion, manufacturer)
+ : std::string("UNKNOWN");
+ }
+};
+using remote_version_info = tREMOTE_VERSION_INFO;
+
#endif // BTM_API_TYPES_H
diff --git a/stack/include/btm_ble_api_types.h b/stack/include/btm_ble_api_types.h
index 4375353..04323e9 100644
--- a/stack/include/btm_ble_api_types.h
+++ b/stack/include/btm_ble_api_types.h
@@ -26,6 +26,7 @@
#include "stack/include/btm_api_types.h"
#include "stack/include/btm_status.h"
+#include "stack/include/hci_error_code.h"
#include "types/ble_address_with_type.h"
#define CHNL_MAP_LEN 5
@@ -253,6 +254,7 @@
#define BTM_BLE_APPEARANCE_CYCLING_CADENCE 0x0483
#define BTM_BLE_APPEARANCE_CYCLING_POWER 0x0484
#define BTM_BLE_APPEARANCE_CYCLING_SPEED_CADENCE 0x0485
+#define BTM_BLE_APPEARANCE_WEARABLE_AUDIO_DEVICE_EARBUD 0x0941
#define BTM_BLE_APPEARANCE_GENERIC_PULSE_OXIMETER 0x0C40
#define BTM_BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP 0x0C41
#define BTM_BLE_APPEARANCE_PULSE_OXIMETER_WRIST 0x0C42
@@ -424,15 +426,15 @@
/* BLE adv payload filtering config complete callback */
using tBTM_BLE_PF_CFG_CBACK = base::Callback<void(
- uint8_t /* avbl_space */, uint8_t /* action */, uint8_t /* status */)>;
+ uint8_t /* avbl_space */, uint8_t /* action */, uint8_t /* btm_status */)>;
/* BLE adv payload filtering status setup complete callback */
using tBTM_BLE_PF_STATUS_CBACK =
- base::Callback<void(uint8_t /*action*/, tBTM_STATUS /* status */)>;
+ base::Callback<void(uint8_t /*action*/, uint8_t /* btm_status */)>;
/* BLE adv payload filtering param setup complete callback */
using tBTM_BLE_PF_PARAM_CB = base::Callback<void(
- uint8_t /* avbl_space */, uint8_t /* action */, uint8_t /* status */)>;
+ uint8_t /* avbl_space */, uint8_t /* action */, uint8_t /* btm_status */)>;
#ifndef BTM_CS_IRK_LIST_MAX
#define BTM_CS_IRK_LIST_MAX 0x20
@@ -485,13 +487,13 @@
tBTM_BLE_RX_TIME_MS rx_time,
tBTM_BLE_IDLE_TIME_MS idle_time,
tBTM_BLE_ENERGY_USED energy_used,
- tBTM_STATUS status);
+ tHCI_STATUS status);
typedef struct {
tBTM_BLE_ENERGY_INFO_CBACK* p_ener_cback;
} tBTM_BLE_ENERGY_INFO_CB;
-typedef void(tBTM_BLE_CTRL_FEATURES_CBACK)(tBTM_STATUS status);
+typedef void(tBTM_BLE_CTRL_FEATURES_CBACK)(tHCI_STATUS status);
/* BLE encryption keys */
typedef struct {
diff --git a/stack/include/btm_iso_api.h b/stack/include/btm_iso_api.h
index dc3e91d..a8d0229 100644
--- a/stack/include/btm_iso_api.h
+++ b/stack/include/btm_iso_api.h
@@ -206,6 +206,7 @@
* @param evt_len event packet buffer length
*/
virtual void HandleNumComplDataPkts(uint8_t* p, uint8_t evt_len);
+ virtual void HandleGdNumComplDataPkts(uint16_t handle, uint16_t credits);
/**
* Handle CIS and BIG related HCI events
diff --git a/stack/include/btm_log_history.h b/stack/include/btm_log_history.h
new file mode 100644
index 0000000..e9f1e0b
--- /dev/null
+++ b/stack/include/btm_log_history.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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 "types/ble_address_with_type.h"
+#include "types/raw_address.h"
+
+void BTM_LogHistory(const std::string& tag, const RawAddress& addr,
+ const std::string& msg);
+void BTM_LogHistory(const std::string& tag, const RawAddress& addr,
+ const std::string& msg, const std::string& extra);
+void BTM_LogHistory(const std::string& tag, const tBLE_BD_ADDR& addr,
+ const std::string& msg);
+void BTM_LogHistory(const std::string& tag, const tBLE_BD_ADDR& addr,
+ const std::string& msg, const std::string& extra);
diff --git a/stack/include/btm_status.h b/stack/include/btm_status.h
index 3fba1c1..9d50571 100644
--- a/stack/include/btm_status.h
+++ b/stack/include/btm_status.h
@@ -43,57 +43,52 @@
BTM_REPEATED_ATTEMPTS, /* 19 repeated attempts for LE security requests */
BTM_MODE4_LEVEL4_NOT_SUPPORTED, /* 20 Secure Connections Only Mode can't be
supported */
- BTM_DEV_RESTRICT_LISTED /* 21 The device is restrict listed */
+ BTM_DEV_RESTRICT_LISTED, /* 21 The device is restrict listed */
+ BTM_MAX_STATUS_VALUE = BTM_DEV_RESTRICT_LISTED,
+ BTM_UNDEFINED = 0xFF,
};
typedef uint8_t tBTM_STATUS;
-inline std::string btm_status_text(tBTM_STATUS status) {
+inline uint8_t btm_status_value(const tBTM_STATUS& status) {
+ return static_cast<uint8_t>(status);
+}
+
+inline tBTM_STATUS to_btm_status(const uint8_t& value) {
+ if (value > BTM_MAX_STATUS_VALUE) return BTM_UNDEFINED;
+ return static_cast<tBTM_STATUS>(value);
+}
+
+#define CASE_RETURN_TEXT(code) \
+ case code: \
+ return #code
+
+inline std::string btm_status_text(const tBTM_STATUS& status) {
switch (status) {
- case BTM_SUCCESS:
- return std::string("success");
- case BTM_CMD_STARTED:
- return std::string("command_started");
- case BTM_BUSY:
- return std::string("busy");
- case BTM_NO_RESOURCES:
- return std::string("no_resources");
- case BTM_MODE_UNSUPPORTED:
- return std::string("unsupported_mode");
- case BTM_ILLEGAL_VALUE:
- return std::string("illegal_value");
- case BTM_WRONG_MODE:
- return std::string("wrong_mode");
- case BTM_UNKNOWN_ADDR:
- return std::string("unknown_address");
- case BTM_DEVICE_TIMEOUT:
- return std::string("device_timeout");
- case BTM_BAD_VALUE_RET:
- return std::string("bad_hci_value");
- case BTM_ERR_PROCESSING:
- return std::string("processing_error");
- case BTM_NOT_AUTHORIZED:
- return std::string("unauthorized");
- case BTM_DEV_RESET:
- return std::string("device_reset");
- case BTM_CMD_STORED:
- return std::string("command_stored");
- case BTM_ILLEGAL_ACTION:
- return std::string("illegal_action");
- case BTM_DELAY_CHECK:
- return std::string("delay_check");
- case BTM_SCO_BAD_LENGTH:
- return std::string("sco_bad_length");
- case BTM_SUCCESS_NO_SECURITY:
- return std::string("success_no_security");
- case BTM_FAILED_ON_SECURITY:
- return std::string("failed_security");
- case BTM_REPEATED_ATTEMPTS:
- return std::string("repeated_attempts");
- case BTM_MODE4_LEVEL4_NOT_SUPPORTED:
- return std::string("level4_security_unsupported");
- case BTM_DEV_RESTRICT_LISTED:
- return std::string("restrict_listed");
+ CASE_RETURN_TEXT(BTM_SUCCESS);
+ CASE_RETURN_TEXT(BTM_CMD_STARTED);
+ CASE_RETURN_TEXT(BTM_BUSY);
+ CASE_RETURN_TEXT(BTM_NO_RESOURCES);
+ CASE_RETURN_TEXT(BTM_MODE_UNSUPPORTED);
+ CASE_RETURN_TEXT(BTM_ILLEGAL_VALUE);
+ CASE_RETURN_TEXT(BTM_WRONG_MODE);
+ CASE_RETURN_TEXT(BTM_UNKNOWN_ADDR);
+ CASE_RETURN_TEXT(BTM_DEVICE_TIMEOUT);
+ CASE_RETURN_TEXT(BTM_BAD_VALUE_RET);
+ CASE_RETURN_TEXT(BTM_ERR_PROCESSING);
+ CASE_RETURN_TEXT(BTM_NOT_AUTHORIZED);
+ CASE_RETURN_TEXT(BTM_DEV_RESET);
+ CASE_RETURN_TEXT(BTM_CMD_STORED);
+ CASE_RETURN_TEXT(BTM_ILLEGAL_ACTION);
+ CASE_RETURN_TEXT(BTM_DELAY_CHECK);
+ CASE_RETURN_TEXT(BTM_SCO_BAD_LENGTH);
+ CASE_RETURN_TEXT(BTM_SUCCESS_NO_SECURITY);
+ CASE_RETURN_TEXT(BTM_FAILED_ON_SECURITY);
+ CASE_RETURN_TEXT(BTM_REPEATED_ATTEMPTS);
+ CASE_RETURN_TEXT(BTM_MODE4_LEVEL4_NOT_SUPPORTED);
+ CASE_RETURN_TEXT(BTM_DEV_RESTRICT_LISTED);
default:
- return base::StringPrintf("UNKNOWN[%u]", status);
+ return std::string("UNKNOWN[%hhu]", status);
}
}
+
+#undef CASE_RETURN_TEXT
diff --git a/stack/include/gatt_api.h b/stack/include/gatt_api.h
index ee25653..edf30c3 100644
--- a/stack/include/gatt_api.h
+++ b/stack/include/gatt_api.h
@@ -196,7 +196,6 @@
typedef enum : uint16_t {
GATT_CONN_OK = 0,
- GATT_CONN_UNKNOWN = 0,
/* general L2cap failure */
GATT_CONN_L2C_FAILURE = 1,
/* 0x08 connection timeout */
@@ -207,27 +206,33 @@
GATT_CONN_TERMINATE_LOCAL_HOST = HCI_ERR_CONN_CAUSE_LOCAL_HOST,
/* 0x22 connection fail for LMP response tout */
GATT_CONN_LMP_TIMEOUT = HCI_ERR_LMP_RESPONSE_TIMEOUT,
+
+ GATT_CONN_FAILED_ESTABLISHMENT = HCI_ERR_CONN_FAILED_ESTABLISHMENT,
+
+ BTA_GATT_CONN_NONE = 0x0101, /* 0x0101 no connection to cancel */
+
} tGATT_DISCONN_REASON;
+#define CASE_RETURN_TEXT(code) \
+ case code: \
+ return #code
+
inline std::string gatt_disconnection_reason_text(
const tGATT_DISCONN_REASON& reason) {
switch (reason) {
- case GATT_CONN_OK:
- return std::string("ok/unknown");
- case GATT_CONN_L2C_FAILURE:
- return std::string("l2cap_failure");
- case GATT_CONN_TIMEOUT:
- return std::string("timeout");
- case GATT_CONN_TERMINATE_PEER_USER:
- return std::string("remote_terminated");
- case GATT_CONN_TERMINATE_LOCAL_HOST:
- return std::string("local_terminated");
- case GATT_CONN_LMP_TIMEOUT:
- return std::string("lmp_response_timeout");
+ CASE_RETURN_TEXT(GATT_CONN_OK);
+ CASE_RETURN_TEXT(GATT_CONN_L2C_FAILURE);
+ CASE_RETURN_TEXT(GATT_CONN_TIMEOUT);
+ CASE_RETURN_TEXT(GATT_CONN_TERMINATE_PEER_USER);
+ CASE_RETURN_TEXT(GATT_CONN_TERMINATE_LOCAL_HOST);
+ CASE_RETURN_TEXT(GATT_CONN_LMP_TIMEOUT);
+ CASE_RETURN_TEXT(GATT_CONN_FAILED_ESTABLISHMENT);
+ CASE_RETURN_TEXT(BTA_GATT_CONN_NONE);
default:
- return base::StringPrintf("UNKNOWN:[0x%04hx]", reason);
+ return std::string("UNKNOWN[%hu]", reason);
}
}
+#undef CASE_RETURN_TEXT
/* MAX GATT MTU size
*/
@@ -573,15 +578,16 @@
/* GATT client operation type, used in client callback function
*/
-#define GATTC_OPTYPE_NONE 0
-#define GATTC_OPTYPE_DISCOVERY 1
-#define GATTC_OPTYPE_READ 2
-#define GATTC_OPTYPE_WRITE 3
-#define GATTC_OPTYPE_EXE_WRITE 4
-#define GATTC_OPTYPE_CONFIG 5
-#define GATTC_OPTYPE_NOTIFICATION 6
-#define GATTC_OPTYPE_INDICATION 7
-typedef uint8_t tGATTC_OPTYPE;
+typedef enum : uint8_t {
+ GATTC_OPTYPE_NONE = 0,
+ GATTC_OPTYPE_DISCOVERY = 1,
+ GATTC_OPTYPE_READ = 2,
+ GATTC_OPTYPE_WRITE = 3,
+ GATTC_OPTYPE_EXE_WRITE = 4,
+ GATTC_OPTYPE_CONFIG = 5,
+ GATTC_OPTYPE_NOTIFICATION = 6,
+ GATTC_OPTYPE_INDICATION = 7,
+} tGATTC_OPTYPE;
/* characteristic declaration
*/
@@ -680,15 +686,15 @@
* MUST be provided.
*/
typedef struct {
- tGATT_CONN_CBACK* p_conn_cb;
- tGATT_CMPL_CBACK* p_cmpl_cb;
- tGATT_DISC_RES_CB* p_disc_res_cb;
- tGATT_DISC_CMPL_CB* p_disc_cmpl_cb;
- tGATT_REQ_CBACK* p_req_cb;
- tGATT_ENC_CMPL_CB* p_enc_cmpl_cb;
- tGATT_CONGESTION_CBACK* p_congestion_cb;
- tGATT_PHY_UPDATE_CB* p_phy_update_cb;
- tGATT_CONN_UPDATE_CB* p_conn_update_cb;
+ tGATT_CONN_CBACK* p_conn_cb{nullptr};
+ tGATT_CMPL_CBACK* p_cmpl_cb{nullptr};
+ tGATT_DISC_RES_CB* p_disc_res_cb{nullptr};
+ tGATT_DISC_CMPL_CB* p_disc_cmpl_cb{nullptr};
+ tGATT_REQ_CBACK* p_req_cb{nullptr};
+ tGATT_ENC_CMPL_CB* p_enc_cmpl_cb{nullptr};
+ tGATT_CONGESTION_CBACK* p_congestion_cb{nullptr};
+ tGATT_PHY_UPDATE_CB* p_phy_update_cb{nullptr};
+ tGATT_CONN_UPDATE_CB* p_conn_update_cb{nullptr};
} tGATT_CBACK;
/***************** Start Handle Management Definitions *********************/
@@ -1024,7 +1030,8 @@
*
******************************************************************************/
extern tGATT_IF GATT_Register(const bluetooth::Uuid& p_app_uuid128,
- tGATT_CBACK* p_cb_info, bool eatt_support);
+ const std::string name, tGATT_CBACK* p_cb_info,
+ bool eatt_support);
/*******************************************************************************
*
diff --git a/stack/include/hcidefs.h b/stack/include/hcidefs.h
index 8b3584b..c6a468b 100644
--- a/stack/include/hcidefs.h
+++ b/stack/include/hcidefs.h
@@ -674,21 +674,23 @@
/*
* Definitions for packet type masks (BT1.2 and BT2.0 definitions)
*/
-#define HCI_PKT_TYPES_MASK_NO_2_DH1 0x0002
-#define HCI_PKT_TYPES_MASK_NO_3_DH1 0x0004
-#define HCI_PKT_TYPES_MASK_DM1 0x0008
-#define HCI_PKT_TYPES_MASK_DH1 0x0010
-#define HCI_PKT_TYPES_MASK_HV1 0x0020
-#define HCI_PKT_TYPES_MASK_HV2 0x0040
-#define HCI_PKT_TYPES_MASK_HV3 0x0080
-#define HCI_PKT_TYPES_MASK_NO_2_DH3 0x0100
-#define HCI_PKT_TYPES_MASK_NO_3_DH3 0x0200
-#define HCI_PKT_TYPES_MASK_DM3 0x0400
-#define HCI_PKT_TYPES_MASK_DH3 0x0800
-#define HCI_PKT_TYPES_MASK_NO_2_DH5 0x1000
-#define HCI_PKT_TYPES_MASK_NO_3_DH5 0x2000
-#define HCI_PKT_TYPES_MASK_DM5 0x4000
-#define HCI_PKT_TYPES_MASK_DH5 0x8000
+typedef enum : uint16_t {
+ HCI_PKT_TYPES_MASK_NO_2_DH1 = 0x0002,
+ HCI_PKT_TYPES_MASK_NO_3_DH1 = 0x0004,
+ HCI_PKT_TYPES_MASK_DM1 = 0x0008,
+ HCI_PKT_TYPES_MASK_DH1 = 0x0010,
+ HCI_PKT_TYPES_MASK_HV1 = 0x0020,
+ HCI_PKT_TYPES_MASK_HV2 = 0x0040,
+ HCI_PKT_TYPES_MASK_HV3 = 0x0080,
+ HCI_PKT_TYPES_MASK_NO_2_DH3 = 0x0100,
+ HCI_PKT_TYPES_MASK_NO_3_DH3 = 0x0200,
+ HCI_PKT_TYPES_MASK_DM3 = 0x0400,
+ HCI_PKT_TYPES_MASK_DH3 = 0x0800,
+ HCI_PKT_TYPES_MASK_NO_2_DH5 = 0x1000,
+ HCI_PKT_TYPES_MASK_NO_3_DH5 = 0x2000,
+ HCI_PKT_TYPES_MASK_DM5 = 0x4000,
+ HCI_PKT_TYPES_MASK_DH5 = 0x8000,
+} tHCI_PKT_TYPE_BITMASK;
/*
* Define parameters to allow role switch during create connection
@@ -858,7 +860,40 @@
*/
#define HCIE_PREAMBLE_SIZE 2
#define HCI_SCO_PREAMBLE_SIZE 3
-#define HCI_DATA_PREAMBLE_SIZE 4
+
+// Packet boundary flags
+constexpr uint8_t kFIRST_NON_AUTOMATICALLY_FLUSHABLE = 0x0;
+constexpr uint8_t kCONTINUING_FRAGMENT = 0x1;
+constexpr uint8_t kHCI_FIRST_AUTOMATICALLY_FLUSHABLE = 0x2;
+
+struct HciDataPreambleBits {
+ uint16_t handle : 12;
+ uint16_t boundary : 2;
+ uint16_t broadcast : 1;
+ uint16_t unused15 : 1;
+ uint16_t length;
+};
+struct HciDataPreambleRaw {
+ uint16_t word0;
+ uint16_t word1;
+};
+union HciDataPreamble {
+ HciDataPreambleBits bits;
+ HciDataPreambleRaw raw;
+ void Serialize(uint8_t* data) {
+ *data++ = ((raw.word0) & 0xff);
+ *data++ = (((raw.word0) >> 8) & 0xff);
+ *data++ = ((raw.word1) & 0xff);
+ *data++ = (((raw.word1 >> 8)) & 0xff);
+ }
+ bool IsFlushable() const {
+ return bits.boundary == kHCI_FIRST_AUTOMATICALLY_FLUSHABLE;
+ }
+ void SetFlushable() { bits.boundary = kHCI_FIRST_AUTOMATICALLY_FLUSHABLE; }
+};
+#define HCI_DATA_PREAMBLE_SIZE sizeof(HciDataPreamble)
+static_assert(HCI_DATA_PREAMBLE_SIZE == 4);
+static_assert(sizeof(HciDataPreambleRaw) == sizeof(HciDataPreambleBits));
/* local Bluetooth controller id for AMP HCI */
#define LOCAL_BR_EDR_CONTROLLER_ID 0
diff --git a/stack/include/hidh_api.h b/stack/include/hidh_api.h
index 6383e38..71a0533 100644
--- a/stack/include/hidh_api.h
+++ b/stack/include/hidh_api.h
@@ -25,11 +25,6 @@
* Constants
****************************************************************************/
-enum {
- HID_SDP_NO_SERV_UUID = (SDP_ILLEGAL_PARAMETER + 1),
- HID_SDP_MANDATORY_MISSING
-};
-
/* Attributes mask values to be used in HID_HostAddDev API */
#define HID_VIRTUAL_CABLE 0x0001
#define HID_NORMALLY_CONNECTABLE 0x0002
diff --git a/stack/include/sdp_api.h b/stack/include/sdp_api.h
index 969a822..e13a942 100644
--- a/stack/include/sdp_api.h
+++ b/stack/include/sdp_api.h
@@ -26,25 +26,66 @@
****************************************************************************/
/* Success code and error codes */
-#define SDP_SUCCESS 0x0000
-#define SDP_INVALID_VERSION 0x0001
-#define SDP_INVALID_SERV_REC_HDL 0x0002
-#define SDP_INVALID_REQ_SYNTAX 0x0003
-#define SDP_INVALID_PDU_SIZE 0x0004
-#define SDP_INVALID_CONT_STATE 0x0005
-#define SDP_NO_RESOURCES 0x0006
-#define SDP_DI_REG_FAILED 0x0007
-#define SDP_DI_DISC_FAILED 0x0008
-#define SDP_NO_DI_RECORD_FOUND 0x0009
-#define SDP_ERR_ATTR_NOT_PRESENT 0x000A
-#define SDP_ILLEGAL_PARAMETER 0x000B
+typedef enum : uint16_t {
+ SDP_SUCCESS = 0x0000,
+ SDP_INVALID_VERSION = 0x0001,
+ SDP_INVALID_SERV_REC_HDL = 0x0002,
+ SDP_INVALID_REQ_SYNTAX = 0x0003,
+ SDP_INVALID_PDU_SIZE = 0x0004,
+ SDP_INVALID_CONT_STATE = 0x0005,
+ SDP_NO_RESOURCES = 0x0006,
+ SDP_DI_REG_FAILED = 0x0007,
+ SDP_DI_DISC_FAILED = 0x0008,
+ SDP_NO_DI_RECORD_FOUND = 0x0009,
+ SDP_ERR_ATTR_NOT_PRESENT = 0x000A,
+ SDP_ILLEGAL_PARAMETER = 0x000B,
-#define SDP_NO_RECS_MATCH 0xFFF0
-#define SDP_CONN_FAILED 0xFFF1
-#define SDP_CFG_FAILED 0xFFF2
-#define SDP_GENERIC_ERROR 0xFFF3
-#define SDP_DB_FULL 0xFFF4
-#define SDP_CANCEL 0xFFF8
+ HID_SDP_NO_SERV_UUID = (SDP_ILLEGAL_PARAMETER + 1),
+ HID_SDP_MANDATORY_MISSING,
+
+ SDP_NO_RECS_MATCH = 0xFFF0,
+ SDP_CONN_FAILED = 0xFFF1,
+ SDP_CFG_FAILED = 0xFFF2,
+ SDP_GENERIC_ERROR = 0xFFF3,
+ SDP_DB_FULL = 0xFFF4,
+ SDP_CANCEL = 0xFFF8,
+} tSDP_STATUS;
+using tSDP_RESULT = tSDP_STATUS;
+using tSDP_REASON = tSDP_STATUS;
+
+#define CASE_RETURN_TEXT(code) \
+ case code: \
+ return #code
+
+inline std::string sdp_status_text(const tSDP_STATUS& status) {
+ switch (status) {
+ CASE_RETURN_TEXT(SDP_SUCCESS);
+ CASE_RETURN_TEXT(SDP_INVALID_VERSION);
+ CASE_RETURN_TEXT(SDP_INVALID_SERV_REC_HDL);
+ CASE_RETURN_TEXT(SDP_INVALID_REQ_SYNTAX);
+ CASE_RETURN_TEXT(SDP_INVALID_PDU_SIZE);
+ CASE_RETURN_TEXT(SDP_INVALID_CONT_STATE);
+ CASE_RETURN_TEXT(SDP_NO_RESOURCES);
+ CASE_RETURN_TEXT(SDP_DI_REG_FAILED);
+ CASE_RETURN_TEXT(SDP_DI_DISC_FAILED);
+ CASE_RETURN_TEXT(SDP_NO_DI_RECORD_FOUND);
+ CASE_RETURN_TEXT(SDP_ERR_ATTR_NOT_PRESENT);
+ CASE_RETURN_TEXT(SDP_ILLEGAL_PARAMETER);
+
+ CASE_RETURN_TEXT(HID_SDP_NO_SERV_UUID);
+ CASE_RETURN_TEXT(HID_SDP_MANDATORY_MISSING);
+
+ CASE_RETURN_TEXT(SDP_NO_RECS_MATCH);
+ CASE_RETURN_TEXT(SDP_CONN_FAILED);
+ CASE_RETURN_TEXT(SDP_CFG_FAILED);
+ CASE_RETURN_TEXT(SDP_GENERIC_ERROR);
+ CASE_RETURN_TEXT(SDP_DB_FULL);
+ CASE_RETURN_TEXT(SDP_CANCEL);
+ default:
+ return std::string("UNKNOWN[%hhu]", status);
+ }
+}
+#undef CASE_RETURN_TEXT
/* Masks for attr_value field of tSDP_DISC_ATTR */
#define SDP_DISC_ATTR_LEN_MASK 0x0FFF
@@ -59,8 +100,8 @@
****************************************************************************/
/* Define a callback function for when discovery is complete. */
-typedef void(tSDP_DISC_CMPL_CB)(uint16_t result);
-typedef void(tSDP_DISC_CMPL_CB2)(uint16_t result, void* user_data);
+typedef void(tSDP_DISC_CMPL_CB)(tSDP_RESULT result);
+typedef void(tSDP_DISC_CMPL_CB2)(tSDP_RESULT result, void* user_data);
typedef struct {
RawAddress peer_addr;
@@ -528,9 +569,9 @@
* Returns SDP_SUCCESS if query started successfully, else error
*
******************************************************************************/
-uint16_t SDP_DiDiscover(const RawAddress& remote_device,
- tSDP_DISCOVERY_DB* p_db, uint32_t len,
- tSDP_DISC_CMPL_CB* p_cb);
+tSDP_STATUS SDP_DiDiscover(const RawAddress& remote_device,
+ tSDP_DISCOVERY_DB* p_db, uint32_t len,
+ tSDP_DISC_CMPL_CB* p_cb);
/*******************************************************************************
*
diff --git a/stack/include/smp_api.h b/stack/include/smp_api.h
index 4108c37..bc4060c 100644
--- a/stack/include/smp_api.h
+++ b/stack/include/smp_api.h
@@ -26,6 +26,7 @@
#include "bt_target.h"
#include "smp_api_types.h"
+#include "types/bt_transport.h"
/*****************************************************************************
* External Function Declarations
@@ -174,6 +175,22 @@
******************************************************************************/
extern void SMP_SecureConnectionOobDataReply(uint8_t* p_data);
+/*******************************************************************************
+ *
+ * Function SMP_CrLocScOobData
+ *
+ * Description This function is called to generate a public key to be
+ * passed to a remote device via an Out of Band transport
+ *
+ * Parameters: callback - receive the data
+ *
+ ******************************************************************************/
+extern void SMP_CrLocScOobData(
+ base::OnceCallback<void(tBT_TRANSPORT, bool,
+ const std::array<unsigned char, 16>&,
+ const std::array<unsigned char, 16>&)>
+ callback);
+
// Called when LTK request is received from controller.
extern bool smp_proc_ltk_request(const RawAddress& bda);
diff --git a/stack/include/smp_api_types.h b/stack/include/smp_api_types.h
index 6318129..04cd7c5 100644
--- a/stack/include/smp_api_types.h
+++ b/stack/include/smp_api_types.h
@@ -19,7 +19,9 @@
#ifndef SMP_API_TYPES_H
#define SMP_API_TYPES_H
-#include "bt_target.h"
+#include "bt_target.h" // Must be first to define build configuration
+
+#include "stack/include/btm_status.h"
#include "types/ble_address_with_type.h"
/* SMP command code */
@@ -40,64 +42,95 @@
SMP_OPCODE_PAIR_KEYPR_NOTIF = 0x0E,
SMP_OPCODE_MAX = SMP_OPCODE_PAIR_KEYPR_NOTIF,
SMP_OPCODE_MIN = SMP_OPCODE_PAIRING_REQ,
+ // NOTE: For some reason this is outside the MAX/MIN values
SMP_OPCODE_PAIR_COMMITM = 0x0F,
} tSMP_OPCODE;
-/* SMP event type */
-#define SMP_EVT_NONE 0 /* Default no event */
-#define SMP_IO_CAP_REQ_EVT 1 /* IO capability request event */
-#define SMP_SEC_REQUEST_EVT 2 /* SMP pairing request */
-#define SMP_PASSKEY_NOTIF_EVT 3 /* passkey notification event */
-#define SMP_PASSKEY_REQ_EVT 4 /* passkey request event */
-#define SMP_OOB_REQ_EVT 5 /* OOB request event */
-#define SMP_NC_REQ_EVT 6 /* Numeric Comparison request event */
-#define SMP_COMPLT_EVT 7 /* SMP complete event */
-#define SMP_PEER_KEYPR_NOT_EVT 8 /* Peer keypress notification */
+#define CASE_RETURN_TEXT(code) \
+ case code: \
+ return #code
-/* SC OOB request event (both local and peer OOB data can be expected in
- * response) */
-#define SMP_SC_OOB_REQ_EVT 9
-/* SC OOB local data set is created (as result of SMP_CrLocScOobData(...)) */
-#define SMP_SC_LOC_OOB_DATA_UP_EVT 10
-#define SMP_BR_KEYS_REQ_EVT 12 /* SMP over BR keys request event */
-#define SMP_CONSENT_REQ_EVT 14 /* Consent request event */
-typedef uint8_t tSMP_EVT;
+inline std::string smp_opcode_text(const tSMP_OPCODE& opcode) {
+ switch (opcode) {
+ CASE_RETURN_TEXT(SMP_OPCODE_PAIRING_REQ);
+ CASE_RETURN_TEXT(SMP_OPCODE_PAIRING_RSP);
+ CASE_RETURN_TEXT(SMP_OPCODE_CONFIRM);
+ CASE_RETURN_TEXT(SMP_OPCODE_RAND);
+ CASE_RETURN_TEXT(SMP_OPCODE_PAIRING_FAILED);
+ CASE_RETURN_TEXT(SMP_OPCODE_ENCRYPT_INFO);
+ CASE_RETURN_TEXT(SMP_OPCODE_CENTRAL_ID);
+ CASE_RETURN_TEXT(SMP_OPCODE_IDENTITY_INFO);
+ CASE_RETURN_TEXT(SMP_OPCODE_ID_ADDR);
+ CASE_RETURN_TEXT(SMP_OPCODE_SIGN_INFO);
+ CASE_RETURN_TEXT(SMP_OPCODE_SEC_REQ);
+ CASE_RETURN_TEXT(SMP_OPCODE_PAIR_PUBLIC_KEY);
+ CASE_RETURN_TEXT(SMP_OPCODE_PAIR_DHKEY_CHECK);
+ CASE_RETURN_TEXT(SMP_OPCODE_PAIR_KEYPR_NOTIF);
+ CASE_RETURN_TEXT(SMP_OPCODE_PAIR_COMMITM);
+ default:
+ return std::string("UNKNOWN:%hhu", opcode);
+ }
+}
+#undef CASE_RETURN_TEXT
+
+/* SMP event type */
+typedef enum : uint8_t {
+ SMP_EVT_NONE = 0, /* Default no event */
+ SMP_IO_CAP_REQ_EVT = 1, /* IO capability request event */
+ SMP_SEC_REQUEST_EVT = 2, /* SMP pairing request */
+ SMP_PASSKEY_NOTIF_EVT = 3, /* passkey notification event */
+ SMP_PASSKEY_REQ_EVT = 4, /* passkey request event */
+ SMP_OOB_REQ_EVT = 5, /* OOB request event */
+ SMP_NC_REQ_EVT = 6, /* Numeric Comparison request event */
+ SMP_COMPLT_EVT = 7, /* SMP complete event */
+ SMP_PEER_KEYPR_NOT_EVT = 8, /* Peer keypress notification */
+
+ /* SC OOB request event (both local and peer OOB data can be expected in
+ * response) */
+ SMP_SC_OOB_REQ_EVT = 9,
+ /* SC OOB local data set is created (as result of SMP_CrLocScOobData(...)) */
+ SMP_SC_LOC_OOB_DATA_UP_EVT = 10,
+ SMP_UNUSED11 = 11,
+ SMP_BR_KEYS_REQ_EVT = 12, /* SMP over BR keys request event */
+ SMP_UNUSED13 = 13,
+ SMP_CONSENT_REQ_EVT = 14, /* Consent request event */
+} tSMP_EVT;
/* pairing failure reason code */
-#define SMP_PASSKEY_ENTRY_FAIL 0x01
-#define SMP_OOB_FAIL 0x02
-#define SMP_PAIR_AUTH_FAIL 0x03
-#define SMP_CONFIRM_VALUE_ERR 0x04
-#define SMP_PAIR_NOT_SUPPORT 0x05
-#define SMP_ENC_KEY_SIZE 0x06
-#define SMP_INVALID_CMD 0x07
-#define SMP_PAIR_FAIL_UNKNOWN 0x08
-#define SMP_REPEATED_ATTEMPTS 0x09
-#define SMP_INVALID_PARAMETERS 0x0A
-#define SMP_DHKEY_CHK_FAIL 0x0B
-#define SMP_NUMERIC_COMPAR_FAIL 0x0C
-#define SMP_BR_PARING_IN_PROGR 0x0D
-#define SMP_XTRANS_DERIVE_NOT_ALLOW 0x0E
-#define SMP_MAX_FAIL_RSN_PER_SPEC SMP_XTRANS_DERIVE_NOT_ALLOW
+typedef enum : uint8_t {
+ SMP_SUCCESS = 0,
+ SMP_PASSKEY_ENTRY_FAIL = 0x01,
+ SMP_OOB_FAIL = 0x02,
+ SMP_PAIR_AUTH_FAIL = 0x03,
+ SMP_CONFIRM_VALUE_ERR = 0x04,
+ SMP_PAIR_NOT_SUPPORT = 0x05,
+ SMP_ENC_KEY_SIZE = 0x06,
+ SMP_INVALID_CMD = 0x07,
+ SMP_PAIR_FAIL_UNKNOWN = 0x08,
+ SMP_REPEATED_ATTEMPTS = 0x09,
+ SMP_INVALID_PARAMETERS = 0x0A,
+ SMP_DHKEY_CHK_FAIL = 0x0B,
+ SMP_NUMERIC_COMPAR_FAIL = 0x0C,
+ SMP_BR_PARING_IN_PROGR = 0x0D,
+ SMP_XTRANS_DERIVE_NOT_ALLOW = 0x0E,
+ SMP_MAX_FAIL_RSN_PER_SPEC = SMP_XTRANS_DERIVE_NOT_ALLOW,
-/* self defined error code */
-#define SMP_PAIR_INTERNAL_ERR (SMP_MAX_FAIL_RSN_PER_SPEC + 0x01) /* 0x0F */
+ /* self defined error code */
+ SMP_PAIR_INTERNAL_ERR = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x01), /* 0x0F */
-/* Unknown IO capability, unable to decide association model */
-#define SMP_UNKNOWN_IO_CAP (SMP_MAX_FAIL_RSN_PER_SPEC + 0x02) /* 0x10 */
+ /* Unknown IO capability, unable to decide association model */
+ SMP_UNKNOWN_IO_CAP = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x02), /* 0x10 */
-#define SMP_BUSY (SMP_MAX_FAIL_RSN_PER_SPEC + 0x05) /* 0x13 */
-#define SMP_ENC_FAIL (SMP_MAX_FAIL_RSN_PER_SPEC + 0x06) /* 0x14 */
-#define SMP_STARTED (SMP_MAX_FAIL_RSN_PER_SPEC + 0x07) /* 0x15 */
-#define SMP_RSP_TIMEOUT (SMP_MAX_FAIL_RSN_PER_SPEC + 0x08) /* 0x16 */
+ SMP_BUSY = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x05), /* 0x13 */
+ SMP_ENC_FAIL = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x06), /* 0x14 */
+ SMP_STARTED = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x07), /* 0x15 */
+ SMP_RSP_TIMEOUT = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x08), /* 0x16 */
-/* Unspecified failure reason */
-#define SMP_FAIL (SMP_MAX_FAIL_RSN_PER_SPEC + 0x0A) /* 0x18 */
+ /* Unspecified failure reason */
+ SMP_FAIL = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x0A), /* 0x18 */
-#define SMP_CONN_TOUT (SMP_MAX_FAIL_RSN_PER_SPEC + 0x0B) /* 0x19 */
-#define SMP_SUCCESS 0
-
-typedef uint8_t tSMP_STATUS;
+ SMP_CONN_TOUT = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x0B), /* 0x19 */
+} tSMP_STATUS;
/* Device IO capability */
#define SMP_IO_CAP_IO BTM_IO_CAP_IO /* DisplayYesNo */
@@ -149,19 +182,21 @@
#define SMP_ENCR_KEY_SIZE_MAX 16
/* SMP key types */
-#define SMP_SEC_KEY_TYPE_ENC (1 << 0) /* encryption key */
-#define SMP_SEC_KEY_TYPE_ID (1 << 1) /* identity key */
-#define SMP_SEC_KEY_TYPE_CSRK (1 << 2) /* peripheral CSRK */
-#define SMP_SEC_KEY_TYPE_LK (1 << 3) /* BR/EDR link key */
+enum tSMP_KEYS_BITMASK : uint8_t {
+ SMP_SEC_KEY_TYPE_ENC = (1 << 0), /* encryption key */
+ SMP_SEC_KEY_TYPE_ID = (1 << 1), /* identity key */
+ SMP_SEC_KEY_TYPE_CSRK = (1 << 2), /* peripheral CSRK */
+ SMP_SEC_KEY_TYPE_LK = (1 << 3), /* BR/EDR link key */
+};
typedef uint8_t tSMP_KEYS;
-#define SMP_BR_SEC_DEFAULT_KEY \
- (SMP_SEC_KEY_TYPE_ENC | SMP_SEC_KEY_TYPE_ID | SMP_SEC_KEY_TYPE_CSRK)
+constexpr tSMP_KEYS SMP_BR_SEC_DEFAULT_KEY =
+ (SMP_SEC_KEY_TYPE_ENC | SMP_SEC_KEY_TYPE_ID | SMP_SEC_KEY_TYPE_CSRK);
/* default security key distribution value */
-#define SMP_SEC_DEFAULT_KEY \
- (SMP_SEC_KEY_TYPE_ENC | SMP_SEC_KEY_TYPE_ID | SMP_SEC_KEY_TYPE_CSRK | \
- SMP_SEC_KEY_TYPE_LK)
+constexpr tSMP_KEYS SMP_SEC_DEFAULT_KEY =
+ (SMP_SEC_KEY_TYPE_ENC | SMP_SEC_KEY_TYPE_ID | SMP_SEC_KEY_TYPE_CSRK |
+ SMP_SEC_KEY_TYPE_LK);
#define SMP_SC_KEY_OUT_OF_RANGE 5 /* out of range */
typedef uint8_t tSMP_SC_KEY_TYPE;
@@ -233,7 +268,7 @@
/* Security Manager events - Called by the stack when Security Manager related
* events occur.*/
-typedef uint8_t(tSMP_CALLBACK)(tSMP_EVT event, const RawAddress& bd_addr,
- tSMP_EVT_DATA* p_data);
+typedef tBTM_STATUS(tSMP_CALLBACK)(tSMP_EVT event, const RawAddress& bd_addr,
+ tSMP_EVT_DATA* p_data);
#endif // SMP_API_TYPES_H
diff --git a/stack/l2cap/l2c_csm.cc b/stack/l2cap/l2c_csm.cc
index e4ff6a2..07d1d92 100644
--- a/stack/l2cap/l2c_csm.cc
+++ b/stack/l2cap/l2c_csm.cc
@@ -38,23 +38,23 @@
/******************************************************************************/
/* L O C A L F U N C T I O N P R O T O T Y P E S */
/******************************************************************************/
-static void l2c_csm_closed(tL2C_CCB* p_ccb, uint16_t event, void* p_data);
-static void l2c_csm_orig_w4_sec_comp(tL2C_CCB* p_ccb, uint16_t event,
+static void l2c_csm_closed(tL2C_CCB* p_ccb, tL2CEVT event, void* p_data);
+static void l2c_csm_orig_w4_sec_comp(tL2C_CCB* p_ccb, tL2CEVT event,
void* p_data);
-static void l2c_csm_term_w4_sec_comp(tL2C_CCB* p_ccb, uint16_t event,
+static void l2c_csm_term_w4_sec_comp(tL2C_CCB* p_ccb, tL2CEVT event,
void* p_data);
-static void l2c_csm_w4_l2cap_connect_rsp(tL2C_CCB* p_ccb, uint16_t event,
+static void l2c_csm_w4_l2cap_connect_rsp(tL2C_CCB* p_ccb, tL2CEVT event,
void* p_data);
-static void l2c_csm_w4_l2ca_connect_rsp(tL2C_CCB* p_ccb, uint16_t event,
+static void l2c_csm_w4_l2ca_connect_rsp(tL2C_CCB* p_ccb, tL2CEVT event,
void* p_data);
-static void l2c_csm_config(tL2C_CCB* p_ccb, uint16_t event, void* p_data);
-static void l2c_csm_open(tL2C_CCB* p_ccb, uint16_t event, void* p_data);
-static void l2c_csm_w4_l2cap_disconnect_rsp(tL2C_CCB* p_ccb, uint16_t event,
+static void l2c_csm_config(tL2C_CCB* p_ccb, tL2CEVT event, void* p_data);
+static void l2c_csm_open(tL2C_CCB* p_ccb, tL2CEVT event, void* p_data);
+static void l2c_csm_w4_l2cap_disconnect_rsp(tL2C_CCB* p_ccb, tL2CEVT event,
void* p_data);
-static void l2c_csm_w4_l2ca_disconnect_rsp(tL2C_CCB* p_ccb, uint16_t event,
+static void l2c_csm_w4_l2ca_disconnect_rsp(tL2C_CCB* p_ccb, tL2CEVT event,
void* p_data);
-static const char* l2c_csm_get_event_name(uint16_t event);
+static const char* l2c_csm_get_event_name(tL2CEVT event);
// Send a connect response with result OK and adjust the state machine
static void l2c_csm_send_connect_rsp(tL2C_CCB* p_ccb) {
@@ -100,29 +100,6 @@
}
}
-static std::string channel_state_text(const tL2C_CHNL_STATE& state) {
- switch (state) {
- case CST_CLOSED: /* Channel is in closed state */
- return std::string("closed");
- case CST_ORIG_W4_SEC_COMP: /* Originator waits security clearence */
- return std::string("security pending(orig)");
- case CST_TERM_W4_SEC_COMP: /* Acceptor waits security clearence */
- return std::string("security pending(term)");
- case CST_W4_L2CAP_CONNECT_RSP: /* Waiting for peer connect response */
- return std::string("wait connect response from peer");
- case CST_W4_L2CA_CONNECT_RSP: /* Waiting for upper layer connect rsp */
- return std::string("wait connect response from upper");
- case CST_CONFIG: /* Negotiating configuration */
- return std::string("configuring");
- case CST_OPEN: /* Data transfer state */
- return std::string("open");
- case CST_W4_L2CAP_DISCONNECT_RSP: /* Waiting for peer disconnect rsp */
- return std::string("wait disconnect response from peer");
- case CST_W4_L2CA_DISCONNECT_RSP: /* Waiting for upper layer disc rsp */
- return std::string("wait disconnect response from upper");
- }
-}
-
/*******************************************************************************
*
* Function l2c_csm_execute
@@ -132,7 +109,7 @@
* Returns void
*
******************************************************************************/
-void l2c_csm_execute(tL2C_CCB* p_ccb, uint16_t event, void* p_data) {
+void l2c_csm_execute(tL2C_CCB* p_ccb, tL2CEVT event, void* p_data) {
if (!l2cu_is_ccb_active(p_ccb)) {
LOG_WARN("CCB not in use, event (%d) cannot be processed", event);
return;
@@ -196,7 +173,7 @@
* Returns void
*
******************************************************************************/
-static void l2c_csm_closed(tL2C_CCB* p_ccb, uint16_t event, void* p_data) {
+static void l2c_csm_closed(tL2C_CCB* p_ccb, tL2CEVT event, void* p_data) {
tL2C_CONN_INFO* p_ci = (tL2C_CONN_INFO*)p_data;
uint16_t local_cid = p_ccb->local_cid;
tL2CA_DISCONNECT_IND_CB* disconnect_ind;
@@ -347,6 +324,9 @@
case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
l2cu_release_ccb(p_ccb);
break;
+
+ default:
+ LOG_ERROR("Handling unexpected event:%s", l2c_csm_get_event_name(event));
}
LOG_DEBUG("Exit chnl_state=%s [%d], event=%s [%d]",
channel_state_text(p_ccb->chnl_state).c_str(), p_ccb->chnl_state,
@@ -363,7 +343,7 @@
* Returns void
*
******************************************************************************/
-static void l2c_csm_orig_w4_sec_comp(tL2C_CCB* p_ccb, uint16_t event,
+static void l2c_csm_orig_w4_sec_comp(tL2C_CCB* p_ccb, tL2CEVT event,
void* p_data) {
tL2CA_DISCONNECT_IND_CB* disconnect_ind =
p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
@@ -443,6 +423,9 @@
l2cu_release_ccb(p_ccb);
break;
+
+ default:
+ LOG_ERROR("Handling unexpected event:%s", l2c_csm_get_event_name(event));
}
LOG_DEBUG("Exit chnl_state=%s [%d], event=%s [%d]",
channel_state_text(p_ccb->chnl_state).c_str(), p_ccb->chnl_state,
@@ -459,7 +442,7 @@
* Returns void
*
******************************************************************************/
-static void l2c_csm_term_w4_sec_comp(tL2C_CCB* p_ccb, uint16_t event,
+static void l2c_csm_term_w4_sec_comp(tL2C_CCB* p_ccb, tL2CEVT event,
void* p_data) {
LOG_DEBUG("LCID: 0x%04x st: TERM_W4_SEC_COMP evt: %s", p_ccb->local_cid,
l2c_csm_get_event_name(event));
@@ -572,6 +555,9 @@
btm_sec_l2cap_access_req(p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
false, &l2c_link_sec_comp, p_ccb);
break;
+
+ default:
+ LOG_ERROR("Handling unexpected event:%s", l2c_csm_get_event_name(event));
}
LOG_DEBUG("Exit chnl_state=%s [%d], event=%s [%d]",
channel_state_text(p_ccb->chnl_state).c_str(), p_ccb->chnl_state,
@@ -588,7 +574,7 @@
* Returns void
*
******************************************************************************/
-static void l2c_csm_w4_l2cap_connect_rsp(tL2C_CCB* p_ccb, uint16_t event,
+static void l2c_csm_w4_l2cap_connect_rsp(tL2C_CCB* p_ccb, tL2CEVT event,
void* p_data) {
tL2C_CONN_INFO* p_ci = (tL2C_CONN_INFO*)p_data;
tL2CA_DISCONNECT_IND_CB* disconnect_ind =
@@ -729,6 +715,9 @@
l2cu_send_peer_connect_req(p_ccb); /* Start Connection */
}
break;
+
+ default:
+ LOG_ERROR("Handling unexpected event:%s", l2c_csm_get_event_name(event));
}
LOG_DEBUG("Exit chnl_state=%s [%d], event=%s [%d]",
channel_state_text(p_ccb->chnl_state).c_str(), p_ccb->chnl_state,
@@ -745,7 +734,7 @@
* Returns void
*
******************************************************************************/
-static void l2c_csm_w4_l2ca_connect_rsp(tL2C_CCB* p_ccb, uint16_t event,
+static void l2c_csm_w4_l2ca_connect_rsp(tL2C_CCB* p_ccb, tL2CEVT event,
void* p_data) {
tL2C_CONN_INFO* p_ci;
tL2CA_DISCONNECT_IND_CB* disconnect_ind =
@@ -878,6 +867,8 @@
l2c_csm_send_connect_rsp(p_ccb);
l2c_csm_send_config_req(p_ccb);
break;
+ default:
+ LOG_ERROR("Handling unexpected event:%s", l2c_csm_get_event_name(event));
}
LOG_DEBUG("Exit chnl_state=%s [%d], event=%s [%d]",
channel_state_text(p_ccb->chnl_state).c_str(), p_ccb->chnl_state,
@@ -894,7 +885,7 @@
* Returns void
*
******************************************************************************/
-static void l2c_csm_config(tL2C_CCB* p_ccb, uint16_t event, void* p_data) {
+static void l2c_csm_config(tL2C_CCB* p_ccb, tL2CEVT event, void* p_data) {
tL2CAP_CFG_INFO* p_cfg = (tL2CAP_CFG_INFO*)p_data;
tL2CA_DISCONNECT_IND_CB* disconnect_ind =
p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
@@ -1107,16 +1098,19 @@
p_ccb->local_cid <= L2CAP_LAST_FIXED_CHNL) {
if (p_ccb->local_cid < L2CAP_BASE_APPL_CID) {
if (l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL]
- .pL2CA_FixedData_Cb)
+ .pL2CA_FixedData_Cb != nullptr) {
+ p_ccb->metrics.rx(static_cast<BT_HDR*>(p_data)->len);
(*l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL]
.pL2CA_FixedData_Cb)(p_ccb->local_cid,
p_ccb->p_lcb->remote_bd_addr,
(BT_HDR*)p_data);
- else
- osi_free(p_data);
+ } else {
+ if (p_data != nullptr) osi_free_and_reset(&p_data);
+ }
break;
}
}
+ if (p_data) p_ccb->metrics.rx(static_cast<BT_HDR*>(p_data)->len);
(*p_ccb->p_rcb->api.pL2CA_DataInd_Cb)(p_ccb->local_cid, (BT_HDR*)p_data);
break;
@@ -1149,6 +1143,8 @@
l2cu_release_ccb(p_ccb);
(*disconnect_ind)(local_cid, false);
break;
+ default:
+ LOG_ERROR("Handling unexpected event:%s", l2c_csm_get_event_name(event));
}
LOG_DEBUG("Exit chnl_state=%s [%d], event=%s [%d]",
channel_state_text(p_ccb->chnl_state).c_str(), p_ccb->chnl_state,
@@ -1165,7 +1161,7 @@
* Returns void
*
******************************************************************************/
-static void l2c_csm_open(tL2C_CCB* p_ccb, uint16_t event, void* p_data) {
+static void l2c_csm_open(tL2C_CCB* p_ccb, tL2CEVT event, void* p_data) {
uint16_t local_cid = p_ccb->local_cid;
tL2CAP_CFG_INFO* p_cfg;
tL2C_CHNL_STATE tempstate;
@@ -1251,9 +1247,11 @@
break;
case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
- if ((p_ccb->p_rcb) && (p_ccb->p_rcb->api.pL2CA_DataInd_Cb))
+ if ((p_ccb->p_rcb) && (p_ccb->p_rcb->api.pL2CA_DataInd_Cb)) {
+ p_ccb->metrics.rx(static_cast<BT_HDR*>(p_data)->len);
(*p_ccb->p_rcb->api.pL2CA_DataInd_Cb)(p_ccb->local_cid,
(BT_HDR*)p_data);
+ }
break;
case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
@@ -1325,6 +1323,8 @@
l2c_link_check_send_pkts(p_ccb->p_lcb, 0, NULL);
}
break;
+ default:
+ LOG_ERROR("Handling unexpected event:%s", l2c_csm_get_event_name(event));
}
LOG_DEBUG("Exit chnl_state=%s [%d], event=%s [%d]",
channel_state_text(p_ccb->chnl_state).c_str(), p_ccb->chnl_state,
@@ -1341,7 +1341,7 @@
* Returns void
*
******************************************************************************/
-static void l2c_csm_w4_l2cap_disconnect_rsp(tL2C_CCB* p_ccb, uint16_t event,
+static void l2c_csm_w4_l2cap_disconnect_rsp(tL2C_CCB* p_ccb, tL2CEVT event,
void* p_data) {
LOG_DEBUG("LCID: 0x%04x st: W4_L2CAP_DISC_RSP evt: %s", p_ccb->local_cid,
l2c_csm_get_event_name(event));
@@ -1366,6 +1366,8 @@
case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
osi_free(p_data);
break;
+ default:
+ LOG_ERROR("Handling unexpected event:%s", l2c_csm_get_event_name(event));
}
LOG_DEBUG("Exit chnl_state=%s [%d], event=%s [%d]",
channel_state_text(p_ccb->chnl_state).c_str(), p_ccb->chnl_state,
@@ -1382,7 +1384,7 @@
* Returns void
*
******************************************************************************/
-static void l2c_csm_w4_l2ca_disconnect_rsp(tL2C_CCB* p_ccb, uint16_t event,
+static void l2c_csm_w4_l2ca_disconnect_rsp(tL2C_CCB* p_ccb, tL2CEVT event,
void* p_data) {
tL2CA_DISCONNECT_IND_CB* disconnect_ind =
p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
@@ -1419,6 +1421,8 @@
case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
osi_free(p_data);
break;
+ default:
+ LOG_ERROR("Handling unexpected event:%s", l2c_csm_get_event_name(event));
}
LOG_DEBUG("Exit chnl_state=%s [%d], event=%s [%d]",
channel_state_text(p_ccb->chnl_state).c_str(), p_ccb->chnl_state,
@@ -1436,7 +1440,7 @@
* Returns pointer to the name
*
******************************************************************************/
-static const char* l2c_csm_get_event_name(uint16_t event) {
+static const char* l2c_csm_get_event_name(tL2CEVT event) {
switch (event) {
case L2CEVT_LP_CONNECT_CFM: /* Lower layer connect confirm */
return ("LOWER_LAYER_CONNECT_CFM");
@@ -1544,6 +1548,10 @@
*
******************************************************************************/
void l2c_enqueue_peer_data(tL2C_CCB* p_ccb, BT_HDR* p_buf) {
+ CHECK(p_ccb != nullptr);
+
+ p_ccb->metrics.tx(p_buf->len);
+
uint8_t* p;
if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE) {
diff --git a/stack/l2cap/l2c_int.h b/stack/l2cap/l2c_int.h
index 8d083e6..b16678b 100644
--- a/stack/l2cap/l2c_int.h
+++ b/stack/l2cap/l2c_int.h
@@ -81,6 +81,27 @@
CST_W4_L2CA_DISCONNECT_RSP /* Waiting for upper layer disc rsp */
} tL2C_CHNL_STATE;
+#define CASE_RETURN_TEXT(code) \
+ case code: \
+ return #code
+
+inline std::string channel_state_text(const tL2C_CHNL_STATE& state) {
+ switch (state) {
+ CASE_RETURN_TEXT(CST_CLOSED);
+ CASE_RETURN_TEXT(CST_ORIG_W4_SEC_COMP);
+ CASE_RETURN_TEXT(CST_TERM_W4_SEC_COMP);
+ CASE_RETURN_TEXT(CST_W4_L2CAP_CONNECT_RSP);
+ CASE_RETURN_TEXT(CST_W4_L2CA_CONNECT_RSP);
+ CASE_RETURN_TEXT(CST_CONFIG);
+ CASE_RETURN_TEXT(CST_OPEN);
+ CASE_RETURN_TEXT(CST_W4_L2CAP_DISCONNECT_RSP);
+ CASE_RETURN_TEXT(CST_W4_L2CA_DISCONNECT_RSP);
+ default:
+ return std::string("UNKNOWN[%hhu]", state);
+ }
+}
+#undef CASE_RETURN_TEXT
+
/* Define the possible L2CAP link states
*/
typedef enum {
@@ -115,7 +136,7 @@
* of the events may seem a bit strange, but they are taken from
* the Bluetooth specification.
*/
-enum : uint16_t {
+typedef enum : uint16_t {
/* Lower layer */
L2CEVT_LP_CONNECT_CFM = 0, /* connect confirm */
L2CEVT_LP_CONNECT_CFM_NEG = 1, /* connect confirm (failed) */
@@ -178,7 +199,7 @@
L2CEVT_L2CA_CREDIT_BASED_CONNECT_RSP = 43, /* connect response */
L2CEVT_L2CA_CREDIT_BASED_CONNECT_RSP_NEG = 44, /* connect response (failed)*/
L2CEVT_L2CA_CREDIT_BASED_RECONFIG_REQ = 45, /* reconfig request */
-};
+} tL2CEVT;
/* Constants for LE Dynamic PSM values */
#define LE_DYNAMIC_PSM_START 0x0080
@@ -242,7 +263,9 @@
uint16_t required_remote_mtu;
} tL2C_RCB;
+#ifndef L2CAP_CBB_DEFAULT_DATA_RATE_BUFF_QUOTA
#define L2CAP_CBB_DEFAULT_DATA_RATE_BUFF_QUOTA 100
+#endif
typedef void(tL2CAP_SEC_CBACK)(const RawAddress& bd_addr,
tBT_TRANSPORT trasnport, void* p_ref_data,
@@ -331,6 +354,28 @@
/* used to indicate that ECOC is used */
bool ecoc{false};
bool reconfig_started;
+
+ struct {
+ struct {
+ unsigned bytes{0};
+ unsigned packets{0};
+ void operator()(unsigned bytes) {
+ this->bytes += bytes;
+ this->packets++;
+ }
+ } rx, tx;
+ struct {
+ struct {
+ unsigned bytes{0};
+ unsigned packets{0};
+ void operator()(unsigned bytes) {
+ this->bytes += bytes;
+ this->packets++;
+ }
+ } rx, tx;
+ } dropped;
+ } metrics;
+
} tL2C_CCB;
/***********************************************************************
@@ -751,7 +796,7 @@
/* Functions provided by l2c_csm.cc
***********************************
*/
-extern void l2c_csm_execute(tL2C_CCB* p_ccb, uint16_t event, void* p_data);
+extern void l2c_csm_execute(tL2C_CCB* p_ccb, tL2CEVT event, void* p_data);
extern void l2c_enqueue_peer_data(tL2C_CCB* p_ccb, BT_HDR* p_buf);
diff --git a/stack/l2cap/l2c_link.cc b/stack/l2cap/l2c_link.cc
index 8f92aea..70adbb6 100644
--- a/stack/l2cap/l2c_link.cc
+++ b/stack/l2cap/l2c_link.cc
@@ -276,11 +276,10 @@
tL2C_LCB* p_lcb;
tL2C_CCB* p_ccb;
tL2C_CCB* p_next_ccb;
- uint8_t event;
LOG_DEBUG("btm_status=%s, BD_ADDR=%s, transport=%s",
btm_status_text(status).c_str(), PRIVATE_ADDRESS(p_bda),
- BtTransportText(transport).c_str());
+ bt_transport_text(transport).c_str());
if (status == BTM_SUCCESS_NO_SECURITY) {
status = BTM_SUCCESS;
@@ -305,7 +304,7 @@
if (p_ccb == p_ref_data) {
switch (status) {
case BTM_SUCCESS:
- event = L2CEVT_SEC_COMP;
+ l2c_csm_execute(p_ccb, L2CEVT_SEC_COMP, &ci);
break;
case BTM_DELAY_CHECK:
@@ -317,9 +316,9 @@
return;
default:
- event = L2CEVT_SEC_COMP_NEG;
+ l2c_csm_execute(p_ccb, L2CEVT_SEC_COMP_NEG, &ci);
+ break;
}
- l2c_csm_execute(p_ccb, event, &ci);
break;
}
}
diff --git a/stack/l2cap/l2c_main.cc b/stack/l2cap/l2c_main.cc
index d77242c..003c8fb 100644
--- a/stack/l2cap/l2c_main.cc
+++ b/stack/l2cap/l2c_main.cc
@@ -199,6 +199,7 @@
/* If no CCB for this channel, allocate one */
p_ccb = p_lcb->p_fixed_ccbs[rcv_cid - L2CAP_FIRST_FIXED_CHNL];
+ p_ccb->metrics.rx(p_msg->len);
if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
l2c_fcr_proc_pdu(p_ccb, p_msg);
diff --git a/stack/sdp/sdp_api.cc b/stack/sdp/sdp_api.cc
index 759b3b0..2d7ec6b 100644
--- a/stack/sdp/sdp_api.cc
+++ b/stack/sdp/sdp_api.cc
@@ -726,10 +726,10 @@
* Returns SDP_SUCCESS if query started successfully, else error
*
******************************************************************************/
-uint16_t SDP_DiDiscover(const RawAddress& remote_device,
- tSDP_DISCOVERY_DB* p_db, uint32_t len,
- tSDP_DISC_CMPL_CB* p_cb) {
- uint16_t result = SDP_DI_DISC_FAILED;
+tSDP_STATUS SDP_DiDiscover(const RawAddress& remote_device,
+ tSDP_DISCOVERY_DB* p_db, uint32_t len,
+ tSDP_DISC_CMPL_CB* p_cb) {
+ tSDP_STATUS result = SDP_DI_DISC_FAILED;
uint16_t num_uuids = 1;
uint16_t di_uuid = UUID_SERVCLASS_PNP_INFORMATION;
diff --git a/stack/sdp/sdp_main.cc b/stack/sdp/sdp_main.cc
index 339bae4..b2b0486 100644
--- a/stack/sdp/sdp_main.cc
+++ b/stack/sdp/sdp_main.cc
@@ -258,13 +258,13 @@
SDP_TRACE_EVENT("SDP - Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
/* Tell the user if there is a callback */
if (p_ccb->p_cb)
- (*p_ccb->p_cb)((uint16_t)((p_ccb->con_state == SDP_STATE_CONNECTED)
- ? SDP_SUCCESS
- : SDP_CONN_FAILED));
+ (*p_ccb->p_cb)(((p_ccb->con_state == SDP_STATE_CONNECTED)
+ ? SDP_SUCCESS
+ : SDP_CONN_FAILED));
else if (p_ccb->p_cb2)
(*p_ccb->p_cb2)(
- (uint16_t)((p_ccb->con_state == SDP_STATE_CONNECTED) ? SDP_SUCCESS
- : SDP_CONN_FAILED),
+ ((p_ccb->con_state == SDP_STATE_CONNECTED) ? SDP_SUCCESS
+ : SDP_CONN_FAILED),
p_ccb->user_data);
sdpu_release_ccb(p_ccb);
@@ -365,7 +365,7 @@
* Returns void
*
******************************************************************************/
-void sdp_disconnect(tCONN_CB* p_ccb, uint16_t reason) {
+void sdp_disconnect(tCONN_CB* p_ccb, tSDP_REASON reason) {
SDP_TRACE_EVENT("SDP - disconnect CID: 0x%x", p_ccb->connection_id);
/* Check if we have a connection ID */
@@ -383,7 +383,6 @@
sdpu_release_ccb(p_ccb);
}
-
/*******************************************************************************
*
* Function sdp_conn_timer_timeout
diff --git a/stack/sdp/sdpint.h b/stack/sdp/sdpint.h
index 8a4918e..770bf7f 100644
--- a/stack/sdp/sdpint.h
+++ b/stack/sdp/sdpint.h
@@ -183,7 +183,7 @@
/* Functions provided by sdp_main.cc */
extern void sdp_init(void);
extern void sdp_free(void);
-extern void sdp_disconnect(tCONN_CB* p_ccb, uint16_t reason);
+extern void sdp_disconnect(tCONN_CB* p_ccb, tSDP_REASON reason);
extern void sdp_conn_timer_timeout(void* data);
diff --git a/stack/smp/smp_act.cc b/stack/smp/smp_act.cc
index b11e291..35ad437 100644
--- a/stack/smp/smp_act.cc
+++ b/stack/smp/smp_act.cc
@@ -695,6 +695,16 @@
memcpy(pt.x, p_cb->peer_publ_key.x, BT_OCTET32_LEN);
memcpy(pt.y, p_cb->peer_publ_key.y, BT_OCTET32_LEN);
+ if (!memcmp(p_cb->peer_publ_key.x, p_cb->loc_publ_key.x, BT_OCTET32_LEN) &&
+ !memcmp(p_cb->peer_publ_key.y, p_cb->loc_publ_key.y, BT_OCTET32_LEN)) {
+ android_errorWriteLog(0x534e4554, "174886838");
+ SMP_TRACE_WARNING("Remote and local public keys can't match");
+ tSMP_INT_DATA smp;
+ smp.status = SMP_PAIR_AUTH_FAIL;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp);
+ return;
+ }
+
if (!ECC_ValidatePoint(pt)) {
android_errorWriteLog(0x534e4554, "72377774");
tSMP_INT_DATA smp;
diff --git a/stack/smp/smp_api.cc b/stack/smp/smp_api.cc
index 7cef82f..d738899 100644
--- a/stack/smp/smp_api.cc
+++ b/stack/smp/smp_api.cc
@@ -29,6 +29,8 @@
#include "bt_utils.h"
#include "stack_config.h"
+#include "gd/os/log.h"
+#include "gd/os/rand.h"
#include "hcimsgs.h"
#include "l2c_api.h"
#include "l2cdefs.h"
@@ -498,9 +500,6 @@
*
******************************************************************************/
void SMP_SecureConnectionOobDataReply(uint8_t* p_data) {
- LOG_ASSERT(!bluetooth::shim::is_gd_shim_enabled())
- << "Legacy SMP API should not be invoked when GD Security is used";
-
tSMP_CB* p_cb = &smp_cb;
tSMP_SC_OOB_DATA* p_oob = (tSMP_SC_OOB_DATA*)p_data;
@@ -552,3 +551,25 @@
smp_int_data.p_data = p_data;
smp_sm_event(&smp_cb, SMP_SC_OOB_DATA_EVT, &smp_int_data);
}
+
+/*******************************************************************************
+ *
+ * Function SMP_CrLocScOobData
+ *
+ * Description This function is called to generate a public key to be
+ * passed to a remote device via Out of Band transport
+ *
+ * Parameters: callback - receive the data
+ *
+ ******************************************************************************/
+void SMP_CrLocScOobData(
+ base::OnceCallback<void(tBT_TRANSPORT, bool,
+ const std::array<unsigned char, 16>&,
+ const std::array<unsigned char, 16>&)>
+ callback) {
+ smp_cb.local_random = bluetooth::os::GenerateRandom<16>();
+ smp_cb.selected_association_model = SMP_MODEL_SEC_CONN_OOB;
+ smp_calculate_local_commitment(&smp_cb);
+ std::move(callback).Run(BT_TRANSPORT_LE, true, smp_cb.commitment,
+ smp_cb.local_random);
+}
diff --git a/stack/smp/smp_keys.cc b/stack/smp/smp_keys.cc
index 1a8a3a5..2d7419c 100644
--- a/stack/smp/smp_keys.cc
+++ b/stack/smp/smp_keys.cc
@@ -614,19 +614,18 @@
*
******************************************************************************/
void smp_use_oob_private_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
- SMP_TRACE_DEBUG("%s req_oob_type: %d, role: %d", __func__, p_cb->req_oob_type,
- p_cb->role);
+ LOG_INFO("req_oob_type: %d, role: %d", p_cb->req_oob_type, p_cb->role);
switch (p_cb->req_oob_type) {
case SMP_OOB_BOTH:
case SMP_OOB_LOCAL:
- SMP_TRACE_DEBUG("%s restore secret key", __func__)
+ LOG_INFO("restore secret key");
memcpy(p_cb->private_key, p_cb->sc_oob_data.loc_oob_data.private_key_used,
BT_OCTET32_LEN);
smp_process_private_key(p_cb);
break;
default:
- SMP_TRACE_DEBUG("%s create secret key anew", __func__);
+ LOG_INFO("create secret key anew");
smp_set_state(SMP_STATE_PAIR_REQ_RSP);
smp_decide_association_model(p_cb, NULL);
break;
diff --git a/stack/smp/smp_l2c.cc b/stack/smp/smp_l2c.cc
index 258bf2f..6c286b1 100644
--- a/stack/smp/smp_l2c.cc
+++ b/stack/smp/smp_l2c.cc
@@ -104,10 +104,10 @@
if (connected) {
LOG_DEBUG("SMP Received connect callback bd_addr:%s transport:%s",
- PRIVATE_ADDRESS(bd_addr), BtTransportText(transport).c_str());
+ PRIVATE_ADDRESS(bd_addr), bt_transport_text(transport).c_str());
} else {
LOG_DEBUG("SMP Received disconnect callback bd_addr:%s transport:%s",
- PRIVATE_ADDRESS(bd_addr), BtTransportText(transport).c_str());
+ PRIVATE_ADDRESS(bd_addr), bt_transport_text(transport).c_str());
}
if (bd_addr == p_cb->pairing_bda) {
diff --git a/stack/smp/smp_utils.cc b/stack/smp/smp_utils.cc
index ece16e6..54d4aeb 100644
--- a/stack/smp/smp_utils.cc
+++ b/stack/smp/smp_utils.cc
@@ -31,6 +31,7 @@
#include "device/include/controller.h"
#include "hcidefs.h"
#include "l2c_api.h"
+#include "osi/include/log.h"
#include "osi/include/osi.h"
#include "smp_int.h"
#include "stack/btm/btm_ble_int.h"
@@ -375,8 +376,9 @@
BT_HDR* p_buf;
bool sent = false;
- SMP_TRACE_EVENT("%s: on l2cap cmd_code=0x%x, pairing_bda=%s", __func__,
- cmd_code, p_cb->pairing_bda.ToString().c_str());
+ LOG_DEBUG("Sending SMP command:%s[0x%x] pairing_bda=%s",
+ smp_opcode_text(static_cast<tSMP_OPCODE>(cmd_code)).c_str(),
+ cmd_code, PRIVATE_ADDRESS(p_cb->pairing_bda));
if (cmd_code <= (SMP_OPCODE_MAX + 1 /* for SMP_OPCODE_PAIR_COMMITM */) &&
smp_cmd_build_act[cmd_code] != NULL) {
@@ -941,21 +943,20 @@
tSMP_EVT_DATA evt_data = {0};
tSMP_CALLBACK* p_callback = p_cb->p_callback;
- SMP_TRACE_DEBUG("%s: pairing_bda=%s", __func__,
- p_cb->pairing_bda.ToString().c_str());
-
evt_data.cmplt.reason = p_cb->status;
evt_data.cmplt.smp_over_br = p_cb->smp_over_br;
+ LOG_DEBUG(
+ "Pairing process has completed to remote:%s reason:0x%0x sec_level=0x%0x",
+ PRIVATE_ADDRESS(p_cb->pairing_bda), evt_data.cmplt.reason,
+ evt_data.cmplt.sec_level);
+
if (p_cb->status == SMP_SUCCESS) evt_data.cmplt.sec_level = p_cb->sec_level;
evt_data.cmplt.is_pair_cancel = false;
if (p_cb->is_pair_cancel) evt_data.cmplt.is_pair_cancel = true;
- SMP_TRACE_DEBUG("send SMP_COMPLT_EVT reason=0x%0x sec_level=0x%0x",
- evt_data.cmplt.reason, evt_data.cmplt.sec_level);
-
RawAddress pairing_bda = p_cb->pairing_bda;
smp_reset_control_value(p_cb);
diff --git a/stack/srvc/srvc_eng.cc b/stack/srvc/srvc_eng.cc
index 3792124..571a64e 100644
--- a/stack/srvc/srvc_eng.cc
+++ b/stack/srvc/srvc_eng.cc
@@ -27,7 +27,7 @@
using base::StringPrintf;
static void srvc_eng_s_request_cback(uint16_t conn_id, uint32_t trans_id,
- uint8_t op_code, tGATTS_DATA* p_data);
+ tGATTS_REQ_TYPE type, tGATTS_DATA* p_data);
static void srvc_eng_connect_cback(UNUSED_ATTR tGATT_IF gatt_if,
const RawAddress& bda, uint16_t conn_id,
bool connected, tGATT_DISCONN_REASON reason,
@@ -36,21 +36,24 @@
tGATT_STATUS status,
tGATT_CL_COMPLETE* p_data);
-static tGATT_CBACK srvc_gatt_cback = {srvc_eng_connect_cback,
- srvc_eng_c_cmpl_cback,
- NULL,
- NULL,
- srvc_eng_s_request_cback,
- NULL,
- NULL,
- NULL,
- NULL};
+static tGATT_CBACK srvc_gatt_cback = {
+ .p_conn_cb = srvc_eng_connect_cback,
+ .p_cmpl_cb = srvc_eng_c_cmpl_cback,
+ .p_disc_res_cb = nullptr,
+ .p_disc_cmpl_cb = nullptr,
+ .p_req_cb = srvc_eng_s_request_cback,
+ .p_enc_cmpl_cb = nullptr,
+ .p_congestion_cb = nullptr,
+ .p_phy_update_cb = nullptr,
+ .p_conn_update_cb = nullptr,
+};
+
/* type for action functions */
typedef void (*tSRVC_ENG_C_CMPL_ACTION)(tSRVC_CLCB* p_clcb, tGATTC_OPTYPE op,
tGATT_STATUS status,
tGATT_CL_COMPLETE* p_data);
-const tSRVC_ENG_C_CMPL_ACTION srvc_eng_c_cmpl_act[SRVC_ID_MAX] = {
+static const tSRVC_ENG_C_CMPL_ACTION srvc_eng_c_cmpl_act[SRVC_ID_MAX] = {
dis_c_cmpl_cback,
};
@@ -58,29 +61,6 @@
/*******************************************************************************
*
- * Function srvc_eng_find_conn_id_by_bd_addr
- *
- * Description The function searches all LCB with macthing bd address
- *
- * Returns total number of clcb found.
- *
- ******************************************************************************/
-uint16_t srvc_eng_find_conn_id_by_bd_addr(const RawAddress& bda) {
- uint8_t i_clcb;
- tSRVC_CLCB* p_clcb = NULL;
-
- for (i_clcb = 0, p_clcb = srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS;
- i_clcb++, p_clcb++) {
- if (p_clcb->in_use && p_clcb->connected && p_clcb->bda == bda) {
- return p_clcb->conn_id;
- }
- }
-
- return GATT_INVALID_CONN_ID;
-}
-
-/*******************************************************************************
- *
* Function srvc_eng_find_clcb_by_bd_addr
*
* Description The function searches all LCBs with macthing bd address.
@@ -88,7 +68,7 @@
* Returns Pointer to the found link conenction control block.
*
******************************************************************************/
-tSRVC_CLCB* srvc_eng_find_clcb_by_bd_addr(const RawAddress& bda) {
+static tSRVC_CLCB* srvc_eng_find_clcb_by_bd_addr(const RawAddress& bda) {
uint8_t i_clcb;
tSRVC_CLCB* p_clcb = NULL;
@@ -132,7 +112,7 @@
* Returns Pointer to the found link conenction control block.
*
******************************************************************************/
-uint8_t srvc_eng_find_clcb_idx_by_conn_id(uint16_t conn_id) {
+static uint8_t srvc_eng_find_clcb_idx_by_conn_id(uint16_t conn_id) {
uint8_t i_clcb;
tSRVC_CLCB* p_clcb = NULL;
@@ -155,7 +135,8 @@
* block.
*
******************************************************************************/
-tSRVC_CLCB* srvc_eng_clcb_alloc(uint16_t conn_id, const RawAddress& bda) {
+static tSRVC_CLCB* srvc_eng_clcb_alloc(uint16_t conn_id,
+ const RawAddress& bda) {
uint8_t i_clcb = 0;
tSRVC_CLCB* p_clcb = NULL;
@@ -180,7 +161,7 @@
* Returns True the deallocation is successful
*
******************************************************************************/
-bool srvc_eng_clcb_dealloc(uint16_t conn_id) {
+static bool srvc_eng_clcb_dealloc(uint16_t conn_id) {
uint8_t i_clcb = 0;
tSRVC_CLCB* p_clcb = NULL;
@@ -200,8 +181,10 @@
/*******************************************************************************
* Service Engine Server Attributes Database Read/Read Blob Request process
******************************************************************************/
-uint8_t srvc_eng_process_read_req(uint8_t clcb_idx, tGATT_READ_REQ* p_data,
- tGATTS_RSP* p_rsp, tGATT_STATUS* p_status) {
+static uint8_t srvc_eng_process_read_req(uint8_t clcb_idx,
+ tGATT_READ_REQ* p_data,
+ tGATTS_RSP* p_rsp,
+ tGATT_STATUS* p_status) {
tGATT_STATUS status = GATT_NOT_FOUND;
uint8_t act = SRVC_ACT_RSP;
@@ -219,9 +202,10 @@
/*******************************************************************************
* Service Engine Server Attributes Database write Request process
******************************************************************************/
-uint8_t srvc_eng_process_write_req(uint8_t clcb_idx, tGATT_WRITE_REQ* p_data,
- UNUSED_ATTR tGATTS_RSP* p_rsp,
- tGATT_STATUS* p_status) {
+static uint8_t srvc_eng_process_write_req(uint8_t clcb_idx,
+ tGATT_WRITE_REQ* p_data,
+ UNUSED_ATTR tGATTS_RSP* p_rsp,
+ tGATT_STATUS* p_status) {
uint8_t act = SRVC_ACT_RSP;
if (dis_valid_handle_range(p_data->handle)) {
@@ -401,7 +385,8 @@
/* Create a GATT profile service */
bluetooth::Uuid app_uuid =
bluetooth::Uuid::From16Bit(UUID_SERVCLASS_DEVICE_INFO);
- srvc_eng_cb.gatt_if = GATT_Register(app_uuid, &srvc_gatt_cback, false);
+ srvc_eng_cb.gatt_if =
+ GATT_Register(app_uuid, "GattServiceEngine", &srvc_gatt_cback, false);
GATT_StartIf(srvc_eng_cb.gatt_if);
VLOG(1) << "Srvc_Init: gatt_if=" << +srvc_eng_cb.gatt_if;
@@ -411,20 +396,3 @@
}
return GATT_SUCCESS;
}
-
-void srvc_sr_rsp(uint8_t clcb_idx, tGATT_STATUS st, tGATTS_RSP* p_rsp) {
- if (srvc_eng_cb.clcb[clcb_idx].trans_id != 0) {
- GATTS_SendRsp(srvc_eng_cb.clcb[clcb_idx].conn_id,
- srvc_eng_cb.clcb[clcb_idx].trans_id, st, p_rsp);
-
- srvc_eng_cb.clcb[clcb_idx].trans_id = 0;
- }
-}
-void srvc_sr_notify(const RawAddress& remote_bda, uint16_t handle, uint16_t len,
- uint8_t* p_value) {
- uint16_t conn_id = srvc_eng_find_conn_id_by_bd_addr(remote_bda);
-
- if (conn_id != GATT_INVALID_CONN_ID) {
- GATTS_HandleValueNotification(conn_id, handle, len, p_value);
- }
-}
diff --git a/stack/srvc/srvc_eng_int.h b/stack/srvc/srvc_eng_int.h
index 9ea2d0b..63f1e47 100644
--- a/stack/srvc/srvc_eng_int.h
+++ b/stack/srvc/srvc_eng_int.h
@@ -57,14 +57,8 @@
extern tSRVC_ENG_CB srvc_eng_cb;
extern tSRVC_CLCB* srvc_eng_find_clcb_by_conn_id(uint16_t conn_id);
-extern tSRVC_CLCB* srvc_eng_find_clcb_by_bd_addr(const RawAddress& bda);
-extern uint16_t srvc_eng_find_conn_id_by_bd_addr(const RawAddress& bda);
extern void srvc_eng_release_channel(uint16_t conn_id);
extern bool srvc_eng_request_channel(const RawAddress& remote_bda,
uint8_t srvc_id);
-extern void srvc_sr_rsp(uint8_t clcb_idx, tGATT_STATUS st, tGATTS_RSP* p_rsp);
-extern void srvc_sr_notify(const RawAddress& remote_bda, uint16_t handle,
- uint16_t len, uint8_t* p_value);
-
#endif
diff --git a/stack/test/btm/peer_packet_types_test.cc b/stack/test/btm/peer_packet_types_test.cc
new file mode 100644
index 0000000..905a6ea
--- /dev/null
+++ b/stack/test/btm/peer_packet_types_test.cc
@@ -0,0 +1,86 @@
+/*
+ *
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <map>
+
+#include "stack/acl/peer_packet_types.h"
+#include "stack/include/bt_types.h"
+
+namespace {
+
+using testing::_;
+using testing::DoAll;
+using testing::NotNull;
+using testing::Pointee;
+using testing::Return;
+using testing::SaveArg;
+using testing::SaveArgPointee;
+using testing::StrEq;
+using testing::StrictMock;
+using testing::Test;
+
+class PeerPacketTest : public Test {
+ public:
+ protected:
+ void SetUp() override {}
+ void TearDown() override {}
+};
+
+TEST_F(PeerPacketTest, all_ones) {
+ const BD_FEATURES bd_features = {0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff};
+ PeerPacketTypes peer_packet_types(bd_features);
+ ASSERT_EQ(peer_packet_types.acl.supported, 0xcc00);
+ ASSERT_EQ(peer_packet_types.acl.unsupported, 0x0);
+}
+
+TEST_F(PeerPacketTest, 3SLOT_DH3_DM3) {
+ const BD_FEATURES bd_features = {0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+ PeerPacketTypes peer_packet_types(bd_features);
+ ASSERT_EQ(peer_packet_types.acl.supported, 0x0c00);
+ ASSERT_EQ(peer_packet_types.acl.unsupported, 0x3306);
+}
+
+TEST_F(PeerPacketTest, 5SLOT_DH5_DM5) {
+ const BD_FEATURES bd_features = {0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+ PeerPacketTypes peer_packet_types(bd_features);
+ ASSERT_EQ(peer_packet_types.acl.supported, 0xc000);
+ ASSERT_EQ(peer_packet_types.acl.unsupported, 0x3306);
+}
+
+TEST_F(PeerPacketTest, 2Mb_support) {
+ const BD_FEATURES bd_features = {0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00};
+ PeerPacketTypes peer_packet_types(bd_features);
+ ASSERT_EQ(peer_packet_types.acl.supported, 0x0000);
+ ASSERT_EQ(peer_packet_types.acl.unsupported, 0x3304);
+}
+
+TEST_F(PeerPacketTest, 3Mb_support) {
+ const BD_FEATURES bd_features = {0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x00, 0x00, 0x00};
+ PeerPacketTypes peer_packet_types(bd_features);
+ ASSERT_EQ(peer_packet_types.acl.supported, 0x0000);
+ ASSERT_EQ(peer_packet_types.acl.unsupported, 0x3302);
+}
+
+} // namespace
diff --git a/stack/test/btm/stack_btm_test.cc b/stack/test/btm/stack_btm_test.cc
index 52c153f..f2880c6 100644
--- a/stack/test/btm/stack_btm_test.cc
+++ b/stack/test/btm/stack_btm_test.cc
@@ -20,28 +20,33 @@
#include <gtest/gtest.h>
#include <map>
+#include "btif/include/btif_hh.h"
#include "hci/include/hci_layer.h"
#include "hci/include/hci_packet_factory.h"
+#include "hci/include/packet_fragmenter.h"
#include "internal_include/stack_config.h"
#include "osi/include/osi.h"
#include "stack/btm/btm_int_types.h"
+#include "stack/include/acl_api.h"
#include "stack/include/acl_hci_link_interface.h"
#include "stack/include/btm_client_interface.h"
+#include "stack/l2cap/l2c_int.h"
+#include "test/mock/mock_hcic_hcicmds.h"
#include "types/raw_address.h"
+namespace mock = test::mock::hcic_hcicmds;
+
extern tBTM_CB btm_cb;
-bluetooth::common::MessageLoopThread* get_main_thread() { return nullptr; }
+uint8_t appl_trace_level = BT_TRACE_LEVEL_VERBOSE;
+btif_hh_cb_t btif_hh_cb;
+tL2C_CB l2cb;
const hci_packet_factory_t* hci_packet_factory_get_interface() {
return nullptr;
}
const hci_t* hci_layer_get_interface() { return nullptr; }
-bt_status_t do_in_main_thread(const base::Location& from_here,
- base::OnceClosure task) {
- return BT_STATUS_SUCCESS;
-}
void LogMsg(uint32_t trace_set_mask, const char* fmt_str, ...) {}
const std::string kSmpOptions("mock smp options");
@@ -54,6 +59,7 @@
const std::string* get_pts_smp_options(void) { return &kSmpOptions; }
int get_pts_smp_failure_case(void) { return 123; }
config_t* get_all(void) { return nullptr; }
+const packet_fragmenter_t* packet_fragmenter_get_interface() { return nullptr; }
stack_config_t mock_stack_config{
.get_trace_config_enabled = get_trace_config_enabled,
@@ -71,7 +77,7 @@
std::map<std::string, int> mock_function_count_map;
-bool MOCK_bluetooth_shim_is_gd_acl_enabled_;
+extern bool MOCK_bluetooth_shim_is_gd_acl_enabled_;
namespace {
@@ -140,4 +146,40 @@
get_btm_client_interface().lifecycle.btm_free();
}
+TEST_F(StackBtmTest, change_packet_type) {
+ int cnt = 0;
+ get_btm_client_interface().lifecycle.btm_init();
+
+ btm_cb.acl_cb_.SetDefaultPacketTypeMask(0xffff);
+ ASSERT_EQ(0xffff, btm_cb.acl_cb_.DefaultPacketTypes());
+
+ // Create connection
+ RawAddress bda({0x11, 0x22, 0x33, 0x44, 0x55, 0x66});
+ btm_acl_created(bda, 0x123, HCI_ROLE_CENTRAL, BT_TRANSPORT_BR_EDR);
+
+ uint64_t features = 0xffffffffffffffff;
+ acl_process_supported_features(0x123, features);
+
+ mock::btsnd_hcic_change_conn_type = {};
+ uint16_t pkt_types = 0x55aa;
+ btm_set_packet_types_from_address(bda, pkt_types);
+ ASSERT_EQ(++cnt, mock_function_count_map["btsnd_hcic_change_conn_type"]);
+ ASSERT_EQ(0x123, mock::btsnd_hcic_change_conn_type.handle);
+ ASSERT_EQ(0x4400, mock::btsnd_hcic_change_conn_type.packet_types);
+
+ mock::btsnd_hcic_change_conn_type = {};
+ btm_set_packet_types_from_address(bda, 0xffff);
+ ASSERT_EQ(++cnt, mock_function_count_map["btsnd_hcic_change_conn_type"]);
+ ASSERT_EQ(0x123, mock::btsnd_hcic_change_conn_type.handle);
+ ASSERT_EQ(0xcc00, mock::btsnd_hcic_change_conn_type.packet_types);
+
+ mock::btsnd_hcic_change_conn_type = {};
+ btm_set_packet_types_from_address(bda, 0x0);
+ // NOTE: The call should not be executed with no bits set
+ ASSERT_EQ(0x0, mock::btsnd_hcic_change_conn_type.handle);
+ ASSERT_EQ(0x0, mock::btsnd_hcic_change_conn_type.packet_types);
+
+ get_btm_client_interface().lifecycle.btm_free();
+}
+
} // namespace
diff --git a/stack/test/common/mock_acl.cc b/stack/test/common/mock_acl.cc
deleted file mode 100644
index ed0095f..0000000
--- a/stack/test/common/mock_acl.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:14
- */
-
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-#define LOG_TAG "bt_shim"
-#include "gd/common/init_flags.h"
-#include "main/shim/entry.h"
-#include "main/shim/shim.h"
-#include "types/raw_address.h"
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-void acl_add_to_ignore_auto_connect_after_disconnect(
- const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
-}
-
-bool acl_check_and_clear_ignore_auto_connect_after_disconnect(
- const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return false;
-}
-
-void acl_clear_all_ignore_auto_connect_after_disconnect() {
- mock_function_count_map[__func__]++;
-}
diff --git a/stack/test/common/mock_btif_dm.cc b/stack/test/common/mock_btif_dm.cc
index 1f2b2fb..d783cea 100644
--- a/stack/test/common/mock_btif_dm.cc
+++ b/stack/test/common/mock_btif_dm.cc
@@ -27,6 +27,7 @@
#include <cstdint>
#include "bta/include/bta_api.h"
#include "include/hardware/bluetooth.h"
+#include "types/bt_transport.h"
#include "types/raw_address.h"
struct uid_set_t;
@@ -155,3 +156,8 @@
tBT_DEVICE_TYPE dev_type) {
mock_function_count_map[__func__]++;
}
+
+void btif_dm_proc_loc_oob(tBT_TRANSPORT transport, bool is_valid,
+ const Octet16& c, const Octet16& r) {
+ mock_function_count_map[__func__]++;
+}
diff --git a/stack/test/common/mock_gatt_layer.cc b/stack/test/common/mock_gatt_layer.cc
index 01b7ef7..a941066 100644
--- a/stack/test/common/mock_gatt_layer.cc
+++ b/stack/test/common/mock_gatt_layer.cc
@@ -24,8 +24,16 @@
gatt_interface = mock_gatt_interface;
}
-bool gatt_profile_get_eatt_support(
+bool gatt_profile_get_eatt_support(const RawAddress& peer_bda) {
+ return gatt_interface->GetEattSupport(peer_bda);
+}
+
+void gatt_cl_init_sr_status(tGATT_TCB& tcb) {
+ return gatt_interface->ClientInitServerStatus(tcb);
+}
+
+bool gatt_cl_read_sr_supp_feat_req(
const RawAddress& peer_bda,
- base::OnceCallback<void(const RawAddress&, bool)> cb) {
- return gatt_interface->GetEattSupport(peer_bda, std::move(cb));
+ base::OnceCallback<void(const RawAddress&, uint8_t)> cb) {
+ return gatt_interface->ClientReadSupportedFeatures(peer_bda, std::move(cb));
}
diff --git a/stack/test/common/mock_gatt_layer.h b/stack/test/common/mock_gatt_layer.h
index 255f43d..c61ef4a 100644
--- a/stack/test/common/mock_gatt_layer.h
+++ b/stack/test/common/mock_gatt_layer.h
@@ -18,7 +18,7 @@
#include <gmock/gmock.h>
-#include "base/bind_helpers.h"
+#include "bind_helpers.h"
#include "stack/gatt/gatt_int.h"
namespace bluetooth {
@@ -26,17 +26,21 @@
class GattInterface {
public:
- virtual bool GetEattSupport(
+ virtual void ClientInitServerStatus(tGATT_TCB& tcb) = 0;
+ virtual bool ClientReadSupportedFeatures(
const RawAddress& peer_bda,
- base::OnceCallback<void(const RawAddress&, bool)> cb) = 0;
+ base::OnceCallback<void(const RawAddress&, uint8_t)> cb) = 0;
+ virtual bool GetEattSupport(const RawAddress& peer_bda) = 0;
virtual ~GattInterface() = default;
};
class MockGattInterface : public GattInterface {
public:
- MOCK_METHOD2(GetEattSupport,
+ MOCK_METHOD1(ClientInitServerStatus, void(tGATT_TCB& tcb));
+ MOCK_METHOD2(ClientReadSupportedFeatures,
bool(const RawAddress& peer_bda,
- base::OnceCallback<void(const RawAddress&, bool)> cb));
+ base::OnceCallback<void(const RawAddress&, uint8_t)> cb));
+ MOCK_METHOD1(GetEattSupport, bool(const RawAddress& peer_bda));
};
/**
diff --git a/stack/test/common/mock_hcic_hcicmds.cc b/stack/test/common/mock_hcic_hcicmds.cc
deleted file mode 100644
index 18c8416..0000000
--- a/stack/test/common/mock_hcic_hcicmds.cc
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:77
- */
-
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-#define UNUSED_ATTR
-
-#include <stddef.h>
-#include <string.h>
-#include "bt_common.h"
-#include "bt_target.h"
-#include "btu.h"
-#include "hcidefs.h"
-#include "hcimsgs.h"
-#include "stack/include/acl_hci_link_interface.h"
-void btsnd_hcic_accept_conn(const RawAddress& dest, uint8_t role) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_accept_esco_conn(const RawAddress& bd_addr,
- uint32_t transmit_bandwidth,
- uint32_t receive_bandwidth,
- uint16_t max_latency, uint16_t content_fmt,
- uint8_t retrans_effort,
- uint16_t packet_types) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_add_SCO_conn(uint16_t handle, uint16_t packet_types) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_auth_request(uint16_t handle) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_change_conn_type(uint16_t handle, uint16_t packet_types) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_change_name(BD_NAME name) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_create_conn(const RawAddress& dest, uint16_t packet_types,
- uint8_t page_scan_rep_mode, uint8_t page_scan_mode,
- uint16_t clock_offset, uint8_t allow_switch) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_create_conn_cancel(const RawAddress& dest) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_delete_stored_key(const RawAddress& bd_addr,
- bool delete_all_flag) {
- mock_function_count_map[__func__]++;
-}
-static void btsnd_hcic_disconnect(uint16_t handle, uint8_t reason) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_enable_test_mode(void) { mock_function_count_map[__func__]++; }
-void btsnd_hcic_enhanced_accept_synchronous_connection(
- const RawAddress& bd_addr, enh_esco_params_t* p_params) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_enhanced_flush(uint16_t handle, uint8_t packet_type) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_enhanced_set_up_synchronous_connection(
- uint16_t conn_handle, enh_esco_params_t* p_params) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_exit_park_mode(uint16_t handle) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_exit_per_inq(void) { mock_function_count_map[__func__]++; }
-void btsnd_hcic_exit_sniff_mode(uint16_t handle) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_get_link_quality(uint16_t handle) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_hold_mode(uint16_t handle, uint16_t max_hold_period,
- uint16_t min_hold_period) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_host_num_xmitted_pkts(uint8_t num_handles, uint16_t* handle,
- uint16_t* num_pkts) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_inq_cancel(void) { mock_function_count_map[__func__]++; }
-void btsnd_hcic_inquiry(const LAP inq_lap, uint8_t duration,
- uint8_t response_cnt) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_io_cap_req_neg_reply(const RawAddress& bd_addr,
- uint8_t err_code) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_io_cap_req_reply(const RawAddress& bd_addr, uint8_t capability,
- uint8_t oob_present, uint8_t auth_req) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_link_key_neg_reply(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_link_key_req_reply(const RawAddress& bd_addr,
- const LinkKey& link_key) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_park_mode(uint16_t handle, uint16_t beacon_max_interval,
- uint16_t beacon_min_interval) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_per_inq_mode(uint16_t max_period, uint16_t min_period,
- const LAP inq_lap, uint8_t duration,
- uint8_t response_cnt) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_pin_code_neg_reply(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_pin_code_req_reply(const RawAddress& bd_addr,
- uint8_t pin_code_len, PIN_CODE pin_code) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_qos_setup(uint16_t handle, uint8_t flags, uint8_t service_type,
- uint32_t token_rate, uint32_t peak, uint32_t latency,
- uint32_t delay_var) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_read_automatic_flush_timeout(uint16_t handle) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_read_encryption_key_size(uint16_t handle, ReadEncKeySizeCb cb) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_read_failed_contact_counter(uint16_t handle) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_read_inq_tx_power(void) { mock_function_count_map[__func__]++; }
-void btsnd_hcic_read_lmp_handle(uint16_t handle) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_read_local_oob_data(void) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_read_name(void) { mock_function_count_map[__func__]++; }
-void btsnd_hcic_read_rmt_clk_offset(uint16_t handle) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_read_rssi(uint16_t handle) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_read_tx_power(uint16_t handle, uint8_t type) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_reject_conn(const RawAddress& dest, uint8_t reason) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_reject_esco_conn(const RawAddress& bd_addr, uint8_t reason) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_rem_oob_neg_reply(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_rem_oob_reply(const RawAddress& bd_addr, const Octet16& c,
- const Octet16& r) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_rmt_ext_features(uint16_t handle, uint8_t page_num) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_rmt_features_req(uint16_t handle) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_rmt_name_req(const RawAddress& bd_addr,
- uint8_t page_scan_rep_mode, uint8_t page_scan_mode,
- uint16_t clock_offset) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_rmt_name_req_cancel(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_rmt_ver_req(uint16_t handle) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_send_keypress_notif(const RawAddress& bd_addr, uint8_t notif) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_set_conn_encrypt(uint16_t handle, bool enable) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_set_event_filter(uint8_t filt_type, uint8_t filt_cond_type,
- uint8_t* filt_cond, uint8_t filt_cond_len) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_setup_esco_conn(uint16_t handle, uint32_t transmit_bandwidth,
- uint32_t receive_bandwidth,
- uint16_t max_latency, uint16_t voice,
- uint8_t retrans_effort, uint16_t packet_types) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_sniff_mode(uint16_t handle, uint16_t max_sniff_period,
- uint16_t min_sniff_period, uint16_t sniff_attempt,
- uint16_t sniff_timeout) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_sniff_sub_rate(uint16_t handle, uint16_t max_lat,
- uint16_t min_remote_lat,
- uint16_t min_local_lat) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_switch_role(const RawAddress& bd_addr, uint8_t role) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_user_conf_reply(const RawAddress& bd_addr, bool is_yes) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_user_passkey_neg_reply(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_user_passkey_reply(const RawAddress& bd_addr, uint32_t value) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_vendor_spec_cmd(void* buffer, uint16_t opcode, uint8_t len,
- uint8_t* p_data, void* p_cmd_cplt_cback) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_write_auth_enable(uint8_t flag) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_write_auto_flush_tout(uint16_t handle, uint16_t tout) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_write_cur_iac_lap(uint8_t num_cur_iac, LAP* const iac_lap) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_write_def_policy_set(uint16_t settings) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_write_dev_class(DEV_CLASS dev_class) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_write_ext_inquiry_response(void* buffer, uint8_t fec_req) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_write_inqscan_cfg(uint16_t interval, uint16_t window) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_write_inqscan_type(uint8_t type) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_write_inquiry_mode(uint8_t mode) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_write_link_super_tout(uint8_t local_controller_id,
- uint16_t handle, uint16_t timeout) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_write_page_tout(uint16_t timeout) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_write_pagescan_cfg(uint16_t interval, uint16_t window) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_write_pagescan_type(uint8_t type) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_write_pin_type(uint8_t type) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_write_policy_set(uint16_t handle, uint16_t settings) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_write_scan_enable(uint8_t flag) {
- mock_function_count_map[__func__]++;
-}
-void btsnd_hcic_write_voice_settings(uint16_t flags) {
- mock_function_count_map[__func__]++;
-}
-
-bluetooth::legacy::hci::Interface interface_ = {
- .Disconnect = btsnd_hcic_disconnect,
- .StartRoleSwitch = btsnd_hcic_switch_role,
-};
-
-const bluetooth::legacy::hci::Interface&
-bluetooth::legacy::hci::GetInterface() {
- return interface_;
-}
diff --git a/stack/test/common/mock_l2cap_l2c_api.cc b/stack/test/common/mock_l2cap_l2c_api.cc
deleted file mode 100644
index 8f8326dc..0000000
--- a/stack/test/common/mock_l2cap_l2c_api.cc
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:33
- */
-
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-#include <cstdint>
-#include "stack/include/l2c_api.h"
-#include "types/raw_address.h"
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-bool L2CA_ConnectCreditBasedRsp(const RawAddress& p_bd_addr, uint8_t id,
- std::vector<uint16_t>& accepted_lcids,
- uint16_t result, tL2CAP_LE_CFG_INFO* p_cfg) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_ConnectFixedChnl(uint16_t fixed_cid, const RawAddress& rem_bda) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_DisconnectLECocReq(uint16_t cid) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_DisconnectReq(uint16_t cid) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_GetPeerFeatures(const RawAddress& bd_addr, uint32_t* p_ext_feat,
- uint8_t* p_chnl_mask) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_GetPeerLECocConfig(uint16_t lcid, tL2CAP_LE_CFG_INFO* peer_cfg) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_GetRemoteCid(uint16_t lcid, uint16_t* rcid) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_IsLinkEstablished(const RawAddress& bd_addr,
- tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_ReconfigCreditBasedConnsReq(const RawAddress& bda,
- std::vector<uint16_t>& lcids,
- tL2CAP_LE_CFG_INFO* p_cfg) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_RegisterFixedChannel(uint16_t fixed_cid,
- tL2CAP_FIXED_CHNL_REG* p_freg) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_RemoveFixedChnl(uint16_t fixed_cid, const RawAddress& rem_bda) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_SetAclPriority(const RawAddress& bd_addr, tL2CAP_PRIORITY priority) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_SetChnlFlushability(uint16_t cid, bool is_flushable) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_SetLeGattTimeout(const RawAddress& rem_bda, uint16_t idle_tout) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_SetIdleTimeoutByBdAddr(const RawAddress& bd_addr, uint16_t timeout,
- tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_SetTxPriority(uint16_t cid, tL2CAP_CHNL_PRIORITY priority) {
- mock_function_count_map[__func__]++;
- return false;
-}
-std::vector<uint16_t> L2CA_ConnectCreditBasedReq(uint16_t psm,
- const RawAddress& p_bd_addr,
- tL2CAP_LE_CFG_INFO* p_cfg) {
- mock_function_count_map[__func__]++;
- std::vector<uint16_t> v;
- return v;
-}
-tBT_TRANSPORT l2c_get_transport_from_fixed_cid(uint16_t fixed_cid) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint16_t L2CA_AllocateLePSM(void) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint16_t L2CA_ConnectLECocReq(uint16_t psm, const RawAddress& p_bd_addr,
- tL2CAP_LE_CFG_INFO* p_cfg, uint16_t sec_level) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint16_t L2CA_ConnectReq(uint16_t psm, const RawAddress& p_bd_addr) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint16_t L2CA_ConnectReq2(uint16_t psm, const RawAddress& p_bd_addr,
- uint16_t sec_level) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint16_t L2CA_FlushChannel(uint16_t lcid, uint16_t num_to_flush) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint16_t L2CA_Register(uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info,
- bool enable_snoop, tL2CAP_ERTM_INFO* p_ertm_info,
- uint16_t my_mtu, uint16_t required_remote_mtu) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint16_t L2CA_Register2(uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info,
- bool enable_snoop, tL2CAP_ERTM_INFO* p_ertm_info,
- uint16_t my_mtu, uint16_t required_remote_mtu,
- uint16_t sec_level) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint16_t L2CA_RegisterLECoc(uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info,
- uint16_t sec_level, tL2CAP_LE_CFG_INFO cfg) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint16_t L2CA_SendFixedChnlData(uint16_t fixed_cid, const RawAddress& rem_bda,
- BT_HDR* p_buf) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint8_t L2CA_DataWrite(uint16_t cid, BT_HDR* p_data) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint8_t L2CA_LECocDataWrite(uint16_t cid, BT_HDR* p_data) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint8_t L2CA_SetTraceLevel(uint8_t new_level) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-void L2CA_Deregister(uint16_t psm) { mock_function_count_map[__func__]++; }
-void L2CA_DeregisterLECoc(uint16_t psm) { mock_function_count_map[__func__]++; }
-void L2CA_FreeLePSM(uint16_t psm) { mock_function_count_map[__func__]++; }
diff --git a/stack/test/common/mock_l2cap_l2c_ble.cc b/stack/test/common/mock_l2cap_l2c_ble.cc
deleted file mode 100644
index 44ae6e2..0000000
--- a/stack/test/common/mock_l2cap_l2c_ble.cc
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:26
- */
-
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-#include <base/logging.h>
-#include "bt_target.h"
-#include "device/include/controller.h"
-#include "hcimsgs.h"
-#include "main/shim/shim.h"
-#include "osi/include/log.h"
-#include "osi/include/osi.h"
-#include "stack/btm/btm_dev.h"
-#include "stack/btm/btm_sec.h"
-#include "stack/include/acl_api.h"
-#include "stack/include/l2c_api.h"
-#include "stack/include/l2cdefs.h"
-#include "stack/l2cap/l2c_int.h"
-#include "stack_config.h"
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-bool L2CA_EnableUpdateBleConnParams(const RawAddress& rem_bda, bool enable) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_UpdateBleConnParams(const RawAddress& rem_bda, uint16_t min_int,
- uint16_t max_int, uint16_t latency,
- uint16_t timeout) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_UpdateBleConnParams(const RawAddress& rem_bda, uint16_t min_int,
- uint16_t max_int, uint16_t latency,
- uint16_t timeout, uint16_t min_ce_len,
- uint16_t max_ce_len) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool 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) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool l2cble_conn_comp_from_address_with_type(
- uint16_t handle, uint8_t role, const tBLE_BD_ADDR& address_with_type,
- uint16_t conn_interval, uint16_t conn_latency, uint16_t conn_timeout) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool l2cble_create_conn(tL2C_LCB* p_lcb) {
- mock_function_count_map[__func__]++;
- return false;
-}
-hci_role_t L2CA_GetBleConnRole(const RawAddress& bd_addr) {
- mock_function_count_map[__func__]++;
- return HCI_ROLE_CENTRAL;
-}
-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) {
- mock_function_count_map[__func__]++;
- return L2CAP_LE_RESULT_CONN_OK;
-}
-uint16_t L2CA_GetDisconnectReason(const RawAddress& remote_bda,
- tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-void L2CA_AdjustConnectionIntervals(uint16_t* min_interval,
- uint16_t* max_interval,
- uint16_t floor_interval) {
- mock_function_count_map[__func__]++;
-}
-void L2CA_SetLeFixedChannelTxDataLength(const RawAddress& remote_bda,
- uint16_t fix_cid, uint16_t tx_mtu) {
- mock_function_count_map[__func__]++;
-}
-void l2c_ble_link_adjust_allocation(void) {
- mock_function_count_map[__func__]++;
-}
-void l2c_link_processs_ble_num_bufs(uint16_t num_lm_ble_bufs) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_credit_based_conn_req(tL2C_CCB* p_ccb) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_credit_based_conn_res(tL2C_CCB* p_ccb, uint16_t result) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_notify_le_connection(const RawAddress& bda) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_process_conn_update_evt(uint16_t handle, uint8_t status,
- uint16_t interval, uint16_t latency,
- uint16_t timeout) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_process_data_length_change_event(uint16_t handle,
- uint16_t tx_data_len,
- uint16_t rx_data_len) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_sec_comp(const RawAddress* bda, tBT_TRANSPORT transport,
- void* p_ref_data, uint8_t status) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_send_flow_control_credit(tL2C_CCB* p_ccb, uint16_t credit_value) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_send_peer_disc_req(tL2C_CCB* p_ccb) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_set_fixed_channel_tx_data_length(const RawAddress& remote_bda,
- uint16_t fix_cid,
- uint16_t tx_mtu) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_update_data_length(tL2C_LCB* p_lcb) {
- mock_function_count_map[__func__]++;
-}
-void l2cble_use_preferred_conn_params(const RawAddress& bda) {
- mock_function_count_map[__func__]++;
-}
diff --git a/stack/test/common/mock_l2cap_l2c_main.cc b/stack/test/common/mock_l2cap_l2c_main.cc
deleted file mode 100644
index 6b11dcb..0000000
--- a/stack/test/common/mock_l2cap_l2c_main.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:9
- */
-
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-#include <string.h>
-#include "bt_common.h"
-#include "bt_target.h"
-#include "hci/include/btsnoop.h"
-#include "hcimsgs.h"
-#include "main/shim/shim.h"
-#include "osi/include/log.h"
-#include "osi/include/osi.h"
-#include "stack/include/l2c_api.h"
-#include "stack/include/l2cdefs.h"
-#include "stack/l2cap/l2c_int.h"
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-uint8_t l2c_data_write(uint16_t cid, BT_HDR* p_data, uint16_t flags) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-void l2c_ccb_timer_timeout(void* data) { mock_function_count_map[__func__]++; }
-void l2c_fcrb_ack_timer_timeout(void* data) {
- mock_function_count_map[__func__]++;
-}
-void l2c_free(void) { mock_function_count_map[__func__]++; }
-void l2c_init(void) { mock_function_count_map[__func__]++; }
-void l2c_lcb_timer_timeout(void* data) { mock_function_count_map[__func__]++; }
-void l2c_process_held_packets(bool timed_out) {
- mock_function_count_map[__func__]++;
-}
-void l2c_rcv_acl_data(BT_HDR* p_msg) { mock_function_count_map[__func__]++; }
-void l2c_receive_hold_timer_timeout(UNUSED_ATTR void* data) {
- mock_function_count_map[__func__]++;
-}
diff --git a/stack/test/common/mock_smp_smp_api.cc b/stack/test/common/mock_smp_smp_api.cc
index ad0b68f..1fd8fe6 100644
--- a/stack/test/common/mock_smp_smp_api.cc
+++ b/stack/test/common/mock_smp_smp_api.cc
@@ -78,3 +78,11 @@
void SMP_SecurityGrant(const RawAddress& bd_addr, tSMP_STATUS res) {
mock_function_count_map[__func__]++;
}
+
+void SMP_CrLocScOobData(
+ base::OnceCallback<void(tBT_TRANSPORT, bool,
+ const std::array<unsigned char, 16>&,
+ const std::array<unsigned char, 16>&)>
+ callback) {
+ mock_function_count_map[__func__]++;
+}
diff --git a/stack/test/common/mock_stack_avdt_msg.cc b/stack/test/common/mock_stack_avdt_msg.cc
new file mode 100644
index 0000000..a4eebf6
--- /dev/null
+++ b/stack/test/common/mock_stack_avdt_msg.cc
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <map>
+#include <string>
+#include <vector>
+#include "stack/avdt/avdt_int.h"
+
+extern std::map<std::string, int> mock_function_count_map;
+
+/*
+ * TODO: This way of mocking is primitive.
+ * Need to consider more sophisticated existing methods.
+ */
+
+static std::vector<uint8_t> _rsp_sig_ids{};
+
+void avdt_msg_send_rsp(AvdtpCcb* p_ccb, uint8_t sig_id, tAVDT_MSG* p_params) {
+ mock_function_count_map[__func__]++;
+ _rsp_sig_ids.push_back(sig_id);
+}
+
+size_t mock_avdt_msg_send_rsp_get_count(void) {
+ return _rsp_sig_ids.size();
+}
+
+void mock_avdt_msg_send_rsp_clear_history(void) {
+ _rsp_sig_ids.clear();
+}
+
+uint8_t mock_avdt_msg_send_rsp_get_sig_id_at(size_t nth) {
+ return _rsp_sig_ids[nth];
+}
+
+void avdt_msg_ind(AvdtpCcb* p_ccb, BT_HDR* p_buf) {
+ mock_function_count_map[__func__]++;
+}
+
+void avdt_msg_send_rej(AvdtpCcb* p_ccb, uint8_t sig_id, tAVDT_MSG* p_params) {
+ mock_function_count_map[__func__]++;
+}
+
+static std::vector<uint8_t> _cmd_sig_ids{};
+
+void avdt_msg_send_cmd(AvdtpCcb* p_ccb, void* p_scb, uint8_t sig_id,
+ tAVDT_MSG* p_params) {
+ mock_function_count_map[__func__]++;
+ _cmd_sig_ids.push_back(sig_id);
+}
+
+size_t mock_avdt_msg_send_cmd_get_count(void) {
+ return _cmd_sig_ids.size();
+}
+
+void mock_avdt_msg_send_cmd_clear_history(void) {
+ _cmd_sig_ids.clear();
+}
+
+uint8_t mock_avdt_msg_send_cmd_get_sig_id_at(size_t nth) {
+ return _cmd_sig_ids[nth];
+}
+
+bool avdt_msg_send(AvdtpCcb* p_ccb, BT_HDR* p_msg) {
+ mock_function_count_map[__func__]++;
+ return true;
+}
+
+const uint8_t avdt_msg_rej_2_evt[AVDT_CCB_NUM_ACTIONS] = { };
\ No newline at end of file
diff --git a/stack/test/common/mock_stack_avdt_msg.h b/stack/test/common/mock_stack_avdt_msg.h
new file mode 100644
index 0000000..038ee79
--- /dev/null
+++ b/stack/test/common/mock_stack_avdt_msg.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+/**
+ * Get how many responses sent
+ *
+ * @return the count of responses.
+ */
+size_t mock_avdt_msg_send_rsp_get_count(void);
+
+/**
+ * Clear all the history of the sent responses.
+ */
+void mock_avdt_msg_send_rsp_clear_history(void);
+
+/**
+ * Get the nth (zero based) response's sig id
+ *
+ * @param nth response recorded since last time clear history
+ * @return the sig id of the response
+ *
+ * @note undefined behavior if nth >= total count
+ */
+uint8_t mock_avdt_msg_send_rsp_get_sig_id_at(size_t nth);
+
+/**
+ * Get how many commands sent
+ *
+ * @return the count of commands.
+ */
+size_t mock_avdt_msg_send_cmd_get_count(void);
+
+/**
+ * Clear all the history of the sent commands.
+ */
+void mock_avdt_msg_send_cmd_clear_history(void);
+
+/**
+ * Get the nth (zero based) commands's sig id
+ *
+ * @param nth command recorded since last time clear history
+ * @return the sig id of the command
+ *
+ * @note undefined behavior if nth >= total count
+ */
+uint8_t mock_avdt_msg_send_cmd_get_sig_id_at(size_t nth);
\ No newline at end of file
diff --git a/stack/test/common/mock_l2cap_l2c_link.cc b/stack/test/common/mock_stack_l2cap_link.cc
similarity index 100%
rename from stack/test/common/mock_l2cap_l2c_link.cc
rename to stack/test/common/mock_stack_l2cap_link.cc
diff --git a/stack/test/eatt/eatt_test.cc b/stack/test/eatt/eatt_test.cc
index 8e93227..51a85fd 100644
--- a/stack/test/eatt/eatt_test.cc
+++ b/stack/test/eatt/eatt_test.cc
@@ -20,7 +20,7 @@
#include <vector>
-#include "base/bind_helpers.h"
+#include "bind_helpers.h"
#include "btm_api.h"
#include "l2c_api.h"
#include "mock_btif_storage.h"
@@ -43,6 +43,8 @@
using bluetooth::eatt::EattChannel;
using bluetooth::eatt::EattChannelState;
+#define BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK 0x01
+
/* Needed for testing context */
static tGATT_TCB test_tcb;
void btif_storage_add_eatt_supported(const RawAddress& addr) { return; }
@@ -59,13 +61,15 @@
class EattTest : public testing::Test {
protected:
void ConnectDeviceEattSupported(int num_of_accepted_connections) {
- ON_CALL(gatt_interface_, GetEattSupport)
+ ON_CALL(gatt_interface_, ClientReadSupportedFeatures)
.WillByDefault(
[](const RawAddress& addr,
- base::OnceCallback<void(const RawAddress&, bool)> cb) {
- std::move(cb).Run(addr, true);
+ base::OnceCallback<void(const RawAddress&, uint8_t)> cb) {
+ std::move(cb).Run(addr, BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK);
return true;
});
+ ON_CALL(gatt_interface_, GetEattSupport)
+ .WillByDefault([](const RawAddress& addr) { return true; });
std::vector<uint16_t> test_local_cids{61, 62, 63, 64, 65};
EXPECT_CALL(l2cap_interface_,
@@ -182,12 +186,15 @@
}
TEST_F(EattTest, ConnectFailedEattNotSupported) {
+ ON_CALL(gatt_interface_, ClientReadSupportedFeatures)
+ .WillByDefault(
+ [](const RawAddress& addr,
+ base::OnceCallback<void(const RawAddress&, uint8_t)> cb) {
+ std::move(cb).Run(addr, 0);
+ return true;
+ });
ON_CALL(gatt_interface_, GetEattSupport)
- .WillByDefault([](const RawAddress& addr,
- base::OnceCallback<void(const RawAddress&, bool)> cb) {
- std::move(cb).Run(addr, false);
- return true;
- });
+ .WillByDefault([](const RawAddress& addr) { return false; });
EXPECT_CALL(l2cap_interface_,
ConnectCreditBasedReq(BT_PSM_EATT, test_address, _))
@@ -370,4 +377,12 @@
DisconnectEattDevice();
}
+
+TEST_F(EattTest, DoubleDisconnect) {
+ ConnectDeviceEattSupported(1);
+ DisconnectEattDevice();
+
+ /* Force second disconnect */
+ eatt_instance_->Disconnect(test_address);
+}
} // namespace
diff --git a/stack/test/fuzzers/a2dp/codec/a2dpCodecHelperFunctions.h b/stack/test/fuzzers/a2dp/codec/a2dpCodecHelperFunctions.h
index 5b3848a..dec0e49 100644
--- a/stack/test/fuzzers/a2dp/codec/a2dpCodecHelperFunctions.h
+++ b/stack/test/fuzzers/a2dp/codec/a2dpCodecHelperFunctions.h
@@ -20,7 +20,6 @@
#include <fuzzer/FuzzedDataProvider.h>
#include <vector>
-// =============================================================================
static const std::vector<const btav_a2dp_codec_index_t> CODEC_INDEX_ENUM_VALS =
{BTAV_A2DP_CODEC_INDEX_SOURCE_MIN,
BTAV_A2DP_CODEC_INDEX_SOURCE_SBC,
@@ -107,7 +106,7 @@
return config;
}
-// =============================================================================
+
tA2DP_ENCODER_INIT_PEER_PARAMS getArbitraryA2dpEncoderInitPeerParams(
FuzzedDataProvider* fdp) {
tA2DP_ENCODER_INIT_PEER_PARAMS params;
@@ -118,7 +117,7 @@
return params;
}
-// =============================================================================
+
#include "bt_types.h"
#define MAX_BTHDR_SIZE 1024
std::shared_ptr<BT_HDR> getArbitraryBtHdr(FuzzedDataProvider* fdp) {
@@ -143,7 +142,7 @@
return bt_hdr;
}
-// =============================================================================
+
#include "bta/av/bta_av_int.h"
tBT_A2DP_OFFLOAD generateArbitrarytA2dpOffload(FuzzedDataProvider* fdp) {
tBT_A2DP_OFFLOAD retval;
@@ -166,6 +165,5 @@
return retval;
}
-// =============================================================================
#endif // A2DP_CODEC_HELPERFUNCTIONS_H_
diff --git a/stack/test/fuzzers/sdp/sdpFuzzHelpers.h b/stack/test/fuzzers/sdp/sdpFuzzHelpers.h
index 1d823ca..bae1785 100644
--- a/stack/test/fuzzers/sdp/sdpFuzzHelpers.h
+++ b/stack/test/fuzzers/sdp/sdpFuzzHelpers.h
@@ -267,7 +267,7 @@
}
// Define our callback functions we'll be using within our functions
-void sdp_disc_cmpl_cb(uint16_t result) {}
-void sdp_disc_cmpl_cb2(uint16_t result, void* user_data) {}
+void sdp_disc_cmpl_cb(tSDP_STATUS result) {}
+void sdp_disc_cmpl_cb2(tSDP_STATUS result, void* user_data) {}
#endif // FUZZER_SDP_HELPERS_H_
diff --git a/stack/test/gatt/stack_gatt_test.cc b/stack/test/gatt/stack_gatt_test.cc
new file mode 100644
index 0000000..4c58ea8
--- /dev/null
+++ b/stack/test/gatt/stack_gatt_test.cc
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.h>
+
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <string>
+
+#include "common/message_loop_thread.h"
+#include "common/strings.h"
+#include "stack/gatt/gatt_int.h"
+#include "stack/include/gatt_api.h"
+
+std::map<std::string, int> mock_function_count_map;
+
+void LogMsg(uint32_t trace_set_mask, const char* fmt_str, ...) {}
+
+bluetooth::common::MessageLoopThread* get_main_thread() { return nullptr; }
+
+class StackGattTest : public ::testing::Test {};
+
+namespace {
+
+// Actual size of structure without compiler padding
+size_t actual_sizeof_tGATT_REG() {
+ return sizeof(bluetooth::Uuid) + sizeof(tGATT_CBACK) + sizeof(tGATT_IF) +
+ sizeof(bool) + sizeof(uint8_t) + sizeof(bool);
+}
+
+void tGATT_DISC_RES_CB(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
+ tGATT_DISC_RES* p_data) {}
+void tGATT_DISC_CMPL_CB(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
+ tGATT_STATUS status) {}
+void tGATT_CMPL_CBACK(uint16_t conn_id, tGATTC_OPTYPE op, tGATT_STATUS status,
+ tGATT_CL_COMPLETE* p_data) {}
+void tGATT_CONN_CBACK(tGATT_IF gatt_if, const RawAddress& bda, uint16_t conn_id,
+ bool connected, tGATT_DISCONN_REASON reason,
+ tBT_TRANSPORT transport) {}
+void tGATT_REQ_CBACK(uint16_t conn_id, uint32_t trans_id, tGATTS_REQ_TYPE type,
+ tGATTS_DATA* p_data) {}
+void tGATT_CONGESTION_CBACK(uint16_t conn_id, bool congested) {}
+void tGATT_ENC_CMPL_CB(tGATT_IF gatt_if, const RawAddress& bda) {}
+void tGATT_PHY_UPDATE_CB(tGATT_IF gatt_if, uint16_t conn_id, uint8_t tx_phy,
+ uint8_t rx_phy, tGATT_STATUS status) {}
+void tGATT_CONN_UPDATE_CB(tGATT_IF gatt_if, uint16_t conn_id, uint16_t interval,
+ uint16_t latency, uint16_t timeout,
+ tGATT_STATUS status) {}
+
+tGATT_CBACK gatt_callbacks = {
+ .p_conn_cb = tGATT_CONN_CBACK,
+ .p_cmpl_cb = tGATT_CMPL_CBACK,
+ .p_disc_res_cb = tGATT_DISC_RES_CB,
+ .p_disc_cmpl_cb = tGATT_DISC_CMPL_CB,
+ .p_req_cb = tGATT_REQ_CBACK,
+ .p_enc_cmpl_cb = tGATT_ENC_CMPL_CB,
+ .p_congestion_cb = tGATT_CONGESTION_CBACK,
+ .p_phy_update_cb = tGATT_PHY_UPDATE_CB,
+ .p_conn_update_cb = tGATT_CONN_UPDATE_CB,
+};
+
+} // namespace
+
+TEST_F(StackGattTest, lifecycle_tGATT_REG) {
+ {
+ std::unique_ptr<tGATT_REG> reg0 = std::make_unique<tGATT_REG>();
+ std::unique_ptr<tGATT_REG> reg1 = std::make_unique<tGATT_REG>();
+ memset(reg0.get(), 0xff, sizeof(tGATT_REG));
+ memset(reg1.get(), 0xff, sizeof(tGATT_REG));
+ ASSERT_EQ(0, memcmp(reg0.get(), reg1.get(), sizeof(tGATT_REG)));
+
+ memset(reg0.get(), 0x0, sizeof(tGATT_REG));
+ memset(reg1.get(), 0x0, sizeof(tGATT_REG));
+ ASSERT_EQ(0, memcmp(reg0.get(), reg1.get(), sizeof(tGATT_REG)));
+ }
+
+ {
+ std::unique_ptr<tGATT_REG> reg0 = std::make_unique<tGATT_REG>();
+ memset(reg0.get(), 0xff, sizeof(tGATT_REG));
+
+ tGATT_REG reg1;
+ memset(®1, 0xff, sizeof(tGATT_REG));
+
+ // Clear the structures
+ memset(reg0.get(), 0, sizeof(tGATT_REG));
+ // Restore the complex structure after memset
+ memset(®1.name, 0, sizeof(std::string));
+ reg1 = {};
+ ASSERT_EQ(0, memcmp(reg0.get(), ®1, actual_sizeof_tGATT_REG()));
+ }
+
+ {
+ tGATT_REG* reg0 = new tGATT_REG();
+ tGATT_REG* reg1 = new tGATT_REG();
+ memset(reg0, 0, sizeof(tGATT_REG));
+ *reg1 = {};
+ reg0->in_use = true;
+ ASSERT_NE(0, memcmp(reg0, reg1, sizeof(tGATT_REG)));
+ delete reg1;
+ delete reg0;
+ }
+}
+
+TEST_F(StackGattTest, gatt_init_free) {
+ gatt_init();
+ gatt_free();
+}
+
+TEST_F(StackGattTest, GATT_Register_Deregister) {
+ gatt_init();
+
+ // Gatt db profile always takes the first slot
+ tGATT_IF apps[GATT_MAX_APPS - 1];
+
+ for (int i = 0; i < GATT_MAX_APPS - 1; i++) {
+ std::string name = bluetooth::common::StringFormat("name%02d", i);
+ apps[i] = GATT_Register(bluetooth::Uuid::GetRandom(), name, &gatt_callbacks,
+ false);
+ }
+
+ for (int i = 0; i < GATT_MAX_APPS - 1; i++) {
+ GATT_Deregister(apps[i]);
+ }
+
+ gatt_free();
+}
diff --git a/stack/test/hci/stack_hci_test.cc b/stack/test/hci/stack_hci_test.cc
new file mode 100644
index 0000000..8ef98a3
--- /dev/null
+++ b/stack/test/hci/stack_hci_test.cc
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <cstring>
+#include <map>
+
+#include "osi/include/log.h"
+#include "stack/include/hcidefs.h"
+#include "stack/include/l2cdefs.h"
+#include "test/mock/mock_hcic_hcicmds.h"
+
+std::map<std::string, int> mock_function_count_map;
+
+namespace mock = test::mock::hcic_hcicmds;
+
+namespace {
+
+using testing::_;
+using testing::DoAll;
+using testing::NotNull;
+using testing::Pointee;
+using testing::Return;
+using testing::SaveArg;
+using testing::SaveArgPointee;
+using testing::StrEq;
+using testing::StrictMock;
+using testing::Test;
+
+class StackHciTest : public Test {
+ public:
+ protected:
+ void SetUp() override { mock_function_count_map.clear(); }
+ void TearDown() override {}
+};
+
+TEST_F(StackHciTest, hci_preamble) {
+ {
+ HciDataPreamble preamble;
+
+ ASSERT_EQ(sizeof(preamble), HCI_DATA_PREAMBLE_SIZE);
+
+ preamble.bits.handle = 0xfff;
+ preamble.bits.boundary = 0x3;
+ preamble.bits.broadcast = 0x1;
+ preamble.bits.unused15 = 0x0;
+ preamble.bits.length = 0xffff;
+
+ ASSERT_EQ(0x7fff, preamble.raw.word0);
+ ASSERT_EQ(0xffff, preamble.raw.word1);
+
+ const uint8_t exp[] = {0xff, 0x7f, 0xff, 0xff};
+ uint8_t act[sizeof(preamble)];
+ preamble.Serialize(act);
+ ASSERT_EQ(0, std::memcmp(exp, act, sizeof(preamble)));
+ }
+
+ {
+ HciDataPreamble preamble;
+ preamble.raw.word0 =
+ 0x123 | (L2CAP_PKT_START_NON_FLUSHABLE << L2CAP_PKT_TYPE_SHIFT);
+ preamble.raw.word1 = 0x4567;
+
+ ASSERT_EQ(sizeof(preamble), HCI_DATA_PREAMBLE_SIZE);
+
+ ASSERT_EQ(0x0123, preamble.raw.word0);
+ ASSERT_EQ(0x4567, preamble.raw.word1);
+
+ const uint8_t exp[] = {0x23, 0x01, 0x67, 0x45};
+ uint8_t act[sizeof(preamble)];
+ preamble.Serialize(act);
+ ASSERT_EQ(0, std::memcmp(exp, act, sizeof(preamble)));
+ }
+ {
+ HciDataPreamble preamble;
+ preamble.raw.word0 = 0x123 | (L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT);
+ preamble.raw.word1 = 0x4567;
+
+ ASSERT_EQ(sizeof(preamble), HCI_DATA_PREAMBLE_SIZE);
+
+ ASSERT_EQ(0x2123, preamble.raw.word0);
+ ASSERT_EQ(0x4567, preamble.raw.word1);
+
+ const uint8_t exp[] = {0x23, 0x21, 0x67, 0x45};
+ uint8_t act[sizeof(preamble)];
+ preamble.Serialize(act);
+ ASSERT_EQ(0, std::memcmp(exp, act, sizeof(preamble)));
+ }
+
+ {
+ HciDataPreamble preamble;
+ preamble.raw.word0 = 0x0 | (L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT);
+ preamble.raw.word1 = 0x0;
+
+ ASSERT_EQ(sizeof(preamble), HCI_DATA_PREAMBLE_SIZE);
+
+ ASSERT_EQ(0x2000, preamble.raw.word0);
+ ASSERT_EQ(0x0000, preamble.raw.word1);
+
+ const uint8_t exp[] = {0x00, 0x20, 0x00, 0x00};
+ uint8_t act[sizeof(preamble)];
+ preamble.Serialize(act);
+ ASSERT_EQ(0, std::memcmp(exp, act, sizeof(preamble)));
+ }
+
+ {
+ HciDataPreamble preamble;
+ preamble.raw.word0 = 0x0 | (L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT);
+ preamble.raw.word1 = 0x0;
+
+ ASSERT_TRUE(preamble.IsFlushable());
+
+ preamble.raw.word0 =
+ 0x0 | (L2CAP_PKT_START << L2CAP_PKT_START_NON_FLUSHABLE);
+ ASSERT_TRUE(!preamble.IsFlushable());
+ }
+}
+
+} // namespace
diff --git a/stack/test/hid/stack_hid_test.cc b/stack/test/hid/stack_hid_test.cc
new file mode 100644
index 0000000..3a955d3
--- /dev/null
+++ b/stack/test/hid/stack_hid_test.cc
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <cstring>
+#include <map>
+
+#include "common/message_loop_thread.h"
+#include "osi/include/log.h"
+#include "stack/hid/hidh_int.h"
+#include "stack/include/hci_error_code.h"
+#include "test/mock/mock_stack_l2cap_api.h"
+#include "types/bt_transport.h"
+#include "types/raw_address.h"
+
+std::map<std::string, int> mock_function_count_map;
+
+bluetooth::common::MessageLoopThread* get_main_thread() { return nullptr; }
+tHCI_REASON btm_get_acl_disc_reason_code(void) { return HCI_SUCCESS; }
+
+bool BTM_IsAclConnectionUp(const RawAddress& remote_bda,
+ tBT_TRANSPORT transport) {
+ return true;
+}
+namespace {
+
+using testing::_;
+using testing::DoAll;
+using testing::NotNull;
+using testing::Pointee;
+using testing::Return;
+using testing::SaveArg;
+using testing::SaveArgPointee;
+using testing::StrEq;
+using testing::StrictMock;
+using testing::Test;
+
+class StackHidTest : public Test {
+ public:
+ protected:
+ void SetUp() override { mock_function_count_map.clear(); }
+ void TearDown() override {}
+};
+
+TEST_F(StackHidTest, disconnect_bad_cid) {
+ tL2CAP_APPL_INFO l2cap_callbacks;
+
+ test::mock::stack_l2cap_api::L2CA_Register2.body =
+ [&l2cap_callbacks](uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info,
+ bool enable_snoop, tL2CAP_ERTM_INFO* p_ertm_info,
+ uint16_t my_mtu, uint16_t required_remote_mtu,
+ uint16_t sec_level) {
+ l2cap_callbacks = p_cb_info;
+ return psm;
+ };
+
+ tHID_STATUS status = hidh_conn_reg();
+ ASSERT_EQ(HID_SUCCESS, status);
+
+ l2cap_callbacks.pL2CA_Error_Cb(123, 456);
+}
+
+} // namespace
diff --git a/stack/test/stack_avdtp_test.cc b/stack/test/stack_avdtp_test.cc
new file mode 100644
index 0000000..e6621be
--- /dev/null
+++ b/stack/test/stack_avdtp_test.cc
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <dlfcn.h>
+#include <gtest/gtest.h>
+
+#include "stack/include/avdt_api.h"
+#include "stack/avdt/avdt_int.h"
+#include "stack/test/common/mock_stack_avdt_msg.h"
+
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+// Global trace level referred in the code under test
+uint8_t appl_trace_level = BT_TRACE_LEVEL_VERBOSE;
+
+void LogMsg(uint32_t trace_set_mask, const char* fmt_str, ...) { }
+
+// All mock requires this symbol to count calling times
+std::map<std::string, int> mock_function_count_map;
+
+class StackAvdtpTest : public ::testing::Test {
+ protected:
+ StackAvdtpTest() = default;
+
+ virtual ~StackAvdtpTest() = default;
+ protected:
+ static AvdtpRcb _reg;
+ static uint8_t _expected_stream_event;
+
+ uint8_t scb_handle_;
+
+ protected:
+ static void _avdtcallback(UNUSED_ATTR uint8_t handle, const RawAddress& bd_addr,
+ uint8_t event, tAVDT_CTRL* p_data, uint8_t scb_index) {
+ mock_function_count_map[__func__]++;
+ }
+
+ static void _streamcallback(uint8_t handle, const RawAddress& bd_addr,
+ uint8_t event, tAVDT_CTRL* p_data,
+ uint8_t scb_index) {
+ mock_function_count_map[__func__]++;
+ ASSERT_EQ(event, _expected_stream_event);
+ };
+
+ static void SetUpTestCase() {
+ _reg.ctrl_mtu = 672;
+ _reg.ret_tout = 4;
+ _reg.sig_tout = 4;
+ _reg.idle_tout = 10;
+ _reg.scb_index = 0;
+ AVDT_Register(&_reg, _avdtcallback);
+ }
+
+ static void TearDownTestCase() {
+ AVDT_Deregister();
+ }
+
+ void SetUp() override {
+ uint8_t peer_id = 1;
+ scb_handle_ = 0;
+ _expected_stream_event = 0;
+ AvdtpStreamConfig avdtp_stream_config;
+ avdtp_stream_config.cfg.psc_mask = AVDT_PSC_DELAY_RPT;
+ avdtp_stream_config.tsep = AVDT_TSEP_SNK;
+ avdtp_stream_config.p_avdt_ctrl_cback = _streamcallback;
+ mock_function_count_map["_streamcallback"] = 0;
+
+ ASSERT_EQ(AVDT_CreateStream(peer_id, &scb_handle_, avdtp_stream_config), AVDT_SUCCESS);
+ }
+
+ void TearDown() override {
+ ASSERT_EQ(AVDT_RemoveStream(scb_handle_), AVDT_SUCCESS);
+ }
+
+ void StreamCallBackExpect(uint8_t event) {
+ _expected_stream_event = event;
+ }
+};
+
+AvdtpRcb StackAvdtpTest::_reg{};
+uint8_t StackAvdtpTest::_expected_stream_event = 0;
+
+TEST_F(StackAvdtpTest, test_delay_report_as_accept) {
+ // Get SCB ready to send response
+ auto pscb = avdt_scb_by_hdl(scb_handle_);
+ pscb->in_use = true;
+
+ // Send SetConfig response
+ uint8_t label = 0;
+ uint8_t err_code = 0;
+ uint8_t category = 0;
+
+ mock_avdt_msg_send_cmd_clear_history();
+ mock_avdt_msg_send_rsp_clear_history();
+ mock_function_count_map["avdt_msg_send_rsp"] = 0;
+ mock_function_count_map["avdt_msg_send_cmd"] = 0;
+ ASSERT_EQ(AVDT_ConfigRsp(scb_handle_, label, err_code, category), AVDT_SUCCESS);
+
+ // Config response sent
+ ASSERT_EQ(mock_function_count_map["avdt_msg_send_rsp"], 1);
+ ASSERT_EQ(mock_avdt_msg_send_rsp_get_sig_id_at(0), AVDT_SIG_SETCONFIG);
+
+ // Delay report command sent
+ ASSERT_EQ(mock_function_count_map["avdt_msg_send_cmd"], 1);
+ ASSERT_EQ(mock_avdt_msg_send_cmd_get_sig_id_at(0), AVDT_SIG_DELAY_RPT);
+
+ // Delay report confirmed
+ tAVDT_SCB_EVT data;
+ ASSERT_EQ(mock_function_count_map["_streamcallback"], 0);
+ StreamCallBackExpect(AVDT_DELAY_REPORT_CFM_EVT);
+ avdt_scb_hdl_delay_rpt_rsp(pscb, &data);
+ ASSERT_EQ(mock_function_count_map["_streamcallback"], 1);
+}
+
+TEST_F(StackAvdtpTest, test_no_delay_report_if_not_sink) {
+ // Get SCB ready to send response
+ auto pscb = avdt_scb_by_hdl(scb_handle_);
+ pscb->in_use = true;
+
+ // Change the scb to SRC
+ pscb->stream_config.tsep = AVDT_TSEP_SRC;
+
+ // Send SetConfig response
+ uint8_t label = 0;
+ uint8_t err_code = 0;
+ uint8_t category = 0;
+ mock_function_count_map["avdt_msg_send_rsp"] = 0;
+ mock_function_count_map["avdt_msg_send_cmd"] = 0;
+ ASSERT_EQ(AVDT_ConfigRsp(scb_handle_, label, err_code, category), AVDT_SUCCESS);
+ ASSERT_EQ(mock_function_count_map["avdt_msg_send_rsp"], 1); // Config response sent
+ ASSERT_EQ(mock_function_count_map["avdt_msg_send_cmd"], 0); // Delay report command not sent
+}
+
+TEST_F(StackAvdtpTest, test_no_delay_report_if_not_enabled) {
+ // Get SCB ready to send response
+ auto pscb = avdt_scb_by_hdl(scb_handle_);
+ pscb->in_use = true;
+
+ // Disable the scb's delay report mask
+ pscb->stream_config.cfg.psc_mask &= ~AVDT_PSC_DELAY_RPT;
+
+ // Send SetConfig response
+ uint8_t label = 0;
+ uint8_t err_code = 0;
+ uint8_t category = 0;
+ mock_function_count_map["avdt_msg_send_rsp"] = 0;
+ mock_function_count_map["avdt_msg_send_cmd"] = 0;
+ ASSERT_EQ(AVDT_ConfigRsp(scb_handle_, label, err_code, category), AVDT_SUCCESS);
+ ASSERT_EQ(mock_function_count_map["avdt_msg_send_rsp"], 1); // Config response sent
+ ASSERT_EQ(mock_function_count_map["avdt_msg_send_cmd"], 0); // Delay report command not sent
+}
+
+TEST_F(StackAvdtpTest, test_delay_report_as_init) {
+ auto pscb = avdt_scb_by_hdl(scb_handle_);
+
+ tAVDT_SCB_EVT data;
+
+ mock_function_count_map["avdt_msg_send_cmd"] = 0;
+
+ // Delay report -> Open command
+ mock_avdt_msg_send_cmd_clear_history();
+ avdt_scb_event(pscb, AVDT_SCB_MSG_SETCONFIG_RSP_EVT, &data);
+ ASSERT_EQ(mock_function_count_map["avdt_msg_send_cmd"], 2);
+ ASSERT_EQ(mock_avdt_msg_send_cmd_get_sig_id_at(0), AVDT_SIG_DELAY_RPT);
+ ASSERT_EQ(mock_avdt_msg_send_cmd_get_sig_id_at(1), AVDT_SIG_OPEN);
+}
+
diff --git a/bta/test/common/mock_stack_gatt_connection_manager.cc b/stack/test/stack_btu_test.cc
similarity index 63%
copy from bta/test/common/mock_stack_gatt_connection_manager.cc
copy to stack/test/stack_btu_test.cc
index 1c4887c..86011d0 100644
--- a/bta/test/common/mock_stack_gatt_connection_manager.cc
+++ b/stack/test/stack_btu_test.cc
@@ -14,24 +14,17 @@
* limitations under the License.
*/
-/*
- * Generated mock file from original source file
- * Functions generated:4
- */
-
+#include <gtest/gtest.h>
+#include <cstdint>
#include <map>
#include <string>
-extern std::map<std::string, int> mock_function_count_map;
+#include "stack/include/btu.h"
-#include "stack/gatt/connection_manager.h"
+std::map<std::string, int> mock_function_count_map;
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
+void LogMsg(uint32_t trace_set_mask, const char* fmt_str, ...) {}
-namespace connection_manager {
+class StackBtuTest : public ::testing::Test {};
-void reset(bool after_reset) { mock_function_count_map[__func__]++; }
-
-} // namespace connection_manager
+TEST_F(StackBtuTest, post_on_main) {}
diff --git a/test/Android.bp b/test/Android.bp
index f5125c9..269e517 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -34,6 +34,20 @@
}
filegroup {
+ name: "TestMockStackA2dp",
+ srcs: [
+ "mock/mock_stack_a2dp_*.cc",
+ ],
+}
+
+filegroup {
+ name: "TestMockStackL2cap",
+ srcs: [
+ "mock/mock_stack_l2cap_*.cc",
+ ],
+}
+
+filegroup {
name: "TestMockStack",
srcs: [
"mock/mock_stack_*.cc",
@@ -81,3 +95,143 @@
"mock/mock_android_hardware_*.cc",
],
}
+
+filegroup {
+ name: "TestMockDevice",
+ srcs: [
+ "mock/mock_device_*.cc",
+ ],
+}
+
+filegroup {
+ name: "TestMockLegacyHciCommands",
+ srcs: [
+ "mock/mock_hcic_*.cc",
+ ],
+}
+
+filegroup {
+ name: "TestMockMainShimEntry",
+ srcs: [
+ "mock/mock_main_shim_entry.cc",
+ ],
+}
+
+filegroup {
+ name: "TestMockMainShimFlags",
+ srcs: [
+ "mock/mock_main_shim.cc",
+ ],
+}
+
+filegroup {
+ name: "TestMockBtif",
+ srcs: [
+ "mock/mock_btif*.cc",
+ ],
+}
+
+filegroup {
+ name: "TestStackL2cap",
+ srcs: [
+ "mock/mock_stack_l2cap_*.cc",
+ ],
+}
+
+filegroup {
+ name: "TestStackSdp",
+ srcs: [
+ "mock/mock_stack_sdp*.cc",
+ ],
+}
+
+filegroup {
+ name: "TestStackBtm",
+ srcs: [
+ "mock/mock_stack_btm*.cc",
+ ],
+}
+
+filegroup {
+ name: "TestStubLegacyTrace",
+ srcs: [
+ "stub/legacy_trace.cc",
+ ],
+}
+
+filegroup {
+ name: "TestStubOsi",
+ srcs: [
+ "stub/osi.cc",
+ ],
+}
+
+filegroup {
+ name: "TestMockStackAcl",
+ srcs: [
+ "mock/mock_stack_acl*.cc",
+ ],
+}
+
+filegroup {
+ name: "TestMockStackSmp",
+ srcs: [
+ "mock/mock_stack_smp*.cc",
+ ],
+}
+
+filegroup {
+ name: "TestMockStackMetrics",
+ srcs: [
+ "mock/mock_stack_metrics*.cc",
+ ],
+}
+
+filegroup {
+ name: "TestMockStackGap",
+ srcs: [
+ "mock/mock_stack_gap*.cc",
+ ],
+}
+
+filegroup {
+ name: "TestMockStackGatt",
+ srcs: [
+ "mock/mock_stack_gatt*.cc",
+ ],
+}
+
+filegroup {
+ name: "TestMockStackBtu",
+ srcs: [
+ "mock/mock_stack_btu*.cc",
+ ],
+}
+
+filegroup {
+ name: "TestMockMainBte",
+ srcs: [
+ "mock/mock_main_bte*.cc",
+ ],
+}
+
+filegroup {
+ name: "TestMockStackCryptotoolbox",
+ srcs: [
+ "mock/mock_stack_crypto_toolbox*.cc",
+ ],
+}
+
+filegroup {
+ name: "TestMockBtu",
+ srcs: [
+ "mock/mock_btu_*cc",
+ ],
+}
+
+filegroup {
+ name: "TestCommonMainHandler",
+ srcs: [
+ "common/main_handler.cc",
+ ],
+}
diff --git a/test/common/main_handler.cc b/test/common/main_handler.cc
new file mode 100644
index 0000000..45cf879
--- /dev/null
+++ b/test/common/main_handler.cc
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/callback_forward.h>
+#include <base/location.h>
+#include <base/time/time.h>
+#include <functional>
+#include <future>
+
+#include "common/message_loop_thread.h"
+#include "include/hardware/bluetooth.h"
+#include "osi/include/log.h"
+
+using bluetooth::common::MessageLoopThread;
+using BtMainClosure = std::function<void()>;
+
+namespace {
+
+MessageLoopThread main_thread("bt_test_main_thread", true);
+void do_post_on_bt_main(BtMainClosure closure) { closure(); }
+
+} // namespace
+
+bt_status_t do_in_main_thread(const base::Location& from_here,
+ base::OnceClosure task) {
+ ASSERT_LOG(main_thread.DoInThread(from_here, std::move(task)),
+ "Unable to run on main thread");
+ return BT_STATUS_SUCCESS;
+}
+
+bt_status_t do_in_main_thread_delayed(const base::Location& from_here,
+ base::OnceClosure task,
+ const base::TimeDelta& delay) {
+ ASSERT_LOG(!main_thread.DoInThreadDelayed(from_here, std::move(task), delay),
+ "Unable to run on main thread delayed");
+ return BT_STATUS_SUCCESS;
+}
+
+void post_on_bt_main(BtMainClosure closure) {
+ ASSERT(do_in_main_thread(
+ FROM_HERE, base::Bind(do_post_on_bt_main, std::move(closure))) ==
+ BT_STATUS_SUCCESS);
+}
+
+void main_thread_start_up() {
+ main_thread.StartUp();
+ ASSERT_LOG(main_thread.IsRunning(),
+ "Unable to start message loop on main thread");
+}
+
+void main_thread_shut_down() { main_thread.ShutDown(); }
+
+// osi_alarm
+bluetooth::common::MessageLoopThread* get_main_thread() { return &main_thread; }
+
+int sync_timeout_in_ms = 3000;
+
+void sync_main_handler() {
+ std::promise promise = std::promise<void>();
+ std::future future = promise.get_future();
+ post_on_bt_main([&promise]() { promise.set_value(); });
+ future.wait_for(std::chrono::milliseconds(sync_timeout_in_ms));
+};
diff --git a/test/common/main_handler.h b/test/common/main_handler.h
new file mode 100644
index 0000000..c869ddc
--- /dev/null
+++ b/test/common/main_handler.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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/callback_forward.h>
+#include <base/location.h>
+#include <base/time/time.h>
+#include <functional>
+
+#include "common/message_loop_thread.h"
+
+using bluetooth::common::MessageLoopThread;
+using BtMainClosure = std::function<void()>;
+
+bt_status_t do_in_main_thread(const base::Location& from_here,
+ base::OnceClosure task);
+bt_status_t do_in_main_thread_delayed(const base::Location& from_here,
+ base::OnceClosure task,
+ const base::TimeDelta& delay);
+void post_on_bt_main(BtMainClosure closure);
+void main_thread_start_up();
+void main_thread_shut_down();
+extern int sync_timeout_in_ms;
+void sync_main_handler();
+bluetooth::common::MessageLoopThread* get_main_thread();
diff --git a/test/headless/Android.bp b/test/headless/Android.bp
index 0ef3f2a..0aff030 100644
--- a/test/headless/Android.bp
+++ b/test/headless/Android.bp
@@ -61,6 +61,7 @@
"android.hardware.bluetooth@1.0",
"android.hardware.bluetooth@1.1",
"android.system.suspend.control-V1-ndk",
+ "android.system.suspend@1.0",
"libaaudio",
"libbase",
"libbinder_ndk",
diff --git a/test/headless/README.md b/test/headless/README.md
new file mode 100644
index 0000000..13b7f92
--- /dev/null
+++ b/test/headless/README.md
@@ -0,0 +1,24 @@
+##
+## bluetooth headless
+##
+## A device-side executable that consists of a binary executable
+## driving the Android libbluetooth libraries.
+##
+
+Requirements:
+ 1. Android installation,
+ 2. Root access to adb connected Android device.
+
+Build: Source, lunch and build as typical Android target for selected device and architecture.
+ cd $ANDROID_BUILD_TOP
+ . build/envsetup.sh && lunch <target>
+ make bt_headless
+
+Install: Push the binary to an executable area on target device.
+ adb push out/target/product/<device..arch>/bt_headless/bt_headless /data/data/.
+
+Prepare: Ensure the system is queisced to prevent resource conflicts from the bluetooth process.
+ adb shell stop
+
+Run: Script or directly execute the target file.
+ adb shell /data/data/bt_headless --flags=INIT_logging_debug_enabled_for_all=true,INIT_gd_acl=true nop
diff --git a/test/headless/headless.cc b/test/headless/headless.cc
index 31a9687..a3b5441 100644
--- a/test/headless/headless.cc
+++ b/test/headless/headless.cc
@@ -189,8 +189,14 @@
void HeadlessStack::SetUp() {
LOG(INFO) << __func__ << " Entry";
- int status = bluetoothInterface.init(&bt_callbacks, false, false, 0,
- StackInitFlags(), false);
+ const bool start_restricted = false;
+ const bool is_common_criteria_mode = false;
+ const int config_compare_result = 0;
+ const bool is_atv = false;
+ int status = bluetoothInterface.init(
+ &bt_callbacks, start_restricted, is_common_criteria_mode,
+ config_compare_result, StackInitFlags(), is_atv);
+
(status == BT_STATUS_SUCCESS)
? LOG(INFO) << __func__ << " Initialized bluetooth callbacks"
: LOG(FATAL) << "Failed to initialize Bluetooth stack";
diff --git a/test/headless/headless.h b/test/headless/headless.h
index dd2507e..1931b70 100644
--- a/test/headless/headless.h
+++ b/test/headless/headless.h
@@ -35,12 +35,18 @@
template <typename T>
using ExecutionUnit = std::function<T()>;
+constexpr char kHeadlessInitialSentinel[] =
+ " INITIAL HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS "
+ "HEADLESS";
constexpr char kHeadlessStartSentinel[] =
" START HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS "
"HEADLESS";
constexpr char kHeadlessStopSentinel[] =
" STOP HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS "
"HEADLESS";
+constexpr char kHeadlessFinalSentinel[] =
+ " FINAL HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS "
+ "HEADLESS";
} // namespace
@@ -68,6 +74,7 @@
template <typename T>
T RunOnHeadlessStack(ExecutionUnit<T> func) {
+ LOG(INFO) << kHeadlessInitialSentinel;
SetUp();
LOG(INFO) << kHeadlessStartSentinel;
@@ -91,6 +98,7 @@
LOG(INFO) << kHeadlessStopSentinel;
TearDown();
+ LOG(INFO) << kHeadlessFinalSentinel;
return rc;
}
virtual ~HeadlessRun() = default;
diff --git a/test/headless/sdp/sdp.cc b/test/headless/sdp/sdp.cc
index 9e20340..ea7efe4 100644
--- a/test/headless/sdp/sdp.cc
+++ b/test/headless/sdp/sdp.cc
@@ -29,7 +29,8 @@
using namespace bluetooth::test::headless;
-static void bta_jv_start_discovery_callback(uint16_t result, void* user_data) {
+static void bta_jv_start_discovery_callback(tSDP_STATUS result,
+ void* user_data) {
auto promise = static_cast<std::promise<uint16_t>*>(user_data);
promise->set_value(result);
}
diff --git a/test/mock/mock_activity_attribution.cc b/test/mock/mock_activity_attribution.cc
index e5cb2d9..6879796 100644
--- a/test/mock/mock_activity_attribution.cc
+++ b/test/mock/mock_activity_attribution.cc
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "module.h"
+#include "gd/module.h"
#include "btif/include/btif_activity_attribution.h"
#include "main/shim/activity_attribution.h"
diff --git a/test/mock/mock_bta_ag_api.cc b/test/mock/mock_bta_ag_api.cc
index ab2b866..bc716b7 100644
--- a/test/mock/mock_bta_ag_api.cc
+++ b/test/mock/mock_bta_ag_api.cc
@@ -39,7 +39,7 @@
tBTA_STATUS BTA_AgEnable(tBTA_AG_CBACK* p_cback) {
mock_function_count_map[__func__]++;
- return 0;
+ return BTA_SUCCESS;
}
void BTA_AgAudioClose(uint16_t handle) { mock_function_count_map[__func__]++; }
void BTA_AgAudioOpen(uint16_t handle) { mock_function_count_map[__func__]++; }
diff --git a/test/mock/mock_bta_dm_api.cc b/test/mock/mock_bta_dm_api.cc
index 2f2bf17..5c8b07d 100644
--- a/test/mock/mock_bta_dm_api.cc
+++ b/test/mock/mock_bta_dm_api.cc
@@ -46,12 +46,12 @@
}
tBTA_STATUS BTA_DmRemoveDevice(const RawAddress& bd_addr) {
mock_function_count_map[__func__]++;
- return 0;
+ return BTA_SUCCESS;
}
-tBTA_STATUS BTA_DmSetLocalDiRecord(tBTA_DI_RECORD* p_device_info,
+tBTA_STATUS BTA_DmSetLocalDiRecord(tSDP_DI_RECORD* p_device_info,
uint32_t* p_handle) {
mock_function_count_map[__func__]++;
- return 0;
+ return BTA_SUCCESS;
}
void BTA_AddEirUuid(uint16_t uuid16) { mock_function_count_map[__func__]++; }
void BTA_DmAddBleDevice(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type,
diff --git a/test/mock/mock_bta_hearing_aid.cc b/test/mock/mock_bta_hearing_aid.cc
index dea63d9..865a784 100644
--- a/test/mock/mock_bta_hearing_aid.cc
+++ b/test/mock/mock_bta_hearing_aid.cc
@@ -32,7 +32,6 @@
#include "bta/include/bta_gatt_api.h"
#include "bta/include/bta_gatt_queue.h"
#include "bta/include/bta_hearing_aid_api.h"
-#include "bta_hearing_aid_api.h"
#include "device/include/controller.h"
#include "embdrv/g722/g722_enc_dec.h"
#include "osi/include/log.h"
diff --git a/test/mock/mock_bta_vc.cc b/test/mock/mock_bta_vc.cc
index 6ac9f57..b47f549 100644
--- a/test/mock/mock_bta_vc.cc
+++ b/test/mock/mock_bta_vc.cc
@@ -25,17 +25,16 @@
extern std::map<std::string, int> mock_function_count_map;
#include <base/bind.h>
-#include <base/bind_helpers.h>
#include <base/logging.h>
#include <base/strings/string_number_conversions.h>
#include <hardware/bt_vc.h>
#include <string>
#include <vector>
-#include "bta/vc/devices.h"
-#include "bta_gatt_api.h"
-#include "bta_gatt_queue.h"
-#include "bta_vc_api.h"
-#include "btif_storage.h"
+#include "bind_helpers.h"
+#include "bta/include/bta_gatt_api.h"
+#include "bta/include/bta_gatt_queue.h"
+#include "bta/include/bta_vc_api.h"
+#include "btif/include/btif_storage.h"
#ifndef UNUSED_ATTR
#define UNUSED_ATTR
diff --git a/test/mock/mock_bta_vc_device.cc b/test/mock/mock_bta_vc_device.cc
index d410246..c2457cc 100644
--- a/test/mock/mock_bta_vc_device.cc
+++ b/test/mock/mock_bta_vc_device.cc
@@ -27,9 +27,6 @@
#include <map>
#include <vector>
#include "bta/vc/devices.h"
-#include "bta_gatt_api.h"
-#include "bta_gatt_queue.h"
-#include "gatt_api.h"
#include "stack/btm/btm_sec.h"
using namespace bluetooth::vc::internal;
diff --git a/stack/test/common/mock_btif_bqr.cc b/test/mock/mock_btif_bqr.cc
similarity index 100%
rename from stack/test/common/mock_btif_bqr.cc
rename to test/mock/mock_btif_bqr.cc
diff --git a/bta/test/common/mock_btif_co_bta_dm_co.cc b/test/mock/mock_btif_co_bta_dm_co.cc
similarity index 100%
rename from bta/test/common/mock_btif_co_bta_dm_co.cc
rename to test/mock/mock_btif_co_bta_dm_co.cc
diff --git a/bta/test/common/mock_btif_co_bta_hh_co.cc b/test/mock/mock_btif_co_bta_hh_co.cc
similarity index 100%
rename from bta/test/common/mock_btif_co_bta_hh_co.cc
rename to test/mock/mock_btif_co_bta_hh_co.cc
diff --git a/test/mock/mock_btif_config.cc b/test/mock/mock_btif_config.cc
new file mode 100644
index 0000000..512a01f
--- /dev/null
+++ b/test/mock/mock_btif_config.cc
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:18
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <cstdint>
+#include <functional>
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+
+// Mock include file to share data between tests and mock
+#include "test/mock/mock_btif_config.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+// Mocked internal structures, if any
+
+namespace test {
+namespace mock {
+namespace btif_config {
+
+// Function state capture and return values, if needed
+struct btif_get_device_type btif_get_device_type;
+struct btif_get_address_type btif_get_address_type;
+struct btif_config_exist btif_config_exist;
+struct btif_config_get_int btif_config_get_int;
+struct btif_config_set_int btif_config_set_int;
+struct btif_config_get_uint64 btif_config_get_uint64;
+struct btif_config_set_uint64 btif_config_set_uint64;
+struct btif_config_get_str btif_config_get_str;
+struct btif_config_set_str btif_config_set_str;
+struct btif_config_get_bin btif_config_get_bin;
+struct btif_config_get_bin_length btif_config_get_bin_length;
+struct btif_config_set_bin btif_config_set_bin;
+struct btif_config_get_paired_devices btif_config_get_paired_devices;
+struct btif_config_remove btif_config_remove;
+struct btif_config_save btif_config_save;
+struct btif_config_flush btif_config_flush;
+struct btif_config_clear btif_config_clear;
+struct btif_debug_config_dump btif_debug_config_dump;
+
+} // namespace btif_config
+} // namespace mock
+} // namespace test
+
+// Mocked functions, if any
+bool btif_get_device_type(const RawAddress& bda, int* p_device_type) {
+ mock_function_count_map[__func__]++;
+ return test::mock::btif_config::btif_get_device_type(bda, p_device_type);
+}
+bool btif_get_address_type(const RawAddress& bda, tBLE_ADDR_TYPE* p_addr_type) {
+ mock_function_count_map[__func__]++;
+ return test::mock::btif_config::btif_get_address_type(bda, p_addr_type);
+}
+bool btif_config_exist(const std::string& section, const std::string& key) {
+ mock_function_count_map[__func__]++;
+ return test::mock::btif_config::btif_config_exist(section, key);
+}
+bool btif_config_get_int(const std::string& section, const std::string& key,
+ int* value) {
+ mock_function_count_map[__func__]++;
+ return test::mock::btif_config::btif_config_get_int(section, key, value);
+}
+bool btif_config_set_int(const std::string& section, const std::string& key,
+ int value) {
+ mock_function_count_map[__func__]++;
+ return test::mock::btif_config::btif_config_set_int(section, key, value);
+}
+bool btif_config_get_uint64(const std::string& section, const std::string& key,
+ uint64_t* value) {
+ mock_function_count_map[__func__]++;
+ return test::mock::btif_config::btif_config_get_uint64(section, key, value);
+}
+bool btif_config_set_uint64(const std::string& section, const std::string& key,
+ uint64_t value) {
+ mock_function_count_map[__func__]++;
+ return test::mock::btif_config::btif_config_set_uint64(section, key, value);
+}
+bool btif_config_get_str(const std::string& section, const std::string& key,
+ char* value, int* size_bytes) {
+ mock_function_count_map[__func__]++;
+ return test::mock::btif_config::btif_config_get_str(section, key, value,
+ size_bytes);
+}
+bool btif_config_set_str(const std::string& section, const std::string& key,
+ const std::string& value) {
+ mock_function_count_map[__func__]++;
+ return test::mock::btif_config::btif_config_set_str(section, key, value);
+}
+bool btif_config_get_bin(const std::string& section, const std::string& key,
+ uint8_t* value, size_t* length) {
+ mock_function_count_map[__func__]++;
+ return test::mock::btif_config::btif_config_get_bin(section, key, value,
+ length);
+}
+size_t btif_config_get_bin_length(const std::string& section,
+ const std::string& key) {
+ mock_function_count_map[__func__]++;
+ return test::mock::btif_config::btif_config_get_bin_length(section, key);
+}
+bool btif_config_set_bin(const std::string& section, const std::string& key,
+ const uint8_t* value, size_t length) {
+ mock_function_count_map[__func__]++;
+ return test::mock::btif_config::btif_config_set_bin(section, key, value,
+ length);
+}
+std::vector<RawAddress> btif_config_get_paired_devices() {
+ mock_function_count_map[__func__]++;
+ return test::mock::btif_config::btif_config_get_paired_devices();
+}
+bool btif_config_remove(const std::string& section, const std::string& key) {
+ mock_function_count_map[__func__]++;
+ return test::mock::btif_config::btif_config_remove(section, key);
+}
+void btif_config_save(void) {
+ mock_function_count_map[__func__]++;
+ test::mock::btif_config::btif_config_save();
+}
+void btif_config_flush(void) {
+ mock_function_count_map[__func__]++;
+ test::mock::btif_config::btif_config_flush();
+}
+bool btif_config_clear(void) {
+ mock_function_count_map[__func__]++;
+ return test::mock::btif_config::btif_config_clear();
+}
+void btif_debug_config_dump(int fd) {
+ mock_function_count_map[__func__]++;
+ test::mock::btif_config::btif_debug_config_dump(fd);
+}
+
+// END mockcify generation
diff --git a/test/mock/mock_btif_config.h b/test/mock/mock_btif_config.h
new file mode 100644
index 0000000..6423855
--- /dev/null
+++ b/test/mock/mock_btif_config.h
@@ -0,0 +1,265 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:18
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+
+#include "btif/include/btif_config.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+namespace test {
+namespace mock {
+namespace btif_config {
+
+// Shared state between mocked functions and tests
+// Name: btif_get_device_type
+// Params: const RawAddress& bda, int* p_device_type
+// Returns: bool
+struct btif_get_device_type {
+ std::function<bool(const RawAddress& bda, int* p_device_type)> body{
+ [](const RawAddress& bda, int* p_device_type) { return false; }};
+ bool operator()(const RawAddress& bda, int* p_device_type) {
+ return body(bda, p_device_type);
+ };
+};
+extern struct btif_get_device_type btif_get_device_type;
+// Name: btif_get_address_type
+// Params: const RawAddress& bda, tBLE_ADDR_TYPE* p_addr_type
+// Returns: bool
+struct btif_get_address_type {
+ std::function<bool(const RawAddress& bda, tBLE_ADDR_TYPE* p_addr_type)> body{
+ [](const RawAddress& bda, tBLE_ADDR_TYPE* p_addr_type) { return false; }};
+ bool operator()(const RawAddress& bda, tBLE_ADDR_TYPE* p_addr_type) {
+ return body(bda, p_addr_type);
+ };
+};
+extern struct btif_get_address_type btif_get_address_type;
+// Name: btif_config_exist
+// Params: const std::string& section, const std::string& key
+// Returns: bool
+struct btif_config_exist {
+ std::function<bool(const std::string& section, const std::string& key)> body{
+ [](const std::string& section, const std::string& key) { return false; }};
+ bool operator()(const std::string& section, const std::string& key) {
+ return body(section, key);
+ };
+};
+extern struct btif_config_exist btif_config_exist;
+// Name: btif_config_get_int
+// Params: const std::string& section, const std::string& key, int* value
+// Returns: bool
+struct btif_config_get_int {
+ std::function<bool(const std::string& section, const std::string& key,
+ int* value)>
+ body{[](const std::string& section, const std::string& key, int* value) {
+ return false;
+ }};
+ bool operator()(const std::string& section, const std::string& key,
+ int* value) {
+ return body(section, key, value);
+ };
+};
+extern struct btif_config_get_int btif_config_get_int;
+// Name: btif_config_set_int
+// Params: const std::string& section, const std::string& key, int value
+// Returns: bool
+struct btif_config_set_int {
+ std::function<bool(const std::string& section, const std::string& key,
+ int value)>
+ body{[](const std::string& section, const std::string& key, int value) {
+ return false;
+ }};
+ bool operator()(const std::string& section, const std::string& key,
+ int value) {
+ return body(section, key, value);
+ };
+};
+extern struct btif_config_set_int btif_config_set_int;
+// Name: btif_config_get_uint64
+// Params: const std::string& section, const std::string& key, uint64_t* value
+// Returns: bool
+struct btif_config_get_uint64 {
+ std::function<bool(const std::string& section, const std::string& key,
+ uint64_t* value)>
+ body{[](const std::string& section, const std::string& key,
+ uint64_t* value) { return false; }};
+ bool operator()(const std::string& section, const std::string& key,
+ uint64_t* value) {
+ return body(section, key, value);
+ };
+};
+extern struct btif_config_get_uint64 btif_config_get_uint64;
+// Name: btif_config_set_uint64
+// Params: const std::string& section, const std::string& key, uint64_t value
+// Returns: bool
+struct btif_config_set_uint64 {
+ std::function<bool(const std::string& section, const std::string& key,
+ uint64_t value)>
+ body{[](const std::string& section, const std::string& key,
+ uint64_t value) { return false; }};
+ bool operator()(const std::string& section, const std::string& key,
+ uint64_t value) {
+ return body(section, key, value);
+ };
+};
+extern struct btif_config_set_uint64 btif_config_set_uint64;
+// Name: btif_config_get_str
+// Params: const std::string& section, const std::string& key, char* value, int*
+// size_bytes Returns: bool
+struct btif_config_get_str {
+ std::function<bool(const std::string& section, const std::string& key,
+ char* value, int* size_bytes)>
+ body{[](const std::string& section, const std::string& key, char* value,
+ int* size_bytes) { return false; }};
+ bool operator()(const std::string& section, const std::string& key,
+ char* value, int* size_bytes) {
+ return body(section, key, value, size_bytes);
+ };
+};
+extern struct btif_config_get_str btif_config_get_str;
+// Name: btif_config_set_str
+// Params: const std::string& section, const std::string& key, const
+// std::string& value Returns: bool
+struct btif_config_set_str {
+ std::function<bool(const std::string& section, const std::string& key,
+ const std::string& value)>
+ body{[](const std::string& section, const std::string& key,
+ const std::string& value) { return false; }};
+ bool operator()(const std::string& section, const std::string& key,
+ const std::string& value) {
+ return body(section, key, value);
+ };
+};
+extern struct btif_config_set_str btif_config_set_str;
+// Name: btif_config_get_bin
+// Params: const std::string& section, const std::string& key, uint8_t* value,
+// size_t* length Returns: bool
+struct btif_config_get_bin {
+ std::function<bool(const std::string& section, const std::string& key,
+ uint8_t* value, size_t* length)>
+ body{[](const std::string& section, const std::string& key,
+ uint8_t* value, size_t* length) { return false; }};
+ bool operator()(const std::string& section, const std::string& key,
+ uint8_t* value, size_t* length) {
+ return body(section, key, value, length);
+ };
+};
+extern struct btif_config_get_bin btif_config_get_bin;
+// Name: btif_config_get_bin_length
+// Params: const std::string& section, const std::string& key
+// Returns: size_t
+struct btif_config_get_bin_length {
+ std::function<size_t(const std::string& section, const std::string& key)>
+ body{
+ [](const std::string& section, const std::string& key) { return 0; }};
+ size_t operator()(const std::string& section, const std::string& key) {
+ return body(section, key);
+ };
+};
+extern struct btif_config_get_bin_length btif_config_get_bin_length;
+// Name: btif_config_set_bin
+// Params: const std::string& section, const std::string& key, const uint8_t*
+// value, size_t length Returns: bool
+struct btif_config_set_bin {
+ std::function<bool(const std::string& section, const std::string& key,
+ const uint8_t* value, size_t length)>
+ body{[](const std::string& section, const std::string& key,
+ const uint8_t* value, size_t length) { return false; }};
+ bool operator()(const std::string& section, const std::string& key,
+ const uint8_t* value, size_t length) {
+ return body(section, key, value, length);
+ };
+};
+extern struct btif_config_set_bin btif_config_set_bin;
+// Name: btif_config_get_paired_devices
+// Params:
+// Returns: std::vector<RawAddress>
+struct btif_config_get_paired_devices {
+ std::vector<RawAddress> raw_addresses;
+ std::function<std::vector<RawAddress>()> body{
+ [this]() { return raw_addresses; }};
+ std::vector<RawAddress> operator()() { return body(); };
+};
+extern struct btif_config_get_paired_devices btif_config_get_paired_devices;
+// Name: btif_config_remove
+// Params: const std::string& section, const std::string& key
+// Returns: bool
+struct btif_config_remove {
+ std::function<bool(const std::string& section, const std::string& key)> body{
+ [](const std::string& section, const std::string& key) { return false; }};
+ bool operator()(const std::string& section, const std::string& key) {
+ return body(section, key);
+ };
+};
+extern struct btif_config_remove btif_config_remove;
+// Name: btif_config_save
+// Params: void
+// Returns: void
+struct btif_config_save {
+ std::function<void(void)> body{[](void) {}};
+ void operator()(void) { body(); };
+};
+extern struct btif_config_save btif_config_save;
+// Name: btif_config_flush
+// Params: void
+// Returns: void
+struct btif_config_flush {
+ std::function<void(void)> body{[](void) {}};
+ void operator()(void) { body(); };
+};
+extern struct btif_config_flush btif_config_flush;
+// Name: btif_config_clear
+// Params: void
+// Returns: bool
+struct btif_config_clear {
+ std::function<bool(void)> body{[](void) { return false; }};
+ bool operator()(void) { return body(); };
+};
+extern struct btif_config_clear btif_config_clear;
+// Name: btif_debug_config_dump
+// Params: int fd
+// Returns: void
+struct btif_debug_config_dump {
+ std::function<void(int fd)> body{[](int fd) {}};
+ void operator()(int fd) { body(fd); };
+};
+extern struct btif_debug_config_dump btif_debug_config_dump;
+
+} // namespace btif_config
+} // namespace mock
+} // namespace test
+
+// END mockcify generation
diff --git a/main/test/common/mock_btif_core.cc b/test/mock/mock_btif_core.cc
similarity index 100%
rename from main/test/common/mock_btif_core.cc
rename to test/mock/mock_btif_core.cc
diff --git a/bta/test/common/mock_btif_debug_conn.cc b/test/mock/mock_btif_debug_conn.cc
similarity index 100%
rename from bta/test/common/mock_btif_debug_conn.cc
rename to test/mock/mock_btif_debug_conn.cc
diff --git a/main/test/common/mock_btif_dm.cc b/test/mock/mock_btif_dm.cc
similarity index 96%
rename from main/test/common/mock_btif_dm.cc
rename to test/mock/mock_btif_dm.cc
index 0e986b5..f65fba0 100644
--- a/main/test/common/mock_btif_dm.cc
+++ b/test/mock/mock_btif_dm.cc
@@ -28,6 +28,7 @@
#include "bta/include/bta_api.h"
#include "include/hardware/bluetooth.h"
#include "internal_include/bte_appl.h"
+#include "types/bt_transport.h"
#include "types/raw_address.h"
struct uid_set_t;
@@ -168,6 +169,7 @@
return false;
}
-void btif_dm_proc_loc_oob(const Octet16& c, const Octet16& r) {
+void btif_dm_proc_loc_oob(tBT_TRANSPORT transport, bool is_valid,
+ const Octet16& c, const Octet16& r) {
mock_function_count_map[__func__]++;
}
diff --git a/bta/test/common/mock_btif_stack_manager.cc b/test/mock/mock_btif_stack_manager.cc
similarity index 100%
rename from bta/test/common/mock_btif_stack_manager.cc
rename to test/mock/mock_btif_stack_manager.cc
diff --git a/bta/test/common/mock_btif_storage.cc b/test/mock/mock_btif_storage.cc
similarity index 96%
rename from bta/test/common/mock_btif_storage.cc
rename to test/mock/mock_btif_storage.cc
index 8c09ad9..4a700db 100644
--- a/bta/test/common/mock_btif_storage.cc
+++ b/test/mock/mock_btif_storage.cc
@@ -215,3 +215,10 @@
bool add_to_acceptlist) {
mock_function_count_map[__func__]++;
}
+void btif_storage_set_gatt_sr_supp_feat(const RawAddress& addr, uint8_t feat) {
+ mock_function_count_map[__func__]++;
+}
+uint8_t btif_storage_get_sr_supp_feat(const RawAddress& bd_addr) {
+ mock_function_count_map[__func__]++;
+ return 0;
+}
diff --git a/test/mock/mock_stack_btu_task.cc b/test/mock/mock_btu_task.cc
similarity index 64%
rename from test/mock/mock_stack_btu_task.cc
rename to test/mock/mock_btu_task.cc
index f4ba839..cc4a50b 100644
--- a/test/mock/mock_stack_btu_task.cc
+++ b/test/mock/mock_btu_task.cc
@@ -47,24 +47,4 @@
#define UNUSED_ATTR
#endif
-bluetooth::common::MessageLoopThread* get_main_thread() {
- mock_function_count_map[__func__]++;
- return nullptr;
-}
-bt_status_t do_in_main_thread(const base::Location& from_here,
- base::OnceClosure task) {
- mock_function_count_map[__func__]++;
- return BT_STATUS_SUCCESS;
-}
-bt_status_t do_in_main_thread_delayed(const base::Location& from_here,
- base::OnceClosure task,
- const base::TimeDelta& delay) {
- mock_function_count_map[__func__]++;
- return BT_STATUS_SUCCESS;
-}
void btu_hci_msg_process(BT_HDR* p_msg) { mock_function_count_map[__func__]++; }
-void main_thread_shut_down() { mock_function_count_map[__func__]++; }
-void main_thread_start_up() { mock_function_count_map[__func__]++; }
-void post_on_bt_main(BtMainClosure closure) {
- mock_function_count_map[__func__]++;
-}
diff --git a/test/mock/mock_common_stop_watch_legacy.cc b/test/mock/mock_common_stop_watch_legacy.cc
index c3d7b4a..534c537 100644
--- a/test/mock/mock_common_stop_watch_legacy.cc
+++ b/test/mock/mock_common_stop_watch_legacy.cc
@@ -40,14 +40,15 @@
StopWatchLegacy::StopWatchLegacy(std::string text)
: text_(std::move(text)),
- start_time_(std::chrono::high_resolution_clock::now()) {
+ timestamp_(std::chrono::system_clock::now()),
+ start_timestamp_(std::chrono::high_resolution_clock::now()) {
mock_function_count_map[__func__]++;
}
StopWatchLegacy::~StopWatchLegacy() { mock_function_count_map[__func__]++; }
void StopWatchLegacy::DumpStopWatchLog() {
mock_function_count_map[__func__]++;
}
-void StopWatchLegacy::RecordLog(std::string log) {
+void StopWatchLegacy::RecordLog(StopWatchLog log) {
mock_function_count_map[__func__]++;
}
diff --git a/test/mock/mock_device_controller.cc b/test/mock/mock_device_controller.cc
new file mode 100644
index 0000000..1d087b5
--- /dev/null
+++ b/test/mock/mock_device_controller.cc
@@ -0,0 +1,460 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:1
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+#include "bt_types.h"
+#include "main/shim/controller.h"
+
+// Mock include file to share data between tests and mock
+#include "test/mock/mock_device_controller.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+// Mocked internal structures, if any
+namespace test {
+namespace mock {
+namespace device_controller {
+
+RawAddress address;
+bt_version_t bt_version = {
+ .hci_version = 0,
+ .hci_revision = 0,
+ .lmp_version = 0,
+ .manufacturer = 0,
+ .lmp_subversion = 0,
+};
+
+uint8_t supported_commands[HCI_SUPPORTED_COMMANDS_ARRAY_SIZE]{0};
+bt_device_features_t features_classic[MAX_FEATURES_CLASSIC_PAGE_COUNT] = {{
+ .as_array{0},
+}};
+uint8_t last_features_classic_page_index{0};
+
+uint16_t acl_data_size_classic{0};
+uint16_t acl_data_size_ble{0};
+uint16_t iso_data_size{0};
+
+uint16_t acl_buffer_count_classic{0};
+uint8_t acl_buffer_count_ble{0};
+uint8_t iso_buffer_count{0};
+
+uint8_t ble_acceptlist_size{0};
+uint8_t ble_resolving_list_max_size{0};
+uint8_t ble_supported_states[BLE_SUPPORTED_STATES_SIZE]{0};
+bt_device_features_t features_ble{0};
+uint16_t ble_suggested_default_data_length{0};
+uint16_t ble_supported_max_tx_octets{0};
+uint16_t ble_supported_max_tx_time{0};
+uint16_t ble_supported_max_rx_octets{0};
+uint16_t ble_supported_max_rx_time{0};
+
+uint16_t ble_maxium_advertising_data_length{0};
+uint8_t ble_number_of_supported_advertising_sets{0};
+uint8_t ble_periodic_advertiser_list_size{0};
+uint8_t local_supported_codecs[MAX_LOCAL_SUPPORTED_CODECS_SIZE]{0};
+uint8_t number_of_local_supported_codecs{0};
+
+bool readable{false};
+bool ble_supported{false};
+bool iso_supported{false};
+bool simple_pairing_supported{false};
+bool secure_connections_supported{false};
+
+bool get_is_ready(void) { return readable; }
+
+const RawAddress* get_address(void) { return &address; }
+
+const bt_version_t* get_bt_version(void) { return &bt_version; }
+
+uint8_t* get_local_supported_codecs(uint8_t* number_of_codecs) {
+ if (number_of_local_supported_codecs) {
+ *number_of_codecs = number_of_local_supported_codecs;
+ return local_supported_codecs;
+ }
+ return NULL;
+}
+
+const uint8_t* get_ble_supported_states(void) { return ble_supported_states; }
+
+bool supports_simple_pairing(void) { return simple_pairing_supported; }
+
+bool supports_secure_connections(void) { return secure_connections_supported; }
+
+bool supports_simultaneous_le_bredr(void) {
+ return HCI_SIMUL_LE_BREDR_SUPPORTED(features_classic[0].as_array);
+}
+
+bool supports_reading_remote_extended_features(void) {
+ return HCI_READ_REMOTE_EXT_FEATURES_SUPPORTED(supported_commands);
+}
+
+bool supports_interlaced_inquiry_scan(void) {
+ return HCI_LMP_INTERLACED_INQ_SCAN_SUPPORTED(features_classic[0].as_array);
+}
+
+bool supports_rssi_with_inquiry_results(void) {
+ return HCI_LMP_INQ_RSSI_SUPPORTED(features_classic[0].as_array);
+}
+
+bool supports_extended_inquiry_response(void) {
+ return HCI_EXT_INQ_RSP_SUPPORTED(features_classic[0].as_array);
+}
+
+bool supports_central_peripheral_role_switch(void) {
+ return HCI_SWITCH_SUPPORTED(features_classic[0].as_array);
+}
+
+bool supports_enhanced_setup_synchronous_connection(void) {
+ return HCI_ENH_SETUP_SYNCH_CONN_SUPPORTED(supported_commands);
+}
+
+bool supports_enhanced_accept_synchronous_connection(void) {
+ return HCI_ENH_ACCEPT_SYNCH_CONN_SUPPORTED(supported_commands);
+}
+
+bool supports_3_slot_packets(void) {
+ return HCI_3_SLOT_PACKETS_SUPPORTED(features_classic[0].as_array);
+}
+
+bool supports_5_slot_packets(void) {
+ return HCI_5_SLOT_PACKETS_SUPPORTED(features_classic[0].as_array);
+}
+
+bool supports_classic_2m_phy(void) {
+ return HCI_EDR_ACL_2MPS_SUPPORTED(features_classic[0].as_array);
+}
+
+bool supports_classic_3m_phy(void) {
+ return HCI_EDR_ACL_3MPS_SUPPORTED(features_classic[0].as_array);
+}
+
+bool supports_3_slot_edr_packets(void) {
+ return HCI_3_SLOT_EDR_ACL_SUPPORTED(features_classic[0].as_array);
+}
+
+bool supports_5_slot_edr_packets(void) {
+ return HCI_5_SLOT_EDR_ACL_SUPPORTED(features_classic[0].as_array);
+}
+
+bool supports_sco(void) {
+ return HCI_SCO_LINK_SUPPORTED(features_classic[0].as_array);
+}
+
+bool supports_hv2_packets(void) {
+ return HCI_HV2_PACKETS_SUPPORTED(features_classic[0].as_array);
+}
+
+bool supports_hv3_packets(void) {
+ return HCI_HV3_PACKETS_SUPPORTED(features_classic[0].as_array);
+}
+
+bool supports_ev3_packets(void) {
+ return HCI_ESCO_EV3_SUPPORTED(features_classic[0].as_array);
+}
+
+bool supports_ev4_packets(void) {
+ return HCI_ESCO_EV4_SUPPORTED(features_classic[0].as_array);
+}
+
+bool supports_ev5_packets(void) {
+ return HCI_ESCO_EV5_SUPPORTED(features_classic[0].as_array);
+}
+
+bool supports_esco_2m_phy(void) {
+ return HCI_EDR_ESCO_2MPS_SUPPORTED(features_classic[0].as_array);
+}
+
+bool supports_esco_3m_phy(void) {
+ return HCI_EDR_ESCO_3MPS_SUPPORTED(features_classic[0].as_array);
+}
+
+bool supports_3_slot_esco_edr_packets(void) {
+ return HCI_3_SLOT_EDR_ESCO_SUPPORTED(features_classic[0].as_array);
+}
+
+bool supports_role_switch(void) {
+ return HCI_SWITCH_SUPPORTED(features_classic[0].as_array);
+}
+
+bool supports_hold_mode(void) {
+ return HCI_HOLD_MODE_SUPPORTED(features_classic[0].as_array);
+}
+
+bool supports_sniff_mode(void) {
+ return HCI_SNIFF_MODE_SUPPORTED(features_classic[0].as_array);
+}
+
+bool supports_park_mode(void) {
+ return HCI_PARK_MODE_SUPPORTED(features_classic[0].as_array);
+}
+
+bool supports_non_flushable_pb(void) {
+ return HCI_NON_FLUSHABLE_PB_SUPPORTED(features_classic[0].as_array);
+}
+
+bool supports_sniff_subrating(void) {
+ return HCI_SNIFF_SUB_RATE_SUPPORTED(features_classic[0].as_array);
+}
+
+bool supports_encryption_pause(void) {
+ return HCI_ATOMIC_ENCRYPT_SUPPORTED(features_classic[0].as_array);
+}
+
+bool supports_ble(void) { return ble_supported; }
+
+bool supports_ble_privacy(void) {
+ return HCI_LE_ENHANCED_PRIVACY_SUPPORTED(features_ble.as_array);
+}
+
+bool supports_ble_set_privacy_mode() {
+ return HCI_LE_ENHANCED_PRIVACY_SUPPORTED(features_ble.as_array) &&
+ HCI_LE_SET_PRIVACY_MODE_SUPPORTED(supported_commands);
+}
+
+bool supports_ble_packet_extension(void) {
+ return HCI_LE_DATA_LEN_EXT_SUPPORTED(features_ble.as_array);
+}
+
+bool supports_ble_connection_parameters_request(void) {
+ return HCI_LE_CONN_PARAM_REQ_SUPPORTED(features_ble.as_array);
+}
+
+bool supports_ble_2m_phy(void) {
+ return HCI_LE_2M_PHY_SUPPORTED(features_ble.as_array);
+}
+
+bool supports_ble_coded_phy(void) {
+ return HCI_LE_CODED_PHY_SUPPORTED(features_ble.as_array);
+}
+
+bool supports_ble_extended_advertising(void) {
+ return HCI_LE_EXTENDED_ADVERTISING_SUPPORTED(features_ble.as_array);
+}
+
+bool supports_ble_periodic_advertising(void) {
+ return HCI_LE_PERIODIC_ADVERTISING_SUPPORTED(features_ble.as_array);
+}
+
+bool supports_ble_peripheral_initiated_feature_exchange(void) {
+ return HCI_LE_PERIPHERAL_INIT_FEAT_EXC_SUPPORTED(features_ble.as_array);
+}
+
+bool supports_ble_connection_parameter_request(void) {
+ return HCI_LE_CONN_PARAM_REQ_SUPPORTED(features_ble.as_array);
+}
+
+bool supports_ble_periodic_advertising_sync_transfer_sender(void) {
+ return HCI_LE_PERIODIC_ADVERTISING_SYNC_TRANSFER_SENDER(
+ features_ble.as_array);
+}
+
+bool supports_ble_periodic_advertising_sync_transfer_recipient(void) {
+ return HCI_LE_PERIODIC_ADVERTISING_SYNC_TRANSFER_RECIPIENT(
+ features_ble.as_array);
+}
+
+bool supports_ble_connected_isochronous_stream_central(void) {
+ return HCI_LE_CIS_CENTRAL(features_ble.as_array);
+}
+
+bool supports_ble_connected_isochronous_stream_peripheral(void) {
+ return HCI_LE_CIS_PERIPHERAL(features_ble.as_array);
+}
+
+bool supports_ble_isochronous_broadcaster(void) {
+ return HCI_LE_ISO_BROADCASTER(features_ble.as_array);
+}
+
+bool supports_ble_synchronized_receiver(void) {
+ return HCI_LE_SYNCHRONIZED_RECEIVER(features_ble.as_array);
+}
+
+uint16_t get_acl_data_size_classic(void) { return acl_data_size_classic; }
+
+uint16_t get_acl_data_size_ble(void) { return acl_data_size_ble; }
+
+uint16_t get_iso_data_size(void) { return iso_data_size; }
+
+uint16_t get_acl_packet_size_classic(void) {
+ return acl_data_size_classic + HCI_DATA_PREAMBLE_SIZE;
+}
+
+uint16_t get_acl_packet_size_ble(void) {
+ return acl_data_size_ble + HCI_DATA_PREAMBLE_SIZE;
+}
+
+uint16_t get_iso_packet_size(void) {
+ return iso_data_size + HCI_DATA_PREAMBLE_SIZE;
+}
+
+uint16_t get_ble_suggested_default_data_length(void) {
+ return ble_suggested_default_data_length;
+}
+
+uint16_t get_ble_maximum_tx_data_length(void) {
+ return ble_supported_max_tx_octets;
+}
+
+uint16_t get_ble_maximum_tx_time(void) { return ble_supported_max_tx_time; }
+
+uint16_t get_ble_maxium_advertising_data_length(void) {
+ return ble_maxium_advertising_data_length;
+}
+
+uint8_t get_ble_number_of_supported_advertising_sets(void) {
+ return ble_number_of_supported_advertising_sets;
+}
+
+uint8_t get_ble_periodic_advertiser_list_size(void) {
+ return ble_periodic_advertiser_list_size;
+}
+
+uint16_t get_acl_buffer_count_classic(void) { return acl_buffer_count_classic; }
+
+uint8_t get_acl_buffer_count_ble(void) { return acl_buffer_count_ble; }
+
+uint8_t get_iso_buffer_count(void) { return iso_buffer_count; }
+
+uint8_t get_ble_acceptlist_size(void) { return ble_acceptlist_size; }
+
+uint8_t get_ble_resolving_list_max_size(void) {
+ return ble_resolving_list_max_size;
+}
+
+void set_ble_resolving_list_max_size(int resolving_list_max_size) {
+ ble_resolving_list_max_size = resolving_list_max_size;
+}
+
+uint8_t get_le_all_initiating_phys() {
+ uint8_t phy = PHY_LE_1M;
+ return phy;
+}
+
+const controller_t interface = {
+ get_is_ready,
+
+ get_address,
+ get_bt_version,
+
+ get_ble_supported_states,
+
+ supports_simple_pairing,
+ supports_secure_connections,
+ supports_simultaneous_le_bredr,
+ supports_reading_remote_extended_features,
+ supports_interlaced_inquiry_scan,
+ supports_rssi_with_inquiry_results,
+ supports_extended_inquiry_response,
+ supports_central_peripheral_role_switch,
+ supports_enhanced_setup_synchronous_connection,
+ supports_enhanced_accept_synchronous_connection,
+ supports_3_slot_packets,
+ supports_5_slot_packets,
+ supports_classic_2m_phy,
+ supports_classic_3m_phy,
+ supports_3_slot_edr_packets,
+ supports_5_slot_edr_packets,
+ supports_sco,
+ supports_hv2_packets,
+ supports_hv3_packets,
+ supports_ev3_packets,
+ supports_ev4_packets,
+ supports_ev5_packets,
+ supports_esco_2m_phy,
+ supports_esco_3m_phy,
+ supports_3_slot_esco_edr_packets,
+ supports_role_switch,
+ supports_hold_mode,
+ supports_sniff_mode,
+ supports_park_mode,
+ supports_non_flushable_pb,
+ supports_sniff_subrating,
+ supports_encryption_pause,
+
+ supports_ble,
+ supports_ble_packet_extension,
+ supports_ble_connection_parameters_request,
+ supports_ble_privacy,
+ supports_ble_set_privacy_mode,
+ supports_ble_2m_phy,
+ supports_ble_coded_phy,
+ supports_ble_extended_advertising,
+ supports_ble_periodic_advertising,
+ supports_ble_peripheral_initiated_feature_exchange,
+ supports_ble_connection_parameter_request,
+ supports_ble_periodic_advertising_sync_transfer_sender,
+ supports_ble_periodic_advertising_sync_transfer_recipient,
+ supports_ble_connected_isochronous_stream_central,
+ supports_ble_connected_isochronous_stream_peripheral,
+ supports_ble_isochronous_broadcaster,
+ supports_ble_synchronized_receiver,
+
+ get_acl_data_size_classic,
+ get_acl_data_size_ble,
+ get_iso_data_size,
+
+ get_acl_packet_size_classic,
+ get_acl_packet_size_ble,
+ get_iso_packet_size,
+
+ get_ble_suggested_default_data_length,
+ get_ble_maximum_tx_data_length,
+ get_ble_maximum_tx_time,
+ get_ble_maxium_advertising_data_length,
+ get_ble_number_of_supported_advertising_sets,
+ get_ble_periodic_advertiser_list_size,
+
+ get_acl_buffer_count_classic,
+ get_acl_buffer_count_ble,
+ get_iso_buffer_count,
+
+ get_ble_acceptlist_size,
+
+ get_ble_resolving_list_max_size,
+ set_ble_resolving_list_max_size,
+ get_local_supported_codecs,
+ get_le_all_initiating_phys};
+
+} // namespace device_controller
+} // namespace mock
+} // namespace test
+
+// Mocked functions, if any
+const controller_t* controller_get_interface() {
+ return &test::mock::device_controller::interface;
+}
+
+// END mockcify generation
diff --git a/test/mock/mock_device_controller.h b/test/mock/mock_device_controller.h
new file mode 100644
index 0000000..3417910
--- /dev/null
+++ b/test/mock/mock_device_controller.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:1
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+#include <base/logging.h>
+#include "bt_types.h"
+#include "btcore/include/event_mask.h"
+#include "btcore/include/module.h"
+#include "btcore/include/version.h"
+#include "device/include/controller.h"
+#include "hcimsgs.h"
+#include "main/shim/controller.h"
+#include "main/shim/shim.h"
+#include "osi/include/future.h"
+#include "osi/include/properties.h"
+#include "stack/include/btm_ble_api.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+namespace test {
+namespace mock {
+namespace device_controller {
+
+constexpr size_t HCI_SUPPORTED_COMMANDS_ARRAY_SIZE = 64;
+constexpr size_t MAX_FEATURES_CLASSIC_PAGE_COUNT = 3;
+constexpr size_t BLE_SUPPORTED_STATES_SIZE = 8;
+constexpr size_t MAX_LOCAL_SUPPORTED_CODECS_SIZE = 8;
+
+// Shared state between mocked functions and tests
+extern uint8_t supported_commands[HCI_SUPPORTED_COMMANDS_ARRAY_SIZE];
+extern bt_device_features_t features_classic[MAX_FEATURES_CLASSIC_PAGE_COUNT];
+extern uint8_t last_features_classic_page_index;
+
+extern uint16_t acl_data_size_classic;
+extern uint16_t acl_data_size_ble;
+extern uint16_t iso_data_size;
+
+extern uint16_t acl_buffer_count_classic;
+extern uint8_t acl_buffer_count_ble;
+extern uint8_t iso_buffer_count;
+
+extern uint8_t ble_acceptlist_size;
+extern uint8_t ble_resolving_list_max_size;
+extern uint8_t ble_supported_states[BLE_SUPPORTED_STATES_SIZE];
+extern bt_device_features_t features_ble;
+extern uint16_t ble_suggested_default_data_length;
+extern uint16_t ble_supported_max_tx_octets;
+extern uint16_t ble_supported_max_tx_time;
+extern uint16_t ble_supported_max_rx_octets;
+extern uint16_t ble_supported_max_rx_time;
+
+extern uint16_t ble_maxium_advertising_data_length;
+extern uint8_t ble_number_of_supported_advertising_sets;
+extern uint8_t ble_periodic_advertiser_list_size;
+extern uint8_t local_supported_codecs[MAX_LOCAL_SUPPORTED_CODECS_SIZE];
+extern uint8_t number_of_local_supported_codecs;
+
+extern bool readable;
+extern bool ble_supported;
+extern bool iso_supported;
+extern bool simple_pairing_supported;
+extern bool secure_connections_supported;
+
+} // namespace device_controller
+} // namespace mock
+} // namespace test
+
+// END mockcify generation
diff --git a/bta/test/common/mock_device_interop.cc b/test/mock/mock_device_interop.cc
similarity index 100%
rename from bta/test/common/mock_device_interop.cc
rename to test/mock/mock_device_interop.cc
diff --git a/test/mock/mock_hci_layer.cc b/test/mock/mock_hci_layer.cc
new file mode 100644
index 0000000..771998c
--- /dev/null
+++ b/test/mock/mock_hci_layer.cc
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:13
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+
+// Mock include file to share data between tests and mock
+#include "test/mock/mock_hci_layer.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+// Mocked internal structures, if any
+typedef struct {
+} waiting_command_t;
+
+namespace test {
+namespace mock {
+namespace hci_layer {
+
+// Function state capture and return values, if needed
+struct initialization_complete initialization_complete;
+struct hci_event_received hci_event_received;
+struct acl_event_received acl_event_received;
+struct sco_data_received sco_data_received;
+struct iso_data_received iso_data_received;
+struct hal_service_died hal_service_died;
+struct process_command_credits process_command_credits;
+struct hci_is_root_inflammation_event_received
+ hci_is_root_inflammation_event_received;
+struct handle_root_inflammation_event handle_root_inflammation_event;
+struct hci_layer_cleanup_interface hci_layer_cleanup_interface;
+struct hci_layer_get_interface hci_layer_get_interface;
+struct hci_layer_get_test_interface hci_layer_get_test_interface;
+
+} // namespace hci_layer
+} // namespace mock
+} // namespace test
+
+// Mocked functions, if any
+void initialization_complete() {
+ mock_function_count_map[__func__]++;
+ test::mock::hci_layer::initialization_complete();
+}
+void hci_event_received(const base::Location& from_here, BT_HDR* packet) {
+ mock_function_count_map[__func__]++;
+ test::mock::hci_layer::hci_event_received(from_here, packet);
+}
+void acl_event_received(BT_HDR* packet) {
+ mock_function_count_map[__func__]++;
+ test::mock::hci_layer::acl_event_received(packet);
+}
+void sco_data_received(BT_HDR* packet) {
+ mock_function_count_map[__func__]++;
+ test::mock::hci_layer::sco_data_received(packet);
+}
+void iso_data_received(BT_HDR* packet) {
+ mock_function_count_map[__func__]++;
+ test::mock::hci_layer::iso_data_received(packet);
+}
+void hal_service_died() {
+ mock_function_count_map[__func__]++;
+ test::mock::hci_layer::hal_service_died();
+}
+void process_command_credits(int credits) {
+ mock_function_count_map[__func__]++;
+ test::mock::hci_layer::process_command_credits(credits);
+}
+bool hci_is_root_inflammation_event_received() {
+ mock_function_count_map[__func__]++;
+ return test::mock::hci_layer::hci_is_root_inflammation_event_received();
+}
+void handle_root_inflammation_event() {
+ mock_function_count_map[__func__]++;
+ test::mock::hci_layer::handle_root_inflammation_event();
+}
+void hci_layer_cleanup_interface() {
+ mock_function_count_map[__func__]++;
+ test::mock::hci_layer::hci_layer_cleanup_interface();
+}
+const hci_t* hci_layer_get_interface() {
+ mock_function_count_map[__func__]++;
+ return test::mock::hci_layer::hci_layer_get_interface();
+}
+const hci_t* hci_layer_get_test_interface(
+ const allocator_t* buffer_allocator_interface,
+ const btsnoop_t* btsnoop_interface,
+ const packet_fragmenter_t* packet_fragmenter_interface) {
+ mock_function_count_map[__func__]++;
+ return test::mock::hci_layer::hci_layer_get_test_interface(
+ buffer_allocator_interface, btsnoop_interface,
+ packet_fragmenter_interface);
+}
+
+// END mockcify generation
diff --git a/test/mock/mock_hci_layer.h b/test/mock/mock_hci_layer.h
new file mode 100644
index 0000000..80e30ef
--- /dev/null
+++ b/test/mock/mock_hci_layer.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:13
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+
+#include "hci/include/hci_layer.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+namespace test {
+namespace mock {
+namespace hci_layer {
+
+// Shared state between mocked functions and tests
+// Name: initialization_complete
+// Params:
+// Returns: void
+struct initialization_complete {
+ std::function<void()> body{[]() {}};
+ void operator()() { body(); };
+};
+extern struct initialization_complete initialization_complete;
+// Name: hci_event_received
+// Params: const base::Location& from_here, BT_HDR* packet
+// Returns: void
+struct hci_event_received {
+ std::function<void(const base::Location& from_here, BT_HDR* packet)> body{
+ [](const base::Location& from_here, BT_HDR* packet) {}};
+ void operator()(const base::Location& from_here, BT_HDR* packet) {
+ body(from_here, packet);
+ };
+};
+extern struct hci_event_received hci_event_received;
+// Name: acl_event_received
+// Params: BT_HDR* packet
+// Returns: void
+struct acl_event_received {
+ std::function<void(BT_HDR* packet)> body{[](BT_HDR* packet) {}};
+ void operator()(BT_HDR* packet) { body(packet); };
+};
+extern struct acl_event_received acl_event_received;
+// Name: sco_data_received
+// Params: BT_HDR* packet
+// Returns: void
+struct sco_data_received {
+ std::function<void(BT_HDR* packet)> body{[](BT_HDR* packet) {}};
+ void operator()(BT_HDR* packet) { body(packet); };
+};
+extern struct sco_data_received sco_data_received;
+// Name: iso_data_received
+// Params: BT_HDR* packet
+// Returns: void
+struct iso_data_received {
+ std::function<void(BT_HDR* packet)> body{[](BT_HDR* packet) {}};
+ void operator()(BT_HDR* packet) { body(packet); };
+};
+extern struct iso_data_received iso_data_received;
+// Name: hal_service_died
+// Params:
+// Returns: void
+struct hal_service_died {
+ std::function<void()> body{[]() {}};
+ void operator()() { body(); };
+};
+extern struct hal_service_died hal_service_died;
+// Name: process_command_credits
+// Params: int credits
+// Returns: void
+struct process_command_credits {
+ std::function<void(int credits)> body{[](int credits) {}};
+ void operator()(int credits) { body(credits); };
+};
+extern struct process_command_credits process_command_credits;
+// Name: hci_is_root_inflammation_event_received
+// Params:
+// Returns: bool
+struct hci_is_root_inflammation_event_received {
+ std::function<bool()> body{[]() { return false; }};
+ bool operator()() { return body(); };
+};
+extern struct hci_is_root_inflammation_event_received
+ hci_is_root_inflammation_event_received;
+// Name: handle_root_inflammation_event
+// Params:
+// Returns: void
+struct handle_root_inflammation_event {
+ std::function<void()> body{[]() {}};
+ void operator()() { body(); };
+};
+extern struct handle_root_inflammation_event handle_root_inflammation_event;
+// Name: hci_layer_cleanup_interface
+// Params:
+// Returns: void
+struct hci_layer_cleanup_interface {
+ std::function<void()> body{[]() {}};
+ void operator()() { body(); };
+};
+extern struct hci_layer_cleanup_interface hci_layer_cleanup_interface;
+// Name: hci_layer_get_interface
+// Params:
+// Returns: const hci_t*
+struct hci_layer_get_interface {
+ hci_t* hci;
+ std::function<const hci_t*()> body{[this]() { return hci; }};
+ const hci_t* operator()() { return body(); };
+};
+extern struct hci_layer_get_interface hci_layer_get_interface;
+// Name: hci_layer_get_test_interface
+// Params: const allocator_t* buffer_allocator_interface, const btsnoop_t*
+// btsnoop_interface, const packet_fragmenter_t* packet_fragmenter_interface
+// Returns: const hci_t*
+struct hci_layer_get_test_interface {
+ std::function<const hci_t*(
+ const allocator_t* buffer_allocator_interface,
+ const btsnoop_t* btsnoop_interface,
+ const packet_fragmenter_t* packet_fragmenter_interface)>
+ body{[](const allocator_t* buffer_allocator_interface,
+ const btsnoop_t* btsnoop_interface,
+ const packet_fragmenter_t* packet_fragmenter_interface) {
+ return nullptr;
+ }};
+ const hci_t* operator()(
+ const allocator_t* buffer_allocator_interface,
+ const btsnoop_t* btsnoop_interface,
+ const packet_fragmenter_t* packet_fragmenter_interface) {
+ return body(buffer_allocator_interface, btsnoop_interface,
+ packet_fragmenter_interface);
+ };
+};
+extern struct hci_layer_get_test_interface hci_layer_get_test_interface;
+
+} // namespace hci_layer
+} // namespace mock
+} // namespace test
+
+// END mockcify generation
diff --git a/test/mock/mock_hci_packet_factory.cc b/test/mock/mock_hci_packet_factory.cc
index 4c28831..a80f17c 100644
--- a/test/mock/mock_hci_packet_factory.cc
+++ b/test/mock/mock_hci_packet_factory.cc
@@ -24,15 +24,7 @@
extern std::map<std::string, int> mock_function_count_map;
-#include <base/logging.h>
-#include "bt_types.h"
-#include "buffer_allocator.h"
-#include "hci_internals.h"
-#include "hci_layer.h"
-#include "hci_packet_factory.h"
-#include "hcidefs.h"
-#include "hcimsgs.h"
-#include "osi/include/allocator.h"
+#include "hci/include/hci_packet_factory.h"
#ifndef UNUSED_ATTR
#define UNUSED_ATTR
diff --git a/stack/test/common/mock_hcic_hciblecmds.cc b/test/mock/mock_hcic_hciblecmds.cc
similarity index 100%
rename from stack/test/common/mock_hcic_hciblecmds.cc
rename to test/mock/mock_hcic_hciblecmds.cc
diff --git a/main/test/common/mock_hcic_hcicmds.cc b/test/mock/mock_hcic_hcicmds.cc
similarity index 95%
rename from main/test/common/mock_hcic_hcicmds.cc
rename to test/mock/mock_hcic_hcicmds.cc
index 18c8416..1b3f9d9 100644
--- a/main/test/common/mock_hcic_hcicmds.cc
+++ b/test/mock/mock_hcic_hcicmds.cc
@@ -26,13 +26,31 @@
#define UNUSED_ATTR
#include <stddef.h>
-#include <string.h>
+#include "types/raw_address.h"
+
#include "bt_common.h"
#include "bt_target.h"
#include "btu.h"
#include "hcidefs.h"
#include "hcimsgs.h"
#include "stack/include/acl_hci_link_interface.h"
+
+namespace test {
+namespace mock {
+namespace hcic_hcicmds {
+
+struct btsnd_hcic_change_conn_type {
+ uint16_t handle{0};
+ uint16_t packet_types{0};
+} btsnd_hcic_change_conn_type;
+
+} // namespace hcic_hcicmds
+} // namespace mock
+} // namespace test
+
+namespace mock = test::mock::hcic_hcicmds;
+
+// Global by definition
void btsnd_hcic_accept_conn(const RawAddress& dest, uint8_t role) {
mock_function_count_map[__func__]++;
}
@@ -51,6 +69,8 @@
mock_function_count_map[__func__]++;
}
void btsnd_hcic_change_conn_type(uint16_t handle, uint16_t packet_types) {
+ mock::btsnd_hcic_change_conn_type.handle = handle;
+ mock::btsnd_hcic_change_conn_type.packet_types = packet_types;
mock_function_count_map[__func__]++;
}
void btsnd_hcic_change_name(BD_NAME name) {
@@ -296,6 +316,7 @@
bluetooth::legacy::hci::Interface interface_ = {
.Disconnect = btsnd_hcic_disconnect,
.StartRoleSwitch = btsnd_hcic_switch_role,
+ .ChangeConnectionPacketType = btsnd_hcic_change_conn_type,
};
const bluetooth::legacy::hci::Interface&
diff --git a/test/mock/mock_hcic_hcicmds.h b/test/mock/mock_hcic_hcicmds.h
new file mode 100644
index 0000000..980189b
--- /dev/null
+++ b/test/mock/mock_hcic_hcicmds.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:1
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+namespace test {
+namespace mock {
+namespace hcic_hcicmds {
+
+struct btsnd_hcic_change_conn_type {
+ uint16_t handle;
+ uint16_t packet_types;
+};
+extern struct btsnd_hcic_change_conn_type btsnd_hcic_change_conn_type;
+
+} // namespace hcic_hcicmds
+} // namespace mock
+} // namespace test
+
+// END mockcify generation
diff --git a/test/mock/mock_l2cap_l2c_api.cc b/test/mock/mock_l2cap_l2c_api.cc
deleted file mode 100644
index 85f2f4f..0000000
--- a/test/mock/mock_l2cap_l2c_api.cc
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:33
- */
-
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-#include <cstdint>
-#include "stack/include/l2c_api.h"
-#include "types/raw_address.h"
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-bool L2CA_ConnectCreditBasedRsp(const RawAddress& p_bd_addr, uint8_t id,
- std::vector<uint16_t>& accepted_lcids,
- uint16_t result, tL2CAP_LE_CFG_INFO* p_cfg) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_ConnectFixedChnl(uint16_t fixed_cid, const RawAddress& rem_bda) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_DisconnectLECocReq(uint16_t cid) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_DisconnectReq(uint16_t cid) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_GetPeerFeatures(const RawAddress& bd_addr, uint32_t* p_ext_feat,
- uint8_t* p_chnl_mask) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_GetPeerLECocConfig(uint16_t lcid, tL2CAP_LE_CFG_INFO* peer_cfg) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_GetRemoteCid(uint16_t lcid, uint16_t* rcid) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_IsLinkEstablished(const RawAddress& bd_addr,
- tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_ReconfigCreditBasedConnsReq(const RawAddress& bda,
- std::vector<uint16_t>& lcids,
- tL2CAP_LE_CFG_INFO* p_cfg) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_RegisterFixedChannel(uint16_t fixed_cid,
- tL2CAP_FIXED_CHNL_REG* p_freg) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_RemoveFixedChnl(uint16_t fixed_cid, const RawAddress& rem_bda) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_SetAclPriority(const RawAddress& bd_addr, tL2CAP_PRIORITY priority) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_SetChnlFlushability(uint16_t cid, bool is_flushable) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_SetLeGattTimeout(const RawAddress& rem_bda, uint16_t idle_tout) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_SetIdleTimeoutByBdAddr(const RawAddress& bd_addr, uint16_t timeout,
- tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_SetTxPriority(uint16_t cid, tL2CAP_CHNL_PRIORITY priority) {
- mock_function_count_map[__func__]++;
- return false;
-}
-std::vector<uint16_t> L2CA_ConnectCreditBasedReq(uint16_t psm,
- const RawAddress& p_bd_addr,
- tL2CAP_LE_CFG_INFO* p_cfg) {
- mock_function_count_map[__func__]++;
- std::vector<uint16_t> v;
- return v;
-}
-tBT_TRANSPORT l2c_get_transport_from_fixed_cid(uint16_t fixed_cid) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint16_t L2CA_AllocateLePSM(void) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint16_t L2CA_ConnectLECocReq(uint16_t psm, const RawAddress& p_bd_addr,
- tL2CAP_LE_CFG_INFO* p_cfg, uint16_t sec_level) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint16_t L2CA_ConnectReq(uint16_t psm, const RawAddress& p_bd_addr) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint16_t L2CA_ConnectReq2(uint16_t psm, const RawAddress& p_bd_addr,
- uint16_t sec_level) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint16_t L2CA_FlushChannel(uint16_t lcid, uint16_t num_to_flush) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint16_t L2CA_Register(uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info,
- bool enable_snoop, tL2CAP_ERTM_INFO* p_ertm_info,
- uint16_t my_mtu, uint16_t required_remote_mtu) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint16_t L2CA_Register2(uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info,
- bool enable_snoop, tL2CAP_ERTM_INFO* p_ertm_info,
- uint16_t my_mtu, uint16_t required_remote_mtu,
- uint16_t sec_level) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint16_t L2CA_RegisterLECoc(uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info,
- uint16_t sec_level, tL2CAP_LE_CFG_INFO cfg) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint16_t L2CA_SendFixedChnlData(uint16_t fixed_cid, const RawAddress& rem_bda,
- BT_HDR* p_buf) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint8_t L2CA_DataWrite(uint16_t cid, BT_HDR* p_data) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint8_t L2CA_LECocDataWrite(uint16_t cid, BT_HDR* p_data) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint8_t L2CA_SetTraceLevel(uint8_t new_level) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-void L2CA_Deregister(uint16_t psm) { mock_function_count_map[__func__]++; }
-void L2CA_DeregisterLECoc(uint16_t psm) { mock_function_count_map[__func__]++; }
-void L2CA_FreeLePSM(uint16_t psm) { mock_function_count_map[__func__]++; }
diff --git a/test/mock/mock_l2cap_main.cc b/test/mock/mock_l2cap_main.cc
deleted file mode 100644
index 677858e..0000000
--- a/test/mock/mock_l2cap_main.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- * Functions generated:9
- */
-
-#include <map>
-#include <string>
-
-extern std::map<std::string, int> mock_function_count_map;
-
-#include <string.h>
-#include "bt_common.h"
-#include "bt_target.h"
-#include "hci/include/btsnoop.h"
-#include "hcimsgs.h"
-#include "l2c_api.h"
-#include "l2c_int.h"
-#include "l2cdefs.h"
-#include "main/shim/shim.h"
-#include "osi/include/log.h"
-#include "osi/include/osi.h"
-
-#ifndef UNUSED_ATTR
-#define UNUSED_ATTR
-#endif
-
-uint8_t l2c_data_write(uint16_t cid, BT_HDR* p_data, uint16_t flags) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-void l2c_ccb_timer_timeout(void* data) { mock_function_count_map[__func__]++; }
-void l2c_fcrb_ack_timer_timeout(void* data) {
- mock_function_count_map[__func__]++;
-}
-void l2c_free(void) { mock_function_count_map[__func__]++; }
-void l2c_init(void) { mock_function_count_map[__func__]++; }
-void l2c_lcb_timer_timeout(void* data) { mock_function_count_map[__func__]++; }
-void l2c_process_held_packets(bool timed_out) {
- mock_function_count_map[__func__]++;
-}
-void l2c_rcv_acl_data(BT_HDR* p_msg) { mock_function_count_map[__func__]++; }
-void l2c_receive_hold_timer_timeout(UNUSED_ATTR void* data) {
- mock_function_count_map[__func__]++;
-}
diff --git a/test/mock/mock_main_bte.cc b/test/mock/mock_main_bte.cc
new file mode 100644
index 0000000..c0734f5
--- /dev/null
+++ b/test/mock/mock_main_bte.cc
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:3
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <cstdint>
+#include <functional>
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Mock include file to share data between tests and mock
+#include "test/mock/mock_main_bte.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+// Mocked internal structures, if any
+
+namespace test {
+namespace mock {
+namespace main_bte {
+
+// Function state capture and return values, if needed
+struct post_to_main_message_loop post_to_main_message_loop;
+struct bte_main_init bte_main_init;
+struct bte_main_hci_send bte_main_hci_send;
+
+} // namespace main_bte
+} // namespace mock
+} // namespace test
+
+// Mocked functions, if any
+void post_to_main_message_loop(const base::Location& from_here, BT_HDR* p_msg) {
+ mock_function_count_map[__func__]++;
+ test::mock::main_bte::post_to_main_message_loop(from_here, p_msg);
+}
+void bte_main_init(void) {
+ mock_function_count_map[__func__]++;
+ test::mock::main_bte::bte_main_init();
+}
+void bte_main_hci_send(BT_HDR* p_msg, uint16_t event) {
+ mock_function_count_map[__func__]++;
+ test::mock::main_bte::bte_main_hci_send(p_msg, event);
+}
+
+// END mockcify generation
diff --git a/test/mock/mock_main_bte.h b/test/mock/mock_main_bte.h
new file mode 100644
index 0000000..3ef95e1
--- /dev/null
+++ b/test/mock/mock_main_bte.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:3
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <cstdint>
+#include <functional>
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+#include <base/logging.h>
+#include <hardware/bluetooth.h>
+#include "bt_common.h"
+#include "btcore/include/module.h"
+#include "bte.h"
+#include "btif/include/btif_config.h"
+#include "btu.h"
+#include "device/include/interop.h"
+#include "hci/include/btsnoop.h"
+#include "hci/include/hci_layer.h"
+#include "main/shim/hci_layer.h"
+#include "main/shim/shim.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "stack_config.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+namespace test {
+namespace mock {
+namespace main_bte {
+
+// Shared state between mocked functions and tests
+// Name: post_to_main_message_loop
+// Params: const base::Location& from_here, BT_HDR* p_msg
+// Returns: void
+struct post_to_main_message_loop {
+ std::function<void(const base::Location& from_here, BT_HDR* p_msg)> body{
+ [](const base::Location& from_here, BT_HDR* p_msg) {}};
+ void operator()(const base::Location& from_here, BT_HDR* p_msg) {
+ body(from_here, p_msg);
+ };
+};
+extern struct post_to_main_message_loop post_to_main_message_loop;
+// Name: bte_main_init
+// Params: void
+// Returns: void
+struct bte_main_init {
+ std::function<void(void)> body{[](void) {}};
+ void operator()(void) { body(); };
+};
+extern struct bte_main_init bte_main_init;
+// Name: bte_main_hci_send
+// Params: BT_HDR* p_msg, uint16_t event
+// Returns: void
+struct bte_main_hci_send {
+ std::function<void(BT_HDR* p_msg, uint16_t event)> body{
+ [](BT_HDR* p_msg, uint16_t event) {}};
+ void operator()(BT_HDR* p_msg, uint16_t event) { body(p_msg, event); };
+};
+extern struct bte_main_hci_send bte_main_hci_send;
+
+} // namespace main_bte
+} // namespace mock
+} // namespace test
+
+// END mockcify generation
diff --git a/bta/test/common/mock_stack_gatt_connection_manager.cc b/test/mock/mock_main_shim_acl.cc
similarity index 77%
rename from bta/test/common/mock_stack_gatt_connection_manager.cc
rename to test/mock/mock_main_shim_acl.cc
index 1c4887c..ae7c9e5 100644
--- a/bta/test/common/mock_stack_gatt_connection_manager.cc
+++ b/test/mock/mock_main_shim_acl.cc
@@ -16,22 +16,21 @@
/*
* Generated mock file from original source file
- * Functions generated:4
+ * Functions generated:7
*/
+#include <cstdint>
#include <map>
#include <string>
extern std::map<std::string, int> mock_function_count_map;
-#include "stack/gatt/connection_manager.h"
+#include "main/shim/acl_api.h"
+#include "types/ble_address_with_type.h"
+#include "types/raw_address.h"
#ifndef UNUSED_ATTR
#define UNUSED_ATTR
#endif
-namespace connection_manager {
-
-void reset(bool after_reset) { mock_function_count_map[__func__]++; }
-
-} // namespace connection_manager
+void bluetooth::shim::ACL_Shutdown() { mock_function_count_map[__func__]++; }
diff --git a/stack/test/common/mock_main_shim_acl_api.cc b/test/mock/mock_main_shim_acl_api.cc
similarity index 93%
rename from stack/test/common/mock_main_shim_acl_api.cc
rename to test/mock/mock_main_shim_acl_api.cc
index b5bf4a2..3073c07 100644
--- a/stack/test/common/mock_main_shim_acl_api.cc
+++ b/test/mock/mock_main_shim_acl_api.cc
@@ -43,7 +43,7 @@
mock_function_count_map[__func__]++;
}
bool bluetooth::shim::ACL_AcceptLeConnectionFrom(
- const tBLE_BD_ADDR& legacy_address_with_type) {
+ const tBLE_BD_ADDR& legacy_address_with_type, bool is_direct) {
mock_function_count_map[__func__]++;
return true;
}
@@ -54,7 +54,7 @@
void bluetooth::shim::ACL_ConfigureLePrivacy(bool is_le_privacy_enabled) {
mock_function_count_map[__func__]++;
}
-void bluetooth::shim::ACL_WriteData(uint16_t handle, const BT_HDR* p_buf) {
+void bluetooth::shim::ACL_WriteData(uint16_t handle, BT_HDR* p_buf) {
mock_function_count_map[__func__]++;
}
void bluetooth::shim::ACL_Disconnect(uint16_t handle, bool is_classic,
diff --git a/bta/test/common/mock_main_shim_btm_api.cc b/test/mock/mock_main_shim_btm_api.cc
similarity index 100%
rename from bta/test/common/mock_main_shim_btm_api.cc
rename to test/mock/mock_main_shim_btm_api.cc
diff --git a/main/test/common/mock_entry.cc b/test/mock/mock_main_shim_entry.cc
similarity index 89%
rename from main/test/common/mock_entry.cc
rename to test/mock/mock_main_shim_entry.cc
index 24ef156..13cd5f3 100644
--- a/main/test/common/mock_entry.cc
+++ b/test/mock/mock_main_shim_entry.cc
@@ -14,7 +14,9 @@
* limitations under the License.
*/
-#include "gd/btaa/activity_attribution.h"
+// #include "gd/btaa/activity_attribution.h"
+#include "gd/module.h"
+
#include "gd/hci/acl_manager_mock.h"
#include "gd/hci/controller_mock.h"
#include "gd/hci/hci_layer.h"
@@ -30,7 +32,6 @@
#include "gd/security/security_module.h"
#include "gd/shim/dumpsys.h"
#include "gd/storage/storage_module.h"
-#include "hci/acl_manager.h"
#include "main/shim/entry.h"
#include "main/shim/stack.h"
@@ -40,16 +41,11 @@
MockAclManager* mock_acl_manager_{nullptr};
MockController* mock_controller_{nullptr};
+os::Handler* mock_gd_shim_handler_{nullptr};
} // namespace testing
} // namespace hci
-namespace legacy {
-namespace testing {
-// os::Handler* mock_handler_ { nullptr };
-}
-} // namespace legacy
-
namespace shim {
Dumpsys* GetDumpsys() { return nullptr; }
@@ -61,6 +57,9 @@
hci::HciLayer* GetHciLayer() { return nullptr; }
hci::LeAdvertisingManager* GetAdvertising() { return nullptr; }
hci::LeScanningManager* GetScanning() { return nullptr; }
+hci::VendorSpecificEventManager* GetVendorSpecificEventManager() {
+ return nullptr;
+}
l2cap::classic::L2capClassicModule* GetL2capClassicModule() { return nullptr; }
l2cap::le::L2capLeModule* GetL2capLeModule() { return nullptr; }
neighbor::ConnectabilityModule* GetConnectability() { return nullptr; }
@@ -68,7 +67,7 @@
neighbor::InquiryModule* GetInquiry() { return nullptr; }
neighbor::NameModule* GetName() { return nullptr; }
neighbor::PageModule* GetPage() { return nullptr; }
-os::Handler* GetGdShimHandler() { return Stack::GetInstance()->GetHandler(); }
+os::Handler* GetGdShimHandler() { return hci::testing::mock_gd_shim_handler_; }
security::SecurityModule* GetSecurityModule() { return nullptr; }
storage::StorageModule* GetStorage() { return nullptr; }
diff --git a/gd/shim/only_include_this_file_into_legacy_stack___ever.h b/test/mock/mock_main_shim_entry.h
similarity index 63%
rename from gd/shim/only_include_this_file_into_legacy_stack___ever.h
rename to test/mock/mock_main_shim_entry.h
index 5658ce8..4f6aa70 100644
--- a/gd/shim/only_include_this_file_into_legacy_stack___ever.h
+++ b/test/mock/mock_main_shim_entry.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,18 +14,13 @@
* limitations under the License.
*/
-#pragma once
-
-/**
- * This common file provides the only visibility from the legacy stack into GD stack.
- *
- * Only interfaces or APIs should be exported.
- *
- * Only common data structures should be used to pass data between the stacks.
- *
- */
namespace bluetooth {
-namespace shim {
-class Dumpsys;
-} // namespace shim
+namespace hci {
+namespace testing {
+
+extern MockAclManager* mock_acl_manager_;
+extern MockController* mock_controller_;
+
+} // namespace testing
+} // namespace hci
} // namespace bluetooth
diff --git a/test/mock/mock_main_shim_l2cap_api.cc b/test/mock/mock_main_shim_l2cap_api.cc
new file mode 100644
index 0000000..d934cac
--- /dev/null
+++ b/test/mock/mock_main_shim_l2cap_api.cc
@@ -0,0 +1,343 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:45
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <cstdint>
+#include <functional>
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Mock include file to share data between tests and mock
+#include "test/mock/mock_main_shim_l2cap_api.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+// Mocked internal structures, if any
+
+namespace test {
+namespace mock {
+namespace main_shim_l2cap_api {
+
+// Function state capture and return values, if needed
+struct L2CA_ReadRemoteVersion L2CA_ReadRemoteVersion;
+struct L2CA_ReadRemoteFeatures L2CA_ReadRemoteFeatures;
+struct L2CA_UseLegacySecurityModule L2CA_UseLegacySecurityModule;
+struct L2CA_Register L2CA_Register;
+struct L2CA_Deregister L2CA_Deregister;
+struct L2CA_ConnectReq L2CA_ConnectReq;
+struct L2CA_DisconnectReq L2CA_DisconnectReq;
+struct L2CA_DataWrite L2CA_DataWrite;
+struct L2CA_ReconfigCreditBasedConnsReq L2CA_ReconfigCreditBasedConnsReq;
+struct L2CA_ConnectCreditBasedReq L2CA_ConnectCreditBasedReq;
+struct L2CA_ConnectCreditBasedRsp L2CA_ConnectCreditBasedRsp;
+struct L2CA_SetIdleTimeoutByBdAddr L2CA_SetIdleTimeoutByBdAddr;
+struct L2CA_SetAclPriority L2CA_SetAclPriority;
+struct L2CA_SetAclPriority2 L2CA_SetAclPriority2;
+struct L2CA_GetPeerFeatures L2CA_GetPeerFeatures;
+struct L2CA_RegisterFixedChannel L2CA_RegisterFixedChannel;
+struct L2CA_ConnectFixedChnl L2CA_ConnectFixedChnl;
+struct L2CA_SendFixedChnlData L2CA_SendFixedChnlData;
+struct L2CA_RemoveFixedChnl L2CA_RemoveFixedChnl;
+struct L2CA_GetLeHandle L2CA_GetLeHandle;
+struct L2CA_LeConnectionUpdate L2CA_LeConnectionUpdate;
+struct L2CA_EnableUpdateBleConnParams L2CA_EnableUpdateBleConnParams;
+struct L2CA_GetRemoteCid L2CA_GetRemoteCid;
+struct L2CA_SetTxPriority L2CA_SetTxPriority;
+struct L2CA_SetLeGattTimeout L2CA_SetLeGattTimeout;
+struct L2CA_SetChnlFlushability L2CA_SetChnlFlushability;
+struct L2CA_FlushChannel L2CA_FlushChannel;
+struct L2CA_IsLinkEstablished L2CA_IsLinkEstablished;
+struct L2CA_IsLeLink L2CA_IsLeLink;
+struct L2CA_ReadConnectionAddr L2CA_ReadConnectionAddr;
+struct L2CA_ReadRemoteConnectionAddr L2CA_ReadRemoteConnectionAddr;
+struct L2CA_GetBleConnRole L2CA_GetBleConnRole;
+struct L2CA_ConnectForSecurity L2CA_ConnectForSecurity;
+struct L2CA_SetBondingState L2CA_SetBondingState;
+struct L2CA_DisconnectLink L2CA_DisconnectLink;
+struct L2CA_GetNumLinks L2CA_GetNumLinks;
+struct L2CA_AllocateLePSM L2CA_AllocateLePSM;
+struct L2CA_FreeLePSM L2CA_FreeLePSM;
+struct L2CA_RegisterLECoc L2CA_RegisterLECoc;
+struct L2CA_DeregisterLECoc L2CA_DeregisterLECoc;
+struct L2CA_ConnectLECocReq L2CA_ConnectLECocReq;
+struct L2CA_GetPeerLECocConfig L2CA_GetPeerLECocConfig;
+struct L2CA_DisconnectLECocReq L2CA_DisconnectLECocReq;
+struct L2CA_LECocDataWrite L2CA_LECocDataWrite;
+struct L2CA_SwitchRoleToCentral L2CA_SwitchRoleToCentral;
+
+} // namespace main_shim_l2cap_api
+} // namespace mock
+} // namespace test
+
+// Mocked functions, if any
+bool bluetooth::shim::L2CA_ReadRemoteVersion(const RawAddress& addr,
+ uint8_t* lmp_version,
+ uint16_t* manufacturer,
+ uint16_t* lmp_sub_version) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_ReadRemoteVersion(
+ addr, lmp_version, manufacturer, lmp_sub_version);
+}
+uint8_t* bluetooth::shim::L2CA_ReadRemoteFeatures(const RawAddress& addr) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_ReadRemoteFeatures(addr);
+}
+void bluetooth::shim::L2CA_UseLegacySecurityModule() {
+ mock_function_count_map[__func__]++;
+ test::mock::main_shim_l2cap_api::L2CA_UseLegacySecurityModule();
+}
+uint16_t bluetooth::shim::L2CA_Register(
+ uint16_t client_psm, const tL2CAP_APPL_INFO& callbacks, bool enable_snoop,
+ tL2CAP_ERTM_INFO* p_ertm_info, uint16_t my_mtu,
+ uint16_t required_remote_mtu, uint16_t sec_level) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_Register(
+ client_psm, callbacks, enable_snoop, p_ertm_info, my_mtu,
+ required_remote_mtu, sec_level);
+}
+void bluetooth::shim::L2CA_Deregister(uint16_t psm) {
+ mock_function_count_map[__func__]++;
+ test::mock::main_shim_l2cap_api::L2CA_Deregister(psm);
+}
+uint16_t bluetooth::shim::L2CA_ConnectReq(uint16_t psm,
+ const RawAddress& raw_address) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_ConnectReq(psm, raw_address);
+}
+bool bluetooth::shim::L2CA_DisconnectReq(uint16_t cid) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_DisconnectReq(cid);
+}
+uint8_t bluetooth::shim::L2CA_DataWrite(uint16_t cid, BT_HDR* p_data) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_DataWrite(cid, p_data);
+}
+bool bluetooth::shim::L2CA_ReconfigCreditBasedConnsReq(
+ const RawAddress& bd_addr, std::vector<uint16_t>& lcids,
+ tL2CAP_LE_CFG_INFO* p_cfg) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_ReconfigCreditBasedConnsReq(
+ bd_addr, lcids, p_cfg);
+}
+std::vector<uint16_t> bluetooth::shim::L2CA_ConnectCreditBasedReq(
+ uint16_t psm, const RawAddress& p_bd_addr, tL2CAP_LE_CFG_INFO* p_cfg) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_ConnectCreditBasedReq(
+ psm, p_bd_addr, p_cfg);
+}
+bool bluetooth::shim::L2CA_ConnectCreditBasedRsp(
+ const RawAddress& bd_addr, uint8_t id,
+ std::vector<uint16_t>& accepted_lcids, uint16_t result,
+ tL2CAP_LE_CFG_INFO* p_cfg) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_ConnectCreditBasedRsp(
+ bd_addr, id, accepted_lcids, result, p_cfg);
+}
+bool bluetooth::shim::L2CA_SetIdleTimeoutByBdAddr(const RawAddress& bd_addr,
+ uint16_t timeout,
+ tBT_TRANSPORT transport) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_SetIdleTimeoutByBdAddr(
+ bd_addr, timeout, transport);
+}
+bool bluetooth::shim::L2CA_SetAclPriority(uint16_t handle, bool high_priority) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_SetAclPriority(handle,
+ high_priority);
+}
+bool bluetooth::shim::L2CA_SetAclPriority(const RawAddress& bd_addr,
+ tL2CAP_PRIORITY priority) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_SetAclPriority2(bd_addr,
+ priority);
+}
+bool bluetooth::shim::L2CA_GetPeerFeatures(const RawAddress& bd_addr,
+ uint32_t* p_ext_feat,
+ uint8_t* p_chnl_mask) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_GetPeerFeatures(
+ bd_addr, p_ext_feat, p_chnl_mask);
+}
+bool bluetooth::shim::L2CA_RegisterFixedChannel(uint16_t cid,
+ tL2CAP_FIXED_CHNL_REG* p_freg) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_RegisterFixedChannel(cid,
+ p_freg);
+}
+bool bluetooth::shim::L2CA_ConnectFixedChnl(uint16_t cid,
+ const RawAddress& rem_bda) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_ConnectFixedChnl(cid, rem_bda);
+}
+uint16_t bluetooth::shim::L2CA_SendFixedChnlData(uint16_t cid,
+ const RawAddress& rem_bda,
+ BT_HDR* p_buf) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_SendFixedChnlData(cid, rem_bda,
+ p_buf);
+}
+bool bluetooth::shim::L2CA_RemoveFixedChnl(uint16_t cid,
+ const RawAddress& rem_bda) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_RemoveFixedChnl(cid, rem_bda);
+}
+uint16_t bluetooth::shim::L2CA_GetLeHandle(const RawAddress& rem_bda) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_GetLeHandle(rem_bda);
+}
+void bluetooth::shim::L2CA_LeConnectionUpdate(
+ const RawAddress& rem_bda, uint16_t min_int, uint16_t max_int,
+ uint16_t latency, uint16_t timeout, uint16_t min_ce_len,
+ uint16_t max_ce_len) {
+ mock_function_count_map[__func__]++;
+ test::mock::main_shim_l2cap_api::L2CA_LeConnectionUpdate(
+ rem_bda, min_int, max_int, latency, timeout, min_ce_len, max_ce_len);
+}
+bool bluetooth::shim::L2CA_EnableUpdateBleConnParams(const RawAddress& rem_bda,
+ bool enable) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_EnableUpdateBleConnParams(
+ rem_bda, enable);
+}
+bool bluetooth::shim::L2CA_GetRemoteCid(uint16_t lcid, uint16_t* rcid) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_GetRemoteCid(lcid, rcid);
+}
+bool bluetooth::shim::L2CA_SetTxPriority(uint16_t cid,
+ tL2CAP_CHNL_PRIORITY priority) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_SetTxPriority(cid, priority);
+}
+bool bluetooth::shim::L2CA_SetLeGattTimeout(const RawAddress& rem_bda,
+ uint16_t idle_tout) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_SetLeGattTimeout(rem_bda,
+ idle_tout);
+}
+bool bluetooth::shim::L2CA_SetChnlFlushability(uint16_t cid,
+ bool is_flushable) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_SetChnlFlushability(
+ cid, is_flushable);
+}
+uint16_t bluetooth::shim::L2CA_FlushChannel(uint16_t lcid,
+ uint16_t num_to_flush) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_FlushChannel(lcid, num_to_flush);
+}
+bool bluetooth::shim::L2CA_IsLinkEstablished(const RawAddress& bd_addr,
+ tBT_TRANSPORT transport) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_IsLinkEstablished(bd_addr,
+ transport);
+}
+bool bluetooth::shim::L2CA_IsLeLink(uint16_t acl_handle) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_IsLeLink(acl_handle);
+}
+void bluetooth::shim::L2CA_ReadConnectionAddr(const RawAddress& pseudo_addr,
+ RawAddress& conn_addr,
+ uint8_t* p_addr_type) {
+ mock_function_count_map[__func__]++;
+ test::mock::main_shim_l2cap_api::L2CA_ReadConnectionAddr(
+ pseudo_addr, conn_addr, p_addr_type);
+}
+bool bluetooth::shim::L2CA_ReadRemoteConnectionAddr(
+ const RawAddress& pseudo_addr, RawAddress& conn_addr,
+ uint8_t* p_addr_type) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_ReadRemoteConnectionAddr(
+ pseudo_addr, conn_addr, p_addr_type);
+}
+hci_role_t bluetooth::shim::L2CA_GetBleConnRole(const RawAddress& bd_addr) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_GetBleConnRole(bd_addr);
+}
+void bluetooth::shim::L2CA_ConnectForSecurity(const RawAddress& bd_addr) {
+ mock_function_count_map[__func__]++;
+ test::mock::main_shim_l2cap_api::L2CA_ConnectForSecurity(bd_addr);
+}
+void bluetooth::shim::L2CA_SetBondingState(const RawAddress& bd_addr,
+ bool is_bonding) {
+ mock_function_count_map[__func__]++;
+ test::mock::main_shim_l2cap_api::L2CA_SetBondingState(bd_addr, is_bonding);
+}
+void bluetooth::shim::L2CA_DisconnectLink(const RawAddress& remote) {
+ mock_function_count_map[__func__]++;
+ test::mock::main_shim_l2cap_api::L2CA_DisconnectLink(remote);
+}
+uint16_t bluetooth::shim::L2CA_GetNumLinks() {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_GetNumLinks();
+}
+uint16_t bluetooth::shim::L2CA_AllocateLePSM() {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_AllocateLePSM();
+}
+void bluetooth::shim::L2CA_FreeLePSM(uint16_t psm) {
+ mock_function_count_map[__func__]++;
+ test::mock::main_shim_l2cap_api::L2CA_FreeLePSM(psm);
+}
+uint16_t bluetooth::shim::L2CA_RegisterLECoc(uint16_t psm,
+ const tL2CAP_APPL_INFO& callbacks,
+ uint16_t sec_level,
+ tL2CAP_LE_CFG_INFO cfg) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_RegisterLECoc(psm, callbacks,
+ sec_level, cfg);
+}
+void bluetooth::shim::L2CA_DeregisterLECoc(uint16_t psm) {
+ mock_function_count_map[__func__]++;
+ test::mock::main_shim_l2cap_api::L2CA_DeregisterLECoc(psm);
+}
+uint16_t bluetooth::shim::L2CA_ConnectLECocReq(uint16_t psm,
+ const RawAddress& p_bd_addr,
+ tL2CAP_LE_CFG_INFO* p_cfg) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_ConnectLECocReq(psm, p_bd_addr,
+ p_cfg);
+}
+bool bluetooth::shim::L2CA_GetPeerLECocConfig(uint16_t cid,
+ tL2CAP_LE_CFG_INFO* peer_cfg) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_GetPeerLECocConfig(cid,
+ peer_cfg);
+}
+bool bluetooth::shim::L2CA_DisconnectLECocReq(uint16_t cid) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_DisconnectLECocReq(cid);
+}
+uint8_t bluetooth::shim::L2CA_LECocDataWrite(uint16_t cid, BT_HDR* p_data) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_l2cap_api::L2CA_LECocDataWrite(cid, p_data);
+}
+void bluetooth::shim::L2CA_SwitchRoleToCentral(const RawAddress& addr) {
+ mock_function_count_map[__func__]++;
+ test::mock::main_shim_l2cap_api::L2CA_SwitchRoleToCentral(addr);
+}
+
+// END mockcify generation
diff --git a/test/mock/mock_main_shim_l2cap_api.h b/test/mock/mock_main_shim_l2cap_api.h
new file mode 100644
index 0000000..778ddbc
--- /dev/null
+++ b/test/mock/mock_main_shim_l2cap_api.h
@@ -0,0 +1,590 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:45
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <cstdint>
+#include <functional>
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+#include "gd/module.h"
+
+#include <future>
+#include <unordered_map>
+#include <unordered_set>
+#include "bta/include/bta_dm_acl.h"
+#include "gd/l2cap/classic/l2cap_classic_module.h"
+#include "gd/l2cap/le/l2cap_le_module.h"
+#include "gd/os/log.h"
+#include "gd/os/queue.h"
+#include "main/shim/acl_api.h"
+#include "main/shim/btm.h"
+#include "main/shim/entry.h"
+#include "main/shim/helpers.h"
+#include "main/shim/l2c_api.h"
+#include "main/shim/stack.h"
+#include "osi/include/allocator.h"
+#include "stack/btm/btm_ble_int.h"
+#include "stack/btm/btm_sec.h"
+#include "stack/include/acl_hci_link_interface.h"
+#include "stack/include/ble_acl_interface.h"
+#include "stack/include/btm_api.h"
+#include "stack/include/btu.h"
+#include "stack/include/gatt_api.h"
+#include "stack/include/sco_hci_link_interface.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+namespace test {
+namespace mock {
+namespace main_shim_l2cap_api {
+
+// Shared state between mocked functions and tests
+// Name: L2CA_ReadRemoteVersion
+// Params: const RawAddress& addr, uint8_t* lmp_version, uint16_t* manufacturer,
+// uint16_t* lmp_sub_version Returns: bool
+struct L2CA_ReadRemoteVersion {
+ std::function<bool(const RawAddress& addr, uint8_t* lmp_version,
+ uint16_t* manufacturer, uint16_t* lmp_sub_version)>
+ body{[](const RawAddress& addr, uint8_t* lmp_version,
+ uint16_t* manufacturer,
+ uint16_t* lmp_sub_version) { return false; }};
+ bool operator()(const RawAddress& addr, uint8_t* lmp_version,
+ uint16_t* manufacturer, uint16_t* lmp_sub_version) {
+ return body(addr, lmp_version, manufacturer, lmp_sub_version);
+ };
+};
+extern struct L2CA_ReadRemoteVersion L2CA_ReadRemoteVersion;
+// Name: L2CA_ReadRemoteFeatures
+// Params: const RawAddress& addr
+// Returns: uint8_t*
+struct L2CA_ReadRemoteFeatures {
+ std::function<uint8_t*(const RawAddress& addr)> body{
+ [](const RawAddress& addr) { return nullptr; }};
+ uint8_t* operator()(const RawAddress& addr) { return body(addr); };
+};
+extern struct L2CA_ReadRemoteFeatures L2CA_ReadRemoteFeatures;
+// Name: L2CA_UseLegacySecurityModule
+// Params:
+// Returns: void
+struct L2CA_UseLegacySecurityModule {
+ std::function<void()> body{[]() {}};
+ void operator()() { body(); };
+};
+extern struct L2CA_UseLegacySecurityModule L2CA_UseLegacySecurityModule;
+// Name: L2CA_Register
+// Params: uint16_t client_psm, const tL2CAP_APPL_INFO& callbacks, bool
+// enable_snoop, tL2CAP_ERTM_INFO* p_ertm_info, uint16_t my_mtu, uint16_t
+// required_remote_mtu, uint16_t sec_level Returns: uint16_t
+struct L2CA_Register {
+ std::function<uint16_t(uint16_t client_psm, const tL2CAP_APPL_INFO& callbacks,
+ bool enable_snoop, tL2CAP_ERTM_INFO* p_ertm_info,
+ uint16_t my_mtu, uint16_t required_remote_mtu,
+ uint16_t sec_level)>
+ body{[](uint16_t client_psm, const tL2CAP_APPL_INFO& callbacks,
+ bool enable_snoop, tL2CAP_ERTM_INFO* p_ertm_info, uint16_t my_mtu,
+ uint16_t required_remote_mtu, uint16_t sec_level) { return 0; }};
+ uint16_t operator()(uint16_t client_psm, const tL2CAP_APPL_INFO& callbacks,
+ bool enable_snoop, tL2CAP_ERTM_INFO* p_ertm_info,
+ uint16_t my_mtu, uint16_t required_remote_mtu,
+ uint16_t sec_level) {
+ return body(client_psm, callbacks, enable_snoop, p_ertm_info, my_mtu,
+ required_remote_mtu, sec_level);
+ };
+};
+extern struct L2CA_Register L2CA_Register;
+// Name: L2CA_Deregister
+// Params: uint16_t psm
+// Returns: void
+struct L2CA_Deregister {
+ std::function<void(uint16_t psm)> body{[](uint16_t psm) {}};
+ void operator()(uint16_t psm) { body(psm); };
+};
+extern struct L2CA_Deregister L2CA_Deregister;
+// Name: L2CA_ConnectReq
+// Params: uint16_t psm, const RawAddress& raw_address
+// Returns: uint16_t
+struct L2CA_ConnectReq {
+ std::function<uint16_t(uint16_t psm, const RawAddress& raw_address)> body{
+ [](uint16_t psm, const RawAddress& raw_address) { return 0; }};
+ uint16_t operator()(uint16_t psm, const RawAddress& raw_address) {
+ return body(psm, raw_address);
+ };
+};
+extern struct L2CA_ConnectReq L2CA_ConnectReq;
+// Name: L2CA_DisconnectReq
+// Params: uint16_t cid
+// Returns: bool
+struct L2CA_DisconnectReq {
+ std::function<bool(uint16_t cid)> body{[](uint16_t cid) { return false; }};
+ bool operator()(uint16_t cid) { return body(cid); };
+};
+extern struct L2CA_DisconnectReq L2CA_DisconnectReq;
+// Name: L2CA_DataWrite
+// Params: uint16_t cid, BT_HDR* p_data
+// Returns: uint8_t
+struct L2CA_DataWrite {
+ std::function<uint8_t(uint16_t cid, BT_HDR* p_data)> body{
+ [](uint16_t cid, BT_HDR* p_data) { return 0; }};
+ uint8_t operator()(uint16_t cid, BT_HDR* p_data) {
+ return body(cid, p_data);
+ };
+};
+extern struct L2CA_DataWrite L2CA_DataWrite;
+// Name: L2CA_ReconfigCreditBasedConnsReq
+// Params: const RawAddress& bd_addr, std::vector<uint16_t>& lcids,
+// tL2CAP_LE_CFG_INFO* p_cfg Returns: bool
+struct L2CA_ReconfigCreditBasedConnsReq {
+ std::function<bool(const RawAddress& bd_addr, std::vector<uint16_t>& lcids,
+ tL2CAP_LE_CFG_INFO* p_cfg)>
+ body{[](const RawAddress& bd_addr, std::vector<uint16_t>& lcids,
+ tL2CAP_LE_CFG_INFO* p_cfg) { return false; }};
+ bool operator()(const RawAddress& bd_addr, std::vector<uint16_t>& lcids,
+ tL2CAP_LE_CFG_INFO* p_cfg) {
+ return body(bd_addr, lcids, p_cfg);
+ };
+};
+extern struct L2CA_ReconfigCreditBasedConnsReq L2CA_ReconfigCreditBasedConnsReq;
+// Name: L2CA_ConnectCreditBasedReq
+// Params: uint16_t psm, const RawAddress& p_bd_addr, tL2CAP_LE_CFG_INFO* p_cfg
+// Returns: std::vector<uint16_t>
+struct L2CA_ConnectCreditBasedReq {
+ std::vector<uint16_t> cids;
+ std::function<std::vector<uint16_t>(uint16_t psm, const RawAddress& p_bd_addr,
+ tL2CAP_LE_CFG_INFO* p_cfg)>
+ body{[this](uint16_t psm, const RawAddress& p_bd_addr,
+ tL2CAP_LE_CFG_INFO* p_cfg) { return cids; }};
+ std::vector<uint16_t> operator()(uint16_t psm, const RawAddress& p_bd_addr,
+ tL2CAP_LE_CFG_INFO* p_cfg) {
+ return body(psm, p_bd_addr, p_cfg);
+ };
+};
+extern struct L2CA_ConnectCreditBasedReq L2CA_ConnectCreditBasedReq;
+// Name: L2CA_ConnectCreditBasedRsp
+// Params: const RawAddress& bd_addr, uint8_t id, std::vector<uint16_t>&
+// accepted_lcids, uint16_t result, tL2CAP_LE_CFG_INFO* p_cfg Returns: bool
+struct L2CA_ConnectCreditBasedRsp {
+ std::function<bool(const RawAddress& bd_addr, uint8_t id,
+ std::vector<uint16_t>& accepted_lcids, uint16_t result,
+ tL2CAP_LE_CFG_INFO* p_cfg)>
+ body{[](const RawAddress& bd_addr, uint8_t id,
+ std::vector<uint16_t>& accepted_lcids, uint16_t result,
+ tL2CAP_LE_CFG_INFO* p_cfg) { return false; }};
+ bool operator()(const RawAddress& bd_addr, uint8_t id,
+ std::vector<uint16_t>& accepted_lcids, uint16_t result,
+ tL2CAP_LE_CFG_INFO* p_cfg) {
+ return body(bd_addr, id, accepted_lcids, result, p_cfg);
+ };
+};
+extern struct L2CA_ConnectCreditBasedRsp L2CA_ConnectCreditBasedRsp;
+// Name: L2CA_SetIdleTimeoutByBdAddr
+// Params: const RawAddress& bd_addr, uint16_t timeout, tBT_TRANSPORT transport
+// Returns: bool
+struct L2CA_SetIdleTimeoutByBdAddr {
+ std::function<bool(const RawAddress& bd_addr, uint16_t timeout,
+ tBT_TRANSPORT transport)>
+ body{[](const RawAddress& bd_addr, uint16_t timeout,
+ tBT_TRANSPORT transport) { return false; }};
+ bool operator()(const RawAddress& bd_addr, uint16_t timeout,
+ tBT_TRANSPORT transport) {
+ return body(bd_addr, timeout, transport);
+ };
+};
+extern struct L2CA_SetIdleTimeoutByBdAddr L2CA_SetIdleTimeoutByBdAddr;
+// Name: L2CA_SetAclPriority
+// Params: uint16_t handle, bool high_priority
+// Returns: bool
+struct L2CA_SetAclPriority {
+ std::function<bool(uint16_t handle, bool high_priority)> body{
+ [](uint16_t handle, bool high_priority) { return false; }};
+ bool operator()(uint16_t handle, bool high_priority) {
+ return body(handle, high_priority);
+ };
+};
+extern struct L2CA_SetAclPriority L2CA_SetAclPriority;
+// Name: L2CA_SetAclPriority
+// Params: const RawAddress& bd_addr, tL2CAP_PRIORITY priority
+// Returns: bool
+struct L2CA_SetAclPriority2 {
+ std::function<bool(const RawAddress& bd_addr, tL2CAP_PRIORITY priority)> body{
+ [](const RawAddress& bd_addr, tL2CAP_PRIORITY priority) {
+ return false;
+ }};
+ bool operator()(const RawAddress& bd_addr, tL2CAP_PRIORITY priority) {
+ return body(bd_addr, priority);
+ };
+};
+extern struct L2CA_SetAclPriority2 L2CA_SetAclPriority2;
+// Name: L2CA_GetPeerFeatures
+// Params: const RawAddress& bd_addr, uint32_t* p_ext_feat, uint8_t* p_chnl_mask
+// Returns: bool
+struct L2CA_GetPeerFeatures {
+ std::function<bool(const RawAddress& bd_addr, uint32_t* p_ext_feat,
+ uint8_t* p_chnl_mask)>
+ body{[](const RawAddress& bd_addr, uint32_t* p_ext_feat,
+ uint8_t* p_chnl_mask) { return false; }};
+ bool operator()(const RawAddress& bd_addr, uint32_t* p_ext_feat,
+ uint8_t* p_chnl_mask) {
+ return body(bd_addr, p_ext_feat, p_chnl_mask);
+ };
+};
+extern struct L2CA_GetPeerFeatures L2CA_GetPeerFeatures;
+// Name: L2CA_RegisterFixedChannel
+// Params: uint16_t cid, tL2CAP_FIXED_CHNL_REG* p_freg
+// Returns: bool
+struct L2CA_RegisterFixedChannel {
+ std::function<bool(uint16_t cid, tL2CAP_FIXED_CHNL_REG* p_freg)> body{
+ [](uint16_t cid, tL2CAP_FIXED_CHNL_REG* p_freg) { return false; }};
+ bool operator()(uint16_t cid, tL2CAP_FIXED_CHNL_REG* p_freg) {
+ return body(cid, p_freg);
+ };
+};
+extern struct L2CA_RegisterFixedChannel L2CA_RegisterFixedChannel;
+// Name: L2CA_ConnectFixedChnl
+// Params: uint16_t cid, const RawAddress& rem_bda
+// Returns: bool
+struct L2CA_ConnectFixedChnl {
+ std::function<bool(uint16_t cid, const RawAddress& rem_bda)> body{
+ [](uint16_t cid, const RawAddress& rem_bda) { return false; }};
+ bool operator()(uint16_t cid, const RawAddress& rem_bda) {
+ return body(cid, rem_bda);
+ };
+};
+extern struct L2CA_ConnectFixedChnl L2CA_ConnectFixedChnl;
+// Name: L2CA_SendFixedChnlData
+// Params: uint16_t cid, const RawAddress& rem_bda, BT_HDR* p_buf
+// Returns: uint16_t
+struct L2CA_SendFixedChnlData {
+ std::function<uint16_t(uint16_t cid, const RawAddress& rem_bda,
+ BT_HDR* p_buf)>
+ body{[](uint16_t cid, const RawAddress& rem_bda, BT_HDR* p_buf) {
+ return 0;
+ }};
+ uint16_t operator()(uint16_t cid, const RawAddress& rem_bda, BT_HDR* p_buf) {
+ return body(cid, rem_bda, p_buf);
+ };
+};
+extern struct L2CA_SendFixedChnlData L2CA_SendFixedChnlData;
+// Name: L2CA_RemoveFixedChnl
+// Params: uint16_t cid, const RawAddress& rem_bda
+// Returns: bool
+struct L2CA_RemoveFixedChnl {
+ std::function<bool(uint16_t cid, const RawAddress& rem_bda)> body{
+ [](uint16_t cid, const RawAddress& rem_bda) { return false; }};
+ bool operator()(uint16_t cid, const RawAddress& rem_bda) {
+ return body(cid, rem_bda);
+ };
+};
+extern struct L2CA_RemoveFixedChnl L2CA_RemoveFixedChnl;
+// Name: L2CA_GetLeHandle
+// Params: const RawAddress& rem_bda
+// Returns: uint16_t
+struct L2CA_GetLeHandle {
+ std::function<uint16_t(const RawAddress& rem_bda)> body{
+ [](const RawAddress& rem_bda) { return 0; }};
+ uint16_t operator()(const RawAddress& rem_bda) { return body(rem_bda); };
+};
+extern struct L2CA_GetLeHandle L2CA_GetLeHandle;
+// Name: L2CA_LeConnectionUpdate
+// Params: const RawAddress& rem_bda, uint16_t min_int, uint16_t max_int,
+// uint16_t latency, uint16_t timeout, uint16_t min_ce_len, uint16_t max_ce_len
+// Returns: void
+struct L2CA_LeConnectionUpdate {
+ std::function<void(const RawAddress& rem_bda, uint16_t min_int,
+ uint16_t max_int, uint16_t latency, uint16_t timeout,
+ uint16_t min_ce_len, uint16_t max_ce_len)>
+ body{[](const RawAddress& rem_bda, uint16_t min_int, uint16_t max_int,
+ uint16_t latency, uint16_t timeout, uint16_t min_ce_len,
+ uint16_t max_ce_len) {}};
+ void operator()(const RawAddress& rem_bda, uint16_t min_int, uint16_t max_int,
+ uint16_t latency, uint16_t timeout, uint16_t min_ce_len,
+ uint16_t max_ce_len) {
+ body(rem_bda, min_int, max_int, latency, timeout, min_ce_len, max_ce_len);
+ };
+};
+extern struct L2CA_LeConnectionUpdate L2CA_LeConnectionUpdate;
+// Name: L2CA_EnableUpdateBleConnParams
+// Params: const RawAddress& rem_bda, bool enable
+// Returns: bool
+struct L2CA_EnableUpdateBleConnParams {
+ std::function<bool(const RawAddress& rem_bda, bool enable)> body{
+ [](const RawAddress& rem_bda, bool enable) { return false; }};
+ bool operator()(const RawAddress& rem_bda, bool enable) {
+ return body(rem_bda, enable);
+ };
+};
+extern struct L2CA_EnableUpdateBleConnParams L2CA_EnableUpdateBleConnParams;
+// Name: L2CA_GetRemoteCid
+// Params: uint16_t lcid, uint16_t* rcid
+// Returns: bool
+struct L2CA_GetRemoteCid {
+ std::function<bool(uint16_t lcid, uint16_t* rcid)> body{
+ [](uint16_t lcid, uint16_t* rcid) { return false; }};
+ bool operator()(uint16_t lcid, uint16_t* rcid) { return body(lcid, rcid); };
+};
+extern struct L2CA_GetRemoteCid L2CA_GetRemoteCid;
+// Name: L2CA_SetTxPriority
+// Params: uint16_t cid, tL2CAP_CHNL_PRIORITY priority
+// Returns: bool
+struct L2CA_SetTxPriority {
+ std::function<bool(uint16_t cid, tL2CAP_CHNL_PRIORITY priority)> body{
+ [](uint16_t cid, tL2CAP_CHNL_PRIORITY priority) { return false; }};
+ bool operator()(uint16_t cid, tL2CAP_CHNL_PRIORITY priority) {
+ return body(cid, priority);
+ };
+};
+extern struct L2CA_SetTxPriority L2CA_SetTxPriority;
+// Name: L2CA_SetLeGattTimeout
+// Params: const RawAddress& rem_bda, uint16_t idle_tout
+// Returns: bool
+struct L2CA_SetLeGattTimeout {
+ std::function<bool(const RawAddress& rem_bda, uint16_t idle_tout)> body{
+ [](const RawAddress& rem_bda, uint16_t idle_tout) { return false; }};
+ bool operator()(const RawAddress& rem_bda, uint16_t idle_tout) {
+ return body(rem_bda, idle_tout);
+ };
+};
+extern struct L2CA_SetLeGattTimeout L2CA_SetLeGattTimeout;
+// Name: L2CA_SetChnlFlushability
+// Params: uint16_t cid, bool is_flushable
+// Returns: bool
+struct L2CA_SetChnlFlushability {
+ std::function<bool(uint16_t cid, bool is_flushable)> body{
+ [](uint16_t cid, bool is_flushable) { return false; }};
+ bool operator()(uint16_t cid, bool is_flushable) {
+ return body(cid, is_flushable);
+ };
+};
+extern struct L2CA_SetChnlFlushability L2CA_SetChnlFlushability;
+// Name: L2CA_FlushChannel
+// Params: uint16_t lcid, uint16_t num_to_flush
+// Returns: uint16_t
+struct L2CA_FlushChannel {
+ std::function<uint16_t(uint16_t lcid, uint16_t num_to_flush)> body{
+ [](uint16_t lcid, uint16_t num_to_flush) { return 0; }};
+ uint16_t operator()(uint16_t lcid, uint16_t num_to_flush) {
+ return body(lcid, num_to_flush);
+ };
+};
+extern struct L2CA_FlushChannel L2CA_FlushChannel;
+// Name: L2CA_IsLinkEstablished
+// Params: const RawAddress& bd_addr, tBT_TRANSPORT transport
+// Returns: bool
+struct L2CA_IsLinkEstablished {
+ std::function<bool(const RawAddress& bd_addr, tBT_TRANSPORT transport)> body{
+ [](const RawAddress& bd_addr, tBT_TRANSPORT transport) { return false; }};
+ bool operator()(const RawAddress& bd_addr, tBT_TRANSPORT transport) {
+ return body(bd_addr, transport);
+ };
+};
+extern struct L2CA_IsLinkEstablished L2CA_IsLinkEstablished;
+// Name: L2CA_IsLeLink
+// Params: uint16_t acl_handle
+// Returns: bool
+struct L2CA_IsLeLink {
+ std::function<bool(uint16_t acl_handle)> body{
+ [](uint16_t acl_handle) { return false; }};
+ bool operator()(uint16_t acl_handle) { return body(acl_handle); };
+};
+extern struct L2CA_IsLeLink L2CA_IsLeLink;
+// Name: L2CA_ReadConnectionAddr
+// Params: const RawAddress& pseudo_addr, RawAddress& conn_addr, uint8_t*
+// p_addr_type Returns: void
+struct L2CA_ReadConnectionAddr {
+ std::function<void(const RawAddress& pseudo_addr, RawAddress& conn_addr,
+ uint8_t* p_addr_type)>
+ body{[](const RawAddress& pseudo_addr, RawAddress& conn_addr,
+ uint8_t* p_addr_type) {}};
+ void operator()(const RawAddress& pseudo_addr, RawAddress& conn_addr,
+ uint8_t* p_addr_type) {
+ body(pseudo_addr, conn_addr, p_addr_type);
+ };
+};
+extern struct L2CA_ReadConnectionAddr L2CA_ReadConnectionAddr;
+// Name: L2CA_ReadRemoteConnectionAddr
+// Params: const RawAddress& pseudo_addr, RawAddress& conn_addr, uint8_t*
+// p_addr_type Returns: bool
+struct L2CA_ReadRemoteConnectionAddr {
+ std::function<bool(const RawAddress& pseudo_addr, RawAddress& conn_addr,
+ uint8_t* p_addr_type)>
+ body{[](const RawAddress& pseudo_addr, RawAddress& conn_addr,
+ uint8_t* p_addr_type) { return false; }};
+ bool operator()(const RawAddress& pseudo_addr, RawAddress& conn_addr,
+ uint8_t* p_addr_type) {
+ return body(pseudo_addr, conn_addr, p_addr_type);
+ };
+};
+extern struct L2CA_ReadRemoteConnectionAddr L2CA_ReadRemoteConnectionAddr;
+// Name: L2CA_GetBleConnRole
+// Params: const RawAddress& bd_addr
+// Returns: hci_role_t
+struct L2CA_GetBleConnRole {
+ std::function<hci_role_t(const RawAddress& bd_addr)> body{
+ [](const RawAddress& bd_addr) { return HCI_ROLE_CENTRAL; }};
+ hci_role_t operator()(const RawAddress& bd_addr) { return body(bd_addr); };
+};
+extern struct L2CA_GetBleConnRole L2CA_GetBleConnRole;
+// Name: L2CA_ConnectForSecurity
+// Params: const RawAddress& bd_addr
+// Returns: void
+struct L2CA_ConnectForSecurity {
+ std::function<void(const RawAddress& bd_addr)> body{
+ [](const RawAddress& bd_addr) {}};
+ void operator()(const RawAddress& bd_addr) { body(bd_addr); };
+};
+extern struct L2CA_ConnectForSecurity L2CA_ConnectForSecurity;
+// Name: L2CA_SetBondingState
+// Params: const RawAddress& bd_addr, bool is_bonding
+// Returns: void
+struct L2CA_SetBondingState {
+ std::function<void(const RawAddress& bd_addr, bool is_bonding)> body{
+ [](const RawAddress& bd_addr, bool is_bonding) {}};
+ void operator()(const RawAddress& bd_addr, bool is_bonding) {
+ body(bd_addr, is_bonding);
+ };
+};
+extern struct L2CA_SetBondingState L2CA_SetBondingState;
+// Name: L2CA_DisconnectLink
+// Params: const RawAddress& remote
+// Returns: void
+struct L2CA_DisconnectLink {
+ std::function<void(const RawAddress& remote)> body{
+ [](const RawAddress& remote) {}};
+ void operator()(const RawAddress& remote) { body(remote); };
+};
+extern struct L2CA_DisconnectLink L2CA_DisconnectLink;
+// Name: L2CA_GetNumLinks
+// Params:
+// Returns: uint16_t
+struct L2CA_GetNumLinks {
+ std::function<uint16_t()> body{[]() { return 0; }};
+ uint16_t operator()() { return body(); };
+};
+extern struct L2CA_GetNumLinks L2CA_GetNumLinks;
+// Name: L2CA_AllocateLePSM
+// Params:
+// Returns: uint16_t
+struct L2CA_AllocateLePSM {
+ std::function<uint16_t()> body{[]() { return 0; }};
+ uint16_t operator()() { return body(); };
+};
+extern struct L2CA_AllocateLePSM L2CA_AllocateLePSM;
+// Name: L2CA_FreeLePSM
+// Params: uint16_t psm
+// Returns: void
+struct L2CA_FreeLePSM {
+ std::function<void(uint16_t psm)> body{[](uint16_t psm) {}};
+ void operator()(uint16_t psm) { body(psm); };
+};
+extern struct L2CA_FreeLePSM L2CA_FreeLePSM;
+// Name: L2CA_RegisterLECoc
+// Params: uint16_t psm, const tL2CAP_APPL_INFO& callbacks, uint16_t sec_level,
+// tL2CAP_LE_CFG_INFO cfg Returns: uint16_t
+struct L2CA_RegisterLECoc {
+ std::function<uint16_t(uint16_t psm, const tL2CAP_APPL_INFO& callbacks,
+ uint16_t sec_level, tL2CAP_LE_CFG_INFO cfg)>
+ body{[](uint16_t psm, const tL2CAP_APPL_INFO& callbacks,
+ uint16_t sec_level, tL2CAP_LE_CFG_INFO cfg) { return 0; }};
+ uint16_t operator()(uint16_t psm, const tL2CAP_APPL_INFO& callbacks,
+ uint16_t sec_level, tL2CAP_LE_CFG_INFO cfg) {
+ return body(psm, callbacks, sec_level, cfg);
+ };
+};
+extern struct L2CA_RegisterLECoc L2CA_RegisterLECoc;
+// Name: L2CA_DeregisterLECoc
+// Params: uint16_t psm
+// Returns: void
+struct L2CA_DeregisterLECoc {
+ std::function<void(uint16_t psm)> body{[](uint16_t psm) {}};
+ void operator()(uint16_t psm) { body(psm); };
+};
+extern struct L2CA_DeregisterLECoc L2CA_DeregisterLECoc;
+// Name: L2CA_ConnectLECocReq
+// Params: uint16_t psm, const RawAddress& p_bd_addr, tL2CAP_LE_CFG_INFO* p_cfg
+// Returns: uint16_t
+struct L2CA_ConnectLECocReq {
+ std::function<uint16_t(uint16_t psm, const RawAddress& p_bd_addr,
+ tL2CAP_LE_CFG_INFO* p_cfg)>
+ body{[](uint16_t psm, const RawAddress& p_bd_addr,
+ tL2CAP_LE_CFG_INFO* p_cfg) { return 0; }};
+ uint16_t operator()(uint16_t psm, const RawAddress& p_bd_addr,
+ tL2CAP_LE_CFG_INFO* p_cfg) {
+ return body(psm, p_bd_addr, p_cfg);
+ };
+};
+extern struct L2CA_ConnectLECocReq L2CA_ConnectLECocReq;
+// Name: L2CA_GetPeerLECocConfig
+// Params: uint16_t cid, tL2CAP_LE_CFG_INFO* peer_cfg
+// Returns: bool
+struct L2CA_GetPeerLECocConfig {
+ std::function<bool(uint16_t cid, tL2CAP_LE_CFG_INFO* peer_cfg)> body{
+ [](uint16_t cid, tL2CAP_LE_CFG_INFO* peer_cfg) { return false; }};
+ bool operator()(uint16_t cid, tL2CAP_LE_CFG_INFO* peer_cfg) {
+ return body(cid, peer_cfg);
+ };
+};
+extern struct L2CA_GetPeerLECocConfig L2CA_GetPeerLECocConfig;
+// Name: L2CA_DisconnectLECocReq
+// Params: uint16_t cid
+// Returns: bool
+struct L2CA_DisconnectLECocReq {
+ std::function<bool(uint16_t cid)> body{[](uint16_t cid) { return false; }};
+ bool operator()(uint16_t cid) { return body(cid); };
+};
+extern struct L2CA_DisconnectLECocReq L2CA_DisconnectLECocReq;
+// Name: L2CA_LECocDataWrite
+// Params: uint16_t cid, BT_HDR* p_data
+// Returns: uint8_t
+struct L2CA_LECocDataWrite {
+ std::function<uint8_t(uint16_t cid, BT_HDR* p_data)> body{
+ [](uint16_t cid, BT_HDR* p_data) { return 0; }};
+ uint8_t operator()(uint16_t cid, BT_HDR* p_data) {
+ return body(cid, p_data);
+ };
+};
+extern struct L2CA_LECocDataWrite L2CA_LECocDataWrite;
+// Name: L2CA_SwitchRoleToCentral
+// Params: const RawAddress& addr
+// Returns: void
+struct L2CA_SwitchRoleToCentral {
+ std::function<void(const RawAddress& addr)> body{
+ [](const RawAddress& addr) {}};
+ void operator()(const RawAddress& addr) { body(addr); };
+};
+extern struct L2CA_SwitchRoleToCentral L2CA_SwitchRoleToCentral;
+
+} // namespace main_shim_l2cap_api
+} // namespace mock
+} // namespace test
+
+// END mockcify generation
diff --git a/test/mock/mock_main_shim_link_policy.cc b/test/mock/mock_main_shim_link_policy.cc
new file mode 100644
index 0000000..06b4bbb
--- /dev/null
+++ b/test/mock/mock_main_shim_link_policy.cc
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:10
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <cstdint>
+#include <functional>
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Mock include file to share data between tests and mock
+#include "test/mock/mock_main_shim_link_policy.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+// Mocked internal structures, if any
+
+namespace test {
+namespace mock {
+namespace main_shim_link_policy {
+
+// Function state capture and return values, if needed
+struct set_active_mode set_active_mode;
+struct set_hold_mode set_hold_mode;
+struct set_sniff_mode set_sniff_mode;
+struct controller_supports_link_policy_mode
+ controller_supports_link_policy_mode;
+struct RegisterLinkPolicyClient RegisterLinkPolicyClient;
+struct UnregisterLinkPolicyClient UnregisterLinkPolicyClient;
+struct BTM_SetPowerMode BTM_SetPowerMode;
+struct btm_pm_on_mode_change btm_pm_on_mode_change;
+struct BTM_SetSsrParams BTM_SetSsrParams;
+struct btm_pm_on_sniff_subrating btm_pm_on_sniff_subrating;
+
+} // namespace main_shim_link_policy
+} // namespace mock
+} // namespace test
+
+// Mocked functions, if any
+tBTM_STATUS set_active_mode(tACL_CONN& p_acl) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_link_policy::set_active_mode(p_acl);
+}
+tBTM_STATUS set_hold_mode(tACL_CONN& p_acl, uint16_t max, uint16_t min) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_link_policy::set_hold_mode(p_acl, max, min);
+}
+tBTM_STATUS set_sniff_mode(tACL_CONN& p_acl, uint16_t max_interval,
+ uint16_t min_interval, uint16_t attempt,
+ uint16_t timeout) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_link_policy::set_sniff_mode(
+ p_acl, max_interval, min_interval, attempt, timeout);
+}
+bool controller_supports_link_policy_mode(const tBTM_PM_MODE& mode,
+ bool interop_check) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_link_policy::
+ controller_supports_link_policy_mode(mode, interop_check);
+}
+bool bluetooth::shim::RegisterLinkPolicyClient(tBTM_PM_STATUS_CBACK* p_cb) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_link_policy::RegisterLinkPolicyClient(p_cb);
+}
+bool bluetooth::shim::UnregisterLinkPolicyClient(tBTM_PM_STATUS_CBACK* p_cb) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_link_policy::UnregisterLinkPolicyClient(p_cb);
+}
+tBTM_STATUS bluetooth::shim::BTM_SetPowerMode(uint16_t handle,
+ const tBTM_PM_PWR_MD& new_mode) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_link_policy::BTM_SetPowerMode(handle, new_mode);
+}
+void bluetooth::shim::btm_pm_on_mode_change(tHCI_STATUS status, uint16_t handle,
+ tHCI_MODE hci_mode,
+ uint16_t interval) {
+ mock_function_count_map[__func__]++;
+ test::mock::main_shim_link_policy::btm_pm_on_mode_change(status, handle,
+ hci_mode, interval);
+}
+tBTM_STATUS bluetooth::shim::BTM_SetSsrParams(uint16_t handle, uint16_t max_lat,
+ uint16_t min_rmt_to,
+ uint16_t min_loc_to) {
+ mock_function_count_map[__func__]++;
+ return test::mock::main_shim_link_policy::BTM_SetSsrParams(
+ handle, max_lat, min_rmt_to, min_loc_to);
+}
+void bluetooth::shim::btm_pm_on_sniff_subrating(
+ tHCI_STATUS status, uint16_t handle, uint16_t maximum_transmit_latency,
+ UNUSED_ATTR uint16_t maximum_receive_latency,
+ uint16_t minimum_remote_timeout, uint16_t minimum_local_timeout) {
+ mock_function_count_map[__func__]++;
+ test::mock::main_shim_link_policy::btm_pm_on_sniff_subrating(
+ status, handle, maximum_transmit_latency, maximum_receive_latency,
+ minimum_remote_timeout, minimum_local_timeout);
+}
+
+// END mockcify generation
diff --git a/test/mock/mock_main_shim_link_policy.h b/test/mock/mock_main_shim_link_policy.h
new file mode 100644
index 0000000..fe0f4cf
--- /dev/null
+++ b/test/mock/mock_main_shim_link_policy.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:10
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <cstdint>
+#include <functional>
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+#include <base/bind.h>
+#include <base/location.h>
+#include <base/strings/stringprintf.h>
+#include <cstdint>
+#include <memory>
+#include "device/include/interop.h"
+#include "gd/module.h"
+#include "hci/controller.h"
+#include "main/shim/controller.h"
+#include "main/shim/dumpsys.h"
+#include "main/shim/link_policy.h"
+#include "main/shim/stack.h"
+#include "osi/include/log.h"
+#include "stack/btm/btm_int_types.h"
+#include "stack/include/btm_api.h"
+#include "stack/include/btm_api_types.h"
+#include "stack/include/btm_ble_api_types.h"
+#include "stack/include/hci_error_code.h"
+#include "stack/include/hcidefs.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+namespace test {
+namespace mock {
+namespace main_shim_link_policy {
+
+// Shared state between mocked functions and tests
+// Name: set_active_mode
+// Params: tACL_CONN& p_acl
+// Returns: tBTM_STATUS
+struct set_active_mode {
+ std::function<tBTM_STATUS(tACL_CONN& p_acl)> body{
+ [](tACL_CONN& p_acl) { return 0; }};
+ tBTM_STATUS operator()(tACL_CONN& p_acl) { return body(p_acl); };
+};
+extern struct set_active_mode set_active_mode;
+// Name: set_hold_mode
+// Params: tACL_CONN& p_acl, uint16_t max, uint16_t min
+// Returns: tBTM_STATUS
+struct set_hold_mode {
+ std::function<tBTM_STATUS(tACL_CONN& p_acl, uint16_t max, uint16_t min)> body{
+ [](tACL_CONN& p_acl, uint16_t max, uint16_t min) { return 0; }};
+ tBTM_STATUS operator()(tACL_CONN& p_acl, uint16_t max, uint16_t min) {
+ return body(p_acl, max, min);
+ };
+};
+extern struct set_hold_mode set_hold_mode;
+// Name: set_sniff_mode
+// Params: tACL_CONN& p_acl, uint16_t max_interval, uint16_t min_interval,
+// uint16_t attempt, uint16_t timeout Returns: tBTM_STATUS
+struct set_sniff_mode {
+ std::function<tBTM_STATUS(tACL_CONN& p_acl, uint16_t max_interval,
+ uint16_t min_interval, uint16_t attempt,
+ uint16_t timeout)>
+ body{[](tACL_CONN& p_acl, uint16_t max_interval, uint16_t min_interval,
+ uint16_t attempt, uint16_t timeout) { return 0; }};
+ tBTM_STATUS operator()(tACL_CONN& p_acl, uint16_t max_interval,
+ uint16_t min_interval, uint16_t attempt,
+ uint16_t timeout) {
+ return body(p_acl, max_interval, min_interval, attempt, timeout);
+ };
+};
+extern struct set_sniff_mode set_sniff_mode;
+// Name: controller_supports_link_policy_mode
+// Params: const tBTM_PM_MODE& mode, bool interop_check
+// Returns: bool
+struct controller_supports_link_policy_mode {
+ std::function<bool(const tBTM_PM_MODE& mode, bool interop_check)> body{
+ [](const tBTM_PM_MODE& mode, bool interop_check) { return false; }};
+ bool operator()(const tBTM_PM_MODE& mode, bool interop_check) {
+ return body(mode, interop_check);
+ };
+};
+extern struct controller_supports_link_policy_mode
+ controller_supports_link_policy_mode;
+// Name: bluetooth::shim::RegisterLinkPolicyClient
+// Params: tBTM_PM_STATUS_CBACK* p_cb
+// Returns: bool
+struct RegisterLinkPolicyClient {
+ std::function<bool(tBTM_PM_STATUS_CBACK* p_cb)> body{
+ [](tBTM_PM_STATUS_CBACK* p_cb) { return false; }};
+ bool operator()(tBTM_PM_STATUS_CBACK* p_cb) { return body(p_cb); };
+};
+extern struct RegisterLinkPolicyClient RegisterLinkPolicyClient;
+// Name: bluetooth::shim::UnregisterLinkPolicyClient
+// Params: tBTM_PM_STATUS_CBACK* p_cb
+// Returns: bool
+struct UnregisterLinkPolicyClient {
+ std::function<bool(tBTM_PM_STATUS_CBACK* p_cb)> body{
+ [](tBTM_PM_STATUS_CBACK* p_cb) { return false; }};
+ bool operator()(tBTM_PM_STATUS_CBACK* p_cb) { return body(p_cb); };
+};
+extern struct UnregisterLinkPolicyClient UnregisterLinkPolicyClient;
+// Name: bluetooth::shim::BTM_SetPowerMode
+// Params: uint16_t handle, const tBTM_PM_PWR_MD& new_mode
+// Returns: tBTM_STATUS
+struct BTM_SetPowerMode {
+ std::function<tBTM_STATUS(uint16_t handle, const tBTM_PM_PWR_MD& new_mode)>
+ body{[](uint16_t handle, const tBTM_PM_PWR_MD& new_mode) { return 0; }};
+ tBTM_STATUS operator()(uint16_t handle, const tBTM_PM_PWR_MD& new_mode) {
+ return body(handle, new_mode);
+ };
+};
+extern struct BTM_SetPowerMode BTM_SetPowerMode;
+// Name: bluetooth::shim::btm_pm_on_mode_change
+// Params: tHCI_STATUS status, uint16_t handle, tHCI_MODE hci_mode, uint16_t
+// interval Returns: void
+struct btm_pm_on_mode_change {
+ std::function<void(tHCI_STATUS status, uint16_t handle, tHCI_MODE hci_mode,
+ uint16_t interval)>
+ body{[](tHCI_STATUS status, uint16_t handle, tHCI_MODE hci_mode,
+ uint16_t interval) {}};
+ void operator()(tHCI_STATUS status, uint16_t handle, tHCI_MODE hci_mode,
+ uint16_t interval) {
+ body(status, handle, hci_mode, interval);
+ };
+};
+extern struct btm_pm_on_mode_change btm_pm_on_mode_change;
+// Name: bluetooth::shim::BTM_SetSsrParams
+// Params: uint16_t handle, uint16_t max_lat, uint16_t min_rmt_to, uint16_t
+// min_loc_to Returns: tBTM_STATUS
+struct BTM_SetSsrParams {
+ std::function<tBTM_STATUS(uint16_t handle, uint16_t max_lat,
+ uint16_t min_rmt_to, uint16_t min_loc_to)>
+ body{[](uint16_t handle, uint16_t max_lat, uint16_t min_rmt_to,
+ uint16_t min_loc_to) { return 0; }};
+ tBTM_STATUS operator()(uint16_t handle, uint16_t max_lat, uint16_t min_rmt_to,
+ uint16_t min_loc_to) {
+ return body(handle, max_lat, min_rmt_to, min_loc_to);
+ };
+};
+extern struct BTM_SetSsrParams BTM_SetSsrParams;
+// Name: bluetooth::shim::btm_pm_on_sniff_subrating
+// Params: tHCI_STATUS status, uint16_t handle, uint16_t
+// maximum_transmit_latency, UNUSED_ATTR uint16_t maximum_receive_latency,
+// uint16_t minimum_remote_timeout, uint16_t minimum_local_timeout Returns: void
+struct btm_pm_on_sniff_subrating {
+ std::function<void(
+ tHCI_STATUS status, uint16_t handle, uint16_t maximum_transmit_latency,
+ UNUSED_ATTR uint16_t maximum_receive_latency,
+ uint16_t minimum_remote_timeout, uint16_t minimum_local_timeout)>
+ body{[](tHCI_STATUS status, uint16_t handle,
+ uint16_t maximum_transmit_latency,
+ UNUSED_ATTR uint16_t maximum_receive_latency,
+ uint16_t minimum_remote_timeout,
+ uint16_t minimum_local_timeout) {}};
+ void operator()(tHCI_STATUS status, uint16_t handle,
+ uint16_t maximum_transmit_latency,
+ UNUSED_ATTR uint16_t maximum_receive_latency,
+ uint16_t minimum_remote_timeout,
+ uint16_t minimum_local_timeout) {
+ body(status, handle, maximum_transmit_latency, maximum_receive_latency,
+ minimum_remote_timeout, minimum_local_timeout);
+ };
+};
+extern struct btm_pm_on_sniff_subrating btm_pm_on_sniff_subrating;
+
+} // namespace main_shim_link_policy
+} // namespace mock
+} // namespace test
+
+// END mockcify generation
diff --git a/test/mock/mock_main_shim_metrics_api.cc b/test/mock/mock_main_shim_metrics_api.cc
index 0d39d73..76c5e3c 100644
--- a/test/mock/mock_main_shim_metrics_api.cc
+++ b/test/mock/mock_main_shim_metrics_api.cc
@@ -17,43 +17,153 @@
/*
* Generated mock file from original source file
* Functions generated:12
+ *
+ * mockcify.pl ver 0.2
*/
#include <cstdint>
+#include <functional>
#include <map>
#include <string>
extern std::map<std::string, int> mock_function_count_map;
-#include "gd/common/metrics.h"
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+#include "gd/hci/address.h"
+#include "gd/os/metrics.h"
+#include "main/shim/helpers.h"
#include "main/shim/metrics_api.h"
#include "types/raw_address.h"
+// Mock include file to share data between tests and mock
+#include "test/mock/mock_main_shim_metrics_api.h"
+
+// Mocked compile conditionals, if any
#ifndef UNUSED_ATTR
#define UNUSED_ATTR
#endif
-void bluetooth::shim::LogMetricA2dpAudioOverrunEvent(
- const RawAddress& raw_address, uint64_t encoding_interval_millis,
- int num_dropped_buffers, int num_dropped_encoded_frames,
- int num_dropped_encoded_bytes) {
+// Mocked internal structures, if any
+
+namespace test {
+namespace mock {
+namespace main_shim_metrics_api {
+
+// Function state capture and return values, if needed
+struct LogMetricLinkLayerConnectionEvent LogMetricLinkLayerConnectionEvent;
+struct LogMetricA2dpAudioUnderrunEvent LogMetricA2dpAudioUnderrunEvent;
+struct LogMetricA2dpAudioOverrunEvent LogMetricA2dpAudioOverrunEvent;
+struct LogMetricA2dpPlaybackEvent LogMetricA2dpPlaybackEvent;
+struct LogMetricReadRssiResult LogMetricReadRssiResult;
+struct LogMetricReadFailedContactCounterResult
+ LogMetricReadFailedContactCounterResult;
+struct LogMetricReadTxPowerLevelResult LogMetricReadTxPowerLevelResult;
+struct LogMetricSmpPairingEvent LogMetricSmpPairingEvent;
+struct LogMetricClassicPairingEvent LogMetricClassicPairingEvent;
+struct LogMetricSdpAttribute LogMetricSdpAttribute;
+struct LogMetricSocketConnectionState LogMetricSocketConnectionState;
+struct LogMetricManufacturerInfo LogMetricManufacturerInfo;
+
+} // namespace main_shim_metrics_api
+} // namespace mock
+} // namespace test
+
+// Mocked functions, if any
+void bluetooth::shim::LogMetricLinkLayerConnectionEvent(
+ const RawAddress* raw_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) {
mock_function_count_map[__func__]++;
+ test::mock::main_shim_metrics_api::LogMetricLinkLayerConnectionEvent(
+ raw_address, connection_handle, direction, link_type, hci_cmd, hci_event,
+ hci_ble_event, cmd_status, reason_code);
}
void bluetooth::shim::LogMetricA2dpAudioUnderrunEvent(
const RawAddress& raw_address, uint64_t encoding_interval_millis,
int num_missing_pcm_bytes) {
mock_function_count_map[__func__]++;
+ test::mock::main_shim_metrics_api::LogMetricA2dpAudioUnderrunEvent(
+ raw_address, encoding_interval_millis, num_missing_pcm_bytes);
+}
+void bluetooth::shim::LogMetricA2dpAudioOverrunEvent(
+ const RawAddress& raw_address, uint64_t encoding_interval_millis,
+ int num_dropped_buffers, int num_dropped_encoded_frames,
+ int num_dropped_encoded_bytes) {
+ mock_function_count_map[__func__]++;
+ test::mock::main_shim_metrics_api::LogMetricA2dpAudioOverrunEvent(
+ raw_address, encoding_interval_millis, num_dropped_buffers,
+ num_dropped_encoded_frames, num_dropped_encoded_bytes);
}
void bluetooth::shim::LogMetricA2dpPlaybackEvent(const RawAddress& raw_address,
int playback_state,
int audio_coding_mode) {
mock_function_count_map[__func__]++;
+ test::mock::main_shim_metrics_api::LogMetricA2dpPlaybackEvent(
+ raw_address, playback_state, audio_coding_mode);
+}
+void bluetooth::shim::LogMetricReadRssiResult(const RawAddress& raw_address,
+ uint16_t handle,
+ uint32_t cmd_status,
+ int8_t rssi) {
+ mock_function_count_map[__func__]++;
+ test::mock::main_shim_metrics_api::LogMetricReadRssiResult(
+ raw_address, handle, cmd_status, rssi);
+}
+void bluetooth::shim::LogMetricReadFailedContactCounterResult(
+ const RawAddress& raw_address, uint16_t handle, uint32_t cmd_status,
+ int32_t failed_contact_counter) {
+ mock_function_count_map[__func__]++;
+ test::mock::main_shim_metrics_api::LogMetricReadFailedContactCounterResult(
+ raw_address, handle, cmd_status, failed_contact_counter);
+}
+void bluetooth::shim::LogMetricReadTxPowerLevelResult(
+ const RawAddress& raw_address, uint16_t handle, uint32_t cmd_status,
+ int32_t transmit_power_level) {
+ mock_function_count_map[__func__]++;
+ test::mock::main_shim_metrics_api::LogMetricReadTxPowerLevelResult(
+ raw_address, handle, cmd_status, transmit_power_level);
+}
+void bluetooth::shim::LogMetricSmpPairingEvent(
+ const RawAddress& raw_address, uint8_t smp_cmd,
+ android::bluetooth::DirectionEnum direction, uint8_t smp_fail_reason) {
+ mock_function_count_map[__func__]++;
+ test::mock::main_shim_metrics_api::LogMetricSmpPairingEvent(
+ raw_address, smp_cmd, direction, smp_fail_reason);
}
void bluetooth::shim::LogMetricClassicPairingEvent(
const RawAddress& raw_address, uint16_t handle, uint32_t hci_cmd,
uint16_t hci_event, uint16_t cmd_status, uint16_t reason_code,
int64_t event_value) {
mock_function_count_map[__func__]++;
+ test::mock::main_shim_metrics_api::LogMetricClassicPairingEvent(
+ raw_address, handle, hci_cmd, hci_event, cmd_status, reason_code,
+ event_value);
+}
+void bluetooth::shim::LogMetricSdpAttribute(const RawAddress& raw_address,
+ uint16_t protocol_uuid,
+ uint16_t attribute_id,
+ size_t attribute_size,
+ const char* attribute_value) {
+ mock_function_count_map[__func__]++;
+ test::mock::main_shim_metrics_api::LogMetricSdpAttribute(
+ raw_address, protocol_uuid, attribute_id, attribute_size,
+ attribute_value);
+}
+void bluetooth::shim::LogMetricSocketConnectionState(
+ const RawAddress& raw_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) {
+ mock_function_count_map[__func__]++;
+ test::mock::main_shim_metrics_api::LogMetricSocketConnectionState(
+ raw_address, port, type, connection_state, tx_bytes, rx_bytes, uid,
+ server_port, socket_role);
}
void bluetooth::shim::LogMetricManufacturerInfo(
const RawAddress& raw_address,
@@ -62,39 +172,9 @@
const std::string& model, const std::string& hardware_version,
const std::string& software_version) {
mock_function_count_map[__func__]++;
+ test::mock::main_shim_metrics_api::LogMetricManufacturerInfo(
+ raw_address, source_type, source_name, manufacturer, model,
+ hardware_version, software_version);
}
-void bluetooth::shim::LogMetricReadFailedContactCounterResult(
- const RawAddress& raw_address, uint16_t handle, uint32_t cmd_status,
- int32_t failed_contact_counter) {
- mock_function_count_map[__func__]++;
-}
-void bluetooth::shim::LogMetricReadRssiResult(const RawAddress& raw_address,
- uint16_t handle,
- uint32_t cmd_status,
- int8_t rssi) {
- mock_function_count_map[__func__]++;
-}
-void bluetooth::shim::LogMetricReadTxPowerLevelResult(
- const RawAddress& raw_address, uint16_t handle, uint32_t cmd_status,
- int32_t transmit_power_level) {
- mock_function_count_map[__func__]++;
-}
-void bluetooth::shim::LogMetricSdpAttribute(const RawAddress& raw_address,
- uint16_t protocol_uuid,
- uint16_t attribute_id,
- size_t attribute_size,
- const char* attribute_value) {
- mock_function_count_map[__func__]++;
-}
-void bluetooth::shim::LogMetricSmpPairingEvent(
- const RawAddress& raw_address, uint8_t smp_cmd,
- android::bluetooth::DirectionEnum direction, uint8_t smp_fail_reason) {
- mock_function_count_map[__func__]++;
-}
-void bluetooth::shim::LogMetricSocketConnectionState(
- const RawAddress& raw_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) {
- mock_function_count_map[__func__]++;
-}
+
+// END mockcify generation
diff --git a/test/mock/mock_main_shim_metrics_api.h b/test/mock/mock_main_shim_metrics_api.h
new file mode 100644
index 0000000..aba10a8
--- /dev/null
+++ b/test/mock/mock_main_shim_metrics_api.h
@@ -0,0 +1,287 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:12
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <cstdint>
+#include <functional>
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+#include "gd/hci/address.h"
+#include "gd/os/metrics.h"
+#include "main/shim/helpers.h"
+#include "main/shim/metrics_api.h"
+#include "types/raw_address.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+namespace test {
+namespace mock {
+namespace main_shim_metrics_api {
+
+// Shared state between mocked functions and tests
+// Name: LogMetricLinkLayerConnectionEvent
+// Params: const RawAddress* raw_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 Returns: void
+struct LogMetricLinkLayerConnectionEvent {
+ std::function<void(const RawAddress* raw_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)>
+ body{[](const RawAddress* raw_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) {}};
+ void operator()(const RawAddress* raw_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) {
+ body(raw_address, connection_handle, direction, link_type, hci_cmd,
+ hci_event, hci_ble_event, cmd_status, reason_code);
+ };
+};
+extern struct LogMetricLinkLayerConnectionEvent
+ LogMetricLinkLayerConnectionEvent;
+// Name: LogMetricA2dpAudioUnderrunEvent
+// Params: const RawAddress& raw_address, uint64_t encoding_interval_millis, int
+// num_missing_pcm_bytes Returns: void
+struct LogMetricA2dpAudioUnderrunEvent {
+ std::function<void(const RawAddress& raw_address,
+ uint64_t encoding_interval_millis,
+ int num_missing_pcm_bytes)>
+ body{[](const RawAddress& raw_address, uint64_t encoding_interval_millis,
+ int num_missing_pcm_bytes) {}};
+ void operator()(const RawAddress& raw_address,
+ uint64_t encoding_interval_millis,
+ int num_missing_pcm_bytes) {
+ body(raw_address, encoding_interval_millis, num_missing_pcm_bytes);
+ };
+};
+extern struct LogMetricA2dpAudioUnderrunEvent LogMetricA2dpAudioUnderrunEvent;
+// Name: LogMetricA2dpAudioOverrunEvent
+// Params: const RawAddress& raw_address, uint64_t encoding_interval_millis, int
+// num_dropped_buffers, int num_dropped_encoded_frames, int
+// num_dropped_encoded_bytes Returns: void
+struct LogMetricA2dpAudioOverrunEvent {
+ std::function<void(const RawAddress& raw_address,
+ uint64_t encoding_interval_millis, int num_dropped_buffers,
+ int num_dropped_encoded_frames,
+ int num_dropped_encoded_bytes)>
+ body{[](const RawAddress& raw_address, uint64_t encoding_interval_millis,
+ int num_dropped_buffers, int num_dropped_encoded_frames,
+ int num_dropped_encoded_bytes) {}};
+ void operator()(const RawAddress& raw_address,
+ uint64_t encoding_interval_millis, int num_dropped_buffers,
+ int num_dropped_encoded_frames,
+ int num_dropped_encoded_bytes) {
+ body(raw_address, encoding_interval_millis, num_dropped_buffers,
+ num_dropped_encoded_frames, num_dropped_encoded_bytes);
+ };
+};
+extern struct LogMetricA2dpAudioOverrunEvent LogMetricA2dpAudioOverrunEvent;
+// Name: LogMetricA2dpPlaybackEvent
+// Params: const RawAddress& raw_address, int playback_state, int
+// audio_coding_mode Returns: void
+struct LogMetricA2dpPlaybackEvent {
+ std::function<void(const RawAddress& raw_address, int playback_state,
+ int audio_coding_mode)>
+ body{[](const RawAddress& raw_address, int playback_state,
+ int audio_coding_mode) {}};
+ void operator()(const RawAddress& raw_address, int playback_state,
+ int audio_coding_mode) {
+ body(raw_address, playback_state, audio_coding_mode);
+ };
+};
+extern struct LogMetricA2dpPlaybackEvent LogMetricA2dpPlaybackEvent;
+// Name: LogMetricReadRssiResult
+// Params: const RawAddress& raw_address, uint16_t handle, uint32_t cmd_status,
+// int8_t rssi Returns: void
+struct LogMetricReadRssiResult {
+ std::function<void(const RawAddress& raw_address, uint16_t handle,
+ uint32_t cmd_status, int8_t rssi)>
+ body{[](const RawAddress& raw_address, uint16_t handle,
+ uint32_t cmd_status, int8_t rssi) {}};
+ void operator()(const RawAddress& raw_address, uint16_t handle,
+ uint32_t cmd_status, int8_t rssi) {
+ body(raw_address, handle, cmd_status, rssi);
+ };
+};
+extern struct LogMetricReadRssiResult LogMetricReadRssiResult;
+// Name: LogMetricReadFailedContactCounterResult
+// Params: const RawAddress& raw_address, uint16_t handle, uint32_t cmd_status,
+// int32_t failed_contact_counter Returns: void
+struct LogMetricReadFailedContactCounterResult {
+ std::function<void(const RawAddress& raw_address, uint16_t handle,
+ uint32_t cmd_status, int32_t failed_contact_counter)>
+ body{[](const RawAddress& raw_address, uint16_t handle,
+ uint32_t cmd_status, int32_t failed_contact_counter) {}};
+ void operator()(const RawAddress& raw_address, uint16_t handle,
+ uint32_t cmd_status, int32_t failed_contact_counter) {
+ body(raw_address, handle, cmd_status, failed_contact_counter);
+ };
+};
+extern struct LogMetricReadFailedContactCounterResult
+ LogMetricReadFailedContactCounterResult;
+// Name: LogMetricReadTxPowerLevelResult
+// Params: const RawAddress& raw_address, uint16_t handle, uint32_t cmd_status,
+// int32_t transmit_power_level Returns: void
+struct LogMetricReadTxPowerLevelResult {
+ std::function<void(const RawAddress& raw_address, uint16_t handle,
+ uint32_t cmd_status, int32_t transmit_power_level)>
+ body{[](const RawAddress& raw_address, uint16_t handle,
+ uint32_t cmd_status, int32_t transmit_power_level) {}};
+ void operator()(const RawAddress& raw_address, uint16_t handle,
+ uint32_t cmd_status, int32_t transmit_power_level) {
+ body(raw_address, handle, cmd_status, transmit_power_level);
+ };
+};
+extern struct LogMetricReadTxPowerLevelResult LogMetricReadTxPowerLevelResult;
+// Name: LogMetricSmpPairingEvent
+// Params: const RawAddress& raw_address, uint8_t smp_cmd,
+// android::bluetooth::DirectionEnum direction, uint8_t smp_fail_reason Returns:
+// void
+struct LogMetricSmpPairingEvent {
+ std::function<void(const RawAddress& raw_address, uint8_t smp_cmd,
+ android::bluetooth::DirectionEnum direction,
+ uint8_t smp_fail_reason)>
+ body{[](const RawAddress& raw_address, uint8_t smp_cmd,
+ android::bluetooth::DirectionEnum direction,
+ uint8_t smp_fail_reason) {}};
+ void operator()(const RawAddress& raw_address, uint8_t smp_cmd,
+ android::bluetooth::DirectionEnum direction,
+ uint8_t smp_fail_reason) {
+ body(raw_address, smp_cmd, direction, smp_fail_reason);
+ };
+};
+extern struct LogMetricSmpPairingEvent LogMetricSmpPairingEvent;
+// Name: LogMetricClassicPairingEvent
+// Params: const RawAddress& raw_address, uint16_t handle, uint32_t hci_cmd,
+// uint16_t hci_event, uint16_t cmd_status, uint16_t reason_code, int64_t
+// event_value Returns: void
+struct LogMetricClassicPairingEvent {
+ std::function<void(const RawAddress& raw_address, uint16_t handle,
+ uint32_t hci_cmd, uint16_t hci_event, uint16_t cmd_status,
+ uint16_t reason_code, int64_t event_value)>
+ body{[](const RawAddress& raw_address, uint16_t handle, uint32_t hci_cmd,
+ uint16_t hci_event, uint16_t cmd_status, uint16_t reason_code,
+ int64_t event_value) {}};
+ void operator()(const RawAddress& raw_address, uint16_t handle,
+ uint32_t hci_cmd, uint16_t hci_event, uint16_t cmd_status,
+ uint16_t reason_code, int64_t event_value) {
+ body(raw_address, handle, hci_cmd, hci_event, cmd_status, reason_code,
+ event_value);
+ };
+};
+extern struct LogMetricClassicPairingEvent LogMetricClassicPairingEvent;
+// Name: LogMetricSdpAttribute
+// Params: const RawAddress& raw_address, uint16_t protocol_uuid, uint16_t
+// attribute_id, size_t attribute_size, const char* attribute_value Returns:
+// void
+struct LogMetricSdpAttribute {
+ std::function<void(const RawAddress& raw_address, uint16_t protocol_uuid,
+ uint16_t attribute_id, size_t attribute_size,
+ const char* attribute_value)>
+ body{[](const RawAddress& raw_address, uint16_t protocol_uuid,
+ uint16_t attribute_id, size_t attribute_size,
+ const char* attribute_value) {}};
+ void operator()(const RawAddress& raw_address, uint16_t protocol_uuid,
+ uint16_t attribute_id, size_t attribute_size,
+ const char* attribute_value) {
+ body(raw_address, protocol_uuid, attribute_id, attribute_size,
+ attribute_value);
+ };
+};
+extern struct LogMetricSdpAttribute LogMetricSdpAttribute;
+// Name: LogMetricSocketConnectionState
+// Params: const RawAddress& raw_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 Returns: void
+struct LogMetricSocketConnectionState {
+ std::function<void(
+ const RawAddress& raw_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)>
+ body{[](const RawAddress& raw_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) {}};
+ void operator()(
+ const RawAddress& raw_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) {
+ body(raw_address, port, type, connection_state, tx_bytes, rx_bytes, uid,
+ server_port, socket_role);
+ };
+};
+extern struct LogMetricSocketConnectionState LogMetricSocketConnectionState;
+// Name: LogMetricManufacturerInfo
+// Params: const RawAddress& raw_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 Returns: void
+struct LogMetricManufacturerInfo {
+ std::function<void(const RawAddress& raw_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)>
+ body{[](const RawAddress& raw_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) {}};
+ void operator()(const RawAddress& raw_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) {
+ body(raw_address, source_type, source_name, manufacturer, model,
+ hardware_version, software_version);
+ };
+};
+extern struct LogMetricManufacturerInfo LogMetricManufacturerInfo;
+
+} // namespace main_shim_metrics_api
+} // namespace mock
+} // namespace test
+
+// END mockcify generation
\ No newline at end of file
diff --git a/test/mock/mock_stack_a2dp_api.cc b/test/mock/mock_stack_a2dp_api.cc
index 5ca5671..db59f9f 100644
--- a/test/mock/mock_stack_a2dp_api.cc
+++ b/test/mock/mock_stack_a2dp_api.cc
@@ -26,12 +26,12 @@
#include <string.h>
#include "a2dp_api.h"
-#include "a2dp_int.h"
#include "avdt_api.h"
#include "bt_common.h"
#include "bt_target.h"
#include "osi/include/log.h"
#include "sdpdefs.h"
+#include "stack/a2dp/a2dp_int.h"
#ifndef UNUSED_ATTR
#define UNUSED_ATTR
diff --git a/test/mock/mock_stack_acl.cc b/test/mock/mock_stack_acl.cc
index b0975b1..ad69ce4 100644
--- a/test/mock/mock_stack_acl.cc
+++ b/test/mock/mock_stack_acl.cc
@@ -287,6 +287,9 @@
void acl_packets_completed(uint16_t handle, uint16_t credits) {
mock_function_count_map[__func__]++;
}
+void acl_process_supported_features(uint16_t handle, uint64_t features) {
+ mock_function_count_map[__func__]++;
+}
void acl_process_extended_features(uint16_t handle, uint8_t current_page_number,
uint8_t max_page_number, uint64_t features) {
mock_function_count_map[__func__]++;
@@ -308,9 +311,6 @@
uint16_t flush_timeout_in_ticks) {
mock_function_count_map[__func__]++;
}
-void btm_acl_chk_peer_pkt_type_support(tACL_CONN* p, uint16_t* p_pkt_type) {
- mock_function_count_map[__func__]++;
-}
void btm_acl_connected(const RawAddress& bda, uint16_t handle,
tHCI_STATUS status, uint8_t enc_mode) {
mock_function_count_map[__func__]++;
@@ -366,7 +366,7 @@
mock_function_count_map[__func__]++;
}
void btm_process_remote_ext_features(tACL_CONN* p_acl_cb,
- uint8_t num_read_pages) {
+ uint8_t max_page_number) {
mock_function_count_map[__func__]++;
}
void btm_process_remote_version_complete(uint8_t status, uint16_t handle,
@@ -450,3 +450,7 @@
void on_acl_br_edr_failed(const RawAddress& bda, tHCI_STATUS status) {
mock_function_count_map[__func__]++;
}
+void acl_add_to_ignore_auto_connect_after_disconnect(
+ const RawAddress& bd_addr) {
+ mock_function_count_map[__func__]++;
+}
diff --git a/main/test/common/mock_acl_ble.cc b/test/mock/mock_stack_acl_ble.cc
similarity index 100%
rename from main/test/common/mock_acl_ble.cc
rename to test/mock/mock_stack_acl_ble.cc
diff --git a/test/mock/mock_stack_acl_btm_ble_connection_establishment.cc b/test/mock/mock_stack_acl_btm_ble_connection_establishment.cc
new file mode 100644
index 0000000..465a3fe
--- /dev/null
+++ b/test/mock/mock_stack_acl_btm_ble_connection_establishment.cc
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:6
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <cstdint>
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+
+// Mock include file to share data between tests and mock
+#include "test/mock/mock_stack_acl_btm_ble_connection_establishment.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+// Mocked internal structures, if any
+
+namespace test {
+namespace mock {
+namespace stack_acl_btm_ble_connection_establishment {
+
+// Function state capture and return values, if needed
+struct btm_send_hci_create_connection btm_send_hci_create_connection;
+struct btm_ble_create_ll_conn_complete btm_ble_create_ll_conn_complete;
+struct maybe_resolve_address maybe_resolve_address;
+struct btm_ble_conn_complete btm_ble_conn_complete;
+struct btm_ble_create_conn_cancel btm_ble_create_conn_cancel;
+struct btm_ble_create_conn_cancel_complete btm_ble_create_conn_cancel_complete;
+
+} // namespace stack_acl_btm_ble_connection_establishment
+} // namespace mock
+} // namespace test
+
+// Mocked functions, if any
+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) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_acl_btm_ble_connection_establishment::
+ btm_send_hci_create_connection(
+ 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, initiating_phys);
+}
+void btm_ble_create_ll_conn_complete(tHCI_STATUS status) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_acl_btm_ble_connection_establishment::
+ btm_ble_create_ll_conn_complete(status);
+}
+bool maybe_resolve_address(RawAddress* bda, tBLE_ADDR_TYPE* bda_type) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_acl_btm_ble_connection_establishment::
+ maybe_resolve_address(bda, bda_type);
+}
+void btm_ble_conn_complete(uint8_t* p, uint16_t evt_len, bool enhanced) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_acl_btm_ble_connection_establishment::btm_ble_conn_complete(
+ p, evt_len, enhanced);
+}
+void btm_ble_create_conn_cancel() {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_acl_btm_ble_connection_establishment::
+ btm_ble_create_conn_cancel();
+}
+void btm_ble_create_conn_cancel_complete(uint8_t* p) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_acl_btm_ble_connection_establishment::
+ btm_ble_create_conn_cancel_complete(p);
+}
+
+// END mockcify generation
diff --git a/test/mock/mock_stack_acl_btm_ble_connection_establishment.h b/test/mock/mock_stack_acl_btm_ble_connection_establishment.h
new file mode 100644
index 0000000..c546d03
--- /dev/null
+++ b/test/mock/mock_stack_acl_btm_ble_connection_establishment.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:6
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <cstdint>
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+
+#include "stack/include/hci_error_code.h"
+#include "types/ble_address_with_type.h"
+#include "types/raw_address.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+namespace test {
+namespace mock {
+namespace stack_acl_btm_ble_connection_establishment {
+
+// Shared state between mocked functions and tests
+// Name: btm_send_hci_create_connection
+// Params: 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 Returns: void
+struct btm_send_hci_create_connection {
+ std::function<void(
+ 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)>
+ body{[](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) {}};
+ void operator()(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) {
+ body(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, initiating_phys);
+ };
+};
+extern struct btm_send_hci_create_connection btm_send_hci_create_connection;
+// Name: btm_ble_create_ll_conn_complete
+// Params: tHCI_STATUS status
+// Returns: void
+struct btm_ble_create_ll_conn_complete {
+ std::function<void(tHCI_STATUS status)> body{[](tHCI_STATUS status) {}};
+ void operator()(tHCI_STATUS status) { body(status); };
+};
+extern struct btm_ble_create_ll_conn_complete btm_ble_create_ll_conn_complete;
+// Name: maybe_resolve_address
+// Params: RawAddress* bda, tBLE_ADDR_TYPE* bda_type
+// Returns: bool
+struct maybe_resolve_address {
+ std::function<bool(RawAddress* bda, tBLE_ADDR_TYPE* bda_type)> body{
+ [](RawAddress* bda, tBLE_ADDR_TYPE* bda_type) { return false; }};
+ bool operator()(RawAddress* bda, tBLE_ADDR_TYPE* bda_type) {
+ return body(bda, bda_type);
+ };
+};
+extern struct maybe_resolve_address maybe_resolve_address;
+// Name: btm_ble_conn_complete
+// Params: uint8_t* p, uint16_t evt_len, bool enhanced
+// Returns: void
+struct btm_ble_conn_complete {
+ std::function<void(uint8_t* p, uint16_t evt_len, bool enhanced)> body{
+ [](uint8_t* p, uint16_t evt_len, bool enhanced) {}};
+ void operator()(uint8_t* p, uint16_t evt_len, bool enhanced) {
+ body(p, evt_len, enhanced);
+ };
+};
+extern struct btm_ble_conn_complete btm_ble_conn_complete;
+// Name: btm_ble_create_conn_cancel
+// Params:
+// Returns: void
+struct btm_ble_create_conn_cancel {
+ std::function<void()> body{[]() {}};
+ void operator()() { body(); };
+};
+extern struct btm_ble_create_conn_cancel btm_ble_create_conn_cancel;
+// Name: btm_ble_create_conn_cancel_complete
+// Params: uint8_t* p
+// Returns: void
+struct btm_ble_create_conn_cancel_complete {
+ std::function<void(uint8_t* p)> body{[](uint8_t* p) {}};
+ void operator()(uint8_t* p) { body(p); };
+};
+extern struct btm_ble_create_conn_cancel_complete
+ btm_ble_create_conn_cancel_complete;
+
+} // namespace stack_acl_btm_ble_connection_establishment
+} // namespace mock
+} // namespace test
+
+// END mockcify generation
diff --git a/main/test/common/mock_acl_btm_pm.cc b/test/mock/mock_stack_acl_btm_pm.cc
similarity index 94%
rename from main/test/common/mock_acl_btm_pm.cc
rename to test/mock/mock_stack_acl_btm_pm.cc
index 1b2305a..2461c37 100644
--- a/main/test/common/mock_acl_btm_pm.cc
+++ b/test/mock/mock_stack_acl_btm_pm.cc
@@ -56,6 +56,11 @@
mock_function_count_map[__func__]++;
return 0;
}
+tBTM_STATUS BTM_PmRegister(uint8_t mask, uint8_t* p_pm_id,
+ tBTM_PM_STATUS_CBACK* p_cb) {
+ mock_function_count_map[__func__]++;
+ return BTM_SUCCESS;
+}
tBTM_STATUS BTM_SetPowerMode(uint8_t pm_id, const RawAddress& remote_bda,
const tBTM_PM_PWR_MD* p_mode) {
mock_function_count_map[__func__]++;
diff --git a/test/mock/mock_stack_avct_api.cc b/test/mock/mock_stack_avct_api.cc
index 4c20810..85adf06 100644
--- a/test/mock/mock_stack_avct_api.cc
+++ b/test/mock/mock_stack_avct_api.cc
@@ -29,7 +29,6 @@
#include "bt_common.h"
#include "bt_target.h"
#include "bt_types.h"
-#include "bt_utils.h"
#include "bta/include/bta_api.h"
#include "btm_api.h"
#include "l2c_api.h"
diff --git a/test/mock/mock_stack_avdt_api.cc b/test/mock/mock_stack_avdt_api.cc
index e305168..a758601 100644
--- a/test/mock/mock_stack_avdt_api.cc
+++ b/test/mock/mock_stack_avdt_api.cc
@@ -26,7 +26,6 @@
#include <string.h>
#include "avdt_api.h"
-#include "avdt_int.h"
#include "avdtc_api.h"
#include "bt_target.h"
#include "bt_types.h"
@@ -36,6 +35,7 @@
#include "l2c_api.h"
#include "main/shim/dumpsys.h"
#include "osi/include/log.h"
+#include "stack/avdt/avdt_int.h"
#include "stack/btm/btm_sec.h"
#include "stack/include/a2dp_codec_api.h"
diff --git a/test/mock/mock_stack_avrc_bld_tg.cc b/test/mock/mock_stack_avrc_bld_tg.cc
index 96ebee0..2189915 100644
--- a/test/mock/mock_stack_avrc_bld_tg.cc
+++ b/test/mock/mock_stack_avrc_bld_tg.cc
@@ -29,7 +29,6 @@
#include "avrc_api.h"
#include "avrc_defs.h"
#include "bt_common.h"
-#include "bt_utils.h"
#include "osi/include/osi.h"
#include "stack/avrc/avrc_int.h"
diff --git a/test/mock/mock_stack_avrc_pars.ct.cc b/test/mock/mock_stack_avrc_pars.ct.cc
index d4d4ee4..b4f88e7 100644
--- a/test/mock/mock_stack_avrc_pars.ct.cc
+++ b/test/mock/mock_stack_avrc_pars.ct.cc
@@ -28,7 +28,6 @@
#include "avrc_api.h"
#include "avrc_defs.h"
#include "bt_common.h"
-#include "bt_utils.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
#include "stack/avrc/avrc_int.h"
diff --git a/test/mock/mock_stack_btm.cc b/test/mock/mock_stack_btm.cc
index 12f62af..d1a8b6b 100644
--- a/test/mock/mock_stack_btm.cc
+++ b/test/mock/mock_stack_btm.cc
@@ -22,39 +22,10 @@
#include "stack/include/btm_client_interface.h"
#include "types/raw_address.h"
-bool BTM_HasEirService(const uint32_t* p_eir_uuid, uint16_t uuid16) {
- return false;
-}
-tBTM_INQ_INFO* BTM_InqDbFirst(void) { return nullptr; }
-tBTM_INQ_INFO* BTM_InqDbNext(tBTM_INQ_INFO* p_cur) { return nullptr; }
-tBTM_INQ_INFO* BTM_InqDbRead(const RawAddress& p_bda) { return nullptr; }
-tBTM_STATUS BTM_CancelRemoteDeviceName(void) { return BTM_SUCCESS; }
-tBTM_STATUS BTM_ClearInqDb(const RawAddress* p_bda) { return BTM_SUCCESS; }
-tBTM_STATUS BTM_ReadRemoteDeviceName(const RawAddress& remote_bda,
- tBTM_CMPL_CB* p_cb,
- tBT_TRANSPORT transport) {
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_SetConnectability(uint16_t page_mode) { return BTM_SUCCESS; }
-tBTM_STATUS BTM_StartInquiry(tBTM_INQ_RESULTS_CB* p_results_cb,
- tBTM_CMPL_CB* p_cmpl_cb) {
- return BTM_SUCCESS;
-}
-tBTM_STATUS BTM_WriteEIR(BT_HDR* p_buff) { return BTM_SUCCESS; }
-tBTM_STATUS BTM_SetDiscoverability(uint16_t inq_mode) { return BTM_SUCCESS; }
tBTM_STATUS BTM_BleGetEnergyInfo(tBTM_BLE_ENERGY_INFO_CBACK* p_ener_cback) {
return BTM_SUCCESS;
}
-uint16_t BTM_IsInquiryActive(void) { return 0; }
-uint8_t BTM_GetEirSupportedServices(uint32_t* p_eir_uuid, uint8_t** p,
- uint8_t max_num_uuid16,
- uint8_t* p_num_uuid16) {
- return 0;
-}
-void BTM_AddEirService(uint32_t* p_eir_uuid, uint16_t uuid16) {}
void BTM_BleReadControllerFeatures(tBTM_BLE_CTRL_FEATURES_CBACK* p_vsc_cback) {}
-void BTM_CancelInquiry(void) {}
-void BTM_RemoveEirService(uint32_t* p_eir_uuid, uint16_t uuid16) {}
bool BTM_is_sniff_allowed_for(const RawAddress& peer_addr) { return false; }
uint8_t BTM_GetAcceptlistSize() { return 0; }
diff --git a/test/mock/mock_stack_btm_ble_addr.cc b/test/mock/mock_stack_btm_ble_addr.cc
new file mode 100644
index 0000000..7db8498
--- /dev/null
+++ b/test/mock/mock_stack_btm_ble_addr.cc
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:10
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+
+// Mock include file to share data between tests and mock
+#include "test/mock/mock_stack_btm_ble_addr.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+// Mocked internal structures, if any
+
+namespace test {
+namespace mock {
+namespace stack_btm_ble_addr {
+
+// Function state capture and return values, if needed
+struct btm_gen_resolve_paddr_low btm_gen_resolve_paddr_low;
+struct btm_gen_resolvable_private_addr btm_gen_resolvable_private_addr;
+struct btm_get_next_private_addrress_interval_ms
+ btm_get_next_private_addrress_interval_ms;
+struct btm_ble_init_pseudo_addr btm_ble_init_pseudo_addr;
+struct btm_ble_addr_resolvable btm_ble_addr_resolvable;
+struct btm_ble_resolve_random_addr btm_ble_resolve_random_addr;
+struct btm_identity_addr_to_random_pseudo btm_identity_addr_to_random_pseudo;
+struct btm_identity_addr_to_random_pseudo_from_address_with_type
+ btm_identity_addr_to_random_pseudo_from_address_with_type;
+struct btm_random_pseudo_to_identity_addr btm_random_pseudo_to_identity_addr;
+struct btm_ble_refresh_peer_resolvable_private_addr
+ btm_ble_refresh_peer_resolvable_private_addr;
+
+} // namespace stack_btm_ble_addr
+} // namespace mock
+} // namespace test
+
+// Mocked functions, if any
+void btm_gen_resolve_paddr_low(const RawAddress& address) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_btm_ble_addr::btm_gen_resolve_paddr_low(address);
+}
+void btm_gen_resolvable_private_addr(
+ base::Callback<void(const RawAddress&)> cb) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_btm_ble_addr::btm_gen_resolvable_private_addr(cb);
+}
+uint64_t btm_get_next_private_addrress_interval_ms() {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_btm_ble_addr::
+ btm_get_next_private_addrress_interval_ms();
+}
+bool btm_ble_init_pseudo_addr(tBTM_SEC_DEV_REC* p_dev_rec,
+ const RawAddress& new_pseudo_addr) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_btm_ble_addr::btm_ble_init_pseudo_addr(
+ p_dev_rec, new_pseudo_addr);
+}
+bool btm_ble_addr_resolvable(const RawAddress& rpa,
+ tBTM_SEC_DEV_REC* p_dev_rec) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_btm_ble_addr::btm_ble_addr_resolvable(rpa,
+ p_dev_rec);
+}
+tBTM_SEC_DEV_REC* btm_ble_resolve_random_addr(const RawAddress& random_bda) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_btm_ble_addr::btm_ble_resolve_random_addr(
+ random_bda);
+}
+bool btm_identity_addr_to_random_pseudo(RawAddress* bd_addr,
+ uint8_t* p_addr_type, bool refresh) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_btm_ble_addr::btm_identity_addr_to_random_pseudo(
+ bd_addr, p_addr_type, refresh);
+}
+bool btm_identity_addr_to_random_pseudo_from_address_with_type(
+ tBLE_BD_ADDR* address_with_type, bool refresh) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_btm_ble_addr::
+ btm_identity_addr_to_random_pseudo_from_address_with_type(
+ address_with_type, refresh);
+}
+bool btm_random_pseudo_to_identity_addr(RawAddress* random_pseudo,
+ uint8_t* p_identity_addr_type) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_btm_ble_addr::btm_random_pseudo_to_identity_addr(
+ random_pseudo, p_identity_addr_type);
+}
+void btm_ble_refresh_peer_resolvable_private_addr(
+ const RawAddress& pseudo_bda, const RawAddress& rpa,
+ tBTM_SEC_BLE::tADDRESS_TYPE rra_type) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_btm_ble_addr::btm_ble_refresh_peer_resolvable_private_addr(
+ pseudo_bda, rpa, rra_type);
+}
+
+// END mockcify generation
diff --git a/test/mock/mock_stack_btm_ble_addr.h b/test/mock/mock_stack_btm_ble_addr.h
new file mode 100644
index 0000000..a3236fb
--- /dev/null
+++ b/test/mock/mock_stack_btm_ble_addr.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:10
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <base/callback.h> // RepeatingCallback
+#include <cstdint>
+#include <functional>
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+//
+#include "stack/btm/security_device_record.h"
+#include "types/ble_address_with_type.h"
+#include "types/raw_address.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+namespace test {
+namespace mock {
+namespace stack_btm_ble_addr {
+
+// Shared state between mocked functions and tests
+// Name: btm_gen_resolve_paddr_low
+// Params: const RawAddress& address
+// Returns: void
+struct btm_gen_resolve_paddr_low {
+ std::function<void(const RawAddress& address)> body{
+ [](const RawAddress& address) {}};
+ void operator()(const RawAddress& address) { body(address); };
+};
+extern struct btm_gen_resolve_paddr_low btm_gen_resolve_paddr_low;
+// Name: btm_gen_resolvable_private_addr
+// Params: base::Callback<void(const RawAddress&)> cb
+// Returns: void
+struct btm_gen_resolvable_private_addr {
+ std::function<void(base::Callback<void(const RawAddress&)> cb)> body{
+ [](base::Callback<void(const RawAddress&)> cb) {}};
+ void operator()(base::Callback<void(const RawAddress&)> cb) { body(cb); };
+};
+extern struct btm_gen_resolvable_private_addr btm_gen_resolvable_private_addr;
+// Name: btm_get_next_private_addrress_interval_ms
+// Params:
+// Returns: uint64_t
+struct btm_get_next_private_addrress_interval_ms {
+ std::function<uint64_t()> body{[]() { return 0; }};
+ uint64_t operator()() { return body(); };
+};
+extern struct btm_get_next_private_addrress_interval_ms
+ btm_get_next_private_addrress_interval_ms;
+// Name: btm_ble_init_pseudo_addr
+// Params: tBTM_SEC_DEV_REC* p_dev_rec, const RawAddress& new_pseudo_addr
+// Returns: bool
+struct btm_ble_init_pseudo_addr {
+ std::function<bool(tBTM_SEC_DEV_REC* p_dev_rec,
+ const RawAddress& new_pseudo_addr)>
+ body{[](tBTM_SEC_DEV_REC* p_dev_rec, const RawAddress& new_pseudo_addr) {
+ return false;
+ }};
+ bool operator()(tBTM_SEC_DEV_REC* p_dev_rec,
+ const RawAddress& new_pseudo_addr) {
+ return body(p_dev_rec, new_pseudo_addr);
+ };
+};
+extern struct btm_ble_init_pseudo_addr btm_ble_init_pseudo_addr;
+// Name: btm_ble_addr_resolvable
+// Params: const RawAddress& rpa, tBTM_SEC_DEV_REC* p_dev_rec
+// Returns: bool
+struct btm_ble_addr_resolvable {
+ std::function<bool(const RawAddress& rpa, tBTM_SEC_DEV_REC* p_dev_rec)> body{
+ [](const RawAddress& rpa, tBTM_SEC_DEV_REC* p_dev_rec) { return false; }};
+ bool operator()(const RawAddress& rpa, tBTM_SEC_DEV_REC* p_dev_rec) {
+ return body(rpa, p_dev_rec);
+ };
+};
+extern struct btm_ble_addr_resolvable btm_ble_addr_resolvable;
+// Name: btm_ble_resolve_random_addr
+// Params: const RawAddress& random_bda
+// Returns: tBTM_SEC_DEV_REC*
+struct btm_ble_resolve_random_addr {
+ std::function<tBTM_SEC_DEV_REC*(const RawAddress& random_bda)> body{
+ [](const RawAddress& random_bda) { return nullptr; }};
+ tBTM_SEC_DEV_REC* operator()(const RawAddress& random_bda) {
+ return body(random_bda);
+ };
+};
+extern struct btm_ble_resolve_random_addr btm_ble_resolve_random_addr;
+// Name: btm_identity_addr_to_random_pseudo
+// Params: RawAddress* bd_addr, uint8_t* p_addr_type, bool refresh
+// Returns: bool
+struct btm_identity_addr_to_random_pseudo {
+ std::function<bool(RawAddress* bd_addr, uint8_t* p_addr_type, bool refresh)>
+ body{[](RawAddress* bd_addr, uint8_t* p_addr_type, bool refresh) {
+ return false;
+ }};
+ bool operator()(RawAddress* bd_addr, uint8_t* p_addr_type, bool refresh) {
+ return body(bd_addr, p_addr_type, refresh);
+ };
+};
+extern struct btm_identity_addr_to_random_pseudo
+ btm_identity_addr_to_random_pseudo;
+// Name: btm_identity_addr_to_random_pseudo_from_address_with_type
+// Params: tBLE_BD_ADDR* address_with_type, bool refresh
+// Returns: bool
+struct btm_identity_addr_to_random_pseudo_from_address_with_type {
+ std::function<bool(tBLE_BD_ADDR* address_with_type, bool refresh)> body{
+ [](tBLE_BD_ADDR* address_with_type, bool refresh) { return false; }};
+ bool operator()(tBLE_BD_ADDR* address_with_type, bool refresh) {
+ return body(address_with_type, refresh);
+ };
+};
+extern struct btm_identity_addr_to_random_pseudo_from_address_with_type
+ btm_identity_addr_to_random_pseudo_from_address_with_type;
+// Name: btm_random_pseudo_to_identity_addr
+// Params: RawAddress* random_pseudo, uint8_t* p_identity_addr_type
+// Returns: bool
+struct btm_random_pseudo_to_identity_addr {
+ std::function<bool(RawAddress* random_pseudo, uint8_t* p_identity_addr_type)>
+ body{[](RawAddress* random_pseudo, uint8_t* p_identity_addr_type) {
+ return false;
+ }};
+ bool operator()(RawAddress* random_pseudo, uint8_t* p_identity_addr_type) {
+ return body(random_pseudo, p_identity_addr_type);
+ };
+};
+extern struct btm_random_pseudo_to_identity_addr
+ btm_random_pseudo_to_identity_addr;
+// Name: btm_ble_refresh_peer_resolvable_private_addr
+// Params: const RawAddress& pseudo_bda, const RawAddress& rpa,
+// tBTM_SEC_BLE::tADDRESS_TYPE rra_type Returns: void
+struct btm_ble_refresh_peer_resolvable_private_addr {
+ std::function<void(const RawAddress& pseudo_bda, const RawAddress& rpa,
+ tBTM_SEC_BLE::tADDRESS_TYPE rra_type)>
+ body{[](const RawAddress& pseudo_bda, const RawAddress& rpa,
+ tBTM_SEC_BLE::tADDRESS_TYPE rra_type) {}};
+ void operator()(const RawAddress& pseudo_bda, const RawAddress& rpa,
+ tBTM_SEC_BLE::tADDRESS_TYPE rra_type) {
+ body(pseudo_bda, rpa, rra_type);
+ };
+};
+extern struct btm_ble_refresh_peer_resolvable_private_addr
+ btm_ble_refresh_peer_resolvable_private_addr;
+
+} // namespace stack_btm_ble_addr
+} // namespace mock
+} // namespace test
+
+// END mockcify generation
diff --git a/test/mock/mock_stack_btm_ble_adv_filter.cc b/test/mock/mock_stack_btm_ble_adv_filter.cc
index c65dea0..8d53a80 100644
--- a/test/mock/mock_stack_btm_ble_adv_filter.cc
+++ b/test/mock/mock_stack_btm_ble_adv_filter.cc
@@ -25,14 +25,13 @@
extern std::map<std::string, int> mock_function_count_map;
#include <base/bind.h>
-#include <base/bind_helpers.h>
#include <string.h>
#include <algorithm>
#include <vector>
+#include "bind_helpers.h"
#include "bt_target.h"
#include "bt_types.h"
#include "btm_ble_api.h"
-#include "btm_int.h"
#include "btu.h"
#include "device/include/controller.h"
#include "hcidefs.h"
diff --git a/test/mock/mock_stack_btm_ble_advertiser_hci_interface.cc b/test/mock/mock_stack_btm_ble_advertiser_hci_interface.cc
new file mode 100644
index 0000000..777410b
--- /dev/null
+++ b/test/mock/mock_stack_btm_ble_advertiser_hci_interface.cc
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:5
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <cstdint>
+#include <functional>
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+
+// Mock include file to share data between tests and mock
+#include "test/mock/mock_stack_btm_ble_advertiser_hci_interface.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+// Mocked internal structures, if any
+
+namespace test {
+namespace mock {
+namespace stack_btm_ble_advertiser_hci_interface {
+
+// Function state capture and return values, if needed
+struct btm_le_on_advertising_set_terminated
+ btm_le_on_advertising_set_terminated;
+struct btm_ble_advertiser_notify_terminated_legacy
+ btm_ble_advertiser_notify_terminated_legacy;
+
+} // namespace stack_btm_ble_advertiser_hci_interface
+} // namespace mock
+} // namespace test
+
+// Mocked functions, if any
+void btm_le_on_advertising_set_terminated(uint8_t* p, uint16_t length) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_btm_ble_advertiser_hci_interface::
+ btm_le_on_advertising_set_terminated(p, length);
+}
+void btm_ble_advertiser_notify_terminated_legacy(uint8_t status,
+ uint16_t connection_handle) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_btm_ble_advertiser_hci_interface::
+ btm_ble_advertiser_notify_terminated_legacy(status, connection_handle);
+}
+
+// END mockcify generation
diff --git a/test/mock/mock_stack_btm_ble_advertiser_hci_interface.h b/test/mock/mock_stack_btm_ble_advertiser_hci_interface.h
new file mode 100644
index 0000000..05fef71
--- /dev/null
+++ b/test/mock/mock_stack_btm_ble_advertiser_hci_interface.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:5
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <cstdint>
+#include <functional>
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+#include "stack/btm/ble_advertiser_hci_interface.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+namespace test {
+namespace mock {
+namespace stack_btm_ble_advertiser_hci_interface {
+
+// Shared state between mocked functions and tests
+// Name: btm_le_on_advertising_set_terminated
+// Params: uint8_t* p, uint16_t length
+// Returns: void
+struct btm_le_on_advertising_set_terminated {
+ std::function<void(uint8_t* p, uint16_t length)> body{
+ [](uint8_t* p, uint16_t length) {}};
+ void operator()(uint8_t* p, uint16_t length) { body(p, length); };
+};
+extern struct btm_le_on_advertising_set_terminated
+ btm_le_on_advertising_set_terminated;
+// Name: btm_ble_advertiser_notify_terminated_legacy
+// Params: uint8_t status, uint16_t connection_handle
+// Returns: void
+struct btm_ble_advertiser_notify_terminated_legacy {
+ std::function<void(uint8_t status, uint16_t connection_handle)> body{
+ [](uint8_t status, uint16_t connection_handle) {}};
+ void operator()(uint8_t status, uint16_t connection_handle) {
+ body(status, connection_handle);
+ };
+};
+extern struct btm_ble_advertiser_notify_terminated_legacy
+ btm_ble_advertiser_notify_terminated_legacy;
+
+} // namespace stack_btm_ble_advertiser_hci_interface
+} // namespace mock
+} // namespace test
+
+// END mockcify generation
diff --git a/test/mock/mock_stack_btm_ble_batchscan.cc b/test/mock/mock_stack_btm_ble_batchscan.cc
index 143783b..3f5a880 100644
--- a/test/mock/mock_stack_btm_ble_batchscan.cc
+++ b/test/mock/mock_stack_btm_ble_batchscan.cc
@@ -32,7 +32,6 @@
#include "bt_target.h"
#include "bt_types.h"
#include "btm_ble_api.h"
-#include "btm_int.h"
#include "btu.h"
#include "device/include/controller.h"
#include "hcimsgs.h"
diff --git a/test/mock/mock_stack_btm_ble_bgconn.cc b/test/mock/mock_stack_btm_ble_bgconn.cc
new file mode 100644
index 0000000..0772b2b
--- /dev/null
+++ b/test/mock/mock_stack_btm_ble_bgconn.cc
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:11
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <cstdint>
+#include <functional>
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Mock include file to share data between tests and mock
+#include "test/mock/mock_stack_btm_ble_bgconn.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+// Mocked internal structures, if any
+struct BackgroundConnection {};
+struct BgConnHash {};
+
+namespace test {
+namespace mock {
+namespace stack_btm_ble_bgconn {
+
+// Function state capture and return values, if needed
+struct convert_to_address_with_type convert_to_address_with_type;
+struct btm_update_scanner_filter_policy btm_update_scanner_filter_policy;
+struct btm_ble_bgconn_cancel_if_disconnected
+ btm_ble_bgconn_cancel_if_disconnected;
+struct btm_ble_suspend_bg_conn btm_ble_suspend_bg_conn;
+struct btm_ble_resume_bg_conn btm_ble_resume_bg_conn;
+struct BTM_BackgroundConnectAddressKnown BTM_BackgroundConnectAddressKnown;
+struct BTM_SetLeConnectionModeToFast BTM_SetLeConnectionModeToFast;
+struct BTM_SetLeConnectionModeToSlow BTM_SetLeConnectionModeToSlow;
+struct BTM_AcceptlistAdd BTM_AcceptlistAdd;
+struct BTM_AcceptlistRemove BTM_AcceptlistRemove;
+struct BTM_AcceptlistClear BTM_AcceptlistClear;
+
+} // namespace stack_btm_ble_bgconn
+} // namespace mock
+} // namespace test
+
+// Mocked functions, if any
+const tBLE_BD_ADDR convert_to_address_with_type(
+ const RawAddress& bd_addr, const tBTM_SEC_DEV_REC* p_dev_rec) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_btm_ble_bgconn::convert_to_address_with_type(
+ bd_addr, p_dev_rec);
+}
+void btm_update_scanner_filter_policy(tBTM_BLE_SFP scan_policy) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_btm_ble_bgconn::btm_update_scanner_filter_policy(
+ scan_policy);
+}
+void btm_ble_bgconn_cancel_if_disconnected(const RawAddress& bd_addr) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_btm_ble_bgconn::btm_ble_bgconn_cancel_if_disconnected(
+ bd_addr);
+}
+bool btm_ble_suspend_bg_conn(void) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_btm_ble_bgconn::btm_ble_suspend_bg_conn();
+}
+bool btm_ble_resume_bg_conn(void) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_btm_ble_bgconn::btm_ble_resume_bg_conn();
+}
+bool BTM_BackgroundConnectAddressKnown(const RawAddress& address) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_btm_ble_bgconn::BTM_BackgroundConnectAddressKnown(
+ address);
+}
+bool BTM_SetLeConnectionModeToFast() {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_btm_ble_bgconn::BTM_SetLeConnectionModeToFast();
+}
+void BTM_SetLeConnectionModeToSlow() {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_btm_ble_bgconn::BTM_SetLeConnectionModeToSlow();
+}
+bool BTM_AcceptlistAdd(const RawAddress& address) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_btm_ble_bgconn::BTM_AcceptlistAdd(address);
+}
+void BTM_AcceptlistRemove(const RawAddress& address) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_btm_ble_bgconn::BTM_AcceptlistRemove(address);
+}
+void BTM_AcceptlistClear() {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_btm_ble_bgconn::BTM_AcceptlistClear();
+}
+
+// END mockcify generation
diff --git a/test/mock/mock_stack_btm_ble_bgconn.h b/test/mock/mock_stack_btm_ble_bgconn.h
new file mode 100644
index 0000000..41914ba
--- /dev/null
+++ b/test/mock/mock_stack_btm_ble_bgconn.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:11
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <cstdint>
+#include <functional>
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+#include <base/bind.h>
+#include <cstdint>
+#include <unordered_map>
+#include "device/include/controller.h"
+#include "main/shim/acl_api.h"
+#include "main/shim/shim.h"
+#include "stack/btm/btm_dev.h"
+#include "stack/btm/btm_int_types.h"
+#include "stack/btm/security_device_record.h"
+#include "stack/include/bt_types.h"
+#include "stack/include/hcimsgs.h"
+#include "types/raw_address.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+namespace test {
+namespace mock {
+namespace stack_btm_ble_bgconn {
+
+// Shared state between mocked functions and tests
+// Name: convert_to_address_with_type
+// Params: const RawAddress& bd_addr, const tBTM_SEC_DEV_REC* p_dev_rec
+// Returns: const tBLE_BD_ADDR
+struct convert_to_address_with_type {
+ tBLE_BD_ADDR ble_bd_addr;
+ std::function<const tBLE_BD_ADDR(const RawAddress& bd_addr,
+ const tBTM_SEC_DEV_REC* p_dev_rec)>
+ body{[this](const RawAddress& bd_addr,
+ const tBTM_SEC_DEV_REC* p_dev_rec) { return ble_bd_addr; }};
+ const tBLE_BD_ADDR operator()(const RawAddress& bd_addr,
+ const tBTM_SEC_DEV_REC* p_dev_rec) {
+ return body(bd_addr, p_dev_rec);
+ };
+};
+extern struct convert_to_address_with_type convert_to_address_with_type;
+// Name: btm_update_scanner_filter_policy
+// Params: tBTM_BLE_SFP scan_policy
+// Returns: void
+struct btm_update_scanner_filter_policy {
+ std::function<void(tBTM_BLE_SFP scan_policy)> body{
+ [](tBTM_BLE_SFP scan_policy) {}};
+ void operator()(tBTM_BLE_SFP scan_policy) { body(scan_policy); };
+};
+extern struct btm_update_scanner_filter_policy btm_update_scanner_filter_policy;
+// Name: btm_ble_bgconn_cancel_if_disconnected
+// Params: const RawAddress& bd_addr
+// Returns: void
+struct btm_ble_bgconn_cancel_if_disconnected {
+ std::function<void(const RawAddress& bd_addr)> body{
+ [](const RawAddress& bd_addr) {}};
+ void operator()(const RawAddress& bd_addr) { body(bd_addr); };
+};
+extern struct btm_ble_bgconn_cancel_if_disconnected
+ btm_ble_bgconn_cancel_if_disconnected;
+// Name: btm_ble_suspend_bg_conn
+// Params: void
+// Returns: bool
+struct btm_ble_suspend_bg_conn {
+ std::function<bool(void)> body{[](void) { return false; }};
+ bool operator()(void) { return body(); };
+};
+extern struct btm_ble_suspend_bg_conn btm_ble_suspend_bg_conn;
+// Name: btm_ble_resume_bg_conn
+// Params: void
+// Returns: bool
+struct btm_ble_resume_bg_conn {
+ std::function<bool(void)> body{[](void) { return false; }};
+ bool operator()(void) { return body(); };
+};
+extern struct btm_ble_resume_bg_conn btm_ble_resume_bg_conn;
+// Name: BTM_BackgroundConnectAddressKnown
+// Params: const RawAddress& address
+// Returns: bool
+struct BTM_BackgroundConnectAddressKnown {
+ std::function<bool(const RawAddress& address)> body{
+ [](const RawAddress& address) { return false; }};
+ bool operator()(const RawAddress& address) { return body(address); };
+};
+extern struct BTM_BackgroundConnectAddressKnown
+ BTM_BackgroundConnectAddressKnown;
+// Name: BTM_SetLeConnectionModeToFast
+// Params:
+// Returns: bool
+struct BTM_SetLeConnectionModeToFast {
+ std::function<bool()> body{[]() { return false; }};
+ bool operator()() { return body(); };
+};
+extern struct BTM_SetLeConnectionModeToFast BTM_SetLeConnectionModeToFast;
+// Name: BTM_SetLeConnectionModeToSlow
+// Params:
+// Returns: void
+struct BTM_SetLeConnectionModeToSlow {
+ std::function<void()> body{[]() {}};
+ void operator()() { body(); };
+};
+extern struct BTM_SetLeConnectionModeToSlow BTM_SetLeConnectionModeToSlow;
+// Name: BTM_AcceptlistAdd
+// Params: const RawAddress& address
+// Returns: bool
+struct BTM_AcceptlistAdd {
+ std::function<bool(const RawAddress& address)> body{
+ [](const RawAddress& address) { return false; }};
+ bool operator()(const RawAddress& address) { return body(address); };
+};
+extern struct BTM_AcceptlistAdd BTM_AcceptlistAdd;
+// Name: BTM_AcceptlistRemove
+// Params: const RawAddress& address
+// Returns: void
+struct BTM_AcceptlistRemove {
+ std::function<void(const RawAddress& address)> body{
+ [](const RawAddress& address) {}};
+ void operator()(const RawAddress& address) { body(address); };
+};
+extern struct BTM_AcceptlistRemove BTM_AcceptlistRemove;
+// Name: BTM_AcceptlistClear
+// Params:
+// Returns: void
+struct BTM_AcceptlistClear {
+ std::function<void()> body{[]() {}};
+ void operator()() { body(); };
+};
+extern struct BTM_AcceptlistClear BTM_AcceptlistClear;
+
+} // namespace stack_btm_ble_bgconn
+} // namespace mock
+} // namespace test
+
+// END mockcify generation
diff --git a/test/mock/mock_stack_btm_ble_multi_adv.cc b/test/mock/mock_stack_btm_ble_multi_adv.cc
index 12664bd..f6f25ed 100644
--- a/test/mock/mock_stack_btm_ble_multi_adv.cc
+++ b/test/mock/mock_stack_btm_ble_multi_adv.cc
@@ -25,7 +25,6 @@
extern std::map<std::string, int> mock_function_count_map;
#include <base/bind.h>
-#include <base/bind_helpers.h>
#include <base/location.h>
#include <base/logging.h>
#include <base/memory/weak_ptr.h>
@@ -34,13 +33,14 @@
#include <string.h>
#include <queue>
#include <vector>
+#include "bind_helpers.h"
#include "ble_advertiser.h"
-#include "ble_advertiser_hci_interface.h"
#include "bt_target.h"
-#include "btm_int_types.h"
#include "device/include/controller.h"
#include "osi/include/alarm.h"
+#include "stack/btm/ble_advertiser_hci_interface.h"
#include "stack/btm/btm_ble_int.h"
+#include "stack/btm/btm_int_types.h"
#ifndef UNUSED_ATTR
#define UNUSED_ATTR
diff --git a/test/mock/mock_stack_btm_ble_privacy.cc b/test/mock/mock_stack_btm_ble_privacy.cc
new file mode 100644
index 0000000..2482a0e
--- /dev/null
+++ b/test/mock/mock_stack_btm_ble_privacy.cc
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:13
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+
+// Mock include file to share data between tests and mock
+#include "test/mock/mock_stack_btm_ble_privacy.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+// Mocked internal structures, if any
+
+namespace test {
+namespace mock {
+namespace stack_btm_ble_privacy {
+
+// Function state capture and return values, if needed
+struct btm_ble_clear_resolving_list_complete
+ btm_ble_clear_resolving_list_complete;
+struct btm_ble_add_resolving_list_entry_complete
+ btm_ble_add_resolving_list_entry_complete;
+struct btm_ble_remove_resolving_list_entry_complete
+ btm_ble_remove_resolving_list_entry_complete;
+struct btm_ble_read_resolving_list_entry_complete
+ btm_ble_read_resolving_list_entry_complete;
+struct btm_ble_remove_resolving_list_entry btm_ble_remove_resolving_list_entry;
+struct btm_ble_clear_resolving_list btm_ble_clear_resolving_list;
+struct btm_ble_read_resolving_list_entry btm_ble_read_resolving_list_entry;
+struct btm_ble_disable_resolving_list btm_ble_disable_resolving_list;
+struct btm_ble_resolving_list_load_dev btm_ble_resolving_list_load_dev;
+struct btm_ble_resolving_list_remove_dev btm_ble_resolving_list_remove_dev;
+struct btm_ble_enable_resolving_list btm_ble_enable_resolving_list;
+struct btm_ble_enable_resolving_list_for_platform
+ btm_ble_enable_resolving_list_for_platform;
+struct btm_ble_resolving_list_init btm_ble_resolving_list_init;
+
+} // namespace stack_btm_ble_privacy
+} // namespace mock
+} // namespace test
+
+// Mocked functions, if any
+void btm_ble_clear_resolving_list_complete(uint8_t* p, uint16_t evt_len) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_btm_ble_privacy::btm_ble_clear_resolving_list_complete(
+ p, evt_len);
+}
+void btm_ble_add_resolving_list_entry_complete(uint8_t* p, uint16_t evt_len) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_btm_ble_privacy::btm_ble_add_resolving_list_entry_complete(
+ p, evt_len);
+}
+void btm_ble_remove_resolving_list_entry_complete(uint8_t* p,
+ uint16_t evt_len) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_btm_ble_privacy::
+ btm_ble_remove_resolving_list_entry_complete(p, evt_len);
+}
+void btm_ble_read_resolving_list_entry_complete(uint8_t* p, uint16_t evt_len) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_btm_ble_privacy::btm_ble_read_resolving_list_entry_complete(
+ p, evt_len);
+}
+tBTM_STATUS btm_ble_remove_resolving_list_entry(tBTM_SEC_DEV_REC* p_dev_rec) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_btm_ble_privacy::btm_ble_remove_resolving_list_entry(
+ p_dev_rec);
+}
+void btm_ble_clear_resolving_list(void) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_btm_ble_privacy::btm_ble_clear_resolving_list();
+}
+bool btm_ble_read_resolving_list_entry(tBTM_SEC_DEV_REC* p_dev_rec) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_btm_ble_privacy::btm_ble_read_resolving_list_entry(
+ p_dev_rec);
+}
+bool btm_ble_disable_resolving_list(uint8_t rl_mask, bool to_resume) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_btm_ble_privacy::btm_ble_disable_resolving_list(
+ rl_mask, to_resume);
+}
+bool btm_ble_resolving_list_load_dev(tBTM_SEC_DEV_REC* p_dev_rec) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_btm_ble_privacy::btm_ble_resolving_list_load_dev(
+ p_dev_rec);
+}
+void btm_ble_resolving_list_remove_dev(tBTM_SEC_DEV_REC* p_dev_rec) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_btm_ble_privacy::btm_ble_resolving_list_remove_dev(
+ p_dev_rec);
+}
+void btm_ble_enable_resolving_list(uint8_t rl_mask) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_btm_ble_privacy::btm_ble_enable_resolving_list(rl_mask);
+}
+void btm_ble_enable_resolving_list_for_platform(uint8_t rl_mask) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_btm_ble_privacy::btm_ble_enable_resolving_list_for_platform(
+ rl_mask);
+}
+void btm_ble_resolving_list_init(uint8_t max_irk_list_sz) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_btm_ble_privacy::btm_ble_resolving_list_init(
+ max_irk_list_sz);
+}
+
+// END mockcify generation
diff --git a/test/mock/mock_stack_btm_ble_privacy.h b/test/mock/mock_stack_btm_ble_privacy.h
new file mode 100644
index 0000000..18dbb3d
--- /dev/null
+++ b/test/mock/mock_stack_btm_ble_privacy.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:13
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <cstdint>
+#include <functional>
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+#include "stack/btm/security_device_record.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+namespace test {
+namespace mock {
+namespace stack_btm_ble_privacy {
+
+// Shared state between mocked functions and tests
+// Name: btm_ble_clear_resolving_list_complete
+// Params: uint8_t* p, uint16_t evt_len
+// Returns: void
+struct btm_ble_clear_resolving_list_complete {
+ std::function<void(uint8_t* p, uint16_t evt_len)> body{
+ [](uint8_t* p, uint16_t evt_len) {}};
+ void operator()(uint8_t* p, uint16_t evt_len) { body(p, evt_len); };
+};
+extern struct btm_ble_clear_resolving_list_complete
+ btm_ble_clear_resolving_list_complete;
+// Name: btm_ble_add_resolving_list_entry_complete
+// Params: uint8_t* p, uint16_t evt_len
+// Returns: void
+struct btm_ble_add_resolving_list_entry_complete {
+ std::function<void(uint8_t* p, uint16_t evt_len)> body{
+ [](uint8_t* p, uint16_t evt_len) {}};
+ void operator()(uint8_t* p, uint16_t evt_len) { body(p, evt_len); };
+};
+extern struct btm_ble_add_resolving_list_entry_complete
+ btm_ble_add_resolving_list_entry_complete;
+// Name: btm_ble_remove_resolving_list_entry_complete
+// Params: uint8_t* p, uint16_t evt_len
+// Returns: void
+struct btm_ble_remove_resolving_list_entry_complete {
+ std::function<void(uint8_t* p, uint16_t evt_len)> body{
+ [](uint8_t* p, uint16_t evt_len) {}};
+ void operator()(uint8_t* p, uint16_t evt_len) { body(p, evt_len); };
+};
+extern struct btm_ble_remove_resolving_list_entry_complete
+ btm_ble_remove_resolving_list_entry_complete;
+// Name: btm_ble_read_resolving_list_entry_complete
+// Params: uint8_t* p, uint16_t evt_len
+// Returns: void
+struct btm_ble_read_resolving_list_entry_complete {
+ std::function<void(uint8_t* p, uint16_t evt_len)> body{
+ [](uint8_t* p, uint16_t evt_len) {}};
+ void operator()(uint8_t* p, uint16_t evt_len) { body(p, evt_len); };
+};
+extern struct btm_ble_read_resolving_list_entry_complete
+ btm_ble_read_resolving_list_entry_complete;
+// Name: btm_ble_remove_resolving_list_entry
+// Params: tBTM_SEC_DEV_REC* p_dev_rec
+// Returns: tBTM_STATUS
+struct btm_ble_remove_resolving_list_entry {
+ std::function<tBTM_STATUS(tBTM_SEC_DEV_REC* p_dev_rec)> body{
+ [](tBTM_SEC_DEV_REC* p_dev_rec) { return 0; }};
+ tBTM_STATUS operator()(tBTM_SEC_DEV_REC* p_dev_rec) {
+ return body(p_dev_rec);
+ };
+};
+extern struct btm_ble_remove_resolving_list_entry
+ btm_ble_remove_resolving_list_entry;
+// Name: btm_ble_clear_resolving_list
+// Params: void
+// Returns: void
+struct btm_ble_clear_resolving_list {
+ std::function<void(void)> body{[](void) {}};
+ void operator()(void) { body(); };
+};
+extern struct btm_ble_clear_resolving_list btm_ble_clear_resolving_list;
+// Name: btm_ble_read_resolving_list_entry
+// Params: tBTM_SEC_DEV_REC* p_dev_rec
+// Returns: bool
+struct btm_ble_read_resolving_list_entry {
+ std::function<bool(tBTM_SEC_DEV_REC* p_dev_rec)> body{
+ [](tBTM_SEC_DEV_REC* p_dev_rec) { return false; }};
+ bool operator()(tBTM_SEC_DEV_REC* p_dev_rec) { return body(p_dev_rec); };
+};
+extern struct btm_ble_read_resolving_list_entry
+ btm_ble_read_resolving_list_entry;
+// Name: btm_ble_disable_resolving_list
+// Params: uint8_t rl_mask, bool to_resume
+// Returns: bool
+struct btm_ble_disable_resolving_list {
+ std::function<bool(uint8_t rl_mask, bool to_resume)> body{
+ [](uint8_t rl_mask, bool to_resume) { return false; }};
+ bool operator()(uint8_t rl_mask, bool to_resume) {
+ return body(rl_mask, to_resume);
+ };
+};
+extern struct btm_ble_disable_resolving_list btm_ble_disable_resolving_list;
+// Name: btm_ble_resolving_list_load_dev
+// Params: tBTM_SEC_DEV_REC* p_dev_rec
+// Returns: bool
+struct btm_ble_resolving_list_load_dev {
+ std::function<bool(tBTM_SEC_DEV_REC* p_dev_rec)> body{
+ [](tBTM_SEC_DEV_REC* p_dev_rec) { return false; }};
+ bool operator()(tBTM_SEC_DEV_REC* p_dev_rec) { return body(p_dev_rec); };
+};
+extern struct btm_ble_resolving_list_load_dev btm_ble_resolving_list_load_dev;
+// Name: btm_ble_resolving_list_remove_dev
+// Params: tBTM_SEC_DEV_REC* p_dev_rec
+// Returns: void
+struct btm_ble_resolving_list_remove_dev {
+ std::function<void(tBTM_SEC_DEV_REC* p_dev_rec)> body{
+ [](tBTM_SEC_DEV_REC* p_dev_rec) {}};
+ void operator()(tBTM_SEC_DEV_REC* p_dev_rec) { body(p_dev_rec); };
+};
+extern struct btm_ble_resolving_list_remove_dev
+ btm_ble_resolving_list_remove_dev;
+// Name: btm_ble_enable_resolving_list
+// Params: uint8_t rl_mask
+// Returns: void
+struct btm_ble_enable_resolving_list {
+ std::function<void(uint8_t rl_mask)> body{[](uint8_t rl_mask) {}};
+ void operator()(uint8_t rl_mask) { body(rl_mask); };
+};
+extern struct btm_ble_enable_resolving_list btm_ble_enable_resolving_list;
+// Name: btm_ble_enable_resolving_list_for_platform
+// Params: uint8_t rl_mask
+// Returns: void
+struct btm_ble_enable_resolving_list_for_platform {
+ std::function<void(uint8_t rl_mask)> body{[](uint8_t rl_mask) {}};
+ void operator()(uint8_t rl_mask) { body(rl_mask); };
+};
+extern struct btm_ble_enable_resolving_list_for_platform
+ btm_ble_enable_resolving_list_for_platform;
+// Name: btm_ble_resolving_list_init
+// Params: uint8_t max_irk_list_sz
+// Returns: void
+struct btm_ble_resolving_list_init {
+ std::function<void(uint8_t max_irk_list_sz)> body{
+ [](uint8_t max_irk_list_sz) {}};
+ void operator()(uint8_t max_irk_list_sz) { body(max_irk_list_sz); };
+};
+extern struct btm_ble_resolving_list_init btm_ble_resolving_list_init;
+
+} // namespace stack_btm_ble_privacy
+} // namespace mock
+} // namespace test
+
+// END mockcify generation
diff --git a/test/mock/mock_stack_btm_ble_scanner_hci_interface.cc b/test/mock/mock_stack_btm_ble_scanner_hci_interface.cc
new file mode 100644
index 0000000..8a69f1f
--- /dev/null
+++ b/test/mock/mock_stack_btm_ble_scanner_hci_interface.cc
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:6
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <cstdint>
+#include <functional>
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+// Mock include file to share data between tests and mock
+#include "test/mock/mock_stack_btm_ble_scanner_hci_interface.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+// Mocked internal structures, if any
+
+namespace test {
+namespace mock {
+namespace stack_btm_ble_scanner_hci_interface {
+
+// Function state capture and return values, if needed
+struct btm_ble_process_periodic_adv_sync_est_evt
+ btm_ble_process_periodic_adv_sync_est_evt;
+struct btm_ble_process_periodic_adv_pkt btm_ble_process_periodic_adv_pkt;
+struct btm_ble_process_periodic_adv_sync_lost_evt
+ btm_ble_process_periodic_adv_sync_lost_evt;
+
+} // namespace stack_btm_ble_scanner_hci_interface
+} // namespace mock
+} // namespace test
+
+// Mocked functions, if any
+void btm_ble_process_periodic_adv_sync_est_evt(uint8_t data_len,
+ uint8_t* data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_btm_ble_scanner_hci_interface::
+ btm_ble_process_periodic_adv_sync_est_evt(data_len, data);
+}
+void btm_ble_process_periodic_adv_pkt(uint8_t data_len, uint8_t* data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_btm_ble_scanner_hci_interface::
+ btm_ble_process_periodic_adv_pkt(data_len, data);
+}
+void btm_ble_process_periodic_adv_sync_lost_evt(uint8_t data_len,
+ uint8_t* data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_btm_ble_scanner_hci_interface::
+ btm_ble_process_periodic_adv_sync_lost_evt(data_len, data);
+}
+
+// END mockcify generation
diff --git a/test/mock/mock_stack_btm_ble_scanner_hci_interface.h b/test/mock/mock_stack_btm_ble_scanner_hci_interface.h
new file mode 100644
index 0000000..a28a498
--- /dev/null
+++ b/test/mock/mock_stack_btm_ble_scanner_hci_interface.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:6
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <cstdint>
+#include <functional>
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+#include "stack/btm/ble_scanner_hci_interface.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+namespace test {
+namespace mock {
+namespace stack_btm_ble_scanner_hci_interface {
+
+// Name: btm_ble_process_periodic_adv_sync_est_evt
+// Params: uint8_t data_len, uint8_t* data
+// Returns: void
+struct btm_ble_process_periodic_adv_sync_est_evt {
+ std::function<void(uint8_t data_len, uint8_t* data)> body{
+ [](uint8_t data_len, uint8_t* data) {}};
+ void operator()(uint8_t data_len, uint8_t* data) { body(data_len, data); };
+};
+extern struct btm_ble_process_periodic_adv_sync_est_evt
+ btm_ble_process_periodic_adv_sync_est_evt;
+// Name: btm_ble_process_periodic_adv_pkt
+// Params: uint8_t data_len, uint8_t* data
+// Returns: void
+struct btm_ble_process_periodic_adv_pkt {
+ std::function<void(uint8_t data_len, uint8_t* data)> body{
+ [](uint8_t data_len, uint8_t* data) {}};
+ void operator()(uint8_t data_len, uint8_t* data) { body(data_len, data); };
+};
+extern struct btm_ble_process_periodic_adv_pkt btm_ble_process_periodic_adv_pkt;
+// Name: btm_ble_process_periodic_adv_sync_lost_evt
+// Params: uint8_t data_len, uint8_t* data
+// Returns: void
+struct btm_ble_process_periodic_adv_sync_lost_evt {
+ std::function<void(uint8_t data_len, uint8_t* data)> body{
+ [](uint8_t data_len, uint8_t* data) {}};
+ void operator()(uint8_t data_len, uint8_t* data) { body(data_len, data); };
+};
+extern struct btm_ble_process_periodic_adv_sync_lost_evt
+ btm_ble_process_periodic_adv_sync_lost_evt;
+
+} // namespace stack_btm_ble_scanner_hci_interface
+} // namespace mock
+} // namespace test
+
+// END mockcify generation
diff --git a/test/mock/mock_stack_btm_devctl.cc b/test/mock/mock_stack_btm_devctl.cc
index e51b253..ea3d41a 100644
--- a/test/mock/mock_stack_btm_devctl.cc
+++ b/test/mock/mock_stack_btm_devctl.cc
@@ -33,7 +33,6 @@
#include "bta/sys/bta_sys.h"
#include "btcore/include/module.h"
#include "btif/include/btif_bqr.h"
-#include "btm_int.h"
#include "btu.h"
#include "common/message_loop_thread.h"
#include "device/include/controller.h"
diff --git a/main/test/common/mock_btm_inq.cc b/test/mock/mock_stack_btm_inq.cc
similarity index 100%
rename from main/test/common/mock_btm_inq.cc
rename to test/mock/mock_stack_btm_inq.cc
diff --git a/test/mock/mock_stack_btm_iso.cc b/test/mock/mock_stack_btm_iso.cc
new file mode 100644
index 0000000..a4018ab
--- /dev/null
+++ b/test/mock/mock_stack_btm_iso.cc
@@ -0,0 +1,46 @@
+#include <memory>
+
+#include "stack/include/btm_iso_api.h"
+
+using bluetooth::hci::iso_manager::BigCallbacks;
+using bluetooth::hci::iso_manager::CigCallbacks;
+
+namespace bluetooth {
+namespace hci {
+
+struct IsoManager::impl {};
+
+IsoManager::IsoManager() {}
+IsoManager::~IsoManager() {}
+void IsoManager::RegisterCigCallbacks(CigCallbacks* callbacks) const {}
+void IsoManager::RegisterBigCallbacks(BigCallbacks* callbacks) const {}
+void IsoManager::CreateCig(uint8_t cig_id,
+ struct iso_manager::cig_create_params cig_params) {}
+void IsoManager::ReconfigureCig(
+ uint8_t cig_id, struct iso_manager::cig_create_params cig_params) {}
+void IsoManager::RemoveCig(uint8_t cig_id) {}
+void IsoManager::EstablishCis(
+ struct iso_manager::cis_establish_params conn_params) {}
+void IsoManager::DisconnectCis(uint16_t cis_handle, uint8_t reason) {}
+void IsoManager::SetupIsoDataPath(
+ uint16_t iso_handle, struct iso_manager::iso_data_path_params path_params) {
+}
+void IsoManager::RemoveIsoDataPath(uint16_t iso_handle, uint8_t data_path_dir) {
+}
+void IsoManager::ReadIsoLinkQuality(uint16_t iso_handle) {}
+void IsoManager::SendIsoData(uint16_t iso_handle, const uint8_t* data,
+ uint16_t data_len) {}
+void IsoManager::CreateBig(uint8_t big_id,
+ struct iso_manager::big_create_params big_params) {}
+void IsoManager::TerminateBig(uint8_t big_id, uint8_t reason) {}
+void IsoManager::HandleIsoData(void* p_msg) {}
+void IsoManager::HandleDisconnect(uint16_t handle, uint8_t reason) {}
+void IsoManager::HandleNumComplDataPkts(uint8_t* p, uint8_t evt_len) {}
+void IsoManager::HandleGdNumComplDataPkts(uint16_t handle, uint16_t credits) {}
+void IsoManager::HandleHciEvent(uint8_t sub_code, uint8_t* params,
+ uint16_t length) {}
+void IsoManager::Start() {}
+void IsoManager::Stop() {}
+
+} // namespace hci
+} // namespace bluetooth
diff --git a/test/mock/mock_stack_btm_sec.cc b/test/mock/mock_stack_btm_sec.cc
index c21f4e5..27d76f8 100644
--- a/test/mock/mock_stack_btm_sec.cc
+++ b/test/mock/mock_stack_btm_sec.cc
@@ -86,6 +86,10 @@
mock_function_count_map[__func__]++;
return false;
}
+tBT_DEVICE_TYPE BTM_GetPeerDeviceTypeFromFeatures(const RawAddress& bd_addr) {
+ mock_function_count_map[__func__]++;
+ return BT_DEVICE_TYPE_BREDR;
+}
bool BTM_SecAddRmtNameNotifyCallback(tBTM_RMT_NAME_CALLBACK* p_callback) {
mock_function_count_map[__func__]++;
return false;
@@ -252,7 +256,8 @@
mock_function_count_map[__func__]++;
}
void btm_sec_connected(const RawAddress& bda, uint16_t handle,
- tHCI_STATUS status, uint8_t enc_mode) {
+ tHCI_STATUS status, uint8_t enc_mode,
+ tHCI_ROLE assigned_role) {
mock_function_count_map[__func__]++;
}
void btm_sec_dev_rec_cback_event(tBTM_SEC_DEV_REC* p_dev_rec,
@@ -286,7 +291,8 @@
}
void btm_sec_set_peer_sec_caps(uint16_t hci_handle, bool ssp_supported,
bool sc_supported,
- bool hci_role_switch_supported) {
+ bool hci_role_switch_supported,
+ bool br_edr_supported, bool le_supported) {
mock_function_count_map[__func__]++;
}
void btm_sec_update_clock_offset(uint16_t handle, uint16_t clock_offset) {
diff --git a/stack/test/common/mock_btu_hcif.cc b/test/mock/mock_stack_btu_hcif.cc
similarity index 100%
rename from stack/test/common/mock_btu_hcif.cc
rename to test/mock/mock_stack_btu_hcif.cc
diff --git a/test/mock/mock_stack_crypto_toolbox.cc b/test/mock/mock_stack_crypto_toolbox.cc
new file mode 100644
index 0000000..40b4e69
--- /dev/null
+++ b/test/mock/mock_stack_crypto_toolbox.cc
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:8
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <cstdint>
+#include <functional>
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Mock include file to share data between tests and mock
+#include "test/mock/mock_stack_crypto_toolbox.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+// Mocked internal structures, if any
+
+namespace test {
+namespace mock {
+namespace stack_crypto_toolbox {
+
+// Function state capture and return values, if needed
+struct h6 h6;
+struct h7 h7;
+struct f4 f4;
+struct f5 f5;
+struct f6 f6;
+struct g2 g2;
+struct ltk_to_link_key ltk_to_link_key;
+struct link_key_to_ltk link_key_to_ltk;
+
+} // namespace stack_crypto_toolbox
+} // namespace mock
+} // namespace test
+
+// Mocked functions, if any
+Octet16 h6(const Octet16& w, std::array<uint8_t, 4> keyid) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_crypto_toolbox::h6(w, keyid);
+}
+Octet16 h7(const Octet16& salt, const Octet16& w) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_crypto_toolbox::h7(salt, w);
+}
+Octet16 f4(const uint8_t* u, const uint8_t* v, const Octet16& x, uint8_t z) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_crypto_toolbox::f4(u, v, x, z);
+}
+void f5(const uint8_t* w, const Octet16& n1, const Octet16& n2, uint8_t* a1,
+ uint8_t* a2, Octet16* mac_key, Octet16* ltk) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_crypto_toolbox::f5(w, n1, n2, a1, a2, mac_key, ltk);
+}
+Octet16 f6(const Octet16& w, const Octet16& n1, const Octet16& n2,
+ const Octet16& r, uint8_t* iocap, uint8_t* a1, uint8_t* a2) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_crypto_toolbox::f6(w, n1, n2, r, iocap, a1, a2);
+}
+uint32_t g2(const uint8_t* u, const uint8_t* v, const Octet16& x,
+ const Octet16& y) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_crypto_toolbox::g2(u, v, x, y);
+}
+Octet16 ltk_to_link_key(const Octet16& ltk, bool use_h7) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_crypto_toolbox::ltk_to_link_key(ltk, use_h7);
+}
+Octet16 link_key_to_ltk(const Octet16& link_key, bool use_h7) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_crypto_toolbox::link_key_to_ltk(link_key, use_h7);
+}
+
+// END mockcify generation
diff --git a/test/mock/mock_stack_crypto_toolbox.h b/test/mock/mock_stack_crypto_toolbox.h
new file mode 100644
index 0000000..bfbe800
--- /dev/null
+++ b/test/mock/mock_stack_crypto_toolbox.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:8
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <cstdint>
+#include <functional>
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+#include <base/logging.h>
+#include <base/strings/string_number_conversions.h>
+#include <algorithm>
+#include "stack/crypto_toolbox/aes.h"
+#include "stack/crypto_toolbox/crypto_toolbox.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+namespace test {
+namespace mock {
+namespace stack_crypto_toolbox {
+
+// Shared state between mocked functions and tests
+// Name: h6
+// Params: const Octet16& w, std::array<uint8_t, 4> keyid
+// Returns: Octet16
+struct h6 {
+ Octet16 octet16;
+ std::function<Octet16(const Octet16& w, std::array<uint8_t, 4> keyid)> body{
+ [this](const Octet16& w, std::array<uint8_t, 4> keyid) {
+ return octet16;
+ }};
+ Octet16 operator()(const Octet16& w, std::array<uint8_t, 4> keyid) {
+ return body(w, keyid);
+ };
+};
+extern struct h6 h6;
+// Name: h7
+// Params: const Octet16& salt, const Octet16& w
+// Returns: Octet16
+struct h7 {
+ Octet16 octet16;
+ std::function<Octet16(const Octet16& salt, const Octet16& w)> body{
+ [this](const Octet16& salt, const Octet16& w) { return octet16; }};
+ Octet16 operator()(const Octet16& salt, const Octet16& w) {
+ return body(salt, w);
+ };
+};
+extern struct h7 h7;
+// Name: f4
+// Params: const uint8_t* u, const uint8_t* v, const Octet16& x, uint8_t z
+// Returns: Octet16
+struct f4 {
+ Octet16 octet16;
+ std::function<Octet16(const uint8_t* u, const uint8_t* v, const Octet16& x,
+ uint8_t z)>
+ body{[this](const uint8_t* u, const uint8_t* v, const Octet16& x,
+ uint8_t z) { return octet16; }};
+ Octet16 operator()(const uint8_t* u, const uint8_t* v, const Octet16& x,
+ uint8_t z) {
+ return body(u, v, x, z);
+ };
+};
+extern struct f4 f4;
+// Name: f5
+// Params: const uint8_t* w, const Octet16& n1, const Octet16& n2, uint8_t* a1,
+// uint8_t* a2, Octet16* mac_key, Octet16* ltk Returns: void
+struct f5 {
+ std::function<void(const uint8_t* w, const Octet16& n1, const Octet16& n2,
+ uint8_t* a1, uint8_t* a2, Octet16* mac_key, Octet16* ltk)>
+ body{[](const uint8_t* w, const Octet16& n1, const Octet16& n2,
+ uint8_t* a1, uint8_t* a2, Octet16* mac_key, Octet16* ltk) {}};
+ void operator()(const uint8_t* w, const Octet16& n1, const Octet16& n2,
+ uint8_t* a1, uint8_t* a2, Octet16* mac_key, Octet16* ltk) {
+ body(w, n1, n2, a1, a2, mac_key, ltk);
+ };
+};
+extern struct f5 f5;
+// Name: f6
+// Params: const Octet16& w, const Octet16& n1, const Octet16& n2, const
+// Octet16& r, uint8_t* iocap, uint8_t* a1, uint8_t* a2 Returns: Octet16
+struct f6 {
+ Octet16 octet16;
+ std::function<Octet16(const Octet16& w, const Octet16& n1, const Octet16& n2,
+ const Octet16& r, uint8_t* iocap, uint8_t* a1,
+ uint8_t* a2)>
+ body{[this](const Octet16& w, const Octet16& n1, const Octet16& n2,
+ const Octet16& r, uint8_t* iocap, uint8_t* a1,
+ uint8_t* a2) { return octet16; }};
+ Octet16 operator()(const Octet16& w, const Octet16& n1, const Octet16& n2,
+ const Octet16& r, uint8_t* iocap, uint8_t* a1,
+ uint8_t* a2) {
+ return body(w, n1, n2, r, iocap, a1, a2);
+ };
+};
+extern struct f6 f6;
+// Name: g2
+// Params: const uint8_t* u, const uint8_t* v, const Octet16& x, const Octet16&
+// y Returns: uint32_t
+struct g2 {
+ std::function<uint32_t(const uint8_t* u, const uint8_t* v, const Octet16& x,
+ const Octet16& y)>
+ body{[](const uint8_t* u, const uint8_t* v, const Octet16& x,
+ const Octet16& y) { return 0; }};
+ uint32_t operator()(const uint8_t* u, const uint8_t* v, const Octet16& x,
+ const Octet16& y) {
+ return body(u, v, x, y);
+ };
+};
+extern struct g2 g2;
+// Name: ltk_to_link_key
+// Params: const Octet16& ltk, bool use_h7
+// Returns: Octet16
+struct ltk_to_link_key {
+ Octet16 octet16;
+ std::function<Octet16(const Octet16& ltk, bool use_h7)> body{
+ [this](const Octet16& ltk, bool use_h7) { return octet16; }};
+ Octet16 operator()(const Octet16& ltk, bool use_h7) {
+ return body(ltk, use_h7);
+ };
+};
+extern struct ltk_to_link_key ltk_to_link_key;
+// Name: link_key_to_ltk
+// Params: const Octet16& link_key, bool use_h7
+// Returns: Octet16
+struct link_key_to_ltk {
+ Octet16 octet16;
+ std::function<Octet16(const Octet16& link_key, bool use_h7)> body{
+ [this](const Octet16& link_key, bool use_h7) { return octet16; }};
+ Octet16 operator()(const Octet16& link_key, bool use_h7) {
+ return body(link_key, use_h7);
+ };
+};
+extern struct link_key_to_ltk link_key_to_ltk;
+
+} // namespace stack_crypto_toolbox
+} // namespace mock
+} // namespace test
+
+// END mockcify generation
diff --git a/bta/test/common/mock_stack_crypto_toolbox_aes_cmac.cc b/test/mock/mock_stack_crypto_toolbox_aes_cmac.cc
similarity index 100%
rename from bta/test/common/mock_stack_crypto_toolbox_aes_cmac.cc
rename to test/mock/mock_stack_crypto_toolbox_aes_cmac.cc
diff --git a/bta/test/common/mock_stack_gap_ble.cc b/test/mock/mock_stack_gap_ble.cc
similarity index 100%
rename from bta/test/common/mock_stack_gap_ble.cc
rename to test/mock/mock_stack_gap_ble.cc
diff --git a/test/mock/mock_stack_gatt.cc b/test/mock/mock_stack_gatt.cc
index 6ae3c8e..60f4f3d 100644
--- a/test/mock/mock_stack_gatt.cc
+++ b/test/mock/mock_stack_gatt.cc
@@ -82,8 +82,8 @@
mock_function_count_map[__func__]++;
return elem;
}
-tGATT_IF GATT_Register(const Uuid& app_uuid128, tGATT_CBACK* p_cb_info,
- bool eatt_support) {
+tGATT_IF GATT_Register(const Uuid& app_uuid128, std::string name,
+ tGATT_CBACK* p_cb_info, bool eatt_support) {
mock_function_count_map[__func__]++;
return 0;
}
diff --git a/bta/test/common/mock_stack_gatt_attr.cc b/test/mock/mock_stack_gatt_attr.cc
similarity index 100%
rename from bta/test/common/mock_stack_gatt_attr.cc
rename to test/mock/mock_stack_gatt_attr.cc
diff --git a/stack/test/common/mock_gatt_gatt_auth.cc b/test/mock/mock_stack_gatt_auth.cc
similarity index 96%
rename from stack/test/common/mock_gatt_gatt_auth.cc
rename to test/mock/mock_stack_gatt_auth.cc
index f6fe629..db0820e 100644
--- a/stack/test/common/mock_gatt_gatt_auth.cc
+++ b/test/mock/mock_stack_gatt_auth.cc
@@ -37,11 +37,11 @@
}
tGATT_SEC_ACTION gatt_determine_sec_act(tGATT_CLCB* p_clcb) {
mock_function_count_map[__func__]++;
- return 0;
+ return GATT_SEC_NONE;
}
tGATT_SEC_ACTION gatt_get_sec_act(tGATT_TCB* p_tcb) {
mock_function_count_map[__func__]++;
- return 0;
+ return GATT_SEC_NONE;
}
tGATT_STATUS gatt_get_link_encrypt_status(tGATT_TCB& tcb) {
mock_function_count_map[__func__]++;
diff --git a/test/mock/mock_stack_gatt_connection_manager.cc b/test/mock/mock_stack_gatt_connection_manager.cc
index d1341c7..e4bfee0 100644
--- a/test/mock/mock_stack_gatt_connection_manager.cc
+++ b/test/mock/mock_stack_gatt_connection_manager.cc
@@ -69,6 +69,11 @@
mock_function_count_map[__func__]++;
return false;
}
+bool connection_manager::remove_unconditional_from_shim(
+ const RawAddress& address) {
+ mock_function_count_map[__func__]++;
+ return false;
+}
std::set<tAPP_ID> connection_manager::get_apps_connecting_to(
const RawAddress& address) {
mock_function_count_map[__func__]++;
diff --git a/test/mock/mock_stack_gatt_main.cc b/test/mock/mock_stack_gatt_main.cc
index db36dc9..cdc037b 100644
--- a/test/mock/mock_stack_gatt_main.cc
+++ b/test/mock/mock_stack_gatt_main.cc
@@ -26,12 +26,10 @@
#include "bt_common.h"
#include "bt_target.h"
-#include "bt_utils.h"
-#include "btif_storage.h"
-#include "btm_ble_int.h"
#include "device/include/interop.h"
#include "l2c_api.h"
#include "osi/include/osi.h"
+#include "stack/btm/btm_ble_int.h"
#include "stack/btm/btm_dev.h"
#include "stack/btm/btm_sec.h"
#include "stack/gatt/gatt_int.h"
diff --git a/test/mock/mock_stack_l2cap_api.cc b/test/mock/mock_stack_l2cap_api.cc
index 85f2f4f..1c00c2b 100644
--- a/test/mock/mock_stack_l2cap_api.cc
+++ b/test/mock/mock_stack_l2cap_api.cc
@@ -17,6 +17,8 @@
/*
* Generated mock file from original source file
* Functions generated:33
+ *
+ * mockcify.pl ver 0.2
*/
#include <map>
@@ -24,154 +26,246 @@
extern std::map<std::string, int> mock_function_count_map;
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+#include <base/logging.h>
+#include <base/strings/stringprintf.h>
#include <cstdint>
+#include <string>
+#include "device/include/controller.h"
+#include "main/shim/l2c_api.h"
+#include "main/shim/shim.h"
+#include "osi/include/log.h"
+#include "stack/btm/btm_sec.h"
#include "stack/include/l2c_api.h"
-#include "types/raw_address.h"
+#include "stack/l2cap/l2c_int.h"
+// Mock include file to share data between tests and mock
+#include "test/mock/mock_stack_l2cap_api.h"
+
+// Mocked compile conditionals, if any
#ifndef UNUSED_ATTR
#define UNUSED_ATTR
#endif
-bool L2CA_ConnectCreditBasedRsp(const RawAddress& p_bd_addr, uint8_t id,
- std::vector<uint16_t>& accepted_lcids,
- uint16_t result, tL2CAP_LE_CFG_INFO* p_cfg) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_ConnectFixedChnl(uint16_t fixed_cid, const RawAddress& rem_bda) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_DisconnectLECocReq(uint16_t cid) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_DisconnectReq(uint16_t cid) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_GetPeerFeatures(const RawAddress& bd_addr, uint32_t* p_ext_feat,
- uint8_t* p_chnl_mask) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_GetPeerLECocConfig(uint16_t lcid, tL2CAP_LE_CFG_INFO* peer_cfg) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_GetRemoteCid(uint16_t lcid, uint16_t* rcid) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_IsLinkEstablished(const RawAddress& bd_addr,
- tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_ReconfigCreditBasedConnsReq(const RawAddress& bda,
- std::vector<uint16_t>& lcids,
- tL2CAP_LE_CFG_INFO* p_cfg) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_RegisterFixedChannel(uint16_t fixed_cid,
- tL2CAP_FIXED_CHNL_REG* p_freg) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_RemoveFixedChnl(uint16_t fixed_cid, const RawAddress& rem_bda) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_SetAclPriority(const RawAddress& bd_addr, tL2CAP_PRIORITY priority) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_SetChnlFlushability(uint16_t cid, bool is_flushable) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_SetLeGattTimeout(const RawAddress& rem_bda, uint16_t idle_tout) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_SetIdleTimeoutByBdAddr(const RawAddress& bd_addr, uint16_t timeout,
- tBT_TRANSPORT transport) {
- mock_function_count_map[__func__]++;
- return false;
-}
-bool L2CA_SetTxPriority(uint16_t cid, tL2CAP_CHNL_PRIORITY priority) {
- mock_function_count_map[__func__]++;
- return false;
-}
-std::vector<uint16_t> L2CA_ConnectCreditBasedReq(uint16_t psm,
- const RawAddress& p_bd_addr,
- tL2CAP_LE_CFG_INFO* p_cfg) {
- mock_function_count_map[__func__]++;
- std::vector<uint16_t> v;
- return v;
-}
+// Mocked internal structures, if any
+
+namespace test {
+namespace mock {
+namespace stack_l2cap_api {
+
+// Function state capture and return values, if needed
+struct l2c_get_transport_from_fixed_cid l2c_get_transport_from_fixed_cid;
+struct L2CA_Register2 L2CA_Register2;
+struct L2CA_Register L2CA_Register;
+struct L2CA_Deregister L2CA_Deregister;
+struct L2CA_AllocateLePSM L2CA_AllocateLePSM;
+struct L2CA_FreeLePSM L2CA_FreeLePSM;
+struct L2CA_ConnectReq2 L2CA_ConnectReq2;
+struct L2CA_ConnectReq L2CA_ConnectReq;
+struct L2CA_RegisterLECoc L2CA_RegisterLECoc;
+struct L2CA_DeregisterLECoc L2CA_DeregisterLECoc;
+struct L2CA_ConnectLECocReq L2CA_ConnectLECocReq;
+struct L2CA_GetPeerLECocConfig L2CA_GetPeerLECocConfig;
+struct L2CA_ConnectCreditBasedRsp L2CA_ConnectCreditBasedRsp;
+struct L2CA_ConnectCreditBasedReq L2CA_ConnectCreditBasedReq;
+struct L2CA_ReconfigCreditBasedConnsReq L2CA_ReconfigCreditBasedConnsReq;
+struct L2CA_DisconnectReq L2CA_DisconnectReq;
+struct L2CA_DisconnectLECocReq L2CA_DisconnectLECocReq;
+struct L2CA_GetRemoteCid L2CA_GetRemoteCid;
+struct L2CA_SetIdleTimeoutByBdAddr L2CA_SetIdleTimeoutByBdAddr;
+struct L2CA_SetTraceLevel L2CA_SetTraceLevel;
+struct L2CA_SetAclPriority L2CA_SetAclPriority;
+struct L2CA_SetTxPriority L2CA_SetTxPriority;
+struct L2CA_GetPeerFeatures L2CA_GetPeerFeatures;
+struct L2CA_RegisterFixedChannel L2CA_RegisterFixedChannel;
+struct L2CA_ConnectFixedChnl L2CA_ConnectFixedChnl;
+struct L2CA_SendFixedChnlData L2CA_SendFixedChnlData;
+struct L2CA_RemoveFixedChnl L2CA_RemoveFixedChnl;
+struct L2CA_SetLeGattTimeout L2CA_SetLeGattTimeout;
+struct L2CA_DataWrite L2CA_DataWrite;
+struct L2CA_LECocDataWrite L2CA_LECocDataWrite;
+struct L2CA_SetChnlFlushability L2CA_SetChnlFlushability;
+struct L2CA_FlushChannel L2CA_FlushChannel;
+struct L2CA_IsLinkEstablished L2CA_IsLinkEstablished;
+
+} // namespace stack_l2cap_api
+} // namespace mock
+} // namespace test
+
+// Mocked functions, if any
tBT_TRANSPORT l2c_get_transport_from_fixed_cid(uint16_t fixed_cid) {
mock_function_count_map[__func__]++;
- return 0;
-}
-uint16_t L2CA_AllocateLePSM(void) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint16_t L2CA_ConnectLECocReq(uint16_t psm, const RawAddress& p_bd_addr,
- tL2CAP_LE_CFG_INFO* p_cfg, uint16_t sec_level) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint16_t L2CA_ConnectReq(uint16_t psm, const RawAddress& p_bd_addr) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint16_t L2CA_ConnectReq2(uint16_t psm, const RawAddress& p_bd_addr,
- uint16_t sec_level) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint16_t L2CA_FlushChannel(uint16_t lcid, uint16_t num_to_flush) {
- mock_function_count_map[__func__]++;
- return 0;
-}
-uint16_t L2CA_Register(uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info,
- bool enable_snoop, tL2CAP_ERTM_INFO* p_ertm_info,
- uint16_t my_mtu, uint16_t required_remote_mtu) {
- mock_function_count_map[__func__]++;
- return 0;
+ return test::mock::stack_l2cap_api::l2c_get_transport_from_fixed_cid(
+ fixed_cid);
}
uint16_t L2CA_Register2(uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info,
bool enable_snoop, tL2CAP_ERTM_INFO* p_ertm_info,
uint16_t my_mtu, uint16_t required_remote_mtu,
uint16_t sec_level) {
mock_function_count_map[__func__]++;
- return 0;
+ return test::mock::stack_l2cap_api::L2CA_Register2(
+ psm, p_cb_info, enable_snoop, p_ertm_info, my_mtu, required_remote_mtu,
+ sec_level);
+}
+uint16_t L2CA_Register(uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info,
+ bool enable_snoop, tL2CAP_ERTM_INFO* p_ertm_info,
+ uint16_t my_mtu, uint16_t required_remote_mtu,
+ uint16_t sec_level) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_api::L2CA_Register(
+ psm, p_cb_info, enable_snoop, p_ertm_info, my_mtu, required_remote_mtu,
+ sec_level);
+}
+void L2CA_Deregister(uint16_t psm) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_l2cap_api::L2CA_Deregister(psm);
+}
+uint16_t L2CA_AllocateLePSM(void) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_api::L2CA_AllocateLePSM();
+}
+void L2CA_FreeLePSM(uint16_t psm) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_l2cap_api::L2CA_FreeLePSM(psm);
+}
+uint16_t L2CA_ConnectReq2(uint16_t psm, const RawAddress& p_bd_addr,
+ uint16_t sec_level) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_api::L2CA_ConnectReq2(psm, p_bd_addr,
+ sec_level);
+}
+uint16_t L2CA_ConnectReq(uint16_t psm, const RawAddress& p_bd_addr) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_api::L2CA_ConnectReq(psm, p_bd_addr);
}
uint16_t L2CA_RegisterLECoc(uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info,
uint16_t sec_level, tL2CAP_LE_CFG_INFO cfg) {
mock_function_count_map[__func__]++;
- return 0;
+ return test::mock::stack_l2cap_api::L2CA_RegisterLECoc(psm, p_cb_info,
+ sec_level, cfg);
+}
+void L2CA_DeregisterLECoc(uint16_t psm) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_l2cap_api::L2CA_DeregisterLECoc(psm);
+}
+uint16_t L2CA_ConnectLECocReq(uint16_t psm, const RawAddress& p_bd_addr,
+ tL2CAP_LE_CFG_INFO* p_cfg, uint16_t sec_level) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_api::L2CA_ConnectLECocReq(psm, p_bd_addr,
+ p_cfg, sec_level);
+}
+bool L2CA_GetPeerLECocConfig(uint16_t lcid, tL2CAP_LE_CFG_INFO* peer_cfg) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_api::L2CA_GetPeerLECocConfig(lcid, peer_cfg);
+}
+bool L2CA_ConnectCreditBasedRsp(const RawAddress& p_bd_addr, uint8_t id,
+ std::vector<uint16_t>& accepted_lcids,
+ uint16_t result, tL2CAP_LE_CFG_INFO* p_cfg) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_api::L2CA_ConnectCreditBasedRsp(
+ p_bd_addr, id, accepted_lcids, result, p_cfg);
+}
+std::vector<uint16_t> L2CA_ConnectCreditBasedReq(uint16_t psm,
+ const RawAddress& p_bd_addr,
+ tL2CAP_LE_CFG_INFO* p_cfg) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_api::L2CA_ConnectCreditBasedReq(psm, p_bd_addr,
+ p_cfg);
+}
+bool L2CA_ReconfigCreditBasedConnsReq(const RawAddress& bda,
+ std::vector<uint16_t>& lcids,
+ tL2CAP_LE_CFG_INFO* p_cfg) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_api::L2CA_ReconfigCreditBasedConnsReq(
+ bda, lcids, p_cfg);
+}
+bool L2CA_DisconnectReq(uint16_t cid) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_api::L2CA_DisconnectReq(cid);
+}
+bool L2CA_DisconnectLECocReq(uint16_t cid) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_api::L2CA_DisconnectLECocReq(cid);
+}
+bool L2CA_GetRemoteCid(uint16_t lcid, uint16_t* rcid) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_api::L2CA_GetRemoteCid(lcid, rcid);
+}
+bool L2CA_SetIdleTimeoutByBdAddr(const RawAddress& bd_addr, uint16_t timeout,
+ tBT_TRANSPORT transport) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_api::L2CA_SetIdleTimeoutByBdAddr(
+ bd_addr, timeout, transport);
+}
+uint8_t L2CA_SetTraceLevel(uint8_t new_level) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_api::L2CA_SetTraceLevel(new_level);
+}
+bool L2CA_SetAclPriority(const RawAddress& bd_addr, tL2CAP_PRIORITY priority) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_api::L2CA_SetAclPriority(bd_addr, priority);
+}
+bool L2CA_SetTxPriority(uint16_t cid, tL2CAP_CHNL_PRIORITY priority) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_api::L2CA_SetTxPriority(cid, priority);
+}
+bool L2CA_GetPeerFeatures(const RawAddress& bd_addr, uint32_t* p_ext_feat,
+ uint8_t* p_chnl_mask) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_api::L2CA_GetPeerFeatures(bd_addr, p_ext_feat,
+ p_chnl_mask);
+}
+bool L2CA_RegisterFixedChannel(uint16_t fixed_cid,
+ tL2CAP_FIXED_CHNL_REG* p_freg) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_api::L2CA_RegisterFixedChannel(fixed_cid,
+ p_freg);
+}
+bool L2CA_ConnectFixedChnl(uint16_t fixed_cid, const RawAddress& rem_bda) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_api::L2CA_ConnectFixedChnl(fixed_cid, rem_bda);
}
uint16_t L2CA_SendFixedChnlData(uint16_t fixed_cid, const RawAddress& rem_bda,
BT_HDR* p_buf) {
mock_function_count_map[__func__]++;
- return 0;
+ return test::mock::stack_l2cap_api::L2CA_SendFixedChnlData(fixed_cid, rem_bda,
+ p_buf);
+}
+bool L2CA_RemoveFixedChnl(uint16_t fixed_cid, const RawAddress& rem_bda) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_api::L2CA_RemoveFixedChnl(fixed_cid, rem_bda);
+}
+bool L2CA_SetLeGattTimeout(const RawAddress& rem_bda, uint16_t idle_tout) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_api::L2CA_SetLeGattTimeout(rem_bda, idle_tout);
}
uint8_t L2CA_DataWrite(uint16_t cid, BT_HDR* p_data) {
mock_function_count_map[__func__]++;
- return 0;
+ return test::mock::stack_l2cap_api::L2CA_DataWrite(cid, p_data);
}
uint8_t L2CA_LECocDataWrite(uint16_t cid, BT_HDR* p_data) {
mock_function_count_map[__func__]++;
- return 0;
+ return test::mock::stack_l2cap_api::L2CA_LECocDataWrite(cid, p_data);
}
-uint8_t L2CA_SetTraceLevel(uint8_t new_level) {
+bool L2CA_SetChnlFlushability(uint16_t cid, bool is_flushable) {
mock_function_count_map[__func__]++;
- return 0;
+ return test::mock::stack_l2cap_api::L2CA_SetChnlFlushability(cid,
+ is_flushable);
}
-void L2CA_Deregister(uint16_t psm) { mock_function_count_map[__func__]++; }
-void L2CA_DeregisterLECoc(uint16_t psm) { mock_function_count_map[__func__]++; }
-void L2CA_FreeLePSM(uint16_t psm) { mock_function_count_map[__func__]++; }
+uint16_t L2CA_FlushChannel(uint16_t lcid, uint16_t num_to_flush) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_api::L2CA_FlushChannel(lcid, num_to_flush);
+}
+bool L2CA_IsLinkEstablished(const RawAddress& bd_addr,
+ tBT_TRANSPORT transport) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_api::L2CA_IsLinkEstablished(bd_addr,
+ transport);
+}
+
+// END mockcify generation
diff --git a/test/mock/mock_stack_l2cap_api.h b/test/mock/mock_stack_l2cap_api.h
new file mode 100644
index 0000000..0c363f9
--- /dev/null
+++ b/test/mock/mock_stack_l2cap_api.h
@@ -0,0 +1,458 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:33
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <functional>
+#include <map>
+#include <string>
+#include <vector>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+#include <base/logging.h>
+#include <base/strings/stringprintf.h>
+#include <cstdint>
+#include <string>
+#include "device/include/controller.h"
+#include "main/shim/l2c_api.h"
+#include "main/shim/shim.h"
+#include "osi/include/log.h"
+#include "stack/btm/btm_sec.h"
+#include "stack/include/l2c_api.h"
+#include "stack/l2cap/l2c_int.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+namespace test {
+namespace mock {
+namespace stack_l2cap_api {
+
+// Shared state between mocked functions and tests
+// Name: l2c_get_transport_from_fixed_cid
+// Params: uint16_t fixed_cid
+// Returns: tBT_TRANSPORT
+struct l2c_get_transport_from_fixed_cid {
+ std::function<tBT_TRANSPORT(uint16_t fixed_cid)> body{
+ [](uint16_t fixed_cid) { return 0; }};
+ tBT_TRANSPORT operator()(uint16_t fixed_cid) { return body(fixed_cid); };
+};
+extern struct l2c_get_transport_from_fixed_cid l2c_get_transport_from_fixed_cid;
+// Name: L2CA_Register2
+// Params: uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info, bool enable_snoop,
+// tL2CAP_ERTM_INFO* p_ertm_info, uint16_t my_mtu, uint16_t required_remote_mtu,
+// uint16_t sec_level Returns: uint16_t
+struct L2CA_Register2 {
+ std::function<uint16_t(uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info,
+ bool enable_snoop, tL2CAP_ERTM_INFO* p_ertm_info,
+ uint16_t my_mtu, uint16_t required_remote_mtu,
+ uint16_t sec_level)>
+ body{[](uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info,
+ bool enable_snoop, tL2CAP_ERTM_INFO* p_ertm_info, uint16_t my_mtu,
+ uint16_t required_remote_mtu, uint16_t sec_level) { return 0; }};
+ uint16_t operator()(uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info,
+ bool enable_snoop, tL2CAP_ERTM_INFO* p_ertm_info,
+ uint16_t my_mtu, uint16_t required_remote_mtu,
+ uint16_t sec_level) {
+ return body(psm, p_cb_info, enable_snoop, p_ertm_info, my_mtu,
+ required_remote_mtu, sec_level);
+ };
+};
+extern struct L2CA_Register2 L2CA_Register2;
+// Name: L2CA_Register
+// Params: uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info, bool enable_snoop,
+// tL2CAP_ERTM_INFO* p_ertm_info, uint16_t my_mtu, uint16_t required_remote_mtu,
+// uint16_t sec_level Returns: uint16_t
+struct L2CA_Register {
+ std::function<uint16_t(uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info,
+ bool enable_snoop, tL2CAP_ERTM_INFO* p_ertm_info,
+ uint16_t my_mtu, uint16_t required_remote_mtu,
+ uint16_t sec_level)>
+ body{[](uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info,
+ bool enable_snoop, tL2CAP_ERTM_INFO* p_ertm_info, uint16_t my_mtu,
+ uint16_t required_remote_mtu, uint16_t sec_level) { return 0; }};
+ uint16_t operator()(uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info,
+ bool enable_snoop, tL2CAP_ERTM_INFO* p_ertm_info,
+ uint16_t my_mtu, uint16_t required_remote_mtu,
+ uint16_t sec_level) {
+ return body(psm, p_cb_info, enable_snoop, p_ertm_info, my_mtu,
+ required_remote_mtu, sec_level);
+ };
+};
+extern struct L2CA_Register L2CA_Register;
+// Name: L2CA_Deregister
+// Params: uint16_t psm
+// Returns: void
+struct L2CA_Deregister {
+ std::function<void(uint16_t psm)> body{[](uint16_t psm) {}};
+ void operator()(uint16_t psm) { body(psm); };
+};
+extern struct L2CA_Deregister L2CA_Deregister;
+// Name: L2CA_AllocateLePSM
+// Params: void
+// Returns: uint16_t
+struct L2CA_AllocateLePSM {
+ std::function<uint16_t(void)> body{[](void) { return 0; }};
+ uint16_t operator()(void) { return body(); };
+};
+extern struct L2CA_AllocateLePSM L2CA_AllocateLePSM;
+// Name: L2CA_FreeLePSM
+// Params: uint16_t psm
+// Returns: void
+struct L2CA_FreeLePSM {
+ std::function<void(uint16_t psm)> body{[](uint16_t psm) {}};
+ void operator()(uint16_t psm) { body(psm); };
+};
+extern struct L2CA_FreeLePSM L2CA_FreeLePSM;
+// Name: L2CA_ConnectReq2
+// Params: uint16_t psm, const RawAddress& p_bd_addr, uint16_t sec_level
+// Returns: uint16_t
+struct L2CA_ConnectReq2 {
+ std::function<uint16_t(uint16_t psm, const RawAddress& p_bd_addr,
+ uint16_t sec_level)>
+ body{[](uint16_t psm, const RawAddress& p_bd_addr, uint16_t sec_level) {
+ return 0;
+ }};
+ uint16_t operator()(uint16_t psm, const RawAddress& p_bd_addr,
+ uint16_t sec_level) {
+ return body(psm, p_bd_addr, sec_level);
+ };
+};
+extern struct L2CA_ConnectReq2 L2CA_ConnectReq2;
+// Name: L2CA_ConnectReq
+// Params: uint16_t psm, const RawAddress& p_bd_addr
+// Returns: uint16_t
+struct L2CA_ConnectReq {
+ std::function<uint16_t(uint16_t psm, const RawAddress& p_bd_addr)> body{
+ [](uint16_t psm, const RawAddress& p_bd_addr) { return 0; }};
+ uint16_t operator()(uint16_t psm, const RawAddress& p_bd_addr) {
+ return body(psm, p_bd_addr);
+ };
+};
+extern struct L2CA_ConnectReq L2CA_ConnectReq;
+// Name: L2CA_RegisterLECoc
+// Params: uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info, uint16_t sec_level,
+// tL2CAP_LE_CFG_INFO cfg Returns: uint16_t
+struct L2CA_RegisterLECoc {
+ std::function<uint16_t(uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info,
+ uint16_t sec_level, tL2CAP_LE_CFG_INFO cfg)>
+ body{[](uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info,
+ uint16_t sec_level, tL2CAP_LE_CFG_INFO cfg) { return 0; }};
+ uint16_t operator()(uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info,
+ uint16_t sec_level, tL2CAP_LE_CFG_INFO cfg) {
+ return body(psm, p_cb_info, sec_level, cfg);
+ };
+};
+extern struct L2CA_RegisterLECoc L2CA_RegisterLECoc;
+// Name: L2CA_DeregisterLECoc
+// Params: uint16_t psm
+// Returns: void
+struct L2CA_DeregisterLECoc {
+ std::function<void(uint16_t psm)> body{[](uint16_t psm) {}};
+ void operator()(uint16_t psm) { body(psm); };
+};
+extern struct L2CA_DeregisterLECoc L2CA_DeregisterLECoc;
+// Name: L2CA_ConnectLECocReq
+// Params: uint16_t psm, const RawAddress& p_bd_addr, tL2CAP_LE_CFG_INFO* p_cfg,
+// uint16_t sec_level Returns: uint16_t
+struct L2CA_ConnectLECocReq {
+ std::function<uint16_t(uint16_t psm, const RawAddress& p_bd_addr,
+ tL2CAP_LE_CFG_INFO* p_cfg, uint16_t sec_level)>
+ body{[](uint16_t psm, const RawAddress& p_bd_addr,
+ tL2CAP_LE_CFG_INFO* p_cfg, uint16_t sec_level) { return 0; }};
+ uint16_t operator()(uint16_t psm, const RawAddress& p_bd_addr,
+ tL2CAP_LE_CFG_INFO* p_cfg, uint16_t sec_level) {
+ return body(psm, p_bd_addr, p_cfg, sec_level);
+ };
+};
+extern struct L2CA_ConnectLECocReq L2CA_ConnectLECocReq;
+// Name: L2CA_GetPeerLECocConfig
+// Params: uint16_t lcid, tL2CAP_LE_CFG_INFO* peer_cfg
+// Returns: bool
+struct L2CA_GetPeerLECocConfig {
+ std::function<bool(uint16_t lcid, tL2CAP_LE_CFG_INFO* peer_cfg)> body{
+ [](uint16_t lcid, tL2CAP_LE_CFG_INFO* peer_cfg) { return false; }};
+ bool operator()(uint16_t lcid, tL2CAP_LE_CFG_INFO* peer_cfg) {
+ return body(lcid, peer_cfg);
+ };
+};
+extern struct L2CA_GetPeerLECocConfig L2CA_GetPeerLECocConfig;
+// Name: L2CA_ConnectCreditBasedRsp
+// Params: const RawAddress& p_bd_addr, uint8_t id, std::vector<uint16_t>&
+// accepted_lcids, uint16_t result, tL2CAP_LE_CFG_INFO* p_cfg Returns: bool
+struct L2CA_ConnectCreditBasedRsp {
+ std::function<bool(const RawAddress& p_bd_addr, uint8_t id,
+ std::vector<uint16_t>& accepted_lcids, uint16_t result,
+ tL2CAP_LE_CFG_INFO* p_cfg)>
+ body{[](const RawAddress& p_bd_addr, uint8_t id,
+ std::vector<uint16_t>& accepted_lcids, uint16_t result,
+ tL2CAP_LE_CFG_INFO* p_cfg) { return false; }};
+ bool operator()(const RawAddress& p_bd_addr, uint8_t id,
+ std::vector<uint16_t>& accepted_lcids, uint16_t result,
+ tL2CAP_LE_CFG_INFO* p_cfg) {
+ return body(p_bd_addr, id, accepted_lcids, result, p_cfg);
+ };
+};
+extern struct L2CA_ConnectCreditBasedRsp L2CA_ConnectCreditBasedRsp;
+// Name: L2CA_ConnectCreditBasedReq
+// Params: uint16_t psm, const RawAddress& p_bd_addr, tL2CAP_LE_CFG_INFO* p_cfg
+// Returns: std::vector<uint16_t>
+struct L2CA_ConnectCreditBasedReq {
+ std::vector<uint16_t> cids;
+ std::function<std::vector<uint16_t>(uint16_t psm, const RawAddress& p_bd_addr,
+ tL2CAP_LE_CFG_INFO* p_cfg)>
+ body{[this](uint16_t psm, const RawAddress& p_bd_addr,
+ tL2CAP_LE_CFG_INFO* p_cfg) { return cids; }};
+ std::vector<uint16_t> operator()(uint16_t psm, const RawAddress& p_bd_addr,
+ tL2CAP_LE_CFG_INFO* p_cfg) {
+ return body(psm, p_bd_addr, p_cfg);
+ };
+};
+extern struct L2CA_ConnectCreditBasedReq L2CA_ConnectCreditBasedReq;
+// Name: L2CA_ReconfigCreditBasedConnsReq
+// Params: const RawAddress& bda, std::vector<uint16_t>& lcids,
+// tL2CAP_LE_CFG_INFO* p_cfg Returns: bool
+struct L2CA_ReconfigCreditBasedConnsReq {
+ std::function<bool(const RawAddress& bda, std::vector<uint16_t>& lcids,
+ tL2CAP_LE_CFG_INFO* p_cfg)>
+ body{[](const RawAddress& bda, std::vector<uint16_t>& lcids,
+ tL2CAP_LE_CFG_INFO* p_cfg) { return false; }};
+ bool operator()(const RawAddress& bda, std::vector<uint16_t>& lcids,
+ tL2CAP_LE_CFG_INFO* p_cfg) {
+ return body(bda, lcids, p_cfg);
+ };
+};
+extern struct L2CA_ReconfigCreditBasedConnsReq L2CA_ReconfigCreditBasedConnsReq;
+// Name: L2CA_DisconnectReq
+// Params: uint16_t cid
+// Returns: bool
+struct L2CA_DisconnectReq {
+ std::function<bool(uint16_t cid)> body{[](uint16_t cid) { return false; }};
+ bool operator()(uint16_t cid) { return body(cid); };
+};
+extern struct L2CA_DisconnectReq L2CA_DisconnectReq;
+// Name: L2CA_DisconnectLECocReq
+// Params: uint16_t cid
+// Returns: bool
+struct L2CA_DisconnectLECocReq {
+ std::function<bool(uint16_t cid)> body{[](uint16_t cid) { return false; }};
+ bool operator()(uint16_t cid) { return body(cid); };
+};
+extern struct L2CA_DisconnectLECocReq L2CA_DisconnectLECocReq;
+// Name: L2CA_GetRemoteCid
+// Params: uint16_t lcid, uint16_t* rcid
+// Returns: bool
+struct L2CA_GetRemoteCid {
+ std::function<bool(uint16_t lcid, uint16_t* rcid)> body{
+ [](uint16_t lcid, uint16_t* rcid) { return false; }};
+ bool operator()(uint16_t lcid, uint16_t* rcid) { return body(lcid, rcid); };
+};
+extern struct L2CA_GetRemoteCid L2CA_GetRemoteCid;
+// Name: L2CA_SetIdleTimeoutByBdAddr
+// Params: const RawAddress& bd_addr, uint16_t timeout, tBT_TRANSPORT transport
+// Returns: bool
+struct L2CA_SetIdleTimeoutByBdAddr {
+ std::function<bool(const RawAddress& bd_addr, uint16_t timeout,
+ tBT_TRANSPORT transport)>
+ body{[](const RawAddress& bd_addr, uint16_t timeout,
+ tBT_TRANSPORT transport) { return false; }};
+ bool operator()(const RawAddress& bd_addr, uint16_t timeout,
+ tBT_TRANSPORT transport) {
+ return body(bd_addr, timeout, transport);
+ };
+};
+extern struct L2CA_SetIdleTimeoutByBdAddr L2CA_SetIdleTimeoutByBdAddr;
+// Name: L2CA_SetTraceLevel
+// Params: uint8_t new_level
+// Returns: uint8_t
+struct L2CA_SetTraceLevel {
+ std::function<uint8_t(uint8_t new_level)> body{
+ [](uint8_t new_level) { return 0; }};
+ uint8_t operator()(uint8_t new_level) { return body(new_level); };
+};
+extern struct L2CA_SetTraceLevel L2CA_SetTraceLevel;
+// Name: L2CA_SetAclPriority
+// Params: const RawAddress& bd_addr, tL2CAP_PRIORITY priority
+// Returns: bool
+struct L2CA_SetAclPriority {
+ std::function<bool(const RawAddress& bd_addr, tL2CAP_PRIORITY priority)> body{
+ [](const RawAddress& bd_addr, tL2CAP_PRIORITY priority) {
+ return false;
+ }};
+ bool operator()(const RawAddress& bd_addr, tL2CAP_PRIORITY priority) {
+ return body(bd_addr, priority);
+ };
+};
+extern struct L2CA_SetAclPriority L2CA_SetAclPriority;
+// Name: L2CA_SetTxPriority
+// Params: uint16_t cid, tL2CAP_CHNL_PRIORITY priority
+// Returns: bool
+struct L2CA_SetTxPriority {
+ std::function<bool(uint16_t cid, tL2CAP_CHNL_PRIORITY priority)> body{
+ [](uint16_t cid, tL2CAP_CHNL_PRIORITY priority) { return false; }};
+ bool operator()(uint16_t cid, tL2CAP_CHNL_PRIORITY priority) {
+ return body(cid, priority);
+ };
+};
+extern struct L2CA_SetTxPriority L2CA_SetTxPriority;
+// Name: L2CA_GetPeerFeatures
+// Params: const RawAddress& bd_addr, uint32_t* p_ext_feat, uint8_t* p_chnl_mask
+// Returns: bool
+struct L2CA_GetPeerFeatures {
+ std::function<bool(const RawAddress& bd_addr, uint32_t* p_ext_feat,
+ uint8_t* p_chnl_mask)>
+ body{[](const RawAddress& bd_addr, uint32_t* p_ext_feat,
+ uint8_t* p_chnl_mask) { return false; }};
+ bool operator()(const RawAddress& bd_addr, uint32_t* p_ext_feat,
+ uint8_t* p_chnl_mask) {
+ return body(bd_addr, p_ext_feat, p_chnl_mask);
+ };
+};
+extern struct L2CA_GetPeerFeatures L2CA_GetPeerFeatures;
+// Name: L2CA_RegisterFixedChannel
+// Params: uint16_t fixed_cid, tL2CAP_FIXED_CHNL_REG* p_freg
+// Returns: bool
+struct L2CA_RegisterFixedChannel {
+ std::function<bool(uint16_t fixed_cid, tL2CAP_FIXED_CHNL_REG* p_freg)> body{
+ [](uint16_t fixed_cid, tL2CAP_FIXED_CHNL_REG* p_freg) { return false; }};
+ bool operator()(uint16_t fixed_cid, tL2CAP_FIXED_CHNL_REG* p_freg) {
+ return body(fixed_cid, p_freg);
+ };
+};
+extern struct L2CA_RegisterFixedChannel L2CA_RegisterFixedChannel;
+// Name: L2CA_ConnectFixedChnl
+// Params: uint16_t fixed_cid, const RawAddress& rem_bda
+// Returns: bool
+struct L2CA_ConnectFixedChnl {
+ std::function<bool(uint16_t fixed_cid, const RawAddress& rem_bda)> body{
+ [](uint16_t fixed_cid, const RawAddress& rem_bda) { return false; }};
+ bool operator()(uint16_t fixed_cid, const RawAddress& rem_bda) {
+ return body(fixed_cid, rem_bda);
+ };
+};
+extern struct L2CA_ConnectFixedChnl L2CA_ConnectFixedChnl;
+// Name: L2CA_SendFixedChnlData
+// Params: uint16_t fixed_cid, const RawAddress& rem_bda, BT_HDR* p_buf
+// Returns: uint16_t
+struct L2CA_SendFixedChnlData {
+ std::function<uint16_t(uint16_t fixed_cid, const RawAddress& rem_bda,
+ BT_HDR* p_buf)>
+ body{[](uint16_t fixed_cid, const RawAddress& rem_bda, BT_HDR* p_buf) {
+ return 0;
+ }};
+ uint16_t operator()(uint16_t fixed_cid, const RawAddress& rem_bda,
+ BT_HDR* p_buf) {
+ return body(fixed_cid, rem_bda, p_buf);
+ };
+};
+extern struct L2CA_SendFixedChnlData L2CA_SendFixedChnlData;
+// Name: L2CA_RemoveFixedChnl
+// Params: uint16_t fixed_cid, const RawAddress& rem_bda
+// Returns: bool
+struct L2CA_RemoveFixedChnl {
+ std::function<bool(uint16_t fixed_cid, const RawAddress& rem_bda)> body{
+ [](uint16_t fixed_cid, const RawAddress& rem_bda) { return false; }};
+ bool operator()(uint16_t fixed_cid, const RawAddress& rem_bda) {
+ return body(fixed_cid, rem_bda);
+ };
+};
+extern struct L2CA_RemoveFixedChnl L2CA_RemoveFixedChnl;
+// Name: L2CA_SetLeGattTimeout
+// Params: const RawAddress& rem_bda, uint16_t idle_tout
+// Returns: bool
+struct L2CA_SetLeGattTimeout {
+ std::function<bool(const RawAddress& rem_bda, uint16_t idle_tout)> body{
+ [](const RawAddress& rem_bda, uint16_t idle_tout) { return false; }};
+ bool operator()(const RawAddress& rem_bda, uint16_t idle_tout) {
+ return body(rem_bda, idle_tout);
+ };
+};
+extern struct L2CA_SetLeGattTimeout L2CA_SetLeGattTimeout;
+// Name: L2CA_DataWrite
+// Params: uint16_t cid, BT_HDR* p_data
+// Returns: uint8_t
+struct L2CA_DataWrite {
+ std::function<uint8_t(uint16_t cid, BT_HDR* p_data)> body{
+ [](uint16_t cid, BT_HDR* p_data) { return 0; }};
+ uint8_t operator()(uint16_t cid, BT_HDR* p_data) {
+ return body(cid, p_data);
+ };
+};
+extern struct L2CA_DataWrite L2CA_DataWrite;
+// Name: L2CA_LECocDataWrite
+// Params: uint16_t cid, BT_HDR* p_data
+// Returns: uint8_t
+struct L2CA_LECocDataWrite {
+ std::function<uint8_t(uint16_t cid, BT_HDR* p_data)> body{
+ [](uint16_t cid, BT_HDR* p_data) { return 0; }};
+ uint8_t operator()(uint16_t cid, BT_HDR* p_data) {
+ return body(cid, p_data);
+ };
+};
+extern struct L2CA_LECocDataWrite L2CA_LECocDataWrite;
+// Name: L2CA_SetChnlFlushability
+// Params: uint16_t cid, bool is_flushable
+// Returns: bool
+struct L2CA_SetChnlFlushability {
+ std::function<bool(uint16_t cid, bool is_flushable)> body{
+ [](uint16_t cid, bool is_flushable) { return false; }};
+ bool operator()(uint16_t cid, bool is_flushable) {
+ return body(cid, is_flushable);
+ };
+};
+extern struct L2CA_SetChnlFlushability L2CA_SetChnlFlushability;
+// Name: L2CA_FlushChannel
+// Params: uint16_t lcid, uint16_t num_to_flush
+// Returns: uint16_t
+struct L2CA_FlushChannel {
+ std::function<uint16_t(uint16_t lcid, uint16_t num_to_flush)> body{
+ [](uint16_t lcid, uint16_t num_to_flush) { return 0; }};
+ uint16_t operator()(uint16_t lcid, uint16_t num_to_flush) {
+ return body(lcid, num_to_flush);
+ };
+};
+extern struct L2CA_FlushChannel L2CA_FlushChannel;
+// Name: L2CA_IsLinkEstablished
+// Params: const RawAddress& bd_addr, tBT_TRANSPORT transport
+// Returns: bool
+struct L2CA_IsLinkEstablished {
+ std::function<bool(const RawAddress& bd_addr, tBT_TRANSPORT transport)> body{
+ [](const RawAddress& bd_addr, tBT_TRANSPORT transport) { return false; }};
+ bool operator()(const RawAddress& bd_addr, tBT_TRANSPORT transport) {
+ return body(bd_addr, transport);
+ };
+};
+extern struct L2CA_IsLinkEstablished L2CA_IsLinkEstablished;
+
+} // namespace stack_l2cap_api
+} // namespace mock
+} // namespace test
+
+// END mockcify generation
diff --git a/test/mock/mock_stack_l2cap_ble.cc b/test/mock/mock_stack_l2cap_ble.cc
new file mode 100644
index 0000000..a47ea55
--- /dev/null
+++ b/test/mock/mock_stack_l2cap_ble.cc
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:22
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+
+// Mock include file to share data between tests and mock
+#include "test/mock/mock_stack_l2cap_ble.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+// Mocked internal structures, if any
+
+namespace test {
+namespace mock {
+namespace stack_l2cap_ble {
+
+// Function state capture and return values, if needed
+struct L2CA_UpdateBleConnParams L2CA_UpdateBleConnParams;
+struct L2CA_EnableUpdateBleConnParams L2CA_EnableUpdateBleConnParams;
+struct L2CA_GetBleConnRole L2CA_GetBleConnRole;
+struct l2cble_notify_le_connection l2cble_notify_le_connection;
+struct l2cble_conn_comp l2cble_conn_comp;
+struct l2cble_conn_comp_from_address_with_type
+ l2cble_conn_comp_from_address_with_type;
+struct l2cble_process_conn_update_evt l2cble_process_conn_update_evt;
+struct l2cble_process_sig_cmd l2cble_process_sig_cmd;
+struct l2cble_create_conn l2cble_create_conn;
+struct l2c_link_processs_ble_num_bufs l2c_link_processs_ble_num_bufs;
+struct l2c_ble_link_adjust_allocation l2c_ble_link_adjust_allocation;
+struct l2cble_process_rc_param_request_evt l2cble_process_rc_param_request_evt;
+struct l2cble_update_data_length l2cble_update_data_length;
+struct l2cble_process_data_length_change_event
+ l2cble_process_data_length_change_event;
+struct l2cble_credit_based_conn_req l2cble_credit_based_conn_req;
+struct l2cble_credit_based_conn_res l2cble_credit_based_conn_res;
+struct l2cble_send_flow_control_credit l2cble_send_flow_control_credit;
+struct l2cble_send_peer_disc_req l2cble_send_peer_disc_req;
+struct l2cble_sec_comp l2cble_sec_comp;
+struct l2ble_sec_access_req l2ble_sec_access_req;
+struct L2CA_AdjustConnectionIntervals L2CA_AdjustConnectionIntervals;
+struct l2cble_use_preferred_conn_params l2cble_use_preferred_conn_params;
+
+} // namespace stack_l2cap_ble
+} // namespace mock
+} // namespace test
+
+// Mocked functions, if any
+bool L2CA_UpdateBleConnParams(const RawAddress& rem_bda, uint16_t min_int,
+ uint16_t max_int, uint16_t latency,
+ uint16_t timeout, uint16_t min_ce_len,
+ uint16_t max_ce_len) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_ble::L2CA_UpdateBleConnParams(
+ rem_bda, min_int, max_int, latency, timeout, min_ce_len, max_ce_len);
+}
+bool L2CA_EnableUpdateBleConnParams(const RawAddress& rem_bda, bool enable) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_ble::L2CA_EnableUpdateBleConnParams(rem_bda,
+ enable);
+}
+hci_role_t L2CA_GetBleConnRole(const RawAddress& bd_addr) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_ble::L2CA_GetBleConnRole(bd_addr);
+}
+void l2cble_notify_le_connection(const RawAddress& bda) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_l2cap_ble::l2cble_notify_le_connection(bda);
+}
+bool 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) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_ble::l2cble_conn_comp(
+ handle, role, bda, type, conn_interval, conn_latency, conn_timeout);
+}
+bool l2cble_conn_comp_from_address_with_type(
+ uint16_t handle, uint8_t role, const tBLE_BD_ADDR& address_with_type,
+ uint16_t conn_interval, uint16_t conn_latency, uint16_t conn_timeout) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_ble::l2cble_conn_comp_from_address_with_type(
+ handle, role, address_with_type, conn_interval, conn_latency,
+ conn_timeout);
+}
+void l2cble_process_conn_update_evt(uint16_t handle, uint8_t status,
+ uint16_t interval, uint16_t latency,
+ uint16_t timeout) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_l2cap_ble::l2cble_process_conn_update_evt(
+ handle, status, interval, latency, timeout);
+}
+void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_l2cap_ble::l2cble_process_sig_cmd(p_lcb, p, pkt_len);
+}
+bool l2cble_create_conn(tL2C_LCB* p_lcb) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_ble::l2cble_create_conn(p_lcb);
+}
+void l2c_link_processs_ble_num_bufs(uint16_t num_lm_ble_bufs) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_l2cap_ble::l2c_link_processs_ble_num_bufs(num_lm_ble_bufs);
+}
+void l2c_ble_link_adjust_allocation(void) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_l2cap_ble::l2c_ble_link_adjust_allocation();
+}
+void l2cble_process_rc_param_request_evt(uint16_t handle, uint16_t int_min,
+ uint16_t int_max, uint16_t latency,
+ uint16_t timeout) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_l2cap_ble::l2cble_process_rc_param_request_evt(
+ handle, int_min, int_max, latency, timeout);
+}
+void l2cble_update_data_length(tL2C_LCB* p_lcb) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_l2cap_ble::l2cble_update_data_length(p_lcb);
+}
+void l2cble_process_data_length_change_event(uint16_t handle,
+ uint16_t tx_data_len,
+ uint16_t rx_data_len) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_l2cap_ble::l2cble_process_data_length_change_event(
+ handle, tx_data_len, rx_data_len);
+}
+void l2cble_credit_based_conn_req(tL2C_CCB* p_ccb) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_l2cap_ble::l2cble_credit_based_conn_req(p_ccb);
+}
+void l2cble_credit_based_conn_res(tL2C_CCB* p_ccb, uint16_t result) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_l2cap_ble::l2cble_credit_based_conn_res(p_ccb, result);
+}
+void l2cble_send_flow_control_credit(tL2C_CCB* p_ccb, uint16_t credit_value) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_l2cap_ble::l2cble_send_flow_control_credit(p_ccb,
+ credit_value);
+}
+void l2cble_send_peer_disc_req(tL2C_CCB* p_ccb) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_l2cap_ble::l2cble_send_peer_disc_req(p_ccb);
+}
+void l2cble_sec_comp(const RawAddress* bda, tBT_TRANSPORT transport,
+ void* p_ref_data, tBTM_STATUS status) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_l2cap_ble::l2cble_sec_comp(bda, transport, p_ref_data,
+ status);
+}
+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) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_l2cap_ble::l2ble_sec_access_req(
+ bd_addr, psm, is_originator, p_callback, p_ref_data);
+}
+void L2CA_AdjustConnectionIntervals(uint16_t* min_interval,
+ uint16_t* max_interval,
+ uint16_t floor_interval) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_l2cap_ble::L2CA_AdjustConnectionIntervals(
+ min_interval, max_interval, floor_interval);
+}
+void l2cble_use_preferred_conn_params(const RawAddress& bda) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_l2cap_ble::l2cble_use_preferred_conn_params(bda);
+}
+
+// END mockcify generation
diff --git a/test/mock/mock_stack_l2cap_ble.h b/test/mock/mock_stack_l2cap_ble.h
new file mode 100644
index 0000000..a47cf5f
--- /dev/null
+++ b/test/mock/mock_stack_l2cap_ble.h
@@ -0,0 +1,321 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:22
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <cstdint>
+#include <functional>
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+#include "stack/include/l2c_api.h"
+#include "stack/l2cap/l2c_int.h"
+#include "types/ble_address_with_type.h"
+#include "types/hci_role.h"
+#include "types/raw_address.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+namespace test {
+namespace mock {
+namespace stack_l2cap_ble {
+
+// Shared state between mocked functions and tests
+// Name: L2CA_UpdateBleConnParams
+// Params: const RawAddress& rem_bda, uint16_t min_int, uint16_t max_int,
+// uint16_t latency, uint16_t timeout, uint16_t min_ce_len, uint16_t max_ce_len
+// Returns: bool
+struct L2CA_UpdateBleConnParams {
+ std::function<bool(const RawAddress& rem_bda, uint16_t min_int,
+ uint16_t max_int, uint16_t latency, uint16_t timeout,
+ uint16_t min_ce_len, uint16_t max_ce_len)>
+ body{[](const RawAddress& rem_bda, uint16_t min_int, uint16_t max_int,
+ uint16_t latency, uint16_t timeout, uint16_t min_ce_len,
+ uint16_t max_ce_len) { return false; }};
+ bool operator()(const RawAddress& rem_bda, uint16_t min_int, uint16_t max_int,
+ uint16_t latency, uint16_t timeout, uint16_t min_ce_len,
+ uint16_t max_ce_len) {
+ return body(rem_bda, min_int, max_int, latency, timeout, min_ce_len,
+ max_ce_len);
+ };
+};
+extern struct L2CA_UpdateBleConnParams L2CA_UpdateBleConnParams;
+// Name: L2CA_EnableUpdateBleConnParams
+// Params: const RawAddress& rem_bda, bool enable
+// Returns: bool
+struct L2CA_EnableUpdateBleConnParams {
+ std::function<bool(const RawAddress& rem_bda, bool enable)> body{
+ [](const RawAddress& rem_bda, bool enable) { return false; }};
+ bool operator()(const RawAddress& rem_bda, bool enable) {
+ return body(rem_bda, enable);
+ };
+};
+extern struct L2CA_EnableUpdateBleConnParams L2CA_EnableUpdateBleConnParams;
+// Name: L2CA_GetBleConnRole
+// Params: const RawAddress& bd_addr
+// Returns: hci_role_t
+struct L2CA_GetBleConnRole {
+ std::function<hci_role_t(const RawAddress& bd_addr)> body{
+ [](const RawAddress& bd_addr) { return HCI_ROLE_CENTRAL; }};
+ hci_role_t operator()(const RawAddress& bd_addr) { return body(bd_addr); };
+};
+extern struct L2CA_GetBleConnRole L2CA_GetBleConnRole;
+// Name: l2cble_notify_le_connection
+// Params: const RawAddress& bda
+// Returns: void
+struct l2cble_notify_le_connection {
+ std::function<void(const RawAddress& bda)> body{[](const RawAddress& bda) {}};
+ void operator()(const RawAddress& bda) { body(bda); };
+};
+extern struct l2cble_notify_le_connection l2cble_notify_le_connection;
+// Name: l2cble_conn_comp
+// Params: 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
+// Returns: bool
+struct l2cble_conn_comp {
+ std::function<bool(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)>
+ body{[](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) { return false; }};
+ bool operator()(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) {
+ return body(handle, role, bda, type, conn_interval, conn_latency,
+ conn_timeout);
+ };
+};
+extern struct l2cble_conn_comp l2cble_conn_comp;
+// Name: l2cble_conn_comp_from_address_with_type
+// Params: uint16_t handle, uint8_t role, const tBLE_BD_ADDR&
+// address_with_type, uint16_t conn_interval, uint16_t conn_latency, uint16_t
+// conn_timeout Returns: bool
+struct l2cble_conn_comp_from_address_with_type {
+ std::function<bool(
+ uint16_t handle, uint8_t role, const tBLE_BD_ADDR& address_with_type,
+ uint16_t conn_interval, uint16_t conn_latency, uint16_t conn_timeout)>
+ body{[](uint16_t handle, uint8_t role,
+ const tBLE_BD_ADDR& address_with_type, uint16_t conn_interval,
+ uint16_t conn_latency, uint16_t conn_timeout) { return false; }};
+ bool operator()(uint16_t handle, uint8_t role,
+ const tBLE_BD_ADDR& address_with_type, uint16_t conn_interval,
+ uint16_t conn_latency, uint16_t conn_timeout) {
+ return body(handle, role, address_with_type, conn_interval, conn_latency,
+ conn_timeout);
+ };
+};
+extern struct l2cble_conn_comp_from_address_with_type
+ l2cble_conn_comp_from_address_with_type;
+// Name: l2cble_process_conn_update_evt
+// Params: uint16_t handle, uint8_t status, uint16_t interval, uint16_t latency,
+// uint16_t timeout Returns: void
+struct l2cble_process_conn_update_evt {
+ std::function<void(uint16_t handle, uint8_t status, uint16_t interval,
+ uint16_t latency, uint16_t timeout)>
+ body{[](uint16_t handle, uint8_t status, uint16_t interval,
+ uint16_t latency, uint16_t timeout) {}};
+ void operator()(uint16_t handle, uint8_t status, uint16_t interval,
+ uint16_t latency, uint16_t timeout) {
+ body(handle, status, interval, latency, timeout);
+ };
+};
+extern struct l2cble_process_conn_update_evt l2cble_process_conn_update_evt;
+// Name: l2cble_process_sig_cmd
+// Params: tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len
+// Returns: void
+struct l2cble_process_sig_cmd {
+ std::function<void(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len)> body{
+ [](tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) {}};
+ void operator()(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) {
+ body(p_lcb, p, pkt_len);
+ };
+};
+extern struct l2cble_process_sig_cmd l2cble_process_sig_cmd;
+// Name: l2cble_create_conn
+// Params: tL2C_LCB* p_lcb
+// Returns: bool
+struct l2cble_create_conn {
+ std::function<bool(tL2C_LCB* p_lcb)> body{
+ [](tL2C_LCB* p_lcb) { return false; }};
+ bool operator()(tL2C_LCB* p_lcb) { return body(p_lcb); };
+};
+extern struct l2cble_create_conn l2cble_create_conn;
+// Name: l2c_link_processs_ble_num_bufs
+// Params: uint16_t num_lm_ble_bufs
+// Returns: void
+struct l2c_link_processs_ble_num_bufs {
+ std::function<void(uint16_t num_lm_ble_bufs)> body{
+ [](uint16_t num_lm_ble_bufs) {}};
+ void operator()(uint16_t num_lm_ble_bufs) { body(num_lm_ble_bufs); };
+};
+extern struct l2c_link_processs_ble_num_bufs l2c_link_processs_ble_num_bufs;
+// Name: l2c_ble_link_adjust_allocation
+// Params: void
+// Returns: void
+struct l2c_ble_link_adjust_allocation {
+ std::function<void(void)> body{[](void) {}};
+ void operator()(void) { body(); };
+};
+extern struct l2c_ble_link_adjust_allocation l2c_ble_link_adjust_allocation;
+// Name: l2cble_process_rc_param_request_evt
+// Params: uint16_t handle, uint16_t int_min, uint16_t int_max, uint16_t
+// latency, uint16_t timeout Returns: void
+struct l2cble_process_rc_param_request_evt {
+ std::function<void(uint16_t handle, uint16_t int_min, uint16_t int_max,
+ uint16_t latency, uint16_t timeout)>
+ body{[](uint16_t handle, uint16_t int_min, uint16_t int_max,
+ uint16_t latency, uint16_t timeout) {}};
+ void operator()(uint16_t handle, uint16_t int_min, uint16_t int_max,
+ uint16_t latency, uint16_t timeout) {
+ body(handle, int_min, int_max, latency, timeout);
+ };
+};
+extern struct l2cble_process_rc_param_request_evt
+ l2cble_process_rc_param_request_evt;
+// Name: l2cble_update_data_length
+// Params: tL2C_LCB* p_lcb
+// Returns: void
+struct l2cble_update_data_length {
+ std::function<void(tL2C_LCB* p_lcb)> body{[](tL2C_LCB* p_lcb) {}};
+ void operator()(tL2C_LCB* p_lcb) { body(p_lcb); };
+};
+extern struct l2cble_update_data_length l2cble_update_data_length;
+// Name: l2cble_process_data_length_change_event
+// Params: uint16_t handle, uint16_t tx_data_len, uint16_t rx_data_len
+// Returns: void
+struct l2cble_process_data_length_change_event {
+ std::function<void(uint16_t handle, uint16_t tx_data_len,
+ uint16_t rx_data_len)>
+ body{[](uint16_t handle, uint16_t tx_data_len, uint16_t rx_data_len) {}};
+ void operator()(uint16_t handle, uint16_t tx_data_len, uint16_t rx_data_len) {
+ body(handle, tx_data_len, rx_data_len);
+ };
+};
+extern struct l2cble_process_data_length_change_event
+ l2cble_process_data_length_change_event;
+// Name: l2cble_credit_based_conn_req
+// Params: tL2C_CCB* p_ccb
+// Returns: void
+struct l2cble_credit_based_conn_req {
+ std::function<void(tL2C_CCB* p_ccb)> body{[](tL2C_CCB* p_ccb) {}};
+ void operator()(tL2C_CCB* p_ccb) { body(p_ccb); };
+};
+extern struct l2cble_credit_based_conn_req l2cble_credit_based_conn_req;
+// Name: l2cble_credit_based_conn_res
+// Params: tL2C_CCB* p_ccb, uint16_t result
+// Returns: void
+struct l2cble_credit_based_conn_res {
+ std::function<void(tL2C_CCB* p_ccb, uint16_t result)> body{
+ [](tL2C_CCB* p_ccb, uint16_t result) {}};
+ void operator()(tL2C_CCB* p_ccb, uint16_t result) { body(p_ccb, result); };
+};
+extern struct l2cble_credit_based_conn_res l2cble_credit_based_conn_res;
+// Name: l2cble_send_flow_control_credit
+// Params: tL2C_CCB* p_ccb, uint16_t credit_value
+// Returns: void
+struct l2cble_send_flow_control_credit {
+ std::function<void(tL2C_CCB* p_ccb, uint16_t credit_value)> body{
+ [](tL2C_CCB* p_ccb, uint16_t credit_value) {}};
+ void operator()(tL2C_CCB* p_ccb, uint16_t credit_value) {
+ body(p_ccb, credit_value);
+ };
+};
+extern struct l2cble_send_flow_control_credit l2cble_send_flow_control_credit;
+// Name: l2cble_send_peer_disc_req
+// Params: tL2C_CCB* p_ccb
+// Returns: void
+struct l2cble_send_peer_disc_req {
+ std::function<void(tL2C_CCB* p_ccb)> body{[](tL2C_CCB* p_ccb) {}};
+ void operator()(tL2C_CCB* p_ccb) { body(p_ccb); };
+};
+extern struct l2cble_send_peer_disc_req l2cble_send_peer_disc_req;
+// Name: l2cble_sec_comp
+// Params: const RawAddress* bda, tBT_TRANSPORT transport, void* p_ref_data,
+// tBTM_STATUS status Returns: void
+struct l2cble_sec_comp {
+ std::function<void(const RawAddress* bda, tBT_TRANSPORT transport,
+ void* p_ref_data, tBTM_STATUS status)>
+ body{[](const RawAddress* bda, tBT_TRANSPORT transport, void* p_ref_data,
+ tBTM_STATUS status) {}};
+ void operator()(const RawAddress* bda, tBT_TRANSPORT transport,
+ void* p_ref_data, tBTM_STATUS status) {
+ body(bda, transport, p_ref_data, status);
+ };
+};
+extern struct l2cble_sec_comp l2cble_sec_comp;
+// Name: l2ble_sec_access_req
+// Params: const RawAddress& bd_addr, uint16_t psm, bool is_originator,
+// tL2CAP_SEC_CBACK* p_callback, void* p_ref_data Returns: tL2CAP_LE_RESULT_CODE
+struct l2ble_sec_access_req {
+ std::function<tL2CAP_LE_RESULT_CODE(
+ const RawAddress& bd_addr, uint16_t psm, bool is_originator,
+ tL2CAP_SEC_CBACK* p_callback, void* p_ref_data)>
+ body{[](const RawAddress& bd_addr, uint16_t psm, bool is_originator,
+ tL2CAP_SEC_CBACK* p_callback,
+ void* p_ref_data) { return L2CAP_LE_RESULT_CONN_OK; }};
+ tL2CAP_LE_RESULT_CODE operator()(const RawAddress& bd_addr, uint16_t psm,
+ bool is_originator,
+ tL2CAP_SEC_CBACK* p_callback,
+ void* p_ref_data) {
+ return body(bd_addr, psm, is_originator, p_callback, p_ref_data);
+ };
+};
+extern struct l2ble_sec_access_req l2ble_sec_access_req;
+// Name: L2CA_AdjustConnectionIntervals
+// Params: uint16_t* min_interval, uint16_t* max_interval, uint16_t
+// floor_interval Returns: void
+struct L2CA_AdjustConnectionIntervals {
+ std::function<void(uint16_t* min_interval, uint16_t* max_interval,
+ uint16_t floor_interval)>
+ body{[](uint16_t* min_interval, uint16_t* max_interval,
+ uint16_t floor_interval) {}};
+ void operator()(uint16_t* min_interval, uint16_t* max_interval,
+ uint16_t floor_interval) {
+ body(min_interval, max_interval, floor_interval);
+ };
+};
+extern struct L2CA_AdjustConnectionIntervals L2CA_AdjustConnectionIntervals;
+// Name: l2cble_use_preferred_conn_params
+// Params: const RawAddress& bda
+// Returns: void
+struct l2cble_use_preferred_conn_params {
+ std::function<void(const RawAddress& bda)> body{[](const RawAddress& bda) {}};
+ void operator()(const RawAddress& bda) { body(bda); };
+};
+extern struct l2cble_use_preferred_conn_params l2cble_use_preferred_conn_params;
+
+} // namespace stack_l2cap_ble
+} // namespace mock
+} // namespace test
+
+// END mockcify generation
diff --git a/main/test/common/mock_l2cap_l2c_link.cc b/test/mock/mock_stack_l2cap_link.cc
similarity index 100%
rename from main/test/common/mock_l2cap_l2c_link.cc
rename to test/mock/mock_stack_l2cap_link.cc
diff --git a/test/mock/mock_stack_l2cap_main.cc b/test/mock/mock_stack_l2cap_main.cc
index 677858e..ab28a6c 100644
--- a/test/mock/mock_stack_l2cap_main.cc
+++ b/test/mock/mock_stack_l2cap_main.cc
@@ -30,11 +30,11 @@
#include "hci/include/btsnoop.h"
#include "hcimsgs.h"
#include "l2c_api.h"
-#include "l2c_int.h"
#include "l2cdefs.h"
#include "main/shim/shim.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
+#include "stack/l2cap/l2c_int.h"
#ifndef UNUSED_ATTR
#define UNUSED_ATTR
diff --git a/stack/test/common/mock_l2cap_l2c_utils.cc b/test/mock/mock_stack_l2cap_utils.cc
similarity index 100%
rename from stack/test/common/mock_l2cap_l2c_utils.cc
rename to test/mock/mock_stack_l2cap_utils.cc
diff --git a/test/mock/mock_stack_metrics_logging.cc b/test/mock/mock_stack_metrics_logging.cc
new file mode 100644
index 0000000..3485c35
--- /dev/null
+++ b/test/mock/mock_stack_metrics_logging.cc
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:5
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+#include <frameworks/proto_logging/stats/enums/bluetooth/enums.pb.h>
+#include <frameworks/proto_logging/stats/enums/bluetooth/hci/enums.pb.h>
+#include "common/metrics.h"
+#include "main/shim/metrics_api.h"
+#include "main/shim/shim.h"
+#include "stack/include/stack_metrics_logging.h"
+#include "types/raw_address.h"
+
+// Mock include file to share data between tests and mock
+#include "test/mock/mock_stack_metrics_logging.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+// Mocked internal structures, if any
+
+namespace test {
+namespace mock {
+namespace stack_metrics_logging {
+
+// Function state capture and return values, if needed
+struct log_classic_pairing_event log_classic_pairing_event;
+struct log_link_layer_connection_event log_link_layer_connection_event;
+struct log_smp_pairing_event log_smp_pairing_event;
+struct log_sdp_attribute log_sdp_attribute;
+struct log_manufacturer_info log_manufacturer_info;
+
+} // namespace stack_metrics_logging
+} // namespace mock
+} // namespace test
+
+// Mocked functions, if any
+void log_classic_pairing_event(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) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_metrics_logging::log_classic_pairing_event(
+ address, handle, hci_cmd, hci_event, cmd_status, reason_code,
+ event_value);
+}
+void log_link_layer_connection_event(
+ 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) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_metrics_logging::log_link_layer_connection_event(
+ address, connection_handle, direction, link_type, hci_cmd, hci_event,
+ hci_ble_event, cmd_status, reason_code);
+}
+void log_smp_pairing_event(const RawAddress& address, uint8_t smp_cmd,
+ android::bluetooth::DirectionEnum direction,
+ uint8_t smp_fail_reason) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_metrics_logging::log_smp_pairing_event(
+ address, smp_cmd, direction, smp_fail_reason);
+}
+void log_sdp_attribute(const RawAddress& address, uint16_t protocol_uuid,
+ uint16_t attribute_id, size_t attribute_size,
+ const char* attribute_value) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_metrics_logging::log_sdp_attribute(
+ address, protocol_uuid, attribute_id, attribute_size, attribute_value);
+}
+void log_manufacturer_info(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) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_metrics_logging::log_manufacturer_info(
+ address, source_type, source_name, manufacturer, model, hardware_version,
+ software_version);
+}
+
+// END mockcify generation
diff --git a/test/mock/mock_stack_metrics_logging.h b/test/mock/mock_stack_metrics_logging.h
new file mode 100644
index 0000000..f923859
--- /dev/null
+++ b/test/mock/mock_stack_metrics_logging.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:5
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+#include <frameworks/proto_logging/stats/enums/bluetooth/enums.pb.h>
+#include <frameworks/proto_logging/stats/enums/bluetooth/hci/enums.pb.h>
+#include "common/metrics.h"
+#include "main/shim/metrics_api.h"
+#include "main/shim/shim.h"
+#include "stack/include/stack_metrics_logging.h"
+#include "types/raw_address.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+namespace test {
+namespace mock {
+namespace stack_metrics_logging {
+
+// Shared state between mocked functions and tests
+// Name: log_classic_pairing_event
+// Params: 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 Returns: void
+struct log_classic_pairing_event {
+ std::function<void(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)>
+ body{[](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) {}};
+ void operator()(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) {
+ body(address, handle, hci_cmd, hci_event, cmd_status, reason_code,
+ event_value);
+ };
+};
+extern struct log_classic_pairing_event log_classic_pairing_event;
+// Name: log_link_layer_connection_event
+// Params: 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 Returns: void
+struct log_link_layer_connection_event {
+ std::function<void(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)>
+ body{[](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) {}};
+ void operator()(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) {
+ body(address, connection_handle, direction, link_type, hci_cmd, hci_event,
+ hci_ble_event, cmd_status, reason_code);
+ };
+};
+extern struct log_link_layer_connection_event log_link_layer_connection_event;
+// Name: log_smp_pairing_event
+// Params: const RawAddress& address, uint8_t smp_cmd,
+// android::bluetooth::DirectionEnum direction, uint8_t smp_fail_reason Returns:
+// void
+struct log_smp_pairing_event {
+ std::function<void(const RawAddress& address, uint8_t smp_cmd,
+ android::bluetooth::DirectionEnum direction,
+ uint8_t smp_fail_reason)>
+ body{[](const RawAddress& address, uint8_t smp_cmd,
+ android::bluetooth::DirectionEnum direction,
+ uint8_t smp_fail_reason) {}};
+ void operator()(const RawAddress& address, uint8_t smp_cmd,
+ android::bluetooth::DirectionEnum direction,
+ uint8_t smp_fail_reason) {
+ body(address, smp_cmd, direction, smp_fail_reason);
+ };
+};
+extern struct log_smp_pairing_event log_smp_pairing_event;
+// Name: log_sdp_attribute
+// Params: const RawAddress& address, uint16_t protocol_uuid, uint16_t
+// attribute_id, size_t attribute_size, const char* attribute_value Returns:
+// void
+struct log_sdp_attribute {
+ std::function<void(const RawAddress& address, uint16_t protocol_uuid,
+ uint16_t attribute_id, size_t attribute_size,
+ const char* attribute_value)>
+ body{[](const RawAddress& address, uint16_t protocol_uuid,
+ uint16_t attribute_id, size_t attribute_size,
+ const char* attribute_value) {}};
+ void operator()(const RawAddress& address, uint16_t protocol_uuid,
+ uint16_t attribute_id, size_t attribute_size,
+ const char* attribute_value) {
+ body(address, protocol_uuid, attribute_id, attribute_size, attribute_value);
+ };
+};
+extern struct log_sdp_attribute log_sdp_attribute;
+// Name: log_manufacturer_info
+// Params: 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 Returns: void
+struct log_manufacturer_info {
+ std::function<void(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)>
+ body{[](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) {}};
+ void operator()(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) {
+ body(address, source_type, source_name, manufacturer, model,
+ hardware_version, software_version);
+ };
+};
+extern struct log_manufacturer_info log_manufacturer_info;
+
+} // namespace stack_metrics_logging
+} // namespace mock
+} // namespace test
+
+// END mockcify generation
\ No newline at end of file
diff --git a/test/mock/mock_stack_pan_api.cc b/test/mock/mock_stack_pan_api.cc
index cb452b3..29023b2 100644
--- a/test/mock/mock_stack_pan_api.cc
+++ b/test/mock/mock_stack_pan_api.cc
@@ -29,7 +29,6 @@
#include "bnep_api.h"
#include "bt_common.h"
#include "bt_types.h"
-#include "bta_sys.h"
#include "btm_api.h"
#include "hcidefs.h"
#include "l2c_api.h"
diff --git a/test/mock/mock_stack_sdp.cc b/test/mock/mock_stack_sdp.cc
deleted file mode 100644
index ef39c63..0000000
--- a/test/mock/mock_stack_sdp.cc
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generated mock file from original source file
- */
-
-#include <string.h>
-
-#include "bt_target.h"
-
-#include "sdp_api.h"
-
-#include "osi/include/osi.h"
-
-using bluetooth::Uuid;
-
-bool SDP_InitDiscoveryDb(tSDP_DISCOVERY_DB* p_db, uint32_t len,
- uint16_t num_uuid, const Uuid* p_uuid_list,
- uint16_t num_attr, uint16_t* p_attr_list) {
- return false;
-}
-
-bool SDP_CancelServiceSearch(tSDP_DISCOVERY_DB* p_db) { return false; }
-
-bool SDP_ServiceSearchRequest(const RawAddress& p_bd_addr,
- tSDP_DISCOVERY_DB* p_db,
- tSDP_DISC_CMPL_CB* p_cb) {
- return false;
-}
-
-bool SDP_ServiceSearchAttributeRequest(const RawAddress& p_bd_addr,
- tSDP_DISCOVERY_DB* p_db,
- tSDP_DISC_CMPL_CB* p_cb) {
- return false;
-}
-bool SDP_ServiceSearchAttributeRequest2(const RawAddress& p_bd_addr,
- tSDP_DISCOVERY_DB* p_db,
- tSDP_DISC_CMPL_CB2* p_cb2,
- void* user_data) {
- return false;
-}
-
-tSDP_DISC_ATTR* SDP_FindAttributeInRec(tSDP_DISC_REC* p_rec, uint16_t attr_id) {
- return (NULL);
-}
-
-bool SDP_FindServiceUUIDInRec(tSDP_DISC_REC* p_rec, Uuid* p_uuid) {
- return false;
-}
-
-bool SDP_FindServiceUUIDInRec_128bit(tSDP_DISC_REC* p_rec, Uuid* p_uuid) {
- return false;
-}
-
-tSDP_DISC_REC* SDP_FindServiceInDb(tSDP_DISCOVERY_DB* p_db,
- uint16_t service_uuid,
- tSDP_DISC_REC* p_start_rec) {
- return (NULL);
-}
-
-tSDP_DISC_REC* SDP_FindServiceInDb_128bit(tSDP_DISCOVERY_DB* p_db,
- tSDP_DISC_REC* p_start_rec) {
- return (NULL);
-}
-
-tSDP_DISC_REC* SDP_FindServiceUUIDInDb(tSDP_DISCOVERY_DB* p_db,
- const Uuid& uuid,
- tSDP_DISC_REC* p_start_rec) {
- return (NULL);
-}
-
-bool SDP_FindProtocolListElemInRec(tSDP_DISC_REC* p_rec, uint16_t layer_uuid,
- tSDP_PROTOCOL_ELEM* p_elem) {
- return (false);
-}
-
-bool SDP_FindProfileVersionInRec(tSDP_DISC_REC* p_rec, uint16_t profile_uuid,
- uint16_t* p_version) {
- return (false);
-}
-
-uint16_t SDP_DiDiscover(const RawAddress& remote_device,
- tSDP_DISCOVERY_DB* p_db, uint32_t len,
- tSDP_DISC_CMPL_CB* p_cb) {
- return 0;
-}
-
-uint8_t SDP_GetNumDiRecords(tSDP_DISCOVERY_DB* p_db) { return 0; }
-
-uint16_t SDP_GetDiRecord(uint8_t get_record_index,
- tSDP_DI_GET_RECORD* p_device_info,
- tSDP_DISCOVERY_DB* p_db) {
- return 0;
-}
-uint16_t SDP_SetLocalDiRecord(tSDP_DI_RECORD* p_device_info,
- uint32_t* p_handle) {
- return 0;
-}
-uint8_t SDP_SetTraceLevel(uint8_t new_level) { return 0; }
diff --git a/test/mock/mock_stack_sdp_api.cc b/test/mock/mock_stack_sdp_api.cc
new file mode 100644
index 0000000..2d6e7ce
--- /dev/null
+++ b/test/mock/mock_stack_sdp_api.cc
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:18
+ *
+ * mockcify.pl ver 0.2.1
+ */
+
+#include <cstdint>
+#include <functional>
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Mock include file to share data between tests and mock
+#include "test/mock/mock_stack_sdp_api.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+// Mocked internal structures, if any
+
+namespace test {
+namespace mock {
+namespace stack_sdp_api {
+
+// Function state capture and return values, if needed
+struct SDP_CancelServiceSearch SDP_CancelServiceSearch;
+struct SDP_FindProfileVersionInRec SDP_FindProfileVersionInRec;
+struct SDP_FindProtocolListElemInRec SDP_FindProtocolListElemInRec;
+struct SDP_FindServiceUUIDInRec SDP_FindServiceUUIDInRec;
+struct SDP_FindServiceUUIDInRec_128bit SDP_FindServiceUUIDInRec_128bit;
+struct SDP_InitDiscoveryDb SDP_InitDiscoveryDb;
+struct SDP_ServiceSearchAttributeRequest SDP_ServiceSearchAttributeRequest;
+struct SDP_ServiceSearchAttributeRequest2 SDP_ServiceSearchAttributeRequest2;
+struct SDP_ServiceSearchRequest SDP_ServiceSearchRequest;
+struct SDP_FindAttributeInRec SDP_FindAttributeInRec;
+struct SDP_FindServiceInDb SDP_FindServiceInDb;
+struct SDP_FindServiceInDb_128bit SDP_FindServiceInDb_128bit;
+struct SDP_FindServiceUUIDInDb SDP_FindServiceUUIDInDb;
+struct SDP_DiDiscover SDP_DiDiscover;
+struct SDP_GetDiRecord SDP_GetDiRecord;
+struct SDP_SetLocalDiRecord SDP_SetLocalDiRecord;
+struct SDP_GetNumDiRecords SDP_GetNumDiRecords;
+struct SDP_SetTraceLevel SDP_SetTraceLevel;
+
+} // namespace stack_sdp_api
+} // namespace mock
+} // namespace test
+
+// Mocked functions, if any
+bool SDP_CancelServiceSearch(tSDP_DISCOVERY_DB* p_db) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_sdp_api::SDP_CancelServiceSearch(p_db);
+}
+bool SDP_FindProfileVersionInRec(tSDP_DISC_REC* p_rec, uint16_t profile_uuid,
+ uint16_t* p_version) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_sdp_api::SDP_FindProfileVersionInRec(
+ p_rec, profile_uuid, p_version);
+}
+bool SDP_FindProtocolListElemInRec(tSDP_DISC_REC* p_rec, uint16_t layer_uuid,
+ tSDP_PROTOCOL_ELEM* p_elem) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_sdp_api::SDP_FindProtocolListElemInRec(
+ p_rec, layer_uuid, p_elem);
+}
+bool SDP_FindServiceUUIDInRec(tSDP_DISC_REC* p_rec, bluetooth::Uuid* p_uuid) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_sdp_api::SDP_FindServiceUUIDInRec(p_rec, p_uuid);
+}
+bool SDP_FindServiceUUIDInRec_128bit(tSDP_DISC_REC* p_rec,
+ bluetooth::Uuid* p_uuid) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_sdp_api::SDP_FindServiceUUIDInRec_128bit(p_rec,
+ p_uuid);
+}
+bool SDP_InitDiscoveryDb(tSDP_DISCOVERY_DB* p_db, uint32_t len,
+ uint16_t num_uuid, const bluetooth::Uuid* p_uuid_list,
+ uint16_t num_attr, uint16_t* p_attr_list) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_sdp_api::SDP_InitDiscoveryDb(
+ p_db, len, num_uuid, p_uuid_list, num_attr, p_attr_list);
+}
+bool SDP_ServiceSearchAttributeRequest(const RawAddress& p_bd_addr,
+ tSDP_DISCOVERY_DB* p_db,
+ tSDP_DISC_CMPL_CB* p_cb) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_sdp_api::SDP_ServiceSearchAttributeRequest(
+ p_bd_addr, p_db, p_cb);
+}
+bool SDP_ServiceSearchAttributeRequest2(const RawAddress& p_bd_addr,
+ tSDP_DISCOVERY_DB* p_db,
+ tSDP_DISC_CMPL_CB2* p_cb2,
+ void* user_data) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_sdp_api::SDP_ServiceSearchAttributeRequest2(
+ p_bd_addr, p_db, p_cb2, user_data);
+}
+bool SDP_ServiceSearchRequest(const RawAddress& p_bd_addr,
+ tSDP_DISCOVERY_DB* p_db,
+ tSDP_DISC_CMPL_CB* p_cb) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_sdp_api::SDP_ServiceSearchRequest(p_bd_addr, p_db,
+ p_cb);
+}
+tSDP_DISC_ATTR* SDP_FindAttributeInRec(tSDP_DISC_REC* p_rec, uint16_t attr_id) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_sdp_api::SDP_FindAttributeInRec(p_rec, attr_id);
+}
+tSDP_DISC_REC* SDP_FindServiceInDb(tSDP_DISCOVERY_DB* p_db,
+ uint16_t service_uuid,
+ tSDP_DISC_REC* p_start_rec) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_sdp_api::SDP_FindServiceInDb(p_db, service_uuid,
+ p_start_rec);
+}
+tSDP_DISC_REC* SDP_FindServiceInDb_128bit(tSDP_DISCOVERY_DB* p_db,
+ tSDP_DISC_REC* p_start_rec) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_sdp_api::SDP_FindServiceInDb_128bit(p_db,
+ p_start_rec);
+}
+tSDP_DISC_REC* SDP_FindServiceUUIDInDb(tSDP_DISCOVERY_DB* p_db,
+ const bluetooth::Uuid& uuid,
+ tSDP_DISC_REC* p_start_rec) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_sdp_api::SDP_FindServiceUUIDInDb(p_db, uuid,
+ p_start_rec);
+}
+tSDP_STATUS SDP_DiDiscover(const RawAddress& remote_device,
+ tSDP_DISCOVERY_DB* p_db, uint32_t len,
+ tSDP_DISC_CMPL_CB* p_cb) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_sdp_api::SDP_DiDiscover(remote_device, p_db, len,
+ p_cb);
+}
+uint16_t SDP_GetDiRecord(uint8_t get_record_index,
+ tSDP_DI_GET_RECORD* p_device_info,
+ tSDP_DISCOVERY_DB* p_db) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_sdp_api::SDP_GetDiRecord(get_record_index,
+ p_device_info, p_db);
+}
+uint16_t SDP_SetLocalDiRecord(tSDP_DI_RECORD* p_device_info,
+ uint32_t* p_handle) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_sdp_api::SDP_SetLocalDiRecord(p_device_info,
+ p_handle);
+}
+uint8_t SDP_GetNumDiRecords(tSDP_DISCOVERY_DB* p_db) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_sdp_api::SDP_GetNumDiRecords(p_db);
+}
+uint8_t SDP_SetTraceLevel(uint8_t new_level) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_sdp_api::SDP_SetTraceLevel(new_level);
+}
+
+// END mockcify generation
diff --git a/test/mock/mock_stack_sdp_api.h b/test/mock/mock_stack_sdp_api.h
new file mode 100644
index 0000000..5162477
--- /dev/null
+++ b/test/mock/mock_stack_sdp_api.h
@@ -0,0 +1,297 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:18
+ *
+ * mockcify.pl ver 0.2.1
+ */
+
+#include <cstdint>
+#include <functional>
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+#include <string.h>
+
+#include "bt_target.h"
+#include "osi/include/osi.h"
+#include "stack/include/sdp_api.h"
+#include "stack/sdp/sdpint.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+namespace test {
+namespace mock {
+namespace stack_sdp_api {
+
+// Shared state between mocked functions and tests
+// Name: SDP_CancelServiceSearch
+// Params: tSDP_DISCOVERY_DB* p_db
+// Returns: bool
+struct SDP_CancelServiceSearch {
+ std::function<bool(tSDP_DISCOVERY_DB* p_db)> body{
+ [](tSDP_DISCOVERY_DB* p_db) { return false; }};
+ bool operator()(tSDP_DISCOVERY_DB* p_db) { return body(p_db); };
+};
+extern struct SDP_CancelServiceSearch SDP_CancelServiceSearch;
+// Name: SDP_FindProfileVersionInRec
+// Params: tSDP_DISC_REC* p_rec, uint16_t profile_uuid, uint16_t* p_version
+// Returns: bool
+struct SDP_FindProfileVersionInRec {
+ std::function<bool(tSDP_DISC_REC* p_rec, uint16_t profile_uuid,
+ uint16_t* p_version)>
+ body{[](tSDP_DISC_REC* p_rec, uint16_t profile_uuid,
+ uint16_t* p_version) { return false; }};
+ bool operator()(tSDP_DISC_REC* p_rec, uint16_t profile_uuid,
+ uint16_t* p_version) {
+ return body(p_rec, profile_uuid, p_version);
+ };
+};
+extern struct SDP_FindProfileVersionInRec SDP_FindProfileVersionInRec;
+// Name: SDP_FindProtocolListElemInRec
+// Params: tSDP_DISC_REC* p_rec, uint16_t layer_uuid, tSDP_PROTOCOL_ELEM* p_elem
+// Returns: bool
+struct SDP_FindProtocolListElemInRec {
+ std::function<bool(tSDP_DISC_REC* p_rec, uint16_t layer_uuid,
+ tSDP_PROTOCOL_ELEM* p_elem)>
+ body{[](tSDP_DISC_REC* p_rec, uint16_t layer_uuid,
+ tSDP_PROTOCOL_ELEM* p_elem) { return false; }};
+ bool operator()(tSDP_DISC_REC* p_rec, uint16_t layer_uuid,
+ tSDP_PROTOCOL_ELEM* p_elem) {
+ return body(p_rec, layer_uuid, p_elem);
+ };
+};
+extern struct SDP_FindProtocolListElemInRec SDP_FindProtocolListElemInRec;
+// Name: SDP_FindServiceUUIDInRec
+// Params: tSDP_DISC_REC* p_rec, bluetooth::Uuid* p_uuid
+// Returns: bool
+struct SDP_FindServiceUUIDInRec {
+ std::function<bool(tSDP_DISC_REC* p_rec, bluetooth::Uuid* p_uuid)> body{
+ [](tSDP_DISC_REC* p_rec, bluetooth::Uuid* p_uuid) { return false; }};
+ bool operator()(tSDP_DISC_REC* p_rec, bluetooth::Uuid* p_uuid) {
+ return body(p_rec, p_uuid);
+ };
+};
+extern struct SDP_FindServiceUUIDInRec SDP_FindServiceUUIDInRec;
+// Name: SDP_FindServiceUUIDInRec_128bit
+// Params: tSDP_DISC_REC* p_rec, bluetooth::Uuid* p_uuid
+// Returns: bool
+struct SDP_FindServiceUUIDInRec_128bit {
+ std::function<bool(tSDP_DISC_REC* p_rec, bluetooth::Uuid* p_uuid)> body{
+ [](tSDP_DISC_REC* p_rec, bluetooth::Uuid* p_uuid) { return false; }};
+ bool operator()(tSDP_DISC_REC* p_rec, bluetooth::Uuid* p_uuid) {
+ return body(p_rec, p_uuid);
+ };
+};
+extern struct SDP_FindServiceUUIDInRec_128bit SDP_FindServiceUUIDInRec_128bit;
+// Name: SDP_InitDiscoveryDb
+// Params: tSDP_DISCOVERY_DB* p_db, uint32_t len, uint16_t num_uuid, const
+// bluetooth::Uuid* p_uuid_list, uint16_t num_attr, uint16_t* p_attr_list
+// Returns: bool
+struct SDP_InitDiscoveryDb {
+ std::function<bool(tSDP_DISCOVERY_DB* p_db, uint32_t len, uint16_t num_uuid,
+ const bluetooth::Uuid* p_uuid_list, uint16_t num_attr,
+ uint16_t* p_attr_list)>
+ body{[](tSDP_DISCOVERY_DB* p_db, uint32_t len, uint16_t num_uuid,
+ const bluetooth::Uuid* p_uuid_list, uint16_t num_attr,
+ uint16_t* p_attr_list) { return false; }};
+ bool operator()(tSDP_DISCOVERY_DB* p_db, uint32_t len, uint16_t num_uuid,
+ const bluetooth::Uuid* p_uuid_list, uint16_t num_attr,
+ uint16_t* p_attr_list) {
+ return body(p_db, len, num_uuid, p_uuid_list, num_attr, p_attr_list);
+ };
+};
+extern struct SDP_InitDiscoveryDb SDP_InitDiscoveryDb;
+// Name: SDP_ServiceSearchAttributeRequest
+// Params: const RawAddress& p_bd_addr, tSDP_DISCOVERY_DB* p_db,
+// tSDP_DISC_CMPL_CB* p_cb Returns: bool
+struct SDP_ServiceSearchAttributeRequest {
+ std::function<bool(const RawAddress& p_bd_addr, tSDP_DISCOVERY_DB* p_db,
+ tSDP_DISC_CMPL_CB* p_cb)>
+ body{[](const RawAddress& p_bd_addr, tSDP_DISCOVERY_DB* p_db,
+ tSDP_DISC_CMPL_CB* p_cb) { return false; }};
+ bool operator()(const RawAddress& p_bd_addr, tSDP_DISCOVERY_DB* p_db,
+ tSDP_DISC_CMPL_CB* p_cb) {
+ return body(p_bd_addr, p_db, p_cb);
+ };
+};
+extern struct SDP_ServiceSearchAttributeRequest
+ SDP_ServiceSearchAttributeRequest;
+// Name: SDP_ServiceSearchAttributeRequest2
+// Params: const RawAddress& p_bd_addr, tSDP_DISCOVERY_DB* p_db,
+// tSDP_DISC_CMPL_CB2* p_cb2, void* user_data Returns: bool
+struct SDP_ServiceSearchAttributeRequest2 {
+ std::function<bool(const RawAddress& p_bd_addr, tSDP_DISCOVERY_DB* p_db,
+ tSDP_DISC_CMPL_CB2* p_cb2, void* user_data)>
+ body{[](const RawAddress& p_bd_addr, tSDP_DISCOVERY_DB* p_db,
+ tSDP_DISC_CMPL_CB2* p_cb2, void* user_data) { return false; }};
+ bool operator()(const RawAddress& p_bd_addr, tSDP_DISCOVERY_DB* p_db,
+ tSDP_DISC_CMPL_CB2* p_cb2, void* user_data) {
+ return body(p_bd_addr, p_db, p_cb2, user_data);
+ };
+};
+extern struct SDP_ServiceSearchAttributeRequest2
+ SDP_ServiceSearchAttributeRequest2;
+// Name: SDP_ServiceSearchRequest
+// Params: const RawAddress& p_bd_addr, tSDP_DISCOVERY_DB* p_db,
+// tSDP_DISC_CMPL_CB* p_cb Returns: bool
+struct SDP_ServiceSearchRequest {
+ std::function<bool(const RawAddress& p_bd_addr, tSDP_DISCOVERY_DB* p_db,
+ tSDP_DISC_CMPL_CB* p_cb)>
+ body{[](const RawAddress& p_bd_addr, tSDP_DISCOVERY_DB* p_db,
+ tSDP_DISC_CMPL_CB* p_cb) { return false; }};
+ bool operator()(const RawAddress& p_bd_addr, tSDP_DISCOVERY_DB* p_db,
+ tSDP_DISC_CMPL_CB* p_cb) {
+ return body(p_bd_addr, p_db, p_cb);
+ };
+};
+extern struct SDP_ServiceSearchRequest SDP_ServiceSearchRequest;
+// Name: SDP_FindAttributeInRec
+// Params: tSDP_DISC_REC* p_rec, uint16_t attr_id
+// Returns: tSDP_DISC_ATTR*
+struct SDP_FindAttributeInRec {
+ std::function<tSDP_DISC_ATTR*(tSDP_DISC_REC* p_rec, uint16_t attr_id)> body{
+ [](tSDP_DISC_REC* p_rec, uint16_t attr_id) { return nullptr; }};
+ tSDP_DISC_ATTR* operator()(tSDP_DISC_REC* p_rec, uint16_t attr_id) {
+ return body(p_rec, attr_id);
+ };
+};
+extern struct SDP_FindAttributeInRec SDP_FindAttributeInRec;
+// Name: SDP_FindServiceInDb
+// Params: tSDP_DISCOVERY_DB* p_db, uint16_t service_uuid, tSDP_DISC_REC*
+// p_start_rec Returns: tSDP_DISC_REC*
+struct SDP_FindServiceInDb {
+ std::function<tSDP_DISC_REC*(tSDP_DISCOVERY_DB* p_db, uint16_t service_uuid,
+ tSDP_DISC_REC* p_start_rec)>
+ body{[](tSDP_DISCOVERY_DB* p_db, uint16_t service_uuid,
+ tSDP_DISC_REC* p_start_rec) { return nullptr; }};
+ tSDP_DISC_REC* operator()(tSDP_DISCOVERY_DB* p_db, uint16_t service_uuid,
+ tSDP_DISC_REC* p_start_rec) {
+ return body(p_db, service_uuid, p_start_rec);
+ };
+};
+extern struct SDP_FindServiceInDb SDP_FindServiceInDb;
+// Name: SDP_FindServiceInDb_128bit
+// Params: tSDP_DISCOVERY_DB* p_db, tSDP_DISC_REC* p_start_rec
+// Returns: tSDP_DISC_REC*
+struct SDP_FindServiceInDb_128bit {
+ std::function<tSDP_DISC_REC*(tSDP_DISCOVERY_DB* p_db,
+ tSDP_DISC_REC* p_start_rec)>
+ body{[](tSDP_DISCOVERY_DB* p_db, tSDP_DISC_REC* p_start_rec) {
+ return nullptr;
+ }};
+ tSDP_DISC_REC* operator()(tSDP_DISCOVERY_DB* p_db,
+ tSDP_DISC_REC* p_start_rec) {
+ return body(p_db, p_start_rec);
+ };
+};
+extern struct SDP_FindServiceInDb_128bit SDP_FindServiceInDb_128bit;
+// Name: SDP_FindServiceUUIDInDb
+// Params: tSDP_DISCOVERY_DB* p_db, const bluetooth::Uuid& uuid, tSDP_DISC_REC*
+// p_start_rec Returns: tSDP_DISC_REC*
+struct SDP_FindServiceUUIDInDb {
+ std::function<tSDP_DISC_REC*(tSDP_DISCOVERY_DB* p_db,
+ const bluetooth::Uuid& uuid,
+ tSDP_DISC_REC* p_start_rec)>
+ body{[](tSDP_DISCOVERY_DB* p_db, const bluetooth::Uuid& uuid,
+ tSDP_DISC_REC* p_start_rec) { return nullptr; }};
+ tSDP_DISC_REC* operator()(tSDP_DISCOVERY_DB* p_db,
+ const bluetooth::Uuid& uuid,
+ tSDP_DISC_REC* p_start_rec) {
+ return body(p_db, uuid, p_start_rec);
+ };
+};
+extern struct SDP_FindServiceUUIDInDb SDP_FindServiceUUIDInDb;
+// Name: SDP_DiDiscover
+// Params: const RawAddress& remote_device, tSDP_DISCOVERY_DB* p_db, uint32_t
+// len, tSDP_DISC_CMPL_CB* p_cb Returns: tSDP_STATUS
+struct SDP_DiDiscover {
+ std::function<tSDP_STATUS(const RawAddress& remote_device,
+ tSDP_DISCOVERY_DB* p_db, uint32_t len,
+ tSDP_DISC_CMPL_CB* p_cb)>
+ body{[](const RawAddress& remote_device, tSDP_DISCOVERY_DB* p_db,
+ uint32_t len, tSDP_DISC_CMPL_CB* p_cb) { return SDP_SUCCESS; }};
+ tSDP_STATUS operator()(const RawAddress& remote_device,
+ tSDP_DISCOVERY_DB* p_db, uint32_t len,
+ tSDP_DISC_CMPL_CB* p_cb) {
+ return body(remote_device, p_db, len, p_cb);
+ };
+};
+extern struct SDP_DiDiscover SDP_DiDiscover;
+// Name: SDP_GetDiRecord
+// Params: uint8_t get_record_index, tSDP_DI_GET_RECORD* p_device_info,
+// tSDP_DISCOVERY_DB* p_db Returns: uint16_t
+struct SDP_GetDiRecord {
+ std::function<uint16_t(uint8_t get_record_index,
+ tSDP_DI_GET_RECORD* p_device_info,
+ tSDP_DISCOVERY_DB* p_db)>
+ body{[](uint8_t get_record_index, tSDP_DI_GET_RECORD* p_device_info,
+ tSDP_DISCOVERY_DB* p_db) { return 0; }};
+ uint16_t operator()(uint8_t get_record_index,
+ tSDP_DI_GET_RECORD* p_device_info,
+ tSDP_DISCOVERY_DB* p_db) {
+ return body(get_record_index, p_device_info, p_db);
+ };
+};
+extern struct SDP_GetDiRecord SDP_GetDiRecord;
+// Name: SDP_SetLocalDiRecord
+// Params: tSDP_DI_RECORD* p_device_info, uint32_t* p_handle
+// Returns: uint16_t
+struct SDP_SetLocalDiRecord {
+ std::function<uint16_t(tSDP_DI_RECORD* p_device_info, uint32_t* p_handle)>
+ body{[](tSDP_DI_RECORD* p_device_info, uint32_t* p_handle) { return 0; }};
+ uint16_t operator()(tSDP_DI_RECORD* p_device_info, uint32_t* p_handle) {
+ return body(p_device_info, p_handle);
+ };
+};
+extern struct SDP_SetLocalDiRecord SDP_SetLocalDiRecord;
+// Name: SDP_GetNumDiRecords
+// Params: tSDP_DISCOVERY_DB* p_db
+// Returns: uint8_t
+struct SDP_GetNumDiRecords {
+ std::function<uint8_t(tSDP_DISCOVERY_DB* p_db)> body{
+ [](tSDP_DISCOVERY_DB* p_db) { return 0; }};
+ uint8_t operator()(tSDP_DISCOVERY_DB* p_db) { return body(p_db); };
+};
+extern struct SDP_GetNumDiRecords SDP_GetNumDiRecords;
+// Name: SDP_SetTraceLevel
+// Params: uint8_t new_level
+// Returns: uint8_t
+struct SDP_SetTraceLevel {
+ std::function<uint8_t(uint8_t new_level)> body{
+ [](uint8_t new_level) { return 0; }};
+ uint8_t operator()(uint8_t new_level) { return body(new_level); };
+};
+extern struct SDP_SetTraceLevel SDP_SetTraceLevel;
+
+} // namespace stack_sdp_api
+} // namespace mock
+} // namespace test
+
+// END mockcify generation
diff --git a/test/mock/mock_stack_smp_act.cc b/test/mock/mock_stack_smp_act.cc
new file mode 100644
index 0000000..a7a25fb
--- /dev/null
+++ b/test/mock/mock_stack_smp_act.cc
@@ -0,0 +1,430 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:71
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <cstdint>
+#include <functional>
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+
+// Mock include file to share data between tests and mock
+#include "test/mock/mock_stack_smp_act.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+// Mocked internal structures, if any
+
+namespace test {
+namespace mock {
+namespace stack_smp_act {
+
+// Function state capture and return values, if needed
+struct smp_send_app_cback smp_send_app_cback;
+struct smp_send_pair_fail smp_send_pair_fail;
+struct smp_send_pair_req smp_send_pair_req;
+struct smp_send_pair_rsp smp_send_pair_rsp;
+struct smp_send_confirm smp_send_confirm;
+struct smp_send_init smp_send_init;
+struct smp_send_rand smp_send_rand;
+struct smp_send_pair_public_key smp_send_pair_public_key;
+struct smp_send_commitment smp_send_commitment;
+struct smp_send_dhkey_check smp_send_dhkey_check;
+struct smp_send_keypress_notification smp_send_keypress_notification;
+struct smp_send_enc_info smp_send_enc_info;
+struct smp_send_id_info smp_send_id_info;
+struct smp_send_csrk_info smp_send_csrk_info;
+struct smp_send_ltk_reply smp_send_ltk_reply;
+struct smp_proc_sec_req smp_proc_sec_req;
+struct smp_proc_sec_grant smp_proc_sec_grant;
+struct smp_proc_pair_fail smp_proc_pair_fail;
+struct smp_proc_pair_cmd smp_proc_pair_cmd;
+struct smp_proc_confirm smp_proc_confirm;
+struct smp_proc_init smp_proc_init;
+struct smp_proc_rand smp_proc_rand;
+struct smp_process_pairing_public_key smp_process_pairing_public_key;
+struct smp_process_pairing_commitment smp_process_pairing_commitment;
+struct smp_process_dhkey_check smp_process_dhkey_check;
+struct smp_process_keypress_notification smp_process_keypress_notification;
+struct smp_br_process_pairing_command smp_br_process_pairing_command;
+struct smp_br_process_security_grant smp_br_process_security_grant;
+struct smp_br_check_authorization_request smp_br_check_authorization_request;
+struct smp_br_select_next_key smp_br_select_next_key;
+struct smp_proc_enc_info smp_proc_enc_info;
+struct smp_proc_central_id smp_proc_central_id;
+struct smp_proc_id_info smp_proc_id_info;
+struct smp_proc_id_addr smp_proc_id_addr;
+struct smp_proc_srk_info smp_proc_srk_info;
+struct smp_proc_compare smp_proc_compare;
+struct smp_proc_sl_key smp_proc_sl_key;
+struct smp_start_enc smp_start_enc;
+struct smp_proc_discard smp_proc_discard;
+struct smp_enc_cmpl smp_enc_cmpl;
+struct smp_check_auth_req smp_check_auth_req;
+struct smp_key_pick_key smp_key_pick_key;
+struct smp_key_distribution smp_key_distribution;
+struct smp_decide_association_model smp_decide_association_model;
+struct smp_process_io_response smp_process_io_response;
+struct smp_br_process_peripheral_keys_response
+ smp_br_process_peripheral_keys_response;
+struct smp_br_send_pair_response smp_br_send_pair_response;
+struct smp_pairing_cmpl smp_pairing_cmpl;
+struct smp_pair_terminate smp_pair_terminate;
+struct smp_idle_terminate smp_idle_terminate;
+struct smp_both_have_public_keys smp_both_have_public_keys;
+struct smp_start_secure_connection_phase1 smp_start_secure_connection_phase1;
+struct smp_process_local_nonce smp_process_local_nonce;
+struct smp_process_peer_nonce smp_process_peer_nonce;
+struct smp_match_dhkey_checks smp_match_dhkey_checks;
+struct smp_move_to_secure_connections_phase2
+ smp_move_to_secure_connections_phase2;
+struct smp_phase_2_dhkey_checks_are_present
+ smp_phase_2_dhkey_checks_are_present;
+struct smp_wait_for_both_public_keys smp_wait_for_both_public_keys;
+struct smp_start_passkey_verification smp_start_passkey_verification;
+struct smp_process_secure_connection_oob_data
+ smp_process_secure_connection_oob_data;
+struct smp_set_local_oob_keys smp_set_local_oob_keys;
+struct smp_set_local_oob_random_commitment smp_set_local_oob_random_commitment;
+struct smp_link_encrypted smp_link_encrypted;
+struct smp_cancel_start_encryption_attempt smp_cancel_start_encryption_attempt;
+struct smp_proc_ltk_request smp_proc_ltk_request;
+struct smp_process_secure_connection_long_term_key
+ smp_process_secure_connection_long_term_key;
+struct smp_set_derive_link_key smp_set_derive_link_key;
+struct smp_derive_link_key_from_long_term_key
+ smp_derive_link_key_from_long_term_key;
+struct smp_br_process_link_key smp_br_process_link_key;
+struct smp_key_distribution_by_transport smp_key_distribution_by_transport;
+struct smp_br_pairing_complete smp_br_pairing_complete;
+
+} // namespace stack_smp_act
+} // namespace mock
+} // namespace test
+
+// Mocked functions, if any
+void smp_send_app_cback(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_send_app_cback(p_cb, p_data);
+}
+void smp_send_pair_fail(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_send_pair_fail(p_cb, p_data);
+}
+void smp_send_pair_req(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_send_pair_req(p_cb, p_data);
+}
+void smp_send_pair_rsp(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_send_pair_rsp(p_cb, p_data);
+}
+void smp_send_confirm(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_send_confirm(p_cb, p_data);
+}
+void smp_send_init(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_send_init(p_cb, p_data);
+}
+void smp_send_rand(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_send_rand(p_cb, p_data);
+}
+void smp_send_pair_public_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_send_pair_public_key(p_cb, p_data);
+}
+void smp_send_commitment(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_send_commitment(p_cb, p_data);
+}
+void smp_send_dhkey_check(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_send_dhkey_check(p_cb, p_data);
+}
+void smp_send_keypress_notification(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_send_keypress_notification(p_cb, p_data);
+}
+void smp_send_enc_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_send_enc_info(p_cb, p_data);
+}
+void smp_send_id_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_send_id_info(p_cb, p_data);
+}
+void smp_send_csrk_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_send_csrk_info(p_cb, p_data);
+}
+void smp_send_ltk_reply(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_send_ltk_reply(p_cb, p_data);
+}
+void smp_proc_sec_req(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_proc_sec_req(p_cb, p_data);
+}
+void smp_proc_sec_grant(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_proc_sec_grant(p_cb, p_data);
+}
+void smp_proc_pair_fail(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_proc_pair_fail(p_cb, p_data);
+}
+void smp_proc_pair_cmd(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_proc_pair_cmd(p_cb, p_data);
+}
+void smp_proc_confirm(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_proc_confirm(p_cb, p_data);
+}
+void smp_proc_init(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_proc_init(p_cb, p_data);
+}
+void smp_proc_rand(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_proc_rand(p_cb, p_data);
+}
+void smp_process_pairing_public_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_process_pairing_public_key(p_cb, p_data);
+}
+void smp_process_pairing_commitment(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_process_pairing_commitment(p_cb, p_data);
+}
+void smp_process_dhkey_check(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_process_dhkey_check(p_cb, p_data);
+}
+void smp_process_keypress_notification(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_process_keypress_notification(p_cb, p_data);
+}
+void smp_br_process_pairing_command(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_br_process_pairing_command(p_cb, p_data);
+}
+void smp_br_process_security_grant(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_br_process_security_grant(p_cb, p_data);
+}
+void smp_br_check_authorization_request(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_br_check_authorization_request(p_cb, p_data);
+}
+void smp_br_select_next_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_br_select_next_key(p_cb, p_data);
+}
+void smp_proc_enc_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_proc_enc_info(p_cb, p_data);
+}
+void smp_proc_central_id(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_proc_central_id(p_cb, p_data);
+}
+void smp_proc_id_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_proc_id_info(p_cb, p_data);
+}
+void smp_proc_id_addr(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_proc_id_addr(p_cb, p_data);
+}
+void smp_proc_srk_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_proc_srk_info(p_cb, p_data);
+}
+void smp_proc_compare(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_proc_compare(p_cb, p_data);
+}
+void smp_proc_sl_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_proc_sl_key(p_cb, p_data);
+}
+void smp_start_enc(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_start_enc(p_cb, p_data);
+}
+void smp_proc_discard(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_proc_discard(p_cb, p_data);
+}
+void smp_enc_cmpl(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_enc_cmpl(p_cb, p_data);
+}
+void smp_check_auth_req(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_check_auth_req(p_cb, p_data);
+}
+void smp_key_pick_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_key_pick_key(p_cb, p_data);
+}
+void smp_key_distribution(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_key_distribution(p_cb, p_data);
+}
+void smp_decide_association_model(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_decide_association_model(p_cb, p_data);
+}
+void smp_process_io_response(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_process_io_response(p_cb, p_data);
+}
+void smp_br_process_peripheral_keys_response(tSMP_CB* p_cb,
+ tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_br_process_peripheral_keys_response(p_cb,
+ p_data);
+}
+void smp_br_send_pair_response(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_br_send_pair_response(p_cb, p_data);
+}
+void smp_pairing_cmpl(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_pairing_cmpl(p_cb, p_data);
+}
+void smp_pair_terminate(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_pair_terminate(p_cb, p_data);
+}
+void smp_idle_terminate(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_idle_terminate(p_cb, p_data);
+}
+void smp_both_have_public_keys(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_both_have_public_keys(p_cb, p_data);
+}
+void smp_start_secure_connection_phase1(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_start_secure_connection_phase1(p_cb, p_data);
+}
+void smp_process_local_nonce(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_process_local_nonce(p_cb, p_data);
+}
+void smp_process_peer_nonce(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_process_peer_nonce(p_cb, p_data);
+}
+void smp_match_dhkey_checks(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_match_dhkey_checks(p_cb, p_data);
+}
+void smp_move_to_secure_connections_phase2(tSMP_CB* p_cb,
+ tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_move_to_secure_connections_phase2(p_cb,
+ p_data);
+}
+void smp_phase_2_dhkey_checks_are_present(tSMP_CB* p_cb,
+ tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_phase_2_dhkey_checks_are_present(p_cb, p_data);
+}
+void smp_wait_for_both_public_keys(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_wait_for_both_public_keys(p_cb, p_data);
+}
+void smp_start_passkey_verification(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_start_passkey_verification(p_cb, p_data);
+}
+void smp_process_secure_connection_oob_data(tSMP_CB* p_cb,
+ tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_process_secure_connection_oob_data(p_cb,
+ p_data);
+}
+void smp_set_local_oob_keys(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_set_local_oob_keys(p_cb, p_data);
+}
+void smp_set_local_oob_random_commitment(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_set_local_oob_random_commitment(p_cb, p_data);
+}
+void smp_link_encrypted(const RawAddress& bda, uint8_t encr_enable) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_link_encrypted(bda, encr_enable);
+}
+void smp_cancel_start_encryption_attempt() {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_cancel_start_encryption_attempt();
+}
+bool smp_proc_ltk_request(const RawAddress& bda) {
+ mock_function_count_map[__func__]++;
+ return test::mock::stack_smp_act::smp_proc_ltk_request(bda);
+}
+void smp_process_secure_connection_long_term_key(void) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_process_secure_connection_long_term_key();
+}
+void smp_set_derive_link_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_set_derive_link_key(p_cb, p_data);
+}
+void smp_derive_link_key_from_long_term_key(tSMP_CB* p_cb,
+ tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_derive_link_key_from_long_term_key(p_cb,
+ p_data);
+}
+void smp_br_process_link_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_br_process_link_key(p_cb, p_data);
+}
+void smp_key_distribution_by_transport(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_key_distribution_by_transport(p_cb, p_data);
+}
+void smp_br_pairing_complete(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ mock_function_count_map[__func__]++;
+ test::mock::stack_smp_act::smp_br_pairing_complete(p_cb, p_data);
+}
+
+// END mockcify generation
diff --git a/test/mock/mock_stack_smp_act.h b/test/mock/mock_stack_smp_act.h
new file mode 100644
index 0000000..2265902
--- /dev/null
+++ b/test/mock/mock_stack_smp_act.h
@@ -0,0 +1,707 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:71
+ *
+ * mockcify.pl ver 0.2
+ */
+
+#include <cstdint>
+#include <functional>
+#include <map>
+#include <string>
+
+extern std::map<std::string, int> mock_function_count_map;
+
+// Original included files, if any
+// NOTE: Since this is a mock file with mock definitions some number of
+// include files may not be required. The include-what-you-use
+// still applies, but crafting proper inclusion is out of scope
+// for this effort. This compilation unit may compile as-is, or
+// may need attention to prune the inclusion set.
+#include "btif/include/btif_api.h"
+#include "stack/smp/smp_int.h"
+#include "types/raw_address.h"
+
+// Mocked compile conditionals, if any
+#ifndef UNUSED_ATTR
+#define UNUSED_ATTR
+#endif
+
+namespace test {
+namespace mock {
+namespace stack_smp_act {
+
+// Shared state between mocked functions and tests
+// Name: smp_send_app_cback
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_send_app_cback {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_send_app_cback smp_send_app_cback;
+// Name: smp_send_pair_fail
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_send_pair_fail {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_send_pair_fail smp_send_pair_fail;
+// Name: smp_send_pair_req
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_send_pair_req {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_send_pair_req smp_send_pair_req;
+// Name: smp_send_pair_rsp
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_send_pair_rsp {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_send_pair_rsp smp_send_pair_rsp;
+// Name: smp_send_confirm
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_send_confirm {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_send_confirm smp_send_confirm;
+// Name: smp_send_init
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_send_init {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_send_init smp_send_init;
+// Name: smp_send_rand
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_send_rand {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_send_rand smp_send_rand;
+// Name: smp_send_pair_public_key
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_send_pair_public_key {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_send_pair_public_key smp_send_pair_public_key;
+// Name: smp_send_commitment
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_send_commitment {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_send_commitment smp_send_commitment;
+// Name: smp_send_dhkey_check
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_send_dhkey_check {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_send_dhkey_check smp_send_dhkey_check;
+// Name: smp_send_keypress_notification
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_send_keypress_notification {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_send_keypress_notification smp_send_keypress_notification;
+// Name: smp_send_enc_info
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_send_enc_info {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_send_enc_info smp_send_enc_info;
+// Name: smp_send_id_info
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_send_id_info {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_send_id_info smp_send_id_info;
+// Name: smp_send_csrk_info
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_send_csrk_info {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_send_csrk_info smp_send_csrk_info;
+// Name: smp_send_ltk_reply
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_send_ltk_reply {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_send_ltk_reply smp_send_ltk_reply;
+// Name: smp_proc_sec_req
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_proc_sec_req {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_proc_sec_req smp_proc_sec_req;
+// Name: smp_proc_sec_grant
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_proc_sec_grant {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_proc_sec_grant smp_proc_sec_grant;
+// Name: smp_proc_pair_fail
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_proc_pair_fail {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_proc_pair_fail smp_proc_pair_fail;
+// Name: smp_proc_pair_cmd
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_proc_pair_cmd {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_proc_pair_cmd smp_proc_pair_cmd;
+// Name: smp_proc_confirm
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_proc_confirm {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_proc_confirm smp_proc_confirm;
+// Name: smp_proc_init
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_proc_init {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_proc_init smp_proc_init;
+// Name: smp_proc_rand
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_proc_rand {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_proc_rand smp_proc_rand;
+// Name: smp_process_pairing_public_key
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_process_pairing_public_key {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_process_pairing_public_key smp_process_pairing_public_key;
+// Name: smp_process_pairing_commitment
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_process_pairing_commitment {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_process_pairing_commitment smp_process_pairing_commitment;
+// Name: smp_process_dhkey_check
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_process_dhkey_check {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_process_dhkey_check smp_process_dhkey_check;
+// Name: smp_process_keypress_notification
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_process_keypress_notification {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_process_keypress_notification
+ smp_process_keypress_notification;
+// Name: smp_br_process_pairing_command
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_br_process_pairing_command {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_br_process_pairing_command smp_br_process_pairing_command;
+// Name: smp_br_process_security_grant
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_br_process_security_grant {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_br_process_security_grant smp_br_process_security_grant;
+// Name: smp_br_check_authorization_request
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_br_check_authorization_request {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_br_check_authorization_request
+ smp_br_check_authorization_request;
+// Name: smp_br_select_next_key
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_br_select_next_key {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_br_select_next_key smp_br_select_next_key;
+// Name: smp_proc_enc_info
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_proc_enc_info {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_proc_enc_info smp_proc_enc_info;
+// Name: smp_proc_central_id
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_proc_central_id {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_proc_central_id smp_proc_central_id;
+// Name: smp_proc_id_info
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_proc_id_info {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_proc_id_info smp_proc_id_info;
+// Name: smp_proc_id_addr
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_proc_id_addr {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_proc_id_addr smp_proc_id_addr;
+// Name: smp_proc_srk_info
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_proc_srk_info {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_proc_srk_info smp_proc_srk_info;
+// Name: smp_proc_compare
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_proc_compare {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_proc_compare smp_proc_compare;
+// Name: smp_proc_sl_key
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_proc_sl_key {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_proc_sl_key smp_proc_sl_key;
+// Name: smp_start_enc
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_start_enc {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_start_enc smp_start_enc;
+// Name: smp_proc_discard
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_proc_discard {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_proc_discard smp_proc_discard;
+// Name: smp_enc_cmpl
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_enc_cmpl {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_enc_cmpl smp_enc_cmpl;
+// Name: smp_check_auth_req
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_check_auth_req {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_check_auth_req smp_check_auth_req;
+// Name: smp_key_pick_key
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_key_pick_key {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_key_pick_key smp_key_pick_key;
+// Name: smp_key_distribution
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_key_distribution {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_key_distribution smp_key_distribution;
+// Name: smp_decide_association_model
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_decide_association_model {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_decide_association_model smp_decide_association_model;
+// Name: smp_process_io_response
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_process_io_response {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_process_io_response smp_process_io_response;
+// Name: smp_br_process_peripheral_keys_response
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_br_process_peripheral_keys_response {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_br_process_peripheral_keys_response
+ smp_br_process_peripheral_keys_response;
+// Name: smp_br_send_pair_response
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_br_send_pair_response {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_br_send_pair_response smp_br_send_pair_response;
+// Name: smp_pairing_cmpl
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_pairing_cmpl {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_pairing_cmpl smp_pairing_cmpl;
+// Name: smp_pair_terminate
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_pair_terminate {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_pair_terminate smp_pair_terminate;
+// Name: smp_idle_terminate
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_idle_terminate {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_idle_terminate smp_idle_terminate;
+// Name: smp_both_have_public_keys
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_both_have_public_keys {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_both_have_public_keys smp_both_have_public_keys;
+// Name: smp_start_secure_connection_phase1
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_start_secure_connection_phase1 {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_start_secure_connection_phase1
+ smp_start_secure_connection_phase1;
+// Name: smp_process_local_nonce
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_process_local_nonce {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_process_local_nonce smp_process_local_nonce;
+// Name: smp_process_peer_nonce
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_process_peer_nonce {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_process_peer_nonce smp_process_peer_nonce;
+// Name: smp_match_dhkey_checks
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_match_dhkey_checks {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_match_dhkey_checks smp_match_dhkey_checks;
+// Name: smp_move_to_secure_connections_phase2
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_move_to_secure_connections_phase2 {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_move_to_secure_connections_phase2
+ smp_move_to_secure_connections_phase2;
+// Name: smp_phase_2_dhkey_checks_are_present
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_phase_2_dhkey_checks_are_present {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_phase_2_dhkey_checks_are_present
+ smp_phase_2_dhkey_checks_are_present;
+// Name: smp_wait_for_both_public_keys
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_wait_for_both_public_keys {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_wait_for_both_public_keys smp_wait_for_both_public_keys;
+// Name: smp_start_passkey_verification
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_start_passkey_verification {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_start_passkey_verification smp_start_passkey_verification;
+// Name: smp_process_secure_connection_oob_data
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_process_secure_connection_oob_data {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_process_secure_connection_oob_data
+ smp_process_secure_connection_oob_data;
+// Name: smp_set_local_oob_keys
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_set_local_oob_keys {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_set_local_oob_keys smp_set_local_oob_keys;
+// Name: smp_set_local_oob_random_commitment
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_set_local_oob_random_commitment {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_set_local_oob_random_commitment
+ smp_set_local_oob_random_commitment;
+// Name: smp_link_encrypted
+// Params: const RawAddress& bda, uint8_t encr_enable
+// Returns: void
+struct smp_link_encrypted {
+ std::function<void(const RawAddress& bda, uint8_t encr_enable)> body{
+ [](const RawAddress& bda, uint8_t encr_enable) {}};
+ void operator()(const RawAddress& bda, uint8_t encr_enable) {
+ body(bda, encr_enable);
+ };
+};
+extern struct smp_link_encrypted smp_link_encrypted;
+// Name: smp_cancel_start_encryption_attempt
+// Params:
+// Returns: void
+struct smp_cancel_start_encryption_attempt {
+ std::function<void()> body{[]() {}};
+ void operator()() { body(); };
+};
+extern struct smp_cancel_start_encryption_attempt
+ smp_cancel_start_encryption_attempt;
+// Name: smp_proc_ltk_request
+// Params: const RawAddress& bda
+// Returns: bool
+struct smp_proc_ltk_request {
+ std::function<bool(const RawAddress& bda)> body{
+ [](const RawAddress& bda) { return false; }};
+ bool operator()(const RawAddress& bda) { return body(bda); };
+};
+extern struct smp_proc_ltk_request smp_proc_ltk_request;
+// Name: smp_process_secure_connection_long_term_key
+// Params: void
+// Returns: void
+struct smp_process_secure_connection_long_term_key {
+ std::function<void(void)> body{[](void) {}};
+ void operator()(void) { body(); };
+};
+extern struct smp_process_secure_connection_long_term_key
+ smp_process_secure_connection_long_term_key;
+// Name: smp_set_derive_link_key
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_set_derive_link_key {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_set_derive_link_key smp_set_derive_link_key;
+// Name: smp_derive_link_key_from_long_term_key
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_derive_link_key_from_long_term_key {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_derive_link_key_from_long_term_key
+ smp_derive_link_key_from_long_term_key;
+// Name: smp_br_process_link_key
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_br_process_link_key {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_br_process_link_key smp_br_process_link_key;
+// Name: smp_key_distribution_by_transport
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_key_distribution_by_transport {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_key_distribution_by_transport
+ smp_key_distribution_by_transport;
+// Name: smp_br_pairing_complete
+// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data
+// Returns: void
+struct smp_br_pairing_complete {
+ std::function<void(tSMP_CB* p_cb, tSMP_INT_DATA* p_data)> body{
+ [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}};
+ void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); };
+};
+extern struct smp_br_pairing_complete smp_br_pairing_complete;
+
+} // namespace stack_smp_act
+} // namespace mock
+} // namespace test
+
+// END mockcify generation
diff --git a/test/mock/mock_stack_smp_api.cc b/test/mock/mock_stack_smp_api.cc
index 58cf1de..ae48e42 100644
--- a/test/mock/mock_stack_smp_api.cc
+++ b/test/mock/mock_stack_smp_api.cc
@@ -78,3 +78,11 @@
void SMP_SecurityGrant(const RawAddress& bd_addr, tSMP_STATUS res) {
mock_function_count_map[__func__]++;
}
+
+void SMP_CrLocScOobData(
+ base::OnceCallback<void(tBT_TRANSPORT, bool,
+ const std::array<unsigned char, 16>&,
+ const std::array<unsigned char, 16>&)>
+ callback) {
+ mock_function_count_map[__func__]++;
+}
diff --git a/bta/test/common/mock_stack_srvc_dis.cc b/test/mock/mock_stack_srvc_dis.cc
similarity index 100%
rename from bta/test/common/mock_stack_srvc_dis.cc
rename to test/mock/mock_stack_srvc_dis.cc
diff --git a/test/stub/legacy_trace.cc b/test/stub/legacy_trace.cc
new file mode 100644
index 0000000..2b4e3dc
--- /dev/null
+++ b/test/stub/legacy_trace.cc
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <cstdint>
+
+// tLEGACY_TRACE_LEVEL
+uint8_t btu_trace_level = 6;
+uint8_t appl_trace_level = 6;
+uint8_t btif_trace_level = 6;
+
+uint8_t A2DP_SetTraceLevel(uint8_t new_level) { return 0; }
+uint8_t AVDT_SetTraceLevel(uint8_t new_level) { return 0; }
+uint8_t AVRC_SetTraceLevel(uint8_t new_level) { return 0; }
+uint8_t BNEP_SetTraceLevel(uint8_t new_level) { return 0; }
+uint8_t BTM_SetTraceLevel(uint8_t new_level) { return 0; }
+uint8_t PAN_SetTraceLevel(uint8_t new_level) { return 0; }
+uint8_t PORT_SetTraceLevel(uint8_t new_level) { return 0; }
+uint8_t SMP_SetTraceLevel(uint8_t new_level) { return 0; }
diff --git a/bta/test/common/fake_osi.cc b/test/stub/osi.cc
similarity index 100%
rename from bta/test/common/fake_osi.cc
rename to test/stub/osi.cc
diff --git a/test/suite/Android.bp b/test/suite/Android.bp
index 25b6e38..18050bc 100644
--- a/test/suite/Android.bp
+++ b/test/suite/Android.bp
@@ -1,5 +1,4 @@
// Bluetooth test suite for target
-// ========================================================
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
@@ -37,7 +36,6 @@
}
// Bluetooth test suite for target
-// ========================================================
cc_test {
name: "net_test_rfcomm_suite",
defaults: ["fluoride_defaults"],
diff --git a/tools/bdtool/Android.mk.disabled b/tools/bdtool/Android.mk.disabled
index 4c8321e..76b8dce 100644
--- a/tools/bdtool/Android.mk.disabled
+++ b/tools/bdtool/Android.mk.disabled
@@ -17,7 +17,6 @@
LOCAL_PATH := $(call my-dir)
# Bluetooth tools for target
-# ========================================================
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
diff --git a/tools/hci/Android.mk.disabled b/tools/hci/Android.mk.disabled
index 6439dfc..9244f45 100644
--- a/tools/hci/Android.mk.disabled
+++ b/tools/hci/Android.mk.disabled
@@ -17,7 +17,6 @@
LOCAL_PATH := $(call my-dir)
# Bluetooth HCI tools for target
-# ========================================================
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
diff --git a/types/Android.bp b/types/Android.bp
index a1fea28..2a6e0dd 100644
--- a/types/Android.bp
+++ b/types/Android.bp
@@ -43,7 +43,6 @@
export_header_lib_headers: ["libbluetooth-types-header"],
}
-// ========================================================
cc_test {
name: "net_test_types",
test_suites: ["device-tests"],
diff --git a/types/BUILD.gn b/types/BUILD.gn
index 47604a9..08a47b6 100644
--- a/types/BUILD.gn
+++ b/types/BUILD.gn
@@ -54,6 +54,13 @@
"z",
]
+ # For some reason, this is required for host build. Otherwise, I get
+ # a complaint from gmock:
+ # undefined reference to symbol 'pthread_getspecific@@GLIBC_2.2.5'
+ ldflags = [
+ "-lpthread"
+ ]
+
deps = [
":types",
]
diff --git a/types/bt_transport.h b/types/bt_transport.h
index b4a32a2..79b3411 100644
--- a/types/bt_transport.h
+++ b/types/bt_transport.h
@@ -26,7 +26,7 @@
#define BT_TRANSPORT_LE 2
typedef uint8_t tBT_TRANSPORT;
-inline std::string BtTransportText(tBT_TRANSPORT transport) {
+inline std::string bt_transport_text(tBT_TRANSPORT transport) {
switch (transport) {
case BT_TRANSPORT_BR_EDR:
return std::string("br_edr");
diff --git a/utils/Android.bp b/utils/Android.bp
index befc5cf..725335f 100644
--- a/utils/Android.bp
+++ b/utils/Android.bp
@@ -1,5 +1,4 @@
// Utils static library for target
-// ========================================================
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
diff --git a/vendor_libs/test_vendor_lib/Android.bp b/vendor_libs/test_vendor_lib/Android.bp
index 160dca8..e45b6ea 100644
--- a/vendor_libs/test_vendor_lib/Android.bp
+++ b/vendor_libs/test_vendor_lib/Android.bp
@@ -1,5 +1,4 @@
// simulation library for testing virtual devices
-// ========================================================
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
@@ -94,7 +93,6 @@
}
// test-vendor unit tests for host
-// ========================================================
cc_test_host {
name: "test-vendor_test_host",
defaults: [
@@ -130,7 +128,6 @@
}
// Linux RootCanal Executable
-// ========================================================
cc_binary_host {
name: "root-canal",
defaults: [
diff --git a/vendor_libs/test_vendor_lib/desktop/test_environment.cc b/vendor_libs/test_vendor_lib/desktop/test_environment.cc
index a2888b0..dadb786 100644
--- a/vendor_libs/test_vendor_lib/desktop/test_environment.cc
+++ b/vendor_libs/test_vendor_lib/desktop/test_environment.cc
@@ -33,7 +33,7 @@
using test_vendor_lib::TaskCallback;
void TestEnvironment::initialize(std::promise<void> barrier) {
- LOG_INFO("%s", __func__);
+ LOG_INFO();
barrier_ = std::move(barrier);
@@ -41,13 +41,16 @@
test_channel_transport_.RegisterCommandHandler(
[this, user_id](const std::string& name,
const std::vector<std::string>& args) {
- async_manager_.ExecAsync(
- user_id, std::chrono::milliseconds(0),
- [this, name, args]() { test_channel_.HandleCommand(name, args); });
+ async_manager_.ExecAsync(user_id, std::chrono::milliseconds(0),
+ [this, name, args]() {
+ if (name == "END_SIMULATION") {
+ barrier_.set_value();
+ } else {
+ 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); });
@@ -175,13 +178,22 @@
return;
}
LOG_INFO("Test channel connection accepted.");
+ if (test_channel_open_) {
+ LOG_WARN("Only one connection at a time is supported");
+ async_manager_.StopWatchingFileDescriptor(conn_fd);
+ test_channel_transport_.SendResponse(conn_fd, "The connection is broken");
+ return;
+ }
+ test_channel_open_ = true;
test_channel_.RegisterSendResponse(
- [this, conn_fd](const std::string& response) { test_channel_transport_.SendResponse(conn_fd, response); });
+ [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();
+ test_channel_open_ = false;
});
});
});
diff --git a/vendor_libs/test_vendor_lib/desktop/test_environment.h b/vendor_libs/test_vendor_lib/desktop/test_environment.h
index ff18b42..815721e 100644
--- a/vendor_libs/test_vendor_lib/desktop/test_environment.h
+++ b/vendor_libs/test_vendor_lib/desktop/test_environment.h
@@ -50,6 +50,7 @@
uint16_t hci_server_port_;
uint16_t link_server_port_;
std::string default_commands_file_;
+ bool test_channel_open_{false};
std::promise<void> barrier_;
test_vendor_lib::AsyncManager async_manager_;
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
index c7b5bf7..8e142cb 100644
--- a/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.cc
+++ b/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.cc
@@ -146,6 +146,7 @@
SET_SUPPORTED(READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL,
ReadInquiryResponseTransmitPowerLevel);
SET_SUPPORTED(SEND_KEYPRESS_NOTIFICATION, SendKeypressNotification);
+ SET_HANDLER(SET_EVENT_MASK_PAGE_2, SetEventMaskPage2);
SET_SUPPORTED(READ_LOCAL_OOB_DATA, ReadLocalOobData);
SET_SUPPORTED(READ_LOCAL_OOB_EXTENDED_DATA, ReadLocalOobExtendedData);
SET_SUPPORTED(WRITE_SIMPLE_PAIRING_MODE, WriteSimplePairingMode);
@@ -288,6 +289,8 @@
SET_SUPPORTED(READ_VOICE_SETTING, ReadVoiceSetting);
SET_SUPPORTED(READ_CONNECTION_ACCEPT_TIMEOUT, ReadConnectionAcceptTimeout);
SET_SUPPORTED(WRITE_CONNECTION_ACCEPT_TIMEOUT, WriteConnectionAcceptTimeout);
+ SET_SUPPORTED(LE_SET_ADDRESS_RESOLUTION_ENABLE, LeSetAddressResolutionEnable);
+ SET_SUPPORTED(LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT, LeSetResovalablePrivateAddressTimeout);
#undef SET_HANDLER
#undef SET_SUPPORTED
properties_.SetSupportedCommands(supported_commands);
@@ -854,6 +857,14 @@
kNumCommandPackets, status, peer));
}
+void DualModeController::SetEventMaskPage2(CommandView command) {
+ auto payload =
+ std::make_unique<bluetooth::packet::RawBuilder>(std::vector<uint8_t>(
+ {static_cast<uint8_t>(bluetooth::hci::ErrorCode::SUCCESS)}));
+ send_event_(bluetooth::hci::CommandCompleteBuilder::Create(
+ kNumCommandPackets, command.GetOpCode(), std::move(payload)));
+}
+
void DualModeController::ReadLocalOobData(CommandView command) {
auto command_view = gd_hci::ReadLocalOobDataView::Create(
gd_hci::SecurityCommandView::Create(command));
@@ -1561,6 +1572,24 @@
send_event_(std::move(packet));
}
+void DualModeController::LeSetAddressResolutionEnable(CommandView command) {
+ // NOP
+ auto payload =
+ std::make_unique<bluetooth::packet::RawBuilder>(std::vector<uint8_t>(
+ {static_cast<uint8_t>(bluetooth::hci::ErrorCode::SUCCESS)}));
+ send_event_(bluetooth::hci::CommandCompleteBuilder::Create(
+ kNumCommandPackets, command.GetOpCode(), std::move(payload)));
+}
+
+void DualModeController::LeSetResovalablePrivateAddressTimeout(CommandView command) {
+ // NOP
+ auto payload =
+ std::make_unique<bluetooth::packet::RawBuilder>(std::vector<uint8_t>(
+ {static_cast<uint8_t>(bluetooth::hci::ErrorCode::SUCCESS)}));
+ send_event_(bluetooth::hci::CommandCompleteBuilder::Create(
+ kNumCommandPackets, command.GetOpCode(), std::move(payload)));
+}
+
void DualModeController::LeReadLocalSupportedFeatures(CommandView command) {
auto command_view = gd_hci::LeReadLocalSupportedFeaturesView::Create(command);
ASSERT(command_view.IsValid());
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
index 2a77c72..5d0e767 100644
--- a/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.h
+++ b/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.h
@@ -337,6 +337,9 @@
// 7.3.63
void SendKeypressNotification(CommandView args);
+ // 7.3.69
+ void SetEventMaskPage2(CommandView args);
+
// 7.3.79
void WriteLeHostSupport(CommandView args);
@@ -475,6 +478,12 @@
// 7.8.41
void LeReadResolvingListSize(CommandView args);
+ // 7.8.44
+ void LeSetAddressResolutionEnable(CommandView args);
+
+ // 7.8.45
+ void LeSetResovalablePrivateAddressTimeout(CommandView args);
+
// 7.8.46
void LeReadMaximumDataLength(CommandView args);
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
index d9dfdb9..a584b97 100644
--- a/vendor_libs/test_vendor_lib/model/setup/test_channel_transport.cc
+++ b/vendor_libs/test_vendor_lib/model/setup/test_channel_transport.cc
@@ -99,6 +99,7 @@
int bytes_read = read(fd, &command_name_size, 1);
if (bytes_read != 1) {
LOG_INFO("Unexpected (command_name_size) bytes_read: %d != %d", bytes_read, 1);
+ close(fd);
}
vector<uint8_t> command_name_raw;
command_name_raw.resize(command_name_size);
@@ -148,6 +149,10 @@
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);
+ if (written == -1 && errno == EBADFD) {
+ LOG_WARN("Unable to send a response. EBADFD");
+ return;
+ }
ASSERT_LOG(written == 4, "What happened? written = %d errno = %d", written, errno);
written = write(fd, response.c_str(), size);
ASSERT_LOG(written == static_cast<int>(size), "What happened? written = %d errno = %d", written, errno);
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
index 688d864..65aba67 100644
--- a/vendor_libs/test_vendor_lib/model/setup/test_command_handler.cc
+++ b/vendor_libs/test_vendor_lib/model/setup/test_command_handler.cc
@@ -49,6 +49,7 @@
SET_HANDLER("set_timer_period", SetTimerPeriod);
SET_HANDLER("start_timer", StartTimer);
SET_HANDLER("stop_timer", StopTimer);
+ SET_HANDLER("reset", Reset);
#undef SET_HANDLER
}
diff --git a/vendor_libs/test_vendor_lib/scripts/test_channel.py b/vendor_libs/test_vendor_lib/scripts/test_channel.py
index 161c2bb..bca358c 100644
--- a/vendor_libs/test_vendor_lib/scripts/test_channel.py
+++ b/vendor_libs/test_vendor_lib/scripts/test_channel.py
@@ -241,6 +241,22 @@
sleep_time = float(args.split()[0])
time.sleep(sleep_time)
+ def do_reset(self, args):
+ """Arguments: None.
+
+ Resets the simulation.
+ """
+ self._test_channel.send_command('reset', [])
+
+ def do_end(self, args):
+ """Arguments: None.
+
+ Ends the simulation and exits.
+ """
+ self._test_channel.send_command('END_SIMULATION', [])
+ print('Goodbye.')
+ return True
+
def do_quit(self, args):
"""Arguments: None.
diff --git a/vendor_libs/test_vendor_lib/types/Android.bp b/vendor_libs/test_vendor_lib/types/Android.bp
index 028538a..e68af2a 100644
--- a/vendor_libs/test_vendor_lib/types/Android.bp
+++ b/vendor_libs/test_vendor_lib/types/Android.bp
@@ -31,7 +31,6 @@
export_header_lib_headers: ["libbt-rootcanal-types-header"],
}
-// ========================================================
cc_test {
name: "rootcanal-test_types",
test_suites: ["device-tests"],