Fix flaky netd_integration_test in Cuttlefish

Use vfork/posix_spawn  instead of fork.

Fix test items:
netd_integration_test
 TetherStartStopStatus
 ClatdStartStop

Bug: 124363517
Test: built, flashed, booted
      system/netd/tests/runtests.sh pass
      manual test with remove dnsmasq/clatd, netd works fine

Change-Id: I43880bd8693112fab46a0931457ff468ae01b305
diff --git a/server/TetherController.cpp b/server/TetherController.cpp
index 75cda7d..daa07b4 100644
--- a/server/TetherController.cpp
+++ b/server/TetherController.cpp
@@ -113,6 +113,27 @@
     return !strcmp(BP_TOOLS_MODE, bootmode);
 }
 
+pid_t vfork_and_exec(const char* path, char* const argv[], int pipefd[2]) {
+    auto pid = vfork();
+    if (pid) {
+        // Parent process, or vfork() failed. Let caller deal with it.
+        return pid;
+    }
+
+    // Don't modify any memory between vfork and execv.
+    // Changing state of file descriptors would be fine.
+    // dup2 creates fd without CLOEXEC, dnsmasq will receive commands through the
+    // duplicated fd.
+    if (dup2(pipefd[0], STDIN_FILENO) != STDIN_FILENO) {
+        // dup2 failed
+        _exit(EXIT_FAILURE);
+    }
+    execv(path, argv);
+    // Should never get here!
+    _exit(EXIT_FAILURE);
+    return pid;
+}
+
 }  // namespace
 
 auto TetherController::iptablesRestoreFunction = execIptablesRestoreWithOutput;
@@ -195,47 +216,24 @@
 
     ALOGD("Starting tethering services");
 
-    pid_t pid;
     int pipefd[2];
 
-    if (pipe(pipefd) < 0) {
+    if (pipe2(pipefd, O_CLOEXEC) < 0) {
         int res = errno;
-        ALOGE("pipe failed (%s)", strerror(errno));
+        ALOGE("pipe2() failed (%s)", strerror(errno));
         return -res;
     }
 
-    /*
-     * TODO: Create a monitoring thread to handle and restart
-     * the daemon if it exits prematurely
-     */
-    if ((pid = fork()) < 0) {
-        int res = errno;
-        ALOGE("fork failed (%s)", strerror(errno));
-        close(pipefd[0]);
-        close(pipefd[1]);
-        return -res;
-    }
+    // Set parameters
+    Fwmark fwmark;
+    fwmark.netId = NetworkController::LOCAL_NET_ID;
+    fwmark.explicitlySelected = true;
+    fwmark.protectedFromVpn = true;
+    fwmark.permission = PERMISSION_SYSTEM;
+    char markStr[UINT32_HEX_STRLEN];
+    snprintf(markStr, sizeof(markStr), "0x%x", fwmark.intValue);
 
-    if (!pid) {
-        close(pipefd[1]);
-        if (pipefd[0] != STDIN_FILENO) {
-            if (dup2(pipefd[0], STDIN_FILENO) != STDIN_FILENO) {
-                int res = errno;
-                ALOGE("dup2 failed (%s)", strerror(errno));
-                return -res;
-            }
-            close(pipefd[0]);
-        }
-
-        Fwmark fwmark;
-        fwmark.netId = NetworkController::LOCAL_NET_ID;
-        fwmark.explicitlySelected = true;
-        fwmark.protectedFromVpn = true;
-        fwmark.permission = PERMISSION_SYSTEM;
-        char markStr[UINT32_HEX_STRLEN];
-        snprintf(markStr, sizeof(markStr), "0x%x", fwmark.intValue);
-
-        std::vector<const std::string> argVector = {
+    std::vector<const std::string> argVector = {
             "/system/bin/dnsmasq",
             "--keep-in-foreground",
             "--no-resolv",
@@ -244,35 +242,44 @@
             // TODO: pipe through metered status from ConnService
             "--dhcp-option-force=43,ANDROID_METERED",
             "--pid-file",
-            "--listen-mark", markStr,
-            "--user", kDnsmasqUsername,
-        };
+            "--listen-mark",
+            markStr,
+            "--user",
+            kDnsmasqUsername,
+    };
 
-        // DHCP server will be disabled if num_addrs == 0 and no --dhcp-range is passed.
-        for (int addrIndex = 0; addrIndex < num_addrs; addrIndex += 2) {
-            argVector.push_back(StringPrintf("--dhcp-range=%s,%s,1h", dhcp_ranges[addrIndex],
-                                             dhcp_ranges[addrIndex + 1]));
-        }
-
-        auto args = (char**)std::calloc(argVector.size() + 1, sizeof(char*));
-        for (unsigned i = 0; i < argVector.size(); i++) {
-            args[i] = (char*)argVector[i].c_str();
-        }
-
-        if (execv(args[0], args)) {
-            ALOGE("execv failed (%s)", strerror(errno));
-        }
-        ALOGE("Should never get here!");
-        _exit(-1);
-    } else {
-        close(pipefd[0]);
-        mDaemonPid = pid;
-        mDaemonFd = pipefd[1];
-        configureForTethering(true);
-        applyDnsInterfaces();
-        ALOGD("Tethering services running");
+    // DHCP server will be disabled if num_addrs == 0 and no --dhcp-range is
+    // passed.
+    for (int addrIndex = 0; addrIndex < num_addrs; addrIndex += 2) {
+        argVector.push_back(StringPrintf("--dhcp-range=%s,%s,1h", dhcp_ranges[addrIndex],
+                                         dhcp_ranges[addrIndex + 1]));
     }
 
+    auto args = (char**)std::calloc(argVector.size() + 1, sizeof(char*));
+    for (unsigned i = 0; i < argVector.size(); i++) {
+        args[i] = (char*)argVector[i].c_str();
+    }
+
+    /*
+     * TODO: Create a monitoring thread to handle and restart
+     * the daemon if it exits prematurely
+     */
+    pid_t pid = vfork_and_exec(args[0], args, pipefd);
+    int res = errno;
+    close(pipefd[0]);
+    free(args);
+    if (pid < 0) {
+        ALOGE("vfork & exec failed (%s)", strerror(errno));
+        close(pipefd[1]);
+        return -res;
+    }
+
+    mDaemonPid = pid;
+    mDaemonFd = pipefd[1];
+    configureForTethering(true);
+    applyDnsInterfaces();
+    ALOGD("Tethering services running");
+
     return 0;
 }