1/* 2 * Copyright (C) 2011 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 17package libcore.io; 18 19import dalvik.system.BlockGuard; 20import dalvik.system.SocketTagger; 21import java.io.FileDescriptor; 22import java.net.InetAddress; 23import java.net.InetSocketAddress; 24import java.net.SocketException; 25import java.nio.ByteBuffer; 26import static libcore.io.OsConstants.*; 27 28/** 29 * Informs BlockGuard of any activity it should be aware of. 30 */ 31public class BlockGuardOs extends ForwardingOs { 32 public BlockGuardOs(Os os) { 33 super(os); 34 } 35 36 private FileDescriptor tagSocket(FileDescriptor fd) throws ErrnoException { 37 try { 38 SocketTagger.get().tag(fd); 39 return fd; 40 } catch (SocketException e) { 41 throw new ErrnoException("socket", EINVAL, e); 42 } 43 } 44 45 private void untagSocket(FileDescriptor fd) throws ErrnoException { 46 try { 47 SocketTagger.get().untag(fd); 48 } catch (SocketException e) { 49 throw new ErrnoException("socket", EINVAL, e); 50 } 51 } 52 53 @Override public FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException, SocketException { 54 BlockGuard.getThreadPolicy().onNetwork(); 55 return tagSocket(os.accept(fd, peerAddress)); 56 } 57 58 @Override public void close(FileDescriptor fd) throws ErrnoException { 59 try { 60 if (S_ISSOCK(Libcore.os.fstat(fd).st_mode)) { 61 if (isLingerSocket(fd)) { 62 // If the fd is a socket with SO_LINGER set, we might block indefinitely. 63 // We allow non-linger sockets so that apps can close their network 64 // connections in methods like onDestroy which will run on the UI thread. 65 BlockGuard.getThreadPolicy().onNetwork(); 66 } 67 untagSocket(fd); 68 } 69 } catch (ErrnoException ignored) { 70 // We're called via Socket.close (which doesn't ask for us to be called), so we 71 // must not throw here, because Socket.close must not throw if asked to close an 72 // already-closed socket. Also, the passed-in FileDescriptor isn't necessarily 73 // a socket at all. 74 } 75 os.close(fd); 76 } 77 78 private static boolean isLingerSocket(FileDescriptor fd) throws ErrnoException { 79 StructLinger linger = Libcore.os.getsockoptLinger(fd, SOL_SOCKET, SO_LINGER); 80 return linger.isOn() && linger.l_linger > 0; 81 } 82 83 @Override public void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException { 84 BlockGuard.getThreadPolicy().onNetwork(); 85 os.connect(fd, address, port); 86 } 87 88 // TODO: Untag newFd when needed for dup2(FileDescriptor oldFd, int newFd) 89 90 @Override public void fdatasync(FileDescriptor fd) throws ErrnoException { 91 BlockGuard.getThreadPolicy().onWriteToDisk(); 92 os.fdatasync(fd); 93 } 94 95 @Override public void fsync(FileDescriptor fd) throws ErrnoException { 96 BlockGuard.getThreadPolicy().onWriteToDisk(); 97 os.fsync(fd); 98 } 99 100 @Override public void ftruncate(FileDescriptor fd, long length) throws ErrnoException { 101 BlockGuard.getThreadPolicy().onWriteToDisk(); 102 os.ftruncate(fd, length); 103 } 104 105 @Override public FileDescriptor open(String path, int flags, int mode) throws ErrnoException { 106 BlockGuard.getThreadPolicy().onReadFromDisk(); 107 if ((mode & O_ACCMODE) != O_RDONLY) { 108 BlockGuard.getThreadPolicy().onWriteToDisk(); 109 } 110 return os.open(path, flags, mode); 111 } 112 113 @Override public int poll(StructPollfd[] fds, int timeoutMs) throws ErrnoException { 114 // Greater than 0 is a timeout in milliseconds and -1 means "block forever", 115 // but 0 means "poll and return immediately", which shouldn't be subject to BlockGuard. 116 if (timeoutMs != 0) { 117 BlockGuard.getThreadPolicy().onNetwork(); 118 } 119 return os.poll(fds, timeoutMs); 120 } 121 122 @Override public int pread(FileDescriptor fd, ByteBuffer buffer, long offset) throws ErrnoException { 123 BlockGuard.getThreadPolicy().onReadFromDisk(); 124 return os.pread(fd, buffer, offset); 125 } 126 127 @Override public int pread(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, long offset) throws ErrnoException { 128 BlockGuard.getThreadPolicy().onReadFromDisk(); 129 return os.pread(fd, bytes, byteOffset, byteCount, offset); 130 } 131 132 @Override public int pwrite(FileDescriptor fd, ByteBuffer buffer, long offset) throws ErrnoException { 133 BlockGuard.getThreadPolicy().onWriteToDisk(); 134 return os.pwrite(fd, buffer, offset); 135 } 136 137 @Override public int pwrite(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, long offset) throws ErrnoException { 138 BlockGuard.getThreadPolicy().onWriteToDisk(); 139 return os.pwrite(fd, bytes, byteOffset, byteCount, offset); 140 } 141 142 @Override public int read(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException { 143 BlockGuard.getThreadPolicy().onReadFromDisk(); 144 return os.read(fd, buffer); 145 } 146 147 @Override public int read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException { 148 BlockGuard.getThreadPolicy().onReadFromDisk(); 149 return os.read(fd, bytes, byteOffset, byteCount); 150 } 151 152 @Override public int readv(FileDescriptor fd, Object[] buffers, int[] offsets, int[] byteCounts) throws ErrnoException { 153 BlockGuard.getThreadPolicy().onReadFromDisk(); 154 return os.readv(fd, buffers, offsets, byteCounts); 155 } 156 157 @Override public int recvfrom(FileDescriptor fd, ByteBuffer buffer, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException { 158 BlockGuard.getThreadPolicy().onNetwork(); 159 return os.recvfrom(fd, buffer, flags, srcAddress); 160 } 161 162 @Override public int recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException { 163 BlockGuard.getThreadPolicy().onNetwork(); 164 return os.recvfrom(fd, bytes, byteOffset, byteCount, flags, srcAddress); 165 } 166 167 @Override public int sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException { 168 BlockGuard.getThreadPolicy().onNetwork(); 169 return os.sendto(fd, buffer, flags, inetAddress, port); 170 } 171 172 @Override public int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException { 173 // We permit datagrams without hostname lookups. 174 if (inetAddress != null) { 175 BlockGuard.getThreadPolicy().onNetwork(); 176 } 177 return os.sendto(fd, bytes, byteOffset, byteCount, flags, inetAddress, port); 178 } 179 180 @Override public FileDescriptor socket(int domain, int type, int protocol) throws ErrnoException { 181 return tagSocket(os.socket(domain, type, protocol)); 182 } 183 184 @Override public void socketpair(int domain, int type, int protocol, FileDescriptor fd1, FileDescriptor fd2) throws ErrnoException { 185 os.socketpair(domain, type, protocol, fd1, fd2); 186 tagSocket(fd1); 187 tagSocket(fd2); 188 } 189 190 @Override public int write(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException { 191 BlockGuard.getThreadPolicy().onWriteToDisk(); 192 return os.write(fd, buffer); 193 } 194 195 @Override public int write(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException { 196 BlockGuard.getThreadPolicy().onWriteToDisk(); 197 return os.write(fd, bytes, byteOffset, byteCount); 198 } 199 200 @Override public int writev(FileDescriptor fd, Object[] buffers, int[] offsets, int[] byteCounts) throws ErrnoException { 201 BlockGuard.getThreadPolicy().onWriteToDisk(); 202 return os.writev(fd, buffers, offsets, byteCounts); 203 } 204} 205