Architecture
This page describes the main objects, startup flow, and internal collaboration of brookesia_system_core.
Entry Object
The core entry is esp_brookesia::system::core::System, which exposes:
System lifecycle:
init(),start(),stop(),deinit().App management:
install_app(),install_runtime_app(),start_app(),stop_app(),uninstall_app().App-owned GUI operations:
gui_set_text(),gui_trigger_screen_flow(), and so on.Timer operations:
timer_start_periodic(),timer_start_delayed(),timer_stop().Runtime caller owner lookup:
get_current_runtime_app_owner().
Internal state lives in System::Impl, and the public header exposes only the stable interface. The internal records and shared scheduling helpers of System::Impl live in src/private/system/impl.hpp, while behavior is implemented per module under the system/, app/, service/, and runtime/ directories.
Main Flow
System::init() creates and connects the base runtime environment:
Set
system_typeandgui::Environment.Create and start
lib_utils::TaskSchedulerfor internal app, GUI, and timer scheduling.If
gui_backendis configured, creategui::Runtime.Create
SystemHostBridgeandruntime::Runtime.Initialize
service::ServiceManager.Register and bind
SystemCore,SystemGui,SystemTimer.Call the derived-class extension point
on_init().Install registered native apps and package apps according to configuration.
System::start() calls on_start() and enters the started state; System::stop() calls on_stop() and clears the started state; System::deinit() stops running apps and cleans up the runtime, GUI, timers, services, and app records.
System::process_timers() is currently retained as a compatibility entry; timers are triggered automatically by the internal scheduler and dispatched to apps.
If System::Config::enable_gui_live_preview is on, the core registers live preview after a file-backed GUI document loads, and starts a periodic poll in the SystemGui task group. The poll and document reload still pass through the GUI runtime gate and backend thread guard, and the poll state is canceled on deinit() or document unload.
Task Scheduling
system_core uses one shared lib_utils::TaskScheduler configured with several serial task groups:
Group |
Purpose |
|---|---|
|
GUI document load/mount/unload, regular binding flush, lifecycle-related GUI operations |
|
GUI event dispatch, input-triggered |
|
App lifecycle and regular timer callbacks |
|
The |
|
Periodic/delayed timer trigger source |
SystemGui and SystemGuiInput share one GUI runtime gate and backend thread guard to avoid concurrent access to gui::Runtime and the LVGL backend; SystemApp and SystemAppInput share one app callback gate to avoid native or runtime apps being entered concurrently by timers and actions.
GUI actions do not run app logic directly inside the LVGL event callback stack. For lightweight actions without payload, gui::Runtime uses a fast path to trigger the action subscription directly, and the subscription only posts to SystemAppInput; for events such as ValueChanged that need to sync GUI runtime state, the backend event still enters SystemGuiInput first, and then the action subscription posts to SystemAppInput.
Impl Record Model
Impl::AppRecord keeps the runtime state of each app:
AppInfo info.The native app instance and
AppContext.The app-owned GUI
document_id.The runtime internal app id.
The action connection list.
Registered image/font resource ids.
The map from timer id to timer name.
The currently mounted screen path.
Flags for whether the runtime and GUI are loaded.
The core uses AppRecord to handle native and runtime app differences uniformly.
Source Modules
The implementation of system_core is split by function:
Source File |
Responsibility |
|---|---|
|
|
|
The |
|
|
|
App-owned GUI, system-only GUI, action subscription, binding merge |
|
The system-only GUI facade used by a derived |
|
Automatic registration and unregistration of native app image/font resources |
|
Timer create, stop, cancel, pending merge, and |
|
Base implementation of the app-facing runtime wrapper |
|
App install, start, stop, pause, resume, and query |
|
|
|
Scanning the |
|
Internal/external storage layout, app/private/public directories, and restricted file operations |
|
Runtime initialization, load/unload, |
|
The |
|
|
Public Include Modules
include/brookesia/system_core keeps the top-level compatibility headers and also provides fine-grained per-module headers:
Entry |
Responsibility |
|---|---|
|
Common umbrella for native app authors, aggregating app types, context, runtime wrapper, and |
|
Common umbrella for a derived |
|
Umbrella for service helpers and service classes |
|
Umbrella for package unpacking, manifest reading, and |
|
App types, |
|
|
|
|
In-repo implementation files prefer including the fine-grained headers; external code can keep including the top-level compatibility headers.
Module Collaboration
Module |
Responsibility in System Core |
|---|---|
|
Load JSON UI documents, register runtime image/font, mount screens, find and update views |
|
Load scripted apps and call |
|
The private host bridge of system_core that lets managed runtime apps call system services through a native module |
|
Hosts |
|
Implements internal GUI, app, and timer scheduling |
|
Provides native app providers linked into the project at compile time |
Extension Points
A derived system can override:
on_init()on_start()on_stop()on_deinit()on_app_installed()on_app_started()on_app_stopped()
system_super uses these extension points to install the shell app, mount the overlay, and restore the shell after a regular app stops.