summaryrefslogtreecommitdiff
path: root/hwc2/common/observers/UeventObserver.cpp (plain)
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
30namespace android {
31namespace amlogic {
32
33UeventObserver::UeventObserver()
34 : mUeventFd(-1),
35 mExitRDFd(-1),
36 mExitWDFd(-1),
37 mListeners()
38{
39}
40
41UeventObserver::~UeventObserver()
42{
43 deinitialize();
44}
45
46bool 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
100void 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
123void UeventObserver::start()
124{
125 if (mThread.get()) {
126 mThread->run("UeventObserver", PRIORITY_URGENT_DISPLAY);
127 }
128}
129
130void 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
154bool 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
187void 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