Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
a89e595
feat: Serial over BT/USB (#21), log timestamps (#54), ADB backup (#55)
mithun50 Mar 5, 2026
a94c515
fix: Node capabilities not available to AI (#56)
mithun50 Mar 5, 2026
448d679
docs: Add #56 fix to changelog
mithun50 Mar 5, 2026
1201009
feat: Check for Updates menu option (#59)
mithun50 Mar 5, 2026
0c94229
docs: Add #59 update check to changelog
mithun50 Mar 5, 2026
720d89d
fix: Terminal ENTER key (#58), ADB backup (#55), background capabilit…
mithun50 Mar 6, 2026
5e8144f
fix: Remove invalid exclude rules from backup XML (#55)
mithun50 Mar 6, 2026
0140474
fix: SSHD crash with VPN (#61), DNS resolution (#60)
mithun50 Mar 6, 2026
67a3969
fix: Kill stale gateway processes before starting new instance (#60)
mithun50 Mar 6, 2026
1f41fe7
fix: Prevent deleteRecursively from following symlinks (data loss)
mithun50 Mar 6, 2026
5980af5
fix: Include models array in provider config (#60)
mithun50 Mar 6, 2026
ecd552f
revert: Remove pkill before gateway start
mithun50 Mar 6, 2026
60852aa
fix: Prevent duplicate gateway instances via port check (#60)
mithun50 Mar 6, 2026
3618c93
fix: Storage safety, gateway crash loop, auth UX, canvas status, miss…
mithun50 Mar 8, 2026
414dd17
fix: Prevent gateway crash loop from orphaned timers and race conditions
mithun50 Mar 8, 2026
33773de
fix: Detect actual process death instead of relying on stale boolean …
mithun50 Mar 8, 2026
6418a81
fix: Post emitLog to main thread — EventSink.success() requires UI th…
mithun50 Mar 8, 2026
8409df6
fix: isProcessAlive reports true while gateway thread is still settin…
mithun50 Mar 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
# Changelog

## v1.8.4 — Serial, Log Timestamps & ADB Backup

### New Features

- **Serial over Bluetooth & USB (#21)** — New `serial` node capability with 5 commands (`list`, `connect`, `disconnect`, `write`, `read`). Supports USB serial devices via `usb_serial` and BLE devices via Nordic UART Service (flutter_blue_plus). Device IDs prefixed with `usb:` or `ble:` for disambiguation
- **Gateway Log Timestamps (#54)** — All gateway log messages (both Kotlin and Dart side) now include ISO 8601 UTC timestamps for easier debugging
- **ADB Backup Support (#55)** — Added `android:allowBackup="true"` to AndroidManifest so users can back up app data via `adb backup`

### Bug Fixes

- **Node Capabilities Not Available to AI (#56)** — `_writeNodeAllowConfig()` silently failed when proot/node wasn't ready, causing the gateway to start with no `allowCommands`. Added direct file I/O fallback to write `openclaw.json` directly on the Android filesystem. Also fixed `node.capabilities` event to send both `commands` and `caps` fields matching the connect frame format

### Node Command Reference Update

| Capability | Commands |
|------------|----------|
| Serial | `serial.list`, `serial.connect`, `serial.disconnect`, `serial.write`, `serial.read` |

---

## v1.8.3 — Multi-Instance Guard

### Bug Fixes
Expand Down
14 changes: 13 additions & 1 deletion flutter_app/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,20 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" tools:replace="android:maxSdkVersion" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-feature android:name="android.hardware.usb.host" android:required="false" />

<application
android:label="OpenClaw"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"
android:usesCleartextTraffic="true"
android:requestLegacyExternalStorage="true"
android:extractNativeLibs="true">
android:extractNativeLibs="true"
android:allowBackup="true">
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verify sensitive persisted keys/paths that could be included in backup payloads
echo "=== Searching for sensitive keys/paths in flutter_app/lib ==="
rg -n "nodeGatewayToken|dashboardUrl|openclaw\.json|api.?key|token|secret" flutter_app/lib -C2 2>/dev/null || echo "No sensitive keys found"

echo -e "\n=== Checking for backup rule resources ==="
# Verify whether backup rule resources already exist
fd -a "backup_rules.xml|data_extraction_rules.xml" flutter_app/android/app/src/main/res/xml 2>/dev/null || echo "No backup rule resources found"

Repository: mithun50/openclaw-termux

Length of output: 28665


Exclude sensitive tokens from backups.

android:allowBackup="true" on Line 35 can expose persisted authentication tokens (nodeGatewayToken, dashboardUrl containing token fragments, nodeDeviceToken) and configuration (openclaw.json) unless backup rules explicitly exclude them. Currently, no backup rule resources exist.

🔐 Suggested manifest hardening
     <application
         android:label="OpenClaw"
         android:name="${applicationName}"
         android:icon="@mipmap/ic_launcher"
         android:usesCleartextTraffic="true"
         android:requestLegacyExternalStorage="true"
         android:extractNativeLibs="true"
-        android:allowBackup="true">
+        android:allowBackup="true"
+        android:fullBackupContent="@xml/backup_rules"
+        android:dataExtractionRules="@xml/data_extraction_rules">

Create flutter_app/android/app/src/main/res/xml/backup_rules.xml and flutter_app/android/app/src/main/res/xml/data_extraction_rules.xml to exclude SharedPreferences keys containing tokens and sensitive configuration.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@flutter_app/android/app/src/main/AndroidManifest.xml` at line 35, The
manifest currently sets android:allowBackup="true" which will include app data
in backups; create res/xml/backup_rules.xml and
res/xml/data_extraction_rules.xml and reference them from the AndroidManifest
via android:fullBackupContent="@xml/backup_rules" and
android:dataExtractionRules="@xml/data_extraction_rules" (keeping
android:allowBackup as needed) so that sensitive keys are excluded; in
backup_rules.xml exclude SharedPreferences keys "nodeGatewayToken",
"dashboardUrl" (and any token fragments), "nodeDeviceToken" and the file
"openclaw.json", and in data_extraction_rules.xml exclude the same files/keys to
prevent extraction during Android 10+ data migrations. Ensure filenames match
backup_rules.xml and data_extraction_rules.xml and that the manifest uses the
exact attributes fullBackupContent and dataExtractionRules to point to them.


<activity
android:name=".MainActivity"
Expand All @@ -44,6 +50,12 @@
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/usb_device_filter" />
</activity>

<service
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,8 @@ class GatewayService : Service() {

private fun emitLog(message: String) {
try {
logSink?.success(message)
val ts = java.time.Instant.now().toString()
logSink?.success("$ts $message")
} catch (_: Exception) {}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<usb-device />
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Overly permissive USB device filter — <usb-device /> with no attributes matches every USB device. This causes Android to prompt the user to open this app for any USB device attachment (keyboards, storage devices, cameras, etc.), not just serial adapters.

Consider restricting to common USB-serial adapter vendor/product IDs (FTDI, CP210x, CH340, PL2303) or at minimum filtering by device class. For example:

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At flutter_app/android/app/src/main/res/xml/usb_device_filter.xml, line 3:

<comment>Overly permissive USB device filter — `<usb-device />` with no attributes matches **every** USB device. This causes Android to prompt the user to open this app for any USB device attachment (keyboards, storage devices, cameras, etc.), not just serial adapters.

Consider restricting to common USB-serial adapter vendor/product IDs (FTDI, CP210x, CH340, PL2303) or at minimum filtering by device class. For example:</comment>

<file context>
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <usb-device />
+</resources>
</file context>
Fix with Cubic

</resources>
10 changes: 10 additions & 0 deletions flutter_app/lib/providers/node_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import '../services/capabilities/flash_capability.dart';
import '../services/capabilities/location_capability.dart';
import '../services/capabilities/screen_capability.dart';
import '../services/capabilities/sensor_capability.dart';
import '../services/capabilities/serial_capability.dart';
import '../services/capabilities/vibration_capability.dart';
import '../services/native_bridge.dart';
import '../services/node_service.dart';
Expand All @@ -29,6 +30,7 @@ class NodeProvider extends ChangeNotifier with WidgetsBindingObserver {
final _locationCapability = LocationCapability();
final _screenCapability = ScreenCapability();
final _sensorCapability = SensorCapability();
final _serialCapability = SerialCapability();
final _vibrationCapability = VibrationCapability();

NodeState get state => _state;
Expand Down Expand Up @@ -156,6 +158,11 @@ class NodeProvider extends ChangeNotifier with WidgetsBindingObserver {
_sensorCapability.commands.map((c) => '${_sensorCapability.name}.$c').toList(),
(cmd, params) => _sensorCapability.handleWithPermission(cmd, params),
);
_nodeService.registerCapability(
_serialCapability.name,
_serialCapability.commands.map((c) => '${_serialCapability.name}.$c').toList(),
(cmd, params) => _serialCapability.handleWithPermission(cmd, params),
);
}

Future<void> _init() async {
Expand Down Expand Up @@ -211,6 +218,8 @@ class NodeProvider extends ChangeNotifier with WidgetsBindingObserver {
Permission.camera,
Permission.location,
Permission.sensors,
Permission.bluetoothConnect,
Permission.bluetoothScan,
].request();
}

Expand Down Expand Up @@ -306,6 +315,7 @@ class NodeProvider extends ChangeNotifier with WidgetsBindingObserver {
_nodeService.dispose();
_cameraCapability.dispose();
_flashCapability.dispose();
_serialCapability.dispose();
NativeBridge.stopNodeService();
super.dispose();
}
Expand Down
6 changes: 6 additions & 0 deletions flutter_app/lib/screens/node_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,12 @@ class _NodeScreenState extends State<NodeScreen> {
'Read accelerometer, gyroscope, magnetometer, barometer',
Icons.sensors,
),
_capabilityTile(
theme,
'Serial',
'Bluetooth and USB serial communication',
Icons.usb,
),
const SizedBox(height: 16),

// Device Info
Expand Down
Loading