resolve merge conflicts of 8890690 to nyc-mr1-dev-plus-aosp

Change-Id: Ie5fbcd93c438ebb271a871224ea668593b5ce269
diff --git a/runtime/utils.cc b/runtime/utils.cc
index b676ae5..6d4889c 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -44,6 +44,7 @@
 #if defined(__APPLE__)
 #include "AvailabilityMacros.h"  // For MAC_OS_X_VERSION_MAX_ALLOWED
 #include <sys/syscall.h>
+#include <crt_externs.h>
 #endif
 
 #if defined(__linux__)
@@ -52,6 +53,22 @@
 
 namespace art {
 
+namespace {
+#ifdef __APPLE__
+inline char** GetEnviron() {
+  // When Google Test is built as a framework on MacOS X, the environ variable
+  // is unavailable. Apple's documentation (man environ) recommends using
+  // _NSGetEnviron() instead.
+  return *_NSGetEnviron();
+}
+#else
+// Some POSIX platforms expect you to declare environ. extern "C" makes
+// it reside in the global namespace.
+extern "C" char** environ;
+inline char** GetEnviron() { return environ; }
+#endif
+}  // namespace
+
 pid_t GetTid() {
 #if defined(__APPLE__)
   uint64_t owner;
@@ -1132,6 +1149,15 @@
   return filename;
 }
 
+const EnvSnapshot* TakeEnvSnapshot() {
+  EnvSnapshot* snapshot = new EnvSnapshot();
+  char** env = GetEnviron();
+  for (size_t i = 0; env[i] != nullptr; ++i) {
+    snapshot->name_value_pairs_.emplace_back(new std::string(env[i]));
+  }
+  return snapshot;
+}
+
 int ExecAndReturnCode(std::vector<std::string>& arg_vector, std::string* error_msg) {
   const std::string command_line(Join(arg_vector, ' '));
   CHECK_GE(arg_vector.size(), 1U) << command_line;
@@ -1155,8 +1181,20 @@
     // change process groups, so we don't get reaped by ProcessManager
     setpgid(0, 0);
 
-    execv(program, &args[0]);
-    PLOG(ERROR) << "Failed to execv(" << command_line << ")";
+    // The child inherits the environment unless the caller overrides it.
+    if (Runtime::Current() == nullptr || Runtime::Current()->GetEnvSnapshot() == nullptr) {
+      execv(program, &args[0]);
+    } else {
+      const EnvSnapshot* saved_snapshot = Runtime::Current()->GetEnvSnapshot();
+      // Allocation between fork and exec is not well-behaved.  Use a variable-length array instead.
+      char* envp[saved_snapshot->name_value_pairs_.size() + 1];
+      for (size_t i = 0; i < saved_snapshot->name_value_pairs_.size(); ++i) {
+        envp[i] = const_cast<char*>(saved_snapshot->name_value_pairs_[i]->c_str());
+      }
+      envp[saved_snapshot->name_value_pairs_.size()] = nullptr;
+      execve(program, &args[0], envp);
+    }
+    PLOG(ERROR) << "Failed to execve(" << command_line << ")";
     // _exit to avoid atexit handlers in child.
     _exit(1);
   } else {