Введение
Для встраиваемого устройства (информационная панель, панель управления умным домом, продолжающая тему статей 254/308/320) Qt-приложение должно запускаться автоматически при включении питания, занимать весь экран, и не позволять пользователю случайно выйти в обычную рабочую среду Linux. В статье разберём настройку такого kiosk-режима через systemd-сервис и параметры EGLFS из статьи 346.
Концепция
Kiosk-режим достигается комбинацией нескольких настроек: автозапуск приложения через systemd-сервис, привязанный к старту графической сессии (или вовсе без неё, в случае EGLFS), полноэкранный режим самого приложения без оконных элементов управления (заголовок окна, кнопка закрытия), и отключение нежелательных способов выхода из приложения (комбинации клавиш переключения окон, виртуальные консоли). Подход без графической оконной среды вовсе (через прямой EGLFS-доступ к GPU, статья 346) даёт наиболее «чистый» kiosk — приложение буквально единственная программа, способная рисовать что-либо на экране.
Пример кода: Автозапуск Qt-приложения как
# /etc/systemd/system/kiosk-app.service — systemd-сервис для автозапуска приложения
[Unit]
Description=Kiosk Qt Application
After=multi-user.target
[Service]
Type=simple
User=pi
Environment=QT_QPA_PLATFORM=eglfs
Environment=QT_QPA_EGLFS_INTEGRATION=eglfs_kms
ExecStart=/home/pi/MyKioskApp/MyKioskApp
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
# Активация сервиса — запуск автоматически при каждой загрузке системы
sudo systemctl enable kiosk-app.service
sudo systemctl start kiosk-app.service
# Проверка состояния и логов сервиса
sudo systemctl status kiosk-app.service
journalctl -u kiosk-app.service -f
# Дополнительно: отключение текстовых консолей (Ctrl+Alt+F1...F6),
# не дающих пользователю случайно переключиться на текстовый терминал
sudo systemctl mask getty@tty1.service getty@tty2.service
// main.cpp — программные меры для предотвращения случайного выхода из kiosk-приложения
#include <QGuiApplication>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
// Перехват и игнорирование стандартных сочетаний клавиш выхода/сворачивания —
// конкретная реализация зависит от используемого виджета/QML-сцены,
// здесь — концептуальный пример через фильтр событий приложения
app.installEventFilter(new KioskKeyFilter());
QQuickView view;
view.setSource(QUrl("qrc:/main.qml"));
view.showFullScreen();
view.setFlags(view.flags() | Qt::FramelessWindowHint); // без заголовка окна и кнопки закрытия
return app.exec();
}
Пояснения к коду
Restart=always/RestartSec=3 в конфигурации systemd-сервиса гарантируют, что приложение автоматически перезапустится, если оно неожиданно завершится (краш, необработанное исключение) — критично важная настройка для устройства без постоянного присутствия оператора, способного вручную перезапустить приложение после сбоя. Environment=QT_QPA_PLATFORM=eglfs внутри определения systemd-сервиса задаёт нужные переменные окружения для самого процесса сервиса, не требуя их установки где-либо ещё (например, в .bashrc пользователя, который для systemd-сервиса, запускаемого не из интерактивной сессии, вообще не был бы прочитан). systemctl mask getty@tty1.service — мера, предотвращающая доступ к текстовым консолям, дополняющая программные ограничения внутри самого приложения для более полного, многоуровневого замыкания kiosk-режима.
Подводные камни
- Отсутствие
Restart=always(или аналогичной политики перезапуска) в конфигурации systemd-сервиса, что означает, что любой крах приложения оставит экран пустым/чёрным до следующей ручной перезагрузки устройства — для удалённо развёрнутого устройства без постоянного физического доступа оператора это превращает любую, даже мелкую, ошибку приложения в полную неработоспособность устройства до физического вмешательства; политика автоматического перезапуска — обязательная мера для production kiosk-развёртывания. - Тестирование kiosk-режима только в обычной X11/desktop сессии разработчика, без проверки реального поведения после полной, «холодной» перезагрузки устройства — некоторые проблемы (порядок запуска сервисов, доступность сети/GPU-драйверов на момент старта приложения) проявляются только при настоящей загрузке системы с нуля, и для надёжного kiosk-развёртывания стоит явно протестировать несколько полных циклов перезагрузки устройства, а не полагаться только на запуск приложения вручную из уже работающей сессии.
- Полное отсутствие способа для разработчика/администратора получить доступ к системе для обновления или диагностики после максимально жёсткого закрытия всех путей выхода из kiosk-режима — стоит сохранить хотя бы один безопасный путь администрирования (SSH-доступ по сети, статья 349, или физический доступ через специальную комбинацию клавиш, известную только администратору), иначе устройство, технически работающее некорректно, будет невозможно диагностировать или обновить без полной переустановки системы.
- Игнорирование журналирования (logging) для kiosk-приложения, работающего без какого-либо видимого для оператора вывода консоли — без явной настройки логирования (аналогично spdlog-циклу, статьи 333-340) диагностика проблем удалённо развёрнутого kiosk-устройства, особенно после редкого, трудно воспроизводимого сбоя, становится крайне затруднительной;
journalctl -u kiosk-app.service— минимально необходимый, но не единственно достаточный источник диагностической информации, и приложение само должно вести подробные логи происходящих в нём событий.