D-Bus——system 调用session 报错

2024-06-13 04:36
文章标签 报错 调用 bus system session

本文主要是介绍D-Bus——system 调用session 报错,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

以下代码是一个 session 服务和 systemd 服务 demo :

systemd DBus
#include <QCoreApplication>
#include <QDBusConnection>
#include <QDBusInterface>
#include <QDBusError>
#include <QDebug>class TestObject : public QObject
{Q_OBJECT
public:TestObject() {registerSystemDBus();callSession()}void registerSystemDBus() {QDBusConnection systemBus = QDBusConnection::systemBus();if (!systemBus.isConnected()) {qDebug() << "Failed to connect to system bus:" << systemBus.lastError().message();return;}if (!systemBus.registerService("com.example.TestSystemdService")) {qDebug() << "Failed to register service:" << systemBus.lastError().message();return;}if (!systemBus.registerObject("/com/example/TestObject",this,QDBusConnection::ExportAllSlots)) {qDebug() << "Failed to register object:" << systemBus.lastError().message();return;}}void callSession(){QDBusInterface interface("com.example.TestService","/com/example/TestObject","local.session.MainWindow",QDBusConnection::sessionBus());if (!interface.isValid()) {qDebug() << "Failed to create interface:" << interface.lastError().message();return;}QDBusMessage reply = interface.call("testMethod");if (reply.type() == QDBusMessage::ErrorMessage) {qDebug() << "Call failed:" << reply.errorMessage();} else {qDebug() << "Call succeeded.";}}public slots:void testMethod() {qDebug() << "testMethod called";}
};int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);TestObject testObject;QString path = QProcessEnvironment::systemEnvironment().value("DBUS_SESSION_BUS_ADDRESS");qDebug() << "path is " << path; // path is  ""return a.exec();
}#include "main.moc"cmakelistcmake_minimum_required(VERSION 3.14)project(systemd LANGUAGES CXX)set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core)
find_package(Qt5DBus)find_package(PkgConfig REQUIRED)
pkg_check_modules(QGSettings REQUIRED gsettings-qt)add_executable(systemdmain.cpp
)
target_link_libraries(systemd Qt${QT_VERSION_MAJOR}::CoreQt5::DBus${QGSettings_LIBRARIES})install(TARGETS systemdLIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
session DBus#include "mainwindow.h"
#include "./ui_mainwindow.h"#include <QDebug>
#include <QDBusConnection>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);QString path = QProcessEnvironment::systemEnvironment().value("DBUS_SESSION_BUS_ADDRESS");qDebug() << "path is " << path; // path is  "unix:path=/run/user/1000/bus"registerSessionDBus();
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::registerSessionDBus()
{QDBusConnection::sessionBus().registerService("com.example.TestService");if (!QDBusConnection::sessionBus().registerObject("/com/example/TestObject",this, QDBusConnection::ExportAllSlots)) {qDebug() << "fail";}
}void MainWindow::testMethod()
{qDebug() << "test";
}cmakelistcmake_minimum_required(VERSION 3.5)project(session VERSION 0.1 LANGUAGES CXX)set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)
find_package(Qt5DBus)find_package(PkgConfig REQUIRED)
pkg_check_modules(QGSettings REQUIRED gsettings-qt)set(PROJECT_SOURCESmain.cppmainwindow.cppmainwindow.hmainwindow.ui
)if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)qt_add_executable(sessionMANUAL_FINALIZATION${PROJECT_SOURCES})
# Define target properties for Android with Qt 6 as:
#    set_property(TARGET session APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
#                 ${CMAKE_CURRENT_SOURCE_DIR}/android)
# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation
else()if(ANDROID)add_library(session SHARED${PROJECT_SOURCES})
# Define properties for Android with Qt 5 after find_package() calls as:
#    set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")else()add_executable(session${PROJECT_SOURCES})endif()
endif()target_link_libraries(session PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt5::DBus ${QGSettings_LIBRARIES})set_target_properties(session PROPERTIESMACOSX_BUNDLE_GUI_IDENTIFIER my.example.comMACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}MACOSX_BUNDLE TRUEWIN32_EXECUTABLE TRUE
)install(TARGETS sessionBUNDLE DESTINATION .LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})if(QT_VERSION_MAJOR EQUAL 6)qt_finalize_executable(session)
endif()

        当在 Systemed DBus 服务中,调用 session DBus 服务的接口,会发现即使 session 服务在运行,但依然会报如下错误:

