1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2024. 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 "network_profiler.h"
17
18 #include <charconv>
19 #include <fstream>
20 #include <unistd.h>
21 #include <sched.h>
22 #include <sys/prctl.h>
23
24 #include "logging.h"
25
26 namespace {
27 CachedHandle g_cachedHandle;
28 #define EXPECTANTLY(exp) (__builtin_expect(!!(exp), true))
29 #define UNEXPECTANTLY(exp) (__builtin_expect(!!(exp), false))
30
31 std::mutex g_cachedMtx;
32 std::mutex g_mtx;
33 std::once_flag g_flag;
34 thread_local std::string g_threadName;
35 const std::string PARAM_KAY = "hiviewdfx.hiprofiler.networkprofiler.target";
36 static std::atomic<bool> g_serverClosing{false};
37 static std::atomic<bool> waitingConnect_{false};
38 static std::vector<OHOS::Developtools::Profiler::NetworkProfiler::CachedData> cachedData_;
39 static std::atomic<bool> enable_{false};
40 static std::shared_ptr<OHOS::Developtools::Profiler::NetworkProfilerSocketClient> socketClent_{nullptr};
41 static std::string processName_;
42 static int32_t pid_{0};
43 static int g_changed{0};
44 } // namespace
45
46 namespace OHOS::Developtools::Profiler {
47 NetworkProfiler* NetworkProfiler::instance_ = nullptr;
48
GetInstance()49 NetworkProfiler* NetworkProfiler::GetInstance()
50 {
51 if (instance_ == nullptr) {
52 std::unique_lock<std::mutex> lock(g_mtx);
53 if (instance_ == nullptr) {
54 instance_ = new (std::nothrow) NetworkProfiler();
55 }
56 }
57 return instance_;
58 }
59
NetworkProfiler()60 NetworkProfiler::NetworkProfiler()
61 {
62 pid_ = getprocpid();
63 processName_ = GetProcessNameByPid(pid_);
64 }
65
~NetworkProfiler()66 NetworkProfiler::~NetworkProfiler() {}
67
SetEnableFlag(bool flag)68 void NetworkProfiler::SetEnableFlag(bool flag)
69 {
70 enable_ = flag;
71 }
72
SetWaitingFlag(bool flag)73 void NetworkProfiler::SetWaitingFlag(bool flag)
74 {
75 waitingConnect_ = flag;
76 }
77
IsProfilerEnable()78 bool NetworkProfiler::IsProfilerEnable()
79 {
80 if (g_serverClosing) {
81 PROFILER_LOG_ERROR(LOG_CORE, "network profiler server is closing");
82 return false;
83 }
84 CheckNetworkProfilerParam();
85 return enable_ || waitingConnect_;
86 }
87
CheckNetworkProfilerParam()88 void NetworkProfiler::CheckNetworkProfilerParam()
89 {
90 if (UNEXPECTANTLY(g_cachedHandle == nullptr)) {
91 std::unique_lock<std::mutex> lock(g_mtx);
92 if (g_cachedHandle == nullptr) {
93 g_cachedHandle = CachedParameterCreate(PARAM_KAY.c_str(), "");
94 }
95 }
96 int changed = 0;
97 const char *paramValue = CachedParameterGetChanged(g_cachedHandle, &changed);
98 std::call_once(g_flag, [&]() { changed = 1; });
99
100 if ((UNEXPECTANTLY(changed == 1) || g_changed) && paramValue != nullptr) {
101 if (!enable_ && strlen(paramValue) > 0) {
102 std::vector<std::string> values;
103 SplitParamValue(paramValue, ",", values);
104 for (auto& item : values) {
105 int32_t pid = static_cast<int32_t>(strtoull(item.c_str(), nullptr, 0));
106 if (((pid > 0) && (pid == pid_)) || ((pid == 0) && (item == processName_))) {
107 Enable();
108 break;
109 }
110 }
111 }
112 }
113 }
114
Enable()115 void NetworkProfiler::Enable()
116 {
117 if (enable_) {
118 return;
119 }
120 waitingConnect_ = true;
121 socketClent_ = std::make_shared<NetworkProfilerSocketClient>(pid_, this,
122 reinterpret_cast<void (*)()>(&ServiceCloseCallback));
123 if (!socketClent_->ClientConnectState()) {
124 waitingConnect_ = false;
125 PROFILER_LOG_ERROR(LOG_CORE, "network profiler start failed");
126 return;
127 }
128 PROFILER_LOG_DEBUG(LOG_CORE, "network profiler clent start, pid: %d, processName: %s", pid_, processName_.c_str());
129 }
130
ServiceCloseCallback()131 void NetworkProfiler::ServiceCloseCallback()
132 {
133 bool expected = false;
134 if (g_serverClosing.compare_exchange_strong(expected, true, std::memory_order_release, std::memory_order_relaxed)) {
135 g_changed = 1;
136 Disable();
137 g_serverClosing = false;
138 g_changed = 0;
139 waitingConnect_ = false;
140 cachedData_.clear();
141 }
142 }
143
Disable()144 void NetworkProfiler::Disable()
145 {
146 if (!enable_) {
147 return;
148 }
149 PROFILER_LOG_DEBUG(LOG_CORE, "network profiler clent stop, pid: %d, processName: %s", pid_, processName_.c_str());
150 if (socketClent_) {
151 socketClent_->Reset();
152 }
153 enable_ = false;
154 }
155
SendCachedData()156 void NetworkProfiler::SendCachedData()
157 {
158 std::unique_lock<std::mutex> lock(g_cachedMtx);
159 for (size_t index = 0; index < cachedData_.size(); ++index) {
160 NetworkProfiling(cachedData_[index].cachedType, cachedData_[index].cachedData,
161 cachedData_[index].cachedDataSize);
162 }
163 cachedData_.clear();
164 }
165
NetworkProfiling(const uint8_t type,const char * data,size_t dataSize)166 void NetworkProfiler::NetworkProfiling(const uint8_t type, const char* data, size_t dataSize)
167 {
168 if (EXPECTANTLY((!enable_))) {
169 if (waitingConnect_) {
170 std::unique_lock<std::mutex> lock(g_cachedMtx);
171 cachedData_.push_back({type, data, dataSize});
172 }
173 return;
174 }
175 NetworkEvent event;
176 event.type = type;
177 event.tid = getproctid();
178 clock_gettime(clockType_, &event.ts);
179 GetThreadName(event.threadName);
180 if (g_threadName.size() == 0) {
181 GetThreadName(event.threadName);
182 } else {
183 if (sprintf_s(event.threadName, sizeof(event.threadName), "%s", g_threadName.c_str()) < 0) {
184 PROFILER_LOG_DEBUG(LOG_CORE, "sprintf_s event.threadName failed");
185 return;
186 }
187 }
188 NetworkProfilerSendData(reinterpret_cast<const void*>(&event), sizeof(event), data, dataSize);
189 }
190
NetworkProfilerSendData(const void * src,size_t size,const char * payload,size_t payloadSize)191 void NetworkProfiler::NetworkProfilerSendData(const void* src, size_t size, const char* payload, size_t payloadSize)
192 {
193 if (EXPECTANTLY((!enable_)) || src == nullptr) {
194 return;
195 }
196 std::weak_ptr<NetworkProfilerSocketClient> weakClient = socketClent_;
197 auto holder = weakClient.lock();
198 if (holder == nullptr) {
199 return;
200 }
201
202 if (!holder->SendNetworkProfilerData(src, size, payload, payloadSize)) {
203 PROFILER_LOG_ERROR(LOG_CORE, "network profiler SendNetworkProfilerData failed");
204 }
205 }
206
GetThreadName(const char * src)207 void NetworkProfiler::GetThreadName(const char* src)
208 {
209 prctl(PR_GET_NAME, src);
210 std::string tmp(src);
211 g_threadName = tmp;
212 }
213 } // namespace OHOS::Developtools::Profiler
214