1*6777b538SAndroid Build Coastguard Worker // Copyright 2013 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "base/android/java_handler_thread.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <jni.h>
8*6777b538SAndroid Build Coastguard Worker
9*6777b538SAndroid Build Coastguard Worker #include "base/android/jni_android.h"
10*6777b538SAndroid Build Coastguard Worker #include "base/android/jni_string.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/base_jni/JavaHandlerThread_jni.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/functional/bind.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/message_loop/message_pump.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/message_loop/message_pump_type.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/run_loop.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/synchronization/waitable_event.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/task/sequence_manager/sequence_manager_impl.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/threading/platform_thread_internal_posix.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/threading/thread_id_name_manager.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/threading/thread_restrictions.h"
21*6777b538SAndroid Build Coastguard Worker
22*6777b538SAndroid Build Coastguard Worker using base::android::AttachCurrentThread;
23*6777b538SAndroid Build Coastguard Worker
24*6777b538SAndroid Build Coastguard Worker namespace base {
25*6777b538SAndroid Build Coastguard Worker
26*6777b538SAndroid Build Coastguard Worker namespace android {
27*6777b538SAndroid Build Coastguard Worker
JavaHandlerThread(const char * name,base::ThreadType thread_type)28*6777b538SAndroid Build Coastguard Worker JavaHandlerThread::JavaHandlerThread(const char* name,
29*6777b538SAndroid Build Coastguard Worker base::ThreadType thread_type)
30*6777b538SAndroid Build Coastguard Worker : JavaHandlerThread(
31*6777b538SAndroid Build Coastguard Worker name,
32*6777b538SAndroid Build Coastguard Worker Java_JavaHandlerThread_create(
33*6777b538SAndroid Build Coastguard Worker AttachCurrentThread(),
34*6777b538SAndroid Build Coastguard Worker name,
35*6777b538SAndroid Build Coastguard Worker base::internal::ThreadTypeToNiceValue(thread_type))) {}
36*6777b538SAndroid Build Coastguard Worker
JavaHandlerThread(const char * name,const base::android::ScopedJavaLocalRef<jobject> & obj)37*6777b538SAndroid Build Coastguard Worker JavaHandlerThread::JavaHandlerThread(
38*6777b538SAndroid Build Coastguard Worker const char* name,
39*6777b538SAndroid Build Coastguard Worker const base::android::ScopedJavaLocalRef<jobject>& obj)
40*6777b538SAndroid Build Coastguard Worker : name_(name), java_thread_(obj) {}
41*6777b538SAndroid Build Coastguard Worker
~JavaHandlerThread()42*6777b538SAndroid Build Coastguard Worker JavaHandlerThread::~JavaHandlerThread() {
43*6777b538SAndroid Build Coastguard Worker JNIEnv* env = base::android::AttachCurrentThread();
44*6777b538SAndroid Build Coastguard Worker DCHECK(!Java_JavaHandlerThread_isAlive(env, java_thread_));
45*6777b538SAndroid Build Coastguard Worker DCHECK(!state_ || state_->pump->IsAborted());
46*6777b538SAndroid Build Coastguard Worker // TODO(mthiesse): We shouldn't leak the MessageLoop as this could affect
47*6777b538SAndroid Build Coastguard Worker // future tests.
48*6777b538SAndroid Build Coastguard Worker if (state_ && state_->pump->IsAborted()) {
49*6777b538SAndroid Build Coastguard Worker // When the Pump has been aborted due to a crash, we intentionally leak the
50*6777b538SAndroid Build Coastguard Worker // SequenceManager because the SequenceManager hasn't been shut down
51*6777b538SAndroid Build Coastguard Worker // properly and would trigger DCHECKS. This should only happen in tests,
52*6777b538SAndroid Build Coastguard Worker // where we handle the exception instead of letting it take down the
53*6777b538SAndroid Build Coastguard Worker // process.
54*6777b538SAndroid Build Coastguard Worker state_.release();
55*6777b538SAndroid Build Coastguard Worker }
56*6777b538SAndroid Build Coastguard Worker }
57*6777b538SAndroid Build Coastguard Worker
Start()58*6777b538SAndroid Build Coastguard Worker void JavaHandlerThread::Start() {
59*6777b538SAndroid Build Coastguard Worker // Check the thread has not already been started.
60*6777b538SAndroid Build Coastguard Worker DCHECK(!state_);
61*6777b538SAndroid Build Coastguard Worker
62*6777b538SAndroid Build Coastguard Worker JNIEnv* env = base::android::AttachCurrentThread();
63*6777b538SAndroid Build Coastguard Worker base::WaitableEvent initialize_event(
64*6777b538SAndroid Build Coastguard Worker WaitableEvent::ResetPolicy::AUTOMATIC,
65*6777b538SAndroid Build Coastguard Worker WaitableEvent::InitialState::NOT_SIGNALED);
66*6777b538SAndroid Build Coastguard Worker Java_JavaHandlerThread_startAndInitialize(
67*6777b538SAndroid Build Coastguard Worker env, java_thread_, reinterpret_cast<intptr_t>(this),
68*6777b538SAndroid Build Coastguard Worker reinterpret_cast<intptr_t>(&initialize_event));
69*6777b538SAndroid Build Coastguard Worker // Wait for thread to be initialized so it is ready to be used when Start
70*6777b538SAndroid Build Coastguard Worker // returns.
71*6777b538SAndroid Build Coastguard Worker base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope wait_allowed;
72*6777b538SAndroid Build Coastguard Worker initialize_event.Wait();
73*6777b538SAndroid Build Coastguard Worker }
74*6777b538SAndroid Build Coastguard Worker
Stop()75*6777b538SAndroid Build Coastguard Worker void JavaHandlerThread::Stop() {
76*6777b538SAndroid Build Coastguard Worker DCHECK(!task_runner()->BelongsToCurrentThread());
77*6777b538SAndroid Build Coastguard Worker task_runner()->PostTask(
78*6777b538SAndroid Build Coastguard Worker FROM_HERE,
79*6777b538SAndroid Build Coastguard Worker base::BindOnce(&JavaHandlerThread::StopOnThread, base::Unretained(this)));
80*6777b538SAndroid Build Coastguard Worker JNIEnv* env = base::android::AttachCurrentThread();
81*6777b538SAndroid Build Coastguard Worker Java_JavaHandlerThread_joinThread(env, java_thread_);
82*6777b538SAndroid Build Coastguard Worker }
83*6777b538SAndroid Build Coastguard Worker
InitializeThread(JNIEnv * env,jlong event)84*6777b538SAndroid Build Coastguard Worker void JavaHandlerThread::InitializeThread(JNIEnv* env,
85*6777b538SAndroid Build Coastguard Worker jlong event) {
86*6777b538SAndroid Build Coastguard Worker base::ThreadIdNameManager::GetInstance()->RegisterThread(
87*6777b538SAndroid Build Coastguard Worker base::PlatformThread::CurrentHandle().platform_handle(),
88*6777b538SAndroid Build Coastguard Worker base::PlatformThread::CurrentId());
89*6777b538SAndroid Build Coastguard Worker
90*6777b538SAndroid Build Coastguard Worker if (name_)
91*6777b538SAndroid Build Coastguard Worker PlatformThread::SetName(name_);
92*6777b538SAndroid Build Coastguard Worker
93*6777b538SAndroid Build Coastguard Worker thread_id_ = base::PlatformThread::CurrentId();
94*6777b538SAndroid Build Coastguard Worker state_ = std::make_unique<State>();
95*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
96*6777b538SAndroid Build Coastguard Worker initialized_ = true;
97*6777b538SAndroid Build Coastguard Worker #endif
98*6777b538SAndroid Build Coastguard Worker Init();
99*6777b538SAndroid Build Coastguard Worker reinterpret_cast<base::WaitableEvent*>(event)->Signal();
100*6777b538SAndroid Build Coastguard Worker }
101*6777b538SAndroid Build Coastguard Worker
OnLooperStopped(JNIEnv * env)102*6777b538SAndroid Build Coastguard Worker void JavaHandlerThread::OnLooperStopped(JNIEnv* env) {
103*6777b538SAndroid Build Coastguard Worker DCHECK(task_runner()->BelongsToCurrentThread());
104*6777b538SAndroid Build Coastguard Worker state_.reset();
105*6777b538SAndroid Build Coastguard Worker
106*6777b538SAndroid Build Coastguard Worker CleanUp();
107*6777b538SAndroid Build Coastguard Worker
108*6777b538SAndroid Build Coastguard Worker base::ThreadIdNameManager::GetInstance()->RemoveName(
109*6777b538SAndroid Build Coastguard Worker base::PlatformThread::CurrentHandle().platform_handle(),
110*6777b538SAndroid Build Coastguard Worker base::PlatformThread::CurrentId());
111*6777b538SAndroid Build Coastguard Worker }
112*6777b538SAndroid Build Coastguard Worker
StopSequenceManagerForTesting()113*6777b538SAndroid Build Coastguard Worker void JavaHandlerThread::StopSequenceManagerForTesting() {
114*6777b538SAndroid Build Coastguard Worker DCHECK(task_runner()->BelongsToCurrentThread());
115*6777b538SAndroid Build Coastguard Worker StopOnThread();
116*6777b538SAndroid Build Coastguard Worker }
117*6777b538SAndroid Build Coastguard Worker
JoinForTesting()118*6777b538SAndroid Build Coastguard Worker void JavaHandlerThread::JoinForTesting() {
119*6777b538SAndroid Build Coastguard Worker DCHECK(!task_runner()->BelongsToCurrentThread());
120*6777b538SAndroid Build Coastguard Worker JNIEnv* env = base::android::AttachCurrentThread();
121*6777b538SAndroid Build Coastguard Worker Java_JavaHandlerThread_joinThread(env, java_thread_);
122*6777b538SAndroid Build Coastguard Worker }
123*6777b538SAndroid Build Coastguard Worker
ListenForUncaughtExceptionsForTesting()124*6777b538SAndroid Build Coastguard Worker void JavaHandlerThread::ListenForUncaughtExceptionsForTesting() {
125*6777b538SAndroid Build Coastguard Worker DCHECK(!task_runner()->BelongsToCurrentThread());
126*6777b538SAndroid Build Coastguard Worker JNIEnv* env = base::android::AttachCurrentThread();
127*6777b538SAndroid Build Coastguard Worker Java_JavaHandlerThread_listenForUncaughtExceptionsForTesting(env,
128*6777b538SAndroid Build Coastguard Worker java_thread_);
129*6777b538SAndroid Build Coastguard Worker }
130*6777b538SAndroid Build Coastguard Worker
GetUncaughtExceptionIfAny()131*6777b538SAndroid Build Coastguard Worker ScopedJavaLocalRef<jthrowable> JavaHandlerThread::GetUncaughtExceptionIfAny() {
132*6777b538SAndroid Build Coastguard Worker DCHECK(!task_runner()->BelongsToCurrentThread());
133*6777b538SAndroid Build Coastguard Worker JNIEnv* env = base::android::AttachCurrentThread();
134*6777b538SAndroid Build Coastguard Worker return Java_JavaHandlerThread_getUncaughtExceptionIfAny(env, java_thread_);
135*6777b538SAndroid Build Coastguard Worker }
136*6777b538SAndroid Build Coastguard Worker
GetThreadId() const137*6777b538SAndroid Build Coastguard Worker PlatformThreadId JavaHandlerThread::GetThreadId() const {
138*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
139*6777b538SAndroid Build Coastguard Worker DCHECK(initialized_);
140*6777b538SAndroid Build Coastguard Worker #endif
141*6777b538SAndroid Build Coastguard Worker return thread_id_;
142*6777b538SAndroid Build Coastguard Worker }
143*6777b538SAndroid Build Coastguard Worker
StopOnThread()144*6777b538SAndroid Build Coastguard Worker void JavaHandlerThread::StopOnThread() {
145*6777b538SAndroid Build Coastguard Worker DCHECK(task_runner()->BelongsToCurrentThread());
146*6777b538SAndroid Build Coastguard Worker DCHECK(state_);
147*6777b538SAndroid Build Coastguard Worker state_->pump->QuitWhenIdle(base::BindOnce(
148*6777b538SAndroid Build Coastguard Worker &JavaHandlerThread::QuitThreadSafely, base::Unretained(this)));
149*6777b538SAndroid Build Coastguard Worker }
150*6777b538SAndroid Build Coastguard Worker
QuitThreadSafely()151*6777b538SAndroid Build Coastguard Worker void JavaHandlerThread::QuitThreadSafely() {
152*6777b538SAndroid Build Coastguard Worker DCHECK(task_runner()->BelongsToCurrentThread());
153*6777b538SAndroid Build Coastguard Worker JNIEnv* env = base::android::AttachCurrentThread();
154*6777b538SAndroid Build Coastguard Worker Java_JavaHandlerThread_quitThreadSafely(env, java_thread_,
155*6777b538SAndroid Build Coastguard Worker reinterpret_cast<intptr_t>(this));
156*6777b538SAndroid Build Coastguard Worker }
157*6777b538SAndroid Build Coastguard Worker
State()158*6777b538SAndroid Build Coastguard Worker JavaHandlerThread::State::State()
159*6777b538SAndroid Build Coastguard Worker : sequence_manager(sequence_manager::CreateUnboundSequenceManager(
160*6777b538SAndroid Build Coastguard Worker sequence_manager::SequenceManager::Settings::Builder()
161*6777b538SAndroid Build Coastguard Worker .SetMessagePumpType(base::MessagePumpType::JAVA)
162*6777b538SAndroid Build Coastguard Worker .Build())),
163*6777b538SAndroid Build Coastguard Worker default_task_queue(
164*6777b538SAndroid Build Coastguard Worker sequence_manager->CreateTaskQueue(sequence_manager::TaskQueue::Spec(
165*6777b538SAndroid Build Coastguard Worker sequence_manager::QueueName::DEFAULT_TQ))) {
166*6777b538SAndroid Build Coastguard Worker // TYPE_JAVA to get the Android java style message loop.
167*6777b538SAndroid Build Coastguard Worker std::unique_ptr<MessagePump> message_pump =
168*6777b538SAndroid Build Coastguard Worker MessagePump::Create(base::MessagePumpType::JAVA);
169*6777b538SAndroid Build Coastguard Worker pump = static_cast<MessagePumpForUI*>(message_pump.get());
170*6777b538SAndroid Build Coastguard Worker
171*6777b538SAndroid Build Coastguard Worker // We must set SetTaskRunner before binding because the Android UI pump
172*6777b538SAndroid Build Coastguard Worker // creates a RunLoop which samples SingleThreadTaskRunner::GetCurrentDefault.
173*6777b538SAndroid Build Coastguard Worker static_cast<sequence_manager::internal::SequenceManagerImpl*>(
174*6777b538SAndroid Build Coastguard Worker sequence_manager.get())
175*6777b538SAndroid Build Coastguard Worker ->SetTaskRunner(default_task_queue->task_runner());
176*6777b538SAndroid Build Coastguard Worker sequence_manager->BindToMessagePump(std::move(message_pump));
177*6777b538SAndroid Build Coastguard Worker }
178*6777b538SAndroid Build Coastguard Worker
179*6777b538SAndroid Build Coastguard Worker JavaHandlerThread::State::~State() = default;
180*6777b538SAndroid Build Coastguard Worker
181*6777b538SAndroid Build Coastguard Worker } // namespace android
182*6777b538SAndroid Build Coastguard Worker } // namespace base
183