ashmem_test: Rewrite fork tests to use fork() explicitly

The fork tests use the ASSERT_EXIT() macro to spawn a child process
that maniuplates ashmem buffers. However, using ASSERT_EXIT() makes
the child process creation non-obvious.

Therefore, make the tests easier to understand by using fork()
explicitly to capture what is going on in each test.

No functional change.

Bug: 390672531
Change-Id: I84d3c17d229a1036030eea40e159664b8eeb3af7
Signed-off-by: Isaac J. Manjarres <isaacmanjarres@google.com>
diff --git a/libcutils/ashmem_test.cpp b/libcutils/ashmem_test.cpp
index 7abc370..b0a552f 100644
--- a/libcutils/ashmem_test.cpp
+++ b/libcutils/ashmem_test.cpp
@@ -69,6 +69,15 @@
     }
 }
 
+static void waitForChildProcessExit(pid_t pid) {
+    int exitStatus;
+    pid_t childPid = waitpid(pid, &exitStatus, 0);
+
+    ASSERT_GT(childPid, 0);
+    ASSERT_TRUE(WIFEXITED(exitStatus));
+    ASSERT_EQ(0, WEXITSTATUS(exitStatus));
+}
+
 TEST(AshmemTest, ForkTest) {
     const size_t size = getpagesize();
     std::vector<uint8_t> data(size);
@@ -84,28 +93,30 @@
     ASSERT_EQ(0, memcmp(region1, data.data(), size));
     EXPECT_EQ(0, munmap(region1, size));
 
-    // This part of the test forks a separate process via ASSERT_EXIT() and
-    // clears the ashmem buffer.
-    //
-    // This is to ensure that updates to the contents of the buffer are visible
-    // across processes with a reference to the buffer.
-    ASSERT_EXIT(
-        {
-            if (!ashmem_valid(fd)) {
-                _exit(3);
-            }
-            void* region2 = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
-            if (region2 == MAP_FAILED) {
-                _exit(1);
-            }
-            if (memcmp(region2, data.data(), size) != 0) {
-                _exit(2);
-            }
-            memset(region2, 0, size);
-            munmap(region2, size);
-            _exit(0);
-        },
-        ::testing::ExitedWithCode(0), "");
+
+    pid_t pid = fork();
+    if (!pid) {
+        if (!ashmem_valid(fd)) {
+            _exit(3);
+        }
+
+        void *region2 = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+        if (region2 == MAP_FAILED) {
+            _exit(1);
+        } else if (memcmp(region2, data.data(), size) != 0){
+            _exit(2);
+        }
+
+        // Clear the ashmem buffer here to ensure that updates to the contents
+        // of the buffer are visible across processes with a reference to the
+        // buffer.
+        memset(region2, 0, size);
+        munmap(region2, size);
+        _exit(0);
+    } else {
+        ASSERT_GT(pid, 0);
+        ASSERT_NO_FATAL_FAILURE(waitForChildProcessExit(pid));
+    }
 
     memset(data.data(), 0, size);
     void *region2;
@@ -206,26 +217,22 @@
 
     ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd, PROT_READ | PROT_WRITE));
 
-    // This part of the test forks a process via ASSERT_EXIT()
-    // and has the child process change the mapping permissions of the
-    // buffer to read-only.
-    //
-    // The intent of this is to ensure that updates to the buffer's
-    // mapping permissions are visible across processes that reference the
-    // buffer.
-    //
-    // In this case, the parent process attempts to map the buffer with write
-    // permission, which should fail.
-    ASSERT_EXIT(
-        {
-            if (!ashmem_valid(fd)) {
-                _exit(3);
-            } else if (ashmem_set_prot_region(fd, PROT_READ) == -1) {
-                _exit(1);
-            }
-            _exit(0);
-        },
-        ::testing::ExitedWithCode(0), "");
+    pid_t pid = fork();
+    if (!pid) {
+        // Change buffer mapping permissions to read-only to ensure that
+        // updates to the buffer's mapping permissions are visible across
+        // processes that reference the buffer.
+        if (!ashmem_valid(fd)) {
+            _exit(3);
+        } else if (ashmem_set_prot_region(fd, PROT_READ) == -1) {
+            _exit(1);
+        }
+        _exit(0);
+    } else {
+        ASSERT_GT(pid, 0);
+        ASSERT_NO_FATAL_FAILURE(waitForChildProcessExit(pid));
+    }
+
     ASSERT_NO_FATAL_FAILURE(TestProtDenied(fd, size, PROT_WRITE));
 }
 
@@ -245,14 +252,10 @@
         EXPECT_EQ(0, munmap(region, size));
     }
 
-    // This part of the test creates a child process via ASSERT_EXIT()
-    // that clears each of the ashmem buffers that were created earlier.
-    //
-    // The intent of this is for the parent process to check each region to make
-    // sure that the updates from the child process are visible, thereby showing
-    // that updates across multiple shared buffers are visible across multiple
-    // processes.
-    ASSERT_EXIT({
+    pid_t pid = fork();
+    if (!pid) {
+        // Clear each ashmem buffer in the context of the child process to
+        // ensure that the updates are visible to the parent process later.
         for (int i = 0; i < nRegions; i++) {
             if (!ashmem_valid(fd[i])) {
                 _exit(3);
@@ -269,7 +272,10 @@
             munmap(region, size);
         }
         _exit(0);
-    }, ::testing::ExitedWithCode(0), "");
+    } else {
+        ASSERT_GT(pid, 0);
+        ASSERT_NO_FATAL_FAILURE(waitForChildProcessExit(pid));
+    }
 
     memset(data.data(), 0, size);
     for (int i = 0; i < nRegions; i++) {