Skip to content

Commit 6525cb7

Browse files
reddevillgdengbo11
authored andcommitted
fix: fix regression by 9937c54
ReplyInteraction signal may lost if Task object is not ready. Move it from per-task interface to the PackageManager1 interface. Add syncTaskProperties to fetch initial task state also. Signed-off-by: reddevillg <reddevillg@gmail.com>
1 parent 6b93bf2 commit 6525cb7

10 files changed

Lines changed: 207 additions & 146 deletions

File tree

api/dbus/org.deepin.linglong.PackageManager1.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ SPDX-License-Identifier: LGPL-3.0-or-later
6767
<arg direction="in" name="parameters" type="a{sv}" />
6868
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QVariantMap" />
6969
</method>
70+
<method name="ReplyInteraction">
71+
<arg direction="in" name="task" type="o" />
72+
<arg direction="in" name="replies" type="a{sv}" />
73+
<annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="QVariantMap" />
74+
</method>
7075
<property name="Configuration" type="a{sv}" access="read">
7176
<annotation name="org.qtproject.QtDBus.QtTypeName" value="QVariantMap" />
7277
</property>
@@ -76,5 +81,11 @@ SPDX-License-Identifier: LGPL-3.0-or-later
7681
<signal name="TaskRemoved">
7782
<arg name="task" type="o" />
7883
</signal>
84+
<signal name="RequestInteraction">
85+
<arg name="task" type="o" />
86+
<arg name="messageID" type="i" />
87+
<arg name="additionalMessage" type="a{sv}" />
88+
<annotation name="org.qtproject.QtDBus.QtTypeName.Out2" value="QVariantMap" />
89+
</signal>
7990
</interface>
8091
</node>

api/dbus/org.deepin.linglong.Task1.xml

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,9 @@ SPDX-License-Identifier: LGPL-3.0-or-later
77
<node>
88
<interface name="org.deepin.linglong.Task1">
99
<method name="Cancel" />
10-
<method name="ReplyInteraction">
11-
<arg direction="in" name="replies" type="a{sv}" />
12-
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QVariantMap" />
13-
</method>
1410
<property name="State" type="i" access="read" />
1511
<property name="Percentage" type="d" access="read" />
1612
<property name="Message" type="s" access="read" />
1713
<property name="Code" type="i" access="read" />
18-
<signal name="RequestInteraction">
19-
<arg name="messageID" type="i" />
20-
<arg name="additionalMessage" type="a{sv}" />
21-
<annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="QVariantMap" />
22-
</signal>
2314
</interface>
2415
</node>

libs/linglong/src/linglong/cli/cli.cpp

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@
5151
#include <linux/un.h>
5252
#include <nlohmann/json.hpp>
5353

54+
#include <QDBusInterface>
55+
#include <QDBusReply>
5456
#include <QEventLoop>
5557
#include <QFileInfo>
5658
#include <QProcess>
@@ -293,9 +295,14 @@ void Cli::onTaskPropertiesChanged(
293295
handleTaskState();
294296
}
295297

