• 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(void*)) {
471                 if (data) {
472                     CHECK_TRUE(memcpy_s(&rawStack->freeData, sizeof(rawStack->freeData), data, size) == EOK, false,
473                                "memcpy_s freeData failed!");
474                 }
475                 rawStack->baseStackData = nullptr;
476                 return true;
477             }
478             rawStack->freeData = 0;
479             CHECK_TRUE(size >= sizeof(BaseStackRawData), false, "stack data invalid!");
480 
481             rawStack->baseStackData = std::make_unique<uint8_t[]>(size);
482             CHECK_TRUE(memcpy_s(rawStack->baseStackData.get(), size, data, size) == EOK, false,
483                        "memcpy_s raw data failed!");
484 
485             rawStack->stackConext = reinterpret_cast<BaseStackRawData*>(rawStack->baseStackData.get());
486 
487             if (rawStack->stackConext->type == NMD_MSG && printMallocNmd_) {
488                 rawStack->data = rawStack->baseStackData.get() + sizeof(BaseStackRawData);
489                 const char* nmdResult = reinterpret_cast<const char*>(rawStack->data);
490                 lseek(nmdParamInfo_.fd, 0, SEEK_END);
491                 (void)write(nmdParamInfo_.fd, nmdResult, strlen(nmdResult));
492                 return true;
493             } else if (rawStack->stackConext->type == END_MSG) {
494                 return true;
495             }
496             rawStack->data = rawStack->baseStackData.get() + sizeof(BaseStackRawData);
497             rawStack->reportFlag = true;
498             if (rawStack->stackConext->type == MEMORY_TAG || rawStack->stackConext->type == THREAD_NAME_MSG ||
499                 rawStack->stackConext->type == MMAP_FILE_TYPE || rawStack->stackConext->type == PR_SET_VMA_MSG ||
500                 rawStack->stackConext->type == JS_STACK_MSG) {
501                 return true;
502             }
503             rawStack->reduceStackFlag = false;
504             if (hookConfig_.fp_unwind()) {
505                 rawStack->fpDepth = (size - sizeof(BaseStackRawData)) / sizeof(uint64_t);
506                 if (rawStack->stackConext->jsChainId > 0) {
507                     rawStack->jsStackData = hookCtx->stackPreprocess->GetJsRawStack(rawStack->stackConext->jsChainId);
508                 }
509                 return true;
510             } else {
511                 rawRealSize = sizeof(BaseStackRawData) + MAX_REG_SIZE * sizeof(char);
512             }
513 
514             rawStack->stackSize = size - rawRealSize;
515             if (rawStack->stackSize > 0) {
516                 rawStack->stackData = rawStack->baseStackData.get() + rawRealSize;
517             }
518             return true;
519         });
520         if (!ret) {
521             break;
522         }
523         if (rawStack->baseStackData == nullptr) {
524             FlushRawStackArray(hookCtx, rawStack);
525             continue;
526         }
527         if (rawStack->stackConext->type == MEMORY_TAG) {
528             std::string tagName = reinterpret_cast<char*>(rawStack->data);
529             hookCtx->stackPreprocess->SaveMemTag(rawStack->stackConext->tagId, tagName);
530             continue;
531         } else if (rawStack->stackConext->type == JS_STACK_MSG) {
532             hookCtx->stackPreprocess->SaveJsRawStack(rawStack->stackConext->jsChainId,
533                                                      reinterpret_cast<char*>(rawStack->data));
534             continue;
535         } else if (rawStack->stackConext->type == END_MSG) {
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     }
570     if (fpHookData_) {
571         fclose(fpHookData_);
572         fpHookData_ = nullptr;
573     }
574     return true;
575 }
576 
StartPluginSession(const std::vector<uint32_t> & pluginIds,const std::vector<ProfilerPluginConfig> & config,PluginResult & result)577 bool HookManager::StartPluginSession(const std::vector<uint32_t>& pluginIds,
578                                      const std::vector<ProfilerPluginConfig>& config, PluginResult& result)
579 {
580     UNUSED_PARAMETER(config);
581     if (hookCtx_.empty()) {
582         return false;
583     }
584     if ((!saMode_) && (COMMON::IsUserMode())) {
585         if (!COMMON::CheckApplicationPermission(hookConfig_.pid(), hookConfig_.process_name())) {
586             return false;
587         }
588     }
589     StartPluginSession();
590     return true;
591 }
592 
StopPluginSession(const std::vector<uint32_t> & pluginIds)593 bool HookManager::StopPluginSession(const std::vector<uint32_t>& pluginIds)
594 {
595     if (hookCtx_.empty()) {
596         return false;
597     }
598     if ((!saMode_) && (COMMON::IsUserMode())) {
599         if (!COMMON::CheckApplicationPermission(hookConfig_.pid(), hookConfig_.process_name())) {
600             return false;
601         }
602     }
603     for (const auto& item : hookCtx_) {
604         if (item->pid > 0) {
605             PROFILER_LOG_INFO(LOG_CORE, "stop command : send 37 signal to process  %d", item->pid);
606             if (kill(item->pid, SIGNAL_STOP_HOOK) == -1) {
607                 const int bufSize = 256;
608                 char buf[bufSize] = {0};
609                 strerror_r(errno, buf, bufSize);
610                 PROFILER_LOG_ERROR(LOG_CORE, "send 37 signal to process %d , error = %s", item->pid, buf);
611             }
612         } else {
613             PROFILER_LOG_INFO(LOG_CORE, "StopPluginSession: pid(%d) is less or equal zero.", item->pid);
614         }
615         item->FlushStackArray();
616         CHECK_TRUE(item->stackPreprocess != nullptr, false, "stop StackPreprocess FAIL");
617         item->stackPreprocess->StopTakeResults();
618         PROFILER_LOG_INFO(LOG_CORE, "StopTakeResults success");
619         if (hookConfig_.statistics_interval() > 0) {
620             item->stackPreprocess->FlushRecordStatistics();
621         }
622         if (hookConfig_.malloc_free_matching_interval() > 0) {
623             item->stackPreprocess->FlushRecordApplyAndReleaseMatchData();
624         }
625         if (item->stackData != nullptr) {
626             item->stackData->Close();
627         }
628         item->stackPreprocess->FinishTraceFile();
629     }
630     return true;
631 }
632 
ResetStartupParam()633 void HookManager::ResetStartupParam()
634 {
635     const std::string resetParam = "startup:disabled";
636     if (hookConfig_.startup_mode()) {
637         int ret = SystemSetParameter(PARAM_NAME.c_str(), resetParam.c_str());
638         if (ret < 0) {
639             PROFILER_LOG_WARN(LOG_CORE, "set param failed, please reset param(%s)", PARAM_NAME.c_str());
640         } else {
641             PROFILER_LOG_INFO(LOG_CORE, "reset param success");
642         }
643     }
644 }
645 
ReportPluginBasicData(const std::vector<uint32_t> & pluginIds)646 bool HookManager::ReportPluginBasicData(const std::vector<uint32_t>& pluginIds)
647 {
648     return true;
649 }
650 
CreateWriter(std::string pluginName,uint32_t bufferSize,int smbFd,int eventFd,bool isProtobufSerialize)651 bool HookManager::CreateWriter(std::string pluginName, uint32_t bufferSize, int smbFd, int eventFd,
652                                bool isProtobufSerialize)
653 {
654     PROFILER_LOG_DEBUG(LOG_CORE, "agentIndex_ %d", agentIndex_);
655     writer_ = std::make_shared<BufferWriter>(pluginName, VERSION, bufferSize, smbFd, eventFd, agentIndex_);
656     isProtobufSerialize_ = isProtobufSerialize;
657     shareMemorySize_ = bufferSize;
658     return true;
659 }
660 
CreateWriter()661 void HookManager::CreateWriter()
662 {
663     PROFILER_LOG_INFO(LOG_CORE, "CreateWriter isProtobufSerialize: %d, noDataQueue_: %d",
664                       isProtobufSerialize_, noDataQueue_);
665     if (isProtobufSerialize_) {
666         RegisterWriter(writer_);
667     } else {
668         writerAdapter_ = std::make_shared<WriterAdapter>(isProtobufSerialize_);
669         writerAdapter_->SetWriter(writer_);
670     }
671 }
672 
ResetWriter(uint32_t pluginId)673 bool HookManager::ResetWriter(uint32_t pluginId)
674 {
675     RegisterWriter(nullptr);
676     return true;
677 }
678 
RegisterWriter(const std::shared_ptr<Writer> writer)679 void HookManager::RegisterWriter(const std::shared_ptr<Writer> writer)
680 {
681     g_buffWriter = writer;
682     return;
683 }
684 
SetHookConfig(const NativeHookConfig & hookConfig)685 void HookManager::SetHookConfig(const NativeHookConfig& hookConfig)
686 {
687     hookConfig_ = hookConfig;
688 }
689 
SethookStandalone(bool HookStandalone)690 void HookManager::SethookStandalone(bool HookStandalone)
691 {
692     isHookStandalone_ = HookStandalone;
693 }
694 
SetHookConfig(const std::shared_ptr<NativeMemoryProfilerSaConfig> & config)695 void HookManager::SetHookConfig(const std::shared_ptr<NativeMemoryProfilerSaConfig>& config)
696 {
697     hookConfig_.set_pid(config->pid_);
698     if (!config->processName_.empty()) {
699         hookConfig_.set_process_name(config->processName_);
700     }
701     hookConfig_.set_filter_size(config->filterSize_);
702     hookConfig_.set_smb_pages(config->shareMemorySize_);
703     hookConfig_.set_max_stack_depth(config->maxStackDepth_);
704     hookConfig_.set_malloc_disable(config->mallocDisable_);
705     hookConfig_.set_mmap_disable(config->mmapDisable_);
706     hookConfig_.set_free_stack_report(config->freeStackData_);
707     hookConfig_.set_munmap_stack_report(config->munmapStackData_);
708     hookConfig_.set_malloc_free_matching_interval(config->mallocFreeMatchingInterval_);
709     hookConfig_.set_malloc_free_matching_cnt(config->mallocFreeMatchingCnt_);
710     hookConfig_.set_string_compressed(config->stringCompressed_);
711     hookConfig_.set_fp_unwind(config->fpUnwind_);
712     hookConfig_.set_blocked(config->blocked_);
713     hookConfig_.set_record_accurately(config->recordAccurately_);
714     hookConfig_.set_startup_mode(config->startupMode_);
715     hookConfig_.set_memtrace_enable(config->memtraceEnable_);
716     hookConfig_.set_offline_symbolization(config->offlineSymbolization_);
717     hookConfig_.set_callframe_compress(config->callframeCompress_);
718     hookConfig_.set_statistics_interval(config->statisticsInterval_);
719     hookConfig_.set_clock(COMMON::GetClockStr(config->clockId_));
720     hookConfig_.set_sample_interval(config->sampleInterval_);
721     hookConfig_.set_response_library_mode(config->responseLibraryMode_);
722     hookConfig_.set_js_stack_report(config->jsStackReport_);
723     hookConfig_.set_max_js_stack_depth(config->maxJsStackDepth_);
724     hookConfig_.set_filter_napi_name(config->filterNapiName_);
725     printMallocNmd_ = config->printNmd_;
726 }
727 
CreatePluginSession()728 int32_t HookManager::CreatePluginSession()
729 {
730     if (CreatePluginSession({})) {
731         return RET_OK;
732     }
733     return RET_ERR;
734 }
735 
StartPluginSession()736 void HookManager::StartPluginSession()
737 {
738     for (const auto& item : hookCtx_) {
739         if (item->stackPreprocess == nullptr) {
740             continue;
741         }
742         PROFILER_LOG_ERROR(LOG_CORE, "StartPluginSession name: %s", item->processName.c_str());
743         if (!noDataQueue_) {
744             item->stackPreprocess->StartTakeResults();
745         }
746         item->stackPreprocess->InitStatisticsTime();
747         if (item->pid > 0) {
748             PROFILER_LOG_INFO(LOG_CORE, "start command : send 36 signal to process  %d", item->pid);
749             if (kill(item->pid, SIGNAL_START_HOOK) == -1) {
750                 const int bufSize = 256;
751                 char buf[bufSize] = {0};
752                 strerror_r(errno, buf, bufSize);
753                 PROFILER_LOG_ERROR(LOG_CORE, "send 36 signal error = %s", buf);
754             }
755         } else {
756             PROFILER_LOG_INFO(LOG_CORE, "StartPluginSession: pid(%d) is less or equal zero.", item->pid);
757         }
758     }
759 }
760 
WriteHookConfig()761 void HookManager::WriteHookConfig()
762 {
763     for (const auto& item : hookCtx_) {
764         if (item == nullptr) {
765             PROFILER_LOG_ERROR(LOG_CORE, "HookManager WriteHookConfig failed");
766             return;
767         }
768         item->stackPreprocess->WriteHookConfig();
769     }
770 }
771 
GetFds(int32_t pid,const std::string & name)772 std::pair<int, int> HookManager::GetFds(int32_t pid, const std::string& name)
773 {
774     for (const auto& item : hookCtx_) {
775         if (item->pid == pid || item->processName == name) {
776             if (item->pid == -1) {
777                 item->pid = pid;
778             }
779             item->stackPreprocess->SetPid(pid);
780             return {item->eventNotifier->GetFd(), item->shareMemoryBlock->GetfileDescriptor()};
781         }
782     }
783     return {-1, -1};
784 }
785 
SetNmdInfo(std::pair<uint32_t,uint32_t> info)786 void HookManager::SetNmdInfo(std::pair<uint32_t, uint32_t> info)
787 {
788     printMallocNmd_ = true;
789     nmdParamInfo_.fd = info.first;
790     nmdParamInfo_.type = info.second;
791 }
792 }