diff options
Diffstat (limited to 'chromium/base/android/java_handler_thread.cc')
-rw-r--r-- | chromium/base/android/java_handler_thread.cc | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/chromium/base/android/java_handler_thread.cc b/chromium/base/android/java_handler_thread.cc new file mode 100644 index 00000000000..74fb75bfe82 --- /dev/null +++ b/chromium/base/android/java_handler_thread.cc @@ -0,0 +1,182 @@ +// Copyright 2013 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/android/java_handler_thread.h" + +#include <jni.h> + +#include "base/android/jni_android.h" +#include "base/android/jni_string.h" +#include "base/base_jni_headers/JavaHandlerThread_jni.h" +#include "base/functional/bind.h" +#include "base/message_loop/message_pump.h" +#include "base/message_loop/message_pump_type.h" +#include "base/run_loop.h" +#include "base/synchronization/waitable_event.h" +#include "base/task/sequence_manager/sequence_manager_impl.h" +#include "base/threading/platform_thread_internal_posix.h" +#include "base/threading/thread_id_name_manager.h" +#include "base/threading/thread_restrictions.h" + +using base::android::AttachCurrentThread; + +namespace base { + +namespace android { + +JavaHandlerThread::JavaHandlerThread(const char* name, + base::ThreadType thread_type) + : JavaHandlerThread( + name, + Java_JavaHandlerThread_create( + AttachCurrentThread(), + ConvertUTF8ToJavaString(AttachCurrentThread(), name), + base::internal::ThreadTypeToNiceValue(thread_type))) {} + +JavaHandlerThread::JavaHandlerThread( + const char* name, + const base::android::ScopedJavaLocalRef<jobject>& obj) + : name_(name), java_thread_(obj) {} + +JavaHandlerThread::~JavaHandlerThread() { + JNIEnv* env = base::android::AttachCurrentThread(); + DCHECK(!Java_JavaHandlerThread_isAlive(env, java_thread_)); + DCHECK(!state_ || state_->pump->IsAborted()); + // TODO(mthiesse): We shouldn't leak the MessageLoop as this could affect + // future tests. + if (state_ && state_->pump->IsAborted()) { + // When the Pump has been aborted due to a crash, we intentionally leak the + // SequenceManager because the SequenceManager hasn't been shut down + // properly and would trigger DCHECKS. This should only happen in tests, + // where we handle the exception instead of letting it take down the + // process. + state_.release(); + } +} + +void JavaHandlerThread::Start() { + // Check the thread has not already been started. + DCHECK(!state_); + + JNIEnv* env = base::android::AttachCurrentThread(); + base::WaitableEvent initialize_event( + WaitableEvent::ResetPolicy::AUTOMATIC, + WaitableEvent::InitialState::NOT_SIGNALED); + Java_JavaHandlerThread_startAndInitialize( + env, java_thread_, reinterpret_cast<intptr_t>(this), + reinterpret_cast<intptr_t>(&initialize_event)); + // Wait for thread to be initialized so it is ready to be used when Start + // returns. + base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope wait_allowed; + initialize_event.Wait(); +} + +void JavaHandlerThread::Stop() { + DCHECK(!task_runner()->BelongsToCurrentThread()); + task_runner()->PostTask( + FROM_HERE, + base::BindOnce(&JavaHandlerThread::StopOnThread, base::Unretained(this))); + JNIEnv* env = base::android::AttachCurrentThread(); + Java_JavaHandlerThread_joinThread(env, java_thread_); +} + +void JavaHandlerThread::InitializeThread(JNIEnv* env, + jlong event) { + base::ThreadIdNameManager::GetInstance()->RegisterThread( + base::PlatformThread::CurrentHandle().platform_handle(), + base::PlatformThread::CurrentId()); + + if (name_) + PlatformThread::SetName(name_); + + thread_id_ = base::PlatformThread::CurrentId(); + state_ = std::make_unique<State>(); +#if DCHECK_IS_ON() + initialized_ = true; +#endif + Init(); + reinterpret_cast<base::WaitableEvent*>(event)->Signal(); +} + +void JavaHandlerThread::OnLooperStopped(JNIEnv* env) { + DCHECK(task_runner()->BelongsToCurrentThread()); + state_.reset(); + + CleanUp(); + + base::ThreadIdNameManager::GetInstance()->RemoveName( + base::PlatformThread::CurrentHandle().platform_handle(), + base::PlatformThread::CurrentId()); +} + +void JavaHandlerThread::StopSequenceManagerForTesting() { + DCHECK(task_runner()->BelongsToCurrentThread()); + StopOnThread(); +} + +void JavaHandlerThread::JoinForTesting() { + DCHECK(!task_runner()->BelongsToCurrentThread()); + JNIEnv* env = base::android::AttachCurrentThread(); + Java_JavaHandlerThread_joinThread(env, java_thread_); +} + +void JavaHandlerThread::ListenForUncaughtExceptionsForTesting() { + DCHECK(!task_runner()->BelongsToCurrentThread()); + JNIEnv* env = base::android::AttachCurrentThread(); + Java_JavaHandlerThread_listenForUncaughtExceptionsForTesting(env, + java_thread_); +} + +ScopedJavaLocalRef<jthrowable> JavaHandlerThread::GetUncaughtExceptionIfAny() { + DCHECK(!task_runner()->BelongsToCurrentThread()); + JNIEnv* env = base::android::AttachCurrentThread(); + return Java_JavaHandlerThread_getUncaughtExceptionIfAny(env, java_thread_); +} + +PlatformThreadId JavaHandlerThread::GetThreadId() const { +#if DCHECK_IS_ON() + DCHECK(initialized_); +#endif + return thread_id_; +} + +void JavaHandlerThread::StopOnThread() { + DCHECK(task_runner()->BelongsToCurrentThread()); + DCHECK(state_); + state_->pump->QuitWhenIdle(base::BindOnce( + &JavaHandlerThread::QuitThreadSafely, base::Unretained(this))); +} + +void JavaHandlerThread::QuitThreadSafely() { + DCHECK(task_runner()->BelongsToCurrentThread()); + JNIEnv* env = base::android::AttachCurrentThread(); + Java_JavaHandlerThread_quitThreadSafely(env, java_thread_, + reinterpret_cast<intptr_t>(this)); +} + +JavaHandlerThread::State::State() + : sequence_manager(sequence_manager::CreateUnboundSequenceManager( + sequence_manager::SequenceManager::Settings::Builder() + .SetMessagePumpType(base::MessagePumpType::JAVA) + .Build())), + default_task_queue( + sequence_manager->CreateTaskQueue(sequence_manager::TaskQueue::Spec( + sequence_manager::QueueName::DEFAULT_TQ))) { + // TYPE_JAVA to get the Android java style message loop. + std::unique_ptr<MessagePump> message_pump = + MessagePump::Create(base::MessagePumpType::JAVA); + pump = static_cast<MessagePumpForUI*>(message_pump.get()); + + // We must set SetTaskRunner before binding because the Android UI pump + // creates a RunLoop which samples SingleThreadTaskRunner::GetCurrentDefault. + static_cast<sequence_manager::internal::SequenceManagerImpl*>( + sequence_manager.get()) + ->SetTaskRunner(default_task_queue->task_runner()); + sequence_manager->BindToMessagePump(std::move(message_pump)); +} + +JavaHandlerThread::State::~State() = default; + +} // namespace android +} // namespace base |