diff options
author | Joey Grover <joeygrover@gmail.com> | 2019-09-12 12:09:55 -0400 |
---|---|---|
committer | Joey Grover <joeygrover@gmail.com> | 2019-09-12 12:09:55 -0400 |
commit | 45a61017af4b9af7ecd433b0cc77f945d9fe4792 (patch) | |
tree | 132733578a4b804b1de3211e6c2434b3c6325c3e | |
parent | b619a5c567c53ba3f4009b5b12a3e9b596bc0289 (diff) | |
download | sdl_android-hotfix/issue_1167.tar.gz |
Add setForegroundExceptionHandler to prevent ANRhotfix/issue_1167
-rw-r--r-- | android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java | 40 |
1 files changed, 38 insertions, 2 deletions
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java b/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java index 5bd9bdbca..590f9c12f 100644 --- a/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java +++ b/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java @@ -45,7 +45,9 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.hardware.usb.UsbManager; import android.os.Build; +import android.os.Looper; import android.os.Parcelable; +import android.util.AndroidRuntimeException; import android.util.Log; import com.smartdevicelink.R; @@ -82,7 +84,8 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver{ private static final Object QUEUED_SERVICE_LOCK = new Object(); private static ComponentName queuedService = null; - + private static Thread.UncaughtExceptionHandler foregroundExceptionHandler = null; + public int getRouterServiceVersion(){ return SdlRouterService.ROUTER_SERVICE_VERSION_NUMBER; } @@ -217,7 +220,7 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver{ } private boolean wakeUpRouterService(final Context context, final boolean ping, final boolean altTransportWake, final BluetoothDevice device){ - new ServiceFinder(context, context.getPackageName(), new ServiceFinder.ServiceFinderCallback() { + new ServiceFinder(context, context.getPackageName(), new ServiceFinder.ServiceFinderCallback() { @Override public void onComplete(Vector<ComponentName> routerServices) { runningBluetoothServicePackage = new Vector<ComponentName>(); @@ -247,6 +250,7 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver{ }else { serviceIntent.putExtra(FOREGROUND_EXTRA, true); DebugTool.logInfo("Attempting to startForegroundService - " + System.currentTimeMillis()); + setForegroundExceptionHandler(); //Prevent ANR in case the OS takes too long to start the service context.startForegroundService(serviceIntent); } @@ -287,6 +291,37 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver{ } /** + * This method will set a new UncaughtExceptionHandler for the current thread. The only + * purpose of the custom UncaughtExceptionHandler is to catch the rare occurrence that the + * SdlRouterService can't be started fast enough by the system after calling + * startForegroundService so the onCreate method doesn't get called before the foreground promise + * timer expires. The new UncaughtExceptionHandler will catch that specific exception and tell the + * main looper to continue forward. This still leaves the SdlRouterService killed, but prevents + * an ANR to the app that makes the startForegroundService call. + */ + static private void setForegroundExceptionHandler() { + final Thread.UncaughtExceptionHandler defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler(); + if(defaultUncaughtExceptionHandler != foregroundExceptionHandler){ + foregroundExceptionHandler = new Thread.UncaughtExceptionHandler() { + @Override + public void uncaughtException(Thread t, Throwable e) { + if (e != null + && e instanceof AndroidRuntimeException + && "android.app.RemoteServiceException".equals(e.getClass().getName()) //android.app.RemoteServiceException is a private class + && e.getMessage().contains("SdlRouterService")) { + + Log.i(TAG, "Handling failed startForegroundService call"); + Looper.loop(); + } else if (defaultUncaughtExceptionHandler != null) { //No other exception should be handled + defaultUncaughtExceptionHandler.uncaughtException(t, e); + } + } + }; + Thread.setDefaultUncaughtExceptionHandler(foregroundExceptionHandler); + } + } + + /** * Determines if an instance of the Router Service is currently running on the device.<p> * <b>Note:</b> This method no longer works on Android Oreo or newer * @param context A context to access Android system services through. @@ -343,6 +378,7 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver{ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){ intent.putExtra(FOREGROUND_EXTRA, true); DebugTool.logInfo("Attempting to startForegroundService - " + System.currentTimeMillis()); + setForegroundExceptionHandler(); //Prevent ANR in case the OS takes too long to start the service context.startForegroundService(intent); }else { context.startService(intent); |