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