mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-01-09 23:11:10 +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
|
from trezor import TR, ui
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from typing import Any, Iterator
|
from typing import Any, Callable, Iterator, ParamSpec, TypeVar
|
||||||
|
|
||||||
from trezor import loop
|
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):
|
class HomescreenBase(ui.Layout):
|
||||||
RENDER_INDICATOR: object | None = None
|
RENDER_INDICATOR: object | None = None
|
||||||
@ -56,7 +83,8 @@ class Homescreen(HomescreenBase):
|
|||||||
level = 0
|
level = 0
|
||||||
|
|
||||||
super().__init__(
|
super().__init__(
|
||||||
layout=trezorui_api.show_homescreen(
|
layout=_retry_with_gc(
|
||||||
|
trezorui_api.show_homescreen,
|
||||||
label=label,
|
label=label,
|
||||||
notification=notification,
|
notification=notification,
|
||||||
notification_level=level,
|
notification_level=level,
|
||||||
@ -96,7 +124,8 @@ class Lockscreen(HomescreenBase):
|
|||||||
not bootscreen and storage_cache.homescreen_shown is self.RENDER_INDICATOR
|
not bootscreen and storage_cache.homescreen_shown is self.RENDER_INDICATOR
|
||||||
)
|
)
|
||||||
super().__init__(
|
super().__init__(
|
||||||
layout=trezorui_api.show_lockscreen(
|
layout=_retry_with_gc(
|
||||||
|
trezorui_api.show_lockscreen,
|
||||||
label=label,
|
label=label,
|
||||||
bootscreen=bootscreen,
|
bootscreen=bootscreen,
|
||||||
skip_first_paint=skip,
|
skip_first_paint=skip,
|
||||||
@ -117,7 +146,8 @@ class Busyscreen(HomescreenBase):
|
|||||||
|
|
||||||
def __init__(self, delay_ms: int) -> None:
|
def __init__(self, delay_ms: int) -> None:
|
||||||
super().__init__(
|
super().__init__(
|
||||||
layout=trezorui_api.show_progress_coinjoin(
|
layout=_retry_with_gc(
|
||||||
|
trezorui_api.show_progress_coinjoin,
|
||||||
title=TR.coinjoin__waiting_for_others,
|
title=TR.coinjoin__waiting_for_others,
|
||||||
indeterminate=True,
|
indeterminate=True,
|
||||||
time_ms=delay_ms,
|
time_ms=delay_ms,
|
||||||
|
Loading…
Reference in New Issue
Block a user