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