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 29namespace { 30using namespace OHOS::Developtools::Profiler; 31constexpr int FILE_READ_CHUNK_SIZE = 4096; 32constexpr char HEX_CHARS[] = "0123456789abcdef"; 33 34#define HHB(v) (((v) & 0xF0) >> 4) 35#define LHB(v) ((v) & 0x0F) 36 37std::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 69PluginManager::~PluginManager() {} 70 71void PluginManager::SetCommandPoller(const CommandPollerPtr& p) 72{ 73 this->commandPoller_ = p; 74} 75 76bool 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 110bool 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 144bool 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 207bool 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 223bool 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 234bool 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 247bool 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 265bool 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 277bool 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 327bool 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 350bool 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 360bool 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 371bool 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 393bool 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 466bool 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 489bool 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