@@ -42,13 +42,15 @@ type IOSDevice struct {
4242 DeviceName string `json:"DeviceName"`
4343 OSVersion string `json:"Version"`
4444
45- mu sync.Mutex // protects fields below
46- tunnelManager * ios.TunnelManager
47- wdaClient * wda.WdaClient
48- mjpegClient * mjpeg.WdaMjpegClient
49- wdaCancel context.CancelFunc
50- portForwarder * ios.PortForwarder
51- portForwarderMjpeg * ios.PortForwarder
45+ mu sync.Mutex // protects fields below
46+ tunnelManager * ios.TunnelManager
47+ wdaClient * wda.WdaClient
48+ mjpegClient * mjpeg.WdaMjpegClient
49+ wdaCancel context.CancelFunc
50+ portForwarderWda * ios.PortForwarder
51+ portForwarderMjpeg * ios.PortForwarder
52+ portForwarderDeviceKit * ios.PortForwarder // devicekit http forwarder
53+ portForwarderAvc * ios.PortForwarder // devicekit h264 stream forwarder
5254}
5355
5456func (d IOSDevice ) ID () string {
@@ -256,11 +258,13 @@ func (d *IOSDevice) hasResourcesToCleanup() bool {
256258 defer d .mu .Unlock ()
257259
258260 hasWda := d .wdaCancel != nil
259- hasWdaPort := d .portForwarder != nil && d .portForwarder .IsRunning ()
261+ hasWdaPort := d .portForwarderWda != nil && d .portForwarderWda .IsRunning ()
260262 hasMjpegPort := d .portForwarderMjpeg != nil && d .portForwarderMjpeg .IsRunning ()
263+ hasHTTPPort := d .portForwarderDeviceKit != nil && d .portForwarderDeviceKit .IsRunning ()
264+ hasStreamPort := d .portForwarderAvc != nil && d .portForwarderAvc .IsRunning ()
261265 hasTunnel := d .tunnelManager != nil && d .tunnelManager .IsTunnelRunning ()
262266
263- return hasWda || hasWdaPort || hasMjpegPort || hasTunnel
267+ return hasWda || hasWdaPort || hasMjpegPort || hasHTTPPort || hasStreamPort || hasTunnel
264268}
265269
266270// cleanupWDA cancels the WebDriverAgent context
@@ -278,11 +282,13 @@ func (d *IOSDevice) cleanupWDA() error {
278282 return nil
279283}
280284
281- // cleanupPortForwarders stops WDA and MJPEG port forwarders
285+ // cleanupPortForwarders stops WDA, MJPEG, and DeviceKit port forwarders
282286func (d * IOSDevice ) cleanupPortForwarders () error {
283287 d .mu .Lock ()
284- wdaForwarder := d .portForwarder
288+ wdaForwarder := d .portForwarderWda
285289 mjpegForwarder := d .portForwarderMjpeg
290+ httpForwarder := d .portForwarderDeviceKit
291+ streamForwarder := d .portForwarderAvc
286292 d .mu .Unlock ()
287293
288294 var errs []error
@@ -301,6 +307,20 @@ func (d *IOSDevice) cleanupPortForwarders() error {
301307 }
302308 }
303309
310+ if httpForwarder != nil && httpForwarder .IsRunning () {
311+ utils .Verbose ("Stopping DeviceKit HTTP port forwarder for device %s" , d .Udid )
312+ if err := httpForwarder .Stop (); err != nil {
313+ errs = append (errs , fmt .Errorf ("failed to stop DeviceKit HTTP port forwarder: %w" , err ))
314+ }
315+ }
316+
317+ if streamForwarder != nil && streamForwarder .IsRunning () {
318+ utils .Verbose ("Stopping DeviceKit AVC stream port forwarder for device %s" , d .Udid )
319+ if err := streamForwarder .Stop (); err != nil {
320+ errs = append (errs , fmt .Errorf ("failed to stop DeviceKit AVC stream port forwarder: %w" , err ))
321+ }
322+ }
323+
304324 if len (errs ) > 0 {
305325 return fmt .Errorf ("port forwarder cleanup errors: %v" , errs )
306326 }
@@ -442,7 +462,7 @@ func (d *IOSDevice) StartAgent(config StartAgentConfig) error {
442462
443463 // set up WDA port forwarding if not already running
444464 d .mu .Lock ()
445- needsPortForwarder := d .portForwarder == nil || ! d .portForwarder .IsRunning ()
465+ needsPortForwarder := d .portForwarderWda == nil || ! d .portForwarderWda .IsRunning ()
446466 d .mu .Unlock ()
447467
448468 if needsPortForwarder {
@@ -458,21 +478,23 @@ func (d *IOSDevice) StartAgent(config StartAgentConfig) error {
458478 }
459479
460480 d .mu .Lock ()
461- d .portForwarder = forwarder
481+ d .portForwarderWda = forwarder
462482 d .wdaClient = wda .NewWdaClient (fmt .Sprintf ("http://localhost:%d" , port ))
463483 d .mu .Unlock ()
464484
465485 utils .Verbose ("WDA port forwarder set up on port %d" , port )
466486 } else {
467487 d .mu .Lock ()
468- srcPort , _ := d .portForwarder .GetPorts ()
488+ srcPort , _ := d .portForwarderWda .GetPorts ()
469489 d .mu .Unlock ()
470490 utils .Verbose ("WDA port forwarder already running on port %d" , srcPort )
471491
472492 // ensure wdaClient is set if not already
493+ d .mu .Lock ()
473494 if d .wdaClient == nil {
474495 d .wdaClient = wda .NewWdaClient (fmt .Sprintf ("http://localhost:%d" , srcPort ))
475496 }
497+ d .mu .Unlock ()
476498 }
477499
478500 // check if wda is already running, now that we have a port forwarder set up
@@ -1204,24 +1226,30 @@ func (d *IOSDevice) StartDeviceKit(hook *ShutdownHook) (*DeviceKitInfo, error) {
12041226 return nil , fmt .Errorf ("failed to find available port for HTTP: %w" , err )
12051227 }
12061228
1207- httpForwarder := ios .NewPortForwarder (d .ID ())
1208- err = httpForwarder .Forward (localHTTPPort , deviceKitHTTPPort )
1229+ d .mu .Lock ()
1230+ d .portForwarderDeviceKit = ios .NewPortForwarder (d .ID ())
1231+ d .mu .Unlock ()
1232+
1233+ err = d .portForwarderDeviceKit .Forward (localHTTPPort , deviceKitHTTPPort )
12091234 if err != nil {
12101235 return nil , fmt .Errorf ("failed to forward HTTP port: %w" , err )
12111236 }
12121237 utils .Verbose ("Port forwarding started: localhost:%d -> device:%d (HTTP)" , localHTTPPort , deviceKitHTTPPort )
12131238 // Find available local port for stream forwarding after HTTP is bound.
12141239 localStreamPort , err := findAvailablePortInRange (portRangeStart , portRangeEnd )
12151240 if err != nil {
1216- _ = httpForwarder .Stop ()
1241+ _ = d . portForwarderDeviceKit .Stop ()
12171242 return nil , fmt .Errorf ("failed to find available port for stream: %w" , err )
12181243 }
12191244
1220- streamForwarder := ios .NewPortForwarder (d .ID ())
1221- err = streamForwarder .Forward (localStreamPort , deviceKitStreamPort )
1245+ d .mu .Lock ()
1246+ d .portForwarderAvc = ios .NewPortForwarder (d .ID ())
1247+ d .mu .Unlock ()
1248+
1249+ err = d .portForwarderAvc .Forward (localStreamPort , deviceKitStreamPort )
12221250 if err != nil {
12231251 // clean up HTTP forwarder on failure
1224- _ = httpForwarder .Stop ()
1252+ _ = d . portForwarderDeviceKit .Stop ()
12251253 return nil , fmt .Errorf ("failed to forward stream port: %w" , err )
12261254 }
12271255 utils .Verbose ("Port forwarding started: localhost:%d -> device:%d (H.264 stream)" , localStreamPort , deviceKitStreamPort )
@@ -1231,8 +1259,8 @@ func (d *IOSDevice) StartDeviceKit(hook *ShutdownHook) (*DeviceKitInfo, error) {
12311259 err = d .LaunchApp (devicekitMainAppBundleId )
12321260 if err != nil {
12331261 // clean up port forwarders on failure
1234- _ = httpForwarder .Stop ()
1235- _ = streamForwarder .Stop ()
1262+ _ = d . portForwarderDeviceKit .Stop ()
1263+ _ = d . portForwarderAvc .Stop ()
12361264 return nil , fmt .Errorf ("failed to launch DeviceKit app: %w" , err )
12371265 }
12381266
@@ -1248,17 +1276,17 @@ func (d *IOSDevice) StartDeviceKit(hook *ShutdownHook) (*DeviceKitInfo, error) {
12481276 })
12491277 if err != nil {
12501278 // clean up port forwarders on failure
1251- _ = httpForwarder .Stop ()
1252- _ = streamForwarder .Stop ()
1279+ _ = d . portForwarderDeviceKit .Stop ()
1280+ _ = d . portForwarderAvc .Stop ()
12531281 return nil , fmt .Errorf ("failed to start agent: %w" , err )
12541282 }
12551283
12561284 // find and tap the "Start Broadcast" button
12571285 err = d .clickStartBroadcastButton ()
12581286 if err != nil {
12591287 // clean up port forwarders on failure
1260- _ = httpForwarder .Stop ()
1261- _ = streamForwarder .Stop ()
1288+ _ = d . portForwarderDeviceKit .Stop ()
1289+ _ = d . portForwarderAvc .Stop ()
12621290 return nil , fmt .Errorf ("failed to click Start Broadcast button: %w" , err )
12631291 }
12641292
0 commit comments