296-
void Cli::onTaskRequestInteraction(int messageID, const QVariantMap &additionalMessage)
298+
void Cli::interaction(const QDBusObjectPath &object_path,
299+
int messageID,
300+
const QVariantMap &additionalMessage)
297301
{
298302
LINGLONG_TRACE("interactive with user")
303+
if (object_path.path() != taskObjectPath) {
304+
return;
305+
}
299306

300307
auto messageType = static_cast<api::types::v1::InteractionMessageType>(messageID);
301308
auto msg = common::serialize::fromQVariantMap<
@@ -346,13 +353,14 @@ void Cli::onTaskRequestInteraction(int messageID, const QVariantMap &additionalM
346353
LogD("action: {}", action);
347354

348355
auto reply = api::types::v1::InteractionReply{ .action = action };
349-
if (!this->task) {
350-
this->printer.printErr(LINGLONG_ERRV("task object is null"));
356+
auto pkgMan = this->getPkgMan();
357+
if (!pkgMan) {
358+
this->printer.printErr(pkgMan.error());
351359
return;
352360
}
353361

354362
QDBusPendingReply<void> dbusReply =
355-
this->task->ReplyInteraction(common::serialize::toQVariantMap(reply));
363+
(*pkgMan)->ReplyInteraction(object_path, common::serialize::toQVariantMap(reply));
356364
dbusReply.waitForFinished();
357365
if (dbusReply.isError()) {
358366
this->printer.printErr(
@@ -535,7 +543,7 @@ utils::error::Result<void> Cli::initPkgManSignals()
535543
if (!conn.connect(pkgMan->service(),
536544
pkgMan->path(),
537545
pkgMan->interface(),
538-
"TaskAdd",
546+
"TaskAdded",
539547
this,
540548
SLOT(onTaskAdded(QDBusObjectPath)))) {
541549
return LINGLONG_ERR("couldn't connect to package manager signal 'TaskAdded'");
@@ -550,6 +558,16 @@ utils::error::Result<void> Cli::initPkgManSignals()
550558
return LINGLONG_ERR("couldn't connect to package manager signal 'TaskRemoved'");
551559
}
552560

561+
if (!conn.connect(pkgMan->service(),
562+
pkgMan->path(),
563+
pkgMan->interface(),
564+
"RequestInteraction",
565+
this,
566+
SLOT(interaction(QDBusObjectPath, int, QVariantMap)))) {
567+
return LINGLONG_ERR(fmt::format("Failed to connect signal RequestInteraction: {}",
568+
conn.lastError().message().toStdString()));
569+
}
570+
553571
this->pkgManSignalsInitialized = true;
554572
return LINGLONG_OK;
555573
}
@@ -2246,6 +2264,30 @@ int Cli::getBundleDir(const InspectOptions &options)
22462264
return 0;
22472265
}
22482266

2267+
utils::error::Result<void> Cli::syncTaskProperties()
2268+
{
2269+
LINGLONG_TRACE("syncTaskProperties");
2270+
2271+
auto pkgMan = this->getPkgMan();
2272+
if (!pkgMan) {
2273+
return LINGLONG_ERR(pkgMan);
2274+
}
2275+
2276+
QDBusInterface properties((*pkgMan)->service(),
2277+
this->taskObjectPath,
2278+
"org.freedesktop.DBus.Properties",
2279+
(*pkgMan)->connection());
2280+
QDBusReply<QVariantMap> reply =
2281+
properties.call("GetAll", QStringLiteral("org.deepin.linglong.Task1"));
2282+
if (!reply.isValid()) {
2283+
return LINGLONG_ERR(
2284+
fmt::format("failed to get task properties: {}", reply.error().message().toStdString()));
2285+
}
2286+
2287+
this->onTaskPropertiesChanged(QStringLiteral("org.deepin.linglong.Task1"), reply.value(), {});
2288+
return LINGLONG_OK;
2289+
}
2290+
22492291
utils::error::Result<void> Cli::waitTaskCreated(QDBusPendingReply<QVariantMap> &reply,
22502292
TaskType taskType)
22512293
{
@@ -2285,21 +2327,17 @@ utils::error::Result<void> Cli::waitTaskCreated(QDBusPendingReply<QVariantMap> &
22852327
conn.lastError().message().toStdString()));
22862328
}
22872329

2288-
if (!conn.connect((*pkgMan)->service(),
2289-
taskObjectPath,
2290-
"org.deepin.linglong.Task1",
2291-
"RequestInteraction",
2292-
this,
2293-
SLOT(onTaskRequestInteraction(int, QVariantMap)))) {
2294-
return LINGLONG_ERR(fmt::format("Failed to connect signal RequestInteraction: {}",
2295-
conn.lastError().message().toStdString()));
2296-
}
2297-
2298-
return LINGLONG_OK;
2330+
return this->syncTaskProperties();
22992331
}
23002332

23012333
void Cli::waitTaskDone()
23022334
{
2335+
if (this->taskState.state == api::types::v1::State::Failed
2336+
|| this->taskState.state == api::types::v1::State::Canceled
2337+
|| this->taskState.state == api::types::v1::State::Succeed) {
2338+
return;
2339+
}
2340+
23032341
QEventLoop loop;
23042342
if (QObject::connect(this, &Cli::taskDone, &loop, &QEventLoop::quit) == nullptr) {
23052343
LogE("connect taskDone failed");

libs/linglong/src/linglong/cli/cli.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ class Cli : public QObject
229229
void detectDrivers();
230230
utils::error::Result<api::dbus::v1::PackageManager *> getPkgMan();
231231
utils::error::Result<void> initPkgManSignals();
232+
utils::error::Result<void> syncTaskProperties();
232233
int runResolvedContext(runtime::RunContext &runContext,
233234
const RunOptions &options,
234235
std::optional<api::types::v1::RuntimeConfigure> runtimeConfig);
@@ -272,7 +273,9 @@ private Q_SLOTS:
272273
void onTaskPropertiesChanged(const QString &interface,
273274
const QVariantMap &changed_properties,
274275
const QStringList &invalidated_properties);
275-
void onTaskRequestInteraction(int messageID, const QVariantMap &additionalMessage);
276+
void interaction(const QDBusObjectPath &object_path,
277+
int messageID,
278+
const QVariantMap &additionalMessage);
276279

277280
Q_SIGNALS:
278281
void taskDone();

libs/linglong/src/linglong/package_manager/package_manager.cpp

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "configure.h"
1010
#include "linglong/api/types/helper.h"
1111
#include "linglong/api/types/v1/Generators.hpp" // IWYU pragma: keep
12+
#include "linglong/api/types/v1/InteractionReply.hpp"
1213
#include "linglong/api/types/v1/PackageInfoV2.hpp"
1314
#include "linglong/api/types/v1/PackageManager1JobInfo.hpp"
1415
#include "linglong/api/types/v1/PackageManager1PruneResult.hpp"
@@ -45,12 +46,14 @@
4546

4647
#include <QDBusInterface>
4748
#include <QDBusReply>
49+
#include <QDBusServiceWatcher>
4850
#include <QDBusUnixFileDescriptor>
4951
#include <QEventLoop>
5052
#include <QMetaObject>
5153
#include <QTimer>
5254

5355
#include <algorithm>
56+
#include <chrono>
5457
#include <cstdint>
5558
#include <functional>
5659
#include <unordered_map>
@@ -655,7 +658,7 @@ QVariantMap PackageManager::installFromLayer(const QDBusUnixFileDescriptor &fd,
655658
PackageTask &taskRef = dynamic_cast<PackageTask &>(task);
656659
if (msgType == api::types::v1::InteractionMessageType::Upgrade
657660
&& !options.skipInteraction) {
658-
if (!taskRef.waitConfirm(msgType, additionalMessage)) {
661+
if (!this->waitConfirm(taskRef, msgType, additionalMessage)) {
659662
return;
660663
}
661664
}
@@ -1887,6 +1890,117 @@ auto PackageManager::InitRunContext(const QString &runContextCfg,
18871890
});
18881891
}
18891892

1893+
void PackageManager::ReplyInteraction(QDBusObjectPath object_path, const QVariantMap &replies)
1894+
{
1895+
Q_EMIT this->ReplyReceived(object_path, replies);
1896+
}
1897+
1898+
void PackageManager::onPeerDisconnected() noexcept
1899+
{
1900+
LogW("peer caller disconnected");
1901+
Q_EMIT CallerDisconnected();
1902+
}
1903+
1904+
bool PackageManager::waitConfirm(
1905+
PackageTask &taskRef,
1906+
api::types::v1::InteractionMessageType msgType,
1907+
const api::types::v1::PackageManager1RequestInteractionAdditionalMessage
1908+
&additionalMessage) noexcept
1909+
{
1910+
auto objectPath = QDBusObjectPath(taskRef.taskObjectPath().c_str());
1911+
QEventLoop loop;
1912+
QTimer timeoutTimer;
1913+
timeoutTimer.setSingleShot(true);
1914+
1915+
auto callerContext = taskRef.callerContext();
1916+
std::unique_ptr<QDBusServiceWatcher> watcher;
1917+
1918+
QMetaObject::Connection callerDisconnectedConn;
1919+
1920+
if (callerContext.isPeerMode()) {
1921+
callerDisconnectedConn =
1922+
connect(this, &PackageManager::CallerDisconnected, &loop, [&taskRef, &loop]() {
1923+
taskRef.updateState(linglong::api::types::v1::State::Canceled, "caller disconnected");
1924+
loop.exit(1);
1925+
});
1926+
1927+
auto connected = callerContext.connection.connect("",
1928+
"/org/freedesktop/DBus/Local",
1929+
"org.freedesktop.DBus.Local",
1930+
"Disconnected",
1931+
this,
1932+
SLOT(onPeerDisconnected()));
1933+
if (!connected) {
1934+
LogW("failed to connect to Disconnected signal for peer mode");
1935+
}
1936+
} else {
1937+
auto callerName = callerContext.callerBusName();
1938+
if (!callerName.isEmpty()) {
1939+
watcher =
1940+
std::make_unique<QDBusServiceWatcher>(callerName,
1941+
callerContext.connection,
1942+
QDBusServiceWatcher::WatchForUnregistration);
1943+
connect(watcher.get(),
1944+
&QDBusServiceWatcher::serviceUnregistered,
1945+
&loop,
1946+
[&taskRef, &loop, callerName]() {
1947+
LogW("caller {} disconnected", callerName.toStdString());
1948+
taskRef.updateState(linglong::api::types::v1::State::Canceled,
1949+
"caller disconnected");
1950+
loop.exit(1);
1951+
});
1952+
}
1953+
}
1954+
1955+
auto replyConn =
1956+
connect(this,
1957+
&PackageManager::ReplyReceived,
1958+
&loop,
1959+
[&taskRef, &loop, objectPath](const QDBusObjectPath &replyObjectPath,
1960+
const QVariantMap &reply) {
1961+
if (replyObjectPath.path() != objectPath.path()) {
1962+
return;
1963+
}
1964+
1965+
auto interactionReply =
1966+
common::serialize::fromQVariantMap<api::types::v1::InteractionReply>(reply);
1967+
if (!interactionReply || interactionReply->action != "yes") {
1968+
taskRef.updateState(linglong::api::types::v1::State::Canceled, "canceled");
1969+
}
1970+
loop.exit(0);
1971+
});
1972+
1973+
auto timeoutConn = connect(&timeoutTimer, &QTimer::timeout, &loop, [&taskRef, &loop]() {
1974+
auto msg = fmt::format("task {} confirm timeout", taskRef.taskID());
1975+
LogW(msg);
1976+
taskRef.updateState(linglong::api::types::v1::State::Canceled, msg);
1977+
loop.exit(1);
1978+
});
1979+
1980+
Q_EMIT RequestInteraction(objectPath,
1981+
static_cast<int>(msgType),
1982+
common::serialize::toQVariantMap(additionalMessage));
1983+
1984+
timeoutTimer.start(std::chrono::milliseconds{ 180000 });
1985+
loop.exec();
1986+
timeoutTimer.stop();
1987+
1988+
disconnect(replyConn);
1989+
disconnect(timeoutConn);
1990+
disconnect(callerDisconnectedConn);
1991+
1992+
if (callerContext.isPeerMode()) {
1993+
callerContext.connection.disconnect("",
1994+
"/org/freedesktop/DBus/Local",
1995+
"org.freedesktop.DBus.Local",
1996+
"Disconnected",
1997+
this,
1998+
SLOT(onPeerDisconnected()));
1999+
}
2000+
2001+
return !taskRef.isTaskDone();
2002+
}
2003+
18902004
// no-op for now
18912005
utils::error::Result<void> PackageManager::tryGenerateCache(const package::Reference &ref) noexcept
18922006
{

libs/linglong/src/linglong/package_manager/package_manager.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
#include "linglong/api/types/v1/CommonOptions.hpp"
1010
#include "linglong/api/types/v1/ContainerProcessStateInfo.hpp"
11+
#include "linglong/api/types/v1/InteractionMessageType.hpp"
12+
#include "linglong/api/types/v1/PackageManager1RequestInteractionAdditionalMessage.hpp"
1113
#include "linglong/api/types/v1/Repo.hpp"
1214
#include "linglong/api/types/v1/UabLayer.hpp"
1315
#include "linglong/package/fuzzy_reference.h"
@@ -20,6 +22,7 @@
2022
#include <QDBusArgument>
2123
#include <QDBusConnection>
2224
#include <QDBusContext>
25+
#include <QDBusObjectPath>
2326
#include <QList>
2427
#include <QObject>
2528

@@ -58,6 +61,7 @@ public
5861
auto Update(const QVariantMap &parameters) noexcept -> QVariantMap;
5962
auto Search(const QVariantMap &parameters) noexcept -> QVariantMap;
6063
auto Prune() noexcept -> QVariantMap;
64+
void ReplyInteraction(QDBusObjectPath object_path, const QVariantMap &replies);
6165

6266
auto InitRunContext(const QString &runContextCfg, const QString &containerID) noexcept
6367
-> QVariantMap;
@@ -73,6 +77,10 @@ public
7377
virtual utils::error::Result<void> tryGenerateCache(const package::Reference &ref) noexcept;
7478
utils::error::Result<void> executePostInstallHooks(const package::Reference &ref) noexcept;
7579
utils::error::Result<void> executePostUninstallHooks(const package::Reference &ref) noexcept;
80+
bool waitConfirm(PackageTask &taskRef,
81+
api::types::v1::InteractionMessageType msgType,
82+
const api::types::v1::PackageManager1RequestInteractionAdditionalMessage
83+
&additionalMessage) noexcept;
7684

7785
virtual utils::error::Result<void> installAppDepends(Task &task,
7886
const api::types::v1::PackageInfoV2 &app);
@@ -107,9 +115,17 @@ public
107115
Q_SIGNALS:
108116
void TaskAdded(QDBusObjectPath object_path);
109117
void TaskRemoved(QDBusObjectPath object_path);
118+
void RequestInteraction(QDBusObjectPath object_path,
119+
int messageID,
120+
QVariantMap additionalMessage);
121+
void CallerDisconnected();
110122
void SearchFinished(QString jobID, QVariantMap result);
111123
void PruneFinished(QString jobID, QVariantMap result);
112124
void InitRunContextFinished(QString jobID, bool success);
125+
void ReplyReceived(QDBusObjectPath object_path, const QVariantMap &replies);
126+
127+
private Q_SLOTS:
128+
void onPeerDisconnected() noexcept;
113129

114130
private:
115131
QVariantMap installFromLayer(const QDBusUnixFileDescriptor &fd,

0 commit comments

Comments
 (0)