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