diff --git a/services/distributeddataservice/service/test/udmf_service_impl_test.cpp b/services/distributeddataservice/service/test/udmf_service_impl_test.cpp index 9a32e1587fb02ae3e7677a42a955c9476e9e38d4..d5ae9fab15cb228f6181c5954d2eb0ad95164bdb 100644 --- a/services/distributeddataservice/service/test/udmf_service_impl_test.cpp +++ b/services/distributeddataservice/service/test/udmf_service_impl_test.cpp @@ -676,5 +676,158 @@ HWTEST_F(UdmfServiceImplTest, VerifyDataAccessPermission002, TestSize.Level1) EXPECT_EQ(runtime->privileges[0].tokenId, query.tokenId); EXPECT_EQ(result, OHOS::UDMF::E_OK); } + +/** + * @tc.name: HandleDelayLoad001 + * @tc.desc: Returns true when data not arrives + * @tc.type: FUNC + */ +HWTEST_F(UdmfServiceImplTest, HandleDelayLoad001, TestSize.Level1) +{ + QueryOption query; + query.key = "k1"; + query.tokenId = 123; + + UnifiedData result; + int32_t res = UDMF::E_OK; + + UdmfServiceImpl service; + service.dataLoadCallback_.Insert(query.key, nullptr); + + using CacheData = BlockData, std::chrono::milliseconds>; + UdmfServiceImpl::BlockDelayData data; + data.tokenId = query.tokenId; + data.blockData = std::make_shared(100); + service.blockDelayDataCache_.Insert(query.key, data); + + bool handled = service.HandleDelayLoad(query, result, res); + + service.dataLoadCallback_.Erase(query.key); + service.blockDelayDataCache_.Erase(query.key); + + EXPECT_TRUE(handled); + EXPECT_EQ(res, UDMF::E_NOT_FOUND); +} + +/** + * @tc.name: HandleDelayLoad002 + * @tc.desc: Returns false when not exist + * @tc.type: FUNC + */ +HWTEST_F(UdmfServiceImplTest, HandleDelayLoad002, TestSize.Level1) +{ + QueryOption query; + query.key = "k1"; + query.tokenId = 123; + + UnifiedData result; + int32_t res = UDMF::E_OK; + + UdmfServiceImpl service; + bool handled = service.HandleDelayLoad(query, result, res); + + EXPECT_FALSE(handled); +} + +/** + * @tc.name: HandleDelayLoad003 + * @tc.desc: Returns true when data arrives + * @tc.type: FUNC + */ +HWTEST_F(UdmfServiceImplTest, HandleDelayLoad003, TestSize.Level1) +{ + QueryOption query; + query.key = "k1"; + query.tokenId = 123; + + UnifiedData result; + int32_t res = UDMF::E_OK; + + UnifiedData insertedData; + insertedData.AddRecord(std::make_shared()); + + UdmfServiceImpl service; + service.dataLoadCallback_.Insert(query.key, nullptr); + + using CacheData = BlockData, std::chrono::milliseconds>; + UdmfServiceImpl::BlockDelayData data; + data.tokenId = query.tokenId; + data.blockData = std::make_shared(100); + service.blockDelayDataCache_.Insert(query.key, data); + + data.blockData->SetValue(insertedData); + bool handled = service.HandleDelayLoad(query, result, res); + + EXPECT_TRUE(handled); + EXPECT_EQ(res, UDMF::E_OK); +} + +/** + * @tc.name: PushDelayData002 + * @tc.desc: DelayData callback and block cache not exist + * @tc.type: FUNC + */ +HWTEST_F(UdmfServiceImplTest, PushDelayData002, TestSize.Level1) +{ + QueryOption query; + query.key = "k1"; + query.tokenId = 123; + UnifiedData insertedData; + insertedData.AddRecord(std::make_shared()); + + UdmfServiceImpl service; + auto status = service.PushDelayData(query.key, insertedData); + EXPECT_EQ(status, UDMF::E_ERROR); +} + +/** + * @tc.name: PushDelayData003 + * @tc.desc: No permission + * @tc.type: FUNC + */ +HWTEST_F(UdmfServiceImplTest, PushDelayData003, TestSize.Level1) +{ + QueryOption query; + query.key = "k1"; + query.tokenId = 123; + + using CacheData = BlockData, std::chrono::milliseconds>; + UdmfServiceImpl::BlockDelayData data; + data.tokenId = query.tokenId; + data.blockData = std::make_shared(100); + UdmfServiceImpl service; + service.blockDelayDataCache_.Insert(query.key, data); + + UnifiedData insertedData; + auto status = service.PushDelayData(query.key, insertedData); + EXPECT_EQ(status, UDMF::E_NO_PERMISSION); +} + +/** + * @tc.name: PushDelayData004 + * @tc.desc: PushDelayData success + * @tc.type: FUNC + */ +HWTEST_F(UdmfServiceImplTest, PushDelayData004, TestSize.Level1) +{ + QueryOption query; + query.key = "k1"; + query.tokenId = IPCSkeleton::GetSelfTokenID(); + + using CacheData = BlockData, std::chrono::milliseconds>; + UdmfServiceImpl::BlockDelayData data; + data.tokenId = query.tokenId; + data.blockData = std::make_shared(100); + UdmfServiceImpl service; + service.blockDelayDataCache_.Insert(query.key, data); + + Privilege privilege; + privilege.tokenId = query.tokenId; + service.privilegeCache_[query.key] = privilege; + + UnifiedData insertedData; + auto status = service.PushDelayData(query.key, insertedData); + EXPECT_EQ(status, UDMF::E_OK); +} }; // namespace DistributedDataTest }; // namespace OHOS::Test diff --git a/services/distributeddataservice/service/udmf/udmf_service_impl.cpp b/services/distributeddataservice/service/udmf/udmf_service_impl.cpp index 36e4deba58ef0d86f6020e2ab934f2999782057d..0611b796f86931ee8e0b00dfa3501c4e85d3394f 100644 --- a/services/distributeddataservice/service/udmf/udmf_service_impl.cpp +++ b/services/distributeddataservice/service/udmf/udmf_service_impl.cpp @@ -67,6 +67,7 @@ constexpr const char *DEVICE_PHONE_TAG = "phone"; constexpr const char *DEVICE_DEFAULT_TAG = "default"; constexpr const char *HAP_LIST[] = {"com.ohos.pasteboarddialog"}; constexpr uint32_t FOUNDATION_UID = 5523; +constexpr uint32_t WAIT_TIME = 800; __attribute__((used)) UdmfServiceImpl::Factory UdmfServiceImpl::factory_; UdmfServiceImpl::Factory::Factory() { @@ -174,12 +175,16 @@ int32_t UdmfServiceImpl::GetData(const QueryOption &query, UnifiedData &unifiedD std::string bundleName; if (!PreProcessUtils::GetHapBundleNameByToken(query.tokenId, bundleName)) { msg.appId = "unknown"; - res = E_ERROR; - } else { - msg.appId = bundleName; + Reporter::GetInstance()->GetBehaviourReporter()->UDMFReport(msg); + ZLOGE("Failed to get bundle name by token, token:%{public}d", query.tokenId); + return E_ERROR; + } + msg.appId = bundleName; + + bool handledByDelay = HandleDelayLoad(query, unifiedData, res); + if (!handledByDelay) { res = RetrieveData(query, unifiedData); } - TransferToEntriesIfNeed(query, unifiedData); auto errFind = ERROR_MAP.find(res); msg.result = errFind == ERROR_MAP.end() ? "E_ERROR" : errFind->second; for (const auto &record : unifiedData.GetRecords()) { @@ -190,9 +195,36 @@ int32_t UdmfServiceImpl::GetData(const QueryOption &query, UnifiedData &unifiedD msg.dataType = types; msg.dataSize = unifiedData.GetSize(); Reporter::GetInstance()->GetBehaviourReporter()->UDMFReport(msg); + if (res != E_OK) { + ZLOGE("GetData failed, res:%{public}d, key:%{public}s", res, query.key.c_str()); + } return res; } +bool UdmfServiceImpl::HandleDelayLoad(const QueryOption &query, UnifiedData &unifiedData, int32_t &res) +{ + return dataLoadCallback_.ComputeIfPresent(query.key, [&](const auto &key, auto &callback) { + std::shared_ptr, std::chrono::milliseconds>> blockData; + auto [found, cache] = blockDelayDataCache_.Find(key); + if (!found) { + blockData = std::make_shared, std::chrono::milliseconds>>(WAIT_TIME); + blockDelayDataCache_.Insert(key, BlockDelayData{query.tokenId, blockData}); + callback->HandleDelayObserver(key, DataLoadInfo()); + } else { + blockData = cache.blockData; + } + ZLOGI("Start waiting for data, key:%{public}s", key.c_str()); + auto dataOpt = blockData->GetValue(); + if (dataOpt.has_value()) { + unifiedData = *dataOpt; + blockDelayDataCache_.Erase(key); + return false; + } + res = E_NOT_FOUND; + return true; + }); +} + bool UdmfServiceImpl::CheckDragParams(UnifiedKey &key, const QueryOption &query) { if (!key.IsValid()) { @@ -247,11 +279,9 @@ int32_t UdmfServiceImpl::RetrieveData(const QueryOption &query, UnifiedData &uni return E_NO_PERMISSION; } } - if (!IsReadAndKeep(runtime->privileges, query)) { - if (LifeCycleManager::GetInstance().OnGot(key) != E_OK) { - ZLOGE("Remove data failed:%{public}s", key.intention.c_str()); - return E_DB_ERROR; - } + if (!IsReadAndKeep(runtime->privileges, query) && LifeCycleManager::GetInstance().OnGot(key) != E_OK) { + ZLOGE("Remove data failed:%{public}s", key.intention.c_str()); + return E_DB_ERROR; } { @@ -259,6 +289,7 @@ int32_t UdmfServiceImpl::RetrieveData(const QueryOption &query, UnifiedData &uni privilegeCache_.erase(query.key); } PreProcessUtils::SetRemoteData(unifiedData); + TransferToEntriesIfNeed(query, unifiedData); return E_OK; } @@ -1198,6 +1229,14 @@ int32_t UdmfServiceImpl::SetDelayInfo(const DataLoadInfo &dataLoadInfo, sptr(IPCSkeleton::GetCallingTokenID()); @@ -1210,13 +1249,8 @@ int32_t UdmfServiceImpl::PushDelayData(const std::string &key, UnifiedData &unif ZLOGW("SetRemoteUri failed, ret:%{public}d, key:%{public}s.", ret, key.c_str()); } - auto it = delayDataCallback_.Find(key); - if (!it.first) { - ZLOGE("DelayData callback no exist, key:%{public}s", key.c_str()); - return E_ERROR; - } QueryOption query; - query.tokenId = it.second.tokenId; + query.tokenId = isDataLoading ? delayIt.second.tokenId : blockIt.second.tokenId; query.key = key; if (option.tokenId != query.tokenId && !IsPermissionInCache(query)) { ZLOGE("No permission"); @@ -1232,9 +1266,13 @@ int32_t UdmfServiceImpl::PushDelayData(const std::string &key, UnifiedData &unif privilegeCache_.erase(key); } PreProcessUtils::SetRemoteData(unifiedData); - TransferToEntriesIfNeed(query, unifiedData); - return HandleDelayDataCallback(it.second, unifiedData, key); + + if (!isDataLoading) { + blockIt.second.blockData->SetValue(unifiedData); + return E_OK; + } + return HandleDelayDataCallback(delayIt.second, unifiedData, key); } int32_t UdmfServiceImpl::HandleDelayDataCallback(DelayGetDataInfo &delayGetDataInfo, UnifiedData &unifiedData, diff --git a/services/distributeddataservice/service/udmf/udmf_service_impl.h b/services/distributeddataservice/service/udmf/udmf_service_impl.h index 0260d75fdba8aa8a8dbce25d6736d9bc8fc9a8e6..beef4dda4af40b975f557f4139e4a7d750f219ba 100644 --- a/services/distributeddataservice/service/udmf/udmf_service_impl.h +++ b/services/distributeddataservice/service/udmf/udmf_service_impl.h @@ -16,12 +16,13 @@ #ifndef UDMF_SERVICE_IMPL_H #define UDMF_SERVICE_IMPL_H -#include "store_cache.h" -#include "udmf_service_stub.h" +#include "block_data.h" +#include "checker_manager.h" #include "kv_store_delegate_manager.h" #include "metadata/store_meta_data.h" -#include "checker_manager.h" +#include "store_cache.h" #include "udmf_notifier_proxy.h" +#include "udmf_service_stub.h" namespace OHOS { namespace UDMF { /* @@ -92,6 +93,7 @@ private: std::vector ProcessResult(const std::map &results); DistributedData::StoreMetaData BuildMeta(const std::string &storeId, int userId); int32_t VerifyUpdatePermission(const QueryOption &query, UnifiedData &unifiedData, std::string &bundleName); + bool HandleDelayLoad(const QueryOption &query, UnifiedData &unifiedData, int32_t &res); class Factory { public: @@ -110,6 +112,12 @@ private: std::unordered_map asyncProcessInfoMap_ {}; ConcurrentMap> dataLoadCallback_ {}; ConcurrentMap delayDataCallback_ {}; + + struct BlockDelayData { + uint32_t tokenId {0}; + std::shared_ptr, std::chrono::milliseconds>> blockData; + }; + ConcurrentMap blockDelayDataCache_ {}; }; } // namespace UDMF } // namespace OHOS