Failed to create interface: "Not connected to D-Bus server"

        此时当我们在 demo 中增加以下日志输出,会发现在 root 下,DBUS_SESSION_BUS_ADDRESS 输出为空。

QString path = QProcessEnvironment::systemEnvironment().value("DBUS_SESSION_BUS_ADDRESS");qDebug() << "session service print path is " << path; // "unix:path=/run/user/1000/bus"
qDebug() << "system service print path is " << path; // ""

        而 DBUS_SESSION_BUS_ADDRESS 为空,即为导致报错的原因,在解释 DBUS_SESSION_BUS_ADDRESS 为空会导致报错的原因之前,先了解几个概念:

dbus-daemon: 是 D-Bus 守护进程的实际实现,用于管理和协调消息传递,作为 D-Bus 的消息中转枢纽,可分成 system 和 session 两种。

System Bus:这个总线用于系统范围内的通信,通常涉及到系统服务和守护进程。

Session Bus:这个总线用于用户会话范围内的通信,通常涉及到用户应用程序。

DBUS_SESSION_BUS_ADDRESS:环境变量,用于存储会话总线的地址。

dbus-daemon官方文档参数介绍

        当用户登录时,会启动一个 dbus-daemon --session 进程,这个进程会创建一个会话总线并生成一个唯一的地址。这个地址会存储在 DBUS_SESSION_BUS_ADDRESS 环境变量中。当某个应用程序需要和其他应用程序通信时,它会读取 DBUS_SESSION_BUS_ADDRESS 环境变量来找到会话总线并进行通信。如果这个环境变量为空或者没有正确设置,服务将无法连接到会话总线,从而导致无法找到目标服务文件。

参考文献

D-Bus Specification

dbus-daemon

systemd/User - ArchWiki

解决方案供参考

        如果你给 root 用户导入了普通用户的 DBUS_SESSION_BUS_ADDRESS 环境变量,但仍然不能访问会话总线(session bus)服务,可能有以下几个原因:

1. 权限问题

        会话总线的 Unix 套接字通常设置为只有特定用户才能访问。即使你将 DBUS_SESSION_BUS_ADDRESS 设置为指向普通用户的会话总线地址,root 用户可能没有访问该套接字的权限。

2. 会话总线的安全策略

        D-Bus 有一套安全策略,用于限制哪些用户和进程可以访问哪些服务。即使 root 用户可以访问会话总线地址,也可能被会话总线的安全策略阻止访问特定服务。

3. 会话总线的用户隔离

        会话总线通常设计为与用户会话隔离。每个用户会话有自己的会话总线,且这些总线是相互隔离的,防止不同用户会话之间的干扰。

解决方案

方法一:修改会话总线套接字权限

        你可以尝试修改会话总线套接字的权限,以允许 root 用户访问。这种方法比较危险,需要谨慎操作:

查看套接字的权限:

ls -l /run/user/1000/bus

修改套接字的权限(不推荐):

chmod 777 /run/user/1000/bus

        这种方法会将套接字的权限设置为所有用户可读写,但可能会带来安全风险。

方法二:使用 dbus-launch

可以使用 dbus-launch 在 root 会话中启动一个新的会话总线:

启动一个新的会话总线:

sudo dbus-launch --sh-syntax

        这会输出一组新的环境变量,包括 DBUS_SESSION_BUS_ADDRESS。

导出这些环境变量:

export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus

运行需要访问会话总线的命令:

your_command_here

方法三:通过代理或中继访问

        可以通过代理或中继的方式在 root 环境中访问用户会话总线服务。这种方法需要设置一些额外的工具和配置。

        假设你需要让 root 用户访问普通用户的 D-Bus 服务,可以尝试以下步骤:

启动新会话总线

        (如果需要 root 用户有自己的会话总线):sudo dbus-launch --sh-syntax

导出新的会话总线环境变量

        将命令输出的环境变量导出到当前环境。

确保会话总线地址正确设置

        确保 DBUS_SESSION_BUS_ADDRESS 环境变量正确指向普通用户的会话总线地址。

