xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/fuchsia/bt_host/host.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2024 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "pw_bluetooth_sapphire/fuchsia/bt_host/host.h"
16 
17 #include <lib/fdio/directory.h>
18 #include <lib/inspect/component/cpp/component.h>
19 
20 #include "lib/async/default.h"
21 #include "pw_bluetooth_sapphire/fuchsia/bt_host/bt_host_config.h"
22 #include "pw_bluetooth_sapphire/fuchsia/host/controllers/fidl_controller.h"
23 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/host_server.h"
24 #include "pw_bluetooth_sapphire/internal/host/common/log.h"
25 #include "pw_bluetooth_sapphire/internal/host/common/random.h"
26 
27 using namespace bt;
28 
29 namespace bthost {
30 
BtHostComponent(async_dispatcher_t * dispatcher,const std::string & device_path,bool initialize_rng)31 BtHostComponent::BtHostComponent(async_dispatcher_t* dispatcher,
32                                  const std::string& device_path,
33                                  bool initialize_rng)
34     : pw_dispatcher_(dispatcher),
35       device_path_(device_path),
36       initialize_rng_(initialize_rng),
37       inspector_(inspect::ComponentInspector(dispatcher, {})) {
38   if (initialize_rng) {
39     set_random_generator(&random_generator_);
40   }
41   inspector_.root().RecordString("name", device_path_);
42 }
43 
~BtHostComponent()44 BtHostComponent::~BtHostComponent() {
45   if (initialize_rng_) {
46     set_random_generator(nullptr);
47   }
48 }
49 
50 // static
Create(async_dispatcher_t * dispatcher,const std::string & device_path)51 std::unique_ptr<BtHostComponent> BtHostComponent::Create(
52     async_dispatcher_t* dispatcher, const std::string& device_path) {
53   std::unique_ptr<BtHostComponent> host(
54       new BtHostComponent(dispatcher, device_path, /*initialize_rng=*/true));
55   return host;
56 }
57 
58 // static
CreateForTesting(async_dispatcher_t * dispatcher,const std::string & device_path)59 std::unique_ptr<BtHostComponent> BtHostComponent::CreateForTesting(
60     async_dispatcher_t* dispatcher, const std::string& device_path) {
61   std::unique_ptr<BtHostComponent> host(
62       new BtHostComponent(dispatcher, device_path, /*initialize_rng=*/false));
63   return host;
64 }
65 
Initialize(fidl::ClientEnd<fuchsia_hardware_bluetooth::Vendor> vendor_client_end,InitCallback init_cb,ErrorCallback error_cb,bool legacy_pairing_enabled)66 bool BtHostComponent::Initialize(
67     fidl::ClientEnd<fuchsia_hardware_bluetooth::Vendor> vendor_client_end,
68     InitCallback init_cb,
69     ErrorCallback error_cb,
70     bool legacy_pairing_enabled) {
71   std::unique_ptr<bt::controllers::FidlController> controller =
72       std::make_unique<bt::controllers::FidlController>(
73           std::move(vendor_client_end), async_get_default_dispatcher());
74 
75   bt_log(INFO, "bt-host", "Create HCI transport layer");
76   hci_ =
77       std::make_unique<hci::Transport>(std::move(controller), pw_dispatcher_);
78 
79   bt_log(INFO, "bt-host", "Create GATT layer");
80   gatt_ = gatt::GATT::Create();
81   gap::Adapter::Config config = {
82       .legacy_pairing_enabled = legacy_pairing_enabled,
83   };
84   gap_ = gap::Adapter::Create(
85       pw_dispatcher_, hci_->GetWeakPtr(), gatt_->GetWeakPtr(), config);
86   if (!gap_) {
87     bt_log(WARN, "bt-host", "GAP could not be created");
88     return false;
89   }
90   gap_->AttachInspect(inspector_.root(), "adapter");
91 
92   // Called when the GAP layer is ready. We initialize the GATT profile after
93   // initial setup in GAP. The data domain will be initialized by GAP because it
94   // both sets up the HCI ACL data channel that L2CAP relies on and registers
95   // L2CAP services.
96   auto gap_init_callback = [callback =
97                                 std::move(init_cb)](bool success) mutable {
98     bt_log(DEBUG,
99            "bt-host",
100            "GAP init complete status: (%s)",
101            (success ? "success" : "failure"));
102     callback(success);
103   };
104 
105   auto transport_closed_callback = [error_cb = std::move(error_cb)]() mutable {
106     bt_log(WARN, "bt-host", "HCI transport has closed");
107     error_cb();
108   };
109 
110   bt_log(DEBUG, "bt-host", "Initializing GAP");
111   return gap_->Initialize(std::move(gap_init_callback),
112                           std::move(transport_closed_callback));
113 }
114 
ShutDown()115 void BtHostComponent::ShutDown() {
116   bt_log(DEBUG, "bt-host", "Shutting down");
117 
118   if (!gap_) {
119     bt_log(DEBUG, "bt-host", "Already shut down");
120     return;
121   }
122 
123   // Closes all FIDL channels owned by |host_server_|.
124   host_server_ = nullptr;
125 
126   // Make sure that |gap_| gets shut down and destroyed on its creation thread
127   // as it is not thread-safe.
128   gap_->ShutDown();
129   gap_ = nullptr;
130 
131   // This shuts down the GATT profile and all of its clients.
132   gatt_ = nullptr;
133 
134   // Shuts down HCI command channel and ACL data channel.
135   hci_ = nullptr;
136 }
137 
BindToHostInterface(fidl::ServerEnd<fuchsia_bluetooth_host::Host> host_client)138 void BtHostComponent::BindToHostInterface(
139     fidl::ServerEnd<fuchsia_bluetooth_host::Host> host_client) {
140   if (host_server_) {
141     bt_log(WARN, "bt-host", "Host interface channel already open");
142     return;
143   }
144 
145   PW_DCHECK(gap_);
146   PW_DCHECK(gatt_);
147 
148   zx::channel channel = host_client.TakeChannel();
149 
150   host_server_ = std::make_unique<HostServer>(
151       std::move(channel), gap_->AsWeakPtr(), gatt_->GetWeakPtr());
152   host_server_->set_error_handler([this](zx_status_t status) {
153     PW_DCHECK(host_server_);
154     bt_log(WARN, "bt-host", "Host interface disconnected");
155     host_server_ = nullptr;
156   });
157 }
158 
159 }  // namespace bthost
160