• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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