• 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_manager.h"
17 
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <unistd.h>
21 #include <map>
22 
23 #include "logging.h"
24 #include "init_param.h"
25 #include "common.h"
26 #include "network_profiler_common.h"
27 #include "plugin_service_types.pb.h"
28 #include "command_poller.h"
29 #include "epoll_event_poller.h"
30 #include "event_notifier.h"
31 
32 namespace {
33 constexpr int DEFAULT_EVENT_POLLING_INTERVAL = 5000;
34 constexpr uint32_t PAGE_BYTES = 4096;
35 constexpr uint32_t BUFFER_SIZE = (1UL << 23);
36 const std::string VERSION = "1.02";
37 const std::string PARAM_KAY = "hiviewdfx.hiprofiler.networkprofiler.target";
38 std::shared_ptr<Writer> g_buffWriter = nullptr;
39 }
40 
41 namespace OHOS::Developtools::Profiler {
NetworkProfilerManager()42 NetworkProfilerManager::NetworkProfilerManager()
43 {
44 }
45 
~NetworkProfilerManager()46 NetworkProfilerManager::~NetworkProfilerManager()
47 {
48     StopNetworkProfiler();
49 }
50 
Init()51 void NetworkProfilerManager::Init()
52 {
53     auto commandPoller = std::make_shared<CommandPoller>(shared_from_this());
54     CHECK_NOTNULL(commandPoller, NO_RETVAL, "create CommandPoller FAILED!");
55     CHECK_TRUE(commandPoller->OnConnect(), NO_RETVAL, "connect FAILED");
56     SetCommandPoller(commandPoller);
57     RegisterAgentPlugin("network-profiler");
58 }
59 
CheckConfig()60 bool NetworkProfilerManager::CheckConfig()
61 {
62     std::set<int32_t> pidCache;
63     for (const auto& pid : config_.pid()) {
64         if (pid > 0) {
65             if (COMMON::IsUserMode() && (!COMMON::CheckApplicationPermission(pid, ""))) {
66                 continue;
67             }
68             struct stat statBuf;
69             std::string pidPath = "/proc/" + std::to_string(pid) + "/status";
70             if (stat(pidPath.c_str(), &statBuf) != 0) {
71                 PROFILER_LOG_ERROR(LOG_CORE, "%s: hook process does not exist", __func__);
72                 return false;
73             } else {
74                 auto [iter, ret] = pidCache.emplace(pid);
75                 if (ret) {
76                     networkCtx_.emplace_back(std::make_shared<NetworkProfilerCtx>(pid));
77                     paramValue_ += std::to_string(pid) + ",";
78                 }
79                 continue;
80             }
81         }
82     }
83 
84     for (const auto& name : config_.startup_process_name()) {
85         if (name.empty()) {
86             continue;
87         }
88         if (COMMON::IsUserMode() && (!COMMON::CheckApplicationPermission(0, name))) {
89             continue;
90         }
91         int pidValue = -1;
92         bool isExist = COMMON::IsProcessExist(name, pidValue);
93         if (isExist) {
94             PROFILER_LOG_ERROR(LOG_CORE, "NetworkProfilerManager Process %s already exists", name.c_str());
95             return false;
96         } else {
97             paramValue_ += name + ",";
98             networkCtx_.emplace_back(std::make_shared<NetworkProfilerCtx>(name));
99         }
100     }
101 
102     for (const auto& name : config_.restart_process_name()) {
103         if (name.empty()) {
104             continue;
105         }
106         if (COMMON::IsUserMode() && (!COMMON::CheckApplicationPermission(0, name))) {
107             continue;
108         }
109         int pidValue = -1;
110         bool isExist = COMMON::IsProcessExist(name, pidValue);
111         if (isExist) {
112             auto [iter, ret] = pidCache.emplace(pidValue);
113             if (!ret) {
114                 PROFILER_LOG_ERROR(LOG_CORE,
115                     "NetworkProfilerManager process %s pid is %d, duplicate of pid list in config",
116                     name.c_str(), pidValue);
117                 return false;
118             }
119             paramValue_ += name + ",";
120             networkCtx_.emplace_back(std::make_shared<NetworkProfilerCtx>(pidValue, name, true));
121         } else {
122             PROFILER_LOG_ERROR(LOG_CORE, "NetworkProfilerManager Process %s does not exist", name.c_str());
123             return false;
124         }
125     }
126 
127     if (config_.flush_interval() == 0) {
128         config_.set_flush_interval(1);
129     }
130 
131     if (config_.clock_id() == NetworkProfilerConfig::UNKNOW) {
132         PROFILER_LOG_ERROR(LOG_CORE, "NetworkProfilerManager clock_id is unknow");
133         return false;
134     }
135     return true;
136 }
137 
GetClockId(NetworkProfilerConfig::ClockId clockType)138 clockid_t NetworkProfilerManager::GetClockId(NetworkProfilerConfig::ClockId clockType)
139 {
140     std::map<NetworkProfilerConfig::ClockId, clockid_t> clockMap = {
141         {NetworkProfilerConfig::BOOTTIME, CLOCK_BOOTTIME},
142         {NetworkProfilerConfig::REALTIME, CLOCK_REALTIME},
143         {NetworkProfilerConfig::REALTIME_COARSE, CLOCK_REALTIME_COARSE},
144         {NetworkProfilerConfig::MONOTONIC, CLOCK_MONOTONIC},
145         {NetworkProfilerConfig::MONOTONIC_COARSE, CLOCK_MONOTONIC_COARSE},
146         {NetworkProfilerConfig::MONOTONIC_RAW, CLOCK_MONOTONIC_RAW},
147     };
148 
149     return clockMap.find(clockType) != clockMap.end() ? clockMap[clockType] : CLOCK_BOOTTIME;
150 }
151 
StartNetworkProfiler()152 bool NetworkProfilerManager::StartNetworkProfiler()
153 {
154     if (!CheckConfig()) {
155         PROFILER_LOG_ERROR(LOG_CORE, "StartNetworkProfiler CheckConfig failed");
156         return false;
157     }
158     if (paramValue_.empty() || networkCtx_.empty()) {
159         PROFILER_LOG_ERROR(LOG_CORE, "StartNetworkProfiler ctx is empty");
160         return false;
161     }
162 
163     for (auto& item : networkCtx_) {
164         CHECK_TRUE(HandleNetworkProfilerContext(item), false, "HandleNetworkProfilerContext failed");
165     }
166 
167     socketService_ = std::make_shared<NetworkProfilerSocketService>(shared_from_this());
168     socketService_->SetConfig(config_.smb_pages() * PAGE_BYTES, config_.flush_interval(),
169         config_.block(), GetClockId(config_.clock_id()));
170 
171     int ret = SystemSetParameter(PARAM_KAY.c_str(), paramValue_.c_str());
172     PROFILER_LOG_INFO(LOG_CORE, "StartNetworkProfiler parameter: %s", paramValue_.c_str());
173     if (ret < 0) {
174         PROFILER_LOG_ERROR(LOG_CORE, "StartNetworkProfiler set parameter failed");
175         return false;
176     } else {
177         PROFILER_LOG_INFO(LOG_CORE, "StartNetworkProfiler set parameter success");
178     }
179     return true;
180 }
181 
StopNetworkProfiler()182 void NetworkProfilerManager::StopNetworkProfiler()
183 {
184     int ret = SystemSetParameter(PARAM_KAY.c_str(), "");
185     if (ret < 0) {
186         PROFILER_LOG_ERROR(LOG_CORE, "StopNetworkProfiler set parameter failed");
187     } else {
188         PROFILER_LOG_INFO(LOG_CORE, "StopNetworkProfiler set parameter success");
189     }
190 
191     socketService_ = nullptr;
192 
193     for (const auto& item : networkCtx_) {
194         if (item->eventPoller != nullptr) {
195             HILOG_ERROR(LOG_CORE, "eventPoller unset!");
196             if (item->eventNotifier != nullptr) {
197                 item->eventPoller->RemoveFileDescriptor(item->eventNotifier->GetFd());
198             }
199             item->eventPoller->Stop();
200             item->eventPoller->Finalize();
201             item->eventPoller = nullptr;
202         }
203 
204         if (item->shareMemoryBlock != nullptr) {
205             ShareMemoryAllocator::GetInstance().ReleaseMemoryBlockLocal(item->smbName);
206             item->shareMemoryBlock = nullptr;
207         }
208         if (item->eventNotifier != nullptr) {
209             item->eventNotifier = nullptr;
210         }
211         item->handle = nullptr;
212     }
213 }
214 
HandleNetworkProfilerContext(const std::shared_ptr<NetworkProfilerCtx> & ctx)215 bool NetworkProfilerManager::HandleNetworkProfilerContext(const std::shared_ptr<NetworkProfilerCtx>& ctx)
216 {
217     if (ctx == nullptr) {
218         return false;
219     }
220     if (ctx->pid > 0) {
221         ctx->smbName = "network_profiler_smb_" + std::to_string(ctx->pid);
222     } else if (!ctx->processName.empty()) {
223         ctx->smbName = "network_profiler_smb_" + ctx->processName;
224     } else {
225         PROFILER_LOG_ERROR(LOG_CORE, "HandleHookContext context error, pid: %d, process name: %s",
226             ctx->pid, ctx->processName.c_str());
227         return false;
228     }
229 
230     uint32_t bufferSize = static_cast<uint32_t>(config_.smb_pages() * PAGE_BYTES);
231     ctx->shareMemoryBlock = ShareMemoryAllocator::GetInstance().CreateMemoryBlockLocal(ctx->smbName, bufferSize);
232     CHECK_TRUE(ctx->shareMemoryBlock != nullptr, false, "CreateMemoryBlockLocal FAIL %s", ctx->smbName.c_str());
233 
234     ctx->eventNotifier = EventNotifier::Create(0, EventNotifier::NONBLOCK);
235     CHECK_NOTNULL(ctx->eventNotifier, false, "create EventNotifier for %s failed!", ctx->smbName.c_str());
236 
237     // start event poller task
238     ctx->eventPoller = std::make_unique<EpollEventPoller>(DEFAULT_EVENT_POLLING_INTERVAL);
239     CHECK_NOTNULL(ctx->eventPoller, false, "create event poller FAILED!");
240 
241     ctx->eventPoller->Init();
242     ctx->eventPoller->Start();
243 
244     PROFILER_LOG_INFO(LOG_CORE, "%s smbFd = %d, eventFd = %d\n", ctx->smbName.c_str(),
245         ctx->shareMemoryBlock->GetfileDescriptor(), ctx->eventNotifier->GetFd());
246 
247     ctx->handle = std::make_shared<NetworkProfilerHandle>(CLOCK_REALTIME, BUFFER_SIZE, isProtobufSerialize_);
248     if (isProtobufSerialize_) {
249         ctx->handle->SetWriter(g_buffWriter);
250     } else {
251         ctx->handle->SetWriter(const_cast<WriterStructPtr>(writerAdapter_->GetStruct()));
252     }
253 
254     ctx->eventPoller->AddFileDescriptor(
255         ctx->eventNotifier->GetFd(),
256         [this, ctx] { this->ReadShareMemory(ctx); }
257     );
258     PROFILER_LOG_DEBUG(LOG_CORE, "network profiler context: pid: %d, processName: %s, eventFd: %d, shmFd: %d",
259         ctx->pid, ctx->processName.c_str(), ctx->eventNotifier->GetFd(), ctx->shareMemoryBlock->GetfileDescriptor());
260     return true;
261 }
262 
ReadShareMemory(std::shared_ptr<NetworkProfilerCtx> ctx)263 void NetworkProfilerManager::ReadShareMemory(std::shared_ptr<NetworkProfilerCtx> ctx)
264 {
265     ctx->eventNotifier->Take();
266     while (true) {
267         bool ret = ctx->shareMemoryBlock->TakeData([&](const int8_t data[], uint32_t size) -> bool {
268             ctx->handle->SerializeData(data, size);
269             return true;
270         });
271         if (!ret) {
272             break;
273         }
274     }
275 }
276 
GetNetworkProfilerCtx(int32_t pid,const std::string & name)277 std::pair<int, int> NetworkProfilerManager::GetNetworkProfilerCtx(int32_t pid, const std::string& name)
278 {
279     for (const auto& item : networkCtx_) {
280         if (item->pid == pid || item->processName == name) {
281             if (item->restart && (item->pid == pid)) {
282                 return {0, 0};
283             }
284             PROFILER_LOG_DEBUG(LOG_CORE, "GetNetworkProfilerCtx: pid: %d, name: %s, eventFd: %d, shmFd: %d",
285                 pid, name.c_str(), item->eventNotifier->GetFd(), item->shareMemoryBlock->GetfileDescriptor());
286             item->handle->SetTargetProcessInfo(pid, name);
287             return {item->eventNotifier->GetFd(), item->shareMemoryBlock->GetfileDescriptor()};
288         }
289     }
290     return {-1, -1};
291 }
292 
LoadPlugin(const std::string & pluginPath)293 bool NetworkProfilerManager::LoadPlugin(const std::string& pluginPath)
294 {
295     return true;
296 }
297 
UnloadPlugin(const std::string & pluginPath)298 bool NetworkProfilerManager::UnloadPlugin(const std::string& pluginPath)
299 {
300     return true;
301 }
302 
UnloadPlugin(const uint32_t pluginId)303 bool NetworkProfilerManager::UnloadPlugin(const uint32_t pluginId)
304 {
305     return true;
306 }
307 
CreatePluginSession(const std::vector<ProfilerPluginConfig> & config)308 bool NetworkProfilerManager::CreatePluginSession(const std::vector<ProfilerPluginConfig>& config)
309 {
310     std::string cfgData = config[0].config_data();
311     if (config_.ParseFromArray(reinterpret_cast<const uint8_t*>(cfgData.c_str()), cfgData.size()) <= 0) {
312         PROFILER_LOG_ERROR(LOG_CORE, "%s:parseFromArray failed!", __func__);
313         return false;
314     }
315     return true;
316 }
317 
DestroyPluginSession(const std::vector<uint32_t> & pluginIds)318 bool NetworkProfilerManager::DestroyPluginSession(const std::vector<uint32_t>& pluginIds)
319 {
320     socketService_ = nullptr;
321     return true;
322 }
323 
StartPluginSession(const std::vector<uint32_t> & pluginIds,const std::vector<ProfilerPluginConfig> & config,PluginResult & result)324 bool NetworkProfilerManager::StartPluginSession(const std::vector<uint32_t>& pluginIds,
325     const std::vector<ProfilerPluginConfig>& config, PluginResult& result)
326 {
327     return StartNetworkProfiler();
328 }
329 
StopPluginSession(const std::vector<uint32_t> & pluginIds)330 bool NetworkProfilerManager::StopPluginSession(const std::vector<uint32_t>& pluginIds)
331 {
332     StopNetworkProfiler();
333     return true;
334 }
335 
ReportPluginBasicData(const std::vector<uint32_t> & pluginIds)336 bool NetworkProfilerManager::ReportPluginBasicData(const std::vector<uint32_t>& pluginIds)
337 {
338     return true;
339 }
340 
CreateWriter(std::string pluginName,uint32_t bufferSize,int smbFd,int eventFd,bool isProtobufSerialize)341 bool NetworkProfilerManager::CreateWriter(std::string pluginName, uint32_t bufferSize, int smbFd, int eventFd,
342     bool isProtobufSerialize)
343 {
344     PROFILER_LOG_INFO(LOG_CORE, "network CreateWriter isProtobufSerialize: %d", isProtobufSerialize);
345     writer_ = std::make_shared<BufferWriter>("network-profiler", VERSION, bufferSize, smbFd, eventFd, agentIndex_);
346     isProtobufSerialize_ = isProtobufSerialize;
347     if (!isProtobufSerialize_) {
348         writerAdapter_ = std::make_shared<WriterAdapter>(isProtobufSerialize_);
349         writerAdapter_->SetWriter(writer_);
350     } else {
351         g_buffWriter = writer_;
352     }
353     return true;
354 }
355 
ResetWriter(uint32_t pluginId)356 bool NetworkProfilerManager::ResetWriter(uint32_t pluginId)
357 {
358     g_buffWriter = nullptr;
359     return true;
360 }
361 
SetCommandPoller(const std::shared_ptr<CommandPoller> & p)362 void NetworkProfilerManager::SetCommandPoller(const std::shared_ptr<CommandPoller>& p)
363 {
364     commandPoller_ = p;
365 }
366 
RegisterAgentPlugin(const std::string & pluginPath)367 bool NetworkProfilerManager::RegisterAgentPlugin(const std::string& pluginPath)
368 {
369     RegisterPluginRequest request;
370     request.set_request_id(commandPoller_->GetRequestId());
371     request.set_path("builtin/" + pluginPath);
372     request.set_sha256("");
373     request.set_name(pluginPath);
374     request.set_buffer_size_hint(0);
375     RegisterPluginResponse response;
376 
377     if (commandPoller_->RegisterPlugin(request, response)) {
378         if (response.status() == ResponseStatus::OK) {
379             PROFILER_LOG_DEBUG(LOG_CORE, "response.plugin_id() = %d", response.plugin_id());
380             agentIndex_ = static_cast<int>(response.plugin_id());
381             PROFILER_LOG_DEBUG(LOG_CORE, "RegisterPlugin OK");
382         } else {
383             PROFILER_LOG_DEBUG(LOG_CORE, "RegisterPlugin FAIL 1");
384             return false;
385         }
386     } else {
387         PROFILER_LOG_DEBUG(LOG_CORE, "RegisterPlugin FAIL 2");
388         return false;
389     }
390     return true;
391 }
392 } // namespace OHOS::Developtools::Profiler
393