• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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