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
53 constexpr const int32_t SOUND_FLAG = 1 << 10;
54 constexpr const int32_t LOCKSCREEN_FLAG = 1 << 11;
55 constexpr const int32_t BANNER_FLAG = 1 << 12;
56 constexpr const int32_t VIBRATION_FLAG = 1 << 13;
57
58 const static std::string NOTIFICATION_EVENT_PUSH_AGENT = "notification.event.PUSH_AGENT";
59 static std::mutex reportFlowControlMutex_;
60 static std::map<int32_t, std::list<std::chrono::system_clock::time_point>> flowControlTimestampMap_ = {
61 {MODIFY_ERROR_EVENT_CODE, {}},
62 {PUBLISH_ERROR_EVENT_CODE, {}},
63 {DELETE_ERROR_EVENT_CODE, {}},
64 };
65
66 static std::mutex reportCacheMutex_;
67 static uint64_t reportTimerId = 0;
68 static std::list<ReportCache> reportCacheList;
69 static bool g_reportFlag = false;
70 static std::shared_ptr<ReportTimerInfo> reportTimeInfo = std::make_shared<ReportTimerInfo>();
71
72 static std::mutex reportSuccessCacheMutex_;
73 static uint64_t reportSuccessTimerId = 0;
74 static std::list<ReportCache> successReportCacheList;
75 static bool g_successReportFlag = false;
76 static std::shared_ptr<ReportTimerInfo> reportSuccessTimeInfo = std::make_shared<ReportTimerInfo>();
77
HaMetaMessage(uint32_t sceneId,uint32_t branchId)78 HaMetaMessage::HaMetaMessage(uint32_t sceneId, uint32_t branchId)
79 : sceneId_(sceneId), branchId_(branchId)
80 {
81 }
82
NeedReport() const83 bool HaMetaMessage::NeedReport() const
84 {
85 if (errorCode_ == ERR_OK && checkfailed_) {
86 return false;
87 }
88 return true;
89 }
90
SceneId(uint32_t sceneId)91 HaMetaMessage& HaMetaMessage::SceneId(uint32_t sceneId)
92 {
93 sceneId_ = sceneId;
94 return *this;
95 }
96
BranchId(uint32_t branchId)97 HaMetaMessage& HaMetaMessage::BranchId(uint32_t branchId)
98 {
99 branchId_ = branchId;
100 return *this;
101 }
102
ErrorCode(uint32_t errorCode)103 HaMetaMessage& HaMetaMessage::ErrorCode(uint32_t errorCode)
104 {
105 errorCode_ = errorCode;
106 return *this;
107 }
108
Message(const std::string & message,bool print)109 HaMetaMessage& HaMetaMessage::Message(const std::string& message, bool print)
110 {
111 message_ = message;
112 if (print) {
113 ANSR_LOGE("%{public}s, %{public}d", message.c_str(), errorCode_);
114 }
115 return *this;
116 }
117
Append(const std::string & message)118 HaMetaMessage& HaMetaMessage::Append(const std::string& message)
119 {
120 message_+=message;
121 return *this;
122 }
Checkfailed(bool checkfailed)123 HaMetaMessage& HaMetaMessage::Checkfailed(bool checkfailed)
124 {
125 checkfailed_ = checkfailed;
126 return *this;
127 }
128
BundleName(const std::string & bundleName)129 HaMetaMessage& HaMetaMessage::BundleName(const std::string& bundleName)
130 {
131 bundleName_ = bundleName;
132 return *this;
133 }
134
AgentBundleName(const std::string & agentBundleName)135 HaMetaMessage& HaMetaMessage::AgentBundleName(const std::string& agentBundleName)
136 {
137 agentBundleName_ = agentBundleName;
138 return *this;
139 }
140
TypeCode(int32_t typeCode)141 HaMetaMessage& HaMetaMessage::TypeCode(int32_t typeCode)
142 {
143 typeCode_ = typeCode;
144 return *this;
145 }
146
NotificationId(int32_t notificationId)147 HaMetaMessage& HaMetaMessage::NotificationId(int32_t notificationId)
148 {
149 notificationId_ = notificationId;
150 return *this;
151 }
152
GetMessage() const153 std::string HaMetaMessage::GetMessage() const
154 {
155 return message_;
156 }
157
SlotType(int32_t slotType)158 HaMetaMessage& HaMetaMessage::SlotType(int32_t slotType)
159 {
160 slotType_ = static_cast<uint32_t>(slotType);
161 return *this;
162 }
163
Build() const164 std::string HaMetaMessage::Build() const
165 {
166 return std::to_string(sceneId_) + MESSAGE_DELIMITER +
167 std::to_string(branchId_) + MESSAGE_DELIMITER + std::to_string(errorCode_) +
168 MESSAGE_DELIMITER + message_ + MESSAGE_DELIMITER;
169 }
170
ReportPublishFailedEvent(const sptr<NotificationRequest> & request,const HaMetaMessage & message)171 void NotificationAnalyticsUtil::ReportPublishFailedEvent(const sptr<NotificationRequest>& request,
172 const HaMetaMessage& message)
173 {
174 CommonNotificationEvent(request, PUBLISH_ERROR_EVENT_CODE, message);
175 }
176
ReportDeleteFailedEvent(const sptr<NotificationRequest> & request,HaMetaMessage & message)177 void NotificationAnalyticsUtil::ReportDeleteFailedEvent(const sptr<NotificationRequest>& request,
178 HaMetaMessage& message)
179 {
180 if (request == nullptr || !message.NeedReport()) {
181 ANS_LOGE("request is null %{public}d", message.NeedReport());
182 return;
183 }
184 std::shared_ptr<NotificationBundleOption> agentBundleNameOption = request->GetAgentBundle();
185 if (agentBundleNameOption != nullptr) {
186 std::string agentBundleName = agentBundleNameOption->GetBundleName();
187 if (!agentBundleName.empty()) {
188 message = message.AgentBundleName(agentBundleName);
189 }
190 }
191 }
192
CommonNotificationEvent(const sptr<NotificationRequest> & request,int32_t eventCode,const HaMetaMessage & message)193 void NotificationAnalyticsUtil::CommonNotificationEvent(const sptr<NotificationRequest>& request,
194 int32_t eventCode, const HaMetaMessage& message)
195 {
196 if (request == nullptr) {
197 return;
198 }
199
200 if (!ReportFlowControl(eventCode)) {
201 ANS_LOGI("Publish event failed, eventCode:%{public}d, reason:%{public}s",
202 eventCode, message.Build().c_str());
203 return;
204 }
205 EventFwk::Want want;
206 std::string extraInfo = NotificationAnalyticsUtil::BuildExtraInfoWithReq(message, request);
207 NotificationAnalyticsUtil::SetCommonWant(want, message, extraInfo);
208
209 want.SetParam("typeCode", message.typeCode_);
210 IN_PROCESS_CALL_WITHOUT_RET(ReportNotificationEvent(
211 request, want, eventCode, message.Build()));
212 }
213
ReportNotificationEvent(const sptr<NotificationRequest> & request,EventFwk::Want want,int32_t eventCode,const std::string & reason)214 void NotificationAnalyticsUtil::ReportNotificationEvent(const sptr<NotificationRequest>& request,
215 EventFwk::Want want, int32_t eventCode, const std::string& reason)
216 {
217 NotificationNapi::SlotType slotType;
218 NotificationNapi::AnsEnumUtil::SlotTypeCToJS(
219 static_cast<NotificationConstant::SlotType>(request->GetSlotType()), slotType);
220 NotificationNapi::ContentType contentType;
221 NotificationNapi::AnsEnumUtil::ContentTypeCToJS(
222 static_cast<NotificationContent::Type>(request->GetNotificationType()), contentType);
223
224 want.SetParam("id", request->GetNotificationId());
225 want.SetParam("uid", request->GetOwnerUid());
226 want.SetParam("slotType", static_cast<int32_t>(slotType));
227 want.SetParam("contentType", std::to_string(static_cast<int32_t>(contentType)));
228
229 if (!request->GetCreatorBundleName().empty()) {
230 want.SetParam("agentBundleName", request->GetCreatorBundleName());
231 }
232 if (!request->GetOwnerBundleName().empty()) {
233 want.SetBundle(request->GetOwnerBundleName());
234 }
235 IN_PROCESS_CALL_WITHOUT_RET(AddListCache(want, eventCode));
236 }
237
ReportModifyEvent(const HaMetaMessage & message)238 void NotificationAnalyticsUtil::ReportModifyEvent(const HaMetaMessage& message)
239 {
240 if (!ReportFlowControl(MODIFY_ERROR_EVENT_CODE)) {
241 ANS_LOGI("Publish event failed, reason:%{public}s", message.Build().c_str());
242 return;
243 }
244 EventFwk::Want want;
245 std::string extraInfo = NotificationAnalyticsUtil::BuildExtraInfo(message);
246 NotificationAnalyticsUtil::SetCommonWant(want, message, extraInfo);
247
248 std::string bundle;
249 int32_t callingUid = IPCSkeleton::GetCallingUid();
250 std::shared_ptr<BundleManagerHelper> bundleManager = BundleManagerHelper::GetInstance();
251 if (bundleManager != nullptr) {
252 bundle = bundleManager->GetBundleNameByUid(callingUid);
253 }
254 want.SetBundle(bundle + "_" + std::to_string(callingUid));
255 want.SetParam("slotType", static_cast<int32_t>(message.slotType_));
256 IN_PROCESS_CALL_WITHOUT_RET(AddListCache(want, MODIFY_ERROR_EVENT_CODE));
257 }
258
ReportDeleteFailedEvent(const HaMetaMessage & message)259 void NotificationAnalyticsUtil::ReportDeleteFailedEvent(const HaMetaMessage& message)
260 {
261 if (!ReportFlowControl(DELETE_ERROR_EVENT_CODE)) {
262 ANS_LOGI("Publish event failed, reason:%{public}s", message.Build().c_str());
263 return;
264 }
265 EventFwk::Want want;
266 std::string extraInfo = NotificationAnalyticsUtil::BuildExtraInfo(message);
267 NotificationAnalyticsUtil::SetCommonWant(want, message, extraInfo);
268
269 want.SetParam("agentBundleName", message.agentBundleName_);
270 want.SetParam("typeCode", message.typeCode_);
271 want.SetParam("id", message.notificationId_);
272
273 IN_PROCESS_CALL_WITHOUT_RET(AddListCache(want, DELETE_ERROR_EVENT_CODE));
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("Report success, 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 }
ReportNotificationEvent(EventFwk::Want want,int32_t eventCode,const std::string & reason)386 void NotificationAnalyticsUtil::ReportNotificationEvent(EventFwk::Want want,
387 int32_t eventCode, const std::string& reason)
388 {
389 EventFwk::CommonEventPublishInfo publishInfo;
390 publishInfo.SetSubscriberPermissions({OHOS_PERMISSION_NOTIFICATION_AGENT_CONTROLLER});
391 EventFwk::CommonEventData commonData {want, eventCode, ""};
392 ANS_LOGD("Publish event success %{public}d, %{public}s", eventCode, reason.c_str());
393 if (!EventFwk::CommonEventManager::PublishCommonEvent(commonData, publishInfo)) {
394 ANS_LOGE("Publish event failed %{public}d, %{public}s", eventCode, reason.c_str());
395 }
396 }
397
ReportFlowControl(const int32_t reportType)398 bool NotificationAnalyticsUtil::ReportFlowControl(const int32_t reportType)
399 {
400 std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
401 std::lock_guard<std::mutex> lock(reportFlowControlMutex_);
402 auto iter = flowControlTimestampMap_.find(reportType);
403 if (iter == flowControlTimestampMap_.end()) {
404 return false;
405 }
406 auto& list = iter->second;
407 FlowControllerOption option = GetFlowOptionByType(reportType);
408 RemoveExpired(list, now, option.time);
409 int32_t size = list.size();
410 int32_t count = option.count;
411 if (size >= count) {
412 return false;
413 }
414 list.push_back(now);
415 return true;
416 }
417
RemoveExpired(std::list<std::chrono::system_clock::time_point> & list,const std::chrono::system_clock::time_point & now,int32_t time)418 void NotificationAnalyticsUtil::RemoveExpired(std::list<std::chrono::system_clock::time_point> &list,
419 const std::chrono::system_clock::time_point &now, int32_t time)
420 {
421 auto iter = list.begin();
422 while (iter != list.end()) {
423 if (abs(now - *iter) > std::chrono::seconds(time)) {
424 iter = list.erase(iter);
425 } else {
426 break;
427 }
428 }
429 }
430
GetFlowOptionByType(const int32_t reportType)431 FlowControllerOption NotificationAnalyticsUtil::GetFlowOptionByType(const int32_t reportType)
432 {
433 FlowControllerOption option;
434 switch (reportType) {
435 case MODIFY_ERROR_EVENT_CODE:
436 option.count = MODIFY_ERROR_EVENT_COUNT;
437 option.time = MODIFY_ERROR_EVENT_TIME;
438 break;
439 default:
440 option.count = DEFAULT_ERROR_EVENT_COUNT;
441 option.time = DEFAULT_ERROR_EVENT_TIME;
442 break;
443 }
444 return option;
445 }
446
BuildExtraInfo(const HaMetaMessage & message)447 std::string NotificationAnalyticsUtil::BuildExtraInfo(const HaMetaMessage& message)
448 {
449 nlohmann::json reason;
450 reason["scene"] = message.sceneId_;
451 reason["branch"] = message.branchId_;
452 reason["innerErr"] = message.errorCode_;
453 reason["detail"] = message.message_;
454
455 auto now = std::chrono::duration_cast<std::chrono::milliseconds>(
456 std::chrono::system_clock::now().time_since_epoch()).count();
457 reason["time"] = now;
458
459 std::shared_ptr<AAFwk::WantParams> extraInfo = std::make_shared<AAFwk::WantParams>();
460
461 reason["detail"] = "";
462 int32_t reasonFixedSize =
463 static_cast<int32_t>(reason.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace).size());
464 int32_t leftSpace = REASON_MAX_LENGTH - reasonFixedSize;
465 if (leftSpace < 0) {
466 std::string basicInfo = std::to_string(message.sceneId_) + MESSAGE_DELIMITER +
467 std::to_string(message.branchId_) + MESSAGE_DELIMITER +
468 std::to_string(message.errorCode_) + MESSAGE_DELIMITER +
469 std::to_string(now) + " Reason fixed size exceeds limit";
470 extraInfo->SetParam("reason", AAFwk::String::Box(basicInfo));
471 ANS_LOGI("%{public}s", basicInfo.c_str());
472 } else {
473 reason["detail"] = message.message_.substr(0, leftSpace);
474 extraInfo->SetParam("reason",
475 AAFwk::String::Box(reason.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace)));
476 }
477
478 AAFwk::WantParamWrapper wWrapper(*extraInfo);
479
480 return wWrapper.ToString();
481 }
482
BuildExtraInfoWithReq(const HaMetaMessage & message,const sptr<NotificationRequest> & request)483 std::string NotificationAnalyticsUtil::BuildExtraInfoWithReq(const HaMetaMessage& message,
484 const sptr<NotificationRequest>& request)
485 {
486 NotificationNapi::ContentType contentType;
487 NotificationNapi::AnsEnumUtil::ContentTypeCToJS(
488 static_cast<NotificationContent::Type>(request->GetNotificationType()), contentType);
489 nlohmann::json reason;
490 if (contentType == NotificationNapi::ContentType::NOTIFICATION_CONTENT_LIVE_VIEW) {
491 auto content = request->GetContent()->GetNotificationContent();
492 auto liveViewContent = std::static_pointer_cast<NotificationLiveViewContent>(content);
493 reason["status"] = static_cast<int32_t>(liveViewContent->GetLiveViewStatus());
494 }
495
496 reason["scene"] = message.sceneId_;
497 reason["branch"] = message.branchId_;
498 reason["innerErr"] = message.errorCode_;
499 reason["detail"] = message.message_;
500
501 auto now = std::chrono::duration_cast<std::chrono::milliseconds>(
502 std::chrono::system_clock::now().time_since_epoch()).count();
503 reason["time"] = now;
504
505 std::shared_ptr<AAFwk::WantParams> extraInfo = nullptr;
506 if (request->GetUnifiedGroupInfo() != nullptr &&
507 request->GetUnifiedGroupInfo()->GetExtraInfo() != nullptr) {
508 extraInfo = request->GetUnifiedGroupInfo()->GetExtraInfo();
509 } else {
510 extraInfo = std::make_shared<AAFwk::WantParams>();
511 }
512
513 reason["detail"] = "";
514 int32_t reasonFixedSize =
515 static_cast<int32_t>(reason.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace).size());
516 int32_t leftSpace = REASON_MAX_LENGTH - reasonFixedSize;
517 if (leftSpace < 0) {
518 std::string basicInfo = std::to_string(message.sceneId_) + MESSAGE_DELIMITER +
519 std::to_string(message.branchId_) + MESSAGE_DELIMITER +
520 std::to_string(message.errorCode_) + MESSAGE_DELIMITER +
521 std::to_string(now) + " Reason fixed size exceeds limit";
522 extraInfo->SetParam("reason", AAFwk::String::Box(basicInfo));
523 ANS_LOGI("%{public}s", basicInfo.c_str());
524 } else {
525 reason["detail"] = message.message_.substr(0, leftSpace);
526 extraInfo->SetParam("reason",
527 AAFwk::String::Box(reason.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace)));
528 }
529
530 AAFwk::WantParamWrapper wWrapper(*extraInfo);
531
532 return wWrapper.ToString();
533 }
534
SetCommonWant(EventFwk::Want & want,const HaMetaMessage & message,std::string & extraInfo)535 void NotificationAnalyticsUtil::SetCommonWant(EventFwk::Want& want, const HaMetaMessage& message,
536 std::string& extraInfo)
537 {
538 want.SetBundle(message.bundleName_);
539 want.SetParam("extraInfo", extraInfo);
540 want.SetAction(NOTIFICATION_EVENT_PUSH_AGENT);
541 }
542
AddListCache(EventFwk::Want & want,int32_t eventCode)543 void NotificationAnalyticsUtil::AddListCache(EventFwk::Want& want, int32_t eventCode)
544 {
545 std::lock_guard<std::mutex> lock(reportCacheMutex_);
546 int32_t size = static_cast<int32_t>(reportCacheList.size());
547 if (size >= REPORT_CACHE_MAX_SIZE) {
548 ANS_LOGW("list size is max");
549 return;
550 }
551
552 if (reportTimerId == 0) {
553 sptr<MiscServices::TimeServiceClient> timer = MiscServices::TimeServiceClient::GetInstance();
554 if (timer == nullptr) {
555 ANS_LOGE("Failed to start timer due to get TimeServiceClient is null.");
556 return;
557 }
558 reportTimerId = timer->CreateTimer(reportTimeInfo);
559 }
560
561 ReportCache reportCache;
562 reportCache.want = want;
563 reportCache.eventCode = eventCode;
564 reportCacheList.push_back(reportCache);
565 if (!g_reportFlag) {
566 ExecuteCacheList();
567 }
568 }
569
AddSuccessListCache(EventFwk::Want & want,int32_t eventCode)570 void NotificationAnalyticsUtil::AddSuccessListCache(EventFwk::Want& want, int32_t eventCode)
571 {
572 std::lock_guard<std::mutex> lock(reportSuccessCacheMutex_);
573 int32_t size = static_cast<int32_t>(successReportCacheList.size());
574 if (size >= SUCCESS_REPORT_CACHE_MAX_SIZE) {
575 ANS_LOGW("Success list size is max.");
576 return;
577 }
578
579 if (reportSuccessTimerId == 0) {
580 sptr<MiscServices::TimeServiceClient> successTimer = MiscServices::TimeServiceClient::GetInstance();
581 if (successTimer == nullptr) {
582 ANS_LOGE("Failed to start timer due to get TimeServiceClient is null.");
583 return;
584 }
585 reportSuccessTimerId = successTimer->CreateTimer(reportSuccessTimeInfo);
586 }
587
588 ReportCache reportCache;
589 reportCache.want = want;
590 reportCache.eventCode = eventCode;
591 successReportCacheList.push_back(reportCache);
592 if (!g_successReportFlag) {
593 ExecuteSuccessCacheList();
594 }
595 }
596
Aggregate()597 ReportCache NotificationAnalyticsUtil::Aggregate()
598 {
599 ANS_LOGI("Success list aggregated.");
600 EventFwk::Want want;
601 auto reportCachetemp = successReportCacheList.front();
602
603 std::shared_ptr<AAFwk::WantParams> extraInfo = std::make_shared<AAFwk::WantParams>();
604 AAFwk::WantParamWrapper wWrapper(*extraInfo);
605 std::string extralInfoStr = wWrapper.ToString();
606 want.SetParam("extraInfo", extralInfoStr);
607 want.SetBundle(reportCachetemp.want.GetBundle());
608 std::string agentBundleName = reportCachetemp.want.GetStringParam("agentBundleName");
609 if (!agentBundleName.empty()) {
610 want.SetParam("agentBundleName", agentBundleName);
611 }
612 want.SetAction(NOTIFICATION_EVENT_PUSH_AGENT);
613
614 std::string ansData = reportCachetemp.want.GetStringParam("ansData");
615 successReportCacheList.pop_front();
616 int32_t aggreCount = MAX_NUMBER_EVERY_REPORT;
617 while (aggreCount > 0) {
618 if (successReportCacheList.empty()) {
619 break;
620 }
621 auto reportCache = successReportCacheList.front();
622
623 ansData += "|" + reportCache.want.GetStringParam("ansData");
624 successReportCacheList.pop_front();
625 aggreCount--;
626 }
627 want.SetParam("ansData", ansData);
628 ReportCache reportInfo;
629 reportInfo.want = want;
630 reportInfo.eventCode = ANS_CUSTOMIZE_CODE ;
631 return reportInfo;
632 }
633
ExecuteSuccessCacheList()634 void NotificationAnalyticsUtil::ExecuteSuccessCacheList()
635 {
636 if (successReportCacheList.empty()) {
637 g_successReportFlag = false;
638 ANS_LOGI("successReportCacheList is end");
639 return;
640 }
641
642 auto reportCount = MAX_REPORT_COUNT;
643 while (reportCount > 0) {
644 if (successReportCacheList.empty()) {
645 break;
646 }
647 auto reportCache = Aggregate();
648 ReportCommonEvent(reportCache);
649 reportCount--;
650 }
651 auto triggerFunc = [] {
652 std::lock_guard<std::mutex> lock(reportSuccessCacheMutex_);
653 NotificationAnalyticsUtil::ExecuteSuccessCacheList();
654 };
655 reportSuccessTimeInfo->SetCallbackInfo(triggerFunc);
656 sptr<MiscServices::TimeServiceClient> successTimer = MiscServices::TimeServiceClient::GetInstance();
657 if (successTimer == nullptr || reportSuccessTimerId == 0) {
658 g_successReportFlag = false;
659 ANS_LOGE("Failed to start timer due to get TimeServiceClient is null.");
660 return;
661 }
662 successTimer->StartTimer(reportSuccessTimerId, NotificationAnalyticsUtil::GetCurrentTime() +
663 SUCCESS_REPORT_CACHE_INTERVAL_TIME * NotificationConstant::SECOND_TO_MS);
664 g_successReportFlag = true;
665 }
666
667
ExecuteCacheList()668 void NotificationAnalyticsUtil::ExecuteCacheList()
669 {
670 if (reportCacheList.empty()) {
671 g_reportFlag = false;
672 ANS_LOGI("reportCacheList is end");
673 return;
674 }
675 auto reportCache = reportCacheList.front();
676 ReportCommonEvent(reportCache);
677 auto triggerFunc = [] {
678 std::lock_guard<std::mutex> lock(reportCacheMutex_);
679 NotificationAnalyticsUtil::ExecuteCacheList();
680 };
681 reportCacheList.pop_front();
682 reportTimeInfo->SetCallbackInfo(triggerFunc);
683 sptr<MiscServices::TimeServiceClient> timer = MiscServices::TimeServiceClient::GetInstance();
684 if (timer == nullptr || reportTimerId == 0) {
685 g_reportFlag = false;
686 ANS_LOGE("Failed to start timer due to get TimeServiceClient is null.");
687 return;
688 }
689 timer->StartTimer(reportTimerId, NotificationAnalyticsUtil::GetCurrentTime() +
690 REPORT_CACHE_INTERVAL_TIME * NotificationConstant::SECOND_TO_MS);
691 g_reportFlag = true;
692 }
693
ReportCommonEvent(const ReportCache & reportCache)694 void NotificationAnalyticsUtil::ReportCommonEvent(const ReportCache& reportCache)
695 {
696 EventFwk::CommonEventPublishInfo publishInfo;
697 publishInfo.SetSubscriberPermissions({OHOS_PERMISSION_NOTIFICATION_CONTROLLER});
698 EventFwk::CommonEventData commonData {reportCache.want, reportCache.eventCode, ""};
699 if (!EventFwk::CommonEventManager::PublishCommonEvent(commonData, publishInfo)) {
700 ANS_LOGE("Publish event failed %{public}d", reportCache.eventCode);
701 }
702 }
703
GetCurrentTime()704 int64_t NotificationAnalyticsUtil::GetCurrentTime()
705 {
706 auto now = std::chrono::system_clock::now();
707 auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
708 return duration.count();
709 }
710 } // namespace Notification
711 } // namespace OHOS
712