diff --git a/frameworks/native/backup_ext/include/ext_backup.h b/frameworks/native/backup_ext/include/ext_backup.h index 570bdac446ea509a775d3de3b2b157d448d6cfb1..395290b8ec3ca2ae7c03fda0216a30ef3a1504c9 100644 --- a/frameworks/native/backup_ext/include/ext_backup.h +++ b/frameworks/native/backup_ext/include/ext_backup.h @@ -196,6 +196,7 @@ protected: std::string backupExtInfo_; int64_t appVersionCode_; int restoreType_; + std::string oldBackupVersion_; private: BConstants::ExtensionAction VerifyAndGetAction(const AAFwk::Want &want, diff --git a/frameworks/native/backup_ext/src/ext_backup.cpp b/frameworks/native/backup_ext/src/ext_backup.cpp index 53da3a7ea9b9c2cf6393b9cd3208f7897e3627ef..92e37c8b70cca78cc93f9781285974a70d349fb6 100644 --- a/frameworks/native/backup_ext/src/ext_backup.cpp +++ b/frameworks/native/backup_ext/src/ext_backup.cpp @@ -165,8 +165,10 @@ ErrCode ExtBackup::GetParament(const AAFwk::Want &want) appVersionCode_ = want.GetLongParam(BConstants::EXTENSION_VERSION_CODE_PARA, 0); restoreType_ = want.GetIntParam(BConstants::EXTENSION_RESTORE_TYPE_PARA, 0); restoreExtInfo_ = want.GetStringParam(BConstants::EXTENSION_RESTORE_EXT_INFO_PARA); + oldBackupVersion_ = want.GetStringParam(BConstants::EXTENSION_OLD_BACKUP_VERSION_PARA); HILOGI("restoreExtInfo_ is %{public}s", GetAnonyString(restoreExtInfo_).c_str()); HILOGI("Get version %{public}s type %{public}d from want when restore.", appVersionStr_.c_str(), restoreType_); + HILOGI("oldBackupVersion_ is %{public}s", oldBackupVersion_.c_str()); } else if (extAction_ == BConstants::ExtensionAction::BACKUP) { backupExtInfo_ = want.GetStringParam(BConstants::EXTENSION_BACKUP_EXT_INFO_PARA); HILOGI("backupExtInfo_ is %{public}s", backupExtInfo_.c_str()); diff --git a/interfaces/kits/js/backup/prop_n_exporter.cpp b/interfaces/kits/js/backup/prop_n_exporter.cpp index cbec6854a8e09bba1fc01b8fc10dd922c679f348..adddc5128246a86a6d2fc43d0fee659028f46997 100644 --- a/interfaces/kits/js/backup/prop_n_exporter.cpp +++ b/interfaces/kits/js/backup/prop_n_exporter.cpp @@ -27,6 +27,7 @@ bool PropNExporter::Export() NVal::DeclareNapiFunction("getBackupInfo", PropNOperation::DoGetBackupInfo), NVal::DeclareNapiFunction("updateTimer", PropNOperation::DoUpdateTimer), NVal::DeclareNapiFunction("updateSendRate", PropNOperation::DoUpdateSendRate), + NVal::DeclareNapiFunction("getBackupVersion", PropNOperation::DoGetBackupVersion), }); } diff --git a/interfaces/kits/js/backup/prop_n_operation.cpp b/interfaces/kits/js/backup/prop_n_operation.cpp index 08031fb076a632949288bfa53c66f08769b0efcb..d044890ab38ba008483704c8bb351ad2322e8366 100644 --- a/interfaces/kits/js/backup/prop_n_operation.cpp +++ b/interfaces/kits/js/backup/prop_n_operation.cpp @@ -378,4 +378,28 @@ napi_value PropNOperation::DoUpdateSendRate(napi_env env, napi_callback_info inf HILOGI("DoUpdateSendRate success with result: %{public}d", result); return nResult; } + +napi_value PropNOperation::DoGetBackupVersion(napi_env env, napi_callback_info info) +{ + HILOGD("called DoGetBackupVersion begin"); + if (!SAUtils::CheckBackupPermission()) { + HILOGE("Has not permission!"); + NError(E_PERMISSION).ThrowErr(env); + return nullptr; + } + if (!SAUtils::IsSystemApp()) { + HILOGE("System App check fail!"); + NError(E_PERMISSION_SYS).ThrowErr(env); + return nullptr; + } + std::string result = BConstants::BACKUP_VERSION; + napi_value nResult; + napi_status status = napi_create_string_utf8(env, result.c_str(), result.size(), &nResult); + if (status != napi_ok) { + HILOGE("napi_create_string_utf8 faild."); + return nullptr; + } + HILOGI("DoGetBackupVersion success with result: %{public}s", result.c_str()); + return nResult; +} } // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/interfaces/kits/js/backup/prop_n_operation.h b/interfaces/kits/js/backup/prop_n_operation.h index 7137d8d14d7ac98fc9586306a4e0781752d61b04..94dd1d5e1e7fd757132bd25383259e81307c8af3 100644 --- a/interfaces/kits/js/backup/prop_n_operation.h +++ b/interfaces/kits/js/backup/prop_n_operation.h @@ -25,6 +25,7 @@ public: static napi_value DoGetBackupInfo(napi_env env, napi_callback_info info); static napi_value DoUpdateTimer(napi_env env, napi_callback_info info); static napi_value DoUpdateSendRate(napi_env env, napi_callback_info info); + static napi_value DoGetBackupVersion(napi_env env, napi_callback_info info); private: static bool UpdateTimer(std::string &bundleName, uint32_t timeout); static bool UpdateSendRate(std::string &bundleName, int32_t sendRate); diff --git a/services/backup_sa/include/module_ipc/service.h b/services/backup_sa/include/module_ipc/service.h index 1b92cc342064fb7333e4bf19fb8b695165fa3214..e5002ecf9214a4ccac1b9f52d1ff975a9bfc601d 100644 --- a/services/backup_sa/include/module_ipc/service.h +++ b/services/backup_sa/include/module_ipc/service.h @@ -396,11 +396,12 @@ private: * @param bundleNameDetailMap bundle和detail的对应关系 * @param isClearDataFlags 清理数据标志集合 * @param restoreType 任务类型 + * @param backupVersion 旧机backupVersion */ void SetCurrentSessProperties(std::vector &restoreBundleInfos, std::vector &restoreBundleNames, std::map> &bundleNameDetailMap, - std::map &isClearDataFlags, RestoreTypeEnum restoreType); + std::map &isClearDataFlags, RestoreTypeEnum restoreType, std::string &backupVersion); /** * @brief set session info @@ -408,9 +409,10 @@ private: * @param restoreBundleInfos: bundles to be restored * @param restoreBundleNames: bundles info to be restored * @param restoreType: retore type + * @param backupVersion backupVersion of old device */ void SetCurrentSessProperties(std::vector &restoreBundleInfos, - std::vector &restoreBundleNames, RestoreTypeEnum restoreType); + std::vector &restoreBundleNames, RestoreTypeEnum restoreType, std::string &backupVersion); void SetCurrentSessProperties(BJsonEntityCaps::BundleInfo &info, std::map &isClearDataFlags, const std::string &bundleNameIndexInfo); @@ -547,6 +549,8 @@ private: void ClearFailedBundles(); void CreateDirIfNotExist(const std::string &path); + + void GetOldDeviceBackupVersion(); std::vector GetSupportBackupBundleNames(vector &bundleInfos, bool isIncBackup, const vector &srcBundleNames); diff --git a/services/backup_sa/include/module_ipc/svc_session_manager.h b/services/backup_sa/include/module_ipc/svc_session_manager.h index a3656084e4c83d320f9b72f0154ecab5b842b2c9..1d63fdf2bdecd8e7b63a89adf5015e705c1acbcc 100644 --- a/services/backup_sa/include/module_ipc/svc_session_manager.h +++ b/services/backup_sa/include/module_ipc/svc_session_manager.h @@ -91,6 +91,7 @@ public: int32_t userId {100}; RestoreTypeEnum restoreDataType {RESTORE_DATA_WAIT_SEND}; bool isIncrementalBackup {false}; + std::string oldBackupVersion {""}; }; public: @@ -499,6 +500,18 @@ public: */ void SetMemParaCurSize(int32_t size); + /** + * @brief Set the old device backup version object + * + * @param backupVersion + */ + void SetOldBackupVersion(const std::string &backupVersion); + + /** + * @brief Get the old device backup version object + */ + std::string GetOldBackupVersion(); + bool ValidRestoreDataType(RestoreTypeEnum restoreType); Impl GetImpl(); diff --git a/services/backup_sa/src/module_ipc/service.cpp b/services/backup_sa/src/module_ipc/service.cpp index 3f9f76ef441666062b3b2564a43486d96ad39d6d..330ca702161e1f494712bc78c92ae38c34e6f150 100644 --- a/services/backup_sa/src/module_ipc/service.cpp +++ b/services/backup_sa/src/module_ipc/service.cpp @@ -104,6 +104,15 @@ static inline int32_t GetUserIdDefault() return multiuser.userId; } +void Service::GetOldDeviceBackupVersion() +{ + std::string oldBackupVersion = session_->GetOldBackupVersion(); + if (oldBackupVersion.empty()) { + HILOGE("Failed to get backupVersion of old device"); + } + HILOGI("backupVersion of old device = %{public}s", oldBackupVersion.c_str()); +} + void OnStartResRadarReport(const std::vector &bundleNameList, int32_t stage) { std::stringstream ss; @@ -293,7 +302,8 @@ UniqueFd Service::GetLocalCapabilities() BJsonCachedEntity cachedEntity(std::move(fd)); auto cache = cachedEntity.Structuralize(); - + std::string backupVersion = BJsonUtil::ParseBackupVersion(); + cache.SetBackupVersion(backupVersion); cache.SetSystemFullName(GetOSFullName()); cache.SetDeviceType(GetDeviceType()); auto bundleInfos = BundleMgrAdapter::GetFullBundleInfos(GetUserIdDefault()); @@ -533,13 +543,18 @@ void Service::OnBundleStarted(BError error, sptr session, con static vector GetRestoreBundleNames(UniqueFd fd, sptr session, - const vector &bundleNames) + const vector &bundleNames, + std::string &oldBackupVersion) { HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__); // BundleMgrAdapter::GetBundleInfos可能耗时 auto restoreInfos = BundleMgrAdapter::GetBundleInfos(bundleNames, session->GetSessionUserId()); BJsonCachedEntity cachedEntity(move(fd)); auto cache = cachedEntity.Structuralize(); + oldBackupVersion = cache.GetBackupVersion(); + if (oldBackupVersion.empty()) { + HILOGE("backupVersion of old device is empty"); + } auto bundleInfos = cache.GetBundleInfos(); if (!bundleInfos.size()) { throw BError(BError::Codes::SA_INVAL_ARG, "Json entity caps is empty"); @@ -622,7 +637,8 @@ ErrCode Service::AppendBundlesRestoreSession(UniqueFd fd, const vector> bundleNameDetailMap = BJsonUtil::BuildBundleInfos(bundleNames, bundleInfos, bundleNamesOnly, session_->GetSessionUserId(), isClearDataFlags); - auto restoreInfos = GetRestoreBundleNames(move(fd), session_, bundleNames); + std::string oldBackupVersion; + auto restoreInfos = GetRestoreBundleNames(move(fd), session_, bundleNames, oldBackupVersion); auto restoreBundleNames = SvcRestoreDepsManager::GetInstance().GetRestoreBundleNames(restoreInfos, restoreType); HandleExceptionOnAppendBundles(session_, bundleNames, restoreBundleNames); if (restoreBundleNames.empty()) { @@ -632,7 +648,7 @@ ErrCode Service::AppendBundlesRestoreSession(UniqueFd fd, const vectorAppendBundles(restoreBundleNames); SetCurrentSessProperties(restoreInfos, restoreBundleNames, bundleNameDetailMap, - isClearDataFlags, restoreType); + isClearDataFlags, restoreType, oldBackupVersion); OnStartSched(); session_->DecreaseSessionCnt(__PRETTY_FUNCTION__); HILOGI("End"); @@ -651,9 +667,10 @@ ErrCode Service::AppendBundlesRestoreSession(UniqueFd fd, const vector &restoreBundleInfos, - std::vector &restoreBundleNames, RestoreTypeEnum restoreType) + std::vector &restoreBundleNames, RestoreTypeEnum restoreType, std::string &backupVersion) { HILOGI("Start"); + session_->SetOldBackupVersion(backupVersion); for (auto restoreInfo : restoreBundleInfos) { auto it = find_if(restoreBundleNames.begin(), restoreBundleNames.end(), [&restoreInfo](const auto &bundleName) { std::string bundleNameIndex = BJsonUtil::BuildBundleNameIndexInfo(restoreInfo.name, restoreInfo.appIndex); @@ -703,7 +720,8 @@ ErrCode Service::AppendBundlesRestoreSession(UniqueFd fd, session_->SetSessionUserId(GetUserIdDefault()); } VerifyCaller(IServiceReverse::Scenario::RESTORE); - auto restoreInfos = GetRestoreBundleNames(move(fd), session_, bundleNames); + std::string oldBackupVersion; + auto restoreInfos = GetRestoreBundleNames(move(fd), session_, bundleNames, oldBackupVersion); auto restoreBundleNames = SvcRestoreDepsManager::GetInstance().GetRestoreBundleNames(restoreInfos, restoreType); HandleExceptionOnAppendBundles(session_, bundleNames, restoreBundleNames); if (restoreBundleNames.empty()) { @@ -712,7 +730,7 @@ ErrCode Service::AppendBundlesRestoreSession(UniqueFd fd, return BError(BError::Codes::OK); } session_->AppendBundles(restoreBundleNames); - SetCurrentSessProperties(restoreInfos, restoreBundleNames, restoreType); + SetCurrentSessProperties(restoreInfos, restoreBundleNames, restoreType, oldBackupVersion); OnStartSched(); session_->DecreaseSessionCnt(__PRETTY_FUNCTION__); return BError(BError::Codes::OK); @@ -732,9 +750,10 @@ ErrCode Service::AppendBundlesRestoreSession(UniqueFd fd, void Service::SetCurrentSessProperties(std::vector &restoreBundleInfos, std::vector &restoreBundleNames, std::map> &bundleNameDetailMap, - std::map &isClearDataFlags, RestoreTypeEnum restoreType) + std::map &isClearDataFlags, RestoreTypeEnum restoreType, std::string &backupVersion) { HILOGI("Start"); + session_->SetOldBackupVersion(backupVersion); for (auto restoreInfo : restoreBundleInfos) { auto it = find_if(restoreBundleNames.begin(), restoreBundleNames.end(), [&restoreInfo](const auto &bundleName) { @@ -1131,6 +1150,7 @@ void Service::ExtStart(const string &bundleName) } auto ret = proxy->HandleRestore(session_->GetClearDataFlag(bundleName)); session_->GetServiceReverseProxy()->RestoreOnBundleStarted(ret, bundleName); + GetOldDeviceBackupVersion(); BundleBeginRadarReport(bundleName, ret, scenario); auto fileNameVec = session_->GetExtFileNameRequest(bundleName); for (auto &fileName : fileNameVec) { diff --git a/services/backup_sa/src/module_ipc/service_incremental.cpp b/services/backup_sa/src/module_ipc/service_incremental.cpp index 8583f06e2b92fad6e2c470a4d64942aa1566fcdd..62f0c60b7e148b1bfe6a9136b059af63fd35a6fe 100644 --- a/services/backup_sa/src/module_ipc/service_incremental.cpp +++ b/services/backup_sa/src/module_ipc/service_incremental.cpp @@ -162,7 +162,8 @@ UniqueFd Service::GetLocalCapabilitiesIncremental(const std::vector cachedEntity(move(fd)); auto cache = cachedEntity.Structuralize(); - + std::string backupVersion = BJsonUtil::ParseBackupVersion(); + cache.SetBackupVersion(backupVersion); cache.SetSystemFullName(GetOSFullName()); cache.SetDeviceType(GetDeviceType()); auto bundleInfos = BundleMgrAdapter::GetBundleInfosForIncremental(GetUserIdDefault(), bundleNames); @@ -653,6 +654,11 @@ bool Service::IncrementalBackup(const string &bundleName) session_->ValidRestoreDataType(RestoreTypeEnum::RESTORE_DATA_WAIT_SEND)) { auto ret = proxy->HandleRestore(session_->GetClearDataFlag(bundleName)); session_->GetServiceReverseProxy()->IncrementalRestoreOnBundleStarted(ret, bundleName); + std::string oldBackupVersion = session_->GetOldBackupVersion(); + if (oldBackupVersion.empty()) { + HILOGE("Failed to get backupVersion of old device"); + } + HILOGD("backupVersion of old device = %{public}s", oldBackupVersion.c_str()); BundleBeginRadarReport(bundleName, ret, IServiceReverse::Scenario::RESTORE); auto fileNameVec = session_->GetExtFileNameRequest(bundleName); for (auto &fileName : fileNameVec) { diff --git a/services/backup_sa/src/module_ipc/sub_service.cpp b/services/backup_sa/src/module_ipc/sub_service.cpp index 8bbdf24822fd1c8958c992402912632f43990c8f..be07397ba93f68b8f6037c422254bc4e2ed1b204 100644 --- a/services/backup_sa/src/module_ipc/sub_service.cpp +++ b/services/backup_sa/src/module_ipc/sub_service.cpp @@ -292,6 +292,10 @@ void Service::SetWant(AAFwk::Want &want, const BundleName &bundleName, const BCo RestoreTypeEnum restoreType = session_->GetBundleRestoreType(bundleName); /* app restore type */ string bundleExtInfo = session_->GetBackupExtInfo(bundleName); HILOGI("BundleExtInfo is:%{public}s", GetAnonyString(bundleExtInfo).c_str()); + string oldBackupVersion = session_->GetOldBackupVersion(); /* old device backup version */ + if (oldBackupVersion.empty()) { + HILOGE("Failed to get backupVersion of old device"); + } want.SetElementName(bundleDetail.bundleName, backupExtName); want.SetParam(BConstants::EXTENSION_ACTION_PARA, static_cast(action)); want.SetParam(BConstants::EXTENSION_VERSION_CODE_PARA, static_cast(versionCode)); @@ -300,6 +304,7 @@ void Service::SetWant(AAFwk::Want &want, const BundleName &bundleName, const BCo want.SetParam(BConstants::EXTENSION_RESTORE_EXT_INFO_PARA, bundleExtInfo); want.SetParam(BConstants::EXTENSION_BACKUP_EXT_INFO_PARA, bundleExtInfo); want.SetParam(BConstants::EXTENSION_APP_CLONE_INDEX_PARA, bundleDetail.bundleIndex); + want.SetParam(BConstants::EXTENSION_OLD_BACKUP_VERSION_PARA, oldBackupVersion); } std::vector Service::GetSupportBackupBundleNames(vector &backupInfos, diff --git a/services/backup_sa/src/module_ipc/svc_session_manager.cpp b/services/backup_sa/src/module_ipc/svc_session_manager.cpp index f47d3e151d3389145ec075492394fc9591adb615..9fec17ab3df04c827c7748c08944d34e90277c0d 100644 --- a/services/backup_sa/src/module_ipc/svc_session_manager.cpp +++ b/services/backup_sa/src/module_ipc/svc_session_manager.cpp @@ -1021,6 +1021,24 @@ void SvcSessionManager::SetPublishFlag(const std::string &bundleName) HILOGE("Set PublishFile success, bundleName = %{public}s", bundleName.c_str()); } +void SvcSessionManager::SetOldBackupVersion(const std::string &backupVersion) +{ + unique_lock lock(lock_); + if (!impl_.clientToken) { + throw BError(BError::Codes::SA_INVAL_ARG, "No caller token was specified"); + } + impl_.oldBackupVersion = backupVersion; +} + +std::string SvcSessionManager::GetOldBackupVersion() +{ + shared_lock lock(lock_); + if (!impl_.clientToken) { + throw BError(BError::Codes::SA_INVAL_ARG, "No caller token was specified"); + } + return impl_.oldBackupVersion; +} + void SvcSessionManager::SetImplRestoreType(const RestoreTypeEnum restoreType) { impl_.restoreDataType = restoreType; diff --git a/tests/mock/module_ipc/include/svc_session_manager_mock.h b/tests/mock/module_ipc/include/svc_session_manager_mock.h index 680c2bea6989d0dbb59d934573b808c8f805a771..e8f74bb042c05c7418605739e68aa244abc043bc 100644 --- a/tests/mock/module_ipc/include/svc_session_manager_mock.h +++ b/tests/mock/module_ipc/include/svc_session_manager_mock.h @@ -58,6 +58,7 @@ public: virtual ErrCode ClearSessionData() = 0; virtual int GetSessionCnt() = 0; virtual SvcSessionManager::Impl GetImpl() = 0; + virtual std::string GetOldBackupVersion() = 0; public: BSvcSessionManager() = default; virtual ~BSvcSessionManager() = default; @@ -102,6 +103,7 @@ public: MOCK_METHOD(ErrCode, ClearSessionData, ()); MOCK_METHOD(int, GetSessionCnt, ()); MOCK_METHOD(SvcSessionManager::Impl, GetImpl, ()); + MOCK_METHOD(std::string, GetOldBackupVersion, ()); }; } // namespace OHOS::FileManagement::Backup #endif // OHOS_FILEMGMT_BACKUP_SVC_SESSION_MANAGER_MOCK_H diff --git a/tests/mock/module_ipc/service_mock.cpp b/tests/mock/module_ipc/service_mock.cpp index 4f6a1d0d1ac5a80aab55729dbec2450ed6320054..f04c209a5336d6156e58fb298a0e33a84dcf7c7c 100644 --- a/tests/mock/module_ipc/service_mock.cpp +++ b/tests/mock/module_ipc/service_mock.cpp @@ -285,6 +285,8 @@ void Service::UpdateFailedBundles(const std::string &bundleName, BundleTaskInfo void Service::ClearFailedBundles() {} +void Service::GetOldDeviceBackupVersion() {} + void Service::CreateDirIfNotExist(const std::string &path) { } diff --git a/tests/mock/module_ipc/src/svc_session_manager_mock.cpp b/tests/mock/module_ipc/src/svc_session_manager_mock.cpp index 59c9e2a34f772dd4f54c74602c122162c993c5ba..b4aa9f283e7133900b57bb5881dcd69dc52b4730 100644 --- a/tests/mock/module_ipc/src/svc_session_manager_mock.cpp +++ b/tests/mock/module_ipc/src/svc_session_manager_mock.cpp @@ -257,4 +257,11 @@ SvcSessionManager::Impl SvcSessionManager::GetImpl() void SvcSessionManager::SetImplRestoreType(const RestoreTypeEnum restoreType) {} void SvcSessionManager::SetIsReadyLaunch(const std::string&) {} + +void SvcSessionManager::SetOldBackupVersion(const std::string &backupVersion) {} + +std::string SvcSessionManager::GetOldBackupVersion() +{ + return BSvcSessionManager::sessionManager->GetOldBackupVersion(); +} } // namespace OHOS::FileManagement::Backup diff --git a/tests/mock/module_ipc/svc_session_manager_mock.cpp b/tests/mock/module_ipc/svc_session_manager_mock.cpp index 257ad09c2a3b0802335f4c2b5666684dabe7b210..1e9e265b8fb0cff65b5470aa8279313d9d5b6570 100644 --- a/tests/mock/module_ipc/svc_session_manager_mock.cpp +++ b/tests/mock/module_ipc/svc_session_manager_mock.cpp @@ -445,4 +445,14 @@ void SvcSessionManager::SetPublishFlag(const std::string &bundleName) {} void SvcSessionManager::SetImplRestoreType(const RestoreTypeEnum restoreType) {} void SvcSessionManager::SetIsReadyLaunch(const std::string &bundleName) {} + +void SvcSessionManager::SetOldBackupVersion(const std::string &backupVersion) +{ + impl_.oldBackupVersion = backupVersion; +} + +std::string SvcSessionManager::GetOldBackupVersion() +{ + return impl_.oldBackupVersion; +} } // namespace OHOS::FileManagement::Backup diff --git a/tests/mock/module_ipc/svc_session_manager_throw_mock.cpp b/tests/mock/module_ipc/svc_session_manager_throw_mock.cpp index 8a0b29390d8c1c10d91c8847f9ae5db9059b1ebf..c76234055b29952aa9042d0682b8dcf6f683ae45 100644 --- a/tests/mock/module_ipc/svc_session_manager_throw_mock.cpp +++ b/tests/mock/module_ipc/svc_session_manager_throw_mock.cpp @@ -325,4 +325,11 @@ void SvcSessionManager::SetPublishFlag(const std::string &bundleName) {} void SvcSessionManager::SetImplRestoreType(const RestoreTypeEnum restoreType) {} void SvcSessionManager::SetIsReadyLaunch(const std::string &bundleName) {} + +void SvcSessionManager::SetOldBackupVersion(const std::string &backupVersion) {} + +std::string SvcSessionManager::GetOldBackupVersion() +{ + return BackupSvcSessionManager::session->GetOldBackupVersion(); +} } // namespace OHOS::FileManagement::Backup diff --git a/tests/mock/module_ipc/svc_session_manager_throw_mock.h b/tests/mock/module_ipc/svc_session_manager_throw_mock.h index cb9904f7329a83785fa12f0decf9cf32b2871715..60113e1d789c02e9ce5b655fea4b9a2c365195e4 100644 --- a/tests/mock/module_ipc/svc_session_manager_throw_mock.h +++ b/tests/mock/module_ipc/svc_session_manager_throw_mock.h @@ -90,6 +90,8 @@ public: virtual void SetPublishFlag(const std::string &bundleName) = 0; virtual void SetImplRestoreType(const RestoreTypeEnum restoreType) = 0; virtual void SetIsReadyLaunch(const std::string &bundleName) = 0; + virtual void SetOldBackupVersion(const std::string &backupVersion) = 0; + virtual std::string GetOldBackupVersion() = 0; public: static inline std::shared_ptr session = nullptr; }; @@ -159,6 +161,8 @@ public: MOCK_METHOD(void, SetPublishFlag, (const std::string &)); MOCK_METHOD(void, SetImplRestoreType, (const RestoreTypeEnum restoreType)); MOCK_METHOD(void, SetIsReadyLaunch, (const std::string &)); + MOCK_METHOD(void, SetOldBackupVersion, (const std::string &)); + MOCK_METHOD(std::string, GetOldBackupVersion, ()); }; } // namespace OHOS::FileManagement::Backup diff --git a/tests/unittests/backup_sa/module_ipc/service_incremental_test.cpp b/tests/unittests/backup_sa/module_ipc/service_incremental_test.cpp index 9d43383b8e3e1b502305aba3dc479777e98a53a2..6bae0e06bf144e2cf80dfdfca64a1e16a1c17f66 100644 --- a/tests/unittests/backup_sa/module_ipc/service_incremental_test.cpp +++ b/tests/unittests/backup_sa/module_ipc/service_incremental_test.cpp @@ -208,10 +208,11 @@ ErrCode Service::StartFwkTimer(bool &isFwkStart) } void Service::SetCurrentSessProperties(std::vector&, std::vector&, - RestoreTypeEnum) {} + RestoreTypeEnum, std::string &) {} void Service::SetCurrentSessProperties(std::vector&, std::vector&, - std::map>&, std::map&, RestoreTypeEnum) {} + std::map>&, std::map&, + RestoreTypeEnum, std::string &) {} void Service::SetCurrentSessProperties(BJsonEntityCaps::BundleInfo&, std::map&, const std::string&) {} diff --git a/tests/unittests/backup_sa/module_ipc/service_other_test.cpp b/tests/unittests/backup_sa/module_ipc/service_other_test.cpp index e59fd30f24339c48c6c98f56986a78185b006325..d1dff3b397257f342818345cf59c5f0db84edd14 100644 --- a/tests/unittests/backup_sa/module_ipc/service_other_test.cpp +++ b/tests/unittests/backup_sa/module_ipc/service_other_test.cpp @@ -695,9 +695,10 @@ HWTEST_F(ServiceTest, SUB_Service_GetRestoreBundleNames_0100, TestSize.Level1) try { vector bundleNames; vector bundleInfos; + std::string backupVersion; EXPECT_CALL(*session, GetSessionUserId()).WillOnce(Return(0)); EXPECT_CALL(*bms, GetBundleInfos(_, _)).WillOnce(Return(bundleInfos)); - EXPECT_THROW(GetRestoreBundleNames(UniqueFd(-1), service->session_, bundleNames), BError); + EXPECT_THROW(GetRestoreBundleNames(UniqueFd(-1), service->session_, bundleNames, backupVersion), BError); } catch (...) { EXPECT_TRUE(false); GTEST_LOG_(INFO) << "ServiceTest-an exception occurred by GetRestoreBundleNames."; @@ -861,15 +862,16 @@ HWTEST_F(ServiceTest, SUB_Service_SetCurrentSessProperties_0200, TestSize.Level1 map> bundleNameDetailMap; map isClearDataFlags; RestoreTypeEnum restoreType = RestoreTypeEnum::RESTORE_DATA_WAIT_SEND; + std::string backupVersion; EXPECT_THROW(service->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, bundleNameDetailMap, - isClearDataFlags, restoreType), BError); + isClearDataFlags, restoreType, backupVersion), BError); restoreBundleNames.emplace_back("bundleName"); EXPECT_CALL(*jsonUtil, BuildBundleNameIndexInfo(_, _)).WillOnce(Return("bundleName")) .WillOnce(Return("bundleName")); EXPECT_CALL(*session, GetScenario()).WillOnce(Return(IServiceReverse::Scenario::UNDEFINED)); service->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, bundleNameDetailMap, - isClearDataFlags, restoreType); + isClearDataFlags, restoreType, backupVersion); EXPECT_TRUE(true); restoreBundleInfos[0].allToBackup = true; @@ -878,7 +880,7 @@ HWTEST_F(ServiceTest, SUB_Service_SetCurrentSessProperties_0200, TestSize.Level1 EXPECT_CALL(*session, GetScenario()).WillOnce(Return(IServiceReverse::Scenario::UNDEFINED)); EXPECT_CALL(*saUtils, IsSABundleName(_)).WillOnce(Return(false)); service->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, bundleNameDetailMap, - isClearDataFlags, restoreType); + isClearDataFlags, restoreType, backupVersion); EXPECT_TRUE(true); restoreBundleInfos[0].allToBackup = false; @@ -888,7 +890,7 @@ HWTEST_F(ServiceTest, SUB_Service_SetCurrentSessProperties_0200, TestSize.Level1 EXPECT_CALL(*session, GetScenario()).WillOnce(Return(IServiceReverse::Scenario::UNDEFINED)); EXPECT_CALL(*saUtils, IsSABundleName(_)).WillOnce(Return(false)); service->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, bundleNameDetailMap, - isClearDataFlags, restoreType); + isClearDataFlags, restoreType, backupVersion); EXPECT_TRUE(true); } catch (...) { EXPECT_TRUE(false); @@ -917,13 +919,14 @@ HWTEST_F(ServiceTest, SUB_Service_SetCurrentSessProperties_0300, TestSize.Level1 map> bundleNameDetailMap; map isClearDataFlags; RestoreTypeEnum restoreType = RestoreTypeEnum::RESTORE_DATA_WAIT_SEND; + std::string backupVersion; EXPECT_CALL(*jsonUtil, BuildBundleNameIndexInfo(_, _)).WillOnce(Return("bundleName")) .WillOnce(Return("bundleName")); EXPECT_CALL(*saUtils, IsSABundleName(_)).WillOnce(Return(true)); EXPECT_CALL(*jsonUtil, FindBundleInfoByName(_, _, _, _)).WillOnce(Return(false)).WillOnce(Return(false)); service->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, bundleNameDetailMap, - isClearDataFlags, restoreType); + isClearDataFlags, restoreType, backupVersion); EXPECT_TRUE(true); restoreBundleInfos[0].extensionName = "extensionName"; @@ -931,27 +934,27 @@ HWTEST_F(ServiceTest, SUB_Service_SetCurrentSessProperties_0300, TestSize.Level1 .WillOnce(Return("bundleName")); EXPECT_CALL(*jsonUtil, FindBundleInfoByName(_, _, _, _)).WillOnce(Return(false)).WillOnce(Return(false)); service->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, bundleNameDetailMap, - isClearDataFlags, restoreType); + isClearDataFlags, restoreType, backupVersion); EXPECT_TRUE(true); EXPECT_CALL(*jsonUtil, BuildBundleNameIndexInfo(_, _)).WillOnce(Return("bundleName")) .WillOnce(Return("bundleName")); EXPECT_CALL(*jsonUtil, FindBundleInfoByName(_, _, _, _)).WillOnce(Return(false)).WillOnce(Return(false)); service->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, bundleNameDetailMap, - isClearDataFlags, restoreType); + isClearDataFlags, restoreType, backupVersion); EXPECT_CALL(*jsonUtil, BuildBundleNameIndexInfo(_, _)).WillOnce(Return("bundleName")) .WillOnce(Return("bundleName")); EXPECT_CALL(*jsonUtil, FindBundleInfoByName(_, _, _, _)).WillOnce(Return(true)).WillOnce(Return(false)); EXPECT_CALL(*notify, NotifyBundleDetail(_)).WillOnce(Return(true)); service->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, bundleNameDetailMap, - isClearDataFlags, restoreType); + isClearDataFlags, restoreType, backupVersion); EXPECT_CALL(*jsonUtil, BuildBundleNameIndexInfo(_, _)).WillOnce(Return("bundleName")) .WillOnce(Return("bundleName")); EXPECT_CALL(*jsonUtil, FindBundleInfoByName(_, _, _, _)).WillOnce(Return(false)).WillOnce(Return(true)); service->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, bundleNameDetailMap, - isClearDataFlags, restoreType); + isClearDataFlags, restoreType, backupVersion); EXPECT_TRUE(true); } catch (...) { EXPECT_TRUE(false); diff --git a/tests/unittests/backup_sa/module_ipc/service_test.cpp b/tests/unittests/backup_sa/module_ipc/service_test.cpp index 0835ba5e0d911e98097304117ac608520f74a87c..ff2176f75f40ab5065ad42a9ce2cb07d711a236e 100644 --- a/tests/unittests/backup_sa/module_ipc/service_test.cpp +++ b/tests/unittests/backup_sa/module_ipc/service_test.cpp @@ -1337,37 +1337,38 @@ HWTEST_F(ServiceTest, SUB_Service_SetCurrentSessProperties_0100, testing::ext::T std::vector restoreBundleInfos {aInfo}; std::vector restoreBundleNames {"12345678"}; RestoreTypeEnum restoreType = RESTORE_DATA_READDY; + std::string backupVersion; EXPECT_TRUE(servicePtr_ != nullptr); servicePtr_->session_ = sptr(new SvcSessionManager(servicePtr_)); - servicePtr_->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, restoreType); + servicePtr_->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, restoreType, backupVersion); restoreBundleNames.push_back("123456"); - servicePtr_->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, restoreType); + servicePtr_->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, restoreType, backupVersion); restoreBundleInfos.clear(); aInfo.allToBackup = true; aInfo.versionName = "0.0.0.0-0.0.0.0"; aInfo.extensionName = ""; restoreBundleInfos.push_back(aInfo); - servicePtr_->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, restoreType); + servicePtr_->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, restoreType, backupVersion); restoreBundleInfos.clear(); aInfo.name = "123456a"; restoreBundleInfos.push_back(aInfo); restoreBundleNames.push_back("123456a"); - servicePtr_->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, restoreType); + servicePtr_->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, restoreType, backupVersion); restoreBundleInfos.clear(); aInfo.allToBackup = false; aInfo.extensionName = ""; restoreBundleInfos.push_back(aInfo); - servicePtr_->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, restoreType); + servicePtr_->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, restoreType, backupVersion); restoreBundleInfos.clear(); aInfo.allToBackup = false; aInfo.extensionName = ""; restoreBundleInfos.push_back(aInfo); - servicePtr_->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, restoreType); + servicePtr_->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, restoreType, backupVersion); } catch (...) { EXPECT_TRUE(true); GTEST_LOG_(INFO) << "ServiceTest-an exception occurred by SetCurrentSessProperties."; @@ -1396,20 +1397,21 @@ HWTEST_F(ServiceTest, SUB_Service_SetCurrentSessProperties_0101, testing::ext::T std::vector restoreBundleInfos {aInfo}; std::vector restoreBundleNames {"123456"}; RestoreTypeEnum restoreType = RESTORE_DATA_READDY; + std::string backupVersion; EXPECT_TRUE(servicePtr_ != nullptr); servicePtr_->session_ = sptr(new SvcSessionManager(servicePtr_)); - servicePtr_->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, restoreType); + servicePtr_->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, restoreType, backupVersion); restoreBundleInfos.clear(); aInfo.extensionName = ""; restoreBundleInfos.push_back(aInfo); - servicePtr_->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, restoreType); + servicePtr_->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, restoreType, backupVersion); restoreBundleInfos.clear(); aInfo.name = "123456a"; restoreBundleInfos.push_back(aInfo); restoreBundleNames.push_back("123456a"); - servicePtr_->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, restoreType); + servicePtr_->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, restoreType, backupVersion); } catch (...) { EXPECT_TRUE(false); GTEST_LOG_(INFO) << "ServiceTest-an exception occurred by SetCurrentSessProperties."; @@ -1438,30 +1440,31 @@ HWTEST_F(ServiceTest, SUB_Service_SetCurrentSessProperties_0102, testing::ext::T std::vector restoreBundleInfos {aInfo}; std::vector restoreBundleNames {"123456"}; RestoreTypeEnum restoreType = RESTORE_DATA_READDY; + std::string backupVersion; EXPECT_TRUE(servicePtr_ != nullptr); - servicePtr_->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, restoreType); + servicePtr_->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, restoreType, backupVersion); restoreBundleInfos.clear(); aInfo.versionName = "1.1.1.1-1.1.1.1"; aInfo.extensionName = ""; aInfo.name = "123456"; restoreBundleInfos.push_back(aInfo); - servicePtr_->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, restoreType); + servicePtr_->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, restoreType, backupVersion); restoreBundleInfos.clear(); aInfo.name = "123456a"; restoreBundleInfos.push_back(aInfo); - servicePtr_->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, restoreType); + servicePtr_->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, restoreType, backupVersion); restoreBundleInfos.clear(); aInfo.extensionName = "abcdef"; restoreBundleInfos.push_back(aInfo); - servicePtr_->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, restoreType); + servicePtr_->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, restoreType, backupVersion); restoreBundleInfos.clear(); aInfo.name = "123456"; restoreBundleInfos.push_back(aInfo); - servicePtr_->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, restoreType); + servicePtr_->SetCurrentSessProperties(restoreBundleInfos, restoreBundleNames, restoreType, backupVersion); } catch (...) { EXPECT_TRUE(true); GTEST_LOG_(INFO) << "ServiceTest-an exception occurred by SetCurrentSessProperties."; diff --git a/tests/unittests/backup_sa/module_ipc/svc_session_manager_test.cpp b/tests/unittests/backup_sa/module_ipc/svc_session_manager_test.cpp index 6ddbbe2e61f51648e2851374cd49facd6c357959..9370532d014da1db08e695406c8c62693008cbab 100644 --- a/tests/unittests/backup_sa/module_ipc/svc_session_manager_test.cpp +++ b/tests/unittests/backup_sa/module_ipc/svc_session_manager_test.cpp @@ -1322,6 +1322,57 @@ HWTEST_F(SvcSessionManagerTest, SUB_backup_sa_session_GetSessionUserId_0100, tes GTEST_LOG_(INFO) << "ServiceTest-end SUB_backup_sa_session_GetSessionUserId_0100"; } +/** + * @tc.number: SUB_backup_sa_session_SetOldBackupVersion_0100 + * @tc.name: SUB_backup_sa_session_SetOldBackupVersion_0100 + * @tc.desc: 测试 SetSessionUserId + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: I8ZIMJ + */ +HWTEST_F(SvcSessionManagerTest, SUB_backup_sa_session_SetOldBackupVersion_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceTest-begin SUB_backup_sa_session_SetOldBackupVersion_0100"; + try { + std::string backupVersion = "16.0"; + EXPECT_TRUE(sessionManagerPtr_ != nullptr); + sessionManagerPtr_->SetOldBackupVersion(backupVersion); + EXPECT_EQ(sessionManagerPtr_->impl_.oldBackupVersion, backupVersion); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceTest-an exception occurred by SetOldBackupVersion."; + } + GTEST_LOG_(INFO) << "ServiceTest-end SUB_backup_sa_session_SetOldBackupVersion_0100"; +} + +/** + * @tc.number: SUB_backup_sa_session_GetOldBackupVersion_0100 + * @tc.name: SUB_backup_sa_session_GetOldBackupVersion_0100 + * @tc.desc: 测试 GetSessionUserId + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: I8ZIMJ + */ +HWTEST_F(SvcSessionManagerTest, SUB_backup_sa_session_GetOldBackupVersion_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceTest-begin SUB_backup_sa_session_GetOldBackupVersion_0100"; + try { + EXPECT_TRUE(sessionManagerPtr_ != nullptr); + sessionManagerPtr_->GetOldBackupVersion(); + EXPECT_TRUE(true); + + sessionManagerPtr_->impl_.oldBackupVersion = "16.0"; + EXPECT_EQ(sessionManagerPtr_->GetOldBackupVersion(), "16.0"); + EXPECT_TRUE(true); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceTest-an exception occurred by GetOldBackupVersion."; + } + GTEST_LOG_(INFO) << "ServiceTest-end SUB_backup_sa_session_GetOldBackupVersion_0100"; +} + /** * @tc.number: SUB_backup_sa_session_SetBundleRestoreType_0100 * @tc.name: SUB_backup_sa_session_SetBundleRestoreType_0100 diff --git a/utils/include/b_json/b_json_entity_caps.h b/utils/include/b_json/b_json_entity_caps.h index 74d092864e9b6f7f3356106cf9db82701ee4678d..1321ecde546927b096a41a12f602eda548ea606a 100644 --- a/utils/include/b_json/b_json_entity_caps.h +++ b/utils/include/b_json/b_json_entity_caps.h @@ -99,6 +99,31 @@ public: } } + void SetBackupVersion(const std::string &backupVersion) + { + if (obj_.isMember("backupVersion")) { + obj_["backupVersion"].clear(); + } + obj_["backupVersion"] = backupVersion; + } + + std::string GetBackupVersion() + { + if (!obj_) { + HILOGI("Failed to get field backupVersion"); + return ""; + } + if (!obj_.isMember("backupVersion")) { + HILOGI("Failed to get field backupVersion from early Version, returning the default value"); + return ""; + } + if (!obj_["backupVersion"].isString()) { + HILOGI("Failed to get field backupVersion"); + return ""; + } + return obj_["backupVersion"].asString(); + } + std::string GetSystemFullName() { if (!obj_ || !obj_.isMember("systemFullName") || !obj_["systemFullName"].isString()) { diff --git a/utils/include/b_jsonutil/b_jsonutil.h b/utils/include/b_jsonutil/b_jsonutil.h index 0758165801532e06bcdb7359e3d69af6aa063335..ebaadfbeec6011bd03ebfbbaea3176df3a30e1a1 100644 --- a/utils/include/b_jsonutil/b_jsonutil.h +++ b/utils/include/b_jsonutil/b_jsonutil.h @@ -160,6 +160,14 @@ public: * */ static bool HasUnicastInfo(std::string &bundleInfo); + + /** + * @brief 解析备份框架版本号字段 + * + * @return 备份恢复框架版本号 + * + */ + static std::string ParseBackupVersion(); }; } // namespace OHOS::FileManagement::Backup diff --git a/utils/include/b_resources/b_constants.h b/utils/include/b_resources/b_constants.h index fe7934006af567336cd85b49f86762f2645b64ec..67d094749aa14eae07aab99833018de1d4f62778 100644 --- a/utils/include/b_resources/b_constants.h +++ b/utils/include/b_resources/b_constants.h @@ -31,6 +31,7 @@ static inline const char *EXTENSION_VERSION_NAME_PARA = "versionName"; static inline const char *EXTENSION_RESTORE_EXT_INFO_PARA = "restoreExtInfo"; static inline const char *EXTENSION_BACKUP_EXT_INFO_PARA = "backupExtInfo"; static inline const char *EXTENSION_APP_CLONE_INDEX_PARA = "ohos.extra.param.key.appCloneIndex"; +static inline const char *EXTENSION_OLD_BACKUP_VERSION_PARA = "oldBackupVersion"; enum class ExtensionAction { INVALID = 0, @@ -205,6 +206,7 @@ static inline std::vector DEFAULT_VERSION_NAMES_VEC = { DEFAULT_VERSION_NAME, DEFAULT_VERSION_NAME_CLONE, DEFAULT_VERSION_NAME_CLONE_2, DEFAULT_VERSION_NAME_CLONE_3, DEFAULT_VERSION_NAME_PC, DEFAULT_VERSION_NAME_CLOUD, }; +static inline std::string BACKUP_VERSION = R"({"backupVersion" : "16.0"})"; // 应用默认备份的目录,其均为相对根路径的路径。为避免模糊匹配,务必以斜线为结尾。 static inline std::array PATHES_TO_BACKUP = { diff --git a/utils/src/b_jsonutil/b_jsonutil.cpp b/utils/src/b_jsonutil/b_jsonutil.cpp index 24c841ebea2ea2816ef15e6d252fe3bdf4f97c41..432604604cf9eb55605d81c8dd82eeb964c67f3a 100644 --- a/utils/src/b_jsonutil/b_jsonutil.cpp +++ b/utils/src/b_jsonutil/b_jsonutil.cpp @@ -437,4 +437,23 @@ bool BJsonUtil::BuildBundleInfoJson(int32_t userId, string &detailInfo) free(jsonStr); return true; } + +std::string BJsonUtil::ParseBackupVersion() +{ + std::string backupVersion; + cJSON *root = cJSON_Parse(BConstants::BACKUP_VERSION.c_str()); + if (root == nullptr) { + HILOGE("Parse json error,root is null"); + return ""; + } + cJSON *value = cJSON_GetObjectItem(root, "backupVersion"); + if (value == nullptr || !cJSON_IsString(value) || (value->valuestring == nullptr)) { + HILOGE("Parse json backupVersion element error"); + cJSON_Delete(root); + return ""; + } + backupVersion = value->valuestring; + cJSON_Delete(root); + return backupVersion; +} } \ No newline at end of file