通过 DBus 使用 Qt 设置系统时间
Set system time using Qt through DBus
我尝试通过以下方式使用 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.
获取源代码和构建脚本
简而言之: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 activation of a service'。因此,当有人试图访问名称 org.freedesktop.timedate1
.
时,该服务将启动
但显然需要时间才能开始。我不知道应该如何干净地完成它,但是您可以创建一个重试循环来创建 QDBusInterface
。您会看到 sudo systemctl status systemd-timedated
变为活动状态并且 Qt 检索到有效接口。
我尝试过的对象名称和路径:
QDBusInterface dbInterface (
"org.freedesktop.timedate1"
, "/org/freedesktop/timedate1"
, "org.freedesktop.timedate1"
, dbConnection);
有几个问题。
使用了错误的 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 所述,定时服务处于非活动状态:
the service is started when someone tries to access the name
org.freedesktop.timedate1
在我的环境 (KUbuntu 15.10 x86_64
) 中,服务在上次调用 30 秒后处于活动状态。
-
bool QDBusAbstractInterface::isValid() const
Returns true if this is a
valid reference to a remote object. It returns false if there was an
error during the creation of this interface (for instance, if the
remote application does not exist).
Note: when dealing with remote objects, it is not always possible to
determine if it exists when creating a QDBusInterface.
即使 QDBusAbstractInterface::isValid()
returns false
call
函数执行成功。
所以最后,正确的代码非常简短:
QDBusInterface dbInterface (
"org.freedesktop.timedate1"
, "/org/freedesktop/timedate1"
, "org.freedesktop.timedate1"
, QDBusConnection::systemBus () );
qDebug () << dbInterface.call ("SetTime", 120000000ll, true, false);
此命令将时间设置为提前两分钟。
感谢@Velkan帮忙解答问题并提供有用信息!
我尝试通过以下方式使用 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.
获取源代码和构建脚本简而言之: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 activation of a service'。因此,当有人试图访问名称 org.freedesktop.timedate1
.
但显然需要时间才能开始。我不知道应该如何干净地完成它,但是您可以创建一个重试循环来创建 QDBusInterface
。您会看到 sudo systemctl status systemd-timedated
变为活动状态并且 Qt 检索到有效接口。
我尝试过的对象名称和路径:
QDBusInterface dbInterface (
"org.freedesktop.timedate1"
, "/org/freedesktop/timedate1"
, "org.freedesktop.timedate1"
, dbConnection);
有几个问题。
使用了错误的 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 所述,定时服务处于非活动状态:
the service is started when someone tries to access the name
org.freedesktop.timedate1
在我的环境 (
KUbuntu 15.10 x86_64
) 中,服务在上次调用 30 秒后处于活动状态。-
bool QDBusAbstractInterface::isValid() const
Returns true if this is a valid reference to a remote object. It returns false if there was an error during the creation of this interface (for instance, if the remote application does not exist).
Note: when dealing with remote objects, it is not always possible to determine if it exists when creating a QDBusInterface.
即使
QDBusAbstractInterface::isValid()
returnsfalse
call
函数执行成功。所以最后,正确的代码非常简短:
QDBusInterface dbInterface ( "org.freedesktop.timedate1" , "/org/freedesktop/timedate1" , "org.freedesktop.timedate1" , QDBusConnection::systemBus () ); qDebug () << dbInterface.call ("SetTime", 120000000ll, true, false);
此命令将时间设置为提前两分钟。
感谢@Velkan帮忙解答问题并提供有用信息!