• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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 kLocationDataChannelLabel = "location-channel";
69 static constexpr auto kKmlLocationsDataChannelLabel = "kml-locations-channel";
70 static constexpr auto kGpxLocationsDataChannelLabel = "gpx-locations-channel";
71 static constexpr auto kCameraDataEof = "EOF";
72 
73 // These classes use the Template pattern to minimize code repetition between
74 // data channel handlers.
75 
76 class InputChannelHandler : public DataChannelHandler {
77  public:
OnMessageInner(const webrtc::DataBuffer & msg)78   void OnMessageInner(const webrtc::DataBuffer &msg) override {
79     if (msg.binary) {
80       // TODO (jemoreira) consider binary protocol to avoid JSON parsing
81       // overhead
82       LOG(ERROR) << "Received invalid (binary) data on input channel";
83       return;
84     }
85     auto size = msg.size();
86 
87     Json::Value evt;
88     Json::CharReaderBuilder builder;
89     std::unique_ptr<Json::CharReader> json_reader(builder.newCharReader());
90     std::string errorMessage;
91     auto str = msg.data.cdata<char>();
92     if (!json_reader->parse(str, str + size, &evt, &errorMessage) < 0) {
93       LOG(ERROR) << "Received invalid JSON object over input channel: "
94                  << errorMessage;
95       return;
96     }
97     if (!evt.isMember("type") || !evt["type"].isString()) {
98       LOG(ERROR) << "Input event doesn't have a valid 'type' field: "
99                  << evt.toStyledString();
100       return;
101     }
102     auto event_type = evt["type"].asString();
103     if (event_type == "mouse") {
104       auto result =
105           ValidateJsonObject(evt, "mouse",
106                              {{"down", Json::ValueType::intValue},
107                               {"x", Json::ValueType::intValue},
108                               {"y", Json::ValueType::intValue},
109                               {"display_label", Json::ValueType::stringValue}});
110       if (!result.ok()) {
111         LOG(ERROR) << result.error().Trace();
112         return;
113       }
114       auto label = evt["display_label"].asString();
115       int32_t down = evt["down"].asInt();
116       int32_t x = evt["x"].asInt();
117       int32_t y = evt["y"].asInt();
118 
119       observer()->OnTouchEvent(label, x, y, down);
120     } else if (event_type == "multi-touch") {
121       auto result =
122           ValidateJsonObject(evt, "multi-touch",
123                              {{"id", Json::ValueType::arrayValue},
124                               {"down", Json::ValueType::intValue},
125                               {"x", Json::ValueType::arrayValue},
126                               {"y", Json::ValueType::arrayValue},
127                               {"slot", Json::ValueType::arrayValue},
128                               {"display_label", Json::ValueType::stringValue}});
129       if (!result.ok()) {
130         LOG(ERROR) << result.error().Trace();
131         return;
132       }
133 
134       auto label = evt["display_label"].asString();
135       auto idArr = evt["id"];
136       int32_t down = evt["down"].asInt();
137       auto xArr = evt["x"];
138       auto yArr = evt["y"];
139       auto slotArr = evt["slot"];
140       int size = evt["id"].size();
141 
142       observer()->OnMultiTouchEvent(label, idArr, slotArr, xArr, yArr, down,
143                                     size);
144     } else if (event_type == "keyboard") {
145       auto result =
146           ValidateJsonObject(evt, "keyboard",
147                              {{"event_type", Json::ValueType::stringValue},
148                               {"keycode", Json::ValueType::stringValue}});
149       if (!result.ok()) {
150         LOG(ERROR) << result.error().Trace();
151         return;
152       }
153       auto down = evt["event_type"].asString() == std::string("keydown");
154       auto code = DomKeyCodeToLinux(evt["keycode"].asString());
155       observer()->OnKeyboardEvent(code, down);
156     } else {
157       LOG(ERROR) << "Unrecognized event type: " << event_type;
158       return;
159     }
160   }
161 };
162 
163 class ControlChannelHandler : public DataChannelHandler {
164  public:
OnStateChangeInner(webrtc::DataChannelInterface::DataState state)165   void OnStateChangeInner(
166       webrtc::DataChannelInterface::DataState state) override {
167     if (state == webrtc::DataChannelInterface::kOpen) {
168       observer()->OnControlChannelOpen(GetJSONSender());
169     }
170   }
OnMessageInner(const webrtc::DataBuffer & msg)171   void OnMessageInner(const webrtc::DataBuffer &msg) override {
172     auto msg_str = msg.data.cdata<char>();
173     auto size = msg.size();
174     Json::Value evt;
175     Json::CharReaderBuilder builder;
176     std::unique_ptr<Json::CharReader> json_reader(builder.newCharReader());
177     std::string errorMessage;
178     if (!json_reader->parse(msg_str, msg_str + size, &evt, &errorMessage)) {
179       LOG(ERROR) << "Received invalid JSON object over control channel: "
180                  << errorMessage;
181       return;
182     }
183 
184     auto result = ValidateJsonObject(
185         evt, "command",
186         /*required_fields=*/{{"command", Json::ValueType::stringValue}},
187         /*optional_fields=*/
188         {
189             {"button_state", Json::ValueType::stringValue},
190             {"lid_switch_open", Json::ValueType::booleanValue},
191             {"hinge_angle_value", Json::ValueType::intValue},
192         });
193     if (!result.ok()) {
194       LOG(ERROR) << result.error().Trace();
195       return;
196     }
197     auto command = evt["command"].asString();
198 
199     if (command == "device_state") {
200       if (evt.isMember("lid_switch_open")) {
201         observer()->OnLidStateChange(evt["lid_switch_open"].asBool());
202       }
203       if (evt.isMember("hinge_angle_value")) {
204         observer()->OnHingeAngleChange(evt["hinge_angle_value"].asInt());
205       }
206       return;
207     } else if (command.rfind("camera_", 0) == 0) {
208       observer()->OnCameraControlMsg(evt);
209       return;
210     }
211 
212     auto button_state = evt["button_state"].asString();
213     LOG(VERBOSE) << "Control command: " << command << " (" << button_state
214                  << ")";
215     if (command == "power") {
216       observer()->OnPowerButton(button_state == "down");
217     } else if (command == "back") {
218       observer()->OnBackButton(button_state == "down");
219     } else if (command == "home") {
220       observer()->OnHomeButton(button_state == "down");
221     } else if (command == "menu") {
222       observer()->OnMenuButton(button_state == "down");
223     } else if (command == "volumedown") {
224       observer()->OnVolumeDownButton(button_state == "down");
225     } else if (command == "volumeup") {
226       observer()->OnVolumeUpButton(button_state == "down");
227     } else {
228       observer()->OnCustomActionButton(command, button_state);
229     }
230   }
231 };
232 
233 class AdbChannelHandler : public DataChannelHandler {
234  public:
OnMessageInner(const webrtc::DataBuffer & msg)235   void OnMessageInner(const webrtc::DataBuffer &msg) override {
236     observer()->OnAdbMessage(msg.data.cdata(), msg.size());
237   }
OnFirstMessage()238   void OnFirstMessage() override {
239     // Report the adb channel as open on the first message received instead of
240     // at channel open, this avoids unnecessarily connecting to the adb daemon
241     // for clients that don't use ADB.
242     observer()->OnAdbChannelOpen(GetBinarySender());
243   }
244 };
245 
246 class BluetoothChannelHandler : public DataChannelHandler {
247  public:
OnMessageInner(const webrtc::DataBuffer & msg)248   void OnMessageInner(const webrtc::DataBuffer &msg) override {
249     observer()->OnBluetoothMessage(msg.data.cdata(), msg.size());
250   }
OnFirstMessage()251   void OnFirstMessage() override {
252     // Notify bluetooth channel opening when actually using the channel,
253     // it has the same reason with AdbChannelHandler::OnMessageInner,
254     // to avoid unnecessary connection for Rootcanal.
255     observer()->OnBluetoothChannelOpen(GetBinarySender());
256   }
257 };
258 
259 class CameraChannelHandler : public DataChannelHandler {
260  public:
OnMessageInner(const webrtc::DataBuffer & msg)261   void OnMessageInner(const webrtc::DataBuffer &msg) override {
262     auto msg_data = msg.data.cdata<char>();
263     if (msg.size() == strlen(kCameraDataEof) &&
264         !strncmp(msg_data, kCameraDataEof, msg.size())) {
265       // Send complete buffer to observer on EOF marker
266       observer()->OnCameraData(receive_buffer_);
267       receive_buffer_.clear();
268       return;
269     }
270     // Otherwise buffer up data
271     receive_buffer_.insert(receive_buffer_.end(), msg_data,
272                            msg_data + msg.size());
273   }
274 
275  private:
276   std::vector<char> receive_buffer_;
277 };
278 
279 class LocationChannelHandler : public DataChannelHandler {
280  public:
OnMessageInner(const webrtc::DataBuffer & msg)281   void OnMessageInner(const webrtc::DataBuffer &msg) override {
282     observer()->OnLocationMessage(msg.data.cdata(), msg.size());
283   }
OnFirstMessage()284   void OnFirstMessage() override {
285     // Notify location channel opening when actually using the channel,
286     // it has the same reason with AdbChannelHandler::OnMessageInner,
287     // to avoid unnecessary connections.
288     observer()->OnLocationChannelOpen(GetBinarySender());
289   }
290 };
291 
292 class KmlLocationChannelHandler : public DataChannelHandler {
293  public:
OnMessageInner(const webrtc::DataBuffer & msg)294   void OnMessageInner(const webrtc::DataBuffer &msg) override {
295     observer()->OnKmlLocationsMessage(msg.data.cdata(), msg.size());
296   }
OnFirstMessage()297   void OnFirstMessage() override {
298     // Notify location channel opening when actually using the channel,
299     // it has the same reason with AdbChannelHandler::OnMessageInner,
300     // to avoid unnecessary connections.
301     observer()->OnKmlLocationsChannelOpen(GetBinarySender());
302   }
303 };
304 
305 class GpxLocationChannelHandler : public DataChannelHandler {
306  public:
OnMessageInner(const webrtc::DataBuffer & msg)307   void OnMessageInner(const webrtc::DataBuffer &msg) override {
308     observer()->OnGpxLocationsMessage(msg.data.cdata(), msg.size());
309   }
OnFirstMessage()310   void OnFirstMessage() override {
311     // Notify location channel opening when actually using the channel,
312     // it has the same reason with AdbChannelHandler::OnMessageInner,
313     // to avoid unnecessary connections.
314     observer()->OnGpxLocationsChannelOpen(GetBinarySender());
315   }
316 };
317 
318 class UnknownChannelHandler : public DataChannelHandler {
319  public:
OnMessageInner(const webrtc::DataBuffer &)320   void OnMessageInner(const webrtc::DataBuffer &) override {
321     LOG(WARNING) << "Message received on unknown channel: "
322                  << channel()->label();
323   }
324 };
325 
326 template <typename H>
327 class DataChannelHandlerImpl : public H {
328  public:
DataChannelHandlerImpl(rtc::scoped_refptr<webrtc::DataChannelInterface> channel,std::shared_ptr<ConnectionObserver> observer)329   DataChannelHandlerImpl(
330       rtc::scoped_refptr<webrtc::DataChannelInterface> channel,
331       std::shared_ptr<ConnectionObserver> observer)
332       : channel_(channel), observer_(observer) {
333     channel->RegisterObserver(this);
334   }
~DataChannelHandlerImpl()335   ~DataChannelHandlerImpl() override { channel_->UnregisterObserver(); }
336 
337  protected:
338   // DataChannelHandler implementation
channel()339   rtc::scoped_refptr<webrtc::DataChannelInterface> channel() override {
340     return channel_;
341   }
observer()342   std::shared_ptr<ConnectionObserver> observer() override { return observer_; }
343 
344  private:
345   rtc::scoped_refptr<webrtc::DataChannelInterface> channel_;
346   std::shared_ptr<ConnectionObserver> observer_;
347 };
348 
349 }  // namespace
350 
Send(const uint8_t * msg,size_t size,bool binary)351 bool DataChannelHandler::Send(const uint8_t *msg, size_t size, bool binary) {
352   webrtc::DataBuffer buffer(rtc::CopyOnWriteBuffer(msg, size), binary);
353   // TODO (b/185832105): When the SCTP channel is congested data channel
354   // messages are buffered up to 16MB, when the buffer is full the channel
355   // is abruptly closed. Keep track of the buffered data to avoid losing the
356   // adb data channel.
357   return channel()->Send(buffer);
358 }
359 
Send(const Json::Value & message)360 bool DataChannelHandler::Send(const Json::Value &message) {
361   Json::StreamWriterBuilder factory;
362   std::string message_string = Json::writeString(factory, message);
363   return Send(reinterpret_cast<const uint8_t *>(message_string.c_str()),
364               message_string.size(), /*binary=*/false);
365 }
366 
OnStateChange()367 void DataChannelHandler::OnStateChange() {
368   LOG(VERBOSE) << channel()->label() << " channel state changed to "
369                << webrtc::DataChannelInterface::DataStateString(
370                       channel()->state());
371   OnStateChangeInner(channel()->state());
372 }
373 
OnMessage(const webrtc::DataBuffer & msg)374 void DataChannelHandler::OnMessage(const webrtc::DataBuffer &msg) {
375   if (!first_msg_received_) {
376     first_msg_received_ = true;
377     OnFirstMessage();
378   }
379   OnMessageInner(msg);
380 }
381 
DataChannelHandlers(std::shared_ptr<ConnectionObserver> observer)382 DataChannelHandlers::DataChannelHandlers(
383     std::shared_ptr<ConnectionObserver> observer)
384     : observer_(observer) {}
385 
~DataChannelHandlers()386 DataChannelHandlers::~DataChannelHandlers() {}
387 
OnDataChannelOpen(rtc::scoped_refptr<webrtc::DataChannelInterface> channel)388 void DataChannelHandlers::OnDataChannelOpen(
389     rtc::scoped_refptr<webrtc::DataChannelInterface> channel) {
390   auto label = channel->label();
391   LOG(VERBOSE) << "Data channel connected: " << label;
392   if (label == kInputChannelLabel) {
393     input_.reset(
394         new DataChannelHandlerImpl<InputChannelHandler>(channel, observer_));
395   } else if (label == kControlChannelLabel) {
396     control_.reset(
397         new DataChannelHandlerImpl<ControlChannelHandler>(channel, observer_));
398   } else if (label == kAdbChannelLabel) {
399     adb_.reset(
400         new DataChannelHandlerImpl<AdbChannelHandler>(channel, observer_));
401   } else if (label == kBluetoothChannelLabel) {
402     bluetooth_.reset(new DataChannelHandlerImpl<BluetoothChannelHandler>(
403         channel, observer_));
404   } else if (label == kCameraDataChannelLabel) {
405     camera_.reset(
406         new DataChannelHandlerImpl<CameraChannelHandler>(channel, observer_));
407   } else if (label == kLocationDataChannelLabel) {
408     location_.reset(
409         new DataChannelHandlerImpl<LocationChannelHandler>(channel, observer_));
410   } else if (label == kKmlLocationsDataChannelLabel) {
411     kml_location_.reset(new DataChannelHandlerImpl<KmlLocationChannelHandler>(
412         channel, observer_));
413   } else if (label == kGpxLocationsDataChannelLabel) {
414     gpx_location_.reset(new DataChannelHandlerImpl<GpxLocationChannelHandler>(
415         channel, observer_));
416   } else {
417     unknown_channels_.emplace_back(
418         new DataChannelHandlerImpl<UnknownChannelHandler>(channel, observer_));
419   }
420 }
421 
422 }  // namespace webrtc_streaming
423 }  // namespace cuttlefish
424