From 2558992a39cb899311d9acad588e5f712e3c246a Mon Sep 17 00:00:00 2001 From: yang-jingbo1985 Date: Wed, 21 Feb 2024 17:25:29 +0800 Subject: [PATCH] =?UTF-8?q?=E5=85=8B=E9=9A=86=E4=BC=98=E5=8C=96=E7=A7=BB?= =?UTF-8?q?=E6=A4=8D=E5=A2=9E=E9=87=8F=E5=A4=87=E4=BB=BD=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=20Signed-off-by:=20yangjingbo10=20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I01dfe35d96c2d98036f3bfb7e37f12b2f5c6597f --- .../native/backup_ext/include/ext_extension.h | 6 + .../native/backup_ext/src/ext_extension.cpp | 86 +++- .../b_incremental_session_restore_async.cpp | 131 ++++++ .../src/b_session_restore_async.cpp | 2 +- .../native/backup_kit_inner/BUILD.gn | 1 + .../backup_kit_inner/backup_kit_inner.h | 1 + .../b_incremental_session_restore_async.h | 120 ++++++ tools/backup_tool/BUILD.gn | 1 + .../tools_op_incremental_restore_async.h | 24 ++ tools/backup_tool/src/main.cpp | 2 + .../tools_op_incremental_restore_async.cpp | 399 ++++++++++++++++++ utils/include/b_resources/b_constants.h | 3 + 12 files changed, 771 insertions(+), 5 deletions(-) create mode 100644 frameworks/native/backup_kit_inner/src/b_incremental_session_restore_async.cpp create mode 100644 interfaces/inner_api/native/backup_kit_inner/impl/b_incremental_session_restore_async.h create mode 100644 tools/backup_tool/include/tools_op_incremental_restore_async.h create mode 100644 tools/backup_tool/src/tools_op_incremental_restore_async.cpp diff --git a/frameworks/native/backup_ext/include/ext_extension.h b/frameworks/native/backup_ext/include/ext_extension.h index 5120b9285..d316da27f 100644 --- a/frameworks/native/backup_ext/include/ext_extension.h +++ b/frameworks/native/backup_ext/include/ext_extension.h @@ -117,6 +117,12 @@ private: */ void AsyncTaskIncrementalRestore(); + /** + * @brief Executing Incremental Restoration Tasks Asynchronously for special clone & cloud + * + */ + void AsyncTaskIncrementalRestoreSpecialCloneCloud(); + void AsyncTaskOnBackup(); int DoIncrementalBackup(const std::map &allFiles, diff --git a/frameworks/native/backup_ext/src/ext_extension.cpp b/frameworks/native/backup_ext/src/ext_extension.cpp index 8f81a35c1..4af8ae5d1 100644 --- a/frameworks/native/backup_ext/src/ext_extension.cpp +++ b/frameworks/native/backup_ext/src/ext_extension.cpp @@ -165,6 +165,35 @@ static string GetReportFileName(const string &fileName) return reportName; } +static ErrCode GetIncrementalFileHandleForSpecialCloneCloud(const string &fileName) +{ + UniqueFd fd = GetFileHandleForSpecialCloneCloud(fileName); + if (fd < 0) { + HILOGE("Failed to open file = %{private}s, err = %{public}d", fileName.c_str(), errno); + throw BError(BError::Codes::EXT_INVAL_ARG, string("open tar file failed")); + } + + 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)); + throw BError(BError::Codes::EXT_INVAL_ARG, str); + } + string reportName = path + BConstants::BLANK_REPORT_NAME; + UniqueFd reportFd(open(reportName.data(), O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)); + if (reportFd < 0) { + HILOGE("Failed to open report file = %{private}s, err = %{public}d", reportName.c_str(), errno); + throw BError(BError::Codes::EXT_INVAL_ARG, string("open report file failed")); + } + + auto proxy = ServiceProxy::GetInstance(); + auto ret = proxy->AppIncrementalFileReady(fileName, move(fd), move(reportFd)); + if (ret != ERR_OK) { + HILOGI("Failed to AppIncrementalFileReady %{public}d", ret); + } + + return ERR_OK; +} + ErrCode BackupExtExtension::GetIncrementalFileHandle(const string &fileName) { HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__); @@ -176,6 +205,10 @@ ErrCode BackupExtExtension::GetIncrementalFileHandle(const string &fileName) VerifyCaller(); + if (extension_->SpeicalVersionForCloneAndCloud()) { + return GetIncrementalFileHandleForSpecialCloneCloud(fileName); + } + 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)); @@ -374,23 +407,29 @@ ErrCode BackupExtExtension::PublishIncrementalFile(const string &fileName) } VerifyCaller(); + bool isSpeicalVersion = extension_->SpeicalVersionForCloneAndCloud(); + string path = string(BConstants::PATH_BUNDLE_BACKUP_HOME).append(BConstants::SA_BUNDLE_BACKUP_RESTORE); - string tarName = path + fileName; + string tarName = isSpeicalVersion ? fileName : path + fileName; { - BExcepUltils::VerifyPath(tarName, true); + BExcepUltils::VerifyPath(tarName, !isSpeicalVersion); unique_lock lock(lock_); if (find(tars_.begin(), tars_.end(), fileName) != tars_.end() || access(tarName.data(), F_OK) != 0) { throw BError(BError::Codes::EXT_INVAL_ARG, "The file does not exist"); } tars_.push_back(fileName); - if (!IsAllFileReceived(tars_, false)) { + if (!IsAllFileReceived(tars_, isSpeicalVersion)) { return ERR_OK; } } // 异步执行解压操作 if (extension_->AllowToBackupRestore()) { - AsyncTaskIncrementalRestore(); + if (isSpeicalVersion) { + AsyncTaskIncrementalRestoreSpecialCloneCloud(); + } else { + AsyncTaskIncrementalRestore(); + } } return ERR_OK; @@ -936,6 +975,45 @@ void BackupExtExtension::AsyncTaskIncrementalRestore() }); } +void BackupExtExtension::AsyncTaskIncrementalRestoreSpecialCloneCloud() +{ + auto task = [obj {wptr(this)}, tars {tars_}]() { + auto ptr = obj.promote(); + BExcepUltils::BAssert(ptr, BError::Codes::EXT_BROKEN_FRAMEWORK, + "Ext extension handle have been already released"); + BExcepUltils::BAssert(ptr->extension_, BError::Codes::EXT_INVAL_ARG, + "extension handle have been already released"); + try { + int ret = RestoreFilesForSpecialCloneCloud(); + if (ret == ERR_OK) { + ptr->AsyncTaskIncrementalRestoreForUpgrade(); + } else { + ptr->AppIncrementalDone(ret); + ptr->DoClear(); + } + } catch (const BError &e) { + ptr->AppIncrementalDone(e.GetCode()); + } catch (const exception &e) { + HILOGE("Catched an unexpected low-level exception %{public}s", e.what()); + ptr->AppIncrementalDone(BError(BError::Codes::EXT_INVAL_ARG).GetCode()); + } catch (...) { + HILOGE("Failed to restore the ext bundle"); + ptr->AppIncrementalDone(BError(BError::Codes::EXT_INVAL_ARG).GetCode()); + } + }; + + // REM: 这里异步化了,需要做并发控制 + // 在往线程池中投入任务之前将需要的数据拷贝副本到参数中,保证不发生读写竞争, + // 由于拷贝参数时尚运行在主线程中,故在参数拷贝过程中是线程安全的。 + threadPool_.AddTask([task]() { + try { + task(); + } catch (...) { + HILOGE("Failed to add task to thread pool"); + } + }); +} + void BackupExtExtension::AsyncTaskRestoreForUpgrade() { HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__); diff --git a/frameworks/native/backup_kit_inner/src/b_incremental_session_restore_async.cpp b/frameworks/native/backup_kit_inner/src/b_incremental_session_restore_async.cpp new file mode 100644 index 000000000..c531d37d9 --- /dev/null +++ b/frameworks/native/backup_kit_inner/src/b_incremental_session_restore_async.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "b_incremental_session_restore_async.h" + +#include "b_error/b_error.h" +#include "b_resources/b_constants.h" +#include "filemgmt_libhilog.h" +#include "service_proxy.h" +#include "service_reverse.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +BIncrementalSessionRestoreAsync::~BIncrementalSessionRestoreAsync() +{ + if (!deathRecipient_) { + HILOGI("Death Recipient is nullptr"); + return; + } + auto proxy = ServiceProxy::GetInstance(); + if (proxy == nullptr) { + return; + } + auto remoteObject = proxy->AsObject(); + if (remoteObject != nullptr) { + remoteObject->RemoveDeathRecipient(deathRecipient_); + } + callbacks_ = {}; + deathRecipient_ = nullptr; +} + +shared_ptr BIncrementalSessionRestoreAsync::Init(Callbacks callbacks) +{ + try { + auto restore = make_shared(callbacks); + ServiceProxy::InvaildInstance(); + auto proxy = ServiceProxy::GetInstance(); + if (proxy == nullptr) { + HILOGI("Failed to get backup service"); + return nullptr; + } + BIncrementalRestoreSession::Callbacks callbacksTmp {.onFileReady = callbacks.onFileReady, + .onBundleStarted = callbacks.onBundleStarted, + .onBundleFinished = callbacks.onBundleFinished, + .onAllBundlesFinished = callbacks.onAllBundlesFinished, + .onBackupServiceDied = callbacks.onBackupServiceDied}; + int32_t res = proxy->InitRestoreSession(new ServiceReverse(callbacksTmp)); + if (res != 0) { + HILOGE("Failed to Restore because of %{public}d", res); + return nullptr; + } + + restore->RegisterBackupServiceDied(callbacks.onBackupServiceDied); + return restore; + } catch (const exception &e) { + HILOGE("Failed to Restore because of %{public}s", e.what()); + } + return nullptr; +} + +ErrCode BIncrementalSessionRestoreAsync::PublishFile(BFileInfo fileInfo) +{ + auto proxy = ServiceProxy::GetInstance(); + if (proxy == nullptr) { + return BError(BError::Codes::SDK_BROKEN_IPC, "Failed to get backup service").GetCode(); + } + return proxy->PublishIncrementalFile(fileInfo); +} + +ErrCode BIncrementalSessionRestoreAsync::GetFileHandle(const string &bundleName, const string &fileName) +{ + auto proxy = ServiceProxy::GetInstance(); + if (proxy == nullptr) { + return BError(BError::Codes::SDK_BROKEN_IPC, "Failed to get backup service").GetCode(); + } + + return proxy->GetIncrementalFileHandle(bundleName, fileName); +} + +ErrCode BIncrementalSessionRestoreAsync::AppendBundles(UniqueFd remoteCap, + vector bundlesToRestore, + RestoreTypeEnum restoreType, + int32_t userId) +{ + auto proxy = ServiceProxy::GetInstance(); + if (proxy == nullptr) { + return BError(BError::Codes::SDK_BROKEN_IPC, "Failed to get backup service").GetCode(); + } + + return proxy->AppendBundlesRestoreSession(move(remoteCap), bundlesToRestore, restoreType, userId); +} + +ErrCode BIncrementalSessionRestoreAsync::Release() +{ + auto proxy = ServiceProxy::GetInstance(); + if (proxy == nullptr) { + return BError(BError::Codes::SDK_BROKEN_IPC, "Failed to get backup service").GetCode(); + } + + return proxy->Release(); +} + +void BIncrementalSessionRestoreAsync::RegisterBackupServiceDied(std::function functor) +{ + auto proxy = ServiceProxy::GetInstance(); + if (proxy == nullptr || !functor) { + return; + } + auto remoteObj = proxy->AsObject(); + if (!remoteObj) { + throw BError(BError::Codes::SA_BROKEN_IPC, "Proxy's remote object can't be nullptr"); + } + + auto callback = [functor](const wptr &obj) { functor(); }; + deathRecipient_ = sptr(new SvcDeathRecipient(callback)); + remoteObj->AddDeathRecipient(deathRecipient_); +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/frameworks/native/backup_kit_inner/src/b_session_restore_async.cpp b/frameworks/native/backup_kit_inner/src/b_session_restore_async.cpp index 9336f3d95..a6443100d 100644 --- a/frameworks/native/backup_kit_inner/src/b_session_restore_async.cpp +++ b/frameworks/native/backup_kit_inner/src/b_session_restore_async.cpp @@ -17,7 +17,7 @@ #include "b_error/b_error.h" #include "b_resources/b_constants.h" -#include "b_session_restore.h" + #include "b_session_restore.h" #include "filemgmt_libhilog.h" #include "service_proxy.h" #include "service_reverse.h" diff --git a/interfaces/inner_api/native/backup_kit_inner/BUILD.gn b/interfaces/inner_api/native/backup_kit_inner/BUILD.gn index f84fc96cc..e9eda79c8 100644 --- a/interfaces/inner_api/native/backup_kit_inner/BUILD.gn +++ b/interfaces/inner_api/native/backup_kit_inner/BUILD.gn @@ -46,6 +46,7 @@ ohos_shared_library("backup_kit_inner") { "${path_backup}/frameworks/native/backup_kit_inner/src/b_incremental_backup_session.cpp", "${path_backup}/frameworks/native/backup_kit_inner/src/b_incremental_data.cpp", "${path_backup}/frameworks/native/backup_kit_inner/src/b_incremental_restore_session.cpp", + "${path_backup}/frameworks/native/backup_kit_inner/src/b_incremental_session_restore_async.cpp", "${path_backup}/frameworks/native/backup_kit_inner/src/b_session_backup.cpp", "${path_backup}/frameworks/native/backup_kit_inner/src/b_session_restore.cpp", "${path_backup}/frameworks/native/backup_kit_inner/src/b_session_restore_async.cpp", diff --git a/interfaces/inner_api/native/backup_kit_inner/backup_kit_inner.h b/interfaces/inner_api/native/backup_kit_inner/backup_kit_inner.h index b9cc25e1b..0d9925c94 100644 --- a/interfaces/inner_api/native/backup_kit_inner/backup_kit_inner.h +++ b/interfaces/inner_api/native/backup_kit_inner/backup_kit_inner.h @@ -18,6 +18,7 @@ #include "impl/b_incremental_backup_session.h" #include "impl/b_incremental_restore_session.h" +#include "impl/b_incremental_session_restore_async.h" #include "impl/b_session_backup.h" #include "impl/b_session_restore.h" #include "impl/b_session_restore_async.h" diff --git a/interfaces/inner_api/native/backup_kit_inner/impl/b_incremental_session_restore_async.h b/interfaces/inner_api/native/backup_kit_inner/impl/b_incremental_session_restore_async.h new file mode 100644 index 000000000..742c3c096 --- /dev/null +++ b/interfaces/inner_api/native/backup_kit_inner/impl/b_incremental_session_restore_async.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_FILEMGMT_BACKUP_B_INCREMENTAL_SESSION_RESTORE_ASYNC_H +#define OHOS_FILEMGMT_BACKUP_B_INCREMENTAL_SESSION_RESTORE_ASYNC_H + +#include +#include +#include +#include +#include + +#include "b_file_info.h" +#include "errors.h" +#include "i_service.h" +#include "svc_death_recipient.h" +#include "unique_fd.h" + +namespace OHOS::FileManagement::Backup { +class BIncrementalSessionRestoreAsync : public std::enable_shared_from_this { +public: + struct Callbacks { + std::function onFileReady; // 当备份服务有文件待发送时执行的回调 + std::function onBundleStarted; // 当启动某个应用的恢复流程结束时执行的回调函数 + std::function + onBundleFinished; // 当某个应用的恢复流程结束或意外中止时执行的回调函数 + std::function onAllBundlesFinished; // 当整个恢复流程结束或意外中止时执行的回调函数 + std::function onBackupServiceDied; // 当备份服务意外死亡时执行的回调函数 + }; + + struct AppendBundleInfo { + UniqueFd remoteCap; // 已打开的保存远端设备能力的Json文件 + std::vector bundlesToRestore; // 需要恢复的应用名称列表 + RestoreTypeEnum restoreType; // 待恢复类型(例如升级服务数据迁移就绪无需进行数据传输) + int32_t userId; // 用户ID + }; + +public: + /** + * @brief 获取一个用于控制恢复流程的会话 + * + * @param callbacks 注册的回调函数 + * @return std::unique_ptr 指向BRestoreSession的智能指针。失败时为空指针 + */ + static std::shared_ptr Init(Callbacks callbacks); + + /** + * @brief 通知备份服务文件内容已就绪 + * + * @param fileInfo 文件描述信息 + * @return ErrCode 规范错误码 + * @see GetFileHandle + */ + ErrCode PublishFile(BFileInfo fileInfo); + + /** + * @brief 请求恢复流程所需的真实文件 + * + * @param bundleName 应用名称 + * @param fileName 文件名称 + */ + ErrCode GetFileHandle(const std::string &bundleName, const std::string &fileName); + + /** + * @brief 用于追加待恢复应用 + * + * @param remoteCap 已打开的保存远端设备能力的Json文件。可使用GetLocalCapabilities方法获取 + * @param bundlesToRestore 待恢复的应用清单 + * @param userId 用户ID + * @return ErrCode 规范错误码 + */ + ErrCode AppendBundles(UniqueFd remoteCap, + std::vector bundlesToRestore, + RestoreTypeEnum restoreType = RestoreTypeEnum::RESTORE_DATA_WAIT_SEND, + int32_t userId = DEFAULT_INVAL_VALUE); + + /** + * @brief 用于结束服务 + * + * @return ErrCode 规范错误码 + */ + ErrCode Release(); + +public: + explicit BIncrementalSessionRestoreAsync(Callbacks callbacks) : callbacks_(callbacks) {}; + ~BIncrementalSessionRestoreAsync(); + +private: + /** @brief 注册备份服务意外死亡时执行的回调函数 */ + void OnBackupServiceDied(); + + /** + * @brief 注册备份服务意外死亡时执行的回调函数 + * + * @param functor 回调函数 + */ + void RegisterBackupServiceDied(std::function functor); + +private: + sptr deathRecipient_; + Callbacks callbacks_; + std::atomic isAppend_ {false}; + std::mutex mutex_; + std::queue workList_; +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_B_INCREMENTAL_SESSION_RESTORE_ASYNC_H \ No newline at end of file diff --git a/tools/backup_tool/BUILD.gn b/tools/backup_tool/BUILD.gn index 34f6cbbe2..f86768293 100644 --- a/tools/backup_tool/BUILD.gn +++ b/tools/backup_tool/BUILD.gn @@ -41,6 +41,7 @@ ohos_executable("backup_tool") { "src/tools_op_help.cpp", "src/tools_op_incremental_backup.cpp", "src/tools_op_incremental_restore.cpp", + "src/tools_op_incremental_restore_async.cpp", "src/tools_op_restore.cpp", "src/tools_op_restore_async.cpp", ] diff --git a/tools/backup_tool/include/tools_op_incremental_restore_async.h b/tools/backup_tool/include/tools_op_incremental_restore_async.h new file mode 100644 index 000000000..4d379776b --- /dev/null +++ b/tools/backup_tool/include/tools_op_incremental_restore_async.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_FILEMGMT_BACKUP_TOOLS_OP_INCREMENTAL_RESTORE_ASYNC_H +#define OHOS_FILEMGMT_BACKUP_TOOLS_OP_INCREMENTAL_RESTORE_ASYNC_H + +namespace OHOS::FileManagement::Backup { + bool IncrementalRestoreAsyncRegister(); + +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_TOOLS_OP_INCREMENTAL_RESTORE_ASYNC_H \ No newline at end of file diff --git a/tools/backup_tool/src/main.cpp b/tools/backup_tool/src/main.cpp index 704900544..9b977652e 100644 --- a/tools/backup_tool/src/main.cpp +++ b/tools/backup_tool/src/main.cpp @@ -29,6 +29,7 @@ int main() #include "tools_op_restore_async.h" #include "tools_op_incremental_backup.h" #include "tools_op_incremental_restore.h" +#include "tools_op_incremental_restore_async.h" #include #include @@ -87,6 +88,7 @@ void ToolRegister() OHOS::FileManagement::Backup::RestoreAsyncRegister(); OHOS::FileManagement::Backup::IncrementalBackUpRegister(); OHOS::FileManagement::Backup::IncrementalRestoreRegister(); + OHOS::FileManagement::Backup::IncrementalRestoreAsyncRegister(); } int ParseOpAndExecute(const int argc, char *const argv[]) diff --git a/tools/backup_tool/src/tools_op_incremental_restore_async.cpp b/tools/backup_tool/src/tools_op_incremental_restore_async.cpp new file mode 100644 index 000000000..fe9628ac9 --- /dev/null +++ b/tools/backup_tool/src/tools_op_incremental_restore_async.cpp @@ -0,0 +1,399 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "b_error/b_error.h" +#include "b_error/b_excep_utils.h" +#include "b_filesystem/b_dir.h" +#include "b_filesystem/b_file.h" +#include "b_json/b_json_entity_caps.h" +#include "b_json/b_json_entity_ext_manage.h" +#include "b_resources/b_constants.h" +#include "backup_kit_inner.h" +#include "directory_ex.h" +#include "errors.h" +#include "hitrace_meter.h" +#include "service_proxy.h" +#include "tools_op.h" +#include "tools_op_incremental_restore_async.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +class InrementalSessionAsync { +public: + void TryNotify(bool flag = false) + { + if (flag == true) { + ready_ = true; + cv_.notify_all(); + } else if (cnt_ == 0) { + ready_ = true; + cv_.notify_all(); + } + } + + void Wait() + { + unique_lock lk(lock_); + cv_.wait(lk, [&] { return ready_; }); + } + + void UpdateBundleFinishedCount() + { + lock_guard lk(lock_); + cnt_--; + } + + void SetBundleFinishedCount(uint32_t cnt) + { + cnt_ = cnt; + } + + shared_ptr session_ = {}; + +private: + mutable condition_variable cv_; + mutex lock_; + bool ready_ = false; + uint32_t cnt_ {0}; +}; + +static string GenHelpMsg() +{ + return "\tThis operation helps to restore application data.\n" + "\t\t--pathCapFile\t\t This parameter should be the path of the capability file.\n" + "\t\t--bundle\t\t This parameter is bundleName.\n" + "\t\t--userId\t\t This parameter is userId.\n" + "\t\t--restoreType\t\t The parameter is a bool variable. true Simulates the upgrade service scenario; false " + "simulates the application recovery scenario.\n"; +} + +static void OnFileReady(shared_ptr ctx, const BFileInfo &fileInfo, UniqueFd fd, UniqueFd rpFd) +{ + printf("FileReady owner = %s, fileName = %s, sn = %u, fd = %d\n", fileInfo.owner.c_str(), fileInfo.fileName.c_str(), + fileInfo.sn, fd.Get()); + string formatFileName = fileInfo.fileName; + // Only manage.json was in data/backup/receive; + // Other flles and tars was in data/backup/receive + bundle + path is manage.json + if (formatFileName.rfind(string(BConstants::EXT_BACKUP_MANAGE)) != string::npos) { + formatFileName = string(BConstants::EXT_BACKUP_MANAGE); + } + printf(" OnFileReady formatFileName = %s\n", formatFileName.c_str()); + + // data path: /data/backup/incrementalreceived/bundleName/{timestamp}/incremental/{filename} + // For Special clone, timestamp is always 0 + string tmpPath = string(BConstants::BACKUP_TOOL_INCREMENTAL_RECEIVE_DIR) + fileInfo.owner + "/0" + + string(BConstants::BACKUP_TOOL_INCREMENTAL) + "/" + formatFileName; + printf(" OnFileReady tmpPath = %s \n", tmpPath.c_str()); + if (access(tmpPath.data(), F_OK) != 0) { + throw BError(BError::Codes::TOOL_INVAL_ARG, generic_category().message(errno)); + } + + BExcepUltils::VerifyPath(tmpPath, false); + UniqueFd fdLocal(open(tmpPath.data(), O_RDONLY)); + if (fdLocal < 0) { + throw BError(BError::Codes::TOOL_INVAL_ARG, generic_category().message(errno)); + } + BFile::SendFile(fd, fdLocal); + int ret = ctx->session_->PublishFile(fileInfo); + if (ret != 0) { + throw BError(BError::Codes::TOOL_INVAL_ARG, "PublishFile error"); + } +} + +static void OnBundleStarted(shared_ptr ctx, ErrCode err, const BundleName name) +{ + printf("BundleStarted errCode = %d, BundleName = %s\n", err, name.c_str()); + if (err != 0) { + ctx->UpdateBundleFinishedCount(); + ctx->TryNotify(); + } +} + +static void OnBundleFinished(shared_ptr ctx, ErrCode err, const BundleName name) +{ + printf("BundleFinished errCode = %d, BundleName = %s\n", err, name.c_str()); + if (err != 0) { + ctx->UpdateBundleFinishedCount(); + ctx->TryNotify(); + } +} + +static void OnAllBundlesFinished(shared_ptr ctx, ErrCode err) +{ + printf("all bundles finished end\n"); + ctx->TryNotify(true); +} + +static void OnBackupServiceDied(shared_ptr ctx) +{ + printf("backupServiceDied\n"); + ctx->TryNotify(true); +} + +static void AdapteCloneOptimize(const string &path) +{ + string manageJosnStr = path; + manageJosnStr = manageJosnStr + BConstants::FILE_SEPARATOR_CHAR + string(BConstants::EXT_BACKUP_MANAGE); + BJsonCachedEntity cachedEntityOld(UniqueFd(open(manageJosnStr.data(), O_RDWR))); + auto cacheOld = cachedEntityOld.Structuralize(); + auto pkgInfo = cacheOld.GetExtManageInfo(); + close(cachedEntityOld.GetFd().Release()); + + map> info; + for (auto &item : pkgInfo) { + string fileName = item.hashName; + string filePath = item.fileName; + if (fileName.empty() || filePath.empty()) { + continue; + } + + // Rename big file with real name in backup/receive directory + // To support file with different path but same name, create directories in /data/backup/receive + string realNameInReceive = path + BConstants::FILE_SEPARATOR_CHAR + filePath; + string realPathInReceive = realNameInReceive.substr(0, realNameInReceive.rfind("/")); + string currentNameInReceive = path + BConstants::FILE_SEPARATOR_CHAR + fileName; + if (access(realPathInReceive.c_str(), F_OK) != 0) { + if (!ForceCreateDirectory(realPathInReceive.data())) { + printf("err create directory %d %s\n", errno, strerror(errno)); + } + } + if (rename(currentNameInReceive.data(), realNameInReceive.data()) != 0) { + printf("err rename %d %s\n", errno, strerror(errno)); + } + + // update fileName with filePath according to clone optimize + item.hashName = filePath; + if (item.hashName.front() == BConstants::FILE_SEPARATOR_CHAR) { + item.hashName = item.hashName.substr(1); + } + + // update filePath + if (!item.isBigFile && !item.isUserTar) { + item.fileName = "/"; + } else { + item.fileName = ""; + } + info.emplace(item.hashName, make_tuple(item.fileName, item.sta, item.isBigFile, item.isUserTar)); + } + + BJsonCachedEntity cachedEntity(UniqueFd(open(manageJosnStr.data(), + O_RDWR | O_CREAT, S_IRUSR | S_IWUSR))); + auto cache = cachedEntity.Structuralize(); + cache.SetExtManageForClone(info); + cachedEntity.Persist(); + close(cachedEntity.GetFd().Release()); +} + +static void RestoreApp(shared_ptr restore, vector &bundleNames) +{ + StartTrace(HITRACE_TAG_FILEMANAGEMENT, "RestoreApp"); + if (!restore || !restore->session_) { + throw BError(BError::Codes::TOOL_INVAL_ARG, generic_category().message(errno)); + } + for (auto &bundleName : bundleNames) { + if (bundleName.find('/') != string::npos) { + throw BError(BError::Codes::TOOL_INVAL_ARG, "bundleName is not valid"); + } + string tmpPath = string(BConstants::BACKUP_TOOL_INCREMENTAL_RECEIVE_DIR) + bundleName; + if (access(tmpPath.data(), F_OK) != 0) { + throw BError(BError::Codes::TOOL_INVAL_ARG, generic_category().message(errno)); + } + // For Special clone, timestamp is always 0 + tmpPath = tmpPath + "/0"; + if (access(tmpPath.data(), F_OK) != 0 && mkdir(tmpPath.data(), S_IRWXU) != 0) { + throw BError(BError::Codes::TOOL_INVAL_ARG, generic_category().message(errno)); + } + // data path: /data/backup/incrementalreceived/bundleName/{timestamp}/incremental/{filename} + string tmpDataPath = tmpPath + string(BConstants::BACKUP_TOOL_INCREMENTAL); + if (access(tmpDataPath.data(), F_OK) != 0 && mkdir(tmpDataPath.data(), S_IRWXU) != 0) { + throw BError(BError::Codes::TOOL_INVAL_ARG, generic_category().message(errno)); + } + + // update manage.json and fileName + AdapteCloneOptimize(tmpDataPath); + + // manage.json first + string manageJsonPath = string(BConstants::PATH_BUNDLE_BACKUP_HOME). + append(BConstants::SA_BUNDLE_BACKUP_RESTORE).append(BConstants::EXT_BACKUP_MANAGE); + if (manageJsonPath.front() == BConstants::FILE_SEPARATOR_CHAR) { + manageJsonPath = manageJsonPath.substr(1); + } + restore->session_->GetFileHandle(bundleName, manageJsonPath); + + string manageJsonStr = tmpDataPath + BConstants::FILE_SEPARATOR_CHAR + string(BConstants::EXT_BACKUP_MANAGE); + BJsonCachedEntity cachedEntity(UniqueFd(open(manageJsonStr.data(), O_RDONLY))); + auto cache = cachedEntity.Structuralize(); + auto pkgInfo = cache.GetExtManageInfo(); + for (auto &item : pkgInfo) { + printf("New FileName %s\n", item.hashName.data()); + restore->session_->GetFileHandle(bundleName, item.hashName); + } + } + FinishTrace(HITRACE_TAG_FILEMANAGEMENT); +} + +static int32_t ChangeBundleInfo(const string &pathCapFile, const vector &bundleNames, const string &type) +{ + BExcepUltils::VerifyPath(pathCapFile, false); + UniqueFd fd(open(pathCapFile.data(), O_RDWR, S_IRWXU)); + if (fd < 0) { + fprintf(stderr, "Failed to open file error: %d %s\n", errno, strerror(errno)); + FinishTrace(HITRACE_TAG_FILEMANAGEMENT); + return -errno; + } + BJsonCachedEntity cachedEntity(move(fd)); + auto cache = cachedEntity.Structuralize(); + vector bundleInfos; + auto cacheBundleInfos = cache.GetBundleInfos(); + for (auto name : bundleNames) { + string versionName = string(BConstants::DEFAULT_VERSION_NAME); + uint32_t versionCode = static_cast(BConstants::DEFAULT_VERSION_CODE); + if (type == "false") { + versionName = string(BConstants::DEFAULT_VERSION_NAME_CLONE); + versionCode = static_cast(BConstants::DEFAULT_VERSION_CODE); + } + for (auto &&bundleInfo : cacheBundleInfos) { + if (bundleInfo.name != name) { + continue; + } + bundleInfos.emplace_back(BJsonEntityCaps::BundleInfo {.name = name, + .versionCode = versionCode, + .versionName = versionName, + .spaceOccupied = bundleInfo.spaceOccupied, + .allToBackup = bundleInfo.allToBackup, + .extensionName = bundleInfo.extensionName}); + } + } + cache.SetBundleInfos(bundleInfos); + cachedEntity.Persist(); + + return 0; +} + +static int32_t AppendBundles(shared_ptr restore, + const string &pathCapFile, + vector bundleNames, + const string &type, + const string &userId) +{ + BExcepUltils::VerifyPath(pathCapFile, false); + UniqueFd fd(open(pathCapFile.data(), O_RDWR, S_IRWXU)); + if (fd < 0) { + fprintf(stderr, "Failed to open file error: %d %s\n", errno, strerror(errno)); + FinishTrace(HITRACE_TAG_FILEMANAGEMENT); + return -errno; + } + RestoreTypeEnum restoreType = RestoreTypeEnum::RESTORE_DATA_WAIT_SEND; + if (type == "true") { + restoreType = RestoreTypeEnum::RESTORE_DATA_READDY; + } + try { + int ret = restore->session_->AppendBundles(move(fd), bundleNames, restoreType, atoi(userId.data())); + if (ret != 0) { + printf("restore append bundles error: %d\n", ret); + return -ret; + } + if (type == "false") { + RestoreApp(restore, bundleNames); + } + } catch (const BError &e) { + printf("restore append bundles error: %d\n", e.GetCode()); + return -1; + } catch (...) { + printf("Unexpected exception"); + return -1; + } + restore->Wait(); + return 0; +} + +static int32_t InitArg(const string &pathCapFile, + const vector &bundleNames, + const string &type, + const string &userId) +{ + StartTrace(HITRACE_TAG_FILEMANAGEMENT, "Init"); + BExcepUltils::VerifyPath(pathCapFile, false); + + if (ChangeBundleInfo(pathCapFile, bundleNames, type)) { + fprintf(stderr, "ChangeBundleInfo error"); + return -errno; + } + + auto ctx = make_shared(); + ctx->session_ = BIncrementalSessionRestoreAsync::Init(BIncrementalSessionRestoreAsync::Callbacks { + .onFileReady = bind(OnFileReady, ctx, placeholders::_1, placeholders::_2, placeholders::_3), + .onBundleStarted = bind(OnBundleStarted, ctx, placeholders::_1, placeholders::_2), + .onBundleFinished = bind(OnBundleFinished, ctx, placeholders::_1, placeholders::_2), + .onAllBundlesFinished = bind(OnAllBundlesFinished, ctx, placeholders::_1), + .onBackupServiceDied = bind(OnBackupServiceDied, ctx)}); + if (ctx->session_ == nullptr) { + printf("Failed to init restore\n"); + FinishTrace(HITRACE_TAG_FILEMANAGEMENT); + return -EPERM; + } + ctx->SetBundleFinishedCount(bundleNames.size()); + return AppendBundles(ctx, pathCapFile, bundleNames, type, userId); +} + +static int g_exec(map> &mapArgToVal) +{ + if (mapArgToVal.find("pathCapFile") == mapArgToVal.end() || mapArgToVal.find("bundles") == mapArgToVal.end() || + mapArgToVal.find("restoreType") == mapArgToVal.end() || mapArgToVal.find("userId") == mapArgToVal.end()) { + return -EPERM; + } + return InitArg(*(mapArgToVal["pathCapFile"].begin()), mapArgToVal["bundles"], *(mapArgToVal["restoreType"].begin()), + *(mapArgToVal["userId"].begin())); +} + +bool IncrementalRestoreAsyncRegister() +{ + return ToolsOp::Register(ToolsOp {ToolsOp::Descriptor { + .opName = {"incrementalRestoreAsync"}, + .argList = {{ + .paramName = "pathCapFile", + .repeatable = false, + }, + { + .paramName = "bundles", + .repeatable = true, + }, + { + .paramName = "restoreType", + .repeatable = true, + }, + { + .paramName = "userId", + .repeatable = true, + }}, + .funcGenHelpMsg = GenHelpMsg, + .funcExec = g_exec, + }}); +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/utils/include/b_resources/b_constants.h b/utils/include/b_resources/b_constants.h index 414956a10..2be87bb69 100644 --- a/utils/include/b_resources/b_constants.h +++ b/utils/include/b_resources/b_constants.h @@ -141,6 +141,9 @@ static inline std::string_view BACKUP_CONFIG_JSON = "backup_config.json"; // 简报文件名后缀 static inline std::string_view REPORT_FILE_EXT = "rp"; +// 空简报 +static inline std::string BLANK_REPORT_NAME = "blankReport.rp"; + // 特殊版本信息 constexpr int DEFAULT_VERSION_CODE = 0; static inline std::string_view DEFAULT_VERSION_NAME = "0.0.0.0"; -- Gitee