152724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes/*
252724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes * Copyright (C) 2011 The Android Open Source Project
352724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes *
452724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes * Licensed under the Apache License, Version 2.0 (the "License");
552724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes * you may not use this file except in compliance with the License.
652724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes * You may obtain a copy of the License at
752724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes *
852724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes *      http://www.apache.org/licenses/LICENSE-2.0
952724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes *
1052724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes * Unless required by applicable law or agreed to in writing, software
1152724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
1252724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1352724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes * See the License for the specific language governing permissions and
1452724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes * limitations under the License.
1552724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes */
1652724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes
1752724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughespackage libcore.io;
1852724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes
1952724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughesimport dalvik.system.BlockGuard;
205112325117859c7c6cd042c17f519f967c551b20Jesse Wilsonimport dalvik.system.SocketTagger;
2152724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughesimport java.io.FileDescriptor;
22996bf79565ac88402920bd826d6f85952c83be20Elliott Hughesimport java.net.InetAddress;
2323ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughesimport java.net.InetSocketAddress;
241e8d508f2d97e19f2fc8a709330ea97e1e9f203aJeff Sharkeyimport java.net.SocketException;
2526c7025a7a919044771fb89031161bd26fe03032Elliott Hughesimport java.nio.ByteBuffer;
260ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughesimport static libcore.io.OsConstants.*;
2752724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes
2852724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes/**
2952724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes * Informs BlockGuard of any activity it should be aware of.
3052724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes */
3152724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughespublic class BlockGuardOs extends ForwardingOs {
3252724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes    public BlockGuardOs(Os os) {
3352724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes        super(os);
3452724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes    }
3552724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes
369b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes    private FileDescriptor tagSocket(FileDescriptor fd) throws ErrnoException {
37553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes        try {
385112325117859c7c6cd042c17f519f967c551b20Jesse Wilson            SocketTagger.get().tag(fd);
39553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes            return fd;
40553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes        } catch (SocketException e) {
41553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes            throw new ErrnoException("socket", EINVAL, e);
42553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes        }
43553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes    }
44553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes
454ff585466887785d48c02d14a15dcde64934442bJP Abgrall    private void untagSocket(FileDescriptor fd) throws ErrnoException {
464ff585466887785d48c02d14a15dcde64934442bJP Abgrall        try {
474ff585466887785d48c02d14a15dcde64934442bJP Abgrall            SocketTagger.get().untag(fd);
484ff585466887785d48c02d14a15dcde64934442bJP Abgrall        } catch (SocketException e) {
494ff585466887785d48c02d14a15dcde64934442bJP Abgrall            throw new ErrnoException("socket", EINVAL, e);
504ff585466887785d48c02d14a15dcde64934442bJP Abgrall        }
514ff585466887785d48c02d14a15dcde64934442bJP Abgrall    }
524ff585466887785d48c02d14a15dcde64934442bJP Abgrall
5326010ab930a2cee3bf10b9612cf070183c21228bElliott Hughes    @Override public FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException, SocketException {
54553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes        BlockGuard.getThreadPolicy().onNetwork();
55553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes        return tagSocket(os.accept(fd, peerAddress));
56553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes    }
57553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes
58e27d02044ec399884bfd4343d513bf270b9b9b11Elliott Hughes    @Override public void close(FileDescriptor fd) throws ErrnoException {
59e27d02044ec399884bfd4343d513bf270b9b9b11Elliott Hughes        try {
604ff585466887785d48c02d14a15dcde64934442bJP Abgrall            if (S_ISSOCK(Libcore.os.fstat(fd).st_mode)) {
614ff585466887785d48c02d14a15dcde64934442bJP Abgrall                if (isLingerSocket(fd)) {
624ff585466887785d48c02d14a15dcde64934442bJP Abgrall                    // If the fd is a socket with SO_LINGER set, we might block indefinitely.
634ff585466887785d48c02d14a15dcde64934442bJP Abgrall                    // We allow non-linger sockets so that apps can close their network
644ff585466887785d48c02d14a15dcde64934442bJP Abgrall                    // connections in methods like onDestroy which will run on the UI thread.
654ff585466887785d48c02d14a15dcde64934442bJP Abgrall                    BlockGuard.getThreadPolicy().onNetwork();
664ff585466887785d48c02d14a15dcde64934442bJP Abgrall                }
674ff585466887785d48c02d14a15dcde64934442bJP Abgrall                untagSocket(fd);
68e8e19f6476b30ccf9f69925c10ce62efdba4e62aElliott Hughes            }
69e27d02044ec399884bfd4343d513bf270b9b9b11Elliott Hughes        } catch (ErrnoException ignored) {
70e27d02044ec399884bfd4343d513bf270b9b9b11Elliott Hughes            // We're called via Socket.close (which doesn't ask for us to be called), so we
71e27d02044ec399884bfd4343d513bf270b9b9b11Elliott Hughes            // must not throw here, because Socket.close must not throw if asked to close an
72e27d02044ec399884bfd4343d513bf270b9b9b11Elliott Hughes            // already-closed socket. Also, the passed-in FileDescriptor isn't necessarily
73e27d02044ec399884bfd4343d513bf270b9b9b11Elliott Hughes            // a socket at all.
74e27d02044ec399884bfd4343d513bf270b9b9b11Elliott Hughes        }
75e8e19f6476b30ccf9f69925c10ce62efdba4e62aElliott Hughes        os.close(fd);
76e8e19f6476b30ccf9f69925c10ce62efdba4e62aElliott Hughes    }
77e8e19f6476b30ccf9f69925c10ce62efdba4e62aElliott Hughes
78e8e19f6476b30ccf9f69925c10ce62efdba4e62aElliott Hughes    private static boolean isLingerSocket(FileDescriptor fd) throws ErrnoException {
79e8e19f6476b30ccf9f69925c10ce62efdba4e62aElliott Hughes        StructLinger linger = Libcore.os.getsockoptLinger(fd, SOL_SOCKET, SO_LINGER);
80e8e19f6476b30ccf9f69925c10ce62efdba4e62aElliott Hughes        return linger.isOn() && linger.l_linger > 0;
81e27d02044ec399884bfd4343d513bf270b9b9b11Elliott Hughes    }
82e27d02044ec399884bfd4343d513bf270b9b9b11Elliott Hughes
8326010ab930a2cee3bf10b9612cf070183c21228bElliott Hughes    @Override public void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException {
84996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes        BlockGuard.getThreadPolicy().onNetwork();
85996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes        os.connect(fd, address, port);
86996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes    }
87996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes
884ff585466887785d48c02d14a15dcde64934442bJP Abgrall    // TODO: Untag newFd when needed for dup2(FileDescriptor oldFd, int newFd)
894ff585466887785d48c02d14a15dcde64934442bJP Abgrall
9070c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    @Override public void fdatasync(FileDescriptor fd) throws ErrnoException {
9152724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes        BlockGuard.getThreadPolicy().onWriteToDisk();
9252724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes        os.fdatasync(fd);
9352724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes    }
9452724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes
9590d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes    @Override public void fsync(FileDescriptor fd) throws ErrnoException {
9652724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes        BlockGuard.getThreadPolicy().onWriteToDisk();
9752724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes        os.fsync(fd);
9852724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes    }
99f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes
10090d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes    @Override public void ftruncate(FileDescriptor fd, long length) throws ErrnoException {
101f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes        BlockGuard.getThreadPolicy().onWriteToDisk();
102f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes        os.ftruncate(fd, length);
103f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes    }
1040ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughes
10590d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes    @Override public FileDescriptor open(String path, int flags, int mode) throws ErrnoException {
1060ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughes        BlockGuard.getThreadPolicy().onReadFromDisk();
1070ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughes        if ((mode & O_ACCMODE) != O_RDONLY) {
1080ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughes            BlockGuard.getThreadPolicy().onWriteToDisk();
1090ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughes        }
1100ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughes        return os.open(path, flags, mode);
1110ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughes    }
11226c7025a7a919044771fb89031161bd26fe03032Elliott Hughes
11370c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    @Override public int poll(StructPollfd[] fds, int timeoutMs) throws ErrnoException {
1142bad9bff258de6275bd3847e5e9f3169b0a93c61Elliott Hughes        // Greater than 0 is a timeout in milliseconds and -1 means "block forever",
1152bad9bff258de6275bd3847e5e9f3169b0a93c61Elliott Hughes        // but 0 means "poll and return immediately", which shouldn't be subject to BlockGuard.
1162bad9bff258de6275bd3847e5e9f3169b0a93c61Elliott Hughes        if (timeoutMs != 0) {
1172bad9bff258de6275bd3847e5e9f3169b0a93c61Elliott Hughes            BlockGuard.getThreadPolicy().onNetwork();
1182bad9bff258de6275bd3847e5e9f3169b0a93c61Elliott Hughes        }
11970c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        return os.poll(fds, timeoutMs);
12070c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    }
12170c820401677ca251ad09ac64cc23c760764e75dElliott Hughes
122e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes    @Override public int pread(FileDescriptor fd, ByteBuffer buffer, long offset) throws ErrnoException {
123e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes        BlockGuard.getThreadPolicy().onReadFromDisk();
124e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes        return os.pread(fd, buffer, offset);
125e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes    }
126e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes
127e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes    @Override public int pread(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, long offset) throws ErrnoException {
128e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes        BlockGuard.getThreadPolicy().onReadFromDisk();
129e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes        return os.pread(fd, bytes, byteOffset, byteCount, offset);
130e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes    }
131e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes
132e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes    @Override public int pwrite(FileDescriptor fd, ByteBuffer buffer, long offset) throws ErrnoException {
133e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes        BlockGuard.getThreadPolicy().onWriteToDisk();
134e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes        return os.pwrite(fd, buffer, offset);
135e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes    }
136e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes
137e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes    @Override public int pwrite(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, long offset) throws ErrnoException {
138e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes        BlockGuard.getThreadPolicy().onWriteToDisk();
139e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes        return os.pwrite(fd, bytes, byteOffset, byteCount, offset);
140e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes    }
141e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes
14270c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    @Override public int read(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException {
14326c7025a7a919044771fb89031161bd26fe03032Elliott Hughes        BlockGuard.getThreadPolicy().onReadFromDisk();
14426c7025a7a919044771fb89031161bd26fe03032Elliott Hughes        return os.read(fd, buffer);
14526c7025a7a919044771fb89031161bd26fe03032Elliott Hughes    }
14626c7025a7a919044771fb89031161bd26fe03032Elliott Hughes
14790d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes    @Override public int read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException {
14826c7025a7a919044771fb89031161bd26fe03032Elliott Hughes        BlockGuard.getThreadPolicy().onReadFromDisk();
14926c7025a7a919044771fb89031161bd26fe03032Elliott Hughes        return os.read(fd, bytes, byteOffset, byteCount);
15026c7025a7a919044771fb89031161bd26fe03032Elliott Hughes    }
15178c7cc547101002b9f9043cf3845970719d1bda8Elliott Hughes
15290d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes    @Override public int readv(FileDescriptor fd, Object[] buffers, int[] offsets, int[] byteCounts) throws ErrnoException {
153bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        BlockGuard.getThreadPolicy().onReadFromDisk();
154bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        return os.readv(fd, buffers, offsets, byteCounts);
155bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    }
156bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes
15726010ab930a2cee3bf10b9612cf070183c21228bElliott Hughes    @Override public int recvfrom(FileDescriptor fd, ByteBuffer buffer, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException {
15823ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes        BlockGuard.getThreadPolicy().onNetwork();
159553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes        return os.recvfrom(fd, buffer, flags, srcAddress);
16023ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes    }
16123ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes
16226010ab930a2cee3bf10b9612cf070183c21228bElliott Hughes    @Override public int recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException {
16323ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes        BlockGuard.getThreadPolicy().onNetwork();
164553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes        return os.recvfrom(fd, bytes, byteOffset, byteCount, flags, srcAddress);
16523ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes    }
16623ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes
16726010ab930a2cee3bf10b9612cf070183c21228bElliott Hughes    @Override public int sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException {
16890d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes        BlockGuard.getThreadPolicy().onNetwork();
16990d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes        return os.sendto(fd, buffer, flags, inetAddress, port);
17090d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes    }
17190d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes
17226010ab930a2cee3bf10b9612cf070183c21228bElliott Hughes    @Override public int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException {
17390d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes        // We permit datagrams without hostname lookups.
17490d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes        if (inetAddress != null) {
17590d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes            BlockGuard.getThreadPolicy().onNetwork();
17690d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes        }
17790d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes        return os.sendto(fd, bytes, byteOffset, byteCount, flags, inetAddress, port);
17890d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes    }
17990d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes
18090d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes    @Override public FileDescriptor socket(int domain, int type, int protocol) throws ErrnoException {
181553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes        return tagSocket(os.socket(domain, type, protocol));
1821e8d508f2d97e19f2fc8a709330ea97e1e9f203aJeff Sharkey    }
1831e8d508f2d97e19f2fc8a709330ea97e1e9f203aJeff Sharkey
1843218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes    @Override public void socketpair(int domain, int type, int protocol, FileDescriptor fd1, FileDescriptor fd2) throws ErrnoException {
1853218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes        os.socketpair(domain, type, protocol, fd1, fd2);
1863218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes        tagSocket(fd1);
1873218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes        tagSocket(fd2);
1883218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes    }
1893218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes
19090d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes    @Override public int write(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException {
19178c7cc547101002b9f9043cf3845970719d1bda8Elliott Hughes        BlockGuard.getThreadPolicy().onWriteToDisk();
19278c7cc547101002b9f9043cf3845970719d1bda8Elliott Hughes        return os.write(fd, buffer);
19378c7cc547101002b9f9043cf3845970719d1bda8Elliott Hughes    }
19478c7cc547101002b9f9043cf3845970719d1bda8Elliott Hughes
19590d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes    @Override public int write(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException {
19678c7cc547101002b9f9043cf3845970719d1bda8Elliott Hughes        BlockGuard.getThreadPolicy().onWriteToDisk();
19778c7cc547101002b9f9043cf3845970719d1bda8Elliott Hughes        return os.write(fd, bytes, byteOffset, byteCount);
19878c7cc547101002b9f9043cf3845970719d1bda8Elliott Hughes    }
199bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes
20090d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes    @Override public int writev(FileDescriptor fd, Object[] buffers, int[] offsets, int[] byteCounts) throws ErrnoException {
201bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        BlockGuard.getThreadPolicy().onWriteToDisk();
202bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        return os.writev(fd, buffers, offsets, byteCounts);
203bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    }
20452724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes}
205