Architecture
Architecture
Section titled “Architecture”Rebound consists of five modules that span compile time, runtime, and developer tooling.
Module Map
Section titled “Module Map”compose-rebound/ rebound-compiler/ Kotlin IR compiler plugin (Kotlin 2.0.x-2.1.x) rebound-compiler-k2/ Kotlin IR compiler plugin (Kotlin 2.2+, composite build) rebound-runtime/ KMP runtime (Android, JVM, iOS arm64/x64/sim, Wasm) rebound-gradle/ Gradle plugin (auto-wires compiler + runtime) rebound-ide/ Android Studio tool window plugin rebound-cli.sh CLI over ADB socket sample/ Sample app + instrumented test suiterebound-compiler
Section titled “rebound-compiler”The Kotlin compiler plugin that runs after the Compose compiler in the IR pipeline. Entry point: ReboundCompilerPluginRegistrar registers ReboundIrGenerationExtension, which applies ReboundIrTransformer to every file.
The transformer:
- Visits every function in the IR tree
- Identifies
@Composablefunctions (those with a$composerparameter) - Infers a budget class from function name and call tree structure
- Resolves human-readable keys for anonymous lambdas
- Injects
onEnter,onComposition, andonExittracking calls
rebound-compiler-k2
Section titled “rebound-compiler-k2”A standalone composite build targeting Kotlin 2.2+. The Kotlin 2.2 release changed several IR API method names (valueParameters to parameters, putValueArgument to setArgumentByIndex). This module contains the same transformation logic adapted to the new API surface.
rebound-runtime
Section titled “rebound-runtime”The KMP runtime library. Core components:
- ReboundTracker — thread-safe singleton (
ConcurrentHashMap) that processes tracking events, calculates rates, and detects violations - ComposableMetrics — per-composable data: rate, peak, skip rate, forced count, param-driven count
- ReboundServer (Android) —
LocalServerSocketserving JSON snapshots - StateTracker (Android) —
Snapshot.registerApplyObserverfor state invalidation tracking - ReboundSnapshot — JSON serialization for baseline comparison
- ChangedMaskDecoder — decodes
$changedbitmasks into per-parameter state
No external dependencies. JSON serialization is hand-written to avoid pulling in Gson, Moshi, or kotlinx.serialization.
rebound-gradle
Section titled “rebound-gradle”The Gradle plugin that wires everything together at apply time:
- Detects the project’s Kotlin version via reflection on the
kotlinextension - Adds the correct compiler artifact (
rebound-compilerorrebound-compiler-kotlin-2.2) tokotlinCompilerPluginClasspathconfigurations - Adds
rebound-runtimeasdebugImplementation(whendebugOnly = true) orimplementation - Passes the
enabledflag to the compiler via-P plugin:io.aldefy.rebound:enabled=<bool>
rebound-ide
Section titled “rebound-ide”The Android Studio plugin built with IntelliJ Platform Gradle Plugin 2.2.1. Architecture:
ReboundToolWindowFactory +-- SessionStore (shared data layer) +-- ReboundConnection (ADB forward + socket polling) +-- Tab 1: Monitor (tree + sparkline + event log) +-- Tab 2: Hot Spots (sortable flat table) +-- Tab 3: Timeline (composable x time heatmap) +-- Tab 4: Stability (param matrix + cascade tree) +-- Tab 5: History (session persistence + VCS comparison) +-- Editor: gutter icons + inlay hints + status bar widgetTabs are lazy-initialized — only created when first selected. One socket connection serves all tabs via the observer pattern.
Data Flow
Section titled “Data Flow”1. BUILD: .kt -> Compose compiler -> Rebound IR transformer -> instrumented .kt2. RUNTIME: Composable executes -> onEnter/onComposition/onExit -> ReboundTracker3. DETECT: Rolling window rate > budget x interaction multiplier -> violation logged4. EXPORT: ReboundServer (socket) -> JSON snapshot5. DISPLAY: IDE plugin / CLI / logcatIR Pipeline Detail
Section titled “IR Pipeline Detail”The Compose compiler runs first and transforms @Composable functions by injecting $composer and $changed parameters, wrapping the body in startRestartGroup/endRestartGroup, and inserting skip logic.
Rebound runs after this transformation. It reads the $composer and $changed parameters that the Compose compiler already inserted. This ordering is enforced by the Kotlin compiler plugin registration mechanism — Rebound registers at a lower priority.
Socket Protocol
Section titled “Socket Protocol”Client connects to localhost:18462 -> sends command string ("ping", "snapshot", "summary", "telemetry") -> server responds with JSON -> connection closes
Each request is a fresh TCP connection (no persistent connections).The ADB bridge: adb forward tcp:18462 localabstract:rebound
Design Principles
Section titled “Design Principles”| Principle | Implementation |
|---|---|
| Zero config | Gradle plugin auto-wires everything; IR heuristics classify composables |
| Budget = f(role) | 7 budget classes, not flat thresholds |
| Debug-only | No instrumentation in release builds by default |
| No external deps | Hand-written JSON, no Gson/Moshi/kotlinx |
| Throttled output | 1 violation per composable per 5s; logcat throttled to 1/s/composable |
| KMP | Runtime works on Android, JVM, iOS, Wasm |
| Kotlin version agnostic | Auto-selects correct compiler artifact for 2.0.x through 2.2+ |