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