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 ssize_t BitTube::write(void const* vaddr, size_t size)
    103 {
    104     ssize_t err, len;
    105     do {
    106         len = ::send(mSendFd, vaddr, size, MSG_DONTWAIT | MSG_NOSIGNAL);
    107         // cannot return less than size, since we're using SOCK_SEQPACKET
    108         err = len < 0 ? errno : 0;
    109     } while (err == EINTR);
    110     return err == 0 ? len : -err;
    111 }
    112 
    113 ssize_t BitTube::read(void* vaddr, size_t size)
    114 {
    115     ssize_t err, len;
    116     do {
    117         len = ::recv(mReceiveFd, vaddr, size, MSG_DONTWAIT);
    118         err = len < 0 ? errno : 0;
    119     } while (err == EINTR);
    120     if (err == EAGAIN || err == EWOULDBLOCK) {
    121         // EAGAIN means that we have non-blocking I/O but there was
    122         // no data to be read. Nothing the client should care about.
    123         return 0;
    124     }
    125     return err == 0 ? len : -err;
    126 }
    127 
    128 status_t BitTube::writeToParcel(Parcel* reply) const
    129 {
    130     if (mReceiveFd < 0)
    131         return -EINVAL;
    132 
    133     status_t result = reply->writeDupFileDescriptor(mReceiveFd);
    134     close(mReceiveFd);
    135     mReceiveFd = -1;
    136     return result;
    137 }
    138 
    139 
    140 ssize_t BitTube::sendObjects(const sp<BitTube>& tube,
    141         void const* events, size_t count, size_t objSize)
    142 {
    143     const char* vaddr = reinterpret_cast<const char*>(events);
    144     ssize_t size = tube->write(vaddr, count*objSize);
    145 
    146     // should never happen because of SOCK_SEQPACKET
    147     LOG_ALWAYS_FATAL_IF((size >= 0) && (size % objSize),
    148             "BitTube::sendObjects(count=%d, size=%d), res=%d (partial events were sent!)",
    149             count, objSize, size);
    150 
    151     //ALOGE_IF(size<0, "error %d sending %d events", size, count);
    152     return size < 0 ? size : size / objSize;
    153 }
    154 
    155 ssize_t BitTube::recvObjects(const sp<BitTube>& tube,
    156         void* events, size_t count, size_t objSize)
    157 {
    158     char* vaddr = reinterpret_cast<char*>(events);
    159     ssize_t size = tube->read(vaddr, count*objSize);
    160 
    161     // should never happen because of SOCK_SEQPACKET
    162     LOG_ALWAYS_FATAL_IF((size >= 0) && (size % objSize),
    163             "BitTube::recvObjects(count=%d, size=%d), res=%d (partial events were received!)",
    164             count, objSize, size);
    165 
    166     //ALOGE_IF(size<0, "error %d receiving %d events", size, count);
    167     return size < 0 ? size : size / objSize;
    168 }
    169 
    170 // ----------------------------------------------------------------------------
    171 }; // namespace android
    172