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