Установите системное время с помощью Qt через DBus

Я пытаюсь установить системное время с помощью Qt через 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.


person Gluttton    schedule 13.06.2016    source источник
comment
Похоже, объект должен быть создан. Когда я смотрю с d-feet - его там нет. Затем я запускаю $ gdbus introspect --system --dest org.freedesktop.timedate1 --object-path /org/freedesktop/timedate1 из терминала - появляется timedate1 (и приложение Qt затем сообщает об этом как о действительном).   -  person Velkan    schedule 13.06.2016
comment
@Velkan, Looks like the object needs to be instantiated. Я не знаком с D-Bus. Можете ли вы объяснить, что именно я должен делать?   -  person Gluttton    schedule 13.06.2016


Ответы (2)


Есть несколько проблем.

  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. Поэтому (как предлагается здесь) синхронизация должна быть отключена:

    timedatectl set-ntp 0
    
  3. #P4# <блочная цитата> #P5# #P6#
  4. #P7#
    #P8# #P9# #P10#
  5. Даже если QDBusAbstractInterface::isValid() возвращает false, функция call выполняется с успешным результатом.

  6. Итак, наконец, правильный код очень короткий и простой:

    QDBusInterface dbInterface (
        "org.freedesktop.timedate1"
      , "/org/freedesktop/timedate1"
      , "org.freedesktop.timedate1"
      , QDBusConnection::systemBus () );
    qDebug () << dbInterface.call ("SetTime", 120000000ll, true, false);  
    

    Эта команда устанавливает время на две минуты вперед.

    Спасибо @Velkan за помощь в решении вопроса и предоставление полезной информации!

person Gluttton    schedule 14.06.2016

Вкратце: цикл повтора при создании 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);
person Velkan    schedule 14.06.2016
comment
Спасибо за ваш ответ, который очень полезен для меня! Но, на мой взгляд, предложенное решение недостаточно хорошо. - person Gluttton; 14.06.2016