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 }