Blink roll 25b6bd3a7a131ffe68d809546ad1a20707915cdc:3a503f41ae42e5b79cfcd2ff10e65afde...
[chromium-blink-merge.git] / remoting / client / jni / chromoting_jni_instance.cc
blob1a691156a516707b2ee2d24a66e3076441ef9104
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/software_video_renderer.h"
19 #include "remoting/client/token_fetcher_proxy.h"
20 #include "remoting/protocol/chromium_port_allocator.h"
21 #include "remoting/protocol/chromium_socket_factory.h"
22 #include "remoting/protocol/host_stub.h"
23 #include "remoting/protocol/libjingle_transport_factory.h"
24 #include "remoting/protocol/negotiating_client_authenticator.h"
25 #include "remoting/protocol/network_settings.h"
26 #include "remoting/signaling/server_log_entry.h"
28 namespace remoting {
30 namespace {
32 // TODO(solb) Move into location shared with client plugin.
33 const char* const kXmppServer = "talk.google.com";
34 const int kXmppPort = 5222;
35 const bool kXmppUseTls = true;
37 // Interval at which to log performance statistics, if enabled.
38 const int kPerfStatsIntervalMs = 60000;
42 ChromotingJniInstance::ChromotingJniInstance(ChromotingJniRuntime* jni_runtime,
43 const char* username,
44 const char* auth_token,
45 const char* host_jid,
46 const char* host_id,
47 const char* host_pubkey,
48 const char* pairing_id,
49 const char* pairing_secret,
50 const char* capabilities)
51 : jni_runtime_(jni_runtime),
52 host_id_(host_id),
53 host_jid_(host_jid),
54 create_pairing_(false),
55 stats_logging_enabled_(false),
56 capabilities_(capabilities),
57 weak_factory_(this) {
58 DCHECK(jni_runtime_->ui_task_runner()->BelongsToCurrentThread());
60 // Intialize XMPP config.
61 xmpp_config_.host = kXmppServer;
62 xmpp_config_.port = kXmppPort;
63 xmpp_config_.use_tls = kXmppUseTls;
64 xmpp_config_.username = username;
65 xmpp_config_.auth_token = auth_token;
66 xmpp_config_.auth_service = "oauth2";
68 // Initialize |authenticator_|.
69 scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>
70 token_fetcher(new TokenFetcherProxy(
71 base::Bind(&ChromotingJniInstance::FetchThirdPartyToken,
72 weak_factory_.GetWeakPtr()),
73 host_pubkey));
75 std::vector<protocol::AuthenticationMethod> auth_methods;
76 auth_methods.push_back(protocol::AuthenticationMethod::Spake2Pair());
77 auth_methods.push_back(protocol::AuthenticationMethod::Spake2(
78 protocol::AuthenticationMethod::HMAC_SHA256));
79 auth_methods.push_back(protocol::AuthenticationMethod::Spake2(
80 protocol::AuthenticationMethod::NONE));
81 auth_methods.push_back(protocol::AuthenticationMethod::ThirdParty());
83 authenticator_.reset(new protocol::NegotiatingClientAuthenticator(
84 pairing_id, pairing_secret, host_id_,
85 base::Bind(&ChromotingJniInstance::FetchSecret, this),
86 token_fetcher.Pass(), auth_methods));
88 // Post a task to start connection
89 jni_runtime_->display_task_runner()->PostTask(
90 FROM_HERE,
91 base::Bind(&ChromotingJniInstance::ConnectToHostOnDisplayThread,
92 this));
95 ChromotingJniInstance::~ChromotingJniInstance() {
96 // This object is ref-counted, so this dtor can execute on any thread.
97 // Ensure that all these objects have been freed already, so they are not
98 // destroyed on some random thread.
99 DCHECK(!view_);
100 DCHECK(!client_context_);
101 DCHECK(!video_renderer_);
102 DCHECK(!authenticator_);
103 DCHECK(!client_);
104 DCHECK(!signaling_);
105 DCHECK(!client_status_logger_);
108 void ChromotingJniInstance::Disconnect() {
109 if (!jni_runtime_->display_task_runner()->BelongsToCurrentThread()) {
110 jni_runtime_->display_task_runner()->PostTask(
111 FROM_HERE,
112 base::Bind(&ChromotingJniInstance::Disconnect, this));
113 return;
116 // This must be destroyed on the display thread before the producer is gone.
117 view_.reset();
119 // The weak pointers must be invalidated on the same thread they were used.
120 view_weak_factory_->InvalidateWeakPtrs();
122 jni_runtime_->network_task_runner()->PostTask(
123 FROM_HERE,
124 base::Bind(&ChromotingJniInstance::DisconnectFromHostOnNetworkThread,
125 this));
128 void ChromotingJniInstance::FetchThirdPartyToken(
129 const GURL& token_url,
130 const std::string& client_id,
131 const std::string& scope,
132 base::WeakPtr<TokenFetcherProxy> token_fetcher_proxy) {
133 DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
134 DCHECK(!token_fetcher_proxy_.get());
136 __android_log_print(ANDROID_LOG_INFO,
137 "ThirdPartyAuth",
138 "Fetching Third Party Token from user.");
140 token_fetcher_proxy_ = token_fetcher_proxy;
141 jni_runtime_->ui_task_runner()->PostTask(
142 FROM_HERE,
143 base::Bind(&ChromotingJniRuntime::FetchThirdPartyToken,
144 base::Unretained(jni_runtime_),
145 token_url,
146 client_id,
147 scope));
150 void ChromotingJniInstance::HandleOnThirdPartyTokenFetched(
151 const std::string& token,
152 const std::string& shared_secret) {
153 DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
155 __android_log_print(
156 ANDROID_LOG_INFO, "ThirdPartyAuth", "Third Party Token Fetched.");
158 if (token_fetcher_proxy_.get()) {
159 token_fetcher_proxy_->OnTokenFetched(token, shared_secret);
160 token_fetcher_proxy_.reset();
161 } else {
162 __android_log_print(
163 ANDROID_LOG_WARN,
164 "ThirdPartyAuth",
165 "Ignored OnThirdPartyTokenFetched() without a pending fetch.");
169 void ChromotingJniInstance::ProvideSecret(const std::string& pin,
170 bool create_pairing,
171 const std::string& device_name) {
172 DCHECK(jni_runtime_->ui_task_runner()->BelongsToCurrentThread());
173 DCHECK(!pin_callback_.is_null());
175 create_pairing_ = create_pairing;
177 if (create_pairing)
178 SetDeviceName(device_name);
180 jni_runtime_->network_task_runner()->PostTask(FROM_HERE,
181 base::Bind(pin_callback_, pin));
184 void ChromotingJniInstance::RedrawDesktop() {
185 if (!jni_runtime_->display_task_runner()->BelongsToCurrentThread()) {
186 jni_runtime_->display_task_runner()->PostTask(
187 FROM_HERE,
188 base::Bind(&ChromotingJniInstance::RedrawDesktop, this));
189 return;
192 jni_runtime_->RedrawCanvas();
195 void ChromotingJniInstance::SendMouseEvent(
196 int x, int y,
197 protocol::MouseEvent_MouseButton button,
198 bool button_down) {
199 if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
200 jni_runtime_->network_task_runner()->PostTask(
201 FROM_HERE, base::Bind(&ChromotingJniInstance::SendMouseEvent,
202 this, x, y, button, button_down));
203 return;
206 protocol::MouseEvent event;
207 event.set_x(x);
208 event.set_y(y);
209 event.set_button(button);
210 if (button != protocol::MouseEvent::BUTTON_UNDEFINED)
211 event.set_button_down(button_down);
213 client_->input_stub()->InjectMouseEvent(event);
216 void ChromotingJniInstance::SendMouseWheelEvent(int delta_x, int delta_y) {
217 if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
218 jni_runtime_->network_task_runner()->PostTask(
219 FROM_HERE,
220 base::Bind(&ChromotingJniInstance::SendMouseWheelEvent, this,
221 delta_x, delta_y));
222 return;
225 protocol::MouseEvent event;
226 event.set_wheel_delta_x(delta_x);
227 event.set_wheel_delta_y(delta_y);
228 client_->input_stub()->InjectMouseEvent(event);
231 bool ChromotingJniInstance::SendKeyEvent(int key_code, bool key_down) {
232 uint32 usb_key_code = AndroidKeycodeToUsbKeycode(key_code);
233 if (!usb_key_code) {
234 LOG(WARNING) << "Ignoring unknown keycode: " << key_code;
235 return false;
238 SendKeyEventInternal(usb_key_code, key_down);
239 return true;
242 void ChromotingJniInstance::SendTextEvent(const std::string& text) {
243 if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
244 jni_runtime_->network_task_runner()->PostTask(
245 FROM_HERE,
246 base::Bind(&ChromotingJniInstance::SendTextEvent, this, text));
247 return;
250 protocol::TextEvent event;
251 event.set_text(text);
252 client_->input_stub()->InjectTextEvent(event);
255 void ChromotingJniInstance::SendClientMessage(const std::string& type,
256 const std::string& data) {
257 if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
258 jni_runtime_->network_task_runner()->PostTask(
259 FROM_HERE,
260 base::Bind(
261 &ChromotingJniInstance::SendClientMessage, this, type, data));
262 return;
265 protocol::ExtensionMessage extension_message;
266 extension_message.set_type(type);
267 extension_message.set_data(data);
268 client_->host_stub()->DeliverClientMessage(extension_message);
271 void ChromotingJniInstance::RecordPaintTime(int64 paint_time_ms) {
272 if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
273 jni_runtime_->network_task_runner()->PostTask(
274 FROM_HERE, base::Bind(&ChromotingJniInstance::RecordPaintTime, this,
275 paint_time_ms));
276 return;
279 if (stats_logging_enabled_)
280 video_renderer_->GetStats()->video_paint_ms()->Record(paint_time_ms);
283 void ChromotingJniInstance::OnConnectionState(
284 protocol::ConnectionToHost::State state,
285 protocol::ErrorCode error) {
286 DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
288 EnableStatsLogging(state == protocol::ConnectionToHost::CONNECTED);
290 client_status_logger_->LogSessionStateChange(state, error);
292 if (create_pairing_ && state == protocol::ConnectionToHost::CONNECTED) {
293 protocol::PairingRequest request;
294 DCHECK(!device_name_.empty());
295 request.set_client_name(device_name_);
296 client_->host_stub()->RequestPairing(request);
299 jni_runtime_->ui_task_runner()->PostTask(
300 FROM_HERE,
301 base::Bind(&ChromotingJniRuntime::OnConnectionState,
302 base::Unretained(jni_runtime_),
303 state,
304 error));
307 void ChromotingJniInstance::OnConnectionReady(bool ready) {
308 // We ignore this message, since OnConnectionState tells us the same thing.
311 void ChromotingJniInstance::OnRouteChanged(
312 const std::string& channel_name,
313 const protocol::TransportRoute& route) {
314 std::string message = "Channel " + channel_name + " using " +
315 protocol::TransportRoute::GetTypeString(route.type) + " connection.";
316 __android_log_print(ANDROID_LOG_INFO, "route", "%s", message.c_str());
319 void ChromotingJniInstance::SetCapabilities(const std::string& capabilities) {
320 jni_runtime_->ui_task_runner()->PostTask(
321 FROM_HERE,
322 base::Bind(&ChromotingJniRuntime::SetCapabilities,
323 base::Unretained(jni_runtime_),
324 capabilities));
327 void ChromotingJniInstance::SetPairingResponse(
328 const protocol::PairingResponse& response) {
330 jni_runtime_->ui_task_runner()->PostTask(
331 FROM_HERE,
332 base::Bind(&ChromotingJniRuntime::CommitPairingCredentials,
333 base::Unretained(jni_runtime_),
334 host_id_, response.client_id(), response.shared_secret()));
337 void ChromotingJniInstance::DeliverHostMessage(
338 const protocol::ExtensionMessage& message) {
339 jni_runtime_->ui_task_runner()->PostTask(
340 FROM_HERE,
341 base::Bind(&ChromotingJniRuntime::HandleExtensionMessage,
342 base::Unretained(jni_runtime_),
343 message.type(),
344 message.data()));
347 protocol::ClipboardStub* ChromotingJniInstance::GetClipboardStub() {
348 return this;
351 protocol::CursorShapeStub* ChromotingJniInstance::GetCursorShapeStub() {
352 return this;
355 void ChromotingJniInstance::InjectClipboardEvent(
356 const protocol::ClipboardEvent& event) {
357 NOTIMPLEMENTED();
360 void ChromotingJniInstance::SetCursorShape(
361 const protocol::CursorShapeInfo& shape) {
362 if (!jni_runtime_->display_task_runner()->BelongsToCurrentThread()) {
363 jni_runtime_->display_task_runner()->PostTask(
364 FROM_HERE,
365 base::Bind(&ChromotingJniInstance::SetCursorShape, this, shape));
366 return;
369 jni_runtime_->UpdateCursorShape(shape);
372 void ChromotingJniInstance::ConnectToHostOnDisplayThread() {
373 DCHECK(jni_runtime_->display_task_runner()->BelongsToCurrentThread());
375 view_.reset(new JniFrameConsumer(jni_runtime_, this));
376 view_weak_factory_.reset(new base::WeakPtrFactory<JniFrameConsumer>(
377 view_.get()));
378 frame_consumer_ = new FrameConsumerProxy(jni_runtime_->display_task_runner(),
379 view_weak_factory_->GetWeakPtr());
381 jni_runtime_->network_task_runner()->PostTask(
382 FROM_HERE,
383 base::Bind(&ChromotingJniInstance::ConnectToHostOnNetworkThread,
384 this));
387 void ChromotingJniInstance::ConnectToHostOnNetworkThread() {
388 DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
390 jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop();
392 client_context_.reset(new ClientContext(
393 jni_runtime_->network_task_runner().get()));
394 client_context_->Start();
396 SoftwareVideoRenderer* renderer =
397 new SoftwareVideoRenderer(client_context_->main_task_runner(),
398 client_context_->decode_task_runner(),
399 frame_consumer_);
400 view_->set_frame_producer(renderer);
401 video_renderer_.reset(renderer);
403 client_.reset(new ChromotingClient(
404 client_context_.get(), this, video_renderer_.get(), nullptr));
406 signaling_.reset(new XmppSignalStrategy(
407 net::ClientSocketFactory::GetDefaultFactory(),
408 jni_runtime_->url_requester(), xmpp_config_));
410 client_status_logger_.reset(
411 new ClientStatusLogger(ServerLogEntry::ME2ME,
412 signaling_.get(),
413 ServiceUrls::GetInstance()->directory_bot_jid()));
415 protocol::NetworkSettings network_settings(
416 protocol::NetworkSettings::NAT_TRAVERSAL_FULL);
418 // Use Chrome's network stack to allocate ports for peer-to-peer channels.
419 scoped_ptr<protocol::ChromiumPortAllocator> port_allocator(
420 protocol::ChromiumPortAllocator::Create(jni_runtime_->url_requester(),
421 network_settings));
423 scoped_ptr<protocol::TransportFactory> transport_factory(
424 new protocol::LibjingleTransportFactory(
425 signaling_.get(), port_allocator.Pass(), network_settings));
427 client_->Start(signaling_.get(), authenticator_.Pass(),
428 transport_factory.Pass(), host_jid_, capabilities_);
431 void ChromotingJniInstance::DisconnectFromHostOnNetworkThread() {
432 DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
434 host_id_.clear();
436 stats_logging_enabled_ = false;
438 // |client_| must be torn down before |signaling_|.
439 client_.reset();
440 client_status_logger_.reset();
441 client_context_.reset();
442 video_renderer_.reset();
443 authenticator_.reset();
444 signaling_.reset();
447 void ChromotingJniInstance::FetchSecret(
448 bool pairable,
449 const protocol::SecretFetchedCallback& callback) {
450 if (!jni_runtime_->ui_task_runner()->BelongsToCurrentThread()) {
451 jni_runtime_->ui_task_runner()->PostTask(
452 FROM_HERE, base::Bind(&ChromotingJniInstance::FetchSecret,
453 this, pairable, callback));
454 return;
457 // Delete pairing credentials if they exist.
458 jni_runtime_->CommitPairingCredentials(host_id_, "", "");
460 pin_callback_ = callback;
461 jni_runtime_->DisplayAuthenticationPrompt(pairable);
464 void ChromotingJniInstance::SetDeviceName(const std::string& device_name) {
465 if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
466 jni_runtime_->network_task_runner()->PostTask(
467 FROM_HERE, base::Bind(&ChromotingJniInstance::SetDeviceName, this,
468 device_name));
469 return;
472 device_name_ = device_name;
475 void ChromotingJniInstance::SendKeyEventInternal(int usb_key_code,
476 bool key_down) {
477 if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
478 jni_runtime_->network_task_runner()->PostTask(
479 FROM_HERE, base::Bind(&ChromotingJniInstance::SendKeyEventInternal,
480 this, usb_key_code, key_down));
481 return;
485 protocol::KeyEvent event;
486 event.set_usb_keycode(usb_key_code);
487 event.set_pressed(key_down);
488 client_->input_stub()->InjectKeyEvent(event);
491 void ChromotingJniInstance::EnableStatsLogging(bool enabled) {
492 DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
494 if (enabled && !stats_logging_enabled_) {
495 jni_runtime_->network_task_runner()->PostDelayedTask(
496 FROM_HERE, base::Bind(&ChromotingJniInstance::LogPerfStats, this),
497 base::TimeDelta::FromMilliseconds(kPerfStatsIntervalMs));
499 stats_logging_enabled_ = enabled;
502 void ChromotingJniInstance::LogPerfStats() {
503 DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
505 if (!stats_logging_enabled_)
506 return;
508 ChromotingStats* stats = video_renderer_->GetStats();
509 __android_log_print(ANDROID_LOG_INFO, "stats",
510 "Bandwidth:%.0f FrameRate:%.1f Capture:%.1f Encode:%.1f "
511 "Decode:%.1f Render:%.1f Latency:%.0f",
512 stats->video_bandwidth()->Rate(),
513 stats->video_frame_rate()->Rate(),
514 stats->video_capture_ms()->Average(),
515 stats->video_encode_ms()->Average(),
516 stats->video_decode_ms()->Average(),
517 stats->video_paint_ms()->Average(),
518 stats->round_trip_ms()->Average());
520 client_status_logger_->LogStatistics(stats);
522 jni_runtime_->network_task_runner()->PostDelayedTask(
523 FROM_HERE, base::Bind(&ChromotingJniInstance::LogPerfStats, this),
524 base::TimeDelta::FromMilliseconds(kPerfStatsIntervalMs));
527 } // namespace remoting