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