I'm using code from Extending the Service class to handle messaging in two Services and in another class (that's not a Service).
Below is the code that initializes and gets the suspicious objects (one thread each in onCreate() in the Services, and 2 threads in a static method in the other class). Nowhere is thread.run() explicitly called (as it shouldn't be, but I know that I can make the crash happen by calling it after calling thread.start() but not by calling thread.start() twice). While this code is taken from the Android documentation, I've only altered some of the variable names in my implementation. The same is true of the message-handling code that relies on this.
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
Here's the stacktrace. Unfortunately, there's nothing indicating which implementation in my code is the offender, and I'm not able to reproduce the crash.
Fatal Exception: java.lang.RuntimeException: Only one Looper may be created per thread
at android.os.Looper.prepare(Looper.java:89)
at android.os.Looper.prepare(Looper.java:84)
at android.os.HandlerThread.run(HandlerThread.java:54)
06-15 06:23:18.599 27561-29056/? E/BluetoothBoundService﹕ Interrupted
read:
java.lang.InterruptedException
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:371)
at java.lang.Thread.sleep(Thread.java:313)
at services.BluetoothBoundService.receiveDataFromBT
(BluetoothBoundService.java:1442)
at
services.BluetoothBoundService.access$2700(BluetoothBoundService.java:147)
at services.BluetoothBoundService$9.run(BluetoothBoundService.java:1173)
at java.lang.Thread.run(Thread.java:761)
06-15 06:23:18.898 28954-28975/? E/BluetoothRemoteDevices﹕
state12newState1
06-15 06:23:23.469 27561-27570/? E/System﹕ Uncaught exception thrown by
finalizer
06-15 06:23:23.470 27561-27570/? E/System﹕ java.io.IOException: socket
not created
at android.net.LocalSocketImpl.shutdownInput(LocalSocketImpl.java:404)
at android.net.LocalSocket.shutdownInput(LocalSocket.java:207)
at android.bluetooth.BluetoothSocket.close(BluetoothSocket.java:575)
at android.bluetooth.BluetoothSocket.finalize(BluetoothSocket.java:273)
at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:222)
at java.lang.Daemons$FinalizerDaemon.run(Daemons.java:209)
at java.lang.Thread.run(Thread.java:761)
06-15 06:23:24.112 15861-15861/? E/SearchServiceStarter﹕ Task 174 failed
or timed out. Client 69758913221593243 disconnecting from SearchService!
java.util.concurrent.CancellationException: Task was cancelled.
at com.google.common.util.concurrent.d.ct(SourceFile:75)
at com.google.common.util.concurrent.d.get(SourceFile:57)
at com.google.common.util.concurrent.cg.n(SourceFile:2)
at com.google.common.util.concurrent.av.l(SourceFile:50)
at com.google.common.util.concurrent.ax.run(SourceFile:5)
at
com.google.android.apps.gsa.shared.util.concurrent.a.bc.run(SourceFile:2)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at
com.android....ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
06-15 06:23:24.144 15861-15861/? E/WorkerRegistryImpl﹕ getWorker() is
called after WorkerRegistry disposal.
06-15 06:23:24.153 15861-15861/? E/WorkerRegistryImpl﹕ getWorker() is
called after WorkerRegistry disposal.
06-15 06:23:34.229 15861-15861/? E/SearchServiceStarter﹕ Task 174 failed
or timed out. Client 69758913221593244 disconnecting from SearchService!
java.util.concurrent.CancellationException: Task was cancelled.
at com.google.common.util.concurrent.d.ct(SourceFile:75)
at com.google.common.util.concurrent.d.get(SourceFile:57)
at com.google.common.util.concurrent.cg.n(SourceFile:2)
at com.google.common.util.concurrent.av.l(SourceFile:50)
at com.google.common.util.concurrent.ax.run(SourceFile:5)
at
com.google.android.apps.gsa.shared.util.concurrent.a.bc.run(SourceFile:2)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(Zy
It seems that somehow and somewhy Android is calling thread.run() when it shouldn't be, but I don't know how to tell what's triggering that. I've looked at the other questions and answers that propose overriding run() to prevent this from happening (for example https://stackoverflow.com/a/24115631/1493426), but I don't see how to do that by extending HandlerThread in a reasonable way that won't have undesirable, unintended consequences.
For now I'm inclined to leave everyting alone, since the code has been around for at least several months, and this crash has only been seen once, but I'd like to know if there's a safe way to make the code more crash proof without hiding any underlying problems.