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