| OLD | NEW |
| 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_runtime.h" | 5 #include "remoting/client/jni/chromoting_jni_runtime.h" |
| 6 | 6 |
| 7 #include "base/android/jni_android.h" | 7 #include "base/android/jni_android.h" |
| 8 #include "base/android/jni_array.h" | 8 #include "base/android/jni_array.h" |
| 9 #include "base/android/jni_string.h" | 9 #include "base/android/jni_string.h" |
| 10 #include "base/android/library_loader/library_loader_hooks.h" | 10 #include "base/android/library_loader/library_loader_hooks.h" |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 206 } | 206 } |
| 207 | 207 |
| 208 // ChromotingJniRuntime implementation. | 208 // ChromotingJniRuntime implementation. |
| 209 | 209 |
| 210 // static | 210 // static |
| 211 ChromotingJniRuntime* ChromotingJniRuntime::GetInstance() { | 211 ChromotingJniRuntime* ChromotingJniRuntime::GetInstance() { |
| 212 return base::Singleton<ChromotingJniRuntime>::get(); | 212 return base::Singleton<ChromotingJniRuntime>::get(); |
| 213 } | 213 } |
| 214 | 214 |
| 215 ChromotingJniRuntime::ChromotingJniRuntime() { | 215 ChromotingJniRuntime::ChromotingJniRuntime() { |
| 216 // On Android, the UI thread is managed by Java, so we need to attach and | 216 // Grab or create the threads. |
| 217 // start a special type of message loop to allow Chromium code to run tasks. | 217 // TODO(nicholss) We could runtime this as a constructor argument when jni |
| 218 ui_loop_.reset(new base::MessageLoopForUI()); | 218 // runtime is not no longer a singleton. |
| 219 ui_loop_->Start(); | |
| 220 | 219 |
| 221 // TODO(solb) Stop pretending to control the managed UI thread's lifetime. | 220 if (!base::MessageLoop::current()) { |
| 222 ui_task_runner_ = new AutoThreadTaskRunner( | 221 VLOG(1) << "Starting main message loop"; |
| 223 ui_loop_->task_runner(), base::MessageLoop::QuitWhenIdleClosure()); | 222 // On Android, the UI thread is managed by Java, so we need to attach and |
| 224 network_task_runner_ = AutoThread::CreateWithType("native_net", | 223 // start a special type of message loop to allow Chromium code to run tasks. |
| 225 ui_task_runner_, | 224 ui_loop_.reset(new base::MessageLoopForUI()); |
| 226 base::MessageLoop::TYPE_IO); | 225 ui_loop_->Start(); |
| 227 display_task_runner_ = AutoThread::Create("native_disp", | 226 } else { |
| 228 ui_task_runner_); | 227 VLOG(1) << "Using existing main message loop"; |
| 228 ui_loop_.reset(base::MessageLoopForUI::current()); |
| 229 } |
| 229 | 230 |
| 230 url_requester_ = | 231 // Pass the main ui loop already attached to be used for creating threads. |
| 231 new URLRequestContextGetter(network_task_runner_, network_task_runner_); | 232 runtime_ = ChromotingClientRuntime::Create(ui_loop_.get()); |
| 232 } | 233 } |
| 233 | 234 |
| 234 ChromotingJniRuntime::~ChromotingJniRuntime() { | 235 ChromotingJniRuntime::~ChromotingJniRuntime() { |
| 235 // The singleton should only ever be destroyed on the main thread. | 236 // The singleton should only ever be destroyed on the main thread. |
| 236 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 237 DCHECK(ui_task_runner()->BelongsToCurrentThread()); |
| 237 | 238 |
| 238 // The session must be shut down first, since it depends on our other | 239 // The session must be shut down first, since it depends on our other |
| 239 // components' still being alive. | 240 // components' still being alive. |
| 240 DisconnectFromHost(); | 241 DisconnectFromHost(); |
| 241 | 242 |
| 242 base::WaitableEvent done_event(false, false); | 243 base::WaitableEvent done_event(false, false); |
| 243 network_task_runner_->PostTask(FROM_HERE, base::Bind( | 244 network_task_runner()->PostTask( |
| 244 &ChromotingJniRuntime::DetachFromVmAndSignal, | 245 FROM_HERE, base::Bind(&ChromotingJniRuntime::DetachFromVmAndSignal, |
| 245 base::Unretained(this), | 246 base::Unretained(this), &done_event)); |
| 246 &done_event)); | |
| 247 done_event.Wait(); | 247 done_event.Wait(); |
| 248 display_task_runner_->PostTask(FROM_HERE, base::Bind( | 248 display_task_runner()->PostTask( |
| 249 &ChromotingJniRuntime::DetachFromVmAndSignal, | 249 FROM_HERE, base::Bind(&ChromotingJniRuntime::DetachFromVmAndSignal, |
| 250 base::Unretained(this), | 250 base::Unretained(this), &done_event)); |
| 251 &done_event)); | |
| 252 done_event.Wait(); | 251 done_event.Wait(); |
| 253 base::android::LibraryLoaderExitHook(); | 252 base::android::LibraryLoaderExitHook(); |
| 254 base::android::DetachFromVM(); | 253 base::android::DetachFromVM(); |
| 255 } | 254 } |
| 256 | 255 |
| 257 void ChromotingJniRuntime::ConnectToHost(const std::string& username, | 256 void ChromotingJniRuntime::ConnectToHost(const std::string& username, |
| 258 const std::string& auth_token, | 257 const std::string& auth_token, |
| 259 const std::string& host_jid, | 258 const std::string& host_jid, |
| 260 const std::string& host_id, | 259 const std::string& host_id, |
| 261 const std::string& host_pubkey, | 260 const std::string& host_pubkey, |
| 262 const std::string& pairing_id, | 261 const std::string& pairing_id, |
| 263 const std::string& pairing_secret, | 262 const std::string& pairing_secret, |
| 264 const std::string& capabilities, | 263 const std::string& capabilities, |
| 265 const std::string& flags) { | 264 const std::string& flags) { |
| 266 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 265 DCHECK(ui_task_runner()->BelongsToCurrentThread()); |
| 267 DCHECK(!session_.get()); | 266 DCHECK(!session_.get()); |
| 268 session_ = new ChromotingJniInstance(this, username, auth_token, host_jid, | 267 session_ = new ChromotingJniInstance(this, username, auth_token, host_jid, |
| 269 host_id, host_pubkey, pairing_id, | 268 host_id, host_pubkey, pairing_id, |
| 270 pairing_secret, capabilities, flags); | 269 pairing_secret, capabilities, flags); |
| 271 } | 270 } |
| 272 | 271 |
| 273 void ChromotingJniRuntime::DisconnectFromHost() { | 272 void ChromotingJniRuntime::DisconnectFromHost() { |
| 274 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 273 DCHECK(ui_task_runner()->BelongsToCurrentThread()); |
| 275 if (session_.get()) { | 274 if (session_.get()) { |
| 276 session_->Disconnect(); | 275 session_->Disconnect(); |
| 277 session_ = nullptr; | 276 session_ = nullptr; |
| 278 } | 277 } |
| 279 } | 278 } |
| 280 | 279 |
| 281 void ChromotingJniRuntime::OnConnectionState( | 280 void ChromotingJniRuntime::OnConnectionState( |
| 282 protocol::ConnectionToHost::State state, | 281 protocol::ConnectionToHost::State state, |
| 283 protocol::ErrorCode error) { | 282 protocol::ErrorCode error) { |
| 284 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 283 DCHECK(ui_task_runner()->BelongsToCurrentThread()); |
| 285 | 284 |
| 286 JNIEnv* env = base::android::AttachCurrentThread(); | 285 JNIEnv* env = base::android::AttachCurrentThread(); |
| 287 Java_JniInterface_onConnectionState(env, state, error); | 286 Java_JniInterface_onConnectionState(env, state, error); |
| 288 } | 287 } |
| 289 | 288 |
| 290 void ChromotingJniRuntime::DisplayAuthenticationPrompt(bool pairing_supported) { | 289 void ChromotingJniRuntime::DisplayAuthenticationPrompt(bool pairing_supported) { |
| 291 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 290 DCHECK(ui_task_runner()->BelongsToCurrentThread()); |
| 292 | 291 |
| 293 JNIEnv* env = base::android::AttachCurrentThread(); | 292 JNIEnv* env = base::android::AttachCurrentThread(); |
| 294 Java_JniInterface_displayAuthenticationPrompt(env, pairing_supported); | 293 Java_JniInterface_displayAuthenticationPrompt(env, pairing_supported); |
| 295 } | 294 } |
| 296 | 295 |
| 297 void ChromotingJniRuntime::CommitPairingCredentials(const std::string& host, | 296 void ChromotingJniRuntime::CommitPairingCredentials(const std::string& host, |
| 298 const std::string& id, | 297 const std::string& id, |
| 299 const std::string& secret) { | 298 const std::string& secret) { |
| 300 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 299 DCHECK(ui_task_runner()->BelongsToCurrentThread()); |
| 301 | 300 |
| 302 JNIEnv* env = base::android::AttachCurrentThread(); | 301 JNIEnv* env = base::android::AttachCurrentThread(); |
| 303 ScopedJavaLocalRef<jstring> j_host = ConvertUTF8ToJavaString(env, host); | 302 ScopedJavaLocalRef<jstring> j_host = ConvertUTF8ToJavaString(env, host); |
| 304 ScopedJavaLocalRef<jstring> j_id = ConvertUTF8ToJavaString(env, id); | 303 ScopedJavaLocalRef<jstring> j_id = ConvertUTF8ToJavaString(env, id); |
| 305 ScopedJavaLocalRef<jstring> j_secret = ConvertUTF8ToJavaString(env,secret); | 304 ScopedJavaLocalRef<jstring> j_secret = ConvertUTF8ToJavaString(env,secret); |
| 306 | 305 |
| 307 Java_JniInterface_commitPairingCredentials( | 306 Java_JniInterface_commitPairingCredentials( |
| 308 env, j_host.obj(), j_id.obj(), j_secret.obj()); | 307 env, j_host.obj(), j_id.obj(), j_secret.obj()); |
| 309 } | 308 } |
| 310 | 309 |
| 311 void ChromotingJniRuntime::FetchThirdPartyToken(const GURL& token_url, | 310 void ChromotingJniRuntime::FetchThirdPartyToken(const GURL& token_url, |
| 312 const std::string& client_id, | 311 const std::string& client_id, |
| 313 const std::string& scope) { | 312 const std::string& scope) { |
| 314 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 313 DCHECK(ui_task_runner()->BelongsToCurrentThread()); |
| 315 JNIEnv* env = base::android::AttachCurrentThread(); | 314 JNIEnv* env = base::android::AttachCurrentThread(); |
| 316 | 315 |
| 317 ScopedJavaLocalRef<jstring> j_url = | 316 ScopedJavaLocalRef<jstring> j_url = |
| 318 ConvertUTF8ToJavaString(env, token_url.spec()); | 317 ConvertUTF8ToJavaString(env, token_url.spec()); |
| 319 ScopedJavaLocalRef<jstring> j_client_id = | 318 ScopedJavaLocalRef<jstring> j_client_id = |
| 320 ConvertUTF8ToJavaString(env, client_id); | 319 ConvertUTF8ToJavaString(env, client_id); |
| 321 ScopedJavaLocalRef<jstring> j_scope = ConvertUTF8ToJavaString(env, scope); | 320 ScopedJavaLocalRef<jstring> j_scope = ConvertUTF8ToJavaString(env, scope); |
| 322 | 321 |
| 323 Java_JniInterface_fetchThirdPartyToken( | 322 Java_JniInterface_fetchThirdPartyToken( |
| 324 env, j_url.obj(), j_client_id.obj(), j_scope.obj()); | 323 env, j_url.obj(), j_client_id.obj(), j_scope.obj()); |
| 325 } | 324 } |
| 326 | 325 |
| 327 void ChromotingJniRuntime::SetCapabilities(const std::string& capabilities) { | 326 void ChromotingJniRuntime::SetCapabilities(const std::string& capabilities) { |
| 328 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 327 DCHECK(ui_task_runner()->BelongsToCurrentThread()); |
| 329 JNIEnv* env = base::android::AttachCurrentThread(); | 328 JNIEnv* env = base::android::AttachCurrentThread(); |
| 330 | 329 |
| 331 ScopedJavaLocalRef<jstring> j_cap = | 330 ScopedJavaLocalRef<jstring> j_cap = |
| 332 ConvertUTF8ToJavaString(env, capabilities); | 331 ConvertUTF8ToJavaString(env, capabilities); |
| 333 | 332 |
| 334 Java_JniInterface_setCapabilities(env, j_cap.obj()); | 333 Java_JniInterface_setCapabilities(env, j_cap.obj()); |
| 335 } | 334 } |
| 336 | 335 |
| 337 void ChromotingJniRuntime::HandleExtensionMessage(const std::string& type, | 336 void ChromotingJniRuntime::HandleExtensionMessage(const std::string& type, |
| 338 const std::string& message) { | 337 const std::string& message) { |
| 339 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 338 DCHECK(ui_task_runner()->BelongsToCurrentThread()); |
| 340 JNIEnv* env = base::android::AttachCurrentThread(); | 339 JNIEnv* env = base::android::AttachCurrentThread(); |
| 341 | 340 |
| 342 ScopedJavaLocalRef<jstring> j_type = ConvertUTF8ToJavaString(env, type); | 341 ScopedJavaLocalRef<jstring> j_type = ConvertUTF8ToJavaString(env, type); |
| 343 ScopedJavaLocalRef<jstring> j_message = ConvertUTF8ToJavaString(env, message); | 342 ScopedJavaLocalRef<jstring> j_message = ConvertUTF8ToJavaString(env, message); |
| 344 | 343 |
| 345 Java_JniInterface_handleExtensionMessage(env, j_type.obj(), j_message.obj()); | 344 Java_JniInterface_handleExtensionMessage(env, j_type.obj(), j_message.obj()); |
| 346 } | 345 } |
| 347 | 346 |
| 348 base::android::ScopedJavaLocalRef<jobject> ChromotingJniRuntime::NewBitmap( | 347 base::android::ScopedJavaLocalRef<jobject> ChromotingJniRuntime::NewBitmap( |
| 349 int width, int height) { | 348 int width, int height) { |
| 350 JNIEnv* env = base::android::AttachCurrentThread(); | 349 JNIEnv* env = base::android::AttachCurrentThread(); |
| 351 return Java_JniInterface_newBitmap(env, width, height); | 350 return Java_JniInterface_newBitmap(env, width, height); |
| 352 } | 351 } |
| 353 | 352 |
| 354 void ChromotingJniRuntime::UpdateFrameBitmap(jobject bitmap) { | 353 void ChromotingJniRuntime::UpdateFrameBitmap(jobject bitmap) { |
| 355 DCHECK(display_task_runner_->BelongsToCurrentThread()); | 354 DCHECK(display_task_runner()->BelongsToCurrentThread()); |
| 356 | 355 |
| 357 JNIEnv* env = base::android::AttachCurrentThread(); | 356 JNIEnv* env = base::android::AttachCurrentThread(); |
| 358 Java_JniInterface_setVideoFrame(env, bitmap); | 357 Java_JniInterface_setVideoFrame(env, bitmap); |
| 359 } | 358 } |
| 360 | 359 |
| 361 void ChromotingJniRuntime::UpdateCursorShape( | 360 void ChromotingJniRuntime::UpdateCursorShape( |
| 362 const protocol::CursorShapeInfo& cursor_shape) { | 361 const protocol::CursorShapeInfo& cursor_shape) { |
| 363 DCHECK(display_task_runner_->BelongsToCurrentThread()); | 362 DCHECK(display_task_runner()->BelongsToCurrentThread()); |
| 364 | 363 |
| 365 // const_cast<> is safe as long as the Java updateCursorShape() method copies | 364 // const_cast<> is safe as long as the Java updateCursorShape() method copies |
| 366 // the data out of the buffer without mutating it, and doesn't keep any | 365 // the data out of the buffer without mutating it, and doesn't keep any |
| 367 // reference to the buffer afterwards. Unfortunately, there seems to be no way | 366 // reference to the buffer afterwards. Unfortunately, there seems to be no way |
| 368 // to create a read-only ByteBuffer from a pointer-to-const. | 367 // to create a read-only ByteBuffer from a pointer-to-const. |
| 369 char* data = string_as_array(const_cast<std::string*>(&cursor_shape.data())); | 368 char* data = string_as_array(const_cast<std::string*>(&cursor_shape.data())); |
| 370 int cursor_total_bytes = | 369 int cursor_total_bytes = |
| 371 cursor_shape.width() * cursor_shape.height() * kBytesPerPixel; | 370 cursor_shape.width() * cursor_shape.height() * kBytesPerPixel; |
| 372 | 371 |
| 373 JNIEnv* env = base::android::AttachCurrentThread(); | 372 JNIEnv* env = base::android::AttachCurrentThread(); |
| 374 base::android::ScopedJavaLocalRef<jobject> buffer(env, | 373 base::android::ScopedJavaLocalRef<jobject> buffer(env, |
| 375 env->NewDirectByteBuffer(data, cursor_total_bytes)); | 374 env->NewDirectByteBuffer(data, cursor_total_bytes)); |
| 376 Java_JniInterface_updateCursorShape(env, | 375 Java_JniInterface_updateCursorShape(env, |
| 377 cursor_shape.width(), | 376 cursor_shape.width(), |
| 378 cursor_shape.height(), | 377 cursor_shape.height(), |
| 379 cursor_shape.hotspot_x(), | 378 cursor_shape.hotspot_x(), |
| 380 cursor_shape.hotspot_y(), | 379 cursor_shape.hotspot_y(), |
| 381 buffer.obj()); | 380 buffer.obj()); |
| 382 } | 381 } |
| 383 | 382 |
| 384 void ChromotingJniRuntime::RedrawCanvas() { | 383 void ChromotingJniRuntime::RedrawCanvas() { |
| 385 DCHECK(display_task_runner_->BelongsToCurrentThread()); | 384 DCHECK(display_task_runner()->BelongsToCurrentThread()); |
| 386 | 385 |
| 387 JNIEnv* env = base::android::AttachCurrentThread(); | 386 JNIEnv* env = base::android::AttachCurrentThread(); |
| 388 Java_JniInterface_redrawGraphicsInternal(env); | 387 Java_JniInterface_redrawGraphicsInternal(env); |
| 389 } | 388 } |
| 390 | 389 |
| 391 void ChromotingJniRuntime::DetachFromVmAndSignal(base::WaitableEvent* waiter) { | 390 void ChromotingJniRuntime::DetachFromVmAndSignal(base::WaitableEvent* waiter) { |
| 392 base::android::DetachFromVM(); | 391 base::android::DetachFromVM(); |
| 393 waiter->Signal(); | 392 waiter->Signal(); |
| 394 } | 393 } |
| 395 } // namespace remoting | 394 } // namespace remoting |
| OLD | NEW |