• 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"
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