Home | History | Annotate | Download | only in sensor
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      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 
     17 #include <sensor/BitTube.h>
     18 
     19 #include <stdint.h>
     20 #include <sys/types.h>
     21 #include <sys/socket.h>
     22 
     23 #include <fcntl.h>
     24 #include <unistd.h>
     25 
     26 #include <binder/Parcel.h>
     27 
     28 namespace android {
     29 // ----------------------------------------------------------------------------
     30 
     31 // Socket buffer size.  The default is typically about 128KB, which is much larger than
     32 // we really need.  So we make it smaller.
     33 static const size_t DEFAULT_SOCKET_BUFFER_SIZE = 4 * 1024;
     34 
     35 
     36 BitTube::BitTube()
     37     : mSendFd(-1), mReceiveFd(-1)
     38 {
     39     init(DEFAULT_SOCKET_BUFFER_SIZE, DEFAULT_SOCKET_BUFFER_SIZE);
     40 }
     41 
     42 BitTube::BitTube(size_t bufsize)
     43     : mSendFd(-1), mReceiveFd(-1)
     44 {
     45     init(bufsize, bufsize);
     46 }
     47 
     48 BitTube::BitTube(const Parcel& data)
     49     : mSendFd(-1), mReceiveFd(-1)
     50 {
     51     mReceiveFd = dup(data.readFileDescriptor());
     52     if (mReceiveFd < 0) {
     53         mReceiveFd = -errno;
     54         ALOGE("BitTube(Parcel): can't dup filedescriptor (%s)",
     55                 strerror(-mReceiveFd));
     56     }
     57 }
     58 
     59 BitTube::~BitTube()
     60 {
     61     if (mSendFd >= 0)
     62         close(mSendFd);
     63 
     64     if (mReceiveFd >= 0)
     65         close(mReceiveFd);
     66 }
     67 
     68 void BitTube::init(size_t rcvbuf, size_t sndbuf) {
     69     int sockets[2];
     70     if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) == 0) {
     71         size_t size = DEFAULT_SOCKET_BUFFER_SIZE;
     72         setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf));
     73         setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf));
     74         // sine we don't use the "return channel", we keep it small...
     75         setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
     76         setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
     77         fcntl(sockets[0], F_SETFL, O_NONBLOCK);
     78         fcntl(sockets[1], F_SETFL, O_NONBLOCK);
     79         mReceiveFd = sockets[0];
     80         mSendFd = sockets[1];
     81     } else {
     82         mReceiveFd = -errno;
     83         ALOGE("BitTube: pipe creation failed (%s)", strerror(-mReceiveFd));
     84     }
     85 }
     86 
     87 status_t BitTube::initCheck() const
     88 {
     89     if (mReceiveFd < 0) {
     90         return status_t(mReceiveFd);
     91     }
     92     return NO_ERROR;
     93 }
     94 
     95 int BitTube::getFd() const
     96 {
     97     return mReceiveFd;
     98 }
     99 
    100 int BitTube::getSendFd() const
    101 {
    102     return mSendFd;
    103 }
    104 
    105 ssize_t BitTube::write(void const* vaddr, size_t size)
    106 {
    107     ssize_t err, len;
    108     do {
    109         len = ::send(mSendFd, vaddr, size, MSG_DONTWAIT | MSG_NOSIGNAL);
    110         // cannot return less than size, since we're using SOCK_SEQPACKET
    111         err = len < 0 ? errno : 0;
    112     } while (err == EINTR);
    113     return err == 0 ? len : -err;
    114 }
    115 
    116 ssize_t BitTube::read(void* vaddr, size_t size)
    117 {
    118     ssize_t err, len;
    119     do {
    120         len = ::recv(mReceiveFd, vaddr, size, MSG_DONTWAIT);
    121         err = len < 0 ? errno : 0;
    122     } while (err == EINTR);
    123     if (err == EAGAIN || err == EWOULDBLOCK) {
    124         // EAGAIN means that we have non-blocking I/O but there was
    125         // no data to be read. Nothing the client should care about.
    126         return 0;
    127     }
    128     return err == 0 ? len : -err;
    129 }
    130 
    131 status_t BitTube::writeToParcel(Parcel* reply) const
    132 {
    133     if (mReceiveFd < 0)
    134         return -EINVAL;
    135 
    136     status_t result = reply->writeDupFileDescriptor(mReceiveFd);
    137     close(mReceiveFd);
    138     mReceiveFd = -1;
    139     return result;
    140 }
    141 
    142 
    143 ssize_t BitTube::sendObjects(const sp<BitTube>& tube,
    144         void const* events, size_t count, size_t objSize)
    145 {
    146     const char* vaddr = reinterpret_cast<const char*>(events);
    147     ssize_t size = tube->write(vaddr, count*objSize);
    148 
    149     // should never happen because of SOCK_SEQPACKET
    150     LOG_ALWAYS_FATAL_IF((size >= 0) && (size % static_cast<ssize_t>(objSize)),
    151             "BitTube::sendObjects(count=%zu, size=%zu), res=%zd (partial events were sent!)",
    152             count, objSize, size);
    153 
    154     //ALOGE_IF(size<0, "error %d sending %d events", size, count);
    155     return size < 0 ? size : size / static_cast<ssize_t>(objSize);
    156 }
    157 
    158 ssize_t BitTube::recvObjects(const sp<BitTube>& tube,
    159         void* events, size_t count, size_t objSize)
    160 {
    161     char* vaddr = reinterpret_cast<char*>(events);
    162     ssize_t size = tube->read(vaddr, count*objSize);
    163 
    164     // should never happen because of SOCK_SEQPACKET
    165     LOG_ALWAYS_FATAL_IF((size >= 0) && (size % static_cast<ssize_t>(objSize)),
    166             "BitTube::recvObjects(count=%zu, size=%zu), res=%zd (partial events were received!)",
    167             count, objSize, size);
    168 
    169     //ALOGE_IF(size<0, "error %d receiving %d events", size, count);
    170     return size < 0 ? size : size / static_cast<ssize_t>(objSize);
    171 }
    172 
    173 // ----------------------------------------------------------------------------
    174 }; // namespace android
    175