• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <pw_assert/check.h>
20 
21 #include "lib/async/default.h"
22 #include "pw_bluetooth_sapphire/fuchsia/bt_host/bt_host_config.h"
23 #include "pw_bluetooth_sapphire/fuchsia/host/controllers/fidl_controller.h"
24 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/host_server.h"
25 #include "pw_bluetooth_sapphire/internal/host/common/log.h"
26 #include "pw_bluetooth_sapphire/internal/host/common/random.h"
27 
28 using namespace bt;
29 
30 namespace bthost {
31 
BtHostComponent(async_dispatcher_t * dispatcher,const std::string & device_path,bool initialize_rng)32 BtHostComponent::BtHostComponent(async_dispatcher_t* dispatcher,
33                                  const std::string& device_path,
34                                  bool initialize_rng)
35     : pw_dispatcher_(dispatcher),
36       device_path_(device_path),
37       initialize_rng_(initialize_rng),
38       inspector_(inspect::ComponentInspector(dispatcher, {})) {
39   if (initialize_rng) {
40     set_random_generator(&random_generator_);
41   }
42   inspector_.root().RecordString("name", device_path_);
43 }
44 
~BtHostComponent()45 BtHostComponent::~BtHostComponent() {
46   if (initialize_rng_) {
47     set_random_generator(nullptr);
48   }
49 }
50 
51 // static
Create(async_dispatcher_t * dispatcher,const std::string & device_path)52 std::unique_ptr<BtHostComponent> BtHostComponent::Create(
53     async_dispatcher_t* dispatcher, const std::string& device_path) {
54   std::unique_ptr<BtHostComponent> host(
55       new BtHostComponent(dispatcher, device_path, /*initialize_rng=*/true));
56   return host;
57 }
58 
59 // static
CreateForTesting(async_dispatcher_t * dispatcher,const std::string & device_path)60 std::unique_ptr<BtHostComponent> BtHostComponent::CreateForTesting(
61     async_dispatcher_t* dispatcher, const std::string& device_path) {
62   std::unique_ptr<BtHostComponent> host(
63       new BtHostComponent(dispatcher, device_path, /*initialize_rng=*/false));
64   return host;
65 }
66 
Initialize(fidl::ClientEnd<fuchsia_hardware_bluetooth::Vendor> vendor_client_end,InitCallback init_cb,ErrorCallback error_cb,bool legacy_pairing_enabled)67 bool BtHostComponent::Initialize(
68     fidl::ClientEnd<fuchsia_hardware_bluetooth::Vendor> vendor_client_end,
69     InitCallback init_cb,
70     ErrorCallback error_cb,
71     bool legacy_pairing_enabled) {
72   std::unique_ptr<bt::controllers::FidlController> controller =
73       std::make_unique<bt::controllers::FidlController>(
74           std::move(vendor_client_end), async_get_default_dispatcher());
75 
76   bt_log(INFO, "bt-host", "Create HCI transport layer");
77   hci_ =
78       std::make_unique<hci::Transport>(std::move(controller), pw_dispatcher_);
79 
80   bt_log(INFO, "bt-host", "Create GATT layer");
81   gatt_ = gatt::GATT::Create();
82   gap::Adapter::Config config = {
83       .legacy_pairing_enabled = legacy_pairing_enabled,
84   };
85   gap_ = gap::Adapter::Create(
86       pw_dispatcher_, hci_->GetWeakPtr(), gatt_->GetWeakPtr(), config);
87   if (!gap_) {
88     bt_log(WARN, "bt-host", "GAP could not be created");
89     return false;
90   }
91   gap_->AttachInspect(inspector_.root(), "adapter");
92 
93   // Called when the GAP layer is ready. We initialize the GATT profile after
94   // initial setup in GAP. The data domain will be initialized by GAP because it
95   // both sets up the HCI ACL data channel that L2CAP relies on and registers
96   // L2CAP services.
97   auto gap_init_callback = [callback =
98                                 std::move(init_cb)](bool success) mutable {
99     bt_log(DEBUG,
100            "bt-host",
101            "GAP init complete status: (%s)",
102            (success ? "success" : "failure"));
103     callback(success);
104   };
105 
106   auto transport_closed_callback = [error_cb = std::move(error_cb)]() mutable {
107     bt_log(WARN, "bt-host", "HCI transport has closed");
108     error_cb();
109   };
110 
111   bt_log(DEBUG, "bt-host", "Initializing GAP");
112   return gap_->Initialize(std::move(gap_init_callback),
113                           std::move(transport_closed_callback));
114 }
115 
ShutDown()116 void BtHostComponent::ShutDown() {
117   bt_log(DEBUG, "bt-host", "Shutting down");
118 
119   if (!gap_) {
120     bt_log(DEBUG, "bt-host", "Already shut down");
121     return;
122   }
123 
124   // Closes all FIDL channels owned by |host_server_|.
125   host_server_ = nullptr;
126 
127   // Make sure that |gap_| gets shut down and destroyed on its creation thread
128   // as it is not thread-safe.
129   gap_->ShutDown();
130   gap_ = nullptr;
131 
132   // This shuts down the GATT profile and all of its clients.
133   gatt_ = nullptr;
134 
135   // Shuts down HCI command channel and ACL data channel.
136   hci_ = nullptr;
137 }
138 
BindToHostInterface(fidl::ServerEnd<fuchsia_bluetooth_host::Host> host_client)139 void BtHostComponent::BindToHostInterface(
140     fidl::ServerEnd<fuchsia_bluetooth_host::Host> host_client) {
141   if (host_server_) {
142     bt_log(WARN, "bt-host", "Host interface channel already open");
143     return;
144   }
145 
146   PW_DCHECK(gap_);
147   PW_DCHECK(gatt_);
148 
149   zx::channel channel = host_client.TakeChannel();
150 
151   host_server_ = std::make_unique<HostServer>(
152       std::move(channel), gap_->AsWeakPtr(), gatt_->GetWeakPtr());
153   host_server_->set_error_handler([this](zx_status_t status) {
154     PW_DCHECK(host_server_);
155     bt_log(WARN, "bt-host", "Host interface disconnected");
156     host_server_ = nullptr;
157   });
158 }
159 
160 }  // namespace bthost
161