Dissarming non-essential threads

I am looking into a general solution to the problem with crashing external libraries. Particularly thosed that are installed on the device and not the app so that they are outside the control of the app developer.

The problem is that when an external library crashes because of an unhandled exception it will cause the entire app to crash.

The assumption is that there are two types of tasks carried out by external libraries. The first is the essential task and here the application is able to explicitly verify weather something has failed or not and deal with it. The second type is the non-essential task where your app will function adequately even without that functionality. Of course there may be essential tasks that it is difficult to determine weather there was a failure or not, but this attempted solution does not address that problem.

A non-essential task is a task that it is better to live without then to crash the whole app. Such
- Some specific ad that doesn’t load.
- Some service like automatical sharing of game progress on social networks.
- Bug reporting, telemetry and diagnostics ( you can get this information in another way than as an app crash ).

You want to avoid that user getting locked out of your app.


        import java.lang.Thread.UncaughtExceptionHandler;
	import java.util.ArrayList;
	import java.util.List;

	import android.os.Looper;
	import android.util.Log;

	public class EssentialThreads {

		UncaughtExceptionHandler defaultHandler ;
		final List<Thread> threads ;
		
		public EssentialThreads() {
			threads = new ArrayList<Thread>() ;
		}

		void install() {
	        defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
	        Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {

	            @Override
	            public void uncaughtException( Thread thread, Throwable throwable ) {
	            	if ( !threads.contains( thread ) ) {
	                	Log.e( "EssentialThreads", "UncaughtException in " + thread.getName(), throwable ) ;
	                } else if ( defaultHandler != null ) {
	                    defaultHandler.uncaughtException( thread, throwable ) ;
	                } else {
	                    throw new RuntimeException( "No default uncaught exception handler.", throwable ) ;
	                }
	            }
	        });
		}

		void uninstall() {
	        Thread.setDefaultUncaughtExceptionHandler( defaultHandler ) ;
	        defaultHandler = null ;
		}
		
		Thread getCurrentThread() {
			return Looper.getMainLooper().getThread() ;
		}
		
		void register( Thread thread ) {
		    threads.add( thread ) ;
		}

		void registerCurrent() {
			register( getCurrentThread() ) ;
		}

		void unregister( Thread thread ) {
			threads.remove( thread ) ;
		}

		void unregisterCurrent() {
			unregister( getCurrentThread() ) ;
		}
		
	}


EssentialThreads makes sure only an unhandled exception in an essential thread can crash your app. If there is an unhandled exception in a non-essential thread it is logged as an error with a stack trace.
This can be activated early on in the app, for example Activity.onCreate():


        EssentialTreads essentialThreads = new essentialThreads() ;
        essentialThreads.install() ;
        essentialThreads.registerCurrent() ;

Newly created threads can then be registered and unregistered as neccesary. It may be neccesary in some situations to verify more carefully weather some external task has been successfull, for example a failed thread my leave a null pointer or other uninitialized data in an app where it normally wouldn’t occur.

This solves the problem mentioned here https://groups.google.com/forum/#!topic/google-admob-ads-sdk/DkjtCx_Zvn8. The code itself is a generalization of a solution mentioned in the same thread.

The reason I am making a big deal about this is that I want to use this in my app, but I cannot claim to fully understand the consequences. I understand that this can potentially be a catastropic and nasty hack. So, what are the pro’s and con’s of this kind of solution?

How can this code be improved? Is there a better way to differenciate between essential and non-essential threads?

Is there a better tag for the error message than “EssentialThreads”?

Also, there may be all sorts of opinion views on this kind of hack. I’m only interested in the technical stuff.