• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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