diff options
author | solb@chromium.org <solb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-17 05:57:45 +0000 |
---|---|---|
committer | solb@chromium.org <solb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-17 05:57:45 +0000 |
commit | d5d631fa8b506f6a7c00dbaad387b7d0d6d83a4d (patch) | |
tree | 55273e25bd222dcc9e938deaae9749091e1f8a94 /remoting | |
parent | 8eb4090f60a9a26882e3b2b44c17a76a142d4149 (diff) | |
download | chromium_src-d5d631fa8b506f6a7c00dbaad387b7d0d6d83a4d.zip chromium_src-d5d631fa8b506f6a7c00dbaad387b7d0d6d83a4d.tar.gz chromium_src-d5d631fa8b506f6a7c00dbaad387b7d0d6d83a4d.tar.bz2 |
Separate singleton out of ChromotingJNIInstance
Platform prerequisite and intersession components of this class have been culled into the new ChromotingJNI singleton, which holds an instance of ChromotingJNIInstance during each connection. This paves the way for future concurrent sessions support.
Review URL: https://chromiumcodereview.appspot.com/19253003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@211965 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting')
-rw-r--r-- | remoting/client/jni/chromoting_jni.cc | 117 | ||||
-rw-r--r-- | remoting/client/jni/chromoting_jni.h | 110 | ||||
-rw-r--r-- | remoting/client/jni/chromoting_jni_instance.cc | 244 | ||||
-rw-r--r-- | remoting/client/jni/chromoting_jni_instance.h | 82 | ||||
-rw-r--r-- | remoting/client/jni/jni_interface.cc | 14 | ||||
-rw-r--r-- | remoting/remoting.gyp | 2 |
6 files changed, 353 insertions, 216 deletions
diff --git a/remoting/client/jni/chromoting_jni.cc b/remoting/client/jni/chromoting_jni.cc new file mode 100644 index 0000000..4d1d0cf4 --- /dev/null +++ b/remoting/client/jni/chromoting_jni.cc @@ -0,0 +1,117 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "remoting/client/jni/chromoting_jni.h" + +#include "base/android/base_jni_registrar.h" +#include "base/android/jni_android.h" +#include "base/memory/singleton.h" +#include "net/android/net_jni_registrar.h" +#include "remoting/base/url_request_context.h" +#include "remoting/client/jni/chromoting_jni_instance.h" + +namespace { +// Class and package name of the Java class supporting the methods we call. +const char* const JAVA_CLASS = "org/chromium/chromoting/jni/JNIInterface"; +} // namespace + +namespace remoting { + +// static +ChromotingJni* ChromotingJni::GetInstance() { + return Singleton<ChromotingJni>::get(); +} + +ChromotingJni::ChromotingJni() { + // Obtain a reference to the Java environment. (Future calls to this function + // made from the same thread return the same stored reference instead of + // repeating the work of attaching to the JVM.) + JNIEnv* env = base::android::AttachCurrentThread(); + + // The base and networks stacks must be registered with JNI in order to work + // on Android. An AtExitManager cleans this up at process exit. + at_exit_manager_.reset(new base::AtExitManager()); + base::android::RegisterJni(env); + net::android::RegisterJni(env); + + // On Android, the UI thread is managed by Java, so we need to attach and + // start a special type of message loop to allow Chromium code to run tasks. + LOG(INFO) << "Starting main message loop"; + ui_loop_.reset(new base::MessageLoopForUI()); + ui_loop_->Start(); + + LOG(INFO) << "Spawning additional threads"; + // TODO(solb) Stop pretending to control the managed UI thread's lifetime. + ui_task_runner_ = new AutoThreadTaskRunner(ui_loop_->message_loop_proxy(), + base::MessageLoop::QuitClosure()); + network_task_runner_ = AutoThread::CreateWithType("native_net", + ui_task_runner_, + base::MessageLoop::TYPE_IO); + display_task_runner_ = AutoThread::Create("native_disp", + ui_task_runner_); + + url_requester_ = new URLRequestContextGetter(ui_task_runner_, + network_task_runner_); + + class_ = static_cast<jclass>(env->NewGlobalRef(env->FindClass(JAVA_CLASS))); +} + +ChromotingJni::~ChromotingJni() { + // The singleton should only ever be destroyed on the main thread. + DCHECK(ui_task_runner_->BelongsToCurrentThread()); + + // The session must be shut down first, since it depends on our other + // components' still being alive. + DisconnectFromHost(); + + JNIEnv* env = base::android::AttachCurrentThread(); + env->DeleteGlobalRef(class_); + // TODO(solb): crbug.com/259594 Detach all threads from JVM here. +} + +void ChromotingJni::ConnectToHost(const char* username, + const char* auth_token, + const char* host_jid, + const char* host_id, + const char* host_pubkey) { + DCHECK(ui_task_runner_->BelongsToCurrentThread()); + DCHECK(!session_); + session_ = new ChromotingJniInstance(username, + auth_token, + host_jid, + host_id, + host_pubkey); +} + +void ChromotingJni::DisconnectFromHost() { + DCHECK(ui_task_runner_->BelongsToCurrentThread()); + if (session_) { + session_->Cleanup(); + session_ = NULL; + } +} + +void ChromotingJni::ReportConnectionStatus( + protocol::ConnectionToHost::State state, + protocol::ErrorCode error) { + DCHECK(ui_task_runner_->BelongsToCurrentThread()); + + JNIEnv* env = base::android::AttachCurrentThread(); + env->CallStaticVoidMethod( + class_, + env->GetStaticMethodID(class_, "reportConnectionStatus", "(II)V"), + state, + error); +} + +void ChromotingJni::DisplayAuthenticationPrompt() { + DCHECK(ui_task_runner_->BelongsToCurrentThread()); + + JNIEnv* env = base::android::AttachCurrentThread(); + env->CallStaticVoidMethod( + class_, + env->GetStaticMethodID(class_, "displayAuthenticationPrompt", "()V")); +} + +} // namespace remoting diff --git a/remoting/client/jni/chromoting_jni.h b/remoting/client/jni/chromoting_jni.h new file mode 100644 index 0000000..23df7b0 --- /dev/null +++ b/remoting/client/jni/chromoting_jni.h @@ -0,0 +1,110 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef REMOTING_CLIENT_JNI_CHROMOTING_JNI_H_ +#define REMOTING_CLIENT_JNI_CHROMOTING_JNI_H_ + +#include <jni.h> + +#include "base/at_exit.h" +#include "net/url_request/url_request_context_getter.h" +#include "remoting/base/auto_thread.h" +#include "remoting/protocol/connection_to_host.h" + +template<typename T> struct DefaultSingletonTraits; + +namespace remoting { +class ChromotingJniInstance; + +// Houses the global resources on which the Chromoting components run +// (e.g. message loops and task runners). Proxies outgoing JNI calls from its +// ChromotingJniInstance member to Java. All its methods should be invoked +// exclusively from the UI thread. +class ChromotingJni { + public: + // This class is instantiated at process initialization and persists until + // we close. Its components are reused across |ChromotingJniInstance|s. + static ChromotingJni* GetInstance(); + + scoped_refptr<AutoThreadTaskRunner> ui_task_runner() { + return ui_task_runner_; + } + + scoped_refptr<AutoThreadTaskRunner> network_task_runner() { + return network_task_runner_; + } + + scoped_refptr<AutoThreadTaskRunner> display_task_runner() { + return display_task_runner_; + } + + scoped_refptr<net::URLRequestContextGetter> url_requester() { + return url_requester_; + } + + // Initiates a connection with the specified host. Must only be called when + // |session_| is null (i.e. before any other call to Connect() or following + // a call to Disconnect()). + void ConnectToHost(const char* username, + const char* auth_token, + const char* host_jid, + const char* host_id, + const char* host_pubkey); + + // Terminates any ongoing connection attempt and cleans up by nullifying + // |session_|. This is a no-op unless |session| is currently non-null. + void DisconnectFromHost(); + + // Returns the client for the currently-active session. Do not call if + // |session| is null. + scoped_refptr<ChromotingJniInstance> session() { + DCHECK(session_); + return session_; + } + + // Notifies the user that the connection status has changed. + void ReportConnectionStatus(protocol::ConnectionToHost::State state, + protocol::ErrorCode error); + + // Pops up a dialog box asking the user to enter a PIN. + void DisplayAuthenticationPrompt(); + + private: + ChromotingJni(); + + // Forces a DisconnectFromHost() in case there is any active or failed + // connection, then proceeds to tear down the Chromium dependencies on which + // all sessions depended. Because destruction only occurs at application exit + // after all connections have terminated, it is safe to make unretained + // cross-thread calls on the class. + virtual ~ChromotingJni(); + + // Reference to the Java class into which we make JNI calls. + jclass class_; + + // Used by the Chromium libraries to clean up the base and net libraries' JNI + // bindings. It must persist for the lifetime of the singleton. + scoped_ptr<base::AtExitManager> at_exit_manager_; + + // Chromium code's connection to the Java message loop. + scoped_ptr<base::MessageLoopForUI> ui_loop_; + + // References to native threads. + scoped_refptr<AutoThreadTaskRunner> ui_task_runner_; + scoped_refptr<AutoThreadTaskRunner> network_task_runner_; + scoped_refptr<AutoThreadTaskRunner> display_task_runner_; + + scoped_refptr<net::URLRequestContextGetter> url_requester_; + + // Contains all connection-specific state. + scoped_refptr<ChromotingJniInstance> session_; + + friend struct DefaultSingletonTraits<ChromotingJni>; + + DISALLOW_COPY_AND_ASSIGN(ChromotingJni); +}; + +} // namespace remoting + +#endif diff --git a/remoting/client/jni/chromoting_jni_instance.cc b/remoting/client/jni/chromoting_jni_instance.cc index 77fa9c8..df6583d 100644 --- a/remoting/client/jni/chromoting_jni_instance.cc +++ b/remoting/client/jni/chromoting_jni_instance.cc @@ -4,73 +4,29 @@ #include "remoting/client/jni/chromoting_jni_instance.h" -#include "base/android/base_jni_registrar.h" -#include "base/android/jni_android.h" #include "base/bind.h" -#include "base/bind_helpers.h" #include "base/logging.h" -#include "base/memory/singleton.h" -#include "net/android/net_jni_registrar.h" -#include "remoting/base/url_request_context.h" #include "remoting/client/audio_player.h" +#include "remoting/client/jni/chromoting_jni.h" #include "remoting/protocol/libjingle_transport_factory.h" -namespace remoting { - -// static -ChromotingJNIInstance* ChromotingJNIInstance::GetInstance() { - return Singleton<ChromotingJNIInstance>::get(); -} - -ChromotingJNIInstance::ChromotingJNIInstance() - : connected_(false) { - JNIEnv* env = base::android::AttachCurrentThread(); - - // The base and networks stacks must be registered with JNI in order to work - // on Android. An AtExitManager cleans this up at world's end. - collector_.reset(new base::AtExitManager()); - base::android::RegisterJni(env); - net::android::RegisterJni(env); - - // On Android, the UI thread is managed by Java, so we need to attach and - // start a special type of message loop to allow Chromium code to run tasks. - LOG(INFO) << "Starting main message loop"; - ui_loop_.reset(new base::MessageLoopForUI()); - ui_loop_->Start(); - - LOG(INFO) << "Spawning additional threads"; - // TODO(solb) Stop pretending to control the managed UI thread's lifetime. - ui_task_runner_ = new AutoThreadTaskRunner(ui_loop_->message_loop_proxy(), - base::MessageLoop::QuitClosure()); - network_task_runner_ = AutoThread::CreateWithType("native_net", - ui_task_runner_, - base::MessageLoop::TYPE_IO); - display_task_runner_ = AutoThread::Create("native_disp", - ui_task_runner_); - - url_requester_ = new URLRequestContextGetter(ui_task_runner_, - network_task_runner_); - - class_ = static_cast<jclass>(env->NewGlobalRef(env->FindClass(JAVA_CLASS))); -} - -ChromotingJNIInstance::~ChromotingJNIInstance() { - DCHECK(ui_task_runner_->BelongsToCurrentThread()); - DCHECK(!connected_); +namespace { +// TODO(solb) Move into location shared with client plugin. +const char* const CHAT_SERVER = "talk.google.com"; +const int CHAT_PORT = 5222; +const bool CHAT_USE_TLS = true; +const char* const CHAT_AUTH_METHOD = "oauth2"; +} // namespace - JNIEnv* env = base::android::AttachCurrentThread(); - env->DeleteGlobalRef(class_); - // TODO(solb): crbug.com/259594 Detach all threads from JVM here. -} +namespace remoting { -void ChromotingJNIInstance::ConnectToHost(const char* username, - const char* auth_token, - const char* host_jid, - const char* host_id, - const char* host_pubkey) { - DCHECK(ui_task_runner_->BelongsToCurrentThread()); - DCHECK(!connected_); - connected_ = true; +ChromotingJniInstance::ChromotingJniInstance(const char* username, + const char* auth_token, + const char* host_jid, + const char* host_id, + const char* host_pubkey) { + DCHECK(ChromotingJni::GetInstance()-> + ui_task_runner()->BelongsToCurrentThread()); username_ = username; auth_token_ = auth_token; @@ -78,101 +34,123 @@ void ChromotingJNIInstance::ConnectToHost(const char* username, host_id_ = host_id; host_pubkey_ = host_pubkey; - display_task_runner_->PostTask(FROM_HERE, base::Bind( - &ChromotingJNIInstance::ConnectToHostOnDisplayThread, - base::Unretained(this))); + ChromotingJni::GetInstance()->display_task_runner()->PostTask( + FROM_HERE, + base::Bind(&ChromotingJniInstance::ConnectToHostOnDisplayThread, + this)); } -void ChromotingJNIInstance::DisconnectFromHost() { - DCHECK(ui_task_runner_->BelongsToCurrentThread()); - DCHECK(connected_); - connected_ = false; +ChromotingJniInstance::~ChromotingJniInstance() {} + +void ChromotingJniInstance::Cleanup() { + if (!ChromotingJni::GetInstance()-> + network_task_runner()->BelongsToCurrentThread()) { + ChromotingJni::GetInstance()->network_task_runner()->PostTask( + FROM_HERE, + base::Bind(&ChromotingJniInstance::Cleanup, this)); + return; + } + + username_ = ""; + auth_token_ = ""; + host_jid_ = ""; + host_id_ = ""; + host_pubkey_ = ""; - network_task_runner_->PostTask(FROM_HERE, base::Bind( - &ChromotingJNIInstance::DisconnectFromHostOnNetworkThread, - base::Unretained(this))); + // |client_| must be torn down before |signaling_|. + pin_callback_.Reset(); + client_.reset(); + connection_.reset(); + client_context_.reset(); + client_config_.reset(); + signaling_.reset(); + signaling_config_.reset(); + network_settings_.reset(); } -void ChromotingJNIInstance::ProvideSecret(const char* pin) { - DCHECK(ui_task_runner_->BelongsToCurrentThread()); +void ChromotingJniInstance::ProvideSecret(const char* pin) { + DCHECK(ChromotingJni::GetInstance()-> + ui_task_runner()->BelongsToCurrentThread()); DCHECK(!pin_callback_.is_null()); // We invoke the string constructor to ensure |pin| gets copied *before* the // asynchronous run, since Java might want it back as soon as we return. - network_task_runner_->PostTask(FROM_HERE, - base::Bind(pin_callback_, std::string(pin))); + ChromotingJni::GetInstance()->network_task_runner()->PostTask(FROM_HERE, + base::Bind(pin_callback_, pin)); } -void ChromotingJNIInstance::OnConnectionState( +void ChromotingJniInstance::OnConnectionState( protocol::ConnectionToHost::State state, protocol::ErrorCode error) { - if (!ui_task_runner_->BelongsToCurrentThread()) { - ui_task_runner_->PostTask(FROM_HERE, base::Bind( - &ChromotingJNIInstance::OnConnectionState, - base::Unretained(this), - state, - error)); + if (!ChromotingJni::GetInstance()-> + ui_task_runner()->BelongsToCurrentThread()) { + ChromotingJni::GetInstance()-> + ui_task_runner()->PostTask( + FROM_HERE, + base::Bind(&ChromotingJniInstance::OnConnectionState, + this, + state, + error)); return; } - JNIEnv* env = base::android::AttachCurrentThread(); - env->CallStaticVoidMethod( - class_, - env->GetStaticMethodID(class_, "reportConnectionStatus", "(II)V"), - state, - error); + ChromotingJni::GetInstance()->ReportConnectionStatus(state, error); } -void ChromotingJNIInstance::OnConnectionReady(bool ready) { +void ChromotingJniInstance::OnConnectionReady(bool ready) { // We ignore this message, since OnConnectionState() tells us the same thing. } -void ChromotingJNIInstance::SetCapabilities(const std::string& capabilities) {} +void ChromotingJniInstance::SetCapabilities(const std::string& capabilities) {} -void ChromotingJNIInstance::SetPairingResponse( +void ChromotingJniInstance::SetPairingResponse( const protocol::PairingResponse& response) { NOTIMPLEMENTED(); } -protocol::ClipboardStub* ChromotingJNIInstance::GetClipboardStub() { +protocol::ClipboardStub* ChromotingJniInstance::GetClipboardStub() { NOTIMPLEMENTED(); return NULL; } -protocol::CursorShapeStub* ChromotingJNIInstance::GetCursorShapeStub() { +protocol::CursorShapeStub* ChromotingJniInstance::GetCursorShapeStub() { NOTIMPLEMENTED(); return NULL; } scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher> - ChromotingJNIInstance::GetTokenFetcher(const std::string& host_public_key) { + ChromotingJniInstance::GetTokenFetcher(const std::string& host_public_key) { // Return null to indicate that third-party authentication is unsupported. return scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>(); } -void ChromotingJNIInstance::ConnectToHostOnDisplayThread() { - DCHECK(display_task_runner_->BelongsToCurrentThread()); +void ChromotingJniInstance::ConnectToHostOnDisplayThread() { + DCHECK(ChromotingJni::GetInstance()-> + display_task_runner()->BelongsToCurrentThread()); if (!frame_consumer_.get()) { - frame_consumer_ = new FrameConsumerProxy(display_task_runner_); + frame_consumer_ = new FrameConsumerProxy( + ChromotingJni::GetInstance()->display_task_runner()); // TODO(solb) Instantiate some FrameConsumer implementation and attach it. } - network_task_runner_->PostTask(FROM_HERE, base::Bind( - &ChromotingJNIInstance::ConnectToHostOnNetworkThread, - base::Unretained(this))); + ChromotingJni::GetInstance()->network_task_runner()->PostTask( + FROM_HERE, + base::Bind(&ChromotingJniInstance::ConnectToHostOnNetworkThread, + this)); } -void ChromotingJNIInstance::ConnectToHostOnNetworkThread() { - DCHECK(network_task_runner_->BelongsToCurrentThread()); +void ChromotingJniInstance::ConnectToHostOnNetworkThread() { + DCHECK(ChromotingJni::GetInstance()-> + network_task_runner()->BelongsToCurrentThread()); client_config_.reset(new ClientConfig()); client_config_->host_jid = host_jid_; client_config_->host_public_key = host_pubkey_; client_config_->fetch_secret_callback = base::Bind( - &ChromotingJNIInstance::FetchSecret, - base::Unretained(this)); + &ChromotingJniInstance::FetchSecret, + this); client_config_->authentication_tag = host_id_; // TODO(solb) Move these hardcoded values elsewhere: @@ -181,7 +159,8 @@ void ChromotingJNIInstance::ConnectToHostOnNetworkThread() { client_config_->authentication_methods.push_back( protocol::AuthenticationMethod::FromString("spake2_plain")); - client_context_.reset(new ClientContext(network_task_runner_.get())); + client_context_.reset(new ClientContext( + ChromotingJni::GetInstance()->network_task_runner().get())); client_context_->Start(); connection_.reset(new protocol::ConnectionToHost(true)); @@ -198,58 +177,39 @@ void ChromotingJNIInstance::ConnectToHostOnNetworkThread() { signaling_config_->port = CHAT_PORT; signaling_config_->use_tls = CHAT_USE_TLS; - signaling_.reset(new XmppSignalStrategy(url_requester_, - username_, - auth_token_, - CHAT_AUTH_METHOD, - *signaling_config_)); + signaling_.reset(new XmppSignalStrategy( + ChromotingJni::GetInstance()->url_requester(), + username_, + auth_token_, + CHAT_AUTH_METHOD, + *signaling_config_)); network_settings_.reset(new NetworkSettings( NetworkSettings::NAT_TRAVERSAL_OUTGOING)); scoped_ptr<protocol::TransportFactory> fact( - protocol::LibjingleTransportFactory::Create(*network_settings_, - url_requester_)); + protocol::LibjingleTransportFactory::Create( + *network_settings_, + ChromotingJni::GetInstance()->url_requester())); client_->Start(signaling_.get(), fact.Pass()); } -void ChromotingJNIInstance::DisconnectFromHostOnNetworkThread() { - DCHECK(network_task_runner_->BelongsToCurrentThread()); - - username_ = ""; - auth_token_ = ""; - host_jid_ = ""; - host_id_ = ""; - host_pubkey_ = ""; - - // |client_| must be torn down before |signaling_|. - pin_callback_.Reset(); - client_.reset(); - connection_.reset(); - client_context_.reset(); - client_config_.reset(); - signaling_.reset(); - signaling_config_.reset(); - network_settings_.reset(); -} - -void ChromotingJNIInstance::FetchSecret( +void ChromotingJniInstance::FetchSecret( bool pairable, const protocol::SecretFetchedCallback& callback) { - if (!ui_task_runner_->BelongsToCurrentThread()) { - ui_task_runner_->PostTask(FROM_HERE, base::Bind( - &ChromotingJNIInstance::FetchSecret, - base::Unretained(this), - pairable, - callback)); + if (!ChromotingJni::GetInstance()-> + ui_task_runner()->BelongsToCurrentThread()) { + ChromotingJni::GetInstance()->ui_task_runner()->PostTask( + FROM_HERE, + base::Bind(&ChromotingJniInstance::FetchSecret, + this, + pairable, + callback)); return; } pin_callback_ = callback; - JNIEnv* env = base::android::AttachCurrentThread(); - env->CallStaticVoidMethod( - class_, - env->GetStaticMethodID(class_, "displayAuthenticationPrompt", "()V")); + ChromotingJni::GetInstance()->DisplayAuthenticationPrompt(); } } // namespace remoting diff --git a/remoting/client/jni/chromoting_jni_instance.h b/remoting/client/jni/chromoting_jni_instance.h index 05ee17f..c9e689a 100644 --- a/remoting/client/jni/chromoting_jni_instance.h +++ b/remoting/client/jni/chromoting_jni_instance.h @@ -5,15 +5,11 @@ #ifndef REMOTING_CLIENT_CHROMOTING_JNI_INSTANCE_H_ #define REMOTING_CLIENT_CHROMOTING_JNI_INSTANCE_H_ -#include <jni.h> #include <string> -#include "base/at_exit.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop.h" -#include "net/url_request/url_request_context_getter.h" -#include "remoting/base/auto_thread.h" #include "remoting/client/chromoting_client.h" #include "remoting/client/client_config.h" #include "remoting/client/client_context.h" @@ -23,41 +19,25 @@ #include "remoting/jingle_glue/xmpp_signal_strategy.h" #include "remoting/protocol/connection_to_host.h" -template<typename T> struct DefaultSingletonTraits; - namespace remoting { +class ChromotingJni; -// Class and package name of the Java class supporting the methods we call. -const char* const JAVA_CLASS = "org/chromium/chromoting/jni/JNIInterface"; - -// TODO(solb) Move into location shared with client plugin. -const char* const CHAT_SERVER = "talk.google.com"; -const int CHAT_PORT = 5222; -const bool CHAT_USE_TLS = true; -const char* const CHAT_AUTH_METHOD = "oauth2"; - -// ClientUserInterface that makes and (indirectly) receives JNI calls. It also -// contains global resources on which the Chromoting components run -// (e.g. message loops and task runners). -class ChromotingJNIInstance : public ClientUserInterface { +// ClientUserInterface that indirectly makes and receives JNI calls. +class ChromotingJniInstance + : public ClientUserInterface, + public base::RefCountedThreadSafe<ChromotingJniInstance> { public: - // This class is instantiated at process initialization and persists until - // we close. It reuses many of its components between connections (i.e. when - // a DisconnectFromHost() call is followed by a ConnectToHost() one. - static ChromotingJNIInstance* GetInstance(); - - // Initiates a connection with the specified host. This may only be called - // when |connected_| is false, and must be invoked on the UI thread. - void ConnectToHost( + // Initiates a connection with the specified host. Call from the UI thread. + ChromotingJniInstance( const char* username, const char* auth_token, const char* host_jid, const char* host_id, const char* host_pubkey); - // Terminates the current connection (if it hasn't already failed) and clean - // up. This may only be called when |connected_|, and only from the UI thread. - void DisconnectFromHost(); + // Terminates the current connection (if it hasn't already failed) and cleans + // up. Must be called before destruction. + void Cleanup(); // Provides the user's PIN and resumes the host authentication attempt. Call // on the UI thread once the user has finished entering this PIN into the UI, @@ -78,53 +58,19 @@ class ChromotingJNIInstance : public ClientUserInterface { GetTokenFetcher(const std::string& host_public_key) OVERRIDE; private: - ChromotingJNIInstance(); - - // Any existing or attempted connection must have been terminated using - // DisconnectFromHost() before this singleton is destroyed. Because - // destruction only occurs at application exit after all connections have - // terminated, it is safe to make unretained cross-thread calls on the class. - // As a singleton, this object must be destroyed on the main (UI) thread. - virtual ~ChromotingJNIInstance(); + // This object is ref-counted, so it cleans itself up. + virtual ~ChromotingJniInstance(); void ConnectToHostOnDisplayThread(); void ConnectToHostOnNetworkThread(); - void DisconnectFromHostOnNetworkThread(); - // Notifies the user interface that the user needs to enter a PIN. The // current authentication attempt is put on hold until |callback| is invoked. void FetchSecret(bool pairable, const protocol::SecretFetchedCallback& callback); - // The below variables are reused across consecutive sessions. - - // Reference to the Java class into which we make JNI calls. - jclass class_; - - // Used by the Chromium libraries to clean up the base and net libraries' JNI - // bindings. It must persist for the lifetime of the singleton. - scoped_ptr<base::AtExitManager> collector_; - - // Chromium code's connection to the Java message loop. - scoped_ptr<base::MessageLoopForUI> ui_loop_; - - // Runners that allow posting tasks to the various native threads. - scoped_refptr<AutoThreadTaskRunner> ui_task_runner_; - scoped_refptr<AutoThreadTaskRunner> network_task_runner_; - scoped_refptr<AutoThreadTaskRunner> display_task_runner_; - - scoped_refptr<net::URLRequestContextGetter> url_requester_; scoped_refptr<FrameConsumerProxy> frame_consumer_; - // All below variables are specific to each connection. - - // True iff ConnectToHost() has been called without a subsequent - // call to DisconnectFromHost() (i.e. while connecting, once connected, and - // between the time a connection fails and DisconnectFromHost() is called). - // To be used on the UI thread. - bool connected_; - // This group of variables is to be used on the network thread. scoped_ptr<ClientConfig> client_config_; scoped_ptr<ClientContext> client_context_; @@ -148,9 +94,9 @@ class ChromotingJNIInstance : public ClientUserInterface { std::string host_id_; std::string host_pubkey_; - friend struct DefaultSingletonTraits<ChromotingJNIInstance>; + friend class base::RefCountedThreadSafe<ChromotingJniInstance>; - DISALLOW_COPY_AND_ASSIGN(ChromotingJNIInstance); + DISALLOW_COPY_AND_ASSIGN(ChromotingJniInstance); }; } // namespace remoting diff --git a/remoting/client/jni/jni_interface.cc b/remoting/client/jni/jni_interface.cc index b78ff05..d8f03c9 100644 --- a/remoting/client/jni/jni_interface.cc +++ b/remoting/client/jni/jni_interface.cc @@ -5,8 +5,8 @@ // This file defines functions that implement the static methods declared in a // closely-related Java class in the platform-specific user interface // implementation. In effect, it is the entry point for all JNI calls *into* -// the C++ codebase from Java. The separate ChromotingJNIInstance class serves -// as the corresponding exit point, and is responsible for making all JNI calls +// the C++ codebase from Java. The separate ChromotingJni class serves as the +// corresponding exit point, and is responsible for making all JNI calls // *out of* the C++ codebase into Java. #include <jni.h> @@ -15,6 +15,7 @@ #include "base/command_line.h" #include "base/memory/ref_counted.h" #include "google_apis/google_api_keys.h" +#include "remoting/client/jni/chromoting_jni.h" #include "remoting/client/jni/chromoting_jni_instance.h" // Class and package name of the Java class that declares this file's functions. @@ -41,7 +42,7 @@ JNIEXPORT void JNICALL JNI_IMPLEMENTATION(loadNative)(JNIEnv* env, CommandLine::Init(0, NULL); // Create the singleton now so that the Chromoting threads will be set up. - remoting::ChromotingJNIInstance::GetInstance(); + remoting::ChromotingJni::GetInstance(); } JNIEXPORT jstring JNICALL JNI_IMPLEMENTATION(getApiKey)(JNIEnv* env, @@ -75,7 +76,7 @@ JNIEXPORT void JNICALL JNI_IMPLEMENTATION(connectNative)( const char* host_id_cstr = env->GetStringUTFChars(host_id_jstr, NULL); const char* host_pubkey_cstr = env->GetStringUTFChars(host_pubkey_jstr, NULL); - remoting::ChromotingJNIInstance::GetInstance()->ConnectToHost( + remoting::ChromotingJni::GetInstance()->ConnectToHost( username_cstr, auth_token_cstr, host_jid_cstr, @@ -91,7 +92,7 @@ JNIEXPORT void JNICALL JNI_IMPLEMENTATION(connectNative)( JNIEXPORT void JNICALL JNI_IMPLEMENTATION(disconnectNative)(JNIEnv* env, jobject that) { - remoting::ChromotingJNIInstance::GetInstance()->DisconnectFromHost(); + remoting::ChromotingJni::GetInstance()->DisconnectFromHost(); } JNIEXPORT void JNICALL JNI_IMPLEMENTATION(authenticationResponse)( @@ -100,7 +101,8 @@ JNIEXPORT void JNICALL JNI_IMPLEMENTATION(authenticationResponse)( jstring pin_jstr) { const char* pin_cstr = env->GetStringUTFChars(pin_jstr, NULL); - remoting::ChromotingJNIInstance::GetInstance()->ProvideSecret(pin_cstr); + remoting::ChromotingJni::GetInstance()-> + session()->ProvideSecret(pin_cstr); env->ReleaseStringUTFChars(pin_jstr, pin_cstr); } diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp index f01335c..c514033 100644 --- a/remoting/remoting.gyp +++ b/remoting/remoting.gyp @@ -1819,6 +1819,8 @@ '../google_apis/google_apis.gyp:google_apis', ], 'sources': [ + 'client/jni/chromoting_jni.cc', + 'client/jni/chromoting_jni.h', 'client/jni/chromoting_jni_instance.cc', 'client/jni/chromoting_jni_instance.h', 'client/jni/jni_interface.cc', |