• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 #include "core/common/recorder/event_recorder.h"
16 
17 #include <cstdint>
18 #include <optional>
19 #include <vector>
20 
21 #include "core/common/container.h"
22 #include "core/common/recorder/event_controller.h"
23 #include "core/common/recorder/event_definition.h"
24 #include "core/common/recorder/node_data_cache.h"
25 
26 namespace OHOS::Ace::Recorder {
27 constexpr char IGNORE_WINDOW_NAME[] = "$HA_FLOAT_WINDOW$";
28 
IsCacheAvaliable()29 bool IsCacheAvaliable()
30 {
31     return EventRecorder::Get().IsComponentRecordEnable() && !NodeDataCache::Get().IsShareNodeEmpty();
32 }
33 
EventParamsBuilder()34 EventParamsBuilder::EventParamsBuilder()
35 {
36     params_ = std::make_shared<std::unordered_map<std::string, std::string>>();
37 }
38 
SetEventType(EventType eventType)39 EventParamsBuilder& EventParamsBuilder::SetEventType(EventType eventType)
40 {
41     eventType_ = eventType;
42     return *this;
43 }
44 
SetEventCategory(EventCategory category)45 EventParamsBuilder& EventParamsBuilder::SetEventCategory(EventCategory category)
46 {
47     category_ = category;
48     return *this;
49 }
50 
SetId(const std::string & id)51 EventParamsBuilder& EventParamsBuilder::SetId(const std::string& id)
52 {
53     if (!id.empty()) {
54         params_->emplace(KEY_ID, id);
55     }
56     return *this;
57 }
58 
SetType(const std::string & type)59 EventParamsBuilder& EventParamsBuilder::SetType(const std::string& type)
60 {
61     params_->emplace(KEY_TYPE, type);
62     return *this;
63 }
64 
SetDescription(const std::string & desc)65 EventParamsBuilder& EventParamsBuilder::SetDescription(const std::string& desc)
66 {
67     if (!desc.empty()) {
68         params_->emplace(KEY_DESCRIPTION, desc);
69     }
70     return *this;
71 }
72 
SetNavDst(const std::string & dstName)73 EventParamsBuilder& EventParamsBuilder::SetNavDst(const std::string& dstName)
74 {
75     if (!dstName.empty()) {
76         params_->emplace(KEY_NAV_DST, dstName);
77     }
78     return *this;
79 }
80 
SetPageUrl(const std::string & pageUrl)81 EventParamsBuilder& EventParamsBuilder::SetPageUrl(const std::string& pageUrl)
82 {
83     if (!pageUrl.empty()) {
84         params_->emplace(KEY_PAGE, pageUrl);
85     }
86     return *this;
87 }
88 
SetText(const std::string & value)89 EventParamsBuilder& EventParamsBuilder::SetText(const std::string& value)
90 {
91     if (!value.empty()) {
92         params_->emplace(KEY_TEXT, value);
93     }
94     return *this;
95 }
96 
SetChecked(bool value)97 EventParamsBuilder& EventParamsBuilder::SetChecked(bool value)
98 {
99     std::string strVal = value ? "true" : "false";
100     params_->emplace(KEY_CHECKED, strVal);
101     return *this;
102 }
103 
SetIndex(int value)104 EventParamsBuilder& EventParamsBuilder::SetIndex(int value)
105 {
106     params_->emplace(KEY_INDEX, std::to_string(value));
107     return *this;
108 }
109 
SetTextArray(const std::vector<std::string> & value)110 EventParamsBuilder& EventParamsBuilder::SetTextArray(const std::vector<std::string>& value)
111 {
112     auto jsonArray = JsonUtil::CreateArray(true);
113     for (size_t i = 0; i < value.size(); i++) {
114         jsonArray->Put(std::to_string(i).c_str(), value.at(i).c_str());
115     }
116     params_->emplace(KEY_TEXT_ARRAY, jsonArray->ToString());
117     return *this;
118 }
119 
FillExtraTextIfNeed(EventType eventType,EventParamsBuilder & builder,const RefPtr<NG::FrameNode> & host)120 void FillExtraTextIfNeed(EventType eventType, EventParamsBuilder& builder, const RefPtr<NG::FrameNode>& host)
121 {
122     if (eventType != EventType::CLICK || !builder.GetValue(KEY_TEXT).empty()) {
123         return;
124     }
125     if (!EventRecorder::Get().IsRecordEnable(Recorder::EventCategory::CATEGORY_PARENT_TEXT)) {
126         return;
127     }
128     if (!host->GetChildren().empty()) {
129         return;
130     }
131     auto parent = host->GetParentFrameNode();
132     CHECK_NULL_VOID(parent);
133     auto property = parent->GetAccessibilityProperty<NG::AccessibilityProperty>();
134     CHECK_NULL_VOID(property);
135     builder.SetExtra(KEY_EXTRA_TEXT, property->GetGroupText(true));
136 }
137 
SetHost(const RefPtr<NG::FrameNode> & node)138 EventParamsBuilder& EventParamsBuilder::SetHost(const RefPtr<NG::FrameNode>& node)
139 {
140     if (!node) {
141         return *this;
142     }
143     if (EventRecorder::Get().IsRecordEnable(EventCategory::CATEGORY_RECT)) {
144         auto rect = node->GetTransformRectRelativeToWindow().ToBounds();
145         params_->emplace(Recorder::KEY_NODE_RECT, std::move(rect));
146     }
147     params_->emplace(KEY_ACE_ID, std::to_string(node->GetId()));
148     SetPageUrl(GetPageUrlByNode(node));
149     FillExtraTextIfNeed(eventType_, *this, node);
150     return *this;
151 }
152 
SetExtra(const std::string & key,const std::string & value)153 EventParamsBuilder& EventParamsBuilder::SetExtra(const std::string& key, const std::string& value)
154 {
155     if (!key.empty() && !value.empty()) {
156         params_->emplace(key, value);
157     }
158     return *this;
159 }
160 
build()161 std::shared_ptr<std::unordered_map<std::string, std::string>> EventParamsBuilder::build()
162 {
163     auto current = Container::Current();
164     if (current) {
165         params_->emplace(KEY_MOUDLE_NAME, current->GetModuleName());
166     }
167     params_->emplace(KEY_ABILITY_NAME, AceApplicationInfo::GetInstance().GetAbilityName());
168     return params_;
169 }
170 
GetEventType() const171 EventType EventParamsBuilder::GetEventType() const
172 {
173     return eventType_;
174 }
175 
GetEventCategory() const176 EventCategory EventParamsBuilder::GetEventCategory() const
177 {
178     return category_;
179 }
180 
GetValue(const std::string & key) const181 std::string EventParamsBuilder::GetValue(const std::string& key) const
182 {
183     auto iter = params_->find(key);
184     if (iter != params_->end()) {
185         return iter->second;
186     }
187     return "";
188 }
189 
ToString() const190 std::string EventParamsBuilder::ToString() const
191 {
192     std::stringstream ss;
193     ss << "{";
194     if (eventType_ != EventType::INVALID) {
195         ss << "eventType:" << eventType_ << ", ";
196     }
197     for (auto&& it : *params_) {
198         ss << it.first << ":" << it.second << ", ";
199     }
200     ss << "}";
201     return ss.str();
202 }
203 
MapToString(const std::shared_ptr<std::unordered_map<std::string,std::string>> & input)204 std::string MapToString(const std::shared_ptr<std::unordered_map<std::string, std::string>>& input)
205 {
206     if (!input) {
207         return "";
208     }
209     std::stringstream ss;
210     ss << "{";
211     for (auto it = input->begin(); it != input->end(); it++) {
212         ss << it->first << ":" << it->second << ", ";
213     }
214     ss << "}";
215     return ss.str();
216 }
217 
Get()218 EventRecorder& EventRecorder::Get()
219 {
220     static EventRecorder eventRecorder;
221     return eventRecorder;
222 }
223 
EventRecorder()224 EventRecorder::EventRecorder()
225 {
226     eventSwitch_.resize(static_cast<int32_t>(EventCategory::CATEGORY_END), false);
227     eventSwitch_[static_cast<int32_t>(EventCategory::CATEGORY_PAGE)] = true;
228     globalSwitch_.resize(static_cast<int32_t>(EventCategory::CATEGORY_END), true);
229 }
230 
UpdateEventSwitch(const std::vector<bool> & eventSwitch)231 void EventRecorder::UpdateEventSwitch(const std::vector<bool>& eventSwitch)
232 {
233     eventSwitch_ = eventSwitch;
234 }
235 
UpdateWebIdentifier(const std::unordered_map<std::string,std::string> identifierMap)236 void EventRecorder::UpdateWebIdentifier(const std::unordered_map<std::string, std::string> identifierMap)
237 {
238     webIdentifierMap_ = identifierMap;
239 }
240 
IsPageRecordEnable() const241 bool EventRecorder::IsPageRecordEnable() const
242 {
243     int32_t index = static_cast<int32_t>(EventCategory::CATEGORY_PAGE);
244     return globalSwitch_[index] && eventSwitch_[index];
245 }
246 
IsPageParamRecordEnable() const247 bool EventRecorder::IsPageParamRecordEnable() const
248 {
249     int32_t index = static_cast<int32_t>(EventCategory::CATEGORY_PAGE_PARAM);
250     return globalSwitch_[index] && eventSwitch_[index];
251 }
252 
IsExposureRecordEnable() const253 bool EventRecorder::IsExposureRecordEnable() const
254 {
255     int32_t index = static_cast<int32_t>(EventCategory::CATEGORY_EXPOSURE);
256     return globalSwitch_[index] && eventSwitch_[index];
257 }
258 
IsComponentRecordEnable() const259 bool EventRecorder::IsComponentRecordEnable() const
260 {
261     int32_t index = static_cast<int32_t>(EventCategory::CATEGORY_COMPONENT);
262     return globalSwitch_[index] && eventSwitch_[index];
263 }
264 
IsRecordEnable(EventCategory category) const265 bool EventRecorder::IsRecordEnable(EventCategory category) const
266 {
267     int32_t index = static_cast<int32_t>(category);
268     return globalSwitch_[index] && eventSwitch_[index];
269 }
270 
SetContainerInfo(const std::string & windowName,int32_t id,bool foreground)271 void EventRecorder::SetContainerInfo(const std::string& windowName, int32_t id, bool foreground)
272 {
273     if (windowName == IGNORE_WINDOW_NAME) {
274         return;
275     }
276     if (foreground) {
277         containerId_ = id;
278     }
279 }
280 
SetFocusContainerInfo(const std::string & windowName,int32_t id)281 void EventRecorder::SetFocusContainerInfo(const std::string& windowName, int32_t id)
282 {
283     if (windowName == IGNORE_WINDOW_NAME) {
284         return;
285     }
286     focusContainerId_ = id;
287 }
288 
GetContainerId(bool isFoucs)289 int32_t EventRecorder::GetContainerId(bool isFoucs)
290 {
291     if (isFoucs) {
292         return focusContainerId_;
293     } else {
294         return containerId_;
295     }
296 }
297 
GetPageUrl()298 const std::string& EventRecorder::GetPageUrl()
299 {
300     auto pageUrl = GetPageUrlByContainerId(focusContainerId_);
301     if (!pageUrl.empty()) {
302         pageUrl_ = pageUrl;
303     }
304     return pageUrl_;
305 }
306 
GetNavDstName() const307 const std::string& EventRecorder::GetNavDstName() const
308 {
309     return navDstName_;
310 }
311 
GetCacheJsCode() const312 std::string EventRecorder::GetCacheJsCode() const
313 {
314     return EventController::Get().GetCacheJsCode();
315 }
316 
FillWebJsCode(std::optional<WebJsItem> & scriptItems) const317 void EventRecorder::FillWebJsCode(std::optional<WebJsItem>& scriptItems) const
318 {
319     if (!IsRecordEnable(EventCategory::CATEGORY_WEB)) {
320         return;
321     }
322     auto codeList = EventController::Get().GetWebJsCodeList();
323     if (codeList.empty()) {
324         return;
325     }
326     std::vector<std::string> scriptRules = { "*" };
327     if (scriptItems.has_value()) {
328         for (const auto& code : codeList) {
329             scriptItems->emplace(std::make_pair(code, scriptRules));
330         }
331     } else {
332         WebJsItem webJsItems;
333         for (const auto& code : codeList) {
334             webJsItems.emplace(std::make_pair(code, scriptRules));
335         }
336         scriptItems = std::make_optional<WebJsItem>(webJsItems);
337     }
338 }
339 
SaveJavascriptItems(const std::map<std::string,std::vector<std::string>> & scriptItems,const std::vector<std::string> & orderScriptItems)340 void EventRecorder::SaveJavascriptItems(const std::map<std::string, std::vector<std::string>>& scriptItems,
341     const std::vector<std::string>& orderScriptItems)
342 {
343     if (scriptItems.empty()) {
344         return;
345     }
346     if (EventController::Get().HasCached() || EventController::Get().HasWebProcessed()) {
347         return;
348     }
349     cacheScriptItems_ = std::make_optional<std::map<std::string, std::vector<std::string>>>(scriptItems);
350     if (!orderScriptItems.empty()) {
351         cacheOrderScriptItems_ = std::make_optional<std::vector<std::string>>(orderScriptItems);
352     }
353 }
354 
HandleJavascriptItems(std::optional<WebJsItem> & scriptItems,std::optional<std::vector<std::string>> & orderScriptItems)355 void EventRecorder::HandleJavascriptItems(
356     std::optional<WebJsItem>& scriptItems, std::optional<std::vector<std::string>>& orderScriptItems)
357 {
358     if (scriptItems.has_value()) {
359         cacheScriptItems_ = std::nullopt;
360         cacheOrderScriptItems_ = std::nullopt;
361         return;
362     }
363     FillWebJsCode(cacheScriptItems_);
364     if (!cacheScriptItems_.has_value()) {
365         cacheOrderScriptItems_ = std::nullopt;
366         return;
367     }
368     scriptItems.swap(cacheScriptItems_);
369     cacheScriptItems_ = std::nullopt;
370     if (cacheOrderScriptItems_.has_value()) {
371         orderScriptItems.swap(cacheOrderScriptItems_);
372         cacheOrderScriptItems_ = std::nullopt;
373     }
374 }
375 
IsMessageValid(const std::string & webCategory,const std::string & identifier)376 bool EventRecorder::IsMessageValid(const std::string& webCategory, const std::string& identifier)
377 {
378     auto iter = webIdentifierMap_.find(webCategory);
379     if (iter == webIdentifierMap_.end()) {
380         return false;
381     }
382     return iter->second == identifier;
383 }
384 
NotifyEventCacheEnd()385 void EventRecorder::NotifyEventCacheEnd()
386 {
387     cacheScriptItems_ = std::nullopt;
388     cacheOrderScriptItems_ = std::nullopt;
389 }
390 
OnPageShow(const std::string & pageUrl,const std::string & param,const std::string & name)391 void EventRecorder::OnPageShow(const std::string& pageUrl, const std::string& param, const std::string& name)
392 {
393     pageUrl_ = pageUrl;
394     NodeDataCache::Get().OnPageShow(pageUrl);
395     Recorder::EventParamsBuilder builder;
396     builder.SetType(std::to_string(PageEventType::ROUTER_PAGE))
397         .SetPageUrl(pageUrl)
398         .SetExtra(KEY_NAME, name)
399         .SetExtra(Recorder::KEY_PAGE_PARAM, param);
400     EventController::Get().NotifyEvent(
401         EventCategory::CATEGORY_PAGE, static_cast<int32_t>(EventType::PAGE_SHOW), std::move(builder.build()));
402 }
403 
OnPageHide(const std::string & pageUrl,const int64_t duration,const std::string & name)404 void EventRecorder::OnPageHide(const std::string& pageUrl, const int64_t duration, const std::string& name)
405 {
406     Recorder::EventParamsBuilder builder;
407     builder.SetType(std::to_string(PageEventType::ROUTER_PAGE))
408         .SetPageUrl(pageUrl)
409         .SetExtra(KEY_NAME, name)
410         .SetExtra(KEY_DURATION, std::to_string(duration));
411     EventController::Get().NotifyEvent(
412         EventCategory::CATEGORY_PAGE, static_cast<int32_t>(EventType::PAGE_HIDE), std::move(builder.build()));
413 }
414 
OnClick(EventParamsBuilder && builder)415 void EventRecorder::OnClick(EventParamsBuilder&& builder)
416 {
417     if (!taskExecutor_) {
418         auto container = Container::Current();
419         CHECK_NULL_VOID(container);
420         taskExecutor_ = container->GetTaskExecutor();
421     }
422     CHECK_NULL_VOID(taskExecutor_);
423     if (builder.GetValue(KEY_PAGE).empty()) {
424         builder.SetPageUrl(GetPageUrl());
425     }
426     builder.SetNavDst(navDstName_);
427     auto params = builder.build();
428     taskExecutor_->PostTask(
429         [taskExecutor = taskExecutor_, params]() {
430             EventController::Get().NotifyEvent(
431                 EventCategory::CATEGORY_COMPONENT, static_cast<int32_t>(EventType::CLICK), std::move(params));
432         },
433         TaskExecutor::TaskType::UI, "ArkUINotifyClickEvent");
434 }
435 
OnChange(EventParamsBuilder && builder)436 void EventRecorder::OnChange(EventParamsBuilder&& builder)
437 {
438     if (builder.GetValue(KEY_PAGE).empty()) {
439         builder.SetPageUrl(GetPageUrl());
440     }
441     builder.SetNavDst(navDstName_);
442     auto params = builder.build();
443     EventController::Get().NotifyEvent(
444         EventCategory::CATEGORY_COMPONENT, static_cast<int32_t>(EventType::CHANGE), std::move(params));
445 }
446 
OnEvent(EventParamsBuilder && builder)447 void EventRecorder::OnEvent(EventParamsBuilder&& builder)
448 {
449     if (builder.GetValue(KEY_PAGE).empty()) {
450         builder.SetPageUrl(GetPageUrl());
451     }
452     builder.SetNavDst(navDstName_);
453     auto eventType = builder.GetEventType();
454     auto params = builder.build();
455     EventController::Get().NotifyEvent(builder.GetEventCategory(), static_cast<int32_t>(eventType), std::move(params));
456 }
457 
OnNavDstShow(EventParamsBuilder && builder)458 void EventRecorder::OnNavDstShow(EventParamsBuilder&& builder)
459 {
460     navDstName_ = builder.GetValue(KEY_NAV_DST);
461     navShowTime_ = GetCurrentTimestamp();
462     builder.SetPageUrl(GetPageUrl());
463     builder.SetType(std::to_string(PageEventType::NAV_PAGE));
464     auto params = builder.build();
465     EventController::Get().NotifyEvent(
466         EventCategory::CATEGORY_PAGE, static_cast<int32_t>(EventType::PAGE_SHOW), std::move(params));
467 }
468 
OnNavDstHide(EventParamsBuilder && builder)469 void EventRecorder::OnNavDstHide(EventParamsBuilder&& builder)
470 {
471     if (builder.GetValue(KEY_NAV_DST) == navDstName_) {
472         navDstName_ = "";
473         if (navShowTime_ > 0) {
474             int64_t duration = GetCurrentTimestamp() - navShowTime_;
475             builder.SetExtra(KEY_DURATION, std::to_string(duration));
476             navShowTime_ = 0;
477         }
478     }
479     builder.SetPageUrl(GetPageUrl());
480     builder.SetType(std::to_string(PageEventType::NAV_PAGE));
481     auto params = builder.build();
482     EventController::Get().NotifyEvent(
483         EventCategory::CATEGORY_PAGE, static_cast<int32_t>(EventType::PAGE_HIDE), std::move(params));
484 }
485 
OnExposure(EventParamsBuilder && builder)486 void EventRecorder::OnExposure(EventParamsBuilder&& builder)
487 {
488     auto params = builder.build();
489     EventController::Get().NotifyEvent(
490         EventCategory::CATEGORY_EXPOSURE, static_cast<int32_t>(EventType::EXPOSURE), std::move(params));
491 }
492 
OnWebEvent(const RefPtr<NG::FrameNode> & node,const std::vector<std::string> & params)493 void EventRecorder::OnWebEvent(const RefPtr<NG::FrameNode>& node, const std::vector<std::string>& params)
494 {
495     CHECK_NULL_VOID(node);
496     if (params.empty()) {
497         return;
498     }
499     if (params.size() == WEB_PARAM_SIZE) {
500         if (!IsRecordEnable(EventCategory::CATEGORY_WEB)) {
501             return;
502         }
503         if (!IsMessageValid(params[WEB_PARAM_INDEX_CATEGORY], params[WEB_PARAM_INDEX_IDENTIFIER])) {
504             return;
505         }
506         EventParamsBuilder builder;
507         builder.SetId(node->GetInspectorIdValue(""))
508             .SetType(node->GetHostTag())
509             .SetEventType(EventType::WEB_ACTION)
510             .SetEventCategory(EventCategory::CATEGORY_WEB)
511             .SetExtra(KEY_WEB_CATEGORY, params[WEB_PARAM_INDEX_CATEGORY])
512             .SetText(params[WEB_PARAM_INDEX_CONTENT])
513             .SetHost(node)
514             .SetDescription(node->GetAutoEventParamValue(""));
515         OnEvent(std::move(builder));
516     }
517 }
518 
OnAttachWeb(const RefPtr<NG::FrameNode> & node)519 void EventRecorder::OnAttachWeb(const RefPtr<NG::FrameNode>& node)
520 {
521     CHECK_NULL_VOID(node);
522     weakNodeCache_[node->GetId()] = Referenced::WeakClaim(Referenced::RawPtr(node));
523 }
524 
OnDetachWeb(int32_t nodeId)525 void EventRecorder::OnDetachWeb(int32_t nodeId)
526 {
527     weakNodeCache_.erase(nodeId);
528 }
529 } // namespace OHOS::Ace::Recorder
530