diff --git a/interfaces/kits/js/src/mod_fs/class_watcher/watcher_entity.cpp b/interfaces/kits/js/src/mod_fs/class_watcher/watcher_entity.cpp index 1500dfcfd4f9c268bbe8370d32799e60c91878da..f3adc69612b5c5bf89bbfc3d93d0492c8c089727 100644 --- a/interfaces/kits/js/src/mod_fs/class_watcher/watcher_entity.cpp +++ b/interfaces/kits/js/src/mod_fs/class_watcher/watcher_entity.cpp @@ -14,85 +14,568 @@ */ #include "watcher_entity.h" +#include #include +#include +#include #include +#include #include "filemgmt_libhilog.h" #include "uv.h" + namespace OHOS::FileManagement::ModuleFileIO { using namespace OHOS::FileManagement::LibN; -FileWatcher::FileWatcher() {} +using namespace std; + +namespace { + constexpr int64_t SELECT_TIME_OUT_US = 100000; + constexpr int64_t STOP_WATCHER_TIME_OUT_US = 120000; + const vector EVENT_LIST = { IN_ACCESS, IN_MODIFY, IN_ATTRIB, IN_CLOSE_WRITE, IN_CLOSE_NOWRITE, + IN_OPEN, IN_MOVED_FROM, IN_MOVED_TO, IN_CREATE, IN_DELETE, + IN_DELETE_SELF, IN_MOVE_SELF }; +} -FileWatcher::~FileWatcher() {} +shared_ptr FileWatcher::instance_ = nullptr; +mutex FileWatcher::mutex_; +mutex FileWatcher::watchMutex_; + +shared_ptr FileWatcher::GetInstance() +{ + if (instance_ == nullptr) { + lock_guard lock(mutex_); + if (instance_ == nullptr) { + instance_ = shared_ptr(new FileWatcher()); + } + } + return instance_; +} -bool FileWatcher::InitNotify(int &fd) +int32_t FileWatcher::GetNotifyId() { - fd = inotify_init(); - if (fd < 0) { + return notifyFd_; +} + +bool FileWatcher::InitNotify() +{ + notifyFd_ = inotify_init(); + if (notifyFd_ < 0) { HILOGE("Failed to init notify fail errCode:%{public}d", errno); return false; } return true; } -bool FileWatcher::StartNotify(WatcherInfoArg &arg) +vector GetEvents(const uint32_t &watchEvent) { - int wd = inotify_add_watch(arg.fd, arg.filename.c_str(), arg.events); + vector eventList; + for (auto event : EVENT_LIST) { + HILOGI("GetEvents 1 watchEvent:%{public}x, event:%{public}x", watchEvent, event); + if (watchEvent & event) { + HILOGI("GetEvents 2 found watchEvent:%{public}x", watchEvent); + eventList.push_back(event); + } + } + return eventList; +} + +vector FindUnWatchedEvent(const vector &allEvents, const uint32_t &event) +{ + HILOGI("FindUnWatchedEvent allEvents.size:%{public}d, event:%{public}x", allEvents.size(), event); + for(auto allevent: allEvents) { + HILOGI("FindUnWatchedEvent 1 allEvents.size:%{public}d, allevent:%{public}x", allEvents.size(), allevent); + } + + vector unWatchedEvents; + vector watchEvents = GetEvents(event); + HILOGI("FindUnWatchedEvent 2 watchEvents:%{public}d", watchEvents.size()); + for (auto event: watchEvents) { + HILOGI("FindUnWatchedEvent 3 event:%{public}x", event); + auto iter = find(allEvents.begin(), allEvents.end(), event); + if (iter == allEvents.end()) { + HILOGI("FindUnWatchedEvent 4 event:%{public}x", event); + unWatchedEvents.push_back(event); + } + } + return unWatchedEvents; +} + +bool FileWatcher::CheckEventWatched(const string &fileName, const uint32_t &event) +{ + HILOGI("CheckEventWatched fileName:%{public}s, event:%{public}x", fileName.c_str(), event); + auto iter = fileNameEventMap_.find(fileName); + if (iter == fileNameEventMap_.end()) { + return false; + } + vector allEvents = iter->second; + vector unWatchedEvents = FindUnWatchedEvent(allEvents, event); + if (unWatchedEvents.size() == 0) { + return true; + } + + return false; +} + +bool FileWatcher::CheckEventValid(const uint32_t &event) +{ + HILOGI("CheckEventValid begin:event:%{public}x", event); + vector events = GetEvents(event); + return events.size() > 0 ? true : false; +} + +bool FileWatcher::StartNotify(shared_ptr &arg) +{ + lock_guard lock(watchMutex_); + if (notifyFd_ < 0) { + HILOGE("Failed to start notify fail notifyFd_:%{public}d", notifyFd_); + return false; + } + + HILOGI("StartNotify event:%{public}x", arg->events); + if (!CheckEventValid(arg->events)) { + HILOGE("Failed to start notify, the watch event:%{public}x is wrong", arg->events); + errno = E_INVAL; + return false; + } + + if (CheckEventWatched(arg->fileName, arg->events)) { + for (auto iter = wdFileNameMap_.begin(); iter != wdFileNameMap_.end(); iter++) { + HILOGI("StartNotify 1 fileName:%{public}s", arg->fileName.c_str()); + if (iter->second == arg->fileName) { + HILOGI("StartNotify 2 fileName:%{public}s, wd:%{public}d", arg->fileName.c_str(), iter->first); + arg->wd = iter->first; + return true; + } + } + HILOGI("StartNotify 3 fileName:%{public}s", arg->fileName.c_str()); + HILOGE("Failed to start notify, not find:%{public}s data" , arg->fileName.c_str()); + return false; + } + + vector watchEvents = ParseEvent(arg->fileName.c_str(), arg->events); + uint32_t watchEvent = 0; + for (auto event: watchEvents) { + watchEvent |= event; + HILOGI("StartNotify 4 fileName:%{public}s, event:%{public}x, watchEvent:%{public}x", arg->fileName.c_str(), event, watchEvent); + } + HILOGI("StartNotify 5 fileName:%{public}s, watchEvent:%{public}x", arg->fileName.c_str(), watchEvent); + int wd = inotify_add_watch(notifyFd_, arg->fileName.c_str(), watchEvent); + HILOGI("StartNotify fileName:%{public}s, wd:%{public}d", arg->fileName.c_str(), wd); if (wd < 0) { HILOGE("Failed to start notify fail errCode:%{public}d", errno); return false; } - arg.wd = wd; - run_ = true; + arg->wd = wd; + AddWatcherWdFileNameMap(wd, arg->fileName); return true; } -bool FileWatcher::StopNotify(const WatcherInfoArg &arg) +bool FileWatcher::FindWatcherInfo(const std::string &fileName, const uint32_t &event) { - run_ = false; - if (arg.events == IN_DELETE_SELF) { - close(arg.fd); + auto iter = watcherInfoMap_.find(fileName); + if (iter == watcherInfoMap_.end()) { + return false; + } + vector> args = iter->second; + for (auto arg : args) { + if (arg->events == event) { + return true; + } + } + return false; +} + +void FileWatcher::RemoveEventFromMap(const shared_ptr &arg) +{ + HILOGI("RemoveEventFromMap fileName:%{public}s", arg->fileName.c_str()); + auto watcherInfosIter = watcherInfoMap_.find(arg->fileName); + if (watcherInfosIter == watcherInfoMap_.end()) { + HILOGI("RemoveEventFromMap 1 fileName:%{public}s", arg->fileName.c_str()); + return; + } + HILOGI("RemoveEventFromMap 2 fileName:%{public}s", arg->fileName.c_str()); + auto args = watcherInfosIter->second; + vector watchedEvent; + for (auto arg : args) { + uint32_t event = arg->events; + vector events = GetEvents(event); + watchedEvent.insert(watchedEvent.end(), events.begin(), events.end()); + } + HILOGI("RemoveEventFromMap 3 fileName:%{public}s, watchedEvent.size:%{public}d", arg->fileName.c_str(), + watchedEvent.size()); + sort(watchedEvent.begin(), watchedEvent.end()); + HILOGI("RemoveEventFromMap 4 fileName:%{public}s, watchedEvent.size:%{public}d", arg->fileName.c_str(), + watchedEvent.size()); + auto iter = unique(watchedEvent.begin(), watchedEvent.end()); + HILOGI("RemoveEventFromMap 5 fileName:%{public}s, watchedEvent.size:%{public}d", arg->fileName.c_str(), + watchedEvent.size()); + watchedEvent.erase(iter, watchedEvent.end()); + HILOGI("RemoveEventFromMap 6 fileName:%{public}s, watchedEvent.size:%{public}d", arg->fileName.c_str(), + watchedEvent.size()); + map>::iterator fileIter; + uint32_t removeEvent = arg->events; + vector removeEvents = GetEvents(removeEvent); + HILOGI("RemoveEventFromMap 7 fileName:%{public}s, removeEvents.size:%{public}d", arg->fileName.c_str(), + removeEvents.size()); + for (auto toRemoveEvent : removeEvents) { + HILOGI("RemoveEventFromMap 8 fileName:%{public}s, removeEvents.size:%{public}d, toRemoveEvent:%{public}x", + arg->fileName.c_str(), removeEvents.size(), toRemoveEvent); + auto watchedIter = find(watchedEvent.begin(), watchedEvent.end(), toRemoveEvent); + if (watchedIter != watchedEvent.end()) { + HILOGI("RemoveEventFromMap 9 fileName:%{public}s, removeEvents.size:%{public}d, toRemoveEvent:%{public}x", + arg->fileName.c_str(), removeEvents.size(), toRemoveEvent); + continue; + } + fileIter = fileNameEventMap_.find(arg->fileName); + HILOGI("RemoveEventFromMap 10 fileName:%{public}s, removeEvents.size:%{public}d, toRemoveEvent:%{public}x", + arg->fileName.c_str(), removeEvents.size(), toRemoveEvent); + if (fileIter == fileNameEventMap_.end()) { + HILOGI("RemoveEventFromMap 11 fileName:%{public}s, removeEvents.size:%{public}d, toRemoveEvent:%{public}x", + arg->fileName.c_str(), removeEvents.size(), toRemoveEvent); + continue; + } + HILOGI("RemoveEventFromMap 12 fileName:%{public}s, removeEvents.size:%{public}d, toRemoveEvent:%{public}x", + arg->fileName.c_str(), removeEvents.size(), toRemoveEvent); + auto eventIter = find(fileIter->second.begin(), fileIter->second.end(), toRemoveEvent); + HILOGI("RemoveEventFromMap 13 fileName:%{public}s, removeEvents.size:%{public}d, toRemoveEvent:%{public}x", + arg->fileName.c_str(), removeEvents.size(), toRemoveEvent); + if (eventIter == fileIter->second.end()) { + HILOGI("RemoveEventFromMap 14 fileName:%{public}s, removeEvents.size:%{public}d, toRemoveEvent:%{public}x", + arg->fileName.c_str(), removeEvents.size(), toRemoveEvent); + continue; + } + HILOGI("RemoveEventFromMap fileName:%{public}s remove:event%{public}x", arg->fileName.c_str(), toRemoveEvent); + fileIter->second.erase(eventIter); + } + + if (fileIter->second.size() == 0) { + fileNameEventMap_.erase(fileIter); + } + HILOGI("RemoveEventFromMap fileName:%{public}s end", arg->fileName.c_str()); +} + +bool FileWatcher::NotifyToWatchNewEvents(const shared_ptr &arg) +{ + if (FindWatcherInfo(arg->fileName, arg->events)) { return true; } - if (inotify_rm_watch(arg.fd, arg.wd) == -1) { - HILOGE("Failed to stop notify fail errCode:%{public}d", errno); + RemoveEventFromMap(arg); + auto eventIter = fileNameEventMap_.find(arg->fileName); + if (eventIter == fileNameEventMap_.end()) { + return true; + } + vector watchEvents = eventIter->second; + uint32_t watchEvent = 0; + for (auto event : watchEvents) { + watchEvent |= event; + } + int newWd = inotify_add_watch(notifyFd_, arg->fileName.c_str(), watchEvent); + + HILOGI("NotifyNewEvents fd:%{public}d, wd:%{public}d, fileName:%{public}s, watchEvent:%{public}x,newWd:%{public}d", + notifyFd_, arg->wd, arg->fileName.c_str(), watchEvent, newWd); + if (newWd < 0) { + HILOGE("Failed to start new notify fail errCode:%{public}d", errno); + return false; + } else { + if (newWd != arg->wd) { + HILOGE("New notify wd is error"); + return false; + } + AddWatcherWdFileNameMap(newWd, arg->fileName); + return true; + } +} + +bool FileWatcher::FindWatcherByFileName(const shared_ptr &arg) +{ + auto iter = watcherInfoMap_.find(arg->fileName); + if (iter == watcherInfoMap_.end()) { return false; } - close(arg.fd); return true; } -void FileWatcher::HandleEvent(WatcherInfoArg &arg, const struct inotify_event *event, WatcherCallback callback) +bool FileWatcher::StopNotify(const shared_ptr &arg) { - if (event->wd != arg.wd) { - return; + unique_lock lock(watchMutex_); + HILOGI("FileWatcher::StopNotify!"); + if (notifyFd_ < 0) { + HILOGE("Failed to stop notify fail notifyFd_:%{public}d", notifyFd_); + return false; } - std::string fileName = arg.filename; - if (event->len > 0) { - fileName.append(std::string("/")); - fileName.append(std::string(event->name)); + HILOGI("StopNotify wd :%{public}d", arg->wd); + RemoveWatcherInfo(arg); + if (FindWatcherByFileName(arg)) { + HILOGI("FindWatcherByFileName filename:%{public}s", arg->fileName.c_str()); + bool ret = NotifyToWatchNewEvents(arg); + if (!ret) { + HILOGE("Failed to notify watch new event notifyFd_:%{public}d", notifyFd_); + return false; + } + } else { + HILOGI("FindWatcherByFileName 2 filename:%{public}s", arg->fileName.c_str()); + auto iter = fileNameEventMap_.find(arg->fileName); + if (iter != fileNameEventMap_.end()) { + HILOGI("FindWatcherByFileName 3 filename:%{public}s", arg->fileName.c_str()); + fileNameEventMap_.erase(iter); + } } - callback(arg.env, arg.nRef, fileName, event->mask, event->cookie); + if (GetWatcherInfoSize(arg->wd) == 0) { + HILOGI("StopNotify 1"); + if (inotify_rm_watch(notifyFd_, arg->wd) == -1) { + HILOGI("StopNotify 2"); + auto iter = wdFileNameMap_.find(arg->wd); + if (iter == wdFileNameMap_.end()) { + HILOGE("Failed to stop notify, not find wd:%{public}d", arg->wd); + return false; + } + string filename = iter->second; + if (access(filename.c_str(), F_OK) == 0) { + HILOGE("Failed to stop notify fail errCode:%{public}d", errno); + RemoveWatcherWdFileNameMap(arg->wd); + return false; + } + } + HILOGI("StopNotify 3"); + RemoveWatcherWdFileNameMap(arg->wd); + if (watcherInfoMap_.size() == 0) { + HILOGI("StopNotify 4"); + close(notifyFd_); + notifyFd_ = -1; + run_ = false; + stopWatcherCv_.wait_for(lock, chrono::milliseconds(STOP_WATCHER_TIME_OUT_US)); + } + HILOGI("StopNotify 5"); + return true; + } + return true; } -void FileWatcher::GetNotifyEvent(WatcherInfoArg &arg, WatcherCallback callback) +void FileWatcher::GetNotifyEvent(WatcherCallback callback) { + if (run_) { + HILOGI("Listener Thread has started and do nothing!"); + return; + } + + run_ =true; char buf[BUF_SIZE] = {0}; struct inotify_event *event = nullptr; while (run_) { - int fd = arg.fd; + if (notifyFd_ < 0) { + HILOGE("Failed to run Listener Thread because notifyFd_:%{public}d", notifyFd_); + break; + } fd_set fds; FD_ZERO(&fds); - FD_SET(fd, &fds); - if (select(fd + 1, &fds, nullptr, nullptr, nullptr) > 0) { + FD_SET(notifyFd_, &fds); + timeval timeout{.tv_sec = 0, .tv_usec = SELECT_TIME_OUT_US}; + if (select(notifyFd_ + 1, &fds, nullptr, nullptr, &timeout) > 0) { int len, index = 0; - while (((len = read(fd, &buf, sizeof(buf))) < 0) && (errno == EINTR)) {}; + while (((len = read(notifyFd_, &buf, sizeof(buf))) < 0) && (errno == EINTR)) {}; while (index < len) { event = reinterpret_cast(buf + index); - HandleEvent(arg, event, callback); + NotifyEvent(event, callback); index += sizeof(struct inotify_event) + event->len; } } } + + if (!run_) { + stopWatcherCv_.notify_one(); + } + HILOGI("Listener Thread has stopped!"); +} + +void FileWatcher::AddWatcherInfo(const string &fileName, const shared_ptr &arg) +{ + WatcherInfoMap::iterator it = watcherInfoMap_.find(fileName); + if (it == watcherInfoMap_.end()) { + vector> watcherInfoVec = { arg }; + watcherInfoMap_[fileName] = watcherInfoVec; + return; + } + + auto watcherInfos = it->second; + for (auto &info : watcherInfos) { + bool isSame = false; + napi_strict_equals(info->env, info->nRef.Deref(info->env).val_, arg->nRef.Deref(arg->env).val_, &isSame); +HILOGI("AddWatcherInfo isSame: %{public}d", isSame); + if (isSame && info->events == arg->events) { + return; + } + } + it->second.push_back(arg); +} + +vector FileWatcher::ParseEvent(const string &fileName, const uint32_t &watcherEvent) +{ + HILOGI("ParseEvent begin fileName:%{public}s, watcherEvent:%{public}x", fileName.c_str(), watcherEvent); + auto iter = fileNameEventMap_.find(fileName); + if (iter == fileNameEventMap_.end()) { + HILOGI("ParseEvent 1 fileName:%{public}s, watcherEvent:%{public}x", fileName.c_str(), watcherEvent); + vector events = GetEvents(watcherEvent); + fileNameEventMap_[fileName] = events; + return events; + } else { + HILOGI("ParseEvent 01 fileName:%{public}s, iter->second.size:%{public}d", fileName.c_str(), + iter->second.size()); + vector notWatchedEvents = FindUnWatchedEvent(iter->second, watcherEvent); + if (notWatchedEvents.size() > 0) { + HILOGI("ParseEvent 2 fileName:%{public}s, watcherEvent:%{public}x, notWatchedEvents.size:%{public}d", + fileName.c_str(), watcherEvent, notWatchedEvents.size()); + vector newEvents; + newEvents.insert(newEvents.end(), iter->second.begin(), iter->second.end()); + newEvents.insert(newEvents.end(), notWatchedEvents.begin(), notWatchedEvents.end()); + sort(newEvents.begin(), newEvents.end()); + auto newEventIter = unique(newEvents.begin(), newEvents.end()); + newEvents.erase(newEventIter, newEvents.end()); + fileNameEventMap_[fileName] = newEvents; + HILOGI("ParseEvent 3 fileName:%{public}s, watcherEvent:%{public}x, newEvents.size:%{public}d", + fileName.c_str(), watcherEvent, newEvents.size()); + return newEvents; + } else { + HILOGI("ParseEvent 4 fileName:%{public}s, watcherEvent:%{public}x, event:%{public}d", + fileName.c_str(), watcherEvent, iter->second.size()); + return iter->second; + } + } +} + +void FileWatcher::RemoveWatcherInfo(const shared_ptr &arg) +{ + HILOGI("RemoveWatcherInfo filename:%{public}s, wd:%{public}d", arg->fileName.c_str(), arg->wd); + auto fileNameIter = wdFileNameMap_.find(arg->wd); + if (fileNameIter == wdFileNameMap_.end()) { + HILOGI("RemoveWatcherInfo 1 filename:%{public}s, wd:%{public}d", arg->fileName.c_str(), arg->wd); + return; + } + string fileName = fileNameIter->second; + HILOGI("RemoveWatcherInfo 2 filename:%{public}s, wd:%{public}d", arg->fileName.c_str(), arg->wd); + auto iter = watcherInfoMap_.find(fileName); + if (iter == watcherInfoMap_.end()) { + HILOGI("RemoveWatcherInfo 3 filename:%{public}s, wd:%{public}d", arg->fileName.c_str(), arg->wd); + return; + } + auto infoArgs = iter->second; + for (size_t i = 0; i < infoArgs.size(); i++) { + if (infoArgs[i]->events == arg->events) { + bool isSame = false; + napi_strict_equals(infoArgs[i]->env, infoArgs[i]->nRef.Deref(infoArgs[i]->env).val_, + arg->nRef.Deref(arg->env).val_, &isSame); + if (isSame) { + HILOGI("RemoveWatcherInfo 4 filename:%{public}s, wd:%{public}d", arg->fileName.c_str(), arg->wd); + iter->second.erase(iter->second.begin() + i); + } + } + } + if (iter->second.size() == 0) { + watcherInfoMap_.erase(iter); + } +} + +int32_t FileWatcher::GetWatcherInfoSize(const int &wd) +{ + HILOGI("GetWatcherInfoSize 1"); + auto fileNameIter = wdFileNameMap_.find(wd); + if (fileNameIter == wdFileNameMap_.end()) { + HILOGI("GetWatcherInfoSize 2"); + return 0; + } + string fileName = fileNameIter->second; + auto watcherInfosIter = watcherInfoMap_.find(fileName); + if (watcherInfosIter == watcherInfoMap_.end()) { + HILOGI("GetWatcherInfoSize 3"); + return 0; + } + HILOGI("GetWatcherInfoSize 4 size:%{public}d", watcherInfosIter->second.size()); + return watcherInfosIter->second.size(); +} + +bool CheckIncludeEvent(const uint32_t &allEvent, const uint32_t &event) +{ + HILOGI("CheckIncludeEvent 1 allEvent:%{public}x, event:%{public}x", allEvent, event); + vector events = GetEvents(event); + HILOGI("CheckIncludeEvent 2 events.size:%{public}d", events.size()); + for (auto event : events) { + HILOGI("CheckIncludeEvent 3 event:%{public}x", event); + if (allEvent & event) { + HILOGI("CheckIncludeEvent 4 found event:%{public}x", event); + return true; + } + } + HILOGI("CheckIncludeEvent 5 allEvent:%{public}x, event:%{public}x", allEvent, event); + return false; +} + +void FileWatcher::NotifyEvent(const struct inotify_event *event, WatcherCallback callback) +{ + lock_guard lock(watchMutex_); + HILOGI("NotifyEvent 1 wd:%{public}d, mask:%{public}x", event->wd, event->mask); + auto fileNameIter = wdFileNameMap_.find(event->wd); + if (fileNameIter == wdFileNameMap_.end()) { + return; + } + HILOGI("NotifyEvent 2 wd:%{public}d", event->wd); + string fileName = fileNameIter->second; + HILOGI("NotifyEvent 3 wd:%{public}d, fileName:%{public}s", event->wd, fileName.c_str()); + auto watcherInfosIter = watcherInfoMap_.find(fileName); + if (watcherInfosIter == watcherInfoMap_.end()) { + return; + } + HILOGI("NotifyEvent 4 wd:%{public}d, fileName:%{public}s", event->wd, fileName.c_str()); + auto args = watcherInfosIter->second; + HILOGI("NotifyEvent 04 wd:%{public}d, fileName:%{public}s, args.size:%{public}d", + event->wd, fileName.c_str(), args.size()); + for (int i = 0; i < args.size(); i++) { + HILOGI("NotifyEvent 05 i:%{public}d, wd:%{public}d, fileName:%{public}s, watchEvent:%{public}x", + i, event->wd, fileName.c_str(), args[i]->events); + } + for (auto arg : args) { + uint32_t watchEvent = arg->events; + HILOGI("NotifyEvent 5 wd:%{public}d, fileName:%{public}s, watchEvent:%{public}x", event->wd, fileName.c_str(), + arg->events); + if (!CheckIncludeEvent(event->mask, watchEvent)) { + HILOGI("NotifyEvent 6 wd:%{public}d, fileName:%{public}s, watchEvent:%{public}x, mask:%{public}x", + event->wd, fileName.c_str(), arg->events, event->mask); + continue; + } + if (event->len > 0) { + HILOGI("NotifyEvent 7 wd:%{public}d, fileName:%{public}s, watchEvent:%{public}x, mask:%{public}x", + event->wd, fileName.c_str(), arg->events, event->mask); + fileName.append(string("/")); + fileName.append(string(event->name)); + } + HILOGI("NotifyEvent 8 wd:%{public}d, fileName:%{public}s, watchEvent:%{public}x, mask:%{public}x", + event->wd, fileName.c_str(), arg->events, event->mask); + callback(arg->env, arg->nRef, fileName, event->mask, event->cookie); + } +} + +void FileWatcher::AddWatcherWdFileNameMap(const int &wd, const string &fileName) +{ + HILOGI("AddWatcherWdFileNameMap fileName:%{public}s, wd:%{public}d", fileName.c_str(), wd); + auto it = wdFileNameMap_.find(wd); + if (it == wdFileNameMap_.end()) { + HILOGI("AddWatcherWdFileNameMap fileName:%{public}s, wd:%{public}d insert", fileName.c_str(), wd); + wdFileNameMap_.insert(pair(wd, fileName)); + } +} + +void FileWatcher::RemoveWatcherWdFileNameMap(const int &wd) +{ + HILOGI("RemoveWatcherWdFileNameMap wd:%{public}d", wd); + auto pathIter = wdFileNameMap_.find(wd); + if(pathIter != wdFileNameMap_.end()) { + string fileName = pathIter->second; + HILOGI("RemoveWatcherWdFileNameMap wd:%{public}d, fileName:%{public}s", wd, fileName.c_str()); + auto watcherInfosIter = watcherInfoMap_.find(fileName); + if (watcherInfosIter == watcherInfoMap_.end()) { + HILOGI("RemoveWatcherWdFileNameMap 1 wd:%{public}d, fileName:%{public}s", wd, fileName.c_str()); + wdFileNameMap_.erase(pathIter); + } else { + HILOGI("RemoveWatcherWdFileNameMap 2 wd:%{public}d, fileName:%{public}s", wd, fileName.c_str()); + } + } } } // namespace OHOS::FileManagement::ModuleFileIO diff --git a/interfaces/kits/js/src/mod_fs/class_watcher/watcher_entity.h b/interfaces/kits/js/src/mod_fs/class_watcher/watcher_entity.h index fad6ec27adcd5a43fb5ed99f44b4ed9b391dde84..36fb462cd330c987ab281e7e595058f35f529007 100644 --- a/interfaces/kits/js/src/mod_fs/class_watcher/watcher_entity.h +++ b/interfaces/kits/js/src/mod_fs/class_watcher/watcher_entity.h @@ -14,23 +14,30 @@ */ #ifndef INTERFACES_KITS_JS_SRC_MOD_FILEIO_CLASS_WATCHER_WATCHER_ENTITY_H #define INTERFACES_KITS_JS_SRC_MOD_FILEIO_CLASS_WATCHER_WATCHER_ENTITY_H + +#include #include +#include +#include #include #include +#include +#include #include #include "filemgmt_libn.h" + namespace OHOS::FileManagement::ModuleFileIO { using WatcherCallback = void (*)(napi_env env, LibN::NRef &callback, const std::string &filename, const uint32_t &event, const uint32_t &cookie); + constexpr int BUF_SIZE = 1024; struct WatcherInfoArg { - std::string filename = ""; + std::string fileName = ""; uint32_t events = 0; - int fd = -1; int wd = -1; napi_env env = nullptr; LibN::NRef nRef; @@ -38,24 +45,49 @@ struct WatcherInfoArg { ~WatcherInfoArg() = default; }; +using WatcherInfoMap = std::unordered_map>>; + class FileWatcher { public: - FileWatcher(); - ~FileWatcher(); - bool InitNotify(int &fd); - bool StartNotify(WatcherInfoArg &arg); - bool StopNotify(const WatcherInfoArg &arg); - void GetNotifyEvent(WatcherInfoArg &arg, WatcherCallback callback); + virtual ~FileWatcher() = default; + + static std::shared_ptr GetInstance(); + int32_t GetNotifyId(); + bool InitNotify(); + bool StartNotify(std::shared_ptr &arg); + bool StopNotify(const std::shared_ptr &arg); + void GetNotifyEvent(WatcherCallback callback); + void AddWatcherInfo(const std::string &fileName, const std::shared_ptr &arg); + +private: + FileWatcher() = default; + void AddWatcherWdFileNameMap(const int &wd, const std::string &fileName); + void RemoveWatcherWdFileNameMap(const int &wd); + void RemoveWatcherInfo(const std::shared_ptr &arg); + int32_t GetWatcherInfoSize(const int &wd); + bool CheckEventWatched(const std::string &fileName, const uint32_t &event); + std::vector ParseEvent(const std::string &fileName, const uint32_t &watcherEvent); + void NotifyEvent(const struct inotify_event *event, WatcherCallback callback); + bool NotifyToWatchNewEvents(const std::shared_ptr &arg); + bool FindWatcherInfo(const std::string &fileName, const uint32_t &event); + bool FindWatcherByFileName(const std::shared_ptr &arg); + void RemoveEventFromMap(const std::shared_ptr &arg); + bool CheckEventValid(const uint32_t &event); private: - void HandleEvent(WatcherInfoArg &arg, const struct inotify_event *event, - WatcherCallback callback); + static std::mutex mutex_; + static std::mutex watchMutex_; + static std::shared_ptr instance_; bool run_ = false; + int32_t notifyFd_ = -1; + WatcherInfoMap watcherInfoMap_; + std::map wdFileNameMap_; + std::map> fileNameEventMap_; + std::condition_variable stopWatcherCv_; }; struct WatcherEntity { - std::unique_ptr data_; - std::shared_ptr watcherPtr_; + std::shared_ptr data_; }; } // namespace OHOS::FileManagement::ModuleFileIO namespace OHOS #endif diff --git a/interfaces/kits/js/src/mod_fs/class_watcher/watcher_n_exporter.cpp b/interfaces/kits/js/src/mod_fs/class_watcher/watcher_n_exporter.cpp index a1988cbebe6849b9088c21bfde63a443937417b1..10c4bb06ed22166b50a618a0019ff96dc4d266fa 100644 --- a/interfaces/kits/js/src/mod_fs/class_watcher/watcher_n_exporter.cpp +++ b/interfaces/kits/js/src/mod_fs/class_watcher/watcher_n_exporter.cpp @@ -64,11 +64,14 @@ napi_value WatcherNExporter::Stop(napi_env env, napi_callback_info info) NError(EINVAL).ThrowErr(env); return nullptr; } - if (!watchEntity->watcherPtr_->StopNotify(*(watchEntity->data_))) { +HILOGE("WatcherNExporter::Stop notifyFd_: %{public}d", FileWatcher::GetInstance()->GetNotifyId()); +HILOGE("WatcherNExporter::Stop wd: %{public}d", watchEntity->data_->wd); + if (!FileWatcher::GetInstance()->StopNotify(watchEntity->data_)) { NError(errno).ThrowErr(env); return nullptr; } - + + HILOGE("WatcherNExporter::Stop wd: %{public}d success", watchEntity->data_->wd); return NVal::CreateUndefined(env).val_; } @@ -85,14 +88,16 @@ napi_value WatcherNExporter::Start(napi_env env, napi_callback_info info) NError(EINVAL).ThrowErr(env); return nullptr; } - - if (!watchEntity->watcherPtr_->StartNotify(*(watchEntity->data_))) { +HILOGE("WatcherNExporter::Start notifyFd_: %{public}d", FileWatcher::GetInstance()->GetNotifyId()); + if (!FileWatcher::GetInstance()->StartNotify(watchEntity->data_)) { NError(errno).ThrowErr(env); return nullptr; } +HILOGE("WatcherNExporter::Start filename: %{public}s", watchEntity->data_->fileName.c_str()); auto cbExec = [watchEntity]() -> NError { - watchEntity->watcherPtr_->GetNotifyEvent(*(watchEntity->data_), WatcherCallback); +HILOGE("WatcherNExporter::Start GetNotifyEvent wd: %{public}d", watchEntity->data_->wd); + FileWatcher::GetInstance()->GetNotifyEvent(WatcherCallback); return NError(ERRNO_NOERR); }; @@ -155,34 +160,45 @@ static void WatcherCallbackComplete(uv_work_t *work, int stat) void WatcherNExporter::WatcherCallback(napi_env env, NRef &callback, const std::string &fileName, const uint32_t &event, const uint32_t &cookie) { + HILOGI("WatcherCallback 1 fileName:%{public}s, event:%{public}x, cookie:%{public}d", + fileName.c_str(), event, cookie); uv_loop_s *loop = nullptr; + HILOGI("WatcherCallback 2"); napi_get_uv_event_loop(env, &loop); + HILOGI("WatcherCallback 3"); if (loop == nullptr) { + HILOGI("WatcherCallback 4"); HILOGE("Failed to get uv event loop"); return; } - + HILOGI("WatcherCallback 5"); uv_work_t *work = new (std::nothrow) uv_work_t; + HILOGI("WatcherCallback 6"); if (work == nullptr) { + HILOGI("WatcherCallback 7"); HILOGE("Failed to create uv_work_t pointer"); return; } - + HILOGI("WatcherCallback 8"); if (!callback) { + HILOGI("WatcherCallback 9"); HILOGE("Failed to pass watcher callback"); return; } + HILOGI("WatcherCallback 10"); JSCallbackContext *callbackContext = new (std::nothrow) JSCallbackContext(callback); callbackContext->env_ = env; callbackContext->fileName_ = fileName; callbackContext->event_ = event; callbackContext->cookie_ = cookie; work->data = reinterpret_cast(callbackContext); - + HILOGI("WatcherCallback 11"); int ret = uv_queue_work( loop, work, [](uv_work_t *work) {}, reinterpret_cast(WatcherCallbackComplete)); + HILOGI("WatcherCallback 12"); if (ret != 0) { + HILOGI("WatcherCallback 13"); HILOGE("Failed to execute libuv work queue, ret: %{public}d", ret); delete callbackContext; delete work; diff --git a/interfaces/kits/js/src/mod_fs/properties/watcher.cpp b/interfaces/kits/js/src/mod_fs/properties/watcher.cpp index 8d3fa0341affa6418f068f2b485a6acb606f371c..d18da71d6c5232c0785591dd8bbee340833b41f5 100644 --- a/interfaces/kits/js/src/mod_fs/properties/watcher.cpp +++ b/interfaces/kits/js/src/mod_fs/properties/watcher.cpp @@ -31,7 +31,7 @@ using namespace std; using namespace OHOS::FileManagement::LibN; namespace { - const std::string STORAGE_DATA_PATH = "/data"; + const string STORAGE_DATA_PATH = "/data"; bool IsSystemApp() { uint64_t fullTokenId = OHOS::IPCSkeleton::GetCallingFullTokenID(); @@ -39,21 +39,16 @@ namespace { } } -static tuple, napi_value, NError> CreateAndCheckForWatcherEntity(napi_env env, int& fd) +static tuple CreateAndCheckForWatcherEntity(napi_env env, int &fd) { - auto watcherPtr = CreateSharedPtr(); - if (watcherPtr == nullptr) { - HILOGE("Failed to request heap memory."); - return {nullptr, nullptr, NError(ENOMEM)}; - } - if (!watcherPtr->InitNotify(fd)) { - return {watcherPtr, nullptr, NError(errno)}; + if (FileWatcher::GetInstance()->GetNotifyId() < 0 && !FileWatcher::GetInstance()->InitNotify()) { + return {nullptr, NError(errno)}; } napi_value objWatcher = NClass::InstantiateClass(env, WatcherNExporter::className_, {}); if (!objWatcher) { - return {watcherPtr, nullptr, NError(EINVAL)}; + return {nullptr, NError(EINVAL)}; } - return {watcherPtr, objWatcher, NError(ERRNO_NOERR)}; + return {objWatcher, NError(ERRNO_NOERR)}; } napi_value Watcher::CreateWatcher(napi_env env, napi_callback_info info) @@ -75,15 +70,21 @@ napi_value Watcher::CreateWatcher(napi_env env, napi_callback_info info) return nullptr; } - auto [succGetEvent, events] = NVal(env, funcArg[NARG_POS::SECOND]).ToUint32(); + auto [succGetEvent, events] = NVal(env, funcArg[NARG_POS::SECOND]).ToInt32(); if (!succGetEvent) { NError(EINVAL).ThrowErr(env); return nullptr; } + HILOGE("CreateWatcher events: %{public}d", events); + if (events <= 0) { + NError(EINVAL).ThrowErr(env); + return nullptr; + } + int fd = -1; - auto [watcherPtr, objWatcher, err] = CreateAndCheckForWatcherEntity(env, fd); - if (watcherPtr == nullptr || !objWatcher) { + auto [objWatcher, err] = CreateAndCheckForWatcherEntity(env, fd); + if (!objWatcher) { err.ThrowErr(env); return nullptr; } @@ -98,19 +99,18 @@ napi_value Watcher::CreateWatcher(napi_env env, napi_callback_info info) NError(EINVAL).ThrowErr(env); return nullptr; } - watcherEntity->data_ = CreateUniquePtr(NVal(env, funcArg[NARG_POS::THIRD])); - if (watcherEntity->data_ == nullptr) { + auto infoArg = CreateSharedPtr(NVal(env, funcArg[NARG_POS::THIRD])); + if (infoArg == nullptr) { HILOGE("Failed to request heap memory."); NError(ENOMEM).ThrowErr(env); return nullptr; } - watcherEntity->data_->events = events; - watcherEntity->data_->env = env; - watcherEntity->data_->filename = string(filename.get()); - watcherEntity->data_->fd = fd; + infoArg->events = events; + infoArg->env = env; + infoArg->fileName = string(filename.get()); + watcherEntity->data_ = infoArg; + FileWatcher::GetInstance()->AddWatcherInfo(string(filename.get()), infoArg); - watcherEntity->watcherPtr_ = watcherPtr; - return objWatcher; } } // namespace OHOS::FileManagement::ModuleFileIO