1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-18 05:28:40 +00:00

core: replace workflow.kill_default with workflow.close_others

This commit is contained in:
matejcik 2020-05-25 13:04:15 +02:00 committed by matejcik
parent 3c128cde38
commit f32c2f9e23
4 changed files with 30 additions and 46 deletions

View File

@ -57,9 +57,8 @@ def get_seed(passphrase: str = "", progress_bar: bool = True) -> bytes:
def _start_progress() -> None: def _start_progress() -> None:
# Because we are drawing to the screen manually, without a layout, we # Because we are drawing to the screen manually, without a layout, we
# should make sure that no other layout is running. At this point, only # should make sure that no other layout is running.
# the homescreen should be on, so shut it down. workflow.close_others()
workflow.kill_default()
t = Text("Please wait", ui.ICON_CONFIG) t = Text("Please wait", ui.ICON_CONFIG)
ui.draw_simple(t) ui.draw_simple(t)

View File

@ -26,6 +26,7 @@ async def get(ctx: wire.Context) -> str:
async def _request_from_user(ctx: wire.Context) -> str: async def _request_from_user(ctx: wire.Context) -> str:
workflow.close_others() # request exclusive UI access
if storage.device.get_passphrase_always_on_device(): if storage.device.get_passphrase_always_on_device():
passphrase = await _request_on_device(ctx) passphrase = await _request_on_device(ctx)
else: else:
@ -69,7 +70,6 @@ async def _request_on_device(ctx: wire.Context) -> str:
def _entry_dialog() -> None: def _entry_dialog() -> None:
workflow.kill_default()
text = Text("Passphrase entry", ICON_CONFIG) text = Text("Passphrase entry", ICON_CONFIG)
text.normal("Please type your", "passphrase on the", "connected host.") text.normal("Please type your", "passphrase on the", "connected host.")
draw_simple(text) draw_simple(text)

View File

@ -168,7 +168,8 @@ def draw_simple(t: Component) -> None: # noqa: F405
This function bypasses the UI workflow engine, so other layouts will not know This function bypasses the UI workflow engine, so other layouts will not know
that something was drawn over them. In particular, if no other Layout is shown that something was drawn over them. In particular, if no other Layout is shown
in a workflow, the homescreen will not redraw when the workflow is finished. in a workflow, the homescreen will not redraw when the workflow is finished.
Use `workflow.kill_default()` if you need to avoid this situation. Make sure you use `workflow.close_others()` before invoking this function
(note that `workflow.close_others()` is implicitly called with `button_request()`).
""" """
backlight_fade(style.BACKLIGHT_DIM) backlight_fade(style.BACKLIGHT_DIM)
display.clear() display.clear()

View File

@ -3,7 +3,7 @@ import utime
from trezor import log, loop from trezor import log, loop
if False: if False:
from typing import Any, Callable, Dict, Optional, Set from typing import Callable, Dict, Optional, Set
IdleCallback = Callable[[], None] IdleCallback = Callable[[], None]
@ -20,7 +20,7 @@ tasks = set() # type: Set[loop.spawn]
# Default workflow task, if a default workflow is running. Default workflow # Default workflow task, if a default workflow is running. Default workflow
# is not contained in the `tasks` set above. # is not contained in the `tasks` set above.
default_task = None # type: Optional[loop.Task] default_task = None # type: Optional[loop.spawn]
# Constructor for the default workflow. Returns a workflow task. # Constructor for the default workflow. Returns a workflow task.
default_constructor = None # type: Optional[Callable[[], loop.Task]] default_constructor = None # type: Optional[Callable[[], loop.Task]]
@ -78,12 +78,10 @@ def start_default() -> None:
assert default_constructor is not None assert default_constructor is not None
if not default_task: if not default_task:
default_task = default_constructor() default_task = loop.spawn(default_constructor())
if __debug__: if __debug__:
log.debug(__name__, "start default: %s", default_task) log.debug(__name__, "start default: %s", default_task.task)
# Schedule the default task. Because the task can complete on its own, default_task.set_finalizer(_finalize_default)
# we need to reset the `default_task` global in a finalizer.
loop.schedule(default_task, None, None, _finalize_default)
else: else:
if __debug__: if __debug__:
log.debug(__name__, "default already started") log.debug(__name__, "default already started")
@ -110,17 +108,19 @@ def kill_default() -> None:
if __debug__: if __debug__:
log.debug(__name__, "close default") log.debug(__name__, "close default")
# We let the `_finalize_default` reset the global. # We let the `_finalize_default` reset the global.
loop.close(default_task) default_task.close()
def close_others() -> None: def close_others() -> None:
"""Shut down all running tasks, except the one that is currently executing, and """Request workflow (and UI) exclusivity: shut down all running tasks, except
restart the default.""" the one that is currently executing.
try:
kill_default() If this is called from outside a registered workflow, it is equivalent to "close
all tasks". In that case, the default task will be restarted afterwards.
"""
if default_task is not None and not default_task.is_running():
default_task.close()
# if no other tasks are running, start_default will run immediately # if no other tasks are running, start_default will run immediately
except ValueError:
pass
# we need a local copy of tasks because processing task.close() modifies # we need a local copy of tasks because processing task.close() modifies
# the global instance # the global instance
@ -131,39 +131,23 @@ def close_others() -> None:
# if tasks were running, closing the last of them will run start_default # if tasks were running, closing the last of them will run start_default
def _finalize_default(task: loop.Task, value: Any) -> None: def _finalize_default(task: loop.spawn) -> None:
"""Finalizer for the default task. Cleans up globals and restarts the default """Finalizer for the default task. Cleans up globals and restarts the default
in case no other task is running.""" in case no other task is running."""
global default_task global default_task
if default_task is task: assert default_task is task # finalizer is closing something other than default?
if __debug__: assert default_constructor is not None # it should always be configured
log.debug(__name__, "default closed: %s", task)
default_task = None
if not tasks: if __debug__:
# No registered workflows are running and we are in the default task log.debug(__name__, "default closed: %s", task.task)
# finalizer, so when this function finished, nothing will be running. default_task = None
# We must schedule a new instance of the default now.
if default_constructor is not None:
start_default()
else:
raise RuntimeError # no tasks and no default constructor
else: if not tasks:
if __debug__: # No registered workflows are running and we are in the default task
log.warning( # finalizer, so when this function finished, nothing will be running.
__name__, # We must schedule a new instance of the default now.
"default task does not match: task=%s, default_task=%s", start_default()
task,
default_task,
)
# TODO
# If required, a function `shutdown_default` should be written, that clears the
# default constructor and shuts down the running default task.
# We currently do not need such function, so I'm just noting how it should work.
class IdleTimer: class IdleTimer: