/** * brief 程序比较小,将接口层和控制层合到一起;主要做一些任务分发,状态监控等一些简单工作;复杂的耗时的逻辑放到任务中moveToThread中去执行 */ #include #include #include #include #include #include #include #include #include #include #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 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 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 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) }