• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2021-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 #include "hook_socket_client.h"
16 #include "runtime_stack_range.h"
17 #include "common.h"
18 #include "hook_common.h"
19 #include "unix_socket_client.h"
20 #include "share_memory_allocator.h"
21 #include "logging.h"
22 #include "sampling.h"
23 #include <unistd.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <fcntl.h>
27 #include <cstdio>
28 #include <cstdlib>
29 #include <cstring>
30 #include <iostream>
31 
32 namespace {
33 constexpr int FLUSH_FLAG = 20;
34 constexpr int ONLY_NMD_TYPE = 2;
35 constexpr int SIMP_NMD = 3;
36 std::atomic<bool> g_disableHook = true;
37 constexpr uint32_t MEMCHECK_DETAILINFO_MAXSIZE = 102400;
38 
39 struct OptArg {
40     size_t pos;
41     char *buf;
42 };
43 
44 } // namespace
45 
46 using namespace OHOS::Developtools::NativeDaemon;
GetRealTime()47 static std::string GetRealTime()
48 {
49     time_t now = time(nullptr);
50     tm tm;
51     const int timeLength = 64;
52     char stampStr[timeLength] = {0};
53 
54     if (localtime_r(&now, &tm) == nullptr || strftime(stampStr, timeLength, "%Y/%m/%d %H:%M:%S", &tm) == 0) {
55         return "error time format!";
56     }
57     return std::string(stampStr);
58 }
59 
NmdWriteStat(void * arg,const char * buf)60 static void NmdWriteStat(void *arg, const char *buf)
61 {
62     struct OptArg *opt = static_cast<struct OptArg*>(arg);
63     std::string getNmdTime = std::to_string(getpid()) + " " + GetRealTime() + "\n";
64     size_t nmdTimeLen = getNmdTime.size();
65     if (strncpy_s(opt->buf + opt->pos, MEMCHECK_DETAILINFO_MAXSIZE - opt->pos,
66                   getNmdTime.c_str(), nmdTimeLen) != EOK) {
67         return;
68     }
69     opt->pos += nmdTimeLen;
70 
71     size_t len = strlen(buf);
72     if (len + opt->pos + 1 > MEMCHECK_DETAILINFO_MAXSIZE) {
73         return;
74     }
75     if (strncpy_s(opt->buf + opt->pos, MEMCHECK_DETAILINFO_MAXSIZE - opt->pos, buf, len) != EOK) {
76         return;
77     }
78     opt->pos += len;
79 }
80 
HookSocketClient(int pid,ClientConfig * config,Sampling * sampler,std::atomic<Range> * targetedRange,std::atomic<int> * memCount,void (* disableHookCallback)())81 HookSocketClient::HookSocketClient(int pid, ClientConfig *config, Sampling *sampler,
82                                    std::atomic<Range>* targetedRange, std::atomic<int>* memCount,
83                                    void (*disableHookCallback)())
84     : pid_(pid), config_(config), sampler_(sampler), targetedRange_(targetedRange),
85       sharedMemCount_(memCount), disableHookCallback_(disableHookCallback)
86 {
87     g_disableHook = true;
88     int sharedMemCount = (config_->offlineSymbolization) ? SHARED_MEMORY_NUM : 1;
89     smbFds_.reserve(sharedMemCount);
90     eventFds_.reserve(sharedMemCount);
91     stackWriterList_.reserve(sharedMemCount);
92     unixSocketClient_ = nullptr;
93     serviceName_ = "HookService";
94     Connect(DEFAULT_UNIX_SOCKET_HOOK_FULL_PATH);
95 }
96 
~HookSocketClient()97 HookSocketClient::~HookSocketClient()
98 {
99     for (size_t i = 0; i < stackWriterList_.size(); ++i) {
100         if (stackWriterList_[i]) {
101             stackWriterList_[i]->Flush();
102         }
103         stackWriterList_[i] = nullptr;
104     }
105     unixSocketClient_ = nullptr;
106     g_disableHook = true;
107 }
108 
Connect(const std::string addrname)109 bool HookSocketClient::Connect(const std::string addrname)
110 {
111     if (unixSocketClient_ != nullptr) {
112         return false;
113     }
114     unixSocketClient_ = std::make_shared<UnixSocketClient>();
115     if (!unixSocketClient_->Connect(addrname, *this, disableHookCallback_)) {
116         unixSocketClient_ = nullptr;
117         return false;
118     }
119 
120     unixSocketClient_->SendHookConfig(reinterpret_cast<uint8_t *>(&pid_), sizeof(pid_));
121     return true;
122 }
123 
ProtocolProc(SocketContext & context,uint32_t pnum,const int8_t * buf,const uint32_t size)124 bool HookSocketClient::ProtocolProc(SocketContext &context, uint32_t pnum, const int8_t *buf, const uint32_t size)
125 {
126     if (size != sizeof(ClientConfig)) {
127         return true;
128     }
129     *config_ = *reinterpret_cast<ClientConfig *>(const_cast<int8_t*>(buf));
130     config_->maxStackDepth  = config_->maxStackDepth > MAX_UNWIND_DEPTH ? MAX_UNWIND_DEPTH : config_->maxStackDepth;
131     std::string configStr = config_->ToString();
132     sampler_->InitSampling(config_->sampleInterval);
133     int sharedMemCount = (config_->offlineSymbolization) ? SHARED_MEMORY_NUM : 1;
134     for (int i = 0; i < sharedMemCount; ++i) {
135         int smbfd = context.ReceiveFileDiscriptor();
136         int eventfd = context.ReceiveFileDiscriptor();
137         smbFds_.push_back(smbfd);
138         eventFds_.push_back(eventfd);
139         std::string smbName = "hooknativesmb_" + std::to_string(pid_) + ":" + std::to_string(i);
140         std::shared_ptr<StackWriter> stackWriter = std::make_shared<StackWriter>(smbName, config_->shareMemorySize,
141             smbfd, eventfd, config_->isBlocked, config_->isSaMode);
142         stackWriterList_.push_back(stackWriter);
143     }
144     nmdType_ = config_->nmdType;
145     g_disableHook = false;
146     if (sharedMemCount_ != nullptr) {
147         *sharedMemCount_ = sharedMemCount;
148     }
149     largestSize_ = config_->largestSize;
150     secondLargestSize_ = config_->secondLargestSize;
151     maxGrowthSize_ = config_->maxGrowthSize;
152     sampleInterval_ = config_->sampleInterval;
153     PROFILER_LOG_INFO(LOG_CORE, "HookSocketClient::ProtocolProc, ts1.1 = %d, ts1.2 = %d, ts2 = %d, ts3 = %d",
154         largestSize_, secondLargestSize_, maxGrowthSize_, sampleInterval_);
155     if (nmdType_ == 0 || nmdType_ == ONLY_NMD_TYPE) {
156         SendNmdInfo();
157     } else if (nmdType_ == SIMP_NMD) {
158         SendSimplifiedNmdInfo();
159     }
160     if (!config_->targetSoName.empty() && !ParseTargetedMaps(*targetedRange_, config_->targetSoName)) {
161         PROFILER_LOG_ERROR(LOG_CORE, "HookSocketClient::ProtocolProc ParseTargetedMaps failed!");
162         return false;
163     }
164     return true;
165 }
166 
SendStack(const void * data,size_t size)167 bool HookSocketClient::SendStack(const void* data, size_t size)
168 {
169     if (stackWriterList_.size() == 0 || stackWriterList_[0] == nullptr || unixSocketClient_ == nullptr) {
170         return false;
171     }
172 
173     if (!unixSocketClient_->SendHeartBeat()) {
174         return false;
175     }
176 
177     stackWriterList_[0]->WriteTimeout(data, size);
178     stackWriterList_[0]->Flush();
179 
180     return true;
181 }
182 
SendStackWithPayload(const void * data,size_t size,const void * payload,size_t payloadSize,int smbIndex)183 bool HookSocketClient::SendStackWithPayload(const void* data, size_t size, const void* payload,
184     size_t payloadSize, int smbIndex)
185 {
186     if (smbIndex + 1 > static_cast<int>(stackWriterList_.size())) {
187         return false;
188     }
189     std::shared_ptr<StackWriter> stackWriter = stackWriterList_[smbIndex];
190     if (stackWriter == nullptr || unixSocketClient_ == nullptr || g_disableHook) {
191         return false;
192     } else if (unixSocketClient_->GetClientState() == CLIENT_STAT_THREAD_EXITED) {
193         DisableHook();
194         return false;
195     }
196 
197     bool ret = stackWriter->WriteWithPayloadTimeout(data, size, payload, payloadSize,
198                                                     std::bind(&HookSocketClient::PeerIsConnected, this));
199     if (!ret && config_->isBlocked) {
200         DisableHook();
201         return false;
202     }
203     if (stackWriter->PrepareFlush()) {
204         stackWriter->Flush();
205     }
206     return true;
207 }
208 
Flush()209 void HookSocketClient::Flush()
210 {
211     for (size_t i = 0; i < stackWriterList_.size(); ++i) {
212         if (stackWriterList_[i] == nullptr || unixSocketClient_ == nullptr) {
213             return;
214         }
215         stackWriterList_[i]->Flush();
216     }
217 }
218 
DisableHook()219 void HookSocketClient::DisableHook()
220 {
221     bool expected = false;
222     if (g_disableHook.compare_exchange_strong(expected, true, std::memory_order_release, std::memory_order_relaxed)) {
223         HILOG_BASE_INFO(LOG_CORE, "%s", __func__);
224         if (disableHookCallback_) {
225             disableHookCallback_();
226         }
227     }
228 }
229 
PeerIsConnected()230 bool HookSocketClient::PeerIsConnected()
231 {
232     return !unixSocketClient_->IsConnected();
233 }
234 
SendNmdInfo()235 bool HookSocketClient::SendNmdInfo()
236 {
237     if ((!config_->printNmd) || (stackWriterList_.size() == 0)) {
238         return false;
239     }
240     void* nmdBuf = malloc(MEMCHECK_DETAILINFO_MAXSIZE);
241     if (nmdBuf == nullptr) {
242         return false;
243     }
244     struct OptArg opt = {0, reinterpret_cast<char*>(nmdBuf) };
245     malloc_stats_print(NmdWriteStat, &opt, "a");
246     StackRawData rawdata = {{{{0}}}};
247     rawdata.type = NMD_MSG;
248     if (stackWriterList_[0]) {
249         stackWriterList_[0]->WriteWithPayloadTimeout(&rawdata, sizeof(BaseStackRawData),
250                                                      reinterpret_cast<int8_t*>(opt.buf), strlen(opt.buf) + 1,
251                                                      std::bind(&HookSocketClient::PeerIsConnected, this));
252     }
253     stackWriterList_[0]->Flush();
254     free(nmdBuf);
255     return true;
256 }
257 
SendSimplifiedNmdInfo()258 bool HookSocketClient::SendSimplifiedNmdInfo()
259 {
260     if ((!config_->printNmd) || (stackWriterList_.size() == 0)) {
261         return false;
262     }
263     void* nmdBuf = malloc(MEMCHECK_DETAILINFO_MAXSIZE);
264     if (nmdBuf == nullptr) {
265         return false;
266     }
267     struct OptArg opt = {0, reinterpret_cast<char*>(nmdBuf) };
268     malloc_stats_print(NmdWriteStat, &opt, "s");
269     StackRawData rawdata = {{{{0}}}};
270     rawdata.type = NMD_MSG;
271     if (stackWriterList_[0]) {
272         stackWriterList_[0]->WriteWithPayloadTimeout(&rawdata, sizeof(BaseStackRawData),
273                                                      reinterpret_cast<int8_t*>(opt.buf), strlen(opt.buf) + 1,
274                                                      std::bind(&HookSocketClient::PeerIsConnected, this));
275     }
276     stackWriterList_[0]->Flush();
277     free(nmdBuf);
278     return true;
279 }
280 
SendEndMsg()281 bool HookSocketClient::SendEndMsg()
282 {
283     StackRawData rawdata = {{{{0}}}};
284     rawdata.type = END_MSG;
285     std::for_each(stackWriterList_.begin(), stackWriterList_.end(),
286         [&rawdata](std::shared_ptr<StackWriter>& writer) {
287         if (writer) {
288             writer->WriteTimeout(&rawdata, sizeof(BaseStackRawData));
289         }
290     });
291     return true;
292 }