Android WebView Crash in Jetpack Compose

Recently I had an issue reported on an app of mine, SimpleMarkdown, where the app would crash when tapping on a menu item from the navigation drawer. I unfortunately wasn't able to reproduce the issue on my personal device, a Pixel 7 at the time of writing, but I got a couple of other reports on the same issue and via the reviews on the Play Store1. I also wasn't seeing the crash in any of my automated tests that run on Firebase Test Lab for each pull request. One user affected by the crash asked if I was able to reproduce the issue in an emulator, so I figured I'd give it a shot2, and sure enough, the app crashed. Much to my dismay, the error message was entirely unhelpful though:

Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x28 in tid 12327 (RenderThread), pid 12254 (lemarkdown.free)
Cmdline: com.wbrawner.simplemarkdown.free
pid: 12254, tid: 12327, name: RenderThread  >>> com.wbrawner.simplemarkdown.free <<<

Some kind of native crash (yay) and not a whole lot to work with. I was tempted to just throw my hands up and say "maybe a future release of Android/Jetpack Compose will solve this", but I didn't know how many users would be affected by this and given that it was following a pretty major release, I figured I should at least investigate a little. I needed some more information though, so I tried removing the package:mine filter from logcat in Android Studio, and there I did in fact get some more information, though still not quite actionable:

The full native backtrace
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'google/sdk_gphone64_x86_64/emu64xa:15/AP31.240617.003/12088229:user/release-keys'
Revision: '0'
ABI: 'x86_64'
Timestamp: 2024-08-28 21:29:05.474897959-0600
Process uptime: 222s
Cmdline: com.wbrawner.simplemarkdown.free
pid: 12254, tid: 12327, name: RenderThread  >>> com.wbrawner.simplemarkdown.free <<<
uid: 10251
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0000000000000028
Cause: null pointer dereference
    rax 00007d21f6e2d4e0  rbx 0000000000000000  rcx 0000000000000000  rdx 0000000000000002
    r8  0000000000000001  r9  0000000000000000  r10 0000000000000000  r11 0000000000000000
    r12 00007d21f6e2d5c0  r13 0000000000000000  r14 0000000000000000  r15 00007d21f6e2d4e0
    rdi 0000000000000000  rsi 00007d21f6e2d2d8
    rbp 0000000000000000  rsp 00007d21f6e2d3e8  rip 00007d2514e24820
