software-mansion / software-mansion/react-native-audio-api

[Android] PlaybackNotification.loadArtwork decodes artwork at full resolution — unbounded memory, no cache, no timeouts

Open
#1,264 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

android bug pkg:audio-api
Dominant language
C++
Stars
839
Forks
92
Avg merge
4d 15h
Merged PRs (30d)
27

Description

Description

PlaybackNotification.loadArtwork (L509-539) downloads and decodes remote artwork at full resolution:

val connection = URL(url).openConnection()
connection.connect()
val inputStream = connection.getInputStream()
val bitmap = BitmapFactory.decodeStream(inputStream)
  • Unbounded decode — no BitmapFactory.Options, so a 4000×4000 artwork allocates ~64 MB in ARGB_8888 for something rendered at notification-icon size. BitmapFactory.decodeFile in the local branch has the same issue.
  • No cache — every metadata update re-downloads and re-decodes the same URL.
  • No timeouts — default (infinite) connect/read on a bare Thread that interrupt() can't unblock from a socket read.
  • The result is then passed to mediaSession.setMetadata(...putBitmap(METADATA_KEY_ART, bitmap)) (L288), crossing a Binder transaction at full size.

Google Play Console flags this under App quality insights → "bitmap image optimization":

Decoded in com.swmansion.audioapi.system.notification.PlaybackNotification.loadArtwork
Downloaded in com.swmansion.audioapi.system.notification.PlaybackNotification.loadArtwork

Suggested fix: two-pass decode (inJustDecodeBoundsinSampleSize against notification_large_icon_width/height or a ~512 px cap), plus connect/read timeouts and a small LRU on the URL. Alternatively delegate to Fresco, already on the classpath in every RN app, via ImageRequestBuilder + ResizeOptions — that gets downsampling, caching and cancellation for free.

Steps to reproduce
  1. AudioManager.setNowPlaying({ ..., artwork: '<url to a 4000×4000 JPEG>' }).
  2. Android Studio Profiler shows the bitmap allocated at source resolution, not icon size. On low-RAM devices this surfaces as OutOfMemoryError in BitmapFactory.decodeStream.
Snack or a link to a repository

None — code-level report, verified against main; source linked above.

React Native Audio API version

0.13.2 (unchanged on main and in 0.13.3)

React Native version

0.86.3

Platforms

Android

Architecture

New architecture

Build type

Release mode

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in packages/react-native-audio-api/android/src/main/java/com/swmansion/audioapi/system/notification/PlaybackNotification.kt, especially loadArtwork at lines 509-539 and the mediaSession metadata call near line 288. Reproduce with a large remote artwork while profiling memory, then verify that artwork decoding is bounded, repeated URLs are cached, and network reads have finite timeouts without causing the reported OutOfMemoryError.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, kotlin, react-native
Domain
mobile, performance
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.