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 }