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