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.
4
5 #include "base/android/java_handler_thread.h"
6
7 #include <jni.h>
8
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"
21
22 using base::android::AttachCurrentThread;
23
24 namespace base {
25
26 namespace android {
27
JavaHandlerThread(const char * name,base::ThreadType thread_type)28 JavaHandlerThread::JavaHandlerThread(const char* name,
29 base::ThreadType thread_type)
30 : JavaHandlerThread(
31 name,
32 Java_JavaHandlerThread_create(
33 AttachCurrentThread(),
34 name,
35 base::internal::ThreadTypeToNiceValue(thread_type))) {}
36
JavaHandlerThread(const char * name,const base::android::ScopedJavaLocalRef<jobject> & obj)37 JavaHandlerThread::JavaHandlerThread(
38 const char* name,
39 const base::android::ScopedJavaLocalRef<jobject>& obj)
40 : name_(name), java_thread_(obj) {}
41
~JavaHandlerThread()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
47 // future tests.
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
53 // process.
54 state_.release();
55 }
56 }
57
Start()58 void JavaHandlerThread::Start() {
59 // Check the thread has not already been started.
60 DCHECK(!state_);
61
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
70 // returns.
71 base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope wait_allowed;
72 initialize_event.Wait();
73 }
74
Stop()75 void JavaHandlerThread::Stop() {
76 DCHECK(!task_runner()->BelongsToCurrentThread());
77 task_runner()->PostTask(
78 FROM_HERE,
79 base::BindOnce(&JavaHandlerThread::StopOnThread, base::Unretained(this)));
80 JNIEnv* env = base::android::AttachCurrentThread();
81 Java_JavaHandlerThread_joinThread(env, java_thread_);
82 }
83
InitializeThread(JNIEnv * env,jlong event)84 void JavaHandlerThread::InitializeThread(JNIEnv* env,
85 jlong event) {
86 base::ThreadIdNameManager::GetInstance()->RegisterThread(
87 base::PlatformThread::CurrentHandle().platform_handle(),
88 base::PlatformThread::CurrentId());
89
90 if (name_)
91 PlatformThread::SetName(name_);
92
93 thread_id_ = base::PlatformThread::CurrentId();
94 state_ = std::make_unique<State>();
95 #if DCHECK_IS_ON()
96 initialized_ = true;
97 #endif
98 Init();
99 reinterpret_cast<base::WaitableEvent*>(event)->Signal();
100 }
101
OnLooperStopped(JNIEnv * env)102 void JavaHandlerThread::OnLooperStopped(JNIEnv* env) {
103 DCHECK(task_runner()->BelongsToCurrentThread());
104 state_.reset();
105
106 CleanUp();
107
108 base::ThreadIdNameManager::GetInstance()->RemoveName(
109 base::PlatformThread::CurrentHandle().platform_handle(),
110 base::PlatformThread::CurrentId());
111 }
112
StopSequenceManagerForTesting()113 void JavaHandlerThread::StopSequenceManagerForTesting() {
114 DCHECK(task_runner()->BelongsToCurrentThread());
115 StopOnThread();
116 }
117
JoinForTesting()118 void JavaHandlerThread::JoinForTesting() {
119 DCHECK(!task_runner()->BelongsToCurrentThread());
120 JNIEnv* env = base::android::AttachCurrentThread();
121 Java_JavaHandlerThread_joinThread(env, java_thread_);
122 }
123
ListenForUncaughtExceptionsForTesting()124 void JavaHandlerThread::ListenForUncaughtExceptionsForTesting() {
125 DCHECK(!task_runner()->BelongsToCurrentThread());
126 JNIEnv* env = base::android::AttachCurrentThread();
127 Java_JavaHandlerThread_listenForUncaughtExceptionsForTesting(env,
128 java_thread_);
129 }
130
GetUncaughtExceptionIfAny()131 ScopedJavaLocalRef<jthrowable> JavaHandlerThread::GetUncaughtExceptionIfAny() {
132 DCHECK(!task_runner()->BelongsToCurrentThread());
133 JNIEnv* env = base::android::AttachCurrentThread();
134 return Java_JavaHandlerThread_getUncaughtExceptionIfAny(env, java_thread_);
135 }
136
GetThreadId() const137 PlatformThreadId JavaHandlerThread::GetThreadId() const {
138 #if DCHECK_IS_ON()
139 DCHECK(initialized_);
140 #endif
141 return thread_id_;
142 }
143
StopOnThread()144 void JavaHandlerThread::StopOnThread() {
145 DCHECK(task_runner()->BelongsToCurrentThread());
146 DCHECK(state_);
147 state_->pump->QuitWhenIdle(base::BindOnce(
148 &JavaHandlerThread::QuitThreadSafely, base::Unretained(this)));
149 }
150
QuitThreadSafely()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));
156 }
157
State()158 JavaHandlerThread::State::State()
159 : sequence_manager(sequence_manager::CreateUnboundSequenceManager(
160 sequence_manager::SequenceManager::Settings::Builder()
161 .SetMessagePumpType(base::MessagePumpType::JAVA)
162 .Build())),
163 default_task_queue(
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());
170
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));
177 }
178
179 JavaHandlerThread::State::~State() = default;
180
181 } // namespace android
182 } // namespace base
183