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