1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package libcore.libcore.io;
18
19import android.system.ErrnoException;
20import android.system.Int64Ref;
21import android.system.NetlinkSocketAddress;
22import android.system.OsConstants;
23import android.system.PacketSocketAddress;
24import android.system.StructRlimit;
25import android.system.StructStat;
26import android.system.StructTimeval;
27import android.system.StructUcred;
28import android.system.UnixSocketAddress;
29
30import java.io.File;
31import java.io.FileDescriptor;
32import java.io.FileInputStream;
33import java.io.FileOutputStream;
34import java.io.FileWriter;
35import java.io.IOException;
36import java.net.DatagramPacket;
37import java.net.DatagramSocket;
38import java.net.Inet4Address;
39import java.net.Inet6Address;
40import java.net.InetAddress;
41import java.net.InetSocketAddress;
42import java.net.NetworkInterface;
43import java.net.ServerSocket;
44import java.net.SocketOptions;
45import java.nio.ByteBuffer;
46import java.nio.charset.StandardCharsets;
47import java.nio.file.Files;
48import java.util.Arrays;
49import java.util.Collections;
50import java.util.List;
51import java.util.Locale;
52import java.util.concurrent.atomic.AtomicReference;
53import junit.framework.TestCase;
54
55import libcore.io.IoBridge;
56import libcore.io.IoUtils;
57import libcore.io.Libcore;
58
59import static android.system.OsConstants.*;
60import static libcore.libcore.io.OsTest.SendFileImpl.ANDROID_SYSTEM_OS_INT64_REF;
61import static libcore.libcore.io.OsTest.SendFileImpl.LIBCORE_OS;
62
63public 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