1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 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 "native_memory_profiler_sa_service.h"
17 #include "native_memory_profiler_sa_death_recipient.h"
18 #include "iservice_registry.h"
19 #include "ipc_skeleton.h"
20 #include "trace_file_writer.h"
21 #include "socket_context.h"
22 #include "hook_common.h"
23 #include "init_param.h"
24 #include "token_setproc.h"
25 #include "accesstoken_kit.h"
26 #include "common.h"
27 #include "logging.h"
28 #include <sys/socket.h>
29
30 namespace OHOS::Developtools::NativeDaemon {
31 namespace {
32 constexpr int32_t TIME_BASE = 1000;
33 const std::string FILE_PATH_HEAD = "/data/local/tmp/native_memory_";
34 const std::string FILE_PATH_TAIL = ".htrace";
35 const std::string PRODUCT_CONFIG_PATH = "/sys_prod/etc/hiview/hiprofiler/hiprofiler_cfg.json";
36 constexpr int32_t DELAYED_SHUTDOWN_TIME = 20;
37 constexpr int FILE_MODE = 0644;
38 constexpr int32_t SIMP_NMD = 3;
39 constexpr int32_t NMD_WAIT_MS = 100;
40 constexpr int32_t NMD_WAIT_TIMES = 50;
41 constexpr int VEC_SHIFT = 2;
42
43 static std::unordered_map<std::string, std::shared_ptr<TaskConfig>> g_nameAndFilePathCtx;
44 static std::unordered_map<int32_t, std::shared_ptr<TaskConfig>> g_pidCtx;
45 static std::mutex g_mtx;
46 static ScheduleTaskManager g_scheduleTaskManager;
47 static bool g_hasStartupMode{false};
48 static int32_t g_taskNum{0};
49 static std::shared_ptr<ServiceEntry> g_serviceEntry{nullptr};
50 static int32_t g_delayedShutdownTimerFd{-1};
51 static std::unordered_map<uint32_t, std::pair<uint32_t, uint32_t>> g_nmdPidType;
52 static std::unordered_map<pid_t, int> g_pidFds;
53 static std::mutex g_pidFdMtx;
54 static std::unordered_map<pid_t, std::pair<uid_t, gid_t>> g_pidInfo;
55 }
56
NativeMemoryProfilerSaService()57 NativeMemoryProfilerSaService::NativeMemoryProfilerSaService() : SystemAbility(NATIVE_DAEMON_SYSTEM_ABILITY_ID, true)
58 {
59 serviceName_ = "HookService";
60 g_serviceEntry = std::make_shared<ServiceEntry>();
61 if (!g_serviceEntry->StartServer(DEFAULT_UNIX_SOCKET_HOOK_PATH,
62 reinterpret_cast<void (*)(int)>(&ClientDisconnectCallback))) {
63 g_serviceEntry = nullptr;
64 PROFILER_LOG_ERROR(LOG_CORE, "Start IPC Service FAIL");
65 return;
66 }
67 g_serviceEntry->RegisterService(*this);
68 DelayedShutdown(false);
69 }
70
~NativeMemoryProfilerSaService()71 NativeMemoryProfilerSaService::~NativeMemoryProfilerSaService()
72 {
73 g_serviceEntry = nullptr;
74 }
75
ClientDisconnectCallback(int socketFd)76 void NativeMemoryProfilerSaService::ClientDisconnectCallback(int socketFd)
77 {
78 std::unique_lock<std::mutex> lock(g_pidFdMtx);
79 pid_t pidval = 0;
80 for (auto iter = g_pidFds.begin(); iter != g_pidFds.end(); ++iter) {
81 if (iter->second == socketFd) {
82 pidval = iter->first;
83 break;
84 }
85 }
86 PROFILER_LOG_ERROR(LOG_CORE, "ClientDisconnectCallback get pid: %d", static_cast<int>(pidval));
87 lock.unlock();
88 StopHook(static_cast<uint32_t>(pidval));
89 }
90
StartServiceAbility()91 bool NativeMemoryProfilerSaService::StartServiceAbility()
92 {
93 sptr<ISystemAbilityManager> serviceManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
94 CHECK_NOTNULL(serviceManager, false, "serviceManager is nullptr");
95
96 static sptr<NativeMemoryProfilerSaService> native(new NativeMemoryProfilerSaService());
97 CHECK_NOTNULL(native, false, "native is nullptr");
98 int32_t result = serviceManager->AddSystemAbility(NATIVE_DAEMON_SYSTEM_ABILITY_ID, native);
99 if (result != 0) {
100 PROFILER_LOG_ERROR(LOG_CORE, "Service native memory failed to start");
101 return false;
102 }
103
104 auto abilityObject = serviceManager->AsObject();
105 CHECK_NOTNULL(abilityObject, false, "abilityObject is nullptr");
106
107 bool ret = abilityObject->AddDeathRecipient(new NativeMemoryProfilerSaDeathRecipient());
108 if (ret == false) {
109 PROFILER_LOG_ERROR(LOG_CORE, "AddDeathRecipient failed");
110 return false;
111 }
112 PROFILER_LOG_INFO(LOG_CORE, "Service native memory started successfully");
113 return true;
114 }
115
HasProfilingPermission()116 bool NativeMemoryProfilerSaService::HasProfilingPermission()
117 {
118 uint32_t callingTokenID = IPCSkeleton::GetCallingTokenID();
119 int res = Security::AccessToken::AccessTokenKit::VerifyAccessToken(callingTokenID,
120 "ohos.permission.ENABLE_PROFILER");
121 if (res != Security::AccessToken::PermissionState::PERMISSION_GRANTED) {
122 PROFILER_LOG_ERROR(LOG_CORE, "No profiling permission, please check!");
123 return false;
124 }
125 return true;
126 }
127
Start(std::shared_ptr<NativeMemoryProfilerSaConfig> & config)128 int32_t NativeMemoryProfilerSaService::Start(std::shared_ptr<NativeMemoryProfilerSaConfig>& config)
129 {
130 if (config->printNmd_) {
131 std::lock_guard<std::mutex> guard(nmdMtx_);
132 g_nmdPidType[config->nmdPid_] = std::make_pair(0, config->nmdType_);
133 if (!config->printNmdOnly_) {
134 return RET_OK;
135 }
136 }
137 return StartHook(config);
138 }
139
Start(std::shared_ptr<NativeMemoryProfilerSaConfig> & config,MessageParcel & reply)140 int32_t NativeMemoryProfilerSaService::Start(std::shared_ptr<NativeMemoryProfilerSaConfig>& config,
141 MessageParcel &reply)
142 {
143 if (config->printNmd_) {
144 std::lock_guard<std::mutex> guard(nmdMtx_);
145 g_nmdPidType[config->nmdPid_] = std::make_pair(0, config->nmdType_);
146 if (!config->printNmdOnly_) {
147 return RET_OK;
148 }
149 }
150 return StartHook(config, 0, reply);
151 }
152
Stop(uint32_t pid)153 int32_t NativeMemoryProfilerSaService::Stop(uint32_t pid)
154 {
155 StopHook(pid);
156 return RET_OK;
157 }
158
Stop(const std::string & name)159 int32_t NativeMemoryProfilerSaService::Stop(const std::string& name)
160 {
161 StopHook(0, name);
162 return RET_OK;
163 }
164
DumpData(uint32_t fd,std::shared_ptr<NativeMemoryProfilerSaConfig> & config)165 int32_t NativeMemoryProfilerSaService::DumpData(uint32_t fd, std::shared_ptr<NativeMemoryProfilerSaConfig>& config)
166 {
167 if (config->printNmd_) {
168 std::lock_guard<std::mutex> guard(nmdMtx_);
169 g_nmdPidType[config->nmdPid_] = std::make_pair(fd, config->nmdType_);
170 if (!config->printNmdOnly_) {
171 return RET_OK;
172 }
173 }
174 if (StartHook(config, fd) == RET_ERR) {
175 close(fd);
176 return RET_ERR;
177 }
178 return RET_OK;
179 }
180
CloseSocketFd(pid_t pid)181 void NativeMemoryProfilerSaService::CloseSocketFd(pid_t pid)
182 {
183 std::unique_lock<std::mutex> lock(g_pidFdMtx);
184 if ((g_pidFds.find(pid) != g_pidFds.end()) && (g_pidFds[pid] != 0)) {
185 int socketFd = g_pidFds[pid];
186 g_pidFds.erase(pid);
187 lock.unlock();
188 g_serviceEntry->RemoveContext(socketFd);
189 } else {
190 PROFILER_LOG_ERROR(LOG_CORE, "NativeMemoryProfilerSaService::CloseSocketFd pid invalid");
191 }
192 }
193
StopHook(uint32_t pid,std::string name)194 void NativeMemoryProfilerSaService::StopHook(uint32_t pid, std::string name)
195 {
196 if (!HasProfilingPermission()) {
197 PROFILER_LOG_ERROR(LOG_CORE, "StopHook failed, no profiling permission!");
198 return;
199 }
200 std::lock_guard<std::mutex> guard(g_mtx);
201 std::shared_ptr<TaskConfig> config = nullptr;
202 if (pid > 0) {
203 if (auto taskIter = g_pidCtx.find(pid); taskIter != g_pidCtx.end()) {
204 config = taskIter->second;
205 }
206 } else if (auto taskIter = g_nameAndFilePathCtx.find(name); taskIter != g_nameAndFilePathCtx.end()) {
207 config = taskIter->second;
208 pid = static_cast<pid_t>(config->hookMgr->GetPid());
209 }
210 if (config == nullptr) {
211 PROFILER_LOG_INFO(LOG_CORE, "NativeMemoryProfilerSaService: hook has stop, pid: %d, process name: %s",
212 pid, name.c_str());
213 return;
214 }
215 CloseSocketFd(static_cast<pid_t>(pid));
216 config->hookMgr->StopPluginSession({});
217 config->hookMgr->DestroyPluginSession({});
218 g_nameAndFilePathCtx.erase(config->processName);
219 g_nameAndFilePathCtx.erase(config->filePath);
220 g_pidCtx.erase(config->pid);
221 g_pidInfo.erase(static_cast<pid_t>(pid));
222 if (g_nmdPidType.find(config->pid) != g_nmdPidType.end()) {
223 g_nmdPidType.erase(config->pid);
224 }
225 if (config->isStartupMode) {
226 g_hasStartupMode = false;
227 }
228 if (config->fd > 0) {
229 close(config->fd);
230 }
231 if (--g_taskNum == 0) {
232 PROFILER_LOG_INFO(LOG_CORE, "StringViewMemoryHold clear");
233 StringViewMemoryHold::GetInstance().Clear();
234 DelayedShutdown(false);
235 }
236 }
237
GetCmdArgs(std::shared_ptr<NativeMemoryProfilerSaConfig> & config)238 std::string NativeMemoryProfilerSaService::GetCmdArgs(std::shared_ptr<NativeMemoryProfilerSaConfig>& config)
239 {
240 std::stringstream args;
241 args << "pid: " << COMMON::GetProcessNameByPid(config->pid_) << ", ";
242 args << "filter_size: " << config->filterSize_ << ", ";
243 args << "max_stack_depth: " << std::to_string(config->maxStackDepth_) << ", ";
244 args << "process_name: " << config->processName_ << ", ";
245 args << "malloc_disable: " << (config->mallocDisable_ ? "true" : "false") << ", ";
246 args << "mmap_disable: " << (config->mmapDisable_ ? "true" : "false") << ", ";
247 args << "free_stack_report: " << (config->freeStackData_ ? "true" : "false") << ", ";
248 args << "munmap_stack_report: " << (config->munmapStackData_ ? "true" : "false") << ", ";
249 args << "malloc_free_matching_interval: " << std::to_string(config->mallocFreeMatchingInterval_) << ", ";
250 args << "malloc_free_matching_cnt: " << std::to_string(config->mallocFreeMatchingCnt_) << ", ";
251 args << "string_compressed: " << (config->stringCompressed_ ? "true" : "false") << ", ";
252 args << "fp_unwind: " << (config->fpUnwind_ ? "true" : "false") << ", ";
253 args << "blocked: " << (config->blocked_ ? "true" : "false") << ", ";
254 args << "record_accurately: " << (config->recordAccurately_ ? "true" : "false") << ", ";
255 args << "startup_mode: " << (config->startupMode_ ? "true" : "false") << ", ";
256 args << "memtrace_enable: " << (config->memtraceEnable_ ? "true" : "false") << ", ";
257 args << "offline_symbolization: " << (config->offlineSymbolization_ ? "true" : "false") << ", ";
258 args << "callframe_compress: " << (config->callframeCompress_ ? "true" : "false") << ", ";
259 args << "statistics_interval: " << std::to_string(config->statisticsInterval_) << ", ";
260 args << "clock: " << std::to_string(config->clockId_) << ", ";
261 args << "sample_interval: " << std::to_string(config->sampleInterval_) << ", ";
262 args << "response_library_mode: " << (config->responseLibraryMode_ ? "true" : "false") << ", ";
263 args << "js_stack_report: " << std::to_string(config->jsStackReport_) << ", ";
264 args << "max_js_stack_depth: " << std::to_string(config->maxJsStackDepth_) << ", ";
265 args << "filter_napi_name: " << config->filterNapiName_ << ", ";
266 args << "nmd_pid: " << std::to_string(config->nmdPid_) << ", ";
267 args << "nmd_type: " << std::to_string(config->nmdType_) << ", ";
268 return args.str();
269 }
270
StartHookLock(std::shared_ptr<NativeMemoryProfilerSaConfig> & config,uint32_t fd,std::shared_ptr<HookManager> & hook,std::string & args)271 int32_t NativeMemoryProfilerSaService::StartHookLock(std::shared_ptr<NativeMemoryProfilerSaConfig>& config,
272 uint32_t fd, std::shared_ptr<HookManager>& hook,
273 std::string& args)
274 {
275 std::lock_guard<std::mutex> guard(g_mtx);
276 if (COMMON::GetProcessNameByPid(config->pid_) == "hiview") {
277 PROFILER_LOG_INFO(LOG_CORE, "NativeMemoryProfilerSaService: process name is hiview, return false");
278 return RET_ERR;
279 }
280 if (config->filePath_.empty() && fd == 0) {
281 std::string filePathStr = (config->pid_ > 0) ? std::to_string(config->pid_) : config->processName_;
282 config->filePath_ = FILE_PATH_HEAD + filePathStr + FILE_PATH_TAIL;
283 }
284 PROFILER_LOG_INFO(LOG_CORE, "file path: %s", config->filePath_.c_str());
285
286 if (!CheckConfig(config, fd)) {
287 COMMON::PluginWriteToHisysevent("native_hook_plugin", "hiview", args, COMMON::ErrorType::RET_MSG_EMPTY,
288 "check config failed");
289 return RET_ERR;
290 }
291
292 if (fd == 0) {
293 auto retFile = COMMON::CheckNotExistsFilePath(config->filePath_);
294 if (!retFile.first) {
295 PROFILER_LOG_INFO(LOG_CORE, "%s:check file path %s fail", __func__, config->filePath_.c_str());
296 COMMON::PluginWriteToHisysevent("native_hook_plugin", "hiview", args, COMMON::ErrorType::RET_INVALID_PATH,
297 "check file path failed");
298 return RET_ERR;
299 }
300 int fdTemp = open(retFile.second.c_str(), O_RDWR | O_CREAT, FILE_MODE);
301 CHECK_TRUE(fdTemp >= 0, RET_ERR, "Failed to open file(%s)", config->filePath_.c_str());
302 fd = static_cast<uint32_t>(fdTemp);
303 }
304 std::shared_ptr<TraceFileWriter> writeFile = nullptr;
305 if (config->printNmdOnly_) {
306 writeFile = std::make_shared<TraceFileWriter>(0);
307 } else {
308 writeFile = std::make_shared<TraceFileWriter>(fd);
309 }
310 CHECK_NOTNULL(writeFile, RET_ERR, "Failed to create TraceFileWriter");
311 writeFile->SetTimeSource();
312
313 hook->RegisterWriter(writeFile);
314 hook->SetSaMode(true);
315 hook->SetHookConfig(config);
316 if (config->hookstandalone_) {
317 hook->SetSaServiceConfig(true, true);
318 } else {
319 hook->SetSaServiceConfig(true, false);
320 }
321 if (config->pid_ > 0) {
322 std::lock_guard<std::mutex> nmdGuard(nmdMtx_);
323 if (g_nmdPidType.find(config->pid_) != g_nmdPidType.end()) {
324 hook->SetNmdInfo(g_nmdPidType[config->pid_]);
325 }
326 }
327 if (hook->CreatePluginSession() != RET_OK) {
328 COMMON::PluginWriteToHisysevent("native_hook_plugin", "hiview", args, COMMON::ErrorType::RET_FAIL,
329 "create pluginsession failed");
330 return RET_ERR;
331 }
332 if (!config->printNmdOnly_) {
333 hook->WriteHookConfig();
334 }
335 hook->StartPluginSession(&g_pidInfo);
336
337 int32_t timerFd = g_scheduleTaskManager.ScheduleTask(
338 [this, config] { this->StopHook(config->pid_, config->processName_); },
339 config->duration_ * TIME_BASE,
340 true);
341 if (timerFd == -1) {
342 PROFILER_LOG_ERROR(LOG_CORE, "NativeMemoryProfilerSaService Start Schedule Task failed");
343 COMMON::PluginWriteToHisysevent("native_hook_plugin", "hiview", args, COMMON::ErrorType::RET_FAIL,
344 "start schedule task failed");
345 return RET_ERR;
346 }
347
348 std::shared_ptr<TaskConfig> configCtx =
349 std::make_shared<TaskConfig>(hook, config->pid_, config->processName_, config->filePath_, timerFd,
350 config->startupMode_, fd);
351 CHECK_NOTNULL(hook, RET_ERR, "Failed to create TaskConfig");
352 if (!g_hasStartupMode && config->startupMode_) {
353 g_hasStartupMode = true;
354 startupModeProcessName_ = config->processName_;
355 }
356
357 if (configCtx->pid > 0) {
358 g_pidCtx[configCtx->pid] = configCtx;
359 } else if (!configCtx->processName.empty()) {
360 g_nameAndFilePathCtx[configCtx->processName] = configCtx;
361 }
362
363 if (fd == 0) {
364 g_nameAndFilePathCtx[configCtx->filePath] = configCtx;
365 }
366 ++g_taskNum;
367 DelayedShutdown(true);
368 COMMON::PluginWriteToHisysevent("native_hook_plugin", "hiview", args, COMMON::ErrorType::RET_SUCC, "success");
369 return RET_OK;
370 }
371
StartHook(std::shared_ptr<NativeMemoryProfilerSaConfig> & config,uint32_t fd)372 int32_t NativeMemoryProfilerSaService::StartHook(std::shared_ptr<NativeMemoryProfilerSaConfig>& config, uint32_t fd)
373 {
374 auto args = GetCmdArgs(config);
375 if (!HasProfilingPermission()) {
376 COMMON::PluginWriteToHisysevent("native_hook_plugin", "hiview", args, COMMON::ErrorType::RET_NO_PERMISSION,
377 "no profiling permission");
378 PROFILER_LOG_ERROR(LOG_CORE, "StartHook failed, no profiling permission!");
379 return RET_ERR;
380 }
381 if (config == nullptr) {
382 return RET_ERR;
383 }
384 std::shared_ptr<HookManager> hook = std::make_shared<HookManager>();
385 CHECK_NOTNULL(hook, RET_ERR, "Failed to create HookManager");
386
387 return StartHookLock(config, fd, hook, args);
388 }
389
WaitSimplifiedNmdTimeout(uint32_t times,std::shared_ptr<HookManager> & hook,MessageParcel & reply)390 static int32_t WaitSimplifiedNmdTimeout(uint32_t times, std::shared_ptr<HookManager>& hook, MessageParcel &reply)
391 {
392 uint32_t cnt = 0;
393 while ((!hook->nmdComplete_) && (cnt < times)) {
394 std::this_thread::sleep_for(std::chrono::milliseconds(NMD_WAIT_MS));
395 cnt++;
396 }
397 if (!hook->nmdComplete_) {
398 PROFILER_LOG_ERROR(LOG_CORE, "WaitSimplifiedNmdTimeout, %d ms", times * NMD_WAIT_MS);
399 return RET_ERR;
400 }
401 WRITESTRING(reply, hook->simplifiedNmd_, RET_ERR);
402 return RET_OK;
403 }
404
StartHook(std::shared_ptr<NativeMemoryProfilerSaConfig> & config,uint32_t fd,MessageParcel & reply)405 int32_t NativeMemoryProfilerSaService::StartHook(std::shared_ptr<NativeMemoryProfilerSaConfig>& config,
406 uint32_t fd, MessageParcel &reply)
407 {
408 auto args = GetCmdArgs(config);
409 if (!HasProfilingPermission()) {
410 COMMON::PluginWriteToHisysevent("native_hook_plugin", "hiview", args, COMMON::ErrorType::RET_NO_PERMISSION,
411 "no profiling permission");
412 PROFILER_LOG_ERROR(LOG_CORE, "StartHook failed, no profiling permission!");
413 return RET_ERR;
414 }
415 if (config == nullptr) {
416 return RET_ERR;
417 }
418 std::shared_ptr<HookManager> hook = std::make_shared<HookManager>();
419 CHECK_NOTNULL(hook, RET_ERR, "Failed to create HookManager");
420
421 int32_t ret = StartHookLock(config, fd, hook, args);
422 if (ret != RET_OK) {
423 return ret;
424 }
425
426 if (config->nmdType_ == SIMP_NMD) {
427 return WaitSimplifiedNmdTimeout(NMD_WAIT_TIMES, hook, reply);
428 }
429 return RET_OK;
430 }
431
CheckConfig(std::shared_ptr<NativeMemoryProfilerSaConfig> & config,uint32_t fd)432 bool NativeMemoryProfilerSaService::CheckConfig(std::shared_ptr<NativeMemoryProfilerSaConfig>& config, uint32_t fd)
433 {
434 auto maxTaskCount = GetValueFromJsonFile(PRODUCT_CONFIG_PATH, "hiprofiler_hook_process_count");
435 taskMaxNum_ = maxTaskCount > 0 ? maxTaskCount : taskMaxNum_;
436 if (g_taskNum + 1 > taskMaxNum_) {
437 PROFILER_LOG_INFO(LOG_CORE, "NativeMemoryProfilerSaService: Support up to 4 tasks at the same time");
438 return false;
439 }
440
441 if (g_hasStartupMode && config->startupMode_) {
442 PROFILER_LOG_INFO(LOG_CORE, "NativeMemoryProfilerSaService: tasks with an existing startup mode, name: %s",
443 startupModeProcessName_.c_str());
444 return false;
445 }
446
447 if (config->pid_ > 0) {
448 config->processName_.clear();
449 if (g_pidCtx.find(config->pid_) != g_pidCtx.end()) {
450 PROFILER_LOG_INFO(LOG_CORE, "NativeMemoryProfilerSaService: hook has started, pid: %d", config->pid_);
451 return false;
452 }
453 } else if (!config->processName_.empty()) {
454 if (g_nameAndFilePathCtx.find(config->processName_) != g_nameAndFilePathCtx.end()) {
455 PROFILER_LOG_INFO(LOG_CORE, "NativeMemoryProfilerSaService: hook has started, process name: %s",
456 config->processName_.c_str());
457 return false;
458 }
459 } else {
460 PROFILER_LOG_ERROR(LOG_CORE, "The PID and process name are not configured");
461 return false;
462 }
463
464 if (fd > 0) {
465 return true;
466 }
467
468 if (!config->filePath_.empty()) {
469 if (g_nameAndFilePathCtx.find(config->filePath_) != g_nameAndFilePathCtx.end()) {
470 PROFILER_LOG_ERROR(LOG_CORE,
471 "NativeMemoryProfilerSaService: File %s is being used.", config->filePath_.c_str());
472 return false;
473 }
474 } else {
475 PROFILER_LOG_ERROR(LOG_CORE, "The file path are not configured");
476 return false;
477 }
478 return true;
479 }
480
FillTaskConfigContext(int32_t pid,const std::string & name)481 void NativeMemoryProfilerSaService::FillTaskConfigContext(int32_t pid, const std::string& name)
482 {
483 std::lock_guard<std::mutex> guard(g_mtx);
484 if (auto iter = g_pidCtx.find(pid); iter != g_pidCtx.end()) {
485 iter->second->processName = name;
486 g_nameAndFilePathCtx[name] = iter->second;
487 if (iter->second->isStartupMode) {
488 g_hasStartupMode = false;
489 }
490 } else if (auto it = g_nameAndFilePathCtx.find(name); it != g_nameAndFilePathCtx.end()) {
491 it->second->pid = pid;
492 g_pidCtx[pid] = it->second;
493 if (it->second->isStartupMode) {
494 g_hasStartupMode = false;
495 }
496 } else {
497 PROFILER_LOG_ERROR(LOG_CORE, "NativeMemoryProfilerSaService: fill TaskConfig context failed");
498 }
499 }
500
ProtocolProc(SocketContext & context,uint32_t pnum,const int8_t * buf,const uint32_t size)501 bool NativeMemoryProfilerSaService::ProtocolProc(SocketContext &context, uint32_t pnum, const int8_t *buf,
502 const uint32_t size)
503 {
504 if (size != sizeof(int)) {
505 return false;
506 }
507 int peerConfig = *const_cast<int *>(reinterpret_cast<const int *>(buf));
508 if (peerConfig == -1) {
509 return false;
510 }
511
512 std::string filePath = "/proc/" + std::to_string(peerConfig) + "/cmdline";
513 std::string bundleName;
514 if (!LoadStringFromFile(filePath, bundleName)) {
515 PROFILER_LOG_ERROR(LOG_CORE, "Get process name by pid failed!, pid: %d", peerConfig);
516 return false;
517 }
518 bundleName.resize(strlen(bundleName.c_str()));
519
520 if (bundleName.substr(0, 2) == "./") { // 2: size, Command line programs will be prefixed with "./"
521 bundleName = bundleName.substr(2); // 2: point
522 }
523 bool startupMode = g_hasStartupMode;
524 FillTaskConfigContext(peerConfig, bundleName); // Save the relevant context for subsequent inspection
525
526 std::lock_guard<std::mutex> guard(g_mtx);
527 if (auto iter = g_pidCtx.find(peerConfig); iter != g_pidCtx.end()) {
528 if (!startupMode) {
529 int socketHandle = context.GetSocketHandle();
530 struct ucred cred;
531 socklen_t len = sizeof(struct ucred);
532 if (getsockopt(socketHandle, SOL_SOCKET, SO_PEERCRED, &cred, &len) == -1) {
533 PROFILER_LOG_ERROR(LOG_CORE, "ProtocolProc getsockopt failed");
534 return false;
535 }
536 if (!((g_pidInfo.find(cred.pid) != g_pidInfo.end()) && (g_pidInfo[cred.pid].first == cred.uid) &&
537 (g_pidInfo[cred.pid].second == cred.gid))) {
538 PROFILER_LOG_ERROR(LOG_CORE, "ProtocolProc process uid gid check failed");
539 return false;
540 }
541 }
542 iter->second->hookMgr->SetPid(peerConfig);
543 PROFILER_LOG_INFO(LOG_CORE,
544 "ProtocolProc, receive message from hook client, and send hook config to process %d, name: %s",
545 peerConfig, bundleName.c_str());
546 ClientConfig clientConfig;
547 iter->second->hookMgr->GetClientConfig(clientConfig);
548 if (iter->second->hookMgr->GetNoDataQueueFlag()) {
549 clientConfig.freeEventOnlyAddrEnable = true;
550 }
551 clientConfig.isSaMode = true;
552 context.SendHookConfig(reinterpret_cast<uint8_t *>(&clientConfig), sizeof(clientConfig));
553 int sharedMemCount = (clientConfig.offlineSymbolization) ? SHARED_MEMORY_NUM : 1;
554 std::vector<int> fdVec = iter->second->hookMgr->GetFds(peerConfig, bundleName, sharedMemCount);
555 for (int i = 0; i < sharedMemCount; ++i) {
556 int eventFd = fdVec[i * VEC_SHIFT];
557 int smbFd = fdVec[i * VEC_SHIFT + 1];
558 if (eventFd == smbFd) {
559 PROFILER_LOG_ERROR(LOG_CORE,
560 "Get eventFd and smbFd failed!, name: %s, pid: %d", bundleName.c_str(), peerConfig);
561 return false;
562 }
563 context.SendFileDescriptor(smbFd);
564 context.SendFileDescriptor(eventFd);
565 }
566 iter->second->hookMgr->ResetStartupParam();
567 } else {
568 PROFILER_LOG_ERROR(LOG_CORE, "ProtocolProc: send config failed");
569 return false;
570 }
571 std::unique_lock<std::mutex> socketLock(g_pidFdMtx);
572 g_pidFds[static_cast<pid_t>(peerConfig)] = context.GetSocketHandle();
573 socketLock.unlock();
574 return true;
575 }
576
DelayedShutdown(bool cancel)577 void NativeMemoryProfilerSaService::DelayedShutdown(bool cancel)
578 {
579 if (cancel) {
580 g_scheduleTaskManager.UnscheduleTask(g_delayedShutdownTimerFd);
581 g_delayedShutdownTimerFd = -1;
582 } else {
583 int32_t timerFd = g_scheduleTaskManager.ScheduleTask(
584 []() {
585 int ret = SystemSetParameter("hiviewdfx.hiprofiler.native_memoryd.start", "0");
586 if (ret < 0) {
587 PROFILER_LOG_ERROR(LOG_CORE, "DelayedShutdown close sa failed");
588 } else {
589 PROFILER_LOG_INFO(LOG_CORE, "DelayedShutdown close sa success");
590 }
591 },
592 DELAYED_SHUTDOWN_TIME * TIME_BASE, true);
593 if (timerFd == -1) {
594 PROFILER_LOG_ERROR(LOG_CORE, "NativeMemoryProfilerSaService:DelayedShutdown Schedule Task failed");
595 return;
596 }
597 g_delayedShutdownTimerFd = timerFd;
598 }
599 }
600 } // namespace OHOS::Developtools::NativeDaemon