Skip to content

Fix unhandled exceptions in BrowserTabRouteDecisionHandler and SystemNavigationRouteDecisionHandler#191

Open
noah44846 wants to merge 1 commit intohotwired:mainfrom
noah44846:fix/route-decision-handler-unhandled-exceptions
Open

Fix unhandled exceptions in BrowserTabRouteDecisionHandler and SystemNavigationRouteDecisionHandler#191
noah44846 wants to merge 1 commit intohotwired:mainfrom
noah44846:fix/route-decision-handler-unhandled-exceptions

Conversation

@noah44846
Copy link
Copy Markdown

Hi! We ran into two crashes in our production app that both stem from unhandled exceptions in route decision handlers. Sharing the stack traces below in case they're useful — happy to adjust anything if the fix looks different to you.

BrowserTabRouteDecisionHandler throws ActivityNotFoundException when CustomTabsIntent.launchUrl finds no browser with Custom Tabs support installed. This can happen on locked-down or minimal devices.

SystemNavigationRouteDecisionHandler already catches ActivityNotFoundException, but not SecurityException, which is thrown when the target activity exists but is not accessible — e.g. android:exported="false" or a permission requirement the calling app doesn't satisfy. This can happen with deep links targeting third-party apps with restricted activities.

Both cases now log the error and return CANCEL instead of crashing.


Stack trace 1 — ActivityNotFoundException in BrowserTabRouteDecisionHandler:

Exception org.chromium.base.JniAndroid$UncaughtExceptionException:
  at org.chromium.base.JniAndroid.handleException (chromium-SystemWebViewGoogle6432.aab-stable-763207903:21)
  at android.os.MessageQueue.nativePollOnce
  at android.os.MessageQueue.next (MessageQueue.java:346)
  at android.os.Looper.loopOnce (Looper.java:214)
  at android.os.Looper.loop (Looper.java:342)
  at android.app.ActivityThread.main (ActivityThread.java:9634)
  at java.lang.reflect.Method.invoke
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:619)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:929)
Caused by android.content.ActivityNotFoundException:
  at android.app.Instrumentation.checkStartActivityResult (Instrumentation.java:2443)
  at android.app.Instrumentation.execStartActivity (Instrumentation.java:2005)
  at android.app.Activity.startActivityForResult (Activity.java:6043)
  at androidx.activity.ComponentActivity.startActivityForResult (ComponentActivity.kt:694)
  at android.app.Activity.startActivity (Activity.java:6494)
  at androidx.core.content.ContextCompat.startActivity (ContextCompat.java)
  at androidx.browser.customtabs.CustomTabsIntent.launchUrl (CustomTabsIntent.java:662)
  at dev.hotwire.navigation.routing.BrowserTabRouteDecisionHandler.handle (BrowserTabRouteDecisionHandler.kt:48)
  at dev.hotwire.navigation.routing.Router.decideRoute$navigation_fragments_release (Router.kt:70)
  at dev.hotwire.navigation.navigator.Navigator.getRouteDecision (Navigator.kt:429)
  at dev.hotwire.navigation.navigator.Navigator.route (Navigator.kt:141)
  at dev.hotwire.navigation.navigator.Navigator.route$default (Navigator.kt:134)
  at dev.hotwire.navigation.fragments.HotwireWebFragmentDelegate.visitProposedToLocation (HotwireWebFragmentDelegate.kt:257)
  at dev.hotwire.core.turbo.session.Session.visitProposedToLocation$lambda$0 (r8-map-id-8953dcc4730f437e1589552f5d1f4c8962afcd4e2cae4fdbe400ef7f2e0b5d64:1)
  at dev.hotwire.core.turbo.session.Session.callback$lambda$0 (r8-map-id-8953dcc4730f437e1589552f5d1f4c8962afcd4e2cae4fdbe400ef7f2e0b5d64:3)
  at dev.hotwire.core.turbo.util.CoreExtensionsKt.runOnUiThread (r8-map-id-8953dcc4730f437e1589552f5d1f4c8962afcd4e2cae4fdbe400ef7f2e0b5d64:2)
  at dev.hotwire.core.turbo.session.Session.callback (r8-map-id-8953dcc4730f437e1589552f5d1f4c8962afcd4e2cae4fdbe400ef7f2e0b5d64:1)
  at dev.hotwire.core.turbo.session.Session.visitProposedToLocation (r8-map-id-8953dcc4730f437e1589552f5d1f4c8962afcd4e2cae4fdbe400ef7f2e0b5d64:4)
  at dev.hotwire.core.turbo.webview.HotwireWebChromeClient.onCreateWindow (r8-map-id-8953dcc4730f437e1589552f5d1f4c8962afcd4e2cae4fdbe400ef7f2e0b5d64:8)
  at WV.um.addNewContents (chromium-SystemWebViewGoogle6432.aab-stable-763207903:39)

Stack trace 2 — SecurityException in SystemNavigationRouteDecisionHandler:

