From: Chris Manton Date: Wed, 15 Jan 2020 00:34:08 +0000 (-0800) Subject: Initial entry for headless X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=a402061dce6b741a34a34322e051e091d5ab4bf1;p=android-x86%2Fsystem-bt.git Initial entry for headless Bug: 147316415 Test: Compiles and sdp test runs Change-Id: I2db01df68fb8807ce934b59aab5a4f593d4f8074 --- diff --git a/test/headless/Android.bp b/test/headless/Android.bp new file mode 100644 index 000000000..5ebe9a311 --- /dev/null +++ b/test/headless/Android.bp @@ -0,0 +1,55 @@ +cc_test { + name: "bt_headless", + test_suites: ["device-tests"], + defaults: ["fluoride_defaults"], + srcs: [ + "get_options.cc", + "headless.cc", + "sdp/main.cc", + ], + include_dirs: [ + "system/bt", + "system/bt/stack/include", + ], + whole_static_libs: [ + "libbtcore", + ], + static_libs: [ + "libFraunhoferAAC", + "libbluetooth_gd", + "libbt-bta", + "libbt-common", + "libbt-hci", + "libbt-protos-lite", + "libbt-sbc-decoder", + "libbt-sbc-encoder", + "libbt-stack", + "libbt-utils", + "libbtdevice", + "libbte", + "libbtif", + "libg722codec", + "libosi", + "libprotobuf-cpp-lite", + "libudrv-uipc", + "libz", + ], + shared_libs: [ + "android.hardware.bluetooth.a2dp@1.0", + "android.hardware.bluetooth.audio@2.0", + "android.hardware.bluetooth@1.0", + "android.hardware.bluetooth@1.1", + "libaaudio", + "libbase", + "libcrypto", + "libcutils", // property_get_bool + "libfmq", + "libhidlbase", + "libjsoncpp", + "liblog", // __android_log_print + "libprocessgroup", + "libtinyxml2", + "libutils", + ], + ldflags: ["-rdynamic"], +} diff --git a/test/headless/get_options.cc b/test/headless/get_options.cc new file mode 100644 index 000000000..c28e30ec2 --- /dev/null +++ b/test/headless/get_options.cc @@ -0,0 +1,127 @@ +/* + * 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 "test/headless/get_options.h" + +#include +#include +#include +#include +#include +#include + +namespace { +constexpr struct option long_options[] = {{"device", required_argument, 0, 0}, + {"loop", required_argument, 0, 0}, + {"uuid", required_argument, 0, 0}, + {0, 0, 0, 0}}; + +enum OptionType { + kOptionDevice = 0, + kOptionLoop = 1, + kOptionUuid = 2, +}; + +} // namespace + +void bluetooth::test::headless::GetOpt::ParseValue( + char* optarg, std::list& string_list) { + CHECK(optarg != nullptr); + char* p = optarg; + char* pp = optarg; + while (*p != '\0') { + if (*p == ',') { + *p = 0; + string_list.push_back(std::string(pp)); + pp = p + 1; + } + p++; + } + if (pp != p) string_list.push_back(std::string(pp)); +} + +void bluetooth::test::headless::GetOpt::ProcessOption(int option_index, + char* optarg) { + std::list string_list; + OptionType option_type = static_cast(option_index); + + if (!optarg) return; + switch (option_type) { + case kOptionDevice: + ParseValue(optarg, string_list); + for (auto& entry : string_list) { + if (RawAddress::IsValidAddress(entry)) { + RawAddress address; + RawAddress::FromString(entry, address); + device_.push_back(address); + } + } + break; + case kOptionLoop: + loop_ = std::stoul(optarg, nullptr, 0); + break; + case kOptionUuid: + ParseValue(optarg, string_list); + for (auto& entry : string_list) { + uuid_.push_back( + bluetooth::Uuid::From16Bit(std::stoul(entry.c_str(), nullptr, 0))); + } + break; + default: + fflush(nullptr); + valid_ = false; + return; + break; + } +} + +bluetooth::test::headless::GetOpt::GetOpt(int argc, char** argv) + : name_(argv[0]) { + while (1) { + int option_index = 0; + int c = getopt_long_only(argc, argv, "d:l:u:", long_options, &option_index); + if (c == -1) break; + + switch (c) { + case 0: + ProcessOption(static_cast(option_index), optarg); + break; + case '?': + Usage(); + valid_ = false; + return; + default: + printf("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) { + printf("non-option ARGV-elements: "); + while (optind < argc) printf("%s ", argv[optind++]); + printf("\n"); + valid_ = false; + } + fflush(nullptr); +} + +void bluetooth::test::headless::GetOpt::Usage() const { + printf("%s: Usage:\n", name_); + printf("%s --device= Comma separated list of remote devices\n", + name_); + printf("%s --uuid= Comma separated list of uuids\n", name_); + printf("%s --loop= Number of loops\n", name_); + fflush(nullptr); +} diff --git a/test/headless/get_options.h b/test/headless/get_options.h new file mode 100644 index 000000000..65ab9201d --- /dev/null +++ b/test/headless/get_options.h @@ -0,0 +1,49 @@ +/* + * 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 +#include +#include "types/bluetooth/uuid.h" +#include "types/raw_address.h" + +namespace bluetooth { +namespace test { +namespace headless { + +class GetOpt { + public: + GetOpt(int argc, char** arv); + virtual ~GetOpt() = default; + + virtual void Usage() const; + virtual bool IsValid() const { return valid_; }; + + std::list device_; + std::list uuid_; + int loop_; + + private: + void ParseValue(char* optarg, std::list& my_list); + void ProcessOption(int option_index, char* optarg); + const char* name_{nullptr}; + bool valid_{true}; +}; + +} // namespace headless +} // namespace test +} // namespace bluetooth diff --git a/test/headless/headless.cc b/test/headless/headless.cc new file mode 100644 index 000000000..2cf633476 --- /dev/null +++ b/test/headless/headless.cc @@ -0,0 +1,173 @@ +/* + * 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. + */ + +#define LOG_TAG "bt_headless" + +#include // dlopen + +#include "base/logging.h" // LOG() stdout and android log +#include "include/hardware/bluetooth.h" +#include "osi/include/log.h" // android log only +#include "test/headless/headless.h" + +extern bt_interface_t bluetoothInterface; + +using namespace bluetooth::test::headless; + +namespace { +std::mutex adapter_state_mutex_; +std::condition_variable adapter_state_cv_; +bt_state_t bt_state_{BT_STATE_OFF}; + +void adapter_state_changed(bt_state_t state) { + std::unique_lock lck(adapter_state_mutex_); + bt_state_ = state; + adapter_state_cv_.notify_all(); +} +void adapter_properties(bt_status_t status, int num_properties, + bt_property_t* properties) { + LOG_INFO(LOG_TAG, "%s", __func__); +} + +void remote_device_properties(bt_status_t status, RawAddress* bd_addr, + int num_properties, bt_property_t* properties) { + LOG_INFO(LOG_TAG, "%s", __func__); +} + +void device_found(int num_properties, bt_property_t* properties) { + LOG_INFO(LOG_TAG, "%s", __func__); +} + +void discovery_state_changed(bt_discovery_state_t state) { + LOG_INFO(LOG_TAG, "%s", __func__); +} + +/** Bluetooth Legacy PinKey Request callback */ +void pin_request(RawAddress* remote_bd_addr, bt_bdname_t* bd_name, uint32_t cod, + bool min_16_digit) { + LOG_INFO(LOG_TAG, "%s", __func__); +} + +void ssp_request(RawAddress* remote_bd_addr, bt_bdname_t* bd_name, uint32_t cod, + bt_ssp_variant_t pairing_variant, uint32_t pass_key) { + LOG_INFO(LOG_TAG, "%s", __func__); +} + +/** Bluetooth Bond state changed callback */ +/* Invoked in response to create_bond, cancel_bond or remove_bond */ +void bond_state_changed(bt_status_t status, RawAddress* remote_bd_addr, + bt_bond_state_t state) { + LOG_INFO(LOG_TAG, "%s", __func__); +} + +/** Bluetooth ACL connection state changed callback */ +void acl_state_changed(bt_status_t status, RawAddress* remote_bd_addr, + bt_acl_state_t state) { + LOG_INFO(LOG_TAG, "%s", __func__); +} + +void thread_event(bt_cb_thread_evt evt) { LOG_INFO(LOG_TAG, "%s", __func__); } + +void dut_mode_recv(uint16_t opcode, uint8_t* buf, uint8_t len) { + LOG_INFO(LOG_TAG, "%s", __func__); +} + +void le_test_mode(bt_status_t status, uint16_t num_packets) { + LOG_INFO(LOG_TAG, "%s", __func__); +} + +void energy_info(bt_activity_energy_info* energy_info, + bt_uid_traffic_t* uid_data) { + LOG_INFO(LOG_TAG, "%s", __func__); +} + +bt_callbacks_t bt_callbacks{ + /** set to sizeof(bt_callbacks_t) */ + .size = sizeof(bt_callbacks_t), + .adapter_state_changed_cb = adapter_state_changed, + .adapter_properties_cb = adapter_properties, + .remote_device_properties_cb = remote_device_properties, + .device_found_cb = device_found, + .discovery_state_changed_cb = discovery_state_changed, + .pin_request_cb = pin_request, + .ssp_request_cb = ssp_request, + .bond_state_changed_cb = bond_state_changed, + .acl_state_changed_cb = acl_state_changed, + .thread_evt_cb = thread_event, + .dut_mode_recv_cb = dut_mode_recv, + .le_test_mode_cb = le_test_mode, + .energy_info_cb = energy_info, +}; +// HAL HARDWARE CALLBACKS + +// OS CALLOUTS +bool set_wake_alarm_co(uint64_t delay_millis, bool should_wake, alarm_cb cb, + void* data) { + LOG_INFO(LOG_TAG, "%s", __func__); + return true; +} +int acquire_wake_lock_co(const char* lock_name) { + LOG_INFO(LOG_TAG, "%s", __func__); + return 1; +} + +int release_wake_lock_co(const char* lock_name) { + LOG_INFO(LOG_TAG, "%s", __func__); + return 0; +} + +bt_os_callouts_t bt_os_callouts{ + .size = sizeof(bt_os_callouts_t), + .set_wake_alarm = set_wake_alarm_co, + .acquire_wake_lock = acquire_wake_lock_co, + .release_wake_lock = release_wake_lock_co, +}; +} // namespace + +void Headless::SetUp() { + LOG(INFO) << __func__ << " Entry"; + + int status = bluetoothInterface.init(&bt_callbacks, false, false); + (status == BT_STATUS_SUCCESS) + ? LOG(INFO) << __func__ << " Initialized bluetooth callbacks" + : LOG(FATAL) << "Failed to initialize Bluetooth stack"; + + status = bluetoothInterface.set_os_callouts(&bt_os_callouts); + (status == BT_STATUS_SUCCESS) + ? LOG(INFO) << __func__ << " Initialized os callouts" + : LOG(ERROR) << "Failed to set up Bluetooth OS callouts"; + + bluetoothInterface.enable(); + LOG_INFO(LOG_TAG, "%s Headless stack has enabled", __func__); + + std::unique_lock lck(adapter_state_mutex_); + while (bt_state_ != BT_STATE_ON) adapter_state_cv_.wait(lck); + LOG_INFO(LOG_TAG, "%s Headless stack is operational", __func__); +} + +void Headless::TearDown() { + LOG_INFO(LOG_TAG, "Stack has disabled"); + int status = bluetoothInterface.disable(); + + LOG(INFO) << __func__ << " Interface has been disabled status:" << status; + + bluetoothInterface.cleanup(); + LOG(INFO) << __func__ << " Cleaned up hal bluetooth library"; + + std::unique_lock lck(adapter_state_mutex_); + while (bt_state_ != BT_STATE_OFF) adapter_state_cv_.wait(lck); + LOG_INFO(LOG_TAG, "%s Headless stack has exited", __func__); +} diff --git a/test/headless/headless.h b/test/headless/headless.h new file mode 100644 index 000000000..c51d640f1 --- /dev/null +++ b/test/headless/headless.h @@ -0,0 +1,47 @@ +/* + * 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. + */ + +namespace bluetooth { +namespace test { +namespace headless { + +template +using ExecutionUnit = std::function; + +class Headless { + public: + Headless() = default; + virtual ~Headless() = default; + + protected: + virtual void SetUp(); + virtual void TearDown(); +}; + +class Test : public Headless { + public: + template + T Run(ExecutionUnit func) { + SetUp(); + T rc = func(); + TearDown(); + return rc; + } +}; + +} // namespace headless +} // namespace test +} // namespace bluetooth diff --git a/test/headless/sdp/main.cc b/test/headless/sdp/main.cc new file mode 100644 index 000000000..b031e28ec --- /dev/null +++ b/test/headless/sdp/main.cc @@ -0,0 +1,120 @@ +/* + * 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. + */ + +#define LOG_TAG "bt_headless_sdp" + +#include + +#include "base/logging.h" // LOG() stdout and android log +#include "osi/include/log.h" // android log only +#include "stack/include/sdp_api.h" +#include "test/headless/get_options.h" +#include "test/headless/headless.h" +#include "types/raw_address.h" + +static void bta_jv_start_discovery_callback(uint16_t result, void* user_data) { + auto promise = static_cast*>(user_data); + promise->set_value(result); +} + +constexpr size_t kMaxDiscoveryRecords = 16; + +int sdp_query_uuid(int num_loops, const RawAddress& raw_address, + const bluetooth::Uuid& uuid) { + for (int i = 0; i < num_loops; i++) { + tSDP_DISCOVERY_DB* sdp_discovery_db = (tSDP_DISCOVERY_DB*)malloc( + sizeof(tSDP_DISCOVERY_DB) + + sizeof(tSDP_DISC_REC) * kMaxDiscoveryRecords); + + if (!SDP_InitDiscoveryDb(sdp_discovery_db, + sizeof(tSDP_DISCOVERY_DB) + + sizeof(tSDP_DISC_REC) * kMaxDiscoveryRecords, + 1, // num_uuid, + &uuid, 0, nullptr)) { + LOG(ERROR) << __func__ << " Unable to initialize sdp discovery"; + return -1; + } + + std::promise promise; + auto future = promise.get_future(); + + if (!SDP_ServiceSearchAttributeRequest2(raw_address, sdp_discovery_db, + bta_jv_start_discovery_callback, + (void*)&promise)) { + LOG(ERROR) << __func__ + << " Failed to start search attribute request.. waiting"; + return -2; + } + uint16_t result = future.get(); + LOG(INFO) << __func__ << " connection result:" << result; + + tSDP_DISC_REC* rec = + SDP_FindServiceInDb(sdp_discovery_db, uuid.As16Bit(), nullptr); + if (rec == nullptr) { + LOG(INFO) << __func__ << " iter:" << i << " discovery record is null" + << " from:" << raw_address.ToString() << " uuid:" << uuid; + } else { + printf("iter:%d result:%d attr_id:%x from:%s uuid:%s", i, result, + rec->p_first_attr->attr_id, rec->remote_bd_addr.ToString().c_str(), + uuid.ToString().c_str()); + + LOG(INFO) << __func__ << " iter:" << i << " result:" << result + << " discovery record found attr_id:" + << rec->p_first_attr->attr_id + << " len_type:" << rec->p_first_attr->attr_len_type << " time" + << rec->time_read << " from:" << rec->remote_bd_addr.ToString() + << " uuid:" << uuid; + fflush(nullptr); + } + free(sdp_discovery_db); + } + return 0; +} + +int main(int argc, char** argv) { + printf("Hello world\n"); + fflush(nullptr); + + LOG(INFO) << "bt_headless start up"; + + bluetooth::test::headless::GetOpt options(argc, argv); + if (!options.IsValid()) { + return -1; + } + if (options.loop_ < 1) { + LOG(INFO) << "This test requires at least a single loop"; + options.Usage(); + return -1; + } + if (options.device_.size() != 1) { + LOG(INFO) << "This test requires a single device specified"; + options.Usage(); + return -1; + } + if (options.uuid_.size() != 1) { + LOG(INFO) << "This test requires a single uuid specified"; + options.Usage(); + return -1; + } + + bluetooth::test::headless::Test test; + int rc = test.Run([options]() { + return sdp_query_uuid(options.loop_, options.device_.front(), + options.uuid_.front()); + }); + LOG(INFO) << "bt_headless shut down"; + return rc; +}