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