From 5ba1abac11dda67c01be6d630ceb519e2bddd43b Mon Sep 17 00:00:00 2001 From: Robertkill Date: Mon, 8 Jun 2026 10:58:43 +0800 Subject: [PATCH] fix: prevent polkit popup when session is in background MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Added SessionStateTracker using login1 User.Display to get current session path, then query Session.Active property 2. Guard conn->save() calls in DeviceManagerRealize and DeviceInterRealize with session active check to prevent unnecessary polkit authentication requests when user switches to another session 3. Use leaky singleton pattern for SessionStateTracker to avoid destructor race conditions with static local objects Influence: 1. Test switching between user sessions (e.g. switch to aaa desktop) and verify no polkit popup (settings.modify.system) appears on the background session 2. Verify WiFi connection saving still works correctly when session is in foreground 3. Check that network settings are properly saved when user is actively using the session 4. Test with multiple user sessions and verify no crashes on logout/login fix: 防止会话在后台时弹出polkit弹框 1. 添加SessionStateTracker,通过login1 User.Display获取当前用户主会话 路径,查询Session.Active属性判断会话状态 2. 在DeviceManagerRealize和DeviceInterRealize中用会话活跃状态守护 conn->save()调用,防止用户切换到其他会话时触发不必要的polkit认证请求 3. 使用leaky singleton模式避免静态局部对象析构竞态问题 Influence: 1. 测试在用户会话间切换(如切换到aaa桌面)时,后台会话不会弹出polkit弹框 2. 验证会话在前台时WiFi连接保存功能正常 3. 检查用户活跃使用会话时网络设置能正确保存 4. 测试多用户会话场景,验证注销/登录时无崩溃 PMS: BUG-363065 --- .../networkmanager/devicemanagerrealize.cpp | 29 ++-- .../networkmanagerprocesser.cpp | 8 ++ src/impl/networkmanager/sessionstatetracker.h | 136 ++++++++++++++++++ src/impl/serviceinter/deviceinterrealize.cpp | 17 ++- 4 files changed, 171 insertions(+), 19 deletions(-) create mode 100644 src/impl/networkmanager/sessionstatetracker.h diff --git a/src/impl/networkmanager/devicemanagerrealize.cpp b/src/impl/networkmanager/devicemanagerrealize.cpp index d9a34eeae..3ad7b6b3e 100644 --- a/src/impl/networkmanager/devicemanagerrealize.cpp +++ b/src/impl/networkmanager/devicemanagerrealize.cpp @@ -10,6 +10,7 @@ #include "configsetting.h" #include "ipmanager.h" #include "nmnetworkmanager.h" +#include "sessionstatetracker.h" #include #include @@ -846,12 +847,14 @@ void WirelessDeviceManagerRealize::connectNetwork(const AccessPoints *accessPoin wsSetting->setInitialized(keyMgmt != NetworkManager::WirelessSecuritySetting::KeyMgmt::WpaNone && keyMgmt != NetworkManager::WirelessSecuritySetting::KeyMgmt::Unknown); NMVariantMapMap settingMap = currentConnection->settings()->toMap(); qCDebug(DNC) << "securit changed..." << settingMap; - if (currentConnection->isUnsaved()) { - currentConnection->updateUnsaved(settingMap); - } else { - currentConnection->update(settingMap); - QDBusPendingReply<> reply = currentConnection->save(); - reply.waitForFinished(); + if (SessionStateTracker::instance()->isSessionActive()) { + if (currentConnection->isUnsaved()) { + currentConnection->updateUnsaved(settingMap); + } else { + currentConnection->update(settingMap); + QDBusPendingReply<> reply = currentConnection->save(); + reply.waitForFinished(); + } } } QVariantMap options; @@ -1009,14 +1012,16 @@ void WirelessDeviceManagerRealize::onActiveConnectionChanged() if (activeAp && conn) { conn->settings()->setTimestamp(QDateTime::currentDateTime()); if (state == NetworkManager::ActiveConnection::Activated && conn->isUnsaved()) { - const NetworkManager::Setting::SettingType settingType[] = { NetworkManager::Setting::Security8021x, NetworkManager::Setting::WirelessSecurity }; - for (auto type : settingType) { - NetworkManager::Setting::Ptr setting = conn->settings()->setting(type); - if (setting) { - conn->secrets(setting->name()); + if (SessionStateTracker::instance()->isSessionActive()) { + const NetworkManager::Setting::SettingType settingType[] = { NetworkManager::Setting::Security8021x, NetworkManager::Setting::WirelessSecurity }; + for (auto type : settingType) { + NetworkManager::Setting::Ptr setting = conn->settings()->setting(type); + if (setting) { + conn->secrets(setting->name()); + } } + conn->save(); } - conn->save(); connect(conn.data(), &NetworkManager::Connection::unsavedChanged, this, [this] { Q_EMIT activeConnectionChanged(); }); diff --git a/src/impl/networkmanager/networkmanagerprocesser.cpp b/src/impl/networkmanager/networkmanagerprocesser.cpp index a8b1d0f6c..a0911faa3 100644 --- a/src/impl/networkmanager/networkmanagerprocesser.cpp +++ b/src/impl/networkmanager/networkmanagerprocesser.cpp @@ -7,6 +7,7 @@ #include "hotspotcontrollernm.h" #include "networkdevicebase.h" #include "networkmanagerprocesser.h" +#include "sessionstatetracker.h" #include "proxycontrollernm.h" #include "vpncontrollernm.h" #include "networkdetails.h" @@ -80,6 +81,13 @@ void NetworkManagerProcesser::initConnections() connect(NetworkManager::notifier(), &NetworkManager::Notifier::activeConnectionsChanged, this, &NetworkManagerProcesser::onUpdateNetworkDetail); // 当网络状态发生变化时,也刷新Detail connect(NetworkManager::notifier(), &NetworkManager::Notifier::statusChanged, this, &NetworkManagerProcesser::onUpdateNetworkDetail); + // 会话从后台切回前台时,本地用户主动刷新网络状态 + connect(SessionStateTracker::instance(), &SessionStateTracker::sessionResumed, this, [this] { + if (SessionStateTracker::instance()->isLocalUser()) { + qCDebug(DNC) << "session resumed, refreshing network state"; + onUpdateNetworkDetail(); + } + }); } void NetworkManagerProcesser::onDevicesChanged(const QList &devices) diff --git a/src/impl/networkmanager/sessionstatetracker.h b/src/impl/networkmanager/sessionstatetracker.h new file mode 100644 index 000000000..fdad83839 --- /dev/null +++ b/src/impl/networkmanager/sessionstatetracker.h @@ -0,0 +1,136 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later +#ifndef SESSIONSTATETRACKER_H +#define SESSIONSTATETRACKER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class SessionStateTracker : public QObject { + Q_OBJECT +public: + static SessionStateTracker *instance() { + static SessionStateTracker *s_instance = new SessionStateTracker(); + return s_instance; + } + + bool isSessionActive() const { + return m_userActive; + } + + bool isLocalUser() const { + return m_isLocal; + } + +private: + SessionStateTracker() + : QObject(nullptr) + , m_userActive(true) + , m_isLocal(false) + { + // Step 1: 异步获取 User.Display(session 路径) + QDBusMessage msg = QDBusMessage::createMethodCall( + "org.freedesktop.login1", + "/org/freedesktop/login1/user/self", + "org.freedesktop.DBus.Properties", + "Get" + ); + msg << "org.freedesktop.login1.User" << "Display"; + QDBusConnection::systemBus().callWithCallback(msg, this, SLOT(onDisplayReady(QDBusVariant))); + } + + ~SessionStateTracker() = default; + SessionStateTracker(const SessionStateTracker &) = delete; + SessionStateTracker &operator=(const SessionStateTracker &) = delete; + +private slots: + void onDisplayReady(const QDBusVariant &display) { + const QDBusArgument arg = display.variant().value(); + QString id; + QDBusObjectPath path; + arg.beginStructure(); + arg >> id >> path; + arg.endStructure(); + + if (path.path().isEmpty()) { + qWarning() << "[SessionStateTracker] Display empty, keep default active"; + return; + } + + // Step 2: 检查 Remote 属性 + QDBusMessage remoteMsg = QDBusMessage::createMethodCall( + "org.freedesktop.login1", + path.path(), + "org.freedesktop.DBus.Properties", + "Get" + ); + remoteMsg << "org.freedesktop.login1.Session" << "Remote"; + QDBusPendingReply remoteReply = QDBusConnection::systemBus().asyncCall(remoteMsg); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(remoteReply, this); + connect(watcher, &QDBusPendingCallWatcher::finished, this, [path, this](QDBusPendingCallWatcher *self) { + QDBusPendingReply reply = *self; + bool remote = !reply.isError() && reply.value().variant().toBool(); + if (!remote) { + m_isLocal = true; + // Step 3: 监听 Active 变化 + QDBusConnection::systemBus().connect( + "org.freedesktop.login1", + path.path(), + "org.freedesktop.DBus.Properties", + "PropertiesChanged", + this, + SLOT(onSessionPropertiesChanged(QString, QVariantMap, QStringList)) + ); + // 同时读一次初始 Active 状态 + QDBusMessage activeMsg = QDBusMessage::createMethodCall( + "org.freedesktop.login1", + path.path(), + "org.freedesktop.DBus.Properties", + "Get" + ); + activeMsg << "org.freedesktop.login1.Session" << "Active"; + QDBusPendingReply activeReply = QDBusConnection::systemBus().asyncCall(activeMsg); + QDBusPendingCallWatcher *activeWatcher = new QDBusPendingCallWatcher(activeReply, this); + connect(activeWatcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *sw) { + QDBusPendingReply sr = *sw; + if (!sr.isError()) { + m_userActive = sr.value().variant().toBool(); + } + sw->deleteLater(); + }); + } + self->deleteLater(); + }); + } + + void onSessionPropertiesChanged(const QString &interface, const QVariantMap &properties, const QStringList &) { + if (interface == "org.freedesktop.login1.Session" && properties.contains("Active")) { + m_userActive = properties.value("Active").toBool(); + if (m_userActive) { + qWarning() << "[SessionStateTracker] session resumed"; + Q_EMIT sessionResumed(); + } else { + qWarning() << "[SessionStateTracker] session left"; + } + } + } + +signals: + void sessionResumed(); + +private: + bool m_userActive; + bool m_isLocal; +}; + +#endif // SESSIONSTATETRACKER_H \ No newline at end of file diff --git a/src/impl/serviceinter/deviceinterrealize.cpp b/src/impl/serviceinter/deviceinterrealize.cpp index b1d9c1296..83d4f6f46 100644 --- a/src/impl/serviceinter/deviceinterrealize.cpp +++ b/src/impl/serviceinter/deviceinterrealize.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2018-2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -7,6 +7,7 @@ #include "wireddevice.h" #include "wirelessdevice.h" #include "accesspointsproxyinter.h" +#include "../networkmanager/sessionstatetracker.h" #include @@ -366,14 +367,16 @@ void DeviceInterRealize::onActiveConnectionChanged() connect(activeConnection.data(), &NetworkManager::ActiveConnection::stateChanged, this, [ activeConnection, this ](NetworkManager::ActiveConnection::State state) { if (state == NetworkManager::ActiveConnection::State::Activated) { NetworkManager::Connection::Ptr conn = activeConnection->connection(); - const NetworkManager::Setting::SettingType settingType[] = { NetworkManager::Setting::Security8021x, NetworkManager::Setting::WirelessSecurity }; - for (auto type : settingType) { - NetworkManager::Setting::Ptr setting = conn->settings()->setting(type); - if (setting) { - conn->secrets(setting->name()); + if (SessionStateTracker::instance()->isSessionActive()) { + const NetworkManager::Setting::SettingType settingType[] = { NetworkManager::Setting::Security8021x, NetworkManager::Setting::WirelessSecurity }; + for (auto type : settingType) { + NetworkManager::Setting::Ptr setting = conn->settings()->setting(type); + if (setting) { + conn->secrets(setting->name()); + } } + conn->save(); } - conn->save(); connect(conn.data(), &NetworkManager::Connection::unsavedChanged, this, [this] { Q_EMIT activeConnectionChanged(); });