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