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