• 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_watcher.h"
17 
18 #include <climits>
19 #include <cstdio>
20 #include <cstring>
21 #include <dirent.h>
22 #include <pthread.h>
23 #include <sys/inotify.h>
24 #include <unistd.h>
25 
26 #include "logging.h"
27 #include "plugin_manager.h"
28 #include "securec.h"
29 
30 namespace {
31 constexpr uint32_t MAX_BUF_SIZE = 1024;
32 } // namespace
33 
PluginWatcher(const PluginManagerPtr & pluginManager)34 PluginWatcher::PluginWatcher(const PluginManagerPtr& pluginManager)
35     : inotifyFd_(-1), pluginManager_(pluginManager), runMonitor_(true)
36 {
37     inotifyFd_ = inotify_init1(IN_CLOEXEC | IN_NONBLOCK);
38     if (inotifyFd_ < 0) {
39         HILOG_INFO(LOG_CORE, "%s:inotify_init1 failed! inotifyFd_ : %d", __func__, inotifyFd_);
40     } else {
41         monitorThread_ = std::thread(&PluginWatcher::Monitor, this);
42     }
43 }
44 
~PluginWatcher()45 PluginWatcher::~PluginWatcher()
46 {
47     runMonitor_ = false;
48     for (auto it = wdToDir_.begin(); it != wdToDir_.end(); ++it) {
49         inotify_rm_watch(inotifyFd_, it->first);
50     }
51 
52     if (inotifyFd_ != -1) {
53         close(inotifyFd_);
54     }
55     monitorThread_.join();
56 }
57 
ScanPlugins(const std::string & pluginDir)58 bool PluginWatcher::ScanPlugins(const std::string& pluginDir)
59 {
60     DIR* dir = nullptr;
61     struct dirent* entry = nullptr;
62     char fullpath[PATH_MAX + 1] = {0};
63     realpath(pluginDir.c_str(), fullpath);
64     HILOG_INFO(LOG_CORE, "%s:scan plugin from directory %s", __func__, fullpath);
65     dir = opendir(fullpath);
66     if (dir == nullptr) {
67         return false;
68     }
69     while (true) {
70         entry = readdir(dir);
71         if (!entry) {
72             HILOG_INFO(LOG_CORE, "%s:readdir finish!", __func__);
73             break;
74         }
75         std::string fileName = entry->d_name;
76         if (entry->d_type & DT_REG) {
77             size_t pos = fileName.rfind(".so");
78             if (pos != std::string::npos && (pos == fileName.length() - strlen(".so"))) {
79                 OnPluginAdded(std::string(fullpath) + '/' + fileName);
80             }
81         }
82     }
83     closedir(dir);
84     return true;
85 }
86 
WatchPlugins(const std::string & pluginDir)87 bool PluginWatcher::WatchPlugins(const std::string& pluginDir)
88 {
89     char fullpath[PATH_MAX + 1] = {0};
90     realpath(pluginDir.c_str(), fullpath);
91 
92     int wd = inotify_add_watch(inotifyFd_, fullpath, IN_ALL_EVENTS);
93     if (wd < 0) {
94         HILOG_INFO(LOG_CORE, "%s:inotify_add_watch add directory %s failed!", __func__, pluginDir.c_str());
95         return false;
96     }
97     HILOG_INFO(LOG_CORE, "%s:inotify_add_watch add directory %s success!", __func__, fullpath);
98     std::lock_guard<std::mutex> guard(mtx_);
99     wdToDir_.insert(std::pair<int, std::string>(wd, std::string(fullpath)));
100     return true;
101 }
102 
MonitorIsSet()103 bool PluginWatcher::MonitorIsSet()
104 {
105     const struct inotify_event* event = nullptr;
106     char buffer[MAX_BUF_SIZE] = {'\0'};
107     char* ptr = nullptr;
108 
109     ssize_t readLength = read(inotifyFd_, buffer, MAX_BUF_SIZE);
110     if (readLength == -1) {
111         return false;
112     }
113     for (ptr = buffer; ptr < buffer + readLength; ptr += sizeof(struct inotify_event) + event->len) {
114         event = reinterpret_cast<const struct inotify_event*>(ptr);
115         std::unique_lock<std::mutex> guard(mtx_, std::adopt_lock);
116         const std::string& pluginDir = wdToDir_[event->wd];
117         guard.unlock();
118         if (event->mask & IN_ISDIR) {
119             continue;
120         }
121         std::string fileName = event->name;
122         size_t pos = fileName.rfind(".so");
123         if ((pos == std::string::npos) || (pos != fileName.length() - strlen(".so"))) {
124             continue;
125         }
126         switch (event->mask) {
127             case IN_CLOSE_WRITE:
128             case IN_MOVED_TO:
129                 OnPluginAdded(pluginDir + '/' + fileName);
130                 break;
131             case IN_DELETE:
132             case IN_MOVED_FROM:
133                 OnPluginRemoved(pluginDir + '/' + fileName);
134                 break;
135             default:
136                 break;
137         }
138     }
139     if (memset_s(buffer, sizeof(buffer), 0, sizeof(buffer)) != 0) {
140         HILOG_ERROR(LOG_CORE, "%s:memset_s error!", __func__);
141     }
142     return true;
143 }
144 
Monitor()145 void PluginWatcher::Monitor()
146 {
147     struct timeval time;
148 
149     pthread_setname_np(pthread_self(), "PluginWatcher");
150     while (runMonitor_) {
151         fd_set rFds;
152         FD_ZERO(&rFds);
153         FD_SET(inotifyFd_, &rFds);
154         time.tv_sec = 1;
155         time.tv_usec = 0;
156         int ret = select(inotifyFd_ + 1, &rFds, nullptr, nullptr, &time);
157         if (ret < 0) {
158             continue;
159         } else if (!ret) {
160             continue;
161         } else if (FD_ISSET(inotifyFd_, &rFds)) {
162             if (!MonitorIsSet()) {
163                 continue;
164             }
165         }
166     }
167 }
168 
OnPluginAdded(const std::string & pluginPath)169 void PluginWatcher::OnPluginAdded(const std::string& pluginPath)
170 {
171     auto pluginManager = pluginManager_.lock();
172     if (pluginManager != nullptr) {
173         if (pluginManager->AddPlugin(pluginPath)) {
174             HILOG_INFO(LOG_CORE, "%s:plugin %s add success!", __func__, pluginPath.c_str());
175         } else {
176             HILOG_INFO(LOG_CORE, "%s:pluginPath %s add failed!", __func__, pluginPath.c_str());
177         }
178     } else {
179         HILOG_INFO(LOG_CORE, "%s:weak_ptr pluginManager lock failed!", __func__);
180     }
181 }
182 
OnPluginRemoved(const std::string & pluginPath)183 void PluginWatcher::OnPluginRemoved(const std::string& pluginPath)
184 {
185     auto pluginManager = pluginManager_.lock();
186     if (pluginManager != nullptr) {
187         if (pluginManager->RemovePlugin(pluginPath)) {
188             HILOG_INFO(LOG_CORE, "%s:pluginPath %s remove success!", __func__, pluginPath.c_str());
189         } else {
190             HILOG_INFO(LOG_CORE, "%s:pluginPath %s remove failed!", __func__, pluginPath.c_str());
191         }
192     } else {
193         HILOG_INFO(LOG_CORE, "%s:weak_ptr pluginManager lock failed!", __func__);
194     }
195 }