• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 SOCKET_BUFFER_SIZE = 4 * 1024;
36 
37 
BitTube()38 BitTube::BitTube()
39     : mSendFd(-1), mReceiveFd(-1)
40 {
41     int sockets[2];
42     if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) == 0) {
43         int size = SOCKET_BUFFER_SIZE;
44         setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
45         setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
46         setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
47         setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
48         fcntl(sockets[0], F_SETFL, O_NONBLOCK);
49         fcntl(sockets[1], F_SETFL, O_NONBLOCK);
50         mReceiveFd = sockets[0];
51         mSendFd = sockets[1];
52     } else {
53         mReceiveFd = -errno;
54         ALOGE("BitTube: pipe creation failed (%s)", strerror(-mReceiveFd));
55     }
56 }
57 
BitTube(const Parcel & data)58 BitTube::BitTube(const Parcel& data)
59     : mSendFd(-1), mReceiveFd(-1)
60 {
61     mReceiveFd = dup(data.readFileDescriptor());
62     if (mReceiveFd >= 0) {
63         int size = SOCKET_BUFFER_SIZE;
64         setsockopt(mReceiveFd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
65         setsockopt(mReceiveFd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
66         fcntl(mReceiveFd, F_SETFL, O_NONBLOCK);
67     } else {
68         mReceiveFd = -errno;
69         ALOGE("BitTube(Parcel): can't dup filedescriptor (%s)",
70                 strerror(-mReceiveFd));
71     }
72 }
73 
~BitTube()74 BitTube::~BitTube()
75 {
76     if (mSendFd >= 0)
77         close(mSendFd);
78 
79     if (mReceiveFd >= 0)
80         close(mReceiveFd);
81 }
82 
initCheck() const83 status_t BitTube::initCheck() const
84 {
85     if (mReceiveFd < 0) {
86         return status_t(mReceiveFd);
87     }
88     return NO_ERROR;
89 }
90 
getFd() const91 int BitTube::getFd() const
92 {
93     return mReceiveFd;
94 }
95 
write(void const * vaddr,size_t size)96 ssize_t BitTube::write(void const* vaddr, size_t size)
97 {
98     ssize_t err, len;
99     do {
100         len = ::send(mSendFd, vaddr, size, MSG_DONTWAIT | MSG_NOSIGNAL);
101         err = len < 0 ? errno : 0;
102     } while (err == EINTR);
103     return err == 0 ? len : -err;
104 
105 }
106 
read(void * vaddr,size_t size)107 ssize_t BitTube::read(void* vaddr, size_t size)
108 {
109     ssize_t err, len;
110     do {
111         len = ::recv(mReceiveFd, vaddr, size, MSG_DONTWAIT);
112         err = len < 0 ? errno : 0;
113     } while (err == EINTR);
114     if (err == EAGAIN || err == EWOULDBLOCK) {
115         // EAGAIN means that we have non-blocking I/O but there was
116         // no data to be read. Nothing the client should care about.
117         return 0;
118     }
119     return err == 0 ? len : -err;
120 }
121 
writeToParcel(Parcel * reply) const122 status_t BitTube::writeToParcel(Parcel* reply) const
123 {
124     if (mReceiveFd < 0)
125         return -EINVAL;
126 
127     status_t result = reply->writeDupFileDescriptor(mReceiveFd);
128     close(mReceiveFd);
129     mReceiveFd = -1;
130     return result;
131 }
132 
133 
sendObjects(const sp<BitTube> & tube,void const * events,size_t count,size_t objSize)134 ssize_t BitTube::sendObjects(const sp<BitTube>& tube,
135         void const* events, size_t count, size_t objSize)
136 {
137     ssize_t numObjects = 0;
138     for (size_t i=0 ; i<count ; i++) {
139         const char* vaddr = reinterpret_cast<const char*>(events) + objSize * i;
140         ssize_t size = tube->write(vaddr, objSize);
141         if (size < 0) {
142             // error occurred
143             return size;
144         } else if (size == 0) {
145             // no more space
146             break;
147         }
148         numObjects++;
149     }
150     return numObjects;
151 }
152 
recvObjects(const sp<BitTube> & tube,void * events,size_t count,size_t objSize)153 ssize_t BitTube::recvObjects(const sp<BitTube>& tube,
154         void* events, size_t count, size_t objSize)
155 {
156     ssize_t numObjects = 0;
157     for (size_t i=0 ; i<count ; i++) {
158         char* vaddr = reinterpret_cast<char*>(events) + objSize * i;
159         ssize_t size = tube->read(vaddr, objSize);
160         if (size < 0) {
161             // error occurred
162             return size;
163         } else if (size == 0) {
164             // no more messages
165             break;
166         }
167         numObjects++;
168     }
169     return numObjects;
170 }
171 
172 // ----------------------------------------------------------------------------
173 }; // namespace android
174