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