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