From b287884334798c2d095765f78f39fcd3e192048e Mon Sep 17 00:00:00 2001 From: "baozeyu1@huawei.com" Date: Thu, 22 May 2025 14:29:26 +0800 Subject: [PATCH] report slot enabled Signed-off-by: baozeyu1@huawei.com --- .../ans/include/notification_analytics_util.h | 31 +++ .../ans/include/notification_preferences.h | 2 + .../notification_preferences_database.h | 2 + .../ans/include/notification_rdb_data_mgr.h | 10 + .../advanced_notification_publish_service.cpp | 1 + .../common/notification_analytics_util.cpp | 224 ++++++++++++++++++ services/ans/src/notification_preferences.cpp | 9 + .../src/notification_preferences_database.cpp | 17 ++ .../ans/src/notification_rdb_data_mgr.cpp | 74 ++++++ 9 files changed, 370 insertions(+) diff --git a/services/ans/include/notification_analytics_util.h b/services/ans/include/notification_analytics_util.h index 055304076..0263dda41 100644 --- a/services/ans/include/notification_analytics_util.h +++ b/services/ans/include/notification_analytics_util.h @@ -23,6 +23,13 @@ namespace OHOS { namespace Notification { +namespace { + const static std::string LINE = "_"; + const static std::string ANS_BUNDLE_BEGIN = "ans_bundle"; + const static std::string LIVE_VIEW_SLOT_ENABLE_END = "slot_type_5_enabled"; + const static std::string NAME = "name"; + const static std::string UID = "uid"; +} enum EventSceneId { SCENE_0 = 0, @@ -152,6 +159,13 @@ struct BadgeInfo { bool isNeedReport; }; +struct ReportSlotMessage { + std::string bundleName; + int32_t uid; + int32_t slotType; + bool status; +}; + class NotificationAnalyticsUtil { public: static void ReportPublishFailedEvent(const sptr& request, const HaMetaMessage& message); @@ -183,6 +197,7 @@ public: static void ReportBadgeChange(const sptr &badgeData); + static bool ReportAllBundlesSlotEnabled(); private: static void ReportNotificationEvent(const sptr& request, EventFwk::Want want, int32_t eventCode, const std::string& reason); @@ -235,6 +250,22 @@ private: static void CheckBadgeReport(); static void AggregateBadgeChange(); + + static bool CheckSlotNeedReport(); + + static bool GetAllSlotMessageCache(const int32_t &userId); + + static bool GetReportSlotMessage(std::string& budleEntryKey, std::string& budleEntryValue, + ReportSlotMessage& reportSlotMessage, const int32_t &userId); + + static bool CreateSlotTimerExecute(const int32_t &userId); + + static void ExecuteSlotReportList(); + + static bool ReportSlotEnable(); + + static bool BuildSlotReportCache(ReportCache& reportCache, + std::list& slotEnabledReportList); }; } // namespace Notification } // namespace OHOS diff --git a/services/ans/include/notification_preferences.h b/services/ans/include/notification_preferences.h index 97eed85dc..cfce6f59c 100644 --- a/services/ans/include/notification_preferences.h +++ b/services/ans/include/notification_preferences.h @@ -402,6 +402,8 @@ public: int32_t SetKvToDb(const std::string &key, const std::string &value, const int32_t &userId); int32_t SetByteToDb(const std::string &key, const std::vector &value, const int32_t &userId); int32_t GetKvFromDb(const std::string &key, std::string &value, const int32_t &userId); + int32_t GetBatchKvsFromDbContainsKey( + const std::string &key, std::unordered_map &values, const int32_t &userId); int32_t GetByteFromDb(const std::string &key, std::vector &value, const int32_t &userId); int32_t GetBatchKvsFromDb( const std::string &key, std::unordered_map &values, const int32_t &userId); diff --git a/services/ans/include/notification_preferences_database.h b/services/ans/include/notification_preferences_database.h index b0ad444f1..198e4af45 100644 --- a/services/ans/include/notification_preferences_database.h +++ b/services/ans/include/notification_preferences_database.h @@ -264,6 +264,8 @@ public: int32_t GetByteFromDb(const std::string &key, std::vector &value, const int32_t &userId); int32_t GetBatchKvsFromDb( const std::string &key, std::unordered_map &values, const int32_t &userId); + int32_t GetBatchKvsFromDbContainsKey( + const std::string &key, std::unordered_map &values, const int32_t &userId); int32_t DeleteKvFromDb(const std::string &key, const int32_t &userId); int32_t DeleteBatchKvFromDb(const std::vector &keys, const int &userId); int32_t DropUserTable(const int32_t userId); diff --git a/services/ans/include/notification_rdb_data_mgr.h b/services/ans/include/notification_rdb_data_mgr.h index e8e980312..d694334eb 100644 --- a/services/ans/include/notification_rdb_data_mgr.h +++ b/services/ans/include/notification_rdb_data_mgr.h @@ -134,6 +134,14 @@ public: int32_t QueryDataBeginWithKey(const std::string &key, std::unordered_map &values, const int32_t &userId = -1); + /** + * @brief Query data Contains whith key in DB. + * @param userId Optional, Indicate which table to query data. + * @return Returns ERR_OK on success, others on failure. + */ + int32_t QueryDataContainsWithKey(const std::string &key, std::unordered_map &values, + const int32_t &userId = -1); + /** * @brief Query all data in DB. * @param userId Optional, Indicate which table to query data. @@ -156,6 +164,8 @@ private: int32_t QueryData(const std::string tableName, const std::string key, std::vector &value); int32_t QueryDataBeginWithKey(const std::string tableName, const std::string key, std::unordered_map &values); + int32_t QueryDataContainsWithKey(const std::string tableName, const std::string key, + std::unordered_map &values); int32_t QueryAllData(const std::string tableName, std::unordered_map &datas); int32_t InitCreatedTables(); int32_t RestoreForMasterSlaver(); diff --git a/services/ans/src/advanced_notification_publish_service.cpp b/services/ans/src/advanced_notification_publish_service.cpp index 8f7556ddb..9cb530507 100644 --- a/services/ans/src/advanced_notification_publish_service.cpp +++ b/services/ans/src/advanced_notification_publish_service.cpp @@ -199,6 +199,7 @@ ErrCode AdvancedNotificationService::Publish(const std::string &label, const spt } } while (0); + NotificationAnalyticsUtil::ReportAllBundlesSlotEnabled(); SendPublishHiSysEvent(request, result); return result; } diff --git a/services/ans/src/common/notification_analytics_util.cpp b/services/ans/src/common/notification_analytics_util.cpp index b3c651104..0d14f3e01 100644 --- a/services/ans/src/common/notification_analytics_util.cpp +++ b/services/ans/src/common/notification_analytics_util.cpp @@ -28,6 +28,9 @@ #include "nlohmann/json.hpp" #include "bundle_manager_helper.h" #include "notification_config_parse.h" +#include "notification_preferences.h" +#include "os_account_manager_helper.h" +#include "notification_constant.h" namespace OHOS { namespace Notification { @@ -100,6 +103,19 @@ static bool g_successReportFlag = false; static std::shared_ptr reportAggregateTimeInfo = std::make_shared(); static std::list reportAggList; +static int32_t SLOT_REPORT_INTERVAL = 7 * 24 * NotificationConstant::HOUR_TO_MS; +static int64_t lastReportTime_ = 0; +static std::mutex lastReportTimeMutex_; +static int32_t SLOT_SUB_CODE = 101; +static int32_t SLOT_ONCE_REPORT = 10; +static uint32_t SLOT_MAX_REPORT = 200; +static uint64_t reportSlotEnabledTimerId_ = 0; +static std::shared_ptr slotTimeInfo = std::make_shared(); +static std::list slotEnabledList_; +static std::mutex slotEnabledListMutex_; +static bool g_reportSlotFlag = false; +static std::mutex reportSlotEnabledMutex_; + HaMetaMessage::HaMetaMessage(uint32_t sceneId, uint32_t branchId) : sceneId_(sceneId), branchId_(branchId) { @@ -1145,5 +1161,213 @@ void NotificationAnalyticsUtil::ReportSkipFailedEvent(const HaMetaMessage& messa IN_PROCESS_CALL_WITHOUT_RET(AddListCache(want, MODIFY_ERROR_EVENT_CODE)); } + +bool NotificationAnalyticsUtil::ReportAllBundlesSlotEnabled() +{ + if (!CheckSlotNeedReport()) { + return false; + } + + int32_t userId = SUBSCRIBE_USER_INIT; + OsAccountManagerHelper::GetInstance().GetCurrentActiveUserId(userId); + + if (userId == SUBSCRIBE_USER_INIT) { + ANS_LOGE("userId is failed"); + return false; + } + + if (!CreateSlotTimerExecute(userId)) { + return false; + } + return true; +} + +bool NotificationAnalyticsUtil::CreateSlotTimerExecute(const int32_t &userId) +{ + std::lock_guard lock(reportSlotEnabledMutex_); + if (g_reportSlotFlag) { + ANS_LOGW("now has message is reporting"); + return false; + } + + sptr timer = + MiscServices::TimeServiceClient::GetInstance(); + if (timer == nullptr) { + ANS_LOGE("Failed to start timer due to get TimeServiceClient is null."); + g_reportSlotFlag = false; + return false; + } + if (reportSlotEnabledTimerId_ == 0) { + reportSlotEnabledTimerId_ = timer->CreateTimer(slotTimeInfo); + } + + auto triggerFunc = [userId] { + ANS_LOGI("trigger is arrived, userid:%{public}d", userId); + GetAllSlotMessageCache(userId); + ExecuteSlotReportList(); + }; + + slotTimeInfo->SetCallbackInfo(triggerFunc); + timer->StartTimer(reportSlotEnabledTimerId_, NotificationAnalyticsUtil::GetCurrentTime() + + DEFAULT_ERROR_EVENT_TIME * NotificationConstant::SECOND_TO_MS); + g_reportSlotFlag = true; + return true; +} + +void NotificationAnalyticsUtil::ExecuteSlotReportList() +{ + std::lock_guard lock(reportSlotEnabledMutex_); + + if (!ReportSlotEnable()) { + g_reportSlotFlag = false; + return; + } + + sptr timer = MiscServices::TimeServiceClient::GetInstance(); + if (timer == nullptr) { + ANS_LOGE("Failed to start timer due to get TimeServiceClient is null."); + g_reportSlotFlag = false; + return; + } + auto triggerFunc = [] { + ExecuteSlotReportList(); + }; + + slotTimeInfo->SetCallbackInfo(triggerFunc); + timer->StartTimer(reportSlotEnabledTimerId_, NotificationAnalyticsUtil::GetCurrentTime() + + DEFAULT_ERROR_EVENT_TIME * NotificationConstant::SECOND_TO_MS); + g_reportSlotFlag = true; +} + +bool NotificationAnalyticsUtil::ReportSlotEnable() +{ + std::lock_guard lock(slotEnabledListMutex_); + if (slotEnabledList_.empty()) { + ANS_LOGI("report end"); + return false; + } + + std::list slotEnabledReportList; + int count = SLOT_ONCE_REPORT; + while (count-- > 0 && !slotEnabledList_.empty()) { + auto slotMessage = slotEnabledList_.front(); + slotEnabledReportList.push_back(slotMessage); + slotEnabledList_.pop_front(); + } + + ReportCache reportCache; + BuildSlotReportCache(reportCache, slotEnabledReportList); + ReportCommonEvent(reportCache); + return true; +} + +bool NotificationAnalyticsUtil::BuildSlotReportCache(ReportCache &reportCache, + std::list &slotEnabledReportList) +{ + nlohmann::json ansData; + ansData["subCode"] = std::to_string(SLOT_SUB_CODE); + nlohmann::json dataArray; + for (const auto &report : slotEnabledReportList) { + nlohmann::json dataItem; + dataItem["slotType"] = report.slotType; + dataItem["status"] = report.status; + dataItem["bundleName"] = report.bundleName; + dataItem["uid"] = report.uid; + dataArray.push_back(dataItem); + } + ansData["data"] = dataArray; + + std::string message = ansData.dump(-1, ' ', false, + nlohmann::json::error_handler_t::replace); + EventFwk::Want want; + want.SetAction(NOTIFICATION_EVENT_PUSH_AGENT); + want.SetParam("ansData", message); + + reportCache.want = want; + reportCache.eventCode = ANS_CUSTOMIZE_CODE; + return true; +} + +bool NotificationAnalyticsUtil::CheckSlotNeedReport() +{ + std::lock_guard lock(lastReportTimeMutex_); + auto now = GetCurrentTime(); + if (lastReportTime_ != 0 && abs(now - lastReportTime_) <= SLOT_REPORT_INTERVAL) { + ANS_LOGD("no need report"); + return false; + } + + ANS_LOGI("slot enabled need report"); + lastReportTime_ = now; + return true; +} + +bool NotificationAnalyticsUtil::GetAllSlotMessageCache(const int32_t &userId) +{ + std::unordered_map slotEnablesMap; + auto res = NotificationPreferences::GetInstance()->GetBatchKvsFromDbContainsKey( + LIVE_VIEW_SLOT_ENABLE_END, slotEnablesMap, userId); + if (res != ERR_OK) { + ANS_LOGW("message is err:%{public}d, userId:%{public}d ", res, userId); + return false; + } + + if (slotEnablesMap.size() == 0 || slotEnablesMap.size() > SLOT_MAX_REPORT) { + ANS_LOGW("slotEnablesMap size %{public}zu", slotEnablesMap.size()); + return false; + } + std::lock_guard lock(slotEnabledListMutex_); + for (const auto& budleEntry : slotEnablesMap) { + std::string budleEntryKey = budleEntry.first; + // enable + ReportSlotMessage reportSlotMessage; + std::string budleEntryValue = budleEntry.second; + NotificationAnalyticsUtil::GetReportSlotMessage(budleEntryKey, + budleEntryValue, reportSlotMessage, userId); + slotEnabledList_.push_back(reportSlotMessage); + } + return true; +} + +bool NotificationAnalyticsUtil::GetReportSlotMessage(std::string& budleEntryKey, + std::string& budleEntryValue, ReportSlotMessage& reportSlotMessage, const int32_t &userId) +{ + // find first + size_t firstUnderscore = budleEntryKey.find('_'); + // find second + size_t secondUnderscore = budleEntryKey.find('_', firstUnderscore + 1); + // find third + size_t thirdUnderscore = budleEntryKey.find('_', secondUnderscore + 1); + // get bundle string + std::string extracted = budleEntryKey.substr(secondUnderscore + 1, thirdUnderscore - secondUnderscore - 1); + + std::unordered_map bundleInfoMap; + auto res = NotificationPreferences::GetInstance()->GetBatchKvsFromDbContainsKey( + extracted, bundleInfoMap, userId); + if (res != ERR_OK) { + ANS_LOGW("get bundleInfoMap is err:%{public}d", res); + return false; + } + + auto nameIt = bundleInfoMap.find(ANS_BUNDLE_BEGIN + LINE + extracted + LINE + NAME); + auto uidIt = bundleInfoMap.find(ANS_BUNDLE_BEGIN + LINE + extracted + LINE + UID); + if (nameIt == bundleInfoMap.end() || uidIt == bundleInfoMap.end()) { + ANS_LOGW("bundleInfoMap is empty, database error"); + return false; + } + + // data process + std::string bundleName = nameIt->second; + int32_t uid = std::atoi(uidIt->second.c_str()); + bool enable = std::atoi(budleEntryValue.c_str()); + ANS_LOGI("budleInfoEntry uid %{public}d, name is:%{public}s, enabled:%{public}d", + uid, bundleName.c_str(), enable); + reportSlotMessage.uid = uid; + reportSlotMessage.status = enable; + reportSlotMessage.slotType = static_cast( + NotificationConstant::SlotType::LIVE_VIEW); + reportSlotMessage.bundleName = bundleName; + return true; +} } // namespace Notification } // namespace OHOS diff --git a/services/ans/src/notification_preferences.cpp b/services/ans/src/notification_preferences.cpp index 488a956cb..63c514263 100644 --- a/services/ans/src/notification_preferences.cpp +++ b/services/ans/src/notification_preferences.cpp @@ -1268,6 +1268,15 @@ int32_t NotificationPreferences::GetByteFromDb( return preferncesDB_->GetByteFromDb(key, value, userId); } +int32_t NotificationPreferences::GetBatchKvsFromDbContainsKey( + const std::string &key, std::unordered_map &values, const int32_t &userId) +{ + if (preferncesDB_ == nullptr) { + return ERR_ANS_SERVICE_NOT_READY; + } + return preferncesDB_->GetBatchKvsFromDbContainsKey(key, values, userId); +} + int32_t NotificationPreferences::GetBatchKvsFromDb( const std::string &key, std::unordered_map &values, const int32_t &userId) { diff --git a/services/ans/src/notification_preferences_database.cpp b/services/ans/src/notification_preferences_database.cpp index 81a380ec8..dc104ed8a 100644 --- a/services/ans/src/notification_preferences_database.cpp +++ b/services/ans/src/notification_preferences_database.cpp @@ -1925,6 +1925,23 @@ int32_t NotificationPreferencesDatabase::GetBatchKvsFromDb( return NativeRdb::E_OK; } +int32_t NotificationPreferencesDatabase::GetBatchKvsFromDbContainsKey( + const std::string &key, std::unordered_map &values, const int32_t &userId) +{ + if (!CheckRdbStore()) { + ANS_LOGE("RdbStore is nullptr."); + return NativeRdb::E_ERROR; + } + + int32_t result = rdbDataManager_->QueryDataContainsWithKey(key, values, userId); + if (result != NativeRdb::E_OK) { + ANS_LOGE("QueryDataContainsWithKey failed, key %{public}s, result %{public}d.", key.c_str(), result); + return NativeRdb::E_ERROR; + } + ANS_LOGD("Key:%{public}s.", key.c_str()); + return NativeRdb::E_OK; +} + int32_t NotificationPreferencesDatabase::DeleteKvFromDb(const std::string &key, const int32_t &userId) { if (!CheckRdbStore()) { diff --git a/services/ans/src/notification_rdb_data_mgr.cpp b/services/ans/src/notification_rdb_data_mgr.cpp index 9a75b4a65..55cb92b5b 100644 --- a/services/ans/src/notification_rdb_data_mgr.cpp +++ b/services/ans/src/notification_rdb_data_mgr.cpp @@ -559,6 +559,80 @@ int32_t NotificationDataMgr::QueryDataBeginWithKey( return NativeRdb::E_OK; } +int32_t NotificationDataMgr::QueryDataContainsWithKey( + const std::string &key, std::unordered_map &values, const int32_t &userId) +{ + ANS_LOGD("QueryDataContainsWithKey start"); + std::vector operatedTables = GenerateOperatedTables(userId); + std::lock_guard lock(rdbStorePtrMutex_); + if (rdbStore_ == nullptr) { + ANS_LOGE("notification rdb is null"); + return NativeRdb::E_ERROR; + } + int32_t ret = NativeRdb::E_OK; + for (auto tableName : operatedTables) { + ret = QueryDataContainsWithKey(tableName, key, values); + if (ret == NativeRdb::E_ERROR) { + return ret; + } + } + if (ret == NativeRdb::E_EMPTY_VALUES_BUCKET && values.empty()) { + return NativeRdb::E_EMPTY_VALUES_BUCKET; + } + return NativeRdb::E_OK; +} + +int32_t NotificationDataMgr::QueryDataContainsWithKey( + const std::string tableName, const std::string key, std::unordered_map &values) +{ + NativeRdb::AbsRdbPredicates absRdbPredicates(tableName); + HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_10, EventBranchId::BRANCH_9); + absRdbPredicates.Contains(NOTIFICATION_KEY, key); + auto absSharedResultSet = rdbStore_->Query(absRdbPredicates, std::vector()); + if (absSharedResultSet == nullptr) { + ANS_LOGE("absSharedResultSet failed from %{public}s table.", tableName.c_str()); + return NativeRdb::E_ERROR; + } + int32_t ret = absSharedResultSet->GoToFirstRow(); + if (ret == NativeRdb::E_SQLITE_CORRUPT) { + RestoreForMasterSlaver(); + } + if (ret != NativeRdb::E_OK) { + ANS_LOGD("GoToFirstRow failed from %{public}s table.It is empty!, key=%{public}s", + tableName.c_str(), key.c_str()); + if (ret != NativeRdb::E_ROW_OUT_RANGE) { + ANS_LOGW("GoToFirstRow failed, rdb error is %{public}d.", ret); + message.ErrorCode(ret).Message("GoToFirstRow failed."); + NotificationAnalyticsUtil::ReportModifyEvent(message); + } + absSharedResultSet->Close(); + return NativeRdb::E_EMPTY_VALUES_BUCKET; + } + do { + std::string resultKey; + ret = absSharedResultSet->GetString(NOTIFICATION_KEY_INDEX, resultKey); + if (ret != NativeRdb::E_OK) { + ANS_LOGE("Failed to GetString key from %{public}s table.", tableName.c_str()); + message.ErrorCode(ret).Message("GetString key failed."); + NotificationAnalyticsUtil::ReportModifyEvent(message); + absSharedResultSet->Close(); + return NativeRdb::E_ERROR; + } + std::string resultValue; + ret = absSharedResultSet->GetString(NOTIFICATION_VALUE_INDEX, resultValue); + if (ret != NativeRdb::E_OK) { + ANS_LOGE("GetString value failed from %{public}s table", tableName.c_str()); + message.ErrorCode(ret).Message("GetString value failed."); + NotificationAnalyticsUtil::ReportModifyEvent(message); + absSharedResultSet->Close(); + return NativeRdb::E_ERROR; + } + values.emplace(resultKey, resultValue); + } while (absSharedResultSet->GoToNextRow() == NativeRdb::E_OK); + absSharedResultSet->Close(); + return NativeRdb::E_OK; +} + int32_t NotificationDataMgr::QueryAllData(std::unordered_map &datas, const int32_t &userId) { ANS_LOGD("QueryAllData start"); -- Gitee