mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-01-09 15:00:58 +00:00
fix(core): retry creation of homescreen layout
For reasons unknown, a previous homescreen layout can sometimes survive a GC cycle in main's unimport loop. Two homescreen layouts can't exist simultaneously, so creating a new one would fail. It _seems_ that after restarting the session, the homescreen object still exists but is not reachable anymore, so a second GC cycle properly disposes of it. So what we do is simply catch the possible MemoryError, invoke GC explicitly, and try again.
This commit is contained in:
parent
e424fd8d3b
commit
e0b4cab2db
@ -6,10 +6,37 @@ from storage.cache_common import APP_COMMON_BUSY_DEADLINE_MS
|
||||
from trezor import TR, ui
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Iterator
|
||||
from typing import Any, Callable, Iterator, ParamSpec, TypeVar
|
||||
|
||||
from trezor import loop
|
||||
|
||||
P = ParamSpec("P")
|
||||
R = TypeVar("R")
|
||||
|
||||
|
||||
def _retry_with_gc(layout: Callable[P, R], *args: P.args, **kwargs: P.kwargs) -> R:
|
||||
"""Retry creating the layout after garbage collection.
|
||||
|
||||
For reasons unknown, a previous homescreen layout may survive an unimport, and still
|
||||
exists in the GC arena. At the time a new one is instantiated, the old one still
|
||||
holds a lock on the JPEG buffer, and creating a new layout will fail with a
|
||||
MemoryError.
|
||||
|
||||
It seems that the previous layout's survival is a glitch, and at a later time it is
|
||||
still in memory but not held anymore. We assume that triggering a GC cycle will
|
||||
correctly throw it away, and we will be able to create the new layout.
|
||||
|
||||
We only try this once because if it didn't help, the above assumption is wrong, so
|
||||
no point in trying again.
|
||||
"""
|
||||
try:
|
||||
return layout(*args, **kwargs)
|
||||
except MemoryError:
|
||||
import gc
|
||||
|
||||
gc.collect()
|
||||
return layout(*args, **kwargs)
|
||||
|
||||
|
||||
class HomescreenBase(ui.Layout):
|
||||
RENDER_INDICATOR: object | None = None
|
||||
@ -56,7 +83,8 @@ class Homescreen(HomescreenBase):
|
||||
level = 0
|
||||
|
||||
super().__init__(
|
||||
layout=trezorui_api.show_homescreen(
|
||||
layout=_retry_with_gc(
|
||||
trezorui_api.show_homescreen,
|
||||
label=label,
|
||||
notification=notification,
|
||||
notification_level=level,
|
||||
@ -96,7 +124,8 @@ class Lockscreen(HomescreenBase):
|
||||
not bootscreen and storage_cache.homescreen_shown is self.RENDER_INDICATOR
|
||||
)
|
||||
super().__init__(
|
||||
layout=trezorui_api.show_lockscreen(
|
||||
layout=_retry_with_gc(
|
||||
trezorui_api.show_lockscreen,
|
||||
label=label,
|
||||
bootscreen=bootscreen,
|
||||
skip_first_paint=skip,
|
||||
@ -117,7 +146,8 @@ class Busyscreen(HomescreenBase):
|
||||
|
||||
def __init__(self, delay_ms: int) -> None:
|
||||
super().__init__(
|
||||
layout=trezorui_api.show_progress_coinjoin(
|
||||
layout=_retry_with_gc(
|
||||
trezorui_api.show_progress_coinjoin,
|
||||
title=TR.coinjoin__waiting_for_others,
|
||||
indeterminate=True,
|
||||
time_ms=delay_ms,
|
||||
|
Loading…
Reference in New Issue
Block a user