1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/hal/gonk/UeventPoller.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,226 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* Copyright 2012 Mozilla Foundation and Mozilla contributors 1.6 + * 1.7 + * Licensed under the Apache License, Version 2.0 (the "License"); 1.8 + * you may not use this file except in compliance with the License. 1.9 + * You may obtain a copy of the License at 1.10 + * 1.11 + * http://www.apache.org/licenses/LICENSE-2.0 1.12 + * 1.13 + * Unless required by applicable law or agreed to in writing, software 1.14 + * distributed under the License is distributed on an "AS IS" BASIS, 1.15 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.16 + * See the License for the specific language governing permissions and 1.17 + * limitations under the License. 1.18 + */ 1.19 + 1.20 +#include <errno.h> 1.21 +#include <fcntl.h> 1.22 +#include <pthread.h> 1.23 +#include <signal.h> 1.24 +#include <string.h> 1.25 +#include <strings.h> 1.26 +#include <unistd.h> 1.27 + 1.28 +#include <arpa/inet.h> 1.29 +#include <linux/types.h> 1.30 +#include <linux/netlink.h> 1.31 +#include <netinet/in.h> 1.32 +#include <sys/socket.h> 1.33 + 1.34 +#include "nsDebug.h" 1.35 +#include "base/message_loop.h" 1.36 +#include "mozilla/FileUtils.h" 1.37 +#include "nsAutoPtr.h" 1.38 +#include "nsThreadUtils.h" 1.39 +#include "nsXULAppAPI.h" 1.40 + 1.41 +#include "UeventPoller.h" 1.42 + 1.43 +namespace mozilla { 1.44 +namespace hal_impl { 1.45 + 1.46 +static void ShutdownUevent(); 1.47 + 1.48 +class NetlinkPoller : public MessageLoopForIO::Watcher 1.49 +{ 1.50 +public: 1.51 + NetlinkPoller() : mSocket(-1), 1.52 + mIOLoop(MessageLoopForIO::current()) 1.53 + { 1.54 + } 1.55 + 1.56 + virtual ~NetlinkPoller() {} 1.57 + 1.58 + bool OpenSocket(); 1.59 + 1.60 + virtual void OnFileCanReadWithoutBlocking(int fd); 1.61 + 1.62 + // no writing to the netlink socket 1.63 + virtual void OnFileCanWriteWithoutBlocking(int fd) 1.64 + { 1.65 + MOZ_CRASH("Must not write to netlink socket"); 1.66 + } 1.67 + 1.68 + MessageLoopForIO *GetIOLoop () const { return mIOLoop; } 1.69 + void RegisterObserver(IUeventObserver *aObserver) 1.70 + { 1.71 + mUeventObserverList.AddObserver(aObserver); 1.72 + } 1.73 + 1.74 + void UnregisterObserver(IUeventObserver *aObserver) 1.75 + { 1.76 + mUeventObserverList.RemoveObserver(aObserver); 1.77 + if (mUeventObserverList.Length() == 0) 1.78 + ShutdownUevent(); // this will destroy self 1.79 + } 1.80 + 1.81 +private: 1.82 + ScopedClose mSocket; 1.83 + MessageLoopForIO* mIOLoop; 1.84 + MessageLoopForIO::FileDescriptorWatcher mReadWatcher; 1.85 + 1.86 + const static int kBuffsize = 64 * 1024; 1.87 + uint8_t mBuffer [kBuffsize]; 1.88 + 1.89 + typedef ObserverList<NetlinkEvent> UeventObserverList; 1.90 + UeventObserverList mUeventObserverList; 1.91 +}; 1.92 + 1.93 +bool 1.94 +NetlinkPoller::OpenSocket() 1.95 +{ 1.96 + mSocket.rwget() = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); 1.97 + if (mSocket.get() < 0) 1.98 + return false; 1.99 + 1.100 + int sz = kBuffsize; 1.101 + 1.102 + if (setsockopt(mSocket.get(), SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) 1.103 + return false; 1.104 + 1.105 + // add FD_CLOEXEC flag 1.106 + int flags = fcntl(mSocket.get(), F_GETFD); 1.107 + if (flags == -1) { 1.108 + return false; 1.109 + } 1.110 + flags |= FD_CLOEXEC; 1.111 + if (fcntl(mSocket.get(), F_SETFD, flags) == -1) 1.112 + return false; 1.113 + 1.114 + // set non-blocking 1.115 + if (fcntl(mSocket.get(), F_SETFL, O_NONBLOCK) == -1) 1.116 + return false; 1.117 + 1.118 + struct sockaddr_nl saddr; 1.119 + bzero(&saddr, sizeof(saddr)); 1.120 + saddr.nl_family = AF_NETLINK; 1.121 + saddr.nl_groups = 1; 1.122 + saddr.nl_pid = gettid(); 1.123 + 1.124 + do { 1.125 + if (bind(mSocket.get(), (struct sockaddr *)&saddr, sizeof(saddr)) == 0) { 1.126 + break; 1.127 + } 1.128 + 1.129 + if (errno != EADDRINUSE) { 1.130 + return false; 1.131 + } 1.132 + 1.133 + if (saddr.nl_pid == 0) { 1.134 + return false; 1.135 + } 1.136 + 1.137 + // Once there was any other place in the same process assigning saddr.nl_pid by 1.138 + // gettid(), we can detect it and print warning message. 1.139 + printf_stderr("The netlink socket address saddr.nl_pid=%u is in use. Let the kernel re-assign.\n", saddr.nl_pid); 1.140 + saddr.nl_pid = 0; 1.141 + } while (true); 1.142 + 1.143 + if (!mIOLoop->WatchFileDescriptor(mSocket.get(), 1.144 + true, 1.145 + MessageLoopForIO::WATCH_READ, 1.146 + &mReadWatcher, 1.147 + this)) { 1.148 + return false; 1.149 + } 1.150 + 1.151 + return true; 1.152 +} 1.153 + 1.154 +static nsAutoPtr<NetlinkPoller> sPoller; 1.155 + 1.156 +class UeventInitTask : public Task 1.157 +{ 1.158 + virtual void Run() 1.159 + { 1.160 + if (!sPoller) { 1.161 + return; 1.162 + } 1.163 + if (sPoller->OpenSocket()) { 1.164 + return; 1.165 + } 1.166 + sPoller->GetIOLoop()->PostDelayedTask(FROM_HERE, new UeventInitTask(), 1000); 1.167 + } 1.168 +}; 1.169 + 1.170 +void 1.171 +NetlinkPoller::OnFileCanReadWithoutBlocking(int fd) 1.172 +{ 1.173 + MOZ_ASSERT(fd == mSocket.get()); 1.174 + while (true) { 1.175 + int ret = read(fd, mBuffer, kBuffsize); 1.176 + if (ret == -1) { 1.177 + if (errno == EAGAIN || errno == EWOULDBLOCK) { 1.178 + return; 1.179 + } 1.180 + if (errno == EINTR) { 1.181 + continue; 1.182 + } 1.183 + } 1.184 + if (ret <= 0) { 1.185 + // fatal error on netlink socket which should not happen 1.186 + _exit(1); 1.187 + } 1.188 + NetlinkEvent netlinkEvent; 1.189 + netlinkEvent.decode(reinterpret_cast<char*>(mBuffer), ret); 1.190 + mUeventObserverList.Broadcast(netlinkEvent); 1.191 + } 1.192 +} 1.193 + 1.194 +static void 1.195 +InitializeUevent() 1.196 +{ 1.197 + MOZ_ASSERT(!sPoller); 1.198 + sPoller = new NetlinkPoller(); 1.199 + sPoller->GetIOLoop()->PostTask(FROM_HERE, new UeventInitTask()); 1.200 + 1.201 +} 1.202 + 1.203 +static void 1.204 +ShutdownUevent() 1.205 +{ 1.206 + sPoller = nullptr; 1.207 +} 1.208 + 1.209 +void 1.210 +RegisterUeventListener(IUeventObserver *aObserver) 1.211 +{ 1.212 + MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); 1.213 + 1.214 + if (!sPoller) 1.215 + InitializeUevent(); 1.216 + sPoller->RegisterObserver(aObserver); 1.217 +} 1.218 + 1.219 +void 1.220 +UnregisterUeventListener(IUeventObserver *aObserver) 1.221 +{ 1.222 + MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); 1.223 + 1.224 + sPoller->UnregisterObserver(aObserver); 1.225 +} 1.226 + 1.227 +} // hal_impl 1.228 +} // mozilla 1.229 +