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;
}