diff --git a/frameworks/native/backup_ext/include/ext_extension.h b/frameworks/native/backup_ext/include/ext_extension.h index c39e05fcd9dbdfcc9d29cc48be36a806f5c75ec2..6f1ad11c2d04b62264dd6458bf1816d7b08f3e52 100644 --- a/frameworks/native/backup_ext/include/ext_extension.h +++ b/frameworks/native/backup_ext/include/ext_extension.h @@ -21,6 +21,7 @@ #include #include "b_json/b_json_entity_extension_config.h" +#include "b_json/b_json_entity_ext_manage.h" #include "b_resources/b_constants.h" #include "ext_backup_js.h" #include "ext_extension_stub.h" @@ -95,9 +96,29 @@ private: void AsyncTaskOnBackup(); + /** + * @brief Check if manage.json is received + * + */ + bool isIndexReadyForRestore(std::vector indexInfos_); + + /** + * @brief Execute GetFileHandle + * + */ + UniqueFd DoGetFileHandle(const string &fileName); + + /** + * @brief read info from manage.json + * + */ + bool readInfoFromIndexFile(std::vector indexInfos_); + private: std::shared_mutex lock_; std::shared_ptr extension_; + std::vector indexInfos_; + std::vector waitedFiles_; std::vector tars_; OHOS::ThreadPool threadPool_; }; diff --git a/frameworks/native/backup_ext/src/ext_extension.cpp b/frameworks/native/backup_ext/src/ext_extension.cpp index 987333bb3086a03a12a291bfe6004b1c08dbf85c..92d7fbec28c03bfcff0348e68d9b2d9e250349b7 100644 --- a/frameworks/native/backup_ext/src/ext_extension.cpp +++ b/frameworks/native/backup_ext/src/ext_extension.cpp @@ -70,6 +70,67 @@ void BackupExtExtension::VerifyCaller() } } +bool BackupExtExtension::isIndexReadyForRestore(std::vector indexInfos_) +{ + shared_lock lock(lock_); + if (indexInfos_.empty()) { + return false; + } + return true; +} + +bool BackupExtExtension::readInfoFromIndexFile(std::vector indexInfos_) +{ + HILOGE("!!!!!!!! readInfoFromIndexFile start %{public}s", INDEX_FILE_RESTORE.data()); + if (access(INDEX_FILE_RESTORE.data(), F_OK) != 0) { + HILOGE("Index file does not exist"); + return false; + } + HILOGE("!!!!!!!! readInfoFromIndexFile get %{public}s", INDEX_FILE_RESTORE.data()); + // 获取索引文件内容 + BJsonCachedEntity cachedEntity(UniqueFd(open(INDEX_FILE_RESTORE.data(), O_RDONLY))); + auto cache = cachedEntity.Structuralize(); + // 写入索引信息加锁 + unique_lock lock(lock_); + indexInfos_ = cache.GetExtManageInfo(); + return true; +} + +static UniqueFd createFileFromIndexFile(ExtManageInfo& manageInfo) +{ + string filePath = manageInfo.fileName; + struct stat sta = manageInfo.sta; + HILOGE("!!!!!!!! createFileFromIndexFile filePath %{public}s", filePath.data()); + // 创建目录 + ForceCreateDirectory(filePath.data()); + + // 创建FD + auto fd = UniqueFd(open(filePath.data(), O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)); + struct timespec tv[2] = {sta.st_atim, sta.st_mtim}; + if (futimens(fd.Get(), tv) != 0) { + HILOGE("failed to change the file time. %{public}s , %{public}d", filePath.c_str(), errno); + } + return fd; +} + +static bool IsUserTar(const string &tarFile, const string &indexFile) +{ + if (tarFile.empty()) { + return false; + } + BJsonCachedEntity cachedEntity(UniqueFd(open(indexFile.data(), O_RDONLY))); + auto cache = cachedEntity.Structuralize(); + auto info = cache.GetExtManageInfo(); + for (auto &item : info) { + if (item.hashName == tarFile) { + HILOGI("tarFile:%{public}s isUserTar:%{public}d", tarFile.data(), item.isUserTar); + return item.isUserTar; + } + } + HILOGE("Can not find tarFile %{public}s", tarFile.data()); + return false; +} + UniqueFd BackupExtExtension::GetFileHandle(const string &fileName) { try { @@ -79,11 +140,47 @@ UniqueFd BackupExtExtension::GetFileHandle(const string &fileName) } VerifyCaller(); + return DoGetFileHandle(fileName); + } catch (...) { + HILOGE("Failed to get file handle"); + DoClear(); + return UniqueFd(-1); + } +} + +UniqueFd BackupExtExtension::DoGetFileHandle(const string &fileName) +{ + HILOGE("!!!!!!!! DoGetFileHandle fileName %{public}s", fileName.data()); + try { + // 查看manage.json信息是否已经获取 + if (!isIndexReadyForRestore(indexInfos_)) { + HILOGE("!!!!!!!! isIndexReadyForRestore filePath %{public}s", fileName.data()); + HILOGI("Index file is not ready for restore"); + waitedFiles_.emplace_back(fileName); + return UniqueFd(-1); + } - if (fileName.find('/') != string::npos) { - throw BError(BError::Codes::EXT_INVAL_ARG, "Filename is not valid"); + for (auto &item : indexInfos_) { + HILOGE("!!!!!!!! DoGetFileHandle item.hashName %{public}s", item.hashName.data()); + HILOGE("!!!!!!!! DoGetFileHandle item.fileName %{public}s", item.fileName.data()); } + // 从Manage.json中获取对应的文件信息 + auto item = find_if(indexInfos_.begin(), indexInfos_.end(), + [fileName](auto &obj) { return obj.hashName == fileName; }); + if (item == indexInfos_.end()) { + throw BError(BError::Codes::EXT_INVAL_ARG, "failed to get the fileName from manage.json"); + return UniqueFd(-1); + } + + // 普通大文件或者userTar + HILOGE("!!!!!!!! DoGetFileHandle ExtractFileExt && IsUserTar %{public}s", fileName.data()); + if (ExtractFileExt(fileName) != "tar" || IsUserTar(fileName, INDEX_FILE_RESTORE)) { + HILOGI("FileName contains path symbol."); + return createFileFromIndexFile(*item); + } + + HILOGE("!!!!!!!! DoGetFileHandle tar not user tar"); string path = string(BConstants::PATH_BUNDLE_BACKUP_HOME).append(BConstants::SA_BUNDLE_BACKUP_RESTORE); if (mkdir(path.data(), S_IRWXU) && errno != EEXIST) { string str = string("Failed to create restore folder. ").append(std::generic_category().message(errno)); @@ -197,6 +294,33 @@ ErrCode BackupExtExtension::PublishFile(const string &fileName) } VerifyCaller(); + // 对于manage.json,需要读取文件信息到容器 + if (fileName == BConstants::EXT_BACKUP_MANAGE) { + HILOGE("!!!!!!!! PublishFile before readInfoFromIndexFile"); + if (!readInfoFromIndexFile(indexInfos_)) { + throw BError(BError::Codes::EXT_INVAL_ARG, "Index file not exist"); + } + auto task = [obj {wptr(this)}]() { + auto ptr = obj.promote(); + for (auto &waitedFile : ptr->waitedFiles_) { + HILOGE("!!!!!!!! waitedFile %{public}s", waitedFile.data()); + ptr->DoGetFileHandle(waitedFile); + } + }; + // 读取等待中的waitedFiles_,触发操作 + threadPool_.AddTask([task]() { + try { + task(); + } catch (...) { + HILOGE("Failed to add task to thread pool"); + } + }); + HILOGE("!!!!!!!! PublishFile after AddTask"); + unique_lock lock(lock_); + tars_.push_back(fileName); + return ERR_OK; + } + HILOGE("!!!!!!!! PublishFile Not Manage.json"); string path = string(BConstants::PATH_BUNDLE_BACKUP_HOME).append(BConstants::SA_BUNDLE_BACKUP_RESTORE); string tarName = path + fileName; { @@ -213,6 +337,7 @@ ErrCode BackupExtExtension::PublishFile(const string &fileName) // 异步执行解压操作 if (extension_->AllowToBackupRestore()) { + HILOGE("!!!!!!!! AllowToBackupRestore AsyncTaskRestore"); AsyncTaskRestore(); } @@ -244,24 +369,6 @@ ErrCode BackupExtExtension::HandleBackup() return 0; } -static bool IsUserTar(const string &tarFile, const string &indexFile) -{ - if (tarFile.empty()) { - return false; - } - BJsonCachedEntity cachedEntity(UniqueFd(open(indexFile.data(), O_RDONLY))); - auto cache = cachedEntity.Structuralize(); - auto info = cache.GetExtManageInfo(); - for (auto &item : info) { - if (item.hashName == tarFile) { - HILOGI("tarFile:%{public}s isUserTar:%{public}d", tarFile.data(), item.isUserTar); - return item.isUserTar; - } - } - HILOGE("Can not find tarFile %{public}s", tarFile.data()); - return false; -} - static pair> GetFileInfos(const vector &includes, const vector &excludes) { auto [errCode, files, smallFiles] = BDir::GetBigFiles(includes, excludes); @@ -650,6 +757,24 @@ ErrCode BackupExtExtension::HandleRestore() if (extension_->WasFromSpeicalVersion() && extension_->RestoreDataReady()) { HILOGI("Restore directly when upgrading."); AsyncTaskRestoreForUpgrade(); + } else { + // To provide fd for manage.json first. + auto proxy = ServiceProxy::GetInstance(); + HILOGE("!!!!!!!!!!!!!!!!Restore start: Manage.json request"); + string path = string(BConstants::PATH_BUNDLE_BACKUP_HOME).append(BConstants::SA_BUNDLE_BACKUP_RESTORE); + HILOGE("!!!!!!!!!!!!!!!!Restore start: Manage.json request %{public}s", path.data()); + if (mkdir(path.data(), S_IRWXU) && errno != EEXIST) { + string str = string("Failed to create restore folder. ").append(std::generic_category().message(errno)); + throw BError(BError::Codes::EXT_INVAL_ARG, str); + } + ErrCode ret = + proxy->AppFileReady(string(BConstants::EXT_BACKUP_MANAGE), UniqueFd(open(INDEX_FILE_RESTORE.data(), O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR))); + if (SUCCEEDED(ret)) { + HILOGI("Restore start: Manage.json request successfully"); + } else { + HILOGI("Restore start: AppFileReady interface fails to be invoked: %{public}d", ret); + } + return ret; } return 0; diff --git a/services/backup_sa/src/module_ipc/service.cpp b/services/backup_sa/src/module_ipc/service.cpp index 937146137211e0a1781b5604f962f71c147f19d0..66e9112636d13a2ccc3a0467468f2c42c3dec0da 100644 --- a/services/backup_sa/src/module_ipc/service.cpp +++ b/services/backup_sa/src/module_ipc/service.cpp @@ -353,10 +353,6 @@ ErrCode Service::PublishFile(const BFileInfo &fileInfo) sched_->Sched(fileInfo.owner); return BError(BError::Codes::OK); } - if (fileInfo.fileName.find('/') != string::npos) { - throw BError(BError::Codes::SA_INVAL_ARG, "Filename is not valid"); - } - auto backUpConnection = session_->GetExtConnection(fileInfo.owner); auto proxy = backUpConnection->GetBackupExtProxy(); @@ -385,6 +381,13 @@ ErrCode Service::AppFileReady(const string &fileName, UniqueFd fd) try { HILOGI("Begin"); string callerName = VerifyCallerAndGetCallerName(); + + IServiceReverse::Scenario scenario = session_->GetScenario(); + if (scenario == IServiceReverse::Scenario::RESTORE && fileName == BConstants::EXT_BACKUP_MANAGE) { + session_->GetServiceReverseProxy()->RestoreOnFileReady(callerName, fileName, move(fd)); + return BError(BError::Codes::OK); + } + if (fileName.find('/') != string::npos) { throw BError(BError::Codes::SA_INVAL_ARG, "Filename is not valid"); } @@ -505,6 +508,11 @@ ErrCode Service::GetFileHandle(const string &bundleName, const string &fileName) try { HILOGI("Begin"); VerifyCaller(IServiceReverse::Scenario::RESTORE); + // ignore manage.json + HILOGE("!!!!!!GetFileHandle Ignore manage.json"); + if (fileName == BConstants::EXT_BACKUP_MANAGE) { + return BError(BError::Codes::OK); + } if (fileName == BConstants::RESTORE_INSTALL_PATH && bundleName.find('/') == string::npos) { session_->SetInstallState(bundleName, string(BConstants::RESTORE_INSTALL_PATH)); auto action = session_->GetServiceSchedAction(bundleName); @@ -513,9 +521,6 @@ ErrCode Service::GetFileHandle(const string &bundleName, const string &fileName) } return BError(BError::Codes::OK); } - if (fileName.find('/') != string::npos) { - throw BError(BError::Codes::SA_INVAL_ARG, "Filename is not valid"); - } auto action = session_->GetServiceSchedAction(bundleName); if (action == BConstants::ServiceSchedAction::RUNNING) { auto backUpConnection = session_->GetExtConnection(bundleName);