Fix 'test-wait' test.

wait4() is only available since API level 19, before that the
C library didn't export the symbol. See [1] for the
corresponding NDK platforms patch.

+ Rewrite the test to avoid sleeping and too much copy-and-paste.

+ Add a test-wait-api19 test that links the test program against
  API level 19 system libraries, which include wait4().

http://b.android.com/19854

[1] https://android-review.googlesource.com/#/c/71850/

Change-Id: Ia79461082a23b615650263102645ef302c14653f
diff --git a/tests/device/test-wait-api19/jni/Android.mk b/tests/device/test-wait-api19/jni/Android.mk
new file mode 100644
index 0000000..eab2175
--- /dev/null
+++ b/tests/device/test-wait-api19/jni/Android.mk
@@ -0,0 +1,13 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := test_wait-dynamic
+LOCAL_SRC_FILES := test_wait.c
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := test_wait-static
+LOCAL_SRC_FILES := test_wait.c
+LOCAL_CFLAGS := -DSTATIC_LINK=1
+LOCAL_LDFLAGS += -static -Wl,--eh-frame-hdr
+include $(BUILD_EXECUTABLE)
diff --git a/tests/device/test-wait-api19/jni/Application.mk b/tests/device/test-wait-api19/jni/Application.mk
new file mode 100644
index 0000000..126e25b
--- /dev/null
+++ b/tests/device/test-wait-api19/jni/Application.mk
@@ -0,0 +1,5 @@
+APP_ABI := all
+APP_PLATFORM := android-19
+# When building the static executable, avoids the linker error message:
+# 'fatal error: -pie and -static are incompatible'
+APP_PIE := false
diff --git a/tests/device/test-wait-api19/jni/test_wait.c b/tests/device/test-wait-api19/jni/test_wait.c
new file mode 100644
index 0000000..6388f53
--- /dev/null
+++ b/tests/device/test-wait-api19/jni/test_wait.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <android/api-level.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#if __ANDROID_API__ < 19 || defined(STATIC_LINK)
+/* wait4() was not defined by the C library before API level 19,
+ * and libc.a is currently stuck at API level 9 */
+
+#include <asm/unistd.h>  /* For __NR_wait4 */
+
+pid_t wait4(pid_t pid, int* status, int options, struct rusage* rusage) {
+  return (pid_t)syscall(__NR_wait4, pid, status, options, rusage);
+}
+#endif
+
+#define CHILD_EXIT_CODE  111
+
+typedef int (*wait_call_function)(pid_t child_pid);
+
+static int check_wait_call(const char* title,
+                           wait_call_function wait_func,
+                           int expected_exit_code) {
+  printf("Testing %s(): ", title);
+  int cpid = fork();
+  if (cpid < 0) {
+    fprintf(stderr, "ERROR: fork() failed: %s\n", strerror(errno));
+    return -1;
+  }
+
+  if (cpid == 0) {  /* in the chid process */
+    printf("Child created pid=%d parent_pid=%d\n", getpid(), getppid());
+    exit(expected_exit_code);
+  }
+
+  /* in the parent process */
+  printf("Parent waiting for child with pid=%d\n", cpid);
+  int exit_code = wait_func(cpid);
+  if (exit_code < 0)
+    return -1;
+
+  if (exit_code != expected_exit_code) {
+    fprintf(stderr, "ERROR: Child exited with code %d, expected %d\n",
+            exit_code, expected_exit_code);
+    return -1;
+  }
+  printf("Testing %s(): OK\n", title);
+  return 0;
+}
+
+// To be called by check_wait_call() to check wait().
+static int check_wait(pid_t child_pid) {
+  int status = 0;
+  pid_t ret = wait(&status);
+  if (ret != child_pid) {
+    fprintf(stderr, "ERROR: wait() returned %d, expected %d\n", ret, child_pid);
+    return -1;
+  }
+  return WEXITSTATUS(status);
+}
+
+// To be called by check_wait_call() to check waitpid()
+static int check_waitpid(pid_t child_pid) {
+  int status = 0;
+  pid_t ret = waitpid((pid_t)-1, &status, 0);
+  if (ret != child_pid) {
+    fprintf(stderr, "ERROR: waitpid() returned %d, expected %d\n", ret, child_pid);
+    return -1;
+  }
+  return WEXITSTATUS(status);
+}
+
+// To be called by check_wait_call() to check wait3()
+static int check_wait3(pid_t child_pid) {
+  int status = 0;
+  struct rusage ru;
+  pid_t ret = wait3(&status, 0, &ru);
+  if (ret != child_pid) {
+    fprintf(stderr, "ERROR: wait3() returned %d, expected %d\n", ret, child_pid);
+    return -1;
+  }
+  return WEXITSTATUS(status);
+}
+
+// To be called by check_wait_call() to check wait3()
+static int check_wait4(pid_t child_pid) {
+  int status = 0;
+  struct rusage ru;
+  pid_t ret = wait4(-1, &status, 0, &ru);
+  if (ret != child_pid) {
+    fprintf(stderr, "ERROR: wait3() returned %d, expected %d\n", ret, child_pid);
+    return -1;
+  }
+  return WEXITSTATUS(status);
+}
+
+int main(int argc, char *argv[]) {
+  printf("Testing for API level %d\n", __ANDROID_API__);
+  if (check_wait_call("wait", check_wait, CHILD_EXIT_CODE + 0) < 0 ||
+      check_wait_call("waitpid", check_waitpid, CHILD_EXIT_CODE + 1) < 0 ||
+      check_wait_call("wait3", check_wait3, CHILD_EXIT_CODE + 2) < 0 ||
+      check_wait_call("wait4", check_wait4, CHILD_EXIT_CODE + 3)) {
+    return 1;
+  }
+
+  return EXIT_SUCCESS;
+}
+
diff --git a/tests/device/test-wait/jni/Android.mk b/tests/device/test-wait/jni/Android.mk
index 94d662a..eab2175 100644
--- a/tests/device/test-wait/jni/Android.mk
+++ b/tests/device/test-wait/jni/Android.mk
@@ -8,6 +8,6 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := test_wait-static
 LOCAL_SRC_FILES := test_wait.c
