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