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 }