106f6ba60Sopenharmony_ci/* 206f6ba60Sopenharmony_ci * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved. 306f6ba60Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 406f6ba60Sopenharmony_ci * you may not use this file except in compliance with the License. 506f6ba60Sopenharmony_ci * You may obtain a copy of the License at 606f6ba60Sopenharmony_ci * 706f6ba60Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 806f6ba60Sopenharmony_ci * 906f6ba60Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 1006f6ba60Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 1106f6ba60Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1206f6ba60Sopenharmony_ci * See the License for the specific language governing permissions and 1306f6ba60Sopenharmony_ci * limitations under the License. 1406f6ba60Sopenharmony_ci */ 1506f6ba60Sopenharmony_ci 1606f6ba60Sopenharmony_ci#include "plugin_watcher.h" 1706f6ba60Sopenharmony_ci 1806f6ba60Sopenharmony_ci#include <climits> 1906f6ba60Sopenharmony_ci#include <cstdio> 2006f6ba60Sopenharmony_ci#include <cstring> 2106f6ba60Sopenharmony_ci#include <dirent.h> 2206f6ba60Sopenharmony_ci#include <pthread.h> 2306f6ba60Sopenharmony_ci#include <sys/inotify.h> 2406f6ba60Sopenharmony_ci#include <unistd.h> 2506f6ba60Sopenharmony_ci 2606f6ba60Sopenharmony_ci#include "logging.h" 2706f6ba60Sopenharmony_ci#include "plugin_manager.h" 2806f6ba60Sopenharmony_ci#include "securec.h" 2906f6ba60Sopenharmony_ci 3006f6ba60Sopenharmony_cinamespace { 3106f6ba60Sopenharmony_ciconstexpr uint32_t MAX_BUF_SIZE = 1024; 3206f6ba60Sopenharmony_ci} // namespace 3306f6ba60Sopenharmony_ci 3406f6ba60Sopenharmony_ciPluginWatcher::PluginWatcher(const PluginManagerPtr& pluginManager) 3506f6ba60Sopenharmony_ci : inotifyFd_(-1), pluginManager_(pluginManager), runMonitor_(true) 3606f6ba60Sopenharmony_ci{ 3706f6ba60Sopenharmony_ci inotifyFd_ = inotify_init1(IN_CLOEXEC | IN_NONBLOCK); 3806f6ba60Sopenharmony_ci if (inotifyFd_ < 0) { 3906f6ba60Sopenharmony_ci PROFILER_LOG_INFO(LOG_CORE, "%s:inotify_init1 failed! inotifyFd_ : %d", __func__, inotifyFd_); 4006f6ba60Sopenharmony_ci } else { 4106f6ba60Sopenharmony_ci monitorThread_ = std::thread([this] { this->Monitor(); }); 4206f6ba60Sopenharmony_ci } 4306f6ba60Sopenharmony_ci} 4406f6ba60Sopenharmony_ci 4506f6ba60Sopenharmony_ciPluginWatcher::~PluginWatcher() 4606f6ba60Sopenharmony_ci{ 4706f6ba60Sopenharmony_ci runMonitor_ = false; 4806f6ba60Sopenharmony_ci for (auto it = wdToDir_.begin(); it != wdToDir_.end(); ++it) { 4906f6ba60Sopenharmony_ci inotify_rm_watch(inotifyFd_, it->first); 5006f6ba60Sopenharmony_ci } 5106f6ba60Sopenharmony_ci 5206f6ba60Sopenharmony_ci if (inotifyFd_ != -1) { 5306f6ba60Sopenharmony_ci close(inotifyFd_); 5406f6ba60Sopenharmony_ci } 5506f6ba60Sopenharmony_ci monitorThread_.join(); 5606f6ba60Sopenharmony_ci} 5706f6ba60Sopenharmony_ci 5806f6ba60Sopenharmony_cibool PluginWatcher::ScanPlugins(const std::string& pluginDir) 5906f6ba60Sopenharmony_ci{ 6006f6ba60Sopenharmony_ci DIR* dir = nullptr; 6106f6ba60Sopenharmony_ci struct dirent* entry = nullptr; 6206f6ba60Sopenharmony_ci char fullpath[PATH_MAX + 1] = {0}; 6306f6ba60Sopenharmony_ci realpath(pluginDir.c_str(), fullpath); 6406f6ba60Sopenharmony_ci PROFILER_LOG_INFO(LOG_CORE, "%s:scan plugin from directory %s", __func__, fullpath); 6506f6ba60Sopenharmony_ci dir = opendir(fullpath); 6606f6ba60Sopenharmony_ci if (dir == nullptr) { 6706f6ba60Sopenharmony_ci return false; 6806f6ba60Sopenharmony_ci } 6906f6ba60Sopenharmony_ci while (true) { 7006f6ba60Sopenharmony_ci entry = readdir(dir); 7106f6ba60Sopenharmony_ci if (!entry) { 7206f6ba60Sopenharmony_ci PROFILER_LOG_INFO(LOG_CORE, "%s:readdir finish!", __func__); 7306f6ba60Sopenharmony_ci break; 7406f6ba60Sopenharmony_ci } 7506f6ba60Sopenharmony_ci std::string fileName = entry->d_name; 7606f6ba60Sopenharmony_ci if (entry->d_type & DT_REG) { 7706f6ba60Sopenharmony_ci size_t pos = fileName.rfind(".so"); 7806f6ba60Sopenharmony_ci if (pos != std::string::npos && (pos == fileName.length() - strlen(".so"))) { 7906f6ba60Sopenharmony_ci OnPluginAdded(std::string(fullpath) + '/' + fileName); 8006f6ba60Sopenharmony_ci } 8106f6ba60Sopenharmony_ci } 8206f6ba60Sopenharmony_ci } 8306f6ba60Sopenharmony_ci closedir(dir); 8406f6ba60Sopenharmony_ci return true; 8506f6ba60Sopenharmony_ci} 8606f6ba60Sopenharmony_ci 8706f6ba60Sopenharmony_cibool PluginWatcher::WatchPlugins(const std::string& pluginDir) 8806f6ba60Sopenharmony_ci{ 8906f6ba60Sopenharmony_ci char fullpath[PATH_MAX + 1] = {0}; 9006f6ba60Sopenharmony_ci realpath(pluginDir.c_str(), fullpath); 9106f6ba60Sopenharmony_ci 9206f6ba60Sopenharmony_ci int wd = inotify_add_watch(inotifyFd_, fullpath, IN_ALL_EVENTS); 9306f6ba60Sopenharmony_ci if (wd < 0) { 9406f6ba60Sopenharmony_ci PROFILER_LOG_INFO(LOG_CORE, "%s:inotify_add_watch add directory %s failed!", __func__, pluginDir.c_str()); 9506f6ba60Sopenharmony_ci return false; 9606f6ba60Sopenharmony_ci } 9706f6ba60Sopenharmony_ci PROFILER_LOG_INFO(LOG_CORE, "%s:inotify_add_watch add directory %s success!", __func__, fullpath); 9806f6ba60Sopenharmony_ci std::lock_guard<std::mutex> guard(mtx_); 9906f6ba60Sopenharmony_ci wdToDir_.insert(std::pair<int, std::string>(wd, std::string(fullpath))); 10006f6ba60Sopenharmony_ci return true; 10106f6ba60Sopenharmony_ci} 10206f6ba60Sopenharmony_ci 10306f6ba60Sopenharmony_cibool PluginWatcher::MonitorIsSet() 10406f6ba60Sopenharmony_ci{ 10506f6ba60Sopenharmony_ci const struct inotify_event* event = nullptr; 10606f6ba60Sopenharmony_ci char buffer[MAX_BUF_SIZE] = {'\0'}; 10706f6ba60Sopenharmony_ci char* ptr = nullptr; 10806f6ba60Sopenharmony_ci 10906f6ba60Sopenharmony_ci ssize_t readLength = read(inotifyFd_, buffer, MAX_BUF_SIZE); 11006f6ba60Sopenharmony_ci if (readLength == -1) { 11106f6ba60Sopenharmony_ci return false; 11206f6ba60Sopenharmony_ci } 11306f6ba60Sopenharmony_ci for (ptr = buffer; ptr < buffer + readLength; ptr += sizeof(struct inotify_event) + event->len) { 11406f6ba60Sopenharmony_ci event = reinterpret_cast<const struct inotify_event*>(ptr); 11506f6ba60Sopenharmony_ci std::unique_lock<std::mutex> guard(mtx_, std::adopt_lock); 11606f6ba60Sopenharmony_ci const std::string& pluginDir = wdToDir_[event->wd]; 11706f6ba60Sopenharmony_ci guard.unlock(); 11806f6ba60Sopenharmony_ci if (event->mask & IN_ISDIR) { 11906f6ba60Sopenharmony_ci continue; 12006f6ba60Sopenharmony_ci } 12106f6ba60Sopenharmony_ci std::string fileName = event->name; 12206f6ba60Sopenharmony_ci size_t pos = fileName.rfind(".so"); 12306f6ba60Sopenharmony_ci if ((pos == std::string::npos) || (pos != fileName.length() - strlen(".so"))) { 12406f6ba60Sopenharmony_ci continue; 12506f6ba60Sopenharmony_ci } 12606f6ba60Sopenharmony_ci switch (event->mask) { 12706f6ba60Sopenharmony_ci case IN_CLOSE_WRITE: 12806f6ba60Sopenharmony_ci case IN_MOVED_TO: 12906f6ba60Sopenharmony_ci OnPluginAdded(pluginDir + '/' + fileName); 13006f6ba60Sopenharmony_ci break; 13106f6ba60Sopenharmony_ci case IN_DELETE: 13206f6ba60Sopenharmony_ci case IN_MOVED_FROM: 13306f6ba60Sopenharmony_ci OnPluginRemoved(pluginDir + '/' + fileName); 13406f6ba60Sopenharmony_ci break; 13506f6ba60Sopenharmony_ci default: 13606f6ba60Sopenharmony_ci break; 13706f6ba60Sopenharmony_ci } 13806f6ba60Sopenharmony_ci } 13906f6ba60Sopenharmony_ci if (memset_s(buffer, sizeof(buffer), 0, sizeof(buffer)) != 0) { 14006f6ba60Sopenharmony_ci PROFILER_LOG_ERROR(LOG_CORE, "%s:memset_s error!", __func__); 14106f6ba60Sopenharmony_ci } 14206f6ba60Sopenharmony_ci return true; 14306f6ba60Sopenharmony_ci} 14406f6ba60Sopenharmony_ci 14506f6ba60Sopenharmony_civoid PluginWatcher::Monitor() 14606f6ba60Sopenharmony_ci{ 14706f6ba60Sopenharmony_ci struct timeval time; 14806f6ba60Sopenharmony_ci 14906f6ba60Sopenharmony_ci pthread_setname_np(pthread_self(), "PluginWatcher"); 15006f6ba60Sopenharmony_ci while (runMonitor_) { 15106f6ba60Sopenharmony_ci fd_set rFds; 15206f6ba60Sopenharmony_ci FD_ZERO(&rFds); 15306f6ba60Sopenharmony_ci FD_SET(inotifyFd_, &rFds); 15406f6ba60Sopenharmony_ci time.tv_sec = 1; 15506f6ba60Sopenharmony_ci time.tv_usec = 0; 15606f6ba60Sopenharmony_ci int ret = select(inotifyFd_ + 1, &rFds, nullptr, nullptr, &time); 15706f6ba60Sopenharmony_ci if (ret < 0) { 15806f6ba60Sopenharmony_ci continue; 15906f6ba60Sopenharmony_ci } else if (!ret) { 16006f6ba60Sopenharmony_ci continue; 16106f6ba60Sopenharmony_ci } else if (FD_ISSET(inotifyFd_, &rFds)) { 16206f6ba60Sopenharmony_ci if (!MonitorIsSet()) { 16306f6ba60Sopenharmony_ci continue; 16406f6ba60Sopenharmony_ci } 16506f6ba60Sopenharmony_ci } 16606f6ba60Sopenharmony_ci } 16706f6ba60Sopenharmony_ci} 16806f6ba60Sopenharmony_ci 16906f6ba60Sopenharmony_civoid PluginWatcher::OnPluginAdded(const std::string& pluginPath) 17006f6ba60Sopenharmony_ci{ 17106f6ba60Sopenharmony_ci auto pluginManager = pluginManager_.lock(); 17206f6ba60Sopenharmony_ci if (pluginManager != nullptr) { 17306f6ba60Sopenharmony_ci if (pluginManager->AddPlugin(pluginPath)) { 17406f6ba60Sopenharmony_ci PROFILER_LOG_INFO(LOG_CORE, "%s:plugin %s add success!", __func__, pluginPath.c_str()); 17506f6ba60Sopenharmony_ci } else { 17606f6ba60Sopenharmony_ci PROFILER_LOG_INFO(LOG_CORE, "%s:pluginPath %s add failed!", __func__, pluginPath.c_str()); 17706f6ba60Sopenharmony_ci } 17806f6ba60Sopenharmony_ci } else { 17906f6ba60Sopenharmony_ci PROFILER_LOG_INFO(LOG_CORE, "%s:weak_ptr pluginManager lock failed!", __func__); 18006f6ba60Sopenharmony_ci } 18106f6ba60Sopenharmony_ci} 18206f6ba60Sopenharmony_ci 18306f6ba60Sopenharmony_civoid PluginWatcher::OnPluginRemoved(const std::string& pluginPath) 18406f6ba60Sopenharmony_ci{ 18506f6ba60Sopenharmony_ci auto pluginManager = pluginManager_.lock(); 18606f6ba60Sopenharmony_ci if (pluginManager != nullptr) { 18706f6ba60Sopenharmony_ci if (pluginManager->RemovePlugin(pluginPath)) { 18806f6ba60Sopenharmony_ci PROFILER_LOG_INFO(LOG_CORE, "%s:pluginPath %s remove success!", __func__, pluginPath.c_str()); 18906f6ba60Sopenharmony_ci } else { 19006f6ba60Sopenharmony_ci PROFILER_LOG_INFO(LOG_CORE, "%s:pluginPath %s remove failed!", __func__, pluginPath.c_str()); 19106f6ba60Sopenharmony_ci } 19206f6ba60Sopenharmony_ci } else { 19306f6ba60Sopenharmony_ci PROFILER_LOG_INFO(LOG_CORE, "%s:weak_ptr pluginManager lock failed!", __func__); 19406f6ba60Sopenharmony_ci } 19506f6ba60Sopenharmony_ci}