From: Chris Manton Date: Tue, 18 Feb 2020 15:56:15 +0000 (-0800) Subject: Refactor of headless test to allow additional tests X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=25cc82882b799af0904c57c1a3bd30dba6e3cc93;p=android-x86%2Fsystem-bt.git Refactor of headless test to allow additional tests Bug: 147316415 Test: bt_headless --device=40:4e:36:56:f3:9b --loop=1 pairing Test: bt_headless --device=40:4e:36:56:f3:9b --loop=1 --uuid=0x110e sdp Change-Id: I202c7af885d86fd77fffeec5a87b56ffe18882da --- diff --git a/test/headless/Android.bp b/test/headless/Android.bp index 5ebe9a311..fbfb2f46c 100644 --- a/test/headless/Android.bp +++ b/test/headless/Android.bp @@ -5,7 +5,13 @@ cc_test { srcs: [ "get_options.cc", "headless.cc", - "sdp/main.cc", + "main.cc", + "pairing/pairing.cc", + "sdp/sdp.cc", + "sdp/sdp_db.cc", + "nop/nop.cc", + "read/read.cc", + "read/name.cc", ], include_dirs: [ "system/bt", diff --git a/test/headless/get_options.cc b/test/headless/get_options.cc index c28e30ec2..f8d85760f 100644 --- a/test/headless/get_options.cc +++ b/test/headless/get_options.cc @@ -24,19 +24,34 @@ #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}}; +constexpr struct option long_options[] = { + {"device", required_argument, 0, 0}, {"loop", required_argument, 0, 0}, + {"uuid", required_argument, 0, 0}, {"msleep", required_argument, 0, 0}, + {"stderr", no_argument, 0, 0}, {0, 0, 0, 0}}; enum OptionType { kOptionDevice = 0, kOptionLoop = 1, kOptionUuid = 2, + kOptionMsleep = 3, + kOptionStdErr = 4, }; } // namespace +void bluetooth::test::headless::GetOpt::Usage() const { + fprintf(stdout, "%s: Usage:\n", name_); + fprintf(stdout, + "%s --device= Comma separated list of remote devices\n", + name_); + fprintf(stdout, "%s --uuid= Comma separated list of uuids\n", + name_); + fprintf(stdout, "%s --loop= Number of loops\n", name_); + fprintf(stdout, "%s --msleep= Sleep msec between loops\n", name_); + fprintf(stdout, "%s --stderr Dump stderr to stdout\n", name_); + fflush(nullptr); +} + void bluetooth::test::headless::GetOpt::ParseValue( char* optarg, std::list& string_list) { CHECK(optarg != nullptr); @@ -58,9 +73,9 @@ void bluetooth::test::headless::GetOpt::ProcessOption(int option_index, std::list string_list; OptionType option_type = static_cast(option_index); - if (!optarg) return; switch (option_type) { case kOptionDevice: + if (!optarg) return; ParseValue(optarg, string_list); for (auto& entry : string_list) { if (RawAddress::IsValidAddress(entry)) { @@ -74,12 +89,20 @@ void bluetooth::test::headless::GetOpt::ProcessOption(int option_index, loop_ = std::stoul(optarg, nullptr, 0); break; case kOptionUuid: + if (!optarg) return; ParseValue(optarg, string_list); for (auto& entry : string_list) { uuid_.push_back( bluetooth::Uuid::From16Bit(std::stoul(entry.c_str(), nullptr, 0))); } break; + case kOptionMsleep: + if (!optarg) return; + msec_ = std::stoul(optarg, nullptr, 0); + break; + case kOptionStdErr: + close_stderr_ = false; + break; default: fflush(nullptr); valid_ = false; @@ -108,20 +131,9 @@ bluetooth::test::headless::GetOpt::GetOpt(int argc, char** argv) } } - if (optind < argc) { - printf("non-option ARGV-elements: "); - while (optind < argc) printf("%s ", argv[optind++]); - printf("\n"); - valid_ = false; + while (optind < argc) { + non_options_.push_back(argv[optind++]); } 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 index 65ab9201d..04a502564 100644 --- a/test/headless/get_options.h +++ b/test/headless/get_options.h @@ -33,9 +33,20 @@ class GetOpt { virtual void Usage() const; virtual bool IsValid() const { return valid_; }; + std::string GetNextSubTest() const { + std::string test = non_options_.front(); + non_options_.pop_front(); + return test; + } + std::list device_; std::list uuid_; - int loop_; + unsigned long loop_{1}; + unsigned long msec_{0}; + + bool close_stderr_{true}; + + mutable std::list non_options_; private: void ParseValue(char* optarg, std::list& my_list); diff --git a/test/headless/headless.cc b/test/headless/headless.cc index 2cf633476..384159def 100644 --- a/test/headless/headless.cc +++ b/test/headless/headless.cc @@ -21,6 +21,7 @@ #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/get_options.h" #include "test/headless/headless.h" extern bt_interface_t bluetoothInterface; @@ -137,7 +138,7 @@ bt_os_callouts_t bt_os_callouts{ }; } // namespace -void Headless::SetUp() { +void HeadlessStack::SetUp() { LOG(INFO) << __func__ << " Entry"; int status = bluetoothInterface.init(&bt_callbacks, false, false); @@ -151,14 +152,14 @@ void Headless::SetUp() { : LOG(ERROR) << "Failed to set up Bluetooth OS callouts"; bluetoothInterface.enable(); - LOG_INFO(LOG_TAG, "%s Headless stack has enabled", __func__); + LOG_INFO(LOG_TAG, "%s HeadlessStack 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__); + LOG_INFO(LOG_TAG, "%s HeadlessStack stack is operational", __func__); } -void Headless::TearDown() { +void HeadlessStack::TearDown() { LOG_INFO(LOG_TAG, "Stack has disabled"); int status = bluetoothInterface.disable(); @@ -169,5 +170,5 @@ void Headless::TearDown() { 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__); + LOG_INFO(LOG_TAG, "%s HeadlessStack stack has exited", __func__); } diff --git a/test/headless/headless.h b/test/headless/headless.h index c51d640f1..551f60f04 100644 --- a/test/headless/headless.h +++ b/test/headless/headless.h @@ -14,32 +14,104 @@ * limitations under the License. */ +#pragma once + +#include + +#include + +#include "base/logging.h" // LOG() stdout and android log +#include "test/headless/get_options.h" + namespace bluetooth { namespace test { namespace headless { +namespace { + template using ExecutionUnit = std::function; -class Headless { - public: - Headless() = default; - virtual ~Headless() = default; +constexpr char kHeadlessStartSentinel[] = + " START HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS " + "HEADLESS"; +constexpr char kHeadlessStopSentinel[] = + " STOP HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS " + "HEADLESS"; +} // namespace + +class HeadlessStack { protected: - virtual void SetUp(); - virtual void TearDown(); + HeadlessStack() = default; + virtual ~HeadlessStack() = default; + + void SetUp(); + void TearDown(); }; -class Test : public Headless { - public: +class HeadlessRun : public HeadlessStack { + protected: + const bluetooth::test::headless::GetOpt& options_; + unsigned long loop_{0}; + + HeadlessRun(const bluetooth::test::headless::GetOpt& options) + : options_(options) {} + template - T Run(ExecutionUnit func) { + T RunOnHeadlessStack(ExecutionUnit func) { SetUp(); - T rc = func(); + LOG(INFO) << kHeadlessStartSentinel; + + T rc; + for (loop_ = 0; loop_ < options_.loop_; loop_++) { + rc = func(); + if (options_.msec_ != 0) { + usleep(options_.msec_ * 1000); + } + if (rc) { + break; + } + } + if (rc) { + LOG(ERROR) << "FAIL:" << rc << " loop/loops:" << loop_ << "/" + << options_.loop_; + } else { + LOG(INFO) << "PASS:" << rc << " loop/loops:" << loop_ << "/" + << options_.loop_; + } + + LOG(INFO) << kHeadlessStopSentinel; TearDown(); return rc; } + virtual ~HeadlessRun() = default; +}; + +template +class HeadlessTest : public HeadlessRun { + public: + virtual T Run() { + if (options_.non_options_.size() == 0) { + fprintf(stdout, "Must supply at least one subtest name\n"); + return -1; + } + + std::string subtest = options_.GetNextSubTest(); + if (test_nodes_.find(subtest) == test_nodes_.end()) { + fprintf(stdout, "Unknown subtest module:%s\n", subtest.c_str()); + return -1; + } + return test_nodes_.at(subtest)->Run(); + } + + virtual ~HeadlessTest() = default; + + protected: + HeadlessTest(const bluetooth::test::headless::GetOpt& options) + : HeadlessRun(options) {} + + std::unordered_map>> test_nodes_; }; } // namespace headless diff --git a/test/headless/main.cc b/test/headless/main.cc new file mode 100644 index 000000000..487e96c49 --- /dev/null +++ b/test/headless/main.cc @@ -0,0 +1,70 @@ +/* + * 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 + +#include "base/logging.h" // LOG() stdout and android log +#include "osi/include/log.h" // android log only +#include "test/headless/get_options.h" +#include "test/headless/headless.h" +#include "test/headless/nop/nop.h" +#include "test/headless/pairing/pairing.h" +#include "test/headless/read/read.h" +#include "test/headless/sdp/sdp.h" + +using namespace bluetooth::test::headless; + +namespace { + +class Main : public HeadlessTest { + public: + Main(const bluetooth::test::headless::GetOpt& options) + : HeadlessTest(options) { + test_nodes_.emplace( + "nop", std::make_unique(options)); + test_nodes_.emplace( + "pairing", + std::make_unique(options)); + test_nodes_.emplace( + "read", std::make_unique(options)); + test_nodes_.emplace( + "sdp", std::make_unique(options)); + } + + int Run() override { + if (options_.close_stderr_) { + fclose(stderr); + } + return HeadlessTest::Run(); + } +}; + +} // namespace + +int main(int argc, char** argv) { + fflush(nullptr); + setvbuf(stdout, nullptr, _IOLBF, 0); + + bluetooth::test::headless::GetOpt options(argc, argv); + if (!options.IsValid()) { + return -1; + } + + Main main(options); + return main.Run(); +} diff --git a/test/headless/nop/nop.cc b/test/headless/nop/nop.cc new file mode 100644 index 000000000..f6ac42c45 --- /dev/null +++ b/test/headless/nop/nop.cc @@ -0,0 +1,34 @@ +/* + * 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 "test/headless/nop/nop.h" +#include "types/raw_address.h" + +int bluetooth::test::headless::Nop::Run() { + return RunOnHeadlessStack([this]() { + fprintf(stdout, "Nop loop:%lu\n", loop_); + return 0; + }); +} diff --git a/test/headless/nop/nop.h b/test/headless/nop/nop.h new file mode 100644 index 000000000..e65efa3ba --- /dev/null +++ b/test/headless/nop/nop.h @@ -0,0 +1,35 @@ +/* + * 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 "test/headless/get_options.h" +#include "test/headless/headless.h" + +namespace bluetooth { +namespace test { +namespace headless { + +class Nop : public HeadlessTest { + public: + Nop(const bluetooth::test::headless::GetOpt& options) + : HeadlessTest(options) {} + int Run() override; +}; + +} // namespace headless +} // namespace test +} // namespace bluetooth diff --git a/test/headless/pairing/pairing.cc b/test/headless/pairing/pairing.cc new file mode 100644 index 000000000..7785ea4c1 --- /dev/null +++ b/test/headless/pairing/pairing.cc @@ -0,0 +1,54 @@ +/* + * 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 "btif/include/btif_api.h" +#include "osi/include/log.h" // android log only +#include "test/headless/get_options.h" +#include "test/headless/headless.h" +#include "test/headless/pairing/pairing.h" +#include "types/raw_address.h" + +int bluetooth::test::headless::Pairing::Run() { + if (options_.loop_ < 1) { + fprintf(stdout, "This test requires at least a single loop"); + options_.Usage(); + return -1; + } + if (options_.device_.size() != 1) { + fprintf(stdout, "This test requires a single device specified"); + options_.Usage(); + return -1; + } + + RawAddress raw_address = options_.device_.front(); + + return RunOnHeadlessStack([raw_address]() { + bt_status_t status = btif_dm_create_bond(&raw_address, BT_TRANSPORT_BR_EDR); + switch (status) { + case BT_STATUS_SUCCESS: + break; + default: + fprintf(stdout, "Failed to create bond status:%d", status); + break; + } + return status; + }); +} diff --git a/test/headless/pairing/pairing.h b/test/headless/pairing/pairing.h new file mode 100644 index 000000000..4125d48b3 --- /dev/null +++ b/test/headless/pairing/pairing.h @@ -0,0 +1,20 @@ + +#pragma once + +#include "test/headless/get_options.h" +#include "test/headless/headless.h" + +namespace bluetooth { +namespace test { +namespace headless { + +class Pairing : public HeadlessTest { + public: + Pairing(const bluetooth::test::headless::GetOpt& options) + : HeadlessTest(options) {} + int Run() override; +}; + +} // namespace headless +} // namespace test +} // namespace bluetooth diff --git a/test/headless/read/name.cc b/test/headless/read/name.cc new file mode 100644 index 000000000..6a8ea9fb0 --- /dev/null +++ b/test/headless/read/name.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. + */ + +#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/btm_api.h" +#include "stack/include/btm_api_types.h" +#include "test/headless/get_options.h" +#include "test/headless/headless.h" +#include "test/headless/read/name.h" +#include "types/raw_address.h" + +std::promise promise_; + +void RemoteNameCallback(void* data) { + promise_.set_value(*static_cast(data)); +} + +int bluetooth::test::headless::Name::Run() { + if (options_.loop_ < 1) { + fprintf(stdout, "This test requires at least a single loop"); + options_.Usage(); + return -1; + } + if (options_.device_.size() != 1) { + fprintf(stdout, "This test requires a single device specified"); + options_.Usage(); + return -1; + } + + const RawAddress& raw_address = options_.device_.front(); + + return RunOnHeadlessStack([&raw_address]() { + promise_ = std::promise(); + + auto future = promise_.get_future(); + + tBTM_STATUS status = BTM_ReadRemoteDeviceName( + raw_address, &RemoteNameCallback, BT_TRANSPORT_BR_EDR); + if (status != BTM_CMD_STARTED) { + fprintf(stdout, "Failure to start read remote device\n"); + return -1; + } + + tBTM_REMOTE_DEV_NAME name_packet = future.get(); + switch (name_packet.status) { + case BTM_SUCCESS: { + char buf[BD_NAME_LEN]; + memcpy(buf, name_packet.remote_bd_name, BD_NAME_LEN); + std::string name(buf); + fprintf(stdout, "Name result mac:%s name:%s\n", + raw_address.ToString().c_str(), name.c_str()); + } break; + case BTM_BAD_VALUE_RET: + fprintf(stdout, "Name Timeout or other failure"); + return -2; + default: + fprintf(stdout, "Unexpected remote name request failure status:%hd", + name_packet.status); + return -2; + } + return 0; + }); +} diff --git a/test/headless/read/name.h b/test/headless/read/name.h new file mode 100644 index 000000000..587cee231 --- /dev/null +++ b/test/headless/read/name.h @@ -0,0 +1,35 @@ +/* + * 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 "test/headless/get_options.h" +#include "test/headless/headless.h" + +namespace bluetooth { +namespace test { +namespace headless { + +class Name : public HeadlessTest { + public: + Name(const bluetooth::test::headless::GetOpt& options) + : HeadlessTest(options) {} + int Run() override; +}; + +} // namespace headless +} // namespace test +} // namespace bluetooth diff --git a/test/headless/read/read.cc b/test/headless/read/read.cc new file mode 100644 index 000000000..d1a3b8d29 --- /dev/null +++ b/test/headless/read/read.cc @@ -0,0 +1,32 @@ +/* + * 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 "test/headless/read/read.h" +#include "base/logging.h" // LOG() stdout and android log +#include "osi/include/log.h" // android log only +#include "test/headless/get_options.h" +#include "test/headless/headless.h" +#include "test/headless/read/name.h" + +using namespace bluetooth::test::headless; + +Read::Read(const bluetooth::test::headless::GetOpt& options) + : HeadlessTest(options) { + test_nodes_.emplace( + "name", std::make_unique(options)); +} diff --git a/test/headless/read/read.h b/test/headless/read/read.h new file mode 100644 index 000000000..04ab0f2eb --- /dev/null +++ b/test/headless/read/read.h @@ -0,0 +1,33 @@ +/* + * 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 "test/headless/get_options.h" +#include "test/headless/headless.h" + +namespace bluetooth { +namespace test { +namespace headless { + +class Read : public HeadlessTest { + public: + Read(const bluetooth::test::headless::GetOpt& options); +}; + +} // namespace headless +} // namespace test +} // namespace bluetooth diff --git a/test/headless/sdp/main.cc b/test/headless/sdp/main.cc deleted file mode 100644 index b031e28ec..000000000 --- a/test/headless/sdp/main.cc +++ /dev/null @@ -1,120 +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. - */ - -#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; -} diff --git a/test/headless/sdp/sdp.cc b/test/headless/sdp/sdp.cc new file mode 100644 index 000000000..9e20340ea --- /dev/null +++ b/test/headless/sdp/sdp.cc @@ -0,0 +1,147 @@ +/* + * 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 "test/headless/sdp/sdp.h" +#include "test/headless/sdp/sdp_db.h" +#include "types/raw_address.h" + +using namespace bluetooth::test::headless; + +static void bta_jv_start_discovery_callback(uint16_t result, void* user_data) { + auto promise = static_cast*>(user_data); + promise->set_value(result); +} + +namespace { + +struct sdp_error_code_s { + const char* name; + uint16_t error_code; +} sdp_error_code[] = { + {"KsdpSuccess", 0}, + {"KsdpInvalidVersion", 0x0001}, + {"KsdpInvalidServRecHdl", 0x0002}, + {"KsdpInvalidReqSyntax", 0x0003}, + {"KsdpInvalidPduSize", 0x0004}, + {"KsdpInvalidContState", 0x0005}, + {"KsdpNoResources", 0x0006}, + {"KsdpDiRegFailed", 0x0007}, + {"KsdpDiDiscFailed", 0x0008}, + {"KsdpNoDiRecordFound", 0x0009}, + {"KsdpErrAttrNotPresent", 0x000a}, + {"KsdpIllegalParameter", 0x000b}, + {"KsdpNoRecsMatch", 0xFFF0}, + {"KsdpConnFailed", 0xFFF1}, + {"KsdpCfgFailed", 0xFFF2}, + {"KsdpGenericError", 0xFFF3}, + {"KsdpDbFull", 0xFFF4}, + {"KsdpInvalidPdu", 0xFFF5}, + {"KsdpSecurityErr", 0xFFF6}, + {"KsdpConnRejected", 0xFFF7}, + {"KsdpCancel", 0xFFF8}, +}; + +const char* kUnknownText = "Unknown"; + +const char* SdpErrorCodeToString(uint16_t code) { + for (size_t i = 0; i < sizeof(sdp_error_code) / sizeof(sdp_error_code_s); + ++i) { + if (sdp_error_code[i].error_code == code) { + return sdp_error_code[i].name; + } + } + return kUnknownText; +} + +constexpr size_t kMaxDiscoveryRecords = 64; + +int sdp_query_uuid(unsigned int num_loops, const RawAddress& raw_address, + const bluetooth::Uuid& uuid) { + SdpDb sdp_discovery_db(kMaxDiscoveryRecords); + + if (!SDP_InitDiscoveryDb(sdp_discovery_db.RawPointer(), + sdp_discovery_db.Length(), + 1, // num_uuid, + &uuid, 0, nullptr)) { + fprintf(stdout, "%s Unable to initialize sdp discovery\n", __func__); + return -1; + } + + std::promise promise; + auto future = promise.get_future(); + + sdp_discovery_db.Print(stdout); + + if (!SDP_ServiceSearchAttributeRequest2( + raw_address, sdp_discovery_db.RawPointer(), + bta_jv_start_discovery_callback, (void*)&promise)) { + fprintf(stdout, "%s Failed to start search attribute request\n", __func__); + return -2; + } + + uint16_t result = future.get(); + if (result != 0) { + fprintf(stdout, "Failed search discovery result:%s\n", + SdpErrorCodeToString(result)); + return result; + } + + tSDP_DISC_REC* rec = SDP_FindServiceInDb(sdp_discovery_db.RawPointer(), + uuid.As16Bit(), nullptr); + if (rec == nullptr) { + fprintf(stdout, "discovery record is null from:%s uuid:%s\n", + raw_address.ToString().c_str(), uuid.ToString().c_str()); + } else { + fprintf(stdout, "result:%d attr_id:%x from:%s uuid:%s\n", result, + rec->p_first_attr->attr_id, rec->remote_bd_addr.ToString().c_str(), + uuid.ToString().c_str()); + } + return 0; +} + +} // namespace + +int bluetooth::test::headless::Sdp::Run() { + if (options_.loop_ < 1) { + printf("This test requires at least a single loop\n"); + options_.Usage(); + return -1; + } + if (options_.device_.size() != 1) { + printf("This test requires a single device specified\n"); + options_.Usage(); + return -1; + } + if (options_.uuid_.size() != 1) { + printf("This test requires a single uuid specified\n"); + options_.Usage(); + return -1; + } + + return RunOnHeadlessStack([this]() { + return sdp_query_uuid(options_.loop_, options_.device_.front(), + options_.uuid_.front()); + }); +} diff --git a/test/headless/sdp/sdp.h b/test/headless/sdp/sdp.h new file mode 100644 index 000000000..6542a1de7 --- /dev/null +++ b/test/headless/sdp/sdp.h @@ -0,0 +1,35 @@ +/* + * 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 "test/headless/get_options.h" +#include "test/headless/headless.h" + +namespace bluetooth { +namespace test { +namespace headless { + +class Sdp : public HeadlessTest { + public: + Sdp(const bluetooth::test::headless::GetOpt& options) + : HeadlessTest(options) {} + int Run() override; +}; + +} // namespace headless +} // namespace test +} // namespace bluetooth diff --git a/test/headless/sdp/sdp_db.cc b/test/headless/sdp/sdp_db.cc new file mode 100644 index 000000000..023861b70 --- /dev/null +++ b/test/headless/sdp/sdp_db.cc @@ -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. + */ + +#define LOG_TAG "bt_headless" + +#include "test/headless/sdp/sdp_db.h" +#include "base/logging.h" // LOG() stdout and android log +#include "osi/include/log.h" // android log only +#include "stack/include/sdp_api.h" +#include "types/bluetooth/uuid.h" +#include "types/raw_address.h" + +using namespace bluetooth::test::headless; + +SdpDb::SdpDb(unsigned int max_records) : max_records_(max_records) { + db_ = (tSDP_DISCOVERY_DB*)malloc(max_records_ * sizeof(tSDP_DISC_REC) + + sizeof(tSDP_DISCOVERY_DB)); +} + +SdpDb::~SdpDb() { free(db_); } + +tSDP_DISCOVERY_DB* SdpDb::RawPointer() { return db_; } + +uint32_t SdpDb::Length() const { + return max_records_ * sizeof(tSDP_DISC_REC) + sizeof(tSDP_DISCOVERY_DB); +} + +void SdpDb::Print(FILE* filep) const { + fprintf(filep, "memory size:0x%x free:0x%x\n", db_->mem_size, db_->mem_free); + fprintf(filep, "number of filters:%hd\n", db_->num_uuid_filters); + for (int i = 0; i < db_->num_uuid_filters; i++) { + fprintf(filep, " uuid:%s\n", db_->uuid_filters[i].ToString().c_str()); + } + fprintf(filep, "raw data size:0x%x used:0x%x\n", db_->raw_size, + db_->raw_used); +} diff --git a/test/headless/sdp/sdp_db.h b/test/headless/sdp/sdp_db.h new file mode 100644 index 000000000..63de0cc66 --- /dev/null +++ b/test/headless/sdp/sdp_db.h @@ -0,0 +1,46 @@ +/* + * 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 "stack/include/sdp_api.h" + +namespace bluetooth { +namespace test { +namespace headless { + +class SdpDb { + public: + SdpDb(unsigned int max_records); + ~SdpDb(); + + tSDP_DISCOVERY_DB* RawPointer(); + + uint32_t Length() const; + + void Print(FILE* filep) const; + + private: + unsigned int max_records_; + tSDP_DISCOVERY_DB* db_; +}; + +} // namespace headless +} // namespace test +} // namespace bluetooth