Synchronize Android relocation packer source with AOSP.
[chromium-blink-merge.git] / remoting / client / jni / chromoting_jni_instance.cc
blobfd19deaaffea633450de5fa3468facf96cf809fb
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;
67 // Initialize |authenticator_|.
68 scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>
69 token_fetcher(new TokenFetcherProxy(
70 base::Bind(&ChromotingJniInstance::FetchThirdPartyToken,
71 weak_factory_.GetWeakPtr()),
72 host_pubkey));
74 std::vector<protocol::AuthenticationMethod> auth_methods;
75 auth_methods.push_back(protocol::AuthenticationMethod::Spake2Pair());
76 auth_methods.push_back(protocol::AuthenticationMethod::Spake2(
77 protocol::AuthenticationMethod::HMAC_SHA256));
78 auth_methods.push_back(protocol::AuthenticationMethod::Spake2(
79 protocol::AuthenticationMethod::NONE));
80 auth_methods.push_back(protocol::AuthenticationMethod::ThirdParty());
82 authenticator_.reset(new protocol::NegotiatingClientAuthenticator(
83 pairing_id, pairing_secret, host_id_,
84 base::Bind(&ChromotingJniInstance::FetchSecret, this),
85 token_fetcher.Pass(), auth_methods));
87 // Post a task to start connection
88 jni_runtime_->display_task_runner()->PostTask(
89 FROM_HERE,
90 base::Bind(&ChromotingJniInstance::ConnectToHostOnDisplayThread,
91 this));
94 ChromotingJniInstance::~ChromotingJniInstance() {
95 // This object is ref-counted, so this dtor can execute on any thread.
96 // Ensure that all these objects have been freed already, so they are not
97 // destroyed on some random thread.
98 DCHECK(!view_);
99 DCHECK(!client_context_);
100 DCHECK(!video_renderer_);
101 DCHECK(!authenticator_);
102 DCHECK(!client_);
103 DCHECK(!signaling_);
104 DCHECK(!client_status_logger_);
107 void ChromotingJniInstance::Disconnect() {
108 if (!jni_runtime_->display_task_runner()->BelongsToCurrentThread()) {
109 jni_runtime_->display_task_runner()->PostTask(
110 FROM_HERE,
111 base::Bind(&ChromotingJniInstance::Disconnect, this));
112 return;
115 // This must be destroyed on the display thread before the producer is gone.
116 view_.reset();
118 // The weak pointers must be invalidated on the same thread they were used.
119 view_weak_factory_->InvalidateWeakPtrs();
121 jni_runtime_->network_task_runner()->PostTask(
122 FROM_HERE,
123 base::Bind(&ChromotingJniInstance::DisconnectFromHostOnNetworkThread,
124 this));
127 void ChromotingJniInstance::FetchThirdPartyToken(
128 const GURL& token_url,
129 const std::string& client_id,
130 const std::string& scope,
131 base::WeakPtr<TokenFetcherProxy> token_fetcher_proxy) {
132 DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
133 DCHECK(!token_fetcher_proxy_.get());
135 __android_log_print(ANDROID_LOG_INFO,
136 "ThirdPartyAuth",
137 "Fetching Third Party Token from user.");
139 token_fetcher_proxy_ = token_fetcher_proxy;
140 jni_runtime_->ui_task_runner()->PostTask(
141 FROM_HERE,
142 base::Bind(&ChromotingJniRuntime::FetchThirdPartyToken,
143 base::Unretained(jni_runtime_),
144 token_url,
145 client_id,
146 scope));
149 void ChromotingJniInstance::HandleOnThirdPartyTokenFetched(
150 const std::string& token,
151 const std::string& shared_secret) {
152 DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
154 __android_log_print(
155 ANDROID_LOG_INFO, "ThirdPartyAuth", "Third Party Token Fetched.");
157 if (token_fetcher_proxy_.get()) {
158 token_fetcher_proxy_->OnTokenFetched(token, shared_secret);
159 token_fetcher_proxy_.reset();
160 } else {
161 __android_log_print(
162 ANDROID_LOG_WARN,
163 "ThirdPartyAuth",
164 "Ignored OnThirdPartyTokenFetched() without a pending fetch.");
168 void ChromotingJniInstance::ProvideSecret(const std::string& pin,
169 bool create_pairing,
170 const std::string& device_name) {
171 DCHECK(jni_runtime_->ui_task_runner()->BelongsToCurrentThread());
172 DCHECK(!pin_callback_.is_null());
174 create_pairing_ = create_pairing;
176 if (create_pairing)
177 SetDeviceName(device_name);
179 jni_runtime_->network_task_runner()->PostTask(FROM_HERE,
180 base::Bind(pin_callback_, pin));
183 void ChromotingJniInstance::RedrawDesktop() {
184 if (!jni_runtime_->display_task_runner()->BelongsToCurrentThread()) {
185 jni_runtime_->display_task_runner()->PostTask(
186 FROM_HERE,
187 base::Bind(&ChromotingJniInstance::RedrawDesktop, this));
188 return;
191 jni_runtime_->RedrawCanvas();
194 void ChromotingJniInstance::SendMouseEvent(
195 int x, int y,
196 protocol::MouseEvent_MouseButton button,
197 bool button_down) {
198 if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
199 jni_runtime_->network_task_runner()->PostTask(
200 FROM_HERE, base::Bind(&ChromotingJniInstance::SendMouseEvent,
201 this, x, y, button, button_down));
202 return;
205 protocol::MouseEvent event;
206 event.set_x(x);
207 event.set_y(y);
208 event.set_button(button);
209 if (button != protocol::MouseEvent::BUTTON_UNDEFINED)
210 event.set_button_down(button_down);
212 client_->input_stub()->InjectMouseEvent(event);
215 void ChromotingJniInstance::SendMouseWheelEvent(int delta_x, int delta_y) {
216 if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
217 jni_runtime_->network_task_runner()->PostTask(
218 FROM_HERE,
219 base::Bind(&ChromotingJniInstance::SendMouseWheelEvent, this,
220 delta_x, delta_y));
221 return;
224 protocol::MouseEvent event;
225 event.set_wheel_delta_x(delta_x);
226 event.set_wheel_delta_y(delta_y);
227 client_->input_stub()->InjectMouseEvent(event);
230 bool ChromotingJniInstance::SendKeyEvent(int key_code, bool key_down) {
231 uint32 usb_key_code = AndroidKeycodeToUsbKeycode(key_code);
232 if (!usb_key_code) {
233 LOG(WARNING) << "Ignoring unknown keycode: " << key_code;
234 return false;
237 SendKeyEventInternal(usb_key_code, key_down);
238 return true;
241 void ChromotingJniInstance::SendTextEvent(const std::string& text) {
242 if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
243 jni_runtime_->network_task_runner()->PostTask(
244 FROM_HERE,
245 base::Bind(&ChromotingJniInstance::SendTextEvent, this, text));
246 return;
249 protocol::TextEvent event;
250 event.set_text(text);
251 client_->input_stub()->InjectTextEvent(event);
254 void ChromotingJniInstance::EnableVideoChannel(bool enable) {
255 if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
256 jni_runtime_->network_task_runner()->PostTask(
257 FROM_HERE,
258 base::Bind(&ChromotingJniInstance::EnableVideoChannel, this, enable));
259 return;
262 protocol::VideoControl video_control;
263 video_control.set_enable(enable);
264 client_->host_stub()->ControlVideo(video_control);
267 void ChromotingJniInstance::SendClientMessage(const std::string& type,
268 const std::string& data) {
269 if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
270 jni_runtime_->network_task_runner()->PostTask(
271 FROM_HERE,
272 base::Bind(
273 &ChromotingJniInstance::SendClientMessage, this, type, data));
274 return;
277 protocol::ExtensionMessage extension_message;
278 extension_message.set_type(type);
279 extension_message.set_data(data);
280 client_->host_stub()->DeliverClientMessage(extension_message);
283 void ChromotingJniInstance::RecordPaintTime(int64 paint_time_ms) {
284 if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
285 jni_runtime_->network_task_runner()->PostTask(
286 FROM_HERE, base::Bind(&ChromotingJniInstance::RecordPaintTime, this,
287 paint_time_ms));
288 return;
291 if (stats_logging_enabled_)
292 video_renderer_->GetStats()->video_paint_ms()->Record(paint_time_ms);
295 void ChromotingJniInstance::OnConnectionState(
296 protocol::ConnectionToHost::State state,
297 protocol::ErrorCode error) {
298 DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
300 EnableStatsLogging(state == protocol::ConnectionToHost::CONNECTED);
302 client_status_logger_->LogSessionStateChange(state, error);
304 if (create_pairing_ && state == protocol::ConnectionToHost::CONNECTED) {
305 protocol::PairingRequest request;
306 DCHECK(!device_name_.empty());
307 request.set_client_name(device_name_);
308 client_->host_stub()->RequestPairing(request);
311 jni_runtime_->ui_task_runner()->PostTask(
312 FROM_HERE,
313 base::Bind(&ChromotingJniRuntime::OnConnectionState,
314 base::Unretained(jni_runtime_),
315 state,
316 error));
319 void ChromotingJniInstance::OnConnectionReady(bool ready) {
320 // We ignore this message, since OnConnectionState tells us the same thing.
323 void ChromotingJniInstance::OnRouteChanged(
324 const std::string& channel_name,
325 const protocol::TransportRoute& route) {
326 std::string message = "Channel " + channel_name + " using " +
327 protocol::TransportRoute::GetTypeString(route.type) + " connection.";
328 __android_log_print(ANDROID_LOG_INFO, "route", "%s", message.c_str());
331 void ChromotingJniInstance::SetCapabilities(const std::string& capabilities) {
332 jni_runtime_->ui_task_runner()->PostTask(
333 FROM_HERE,
334 base::Bind(&ChromotingJniRuntime::SetCapabilities,
335 base::Unretained(jni_runtime_),
336 capabilities));
339 void ChromotingJniInstance::SetPairingResponse(
340 const protocol::PairingResponse& response) {
342 jni_runtime_->ui_task_runner()->PostTask(
343 FROM_HERE,
344 base::Bind(&ChromotingJniRuntime::CommitPairingCredentials,
345 base::Unretained(jni_runtime_),
346 host_id_, response.client_id(), response.shared_secret()));
349 void ChromotingJniInstance::DeliverHostMessage(
350 const protocol::ExtensionMessage& message) {
351 jni_runtime_->ui_task_runner()->PostTask(
352 FROM_HERE,
353 base::Bind(&ChromotingJniRuntime::HandleExtensionMessage,
354 base::Unretained(jni_runtime_),
355 message.type(),
356 message.data()));
359 protocol::ClipboardStub* ChromotingJniInstance::GetClipboardStub() {
360 return this;
363 protocol::CursorShapeStub* ChromotingJniInstance::GetCursorShapeStub() {
364 return this;
367 void ChromotingJniInstance::InjectClipboardEvent(
368 const protocol::ClipboardEvent& event) {
369 NOTIMPLEMENTED();
372 void ChromotingJniInstance::SetCursorShape(
373 const protocol::CursorShapeInfo& shape) {
374 if (!jni_runtime_->display_task_runner()->BelongsToCurrentThread()) {
375 jni_runtime_->display_task_runner()->PostTask(
376 FROM_HERE,
377 base::Bind(&ChromotingJniInstance::SetCursorShape, this, shape));
378 return;
381 jni_runtime_->UpdateCursorShape(shape);
384 void ChromotingJniInstance::ConnectToHostOnDisplayThread() {
385 DCHECK(jni_runtime_->display_task_runner()->BelongsToCurrentThread());
387 view_.reset(new JniFrameConsumer(jni_runtime_, this));
388 view_weak_factory_.reset(new base::WeakPtrFactory<JniFrameConsumer>(
389 view_.get()));
390 frame_consumer_ = new FrameConsumerProxy(jni_runtime_->display_task_runner(),
391 view_weak_factory_->GetWeakPtr());
393 jni_runtime_->network_task_runner()->PostTask(
394 FROM_HERE,
395 base::Bind(&ChromotingJniInstance::ConnectToHostOnNetworkThread,
396 this));
399 void ChromotingJniInstance::ConnectToHostOnNetworkThread() {
400 DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
402 jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop();
404 client_context_.reset(new ClientContext(
405 jni_runtime_->network_task_runner().get()));
406 client_context_->Start();
408 SoftwareVideoRenderer* renderer =
409 new SoftwareVideoRenderer(client_context_->main_task_runner(),
410 client_context_->decode_task_runner(),
411 frame_consumer_);
412 view_->set_frame_producer(renderer);
413 video_renderer_.reset(renderer);
415 client_.reset(new ChromotingClient(
416 client_context_.get(), this, video_renderer_.get(), nullptr));
418 signaling_.reset(new XmppSignalStrategy(
419 net::ClientSocketFactory::GetDefaultFactory(),
420 jni_runtime_->url_requester(), xmpp_config_));
422 client_status_logger_.reset(
423 new ClientStatusLogger(ServerLogEntry::ME2ME,
424 signaling_.get(),
425 ServiceUrls::GetInstance()->directory_bot_jid()));
427 protocol::NetworkSettings network_settings(
428 protocol::NetworkSettings::NAT_TRAVERSAL_FULL);
430 // Use Chrome's network stack to allocate ports for peer-to-peer channels.
431 scoped_ptr<protocol::ChromiumPortAllocator> port_allocator(
432 protocol::ChromiumPortAllocator::Create(jni_runtime_->url_requester(),
433 network_settings));
435 scoped_ptr<protocol::TransportFactory> transport_factory(
436 new protocol::LibjingleTransportFactory(
437 signaling_.get(), port_allocator.Pass(), network_settings,
438 protocol::TransportRole::CLIENT));
440 client_->Start(signaling_.get(), authenticator_.Pass(),
441 transport_factory.Pass(), host_jid_, capabilities_);
444 void ChromotingJniInstance::DisconnectFromHostOnNetworkThread() {
445 DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
447 host_id_.clear();
449 stats_logging_enabled_ = false;
451 // |client_| must be torn down before |signaling_|.
452 client_.reset();
453 client_status_logger_.reset();
454 video_renderer_.reset();
455 authenticator_.reset();
456 signaling_.reset();
457 client_context_.reset();
460 void ChromotingJniInstance::FetchSecret(
461 bool pairable,
462 const protocol::SecretFetchedCallback& callback) {
463 if (!jni_runtime_->ui_task_runner()->BelongsToCurrentThread()) {
464 jni_runtime_->ui_task_runner()->PostTask(
465 FROM_HERE, base::Bind(&ChromotingJniInstance::FetchSecret,
466 this, pairable, callback));
467 return;
470 // Delete pairing credentials if they exist.
471 jni_runtime_->CommitPairingCredentials(host_id_, "", "");
473 pin_callback_ = callback;
474 jni_runtime_->DisplayAuthenticationPrompt(pairable);
477 void ChromotingJniInstance::SetDeviceName(const std::string& device_name) {
478 if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
479 jni_runtime_->network_task_runner()->PostTask(
480 FROM_HERE, base::Bind(&ChromotingJniInstance::SetDeviceName, this,
481 device_name));
482 return;
485 device_name_ = device_name;
488 void ChromotingJniInstance::SendKeyEventInternal(int usb_key_code,
489 bool key_down) {
490 if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
491 jni_runtime_->network_task_runner()->PostTask(
492 FROM_HERE, base::Bind(&ChromotingJniInstance::SendKeyEventInternal,
493 this, usb_key_code, key_down));
494 return;
498 protocol::KeyEvent event;
499 event.set_usb_keycode(usb_key_code);
500 event.set_pressed(key_down);
501 client_->input_stub()->InjectKeyEvent(event);
504 void ChromotingJniInstance::EnableStatsLogging(bool enabled) {
505 DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
507 if (enabled && !stats_logging_enabled_) {
508 jni_runtime_->network_task_runner()->PostDelayedTask(
509 FROM_HERE, base::Bind(&ChromotingJniInstance::LogPerfStats, this),
510 base::TimeDelta::FromMilliseconds(kPerfStatsIntervalMs));
512 stats_logging_enabled_ = enabled;
515 void ChromotingJniInstance::LogPerfStats() {
516 DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
518 if (!stats_logging_enabled_)
519 return;
521 ChromotingStats* stats = video_renderer_->GetStats();
522 __android_log_print(ANDROID_LOG_INFO, "stats",
523 "Bandwidth:%.0f FrameRate:%.1f Capture:%.1f Encode:%.1f "
524 "Decode:%.1f Render:%.1f Latency:%.0f",
525 stats->video_bandwidth()->Rate(),
526 stats->video_frame_rate()->Rate(),
527 stats->video_capture_ms()->Average(),
528 stats->video_encode_ms()->Average(),
529 stats->video_decode_ms()->Average(),
530 stats->video_paint_ms()->Average(),
531 stats->round_trip_ms()->Average());
533 client_status_logger_->LogStatistics(stats);
535 jni_runtime_->network_task_runner()->PostDelayedTask(
536 FROM_HERE, base::Bind(&ChromotingJniInstance::LogPerfStats, this),
537 base::TimeDelta::FromMilliseconds(kPerfStatsIntervalMs));
540 } // namespace remoting