55 total frames
backtrace:
      #00 pc 0000000000424820  /system/lib64/libhwui.so (SkSurface::getCanvas()+0) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #01 pc 00000000002a2a90  /system/lib64/libhwui.so (android::uirenderer::skiapipeline::GLFunctorDrawable::onDraw(SkCanvas*)+1216) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #02 pc 000000000033a429  /system/lib64/libhwui.so (SkDrawable::draw(SkCanvas*, SkMatrix const*)+105) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #03 pc 000000000055af68  /system/lib64/libhwui.so (skgpu::ganesh::Device::drawDrawable(SkCanvas*, SkDrawable*, SkMatrix const*)+392) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #04 pc 0000000000289634  /system/lib64/libhwui.so (android::uirenderer::$_37::__invoke(void const*, SkCanvas*, SkMatrix const&) (.__uniq.150848978645254602633048518174355561839)+132) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #05 pc 0000000000285b26  /system/lib64/libhwui.so (android::uirenderer::DisplayListData::draw(SkCanvas*) const+182) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #06 pc 0000000000250eec  /system/lib64/libhwui.so (android::uirenderer::skiapipeline::RenderNodeDrawable::drawContent(SkCanvas*) const+1068) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #07 pc 0000000000251774  /system/lib64/libhwui.so (android::uirenderer::skiapipeline::RenderNodeDrawable::forceDraw(SkCanvas*) const+276) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #08 pc 000000000033a429  /system/lib64/libhwui.so (SkDrawable::draw(SkCanvas*, SkMatrix const*)+105) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #09 pc 0000000000285b26  /system/lib64/libhwui.so (android::uirenderer::DisplayListData::draw(SkCanvas*) const+182) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #10 pc 0000000000250eec  /system/lib64/libhwui.so (android::uirenderer::skiapipeline::RenderNodeDrawable::drawContent(SkCanvas*) const+1068) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #11 pc 0000000000251774  /system/lib64/libhwui.so (android::uirenderer::skiapipeline::RenderNodeDrawable::forceDraw(SkCanvas*) const+276) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #12 pc 000000000033a429  /system/lib64/libhwui.so (SkDrawable::draw(SkCanvas*, SkMatrix const*)+105) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #13 pc 0000000000285b26  /system/lib64/libhwui.so (android::uirenderer::DisplayListData::draw(SkCanvas*) const+182) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #14 pc 0000000000250eec  /system/lib64/libhwui.so (android::uirenderer::skiapipeline::RenderNodeDrawable::drawContent(SkCanvas*) const+1068) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #15 pc 0000000000251774  /system/lib64/libhwui.so (android::uirenderer::skiapipeline::RenderNodeDrawable::forceDraw(SkCanvas*) const+276) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #16 pc 000000000033a429  /system/lib64/libhwui.so (SkDrawable::draw(SkCanvas*, SkMatrix const*)+105) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #17 pc 0000000000285b26  /system/lib64/libhwui.so (android::uirenderer::DisplayListData::draw(SkCanvas*) const+182) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #18 pc 0000000000250eec  /system/lib64/libhwui.so (android::uirenderer::skiapipeline::RenderNodeDrawable::drawContent(SkCanvas*) const+1068) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #19 pc 0000000000251774  /system/lib64/libhwui.so (android::uirenderer::skiapipeline::RenderNodeDrawable::forceDraw(SkCanvas*) const+276) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #20 pc 000000000033a429  /system/lib64/libhwui.so (SkDrawable::draw(SkCanvas*, SkMatrix const*)+105) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #21 pc 0000000000285b26  /system/lib64/libhwui.so (android::uirenderer::DisplayListData::draw(SkCanvas*) const+182) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #22 pc 0000000000250eec  /system/lib64/libhwui.so (android::uirenderer::skiapipeline::RenderNodeDrawable::drawContent(SkCanvas*) const+1068) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #23 pc 0000000000251774  /system/lib64/libhwui.so (android::uirenderer::skiapipeline::RenderNodeDrawable::forceDraw(SkCanvas*) const+276) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #24 pc 000000000033a429  /system/lib64/libhwui.so (SkDrawable::draw(SkCanvas*, SkMatrix const*)+105) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #25 pc 0000000000285b26  /system/lib64/libhwui.so (android::uirenderer::DisplayListData::draw(SkCanvas*) const+182) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #26 pc 0000000000250eec  /system/lib64/libhwui.so (android::uirenderer::skiapipeline::RenderNodeDrawable::drawContent(SkCanvas*) const+1068) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #27 pc 0000000000251774  /system/lib64/libhwui.so (android::uirenderer::skiapipeline::RenderNodeDrawable::forceDraw(SkCanvas*) const+276) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #28 pc 000000000033a429  /system/lib64/libhwui.so (SkDrawable::draw(SkCanvas*, SkMatrix const*)+105) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #29 pc 0000000000285b26  /system/lib64/libhwui.so (android::uirenderer::DisplayListData::draw(SkCanvas*) const+182) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #30 pc 0000000000250eec  /system/lib64/libhwui.so (android::uirenderer::skiapipeline::RenderNodeDrawable::drawContent(SkCanvas*) const+1068) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #31 pc 0000000000251774  /system/lib64/libhwui.so (android::uirenderer::skiapipeline::RenderNodeDrawable::forceDraw(SkCanvas*) const+276) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #32 pc 000000000033a429  /system/lib64/libhwui.so (SkDrawable::draw(SkCanvas*, SkMatrix const*)+105) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #33 pc 0000000000285b26  /system/lib64/libhwui.so (android::uirenderer::DisplayListData::draw(SkCanvas*) const+182) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #34 pc 0000000000250eec  /system/lib64/libhwui.so (android::uirenderer::skiapipeline::RenderNodeDrawable::drawContent(SkCanvas*) const+1068) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #35 pc 0000000000251774  /system/lib64/libhwui.so (android::uirenderer::skiapipeline::RenderNodeDrawable::forceDraw(SkCanvas*) const+276) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #36 pc 000000000033a429  /system/lib64/libhwui.so (SkDrawable::draw(SkCanvas*, SkMatrix const*)+105) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #37 pc 0000000000285b26  /system/lib64/libhwui.so (android::uirenderer::DisplayListData::draw(SkCanvas*) const+182) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #38 pc 0000000000250eec  /system/lib64/libhwui.so (android::uirenderer::skiapipeline::RenderNodeDrawable::drawContent(SkCanvas*) const+1068) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #39 pc 0000000000251774  /system/lib64/libhwui.so (android::uirenderer::skiapipeline::RenderNodeDrawable::forceDraw(SkCanvas*) const+276) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #40 pc 000000000033a429  /system/lib64/libhwui.so (SkDrawable::draw(SkCanvas*, SkMatrix const*)+105) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #41 pc 0000000000285b26  /system/lib64/libhwui.so (android::uirenderer::DisplayListData::draw(SkCanvas*) const+182) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #42 pc 0000000000250eec  /system/lib64/libhwui.so (android::uirenderer::skiapipeline::RenderNodeDrawable::drawContent(SkCanvas*) const+1068) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #43 pc 0000000000251774  /system/lib64/libhwui.so (android::uirenderer::skiapipeline::RenderNodeDrawable::forceDraw(SkCanvas*) const+276) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #44 pc 0000000000248e1a  /system/lib64/libhwui.so (android::uirenderer::skiapipeline::SkiaPipeline::renderLayerImpl(android::uirenderer::RenderNode*, android::uirenderer::Rect const&)+442) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #45 pc 00000000002a48e3  /system/lib64/libhwui.so (android::uirenderer::skiapipeline::SkiaGpuPipeline::renderLayersImpl(android::uirenderer::LayerUpdateQueue const&, bool)+147) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #46 pc 0000000000249a69  /system/lib64/libhwui.so (android::uirenderer::skiapipeline::SkiaPipeline::renderFrame(android::uirenderer::LayerUpdateQueue const&, SkRect const&, std::__1::vector<android::sp<android::uirenderer::RenderNode>, std::__1::allocator<android::sp<android::uirenderer::RenderNode>>> const&, bool, android::uirenderer::Rect const&, sk_sp<SkSurface>, SkMatrix const&)+601) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #47 pc 00000000002a925e  /system/lib64/libhwui.so (android::uirenderer::skiapipeline::SkiaOpenGLPipeline::draw(android::uirenderer::renderthread::Frame const&, SkRect const&, SkRect const&, android::uirenderer::LightGeometry const&, android::uirenderer::LayerUpdateQueue*, android::uirenderer::Rect const&, bool, android::uirenderer::LightInfo const&, std::__1::vector<android::sp<android::uirenderer::RenderNode>, std::__1::allocator<android::sp<android::uirenderer::RenderNode>>> const&, android::uirenderer::FrameInfoVisualizer*, android::uirenderer::renderthread::HardwareBufferRenderParams const&, std::__1::mutex&)+830) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #48 pc 0000000000256f03  /system/lib64/libhwui.so (android::uirenderer::renderthread::CanvasContext::draw(bool)+979) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #49 pc 000000000025a8dc  /system/lib64/libhwui.so (std::__1::__function::__func<android::uirenderer::renderthread::DrawFrameTask::postAndWait()::$_0, std::__1::allocator<android::uirenderer::renderthread::DrawFrameTask::postAndWait()::$_0>, void ()>::operator()() (.__uniq.264041412789356548918088680803242235290.c303f2d2360db58ed70a2d0ac7ed911b)+1548) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #50 pc 000000000026653e  /system/lib64/libhwui.so (android::uirenderer::WorkQueue::process()+686) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #51 pc 00000000002b43db  /system/lib64/libhwui.so (android::uirenderer::renderthread::RenderThread::threadLoop()+475) (BuildId: 7bfb5921a7aa43da3c2e07e65703d737)
      #52 pc 0000000000010562  /system/lib64/libutils.so (android::Thread::_threadLoop(void*)+178) (BuildId: 8a1cecdd149caf732e29843b6721becd)
      #53 pc 000000000006d62a  /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+58) (BuildId: eb58b4d427279994f00c0e1818477e4f)
      #54 pc 0000000000060348  /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+56) (BuildId: eb58b4d427279994f00c0e1818477e4f)

