Skip to content

system/nxstore: add LVGL touchscreen app-store frontend#3643

Draft
aviralgarg05 wants to merge 2 commits into
apache:masterfrom
aviralgarg05:gsoc/nxstore-app-store-ui-pr6
Draft

system/nxstore: add LVGL touchscreen app-store frontend#3643
aviralgarg05 wants to merge 2 commits into
apache:masterfrom
aviralgarg05:gsoc/nxstore-app-store-ui-pr6

Conversation

@aviralgarg05

@aviralgarg05 aviralgarg05 commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Note: Please adhere to Contributing Guidelines.

Summary

This PR adds system/nxstore, an LVGL touchscreen frontend for nxpkg. It lets
users browse the package catalog, install an application, launch it, and return
to the catalog without using the nxpkg command line.

The interface presents each package as a card with its name, version,
description, and current install/launch state. Install work runs in the
background and is shown with an indeterminate progress indicator because
pkg_install() does not report byte-level progress. Toasts provide immediate
feedback for install, uninstall, launch, close, and error events.

When an application is launched, nxstore shows a small supervisor area with a
Close button. Closing sends SIGTERM and reaps the child with
waitpid(WNOHANG). ECHILD is treated as an already-reaped process because the
button handler and periodic poll can race to collect the same child. There is
intentionally no forced task deletion: applications must handle SIGTERM and
exit cleanly.

At startup, catalog synchronization waits up to 15 seconds for DHCP to finish.
This avoids reporting an offline error during the interval after Wi-Fi
association but before an address has been assigned.

This PR depends on #3642 for the package synchronization, uninstall, allocation,
and metadata APIs used by nxstore. It currently targets master, so its diff
also contains #3642 until that dependency is merged.

Impact

Enabling CONFIG_SYSTEM_NXSTORE adds the nxstore command and a touchscreen UI
for browsing, installing, launching, and closing packages.

The application depends on CONFIG_GRAPHICS_LVGL and
CONFIG_SYSTEM_NXPKG, including the cJSON and web-client dependencies required
by #3642. At runtime it expects /dev/fb0 and /dev/input0.

Launched applications receive a 32 KiB stack (NXSTORE_LAUNCH_STACKSIZE). The
default POSIX spawn stack is too small for the LVGL/framebuffer applications
used during testing.

Existing applications and configurations are unaffected unless
CONFIG_SYSTEM_NXSTORE is enabled.

Testing

Build host:

  • macOS 26.5, arm64
  • xtensa-esp-elf-gcc 14.2.0 (esp-14.2.0_20241119)

Target:

  • Xtensa / ESP32-S3
  • esp32s3-touch-lcd-7:nsh on a Waveshare ESP32-S3-Touch-LCD-7
    (custom, not-yet-upstream board configuration)

The full image was built and the following flow was repeated on the physical
touchscreen target with several packages:

  1. Boot into nxstore and synchronize the catalog.
  2. Select an uninstalled package and wait for the background install to finish.
  3. Launch the installed package and verify its framebuffer output.
  4. Press Close and verify that the application exits and the catalog returns.
  5. Uninstall the package and verify the card state updates.

The close/reap path produced the following syslog output during the most recent
hardware run:

nxstore: close cb fired, active=1 pid=13
nxstore: close SIGTERM sent to 13
nxstore: close reaped=0 gone=1 after 2 tries

Fill in most of what the initial nxpkg slice deferred: network sync
and artifact acquisition over plain HTTP (verified via SHA-256), an
install rewrite that supports network sources and reclaims state left
by an interrupted previous install, and wiring update/remove/rollback/
available into the CLI.

Harden the package path against untrusted input along the way: bounded
memory-safety helpers and explicit size limits throughout, storage
read/write hardened against partially-written files, path-traversal
rejection in manifest name/version before they reach the filesystem,
and a fix for a lost-update race on the shared installed-packages
database (two concurrent installs of different packages could
otherwise silently clobber each other's recorded state).

Add an optional manifest icon field for the nxstore GUI frontend to
consume, raise PKG_INDEX_MAX now that the in-memory index is
heap-allocated, and document the repository layout and local server
setup in system/nxpkg/README.txt.

Also fixes a real build break: pkg_runtime_compat() unconditionally
referenced CONFIG_ARCH_BOARD, a Kconfig string symbol with no default
clause under ARCH_BOARD_CUSTOM, so it is left entirely undefined
rather than defined-but-empty on a custom board - falls back to
CONFIG_ARCH_BOARD_CUSTOM_NAME instead. Routes pkg_error()/pkg_info()
through syslog rather than stdio, since neither is visible to a
supervisor with no attached console.

Assisted-by: Claude <noreply@anthropic.com>
Signed-off-by: aviralgarg05 <gargaviral99@gmail.com>
Add nxstore, an LVGL-based frontend for nxpkg (system/nxpkg): lists
packages from the local index, installs/launches the selected one,
and supervises whatever it hands the screen to.

Card-based app list (populate_app_list()): each row shows name,
version, and description/status, install/launch state reflected via
icon glyph and color (LV_SYMBOL_DOWNLOAD/PLAY, accent/success color),
and a sliding-segment progress bar during install (no real byte-level
progress is available from pkg_install(), so this reads as
'actively working' without fabricating a percentage). Explicit
LV_STATE_PRESSED styling on every tappable row/button, since no LVGL
theme is loaded and a tap would otherwise give no visual feedback at
all.

Supervisor screen (build_run_screen()/nxstore_enter_running_screen()):
a launched app (e.g. a game that owns /dev/fb0 directly, not just
another LVGL client) gets a dedicated screen with a name label and a
Close button, confined to the border region the launched app's own
scaled/centered framebuffer output never draws into, so switching
back to it doesn't fight over pixels with whatever the app already
put in the framebuffer.

Close/reap handling (close_running_app_event_cb()/
nxstore_poll_running_app()): sends SIGTERM and polls waitpid(WNOHANG)
for the launched pid, but explicitly also treats waitpid() returning
ECHILD as 'already gone' rather than 'still running' - both the
close-button handler and the passive per-loop poll independently race
to reap the same child, so whichever one loses that race must not
spin forever waiting for a wait() that can now never succeed. Requires
the target app to install its own SIGTERM handler to exit cleanly
(this is why there is no generic force-kill fallback here: an
earlier version of this code called task_delete() when SIGTERM wasn't
reaped quickly enough, which was found on real hardware to hang the
entire board - not just the one task - when it landed mid
framebuffer/heap access on this flat-memory build).

Toast notifications (nxstore_toast()) provide a transient, unmissable
confirmation for install/uninstall/launch outcomes and app-closed
events, additive to the durable per-row subtitle text rather than a
replacement for it.

nxstore's own boot-time catalog sync waits (bounded, 15s) on
g_wifi_dhcp_ret before attempting a network fetch, since Wi-Fi
association completing doesn't imply DHCP has - an HTTP fetch
attempted in that window fails with -ENETUNREACH even though the
link itself is already up, indistinguishable from being genuinely
offline without this wait.

Assisted-by: Claude <noreply@anthropic.com>
Signed-off-by: aviralgarg05 <gargaviral99@gmail.com>
@aviralgarg05
aviralgarg05 force-pushed the gsoc/nxstore-app-store-ui-pr6 branch from ce6c2e5 to 513edde Compare July 17, 2026 19:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant