• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved.
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 #ifndef STACK_PREPROCESS_H
16 #define STACK_PREPROCESS_H
17 
18 #include <chrono>
19 #include <thread>
20 #include <unordered_map>
21 #include <list>
22 #include <algorithm>
23 #include <mutex>
24 #include <variant>
25 #include <numeric>
26 #include "hook_record_factory.h"
27 #include "hook_record.h"
28 #include "logging.h"
29 #include "nocopyable.h"
30 #include "stack_data_repeater.h"
31 #include "buffer_writer.h"
32 #include "virtual_runtime.h"
33 #include "hook_common.h"
34 #include "native_hook_config.pb.h"
35 #include "native_hook_result.pb.h"
36 #include "native_hook_result.pbencoder.h"
37 #include "safe_map.h"
38 #include "schedule_task_manager.h"
39 #include "common.h"
40 #include "stack_builder.h"
41 
42 namespace OHOS::Developtools::NativeDaemon {
43 using WriterStructPtr = std::unique_ptr<WriterStruct>::pointer;
44 
45 struct RecordStatistic {
46     uint32_t pid {0};
47     uint32_t callstackId {0};
48     uint32_t tagId {0};
49     RecordStatisticsEvent::MemoryType type {RecordStatisticsEvent::MALLOC};
50     uint64_t applyCount {0};
51     uint64_t releaseCount {0};
52     uint64_t applySize {0};
53     uint64_t releaseSize {0};
54 };
55 
56 struct CallStackHash {
operatorCallStackHash57     uint64_t operator()(const std::vector<uint64_t>& stack) const
58     {
59         return std::accumulate(stack.begin(), stack.end(), 0);
60     }
61 };
62 
63 
64 class StackPreprocess : public std::enable_shared_from_this<StackPreprocess> {
65 public:
66     explicit StackPreprocess(const StackDataRepeaterPtr& dataRepeater, const NativeHookConfig& hookConfig,
67         clockid_t pluginDataClockId, FILE* fpHookData = nullptr, bool isHookStandalone = false,
68         bool isSaService = false, bool isProtobufSerialize = true);
69     ~StackPreprocess();
70     void SetWriter(const std::shared_ptr<Writer>& writer);
71     void SetWriter(const WriterStructPtr& writer);
SetFactory(std::shared_ptr<HookRecordFactory> factory)72     void SetFactory(std::shared_ptr<HookRecordFactory> factory)
73     {
74         factory_ = factory;
75     }
76     bool StartTakeResults();
77     bool StopTakeResults();
78     void FinishTraceFile();
79     bool FlushRecordStatistics();
80     void FlushRecordApplyAndReleaseMatchData();
81     void ForceStop();
SetPid(int32_t pid)82     inline void SetPid(int32_t pid)
83     {
84         pid_ = pid;
85     }
InitStatisticsTime()86     inline void InitStatisticsTime()
87     {
88         lastStatisticsTime_ = std::chrono::steady_clock::now();
89     }
90     void SaveMemTag(uint32_t tagId, const std::string& tagName);
91     bool GetMemTag(uint32_t tagId, std::string& tagName);
92     void SaveJsRawStack(uint64_t jsChainId, const char* jsRawStack);
93     const char* GetJsRawStack(uint64_t jsChainId);
94     void ReportBasicData();
95     void WriteHookConfig();
96     void TakeResultsFromShmem(const std::shared_ptr<EventNotifier>&, const std::shared_ptr<ShareMemoryBlock>&);
SetNmdFd(uint32_t fd)97     void SetNmdFd(uint32_t fd)
98     {
99         nmdFd_ = fd;
100     }
SetFlushSize(uint64_t size)101     void SetFlushSize(uint64_t size)
102     {
103         double tenth = static_cast<double>(size) / 10.0;
104         flushSize_ = static_cast<uint64_t>(std::ceil(tenth));
105         PROFILER_LOG_INFO(LOG_CORE, "SetFlushSize size: %" PRIu64 ", flushSize_: %" PRIu64 "", size, flushSize_);
106         if (isProtobufSerialize_) {
107             bufferSize_ = flushSize_ << 1;
108             buffer_ = std::make_unique<uint8_t[]>(bufferSize_);
109         }
110     }
111 
112 private:
113     using CallFrame = OHOS::Developtools::NativeDaemon::CallFrame;
114     struct ElfSymbolTable {
115         uint64_t textVaddr;
116         uint32_t textOffset;
117         uint32_t symEntSize;
118         std::vector<uint8_t> strTable;
119         std::vector<uint8_t> symTable;
120     };
121 
122     enum RecordStatisticsLimit : std::size_t {
123         STATISTICS_MAP_SZIE = 100000,
124         STATISTICS_PERIOD_DATA_SIZE = 100000,
125         ALLOC_ADDRMAMP_SIZE = 100000,
126         MATCH_ADDRMAMP_SIZE = 100000,
127     };
128 
129     struct ScopedLockFile {
ScopedLockFileScopedLockFile130         ScopedLockFile(FILE* fpHook): fpHookData(fpHook)
131         {
132             flockfile(fpHookData);
133         }
~ScopedLockFileScopedLockFile134         ~ScopedLockFile()
135         {
136             funlockfile(fpHookData);
137         }
138         FILE* fpHookData {nullptr};
139     };
140 
141 private:
142     void TakeResults();
143     template <typename T>
144     void SetHookData(HookRecordPtr hookRecord, T& stackData);
145     template <typename T>
146     void SetHookData(HookRecordPtr hookRecord, std::vector<CallFrame>& callFrames, T& stackData);
147     void WriteFrames(HookRecordPtr hookRecord, const std::vector<CallFrame>& callFrames);
148     template <typename T>
149     void SetFrameInfo(T& frame, CallFrame& callFrame);
150     template <typename T>
151     void ReportSymbolNameMap(CallFrame& callFrame, T& stackData);
152     template <typename T>
153     void ReportFilePathMap(CallFrame& callFrame, T& stackData);
154     template <typename T>
155     void ReportFrameMap(CallFrame& callFrame, T& stackData);
156     void ReportThreadNameMap(uint32_t tid, const std::string& tname);
157     void SetMapsInfo();
158     template <typename T>
159     void SetSymbolInfo(uint32_t filePathId, ElfSymbolTable& symbolInfo, T& batchNativeHookData);
160     template <typename T>
161     void FlushCheck(T& stackData);
162     void FlushData(BatchNativeHookData& stackData);
163     void FlushData(OHOS::Developtools::Profiler::ProtoEncoder::BatchNativeHookData& stackData);
164     void Flush(const uint8_t* src, size_t size);
165     void GetSymbols(const std::string& filePath, ElfSymbolTable& symbols);
166     template <typename T>
167     void FillOfflineCallStack(std::vector<CallFrame>& callFrames, size_t idx, T& stackData);
168     template <typename T>
169     void FillCallStack(std::vector<CallFrame>& callFrames, size_t idx, T& stackData);
170     template <typename T>
171     uint32_t SetCallStackMap(T& stackData);
172     template <typename T>
173     uint32_t GetCallStackId(const HookRecordPtr& hookRecord, std::vector<CallFrame>& callFrames, T& stackData);
174     uint32_t FindCallStackId(std::vector<uint64_t>& callStack);
175     template <typename T>
176     void SetEventFrame(const RawStackPtr& rawStack, std::vector<CallFrame>& callFrames,
177         T* event, uint32_t stackId, const std::string& type = "");
178     template <typename T>
179     void SetEventFrame(const ReportEventBaseData& rawStack, T* event, uint32_t stackMapId,
180                        const std::string& type = "");
181     template <typename T>
182     void SetAllocStatisticsFrame(const HookRecordPtr& hookRecord, std::vector<CallFrame>& callFrames, T& stackData);
183     template <typename T>
184     void SetAllocStatisticsFrame(const HookRecordPtr& hookRecord, T& stackData);
185     template <typename T>
186     void SetApplyAndReleaseMatchFrame(HookRecordPtr hookRecord, std::vector<CallFrame>& callFrames, T& stackData);
187     void IntervalFlushRecordStatistics();
188     void IntervalFlushApplyAndReleaseMatchData();
189     bool HandleNoStackEvent(HookRecordPtr& hookRecord);
190     bool SetFreeStatisticsData(uint64_t addr);
191     void SetAllocStatisticsData(const HookRecordPtr& hookRecord, size_t stackId, bool isExists = false);
192     unsigned LgFloor(unsigned long x);
193     uint64_t PowCeil(uint64_t x);
194     void ReportOfflineSymbolizationData();
195 
196     RandomWriteCtx* StartReport();
197     int32_t FinishReport();
198     void FillNapiStack(std::string& tagName, std::vector<CallFrame>& callFrames, uint64_t napiIndex);
199 private:
200     std::chrono::steady_clock::time_point lastStatisticsTime_ = std::chrono::steady_clock::now();
201     std::shared_ptr<Writer> writer_ = nullptr;
202     StackDataRepeaterPtr dataRepeater_ = nullptr;
203     std::thread thread_ {};
204     std::unique_ptr<uint8_t[]> buffer_;
205     std::atomic_bool isStopTakeData_ = false;
206     std::shared_ptr<OHOS::Developtools::NativeDaemon::VirtualRuntime> runtime_instance;
207     DISALLOW_COPY_AND_MOVE(StackPreprocess);
208     OHOS::SafeMap<uint32_t, std::string> memTagMap_ = {};
209     std::unordered_map<uint32_t, std::string> threadNameMap_ = {};
210     NativeHookConfig hookConfig_;
211     uint32_t ignoreCnts_ = 0;
212     uint32_t eventCnts_ = 0;
213     bool flushBasicData_ {true};
214     std::vector<u64> u64regs_;
215     // Key is callStack_, value is call stack id
216     std::unordered_map<std::vector<uint64_t>, uint32_t, CallStackHash> callStackMap_;
217     std::chrono::seconds statisticsInterval_ {0};
218     // Key is call stack id, value is recordstatistic data
219     std::unordered_map<uint32_t, RecordStatistic> recordStatisticsMap_;
220     // Key is call stack id, value is recordstatistic data pointer
221     std::unordered_map<uint32_t, RecordStatistic*> statisticsPeriodData_;
222     // Key is alloc or mmap address, value is ReportEventBaseData list iterator
223     std::unordered_map<uint64_t, std::list<ReportEventBaseData>::iterator> applyAndReleaseMatchIntervallMap_;
224     std::list<ReportEventBaseData> applyAndReleaseMatchPeriodListData_;
225     std::list<ReportEventBaseData> releasedPeriodListData_;
226     std::chrono::seconds applyAndReleaseMatchInterval_{0};
227     // used for plugin data
228     clockid_t pluginDataClockId_ = CLOCK_REALTIME;
229     // used for clac wait time in StackDataRepeater::TakeRawData() or statistics HookData
230     clockid_t hookDataClockId_ = CLOCK_REALTIME;
231     FILE* fpHookData_ {nullptr};
232     bool isHookStandaloneSerialize_ {false};
233     int32_t pid_ {-1};
234     std::mutex mtx_;
235     std::mutex memTagMtx_;
236     std::mutex jsMapMtx_;
237     COMMON::SpinLock spinLock_;
238     bool isSaService_{false};
239     std::mutex allocAddrMapMtx_;
240     bool isProtobufSerialize_{true};
241     WriterStructPtr resultWriter_{nullptr};
242     std::variant<BatchNativeHookData, OHOS::Developtools::Profiler::ProtoEncoder::BatchNativeHookData> stackData_;
243     uint64_t flushSize_{0};
244     uint64_t bufferSize_{0};
245     bool statisticsModelFlushCallstack_{false};
246     OHOS::Developtools::Profiler::ProtoEncoder::ProfilerPluginData profilerPluginData_;
247     // Key is js stack id , value is js raw stack pointer
248     std::map<uint64_t, const char*> jsStackMap_ = {};
249     std::set<std::string> jsStackSet_ = {};
250     bool unwindFailReport_ = true;
251     std::vector<std::string> prctlPeriodTags_; // applyAndReleaseMatchInterval mode used
252     std::atomic<uint64_t> napiIndex_{1};
253     std::atomic<int> endMsgCount_ {0};
254     ScheduleTaskManager scheduleTaskManager_;
255     uint32_t nmdFd_ = 0;
256     uint32_t dataFlushSize_ = 0;
257     std::shared_ptr<HookRecordFactory> factory_{nullptr};
258 };
259 }
260 
261 #endif // STACK_PREPROCESS_H