• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 "htrace_native_hook_parser.h"
16 #include "clock_filter.h"
17 #include "process_filter.h"
18 #include "stat_filter.h"
19 namespace SysTuning {
20 namespace TraceStreamer {
HtraceNativeHookParser(TraceDataCache * dataCache,const TraceStreamerFilters * ctx)21 HtraceNativeHookParser::HtraceNativeHookParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx)
22     : HtracePluginTimeParser(dataCache, ctx),
23       addrToAllocEventRow_(INVALID_UINT64),
24       addrToMmapEventRow_(INVALID_UINT64),
25       frameToFrameId_(INVALID_UINT64)
26 {
27     invalidLibPathIndexs_.insert(traceDataCache_->dataDict_.GetStringIndex("/system/lib/libc++.so"));
28     invalidLibPathIndexs_.insert(traceDataCache_->dataDict_.GetStringIndex("/system/lib64/libc++.so"));
29     invalidLibPathIndexs_.insert(traceDataCache_->dataDict_.GetStringIndex("/system/lib/ld-musl-aarch64.so.1"));
30     invalidLibPathIndexs_.insert(traceDataCache_->dataDict_.GetStringIndex("/system/lib/ld-musl-arm.so.1"));
31 }
32 
~HtraceNativeHookParser()33 HtraceNativeHookParser::~HtraceNativeHookParser()
34 {
35     TS_LOGI("native hook data ts MIN:%llu, MAX:%llu", static_cast<unsigned long long>(GetPluginStartTime()),
36             static_cast<unsigned long long>(GetPluginEndTime()));
37     TS_LOGI("native real ts MIN:%llu, MAX:%llu", static_cast<unsigned long long>(MinTs()),
38             static_cast<unsigned long long>(MaxTs()));
39 }
40 // In order to improve the accuracy of data, it is necessary to sort the original data.
41 // Data sorting will be reduced by 5% to 10% Speed of parsing data.
SortNativeHookData(BatchNativeHookData & tracePacket)42 void HtraceNativeHookParser::SortNativeHookData(BatchNativeHookData& tracePacket)
43 {
44     for (auto i = 0; i < tracePacket.events_size(); i++) {
45         auto nativeHookData = std::make_unique<NativeHookData>(*tracePacket.mutable_events(i));
46         auto timeStamp = nativeHookData->tv_nsec() + nativeHookData->tv_sec() * SEC_TO_NS;
47         tsNativeHookQueue_.insert(std::make_pair(timeStamp, std::move(nativeHookData)));
48         MaybeParseNativeHookData();
49     }
50     return;
51 }
52 template <class T1, class T2>
UpdateMap(std::unordered_map<T1,T2> & sourceMap,T1 key,T2 value)53 void HtraceNativeHookParser::UpdateMap(std::unordered_map<T1, T2>& sourceMap, T1 key, T2 value)
54 {
55     auto itor = sourceMap.find(key);
56     if (itor != sourceMap.end()) {
57         itor->second = value;
58     } else {
59         sourceMap.insert(std::make_pair(key, value));
60     }
61 }
MaybeParseNativeHookData()62 void HtraceNativeHookParser::MaybeParseNativeHookData()
63 {
64     if (tsNativeHookQueue_.size() > MAX_CACHE_SIZE) {
65         ParseNativeHookData(tsNativeHookQueue_.begin()->first, tsNativeHookQueue_.begin()->second.get());
66         tsNativeHookQueue_.erase(tsNativeHookQueue_.begin());
67     }
68 }
FinishParseNativeHookData()69 void HtraceNativeHookParser::FinishParseNativeHookData()
70 {
71     for (auto it = tsNativeHookQueue_.begin(); it != tsNativeHookQueue_.end(); it++) {
72         ParseNativeHookData(it->first, it->second.get());
73     }
74     if (traceDataCache_->GetNativeHookData()->Size() == 0) {
75         return;
76     }
77     traceDataCache_->GetNativeHookData()->UpdateMemMapSubType();
78     traceDataCache_->GetNativeHookFrameData()->UpdateSymbolId();
79     traceDataCache_->GetNativeHookFrameData()->UpdateFileId(filePathIdToFilePathName_);
80     std::map<uint64_t, uint64_t> callIdToLastCallerPathIndex;
81     traceDataCache_->GetNativeHookFrameData()->GetCallIdToLastLibId(invalidLibPathIndexs_,
82                                                                     callIdToLastCallerPathIndex);
83     if (callIdToLastCallerPathIndex.size()) {
84         traceDataCache_->GetNativeHookData()->UpdateLastCallerPathIndexs(callIdToLastCallerPathIndex);
85     }
86 
87     UpdateThreadNameWithNativeHookData();
88     tsNativeHookQueue_.clear();
89     threadNameIdToThreadName_.clear();
90     itidToThreadNameId_.clear();
91 }
ParseAllocEvent(uint64_t newTimeStamp,const NativeHookData * nativeHookData)92 void HtraceNativeHookParser::ParseAllocEvent(uint64_t newTimeStamp, const NativeHookData* nativeHookData)
93 {
94     auto allocEvent = nativeHookData->alloc_event();
95     auto itid = streamFilters_->processFilter_->GetOrCreateThreadWithPid(allocEvent.tid(), allocEvent.pid());
96     auto ipid = streamFilters_->processFilter_->GetInternalPid(allocEvent.pid());
97     if (allocEvent.thread_name_id() != 0) {
98         UpdateMap(itidToThreadNameId_, itid, allocEvent.thread_name_id());
99     }
100     auto callChainId = ParseNativeHookFrame(allocEvent.frame_info());
101     auto row = traceDataCache_->GetNativeHookData()->AppendNewNativeHookData(
102         callChainId, ipid, itid, allocEvent.GetTypeName(), INVALID_UINT64, newTimeStamp, 0, 0, allocEvent.addr(),
103         allocEvent.size(), allocEvent.size());
104     addrToAllocEventRow_.Insert(ipid, allocEvent.addr(), static_cast<uint64_t>(row));
105     MaybeUpdateCurrentSizeDur(row, newTimeStamp, true);
106 }
ParseFreeEvent(uint64_t newTimeStamp,const NativeHookData * nativeHookData)107 void HtraceNativeHookParser::ParseFreeEvent(uint64_t newTimeStamp, const NativeHookData* nativeHookData)
108 {
109     auto freeEvent = nativeHookData->free_event();
110     auto itid = streamFilters_->processFilter_->GetOrCreateThreadWithPid(freeEvent.tid(), freeEvent.pid());
111     auto ipid = streamFilters_->processFilter_->GetInternalPid(freeEvent.pid());
112     if (freeEvent.thread_name_id() != 0) {
113         UpdateMap(itidToThreadNameId_, itid, freeEvent.thread_name_id());
114     }
115     int64_t freeHeapSize = 0;
116     auto row = addrToAllocEventRow_.Find(ipid, freeEvent.addr());
117     if (row != INVALID_UINT64 && newTimeStamp > traceDataCache_->GetNativeHookData()->TimeStamData()[row]) {
118         addrToAllocEventRow_.Erase(ipid, freeEvent.addr());
119         traceDataCache_->GetNativeHookData()->UpdateHeapDuration(row, newTimeStamp);
120         freeHeapSize = traceDataCache_->GetNativeHookData()->MemSizes()[row];
121     } else if (row == INVALID_UINT64) {
122         TS_LOGW("func addr:%lu is empty", freeEvent.addr());
123         streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_FREE, STAT_EVENT_DATA_INVALID);
124         return;
125     }
126     auto callChainId = ParseNativeHookFrame(freeEvent.frame_info());
127     row = traceDataCache_->GetNativeHookData()->AppendNewNativeHookData(
128         callChainId, ipid, itid, freeEvent.GetTypeName(), INVALID_UINT64, newTimeStamp, 0, 0, freeEvent.addr(),
129         freeHeapSize, (-1) * freeHeapSize);
130     if (freeHeapSize != 0) {
131         MaybeUpdateCurrentSizeDur(row, newTimeStamp, true);
132     }
133 }
ParseMmapEvent(uint64_t newTimeStamp,const NativeHookData * nativeHookData)134 void HtraceNativeHookParser::ParseMmapEvent(uint64_t newTimeStamp, const NativeHookData* nativeHookData)
135 {
136     auto mMapEvent = nativeHookData->mmap_event();
137     auto itid = streamFilters_->processFilter_->GetOrCreateThreadWithPid(mMapEvent.tid(), mMapEvent.pid());
138     auto ipid = streamFilters_->processFilter_->GetInternalPid(mMapEvent.pid());
139     if (mMapEvent.thread_name_id() != 0) {
140         UpdateMap(itidToThreadNameId_, itid, mMapEvent.thread_name_id());
141     }
142     DataIndex subType = INVALID_UINT64;
143     if (!mMapEvent.type().empty()) {
144         subType = traceDataCache_->dataDict_.GetStringIndex(mMapEvent.type());
145         traceDataCache_->GetNativeHookData()->UpdateAddrToMemMapSubType(mMapEvent.addr(), mMapEvent.size(), subType);
146     }
147     auto callChainId = ParseNativeHookFrame(mMapEvent.frame_info());
148     auto row = traceDataCache_->GetNativeHookData()->AppendNewNativeHookData(
149         callChainId, ipid, itid, mMapEvent.GetTypeName(), subType, newTimeStamp, 0, 0, mMapEvent.addr(),
150         mMapEvent.size(), mMapEvent.size());
151     addrToMmapEventRow_.Insert(ipid, mMapEvent.addr(), static_cast<uint64_t>(row));
152     MaybeUpdateCurrentSizeDur(row, newTimeStamp, false);
153 }
ParseMunmapEvent(uint64_t newTimeStamp,const NativeHookData * nativeHookData)154 void HtraceNativeHookParser::ParseMunmapEvent(uint64_t newTimeStamp, const NativeHookData* nativeHookData)
155 {
156     auto mUnMapEvent = nativeHookData->munmap_event();
157     auto itid = streamFilters_->processFilter_->GetOrCreateThreadWithPid(mUnMapEvent.tid(), mUnMapEvent.pid());
158     auto ipid = streamFilters_->processFilter_->GetInternalPid(mUnMapEvent.pid());
159     if (mUnMapEvent.thread_name_id() != 0) {
160         UpdateMap(itidToThreadNameId_, itid, mUnMapEvent.thread_name_id());
161     }
162     auto row = addrToMmapEventRow_.Find(ipid, mUnMapEvent.addr());
163     int64_t effectiveMUnMapSize = 0;
164     if (row != INVALID_UINT64 && newTimeStamp > traceDataCache_->GetNativeHookData()->TimeStamData()[row]) {
165         addrToMmapEventRow_.Erase(ipid, mUnMapEvent.addr());
166         traceDataCache_->GetNativeHookData()->UpdateHeapDuration(row, newTimeStamp);
167         effectiveMUnMapSize = static_cast<int64_t>(mUnMapEvent.size());
168     } else if (row == INVALID_UINT64) {
169         TS_LOGW("func addr:%lu is empty", mUnMapEvent.addr());
170         streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_MUNMAP, STAT_EVENT_DATA_INVALID);
171         return;
172     }
173     auto callChainId = ParseNativeHookFrame(mUnMapEvent.frame_info());
174     row = traceDataCache_->GetNativeHookData()->AppendNewNativeHookData(
175         callChainId, ipid, itid, mUnMapEvent.GetTypeName(), INVALID_UINT64, newTimeStamp, 0, 0, mUnMapEvent.addr(),
176         mUnMapEvent.size(), (-1) * effectiveMUnMapSize);
177     if (effectiveMUnMapSize != 0) {
178         MaybeUpdateCurrentSizeDur(row, newTimeStamp, false);
179     }
180 }
ParseTagEvent(const NativeHookData * nativeHookData)181 void HtraceNativeHookParser::ParseTagEvent(const NativeHookData* nativeHookData)
182 {
183     auto memMapTagEvent = nativeHookData->tag_event();
184     auto addr = memMapTagEvent.addr();
185     auto size = memMapTagEvent.size();
186     auto tagIndex = traceDataCache_->dataDict_.GetStringIndex(memMapTagEvent.tag());
187     traceDataCache_->GetNativeHookData()->UpdateAddrToMemMapSubType(addr, static_cast<int64_t>(size), tagIndex);
188 }
ParseFileEvent(const NativeHookData * nativeHookData)189 void HtraceNativeHookParser::ParseFileEvent(const NativeHookData* nativeHookData)
190 {
191     auto filePathMapMessage = nativeHookData->file_path();
192     auto id = filePathMapMessage.id();
193     auto nameIndex = traceDataCache_->dataDict_.GetStringIndex(filePathMapMessage.name());
194     filePathIdToFilePathName_.insert(std::make_pair(id, nameIndex));
195 }
ParseSymbolEvent(const NativeHookData * nativeHookData)196 void HtraceNativeHookParser::ParseSymbolEvent(const NativeHookData* nativeHookData)
197 {
198     auto symbolMapMessage = nativeHookData->symbol_name();
199     auto id = symbolMapMessage.id();
200     auto nameIndex = traceDataCache_->dataDict_.GetStringIndex(symbolMapMessage.name());
201     traceDataCache_->GetNativeHookFrameData()->UpdateSymbolIdToNameMap(id, nameIndex);
202 }
ParseThreadEvent(const NativeHookData * nativeHookData)203 void HtraceNativeHookParser::ParseThreadEvent(const NativeHookData* nativeHookData)
204 {
205     auto threadNameMapMessage = nativeHookData->thread_name_map();
206     auto id = threadNameMapMessage.id();
207     auto nameIndex = traceDataCache_->dataDict_.GetStringIndex(threadNameMapMessage.name());
208     UpdateMap(threadNameIdToThreadName_, id, nameIndex);
209 }
210 
ParseNativeHookData(const uint64_t timeStamp,const NativeHookData * nativeHookData)211 void HtraceNativeHookParser::ParseNativeHookData(const uint64_t timeStamp, const NativeHookData* nativeHookData)
212 {
213     auto eventCase = nativeHookData->event_case();
214     uint64_t newTimeStamp = 0;
215     if (eventCase >= NativeHookData::kAllocEvent && eventCase <= NativeHookData::kMunmapEvent) {
216         newTimeStamp = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, timeStamp);
217         UpdatePluginTimeRange(TS_CLOCK_REALTIME, timeStamp, newTimeStamp);
218         switch (eventCase) {
219             case NativeHookData::kAllocEvent:
220                 streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_MALLOC, STAT_EVENT_RECEIVED);
221                 if (newTimeStamp == timeStamp) {
222                     streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_MALLOC, STAT_EVENT_DATA_INVALID);
223                 }
224                 ParseAllocEvent(newTimeStamp, nativeHookData);
225                 break;
226             case NativeHookData::kFreeEvent:
227                 streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_FREE, STAT_EVENT_RECEIVED);
228                 if (newTimeStamp == timeStamp) {
229                     streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_FREE, STAT_EVENT_DATA_INVALID);
230                 }
231                 ParseFreeEvent(newTimeStamp, nativeHookData);
232                 break;
233             case NativeHookData::kMmapEvent:
234                 streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_MMAP, STAT_EVENT_RECEIVED);
235                 if (newTimeStamp == timeStamp) {
236                     streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_MMAP, STAT_EVENT_DATA_INVALID);
237                 }
238                 ParseMmapEvent(newTimeStamp, nativeHookData);
239                 break;
240             case NativeHookData::kMunmapEvent:
241                 streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_MUNMAP, STAT_EVENT_RECEIVED);
242                 if (newTimeStamp == timeStamp) {
243                     streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_MUNMAP, STAT_EVENT_DATA_INVALID);
244                 }
245                 ParseMunmapEvent(newTimeStamp, nativeHookData);
246                 break;
247             default:
248                 TS_LOGE("An unknown type of data was received!");
249                 break;
250         }
251     } else {
252         switch (eventCase) {
253             case NativeHookData::kTagEvent:
254                 ParseTagEvent(nativeHookData);
255                 break;
256             case NativeHookData::kFilePath:
257                 ParseFileEvent(nativeHookData);
258                 break;
259             case NativeHookData::kSymbolName:
260                 ParseSymbolEvent(nativeHookData);
261                 break;
262             case NativeHookData::kThreadNameMap:
263                 ParseThreadEvent(nativeHookData);
264                 break;
265             default:
266                 TS_LOGE("An unknown type of data was received!");
267                 break;
268         }
269     }
270 }
MaybeUpdateCurrentSizeDur(uint64_t row,uint64_t timeStamp,bool isMalloc)271 void HtraceNativeHookParser::MaybeUpdateCurrentSizeDur(uint64_t row, uint64_t timeStamp, bool isMalloc)
272 {
273     auto& lastAnyEventRaw = isMalloc ? lastMallocEventRaw_ : lastMmapEventRaw_;
274     if (lastAnyEventRaw != INVALID_UINT64) {
275         traceDataCache_->GetNativeHookData()->UpdateCurrentSizeDur(lastAnyEventRaw, timeStamp);
276     }
277     lastAnyEventRaw = row;
278 }
ParseNativeHookFrame(const RepeatedPtrField<::Frame> & repeatedFrame)279 uint64_t HtraceNativeHookParser::ParseNativeHookFrame(const RepeatedPtrField<::Frame>& repeatedFrame)
280 {
281     // the callstack from nativehook of sourcedata is reverse order
282     // we need to show the last frame firstly
283     std::vector<std::unique_ptr<NativeHookFrameTemp>> callStackTemp = {};
284     auto depth = 0;
285     for (auto i = repeatedFrame.size() - 1; i >= 0; i--) {
286         auto frame = repeatedFrame.Get(i);
287         DataIndex symbolNameIndex = INVALID_UINT64;
288         DataIndex filePathIndex = INVALID_UINT64;
289         if (!frame.symbol_name().empty()) {
290             symbolNameIndex = traceDataCache_->dataDict_.GetStringIndex(frame.symbol_name().c_str());
291             traceDataCache_->GetNativeHookFrameData()->UpdateSymbolIdToNameMap(symbolNameIndex, symbolNameIndex);
292         } else if (frame.symbol_name_id()) {
293             symbolNameIndex = frame.symbol_name_id();
294         }
295         if (!frame.file_path().empty()) {
296             filePathIndex = traceDataCache_->dataDict_.GetStringIndex(frame.file_path().c_str());
297             filePathIdToFilePathName_.insert(std::make_pair(filePathIndex, filePathIndex));
298         } else if (frame.file_path_id()) {
299             filePathIndex = frame.file_path_id();
300         }
301         callStackTemp.emplace_back(std::move(std::make_unique<NativeHookFrameTemp>(
302             filePathIndex, symbolNameIndex, depth, frame.offset(), frame.symbol_offset())));
303         depth++;
304     }
305 
306     // Determine whether to write callstack data to cache
307     auto callChainId = INVALID_UINT64;
308     bool callStackNotExist = false;
309     auto size = callStackTemp.size();
310     for (auto itor = callStackTemp.begin(); itor != callStackTemp.end(); itor++) {
311         auto callstack = itor->get();
312         auto ret = frameToFrameId_.Find(callstack->fileId_, callstack->symbolId_, callstack->depth_, size);
313         if (ret != INVALID_UINT64) { // find it
314             if (callChainId == INVALID_UINT64) {
315                 callChainId = ret;
316             } else if (callChainId != ret) {
317                 callStackNotExist = true;
318                 break;
319             }
320         } else { // not find it
321             callStackNotExist = true;
322             break;
323         }
324     }
325     // write callstack data to cache
326     if (callStackNotExist) {
327         callChainId = ++callChainId_;
328         for (auto itor = callStackTemp.begin(); itor != callStackTemp.end(); itor++) {
329             auto callstack = itor->get();
330             frameToFrameId_.Insert(callstack->fileId_, callstack->symbolId_, callstack->depth_, callStackTemp.size(),
331                                    callChainId);
332             traceDataCache_->GetNativeHookFrameData()->AppendNewNativeHookFrame(
333                 callChainId, callstack->depth_, callstack->ip_, callstack->sp_,
334                 callstack->symbolId_, callstack->fileId_, callstack->offset_, callstack->symbolOffset_);
335         }
336     }
337     callStackTemp.clear();
338     return callChainId;
339 }
UpdateThreadNameWithNativeHookData() const340 void HtraceNativeHookParser::UpdateThreadNameWithNativeHookData() const
341 {
342     if (itidToThreadNameId_.empty() || threadNameIdToThreadName_.empty()) {
343         return;
344     }
345     for (auto itor = itidToThreadNameId_.begin(); itor != itidToThreadNameId_.end(); ++itor) {
346         auto thread = traceDataCache_->GetThreadData(itor->first);
347         if (thread->nameIndex_ == 0) {
348             auto threadNameMapItor = threadNameIdToThreadName_.find(itor->second);
349             if (threadNameMapItor != threadNameIdToThreadName_.end()) {
350                 thread->nameIndex_ = threadNameMapItor->second;
351             }
352         }
353     }
354 }
Finish()355 void HtraceNativeHookParser::Finish()
356 {
357     traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginEndTime());
358 }
359 } // namespace TraceStreamer
360 } // namespace SysTuning
361