Environment
- Connect IQ SDK 9.1.0 (
com.garmin.connectiq.simulator, arm64 native) - Simulator device: epix gen 2 simulator
- macOS 26.5.2 (25F84), Mac17,9, Apple M5 Pro, 24 GB
com.garmin.connectiq:ciq-companion-app-sdk:2.4.0@aar- Companion app:
IQConnectType.TETHERED, compileSdk 35, targetSdk 35 - Phone: Xiaomi M2004J19C, Android 12 (API 31)
- Connection:
adb forward tcp:7381 tcp:7381
Summary
When using the tethered connection, phone-to-watch messaging works normally and remains stable.
However, the first watch-to-phone call to Communications.transmit() consistently causes the Connect IQ Simulator to crash, regardless of the payload.
The simulator reports:
Socket Error in packet header 0
and then terminates.
The Android companion app simply sees the device transition from connected to disconnected. No exception is reported on the Android side, and adb logcat -b crash is empty.
Steps to reproduce
- Start the Android companion app using
IQConnectType.TETHERED. - Run:
adb forward tcp:7381 tcp:7381
- Start the watch app in the Connect IQ Simulator.
- Select Connection > Start.
- Send a message from the phone using
sendMessage(). - Confirm that the watch receives the message successfully.
- From the watch, call:
Communications.transmit("x", null, listener);
Expected behavior
Communications.transmit() should complete normally and the message should be delivered to the companion application's registerForAppEvents listener, as it does over Bluetooth.
Actual behavior
The watch app prints:
transmit BEGIN
but never prints:
transmit returned
The simulator then reports:
Socket Error in packet header 0
and crashes.
The companion app observes the device changing from connected to disconnected.
Important observation: payload-independent
I reduced the payload to the simplest possible value accepted by transmit().
The crash occurs with a bare six-byte String:
Communications.transmit("x", null, listener);
I also tested progressively more complex payloads, including a Number, an Array, a Dictionary, and the real application message. All produce the same result.
This eliminates payload serialization, payload size, null values, and numeric conversion as likely causes.
The crash also occurs when transmit() is invoked from a timer tick, rather than from the receive callback, and it occurs on the first transmission with no queue/retry pressure.
With Communications.transmit() disabled entirely, phone-to-watch messaging can continue indefinitely without disconnecting.
Crash information
The macOS crash report shows:
Process: simulator
Version: 9.1.0 (9.1.0)
Code Type: ARM-64 (Native)
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS
Termination: SIGNAL 11, Segmentation fault
Triggered by Thread: 14 TVM main
The crashing thread contains the following relevant register state:
x8: 0x00000000abcdabcd
far: 0x9e4f2d6b1ec8f3a7
esr: 0x92000004 (Data Abort) byte read Translation fault
At the same time, another simulator thread is inside sendto().
This makes the failure look potentially related to object lifetime or synchronization between the TVM thread and the communications thread, rather than to the contents of the transmitted message.
I also tried keeping a strong reference to the payload for the entire duration of the transmission:
_inFlight = payload;
Communications.transmit(_inFlight, null, listener);
// cleared in onComplete / onError
This did not change the behavior.
Minimal reproduction
The attached minimal watch app reproduces the crash with Communications as its only manifest permission.
The relevant code is essentially:
class Listener extends Communications.ConnectionListener {
function initialize() { ConnectionListener.initialize(); }
function onComplete() as Void { System.println("onComplete"); }
function onError() as Void { System.println("onError"); }
}
class Delegate extends WatchUi.BehaviorDelegate {
function initialize() { BehaviorDelegate.initialize(); }
function onSelect() as Boolean {
System.println("transmit BEGIN");
Communications.transmit("x", null, new Listener());
System.println("transmit returned");
return true;
}
}
The companion side registers for application events but never receives the transmitted message.
Additional information
The same general EXC_BAD_ACCESS / TVM main crash pattern has been reported previously with the macOS Connect IQ Simulator.
There is also a related discussion concerning tethered Android connections and applicationId. In that discussion, a developer reported successful watch-to-phone transmission over ADB with SDK 8.1.0, suggesting that watch-to-phone tethered transmission has worked in previous versions.
I am therefore wondering whether this is a regression in SDK 9.1.0, or another instance of the simulator's existing macOS memory-management issue.
Impact
The tethered transport is particularly useful for developing companion applications without physical watch hardware.
With Communications.transmit() causing the simulator to terminate, watch-to-phone communication cannot be tested at all in this configuration. This effectively prevents development and debugging of applications whose primary function is sending data from the watch to the companion app.
I have attached the complete macOS .ips crash report as well as the minimal reproduction project.
Could someone from the Connect IQ team confirm whether this is a known issue in Simulator 9.1.0 and whether there is a workaround or planned fix?