Home | History | Annotate | Download | only in observers
      1 /*
      2 // Copyright(c)2014 IntelCorporation
      3 //
      4 // LicensedundertheApacheLicense,Version2.0(the"License");
      5 // youmaynotusethisfileexceptincompliancewiththeLicense.
      6 // YoumayobtainacopyoftheLicenseat
      7 //
      8 // http://www.apache.org/licenses/LICENSE-2.0
      9 //
     10 // Unlessrequiredbyapplicablelaworagreedtoinwriting,software
     11 // distributedundertheLicenseisdistributedonan"ASIS"BASIS,
     12 // WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
     13 // SeetheLicenseforthespecificlanguagegoverningpermissionsand
     14 // limitationsundertheLicense.
     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 
     27 namespace android {
     28 namespace intel {
     29 
     30 UeventObserver::UeventObserver()
     31     : mUeventFd(-1),
     32       mExitRDFd(-1),
     33       mExitWDFd(-1),
     34       mListeners()
     35 {
     36 }
     37 
     38 UeventObserver::~UeventObserver()
     39 {
     40     deinitialize();
     41 }
     42 
     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         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 
     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 
    120 void UeventObserver::start()
    121 {
    122     if (mThread.get()) {
    123         mThread->run("UeventObserver", PRIORITY_URGENT_DISPLAY);
    124     }
    125 }
    126 
    127 
    128 void 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 
    152 bool 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 
    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             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