• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     for (size_t idx = 0; idx < config.size(); ++idx) {
251         PROFILER_LOG_DEBUG(LOG_CORE, "%s:config->name() = %s", __func__, config[idx].name().c_str());
252         auto it = pluginIds_.find(config[idx].name());
253         if (it == pluginIds_.end()) {
254             PROFILER_LOG_DEBUG(LOG_CORE, "%s:plugin not find", __func__);
255             return false;
256         }
257 
258         PROFILER_LOG_INFO(LOG_CORE, "%s:index = %d, clock = %s", __func__, it->second, config[idx].clock().c_str());
259         pluginModules_[it->second]->SetConfigData(config[idx].config_data());
260         pluginModules_[it->second]->SetClockId(COMMON::GetClockId(config[idx].clock()));
261     }
262     return true;
263 }
264 
DestroyPluginSession(const std::vector<uint32_t> & pluginIds)265 bool PluginManager::DestroyPluginSession(const std::vector<uint32_t>& pluginIds)
266 {
267     for (uint32_t id : pluginIds) {
268         auto it = pluginModules_.find(id);
269         if (it == pluginModules_.end()) {
270             PROFILER_LOG_DEBUG(LOG_CORE, "%s:plugin not find", __func__);
271             return false;
272         }
273     }
274     return true;
275 }
276 
StartPluginSession(const std::vector<uint32_t> & pluginIds,const std::vector<ProfilerPluginConfig> & config,PluginResult & result)277 bool PluginManager::StartPluginSession(const std::vector<uint32_t>& pluginIds,
278                                        const std::vector<ProfilerPluginConfig>& config, PluginResult& result)
279 {
280     PROFILER_LOG_INFO(LOG_CORE, "%s:ready!", __func__);
281     size_t idx = 0;
282 
283     for (uint32_t id : pluginIds) {
284         auto it = pluginModules_.find(id);
285         if (it == pluginModules_.end()) {
286             PROFILER_LOG_DEBUG(LOG_CORE, "%s:plugin not find", __func__);
287             return false;
288         }
289         auto plugin = pluginModules_[id];
290         auto cfgData = plugin->GetConfigData();
291         if (!plugin->StartSession(reinterpret_cast<const uint8_t*>(cfgData.c_str()), cfgData.size())) {
292             return false;
293         }
294 
295         if (plugin->GetSampleMode() == PluginModule::SampleMode::POLLING) {
296             if (idx > config.size()) {
297                 PROFILER_LOG_WARN(LOG_CORE, "%s:idx %zu out of size %zu", __func__, idx, config.size());
298                 return false;
299             }
300             if (config[idx].sample_interval() == 0) {
301                 PROFILER_LOG_DEBUG(LOG_CORE, "%s:scheduleTask interval == 0 error!", __func__);
302                 return false;
303             }
304             auto callback = [this, id, config, idx] { this->PullResult(id, config[idx].is_protobuf_serialize()); };
305             int32_t timerFd = scheduleTaskManager_.ScheduleTask(callback, config[idx].sample_interval());
306             if (timerFd == -1) {
307                 PROFILER_LOG_DEBUG(LOG_CORE, "%s:scheduleTask failed!", __func__);
308                 return false;
309             }
310             scheduleTask_[config[idx].name()] = timerFd;
311         }
312 
313         // need update standalone plugin output file name
314         if (plugin->GetStandaloneFileData()) {
315             std::string pluginOutFileName = "";
316             plugin->GetOutFileName(pluginOutFileName);
317             result.set_plugin_id(id);
318             result.set_out_file_name(pluginOutFileName);
319         }
320 
321         idx++;
322     }
323 
324     return true;
325 }
326 
StopPluginSession(const std::vector<uint32_t> & pluginIds)327 bool PluginManager::StopPluginSession(const std::vector<uint32_t>& pluginIds)
328 {
329     PROFILER_LOG_INFO(LOG_CORE, "%s:ready!", __func__);
330     for (uint32_t id : pluginIds) {
331         if (pluginModules_.find(id) == pluginModules_.end()) {
332             PROFILER_LOG_DEBUG(LOG_CORE, "%s:plugin not find", __func__);
333             return false;
334         }
335         if (pluginModules_[id]->GetSampleMode() == PluginModule::SampleMode::POLLING) {
336             for (const auto& it : pluginIds_) {
337                 if (it.second == id) {
338                     PROFILER_LOG_DEBUG(LOG_CORE, "%s:find plugin name = %s", __func__, it.first.c_str());
339                     scheduleTaskManager_.UnscheduleTask(scheduleTask_[it.first]);
340                 }
341             }
342         }
343         if (!pluginModules_[id]->StopSession()) {
344             return false;
345         }
346     }
347     return true;
348 }
349 
StopAllPluginSession()350 bool PluginManager::StopAllPluginSession()
351 {
352     std::vector<uint32_t> vecPluginIds;
353     for (std::map<uint32_t, std::shared_ptr<PluginModule>>::iterator it = pluginModules_.begin();
354          it != pluginModules_.end(); ++it) {
355         vecPluginIds.push_back(it->first);
356     }
357     return StopPluginSession(vecPluginIds);
358 }
359 
ReportPluginBasicData(const std::vector<uint32_t> & pluginIds)360 bool PluginManager::ReportPluginBasicData(const std::vector<uint32_t>& pluginIds)
361 {
362     PROFILER_LOG_INFO(LOG_CORE, "%s:ready!", __func__);
363     for (uint32_t id : pluginIds) {
364         CHECK_TRUE(pluginModules_.find(id) != pluginModules_.end(), false, "%s:plugin not find", __func__);
365         // notify plugin to report basic data
366         CHECK_TRUE(pluginModules_[id]->ReportBasicData(), false, "%s:report basic data failed", __func__);
367     }
368     return true;
369 }
370 
SubmitResult(const PluginResult & pluginResult)371 bool PluginManager::SubmitResult(const PluginResult& pluginResult)
372 {
373     PROFILER_LOG_INFO(LOG_CORE, "%s:ready!", __func__);
374     NotifyResultRequest request;
375     CHECK_NOTNULL(commandPoller_, false, "%s:commandPoller_ is null", __func__);
376     request.set_request_id(commandPoller_->GetRequestId());
377     request.set_command_id(0);
378     PluginResult* p = request.add_result();
379     *p = pluginResult;
380     NotifyResultResponse response;
381     if (!commandPoller_->NotifyResult(request, response)) {
382         PROFILER_LOG_DEBUG(LOG_CORE, "%s:fail 1", __func__);
383         return false;
384     }
385     if (response.status() != ResponseStatus::OK) {
386         PROFILER_LOG_DEBUG(LOG_CORE, "%s:fail 2", __func__);
387         return false;
388     }
389     PROFILER_LOG_DEBUG(LOG_CORE, "%s:ok", __func__);
390     return true;
391 }
392 
PullResult(uint32_t pluginId,bool isProtobufSerialize)393 bool PluginManager::PullResult(uint32_t pluginId, bool isProtobufSerialize)
394 {
395     uint32_t size = 0;
396     std::string name = "";
397     std::string version = "";
398     auto it = pluginModules_.find(pluginId);
399     if (it == pluginModules_.end()) {
400         PROFILER_LOG_DEBUG(LOG_CORE, "%s:plugin not find", __func__);
401         return false;
402     }
403     pluginModules_[pluginId]->GetBufferSizeHint(size);
404     pluginModules_[pluginId]->GetPluginName(name);
405     pluginModules_[pluginId]->GetPluginVersion(version);
406 
407     if (isProtobufSerialize) {
408         std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(size);
409         CHECK_NOTNULL(buffer, false, "%s:buffer new failed!", __func__);
410 
411         int length = it->second->ReportResult(buffer.get(), size);
412         if (length < 0) {
413             return false;
414         }
415 
416         ProfilerPluginData pluginData;
417         pluginData.set_name(name);
418         pluginData.set_version(version);
419         pluginData.set_status(0);
420         pluginData.set_data(buffer.get(), length);
421 
422         struct timespec ts;
423         clockid_t clockId = pluginModules_[pluginId]->GetClockId();
424         clock_gettime(clockId, &ts);
425 
426         pluginData.set_clock_id(static_cast<ProfilerPluginData_ClockId>(clockId));
427         pluginData.set_tv_sec(ts.tv_sec);
428         pluginData.set_tv_nsec(ts.tv_nsec);
429 
430         auto writer = std::static_pointer_cast<BufferWriter>(pluginModules_[pluginId]->GetWriter());
431         CHECK_NOTNULL(writer, false, "PullResult GetWriter nullptr");
432 
433         writer->WriteMessage(pluginData, name);
434         writer->Flush();
435     } else {
436         auto writer = std::static_pointer_cast<BufferWriter>(pluginModules_[pluginId]->GetWriter());
437         CHECK_NOTNULL(writer, false, "PullResult GetWriter nullptr");
438         auto writeCtx = writer->GetCtx();
439         CHECK_NOTNULL(writeCtx, false, "PullResult GetCtx nullptr");
440         writer->ResetPos();
441         ProtoEncoder::ProfilerPluginData pluginData(writeCtx);
442         pluginData.set_name(name);
443         pluginData.set_version(version);
444         pluginData.set_status(0);
445 
446         auto callbackFunc = it->second->ReportResultOptimize();
447         if (callbackFunc != nullptr) {
448             pluginData.set_data(callbackFunc);
449         }
450 
451         struct timespec ts;
452         clockid_t clockId = pluginModules_[pluginId]->GetClockId();
453         clock_gettime(clockId, &ts);
454 
455         pluginData.set_clock_id(static_cast<ProfilerPluginData_ClockId>(clockId));
456         pluginData.set_tv_sec(ts.tv_sec);
457         pluginData.set_tv_nsec(ts.tv_nsec);
458 
459         int32_t len = pluginData.Finish();
460         writer->UseMemory(len);
461         writer->Flush();
462     }
463     return true;
464 }
465 
CreateWriter(std::string pluginName,uint32_t bufferSize,int smbFd,int eventFd,bool isProtobufSerialize)466 bool PluginManager::CreateWriter(std::string pluginName, uint32_t bufferSize, int smbFd, int eventFd,
467                                  bool isProtobufSerialize)
468 {
469     auto it = pluginIds_.find(pluginName);
470     if (it == pluginIds_.end()) {
471         PROFILER_LOG_DEBUG(LOG_CORE, "%s:plugin not exist", __func__);
472         return false;
473     }
474     uint32_t index = it->second;
475 
476     if (bufferSize > 0) {
477         PROFILER_LOG_DEBUG(LOG_CORE, "%s:%s Use ShareMemory %d", __func__, pluginName.c_str(), bufferSize);
478         std::string pluginVersion = "";
479         pluginModules_[index]->GetPluginVersion(pluginVersion);
480         pluginModules_[index]->RegisterWriter(std::make_shared<BufferWriter>
481             (pluginName, pluginVersion, bufferSize, smbFd, eventFd, index), isProtobufSerialize);
482     } else {
483         PROFILER_LOG_ERROR(LOG_CORE, "%s:no shared memory buffer allocated!", __func__);
484         return false;
485     }
486     return true;
487 }
488 
ResetWriter(uint32_t pluginId)489 bool PluginManager::ResetWriter(uint32_t pluginId)
490 {
491     if (pluginModules_.find(pluginId) == pluginModules_.end()) {
492         PROFILER_LOG_DEBUG(LOG_CORE, "%s:plugin not exist", __func__);
493         return false;
494     }
495     PROFILER_LOG_DEBUG(LOG_CORE, "%s:resetWriter %u", __func__, pluginId);
496     pluginModules_[pluginId]->RegisterWriter(nullptr);
497     return true;
498 }
499