tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit dcd39b58cd96d17bae87bc78d639277315baf982
parent eb7385b235a31cefe45f7cf5b5fdad33344c7e52
Author: mcarare <48995920+mcarare@users.noreply.github.com>
Date:   Tue, 30 Sep 2025 19:47:35 +0000

Bug 1990183 - Prevent using recycled bitmaps for PWA icons. r=android-reviewers,boek

This patch avoids potential crashes caused by using recycled bitmaps when creating shortcuts for Progressive Web Apps (PWAs).

The changes ensure that:
- When creating an icon from the session's content, a check for `isRecycled` is added, and a copy of the bitmap is used to prevent it from being recycled prematurely.
- When building an icon from the web app manifest, it now checks if the fetched bitmap is recycled before use. It also creates a copy to prevent the bitmap from being recycled by the image cache after the shortcut is created.

Differential Revision: https://phabricator.services.mozilla.com/D266887

Diffstat:
Mmobile/android/android-components/components/feature/pwa/src/main/java/mozilla/components/feature/pwa/WebAppShortcutManager.kt | 31++++++++++++++++++++++++-------
1 file changed, 24 insertions(+), 7 deletions(-)

diff --git a/mobile/android/android-components/components/feature/pwa/src/main/java/mozilla/components/feature/pwa/WebAppShortcutManager.kt b/mobile/android/android-components/components/feature/pwa/src/main/java/mozilla/components/feature/pwa/WebAppShortcutManager.kt @@ -146,8 +146,13 @@ class WebAppShortcutManager( val icon = if (manifest != null && manifest.hasLargeIcons()) { buildIconFromManifest(manifest) } else { - session.content.icon?.let { IconCompat.createWithBitmap(it) } + session.content.icon?.takeUnless { it.isRecycled }?.let { + val bitmapCopy = + it.copy(it.config ?: android.graphics.Bitmap.Config.ARGB_8888, false) + IconCompat.createWithBitmap(bitmapCopy) + } } + icon?.let { builder.setIcon(it) } @@ -172,22 +177,34 @@ class WebAppShortcutManager( val shortLabel = manifest.shortName ?: manifest.name storage.saveManifest(manifest) - return ShortcutInfoCompat.Builder(context, manifest.startUrl) + val builder = ShortcutInfoCompat.Builder(context, manifest.startUrl) .setLongLabel(manifest.name) .setShortLabel(shortLabel.ifBlank { fallbackLabel }) - .setIcon(buildIconFromManifest(manifest)) .setIntent(shortcutIntent) - .build() + + buildIconFromManifest(manifest)?.let { + builder.setIcon(it) + } + + return builder.build() } @VisibleForTesting - internal suspend fun buildIconFromManifest(manifest: WebAppManifest): IconCompat { + internal suspend fun buildIconFromManifest(manifest: WebAppManifest): IconCompat? { val request = manifest.toIconRequest() val icon = icons.loadIcon(request).await() + + if (icon.bitmap.isRecycled) { + return null + } + + // Create a copy to prevent the icon from being recycled by the cache after we use it. + val bitmapCopy = icon.bitmap.copy(icon.bitmap.config ?: android.graphics.Bitmap.Config.ARGB_8888, false) + return if (icon.maskable) { - IconCompat.createWithAdaptiveBitmap(icon.bitmap) + IconCompat.createWithAdaptiveBitmap(bitmapCopy) } else { - IconCompat.createWithBitmap(icon.bitmap) + IconCompat.createWithBitmap(bitmapCopy) } }