Skip to content

DDM does not recover after unexpected dde-seatd control socket loss #99

Description

@zccrs

Summary

DDM does not recover cleanly if the dde-seatd control socket disappears unexpectedly.

DdeSeatdControl disconnects and clears its cached state on socket error, but it does not attempt to reconnect. If dde-seatd dies and comes back, DDM can stay alive while permanently losing VT change notifications.

Current behavior

src/daemon/DdeSeatdControl.cpp uses /run/dde-seatd-control.sock and does this on failure:

  • connectEventSocket() fails -> log + give up
  • handleEventSocketError() -> disconnectEventSocket()
  • disconnectEventSocket() clears the socket and cached VT state

There is no retry loop and no service-level recovery path inside DDM.

Why this matters

I validated the systemd side separately:

  • if dde-seatd is explicitly stopped/restarted by systemctl, Requires= is enough for systemd to stop/restart dependent services in the same transaction
  • but if the dde-seatd process dies unexpectedly, a plain Requires= dependency does not tear down already-running dependents

That means DDM can remain running while its control socket is gone.

At that point VT change handling is effectively dead until something else restarts DDM.

Reproduction

A minimal systemd reproducer shows the difference clearly:

  • Requires=seatd.service + After=seatd.service
  • start both services
  • kill the seatd main pid directly

Observed result:

  • seatd.service becomes inactive
  • the dependent service stays active

This matches the socket-loss case in DDM: the daemon can survive while the control channel is gone.

Proposed fixes

I see two complementary options:

  1. Make DDM self-heal

    • add reconnect/backoff logic in DdeSeatdControl
    • re-establish the event socket after errorOccurred / disconnected
    • refresh cached active VT after reconnect
  2. Make the service dependency stricter

    • upgrade the unit relationship from Requires= to BindsTo= for the dde-seatd.service dependency
    • keep Restart=always on DDM so a dde-seatd death causes DDM to be torn down and brought back together with the seat daemon

I validated the second approach with a minimal systemd setup:

  • BindsTo=seatd.service
  • Restart=always on both services
  • kill the seatd main pid

Observed result:

  • seatd is restarted
  • the dependent service is also restarted

Files

  • src/daemon/DdeSeatdControl.cpp
  • services/ddm.service.in

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