# Behavior traces — Genymobile/scrcpy

> Canonical page: https://codevetter.com/unpack/scrcpy/behavior-traces

# Behavior traces — Genymobile/scrcpy

Scanned commit 19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac (2026-09-05). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

Three end-to-end flows were traced. (1) Startup: CLI parse -> SDL init -> server thread does adb start-server, device selection, push, tunnel open, app_process exec, socket handshake, device meta read -> demuxer/decoder/screen init -> SDL event loop. (2) Input: SDL key/mouse event -> input_manager/keyboard_sdk/mouse_sdk -> sc_control_msg -> controller queue -> serialized write -> server ControlMessageReader -> Controller.handleEvent -> Device.injectEvent or UhidManager. (3) Shutdown/disconnect: SDL_QUIT or demuxer EOS -> sc_server_stop interrupts sockets -> adb process watchdog (1s grace then SIGKILL) -> threads joined in careful order (demuxers before screen destroy).
- Startup order in main_scrcpy(): parse args -> set log level -> optional terminal title -> net_init() -> sc_main_thread_init() -> scrcpy(&opts); scrcpy() then SDL_Init(EVENTS) -> sc_server_init + sc_sdl_set_hints -> sc_server_start. — [app/src/main.c#L27-126](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/main.c#L27-L126) [app/src/scrcpy.c#L320-449](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/scrcpy.c#L320-L449)
- Server-connection trace (run_server thread): sc_adb_start_server -> sc_adb_select_device (serial/-e/-d/$ANDROID_SERIAL) -> optional TCP/IP switch -> push_server -> sc_adb_tunnel_open -> execute_server -> sc_process_observer_init -> sc_server_connect_to -> cbs->on_connected. — [app/src/server.c#L964-1122](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/server.c#L964-L1122)
- Tunnel connect: in reverse mode the client accept()s video then audio then control sockets on the adb-forwarded local socket; in forward mode it connect()s with retry (100 attempts x 100ms) and a dummy-byte read to detect dead tunnels; control socket gets TCP_NODELAY. — [app/src/server.c#L489-714](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/server.c#L489-L714) [server/src/main/java/com/genymobile/scrcpy/device/DesktopConnection.java#L56-116](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/server/src/main/java/com/genymobile/scrcpy/device/DesktopConnection.java#L56-L116)
- Post-connect init order in scrcpy(): file_pusher -> video/audio demuxer init -> decoders attached as packet sinks -> recorder init+start -> controller configure/start -> screen init -> demuxer start -> optional screen-off msg, timeout, start-app msg -> event_loop(). — [app/src/scrcpy.c#L521-906](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/scrcpy.c#L521-L906)
- Server-side startup: Server.scrcpy() applies Workarounds, opens DesktopConnection, sends device meta, creates Controller (control), audio capture+encoder, SurfaceCapture+SurfaceEncoder, then starts each AsyncProcessor and blocks in Looper.loop() until Completion counts them down or a fatal error quits the looper. — [server/src/main/java/com/genymobile/scrcpy/Server.java#L71-195](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/server/src/main/java/com/genymobile/scrcpy/Server.java#L71-L195)
- Keyboard trace: SDL key event -> sc_input_manager (shortcut_mods decide local shortcut vs device key) -> keyboard_sdk builds INJECT_KEYCODE/INJECT_TEXT msgs -> sc_controller_push_msg -> run_controller -> sc_control_msg_serialize -> socket -> ControlMessageReader.parseInjectKeycode -> Controller.injectKeycode -> Device.injectEvent(ASYNC). — [app/src/input_manager.c#L61-106](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/input_manager.c#L61-L106) [app/src/keyboard_sdk.c](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/keyboard_sdk.c) [app/src/controller.c#L95-160](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/controller.c#L95-L160) [server/src/main/java/com/genymobile/scrcpy/control/ControlMessageReader.java#L72-78](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/server/src/main/java/com/genymobile/scrcpy/control/ControlMessageReader.java#L72-L78) [server/src/main/java/com/genymobile/scrcpy/control/Controller.java#L443-468](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/server/src/main/java/com/genymobile/scrcpy/control/Controller.java#L443-L468)
- Clipboard device->host trace: ClipboardManager.addPrimaryClipChangedListener -> Device.getClipboardText -> DeviceMessageSender.send -> control socket -> client receiver thread -> sc_device_msg_deserialize -> task_set_clipboard on main thread -> SDL_SetClipboardText. — [server/src/main/java/com/genymobile/scrcpy/control/Controller.java#L146-159](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/server/src/main/java/com/genymobile/scrcpy/control/Controller.java#L146-L159) [app/src/receiver.c#L40-60](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/receiver.c#L40-L60) [app/src/device_msg.h#L14-35](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/device_msg.h#L14-L35)
- Event loop dispatch: SC_EVENT_DEVICE_DISCONNECTED/CONTROLLER_ERROR/DEMUXER_ERROR/RECORDER_ERROR/AOA_OPEN_ERROR/TIME_LIMIT_REACHED map to exit codes; all other events (including SC_EVENT_NEW_FRAME, SC_EVENT_OPEN_WINDOW pushed by screen) go to sc_screen_handle_event(). — [app/src/scrcpy.c#L116-153](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/scrcpy.c#L116-L153) [app/src/screen.c#L1130-1262](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/screen.c#L1130-L1262)
- Demuxer end-of-stream posts SC_EVENT_DEVICE_DISCONNECTED (EOS) or SC_EVENT_DEMUXER_ERROR; audio demuxer tolerates DISABLED unless --require-audio; video DISABLED is asserted impossible. — [app/src/scrcpy.c#L193-225](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/scrcpy.c#L193-L225)
- Shutdown: event_loop returns -> sc_main_thread_stop drains pending runnables -> sc_server_stop sets stopped + interrupts -> run_server net_interrupt()s the three sockets, waits 1s WATCHDOG_DELAY then sc_process_terminate -> demuxers/screen/controller joined in dependency order (screen destroyed only after demuxer join). — [app/src/scrcpy.c#L906-1035](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/scrcpy.c#L906-L1035) [app/src/server.c#L1131-1171](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/server.c#L1131-L1171)
- Recording trace: --record -> sc_recorder_init + start before demuxer start; demuxer packet_source pushes AVPacket refs into recorder sinks; recorder thread dequeues, rescales PTS, writes via av_interleaved_write_frame; on_ended failure posts SC_EVENT_RECORDER_ERROR. — [app/src/scrcpy.c#L564-589](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/scrcpy.c#L564-L589) [app/src/recorder.c#L40-120](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/recorder.c#L40-L120) [app/src/scrcpy.c#L182-191](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/scrcpy.c#L182-L191)
- UHID input trace (e.g. --keyboard=uhid): sc_keyboard_uhid_init registers a virtual device; key events -> HID report -> UHID_INPUT control msg -> server UhidManager.writeInput -> /dev/uhid; device output reports come back as DEVICE_MSG_TYPE_UHID_OUTPUT handled by receiver -> uhid_output task. — [app/src/uhid/keyboard_uhid.c](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/uhid/keyboard_uhid.c) [app/src/uhid/uhid_output.c](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/uhid/uhid_output.c) [server/src/main/java/com/genymobile/scrcpy/control/Controller.java#L398-406](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/server/src/main/java/com/genymobile/scrcpy/control/Controller.java#L398-L406) [app/src/receiver.c#L14-18](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/receiver.c#L14-L18)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
