Skip to content

Commit 7f50745

Browse files
mcararervandermeulen
authored andcommitted
Bug 1990183 - Prevent using recycled bitmaps for PWA icons. r=android-reviewers,boek a=RyanVM
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
1 parent a6f6bc8 commit 7f50745

File tree

1 file changed

+24
-7
lines changed
  • mobile/android/android-components/components/feature/pwa/src/main/java/mozilla/components/feature/pwa

1 file changed

+24
-7
lines changed

mobile/android/android-components/components/feature/pwa/src/main/java/mozilla/components/feature/pwa/WebAppShortcutManager.kt

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,13 @@ class WebAppShortcutManager(
146146
val icon = if (manifest != null && manifest.hasLargeIcons()) {
147147
buildIconFromManifest(manifest)
148148
} else {
149-
session.content.icon?.let { IconCompat.createWithBitmap(it) }
149+
session.content.icon?.takeUnless { it.isRecycled }?.let {
150+
val bitmapCopy =
151+
it.copy(it.config ?: android.graphics.Bitmap.Config.ARGB_8888, false)
152+
IconCompat.createWithBitmap(bitmapCopy)
153+
}
150154
}
155+
151156
icon?.let {
152157
builder.setIcon(it)
153158
}
@@ -172,22 +177,34 @@ class WebAppShortcutManager(
172177
val shortLabel = manifest.shortName ?: manifest.name
173178
storage.saveManifest(manifest)
174179

175-
return ShortcutInfoCompat.Builder(context, manifest.startUrl)
180+
val builder = ShortcutInfoCompat.Builder(context, manifest.startUrl)
176181
.setLongLabel(manifest.name)
177182
.setShortLabel(shortLabel.ifBlank { fallbackLabel })
178-
.setIcon(buildIconFromManifest(manifest))
179183
.setIntent(shortcutIntent)
180-
.build()
184+
185+
buildIconFromManifest(manifest)?.let {
186+
builder.setIcon(it)
187+
}
188+
189+
return builder.build()
181190
}
182191

183192
@VisibleForTesting
184-
internal suspend fun buildIconFromManifest(manifest: WebAppManifest): IconCompat {
193+
internal suspend fun buildIconFromManifest(manifest: WebAppManifest): IconCompat? {
185194
val request = manifest.toIconRequest()
186195
val icon = icons.loadIcon(request).await()
196+
197+
if (icon.bitmap.isRecycled) {
198+
return null
199+
}
200+
201+
// Create a copy to prevent the icon from being recycled by the cache after we use it.
202+
val bitmapCopy = icon.bitmap.copy(icon.bitmap.config ?: android.graphics.Bitmap.Config.ARGB_8888, false)
203+
187204
return if (icon.maskable) {
188-
IconCompat.createWithAdaptiveBitmap(icon.bitmap)
205+
IconCompat.createWithAdaptiveBitmap(bitmapCopy)
189206
} else {
190-
IconCompat.createWithBitmap(icon.bitmap)
207+
IconCompat.createWithBitmap(bitmapCopy)
191208
}
192209
}
193210

0 commit comments

Comments
 (0)