1 /*
2 * \copyright Copyright (c) 2014-2021 Governikus GmbH & Co. KG, Germany
3 */
4
5 #include "Bootstrap.h"
6
7 #include "BuildHelper.h"
8 #include "controller/AppController.h"
9 #include "CommandLineParser.h"
10 #include "Env.h"
11 #include "LogHandler.h"
12 #include "SignalHandler.h"
13
14 #include <openssl/crypto.h>
15
16 #include <QLoggingCategory>
17 #include <QProcess>
18 #include <QScopedPointer>
19 #include <QSslSocket>
20 #include <QThread>
21
22 #include "config.h"
23
24 using namespace governikus;
25
26 Q_DECLARE_LOGGING_CATEGORY(init)
27
28
29 #if defined(INTEGRATED_SDK)
30 #ifdef Q_OS_ANDROID
31 #include <QAndroidService>
32 using QAPP = QAndroidService;
33
34 #else
35 #include <QCoreApplication>
36 using QAPP = QCoreApplication;
37 #endif
38
39 #elif defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(Q_OS_WINRT)
40 #ifdef Q_OS_ANDROID
41 #include <QAndroidService>
42 #include <QtAndroid>
43 #endif
44
45 #include <QGuiApplication>
46 using QAPP = QGuiApplication;
47 #else
48 #include <QApplication>
49 using QAPP = QApplication;
50 #endif
51
52
printInfo()53 static inline void printInfo()
54 {
55 qCDebug(init) << "Logging to" << *Env::getSingleton<LogHandler>();
56
57 qCInfo(init) << "##################################################";
58 const auto& info = BuildHelper::getInformationHeader();
59 for (const auto& entry : info)
60 {
61 qCInfo(init).noquote().nospace() << "### " << entry.first << ": " << entry.second;
62 }
63 qCInfo(init) << "##################################################";
64
65 #if OPENSSL_VERSION_NUMBER < 0x10100000L
66 #define OpenSSL_version SSLeay_version
67 #define OPENSSL_VERSION SSLEAY_VERSION
68 #endif
69
70 if (QSslSocket::sslLibraryVersionString() != QLatin1String(OpenSSL_version(OPENSSL_VERSION)))
71 {
72 qCWarning(init) << "Linked OpenSSL Version differs:" << OpenSSL_version(OPENSSL_VERSION);
73 }
74
75 const auto libPathes = QCoreApplication::libraryPaths();
76 for (const auto& path : libPathes)
77 {
78 qCDebug(init) << "Library path:" << path;
79 }
80 }
81
82
initQt(int & argc,char ** argv)83 static inline QCoreApplication* initQt(int& argc, char** argv)
84 {
85 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
86 QCoreApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton);
87 QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
88 #endif
89
90 QCoreApplication::setOrganizationName(QStringLiteral(VENDOR));
91 QCoreApplication::setOrganizationDomain(QStringLiteral(VENDOR_DOMAIN));
92 QCoreApplication::setApplicationName(QStringLiteral(PRODUCT));
93 QCoreApplication::setApplicationVersion(QStringLiteral(VERSION));
94
95 #ifndef INTEGRATED_SDK
96 QGuiApplication::setQuitOnLastWindowClosed(false);
97 #endif
98
99 #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) && !defined(INTEGRATED_SDK)
100 QGuiApplication::setDesktopSettingsAware(false);
101 #endif
102
103 #if defined(Q_OS_ANDROID) && !defined(INTEGRATED_SDK)
104 if (QtAndroid::androidService().isValid())
105 {
106 return new QAndroidService(argc, argv);
107 }
108 #endif
109
110 return new QAPP(argc, argv);
111 }
112
113
exec(const QScopedPointer<QCoreApplication> & pApp)114 static inline int exec(const QScopedPointer<QCoreApplication>& pApp)
115 {
116 #if defined(Q_OS_ANDROID) && !defined(INTEGRATED_SDK)
117 if (QLatin1String(pApp->metaObject()->className()) == QLatin1String("QAndroidService"))
118 {
119 return QAndroidService::exec();
120 }
121 #else
122 Q_UNUSED(pApp)
123 #endif
124 return QAPP::exec();
125 }
126
127
128 #if defined(Q_OS_WIN) || defined(Q_OS_MACOS) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
restartApp(const QString & pApplicationFilePath,QStringList pArgumentList,int pArgc)129 static void restartApp(const QString& pApplicationFilePath, QStringList pArgumentList, int pArgc)
130 {
131 if (pArgumentList.size() == pArgc)
132 {
133 pArgumentList.removeFirst();
134 }
135
136 pArgumentList << QStringLiteral("--show");
137
138 qCInfo(init) << "Attempting to start new process:" << pApplicationFilePath << ", args:" << pArgumentList;
139 if (qint64 pid = -1; QProcess::startDetached(pApplicationFilePath, pArgumentList, QString(), &pid))
140 {
141 qCInfo(init) << "New process successfully launched, PID:" << pid;
142 }
143 else
144 {
145 qCCritical(init) << "Could not launch new process.";
146 }
147 }
148
149
150 #endif
151
initApp(int & argc,char ** argv)152 int governikus::initApp(int& argc, char** argv)
153 {
154 const QScopedPointer<QCoreApplication> app(initQt(argc, argv));
155 QThread::currentThread()->setObjectName(QStringLiteral("MainThread"));
156
157 CommandLineParser::getInstance().parse();
158 Env::getSingleton<LogHandler>()->init();
159 Env::getSingleton<SignalHandler>()->init();
160 printInfo();
161
162 AppController controller;
163 if (!controller.start())
164 {
165 qCCritical(init) << "Cannot start application controller, exit application";
166 return EXIT_FAILURE;
167 }
168
169 Env::getSingleton<SignalHandler>()->setController(controller);
170 if (Env::getSingleton<SignalHandler>()->shouldQuit())
171 {
172 return EXIT_SUCCESS;
173 }
174
175 const int returnCode = exec(app);
176
177 #if defined(Q_OS_WIN) || defined(Q_OS_MACOS) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
178 if (controller.shouldApplicationRestart())
179 {
180 restartApp(QCoreApplication::applicationFilePath(), QCoreApplication::arguments(), argc);
181 }
182 #endif
183
184 qCDebug(init) << "Leaving application... bye bye!";
185 return returnCode;
186 }
187