1 /*
2 * Copyright (C) 2022 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 #include "mtp_file_observer.h"
16 #include <memory>
17 #include <securec.h>
18 #include <string>
19 #include <sys/inotify.h>
20 #include <unistd.h>
21 #include "media_log.h"
22
23 using namespace std;
24 namespace OHOS {
25 namespace Media {
26 bool MtpFileObserver::isRunning_ = false;
27 int MtpFileObserver::inotifyFd_ = 0;
28 std::map<int, std::string> MtpFileObserver::watchMap_;
29 std::mutex MtpFileObserver::eventLock_;
30 const int BUF_SIZE = 1024;
31 #ifdef HAS_BATTERY_MANAGER_PART
32 const int LOW_BATTERY = 50;
33 #endif
SendEvent(const inotify_event & event,const std::string & path,const ContextSptr & context)34 void MtpFileObserver::SendEvent(const inotify_event &event, const std::string &path, const ContextSptr &context)
35 {
36 string fileName;
37 std::shared_ptr<MtpEvent> eventPtr = std::make_shared<OHOS::Media::MtpEvent>(context);
38 if ((event.mask & IN_CREATE) || (event.mask & IN_MOVED_TO)) {
39 fileName = path + "/" + event.name;
40 MEDIA_DEBUG_LOG("MtpFileObserver AddInotifyEvents create/MOVED_TO: path:%{private}s", fileName.c_str());
41 eventPtr->SendObjectAdded(fileName);
42 } else if ((event.mask & IN_DELETE) || (event.mask & IN_MOVED_FROM)) {
43 fileName = path + "/" + event.name;
44 MEDIA_DEBUG_LOG("MtpFileObserver AddInotifyEvents delete/MOVED_FROM: path:%{private}s", fileName.c_str());
45 eventPtr->SendObjectRemoved(fileName);
46 } else if (event.mask & IN_CLOSE_WRITE) {
47 fileName = path + "/" + event.name;
48 MEDIA_DEBUG_LOG("MtpFileObserver AddInotifyEvents IN_CLOSE_WRITE : path:%{private}s", fileName.c_str());
49 eventPtr->SendObjectInfoChanged(fileName);
50 }
51 }
52
AddInotifyEvents(const int & inotifyFd,const ContextSptr & context)53 bool MtpFileObserver::AddInotifyEvents(const int &inotifyFd, const ContextSptr &context)
54 {
55 char eventBuf[BUF_SIZE] = {0};
56
57 int ret = read(inotifyFd, eventBuf, sizeof(eventBuf));
58 if (ret < (int)sizeof(struct inotify_event)) {
59 MEDIA_ERR_LOG("MtpFileObserver AddInotifyEvents no event");
60 return false;
61 }
62
63 struct inotify_event *positionEvent = (struct inotify_event *)eventBuf;
64 struct inotify_event *event;
65 while (ret >= (int)sizeof(struct inotify_event)) {
66 event = positionEvent;
67 if (event->len) {
68 bool isFind;
69 map<int, string>::iterator iter;
70 {
71 lock_guard<mutex> lock(eventLock_);
72 iter = watchMap_.find(event->wd);
73 isFind = iter != watchMap_.end();
74 }
75 if (isFind) {
76 string path = iter->second;
77 SendEvent(*event, path, context);
78 }
79 }
80 positionEvent++;
81 ret -= (int)sizeof(struct inotify_event);
82 }
83 return true;
84 }
85
SendBattery(const ContextSptr & context)86 void MtpFileObserver::SendBattery(const ContextSptr &context)
87 {
88 #ifdef HAS_BATTERY_MANAGER_PART
89 std::shared_ptr<MtpEvent> eventPtr = std::make_shared<OHOS::Media::MtpEvent>(context);
90 auto battery = make_shared<MtpOperationUtils>(context);
91 if (LOW_BATTERY >= battery->GetBatteryLevel()) {
92 eventPtr->SendDevicePropertyChanged();
93 }
94 #endif
95 }
96
StopFileInotify()97 bool MtpFileObserver::StopFileInotify()
98 {
99 isRunning_ = false;
100 lock_guard<mutex> lock(eventLock_);
101 for (auto ret : watchMap_) {
102 if (inotify_rm_watch(inotifyFd_, ret.first) == -1) {
103 MEDIA_ERR_LOG("MtpFileObserver StopFileInotify inotify_rm_watch error");
104 return false;
105 }
106 }
107 close(inotifyFd_);
108 watchMap_.clear();
109 startThread_ = false;
110 inotifySuccess_ = false;
111 inotifyFd_ = 0;
112 return true;
113 }
114
StartFileInotify()115 bool MtpFileObserver::StartFileInotify()
116 {
117 isRunning_ = true;
118 inotifyFd_ = inotify_init();
119 if (inotifyFd_ == -1) {
120 MEDIA_ERR_LOG("MtpFileObserver inotify_init false");
121 return false;
122 } else {
123 inotifySuccess_ = true;
124 return true;
125 }
126 }
127
WatchPathThread(const ContextSptr & context)128 bool MtpFileObserver::WatchPathThread(const ContextSptr &context)
129 {
130 while (isRunning_) {
131 SendBattery(context);
132 size_t size;
133 {
134 lock_guard<mutex> lock(eventLock_);
135 size = watchMap_.size();
136 }
137 if (size > 0) {
138 AddInotifyEvents(inotifyFd_, context);
139 }
140 }
141 return true;
142 }
143
AddFileInotify(const std::string & path,const std::string & realPath,const ContextSptr & context)144 void MtpFileObserver::AddFileInotify(const std::string &path, const std::string &realPath, const ContextSptr &context)
145 {
146 if (inotifySuccess_) {
147 lock_guard<mutex> lock(eventLock_);
148 if (!path.empty() && !realPath.empty()) {
149 int ret = inotify_add_watch(inotifyFd_, realPath.c_str(),
150 IN_CLOSE_WRITE | IN_MOVED_FROM | IN_MOVED_TO | IN_CREATE | IN_DELETE);
151 watchMap_.insert(make_pair(ret, path));
152 }
153 if (!startThread_) {
154 std::thread watchThread([context] { context->WatchPathThread(); });
155 watchThread.detach();
156 startThread_ = true;
157 }
158 }
159 }
160 } // namespace Media
161 } // namespace OHOS
162