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