• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 #include "hook_standalone.h"
16 #include <functional>
17 #include <linux/types.h>
18 #include "utilities.h"
19 #include "hook_service.h"
20 #include "logging.h"
21 #include "share_memory_allocator.h"
22 #include "event_notifier.h"
23 #include "epoll_event_poller.h"
24 #include "virtual_runtime.h"
25 
26 namespace OHOS {
27 namespace Developtools {
28 namespace Profiler {
29 namespace Hook {
30 const int DEFAULT_EVENT_POLLING_INTERVAL = 5000;
31 std::string g_smbName = "hooknativesmb";
32 std::shared_ptr<OHOS::Developtools::NativeDaemon::VirtualRuntime> g_runtimeInstance;
33 std::unique_ptr<EpollEventPoller> g_eventPoller_;
34 std::shared_ptr<ShareMemoryBlock> g_shareMemoryBlock;
35 std::shared_ptr<EventNotifier> g_eventNotifier;
36 std::shared_ptr<HookService> g_hookService;
37 uint32_t g_maxStackDepth;
38 std::unique_ptr<FILE, decltype(&fclose)> g_fpHookFile(nullptr, nullptr);
39 
writeFrames(int type,const struct timespec & ts,void * addr,uint32_t mallocSize,const std::vector<OHOS::Developtools::NativeDaemon::CallFrame> & callsFrames)40 void writeFrames(int type, const struct timespec& ts, void* addr, uint32_t mallocSize,
41     const std::vector<OHOS::Developtools::NativeDaemon::CallFrame>& callsFrames)
42 {
43     if (type == 0) {
44         fprintf(g_fpHookFile.get(), "malloc;%" PRId64 ";%ld;0x%" PRIx64 ";%u\n",
45                 (int64_t)ts.tv_sec, ts.tv_nsec, (uint64_t)addr, mallocSize);
46     } else if (type == 1) {
47         fprintf(g_fpHookFile.get(), "free;%" PRId64 ";%ld;0x%" PRIx64 "\n",
48                 (int64_t)ts.tv_sec, ts.tv_nsec, (uint64_t)addr);
49     } else {
50         return;
51     }
52 
53     for (size_t idx = 0, size = callsFrames.size(); idx < size; ++idx) {
54         (void)fprintf(g_fpHookFile.get(), "0x%" PRIx64 ";0x%" PRIx64 ";%s;%s;0x%" PRIx64 ";%" PRIu64 "\n",
55                       callsFrames[idx].ip_, callsFrames[idx].sp_, callsFrames[idx].symbolName_.c_str(),
56                       callsFrames[idx].filePath_.c_str(), callsFrames[idx].offset_, callsFrames[idx].symbolOffset_);
57     }
58 }
59 
ReadShareMemory(uint64_t duration,const std::string & performance_filename)60 void ReadShareMemory(uint64_t duration, const std::string& performance_filename)
61 {
62     CHECK_NOTNULL(g_shareMemoryBlock, NO_RETVAL, "smb is null!");
63     uint64_t value = g_eventNotifier->Take();
64 
65     static bool first_flag = true;
66     static bool end_flag = false;
67     static uint64_t times = 0;
68 
69     struct timespec first_time;
70     struct timespec begin_time;
71     struct timespec end_time;
72     uint64_t total_time = 0;
73 
74     while (true) {
75         bool ret = g_shareMemoryBlock->TakeData([&](const int8_t data[], uint32_t size) -> bool {
76             std::vector<u64> u64regs;
77             uint32_t *regAddr = nullptr;
78             uint32_t stackSize;
79             pid_t tid;
80             pid_t pid;
81             void *addr = nullptr;
82             int8_t* tmp = const_cast<int8_t *>(data);
83 
84             struct timespec ts = {};
85             if (memcpy_s(&ts, sizeof(ts), data, sizeof(ts)) != EOK) {
86                 HILOG_ERROR(LOG_CORE, "memcpy_s ts failed");
87             }
88             uint32_t type = *(reinterpret_cast<uint32_t *>(tmp + sizeof(ts)));
89             uint32_t mallocSize = *(reinterpret_cast<uint32_t *>(tmp + sizeof(ts) + sizeof(type)));
90             addr = *(reinterpret_cast<void **>(tmp + sizeof(ts) + sizeof(type) + sizeof(mallocSize)));
91             stackSize = *(reinterpret_cast<uint32_t *>(tmp + sizeof(ts)
92                 + sizeof(type) + sizeof(mallocSize) + sizeof(void *)));
93             std::unique_ptr<uint8_t[]> stackData = std::make_unique<uint8_t[]>(stackSize);
94             if (memcpy_s(stackData.get(), stackSize, tmp + sizeof(stackSize) + sizeof(ts) + sizeof(type)
95                 + sizeof(mallocSize) + sizeof(void *), stackSize) != EOK) {
96                 HILOG_ERROR(LOG_CORE, "memcpy_s data failed");
97             }
98             tid = *(reinterpret_cast<pid_t *>(tmp + sizeof(stackSize) + stackSize + sizeof(ts)
99                 + sizeof(type) + sizeof(mallocSize) + sizeof(void *)));
100             pid = *(reinterpret_cast<pid_t *>(tmp + sizeof(stackSize) + stackSize + sizeof(ts)
101                 + sizeof(type) + sizeof(mallocSize) + sizeof(void *) + sizeof(tid)));
102             regAddr = reinterpret_cast<uint32_t *>(tmp + sizeof(tid) + sizeof(pid) + sizeof(stackSize)
103                 + stackSize + sizeof(ts) + sizeof(type) + sizeof(mallocSize) + sizeof(void *));
104 
105             int reg_count = (size - sizeof(tid) - sizeof(pid) - sizeof(stackSize) - stackSize
106                 - sizeof(ts) - sizeof(type) - sizeof(mallocSize) - sizeof(void *))
107                 / sizeof(uint32_t);
108             if (reg_count <= 0) {
109                 HILOG_ERROR(LOG_CORE, "data error size = %u", size);
110             }
111             for (int idx = 0; idx < reg_count; ++idx) {
112                 u64regs.push_back(*regAddr++);
113             }
114 
115             if (!end_flag && duration != 0) {
116                 clock_gettime(CLOCK_REALTIME, &begin_time);
117                 if (first_flag) {
118                     first_flag = false;
119                     first_time = begin_time;
120                 }
121             }
122 
123             std::vector<OHOS::Developtools::NativeDaemon::CallFrame> callsFrames;
124             g_runtimeInstance->UnwindStack(u64regs, stackData.get(), stackSize, pid, tid, callsFrames,
125                 (g_maxStackDepth > 0) ? g_maxStackDepth : OHOS::Developtools::NativeDaemon::MAX_CALL_FRAME_UNWIND_SIZE);
126 
127             if (!end_flag && duration != 0) {
128                 clock_gettime(CLOCK_REALTIME, &end_time);
129                 total_time += (end_time.tv_sec - begin_time.tv_sec) * 1000000000LLU +
130                     (end_time.tv_nsec - begin_time.tv_nsec);
131                 ++times;
132                 if (end_time.tv_sec - first_time.tv_sec >= duration) {
133                     end_flag = true;
134                     FILE *fp = fopen(performance_filename.c_str(), "a");
135                     if (fp) {
136                         time_t now = time(NULL);
137                         struct tm now_tm;
138                         localtime_r(&now, &now_tm);
139                         fprintf(fp, "Current time: %04d-%02d-%02d %02d:%02d:%02d\n", now_tm.tm_year + 1900,
140                                 now_tm.tm_mon + 1, now_tm.tm_mday, now_tm.tm_hour, now_tm.tm_min, now_tm.tm_sec);
141                         fprintf(fp, "Total durations: %" PRIu64 " nanoseconds\n", total_time);
142                         fprintf(fp, "Total times: %" PRIu64 "\n", times);
143                         fprintf(fp, "Average unwinding stack time: %.2f  nanoseconds\n\n",
144                                 (double)(total_time) / times);
145                         fclose(fp);
146                         printf("Performance data has already been generated.\n");
147                     }
148                 }
149             }
150 
151             writeFrames(type, ts, addr, mallocSize, callsFrames);
152             return true;
153         });
154         if (!ret) {
155             break;
156         }
157     }
158 }
159 
StartHook(HookData & hookData)160 bool StartHook(HookData& hookData)
161 {
162     g_runtimeInstance = std::make_shared<OHOS::Developtools::NativeDaemon::VirtualRuntime>();
163     FILE *fp = fopen(hookData.fileName.c_str(), "wb+");
164     if (fp != nullptr) {
165         g_fpHookFile.reset();
166         g_fpHookFile = std::unique_ptr<FILE, decltype(&fclose)>(fp, fclose);
167     }
168     if (g_fpHookFile == nullptr) {
169         printf("create file failed!\n");
170         return false;
171     }
172     // create smb and eventNotifier
173     g_shareMemoryBlock = ShareMemoryAllocator::GetInstance().CreateMemoryBlockLocal(g_smbName, hookData.smbSize);
174 
175     g_eventNotifier = EventNotifier::Create(0, EventNotifier::NONBLOCK);
176 
177     // start event poller task
178     g_eventPoller_ = std::make_unique<EpollEventPoller>(DEFAULT_EVENT_POLLING_INTERVAL);
179     g_eventPoller_->Init();
180     g_eventPoller_->Start();
181 
182     g_eventPoller_->AddFileDescriptor(g_eventNotifier->GetFd(),
183                                       std::bind(ReadShareMemory, hookData.duration, hookData.performance_filename));
184 
185     HILOG_INFO(LOG_CORE, "hookservice smbFd = %d, eventFd = %d\n", g_shareMemoryBlock->GetfileDescriptor(),
186                g_eventNotifier->GetFd());
187 
188     // start service init socket
189     g_hookService = std::make_shared<HookService>(g_shareMemoryBlock->GetfileDescriptor(),
190         g_eventNotifier->GetFd(), hookData.filterSize, hookData.smbSize, hookData.pid, hookData.processName);
191 
192     g_maxStackDepth = hookData.maxStackDepth;
193     return true;
194 }
195 } // namespace Hook
196 } // namespace Profiler
197 } // namespace Developtools
198 } // namespace OHOS
199