Skip to content

← Firmware Downloads

Post-install setup · Reborn (Y2Linux) · Y2

Y2Linux / Y2Reborn 1.0 code review — 2026-10-17/18 (checks and six area reviews complete)

Debian-based Linux with a fast clickwheel interface for the Innioasis Y2.

Instructions published by the project, shown here word for word.

Y2Linux / Y2Reborn 1.0 code review — 2026-10-17/18 (checks and six area reviews complete)

Fixed in Beta 8.0 (Baseline 75, 2026-10-18): B1, B3, B4, B5, B6, B7, B8, P1, P2, R2, R4, R5, R6, R7 (report). B2 kept strict (only v3.2.0 hashes; documented loudly). Open: R1 (large-file split), R3 (owner decision).

Companion to V1-RELEASE-READINESS. Read-only: nothing in either repository was edited, built, committed or sent to the player. The automated checks ran on 2026-10-17. The six area reviews that session launched never reported; they were redone by hand on 2026-10-18 (Y2Linux e771867, Y2Reborn a0b1a50), one time-boxed pass per area over the code that carries the most risk (scope per area under Coverage). Two findings were reproduced on the host in a scratch directory; no hardware evidence was taken.

Checks run

CheckCommand (from repo root)Result
Rust formattingcargo fmt --all -- --check (Y2Reborn, Rust 1.99.0)clean
Clippy, strictcargo clippy --workspace --all-targets -- -D warningsclean, 0 warnings
Testscargo test --workspace26 binaries, 514 passed, 0 failed, 6 ignored
Clippy pedantic+nursery (reported separately)cargo clippy --workspace --all-targets -- -W clippy::pedantic -W clippy::nursery -A missing_errors_doc -A missing_panics_doc -A module_name_repetitions -A doc_markdown≈1 900 warnings over the workspace (reborn-ui 909, reborn-platform 357, reborn bin 152, reborn-core 112, reborn-library 56, reborn-media 44, observability 36, graphics 31, audio 20, control 5). Top lints: unseparated literals 220, suboptimal_flops 151, must_use 143+96, usize→f32 precision 130, const fn 88. Worth a look: 27+27 usize↔i32 casts that wrap on the 32-bit target, 16 u128→u64 truncations, 18 "unchecked Duration subtraction" (all verified safe, see below), 25 redundant clones. No panic-class finding confirmed from the lint output alone.
Y2Linux host suitesh tools/development/host-tests.sh (build out/build)Ran 793 tests, OK (uMTPrd stat warnings on .. are harmless)
Docs links/catalogpython3 tools/development/check-docs.pyY2Linux 392 pages, 4 367 links, 1 problem (catalog omits docs/planning/LASTFM-SCROBBLE-PLAN.md); Y2Reborn 68 pages, 0 problems
shellcheckshellcheck -S warning over 70 project scripts (init.d, overlays, initramfs, tools)17 warnings, none a bug: SC2034 unused loop variables (n, attempt, round…), SC1007 on intentional CDPATH= cd --, one SC2046/SC2155 in wpa-event:9 (export Y2_DHCP_GENERATION=$(cat …) — single-word file, harmless)
clang-tidy on Reborn C (2026-10-18)clang-tidy -checks='-*,clang-analyzer-*,-clang-analyzer-security.insecureAPI.*,bugprone-*,…' on reborn-audio/native/audio.c, reborn-media/native/media.c, reborn-graphics/native/graphics.c with the host pkg-config flags4 analyzer reports, all false positives on reading (media.c:1133 m->io is set on both open paths; :1612/1629/1680 id is set whenever read_image_file succeeds; :1731 loop stops at the terminator). The rest is style (signed bitwise, assignment in if, implicit void * casts).
cppcheck / ruff / pyflakes—not installed on this host; not run

Findings

Severity: high = users lose something or a release feature fails in normal use; medium = fails in a plausible situation; low = narrow or defensive. Status: confirmed = reproduced or traced end to end; plausible = mechanism confirmed, trigger not yet seen on a player.

Bugs

