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 #include "host/frontend/webrtc/connection_observer.h"
18 
19 #include <linux/input.h>
20 
21 #include <thread>
22 #include <vector>
23 
24 #include <android-base/logging.h>
25 #include <gflags/gflags.h>
26 
27 #include "common/libs/fs/shared_buf.h"
28 #include "host/frontend/webrtc/adb_handler.h"
29 #include "host/libs/config/cuttlefish_config.h"
30 
31 DECLARE_bool(write_virtio_input);
32 
33 namespace cuttlefish {
34 
35 // TODO (b/147511234): de-dup this from vnc server and here
36 struct virtio_input_event {
37   uint16_t type;
38   uint16_t code;
39   int32_t value;
40 };
41 
42 struct InputEventBuffer {
43   virtual ~InputEventBuffer() = default;
44   virtual void AddEvent(uint16_t type, uint16_t code, int32_t value) = 0;
45   virtual size_t size() const = 0;
46   virtual const void *data() const = 0;
47 };
48 
49 template <typename T>
50 struct InputEventBufferImpl : public InputEventBuffer {
InputEventBufferImplcuttlefish::InputEventBufferImpl51   InputEventBufferImpl() {
52     buffer_.reserve(6);  // 6 is usually enough
53   }
AddEventcuttlefish::InputEventBufferImpl54   void AddEvent(uint16_t type, uint16_t code, int32_t value) override {
55     buffer_.push_back({.type = type, .code = code, .value = value});
56   }
datacuttlefish::InputEventBufferImpl57   T *data() { return buffer_.data(); }
datacuttlefish::InputEventBufferImpl58   const void *data() const override { return buffer_.data(); }
sizecuttlefish::InputEventBufferImpl59   std::size_t size() const override { return buffer_.size() * sizeof(T); }
60 
61  private:
62   std::vector<T> buffer_;
63 };
64 
GetEventBuffer()65 std::unique_ptr<InputEventBuffer> GetEventBuffer() {
66   if (FLAGS_write_virtio_input) {
67     return std::unique_ptr<InputEventBuffer>(
68         new InputEventBufferImpl<virtio_input_event>());
69   } else {
70     return std::unique_ptr<InputEventBuffer>(
71         new InputEventBufferImpl<input_event>());
72   }
73 }
74 
75 class ConnectionObserverImpl
76     : public cuttlefish::webrtc_streaming::ConnectionObserver {
77  public:
ConnectionObserverImpl(cuttlefish::SharedFD touch_fd,cuttlefish::SharedFD keyboard_fd,std::weak_ptr<DisplayHandler> display_handler,std::shared_ptr<RunLoop> run_loop)78   ConnectionObserverImpl(cuttlefish::SharedFD touch_fd,
79                          cuttlefish::SharedFD keyboard_fd,
80                          std::weak_ptr<DisplayHandler> display_handler,
81                          std::shared_ptr<RunLoop> run_loop)
82       : touch_client_(touch_fd),
83         keyboard_client_(keyboard_fd),
84         weak_display_handler_(display_handler),
85         run_loop_(run_loop) {}
86   virtual ~ConnectionObserverImpl() = default;
87 
OnConnected()88   void OnConnected() override {
89     auto display_handler = weak_display_handler_.lock();
90     if (display_handler) {
91       // A long time may pass before the next frame comes up from the guest.
92       // Send the last one to avoid showing a black screen to the user during
93       // that time.
94       display_handler->SendLastFrame();
95     }
96   }
OnTouchEvent(const std::string &,int x,int y,bool down)97   void OnTouchEvent(const std::string & /*display_label*/, int x, int y,
98                     bool down) override {
99     auto buffer = GetEventBuffer();
100     if (!buffer) {
101       LOG(ERROR) << "Failed to allocate event buffer";
102       return;
103     }
104     buffer->AddEvent(EV_ABS, ABS_X, x);
105     buffer->AddEvent(EV_ABS, ABS_Y, y);
106     buffer->AddEvent(EV_KEY, BTN_TOUCH, down);
107     buffer->AddEvent(EV_SYN, 0, 0);
108     cuttlefish::WriteAll(touch_client_,
109                          reinterpret_cast<const char *>(buffer->data()),
110                          buffer->size());
111   }
OnMultiTouchEvent(const std::string & display_label,int,int,int x,int y,bool initialDown)112   void OnMultiTouchEvent(const std::string &display_label, int /*id*/,
113                          int /*slot*/, int x, int y,
114                          bool initialDown) override {
115     OnTouchEvent(display_label, x, y, initialDown);
116   }
OnKeyboardEvent(uint16_t code,bool down)117   void OnKeyboardEvent(uint16_t code, bool down) override {
118     auto buffer = GetEventBuffer();
119     if (!buffer) {
120       LOG(ERROR) << "Failed to allocate event buffer";
121       return;
122     }
123     buffer->AddEvent(EV_KEY, code, down);
124     buffer->AddEvent(EV_SYN, 0, 0);
125     cuttlefish::WriteAll(keyboard_client_,
126                          reinterpret_cast<const char *>(buffer->data()),
127                          buffer->size());
128   }
OnAdbChannelOpen(std::function<bool (const uint8_t *,size_t)> adb_message_sender)129   void OnAdbChannelOpen(std::function<bool(const uint8_t *, size_t)>
130                             adb_message_sender) override {
131     LOG(VERBOSE) << "Adb Channel open";
132     adb_handler_.reset(new cuttlefish::webrtc_streaming::AdbHandler(
133         run_loop_,
134         cuttlefish::CuttlefishConfig::Get()
135             ->ForDefaultInstance()
136             .adb_ip_and_port(),
137         adb_message_sender));
138     adb_handler_->run();
139   }
OnAdbMessage(const uint8_t * msg,size_t size)140   void OnAdbMessage(const uint8_t *msg, size_t size) override {
141     adb_handler_->handleMessage(msg, size);
142   }
143 
144  private:
145   cuttlefish::SharedFD touch_client_;
146   cuttlefish::SharedFD keyboard_client_;
147   std::shared_ptr<cuttlefish::webrtc_streaming::AdbHandler> adb_handler_;
148   std::weak_ptr<DisplayHandler> weak_display_handler_;
149   std::shared_ptr<RunLoop> run_loop_;
150 };
151 
CfConnectionObserverFactory(cuttlefish::SharedFD touch_fd,cuttlefish::SharedFD keyboard_fd)152 CfConnectionObserverFactory::CfConnectionObserverFactory(
153     cuttlefish::SharedFD touch_fd, cuttlefish::SharedFD keyboard_fd)
154     : touch_fd_(touch_fd),
155       keyboard_fd_(keyboard_fd),
156       run_loop_(RunLoop::main()),
157       run_loop_thread_([this]() { run_loop_->run(); }) {}
158 
159 std::shared_ptr<cuttlefish::webrtc_streaming::ConnectionObserver>
CreateObserver()160 CfConnectionObserverFactory::CreateObserver() {
161   return std::shared_ptr<cuttlefish::webrtc_streaming::ConnectionObserver>(
162       new ConnectionObserverImpl(touch_fd_, keyboard_fd_, weak_display_handler_,
163                                  run_loop_));
164 }
165 
SetDisplayHandler(std::weak_ptr<DisplayHandler> display_handler)166 void CfConnectionObserverFactory::SetDisplayHandler(
167     std::weak_ptr<DisplayHandler> display_handler) {
168   weak_display_handler_ = display_handler;
169 }
170 }  // namespace cuttlefish
171