Exception java.lang.SecurityException:
  at android.os.Parcel.createExceptionOrNull (Parcel.java:2386)
  at android.os.Parcel.createException (Parcel.java:2370)
  at android.os.Parcel.readException (Parcel.java:2353)
  at android.os.Parcel.readException (Parcel.java:2295)
  at android.app.IActivityTaskManager$Stub$Proxy.startActivity (IActivityTaskManager.java:4276)
  at android.app.Instrumentation.execStartActivity (Instrumentation.java:1723)
  at android.app.Activity.startActivityForResult (Activity.java:5377)
  at androidx.activity.ComponentActivity.startActivityForResult (ComponentActivity.kt:694)
  at android.app.Activity.startActivityForResult (Activity.java:5335)
  at androidx.activity.ComponentActivity.startActivityForResult (ComponentActivity.kt:679)
  at android.app.Activity.startActivity (Activity.java:5721)
  at android.app.Activity.startActivity (Activity.java:5674)
  at dev.hotwire.navigation.routing.SystemNavigationRouteDecisionHandler.handle (SystemNavigationRouteDecisionHandler.kt:31)
  at dev.hotwire.navigation.routing.Router.decideRoute$navigation_fragments_release (Router.kt:70)
  at dev.hotwire.navigation.navigator.Navigator.getRouteDecision (Navigator.kt:429)
  at dev.hotwire.navigation.navigator.Navigator.route (Navigator.kt:141)
  at dev.hotwire.navigation.navigator.Navigator.route$default (Navigator.kt:134)
  at dev.hotwire.navigation.fragments.HotwireWebFragmentDelegate.visitProposedToLocation (HotwireWebFragmentDelegate.kt:257)
  at dev.hotwire.core.turbo.session.Session.visitProposedToLocation$lambda$0 (r8-map-id-8953dcc4730f437e1589552f5d1f4c8962afcd4e2cae4fdbe400ef7f2e0b5d64:1)
  at dev.hotwire.core.turbo.session.Session.callback$lambda$0 (r8-map-id-8953dcc4730f437e1589552f5d1f4c8962afcd4e2cae4fdbe400ef7f2e0b5d64:3)
  at dev.hotwire.core.turbo.util.CoreExtensionsKt.runOnUiThread (r8-map-id-8953dcc4730f437e1589552f5d1f4c8962afcd4e2cae4fdbe400ef7f2e0b5d64:2)
  at dev.hotwire.core.turbo.session.Session.callback (r8-map-id-8953dcc4730f437e1589552f5d1f4c8962afcd4e2cae4fdbe400ef7f2e0b5d64:1)
  at dev.hotwire.core.turbo.session.Session.visitProposedToLocation (r8-map-id-8953dcc4730f437e1589552f5d1f4c8962afcd4e2cae4fdbe400ef7f2e0b5d64:4)
  at dev.hotwire.core.turbo.session.Session$TurboWebViewClient.shouldOverrideUrlLoading (r8-map-id-8953dcc4730f437e1589552f5d1f4c8962afcd4e2cae4fdbe400ef7f2e0b5d64:21)
  at java.lang.reflect.Method.invoke
  at WV.kr.invoke (chromium-SystemWebViewGoogle6432.aab-stable-763208003:15)
  at java.lang.reflect.Proxy.invoke (Proxy.java:1006)
  at $Proxy6.shouldOverrideUrlLoading (Unknown Source)
  at org.chromium.android_webview.AwContentsClientBridge.shouldOverrideUrlLoading (chromium-SystemWebViewGoogle6432.aab-stable-763208003:102)
  at android.os.MessageQueue.nativePollOnce
  at android.os.MessageQueue.next (MessageQueue.java:335)
  at android.os.Looper.loop (Looper.java:206)
  at android.app.ActivityThread.main (ActivityThread.java:8653)
  at java.lang.reflect.Method.invoke
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:602)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1130)
Caused by android.os.RemoteException: Remote stack trace:
  at com.android.server.wm.ActivityStackSupervisor.checkStartAnyActivityPermission (ActivityStackSupervisor.java:1344)
  at com.android.server.wm.ActivityStarter.executeRequest (ActivityStarter.java:1263)
  at com.android.server.wm.ActivityStarter.execute (ActivityStarter.java:897)
  at com.android.server.wm.ActivityTaskManagerService.startActivityAsUser (ActivityTaskManagerService.java:1721)
  at com.android.server.wm.ActivityTaskManagerService.startActivityAsUser (ActivityTaskManagerService.java:1571)

BrowserTabRouteDecisionHandler: catch ActivityNotFoundException when no
browser with Custom Tabs support is installed on the device.

SystemNavigationRouteDecisionHandler: catch SecurityException in addition
to the existing ActivityNotFoundException — thrown when the target
activity is found but not accessible, e.g. android:exported="false" or
a permission requirement the calling app does not satisfy.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant