BlockGuardOs.java revision 5112325117859c7c6cd042c17f519f967c551b20
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 @Override public FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException { 46 BlockGuard.getThreadPolicy().onNetwork(); 47 return tagSocket(os.accept(fd, peerAddress)); 48 } 49 50 @Override public void close(FileDescriptor fd) throws ErrnoException { 51 // TODO: is there a way to avoid calling getsockopt(2) on non-socket fds? 52 if (isLingerSocket(fd)) { 53 // If the fd is a socket with SO_LINGER set, we might block indefinitely. 54 // We allow non-linger sockets so that apps can close their network connections in 55 // methods like onDestroy which will run on the UI thread. 56 BlockGuard.getThreadPolicy().onNetwork(); 57 } 58 os.close(fd); 59 } 60 61 private static boolean isLingerSocket(FileDescriptor fd) { 62 try { 63 StructLinger linger = Libcore.os.getsockoptLinger(fd, SOL_SOCKET, SO_LINGER); 64 return linger.isOn() && linger.l_linger > 0; 65 } catch (ErrnoException ignored) { 66 // We're called via Socket.close (which doesn't ask for us to be called), so we 67 // must not throw here, because Socket.close must not throw if asked to close an 68 // already-closed socket. Also, the passed-in FileDescriptor isn't necessarily 69 // a socket at all. 70 return false; 71 } 72 } 73 74 @Override public void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException { 75 BlockGuard.getThreadPolicy().onNetwork(); 76 os.connect(fd, address, port); 77 } 78 79 @Override public void fdatasync(FileDescriptor fd) throws ErrnoException { 80 BlockGuard.getThreadPolicy().onWriteToDisk(); 81 os.fdatasync(fd); 82 } 83 84 @Override public void fsync(FileDescriptor fd) throws ErrnoException { 85 BlockGuard.getThreadPolicy().onWriteToDisk(); 86 os.fsync(fd); 87 } 88 89 @Override public void ftruncate(FileDescriptor fd, long length) throws ErrnoException { 90 BlockGuard.getThreadPolicy().onWriteToDisk(); 91 os.ftruncate(fd, length); 92 } 93 94 @Override public FileDescriptor open(String path, int flags, int mode) throws ErrnoException { 95 BlockGuard.getThreadPolicy().onReadFromDisk(); 96 if ((mode & O_ACCMODE) != O_RDONLY) { 97 BlockGuard.getThreadPolicy().onWriteToDisk(); 98 } 99 return os.open(path, flags, mode); 100 } 101 102 @Override public int poll(StructPollfd[] fds, int timeoutMs) throws ErrnoException { 103 // Greater than 0 is a timeout in milliseconds and -1 means "block forever", 104 // but 0 means "poll and return immediately", which shouldn't be subject to BlockGuard. 105 if (timeoutMs != 0) { 106 BlockGuard.getThreadPolicy().onNetwork(); 107 } 108 return os.poll(fds, timeoutMs); 109 } 110 111 @Override public int pread(FileDescriptor fd, ByteBuffer buffer, long offset) throws ErrnoException { 112 BlockGuard.getThreadPolicy().onReadFromDisk(); 113 return os.pread(fd, buffer, offset); 114 } 115 116 @Override public int pread(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, long offset) throws ErrnoException { 117 BlockGuard.getThreadPolicy().onReadFromDisk(); 118 return os.pread(fd, bytes, byteOffset, byteCount, offset); 119 } 120 121 @Override public int pwrite(FileDescriptor fd, ByteBuffer buffer, long offset) throws ErrnoException { 122 BlockGuard.getThreadPolicy().onWriteToDisk(); 123 return os.pwrite(fd, buffer, offset); 124 } 125 126 @Override public int pwrite(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, long offset) throws ErrnoException { 127 BlockGuard.getThreadPolicy().onWriteToDisk(); 128 return os.pwrite(fd, bytes, byteOffset, byteCount, offset); 129 } 130 131 @Override public int read(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException { 132 BlockGuard.getThreadPolicy().onReadFromDisk(); 133 return os.read(fd, buffer); 134 } 135 136 @Override public int read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException { 137 BlockGuard.getThreadPolicy().onReadFromDisk(); 138 return os.read(fd, bytes, byteOffset, byteCount); 139 } 140 141 @Override public int readv(FileDescriptor fd, Object[] buffers, int[] offsets, int[] byteCounts) throws ErrnoException { 142 BlockGuard.getThreadPolicy().onReadFromDisk(); 143 return os.readv(fd, buffers, offsets, byteCounts); 144 } 145 146 @Override public int recvfrom(FileDescriptor fd, ByteBuffer buffer, int flags, InetSocketAddress srcAddress) throws ErrnoException { 147 BlockGuard.getThreadPolicy().onNetwork(); 148 return os.recvfrom(fd, buffer, flags, srcAddress); 149 } 150 151 @Override public int recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException { 152 BlockGuard.getThreadPolicy().onNetwork(); 153 return os.recvfrom(fd, bytes, byteOffset, byteCount, flags, srcAddress); 154 } 155 156 @Override public int sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port) throws ErrnoException { 157 BlockGuard.getThreadPolicy().onNetwork(); 158 return os.sendto(fd, buffer, flags, inetAddress, port); 159 } 160 161 @Override public int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws ErrnoException { 162 // We permit datagrams without hostname lookups. 163 if (inetAddress != null) { 164 BlockGuard.getThreadPolicy().onNetwork(); 165 } 166 return os.sendto(fd, bytes, byteOffset, byteCount, flags, inetAddress, port); 167 } 168 169 @Override public FileDescriptor socket(int domain, int type, int protocol) throws ErrnoException { 170 return tagSocket(os.socket(domain, type, protocol)); 171 } 172 173 @Override public int write(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException { 174 BlockGuard.getThreadPolicy().onWriteToDisk(); 175 return os.write(fd, buffer); 176 } 177 178 @Override public int write(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException { 179 BlockGuard.getThreadPolicy().onWriteToDisk(); 180 return os.write(fd, bytes, byteOffset, byteCount); 181 } 182 183 @Override public int writev(FileDescriptor fd, Object[] buffers, int[] offsets, int[] byteCounts) throws ErrnoException { 184 BlockGuard.getThreadPolicy().onWriteToDisk(); 185 return os.writev(fd, buffers, offsets, byteCounts); 186 } 187} 188