Skip to content

Commit 596f0b2

Browse files
committed
* fix compatibility for legacy and make sure work on new rsd as well
1 parent c248634 commit 596f0b2

5 files changed

Lines changed: 49 additions & 19 deletions

File tree

CLAUDE.md

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -367,11 +367,11 @@ This section records all practical changes made during iOS 26.2 USB bring-up. Ke
367367
- `ProcessService::GetProcessListDTX()` timeout increased to 15s for large process-list replies on tunnel paths.
368368
- `FPSService` hardening:
369369
- bounded probe/start timeouts
370-
- explicit error path when `startSamplingAtTimeInterval:` times out
370+
- `startSamplingAtTimeInterval:` timeout handled as warning/non-fatal for cross-version compatibility
371371
- cleanup of partially created channel/connection on startup failure.
372372
- `PerformanceService` hardening:
373373
- bounded attribute/config/start timeouts
374-
- explicit failure handling for `start`
374+
- `start` timeout handled as warning/non-fatal for cross-version compatibility
375375
- cleanup on startup failure.
376376
- `Stop()` behavior for FPS/Performance changed to always clean up existing channel/connection resources even when `m_running` is false (prevents leaked receive threads after partial startup failures).
377377
- `XCTestService` hardening:
@@ -381,6 +381,34 @@ This section records all practical changes made during iOS 26.2 USB bring-up. Ke
381381
- reset port-forwarder object if initial port-forward setup fails
382382
- `Stop()` now also runs when only forwarding resources exist (not only when running/thread-active).
383383
384+
### 10) Detailed dual-compatibility findings (iOS 15 + iOS 26.2)
385+
386+
These were the key cross-version findings from real-device validation:
387+
388+
1. Different startup semantics across iOS versions:
389+
- iOS 26.2 reliably replies to `runningProcesses` and stream-start flows on the RSD/CDTunnel path.
390+
- iOS 15 can stream FPS/perf data even when sync `start` reply is delayed/missing.
391+
- Action taken: treat FPS/perf `start` reply timeout as warning (non-fatal), continue waiting for stream data.
392+
393+
2. Cleanup behavior must not depend only on `m_running`:
394+
- Partial startup failures can leave channels/connections allocated while `m_running == false`.
395+
- Action taken: `Stop()` paths in FPS/Performance/XCTest/WDA now clean up resources even in partial-failure states.
396+
397+
3. iOS 15 SSL receive crash during stop:
398+
- Crash stack showed `SSL_read` via `idevice_connection_receive_timeout` while stopping FPS.
399+
- Root cause: close/disconnect race with receive thread in idevice (SSL) transport mode.
400+
- Action taken: split transport close path:
401+
- socket mode: close immediately without recv-lock (avoids tunnel deadlock)
402+
- idevice mode: close under recv+send locks (prevents SSL use-after-free race).
403+
404+
4. Timeout tuning must be service-specific:
405+
- Process list can be large (especially on modern systems), so short sync timeout causes false failures.
406+
- Action taken: increased process list sync timeout; set bounded but practical service timeouts for FPS/perf setup.
407+
408+
5. Final validated matrix:
409+
- iOS 15 (legacy USB DTX/SSL): process list, FPS, performance: working.
410+
- iOS 26.2 (USB CDTunnel + RSD + DTX): process list, FPS, performance: working.
411+
384412
## Service Implementation Patterns (iOS 15 Tested)
385413
386414
### Global Message Handler Pattern

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
A standalone, pure C++20 library for communicating with iOS Instruments services. Supports iOS 12-16 via USB/network and iOS 17+ via USB RSD, USB CDTunnel/CoreDeviceProxy, USB-NCM fallback, or external CoreDevice tunnel.
44

5-
**Status**: DTX protocol working - process listing, FPS monitoring, and performance monitoring tested on **iOS 12 and iOS 15** via USB (Feb 2026). iOS 26.2 USB path validated (Mar 2026): built-in CDTunnel + RSD + DTX handshake + process listing, FPS service, and performance service all working.
5+
**Status**: DTX protocol working - process listing, FPS monitoring, and performance monitoring validated on **iOS 12, iOS 15, and iOS 26.2** via USB. iOS 26.2 uses built-in CDTunnel + RSD + DTX; iOS 15 uses legacy USB DTX/SSL path.
66

