fix: 尝试修复 ISSUE #I68I8W 安装结束时随机崩溃问题

暂时未知,目前怀疑安装结束后,DownloadItem 触发 finished() 信号,在详情页槽函数中执行 disconnect 操作时导致崩溃

Log: 去除 disconnect 操作;修改可能造成问题的控件指针获取方式;修复多线程执行下载安装操作时跨线程相关警告

* 该提交可能存在严重问题,建议多进行测试;如果存在问题,及时 revert 该提交
This commit is contained in:
zty199 2023-02-03 01:35:15 +08:00
parent eaf268a10d
commit cb093dcc2b
7 changed files with 163 additions and 123 deletions

@ -145,17 +145,19 @@ void DownloadController::startDownload(const QString &url)
command.append(aria2NoSeeds.toUtf8());
}
qDebug() << command;
auto cmd = new QProcess(this);
cmd->setProcessChannelMode(QProcess::MergedChannels);
cmd->setProgram("aria2c");
cmd->setArguments(command);
cmd->start();
cmd->waitForStarted(); //等待启动完成
QObject::connect(cmd, &QProcess::readyReadStandardOutput, [&]()
bool downloadSuccess = true;
QProcess cmd;
cmd.setProcessChannelMode(QProcess::MergedChannels);
cmd.setProgram("aria2c");
cmd.setArguments(command);
cmd.start();
cmd.waitForStarted(-1); //等待启动完成
connect(&cmd, &QProcess::readyReadStandardOutput, [&]()
{
//通过读取输出计算下载速度
QString message = cmd->readAllStandardOutput().data();
QString message = cmd.readAllStandardOutput().data();
// qDebug() << message;
message = message.replace(" ", "");
QStringList list;
@ -195,17 +197,21 @@ void DownloadController::startDownload(const QString &url)
emit downloadProcess(speedInfo, downloadSizeRecord, fileSize);
}
});
QObject::connect(cmd, &QProcess::readyReadStandardError, [&]()
connect(&cmd, &QProcess::readyReadStandardError, [&]()
{
emit errorOccur(cmd->readAllStandardError().data());
return;
emit errorOccur(cmd.readAllStandardError().data());
downloadSuccess = false;
cmd.close();
});
auto pidNumber = cmd->processId();
this->pidNumber = pidNumber;
while (cmd->waitForFinished(-1))
pidNumber = cmd.processId();
cmd.waitForFinished(-1);
cmd.close();
if(!downloadSuccess)
{
continue;
return;
}
// 统计下载量
@ -218,7 +224,7 @@ void DownloadController::startDownload(const QString &url)
mailProcess.start(SenderdPath.toUtf8(), QStringList() << metaUrl << "HD70642");
mailProcess.waitForStarted();
mailProcess.waitForFinished(3000);
mailProcess.deleteLater();
mailProcess.close();
emit downloadFinished(); });
}

@ -21,7 +21,7 @@ public:
private:
int threadNum;
int pidNumber = -1;
qint64 pidNumber = -1;
QString filename;
qint64 fileSize;
QVector<QPair<qint64, qint64>> ranges;

