1 /*
2  * Copyright (C) 2022 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/libdevice/data_channels.h"
18 
19 #include <android-base/logging.h>
20 
21 #include "host/frontend/webrtc/libcommon/utils.h"
22 #include "host/frontend/webrtc/libdevice/keyboard.h"
23 
24 namespace cuttlefish {
25 namespace webrtc_streaming {
26 
27 class DataChannelHandler : public webrtc::DataChannelObserver {
28  public:
29   virtual ~DataChannelHandler() = default;
30 
31   bool Send(const uint8_t *msg, size_t size, bool binary);
32   bool Send(const Json::Value &message);
33 
34   // webrtc::DataChannelObserver implementation
35   void OnStateChange() override;
36   void OnMessage(const webrtc::DataBuffer &msg) override;
37 
38  protected:
39   // Provide access to the underlying data channel and the connection observer.
40   virtual rtc::scoped_refptr<webrtc::DataChannelInterface> channel() = 0;
41   virtual std::shared_ptr<ConnectionObserver> observer() = 0;
42 
43   // Subclasses must override this to process messages.
44   virtual Result<void> OnMessageInner(const webrtc::DataBuffer &msg) = 0;
45   // Some subclasses may override this to defer some work until the channel is
46   // actually used.
OnFirstMessage()47   virtual void OnFirstMessage() {}
OnStateChangeInner(webrtc::DataChannelInterface::DataState)48   virtual void OnStateChangeInner(webrtc::DataChannelInterface::DataState) {}
49 
GetBinarySender()50   std::function<bool(const uint8_t *, size_t len)> GetBinarySender() {
51     return [this](const uint8_t *msg, size_t size) {
52       return Send(msg, size, true /*binary*/);
53     };
54   }
GetJSONSender()55   std::function<bool(const Json::Value &)> GetJSONSender() {
56     return [this](const Json::Value &msg) { return Send(msg); };
57   }
58  private:
59   bool first_msg_received_ = false;
60 };
61 
62 namespace {
63 
64 static constexpr auto kInputChannelLabel = "input-channel";
65 static constexpr auto kAdbChannelLabel = "adb-channel";
66 static constexpr auto kBluetoothChannelLabel = "bluetooth-channel";
67 static constexpr auto kCameraDataChannelLabel = "camera-data-channel";
68 static constexpr auto kSensorsDataChannelLabel = "sensors-channel";
69 static constexpr auto kLightsChannelLabel = "lights-channel";
70 static constexpr auto kLocationDataChannelLabel = "location-channel";
71 static constexpr auto kKmlLocationsDataChannelLabel = "kml-locations-channel";
72 static constexpr auto kGpxLocationsDataChannelLabel = "gpx-locations-channel";
73 static constexpr auto kCameraDataEof = "EOF";
74 
75 // These classes use the Template pattern to minimize code repetition between
76 // data channel handlers.
77 
78 class InputChannelHandler : public DataChannelHandler {
79  public:
OnMessageInner(const webrtc::DataBuffer & msg)80   Result<void> OnMessageInner(const webrtc::DataBuffer &msg) override {
81     // TODO: jemoreira - consider binary protocol to avoid JSON parsing
82     // overhead
83     CF_EXPECT(!msg.binary, "Received invalid (binary) data on input channel");
84     auto size = msg.size();
85 
86     Json::Value evt;
87     Json::CharReaderBuilder builder;
88     std::unique_ptr<Json::CharReader> json_reader(builder.newCharReader());
89     std::string error_message;
90     auto str = msg.data.cdata<char>();
91     CF_EXPECTF(json_reader->parse(str, str + size, &evt, &error_message),
92                "Received invalid JSON object over control channel: '{}'",
93                error_message);
94 
95     CF_EXPECTF(evt.isMember("type") && evt["type"].isString(),
96                "Input event doesn't have a valid 'type' field: ",
97                evt.toStyledString());
98     auto event_type = evt["type"].asString();
99 
100     if (event_type == "mouseMove") {
101       CF_EXPECT(ValidateJsonObject(evt, "mouseMove",
102                                    {{"x", Json::ValueType::intValue},
103                                     {"y", Json::ValueType::intValue}}));
104       int32_t x = evt["x"].asInt();
105       int32_t y = evt["y"].asInt();
106 
107       CF_EXPECT(observer()->OnMouseMoveEvent(x, y));
108     } else if (event_type == "mouseButton") {
109       CF_EXPECT(ValidateJsonObject(evt, "mouseButton",
110                                    {{"button", Json::ValueType::intValue},
111                                     {"down", Json::ValueType::intValue}}));
112       int32_t button = evt["button"].asInt();
113       int32_t down = evt["down"].asInt();
114 
115       CF_EXPECT(observer()->OnMouseButtonEvent(button, down));
116     } else if (event_type == "mouseWheel") {
117       CF_EXPECT(ValidateJsonObject(evt, "mouseWheel",
118                                    {{"pixels", Json::ValueType::intValue}}));
119       auto pixels = evt["pixels"].asInt();
120       CF_EXPECT(observer()->OnMouseWheelEvent(pixels));
121     } else if (event_type == "multi-touch") {
122       CF_EXPECT(
123           ValidateJsonObject(evt, "multi-touch",
124                              {{"id", Json::ValueType::arrayValue},
125                               {"down", Json::ValueType::intValue},
126                               {"x", Json::ValueType::arrayValue},
127                               {"y", Json::ValueType::arrayValue},
128                               {"device_label", Json::ValueType::stringValue}}));
129 
130       auto label = evt["device_label"].asString();
131       auto idArr = evt["id"];
132       int32_t down = evt["down"].asInt();
133       auto xArr = evt["x"];
134       auto yArr = evt["y"];
135       auto slotArr = evt["slot"];
136       int size = evt["id"].size();
137 
138       CF_EXPECT(observer()->OnMultiTouchEvent(label, idArr, slotArr, xArr, yArr,
139                                               down, size));
140     } else if (event_type == "keyboard") {
141       CF_EXPECT(
142           ValidateJsonObject(evt, "keyboard",
143                              {{"event_type", Json::ValueType::stringValue},
144                               {"keycode", Json::ValueType::stringValue}}));
145       auto down = evt["event_type"].asString() == std::string("keydown");
146       auto code = DomKeyCodeToLinux(evt["keycode"].asString());
147       CF_EXPECT(observer()->OnKeyboardEvent(code, down));
148     } else if (event_type == "wheel") {
149       CF_EXPECT(ValidateJsonObject(evt, "wheel",
150                                    {{"pixels", Json::ValueType::intValue}}));
151       auto pixels = evt["pixels"].asInt();
152       CF_EXPECT(observer()->OnRotaryWheelEvent(pixels));
153     } else {
154       return CF_ERRF("Unrecognized event type: '{}'", event_type);
155     }
156     return {};
157   }
158 };
159 
160 class ControlChannelHandler : public DataChannelHandler {
161  public:
OnStateChangeInner(webrtc::DataChannelInterface::DataState state)162   void OnStateChangeInner(
163       webrtc::DataChannelInterface::DataState state) override {
164     if (state == webrtc::DataChannelInterface::kOpen) {
165       observer()->OnControlChannelOpen(GetJSONSender());
166     }
167   }
OnMessageInner(const webrtc::DataBuffer & msg)168   Result<void> OnMessageInner(const webrtc::DataBuffer &msg) override {
169     auto msg_str = msg.data.cdata<char>();
170     auto size = msg.size();
171     Json::Value evt;
172     Json::CharReaderBuilder builder;
173     std::unique_ptr<Json::CharReader> json_reader(builder.newCharReader());
174     std::string error_message;
175     CF_EXPECTF(
176         json_reader->parse(msg_str, msg_str + size, &evt, &error_message),
177         "Received invalid JSON object over control channel: '{}'",
178         error_message);
179 
180     CF_EXPECT(ValidateJsonObject(
181         evt, "command",
182         /*required_fields=*/{{"command", Json::ValueType::stringValue}},
183         /*optional_fields=*/
184         {
185             {"button_state", Json::ValueType::stringValue},
186             {"lid_switch_open", Json::ValueType::booleanValue},
187             {"hinge_angle_value", Json::ValueType::intValue},
188         }));
189     auto command = evt["command"].asString();
190 
191     if (command == "device_state") {
192       if (evt.isMember("lid_switch_open")) {
193         CF_EXPECT(
194             observer()->OnLidStateChange(evt["lid_switch_open"].asBool()));
195       }
196       if (evt.isMember("hinge_angle_value")) {
197         observer()->OnHingeAngleChange(evt["hinge_angle_value"].asInt());
198       }
199       return {};
200     } else if (command.rfind("camera_", 0) == 0) {
201       observer()->OnCameraControlMsg(evt);
202       return {};
203     } else if (command == "display") {
204       observer()->OnDisplayControlMsg(evt);
205       return {};
206     }
207 
208     auto button_state = evt["button_state"].asString();
209     LOG(VERBOSE) << "Control command: " << command << " (" << button_state
210                  << ")";
211     if (command == "power") {
212       CF_EXPECT(observer()->OnPowerButton(button_state == "down"));
213     } else if (command == "back") {
214       CF_EXPECT(observer()->OnBackButton(button_state == "down"));
215     } else if (command == "home") {
216       CF_EXPECT(observer()->OnHomeButton(button_state == "down"));
217     } else if (command == "menu") {
218       CF_EXPECT(observer()->OnMenuButton(button_state == "down"));
219     } else if (command == "volumedown") {
220       CF_EXPECT(observer()->OnVolumeDownButton(button_state == "down"));
221     } else if (command == "volumeup") {
222       CF_EXPECT(observer()->OnVolumeUpButton(button_state == "down"));
223     } else {
224       observer()->OnCustomActionButton(command, button_state);
225     }
226     return {};
227   }
228 };
229 
230 class AdbChannelHandler : public DataChannelHandler {
231  public:
OnMessageInner(const webrtc::DataBuffer & msg)232   Result<void> OnMessageInner(const webrtc::DataBuffer &msg) override {
233     observer()->OnAdbMessage(msg.data.cdata(), msg.size());
234     return {};
235   }
OnFirstMessage()236   void OnFirstMessage() override {
237     // Report the adb channel as open on the first message received instead of
238     // at channel open, this avoids unnecessarily connecting to the adb daemon
239     // for clients that don't use ADB.
240     observer()->OnAdbChannelOpen(GetBinarySender());
241   }
242 };
243 
244 class BluetoothChannelHandler : public DataChannelHandler {
245  public:
OnMessageInner(const webrtc::DataBuffer & msg)246   Result<void> OnMessageInner(const webrtc::DataBuffer &msg) override {
247     observer()->OnBluetoothMessage(msg.data.cdata(), msg.size());
248     return {};
249   }
OnFirstMessage()250   void OnFirstMessage() override {
251     // Notify bluetooth channel opening when actually using the channel,
252     // it has the same reason with AdbChannelHandler::OnMessageInner,
253     // to avoid unnecessary connection for Rootcanal.
254     observer()->OnBluetoothChannelOpen(GetBinarySender());
255   }
256 };
257 
258 class CameraChannelHandler : public DataChannelHandler {
259  public:
OnMessageInner(const webrtc::DataBuffer & msg)260   Result<void> OnMessageInner(const webrtc::DataBuffer &msg) override {
261     auto msg_data = msg.data.cdata<char>();
262     if (msg.size() == strlen(kCameraDataEof) &&
263         !strncmp(msg_data, kCameraDataEof, msg.size())) {
264       // Send complete buffer to observer on EOF marker
265       observer()->OnCameraData(receive_buffer_);
266       receive_buffer_.clear();
267       return {};
268     }
269     // Otherwise buffer up data
270     receive_buffer_.insert(receive_buffer_.end(), msg_data,
271                            msg_data + msg.size());
272     return {};
273   }
274 
275  private:
276   std::vector<char> receive_buffer_;
277 };
278 
279 // TODO(b/297361564)
280 class SensorsChannelHandler : public DataChannelHandler {
281  public:
OnFirstMessage()282   void OnFirstMessage() override { observer()->OnSensorsChannelOpen(GetBinarySender()); }
OnMessageInner(const webrtc::DataBuffer & msg)283   Result<void> OnMessageInner(const webrtc::DataBuffer &msg) override {
284     if (!first_msg_received_) {
285       first_msg_received_ = true;
286       return {};
287     }
288     observer()->OnSensorsMessage(msg.data.cdata(), msg.size());
289     return {};
290   }
291 
OnStateChangeInner(webrtc::DataChannelInterface::DataState state)292   void OnStateChangeInner(webrtc::DataChannelInterface::DataState state) override {
293     if (state == webrtc::DataChannelInterface::kClosed) {
294       observer()->OnSensorsChannelClosed();
295     }
296   }
297 
298  private:
299   bool first_msg_received_ = false;
300 };
301 
302 class LightsChannelHandler : public DataChannelHandler {
303  public:
304   // We do not expect any messages from the frontend.
OnMessageInner(const webrtc::DataBuffer & msg)305   Result<void> OnMessageInner(const webrtc::DataBuffer &msg) override {
306     return {};
307   }
308 
OnStateChangeInner(webrtc::DataChannelInterface::DataState state)309   void OnStateChangeInner(
310       webrtc::DataChannelInterface::DataState state) override {
311     if (state == webrtc::DataChannelInterface::kOpen) {
312       observer()->OnLightsChannelOpen(GetJSONSender());
313     } else if (state == webrtc::DataChannelInterface::kClosed) {
314       observer()->OnLightsChannelClosed();
315     }
316   }
317 };
318 
319 class LocationChannelHandler : public DataChannelHandler {
320  public:
OnMessageInner(const webrtc::DataBuffer & msg)321   Result<void> OnMessageInner(const webrtc::DataBuffer &msg) override {
322     observer()->OnLocationMessage(msg.data.cdata(), msg.size());
323     return {};
324   }
OnFirstMessage()325   void OnFirstMessage() override {
326     // Notify location channel opening when actually using the channel,
327     // it has the same reason with AdbChannelHandler::OnMessageInner,
328     // to avoid unnecessary connections.
329     observer()->OnLocationChannelOpen(GetBinarySender());
330   }
331 };
332 
333 class KmlLocationChannelHandler : public DataChannelHandler {
334  public:
OnMessageInner(const webrtc::DataBuffer & msg)335   Result<void> OnMessageInner(const webrtc::DataBuffer &msg) override {
336     observer()->OnKmlLocationsMessage(msg.data.cdata(), msg.size());
337     return {};
338   }
OnFirstMessage()339   void OnFirstMessage() override {
340     // Notify location channel opening when actually using the channel,
341     // it has the same reason with AdbChannelHandler::OnMessageInner,
342     // to avoid unnecessary connections.
343     observer()->OnKmlLocationsChannelOpen(GetBinarySender());
344   }
345 };
346 
347 class GpxLocationChannelHandler : public DataChannelHandler {
348  public:
OnMessageInner(const webrtc::DataBuffer & msg)349   Result<void> OnMessageInner(const webrtc::DataBuffer &msg) override {
350     observer()->OnGpxLocationsMessage(msg.data.cdata(), msg.size());
351     return {};
352   }
OnFirstMessage()353   void OnFirstMessage() override {
354     // Notify location channel opening when actually using the channel,
355     // it has the same reason with AdbChannelHandler::OnMessageInner,
356     // to avoid unnecessary connections.
357     observer()->OnGpxLocationsChannelOpen(GetBinarySender());
358   }
359 };
360 
361 class UnknownChannelHandler : public DataChannelHandler {
362  public:
OnMessageInner(const webrtc::DataBuffer &)363   Result<void> OnMessageInner(const webrtc::DataBuffer &) override {
364     LOG(WARNING) << "Message received on unknown channel: "
365                  << channel()->label();
366     return {};
367   }
368 };
369 
370 template <typename H>
371 class DataChannelHandlerImpl : public H {
372  public:
DataChannelHandlerImpl(rtc::scoped_refptr<webrtc::DataChannelInterface> channel,std::shared_ptr<ConnectionObserver> observer)373   DataChannelHandlerImpl(
374       rtc::scoped_refptr<webrtc::DataChannelInterface> channel,
375       std::shared_ptr<ConnectionObserver> observer)
376       : channel_(channel), observer_(observer) {
377     channel->RegisterObserver(this);
378   }
~DataChannelHandlerImpl()379   ~DataChannelHandlerImpl() override { channel_->UnregisterObserver(); }
380 
381  protected:
382   // DataChannelHandler implementation
channel()383   rtc::scoped_refptr<webrtc::DataChannelInterface> channel() override {
384     return channel_;
385   }
observer()386   std::shared_ptr<ConnectionObserver> observer() override { return observer_; }
387 
388  private:
389   rtc::scoped_refptr<webrtc::DataChannelInterface> channel_;
390   std::shared_ptr<ConnectionObserver> observer_;
391 };
392 
393 }  // namespace
394 
Send(const uint8_t * msg,size_t size,bool binary)395 bool DataChannelHandler::Send(const uint8_t *msg, size_t size, bool binary) {
396   webrtc::DataBuffer buffer(rtc::CopyOnWriteBuffer(msg, size), binary);
397   // TODO (b/185832105): When the SCTP channel is congested data channel
398   // messages are buffered up to 16MB, when the buffer is full the channel
399   // is abruptly closed. Keep track of the buffered data to avoid losing the
400   // adb data channel.
401   return channel()->Send(buffer);
402 }
403 
Send(const Json::Value & message)404 bool DataChannelHandler::Send(const Json::Value &message) {
405   Json::StreamWriterBuilder factory;
406   std::string message_string = Json::writeString(factory, message);
407   return Send(reinterpret_cast<const uint8_t *>(message_string.c_str()),
408               message_string.size(), /*binary=*/false);
409 }
410 
OnStateChange()411 void DataChannelHandler::OnStateChange() {
412   LOG(VERBOSE) << channel()->label() << " channel state changed to "
413                << webrtc::DataChannelInterface::DataStateString(
414                       channel()->state());
415   OnStateChangeInner(channel()->state());
416 }
417 
OnMessage(const webrtc::DataBuffer & msg)418 void DataChannelHandler::OnMessage(const webrtc::DataBuffer &msg) {
419   if (!first_msg_received_) {
420     first_msg_received_ = true;
421     OnFirstMessage();
422   }
423   auto res = OnMessageInner(msg);
424   if (!res.ok()) {
425     LOG(ERROR) << res.error().FormatForEnv();
426   }
427 }
428 
DataChannelHandlers(std::shared_ptr<ConnectionObserver> observer)429 DataChannelHandlers::DataChannelHandlers(
430     std::shared_ptr<ConnectionObserver> observer)
431     : observer_(observer) {}
432 
~DataChannelHandlers()433 DataChannelHandlers::~DataChannelHandlers() {}
434 
OnDataChannelOpen(rtc::scoped_refptr<webrtc::DataChannelInterface> channel)435 void DataChannelHandlers::OnDataChannelOpen(
436     rtc::scoped_refptr<webrtc::DataChannelInterface> channel) {
437   auto label = channel->label();
438   LOG(VERBOSE) << "Data channel connected: " << label;
439   if (label == kInputChannelLabel) {
440     input_.reset(
441         new DataChannelHandlerImpl<InputChannelHandler>(channel, observer_));
442   } else if (label == kControlChannelLabel) {
443     control_.reset(
444         new DataChannelHandlerImpl<ControlChannelHandler>(channel, observer_));
445   } else if (label == kAdbChannelLabel) {
446     adb_.reset(
447         new DataChannelHandlerImpl<AdbChannelHandler>(channel, observer_));
448   } else if (label == kBluetoothChannelLabel) {
449     bluetooth_.reset(new DataChannelHandlerImpl<BluetoothChannelHandler>(
450         channel, observer_));
451   } else if (label == kCameraDataChannelLabel) {
452     camera_.reset(
453         new DataChannelHandlerImpl<CameraChannelHandler>(channel, observer_));
454   } else if (label == kLightsChannelLabel) {
455     lights_.reset(
456         new DataChannelHandlerImpl<LightsChannelHandler>(channel, observer_));
457   } else if (label == kLocationDataChannelLabel) {
458     location_.reset(
459         new DataChannelHandlerImpl<LocationChannelHandler>(channel, observer_));
460   } else if (label == kKmlLocationsDataChannelLabel) {
461     kml_location_.reset(new DataChannelHandlerImpl<KmlLocationChannelHandler>(
462         channel, observer_));
463   } else if (label == kGpxLocationsDataChannelLabel) {
464     gpx_location_.reset(new DataChannelHandlerImpl<GpxLocationChannelHandler>(
465         channel, observer_));
466   } else if (label == kSensorsDataChannelLabel) {
467     sensors_.reset(new DataChannelHandlerImpl<SensorsChannelHandler>(
468         channel, observer_));
469   } else {
470     unknown_channels_.emplace_back(
471         new DataChannelHandlerImpl<UnknownChannelHandler>(channel, observer_));
472   }
473 }
474 
475 }  // namespace webrtc_streaming
476 }  // namespace cuttlefish
477