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