@ -291,34 +291,39 @@ void AppIntoPage::initConnections()
void AppIntoPage::isDownloading(const QUrl &url)
{
if (dw->getUrlList().lastIndexOf(url) == -1)
int index = dw->getUrlList().lastIndexOf(url);
if (index == -1)
{
ui->downloadButton->setEnabled(true);
return;
}
else
DownloadItem *item = dw->getDIList().at(index);
if (item == nullptr)
{
ui->downloadButton->setEnabled(false);
ui->downloadButton->setEnabled(true);
return;
}
ui->downloadButton->setEnabled(false);
ui->pushButton_3->hide();
if (dw->getDIList()[dw->getUrlList().lastIndexOf(url)]->download == 2)
if (item->download == 2)
{
ui->downloadButton->setEnabled(true);
ui->downloadButton->setText(tr("Download"));
}
if (dw->getDIList()[dw->getUrlList().lastIndexOf(url)]->download == 1)
if (item->download == 1)
{
ui->downloadButton->setEnabled(true);
ui->downloadButton->setText(tr("Install"));
}
if (dw->getDIList()[dw->getUrlList().lastIndexOf(url)]->isInstall)
if (item->isInstall)
{
ui->downloadButton->setEnabled(false);
ui->downloadButton->setText(tr("Installing"));
return;
}
if (dw->getDIList()[dw->getUrlList().lastIndexOf(url)]->download == 3)
if (item->download == 3)
{
ui->downloadButton->setEnabled(true);
ui->downloadButton->setText(tr("Reinstall"));
@ -368,32 +373,39 @@ void AppIntoPage::setAppinfoTags(const QStringList &tagList)
void AppIntoPage::on_downloadButton_clicked()
{
QString downloadUrl = SparkAPI::getServerUrl() + "store" + spk.path() + "/" + info["Filename"].toString();
if (ui->downloadButton->text() == tr("Install"))
{
dw->getDIList()[dw->getUrlList().lastIndexOf(SparkAPI::getServerUrl() + "store" + spk.path() + "/" + info["Filename"].toString())]->install(0);
isDownloading(SparkAPI::getServerUrl() + "store" + spk.path() + "/" + info["Filename"].toString());
connect(dw->getDIList()[dw->getUrlList().lastIndexOf(SparkAPI::getServerUrl() + "store" + spk.path() + "/" + info["Filename"].toString())], &DownloadItem::finished, [=]()
{
isDownloading(SparkAPI::getServerUrl() + "store" + spk.path() + "/" + info["Filename"].toString());
disconnect(dw->getDIList()[dw->getUrlList().lastIndexOf(SparkAPI::getServerUrl() + "store" + spk.path() + "/" + info["Filename"].toString())], &DownloadItem::finished, nullptr, nullptr); });
DownloadItem *item = dw->getDIList()[dw->getUrlList().lastIndexOf(downloadUrl)];
if (item == nullptr)
{
return;
}
connect(item, &DownloadItem::finished, [=]() { isDownloading(downloadUrl); });
item->install(0);
isDownloading(downloadUrl);
return;
}
emit clickedDownloadBtn();
dw->addItem(info["Name"].toString(), info["Filename"].toString(), info["Pkgname"].toString(), iconpixmap, SparkAPI::getServerUrl() + "store" + spk.path() + "/" + info["Filename"].toString());
DownloadItem *item = dw->addItem(info["Name"].toString(), info["Filename"].toString(), info["Pkgname"].toString(), iconpixmap, downloadUrl);
if (item == nullptr)
{
return;
}
if (ui->downloadButton->text() == tr("Reinstall"))
{
dw->getDIList()[dw->allDownload - 1]->reinstall = true;
item->reinstall = true;
}
ui->downloadButton->setEnabled(false);
connect(dw->getDIList()[dw->getUrlList().lastIndexOf(SparkAPI::getServerUrl() + "store" + spk.path() + "/" + info["Filename"].toString())], &DownloadItem::finished, [=]()
{
isDownloading(SparkAPI::getServerUrl() + "store" + spk.path() + "/" + info["Filename"].toString());
disconnect(dw->getDIList()[dw->getUrlList().lastIndexOf(SparkAPI::getServerUrl() + "store" + spk.path() + "/" + info["Filename"].toString())], &DownloadItem::finished, nullptr, nullptr); });
connect(item, &DownloadItem::finished, [=]() { isDownloading(downloadUrl); });
isDownloading(SparkAPI::getServerUrl() + "store" + spk.path() + "/" + info["Filename"].toString());
isDownloading(downloadUrl);
}
void AppIntoPage::on_pushButton_3_clicked()

@ -105,76 +105,10 @@ void DownloadItem::install(int t)
ui->label_2->setToolTip(tr("Installing"));
QtConcurrent::run([=]()
{
QProcess installer;
switch(t)
{
case 0:
installer.start("pkexec", QStringList() << "ssinstall" << "/tmp/spark-store/" + ui->label_filename->text().toUtf8());
break;
case 1:
installer.start("deepin-deb-installer", QStringList() << "/tmp/spark-store/" + ui->label_filename->text().toUtf8());
break;
case 2:
installer.start("pkexec", QStringList() << "gdebi" << "-n" << "/tmp/spark-store/" + ui->label_filename->text().toUtf8());
break;
}
{
slotAsyncInstall(t);
});
bool haveError = false;
bool notRoot = false;
installer.waitForFinished(-1); // 不设置超时
out = installer.readAllStandardOutput();
QStringList everyOut = out.split("\n");
for (int i = 0; i < everyOut.size(); i++)
{
if(everyOut[i].left(2) == "E:")
{
haveError = true;
}
if(everyOut[i].right(14) == "Not authorized")
{
notRoot = true;
}
}
QProcess isInstall;
isInstall.start("dpkg", QStringList() << "-s" << pkgName);
isInstall.waitForFinished(180*1000); // 默认超时 3 分钟
int error = QString::fromStdString(isInstall.readAllStandardError().toStdString()).length();
if (error == 0 && !haveError)
{
ui->pushButton_install->hide();
Utils::sendNotification("spark-store",tr("Spark Store"),ui->label->text() + " " + tr("Installation complete."));
ui->label_2->setText(tr("Finish"));
ui->label_2->setToolTip(tr("Finish"));
download = 3;
ui->pushButton_3->show();
}
else
{
ui->pushButton_install->show();
ui->pushButton_install->setText(tr("Retry"));
download = 1;
Utils::sendNotification("spark-store",tr("Spark Store"),tr("Error happened in dpkg progress , you can try it again."));
ui->label_2->setText(tr("Error happened in dpkg progress , you can try it again"));
ui->label_2->setToolTip(tr("Error happened in dpkg progress , you can try it again"));
ui->pushButton_3->show();
}
if (notRoot)
{
Utils::sendNotification("spark-store",tr("Spark Store"),tr("dpkg progress had been abortedyou can retry installation."));
ui->label_2->setText(tr("dpkg progress had been abortedyou can retry installation"));
ui->label_2->setToolTip(tr("dpkg progress had been abortedyou can retry installation"));
ui->pushButton_install->show();
ui->pushButton_3->hide();
}
ui->widget_spinner->hide();
DownloadItem::isInstall = false;
emit finished(); });
// emit finished();
qDebug() << ui->label_filename->text().toUtf8();
}
}
@ -207,3 +141,75 @@ void DownloadItem::on_pushButton_3_clicked()
output_w->layout()->addWidget(textbrowser);
output_w->show();
}
void DownloadItem::slotAsyncInstall(int t)
{
QProcess installer;
switch(t)
{
case 0:
installer.start("pkexec", QStringList() << "ssinstall" << "/tmp/spark-store/" + ui->label_filename->text().toUtf8());
break;
case 1:
installer.start("deepin-deb-installer", QStringList() << "/tmp/spark-store/" + ui->label_filename->text().toUtf8());
break;
case 2:
installer.start("pkexec", QStringList() << "gdebi" << "-n" << "/tmp/spark-store/" + ui->label_filename->text().toUtf8());
break;
}
bool haveError = false;
bool notRoot = false;
installer.waitForFinished(-1); // 不设置超时
out = installer.readAllStandardOutput();
QStringList everyOut = out.split("\n");
for (int i = 0; i < everyOut.size(); i++)
{
if(everyOut[i].left(2) == "E:")
{
haveError = true;
}
if(everyOut[i].right(14) == "Not authorized")
{
notRoot = true;
}
}
QProcess isInstall;
isInstall.start("dpkg", QStringList() << "-s" << pkgName);
isInstall.waitForFinished(180*1000); // 默认超时 3 分钟
int error = QString::fromStdString(isInstall.readAllStandardError().toStdString()).length();
if (error == 0 && !haveError)
{
ui->pushButton_install->hide();
Utils::sendNotification("spark-store",tr("Spark Store"),ui->label->text() + " " + tr("Installation complete."));
ui->label_2->setText(tr("Finish"));
ui->label_2->setToolTip(tr("Finish"));
download = 3;
ui->pushButton_3->show();
}
else
{
ui->pushButton_install->show();
ui->pushButton_install->setText(tr("Retry"));
download = 1;
Utils::sendNotification("spark-store",tr("Spark Store"),tr("Error happened in dpkg progress , you can try it again."));
ui->label_2->setText(tr("Error happened in dpkg progress , you can try it again"));
ui->label_2->setToolTip(tr("Error happened in dpkg progress , you can try it again"));
ui->pushButton_3->show();
}
if (notRoot)
{
Utils::sendNotification("spark-store",tr("Spark Store"),tr("dpkg progress had been abortedyou can retry installation."));
ui->label_2->setText(tr("dpkg progress had been abortedyou can retry installation"));
ui->label_2->setToolTip(tr("dpkg progress had been abortedyou can retry installation"));
ui->pushButton_install->show();
ui->pushButton_3->hide();
}
ui->widget_spinner->hide();
DownloadItem::isInstall = false;
emit finished();
}