Luckily, this gave me enough to go searching for on the web, where I eventually landed upon this PR for React Native that proported to fix what appeared to be the same issue I was running into. I had nothing to lose so I figured I'd adapt the fix to my code and sure enough, the crash went away! You can see the git diff for my fix in the repo, but the TL;DR of it all is, if you are experiencing crashes when trying to use a WebView in Jetpack Compose, try wrapping your AndroidView in a FrameLayout and modifying your code accordingly. Instead of this...

AndroidView(
    factory = { context ->
        WebView(context).apply {
            // ...
        }
    },
    update = { webView ->
        // ...
    }
)

... try this instead:

private const val WEBVIEW_TAG = "myWebViewTag"

AndroidView(
    factory = { context ->
        FrameLayout(context).apply {
            addView(
                WebView(context).apply {
                    tag = WEBVIEW_TAG
                    // ...
                }
            )
        }
    },
    update = { frameLayout ->
        frameLayout.findViewWithTag<WebView>(WEBVIEW_TAG).apply {
            // ...
        }
    }
)

  1. Leaving 1 or 2 star reviews for a bug/crash on a free and open source project is quite demoralizing by the way. 

  2. I actually tend to do most of my development on physical devices since I've usually had the opposite experience, where the app seems to work just fine on an emulator but has some weird issue on a real device, or because I just want to interact with the app in the way that most users will.