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