Skip to content

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

@zccrs

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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions