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.NetlinkSocketAddress;
     21 import android.system.OsConstants;
     22 import android.system.PacketSocketAddress;
     23 import android.system.StructTimeval;
     24 import android.system.StructUcred;
     25 import android.system.UnixSocketAddress;
     26 
     27 import java.io.File;
     28 import java.io.FileDescriptor;
     29 import java.io.FileInputStream;
     30 import java.io.FileOutputStream;
     31 import java.net.DatagramPacket;
     32 import java.net.DatagramSocket;
     33 import java.net.Inet4Address;
     34 import java.net.Inet6Address;
     35 import java.net.InetAddress;
     36 import java.net.InetSocketAddress;
     37 import java.net.NetworkInterface;
     38 import java.net.ServerSocket;
     39 import java.net.SocketOptions;
     40 import java.nio.ByteBuffer;
     41 import java.nio.charset.StandardCharsets;
     42 import java.util.Arrays;
     43 import java.util.Collections;
     44 import java.util.List;
     45 import java.util.Locale;
     46 import java.util.concurrent.atomic.AtomicReference;
     47 import junit.framework.TestCase;
     48 
     49 import static android.system.OsConstants.*;
     50 
     51 public class OsTest extends TestCase {
     52   public void testIsSocket() throws Exception {
     53     File f = new File("/dev/null");
     54     FileInputStream fis = new FileInputStream(f);
     55     assertFalse(S_ISSOCK(Libcore.os.fstat(fis.getFD()).st_mode));
     56     fis.close();
     57 
     58     ServerSocket s = new ServerSocket();
     59     assertTrue(S_ISSOCK(Libcore.os.fstat(s.getImpl().getFD$()).st_mode));
     60     s.close();
     61   }
     62 
     63   public void testFcntlInt() throws Exception {
     64     File f = File.createTempFile("OsTest", "tst");
     65     FileInputStream fis = null;
     66     try {
     67       fis = new FileInputStream(f);
     68       Libcore.os.fcntlInt(fis.getFD(), F_SETFD, FD_CLOEXEC);
     69       int flags = Libcore.os.fcntlVoid(fis.getFD(), F_GETFD);
     70       assertTrue((flags & FD_CLOEXEC) != 0);
     71     } finally {
     72       IoUtils.closeQuietly(fis);
     73       f.delete();
     74     }
     75   }
     76 
     77   public void testUnixDomainSockets_in_file_system() throws Exception {
     78     String path = System.getProperty("java.io.tmpdir") + "/test_unix_socket";
     79     new File(path).delete();
     80     checkUnixDomainSocket(UnixSocketAddress.createFileSystem(path), false);
     81   }
     82 
     83   public void testUnixDomainSocket_abstract_name() throws Exception {
     84     // Linux treats a sun_path starting with a NUL byte as an abstract name. See unix(7).
     85     checkUnixDomainSocket(UnixSocketAddress.createAbstract("/abstract_name_unix_socket"), true);
     86   }
     87 
     88   public void testUnixDomainSocket_unnamed() throws Exception {
     89     final FileDescriptor fd = Libcore.os.socket(AF_UNIX, SOCK_STREAM, 0);
     90     // unix(7) says an unbound socket is unnamed.
     91     checkNoSockName(fd);
     92     Libcore.os.close(fd);
     93   }
     94 
     95   private void checkUnixDomainSocket(final UnixSocketAddress address, final boolean isAbstract)
     96       throws Exception {
     97     final FileDescriptor serverFd = Libcore.os.socket(AF_UNIX, SOCK_STREAM, 0);
     98     Libcore.os.bind(serverFd, address);
     99     Libcore.os.listen(serverFd, 5);
    100 
    101     checkSockName(serverFd, isAbstract, address);
    102 
    103     Thread server = new Thread(new Runnable() {
    104       public void run() {
    105         try {
    106           UnixSocketAddress peerAddress = UnixSocketAddress.createUnnamed();
    107           FileDescriptor clientFd = Libcore.os.accept(serverFd, peerAddress);
    108           checkSockName(clientFd, isAbstract, address);
    109           checkNoName(peerAddress);
    110 
    111           checkNoPeerName(clientFd);
    112 
    113           StructUcred credentials = Libcore.os.getsockoptUcred(clientFd, SOL_SOCKET, SO_PEERCRED);
    114           assertEquals(Libcore.os.getpid(), credentials.pid);
    115           assertEquals(Libcore.os.getuid(), credentials.uid);
    116           assertEquals(Libcore.os.getgid(), credentials.gid);
    117 
    118           byte[] request = new byte[256];
    119           Libcore.os.read(clientFd, request, 0, request.length);
    120 
    121           String s = new String(request, "UTF-8");
    122           byte[] response = s.toUpperCase(Locale.ROOT).getBytes("UTF-8");
    123           Libcore.os.write(clientFd, response, 0, response.length);
    124 
    125           Libcore.os.close(clientFd);
    126         } catch (Exception ex) {
    127           throw new RuntimeException(ex);
    128         }
    129       }
    130     });
    131     server.start();
    132 
    133     FileDescriptor clientFd = Libcore.os.socket(AF_UNIX, SOCK_STREAM, 0);
    134 
    135     Libcore.os.connect(clientFd, address);
    136     checkNoSockName(clientFd);
    137 
    138     String string = "hello, world!";
    139 
    140     byte[] request = string.getBytes("UTF-8");
    141     assertEquals(request.length, Libcore.os.write(clientFd, request, 0, request.length));
    142 
    143     byte[] response = new byte[request.length];
    144     assertEquals(response.length, Libcore.os.read(clientFd, response, 0, response.length));
    145 
    146     assertEquals(string.toUpperCase(Locale.ROOT), new String(response, "UTF-8"));
    147 
    148     Libcore.os.close(clientFd);
    149   }
    150 
    151   private static void checkSockName(FileDescriptor fd, boolean isAbstract,
    152       UnixSocketAddress address) throws Exception {
    153     UnixSocketAddress isa = (UnixSocketAddress) Libcore.os.getsockname(fd);
    154     assertEquals(address, isa);
    155     if (isAbstract) {
    156       assertEquals(0, isa.getSunPath()[0]);
    157     }
    158   }
    159 
    160   private void checkNoName(UnixSocketAddress usa) {
    161     assertEquals(0, usa.getSunPath().length);
    162   }
    163 
    164   private void checkNoPeerName(FileDescriptor fd) throws Exception {
    165     checkNoName((UnixSocketAddress) Libcore.os.getpeername(fd));
    166   }
    167 
    168   private void checkNoSockName(FileDescriptor fd) throws Exception {
    169     checkNoName((UnixSocketAddress) Libcore.os.getsockname(fd));
    170   }
    171 
    172   public void test_strsignal() throws Exception {
    173     assertEquals("Killed", Libcore.os.strsignal(9));
    174     assertEquals("Unknown signal -1", Libcore.os.strsignal(-1));
    175   }
    176 
    177   public void test_byteBufferPositions_write_pwrite() throws Exception {
    178     FileOutputStream fos = new FileOutputStream(new File("/dev/null"));
    179     FileDescriptor fd = fos.getFD();
    180     final byte[] contents = new String("goodbye, cruel world").getBytes(StandardCharsets.US_ASCII);
    181     ByteBuffer byteBuffer = ByteBuffer.wrap(contents);
    182 
    183     byteBuffer.position(0);
    184     int written = Libcore.os.write(fd, byteBuffer);
    185     assertTrue(written > 0);
    186     assertEquals(written, byteBuffer.position());
    187 
    188     byteBuffer.position(4);
    189     written = Libcore.os.write(fd, byteBuffer);
    190     assertTrue(written > 0);
    191     assertEquals(written + 4, byteBuffer.position());
    192 
    193     byteBuffer.position(0);
    194     written = Libcore.os.pwrite(fd, byteBuffer, 64 /* offset */);
    195     assertTrue(written > 0);
    196     assertEquals(written, byteBuffer.position());
    197 
    198     byteBuffer.position(4);
    199     written = Libcore.os.pwrite(fd, byteBuffer, 64 /* offset */);
    200     assertTrue(written > 0);
    201     assertEquals(written + 4, byteBuffer.position());
    202 
    203     fos.close();
    204   }
    205 
    206   public void test_byteBufferPositions_read_pread() throws Exception {
    207     FileInputStream fis = new FileInputStream(new File("/dev/zero"));
    208     FileDescriptor fd = fis.getFD();
    209     ByteBuffer byteBuffer = ByteBuffer.allocate(64);
    210 
    211     byteBuffer.position(0);
    212     int read = Libcore.os.read(fd, byteBuffer);
    213     assertTrue(read > 0);
    214     assertEquals(read, byteBuffer.position());
    215 
    216     byteBuffer.position(4);
    217     read = Libcore.os.read(fd, byteBuffer);
    218     assertTrue(read > 0);
    219     assertEquals(read + 4, byteBuffer.position());
    220 
    221     byteBuffer.position(0);
    222     read = Libcore.os.pread(fd, byteBuffer, 64 /* offset */);
    223     assertTrue(read > 0);
    224     assertEquals(read, byteBuffer.position());
    225 
    226     byteBuffer.position(4);
    227     read = Libcore.os.pread(fd, byteBuffer, 64 /* offset */);
    228     assertTrue(read > 0);
    229     assertEquals(read + 4, byteBuffer.position());
    230 
    231     fis.close();
    232   }
    233 
    234   static void checkByteBufferPositions_sendto_recvfrom(
    235       int family, InetAddress loopback) throws Exception {
    236     final FileDescriptor serverFd = Libcore.os.socket(family, SOCK_STREAM, 0);
    237     Libcore.os.bind(serverFd, loopback, 0);
    238     Libcore.os.listen(serverFd, 5);
    239 
    240     InetSocketAddress address = (InetSocketAddress) Libcore.os.getsockname(serverFd);
    241 
    242     final Thread server = new Thread(new Runnable() {
    243       public void run() {
    244         try {
    245           InetSocketAddress peerAddress = new InetSocketAddress();
    246           FileDescriptor clientFd = Libcore.os.accept(serverFd, peerAddress);
    247 
    248           // Attempt to receive a maximum of 24 bytes from the client, and then
    249           // close the connection.
    250           ByteBuffer buffer = ByteBuffer.allocate(16);
    251           int received = Libcore.os.recvfrom(clientFd, buffer, 0, null);
    252           assertTrue(received > 0);
    253           assertEquals(received, buffer.position());
    254 
    255           ByteBuffer buffer2 = ByteBuffer.allocate(16);
    256           buffer2.position(8);
    257           received = Libcore.os.recvfrom(clientFd, buffer2, 0, null);
    258           assertTrue(received > 0);
    259           assertEquals(received + 8, buffer.position());
    260 
    261           Libcore.os.close(clientFd);
    262         } catch (Exception ex) {
    263           throw new RuntimeException(ex);
    264         }
    265       }
    266     });
    267 
    268     server.start();
    269 
    270     FileDescriptor clientFd = Libcore.os.socket(family, SOCK_STREAM, 0);
    271     Libcore.os.connect(clientFd, address.getAddress(), address.getPort());
    272 
    273     final byte[] bytes = "good bye, cruel black hole with fancy distortion"
    274         .getBytes(StandardCharsets.US_ASCII);
    275     assertTrue(bytes.length > 24);
    276 
    277     ByteBuffer input = ByteBuffer.wrap(bytes);
    278     input.position(0);
    279     input.limit(16);
    280 
    281     int sent = Libcore.os.sendto(clientFd, input, 0, address.getAddress(), address.getPort());
    282     assertTrue(sent > 0);
    283     assertEquals(sent, input.position());
    284 
    285     input.position(16);
    286     input.limit(24);
    287     sent = Libcore.os.sendto(clientFd, input, 0, address.getAddress(), address.getPort());
    288     assertTrue(sent > 0);
    289     assertEquals(sent + 16, input.position());
    290 
    291     Libcore.os.close(clientFd);
    292   }
    293 
    294   public void test_NetlinkSocket() throws Exception {
    295     FileDescriptor nlSocket = Libcore.os.socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
    296     Libcore.os.bind(nlSocket, new NetlinkSocketAddress());
    297     NetlinkSocketAddress address = (NetlinkSocketAddress) Libcore.os.getsockname(nlSocket);
    298     assertTrue(address.getPortId() > 0);
    299     assertEquals(0, address.getGroupsMask());
    300 
    301     NetlinkSocketAddress nlKernel = new NetlinkSocketAddress();
    302     Libcore.os.connect(nlSocket, nlKernel);
    303     NetlinkSocketAddress nlPeer = (NetlinkSocketAddress) Libcore.os.getpeername(nlSocket);
    304     assertEquals(0, nlPeer.getPortId());
    305     assertEquals(0, nlPeer.getGroupsMask());
    306     Libcore.os.close(nlSocket);
    307   }
    308 
    309   public void test_PacketSocketAddress() throws Exception {
    310     NetworkInterface lo = NetworkInterface.getByName("lo");
    311     FileDescriptor fd = Libcore.os.socket(AF_PACKET, SOCK_DGRAM, ETH_P_IPV6);
    312     PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IPV6, lo.getIndex());
    313     Libcore.os.bind(fd, addr);
    314 
    315     PacketSocketAddress bound = (PacketSocketAddress) Libcore.os.getsockname(fd);
    316     assertEquals((short) ETH_P_IPV6, bound.sll_protocol);  // ETH_P_IPV6 is an int.
    317     assertEquals(lo.getIndex(), bound.sll_ifindex);
    318     assertEquals(ARPHRD_LOOPBACK, bound.sll_hatype);
    319     assertEquals(0, bound.sll_pkttype);
    320 
    321     // The loopback address is ETH_ALEN bytes long and is all zeros.
    322     // http://lxr.free-electrons.com/source/drivers/net/loopback.c?v=3.10#L167
    323     assertEquals(6, bound.sll_addr.length);
    324     for (int i = 0; i < 6; i++) {
    325       assertEquals(0, bound.sll_addr[i]);
    326     }
    327   }
    328 
    329   public void test_byteBufferPositions_sendto_recvfrom_af_inet() throws Exception {
    330     checkByteBufferPositions_sendto_recvfrom(AF_INET, InetAddress.getByName("127.0.0.1"));
    331   }
    332 
    333   public void test_byteBufferPositions_sendto_recvfrom_af_inet6() throws Exception {
    334     checkByteBufferPositions_sendto_recvfrom(AF_INET6, InetAddress.getByName("::1"));
    335   }
    336 
    337   private void checkSendToSocketAddress(int family, InetAddress loopback) throws Exception {
    338     FileDescriptor recvFd = Libcore.os.socket(family, SOCK_DGRAM, 0);
    339     Libcore.os.bind(recvFd, loopback, 0);
    340     StructTimeval tv = StructTimeval.fromMillis(20);
    341     Libcore.os.setsockoptTimeval(recvFd, SOL_SOCKET, SO_RCVTIMEO, tv);
    342 
    343     InetSocketAddress to = ((InetSocketAddress) Libcore.os.getsockname(recvFd));
    344     FileDescriptor sendFd = Libcore.os.socket(family, SOCK_DGRAM, 0);
    345     byte[] msg = ("Hello, I'm going to a socket address: " + to.toString()).getBytes("UTF-8");
    346     int len = msg.length;
    347 
    348     assertEquals(len, Libcore.os.sendto(sendFd, msg, 0, len, 0, to));
    349     byte[] received = new byte[msg.length + 42];
    350     InetSocketAddress from = new InetSocketAddress();
    351     assertEquals(len, Libcore.os.recvfrom(recvFd, received, 0, received.length, 0, from));
    352     assertEquals(loopback, from.getAddress());
    353   }
    354 
    355   public void test_sendtoSocketAddress_af_inet() throws Exception {
    356     checkSendToSocketAddress(AF_INET, InetAddress.getByName("127.0.0.1"));
    357   }
    358 
    359   public void test_sendtoSocketAddress_af_inet6() throws Exception {
    360     checkSendToSocketAddress(AF_INET6, InetAddress.getByName("::1"));
    361   }
    362 
    363   public void test_socketFamilies() throws Exception {
    364     FileDescriptor fd = Libcore.os.socket(AF_INET6, SOCK_STREAM, 0);
    365     Libcore.os.bind(fd, InetAddress.getByName("::"), 0);
    366     InetSocketAddress localSocketAddress = (InetSocketAddress) Libcore.os.getsockname(fd);
    367     assertEquals(Inet6Address.ANY, localSocketAddress.getAddress());
    368 
    369     fd = Libcore.os.socket(AF_INET6, SOCK_STREAM, 0);
    370     Libcore.os.bind(fd, InetAddress.getByName("0.0.0.0"), 0);
    371     localSocketAddress = (InetSocketAddress) Libcore.os.getsockname(fd);
    372     assertEquals(Inet6Address.ANY, localSocketAddress.getAddress());
    373 
    374     fd = Libcore.os.socket(AF_INET, SOCK_STREAM, 0);
    375     Libcore.os.bind(fd, InetAddress.getByName("0.0.0.0"), 0);
    376     localSocketAddress = (InetSocketAddress) Libcore.os.getsockname(fd);
    377     assertEquals(Inet4Address.ANY, localSocketAddress.getAddress());
    378     try {
    379       Libcore.os.bind(fd, InetAddress.getByName("::"), 0);
    380       fail("Expected ErrnoException binding IPv4 socket to ::");
    381     } catch (ErrnoException expected) {
    382       assertEquals("Expected EAFNOSUPPORT binding IPv4 socket to ::", EAFNOSUPPORT, expected.errno);
    383     }
    384   }
    385 
    386   private static void assertArrayEquals(byte[] expected, byte[] actual) {
    387     assertTrue("Expected=" + Arrays.toString(expected) + ", actual=" + Arrays.toString(actual),
    388         Arrays.equals(expected, actual));
    389   }
    390 
    391   private static void checkSocketPing(FileDescriptor fd, InetAddress to, byte[] packet,
    392       byte type, byte responseType, boolean useSendto) throws Exception {
    393     int len = packet.length;
    394     packet[0] = type;
    395     if (useSendto) {
    396       assertEquals(len, Libcore.os.sendto(fd, packet, 0, len, 0, to, 0));
    397     } else {
    398       Libcore.os.connect(fd, to, 0);
    399       assertEquals(len, Libcore.os.sendto(fd, packet, 0, len, 0, null, 0));
    400     }
    401 
    402     int icmpId = ((InetSocketAddress) Libcore.os.getsockname(fd)).getPort();
    403     byte[] received = new byte[4096];
    404     InetSocketAddress srcAddress = new InetSocketAddress();
    405     assertEquals(len, Libcore.os.recvfrom(fd, received, 0, received.length, 0, srcAddress));
    406     assertEquals(to, srcAddress.getAddress());
    407     assertEquals(responseType, received[0]);
    408     assertEquals(received[4], (byte) (icmpId >> 8));
    409     assertEquals(received[5], (byte) (icmpId & 0xff));
    410 
    411     received = Arrays.copyOf(received, len);
    412     received[0] = (byte) type;
    413     received[2] = received[3] = 0;  // Checksum.
    414     received[4] = received[5] = 0;  // ICMP ID.
    415     assertArrayEquals(packet, received);
    416   }
    417 
    418   public void test_socketPing() throws Exception {
    419     final byte ICMP_ECHO = 8, ICMP_ECHOREPLY = 0;
    420     final byte ICMPV6_ECHO_REQUEST = (byte) 128, ICMPV6_ECHO_REPLY = (byte) 129;
    421     final byte[] packet = ("\000\000\000\000" +  // ICMP type, code.
    422         "\000\000\000\003" +  // ICMP ID (== port), sequence number.
    423         "Hello myself").getBytes(StandardCharsets.US_ASCII);
    424 
    425     FileDescriptor fd = Libcore.os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
    426     InetAddress ipv6Loopback = InetAddress.getByName("::1");
    427     checkSocketPing(fd, ipv6Loopback, packet, ICMPV6_ECHO_REQUEST, ICMPV6_ECHO_REPLY, true);
    428     checkSocketPing(fd, ipv6Loopback, packet, ICMPV6_ECHO_REQUEST, ICMPV6_ECHO_REPLY, false);
    429 
    430     fd = Libcore.os.socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
    431     InetAddress ipv4Loopback = InetAddress.getByName("127.0.0.1");
    432     checkSocketPing(fd, ipv4Loopback, packet, ICMP_ECHO, ICMP_ECHOREPLY, true);
    433     checkSocketPing(fd, ipv4Loopback, packet, ICMP_ECHO, ICMP_ECHOREPLY, false);
    434   }
    435 
    436   public void test_Ipv4Fallback() throws Exception {
    437     // This number of iterations gives a ~60% chance of creating the conditions that caused
    438     // http://b/23088314 without making test times too long. On a hammerhead running MRZ37C using
    439     // vogar, this test takes about 4s.
    440     final int ITERATIONS = 10000;
    441     for (int i = 0; i < ITERATIONS; i++) {
    442       FileDescriptor mUdpSock = Libcore.os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    443       try {
    444           Libcore.os.bind(mUdpSock, Inet4Address.ANY, 0);
    445       } catch(ErrnoException e) {
    446           fail("ErrnoException after " + i + " iterations: " + e);
    447       } finally {
    448           Libcore.os.close(mUdpSock);
    449       }
    450     }
    451   }
    452 
    453   public void test_unlink() throws Exception {
    454     File f = File.createTempFile("OsTest", "tst");
    455     assertTrue(f.exists());
    456     Libcore.os.unlink(f.getAbsolutePath());
    457     assertFalse(f.exists());
    458 
    459     try {
    460       Libcore.os.unlink(f.getAbsolutePath());
    461       fail();
    462     } catch (ErrnoException e) {
    463       assertEquals(OsConstants.ENOENT, e.errno);
    464     }
    465   }
    466 
    467   // b/27294715
    468   public void test_recvfrom_concurrentShutdown() throws Exception {
    469       final FileDescriptor serverFd = Libcore.os.socket(AF_INET, SOCK_DGRAM, 0);
    470       Libcore.os.bind(serverFd, InetAddress.getByName("127.0.0.1"), 0);
    471       // Set 4s timeout
    472       IoBridge.setSocketOption(serverFd, SocketOptions.SO_TIMEOUT, new Integer(4000));
    473 
    474       final AtomicReference<Exception> killerThreadException = new AtomicReference<Exception>(null);
    475       final Thread killer = new Thread(new Runnable() {
    476           public void run() {
    477               try {
    478                   Thread.sleep(2000);
    479                   try {
    480                       Libcore.os.shutdown(serverFd, SHUT_RDWR);
    481                   } catch (ErrnoException expected) {
    482                       if (OsConstants.ENOTCONN != expected.errno) {
    483                           killerThreadException.set(expected);
    484                       }
    485                   }
    486               } catch (Exception ex) {
    487                   killerThreadException.set(ex);
    488               }
    489           }
    490       });
    491       killer.start();
    492 
    493       ByteBuffer buffer = ByteBuffer.allocate(16);
    494       InetSocketAddress srcAddress = new InetSocketAddress();
    495       int received = Libcore.os.recvfrom(serverFd, buffer, 0, srcAddress);
    496       assertTrue(received == 0);
    497       Libcore.os.close(serverFd);
    498 
    499       killer.join();
    500       assertNull(killerThreadException.get());
    501   }
    502 
    503   public void test_xattr() throws Exception {
    504     final String NAME_TEST = "user.meow";
    505 
    506     final byte[] VALUE_CAKE = "cake cake cake".getBytes(StandardCharsets.UTF_8);
    507     final byte[] VALUE_PIE = "pie".getBytes(StandardCharsets.UTF_8);
    508 
    509     File file = File.createTempFile("xattr", "test");
    510     String path = file.getAbsolutePath();
    511 
    512     try {
    513       try {
    514         Libcore.os.getxattr(path, NAME_TEST);
    515         fail("Expected ENODATA");
    516       } catch (ErrnoException e) {
    517         assertEquals(OsConstants.ENODATA, e.errno);
    518       }
    519       assertFalse(Arrays.asList(Libcore.os.listxattr(path)).contains(NAME_TEST));
    520 
    521       Libcore.os.setxattr(path, NAME_TEST, VALUE_CAKE, OsConstants.XATTR_CREATE);
    522       byte[] xattr_create = Libcore.os.getxattr(path, NAME_TEST);
    523       assertTrue(Arrays.asList(Libcore.os.listxattr(path)).contains(NAME_TEST));
    524       assertEquals(VALUE_CAKE.length, xattr_create.length);
    525       assertStartsWith(VALUE_CAKE, xattr_create);
    526 
    527       try {
    528         Libcore.os.setxattr(path, NAME_TEST, VALUE_PIE, OsConstants.XATTR_CREATE);
    529         fail("Expected EEXIST");
    530       } catch (ErrnoException e) {
    531         assertEquals(OsConstants.EEXIST, e.errno);
    532       }
    533 
    534       Libcore.os.setxattr(path, NAME_TEST, VALUE_PIE, OsConstants.XATTR_REPLACE);
    535       byte[] xattr_replace = Libcore.os.getxattr(path, NAME_TEST);
    536       assertTrue(Arrays.asList(Libcore.os.listxattr(path)).contains(NAME_TEST));
    537       assertEquals(VALUE_PIE.length, xattr_replace.length);
    538       assertStartsWith(VALUE_PIE, xattr_replace);
    539 
    540       Libcore.os.removexattr(path, NAME_TEST);
    541       try {
    542         Libcore.os.getxattr(path, NAME_TEST);
    543         fail("Expected ENODATA");
    544       } catch (ErrnoException e) {
    545         assertEquals(OsConstants.ENODATA, e.errno);
    546       }
    547       assertFalse(Arrays.asList(Libcore.os.listxattr(path)).contains(NAME_TEST));
    548 
    549     } finally {
    550       file.delete();
    551     }
    552   }
    553 
    554   public void test_xattr_NPE() throws Exception {
    555     File file = File.createTempFile("xattr", "test");
    556     final String path = file.getAbsolutePath();
    557     final String NAME_TEST = "user.meow";
    558     final byte[] VALUE_CAKE = "cake cake cake".getBytes(StandardCharsets.UTF_8);
    559 
    560     // getxattr
    561     try {
    562       Libcore.os.getxattr(null, NAME_TEST);
    563       fail();
    564     } catch (NullPointerException expected) { }
    565     try {
    566       Libcore.os.getxattr(path, null);
    567       fail();
    568     } catch (NullPointerException expected) { }
    569 
    570     // listxattr
    571     try {
    572       Libcore.os.listxattr(null);
    573       fail();
    574     } catch (NullPointerException expected) { }
    575 
    576     // removexattr
    577     try {
    578       Libcore.os.removexattr(null, NAME_TEST);
    579       fail();
    580     } catch (NullPointerException expected) { }
    581     try {
    582       Libcore.os.removexattr(path, null);
    583       fail();
    584     } catch (NullPointerException expected) { }
    585 
    586     // setxattr
    587     try {
    588       Libcore.os.setxattr(null, NAME_TEST, VALUE_CAKE, OsConstants.XATTR_CREATE);
    589       fail();
    590     } catch (NullPointerException expected) { }
    591     try {
    592       Libcore.os.setxattr(path, null, VALUE_CAKE, OsConstants.XATTR_CREATE);
    593       fail();
    594     } catch (NullPointerException expected) { }
    595     try {
    596       Libcore.os.setxattr(path, NAME_TEST, null, OsConstants.XATTR_CREATE);
    597       fail();
    598     } catch (NullPointerException expected) { }
    599   }
    600 
    601   public void test_xattr_Errno() throws Exception {
    602     final String NAME_TEST = "user.meow";
    603     final byte[] VALUE_CAKE = "cake cake cake".getBytes(StandardCharsets.UTF_8);
    604 
    605     // ENOENT, No such file or directory.
    606     try {
    607       Libcore.os.getxattr("", NAME_TEST);
    608       fail();
    609     } catch (ErrnoException e) {
    610       assertEquals(ENOENT, e.errno);
    611     }
    612     try {
    613       Libcore.os.listxattr("");
    614       fail();
    615     } catch (ErrnoException e) {
    616       assertEquals(ENOENT, e.errno);
    617     }
    618     try {
    619       Libcore.os.removexattr("", NAME_TEST);
    620       fail();
    621     } catch (ErrnoException e) {
    622       assertEquals(ENOENT, e.errno);
    623     }
    624     try {
    625       Libcore.os.setxattr("", NAME_TEST, VALUE_CAKE, OsConstants.XATTR_CREATE);
    626       fail();
    627     } catch (ErrnoException e) {
    628       assertEquals(ENOENT, e.errno);
    629     }
    630 
    631     // ENOTSUP, Extended attributes are not supported by the filesystem, or are disabled.
    632     final boolean root = (Libcore.os.getuid() == 0);
    633     final String path = "/proc/self/stat";
    634     try {
    635       Libcore.os.setxattr(path, NAME_TEST, VALUE_CAKE, OsConstants.XATTR_CREATE);
    636       fail();
    637     } catch (ErrnoException e) {
    638       // setxattr(2) requires root permission for writing to this file, will get EACCES otherwise.
    639       assertEquals(root ? ENOTSUP : EACCES, e.errno);
    640     }
    641     try {
    642       Libcore.os.getxattr(path, NAME_TEST);
    643       fail();
    644     } catch (ErrnoException e) {
    645       assertEquals(ENOTSUP, e.errno);
    646     }
    647     try {
    648       // Linux listxattr does not set errno.
    649       Libcore.os.listxattr(path);
    650     } catch (ErrnoException e) {
    651       fail();
    652     }
    653     try {
    654       Libcore.os.removexattr(path, NAME_TEST);
    655       fail();
    656     } catch (ErrnoException e) {
    657       assertEquals(ENOTSUP, e.errno);
    658     }
    659   }
    660 
    661   public void test_realpath() throws Exception {
    662       File tmpDir = new File(System.getProperty("java.io.tmpdir"));
    663       // This is a chicken and egg problem. We have no way of knowing whether
    664       // the temporary directory or one of its path elements were symlinked, so
    665       // we'll need this call to realpath.
    666       String canonicalTmpDir = Libcore.os.realpath(tmpDir.getAbsolutePath());
    667 
    668       // Test that "." and ".." are resolved correctly.
    669       assertEquals(canonicalTmpDir,
    670           Libcore.os.realpath(canonicalTmpDir + "/./../" + tmpDir.getName()));
    671 
    672       // Test that symlinks are resolved correctly.
    673       File target = new File(tmpDir, "target");
    674       File link = new File(tmpDir, "link");
    675       try {
    676           assertTrue(target.createNewFile());
    677           Libcore.os.symlink(target.getAbsolutePath(), link.getAbsolutePath());
    678 
    679           assertEquals(canonicalTmpDir + "/target",
    680               Libcore.os.realpath(canonicalTmpDir + "/link"));
    681       } finally {
    682           boolean deletedTarget = target.delete();
    683           boolean deletedLink = link.delete();
    684           // Asserting this here to provide a definitive reason for
    685           // a subsequent failure on the same run.
    686           assertTrue("deletedTarget = " + deletedTarget + ", deletedLink =" + deletedLink,
    687               deletedTarget && deletedLink);
    688       }
    689   }
    690 
    691   /**
    692    * Tests that TCP_USER_TIMEOUT can be set on a TCP socket, but doesn't test
    693    * that it behaves as expected.
    694    */
    695   public void test_socket_tcpUserTimeout_setAndGet() throws Exception {
    696     final FileDescriptor fd = Libcore.os.socket(AF_INET, SOCK_STREAM, 0);
    697     try {
    698       int v = Libcore.os.getsockoptInt(fd, OsConstants.IPPROTO_TCP, OsConstants.TCP_USER_TIMEOUT);
    699       assertEquals(0, v); // system default value
    700       int newValue = 3000;
    701       Libcore.os.setsockoptInt(fd, OsConstants.IPPROTO_TCP, OsConstants.TCP_USER_TIMEOUT,
    702               newValue);
    703       assertEquals(newValue, Libcore.os.getsockoptInt(fd, OsConstants.IPPROTO_TCP,
    704               OsConstants.TCP_USER_TIMEOUT));
    705       // No need to reset the value to 0, since we're throwing the socket away
    706     } finally {
    707       Libcore.os.close(fd);
    708     }
    709   }
    710 
    711   public void test_socket_tcpUserTimeout_doesNotWorkOnDatagramSocket() throws Exception {
    712     final FileDescriptor fd = Libcore.os.socket(AF_INET, SOCK_DGRAM, 0);
    713     try {
    714       Libcore.os.setsockoptInt(fd, OsConstants.IPPROTO_TCP, OsConstants.TCP_USER_TIMEOUT,
    715               3000);
    716       fail("datagram (connectionless) sockets shouldn't support TCP_USER_TIMEOUT");
    717     } catch (ErrnoException expected) {
    718       // expected
    719     } finally {
    720       Libcore.os.close(fd);
    721     }
    722   }
    723 
    724   public void test_if_nametoindex_if_indextoname() throws Exception {
    725     List<NetworkInterface> nis = Collections.list(NetworkInterface.getNetworkInterfaces());
    726 
    727     assertTrue(nis.size() > 0);
    728     for (NetworkInterface ni : nis) {
    729       int index = ni.getIndex();
    730       String name = ni.getName();
    731       assertEquals(index, Libcore.os.if_nametoindex(name));
    732       assertTrue(Libcore.os.if_indextoname(index).equals(name));
    733     }
    734 
    735     assertEquals(0, Libcore.os.if_nametoindex("this-interface-does-not-exist"));
    736     assertEquals(null, Libcore.os.if_indextoname(-1000));
    737 
    738     try {
    739       Libcore.os.if_nametoindex(null);
    740       fail();
    741     } catch (NullPointerException expected) { }
    742   }
    743 
    744   private static void assertStartsWith(byte[] expectedContents, byte[] container) {
    745     for (int i = 0; i < expectedContents.length; i++) {
    746       if (expectedContents[i] != container[i]) {
    747         fail("Expected " + Arrays.toString(expectedContents) + " but found "
    748             + Arrays.toString(expectedContents));
    749       }
    750     }
    751   }
    752 
    753   public void test_readlink() throws Exception {
    754     File path = new File(IoUtils.createTemporaryDirectory("test_readlink"), "symlink");
    755 
    756     // ext2 and ext4 have PAGE_SIZE limits on symlink targets.
    757     // If file encryption is enabled, there's extra overhead to store the
    758     // size of the encrypted symlink target. There's also an off-by-one
    759     // in current kernels (and marlin/sailfish where we're seeing this
    760     // failure are still on 3.18, far from current). Given that we don't
    761     // really care here, just use 2048 instead. http://b/33306057.
    762     int size = 2048;
    763     String xs = "";
    764     for (int i = 0; i < size - 1; ++i) xs += "x";
    765 
    766     Libcore.os.symlink(xs, path.getPath());
    767 
    768     assertEquals(xs, Libcore.os.readlink(path.getPath()));
    769   }
    770 
    771   // Address should be correctly set for empty packets. http://b/33481605
    772   public void test_recvfrom_EmptyPacket() throws Exception {
    773     try (DatagramSocket ds = new DatagramSocket();
    774          DatagramSocket srcSock = new DatagramSocket()) {
    775       srcSock.send(new DatagramPacket(new byte[0], 0, ds.getLocalSocketAddress()));
    776 
    777       byte[] recvBuf = new byte[16];
    778       InetSocketAddress address = new InetSocketAddress();
    779       int recvCount =
    780           android.system.Os.recvfrom(ds.getFileDescriptor$(), recvBuf, 0, 16, 0, address);
    781       assertEquals(0, recvCount);
    782       assertTrue(address.getAddress().isLoopbackAddress());
    783       assertEquals(srcSock.getLocalPort(), address.getPort());
    784     }
    785   }
    786 }
    787