BlockGuardOs.java revision f0d40d662d9dfdb04215c718961765837d2cf00c
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.io.InterruptedIOException; 23import java.net.InetAddress; 24import java.net.InetSocketAddress; 25import java.net.SocketException; 26import java.nio.ByteBuffer; 27import libcore.util.MutableLong; 28import static libcore.io.OsConstants.*; 29 30/** 31 * Informs BlockGuard of any activity it should be aware of. 32 */ 33public class BlockGuardOs extends ForwardingOs { 34 public BlockGuardOs(Os os) { 35 super(os); 36 } 37 38 private FileDescriptor tagSocket(FileDescriptor fd) throws ErrnoException { 39 try { 40 SocketTagger.get().tag(fd); 41 return fd; 42 } catch (SocketException e) { 43 throw new ErrnoException("socket", EINVAL, e); 44 } 45 } 46 47 private void untagSocket(FileDescriptor fd) throws ErrnoException { 48 try { 49 SocketTagger.get().untag(fd); 50 } catch (SocketException e) { 51 throw new ErrnoException("socket", EINVAL, e); 52 } 53 } 54 55 @Override public FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException, SocketException { 56 BlockGuard.getThreadPolicy().onNetwork(); 57 return tagSocket(os.accept(fd, peerAddress)); 58 } 59 60 @Override public boolean access(String path, int mode) throws ErrnoException { 61 BlockGuard.getThreadPolicy().onReadFromDisk(); 62 return os.access(path, mode); 63 } 64 65 @Override public void chmod(String path, int mode) throws ErrnoException { 66 BlockGuard.getThreadPolicy().onWriteToDisk(); 67 os.chmod(path, mode); 68 } 69 70 @Override public void chown(String path, int uid, int gid) throws ErrnoException { 71 BlockGuard.getThreadPolicy().onWriteToDisk(); 72 os.chown(path, uid, gid); 73 } 74 75 @Override public void close(FileDescriptor fd) throws ErrnoException { 76 try { 77 if (S_ISSOCK(Libcore.os.fstat(fd).st_mode)) { 78 if (isLingerSocket(fd)) { 79 // If the fd is a socket with SO_LINGER set, we might block indefinitely. 80 // We allow non-linger sockets so that apps can close their network 81 // connections in methods like onDestroy which will run on the UI thread. 82 BlockGuard.getThreadPolicy().onNetwork(); 83 } 84 untagSocket(fd); 85 } 86 } catch (ErrnoException ignored) { 87 // We're called via Socket.close (which doesn't ask for us to be called), so we 88 // must not throw here, because Socket.close must not throw if asked to close an 89 // already-closed socket. Also, the passed-in FileDescriptor isn't necessarily 90 // a socket at all. 91 } 92 os.close(fd); 93 } 94 95 private static boolean isLingerSocket(FileDescriptor fd) throws ErrnoException { 96 StructLinger linger = Libcore.os.getsockoptLinger(fd, SOL_SOCKET, SO_LINGER); 97 return linger.isOn() && linger.l_linger > 0; 98 } 99 100 @Override public void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException { 101 BlockGuard.getThreadPolicy().onNetwork(); 102 os.connect(fd, address, port); 103 } 104 105 @Override public void fchmod(FileDescriptor fd, int mode) throws ErrnoException { 106 BlockGuard.getThreadPolicy().onWriteToDisk(); 107 os.fchmod(fd, mode); 108 } 109 110 @Override public void fchown(FileDescriptor fd, int uid, int gid) throws ErrnoException { 111 BlockGuard.getThreadPolicy().onWriteToDisk(); 112 os.fchown(fd, uid, gid); 113 } 114 115 // TODO: Untag newFd when needed for dup2(FileDescriptor oldFd, int newFd) 116 117 @Override public void fdatasync(FileDescriptor fd) throws ErrnoException { 118 BlockGuard.getThreadPolicy().onWriteToDisk(); 119 os.fdatasync(fd); 120 } 121 122 @Override public StructStat fstat(FileDescriptor fd) throws ErrnoException { 123 BlockGuard.getThreadPolicy().onReadFromDisk(); 124 return os.fstat(fd); 125 } 126 127 @Override public StructStatVfs fstatvfs(FileDescriptor fd) throws ErrnoException { 128 BlockGuard.getThreadPolicy().onReadFromDisk(); 129 return os.fstatvfs(fd); 130 } 131 132 @Override public void fsync(FileDescriptor fd) throws ErrnoException { 133 BlockGuard.getThreadPolicy().onWriteToDisk(); 134 os.fsync(fd); 135 } 136 137 @Override public void ftruncate(FileDescriptor fd, long length) throws ErrnoException { 138 BlockGuard.getThreadPolicy().onWriteToDisk(); 139 os.ftruncate(fd, length); 140 } 141 142 @Override public void lchown(String path, int uid, int gid) throws ErrnoException { 143 BlockGuard.getThreadPolicy().onWriteToDisk(); 144 os.lchown(path, uid, gid); 145 } 146 147 @Override public long lseek(FileDescriptor fd, long offset, int whence) throws ErrnoException { 148 BlockGuard.getThreadPolicy().onReadFromDisk(); 149 return os.lseek(fd, offset, whence); 150 } 151 152 @Override public StructStat lstat(String path) throws ErrnoException { 153 BlockGuard.getThreadPolicy().onReadFromDisk(); 154 return os.lstat(path); 155 } 156 157 @Override public void mkdir(String path, int mode) throws ErrnoException { 158 BlockGuard.getThreadPolicy().onWriteToDisk(); 159 os.mkdir(path, mode); 160 } 161 162 @Override public void mkfifo(String path, int mode) throws ErrnoException { 163 BlockGuard.getThreadPolicy().onWriteToDisk(); 164 os.mkfifo(path, mode); 165 } 166 167 @Override public FileDescriptor open(String path, int flags, int mode) throws ErrnoException { 168 BlockGuard.getThreadPolicy().onReadFromDisk(); 169 if ((mode & O_ACCMODE) != O_RDONLY) { 170 BlockGuard.getThreadPolicy().onWriteToDisk(); 171 } 172 return os.open(path, flags, mode); 173 } 174 175 @Override public int poll(StructPollfd[] fds, int timeoutMs) throws ErrnoException { 176 // Greater than 0 is a timeout in milliseconds and -1 means "block forever", 177 // but 0 means "poll and return immediately", which shouldn't be subject to BlockGuard. 178 if (timeoutMs != 0) { 179 BlockGuard.getThreadPolicy().onNetwork(); 180 } 181 return os.poll(fds, timeoutMs); 182 } 183 184 @Override public void posix_fallocate(FileDescriptor fd, long offset, long length) throws ErrnoException { 185 BlockGuard.getThreadPolicy().onWriteToDisk(); 186 os.posix_fallocate(fd, offset, length); 187 } 188 189 @Override public int pread(FileDescriptor fd, ByteBuffer buffer, long offset) throws ErrnoException, InterruptedIOException { 190 BlockGuard.getThreadPolicy().onReadFromDisk(); 191 return os.pread(fd, buffer, offset); 192 } 193 194 @Override public int pread(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, long offset) throws ErrnoException, InterruptedIOException { 195 BlockGuard.getThreadPolicy().onReadFromDisk(); 196 return os.pread(fd, bytes, byteOffset, byteCount, offset); 197 } 198 199 @Override public int pwrite(FileDescriptor fd, ByteBuffer buffer, long offset) throws ErrnoException, InterruptedIOException { 200 BlockGuard.getThreadPolicy().onWriteToDisk(); 201 return os.pwrite(fd, buffer, offset); 202 } 203 204 @Override public int pwrite(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, long offset) throws ErrnoException, InterruptedIOException { 205 BlockGuard.getThreadPolicy().onWriteToDisk(); 206 return os.pwrite(fd, bytes, byteOffset, byteCount, offset); 207 } 208 209 @Override public int read(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException, InterruptedIOException { 210 BlockGuard.getThreadPolicy().onReadFromDisk(); 211 return os.read(fd, buffer); 212 } 213 214 @Override public int read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException, InterruptedIOException { 215 BlockGuard.getThreadPolicy().onReadFromDisk(); 216 return os.read(fd, bytes, byteOffset, byteCount); 217 } 218 219 @Override public String readlink(String path) throws ErrnoException { 220 BlockGuard.getThreadPolicy().onReadFromDisk(); 221 return os.readlink(path); 222 } 223 224 @Override public int readv(FileDescriptor fd, Object[] buffers, int[] offsets, int[] byteCounts) throws ErrnoException, InterruptedIOException { 225 BlockGuard.getThreadPolicy().onReadFromDisk(); 226 return os.readv(fd, buffers, offsets, byteCounts); 227 } 228 229 @Override public int recvfrom(FileDescriptor fd, ByteBuffer buffer, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException { 230 BlockGuard.getThreadPolicy().onNetwork(); 231 return os.recvfrom(fd, buffer, flags, srcAddress); 232 } 233 234 @Override public int recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException { 235 BlockGuard.getThreadPolicy().onNetwork(); 236 return os.recvfrom(fd, bytes, byteOffset, byteCount, flags, srcAddress); 237 } 238 239 @Override public void remove(String path) throws ErrnoException { 240 BlockGuard.getThreadPolicy().onWriteToDisk(); 241 os.remove(path); 242 } 243 244 @Override public void rename(String oldPath, String newPath) throws ErrnoException { 245 BlockGuard.getThreadPolicy().onWriteToDisk(); 246 os.rename(oldPath, newPath); 247 } 248 249 @Override public long sendfile(FileDescriptor outFd, FileDescriptor inFd, MutableLong inOffset, long byteCount) throws ErrnoException { 250 BlockGuard.getThreadPolicy().onWriteToDisk(); 251 return os.sendfile(outFd, inFd, inOffset, byteCount); 252 } 253 254 @Override public int sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException { 255 BlockGuard.getThreadPolicy().onNetwork(); 256 return os.sendto(fd, buffer, flags, inetAddress, port); 257 } 258 259 @Override public int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException { 260 // We permit datagrams without hostname lookups. 261 if (inetAddress != null) { 262 BlockGuard.getThreadPolicy().onNetwork(); 263 } 264 return os.sendto(fd, bytes, byteOffset, byteCount, flags, inetAddress, port); 265 } 266 267 @Override public FileDescriptor socket(int domain, int type, int protocol) throws ErrnoException { 268 return tagSocket(os.socket(domain, type, protocol)); 269 } 270 271 @Override public void socketpair(int domain, int type, int protocol, FileDescriptor fd1, FileDescriptor fd2) throws ErrnoException { 272 os.socketpair(domain, type, protocol, fd1, fd2); 273 tagSocket(fd1); 274 tagSocket(fd2); 275 } 276 277 @Override public StructStat stat(String path) throws ErrnoException { 278 BlockGuard.getThreadPolicy().onReadFromDisk(); 279 return os.stat(path); 280 } 281 282 @Override public StructStatVfs statvfs(String path) throws ErrnoException { 283 BlockGuard.getThreadPolicy().onReadFromDisk(); 284 return os.statvfs(path); 285 } 286 287 @Override public void symlink(String oldPath, String newPath) throws ErrnoException { 288 BlockGuard.getThreadPolicy().onWriteToDisk(); 289 os.symlink(oldPath, newPath); 290 } 291 292 @Override public int write(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException, InterruptedIOException { 293 BlockGuard.getThreadPolicy().onWriteToDisk(); 294 return os.write(fd, buffer); 295 } 296 297 @Override public int write(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException, InterruptedIOException { 298 BlockGuard.getThreadPolicy().onWriteToDisk(); 299 return os.write(fd, bytes, byteOffset, byteCount); 300 } 301 302 @Override public int writev(FileDescriptor fd, Object[] buffers, int[] offsets, int[] byteCounts) throws ErrnoException, InterruptedIOException { 303 BlockGuard.getThreadPolicy().onWriteToDisk(); 304 return os.writev(fd, buffers, offsets, byteCounts); 305 } 306} 307