1 /* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 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_service.h" 17 18 #include <cinttypes> 19 #include <fcntl.h> 20 #include <sys/wait.h> 21 #include <unistd.h> 22 23 #include "plugin_command_builder.h" 24 #include "plugin_service_impl.h" 25 #include "plugin_session_manager.h" 26 #include "profiler_capability_manager.h" 27 #include "profiler_data_repeater.h" 28 #include "securec.h" 29 #include "share_memory_allocator.h" 30 #include "socket_context.h" 31 32 namespace { 33 const int PAGE_BYTES = 4096; 34 const int DEFAULT_EVENT_POLLING_INTERVAL = 5000; 35 } // namespace 36 PluginService()37 PluginService::PluginService() 38 { 39 pluginIdCounter_ = 0; 40 StartService(DEFAULT_UNIX_SOCKET_PATH); 41 pluginCommandBuilder_ = std::make_shared<PluginCommandBuilder>(); 42 43 eventPoller_ = std::make_unique<EpollEventPoller>(DEFAULT_EVENT_POLLING_INTERVAL); 44 CHECK_NOTNULL(eventPoller_, NO_RETVAL, "create event poller FAILED!"); 45 46 eventPoller_->Init(); 47 eventPoller_->Start(); 48 } 49 ~PluginService()50 PluginService::~PluginService() 51 { 52 if (eventPoller_) { 53 eventPoller_->Stop(); 54 eventPoller_->Finalize(); 55 } 56 } 57 SetPluginSessionManager(const PluginSessionManagerPtr & pluginSessionManager)58 void PluginService::SetPluginSessionManager(const PluginSessionManagerPtr& pluginSessionManager) 59 { 60 pluginSessionManager_ = pluginSessionManager; 61 } 62 GetSemaphore(uint32_t id) const63 SemaphorePtr PluginService::GetSemaphore(uint32_t id) const 64 { 65 std::unique_lock<std::mutex> lock(mutex_); 66 auto it = waitSemphores_.find(id); 67 if (it != waitSemphores_.end()) { 68 return it->second; 69 } 70 return nullptr; 71 } 72 StartService(const std::string & unixSocketName)73 bool PluginService::StartService(const std::string& unixSocketName) 74 { 75 pluginServiceImpl_ = std::make_shared<PluginServiceImpl>(*this); 76 serviceEntry_ = std::make_shared<ServiceEntry>(); 77 if (!serviceEntry_->StartServer(unixSocketName)) { 78 pluginServiceImpl_ = nullptr; 79 serviceEntry_ = nullptr; 80 HILOG_DEBUG(LOG_CORE, "Start IPC Service FAIL"); 81 return false; 82 } 83 serviceEntry_->RegisterService(*pluginServiceImpl_.get()); 84 return true; 85 } 86 GetReusePolicy(const ProfilerSessionConfig::BufferConfig & bufferConfig)87 static ShareMemoryBlock::ReusePolicy GetReusePolicy(const ProfilerSessionConfig::BufferConfig& bufferConfig) 88 { 89 if (bufferConfig.policy() == ProfilerSessionConfig::BufferConfig::RECYCLE) { 90 return ShareMemoryBlock::DROP_OLD; 91 } 92 return ShareMemoryBlock::DROP_NONE; 93 } 94 95 // create plugin session with buffer config CreatePluginSession(const ProfilerPluginConfig & pluginConfig,const ProfilerSessionConfig::BufferConfig & bufferConfig,const ProfilerDataRepeaterPtr & dataRepeater)96 bool PluginService::CreatePluginSession(const ProfilerPluginConfig& pluginConfig, 97 const ProfilerSessionConfig::BufferConfig& bufferConfig, 98 const ProfilerDataRepeaterPtr& dataRepeater) 99 { 100 uint32_t pluginId = 0; 101 PluginContextPtr pluginCtx = nullptr; 102 std::string pluginName = pluginConfig.name(); 103 std::tie(pluginId, pluginCtx) = GetPluginContext(pluginName); 104 CHECK_NOTNULL(pluginCtx, false, "get PluginContext failed!"); 105 106 pluginCtx->profilerDataRepeater = dataRepeater; 107 108 uint32_t bufferSize = bufferConfig.pages() * PAGE_BYTES; 109 auto cmd = pluginCommandBuilder_->BuildCreateSessionCmd(pluginConfig, bufferSize); 110 CHECK_TRUE(cmd != nullptr, false, "CreatePluginSession BuildCreateSessionCmd FAIL %s", pluginName.c_str()); 111 112 auto smb = ShareMemoryAllocator::GetInstance().CreateMemoryBlockLocal(pluginName, bufferSize); 113 CHECK_TRUE(smb != nullptr, false, "CreateMemoryBlockLocal FAIL %s", pluginName.c_str()); 114 115 auto policy = GetReusePolicy(bufferConfig); 116 HILOG_DEBUG(LOG_CORE, "CreatePluginSession policy = %d", (int)policy); 117 smb->SetReusePolicy(policy); 118 119 auto notifier = EventNotifier::Create(0, EventNotifier::NONBLOCK); 120 CHECK_NOTNULL(notifier, false, "create EventNotifier for %s failed!", pluginName.c_str()); 121 122 pluginCtx->shareMemoryBlock = smb; 123 pluginCtx->eventNotifier = notifier; 124 pluginCtx->profilerPluginState.set_state(ProfilerPluginState::LOADED); 125 126 pluginServiceImpl_->PushCommand(*pluginCtx->context, cmd); 127 128 pluginCtx->context->SendFileDescriptor(smb->GetfileDescriptor()); 129 pluginCtx->context->SendFileDescriptor(notifier->GetFd()); 130 131 eventPoller_->AddFileDescriptor(notifier->GetFd(), std::bind(&PluginService::ReadShareMemory, this, *pluginCtx)); 132 HILOG_DEBUG(LOG_CORE, "CreatePluginSession %s done, shmem fd = %d", pluginName.c_str(), smb->GetfileDescriptor()); 133 return true; 134 } 135 136 // create plugin session without buffer config CreatePluginSession(const ProfilerPluginConfig & pluginConfig,const ProfilerDataRepeaterPtr & dataRepeater)137 bool PluginService::CreatePluginSession(const ProfilerPluginConfig& pluginConfig, 138 const ProfilerDataRepeaterPtr& dataRepeater) 139 { 140 uint32_t pluginId = 0; 141 PluginContextPtr pluginCtx = nullptr; 142 std::string pluginName = pluginConfig.name(); 143 std::tie(pluginId, pluginCtx) = GetPluginContext(pluginName); 144 CHECK_NOTNULL(pluginCtx, false, "get PluginContext failed!"); 145 146 pluginCtx->profilerDataRepeater = dataRepeater; 147 pluginCtx->shareMemoryBlock = nullptr; 148 149 auto cmd = pluginCommandBuilder_->BuildCreateSessionCmd(pluginConfig, 0); 150 CHECK_TRUE(cmd != nullptr, false, "CreatePluginSession BuildCreateSessionCmd FAIL %s", pluginName.c_str()); 151 152 pluginCtx->profilerPluginState.set_state(ProfilerPluginState::LOADED); 153 pluginServiceImpl_->PushCommand(*pluginCtx->context, cmd); 154 155 HILOG_DEBUG(LOG_CORE, "CreatePluginSession %s done!", pluginName.c_str()); 156 return true; 157 } 158 StartPluginSession(const ProfilerPluginConfig & config)159 bool PluginService::StartPluginSession(const ProfilerPluginConfig& config) 160 { 161 uint32_t pluginId = 0; 162 PluginContextPtr pluginCtx = nullptr; 163 std::string pluginName = config.name(); 164 std::tie(pluginId, pluginCtx) = GetPluginContext(pluginName); 165 CHECK_NOTNULL(pluginCtx, false, "get PluginContext failed!"); 166 167 auto cmd = pluginCommandBuilder_->BuildStartSessionCmd(config, pluginId); 168 CHECK_TRUE(cmd != nullptr, false, "StartPluginSession BuildStartSessionCmd FAIL %s", pluginName.c_str()); 169 170 pluginCtx->profilerPluginState.set_state(ProfilerPluginState::IN_SESSION); 171 pluginServiceImpl_->PushCommand(*pluginCtx->context, cmd); 172 HILOG_INFO(LOG_CORE, "StartPluginSession %s done!", pluginName.c_str()); 173 return true; 174 } 175 StopPluginSession(const std::string & pluginName)176 bool PluginService::StopPluginSession(const std::string& pluginName) 177 { 178 uint32_t pluginId = 0; 179 PluginContextPtr pluginCtx = nullptr; 180 std::tie(pluginId, pluginCtx) = GetPluginContext(pluginName); 181 CHECK_NOTNULL(pluginCtx, false, "get PluginContext failed!"); 182 183 auto cmd = pluginCommandBuilder_->BuildStopSessionCmd(pluginId); 184 CHECK_TRUE(cmd != nullptr, false, "StopPluginSession BuildStopSessionCmd FAIL %s", pluginName.c_str()); 185 186 pluginCtx->profilerPluginState.set_state(ProfilerPluginState::LOADED); 187 pluginServiceImpl_->PushCommand(*pluginCtx->context, cmd); 188 189 auto sem = GetSemaphoreFactory().Create(0); 190 CHECK_NOTNULL(sem, false, "create Semaphore for stop %s FAILED!", pluginName.c_str()); 191 192 waitSemphores_[cmd->command_id()] = sem; 193 HILOG_DEBUG(LOG_CORE, "=== StopPluginSession Waiting ... ==="); 194 // wait on semaphore at most 30 seconds. 195 if (!sem->TimedWait(30)) { 196 // semaphore timeout 197 HILOG_DEBUG(LOG_CORE, "=== StopPluginSession Waiting FAIL ==="); 198 return false; 199 } 200 ReadShareMemory(*pluginCtx); 201 HILOG_DEBUG(LOG_CORE, "StopPluginSession %s done!", pluginName.c_str()); 202 return true; 203 } 204 DestroyPluginSession(const std::string & pluginName)205 bool PluginService::DestroyPluginSession(const std::string& pluginName) 206 { 207 uint32_t pluginId = 0; 208 PluginContextPtr pluginCtx = nullptr; 209 std::tie(pluginId, pluginCtx) = GetPluginContext(pluginName); 210 CHECK_NOTNULL(pluginCtx, false, "get PluginContext failed!"); 211 212 auto cmd = pluginCommandBuilder_->BuildDestroySessionCmd(pluginId); 213 CHECK_TRUE(cmd != nullptr, false, "DestroyPluginSession BuildDestroySessionCmd FAIL %s", pluginName.c_str()); 214 215 if (pluginCtx->shareMemoryBlock) { 216 ShareMemoryAllocator::GetInstance().ReleaseMemoryBlockLocal(pluginName); 217 pluginCtx->shareMemoryBlock = nullptr; 218 } 219 220 if (pluginCtx->eventNotifier) { 221 eventPoller_->RemoveFileDescriptor(pluginCtx->eventNotifier->GetFd()); 222 pluginCtx->eventNotifier = nullptr; 223 } 224 225 pluginCtx->profilerPluginState.set_state(ProfilerPluginState::REGISTERED); 226 pluginServiceImpl_->PushCommand(*pluginCtx->context, cmd); 227 HILOG_INFO(LOG_CORE, "DestroyPluginSession %s done!", pluginName.c_str()); 228 return true; 229 } 230 RemovePluginSessionCtx(const std::string & pluginName)231 bool PluginService::RemovePluginSessionCtx(const std::string& pluginName) 232 { 233 PluginContextPtr pluginCtx = GetPluginContext(pluginName).second; 234 CHECK_NOTNULL(pluginCtx, false, "get PluginContext failed!"); 235 236 if (pluginCtx->shareMemoryBlock) { 237 ShareMemoryAllocator::GetInstance().ReleaseMemoryBlockLocal(pluginName); 238 pluginCtx->shareMemoryBlock = nullptr; 239 } 240 241 if (pluginCtx->eventNotifier) { 242 eventPoller_->RemoveFileDescriptor(pluginCtx->eventNotifier->GetFd()); 243 pluginCtx->eventNotifier = nullptr; 244 } 245 246 pluginCtx->profilerPluginState.set_state(ProfilerPluginState::INITED); 247 HILOG_INFO(LOG_CORE, "RemovePluginSessionCtx %s done!", pluginName.c_str()); 248 return true; 249 } 250 GetPluginContext(const std::string & pluginName)251 std::pair<uint32_t, PluginContextPtr> PluginService::GetPluginContext(const std::string& pluginName) 252 { 253 std::unique_lock<std::mutex> lock(mutex_); 254 CHECK_TRUE(nameIndex_.count(pluginName) > 0, std::make_pair(0, nullptr), 255 "GetPluginContext failed, plugin name `%s` not found!", pluginName.c_str()); 256 uint32_t id = nameIndex_[pluginName]; 257 258 CHECK_TRUE(pluginContext_.count(id) > 0, std::make_pair(id, nullptr), "plugin id %u not found!", id); 259 return std::make_pair(id, pluginContext_[id]); 260 } 261 GetPluginContextById(uint32_t id)262 PluginContextPtr PluginService::GetPluginContextById(uint32_t id) 263 { 264 std::unique_lock<std::mutex> lock(mutex_); 265 CHECK_TRUE(pluginContext_.count(id) > 0, nullptr, "plugin id %u not found!", id); 266 return pluginContext_[id]; 267 } 268 AddPluginInfo(const PluginInfo & pluginInfo)269 bool PluginService::AddPluginInfo(const PluginInfo& pluginInfo) 270 { 271 if (nameIndex_.find(pluginInfo.name) == nameIndex_.end()) { // add new plugin 272 auto pluginCtx = std::make_shared<PluginContext>(); 273 CHECK_NOTNULL(pluginCtx, false, "create PluginContext failed!"); 274 275 ProfilerPluginCapability capability; 276 capability.set_path(pluginInfo.path); 277 capability.set_name(pluginInfo.name); 278 CHECK_TRUE(ProfilerCapabilityManager::GetInstance().AddCapability(capability), false, 279 "AddPluginInfo AddCapability FAIL"); 280 281 pluginCtx->name = pluginInfo.name; 282 pluginCtx->path = pluginInfo.path; 283 pluginCtx->context = pluginInfo.context; 284 pluginCtx->config.set_name(pluginInfo.name); 285 pluginCtx->config.set_plugin_sha256(pluginInfo.sha256); 286 pluginCtx->profilerPluginState.set_name(pluginInfo.name); 287 pluginCtx->profilerPluginState.set_state(ProfilerPluginState::REGISTERED); 288 pluginCtx->sha256 = pluginInfo.sha256; 289 pluginCtx->bufferSizeHint = pluginInfo.bufferSizeHint; 290 291 uint32_t pluginId = ++pluginIdCounter_; 292 std::unique_lock<std::mutex> lock(mutex_); 293 pluginContext_[pluginId] = pluginCtx; 294 nameIndex_[pluginInfo.name] = pluginId; 295 } else { // update sha256 or bufferSizeHint 296 std::unique_lock<std::mutex> lock(mutex_); 297 CHECK_TRUE(nameIndex_.count(pluginInfo.name) > 0, false, "plugin name %s not found!", pluginInfo.name.c_str()); 298 299 uint32_t pluginId = nameIndex_[pluginInfo.name]; 300 CHECK_TRUE(pluginContext_.count(pluginId) > 0, false, "plugin id %u not found!", pluginId); 301 auto pluginCtx = pluginContext_[pluginId]; 302 303 if (pluginInfo.sha256 != "") { 304 pluginCtx->sha256 = pluginInfo.sha256; 305 } 306 if (pluginInfo.bufferSizeHint != 0) { 307 pluginCtx->bufferSizeHint = pluginInfo.bufferSizeHint; 308 } 309 } 310 HILOG_DEBUG(LOG_CORE, "AddPluginInfo for %s done!", pluginInfo.name.c_str()); 311 312 return true; 313 } 314 GetPluginInfo(const std::string & pluginName,PluginInfo & pluginInfo)315 bool PluginService::GetPluginInfo(const std::string& pluginName, PluginInfo& pluginInfo) 316 { 317 uint32_t pluginId = 0; 318 PluginContextPtr pluginCtx = nullptr; 319 std::tie(pluginId, pluginCtx) = GetPluginContext(pluginName); 320 CHECK_TRUE(pluginId, false, "plugin name %s not found!", pluginName.c_str()); 321 CHECK_TRUE(pluginCtx, false, "plugin id %u not found!", pluginId); 322 323 pluginInfo.id = pluginId; 324 pluginInfo.name = pluginCtx->name; 325 pluginInfo.path = pluginCtx->path; 326 pluginInfo.sha256 = pluginCtx->sha256; 327 pluginInfo.bufferSizeHint = pluginCtx->bufferSizeHint; 328 return true; 329 } 330 RemovePluginInfo(const PluginInfo & pluginInfo)331 bool PluginService::RemovePluginInfo(const PluginInfo& pluginInfo) 332 { 333 uint32_t pluginId = pluginInfo.id; 334 PluginContextPtr pluginCtx = GetPluginContextById(pluginId); 335 CHECK_NOTNULL(pluginCtx, false, "RemovePluginInfo failed, id %d not found!", pluginId); 336 337 std::string pluginName = pluginCtx->config.name(); 338 CHECK_TRUE(ProfilerCapabilityManager::GetInstance().RemoveCapability(pluginName), false, 339 "RemovePluginInfo RemoveCapability FAIL %d", pluginId); 340 341 auto pluginState = pluginCtx->profilerPluginState.state(); 342 if (pluginState == ProfilerPluginState::LOADED || pluginState == ProfilerPluginState::IN_SESSION) { 343 std::vector<std::string> pluginNames = {pluginName}; 344 pluginSessionManager_->InvalidatePluginSessions(pluginNames); 345 pluginSessionManager_->RemovePluginSessions(pluginNames); 346 this->RemovePluginSessionCtx(pluginName); 347 } 348 349 std::unique_lock<std::mutex> lock(mutex_); 350 nameIndex_.erase(pluginName); 351 pluginContext_.erase(pluginId); 352 HILOG_DEBUG(LOG_CORE, "RemovePluginInfo for %s done!", pluginName.c_str()); 353 return true; 354 } 355 ReadShareMemory(PluginContext & context)356 void PluginService::ReadShareMemory(PluginContext& context) 357 { 358 CHECK_NOTNULL(context.shareMemoryBlock, NO_RETVAL, "smb of %s is null!", context.path.c_str()); 359 uint64_t value = 0; 360 if (context.eventNotifier) { 361 value = context.eventNotifier->Take(); 362 } 363 while (true) { 364 auto pluginData = std::make_shared<ProfilerPluginData>(); 365 bool ret = context.shareMemoryBlock->TakeData([&](const int8_t data[], uint32_t size) -> bool { 366 int retval = pluginData->ParseFromArray(reinterpret_cast<const char*>(data), size); 367 CHECK_TRUE(retval, false, "parse %d bytes failed!", size); 368 return true; 369 }); 370 if (!ret) { 371 break; 372 } 373 if (!context.profilerDataRepeater->PutPluginData(pluginData)) { 374 break; 375 } 376 } 377 } 378 AppendResult(NotifyResultRequest & request)379 bool PluginService::AppendResult(NotifyResultRequest& request) 380 { 381 pluginCommandBuilder_->GetedCommandResponse(request.command_id()); 382 auto sem = GetSemaphore(request.command_id()); 383 if (sem) { 384 sem->Post(); 385 } 386 387 int size = request.result_size(); 388 HILOG_DEBUG(LOG_CORE, "AppendResult size:%d, cmd id:%d", size, request.command_id()); 389 for (int i = 0; i < size; i++) { 390 PluginResult pr = request.result(i); 391 if (pr.data().size() > 0) { 392 HILOG_DEBUG(LOG_CORE, "AppendResult Size : %zu", pr.data().size()); 393 uint32_t pluginId = pr.plugin_id(); 394 PluginContextPtr pluginCtx = GetPluginContextById(pluginId); 395 CHECK_NOTNULL(pluginCtx, false, "plugin id %u not found!", pluginId); 396 if (pluginCtx->profilerDataRepeater == nullptr) { 397 HILOG_DEBUG(LOG_CORE, "AppendResult profilerDataRepeater==nullptr %s %d", pr.status().name().c_str(), 398 pluginId); 399 return false; 400 } 401 auto pluginData = std::make_shared<ProfilerPluginData>(); 402 pluginData->set_name(pr.status().name()); 403 pluginData->set_status(0); 404 pluginData->set_data(pr.data()); 405 if (!pluginCtx->profilerDataRepeater->PutPluginData(pluginData)) { 406 return false; 407 } 408 } else { 409 HILOG_DEBUG(LOG_CORE, "Flush?Data From ShareMemory?"); 410 } 411 } 412 return true; 413 } 414 GetPluginStatus()415 std::vector<ProfilerPluginState> PluginService::GetPluginStatus() 416 { 417 std::vector<ProfilerPluginState> status; 418 std::unique_lock<std::mutex> lock(mutex_); 419 for (auto& entry : pluginContext_) { 420 status.push_back(entry.second->profilerPluginState); 421 } 422 return status; 423 } 424 GetPluginIdByName(std::string name)425 uint32_t PluginService::GetPluginIdByName(std::string name) 426 { 427 std::unique_lock<std::mutex> lock(mutex_); 428 if (nameIndex_.find(name) == nameIndex_.end()) { 429 return 0; 430 } 431 return nameIndex_[name]; 432 } 433