shell: resolve logind session via User.Display, re-register after sessiond restart
SessionEvents asked loginctl for -p ObjectPath, which is not a property — it returned empty on every boot, so external lock signals were never monitored and the shell had no unlock ingress. Resolve the graphical session the way lockhint.rs does; not GetSession(auto) (this shell is a session-less user unit) and not the /session/auto alias (PropertiesChanged only fires on the concrete path). SessiondBridge read root.registered to decide whether to re-register on reconnect, but the disconnect branch had already cleared it, so the shell never re-registered after a sessiond restart. Latch it.
This commit is contained in:
parent
45fc69b56a
commit
4ed8f3dd74
2 changed files with 33 additions and 22 deletions
|
|
@ -76,38 +76,43 @@ Singleton {
|
||||||
signal sleepInhibitorAcquired()
|
signal sleepInhibitorAcquired()
|
||||||
|
|
||||||
// --- Session path resolution -------------------------------------------
|
// --- Session path resolution -------------------------------------------
|
||||||
// The logind session D-Bus object path contains the session ID with dots
|
// Resolve the graphical session's REAL object path via the user's `Display`
|
||||||
// replaced by underscores (session "3" -> /org/freedesktop/login1/session/_3,
|
// session. sessiond resolves exactly this way; see the two measured traps
|
||||||
// session "c1" -> /org/freedesktop/login1/session/_c1). We resolve it once
|
// documented on `resolve_session_path` in src/sessiond/lockhint.rs:
|
||||||
// at startup by asking logind for the current session's object path.
|
//
|
||||||
|
// Not `auto`. `GetSession("auto")` resolves to the CALLER's session, and
|
||||||
|
// this shell is a systemd user unit under user@1000.service, outside any
|
||||||
|
// session scope — it has no session of its own to name.
|
||||||
|
//
|
||||||
|
// Not the `auto` path either. /org/freedesktop/login1/session/auto is an
|
||||||
|
// alias, not an object: PropertiesChanged only fires on the concrete
|
||||||
|
// path, so monitoring the alias subscribes to something never delivered.
|
||||||
|
//
|
||||||
|
// The user's `Display` session is the graphical one by definition, whoever
|
||||||
|
// asks. The previous probe here asked for a `-p ObjectPath` property that
|
||||||
|
// loginctl does not have, so it returned empty on every boot and external
|
||||||
|
// lock signals were never monitored at all.
|
||||||
Process {
|
Process {
|
||||||
id: sessionResolver
|
id: sessionResolver
|
||||||
running: true
|
running: true
|
||||||
command: ["sh", "-c",
|
command: ["sh", "-c",
|
||||||
// loginctl list-sessions -p Name gives the first session's user;
|
"busctl --system get-property org.freedesktop.login1 "
|
||||||
// show-session with no argument operates on the caller's session.
|
+ "/org/freedesktop/login1/user/_$(id -u) "
|
||||||
// -p ObjectPath gives the D-Bus path directly, no encoding needed.
|
+ "org.freedesktop.login1.User Display 2>/dev/null"]
|
||||||
"loginctl show-session -p ObjectPath 2>/dev/null | head -1"]
|
|
||||||
stdout: StdioCollector {
|
stdout: StdioCollector {
|
||||||
onStreamFinished: {
|
onStreamFinished: {
|
||||||
const raw = text.trim();
|
const raw = text.trim();
|
||||||
// loginctl outputs ObjectPath=/org/freedesktop/login1/session/_3
|
// `(so) "1" "/org/freedesktop/login1/session/_31"` — the object
|
||||||
const match = raw.match(/^ObjectPath=(.+)$/);
|
// path is the second quoted field.
|
||||||
if (match && match[1].length > 0) {
|
const path = raw.split('"')[3];
|
||||||
root.sessionPath = match[1];
|
if (path && path.startsWith("/org/freedesktop/login1/session/")) {
|
||||||
|
root.sessionPath = path;
|
||||||
console.log("[session-events] session path:", root.sessionPath);
|
console.log("[session-events] session path:", root.sessionPath);
|
||||||
sessionLockMonitor.running = true;
|
sessionLockMonitor.running = true;
|
||||||
} else if (raw.length > 0) {
|
} else if (raw.length > 0) {
|
||||||
// Some logind versions print just the path without the key.
|
console.log("[session-events] could not parse Display session from:", raw);
|
||||||
if (raw.startsWith("/org/freedesktop/login1/session/")) {
|
|
||||||
root.sessionPath = raw;
|
|
||||||
console.log("[session-events] session path (bare):", root.sessionPath);
|
|
||||||
sessionLockMonitor.running = true;
|
|
||||||
} else {
|
|
||||||
console.log("[session-events] could not parse session path from:", raw);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
console.log("[session-events] no session path returned; "
|
console.log("[session-events] no Display session for this user; "
|
||||||
+ "external lock signals will not be monitored");
|
+ "external lock signals will not be monitored");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,10 @@ Singleton {
|
||||||
|
|
||||||
// Registered = shell_ready was answered ok on the CURRENT connection.
|
// Registered = shell_ready was answered ok on the CURRENT connection.
|
||||||
property bool registered: false
|
property bool registered: false
|
||||||
|
// Latched copy of `registered` taken when the connection drops. The
|
||||||
|
// disconnect branch clears `registered` before the reconnect branch runs,
|
||||||
|
// so reconnect cannot read it directly to decide whether to re-register.
|
||||||
|
property bool wasRegistered: false
|
||||||
// sessiond held the session lock when we registered; we owe it a lock
|
// sessiond held the session lock when we registered; we owe it a lock
|
||||||
// and a locked_ack.
|
// and a locked_ack.
|
||||||
property bool oweLock: false
|
property bool oweLock: false
|
||||||
|
|
@ -112,8 +116,9 @@ Singleton {
|
||||||
onConnectionStateChanged: {
|
onConnectionStateChanged: {
|
||||||
if (sock.connected) {
|
if (sock.connected) {
|
||||||
console.log("[sessiond-bridge] connected");
|
console.log("[sessiond-bridge] connected");
|
||||||
const wasRegistered = root.registered;
|
const wasRegistered = root.wasRegistered;
|
||||||
root.registered = false;
|
root.registered = false;
|
||||||
|
root.wasRegistered = false;
|
||||||
root.ackSent = false;
|
root.ackSent = false;
|
||||||
if (wasRegistered) {
|
if (wasRegistered) {
|
||||||
root.shellReady(function(mustLock) {
|
root.shellReady(function(mustLock) {
|
||||||
|
|
@ -126,6 +131,7 @@ Singleton {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log("[sessiond-bridge] disconnected");
|
console.log("[sessiond-bridge] disconnected");
|
||||||
|
root.wasRegistered = root.registered;
|
||||||
root.registered = false;
|
root.registered = false;
|
||||||
root.pendingReady = null;
|
root.pendingReady = null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue