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