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_manager.h"
17
18 #include <cstdio>
19 #include <functional>
20 #include <iomanip>
21
22 #include "common.h"
23 #include "command_poller.h"
24 #include "common_types.pbencoder.h"
25 #include "logging.h"
26 #include "openssl/sha.h"
27 #include "plugin_service_types.pb.h"
28
29 namespace {
30 using namespace OHOS::Developtools::Profiler;
31 constexpr int FILE_READ_CHUNK_SIZE = 4096;
32 constexpr char HEX_CHARS[] = "0123456789abcdef";
33
34 #define HHB(v) (((v) & 0xF0) >> 4)
35 #define LHB(v) ((v) & 0x0F)
36
ComputeFileSha256(const std::string & path)37 std::string ComputeFileSha256(const std::string& path)
38 {
39 uint8_t out[SHA256_DIGEST_LENGTH];
40 uint8_t buffer[FILE_READ_CHUNK_SIZE];
41 char realPath[PATH_MAX + 1] = {0};
42
43 SHA256_CTX sha;
44 SHA256_Init(&sha);
45
46 size_t nbytes = 0;
47 if ((path.length() >= PATH_MAX) || (realpath(path.c_str(), realPath) == nullptr)) {
48 PROFILER_LOG_ERROR(LOG_CORE, "%s:path is invalid: %s, errno=%d", __func__, path.c_str(), errno);
49 return "";
50 }
51 std::unique_ptr<FILE, decltype(fclose)*> fptr(fopen(realPath, "rb"), fclose);
52 while ((nbytes = fread(buffer, 1, sizeof(buffer), fptr.get())) > 0) {
53 SHA256_Update(&sha, buffer, nbytes);
54 }
55 SHA256_Final(out, &sha);
56
57 std::string result;
58 result.reserve(SHA256_DIGEST_LENGTH + SHA256_DIGEST_LENGTH);
59 for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
60 result.push_back(HEX_CHARS[HHB(out[i])]);
61 result.push_back(HEX_CHARS[LHB(out[i])]);
62 }
63
64 PROFILER_LOG_DEBUG(LOG_CORE, "%s:%s-(%s)", __func__, path.c_str(), result.c_str());
65 return result;
66 }
67 } // namespace
68
~PluginManager()69 PluginManager::~PluginManager() {}
70
SetCommandPoller(const CommandPollerPtr & p)71 void PluginManager::SetCommandPoller(const CommandPollerPtr& p)
72 {
73 this->commandPoller_ = p;
74 }
75
AddPlugin(const std::string & pluginPath)76 bool PluginManager::AddPlugin(const std::string& pluginPath)
77 {
78 PluginModuleInfo info = {"", 0};
79 auto plugin = std::make_shared<PluginModule>(pluginPath);
80 CHECK_TRUE(plugin->Load(), false, "%s:load failed!", __func__);
81
82 if (!plugin->BindFunctions()) {
83 PROFILER_LOG_DEBUG(LOG_CORE, "%s:bindFunctions failed %s", __func__, pluginPath.c_str());
84 plugin->Unload();
85 return false;
86 }
87
88 if (!plugin->GetInfo(info)) {
89 PROFILER_LOG_DEBUG(LOG_CORE, "%s:getinfo failed!", __func__);
90 plugin->Unload();
91 return false;
92 }
93
94 std::string pluginName = info.name;
95 if (pluginIds_.find(pluginName) != pluginIds_.end()) {
96 PROFILER_LOG_DEBUG(LOG_CORE, "%s:already add", __func__);
97 plugin->Unload();
98 return false;
99 }
100 PROFILER_LOG_DEBUG(LOG_CORE, "%s:add plugin name = %s", __func__, pluginName.c_str());
101
102 if (!plugin->Unload()) {
103 PROFILER_LOG_DEBUG(LOG_CORE, "%s:unload failed!", __func__);
104 return false;
105 }
106
107 return RegisterPlugin(plugin, pluginPath, info);
108 }
109
RegisterPlugin(const PluginModulePtr & plugin,const std::string & pluginPath,const PluginModuleInfo & pluginInfo)110 bool PluginManager::RegisterPlugin(const PluginModulePtr& plugin, const std::string& pluginPath,
111 const PluginModuleInfo& pluginInfo)
112 {
113 RegisterPluginRequest request;
114 request.set_request_id(commandPoller_->GetRequestId());
115 request.set_path(pluginPath);
116 request.set_sha256(ComputeFileSha256(pluginPath));
117 RegisterPluginResponse response;
118 request.set_name(pluginInfo.name);
119 request.set_buffer_size_hint(pluginInfo.bufferSizeHint);
120 request.set_is_standalone_data(pluginInfo.isStandaloneFileData);
121 request.set_out_file_name(pluginInfo.outFileName);
122 request.set_plugin_version(pluginInfo.pluginVersion);
123 if (commandPoller_->RegisterPlugin(request, response)) {
124 if (response.status() == ResponseStatus::OK) {
125 PROFILER_LOG_DEBUG(LOG_CORE, "%s:response.plugin_id() = %d", __func__, response.plugin_id());
126 pluginIds_[pluginInfo.name] = response.plugin_id();
127 pluginModules_.insert(std::pair<uint32_t, std::shared_ptr<PluginModule>>(response.plugin_id(), plugin));
128 pluginPathAndNameMap_.insert(
129 {pluginPath, pluginInfo.name}
130 );
131 PROFILER_LOG_DEBUG(LOG_CORE, "%s:registerPlugin ok", __func__);
132 } else {
133 PROFILER_LOG_DEBUG(LOG_CORE, "%s:registerPlugin fail 1", __func__);
134 return false;
135 }
136 } else {
137 PROFILER_LOG_DEBUG(LOG_CORE, "%s:registerPlugin fail 2", __func__);
138 return false;
139 }
140
141 return true;
142 }
143
RemovePlugin(const std::string & pluginPath)144 bool PluginManager::RemovePlugin(const std::string& pluginPath)
145 {
146 CHECK_TRUE(pluginPathAndNameMap_.count(pluginPath) != 0, false,
147 "%s:not find plugin: %s", __func__, pluginPath.c_str());
148
149 std::string pluginName = pluginPathAndNameMap_[pluginPath];
150 auto it = pluginIds_.find(pluginName);
151 if (it == pluginIds_.end()) {
152 PROFILER_LOG_DEBUG(LOG_CORE, "%s:plugin not exist", __func__);
153 return false;
154 }
155 uint32_t index = it->second;
156
157 // stop plugin if plugin running
158 if (pluginModules_[index]->IsRunning()) {
159 PROFILER_LOG_WARN(LOG_CORE, "%s:plugin delete while using, stop plugin", __func__);
160
161 // delete schedule task if POLLING mode
162 if (pluginModules_[index]->GetSampleMode() == PluginModule::SampleMode::POLLING) {
163 PROFILER_LOG_WARN(LOG_CORE, "%s:delete schedule task plugin name = %s", __func__, pluginName.c_str());
164 if (!scheduleTaskManager_.UnscheduleTask(scheduleTask_[pluginName])) {
165 PROFILER_LOG_WARN(LOG_CORE, "%s:delete schedule task plugin name = %s failed!",
166 __func__, pluginName.c_str());
167 }
168 }
169
170 if (!pluginModules_[index]->StopSession()) {
171 PROFILER_LOG_WARN(LOG_CORE, "%s:plugin stop failed!", __func__);
172 }
173 }
174
175 // Unload plugin if plugin loaded
176 if (pluginModules_[index]->IsLoaded()) {
177 PROFILER_LOG_WARN(LOG_CORE, "%s:plugin delete while using, unload plugin", __func__);
178 if (!pluginModules_[index]->Unload()) {
179 PROFILER_LOG_WARN(LOG_CORE, "%s:unload plugin failed!", __func__);
180 }
181 }
182
183 UnregisterPluginRequest request;
184 request.set_request_id(commandPoller_->GetRequestId());
185 request.set_plugin_id(index);
186 UnregisterPluginResponse response;
187 if (commandPoller_->UnregisterPlugin(request, response)) {
188 if (response.status() != ResponseStatus::OK) {
189 PROFILER_LOG_DEBUG(LOG_CORE, "%s:registerPlugin fail 1", __func__);
190 return false;
191 }
192 } else {
193 PROFILER_LOG_DEBUG(LOG_CORE, "%s:registerPlugin fail 2", __func__);
194 return false;
195 }
196
197 auto itPluginModules = pluginModules_.find(index);
198 if (it == pluginIds_.end()) {
199 PROFILER_LOG_DEBUG(LOG_CORE, "%s:plugin not exist", __func__);
200 return false;
201 }
202 pluginModules_.erase(itPluginModules);
203 pluginIds_.erase(it);
204 return true;
205 }
206
LoadPlugin(const std::string & pluginName)207 bool PluginManager::LoadPlugin(const std::string& pluginName)
208 {
209 PROFILER_LOG_DEBUG(LOG_CORE, "%s:size = %zu", __func__, pluginIds_.size());
210 auto it = pluginIds_.find(pluginName);
211 CHECK_TRUE(it != pluginIds_.end(), false, "%s:plugin not exist", __func__);
212 uint32_t index = it->second;
213
214 if (!pluginModules_[index]->Load()) {
215 return false;
216 }
217 if (!pluginModules_[index]->BindFunctions()) {
218 return false;
219 }
220 return true;
221 }
222
UnloadPlugin(const std::string & pluginName)223 bool PluginManager::UnloadPlugin(const std::string& pluginName)
224 {
225 auto it = pluginIds_.find(pluginName);
226 if (it == pluginIds_.end()) {
227 PROFILER_LOG_DEBUG(LOG_CORE, "%s:plugin not exist", __func__);
228 return false;
229 }
230
231 return UnloadPlugin(it->second);
232 }
233
UnloadPlugin(const uint32_t pluginId)234 bool PluginManager::UnloadPlugin(const uint32_t pluginId)
235 {
236 PROFILER_LOG_INFO(LOG_CORE, "%s:ready!", __func__);
237 if (pluginModules_.find(pluginId) == pluginModules_.end()) {
238 PROFILER_LOG_DEBUG(LOG_CORE, "%s:plugin not exist", __func__);
239 return false;
240 }
241 if (!pluginModules_[pluginId]->Unload()) {
242 return false;
243 }
244 return true;
245 }
246
CreatePluginSession(const std::vector<ProfilerPluginConfig> & config)247 bool PluginManager::CreatePluginSession(const std::vector<ProfilerPluginConfig>& config)
248 {
249 PROFILER_LOG_DEBUG(LOG_CORE, "%s:ready", __func__);
250
251 for (size_t idx = 0; idx < config.size(); ++idx) {
252 PROFILER_LOG_DEBUG(LOG_CORE, "%s:config->name() = %s", __func__, config[idx].name().c_str());
253 auto it = pluginIds_.find(config[idx].name());
254 if (it == pluginIds_.end()) {
255 PROFILER_LOG_DEBUG(LOG_CORE, "%s:plugin not find", __func__);
256 return false;
257 }
258
259 PROFILER_LOG_INFO(LOG_CORE, "%s:index = %d, clock = %s", __func__, it->second, config[idx].clock().c_str());
260 pluginModules_[it->second]->SetConfigData(config[idx].config_data());
261 pluginModules_[it->second]->SetClockId(COMMON::GetClockId(config[idx].clock()));
262 }
263 return true;
264 }
265
DestroyPluginSession(const std::vector<uint32_t> & pluginIds)266 bool PluginManager::DestroyPluginSession(const std::vector<uint32_t>& pluginIds)
267 {
268 for (uint32_t id : pluginIds) {
269 auto it = pluginModules_.find(id);
270 if (it == pluginModules_.end()) {
271 PROFILER_LOG_DEBUG(LOG_CORE, "%s:plugin not find", __func__);
272 return false;
273 }
274 }
275 return true;
276 }
277
StartPluginSession(const std::vector<uint32_t> & pluginIds,const std::vector<ProfilerPluginConfig> & config,PluginResult & result)278 bool PluginManager::StartPluginSession(const std::vector<uint32_t>& pluginIds,
279 const std::vector<ProfilerPluginConfig>& config, PluginResult& result)
280 {
281 PROFILER_LOG_INFO(LOG_CORE, "%s:ready!", __func__);
282 size_t idx = 0;
283
284 for (uint32_t id : pluginIds) {
285 auto it = pluginModules_.find(id);
286 if (it == pluginModules_.end()) {
287 PROFILER_LOG_DEBUG(LOG_CORE, "%s:plugin not find", __func__);
288 return false;
289 }
290 auto plugin = pluginModules_[id];
291 auto cfgData = plugin->GetConfigData();
292 if (!plugin->StartSession(reinterpret_cast<const uint8_t*>(cfgData.c_str()), cfgData.size())) {
293 return false;
294 }
295
296 if (plugin->GetSampleMode() == PluginModule::SampleMode::POLLING) {
297 if (idx > config.size()) {
298 PROFILER_LOG_WARN(LOG_CORE, "%s:idx %zu out of size %zu", __func__, idx, config.size());
299 return false;
300 }
301 if (config[idx].sample_interval() == 0) {
302 PROFILER_LOG_DEBUG(LOG_CORE, "%s:scheduleTask interval == 0 error!", __func__);
303 return false;
304 }
305 auto callback = std::bind(&PluginManager::PullResult, this, id, config[idx].is_protobuf_serialize());
306 int32_t timerFd = scheduleTaskManager_.ScheduleTask(callback, config[idx].sample_interval());
307 if (timerFd == -1) {
308 PROFILER_LOG_DEBUG(LOG_CORE, "%s:scheduleTask failed!", __func__);
309 return false;
310 }
311 scheduleTask_[config[idx].name()] = timerFd;
312 }
313
314 // need update standalone plugin output file name
315 if (plugin->GetStandaloneFileData()) {
316 std::string pluginOutFileName = "";
317 plugin->GetOutFileName(pluginOutFileName);
318 result.set_plugin_id(id);
319 result.set_out_file_name(pluginOutFileName);
320 }
321
322 idx++;
323 }
324
325 return true;
326 }
327
StopPluginSession(const std::vector<uint32_t> & pluginIds)328 bool PluginManager::StopPluginSession(const std::vector<uint32_t>& pluginIds)
329 {
330 PROFILER_LOG_INFO(LOG_CORE, "%s:ready!", __func__);
331 for (uint32_t id : pluginIds) {
332 if (pluginModules_.find(id) == pluginModules_.end()) {
333 PROFILER_LOG_DEBUG(LOG_CORE, "%s:plugin not find", __func__);
334 return false;
335 }
336 if (pluginModules_[id]->GetSampleMode() == PluginModule::SampleMode::POLLING) {
337 for (const auto& it : pluginIds_) {
338 if (it.second == id) {
339 PROFILER_LOG_DEBUG(LOG_CORE, "%s:find plugin name = %s", __func__, it.first.c_str());
340 if (!scheduleTaskManager_.UnscheduleTask(scheduleTask_[it.first])) {
341 return false;
342 }
343 }
344 }
345 }
346 if (!pluginModules_[id]->StopSession()) {
347 return false;
348 }
349 }
350 return true;
351 }
352
StopAllPluginSession()353 bool PluginManager::StopAllPluginSession()
354 {
355 std::vector<uint32_t> vecPluginIds;
356 for (std::map<uint32_t, std::shared_ptr<PluginModule>>::iterator it = pluginModules_.begin();
357 it != pluginModules_.end(); ++it) {
358 vecPluginIds.push_back(it->first);
359 }
360 return StopPluginSession(vecPluginIds);
361 }
362
ReportPluginBasicData(const std::vector<uint32_t> & pluginIds)363 bool PluginManager::ReportPluginBasicData(const std::vector<uint32_t>& pluginIds)
364 {
365 PROFILER_LOG_INFO(LOG_CORE, "%s:ready!", __func__);
366 for (uint32_t id : pluginIds) {
367 CHECK_TRUE(pluginModules_.find(id) != pluginModules_.end(), false, "%s:plugin not find", __func__);
368 // notify plugin to report basic data
369 CHECK_TRUE(pluginModules_[id]->ReportBasicData(), false, "%s:report basic data failed", __func__);
370 }
371 return true;
372 }
373
SubmitResult(const PluginResult & pluginResult)374 bool PluginManager::SubmitResult(const PluginResult& pluginResult)
375 {
376 PROFILER_LOG_INFO(LOG_CORE, "%s:ready!", __func__);
377 NotifyResultRequest request;
378 CHECK_NOTNULL(commandPoller_, false, "%s:commandPoller_ is null", __func__);
379 request.set_request_id(commandPoller_->GetRequestId());
380 request.set_command_id(0);
381 PluginResult* p = request.add_result();
382 *p = pluginResult;
383 NotifyResultResponse response;
384 if (!commandPoller_->NotifyResult(request, response)) {
385 PROFILER_LOG_DEBUG(LOG_CORE, "%s:fail 1", __func__);
386 return false;
387 }
388 if (response.status() != ResponseStatus::OK) {
389 PROFILER_LOG_DEBUG(LOG_CORE, "%s:fail 2", __func__);
390 return false;
391 }
392 PROFILER_LOG_DEBUG(LOG_CORE, "%s:ok", __func__);
393 return true;
394 }
395
PullResult(uint32_t pluginId,bool isProtobufSerialize)396 bool PluginManager::PullResult(uint32_t pluginId, bool isProtobufSerialize)
397 {
398 uint32_t size = 0;
399 std::string name = "";
400 std::string version = "";
401 auto it = pluginModules_.find(pluginId);
402 if (it == pluginModules_.end()) {
403 PROFILER_LOG_DEBUG(LOG_CORE, "%s:plugin not find", __func__);
404 return false;
405 }
406 pluginModules_[pluginId]->GetBufferSizeHint(size);
407 pluginModules_[pluginId]->GetPluginName(name);
408 pluginModules_[pluginId]->GetPluginVersion(version);
409
410 if (isProtobufSerialize) {
411 std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(size);
412 CHECK_NOTNULL(buffer, false, "%s:buffer new failed!", __func__);
413
414 int length = it->second->ReportResult(buffer.get(), size);
415 if (length < 0) {
416 return false;
417 }
418
419 ProfilerPluginData pluginData;
420 pluginData.set_name(name);
421 pluginData.set_version(version);
422 pluginData.set_status(0);
423 pluginData.set_data(buffer.get(), length);
424
425 struct timespec ts;
426 clockid_t clockId = pluginModules_[pluginId]->GetClockId();
427 clock_gettime(clockId, &ts);
428
429 pluginData.set_clock_id(static_cast<ProfilerPluginData_ClockId>(clockId));
430 pluginData.set_tv_sec(ts.tv_sec);
431 pluginData.set_tv_nsec(ts.tv_nsec);
432
433 auto writer = std::static_pointer_cast<BufferWriter>(pluginModules_[pluginId]->GetWriter());
434 CHECK_NOTNULL(writer, false, "PullResult GetWriter nullptr");
435
436 writer->WriteMessage(pluginData, name);
437 writer->Flush();
438 } else {
439 auto writer = std::static_pointer_cast<BufferWriter>(pluginModules_[pluginId]->GetWriter());
440 CHECK_NOTNULL(writer, false, "PullResult GetWriter nullptr");
441 auto writeCtx = writer->GetCtx();
442 CHECK_NOTNULL(writeCtx, false, "PullResult GetCtx nullptr");
443 writer->ResetPos();
444 ProtoEncoder::ProfilerPluginData pluginData(writeCtx);
445 pluginData.set_name(name);
446 pluginData.set_version(version);
447 pluginData.set_status(0);
448
449 auto callbackFunc = it->second->ReportResultOptimize();
450 if (callbackFunc != nullptr) {
451 pluginData.set_data(callbackFunc);
452 }
453
454 struct timespec ts;
455 clockid_t clockId = pluginModules_[pluginId]->GetClockId();
456 clock_gettime(clockId, &ts);
457
458 pluginData.set_clock_id(static_cast<ProfilerPluginData_ClockId>(clockId));
459 pluginData.set_tv_sec(ts.tv_sec);
460 pluginData.set_tv_nsec(ts.tv_nsec);
461
462 int32_t len = pluginData.Finish();
463 writer->UseMemory(len);
464 writer->Flush();
465 }
466 return true;
467 }
468
CreateWriter(std::string pluginName,uint32_t bufferSize,int smbFd,int eventFd,bool isProtobufSerialize)469 bool PluginManager::CreateWriter(std::string pluginName, uint32_t bufferSize, int smbFd, int eventFd,
470 bool isProtobufSerialize)
471 {
472 auto it = pluginIds_.find(pluginName);
473 if (it == pluginIds_.end()) {
474 PROFILER_LOG_DEBUG(LOG_CORE, "%s:plugin not exist", __func__);
475 return false;
476 }
477 uint32_t index = it->second;
478
479 if (bufferSize > 0) {
480 PROFILER_LOG_DEBUG(LOG_CORE, "%s:%s Use ShareMemory %d", __func__, pluginName.c_str(), bufferSize);
481 std::string pluginVersion = "";
482 pluginModules_[index]->GetPluginVersion(pluginVersion);
483 pluginModules_[index]->RegisterWriter(std::make_shared<BufferWriter>
484 (pluginName, pluginVersion, bufferSize, smbFd, eventFd, index), isProtobufSerialize);
485 } else {
486 PROFILER_LOG_ERROR(LOG_CORE, "%s:no shared memory buffer allocated!", __func__);
487 return false;
488 }
489 return true;
490 }
491
ResetWriter(uint32_t pluginId)492 bool PluginManager::ResetWriter(uint32_t pluginId)
493 {
494 if (pluginModules_.find(pluginId) == pluginModules_.end()) {
495 PROFILER_LOG_DEBUG(LOG_CORE, "%s:plugin not exist", __func__);
496 return false;
497 }
498 PROFILER_LOG_DEBUG(LOG_CORE, "%s:resetWriter %u", __func__, pluginId);
499 pluginModules_[pluginId]->RegisterWriter(nullptr);
500 return true;
501 }
502