• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2021-2023. 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 
16 #include "hook_manager.h"
17 
18 #include <limits>
19 #include <sys/stat.h>
20 #include <unistd.h>
21 #include <cstdlib>
22 #include "command_poller.h"
23 #include "common.h"
24 #include "epoll_event_poller.h"
25 #include "event_notifier.h"
26 #include "hook_common.h"
27 #include "hook_service.h"
28 #include "init_param.h"
29 #include "logging.h"
30 #include "plugin_service_types.pb.h"
31 #include "share_memory_allocator.h"
32 #include "utilities.h"
33 #include "virtual_runtime.h"
34 #include "native_memory_profiler_sa_service.h"
35 #include "hook_record.h"
36 #include "hook_record_factory.h"
37 
38 namespace OHOS::Developtools::NativeDaemon {
39 namespace {
40 constexpr int DEFAULT_EVENT_POLLING_INTERVAL = 5000;
41 constexpr uint32_t PAGE_BYTES = 4096;
42 std::shared_ptr<Writer> g_buffWriter;
43 const std::string STARTUP = "startup:";
44 const std::string PARAM_NAME = "libc.hook_mode";
45 const std::string PRODUCT_CONFIG_PATH = "/sys_prod/etc/hiview/hiprofiler/hiprofiler_cfg.json";
46 constexpr int SIGNAL_START_HOOK = 36;
47 const std::string VERSION = "1.02";
48 constexpr int32_t RESPONSE_MAX_PID_COUNT = 8;
49 constexpr int32_t ONLY_NMD_TYPE = 2;
50 constexpr int32_t SIMP_NMD = 3;
51 constexpr int DOUBLE = 2;
52 static thread_local std::array<std::shared_ptr<HookRecord>, CACHE_ARRAY_SIZE> g_rawDataArray = {};
53 static thread_local uint32_t g_rawStackCount = 0;
54 }
55 
~HookManager()56 HookManager::~HookManager()
57 {
58     hookService_ = nullptr;
59     for (const auto& item : hookCtx_) {
60         for (size_t i = 0; i < item->shareMemoryBlockList.size(); ++i) {
61             item->shareMemoryBlockList[i] = nullptr;
62         }
63         for (size_t i = 0; i < item->eventPollerList.size(); ++i) {
64             item->eventPollerList[i] = nullptr;
65         }
66         if (item->stackPreprocess != nullptr) {
67             item->stackPreprocess = nullptr;
68         }
69         if (item->stackData != nullptr) {
70             item->stackData = nullptr;
71         }
72     }
73 }
74 
CheckProcess()75 bool HookManager::CheckProcess()
76 {
77     if (hookConfig_.pid() > 0) {
78         hookConfig_.add_expand_pids(hookConfig_.pid());
79     }
80     std::set<int32_t> pidCache;
81     for (const auto& pid : hookConfig_.expand_pids()) {
82         if (pid > 0) {
83             struct stat statBuf;
84             std::string pidPath = "/proc/" + std::to_string(pid) + "/status";
85             if (stat(pidPath.c_str(), &statBuf) != 0) {
86                 PROFILER_LOG_ERROR(LOG_CORE, "%s: hook process does not exist", __func__);
87                 return false;
88             } else {
89                 auto [iter, isExist] = pidCache.emplace(pid);
90                 if (isExist) {
91                     hookCtx_.emplace_back(std::make_shared<HookManagerCtx>(pid));
92                     PROFILER_LOG_INFO(LOG_CORE, "hook context: pid: %d", pid);
93                 }
94                 continue;
95             }
96         }
97     }
98 
99     if (!hookConfig_.process_name().empty() && !CheckProcessName()) {
100         return false;
101     }
102 
103     if (hookConfig_.response_library_mode()) {
104         if (hookCtx_.size() > RESPONSE_MAX_PID_COUNT) {
105             PROFILER_LOG_ERROR(LOG_CORE, "%s: The maximum allowed is to set %d PIDs.",
106                                __func__, RESPONSE_MAX_PID_COUNT);
107             return false;
108         }
109     } else {
110         auto maxPidCount = GetValueFromJsonFile(PRODUCT_CONFIG_PATH, "hiprofiler_hook_process_count");
111         maxProcessCount_ = maxPidCount > 0 ? maxPidCount : maxProcessCount_;
112         if (hookCtx_.size() > static_cast<size_t>(maxProcessCount_)) {
113             PROFILER_LOG_ERROR(LOG_CORE, "%s: The maximum allowed is to set %d PIDs.", __func__, maxProcessCount_);
114             return false;
115         }
116     }
117 
118     if (hookCtx_.size() > 1) {
119         isProtobufSerialize_ = true;
120     }
121     return true;
122 }
123 
CheckProcessName()124 bool HookManager::CheckProcessName()
125 {
126     int pidValue = -1;
127     const std::string processName = hookConfig_.process_name();
128     bool isExist = COMMON::IsProcessExist(processName, pidValue);
129     if (hookConfig_.startup_mode() || !isExist) {
130         PROFILER_LOG_INFO(LOG_CORE, "Wait process %s start or restart, set param", hookConfig_.process_name().c_str());
131         std::string cmd = STARTUP + hookConfig_.process_name();
132         int ret = SystemSetParameter(PARAM_NAME.c_str(), cmd.c_str());
133         if (ret < 0) {
134             PROFILER_LOG_ERROR(LOG_CORE, "set param failed, please manually set param and start process(%s)",
135                                hookConfig_.process_name().c_str());
136         } else {
137             PROFILER_LOG_INFO(LOG_CORE, "set param success, please start process(%s)",
138                               hookConfig_.process_name().c_str());
139             hookCtx_.emplace_back(std::make_shared<HookManagerCtx>(hookConfig_.process_name()));
140             hookConfig_.set_startup_mode(true);
141         }
142     } else if (pidValue != -1) {
143         PROFILER_LOG_INFO(LOG_CORE, "Process %s exist, pid = %d", hookConfig_.process_name().c_str(), pidValue);
144         for (const auto& item : hookCtx_) {
145             if (item->pid == pidValue) {
146                 return true;
147             }
148         }
149         hookCtx_.emplace_back(std::make_shared<HookManagerCtx>(pidValue));
150     } else {
151         PROFILER_LOG_ERROR(LOG_CORE, "The startup mode parameter is not set, name: %s",
152                            hookConfig_.process_name().c_str());
153         return false;
154     }
155     return true;
156 }
157 
SetCommandPoller(const std::shared_ptr<CommandPoller> & p)158 void HookManager::SetCommandPoller(const std::shared_ptr<CommandPoller>& p)
159 {
160     commandPoller_ = p;
161 }
162 
RegisterAgentPlugin(const std::string & pluginPath)163 bool HookManager::RegisterAgentPlugin(const std::string& pluginPath)
164 {
165     RegisterPluginRequest request;
166     request.set_request_id(commandPoller_->GetRequestId());
167     request.set_path(pluginPath);
168     request.set_sha256("");
169     request.set_name(pluginPath);
170     request.set_buffer_size_hint(0);
171     RegisterPluginResponse response;
172 
173     if (commandPoller_->RegisterPlugin(request, response)) {
174         if (response.status() == ResponseStatus::OK) {
175             PROFILER_LOG_DEBUG(LOG_CORE, "response.plugin_id() = %d", response.plugin_id());
176             agentIndex_ = response.plugin_id();
177             PROFILER_LOG_DEBUG(LOG_CORE, "RegisterPlugin OK");
178         } else {
179             PROFILER_LOG_DEBUG(LOG_CORE, "RegisterPlugin FAIL 1");
180             return false;
181         }
182     } else {
183         PROFILER_LOG_DEBUG(LOG_CORE, "RegisterPlugin FAIL 2");
184         return false;
185     }
186 
187     return true;
188 }
189 
UnregisterAgentPlugin(const std::string & pluginPath)190 bool HookManager::UnregisterAgentPlugin(const std::string& pluginPath)
191 {
192     UnregisterPluginRequest request;
193     request.set_request_id(commandPoller_->GetRequestId());
194     request.set_plugin_id(agentIndex_);
195     UnregisterPluginResponse response;
196     if (commandPoller_->UnregisterPlugin(request, response)) {
197         CHECK_TRUE(response.status() == ResponseStatus::OK, false, "UnregisterPlugin FAIL 1");
198     } else {
199         PROFILER_LOG_DEBUG(LOG_CORE, "UnregisterPlugin FAIL 2");
200         return false;
201     }
202     agentIndex_ = -1;
203 
204     return true;
205 }
206 
LoadPlugin(const std::string & pluginPath)207 bool HookManager::LoadPlugin(const std::string& pluginPath)
208 {
209     return true;
210 }
211 
UnloadPlugin(const std::string & pluginPath)212 bool HookManager::UnloadPlugin(const std::string& pluginPath)
213 {
214     return true;
215 }
216 
UnloadPlugin(const uint32_t pluginId)217 bool HookManager::UnloadPlugin(const uint32_t pluginId)
218 {
219     return true;
220 }
221 
GetClientConfig(ClientConfig & clientConfig)222 void HookManager::GetClientConfig(ClientConfig& clientConfig)
223 {
224     int sharedMemCount = (hookConfig_.offline_symbolization()) ? SHARED_MEMORY_NUM : 1;
225     clientConfig.shareMemorySize = (static_cast<uint32_t>(hookConfig_.smb_pages()) / sharedMemCount) * PAGE_BYTES;
226     clientConfig.filterSize = static_cast<int32_t>(hookConfig_.filter_size());
227     clientConfig.clockId = COMMON::GetClockId(hookConfig_.clock());
228     clientConfig.maxStackDepth = hookConfig_.max_stack_depth();
229     clientConfig.arktsConfig.maxJsStackDepth = hookConfig_.max_js_stack_depth();
230     clientConfig.mallocDisable = hookConfig_.malloc_disable();
231     clientConfig.mmapDisable = hookConfig_.mmap_disable();
232     clientConfig.freeStackData = hookConfig_.free_stack_report();
233     clientConfig.munmapStackData = hookConfig_.munmap_stack_report();
234     clientConfig.fpunwind = hookConfig_.fp_unwind();
235     clientConfig.arktsConfig.jsFpunwind = hookConfig_.fp_unwind();
236     clientConfig.isBlocked = hookConfig_.blocked();
237     clientConfig.memtraceEnable = hookConfig_.memtrace_enable();
238     clientConfig.statisticsInterval = hookConfig_.statistics_interval();
239     clientConfig.sampleInterval = hookConfig_.sample_interval();
240     clientConfig.offlineSymbolization = hookConfig_.offline_symbolization();
241     clientConfig.responseLibraryMode = hookConfig_.response_library_mode();
242     clientConfig.arktsConfig.jsStackReport = hookConfig_.js_stack_report();
243     printMallocNmd_ = hookConfig_.dump_nmd() ? hookConfig_.dump_nmd() : printMallocNmd_;
244     clientConfig.nmdType = (printMallocNmd_ && hookConfig_.dump_nmd()) ? ONLY_NMD_TYPE :
245         static_cast<int>(nmdParamInfo_.type);
246     const std::string& soName = hookConfig_.target_so_name();
247     if (soName.length() < PATH_MAX && !COMMON::ContainsSpecialChars(soName)) {
248         clientConfig.targetSoName = hookConfig_.target_so_name();
249     }
250     clientConfig.printNmd = printMallocNmd_;
251     clientConfig.largestSize = largestSize_;
252     clientConfig.secondLargestSize = secondLargestSize_;
253     clientConfig.maxGrowthSize = maxGrowthSize_;
254     // -1 is save '\0'
255     int ret = memcpy_s(clientConfig.arktsConfig.filterNapiName, sizeof(clientConfig.arktsConfig.filterNapiName) - 1,
256                        hookConfig_.filter_napi_name().c_str(), hookConfig_.filter_napi_name().size());
257     if (ret != EOK) {
258         PROFILER_LOG_ERROR(LOG_CORE, "memcpy_s filter_napi_name fail");
259     }
260 }
261 
HandleHookContext(const std::shared_ptr<HookManagerCtx> & ctx)262 bool HookManager::HandleHookContext(const std::shared_ptr<HookManagerCtx>& ctx)
263 {
264     if (ctx == nullptr) {
265         return false;
266     }
267 
268     // create smb and eventNotifier
269     int sharedMemCount = (hookConfig_.offline_symbolization()) ? SHARED_MEMORY_NUM : 1;
270     uint32_t bufferSize = (static_cast<uint32_t>(hookConfig_.smb_pages()) / sharedMemCount) * PAGE_BYTES;
271 
272     for (int i = 0; i < sharedMemCount; ++i) {
273         std::string smbName = "";
274         if (ctx->pid > 0) {
275             smbName = "hooknativesmb_" + std::to_string(ctx->pid) + ":" + std::to_string(i);
276         } else if (!ctx->processName.empty()) {
277             smbName = "hooknativesmb_" + ctx->processName + ":" + std::to_string(i);
278         } else {
279             PROFILER_LOG_ERROR(LOG_CORE, "HandleHookContext context error, pid: %d, process name: %s",
280                 ctx->pid, ctx->processName.c_str());
281             return false;
282         }
283         ctx->smbNames.push_back(smbName);
284         auto shareMemoryBlock = ShareMemoryAllocator::GetInstance().CreateMemoryBlockLocal(smbName, bufferSize);
285         CHECK_TRUE(shareMemoryBlock != nullptr, false, "CreateMemoryBlockLocal FAIL %s", smbName.c_str());
286         ctx->shareMemoryBlockList.push_back(shareMemoryBlock);
287         auto eventNotifier = EventNotifier::Create(0, EventNotifier::NONBLOCK);
288         CHECK_NOTNULL(eventNotifier, false, "create EventNotifier for %s failed!", smbName.c_str());
289         ctx->eventNotifierList.push_back(eventNotifier);
290         PROFILER_LOG_INFO(LOG_CORE, "hookservice smbFd = %d, eventFd = %d\n", shareMemoryBlock->GetfileDescriptor(),
291                           eventNotifier->GetFd());
292         // start event poller task
293         auto eventPoller = std::make_shared<EpollEventPoller>(DEFAULT_EVENT_POLLING_INTERVAL);
294         CHECK_NOTNULL(eventPoller, false, "create event poller FAILED!");
295 
296         eventPoller->Init();
297         eventPoller->Start();
298         ctx->eventPollerList.push_back(eventPoller);
299     }
300 
301     ctx->isRecordAccurately = hookConfig_.record_accurately();
302     PROFILER_LOG_INFO(LOG_CORE, "hookConfig filter size = %d, malloc disable = %d mmap disable = %d",
303         hookConfig_.filter_size(), hookConfig_.malloc_disable(), hookConfig_.mmap_disable());
304     PROFILER_LOG_INFO(LOG_CORE, "hookConfig fp unwind = %d, max stack depth = %d, record_accurately=%d",
305         hookConfig_.fp_unwind(), hookConfig_.max_stack_depth(), ctx->isRecordAccurately);
306     PROFILER_LOG_INFO(LOG_CORE, "hookConfig  offline_symbolization = %d", hookConfig_.offline_symbolization());
307     PROFILER_LOG_INFO(LOG_CORE, "hookConfig  js_stack_report = %d max_js_stack_depth = %u",
308         hookConfig_.js_stack_report(), hookConfig_.max_js_stack_depth());
309 
310     clockid_t pluginDataClockId = COMMON::GetClockId(hookConfig_.clock());
311     if (noDataQueue_) {
312         ctx->stackPreprocess = std::make_shared<StackPreprocess>(nullptr, hookConfig_, pluginDataClockId,
313             fpHookData_, isHookStandalone_, isSaService_, isProtobufSerialize_);
314         ctx->stackPreprocess->SetFlushSize(shareMemorySize_);
315         ctx->stackPreprocess->SetNmdFd(nmdParamInfo_.fd);
316         for (int i = 0; i < sharedMemCount; ++i) {
317             ctx->eventPollerList[i]->AddFileDescriptor(
318                 ctx->eventNotifierList[i]->GetFd(),
319                 std::bind(&StackPreprocess::TakeResultsFromShmem, ctx->stackPreprocess,
320                 ctx->eventNotifierList[i], ctx->shareMemoryBlockList[i]));
321         }
322     } else {
323         ctx->stackData = std::make_shared<StackDataRepeater>(STACK_DATA_SIZE);
324         CHECK_TRUE(ctx->stackData != nullptr, false, "Create StackDataRepeater FAIL");
325         ctx->stackPreprocess = std::make_shared<StackPreprocess>(ctx->stackData, hookConfig_, pluginDataClockId,
326             fpHookData_, isHookStandalone_, isSaService_, isProtobufSerialize_);
327         ctx->stackPreprocess->SetFlushSize(shareMemorySize_);
328         for (int i = 0; i < sharedMemCount; ++i) {
329             ctx->eventPollerList[i]->AddFileDescriptor(
330                 ctx->eventNotifierList[i]->GetFd(),
331                 [this, &ctx, i] { this->ReadShareMemory(ctx, i); });
332         }
333     }
334     if (isProtobufSerialize_ || isSaService_) {
335         ctx->stackPreprocess->SetWriter(g_buffWriter);
336     } else {
337         ctx->stackPreprocess->SetWriter(const_cast<WriterStructPtr>(writerAdapter_->GetStruct()));
338     }
339     ctx->stackPreprocess->SetFactory(factory_);
340     return true;
341 }
342 
CheckHapEncryped()343 void HookManager::CheckHapEncryped()
344 {
345     for (const auto& pid : hookConfig_.expand_pids()) {
346         if (pid > 0 && COMMON::CheckApplicationEncryped(pid, "")) {
347             hookConfig_.set_js_stack_report(0);
348             hookConfig_.set_max_js_stack_depth(0);
349             break;
350         }
351     }
352     const std::string processName = hookConfig_.process_name();
353     if (!processName.empty() && COMMON::CheckApplicationEncryped(0, processName)) {
354         PROFILER_LOG_INFO(LOG_CORE, "Encryped Application don't unwind js stack:%s", processName.c_str());
355         hookConfig_.set_js_stack_report(0);
356         hookConfig_.set_max_js_stack_depth(0);
357     }
358 }
359 
CreatePluginSession(const std::vector<ProfilerPluginConfig> & config)360 bool HookManager::CreatePluginSession(const std::vector<ProfilerPluginConfig>& config)
361 {
362     PROFILER_LOG_DEBUG(LOG_CORE, "CreatePluginSession");
363     // save config
364     if (!config.empty()) {
365         std::string cfgData = config[0].config_data();
366         if (hookConfig_.ParseFromArray(reinterpret_cast<const uint8_t*>(cfgData.c_str()), cfgData.size()) <= 0) {
367             PROFILER_LOG_ERROR(LOG_CORE, "%s: ParseFromArray failed", __func__);
368             return false;
369         }
370     }
371     if ((!saMode_) && (COMMON::IsUserMode())) {
372         if (!COMMON::CheckApplicationPermission(hookConfig_.pid(), hookConfig_.process_name())) {
373             return false;
374         }
375     }
376     int32_t uShortMax = (std::numeric_limits<unsigned short>::max)();
377     if (hookConfig_.filter_size() > uShortMax) {
378         PROFILER_LOG_WARN(LOG_CORE, "%s: filter size invalid(size exceed 65535), reset to 65535!", __func__);
379         hookConfig_.set_filter_size(uShortMax);
380     }
381     if (!CheckProcess()) { // Check and initialize the context for the target process.
382         return false;
383     }
384     (void)CheckHapEncryped();
385     if (hookConfig_.max_stack_depth() < DLOPEN_MIN_UNWIND_DEPTH) {
386         // set default max depth
387         hookConfig_.set_max_stack_depth(DLOPEN_MIN_UNWIND_DEPTH);
388     }
389 #if defined(__arm__)
390     hookConfig_.set_fp_unwind(false); // if OS is 32-bit,set fp_unwind false.
391     hookConfig_.set_response_library_mode(false);
392 #endif
393     if (hookConfig_.response_library_mode()) {
394         hookConfig_.set_fp_unwind(true);
395         hookConfig_.set_offline_symbolization(true);
396         hookConfig_.set_js_stack_report(0);
397     }
398     // offlinem symbolization, callframe must be compressed
399     if (hookConfig_.offline_symbolization()) {
400         hookConfig_.set_callframe_compress(true);
401     }
402 
403     // statistical reporting must be callframe compressed and accurate.
404     if (hookConfig_.statistics_interval() > 0) {
405         hookConfig_.set_callframe_compress(true);
406         hookConfig_.set_record_accurately(true);
407     }
408 
409     // malloc and free matching interval reporting must be callframe compressed and accurate.
410     if (hookConfig_.malloc_free_matching_interval() > 0) {
411         hookConfig_.set_callframe_compress(true);
412         hookConfig_.set_record_accurately(true);
413         hookConfig_.set_statistics_interval(0);
414     }
415 
416     // callframe compressed, string must be compressed.
417     if (hookConfig_.callframe_compress()) {
418         hookConfig_.set_string_compressed(true);
419     }
420 
421     if (hookConfig_.js_stack_report() > 0 && hookConfig_.max_js_stack_depth() == 0 && hookConfig_.fp_unwind()) {
422         hookConfig_.set_max_js_stack_depth(DEFAULT_MAX_JS_STACK_DEPTH);
423     }
424 
425     if (hookCtx_.empty()) {
426         PROFILER_LOG_ERROR(LOG_CORE, "HookManager no task");
427         return false;
428     }
429     if ((hookConfig_.save_file() || isHookStandalone_) && !hookConfig_.file_name().empty()) {
430         auto retFile = COMMON::CheckNotExistsFilePath(hookConfig_.file_name());
431         if (!retFile.first) {
432             PROFILER_LOG_INFO(LOG_CORE, "check file path %s fail", hookConfig_.file_name().c_str());
433             return false;
434         }
435         fpHookData_ = fopen(retFile.second.c_str(), "wb+");
436         if (fpHookData_ == nullptr) {
437             PROFILER_LOG_INFO(LOG_CORE, "fopen file %s fail", hookConfig_.file_name().c_str());
438             return false;
439         }
440     }
441     if (hookConfig_.fp_unwind() && hookConfig_.offline_symbolization()
442         && hookConfig_.statistics_interval() > 0) {
443         noDataQueue_ = true;
444     }
445 
446     if (!isSaService_) {
447         CreateWriter();
448     }
449     factory_ = std::make_shared<HookRecordFactory>(hookConfig_);
450     for (const auto& item : hookCtx_) {
451         CHECK_TRUE(HandleHookContext(item), false, "handle hook context failed"); // Create the required resources.
452     }
453 
454     if (!isSaService_) { // SA mode will start HookService in the service.
455         ClientConfig clientConfig;
456         GetClientConfig(clientConfig);
457         if (noDataQueue_) {
458             clientConfig.freeEventOnlyAddrEnable = true;
459         }
460         std::string clientConfigStr = clientConfig.ToString();
461         PROFILER_LOG_INFO(LOG_CORE, "send hook client config:%s\n", clientConfigStr.c_str());
462         hookService_ = std::make_shared<HookService>(clientConfig, shared_from_this(), (hookCtx_.size() > 1));
463         CHECK_NOTNULL(hookService_, false, "HookService create failed!");
464     }
465 
466     return true;
467 }
468 
FlushStackArray()469 void HookManager::HookManagerCtx::FlushStackArray()
470 {
471     if (g_rawDataArray.size() > 0 && stackData != nullptr) {
472         if (!stackData->PutRawStackArray(g_rawDataArray, g_rawStackCount)) {
473             PROFILER_LOG_INFO(LOG_CORE, "PutRawStackArray error");
474         }
475         g_rawStackCount = 0;
476         g_rawDataArray = {};
477     }
478 }
479 
FlushRawStackArray(const std::shared_ptr<HookManagerCtx> & hookCtx,std::shared_ptr<HookRecord> & hookRecord)480 void HookManager::FlushRawStackArray(const std::shared_ptr<HookManagerCtx>& hookCtx,
481                                      std::shared_ptr<HookRecord>& hookRecord)
482 {
483     if (hookCtx == nullptr || hookRecord == nullptr) {
484         return;
485     }
486     g_rawDataArray[g_rawStackCount] = hookRecord;
487     ++g_rawStackCount;
488     if (g_rawStackCount == CACHE_ARRAY_SIZE) {
489         hookCtx->FlushStackArray();
490     }
491 }
492 
DumpNmdInfo(const char * nmdResult)493 void HookManager::DumpNmdInfo(const char* nmdResult)
494 {
495     std::string fileName = hookConfig_.process_name().empty() ? std::to_string(hookConfig_.pid()) :
496                                                                 hookConfig_.process_name();
497     const std::string filePath = "/data/local/tmp/nmd_" + fileName + ".txt";
498     std::ofstream outFile(filePath);
499     if (!outFile.is_open()) {
500         PROFILER_LOG_ERROR(LOG_CORE, "unable to write into nmd.txt");
501         return;
502     }
503     outFile << nmdResult;
504     if (!outFile) {
505         PROFILER_LOG_ERROR(LOG_CORE, "Error: Failed to write data to file %s", filePath.c_str());
506         outFile.close();
507         return;
508     }
509     outFile.close();
510     PROFILER_LOG_INFO(LOG_CORE, "Data successfully written to nmd file");
511 }
512 
ReadShareMemory(const std::shared_ptr<HookManagerCtx> & hookCtx,int sharedMemoryIndex)513 void HookManager::ReadShareMemory(const std::shared_ptr<HookManagerCtx>& hookCtx, int sharedMemoryIndex)
514 {
515     std::shared_ptr<ShareMemoryBlock> shareMemoryBlock = hookCtx->shareMemoryBlockList[sharedMemoryIndex];
516     CHECK_NOTNULL(shareMemoryBlock, NO_RETVAL, "smb is null!");
517     hookCtx->eventNotifierList[sharedMemoryIndex]->Take();
518     while (true) {
519         std::shared_ptr<HookRecord> hookRecord = nullptr;
520         std::shared_ptr<RawStack> rawStack = nullptr;
521         bool ret = shareMemoryBlock->TakeData([&](const int8_t data[], uint32_t size) -> bool {
522             hookRecord = factory_->GetHookRecord(data, size);
523             CHECK_NOTNULL(hookRecord, false, "ReadShareMemory hookRecord invalid!");
524             rawStack = hookRecord->GetRawStack();
525             uint16_t type = hookRecord->GetType();
526             if (type == FREE_MSG_SIMP) {
527                 return true;
528             }
529 
530             if (type == NMD_MSG && printMallocNmd_) {
531                 const char* nmdResult = reinterpret_cast<const char*>(rawStack->data);
532                 if (!saMode_) {
533                     DumpNmdInfo(nmdResult);
534                 }
535                 if (nmdParamInfo_.type == SIMP_NMD) {
536                     simplifiedNmd_ = std::string(nmdResult);
537                     nmdComplete_ = true;
538                     PROFILER_LOG_INFO(LOG_CORE, "receive simplified nmd info, target pid :%d, processName:%s.\n",
539                                       hookCtx->pid, hookCtx->processName.c_str());
540                 } else {
541                     lseek(nmdParamInfo_.fd, 0, SEEK_END);
542                     (void)write(nmdParamInfo_.fd, nmdResult, strlen(nmdResult));
543                 }
544                 return true;
545             } else if (type == END_MSG) {
546                 return true;
547             }
548             rawStack->reportFlag = true;
549             if (type == MEMORY_TAG || type == THREAD_NAME_MSG ||
550                 type == MMAP_FILE_TYPE || type == PR_SET_VMA_MSG ||
551                 type == JS_STACK_MSG) {
552                 return true;
553             }
554             rawStack->reduceStackFlag = false;
555             if (hookConfig_.fp_unwind()) {
556                 if (rawStack->stackContext->jsChainId > 0) {
557                     rawStack->jsStackData = hookCtx->stackPreprocess->GetJsRawStack(rawStack->stackContext->jsChainId);
558                 }
559                 return true;
560             }
561             return true;
562         });
563         if (!ret) {
564             break;
565         }
566         uint16_t type = hookRecord->GetType();
567         if (type == MEMORY_TAG) {
568             std::string tagName = reinterpret_cast<char*>(rawStack->data);
569             hookCtx->stackPreprocess->SaveMemTag(rawStack->stackContext->tagId, tagName);
570             continue;
571         } else if (type == JS_STACK_MSG) {
572             hookCtx->stackPreprocess->SaveJsRawStack(rawStack->stackContext->jsChainId,
573                                                      reinterpret_cast<char*>(rawStack->data));
574             continue;
575         } else if (type == END_MSG) {
576             hookCtx->FlushStackArray();
577             if (!hookCtx->stackData->PutRawStack(hookRecord, hookCtx->isRecordAccurately)) {
578                 break;
579             }
580             if (!hookCtx->stackData->PutRawStack(nullptr, false)) {
581                 break;
582             }
583             continue;
584         } else if (type == NMD_MSG) {
585             continue;
586         }
587         FlushRawStackArray(hookCtx, hookRecord);
588     }
589 }
590 
DestroyPluginSession(const std::vector<uint32_t> & pluginIds)591 bool HookManager::DestroyPluginSession(const std::vector<uint32_t>& pluginIds)
592 {
593     if ((!saMode_) && (COMMON::IsUserMode())) {
594         if (!COMMON::CheckApplicationPermission(hookConfig_.pid(), hookConfig_.process_name())) {
595             return false;
596         }
597     }
598     for (const auto& item : hookCtx_) {
599         for (int i = 0; i < item->eventPollerList.size(); ++i) {
600             if (item->eventPollerList[i] && item->eventNotifierList[i]) {
601                 PROFILER_LOG_ERROR(LOG_CORE, "eventPoller unset! num: %d", i);
602                 item->eventPollerList[i]->RemoveFileDescriptor(item->eventNotifierList[i]->GetFd());
603                 item->eventPollerList[i]->Stop();
604                 item->eventPollerList[i]->Finalize();
605             }
606             if (item->shareMemoryBlockList[i]) {
607                 ShareMemoryAllocator::GetInstance().ReleaseMemoryBlockLocal(item->smbNames[i]);
608             }
609         }
610         if (item->stackData != nullptr) {
611             item->stackData->ClearCache();
612         }
613     }
614     if (fpHookData_) {
615         fclose(fpHookData_);
616         fpHookData_ = nullptr;
617     }
618     return true;
619 }
620 
StartPluginSession(const std::vector<uint32_t> & pluginIds,const std::vector<ProfilerPluginConfig> & config,PluginResult & result)621 bool HookManager::StartPluginSession(const std::vector<uint32_t>& pluginIds,
622                                      const std::vector<ProfilerPluginConfig>& config, PluginResult& result)
623 {
624     UNUSED_PARAMETER(config);
625     if (hookCtx_.empty()) {
626         return false;
627     }
628     if ((!saMode_) && (COMMON::IsUserMode())) {
629         if (!COMMON::CheckApplicationPermission(hookConfig_.pid(), hookConfig_.process_name())) {
630             return false;
631         }
632     }
633     StartPluginSession();
634     return true;
635 }
636 
StopPluginSession(const std::vector<uint32_t> & pluginIds)637 bool HookManager::StopPluginSession(const std::vector<uint32_t>& pluginIds)
638 {
639     if (hookCtx_.empty()) {
640         return false;
641     }
642     if ((!saMode_) && (COMMON::IsUserMode())) {
643         if (!COMMON::CheckApplicationPermission(hookConfig_.pid(), hookConfig_.process_name())) {
644             return false;
645         }
646     }
647     for (const auto& item : hookCtx_) {
648         if ((item->pid > 0) && hookService_) {
649             hookService_->CloseSocketFd(static_cast<pid_t>(item->pid));
650             hookService_->RemovePidInfo(static_cast<pid_t>(item->pid));
651         } else if (item->pid <= 0) {
652             PROFILER_LOG_INFO(LOG_CORE, "StopPluginSession: pid(%d) is less or equal zero.", item->pid);
653         }
654         CHECK_TRUE(item->stackPreprocess != nullptr, false, "stop StackPreprocess FAIL");
655         item->stackPreprocess->StopTakeResults();
656         PROFILER_LOG_INFO(LOG_CORE, "StopTakeResults success");
657         if (hookConfig_.statistics_interval() > 0) {
658             item->stackPreprocess->FlushRecordStatistics();
659         }
660         if (hookConfig_.malloc_free_matching_interval() > 0) {
661             item->stackPreprocess->FlushRecordApplyAndReleaseMatchData();
662         }
663         if (item->stackData != nullptr) {
664             item->stackData->Close();
665         }
666         item->stackPreprocess->FinishTraceFile();
667     }
668     return true;
669 }
670 
ResetStartupParam()671 void HookManager::ResetStartupParam()
672 {
673     const std::string resetParam = "startup:disabled";
674     if (hookConfig_.startup_mode()) {
675         int ret = SystemSetParameter(PARAM_NAME.c_str(), resetParam.c_str());
676         if (ret < 0) {
677             PROFILER_LOG_WARN(LOG_CORE, "set param failed, please reset param(%s)", PARAM_NAME.c_str());
678         } else {
679             PROFILER_LOG_INFO(LOG_CORE, "reset param success");
680         }
681     }
682 }
683 
ReportPluginBasicData(const std::vector<uint32_t> & pluginIds)684 bool HookManager::ReportPluginBasicData(const std::vector<uint32_t>& pluginIds)
685 {
686     return true;
687 }
688 
CreateWriter(std::string pluginName,uint32_t bufferSize,int smbFd,int eventFd,bool isProtobufSerialize)689 bool HookManager::CreateWriter(std::string pluginName, uint32_t bufferSize, int smbFd, int eventFd,
690                                bool isProtobufSerialize)
691 {
692     PROFILER_LOG_DEBUG(LOG_CORE, "agentIndex_ %d", agentIndex_);
693     writer_ = std::make_shared<BufferWriter>(pluginName, VERSION, bufferSize, smbFd, eventFd, agentIndex_);
694     isProtobufSerialize_ = isProtobufSerialize;
695     shareMemorySize_ = bufferSize;
696     return true;
697 }
698 
CreateWriter()699 void HookManager::CreateWriter()
700 {
701     PROFILER_LOG_INFO(LOG_CORE, "CreateWriter isProtobufSerialize: %d, noDataQueue_: %d",
702                       isProtobufSerialize_, noDataQueue_);
703     if (isProtobufSerialize_) {
704         RegisterWriter(writer_);
705     } else {
706         writerAdapter_ = std::make_shared<WriterAdapter>(isProtobufSerialize_);
707         writerAdapter_->SetWriter(writer_);
708     }
709 }
710 
ResetWriter(uint32_t pluginId)711 bool HookManager::ResetWriter(uint32_t pluginId)
712 {
713     RegisterWriter(nullptr);
714     return true;
715 }
716 
RegisterWriter(const std::shared_ptr<Writer> writer)717 void HookManager::RegisterWriter(const std::shared_ptr<Writer> writer)
718 {
719     g_buffWriter = writer;
720     return;
721 }
722 
SetHookConfig(const NativeHookConfig & hookConfig)723 void HookManager::SetHookConfig(const NativeHookConfig& hookConfig)
724 {
725     hookConfig_ = hookConfig;
726 }
727 
SethookStandalone(bool HookStandalone)728 void HookManager::SethookStandalone(bool HookStandalone)
729 {
730     isHookStandalone_ = HookStandalone;
731 }
732 
SetHookConfig(const std::shared_ptr<NativeMemoryProfilerSaConfig> & config)733 void HookManager::SetHookConfig(const std::shared_ptr<NativeMemoryProfilerSaConfig>& config)
734 {
735     hookConfig_.set_pid(config->pid_);
736     if (!config->processName_.empty()) {
737         hookConfig_.set_process_name(config->processName_);
738     }
739     hookConfig_.set_filter_size(config->filterSize_);
740     hookConfig_.set_smb_pages(config->shareMemorySize_);
741     hookConfig_.set_max_stack_depth(config->maxStackDepth_);
742     hookConfig_.set_malloc_disable(config->mallocDisable_);
743     hookConfig_.set_mmap_disable(config->mmapDisable_);
744     hookConfig_.set_free_stack_report(config->freeStackData_);
745     hookConfig_.set_munmap_stack_report(config->munmapStackData_);
746     hookConfig_.set_malloc_free_matching_interval(config->mallocFreeMatchingInterval_);
747     hookConfig_.set_malloc_free_matching_cnt(config->mallocFreeMatchingCnt_);
748     hookConfig_.set_string_compressed(config->stringCompressed_);
749     hookConfig_.set_fp_unwind(config->fpUnwind_);
750     hookConfig_.set_blocked(config->blocked_);
751     hookConfig_.set_record_accurately(config->recordAccurately_);
752     hookConfig_.set_startup_mode(config->startupMode_);
753     hookConfig_.set_memtrace_enable(config->memtraceEnable_);
754     hookConfig_.set_offline_symbolization(config->offlineSymbolization_);
755     hookConfig_.set_callframe_compress(config->callframeCompress_);
756     hookConfig_.set_statistics_interval(config->statisticsInterval_);
757     hookConfig_.set_clock(COMMON::GetClockStr(config->clockId_));
758     hookConfig_.set_sample_interval(config->sampleInterval_);
759     hookConfig_.set_response_library_mode(config->responseLibraryMode_);
760     hookConfig_.set_js_stack_report(config->jsStackReport_);
761     hookConfig_.set_max_js_stack_depth(config->maxJsStackDepth_);
762     hookConfig_.set_filter_napi_name(config->filterNapiName_);
763     hookConfig_.set_target_so_name(config->targetSoName_);
764     printMallocNmd_ = config->printNmd_;
765     if (config->hookstandalone_) {
766         isHookStandalone_ = true;
767     }
768     if (config->saveFile_ || config->hookstandalone_) {
769         hookConfig_.set_save_file(config->saveFile_);
770         hookConfig_.set_file_name(config->fileName_);
771         isProtobufSerialize_ = true;
772     }
773     largestSize_ = config->largestSize_;
774     secondLargestSize_ = config->secondLargestSize_;
775     maxGrowthSize_ = config->maxGrowthSize_;
776 }
777 
CreatePluginSession()778 int32_t HookManager::CreatePluginSession()
779 {
780     if (CreatePluginSession({})) {
781         return RET_OK;
782     }
783     return RET_ERR;
784 }
785 
StartPluginSession(std::unordered_map<pid_t,std::pair<uid_t,gid_t>> * pidInfo)786 void HookManager::StartPluginSession(std::unordered_map<pid_t, std::pair<uid_t, gid_t>>* pidInfo)
787 {
788     for (const auto& item : hookCtx_) {
789         if (item->stackPreprocess == nullptr) {
790             continue;
791         }
792         PROFILER_LOG_ERROR(LOG_CORE, "StartPluginSession name: %s", item->processName.c_str());
793         if (!noDataQueue_) {
794             item->stackPreprocess->StartTakeResults();
795         }
796         item->stackPreprocess->InitStatisticsTime();
797         if (item->pid > 0) {
798             PROFILER_LOG_INFO(LOG_CORE, "start command : send 36 signal to process  %d", item->pid);
799             uid_t uid = 0;
800             gid_t gid = 0;
801             if (!COMMON::GetUidGidFromPid(static_cast<pid_t>(item->pid), uid, gid)) {
802                 PROFILER_LOG_INFO(LOG_CORE, "get target process uid gid failed");
803                 continue;
804             }
805             if (kill(item->pid, SIGNAL_START_HOOK) == -1) {
806                 const int bufSize = 256;
807                 char buf[bufSize] = {0};
808                 strerror_r(errno, buf, bufSize);
809                 PROFILER_LOG_ERROR(LOG_CORE, "send 36 signal error = %s", buf);
810             }
811             if (!saMode_) {
812                 hookService_->AddPidInfo(static_cast<pid_t>(item->pid), uid, gid);
813             } else if (pidInfo != nullptr) {
814                 (*pidInfo)[static_cast<pid_t>(item->pid)] = std::make_pair(uid, gid);
815             }
816         } else {
817             PROFILER_LOG_INFO(LOG_CORE, "StartPluginSession: pid(%d) is less or equal zero.", item->pid);
818         }
819     }
820     if (!saMode_) {
821         int ret = COMMON::PluginWriteToHisysevent("native_hook_plugin", "sh", GetCmdArgs(hookConfig_),
822             COMMON::ErrorType::RET_SUCC, "success");
823         PROFILER_LOG_INFO(LOG_CORE, "hisysevent report native_hook_plugin result:%d", ret);
824     }
825 }
826 
GetCmdArgs(const NativeHookConfig & traceConfig)827 std::string HookManager::GetCmdArgs(const NativeHookConfig& traceConfig)
828 {
829     std::stringstream args;
830     args << "pid: " << COMMON::GetProcessNameByPid(traceConfig.pid()) << ", ";
831     args << "save_file: " << (traceConfig.save_file() ? "true" : "false") << ", ";
832     args << "filter_size: " << std::to_string(traceConfig.filter_size()) << ", ";
833     args << "smb_pages: " << std::to_string(traceConfig.smb_pages()) << ", ";
834     args << "max_stack_depth: " << std::to_string(traceConfig.max_stack_depth()) << ", ";
835     args << "process_name: " << traceConfig.process_name() << ", ";
836     args << "malloc_disable: " << (traceConfig.malloc_disable() ? "true" : "false") << ", ";
837     args << "mmap_disable: " << (traceConfig.mmap_disable() ? "true" : "false") << ", ";
838     args << "free_stack_report: " << (traceConfig.free_stack_report() ? "true" : "false") << ", ";
839     args << "munmap_stack_report: " << (traceConfig.munmap_stack_report() ? "true" : "false") << ", ";
840     args << "malloc_free_matching_interval: " << std::to_string(traceConfig.malloc_free_matching_interval()) << ", ";
841     args << "malloc_free_matching_cnt: " << std::to_string(traceConfig.malloc_free_matching_cnt()) << ", ";
842     args << "string_compressed: " << (traceConfig.string_compressed() ? "true" : "false") << ", ";
843     args << "fp_unwind: " << (traceConfig.fp_unwind() ? "true" : "false") << ", ";
844     args << "blocked: " << (traceConfig.blocked() ? "true" : "false") << ", ";
845     args << "record_accurately: " << (traceConfig.record_accurately() ? "true" : "false") << ", ";
846     args << "startup_mode: " << (traceConfig.startup_mode() ? "true" : "false") << ", ";
847     args << "memtrace_enable: " << (traceConfig.memtrace_enable() ? "true" : "false") << ", ";
848     args << "offline_symbolization: " << (traceConfig.offline_symbolization() ? "true" : "false") << ", ";
849     args << "callframe_compress: " << (traceConfig.callframe_compress() ? "true" : "false") << ", ";
850     args << "statistics_interval: " << std::to_string(traceConfig.statistics_interval()) << ", ";
851     args << "clock: " << traceConfig.clock() << ", ";
852     args << "sample_interval: " << std::to_string(traceConfig.sample_interval()) << ", ";
853     args << "response_library_mode: " << (traceConfig.response_library_mode() ? "true" : "false") << ", ";
854     args << "js_stack_report: " << std::to_string(traceConfig.js_stack_report()) << ", ";
855     args << "max_js_stack_depth: " << std::to_string(traceConfig.max_js_stack_depth()) << ", ";
856     args << "filter_napi_name: " << traceConfig.filter_napi_name() << ", ";
857     args << "target_so_name: " << traceConfig.target_so_name() << ", ";
858     for (const auto& pid : traceConfig.expand_pids()) {
859         args << "expand_pids: " << std::to_string(pid) << ", ";
860     }
861     return args.str();
862 }
863 
WriteHookConfig()864 void HookManager::WriteHookConfig()
865 {
866     for (const auto& item : hookCtx_) {
867         if (item == nullptr) {
868             PROFILER_LOG_ERROR(LOG_CORE, "HookManager WriteHookConfig failed");
869             return;
870         }
871         item->stackPreprocess->WriteHookConfig();
872     }
873 }
874 
GetFds(int32_t pid,const std::string & name,int sharedMemCount)875 std::vector<int> HookManager::GetFds(int32_t pid, const std::string& name, int sharedMemCount)
876 {
877     for (const auto& item : hookCtx_) {
878         if (item->pid == pid || item->processName == name) {
879             if (item->pid == -1) {
880                 item->pid = pid;
881             }
882             item->stackPreprocess->SetPid(pid);
883             std::vector<int> fds;
884             for (int i = 0; i < sharedMemCount; ++i) {
885                 fds.push_back(item->eventNotifierList[i]->GetFd());
886                 fds.push_back(item->shareMemoryBlockList[i]->GetfileDescriptor());
887             }
888             return fds;
889         }
890     }
891     return std::vector<int>(sharedMemCount * DOUBLE, -1);
892 }
893 
SetNmdInfo(std::pair<uint32_t,uint32_t> info)894 void HookManager::SetNmdInfo(std::pair<uint32_t, uint32_t> info)
895 {
896     printMallocNmd_ = true;
897     nmdParamInfo_.fd = info.first;
898     nmdParamInfo_.type = info.second;
899 }
900 }