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