LCOV - code coverage report
Current view: top level - main-lib - main.cpp (source / functions) Coverage Total Hit
Test: QtApplicationManager Lines: 73.7 % 668 492
Test Date: 2025-05-03 10:54:12 Functions: 80.4 % 46 37
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 40.9 % 1090 446

             Branch data     Line data    Source code
       1                 :             : // Copyright (C) 2021 The Qt Company Ltd.
       2                 :             : // Copyright (C) 2019 Luxoft Sweden AB
       3                 :             : // Copyright (C) 2018 Pelagicore AG
       4                 :             : // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
       5                 :             : 
       6                 :             : #include <memory>
       7                 :             : #include <cstdlib>
       8                 :             : #include <qglobal.h>
       9                 :             : 
      10                 :             : #include "qtappman_common-config_p.h"
      11                 :             : 
      12                 :             : #if defined(QT_DBUS_LIB) && QT_CONFIG(am_external_dbus_interfaces)
      13                 :             : #  include <QDBusConnection>
      14                 :             : #  include <QDBusAbstractAdaptor>
      15                 :             : #  include <QDBusServer>
      16                 :             : #  include "dbusdaemon.h"
      17                 :             : #  include "dbuspolicy.h"
      18                 :             : #  include "dbuscontextadaptor.h"
      19                 :             : #  include "applicationmanager_adaptor.h"
      20                 :             : #  include "packagemanager_adaptor.h"
      21                 :             : #  include "windowmanager_adaptor.h"
      22                 :             : #  include "notifications_adaptor.h"
      23                 :             : #endif
      24                 :             : 
      25                 :             : #include <QFile>
      26                 :             : #include <QDir>
      27                 :             : #include <QStringList>
      28                 :             : #include <QVariant>
      29                 :             : #include <QFileInfo>
      30                 :             : #include <QQmlContext>
      31                 :             : #include <QQmlComponent>
      32                 :             : #include <QQmlApplicationEngine>
      33                 :             : #include <QTimer>
      34                 :             : #include <QUrl>
      35                 :             : #include <QLibrary>
      36                 :             : #include <QFunctionPointer>
      37                 :             : #include <QProcess>
      38                 :             : #include <QQmlDebuggingEnabler>
      39                 :             : #include <QNetworkInterface>
      40                 :             : #include <private/qabstractanimation_p.h>
      41                 :             : #include <QGuiApplication>
      42                 :             : #include <QQuickView>
      43                 :             : #include <QQuickItem>
      44                 :             : #include <QInputDevice>
      45                 :             : #include <QLocalServer>
      46                 :             : #include <QLibraryInfo>
      47                 :             : #include <QStandardPaths>
      48                 :             : #include <QLockFile>
      49                 :             : #if defined(Q_OS_LINUX)
      50                 :             : #  include <sys/file.h>
      51                 :             : #endif
      52                 :             : 
      53                 :             : #include "global.h"
      54                 :             : #include "logging.h"
      55                 :             : #include "main.h"
      56                 :             : #include "configuration.h"
      57                 :             : #include "applicationmanager.h"
      58                 :             : #include "package.h"
      59                 :             : #include "packagemanager.h"
      60                 :             : #include "packagedatabase.h"
      61                 :             : #include "installationreport.h"
      62                 :             : #include "yamlpackagescanner.h"
      63                 :             : #include "sudo.h"
      64                 :             : #if QT_CONFIG(am_installer)
      65                 :             : #  include "packageutilities.h"
      66                 :             : #endif
      67                 :             : #include "runtimefactory.h"
      68                 :             : #include "containerfactory.h"
      69                 :             : #include "globalruntimeconfiguration.h"
      70                 :             : #include "quicklauncher.h"
      71                 :             : #if QT_CONFIG(am_multi_process)
      72                 :             : #  include "processcontainer.h"
      73                 :             : #  include "nativeruntime.h"
      74                 :             : #endif
      75                 :             : #include "plugincontainer.h"
      76                 :             : #include "notification.h"
      77                 :             : #include "notificationmanager.h"
      78                 :             : #include "qmlinprocruntime.h"
      79                 :             : #include "qml-utilities.h"
      80                 :             : #include "dbus-utilities.h"
      81                 :             : #include "intentserver.h"
      82                 :             : #include "intentaminterface.h"
      83                 :             : 
      84                 :             : #include "windowmanager.h"
      85                 :             : #include "applicationmanagerwindow.h"
      86                 :             : #include "frametimer.h"
      87                 :             : #include "gpustatus.h"
      88                 :             : 
      89                 :             : #include "configuration.h"
      90                 :             : #include "utilities.h"
      91                 :             : #include "exception.h"
      92                 :             : #include "crashhandler.h"
      93                 :             : #include "qmllogger.h"
      94                 :             : #include "startuptimer.h"
      95                 :             : #include "unixsignalhandler.h"
      96                 :             : 
      97                 :             : // monitor-lib
      98                 :             : #include "cpustatus.h"
      99                 :             : #include "iostatus.h"
     100                 :             : #include "memorystatus.h"
     101                 :             : #include "monitormodel.h"
     102                 :             : #include "processstatus.h"
     103                 :             : 
     104                 :             : #include "../plugin-interfaces/startupinterface.h"
     105                 :             : 
     106                 :             : using namespace Qt::StringLiterals;
     107                 :             : using namespace std::chrono_literals;
     108                 :             : 
     109                 :             : 
     110                 :             : AM_QML_REGISTER_TYPES(QtApplicationManager_SystemUI)
     111                 :             : AM_QML_REGISTER_TYPES(QtApplicationManager)
     112                 :             : AM_QML_REGISTER_TYPES(QtApplicationManager_Application)
     113                 :             : 
     114                 :             : QT_BEGIN_NAMESPACE_AM
     115                 :             : 
     116                 :             : static bool unexpectedShutdown = true;
     117                 :             : 
     118                 :             : // We need to do some things BEFORE the Q*Application constructor runs, so we're using this
     119                 :             : // old trick to do this hooking transparently for the user of the class.
     120                 :          58 : int &Main::preConstructor(int &argc, char **argv, InitFlags initFlags)
     121                 :             : {
     122         [ +  + ]:          58 :     if (initFlags & InitFlag::InitializeLogging) {
     123                 :          41 :         Logging::initialize(argc, argv);
     124                 :          41 :         StartupTimer::instance()->checkpoint("after logging initialization");
     125                 :             :     }
     126         [ +  + ]:          58 :     if (initFlags & InitFlag::ForkSudoServer) {
     127                 :          41 :         Sudo::forkServer(Sudo::DropPrivilegesPermanently);
     128                 :          41 :         StartupTimer::instance()->checkpoint("after sudo server fork");
     129                 :             :     }
     130                 :          58 :     return argc;
     131                 :             : }
     132                 :             : 
     133                 :          58 : Main::Main(int &argc, char **argv, InitFlags initFlags)
     134                 :             :     : MainBase(SharedMain::preConstructor(Main::preConstructor(argc, argv, initFlags)), argv)
     135   [ +  -  +  - ]:          58 :     , SharedMain()
     136                 :             : {
     137                 :         116 :     m_isRunningOnEmbedded =
     138                 :             : #if defined(Q_OS_LINUX)
     139                 :          58 :             !qEnvironmentVariableIsSet("XDG_CURRENT_DESKTOP");
     140                 :             : #else
     141                 :             :             false;
     142                 :             : #endif
     143                 :             : 
     144                 :          58 :     static bool once = false;
     145         [ +  + ]:          58 :     if (!once) {
     146                 :          43 :         once = true;
     147                 :             : 
     148   [ +  -  +  - ]:          43 :         UnixSignalHandler::instance()->install(UnixSignalHandler::ForwardedToEventLoopHandler,
     149                 :             :                                                { SIGINT, SIGTERM },
     150                 :           0 :                                                [](int sig) {
     151                 :           0 :             UnixSignalHandler::instance()->resetToDefault(sig);
     152         [ #  # ]:           0 :             static_cast<Main *>(QCoreApplication::instance())->shutDown((sig == SIGINT) ? "Ctrl+C" : "SIGTERM");
     153                 :           0 :         });
     154                 :             : 
     155                 :          43 :         atexit([]() {
     156         [ -  + ]:          43 :             if (unexpectedShutdown)
     157                 :           0 :                 fputs("ERROR: Some code outside the Qt ApplicationManager called exit()\n", stderr);
     158                 :          43 :             unexpectedShutdown = true;
     159                 :          43 :         });
     160                 :             :     }
     161   [ +  -  +  - ]:          58 :     StartupTimer::instance()->checkpoint("after application constructor");
     162                 :          58 : }
     163                 :             : 
     164                 :         116 : Main::~Main()
     165                 :             : {
     166         [ +  + ]:          58 :     delete m_engine;
     167                 :             : 
     168         [ +  + ]:          58 :     delete m_intentServer;
     169         [ +  + ]:          58 :     delete m_notificationManager;
     170         [ +  + ]:          58 :     delete m_windowManager;
     171         [ +  + ]:          58 :     delete m_view;
     172         [ +  + ]:          58 :     delete m_applicationManager;
     173         [ +  + ]:          58 :     delete m_packageManager;
     174         [ +  + ]:          58 :     delete m_quickLauncher;
     175                 :             : 
     176         [ +  - ]:          58 :     delete RuntimeFactory::instance();
     177         [ +  - ]:          58 :     delete ContainerFactory::instance();
     178         [ +  - ]:          58 :     delete StartupTimer::instance();
     179                 :             : 
     180                 :             : #if defined(QT_DBUS_LIB) && QT_CONFIG(am_external_dbus_interfaces)
     181         [ +  + ]:          58 :     delete DBusPolicy::instance();
     182                 :             : #endif
     183                 :         116 : }
     184                 :             : 
     185                 :             : /*! \internal
     186                 :             :     The caller has to make sure that cfg will be available even after this function returns:
     187                 :             :     we will access the cfg object from delayed init functions via lambdas!
     188                 :             : */
     189                 :          58 : void Main::setup(const Configuration *cfg) noexcept(false)
     190                 :             : {
     191                 :          58 :     StartupTimer::instance()->checkpoint("after configuration parsing");
     192                 :             : 
     193                 :          58 :     CrashHandler::setCrashActionConfiguration(cfg->yaml.crashAction.printBacktrace,
     194                 :          58 :                                               cfg->yaml.crashAction.printQmlStack,
     195                 :          58 :                                               cfg->yaml.crashAction.waitForGdbAttach.count(),
     196                 :          58 :                                               cfg->yaml.crashAction.dumpCore,
     197                 :          58 :                                               cfg->yaml.crashAction.stackFramesToIgnore.onCrash,
     198                 :          58 :                                               cfg->yaml.crashAction.stackFramesToIgnore.onException);
     199                 :          58 :     setupQmlDebugging(cfg->qmlDebugging());
     200         [ +  - ]:          58 :     if (Logging::isDltAvailable()) {
     201   [ +  -  -  + ]:          58 :         if (!cfg->yaml.logging.dlt.id.isEmpty() || !cfg->yaml.logging.dlt.description.isEmpty())
     202   [ #  #  #  # ]:           0 :             Logging::setSystemUiDltId(cfg->yaml.logging.dlt.id.toLocal8Bit(),
     203                 :           0 :                                       cfg->yaml.logging.dlt.description.toLocal8Bit());
     204                 :          58 :         Logging::setDltLongMessageBehavior(cfg->yaml.logging.dlt.longMessageBehavior);
     205                 :          58 :         Logging::registerUnregisteredDltContexts();
     206                 :             :     }
     207                 :          58 :     setupLogging(cfg->verbose(), cfg->yaml.logging.rules, cfg->yaml.logging.messagePattern,
     208                 :          58 :                  cfg->yaml.logging.useAMConsoleLogger);
     209                 :             : 
     210         [ +  + ]:          58 :     if (!cfg->isWatchdogDisabled())
     211                 :          17 :         setupWatchdog(cfg->yaml.watchdog);
     212                 :             : 
     213                 :          58 :     registerResources(cfg->yaml.ui.resources);
     214                 :             : 
     215                 :          58 :     setupOpenGL(cfg->yaml.ui.opengl);
     216                 :          58 :     setupIconTheme(cfg->yaml.ui.iconThemeSearchPaths, cfg->yaml.ui.iconThemeName);
     217                 :             : 
     218                 :          58 :     loadStartupPlugins(cfg->yaml.plugins.startup);
     219                 :          58 :     parseSystemProperties(cfg->yaml.systemProperties);
     220                 :             : 
     221                 :          58 :     setMainQmlFile(cfg->yaml.ui.mainQml);
     222                 :          52 :     setupSingleOrMultiProcess(cfg);
     223                 :          52 :     setupRuntimesAndContainers(cfg);
     224                 :             : 
     225                 :          52 :     loadPackageDatabase(cfg);
     226                 :             : 
     227                 :          52 :     setupSingletons(cfg);
     228                 :          52 :     setupQuickLauncher(cfg);
     229                 :          52 :     setupIntents(cfg);
     230                 :             : 
     231                 :          52 :     registerPackages();
     232                 :             : 
     233         [ +  + ]:          52 :     if (cfg->yaml.applications.installationDir.isEmpty())
     234                 :          31 :         StartupTimer::instance()->checkpoint("skipping installer");
     235                 :             :     else
     236                 :          21 :         setupInstaller(cfg);
     237                 :             : 
     238   [ +  -  +  - ]:         104 :     setLibraryPaths(libraryPaths() + cfg->yaml.ui.pluginPaths);
     239                 :          52 :     setupQmlEngine(cfg->yaml.ui.importPaths, cfg->yaml.ui.style);
     240                 :             : 
     241                 :             :     // For development only: set an icon, so you know which window is the AM
     242         [ -  + ]:          52 :     if (!isRunningOnEmbedded() && !cfg->yaml.ui.windowIcon.isEmpty())
     243         [ #  # ]:           0 :         QGuiApplication::setWindowIcon(QIcon(cfg->yaml.ui.windowIcon));
     244                 :             : 
     245                 :          52 :     setupWindowManager(cfg);
     246                 :          52 :     setupDBus(cfg);
     247                 :             : 
     248                 :          52 :     createInstanceInfoFile(cfg->yaml.instanceId);
     249                 :             : 
     250                 :          52 :     m_showFullscreen = cfg->yaml.ui.fullscreen;
     251                 :          52 : }
     252                 :             : 
     253                 :           0 : bool Main::isSingleProcessMode() const
     254                 :             : {
     255                 :           0 :     return m_isSingleProcessMode;
     256                 :             : }
     257                 :             : 
     258                 :          73 : bool Main::isRunningOnEmbedded() const
     259                 :             : {
     260         [ +  - ]:          52 :     return m_isRunningOnEmbedded;
     261                 :             : }
     262                 :             : 
     263                 :          52 : void Main::shutDown(const char *shutdownReason, int exitCode)
     264                 :             : {
     265                 :          52 :     enum {
     266                 :             :         ApplicationManagerDown = 0x01,
     267                 :             :         QuickLauncherDown = 0x02,
     268                 :             :         WindowManagerDown = 0x04
     269                 :             :     };
     270                 :             : 
     271                 :          52 :     static int down = 0;
     272   [ +  +  +  - ]:          52 :     static int code = exitCode;
     273   [ +  +  +  - ]:          52 :     static const char *reason = shutdownReason;
     274                 :             : 
     275                 :         104 :     static auto finalShutdown = []() {
     276                 :          52 :         unexpectedShutdown = false;
     277         [ +  + ]:          52 :         if (reason)
     278   [ +  -  +  -  :         123 :             qCInfo(LogSystem) << "Shutting down due to" << reason;
                   +  + ]
     279                 :          52 :         QCoreApplication::exit(code);
     280                 :          52 :     };
     281                 :             : 
     282                 :         167 :     static auto checkShutDownFinished = [](int nextDown) {
     283                 :         115 :         down |= nextDown;
     284         [ +  + ]:         115 :         if (down == (ApplicationManagerDown | QuickLauncherDown | WindowManagerDown)) {
     285                 :          52 :             down = 0;
     286                 :          52 :             finalShutdown();
     287                 :             :         }
     288                 :         115 :     };
     289                 :             : 
     290         [ +  - ]:          52 :     if (m_applicationManager) {
     291                 :          52 :         connect(&m_applicationManager->internalSignals, &ApplicationManagerInternalSignals::shutDownFinished,
     292                 :          57 :                 this, []() { checkShutDownFinished(ApplicationManagerDown); });
     293                 :          52 :         m_applicationManager->shutDown();
     294                 :             :     }
     295         [ +  + ]:          52 :     if (m_quickLauncher) {
     296                 :           6 :         connect(m_quickLauncher, &QuickLauncher::shutDownFinished,
     297                 :           6 :                 this, []() { checkShutDownFinished(QuickLauncherDown); });
     298                 :           6 :         m_quickLauncher->shutDown();
     299                 :             :     } else {
     300                 :          46 :         down |= QuickLauncherDown;
     301                 :             :     }
     302         [ +  - ]:          52 :     if (m_windowManager) {
     303                 :          52 :         connect(&m_windowManager->internalSignals, &WindowManagerInternalSignals::shutDownFinished,
     304                 :          52 :                 this, []() { checkShutDownFinished(WindowManagerDown); });
     305                 :          52 :         m_windowManager->shutDown();
     306                 :             :     }
     307                 :             : 
     308                 :          52 :     QTimer::singleShot(5000, this, [] {
     309                 :           0 :         QStringList resources;
     310         [ #  # ]:           0 :         if (!(down & ApplicationManagerDown))
     311         [ #  # ]:           0 :             resources << u"runtimes"_s;
     312         [ #  # ]:           0 :         if (!(down & QuickLauncherDown))
     313         [ #  # ]:           0 :             resources << u"quick-launchers"_s;
     314         [ #  # ]:           0 :         if (!(down & WindowManagerDown))
     315         [ #  # ]:           0 :             resources << u"windows"_s;
     316   [ #  #  #  #  :           0 :         qCCritical(LogSystem, "There are still resources in use (%s). Check your System UI implementation. "
          #  #  #  #  #  
                      # ]
     317                 :             :                               "Exiting regardless.", resources.join(u", "_s).toLocal8Bit().constData());
     318         [ #  # ]:           0 :         finalShutdown();
     319                 :           0 :     });
     320                 :          52 : }
     321                 :             : 
     322                 :          41 : QQmlApplicationEngine *Main::qmlEngine() const
     323                 :             : {
     324                 :          41 :     return m_engine;
     325                 :             : }
     326                 :             : 
     327                 :          11 : int Main::exec()
     328                 :             : {
     329                 :          11 :     return MainBase::exec();
     330                 :             : }
     331                 :             : 
     332                 :          58 : void Main::registerResources(const QStringList &resources) const
     333                 :             : {
     334         [ +  + ]:          58 :     if (resources.isEmpty())
     335                 :             :         return;
     336         [ +  + ]:           6 :     for (const QString &resource: resources) {
     337                 :           4 :         try {
     338         [ +  - ]:           4 :             loadResource(resource);
     339         [ -  - ]:           0 :         } catch (const Exception &e) {
     340   [ -  -  -  -  :           0 :             qCWarning(LogSystem).noquote() << e.errorString();
             -  -  -  - ]
     341                 :           0 :         }
     342                 :             :     }
     343                 :           2 :     StartupTimer::instance()->checkpoint("after resource registration");
     344                 :             : }
     345                 :             : 
     346                 :          58 : void Main::loadStartupPlugins(const QStringList &startupPluginPaths) noexcept(false)
     347                 :             : {
     348                 :          58 :     QStringList systemStartupPluginPaths;
     349   [ +  -  +  -  :         174 :     const QDir systemStartupPluginDir(QLibraryInfo::path(QLibraryInfo::PluginsPath) + QDir::separator() + u"appman_startup"_s);
                   +  - ]
     350         [ +  - ]:          58 :     const auto allPluginNames = systemStartupPluginDir.entryList(QDir::Files | QDir::NoDotAndDotDot);
     351         [ -  + ]:          58 :     for (const auto &pluginName : allPluginNames) {
     352         [ #  # ]:           0 :         const QString filePath = systemStartupPluginDir.absoluteFilePath(pluginName);
     353   [ #  #  #  # ]:           0 :         if (!QLibrary::isLibrary(filePath))
     354                 :           0 :             continue;
     355         [ #  # ]:           0 :         systemStartupPluginPaths += filePath;
     356                 :           0 :     }
     357                 :             : 
     358   [ +  -  +  - ]:          58 :     m_startupPlugins = loadPlugins<StartupInterface>("startup", systemStartupPluginPaths + startupPluginPaths);
     359   [ +  -  +  - ]:          58 :     StartupTimer::instance()->checkpoint("after startup-plugin load");
     360                 :          58 : }
     361                 :             : 
     362                 :          58 : void Main::parseSystemProperties(const QVariantMap &rawSystemProperties)
     363                 :             : {
     364                 :          58 :     m_systemProperties.resize(SP_SystemUi + 1);
     365         [ +  + ]:          58 :     QVariantMap rawMap = rawSystemProperties;
     366                 :             : 
     367   [ +  -  +  -  :          58 :     m_systemProperties[SP_ThirdParty] = rawMap.value(u"public"_s).toMap();
                   +  - ]
     368                 :             : 
     369         [ +  - ]:          58 :     m_systemProperties[SP_BuiltIn] = m_systemProperties.at(SP_ThirdParty);
     370   [ +  -  +  - ]:         116 :     const QVariantMap pro = rawMap.value(u"protected"_s).toMap();
     371   [ +  +  +  +  :         138 :     for (auto it = pro.cbegin(); it != pro.cend(); ++it)
                   +  + ]
     372   [ +  -  +  - ]:          10 :         m_systemProperties[SP_BuiltIn].insert(it.key(), it.value());
     373                 :             : 
     374         [ +  - ]:          58 :     m_systemProperties[SP_SystemUi] = m_systemProperties.at(SP_BuiltIn);
     375   [ +  -  +  - ]:         116 :     const QVariantMap pri = rawMap.value(u"private"_s).toMap();
     376   [ +  +  +  +  :         168 :     for (auto it = pri.cbegin(); it != pri.cend(); ++it)
                   +  + ]
     377   [ +  -  +  - ]:          24 :         m_systemProperties[SP_SystemUi].insert(it.key(), it.value());
     378                 :             : 
     379         [ -  + ]:          58 :     for (auto iface : std::as_const(m_startupPlugins))
     380         [ #  # ]:           0 :         iface->initialize(m_systemProperties.at(SP_SystemUi));
     381                 :          58 : }
     382                 :             : 
     383                 :          58 : void Main::setMainQmlFile(const QString &mainQml) noexcept(false)
     384                 :             : {
     385                 :             :     // For some weird reason, QFile cannot cope with "qrc:/" and QUrl cannot cope with ":/",
     386                 :             :     // so we have to translate ourselves between those two "worlds".
     387                 :             : 
     388         [ +  - ]:          58 :     m_mainQml = filePathToUrl(mainQml, QDir::currentPath());
     389                 :          58 :     m_mainQmlLocalFile = urlToLocalFilePath(m_mainQml);
     390                 :             : 
     391   [ +  -  +  + ]:          58 :     if (!QFileInfo(m_mainQmlLocalFile).isFile()) {
     392         [ +  + ]:           8 :         if (mainQml.isEmpty())
     393                 :           1 :             throw Exception("No main QML file specified");
     394                 :             : 
     395                 :             :         // basically accept schemes other than file and qrc:
     396         [ +  + ]:           7 :         if (!m_mainQmlLocalFile.isEmpty())
     397                 :           5 :             throw Exception("Invalid main QML file specified: %1").arg(mainQml);
     398                 :             :     }
     399                 :          52 : }
     400                 :             : 
     401                 :          52 : void Main::setupSingleOrMultiProcess(const Configuration *cfg) noexcept(false)
     402                 :             : {
     403                 :          52 :     m_isSingleProcessMode = cfg->yaml.flags.forceSingleProcess;
     404   [ +  +  -  + ]:          52 :     if (cfg->yaml.flags.forceMultiProcess && m_isSingleProcessMode)
     405                 :           0 :         throw Exception("You cannot enforce multi- and single-process mode at the same time.");
     406                 :             : 
     407                 :          52 :     if (!QT_CONFIG(am_multi_process)) {
     408                 :             :         if (cfg->yaml.flags.forceMultiProcess)
     409                 :             :             throw Exception("This application manager build is not multi-process capable.");
     410                 :             :         m_isSingleProcessMode = true;
     411                 :             :     }
     412                 :          52 : }
     413                 :             : 
     414                 :          52 : void Main::setupRuntimesAndContainers(const Configuration *cfg)
     415                 :             : {
     416                 :          52 :     auto &grc = GlobalRuntimeConfiguration::instance();
     417                 :          52 :     grc.openGLConfiguration = cfg->yaml.ui.opengl;
     418                 :          52 :     grc.watchdogDisabled = cfg->isWatchdogDisabled();
     419                 :          52 :     grc.watchdogConfiguration = cfg->yaml.watchdog;
     420                 :          52 :     grc.iconThemeSearchPaths = cfg->yaml.ui.iconThemeSearchPaths;
     421                 :          52 :     grc.iconThemeName = cfg->yaml.ui.iconThemeName;
     422                 :          52 :     grc.systemPropertiesForBuiltInApps = m_systemProperties.at(SP_BuiltIn);
     423                 :          52 :     grc.systemPropertiesForThirdPartyApps= m_systemProperties.at(SP_ThirdParty);
     424                 :             : 
     425                 :          52 :     QVector<PluginContainerManager *> pluginContainerManagers;
     426                 :             : 
     427         [ +  + ]:          52 :     if (m_isSingleProcessMode) {
     428   [ +  -  +  -  :          34 :         RuntimeFactory::instance()->registerRuntime(new QmlInProcRuntimeManager());
                   +  - ]
     429   [ +  -  +  -  :          34 :         RuntimeFactory::instance()->registerRuntime(new QmlInProcRuntimeManager(u"qml"_s));
             +  -  +  - ]
     430                 :             :     } else {
     431   [ +  -  +  -  :          70 :         RuntimeFactory::instance()->registerRuntime(new QmlInProcRuntimeManager());
                   +  - ]
     432                 :             : #if QT_CONFIG(am_multi_process)
     433   [ +  -  +  -  :          70 :         RuntimeFactory::instance()->registerRuntime(new NativeRuntimeManager());
                   +  - ]
     434   [ +  -  +  -  :          35 :         RuntimeFactory::instance()->registerRuntime(new NativeRuntimeManager(u"qml"_s));
             +  -  +  - ]
     435                 :             : 
     436         [ -  + ]:          35 :         for (const QString &runtimeId : cfg->yaml.runtimes.additionalLaunchers)
     437   [ #  #  #  #  :           0 :             RuntimeFactory::instance()->registerRuntime(new NativeRuntimeManager(runtimeId));
             #  #  #  # ]
     438                 :             : 
     439   [ +  -  +  -  :          70 :         ContainerFactory::instance()->registerContainer(new ProcessContainerManager());
                   +  - ]
     440                 :             : #else
     441                 :             :         if (!cfg->yaml.runtimes.additionalLaunchers.isEmpty())
     442                 :             :             qCWarning(LogSystem) << "Addtional runtime launchers are ignored in single-process mode";
     443                 :             : #endif
     444                 :          35 :         QStringList systemContainerPluginPaths;
     445   [ +  -  +  -  :         105 :         const QDir systemContainerPluginDir(QLibraryInfo::path(QLibraryInfo::PluginsPath) + QDir::separator() + u"appman_container"_s);
                   +  - ]
     446         [ +  - ]:          35 :         const auto allPluginNames = systemContainerPluginDir.entryList(QDir::Files | QDir::NoDotAndDotDot);
     447         [ +  + ]:         105 :         for (const auto &pluginName : allPluginNames) {
     448         [ +  - ]:          70 :             const QString filePath = systemContainerPluginDir.absoluteFilePath(pluginName);
     449   [ +  -  +  + ]:          70 :             if (!QLibrary::isLibrary(filePath))
     450                 :          35 :                 continue;
     451         [ +  - ]:          70 :             systemContainerPluginPaths += filePath;
     452                 :          70 :         }
     453                 :             : 
     454                 :          35 :         QSet<QString> containersWithConfiguration(cfg->yaml.containers.configurations.keyBegin(),
     455   [ +  +  +  +  :          37 :                                                   cfg->yaml.containers.configurations.keyEnd());
                   +  - ]
     456                 :             : 
     457   [ +  -  +  - ]:          35 :         auto containerPlugins = loadPlugins<ContainerManagerInterface>("container", systemContainerPluginPaths + cfg->yaml.plugins.container);
     458                 :          35 :         pluginContainerManagers.reserve(containerPlugins.size());
     459         [ +  + ]:          70 :         for (auto iface : std::as_const(containerPlugins)) {
     460   [ +  -  +  + ]:          70 :             if (!containersWithConfiguration.contains(iface->identifier()))
     461                 :          34 :                 continue;
     462   [ +  -  +  - ]:           1 :             auto pcm = new PluginContainerManager(iface);
     463         [ +  - ]:           1 :             pluginContainerManagers << pcm;
     464   [ +  -  +  - ]:           1 :             ContainerFactory::instance()->registerContainer(pcm);
     465                 :             :         }
     466                 :          35 :     }
     467         [ -  + ]:          52 :     for (auto iface : std::as_const(m_startupPlugins))
     468         [ #  # ]:           0 :         iface->afterRuntimeRegistration();
     469                 :             : 
     470   [ +  -  +  - ]:          52 :     ContainerFactory::instance()->setConfiguration(cfg->yaml.containers.configurations);
     471                 :             : 
     472         [ +  + ]:          53 :     for (auto pcm : std::as_const(pluginContainerManagers)) {
     473   [ +  -  -  + ]:           1 :         if (!pcm->initialize()) {
     474   [ #  #  #  #  :           0 :             ContainerFactory::instance()->disableContainer(pcm->identifier());
                   #  # ]
     475   [ #  #  #  #  :           0 :             qCWarning(LogSystem).noquote() << "Disabling container plugin" << pcm->identifier() << "as it failed to initialize";
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     476                 :             :         }
     477                 :             :     }
     478                 :             : 
     479   [ +  -  +  - ]:          52 :     RuntimeFactory::instance()->setConfiguration(cfg->yaml.runtimes.configurations);
     480                 :             : 
     481   [ +  -  +  - ]:          52 :     StartupTimer::instance()->checkpoint("after runtime registration");
     482                 :          52 : }
     483                 :             : 
     484                 :          52 : void Main::loadPackageDatabase(const Configuration *cfg) noexcept(false)
     485                 :             : {
     486         [ +  + ]:          52 :     if (!cfg->singleApp().isEmpty()) {
     487   [ +  -  +  - ]:           2 :         m_packageDatabase = new PackageDatabase(cfg->singleApp());
     488                 :             :     } else {
     489                 :         150 :         m_packageDatabase = new PackageDatabase(cfg->yaml.applications.builtinAppsManifestDir,
     490                 :          50 :                                                 cfg->yaml.applications.installationDir,
     491         [ +  - ]:          50 :                                                 cfg->yaml.applications.installationDirMountPoint);
     492   [ +  -  -  + ]:          50 :         if (!cfg->clearCache() && !cfg->noCache())
     493                 :           0 :             m_packageDatabase->enableLoadFromCache();
     494                 :          50 :         m_packageDatabase->enableSaveToCache();
     495                 :             :     }
     496                 :          52 :     m_packageDatabase->parse();
     497                 :             : 
     498                 :          52 :     const QVector<PackageInfo *> allPackages =
     499         [ +  - ]:         104 :             m_packageDatabase->builtInPackages()
     500                 :         104 :             + m_packageDatabase->installedPackages();
     501                 :             : 
     502         [ +  + ]:         137 :     for (auto package : allPackages) {
     503                 :             :         // check that the runtimes are supported in this instance of the AM
     504         [ +  - ]:          85 :         const auto apps = package->applications();
     505                 :             : 
     506         [ +  + ]:         181 :         for (const auto app : apps) {
     507   [ +  -  +  -  :          96 :             if (!RuntimeFactory::instance()->manager(app->runtimeName()))
             +  -  +  + ]
     508   [ +  -  +  -  :           6 :                 qCWarning(LogSystem) << "Application" << app->id() << "uses an unknown runtime:" << app->runtimeName();
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  + ]
     509                 :             :         }
     510                 :          85 :     }
     511                 :             : 
     512   [ +  -  +  - ]:          52 :     StartupTimer::instance()->checkpoint("after package database loading");
     513                 :          52 : }
     514                 :             : 
     515                 :          52 : void Main::setupIntents(const Configuration *cfg)
     516                 :             : {
     517                 :         104 :     m_intentServer = IntentAMImplementation::createIntentServerAndClientInstance(
     518                 :             :         m_packageManager,
     519                 :          52 :         cfg->yaml.intents.timeouts.disambiguation.count(),
     520                 :          52 :         cfg->yaml.intents.timeouts.startApplication.count(),
     521                 :          52 :         cfg->yaml.intents.timeouts.replyFromApplication.count(),
     522                 :          52 :         cfg->yaml.intents.timeouts.replyFromSystem.count());
     523                 :          52 :     StartupTimer::instance()->checkpoint("after IntentServer instantiation");
     524                 :          52 : }
     525                 :             : 
     526                 :          52 : void Main::setupSingletons(const Configuration *cfg) noexcept(false)
     527                 :             : {
     528                 :          52 :     m_packageManager = PackageManager::createInstance(m_packageDatabase, cfg->yaml.applications.documentDir);
     529                 :          52 :     m_applicationManager = ApplicationManager::createInstance(m_isSingleProcessMode);
     530                 :             : 
     531         [ +  + ]:          52 :     if (cfg->yaml.flags.noSecurity)
     532                 :           7 :         m_applicationManager->setSecurityChecksEnabled(false);
     533         [ +  + ]:          52 :     if (cfg->yaml.flags.developmentMode)
     534                 :           2 :         m_packageManager->setDevelopmentMode(true);
     535                 :             : 
     536                 :          52 :     m_applicationManager->setSystemProperties(m_systemProperties.at(SP_SystemUi));
     537                 :          52 :     m_applicationManager->setContainerSelectionConfiguration(cfg->yaml.containers.selection);
     538                 :             : 
     539                 :          52 :     StartupTimer::instance()->checkpoint("after ApplicationManager instantiation");
     540                 :             : 
     541                 :          52 :     m_notificationManager = NotificationManager::createInstance();
     542                 :          52 :     StartupTimer::instance()->checkpoint("after NotificationManager instantiation");
     543                 :          52 : }
     544                 :             : 
     545                 :          52 : void Main::setupQuickLauncher(const Configuration *cfg)
     546                 :             : {
     547   [ +  +  +  - ]:          52 :     if (!cfg->yaml.quicklaunch.runtimesPerContainer.isEmpty()) {
     548                 :          12 :         m_quickLauncher = QuickLauncher::createInstance(cfg->yaml.quicklaunch.runtimesPerContainer,
     549                 :           6 :                                                         cfg->yaml.quicklaunch.idleLoad,
     550                 :           6 :                                                         cfg->yaml.quicklaunch.failedStartLimit,
     551                 :           6 :                                                         cfg->yaml.quicklaunch.failedStartLimitIntervalSec.count());
     552                 :           6 :         StartupTimer::instance()->checkpoint("after quick-launcher setup");
     553                 :             :     } else {
     554   [ -  -  -  + ]:          92 :         qCDebug(LogSystem) << "Not setting up the quick-launch pool (runtimesPerContainer is 0)";
     555                 :             :     }
     556                 :          52 : }
     557                 :             : 
     558                 :          21 : void Main::setupInstaller(const Configuration *cfg) noexcept(false)
     559                 :             : {
     560                 :             : #if QT_CONFIG(am_installer)
     561                 :             :     // make sure the installation and document dirs are valid
     562                 :          21 :     Q_ASSERT(!cfg->yaml.applications.installationDir.isEmpty());
     563         [ +  - ]:          21 :     const auto instPath = QDir(cfg->yaml.applications.installationDir).canonicalPath();
     564         [ +  + ]:          21 :     const auto docPath = cfg->yaml.applications.documentDir.isEmpty()
     565   [ +  +  +  -  :          21 :                              ? QString { } : QDir(cfg->yaml.applications.documentDir).canonicalPath();
                   +  - ]
     566                 :             : 
     567   [ +  +  +  -  :          21 :     if (!docPath.isEmpty() && (instPath.startsWith(docPath) || docPath.startsWith(instPath)))
          +  -  +  -  -  
                      + ]
     568                 :           0 :         throw Exception("either installationDir or documentDir cannot be a sub-directory of the other");
     569                 :             : 
     570   [ +  -  -  + ]:          21 :     if (Q_UNLIKELY(hardwareId().isEmpty()))
     571                 :           0 :         throw Exception("the installer is enabled, but the device-id is empty");
     572                 :             : 
     573         [ +  - ]:          21 :     if (!isRunningOnEmbedded()) { // this is just for convenience sake during development
     574   [ +  -  +  -  :          21 :         if (Q_UNLIKELY(!cfg->yaml.applications.installationDir.isEmpty() && !QDir::root().mkpath(cfg->yaml.applications.installationDir)))
          +  -  -  +  +  
             -  -  +  -  
                      - ]
     575                 :           0 :             throw Exception("could not create package installation directory: \'%1\'").arg(cfg->yaml.applications.installationDir);
     576   [ +  +  +  -  :          21 :         if (Q_UNLIKELY(!cfg->yaml.applications.documentDir.isEmpty() && !QDir::root().mkpath(cfg->yaml.applications.documentDir)))
          +  -  -  +  +  
             +  -  +  -  
                      - ]
     577                 :           0 :             throw Exception("could not create document directory for packages: \'%1\'").arg(cfg->yaml.applications.documentDir);
     578                 :             :     }
     579                 :             : 
     580   [ +  -  +  - ]:          21 :     StartupTimer::instance()->checkpoint("after installer setup checks");
     581                 :             : 
     582   [ +  +  -  + ]:          21 :     if (cfg->yaml.flags.noSecurity || cfg->yaml.flags.allowUnsignedPackages)
     583         [ +  - ]:           2 :         m_packageManager->setAllowInstallationOfUnsignedPackages(true);
     584                 :             : 
     585         [ +  + ]:          21 :     if (!cfg->yaml.flags.noSecurity) {
     586                 :          19 :         QByteArrayList caCertificateList;
     587                 :          19 :         caCertificateList.reserve(cfg->yaml.installer.caCertificates.size());
     588                 :             : 
     589         [ -  + ]:          19 :         for (const auto &caFile : cfg->yaml.installer.caCertificates) {
     590         [ #  # ]:           0 :             QFile f(caFile);
     591   [ #  #  #  # ]:           0 :             if (Q_UNLIKELY(!f.open(QFile::ReadOnly)))
     592                 :           0 :                 throw Exception(f, "could not open CA-certificate file");
     593         [ #  # ]:           0 :             QByteArray cert = f.readAll();
     594         [ #  # ]:           0 :             if (Q_UNLIKELY(cert.isEmpty()))
     595                 :           0 :                 throw Exception(f, "CA-certificate file is empty");
     596         [ #  # ]:           0 :             caCertificateList << cert;
     597                 :           0 :         }
     598         [ +  - ]:          19 :         m_packageManager->setCACertificates(caCertificateList);
     599                 :          19 :     }
     600                 :             : 
     601         [ +  - ]:          21 :     m_packageManager->enableInstaller();
     602                 :             : 
     603   [ +  -  +  - ]:          21 :     StartupTimer::instance()->checkpoint("after installer setup");
     604                 :             : #else
     605                 :             :     Q_UNUSED(cfg)
     606                 :             : #endif // QT_CONFIG(am_installer)
     607                 :          21 : }
     608                 :             : 
     609                 :          52 : void Main::registerPackages()
     610                 :             : {
     611                 :             :     // the installation dir might not be mounted yet, so we have to watch for the package
     612                 :             :     // DB's signal and then register these packages later in the already running system
     613         [ -  + ]:          52 :     if (!(m_packageDatabase->parsedPackageLocations() & PackageDatabase::Installed)) {
     614                 :           0 :         connect(m_packageDatabase, &PackageDatabase::installedPackagesParsed,
     615                 :           0 :                 m_packageManager, [this]() {
     616                 :             :             // we are not in main() anymore: we can't just throw
     617                 :           0 :             try {
     618         [ #  # ]:           0 :                 m_packageManager->registerPackages();
     619         [ -  - ]:           0 :             } catch (const Exception &e) {
     620   [ -  -  -  -  :           0 :                 qCCritical(LogInstaller) << "Failed to register packages:" << e.what();
          -  -  -  -  -  
                      - ]
     621                 :           0 :                 std::abort(); // there is no qCFatal()
     622                 :           0 :             }
     623                 :           0 :         });
     624                 :           0 :         StartupTimer::instance()->checkpoint("after package registration (delayed)");
     625                 :             :     } else {
     626                 :          52 :         m_packageManager->registerPackages();
     627                 :          52 :         StartupTimer::instance()->checkpoint("after package registration");
     628                 :             :     }
     629                 :          52 : }
     630                 :             : 
     631                 :          52 : void Main::setupQmlEngine(const QStringList &importPaths, const QString &quickControlsStyle)
     632                 :             : {
     633         [ -  + ]:          52 :     if (!quickControlsStyle.isEmpty())
     634         [ #  # ]:           0 :         qputenv("QT_QUICK_CONTROLS_STYLE", quickControlsStyle.toLocal8Bit());
     635                 :             : 
     636                 :          52 :     StartupTimer::instance()->checkpoint("after QML registrations");
     637                 :             : 
     638         [ +  - ]:          52 :     m_engine = new QQmlApplicationEngine(this);
     639                 :          52 :     disconnect(m_engine, &QQmlEngine::quit, qApp, nullptr);
     640                 :          52 :     disconnect(m_engine, &QQmlEngine::exit, qApp, nullptr);
     641                 :          93 :     connect(m_engine, &QQmlEngine::quit, this, [this]() { shutDown("Qt.quit()"); });
     642                 :          52 :     connect(m_engine, &QQmlEngine::exit, this, [this](int retCode) { shutDown("Qt.exit()", retCode); });
     643                 :          52 :     CrashHandler::setQmlEngine(m_engine);
     644         [ +  - ]:          52 :     new QmlLogger(m_engine);
     645                 :          52 :     m_engine->setOutputWarningsToStandardError(false);
     646   [ +  -  +  - ]:         104 :     m_engine->setImportPathList(m_engine->importPathList() + importPaths);
     647                 :             : 
     648                 :          52 :     StartupTimer::instance()->checkpoint("after QML engine instantiation");
     649                 :          52 : }
     650                 :             : 
     651                 :          52 : void Main::setupWindowManager(const Configuration *cfg)
     652                 :             : {
     653                 :          52 :     QUnifiedTimer::instance()->setSlowModeEnabled(cfg->slowAnimations());
     654                 :             : 
     655                 :         155 :     auto waylandSocketName = [cfg]() -> QString {
     656                 :          52 :         QString socketName = cfg->waylandSocketName(); // get the default value
     657         [ +  + ]:          52 :         if (!socketName.isEmpty())
     658                 :           1 :             return socketName;
     659         [ -  + ]:          51 :         if (!cfg->yaml.wayland.socketName.isEmpty())
     660                 :           0 :             return cfg->yaml.wayland.socketName;
     661                 :             : 
     662                 :             : #if defined(Q_OS_LINUX)
     663                 :             :         // modelled after wl_socket_lock() in wayland_server.c
     664   [ +  -  +  - ]:         102 :         const QString xdgDir = qEnvironmentVariable("XDG_RUNTIME_DIR") + u"/"_s;
     665                 :          51 :         const QString pattern = u"qtam-wayland-%1"_s;
     666                 :          51 :         const QString lockSuffix = u".lock"_s;
     667                 :             : 
     668         [ +  - ]:          51 :         for (int i = 0; i < 32; ++i) {
     669         [ +  - ]:          51 :             socketName = pattern.arg(i);
     670   [ +  -  +  - ]:          51 :             QFile lock(xdgDir + socketName + lockSuffix);
     671   [ +  -  +  - ]:          51 :             if (lock.open(QIODevice::ReadWrite)) {
     672   [ +  -  +  - ]:          51 :                 if (::flock(lock.handle(), LOCK_EX | LOCK_NB) == 0) {
     673   [ +  -  +  - ]:          51 :                     QFile socket(xdgDir + socketName);
     674   [ +  -  -  +  :          51 :                     if (!socket.exists() || socket.remove())
             -  -  -  - ]
     675                 :          51 :                         return socketName;
     676                 :          51 :                 }
     677                 :             :             }
     678                 :          51 :         }
     679                 :             : #endif
     680                 :          51 :         return QString();
     681                 :         103 :     };
     682                 :             : 
     683         [ +  - ]:          52 :     m_windowManager = WindowManager::createInstance(m_engine, waylandSocketName());
     684   [ +  +  +  - ]:          97 :     m_windowManager->setAllowUnknownUiClients(cfg->yaml.flags.noSecurity || cfg->yaml.flags.allowUnknownUiClients);
     685                 :          52 :     m_windowManager->setSlowAnimations(cfg->slowAnimations());
     686         [ +  + ]:          52 :     if (!cfg->isWatchdogDisabled()) {
     687                 :          11 :         m_windowManager->setWatchdogTimeouts(cfg->yaml.watchdog.wayland.checkInterval,
     688                 :             :                                              cfg->yaml.watchdog.wayland.warnTimeout,
     689                 :          11 :                                              cfg->yaml.watchdog.wayland.killTimeout);
     690                 :             :     }
     691                 :             : 
     692                 :             : #if defined(QT_WAYLANDCOMPOSITOR_LIB)
     693                 :          52 :     connect(&m_windowManager->internalSignals, &WindowManagerInternalSignals::compositorAboutToBeCreated,
     694                 :          25 :             this, [this, cfg] {
     695                 :             :         // This needs to be delayed until directly before creating the Wayland compositor.
     696                 :             :         // Otherwise we have a "dangling" socket you cannot connect to.
     697                 :             : 
     698         [ -  + ]:          25 :         for (const auto &wes : cfg->yaml.wayland.extraSockets) {
     699                 :           0 :             const QString path = wes.path;
     700                 :             : 
     701         [ #  # ]:           0 :             if (path.isEmpty())
     702                 :           0 :                 continue;
     703                 :             : 
     704                 :           0 :             try {
     705         [ #  # ]:           0 :                 QFileInfo fi(path);
     706   [ #  #  #  #  :           0 :                 if (!fi.dir().mkpath(u"."_s))
                   #  # ]
     707                 :           0 :                     throw Exception("could not create path to extra Wayland socket: %1").arg(path);
     708                 :             : 
     709         [ #  # ]:           0 :                 auto sudo = SudoClient::instance();
     710                 :             : 
     711   [ #  #  #  #  :           0 :                 if (!sudo || sudo->isFallbackImplementation()) {
                   #  # ]
     712   [ #  #  #  # ]:           0 :                     if (!QLocalServer::removeServer(path)) {
     713                 :           0 :                         throw Exception("could not clean up leftover extra Wayland socket %1").arg(path);
     714                 :             :                     }
     715                 :             :                 } else {
     716         [ #  # ]:           0 :                     sudo->removeRecursive(path);
     717                 :             :                 }
     718                 :             : 
     719   [ #  #  #  # ]:           0 :                 std::unique_ptr<QLocalServer> extraSocket(new QLocalServer);
     720         [ #  # ]:           0 :                 extraSocket->setMaxPendingConnections(0); // disable Qt's new connection handling
     721   [ #  #  #  # ]:           0 :                 if (!extraSocket->listen(path)) {
     722         [ #  # ]:           0 :                     throw Exception("could not listen on extra Wayland socket %1: %2")
     723         [ #  # ]:           0 :                         .arg(path, extraSocket->errorString());
     724                 :             :                 }
     725                 :           0 :                 int mode = wes.permissions;
     726                 :           0 :                 int uid = wes.userId;
     727                 :           0 :                 int gid = wes.groupId;
     728                 :             : 
     729         [ #  # ]:           0 :                 QByteArray encodedPath = QFile::encodeName(path);
     730                 :             : 
     731   [ #  #  #  #  :           0 :                 if ((mode > 0) || (uid != -1) || (gid != -1)) {
                   #  # ]
     732   [ #  #  #  #  :           0 :                     if (!sudo || sudo->isFallbackImplementation()) {
                   #  # ]
     733         [ #  # ]:           0 :                         if (mode > 0) {
     734   [ #  #  #  # ]:           0 :                             if (::chmod(encodedPath, static_cast<mode_t>(mode)) != 0)
     735                 :           0 :                                 throw Exception(errno, "could not chmod(mode: %1) the extra Wayland socket %2")
     736         [ #  # ]:           0 :                                     .arg(QString::number(mode, 8), path);
     737                 :             :                         }
     738   [ #  #  #  # ]:           0 :                         if ((uid != -1) || (gid != -1)) {
     739   [ #  #  #  # ]:           0 :                             if (::chown(encodedPath, static_cast<uid_t>(uid), static_cast<gid_t>(gid)) != 0)
     740                 :           0 :                                 throw Exception(errno, "could not chown(uid: %1, gid: %2) the extra Wayland socket %3")
     741                 :           0 :                                     .arg(uid).arg(gid).arg(path);
     742                 :             :                         }
     743                 :             :                     } else {
     744   [ #  #  #  # ]:           0 :                         if (!sudo->setOwnerAndPermissionsRecursive(path, static_cast<uid_t>(uid),
     745                 :             :                                                                    static_cast<gid_t>(gid),
     746                 :             :                                                                    static_cast<mode_t>(mode))) {
     747                 :           0 :                             throw Exception(Error::IO, "could not change the owner to %1:%2 and the permission"
     748                 :             :                                                        " bits to %3 for the extra Wayland socket %4: %5")
     749                 :           0 :                                     .arg(uid).arg(gid).arg(mode, 0, 8).arg(path).arg(sudo->lastError());
     750                 :             :                         }
     751                 :             :                         // if we changed the owner, ~QLocalServer might not be able to clean up the
     752                 :             :                         // socket inode, so we need to sudo this removal as well
     753         [ #  # ]:           0 :                         QObject::connect(extraSocket.get(), &QObject::destroyed, [path, sudo]() {
     754                 :           0 :                             sudo->removeRecursive(path);
     755                 :             :                         });
     756                 :             :                     }
     757                 :             :                 }
     758                 :             : 
     759         [ #  # ]:           0 :                 m_windowManager->addWaylandSocket(extraSocket.release());
     760         [ #  # ]:           0 :             } catch (const std::exception &e) {
     761   [ -  -  -  -  :           0 :                 qCCritical(LogSystem) << "ERROR:" << e.what();
          -  -  -  -  -  
                      - ]
     762                 :           0 :             }
     763                 :           0 :         }
     764                 :          25 :     });
     765                 :             : #endif
     766                 :             : 
     767                 :          52 :     QObject::connect(&m_applicationManager->internalSignals, &ApplicationManagerInternalSignals::newRuntimeCreated,
     768                 :          52 :                      m_windowManager, &WindowManager::setupInProcessRuntime);
     769                 :          52 :     QObject::connect(m_applicationManager, &ApplicationManager::applicationWasActivated,
     770                 :          52 :                      m_windowManager, &WindowManager::raiseApplicationWindow);
     771                 :          52 : }
     772                 :             : 
     773                 :          52 : void Main::createInstanceInfoFile(const QString &instanceId) noexcept(false)
     774                 :             : {
     775                 :             :     // This is needed for the appman-controller tool to talk to running appman instances.
     776                 :             :     // (the tool does not even have a session bus, when started via ssh)
     777                 :             : 
     778   [ +  +  +  - ]:          52 :     static const QString defaultInstanceId = u"appman"_s;
     779                 :             : 
     780                 :          52 :     QString rtPath = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
     781         [ -  + ]:          52 :     if (rtPath.isEmpty())
     782         [ #  # ]:           0 :         rtPath = QDir::tempPath();
     783   [ +  -  +  - ]:         104 :     QDir rtDir(rtPath + u"/qtapplicationmanager"_s);
     784   [ +  -  -  + ]:          52 :     if (!rtDir.mkpath(u"."_s))
     785         [ #  # ]:           0 :         throw Exception("Could not create runtime state directory (%1) for the instance info").arg(rtDir.absolutePath());
     786                 :             : 
     787                 :          52 :     QString fileName;
     788   [ +  +  +  - ]:          53 :     QString filePattern = (instanceId.isEmpty() ? defaultInstanceId : instanceId) + u"-%1";
     789                 :             : 
     790   [ +  +  +  - ]:          52 :     static std::unique_ptr<QLockFile> lockf;
     791   [ +  +  +  -  :         104 :     static std::unique_ptr<QFile, void (*)(QFile *)> infof(nullptr, [](QFile *f) { f->remove(); delete f; });
                   +  - ]
     792                 :             : 
     793         [ +  - ]:          52 :     for (int i = 0; i < 32; ++i) { // Wayland sockets are limited to 32 instances as well
     794         [ +  - ]:          52 :         QString tryPattern = filePattern.arg(i);
     795   [ +  -  +  -  :         104 :         lockf.reset(new QLockFile(rtDir.absoluteFilePath(tryPattern + u".lock"_s)));
             +  -  +  - ]
     796         [ +  - ]:          52 :         lockf->setStaleLockTime(0);
     797   [ +  -  +  - ]:          52 :         if (lockf->tryLock()) {
     798                 :          52 :             fileName = tryPattern;
     799                 :          52 :             break; // found a free instance id
     800                 :             :         }
     801                 :          52 :     }
     802         [ -  + ]:          52 :     if (fileName.isEmpty())
     803         [ #  # ]:           0 :         throw Exception("Could not create a lock file for the instance info at %1").arg(rtDir.absolutePath());;
     804                 :             : 
     805   [ +  -  +  -  :         104 :     infof.reset(new QFile(rtDir.absoluteFilePath(fileName + u".json"_s)));
             +  -  +  - ]
     806                 :             : 
     807   [ +  -  +  - ]:         104 :     const QByteArray json = QJsonDocument::fromVariant(m_infoFileContents).toJson(QJsonDocument::Indented);
     808   [ +  -  -  + ]:          52 :     if (!infof->open(QIODevice::WriteOnly))
     809                 :           0 :         throw Exception(*infof.get(), "failed to create instance info file");
     810   [ +  -  -  + ]:          52 :     if (infof->write(json) !=json.size())
     811                 :           0 :         throw Exception(*infof.get(), "failed to write instance info file");
     812         [ +  - ]:          52 :     infof->close();
     813                 :          52 : }
     814                 :             : 
     815                 :          42 : void Main::loadQml() noexcept(false)
     816                 :             : {
     817         [ -  + ]:          42 :     for (auto iface : std::as_const(m_startupPlugins))
     818                 :           0 :         iface->beforeQmlEngineLoad(m_engine);
     819                 :             : 
     820                 :             :     // protect our namespace from this point onward
     821                 :          42 :     qmlProtectModule("QtApplicationManager", 1);
     822                 :          42 :     qmlProtectModule("QtApplicationManager.SystemUI", 1);
     823                 :          42 :     qmlProtectModule("QtApplicationManager", 2);
     824                 :          42 :     qmlProtectModule("QtApplicationManager.SystemUI", 2);
     825                 :             : 
     826                 :          42 :     m_engine->load(m_mainQml);
     827         [ -  + ]:          42 :     if (Q_UNLIKELY(m_engine->rootObjects().isEmpty()))
     828                 :           0 :         throw Exception("Qml scene does not have a root object");
     829                 :             : 
     830         [ -  + ]:          42 :     for (auto iface : std::as_const(m_startupPlugins))
     831                 :           0 :         iface->afterQmlEngineLoad(m_engine);
     832                 :             : 
     833                 :          42 :     StartupTimer::instance()->checkpoint("after loading main QML file");
     834                 :          42 : }
     835                 :             : 
     836                 :           0 : void Main::showWindow(bool showFullscreen)
     837                 :             : {
     838                 :           0 :     m_showFullscreen = showFullscreen;
     839                 :           0 :     showWindow();
     840                 :           0 : }
     841                 :             : 
     842                 :          42 : void Main::showWindow()
     843                 :             : {
     844                 :          42 :     setQuitOnLastWindowClosed(false);
     845                 :          42 :     connect(this, &QGuiApplication::lastWindowClosed, this, [this]() { shutDown("window closed"); });
     846                 :             : 
     847                 :          42 :     QQuickWindow *window = nullptr;
     848                 :          42 :     QObject *rootObject = m_engine->rootObjects().constFirst();
     849                 :             : 
     850         [ -  + ]:          42 :     if (rootObject->isWindowType()) {
     851                 :           0 :         window = qobject_cast<QQuickWindow *>(rootObject);
     852                 :             :     } else {
     853         [ +  - ]:          42 :         QQuickItem *contentItem = qobject_cast<QQuickItem *>(rootObject);
     854                 :          42 :         if (contentItem) {
     855         [ +  - ]:          42 :             m_view = new QQuickView(m_engine, nullptr);
     856                 :          42 :             m_view->setContent(m_mainQml, nullptr, rootObject);
     857                 :          42 :             m_view->setVisible(contentItem->isVisible());
     858                 :          42 :             connect(contentItem, &QQuickItem::visibleChanged, this, [this, contentItem]() {
     859                 :           0 :                 m_view->setVisible(contentItem->isVisible());
     860                 :           0 :             });
     861                 :          42 :             window = m_view;
     862                 :             :         }
     863                 :             :     }
     864                 :             : 
     865         [ -  + ]:          42 :     for (auto iface : std::as_const(m_startupPlugins))
     866                 :           0 :         iface->beforeWindowShow(window);
     867                 :             : 
     868         [ -  + ]:          42 :     if (!window) {
     869                 :           0 :         const QWindowList windowList = allWindows();
     870         [ #  # ]:           0 :         for (QWindow *w : windowList) {
     871   [ #  #  #  # ]:           0 :             if (w->isVisible()) {
     872         [ #  # ]:           0 :                 window = qobject_cast<QQuickWindow*>(w);
     873                 :             :                 break;
     874                 :             :             }
     875                 :             :         }
     876                 :           0 :     }
     877                 :             : 
     878         [ +  - ]:          42 :     if (window) {
     879                 :          42 :         Q_ASSERT(m_engine->incubationController());
     880                 :             : 
     881                 :          42 :         StartupTimer::instance()->checkpoint("after Window instantiation/setup");
     882                 :             : 
     883                 :         122 :         static QMetaObject::Connection conn = QObject::connect(window, &QQuickWindow::frameSwapped, this, []() {
     884                 :             :             // this is a queued signal, so there may be still one in the queue after calling disconnect()
     885         [ +  + ]:          80 :             if (conn) {
     886                 :             : #if defined(Q_CC_MSVC)
     887                 :             :                 qApp->disconnect(conn); // MSVC cannot distinguish between static and non-static overloads in lambdas
     888                 :             : #else
     889                 :          40 :                 QObject::disconnect(conn);
     890                 :             : #endif
     891                 :          40 :                 auto st = StartupTimer::instance();
     892                 :          40 :                 st->checkFirstFrame();
     893         [ +  - ]:          80 :                 st->createAutomaticReport(u"System UI"_s);
     894                 :             :             }
     895   [ +  -  +  -  :         122 :         });
                   +  - ]
     896                 :             : 
     897                 :             :         // Main window will always be shown, neglecting visible property for backwards compatibility
     898         [ -  + ]:          42 :         if (Q_LIKELY(m_showFullscreen))
     899                 :           0 :             window->showFullScreen();
     900                 :             :         else
     901                 :          42 :             window->setVisible(true);
     902                 :             : 
     903                 :             :         // now check the surface format, in case we had requested a specific GL version/profile
     904         [ +  - ]:          42 :         checkOpenGLFormat("main window", window->format());
     905                 :             : 
     906         [ -  + ]:          42 :         for (auto iface : std::as_const(m_startupPlugins))
     907                 :           0 :             iface->afterWindowShow(window);
     908                 :             : 
     909                 :          42 :         StartupTimer::instance()->checkpoint("after window show");
     910                 :             :     } else {
     911                 :           0 :         static QMetaObject::Connection conn =
     912                 :           0 :             connect(this, &QGuiApplication::focusWindowChanged, this, [this] (QWindow *win) {
     913         [ #  # ]:           0 :             if (conn) {
     914                 :           0 :                 QObject::disconnect(conn);
     915         [ #  # ]:           0 :                 checkOpenGLFormat("first window", win->format());
     916                 :             :             }
     917   [ #  #  #  #  :           0 :         });
                   #  # ]
     918         [ #  # ]:           0 :         StartupTimer::instance()->createAutomaticReport(u"System UI"_s);
     919                 :             :     }
     920                 :          42 : }
     921                 :             : 
     922                 :          52 : void Main::setupDBus(const Configuration *cfg)
     923                 :             : {
     924                 :             : #if defined(QT_DBUS_LIB) && QT_CONFIG(am_external_dbus_interfaces)
     925                 :          52 :     registerDBusTypes();
     926                 :             : 
     927         [ +  - ]:         104 :     DBusPolicy::createInstance([](qint64 pid) { return ApplicationManager::instance()->identifyAllApplications(pid); },
     928                 :           0 :                                [](const QString &appId) { return ApplicationManager::instance()->capabilities(appId); });
     929                 :             : 
     930                 :             :     // <0> DBusContextAdaptor instance
     931                 :             :     // <1> D-Bus name (extracted from callback function busForInterface)
     932                 :             :     // <2> D-Bus service
     933                 :             :     // <3> D-Bus path
     934                 :             :     // <4> Interface name (extracted from Q_CLASSINFO below)
     935                 :             : 
     936                 :          52 :     std::vector<std::tuple<DBusContextAdaptor *, QString, QString, QString, QString>> ifaces;
     937                 :             : 
     938                 :         260 :     auto addInterface = [&](DBusContextAdaptor *adaptor, const QString &service, const QString &path) {
     939                 :         208 :         int idx = adaptor->parent()->metaObject()->indexOfClassInfo("D-Bus Interface");
     940         [ -  + ]:         208 :         if (idx < 0) {
     941                 :           0 :             throw Exception("Could not get class-info \"D-Bus Interface\" for D-Bus adapter %1")
     942   [ #  #  #  #  :           0 :                     .arg(QString::fromLatin1(adaptor->parent()->metaObject()->className()));
             #  #  #  # ]
     943                 :             :         }
     944         [ +  - ]:         416 :         QString interfaceName = QString::fromLatin1(adaptor->parent()->metaObject()->classInfo(idx).value());
     945         [ -  + ]:         208 :         auto iit = cfg->yaml.dbus.registrations.constFind(interfaceName);
     946   [ -  +  -  +  :         208 :         QString bus = (iit != cfg->yaml.dbus.registrations.cend()) ? iit->toString() : cfg->dbus();
             -  -  +  - ]
     947                 :             : 
     948         [ +  - ]:         208 :         ifaces.emplace_back(adaptor, bus, service, path, interfaceName);
     949                 :         208 :     };
     950                 :             : 
     951         [ +  - ]:         104 :     addInterface(DBusContextAdaptor::create<PackageManagerAdaptor>(m_packageManager),
     952         [ +  - ]:         104 :                  u"io.qt.ApplicationManager"_s, u"/PackageManager"_s);
     953         [ +  - ]:         104 :     addInterface(DBusContextAdaptor::create<WindowManagerAdaptor>(m_windowManager),
     954         [ +  - ]:         104 :                  u"io.qt.ApplicationManager"_s, u"/WindowManager"_s);
     955         [ +  - ]:         104 :     addInterface(DBusContextAdaptor::create<NotificationsAdaptor>(m_notificationManager),
     956         [ +  - ]:         104 :                  u"org.freedesktop.Notifications"_s, u"/org/freedesktop/Notifications"_s);
     957         [ +  - ]:         104 :     addInterface(DBusContextAdaptor::create<ApplicationManagerAdaptor>(m_applicationManager),
     958         [ +  - ]:         104 :                  u"io.qt.ApplicationManager"_s, u"/ApplicationManager"_s);
     959                 :             : 
     960                 :          52 :     bool autoOnly = true;
     961                 :          52 :     bool noneOnly = true;
     962                 :             : 
     963                 :             :     // check if all interfaces are on the "auto" bus and replace the "none" bus with nullptr
     964         [ +  + ]:         260 :     for (auto &&iface : ifaces) {
     965                 :         208 :         QString dbusName = std::get<1>(iface);
     966         [ +  + ]:         208 :         if (dbusName != u"auto"_s)
     967                 :          44 :             autoOnly = false;
     968         [ +  + ]:         208 :         if (dbusName == u"none")
     969                 :          44 :             std::get<1>(iface).clear();
     970                 :             :         else
     971                 :             :             noneOnly = false;
     972                 :         208 :     }
     973                 :             : 
     974                 :             :     // start a private dbus-daemon session instance if all interfaces are set to "auto"
     975         [ +  + ]:          52 :     if (Q_UNLIKELY(autoOnly)) {
     976                 :          41 :         try {
     977         [ +  - ]:          41 :             DBusDaemonProcess::start();
     978   [ +  -  +  - ]:          41 :             StartupTimer::instance()->checkpoint("after starting session D-Bus");
     979         [ -  - ]:           0 :         } catch (const Exception &e) {
     980                 :             : #  if defined(Q_OS_LINUX)
     981   [ -  -  -  -  :           0 :             qCWarning(LogDBus) << "Disabling external D-Bus interfaces:" << e.what();
          -  -  -  -  -  
                      - ]
     982         [ -  - ]:           0 :             for (auto &&iface : ifaces)
     983                 :           0 :                 std::get<1>(iface).clear();
     984                 :           0 :             noneOnly = true;
     985                 :             : #  else
     986                 :             :             qCWarning(LogDBus) << "Could not start a private dbus-daemon:" << e.what();
     987                 :             :             qCInfo(LogDBus) << "Enabling DBus P2P access for appman-controller";
     988                 :             :             for (auto &&iface : ifaces) {
     989                 :             :                 QString &dbusName = std::get<1>(iface);
     990                 :             :                 if (dbusName == u"auto")
     991                 :             :                     dbusName = u"p2p"_s;
     992                 :             :             }
     993                 :             : #  endif
     994                 :           0 :         }
     995                 :             :     }
     996                 :             : 
     997         [ +  + ]:          52 :     if (!noneOnly) {
     998   [ +  -  -  -  :          82 :         qCDebug(LogDBus) << "Registering D-Bus services:";
             -  -  -  + ]
     999                 :             : 
    1000         [ +  + ]:         205 :         for (auto &&iface : ifaces) {
    1001         [ +  - ]:         164 :             auto *generatedAdaptor = std::get<0>(iface)->generatedAdaptor<QDBusAbstractAdaptor>();
    1002         [ -  + ]:         164 :             QString &dbusName = std::get<1>(iface);
    1003         [ -  + ]:         164 :             QString &interfaceName = std::get<4>(iface);
    1004                 :             : 
    1005         [ -  + ]:         164 :             if (dbusName.isEmpty())
    1006                 :           0 :                 continue;
    1007                 :             : 
    1008         [ +  - ]:         164 :             auto dbusAddress = registerDBusObject(generatedAdaptor, dbusName,
    1009         [ +  - ]:         164 :                                                   std::get<2>(iface), std::get<3>(iface));
    1010   [ +  -  +  - ]:         328 :             auto policy = cfg->yaml.dbus.policies.value(interfaceName).toMap();
    1011                 :             : 
    1012   [ +  -  +  -  :         164 :             if (!DBusPolicy::instance()->add(generatedAdaptor, policy))
                   -  + ]
    1013                 :           0 :                 throw Exception(Error::DBus, "could not set DBus policy for %1").arg(interfaceName);
    1014                 :             : 
    1015                 :             :             // Write the bus address to our info file for the appman-controller tool
    1016         [ +  + ]:         164 :             if (interfaceName.startsWith(u"io.qt.")) {
    1017   [ +  -  +  - ]:         123 :                 auto map = m_infoFileContents[u"dbus"_s].toMap();
    1018         [ +  - ]:         123 :                 map.insert(interfaceName, dbusAddress);
    1019         [ +  - ]:         123 :                 m_infoFileContents[u"dbus"_s] = map;
    1020                 :         123 :             }
    1021                 :         164 :         }
    1022                 :             :     }
    1023                 :             : #else
    1024                 :             :     Q_UNUSED(cfg)
    1025                 :             :     Q_UNUSED(m_p2pServer)
    1026                 :             :     Q_UNUSED(m_p2pAdaptors)
    1027                 :             :     Q_UNUSED(m_p2pFailed)
    1028                 :             : #endif // defined(QT_DBUS_LIB) && QT_CONFIG(am_external_dbus_interfaces)
    1029                 :          52 : }
    1030                 :             : 
    1031                 :         164 : QString Main::registerDBusObject(QDBusAbstractAdaptor *adaptor, const QString &dbusName,
    1032                 :             :                                  const QString &serviceName, const QString &path) noexcept(false)
    1033                 :             : {
    1034                 :             : #if defined(QT_DBUS_LIB) && QT_CONFIG(am_external_dbus_interfaces)
    1035                 :         164 :     QString dbusAddress;
    1036                 :         164 :     QString dbusRealName = dbusName;
    1037         [ +  - ]:         164 :     QDBusConnection conn((QString()));
    1038                 :         164 :     bool isP2P = false;
    1039                 :             : 
    1040         [ -  + ]:         164 :     if (dbusName.isEmpty()) {
    1041                 :           0 :         return { };
    1042         [ -  + ]:         164 :     } else if (dbusName == u"system") {
    1043         [ #  # ]:           0 :         dbusAddress = QString::fromLocal8Bit(qgetenv("DBUS_SYSTEM_BUS_ADDRESS"));
    1044                 :             : #  if defined(Q_OS_LINUX)
    1045         [ #  # ]:           0 :         if (dbusAddress.isEmpty())
    1046                 :           0 :             dbusAddress = u"unix:path=/var/run/dbus/system_bus_socket"_s;
    1047                 :             : #  endif
    1048         [ #  # ]:           0 :         conn = QDBusConnection::systemBus();
    1049         [ -  + ]:         164 :     } else if (dbusName == u"session") {
    1050         [ #  # ]:           0 :         dbusAddress = QString::fromLocal8Bit(qgetenv("DBUS_SESSION_BUS_ADDRESS"));
    1051         [ #  # ]:           0 :         conn = QDBusConnection::sessionBus();
    1052         [ +  - ]:         164 :     } else if (dbusName == u"auto") {
    1053         [ +  - ]:         328 :         dbusAddress = QString::fromLocal8Bit(qgetenv("DBUS_SESSION_BUS_ADDRESS"));
    1054                 :             :         // we cannot be using QDBusConnection::sessionBus() here, because some plugin
    1055                 :             :         // might have called that function before we could spawn our own session bus. In
    1056                 :             :         // this case, Qt has cached the bus name and we would get the old one back.
    1057         [ +  - ]:         164 :         conn = QDBusConnection::connectToBus(dbusAddress, u"qtam_session"_s);
    1058   [ +  -  -  + ]:         164 :         if (!conn.isConnected())
    1059                 :           0 :             return { };
    1060                 :         164 :         dbusRealName = u"session"_s;
    1061         [ #  # ]:           0 :     } else if (dbusName == u"p2p") {
    1062   [ #  #  #  # ]:           0 :         if (!m_p2pServer && !m_p2pFailed) {
    1063   [ #  #  #  # ]:           0 :             m_p2pServer = new QDBusServer(this);
    1064         [ #  # ]:           0 :             m_p2pServer->setAnonymousAuthenticationAllowed(true);
    1065                 :             : 
    1066   [ #  #  #  # ]:           0 :             if (!m_p2pServer->isConnected()) {
    1067                 :           0 :                 m_p2pFailed = true;
    1068         [ #  # ]:           0 :                 delete m_p2pServer;
    1069                 :           0 :                 m_p2pServer = nullptr;
    1070   [ #  #  #  #  :           0 :                 qCCritical(LogDBus) << "Failed to create a P2P DBus server for appman-controller";
             #  #  #  # ]
    1071                 :             :             } else {
    1072         [ #  # ]:           0 :                 QObject::connect(m_p2pServer, &QDBusServer::newConnection,
    1073                 :           0 :                                  this, [this](const QDBusConnection &conn) {
    1074   [ #  #  #  # ]:           0 :                     for (const auto &[path, object] : std::as_const(m_p2pAdaptors).asKeyValueRange())
    1075   [ #  #  #  # ]:           0 :                         object->registerOnDBus(conn, path);
    1076                 :           0 :                 });
    1077                 :             :             }
    1078                 :             :         }
    1079         [ #  # ]:           0 :         if (m_p2pFailed)
    1080                 :           0 :             return { };
    1081   [ #  #  #  # ]:           0 :         m_p2pAdaptors.insert(path, qobject_cast<DBusContextAdaptor *>(adaptor->parent()));
    1082   [ #  #  #  # ]:           0 :         dbusAddress = u"p2p:"_s + m_p2pServer->address();
    1083                 :           0 :         isP2P = true;
    1084                 :             :     } else {
    1085                 :           0 :         dbusAddress = dbusName;
    1086         [ #  # ]:           0 :         conn = QDBusConnection::connectToBus(dbusAddress, u"custom"_s);
    1087                 :             :     }
    1088                 :             : 
    1089                 :         164 :     if (!isP2P) {
    1090   [ +  -  -  + ]:         164 :         if (!conn.isConnected()) {
    1091         [ #  # ]:           0 :             throw Exception("could not connect to D-Bus (%1): %2")
    1092   [ #  #  #  #  :           0 :                 .arg(dbusAddress.isEmpty() ? dbusRealName : dbusAddress).arg(conn.lastError().message());
                   #  # ]
    1093                 :             :         }
    1094                 :             : 
    1095   [ +  -  -  + ]:         164 :         if (!conn.registerObject(path, adaptor->parent(), QDBusConnection::ExportAdaptors)) {
    1096                 :           0 :             throw Exception("could not register object %1 on D-Bus (%2): %3")
    1097   [ #  #  #  # ]:           0 :                 .arg(path).arg(dbusRealName).arg(conn.lastError().message());
    1098                 :             :         }
    1099                 :             : 
    1100   [ +  -  -  + ]:         164 :         if (!conn.registerService(serviceName)) {
    1101                 :           0 :             throw Exception("could not register service %1 on D-Bus (%2): %3")
    1102   [ #  #  #  # ]:           0 :                 .arg(serviceName).arg(dbusRealName).arg(conn.lastError().message());
    1103                 :             :         }
    1104                 :             :     }
    1105                 :             : 
    1106   [ +  -  +  - ]:         164 :     if (adaptor->parent() && adaptor->parent()->parent()) {
    1107                 :             :         // we need this information later on to tell apps where services are listening
    1108         [ +  - ]:         164 :         adaptor->parent()->parent()->setProperty("_am_dbus_name", dbusRealName);
    1109         [ +  - ]:         164 :         adaptor->parent()->parent()->setProperty("_am_dbus_address", dbusAddress);
    1110                 :             :     }
    1111                 :             : 
    1112   [ +  -  -  -  :         328 :     qCDebug(LogDBus).nospace().noquote() << " * " << serviceName << path << " [on bus: " << dbusRealName << "]";
          -  -  -  -  -  
          -  -  -  -  -  
             -  -  -  + ]
    1113                 :             : 
    1114         [ +  - ]:         164 :     return dbusAddress.isEmpty() ? dbusRealName : dbusAddress;
    1115                 :             : #else
    1116                 :             :     Q_UNUSED(adaptor)
    1117                 :             :     Q_UNUSED(dbusName)
    1118                 :             :     Q_UNUSED(serviceName)
    1119                 :             :     Q_UNUSED(path)
    1120                 :             :     return { };
    1121                 :             : #endif // defined(QT_DBUS_LIB) && QT_CONFIG(am_external_dbus_interfaces)
    1122                 :         164 : }
    1123                 :             : 
    1124                 :          21 : QString Main::hardwareId() const
    1125                 :             : {
    1126   [ +  +  +  - ]:          21 :     static QString hardwareId;
    1127         [ +  + ]:          21 :     if (hardwareId.isEmpty()) {
    1128                 :             : #if defined(QT_AM_HARDWARE_ID)
    1129                 :             :         hardwareId = QString::fromLocal8Bit(QT_AM_HARDWARE_ID);
    1130                 :             :         if (hardwareId.startsWith(u'@')) {
    1131                 :             :             QFile f(hardwareId.mid(1));
    1132                 :             :             hardwareId.clear();
    1133                 :             :             if (f.open(QFile::ReadOnly))
    1134                 :             :                 hardwareId = QString::fromLocal8Bit(f.readAll().trimmed());
    1135                 :             :         }
    1136                 :             : #else
    1137                 :          12 :         QVector<QNetworkInterface> candidateIfaces;
    1138         [ +  - ]:          12 :         const auto allIfaces = QNetworkInterface::allInterfaces();
    1139         [ +  + ]:          48 :         for (const QNetworkInterface &iface : allIfaces) {
    1140         [ +  - ]:          36 :             if (iface.isValid()
    1141   [ +  -  +  + ]:          36 :                     && !(iface.flags() & (QNetworkInterface::IsPointToPoint | QNetworkInterface::IsLoopBack))
    1142   [ +  -  +  - ]:          24 :                     && iface.type() > QNetworkInterface::Virtual
    1143   [ +  -  +  -  :          96 :                     && !iface.hardwareAddress().isEmpty()) {
          -  +  -  +  +  
                      + ]
    1144         [ +  - ]:          60 :                 candidateIfaces << iface;
    1145                 :             :             }
    1146                 :             :         }
    1147         [ +  - ]:          12 :         if (!candidateIfaces.isEmpty()) {
    1148   [ +  -  +  - ]:          24 :             std::sort(candidateIfaces.begin(), candidateIfaces.end(), [](const QNetworkInterface &first, const QNetworkInterface &second) {
    1149         [ +  - ]:          12 :                 return first.name().compare(second.name()) < 0;
    1150                 :             :             });
    1151   [ +  -  +  - ]:          12 :             hardwareId = candidateIfaces.constFirst().hardwareAddress().replace(u':', u'-');
    1152                 :             :         }
    1153                 :             : #endif
    1154                 :          12 :     }
    1155                 :          21 :     return hardwareId;
    1156                 :             : }
    1157                 :             : 
    1158                 :       78349 : bool Main::notify(QObject *receiver, QEvent *event)
    1159                 :             : {
    1160                 :       78349 :     const SharedMain::EventNotifyWatcher enw(receiver, event);
    1161         [ +  - ]:      156698 :     return MainBase::notify(receiver, event);
    1162                 :       78349 : }
    1163                 :             : 
    1164                 :             : QT_END_NAMESPACE_AM
    1165                 :             : 
    1166                 :             : #include "moc_main.cpp"
        

Generated by: LCOV version 2.0-1