+LOCAL_CFLAGS := -DSTATIC_LINK=1
 LOCAL_LDFLAGS += -static -Wl,--eh-frame-hdr
 include $(BUILD_EXECUTABLE)
-
diff --git a/tests/device/test-wait/jni/test_wait.c b/tests/device/test-wait/jni/test_wait.c
index 3e16dfd..6388f53 100644
--- a/tests/device/test-wait/jni/test_wait.c
+++ b/tests/device/test-wait/jni/test_wait.c
@@ -26,127 +26,113 @@
  * SUCH DAMAGE.
  */
 
-#include <sys/wait.h>
-#include <stdlib.h>
-#include <unistd.h>
+#include <android/api-level.h>
+#include <errno.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#if __ANDROID_API__ < 19 || defined(STATIC_LINK)
+/* wait4() was not defined by the C library before API level 19,
+ * and libc.a is currently stuck at API level 9 */
+
+#include <asm/unistd.h>  /* For __NR_wait4 */
+
+pid_t wait4(pid_t pid, int* status, int options, struct rusage* rusage) {
+  return (pid_t)syscall(__NR_wait4, pid, status, options, rusage);
+}
+#endif
+
+#define CHILD_EXIT_CODE  111
+
+typedef int (*wait_call_function)(pid_t child_pid);
+
+static int check_wait_call(const char* title,
+                           wait_call_function wait_func,
+                           int expected_exit_code) {
+  printf("Testing %s(): ", title);
+  int cpid = fork();
+  if (cpid < 0) {
+    fprintf(stderr, "ERROR: fork() failed: %s\n", strerror(errno));
+    return -1;
+  }
+
+  if (cpid == 0) {  /* in the chid process */
+    printf("Child created pid=%d parent_pid=%d\n", getpid(), getppid());
+    exit(expected_exit_code);
+  }
+
+  /* in the parent process */
+  printf("Parent waiting for child with pid=%d\n", cpid);
+  int exit_code = wait_func(cpid);
+  if (exit_code < 0)
+    return -1;
+
+  if (exit_code != expected_exit_code) {
+    fprintf(stderr, "ERROR: Child exited with code %d, expected %d\n",
+            exit_code, expected_exit_code);
+    return -1;
+  }
+  printf("Testing %s(): OK\n", title);
+  return 0;
+}
+
+// To be called by check_wait_call() to check wait().
+static int check_wait(pid_t child_pid) {
+  int status = 0;
+  pid_t ret = wait(&status);
+  if (ret != child_pid) {
+    fprintf(stderr, "ERROR: wait() returned %d, expected %d\n", ret, child_pid);
+    return -1;
+  }
+  return WEXITSTATUS(status);
+}
+
+// To be called by check_wait_call() to check waitpid()
+static int check_waitpid(pid_t child_pid) {
+  int status = 0;
+  pid_t ret = waitpid((pid_t)-1, &status, 0);
+  if (ret != child_pid) {
+    fprintf(stderr, "ERROR: waitpid() returned %d, expected %d\n", ret, child_pid);
+    return -1;
+  }
+  return WEXITSTATUS(status);
+}
+
+// To be called by check_wait_call() to check wait3()
+static int check_wait3(pid_t child_pid) {
+  int status = 0;
+  struct rusage ru;
+  pid_t ret = wait3(&status, 0, &ru);
+  if (ret != child_pid) {
+    fprintf(stderr, "ERROR: wait3() returned %d, expected %d\n", ret, child_pid);
+    return -1;
+  }
+  return WEXITSTATUS(status);
+}
+
+// To be called by check_wait_call() to check wait3()
+static int check_wait4(pid_t child_pid) {
+  int status = 0;
+  struct rusage ru;
+  pid_t ret = wait4(-1, &status, 0, &ru);
+  if (ret != child_pid) {
+    fprintf(stderr, "ERROR: wait3() returned %d, expected %d\n", ret, child_pid);
+    return -1;
+  }
+  return WEXITSTATUS(status);
+}
 
 int main(int argc, char *argv[]) {
+  printf("Testing for API level %d\n", __ANDROID_API__);
+  if (check_wait_call("wait", check_wait, CHILD_EXIT_CODE + 0) < 0 ||
+      check_wait_call("waitpid", check_waitpid, CHILD_EXIT_CODE + 1) < 0 ||
+      check_wait_call("wait3", check_wait3, CHILD_EXIT_CODE + 2) < 0 ||
+      check_wait_call("wait4", check_wait4, CHILD_EXIT_CODE + 3)) {
+    return 1;
+  }
 
-   pid_t cpid;
-   int status;
-   struct rusage usage;
-
-//----------------------------------------------------
-//----------------- Wait(); System Call --------------
-//----------------------------------------------------
-   printf("Testing Wait(); System Call\n");
-   printf("\n");
-
-   cpid = fork();               /* Creates fork */
-   if (cpid == -1) {
-      printf("For has failed, returned = %d\n", EXIT_FAILURE);
-   }
-
-   if (cpid == 0) {		/* This is the child operation */
-      printf("Child Created\n");
-      printf("Child = %d\n", getpid());
-      printf("Parent = %d\n", getppid());
-      sleep(2);
-      exit(3);
-
-   } else {                     /* This is the parent operation */
-      printf("Waiting for child\n");
-      wait(&status);
-      printf("Waiting Complete\n");
-      printf("Child Exit Code: %d\n", WEXITSTATUS(status));
-   }
-
-   printf("\n");               /* Just console space */
-//----------------------------------------------------
-//-------------- Waitpid(); System Call --------------
-//----------------------------------------------------
-   printf("Testing Waitpid(); System Call\n");
-   printf("\n");
-
-
-   cpid = fork();                 /* Creates fork */
-   if (cpid == -1) {
-      printf("Fork has failed, returned = %d\n", EXIT_FAILURE);
-   }
-
-   if (cpid == 0) {               /* This is the child operation */
-      printf("Child Created\n");
-      printf("Child = %d\n", getpid());
-      printf("Parent = %d\n", getppid());
-      sleep(2);
-      exit(3);
-
-   } else {                       /* This is the parent operation */
-      printf("Waiting for child %d\n", cpid);
-      waitpid(cpid, NULL, 0);
-      printf("Waiting Complete\n");
-      printf("Child Exit Code: %d\n", WEXITSTATUS(status));
-   }
-
-   printf("\n");
-//----------------------------------------------------
-//---------------- Wait3(); System Call --------------
-//----------------------------------------------------
-   printf("Testing Wait3(); System Call\n");
-   printf("\n");
-
-   cpid = fork();               /* Creates fork */
-   if (cpid == -1) {
-      printf("For has failed, returned = %d\n", EXIT_FAILURE);
-   }
-
-   if (cpid == 0) {             /* This is the child operation */
-      printf("Child Created\n");
-      printf("Child = %d\n", getpid());
-      printf("Parent = %d\n", getppid());
-      sleep(2);
-      exit(3);
-
-   } else {                     /* This is the parent operation */
-      printf("Waiting for child\n");
-      wait3(&status, 0, &usage);
-      printf("Waiting Complete\n");
-      printf("Child Exit Code: %d\n", WEXITSTATUS(status));
-   }
-
-   printf("\n");
-   sleep(1);
-//----------------------------------------------------
-//---------------- Wait4(); System Call --------------
-//----------------------------------------------------
-   printf("Testing Wait4(); System Call\n");
-   printf("\n");
-
-   cpid = fork();               /* Creates fork */
-   if (cpid == -1) {
-      printf("For has failed, returned = %d\n", EXIT_FAILURE);
-   }
-
-   if (cpid == 0) {             /* This is the child operation */
-      printf("Child Created\n");
-      printf("Child = %d\n", getpid());
-      printf("Parent = %d\n", getppid());
-      sleep(2);
-      exit(3);
-
-   } else {                     /* This is the parent operation */
-      printf("Waiting for child\n");
-      wait4(cpid, &status, 0, &usage);
-      //__wait4(cpid, &status, 0, &usage);  //  This function will work, the above which is delcared will not.
-      printf("Waiting Complete\n");
-      printf("Child Exit Code: %d\n", WEXITSTATUS(status));
-   }
-
-   printf("\n");
-   sleep(1);
-
-   return EXIT_SUCCESS;
-
+  return EXIT_SUCCESS;
 }