• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 
16 #include "notification_analytics_util.h"
17 
18 #include "want_params_wrapper.h"
19 #include "string_wrapper.h"
20 #include "common_event_manager.h"
21 #include "common_event_support.h"
22 #include "common_event_publish_info.h"
23 #include "ans_convert_enum.h"
24 #include "ans_permission_def.h"
25 #include "in_process_call_wrapper.h"
26 #include "report_timer_info.h"
27 #include "time_service_client.h"
28 #include "nlohmann/json.hpp"
29 #include "bundle_manager_helper.h"
30 #include "notification_config_parse.h"
31 
32 namespace OHOS {
33 namespace Notification {
34 constexpr char MESSAGE_DELIMITER = '#';
35 constexpr const int32_t PUBLISH_ERROR_EVENT_CODE = 0;
36 constexpr const int32_t DELETE_ERROR_EVENT_CODE = 5;
37 constexpr const int32_t MODIFY_ERROR_EVENT_CODE = 6;
38 constexpr const int32_t ANS_CUSTOMIZE_CODE = 7;
39 
40 constexpr const int32_t DEFAULT_ERROR_EVENT_COUNT = 5;
41 constexpr const int32_t DEFAULT_ERROR_EVENT_TIME = 60;
42 constexpr const int32_t MODIFY_ERROR_EVENT_COUNT = 6;
43 constexpr const int32_t MODIFY_ERROR_EVENT_TIME = 60;
44 constexpr const int32_t MAX_NUMBER_EVERY_REPORT = 20;
45 constexpr const int32_t MAX_REPORT_COUNT = 3;
46 
47 constexpr const int32_t REPORT_CACHE_MAX_SIZE = 50;
48 constexpr const int32_t SUCCESS_REPORT_CACHE_MAX_SIZE = 60;
49 constexpr const int32_t REPORT_CACHE_INTERVAL_TIME = 30;
50 constexpr const int32_t SUCCESS_REPORT_CACHE_INTERVAL_TIME = 1800;
51 constexpr const int32_t REASON_MAX_LENGTH = 127;
52 constexpr const int32_t SUB_CODE = 100;
53 constexpr const int32_t MAX_TIME = 43200000;
54 constexpr const int32_t NOTIFICATION_MAX_DATA = 100;
55 constexpr const int32_t SOUND_FLAG = 1 << 10;
56 constexpr const int32_t LOCKSCREEN_FLAG = 1 << 11;
57 constexpr const int32_t BANNER_FLAG = 1 << 12;
58 constexpr const int32_t VIBRATION_FLAG = 1 << 13;
59 
60 const static std::string NOTIFICATION_EVENT_PUSH_AGENT = "notification.event.PUSH_AGENT";
61 static std::mutex reportFlowControlMutex_;
62 static std::map<int32_t, std::list<std::chrono::system_clock::time_point>> flowControlTimestampMap_ = {
63     {MODIFY_ERROR_EVENT_CODE, {}},
64     {PUBLISH_ERROR_EVENT_CODE, {}},
65     {DELETE_ERROR_EVENT_CODE, {}},
66     {ANS_CUSTOMIZE_CODE, {}},
67 };
68 
69 int32_t HaMetaMessage::syncWatch_ = 0;
70 int32_t HaMetaMessage::syncHeadSet_ = 0;
71 int32_t HaMetaMessage::syncWatchHeadSet_ = 0;
72 int32_t HaMetaMessage::keyNode_ = 0;
73 int64_t HaMetaMessage::time_ = NotificationAnalyticsUtil::GetCurrentTime();
74 int32_t HaMetaMessage::syncLiveViewWatch_ = 0;
75 int32_t HaMetaMessage::syncLiveViewHeadSet_ = 0;
76 int32_t HaMetaMessage::syncLiveViewWatchHeadSet_ = 0;
77 int64_t HaMetaMessage::liveViewTime_ = NotificationAnalyticsUtil::GetCurrentTime();
78 int32_t HaMetaMessage::delByWatch_ = 0;
79 int32_t HaMetaMessage::liveViewDelByWatch_ = 0;
80 int32_t HaMetaMessage::clickByWatch_ = 0;
81 int32_t HaMetaMessage::replyByWatch_ = 0;
82 static std::mutex reportCacheMutex_;
83 static uint64_t reportTimerId = 0;
84 static std::list<ReportCache> reportCacheList;
85 static bool g_reportFlag = false;
86 static std::shared_ptr<ReportTimerInfo> reportTimeInfo = std::make_shared<ReportTimerInfo>();
87 
88 static std::mutex reportSuccessCacheMutex_;
89 static uint64_t reportSuccessTimerId = 0;
90 static std::list<ReportCache> successReportCacheList;
91 static bool g_successReportFlag = false;
92 static std::shared_ptr<ReportTimerInfo> reportSuccessTimeInfo = std::make_shared<ReportTimerInfo>();
93 
HaMetaMessage(uint32_t sceneId,uint32_t branchId)94 HaMetaMessage::HaMetaMessage(uint32_t sceneId, uint32_t branchId)
95     : sceneId_(sceneId), branchId_(branchId)
96 {
97 }
98 
NeedReport() const99 bool HaMetaMessage::NeedReport() const
100 {
101     if (errorCode_ == ERR_OK && checkfailed_) {
102         return false;
103     }
104     return true;
105 }
106 
SceneId(uint32_t sceneId)107 HaMetaMessage& HaMetaMessage::SceneId(uint32_t sceneId)
108 {
109     sceneId_ = sceneId;
110     return *this;
111 }
112 
BranchId(uint32_t branchId)113 HaMetaMessage& HaMetaMessage::BranchId(uint32_t branchId)
114 {
115     branchId_ = branchId;
116     return *this;
117 }
118 
ErrorCode(uint32_t errorCode)119 HaMetaMessage& HaMetaMessage::ErrorCode(uint32_t errorCode)
120 {
121     errorCode_ = errorCode;
122     return *this;
123 }
124 
Message(const std::string & message,bool print)125 HaMetaMessage& HaMetaMessage::Message(const std::string& message, bool print)
126 {
127     message_ = message;
128     if (print) {
129         ANSR_LOGE("%{public}s, %{public}d", message.c_str(), errorCode_);
130     }
131     return *this;
132 }
133 
Append(const std::string & message)134 HaMetaMessage& HaMetaMessage::Append(const std::string& message)
135 {
136     message_+=message;
137     return *this;
138 }
Checkfailed(bool checkfailed)139 HaMetaMessage& HaMetaMessage::Checkfailed(bool checkfailed)
140 {
141     checkfailed_ = checkfailed;
142     return *this;
143 }
144 
BundleName(const std::string & bundleName)145 HaMetaMessage& HaMetaMessage::BundleName(const std::string& bundleName)
146 {
147     bundleName_ = bundleName;
148     return *this;
149 }
150 
AgentBundleName(const std::string & agentBundleName)151 HaMetaMessage& HaMetaMessage::AgentBundleName(const std::string& agentBundleName)
152 {
153     agentBundleName_ = agentBundleName;
154     return *this;
155 }
156 
TypeCode(int32_t typeCode)157 HaMetaMessage& HaMetaMessage::TypeCode(int32_t typeCode)
158 {
159     typeCode_ = typeCode;
160     return *this;
161 }
162 
NotificationId(int32_t notificationId)163 HaMetaMessage& HaMetaMessage::NotificationId(int32_t notificationId)
164 {
165     notificationId_ = notificationId;
166     return *this;
167 }
168 
GetMessage() const169 std::string HaMetaMessage::GetMessage() const
170 {
171     return message_;
172 }
173 
SlotType(int32_t slotType)174 HaMetaMessage& HaMetaMessage::SlotType(int32_t slotType)
175 {
176     slotType_ = static_cast<uint32_t>(slotType);
177     return *this;
178 }
179 
DeleteReason(int32_t deleteReason)180 HaMetaMessage& HaMetaMessage::DeleteReason(int32_t deleteReason)
181 {
182     deleteReason_ = deleteReason;
183     return *this;
184 }
185 
SyncWatch(bool isLiveView)186 HaMetaMessage& HaMetaMessage::SyncWatch(bool isLiveView)
187 {
188     if (isLiveView) {
189         HaMetaMessage::syncLiveViewWatch_++;
190     } else {
191         HaMetaMessage::syncWatch_++;
192     }
193     return *this;
194 }
195 
SyncHeadSet(bool isLiveView)196 HaMetaMessage& HaMetaMessage::SyncHeadSet(bool isLiveView)
197 {
198     if (isLiveView) {
199         HaMetaMessage::syncLiveViewHeadSet_++;
200     } else {
201         HaMetaMessage::syncHeadSet_++;
202     }
203     return *this;
204 }
205 
SyncWatchHeadSet(bool isLiveView)206 HaMetaMessage& HaMetaMessage::SyncWatchHeadSet(bool isLiveView)
207 {
208     if (isLiveView) {
209         HaMetaMessage::syncLiveViewWatchHeadSet_++;
210     } else {
211         HaMetaMessage::syncWatchHeadSet_++;
212     }
213     return *this;
214 }
215 
KeyNode(bool isKeyNode)216 HaMetaMessage& HaMetaMessage::KeyNode(bool isKeyNode)
217 {
218     if (isKeyNode) {
219         HaMetaMessage::keyNode_++;
220     }
221     return *this;
222 }
223 
DelByWatch(bool isLiveView)224 HaMetaMessage& HaMetaMessage::DelByWatch(bool isLiveView)
225 {
226     if (isLiveView) {
227         HaMetaMessage::liveViewDelByWatch_++;
228     } else {
229         HaMetaMessage::delByWatch_++;
230     }
231     return *this;
232 }
233 
ClickByWatch()234 HaMetaMessage& HaMetaMessage::ClickByWatch()
235 {
236     HaMetaMessage::clickByWatch_++;
237     return *this;
238 }
239 
ReplyByWatch()240 HaMetaMessage& HaMetaMessage::ReplyByWatch()
241 {
242     HaMetaMessage::replyByWatch_++;
243     return *this;
244 }
245 
Build() const246 std::string HaMetaMessage::Build() const
247 {
248     return std::to_string(sceneId_) + MESSAGE_DELIMITER +
249         std::to_string(branchId_) + MESSAGE_DELIMITER + std::to_string(errorCode_) +
250         MESSAGE_DELIMITER + message_ + MESSAGE_DELIMITER;
251 }
252 
ReportPublishFailedEvent(const sptr<NotificationRequest> & request,const HaMetaMessage & message)253 void NotificationAnalyticsUtil::ReportPublishFailedEvent(const sptr<NotificationRequest>& request,
254     const HaMetaMessage& message)
255 {
256     CommonNotificationEvent(request, PUBLISH_ERROR_EVENT_CODE, message);
257 }
258 
ReportDeleteFailedEvent(const sptr<NotificationRequest> & request,HaMetaMessage & message)259 void NotificationAnalyticsUtil::ReportDeleteFailedEvent(const sptr<NotificationRequest>& request,
260     HaMetaMessage& message)
261 {
262     if (request == nullptr || !message.NeedReport()) {
263         ANS_LOGE("request is null %{public}d", message.NeedReport());
264         return;
265     }
266     std::shared_ptr<NotificationBundleOption> agentBundleNameOption = request->GetAgentBundle();
267     if (agentBundleNameOption != nullptr) {
268         std::string agentBundleName = agentBundleNameOption->GetBundleName();
269         if (!agentBundleName.empty()) {
270             message = message.AgentBundleName(agentBundleName);
271         }
272     }
273     CommonNotificationEvent(request, DELETE_ERROR_EVENT_CODE, message);
274 }
275 
ReportPublishSuccessEvent(const sptr<NotificationRequest> & request,const HaMetaMessage & message)276 void NotificationAnalyticsUtil::ReportPublishSuccessEvent(const sptr<NotificationRequest>& request,
277     const HaMetaMessage& message)
278 {
279     ANS_LOGD("ReportPublishSuccessEvent enter");
280     if (request == nullptr) {
281         return;
282     }
283     if (!IsAllowedBundle(request)) {
284         ANS_LOGW("This Bundle not allowed.");
285         return;
286     }
287 
288     EventFwk::Want want;
289     if (!request->GetOwnerBundleName().empty()) {
290         want.SetBundle(request->GetOwnerBundleName());
291     }
292     if (!request->GetCreatorBundleName().empty()) {
293         want.SetParam("agentBundleName", request->GetCreatorBundleName());
294     }
295     std::string ansData = NotificationAnalyticsUtil::BuildAnsData(request, message);
296     want.SetParam("ansData", ansData);
297 
298     IN_PROCESS_CALL_WITHOUT_RET(AddSuccessListCache(want, ANS_CUSTOMIZE_CODE));
299 }
300 
IsAllowedBundle(const sptr<NotificationRequest> & request)301 bool NotificationAnalyticsUtil::IsAllowedBundle(const sptr<NotificationRequest>& request)
302 {
303     ANS_LOGD("IsAllowedBundle enter");
304     std::string bundleName = request->GetOwnerBundleName();
305     return DelayedSingleton<NotificationConfigParse>::GetInstance()->IsReportTrustList(bundleName);
306 }
307 
BuildAnsData(const sptr<NotificationRequest> & request,const HaMetaMessage & message)308 std::string NotificationAnalyticsUtil::BuildAnsData(const sptr<NotificationRequest>& request,
309     const HaMetaMessage& message)
310 {
311     ANS_LOGD("BuildAnsData enter.");
312     nlohmann::json ansData;
313     std::shared_ptr<AAFwk::WantParams> extraInfo = nullptr;
314     if (request->GetUnifiedGroupInfo() != nullptr &&
315         request->GetUnifiedGroupInfo()->GetExtraInfo() != nullptr) {
316         extraInfo = request->GetUnifiedGroupInfo()->GetExtraInfo();
317     } else {
318         extraInfo = std::make_shared<AAFwk::WantParams>();
319     }
320     nlohmann::json extraInfoJson;
321     std::string msgId = extraInfo->GetWantParams("pushData").GetStringParam("msgId");
322     if (!msgId.empty()) {
323         extraInfoJson["msgId"] = msgId;
324     }
325     std::string uniqMsgId = extraInfo->GetWantParams("pushData").GetStringParam("mcMsgId");
326     if (!uniqMsgId.empty()) {
327         extraInfoJson["mcMsgId"] = uniqMsgId;
328     }
329 
330     ansData["extraInfo"] = extraInfoJson.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace);
331     ansData["uid"] = std::to_string(request->GetOwnerUid());
332     ansData["id"] = std::to_string(request->GetNotificationId());
333     NotificationNapi::SlotType slotType;
334     NotificationNapi::AnsEnumUtil::SlotTypeCToJS(
335         static_cast<NotificationConstant::SlotType>(request->GetSlotType()), slotType);
336     NotificationNapi::ContentType contentType;
337     NotificationNapi::AnsEnumUtil::ContentTypeCToJS(
338         static_cast<NotificationContent::Type>(request->GetNotificationType()), contentType);
339     ansData["slotType"] = static_cast<int32_t>(slotType);
340     ansData["contentType"] = std::to_string(static_cast<int32_t>(contentType));
341     ansData["reminderFlags"] = std::to_string(static_cast<int32_t>(request->GetFlags()->GetReminderFlags()));
342     uint32_t controlFlags = request->GetNotificationControlFlags();
343     std::shared_ptr<NotificationFlags> tempFlags = request->GetFlags();
344     ansData["ControlFlags"] = SetControlFlags(tempFlags, controlFlags);
345     ansData["class"] = request->GetClassification();
346     ansData["deviceStatus"] = GetDeviceStatus(request);
347     ANS_LOGI("Ansdata built, the controlFlags is %{public}d, deviceStatus is %{public}s",
348         controlFlags, GetDeviceStatus(request).c_str());
349     return ansData.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace);
350 }
351 
GetDeviceStatus(const sptr<NotificationRequest> & request)352 std::string NotificationAnalyticsUtil::GetDeviceStatus(const sptr<NotificationRequest>& request)
353 {
354     std::map<std::string, std::string> deviceStatus = request->GetdeviceStatus();
355     nlohmann::json deviceStatusJson;
356     for (map<string, string>::const_iterator iter = deviceStatus.begin(); iter != deviceStatus.end(); ++iter) {
357         deviceStatusJson[iter->first] = iter->second;
358     }
359     return deviceStatusJson.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace);
360 }
SetControlFlags(const std::shared_ptr<NotificationFlags> & flags,uint32_t & controlFlags)361 uint32_t NotificationAnalyticsUtil::SetControlFlags(const std::shared_ptr<NotificationFlags> &flags,
362     uint32_t &controlFlags)
363 {
364     if (flags->IsSoundEnabled() == NotificationConstant::FlagStatus::OPEN) {
365         controlFlags |= SOUND_FLAG;
366     } else {
367         controlFlags &= ~SOUND_FLAG;
368     }
369     if (flags->IsVibrationEnabled() == NotificationConstant::FlagStatus::OPEN) {
370         controlFlags |= VIBRATION_FLAG;
371     } else {
372         controlFlags &= ~VIBRATION_FLAG;
373     }
374     if (flags->IsLockScreenVisblenessEnabled()) {
375         controlFlags |= LOCKSCREEN_FLAG;
376     } else {
377         controlFlags &= ~LOCKSCREEN_FLAG;
378     }
379     if (flags->IsBannerEnabled()) {
380         controlFlags |= BANNER_FLAG;
381     } else {
382         controlFlags &= ~BANNER_FLAG;
383     }
384     return controlFlags;
385 }
386 
CommonNotificationEvent(const sptr<NotificationRequest> & request,int32_t eventCode,const HaMetaMessage & message)387 void NotificationAnalyticsUtil::CommonNotificationEvent(const sptr<NotificationRequest>& request,
388     int32_t eventCode, const HaMetaMessage& message)
389 {
390     if (request == nullptr) {
391         return;
392     }
393 
394     if (!ReportFlowControl(eventCode)) {
395         ANS_LOGI("Publish event failed, eventCode:%{public}d, reason:%{public}s",
396             eventCode, message.Build().c_str());
397         return;
398     }
399     EventFwk::Want want;
400     std::string extraInfo;
401     extraInfo = NotificationAnalyticsUtil::BuildExtraInfoWithReq(message, request);
402     NotificationAnalyticsUtil::SetCommonWant(want, message, extraInfo);
403 
404     want.SetParam("typeCode", message.typeCode_);
405     IN_PROCESS_CALL_WITHOUT_RET(ReportNotificationEvent(
406         request, want, eventCode, message.Build()));
407 }
408 
ReportNotificationEvent(const sptr<NotificationRequest> & request,EventFwk::Want want,int32_t eventCode,const std::string & reason)409 void NotificationAnalyticsUtil::ReportNotificationEvent(const sptr<NotificationRequest>& request,
410     EventFwk::Want want, int32_t eventCode, const std::string& reason)
411 {
412     NotificationNapi::SlotType slotType;
413     NotificationNapi::AnsEnumUtil::SlotTypeCToJS(
414         static_cast<NotificationConstant::SlotType>(request->GetSlotType()), slotType);
415     NotificationNapi::ContentType contentType;
416     NotificationNapi::AnsEnumUtil::ContentTypeCToJS(
417         static_cast<NotificationContent::Type>(request->GetNotificationType()), contentType);
418 
419     want.SetParam("id", request->GetNotificationId());
420     want.SetParam("uid", request->GetOwnerUid());
421     want.SetParam("slotType", static_cast<int32_t>(slotType));
422     want.SetParam("contentType", std::to_string(static_cast<int32_t>(contentType)));
423 
424     if (!request->GetCreatorBundleName().empty()) {
425         want.SetParam("agentBundleName", request->GetCreatorBundleName());
426     }
427     if (!request->GetOwnerBundleName().empty()) {
428         want.SetBundle(request->GetOwnerBundleName());
429     }
430     IN_PROCESS_CALL_WITHOUT_RET(AddListCache(want, eventCode));
431 }
432 
ReportModifyEvent(const HaMetaMessage & message)433 void NotificationAnalyticsUtil::ReportModifyEvent(const HaMetaMessage& message)
434 {
435     if (!ReportFlowControl(MODIFY_ERROR_EVENT_CODE)) {
436         ANS_LOGI("Publish event failed, reason:%{public}s", message.Build().c_str());
437         return;
438     }
439     EventFwk::Want want;
440     std::string extraInfo = NotificationAnalyticsUtil::BuildExtraInfo(message);
441     NotificationAnalyticsUtil::SetCommonWant(want, message, extraInfo);
442 
443     std::string bundle;
444     int32_t callingUid = IPCSkeleton::GetCallingUid();
445     std::shared_ptr<BundleManagerHelper> bundleManager = BundleManagerHelper::GetInstance();
446     if (bundleManager != nullptr) {
447         bundle = bundleManager->GetBundleNameByUid(callingUid);
448     }
449     want.SetBundle(bundle + "_" + std::to_string(callingUid));
450     want.SetParam("slotType", static_cast<int32_t>(message.slotType_));
451     IN_PROCESS_CALL_WITHOUT_RET(AddListCache(want, MODIFY_ERROR_EVENT_CODE));
452 }
453 
ReportDeleteFailedEvent(const HaMetaMessage & message)454 void NotificationAnalyticsUtil::ReportDeleteFailedEvent(const HaMetaMessage& message)
455 {
456     if (!ReportFlowControl(DELETE_ERROR_EVENT_CODE)) {
457         ANS_LOGI("Publish event failed, reason:%{public}s", message.Build().c_str());
458         return;
459     }
460     EventFwk::Want want;
461     std::string extraInfo = NotificationAnalyticsUtil::BuildExtraInfo(message);
462     NotificationAnalyticsUtil::SetCommonWant(want, message, extraInfo);
463 
464     want.SetParam("agentBundleName", message.agentBundleName_);
465     want.SetParam("typeCode", message.typeCode_);
466     want.SetParam("id", message.notificationId_);
467     want.SetParam("deleteReason", message.deleteReason_);
468 
469     IN_PROCESS_CALL_WITHOUT_RET(AddListCache(want, DELETE_ERROR_EVENT_CODE));
470 }
471 
ReportNotificationEvent(EventFwk::Want want,int32_t eventCode,const std::string & reason)472 void NotificationAnalyticsUtil::ReportNotificationEvent(EventFwk::Want want,
473     int32_t eventCode, const std::string& reason)
474 {
475     EventFwk::CommonEventPublishInfo publishInfo;
476     publishInfo.SetSubscriberPermissions({OHOS_PERMISSION_NOTIFICATION_AGENT_CONTROLLER});
477     EventFwk::CommonEventData commonData {want, eventCode, ""};
478     ANS_LOGD("Publish event success %{public}d, %{public}s", eventCode, reason.c_str());
479     if (!EventFwk::CommonEventManager::PublishCommonEvent(commonData, publishInfo)) {
480         ANS_LOGE("Publish event failed %{public}d, %{public}s", eventCode, reason.c_str());
481     }
482 }
483 
ReportFlowControl(const int32_t reportType)484 bool NotificationAnalyticsUtil::ReportFlowControl(const int32_t reportType)
485 {
486     std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
487     std::lock_guard<std::mutex> lock(reportFlowControlMutex_);
488     auto iter = flowControlTimestampMap_.find(reportType);
489     if (iter == flowControlTimestampMap_.end()) {
490         return false;
491     }
492     auto& list = iter->second;
493     FlowControllerOption option = GetFlowOptionByType(reportType);
494     RemoveExpired(list, now, option.time);
495     int32_t size = static_cast<int32_t>(list.size());
496     int32_t count = option.count;
497     if (size >= count) {
498         return false;
499     }
500     list.push_back(now);
501     return true;
502 }
503 
RemoveExpired(std::list<std::chrono::system_clock::time_point> & list,const std::chrono::system_clock::time_point & now,int32_t time)504 void NotificationAnalyticsUtil::RemoveExpired(std::list<std::chrono::system_clock::time_point> &list,
505     const std::chrono::system_clock::time_point &now, int32_t time)
506 {
507     auto iter = list.begin();
508     while (iter != list.end()) {
509         if (abs(now - *iter) > std::chrono::seconds(time)) {
510             iter = list.erase(iter);
511         } else {
512             break;
513         }
514     }
515 }
516 
GetFlowOptionByType(const int32_t reportType)517 FlowControllerOption NotificationAnalyticsUtil::GetFlowOptionByType(const int32_t reportType)
518 {
519     FlowControllerOption option;
520     switch (reportType) {
521         case MODIFY_ERROR_EVENT_CODE:
522             option.count = MODIFY_ERROR_EVENT_COUNT;
523             option.time = MODIFY_ERROR_EVENT_TIME;
524             break;
525         default:
526             option.count = DEFAULT_ERROR_EVENT_COUNT;
527             option.time = DEFAULT_ERROR_EVENT_TIME;
528             break;
529     }
530     return option;
531 }
532 
BuildExtraInfo(const HaMetaMessage & message)533 std::string NotificationAnalyticsUtil::BuildExtraInfo(const HaMetaMessage& message)
534 {
535     nlohmann::json reason;
536     reason["scene"] = message.sceneId_;
537     reason["branch"] = message.branchId_;
538     reason["innerErr"] = message.errorCode_;
539     reason["detail"] = message.message_;
540 
541     auto now = std::chrono::duration_cast<std::chrono::milliseconds>(
542         std::chrono::system_clock::now().time_since_epoch()).count();
543     reason["time"] = now;
544 
545     std::shared_ptr<AAFwk::WantParams> extraInfo = std::make_shared<AAFwk::WantParams>();
546 
547     reason["detail"] = "";
548     int32_t reasonFixedSize =
549         static_cast<int32_t>(reason.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace).size());
550     int32_t leftSpace = REASON_MAX_LENGTH - reasonFixedSize;
551     if (leftSpace < 0) {
552         std::string basicInfo = std::to_string(message.sceneId_) + MESSAGE_DELIMITER +
553             std::to_string(message.branchId_) + MESSAGE_DELIMITER +
554             std::to_string(message.errorCode_) + MESSAGE_DELIMITER +
555             std::to_string(now) + " Reason fixed size exceeds limit";
556         extraInfo->SetParam("reason", AAFwk::String::Box(basicInfo));
557         ANS_LOGI("%{public}s", basicInfo.c_str());
558     } else {
559         reason["detail"] = message.message_.substr(0, leftSpace);
560         extraInfo->SetParam("reason",
561             AAFwk::String::Box(reason.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace)));
562     }
563 
564     AAFwk::WantParamWrapper wWrapper(*extraInfo);
565 
566     return wWrapper.ToString();
567 }
568 
BuildExtraInfoWithReq(const HaMetaMessage & message,const sptr<NotificationRequest> & request)569 std::string NotificationAnalyticsUtil::BuildExtraInfoWithReq(const HaMetaMessage& message,
570     const sptr<NotificationRequest>& request)
571 {
572     NotificationNapi::ContentType contentType;
573     NotificationNapi::AnsEnumUtil::ContentTypeCToJS(
574         static_cast<NotificationContent::Type>(request->GetNotificationType()), contentType);
575     nlohmann::json reason;
576     if (contentType == NotificationNapi::ContentType::NOTIFICATION_CONTENT_LIVE_VIEW) {
577         auto content = request->GetContent()->GetNotificationContent();
578         auto liveViewContent = std::static_pointer_cast<NotificationLiveViewContent>(content);
579         reason["status"] = static_cast<int32_t>(liveViewContent->GetLiveViewStatus());
580         if (liveViewContent->GetExtraInfo() != nullptr) {
581             reason["et"] = liveViewContent->GetExtraInfo()->GetStringParam("event");
582         }
583     }
584 
585     reason["scene"] = message.sceneId_;
586     reason["branch"] = message.branchId_;
587     reason["innerErr"] = message.errorCode_;
588     reason["detail"] = message.message_;
589 
590     auto now = std::chrono::duration_cast<std::chrono::milliseconds>(
591         std::chrono::system_clock::now().time_since_epoch()).count();
592     reason["time"] = now;
593 
594     std::shared_ptr<AAFwk::WantParams> extraInfo = nullptr;
595     if (request->GetUnifiedGroupInfo() != nullptr &&
596         request->GetUnifiedGroupInfo()->GetExtraInfo() != nullptr) {
597         const auto originExtraInfo = request->GetUnifiedGroupInfo()->GetExtraInfo();
598         extraInfo = std::make_shared<AAFwk::WantParams>(*originExtraInfo);
599     } else {
600         extraInfo = std::make_shared<AAFwk::WantParams>();
601     }
602 
603     reason["detail"] = "";
604     int32_t reasonFixedSize =
605         static_cast<int32_t>(reason.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace).size());
606     int32_t leftSpace = REASON_MAX_LENGTH - reasonFixedSize;
607     if (leftSpace < 0) {
608         std::string basicInfo = std::to_string(message.sceneId_) + MESSAGE_DELIMITER +
609             std::to_string(message.branchId_) + MESSAGE_DELIMITER +
610             std::to_string(message.errorCode_) + MESSAGE_DELIMITER +
611             std::to_string(now) + " Reason fixed size exceeds limit";
612         extraInfo->SetParam("reason", AAFwk::String::Box(basicInfo));
613         ANS_LOGI("%{public}s", basicInfo.c_str());
614     } else {
615         reason["detail"] = message.message_.substr(0, leftSpace);
616         extraInfo->SetParam("reason",
617             AAFwk::String::Box(reason.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace)));
618     }
619 
620     AAFwk::WantParamWrapper wWrapper(*extraInfo);
621 
622     return wWrapper.ToString();
623 }
624 
SetCommonWant(EventFwk::Want & want,const HaMetaMessage & message,std::string & extraInfo)625 void NotificationAnalyticsUtil::SetCommonWant(EventFwk::Want& want, const HaMetaMessage& message,
626     std::string& extraInfo)
627 {
628     want.SetBundle(message.bundleName_);
629     want.SetParam("extraInfo", extraInfo);
630     want.SetAction(NOTIFICATION_EVENT_PUSH_AGENT);
631 }
632 
AddListCache(EventFwk::Want & want,int32_t eventCode)633 void NotificationAnalyticsUtil::AddListCache(EventFwk::Want& want, int32_t eventCode)
634 {
635     std::lock_guard<std::mutex> lock(reportCacheMutex_);
636     int32_t size = static_cast<int32_t>(reportCacheList.size());
637     if (size >= REPORT_CACHE_MAX_SIZE) {
638         ANS_LOGW("list size is max");
639         return;
640     }
641 
642     if (reportTimerId == 0) {
643         sptr<MiscServices::TimeServiceClient> timer = MiscServices::TimeServiceClient::GetInstance();
644         if (timer == nullptr) {
645             ANS_LOGE("Failed to start timer due to get TimeServiceClient is null.");
646             return;
647         }
648         reportTimerId = timer->CreateTimer(reportTimeInfo);
649     }
650 
651     ReportCache reportCache;
652     reportCache.want = want;
653     reportCache.eventCode = eventCode;
654     reportCacheList.push_back(reportCache);
655     if (!g_reportFlag) {
656         ExecuteCacheList();
657     }
658 }
659 
AddSuccessListCache(EventFwk::Want & want,int32_t eventCode)660 void NotificationAnalyticsUtil::AddSuccessListCache(EventFwk::Want& want, int32_t eventCode)
661 {
662     std::lock_guard<std::mutex> lock(reportSuccessCacheMutex_);
663     int32_t size = static_cast<int32_t>(successReportCacheList.size());
664     if (size >= SUCCESS_REPORT_CACHE_MAX_SIZE) {
665         ANS_LOGW("Success list size is max.");
666         return;
667     }
668 
669     if (reportSuccessTimerId == 0) {
670         sptr<MiscServices::TimeServiceClient> successTimer = MiscServices::TimeServiceClient::GetInstance();
671         if (successTimer == nullptr) {
672             ANS_LOGE("Failed to start timer due to get TimeServiceClient is null.");
673             return;
674         }
675         reportSuccessTimerId = successTimer->CreateTimer(reportSuccessTimeInfo);
676     }
677 
678     ReportCache reportCache;
679     reportCache.want = want;
680     reportCache.eventCode = eventCode;
681     successReportCacheList.push_back(reportCache);
682     if (!g_successReportFlag) {
683         ExecuteSuccessCacheList();
684     }
685 }
686 
Aggregate()687 ReportCache NotificationAnalyticsUtil::Aggregate()
688 {
689     ANS_LOGI("Success list aggregated.");
690     EventFwk::Want want;
691     auto reportCachetemp = successReportCacheList.front();
692 
693     std::shared_ptr<AAFwk::WantParams> extraInfo = std::make_shared<AAFwk::WantParams>();
694     AAFwk::WantParamWrapper wWrapper(*extraInfo);
695     std::string extralInfoStr = wWrapper.ToString();
696     want.SetParam("extraInfo", extralInfoStr);
697     want.SetBundle(reportCachetemp.want.GetBundle());
698     std::string agentBundleName = reportCachetemp.want.GetStringParam("agentBundleName");
699     if (!agentBundleName.empty()) {
700         want.SetParam("agentBundleName", agentBundleName);
701     }
702     want.SetAction(NOTIFICATION_EVENT_PUSH_AGENT);
703 
704     std::string ansData = reportCachetemp.want.GetStringParam("ansData");
705     successReportCacheList.pop_front();
706     int32_t aggreCount = MAX_NUMBER_EVERY_REPORT - 1;
707     while (aggreCount > 0) {
708         if (successReportCacheList.empty()) {
709             break;
710         }
711         auto reportCache = successReportCacheList.front();
712 
713         ansData += "|" + reportCache.want.GetStringParam("ansData");
714         successReportCacheList.pop_front();
715         aggreCount--;
716     }
717     want.SetParam("ansData", ansData);
718     ReportCache reportInfo;
719     reportInfo.want = want;
720     reportInfo.eventCode = ANS_CUSTOMIZE_CODE ;
721     return reportInfo;
722 }
723 
ExecuteSuccessCacheList()724 void NotificationAnalyticsUtil::ExecuteSuccessCacheList()
725 {
726     if (successReportCacheList.empty()) {
727         g_successReportFlag = false;
728         ANS_LOGI("successReportCacheList is end");
729         return;
730     }
731 
732     auto reportCount = MAX_REPORT_COUNT;
733     while (reportCount > 0) {
734         if (successReportCacheList.empty()) {
735             break;
736         }
737         auto reportCache = Aggregate();
738         ReportCommonEvent(reportCache);
739         reportCount--;
740     }
741     auto triggerFunc = [] {
742         std::lock_guard<std::mutex> lock(reportSuccessCacheMutex_);
743         NotificationAnalyticsUtil::ExecuteSuccessCacheList();
744     };
745     reportSuccessTimeInfo->SetCallbackInfo(triggerFunc);
746     sptr<MiscServices::TimeServiceClient> successTimer = MiscServices::TimeServiceClient::GetInstance();
747     if (successTimer == nullptr || reportSuccessTimerId == 0) {
748         g_successReportFlag = false;
749         ANS_LOGE("Failed to start timer due to get TimeServiceClient is null.");
750         return;
751     }
752     successTimer->StartTimer(reportSuccessTimerId, NotificationAnalyticsUtil::GetCurrentTime() +
753         SUCCESS_REPORT_CACHE_INTERVAL_TIME * NotificationConstant::SECOND_TO_MS);
754     g_successReportFlag = true;
755 }
756 
757 
ExecuteCacheList()758 void NotificationAnalyticsUtil::ExecuteCacheList()
759 {
760     if (reportCacheList.empty()) {
761         g_reportFlag = false;
762         ANS_LOGI("reportCacheList is end");
763         return;
764     }
765     auto reportCache = reportCacheList.front();
766     ReportCommonEvent(reportCache);
767     auto triggerFunc = [] {
768         std::lock_guard<std::mutex> lock(reportCacheMutex_);
769         NotificationAnalyticsUtil::ExecuteCacheList();
770     };
771     reportCacheList.pop_front();
772     reportTimeInfo->SetCallbackInfo(triggerFunc);
773     sptr<MiscServices::TimeServiceClient> timer = MiscServices::TimeServiceClient::GetInstance();
774     if (timer == nullptr || reportTimerId == 0) {
775         g_reportFlag = false;
776         ANS_LOGE("Failed to start timer due to get TimeServiceClient is null.");
777         return;
778     }
779     timer->StartTimer(reportTimerId, NotificationAnalyticsUtil::GetCurrentTime() +
780         REPORT_CACHE_INTERVAL_TIME * NotificationConstant::SECOND_TO_MS);
781     g_reportFlag = true;
782 }
783 
ReportCommonEvent(const ReportCache & reportCache)784 void NotificationAnalyticsUtil::ReportCommonEvent(const ReportCache& reportCache)
785 {
786     EventFwk::CommonEventPublishInfo publishInfo;
787     publishInfo.SetSubscriberPermissions({OHOS_PERMISSION_NOTIFICATION_CONTROLLER});
788     EventFwk::CommonEventData commonData {reportCache.want, reportCache.eventCode, ""};
789     if (!EventFwk::CommonEventManager::PublishCommonEvent(commonData, publishInfo)) {
790         ANS_LOGE("Publish event failed %{public}d", reportCache.eventCode);
791     }
792 }
793 
GetCurrentTime()794 int64_t NotificationAnalyticsUtil::GetCurrentTime()
795 {
796     auto now = std::chrono::system_clock::now();
797     auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
798     return duration.count();
799 }
800 
ReportOperationsDotEvent(const HaMetaMessage & message)801 void NotificationAnalyticsUtil::ReportOperationsDotEvent(const HaMetaMessage& message)
802 {
803     if (!ReportFlowControl(ANS_CUSTOMIZE_CODE)) {
804         ANS_LOGI("Publish event failed, reason:%{public}s", message.Build().c_str());
805         return;
806     }
807     EventFwk::Want want;
808     std::string extraInfo = NotificationAnalyticsUtil::BuildExtraInfo(message);
809     NotificationAnalyticsUtil::SetCommonWant(want, message, extraInfo);
810     if (!NotificationAnalyticsUtil::DetermineWhetherToSend(message.slotType_)) {
811         return;
812     }
813     std::string ansData = NotificationAnalyticsUtil::BuildAnsData(message);
814     want.SetParam("ansData", ansData);
815     IN_PROCESS_CALL_WITHOUT_RET(AddListCache(want, ANS_CUSTOMIZE_CODE));
816 }
817 
ReportPublishFailedEvent(const HaMetaMessage & message)818 void NotificationAnalyticsUtil::ReportPublishFailedEvent(const HaMetaMessage& message)
819 {
820     if (!ReportFlowControl(PUBLISH_ERROR_EVENT_CODE)) {
821         ANS_LOGI("Publish event failed, reason:%{public}s", message.Build().c_str());
822         return;
823     }
824     EventFwk::Want want;
825     std::string extraInfo = NotificationAnalyticsUtil::BuildExtraInfo(message);
826     NotificationAnalyticsUtil::SetCommonWant(want, message, extraInfo);
827 
828     want.SetParam("typeCode", message.typeCode_);
829 
830     IN_PROCESS_CALL_WITHOUT_RET(AddListCache(want, PUBLISH_ERROR_EVENT_CODE));
831 }
832 
DetermineWhetherToSend(uint32_t slotType)833 bool NotificationAnalyticsUtil::DetermineWhetherToSend(uint32_t slotType)
834 {
835     if (HaMetaMessage::keyNode_ != 0) {
836         return true;
837     }
838     if (slotType == NotificationConstant::SlotType::LIVE_VIEW) {
839         if ((NotificationAnalyticsUtil::GetCurrentTime() - HaMetaMessage::liveViewTime_) >= MAX_TIME) {
840             return true;
841         } else if (HaMetaMessage::syncLiveViewWatch_ + HaMetaMessage::syncLiveViewHeadSet_ +
842                        HaMetaMessage::syncLiveViewWatchHeadSet_ + HaMetaMessage::liveViewDelByWatch_ +
843                        HaMetaMessage::clickByWatch_ >=
844                    NOTIFICATION_MAX_DATA) {
845             return true;
846         }
847     } else {
848         if ((NotificationAnalyticsUtil::GetCurrentTime() - HaMetaMessage::time_) >= MAX_TIME) {
849             return true;
850         } else if (HaMetaMessage::syncWatch_ + HaMetaMessage::syncHeadSet_ + HaMetaMessage::syncWatchHeadSet_ +
851                        HaMetaMessage::delByWatch_ + HaMetaMessage::replyByWatch_ >=
852                    NOTIFICATION_MAX_DATA) {
853             return true;
854         }
855     }
856     return false;
857 }
858 
BuildAnsData(const HaMetaMessage & message)859 std::string NotificationAnalyticsUtil::BuildAnsData(const HaMetaMessage& message)
860 {
861     nlohmann::json ansData;
862     ansData["subCode"] = std::to_string(SUB_CODE);
863     nlohmann::json data;
864     data["slotType"] = std::to_string(message.slotType_);
865     if (message.slotType_ == NotificationConstant::SlotType::LIVE_VIEW) {
866         data["syncWatch"] = std::to_string(HaMetaMessage::syncLiveViewWatch_);
867         data["syncHeadSet"] = std::to_string(HaMetaMessage::syncLiveViewHeadSet_);
868         data["syncWatchHeadSet"] = std::to_string(HaMetaMessage::syncLiveViewWatchHeadSet_);
869         data["keyNode"] = std::to_string(HaMetaMessage::keyNode_);
870         data["delByWatch"] = std::to_string(HaMetaMessage::liveViewDelByWatch_);
871         data["clickByWatch"] = std::to_string(HaMetaMessage::clickByWatch_);
872         HaMetaMessage::syncLiveViewWatch_ = 0;
873         HaMetaMessage::syncLiveViewHeadSet_ = 0;
874         HaMetaMessage::syncLiveViewWatchHeadSet_ = 0;
875         HaMetaMessage::keyNode_ = 0;
876         HaMetaMessage::liveViewDelByWatch_ = 0;
877         HaMetaMessage::clickByWatch_ = 0;
878         HaMetaMessage::liveViewTime_ = NotificationAnalyticsUtil::GetCurrentTime();
879     } else {
880         data["syncWatch"] = std::to_string(HaMetaMessage::syncWatch_);
881         data["syncHeadSet"] = std::to_string(HaMetaMessage::syncHeadSet_);
882         data["syncWatchHeadSet"] = std::to_string(HaMetaMessage::syncWatchHeadSet_);
883         data["delByWatch"] = std::to_string(HaMetaMessage::delByWatch_);
884         data["replyByWatch"] = std::to_string(HaMetaMessage::replyByWatch_);
885         HaMetaMessage::syncWatch_ = 0;
886         HaMetaMessage::syncHeadSet_ = 0;
887         HaMetaMessage::syncWatchHeadSet_ = 0;
888         HaMetaMessage::delByWatch_ = 0;
889         HaMetaMessage::replyByWatch_ = 0;
890         HaMetaMessage::time_ = NotificationAnalyticsUtil::GetCurrentTime();
891     }
892     ansData["data"] = data.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace);
893     return ansData.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace);
894 }
895 
ReportSkipFailedEvent(const HaMetaMessage & message)896 void NotificationAnalyticsUtil::ReportSkipFailedEvent(const HaMetaMessage& message)
897 {
898     if (!ReportFlowControl(MODIFY_ERROR_EVENT_CODE)) {
899         ANS_LOGI("Publish event failed, reason:%{public}s", message.Build().c_str());
900         return;
901     }
902     EventFwk::Want want;
903     std::string extraInfo = NotificationAnalyticsUtil::BuildExtraInfo(message);
904     NotificationAnalyticsUtil::SetCommonWant(want, message, extraInfo);
905 
906     IN_PROCESS_CALL_WITHOUT_RET(AddListCache(want, MODIFY_ERROR_EVENT_CODE));
907 }
908 } // namespace Notification
909 } // namespace OHOS
910