• 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 package org.chromium.base;
6 
7 import android.os.Build;
8 import android.os.Handler;
9 import android.os.HandlerThread;
10 import android.os.Looper;
11 
12 import org.chromium.base.annotations.CalledByNative;
13 import org.chromium.base.annotations.JNINamespace;
14 import org.chromium.base.annotations.MainDex;
15 
16 import java.lang.Thread.UncaughtExceptionHandler;
17 
18 /**
19  * Thread in Java with an Android Handler. This class is not thread safe.
20  */
21 @JNINamespace("base::android")
22 @MainDex
23 public class JavaHandlerThread {
24     private final HandlerThread mThread;
25 
26     private Throwable mUnhandledException;
27 
28     /**
29      * Construct a java-only instance. Can be connected with native side later.
30      * Useful for cases where a java thread is needed before native library is loaded.
31      */
JavaHandlerThread(String name, int priority)32     public JavaHandlerThread(String name, int priority) {
33         mThread = new HandlerThread(name, priority);
34     }
35 
36     @CalledByNative
create(String name, int priority)37     private static JavaHandlerThread create(String name, int priority) {
38         return new JavaHandlerThread(name, priority);
39     }
40 
getLooper()41     public Looper getLooper() {
42         assert hasStarted();
43         return mThread.getLooper();
44     }
45 
maybeStart()46     public void maybeStart() {
47         if (hasStarted()) return;
48         mThread.start();
49     }
50 
51     @CalledByNative
startAndInitialize(final long nativeThread, final long nativeEvent)52     private void startAndInitialize(final long nativeThread, final long nativeEvent) {
53         maybeStart();
54         new Handler(mThread.getLooper()).post(new Runnable() {
55             @Override
56             public void run() {
57                 nativeInitializeThread(nativeThread, nativeEvent);
58             }
59         });
60     }
61 
62     @CalledByNative
quitThreadSafely(final long nativeThread)63     private void quitThreadSafely(final long nativeThread) {
64         // Allow pending java tasks to run, but don't run any delayed or newly queued up tasks.
65         new Handler(mThread.getLooper()).post(new Runnable() {
66             @Override
67             public void run() {
68                 mThread.quit();
69                 nativeOnLooperStopped(nativeThread);
70             }
71         });
72         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
73             // When we can, signal that new tasks queued up won't be run.
74             mThread.getLooper().quitSafely();
75         }
76     }
77 
78     @CalledByNative
joinThread()79     private void joinThread() {
80         boolean joined = false;
81         while (!joined) {
82             try {
83                 mThread.join();
84                 joined = true;
85             } catch (InterruptedException e) {
86             }
87         }
88     }
89 
hasStarted()90     private boolean hasStarted() {
91         return mThread.getState() != Thread.State.NEW;
92     }
93 
94     @CalledByNative
isAlive()95     private boolean isAlive() {
96         return mThread.isAlive();
97     }
98 
99     // This should *only* be used for tests. In production we always need to call the original
100     // uncaught exception handler (the framework's) after any uncaught exception handling we do, as
101     // it generates crash dumps and kills the process.
102     @CalledByNative
listenForUncaughtExceptionsForTesting()103     private void listenForUncaughtExceptionsForTesting() {
104         mThread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
105             @Override
106             public void uncaughtException(Thread t, Throwable e) {
107                 mUnhandledException = e;
108             }
109         });
110     }
111 
112     @CalledByNative
getUncaughtExceptionIfAny()113     private Throwable getUncaughtExceptionIfAny() {
114         return mUnhandledException;
115     }
116 
nativeInitializeThread(long nativeJavaHandlerThread, long nativeEvent)117     private native void nativeInitializeThread(long nativeJavaHandlerThread, long nativeEvent);
nativeOnLooperStopped(long nativeJavaHandlerThread)118     private native void nativeOnLooperStopped(long nativeJavaHandlerThread);
119 }
120