1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2022. 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 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 * See the License for the specific language governing permissions and
12 * limitations under the License.
13 */
14
15 #include <csignal>
16 #include <mutex>
17 #include <array>
18 #include <fcntl.h>
19 #include <unistd.h>
20 #include <sys/wait.h>
21
22 #include "common.h"
23 #include "hiebpf_plugin_config.pb.h"
24 #include "logging.h"
25 #include "plugin_module_api.h"
26 #include "trace_file_writer.h"
27
28 namespace {
29 constexpr uint32_t MAX_BUFFER_SIZE = 4 * 1024 * 1024;
30 std::mutex g_taskMutex;
31 constexpr int32_t RET_OK = 0;
32 constexpr int32_t RET_ERR = -1;
33 bool g_releaseResources = false;
34 HiebpfConfig g_config;
35 std::shared_ptr<TraceFileWriter> g_splitTraceWriter {nullptr};
36
RunCmd(std::string & cmd)37 void RunCmd(std::string& cmd)
38 {
39 std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose);
40 if (pipe == nullptr) {
41 PROFILER_LOG_ERROR(LOG_CORE, "HiebpfPlugin::RunCmd: create popen FAILED!");
42 return;
43 }
44 constexpr uint32_t readBufferSize = 4096;
45 std::array<char, readBufferSize> buffer;
46 std::string result;
47 while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
48 result += buffer.data();
49 }
50 PROFILER_LOG_INFO(LOG_CORE, "HiebpfPlugin::run command result: %s", result.c_str());
51 }
52 } // namespace
53
HiebpfSessionStart(const uint8_t * configData,uint32_t configSize)54 static int32_t HiebpfSessionStart(const uint8_t* configData, uint32_t configSize)
55 {
56 std::lock_guard<std::mutex> guard(g_taskMutex);
57 CHECK_TRUE(!g_releaseResources, 0, "%s: hiebpf released resources, return", __func__);
58 PROFILER_LOG_DEBUG(LOG_CORE, "enter");
59 if (configData == nullptr || configSize < 0) {
60 PROFILER_LOG_ERROR(LOG_CORE, "Parameter error");
61 return RET_ERR;
62 }
63
64 CHECK_TRUE(g_config.ParseFromArray(configData, configSize) > 0, RET_ERR, "Parameter parsing failed");
65
66 if (!g_config.split_outfile_name().empty()) {
67 g_splitTraceWriter = std::make_shared<TraceFileWriter>(g_config.split_outfile_name());
68 g_splitTraceWriter->WriteStandalonePluginData(
69 std::string(g_pluginModule.name) + "_config",
70 std::string(reinterpret_cast<const char *>(configData),
71 configSize));
72 g_splitTraceWriter->SetTimeSource();
73 }
74
75 size_t defaultSize = sizeof(g_pluginModule.outFileName);
76 CHECK_TRUE(sizeof(g_config.outfile_name().c_str()) <= defaultSize - 1, RET_ERR,
77 "The out file path more than %zu bytes", defaultSize);
78 int32_t ret = strncpy_s(g_pluginModule.outFileName, defaultSize, g_config.outfile_name().c_str(), defaultSize - 1);
79 CHECK_TRUE(ret == EOK, RET_ERR, "strncpy_s error! outfile is %s", g_config.outfile_name().c_str());
80 std::string cmd = g_config.cmd_line();
81 cmd += " --start true --output_file " + g_config.outfile_name();
82 RunCmd(cmd);
83 PROFILER_LOG_DEBUG(LOG_CORE, "leave");
84 return RET_OK;
85 }
86
HiebpfSessionStop()87 static int32_t HiebpfSessionStop()
88 {
89 std::lock_guard<std::mutex> guard(g_taskMutex);
90 CHECK_TRUE(!g_releaseResources, 0, "%s: hiebpf released resources, return", __func__);
91 PROFILER_LOG_DEBUG(LOG_CORE, "enter");
92
93 if (!g_config.split_outfile_name().empty()) {
94 CHECK_NOTNULL(g_splitTraceWriter, -1, "%s: writer is nullptr, SetDurationTime failed", __func__);
95 g_splitTraceWriter->SetDurationTime();
96 }
97
98 std::string stop = "hiebpf --stop true";
99 RunCmd(stop);
100
101 if (!g_config.split_outfile_name().empty()) { // write split file.
102 CHECK_NOTNULL(g_splitTraceWriter, -1, "%s: writer is nullptr, WriteStandaloneFile failed", __func__);
103 g_splitTraceWriter->WriteStandalonePluginFile(std::string(g_pluginModule.outFileName),
104 std::string(g_pluginModule.name), std::string(g_pluginModule.version), DataType::STANDALONE_DATA);
105 g_splitTraceWriter->Finish();
106 g_splitTraceWriter.reset();
107 g_splitTraceWriter = nullptr;
108 }
109 PROFILER_LOG_DEBUG(LOG_CORE, "leave");
110 return RET_OK;
111 }
112
113 static PluginModuleCallbacks g_callbacks = {
114 .onPluginSessionStart = HiebpfSessionStart,
115 .onPluginReportResult = nullptr,
116 .onPluginSessionStop = HiebpfSessionStop,
117 .onRegisterWriterStruct = nullptr,
118 };
119
120 EXPORT_API PluginModuleStruct g_pluginModule = {
121 .callbacks = &g_callbacks,
122 .name = "hiebpf-plugin",
123 .resultBufferSizeHint = MAX_BUFFER_SIZE,
124 .isStandaloneFileData = true,
125 .outFileName = "/data/local/tmp/hiebpf.data",
126 };