• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 #define LOG_TAG "ConnectionObserver"
18 
19 #include "host/frontend/webrtc/connection_observer.h"
20 
21 #include <linux/input.h>
22 
23 #include <chrono>
24 #include <map>
25 #include <set>
26 #include <thread>
27 #include <vector>
28 
29 #include <json/json.h>
30 
31 #include <android-base/logging.h>
32 #include <gflags/gflags.h>
33 
34 #include "common/libs/confui/confui.h"
35 #include "common/libs/fs/shared_buf.h"
36 #include "host/frontend/webrtc/adb_handler.h"
37 #include "host/frontend/webrtc/bluetooth_handler.h"
38 #include "host/frontend/webrtc/lib/utils.h"
39 #include "host/libs/config/cuttlefish_config.h"
40 
41 DECLARE_bool(write_virtio_input);
42 
43 namespace cuttlefish {
44 
45 // TODO (b/147511234): de-dup this from vnc server and here
46 struct virtio_input_event {
47   uint16_t type;
48   uint16_t code;
49   int32_t value;
50 };
51 
52 struct multitouch_slot {
53   int32_t id;
54   int32_t slot;
55   int32_t x;
56   int32_t y;
57 };
58 
59 struct InputEventBuffer {
60   virtual ~InputEventBuffer() = default;
61   virtual void AddEvent(uint16_t type, uint16_t code, int32_t value) = 0;
62   virtual size_t size() const = 0;
63   virtual const void *data() const = 0;
64 };
65 
66 template <typename T>
67 struct InputEventBufferImpl : public InputEventBuffer {
InputEventBufferImplcuttlefish::InputEventBufferImpl68   InputEventBufferImpl() {
69     buffer_.reserve(6);  // 6 is usually enough
70   }
AddEventcuttlefish::InputEventBufferImpl71   void AddEvent(uint16_t type, uint16_t code, int32_t value) override {
72     buffer_.push_back({.type = type, .code = code, .value = value});
73   }
datacuttlefish::InputEventBufferImpl74   T *data() { return buffer_.data(); }
datacuttlefish::InputEventBufferImpl75   const void *data() const override { return buffer_.data(); }
sizecuttlefish::InputEventBufferImpl76   std::size_t size() const override { return buffer_.size() * sizeof(T); }
77 
78  private:
79   std::vector<T> buffer_;
80 };
81 
82 // TODO: we could add an arg here to specify whether we want the multitouch buffer?
GetEventBuffer()83 std::unique_ptr<InputEventBuffer> GetEventBuffer() {
84   if (FLAGS_write_virtio_input) {
85     return std::unique_ptr<InputEventBuffer>(
86         new InputEventBufferImpl<virtio_input_event>());
87   } else {
88     return std::unique_ptr<InputEventBuffer>(
89         new InputEventBufferImpl<input_event>());
90   }
91 }
92 
93 /**
94  * connection observer implementation for regular android mode.
95  * i.e. when it is not in the confirmation UI mode (or TEE),
96  * the control flow will fall back to this ConnectionObserverForAndroid
97  */
98 class ConnectionObserverForAndroid
99     : public cuttlefish::webrtc_streaming::ConnectionObserver {
100  public:
ConnectionObserverForAndroid(cuttlefish::InputSockets & input_sockets,cuttlefish::KernelLogEventsHandler * kernel_log_events_handler,std::map<std::string,cuttlefish::SharedFD> commands_to_custom_action_servers,std::weak_ptr<DisplayHandler> display_handler)101   ConnectionObserverForAndroid(
102       cuttlefish::InputSockets &input_sockets,
103       cuttlefish::KernelLogEventsHandler *kernel_log_events_handler,
104       std::map<std::string, cuttlefish::SharedFD>
105           commands_to_custom_action_servers,
106       std::weak_ptr<DisplayHandler> display_handler)
107       : input_sockets_(input_sockets),
108         kernel_log_events_handler_(kernel_log_events_handler),
109         commands_to_custom_action_servers_(commands_to_custom_action_servers),
110         weak_display_handler_(display_handler) {}
~ConnectionObserverForAndroid()111   virtual ~ConnectionObserverForAndroid() {
112     auto display_handler = weak_display_handler_.lock();
113     if (display_handler) {
114       display_handler->DecClientCount();
115     }
116     if (kernel_log_subscription_id_ != -1) {
117       kernel_log_events_handler_->Unsubscribe(kernel_log_subscription_id_);
118     }
119   }
120 
OnConnected(std::function<void (const uint8_t *,size_t,bool)>)121   void OnConnected(std::function<void(const uint8_t *, size_t, bool)>
122                    /*ctrl_msg_sender*/) override {
123     auto display_handler = weak_display_handler_.lock();
124     if (display_handler) {
125       display_handler->IncClientCount();
126       std::thread th([this]() {
127         // The encoder in libwebrtc won't drop 5 consecutive frames due to frame
128         // size, so we make sure at least 5 frames are sent every time a client
129         // connects to ensure they receive at least one.
130         constexpr int kNumFrames = 5;
131         constexpr int kMillisPerFrame = 16;
132         for (int i = 0; i < kNumFrames; ++i) {
133           auto display_handler = weak_display_handler_.lock();
134           display_handler->SendLastFrame();
135           if (i < kNumFrames - 1) {
136             std::this_thread::sleep_for(std::chrono::milliseconds(kMillisPerFrame));
137           }
138         }
139       });
140       th.detach();
141     }
142     }
143 
OnTouchEvent(const std::string &,int x,int y,bool down)144   void OnTouchEvent(const std::string & /*display_label*/, int x, int y,
145                     bool down) override {
146 
147     auto buffer = GetEventBuffer();
148     if (!buffer) {
149       LOG(ERROR) << "Failed to allocate event buffer";
150       return;
151     }
152     buffer->AddEvent(EV_ABS, ABS_X, x);
153     buffer->AddEvent(EV_ABS, ABS_Y, y);
154     buffer->AddEvent(EV_KEY, BTN_TOUCH, down);
155     buffer->AddEvent(EV_SYN, SYN_REPORT, 0);
156     cuttlefish::WriteAll(input_sockets_.touch_client,
157                          reinterpret_cast<const char *>(buffer->data()),
158                          buffer->size());
159   }
160 
OnMultiTouchEvent(const std::string &,Json::Value id,Json::Value slot,Json::Value x,Json::Value y,bool down,int size)161   void OnMultiTouchEvent(const std::string & /*display_label*/, Json::Value id,
162                          Json::Value slot, Json::Value x, Json::Value y,
163                          bool down, int size) override {
164 
165     auto buffer = GetEventBuffer();
166     if (!buffer) {
167       LOG(ERROR) << "Failed to allocate event buffer";
168       return;
169     }
170 
171     for (int i=0; i<size; i++) {
172       auto this_slot = slot[i].asInt();
173       auto this_id = id[i].asInt();
174       auto this_x = x[i].asInt();
175       auto this_y = y[i].asInt();
176       buffer->AddEvent(EV_ABS, ABS_MT_SLOT, this_slot);
177       if (down) {
178         bool is_new = active_touch_slots_.insert(this_slot).second;
179         if (is_new) {
180           buffer->AddEvent(EV_ABS, ABS_MT_TRACKING_ID, this_id);
181           if (active_touch_slots_.size() == 1) {
182             buffer->AddEvent(EV_KEY, BTN_TOUCH, 1);
183           }
184         }
185         buffer->AddEvent(EV_ABS, ABS_MT_POSITION_X, this_x);
186         buffer->AddEvent(EV_ABS, ABS_MT_POSITION_Y, this_y);
187         // send ABS_X and ABS_Y for single-touch compatibility
188         buffer->AddEvent(EV_ABS, ABS_X, this_x);
189         buffer->AddEvent(EV_ABS, ABS_Y, this_y);
190       } else {
191         // released touch
192         buffer->AddEvent(EV_ABS, ABS_MT_TRACKING_ID, this_id);
193         active_touch_slots_.erase(this_slot);
194         if (active_touch_slots_.empty()) {
195           buffer->AddEvent(EV_KEY, BTN_TOUCH, 0);
196         }
197       }
198     }
199 
200     buffer->AddEvent(EV_SYN, SYN_REPORT, 0);
201     cuttlefish::WriteAll(input_sockets_.touch_client,
202                          reinterpret_cast<const char *>(buffer->data()),
203                          buffer->size());
204   }
205 
OnKeyboardEvent(uint16_t code,bool down)206   void OnKeyboardEvent(uint16_t code, bool down) override {
207     auto buffer = GetEventBuffer();
208     if (!buffer) {
209       LOG(ERROR) << "Failed to allocate event buffer";
210       return;
211     }
212     buffer->AddEvent(EV_KEY, code, down);
213     buffer->AddEvent(EV_SYN, SYN_REPORT, 0);
214     cuttlefish::WriteAll(input_sockets_.keyboard_client,
215                          reinterpret_cast<const char *>(buffer->data()),
216                          buffer->size());
217   }
218 
OnSwitchEvent(uint16_t code,bool state)219   void OnSwitchEvent(uint16_t code, bool state) override {
220     auto buffer = GetEventBuffer();
221     if (!buffer) {
222       LOG(ERROR) << "Failed to allocate event buffer";
223       return;
224     }
225     buffer->AddEvent(EV_SW, code, state);
226     buffer->AddEvent(EV_SYN, SYN_REPORT, 0);
227     cuttlefish::WriteAll(input_sockets_.switches_client,
228                          reinterpret_cast<const char *>(buffer->data()),
229                          buffer->size());
230   }
231 
OnAdbChannelOpen(std::function<bool (const uint8_t *,size_t)> adb_message_sender)232   void OnAdbChannelOpen(std::function<bool(const uint8_t *, size_t)>
233                             adb_message_sender) override {
234     LOG(VERBOSE) << "Adb Channel open";
235     adb_handler_.reset(new cuttlefish::webrtc_streaming::AdbHandler(
236         cuttlefish::CuttlefishConfig::Get()
237             ->ForDefaultInstance()
238             .adb_ip_and_port(),
239         adb_message_sender));
240   }
OnAdbMessage(const uint8_t * msg,size_t size)241   void OnAdbMessage(const uint8_t *msg, size_t size) override {
242     adb_handler_->handleMessage(msg, size);
243   }
OnControlChannelOpen(std::function<bool (const Json::Value)> control_message_sender)244   void OnControlChannelOpen(std::function<bool(const Json::Value)>
245                             control_message_sender) override {
246     LOG(VERBOSE) << "Control Channel open";
247     kernel_log_subscription_id_ =
248         kernel_log_events_handler_->AddSubscriber(control_message_sender);
249   }
OnControlMessage(const uint8_t * msg,size_t size)250   void OnControlMessage(const uint8_t* msg, size_t size) override {
251     Json::Value evt;
252     const char* msg_str = reinterpret_cast<const char*>(msg);
253     Json::CharReaderBuilder builder;
254     std::unique_ptr<Json::CharReader> json_reader(builder.newCharReader());
255     std::string errorMessage;
256     if (!json_reader->parse(msg_str, msg_str + size, &evt, &errorMessage)) {
257       LOG(ERROR) << "Received invalid JSON object over control channel: " << errorMessage;
258       return;
259     }
260 
261     auto result = webrtc_streaming::ValidationResult::ValidateJsonObject(
262         evt, "command",
263         /*required_fields=*/{{"command", Json::ValueType::stringValue}},
264         /*optional_fields=*/
265         {
266             {"button_state", Json::ValueType::stringValue},
267             {"lid_switch_open", Json::ValueType::booleanValue},
268             {"hinge_angle_value", Json::ValueType::intValue},
269         });
270     if (!result.ok()) {
271       LOG(ERROR) << result.error();
272       return;
273     }
274     auto command = evt["command"].asString();
275 
276     if (command == "device_state") {
277       if (evt.isMember("lid_switch_open")) {
278         // InputManagerService treats a value of 0 as open and 1 as closed, so
279         // invert the lid_switch_open value that is sent to the input device.
280         OnSwitchEvent(SW_LID, !evt["lid_switch_open"].asBool());
281       }
282       if (evt.isMember("hinge_angle_value")) {
283         // TODO(b/181157794) Propagate hinge angle sensor data using a custom
284         // Sensor HAL.
285       }
286       return;
287     }
288 
289     auto button_state = evt["button_state"].asString();
290     LOG(VERBOSE) << "Control command: " << command << " (" << button_state
291                  << ")";
292     if (command == "power") {
293       OnKeyboardEvent(KEY_POWER, button_state == "down");
294     } else if (command == "home") {
295       OnKeyboardEvent(KEY_HOMEPAGE, button_state == "down");
296     } else if (command == "menu") {
297       OnKeyboardEvent(KEY_MENU, button_state == "down");
298     } else if (command == "volumemute") {
299       OnKeyboardEvent(KEY_MUTE, button_state == "down");
300     } else if (command == "volumedown") {
301       OnKeyboardEvent(KEY_VOLUMEDOWN, button_state == "down");
302     } else if (command == "volumeup") {
303       OnKeyboardEvent(KEY_VOLUMEUP, button_state == "down");
304     } else if (commands_to_custom_action_servers_.find(command) !=
305                commands_to_custom_action_servers_.end()) {
306       // Simple protocol for commands forwarded to action servers:
307       //   - Always 128 bytes
308       //   - Format:   command:button_state
309       //   - Example:  my_button:down
310       std::string action_server_message = command + ":" + button_state;
311       cuttlefish::WriteAll(commands_to_custom_action_servers_[command],
312                            action_server_message.c_str(), 128);
313     } else {
314       LOG(WARNING) << "Unsupported control command: " << command << " ("
315                    << button_state << ")";
316     }
317   }
318 
OnBluetoothChannelOpen(std::function<bool (const uint8_t *,size_t)> bluetooth_message_sender)319   void OnBluetoothChannelOpen(std::function<bool(const uint8_t *, size_t)>
320                                   bluetooth_message_sender) override {
321     LOG(VERBOSE) << "Bluetooth channel open";
322     bluetooth_handler_.reset(new cuttlefish::webrtc_streaming::BluetoothHandler(
323         cuttlefish::CuttlefishConfig::Get()
324             ->ForDefaultInstance()
325             .rootcanal_test_port(),
326         bluetooth_message_sender));
327   }
328 
OnBluetoothMessage(const uint8_t * msg,size_t size)329   void OnBluetoothMessage(const uint8_t *msg, size_t size) override {
330     bluetooth_handler_->handleMessage(msg, size);
331   }
332 
333  private:
334   cuttlefish::InputSockets& input_sockets_;
335   cuttlefish::KernelLogEventsHandler* kernel_log_events_handler_;
336   int kernel_log_subscription_id_ = -1;
337   std::shared_ptr<cuttlefish::webrtc_streaming::AdbHandler> adb_handler_;
338   std::shared_ptr<cuttlefish::webrtc_streaming::BluetoothHandler>
339       bluetooth_handler_;
340   std::map<std::string, cuttlefish::SharedFD> commands_to_custom_action_servers_;
341   std::weak_ptr<DisplayHandler> weak_display_handler_;
342   std::set<int32_t> active_touch_slots_;
343 };
344 
345 class ConnectionObserverDemuxer
346     : public cuttlefish::webrtc_streaming::ConnectionObserver {
347  public:
ConnectionObserverDemuxer(cuttlefish::InputSockets & input_sockets,cuttlefish::KernelLogEventsHandler * kernel_log_events_handler,std::map<std::string,cuttlefish::SharedFD> commands_to_custom_action_servers,std::weak_ptr<DisplayHandler> display_handler,cuttlefish::confui::HostVirtualInput & confui_input)348   ConnectionObserverDemuxer(
349       /* params for the base class */
350       cuttlefish::InputSockets &input_sockets,
351       cuttlefish::KernelLogEventsHandler *kernel_log_events_handler,
352       std::map<std::string, cuttlefish::SharedFD>
353           commands_to_custom_action_servers,
354       std::weak_ptr<DisplayHandler> display_handler,
355       /* params for this class */
356       cuttlefish::confui::HostVirtualInput &confui_input)
357       : android_input_(input_sockets, kernel_log_events_handler,
358                        commands_to_custom_action_servers, display_handler),
359         confui_input_{confui_input} {}
360   virtual ~ConnectionObserverDemuxer() = default;
361 
OnConnected(std::function<void (const uint8_t *,size_t,bool)> ctrl_msg_sender)362   void OnConnected(std::function<void(const uint8_t *, size_t, bool)>
363                        ctrl_msg_sender) override {
364     android_input_.OnConnected(ctrl_msg_sender);
365   }
366 
OnTouchEvent(const std::string & label,int x,int y,bool down)367   void OnTouchEvent(const std::string &label, int x, int y,
368                     bool down) override {
369     if (confui_input_.IsConfUiActive()) {
370       ConfUiLog(DEBUG) << "touch event ignored in confirmation UI mode";
371       return;
372     }
373     android_input_.OnTouchEvent(label, x, y, down);
374   }
375 
OnMultiTouchEvent(const std::string & label,Json::Value id,Json::Value slot,Json::Value x,Json::Value y,bool down,int size)376   void OnMultiTouchEvent(const std::string &label, Json::Value id,
377                          Json::Value slot, Json::Value x, Json::Value y,
378                          bool down, int size) override {
379     if (confui_input_.IsConfUiActive()) {
380       ConfUiLog(DEBUG) << "multi-touch event ignored in confirmation UI mode";
381       return;
382     }
383     android_input_.OnMultiTouchEvent(label, id, slot, x, y, down, size);
384   }
385 
OnKeyboardEvent(uint16_t code,bool down)386   void OnKeyboardEvent(uint16_t code, bool down) override {
387     if (confui_input_.IsConfUiActive()) {
388       switch (code) {
389         case KEY_POWER:
390           confui_input_.PressConfirmButton(down);
391           break;
392         case KEY_MENU:
393           confui_input_.PressCancelButton(down);
394           break;
395         default:
396           ConfUiLog(DEBUG) << "key" << code
397                            << "is ignored in confirmation UI mode";
398           break;
399       }
400       return;
401     }
402     android_input_.OnKeyboardEvent(code, down);
403   }
404 
OnSwitchEvent(uint16_t code,bool state)405   void OnSwitchEvent(uint16_t code, bool state) override {
406     android_input_.OnSwitchEvent(code, state);
407   }
408 
OnAdbChannelOpen(std::function<bool (const uint8_t *,size_t)> adb_message_sender)409   void OnAdbChannelOpen(std::function<bool(const uint8_t *, size_t)>
410                             adb_message_sender) override {
411     android_input_.OnAdbChannelOpen(adb_message_sender);
412   }
413 
OnAdbMessage(const uint8_t * msg,size_t size)414   void OnAdbMessage(const uint8_t *msg, size_t size) override {
415     android_input_.OnAdbMessage(msg, size);
416   }
417 
OnControlChannelOpen(std::function<bool (const Json::Value)> control_message_sender)418   void OnControlChannelOpen(
419       std::function<bool(const Json::Value)> control_message_sender) override {
420     android_input_.OnControlChannelOpen(control_message_sender);
421   }
422 
OnControlMessage(const uint8_t * msg,size_t size)423   void OnControlMessage(const uint8_t *msg, size_t size) override {
424     android_input_.OnControlMessage(msg, size);
425   }
426 
OnBluetoothChannelOpen(std::function<bool (const uint8_t *,size_t)> bluetooth_message_sender)427   void OnBluetoothChannelOpen(std::function<bool(const uint8_t *, size_t)>
428                                   bluetooth_message_sender) override {
429     android_input_.OnBluetoothChannelOpen(bluetooth_message_sender);
430   }
431 
OnBluetoothMessage(const uint8_t * msg,size_t size)432   void OnBluetoothMessage(const uint8_t *msg, size_t size) override {
433     android_input_.OnBluetoothMessage(msg, size);
434   }
435 
436  private:
437   ConnectionObserverForAndroid android_input_;
438   cuttlefish::confui::HostVirtualInput &confui_input_;
439 };
440 
CfConnectionObserverFactory(cuttlefish::InputSockets & input_sockets,cuttlefish::KernelLogEventsHandler * kernel_log_events_handler,cuttlefish::confui::HostVirtualInput & confui_input)441 CfConnectionObserverFactory::CfConnectionObserverFactory(
442     cuttlefish::InputSockets &input_sockets,
443     cuttlefish::KernelLogEventsHandler* kernel_log_events_handler,
444     cuttlefish::confui::HostVirtualInput &confui_input)
445     : input_sockets_(input_sockets),
446       kernel_log_events_handler_(kernel_log_events_handler),
447       confui_input_{confui_input} {}
448 
449 std::shared_ptr<cuttlefish::webrtc_streaming::ConnectionObserver>
CreateObserver()450 CfConnectionObserverFactory::CreateObserver() {
451   return std::shared_ptr<cuttlefish::webrtc_streaming::ConnectionObserver>(
452       new ConnectionObserverDemuxer(input_sockets_, kernel_log_events_handler_,
453                                     commands_to_custom_action_servers_,
454                                     weak_display_handler_, confui_input_));
455 }
456 
AddCustomActionServer(cuttlefish::SharedFD custom_action_server_fd,const std::vector<std::string> & commands)457 void CfConnectionObserverFactory::AddCustomActionServer(
458     cuttlefish::SharedFD custom_action_server_fd,
459     const std::vector<std::string>& commands) {
460   for (const std::string& command : commands) {
461     LOG(DEBUG) << "Action server is listening to command: " << command;
462     commands_to_custom_action_servers_[command] = custom_action_server_fd;
463   }
464 }
465 
SetDisplayHandler(std::weak_ptr<DisplayHandler> display_handler)466 void CfConnectionObserverFactory::SetDisplayHandler(
467     std::weak_ptr<DisplayHandler> display_handler) {
468   weak_display_handler_ = display_handler;
469 }
470 }  // namespace cuttlefish
471