# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.2.36] - 2026-08-10
### Fixed
- **Binder**: a genuine idle 0-FPS report is no longer mistaken for "no report
yet". `last_fps` used the value's bit pattern as its own sentinel —
`0.0f32` is bit pattern 0, so an idle `onFpsReported(0)` read as `None`:
the sample was dropped for watchers, and (downstream) the first-report-after-
task-swap drop stayed armed and discarded the next real measurement. A
publish-time `FPS_SEEN` flag now disambiguates the states; the decision is
factored into a testable helper with a regression test.
## [1.2.35] - 2026-08-10
### Fixed
- **spawn**: a timed-out child with a custom process-group leader is now
actually signaled. `wait_loop` targets the child's effective pgid
(the configured leader, or the child's own pid after `setsid`) instead of
`kill(-pid)`, which addressed a group that did not contain the child — the
SIGTERM/SIGKILL escalation never reached it and the wait could hang
forever. `Process::kill_pgroup` now delegates to a new explicit-group
`Process::kill_group`.
## [1.2.34] - 2026-08-10
### Fixed
- **Binder**: input parcels on the write path are RAII-owned. A failed
`AParcel_write*` between `AIBinder_prepareTransaction` and `AIBinder_transact`
previously leaked the prepared parcel; `transact_write` now drops it on the
error path and records the transfer into `AIBinder_transact` (the framework
deletes the input parcel even on failure), so the wrapper never deletes
twice. Reworked the observer, foreground-process observer, display-callback,
FPS, and task-stack transactions onto it.
### Security
- **Binder**: parcel string reads are length-bounded. `string_alloc` now
refuses negative or > 1 MiB advertised lengths instead of driving an
unbounded `reserve_exact` (OOM abort); the read surfaces as an error.
### Internal
- **drm**: `wait_vblank_ioctl_matches_known_constant` writes the expected
ioctl via a `u32` literal so the test compiles on the Android target (where
`libc::Ioctl` is `i32`).
## [1.2.33] - 2026-08-10
### Fixed
- **Binder**: `FpsListener` wake routing is now actually functional. The
per-instance eventfd was handed to `AIBinder_new` as the callback binder's
args, but `fps_on_create` still returned `null`, and `AIBinder_getUserData`
returns exactly what `onCreate` returns — so the wake could never fire. The
callback `onCreate` now passes the userdata through (matching
`TaskStackListener`) and `onDestroy` reclaims the box. Released 1.2.32's
per-task FPS reporting regressed to silent (event never signalled); this
restores it.
## [1.2.32] - 2026-08-10
### Fixed
- **Binder**: `FpsListener` now routes its wake eventfd **per-instance**
through the callback binder's userdata (`AIBinder_getUserData`), matching
`TaskStackListener`. The old process-wide `FPS_EVENTFD` static was
overwritten on every `open()`, so a re-opened listener rewired an earlier
registration's `onFpsReported` wake into the newest eventfd (or dropped
it). Each instance now owns its own fd and `AIBinder_new` failure reclaims
it instead of leaking.
- **Binder**: `FpsListener` and `TaskStackListener` now **deregister
best-effort on drop**, so a dropped listener no longer leaves the framework
delivering `onFpsReported` / task-stack wakes forever. The local strong ref
on the callback binder is intentionally not released (safe-by-leak) so the
per-binder userdata can never be reclaimed while a callback is in flight.
## [1.2.31] - 2026-08-10
### Fixed
- **Binder**: `TaskStackListener` now routes its wake eventfd **per-instance**
through the callback binder's userdata instead of a process-wide
`TASK_STACK_EVENTFD` static. Previously every `open()` overwrote the
shared static, so when a single process hosted two listeners (the
foreground task source and the fps channel) all wake writes went to the
listener opened last and the other's eventfd never fired. Each listener now
owns its own fd, resolved in `on_transact` via `AIBinder_getUserData`, and
reclaimed in `on_destroy`; the `AIBinder_new` failure path no longer leaks.
## [1.2.30] - 2026-08-09
### Added
- **Binder**: New `TaskStackListener` — a push-based task-stack change wake-up
registered with `IActivityTaskManager.registerTaskStackListener`. The
`ITaskStackListener` server object signals an eventfd on any stack event
(`onTaskStackChanged`, `onTaskMovedToFront`, …) and parses **nothing**;
consumers re-query `getFocusedRootTaskInfo` (txn 31) for the authoritative
`(taskId, pkg)`. `dex::resolve_task_stack_codes` resolves
`TRANSACTION_registerTaskStackListener`/`unregisterTaskStackListener` for the
legacy `ITaskStackListener` interface — the newer
`ITaskChangeListener`/`registerTaskChangeListener` pair is absent on the
target ROM.
## [1.2.25] - 2026-08-09
### Added
- **DRM**: New `drm` module with `DrmCard::open` (card node by path) and
`DrmCard::wait_vblank` — a blocking `DRM_IOCTL_WAIT_VBLANK` wait that
returns the monotonic unblock instant. Reply timestamps are ignored because
`msm` display stacks zero `t_sec`/`t_usec`.
- **Reactor**: `Fd::dup` for owned descriptor duplication (fan-out eventfd
wakeups across threads).
## [1.1.2] - 2026-05-12
### Fixed
- **Spawn**: Removed a 1ms busy-wait loop that occurred after child process termination while waiting for final I/O drainage.
- **Signals**: Corrected `SignalRuntime::unblock_all` to use `pthread_sigmask` for thread-safe consistency.
- **Documentation**: Resolved duplicated documentation headers in the `unix_socket` module.
## [1.1.1] - 2026-05-12
### Fixed
- **Reactor**: Fixed a bug where `EPOLLERR` events were not folded into `readable`/`writable` flags, potentially causing hangs in callers that do not explicitly check `error`.
- **Spawn**: Fixed a potential hang in the process wait loop by explicitly handling `EPOLLHUP` (hangup) events.
- **Documentation**: Cleaned up redundant lines in `proc` module documentation.
## [1.1.0] - 2026-05-12
### Added
- **Reactor**: Exposed `add_with_flags` for custom epoll registration.
- **Unix Sockets**: Added `accept_timeout` for millisecond-based timeouts.
- **Unix Sockets**: Added `peer_cred` support for retrieving peer process identity.
- **Signals**: Added `register_handler` for arbitrary process-wide signal handlers.
- **Signals**: Added `signalfd_new` for reactor-compatible signal reception.
## [1.0.0] - 2026-05-12
### Added
- **Logging**: Refactored to a backend-agnostic facade with `Logger` instances.
- **Reactor**: Added `hangup` field to `Event`.
- **Documentation**: Comprehensive behavioral contract and architectural invariant documentation.
### Changed
- **Spawn**: `SpawnBackend` is now mandatory at builder construction.
- **Layering**: Renamed `blocklist_fingerprint` to `path_fingerprint`.
### Stability Contract
The 1.x series guarantees stability for the following behavioral contracts. Changes to these are considered **breaking changes**:
- **Reactor Events**: The mapping of epoll flags to `Event` fields (`EPOLLERR` -> `error`, `EPOLLHUP` -> `hangup`).
- **Reactor Timeouts**: The `-1`/`0`/`positive` millisecond contract in `Reactor::wait`.
- **Descriptor Defaults**: The use of `O_CLOEXEC` / `SOCK_CLOEXEC` for all Core-created descriptors.
- **Signal Compatibility**: The requirement to use `signalfd` (via `signalfd_new`) for reactor-compatible signal handling.
- **Policy Neutrality**: The architectural commitment to provide primitives without policy.
## [0.3.0] - 2026-05-11
### Added
- Added Unix socket peer credential support through `SO_PEERCRED`.
## [0.2.0] - 2026-05-10
### Added
- Added low-level mmap/madvise preload primitive with page-aligned offset validation.
## [0.1.0] - 2026-05-04
### Added
- Initial official CoreShift Core release.
- Primitive Linux/Android APIs for process spawning, process lifecycle, process
I/O draining, procfs parsing, filesystem helpers, UID/GID/path identity,
readahead, signals, inotify, epoll/reactor use, eventfd, timerfd, signalfd,
and Unix domain sockets.
- Explicit spawn backends: `Fork` and `PosixSpawn`.
- Explicit file descriptor inheritance policy through `SpawnFdPolicy`.
- Low-level abstract and pathname Unix stream socket primitives.
### Notes
- Core is policy-free and runs the exact argv it is given.
- Core does not choose shell, root, package, foreground, daemon, fallback, or
product behavior.
- Unsupported backend/option combinations return errors instead of selecting a
different backend.