xref: /aosp_15_r20/external/cronet/base/android/java_handler_thread.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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