diff --git a/ipc/chromium/src/base/process_util_linux.cc b/ipc/chromium/src/base/process_util_linux.cc index cf420763c73..1b013fe8be9 100644 --- a/ipc/chromium/src/base/process_util_linux.cc +++ b/ipc/chromium/src/base/process_util_linux.cc @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -19,6 +20,20 @@ #include "base/string_tokenizer.h" #include "base/string_util.h" +#ifdef ANDROID +#include +/* + * Currently, PR_DuplicateEnvironment is implemented in mozglue/build/BionicGlue.cpp + */ +#define HAVE_PR_DUPLICATE_ENVIRONMENT + +#include "plstr.h" +#include "prenv.h" +#include "prmem.h" +/* Temporary until we have PR_DuplicateEnvironment in prenv.h */ +extern "C" { NSPR_API(pthread_mutex_t *)PR_GetEnvLock(void); } +#endif + namespace { enum ParsingState { @@ -32,6 +47,111 @@ static mozilla::EnvironmentLog gProcessLog("MOZ_PROCESS_LOG"); namespace base { +#ifdef HAVE_PR_DUPLICATE_ENVIRONMENT +/* + * I tried to put PR_DuplicateEnvironment down in mozglue, but on android + * this winds up failing because the strdup/free calls wind up mismatching. + */ + +static char ** +PR_DuplicateEnvironment(void) +{ + char **result = NULL; + char **s; + char **d; + pthread_mutex_lock(PR_GetEnvLock()); + for (s = environ; *s != NULL; s++) + ; + if ((result = (char **)PR_Malloc(sizeof(char *) * (s - environ + 1))) != NULL) { + for (s = environ, d = result; *s != NULL; s++, d++) { + *d = PL_strdup(*s); + } + *d = NULL; + } + pthread_mutex_unlock(PR_GetEnvLock()); + return result; +} + +class EnvironmentEnvp +{ +public: + EnvironmentEnvp() + : mEnvp(PR_DuplicateEnvironment()) {} + + EnvironmentEnvp(const environment_map &em) + { + mEnvp = (char **)PR_Malloc(sizeof(char *) * (em.size() + 1)); + if (!mEnvp) { + return; + } + char **e = mEnvp; + for (environment_map::const_iterator it = em.begin(); + it != em.end(); ++it, ++e) { + std::string str = it->first; + str += "="; + str += it->second; + *e = PL_strdup(str.c_str()); + } + *e = NULL; + } + + ~EnvironmentEnvp() + { + if (!mEnvp) { + return; + } + for (char **e = mEnvp; *e; ++e) { + PL_strfree(*e); + } + PR_Free(mEnvp); + } + + char * const *AsEnvp() { return mEnvp; } + + void ToMap(environment_map &em) + { + if (!mEnvp) { + return; + } + em.clear(); + for (char **e = mEnvp; *e; ++e) { + const char *eq; + if ((eq = strchr(*e, '=')) != NULL) { + std::string varname(*e, eq - *e); + em[varname.c_str()] = &eq[1]; + } + } + } + +private: + char **mEnvp; +}; + +class Environment : public environment_map +{ +public: + Environment() + { + EnvironmentEnvp envp; + envp.ToMap(*this); + } + + char * const *AsEnvp() { + mEnvp.reset(new EnvironmentEnvp(*this)); + return mEnvp->AsEnvp(); + } + + void Merge(const environment_map &em) + { + for (const_iterator it = em.begin(); it != em.end(); ++it) { + (*this)[it->first] = it->second; + } + } +private: + std::auto_ptr mEnvp; +}; +#endif // HAVE_PR_DUPLICATE_ENVIRONMENT + bool LaunchApp(const std::vector& argv, const file_handle_mapping_vector& fds_to_remap, bool wait, ProcessHandle* process_handle) { @@ -50,6 +170,16 @@ bool LaunchApp(const std::vector& argv, fd_shuffle1.reserve(fds_to_remap.size()); fd_shuffle2.reserve(fds_to_remap.size()); +#ifdef HAVE_PR_DUPLICATE_ENVIRONMENT + Environment env; + env.Merge(env_vars_to_set); + char * const *envp = env.AsEnvp(); + if (!envp) { + DLOG(ERROR) << "FAILED to duplicate environment for: " << argv_cstr[0]; + return false; + } +#endif + pid_t pid = fork(); if (pid < 0) return false; @@ -66,19 +196,23 @@ bool LaunchApp(const std::vector& argv, CloseSuperfluousFds(fd_shuffle2); + for (size_t i = 0; i < argv.size(); i++) + argv_cstr[i] = const_cast(argv[i].c_str()); + argv_cstr[argv.size()] = NULL; + +#ifdef HAVE_PR_DUPLICATE_ENVIRONMENT + execve(argv_cstr[0], argv_cstr.get(), envp); +#else for (environment_map::const_iterator it = env_vars_to_set.begin(); it != env_vars_to_set.end(); ++it) { if (setenv(it->first.c_str(), it->second.c_str(), 1/*overwrite*/)) _exit(127); } - - for (size_t i = 0; i < argv.size(); i++) - argv_cstr[i] = const_cast(argv[i].c_str()); - argv_cstr[argv.size()] = NULL; - execvp(argv_cstr[0], argv_cstr.get()); + execv(argv_cstr[0], argv_cstr.get()); +#endif // if we get here, we're in serious trouble and should complain loudly DLOG(ERROR) << "FAILED TO exec() CHILD PROCESS, path: " << argv_cstr[0]; - exit(127); + _exit(127); } else { gProcessLog.print("==> process %d launched child process %d\n", GetCurrentProcId(), pid);