1/*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2021-2023. 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 "plugin_module.h"
17
18#include <dlfcn.h>
19#include <iostream>
20
21#include "logging.h"
22#include "plugin_module_api.h"
23
24PluginModule::PluginModule(const std::string& path)
25    : handle_(nullptr), running_(false), path_(path), structPtr_(nullptr) {}
26
27PluginModule::~PluginModule() {}
28
29std::string PluginModule::ComputeSha256()
30{
31    return "";
32}
33
34bool PluginModule::Load()
35{
36    if (handle_ != nullptr) {
37        PROFILER_LOG_DEBUG(LOG_CORE, "%s:already open", __func__);
38        return false;
39    }
40
41    handle_ = dlopen(path_.c_str(), RTLD_NODELETE);
42    if (handle_ == nullptr) {
43        PROFILER_LOG_DEBUG(LOG_CORE, "%s:dlopen err:%s.", __func__, dlerror());
44        return false;
45    }
46    return true;
47}
48
49bool PluginModule::Unload()
50{
51    PROFILER_LOG_INFO(LOG_CORE, "%s:unload ready!", __func__);
52    if (handle_ != nullptr) {
53        int ret = dlclose(handle_);
54        PROFILER_LOG_INFO(LOG_CORE, "%s:unload plugin ret = %d", __func__, ret);
55        handle_ = nullptr;
56        structPtr_ = nullptr;
57        return true;
58    }
59
60    return false;
61}
62
63bool PluginModule::GetInfo(PluginModuleInfo& info)
64{
65    if (handle_ != nullptr) {
66        if (structPtr_ == nullptr) {
67            return false;
68        }
69        info.bufferSizeHint = structPtr_->resultBufferSizeHint;
70        info.name.assign(structPtr_->name);
71        info.isStandaloneFileData = structPtr_->isStandaloneFileData;
72        info.outFileName.assign(structPtr_->outFileName);
73        info.pluginVersion.assign(structPtr_->version);
74        return true;
75    }
76    return false;
77}
78
79PluginModule::SampleMode PluginModule::GetSampleMode() const
80{
81    if (structPtr_ && structPtr_->callbacks) {
82        if (structPtr_->callbacks->onPluginReportResult != nullptr) {
83            return SampleMode::POLLING;
84        } else if (structPtr_->callbacks->onRegisterWriterStruct != nullptr) {
85            return SampleMode::STREAMING;
86        }
87    }
88    return SampleMode::UNKNOWN;
89}
90
91void PluginModule::SetConfigData(const std::string& data)
92{
93    configData_ = data;
94}
95
96std::string PluginModule::GetConfigData() const
97{
98    return configData_;
99}
100
101void PluginModule::SetClockId(clockid_t clockId)
102{
103    clockId_ = clockId;
104    PROFILER_LOG_INFO(LOG_CORE, "SetClockId: plugin=%s, clock=%d", GetPluginName().c_str(), clockId);
105    if (writerAdapter_ != nullptr && writerAdapter_->GetWriter() != nullptr) {
106        writerAdapter_->GetWriter()->SetClockId(clockId);
107    }
108}
109
110clockid_t PluginModule::GetClockId() const
111{
112    return clockId_;
113}
114
115bool PluginModule::GetPluginName(std::string& pluginName)
116{
117    if (handle_ != nullptr) {
118        CHECK_NOTNULL(structPtr_, false, "structPtr_ is nullptr");
119        pluginName.assign(structPtr_->name);
120        return true;
121    }
122    return false;
123}
124
125bool PluginModule::GetBufferSizeHint(uint32_t& bufferSizeHint)
126{
127    if (handle_ != nullptr) {
128        CHECK_NOTNULL(structPtr_, false, "structPtr_ is nullptr");
129        bufferSizeHint = structPtr_->resultBufferSizeHint;
130        return true;
131    }
132    return false;
133}
134
135bool PluginModule::GetStandaloneFileData()
136{
137    if (handle_ != nullptr) {
138        CHECK_NOTNULL(structPtr_, false, "structPtr_ is nullptr");
139        return structPtr_->isStandaloneFileData;
140    }
141    return false;
142}
143
144bool PluginModule::GetOutFileName(std::string& outFileName)
145{
146    if (handle_ != nullptr) {
147        CHECK_NOTNULL(structPtr_, false, "structPtr_ is nullptr");
148        outFileName.assign(structPtr_->outFileName);
149        return true;
150    }
151    return false;
152}
153
154bool PluginModule::GetPluginVersion(std::string& pluginVersion)
155{
156    if (handle_ != nullptr) {
157        if (structPtr_ == nullptr) {
158            return false;
159        }
160        pluginVersion.assign(structPtr_->version);
161        return true;
162    }
163    return false;
164}
165
166std::string PluginModule::GetPath()
167{
168    return path_;
169}
170
171std::string PluginModule::GetPluginName()
172{
173    if (pluginName_ == "") {
174        if (handle_ != nullptr) {
175            CHECK_NOTNULL(structPtr_, "", "structPtr_ is nullptr");
176            pluginName_.assign(structPtr_->name);
177        }
178    }
179    return pluginName_;
180}
181
182bool PluginModule::IsLoaded()
183{
184    return (handle_ != nullptr);
185}
186
187bool PluginModule::IsRunning()
188{
189    return running_;
190}
191
192bool PluginModule::BindFunctions()
193{
194    CHECK_NOTNULL(handle_, false, "%s:plugin not load", __func__);
195    if (structPtr_ == nullptr) {
196        structPtr_ = static_cast<PluginModuleStruct*>(dlsym(handle_, "g_pluginModule"));
197        if (structPtr_ == nullptr) {
198            PROFILER_LOG_DEBUG(LOG_CORE, "%s:structPtr_ == nullptr", __func__);
199            return false;
200        }
201    }
202
203    if (structPtr_->callbacks == nullptr) {
204        PROFILER_LOG_DEBUG(LOG_CORE, "%s:structPtr_->callbacks == nullptr", __func__);
205        return false;
206    }
207
208    if ((structPtr_->callbacks->onPluginSessionStart == nullptr) ||
209        (structPtr_->callbacks->onPluginSessionStop == nullptr)) {
210        PROFILER_LOG_DEBUG(LOG_CORE, "%s:onPluginSessionStart == nullptr", __func__);
211        return false;
212    }
213
214    return true;
215}
216
217bool PluginModule::StartSession(const uint8_t* buffer, uint32_t size)
218{
219    PROFILER_LOG_DEBUG(LOG_CORE, "StartSession");
220    CHECK_NOTNULL(handle_, false, "%s:plugin not load", __func__);
221    if (structPtr_ != nullptr && structPtr_->callbacks != nullptr) {
222        if (structPtr_->callbacks->onPluginSessionStart) {
223            running_ = true;
224            return (structPtr_->callbacks->onPluginSessionStart(buffer, size) == 0);
225        }
226    }
227    return false;
228}
229
230bool PluginModule::StopSession()
231{
232    PROFILER_LOG_INFO(LOG_CORE, "%s:stop Session ready!", __func__);
233    CHECK_NOTNULL(handle_, false, "%s:plugin not load", __func__);
234    if (structPtr_ != nullptr && structPtr_->callbacks != nullptr) {
235        if (structPtr_->callbacks->onPluginSessionStop != nullptr) {
236            running_ = false;
237            return (structPtr_->callbacks->onPluginSessionStop() == 0);
238        }
239    }
240    return false;
241}
242
243bool PluginModule::ReportBasicData()
244{
245    PROFILER_LOG_INFO(LOG_CORE, "%s:report basic data ready!", __func__);
246    CHECK_NOTNULL(handle_, false, "%s:plugin not load", __func__);
247    if (structPtr_ != nullptr && structPtr_->callbacks != nullptr) {
248        if (structPtr_->callbacks->onReportBasicDataCallback != nullptr) {
249            return (structPtr_->callbacks->onReportBasicDataCallback() == 0);
250        }
251    }
252    return false;
253}
254
255int32_t PluginModule::ReportResult(uint8_t* buffer, uint32_t size)
256{
257    CHECK_NOTNULL(handle_, -1, "%s:plugin not load", __func__);
258    if (first_) {
259        lastTime_ = std::chrono::steady_clock::now();
260        first_ = false;
261    } else {
262        std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
263        lastTime_ = t1;
264    }
265
266    if (structPtr_ != nullptr && structPtr_->callbacks != nullptr) {
267        if (structPtr_->callbacks->onPluginReportResult != nullptr) {
268            return structPtr_->callbacks->onPluginReportResult(buffer, size);
269        }
270    }
271
272    return -1;
273}
274
275PluginReportResultOptimizeCallback PluginModule::ReportResultOptimize()
276{
277    CHECK_NOTNULL(handle_, nullptr, "%s:plugin not open", __func__);
278    if (first_) {
279        lastTime_ = std::chrono::steady_clock::now();
280        first_ = false;
281    } else {
282        std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
283        lastTime_ = t1;
284    }
285
286    if (structPtr_ != nullptr && structPtr_->callbacks != nullptr) {
287        if (structPtr_->callbacks->onPluginReportResultOptimize != nullptr) {
288            return structPtr_->callbacks->onPluginReportResultOptimize;
289        }
290    }
291
292    return nullptr;
293}
294
295bool PluginModule::RegisterWriter(const BufferWriterPtr writer, bool isProtobufSerialize)
296{
297    isProtobufSerialize_ = isProtobufSerialize;
298    writerAdapter_ = std::make_shared<WriterAdapter>(isProtobufSerialize);
299    writerAdapter_->SetWriter(writer);
300    CHECK_NOTNULL(writer, true, "%s:bufferWriter is null, update WriterAdapter only!", __func__);
301    if (structPtr_ != nullptr && structPtr_->callbacks != nullptr) {
302        if (structPtr_->callbacks->onRegisterWriterStruct != nullptr) {
303            return structPtr_->callbacks->onRegisterWriterStruct(writerAdapter_->GetStruct());
304        }
305    }
306    return true;
307}
308
309WriterPtr PluginModule::GetWriter()
310{
311    CHECK_NOTNULL(writerAdapter_, nullptr, "%s:pluginModule nullptr", __func__);
312    return writerAdapter_->GetWriter();
313}
314