• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
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 
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 
37 namespace OHOS::Developtools::NativeDaemon {
38 const int DEFAULT_EVENT_POLLING_INTERVAL = 5000;
39 const int PAGE_BYTES = 4096;
40 std::shared_ptr<BufferWriter> g_buffWriter;
41 constexpr uint32_t MAX_BUFFER_SIZE = 10 * 1024;
42 const std::string STARTUP = "startup:";
43 const std::string PARAM_NAME = "libc.hook_mode";
44 const int MOVE_BIT_8 = 8;
45 const int MOVE_BIT_16 = 16;
46 const int MOVE_BIT_32 = 32;
47 const int SIGNAL_START_HOOK = 36;
48 const int SIGNAL_STOP_HOOK = 37;
49 const std::string VERSION = "1.02";
50 
CheckProcess()51 bool HookManager::CheckProcess()
52 {
53     if (pid_ != 0) {
54         int ret = 0;
55         std::string pid_path = std::string();
56         struct stat stat_buf;
57         pid_path = "/proc/" + std::to_string(pid_) + "/status";
58         if (stat(pid_path.c_str(), &stat_buf) != 0) {
59             pid_ = 0;
60             HILOG_ERROR(LOG_CORE, "%s: hook process does not exist", __func__);
61             return false;
62         } else {
63             return true;
64         }
65     } else if (hookConfig_.process_name() != "") {
66         // check if the pid and process name is consistency
67         CheckProcessName();
68     }
69 
70     return true;
71 }
72 
CheckProcessName()73 void HookManager::CheckProcessName()
74 {
75     int pidValue = -1;
76     const std::string processName = hookConfig_.process_name();
77     bool isExist = COMMON::IsProcessExist(processName, pidValue);
78     if (hookConfig_.startup_mode() || !isExist) {
79         HILOG_INFO(LOG_CORE, "Wait process %s start or restart, set param", hookConfig_.process_name().c_str());
80         std::string cmd = STARTUP + hookConfig_.process_name();
81         int ret = SystemSetParameter(PARAM_NAME.c_str(), cmd.c_str());
82         if (ret < 0) {
83             HILOG_WARN(LOG_CORE, "set param failed, please manually set param and start process(%s)",
84                        hookConfig_.process_name().c_str());
85         } else {
86             HILOG_INFO(LOG_CORE, "set param success, please start process(%s)", hookConfig_.process_name().c_str());
87         }
88     } else {
89         pid_ = pidValue;
90         HILOG_INFO(LOG_CORE, "Process %s exist, pid = %d", hookConfig_.process_name().c_str(), pid_);
91     }
92 }
93 
HookManager()94 HookManager::HookManager() : buffer_(new (std::nothrow) uint8_t[MAX_BUFFER_SIZE]), pid_(0) { }
95 
HookManager(std::shared_ptr<ShareMemoryBlock> & shareMemoryBlock,std::shared_ptr<EventNotifier> & eventNotifier,StackDataRepeaterPtr & stackData)96 HookManager::HookManager(std::shared_ptr<ShareMemoryBlock>& shareMemoryBlock,
97                          std::shared_ptr<EventNotifier>& eventNotifier,
98                          StackDataRepeaterPtr& stackData) : shareMemoryBlock_(shareMemoryBlock),
99                                                             eventNotifier_(eventNotifier),
100                                                             stackData_(stackData)
101 {
102 }
103 
SetCommandPoller(const std::shared_ptr<CommandPoller> & p)104 void HookManager::SetCommandPoller(const std::shared_ptr<CommandPoller>& p)
105 {
106     commandPoller_ = p;
107 }
108 
RegisterAgentPlugin(const std::string & pluginPath)109 bool HookManager::RegisterAgentPlugin(const std::string& pluginPath)
110 {
111     RegisterPluginRequest request;
112     request.set_request_id(commandPoller_->GetRequestId());
113     request.set_path(pluginPath);
114     request.set_sha256("");
115     request.set_name(pluginPath);
116     request.set_buffer_size_hint(0);
117     RegisterPluginResponse response;
118 
119     if (commandPoller_->RegisterPlugin(request, response)) {
120         if (response.status() == ResponseStatus::OK) {
121             HILOG_DEBUG(LOG_CORE, "response.plugin_id() = %d", response.plugin_id());
122             agentIndex_ = response.plugin_id();
123             HILOG_DEBUG(LOG_CORE, "RegisterPlugin OK");
124         } else {
125             HILOG_DEBUG(LOG_CORE, "RegisterPlugin FAIL 1");
126             return false;
127         }
128     } else {
129         HILOG_DEBUG(LOG_CORE, "RegisterPlugin FAIL 2");
130         return false;
131     }
132 
133     return true;
134 }
135 
UnregisterAgentPlugin(const std::string & pluginPath)136 bool HookManager::UnregisterAgentPlugin(const std::string& pluginPath)
137 {
138     UnregisterPluginRequest request;
139     request.set_request_id(commandPoller_->GetRequestId());
140     request.set_plugin_id(agentIndex_);
141     UnregisterPluginResponse response;
142     if (commandPoller_->UnregisterPlugin(request, response)) {
143         CHECK_TRUE(response.status() == ResponseStatus::OK, false, "UnregisterPlugin FAIL 1");
144     } else {
145         HILOG_DEBUG(LOG_CORE, "UnregisterPlugin FAIL 2");
146         return false;
147     }
148     agentIndex_ = -1;
149 
150     return true;
151 }
152 
LoadPlugin(const std::string & pluginPath)153 bool HookManager::LoadPlugin(const std::string& pluginPath)
154 {
155     return true;
156 }
157 
UnloadPlugin(const std::string & pluginPath)158 bool HookManager::UnloadPlugin(const std::string& pluginPath)
159 {
160     return true;
161 }
162 
UnloadPlugin(const uint32_t pluginId)163 bool HookManager::UnloadPlugin(const uint32_t pluginId)
164 {
165     return true;
166 }
167 
GetClientConfig(const NativeHookConfig & nativeHookConfig,ClientConfig & clientConfig)168 void HookManager::GetClientConfig(const NativeHookConfig& nativeHookConfig, ClientConfig& clientConfig)
169 {
170     clientConfig.shareMemroySize = static_cast<uint32_t>(hookConfig_.smb_pages() * PAGE_BYTES);
171     clientConfig.filterSize = static_cast<int32_t>(hookConfig_.filter_size());
172     clientConfig.clockId = COMMON::GetClockId(hookConfig_.clock());
173     clientConfig.maxStackDepth = hookConfig_.max_stack_depth();
174     clientConfig.mallocDisable = hookConfig_.malloc_disable();
175     clientConfig.mmapDisable = hookConfig_.mmap_disable();
176     clientConfig.freeStackData = hookConfig_.free_stack_report();
177     clientConfig.munmapStackData = hookConfig_.munmap_stack_report();
178     clientConfig.fpunwind = hookConfig_.fp_unwind();
179     clientConfig.isBlocked = hookConfig_.blocked();
180     clientConfig.memtraceEnable = hookConfig_.memtrace_enable();
181 }
182 
CreatePluginSession(const std::vector<ProfilerPluginConfig> & config)183 bool HookManager::CreatePluginSession(const std::vector<ProfilerPluginConfig>& config)
184 {
185     HILOG_DEBUG(LOG_CORE, "CreatePluginSession");
186     smbName_ = "hooknativesmb";
187     // save config
188     std::string cfgData = config[0].config_data();
189     CHECK_TRUE(hookConfig_.ParseFromArray(reinterpret_cast<const uint8_t*>(cfgData.c_str()), cfgData.size()) > 0,
190                false, "%s: ParseFromArray failed", __func__);
191 
192     CHECK_TRUE(getuid() == 0 || COMMON::CheckApplicationPermission(hookConfig_.pid(), hookConfig_.process_name()),
193                false, "Application debug permisson denied!");
194 
195     pid_ = hookConfig_.pid();
196 
197     int32_t uShortMax = (std::numeric_limits<unsigned short>::max)();
198     if (hookConfig_.filter_size() > uShortMax) {
199         HILOG_WARN(LOG_CORE, "%s: filter size invalid(size exceed 65535), reset to 65535!", __func__);
200         hookConfig_.set_filter_size(uShortMax);
201     }
202     if (!CheckProcess()) {
203         return false;
204     }
205 
206     // create smb and eventNotifier
207     uint32_t bufferSize = hookConfig_.smb_pages() * PAGE_BYTES; /* bufferConfig.pages() */
208     shareMemoryBlock_ = ShareMemoryAllocator::GetInstance().CreateMemoryBlockLocal(smbName_, bufferSize);
209     CHECK_TRUE(shareMemoryBlock_ != nullptr, false, "CreateMemoryBlockLocal FAIL %s", smbName_.c_str());
210 
211     eventNotifier_ = EventNotifier::Create(0, EventNotifier::NONBLOCK);
212     CHECK_NOTNULL(eventNotifier_, false, "create EventNotifier for %s failed!", smbName_.c_str());
213 
214     // start event poller task
215     eventPoller_ = std::make_unique<EpollEventPoller>(DEFAULT_EVENT_POLLING_INTERVAL);
216     CHECK_NOTNULL(eventPoller_, false, "create event poller FAILED!");
217 
218     eventPoller_->Init();
219     eventPoller_->Start();
220     eventPoller_->AddFileDescriptor(eventNotifier_->GetFd(), std::bind(&HookManager::ReadShareMemory, this));
221     HILOG_INFO(LOG_CORE, "hookservice smbFd = %d, eventFd = %d\n", shareMemoryBlock_->GetfileDescriptor(),
222                eventNotifier_->GetFd());
223 
224     if (hookConfig_.max_stack_depth() < DLOPEN_MIN_UNWIND_DEPTH) {
225         // set default max depth
226         hookConfig_.set_max_stack_depth(DLOPEN_MIN_UNWIND_DEPTH);
227     }
228 #if defined(__arm__)
229     hookConfig_.set_fp_unwind(false); // if OS is 32-bit,set fp_unwind false.
230 #endif
231     // offlinem symbolization, callframe must be compressed
232     if (hookConfig_.offline_symbolization()) {
233         hookConfig_.set_callframe_compress(true);
234     }
235 
236     // statistical reporting must be callframe compressed and accurate.
237     if (hookConfig_.statistics_interval() > 0) {
238         hookConfig_.set_callframe_compress(true);
239         hookConfig_.set_record_accurately(true);
240     }
241 
242     // callframe compressed, string must be compressed.
243     if (hookConfig_.callframe_compress()) {
244         hookConfig_.set_string_compressed(true);
245     }
246 
247     isRecordAccurately_ = hookConfig_.record_accurately();
248     HILOG_INFO(LOG_CORE, "hookConfig filter size = %d, malloc disable = %d mmap disable = %d",
249         hookConfig_.filter_size(), hookConfig_.malloc_disable(), hookConfig_.mmap_disable());
250     HILOG_INFO(LOG_CORE, "hookConfig fp unwind = %d, max stack depth = %d, record_accurately=%d",
251         hookConfig_.fp_unwind(), hookConfig_.max_stack_depth(), isRecordAccurately_);
252     HILOG_INFO(LOG_CORE, "hookConfig  offline_symbolization = %d", hookConfig_.offline_symbolization());
253 
254     ClientConfig clientConfig;
255     GetClientConfig(hookConfig_, clientConfig);
256     std::string clientConfigStr = clientConfig.ToString();
257     HILOG_INFO(LOG_CORE, "send hook client config:%s\n", clientConfigStr.c_str());
258     hookService_ = std::make_shared<HookService>(shareMemoryBlock_->GetfileDescriptor(),
259         eventNotifier_->GetFd(), pid_, hookConfig_.process_name(), clientConfig);
260     CHECK_NOTNULL(hookService_, false, "HookService create failed!");
261 
262     stackData_ = std::make_shared<StackDataRepeater>(STACK_DATA_SIZE);
263     CHECK_TRUE(stackData_ != nullptr, false, "Create StackDataRepeater FAIL");
264     clockid_t pluginDataClockId = COMMON::GetClockId(config[0].clock());
265     stackPreprocess_ = std::make_shared<StackPreprocess>(stackData_, hookConfig_, pluginDataClockId);
266     CHECK_TRUE(stackPreprocess_ != nullptr, false, "Create StackPreprocess FAIL");
267     stackPreprocess_->SetWriter(g_buffWriter);
268     return true;
269 }
270 
ReadShareMemory()271 void HookManager::ReadShareMemory()
272 {
273     CHECK_NOTNULL(shareMemoryBlock_, NO_RETVAL, "smb is null!");
274     uint64_t value = eventNotifier_->Take();
275     int rawRealSize = 0;
276     while (true) {
277         auto rawStack = std::make_shared<StackDataRepeater::RawStack>();
278         bool ret = shareMemoryBlock_->TakeData([&](const int8_t data[], uint32_t size) -> bool {
279             CHECK_TRUE(size >= sizeof(BaseStackRawData), false, "stack data invalid!");
280 
281             rawStack->baseStackData = std::make_unique<uint8_t[]>(size);
282             CHECK_TRUE(memcpy_s(rawStack->baseStackData.get(), size, data, size) == EOK, false,
283                        "memcpy_s raw data failed!");
284 
285             rawStack->stackConext = reinterpret_cast<BaseStackRawData*>(rawStack->baseStackData.get());
286             rawStack->data = rawStack->baseStackData.get() + sizeof(BaseStackRawData);
287             rawStack->reportFlag = true;
288             if (rawStack->stackConext->type == MEMORY_TAG || rawStack->stackConext->type == THREAD_NAME_MSG ||
289                 rawStack->stackConext->type == MMAP_FILE_TYPE || rawStack->stackConext->type == PR_SET_VMA_MSG) {
290                 return true;
291             }
292             rawStack->reduceStackFlag = false;
293             if (hookConfig_.fp_unwind()) {
294                 rawStack->fpDepth = (size - sizeof(BaseStackRawData)) / sizeof(uint64_t);
295                 return true;
296             } else {
297                 rawRealSize = sizeof(BaseStackRawData) + MAX_REG_SIZE * sizeof(char);
298             }
299 
300             rawStack->stackSize = size - rawRealSize;
301             if (rawStack->stackSize > 0) {
302                 rawStack->stackData = rawStack->baseStackData.get() + rawRealSize;
303             }
304             return true;
305         });
306         if (!ret) {
307             break;
308         }
309         if (rawStack->stackConext->type == MEMORY_TAG) {
310             std::string tagName = reinterpret_cast<char*>(rawStack->data);
311             stackPreprocess_->SaveMemTag(rawStack->stackConext->tagId, tagName);
312             continue;
313         }
314         if (!stackData_->PutRawStack(rawStack, isRecordAccurately_)) {
315             break;
316         }
317     }
318 }
319 
DestroyPluginSession(const std::vector<uint32_t> & pluginIds)320 bool HookManager::DestroyPluginSession(const std::vector<uint32_t>& pluginIds)
321 {
322     // release hook service
323     hookService_ = nullptr;
324 
325     // stop event poller
326     if (eventPoller_) {
327         HILOG_ERROR(LOG_CORE, "eventPoller_ unset!");
328         if (eventNotifier_ != nullptr) {
329             eventPoller_->RemoveFileDescriptor(eventNotifier_->GetFd());
330         }
331         eventPoller_->Stop();
332         eventPoller_->Finalize();
333         eventPoller_ = nullptr;
334     }
335 
336     // release smb and eventNotifier
337     if (shareMemoryBlock_) {
338         ShareMemoryAllocator::GetInstance().ReleaseMemoryBlockLocal(smbName_);
339         shareMemoryBlock_ = nullptr;
340     }
341 
342     if (eventNotifier_) {
343         eventNotifier_ = nullptr;
344     }
345 
346     stackPreprocess_ = nullptr;
347     stackData_ = nullptr;
348     return true;
349 }
350 
StartPluginSession(const std::vector<uint32_t> & pluginIds,const std::vector<ProfilerPluginConfig> & config,PluginResult & result)351 bool HookManager::StartPluginSession(const std::vector<uint32_t>& pluginIds,
352                                      const std::vector<ProfilerPluginConfig>& config, PluginResult& result)
353 {
354     UNUSED_PARAMETER(config);
355     CHECK_TRUE(stackPreprocess_ != nullptr, false, "start StackPreprocess FAIL");
356     stackPreprocess_->StartTakeResults();
357 
358     if (pid_ > 0) {
359         HILOG_INFO(LOG_CORE, "start command : send 36 signal to process  %d", pid_);
360         if (kill(pid_, SIGNAL_START_HOOK) == -1) {
361             const int bufSize = 256;
362             char buf[bufSize] = {0};
363             strerror_r(errno, buf, bufSize);
364             HILOG_ERROR(LOG_CORE, "send 36 signal error = %s", buf);
365         }
366     } else {
367         HILOG_INFO(LOG_CORE, "StartPluginSession: pid_(%d) is less or equal zero.", pid_);
368     }
369 
370     return true;
371 }
372 
StopPluginSession(const std::vector<uint32_t> & pluginIds)373 bool HookManager::StopPluginSession(const std::vector<uint32_t>& pluginIds)
374 {
375     // send signal
376     if (pid_ == 0 && hookService_ != nullptr) {
377         pid_ = hookService_->GetPid();
378     }
379     if (pid_ > 0) {
380         HILOG_INFO(LOG_CORE, "stop command : send 37 signal to process  %d", pid_);
381         if (kill(pid_, SIGNAL_STOP_HOOK) == -1) {
382             const int bufSize = 256;
383             char buf[bufSize] = {0};
384             strerror_r(errno, buf, bufSize);
385             HILOG_ERROR(LOG_CORE, "send 37 signal to process %d , error = %s", pid_, buf);
386         }
387     } else {
388         HILOG_INFO(LOG_CORE, "StopPluginSession: pid_(%d) is less or equal zero.", pid_);
389     }
390 
391     CHECK_TRUE(stackPreprocess_ != nullptr, false, "stop StackPreprocess FAIL");
392     HILOG_INFO(LOG_CORE, "start StopTakeResults");
393     stackPreprocess_->StopTakeResults();
394 
395     HILOG_INFO(LOG_CORE, "StopTakeResults success");
396     if (hookConfig_.statistics_interval() > 0) {
397         stackPreprocess_->FlushRecordStatistics();
398     }
399 
400     // make sure TakeResults thread exit
401     if (stackData_) {
402         stackData_->Close();
403     }
404     ResetStartupParam();
405     return true;
406 }
407 
ResetStartupParam()408 void HookManager::ResetStartupParam()
409 {
410     const std::string resetParam = "startup:disabled";
411     if (hookConfig_.startup_mode()) {
412         int ret = SystemSetParameter(PARAM_NAME.c_str(), resetParam.c_str());
413         if (ret < 0) {
414             HILOG_WARN(LOG_CORE, "set param failed, please reset param(%s)", PARAM_NAME.c_str());
415         } else {
416             HILOG_INFO(LOG_CORE, "reset param success");
417         }
418     }
419 }
420 
ReportPluginBasicData(const std::vector<uint32_t> & pluginIds)421 bool HookManager::ReportPluginBasicData(const std::vector<uint32_t>& pluginIds)
422 {
423     return true;
424 }
425 
CreateWriter(std::string pluginName,uint32_t bufferSize,int smbFd,int eventFd)426 bool HookManager::CreateWriter(std::string pluginName, uint32_t bufferSize, int smbFd, int eventFd)
427 {
428     HILOG_DEBUG(LOG_CORE, "agentIndex_ %d", agentIndex_);
429     RegisterWriter(std::make_shared<BufferWriter>(pluginName, VERSION, bufferSize, smbFd, eventFd, agentIndex_));
430     return true;
431 }
432 
ResetWriter(uint32_t pluginId)433 bool HookManager::ResetWriter(uint32_t pluginId)
434 {
435     RegisterWriter(nullptr);
436     return true;
437 }
438 
RegisterWriter(const BufferWriterPtr & writer)439 void HookManager::RegisterWriter(const BufferWriterPtr& writer)
440 {
441     g_buffWriter = writer;
442     return;
443 }
444 
SetHookConfig(const NativeHookConfig & hookConfig)445 void HookManager::SetHookConfig(const NativeHookConfig& hookConfig)
446 {
447     hookConfig_ = hookConfig;
448 }
449 }