Skip to content

Multi-device

โœ… Implemented ๐Ÿงช Tested

Current state: Fully implemented. Parallel device execution, criticalSection synchronization, the barrier sync point, per-device abort strategies, and YAML anchor support are all active. See the Status Glossary for chip definitions.

Goal

Enable true parallel steps in executePlan, while supporting critical sections where only one device can proceed at a time. Keep the plan format close to the existing single-device test plans by adding a device key per step and a simple devices list. Parallelism is implicit: top-level steps for different devices run concurrently unless synchronized via criticalSection.

YAML Syntax

Simple device labels, allocated by JUnitRunner/Daemon:

devices: ["A", "B"]

steps:
  - tool: launchApp
    device: A
    appId: com.chat.app
    label: Launch chat app (sender)

  - tool: launchApp
    device: B
    appId: com.chat.app
    label: Launch chat app (receiver)

Top-level steps remain consistent; parallelism is implicit:

devices: ["A", "B"]

steps:
  - tool: launchApp
    params:
      device: A
      appId: com.chat.app
    label: Launch sender

  - tool: launchApp
    params:
      device: B
      appId: com.chat.app
    label: Launch receiver

  - tool: criticalSection
    params:
      lock: "chat-room"
      deviceCount: 2
      steps:
        - tool: inputText
          params:
            device: A
            text: "Hello"
          label: Type message
        - tool: imeAction
          params:
            device: A
            action: send
          label: Send message

  - tool: systemTray
    params:
      device: B
      action: find
      notification: { body: "Hello" }
      awaitTimeout: 5000
    label: Verify notification

YAML anchors (merge keys) are supported for reuse and validation:

devices: ["A", "B"]

tap: &tap
  tool: tapOn
  action: tap

steps:
  - <<: *tap
    device: A
    id: "com.google.android.deskclock:id/tab_menu_alarm"
    label: Tap Alarm tab
  - <<: *tap
    device: B
    id: "com.google.android.deskclock:id/tab_menu_alarm"
    label: Tap Alarm tab

Semantics:

  • devices is a list of labels to allocate sessions for; JUnitRunner requests the required number of devices from the MCP Daemon and maps them to labels.
  • device on a step selects the label for routing.
  • Steps targeting different devices run concurrently by default.
  • criticalSection is a mutex; all devices must reach it, then steps execute one device at a time within the section. See Critical Section for details.
  • barrier synchronizes devices without serializing actions: every device runs its own barrier step with a shared lock and deviceCount, blocks until all deviceCount devices arrive, then all proceed concurrently (no held section, no steps). Use it when tracks must line up at a point but should then continue in parallel. Like criticalSection, barrier is daemon-only and may not be nested inside a criticalSection.

Implementation

Plan Validation

Plans are validated at parse time: - If devices field is present, every step must have a device parameter โ€” including criticalSection and barrier steps and each of their nested sub-steps (there is no device-agnostic exemption) - Device labels must be unique and non-empty strings - Steps cannot reference undeclared device labels - If any step uses device labels or criticalSection, the plan must declare devices

Execution Model

Sequential Mode (Single Device): - Plans without devices field execute sequentially as before - Backward compatible with all existing plans

Parallel Mode (Multi-Device): - Plan is partitioned into device tracks based on device labels - Each device track executes independently in parallel - Steps within a device maintain their relative order - Both plan position and device track position are tracked for debugging

Abort Strategy

Configurable behavior when a device fails: - immediate (default): Abort all devices immediately - finish-current-step: Let other devices finish their current step before aborting

Per-Device Timing

Debug mode or failures log per-device execution timing:

[PARALLEL_EXEC]   A: SUCCESS - 5/5 steps (1234ms)
[PARALLEL_EXEC]   B: FAILED - 3/5 steps (987ms)
[PARALLEL_EXEC]   B: Failed at plan step 7 (track step 2): Timeout waiting for element

Known Limitations

  • YAML anchors (<< merge keys) merge all keys, including device; a per-step device written after the merge simply overrides the merged value.
  • Parallel actions can cause ordering hazards without explicit locks - use critical sections to synchronize.
  • Each device’s abort signal is checked between steps, not mid-step.