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