1 /**
2 * Copyright (c) 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 "guard_name_cache.h"
17
18 #include <regex>
19
20 #include "utils/logger.h"
21 #include "utils/json_builder.h"
22
23 #include "util/assert_util.h"
24 #include "util/file_util.h"
25 #include "util/json_util.h"
26
27 namespace {
28 constexpr std::string_view TAG = "[Guard_NameCache]";
29 constexpr std::string_view IDENTIFIER_CACHE = "IdentifierCache";
30 constexpr std::string_view MEMBER_METHOD_CACHE = "MemberMethodCache";
31 constexpr std::string_view OBF_NAME = "obfName";
32 constexpr std::string_view ORI_SOURCE_FILE = "OriSourceFile";
33 constexpr std::string_view OBF_SOURCE_FILE = "ObfSourceFile";
34 constexpr std::string_view ENTRY_PACKAGE_INFO = "entryPackageInfo";
35 constexpr std::string_view COMPILE_SDK_VERSION = "compileSdkVersion";
36 constexpr std::string_view PROPERTY_CACHE = "PropertyCache";
37 constexpr std::string_view FILE_NAME_CACHE = "FileNameCache";
38
39 /**
40 * Remove the scope identifier # and its line number information from the mapping key value for incremental nameCache
41 * scenario
42 * @param originMap The format of the map key value is a string with scope identifier # and line number information
43 * @return The format of the map key value is a string without scope identifier # and line number information
44 * e.g. DeleteScopeAndLineNum({"#func:1:10", "a"}) => {"func", "a"}
45 */
DeleteScopeAndLineNum(const std::map<std::string,std::string> & originMap)46 std::map<std::string, std::string> DeleteScopeAndLineNum(const std::map<std::string, std::string> &originMap)
47 {
48 std::map<std::string, std::string> res;
49 for (const auto &item : originMap) {
50 auto key = item.first;
51 size_t pos = key.rfind('#');
52 if (pos != std::string::npos) {
53 key = key.substr(pos + 1);
54 }
55 pos = key.find(':');
56 if (pos != std::string::npos) {
57 key = key.substr(0, pos);
58 }
59 res.emplace(key, item.second);
60 }
61 return res;
62 }
63
HasLineNumberInfo(const std::map<std::string,std::string> & table,const std::string & str)64 bool HasLineNumberInfo(const std::map<std::string, std::string> &table, const std::string &str)
65 {
66 std::string match = str + ":\\d+:\\d+";
67 std::regex pattern(match);
68 return std::any_of(table.begin(), table.end(),
69 [&](const auto &item) { return std::regex_search(item.first, pattern); });
70 }
71
MapToJson(const std::map<std::string,std::string> & mapInfo,bool deduplicate=false)72 std::function<void(panda::JsonObjectBuilder &)> MapToJson(const std::map<std::string, std::string> &mapInfo,
73 bool deduplicate = false)
74 {
75 return [mapInfo, deduplicate](panda::JsonObjectBuilder &builder) {
76 for (const auto &item : mapInfo) {
77 if (deduplicate && item.first == item.second) {
78 continue;
79 }
80 builder.AddProperty(item.first, item.second);
81 }
82 };
83 }
84
FileNameCacheToJson(const panda::guard::FileNameCacheInfo & cacheInfo)85 std::function<void(panda::JsonObjectBuilder &)> FileNameCacheToJson(const panda::guard::FileNameCacheInfo &cacheInfo)
86 {
87 return [cacheInfo](panda::JsonObjectBuilder &builder) {
88 builder.AddProperty(IDENTIFIER_CACHE, MapToJson(cacheInfo.identifierCacheMap));
89 builder.AddProperty(MEMBER_METHOD_CACHE, MapToJson(cacheInfo.memberMethodCacheMap));
90 builder.AddProperty(OBF_NAME, cacheInfo.obfName);
91 if (!cacheInfo.oriSourceFile.empty()) {
92 builder.AddProperty(ORI_SOURCE_FILE, cacheInfo.oriSourceFile);
93 builder.AddProperty(OBF_SOURCE_FILE, cacheInfo.obfSourceFile);
94 }
95 };
96 }
97 } // namespace
98
Load(const std::string & applyNameCachePath)99 void panda::guard::NameCache::Load(const std::string &applyNameCachePath)
100 {
101 if (applyNameCachePath.empty()) {
102 return;
103 }
104 std::string content = FileUtil::GetFileContent(applyNameCachePath);
105 if (content.empty()) {
106 LOG(WARNING, PANDAGUARD) << TAG << "get apply name cache file content failed";
107 return;
108 }
109
110 ParseAppliedNameCache(content);
111 ParseHistoryNameCacheToUsedNames();
112 }
113
GetHistoryUsedNames() const114 const std::set<std::string> &panda::guard::NameCache::GetHistoryUsedNames() const
115 {
116 return historyUsedNames_;
117 }
118
GetHistoryFileNameMapping() const119 std::map<std::string, std::string> panda::guard::NameCache::GetHistoryFileNameMapping() const
120 {
121 return historyNameCache_.fileNameCacheMap;
122 }
123
GetHistoryNameMapping() const124 std::map<std::string, std::string> panda::guard::NameCache::GetHistoryNameMapping() const
125 {
126 std::map<std::string, std::string> res = historyNameCache_.propertyCacheMap;
127 for (const auto &item : historyNameCache_.fileCacheInfoMap) {
128 res.insert(item.second.identifierCacheMap.begin(), item.second.identifierCacheMap.end());
129 res.insert(item.second.memberMethodCacheMap.begin(), item.second.memberMethodCacheMap.end());
130 }
131 return res;
132 }
133
AddObfIdentifierName(const std::string & filePath,const std::string & origin,const std::string & obfName)134 void panda::guard::NameCache::AddObfIdentifierName(const std::string &filePath, const std::string &origin,
135 const std::string &obfName)
136 {
137 if (filePath.empty() || origin.empty() || obfName.empty()) {
138 LOG(WARNING, PANDAGUARD) << TAG << "[" << __FUNCTION__ << "], filePath or origin or obfName is empty";
139 LOG(INFO, PANDAGUARD) << TAG << "filePath:" << filePath;
140 LOG(INFO, PANDAGUARD) << TAG << "origin:" << origin;
141 LOG(INFO, PANDAGUARD) << TAG << "obfName:" << obfName;
142 return;
143 }
144 auto fileItem = newNameCache_.fileCacheInfoMap.find(filePath);
145 if (fileItem != newNameCache_.fileCacheInfoMap.end()) {
146 if (!HasLineNumberInfo(fileItem->second.identifierCacheMap, origin)) {
147 fileItem->second.identifierCacheMap.emplace(origin, obfName);
148 }
149 return;
150 }
151 FileNameCacheInfo cacheInfo;
152 cacheInfo.identifierCacheMap.emplace(origin, obfName);
153 newNameCache_.fileCacheInfoMap.emplace(filePath, cacheInfo);
154 }
155
AddObfMemberMethodName(const std::string & filePath,const std::string & origin,const std::string & obfName)156 void panda::guard::NameCache::AddObfMemberMethodName(const std::string &filePath, const std::string &origin,
157 const std::string &obfName)
158 {
159 if (filePath.empty() || origin.empty() || obfName.empty()) {
160 LOG(WARNING, PANDAGUARD) << TAG << "[" << __FUNCTION__ << "], filePath or origin or obfName is empty";
161 LOG(INFO, PANDAGUARD) << TAG << "filePath:" << filePath;
162 LOG(INFO, PANDAGUARD) << TAG << "origin:" << origin;
163 LOG(INFO, PANDAGUARD) << TAG << "obfName:" << obfName;
164 return;
165 }
166 auto fileItem = newNameCache_.fileCacheInfoMap.find(filePath);
167 if (fileItem != newNameCache_.fileCacheInfoMap.end()) {
168 fileItem->second.memberMethodCacheMap.emplace(origin, obfName);
169 return;
170 }
171 FileNameCacheInfo cacheInfo;
172 cacheInfo.memberMethodCacheMap.emplace(origin, obfName);
173 newNameCache_.fileCacheInfoMap.emplace(filePath, cacheInfo);
174 }
175
AddObfName(const std::string & filePath,const std::string & obfName)176 void panda::guard::NameCache::AddObfName(const std::string &filePath, const std::string &obfName)
177 {
178 if (filePath.empty() || obfName.empty()) {
179 LOG(WARNING, PANDAGUARD) << TAG << "[" << __FUNCTION__ << "], filePath or obfName is empty";
180 LOG(INFO, PANDAGUARD) << TAG << "filePath:" << filePath;
181 LOG(INFO, PANDAGUARD) << TAG << "obfName:" << obfName;
182 return;
183 }
184 auto fileItem = newNameCache_.fileCacheInfoMap.find(filePath);
185 if (fileItem != newNameCache_.fileCacheInfoMap.end()) {
186 fileItem->second.obfName = obfName;
187 return;
188 }
189 FileNameCacheInfo cacheInfo;
190 cacheInfo.obfName = obfName;
191 newNameCache_.fileCacheInfoMap.emplace(filePath, cacheInfo);
192 }
193
AddSourceFile(const std::string & filePath,const std::string & oriSource,const std::string & obfSource)194 void panda::guard::NameCache::AddSourceFile(const std::string &filePath, const std::string &oriSource,
195 const std::string &obfSource)
196 {
197 if (filePath.empty() || oriSource.empty() || obfSource.empty()) {
198 LOG(WARNING, PANDAGUARD) << TAG << "[" << __FUNCTION__ << "], filePath or oriSource or obfSource is empty";
199 LOG(INFO, PANDAGUARD) << TAG << "filePath:" << filePath;
200 LOG(INFO, PANDAGUARD) << TAG << "oriSourceFile:" << oriSource;
201 LOG(INFO, PANDAGUARD) << TAG << "obfSourceFile:" << obfSource;
202 return;
203 }
204 auto fileItem = newNameCache_.fileCacheInfoMap.find(filePath);
205 if (fileItem != newNameCache_.fileCacheInfoMap.end()) {
206 fileItem->second.oriSourceFile = oriSource;
207 fileItem->second.obfSourceFile = obfSource;
208 return;
209 }
210 FileNameCacheInfo cacheInfo;
211 cacheInfo.oriSourceFile = oriSource;
212 cacheInfo.obfSourceFile = obfSource;
213 newNameCache_.fileCacheInfoMap.emplace(filePath, cacheInfo);
214 }
215
AddNewNameCacheObfFileName(const std::string & origin,const std::string & obfName)216 void panda::guard::NameCache::AddNewNameCacheObfFileName(const std::string &origin, const std::string &obfName)
217 {
218 if (origin.empty() || obfName.empty()) {
219 LOG(WARNING, PANDAGUARD) << TAG << "[" << __FUNCTION__ << "], origin or obfName is empty";
220 LOG(INFO, PANDAGUARD) << TAG << "origin:" << origin;
221 LOG(INFO, PANDAGUARD) << TAG << "obfName:" << obfName;
222 return;
223 }
224 newNameCache_.fileNameCacheMap.emplace(origin, obfName);
225 }
226
AddObfPropertyName(const std::string & origin,const std::string & obfName)227 void panda::guard::NameCache::AddObfPropertyName(const std::string &origin, const std::string &obfName)
228 {
229 if (origin.empty() || obfName.empty()) {
230 LOG(WARNING, PANDAGUARD) << TAG << "[" << __FUNCTION__ << "], origin or obfName is empty";
231 LOG(INFO, PANDAGUARD) << TAG << "origin:" << origin;
232 LOG(INFO, PANDAGUARD) << TAG << "obfName:" << obfName;
233 return;
234 }
235 newNameCache_.propertyCacheMap.emplace(origin, obfName);
236 }
237
MergeNameCache(ProjectNameCacheInfo & merge)238 void panda::guard::NameCache::MergeNameCache(ProjectNameCacheInfo &merge)
239 {
240 merge.fileCacheInfoMap = newNameCache_.fileCacheInfoMap;
241 merge.entryPackageInfo = options_->GetEntryPackageInfo();
242 merge.compileSdkVersion = options_->GetCompileSdkVersion();
243 merge.propertyCacheMap = historyNameCache_.propertyCacheMap;
244 merge.propertyCacheMap.insert(newNameCache_.propertyCacheMap.begin(), newNameCache_.propertyCacheMap.end());
245 merge.fileNameCacheMap = historyNameCache_.fileNameCacheMap;
246 merge.fileNameCacheMap.insert(newNameCache_.fileNameCacheMap.begin(), newNameCache_.fileNameCacheMap.end());
247 }
248
WriteCache()249 void panda::guard::NameCache::WriteCache()
250 {
251 std::string defaultPath = options_->GetDefaultNameCachePath();
252 std::string printPath = options_->GetPrintNameCache();
253 PANDA_GUARD_ASSERT_PRINT(defaultPath.empty() && printPath.empty(), TAG,
254 ErrorCode::NOT_CONFIGURED_DEFAULT_AND_PRINT_NAME_CACHE_PATH,
255 "the configuration file not configured field defaultNameCachePath and printNameCache");
256
257 ProjectNameCacheInfo merge;
258 MergeNameCache(merge);
259
260 std::string jsonStr = BuildJson(merge);
261 if (!defaultPath.empty()) {
262 FileUtil::WriteFile(defaultPath, jsonStr);
263 }
264
265 if (!printPath.empty()) {
266 FileUtil::WriteFile(printPath, jsonStr);
267 }
268 }
269
ParseAppliedNameCache(const std::string & content)270 void panda::guard::NameCache::ParseAppliedNameCache(const std::string &content)
271 {
272 JsonObject nameCacheObj(content);
273 PANDA_GUARD_ASSERT_PRINT(!nameCacheObj.IsValid(), TAG, ErrorCode::NAME_CACHE_FILE_FORMAT_ERROR,
274 "the name cache file is not a valid json");
275
276 for (size_t idx = 0; idx < nameCacheObj.GetSize(); idx++) {
277 auto key = nameCacheObj.GetKeyByIndex(idx);
278 if (key == ENTRY_PACKAGE_INFO) {
279 historyNameCache_.entryPackageInfo = JsonUtil::GetStringValue(&nameCacheObj, ENTRY_PACKAGE_INFO);
280 } else if (key == COMPILE_SDK_VERSION) {
281 historyNameCache_.compileSdkVersion = JsonUtil::GetStringValue(&nameCacheObj, COMPILE_SDK_VERSION);
282 } else if (key == PROPERTY_CACHE) {
283 historyNameCache_.propertyCacheMap = JsonUtil::GetMapStringValue(&nameCacheObj, PROPERTY_CACHE);
284 } else if (key == FILE_NAME_CACHE) {
285 historyNameCache_.fileNameCacheMap = JsonUtil::GetMapStringValue(&nameCacheObj, FILE_NAME_CACHE);
286 } else {
287 auto fileCacheInfoObj = JsonUtil::GetJsonObject(&nameCacheObj, key);
288 if (!fileCacheInfoObj) {
289 continue;
290 }
291 auto identifierCache = JsonUtil::GetMapStringValue(fileCacheInfoObj, IDENTIFIER_CACHE);
292 auto memberMethodCache = JsonUtil::GetMapStringValue(fileCacheInfoObj, MEMBER_METHOD_CACHE);
293
294 FileNameCacheInfo fileCacheInfo;
295 fileCacheInfo.identifierCacheMap = DeleteScopeAndLineNum(identifierCache);
296 fileCacheInfo.memberMethodCacheMap = DeleteScopeAndLineNum(memberMethodCache);
297 fileCacheInfo.obfName = JsonUtil::GetStringValue(fileCacheInfoObj, OBF_NAME);
298
299 historyNameCache_.fileCacheInfoMap.emplace(key, fileCacheInfo);
300 }
301 }
302 }
303
ParseHistoryNameCacheToUsedNames()304 void panda::guard::NameCache::ParseHistoryNameCacheToUsedNames()
305 {
306 AddHistoryUsedNames(historyNameCache_.entryPackageInfo);
307 AddHistoryUsedNames(historyNameCache_.compileSdkVersion);
308 AddHistoryUsedNames(historyNameCache_.propertyCacheMap);
309 AddHistoryUsedNames(historyNameCache_.fileNameCacheMap);
310 for (const auto &item : historyNameCache_.fileCacheInfoMap) {
311 AddHistoryUsedNames(item.second.identifierCacheMap);
312 AddHistoryUsedNames(item.second.memberMethodCacheMap);
313 AddHistoryUsedNames(item.second.obfName);
314 }
315 }
316
AddHistoryUsedNames(const std::string & value)317 void panda::guard::NameCache::AddHistoryUsedNames(const std::string &value)
318 {
319 historyUsedNames_.emplace(value);
320 }
321
AddHistoryUsedNames(const std::map<std::string,std::string> & values)322 void panda::guard::NameCache::AddHistoryUsedNames(const std::map<std::string, std::string> &values)
323 {
324 for (const auto &item : values) {
325 historyUsedNames_.emplace(item.second);
326 }
327 }
328
BuildJson(const ProjectNameCacheInfo & nameCacheInfo)329 std::string panda::guard::NameCache::BuildJson(const ProjectNameCacheInfo &nameCacheInfo)
330 {
331 JsonObjectBuilder builder;
332 for (const auto &item : nameCacheInfo.fileCacheInfoMap) {
333 builder.AddProperty(item.first, FileNameCacheToJson(item.second));
334 }
335 builder.AddProperty(ENTRY_PACKAGE_INFO, nameCacheInfo.entryPackageInfo);
336 builder.AddProperty(COMPILE_SDK_VERSION, nameCacheInfo.compileSdkVersion);
337
338 if (options_->IsPropertyObfEnabled()) {
339 builder.AddProperty(PROPERTY_CACHE, MapToJson(nameCacheInfo.propertyCacheMap, true));
340 }
341 if (options_->IsFileNameObfEnabled()) {
342 builder.AddProperty(FILE_NAME_CACHE, MapToJson(nameCacheInfo.fileNameCacheMap, true));
343 }
344 return std::move(builder).Build();
345 }
346