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/node_data_cache.h"
16
17 #include "core/components_ng/pattern/stage/page_pattern.h"
18
19 namespace OHOS::Ace::Recorder {
20 constexpr int32_t PAGE_URL_SUFFIX_LENGTH = 3;
21
GetPageUrlByNode(const RefPtr<NG::FrameNode> & node)22 std::string GetPageUrlByNode(const RefPtr<NG::FrameNode>& node)
23 {
24 auto pageNode = node->GetPageNode();
25 CHECK_NULL_RETURN(pageNode, "");
26 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
27 CHECK_NULL_RETURN(pagePattern, "");
28 return pagePattern->GetPageUrl();
29 }
30
GetCurrentPageUrl()31 const std::string GetCurrentPageUrl()
32 {
33 CHECK_RUN_ON(UI);
34 auto container = Container::Current();
35 CHECK_NULL_RETURN(container, "");
36 auto frontEnd = container->GetFrontend();
37 CHECK_NULL_RETURN(frontEnd, "");
38 auto pageUrl = frontEnd->GetCurrentPageUrl();
39 // remove .js suffix if exists
40 if (StringUtils::EndWith(pageUrl, ".js")) {
41 return pageUrl.substr(0, pageUrl.length() - PAGE_URL_SUFFIX_LENGTH);
42 }
43 return pageUrl;
44 }
45
Get()46 NodeDataCache& NodeDataCache::Get()
47 {
48 static NodeDataCache cache;
49 return cache;
50 }
51
NodeDataCache()52 NodeDataCache::NodeDataCache()
53 {
54 container_ = std::make_shared<NodeDataContainer>();
55 mergedConfig_ = std::make_shared<MergedConfig>();
56 }
57
OnPageReady()58 void NodeDataCache::OnPageReady()
59 {
60 prePageUrl_ = pageUrl_;
61 pageUrl_ = GetCurrentPageUrl();
62 }
63
OnPageShow(const std::string & pageUrl)64 void NodeDataCache::OnPageShow(const std::string& pageUrl)
65 {
66 prePageUrl_ = pageUrl_;
67 pageUrl_ = pageUrl;
68 }
69
OnBeforePagePop(bool destroy)70 void NodeDataCache::OnBeforePagePop(bool destroy)
71 {
72 if (destroy) {
73 Clear(prePageUrl_);
74 } else {
75 Clear(pageUrl_);
76 }
77 shouldCollectFull_ = false;
78 EventRecorder::Get().SetContainerChanged();
79 }
80
UpdateConfig(std::shared_ptr<MergedConfig> && mergedConfig)81 void NodeDataCache::UpdateConfig(std::shared_ptr<MergedConfig>&& mergedConfig)
82 {
83 std::unique_lock<std::shared_mutex> lock(configMutex_);
84 mergedConfig_ = mergedConfig;
85 shouldCollectFull_ = false;
86 }
87
PutString(const RefPtr<NG::FrameNode> & node,const std::string & id,const std::string & value)88 bool NodeDataCache::PutString(const RefPtr<NG::FrameNode>& node, const std::string& id, const std::string& value)
89 {
90 if (id.empty() || value.empty() || value.length() > MAX_DATA_LENGTH) {
91 return false;
92 }
93 if (mergedConfig_->shareNodes.empty()) {
94 return false;
95 }
96 auto pageUrl = GetPageUrlByNode(node);
97 if (pageUrl.empty()) {
98 return false;
99 }
100 std::shared_lock<std::shared_mutex> configLock(configMutex_);
101 auto iter = mergedConfig_->shareNodes.find(pageUrl);
102 if (!shouldCollectFull_ && iter == mergedConfig_->shareNodes.end()) {
103 return false;
104 }
105 if (shouldCollectFull_ || iter->second.find(id) != iter->second.end()) {
106 std::unique_lock<std::shared_mutex> cacheLock(cacheMutex_);
107 auto iter = container_->find(pageUrl);
108 if (iter == container_->end()) {
109 auto pageContainer = std::unordered_map<std::string, std::string>();
110 pageContainer.emplace(id, value);
111 container_->emplace(pageUrl, std::move(pageContainer));
112 } else {
113 if (iter->second.size() >= MAX_SIZE_PER_PAGE) {
114 return false;
115 }
116 iter->second[id] = value;
117 }
118 }
119 return true;
120 }
121
PutBool(const RefPtr<NG::FrameNode> & node,const std::string & id,bool value)122 bool NodeDataCache::PutBool(const RefPtr<NG::FrameNode>& node, const std::string& id, bool value)
123 {
124 std::string strVal = value ? "true" : "false";
125 return PutString(node, id, strVal);
126 }
127
PutInt(const RefPtr<NG::FrameNode> & node,const std::string & id,int value)128 bool NodeDataCache::PutInt(const RefPtr<NG::FrameNode>& node, const std::string& id, int value)
129 {
130 return PutString(node, id, std::to_string(value));
131 }
132
PutStringArray(const RefPtr<NG::FrameNode> & node,const std::string & id,const std::vector<std::string> & value)133 bool NodeDataCache::PutStringArray(
134 const RefPtr<NG::FrameNode>& node, const std::string& id, const std::vector<std::string>& value)
135 {
136 auto jsonArray = JsonUtil::CreateArray(true);
137 for (size_t i = 0; i < value.size(); i++) {
138 jsonArray->Put(std::to_string(i).c_str(), value.at(i).c_str());
139 }
140 return PutString(node, id, jsonArray->ToString());
141 }
142
PutMultiple(const RefPtr<NG::FrameNode> & node,const std::string & id,const std::string & name,bool value)143 bool NodeDataCache::PutMultiple(
144 const RefPtr<NG::FrameNode>& node, const std::string& id, const std::string& name, bool value)
145 {
146 auto json = JsonUtil::Create(true);
147 json->Put(KEY_TEXT, name.c_str());
148 json->Put(KEY_CHECKED, value);
149 return PutString(node, id, json->ToString());
150 }
151
PutMultiple(const RefPtr<NG::FrameNode> & node,const std::string & id,const std::string & name,int index)152 bool NodeDataCache::PutMultiple(
153 const RefPtr<NG::FrameNode>& node, const std::string& id, const std::string& name, int index)
154 {
155 auto json = JsonUtil::Create(true);
156 json->Put(KEY_TEXT, name.c_str());
157 json->Put(KEY_INDEX, index);
158 return PutString(node, id, json->ToString());
159 }
160
PutMultiple(const RefPtr<NG::FrameNode> & node,const std::string & id,const std::string & name,const std::vector<std::string> & value)161 bool NodeDataCache::PutMultiple(const RefPtr<NG::FrameNode>& node, const std::string& id, const std::string& name,
162 const std::vector<std::string>& value)
163 {
164 auto json = JsonUtil::Create(true);
165 json->Put(KEY_TEXT, name.c_str());
166 auto jsonArray = JsonUtil::CreateArray(true);
167 for (size_t i = 0; i < value.size(); i++) {
168 jsonArray->Put(std::to_string(i).c_str(), value.at(i).c_str());
169 }
170 json->Put(KEY_TEXT_ARRAY, jsonArray);
171 return PutString(node, id, json->ToString());
172 }
173
GetNodeData(const std::string & pageUrl,std::unordered_map<std::string,std::string> & nodes)174 void NodeDataCache::GetNodeData(const std::string& pageUrl, std::unordered_map<std::string, std::string>& nodes)
175 {
176 if (pageUrl.empty()) {
177 return;
178 }
179 std::shared_lock<std::shared_mutex> lock(cacheMutex_);
180 auto iter = container_->find(pageUrl);
181 if (iter == container_->end()) {
182 return;
183 }
184 for (auto nodeIter = nodes.begin(); nodeIter != nodes.end(); nodeIter++) {
185 auto it = iter->second.find(nodeIter->first);
186 if (it != iter->second.end()) {
187 nodes[it->first] = it->second;
188 }
189 }
190 }
191
Clear(const std::string & pageUrl)192 void NodeDataCache::Clear(const std::string& pageUrl)
193 {
194 if (pageUrl.empty()) {
195 return;
196 }
197 std::unique_lock<std::shared_mutex> lock(cacheMutex_);
198 auto iter = container_->find(pageUrl);
199 if (iter != container_->end()) {
200 container_->erase(iter);
201 }
202 }
203
Reset()204 void NodeDataCache::Reset()
205 {
206 std::unique_lock<std::shared_mutex> lock(cacheMutex_);
207 container_->clear();
208 pageUrl_ = "";
209 prePageUrl_ = "";
210 }
211
GetExposureCfg(const std::string & pageUrl,const std::string & inspectId,ExposureCfg & cfg)212 void NodeDataCache::GetExposureCfg(const std::string& pageUrl, const std::string& inspectId, ExposureCfg& cfg)
213 {
214 if (pageUrl.empty()) {
215 return;
216 }
217 std::shared_lock<std::shared_mutex> configLock(configMutex_);
218 auto iter = mergedConfig_->exposureNodes.find(pageUrl);
219 if (iter == mergedConfig_->exposureNodes.end()) {
220 return;
221 }
222 auto cfgIter = iter->second.find({ inspectId, 0.0, 0 });
223 if (cfgIter == iter->second.end()) {
224 return;
225 }
226 cfg.id = cfgIter->id;
227 cfg.ratio = cfgIter->ratio;
228 cfg.duration = cfgIter->duration;
229 }
230 } // namespace OHOS::Ace::Recorder
231