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",
#include <string>
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=<device,> Comma separated list of remote devices\n",
+ name_);
+ fprintf(stdout, "%s --uuid=<uuid,> Comma separated list of uuids\n",
+ name_);
+ fprintf(stdout, "%s --loop=<loop> Number of loops\n", name_);
+ fprintf(stdout, "%s --msleep=<msecs> 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<std::string>& string_list) {
CHECK(optarg != nullptr);
std::list<std::string> string_list;
OptionType option_type = static_cast<OptionType>(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)) {
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;
}
}
- 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=<device,> Comma separated list of remote devices\n",
- name_);
- printf("%s --uuid=<uuid,> Comma separated list of uuids\n", name_);
- printf("%s --loop=<loop> Number of loops\n", name_);
- fflush(nullptr);
-}
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<RawAddress> device_;
std::list<bluetooth::Uuid> uuid_;
- int loop_;
+ unsigned long loop_{1};
+ unsigned long msec_{0};
+
+ bool close_stderr_{true};
+
+ mutable std::list<std::string> non_options_;
private:
void ParseValue(char* optarg, std::list<std::string>& my_list);
#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;
};
} // namespace
-void Headless::SetUp() {
+void HeadlessStack::SetUp() {
LOG(INFO) << __func__ << " Entry";
int status = bluetoothInterface.init(&bt_callbacks, false, false);
: 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<std::mutex> 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();
std::unique_lock<std::mutex> 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__);
}
* limitations under the License.
*/
+#pragma once
+
+#include <unordered_map>
+
+#include <unistd.h>
+
+#include "base/logging.h" // LOG() stdout and android log
+#include "test/headless/get_options.h"
+
namespace bluetooth {
namespace test {
namespace headless {
+namespace {
+
template <typename T>
using ExecutionUnit = std::function<T()>;
-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 <typename T>
- T Run(ExecutionUnit<T> func) {
+ T RunOnHeadlessStack(ExecutionUnit<T> 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 <typename T>
+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<std::string, std::unique_ptr<HeadlessTest<T>>> test_nodes_;
};
} // namespace headless
--- /dev/null
+/*
+ * 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 <unordered_map>
+
+#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<int> {
+ public:
+ Main(const bluetooth::test::headless::GetOpt& options)
+ : HeadlessTest<int>(options) {
+ test_nodes_.emplace(
+ "nop", std::make_unique<bluetooth::test::headless::Nop>(options));
+ test_nodes_.emplace(
+ "pairing",
+ std::make_unique<bluetooth::test::headless::Pairing>(options));
+ test_nodes_.emplace(
+ "read", std::make_unique<bluetooth::test::headless::Read>(options));
+ test_nodes_.emplace(
+ "sdp", std::make_unique<bluetooth::test::headless::Sdp>(options));
+ }
+
+ int Run() override {
+ if (options_.close_stderr_) {
+ fclose(stderr);
+ }
+ return HeadlessTest<int>::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();
+}
--- /dev/null
+/*
+ * 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 <future>
+
+#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<int>([this]() {
+ fprintf(stdout, "Nop loop:%lu\n", loop_);
+ return 0;
+ });
+}
--- /dev/null
+/*
+ * 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<int> {
+ public:
+ Nop(const bluetooth::test::headless::GetOpt& options)
+ : HeadlessTest<int>(options) {}
+ int Run() override;
+};
+
+} // namespace headless
+} // namespace test
+} // namespace bluetooth
--- /dev/null
+/*
+ * 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 <future>
+
+#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<int>([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;
+ });
+}
--- /dev/null
+
+#pragma once
+
+#include "test/headless/get_options.h"
+#include "test/headless/headless.h"
+
+namespace bluetooth {
+namespace test {
+namespace headless {
+
+class Pairing : public HeadlessTest<int> {
+ public:
+ Pairing(const bluetooth::test::headless::GetOpt& options)
+ : HeadlessTest<int>(options) {}
+ int Run() override;
+};
+
+} // namespace headless
+} // namespace test
+} // namespace bluetooth
--- /dev/null
+/*
+ * 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 <future>
+
+#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<tBTM_REMOTE_DEV_NAME> promise_;
+
+void RemoteNameCallback(void* data) {
+ promise_.set_value(*static_cast<tBTM_REMOTE_DEV_NAME*>(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<int>([&raw_address]() {
+ promise_ = std::promise<tBTM_REMOTE_DEV_NAME>();
+
+ 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;
+ });
+}
--- /dev/null
+/*
+ * 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<int> {
+ public:
+ Name(const bluetooth::test::headless::GetOpt& options)
+ : HeadlessTest<int>(options) {}
+ int Run() override;
+};
+
+} // namespace headless
+} // namespace test
+} // namespace bluetooth
--- /dev/null
+/*
+ * 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<int>(options) {
+ test_nodes_.emplace(
+ "name", std::make_unique<bluetooth::test::headless::Name>(options));
+}
--- /dev/null
+/*
+ * 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<int> {
+ public:
+ Read(const bluetooth::test::headless::GetOpt& options);
+};
+
+} // namespace headless
+} // namespace test
+} // namespace bluetooth
+++ /dev/null
-/*
- * 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 <future>
-
-#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<std::promise<uint16_t>*>(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<uint16_t> 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<int>([options]() {
- return sdp_query_uuid(options.loop_, options.device_.front(),
- options.uuid_.front());
- });
- LOG(INFO) << "bt_headless shut down";
- return rc;
-}
--- /dev/null
+/*
+ * 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 <future>
+
+#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<std::promise<uint16_t>*>(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<uint16_t> 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<int>([this]() {
+ return sdp_query_uuid(options_.loop_, options_.device_.front(),
+ options_.uuid_.front());
+ });
+}
--- /dev/null
+/*
+ * 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<int> {
+ public:
+ Sdp(const bluetooth::test::headless::GetOpt& options)
+ : HeadlessTest<int>(options) {}
+ int Run() override;
+};
+
+} // namespace headless
+} // namespace test
+} // namespace bluetooth
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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 <cstdio>
+
+#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