1 // Copyright 2013 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/android/java_handler_thread.h"
9 #include "base/android/jni_android.h"
10 #include "base/android/jni_string.h"
11 #include "base/base_jni/JavaHandlerThread_jni.h"
12 #include "base/functional/bind.h"
13 #include "base/message_loop/message_pump.h"
14 #include "base/message_loop/message_pump_type.h"
15 #include "base/run_loop.h"
16 #include "base/synchronization/waitable_event.h"
17 #include "base/task/sequence_manager/sequence_manager_impl.h"
18 #include "base/threading/platform_thread_internal_posix.h"
19 #include "base/threading/thread_id_name_manager.h"
20 #include "base/threading/thread_restrictions.h"
22 using base::android::AttachCurrentThread;
28 JavaHandlerThread::JavaHandlerThread(const char* name,
29 base::ThreadType thread_type)
32 Java_JavaHandlerThread_create(
33 AttachCurrentThread(),
34 ConvertUTF8ToJavaString(AttachCurrentThread(), name),
35 base::internal::ThreadTypeToNiceValue(thread_type))) {}
37 JavaHandlerThread::JavaHandlerThread(
39 const base::android::ScopedJavaLocalRef<jobject>& obj)
40 : name_(name), java_thread_(obj) {}
42 JavaHandlerThread::~JavaHandlerThread() {
43 JNIEnv* env = base::android::AttachCurrentThread();
44 DCHECK(!Java_JavaHandlerThread_isAlive(env, java_thread_));
45 DCHECK(!state_ || state_->pump->IsAborted());
46 // TODO(mthiesse): We shouldn't leak the MessageLoop as this could affect
48 if (state_ && state_->pump->IsAborted()) {
49 // When the Pump has been aborted due to a crash, we intentionally leak the
50 // SequenceManager because the SequenceManager hasn't been shut down
51 // properly and would trigger DCHECKS. This should only happen in tests,
52 // where we handle the exception instead of letting it take down the
58 void JavaHandlerThread::Start() {
59 // Check the thread has not already been started.
62 JNIEnv* env = base::android::AttachCurrentThread();
63 base::WaitableEvent initialize_event(
64 WaitableEvent::ResetPolicy::AUTOMATIC,
65 WaitableEvent::InitialState::NOT_SIGNALED);
66 Java_JavaHandlerThread_startAndInitialize(
67 env, java_thread_, reinterpret_cast<intptr_t>(this),
68 reinterpret_cast<intptr_t>(&initialize_event));
69 // Wait for thread to be initialized so it is ready to be used when Start
71 base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope wait_allowed;
72 initialize_event.Wait();
75 void JavaHandlerThread::Stop() {
76 DCHECK(!task_runner()->BelongsToCurrentThread());
77 task_runner()->PostTask(
79 base::BindOnce(&JavaHandlerThread::StopOnThread, base::Unretained(this)));
80 JNIEnv* env = base::android::AttachCurrentThread();
81 Java_JavaHandlerThread_joinThread(env, java_thread_);
84 void JavaHandlerThread::InitializeThread(JNIEnv* env,
86 base::ThreadIdNameManager::GetInstance()->RegisterThread(
87 base::PlatformThread::CurrentHandle().platform_handle(),
88 base::PlatformThread::CurrentId());
91 PlatformThread::SetName(name_);
93 thread_id_ = base::PlatformThread::CurrentId();
94 state_ = std::make_unique<State>();
99 reinterpret_cast<base::WaitableEvent*>(event)->Signal();
102 void JavaHandlerThread::OnLooperStopped(JNIEnv* env) {
103 DCHECK(task_runner()->BelongsToCurrentThread());
108 base::ThreadIdNameManager::GetInstance()->RemoveName(
109 base::PlatformThread::CurrentHandle().platform_handle(),
110 base::PlatformThread::CurrentId());
113 void JavaHandlerThread::StopSequenceManagerForTesting() {
114 DCHECK(task_runner()->BelongsToCurrentThread());
118 void JavaHandlerThread::JoinForTesting() {
119 DCHECK(!task_runner()->BelongsToCurrentThread());
120 JNIEnv* env = base::android::AttachCurrentThread();
121 Java_JavaHandlerThread_joinThread(env, java_thread_);
124 void JavaHandlerThread::ListenForUncaughtExceptionsForTesting() {
125 DCHECK(!task_runner()->BelongsToCurrentThread());
126 JNIEnv* env = base::android::AttachCurrentThread();
127 Java_JavaHandlerThread_listenForUncaughtExceptionsForTesting(env,
131 ScopedJavaLocalRef<jthrowable> JavaHandlerThread::GetUncaughtExceptionIfAny() {
132 DCHECK(!task_runner()->BelongsToCurrentThread());
133 JNIEnv* env = base::android::AttachCurrentThread();
134 return Java_JavaHandlerThread_getUncaughtExceptionIfAny(env, java_thread_);
137 PlatformThreadId JavaHandlerThread::GetThreadId() const {
139 DCHECK(initialized_);
144 void JavaHandlerThread::StopOnThread() {
145 DCHECK(task_runner()->BelongsToCurrentThread());
147 state_->pump->QuitWhenIdle(base::BindOnce(
148 &JavaHandlerThread::QuitThreadSafely, base::Unretained(this)));
151 void JavaHandlerThread::QuitThreadSafely() {
152 DCHECK(task_runner()->BelongsToCurrentThread());
153 JNIEnv* env = base::android::AttachCurrentThread();
154 Java_JavaHandlerThread_quitThreadSafely(env, java_thread_,
155 reinterpret_cast<intptr_t>(this));
158 JavaHandlerThread::State::State()
159 : sequence_manager(sequence_manager::CreateUnboundSequenceManager(
160 sequence_manager::SequenceManager::Settings::Builder()
161 .SetMessagePumpType(base::MessagePumpType::JAVA)
164 sequence_manager->CreateTaskQueue(sequence_manager::TaskQueue::Spec(
165 sequence_manager::QueueName::DEFAULT_TQ))) {
166 // TYPE_JAVA to get the Android java style message loop.
167 std::unique_ptr<MessagePump> message_pump =
168 MessagePump::Create(base::MessagePumpType::JAVA);
169 pump = static_cast<MessagePumpForUI*>(message_pump.get());
171 // We must set SetTaskRunner before binding because the Android UI pump
172 // creates a RunLoop which samples SingleThreadTaskRunner::GetCurrentDefault.
173 static_cast<sequence_manager::internal::SequenceManagerImpl*>(
174 sequence_manager.get())
175 ->SetTaskRunner(default_task_queue->task_runner());
176 sequence_manager->BindToMessagePump(std::move(message_pump));
179 JavaHandlerThread::State::~State() = default;
181 } // namespace android