xref: /aosp_15_r20/external/libchrome/base/android/java_handler_thread.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1*635a8641SAndroid Build Coastguard Worker // Copyright 2013 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker 
5*635a8641SAndroid Build Coastguard Worker #include "base/android/java_handler_thread.h"
6*635a8641SAndroid Build Coastguard Worker 
7*635a8641SAndroid Build Coastguard Worker #include <jni.h>
8*635a8641SAndroid Build Coastguard Worker 
9*635a8641SAndroid Build Coastguard Worker #include "base/android/jni_android.h"
10*635a8641SAndroid Build Coastguard Worker #include "base/android/jni_string.h"
11*635a8641SAndroid Build Coastguard Worker #include "base/bind.h"
12*635a8641SAndroid Build Coastguard Worker #include "base/run_loop.h"
13*635a8641SAndroid Build Coastguard Worker #include "base/synchronization/waitable_event.h"
14*635a8641SAndroid Build Coastguard Worker #include "base/threading/platform_thread_internal_posix.h"
15*635a8641SAndroid Build Coastguard Worker #include "base/threading/thread_restrictions.h"
16*635a8641SAndroid Build Coastguard Worker #include "jni/JavaHandlerThread_jni.h"
17*635a8641SAndroid Build Coastguard Worker 
18*635a8641SAndroid Build Coastguard Worker using base::android::AttachCurrentThread;
19*635a8641SAndroid Build Coastguard Worker 
20*635a8641SAndroid Build Coastguard Worker namespace base {
21*635a8641SAndroid Build Coastguard Worker 
22*635a8641SAndroid Build Coastguard Worker namespace android {
23*635a8641SAndroid Build Coastguard Worker 
JavaHandlerThread(const char * name,base::ThreadPriority priority)24*635a8641SAndroid Build Coastguard Worker JavaHandlerThread::JavaHandlerThread(const char* name,
25*635a8641SAndroid Build Coastguard Worker                                      base::ThreadPriority priority)
26*635a8641SAndroid Build Coastguard Worker     : JavaHandlerThread(Java_JavaHandlerThread_create(
27*635a8641SAndroid Build Coastguard Worker           AttachCurrentThread(),
28*635a8641SAndroid Build Coastguard Worker           ConvertUTF8ToJavaString(AttachCurrentThread(), name),
29*635a8641SAndroid Build Coastguard Worker           base::internal::ThreadPriorityToNiceValue(priority))) {}
30*635a8641SAndroid Build Coastguard Worker 
JavaHandlerThread(const base::android::ScopedJavaLocalRef<jobject> & obj)31*635a8641SAndroid Build Coastguard Worker JavaHandlerThread::JavaHandlerThread(
32*635a8641SAndroid Build Coastguard Worker     const base::android::ScopedJavaLocalRef<jobject>& obj)
33*635a8641SAndroid Build Coastguard Worker     : java_thread_(obj) {}
34*635a8641SAndroid Build Coastguard Worker 
~JavaHandlerThread()35*635a8641SAndroid Build Coastguard Worker JavaHandlerThread::~JavaHandlerThread() {
36*635a8641SAndroid Build Coastguard Worker   JNIEnv* env = base::android::AttachCurrentThread();
37*635a8641SAndroid Build Coastguard Worker   DCHECK(!Java_JavaHandlerThread_isAlive(env, java_thread_));
38*635a8641SAndroid Build Coastguard Worker   DCHECK(!message_loop_ || message_loop_->IsAborted());
39*635a8641SAndroid Build Coastguard Worker   // TODO(mthiesse): We shouldn't leak the MessageLoop as this could affect
40*635a8641SAndroid Build Coastguard Worker   // future tests.
41*635a8641SAndroid Build Coastguard Worker   if (message_loop_ && message_loop_->IsAborted()) {
42*635a8641SAndroid Build Coastguard Worker     // When the message loop has been aborted due to a crash, we intentionally
43*635a8641SAndroid Build Coastguard Worker     // leak the message loop because the message loop hasn't been shut down
44*635a8641SAndroid Build Coastguard Worker     // properly and would trigger DCHECKS. This should only happen in tests,
45*635a8641SAndroid Build Coastguard Worker     // where we handle the exception instead of letting it take down the
46*635a8641SAndroid Build Coastguard Worker     // process.
47*635a8641SAndroid Build Coastguard Worker     message_loop_.release();
48*635a8641SAndroid Build Coastguard Worker   }
49*635a8641SAndroid Build Coastguard Worker }
50*635a8641SAndroid Build Coastguard Worker 
Start()51*635a8641SAndroid Build Coastguard Worker void JavaHandlerThread::Start() {
52*635a8641SAndroid Build Coastguard Worker   // Check the thread has not already been started.
53*635a8641SAndroid Build Coastguard Worker   DCHECK(!message_loop_);
54*635a8641SAndroid Build Coastguard Worker 
55*635a8641SAndroid Build Coastguard Worker   JNIEnv* env = base::android::AttachCurrentThread();
56*635a8641SAndroid Build Coastguard Worker   base::WaitableEvent initialize_event(
57*635a8641SAndroid Build Coastguard Worker       WaitableEvent::ResetPolicy::AUTOMATIC,
58*635a8641SAndroid Build Coastguard Worker       WaitableEvent::InitialState::NOT_SIGNALED);
59*635a8641SAndroid Build Coastguard Worker   Java_JavaHandlerThread_startAndInitialize(
60*635a8641SAndroid Build Coastguard Worker       env, java_thread_, reinterpret_cast<intptr_t>(this),
61*635a8641SAndroid Build Coastguard Worker       reinterpret_cast<intptr_t>(&initialize_event));
62*635a8641SAndroid Build Coastguard Worker   // Wait for thread to be initialized so it is ready to be used when Start
63*635a8641SAndroid Build Coastguard Worker   // returns.
64*635a8641SAndroid Build Coastguard Worker   base::ThreadRestrictions::ScopedAllowWait wait_allowed;
65*635a8641SAndroid Build Coastguard Worker   initialize_event.Wait();
66*635a8641SAndroid Build Coastguard Worker }
67*635a8641SAndroid Build Coastguard Worker 
Stop()68*635a8641SAndroid Build Coastguard Worker void JavaHandlerThread::Stop() {
69*635a8641SAndroid Build Coastguard Worker   DCHECK(!task_runner()->BelongsToCurrentThread());
70*635a8641SAndroid Build Coastguard Worker   task_runner()->PostTask(
71*635a8641SAndroid Build Coastguard Worker       FROM_HERE,
72*635a8641SAndroid Build Coastguard Worker       base::BindOnce(&JavaHandlerThread::StopOnThread, base::Unretained(this)));
73*635a8641SAndroid Build Coastguard Worker   JNIEnv* env = base::android::AttachCurrentThread();
74*635a8641SAndroid Build Coastguard Worker   Java_JavaHandlerThread_joinThread(env, java_thread_);
75*635a8641SAndroid Build Coastguard Worker }
76*635a8641SAndroid Build Coastguard Worker 
InitializeThread(JNIEnv * env,const JavaParamRef<jobject> & obj,jlong event)77*635a8641SAndroid Build Coastguard Worker void JavaHandlerThread::InitializeThread(JNIEnv* env,
78*635a8641SAndroid Build Coastguard Worker                                          const JavaParamRef<jobject>& obj,
79*635a8641SAndroid Build Coastguard Worker                                          jlong event) {
80*635a8641SAndroid Build Coastguard Worker   // TYPE_JAVA to get the Android java style message loop.
81*635a8641SAndroid Build Coastguard Worker   message_loop_ =
82*635a8641SAndroid Build Coastguard Worker       std::make_unique<MessageLoopForUI>(base::MessageLoop::TYPE_JAVA);
83*635a8641SAndroid Build Coastguard Worker   Init();
84*635a8641SAndroid Build Coastguard Worker   reinterpret_cast<base::WaitableEvent*>(event)->Signal();
85*635a8641SAndroid Build Coastguard Worker }
86*635a8641SAndroid Build Coastguard Worker 
OnLooperStopped(JNIEnv * env,const JavaParamRef<jobject> & obj)87*635a8641SAndroid Build Coastguard Worker void JavaHandlerThread::OnLooperStopped(JNIEnv* env,
88*635a8641SAndroid Build Coastguard Worker                                         const JavaParamRef<jobject>& obj) {
89*635a8641SAndroid Build Coastguard Worker   DCHECK(task_runner()->BelongsToCurrentThread());
90*635a8641SAndroid Build Coastguard Worker   message_loop_.reset();
91*635a8641SAndroid Build Coastguard Worker   CleanUp();
92*635a8641SAndroid Build Coastguard Worker }
93*635a8641SAndroid Build Coastguard Worker 
StopMessageLoopForTesting()94*635a8641SAndroid Build Coastguard Worker void JavaHandlerThread::StopMessageLoopForTesting() {
95*635a8641SAndroid Build Coastguard Worker   DCHECK(task_runner()->BelongsToCurrentThread());
96*635a8641SAndroid Build Coastguard Worker   StopOnThread();
97*635a8641SAndroid Build Coastguard Worker }
98*635a8641SAndroid Build Coastguard Worker 
JoinForTesting()99*635a8641SAndroid Build Coastguard Worker void JavaHandlerThread::JoinForTesting() {
100*635a8641SAndroid Build Coastguard Worker   DCHECK(!task_runner()->BelongsToCurrentThread());
101*635a8641SAndroid Build Coastguard Worker   JNIEnv* env = base::android::AttachCurrentThread();
102*635a8641SAndroid Build Coastguard Worker   Java_JavaHandlerThread_joinThread(env, java_thread_);
103*635a8641SAndroid Build Coastguard Worker }
104*635a8641SAndroid Build Coastguard Worker 
ListenForUncaughtExceptionsForTesting()105*635a8641SAndroid Build Coastguard Worker void JavaHandlerThread::ListenForUncaughtExceptionsForTesting() {
106*635a8641SAndroid Build Coastguard Worker   DCHECK(!task_runner()->BelongsToCurrentThread());
107*635a8641SAndroid Build Coastguard Worker   JNIEnv* env = base::android::AttachCurrentThread();
108*635a8641SAndroid Build Coastguard Worker   Java_JavaHandlerThread_listenForUncaughtExceptionsForTesting(env,
109*635a8641SAndroid Build Coastguard Worker                                                                java_thread_);
110*635a8641SAndroid Build Coastguard Worker }
111*635a8641SAndroid Build Coastguard Worker 
GetUncaughtExceptionIfAny()112*635a8641SAndroid Build Coastguard Worker ScopedJavaLocalRef<jthrowable> JavaHandlerThread::GetUncaughtExceptionIfAny() {
113*635a8641SAndroid Build Coastguard Worker   DCHECK(!task_runner()->BelongsToCurrentThread());
114*635a8641SAndroid Build Coastguard Worker   JNIEnv* env = base::android::AttachCurrentThread();
115*635a8641SAndroid Build Coastguard Worker   return Java_JavaHandlerThread_getUncaughtExceptionIfAny(env, java_thread_);
116*635a8641SAndroid Build Coastguard Worker }
117*635a8641SAndroid Build Coastguard Worker 
StopOnThread()118*635a8641SAndroid Build Coastguard Worker void JavaHandlerThread::StopOnThread() {
119*635a8641SAndroid Build Coastguard Worker   DCHECK(task_runner()->BelongsToCurrentThread());
120*635a8641SAndroid Build Coastguard Worker   message_loop_->QuitWhenIdle(base::BindOnce(
121*635a8641SAndroid Build Coastguard Worker       &JavaHandlerThread::QuitThreadSafely, base::Unretained(this)));
122*635a8641SAndroid Build Coastguard Worker }
123*635a8641SAndroid Build Coastguard Worker 
QuitThreadSafely()124*635a8641SAndroid Build Coastguard Worker void JavaHandlerThread::QuitThreadSafely() {
125*635a8641SAndroid Build Coastguard Worker   DCHECK(task_runner()->BelongsToCurrentThread());
126*635a8641SAndroid Build Coastguard Worker   JNIEnv* env = base::android::AttachCurrentThread();
127*635a8641SAndroid Build Coastguard Worker   Java_JavaHandlerThread_quitThreadSafely(env, java_thread_,
128*635a8641SAndroid Build Coastguard Worker                                           reinterpret_cast<intptr_t>(this));
129*635a8641SAndroid Build Coastguard Worker }
130*635a8641SAndroid Build Coastguard Worker 
131*635a8641SAndroid Build Coastguard Worker } // namespace android
132*635a8641SAndroid Build Coastguard Worker } // namespace base
133