Skip to content

TextureVideoView.prepareIfNeeded() crash: FileNotFoundException on cached video file #3200

Description

@jensck

Describe the bug

TextureVideoView.prepareIfNeeded() crashes with a FileNotFoundException when the cached video file (/cache/rc_files/...mp4) is missing at the time MediaPlayer.setDataSource() is called. The setDataSource() call is not wrapped in any error handling, so the exception propagates up through the draw pass and becomes a fatal RuntimeException.

  1. Environment

    1. Platform: Android
    2. SDK version: 9.22.2 (also checked 9.23.0 and 9.23.1 changelogs — no fix present)
    3. OS version: Android 15
    4. Android Studio version: Latest stable
    5. How widespread is the issue: Low occurrence so far — observed on one device during testing, but it's a race condition that could affect any device where the cached video file is evicted or fails to download before playback begins.
  2. Debug logs that reproduce the issue

    N/A — crash occurred in a QA build. Stack trace below.

  3. Steps to reproduce, with a description of expected vs. actual behavior

    Steps:

    • Present a RevenueCat Paywall that includes a video component
    • The video file is downloaded to the rc_files cache directory
    • Before/during playback initialization, the cached file becomes unavailable (OS cache eviction, incomplete download, etc.)
    • onSurfaceTextureAvailable fires, calling prepareIfNeeded()
    • player.setDataSource(context, uri) throws FileNotFoundException

    Expected: The SDK handles the missing file gracefully — e.g., by catching the exception in prepareIfNeeded(), logging an error, and either retrying the download or showing the paywall without the video.

    Actual: Unhandled FileNotFoundException propagates through the view draw pass and crashes the app.

  4. Other information

    Stack trace:

    Fatal Exception: java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
    Caused by java.io.FileNotFoundException: /data/user/0/com.jazarimusic.voloco/cache/rc_files/87f783e76683df036c3fa1165d9303d17162b4c1e21a34192ed124aa9a783a28.mp4: open failed: ENOENT (No such file or directory)
        at libcore.io.IoBridge.open(IoBridge.java:574)
        at java.io.FileInputStream.<init>(FileInputStream.java:179)
        at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1238)
        at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1216)
        at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1181)
        at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1106)
        at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1052)
        at com.revenuecat.purchases.ui.revenuecatui.components.video.TextureVideoView.prepareIfNeeded(VideoView.kt:261)
        at com.revenuecat.purchases.ui.revenuecatui.components.video.TextureVideoView.access$prepareIfNeeded(VideoView.kt:70)
        at com.revenuecat.purchases.ui.revenuecatui.components.video.TextureVideoView$1.onSurfaceTextureAvailable(VideoView.kt:126)
        at android.view.TextureView.getTextureLayer(TextureView.java:501)
        at android.view.TextureView.draw(TextureView.java:431)
        ...
    

    Suggested fix: Wrap the setDataSource() call in prepareIfNeeded() with the existing safely() helper, or add a targeted try-catch for IOException:

    // Current (VideoView.kt ~line 261):
    player.setDataSource(context, it)
    
    // Suggested:
    safely(
        execute = { player.setDataSource(context, it) },
        failureMessage = { e -> "Could not set data source: ${e.message}" }
    )

    Related issues:

    • PW-1061 — ANRs from TextureVideoView.release() (same component, different bug)

Additional context

The safely() wrapper already exists in VideoView.kt and is used for other MediaPlayer operations (e.g., muting audio), but is not applied to setDataSource(). The video component was introduced relatively recently in PR #2680 (Oct 2025).

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions