Задайте системно време с помощта на 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