IDRepoFile:lineSev.StatusTrigger / impactFixEffort
B3bothY2Reborn crates/reborn-library/src/lib.rs:1268-1271, app/reborn/src/main.rs:4219-4227, :3443; Y2Linux tools/platform/y2_platform/update.py:571, :542-546highconfirmed (host repro)One song FFmpeg cannot open rolls back every update. A decode failure sets the source's complete=false; the scan that Reborn starts on every launch then ends in LibraryScanFailed("scan incomplete; retained existing entries (N traversal failures)"), so rebornctl status carries a non-null library.error. The failed file never gets a row, so it is decoded (and fails) again on every scan and the error never clears. health_ack treats any library.error as not healthy; after 180 s it calls core rollback + prepare, and the recovery restores the previous release. Trigger: any file with a supported extension that does not decode — truncated download, 0-byte or mislabelled .mp3, an .m4a with an unsupported codec. Host repro 2026-10-18: headless target/release/reborn with one valid WAV and one garbage broken.mp3 → "library":{"error":"scan incomplete; retained existing entries (1 traversal failures)","scanning":false,"tracks_loaded":1} at uptime 9 s. The owner's player has never hit it because the library decodes cleanly.Both sides: (1) health_ack should require a live library worker, not a clean scan — e.g. accept library.error that starts with scan incomplete, or better a Reborn-owned healthy field (R7). (2) Reborn: count decode failures separately (stats.unreadable), keep complete, and mark the failed path seen (INSERT OR IGNORE INTO scan_seen … WHERE path=?) so its old row survives; show "N files could not be read" as a notice, not an error. Add a library test with one undecodable file and a Y2Linux fixture for health_ack.S
B4Y2Reborncrates/reborn-library/src/lib.rs:1268-1271, :365-371, :1488-1497mediumconfirmed (code trace)Same root: songs deleted over USB stay in the library. Pruning runs only for a complete source, so one undecodable file on Internal Storage or the SD card stops every later scan from retiring rows of deleted files. They keep showing and fail to play until the broken file is removed.The B3 Reborn fix (mark the failed path seen, keep complete). Test: undecodable file + a deleted file → the deleted row is retired, the undecodable one is kept.S (with B3)
B5Y2Linuxtools/platform/y2_platform/service.py:193-194, media.py:64, common.py:62-70, :100-104mediumplausible (mechanism reproduced on host)An SD card whose read-only check takes longer than ≈7 s never mounts. The service loop runs y2-platform media reconcile with timeout=7, but inside it the admission check (fsck.fat/fsck.exfat/e2fsck -n) may take 60 s. command() starts every child in a new session and kills only that process group, so the killed reconcile leaves its checker running. media-lifecycle.json is never written, the next pass (3 s, 10 s with the screen off) starts another Python + checker, and the card stays "not available" while checkers pile up and keep the CPU and card busy. Host test 2026-10-18: a parent command(..., timeout=3) around a child that runs command(['sleep','20'], timeout=60) returns command_timeout after 3.0 s and sleep 20 is still running. Trigger: a large FAT32/exFAT library or a slow card plus the Python start-up on the Y2; no timing for the owner's card is on record.Run reconcile as a background child like daily_update_check (poll, no 7 s limit), or give it a limit above the checker's; make command() kill the whole tree (prctl(PR_SET_PDEATHSIG) in a preexec_fn, or keep nested commands in the caller's group). Device test with the largest card available.S
B6Y2Linuxkernel/patches/0065-y2-musb-pio-progress.patch y2_rx_mode1_start (patch lines ≈110-140)lowplausibleMulti-packet receive start: after three DMAMODE kicks (≈60 µs) without movement the channel is aborted and the CPU reads the waiting packet, assuming "nothing has reached memory". Nothing re-reads the DMA address after channel_abort, so if the engine starts in the last microsecond the request loses or duplicates part of one packet without an error. Never observed (m1_kick and m1_fallback stayed 0 over the 1 GiB hashed uploads). Related: the kick exists only at start; a mid-transfer stall has no re-kick and would end only when the host cancels.After the fallback channel_abort, sample y2_hsdma_moved(); if anything moved, give the request back with -EIO (the host retries) instead of the PIO read. Keep m1_kick/m1_fallback in the cable-pull and sleep tests (A8).S
B7Y2Rebornapp/reborn/src/main.rs:3335-3349, crates/reborn-core/src/lib.rs:1259-1266lowplausibleAfter a rollback, an older Reborn that cannot parse the session (a newer SESSION_SCHEMA_VERSION, or a new enum variant inside Settings/AudioOutput) starts with AppModel::default() and its first checkpoint overwrites session.json: volume, skin, EQ, brightness, codec choice and the queue are lost, also for the later re-update. More likely now because B3 causes rollbacks.Keep a rejected session as session.json.rejected-<stamp> (as the database quarantine does) and parse settings on its own with #[serde(default)] per field and unknown variants mapped to the default.S
B8Y2Linuxinitramfs/production/recovery.sh:57-66lowconfirmed (by design)recovery_stuck (unknown state, RescueRequired, an installer crash) keeps PID 1 in a console loop with the message on screen and never powers off; MISC stays boot-recovery, so the player drains to the PMIC cut-off and returns to the same screen after charging. Data is safe; the battery is deep-discharged.Power off after a few minutes on battery (keep the request); stay on only while a charger is connected.S

Earlier findings that stay open: B1 (tools/production/package.py:116 ships the historical production-install.md as the user's install.md, medium, confirmed) and B2 (tools/platform/y2_platform/radiofw.py:277-311 accepts only the v3.2.0 FM firmware hashes, medium, confirmed); details in the readiness file (A3, A4).

Performance

IDWhereNoteEffort
P1Y2Linux service.py:193-194Part of B5: while a card check overruns, a full Python interpreter plus a filesystem checker start every 3–10 s. The Fix02 note in the same file measured that a recurring interpreter start alone held schedutil at 1040 MHz.with B5
P2Y2Reborn reborn-library/src/lib.rs:1268Part of B3/B4: every undecodable file is opened by FFmpeg again on every scan (no negative cache). Cheap for one file, linear in broken files on each boot. Remember the failure by (path, size, mtime).with B3
P3Y2Linux 0065 y2_rx_mode1_endUp to 50 × (2 µs + register reads) ≈ 100–150 µs in hard IRQ with musb->lock held, once per received transfer (its closing short packet). Negligible at the measured ≈1 450 IRQ/s; noted so nobody adds work there.—

Not measured in this pass: per-frame allocations in reborn-ui (7.3 measured 62 fps median, no evidence of a problem), platform polling intervals (wifi 4 s, avrcp 3–5 s, refresh 30 s), ALSA period 512 / buffer 4096 frames.

Refactoring

IDRepoWhereStatusNoteEffort
R1Y2Rebornapp/reborn/src/main.rs (5 872 lines), playback.rs (2 938), crates/reborn-ui/src/lib.rs (3 143), reborn-library/src/lib.rs (2 822), reborn-platform/src/bluetooth.rs (2 594)confirmed sizesFive files hold a third of the Rust code; the pedantic pass concentrates there. Seams seen in this pass: in main.rs the runtime loop vs storage/scan glue (≈4 190-4 760) vs status/diagnostics JSON (:2821); in reborn-library the scanner walk (:1310-1500) vs the SQLite worker (:200-900) vs search.L, low risk with the 514 tests
R2Y2Linuxdocs/release/Y2-COMMUNITY-BETA-FEATURE-AUDIT.md, docs/architecture/production-*.mdconfirmedHistorical documents are still wired into packaging (B1) and named as current in the audit request; mark retired or move.S
R3Y2Linuxbuildroot/configs/y2_production_defconfig:33-99confirmedDebug/measurement packages (strace, iperf3, memtester, evtest, i2c-tools) ship in production images. Move behind the dev defconfig.S
R4Y2Reborncrates/reborn-audio/native/audio.c:85confirmed, no user impactprofile_section_has falls back to an unquoted strstr, and the profile's rates are bare numbers, so 8000 matches inside 48000. The hardware still refuses (the AFE offers only 44.1/48 kHz, kernel/audio/mt6582-afe.c:34), so the gate is weaker than it reads. Parse the arrays (or match delimited numbers).S
R5Y2Linuxtools/platform/y2_platform/common.py:62-104confirmedcommand() can only kill its direct child's group (B5). A tree-kill helper (or PR_SET_PDEATHSIG) removes a whole class of orphaned helpers; health-ack (8 s), space --cleanup (2 s) and update auto-check run under the same rule.S
R6Y2Linuxkernel/platform/storage-policy.h:43-100, internal_media.py:39-40from the handoff, not re-measuredThe eMMC guard refuses ext4's WRITE_ZEROES/erase inside p8 (mmc_erase: group start error -30 at start; lazy inode-table init then gives up). Harmless, but noisy: advertise no erase/write-zeroes for the internal card, or make Y2MEDIA with lazy_itable_init=0,nodiscard.S
R7bothY2Linux update.py:549-573, Y2Reborn main.rs:2821confirmedThe update health rule reads Reborn's internal status fields (library.error, graphics.available, uptime_seconds). B3 is what happens when one side changes meaning. Have Reborn publish one explicit healthy verdict (with its reasons) in rebornctl status and test the contract in both repos.S

Verified not a problem

Kernel (Y2Linux):

Platform (Y2Linux):

Update and recovery (Y2Linux tools/update/core.c, initramfs/production/recovery.sh):

Reborn:

Coverage

AreaRead in fullRead in part / skipped
Kernel/driverspatched musb_gadget.c RX paths, musbhsdma.c abort/moved, kernel/platform/usb.c DMA selector, storage-policy.h, storage-layout.h, charger policy/limits/driver run loop, btif.c, thermal resumerest of usb.c, spm.c, pm-journal.c (persistence only), audio drivers; the vendor Wi-Fi driver (kernel/platform/connectivity/wifi, ≈130 k lines) not reviewed
Platform daemon/toolsinternal_media.py, media.py, common.py, service.py, update.pyusb.py (views), observe.py (mountinfo); power.py, product_sleep.py, maintenance.py, network.py, radiofw.py beyond B2 not reviewed
Release/update/recoverycore.c (all of verify/backup/restore/recover/prepare/boot_check/main), recovery.shrelease.py, package.py beyond B1, recovery-ui.c not reviewed
Reborn app + platformsession restore, storage pinning, scan triggers and results in main.rs, panic sitesbluetooth.rs, wifi.rs, radio.rs, lastfm.rs, avrcp.rs read only for panic sites
Reborn UI/core/libraryscanner walk, reuse probe, prune, atomic_write, AppModel::restorerendering, skins, search index not reviewed
Reborn native C + FFIaudio.c, native.rs FFI and write path, media.c I/O and artwork, clang-tidy over all three C filesgraphics.c only through clang-tidy

Top 10 (both files)

  1. B3/B4 — one undecodable song rolls back every update and stops pruning: fix the health rule and the scan

    accounting before the next release (S, no hardware needed; then one OTA on a player with a broken file).

  2. A1 — second-unit sleep drain (#42): capture plan, A/B nights, mitigation decision.
  3. B5 — SD admission under the 7 s reconcile limit; device test with a large card.
  4. A3/B1 — ship the real INSTALL guide in the first-install zip.
  5. A5/A6 — fix stale tags and "Beta" wording in readme, BUILDING, INSTALL, STORAGE, release notes template.
  6. A8 + B6 — harden the mode-1 fallback, then the cable-pull, sleep/wake and Windows tests of receive DMA.
  7. A11 — one consolidated device-check pass closing the 34 owed items.
  8. A4/B2 — firmware-version policy for the Innioasis package.
  9. A2 — an external install-from-stock and build-from-source run.
  10. A7, then R7/B7 — toolchain sources in the release; an explicit health contract and a session that survives a rollback.

Not done

No hardware evidence (rules of the audit). The areas and files marked "not reviewed" under Coverage, the vendor Wi-Fi driver, and per-frame/polling performance measurements remain open. cppcheck, ruff and pyflakes are not installed on this host.

Published by the schulzcode/y2linux project [1] [3]