1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "libpixelusb-MonitorFfs"
18
19 #include "include/pixelusb/MonitorFfs.h"
20
21 #include <android-base/file.h>
22 #include <sys/epoll.h>
23 #include <sys/eventfd.h>
24 #include <sys/inotify.h>
25 #include <utils/Log.h>
26
27 #include <chrono>
28 #include <memory>
29 #include <mutex>
30
31 namespace android {
32 namespace hardware {
33 namespace google {
34 namespace pixel {
35 namespace usb {
36
37 using ::android::base::WriteStringToFile;
38 using ::std::chrono::microseconds;
39 using ::std::chrono::steady_clock;
40 using ::std::literals::chrono_literals::operator""ms;
41
42 static volatile bool gadgetPullup;
43
MonitorFfs(const char * const gadget)44 MonitorFfs::MonitorFfs(const char *const gadget)
45 : mWatchFd(),
46 mEndpointList(),
47 mLock(),
48 mCv(),
49 mLockFd(),
50 mCurrentUsbFunctionsApplied(false),
51 mMonitor(),
52 mCallback(NULL),
53 mPayload(NULL),
54 mGadgetName(gadget),
55 mMonitorRunning(false) {
56 unique_fd eventFd(eventfd(0, 0));
57 if (eventFd == -1) {
58 ALOGE("mEventFd failed to create %d", errno);
59 abort();
60 }
61
62 unique_fd epollFd(epoll_create(2));
63 if (epollFd == -1) {
64 ALOGE("mEpollFd failed to create %d", errno);
65 abort();
66 }
67
68 unique_fd inotifyFd(inotify_init());
69 if (inotifyFd < 0) {
70 ALOGE("inotify init failed");
71 abort();
72 }
73
74 if (addEpollFd(epollFd, inotifyFd) == -1)
75 abort();
76
77 if (addEpollFd(epollFd, eventFd) == -1)
78 abort();
79
80 mEpollFd = std::move(epollFd);
81 mInotifyFd = std::move(inotifyFd);
82 mEventFd = std::move(eventFd);
83 gadgetPullup = false;
84 }
85
displayInotifyEvent(struct inotify_event * i)86 static void displayInotifyEvent(struct inotify_event *i) {
87 ALOGE(" wd =%2d; ", i->wd);
88 if (i->cookie > 0)
89 ALOGE("cookie =%4d; ", i->cookie);
90
91 ALOGE("mask = ");
92 if (i->mask & IN_ACCESS)
93 ALOGE("IN_ACCESS ");
94 if (i->mask & IN_ATTRIB)
95 ALOGE("IN_ATTRIB ");
96 if (i->mask & IN_CLOSE_NOWRITE)
97 ALOGE("IN_CLOSE_NOWRITE ");
98 if (i->mask & IN_CLOSE_WRITE)
99 ALOGE("IN_CLOSE_WRITE ");
100 if (i->mask & IN_CREATE)
101 ALOGE("IN_CREATE ");
102 if (i->mask & IN_DELETE)
103 ALOGE("IN_DELETE ");
104 if (i->mask & IN_DELETE_SELF)
105 ALOGE("IN_DELETE_SELF ");
106 if (i->mask & IN_IGNORED)
107 ALOGE("IN_IGNORED ");
108 if (i->mask & IN_ISDIR)
109 ALOGE("IN_ISDIR ");
110 if (i->mask & IN_MODIFY)
111 ALOGE("IN_MODIFY ");
112 if (i->mask & IN_MOVE_SELF)
113 ALOGE("IN_MOVE_SELF ");
114 if (i->mask & IN_MOVED_FROM)
115 ALOGE("IN_MOVED_FROM ");
116 if (i->mask & IN_MOVED_TO)
117 ALOGE("IN_MOVED_TO ");
118 if (i->mask & IN_OPEN)
119 ALOGE("IN_OPEN ");
120 if (i->mask & IN_Q_OVERFLOW)
121 ALOGE("IN_Q_OVERFLOW ");
122 if (i->mask & IN_UNMOUNT)
123 ALOGE("IN_UNMOUNT ");
124 ALOGE("\n");
125
126 if (i->len > 0)
127 ALOGE(" name = %s\n", i->name);
128 }
129
startMonitorFd(void * param)130 void *MonitorFfs::startMonitorFd(void *param) {
131 MonitorFfs *monitorFfs = (MonitorFfs *)param;
132 char buf[kBufferSize];
133 bool writeUdc = true, stopMonitor = false;
134 struct epoll_event events[kEpollEvents];
135 steady_clock::time_point disconnect;
136
137 bool descriptorWritten = true;
138 for (int i = 0; i < static_cast<int>(monitorFfs->mEndpointList.size()); i++) {
139 if (access(monitorFfs->mEndpointList.at(i).c_str(), R_OK)) {
140 descriptorWritten = false;
141 break;
142 }
143 }
144
145 // notify here if the endpoints are already present.
146 if (descriptorWritten) {
147 usleep(kPullUpDelay);
148 if (WriteStringToFile(monitorFfs->mGadgetName, PULLUP_PATH)) {
149 std::lock_guard<std::mutex> lock(monitorFfs->mLock);
150 monitorFfs->mCurrentUsbFunctionsApplied = true;
151 monitorFfs->mCallback(monitorFfs->mCurrentUsbFunctionsApplied, monitorFfs->mPayload);
152 gadgetPullup = true;
153 writeUdc = false;
154 ALOGI("GADGET pulled up");
155 monitorFfs->mCv.notify_all();
156 }
157 }
158
159 while (!stopMonitor) {
160 int nrEvents = epoll_wait(monitorFfs->mEpollFd, events, kEpollEvents, -1);
161
162 if (nrEvents <= 0) {
163 ALOGE("epoll wait did not return descriptor number");
164 continue;
165 }
166
167 for (int i = 0; i < nrEvents; i++) {
168 ALOGV("event=%u on fd=%d\n", events[i].events, events[i].data.fd);
169
170 if (events[i].data.fd == monitorFfs->mInotifyFd) {
171 // Process all of the events in buffer returned by read().
172 int numRead = read(monitorFfs->mInotifyFd, buf, kBufferSize);
173 for (char *p = buf; p < buf + numRead;) {
174 struct inotify_event *event = (struct inotify_event *)p;
175 if (kDebug) {
176 displayInotifyEvent(event);
177 }
178
179 p += sizeof(struct inotify_event) + event->len;
180
181 bool descriptorPresent = true;
182 for (int j = 0; j < static_cast<int>(monitorFfs->mEndpointList.size()); j++) {
183 if (access(monitorFfs->mEndpointList.at(j).c_str(), R_OK)) {
184 if (kDebug) {
185 ALOGI("%s absent", monitorFfs->mEndpointList.at(j).c_str());
186 }
187 descriptorPresent = false;
188 break;
189 }
190 }
191
192 if (!descriptorPresent && !writeUdc) {
193 if (kDebug) {
194 ALOGI("endpoints not up");
195 }
196 writeUdc = true;
197 disconnect = std::chrono::steady_clock::now();
198 } else if (descriptorPresent && writeUdc) {
199 steady_clock::time_point temp = steady_clock::now();
200
201 if (std::chrono::duration_cast<microseconds>(temp - disconnect).count() <
202 kPullUpDelay)
203 usleep(kPullUpDelay);
204
205 if (WriteStringToFile(monitorFfs->mGadgetName, PULLUP_PATH)) {
206 std::lock_guard<std::mutex> lock(monitorFfs->mLock);
207 monitorFfs->mCurrentUsbFunctionsApplied = true;
208 monitorFfs->mCallback(monitorFfs->mCurrentUsbFunctionsApplied,
209 monitorFfs->mPayload);
210 ALOGI("GADGET pulled up");
211 writeUdc = false;
212 gadgetPullup = true;
213 // notify the main thread to signal userspace.
214 monitorFfs->mCv.notify_all();
215 }
216 }
217 }
218 } else {
219 uint64_t flag;
220 read(monitorFfs->mEventFd, &flag, sizeof(flag));
221 if (flag == 100) {
222 stopMonitor = true;
223 break;
224 }
225 }
226 }
227 }
228 return NULL;
229 }
230
reset()231 void MonitorFfs::reset() {
232 std::lock_guard<std::mutex> lock(mLockFd);
233 uint64_t flag = 100;
234 unsigned long ret;
235
236 if (mMonitorRunning) {
237 // Stop the monitor thread by writing into signal fd.
238 ret = TEMP_FAILURE_RETRY(write(mEventFd, &flag, sizeof(flag)));
239 if (ret < 0)
240 ALOGE("Error writing eventfd errno=%d", errno);
241
242 ALOGI("mMonitor signalled to exit");
243 mMonitor->join();
244 ALOGI("mMonitor destroyed");
245 mMonitorRunning = false;
246 }
247
248 for (std::vector<int>::size_type i = 0; i != mWatchFd.size(); i++)
249 inotify_rm_watch(mInotifyFd, mWatchFd[i]);
250
251 mEndpointList.clear();
252 gadgetPullup = false;
253 mCallback = NULL;
254 mPayload = NULL;
255 }
256
startMonitor()257 bool MonitorFfs::startMonitor() {
258 mMonitor = std::make_unique<std::thread>(this->startMonitorFd, this);
259 mMonitorRunning = true;
260 return true;
261 }
262
isMonitorRunning()263 bool MonitorFfs::isMonitorRunning() {
264 return mMonitorRunning;
265 }
266
waitForPullUp(int timeout_ms)267 bool MonitorFfs::waitForPullUp(int timeout_ms) {
268 std::unique_lock<std::mutex> lk(mLock);
269
270 if (gadgetPullup)
271 return true;
272
273 if (mCv.wait_for(lk, timeout_ms * 1ms, [] { return gadgetPullup; })) {
274 ALOGI("monitorFfs signalled true");
275 return true;
276 } else {
277 ALOGI("monitorFfs signalled error");
278 // continue monitoring as the descriptors might be written at a later
279 // point.
280 return false;
281 }
282 }
283
addInotifyFd(std::string fd)284 bool MonitorFfs::addInotifyFd(std::string fd) {
285 std::lock_guard<std::mutex> lock(mLockFd);
286 int wfd;
287
288 wfd = inotify_add_watch(mInotifyFd, fd.c_str(), IN_ALL_EVENTS);
289 if (wfd == -1)
290 return false;
291 else
292 mWatchFd.push_back(wfd);
293
294 return true;
295 }
296
addEndPoint(std::string ep)297 void MonitorFfs::addEndPoint(std::string ep) {
298 std::lock_guard<std::mutex> lock(mLockFd);
299
300 mEndpointList.push_back(ep);
301 }
302
registerFunctionsAppliedCallback(void (* callback)(bool functionsApplied,void * payload),void * payload)303 void MonitorFfs::registerFunctionsAppliedCallback(void (*callback)(bool functionsApplied,
304 void *payload),
305 void *payload) {
306 mCallback = callback;
307 mPayload = payload;
308 }
309
310 } // namespace usb
311 } // namespace pixel
312 } // namespace google
313 } // namespace hardware
314 } // namespace android
315