Refactor ForkExecvp to improve locking behaviour

Do our own fork/exec rather than using a library. This leads to
many improvements:

- unite the output recording path with the other path
- never concatenate arguments with spaces
- never use the shell
- move setexeccon after fork, so we don't need to take the lock
- general code refactor while we're there

My tests:
- Ensure Marlin device boots and vold_prepare_subdirs is called
successfully
- Try adb shell sm set-virtual-disk true, see that eg sgdisk output is
logged.

weilongping@huawei.com's tests:
- unlock a user's de and ce directory;
- connect to a OTG storage device or a sdcard and ensure the mount logic be successful

Bug: 26735063
Bug: 113796163
Test: details in commit
Change-Id: I0976413529d7cbeebf5b8649660a385f9b036f04
diff --git a/Utils.h b/Utils.h
index 4d3522a..7976302 100644
--- a/Utils.h
+++ b/Utils.h
@@ -68,12 +68,8 @@
                                std::string* fsLabel);
 
 /* Returns either WEXITSTATUS() status, or a negative errno */
-status_t ForkExecvp(const std::vector<std::string>& args);
-status_t ForkExecvp(const std::vector<std::string>& args, security_context_t context);
-
-status_t ForkExecvp(const std::vector<std::string>& args, std::vector<std::string>& output);
-status_t ForkExecvp(const std::vector<std::string>& args, std::vector<std::string>& output,
-                    security_context_t context);
+status_t ForkExecvp(const std::vector<std::string>& args, std::vector<std::string>* output = nullptr,
+                    security_context_t context = nullptr);
 
 pid_t ForkExecvpAsync(const std::vector<std::string>& args);