1 // Copyright 2022 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://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,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "hci/bluetooth_facade.h"
16
17 #include <sys/types.h>
18
19 #include <array>
20 #include <cassert>
21 #include <chrono>
22 #include <cstdint>
23 #include <cstring>
24 #include <future>
25 #include <iostream>
26 #include <memory>
27 #include <unordered_map>
28 #include <utility>
29
30 #include "hci/address.h"
31 #include "hci/hci_packet_transport.h"
32 #include "model/setup/async_manager.h"
33 #include "model/setup/test_command_handler.h"
34 #include "model/setup/test_model.h"
35 #include "netsim-daemon/src/ffi.rs.h"
36 #include "netsim/config.pb.h"
37 #include "rust/cxx.h"
38 #include "util/filesystem.h"
39 #include "util/log.h"
40
41 #ifndef NETSIM_ANDROID_EMULATOR
42 #include "net/posix/posix_async_socket_server.h"
43 #endif
44
45 namespace rootcanal::log {
46 void SetLogColorEnable(bool);
47 }
48
49 namespace netsim::hci::facade {
50
51 int8_t SimComputeRssi(int send_id, int recv_id, int8_t tx_power);
52 void IncrTx(uint32_t send_id, rootcanal::Phy::Type phy_type);
53 void IncrRx(uint32_t receive_id, rootcanal::Phy::Type phy_type);
54
55 using namespace std::literals;
56 using namespace rootcanal;
57
58 using rootcanal::PhyDevice;
59 using rootcanal::PhyLayer;
60
61 class SimPhyLayer : public PhyLayer {
62 // for constructor inheritance
63 using PhyLayer::PhyLayer;
64
65 // Overrides ComputeRssi in PhyLayerFactory to provide
66 // simulated RSSI information using actual spatial
67 // device positions.
ComputeRssi(PhyDevice::Identifier sender_id,PhyDevice::Identifier receiver_id,int8_t tx_power)68 int8_t ComputeRssi(PhyDevice::Identifier sender_id,
69 PhyDevice::Identifier receiver_id,
70 int8_t tx_power) override {
71 return SimComputeRssi(sender_id, receiver_id, tx_power);
72 }
73
74 // Check if the device is present in the phy_devices
Contains(PhyDevice::Identifier device_id,const std::list<std::shared_ptr<rootcanal::PhyDevice>> & phy_devices)75 static bool Contains(
76 PhyDevice::Identifier device_id,
77 const std::list<std::shared_ptr<rootcanal::PhyDevice>> &phy_devices) {
78 return std::any_of(
79 phy_devices.begin(), phy_devices.end(),
80 [device_id](const auto &device) { return device->id == device_id; });
81 }
82
83 // Overrides Send in PhyLayerFactory to add Rx/Tx statistics.
Send(std::vector<uint8_t> const & packet,int8_t tx_power,PhyDevice::Identifier sender_id)84 void Send(std::vector<uint8_t> const &packet, int8_t tx_power,
85 PhyDevice::Identifier sender_id) override {
86 // Skip if the sender's phy is in the "down" state. Prevents all outgoing
87 // messages including advertisements occurring when the radio is down.
88 if (!Contains(sender_id, phy_devices_)) {
89 return;
90 }
91 IncrTx(sender_id, type);
92 for (const auto &device : phy_devices_) {
93 if (sender_id != device->id) {
94 IncrRx(device->id, type);
95 device->Receive(packet, type,
96 ComputeRssi(sender_id, device->id, tx_power));
97 }
98 }
99 }
100 };
101
102 class SimTestModel : public rootcanal::TestModel {
103 // for constructor inheritance
104 using rootcanal::TestModel::TestModel;
105
CreatePhyLayer(PhyLayer::Identifier id,rootcanal::Phy::Type type)106 std::unique_ptr<rootcanal::PhyLayer> CreatePhyLayer(
107 PhyLayer::Identifier id, rootcanal::Phy::Type type) override {
108 return std::make_unique<SimPhyLayer>(id, type);
109 }
110 };
111
112 size_t phy_low_energy_index_;
113 size_t phy_classic_index_;
114
115 bool gStarted = false;
116 std::shared_ptr<rootcanal::AsyncManager> gAsyncManager;
117 rootcanal::AsyncUserId gSocketUserId{};
118 std::shared_ptr<SimTestModel> gTestModel;
119 std::shared_ptr<rootcanal::configuration::Controller> controller_proto_;
120
121 #ifndef NETSIM_ANDROID_EMULATOR
122 // test port
123 std::unique_ptr<rootcanal::TestCommandHandler> gTestChannel;
124 std::unique_ptr<rootcanal::TestChannelTransport> gTestChannelTransport;
125 std::shared_ptr<AsyncDataChannelServer> gTestSocketServer;
126 bool gTestChannelOpen{false};
127 constexpr int kDefaultTestPort = 7500;
128 #endif
129
130 namespace {
131 #ifndef NETSIM_ANDROID_EMULATOR
132
133 using ::android::net::PosixAsyncSocketServer;
134
SetUpTestChannel(uint16_t instance_num)135 void SetUpTestChannel(uint16_t instance_num) {
136 gTestSocketServer = std::make_shared<PosixAsyncSocketServer>(
137 kDefaultTestPort + instance_num - 1, gAsyncManager.get());
138
139 gTestChannel = std::make_unique<rootcanal::TestCommandHandler>(*gTestModel);
140
141 gTestChannelTransport = std::make_unique<rootcanal::TestChannelTransport>();
142 gTestChannelTransport->RegisterCommandHandler(
143 [](const std::string &name, const std::vector<std::string> &args) {
144 gAsyncManager->ExecAsync(gSocketUserId, std::chrono::milliseconds(0),
145 [name, args]() {
146 std::string args_str = "";
147 for (auto arg : args) args_str += " " + arg;
148 if (name == "END_SIMULATION") {
149 } else {
150 gTestChannel->HandleCommand(name, args);
151 }
152 });
153 });
154
155 bool transport_configured = gTestChannelTransport->SetUp(
156 gTestSocketServer, [](std::shared_ptr<AsyncDataChannel> conn_fd,
157 AsyncDataChannelServer *server) {
158 BtsLogInfo("Test channel connection accepted.");
159 server->StartListening();
160 if (gTestChannelOpen) {
161 BtsLogWarn("Only one connection at a time is supported");
162 rootcanal::TestChannelTransport::SendResponse(
163 conn_fd, "The connection is broken");
164 return false;
165 }
166 gTestChannelOpen = true;
167 gTestChannel->RegisterSendResponse(
168 [conn_fd](const std::string &response) {
169 rootcanal::TestChannelTransport::SendResponse(conn_fd, response);
170 });
171
172 conn_fd->WatchForNonBlockingRead([](AsyncDataChannel *conn_fd) {
173 gTestChannelTransport->OnCommandReady(
174 conn_fd, []() { gTestChannelOpen = false; });
175 });
176 return false;
177 });
178
179 gTestChannel->SetTimerPeriod({"5"});
180 gTestChannel->StartTimer({});
181
182 if (!transport_configured) {
183 BtsLogError("Failed to set up test channel.");
184 return;
185 }
186
187 BtsLogInfo("Set up test channel.");
188 }
189 #endif
190
191 } // namespace
192
193 // Initialize the rootcanal library.
Start(const rust::Slice<::std::uint8_t const> proto_bytes,uint16_t instance_num)194 void Start(const rust::Slice<::std::uint8_t const> proto_bytes,
195 uint16_t instance_num) {
196 if (gStarted) return;
197
198 // output is to a file, so no color wanted
199 rootcanal::log::SetLogColorEnable(false);
200
201 config::Bluetooth config;
202 config.ParseFromArray(proto_bytes.data(), proto_bytes.size());
203 controller_proto_ = std::make_shared<rootcanal::configuration::Controller>(
204 config.properties());
205
206 // When emulators restore from a snapshot the PacketStreamer connection to
207 // netsim is recreated with a new (uninitialized) Rootcanal device. However
208 // the Android Bluetooth Stack does not re-initialize the controller. Our
209 // solution is for Rootcanal to recognize that it is receiving HCI commands
210 // before a HCI Reset. The flag below causes a hardware error event that
211 // triggers the Reset from the Bluetooth Stack.
212
213 controller_proto_->mutable_quirks()->set_hardware_error_before_reset(true);
214
215 gAsyncManager = std::make_shared<rootcanal::AsyncManager>();
216 // Get a user ID for tasks scheduled within the test environment.
217 gSocketUserId = gAsyncManager->GetNextUserId();
218
219 gTestModel = std::make_unique<SimTestModel>(
220 std::bind(&rootcanal::AsyncManager::GetNextUserId, gAsyncManager),
221 std::bind(&rootcanal::AsyncManager::ExecAsync, gAsyncManager,
222 std::placeholders::_1, std::placeholders::_2,
223 std::placeholders::_3),
224 std::bind(&rootcanal::AsyncManager::ExecAsyncPeriodically, gAsyncManager,
225 std::placeholders::_1, std::placeholders::_2,
226 std::placeholders::_3, std::placeholders::_4),
227 std::bind(&rootcanal::AsyncManager::CancelAsyncTasksFromUser,
228 gAsyncManager, std::placeholders::_1),
229 std::bind(&rootcanal::AsyncManager::CancelAsyncTask, gAsyncManager,
230 std::placeholders::_1),
231 [](const std::string & /* server */, int /* port */,
232 rootcanal::Phy::Type /* phy_type */) { return nullptr; });
233
234 // Disable Address Reuse if '--disable_address_reuse' flag is true
235 // Enable Address Reuse if 'address_reuse' is true
236 if (config.has_disable_address_reuse()) {
237 gTestModel->SetReuseDeviceAddresses(!config.disable_address_reuse());
238 }
239
240 // NOTE: 0:BR_EDR, 1:LOW_ENERGY. The order is used by bluetooth CTS.
241 phy_classic_index_ = gTestModel->AddPhy(rootcanal::Phy::Type::BR_EDR);
242 phy_low_energy_index_ = gTestModel->AddPhy(rootcanal::Phy::Type::LOW_ENERGY);
243
244 // TODO: Remove test channel.
245 #ifdef NETSIM_ANDROID_EMULATOR
246 auto testCommands = rootcanal::TestCommandHandler(*gTestModel);
247 testCommands.RegisterSendResponse([](const std::string &) {});
248 testCommands.SetTimerPeriod({"5"});
249 testCommands.StartTimer({});
250 #else
251 SetUpTestChannel(instance_num);
252 #endif
253 gStarted = true;
254 };
255
256 // Resets the root canal library.
Stop()257 void Stop() {
258 // TODO: Fix TestModel::Reset() in test_model.cc.
259 // gTestModel->Reset();
260 gStarted = false;
261 }
262
AddDeviceToPhy(uint32_t rootcanal_id,bool isLowEnergy)263 void AddDeviceToPhy(uint32_t rootcanal_id, bool isLowEnergy) {
264 auto phy_index = (isLowEnergy) ? phy_low_energy_index_ : phy_classic_index_;
265 gTestModel->AddDeviceToPhy(rootcanal_id, phy_index);
266 }
267
RemoveDeviceFromPhy(uint32_t rootcanal_id,bool isLowEnergy)268 void RemoveDeviceFromPhy(uint32_t rootcanal_id, bool isLowEnergy) {
269 auto phy_index = (isLowEnergy) ? phy_low_energy_index_ : phy_classic_index_;
270 gTestModel->RemoveDeviceFromPhy(rootcanal_id, phy_index);
271 }
272
273 class ChipInfo {
274 public:
275 uint32_t chip_id;
276 std::shared_ptr<model::Chip::Bluetooth> model;
277 int le_tx_count = 0;
278 int classic_tx_count = 0;
279 int le_rx_count = 0;
280 int classic_rx_count = 0;
281 std::shared_ptr<rootcanal::configuration::Controller> controller_proto;
282 std::unique_ptr<rootcanal::ControllerProperties> controller_properties;
283
ChipInfo(uint32_t chip_id,std::shared_ptr<model::Chip::Bluetooth> model)284 ChipInfo(uint32_t chip_id, std::shared_ptr<model::Chip::Bluetooth> model)
285 : chip_id(chip_id), model(model) {}
ChipInfo(uint32_t chip_id,std::shared_ptr<model::Chip::Bluetooth> model,std::shared_ptr<rootcanal::configuration::Controller> controller_proto,std::unique_ptr<rootcanal::ControllerProperties> controller_properties)286 ChipInfo(
287 uint32_t chip_id, std::shared_ptr<model::Chip::Bluetooth> model,
288 std::shared_ptr<rootcanal::configuration::Controller> controller_proto,
289 std::unique_ptr<rootcanal::ControllerProperties> controller_properties)
290 : chip_id(chip_id),
291 model(model),
292 controller_proto(std::move(controller_proto)),
293 controller_properties(std::move(controller_properties)) {}
294 };
295
296 std::unordered_map<uint32_t, std::shared_ptr<ChipInfo>> id_to_chip_info_;
297
Get(uint32_t id)298 model::Chip::Bluetooth Get(uint32_t id) {
299 model::Chip::Bluetooth model;
300 if (id_to_chip_info_.find(id) != id_to_chip_info_.end()) {
301 model.CopyFrom(*id_to_chip_info_[id]->model.get());
302 auto chip_info = id_to_chip_info_[id];
303 model.mutable_classic()->set_tx_count(chip_info->classic_tx_count);
304 model.mutable_classic()->set_rx_count(chip_info->classic_rx_count);
305 model.mutable_low_energy()->set_tx_count(chip_info->le_tx_count);
306 model.mutable_low_energy()->set_rx_count(chip_info->le_rx_count);
307 if (chip_info->controller_proto) {
308 model.mutable_bt_properties()->CopyFrom(*chip_info->controller_proto);
309 }
310 }
311 return model;
312 }
313
Reset(uint32_t id)314 void Reset(uint32_t id) {
315 if (auto it = id_to_chip_info_.find(id); it != id_to_chip_info_.end()) {
316 auto chip_info = it->second;
317 chip_info->le_tx_count = 0;
318 chip_info->le_rx_count = 0;
319 chip_info->classic_tx_count = 0;
320 chip_info->classic_rx_count = 0;
321 }
322 // First remove LOW_ENERGY and BR_EDR Phy
323 RemoveDeviceFromPhy(id, true);
324 RemoveDeviceFromPhy(id, false);
325 // Add to LOW_ENERGY and BR_EDR Phy
326 AddDeviceToPhy(id, true);
327 AddDeviceToPhy(id, false);
328 }
329
Remove(uint32_t id)330 void Remove(uint32_t id) {
331 BtsLogInfo("Removing HCI chip rootcanal_id: %d.", id);
332 id_to_chip_info_.erase(id);
333 // Call the transport close callback. This invokes HciDevice::Close and
334 // TestModel close callback.
335 gAsyncManager->ExecAsync(gSocketUserId, std::chrono::milliseconds(0), [id]() {
336 // rootcanal will call HciPacketTransport::Close().
337 HciPacketTransport::Remove(id);
338 });
339 }
340
341 // Rename AddChip(model::Chip, device, transport)
342
Add(uint32_t chip_id,const std::string & address_string,const rust::Slice<::std::uint8_t const> controller_proto_bytes)343 uint32_t Add(uint32_t chip_id, const std::string &address_string,
344 const rust::Slice<::std::uint8_t const> controller_proto_bytes) {
345 auto transport = std::make_shared<HciPacketTransport>(chip_id, gAsyncManager);
346
347 std::shared_ptr<rootcanal::configuration::Controller> controller_proto =
348 controller_proto_;
349 // If the Bluetooth Controller protobuf is provided, we use the provided
350 if (controller_proto_bytes.size() != 0) {
351 rootcanal::configuration::Controller custom_proto;
352 custom_proto.ParseFromArray(controller_proto_bytes.data(),
353 controller_proto_bytes.size());
354 BtsLogInfo("chip_id: %d has rootcanal Controller configuration: %s",
355 chip_id, custom_proto.ShortDebugString().c_str());
356
357 // When emulators restore from a snapshot the PacketStreamer connection to
358 // netsim is recreated with a new (uninitialized) Rootcanal device. However
359 // the Android Bluetooth Stack does not re-initialize the controller. Our
360 // solution is for Rootcanal to recognize that it is receiving HCI commands
361 // before a HCI Reset. The flag below causes a hardware error event that
362 // triggers the Reset from the Bluetooth Stack.
363 custom_proto.mutable_quirks()->set_hardware_error_before_reset(true);
364
365 controller_proto =
366 std::make_shared<rootcanal::configuration::Controller>(custom_proto);
367 }
368 std::unique_ptr<rootcanal::ControllerProperties> controller_properties =
369 std::make_unique<rootcanal::ControllerProperties>(*controller_proto);
370
371 auto hci_device =
372 std::make_shared<rootcanal::HciDevice>(transport, *controller_properties);
373
374 // Pass netsim::hci::facade::ReportInvalidPacket signature into hci_device
375 hci_device->RegisterInvalidPacketHandler(
376 [](uint32_t rootcanal_id, rootcanal::InvalidPacketReason reason,
377 std::string description, const std::vector<uint8_t> &packet) {
378 netsim::hci::facade::ReportInvalidPacket(
379 rootcanal_id, static_cast<int32_t>(reason), description, packet);
380 });
381
382 // Use the `AsyncManager` to ensure that the `AddHciConnection` method is
383 // invoked atomically, preventing data races.
384 std::promise<uint32_t> rootcanal_id_promise;
385 auto rootcanal_id_future = rootcanal_id_promise.get_future();
386
387 std::optional<Address> address_option;
388 if (address_string != "") {
389 address_option = rootcanal::Address::FromString(address_string);
390 }
391 gAsyncManager->ExecAsync(
392 gSocketUserId, std::chrono::milliseconds(0),
393 [hci_device, &rootcanal_id_promise, address_option]() {
394 rootcanal_id_promise.set_value(
395 gTestModel->AddHciConnection(hci_device, address_option));
396 });
397 auto rootcanal_id = rootcanal_id_future.get();
398
399 HciPacketTransport::Add(rootcanal_id, transport);
400 BtsLogInfo("Creating HCI rootcanal_id: %d for chip_id: %d", rootcanal_id,
401 chip_id);
402
403 auto model = std::make_shared<model::Chip::Bluetooth>();
404 model->mutable_classic()->set_state(true);
405 model->mutable_low_energy()->set_state(true);
406
407 id_to_chip_info_.emplace(rootcanal_id, std::make_shared<ChipInfo>(
408 chip_id, model, controller_proto,
409 std::move(controller_properties)));
410 return rootcanal_id;
411 }
412
RemoveRustDevice(uint32_t rootcanal_id)413 void RemoveRustDevice(uint32_t rootcanal_id) {
414 gTestModel->RemoveDevice(rootcanal_id);
415 }
416
AddRustDevice(uint32_t chip_id,rust::Box<DynRustBluetoothChipCallbacks> callbacks,const std::string & type,const std::string & address)417 rust::Box<AddRustDeviceResult> AddRustDevice(
418 uint32_t chip_id, rust::Box<DynRustBluetoothChipCallbacks> callbacks,
419 const std::string &type, const std::string &address) {
420 auto rust_device =
421 std::make_shared<RustDevice>(std::move(callbacks), type, address);
422
423 // TODO: Use the `AsyncManager` to ensure that the `AddDevice` and
424 // `AddDeviceToPhy` methods are invoked atomically, preventing data races.
425 // For unknown reason, use `AsyncManager` hangs.
426 auto rootcanal_id = gTestModel->AddDevice(rust_device);
427 gTestModel->AddDeviceToPhy(rootcanal_id, phy_low_energy_index_);
428
429 auto model = std::make_shared<model::Chip::Bluetooth>();
430 // Only enable ble for beacon.
431 model->mutable_low_energy()->set_state(true);
432 id_to_chip_info_.emplace(rootcanal_id,
433 std::make_shared<ChipInfo>(chip_id, model));
434 return CreateAddRustDeviceResult(
435 rootcanal_id, std::make_unique<RustBluetoothChip>(rust_device));
436 }
437
SetRustDeviceAddress(uint32_t rootcanal_id,std::array<uint8_t,rootcanal::Address::kLength> address)438 void SetRustDeviceAddress(
439 uint32_t rootcanal_id,
440 std::array<uint8_t, rootcanal::Address::kLength> address) {
441 uint8_t addr[rootcanal::Address::kLength];
442 std::memcpy(addr, address.data(), rootcanal::Address::kLength);
443 gTestModel->SetDeviceAddress(rootcanal_id, rootcanal::Address(addr));
444 }
445
IncrTx(uint32_t id,rootcanal::Phy::Type phy_type)446 void IncrTx(uint32_t id, rootcanal::Phy::Type phy_type) {
447 if (auto it = id_to_chip_info_.find(id); it != id_to_chip_info_.end()) {
448 auto chip_info = it->second;
449 if (phy_type == rootcanal::Phy::Type::LOW_ENERGY) {
450 chip_info->le_tx_count++;
451 } else {
452 chip_info->classic_tx_count++;
453 }
454 }
455 }
456
IncrRx(uint32_t id,rootcanal::Phy::Type phy_type)457 void IncrRx(uint32_t id, rootcanal::Phy::Type phy_type) {
458 if (auto it = id_to_chip_info_.find(id); it != id_to_chip_info_.end()) {
459 auto chip_info = it->second;
460 if (phy_type == rootcanal::Phy::Type::LOW_ENERGY) {
461 chip_info->le_rx_count++;
462 } else {
463 chip_info->classic_rx_count++;
464 }
465 }
466 }
467
468 // TODO: Make SimComputeRssi invoke netsim::device::GetDistanceRust with dev
469 // flag
SimComputeRssi(int send_id,int recv_id,int8_t tx_power)470 int8_t SimComputeRssi(int send_id, int recv_id, int8_t tx_power) {
471 if (id_to_chip_info_.find(send_id) == id_to_chip_info_.end() ||
472 id_to_chip_info_.find(recv_id) == id_to_chip_info_.end()) {
473 #ifdef NETSIM_ANDROID_EMULATOR
474 // NOTE: Ignore log messages in Cuttlefish for beacon devices created by
475 // test channel.
476 BtsLogWarn("Missing chip_info");
477 #endif
478 return tx_power;
479 }
480 auto a = id_to_chip_info_[send_id]->chip_id;
481 auto b = id_to_chip_info_[recv_id]->chip_id;
482 auto distance = netsim::device::GetDistanceCxx(a, b);
483 return netsim::DistanceToRssi(tx_power, distance);
484 }
485
GetCxx(uint32_t id)486 rust::Vec<::std::uint8_t> GetCxx(uint32_t id) {
487 auto bluetooth = Get(id);
488 std::vector<uint8_t> proto_bytes(bluetooth.ByteSizeLong());
489 bluetooth.SerializeToArray(proto_bytes.data(), proto_bytes.size());
490 rust::Vec<uint8_t> proto_rust_bytes;
491 std::copy(proto_bytes.begin(), proto_bytes.end(),
492 std::back_inserter(proto_rust_bytes));
493 return proto_rust_bytes;
494 }
495
496 } // namespace netsim::hci::facade
497