BlockGuardOs.java revision e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7
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 dalvik.system.BlockGuard;
20import java.io.FileDescriptor;
21import java.net.InetAddress;
22import java.net.InetSocketAddress;
23import java.net.SocketException;
24import java.nio.ByteBuffer;
25import static libcore.io.OsConstants.*;
26
27/**
28 * Informs BlockGuard of any activity it should be aware of.
29 */
30public class BlockGuardOs extends ForwardingOs {
31    public BlockGuardOs(Os os) {
32        super(os);
33    }
34
35    private FileDescriptor tagSocket(FileDescriptor fd) throws ErrnoException {
36        try {
37            BlockGuard.tagSocketFd(fd);
38            return fd;
39        } catch (SocketException e) {
40            throw new ErrnoException("socket", EINVAL, e);
41        }
42    }
43
44    @Override public FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException {
45        BlockGuard.getThreadPolicy().onNetwork();
46        return tagSocket(os.accept(fd, peerAddress));
47    }
48
49    @Override public void close(FileDescriptor fd) throws ErrnoException {
50        // TODO: is there a way to avoid calling getsockopt(2) on non-socket fds?
51        if (isLingerSocket(fd)) {
52            // If the fd is a socket with SO_LINGER set, we might block indefinitely.
53            // We allow non-linger sockets so that apps can close their network connections in
54            // methods like onDestroy which will run on the UI thread.
55            BlockGuard.getThreadPolicy().onNetwork();
56        }
57        os.close(fd);
58    }
59
60    private static boolean isLingerSocket(FileDescriptor fd) {
61        try {
62            StructLinger linger = Libcore.os.getsockoptLinger(fd, SOL_SOCKET, SO_LINGER);
63            return linger.isOn() && linger.l_linger > 0;
64        } catch (ErrnoException ignored) {
65            // We're called via Socket.close (which doesn't ask for us to be called), so we
66            // must not throw here, because Socket.close must not throw if asked to close an
67            // already-closed socket. Also, the passed-in FileDescriptor isn't necessarily
68            // a socket at all.
69            return false;
70        }
71    }
72
73    @Override public void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException {
74        BlockGuard.getThreadPolicy().onNetwork();
75        os.connect(fd, address, port);
76    }
77
78    @Override public void fdatasync(FileDescriptor fd) throws ErrnoException {
79        BlockGuard.getThreadPolicy().onWriteToDisk();
80        os.fdatasync(fd);
81    }
82
83    @Override public void fsync(FileDescriptor fd) throws ErrnoException {
84        BlockGuard.getThreadPolicy().onWriteToDisk();
85        os.fsync(fd);
86    }
87
88    @Override public void ftruncate(FileDescriptor fd, long length) throws ErrnoException {
89        BlockGuard.getThreadPolicy().onWriteToDisk();
90        os.ftruncate(fd, length);
91    }
92
93    @Override public FileDescriptor open(String path, int flags, int mode) throws ErrnoException {
94        BlockGuard.getThreadPolicy().onReadFromDisk();
95        if ((mode & O_ACCMODE) != O_RDONLY) {
96            BlockGuard.getThreadPolicy().onWriteToDisk();
97        }
98        return os.open(path, flags, mode);
99    }
100
101    @Override public int poll(StructPollfd[] fds, int timeoutMs) throws ErrnoException {
102        // Greater than 0 is a timeout in milliseconds and -1 means "block forever",
103        // but 0 means "poll and return immediately", which shouldn't be subject to BlockGuard.
104        if (timeoutMs != 0) {
105            BlockGuard.getThreadPolicy().onNetwork();
106        }
107        return os.poll(fds, timeoutMs);
108    }
109
110    @Override public int pread(FileDescriptor fd, ByteBuffer buffer, long offset) throws ErrnoException {
111        BlockGuard.getThreadPolicy().onReadFromDisk();
112        return os.pread(fd, buffer, offset);
113    }
114
115    @Override public int pread(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, long offset) throws ErrnoException {
116        BlockGuard.getThreadPolicy().onReadFromDisk();
117        return os.pread(fd, bytes, byteOffset, byteCount, offset);
118    }
119
120    @Override public int pwrite(FileDescriptor fd, ByteBuffer buffer, long offset) throws ErrnoException {
121        BlockGuard.getThreadPolicy().onWriteToDisk();
122        return os.pwrite(fd, buffer, offset);
123    }
124
125    @Override public int pwrite(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, long offset) throws ErrnoException {
126        BlockGuard.getThreadPolicy().onWriteToDisk();
127        return os.pwrite(fd, bytes, byteOffset, byteCount, offset);
128    }
129
130    @Override public int read(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException {
131        BlockGuard.getThreadPolicy().onReadFromDisk();
132        return os.read(fd, buffer);
133    }
134
135    @Override public int read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException {
136        BlockGuard.getThreadPolicy().onReadFromDisk();
137        return os.read(fd, bytes, byteOffset, byteCount);
138    }
139
140    @Override public int readv(FileDescriptor fd, Object[] buffers, int[] offsets, int[] byteCounts) throws ErrnoException {
141        BlockGuard.getThreadPolicy().onReadFromDisk();
142        return os.readv(fd, buffers, offsets, byteCounts);
143    }
144
145    @Override public int recvfrom(FileDescriptor fd, ByteBuffer buffer, int flags, InetSocketAddress srcAddress) throws ErrnoException {
146        BlockGuard.getThreadPolicy().onNetwork();
147        return os.recvfrom(fd, buffer, flags, srcAddress);
148    }
149
150    @Override public int recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException {
151        BlockGuard.getThreadPolicy().onNetwork();
152        return os.recvfrom(fd, bytes, byteOffset, byteCount, flags, srcAddress);
153    }
154
155    @Override public int sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port) throws ErrnoException {
156        BlockGuard.getThreadPolicy().onNetwork();
157        return os.sendto(fd, buffer, flags, inetAddress, port);
158    }
159
160    @Override public int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws ErrnoException {
161        // We permit datagrams without hostname lookups.
162        if (inetAddress != null) {
163            BlockGuard.getThreadPolicy().onNetwork();
164        }
165        return os.sendto(fd, bytes, byteOffset, byteCount, flags, inetAddress, port);
166    }
167
168    @Override public FileDescriptor socket(int domain, int type, int protocol) throws ErrnoException {
169        return tagSocket(os.socket(domain, type, protocol));
170    }
171
172    @Override public int write(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException {
173        BlockGuard.getThreadPolicy().onWriteToDisk();
174        return os.write(fd, buffer);
175    }
176
177    @Override public int write(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException {
178        BlockGuard.getThreadPolicy().onWriteToDisk();
179        return os.write(fd, bytes, byteOffset, byteCount);
180    }
181
182    @Override public int writev(FileDescriptor fd, Object[] buffers, int[] offsets, int[] byteCounts) throws ErrnoException {
183        BlockGuard.getThreadPolicy().onWriteToDisk();
184        return os.writev(fd, buffers, offsets, byteCounts);
185    }
186}
187