我尝试使用Qt through DBus以下列方式设置系统时间:
#include <QDBusConnection>
#include <QDBusInterface>
#include <QDBusMessage>
#include <QDebug>
#include <QDateTime>
#include <cstdlib>
int main (int /*argc*/, char ** /*argv*/)
{
QDBusConnection dbConnection = QDBusConnection::systemBus ();
QDBusInterface dbInterface (
"org.freedesktop.timedate1.set-time"
, "/org/freedesktop/timedate1/set-time/Manager"
, "org.freedesktop.timedate1.set-time.Manager"
, dbConnection);
qDebug () << "DBus interface validation: " << dbInterface.isValid ();
if (dbInterface.isValid () ) {
QDBusMessage dbMessage = dbInterface.call ("SetTime", QDateTime::currentDateTime ().toMSecsSinceEpoch () * 1000, false, false);
qDebug () << "DBus message: " << dbMessage;
}
return EXIT_SUCCESS;
}
但我得到了:DBus interface validation: false
。
如果我在控制台打电话:
$ gdbus introspect \
--system \
--dest org.freedesktop.timedate1 \
--object-path /org/freedesktop/timedate1
我得到了一些相关的输出(所以它看起来没有环境问题):
node /org/freedesktop/timedate1 {
interface org.freedesktop.DBus.Peer {
...
};
interface org.freedesktop.DBus.Introspectable {
...
};
interface org.freedesktop.DBus.Properties {
methods:
...
signals:
...
properties:
};
interface org.freedesktop.timedate1 {
methods:
SetTime(in x arg_0,
in b arg_1,
in b arg_2);
...
signals:
properties:
...
};
};
GitLab提供的源代码和构建脚本。
答案 0 :(得分:1)
简而言之:QDBusInterface
创建的重试循环可以完成工作。
我探索了一下。该dbus对象由systemd-timedated
服务提供。要了解其状态:
sudo systemctl status systemd-timedated
服务的配置位于/lib/systemd/system/systemd-timedated.service
:
[Unit]
Description=Time & Date Service
Documentation=man:systemd-timedated.service(8) man:localtime(5)
Documentation=http://www.freedesktop.org/wiki/Software/systemd/timedated
[Service]
ExecStart=/lib/systemd/systemd-timedated
BusName=org.freedesktop.timedate1
CapabilityBoundingSet=CAP_SYS_TIME
WatchdogSec=1min
PrivateTmp=yes
ProtectSystem=yes
ProtectHome=yes
BusName
设置负责所谓的服务D-Bus激活&#39;。因此,当有人试图访问名称org.freedesktop.timedate1
时,服务就会启动。
但显然需要时间才能开始。我不知道它应该如何干净利落地完成,但你可以创建一个创建QDBusInterface
的重试循环。您将看到sudo systemctl status systemd-timedated
变为活动状态,Qt将检索有效的接口。
我尝试过的对象名称和路径:
QDBusInterface dbInterface (
"org.freedesktop.timedate1"
, "/org/freedesktop/timedate1"
, "org.freedesktop.timedate1"
, dbConnection);
答案 1 :(得分:1)
有几个问题。
使用了错误的D-Bus命令。在尝试编写Qt程序之前,我必须使用控制台调试命令。所以正确的命令是:
dbus-send \
--system \
--print-reply \
--type=method_call \
--dest='org.freedesktop.timedate1' \
'/org/freedesktop/timedate1' \
org.freedesktop.timedate1.SetTime \
int64:120000000 \
boolean:true \
boolean:false
使用ntp服务时,将执行错误:Automatic time synchronization is enabled
。因此(必须禁用同步here)同步:
timedatectl set-ntp 0
正如@Velcan提到的,时间安排服务处于非活动状态:
当有人试图访问该名称时,服务就会启动
org.freedesktop.timedate1
在我的环境(KUbuntu 15.10 x86_64
)中,服务在最后一次通话后30秒处于活动状态。
bool QDBusAbstractInterface :: isValid()const
如果是a,则返回true 对远程对象的有效引用。如果有,则返回false 创建此接口时出错(例如,如果是 远程应用程序不存在。)
注意:处理远程对象时,并不总是 确定在创建QDBusInterface时是否存在。
即使QDBusAbstractInterface::isValid()
返回false
,call
功能也会成功执行。
最后,正确的代码非常简短:
QDBusInterface dbInterface (
"org.freedesktop.timedate1"
, "/org/freedesktop/timedate1"
, "org.freedesktop.timedate1"
, QDBusConnection::systemBus () );
qDebug () << dbInterface.call ("SetTime", 120000000ll, true, false);
此命令将时间设置为提前两分钟。
感谢@Velkan帮助解决问题并提供有用的信息!