使用Qt到DBus设置系统时间

问题描述 投票:0回答:2

我尝试使用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提供的源代码和构建脚本。

qt dbus freedesktop.org
2个回答
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激活服务”。因此,当有人试图访问名称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
  2. 使用ntp服务时,将执行错误命令:Automatic time synchronization is enabled。所以(如建议的here)必须禁用同步: timedatectl set-ntp 0
  3. 正如@Velcan提到的,timedated服务处于非活动状态: 当有人试图访问名称org.freedesktop.timedate1时,服务启动 在我的环境(KUbuntu 15.10 x86_64)中,服务在最后一次呼叫后30秒处于活动状态。
  4. 根据Qt documentation: bool QDBusAbstractInterface :: isValid()const 如果这是对远程对象的有效引用,则返回true。如果在创建此接口期间出现错误(例如,如果远程应用程序不存在),则返回false。 注意:处理远程对象时,在创建QDBusInterface时并不总是可以确定它是否存在。
  5. 即使QDBusAbstractInterface::isValid()返回falsecall函数也会成功执行。
  6. 最后,正确的代码非常简短: QDBusInterface dbInterface ( "org.freedesktop.timedate1" , "/org/freedesktop/timedate1" , "org.freedesktop.timedate1" , QDBusConnection::systemBus () ); qDebug () << dbInterface.call ("SetTime", 120000000ll, true, false); 此命令将时间设置为提前两分钟。 感谢@Velkan帮助解决问题并提供有用的信息!
© www.soinside.com 2019 - 2024. All rights reserved.