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