1 /*
2  * Copyright 2024 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 #include "btif_hci_vs.h"
18 
19 #include <bluetooth/log.h>
20 
21 #include "btif_common.h"
22 #include "hci/hci_interface.h"
23 #include "main/shim/entry.h"
24 #include "packet/raw_builder.h"
25 #include "stack/include/main_thread.h"
26 
27 namespace bluetooth {
28 namespace hci_vs {
29 
30 using hci::CommandCompleteView;
31 using hci::CommandStatusOrCompleteView;
32 using hci::CommandStatusView;
33 using hci::OpCode;
34 using hci::VendorSpecificEventView;
35 
36 std::unique_ptr<BluetoothHciVendorSpecificInterface> hciVendorSpecificInterface;
37 
CommandStatusOrCompleteCallback(BluetoothHciVendorSpecificCallbacks * callbacks,Cookie cookie,CommandStatusOrCompleteView status_or_complete)38 static void CommandStatusOrCompleteCallback(BluetoothHciVendorSpecificCallbacks* callbacks,
39                                             Cookie cookie,
40                                             CommandStatusOrCompleteView status_or_complete) {
41   if (std::holds_alternative<CommandStatusView>(status_or_complete)) {
42     auto view = std::get<CommandStatusView>(status_or_complete);
43     auto ocf = static_cast<uint16_t>(view.GetCommandOpCode()) & 0x3ff;
44     auto status = static_cast<uint8_t>(view.GetStatus());
45     do_in_jni_thread(base::BindOnce(&BluetoothHciVendorSpecificCallbacks::onCommandStatus,
46                                     base::Unretained(callbacks), ocf, status, cookie));
47 
48   } else if (std::holds_alternative<CommandCompleteView>(status_or_complete)) {
49     auto view = std::get<CommandCompleteView>(status_or_complete);
50     auto ocf = static_cast<uint16_t>(view.GetCommandOpCode()) & 0x3ff;
51     std::vector<uint8_t> return_parameters(view.GetPayload().begin(), view.GetPayload().end());
52     do_in_jni_thread(base::BindOnce(&BluetoothHciVendorSpecificCallbacks::onCommandComplete,
53                                     base::Unretained(callbacks), ocf, return_parameters, cookie));
54   }
55 }
56 
EventCallback(BluetoothHciVendorSpecificCallbacks * callbacks,VendorSpecificEventView view)57 static void EventCallback(BluetoothHciVendorSpecificCallbacks* callbacks,
58                           VendorSpecificEventView view) {
59   const uint8_t aosp_reserved_codes_range[] = {0x50, 0x60};
60   auto code = static_cast<uint8_t>(view.GetSubeventCode());
61   if (code >= aosp_reserved_codes_range[0] && code < aosp_reserved_codes_range[1]) {
62     return;
63   }
64 
65   std::vector<uint8_t> data(view.GetPayload().begin(), view.GetPayload().end());
66   do_in_jni_thread(base::BindOnce(&BluetoothHciVendorSpecificCallbacks::onEvent,
67                                   base::Unretained(callbacks), code, data));
68 }
69 
70 class BluetoothHciVendorSpecificInterfaceImpl
71     : public bluetooth::hci_vs::BluetoothHciVendorSpecificInterface {
72   ~BluetoothHciVendorSpecificInterfaceImpl() override = default;
73 
init(BluetoothHciVendorSpecificCallbacks * callbacks)74   void init(BluetoothHciVendorSpecificCallbacks* callbacks) override {
75     log::info("BluetoothHciVendorSpecificInterfaceImpl");
76     log::assert_that(callbacks != nullptr, "callbacks cannot be null");
77     callbacks_ = callbacks;
78 
79     shim::GetHciLayer()->RegisterDefaultVendorSpecificEventHandler(
80             get_main()->Bind(EventCallback, callbacks_));
81   }
82 
sendCommand(uint16_t ocf,std::vector<uint8_t> parameters,Cookie cookie)83   void sendCommand(uint16_t ocf, std::vector<uint8_t> parameters, Cookie cookie) override {
84     if (callbacks_ == nullptr) {
85       log::error("not initialized");
86       return;
87     }
88 
89     if (ocf & ~0x3ff) {
90       log::error("invalid vendor-specific op-code");
91       return;
92     }
93 
94     const uint16_t ogf_vendor_specific = 0x3f;
95     auto op_code = static_cast<OpCode>((ogf_vendor_specific << 10) | ocf);
96 
97     shim::GetHciLayer()->EnqueueCommand(
98             hci::CommandBuilder::Create(
99                     op_code, std::make_unique<packet::RawBuilder>(std::move(parameters))),
100             get_main()->BindOnce(CommandStatusOrCompleteCallback, callbacks_, std::move(cookie)));
101   }
102 
103 private:
104   BluetoothHciVendorSpecificCallbacks* callbacks_ = nullptr;
105 };
106 
getBluetoothHciVendorSpecificInterface()107 BluetoothHciVendorSpecificInterface* getBluetoothHciVendorSpecificInterface() {
108   if (!hciVendorSpecificInterface) {
109     hciVendorSpecificInterface.reset(new BluetoothHciVendorSpecificInterfaceImpl());
110   }
111 
112   return hciVendorSpecificInterface.get();
113 }
114 
115 }  // namespace hci_vs
116 }  // namespace bluetooth
117