Skip to content

MJPEG server blocks all WDA HTTP endpoints when screenshots fail (DRM-protected apps) #1118

@erdncyz

Description

@erdncyz

Description

When a DRM-protected application (e.g. streaming apps like TOD, Netflix, Disney+) is in the foreground, the MJPEG server's streamScreenshot loop fails continuously with "Cannot take a screenshot within 20000 ms timeout". This causes all other WDA HTTP endpoints (orientation, touch actions, session queries) to become unresponsive or extremely slow, effectively freezing the device for remote control.

Environment

  • WebDriverAgent version: latest (built from source)
  • iOS version: 18.x / 26.x
  • Device: iPhone 15 Pro (also reproducible on other models)
  • Xcode version: 16.x

Steps to Reproduce

  1. Start a WDA session with MJPEG streaming enabled
  2. Open a DRM-protected streaming app (e.g. Netflix, Disney+, or any app using FairPlay DRM)
  3. Play any video content
  4. Try to interact with the device via WDA (tap, swipe, get orientation, etc.)

Expected Behavior

MJPEG screenshot failures should not block other WDA HTTP endpoints. Touch actions, orientation queries, and other commands should continue to work normally even when screenshots cannot be taken.

Actual Behavior

The MJPEG server enters a tight retry loop, logging errors every ~1 second:

Error Domain=com.facebook.WebDriverAgent Code=1 "Cannot take a screenshot within 20000 ms timeout"

This blocks the WDA HTTP server, causing:

  • GET /session/{id}/orientation requests to timeout (12s+)
  • POST /session/{id}/actions (touch/swipe) to queue up and execute with massive delay
  • Device becomes effectively unresponsive for 10-40+ seconds

Root Cause Analysis

In FBMjpegServer.m, the streamScreenshot method uses a serial dispatch queue. When FBScreenshot takeInOriginalResolutionWithScreenID: fails (returns nil), the method immediately schedules the next attempt via scheduleNextScreenshotWithInterval: with the normal frame interval — meaning it retries at full framerate (e.g. 30fps = every ~33ms).

Since iOS blocks screenshot capture for DRM-protected content, every attempt fails, creating a tight loop of failed screenshot calls that saturates the XCTest framework and starves other WDA requests.

Suggested Fix

Add a backoff mechanism when consecutive screenshot failures occur:

if (nil == screenshotData) {
    self.consecutiveScreenshotFailures++;
    NSUInteger backoffMs = MIN(self.consecutiveScreenshotFailures * 500, 2000);
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(backoffMs * NSEC_PER_MSEC)), self.backgroundQueue, ^{
        [self streamScreenshot];
    });
    return;
}
self.consecutiveScreenshotFailures = 0;

This would:

Gradually increase retry delay (500ms → 1s → 1.5s → 2s max)
Free up the XCTest framework to process other requests between retries
Automatically recover to full framerate once screenshots succeed again

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions