From b34c0f6877af54e8bdd6052bf8934dd46a3b5899 Mon Sep 17 00:00:00 2001 From: nicholss Date: Mon, 14 Mar 2016 08:41:03 -0700 Subject: Adding container class for chromoting client runtimes. R=lambroslambrou@chromium.org Review URL: https://codereview.chromium.org/1764503002 Cr-Commit-Position: refs/heads/master@{#380979} --- remoting/client/BUILD.gn | 5 ++ remoting/client/chromoting_client_runtime.cc | 53 +++++++++++++ remoting/client/chromoting_client_runtime.h | 88 ++++++++++++++++++++++ .../client/chromoting_client_runtime_unittest.cc | 39 ++++++++++ remoting/client/jni/chromoting_jni_runtime.cc | 69 +++++++++-------- remoting/client/jni/chromoting_jni_runtime.h | 21 +++--- remoting/remoting_client.gypi | 1 + remoting/remoting_srcs.gypi | 5 ++ remoting/remoting_test.gypi | 1 + 9 files changed, 236 insertions(+), 46 deletions(-) create mode 100644 remoting/client/chromoting_client_runtime.cc create mode 100644 remoting/client/chromoting_client_runtime.h create mode 100644 remoting/client/chromoting_client_runtime_unittest.cc (limited to 'remoting') diff --git a/remoting/client/BUILD.gn b/remoting/client/BUILD.gn index a3cc1b1..7d96c30 100644 --- a/remoting/client/BUILD.gn +++ b/remoting/client/BUILD.gn @@ -31,6 +31,11 @@ source_set("client") { "client_status_logger.cc", "server_log_entry_client.cc", ] + } else { + sources += rebase_path( + remoting_srcs_gypi_values.remoting_client_standalone_sources, + ".", + "//remoting") } } diff --git a/remoting/client/chromoting_client_runtime.cc b/remoting/client/chromoting_client_runtime.cc new file mode 100644 index 0000000..9cb67a6 --- /dev/null +++ b/remoting/client/chromoting_client_runtime.cc @@ -0,0 +1,53 @@ +// Copyright 2016 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/chromoting_client_runtime.h" + +#include "base/bind.h" +#include "base/logging.h" +#include "base/message_loop/message_loop.h" +#include "remoting/base/url_request_context_getter.h" + +namespace remoting { + +scoped_ptr ChromotingClientRuntime::Create( + base::MessageLoopForUI* ui_loop) { + DCHECK(ui_loop); + + // |ui_loop_| runs on the main thread, so |ui_task_runner_| will run on the + // main thread. We can not kill the main thread when the message loop becomes + // idle so the callback function does nothing (as opposed to the typical + // base::MessageLoop::QuitClosure()) + scoped_refptr ui_task_runner = new AutoThreadTaskRunner( + ui_loop->task_runner(), base::Bind(&base::DoNothing)); + + scoped_refptr display_task_runner = + AutoThread::Create("native_disp", ui_task_runner); + scoped_refptr network_task_runner = + AutoThread::CreateWithType("native_net", ui_task_runner, + base::MessageLoop::TYPE_IO); + scoped_refptr file_task_runner = + AutoThread::CreateWithType("native_file", ui_task_runner, + base::MessageLoop::TYPE_IO); + scoped_refptr url_requester = + new URLRequestContextGetter(network_task_runner, file_task_runner); + + return make_scoped_ptr( + new ChromotingClientRuntime(display_task_runner, network_task_runner, + file_task_runner, url_requester)); +} + +ChromotingClientRuntime::ChromotingClientRuntime( + scoped_refptr display_task_runner, + scoped_refptr network_task_runner, + scoped_refptr file_task_runner, + scoped_refptr url_requester) + : display_task_runner_(display_task_runner), + network_task_runner_(network_task_runner), + file_task_runner_(file_task_runner), + url_requester_(url_requester) {} + +ChromotingClientRuntime::~ChromotingClientRuntime() {} + +} // namespace remoting diff --git a/remoting/client/chromoting_client_runtime.h b/remoting/client/chromoting_client_runtime.h new file mode 100644 index 0000000..10268d1 --- /dev/null +++ b/remoting/client/chromoting_client_runtime.h @@ -0,0 +1,88 @@ +// Copyright 2016 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_CHROMOTING_CLIENT_RUNTIME_H_ +#define REMOTING_CLIENT_CHROMOTING_CLIENT_RUNTIME_H_ + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "net/url_request/url_request_context_getter.h" +#include "remoting/base/auto_thread.h" + +namespace base { +class MessageLoopForUI; +} // namespace base + +// Houses the global resources on which the Chromoting components run +// (e.g. message loops and task runners). +namespace remoting { + +class ChromotingClientRuntime { + public: + // Caller to create is responsible for creating and attaching a new ui thread + // for use. Example: + // + // 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. + // + // base::MessageLoopForUI *ui_loop = new base::MessageLoopForUI(); + // ui_loop_->Start(); + // scoped_ptr runtime = + // ChromotingClientRuntime::Create(ui_loop); + // + // On iOS we created a new message loop and now attach it. + // + // base::MessageLoopForUI *ui_loop = new base::MessageLoopForUI(); + // ui_loop_->Attach(); + // scoped_ptr runtime = + // ChromotingClientRuntime::Create(ui_loop); + // + static scoped_ptr Create( + base::MessageLoopForUI* ui_loop); + + ~ChromotingClientRuntime(); + + scoped_refptr network_task_runner() { + return network_task_runner_; + } + + scoped_refptr ui_task_runner() { + return ui_task_runner_; + } + + scoped_refptr display_task_runner() { + return display_task_runner_; + } + + scoped_refptr file_task_runner() { + return file_task_runner_; + } + + scoped_refptr url_requester() { + return url_requester_; + } + + private: + ChromotingClientRuntime(); + ChromotingClientRuntime( + scoped_refptr display_task_runner, + scoped_refptr network_task_runner, + scoped_refptr file_task_runner, + scoped_refptr url_requester); + + // References to native threads. + scoped_refptr ui_task_runner_; + + scoped_refptr display_task_runner_; + scoped_refptr network_task_runner_; + scoped_refptr file_task_runner_; + + scoped_refptr url_requester_; + + DISALLOW_COPY_AND_ASSIGN(ChromotingClientRuntime); +}; + +} // namespace remoting + +#endif // REMOTING_CLIENT_CHROMOTING_CLIENT_RUNTIME_H_ diff --git a/remoting/client/chromoting_client_runtime_unittest.cc b/remoting/client/chromoting_client_runtime_unittest.cc new file mode 100644 index 0000000..89a0f54 --- /dev/null +++ b/remoting/client/chromoting_client_runtime_unittest.cc @@ -0,0 +1,39 @@ +// Copyright (c) 2016 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 "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "remoting/base/auto_thread_task_runner.h" +#include "remoting/client/chromoting_client_runtime.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace remoting { + +#if defined(OS_IOS) || defined(OS_ANDROID) + +// A simple test that starts and stop the runtime. This tests the runtime +// operates properly and all threads and message loops are valid. +TEST(ChromotingClientRuntimeTest, StartAndStop) { + scoped_ptr ui_loop; + ui_loop.reset(new base::MessageLoopForUI()); +#if defined(OS_IOS) + ui_loop->Attach(); +#elif defined(OS_ANDROID) + ui_loop->Start(); +#endif + + scoped_ptr runtime = + ChromotingClientRuntime::Create(ui_loop.get()); + + ASSERT_TRUE(runtime); + EXPECT_TRUE(runtime->network_task_runner().get()); + EXPECT_TRUE(runtime->ui_task_runner().get()); + EXPECT_TRUE(runtime->display_task_runner().get()); + EXPECT_TRUE(runtime->file_task_runner().get()); + EXPECT_TRUE(runtime->url_requester().get()); +} + +#endif + +} // namespace remoting diff --git a/remoting/client/jni/chromoting_jni_runtime.cc b/remoting/client/jni/chromoting_jni_runtime.cc index 37303b3..5b319f7 100644 --- a/remoting/client/jni/chromoting_jni_runtime.cc +++ b/remoting/client/jni/chromoting_jni_runtime.cc @@ -213,42 +213,41 @@ ChromotingJniRuntime* ChromotingJniRuntime::GetInstance() { } ChromotingJniRuntime::ChromotingJniRuntime() { - // 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. - ui_loop_.reset(new base::MessageLoopForUI()); - ui_loop_->Start(); - - // TODO(solb) Stop pretending to control the managed UI thread's lifetime. - ui_task_runner_ = new AutoThreadTaskRunner( - ui_loop_->task_runner(), base::MessageLoop::QuitWhenIdleClosure()); - network_task_runner_ = AutoThread::CreateWithType("native_net", - ui_task_runner_, - base::MessageLoop::TYPE_IO); - display_task_runner_ = AutoThread::Create("native_disp", - ui_task_runner_); + // Grab or create the threads. + // TODO(nicholss) We could runtime this as a constructor argument when jni + // runtime is not no longer a singleton. + + if (!base::MessageLoop::current()) { + VLOG(1) << "Starting main message loop"; + // 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. + ui_loop_.reset(new base::MessageLoopForUI()); + ui_loop_->Start(); + } else { + VLOG(1) << "Using existing main message loop"; + ui_loop_.reset(base::MessageLoopForUI::current()); + } - url_requester_ = - new URLRequestContextGetter(network_task_runner_, network_task_runner_); + // Pass the main ui loop already attached to be used for creating threads. + runtime_ = ChromotingClientRuntime::Create(ui_loop_.get()); } ChromotingJniRuntime::~ChromotingJniRuntime() { // The singleton should only ever be destroyed on the main thread. - DCHECK(ui_task_runner_->BelongsToCurrentThread()); + DCHECK(ui_task_runner()->BelongsToCurrentThread()); // The session must be shut down first, since it depends on our other // components' still being alive. DisconnectFromHost(); base::WaitableEvent done_event(false, false); - network_task_runner_->PostTask(FROM_HERE, base::Bind( - &ChromotingJniRuntime::DetachFromVmAndSignal, - base::Unretained(this), - &done_event)); + network_task_runner()->PostTask( + FROM_HERE, base::Bind(&ChromotingJniRuntime::DetachFromVmAndSignal, + base::Unretained(this), &done_event)); done_event.Wait(); - display_task_runner_->PostTask(FROM_HERE, base::Bind( - &ChromotingJniRuntime::DetachFromVmAndSignal, - base::Unretained(this), - &done_event)); + display_task_runner()->PostTask( + FROM_HERE, base::Bind(&ChromotingJniRuntime::DetachFromVmAndSignal, + base::Unretained(this), &done_event)); done_event.Wait(); base::android::LibraryLoaderExitHook(); base::android::DetachFromVM(); @@ -263,7 +262,7 @@ void ChromotingJniRuntime::ConnectToHost(const std::string& username, const std::string& pairing_secret, const std::string& capabilities, const std::string& flags) { - DCHECK(ui_task_runner_->BelongsToCurrentThread()); + DCHECK(ui_task_runner()->BelongsToCurrentThread()); DCHECK(!session_.get()); session_ = new ChromotingJniInstance(this, username, auth_token, host_jid, host_id, host_pubkey, pairing_id, @@ -271,7 +270,7 @@ void ChromotingJniRuntime::ConnectToHost(const std::string& username, } void ChromotingJniRuntime::DisconnectFromHost() { - DCHECK(ui_task_runner_->BelongsToCurrentThread()); + DCHECK(ui_task_runner()->BelongsToCurrentThread()); if (session_.get()) { session_->Disconnect(); session_ = nullptr; @@ -281,14 +280,14 @@ void ChromotingJniRuntime::DisconnectFromHost() { void ChromotingJniRuntime::OnConnectionState( protocol::ConnectionToHost::State state, protocol::ErrorCode error) { - DCHECK(ui_task_runner_->BelongsToCurrentThread()); + DCHECK(ui_task_runner()->BelongsToCurrentThread()); JNIEnv* env = base::android::AttachCurrentThread(); Java_JniInterface_onConnectionState(env, state, error); } void ChromotingJniRuntime::DisplayAuthenticationPrompt(bool pairing_supported) { - DCHECK(ui_task_runner_->BelongsToCurrentThread()); + DCHECK(ui_task_runner()->BelongsToCurrentThread()); JNIEnv* env = base::android::AttachCurrentThread(); Java_JniInterface_displayAuthenticationPrompt(env, pairing_supported); @@ -297,7 +296,7 @@ void ChromotingJniRuntime::DisplayAuthenticationPrompt(bool pairing_supported) { void ChromotingJniRuntime::CommitPairingCredentials(const std::string& host, const std::string& id, const std::string& secret) { - DCHECK(ui_task_runner_->BelongsToCurrentThread()); + DCHECK(ui_task_runner()->BelongsToCurrentThread()); JNIEnv* env = base::android::AttachCurrentThread(); ScopedJavaLocalRef j_host = ConvertUTF8ToJavaString(env, host); @@ -311,7 +310,7 @@ void ChromotingJniRuntime::CommitPairingCredentials(const std::string& host, void ChromotingJniRuntime::FetchThirdPartyToken(const std::string& token_url, const std::string& client_id, const std::string& scope) { - DCHECK(ui_task_runner_->BelongsToCurrentThread()); + DCHECK(ui_task_runner()->BelongsToCurrentThread()); JNIEnv* env = base::android::AttachCurrentThread(); ScopedJavaLocalRef j_url = ConvertUTF8ToJavaString(env, token_url); @@ -324,7 +323,7 @@ void ChromotingJniRuntime::FetchThirdPartyToken(const std::string& token_url, } void ChromotingJniRuntime::SetCapabilities(const std::string& capabilities) { - DCHECK(ui_task_runner_->BelongsToCurrentThread()); + DCHECK(ui_task_runner()->BelongsToCurrentThread()); JNIEnv* env = base::android::AttachCurrentThread(); ScopedJavaLocalRef j_cap = @@ -335,7 +334,7 @@ void ChromotingJniRuntime::SetCapabilities(const std::string& capabilities) { void ChromotingJniRuntime::HandleExtensionMessage(const std::string& type, const std::string& message) { - DCHECK(ui_task_runner_->BelongsToCurrentThread()); + DCHECK(ui_task_runner()->BelongsToCurrentThread()); JNIEnv* env = base::android::AttachCurrentThread(); ScopedJavaLocalRef j_type = ConvertUTF8ToJavaString(env, type); @@ -351,7 +350,7 @@ base::android::ScopedJavaLocalRef ChromotingJniRuntime::NewBitmap( } void ChromotingJniRuntime::UpdateFrameBitmap(jobject bitmap) { - DCHECK(display_task_runner_->BelongsToCurrentThread()); + DCHECK(display_task_runner()->BelongsToCurrentThread()); JNIEnv* env = base::android::AttachCurrentThread(); Java_JniInterface_setVideoFrame(env, bitmap); @@ -359,7 +358,7 @@ void ChromotingJniRuntime::UpdateFrameBitmap(jobject bitmap) { void ChromotingJniRuntime::UpdateCursorShape( const protocol::CursorShapeInfo& cursor_shape) { - DCHECK(display_task_runner_->BelongsToCurrentThread()); + DCHECK(display_task_runner()->BelongsToCurrentThread()); // const_cast<> is safe as long as the Java updateCursorShape() method copies // the data out of the buffer without mutating it, and doesn't keep any @@ -381,7 +380,7 @@ void ChromotingJniRuntime::UpdateCursorShape( } void ChromotingJniRuntime::RedrawCanvas() { - DCHECK(display_task_runner_->BelongsToCurrentThread()); + DCHECK(display_task_runner()->BelongsToCurrentThread()); JNIEnv* env = base::android::AttachCurrentThread(); Java_JniInterface_redrawGraphicsInternal(env); diff --git a/remoting/client/jni/chromoting_jni_runtime.h b/remoting/client/jni/chromoting_jni_runtime.h index b6128c1..8dedfcb 100644 --- a/remoting/client/jni/chromoting_jni_runtime.h +++ b/remoting/client/jni/chromoting_jni_runtime.h @@ -12,6 +12,7 @@ #include "base/macros.h" #include "net/url_request/url_request_context_getter.h" #include "remoting/base/auto_thread.h" +#include "remoting/client/chromoting_client_runtime.h" #include "remoting/client/jni/chromoting_jni_instance.h" #include "remoting/protocol/connection_to_host.h" @@ -34,19 +35,19 @@ class ChromotingJniRuntime { static ChromotingJniRuntime* GetInstance(); scoped_refptr ui_task_runner() { - return ui_task_runner_; + return runtime_->ui_task_runner(); } scoped_refptr network_task_runner() { - return network_task_runner_; + return runtime_->network_task_runner(); } scoped_refptr display_task_runner() { - return display_task_runner_; + return runtime_->display_task_runner(); } scoped_refptr url_requester() { - return url_requester_; + return runtime_->url_requester(); } // Initiates a connection with the specified host. Only call when a host @@ -126,15 +127,13 @@ class ChromotingJniRuntime { // Detaches JVM from the current thread, then signals. Doesn't own |waiter|. void DetachFromVmAndSignal(base::WaitableEvent* waiter); - // Chromium code's connection to the Java message loop. + // Chromium code's connection to the app message loop. Once created the + // MessageLoop will live for the life of the program. scoped_ptr ui_loop_; - // References to native threads. - scoped_refptr ui_task_runner_; - scoped_refptr network_task_runner_; - scoped_refptr display_task_runner_; - - scoped_refptr url_requester_; + // Contains threads. + // + scoped_ptr runtime_; // Contains all connection-specific state. scoped_refptr session_; diff --git a/remoting/remoting_client.gypi b/remoting/remoting_client.gypi index 891b625..5883914 100644 --- a/remoting/remoting_client.gypi +++ b/remoting/remoting_client.gypi @@ -20,6 +20,7 @@ ], 'sources': [ '<@(remoting_client_sources)', + '<@(remoting_client_standalone_sources)', ], }, # end of target 'remoting_client' diff --git a/remoting/remoting_srcs.gypi b/remoting/remoting_srcs.gypi index 7bc0682..d1c1ee4 100644 --- a/remoting/remoting_srcs.gypi +++ b/remoting/remoting_srcs.gypi @@ -299,6 +299,11 @@ 'client/touch_input_scaler.h', ], + 'remoting_client_standalone_sources': [ + 'client/chromoting_client_runtime.cc', + 'client/chromoting_client_runtime.h', + ], + 'remoting_client_plugin_sources': [ 'client/plugin/chromoting_instance.cc', 'client/plugin/chromoting_instance.h', diff --git a/remoting/remoting_test.gypi b/remoting/remoting_test.gypi index 7f6858d..6781785 100644 --- a/remoting/remoting_test.gypi +++ b/remoting/remoting_test.gypi @@ -231,6 +231,7 @@ 'base/typed_buffer_unittest.cc', 'base/util_unittest.cc', 'client/audio_player_unittest.cc', + 'client/chromoting_client_runtime_unittest.cc', 'client/client_status_logger_unittest.cc', 'client/empty_cursor_filter_unittest.cc', 'client/key_event_mapper_unittest.cc', -- cgit v1.1