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