Bug 772734 - Fixes LaunchApp hang when launching. r=cjones

From 8010cffba6e3dec5f792e965aacb9621ef06e0d7 Mon Sep 17 00:00:00 2001
 plugin-container - v5
Added checks in case PR_DuplicateEnvironment or PR_Malloc fail
Added #ifdef so that only Android builds try to call PR_DuplicateEnvironment
Moved PR_DuplicateEnvironment function from mozglue into process_util_linux.cc
so that matched alloc/free calls happen under android.
---
 ipc/chromium/src/base/process_util_linux.cc |  146 +++++++++++++++++++++++++--
 1 file changed, 140 insertions(+), 6 deletions(-)
This commit is contained in:
Dave Hylands 2012-07-13 08:41:30 -07:00
parent 3fa91a8635
commit c01bd473a9

View File

@ -7,6 +7,7 @@
#include <ctype.h>
#include <dirent.h>
#include <fcntl.h>
#include <memory>
#include <unistd.h>
#include <string>
#include <sys/types.h>
@ -19,6 +20,20 @@
#include "base/string_tokenizer.h"
#include "base/string_util.h"
#ifdef ANDROID
#include <pthread.h>
/*
* 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<EnvironmentEnvp> mEnvp;
};
#endif // HAVE_PR_DUPLICATE_ENVIRONMENT
bool LaunchApp(const std::vector<std::string>& argv,
const file_handle_mapping_vector& fds_to_remap,
bool wait, ProcessHandle* process_handle) {
@ -50,6 +170,16 @@ bool LaunchApp(const std::vector<std::string>& 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<std::string>& argv,
CloseSuperfluousFds(fd_shuffle2);
for (size_t i = 0; i < argv.size(); i++)
argv_cstr[i] = const_cast<char*>(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<char*>(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);