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