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.android.system;
18 
19 import android.system.ErrnoException;
20 import android.system.Int64Ref;
21 import android.system.NetlinkSocketAddress;
22 import android.system.Os;
23 import android.system.OsConstants;
24 import android.system.PacketSocketAddress;
25 import android.system.StructRlimit;
26 import android.system.StructStat;
27 import android.system.StructTimeval;
28 import android.system.StructUcred;
29 import android.system.UnixSocketAddress;
30 
31 import java.io.File;
32 import java.io.FileDescriptor;
33 import java.io.FileInputStream;
34 import java.io.FileOutputStream;
35 import java.io.FileWriter;
36 import java.io.IOException;
37 import java.net.DatagramPacket;
38 import java.net.DatagramSocket;
39 import java.net.Inet4Address;
40 import java.net.Inet6Address;
41 import java.net.InetAddress;
42 import java.net.InetSocketAddress;
43 import java.net.NetworkInterface;
44 import java.net.ServerSocket;
45 import java.net.SocketAddress;
46 import java.net.SocketException;
47 import java.nio.ByteBuffer;
48 import java.nio.charset.StandardCharsets;
49 import java.time.Duration;
50 import java.util.Arrays;
51 import java.util.Collections;
52 import java.util.List;
53 import java.util.Locale;
54 import java.util.concurrent.atomic.AtomicReference;
55 
56 import junit.framework.TestCase;
57 
58 import libcore.io.IoUtils;
59 import libcore.testing.io.TestIoUtils;
60 
61 import static android.system.OsConstants.*;
62 
63 public class OsTest extends TestCase {
64 
testIsSocket()65     public void testIsSocket() throws Exception {
66         File f = new File("/dev/null");
67         FileInputStream fis = new FileInputStream(f);
68         assertFalse(S_ISSOCK(Os.fstat(fis.getFD()).st_mode));
69         fis.close();
70 
71         ServerSocket s = new ServerSocket();
72         assertTrue(S_ISSOCK(Os.fstat(s.getImpl().getFD$()).st_mode));
73         s.close();
74     }
75 
testFcntlInt()76     public void testFcntlInt() throws Exception {
77         File f = File.createTempFile("OsTest", "tst");
78         FileInputStream fis = null;
79         try {
80             fis = new FileInputStream(f);
81             Os.fcntlInt(fis.getFD(), F_SETFD, FD_CLOEXEC);
82             int flags = Os.fcntlVoid(fis.getFD(), F_GETFD);
83             assertTrue((flags & FD_CLOEXEC) != 0);
84         } finally {
85             TestIoUtils.closeQuietly(fis);
86             f.delete();
87         }
88     }
89 
testFcntlInt_udpSocket()90     public void testFcntlInt_udpSocket() throws Exception {
91         final FileDescriptor fd = Os.socket(AF_INET, SOCK_DGRAM, 0);
92         try {
93             assertEquals(0, (Os.fcntlVoid(fd, F_GETFL) & O_NONBLOCK));
94 
95             // Verify that we can set file descriptor flags on sockets
96             Os.fcntlInt(fd, F_SETFL, SOCK_DGRAM | O_NONBLOCK);
97             assertTrue((Os.fcntlVoid(fd, F_GETFL) & O_NONBLOCK) != 0);
98 
99             // Check that we can turn it off also.
100             Os.fcntlInt(fd, F_SETFL, SOCK_DGRAM);
101             assertEquals(0, (Os.fcntlVoid(fd, F_GETFL) & O_NONBLOCK));
102         } finally {
103             Os.close(fd);
104         }
105     }
106 
testFcntlInt_invalidCmd()107     public void testFcntlInt_invalidCmd() throws Exception {
108         final FileDescriptor fd = Os.socket(AF_INET, SOCK_DGRAM, 0);
109         try {
110             final int unknownCmd = -1;
111             Os.fcntlInt(fd, unknownCmd, 0);
112             fail("Expected failure due to invalid cmd");
113         } catch (ErrnoException expected) {
114             assertEquals(EINVAL, expected.errno);
115         } finally {
116             Os.close(fd);
117         }
118     }
119 
testFcntlInt_nullFd()120     public void testFcntlInt_nullFd() throws Exception {
121         try {
122             Os.fcntlInt(null, F_SETFL, O_NONBLOCK);
123             fail("Expected failure due to null file descriptor");
124         } catch (ErrnoException expected) {
125             assertEquals(EBADF, expected.errno);
126         }
127     }
128 
testUnixDomainSockets_in_file_system()129     public void testUnixDomainSockets_in_file_system() throws Exception {
130         String path = System.getProperty("java.io.tmpdir") + "/test_unix_socket";
131         new File(path).delete();
132         checkUnixDomainSocket(UnixSocketAddress.createFileSystem(path), false);
133     }
134 
testUnixDomainSocket_abstract_name()135     public void testUnixDomainSocket_abstract_name() throws Exception {
136         // Linux treats a sun_path starting with a NUL byte as an abstract name. See unix(7).
137         checkUnixDomainSocket(UnixSocketAddress.createAbstract("/abstract_name_unix_socket"), true);
138     }
139 
testUnixDomainSocket_unnamed()140     public void testUnixDomainSocket_unnamed() throws Exception {
141         final FileDescriptor fd = Os.socket(AF_UNIX, SOCK_STREAM, 0);
142         // unix(7) says an unbound socket is unnamed.
143         checkNoSockName(fd);
144         Os.close(fd);
145     }
146 
checkUnixDomainSocket(final UnixSocketAddress address, final boolean isAbstract)147     private void checkUnixDomainSocket(final UnixSocketAddress address, final boolean isAbstract)
148             throws Exception {
149         final FileDescriptor serverFd = Os.socket(AF_UNIX, SOCK_STREAM, 0);
150         Os.bind(serverFd, address);
151         Os.listen(serverFd, 5);
152 
153         checkSockName(serverFd, isAbstract, address);
154 
155         Thread server = new Thread(new Runnable() {
156             public void run() {
157                 try {
158                     UnixSocketAddress peerAddress = UnixSocketAddress.createUnnamed();
159                     FileDescriptor clientFd = Os.accept(serverFd, peerAddress);
160                     checkSockName(clientFd, isAbstract, address);
161                     checkNoName(peerAddress);
162 
163                     checkNoPeerName(clientFd);
164 
165                     StructUcred credentials = Os.getsockoptUcred(clientFd, SOL_SOCKET, SO_PEERCRED);
166                     assertEquals(Os.getpid(), credentials.pid);
167                     assertEquals(Os.getuid(), credentials.uid);
168                     assertEquals(Os.getgid(), credentials.gid);
169 
170                     byte[] request = new byte[256];
171                     Os.read(clientFd, request, 0, request.length);
172 
173                     String s = new String(request, "UTF-8");
174                     byte[] response = s.toUpperCase(Locale.ROOT).getBytes("UTF-8");
175                     Os.write(clientFd, response, 0, response.length);
176 
177                     Os.close(clientFd);
178                 } catch (Exception ex) {
179                     throw new RuntimeException(ex);
180                 }
181             }
182         });
183         server.start();
184 
185         FileDescriptor clientFd = Os.socket(AF_UNIX, SOCK_STREAM, 0);
186 
187         Os.connect(clientFd, address);
188         checkNoSockName(clientFd);
189 
190         String string = "hello, world!";
191 
192         byte[] request = string.getBytes("UTF-8");
193         assertEquals(request.length, Os.write(clientFd, request, 0, request.length));
194 
195         byte[] response = new byte[request.length];
196         assertEquals(response.length, Os.read(clientFd, response, 0, response.length));
197 
198         assertEquals(string.toUpperCase(Locale.ROOT), new String(response, "UTF-8"));
199 
200         Os.close(clientFd);
201     }
202 
checkSockName(FileDescriptor fd, boolean isAbstract, UnixSocketAddress address)203     private static void checkSockName(FileDescriptor fd, boolean isAbstract,
204             UnixSocketAddress address) throws Exception {
205         UnixSocketAddress isa = (UnixSocketAddress) Os.getsockname(fd);
206         assertEquals(address, isa);
207         if (isAbstract) {
208             assertEquals(0, isa.getSunPath()[0]);
209         }
210     }
211 
checkNoName(UnixSocketAddress usa)212     private void checkNoName(UnixSocketAddress usa) {
213         assertEquals(0, usa.getSunPath().length);
214     }
215 
checkNoPeerName(FileDescriptor fd)216     private void checkNoPeerName(FileDescriptor fd) throws Exception {
217         checkNoName((UnixSocketAddress) Os.getpeername(fd));
218     }
219 
checkNoSockName(FileDescriptor fd)220     private void checkNoSockName(FileDescriptor fd) throws Exception {
221         checkNoName((UnixSocketAddress) Os.getsockname(fd));
222     }
223 
test_strsignal()224     public void test_strsignal() throws Exception {
225         assertEquals("Killed", Os.strsignal(9));
226         assertEquals("Unknown signal -1", Os.strsignal(-1));
227     }
228 
test_byteBufferPositions_write_pwrite()229     public void test_byteBufferPositions_write_pwrite() throws Exception {
230         FileOutputStream fos = new FileOutputStream(new File("/dev/null"));
231         FileDescriptor fd = fos.getFD();
232         final byte[] contents = new String("goodbye, cruel world")
233                 .getBytes(StandardCharsets.US_ASCII);
234         ByteBuffer byteBuffer = ByteBuffer.wrap(contents);
235 
236         byteBuffer.position(0);
237         int written = Os.write(fd, byteBuffer);
238         assertTrue(written > 0);
239         assertEquals(written, byteBuffer.position());
240 
241         byteBuffer.position(4);
242         written = Os.write(fd, byteBuffer);
243         assertTrue(written > 0);
244         assertEquals(written + 4, byteBuffer.position());
245 
246         byteBuffer.position(0);
247         written = Os.pwrite(fd, byteBuffer, 64 /* offset */);
248         assertTrue(written > 0);
249         assertEquals(written, byteBuffer.position());
250 
251         byteBuffer.position(4);
252         written = Os.pwrite(fd, byteBuffer, 64 /* offset */);
253         assertTrue(written > 0);
254         assertEquals(written + 4, byteBuffer.position());
255 
256         fos.close();
257     }
258 
test_byteBufferPositions_read_pread()259     public void test_byteBufferPositions_read_pread() throws Exception {
260         FileInputStream fis = new FileInputStream(new File("/dev/zero"));
261         FileDescriptor fd = fis.getFD();
262         ByteBuffer byteBuffer = ByteBuffer.allocate(64);
263 
264         byteBuffer.position(0);
265         int read = Os.read(fd, byteBuffer);
266         assertTrue(read > 0);
267         assertEquals(read, byteBuffer.position());
268 
269         byteBuffer.position(4);
270         read = Os.read(fd, byteBuffer);
271         assertTrue(read > 0);
272         assertEquals(read + 4, byteBuffer.position());
273 
274         byteBuffer.position(0);
275         read = Os.pread(fd, byteBuffer, 64 /* offset */);
276         assertTrue(read > 0);
277         assertEquals(read, byteBuffer.position());
278 
279         byteBuffer.position(4);
280         read = Os.pread(fd, byteBuffer, 64 /* offset */);
281         assertTrue(read > 0);
282         assertEquals(read + 4, byteBuffer.position());
283 
284         fis.close();
285     }
286 
checkByteBufferPositions_sendto_recvfrom( int family, InetAddress loopback)287     static void checkByteBufferPositions_sendto_recvfrom(
288             int family, InetAddress loopback) throws Exception {
289         final FileDescriptor serverFd = Os.socket(family, SOCK_STREAM, 0);
290         Os.bind(serverFd, loopback, 0);
291         Os.listen(serverFd, 5);
292 
293         InetSocketAddress address = (InetSocketAddress) Os.getsockname(serverFd);
294 
295         final Thread server = new Thread(new Runnable() {
296             public void run() {
297                 try {
298                     InetSocketAddress peerAddress = new InetSocketAddress();
299                     FileDescriptor clientFd = Os.accept(serverFd, peerAddress);
300 
301                     // Attempt to receive a maximum of 24 bytes from the client, and then
302                     // close the connection.
303                     ByteBuffer buffer = ByteBuffer.allocate(16);
304                     int received = Os.recvfrom(clientFd, buffer, 0, null);
305                     assertTrue(received > 0);
306                     assertEquals(received, buffer.position());
307 
308                     ByteBuffer buffer2 = ByteBuffer.allocate(16);
309                     buffer2.position(8);
310                     received = Os.recvfrom(clientFd, buffer2, 0, null);
311                     assertTrue(received > 0);
312                     assertEquals(received + 8, buffer.position());
313 
314                     Os.close(clientFd);
315                 } catch (Exception ex) {
316                     throw new RuntimeException(ex);
317                 }
318             }
319         });
320 
321         server.start();
322 
323         FileDescriptor clientFd = Os.socket(family, SOCK_STREAM, 0);
324         Os.connect(clientFd, address.getAddress(), address.getPort());
325 
326         final byte[] bytes = "good bye, cruel black hole with fancy distortion"
327                 .getBytes(StandardCharsets.US_ASCII);
328         assertTrue(bytes.length > 24);
329 
330         ByteBuffer input = ByteBuffer.wrap(bytes);
331         input.position(0);
332         input.limit(16);
333 
334         int sent = Os.sendto(clientFd, input, 0, address.getAddress(), address.getPort());
335         assertTrue(sent > 0);
336         assertEquals(sent, input.position());
337 
338         input.position(16);
339         input.limit(24);
340         sent = Os.sendto(clientFd, input, 0, address.getAddress(), address.getPort());
341         assertTrue(sent > 0);
342         assertEquals(sent + 16, input.position());
343 
344         Os.close(clientFd);
345     }
346 
347     interface ExceptionalRunnable {
348 
run()349         public void run() throws Exception;
350     }
351 
352     /**
353      * Expects that the given Runnable will throw an exception of the specified class. If the class
354      * is ErrnoException, and expectedErrno is non-null, also checks that the errno is equal to
355      * expectedErrno.
356      */
expectException(ExceptionalRunnable r, Class<? extends Exception> exClass, Integer expectedErrno, String msg)357     private static void expectException(ExceptionalRunnable r, Class<? extends Exception> exClass,
358             Integer expectedErrno, String msg) {
359         try {
360             r.run();
361             fail(msg + " did not throw exception");
362         } catch (Exception e) {
363             assertEquals(msg + " threw unexpected exception", exClass, e.getClass());
364 
365             if (expectedErrno != null) {
366                 if (e instanceof ErrnoException) {
367                     assertEquals(msg + "threw ErrnoException with unexpected error number",
368                             (int) expectedErrno, ((ErrnoException) e).errno);
369                 } else {
370                     fail("Can only pass expectedErrno when expecting ErrnoException");
371                 }
372             }
373 
374         }
375     }
376 
expectBindException(FileDescriptor socket, SocketAddress addr, Class exClass, Integer expectedErrno)377     private static void expectBindException(FileDescriptor socket, SocketAddress addr,
378             Class exClass, Integer expectedErrno) {
379         String msg = String.format("bind(%s, %s)", socket, addr);
380         expectException(() -> {
381             Os.bind(socket, addr);
382         }, exClass, expectedErrno, msg);
383     }
384 
expectConnectException(FileDescriptor socket, SocketAddress addr, Class exClass, Integer expectedErrno)385     private static void expectConnectException(FileDescriptor socket, SocketAddress addr,
386             Class exClass, Integer expectedErrno) {
387         String msg = String.format("connect(%s, %s)", socket, addr);
388         expectException(() -> {
389             Os.connect(socket, addr);
390         }, exClass, expectedErrno, msg);
391     }
392 
expectSendtoException(FileDescriptor socket, SocketAddress addr, Class exClass, Integer expectedErrno)393     private static void expectSendtoException(FileDescriptor socket, SocketAddress addr,
394             Class exClass, Integer expectedErrno) {
395         String msg = String.format("sendto(%s, %s)", socket, addr);
396         byte[] packet = new byte[42];
397         expectException(() -> {
398                     Os.sendto(socket, packet, 0, packet.length, 0, addr);
399                 },
400                 exClass, expectedErrno, msg);
401     }
402 
expectBindConnectSendtoSuccess(FileDescriptor socket, String socketDesc, SocketAddress addr)403     private static void expectBindConnectSendtoSuccess(FileDescriptor socket, String socketDesc,
404             SocketAddress addr) {
405         String msg = socketDesc + " socket to " + addr.toString();
406 
407         try {
408             try {
409                 // Expect that bind throws when any of its arguments are null.
410                 expectBindException(null, addr, ErrnoException.class, EBADF);
411                 expectBindException(socket, null, NullPointerException.class, null);
412                 expectBindException(null, null, NullPointerException.class, null);
413 
414                 // Expect bind to succeed.
415                 Os.bind(socket, addr);
416 
417                 // Find out which port we're actually bound to, and use that in subsequent connect()
418                 // and send() calls. We can't send to addr because that has a port of 0.
419                 if (addr instanceof InetSocketAddress) {
420                     InetSocketAddress addrISA = (InetSocketAddress) addr;
421                     InetSocketAddress socknameISA = (InetSocketAddress) Os.getsockname(socket);
422 
423                     assertEquals(addrISA.getAddress(), socknameISA.getAddress());
424                     assertEquals(0, addrISA.getPort());
425                     assertFalse(0 == socknameISA.getPort());
426                     addr = socknameISA;
427                 }
428 
429                 // Expect sendto with a null address to throw because the socket is not connected,
430                 // but to succeed with a non-null address.
431                 byte[] packet = new byte[42];
432                 Os.sendto(socket, packet, 0, packet.length, 0, addr);
433                 // UNIX and IP sockets return different errors for this operation, so we can't check
434                 // errno.
435                 expectSendtoException(socket, null, ErrnoException.class, null);
436                 expectSendtoException(null, null, ErrnoException.class, EBADF);
437 
438                 // Expect that connect throws when any of its arguments are null.
439                 expectConnectException(null, addr, ErrnoException.class, EBADF);
440                 expectConnectException(socket, null, NullPointerException.class, null);
441                 expectConnectException(null, null, NullPointerException.class, null);
442 
443                 // Expect connect to succeed.
444                 Os.connect(socket, addr);
445                 assertEquals(Os.getsockname(socket), Os.getpeername(socket));
446 
447                 // Expect sendto to succeed both when given an explicit address and a null address.
448                 Os.sendto(socket, packet, 0, packet.length, 0, addr);
449                 Os.sendto(socket, packet, 0, packet.length, 0, null);
450             } catch (SocketException | ErrnoException e) {
451                 fail("Expected success for " + msg + ", but got: " + e);
452             }
453 
454         } finally {
455             IoUtils.closeQuietly(socket);
456         }
457     }
458 
expectBindConnectSendtoErrno(int bindErrno, int connectErrno, int sendtoErrno, FileDescriptor socket, String socketDesc, SocketAddress addr)459     private static void expectBindConnectSendtoErrno(int bindErrno, int connectErrno,
460             int sendtoErrno, FileDescriptor socket, String socketDesc, SocketAddress addr) {
461         try {
462 
463             // Expect bind to fail with bindErrno.
464             String msg = "bind " + socketDesc + " socket to " + addr.toString();
465             try {
466                 Os.bind(socket, addr);
467                 fail("Expected to fail " + msg);
468             } catch (ErrnoException e) {
469                 assertEquals("Expected errno " + bindErrno + " " + msg, bindErrno, e.errno);
470             } catch (SocketException e) {
471                 fail("Unexpected SocketException " + msg);
472             }
473 
474             // Expect connect to fail with connectErrno.
475             msg = "connect " + socketDesc + " socket to " + addr.toString();
476             try {
477                 Os.connect(socket, addr);
478                 fail("Expected to fail " + msg);
479             } catch (ErrnoException e) {
480                 assertEquals("Expected errno " + connectErrno + " " + msg, connectErrno, e.errno);
481             } catch (SocketException e) {
482                 fail("Unexpected SocketException " + msg);
483             }
484 
485             // Expect sendto to fail with sendtoErrno.
486             byte[] packet = new byte[42];
487             msg = "sendto " + socketDesc + " socket to " + addr.toString();
488             try {
489                 Os.sendto(socket, packet, 0, packet.length, 0, addr);
490                 fail("Expected to fail " + msg);
491             } catch (ErrnoException e) {
492                 assertEquals("Expected errno " + sendtoErrno + " " + msg, sendtoErrno, e.errno);
493             } catch (SocketException e) {
494                 fail("Unexpected SocketException " + msg);
495             }
496 
497         } finally {
498             // No matter what happened, close the socket.
499             IoUtils.closeQuietly(socket);
500         }
501     }
502 
makeIpv4Socket()503     private FileDescriptor makeIpv4Socket() throws Exception {
504         return Os.socket(AF_INET, SOCK_DGRAM, 0);
505     }
506 
makeIpv6Socket()507     private FileDescriptor makeIpv6Socket() throws Exception {
508         return Os.socket(AF_INET6, SOCK_DGRAM, 0);
509     }
510 
makeUnixSocket()511     private FileDescriptor makeUnixSocket() throws Exception {
512         return Os.socket(AF_UNIX, SOCK_DGRAM, 0);
513     }
514 
testCrossFamilyBindConnectSendto()515     public void testCrossFamilyBindConnectSendto() throws Exception {
516         SocketAddress addrIpv4 = new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 0);
517         SocketAddress addrIpv6 = new InetSocketAddress(InetAddress.getByName("::1"), 0);
518         SocketAddress addrUnix = UnixSocketAddress.createAbstract("/abstract_name_unix_socket");
519 
520         expectBindConnectSendtoSuccess(makeIpv4Socket(), "ipv4", addrIpv4);
521         expectBindConnectSendtoErrno(EAFNOSUPPORT, EAFNOSUPPORT, EAFNOSUPPORT,
522                 makeIpv4Socket(), "ipv4", addrIpv6);
523         expectBindConnectSendtoErrno(EAFNOSUPPORT, EAFNOSUPPORT, EAFNOSUPPORT,
524                 makeIpv4Socket(), "ipv4", addrUnix);
525 
526         // This succeeds because Java always uses dual-stack sockets and all InetAddress and
527         // InetSocketAddress objects represent IPv4 addresses using IPv4-mapped IPv6 addresses.
528         expectBindConnectSendtoSuccess(makeIpv6Socket(), "ipv6", addrIpv4);
529         expectBindConnectSendtoSuccess(makeIpv6Socket(), "ipv6", addrIpv6);
530         expectBindConnectSendtoErrno(EAFNOSUPPORT, EAFNOSUPPORT, EINVAL,
531                 makeIpv6Socket(), "ipv6", addrUnix);
532 
533         expectBindConnectSendtoErrno(EINVAL, EINVAL, EINVAL,
534                 makeUnixSocket(), "unix", addrIpv4);
535         expectBindConnectSendtoErrno(EINVAL, EINVAL, EINVAL,
536                 makeUnixSocket(), "unix", addrIpv6);
537         expectBindConnectSendtoSuccess(makeUnixSocket(), "unix", addrUnix);
538     }
539 
testUnknownSocketAddressSubclass()540     public void testUnknownSocketAddressSubclass() throws Exception {
541         class MySocketAddress extends SocketAddress {
542 
543         }
544         MySocketAddress myaddr = new MySocketAddress();
545 
546         for (int family : new int[] { AF_INET, AF_INET6, AF_NETLINK }) {
547             FileDescriptor s = Os.socket(family, SOCK_DGRAM, 0);
548             try {
549 
550                 try {
551                     Os.bind(s, myaddr);
552                     fail("bind socket family " + family
553                             + " to unknown SocketAddress subclass succeeded");
554                 } catch (UnsupportedOperationException expected) {
555                 }
556 
557                 try {
558                     Os.connect(s, myaddr);
559                     fail("connect socket family " + family
560                             + " to unknown SocketAddress subclass succeeded");
561                 } catch (UnsupportedOperationException expected) {
562                 }
563 
564                 byte[] msg = new byte[42];
565                 try {
566                     Os.sendto(s, msg, 0, msg.length, 0, myaddr);
567                     fail("sendto socket family " + family
568                             + " to unknown SocketAddress subclass succeeded");
569                 } catch (UnsupportedOperationException expected) {
570                 }
571 
572             } finally {
573                 Os.close(s);
574             }
575         }
576     }
577 
test_NetlinkSocket()578     public void test_NetlinkSocket() throws Exception {
579         FileDescriptor nlSocket = Os.socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
580         try {
581             Os.bind(nlSocket, new NetlinkSocketAddress());
582             // Non-system processes should not be allowed to bind() to NETLINK_ROUTE sockets.
583             // http://b/141455849
584             fail("bind() on NETLINK_ROUTE socket succeeded");
585         } catch (ErrnoException expectedException) {
586             assertEquals(expectedException.errno, EACCES);
587         }
588 
589         NetlinkSocketAddress nlKernel = new NetlinkSocketAddress();
590         Os.connect(nlSocket, nlKernel);
591         NetlinkSocketAddress nlPeer = (NetlinkSocketAddress) Os.getpeername(nlSocket);
592         assertEquals(0, nlPeer.getPortId());
593         assertEquals(0, nlPeer.getGroupsMask());
594         Os.close(nlSocket);
595     }
596 
597     // This test is excluded from CTS via the knownfailures.txt because it requires extra
598     // permissions not available in CTS. To run it you have to use an -eng build and use a tool like
599     // vogar that runs the Android runtime as a privileged user.
test_PacketSocketAddress()600     public void test_PacketSocketAddress() throws Exception {
601         NetworkInterface lo = NetworkInterface.getByName("lo");
602         FileDescriptor fd = Os.socket(AF_PACKET, SOCK_DGRAM, ETH_P_IPV6);
603         PacketSocketAddress addr =
604                 new PacketSocketAddress(ETH_P_IPV6, lo.getIndex(), null /* sll_addr */);
605         Os.bind(fd, addr);
606 
607         PacketSocketAddress bound = (PacketSocketAddress) Os.getsockname(fd);
608         assertEquals(ETH_P_IPV6, bound.sll_protocol);
609         assertEquals(lo.getIndex(), bound.sll_ifindex);
610         assertEquals(ARPHRD_LOOPBACK, bound.sll_hatype);
611         assertEquals(0, bound.sll_pkttype);
612 
613         // The loopback address is ETH_ALEN bytes long and is all zeros.
614         // http://lxr.free-electrons.com/source/drivers/net/loopback.c?v=3.10#L167
615         assertEquals(6, bound.sll_addr.length);
616         for (int i = 0; i < 6; i++) {
617             assertEquals(0, bound.sll_addr[i]);
618         }
619 
620         // The following checks that the packet socket address was constructed correctly in a form
621         // that the kernel understands. If the address is correct, the bind should result in a
622         // socket that is listening only for IPv6 packets, and only on loopback.
623 
624         // Send an IPv4 packet on loopback.
625         // We send ourselves an IPv4 packet first. If we don't receive it, that (with high
626         // probability) ensures that the packet socket does not see IPv4 packets.
627         try (DatagramSocket s = new DatagramSocket()) {
628             byte[] packet = new byte[64];
629             s.send(new DatagramPacket(packet, 0, packet.length, Inet4Address.LOOPBACK,
630                     53 /* arbitrary port */));
631         }
632 
633         // Send an IPv6 packet on loopback.
634         // Sending ourselves an IPv6 packet should cause the socket to receive a packet.
635         // The idea is that if the code gets sll_protocol wrong, then the packet socket will receive
636         // no packets and the test will fail.
637         try (DatagramSocket s = new DatagramSocket()) {
638             byte[] packet = new byte[64];
639             s.send(new DatagramPacket(packet, 0, packet.length, Inet6Address.LOOPBACK,
640                     53 /* arbitrary port */));
641         }
642 
643         // Check that the socket associated with fd has received an IPv6 packet, not necessarily the
644         // UDP one we sent above. IPv6 packets always begin with the nibble 6. If we get anything
645         // else it means we're catching non-IPv6 or non-loopback packets unexpectedly. Since the
646         // socket is not discriminating it may catch packets unrelated to this test from things
647         // happening on the device at the same time, so we can't assert too much about the received
648         // packet, i.e. no length / content check.
649         {
650             byte[] receivedPacket = new byte[4096];
651             Os.read(fd, receivedPacket, 0, receivedPacket.length);
652             assertEquals(6, (receivedPacket[0] & 0xf0) >> 4);
653 
654             byte[] sourceAddress = getIPv6AddressBytesAtOffset(receivedPacket, 8);
655             assertArrayEquals(Inet6Address.LOOPBACK.getAddress(), sourceAddress);
656 
657             byte[] destAddress = getIPv6AddressBytesAtOffset(receivedPacket, 24);
658             assertArrayEquals(Inet6Address.LOOPBACK.getAddress(), destAddress);
659         }
660 
661         Os.close(fd);
662     }
663 
getIPv6AddressBytesAtOffset(byte[] packet, int offsetIndex)664     private static byte[] getIPv6AddressBytesAtOffset(byte[] packet, int offsetIndex) {
665         byte[] address = new byte[16];
666         for (int i = 0; i < 16; i++) {
667             address[i] = packet[i + offsetIndex];
668         }
669         return address;
670     }
671 
test_byteBufferPositions_sendto_recvfrom_af_inet()672     public void test_byteBufferPositions_sendto_recvfrom_af_inet() throws Exception {
673         checkByteBufferPositions_sendto_recvfrom(AF_INET, InetAddress.getByName("127.0.0.1"));
674     }
675 
test_byteBufferPositions_sendto_recvfrom_af_inet6()676     public void test_byteBufferPositions_sendto_recvfrom_af_inet6() throws Exception {
677         checkByteBufferPositions_sendto_recvfrom(AF_INET6, InetAddress.getByName("::1"));
678     }
679 
checkSendToSocketAddress(int family, InetAddress loopback)680     private void checkSendToSocketAddress(int family, InetAddress loopback) throws Exception {
681         FileDescriptor recvFd = Os.socket(family, SOCK_DGRAM, 0);
682         Os.bind(recvFd, loopback, 0);
683         StructTimeval tv = StructTimeval.fromMillis(20);
684         Os.setsockoptTimeval(recvFd, SOL_SOCKET, SO_RCVTIMEO, tv);
685 
686         InetSocketAddress to = ((InetSocketAddress) Os.getsockname(recvFd));
687         FileDescriptor sendFd = Os.socket(family, SOCK_DGRAM, 0);
688         byte[] msg = ("Hello, I'm going to a socket address: " + to.toString()).getBytes("UTF-8");
689         int len = msg.length;
690 
691         assertEquals(len, Os.sendto(sendFd, msg, 0, len, 0, to));
692         byte[] received = new byte[msg.length + 42];
693         InetSocketAddress from = new InetSocketAddress();
694         assertEquals(len, Os.recvfrom(recvFd, received, 0, received.length, 0, from));
695         assertEquals(loopback, from.getAddress());
696     }
697 
test_sendtoSocketAddress_af_inet()698     public void test_sendtoSocketAddress_af_inet() throws Exception {
699         checkSendToSocketAddress(AF_INET, InetAddress.getByName("127.0.0.1"));
700     }
701 
test_sendtoSocketAddress_af_inet6()702     public void test_sendtoSocketAddress_af_inet6() throws Exception {
703         checkSendToSocketAddress(AF_INET6, InetAddress.getByName("::1"));
704     }
705 
test_socketFamilies()706     public void test_socketFamilies() throws Exception {
707         FileDescriptor fd = Os.socket(AF_INET6, SOCK_STREAM, 0);
708         Os.bind(fd, InetAddress.getByName("::"), 0);
709         InetSocketAddress localSocketAddress = (InetSocketAddress) Os.getsockname(fd);
710         assertEquals(Inet6Address.ANY, localSocketAddress.getAddress());
711 
712         fd = Os.socket(AF_INET6, SOCK_STREAM, 0);
713         Os.bind(fd, InetAddress.getByName("0.0.0.0"), 0);
714         localSocketAddress = (InetSocketAddress) Os.getsockname(fd);
715         assertEquals(Inet6Address.ANY, localSocketAddress.getAddress());
716 
717         fd = Os.socket(AF_INET, SOCK_STREAM, 0);
718         Os.bind(fd, InetAddress.getByName("0.0.0.0"), 0);
719         localSocketAddress = (InetSocketAddress) Os.getsockname(fd);
720         assertEquals(Inet4Address.ANY, localSocketAddress.getAddress());
721         try {
722             Os.bind(fd, InetAddress.getByName("::"), 0);
723             fail("Expected ErrnoException binding IPv4 socket to ::");
724         } catch (ErrnoException expected) {
725             assertEquals("Expected EAFNOSUPPORT binding IPv4 socket to ::", EAFNOSUPPORT,
726                     expected.errno);
727         }
728     }
729 
assertArrayEquals(byte[] expected, byte[] actual)730     private static void assertArrayEquals(byte[] expected, byte[] actual) {
731         assertTrue("Expected=" + Arrays.toString(expected) + ", actual=" + Arrays.toString(actual),
732                 Arrays.equals(expected, actual));
733     }
734 
checkSocketPing(FileDescriptor fd, InetAddress to, byte[] packet, byte type, byte responseType, boolean useSendto)735     private static void checkSocketPing(FileDescriptor fd, InetAddress to, byte[] packet,
736             byte type, byte responseType, boolean useSendto) throws Exception {
737         int len = packet.length;
738         packet[0] = type;
739         if (useSendto) {
740             assertEquals(len, Os.sendto(fd, packet, 0, len, 0, to, 0));
741         } else {
742             Os.connect(fd, to, 0);
743             assertEquals(len, Os.sendto(fd, packet, 0, len, 0, null, 0));
744         }
745 
746         int icmpId = ((InetSocketAddress) Os.getsockname(fd)).getPort();
747         byte[] received = new byte[4096];
748         InetSocketAddress srcAddress = new InetSocketAddress();
749         assertEquals(len, Os.recvfrom(fd, received, 0, received.length, 0, srcAddress));
750         assertEquals(to, srcAddress.getAddress());
751         assertEquals(responseType, received[0]);
752         assertEquals(received[4], (byte) (icmpId >> 8));
753         assertEquals(received[5], (byte) (icmpId & 0xff));
754 
755         received = Arrays.copyOf(received, len);
756         received[0] = (byte) type;
757         received[2] = received[3] = 0;  // Checksum.
758         received[4] = received[5] = 0;  // ICMP ID.
759         assertArrayEquals(packet, received);
760     }
761 
test_socketPing()762     public void test_socketPing() throws Exception {
763         final byte ICMP_ECHO = 8, ICMP_ECHOREPLY = 0;
764         final byte ICMPV6_ECHO_REQUEST = (byte) 128, ICMPV6_ECHO_REPLY = (byte) 129;
765         final byte[] packet = ("\000\000\000\000" +  // ICMP type, code.
766                 "\000\000\000\003" +  // ICMP ID (== port), sequence number.
767                 "Hello myself").getBytes(StandardCharsets.US_ASCII);
768 
769         FileDescriptor fd = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
770         InetAddress ipv6Loopback = InetAddress.getByName("::1");
771         checkSocketPing(fd, ipv6Loopback, packet, ICMPV6_ECHO_REQUEST, ICMPV6_ECHO_REPLY, true);
772         checkSocketPing(fd, ipv6Loopback, packet, ICMPV6_ECHO_REQUEST, ICMPV6_ECHO_REPLY, false);
773 
774         fd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
775         InetAddress ipv4Loopback = InetAddress.getByName("127.0.0.1");
776         checkSocketPing(fd, ipv4Loopback, packet, ICMP_ECHO, ICMP_ECHOREPLY, true);
777         checkSocketPing(fd, ipv4Loopback, packet, ICMP_ECHO, ICMP_ECHOREPLY, false);
778     }
779 
test_Ipv4Fallback()780     public void test_Ipv4Fallback() throws Exception {
781         // This number of iterations gives a ~60% chance of creating the conditions that caused
782         // http://b/23088314 without making test times too long. On a hammerhead running MRZ37C
783         // using vogar, this test takes about 4s.
784         final int ITERATIONS = 10000;
785         for (int i = 0; i < ITERATIONS; i++) {
786             FileDescriptor mUdpSock = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
787             try {
788                 Os.bind(mUdpSock, Inet4Address.ANY, 0);
789             } catch (ErrnoException e) {
790                 fail("ErrnoException after " + i + " iterations: " + e);
791             } finally {
792                 Os.close(mUdpSock);
793             }
794         }
795     }
796 
test_unlink()797     public void test_unlink() throws Exception {
798         File f = File.createTempFile("OsTest", "tst");
799         assertTrue(f.exists());
800         Os.unlink(f.getAbsolutePath());
801         assertFalse(f.exists());
802 
803         try {
804             Os.unlink(f.getAbsolutePath());
805             fail();
806         } catch (ErrnoException e) {
807             assertEquals(OsConstants.ENOENT, e.errno);
808         }
809     }
810 
811     // b/27294715
test_recvfrom_concurrentShutdown()812     public void test_recvfrom_concurrentShutdown() throws Exception {
813         final FileDescriptor serverFd = Os.socket(AF_INET, SOCK_DGRAM, 0);
814         Os.bind(serverFd, InetAddress.getByName("127.0.0.1"), 0);
815         // Set 4s timeout
816         StructTimeval tv = StructTimeval.fromMillis(4000);
817         Os.setsockoptTimeval(serverFd, SOL_SOCKET, SO_RCVTIMEO, tv);
818 
819         final AtomicReference<Exception> killerThreadException = new AtomicReference<Exception>(
820                 null);
821         final Thread killer = new Thread(new Runnable() {
822             public void run() {
823                 try {
824                     Thread.sleep(2000);
825                     try {
826                         Os.shutdown(serverFd, SHUT_RDWR);
827                     } catch (ErrnoException expected) {
828                         if (OsConstants.ENOTCONN != expected.errno) {
829                             killerThreadException.set(expected);
830                         }
831                     }
832                 } catch (Exception ex) {
833                     killerThreadException.set(ex);
834                 }
835             }
836         });
837         killer.start();
838 
839         ByteBuffer buffer = ByteBuffer.allocate(16);
840         InetSocketAddress srcAddress = new InetSocketAddress();
841         int received = Os.recvfrom(serverFd, buffer, 0, srcAddress);
842         assertTrue(received == 0);
843         Os.close(serverFd);
844 
845         killer.join();
846         assertNull(killerThreadException.get());
847     }
848 
test_xattr()849     public void test_xattr() throws Exception {
850         final String NAME_TEST = "user.meow";
851 
852         final byte[] VALUE_CAKE = "cake cake cake".getBytes(StandardCharsets.UTF_8);
853         final byte[] VALUE_PIE = "pie".getBytes(StandardCharsets.UTF_8);
854 
855         File file = File.createTempFile("xattr", "test");
856         String path = file.getAbsolutePath();
857 
858         try {
859             try {
860                 Os.getxattr(path, NAME_TEST);
861                 fail("Expected ENODATA");
862             } catch (ErrnoException e) {
863                 assertEquals(OsConstants.ENODATA, e.errno);
864             }
865             assertFalse(Arrays.asList(Os.listxattr(path)).contains(NAME_TEST));
866 
867             Os.setxattr(path, NAME_TEST, VALUE_CAKE, OsConstants.XATTR_CREATE);
868             byte[] xattr_create = Os.getxattr(path, NAME_TEST);
869             assertTrue(Arrays.asList(Os.listxattr(path)).contains(NAME_TEST));
870             assertEquals(VALUE_CAKE.length, xattr_create.length);
871             assertStartsWith(VALUE_CAKE, xattr_create);
872 
873             try {
874                 Os.setxattr(path, NAME_TEST, VALUE_PIE, OsConstants.XATTR_CREATE);
875                 fail("Expected EEXIST");
876             } catch (ErrnoException e) {
877                 assertEquals(OsConstants.EEXIST, e.errno);
878             }
879 
880             Os.setxattr(path, NAME_TEST, VALUE_PIE, OsConstants.XATTR_REPLACE);
881             byte[] xattr_replace = Os.getxattr(path, NAME_TEST);
882             assertTrue(Arrays.asList(Os.listxattr(path)).contains(NAME_TEST));
883             assertEquals(VALUE_PIE.length, xattr_replace.length);
884             assertStartsWith(VALUE_PIE, xattr_replace);
885 
886             Os.removexattr(path, NAME_TEST);
887             try {
888                 Os.getxattr(path, NAME_TEST);
889                 fail("Expected ENODATA");
890             } catch (ErrnoException e) {
891                 assertEquals(OsConstants.ENODATA, e.errno);
892             }
893             assertFalse(Arrays.asList(Os.listxattr(path)).contains(NAME_TEST));
894 
895         } finally {
896             file.delete();
897         }
898     }
899 
test_xattr_NPE()900     public void test_xattr_NPE() throws Exception {
901         File file = File.createTempFile("xattr", "test");
902         final String path = file.getAbsolutePath();
903         final String NAME_TEST = "user.meow";
904         final byte[] VALUE_CAKE = "cake cake cake".getBytes(StandardCharsets.UTF_8);
905 
906         // getxattr
907         try {
908             Os.getxattr(null, NAME_TEST);
909             fail();
910         } catch (NullPointerException expected) {
911         }
912         try {
913             Os.getxattr(path, null);
914             fail();
915         } catch (NullPointerException expected) {
916         }
917 
918         // listxattr
919         try {
920             Os.listxattr(null);
921             fail();
922         } catch (NullPointerException expected) {
923         }
924 
925         // removexattr
926         try {
927             Os.removexattr(null, NAME_TEST);
928             fail();
929         } catch (NullPointerException expected) {
930         }
931         try {
932             Os.removexattr(path, null);
933             fail();
934         } catch (NullPointerException expected) {
935         }
936 
937         // setxattr
938         try {
939             Os.setxattr(null, NAME_TEST, VALUE_CAKE, OsConstants.XATTR_CREATE);
940             fail();
941         } catch (NullPointerException expected) {
942         }
943         try {
944             Os.setxattr(path, null, VALUE_CAKE, OsConstants.XATTR_CREATE);
945             fail();
946         } catch (NullPointerException expected) {
947         }
948         try {
949             Os.setxattr(path, NAME_TEST, null, OsConstants.XATTR_CREATE);
950             fail();
951         } catch (NullPointerException expected) {
952         }
953     }
954 
test_xattr_Errno()955     public void test_xattr_Errno() throws Exception {
956         final String NAME_TEST = "user.meow";
957         final byte[] VALUE_CAKE = "cake cake cake".getBytes(StandardCharsets.UTF_8);
958 
959         // ENOENT, No such file or directory.
960         try {
961             Os.getxattr("", NAME_TEST);
962             fail();
963         } catch (ErrnoException e) {
964             assertEquals(ENOENT, e.errno);
965         }
966         try {
967             Os.listxattr("");
968             fail();
969         } catch (ErrnoException e) {
970             assertEquals(ENOENT, e.errno);
971         }
972         try {
973             Os.removexattr("", NAME_TEST);
974             fail();
975         } catch (ErrnoException e) {
976             assertEquals(ENOENT, e.errno);
977         }
978         try {
979             Os.setxattr("", NAME_TEST, VALUE_CAKE, OsConstants.XATTR_CREATE);
980             fail();
981         } catch (ErrnoException e) {
982             assertEquals(ENOENT, e.errno);
983         }
984 
985         // ENOTSUP, Extended attributes are not supported by the filesystem, or are disabled.
986         // Since kernel version 4.9 (or some other version after 4.4), *xattr() methods
987         // may set errno to EACCES instead. This behavior change is likely related to
988         // https://patchwork.kernel.org/patch/9294421/ which reimplemented getxattr, setxattr,
989         // and removexattr on top of generic handlers.
990         final String path = "/proc/self/stat";
991         try {
992             Os.setxattr(path, NAME_TEST, VALUE_CAKE, OsConstants.XATTR_CREATE);
993             fail();
994         } catch (ErrnoException e) {
995             assertTrue("Unexpected errno: " + e.errno, e.errno == ENOTSUP || e.errno == EACCES);
996         }
997         try {
998             Os.getxattr(path, NAME_TEST);
999             fail();
1000         } catch (ErrnoException e) {
1001             assertEquals(ENOTSUP, e.errno);
1002         }
1003         try {
1004             // Linux listxattr does not set errno.
1005             Os.listxattr(path);
1006         } catch (ErrnoException e) {
1007             fail();
1008         }
1009         try {
1010             Os.removexattr(path, NAME_TEST);
1011             fail();
1012         } catch (ErrnoException e) {
1013             assertTrue("Unexpected errno: " + e.errno, e.errno == ENOTSUP || e.errno == EACCES);
1014         }
1015     }
1016 
test_realpath()1017     public void test_realpath() throws Exception {
1018         File tmpDir = new File(System.getProperty("java.io.tmpdir"));
1019         // This is a chicken and egg problem. We have no way of knowing whether
1020         // the temporary directory or one of its path elements were symlinked, so
1021         // we'll need this call to realpath.
1022         String canonicalTmpDir = Os.realpath(tmpDir.getAbsolutePath());
1023 
1024         // Test that "." and ".." are resolved correctly.
1025         assertEquals(canonicalTmpDir,
1026                 Os.realpath(canonicalTmpDir + "/./../" + tmpDir.getName()));
1027 
1028         // Test that symlinks are resolved correctly.
1029         File target = new File(tmpDir, "target");
1030         File link = new File(tmpDir, "link");
1031         try {
1032             assertTrue(target.createNewFile());
1033             Os.symlink(target.getAbsolutePath(), link.getAbsolutePath());
1034 
1035             assertEquals(canonicalTmpDir + "/target",
1036                     Os.realpath(canonicalTmpDir + "/link"));
1037         } finally {
1038             boolean deletedTarget = target.delete();
1039             boolean deletedLink = link.delete();
1040             // Asserting this here to provide a definitive reason for
1041             // a subsequent failure on the same run.
1042             assertTrue("deletedTarget = " + deletedTarget + ", deletedLink =" + deletedLink,
1043                     deletedTarget && deletedLink);
1044         }
1045     }
1046 
1047     /**
1048      * Tests that TCP_USER_TIMEOUT can be set on a TCP socket, but doesn't test
1049      * that it behaves as expected.
1050      */
test_socket_tcpUserTimeout_setAndGet()1051     public void test_socket_tcpUserTimeout_setAndGet() throws Exception {
1052         final FileDescriptor fd = Os.socket(AF_INET, SOCK_STREAM, 0);
1053         try {
1054             int v = Os.getsockoptInt(fd, OsConstants.IPPROTO_TCP, OsConstants.TCP_USER_TIMEOUT);
1055             assertEquals(0, v); // system default value
1056             int newValue = 3000;
1057             Os.setsockoptInt(fd, OsConstants.IPPROTO_TCP, OsConstants.TCP_USER_TIMEOUT,
1058                     newValue);
1059             int actualValue = Os.getsockoptInt(fd, OsConstants.IPPROTO_TCP,
1060                     OsConstants.TCP_USER_TIMEOUT);
1061             // The kernel can round the requested value based on the HZ setting. We allow up to 10ms
1062             // difference.
1063             assertTrue("Returned incorrect timeout:" + actualValue,
1064                     Math.abs(newValue - actualValue) <= 10);
1065             // No need to reset the value to 0, since we're throwing the socket away
1066         } finally {
1067             Os.close(fd);
1068         }
1069     }
1070 
test_socket_tcpUserTimeout_doesNotWorkOnDatagramSocket()1071     public void test_socket_tcpUserTimeout_doesNotWorkOnDatagramSocket() throws Exception {
1072         final FileDescriptor fd = Os.socket(AF_INET, SOCK_DGRAM, 0);
1073         try {
1074             Os.setsockoptInt(fd, OsConstants.IPPROTO_TCP, OsConstants.TCP_USER_TIMEOUT,
1075                     3000);
1076             fail("datagram (connectionless) sockets shouldn't support TCP_USER_TIMEOUT");
1077         } catch (ErrnoException expected) {
1078             // expected
1079         } finally {
1080             Os.close(fd);
1081         }
1082     }
1083 
test_socket_sockoptTimeval_readWrite()1084     public void test_socket_sockoptTimeval_readWrite() throws Exception {
1085         FileDescriptor fd = Os.socket(AF_INET6, SOCK_STREAM, 0);
1086         try {
1087             StructTimeval v = Os.getsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO);
1088             assertEquals(0, v.toMillis()); // system default value
1089 
1090             StructTimeval newValue = StructTimeval.fromMillis(3000);
1091             Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, newValue);
1092 
1093             StructTimeval actualValue = Os.getsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO);
1094 
1095             // The kernel can round the requested value based on the HZ setting. We allow up to 10ms
1096             // difference.
1097             assertTrue("Returned incorrect timeout:" + actualValue,
1098                     Math.abs(newValue.toMillis() - actualValue.toMillis()) <= 10);
1099             // No need to reset the value to 0, since we're throwing the socket away
1100         } finally {
1101             Os.close(fd);
1102         }
1103     }
1104 
test_socket_setSockoptTimeval_effective()1105     public void test_socket_setSockoptTimeval_effective() throws Exception {
1106         int timeoutValueMillis = 50;
1107         int allowedTimeoutMillis = 500;
1108 
1109         FileDescriptor fd = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
1110         try {
1111             StructTimeval tv = StructTimeval.fromMillis(timeoutValueMillis);
1112             Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, tv);
1113             Os.bind(fd, InetAddress.getByName("::1"), 0);
1114 
1115             byte[] request = new byte[1];
1116             long startTime = System.nanoTime();
1117             expectException(() -> Os.read(fd, request, 0, request.length),
1118                     ErrnoException.class, EAGAIN, "Expected timeout");
1119             long endTime = System.nanoTime();
1120             assertTrue(Duration.ofNanos(endTime - startTime).toMillis() < allowedTimeoutMillis);
1121         } finally {
1122             Os.close(fd);
1123         }
1124     }
1125 
1126     public void test_socket_setSockoptTimeval_nullFd() throws Exception {
1127         StructTimeval tv = StructTimeval.fromMillis(500);
1128         expectException(
1129                 () -> Os.setsockoptTimeval(null, SOL_SOCKET, SO_RCVTIMEO, tv),
1130                 ErrnoException.class, EBADF, "setsockoptTimeval(null, ...)");
1131     }
1132 
test_socket_setSockoptTimeval_fileFd()1133     public void test_socket_setSockoptTimeval_fileFd() throws Exception {
1134         File testFile = createTempFile("test_socket_setSockoptTimeval_invalidFd", "");
1135         try (FileInputStream fis = new FileInputStream(testFile)) {
1136             final FileDescriptor fd = fis.getFD();
1137 
1138             StructTimeval tv = StructTimeval.fromMillis(500);
1139             expectException(
1140                     () -> Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, tv),
1141                     ErrnoException.class, ENOTSOCK, "setsockoptTimeval(<file fd>, ...)");
1142         }
1143     }
1144 
test_socket_setSockoptTimeval_badFd()1145     public void test_socket_setSockoptTimeval_badFd() throws Exception {
1146         StructTimeval tv = StructTimeval.fromMillis(500);
1147         FileDescriptor invalidFd = Os.socket(AF_INET6, SOCK_STREAM, 0);
1148         Os.close(invalidFd);
1149 
1150         expectException(
1151                 () -> Os.setsockoptTimeval(invalidFd, SOL_SOCKET, SO_RCVTIMEO, tv),
1152                 ErrnoException.class, EBADF, "setsockoptTimeval(<closed fd>, ...)");
1153     }
1154 
test_socket_setSockoptTimeval_invalidLevel()1155     public void test_socket_setSockoptTimeval_invalidLevel() throws Exception {
1156         StructTimeval tv = StructTimeval.fromMillis(500);
1157         FileDescriptor fd = Os.socket(AF_INET6, SOCK_STREAM, 0);
1158         try {
1159             expectException(
1160                     () -> Os.setsockoptTimeval(fd, -1, SO_RCVTIMEO, tv),
1161                     ErrnoException.class, ENOPROTOOPT,
1162                     "setsockoptTimeval(fd, <invalid level>, ...)");
1163         } finally {
1164             Os.close(fd);
1165         }
1166     }
1167 
test_socket_setSockoptTimeval_invalidOpt()1168     public void test_socket_setSockoptTimeval_invalidOpt() throws Exception {
1169         StructTimeval tv = StructTimeval.fromMillis(500);
1170         FileDescriptor fd = Os.socket(AF_INET6, SOCK_STREAM, 0);
1171         try {
1172             expectException(
1173                     () -> Os.setsockoptTimeval(fd, SOL_SOCKET, -1, tv),
1174                     ErrnoException.class, ENOPROTOOPT,
1175                     "setsockoptTimeval(fd, <invalid level>, ...)");
1176         } finally {
1177             Os.close(fd);
1178         }
1179     }
1180 
test_socket_setSockoptTimeval_nullTimeVal()1181     public void test_socket_setSockoptTimeval_nullTimeVal() throws Exception {
1182         FileDescriptor fd = Os.socket(AF_INET6, SOCK_STREAM, 0);
1183         try {
1184             expectException(
1185                     () -> Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, null),
1186                     NullPointerException.class, null, "setsockoptTimeval(..., null)");
1187         } finally {
1188             Os.close(fd);
1189         }
1190     }
1191 
test_socket_getSockoptTimeval_invalidOption()1192     public void test_socket_getSockoptTimeval_invalidOption() throws Exception {
1193         FileDescriptor fd = Os.socket(AF_INET6, SOCK_STREAM, 0);
1194         try {
1195             expectException(
1196                     () -> Os.getsockoptTimeval(fd, SOL_SOCKET, SO_DEBUG),
1197                     IllegalArgumentException.class, null,
1198                     "getsockoptTimeval(..., <non-timeval option>)");
1199         } finally {
1200             Os.close(fd);
1201         }
1202     }
1203 
test_if_nametoindex_if_indextoname()1204     public void test_if_nametoindex_if_indextoname() throws Exception {
1205         List<NetworkInterface> nis = Collections.list(NetworkInterface.getNetworkInterfaces());
1206 
1207         assertTrue(nis.size() > 0);
1208         for (NetworkInterface ni : nis) {
1209             int index = ni.getIndex();
1210             String name = ni.getName();
1211             assertEquals(index, Os.if_nametoindex(name));
1212             assertTrue(Os.if_indextoname(index).equals(name));
1213         }
1214 
1215         assertEquals(0, Os.if_nametoindex("this-interface-does-not-exist"));
1216         assertEquals(null, Os.if_indextoname(-1000));
1217 
1218         try {
1219             Os.if_nametoindex(null);
1220             fail();
1221         } catch (NullPointerException expected) {
1222         }
1223     }
1224 
assertStartsWith(byte[] expectedContents, byte[] container)1225     private static void assertStartsWith(byte[] expectedContents, byte[] container) {
1226         for (int i = 0; i < expectedContents.length; i++) {
1227             if (expectedContents[i] != container[i]) {
1228                 fail("Expected " + Arrays.toString(expectedContents) + " but found "
1229                         + Arrays.toString(expectedContents));
1230             }
1231         }
1232     }
1233 
test_readlink()1234     public void test_readlink() throws Exception {
1235         File path = new File(TestIoUtils.createTemporaryDirectory("test_readlink"), "symlink");
1236 
1237         // ext2 and ext4 have PAGE_SIZE limits on symlink targets.
1238         // If file encryption is enabled, there's extra overhead to store the
1239         // size of the encrypted symlink target. There's also an off-by-one
1240         // in current kernels (and marlin/sailfish where we're seeing this
1241         // failure are still on 3.18, far from current). Given that we don't
1242         // really care here, just use 2048 instead. http://b/33306057.
1243         int size = 2048;
1244         String xs = "";
1245         for (int i = 0; i < size - 1; ++i) {
1246             xs += "x";
1247         }
1248 
1249         Os.symlink(xs, path.getPath());
1250 
1251         assertEquals(xs, Os.readlink(path.getPath()));
1252     }
1253 
1254     // Address should be correctly set for empty packets. http://b/33481605
test_recvfrom_EmptyPacket()1255     public void test_recvfrom_EmptyPacket() throws Exception {
1256         try (DatagramSocket ds = new DatagramSocket();
1257              DatagramSocket srcSock = new DatagramSocket()) {
1258             srcSock.send(new DatagramPacket(new byte[0], 0, ds.getLocalSocketAddress()));
1259 
1260             byte[] recvBuf = new byte[16];
1261             InetSocketAddress address = new InetSocketAddress();
1262             int recvCount =
1263                     android.system.Os.recvfrom(ds.getFileDescriptor$(), recvBuf, 0, 16, 0, address);
1264             assertEquals(0, recvCount);
1265             assertTrue(address.getAddress().isLoopbackAddress());
1266             assertEquals(srcSock.getLocalPort(), address.getPort());
1267         }
1268     }
1269 
test_fstat_times()1270     public void test_fstat_times() throws Exception {
1271         File file = File.createTempFile("OsTest", "fstattest");
1272         FileOutputStream fos = new FileOutputStream(file);
1273         StructStat structStat1 = Os.fstat(fos.getFD());
1274         assertEquals(structStat1.st_mtim.tv_sec, structStat1.st_mtime);
1275         assertEquals(structStat1.st_ctim.tv_sec, structStat1.st_ctime);
1276         assertEquals(structStat1.st_atim.tv_sec, structStat1.st_atime);
1277         Thread.sleep(100);
1278         fos.write(new byte[] { 1, 2, 3 });
1279         fos.flush();
1280         StructStat structStat2 = Os.fstat(fos.getFD());
1281         fos.close();
1282 
1283         assertEquals(-1, structStat1.st_mtim.compareTo(structStat2.st_mtim));
1284         assertEquals(-1, structStat1.st_ctim.compareTo(structStat2.st_ctim));
1285         assertEquals(0, structStat1.st_atim.compareTo(structStat2.st_atim));
1286     }
1287 
test_getrlimit()1288     public void test_getrlimit() throws Exception {
1289         StructRlimit rlimit = Os.getrlimit(OsConstants.RLIMIT_NOFILE);
1290         // We can't really make any assertions about these values since they might vary from
1291         // device to device and even process to process. We do know that they will be greater
1292         // than zero, though.
1293         assertTrue(rlimit.rlim_cur > 0);
1294         assertTrue(rlimit.rlim_max > 0);
1295     }
1296 
1297     // http://b/65051835
test_pipe2_errno()1298     public void test_pipe2_errno() throws Exception {
1299         try {
1300             // flag=-1 is not a valid value for pip2, will EINVAL
1301             Os.pipe2(-1);
1302             fail();
1303         } catch (ErrnoException expected) {
1304         }
1305     }
1306 
1307     // http://b/65051835
test_sendfile_errno()1308     public void test_sendfile_errno() throws Exception {
1309         try {
1310             // FileDescriptor.out is not open for input, will cause EBADF
1311             Int64Ref offset = new Int64Ref(10);
1312             Os.sendfile(FileDescriptor.out, FileDescriptor.out, offset, 10);
1313             fail();
1314         } catch (ErrnoException expected) {
1315         }
1316     }
1317 
test_sendfile_null()1318     public void test_sendfile_null() throws Exception {
1319         File in = createTempFile("test_sendfile_null", "Hello, world!");
1320         try {
1321             int len = "Hello".length();
1322             assertEquals("Hello", checkSendfile(in, null, len, null));
1323         } finally {
1324             in.delete();
1325         }
1326     }
1327 
test_sendfile_offset()1328     public void test_sendfile_offset() throws Exception {
1329         File in = createTempFile("test_sendfile_offset", "Hello, world!");
1330         try {
1331             // checkSendfile(sendFileImplToUse, in, startOffset, maxBytes, expectedEndOffset)
1332             assertEquals("Hello", checkSendfile(in, 0L, 5, 5L));
1333             assertEquals("ello,", checkSendfile(in, 1L, 5, 6L));
1334             // At offset 9, only 4 bytes/chars available, even though we're asking for 5.
1335             assertEquals("rld!", checkSendfile(in, 9L, 5, 13L));
1336             assertEquals("", checkSendfile(in, 1L, 0, 1L));
1337         } finally {
1338             in.delete();
1339         }
1340     }
1341 
checkSendfile(File in, Long startOffset, int maxBytes, Long expectedEndOffset)1342     private static String checkSendfile(File in, Long startOffset,
1343             int maxBytes, Long expectedEndOffset) throws IOException, ErrnoException {
1344         File out = File.createTempFile(OsTest.class.getSimpleName() + "_checkSendFile", ".out");
1345         try (FileInputStream inStream = new FileInputStream(in)) {
1346             FileDescriptor inFd = inStream.getFD();
1347             try (FileOutputStream outStream = new FileOutputStream(out)) {
1348                 FileDescriptor outFd = outStream.getFD();
1349                 Int64Ref offset = (startOffset == null) ? null : new Int64Ref(startOffset);
1350                 android.system.Os.sendfile(outFd, inFd, offset, maxBytes);
1351                 assertEquals(expectedEndOffset, offset == null ? null : offset.value);
1352             }
1353             return TestIoUtils.readFileAsString(out.getPath());
1354         } finally {
1355             out.delete();
1356         }
1357     }
1358 
createTempFile(String namePart, String contents)1359     private static File createTempFile(String namePart, String contents) throws IOException {
1360         File f = File.createTempFile(OsTest.class.getSimpleName() + namePart, ".in");
1361         try (FileWriter writer = new FileWriter(f)) {
1362             writer.write(contents);
1363         }
1364         return f;
1365     }
1366 
test_odirect()1367     public void test_odirect() throws Exception {
1368         File testFile = createTempFile("test_odirect", "");
1369         try {
1370             FileDescriptor fd =
1371                     Os.open(testFile.toString(), O_WRONLY | O_DIRECT, S_IRUSR | S_IWUSR);
1372             assertNotNull(fd);
1373             assertTrue(fd.valid());
1374             int flags = Os.fcntlVoid(fd, F_GETFL);
1375             assertTrue("Expected file flags to include " + O_DIRECT + ", actual value: " + flags,
1376                     0 != (flags & O_DIRECT));
1377             Os.close(fd);
1378         } finally {
1379             testFile.delete();
1380         }
1381     }
1382 
test_splice()1383     public void test_splice() throws Exception {
1384         FileDescriptor[] pipe = Os.pipe2(0);
1385         File in = createTempFile("splice1", "foobar");
1386         File out = createTempFile("splice2", "");
1387 
1388         Int64Ref offIn = new Int64Ref(1);
1389         Int64Ref offOut = new Int64Ref(0);
1390 
1391         // Splice into pipe
1392         try (FileInputStream streamIn = new FileInputStream(in)) {
1393             FileDescriptor fdIn = streamIn.getFD();
1394             long result = Os
1395                     .splice(fdIn, offIn, pipe[1], null /* offOut */, 10 /* len */, 0 /* flags */);
1396             assertEquals(5, result);
1397             assertEquals(6, offIn.value);
1398         }
1399 
1400         // Splice from pipe
1401         try (FileOutputStream streamOut = new FileOutputStream(out)) {
1402             FileDescriptor fdOut = streamOut.getFD();
1403             long result = Os
1404                     .splice(pipe[0], null /* offIn */, fdOut, offOut, 10 /* len */, 0 /* flags */);
1405             assertEquals(5, result);
1406             assertEquals(5, offOut.value);
1407         }
1408 
1409         assertEquals("oobar", TestIoUtils.readFileAsString(out.getPath()));
1410 
1411         Os.close(pipe[0]);
1412         Os.close(pipe[1]);
1413     }
1414 
test_splice_errors()1415     public void test_splice_errors() throws Exception {
1416         File in = createTempFile("splice3", "");
1417         File out = createTempFile("splice4", "");
1418         FileDescriptor[] pipe = Os.pipe2(0);
1419 
1420         //.fdIn == null
1421         try {
1422             Os.splice(null /* fdIn */, null /* offIn */, pipe[1],
1423                     null /*offOut*/, 10 /* len */, 0 /* flags */);
1424             fail();
1425         } catch (ErrnoException expected) {
1426             assertEquals(EBADF, expected.errno);
1427         }
1428 
1429         //.fdOut == null
1430         try {
1431             Os.splice(pipe[0] /* fdIn */, null /* offIn */, null  /* fdOut */,
1432                     null /*offOut*/, 10 /* len */, 0 /* flags */);
1433             fail();
1434         } catch (ErrnoException expected) {
1435             assertEquals(EBADF, expected.errno);
1436         }
1437 
1438         // No pipe fd
1439         try (FileOutputStream streamOut = new FileOutputStream(out)) {
1440             try (FileInputStream streamIn = new FileInputStream(in)) {
1441                 FileDescriptor fdIn = streamIn.getFD();
1442                 FileDescriptor fdOut = streamOut.getFD();
1443                 Os.splice(fdIn, null  /* offIn */, fdOut, null /* offOut */, 10 /* len */,
1444                         0 /* flags */);
1445                 fail();
1446             } catch (ErrnoException expected) {
1447                 assertEquals(EINVAL, expected.errno);
1448             }
1449         }
1450 
1451         Os.close(pipe[0]);
1452         Os.close(pipe[1]);
1453     }
1454 
testCloseNullFileDescriptor()1455     public void testCloseNullFileDescriptor() throws Exception {
1456         try {
1457             Os.close(null);
1458             fail();
1459         } catch (NullPointerException expected) {
1460         }
1461     }
1462 
testSocketpairNullFileDescriptor1()1463     public void testSocketpairNullFileDescriptor1() throws Exception {
1464         try {
1465             Os.socketpair(AF_UNIX, SOCK_STREAM, 0, null, new FileDescriptor());
1466             fail();
1467         } catch (NullPointerException expected) {
1468         }
1469     }
1470 
testSocketpairNullFileDescriptor2()1471     public void testSocketpairNullFileDescriptor2() throws Exception {
1472         try {
1473             Os.socketpair(AF_UNIX, SOCK_STREAM, 0, new FileDescriptor(), null);
1474             fail();
1475         } catch (NullPointerException expected) {
1476         }
1477     }
1478 
testSocketpairNullFileDescriptorBoth()1479     public void testSocketpairNullFileDescriptorBoth() throws Exception {
1480         try {
1481             Os.socketpair(AF_UNIX, SOCK_STREAM, 0, null, null);
1482             fail();
1483         } catch (NullPointerException expected) {
1484         }
1485     }
1486 
testInetPtonIpv4()1487     public void testInetPtonIpv4() {
1488         String srcAddress = "127.0.0.1";
1489         InetAddress inetAddress = Os.inet_pton(AF_INET, srcAddress);
1490         assertEquals(srcAddress, inetAddress.getHostAddress());
1491     }
1492 
testInetPtonIpv6()1493     public void testInetPtonIpv6() {
1494         String srcAddress = "1123:4567:89ab:cdef:fedc:ba98:7654:3210";
1495         InetAddress inetAddress = Os.inet_pton(AF_INET6, srcAddress);
1496         assertEquals(srcAddress, inetAddress.getHostAddress());
1497     }
1498 
testInetPtonInvalidFamily()1499     public void testInetPtonInvalidFamily() {
1500         String srcAddress = "127.0.0.1";
1501         InetAddress inetAddress = Os.inet_pton(AF_UNIX, srcAddress);
1502         assertNull(inetAddress);
1503     }
1504 
testInetPtonWrongFamily()1505     public void testInetPtonWrongFamily() {
1506         String srcAddress = "127.0.0.1";
1507         InetAddress inetAddress = Os.inet_pton(AF_INET6, srcAddress);
1508         assertNull(inetAddress);
1509     }
1510 
testInetPtonInvalidData()1511     public void testInetPtonInvalidData() {
1512         String srcAddress = "10.1";
1513         InetAddress inetAddress = Os.inet_pton(AF_INET, srcAddress);
1514         assertNull(inetAddress);
1515     }
1516 
1517     /**
1518      * Verifies the {@link OsConstants#MAP_ANONYMOUS}.
1519      */
testMapAnonymous()1520     public void testMapAnonymous() throws Exception {
1521         final long size = 4096;
1522         final long address = Os.mmap(0, size, PROT_READ,
1523                 MAP_PRIVATE | MAP_ANONYMOUS, new FileDescriptor(), 0);
1524         assertTrue(address > 0);
1525         Os.munmap(address, size);
1526     }
1527 
testMemfdCreate()1528     public void testMemfdCreate() throws Exception {
1529         FileDescriptor fd = null;
1530         try {
1531             fd = Os.memfd_create("test_memfd", 0);
1532             assertNotNull(fd);
1533             assertTrue(fd.valid());
1534 
1535             StructStat stat = Os.fstat(fd);
1536             assertEquals(0, stat.st_size);
1537 
1538             final byte[] expected = new byte[] {1, 2, 3, 4};
1539             Os.write(fd, expected, 0, expected.length);
1540             stat = Os.fstat(fd);
1541             assertEquals(expected.length, stat.st_size);
1542 
1543             byte[] actual = new byte[expected.length];
1544             // should be seekable
1545             Os.lseek(fd, 0, SEEK_SET);
1546             Os.read(fd, actual, 0, actual.length);
1547             assertArrayEquals(expected, actual);
1548         } finally {
1549             if (fd != null) {
1550                 Os.close(fd);
1551                 fd = null;
1552             }
1553         }
1554     }
1555 
testMemfdCreateFlags()1556     public void testMemfdCreateFlags() throws Exception {
1557         FileDescriptor fd = null;
1558 
1559         // test that MFD_CLOEXEC is obeyed
1560         try {
1561             fd = Os.memfd_create("test_memfd", 0);
1562             assertNotNull(fd);
1563             assertTrue(fd.valid());
1564             int flags = Os.fcntlVoid(fd, F_GETFD);
1565             assertTrue("Expected flags to not include " + FD_CLOEXEC + ", actual value: " + flags,
1566                     0 == (flags & FD_CLOEXEC));
1567         } finally {
1568             if (fd != null) {
1569                 Os.close(fd);
1570                 fd = null;
1571             }
1572         }
1573         try {
1574             fd = Os.memfd_create("test_memfd", MFD_CLOEXEC);
1575             assertNotNull(fd);
1576             assertTrue(fd.valid());
1577             int flags = Os.fcntlVoid(fd, F_GETFD);
1578             assertTrue("Expected flags to include " + FD_CLOEXEC + ", actual value: " + flags,
1579                     0 != (flags & FD_CLOEXEC));
1580         } finally {
1581             if (fd != null) {
1582                 Os.close(fd);
1583                 fd = null;
1584             }
1585         }
1586     }
1587 
testMemfdCreateErrno()1588     public void testMemfdCreateErrno() throws Exception {
1589         expectException(() -> Os.memfd_create(null, 0), NullPointerException.class, null,
1590                 "memfd_create(null, 0)");
1591 
1592         expectException(() -> Os.memfd_create("test_memfd", 0xffff), ErrnoException.class, EINVAL,
1593                 "memfd_create(\"test_memfd\", 0xffff)");
1594     }
1595 }
1596