@ -59,6 +59,8 @@ private slots:
void on_pushButton_2_clicked();
void on_pushButton_3_clicked();
void slotAsyncInstall(int t);
signals:
void finished();
};

@ -54,36 +54,42 @@ DownloadListWidget::~DownloadListWidget()
{
if (downloadController)
{
downloadController->disconnect();
downloadController->stopDownload();
downloadController->deleteLater();
}
clearItem();
delete ui;
}
void DownloadListWidget::clearItem()
{
ui->listWidget->vScrollBar->scrollTop();
int n = ui->listWidget->count();
for (int i = 0; i < n; i++)
{
QListWidgetItem *item = ui->listWidget->takeItem(0);
QWidget *card = ui->listWidget->itemWidget(item);
delete card;
card = NULL;
delete item;
item = NULL;
}
// QListWidgetItem *item = nullptr;
// while ((item = ui->listWidget->takeItem(0)) != nullptr)
// {
// QWidget *card = ui->listWidget->itemWidget(item);
// if (card)
// {
// card->deleteLater();
// card = nullptr;
// }
// delete item;
// item = nullptr;
// }
// ui->listWidget->vScrollBar->scrollTop();
ui->listWidget->clear();
}
void DownloadListWidget::addItem(QString name, QString fileName, QString pkgName, const QPixmap icon, QString downloadurl)
DownloadItem* DownloadListWidget::addItem(QString name, QString fileName, QString pkgName, const QPixmap icon, QString downloadurl)
{
if (fileName.isEmpty())
{
return;
return nullptr;
}
urList.append(downloadurl);
allDownload += 1;
DownloadItem *di = new DownloadItem(this);
DownloadItem *di = new DownloadItem;
dlist << downloadurl;
downloaditemlist << di;
di->setName(name);
@ -99,6 +105,8 @@ void DownloadListWidget::addItem(QString name, QString fileName, QString pkgName
nowDownload += 1;
startRequest(urList.at(nowDownload - 1), fileName); // 进行链接请求
}
return di;
}
QList<DownloadItem *> DownloadListWidget::getDIList()
@ -119,7 +127,13 @@ void DownloadListWidget::startRequest(QUrl url, QString fileName)
isdownload = true;
downloaditemlist[allDownload - 1]->free = false;
downloadController = new DownloadController(this); // 并发下载,在点击下载按钮的时候才会初始化
if (downloadController)
{
downloadController->disconnect();
downloadController->stopDownload();
downloadController->deleteLater();
}
downloadController = new DownloadController; // 并发下载,在点击下载按钮的时候才会初始化
connect(downloadController, &DownloadController::downloadProcess, this, &DownloadListWidget::updateDataReadProgress);
connect(downloadController, &DownloadController::downloadFinished, this, &DownloadListWidget::httpFinished);
// connect(downloadController, &DownloadController::errorOccur, this, [=](QString msg){this->sendNotification(msg);});

@ -20,7 +20,7 @@ class DownloadListWidget : public DBlurEffectWidget
Q_OBJECT
public:
void addItem(QString name, QString fileName, QString pkgName, const QPixmap icon, QString downloadurl);
DownloadItem *addItem(QString name, QString fileName, QString pkgName, const QPixmap icon, QString downloadurl);
int nowDownload = 0;
int allDownload = 0;
QList<DownloadItem *> getDIList();
@ -35,7 +35,7 @@ private:
QStringList dlist;
QList<QUrl> urList;
QList<DownloadItem *> downloaditemlist;
DownloadController *downloadController;
DownloadController *downloadController = nullptr;
int nowdownload = 0;
QString theSpeed;
QTimer download_speed;