• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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