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