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