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