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