1 /*
2 * Copyright (C) 2020 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 "libusbconfigfs"
18
19 #include "include/UsbGadgetCommon.h"
20
21 namespace android {
22 namespace hardware {
23 namespace usb {
24 namespace gadget {
25
26 static volatile bool gadgetPullup;
27
MonitorFfs(const char * const gadget)28 MonitorFfs::MonitorFfs(const char* const gadget)
29 : mWatchFd(),
30 mEndpointList(),
31 mLock(),
32 mCv(),
33 mLockFd(),
34 mCurrentUsbFunctionsApplied(false),
35 mMonitor(),
36 mCallback(NULL),
37 mPayload(NULL),
38 mGadgetName(gadget),
39 mMonitorRunning(false) {
40 unique_fd eventFd(eventfd(0, 0));
41 if (eventFd == -1) {
42 ALOGE("mEventFd failed to create %d", errno);
43 abort();
44 }
45
46 unique_fd epollFd(epoll_create(2));
47 if (epollFd == -1) {
48 ALOGE("mEpollFd failed to create %d", errno);
49 abort();
50 }
51
52 unique_fd inotifyFd(inotify_init());
53 if (inotifyFd < 0) {
54 ALOGE("inotify init failed");
55 abort();
56 }
57
58 if (addEpollFd(epollFd, inotifyFd) == -1) abort();
59
60 if (addEpollFd(epollFd, eventFd) == -1) abort();
61
62 mEpollFd = std::move(epollFd);
63 mInotifyFd = std::move(inotifyFd);
64 mEventFd = std::move(eventFd);
65 gadgetPullup = false;
66 }
67
displayInotifyEvent(struct inotify_event * i)68 static void displayInotifyEvent(struct inotify_event* i) {
69 ALOGE(" wd =%2d; ", i->wd);
70 if (i->cookie > 0) ALOGE("cookie =%4d; ", i->cookie);
71
72 ALOGE("mask = ");
73 if (i->mask & IN_ACCESS) ALOGE("IN_ACCESS ");
74 if (i->mask & IN_ATTRIB) ALOGE("IN_ATTRIB ");
75 if (i->mask & IN_CLOSE_NOWRITE) ALOGE("IN_CLOSE_NOWRITE ");
76 if (i->mask & IN_CLOSE_WRITE) ALOGE("IN_CLOSE_WRITE ");
77 if (i->mask & IN_CREATE) ALOGE("IN_CREATE ");
78 if (i->mask & IN_DELETE) ALOGE("IN_DELETE ");
79 if (i->mask & IN_DELETE_SELF) ALOGE("IN_DELETE_SELF ");
80 if (i->mask & IN_IGNORED) ALOGE("IN_IGNORED ");
81 if (i->mask & IN_ISDIR) ALOGE("IN_ISDIR ");
82 if (i->mask & IN_MODIFY) ALOGE("IN_MODIFY ");
83 if (i->mask & IN_MOVE_SELF) ALOGE("IN_MOVE_SELF ");
84 if (i->mask & IN_MOVED_FROM) ALOGE("IN_MOVED_FROM ");
85 if (i->mask & IN_MOVED_TO) ALOGE("IN_MOVED_TO ");
86 if (i->mask & IN_OPEN) ALOGE("IN_OPEN ");
87 if (i->mask & IN_Q_OVERFLOW) ALOGE("IN_Q_OVERFLOW ");
88 if (i->mask & IN_UNMOUNT) ALOGE("IN_UNMOUNT ");
89 ALOGE("\n");
90
91 if (i->len > 0) ALOGE(" name = %s\n", i->name);
92 }
93
startMonitorFd(void * param)94 void* MonitorFfs::startMonitorFd(void* param) {
95 MonitorFfs* monitorFfs = (MonitorFfs*)param;
96 char buf[kBufferSize];
97 bool writeUdc = true, stopMonitor = false;
98 struct epoll_event events[kEpollEvents];
99 steady_clock::time_point disconnect;
100
101 bool descriptorWritten = true;
102 for (int i = 0; i < static_cast<int>(monitorFfs->mEndpointList.size()); i++) {
103 if (access(monitorFfs->mEndpointList.at(i).c_str(), R_OK)) {
104 descriptorWritten = false;
105 break;
106 }
107 }
108
109 // notify here if the endpoints are already present.
110 if (descriptorWritten) {
111 usleep(kPullUpDelay);
112 if (!!WriteStringToFile(monitorFfs->mGadgetName, PULLUP_PATH)) {
113 lock_guard<mutex> lock(monitorFfs->mLock);
114 monitorFfs->mCurrentUsbFunctionsApplied = true;
115 monitorFfs->mCallback(monitorFfs->mCurrentUsbFunctionsApplied, monitorFfs->mPayload);
116 gadgetPullup = true;
117 writeUdc = false;
118 ALOGI("GADGET pulled up");
119 monitorFfs->mCv.notify_all();
120 }
121 }
122
123 while (!stopMonitor) {
124 int nrEvents = epoll_wait(monitorFfs->mEpollFd, events, kEpollEvents, -1);
125
126 if (nrEvents <= 0) {
127 ALOGE("epoll wait did not return descriptor number");
128 continue;
129 }
130
131 for (int i = 0; i < nrEvents; i++) {
132 ALOGI("event=%u on fd=%d\n", events[i].events, events[i].data.fd);
133
134 if (events[i].data.fd == monitorFfs->mInotifyFd) {
135 // Process all of the events in buffer returned by read().
136 int numRead = read(monitorFfs->mInotifyFd, buf, kBufferSize);
137 for (char* p = buf; p < buf + numRead;) {
138 struct inotify_event* event = (struct inotify_event*)p;
139 if (kDebug) displayInotifyEvent(event);
140
141 p += sizeof(struct inotify_event) + event->len;
142
143 bool descriptorPresent = true;
144 for (int j = 0; j < static_cast<int>(monitorFfs->mEndpointList.size()); j++) {
145 if (access(monitorFfs->mEndpointList.at(j).c_str(), R_OK)) {
146 if (kDebug) ALOGI("%s absent", monitorFfs->mEndpointList.at(j).c_str());
147 descriptorPresent = false;
148 break;
149 }
150 }
151
152 if (!descriptorPresent && !writeUdc) {
153 if (kDebug) ALOGI("endpoints not up");
154 writeUdc = true;
155 disconnect = std::chrono::steady_clock::now();
156 } else if (descriptorPresent && writeUdc) {
157 steady_clock::time_point temp = steady_clock::now();
158
159 if (std::chrono::duration_cast<microseconds>(temp - disconnect).count() <
160 kPullUpDelay)
161 usleep(kPullUpDelay);
162
163 if (!!WriteStringToFile(monitorFfs->mGadgetName, PULLUP_PATH)) {
164 lock_guard<mutex> lock(monitorFfs->mLock);
165 monitorFfs->mCurrentUsbFunctionsApplied = true;
166 monitorFfs->mCallback(monitorFfs->mCurrentUsbFunctionsApplied,
167 monitorFfs->mPayload);
168 ALOGI("GADGET pulled up");
169 writeUdc = false;
170 gadgetPullup = true;
171 // notify the main thread to signal userspace.
172 monitorFfs->mCv.notify_all();
173 }
174 }
175 }
176 } else {
177 uint64_t flag;
178 read(monitorFfs->mEventFd, &flag, sizeof(flag));
179 if (flag == 100) {
180 stopMonitor = true;
181 break;
182 }
183 }
184 }
185 }
186 return NULL;
187 }
188
reset()189 void MonitorFfs::reset() {
190 lock_guard<mutex> lock(mLockFd);
191 uint64_t flag = 100;
192 unsigned long ret;
193
194 if (mMonitorRunning) {
195 // Stop the monitor thread by writing into signal fd.
196 ret = TEMP_FAILURE_RETRY(write(mEventFd, &flag, sizeof(flag)));
197 if (ret < 0) ALOGE("Error writing eventfd errno=%d", errno);
198
199 ALOGI("mMonitor signalled to exit");
200 mMonitor->join();
201 ALOGI("mMonitor destroyed");
202 mMonitorRunning = false;
203 }
204
205 for (std::vector<int>::size_type i = 0; i != mWatchFd.size(); i++)
206 inotify_rm_watch(mInotifyFd, mWatchFd[i]);
207
208 mEndpointList.clear();
209 gadgetPullup = false;
210 mCallback = NULL;
211 mPayload = NULL;
212 }
213
startMonitor()214 bool MonitorFfs::startMonitor() {
215 mMonitor = unique_ptr<thread>(new thread(this->startMonitorFd, this));
216 mMonitorRunning = true;
217 return true;
218 }
219
isMonitorRunning()220 bool MonitorFfs::isMonitorRunning() {
221 return mMonitorRunning;
222 }
223
waitForPullUp(int timeout_ms)224 bool MonitorFfs::waitForPullUp(int timeout_ms) {
225 std::unique_lock<std::mutex> lk(mLock);
226
227 if (gadgetPullup) return true;
228
229 if (mCv.wait_for(lk, timeout_ms * 1ms, [] { return gadgetPullup; })) {
230 ALOGI("monitorFfs signalled true");
231 return true;
232 } else {
233 ALOGI("monitorFfs signalled error");
234 // continue monitoring as the descriptors might be written at a later
235 // point.
236 return false;
237 }
238 }
239
addInotifyFd(string fd)240 bool MonitorFfs::addInotifyFd(string fd) {
241 lock_guard<mutex> lock(mLockFd);
242 int wfd;
243
244 wfd = inotify_add_watch(mInotifyFd, fd.c_str(), IN_ALL_EVENTS);
245 if (wfd == -1)
246 return false;
247 else
248 mWatchFd.push_back(wfd);
249
250 return true;
251 }
252
addEndPoint(string ep)253 void MonitorFfs::addEndPoint(string ep) {
254 lock_guard<mutex> lock(mLockFd);
255
256 mEndpointList.push_back(ep);
257 }
258
registerFunctionsAppliedCallback(void (* callback)(bool functionsApplied,void * payload),void * payload)259 void MonitorFfs::registerFunctionsAppliedCallback(void (*callback)(bool functionsApplied,
260 void* payload),
261 void* payload) {
262 mCallback = callback;
263 mPayload = payload;
264 }
265
266 } // namespace gadget
267 } // namespace usb
268 } // namespace hardware
269 } // namespace android
270