# AUTARCH Android Plan - Browser-Based Hardware Access ## darkHal Security Group **Created:** 2026-02-14 --- ## Problem Statement The current hardware module (Phase 4.5) is **server-side only**: Flask routes call `adb`/`fastboot`/`esptool` as subprocess commands on the AUTARCH server. This works when devices are physically plugged into the server (e.g., Orange Pi), but does NOT allow a remote user to flash a device plugged into their own machine. **Goal:** Add **browser-based direct USB/Serial access** using WebUSB and Web Serial APIs, so users can flash devices plugged into their local machine through the AUTARCH web interface. Keep the existing server-side mode as a fallback. --- ## Architecture: Dual-Mode Hardware Access ``` ┌─────────────────────────────────────┐ │ AUTARCH Web Dashboard │ │ hardware.html │ │ │ │ ┌─────────┐ ┌──────────────┐ │ │ │ SERVER │ │ DIRECT │ │ │ │ MODE │ │ MODE │ │ │ │ │ │ │ │ │ │ Flask │ │ WebUSB / │ │ │ │ API │ │ Web Serial │ │ │ │ calls │ │ (browser JS) │ │ │ └────┬────┘ └──────┬───────┘ │ └────────┼────────────────┼───────────┘ │ │ ┌────────▼────┐ ┌──────▼───────┐ │ AUTARCH │ │ User's │ │ Server │ │ Browser │ │ (Orange Pi)│ │ ↕ USB/Serial│ │ ↕ USB │ │ ↕ Device │ │ ↕ Device │ └──────────────┘ └─────────────┘ Server Mode: device ↔ server ↔ Flask API ↔ browser (existing) Direct Mode: device ↔ browser (WebUSB/Web Serial) ↔ JS libs (NEW) ``` **Server Mode** = Existing implementation. Device plugged into server. Flask calls adb/fastboot/esptool as subprocesses. Works in any browser. **Direct Mode** = NEW. Device plugged into user's machine. Browser talks directly to device via WebUSB (ADB, Fastboot) or Web Serial (ESP32). Requires Chromium-based browser (Chrome, Edge, Brave, Opera). --- ## JavaScript Libraries ### 1. ADB — ya-webadb / Tango - **npm:** `@yume-chan/adb`, `@yume-chan/adb-daemon-webusb`, `@yume-chan/stream-extra` - **License:** MIT - **API:** WebUSB → ADB protocol (shell, file sync, reboot, logcat, install, scrcpy) - **Source:** https://github.com/yume-chan/ya-webadb - **Key classes:** - `AdbDaemonWebUsbDeviceManager` — enumerate/request USB devices - `AdbDaemonWebUsbDevice` — wrap USB device for ADB transport - `AdbDaemonTransport` — handshake + auth - `Adb` — main interface (shell, sync, subprocess, reboot) - **Usage pattern:** ```js const manager = new AdbDaemonWebUsbDeviceManager(navigator.usb); const device = await manager.requestDevice(); // USB permission prompt const connection = await device.connect(); const transport = await AdbDaemonTransport.authenticate({connection, ...}); const adb = new Adb(transport); const output = await adb.subprocess.spawnAndWait('ls /sdcard'); ``` ### 2. Fastboot — fastboot.js (kdrag0n) - **npm:** `android-fastboot` - **License:** MIT - **API:** WebUSB → Fastboot protocol (getvar, flash, boot, reboot, OEM unlock) - **Source:** https://github.com/niccolozy/fastboot.js (fork of kdrag0n), used by ArKT-7/nabu - **Key classes:** - `FastbootDevice` — connect, getVariable, flashBlob, reboot, flashFactoryZip - **Usage pattern:** ```js const device = new FastbootDevice(); await device.connect(); // USB permission prompt const product = await device.getVariable('product'); await device.flashBlob('boot', blob, (progress) => updateUI(progress)); await device.reboot(); ``` ### 3. ESP32 — esptool-js (Espressif) - **npm:** `esptool-js` - **License:** Apache-2.0 - **API:** Web Serial → ESP32 ROM bootloader (chip detect, flash, erase, read MAC) - **Source:** https://github.com/niccolozy/esptool-js (Espressif) - **Key classes:** - `ESPLoader` — main class, connect/detectChip/writeFlash - `Transport` — Web Serial wrapper - **Usage pattern:** ```js const port = await navigator.serial.requestPort(); await port.open({ baudRate: 115200 }); const transport = new Transport(port); const loader = new ESPLoader({ transport, baudrate: 115200 }); await loader.main(); // connect + detect chip console.log('Chip:', loader.chipName); await loader.writeFlash({ fileArray: [{data: firmware, address: 0x0}], flashSize: 'keep', progressCallback: fn }); ``` --- ## Build Strategy: Pre-bundled ESM Since AUTARCH uses vanilla JS (no React/webpack/build system), we need browser-ready bundles of the npm libraries. **Approach:** Use `esbuild` to create self-contained browser bundles, saved as static JS files. ``` web/static/js/ ├── app.js # Existing (1,477 lines) ├── lib/ │ ├── adb-bundle.js # ya-webadb bundled (ESM → IIFE) │ ├── fastboot-bundle.js # fastboot.js bundled │ └── esptool-bundle.js # esptool-js bundled └── hardware-direct.js # NEW: Direct-mode logic (~500 lines) ``` **Build script** (`scripts/build-hw-libs.sh`): ```bash #!/bin/bash # One-time build — output goes into web/static/js/lib/ # Only needed when updating library versions npm install --save-dev esbuild npm install @yume-chan/adb @yume-chan/adb-daemon-webusb @yume-chan/stream-extra android-fastboot esptool-js # Bundle each library into browser-ready IIFE npx esbuild src/adb-entry.js --bundle --format=iife --global-name=YumeAdb --outfile=web/static/js/lib/adb-bundle.js npx esbuild src/fastboot-entry.js --bundle --format=iife --global-name=Fastboot --outfile=web/static/js/lib/fastboot-bundle.js npx esbuild src/esptool-entry.js --bundle --format=iife --global-name=EspTool --outfile=web/static/js/lib/esptool-bundle.js ``` **Entry point files** (thin wrappers that re-export what we need): ```js // src/adb-entry.js export { AdbDaemonWebUsbDeviceManager, AdbDaemonWebUsbDevice } from '@yume-chan/adb-daemon-webusb'; export { AdbDaemonTransport, Adb, AdbSync } from '@yume-chan/adb'; // src/fastboot-entry.js export { FastbootDevice, setDebugLevel } from 'android-fastboot'; // src/esptool-entry.js export { ESPLoader, Transport } from 'esptool-js'; ``` The pre-built bundles are committed to `web/static/js/lib/` so no npm/node is needed at runtime. The build script is only run when updating library versions. --- ## Implementation Phases ### Phase A: Build Infrastructure & Library Bundles **Files:** `package.json`, `scripts/build-hw-libs.sh`, `src/*.js`, `web/static/js/lib/*.js` 1. Create `package.json` in project root (devDependencies only — not needed at runtime) 2. Create entry-point files in `src/` for each library 3. Create build script `scripts/build-hw-libs.sh` 4. Run build, verify bundles work in browser 5. Add `node_modules/` to `.gitignore` equivalent (cleanup notes) **Deliverable:** Three bundled JS files in `web/static/js/lib/` ### Phase B: Direct-Mode JavaScript Module **Files:** `web/static/js/hardware-direct.js` (~500 lines) Core module providing a unified API that mirrors the existing server-mode functions: ```js // hardware-direct.js — Browser-based device access const HWDirect = { // State supported: { webusb: !!navigator.usb, webserial: !!navigator.serial }, adbDevice: null, // current ADB connection fbDevice: null, // current Fastboot connection espLoader: null, // current ESP32 connection espTransport: null, // ── ADB (WebUSB) ──────────────────────────────── async adbRequestDevice() { ... }, // navigator.usb.requestDevice() async adbConnect(usbDevice) { ... }, // handshake + auth → Adb instance async adbShell(cmd) { ... }, // adb.subprocess.spawnAndWait async adbReboot(mode) { ... }, // adb.power.reboot / bootloader / recovery async adbInstall(blob) { ... }, // adb install APK async adbPush(blob, path) { ... }, // adb.sync().write() async adbPull(path) { ... }, // adb.sync().read() → Blob download async adbLogcat(lines) { ... }, // adb subprocess logcat async adbGetInfo() { ... }, // getprop queries async adbDisconnect() { ... }, // ── Fastboot (WebUSB) ──────────────────────────── async fbRequestDevice() { ... }, // FastbootDevice.connect() async fbGetInfo() { ... }, // getVariable queries async fbFlash(partition, blob, progressCb) { ... }, async fbReboot(mode) { ... }, async fbOemUnlock() { ... }, async fbDisconnect() { ... }, // ── ESP32 (Web Serial) ─────────────────────────── async espRequestPort() { ... }, // navigator.serial.requestPort() async espConnect(port, baud) { ... }, // Transport + ESPLoader.main() async espDetectChip() { ... }, // loader.chipName async espFlash(fileArray, progressCb) { ... }, async espMonitorStart(outputCb) { ... }, async espMonitorSend(data) { ... }, async espMonitorStop() { ... }, async espDisconnect() { ... }, // ── Factory Flash (PixelFlasher PoC) ───────────── async factoryFlash(zipBlob, options, progressCb) { ... }, }; ``` ### Phase C: UI Integration — Mode Switcher & Direct Controls **Files:** `web/templates/hardware.html`, `web/static/js/app.js` 1. **Mode toggle** at top of hardware page: ``` [Connection Mode] ○ Server (device on AUTARCH host) ● Direct (device on this PC) ``` - Direct mode shows browser compatibility warning if WebUSB/Serial not supported - Direct mode shows "Pair Device" buttons (triggers USB/Serial permission prompts) 2. **Modify existing JS functions** to check mode: ```js // In app.js, each hw*() function checks the mode: async function hwRefreshAdbDevices() { if (hwConnectionMode === 'direct') { // Use HWDirect.adbRequestDevice() / enumerate } else { // Existing: fetchJSON('/hardware/adb/devices') } } ``` 3. **New UI elements for direct mode:** - "Connect ADB Device" button (triggers WebUSB permission prompt) - "Connect Fastboot Device" button (triggers WebUSB permission prompt) - "Connect Serial Port" button (triggers Web Serial permission prompt) - File picker for firmware uploads (local files, no server upload needed) - Progress bars driven by JS callbacks instead of SSE streams 4. **Keep all existing server-mode UI** — just add the mode switch. ### Phase D: PixelFlasher Proof-of-Concept **Files:** `web/static/js/hardware-direct.js` (factoryFlash section), `web/templates/hardware.html` (new tab/section) Inspired by PixelFlasher's workflow, create a "Flash Factory Image" feature: 1. **Upload factory image ZIP** (via file input, read in browser — no server upload) 2. **Parse ZIP contents** (identify flash-all.sh/bat, partition images) 3. **Display flash plan** (list of partitions + images to flash, with sizes) 4. **Safety checks:** - Verify device product matches image (getVariable product vs ZIP name) - Check bootloader unlock status - Warn about data wipe partitions (userdata, metadata) - Show A/B slot info if applicable 5. **Options:** - [ ] Flash all partitions (default) - [ ] Skip userdata (preserve data) - [ ] Disable vbmeta verification (for custom ROMs) - [ ] Flash to inactive slot (A/B devices) 6. **Execute flash sequence:** - Reboot to bootloader if in ADB mode - Flash each partition with progress bar - Reboot to system 7. **Boot image patching** (future — Magisk/KernelSU integration) ### Phase E: Polish & Testing 1. Error handling for all WebUSB/Serial operations (device disconnected mid-flash, permission denied, etc.) 2. Browser compatibility detection and graceful degradation 3. Connection status indicators (connected device info in header) 4. Reconnection logic if USB device resets during flash 5. Update `autarch_dev.md` with completed phase notes --- ## File Changes Summary ### New Files | File | Purpose | Est. Lines | |------|---------|-----------| | `package.json` | npm deps for build only | 20 | | `scripts/build-hw-libs.sh` | esbuild bundler script | 25 | | `src/adb-entry.js` | ya-webadb re-export | 5 | | `src/fastboot-entry.js` | fastboot.js re-export | 3 | | `src/esptool-entry.js` | esptool-js re-export | 3 | | `web/static/js/lib/adb-bundle.js` | Built bundle | ~varies | | `web/static/js/lib/fastboot-bundle.js` | Built bundle | ~varies | | `web/static/js/lib/esptool-bundle.js` | Built bundle | ~varies | | `web/static/js/hardware-direct.js` | Direct-mode logic | ~500 | ### Modified Files | File | Changes | |------|---------| | `web/templates/hardware.html` | Add mode toggle, direct-mode connect buttons, factory flash section, script includes | | `web/static/js/app.js` | Add mode switching to all hw*() functions | | `web/static/css/style.css` | Styles for mode toggle, connect buttons, compatibility warnings | ### Unchanged | File | Reason | |------|--------| | `core/hardware.py` | Server-mode backend stays as-is | | `web/routes/hardware.py` | Server-mode routes stay as-is | | `modules/hardware_local.py` | CLI module stays as-is | --- ## Browser Compatibility | Feature | Chrome | Edge | Firefox | Safari | |---------|--------|------|---------|--------| | WebUSB (ADB/Fastboot) | 61+ | 79+ | No | No | | Web Serial (ESP32) | 89+ | 89+ | No | No | **Fallback:** Users with Firefox/Safari use Server Mode (device plugged into AUTARCH host). Direct Mode requires Chromium-based browser. --- ## Security Considerations 1. **WebUSB requires HTTPS** in production (or localhost). AUTARCH currently runs plain HTTP. For direct mode to work remotely, either: - Run behind a reverse proxy with TLS (nginx/caddy) - Use localhost (device and browser on same machine) - Use the server-mode fallback instead 2. **USB permission prompts** — The browser shows a native device picker. Users must explicitly select their device. No access without user gesture. 3. **Flash safety checks** — Same partition whitelist as server mode. Confirm dialogs before destructive operations. Product verification before factory flash. --- ## Implementation Order ``` Phase A → Phase B → Phase C → Phase D → Phase E (libs) (JS API) (UI) (PoC) (polish) ~1 session ~1 session ~1 session ~1 session ~1 session ``` Start with Phase A (build the library bundles) since everything else depends on having working JS libraries available in the browser. --- ## PixelFlasher Feature Mapping | PixelFlasher Feature | AUTARCH Implementation | Phase | |---------------------|----------------------|-------| | Factory image flash | ZIP upload → parse → flash sequence | D | | OTA sideload | ADB sideload (server) / adb.install (direct) | C | | Boot image patching (Magisk) | Future — extract boot.img, patch, flash back | Future | | Multi-device support | Device list + select (both modes already do this) | C | | A/B slot management | fastboot getvar current-slot / set_active | D | | Dry run mode | Parse + display flash plan without executing | D | | Partition backup | fastboot fetch / adb pull partition | Future | | Lock/unlock status | fastboot getvar unlocked | D | | Device state display | Product, variant, bootloader version, secure, etc. | C | --- ## Notes - All npm/node dependencies are **build-time only**. The built JS bundles are static files served by Flask. No Node.js runtime needed. - The `src/` directory and `node_modules/` are build artifacts, not needed for deployment. - Library bundles should be rebuilt when upgrading library versions. Pin versions in package.json. - The server-side mode remains the primary mode for headless/remote AUTARCH deployments where devices are plugged into the server. - Direct mode is an enhancement for users who want to flash devices plugged into their own workstation while using the AUTARCH web UI.