1 /*
2  * Copyright 2018 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 "test_model.h"
18 
19 // TODO: Remove when registration works
20 #include "model/devices/beacon.h"
21 #include "model/devices/beacon_swarm.h"
22 #include "model/devices/car_kit.h"
23 #include "model/devices/classic.h"
24 #include "model/devices/keyboard.h"
25 #include "model/devices/remote_loopback_device.h"
26 #include "model/devices/scripted_beacon.h"
27 #include "model/devices/sniffer.h"
28 
29 #include <memory>
30 
31 #include <stdlib.h>
32 #include <iomanip>
33 #include <iostream>
34 
35 #include "base/files/file_util.h"
36 #include "base/json/json_reader.h"
37 #include "base/values.h"
38 
39 #include "os/log.h"
40 #include "include/phy.h"
41 #include "model/devices/hci_socket_device.h"
42 #include "model/devices/link_layer_socket_device.h"
43 
44 namespace test_vendor_lib {
45 
TestModel(std::function<AsyncUserId ()> get_user_id,std::function<AsyncTaskId (AsyncUserId,std::chrono::milliseconds,const TaskCallback &)> event_scheduler,std::function<AsyncTaskId (AsyncUserId,std::chrono::milliseconds,std::chrono::milliseconds,const TaskCallback &)> periodic_event_scheduler,std::function<void (AsyncUserId)> cancel_tasks_from_user,std::function<void (AsyncTaskId)> cancel,std::function<int (const std::string &,int)> connect_to_remote)46 TestModel::TestModel(
47     std::function<AsyncUserId()> get_user_id,
48     std::function<AsyncTaskId(AsyncUserId, std::chrono::milliseconds,
49                               const TaskCallback&)>
50         event_scheduler,
51 
52     std::function<AsyncTaskId(AsyncUserId, std::chrono::milliseconds,
53                               std::chrono::milliseconds, const TaskCallback&)>
54         periodic_event_scheduler,
55 
56     std::function<void(AsyncUserId)> cancel_tasks_from_user,
57     std::function<void(AsyncTaskId)> cancel,
58     std::function<int(const std::string&, int)> connect_to_remote)
59     : get_user_id_(std::move(get_user_id)),
60       schedule_task_(std::move(event_scheduler)),
61       schedule_periodic_task_(std::move(periodic_event_scheduler)),
62       cancel_task_(std::move(cancel)),
63       cancel_tasks_from_user_(std::move(cancel_tasks_from_user)),
64       connect_to_remote_(std::move(connect_to_remote)) {
65   model_user_id_ = get_user_id_();
66   // TODO: Remove when registration works!
67   example_devices_.push_back(std::make_shared<Beacon>());
68   example_devices_.push_back(std::make_shared<BeaconSwarm>());
69   example_devices_.push_back(std::make_shared<Keyboard>());
70   example_devices_.push_back(std::make_shared<CarKit>());
71   example_devices_.push_back(std::make_shared<Classic>());
72   example_devices_.push_back(std::make_shared<Sniffer>());
73   example_devices_.push_back(std::make_shared<ScriptedBeacon>());
74   example_devices_.push_back(std::make_shared<RemoteLoopbackDevice>());
75 }
76 
SetTimerPeriod(std::chrono::milliseconds new_period)77 void TestModel::SetTimerPeriod(std::chrono::milliseconds new_period) {
78   timer_period_ = new_period;
79 
80   if (timer_tick_task_ == kInvalidTaskId) return;
81 
82   // Restart the timer with the new period
83   StopTimer();
84   StartTimer();
85 }
86 
StartTimer()87 void TestModel::StartTimer() {
88   LOG_INFO("StartTimer()");
89   timer_tick_task_ = schedule_periodic_task_(
90       model_user_id_, std::chrono::milliseconds(0), timer_period_,
91       [this]() { TestModel::TimerTick(); });
92 }
93 
StopTimer()94 void TestModel::StopTimer() {
95   LOG_INFO("StopTimer()");
96   cancel_task_(timer_tick_task_);
97   timer_tick_task_ = kInvalidTaskId;
98 }
99 
Add(std::shared_ptr<Device> new_dev)100 size_t TestModel::Add(std::shared_ptr<Device> new_dev) {
101   devices_.push_back(std::move(new_dev));
102   return devices_.size() - 1;
103 }
104 
Del(size_t dev_index)105 void TestModel::Del(size_t dev_index) {
106   if (dev_index >= devices_.size() || devices_[dev_index] == nullptr) {
107     LOG_WARN("Unknown device %zu", dev_index);
108     return;
109   }
110   schedule_task_(model_user_id_, std::chrono::milliseconds(0),
111                  [this, dev_index]() {
112                    devices_[dev_index]->UnregisterPhyLayers();
113                    devices_[dev_index] = nullptr;
114                  });
115 }
116 
AddPhy(Phy::Type phy_type)117 size_t TestModel::AddPhy(Phy::Type phy_type) {
118   size_t factory_id = phys_.size();
119   phys_.emplace_back(phy_type, factory_id);
120   return factory_id;
121 }
122 
DelPhy(size_t phy_index)123 void TestModel::DelPhy(size_t phy_index) {
124   if (phy_index >= phys_.size()) {
125     LOG_WARN("Unknown phy at index %zu", phy_index);
126     return;
127   }
128   schedule_task_(
129       model_user_id_, std::chrono::milliseconds(0),
130       [this, phy_index]() { phys_[phy_index].UnregisterAllPhyLayers(); });
131 }
132 
AddDeviceToPhy(size_t dev_index,size_t phy_index)133 void TestModel::AddDeviceToPhy(size_t dev_index, size_t phy_index) {
134   if (dev_index >= devices_.size() || devices_[dev_index] == nullptr) {
135     LOG_WARN("Unknown device %zu", dev_index);
136     return;
137   }
138   if (phy_index >= phys_.size()) {
139     LOG_WARN("Can't find phy %zu", phy_index);
140     return;
141   }
142   auto dev = devices_[dev_index];
143   dev->RegisterPhyLayer(phys_[phy_index].GetPhyLayer(
144       [dev](model::packets::LinkLayerPacketView packet) {
145         dev->IncomingPacket(std::move(packet));
146       },
147       dev_index));
148 }
149 
DelDeviceFromPhy(size_t dev_index,size_t phy_index)150 void TestModel::DelDeviceFromPhy(size_t dev_index, size_t phy_index) {
151   if (dev_index >= devices_.size() || devices_[dev_index] == nullptr) {
152     LOG_WARN("Unknown device %zu", dev_index);
153     return;
154   }
155   if (phy_index >= phys_.size()) {
156     LOG_WARN("Can't find phy %zu", phy_index);
157     return;
158   }
159   schedule_task_(model_user_id_, std::chrono::milliseconds(0),
160                  [this, dev_index, phy_index]() {
161                    devices_[dev_index]->UnregisterPhyLayer(
162                        phys_[phy_index].GetType(),
163                        phys_[phy_index].GetFactoryId());
164                  });
165 }
166 
AddLinkLayerConnection(int socket_fd,Phy::Type phy_type)167 void TestModel::AddLinkLayerConnection(int socket_fd, Phy::Type phy_type) {
168   std::shared_ptr<Device> dev = LinkLayerSocketDevice::Create(socket_fd, phy_type);
169   int index = Add(dev);
170   for (size_t i = 0; i < phys_.size(); i++) {
171     if (phy_type == phys_[i].GetType()) {
172       AddDeviceToPhy(index, i);
173     }
174   }
175 }
176 
IncomingLinkLayerConnection(int socket_fd)177 void TestModel::IncomingLinkLayerConnection(int socket_fd) {
178   // TODO: Handle other phys
179   AddLinkLayerConnection(socket_fd, Phy::Type::BR_EDR);
180 }
181 
AddRemote(const std::string & server,int port,Phy::Type phy_type)182 void TestModel::AddRemote(const std::string& server, int port, Phy::Type phy_type) {
183   int socket_fd = connect_to_remote_(server, port);
184   if (socket_fd < 0) {
185     return;
186   }
187   AddLinkLayerConnection(socket_fd, phy_type);
188 }
189 
IncomingHciConnection(int socket_fd)190 void TestModel::IncomingHciConnection(int socket_fd) {
191   auto dev = HciSocketDevice::Create(socket_fd);
192   size_t index = Add(std::static_pointer_cast<Device>(dev));
193   std::string addr = "da:4c:10:de:17:";  // Da HCI dev
194   std::stringstream stream;
195   stream << std::setfill('0') << std::setw(2) << std::hex << (index % 256);
196   addr += stream.str();
197 
198   dev->Initialize({"IgnoredTypeName", addr});
199   LOG_INFO("initialized %s", addr.c_str());
200   for (size_t i = 0; i < phys_.size(); i++) {
201     AddDeviceToPhy(index, i);
202   }
203   AsyncUserId user_id = get_user_id_();
204   dev->RegisterTaskScheduler([user_id, this](std::chrono::milliseconds delay,
205                                              TaskCallback task_callback) {
206     return schedule_task_(user_id, delay, std::move(task_callback));
207   });
208   dev->RegisterTaskCancel(cancel_task_);
209   dev->RegisterCloseCallback([this, socket_fd, index, user_id] {
210     schedule_task_(user_id, std::chrono::milliseconds(0),
211                    [this, socket_fd, index, user_id]() {
212                      OnHciConnectionClosed(socket_fd, index, user_id);
213                    });
214   });
215 }
216 
OnHciConnectionClosed(int socket_fd,size_t index,AsyncUserId user_id)217 void TestModel::OnHciConnectionClosed(int socket_fd, size_t index,
218                                       AsyncUserId user_id) {
219   if (index >= devices_.size() || devices_[index] == nullptr) {
220     LOG_WARN("Unknown device %zu", index);
221     return;
222   }
223   int close_result = close(socket_fd);
224   ASSERT_LOG(close_result == 0, "can't close: %s", strerror(errno));
225 
226   cancel_tasks_from_user_(user_id);
227   devices_[index]->UnregisterPhyLayers();
228   devices_[index] = nullptr;
229 }
230 
SetDeviceAddress(size_t index,Address address)231 void TestModel::SetDeviceAddress(size_t index, Address address) {
232   if (index >= devices_.size() || devices_[index] == nullptr) {
233     LOG_WARN("Can't find device %zu", index);
234     return;
235   }
236   devices_[index]->SetAddress(std::move(address));
237 }
238 
List()239 const std::string& TestModel::List() {
240   list_string_ = "";
241   list_string_ += " Devices: \r\n";
242   for (size_t i = 0; i < devices_.size(); i++) {
243     list_string_ += "  " + std::to_string(i) + ":";
244     if (devices_[i] == nullptr) {
245       list_string_ += " deleted \r\n";
246     } else {
247       list_string_ += devices_[i]->ToString() + " \r\n";
248     }
249   }
250   list_string_ += " Phys: \r\n";
251   for (size_t i = 0; i < phys_.size(); i++) {
252     list_string_ += "  " + std::to_string(i) + ":";
253     list_string_ += phys_[i].ToString() + " \r\n";
254   }
255   return list_string_;
256 }
257 
TimerTick()258 void TestModel::TimerTick() {
259   for (size_t i = 0; i < devices_.size(); i++) {
260     if (devices_[i] != nullptr) {
261       devices_[i]->TimerTick();
262     }
263   }
264 }
265 
Reset()266 void TestModel::Reset() {
267   StopTimer();
268   schedule_task_(model_user_id_, std::chrono::milliseconds(0), [this]() {
269     LOG_INFO("Running Reset task");
270     for (size_t i = 0; i < devices_.size(); i++) {
271       if (devices_[i] != nullptr) {
272         devices_[i]->UnregisterPhyLayers();
273       }
274     }
275     devices_.clear();
276   });
277 }
278 
279 }  // namespace test_vendor_lib
280