yhkylin-backup-tools/backup-daemon/mybackupmanager.cpp

634 lines
20 KiB
C++
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* brief 程序比较小将接口层和控制层合到一起主要做一些任务分发状态监控等一些简单工作复杂的耗时的逻辑放到任务中moveToThread中去执行
*/
#include <QTimer>
#include <QDateTime>
#include <QDBusArgument>
#include <QDBusMessage>
#include <QDBusPendingReply>
#include <QDBusMessage>
#include <QDBusUnixFileDescriptor>
#include <QDBusConnection>
#include <mutex>
#include <sys/reboot.h>
#include "mybackupmanager.h"
#include "../common/utils.h"
#include "mymountproxy.h"
#include "workerfactory.h"
#include "parsebackuplist.h"
/**
* @brief 构造函数
*/
MyBackupManager::MyBackupManager()
{
// 注册BackupWrapper类型之后qdbus接口才能使用
BackupWrapper::registerMetaType();
}
/**
* @brief 析构函数
*/
MyBackupManager::~MyBackupManager()
{
if (workerThread.isRunning()) {
workerThread.quit();
workerThread.wait();
}
}
/**
* @brief 挂载backup分区兼容提供给自动更新模块的老接口
* @return
*/
int MyBackupManager::Mount_backup_partition()
{
m_needUmount = false;
MyMountProxy mymount;
return int(mymount.mountBackupPartition());
}
/**
* @brief 卸载backup分区
* @return
*/
bool MyBackupManager::umountBackupPartition()
{
m_needUmount = true;
return umountBackup();
}
/**
* @brief 卸载backup分区
* @return
*/
bool MyBackupManager::umountBackup()
{
// /backup分区卸载
if (m_needUmount && m_isActive) {
QTimer::singleShot(5*1000, this, &MyBackupManager::umountBackup);
return true;
} else if (m_needUmount) {
MyMountProxy mymount;
return mymount.umountBackupPartition();
}
return true;
}
/**
* @brief 试用模式重新挂载分区
* @return bool
*/
bool MyBackupManager::remountPartitionsForCasperMode()
{
MyMountProxy mymount;
return mymount.remountPartitionsForCasperMode();
}
/**
* @brief 环境检测
* @param backupWrapper参数
* @return 0正确启动非0出现错误
*/
int MyBackupManager::checkEnv(const BackupWrapper& backupWrapper)
{
qDebug("MyBackupManager::checkEnv invoke begin");
if (m_isActive || !lock(backupWrapper.m_frontUid)) {
emit sendEnvCheckResult(int(BackupResult::LOCK_PROGRAM_FAIL));
return int(BackupResult::LOCK_PROGRAM_FAIL);
}
Worker* worker = WorkerFactory::createWorker(backupWrapper.m_type, backupWrapper.m_iPosition);
if (nullptr == worker) {
emit sendEnvCheckResult(int(BackupResult::NO_FOUND_DEALCLASS));
return int(BackupResult::NO_FOUND_DEALCLASS);
}
worker->setParam(backupWrapper);
connect(worker, &Worker::checkResult, this, [&] (int result) {
emit this->sendEnvCheckResult(result);
this->finished();
});
worker->moveToThread(&workerThread);
connect(&workerThread, &MyThread::started, worker, &Worker::checkEnv);
connect(&workerThread, &MyThread::finished, worker, &Worker::deleteLater);
workerThread.start();
qDebug("MyBackupManager::checkEnv invoke end");
return int(BackupResult::BACKUP_RESULT_INIT);
}
/**
* @brief 备份
* @param backupWrapper
* @return 0正确启动备份非0出现错误
*/
int MyBackupManager::goBackup(const BackupWrapper& backupWrapper)
{
qDebug("MyBackupManager::goBackup invoke begin");
if (m_isActive || !lock(backupWrapper.m_frontUid)) {
emit sendEnvCheckResult(int(BackupResult::LOCK_PROGRAM_FAIL));
return int(BackupResult::LOCK_PROGRAM_FAIL);
}
Worker* worker = WorkerFactory::createWorker(backupWrapper.m_type, backupWrapper.m_iPosition);
if (nullptr == worker) {
emit sendEnvCheckResult(int(BackupResult::NO_FOUND_DEALCLASS));
return int(BackupResult::NO_FOUND_DEALCLASS);
}
worker->setParam(backupWrapper);
connect(worker, &Worker::checkResult, this, [&](int result) {
emit this->sendEnvCheckResult(result);
switch (result) {
case int(BackupResult::CHECK_ENV_SUCCESS) :
case int(BackupResult::MKSQUASHFS_START_SUCCESS) :
case int(BackupResult::BACKUP_START_SUCCESS) :
case int(BackupResult::START_CANCEL) :
break;
default:
this->finished();
break;
}
});
connect(worker, &Worker::progress, this, [&](int rate) {
emit this->progress(int(BackupState::WORKING), rate);
});
connect(worker, &Worker::workResult, this, [&] (bool result) {
emit this->backupFinished(result);
this->finished();
});
worker->moveToThread(&workerThread);
connect(&workerThread, &MyThread::started, worker, &Worker::doWork);
connect(&workerThread, &MyThread::finished, worker, &Worker::deleteLater);
connect(&workerThread, &MyThread::cancelWork, worker, &Worker::cancel);
workerThread.start();
qDebug("MyBackupManager::goBackup invoke end");
return int(BackupResult::BACKUP_RESULT_INIT);
}
/**
* @brief 还原
* @param backupWrapper
* @return
*/
int MyBackupManager::goRestore(const BackupWrapper& backupWrapper)
{
qDebug("MyBackupManager::goRestore invoke begin");
if (m_isActive || !lock(backupWrapper.m_frontUid)) {
emit sendEnvCheckResult(int(BackupResult::LOCK_PROGRAM_FAIL));
return int(BackupResult::LOCK_PROGRAM_FAIL);
}
Worker* worker = WorkerFactory::createWorker(backupWrapper.m_type, backupWrapper.m_iPosition);
if (nullptr == worker) {
emit sendEnvCheckResult(int(BackupResult::NO_FOUND_DEALCLASS));
return int(BackupResult::NO_FOUND_DEALCLASS);
}
worker->setParam(backupWrapper);
connect(worker, &Worker::checkResult, this, [&](int result) {
emit this->sendEnvCheckResult(result);
switch (result) {
case int(BackupResult::CHECK_ENV_SUCCESS) :
case int(BackupResult::RESTORE_START_SUCCESS) :
break;
default:
this->finished();
break;
}
});
connect(worker, &Worker::progress, this, [&](int rate) {
emit this->progress(int(BackupState::WORKING), rate);
});
connect(worker, &Worker::workResult, this, [&] (bool result) {
emit this->sendRestoreResult(result);
this->finished();
});
worker->moveToThread(&workerThread);
connect(&workerThread, &MyThread::started, worker, &Worker::doWork);
connect(&workerThread, &MyThread::finished, worker, &Worker::deleteLater);
workerThread.start();
qDebug("MyBackupManager::goRestore invoke end");
return int(BackupResult::BACKUP_RESULT_INIT);
}
/**
* @brief 删除备份
* @param backupWrapper
* @return
*/
int MyBackupManager::deleteBackupPoint(const BackupWrapper& backupWrapper)
{
qDebug("MyBackupManager::deleteBackupPoint invoke begin");
if (m_isActive || !lock(backupWrapper.m_frontUid)) {
emit sendEnvCheckResult(int(BackupResult::LOCK_PROGRAM_FAIL));
return int(BackupResult::LOCK_PROGRAM_FAIL);
}
Worker* worker = WorkerFactory::createWorker(backupWrapper.m_type, backupWrapper.m_iPosition);
if (nullptr == worker) {
emit sendEnvCheckResult(int(BackupResult::NO_FOUND_DEALCLASS));
return int(BackupResult::NO_FOUND_DEALCLASS);
}
worker->setParam(backupWrapper);
connect(worker, &Worker::workResult, this, [&] (bool result) {
emit this->sendDeleteResult(result);
this->finished();
});
worker->moveToThread(&workerThread);
connect(&workerThread, &MyThread::started, worker, &Worker::doWork);
connect(&workerThread, &MyThread::finished, worker, &Worker::deleteLater);
workerThread.start();
qDebug("MyBackupManager::deleteBackupPoint invoke end");
return int(BackupResult::BACKUP_RESULT_INIT);
}
/**
* @brief ghost镜像
* @param backupWrapper
* @return
*/
int MyBackupManager::ghostBackup(const BackupWrapper& backupWrapper)
{
qDebug("MyBackupManager::ghostBackup invoke begin");
if (m_isActive || !lock(backupWrapper.m_frontUid)) {
emit sendEnvCheckResult(int(BackupResult::LOCK_PROGRAM_FAIL));
return int(BackupResult::LOCK_PROGRAM_FAIL);
}
Worker* worker = WorkerFactory::createWorker(backupWrapper.m_type, backupWrapper.m_iPosition);
if (nullptr == worker) {
emit sendEnvCheckResult(int(BackupResult::NO_FOUND_DEALCLASS));
return int(BackupResult::NO_FOUND_DEALCLASS);
}
worker->setParam(backupWrapper);
connect(worker, &Worker::checkResult, this, [&](int result) {
emit this->sendEnvCheckResult(result);
switch (result) {
case int(BackupResult::CHECK_ENV_SUCCESS) :
case int(BackupResult::GHOST_START_SUCCESS) :
case int(BackupResult::MKSQUASHFS_DO_SUCCESS) :
case int(BackupResult::START_CANCEL) :
break;
default:
this->finished();
break;
}
});
connect(worker, &Worker::progress, this, [&](int rate) {
emit this->progress(int(BackupState::WORKING), rate);
});
connect(worker, &Worker::workResult, this, [&] (bool result) {
emit this->sendGhostBackupResult(result);
this->finished();
});
worker->moveToThread(&workerThread);
connect(&workerThread, &MyThread::started, worker, &Worker::doWork);
connect(&workerThread, &MyThread::finished, worker, &Worker::deleteLater);
connect(&workerThread, &MyThread::cancelWork, worker, &Worker::cancel);
workerThread.start();
qDebug("MyBackupManager::ghostBackup invoke end");
return int(BackupResult::BACKUP_RESULT_INIT);
}
/**
* @brief 控制面板调用的备份接口,重构暂时先兼容以前的老接口
* @param backupName 备份名称
* @param createNote 创建时备注
* @param incNote 增量备注
* @param frontUserName 前端用户名
* @param frontUid 前端用户id
*/
void MyBackupManager::autoBackUpForSystemUpdate_noreturn(const QString& backupName, const QString& createNote, const QString& incNote, const QString& frontUserName, int frontUid)
{
qDebug("MyBackupManager::autoBackUpForSystemUpdate_noreturn invoke begin");
if (m_isActive || !lock(frontUid)) {
emit sendStartBackupResult(int(BackupResult::LOCK_PROGRAM_FAIL));
return ;
}
BackupWrapper backupWrapper;
backupWrapper.m_uuid = AUTO_BACKUP_UUID;
QString xmlPath = Utils::getSysRootPath() + BACKUP_XML_PATH;
xmlPath.replace("//", "/");
ParseBackupList parseXml(xmlPath);
ParseBackupList::BackupPoint backupPoint = parseXml.findBackupPointByUuid(backupWrapper.m_uuid);
if (backupName.isEmpty()) {
if (backupPoint.m_backupName.isEmpty())
backupWrapper.m_backupName = QDateTime::currentDateTime().toString("yy-MM-dd hh:mm:ss");
else
backupWrapper.m_backupName = backupPoint.m_backupName;
} else {
backupWrapper.m_backupName = backupName;
}
backupWrapper.m_backupPaths << "/";
backupWrapper.m_backupExcludePaths = Utils::getFromExcludePathsFile();
backupWrapper.m_backupExcludePaths << "/home";
backupWrapper.m_backupExcludePaths << "/root";
backupWrapper.m_backupExcludePaths << "/data/home";
backupWrapper.m_backupExcludePaths << "/data/root";
backupWrapper.m_type = BackupType::BACKUP_SYSTEM;
backupWrapper.m_iPosition = BackupPosition::LOCAL;
backupWrapper.m_frontUserName = frontUserName;
backupWrapper.m_frontUid = frontUid;
backupWrapper.m_note = createNote.isEmpty() ? incNote : createNote;
Worker* worker = WorkerFactory::createWorker(backupWrapper.m_type, backupWrapper.m_iPosition);
if (nullptr == worker) {
emit sendStartBackupResult(int(BackupResult::NO_FOUND_DEALCLASS));
return ;
}
worker->setParam(backupWrapper);
connect(worker, &Worker::checkResult, this, [&](int result) {
switch (result) {
case int(BackupResult::CHECK_ENV_SUCCESS) :
case int(BackupResult::MKSQUASHFS_START_SUCCESS) :
case int(BackupResult::BACKUP_START_SUCCESS) :
break;
default:
emit this->sendStartBackupResult(result);
this->finished();
if (!Utils::isRunning(BACKUP_CLI_NAME)) {
this->umountBackupPartition();
}
break;
}
});
connect(worker, &Worker::progress, this, [&](int rate) {
emit this->sendRate(int(BackupState::WORKING), rate);
});
connect(worker, &Worker::workResult, this, [&] (bool result) {
emit this->sendBackupResult(result);
this->finished();
if (!Utils::isRunning(BACKUP_CLI_NAME)) {
this->umountBackupPartition();
}
});
worker->moveToThread(&workerThread);
connect(&workerThread, &MyThread::started, worker, &Worker::doWork);
connect(&workerThread, &MyThread::finished, worker, &Worker::deleteLater);
workerThread.start();
qDebug("MyBackupManager::autoBackUpForSystemUpdate_noreturn invoke end");
}
/**
* @brief 控制面板调用的系统自动备份点还原接口
* @note 此接口是后来加的,系统更新模块意图在更新失败后直接调用还原接口进行还原
*/
void MyBackupManager::autoRestoreForSystemUpdate(const QString& frontUserName, int frontUid)
{
qDebug("MyBackupManager::autoRestoreForSystemUpdate invoke begin");
if (m_isActive || !lock(frontUid)) {
emit sendAutoRestoreResult(false);
return ;
}
Mount_backup_partition();
BackupWrapper backupWrapper;
backupWrapper.m_uuid = AUTO_BACKUP_UUID;
backupWrapper.m_type = BackupType::RESTORE_SYSTEM;
backupWrapper.m_iPosition = BackupPosition::LOCAL;
backupWrapper.m_frontUserName = frontUserName;
backupWrapper.m_frontUid = frontUid;
Worker* worker = WorkerFactory::createWorker(backupWrapper.m_type, backupWrapper.m_iPosition);
if (nullptr == worker) {
emit sendAutoRestoreResult(false);
return ;
}
worker->setParam(backupWrapper);
connect(worker, &Worker::checkResult, this, [&](int result) {
switch (result) {
case int(BackupResult::CHECK_ENV_SUCCESS) :
case int(BackupResult::RESTORE_START_SUCCESS) :
break;
default:
emit this->sendAutoRestoreResult(false);
this->finished();
if (!Utils::isRunning(BACKUP_CLI_NAME)) {
this->umountBackupPartition();
}
break;
}
});
connect(worker, &Worker::progress, this, [&](int rate) {
emit this->sendRate(int(BackupState::WORKING), rate);
});
connect(worker, &Worker::workResult, this, [&] (bool result) {
emit this->sendAutoRestoreResult(result);
this->finished();
if (!Utils::isRunning(BACKUP_CLI_NAME)) {
this->umountBackupPartition();
}
});
worker->moveToThread(&workerThread);
connect(&workerThread, &MyThread::started, worker, &Worker::doWork);
connect(&workerThread, &MyThread::finished, worker, &Worker::deleteLater);
workerThread.start();
qDebug("MyBackupManager::autoRestoreForSystemUpdate invoke end");
}
/**
* @brief 控制面板调用的获取系统备份接口
* @param state
* @return
*/
QString MyBackupManager::getBackupCommentForSystemUpdate(QString& state)
{
QString xmlPath = Utils::getSysRootPath() + BACKUP_XML_PATH;
xmlPath.replace("//", "/");
ParseBackupList parseXml(xmlPath);
ParseBackupList::BackupPoint backupPoint = parseXml.findBackupPointByUuid(AUTO_BACKUP_UUID);
state = backupPoint.m_state;
return backupPoint.m_backupName;
}
/**
* @brief 获取备份状态
* @param isActive是否活动状态
* @return
*/
int MyBackupManager::getBackupState(bool& isActive)
{
isActive = m_isActive;
return int(m_backupState);
}
/**
* @brief 取消操作
*/
int MyBackupManager::cancel()
{
if (workerThread.isRunning())
emit workerThread.cancelWork();
else
return 1;
return 0;
}
/**
* @brief 重启操作
* @return
*/
int MyBackupManager::reboot()
{
return ::reboot(RB_AUTOBOOT);;
}
/**
* @brief 任务结束
*/
void MyBackupManager::finished()
{
if (workerThread.isRunning()) {
workerThread.quit();
workerThread.wait();
}
unlock();
}
/**
* @brief 锁定应用
* @param frontUid锁定应用的用户id
* @return bool
*/
bool MyBackupManager::lock(int frontUid)
{
std::lock_guard<spinlock_mutex> lock(m_mutex);
int lock_file_fd = Utils::lockProgram(frontUid);
if (lock_file_fd < 0) {
Utils::rmLockFile();
return false;
}
// 用于替换上面的文件锁的对应需求8688
// if (!inhibit())
// return false;
inhibit();
m_fdLockFile = lock_file_fd;
m_backupState = BackupState::PREPARING;
m_isActive = true;
setKysecStatus(false);
return true;
}
/**
* @brief 阻止session关机用dbus新接口Inhibit来替换锁文件的方式
* Inhibti函数有四个参数按顺序分别为
what:需要阻止的是哪些过程如关机、重启可以输入的值有”shutdown”(会同时阻止关机重启)”sleep”会同时阻止睡眠休眠需要同时阻止关机和睡眠可以输入 ”shutdown:sleep”
who:是谁要阻止调用该接口的程序名如”ukui-sessions”
why阻止的原因简单描述即可如”package installing”
mode:阻止的方式可输入的值有”block”(无限期阻止,等到主动取消阻止才会取消)”delay”超时阻止超时一段时间后不管阻止锁直接执行
建议使用”block”的方式阻止加锁后记得解锁
可以使用同服务下ListInhibitors方法获取当前的inhibit锁测试验证是否成功注册
* @return
*/
bool MyBackupManager::inhibit()
{
QDBusMessage message;
message = QDBusMessage::createMethodCall("org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
QStringLiteral("Inhibit"));
QString why("The backup and restore tool is busy, please wait.");
// 区分中英文
QString locale = QLocale::system().name();
if (locale == "zh_CN") {
why = QString("备份还原工具正在忙碌,请稍等");
} else if (locale == "bo_CN") {
why = QString("གྲབས་ཉར་སོར་ཆུད་ལག་ཆ་བྲེལ་བཞིན་ཡོད་།ཏོག་ཙམ་སྒུག་རོགས་།");
}
// QVariantList({what, who, why, mode})
QVariantList args;
args << QString("shutdown:sleep");
args << QString("backup-daemon");
args << why;
args << QString("block");
message.setArguments(args);
QDBusPendingReply<QDBusUnixFileDescriptor> reply = QDBusConnection::systemBus().call(message);
if (!reply.isValid()) {
qDebug() << "inhibit faile!";
return false;
}
QDBusUnixFileDescriptor inhibitFileDescriptor = reply.value();
inhibitFileDescriptor.swap(m_inhibitFileDescriptor);
qDebug() << "inhibit success!";
return true;
}
void MyBackupManager::uninhibit()
{
if (!m_inhibitFileDescriptor.isValid()) {
return;
}
qDebug() << "uninhibit success!";
m_inhibitFileDescriptor = QDBusUnixFileDescriptor();
}
/**
* @brief 解锁应用
* @return bool
*/
bool MyBackupManager::unlock()
{
std::lock_guard<spinlock_mutex> lock(m_mutex);
setKysecStatus(true);
Utils::unLockProgram(m_fdLockFile);
uninhibit();
m_fdLockFile = -1;
m_backupState = BackupState::BACKUP_STATE_INIT;
m_isActive = false;
return true;
}
/**
* @brief 设置安全状态
* @param status,true-开启false-关闭
* @note status=true时不一定会开启取决于关闭时安全状态;
* 使用此方法时注意一定要先setKysecStatus(false);才能setKysecStatus(true);
* 使用场景:备份/还原等业务时先关闭安全保护,业务完成后再重启安全保护
*/
void MyBackupManager::setKysecStatus(bool status)
{
// openkylin平台中不开源安全模块删掉安全模块的调用
Q_UNUSED(status)
}