1 /*
2 // Copyright (c) 2014 Intel Corporation 
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 #include <poll.h>
17 #include <sys/socket.h>
18 #include <sys/un.h>
19 #include <sys/queue.h>
20 #include <linux/netlink.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23 #include <DrmConfig.h>
24 #include <HwcTrace.h>
25 #include <UeventObserver.h>
26 
27 namespace android {
28 namespace intel {
29 
UeventObserver()30 UeventObserver::UeventObserver()
31     : mUeventFd(-1),
32       mExitRDFd(-1),
33       mExitWDFd(-1),
34       mListeners()
35 {
36 }
37 
~UeventObserver()38 UeventObserver::~UeventObserver()
39 {
40     deinitialize();
41 }
42 
initialize()43 bool UeventObserver::initialize()
44 {
45     mListeners.clear();
46 
47     if (mUeventFd != -1) {
48         return true;
49     }
50 
51     mThread = new UeventObserverThread(this);
52     if (!mThread.get()) {
53         ETRACE("failed to create uevent observer thread");
54         return false;
55     }
56 
57     // init uevent socket
58     struct sockaddr_nl addr;
59     // set the socket receive buffer to 64K
60     // NOTE: this is only called for once
61     int sz = 64 * 1024;
62 
63     memset(&addr, 0, sizeof(addr));
64     addr.nl_family = AF_NETLINK;
65     addr.nl_pid =  pthread_self() | getpid();
66     addr.nl_groups = 0xffffffff;
67 
68     mUeventFd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
69     if (mUeventFd < 0) {
70         DEINIT_AND_RETURN_FALSE("failed to create uevent socket");
71     }
72 
73     if (setsockopt(mUeventFd, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz))) {
74         WTRACE("setsockopt() failed");
75         //return false;
76     }
77 
78     if (bind(mUeventFd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
79         DEINIT_AND_RETURN_FALSE("failed to bind scoket");
80         return false;
81     }
82 
83     memset(mUeventMessage, 0, UEVENT_MSG_LEN);
84 
85     int exitFds[2];
86     if (pipe(exitFds) < 0) {
87         ETRACE("failed to make pipe");
88         deinitialize();
89         return false;
90     }
91     mExitRDFd = exitFds[0];
92     mExitWDFd = exitFds[1];
93 
94     return true;
95 }
96 
deinitialize()97 void UeventObserver::deinitialize()
98 {
99     if (mUeventFd != -1) {
100         if (mExitWDFd != -1) {
101             close(mExitWDFd);
102             mExitWDFd = -1;
103         }
104         close(mUeventFd);
105         mUeventFd = -1;
106     }
107 
108     if (mThread.get()) {
109         mThread->requestExitAndWait();
110         mThread = NULL;
111     }
112 
113     while (!mListeners.isEmpty()) {
114         UeventListener *listener = mListeners.valueAt(0);
115         mListeners.removeItemsAt(0);
116         delete listener;
117     }
118 }
119 
start()120 void UeventObserver::start()
121 {
122     if (mThread.get()) {
123         mThread->run("UeventObserver", PRIORITY_URGENT_DISPLAY);
124     }
125 }
126 
127 
registerListener(const char * event,UeventListenerFunc func,void * data)128 void UeventObserver::registerListener(const char *event, UeventListenerFunc func, void *data)
129 {
130     if (!event || !func) {
131         ETRACE("invalid event string or listener to register");
132         return;
133     }
134 
135     String8 key(event);
136     if (mListeners.indexOfKey(key) >= 0) {
137         ETRACE("listener for uevent %s exists", event);
138         return;
139     }
140 
141     UeventListener *listener = new UeventListener;
142     if (!listener) {
143         ETRACE("failed to create Uevent Listener");
144         return;
145     }
146     listener->func = func;
147     listener->data = data;
148 
149     mListeners.add(key, listener);
150 }
151 
threadLoop()152 bool UeventObserver::threadLoop()
153 {
154     if (mUeventFd == -1) {
155         ETRACE("invalid uEvent file descriptor");
156         return false;
157     }
158 
159     struct pollfd fds[2];
160     int nr;
161 
162     fds[0].fd = mUeventFd;
163     fds[0].events = POLLIN;
164     fds[0].revents = 0;
165     fds[1].fd = mExitRDFd;
166     fds[1].events = POLLIN;
167     fds[1].revents = 0;
168     nr = poll(fds, 2, -1);
169 
170     if (nr > 0 && fds[0].revents == POLLIN) {
171         int count = recv(mUeventFd, mUeventMessage, UEVENT_MSG_LEN - 2, 0);
172         if (count > 0) {
173             onUevent();
174         }
175     } else if (fds[1].revents) {
176         close(mExitRDFd);
177         mExitRDFd = -1;
178         ITRACE("exiting wait");
179         return false;
180     }
181     // always looping
182     return true;
183 }
184 
onUevent()185 void UeventObserver::onUevent()
186 {
187     char *msg = mUeventMessage;
188     const char *envelope = DrmConfig::getUeventEnvelope();
189     if (strncmp(msg, envelope, strlen(envelope)) != 0)
190         return;
191 
192     msg += strlen(msg) + 1;
193 
194     UeventListener *listener;
195     String8 key;
196     while (*msg) {
197         key = String8(msg);
198         if (mListeners.indexOfKey(key) >= 0) {
199             DTRACE("received Uevent: %s", msg);
200             listener = mListeners.valueFor(key);
201             if (listener) {
202                 listener->func(listener->data);
203             } else {
204                 ETRACE("no listener for uevent %s", msg);
205             }
206         }
207         msg += strlen(msg) + 1;
208     }
209 }
210 
211 } // namespace intel
212 } // namespace android
213 
214