/
developermodesettings.cpp
611 lines (536 loc) · 23.6 KB
2
* Copyright (c) 2013 – 2019 Jolla Ltd.
3
* Copyright (c) 2019 – 2020 Open Mobile Platform LLC.
4
* Contact: Thomas Perl <thomas.perl@jollamobile.com>
5
* Contact: Raine Makelainen <raine.makelainen@jolla.com>
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
*
* You may use this file under the terms of the BSD license as follows:
*
* "Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Nemo Mobile nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
*/
#include "developermodesettings.h"
36
#include "logging_p.h"
37
38
39
40
#include <QFile>
#include <QDir>
#include <QDBusReply>
41
#include <QNetworkInterface>
42
#include <transaction.h>
44
45
46
47
48
49
50
/* Symbolic constants */
#define PROGRESS_INDETERMINATE (-1)
/* Interfaces for IP addresses */
#define USB_NETWORK_FALLBACK_INTERFACE "usb0"
#define USB_NETWORK_FALLBACK_IP "192.168.2.15"
#define WLAN_NETWORK_INTERFACE "wlan0"
51
#define WLAN_NETWORK_FALLBACK_INTERFACE "tether"
53
54
/* A file that is provided by the developer mode package */
#define DEVELOPER_MODE_PROVIDED_FILE "/usr/bin/devel-su"
55
#define DEVELOPER_MODE_PACKAGE "jolla-developer-mode"
56
#define DEVELOPER_MODE_PACKAGE_PRELOAD_DIR "/var/lib/jolla-developer-mode/preloaded/"
58
59
60
61
62
63
64
65
66
67
68
69
70
/* D-Bus service */
#define USB_MODED_SERVICE "com.meego.usb_moded"
#define USB_MODED_PATH "/com/meego/usb_moded"
#define USB_MODED_INTERFACE "com.meego.usb_moded"
/* D-Bus method names */
#define USB_MODED_GET_NET_CONFIG "get_net_config"
#define USB_MODED_SET_NET_CONFIG "net_config"
/* USB Mode Daemon network configuration properties */
#define USB_MODED_CONFIG_IP "ip"
#define USB_MODED_CONFIG_INTERFACE "interface"
71
72
73
/* Package which will move debug folder to /home/.system/usr/lib */
#define DEBUG_HOME_PACKAGE "jolla-developer-mode-home-debug-location"
74
static QMap<QString,QString> enumerate_network_interfaces()
75
76
77
{
QMap<QString,QString> result;
78
79
for (const QNetworkInterface &intf : QNetworkInterface::allInterfaces()) {
for (const QNetworkAddressEntry &entry : intf.addressEntries()) {
80
81
82
83
84
85
86
87
88
if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol) {
result[intf.name()] = entry.ip().toString();
}
}
}
return result;
}
89
90
91
92
93
94
95
96
97
98
99
static QString get_cached_package(const QString &version)
{
QDir dir(DEVELOPER_MODE_PACKAGE_PRELOAD_DIR);
QStringList filters;
filters << QStringLiteral("%1-%2.*.rpm").arg(DEVELOPER_MODE_PACKAGE).arg(version);
auto preloaded = dir.entryList(filters, QDir::Files, QDir::Name);
if (preloaded.empty())
return QString();
return dir.absoluteFilePath(preloaded.last());
}
100
101
102
103
104
105
106
107
108
109
110
namespace {
bool debugHomeFolderExists()
{
QDir pathDir("/home/.system/usr/lib/debug");
if (pathDir.exists()) {
return true;
}
return false;
}
}
111
112
DeveloperModeSettings::DeveloperModeSettings(QObject *parent)
: QObject(parent)
113
, m_usbModeDaemon(USB_MODED_SERVICE, USB_MODED_PATH, USB_MODED_INTERFACE, QDBusConnection::systemBus())
114
115
116
, m_wlanIpAddress("-")
, m_usbInterface(USB_NETWORK_FALLBACK_INTERFACE)
, m_usbIpAddress(USB_NETWORK_FALLBACK_IP)
117
, m_username(qgetenv("USER"))
118
, m_developerModeEnabled(QFile::exists(DEVELOPER_MODE_PROVIDED_FILE))
119
120
, m_workStatus(Idle)
, m_workProgress(PROGRESS_INDETERMINATE)
121
122
, m_transactionRole(PackageKit::Transaction::RoleUnknown)
, m_transactionStatus(PackageKit::Transaction::StatusUnknown)
123
, m_refreshedForInstall(false)
124
125
, m_localInstallFailed(false)
, m_localDeveloperModePackagePath(get_cached_package(QStringLiteral("*"))) // Initialized to possibly incompatible package
126
127
, m_debugHomeEnabled(debugHomeFolderExists())
, m_installationType(None)
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Resolve and update local package path
if (!m_localDeveloperModePackagePath.isEmpty()) {
PackageKit::Transaction *resolvePackage = PackageKit::Daemon::resolve(DEVELOPER_MODE_PACKAGE"-preload", PackageKit::Transaction::FilterInstalled);
connect(resolvePackage, &PackageKit::Transaction::errorCode, this, &DeveloperModeSettings::reportTransactionErrorCode);
connect(resolvePackage, &PackageKit::Transaction::package,
this, [this](PackageKit::Transaction::Info info, const QString &packageID, const QString &summary) {
Q_UNUSED(summary)
Q_ASSERT(info == PackageKit::Transaction::InfoInstalled);
const QString version = PackageKit::Transaction::packageVersion(packageID);
m_localDeveloperModePackagePath = get_cached_package(version);
if (m_localDeveloperModePackagePath.isEmpty()) {
emit repositoryAccessRequiredChanged();
}
qCDebug(lcDeveloperModeLog) << "Preload package version: " << version << ", local package path: " << m_localDeveloperModePackagePath;
});
}
146
147
148
149
150
151
152
153
154
155
refresh();
// TODO: Watch WLAN / USB IP addresses for changes
// TODO: Watch package manager for changes to developer mode
}
DeveloperModeSettings::~DeveloperModeSettings()
{
}
156
QString DeveloperModeSettings::wlanIpAddress() const
157
158
159
160
{
return m_wlanIpAddress;
}
161
QString DeveloperModeSettings::usbIpAddress() const
162
163
164
165
{
return m_usbIpAddress;
}
166
QString DeveloperModeSettings::username() const
167
168
169
170
{
return m_username;
}
171
bool DeveloperModeSettings::developerModeEnabled() const
172
173
174
175
{
return m_developerModeEnabled;
}
176
enum DeveloperModeSettings::Status DeveloperModeSettings::workStatus() const
178
return m_workStatus;
181
int DeveloperModeSettings::workProgress() const
183
return m_workProgress;
186
187
188
189
190
191
bool DeveloperModeSettings::repositoryAccessRequired() const
{
// Aka local-install-of-developer-mode-package-is-not-possible
return m_localInstallFailed || m_localDeveloperModePackagePath.isEmpty();
}
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
bool DeveloperModeSettings::debugHomeEnabled() const
{
return m_debugHomeEnabled;
}
enum DeveloperModeSettings::InstallationType DeveloperModeSettings::installationType() const
{
return m_installationType;
}
QString DeveloperModeSettings::packageName()
{
if (m_installationType == DeveloperMode) {
return DEVELOPER_MODE_PACKAGE;
} else if (m_installationType == DebugHome) {
return DEBUG_HOME_PACKAGE;
} else {
return QString();
}
}
void DeveloperModeSettings::setInstallationType(InstallationType type)
{
if (m_installationType != type) {
m_installationType = type;
emit installationTypeChanged();
}
}
221
void DeveloperModeSettings::setDeveloperMode(bool enabled)
223
if (m_developerModeEnabled != enabled) {
224
225
226
227
228
229
if (m_workStatus != Idle) {
qCWarning(lcDeveloperModeLog) << "DeveloperMode state change requested during activity, ignored.";
return;
}
m_refreshedForInstall = false;
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
setInstallationType(DeveloperMode);
if (enabled) {
resolveAndExecute(InstallCommand);
} else {
resolveAndExecute(RemoveCommand);
}
}
}
void DeveloperModeSettings::moveDebugToHome(bool enabled)
{
if (m_debugHomeEnabled != enabled) {
if (m_workStatus != Idle) {
qCWarning(lcDeveloperModeLog) << "Debug home state change requested during activity, ignored.";
return;
}
m_refreshedForInstall = false;
setInstallationType(DebugHome);
249
if (enabled) {
250
resolveAndExecute(InstallCommand);
251
} else {
252
resolveAndExecute(RemoveCommand);
253
254
255
256
}
}
}
257
void DeveloperModeSettings::setUsbIpAddress(const QString &usbIpAddress)
258
259
{
if (m_usbIpAddress != usbIpAddress) {
260
usbModedSetConfig(USB_MODED_CONFIG_IP, usbIpAddress);
261
262
263
264
265
m_usbIpAddress = usbIpAddress;
emit usbIpAddressChanged();
}
}
266
void DeveloperModeSettings::refresh()
267
268
{
/* Retrieve network configuration from usb_moded */
269
270
271
m_usbInterface = usbModedGetConfig(USB_MODED_CONFIG_INTERFACE, USB_NETWORK_FALLBACK_INTERFACE);
QString usbIp = usbModedGetConfig(USB_MODED_CONFIG_IP, USB_NETWORK_FALLBACK_IP);
272
if (usbIp != m_usbIpAddress) {
273
m_usbIpAddress = usbIp;
274
275
276
277
278
279
280
emit usbIpAddressChanged();
}
/* Retrieve network configuration from interfaces */
QMap<QString,QString> entries = enumerate_network_interfaces();
if (entries.contains(m_usbInterface)) {
281
QString ip = entries[m_usbInterface];
282
283
284
285
286
287
288
289
290
if (m_usbIpAddress != ip) {
m_usbIpAddress = ip;
emit usbIpAddressChanged();
}
}
if (entries.contains(WLAN_NETWORK_INTERFACE)) {
QString ip = entries[WLAN_NETWORK_INTERFACE];
if (m_wlanIpAddress != ip) {
291
292
293
294
295
296
297
298
299
m_wlanIpAddress = ip;
emit wlanIpAddressChanged();
}
} else if (entries.contains(WLAN_NETWORK_FALLBACK_INTERFACE)) {
// If the WLAN network interface does not have an IP address,
// but there is a "tether" interface that does have an IP, assume
// it is the WLAN interface in tethering mode, and use its IP.
QString ip = entries[WLAN_NETWORK_FALLBACK_INTERFACE];
if (m_wlanIpAddress != ip) {
300
301
302
303
304
m_wlanIpAddress = ip;
emit wlanIpAddressChanged();
}
}
305
306
for (const QString &device : entries.keys()) {
qCDebug(lcDeveloperModeLog) << "Device:" << device << "IP:" << entries[device];
307
308
309
}
}
310
void DeveloperModeSettings::refreshPackageCacheAndInstall()
312
m_refreshedForInstall = true;
314
315
// Soft refresh, do not clear & reload valid cache.
PackageKit::Transaction *refreshCache = PackageKit::Daemon::refreshCache(false);
316
317
318
connect(refreshCache, &PackageKit::Transaction::errorCode, this, &DeveloperModeSettings::reportTransactionErrorCode);
connect(refreshCache, &PackageKit::Transaction::finished,
this, [this](PackageKit::Transaction::Exit status, uint runtime) {
319
qCDebug(lcDeveloperModeLog) << "Package cache updated:" << status << runtime;
320
resolveAndExecute(InstallCommand); // trying again regardless of success, some repositories might be updated
324
void DeveloperModeSettings::resolveAndExecute(Command command)
326
setWorkStatus(Preparing);
327
m_workProgress = 0;
328
m_packageId.clear(); // might differ between installed/available
330
if (command == InstallCommand && !m_localInstallFailed && !m_localDeveloperModePackagePath.isEmpty() && m_installationType == DeveloperMode) {
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
// Resolve which version of developer mode package is expected
PackageKit::Transaction *resolvePackage = PackageKit::Daemon::resolve(DEVELOPER_MODE_PACKAGE"-preload", PackageKit::Transaction::FilterInstalled);
connect(resolvePackage, &PackageKit::Transaction::errorCode, this, &DeveloperModeSettings::reportTransactionErrorCode);
connect(resolvePackage, &PackageKit::Transaction::package,
this, [this](PackageKit::Transaction::Info info, const QString &packageID, const QString &summary) {
Q_UNUSED(summary)
Q_ASSERT(info == PackageKit::Transaction::InfoInstalled);
const QString version = PackageKit::Transaction::packageVersion(packageID);
m_localDeveloperModePackagePath = get_cached_package(version);
emit repositoryAccessRequiredChanged();
qCDebug(lcDeveloperModeLog) << "Preload package version: " << version << ", local package path: " << m_localDeveloperModePackagePath;
});
connect(resolvePackage, &PackageKit::Transaction::finished,
this, [this](PackageKit::Transaction::Exit status, uint runtime) {
Q_UNUSED(runtime)
if (status != PackageKit::Transaction::ExitSuccess || m_localDeveloperModePackagePath.isEmpty()) {
qCDebug(lcDeveloperModeLog) << "Preloaded package not found, must use remote package";
// No cached package => install from repos
resolveAndExecute(InstallCommand);
} else {
PackageKit::Transaction *tx = PackageKit::Daemon::installFiles(QStringList() << m_localDeveloperModePackagePath);
connectCommandSignals(tx);
connect(tx, &PackageKit::Transaction::finished,
this, [this](PackageKit::Transaction::Exit status, uint runtime) {
if (status == PackageKit::Transaction::ExitSuccess) {
qCDebug(lcDeveloperModeLog) << "Developer mode installation from local package transaction done:" << status << runtime;
resetState();
} else if (status == PackageKit::Transaction::ExitFailed) {
qCWarning(lcDeveloperModeLog) << "Developer mode installation from local package failed, trying from repos";
m_localInstallFailed = true;
emit repositoryAccessRequiredChanged();
resolveAndExecute(InstallCommand); // TODO: If repo access is not available this can not bail out
} // else ExitUnknown (ignored)
});
}
});
370
371
372
373
// Install package form repos
installAndRemove(command);
}
}
375
376
377
378
379
380
381
bool DeveloperModeSettings::installAndRemove(Command command)
{
if (packageName().isEmpty()) {
qCWarning(lcDeveloperModeLog) << "No installation package name set. Shouldn't happen.";
resetState();
return false;
}
383
384
385
386
387
388
PackageKit::Transaction::Filters filters;
if (command == RemoveCommand) {
filters = PackageKit::Transaction::FilterInstalled;
} else {
filters = PackageKit::Transaction::FilterNewest;
}
390
PackageKit::Transaction *resolvePackage = PackageKit::Daemon::resolve(packageName(), filters);
392
393
394
395
396
397
connect(resolvePackage, &PackageKit::Transaction::errorCode, this, &DeveloperModeSettings::reportTransactionErrorCode);
connect(resolvePackage, &PackageKit::Transaction::package,
this, [this](PackageKit::Transaction::Info info, const QString &packageId, const QString &summary) {
qCDebug(lcDeveloperModeLog) << "Package transaction:" << info << packageId << "summary:" << summary;
m_packageId = packageId;
});
399
400
401
402
403
404
connect(resolvePackage, &PackageKit::Transaction::finished,
this, [this, command](PackageKit::Transaction::Exit status, uint runtime) {
Q_UNUSED(runtime)
if (status != PackageKit::Transaction::ExitSuccess || m_packageId.isEmpty()) {
if (command == InstallCommand) {
405
if (m_refreshedForInstall) {
406
407
qCWarning(lcDeveloperModeLog) << "Failed to install, package didn't resolve.";
resetState();
409
refreshPackageCacheAndInstall(); // try once if it helps
411
412
413
414
415
416
417
418
419
420
} else if (command == RemoveCommand) {
qCWarning(lcDeveloperModeLog) << "Removing package but package didn't resolve into anything. Shouldn't happen.";
resetState();
}
} else if (command == InstallCommand) {
PackageKit::Transaction *tx = PackageKit::Daemon::installPackage(m_packageId);
connectCommandSignals(tx);
if (m_refreshedForInstall) {
421
422
connect(tx, &PackageKit::Transaction::finished,
this, [this](PackageKit::Transaction::Exit status, uint runtime) {
423
qCDebug(lcDeveloperModeLog) << "Installation transaction done (with refresh):" << status << runtime;
424
resetState();
426
427
428
429
430
431
432
433
434
435
436
} else {
connect(tx, &PackageKit::Transaction::finished,
this, [this](PackageKit::Transaction::Exit status, uint runtime) {
if (status == PackageKit::Transaction::ExitSuccess) {
qCDebug(lcDeveloperModeLog) << "Installation transaction done:" << status << runtime;
resetState();
} else {
qCDebug(lcDeveloperModeLog) << "Installation failed, trying again after refresh";
refreshPackageCacheAndInstall();
}
});
438
439
440
441
442
443
444
445
446
447
448
449
} else {
PackageKit::Transaction *tx = PackageKit::Daemon::removePackage(m_packageId, true, true);
connectCommandSignals(tx);
connect(tx, &PackageKit::Transaction::finished,
this, [this](PackageKit::Transaction::Exit status, uint runtime) {
qCDebug(lcDeveloperModeLog) << "Package removal transaction done:" << status << runtime;
resetState();
});
}
});
return true;
452
void DeveloperModeSettings::connectCommandSignals(PackageKit::Transaction *transaction)
454
connect(transaction, &PackageKit::Transaction::errorCode, this, &DeveloperModeSettings::reportTransactionErrorCode);
455
456
457
connect(transaction, &PackageKit::Transaction::percentageChanged, this, [this, transaction]() {
updateState(transaction->percentage(), m_transactionStatus, m_transactionRole);
});
459
connect(transaction, &PackageKit::Transaction::statusChanged, this, [this, transaction]() {
460
updateState(m_workProgress, transaction->status(), m_transactionRole);
463
connect(transaction, &PackageKit::Transaction::roleChanged, this, [this, transaction]() {
464
updateState(m_workProgress, m_transactionStatus, transaction->role());
468
void DeveloperModeSettings::updateState(int percentage, PackageKit::Transaction::Status status, PackageKit::Transaction::Role role)
470
// Expected changes from PackageKit when installing packages:
471
// 1. Change to 'install packages' role or 'install files' if installing from local package file
472
// 2. Status changes:
473
474
475
476
477
// setup -> refresh cache -> query -> resolve deps -> install (refer to as 'Preparing' status)
// -> download ('DownloadingPackages' status)
// -> install ('InstallingPackages' status)
// -> finished
//
478
479
// If installing from local package fails, it starts over!
//
480
// Expected changes from PackageKit when removing packages:
481
482
// 1. Change to 'remove packages' role
// 2. Status changes:
483
484
485
486
487
488
// setup -> remove -> resolve deps (refer to as 'Preparing' status)
// -> remove ('RemovingPackages' status)
// -> finished
//
// Notice the 'install' and 'remove' packagekit status changes occur twice.
489
490
int progress = m_workProgress;
DeveloperModeSettings::Status workStatus = m_workStatus;
492
493
m_transactionRole = role;
m_transactionStatus = status;
495
496
497
498
499
500
// Do not update progress when finished or role is unknown.
if (m_transactionStatus == PackageKit::Transaction::StatusFinished
|| m_transactionRole == PackageKit::Transaction::RoleUnknown) {
return;
}
501
if (percentage >= 0 && percentage <= 100) {
502
503
int rangeStart = 0;
int rangeEnd = 0;
504
505
if (m_transactionRole == PackageKit::Transaction::RoleInstallPackages
|| m_transactionRole == PackageKit::Transaction::RoleInstallFiles) {
506
switch (m_transactionStatus) {
507
case PackageKit::Transaction::StatusRefreshCache: // 0-10 %
508
509
510
rangeStart = 0;
rangeEnd = 10;
break;
511
512
case PackageKit::Transaction::StatusQuery: // fall through; packagekit progress changes 0-100 over query->resolve stages
case PackageKit::Transaction::StatusDepResolve: // 10-20 %
513
514
515
rangeStart = 10;
rangeEnd = 20;
break;
516
case PackageKit::Transaction::StatusDownload: // 20-60 %
517
518
519
520
// Skip downloading when installing from local file
if (m_transactionRole != PackageKit::Transaction::RoleInstallFiles) {
workStatus = DownloadingPackages;
}
521
522
523
rangeStart = 20;
rangeEnd = 60;
break;
524
case PackageKit::Transaction::StatusInstall: // 60-100 %
525
workStatus = InstallingPackages;
526
527
rangeStart = 60;
rangeEnd = 100;
528
529
530
break;
default:
break;
532
533
534
} else if (m_transactionRole == PackageKit::Transaction::RoleRemovePackages) {
if (m_transactionStatus == PackageKit::Transaction::StatusSetup) {
// Let the setup to be bound between 0-20 %
535
536
537
rangeStart = 0;
rangeEnd = 20;
} else { // 20-100 %
538
workStatus = RemovingPackages;
539
540
rangeStart = 20;
rangeEnd = 100;
543
if (rangeEnd > 0 && rangeEnd > rangeStart) {
544
progress = rangeStart + ((rangeEnd - rangeStart) * (percentage / 100.0));
548
progress = qBound(0, qMax(progress, m_workProgress), 100); // Ensure the emitted progress value never decreases.
550
551
552
553
554
setWorkStatus(workStatus);
if (m_workProgress != progress) {
m_workProgress = progress;
emit workProgressChanged();
558
void DeveloperModeSettings::resetState()
560
561
562
563
564
565
566
567
568
569
570
if (m_installationType == DeveloperMode) {
bool enabled = QFile::exists(DEVELOPER_MODE_PROVIDED_FILE);
if (m_developerModeEnabled != enabled) {
m_developerModeEnabled = enabled;
emit developerModeEnabledChanged();
}
} else if (m_installationType == DebugHome) {
if (m_debugHomeEnabled != debugHomeFolderExists()) {
m_debugHomeEnabled = debugHomeFolderExists();
emit debugHomeEnabledChanged();
}
573
setWorkStatus(Idle);
574
setInstallationType(None);
576
577
578
579
580
if (m_workProgress != PROGRESS_INDETERMINATE) {
m_workProgress = PROGRESS_INDETERMINATE;
emit workProgressChanged();
}
}
582
583
584
585
586
void DeveloperModeSettings::setWorkStatus(DeveloperModeSettings::Status status)
{
if (m_workStatus != status) {
m_workStatus = status;
emit workStatusChanged();
588
589
590
591
592
}
void DeveloperModeSettings::reportTransactionErrorCode(PackageKit::Transaction::Error code, const QString &details)
{
qCWarning(lcDeveloperModeLog) << "Transaction error:" << code << details;
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
QString DeveloperModeSettings::usbModedGetConfig(const QString &key, const QString &fallback)
{
QString value = fallback;
QDBusMessage msg = m_usbModeDaemon.call(USB_MODED_GET_NET_CONFIG, key);
QList<QVariant> result = msg.arguments();
if (result[0].toString() == key && result.size() == 2) {
value = result[1].toString();
}
return value;
}
void DeveloperModeSettings::usbModedSetConfig(const QString &key, const QString &value)
{
m_usbModeDaemon.call(USB_MODED_SET_NET_CONFIG, key, value);
}