1 /*
2 * Copyright (C) 2023 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 "host/libs/input_connector/socket_input_connector.h"
18
19 #include <linux/input.h>
20
21 #include <functional>
22 #include <map>
23 #include <memory>
24 #include <mutex>
25 #include <set>
26 #include <thread>
27 #include <vector>
28
29 #include "common/libs/fs/shared_buf.h"
30 #include "common/libs/fs/shared_fd.h"
31 #include "common/libs/utils/result.h"
32 #include "host/libs/config/cuttlefish_config.h"
33
34 namespace cuttlefish {
35
36 namespace {
37
38 struct virtio_input_event {
39 uint16_t type;
40 uint16_t code;
41 int32_t value;
42 };
43
44 struct InputEventsBuffer {
45 virtual ~InputEventsBuffer() = default;
46 virtual void AddEvent(uint16_t type, uint16_t code, int32_t value) = 0;
47 virtual size_t size() const = 0;
48 virtual const void* data() const = 0;
49 };
50
51 template <typename T>
52 struct InputEventsBufferImpl : public InputEventsBuffer {
InputEventsBufferImplcuttlefish::__anona0d8e5f60111::InputEventsBufferImpl53 InputEventsBufferImpl(size_t num_events) { buffer_.reserve(num_events); }
AddEventcuttlefish::__anona0d8e5f60111::InputEventsBufferImpl54 void AddEvent(uint16_t type, uint16_t code, int32_t value) override {
55 buffer_.push_back({.type = type, .code = code, .value = value});
56 }
datacuttlefish::__anona0d8e5f60111::InputEventsBufferImpl57 T* data() { return buffer_.data(); }
datacuttlefish::__anona0d8e5f60111::InputEventsBufferImpl58 const void* data() const override { return buffer_.data(); }
sizecuttlefish::__anona0d8e5f60111::InputEventsBufferImpl59 std::size_t size() const override { return buffer_.size() * sizeof(T); }
60
61 private:
62 std::vector<T> buffer_;
63 };
64
CreateBuffer(InputEventType event_type,size_t num_events)65 std::unique_ptr<InputEventsBuffer> CreateBuffer(InputEventType event_type,
66 size_t num_events) {
67 switch (event_type) {
68 case InputEventType::Virtio:
69 return std::unique_ptr<InputEventsBuffer>(
70 new InputEventsBufferImpl<virtio_input_event>(num_events));
71 case InputEventType::Evdev:
72 return std::unique_ptr<InputEventsBuffer>(
73 new InputEventsBufferImpl<input_event>(num_events));
74 }
75 }
76
77 } // namespace
78
79 class InputSocket {
80 public:
InputSocket(SharedFD server)81 InputSocket(SharedFD server)
82 : server_(server), monitor_(std::thread([this]() { MonitorLoop(); })) {}
83
84 Result<void> WriteEvents(std::unique_ptr<InputEventsBuffer> buffer);
85
86 private:
87 SharedFD server_;
88 SharedFD client_;
89 std::mutex client_mtx_;
90 std::thread monitor_;
91
92 void MonitorLoop();
93 };
94
MonitorLoop()95 void InputSocket::MonitorLoop() {
96 for (;;) {
97 client_ = SharedFD::Accept(*server_);
98 if (!client_->IsOpen()) {
99 LOG(ERROR) << "Failed to accept on input socket: " << client_->StrError();
100 continue;
101 }
102 do {
103 // Keep reading from the fd to detect when it closes.
104 char buf[128];
105 auto res = client_->Read(buf, sizeof(buf));
106 if (res < 0) {
107 LOG(ERROR) << "Failed to read from input client: "
108 << client_->StrError();
109 } else if (res > 0) {
110 LOG(VERBOSE) << "Received " << res << " bytes on input socket";
111 } else {
112 std::lock_guard<std::mutex> lock(client_mtx_);
113 client_->Close();
114 }
115 } while (client_->IsOpen());
116 }
117 }
118
WriteEvents(std::unique_ptr<InputEventsBuffer> buffer)119 Result<void> InputSocket::WriteEvents(
120 std::unique_ptr<InputEventsBuffer> buffer) {
121 std::lock_guard<std::mutex> lock(client_mtx_);
122 CF_EXPECT(client_->IsOpen(), "No input client connected");
123 auto res = WriteAll(client_, reinterpret_cast<const char*>(buffer->data()),
124 buffer->size());
125 CF_EXPECT(res == buffer->size(), "Failed to write entire event buffer: wrote "
126 << res << " of " << buffer->size()
127 << "bytes");
128 return {};
129 }
130
131 class TouchDevice {
132 public:
TouchDevice(std::unique_ptr<InputSocket> s)133 TouchDevice(std::unique_ptr<InputSocket> s) : socket_(std::move(s)) {}
134
WriteEvents(std::unique_ptr<InputEventsBuffer> buffer)135 Result<void> WriteEvents(std::unique_ptr<InputEventsBuffer> buffer) {
136 return socket_->WriteEvents(std::move(buffer));
137 }
138
HasSlot(void * source,int32_t id)139 bool HasSlot(void* source, int32_t id) {
140 std::lock_guard<std::mutex> lock(slots_mtx_);
141 return slots_by_source_and_id_.find({source, id}) !=
142 slots_by_source_and_id_.end();
143 }
144
GetOrAcquireSlot(void * source,int32_t id)145 int32_t GetOrAcquireSlot(void* source, int32_t id) {
146 std::lock_guard<std::mutex> lock(slots_mtx_);
147 auto slot_it = slots_by_source_and_id_.find({source, id});
148 if (slot_it != slots_by_source_and_id_.end()) {
149 return slot_it->second;
150 }
151 return slots_by_source_and_id_[std::make_pair(source, id)] = UseNewSlot();
152 }
153
ReleaseSlot(void * source,int32_t id)154 void ReleaseSlot(void* source, int32_t id) {
155 std::lock_guard<std::mutex> lock(slots_mtx_);
156 auto slot_it = slots_by_source_and_id_.find({source, id});
157 if (slot_it == slots_by_source_and_id_.end()) {
158 return;
159 }
160 slots_by_source_and_id_.erase(slot_it);
161 active_slots_[slot_it->second] = false;
162 }
163
NumActiveSlots()164 size_t NumActiveSlots() {
165 std::lock_guard<std::mutex> lock(slots_mtx_);
166 return slots_by_source_and_id_.size();
167 }
168
169 // The InputConnector holds state of on-going touch contacts. Event sources
170 // that can produce multi touch events should call this function when it's
171 // known they won't produce any more events (because, for example, the
172 // streaming client disconnected) to make sure no stale touch contacts
173 // remain. This addresses issues arising from clients disconnecting in the
174 // middle of a touch action.
OnDisconnectedSource(void * source)175 void OnDisconnectedSource(void* source) {
176 std::lock_guard<std::mutex> lock(slots_mtx_);
177 auto it = slots_by_source_and_id_.begin();
178 while (it != slots_by_source_and_id_.end()) {
179 if (it->first.first == source) {
180 active_slots_[it->second] = false;
181 it = slots_by_source_and_id_.erase(it);
182 } else {
183 ++it;
184 }
185 }
186 }
187
188 private:
UseNewSlot()189 int32_t UseNewSlot() {
190 // This is not the most efficient implementation for a large number of
191 // slots, but that case should be extremely rare. For the typical number of
192 // slots iterating over a vector is likely faster than using other data
193 // structures.
194 for (auto slot = 0; slot < active_slots_.size(); ++slot) {
195 if (!active_slots_[slot]) {
196 active_slots_[slot] = true;
197 return slot;
198 }
199 }
200 active_slots_.push_back(true);
201 return active_slots_.size() - 1;
202 }
203
204 std::unique_ptr<InputSocket> socket_;
205
206 std::mutex slots_mtx_;
207 std::map<std::pair<void*, int32_t>, int32_t> slots_by_source_and_id_;
208 std::vector<bool> active_slots_;
209 };
210
211 struct InputDevices {
212 InputEventType event_type;
213 // TODO (b/186773052): Finding strings in a map for every input event may
214 // introduce unwanted latency.
215 std::map<std::string, TouchDevice> multitouch_devices;
216 std::map<std::string, TouchDevice> touch_devices;
217
218 std::unique_ptr<InputSocket> keyboard;
219 std::unique_ptr<InputSocket> switches;
220 std::unique_ptr<InputSocket> rotary;
221 };
222
223 // Implements the InputConnector::EventSink interface using unix socket based
224 // virtual input devices.
225 class InputSocketsEventSink : public InputConnector::EventSink {
226 public:
227 InputSocketsEventSink(InputDevices&, std::atomic<int>&);
228 ~InputSocketsEventSink() override;
229
230 Result<void> SendTouchEvent(const std::string& device_label, int x, int y,
231 bool down) override;
232 Result<void> SendMultiTouchEvent(const std::string& device_label,
233 const std::vector<MultitouchSlot>& slots,
234 bool down) override;
235 Result<void> SendKeyboardEvent(uint16_t code, bool down) override;
236 Result<void> SendRotaryEvent(int pixels) override;
237 Result<void> SendSwitchesEvent(uint16_t code, bool state) override;
238
239 private:
240 InputDevices& input_devices_;
241 std::atomic<int>& sinks_count_;
242 };
243
InputSocketsEventSink(InputDevices & devices,std::atomic<int> & count)244 InputSocketsEventSink::InputSocketsEventSink(InputDevices& devices,
245 std::atomic<int>& count)
246 : input_devices_(devices), sinks_count_(count) {
247 ++sinks_count_;
248 }
249
~InputSocketsEventSink()250 InputSocketsEventSink::~InputSocketsEventSink() {
251 for (auto& it : input_devices_.multitouch_devices) {
252 it.second.OnDisconnectedSource(this);
253 }
254 for (auto& it : input_devices_.touch_devices) {
255 it.second.OnDisconnectedSource(this);
256 }
257 --sinks_count_;
258 }
259
SendTouchEvent(const std::string & device_label,int x,int y,bool down)260 Result<void> InputSocketsEventSink::SendTouchEvent(
261 const std::string& device_label, int x, int y, bool down) {
262 auto buffer = CreateBuffer(input_devices_.event_type, 4);
263 CF_EXPECT(buffer != nullptr, "Failed to allocate input events buffer");
264 buffer->AddEvent(EV_ABS, ABS_X, x);
265 buffer->AddEvent(EV_ABS, ABS_Y, y);
266 buffer->AddEvent(EV_KEY, BTN_TOUCH, down);
267 buffer->AddEvent(EV_SYN, SYN_REPORT, 0);
268 auto ts_it = input_devices_.touch_devices.find(device_label);
269 CF_EXPECT(ts_it != input_devices_.touch_devices.end(),
270 "Unknown touch device: " << device_label);
271 auto& ts = ts_it->second;
272 ts.WriteEvents(std::move(buffer));
273 return {};
274 }
275
SendMultiTouchEvent(const std::string & device_label,const std::vector<MultitouchSlot> & slots,bool down)276 Result<void> InputSocketsEventSink::SendMultiTouchEvent(
277 const std::string& device_label, const std::vector<MultitouchSlot>& slots,
278 bool down) {
279 auto buffer = CreateBuffer(input_devices_.event_type, 1 + 7 * slots.size());
280 CF_EXPECT(buffer != nullptr, "Failed to allocate input events buffer");
281
282 auto ts_it = input_devices_.multitouch_devices.find(device_label);
283 if (ts_it == input_devices_.multitouch_devices.end()) {
284 for (const auto& slot : slots) {
285 CF_EXPECT(SendTouchEvent(device_label, slot.x, slot.y, down));
286 }
287 return {};
288 }
289 auto& ts = ts_it->second;
290
291 for (auto& f : slots) {
292 auto this_id = f.id;
293 auto this_x = f.x;
294 auto this_y = f.y;
295
296 auto is_new_contact = !ts.HasSlot(this, this_id);
297 auto was_down = ts.NumActiveSlots() > 0;
298
299 // Make sure to call HasSlot before this line or it will always return true
300 auto this_slot = ts.GetOrAcquireSlot(this, this_id);
301
302 // BTN_TOUCH DOWN must be the first event in a series
303 if (down && !was_down) {
304 buffer->AddEvent(EV_KEY, BTN_TOUCH, 1);
305 }
306
307 buffer->AddEvent(EV_ABS, ABS_MT_SLOT, this_slot);
308 if (down) {
309 if (is_new_contact) {
310 // We already assigned this slot to this source and id combination, we
311 // could use any tracking id for the slot as long as it's greater than 0
312 buffer->AddEvent(EV_ABS, ABS_MT_TRACKING_ID, this_id);
313 }
314 buffer->AddEvent(EV_ABS, ABS_MT_POSITION_X, this_x);
315 buffer->AddEvent(EV_ABS, ABS_MT_POSITION_Y, this_y);
316 } else {
317 // released touch
318 buffer->AddEvent(EV_ABS, ABS_MT_TRACKING_ID, -1);
319 ts.ReleaseSlot(this, this_id);
320 }
321 // Send BTN_TOUCH UP when no more contacts are detected
322 if (was_down && ts.NumActiveSlots() == 0) {
323 buffer->AddEvent(EV_KEY, BTN_TOUCH, 0);
324 }
325 }
326
327 buffer->AddEvent(EV_SYN, SYN_REPORT, 0);
328 ts.WriteEvents(std::move(buffer));
329 return {};
330 }
331
SendKeyboardEvent(uint16_t code,bool down)332 Result<void> InputSocketsEventSink::SendKeyboardEvent(uint16_t code,
333 bool down) {
334 CF_EXPECT(input_devices_.keyboard != nullptr, "No keyboard device setup");
335 auto buffer = CreateBuffer(input_devices_.event_type, 2);
336 CF_EXPECT(buffer != nullptr, "Failed to allocate input events buffer");
337 buffer->AddEvent(EV_KEY, code, down);
338 buffer->AddEvent(EV_SYN, SYN_REPORT, 0);
339 input_devices_.keyboard->WriteEvents(std::move(buffer));
340 return {};
341 }
342
SendRotaryEvent(int pixels)343 Result<void> InputSocketsEventSink::SendRotaryEvent(int pixels) {
344 CF_EXPECT(input_devices_.rotary != nullptr, "No rotary device setup");
345 auto buffer = CreateBuffer(input_devices_.event_type, 2);
346 CF_EXPECT(buffer != nullptr, "Failed to allocate input events buffer");
347 buffer->AddEvent(EV_REL, REL_WHEEL, pixels);
348 buffer->AddEvent(EV_SYN, SYN_REPORT, 0);
349 input_devices_.rotary->WriteEvents(std::move(buffer));
350 return {};
351 }
352
SendSwitchesEvent(uint16_t code,bool state)353 Result<void> InputSocketsEventSink::SendSwitchesEvent(uint16_t code,
354 bool state) {
355 CF_EXPECT(input_devices_.switches != nullptr, "No switches device setup");
356 auto buffer = CreateBuffer(input_devices_.event_type, 2);
357 CF_EXPECT(buffer != nullptr, "Failed to allocate input events buffer");
358 buffer->AddEvent(EV_SW, code, state);
359 buffer->AddEvent(EV_SYN, SYN_REPORT, 0);
360 input_devices_.switches->WriteEvents(std::move(buffer));
361 return {};
362 }
363
364 class InputSocketsConnector : public InputConnector {
365 public:
InputSocketsConnector(InputEventType type)366 InputSocketsConnector(InputEventType type) : devices_{.event_type = type} {}
367 ~InputSocketsConnector();
368
369 std::unique_ptr<EventSink> CreateSink() override;
370
371 private:
372 InputDevices devices_;
373 // Counts the number of events sinks to make sure the class is not destroyed
374 // while any of its sinks still exists.
375 std::atomic<int> sinks_count_ = 0;
376 friend class InputSocketsConnectorBuilder;
377 };
378
~InputSocketsConnector()379 InputSocketsConnector::~InputSocketsConnector() {
380 CHECK(sinks_count_ == 0) << "Input connector destroyed with " << sinks_count_
381 << " event sinks left";
382 }
383
CreateSink()384 std::unique_ptr<InputConnector::EventSink> InputSocketsConnector::CreateSink() {
385 return std::unique_ptr<InputConnector::EventSink>(
386 new InputSocketsEventSink(devices_, sinks_count_));
387 }
388
InputSocketsConnectorBuilder(InputEventType type)389 InputSocketsConnectorBuilder::InputSocketsConnectorBuilder(InputEventType type)
390 : connector_(new InputSocketsConnector(type)) {}
391
392 InputSocketsConnectorBuilder::~InputSocketsConnectorBuilder() = default;
393
WithMultitouchDevice(const std::string & device_label,SharedFD server)394 void InputSocketsConnectorBuilder::WithMultitouchDevice(
395 const std::string& device_label, SharedFD server) {
396 CHECK(connector_->devices_.multitouch_devices.find(device_label) ==
397 connector_->devices_.multitouch_devices.end())
398 << "Multiple touch devices with same label: " << device_label;
399 connector_->devices_.multitouch_devices.emplace(
400 device_label, std::make_unique<InputSocket>(server));
401 }
402
WithTouchDevice(const std::string & device_label,SharedFD server)403 void InputSocketsConnectorBuilder::WithTouchDevice(
404 const std::string& device_label, SharedFD server) {
405 CHECK(connector_->devices_.touch_devices.find(device_label) ==
406 connector_->devices_.touch_devices.end())
407 << "Multiple touch devices with same label: " << device_label;
408 connector_->devices_.touch_devices.emplace(device_label,
409 std::make_unique<InputSocket>(server));
410 }
411
WithKeyboard(SharedFD server)412 void InputSocketsConnectorBuilder::WithKeyboard(SharedFD server) {
413 CHECK(!connector_->devices_.keyboard) << "Keyboard already specified";
414 connector_->devices_.keyboard.reset(new InputSocket(server));
415 }
416
WithSwitches(SharedFD server)417 void InputSocketsConnectorBuilder::WithSwitches(SharedFD server) {
418 CHECK(!connector_->devices_.switches) << "Switches already specified";
419 connector_->devices_.switches.reset(new InputSocket(server));
420 }
421
WithRotary(SharedFD server)422 void InputSocketsConnectorBuilder::WithRotary(SharedFD server) {
423 CHECK(!connector_->devices_.rotary) << "Rotary already specified";
424 connector_->devices_.rotary.reset(new InputSocket(server));
425 }
426
Build()427 std::unique_ptr<InputConnector> InputSocketsConnectorBuilder::Build() && {
428 return std::move(connector_);
429 }
430
431 } // namespace cuttlefish
432