1 /*
2  * Copyright 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "bt_headless_sdp"
18 
19 #include "test/headless/sdp/sdp.h"
20 
21 #include <future>
22 
23 #include "bta/dm/bta_dm_int.h"
24 #include "bta/include/bta_api.h"
25 #include "stack/include/sdp_api.h"
26 #include "test/headless/get_options.h"
27 #include "test/headless/headless.h"
28 #include "test/headless/sdp/sdp_db.h"
29 #include "types/bluetooth/uuid.h"
30 #include "types/raw_address.h"
31 
32 using namespace bluetooth::legacy::stack::sdp;
33 using namespace bluetooth::test::headless;
34 
bta_jv_start_discovery_callback(std::promise<tSDP_STATUS> * promise,const RawAddress &,tSDP_STATUS result)35 static void bta_jv_start_discovery_callback(std::promise<tSDP_STATUS>* promise,
36                                             const RawAddress& /* bd_addr */, tSDP_STATUS result) {
37   promise->set_value(result);
38 }
39 
40 namespace {
41 
42 constexpr size_t kMaxDiscoveryRecords = 1024;
43 
sdp_query_uuid(unsigned int num_loops,const RawAddress & raw_address,const bluetooth::Uuid & uuid)44 int sdp_query_uuid([[maybe_unused]] unsigned int num_loops,
45                    [[maybe_unused]] const RawAddress& raw_address,
46                    [[maybe_unused]] const bluetooth::Uuid& uuid) {
47   SdpDb sdp_discovery_db(kMaxDiscoveryRecords);
48 
49   if (!get_legacy_stack_sdp_api()->service.SDP_InitDiscoveryDb(sdp_discovery_db.RawPointer(),
50                                                                sdp_discovery_db.Length(),
51                                                                1,  // num_uuid,
52                                                                &uuid, 0, nullptr)) {
53     LOG_CONSOLE("Unable to initialize sdp discovery");
54     return -1;
55   }
56   LOG_CONSOLE("Initialized sdp discovery database");
57 
58   std::promise<tSDP_STATUS> promise;
59   auto future = promise.get_future();
60 
61   sdp_discovery_db.Print(stdout);
62 
63   if (!get_legacy_stack_sdp_api()->service.SDP_ServiceSearchAttributeRequest2(
64               raw_address, sdp_discovery_db.RawPointer(),
65               base::BindRepeating(bta_jv_start_discovery_callback, &promise))) {
66     fprintf(stdout, "%s Failed to start search attribute request\n", __func__);
67     return -2;
68   }
69   LOG_CONSOLE("Started service search for uuid:%s", uuid.ToString().c_str());
70 
71   const tSDP_STATUS result = future.get();
72   if (result != tSDP_STATUS::SDP_SUCCESS) {
73     fprintf(stdout, "Failed search discovery result:%s\n", sdp_status_text(result).c_str());
74     return static_cast<int>(result);
75   }
76 
77   LOG_CONSOLE("Found records peer:%s uuid:%s", raw_address.ToString().c_str(),
78               uuid.ToString().c_str());
79   for (unsigned i = 0; i < BTA_MAX_SERVICE_ID; i++) {
80     uint16_t uuid_as16Bit = bta_service_id_to_uuid_lkup_tbl[i];
81     tSDP_DISC_REC* rec = SDP_FindServiceInDb(sdp_discovery_db.RawPointer(), uuid_as16Bit, nullptr);
82     if (rec != nullptr) {
83       LOG_CONSOLE("   uuid:0x%x", uuid_as16Bit);
84     }
85   }
86 
87   return 0;
88 }
89 
90 }  // namespace
91 
Run()92 int bluetooth::test::headless::Sdp::Run() {
93   if (options_.loop_ < 1) {
94     printf("This test requires at least a single loop\n");
95     options_.Usage();
96     return -1;
97   }
98   if (options_.device_.size() != 1) {
99     printf("This test requires a single device specified\n");
100     options_.Usage();
101     return -1;
102   }
103   if (options_.uuid_.size() != 1) {
104     printf("This test requires a single uuid specified\n");
105     options_.Usage();
106     return -1;
107   }
108 
109   return RunOnHeadlessStack<int>([this]() {
110     return sdp_query_uuid(options_.loop_, options_.device_.front(), options_.uuid_.front());
111   });
112 }
113