# How Clipboard Synchronization Works in Scrcpy: Android-to-Host Deep Dive

> Discover how scrcpy clipboard synchronization works from Android to host. Learn about device listeners and control messages for seamless copy-pasting between your devices.

- Repository: [Genymobile/scrcpy](https://github.com/Genymobile/scrcpy)
- Tags: deep-dive
- Published: 2026-02-25

---

**Scrcpy synchronizes clipboards by registering an Android clipboard listener that pushes device changes to the host via `DeviceMessage` objects, while handling host-to-device updates through control messages that set the Android clipboard via a `ServiceManager` wrapper.**

Clipboard synchronization in [Genymobile/scrcpy](https://github.com/Genymobile/scrcpy) enables seamless copy-paste between your Android device and computer. This feature operates through a multi-layered architecture on the server side, utilizing Android's `ClipboardManager` system service wrapped in custom abstractions. The implementation ensures bidirectional sync while preventing feedback loops and gracefully handling devices without clipboard services.

## Architecture Overview

The synchronization mechanism relies on a **control thread** running on the Android device that communicates with the desktop client over a socket connection. The architecture separates concerns into configuration, service wrapping, device abstraction, and control logic layers.

Key components coordinate through the following flow:

- **Options** stores the `clipboardAutosync` flag
- **ServiceManager** lazily initializes the clipboard service wrapper
- **Device** provides static helper methods for read/write operations
- **Controller** manages the event loop and message protocol

## Server-Side Implementation

### Configuration via Options.java

User control over clipboard behavior starts in [`server/src/main/java/com/genymobile/scrcpy/Options.java`](https://github.com/Genymobile/scrcpy/blob/main/server/src/main/java/com/genymobile/scrcpy/Options.java). The class defines a boolean field `clipboardAutosync` that defaults to `true`, enabling automatic synchronization from device to host whenever the Android clipboard changes.

Users can disable this feature via the command line:

```bash
scrcpy --no-clipboard-autosync

```

When disabled, the controller skips listener registration and relies on manual clipboard retrieval triggered by COPY or CUT key events.

### ServiceManager and ClipboardManager Wrapper

Android's clipboard service is accessed through [`server/src/main/java/com/genymobile/scrcpy/wrappers/ServiceManager.java`](https://github.com/Genymobile/scrcpy/blob/main/server/src/main/java/com/genymobile/scrcpy/wrappers/ServiceManager.java). The `getClipboardManager()` method lazily creates a wrapper around `android.content.ClipboardManager`:

```java
// From ServiceManager.java
public ClipboardManager getClipboardManager() {
    if (clipboardManager == null) {
        clipboardManager = ClipboardManager.create();
    }
    return clipboardManager;
}

```

The wrapper class in [`server/src/main/java/com/genymobile/scrcpy/wrappers/ClipboardManager.java`](https://github.com/Genymobile/scrcpy/blob/main/server/src/main/java/com/genymobile/scrcpy/wrappers/ClipboardManager.java) provides simplified methods:

- `getText()` – Retrieves the current primary clip as a string
- `setText(String text)` – Sets the primary clip content
- `addPrimaryClipChangedListener()` – Registers callbacks for clipboard changes

### Device.java Static Helpers

High-level clipboard operations are abstracted in [`server/src/main/java/com/genymobile/scrcpy/device/Device.java`](https://github.com/Genymobile/scrcpy/blob/main/server/src/main/java/com/genymobile/scrcpy/device/Device.java) through static helper methods:

**Reading the clipboard:**

```java
public static String getClipboardText() {
    ClipboardManager clipboardManager = ServiceManager.getClipboardManager();
    if (clipboardManager == null) {
        return null;
    }
    return clipboardManager.getText();
}

```

**Writing with duplicate prevention:**

```java
public static boolean setClipboardText(String text) {
    ClipboardManager clipboardManager = ServiceManager.getClipboardManager();
    if (clipboardManager == null) {
        return false;
    }
    String current = clipboardManager.getText();
    if (text.equals(current)) {
        // Already set, do nothing to avoid duplicate notifications
        return false;
    }
    clipboardManager.setText(text);
    return true;
}

```

The duplicate check prevents unnecessary network traffic and feedback loops when the same text is set multiple times.

## The Control Thread and Two-Way Synchronization

The `Controller` class in [`server/src/main/java/com/genymobile/scrcpy/control/Controller.java`](https://github.com/Genymobile/scrcpy/blob/main/server/src/main/java/com/genymobile/scrcpy/control/Controller.java) orchestrates the bidirectional synchronization through the control thread.

### Device to Host Synchronization

When `clipboardAutosync` is enabled, the controller registers a primary-clip-changed listener during initialization:

```java
// Simplified flow from Controller.java
if (options.clipboardAutosync) {
    clipboardManager.addPrimaryClipChangedListener(() -> {
        if (!isSettingClipboard.get()) {
            String text = Device.getClipboardText();
            if (text != null) {
                deviceMessageSender.send(DeviceMessage.createClipboard(text));
            }
        }
    });
}

```

The `isSettingClipboard` `AtomicBoolean` prevents the listener from reacting to changes initiated by the controller itself, breaking potential feedback loops.

When autosync is disabled, the controller falls back to manual retrieval via the `getClipboard()` method, typically triggered after COPY or CUT key events.

### Host to Device Synchronization

When the user copies text on the host computer, the client sends a *set-clipboard* control message to the Android device. The controller handles this in `setClipboard()`:

```java
public void setClipboard(String text, boolean paste, int sequence) {
    isSettingClipboard.set(true);
    try {
        Device.setClipboardText(text);
        if (paste) {
            // Inject paste key event
            injectKeyEvent(KEYCODE_PASTE);
        }
        if (sequence != ControlMessage.SEQUENCE_INVALID) {
            deviceMessageSender.send(DeviceMessage.createAckClipboard(sequence));
        }
    } finally {
        isSettingClipboard.set(false);
    }
}

```

The method wraps the clipboard operation with the `isSettingClipboard` flag to suppress the listener callback. If the user initiated a paste action (e.g., `Ctrl+V`), the controller injects `KEYCODE_PASTE` after setting the clipboard.

## Disabling Automatic Synchronization

Users can disable the automatic device-to-host synchronization while retaining manual clipboard control:

```bash
scrcpy --no-clipboard-autosync

```

With this flag:
- The primary-clip-changed listener is never registered
- Clipboard content is only retrieved when explicitly requested (e.g., after COPY/CUT operations)
- Host-to-device synchronization remains functional

## Code Examples

### Checking Clipboard Content Programmatically

```java
import com.genymobile.scrcpy.device.Device;

// Read current device clipboard
String content = Device.getClipboardText();
if (content != null) {
    System.out.println("Clipboard contains: " + content);
} else {
    System.out.println("No clipboard manager available");
}

```

### Writing to Device Clipboard

```java
import com.genymobile.scrcpy.device.Device;

// Set text (returns false if text unchanged or manager unavailable)
boolean success = Device.setClipboardText("New clipboard content");
if (success) {
    System.out.println("Clipboard updated successfully");
}

```

### Controller Message Flow

```java
// Device -> Host: Creating a clipboard message
DeviceMessage msg = DeviceMessage.createClipboard("Text copied on device");
deviceMessageSender.send(msg);

// Host -> Device: Handling paste with sequence number
// sequence is used for acknowledgement tracking
controller.setClipboard("Text from host", true, sequence);

```

## Summary

- **Scrcpy** implements bidirectional clipboard synchronization through a dedicated control thread running on the Android device.
- The **`clipboardAutosync`** option (default `true`) controls whether device clipboard changes automatically push to the host via a primary-clip-changed listener.
- **ServiceManager** and **ClipboardManager** wrap Android's system service, providing `getText()` and `setText()` abstractions used by **Device.java**.
- The **Controller** class prevents feedback loops using an **`isSettingClipboard`** atomic flag when handling host-to-device updates.
- Users can disable autosync with **`--no-clipboard-autosync`** while retaining manual clipboard retrieval via COPY/CUT key events.

## Frequently Asked Questions

### How do I disable automatic clipboard synchronization in Scrcpy?

Use the command-line flag `--no-clipboard-autosync` when launching scrcpy. This prevents the controller from registering the primary-clip-changed listener, stopping automatic device-to-host updates while still allowing manual clipboard retrieval when you press COPY or CUT on the device.

### Does Scrcpy support clipboard synchronization on all Android devices?

No. If the Android device does not expose the `clipboard` system service, `ServiceManager.getClipboardManager()` returns `null` and both synchronization directions gracefully degrade to no-ops. Scrcpy logs a warning (`"No clipboard manager"`) in this scenario but continues operating normally.

### How does Scrcpy prevent infinite loops when synchronizing clipboards?

The `Controller` class uses an `AtomicBoolean` named `isSettingClipboard` as a guard flag. When the controller writes to the device clipboard (host-to-device), it sets this flag to `true`. The primary-clip-changed listener checks this flag and skips processing when it is `true`, preventing the controller from reacting to its own changes.

### Can I paste text from my computer directly into an Android app using Scrcpy?

Yes. When you copy text on your host computer, scrcpy sends a `set-clipboard` control message to the Android device. If you trigger a paste action (typically `Ctrl+V`), the controller not only sets the device clipboard but also injects `KEYCODE_PASTE` into the focused Android application, completing the paste operation automatically.