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.libcore.io;
     18 
     19 import android.system.ErrnoException;
     20 import android.system.Int64Ref;
     21 import android.system.NetlinkSocketAddress;
     22 import android.system.OsConstants;
     23 import android.system.PacketSocketAddress;
     24 import android.system.StructRlimit;
     25 import android.system.StructStat;
     26 import android.system.StructTimeval;
     27 import android.system.StructUcred;
     28 import android.system.UnixSocketAddress;
     29 
     30 import java.io.File;
     31 import java.io.FileDescriptor;
     32 import java.io.FileInputStream;
     33 import java.io.FileOutputStream;
     34 import java.io.FileWriter;
     35 import java.io.IOException;
     36 import java.net.DatagramPacket;
     37 import java.net.DatagramSocket;
     38 import java.net.Inet4Address;
     39 import java.net.Inet6Address;
     40 import java.net.InetAddress;
     41 import java.net.InetSocketAddress;
     42 import java.net.NetworkInterface;
     43 import java.net.ServerSocket;
     44 import java.net.SocketOptions;
     45 import java.nio.ByteBuffer;
     46 import java.nio.charset.StandardCharsets;
     47 import java.nio.file.Files;
     48 import java.util.Arrays;
     49 import java.util.Collections;
     50 import java.util.List;
     51 import java.util.Locale;
     52 import java.util.concurrent.atomic.AtomicReference;
     53 import junit.framework.TestCase;
     54 
     55 import libcore.io.IoBridge;
     56 import libcore.io.IoUtils;
     57 import libcore.io.Libcore;
     58 
     59 import static android.system.OsConstants.*;
     60 import static libcore.libcore.io.OsTest.SendFileImpl.ANDROID_SYSTEM_OS_INT64_REF;
     61 import static libcore.libcore.io.OsTest.SendFileImpl.LIBCORE_OS;
     62 
     63 public class OsTest extends TestCase {
     64   public void testIsSocket() throws Exception {
     65     File f = new File("/dev/null");
     66     FileInputStream fis = new FileInputStream(f);
     67     assertFalse(S_ISSOCK(Libcore.os.fstat(fis.getFD()).st_mode));
     68     fis.close();
     69 
     70     ServerSocket s = new ServerSocket();
     71     assertTrue(S_ISSOCK(Libcore.os.fstat(s.getImpl().getFD$()).st_mode));
     72     s.close();
     73   }
     74 
     75   public void testFcntlInt() throws Exception {
     76     File f = File.createTempFile("OsTest", "tst");
     77     FileInputStream fis = null;
     78     try {
     79       fis = new FileInputStream(f);
     80       Libcore.os.fcntlInt(fis.getFD(), F_SETFD, FD_CLOEXEC);
     81       int flags = Libcore.os.fcntlVoid(fis.getFD(), F_GETFD);
     82       assertTrue((flags & FD_CLOEXEC) != 0);
     83     } finally {
     84       IoUtils.closeQuietly(fis);
     85       f.delete();
     86     }
     87   }
     88 
     89   public void testUnixDomainSockets_in_file_system() throws Exception {
     90     String path = System.getProperty("java.io.tmpdir") + "/test_unix_socket";
     91     new File(path).delete();
     92     checkUnixDomainSocket(UnixSocketAddress.createFileSystem(path), false);
     93   }
     94 
     95   public void testUnixDomainSocket_abstract_name() throws Exception {
     96     // Linux treats a sun_path starting with a NUL byte as an abstract name. See unix(7).
     97     checkUnixDomainSocket(UnixSocketAddress.createAbstract("/abstract_name_unix_socket"), true);
     98   }
     99 
    100   public void testUnixDomainSocket_unnamed() throws Exception {
    101     final FileDescriptor fd = Libcore.os.socket(AF_UNIX, SOCK_STREAM, 0);
    102     // unix(7) says an unbound socket is unnamed.
    103     checkNoSockName(fd);
    104     Libcore.os.close(fd);
    105   }
    106 
    107   private void checkUnixDomainSocket(final UnixSocketAddress address, final boolean isAbstract)
    108       throws Exception {
    109     final FileDescriptor serverFd = Libcore.os.socket(AF_UNIX, SOCK_STREAM, 0);
    110     Libcore.os.bind(serverFd, address);
    111     Libcore.os.listen(serverFd, 5);
    112 
    113     checkSockName(serverFd, isAbstract, address);
    114 
    115     Thread server = new Thread(new Runnable() {
    116       public void run() {
    117         try {
    118           UnixSocketAddress peerAddress = UnixSocketAddress.createUnnamed();
    119           FileDescriptor clientFd = Libcore.os.accept(serverFd, peerAddress);
    120           checkSockName(clientFd, isAbstract, address);
    121           checkNoName(peerAddress);
    122 
    123           checkNoPeerName(clientFd);
    124 
    125           StructUcred credentials = Libcore.os.getsockoptUcred(clientFd, SOL_SOCKET, SO_PEERCRED);
    126           assertEquals(Libcore.os.getpid(), credentials.pid);
    127           assertEquals(Libcore.os.getuid(), credentials.uid);
    128           assertEquals(Libcore.os.getgid(), credentials.gid);
    129 
    130           byte[] request = new byte[256];
    131           Libcore.os.read(clientFd, request, 0, request.length);
    132 
    133           String s = new String(request, "UTF-8");
    134           byte[] response = s.toUpperCase(Locale.ROOT).getBytes("UTF-8");
    135           Libcore.os.write(clientFd, response, 0, response.length);
    136 
    137           Libcore.os.close(clientFd);
    138         } catch (Exception ex) {
    139           throw new RuntimeException(ex);
    140         }
    141       }
    142     });
    143     server.start();
    144 
    145     FileDescriptor clientFd = Libcore.os.socket(AF_UNIX, SOCK_STREAM, 0);
    146 
    147     Libcore.os.connect(clientFd, address);
    148     checkNoSockName(clientFd);
    149 
    150     String string = "hello, world!";
    151 
    152     byte[] request = string.getBytes("UTF-8");
    153     assertEquals(request.length, Libcore.os.write(clientFd, request, 0, request.length));
    154 
    155     byte[] response = new byte[request.length];
    156     assertEquals(response.length, Libcore.os.read(clientFd, response, 0, response.length));
    157 
    158     assertEquals(string.toUpperCase(Locale.ROOT), new String(response, "UTF-8"));
    159 
    160     Libcore.os.close(clientFd);
    161   }
    162 
    163   private static void checkSockName(FileDescriptor fd, boolean isAbstract,
    164       UnixSocketAddress address) throws Exception {
    165     UnixSocketAddress isa = (UnixSocketAddress) Libcore.os.getsockname(fd);
    166     assertEquals(address, isa);
    167     if (isAbstract) {
    168       assertEquals(0, isa.getSunPath()[0]);
    169     }
    170   }
    171 
    172   private void checkNoName(UnixSocketAddress usa) {
    173     assertEquals(0, usa.getSunPath().length);
    174   }
    175 
    176   private void checkNoPeerName(FileDescriptor fd) throws Exception {
    177     checkNoName((UnixSocketAddress) Libcore.os.getpeername(fd));
    178   }
    179 
    180   private void checkNoSockName(FileDescriptor fd) throws Exception {
    181     checkNoName((UnixSocketAddress) Libcore.os.getsockname(fd));
    182   }
    183 
    184   public void test_strsignal() throws Exception {
    185     assertEquals("Killed", Libcore.os.strsignal(9));
    186     assertEquals("Unknown signal -1", Libcore.os.strsignal(-1));
    187   }
    188 
    189   public void test_byteBufferPositions_write_pwrite() throws Exception {
    190     FileOutputStream fos = new FileOutputStream(new File("/dev/null"));
    191     FileDescriptor fd = fos.getFD();
    192     final byte[] contents = new String("goodbye, cruel world").getBytes(StandardCharsets.US_ASCII);
    193     ByteBuffer byteBuffer = ByteBuffer.wrap(contents);
    194 
    195     byteBuffer.position(0);
    196     int written = Libcore.os.write(fd, byteBuffer);
    197     assertTrue(written > 0);
    198     assertEquals(written, byteBuffer.position());
    199 
    200     byteBuffer.position(4);
    201     written = Libcore.os.write(fd, byteBuffer);
    202     assertTrue(written > 0);
    203     assertEquals(written + 4, byteBuffer.position());
    204 
    205     byteBuffer.position(0);
    206     written = Libcore.os.pwrite(fd, byteBuffer, 64 /* offset */);
    207     assertTrue(written > 0);
    208     assertEquals(written, byteBuffer.position());
    209 
    210     byteBuffer.position(4);
    211     written = Libcore.os.pwrite(fd, byteBuffer, 64 /* offset */);
    212     assertTrue(written > 0);
    213     assertEquals(written + 4, byteBuffer.position());
    214 
    215     fos.close();
    216   }
    217 
    218   public void test_byteBufferPositions_read_pread() throws Exception {
    219     FileInputStream fis = new FileInputStream(new File("/dev/zero"));
    220     FileDescriptor fd = fis.getFD();
    221     ByteBuffer byteBuffer = ByteBuffer.allocate(64);
    222 
    223     byteBuffer.position(0);
    224     int read = Libcore.os.read(fd, byteBuffer);
    225     assertTrue(read > 0);
    226     assertEquals(read, byteBuffer.position());
    227 
    228     byteBuffer.position(4);
    229     read = Libcore.os.read(fd, byteBuffer);
    230     assertTrue(read > 0);
    231     assertEquals(read + 4, byteBuffer.position());
    232 
    233     byteBuffer.position(0);
    234     read = Libcore.os.pread(fd, byteBuffer, 64 /* offset */);
    235     assertTrue(read > 0);
    236     assertEquals(read, byteBuffer.position());
    237 
    238     byteBuffer.position(4);
    239     read = Libcore.os.pread(fd, byteBuffer, 64 /* offset */);
    240     assertTrue(read > 0);
    241     assertEquals(read + 4, byteBuffer.position());
    242 
    243     fis.close();
    244   }
    245 
    246   static void checkByteBufferPositions_sendto_recvfrom(
    247       int family, InetAddress loopback) throws Exception {
    248     final FileDescriptor serverFd = Libcore.os.socket(family, SOCK_STREAM, 0);
    249     Libcore.os.bind(serverFd, loopback, 0);
    250     Libcore.os.listen(serverFd, 5);
    251 
    252     InetSocketAddress address = (InetSocketAddress) Libcore.os.getsockname(serverFd);
    253 
    254     final Thread server = new Thread(new Runnable() {
    255       public void run() {
    256         try {
    257           InetSocketAddress peerAddress = new InetSocketAddress();
    258           FileDescriptor clientFd = Libcore.os.accept(serverFd, peerAddress);
    259 
    260           // Attempt to receive a maximum of 24 bytes from the client, and then
    261           // close the connection.
    262           ByteBuffer buffer = ByteBuffer.allocate(16);
    263           int received = Libcore.os.recvfrom(clientFd, buffer, 0, null);
    264           assertTrue(received > 0);
    265           assertEquals(received, buffer.position());
    266 
    267           ByteBuffer buffer2 = ByteBuffer.allocate(16);
    268           buffer2.position(8);
    269           received = Libcore.os.recvfrom(clientFd, buffer2, 0, null);
    270           assertTrue(received > 0);
    271           assertEquals(received + 8, buffer.position());
    272 
    273           Libcore.os.close(clientFd);
    274         } catch (Exception ex) {
    275           throw new RuntimeException(ex);
    276         }
    277       }
    278     });
    279 
    280     server.start();
    281 
    282     FileDescriptor clientFd = Libcore.os.socket(family, SOCK_STREAM, 0);
    283     Libcore.os.connect(clientFd, address.getAddress(), address.getPort());
    284 
    285     final byte[] bytes = "good bye, cruel black hole with fancy distortion"
    286         .getBytes(StandardCharsets.US_ASCII);
    287     assertTrue(bytes.length > 24);
    288 
    289     ByteBuffer input = ByteBuffer.wrap(bytes);
    290     input.position(0);
    291     input.limit(16);
    292 
    293     int sent = Libcore.os.sendto(clientFd, input, 0, address.getAddress(), address.getPort());
    294     assertTrue(sent > 0);
    295     assertEquals(sent, input.position());
    296 
    297     input.position(16);
    298     input.limit(24);
    299     sent = Libcore.os.sendto(clientFd, input, 0, address.getAddress(), address.getPort());
    300     assertTrue(sent > 0);
    301     assertEquals(sent + 16, input.position());
    302 
    303     Libcore.os.close(clientFd);
    304   }
    305 
    306   public void test_NetlinkSocket() throws Exception {
    307     FileDescriptor nlSocket = Libcore.os.socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
    308     Libcore.os.bind(nlSocket, new NetlinkSocketAddress());
    309     NetlinkSocketAddress address = (NetlinkSocketAddress) Libcore.os.getsockname(nlSocket);
    310     assertTrue(address.getPortId() > 0);
    311     assertEquals(0, address.getGroupsMask());
    312 
    313     NetlinkSocketAddress nlKernel = new NetlinkSocketAddress();
    314     Libcore.os.connect(nlSocket, nlKernel);
    315     NetlinkSocketAddress nlPeer = (NetlinkSocketAddress) Libcore.os.getpeername(nlSocket);
    316     assertEquals(0, nlPeer.getPortId());
    317     assertEquals(0, nlPeer.getGroupsMask());
    318     Libcore.os.close(nlSocket);
    319   }
    320 
    321   public void test_PacketSocketAddress() throws Exception {
    322     NetworkInterface lo = NetworkInterface.getByName("lo");
    323     FileDescriptor fd = Libcore.os.socket(AF_PACKET, SOCK_DGRAM, ETH_P_IPV6);
    324     PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IPV6, lo.getIndex());
    325     Libcore.os.bind(fd, addr);
    326 
    327     PacketSocketAddress bound = (PacketSocketAddress) Libcore.os.getsockname(fd);
    328     assertEquals((short) ETH_P_IPV6, bound.sll_protocol);  // ETH_P_IPV6 is an int.
    329     assertEquals(lo.getIndex(), bound.sll_ifindex);
    330     assertEquals(ARPHRD_LOOPBACK, bound.sll_hatype);
    331     assertEquals(0, bound.sll_pkttype);
    332 
    333     // The loopback address is ETH_ALEN bytes long and is all zeros.
    334     // http://lxr.free-electrons.com/source/drivers/net/loopback.c?v=3.10#L167
    335     assertEquals(6, bound.sll_addr.length);
    336     for (int i = 0; i < 6; i++) {
    337       assertEquals(0, bound.sll_addr[i]);
    338     }
    339   }
    340 
    341   public void test_byteBufferPositions_sendto_recvfrom_af_inet() throws Exception {
    342     checkByteBufferPositions_sendto_recvfrom(AF_INET, InetAddress.getByName("127.0.0.1"));
    343   }
    344 
    345   public void test_byteBufferPositions_sendto_recvfrom_af_inet6() throws Exception {
    346     checkByteBufferPositions_sendto_recvfrom(AF_INET6, InetAddress.getByName("::1"));
    347   }
    348 
    349   private void checkSendToSocketAddress(int family, InetAddress loopback) throws Exception {
    350     FileDescriptor recvFd = Libcore.os.socket(family, SOCK_DGRAM, 0);
    351     Libcore.os.bind(recvFd, loopback, 0);
    352     StructTimeval tv = StructTimeval.fromMillis(20);
    353     Libcore.os.setsockoptTimeval(recvFd, SOL_SOCKET, SO_RCVTIMEO, tv);
    354 
    355     InetSocketAddress to = ((InetSocketAddress) Libcore.os.getsockname(recvFd));
    356     FileDescriptor sendFd = Libcore.os.socket(family, SOCK_DGRAM, 0);
    357     byte[] msg = ("Hello, I'm going to a socket address: " + to.toString()).getBytes("UTF-8");
    358     int len = msg.length;
    359 
    360     assertEquals(len, Libcore.os.sendto(sendFd, msg, 0, len, 0, to));
    361     byte[] received = new byte[msg.length + 42];
    362     InetSocketAddress from = new InetSocketAddress();
    363     assertEquals(len, Libcore.os.recvfrom(recvFd, received, 0, received.length, 0, from));
    364     assertEquals(loopback, from.getAddress());
    365   }
    366 
    367   public void test_sendtoSocketAddress_af_inet() throws Exception {
    368     checkSendToSocketAddress(AF_INET, InetAddress.getByName("127.0.0.1"));
    369   }
    370 
    371   public void test_sendtoSocketAddress_af_inet6() throws Exception {
    372     checkSendToSocketAddress(AF_INET6, InetAddress.getByName("::1"));
    373   }
    374 
    375   public void test_socketFamilies() throws Exception {
    376     FileDescriptor fd = Libcore.os.socket(AF_INET6, SOCK_STREAM, 0);
    377     Libcore.os.bind(fd, InetAddress.getByName("::"), 0);
    378     InetSocketAddress localSocketAddress = (InetSocketAddress) Libcore.os.getsockname(fd);
    379     assertEquals(Inet6Address.ANY, localSocketAddress.getAddress());
    380 
    381     fd = Libcore.os.socket(AF_INET6, SOCK_STREAM, 0);
    382     Libcore.os.bind(fd, InetAddress.getByName("0.0.0.0"), 0);
    383     localSocketAddress = (InetSocketAddress) Libcore.os.getsockname(fd);
    384     assertEquals(Inet6Address.ANY, localSocketAddress.getAddress());
    385 
    386     fd = Libcore.os.socket(AF_INET, SOCK_STREAM, 0);
    387     Libcore.os.bind(fd, InetAddress.getByName("0.0.0.0"), 0);
    388     localSocketAddress = (InetSocketAddress) Libcore.os.getsockname(fd);
    389     assertEquals(Inet4Address.ANY, localSocketAddress.getAddress());
    390     try {
    391       Libcore.os.bind(fd, InetAddress.getByName("::"), 0);
    392       fail("Expected ErrnoException binding IPv4 socket to ::");
    393     } catch (ErrnoException expected) {
    394       assertEquals("Expected EAFNOSUPPORT binding IPv4 socket to ::", EAFNOSUPPORT, expected.errno);
    395     }
    396   }
    397 
    398   private static void assertArrayEquals(byte[] expected, byte[] actual) {
    399     assertTrue("Expected=" + Arrays.toString(expected) + ", actual=" + Arrays.toString(actual),
    400         Arrays.equals(expected, actual));
    401   }
    402 
    403   private static void checkSocketPing(FileDescriptor fd, InetAddress to, byte[] packet,
    404       byte type, byte responseType, boolean useSendto) throws Exception {
    405     int len = packet.length;
    406     packet[0] = type;
    407     if (useSendto) {
    408       assertEquals(len, Libcore.os.sendto(fd, packet, 0, len, 0, to, 0));
    409     } else {
    410       Libcore.os.connect(fd, to, 0);
    411       assertEquals(len, Libcore.os.sendto(fd, packet, 0, len, 0, null, 0));
    412     }
    413 
    414     int icmpId = ((InetSocketAddress) Libcore.os.getsockname(fd)).getPort();
    415     byte[] received = new byte[4096];
    416     InetSocketAddress srcAddress = new InetSocketAddress();
    417     assertEquals(len, Libcore.os.recvfrom(fd, received, 0, received.length, 0, srcAddress));
    418     assertEquals(to, srcAddress.getAddress());
    419     assertEquals(responseType, received[0]);
    420     assertEquals(received[4], (byte) (icmpId >> 8));
    421     assertEquals(received[5], (byte) (icmpId & 0xff));
    422 
    423     received = Arrays.copyOf(received, len);
    424     received[0] = (byte) type;
    425     received[2] = received[3] = 0;  // Checksum.
    426     received[4] = received[5] = 0;  // ICMP ID.
    427     assertArrayEquals(packet, received);
    428   }
    429 
    430   public void test_socketPing() throws Exception {
    431     final byte ICMP_ECHO = 8, ICMP_ECHOREPLY = 0;
    432     final byte ICMPV6_ECHO_REQUEST = (byte) 128, ICMPV6_ECHO_REPLY = (byte) 129;
    433     final byte[] packet = ("\000\000\000\000" +  // ICMP type, code.
    434         "\000\000\000\003" +  // ICMP ID (== port), sequence number.
    435         "Hello myself").getBytes(StandardCharsets.US_ASCII);
    436 
    437     FileDescriptor fd = Libcore.os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
    438     InetAddress ipv6Loopback = InetAddress.getByName("::1");
    439     checkSocketPing(fd, ipv6Loopback, packet, ICMPV6_ECHO_REQUEST, ICMPV6_ECHO_REPLY, true);
    440     checkSocketPing(fd, ipv6Loopback, packet, ICMPV6_ECHO_REQUEST, ICMPV6_ECHO_REPLY, false);
    441 
    442     fd = Libcore.os.socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
    443     InetAddress ipv4Loopback = InetAddress.getByName("127.0.0.1");
    444     checkSocketPing(fd, ipv4Loopback, packet, ICMP_ECHO, ICMP_ECHOREPLY, true);
    445     checkSocketPing(fd, ipv4Loopback, packet, ICMP_ECHO, ICMP_ECHOREPLY, false);
    446   }
    447 
    448   public void test_Ipv4Fallback() throws Exception {
    449     // This number of iterations gives a ~60% chance of creating the conditions that caused
    450     // http://b/23088314 without making test times too long. On a hammerhead running MRZ37C using
    451     // vogar, this test takes about 4s.
    452     final int ITERATIONS = 10000;
    453     for (int i = 0; i < ITERATIONS; i++) {
    454       FileDescriptor mUdpSock = Libcore.os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    455       try {
    456           Libcore.os.bind(mUdpSock, Inet4Address.ANY, 0);
    457       } catch(ErrnoException e) {
    458           fail("ErrnoException after " + i + " iterations: " + e);
    459       } finally {
    460           Libcore.os.close(mUdpSock);
    461       }
    462     }
    463   }
    464 
    465   public void test_unlink() throws Exception {
    466     File f = File.createTempFile("OsTest", "tst");
    467     assertTrue(f.exists());
    468     Libcore.os.unlink(f.getAbsolutePath());
    469     assertFalse(f.exists());
    470 
    471     try {
    472       Libcore.os.unlink(f.getAbsolutePath());
    473       fail();
    474     } catch (ErrnoException e) {
    475       assertEquals(OsConstants.ENOENT, e.errno);
    476     }
    477   }
    478 
    479   // b/27294715
    480   public void test_recvfrom_concurrentShutdown() throws Exception {
    481       final FileDescriptor serverFd = Libcore.os.socket(AF_INET, SOCK_DGRAM, 0);
    482       Libcore.os.bind(serverFd, InetAddress.getByName("127.0.0.1"), 0);
    483       // Set 4s timeout
    484       IoBridge.setSocketOption(serverFd, SocketOptions.SO_TIMEOUT, new Integer(4000));
    485 
    486       final AtomicReference<Exception> killerThreadException = new AtomicReference<Exception>(null);
    487       final Thread killer = new Thread(new Runnable() {
    488           public void run() {
    489               try {
    490                   Thread.sleep(2000);
    491                   try {
    492                       Libcore.os.shutdown(serverFd, SHUT_RDWR);
    493                   } catch (ErrnoException expected) {
    494                       if (OsConstants.ENOTCONN != expected.errno) {
    495                           killerThreadException.set(expected);
    496                       }
    497                   }
    498               } catch (Exception ex) {
    499                   killerThreadException.set(ex);
    500               }
    501           }
    502       });
    503       killer.start();
    504 
    505       ByteBuffer buffer = ByteBuffer.allocate(16);
    506       InetSocketAddress srcAddress = new InetSocketAddress();
    507       int received = Libcore.os.recvfrom(serverFd, buffer, 0, srcAddress);
    508       assertTrue(received == 0);
    509       Libcore.os.close(serverFd);
    510 
    511       killer.join();
    512       assertNull(killerThreadException.get());
    513   }
    514 
    515   public void test_xattr() throws Exception {
    516     final String NAME_TEST = "user.meow";
    517 
    518     final byte[] VALUE_CAKE = "cake cake cake".getBytes(StandardCharsets.UTF_8);
    519     final byte[] VALUE_PIE = "pie".getBytes(StandardCharsets.UTF_8);
    520 
    521     File file = File.createTempFile("xattr", "test");
    522     String path = file.getAbsolutePath();
    523 
    524     try {
    525       try {
    526         Libcore.os.getxattr(path, NAME_TEST);
    527         fail("Expected ENODATA");
    528       } catch (ErrnoException e) {
    529         assertEquals(OsConstants.ENODATA, e.errno);
    530       }
    531       assertFalse(Arrays.asList(Libcore.os.listxattr(path)).contains(NAME_TEST));
    532 
    533       Libcore.os.setxattr(path, NAME_TEST, VALUE_CAKE, OsConstants.XATTR_CREATE);
    534       byte[] xattr_create = Libcore.os.getxattr(path, NAME_TEST);
    535       assertTrue(Arrays.asList(Libcore.os.listxattr(path)).contains(NAME_TEST));
    536       assertEquals(VALUE_CAKE.length, xattr_create.length);
    537       assertStartsWith(VALUE_CAKE, xattr_create);
    538 
    539       try {
    540         Libcore.os.setxattr(path, NAME_TEST, VALUE_PIE, OsConstants.XATTR_CREATE);
    541         fail("Expected EEXIST");
    542       } catch (ErrnoException e) {
    543         assertEquals(OsConstants.EEXIST, e.errno);
    544       }
    545 
    546       Libcore.os.setxattr(path, NAME_TEST, VALUE_PIE, OsConstants.XATTR_REPLACE);
    547       byte[] xattr_replace = Libcore.os.getxattr(path, NAME_TEST);
    548       assertTrue(Arrays.asList(Libcore.os.listxattr(path)).contains(NAME_TEST));
    549       assertEquals(VALUE_PIE.length, xattr_replace.length);
    550       assertStartsWith(VALUE_PIE, xattr_replace);
    551 
    552       Libcore.os.removexattr(path, NAME_TEST);
    553       try {
    554         Libcore.os.getxattr(path, NAME_TEST);
    555         fail("Expected ENODATA");
    556       } catch (ErrnoException e) {
    557         assertEquals(OsConstants.ENODATA, e.errno);
    558       }
    559       assertFalse(Arrays.asList(Libcore.os.listxattr(path)).contains(NAME_TEST));
    560 
    561     } finally {
    562       file.delete();
    563     }
    564   }
    565 
    566   public void test_xattr_NPE() throws Exception {
    567     File file = File.createTempFile("xattr", "test");
    568     final String path = file.getAbsolutePath();
    569     final String NAME_TEST = "user.meow";
    570     final byte[] VALUE_CAKE = "cake cake cake".getBytes(StandardCharsets.UTF_8);
    571 
    572     // getxattr
    573     try {
    574       Libcore.os.getxattr(null, NAME_TEST);
    575       fail();
    576     } catch (NullPointerException expected) { }
    577     try {
    578       Libcore.os.getxattr(path, null);
    579       fail();
    580     } catch (NullPointerException expected) { }
    581 
    582     // listxattr
    583     try {
    584       Libcore.os.listxattr(null);
    585       fail();
    586     } catch (NullPointerException expected) { }
    587 
    588     // removexattr
    589     try {
    590       Libcore.os.removexattr(null, NAME_TEST);
    591       fail();
    592     } catch (NullPointerException expected) { }
    593     try {
    594       Libcore.os.removexattr(path, null);
    595       fail();
    596     } catch (NullPointerException expected) { }
    597 
    598     // setxattr
    599     try {
    600       Libcore.os.setxattr(null, NAME_TEST, VALUE_CAKE, OsConstants.XATTR_CREATE);
    601       fail();
    602     } catch (NullPointerException expected) { }
    603     try {
    604       Libcore.os.setxattr(path, null, VALUE_CAKE, OsConstants.XATTR_CREATE);
    605       fail();
    606     } catch (NullPointerException expected) { }
    607     try {
    608       Libcore.os.setxattr(path, NAME_TEST, null, OsConstants.XATTR_CREATE);
    609       fail();
    610     } catch (NullPointerException expected) { }
    611   }
    612 
    613   public void test_xattr_Errno() throws Exception {
    614     final String NAME_TEST = "user.meow";
    615     final byte[] VALUE_CAKE = "cake cake cake".getBytes(StandardCharsets.UTF_8);
    616 
    617     // ENOENT, No such file or directory.
    618     try {
    619       Libcore.os.getxattr("", NAME_TEST);
    620       fail();
    621     } catch (ErrnoException e) {
    622       assertEquals(ENOENT, e.errno);
    623     }
    624     try {
    625       Libcore.os.listxattr("");
    626       fail();
    627     } catch (ErrnoException e) {
    628       assertEquals(ENOENT, e.errno);
    629     }
    630     try {
    631       Libcore.os.removexattr("", NAME_TEST);
    632       fail();
    633     } catch (ErrnoException e) {
    634       assertEquals(ENOENT, e.errno);
    635     }
    636     try {
    637       Libcore.os.setxattr("", NAME_TEST, VALUE_CAKE, OsConstants.XATTR_CREATE);
    638       fail();
    639     } catch (ErrnoException e) {
    640       assertEquals(ENOENT, e.errno);
    641     }
    642 
    643     // ENOTSUP, Extended attributes are not supported by the filesystem, or are disabled.
    644     // Since kernel version 4.9 (or some other version after 4.4), *xattr() methods
    645     // may set errno to EACCESS instead. This behavior change is likely related to
    646     // https://patchwork.kernel.org/patch/9294421/ which reimplemented getxattr, setxattr,
    647     // and removexattr on top of generic handlers.
    648     final String path = "/proc/self/stat";
    649     try {
    650       Libcore.os.setxattr(path, NAME_TEST, VALUE_CAKE, OsConstants.XATTR_CREATE);
    651       fail();
    652     } catch (ErrnoException e) {
    653       assertTrue("Unexpected errno: " + e.errno, e.errno == ENOTSUP || e.errno == EACCES);
    654     }
    655     try {
    656       Libcore.os.getxattr(path, NAME_TEST);
    657       fail();
    658     } catch (ErrnoException e) {
    659       assertEquals(ENOTSUP, e.errno);
    660     }
    661     try {
    662       // Linux listxattr does not set errno.
    663       Libcore.os.listxattr(path);
    664     } catch (ErrnoException e) {
    665       fail();
    666     }
    667     try {
    668       Libcore.os.removexattr(path, NAME_TEST);
    669       fail();
    670     } catch (ErrnoException e) {
    671       assertTrue("Unexpected errno: " + e.errno, e.errno == ENOTSUP || e.errno == EACCES);
    672     }
    673   }
    674 
    675   public void test_realpath() throws Exception {
    676       File tmpDir = new File(System.getProperty("java.io.tmpdir"));
    677       // This is a chicken and egg problem. We have no way of knowing whether
    678       // the temporary directory or one of its path elements were symlinked, so
    679       // we'll need this call to realpath.
    680       String canonicalTmpDir = Libcore.os.realpath(tmpDir.getAbsolutePath());
    681 
    682       // Test that "." and ".." are resolved correctly.
    683       assertEquals(canonicalTmpDir,
    684           Libcore.os.realpath(canonicalTmpDir + "/./../" + tmpDir.getName()));
    685 
    686       // Test that symlinks are resolved correctly.
    687       File target = new File(tmpDir, "target");
    688       File link = new File(tmpDir, "link");
    689       try {
    690           assertTrue(target.createNewFile());
    691           Libcore.os.symlink(target.getAbsolutePath(), link.getAbsolutePath());
    692 
    693           assertEquals(canonicalTmpDir + "/target",
    694               Libcore.os.realpath(canonicalTmpDir + "/link"));
    695       } finally {
    696           boolean deletedTarget = target.delete();
    697           boolean deletedLink = link.delete();
    698           // Asserting this here to provide a definitive reason for
    699           // a subsequent failure on the same run.
    700           assertTrue("deletedTarget = " + deletedTarget + ", deletedLink =" + deletedLink,
    701               deletedTarget && deletedLink);
    702       }
    703   }
    704 
    705   /**
    706    * Tests that TCP_USER_TIMEOUT can be set on a TCP socket, but doesn't test
    707    * that it behaves as expected.
    708    */
    709   public void test_socket_tcpUserTimeout_setAndGet() throws Exception {
    710     final FileDescriptor fd = Libcore.os.socket(AF_INET, SOCK_STREAM, 0);
    711     try {
    712       int v = Libcore.os.getsockoptInt(fd, OsConstants.IPPROTO_TCP, OsConstants.TCP_USER_TIMEOUT);
    713       assertEquals(0, v); // system default value
    714       int newValue = 3000;
    715       Libcore.os.setsockoptInt(fd, OsConstants.IPPROTO_TCP, OsConstants.TCP_USER_TIMEOUT,
    716               newValue);
    717       assertEquals(newValue, Libcore.os.getsockoptInt(fd, OsConstants.IPPROTO_TCP,
    718               OsConstants.TCP_USER_TIMEOUT));
    719       // No need to reset the value to 0, since we're throwing the socket away
    720     } finally {
    721       Libcore.os.close(fd);
    722     }
    723   }
    724 
    725   public void test_socket_tcpUserTimeout_doesNotWorkOnDatagramSocket() throws Exception {
    726     final FileDescriptor fd = Libcore.os.socket(AF_INET, SOCK_DGRAM, 0);
    727     try {
    728       Libcore.os.setsockoptInt(fd, OsConstants.IPPROTO_TCP, OsConstants.TCP_USER_TIMEOUT,
    729               3000);
    730       fail("datagram (connectionless) sockets shouldn't support TCP_USER_TIMEOUT");
    731     } catch (ErrnoException expected) {
    732       // expected
    733     } finally {
    734       Libcore.os.close(fd);
    735     }
    736   }
    737 
    738   public void test_if_nametoindex_if_indextoname() throws Exception {
    739     List<NetworkInterface> nis = Collections.list(NetworkInterface.getNetworkInterfaces());
    740 
    741     assertTrue(nis.size() > 0);
    742     for (NetworkInterface ni : nis) {
    743       int index = ni.getIndex();
    744       String name = ni.getName();
    745       assertEquals(index, Libcore.os.if_nametoindex(name));
    746       assertTrue(Libcore.os.if_indextoname(index).equals(name));
    747     }
    748 
    749     assertEquals(0, Libcore.os.if_nametoindex("this-interface-does-not-exist"));
    750     assertEquals(null, Libcore.os.if_indextoname(-1000));
    751 
    752     try {
    753       Libcore.os.if_nametoindex(null);
    754       fail();
    755     } catch (NullPointerException expected) { }
    756   }
    757 
    758   private static void assertStartsWith(byte[] expectedContents, byte[] container) {
    759     for (int i = 0; i < expectedContents.length; i++) {
    760       if (expectedContents[i] != container[i]) {
    761         fail("Expected " + Arrays.toString(expectedContents) + " but found "
    762             + Arrays.toString(expectedContents));
    763       }
    764     }
    765   }
    766 
    767   public void test_readlink() throws Exception {
    768     File path = new File(IoUtils.createTemporaryDirectory("test_readlink"), "symlink");
    769 
    770     // ext2 and ext4 have PAGE_SIZE limits on symlink targets.
    771     // If file encryption is enabled, there's extra overhead to store the
    772     // size of the encrypted symlink target. There's also an off-by-one
    773     // in current kernels (and marlin/sailfish where we're seeing this
    774     // failure are still on 3.18, far from current). Given that we don't
    775     // really care here, just use 2048 instead. http://b/33306057.
    776     int size = 2048;
    777     String xs = "";
    778     for (int i = 0; i < size - 1; ++i) xs += "x";
    779 
    780     Libcore.os.symlink(xs, path.getPath());
    781 
    782     assertEquals(xs, Libcore.os.readlink(path.getPath()));
    783   }
    784 
    785   // Address should be correctly set for empty packets. http://b/33481605
    786   public void test_recvfrom_EmptyPacket() throws Exception {
    787     try (DatagramSocket ds = new DatagramSocket();
    788          DatagramSocket srcSock = new DatagramSocket()) {
    789       srcSock.send(new DatagramPacket(new byte[0], 0, ds.getLocalSocketAddress()));
    790 
    791       byte[] recvBuf = new byte[16];
    792       InetSocketAddress address = new InetSocketAddress();
    793       int recvCount =
    794           android.system.Os.recvfrom(ds.getFileDescriptor$(), recvBuf, 0, 16, 0, address);
    795       assertEquals(0, recvCount);
    796       assertTrue(address.getAddress().isLoopbackAddress());
    797       assertEquals(srcSock.getLocalPort(), address.getPort());
    798     }
    799   }
    800 
    801   public void test_fstat_times() throws Exception {
    802     File file = File.createTempFile("OsTest", "fstattest");
    803     FileOutputStream fos = new FileOutputStream(file);
    804     StructStat structStat1 = Libcore.os.fstat(fos.getFD());
    805     assertEquals(structStat1.st_mtim.tv_sec, structStat1.st_mtime);
    806     assertEquals(structStat1.st_ctim.tv_sec, structStat1.st_ctime);
    807     assertEquals(structStat1.st_atim.tv_sec, structStat1.st_atime);
    808     Thread.sleep(100);
    809     fos.write(new byte[]{1,2,3});
    810     fos.flush();
    811     StructStat structStat2 = Libcore.os.fstat(fos.getFD());
    812     fos.close();
    813 
    814     assertEquals(-1, structStat1.st_mtim.compareTo(structStat2.st_mtim));
    815     assertEquals(-1, structStat1.st_ctim.compareTo(structStat2.st_ctim));
    816     assertEquals(0, structStat1.st_atim.compareTo(structStat2.st_atim));
    817   }
    818 
    819   public void test_getrlimit() throws Exception {
    820     StructRlimit rlimit = Libcore.os.getrlimit(OsConstants.RLIMIT_NOFILE);
    821     // We can't really make any assertions about these values since they might vary from
    822     // device to device and even process to process. We do know that they will be greater
    823     // than zero, though.
    824     assertTrue(rlimit.rlim_cur > 0);
    825     assertTrue(rlimit.rlim_max > 0);
    826   }
    827 
    828   // http://b/65051835
    829   public void test_pipe2_errno() throws Exception {
    830     try {
    831         // flag=-1 is not a valid value for pip2, will EINVAL
    832         Libcore.os.pipe2(-1);
    833         fail();
    834     } catch(ErrnoException expected) {
    835     }
    836   }
    837 
    838   // http://b/65051835
    839   public void test_sendfile_errno() throws Exception {
    840     try {
    841         // FileDescriptor.out is not open for input, will cause EBADF
    842         Int64Ref offset = new Int64Ref(10);
    843         Libcore.os.sendfile(FileDescriptor.out, FileDescriptor.out, offset, 10);
    844         fail();
    845     } catch(ErrnoException expected) {
    846     }
    847   }
    848 
    849   public void test_sendfile_null() throws Exception {
    850     File in = createTempFile("test_sendfile_null", "Hello, world!");
    851     try {
    852       int len = "Hello".length();
    853       assertEquals("Hello", checkSendfile(ANDROID_SYSTEM_OS_INT64_REF, in, null, len, null));
    854       assertEquals("Hello", checkSendfile(LIBCORE_OS, in, null, len, null));
    855     } finally {
    856       in.delete();
    857     }
    858   }
    859 
    860   public void test_sendfile_offset() throws Exception {
    861     File in = createTempFile("test_sendfile_offset", "Hello, world!");
    862     try {
    863       // checkSendfile(sendFileImplToUse, in, startOffset, maxBytes, expectedEndOffset)
    864 
    865       assertEquals("Hello", checkSendfile(ANDROID_SYSTEM_OS_INT64_REF, in, 0L, 5, 5L));
    866       assertEquals("Hello", checkSendfile(LIBCORE_OS, in, 0L, 5, 5L));
    867 
    868       assertEquals("ello,", checkSendfile(ANDROID_SYSTEM_OS_INT64_REF, in, 1L, 5, 6L));
    869       assertEquals("ello,", checkSendfile(LIBCORE_OS, in, 1L, 5, 6L));
    870 
    871       // At offset 9, only 4 bytes/chars available, even though we're asking for 5.
    872       assertEquals("rld!", checkSendfile(ANDROID_SYSTEM_OS_INT64_REF, in, 9L, 5, 13L));
    873       assertEquals("rld!", checkSendfile(LIBCORE_OS, in, 9L, 5, 13L));
    874 
    875       assertEquals("", checkSendfile(ANDROID_SYSTEM_OS_INT64_REF, in, 1L, 0, 1L));
    876       assertEquals("", checkSendfile(LIBCORE_OS, in, 1L, 0, 1L));
    877     } finally {
    878       in.delete();
    879     }
    880   }
    881 
    882   /** Which of the {@code sendfile()} implementations to use. */
    883   enum SendFileImpl {
    884     ANDROID_SYSTEM_OS_INT64_REF,
    885     LIBCORE_OS
    886   }
    887 
    888   private static String checkSendfile(SendFileImpl sendFileImplToUse, File in, Long startOffset,
    889           int maxBytes, Long expectedEndOffset) throws IOException, ErrnoException {
    890     File out = File.createTempFile(OsTest.class.getSimpleName() + "_checkSendFile_" +
    891             sendFileImplToUse, ".out");
    892     try (FileInputStream inStream = new FileInputStream(in)) {
    893       FileDescriptor inFd = inStream.getFD();
    894       try (FileOutputStream outStream = new FileOutputStream(out)) {
    895         FileDescriptor outFd = outStream.getFD();
    896         switch (sendFileImplToUse) {
    897           case ANDROID_SYSTEM_OS_INT64_REF: {
    898             Int64Ref offset = (startOffset == null) ? null : new Int64Ref(startOffset);
    899             android.system.Os.sendfile(outFd, inFd, offset, maxBytes);
    900             assertEquals(expectedEndOffset, offset == null ? null : offset.value);
    901             break;
    902           }
    903           case LIBCORE_OS: {
    904             Int64Ref offset = (startOffset == null) ? null : new Int64Ref(startOffset);
    905             libcore.io.Libcore.os.sendfile(outFd, inFd, offset, maxBytes);
    906             assertEquals(expectedEndOffset, offset == null ? null : offset.value);
    907             break;
    908           }
    909           default: {
    910             fail();
    911             break;
    912           }
    913         }
    914       }
    915       return IoUtils.readFileAsString(out.getPath());
    916     } finally {
    917       out.delete();
    918     }
    919   }
    920 
    921   private static File createTempFile(String namePart, String contents) throws IOException {
    922     File f = File.createTempFile(OsTest.class.getSimpleName() + namePart, ".in");
    923     try (FileWriter writer = new FileWriter(f)) {
    924       writer.write(contents);
    925     }
    926     return f;
    927   }
    928 
    929   public void test_odirect() throws Exception {
    930     File testFile = createTempFile("test_odirect", "");
    931     try {
    932       FileDescriptor fd =
    933             Libcore.os.open(testFile.toString(), O_WRONLY | O_DIRECT, S_IRUSR | S_IWUSR);
    934       assertNotNull(fd);
    935       assertTrue(fd.valid());
    936       int flags = Libcore.os.fcntlVoid(fd, F_GETFL);
    937       assertTrue("Expected file flags to include " + O_DIRECT + ", actual value: " + flags,
    938             0 != (flags & O_DIRECT));
    939       Libcore.os.close(fd);
    940     } finally {
    941       testFile.delete();
    942     }
    943   }
    944 
    945   public void test_splice() throws Exception {
    946     FileDescriptor[] pipe = Libcore.os.pipe2(0);
    947     File in = createTempFile("splice1", "foobar");
    948     File out = createTempFile("splice2", "");
    949 
    950     Int64Ref offIn = new Int64Ref(1);
    951     Int64Ref offOut = new Int64Ref(0);
    952 
    953     // Splice into pipe
    954     try (FileInputStream streamIn = new FileInputStream(in)) {
    955       FileDescriptor fdIn = streamIn.getFD();
    956       long result = Libcore.os.splice(fdIn, offIn, pipe[1], null /* offOut */ , 10 /* len */, 0 /* flags */);
    957       assertEquals(5, result);
    958       assertEquals(6, offIn.value);
    959     }
    960 
    961     // Splice from pipe
    962     try (FileOutputStream streamOut = new FileOutputStream(out)) {
    963       FileDescriptor fdOut = streamOut.getFD();
    964       long result = Libcore.os.splice(pipe[0], null /* offIn */, fdOut, offOut, 10 /* len */, 0 /* flags */);
    965       assertEquals(5, result);
    966       assertEquals(5, offOut.value);
    967     }
    968 
    969     assertEquals("oobar", IoUtils.readFileAsString(out.getPath()));
    970 
    971     Libcore.os.close(pipe[0]);
    972     Libcore.os.close(pipe[1]);
    973   }
    974 
    975   public void test_splice_errors() throws Exception {
    976     File in = createTempFile("splice3", "");
    977     File out = createTempFile("splice4", "");
    978     FileDescriptor[] pipe = Libcore.os.pipe2(0);
    979 
    980     //.fdIn == null
    981     try {
    982       Libcore.os.splice(null /* fdIn */, null /* offIn */, pipe[1],
    983           null /*offOut*/, 10 /* len */, 0 /* flags */);
    984       fail();
    985     } catch(ErrnoException expected) {
    986       assertEquals(EBADF, expected.errno);
    987     }
    988 
    989     //.fdOut == null
    990     try {
    991       Libcore.os.splice(pipe[0] /* fdIn */, null /* offIn */, null  /* fdOut */,
    992           null /*offOut*/, 10 /* len */, 0 /* flags */);
    993       fail();
    994     } catch(ErrnoException expected) {
    995       assertEquals(EBADF, expected.errno);
    996     }
    997 
    998     // No pipe fd
    999     try (FileOutputStream streamOut = new FileOutputStream(out)) {
   1000       try (FileInputStream streamIn = new FileInputStream(in)) {
   1001         FileDescriptor fdIn = streamIn.getFD();
   1002         FileDescriptor fdOut = streamOut.getFD();
   1003         Libcore.os.splice(fdIn, null  /* offIn */, fdOut, null /* offOut */, 10 /* len */, 0 /* flags */);
   1004         fail();
   1005       } catch(ErrnoException expected) {
   1006         assertEquals(EINVAL, expected.errno);
   1007       }
   1008     }
   1009 
   1010     Libcore.os.close(pipe[0]);
   1011     Libcore.os.close(pipe[1]);
   1012   }
   1013 }
   1014