Home | History | Annotate | Download | only in jni
      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 "base/bind.h"
      8 #include "base/logging.h"
      9 #include "remoting/client/audio_player.h"
     10 #include "remoting/client/jni/android_keymap.h"
     11 #include "remoting/client/jni/chromoting_jni_runtime.h"
     12 #include "remoting/protocol/host_stub.h"
     13 #include "remoting/protocol/libjingle_transport_factory.h"
     14 
     15 // TODO(solb) Move into location shared with client plugin.
     16 const char* const kXmppServer = "talk.google.com";
     17 const int kXmppPort = 5222;
     18 const bool kXmppUseTls = true;
     19 
     20 namespace remoting {
     21 
     22 ChromotingJniInstance::ChromotingJniInstance(ChromotingJniRuntime* jni_runtime,
     23                                              const char* username,
     24                                              const char* auth_token,
     25                                              const char* host_jid,
     26                                              const char* host_id,
     27                                              const char* host_pubkey,
     28                                              const char* pairing_id,
     29                                              const char* pairing_secret)
     30     : jni_runtime_(jni_runtime),
     31       username_(username),
     32       auth_token_(auth_token),
     33       host_jid_(host_jid),
     34       host_id_(host_id),
     35       host_pubkey_(host_pubkey),
     36       pairing_id_(pairing_id),
     37       pairing_secret_(pairing_secret),
     38       create_pairing_(false) {
     39   DCHECK(jni_runtime_->ui_task_runner()->BelongsToCurrentThread());
     40 
     41   jni_runtime_->display_task_runner()->PostTask(
     42       FROM_HERE,
     43       base::Bind(&ChromotingJniInstance::ConnectToHostOnDisplayThread,
     44                  this));
     45 }
     46 
     47 ChromotingJniInstance::~ChromotingJniInstance() {}
     48 
     49 void ChromotingJniInstance::Cleanup() {
     50   if (!jni_runtime_->display_task_runner()->BelongsToCurrentThread()) {
     51     jni_runtime_->display_task_runner()->PostTask(
     52         FROM_HERE,
     53         base::Bind(&ChromotingJniInstance::Cleanup, this));
     54     return;
     55   }
     56 
     57   // This must be destroyed on the display thread before the producer is gone.
     58   view_.reset();
     59 
     60   // The weak pointers must be invalidated on the same thread they were used.
     61   view_weak_factory_->InvalidateWeakPtrs();
     62 
     63   jni_runtime_->network_task_runner()->PostTask(
     64       FROM_HERE,
     65       base::Bind(&ChromotingJniInstance::DisconnectFromHostOnNetworkThread,
     66                  this));
     67 }
     68 
     69 void ChromotingJniInstance::ProvideSecret(const std::string& pin,
     70                                           bool create_pairing) {
     71   DCHECK(jni_runtime_->ui_task_runner()->BelongsToCurrentThread());
     72   DCHECK(!pin_callback_.is_null());
     73 
     74   create_pairing_ = create_pairing;
     75 
     76   jni_runtime_->network_task_runner()->PostTask(FROM_HERE,
     77                                                 base::Bind(pin_callback_, pin));
     78 }
     79 
     80 void ChromotingJniInstance::RedrawDesktop() {
     81   if (!jni_runtime_->display_task_runner()->BelongsToCurrentThread()) {
     82     jni_runtime_->display_task_runner()->PostTask(
     83         FROM_HERE,
     84         base::Bind(&ChromotingJniInstance::RedrawDesktop, this));
     85     return;
     86   }
     87 
     88   jni_runtime_->RedrawCanvas();
     89 }
     90 
     91 void ChromotingJniInstance::PerformMouseAction(
     92     int x,
     93     int y,
     94     protocol::MouseEvent_MouseButton button,
     95     bool button_down) {
     96   if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
     97     jni_runtime_->network_task_runner()->PostTask(
     98         FROM_HERE,
     99         base::Bind(&ChromotingJniInstance::PerformMouseAction,
    100                    this,
    101                    x,
    102                    y,
    103                    button,
    104                    button_down));
    105     return;
    106   }
    107 
    108   protocol::MouseEvent action;
    109   action.set_x(x);
    110   action.set_y(y);
    111   action.set_button(button);
    112   if (button != protocol::MouseEvent::BUTTON_UNDEFINED)
    113     action.set_button_down(button_down);
    114 
    115   connection_->input_stub()->InjectMouseEvent(action);
    116 }
    117 
    118 void ChromotingJniInstance::PerformKeyboardAction(int key_code, bool key_down) {
    119   if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
    120     jni_runtime_->network_task_runner()->PostTask(
    121         FROM_HERE,
    122         base::Bind(&ChromotingJniInstance::PerformKeyboardAction,
    123                    this,
    124                    key_code,
    125                    key_down));
    126     return;
    127   }
    128 
    129   uint32 usb_code = AndroidKeycodeToUsbKeycode(key_code);
    130   if (usb_code) {
    131     protocol::KeyEvent action;
    132     action.set_usb_keycode(usb_code);
    133     action.set_pressed(key_down);
    134     connection_->input_stub()->InjectKeyEvent(action);
    135   } else {
    136     LOG(WARNING) << "Ignoring unknown keycode: " << key_code;
    137   }
    138 }
    139 
    140 void ChromotingJniInstance::OnConnectionState(
    141     protocol::ConnectionToHost::State state,
    142     protocol::ErrorCode error) {
    143   DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
    144 
    145   if (create_pairing_ && state == protocol::ConnectionToHost::CONNECTED) {
    146     LOG(INFO) << "Attempting to pair with host";
    147     protocol::PairingRequest request;
    148     request.set_client_name("Android");
    149     connection_->host_stub()->RequestPairing(request);
    150   }
    151 
    152   jni_runtime_->ui_task_runner()->PostTask(
    153       FROM_HERE,
    154       base::Bind(&ChromotingJniRuntime::ReportConnectionStatus,
    155                  base::Unretained(jni_runtime_),
    156                  state,
    157                  error));
    158 }
    159 
    160 void ChromotingJniInstance::OnConnectionReady(bool ready) {
    161   // We ignore this message, since OnConnectoinState tells us the same thing.
    162 }
    163 
    164 void ChromotingJniInstance::SetCapabilities(const std::string& capabilities) {}
    165 
    166 void ChromotingJniInstance::SetPairingResponse(
    167     const protocol::PairingResponse& response) {
    168   LOG(INFO) << "Successfully established pairing with host";
    169 
    170   jni_runtime_->ui_task_runner()->PostTask(
    171       FROM_HERE,
    172       base::Bind(&ChromotingJniRuntime::CommitPairingCredentials,
    173                  base::Unretained(jni_runtime_),
    174                  host_id_,
    175                  response.client_id(),
    176                  response.shared_secret()));
    177 }
    178 
    179 void ChromotingJniInstance::DeliverHostMessage(
    180     const protocol::ExtensionMessage& message) {
    181   NOTIMPLEMENTED();
    182 }
    183 
    184 protocol::ClipboardStub* ChromotingJniInstance::GetClipboardStub() {
    185   return this;
    186 }
    187 
    188 protocol::CursorShapeStub* ChromotingJniInstance::GetCursorShapeStub() {
    189   return this;
    190 }
    191 
    192 scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>
    193     ChromotingJniInstance::GetTokenFetcher(const std::string& host_public_key) {
    194   // Return null to indicate that third-party authentication is unsupported.
    195   return scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>();
    196 }
    197 
    198 void ChromotingJniInstance::InjectClipboardEvent(
    199     const protocol::ClipboardEvent& event) {
    200   NOTIMPLEMENTED();
    201 }
    202 
    203 void ChromotingJniInstance::SetCursorShape(
    204     const protocol::CursorShapeInfo& shape) {
    205   NOTIMPLEMENTED();
    206 }
    207 
    208 void ChromotingJniInstance::ConnectToHostOnDisplayThread() {
    209   DCHECK(jni_runtime_->display_task_runner()->BelongsToCurrentThread());
    210 
    211   frame_consumer_ = new FrameConsumerProxy(jni_runtime_->display_task_runner());
    212   view_.reset(new JniFrameConsumer(jni_runtime_));
    213   view_weak_factory_.reset(new base::WeakPtrFactory<JniFrameConsumer>(
    214       view_.get()));
    215   frame_consumer_->Attach(view_weak_factory_->GetWeakPtr());
    216 
    217   jni_runtime_->network_task_runner()->PostTask(
    218       FROM_HERE,
    219       base::Bind(&ChromotingJniInstance::ConnectToHostOnNetworkThread,
    220                  this));
    221 }
    222 
    223 void ChromotingJniInstance::ConnectToHostOnNetworkThread() {
    224   DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
    225 
    226   client_config_.reset(new ClientConfig());
    227   client_config_->host_jid = host_jid_;
    228   client_config_->host_public_key = host_pubkey_;
    229 
    230   client_config_->fetch_secret_callback = base::Bind(
    231       &ChromotingJniInstance::FetchSecret,
    232       this);
    233   client_config_->authentication_tag = host_id_;
    234 
    235   if (!pairing_id_.empty() && !pairing_secret_.empty()) {
    236     client_config_->client_pairing_id = pairing_id_;
    237     client_config_->client_paired_secret = pairing_secret_;
    238     client_config_->authentication_methods.push_back(
    239         protocol::AuthenticationMethod::FromString("spake2_pair"));
    240   }
    241 
    242   client_config_->authentication_methods.push_back(
    243       protocol::AuthenticationMethod::FromString("spake2_hmac"));
    244   client_config_->authentication_methods.push_back(
    245       protocol::AuthenticationMethod::FromString("spake2_plain"));
    246 
    247   client_context_.reset(new ClientContext(
    248       jni_runtime_->network_task_runner().get()));
    249   client_context_->Start();
    250 
    251   connection_.reset(new protocol::ConnectionToHost(true));
    252 
    253   client_.reset(new ChromotingClient(*client_config_,
    254                                      client_context_.get(),
    255                                      connection_.get(),
    256                                      this,
    257                                      frame_consumer_,
    258                                      scoped_ptr<AudioPlayer>()));
    259 
    260   view_->set_frame_producer(client_->GetFrameProducer());
    261 
    262   signaling_config_.reset(new XmppSignalStrategy::XmppServerConfig());
    263   signaling_config_->host = kXmppServer;
    264   signaling_config_->port = kXmppPort;
    265   signaling_config_->use_tls = kXmppUseTls;
    266 
    267   signaling_.reset(new XmppSignalStrategy(jni_runtime_->url_requester(),
    268                                           username_,
    269                                           auth_token_,
    270                                           "oauth2",
    271                                           *signaling_config_));
    272 
    273   network_settings_.reset(new NetworkSettings(
    274       NetworkSettings::NAT_TRAVERSAL_ENABLED));
    275   scoped_ptr<protocol::TransportFactory> fact(
    276       protocol::LibjingleTransportFactory::Create(
    277           *network_settings_,
    278           jni_runtime_->url_requester()));
    279 
    280   client_->Start(signaling_.get(), fact.Pass());
    281 }
    282 
    283 void ChromotingJniInstance::DisconnectFromHostOnNetworkThread() {
    284   DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
    285 
    286   username_ = "";
    287   auth_token_ = "";
    288   host_jid_ = "";
    289   host_id_ = "";
    290   host_pubkey_ = "";
    291 
    292   // |client_| must be torn down before |signaling_|.
    293   connection_.reset();
    294   client_.reset();
    295 }
    296 
    297 void ChromotingJniInstance::FetchSecret(
    298     bool pairable,
    299     const protocol::SecretFetchedCallback& callback) {
    300   if (!jni_runtime_->ui_task_runner()->BelongsToCurrentThread()) {
    301     jni_runtime_->ui_task_runner()->PostTask(
    302         FROM_HERE,
    303         base::Bind(&ChromotingJniInstance::FetchSecret,
    304                    this,
    305                    pairable,
    306                    callback));
    307     return;
    308   }
    309 
    310   if (!pairing_id_.empty() || !pairing_secret_.empty()) {
    311     // We attempted to connect using an existing pairing that was rejected.
    312     // Unless we forget about the stale credentials, we'll continue trying them.
    313     LOG(INFO) << "Deleting rejected pairing credentials";
    314     jni_runtime_->CommitPairingCredentials(host_id_, "", "");
    315   }
    316 
    317   pin_callback_ = callback;
    318   jni_runtime_->DisplayAuthenticationPrompt();
    319 }
    320 
    321 }  // namespace remoting
    322