16a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu/*
2cd727f537d5085eec7f1b8f9c1d33922d4de75d4Prodyut Hazarika// Copyright (c) 2014 Intel Corporation 
3cd727f537d5085eec7f1b8f9c1d33922d4de75d4Prodyut Hazarika//
4cd727f537d5085eec7f1b8f9c1d33922d4de75d4Prodyut Hazarika// Licensed under the Apache License, Version 2.0 (the "License");
5cd727f537d5085eec7f1b8f9c1d33922d4de75d4Prodyut Hazarika// you may not use this file except in compliance with the License.
6cd727f537d5085eec7f1b8f9c1d33922d4de75d4Prodyut Hazarika// You may obtain a copy of the License at
7cd727f537d5085eec7f1b8f9c1d33922d4de75d4Prodyut Hazarika//
8cd727f537d5085eec7f1b8f9c1d33922d4de75d4Prodyut Hazarika//      http://www.apache.org/licenses/LICENSE-2.0
9cd727f537d5085eec7f1b8f9c1d33922d4de75d4Prodyut Hazarika//
10cd727f537d5085eec7f1b8f9c1d33922d4de75d4Prodyut Hazarika// Unless required by applicable law or agreed to in writing, software
11cd727f537d5085eec7f1b8f9c1d33922d4de75d4Prodyut Hazarika// distributed under the License is distributed on an "AS IS" BASIS,
12cd727f537d5085eec7f1b8f9c1d33922d4de75d4Prodyut Hazarika// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cd727f537d5085eec7f1b8f9c1d33922d4de75d4Prodyut Hazarika// See the License for the specific language governing permissions and
14cd727f537d5085eec7f1b8f9c1d33922d4de75d4Prodyut Hazarika// limitations under the License.
15cd727f537d5085eec7f1b8f9c1d33922d4de75d4Prodyut Hazarika*/
166a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu#include <poll.h>
176a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu#include <sys/socket.h>
186a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu#include <sys/un.h>
196a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu#include <sys/queue.h>
206a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu#include <linux/netlink.h>
216a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu#include <sys/types.h>
226a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu#include <unistd.h>
23877d4ac27c6fde0b89b68e7c6e352edf879b3dedAndy Qiu#include <DrmConfig.h>
240594c42af26255fd8d3d7d39c0cb0e2da5b8841bThierry Strudel#include <common/utils/HwcTrace.h>
25466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu#include <UeventObserver.h>
266a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu
276a6081a46a83da606cf21548879b37695adc7e1fAndy Qiunamespace android {
286a6081a46a83da606cf21548879b37695adc7e1fAndy Qiunamespace intel {
296a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu
30466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin HuUeventObserver::UeventObserver()
31466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    : mUeventFd(-1),
32375f3cbb9faa54c3419bd835c41387ca1b0da0b2Tan Wei      mExitRDFd(-1),
33375f3cbb9faa54c3419bd835c41387ca1b0da0b2Tan Wei      mExitWDFd(-1),
34466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu      mListeners()
356a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu{
36eb726af21649d79ed720bdf329e0849270995c45Andy Qiu}
37eb726af21649d79ed720bdf329e0849270995c45Andy Qiu
38466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin HuUeventObserver::~UeventObserver()
39eb726af21649d79ed720bdf329e0849270995c45Andy Qiu{
40466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    deinitialize();
41eb726af21649d79ed720bdf329e0849270995c45Andy Qiu}
42eb726af21649d79ed720bdf329e0849270995c45Andy Qiu
43466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hubool UeventObserver::initialize()
44eb726af21649d79ed720bdf329e0849270995c45Andy Qiu{
45466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    mListeners.clear();
46466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu
47eb726af21649d79ed720bdf329e0849270995c45Andy Qiu    if (mUeventFd != -1) {
48eb726af21649d79ed720bdf329e0849270995c45Andy Qiu        return true;
49eb726af21649d79ed720bdf329e0849270995c45Andy Qiu    }
506a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu
51466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    mThread = new UeventObserverThread(this);
52466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    if (!mThread.get()) {
534157ee3f6fb20e0a249b9eedc06f3b16785ba31bIliyan Malchev        ELOGTRACE("failed to create uevent observer thread");
54466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu        return false;
55466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    }
56466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu
576a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu    // init uevent socket
586a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu    struct sockaddr_nl addr;
59e6ecdadd57e79c2218b3e6ae407f12599f33bd22Jackie Li    // set the socket receive buffer to 64K
60e6ecdadd57e79c2218b3e6ae407f12599f33bd22Jackie Li    // NOTE: this is only called for once
61e6ecdadd57e79c2218b3e6ae407f12599f33bd22Jackie Li    int sz = 64 * 1024;
626a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu
636a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu    memset(&addr, 0, sizeof(addr));
646a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu    addr.nl_family = AF_NETLINK;
656a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu    addr.nl_pid =  pthread_self() | getpid();
666a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu    addr.nl_groups = 0xffffffff;
676a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu
686a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu    mUeventFd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
69eb726af21649d79ed720bdf329e0849270995c45Andy Qiu    if (mUeventFd < 0) {
70466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu        DEINIT_AND_RETURN_FALSE("failed to create uevent socket");
716a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu    }
726a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu
73466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    if (setsockopt(mUeventFd, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz))) {
744157ee3f6fb20e0a249b9eedc06f3b16785ba31bIliyan Malchev        WLOGTRACE("setsockopt() failed");
75466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu        //return false;
76466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    }
776a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu
78eb726af21649d79ed720bdf329e0849270995c45Andy Qiu    if (bind(mUeventFd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
79466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu        DEINIT_AND_RETURN_FALSE("failed to bind scoket");
80eb726af21649d79ed720bdf329e0849270995c45Andy Qiu        return false;
816a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu    }
826a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu
836a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu    memset(mUeventMessage, 0, UEVENT_MSG_LEN);
84375f3cbb9faa54c3419bd835c41387ca1b0da0b2Tan Wei
85375f3cbb9faa54c3419bd835c41387ca1b0da0b2Tan Wei    int exitFds[2];
86375f3cbb9faa54c3419bd835c41387ca1b0da0b2Tan Wei    if (pipe(exitFds) < 0) {
874157ee3f6fb20e0a249b9eedc06f3b16785ba31bIliyan Malchev        ELOGTRACE("failed to make pipe");
88375f3cbb9faa54c3419bd835c41387ca1b0da0b2Tan Wei        deinitialize();
89375f3cbb9faa54c3419bd835c41387ca1b0da0b2Tan Wei        return false;
90375f3cbb9faa54c3419bd835c41387ca1b0da0b2Tan Wei    }
91375f3cbb9faa54c3419bd835c41387ca1b0da0b2Tan Wei    mExitRDFd = exitFds[0];
92375f3cbb9faa54c3419bd835c41387ca1b0da0b2Tan Wei    mExitWDFd = exitFds[1];
93375f3cbb9faa54c3419bd835c41387ca1b0da0b2Tan Wei
94eb726af21649d79ed720bdf329e0849270995c45Andy Qiu    return true;
956a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu}
966a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu
97466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Huvoid UeventObserver::deinitialize()
986a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu{
99eb726af21649d79ed720bdf329e0849270995c45Andy Qiu    if (mUeventFd != -1) {
100375f3cbb9faa54c3419bd835c41387ca1b0da0b2Tan Wei        if (mExitWDFd != -1) {
101375f3cbb9faa54c3419bd835c41387ca1b0da0b2Tan Wei            close(mExitWDFd);
102375f3cbb9faa54c3419bd835c41387ca1b0da0b2Tan Wei            mExitWDFd = -1;
103375f3cbb9faa54c3419bd835c41387ca1b0da0b2Tan Wei        }
104eb726af21649d79ed720bdf329e0849270995c45Andy Qiu        close(mUeventFd);
105eb726af21649d79ed720bdf329e0849270995c45Andy Qiu        mUeventFd = -1;
106eb726af21649d79ed720bdf329e0849270995c45Andy Qiu    }
107466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu
108466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    if (mThread.get()) {
109466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu        mThread->requestExitAndWait();
110466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu        mThread = NULL;
111466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    }
112466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu
113466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    while (!mListeners.isEmpty()) {
114466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu        UeventListener *listener = mListeners.valueAt(0);
115466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu        mListeners.removeItemsAt(0);
116466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu        delete listener;
117466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    }
118466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu}
119466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu
120466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Huvoid UeventObserver::start()
121466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu{
122466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    if (mThread.get()) {
123466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu        mThread->run("UeventObserver", PRIORITY_URGENT_DISPLAY);
124466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    }
125466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu}
126466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu
127466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu
128466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Huvoid UeventObserver::registerListener(const char *event, UeventListenerFunc func, void *data)
129466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu{
130466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    if (!event || !func) {
1314157ee3f6fb20e0a249b9eedc06f3b16785ba31bIliyan Malchev        ELOGTRACE("invalid event string or listener to register");
132466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu        return;
133466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    }
134466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu
135466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    String8 key(event);
136466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    if (mListeners.indexOfKey(key) >= 0) {
1374157ee3f6fb20e0a249b9eedc06f3b16785ba31bIliyan Malchev        ELOGTRACE("listener for uevent %s exists", event);
138466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu        return;
139466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    }
140466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu
141466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    UeventListener *listener = new UeventListener;
142466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    if (!listener) {
1434157ee3f6fb20e0a249b9eedc06f3b16785ba31bIliyan Malchev        ELOGTRACE("failed to create Uevent Listener");
144466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu        return;
145466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    }
146466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    listener->func = func;
147466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    listener->data = data;
148466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu
149466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    mListeners.add(key, listener);
1506a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu}
1516a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu
152466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hubool UeventObserver::threadLoop()
1536a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu{
154eb726af21649d79ed720bdf329e0849270995c45Andy Qiu    if (mUeventFd == -1) {
1554157ee3f6fb20e0a249b9eedc06f3b16785ba31bIliyan Malchev        ELOGTRACE("invalid uEvent file descriptor");
156eb726af21649d79ed720bdf329e0849270995c45Andy Qiu        return false;
157eb726af21649d79ed720bdf329e0849270995c45Andy Qiu    }
158eb726af21649d79ed720bdf329e0849270995c45Andy Qiu
159375f3cbb9faa54c3419bd835c41387ca1b0da0b2Tan Wei    struct pollfd fds[2];
1606a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu    int nr;
1616a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu
162375f3cbb9faa54c3419bd835c41387ca1b0da0b2Tan Wei    fds[0].fd = mUeventFd;
163375f3cbb9faa54c3419bd835c41387ca1b0da0b2Tan Wei    fds[0].events = POLLIN;
164375f3cbb9faa54c3419bd835c41387ca1b0da0b2Tan Wei    fds[0].revents = 0;
165375f3cbb9faa54c3419bd835c41387ca1b0da0b2Tan Wei    fds[1].fd = mExitRDFd;
166375f3cbb9faa54c3419bd835c41387ca1b0da0b2Tan Wei    fds[1].events = POLLIN;
167375f3cbb9faa54c3419bd835c41387ca1b0da0b2Tan Wei    fds[1].revents = 0;
168375f3cbb9faa54c3419bd835c41387ca1b0da0b2Tan Wei    nr = poll(fds, 2, -1);
1696a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu
170375f3cbb9faa54c3419bd835c41387ca1b0da0b2Tan Wei    if (nr > 0 && fds[0].revents == POLLIN) {
1716a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu        int count = recv(mUeventFd, mUeventMessage, UEVENT_MSG_LEN - 2, 0);
172466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu        if (count > 0) {
173466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu            onUevent();
174466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu        }
175123770a44b11572ea9c0fcbb236eabfc2892bdf8Tan Wei    } else if (fds[1].revents) {
176123770a44b11572ea9c0fcbb236eabfc2892bdf8Tan Wei        close(mExitRDFd);
177123770a44b11572ea9c0fcbb236eabfc2892bdf8Tan Wei        mExitRDFd = -1;
1784157ee3f6fb20e0a249b9eedc06f3b16785ba31bIliyan Malchev        ILOGTRACE("exiting wait");
179123770a44b11572ea9c0fcbb236eabfc2892bdf8Tan Wei        return false;
1806a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu    }
181466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    // always looping
182466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    return true;
1836a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu}
1846a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu
185466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Huvoid UeventObserver::onUevent()
1866a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu{
187466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    char *msg = mUeventMessage;
188466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    const char *envelope = DrmConfig::getUeventEnvelope();
189466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    if (strncmp(msg, envelope, strlen(envelope)) != 0)
190466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu        return;
1916a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu
1926a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu    msg += strlen(msg) + 1;
1936a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu
194466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    UeventListener *listener;
195466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    String8 key;
196466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    while (*msg) {
197466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu        key = String8(msg);
198466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu        if (mListeners.indexOfKey(key) >= 0) {
1994157ee3f6fb20e0a249b9eedc06f3b16785ba31bIliyan Malchev            DLOGTRACE("received Uevent: %s", msg);
200466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu            listener = mListeners.valueFor(key);
201466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu            if (listener) {
202466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu                listener->func(listener->data);
203466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu            } else {
2044157ee3f6fb20e0a249b9eedc06f3b16785ba31bIliyan Malchev                ELOGTRACE("no listener for uevent %s", msg);
205466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu            }
2066a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu        }
2076a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu        msg += strlen(msg) + 1;
208466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu    }
2096a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu}
2106a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu
2116a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu} // namespace intel
2126a6081a46a83da606cf21548879b37695adc7e1fAndy Qiu} // namespace android
213466748a6f67ce4d1ad8baa944e68a88cf3c86d26Austin Hu
214