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