hal/gonk/UeventPoller.cpp

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* Copyright 2012 Mozilla Foundation and Mozilla contributors
     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  */
    17 #include <errno.h>
    18 #include <fcntl.h>
    19 #include <pthread.h>
    20 #include <signal.h>
    21 #include <string.h>
    22 #include <strings.h>
    23 #include <unistd.h>
    25 #include <arpa/inet.h>
    26 #include <linux/types.h>
    27 #include <linux/netlink.h>
    28 #include <netinet/in.h>
    29 #include <sys/socket.h>
    31 #include "nsDebug.h"
    32 #include "base/message_loop.h"
    33 #include "mozilla/FileUtils.h"
    34 #include "nsAutoPtr.h"
    35 #include "nsThreadUtils.h"
    36 #include "nsXULAppAPI.h"
    38 #include "UeventPoller.h"
    40 namespace mozilla {
    41 namespace hal_impl {
    43 static void ShutdownUevent();
    45 class NetlinkPoller : public MessageLoopForIO::Watcher
    46 {
    47 public:
    48   NetlinkPoller() : mSocket(-1),
    49                     mIOLoop(MessageLoopForIO::current())
    50   {
    51   }
    53   virtual ~NetlinkPoller() {}
    55   bool OpenSocket();
    57   virtual void OnFileCanReadWithoutBlocking(int fd);
    59   // no writing to the netlink socket
    60   virtual void OnFileCanWriteWithoutBlocking(int fd)
    61   {
    62     MOZ_CRASH("Must not write to netlink socket");
    63   }
    65   MessageLoopForIO *GetIOLoop () const { return mIOLoop; }
    66   void RegisterObserver(IUeventObserver *aObserver)
    67   {
    68     mUeventObserverList.AddObserver(aObserver);
    69   }
    71   void UnregisterObserver(IUeventObserver *aObserver)
    72   {
    73     mUeventObserverList.RemoveObserver(aObserver);
    74     if (mUeventObserverList.Length() == 0)
    75       ShutdownUevent();  // this will destroy self
    76   }
    78 private:
    79   ScopedClose mSocket;
    80   MessageLoopForIO* mIOLoop;
    81   MessageLoopForIO::FileDescriptorWatcher mReadWatcher;
    83   const static int kBuffsize = 64 * 1024;
    84   uint8_t mBuffer [kBuffsize];
    86   typedef ObserverList<NetlinkEvent> UeventObserverList;
    87   UeventObserverList mUeventObserverList;
    88 };
    90 bool
    91 NetlinkPoller::OpenSocket()
    92 {
    93   mSocket.rwget() = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
    94   if (mSocket.get() < 0)
    95     return false;
    97   int sz = kBuffsize;
    99   if (setsockopt(mSocket.get(), SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0)
   100     return false;
   102   // add FD_CLOEXEC flag
   103   int flags = fcntl(mSocket.get(), F_GETFD);
   104   if (flags == -1) {
   105       return false;
   106   }
   107   flags |= FD_CLOEXEC;
   108   if (fcntl(mSocket.get(), F_SETFD, flags) == -1)
   109     return false;
   111   // set non-blocking
   112   if (fcntl(mSocket.get(), F_SETFL, O_NONBLOCK) == -1)
   113     return false;
   115   struct sockaddr_nl saddr;
   116   bzero(&saddr, sizeof(saddr));
   117   saddr.nl_family = AF_NETLINK;
   118   saddr.nl_groups = 1;
   119   saddr.nl_pid = gettid();
   121   do {
   122     if (bind(mSocket.get(), (struct sockaddr *)&saddr, sizeof(saddr)) == 0) {
   123       break;
   124     }
   126     if (errno != EADDRINUSE) {
   127       return false;
   128     }
   130     if (saddr.nl_pid == 0) {
   131       return false;
   132     }
   134     // Once there was any other place in the same process assigning saddr.nl_pid by
   135     // gettid(), we can detect it and print warning message.
   136     printf_stderr("The netlink socket address saddr.nl_pid=%u is in use. Let the kernel re-assign.\n", saddr.nl_pid);
   137     saddr.nl_pid = 0;
   138   } while (true);
   140   if (!mIOLoop->WatchFileDescriptor(mSocket.get(),
   141                                     true,
   142                                     MessageLoopForIO::WATCH_READ,
   143                                     &mReadWatcher,
   144                                     this)) {
   145       return false;
   146   }
   148   return true;
   149 }
   151 static nsAutoPtr<NetlinkPoller> sPoller;
   153 class UeventInitTask : public Task
   154 {
   155   virtual void Run()
   156   {
   157     if (!sPoller) {
   158       return;
   159     }
   160     if (sPoller->OpenSocket()) {
   161       return;
   162     }
   163     sPoller->GetIOLoop()->PostDelayedTask(FROM_HERE, new UeventInitTask(), 1000);
   164   }
   165 };
   167 void
   168 NetlinkPoller::OnFileCanReadWithoutBlocking(int fd)
   169 {
   170   MOZ_ASSERT(fd == mSocket.get());
   171   while (true) {
   172     int ret = read(fd, mBuffer, kBuffsize);
   173     if (ret == -1) {
   174       if (errno == EAGAIN || errno == EWOULDBLOCK) {
   175         return;
   176       }
   177       if (errno == EINTR) {
   178         continue;
   179       }
   180     }
   181     if (ret <= 0) {
   182       // fatal error on netlink socket which should not happen
   183       _exit(1);
   184     }
   185     NetlinkEvent netlinkEvent;
   186     netlinkEvent.decode(reinterpret_cast<char*>(mBuffer), ret);
   187     mUeventObserverList.Broadcast(netlinkEvent);
   188   }
   189 }
   191 static void
   192 InitializeUevent()
   193 {
   194   MOZ_ASSERT(!sPoller);
   195   sPoller = new NetlinkPoller();
   196   sPoller->GetIOLoop()->PostTask(FROM_HERE, new UeventInitTask());
   198 }
   200 static void
   201 ShutdownUevent()
   202 {
   203   sPoller = nullptr;
   204 }
   206 void
   207 RegisterUeventListener(IUeventObserver *aObserver)
   208 {
   209   MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
   211   if (!sPoller)
   212     InitializeUevent();
   213   sPoller->RegisterObserver(aObserver);
   214 }
   216 void
   217 UnregisterUeventListener(IUeventObserver *aObserver)
   218 {
   219   MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
   221   sPoller->UnregisterObserver(aObserver);
   222 }
   224 } // hal_impl
   225 } // mozilla

mercurial