summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoey Grover <joeygrover@gmail.com>2019-09-12 12:09:55 -0400
committerJoey Grover <joeygrover@gmail.com>2019-09-12 12:09:55 -0400
commit45a61017af4b9af7ecd433b0cc77f945d9fe4792 (patch)
tree132733578a4b804b1de3211e6c2434b3c6325c3e
parentb619a5c567c53ba3f4009b5b12a3e9b596bc0289 (diff)
downloadsdl_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.java40
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);