77
## Features
88

@@ -108,7 +108,7 @@ printf("iOS: %s\n", info.version.c_str());
108108
#### Process Management
109109
110110
```cpp
111-
// List all running processes (✅ Tested on iOS 15 via USB)
111+
// List all running processes (validated on iOS 15 and iOS 26.2 via USB)
112112
std::vector<ProcessInfo> procs;
113113
Error err = inst->Process().GetProcessList(procs);
114114
if (err == Error::Success) {
@@ -459,3 +459,4 @@ GNU Affero General Public License v3.0 (AGPL-3.0)
459459
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
460460

461461
See the [LICENSE](LICENSE) file for full details.
462+

src/dtx/dtx_transport.cpp

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -146,20 +146,21 @@ DTXTransport::~DTXTransport() {
146146

147147
void DTXTransport::Close() {
148148
m_connected = false;
149-
// IMPORTANT: close socket without waiting for m_recvMutex.
150-
// Receive() holds m_recvMutex while blocked in recv(); taking m_recvMutex here
151-
// can deadlock Disconnect()->Close()->join(receiveThread).
149+
// Socket mode: close without taking m_recvMutex to avoid deadlock when the
150+
// receive thread is blocked in recv() while holding m_recvMutex.
152151
if (m_socketFd >= 0) {
153152
CLOSE_SOCKET(static_cast<socket_t>(m_socketFd));
154153
m_socketFd = -1;
154+
return;
155155
}
156-
{
157-
std::lock_guard<std::mutex> lock(m_sendMutex);
158-
if (m_connection && m_ownsConnection) {
159-
idevice_disconnect(m_connection);
160-
}
161-
m_connection = nullptr;
156+
157+
// idevice/SSL mode: synchronize against in-flight ReadExact()/Receive()
158+
// to avoid use-after-free races inside idevice_connection_receive_timeout().
159+
std::scoped_lock<std::mutex, std::mutex> lock(m_recvMutex, m_sendMutex);
160+
if (m_connection && m_ownsConnection) {
161+
idevice_disconnect(m_connection);
162162
}
163+
m_connection = nullptr;
163164
}
164165

165166
bool DTXTransport::ReadExact(uint8_t* buffer, size_t length) {

src/services/fps_service.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,9 @@ Error FPSService::Start(uint32_t sampleIntervalMs,
109109
startMsg->AppendAuxiliary(NSObject(0.0));
110110
auto response = m_channel->SendMessageSync(startMsg, kStartTimeoutMs);
111111
if (!response) {
112-
if (errorCb) errorCb(Error::Timeout, "startSampling timeout");
113-
Stop();
114-
return Error::Timeout;
112+
// Some iOS versions start streaming without returning a sync response.
113+
// Keep the session alive and rely on incoming stream messages.
114+
INST_LOG_WARN(TAG, "startSampling timed out, continuing and waiting for stream data");
115115
}
116116

117117
m_running.store(true);

src/services/performance_service.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,9 +191,9 @@ Error PerformanceService::Start(const PerfConfig& config,
191191
auto startMsg = DTXMessage::CreateWithSelector("start");
192192
response = m_channel->SendMessageSync(startMsg, kStartTimeoutMs);
193193
if (!response) {
194-
if (errorCb) errorCb(Error::Timeout, "start timeout");
195-
Stop();
196-
return Error::Timeout;
194+
// Some iOS versions begin sysmontap streaming without a sync reply.
195+
// Continue and process incoming channel/global messages.
196+
INST_LOG_WARN(TAG, "sysmontap start timed out, continuing and waiting for stream data");
197197
}
198198
INST_LOG_INFO(TAG, "Performance monitoring started (interval=%ums)",
199199
actualConfig.sampleIntervalMs);

0 commit comments

Comments
 (0)