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