diff --git a/bundle.json b/bundle.json index 64feb645ce7a20ba40f8d90e2867aa14b33c926d..46b36eb5a991c8e8e3226f6c54918630c5338df2 100644 --- a/bundle.json +++ b/bundle.json @@ -90,6 +90,7 @@ "header_files": [ "backup_kit_inner.h", "impl/b_session_restore.h", + "impl/b_session_restore_async.h", "impl/b_file_info.h", "impl/service_proxy.h", "impl/b_session_backup.h", diff --git a/frameworks/native/backup_kit_inner/include/service_reverse.h b/frameworks/native/backup_kit_inner/include/service_reverse.h index f0810e14a037ff8cc44e641e5f05b7274313398f..86eee8c5bc10e7cf5ee25162e380b85b0cf74311 100644 --- a/frameworks/native/backup_kit_inner/include/service_reverse.h +++ b/frameworks/native/backup_kit_inner/include/service_reverse.h @@ -18,6 +18,7 @@ #include "b_session_backup.h" #include "b_session_restore.h" +#include "b_session_restore_async.h" #include "service_reverse_stub.h" namespace OHOS::FileManagement::Backup { @@ -37,12 +38,14 @@ public: ServiceReverse() = delete; explicit ServiceReverse(BSessionRestore::Callbacks callbacks); explicit ServiceReverse(BSessionBackup::Callbacks callbacks); + explicit ServiceReverse(BSessionRestoreAsync::Callbacks callbacks); ~ServiceReverse() override = default; private: Scenario scenario_ {Scenario::UNDEFINED}; BSessionBackup::Callbacks callbacksBackup_; BSessionRestore::Callbacks callbacksRestore_; + BSessionRestoreAsync::Callbacks callbacksRestoreAsync_; }; } // namespace OHOS::FileManagement::Backup 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 new file mode 100644 index 0000000000000000000000000000000000000000..0a9a75740eb00bf379e9b0f0c93d1ca2d5e63a72 --- /dev/null +++ b/frameworks/native/backup_kit_inner/src/b_session_restore_async.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2022-2023 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_session_restore_async.h" + +#include "b_error/b_error.h" +#include "b_resources/b_constants.h" +#include "filemgmt_libhilog.h" +#include "service_reverse.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +BSessionRestoreAsync::BSessionRestoreAsync(Callbacks callbacks) : callbacks_(callbacks) {} + +BSessionRestoreAsync::~BSessionRestoreAsync() +{ + 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 +shared_ptr BSessionRestoreAsync::Init(Callbacks callbacks) +{ + try { + auto restore = make_shared(callbacks); + return restore; + } catch (const exception &e) { + HILOGE("Failed to Restore because of %{public}s", e.what()); + } + return nullptr; +} + +ErrCode BSessionRestoreAsync::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->PublishFile(fileInfo); +} + +ErrCode BSessionRestoreAsync::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->GetFileHandle(bundleName, fileName); +} + +ErrCode BSessionRestoreAsync::AppendBundles(UniqueFd remoteCap, + vector bundlesToRestore, + RestoreTpyeEnum restoreType, + int32_t userId) +{ + { + std::unique_lock lock(mutex_); + workList_.push({move(remoteCap), move(bundlesToRestore), restoreType, userId}); + } + + if (isAppend_.exchange(true)) { + return ERR_OK; + } else { + PopBundleInfo(); + } + + return ERR_OK; +} + +void BSessionRestoreAsync::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_); +} + +void BSessionRestoreAsync::OnBackupServiceDied() +{ + HILOGE("Backup service died"); + if (callbacks_.onBackupServiceDied) { + callbacks_.onBackupServiceDied(); + } + deathRecipient_ = nullptr; + ServiceProxy::InvaildInstance(); + PopBundleInfo(); +} + +void BSessionRestoreAsync::PopBundleInfo() +{ + AppendBundleInfo info; + isAppend_.store(true); + { + std::unique_lock lock(mutex_); + if (workList_.empty()) { + isAppend_.store(false); + return; + } + info = move(workList_.front()); + workList_.pop(); + } + AppendBundlesAsync(move(info)); +} + +void BSessionRestoreAsync::AppendBundlesAsync(AppendBundleInfo info) +{ + auto proxy = ServiceProxy::GetInstance(); + if (proxy == nullptr) { + BError(BError::Codes::SDK_BROKEN_IPC, "Failed to get backup service").GetCode(); + } + auto onBackupServiceDied = bind(&BSessionRestoreAsync::OnBackupServiceDied, shared_from_this()); + RegisterBackupServiceDied(onBackupServiceDied); + + Callbacks callbacksTmp {.onFileReady = callbacks_.onFileReady, + .onBundleStarted = callbacks_.onBundleStarted, + .onBundleFinished = callbacks_.onBundleFinished, + .onAllBundlesFinished = callbacks_.onAllBundlesFinished, + .onBackupServiceDied = onBackupServiceDied}; + int32_t res = proxy->InitRestoreSession(new ServiceReverse(callbacksTmp)); + if (res != 0) { + HILOGE("Failed to Restore because of %{public}d", res); + BError(BError::Codes::SDK_BROKEN_IPC, "Failed to int restore session").GetCode(); + } + res = + proxy->AppendBundlesRestoreSession(move(info.remoteCap), info.bundlesToRestore, info.restoreType, info.userId); + if (res != 0) { + HILOGE("Failed to Restore because of %{public}d", res); + BError(BError::Codes::SDK_BROKEN_IPC, "Failed to append bundles").GetCode(); + } +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/frameworks/native/backup_kit_inner/src/service_reverse.cpp b/frameworks/native/backup_kit_inner/src/service_reverse.cpp index 78b73f09b625adb625c66069e12c51c957ad58a1..0f9ee22c8e5ff633d507f4f5d677e1d31b59b34b 100644 --- a/frameworks/native/backup_kit_inner/src/service_reverse.cpp +++ b/frameworks/native/backup_kit_inner/src/service_reverse.cpp @@ -65,42 +65,51 @@ void ServiceReverse::BackupOnAllBundlesFinished(int32_t errCode) void ServiceReverse::RestoreOnBundleStarted(int32_t errCode, string bundleName) { HILOGI("begin"); - if (scenario_ != Scenario::RESTORE || !callbacksRestore_.onBundleStarted) { + if (scenario_ == Scenario::RESTORE && callbacksRestore_.onBundleStarted) { + callbacksRestore_.onBundleStarted(errCode, bundleName); + } else if (scenario_ == Scenario::RESTORE && callbacksRestoreAsync_.onBundleStarted) { + callbacksRestoreAsync_.onBundleStarted(errCode, bundleName); + } else { HILOGI("Error scenario or callback is nullptr"); - return; } - callbacksRestore_.onBundleStarted(errCode, bundleName); } void ServiceReverse::RestoreOnBundleFinished(int32_t errCode, string bundleName) { HILOGI("begin"); - if (scenario_ != Scenario::RESTORE || !callbacksRestore_.onBundleFinished) { + if (scenario_ == Scenario::RESTORE && callbacksRestore_.onBundleFinished) { + callbacksRestore_.onBundleFinished(errCode, bundleName); + } else if (scenario_ == Scenario::RESTORE && callbacksRestoreAsync_.onBundleFinished) { + callbacksRestoreAsync_.onBundleFinished(errCode, bundleName); + } else { HILOGI("Error scenario or callback is nullptr"); - return; } - callbacksRestore_.onBundleFinished(errCode, bundleName); } void ServiceReverse::RestoreOnAllBundlesFinished(int32_t errCode) { HILOGI("errCode = %{public}d", errCode); - if (scenario_ != Scenario::RESTORE || !callbacksRestore_.onAllBundlesFinished) { + if (scenario_ == Scenario::RESTORE && callbacksRestore_.onAllBundlesFinished) { + callbacksRestore_.onAllBundlesFinished(errCode); + } else if (scenario_ == Scenario::RESTORE && callbacksRestoreAsync_.onAllBundlesFinished) { + callbacksRestoreAsync_.onAllBundlesFinished(errCode); + } else { HILOGI("Error scenario or callback is nullptr"); - return; } - callbacksRestore_.onAllBundlesFinished(errCode); + } void ServiceReverse::RestoreOnFileReady(string bundleName, string fileName, int fd) { HILOGI("begin"); - if (scenario_ != Scenario::RESTORE || !callbacksRestore_.onFileReady) { + BFileInfo bFileInfo(bundleName, fileName, 0); + if (scenario_ == Scenario::RESTORE && callbacksRestore_.onFileReady) { + callbacksRestore_.onFileReady(bFileInfo, UniqueFd(fd)); + } else if (scenario_ == Scenario::RESTORE && callbacksRestoreAsync_.onFileReady) { + callbacksRestoreAsync_.onFileReady(bFileInfo, UniqueFd(fd)); + } else { HILOGI("Error scenario or callback is nullptr"); - return; } - BFileInfo bFileInfo(bundleName, fileName, 0); - callbacksRestore_.onFileReady(bFileInfo, UniqueFd(fd)); } ServiceReverse::ServiceReverse(BSessionBackup::Callbacks callbacks) @@ -112,4 +121,9 @@ ServiceReverse::ServiceReverse(BSessionRestore::Callbacks callbacks) : scenario_(Scenario::RESTORE), callbacksRestore_(callbacks) { } + +ServiceReverse::ServiceReverse(BSessionRestoreAsync::Callbacks callbacks) + : scenario_(Scenario::RESTORE), callbacksRestoreAsync_(callbacks) +{ +} } // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/interfaces/inner_api/native/backup_kit_inner/BUILD.gn b/interfaces/inner_api/native/backup_kit_inner/BUILD.gn index b1b64c573e00eb5be799b249f2e04dadcae0eb4d..3abaf9b925b40b53002387e2851f300a63dfe703 100644 --- a/interfaces/inner_api/native/backup_kit_inner/BUILD.gn +++ b/interfaces/inner_api/native/backup_kit_inner/BUILD.gn @@ -35,6 +35,7 @@ ohos_shared_library("backup_kit_inner") { "${path_backup}/frameworks/native/backup_kit_inner/src/b_file_info.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", "${path_backup}/frameworks/native/backup_kit_inner/src/service_proxy.cpp", "${path_backup}/frameworks/native/backup_kit_inner/src/service_reverse.cpp", "${path_backup}/frameworks/native/backup_kit_inner/src/service_reverse_stub.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 b003556271d95ab232d64af5a0ffa3aa6d301d14..7277da994b9f9fe3d73e476f00df3c7ba47c1254 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,5 +18,6 @@ #include "impl/b_session_backup.h" #include "impl/b_session_restore.h" +#include "impl/b_session_restore_async.h" #endif // OHOS_FILEMGMT_BACKUP_BACKUP_KIT_INNER_H \ No newline at end of file diff --git a/interfaces/inner_api/native/backup_kit_inner/impl/b_session_restore_async.h b/interfaces/inner_api/native/backup_kit_inner/impl/b_session_restore_async.h new file mode 100644 index 0000000000000000000000000000000000000000..30e828d6e80c9b748c46850086f59c1b6b4649a3 --- /dev/null +++ b/interfaces/inner_api/native/backup_kit_inner/impl/b_session_restore_async.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2022-2023 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_SESSION_RESTORE_ASYNC_H +#define OHOS_FILEMGMT_BACKUP_B_SESSION_RESTORE_ASYNC_H + +#include +#include +#include +#include +#include + +#include "b_file_info.h" +#include "errors.h" +#include "service_proxy.h" +#include "svc_death_recipient.h" +#include "unique_fd.h" + +namespace OHOS::FileManagement::Backup { +class BSessionRestoreAsync : 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; + std::vector bundlesToRestore; + RestoreTpyeEnum restoreType; + int32_t userId; + }; + +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, + RestoreTpyeEnum restoreType = RestoreTpyeEnum::RESTORE_DATA_WAIT_SEND, + int32_t userId = DEFAULT_INVAL_VALUE); + + /** + * @brief 注册备份服务意外死亡时执行的回调函数 + * + * @param functor 回调函数 + */ + void RegisterBackupServiceDied(std::function functor); + +public: + BSessionRestoreAsync(Callbacks callbacks); + ~BSessionRestoreAsync(); + +private: + void OnBackupServiceDied(); + + void PopBundleInfo(); + + void AppendBundlesAsync(AppendBundleInfo info); + +private: + sptr deathRecipient_; + Callbacks callbacks_; + std::atomic isAppend_ {false}; + std::mutex mutex_; + std::queue workList_; +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_B_SESSION_RESTORE_ASYNC_H \ No newline at end of file diff --git a/services/backup_sa/src/module_ipc/service.cpp b/services/backup_sa/src/module_ipc/service.cpp index 9d1097f7f884c9332320a7be7ea2845008c57fda..8f08e1a558e82182ea508a4073759842220d4c89 100644 --- a/services/backup_sa/src/module_ipc/service.cpp +++ b/services/backup_sa/src/module_ipc/service.cpp @@ -198,7 +198,7 @@ ErrCode Service::Start() HILOGI("Begin"); VerifyCaller(session_->GetScenario()); session_->Start(); - OnStartSched(); + // OnStartSched(); return BError(BError::Codes::OK); } @@ -246,7 +246,7 @@ ErrCode Service::Finish() HILOGI("Begin"); VerifyCaller(session_->GetScenario()); session_->Finish(); - OnAllBundlesFinished(BError(BError::Codes::OK)); + // OnAllBundlesFinished(BError(BError::Codes::OK)); return BError(BError::Codes::OK); } diff --git a/tools/backup_tool/BUILD.gn b/tools/backup_tool/BUILD.gn index f27c0d80ef2db3d426ba3dd3078a116d6292a9e3..6d8c5f5ed9c33d841576f3a68d563531d992eef9 100644 --- a/tools/backup_tool/BUILD.gn +++ b/tools/backup_tool/BUILD.gn @@ -22,6 +22,7 @@ ohos_executable("backup_tool") { "src/tools_op_check_sa.cpp", "src/tools_op_help.cpp", "src/tools_op_restore.cpp", + "src/tools_op_restore_async.cpp", ] defines = [ diff --git a/tools/backup_tool/src/tools_op_restore_async.cpp b/tools/backup_tool/src/tools_op_restore_async.cpp new file mode 100644 index 0000000000000000000000000000000000000000..73eb147633fbdeb690f988f44cda093d86d6d1cd --- /dev/null +++ b/tools/backup_tool/src/tools_op_restore_async.cpp @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2022-2023 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 "errors.h" +#include "hitrace_meter.h" +#include "service_proxy.h" +#include "tools_op.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +class SessionAsync { +public: + void TryNotify(bool flag = false) + { + if (flag == true) { + ready_ = true; + cv_.notify_all(); + } + } + + void Wait() + { + unique_lock lk(lock_); + cv_.wait(lk, [&] { return ready_; }); + } + + shared_ptr session_ = {}; + +private: + mutable condition_variable cv_; + mutex lock_; + bool ready_ = false; +}; + +static string GenHelpMsg() +{ + return "\t\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--type\t\t This parameter is a bool variable. In true case, no data is sent, in false case, data " + "is waiting to be sent.\n"; +} + +static void OnFileReady(shared_ptr ctx, const BFileInfo &fileInfo, UniqueFd fd) +{ + printf("FileReady owner = %s, fileName = %s, sn = %u, fd = %d\n", fileInfo.owner.c_str(), fileInfo.fileName.c_str(), + fileInfo.sn, fd.Get()); + if (!regex_match(fileInfo.fileName, regex("^[0-9a-zA-Z_.]+$")) && + fileInfo.fileName != BConstants::RESTORE_INSTALL_PATH) { + throw BError(BError::Codes::TOOL_INVAL_ARG, "Filename is not alphanumeric"); + } + string tmpPath; + if (fileInfo.fileName == BConstants::RESTORE_INSTALL_PATH) { + printf("OnFileReady bundle hap\n"); + tmpPath = string(BConstants::BACKUP_TOOL_INSTALL_DIR) + fileInfo.owner + ".hap"; + } else { + tmpPath = string(BConstants::BACKUP_TOOL_RECEIVE_DIR) + fileInfo.owner + "/" + fileInfo.fileName; + } + if (access(tmpPath.data(), F_OK) != 0) { + throw BError(BError::Codes::TOOL_INVAL_ARG, generic_category().message(errno)); + } + 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->TryNotify(true); + } +} + +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->TryNotify(true); + } +} + +static void OnAllBundlesFinished(shared_ptr ctx, ErrCode err) +{ + printf("AllBundlesFinished errCode = %d\n", err); + if (err != 0) { + ctx->TryNotify(true); + } +} + +static void OnBackupServiceDied(shared_ptr ctx) +{ + printf("backupServiceDied\n"); + ctx->TryNotify(true); +} + +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 (!regex_match(bundleName, regex("^[0-9a-zA-Z_.]+$"))) { + throw BError(BError::Codes::TOOL_INVAL_ARG, "bundleName is not alphanumeric"); + } + string path = string(BConstants::BACKUP_TOOL_RECEIVE_DIR) + bundleName; + if (access(path.data(), F_OK) != 0) { + throw BError(BError::Codes::TOOL_INVAL_ARG, generic_category().message(errno)); + } + const auto [err, filePaths] = BDir::GetDirFiles(path); + if (err != 0) { + throw BError(BError::Codes::TOOL_INVAL_ARG, "error path"); + } + // install bundle.hap + string installPath = string(BConstants::BACKUP_TOOL_INSTALL_DIR) + bundleName + ".hap"; + if (access(installPath.data(), F_OK) == 0) { + printf("install bundle hap %s\n", installPath.c_str()); + restore->session_->GetFileHandle(bundleName, string(BConstants::RESTORE_INSTALL_PATH)); + } + for (auto &filePath : filePaths) { + string fileName = filePath.substr(filePath.rfind("/") + 1); + restore->session_->GetFileHandle(bundleName, fileName); + } + } + FinishTrace(HITRACE_TAG_FILEMANAGEMENT); +} + +static int32_t ChangeBundleInfo(const string &pathCapFile, const vector &bundleNames, const string &type) +{ + 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 infos = cache.GetBundleInfos(); + vector bundleInfos; + for (auto name : bundleNames) { + string versionName = "0.0.0.0"; + int32_t versionCode = 0; + if (type == "false") { + auto iter = find_if(infos.begin(), infos.end(), [name](const auto &it) { return it.name == name; }); + if (iter == infos.end()) { + versionName = "1.0.0.0"; + versionCode = 0; + } else { + versionName = iter->versionName; + versionCode = iter->versionCode; + } + } + string installPath = string(BConstants::BACKUP_TOOL_INSTALL_DIR) + name + ".hap"; + bool needToInstall = false; + if (access(installPath.data(), F_OK) == 0) { + needToInstall = true; + } + if (type == "true") { + versionName = "0.0.0.0"; + versionCode = 0; + } + bundleInfos.emplace_back(BJsonEntityCaps::BundleInfo { + .name = name, .needToInstall = needToInstall, .versionCode = versionCode, .versionName = versionName}); + } + cache.SetBundleInfos(bundleInfos); + cachedEntity.Persist(); + + return 0; +} + +static int32_t AppendBundles(shared_ptr restore, + const string &pathCapFile, + vector bundleNames, + const string &type, + const string &useId) +{ + 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; + } + RestoreTpyeEnum restoreType = RestoreTpyeEnum::RESTORE_DATA_WAIT_SEND; + if (type == "true") { + restoreType = RestoreTpyeEnum::RESTORE_DATA_READDY; + } + int ret = restore->session_->AppendBundles(move(fd), bundleNames, restoreType, atoi(useId.data())); + if (ret != 0) { + printf("restore append bundles error: %d\n", ret); + return -ret; + } + if (type == "false") { + RestoreApp(restore, bundleNames); + } + restore->Wait(); + return 0; +} + +static int32_t InitArg(const string &pathCapFile, vector bundleNames, const string &type, const string &useId) +{ + 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_ = BSessionRestoreAsync::Init(BSessionRestoreAsync::Callbacks { + .onFileReady = bind(OnFileReady, ctx, placeholders::_1, placeholders::_2), + .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; + } + + return AppendBundles(ctx, pathCapFile, bundleNames, type, useId); +} + +static int Exec(map> &mapArgToVal) +{ + if (mapArgToVal.find("pathCapFile") == mapArgToVal.end() || mapArgToVal.find("bundles") == mapArgToVal.end() || + mapArgToVal["type"].empty() || mapArgToVal["userId"].empty()) { + return -EPERM; + } + return InitArg(*(mapArgToVal["pathCapFile"].begin()), mapArgToVal["bundles"], *(mapArgToVal["type"].begin()), + *(mapArgToVal["userId"].begin())); +} + +/** + * @brief The hack behind is that "variable with static storage duration has initialization or a destructor with side + * effects; it shall not be eliminated even if it appears to be unused" -- point 2.[basic.stc.static].c++ draft + * + */ +static bool g_autoRegHack = ToolsOp::Register(ToolsOp {ToolsOp::Descriptor { + .opName = {"restoreAsync"}, + .argList = {{ + .paramName = "pathCapFile", + .repeatable = false, + }, + { + .paramName = "bundles", + .repeatable = true, + }, + { + .paramName = "type", + .repeatable = true, + }, + { + .paramName = "userId", + .repeatable = true, + }}, + .funcGenHelpMsg = GenHelpMsg, + .funcExec = Exec, +}}); +} // namespace OHOS::FileManagement::Backup \ No newline at end of file