Roll src/third_party/WebKit 06cb9e9:a978ee5 (svn 202558:202559)
[chromium-blink-merge.git] / remoting / client / jni / chromoting_jni_instance.cc
blobba7672b3938d45ac9d537df75f0c10474772a68e
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "remoting/client/jni/chromoting_jni_instance.h"
7 #include <android/log.h>
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "jingle/glue/thread_wrapper.h"
12 #include "net/socket/client_socket_factory.h"
13 #include "remoting/base/service_urls.h"
14 #include "remoting/client/audio_player.h"
15 #include "remoting/client/client_status_logger.h"
16 #include "remoting/client/jni/android_keymap.h"
17 #include "remoting/client/jni/chromoting_jni_runtime.h"
18 #include "remoting/client/jni/jni_frame_consumer.h"
19 #include "remoting/client/software_video_renderer.h"
20 #include "remoting/client/token_fetcher_proxy.h"
21 #include "remoting/protocol/chromium_port_allocator.h"
22 #include "remoting/protocol/chromium_socket_factory.h"
23 #include "remoting/protocol/host_stub.h"
24 #include "remoting/protocol/libjingle_transport_factory.h"
25 #include "remoting/protocol/negotiating_client_authenticator.h"
26 #include "remoting/protocol/network_settings.h"
27 #include "remoting/protocol/performance_tracker.h"
28 #include "remoting/signaling/server_log_entry.h"
29 #include "ui/events/keycodes/dom/keycode_converter.h"
31 namespace remoting {
33 namespace {
35 // TODO(solb) Move into location shared with client plugin.
36 const char* const kXmppServer = "talk.google.com";
37 const int kXmppPort = 5222;
38 const bool kXmppUseTls = true;
40 // Interval at which to log performance statistics, if enabled.
41 const int kPerfStatsIntervalMs = 60000;
45 ChromotingJniInstance::ChromotingJniInstance(ChromotingJniRuntime* jni_runtime,
46 const char* username,
47 const char* auth_token,
48 const char* host_jid,
49 const char* host_id,
50 const char* host_pubkey,
51 const char* pairing_id,
52 const char* pairing_secret,
53 const char* capabilities)
54 : jni_runtime_(jni_runtime),
55 host_id_(host_id),
56 host_jid_(host_jid),
57 create_pairing_(false),
58 stats_logging_enabled_(false),
59 capabilities_(capabilities),
60 weak_factory_(this) {
61 DCHECK(jni_runtime_->ui_task_runner()->BelongsToCurrentThread());
63 // Intialize XMPP config.
64 xmpp_config_.host = kXmppServer;
65 xmpp_config_.port = kXmppPort;
66 xmpp_config_.use_tls = kXmppUseTls;
67 xmpp_config_.username = username;
68 xmpp_config_.auth_token = auth_token;
70 // Initialize |authenticator_|.
71 scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>
72 token_fetcher(new TokenFetcherProxy(
73 base::Bind(&ChromotingJniInstance::FetchThirdPartyToken,
74 weak_factory_.GetWeakPtr()),
75 host_pubkey));
77 std::vector<protocol::AuthenticationMethod> auth_methods;
78 auth_methods.push_back(protocol::AuthenticationMethod::Spake2Pair());
79 auth_methods.push_back(protocol::AuthenticationMethod::Spake2(
80 protocol::AuthenticationMethod::HMAC_SHA256));
81 auth_methods.push_back(protocol::AuthenticationMethod::Spake2(
82 protocol::AuthenticationMethod::NONE));
83 auth_methods.push_back(protocol::AuthenticationMethod::ThirdParty());
85 authenticator_.reset(new protocol::NegotiatingClientAuthenticator(
86 pairing_id, pairing_secret, host_id_,
87 base::Bind(&ChromotingJniInstance::FetchSecret, this),
88 token_fetcher.Pass(), auth_methods));
90 // Post a task to start connection
91 jni_runtime_->network_task_runner()->PostTask(
92 FROM_HERE,
93 base::Bind(&ChromotingJniInstance::ConnectToHostOnNetworkThread, this));
96 ChromotingJniInstance::~ChromotingJniInstance() {
97 // This object is ref-counted, so this dtor can execute on any thread.
98 // Ensure that all these objects have been freed already, so they are not
99 // destroyed on some random thread.
100 DCHECK(!view_);
101 DCHECK(!client_context_);
102 DCHECK(!video_renderer_);
103 DCHECK(!authenticator_);
104 DCHECK(!client_);
105 DCHECK(!signaling_);
106 DCHECK(!client_status_logger_);
109 void ChromotingJniInstance::Disconnect() {
110 if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
111 jni_runtime_->network_task_runner()->PostTask(
112 FROM_HERE,
113 base::Bind(&ChromotingJniInstance::Disconnect, this));
114 return;
117 host_id_.clear();
119 stats_logging_enabled_ = false;
121 // |client_| must be torn down before |signaling_|.
122 client_.reset();
123 client_status_logger_.reset();
124 video_renderer_.reset();
125 view_.reset();
126 authenticator_.reset();
127 signaling_.reset();
128 perf_tracker_.reset();
129 client_context_.reset();
132 void ChromotingJniInstance::FetchThirdPartyToken(
133 const GURL& token_url,
134 const std::string& client_id,
135 const std::string& scope,
136 base::WeakPtr<TokenFetcherProxy> token_fetcher_proxy) {
137 DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
138 DCHECK(!token_fetcher_proxy_.get());
140 __android_log_print(ANDROID_LOG_INFO,
141 "ThirdPartyAuth",
142 "Fetching Third Party Token from user.");
144 token_fetcher_proxy_ = token_fetcher_proxy;
145 jni_runtime_->ui_task_runner()->PostTask(
146 FROM_HERE,
147 base::Bind(&ChromotingJniRuntime::FetchThirdPartyToken,
148 base::Unretained(jni_runtime_),
149 token_url,
150 client_id,
151 scope));
154 void ChromotingJniInstance::HandleOnThirdPartyTokenFetched(
155 const std::string& token,
156 const std::string& shared_secret) {
157 DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
159 __android_log_print(
160 ANDROID_LOG_INFO, "ThirdPartyAuth", "Third Party Token Fetched.");
162 if (token_fetcher_proxy_.get()) {
163 token_fetcher_proxy_->OnTokenFetched(token, shared_secret);
164 token_fetcher_proxy_.reset();
165 } else {
166 __android_log_print(
167 ANDROID_LOG_WARN,
168 "ThirdPartyAuth",
169 "Ignored OnThirdPartyTokenFetched() without a pending fetch.");
173 void ChromotingJniInstance::ProvideSecret(const std::string& pin,
174 bool create_pairing,
175 const std::string& device_name) {
176 DCHECK(jni_runtime_->ui_task_runner()->BelongsToCurrentThread());
177 DCHECK(!pin_callback_.is_null());
179 create_pairing_ = create_pairing;
181 if (create_pairing)
182 SetDeviceName(device_name);
184 jni_runtime_->network_task_runner()->PostTask(FROM_HERE,
185 base::Bind(pin_callback_, pin));
188 void ChromotingJniInstance::RedrawDesktop() {
189 if (!jni_runtime_->display_task_runner()->BelongsToCurrentThread()) {
190 jni_runtime_->display_task_runner()->PostTask(
191 FROM_HERE,
192 base::Bind(&ChromotingJniInstance::RedrawDesktop, this));
193 return;
196 jni_runtime_->RedrawCanvas();
199 void ChromotingJniInstance::SendMouseEvent(
200 int x, int y,
201 protocol::MouseEvent_MouseButton button,
202 bool button_down) {
203 if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
204 jni_runtime_->network_task_runner()->PostTask(
205 FROM_HERE, base::Bind(&ChromotingJniInstance::SendMouseEvent,
206 this, x, y, button, button_down));
207 return;
210 protocol::MouseEvent event;
211 event.set_x(x);
212 event.set_y(y);
213 event.set_button(button);
214 if (button != protocol::MouseEvent::BUTTON_UNDEFINED)
215 event.set_button_down(button_down);
217 client_->input_stub()->InjectMouseEvent(event);
220 void ChromotingJniInstance::SendMouseWheelEvent(int delta_x, int delta_y) {
221 if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
222 jni_runtime_->network_task_runner()->PostTask(
223 FROM_HERE,
224 base::Bind(&ChromotingJniInstance::SendMouseWheelEvent, this,
225 delta_x, delta_y));
226 return;
229 protocol::MouseEvent event;
230 event.set_wheel_delta_x(delta_x);
231 event.set_wheel_delta_y(delta_y);
232 client_->input_stub()->InjectMouseEvent(event);
235 bool ChromotingJniInstance::SendKeyEvent(int scan_code,
236 int key_code,
237 bool key_down) {
238 // For software keyboards |scan_code| is set to 0, in which case the
239 // |key_code| is used instead.
240 uint32_t usb_key_code =
241 scan_code ? ui::KeycodeConverter::NativeKeycodeToUsbKeycode(scan_code)
242 : AndroidKeycodeToUsbKeycode(key_code);
243 if (!usb_key_code) {
244 LOG(WARNING) << "Ignoring unknown key code: " << key_code
245 << " scan code: " << scan_code;
246 return false;
249 SendKeyEventInternal(usb_key_code, key_down);
250 return true;
253 void ChromotingJniInstance::SendTextEvent(const std::string& text) {
254 if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
255 jni_runtime_->network_task_runner()->PostTask(
256 FROM_HERE,
257 base::Bind(&ChromotingJniInstance::SendTextEvent, this, text));
258 return;
261 protocol::TextEvent event;
262 event.set_text(text);
263 client_->input_stub()->InjectTextEvent(event);
266 void ChromotingJniInstance::EnableVideoChannel(bool enable) {
267 if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
268 jni_runtime_->network_task_runner()->PostTask(
269 FROM_HERE,
270 base::Bind(&ChromotingJniInstance::EnableVideoChannel, this, enable));
271 return;
274 protocol::VideoControl video_control;
275 video_control.set_enable(enable);
276 client_->host_stub()->ControlVideo(video_control);
279 void ChromotingJniInstance::SendClientMessage(const std::string& type,
280 const std::string& data) {
281 if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
282 jni_runtime_->network_task_runner()->PostTask(
283 FROM_HERE,
284 base::Bind(
285 &ChromotingJniInstance::SendClientMessage, this, type, data));
286 return;
289 protocol::ExtensionMessage extension_message;
290 extension_message.set_type(type);
291 extension_message.set_data(data);
292 client_->host_stub()->DeliverClientMessage(extension_message);
295 void ChromotingJniInstance::RecordPaintTime(int64 paint_time_ms) {
296 if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
297 jni_runtime_->network_task_runner()->PostTask(
298 FROM_HERE, base::Bind(&ChromotingJniInstance::RecordPaintTime, this,
299 paint_time_ms));
300 return;
303 if (stats_logging_enabled_)
304 perf_tracker_->RecordPaintTime(paint_time_ms);
307 void ChromotingJniInstance::OnConnectionState(
308 protocol::ConnectionToHost::State state,
309 protocol::ErrorCode error) {
310 DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
312 EnableStatsLogging(state == protocol::ConnectionToHost::CONNECTED);
314 client_status_logger_->LogSessionStateChange(state, error);
316 if (create_pairing_ && state == protocol::ConnectionToHost::CONNECTED) {
317 protocol::PairingRequest request;
318 DCHECK(!device_name_.empty());
319 request.set_client_name(device_name_);
320 client_->host_stub()->RequestPairing(request);
323 jni_runtime_->ui_task_runner()->PostTask(
324 FROM_HERE,
325 base::Bind(&ChromotingJniRuntime::OnConnectionState,
326 base::Unretained(jni_runtime_),
327 state,
328 error));
331 void ChromotingJniInstance::OnConnectionReady(bool ready) {
332 // We ignore this message, since OnConnectionState tells us the same thing.
335 void ChromotingJniInstance::OnRouteChanged(
336 const std::string& channel_name,
337 const protocol::TransportRoute& route) {
338 std::string message = "Channel " + channel_name + " using " +
339 protocol::TransportRoute::GetTypeString(route.type) + " connection.";
340 __android_log_print(ANDROID_LOG_INFO, "route", "%s", message.c_str());
343 void ChromotingJniInstance::SetCapabilities(const std::string& capabilities) {
344 jni_runtime_->ui_task_runner()->PostTask(
345 FROM_HERE,
346 base::Bind(&ChromotingJniRuntime::SetCapabilities,
347 base::Unretained(jni_runtime_),
348 capabilities));
351 void ChromotingJniInstance::SetPairingResponse(
352 const protocol::PairingResponse& response) {
354 jni_runtime_->ui_task_runner()->PostTask(
355 FROM_HERE,
356 base::Bind(&ChromotingJniRuntime::CommitPairingCredentials,
357 base::Unretained(jni_runtime_),
358 host_id_, response.client_id(), response.shared_secret()));
361 void ChromotingJniInstance::DeliverHostMessage(
362 const protocol::ExtensionMessage& message) {
363 jni_runtime_->ui_task_runner()->PostTask(
364 FROM_HERE,
365 base::Bind(&ChromotingJniRuntime::HandleExtensionMessage,
366 base::Unretained(jni_runtime_),
367 message.type(),
368 message.data()));
371 protocol::ClipboardStub* ChromotingJniInstance::GetClipboardStub() {
372 return this;
375 protocol::CursorShapeStub* ChromotingJniInstance::GetCursorShapeStub() {
376 return this;
379 void ChromotingJniInstance::InjectClipboardEvent(
380 const protocol::ClipboardEvent& event) {
381 NOTIMPLEMENTED();
384 void ChromotingJniInstance::SetCursorShape(
385 const protocol::CursorShapeInfo& shape) {
386 if (!jni_runtime_->display_task_runner()->BelongsToCurrentThread()) {
387 jni_runtime_->display_task_runner()->PostTask(
388 FROM_HERE,
389 base::Bind(&ChromotingJniInstance::SetCursorShape, this, shape));
390 return;
393 jni_runtime_->UpdateCursorShape(shape);
396 void ChromotingJniInstance::ConnectToHostOnNetworkThread() {
397 DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
399 jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop();
401 client_context_.reset(new ClientContext(jni_runtime_->network_task_runner()));
402 client_context_->Start();
404 perf_tracker_.reset(new protocol::PerformanceTracker());
406 view_.reset(new JniFrameConsumer(jni_runtime_));
407 video_renderer_.reset(new SoftwareVideoRenderer(
408 client_context_->decode_task_runner(), view_.get(), perf_tracker_.get()));
410 client_.reset(new ChromotingClient(
411 client_context_.get(), this, video_renderer_.get(), nullptr));
413 signaling_.reset(new XmppSignalStrategy(
414 net::ClientSocketFactory::GetDefaultFactory(),
415 jni_runtime_->url_requester(), xmpp_config_));
417 client_status_logger_.reset(
418 new ClientStatusLogger(ServerLogEntry::ME2ME,
419 signaling_.get(),
420 ServiceUrls::GetInstance()->directory_bot_jid()));
422 protocol::NetworkSettings network_settings(
423 protocol::NetworkSettings::NAT_TRAVERSAL_FULL);
425 // Use Chrome's network stack to allocate ports for peer-to-peer channels.
426 scoped_ptr<protocol::ChromiumPortAllocator> port_allocator(
427 protocol::ChromiumPortAllocator::Create(jni_runtime_->url_requester(),
428 network_settings));
430 scoped_ptr<protocol::TransportFactory> transport_factory(
431 new protocol::LibjingleTransportFactory(
432 signaling_.get(), port_allocator.Pass(), network_settings,
433 protocol::TransportRole::CLIENT));
435 client_->Start(signaling_.get(), authenticator_.Pass(),
436 transport_factory.Pass(), host_jid_, capabilities_);
439 void ChromotingJniInstance::FetchSecret(
440 bool pairable,
441 const protocol::SecretFetchedCallback& callback) {
442 if (!jni_runtime_->ui_task_runner()->BelongsToCurrentThread()) {
443 jni_runtime_->ui_task_runner()->PostTask(
444 FROM_HERE, base::Bind(&ChromotingJniInstance::FetchSecret,
445 this, pairable, callback));
446 return;
449 // Delete pairing credentials if they exist.
450 jni_runtime_->CommitPairingCredentials(host_id_, "", "");
452 pin_callback_ = callback;
453 jni_runtime_->DisplayAuthenticationPrompt(pairable);
456 void ChromotingJniInstance::SetDeviceName(const std::string& device_name) {
457 if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
458 jni_runtime_->network_task_runner()->PostTask(
459 FROM_HERE, base::Bind(&ChromotingJniInstance::SetDeviceName, this,
460 device_name));
461 return;
464 device_name_ = device_name;
467 void ChromotingJniInstance::SendKeyEventInternal(int usb_key_code,
468 bool key_down) {
469 if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
470 jni_runtime_->network_task_runner()->PostTask(
471 FROM_HERE, base::Bind(&ChromotingJniInstance::SendKeyEventInternal,
472 this, usb_key_code, key_down));
473 return;
476 protocol::KeyEvent event;
477 event.set_usb_keycode(usb_key_code);
478 event.set_pressed(key_down);
479 client_->input_stub()->InjectKeyEvent(event);
482 void ChromotingJniInstance::EnableStatsLogging(bool enabled) {
483 DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
485 if (enabled && !stats_logging_enabled_) {
486 jni_runtime_->network_task_runner()->PostDelayedTask(
487 FROM_HERE, base::Bind(&ChromotingJniInstance::LogPerfStats, this),
488 base::TimeDelta::FromMilliseconds(kPerfStatsIntervalMs));
490 stats_logging_enabled_ = enabled;
493 void ChromotingJniInstance::LogPerfStats() {
494 DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
496 if (!stats_logging_enabled_)
497 return;
499 __android_log_print(
500 ANDROID_LOG_INFO, "stats",
501 "Bandwidth:%.0f FrameRate:%.1f Capture:%.1f Encode:%.1f "
502 "Decode:%.1f Render:%.1f Latency:%.0f",
503 perf_tracker_->video_bandwidth(), perf_tracker_->video_frame_rate(),
504 perf_tracker_->video_capture_ms(), perf_tracker_->video_encode_ms(),
505 perf_tracker_->video_decode_ms(), perf_tracker_->video_paint_ms(),
506 perf_tracker_->round_trip_ms());
508 client_status_logger_->LogStatistics(perf_tracker_.get());
510 jni_runtime_->network_task_runner()->PostDelayedTask(
511 FROM_HERE, base::Bind(&ChromotingJniInstance::LogPerfStats, this),
512 base::TimeDelta::FromMilliseconds(kPerfStatsIntervalMs));
515 } // namespace remoting