diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..a0bdc5d --- /dev/null +++ b/docs/README.md @@ -0,0 +1,102 @@ +# iperf3-gui + +A Flutter-based Android GUI wrapper for iperf3, the popular network performance measurement tool. + +## Architecture + +``` +lib/ # Flutter/Dart application layer +├── main.dart # App entry point (MaterialApp) +├── domain/ # Business logic (platform-independent) +│ ├── models/ +│ │ ├── test_configuration.dart # Server, port, duration, interval, parallel streams +│ │ └── iperf3_result.dart # Raw output + exit code +│ └── services/ +│ ├── iperf3_service.dart # Dart → MethodChannel bridge (async with Completer) +│ └── iperf3_binary_path_provider.dart # Deprecated (kept for reference) +└── ui/ # Presentation layer + └── features/ + └── test_run/ + ├── test_run_screen.dart # Server/port inputs + GO button + └── test_run_view_model.dart # State machine: idle → running → completed/error + +android/app/src/main/ +├── kotlin/ # Kotlin plugin layer +│ └── com/novoyuuparosk/iperf3gui/ +│ ├── MainActivity.kt # Registers IperfRunner as FlutterPlugin +│ └── IperfRunner.kt # MethodChannel handler → native JNI calls +└── cpp/ # Native iperf3 library + ├── CMakeLists.txt # Compiles iperf3 + cJSON + JNI into libiperf3jni.so + ├── iperf_jni.c # JNI bridge: Java String[] → iperf3 API + ├── iperf/ # iperf3 3.19 C source tree (see below) + ├── iperf_config.h # Generated Android-compatible config header + └── iperf_config_android.h # Android-specific compile options +``` + +## Data Flow + +``` +User taps GO + → Dart TestRunViewModel.runTest(config) + → Iperf3Service.run(config) via MethodChannel + → Kotlin IperfRunner.runIperfLive(args, callback) + → JNI C: java_string_array_to_argv() → iperf_parse_arguments() + → iperf_run_client(test) + → Reader thread pipes stdout → CallVoidMethod → Dart onOutput callbacks + → On completion: Dart Completer resolves with Iperf3Result +``` + +## Key Design Decisions + +### JNI Over Process Execution +Android SELinux Enforcing mode blocks `execve()` from the `untrusted_app` domain, making Process.start() of external binaries fail with Permission denied. Compiling iperf3 as a shared library linked into the app process eliminates this restriction entirely — iperf3 code runs in-process with no domain transitions needed. + +### Callback Mechanism +The JNI bridge uses `CallVoidMethod` on stored `jmethodID`s to invoke the Kotlin `IperfCallback` interface, NOT function pointer casts. Direct function pointer casts caused SIGBUS crashes on ARM due to JNINativeInterface method ID layout differences. + +### Output Streaming +iperf3 output is redirected via pipe to a background reader thread that attaches to the Java VM via `AttachCurrentThread` and invokes callbacks via `CallVoidMethod`. The reader thread frees the state struct on exit; the JNI caller owns the callback object's lifetime. + +### Async Pattern +Dart uses `Completer` to await native completion. The MethodChannel callback handler resolves the completer on `onComplete`, with a timeout fallback that calls `stopIperf` on the native layer. + +## iperf3 Source + +- Version: 3.19 +- Location: `android/app/src/main/cpp/iperf/` +- Files: Full C source tree including cJSON, headers, man pages, PEM keys +- Build: CMake compiles into `libiperf3jni.so` for `armeabi-v7a` and `arm64-v8a` +- Config: `iperf_config.h` generated from `iperf_config.h.in` with Android-compatible POSIX/threading macros + +## Native JNI API + +| Kotlin Method | JNI Signature | Purpose | +|---|---|---| +| `runIperfLive(String[], IperfCallback)` | `runIperfLive` | Start test with args and callback | +| `forceStopIperfTest(IperfCallback)` | `forceStopIperfTest` | Graceful stop via shutdown() | +| `isTestRunning()` | `isTestRunning` | Check if test is in progress | + +## Building + +Prerequisites: +- Flutter 3.47+ +- Android SDK with platform android-36 +- JDK 17 +- NDK r28+ +- CMake 3.22.1 + +```bash +flutter pub get +flutter build apk --debug +adb install build/app/outputs/flutter-apk/app-debug.apk +``` + +## Dependencies + +- Dart: `provider`, `path_provider` +- Android: CMake external native build +- Native: iperf3 3.19, cJSON (single file) + +## License + +MIT — bundled iperf3 3.19 is BSD-3-Clause licensed.