测试访问服务        

        尝试从 root 用户运行需要访问会话总线服务的命令,确认是否能够成功访问。

# 获取普通用户的 DBUS_SESSION_BUS_ADDRESS
USER_DBUS_SESSION_BUS_ADDRESS=$(sudo -u your_username echo $DBUS_SESSION_BUS_ADDRESS)# 切换到 root 用户并导出会话总线地址
sudo -i <<EOF
export DBUS_SESSION_BUS_ADDRESS=$USER_DBUS_SESSION_BUS_ADDRESS
your_command_here
EOF

总结

        即使将 DBUS_SESSION_BUS_ADDRESS 环境变量正确设置为普通用户的会话总线地址,root 用户可能仍然无法访问会话总线服务,原因包括权限问题、安全策略和用户会话隔离等。可以尝试修改套接字权限、使用 dbus-launch 启动新的会话总线或通过代理访问来解决这个问题,但每种方法都有其限制和风险。

这篇关于D-Bus——system 调用session 报错的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1056293

相关文章

如何解决mmcv无法安装或安装之后报错问题

《如何解决mmcv无法安装或安装之后报错问题》:本文主要介绍如何解决mmcv无法安装或安装之后报错问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录mmcv无法安装或安装之后报错问题1.当我们运行YOwww.chinasem.cnLO时遇到2.找到下图所示这里3.

浅谈配置MMCV环境,解决报错,版本不匹配问题

《浅谈配置MMCV环境,解决报错,版本不匹配问题》:本文主要介绍浅谈配置MMCV环境,解决报错,版本不匹配问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录配置MMCV环境,解决报错,版本不匹配错误示例正确示例总结配置MMCV环境,解决报错,版本不匹配在col

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

SpringBoot启动报错的11个高频问题排查与解决终极指南

《SpringBoot启动报错的11个高频问题排查与解决终极指南》这篇文章主要为大家详细介绍了SpringBoot启动报错的11个高频问题的排查与解决,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一... 目录1. 依赖冲突:NoSuchMethodError 的终极解法2. Bean注入失败:No qu

在C#中调用Python代码的两种实现方式

《在C#中调用Python代码的两种实现方式》:本文主要介绍在C#中调用Python代码的两种实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C#调用python代码的方式1. 使用 Python.NET2. 使用外部进程调用 Python 脚本总结C#调

springboot报错Invalid bound statement (not found)的解决

《springboot报错Invalidboundstatement(notfound)的解决》本文主要介绍了springboot报错Invalidboundstatement(not... 目录一. 问题描述二.解决问题三. 添加配置项 四.其他的解决方案4.1 Mapper 接口与 XML 文件不匹配

java常见报错及解决方案总结

《java常见报错及解决方案总结》:本文主要介绍Java编程中常见错误类型及示例,包括语法错误、空指针异常、数组下标越界、类型转换异常、文件未找到异常、除以零异常、非法线程操作异常、方法未定义异常... 目录1. 语法错误 (Syntax Errors)示例 1:解决方案:2. 空指针异常 (NullPoi

SpringBoot项目启动报错"找不到或无法加载主类"的解决方法

《SpringBoot项目启动报错找不到或无法加载主类的解决方法》在使用IntelliJIDEA开发基于SpringBoot框架的Java程序时,可能会出现找不到或无法加载主类com.example.... 目录一、问题描述二、排查过程三、解决方案一、问题描述在使用 IntelliJ IDEA 开发基于

SpringCloud之LoadBalancer负载均衡服务调用过程

《SpringCloud之LoadBalancer负载均衡服务调用过程》:本文主要介绍SpringCloud之LoadBalancer负载均衡服务调用过程,具有很好的参考价值,希望对大家有所帮助,... 目录前言一、LoadBalancer是什么?二、使用步骤1、启动consul2、客户端加入依赖3、以服务

Vue 调用摄像头扫描条码功能实现代码

《Vue调用摄像头扫描条码功能实现代码》本文介绍了如何使用Vue.js和jsQR库来实现调用摄像头并扫描条码的功能,通过安装依赖、获取摄像头视频流、解析条码等步骤,实现了从开始扫描到停止扫描的完整流... 目录实现步骤:代码实现1. 安装依赖2. vue 页面代码功能说明注意事项以下是一个基于 Vue.js