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

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: Documentation and guards against using variables on the wrong thread 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
« no previous file with comments | « remoting/client/jni/chromoting_jni_instance.h ('k') | remoting/client/jni/jni_interface.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 // TODO(solb) Stop pretending to control the managed UI thread's lifetime.
44 base::MessageLoop::QuitClosure()); 43 ui_task_runner_ = new AutoThreadTaskRunner(ui_loop_->message_loop_proxy(),
45 net_runner_ = AutoThread::CreateWithType("native_net", 44 base::MessageLoop::QuitClosure());
46 ui_runner_, 45 network_task_runner_ = AutoThread::CreateWithType("native_net",
47 base::MessageLoop::TYPE_IO); 46 ui_task_runner_,
48 disp_runner_ = AutoThread::CreateWithType("native_disp", 47 base::MessageLoop::TYPE_IO);
49 ui_runner_, 48 display_task_runner_ = AutoThread::Create("native_disp",
50 base::MessageLoop::TYPE_DEFAULT); 49 ui_task_runner_);
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(ui_task_runner_->BelongsToCurrentThread());
59 DCHECK(!connected_);
60
58 JNIEnv* env = base::android::AttachCurrentThread(); 61 JNIEnv* env = base::android::AttachCurrentThread();
59 env->DeleteGlobalRef(class_); 62 env->DeleteGlobalRef(class_);
60 // TODO(solb) detach all threads from JVM 63 // TODO(solb): crbug.com/259594 Detach all threads from JVM here.
61 } 64 }
62 65
63 void ChromotingJNIInstance::ConnectToHost(jstring username, 66 void ChromotingJNIInstance::ConnectToHost(const char* username,
64 jstring auth_token, 67 const char* auth_token,
65 jstring host_jid, 68 const char* host_jid,
66 jstring host_id, 69 const char* host_id,
67 jstring host_pubkey) { 70 const char* host_pubkey) {
68 JNIEnv* env = base::android::AttachCurrentThread(); 71 DCHECK(ui_task_runner_->BelongsToCurrentThread());
72 DCHECK(!connected_);
73 connected_ = true;
69 74
70 username_jstr_ = static_cast<jstring>(env->NewGlobalRef(username)); 75 username_ = username;
71 auth_token_jstr_ = static_cast<jstring>(env->NewGlobalRef(auth_token)); 76 auth_token_ = auth_token;
72 host_jid_jstr_ = static_cast<jstring>(env->NewGlobalRef(host_jid)); 77 host_jid_ = host_jid;
73 host_id_jstr_ = static_cast<jstring>(env->NewGlobalRef(host_id)); 78 host_id_ = host_id;
74 host_pubkey_jstr_ = static_cast<jstring>(env->NewGlobalRef(host_pubkey)); 79 host_pubkey_ = host_pubkey;
75 80
76 username_cstr_ = env->GetStringUTFChars(username_jstr_, NULL); 81 display_task_runner_->PostTask(FROM_HERE, base::Bind(
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
82 // We're a singleton, so Unretained is safe here.
83 disp_runner_->PostTask(FROM_HERE, base::Bind(
84 &ChromotingJNIInstance::ConnectToHostOnDisplayThread, 82 &ChromotingJNIInstance::ConnectToHostOnDisplayThread,
85 base::Unretained(this))); 83 base::Unretained(this)));
86 } 84 }
87 85
88 void ChromotingJNIInstance::DisconnectFromHost() { 86 void ChromotingJNIInstance::DisconnectFromHost() {
89 JNIEnv* env = base::android::AttachCurrentThread(); 87 DCHECK(ui_task_runner_->BelongsToCurrentThread());
88 DCHECK(connected_);
89 connected_ = false;
90 90
91 env->ReleaseStringUTFChars(username_jstr_, username_cstr_); 91 network_task_runner_->PostTask(FROM_HERE, base::Bind(
92 env->ReleaseStringUTFChars(auth_token_jstr_, auth_token_cstr_);
93 env->ReleaseStringUTFChars(host_jid_jstr_, host_jid_cstr_);
94 env->ReleaseStringUTFChars(host_id_jstr_, host_id_cstr_);
95 env->ReleaseStringUTFChars(host_pubkey_jstr_, host_pubkey_cstr_);
96
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
116 // We're a singleton, so Unretained is safe here.
117 net_runner_->PostTask(FROM_HERE, base::Bind(
118 &ChromotingJNIInstance::DisconnectFromHostOnNetworkThread, 92 &ChromotingJNIInstance::DisconnectFromHostOnNetworkThread,
119 base::Unretained(this))); 93 base::Unretained(this)));
120 } 94 }
121 95
122 void ChromotingJNIInstance::AuthenticateWithPin(jstring pin) { 96 void ChromotingJNIInstance::ProvideSecret(const char* pin) {
123 JNIEnv* env = base::android::AttachCurrentThread(); 97 DCHECK(ui_task_runner_->BelongsToCurrentThread());
98 DCHECK(!pin_callback_.is_null());
124 99
125 pin_jstr_ = static_cast<jstring>(env->NewGlobalRef(pin)); 100 // We invoke the string constructor to ensure |pin| gets copied *before* the
126 pin_cstr_ = env->GetStringUTFChars(pin_jstr_, NULL); 101 // asynchronous run, since Java might want it back as soon as we return.
Wez 2013/07/12 22:48:22 No need for that; base::Bind() has to copy it anyw
solb 2013/07/12 23:54:22 I'll do this in the next CL so that this lands tod
127 102 network_task_runner_->PostTask(FROM_HERE,
128 net_runner_->PostTask(FROM_HERE, base::Bind(announce_secret_, pin_cstr_)); 103 base::Bind(pin_callback_, std::string(pin)));
129 }
130
131 void ChromotingJNIInstance::FetchSecret(
132 bool pairable,
133 const protocol::SecretFetchedCallback& callback_encore) {
134 // All our work must be done on the UI thread.
135 if (!ui_runner_->BelongsToCurrentThread()) {
136 // We're a singleton, so Unretained is safe here.
137 ui_runner_->PostTask(FROM_HERE, base::Bind(
138 &ChromotingJNIInstance::FetchSecret,
139 base::Unretained(this),
140 pairable,
141 callback_encore));
142 return;
143 }
144
145 announce_secret_ = callback_encore;
146 JNIEnv* env = base::android::AttachCurrentThread();
147 env->CallStaticVoidMethod(
148 class_,
149 env->GetStaticMethodID(class_, "displayAuthenticationPrompt", "()V"));
150 } 104 }
151 105
152 void ChromotingJNIInstance::OnConnectionState( 106 void ChromotingJNIInstance::OnConnectionState(
153 protocol::ConnectionToHost::State state, 107 protocol::ConnectionToHost::State state,
154 protocol::ErrorCode error) { 108 protocol::ErrorCode error) {
155 // All our work must be done on the UI thread. 109 if (!ui_task_runner_->BelongsToCurrentThread()) {
156 if (!ui_runner_->BelongsToCurrentThread()) { 110 ui_task_runner_->PostTask(FROM_HERE, base::Bind(
157 // We're a singleton, so Unretained is safe here.
158 ui_runner_->PostTask(FROM_HERE, base::Bind(
159 &ChromotingJNIInstance::OnConnectionState, 111 &ChromotingJNIInstance::OnConnectionState,
160 base::Unretained(this), 112 base::Unretained(this),
161 state, 113 state,
162 error)); 114 error));
163 return; 115 return;
164 } 116 }
165 117
166 JNIEnv* env = base::android::AttachCurrentThread(); 118 JNIEnv* env = base::android::AttachCurrentThread();
167 env->CallStaticVoidMethod( 119 env->CallStaticVoidMethod(
168 class_, 120 class_,
169 env->GetStaticMethodID(class_, "reportConnectionStatus", "(II)V"), 121 env->GetStaticMethodID(class_, "reportConnectionStatus", "(II)V"),
170 state, 122 state,
171 error); 123 error);
172 } 124 }
173 125
174 void ChromotingJNIInstance::OnConnectionReady(bool ready) { 126 void ChromotingJNIInstance::OnConnectionReady(bool ready) {
127 // We ignore this message, since OnConnectionState() tells us the same thing.
175 } 128 }
176 129
177 void ChromotingJNIInstance::SetCapabilities(const std::string& capabilities) {} 130 void ChromotingJNIInstance::SetCapabilities(const std::string& capabilities) {}
178 131
179 void ChromotingJNIInstance::SetPairingResponse( 132 void ChromotingJNIInstance::SetPairingResponse(
180 const protocol::PairingResponse& response) {} 133 const protocol::PairingResponse& response) {
134 NOTIMPLEMENTED();
135 }
181 136
182 protocol::ClipboardStub* ChromotingJNIInstance::GetClipboardStub() { 137 protocol::ClipboardStub* ChromotingJNIInstance::GetClipboardStub() {
183 NOTIMPLEMENTED(); 138 NOTIMPLEMENTED();
184 return NULL; 139 return NULL;
185 } 140 }
186 141
187 protocol::CursorShapeStub* ChromotingJNIInstance::GetCursorShapeStub() { 142 protocol::CursorShapeStub* ChromotingJNIInstance::GetCursorShapeStub() {
188 NOTIMPLEMENTED(); 143 NOTIMPLEMENTED();
189 return NULL; 144 return NULL;
190 } 145 }
191 146
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> 147 scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>
196 ChromotingJNIInstance::GetTokenFetcher(const std::string& host_public_key) { 148 ChromotingJNIInstance::GetTokenFetcher(const std::string& host_public_key) {
197 LOG(INFO) << "ChromotingJNIInstance::GetTokenFetcher(...) [unimplemented]"; 149 // Return null to indicate that third-party authentication is unsupported.
198 return scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>(); 150 return scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>();
199 } 151 }
200 152
201 void ChromotingJNIInstance::ConnectToHostOnDisplayThread() { 153 void ChromotingJNIInstance::ConnectToHostOnDisplayThread() {
202 DCHECK(disp_runner_->BelongsToCurrentThread()); 154 DCHECK(display_task_runner_->BelongsToCurrentThread());
203 155
204 if (!frames_.get()) { 156 if (!frame_consumer_.get()) {
205 frames_ = new FrameConsumerProxy(disp_runner_); 157 frame_consumer_ = new FrameConsumerProxy(display_task_runner_);
206 // TODO(solb) Instantiate some FrameConsumer implementation and attach it. 158 // TODO(solb) Instantiate some FrameConsumer implementation and attach it.
207 } 159 }
208 160
209 // We're a singleton, so Unretained is safe here. 161 network_task_runner_->PostTask(FROM_HERE, base::Bind(
210 net_runner_->PostTask(FROM_HERE, base::Bind(
211 &ChromotingJNIInstance::ConnectToHostOnNetworkThread, 162 &ChromotingJNIInstance::ConnectToHostOnNetworkThread,
212 base::Unretained(this))); 163 base::Unretained(this)));
213 } 164 }
214 165
215 void ChromotingJNIInstance::ConnectToHostOnNetworkThread() { 166 void ChromotingJNIInstance::ConnectToHostOnNetworkThread() {
216 DCHECK(net_runner_->BelongsToCurrentThread()); 167 DCHECK(network_task_runner_->BelongsToCurrentThread());
217 168
218 client_config_.reset(new ClientConfig()); 169 client_config_.reset(new ClientConfig());
219 client_config_->host_jid = host_jid_cstr_; 170 client_config_->host_jid = host_jid_;
220 client_config_->host_public_key = host_pubkey_cstr_; 171 client_config_->host_public_key = host_pubkey_;
221 // We're a singleton, so Unretained is safe here. 172
222 client_config_->fetch_secret_callback = base::Bind( 173 client_config_->fetch_secret_callback = base::Bind(
223 &ChromotingJNIInstance::FetchSecret, 174 &ChromotingJNIInstance::FetchSecret,
224 base::Unretained(this)); 175 base::Unretained(this));
225 client_config_->authentication_tag = host_id_cstr_; 176 client_config_->authentication_tag = host_id_;
226 177
227 // TODO(solb) Move these hardcoded values elsewhere: 178 // TODO(solb) Move these hardcoded values elsewhere:
228 client_config_->authentication_methods.push_back( 179 client_config_->authentication_methods.push_back(
229 protocol::AuthenticationMethod::FromString("spake2_pair"));
230 client_config_->authentication_methods.push_back(
231 protocol::AuthenticationMethod::FromString("spake2_hmac")); 180 protocol::AuthenticationMethod::FromString("spake2_hmac"));
232 client_config_->authentication_methods.push_back( 181 client_config_->authentication_methods.push_back(
233 protocol::AuthenticationMethod::FromString("spake2_plain")); 182 protocol::AuthenticationMethod::FromString("spake2_plain"));
234 183
235 client_context_.reset(new ClientContext(net_runner_.get())); 184 client_context_.reset(new ClientContext(network_task_runner_.get()));
236 client_context_->Start(); 185 client_context_->Start();
237 186
238 connection_.reset(new protocol::ConnectionToHost(true)); 187 connection_.reset(new protocol::ConnectionToHost(true));
239 188
240 client_.reset(new ChromotingClient(*client_config_, 189 client_.reset(new ChromotingClient(*client_config_,
241 client_context_.get(), 190 client_context_.get(),
242 connection_.get(), 191 connection_.get(),
243 this, 192 this,
244 frames_, 193 frame_consumer_,
245 scoped_ptr<AudioPlayer>())); 194 scoped_ptr<AudioPlayer>()));
246 195
247 chat_config_.reset(new XmppSignalStrategy::XmppServerConfig()); 196 signaling_config_.reset(new XmppSignalStrategy::XmppServerConfig());
248 chat_config_->host = CHAT_SERVER; 197 signaling_config_->host = CHAT_SERVER;
249 chat_config_->port = CHAT_PORT; 198 signaling_config_->port = CHAT_PORT;
250 chat_config_->use_tls = CHAT_USE_TLS; 199 signaling_config_->use_tls = CHAT_USE_TLS;
251 200
252 chat_.reset(new XmppSignalStrategy(url_requester_, 201 signaling_.reset(new XmppSignalStrategy(url_requester_,
253 username_cstr_, 202 username_,
254 auth_token_cstr_, 203 auth_token_,
255 CHAT_AUTH_METHOD, 204 CHAT_AUTH_METHOD,
256 *chat_config_)); 205 *signaling_config_));
257 206
258 netset_.reset(new NetworkSettings(NetworkSettings::NAT_TRAVERSAL_OUTGOING)); 207 network_settings_.reset(new NetworkSettings(
208 NetworkSettings::NAT_TRAVERSAL_OUTGOING));
259 scoped_ptr<protocol::TransportFactory> fact( 209 scoped_ptr<protocol::TransportFactory> fact(
260 protocol::LibjingleTransportFactory::Create(*netset_, url_requester_)); 210 protocol::LibjingleTransportFactory::Create(*network_settings_,
211 url_requester_));
261 212
262 client_->Start(chat_.get(), fact.Pass()); 213 client_->Start(signaling_.get(), fact.Pass());
263 } 214 }
264 215
265 void ChromotingJNIInstance::DisconnectFromHostOnNetworkThread() { 216 void ChromotingJNIInstance::DisconnectFromHostOnNetworkThread() {
266 DCHECK(net_runner_->BelongsToCurrentThread()); 217 DCHECK(network_task_runner_->BelongsToCurrentThread());
267 218
219 username_ = "";
220 auth_token_ = "";
221 host_jid_ = "";
222 host_id_ = "";
223 host_pubkey_ = "";
224
225 // |client_| must be torn down before |signaling_|.
226 pin_callback_.Reset();
268 client_.reset(); 227 client_.reset();
269 connection_.reset(); 228 connection_.reset();
270 client_context_.reset(); 229 client_context_.reset();
271 client_config_.reset(); 230 client_config_.reset();
272 chat_.reset(); // This object must outlive client_. 231 signaling_.reset();
273 chat_config_.reset(); // TODO(solb) Restructure to reuse between sessions. 232 signaling_config_.reset();
274 netset_.reset(); 233 network_settings_.reset();
234 }
235
236 void ChromotingJNIInstance::FetchSecret(
237 bool pairable,
238 const protocol::SecretFetchedCallback& callback) {
239 if (!ui_task_runner_->BelongsToCurrentThread()) {
240 ui_task_runner_->PostTask(FROM_HERE, base::Bind(
241 &ChromotingJNIInstance::FetchSecret,
242 base::Unretained(this),
243 pairable,
244 callback));
245 return;
246 }
247
248 pin_callback_ = callback;
249 JNIEnv* env = base::android::AttachCurrentThread();
250 env->CallStaticVoidMethod(
251 class_,
252 env->GetStaticMethodID(class_, "displayAuthenticationPrompt", "()V"));
275 } 253 }
276 254
277 } // namespace remoting 255 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/client/jni/chromoting_jni_instance.h ('k') | remoting/client/jni/jni_interface.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698