Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(603)

Side by Side Diff: remoting/client/jni/chromoting_jni_instance.cc

Issue 18612018: Restructure chromoting_jni_instance handling of Java strings (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Connection/disconnection state machine and moar comments Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "remoting/client/jni/chromoting_jni_instance.h" 5 #include "remoting/client/jni/chromoting_jni_instance.h"
6 6
7 #include "base/android/base_jni_registrar.h" 7 #include "base/android/base_jni_registrar.h"
8 #include "base/android/jni_android.h" 8 #include "base/android/jni_android.h"
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/bind_helpers.h" 10 #include "base/bind_helpers.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/memory/singleton.h" 12 #include "base/memory/singleton.h"
13 #include "net/android/net_jni_registrar.h" 13 #include "net/android/net_jni_registrar.h"
14 #include "remoting/base/url_request_context.h" 14 #include "remoting/base/url_request_context.h"
15 #include "remoting/client/audio_player.h" 15 #include "remoting/client/audio_player.h"
16 #include "remoting/protocol/libjingle_transport_factory.h" 16 #include "remoting/protocol/libjingle_transport_factory.h"
17 17
18 namespace remoting { 18 namespace remoting {
19 19
20 // static 20 // static
21 ChromotingJNIInstance* ChromotingJNIInstance::GetInstance() { 21 ChromotingJNIInstance* ChromotingJNIInstance::GetInstance() {
22 return Singleton<ChromotingJNIInstance>::get(); 22 return Singleton<ChromotingJNIInstance>::get();
23 } 23 }
24 24
25 ChromotingJNIInstance::ChromotingJNIInstance() 25 ChromotingJNIInstance::ChromotingJNIInstance()
26 : username_cstr_(NULL), 26 : connected_(false) {
27 auth_token_cstr_(NULL),
28 host_jid_cstr_(NULL),
29 host_id_cstr_(NULL),
30 host_pubkey_cstr_(NULL),
31 pin_cstr_(NULL) {
32 JNIEnv* env = base::android::AttachCurrentThread(); 27 JNIEnv* env = base::android::AttachCurrentThread();
33 28
29 // The base and networks stacks must be registered with JNI in order to work
30 // on Android. An AtExitManager cleans this up at world's end.
34 collector_.reset(new base::AtExitManager()); 31 collector_.reset(new base::AtExitManager());
35 base::android::RegisterJni(env); 32 base::android::RegisterJni(env);
36 net::android::RegisterJni(env); 33 net::android::RegisterJni(env);
37 34
38 LOG(INFO) << "starting main message loop"; 35 // On Android, the UI thread is managed by Java, so we need to attach and
36 // start a special type of message loop to allow Chromium code to run tasks.
37 LOG(INFO) << "Starting main message loop";
39 ui_loop_.reset(new base::MessageLoopForUI()); 38 ui_loop_.reset(new base::MessageLoopForUI());
40 ui_loop_->Start(); 39 ui_loop_->Start();
41 40
42 LOG(INFO) << "spawning additional threads"; 41 LOG(INFO) << "Spawning additional threads";
43 ui_runner_ = new AutoThreadTaskRunner(ui_loop_->message_loop_proxy(), 42 ui_task_runner_ = new AutoThreadTaskRunner(ui_loop_->message_loop_proxy(),
44 base::MessageLoop::QuitClosure()); 43 base::MessageLoop::QuitClosure());
Wez 2013/07/12 00:24:48 AutoThreads don't exit until there are no more ref
solb 2013/07/12 01:14:22 I don't believe so. Unlike the threads that are cr
Wez 2013/07/12 01:25:44 But you are wrapping the main MessageLoopForUI in
45 net_runner_ = AutoThread::CreateWithType("native_net", 44 network_task_runner_ = AutoThread::CreateWithType("native_net",
46 ui_runner_, 45 ui_task_runner_,
47 base::MessageLoop::TYPE_IO); 46 base::MessageLoop::TYPE_IO);
48 disp_runner_ = AutoThread::CreateWithType("native_disp", 47 display_task_runner_ = AutoThread::CreateWithType("native_disp",
49 ui_runner_, 48 ui_task_runner_,
50 base::MessageLoop::TYPE_DEFAULT); 49 base::MessageLoop::TYPE_DEFAULT);
51 50
52 url_requester_ = new URLRequestContextGetter(ui_runner_, net_runner_); 51 url_requester_ = new URLRequestContextGetter(ui_task_runner_,
52 network_task_runner_);
53 53
54 class_ = static_cast<jclass>(env->NewGlobalRef(env->FindClass(JAVA_CLASS))); 54 class_ = static_cast<jclass>(env->NewGlobalRef(env->FindClass(JAVA_CLASS)));
55 } 55 }
56 56
57 ChromotingJNIInstance::~ChromotingJNIInstance() { 57 ChromotingJNIInstance::~ChromotingJNIInstance() {
58 DCHECK(!connected_);
59
58 JNIEnv* env = base::android::AttachCurrentThread(); 60 JNIEnv* env = base::android::AttachCurrentThread();
59 env->DeleteGlobalRef(class_); 61 env->DeleteGlobalRef(class_);
60 // TODO(solb) detach all threads from JVM 62 // TODO(solb) detach all threads from JVM
61 } 63 }
62 64
63 void ChromotingJNIInstance::ConnectToHost(jstring username, 65 void ChromotingJNIInstance::ConnectToHost(const char* username,
64 jstring auth_token, 66 const char* auth_token,
65 jstring host_jid, 67 const char* host_jid,
66 jstring host_id, 68 const char* host_id,
67 jstring host_pubkey) { 69 const char* host_pubkey) {
68 JNIEnv* env = base::android::AttachCurrentThread(); 70 DCHECK(!connected_);
71 connected_ = true;
69 72
70 username_jstr_ = static_cast<jstring>(env->NewGlobalRef(username)); 73 username_ = username;
71 auth_token_jstr_ = static_cast<jstring>(env->NewGlobalRef(auth_token)); 74 auth_token_ = auth_token;
72 host_jid_jstr_ = static_cast<jstring>(env->NewGlobalRef(host_jid)); 75 host_jid_ = host_jid;
73 host_id_jstr_ = static_cast<jstring>(env->NewGlobalRef(host_id)); 76 host_id_ = host_id;
74 host_pubkey_jstr_ = static_cast<jstring>(env->NewGlobalRef(host_pubkey)); 77 host_pubkey_ = host_pubkey;
75
76 username_cstr_ = env->GetStringUTFChars(username_jstr_, NULL);
77 auth_token_cstr_ = env->GetStringUTFChars(auth_token_jstr_, NULL);
78 host_jid_cstr_ = env->GetStringUTFChars(host_jid_jstr_, NULL);
79 host_id_cstr_ = env->GetStringUTFChars(host_id_jstr_, NULL);
80 host_pubkey_cstr_ = env->GetStringUTFChars(host_pubkey_jstr_, NULL);
81 78
82 // We're a singleton, so Unretained is safe here. 79 // We're a singleton, so Unretained is safe here.
83 disp_runner_->PostTask(FROM_HERE, base::Bind( 80 display_task_runner_->PostTask(FROM_HERE, base::Bind(
84 &ChromotingJNIInstance::ConnectToHostOnDisplayThread, 81 &ChromotingJNIInstance::ConnectToHostOnDisplayThread,
85 base::Unretained(this))); 82 base::Unretained(this)));
86 } 83 }
87 84
88 void ChromotingJNIInstance::DisconnectFromHost() { 85 void ChromotingJNIInstance::DisconnectFromHost() {
89 JNIEnv* env = base::android::AttachCurrentThread(); 86 DCHECK(connected_);
87 connected_ = false;
90 88
91 env->ReleaseStringUTFChars(username_jstr_, username_cstr_); 89 username_ = "";
92 env->ReleaseStringUTFChars(auth_token_jstr_, auth_token_cstr_); 90 auth_token_ = "";
93 env->ReleaseStringUTFChars(host_jid_jstr_, host_jid_cstr_); 91 host_jid_ = "";
94 env->ReleaseStringUTFChars(host_id_jstr_, host_id_cstr_); 92 host_id_ = "";
95 env->ReleaseStringUTFChars(host_pubkey_jstr_, host_pubkey_cstr_); 93 host_pubkey_ = "";
96 94 pin_ = "";
Wez 2013/07/12 00:24:48 This is racy if the caller calls ConnectToHost and
solb 2013/07/12 01:14:22 This is always called from the same thread as Conn
Wez 2013/07/12 01:25:44 That's not the point - ConnectToHost and Disconnec
97 username_cstr_ = NULL;
98 auth_token_cstr_ = NULL;
99 host_jid_cstr_ = NULL;
100 host_id_cstr_ = NULL;
101 host_pubkey_cstr_ = NULL;
102
103 env->DeleteGlobalRef(username_jstr_);
104 env->DeleteGlobalRef(auth_token_jstr_);
105 env->DeleteGlobalRef(host_jid_jstr_);
106 env->DeleteGlobalRef(host_id_jstr_);
107 env->DeleteGlobalRef(host_pubkey_jstr_);
108
109 if (pin_cstr_) {
110 // AuthenticatedWithPin() has been called.
111 env->ReleaseStringUTFChars(pin_jstr_, pin_cstr_);
112 pin_cstr_ = NULL;
113 env->DeleteGlobalRef(pin_jstr_);
114 }
115 95
116 // We're a singleton, so Unretained is safe here. 96 // We're a singleton, so Unretained is safe here.
117 net_runner_->PostTask(FROM_HERE, base::Bind( 97 network_task_runner_->PostTask(FROM_HERE, base::Bind(
118 &ChromotingJNIInstance::DisconnectFromHostOnNetworkThread, 98 &ChromotingJNIInstance::DisconnectFromHostOnNetworkThread,
119 base::Unretained(this))); 99 base::Unretained(this)));
120 } 100 }
121 101
122 void ChromotingJNIInstance::AuthenticateWithPin(jstring pin) { 102 void ChromotingJNIInstance::AuthenticateWithPin(const char* pin) {
123 JNIEnv* env = base::android::AttachCurrentThread(); 103 pin_ = pin;
124 104 network_task_runner_->PostTask(FROM_HERE, base::Bind(pin_callback_, pin_));
125 pin_jstr_ = static_cast<jstring>(env->NewGlobalRef(pin));
126 pin_cstr_ = env->GetStringUTFChars(pin_jstr_, NULL);
127
128 net_runner_->PostTask(FROM_HERE, base::Bind(announce_secret_, pin_cstr_));
129 } 105 }
130 106
131 void ChromotingJNIInstance::FetchSecret( 107 void ChromotingJNIInstance::FetchSecret(
132 bool pairable, 108 bool pairable,
133 const protocol::SecretFetchedCallback& callback_encore) { 109 const protocol::SecretFetchedCallback& callback) {
134 // All our work must be done on the UI thread. 110 // Although we're invoked on the network thread, we must work on the UI one.
Wez 2013/07/12 00:24:48 This comment is superfluous, since it's clear that
solb 2013/07/12 01:14:22 Done.
135 if (!ui_runner_->BelongsToCurrentThread()) { 111 if (!ui_task_runner_->BelongsToCurrentThread()) {
136 // We're a singleton, so Unretained is safe here. 112 // We're a singleton, so Unretained is safe here.
Wez 2013/07/12 00:24:48 Based on the discussion around the singleton on ot
solb 2013/07/12 01:14:22 Done.
137 ui_runner_->PostTask(FROM_HERE, base::Bind( 113 ui_task_runner_->PostTask(FROM_HERE, base::Bind(
138 &ChromotingJNIInstance::FetchSecret, 114 &ChromotingJNIInstance::FetchSecret,
139 base::Unretained(this), 115 base::Unretained(this),
140 pairable, 116 pairable,
141 callback_encore)); 117 callback));
142 return; 118 return;
143 } 119 }
144 120
145 announce_secret_ = callback_encore; 121 pin_callback_ = callback;
146 JNIEnv* env = base::android::AttachCurrentThread(); 122 JNIEnv* env = base::android::AttachCurrentThread();
147 env->CallStaticVoidMethod( 123 env->CallStaticVoidMethod(
148 class_, 124 class_,
149 env->GetStaticMethodID(class_, "displayAuthenticationPrompt", "()V")); 125 env->GetStaticMethodID(class_, "displayAuthenticationPrompt", "()V"));
150 } 126 }
151 127
152 void ChromotingJNIInstance::OnConnectionState( 128 void ChromotingJNIInstance::OnConnectionState(
153 protocol::ConnectionToHost::State state, 129 protocol::ConnectionToHost::State state,
154 protocol::ErrorCode error) { 130 protocol::ErrorCode error) {
155 // All our work must be done on the UI thread. 131 // Although we're invoked on the network thread, we must work on the UI one.
156 if (!ui_runner_->BelongsToCurrentThread()) { 132 if (!ui_task_runner_->BelongsToCurrentThread()) {
157 // We're a singleton, so Unretained is safe here. 133 // We're a singleton, so Unretained is safe here.
158 ui_runner_->PostTask(FROM_HERE, base::Bind( 134 ui_task_runner_->PostTask(FROM_HERE, base::Bind(
159 &ChromotingJNIInstance::OnConnectionState, 135 &ChromotingJNIInstance::OnConnectionState,
160 base::Unretained(this), 136 base::Unretained(this),
161 state, 137 state,
162 error)); 138 error));
163 return; 139 return;
164 } 140 }
165 141
166 JNIEnv* env = base::android::AttachCurrentThread(); 142 JNIEnv* env = base::android::AttachCurrentThread();
167 env->CallStaticVoidMethod( 143 env->CallStaticVoidMethod(
168 class_, 144 class_,
169 env->GetStaticMethodID(class_, "reportConnectionStatus", "(II)V"), 145 env->GetStaticMethodID(class_, "reportConnectionStatus", "(II)V"),
170 state, 146 state,
171 error); 147 error);
172 } 148 }
173 149
174 void ChromotingJNIInstance::OnConnectionReady(bool ready) { 150 void ChromotingJNIInstance::OnConnectionReady(bool ready) {
151 // We ignore this message, since OnConnectionState() tells us the same thing.
175 } 152 }
176 153
177 void ChromotingJNIInstance::SetCapabilities(const std::string& capabilities) {} 154 void ChromotingJNIInstance::SetCapabilities(const std::string& capabilities) {}
178 155
179 void ChromotingJNIInstance::SetPairingResponse( 156 void ChromotingJNIInstance::SetPairingResponse(
180 const protocol::PairingResponse& response) {} 157 const protocol::PairingResponse& response) {
158 // We ignore this message because OnConnectionState() reveals the same info.
Wez 2013/07/12 00:24:48 This comment actually seems wrong; we just don't s
solb 2013/07/12 01:14:22 Sorry; I guess I didn't pay much attention to what
159 }
181 160
182 protocol::ClipboardStub* ChromotingJNIInstance::GetClipboardStub() { 161 protocol::ClipboardStub* ChromotingJNIInstance::GetClipboardStub() {
183 NOTIMPLEMENTED(); 162 NOTIMPLEMENTED();
184 return NULL; 163 return NULL;
185 } 164 }
186 165
187 protocol::CursorShapeStub* ChromotingJNIInstance::GetCursorShapeStub() { 166 protocol::CursorShapeStub* ChromotingJNIInstance::GetCursorShapeStub() {
188 NOTIMPLEMENTED(); 167 NOTIMPLEMENTED();
189 return NULL; 168 return NULL;
190 } 169 }
191 170
192 // We don't use NOTIMPLEMENTED() here because NegotiatingClientAuthenticator
193 // calls this even if it doesn't use the configuration method, and we don't
194 // want to print an error on every run.
195 scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher> 171 scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>
196 ChromotingJNIInstance::GetTokenFetcher(const std::string& host_public_key) { 172 ChromotingJNIInstance::GetTokenFetcher(const std::string& host_public_key) {
197 LOG(INFO) << "ChromotingJNIInstance::GetTokenFetcher(...) [unimplemented]"; 173 // Return null to indicate that third-party authentication is unsupported.
198 return scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>(); 174 return scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>();
199 } 175 }
200 176
201 void ChromotingJNIInstance::ConnectToHostOnDisplayThread() { 177 void ChromotingJNIInstance::ConnectToHostOnDisplayThread() {
202 DCHECK(disp_runner_->BelongsToCurrentThread()); 178 DCHECK(display_task_runner_->BelongsToCurrentThread());
203 179
204 if (!frames_.get()) { 180 if (!frame_consumer_.get()) {
205 frames_ = new FrameConsumerProxy(disp_runner_); 181 frame_consumer_ = new FrameConsumerProxy(display_task_runner_);
206 // TODO(solb) Instantiate some FrameConsumer implementation and attach it. 182 // TODO(solb) Instantiate some FrameConsumer implementation and attach it.
207 } 183 }
208 184
209 // We're a singleton, so Unretained is safe here. 185 // We're a singleton, so Unretained is safe here.
210 net_runner_->PostTask(FROM_HERE, base::Bind( 186 network_task_runner_->PostTask(FROM_HERE, base::Bind(
211 &ChromotingJNIInstance::ConnectToHostOnNetworkThread, 187 &ChromotingJNIInstance::ConnectToHostOnNetworkThread,
212 base::Unretained(this))); 188 base::Unretained(this)));
213 } 189 }
214 190
215 void ChromotingJNIInstance::ConnectToHostOnNetworkThread() { 191 void ChromotingJNIInstance::ConnectToHostOnNetworkThread() {
216 DCHECK(net_runner_->BelongsToCurrentThread()); 192 DCHECK(network_task_runner_->BelongsToCurrentThread());
217 193
218 client_config_.reset(new ClientConfig()); 194 client_config_.reset(new ClientConfig());
219 client_config_->host_jid = host_jid_cstr_; 195 client_config_->host_jid = host_jid_;
220 client_config_->host_public_key = host_pubkey_cstr_; 196 client_config_->host_public_key = host_pubkey_;
197
221 // We're a singleton, so Unretained is safe here. 198 // We're a singleton, so Unretained is safe here.
222 client_config_->fetch_secret_callback = base::Bind( 199 client_config_->fetch_secret_callback = base::Bind(
223 &ChromotingJNIInstance::FetchSecret, 200 &ChromotingJNIInstance::FetchSecret,
224 base::Unretained(this)); 201 base::Unretained(this));
225 client_config_->authentication_tag = host_id_cstr_; 202 client_config_->authentication_tag = host_id_;
226 203
227 // TODO(solb) Move these hardcoded values elsewhere: 204 // TODO(solb) Move these hardcoded values elsewhere:
228 client_config_->authentication_methods.push_back( 205 client_config_->authentication_methods.push_back(
229 protocol::AuthenticationMethod::FromString("spake2_pair")); 206 protocol::AuthenticationMethod::FromString("spake2_pair"));
Wez 2013/07/12 00:24:48 This object doesn't implement pairing, so don't as
solb 2013/07/12 01:14:22 Done.
230 client_config_->authentication_methods.push_back( 207 client_config_->authentication_methods.push_back(
231 protocol::AuthenticationMethod::FromString("spake2_hmac")); 208 protocol::AuthenticationMethod::FromString("spake2_hmac"));
232 client_config_->authentication_methods.push_back( 209 client_config_->authentication_methods.push_back(
233 protocol::AuthenticationMethod::FromString("spake2_plain")); 210 protocol::AuthenticationMethod::FromString("spake2_plain"));
234 211
235 client_context_.reset(new ClientContext(net_runner_.get())); 212 client_context_.reset(new ClientContext(network_task_runner_.get()));
236 client_context_->Start(); 213 client_context_->Start();
237 214
238 connection_.reset(new protocol::ConnectionToHost(true)); 215 connection_.reset(new protocol::ConnectionToHost(true));
239 216
240 client_.reset(new ChromotingClient(*client_config_, 217 client_.reset(new ChromotingClient(*client_config_,
241 client_context_.get(), 218 client_context_.get(),
242 connection_.get(), 219 connection_.get(),
243 this, 220 this,
244 frames_, 221 frame_consumer_,
245 scoped_ptr<AudioPlayer>())); 222 scoped_ptr<AudioPlayer>()));
246 223
247 chat_config_.reset(new XmppSignalStrategy::XmppServerConfig()); 224 signaling_config_.reset(new XmppSignalStrategy::XmppServerConfig());
248 chat_config_->host = CHAT_SERVER; 225 signaling_config_->host = CHAT_SERVER;
249 chat_config_->port = CHAT_PORT; 226 signaling_config_->port = CHAT_PORT;
250 chat_config_->use_tls = CHAT_USE_TLS; 227 signaling_config_->use_tls = CHAT_USE_TLS;
251 228
252 chat_.reset(new XmppSignalStrategy(url_requester_, 229 signaling_.reset(new XmppSignalStrategy(url_requester_,
253 username_cstr_, 230 username_,
254 auth_token_cstr_, 231 auth_token_,
255 CHAT_AUTH_METHOD, 232 CHAT_AUTH_METHOD,
256 *chat_config_)); 233 *signaling_config_));
257 234
258 netset_.reset(new NetworkSettings(NetworkSettings::NAT_TRAVERSAL_OUTGOING)); 235 network_settings_.reset(new NetworkSettings(
236 NetworkSettings::NAT_TRAVERSAL_OUTGOING));
259 scoped_ptr<protocol::TransportFactory> fact( 237 scoped_ptr<protocol::TransportFactory> fact(
260 protocol::LibjingleTransportFactory::Create(*netset_, url_requester_)); 238 protocol::LibjingleTransportFactory::Create(*network_settings_,
239 url_requester_));
261 240
262 client_->Start(chat_.get(), fact.Pass()); 241 client_->Start(signaling_.get(), fact.Pass());
263 } 242 }
264 243
265 void ChromotingJNIInstance::DisconnectFromHostOnNetworkThread() { 244 void ChromotingJNIInstance::DisconnectFromHostOnNetworkThread() {
266 DCHECK(net_runner_->BelongsToCurrentThread()); 245 DCHECK(network_task_runner_->BelongsToCurrentThread());
267 246
247 // |client_| must be torn down before |signaling_|.
268 client_.reset(); 248 client_.reset();
269 connection_.reset(); 249 connection_.reset();
270 client_context_.reset(); 250 client_context_.reset();
271 client_config_.reset(); 251 client_config_.reset();
272 chat_.reset(); // This object must outlive client_. 252 signaling_.reset();
273 chat_config_.reset(); // TODO(solb) Restructure to reuse between sessions. 253 signaling_config_.reset();
274 netset_.reset(); 254 network_settings_.reset();
275 } 255 }
276 256
277 } // namespace remoting 257 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698