feat(core): implement auto-suspend in bootscreen
What changed, and why it matters
This commit changes the Trezor hardware wallet's boot screen so that, on devices with a power manager, the screen dims after 30 seconds of inactivity and the device auto-locks after the configured battery autolock delay. It also makes sure these timers are cleaned up when the user finishes the boot screen. There is no direct security bug visible in the diff; it is a power-saving and lock-behavior feature.
No immediate action required. Reviewers may want to confirm that `workflow.idle_timer.remove()` always executes on every exit path from `bootscreen()`, and that temporarily disabling `autolock_interrupts_workflow` does not allow the boot screen to remain unlocked indefinitely if the timers are not cleaned up.
Security signals we found
New auto-lock timer registration during boot screen
Change of workflow.autolock_interrupts_workflow flag during sensitive boot flow
Screen dimming timer added to boot screen
Evidence from the diff
The patch adds conditional power-management logic inside bootscreen() in core/src/boot.py. When utils.USE_POWER_MANAGER is true, it registers two idle timers: one at 30,000 ms to call autodim_display, and one at the battery autolock delay to call lock_device_if_unlocked_on_battery. It also sets workflow.autolock_interrupts_workflow = False so the autolock does not interrupt the boot workflow. After the boot loop exits, it removes both timers and restores autolock_interrupts_workflow = True. The return statements inside the loop are changed to break so cleanup runs.
Changed components
core/src/boot.pybootscreen() functionpower management idle timer integrationInspect captured patch +20 / −2
diff --git a/core/src/boot.py b/core/src/boot.py
index 3a0cdedfb..050107efe 100644
--- a/core/src/boot.py
+++ b/core/src/boot.py
@@ -23,6 +23,11 @@ from apps.common.request_pin import can_lock_device, verify_user_pin
if utils.USE_OPTIGA:
from trezor.crypto import optiga
+if utils.USE_POWER_MANAGER:
+ from trezor import workflow
+ from trezor.power_management.autodim import autodim_display
+ from apps.base import lock_device_if_unlocked_on_battery
+
# have to use "==" over "in (list)" so that it can be statically replaced
# with the correct value during the build process
if ( # pylint: disable-next=consider-using-in
@@ -55,6 +60,14 @@ async def bootscreen() -> None:
Any non-PIN loaders are ignored during this function.
Allowing all of them before returning.
"""
+ if utils.USE_POWER_MANAGER:
+ workflow.idle_timer.set(30_000, autodim_display)
+ workflow.idle_timer.set(
+ storage.device.get_autolock_delay_battery_ms(),
+ lock_device_if_unlocked_on_battery,
+ )
+ workflow.autolock_interrupts_workflow = False
+
while True:
try:
@@ -75,7 +88,7 @@ async def bootscreen() -> None:
await verify_user_pin()
storage.init_unlocked()
allow_all_loader_messages()
- return
+ break
else:
# Even if PIN is not configured, storage needs to be unlocked, unless it has just been initialized.
if not config.is_unlocked():
@@ -93,7 +106,7 @@ async def bootscreen() -> None:
ui.backlight_fade(ui.BacklightLevels.NONE)
ui.display.orientation(rotation)
allow_all_loader_messages()
- return
+ break
except wire.PinCancelled:
# verify_user_pin will convert a SdCardUnavailable (in case of sd salt)
# to PinCancelled exception.
@@ -105,6 +118,11 @@ async def bootscreen() -> None:
log.exception(__name__, e)
utils.halt(e.__class__.__name__)
+ if utils.USE_POWER_MANAGER:
+ workflow.idle_timer.remove(autodim_display)
+ workflow.idle_timer.remove(lock_device_if_unlocked_on_battery)
+ workflow.autolock_interrupts_workflow = True
+
# Display emulator warning.
if utils.EMULATOR:
Why this scored 18/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.