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