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