1 package com.android.systemui.shared.system 2 3 import android.util.Log 4 import java.lang.Thread.UncaughtExceptionHandler 5 import java.util.concurrent.CopyOnWriteArrayList 6 import javax.inject.Inject 7 import javax.inject.Singleton 8 9 /** 10 * Sets the global (static var in Thread) uncaught exception pre-handler to an implementation that 11 * delegates to each item in a list of registered UncaughtExceptionHandlers. 12 */ 13 @Singleton 14 class UncaughtExceptionPreHandlerManager @Inject constructor() { 15 private val handlers: MutableList<UncaughtExceptionHandler> = CopyOnWriteArrayList() 16 private val globalUncaughtExceptionPreHandler = GlobalUncaughtExceptionHandler() 17 18 /** 19 * Adds an exception pre-handler to the list of handlers. If this has not yet set the global 20 * (static var in Thread) uncaught exception pre-handler yet, it will do so. 21 */ registerHandlernull22 fun registerHandler(handler: UncaughtExceptionHandler) { 23 checkGlobalHandlerSetup() 24 addHandler(handler) 25 } 26 27 /** 28 * Verifies that the global handler is set in Thread. If not, sets is up. 29 */ checkGlobalHandlerSetupnull30 private fun checkGlobalHandlerSetup() { 31 val currentHandler = Thread.getUncaughtExceptionPreHandler() 32 if (currentHandler != globalUncaughtExceptionPreHandler) { 33 if (currentHandler is GlobalUncaughtExceptionHandler) { 34 throw IllegalStateException("Two UncaughtExceptionPreHandlerManagers created") 35 } 36 currentHandler?.let { addHandler(it) } 37 Thread.setUncaughtExceptionPreHandler(globalUncaughtExceptionPreHandler) 38 } 39 } 40 41 /** 42 * Adds a handler if it has not already been added, preserving order. 43 */ addHandlernull44 private fun addHandler(it: UncaughtExceptionHandler) { 45 if (it !in handlers) { 46 handlers.add(it) 47 } 48 } 49 50 /** 51 * Calls uncaughtException on all registered handlers, catching and logging any new exceptions. 52 */ handleUncaughtExceptionnull53 fun handleUncaughtException(thread: Thread?, throwable: Throwable?) { 54 for (handler in handlers) { 55 try { 56 handler.uncaughtException(thread, throwable) 57 } catch (e: Exception) { 58 Log.wtf("Uncaught exception pre-handler error", e) 59 } 60 } 61 } 62 63 /** 64 * UncaughtExceptionHandler impl that will be set as Thread's pre-handler static variable. 65 */ 66 inner class GlobalUncaughtExceptionHandler : UncaughtExceptionHandler { uncaughtExceptionnull67 override fun uncaughtException(thread: Thread?, throwable: Throwable?) { 68 handleUncaughtException(thread, throwable) 69 } 70 } 71 }