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 <common/utils/HwcTrace.h>
25#include <UeventObserver.h>
26
27namespace android {
28namespace intel {
29
30UeventObserver::UeventObserver()
31    : mUeventFd(-1),
32      mExitRDFd(-1),
33      mExitWDFd(-1),
34      mListeners()
35{
36}
37
38UeventObserver::~UeventObserver()
39{
40    deinitialize();
41}
42
43bool 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        ELOGTRACE("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        WLOGTRACE("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        ELOGTRACE("failed to make pipe");
88        deinitialize();
89        return false;
90    }
91    mExitRDFd = exitFds[0];
92    mExitWDFd = exitFds[1];
93
94    return true;
95}
96
97void 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
120void UeventObserver::start()
121{
122    if (mThread.get()) {
123        mThread->run("UeventObserver", PRIORITY_URGENT_DISPLAY);
124    }
125}
126
127
128void UeventObserver::registerListener(const char *event, UeventListenerFunc func, void *data)
129{
130    if (!event || !func) {
131        ELOGTRACE("invalid event string or listener to register");
132        return;
133    }
134
135    String8 key(event);
136    if (mListeners.indexOfKey(key) >= 0) {
137        ELOGTRACE("listener for uevent %s exists", event);
138        return;
139    }
140
141    UeventListener *listener = new UeventListener;
142    if (!listener) {
143        ELOGTRACE("failed to create Uevent Listener");
144        return;
145    }
146    listener->func = func;
147    listener->data = data;
148
149    mListeners.add(key, listener);
150}
151
152bool UeventObserver::threadLoop()
153{
154    if (mUeventFd == -1) {
155        ELOGTRACE("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        ILOGTRACE("exiting wait");
179        return false;
180    }
181    // always looping
182    return true;
183}
184
185void 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            DLOGTRACE("received Uevent: %s", msg);
200            listener = mListeners.valueFor(key);
201            if (listener) {
202                listener->func(listener->data);
203            } else {
204                ELOGTRACE("no listener for uevent %s", msg);
205            }
206        }
207        msg += strlen(msg) + 1;
208    }
209}
210
211} // namespace intel
212} // namespace android
213
214