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