Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / remoting / client / jni / chromoting_jni_instance.cc
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.
4
5 #include "remoting/client/jni/chromoting_jni_instance.h"
6
7 #include <android/log.h>
8
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"
27
28 namespace remoting {
29
30 namespace {
31
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;
36
37 // Interval at which to log performance statistics, if enabled.
38 const int kPerfStatsIntervalMs = 60000;
39
40 }
41
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());
59
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";
67
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));
74
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());
82
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));
87
88   // Post a task to start connection
89   jni_runtime_->display_task_runner()->PostTask(
90       FROM_HERE,
91       base::Bind(&ChromotingJniInstance::ConnectToHostOnDisplayThread,
92                  this));
93 }
94
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_);
106 }
107
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;
114   }
115
116   // This must be destroyed on the display thread before the producer is gone.
117   view_.reset();
118
119   // The weak pointers must be invalidated on the same thread they were used.
120   view_weak_factory_->InvalidateWeakPtrs();
121
122   jni_runtime_->network_task_runner()->PostTask(
123       FROM_HERE,
124       base::Bind(&ChromotingJniInstance::DisconnectFromHostOnNetworkThread,
125                  this));
126 }
127
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());
135
136   __android_log_print(ANDROID_LOG_INFO,
137                       "ThirdPartyAuth",
138                       "Fetching Third Party Token from user.");
139
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));
148 }
149
150 void ChromotingJniInstance::HandleOnThirdPartyTokenFetched(
151     const std::string& token,
152     const std::string& shared_secret) {
153   DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
154
155   __android_log_print(
156       ANDROID_LOG_INFO, "ThirdPartyAuth", "Third Party Token Fetched.");
157
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.");
166   }
167 }
168
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());
174
175   create_pairing_ = create_pairing;
176
177   if (create_pairing)
178     SetDeviceName(device_name);
179
180   jni_runtime_->network_task_runner()->PostTask(FROM_HERE,
181                                                 base::Bind(pin_callback_, pin));
182 }
183
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;
190   }
191
192   jni_runtime_->RedrawCanvas();
193 }
194
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;
204   }
205
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);
212
213   client_->input_stub()->InjectMouseEvent(event);
214 }
215
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;
223   }
224
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);
229 }
230
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;
236   }
237
238   SendKeyEventInternal(usb_key_code, key_down);
239   return true;
240 }
241
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;
248   }
249
250   protocol::TextEvent event;
251   event.set_text(text);
252   client_->input_stub()->InjectTextEvent(event);
253 }
254
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;
263   }
264
265   protocol::ExtensionMessage extension_message;
266   extension_message.set_type(type);
267   extension_message.set_data(data);
268   client_->host_stub()->DeliverClientMessage(extension_message);
269 }
270
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;
277   }
278
279   if (stats_logging_enabled_)
280     video_renderer_->GetStats()->video_paint_ms()->Record(paint_time_ms);
281 }
282
283 void ChromotingJniInstance::OnConnectionState(
284     protocol::ConnectionToHost::State state,
285     protocol::ErrorCode error) {
286   DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
287
288   EnableStatsLogging(state == protocol::ConnectionToHost::CONNECTED);
289
290   client_status_logger_->LogSessionStateChange(state, error);
291
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);
297   }
298
299   jni_runtime_->ui_task_runner()->PostTask(
300       FROM_HERE,
301       base::Bind(&ChromotingJniRuntime::OnConnectionState,
302                  base::Unretained(jni_runtime_),
303                  state,
304                  error));
305 }
306
307 void ChromotingJniInstance::OnConnectionReady(bool ready) {
308   // We ignore this message, since OnConnectionState tells us the same thing.
309 }
310
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());
317 }
318
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));
325 }
326
327 void ChromotingJniInstance::SetPairingResponse(
328     const protocol::PairingResponse& response) {
329
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()));
335 }
336
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()));
345 }
346
347 protocol::ClipboardStub* ChromotingJniInstance::GetClipboardStub() {
348   return this;
349 }
350
351 protocol::CursorShapeStub* ChromotingJniInstance::GetCursorShapeStub() {
352   return this;
353 }
354
355 void ChromotingJniInstance::InjectClipboardEvent(
356     const protocol::ClipboardEvent& event) {
357   NOTIMPLEMENTED();
358 }
359
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;
367   }
368
369   jni_runtime_->UpdateCursorShape(shape);
370 }
371
372 void ChromotingJniInstance::ConnectToHostOnDisplayThread() {
373   DCHECK(jni_runtime_->display_task_runner()->BelongsToCurrentThread());
374
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());
380
381   jni_runtime_->network_task_runner()->PostTask(
382       FROM_HERE,
383       base::Bind(&ChromotingJniInstance::ConnectToHostOnNetworkThread,
384                  this));
385 }
386
387 void ChromotingJniInstance::ConnectToHostOnNetworkThread() {
388   DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
389
390   jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop();
391
392   client_context_.reset(new ClientContext(
393       jni_runtime_->network_task_runner().get()));
394   client_context_->Start();
395
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);
402
403   client_.reset(new ChromotingClient(client_context_.get(),
404                                      this,
405                                      video_renderer_.get(),
406                                      scoped_ptr<AudioPlayer>()));
407
408   signaling_.reset(new XmppSignalStrategy(
409       net::ClientSocketFactory::GetDefaultFactory(),
410       jni_runtime_->url_requester(), xmpp_config_));
411
412   client_status_logger_.reset(
413       new ClientStatusLogger(ServerLogEntry::ME2ME,
414                              signaling_.get(),
415                              ServiceUrls::GetInstance()->directory_bot_jid()));
416
417   protocol::NetworkSettings network_settings(
418       protocol::NetworkSettings::NAT_TRAVERSAL_FULL);
419
420   // Use Chrome's network stack to allocate ports for peer-to-peer channels.
421   scoped_ptr<protocol::ChromiumPortAllocator> port_allocator(
422       protocol::ChromiumPortAllocator::Create(jni_runtime_->url_requester(),
423                                               network_settings));
424
425   scoped_ptr<protocol::TransportFactory> transport_factory(
426       new protocol::LibjingleTransportFactory(
427           signaling_.get(),
428           port_allocator.PassAs<cricket::HttpPortAllocatorBase>(),
429           network_settings));
430
431   client_->Start(signaling_.get(), authenticator_.Pass(),
432                  transport_factory.Pass(), host_jid_, capabilities_);
433 }
434
435 void ChromotingJniInstance::DisconnectFromHostOnNetworkThread() {
436   DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
437
438   host_id_.clear();
439
440   stats_logging_enabled_ = false;
441
442   // |client_| must be torn down before |signaling_|.
443   client_.reset();
444   client_status_logger_.reset();
445   client_context_.reset();
446   video_renderer_.reset();
447   authenticator_.reset();
448   signaling_.reset();
449 }
450
451 void ChromotingJniInstance::FetchSecret(
452     bool pairable,
453     const protocol::SecretFetchedCallback& callback) {
454   if (!jni_runtime_->ui_task_runner()->BelongsToCurrentThread()) {
455     jni_runtime_->ui_task_runner()->PostTask(
456         FROM_HERE, base::Bind(&ChromotingJniInstance::FetchSecret,
457                               this, pairable, callback));
458     return;
459   }
460
461   // Delete pairing credentials if they exist.
462   jni_runtime_->CommitPairingCredentials(host_id_, "", "");
463
464   pin_callback_ = callback;
465   jni_runtime_->DisplayAuthenticationPrompt(pairable);
466 }
467
468 void ChromotingJniInstance::SetDeviceName(const std::string& device_name) {
469   if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
470     jni_runtime_->network_task_runner()->PostTask(
471         FROM_HERE, base::Bind(&ChromotingJniInstance::SetDeviceName, this,
472                               device_name));
473     return;
474   }
475
476   device_name_ = device_name;
477 }
478
479 void ChromotingJniInstance::SendKeyEventInternal(int usb_key_code,
480                                                  bool key_down) {
481   if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
482     jni_runtime_->network_task_runner()->PostTask(
483         FROM_HERE, base::Bind(&ChromotingJniInstance::SendKeyEventInternal,
484                               this, usb_key_code, key_down));
485     return;
486   }
487
488
489   protocol::KeyEvent event;
490   event.set_usb_keycode(usb_key_code);
491   event.set_pressed(key_down);
492   client_->input_stub()->InjectKeyEvent(event);
493 }
494
495 void ChromotingJniInstance::EnableStatsLogging(bool enabled) {
496   DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
497
498   if (enabled && !stats_logging_enabled_) {
499     jni_runtime_->network_task_runner()->PostDelayedTask(
500         FROM_HERE, base::Bind(&ChromotingJniInstance::LogPerfStats, this),
501         base::TimeDelta::FromMilliseconds(kPerfStatsIntervalMs));
502   }
503   stats_logging_enabled_ = enabled;
504 }
505
506 void ChromotingJniInstance::LogPerfStats() {
507   DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
508
509   if (!stats_logging_enabled_)
510     return;
511
512   ChromotingStats* stats = video_renderer_->GetStats();
513   __android_log_print(ANDROID_LOG_INFO, "stats",
514                       "Bandwidth:%.0f FrameRate:%.1f Capture:%.1f Encode:%.1f "
515                       "Decode:%.1f Render:%.1f Latency:%.0f",
516                       stats->video_bandwidth()->Rate(),
517                       stats->video_frame_rate()->Rate(),
518                       stats->video_capture_ms()->Average(),
519                       stats->video_encode_ms()->Average(),
520                       stats->video_decode_ms()->Average(),
521                       stats->video_paint_ms()->Average(),
522                       stats->round_trip_ms()->Average());
523
524   client_status_logger_->LogStatistics(stats);
525
526   jni_runtime_->network_task_runner()->PostDelayedTask(
527       FROM_HERE, base::Bind(&ChromotingJniInstance::LogPerfStats, this),
528       base::TimeDelta::FromMilliseconds(kPerfStatsIntervalMs));
529 }
530
531 }  // namespace remoting