本文整理汇总了C++中ProcessLaunchInfo::GetArguments方法的典型用法代码示例。如果您正苦于以下问题:C++ ProcessLaunchInfo::GetArguments方法的具体用法?C++ ProcessLaunchInfo::GetArguments怎么用?C++ ProcessLaunchInfo::GetArguments使用的例子?那么, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类ProcessLaunchInfo
的用法示例。
在下文中一共展示了ProcessLaunchInfo::GetArguments方法的9个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: HostProcess
HostProcess
ProcessLauncherAndroid::LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error)
{
// TODO: Handle other launch parameters specified in launc_info
char exe_path[PATH_MAX];
launch_info.GetExecutableFile().GetPath(exe_path, sizeof(exe_path));
lldb::pid_t pid = ::fork();
if (pid == static_cast<lldb::pid_t>(-1))
{
// Fork failed
error.SetErrorStringWithFormat("Fork failed with error message: %s", strerror(errno));
return HostProcess(LLDB_INVALID_PROCESS_ID);
}
else if (pid == 0)
{
if (const lldb_private::FileAction *file_action = launch_info.GetFileActionForFD(STDIN_FILENO)) {
const char* path = file_action->GetPath();
if (path && ::strlen(path))
if (!DupDescriptor(path, STDIN_FILENO, O_RDONLY))
exit(-1);
}
if (const lldb_private::FileAction *file_action = launch_info.GetFileActionForFD(STDOUT_FILENO)) {
const char* path = file_action->GetPath();
if (path && ::strlen(path))
if (!DupDescriptor(path, STDOUT_FILENO, O_WRONLY | O_CREAT | O_TRUNC))
exit(-1);
}
if (const lldb_private::FileAction *file_action = launch_info.GetFileActionForFD(STDERR_FILENO)) {
const char* path = file_action->GetPath();
if (path && ::strlen(path))
if (!DupDescriptor(path, STDERR_FILENO, O_WRONLY | O_CREAT | O_TRUNC))
exit(-1);
}
// Child process
const char **argv = launch_info.GetArguments().GetConstArgumentVector();
Args env = launch_info.GetEnvironmentEntries();
FixupEnvironment(env);
const char **envp = env.GetConstArgumentVector();
const char *working_dir = launch_info.GetWorkingDirectory();
if (working_dir != nullptr && working_dir[0])
{
if (::chdir(working_dir) != 0)
exit(-1);
}
execve(argv[0],
const_cast<char *const *>(argv),
const_cast<char *const *>(envp));
exit(-1);
}
return HostProcess(pid);
}
示例2: WorkingDir
Error
ProcessPOSIX::DoLaunch (Module *module,
ProcessLaunchInfo &launch_info)
{
Error error;
assert(m_monitor == NULL);
const char* working_dir = launch_info.GetWorkingDirectory();
if (working_dir) {
FileSpec WorkingDir(working_dir, true);
if (!WorkingDir || WorkingDir.GetFileType() != FileSpec::eFileTypeDirectory)
{
error.SetErrorStringWithFormat("No such file or directory: %s", working_dir);
return error;
}
}
SetPrivateState(eStateLaunching);
const lldb_private::FileAction *file_action;
// Default of NULL will mean to use existing open file descriptors
const char *stdin_path = NULL;
const char *stdout_path = NULL;
const char *stderr_path = NULL;
const char * dbg_pts_path = launch_info.GetPTY().GetSlaveName(NULL,0);
file_action = launch_info.GetFileActionForFD (STDIN_FILENO);
stdin_path = GetFilePath(file_action, stdin_path, dbg_pts_path);
file_action = launch_info.GetFileActionForFD (STDOUT_FILENO);
stdout_path = GetFilePath(file_action, stdout_path, dbg_pts_path);
file_action = launch_info.GetFileActionForFD (STDERR_FILENO);
stderr_path = GetFilePath(file_action, stderr_path, dbg_pts_path);
m_monitor = new ProcessMonitor (this,
module,
launch_info.GetArguments().GetConstArgumentVector(),
launch_info.GetEnvironmentEntries().GetConstArgumentVector(),
stdin_path,
stdout_path,
stderr_path,
working_dir,
launch_info,
error);
m_module = module;
if (!error.Success())
return error;
SetSTDIOFileDescriptor(m_monitor->GetTerminalFD());
SetID(m_monitor->GetPID());
return error;
}
示例3: assert
Error
ProcessFreeBSD::DoLaunch (Module *module,
ProcessLaunchInfo &launch_info)
{
Error error;
assert(m_monitor == NULL);
FileSpec working_dir = launch_info.GetWorkingDirectory();
if (working_dir &&
(!working_dir.ResolvePath() ||
working_dir.GetFileType() != FileSpec::eFileTypeDirectory))
{
error.SetErrorStringWithFormat("No such file or directory: %s",
working_dir.GetCString());
return error;
}
SetPrivateState(eStateLaunching);
const lldb_private::FileAction *file_action;
// Default of empty will mean to use existing open file descriptors
FileSpec stdin_file_spec{};
FileSpec stdout_file_spec{};
FileSpec stderr_file_spec{};
const FileSpec dbg_pts_file_spec{launch_info.GetPTY().GetSlaveName(NULL,0), false};
file_action = launch_info.GetFileActionForFD (STDIN_FILENO);
stdin_file_spec = GetFileSpec(file_action, stdin_file_spec, dbg_pts_file_spec);
file_action = launch_info.GetFileActionForFD (STDOUT_FILENO);
stdout_file_spec = GetFileSpec(file_action, stdout_file_spec, dbg_pts_file_spec);
file_action = launch_info.GetFileActionForFD (STDERR_FILENO);
stderr_file_spec = GetFileSpec(file_action, stderr_file_spec, dbg_pts_file_spec);
m_monitor = new ProcessMonitor(this,
module,
launch_info.GetArguments().GetConstArgumentVector(),
launch_info.GetEnvironmentEntries().GetConstArgumentVector(),
stdin_file_spec,
stdout_file_spec,
stderr_file_spec,
working_dir,
launch_info,
error);
m_module = module;
if (!error.Success())
return error;
int terminal = m_monitor->GetTerminalFD();
if (terminal >= 0) {
// The reader thread will close the file descriptor when done, so we pass it a copy.
int stdio = fcntl(terminal, F_DUPFD_CLOEXEC, 0);
if (stdio == -1) {
error.SetErrorToErrno();
return error;
}
SetSTDIOFileDescriptor(stdio);
}
SetID(m_monitor->GetPID());
return error;
}
示例4: RunShellCommand
Error
Host::ShellExpandArguments (ProcessLaunchInfo &launch_info)
{
Error error;
if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments))
{
FileSpec expand_tool_spec;
if (!HostInfo::GetLLDBPath(lldb::ePathTypeSupportExecutableDir, expand_tool_spec))
{
error.SetErrorString("could not find argdumper tool");
return error;
}
expand_tool_spec.AppendPathComponent("argdumper.exe");
if (!expand_tool_spec.Exists())
{
error.SetErrorString("could not find argdumper tool");
return error;
}
std::string quoted_cmd_string;
launch_info.GetArguments().GetQuotedCommandString(quoted_cmd_string);
std::replace(quoted_cmd_string.begin(), quoted_cmd_string.end(), '\\', '/');
StreamString expand_command;
expand_command.Printf("%s %s",
expand_tool_spec.GetPath().c_str(),
quoted_cmd_string.c_str());
int status;
std::string output;
RunShellCommand(expand_command.GetData(), launch_info.GetWorkingDirectory(), &status, nullptr, &output, 10);
if (status != 0)
{
error.SetErrorStringWithFormat("argdumper exited with error %d", status);
return error;
}
auto data_sp = StructuredData::ParseJSON(output);
if (!data_sp)
{
error.SetErrorString("invalid JSON");
return error;
}
auto dict_sp = data_sp->GetAsDictionary();
if (!data_sp)
{
error.SetErrorString("invalid JSON");
return error;
}
auto args_sp = dict_sp->GetObjectForDotSeparatedPath("arguments");
if (!args_sp)
{
error.SetErrorString("invalid JSON");
return error;
}
auto args_array_sp = args_sp->GetAsArray();
if (!args_array_sp)
{
error.SetErrorString("invalid JSON");
return error;
}
launch_info.GetArguments().Clear();
for (size_t i = 0;
i < args_array_sp->GetSize();
i++)
{
auto item_sp = args_array_sp->GetItemAtIndex(i);
if (!item_sp)
continue;
auto str_sp = item_sp->GetAsString();
if (!str_sp)
continue;
launch_info.GetArguments().AppendArgument(str_sp->GetValue().c_str());
}
}
return error;
}
示例5: sigemptyset
Error
Host::LaunchProcessPosixSpawn(const char *exe_path, const ProcessLaunchInfo &launch_info, lldb::pid_t &pid)
{
Error error;
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS));
posix_spawnattr_t attr;
error.SetError( ::posix_spawnattr_init (&attr), eErrorTypePOSIX);
if (error.Fail() || log)
error.PutToLog(log, "::posix_spawnattr_init ( &attr )");
if (error.Fail())
return error;
// Make a quick class that will cleanup the posix spawn attributes in case
// we return in the middle of this function.
lldb_utility::CleanUp <posix_spawnattr_t *, int> posix_spawnattr_cleanup(&attr, posix_spawnattr_destroy);
sigset_t no_signals;
sigset_t all_signals;
sigemptyset (&no_signals);
sigfillset (&all_signals);
::posix_spawnattr_setsigmask(&attr, &no_signals);
#if defined (__linux__) || defined (__FreeBSD__)
::posix_spawnattr_setsigdefault(&attr, &no_signals);
#else
::posix_spawnattr_setsigdefault(&attr, &all_signals);
#endif
short flags = GetPosixspawnFlags(launch_info);
error.SetError( ::posix_spawnattr_setflags (&attr, flags), eErrorTypePOSIX);
if (error.Fail() || log)
error.PutToLog(log, "::posix_spawnattr_setflags ( &attr, flags=0x%8.8x )", flags);
if (error.Fail())
return error;
// posix_spawnattr_setbinpref_np appears to be an Apple extension per:
// http://www.unix.com/man-page/OSX/3/posix_spawnattr_setbinpref_np/
#if defined (__APPLE__) && !defined (__arm__)
// Don't set the binpref if a shell was provided. After all, that's only going to affect what version of the shell
// is launched, not what fork of the binary is launched. We insert "arch --arch <ARCH> as part of the shell invocation
// to do that job on OSX.
if (launch_info.GetShell() == nullptr)
{
// We don't need to do this for ARM, and we really shouldn't now that we
// have multiple CPU subtypes and no posix_spawnattr call that allows us
// to set which CPU subtype to launch...
const ArchSpec &arch_spec = launch_info.GetArchitecture();
cpu_type_t cpu = arch_spec.GetMachOCPUType();
cpu_type_t sub = arch_spec.GetMachOCPUSubType();
if (cpu != 0 &&
cpu != static_cast<cpu_type_t>(UINT32_MAX) &&
cpu != static_cast<cpu_type_t>(LLDB_INVALID_CPUTYPE) &&
!(cpu == 0x01000007 && sub == 8)) // If haswell is specified, don't try to set the CPU type or we will fail
{
size_t ocount = 0;
error.SetError( ::posix_spawnattr_setbinpref_np (&attr, 1, &cpu, &ocount), eErrorTypePOSIX);
if (error.Fail() || log)
error.PutToLog(log, "::posix_spawnattr_setbinpref_np ( &attr, 1, cpu_type = 0x%8.8x, count => %llu )", cpu, (uint64_t)ocount);
if (error.Fail() || ocount != 1)
return error;
}
}
#endif
const char *tmp_argv[2];
char * const *argv = (char * const*)launch_info.GetArguments().GetConstArgumentVector();
char * const *envp = (char * const*)launch_info.GetEnvironmentEntries().GetConstArgumentVector();
if (argv == NULL)
{
// posix_spawn gets very unhappy if it doesn't have at least the program
// name in argv[0]. One of the side affects I have noticed is the environment
// variables don't make it into the child process if "argv == NULL"!!!
tmp_argv[0] = exe_path;
tmp_argv[1] = NULL;
argv = (char * const*)tmp_argv;
}
#if !defined (__APPLE__)
// manage the working directory
char current_dir[PATH_MAX];
current_dir[0] = '\0';
#endif
FileSpec working_dir{launch_info.GetWorkingDirectory()};
if (working_dir)
{
#if defined (__APPLE__)
// Set the working directory on this thread only
if (__pthread_chdir(working_dir.GetCString()) < 0) {
if (errno == ENOENT) {
error.SetErrorStringWithFormat("No such file or directory: %s",
working_dir.GetCString());
} else if (errno == ENOTDIR) {
error.SetErrorStringWithFormat("Path doesn't name a directory: %s",
//.........这里部分代码省略.........
示例6: ChildFunc
static void LLVM_ATTRIBUTE_NORETURN ChildFunc(int error_fd,
const ProcessLaunchInfo &info) {
if (info.GetFlags().Test(eLaunchFlagLaunchInSeparateProcessGroup)) {
if (setpgid(0, 0) != 0)
ExitWithError(error_fd, "setpgid");
}
for (size_t i = 0; i < info.GetNumFileActions(); ++i) {
const FileAction &action = *info.GetFileActionAtIndex(i);
switch (action.GetAction()) {
case FileAction::eFileActionClose:
if (close(action.GetFD()) != 0)
ExitWithError(error_fd, "close");
break;
case FileAction::eFileActionDuplicate:
if (dup2(action.GetFD(), action.GetActionArgument()) == -1)
ExitWithError(error_fd, "dup2");
break;
case FileAction::eFileActionOpen:
DupDescriptor(error_fd, action.GetFileSpec(), action.GetFD(),
action.GetActionArgument());
break;
case FileAction::eFileActionNone:
break;
}
}
const char **argv = info.GetArguments().GetConstArgumentVector();
// Change working directory
if (info.GetWorkingDirectory() &&
0 != ::chdir(info.GetWorkingDirectory().GetCString()))
ExitWithError(error_fd, "chdir");
DisableASLRIfRequested(error_fd, info);
Environment env = info.GetEnvironment();
FixupEnvironment(env);
Environment::Envp envp = env.getEnvp();
// Clear the signal mask to prevent the child from being affected by any
// masking done by the parent.
sigset_t set;
if (sigemptyset(&set) != 0 ||
pthread_sigmask(SIG_SETMASK, &set, nullptr) != 0)
ExitWithError(error_fd, "pthread_sigmask");
if (info.GetFlags().Test(eLaunchFlagDebug)) {
// Do not inherit setgid powers.
if (setgid(getgid()) != 0)
ExitWithError(error_fd, "setgid");
// HACK:
// Close everything besides stdin, stdout, and stderr that has no file
// action to avoid leaking. Only do this when debugging, as elsewhere we
// actually rely on passing open descriptors to child processes.
for (int fd = 3; fd < sysconf(_SC_OPEN_MAX); ++fd)
if (!info.GetFileActionForFD(fd) && fd != error_fd)
close(fd);
// Start tracing this child that is about to exec.
if (ptrace(PT_TRACE_ME, 0, nullptr, 0) == -1)
ExitWithError(error_fd, "ptrace");
}
// Execute. We should never return...
execve(argv[0], const_cast<char *const *>(argv), envp);
#if defined(__linux__)
if (errno == ETXTBSY) {
// On android M and earlier we can get this error because the adb daemon
// can hold a write handle on the executable even after it has finished
// uploading it. This state lasts only a short time and happens only when
// there are many concurrent adb commands being issued, such as when
// running the test suite. (The file remains open when someone does an "adb
// shell" command in the fork() child before it has had a chance to exec.)
// Since this state should clear up quickly, wait a while and then give it
// one more go.
usleep(50000);
execve(argv[0], const_cast<char *const *>(argv), envp);
}
#endif
// ...unless exec fails. In which case we definitely need to end the child
// here.
ExitWithError(error_fd, "execve");
}
示例7: getenv
Error
GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,
uint16_t in_port,
ProcessLaunchInfo &launch_info,
uint16_t &out_port)
{
Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
if (log)
log->Printf ("GDBRemoteCommunication::%s(hostname=%s, in_port=%" PRIu16 ", out_port=%" PRIu16, __FUNCTION__, hostname ? hostname : "<empty>", in_port, out_port);
out_port = in_port;
Error error;
// If we locate debugserver, keep that located version around
static FileSpec g_debugserver_file_spec;
char debugserver_path[PATH_MAX];
FileSpec &debugserver_file_spec = launch_info.GetExecutableFile();
// Always check to see if we have an environment override for the path
// to the debugserver to use and use it if we do.
const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH");
if (env_debugserver_path)
{
debugserver_file_spec.SetFile (env_debugserver_path, false);
if (log)
log->Printf ("GDBRemoteCommunication::%s() gdb-remote stub exe path set from environment variable: %s", __FUNCTION__, env_debugserver_path);
}
else
debugserver_file_spec = g_debugserver_file_spec;
bool debugserver_exists = debugserver_file_spec.Exists();
if (!debugserver_exists)
{
// The debugserver binary is in the LLDB.framework/Resources
// directory.
if (HostInfo::GetLLDBPath(ePathTypeSupportExecutableDir, debugserver_file_spec))
{
debugserver_file_spec.AppendPathComponent (DEBUGSERVER_BASENAME);
debugserver_exists = debugserver_file_spec.Exists();
if (debugserver_exists)
{
if (log)
log->Printf ("GDBRemoteCommunication::%s() found gdb-remote stub exe '%s'", __FUNCTION__, debugserver_file_spec.GetPath ().c_str ());
g_debugserver_file_spec = debugserver_file_spec;
}
else
{
if (log)
log->Printf ("GDBRemoteCommunication::%s() could not find gdb-remote stub exe '%s'", __FUNCTION__, debugserver_file_spec.GetPath ().c_str ());
g_debugserver_file_spec.Clear();
debugserver_file_spec.Clear();
}
}
}
if (debugserver_exists)
{
debugserver_file_spec.GetPath (debugserver_path, sizeof(debugserver_path));
Args &debugserver_args = launch_info.GetArguments();
debugserver_args.Clear();
char arg_cstr[PATH_MAX];
// Start args with "debugserver /file/path -r --"
debugserver_args.AppendArgument(debugserver_path);
#if !defined(__APPLE__)
// First argument to lldb-server must be mode in which to run.
debugserver_args.AppendArgument("gdbserver");
#endif
// If a host and port is supplied then use it
char host_and_port[128];
if (hostname)
{
snprintf (host_and_port, sizeof(host_and_port), "%s:%u", hostname, in_port);
debugserver_args.AppendArgument(host_and_port);
}
else
{
host_and_port[0] = '\0';
}
// use native registers, not the GDB registers
debugserver_args.AppendArgument("--native-regs");
if (launch_info.GetLaunchInSeparateProcessGroup())
{
debugserver_args.AppendArgument("--setsid");
}
llvm::SmallString<PATH_MAX> named_pipe_path;
Pipe port_pipe;
bool listen = false;
if (host_and_port[0])
{
// Create a temporary file to get the stdout/stderr and redirect the
// output of the command into this file. We will later read this file
//.........这里部分代码省略.........
示例8: DoLaunch
Status ProcessFreeBSD::DoLaunch(Module *module,
ProcessLaunchInfo &launch_info) {
Status error;
assert(m_monitor == NULL);
FileSpec working_dir = launch_info.GetWorkingDirectory();
if (working_dir) {
FileSystem::Instance().Resolve(working_dir);
if (!FileSystem::Instance().IsDirectory(working_dir.GetPath())) {
error.SetErrorStringWithFormat("No such file or directory: %s",
working_dir.GetCString());
return error;
}
}
SetPrivateState(eStateLaunching);
const lldb_private::FileAction *file_action;
// Default of empty will mean to use existing open file descriptors
FileSpec stdin_file_spec{};
FileSpec stdout_file_spec{};
FileSpec stderr_file_spec{};
const FileSpec dbg_pts_file_spec{launch_info.GetPTY().GetSlaveName(NULL, 0)};
file_action = launch_info.GetFileActionForFD(STDIN_FILENO);
stdin_file_spec =
GetFileSpec(file_action, stdin_file_spec, dbg_pts_file_spec);
file_action = launch_info.GetFileActionForFD(STDOUT_FILENO);
stdout_file_spec =
GetFileSpec(file_action, stdout_file_spec, dbg_pts_file_spec);
file_action = launch_info.GetFileActionForFD(STDERR_FILENO);
stderr_file_spec =
GetFileSpec(file_action, stderr_file_spec, dbg_pts_file_spec);
m_monitor = new ProcessMonitor(
this, module, launch_info.GetArguments().GetConstArgumentVector(),
launch_info.GetEnvironment(), stdin_file_spec, stdout_file_spec,
stderr_file_spec, working_dir, launch_info, error);
m_module = module;
if (!error.Success())
return error;
int terminal = m_monitor->GetTerminalFD();
if (terminal >= 0) {
// The reader thread will close the file descriptor when done, so we pass it a
// copy.
#ifdef F_DUPFD_CLOEXEC
int stdio = fcntl(terminal, F_DUPFD_CLOEXEC, 0);
if (stdio == -1) {
error.SetErrorToErrno();
return error;
}
#else
// Special case when F_DUPFD_CLOEXEC does not exist (Debian kFreeBSD)
int stdio = fcntl(terminal, F_DUPFD, 0);
if (stdio == -1) {
error.SetErrorToErrno();
return error;
}
stdio = fcntl(terminal, F_SETFD, FD_CLOEXEC);
if (stdio == -1) {
error.SetErrorToErrno();
return error;
}
#endif
SetSTDIOFileDescriptor(stdio);
}
SetID(m_monitor->GetPID());
return error;
}
示例9: ChildFunc
static void LLVM_ATTRIBUTE_NORETURN ChildFunc(int error_fd,
const ProcessLaunchInfo &info) {
// First, make sure we disable all logging. If we are logging to stdout, our
// logs can be
// mistaken for inferior output.
Log::DisableAllLogChannels(nullptr);
// Do not inherit setgid powers.
if (setgid(getgid()) != 0)
ExitWithError(error_fd, "setgid");
if (info.GetFlags().Test(eLaunchFlagLaunchInSeparateProcessGroup)) {
if (setpgid(0, 0) != 0)
ExitWithError(error_fd, "setpgid");
}
for (size_t i = 0; i < info.GetNumFileActions(); ++i) {
const FileAction &action = *info.GetFileActionAtIndex(i);
switch (action.GetAction()) {
case FileAction::eFileActionClose:
if (close(action.GetFD()) != 0)
ExitWithError(error_fd, "close");
break;
case FileAction::eFileActionDuplicate:
if (dup2(action.GetFD(), action.GetActionArgument()) == -1)
ExitWithError(error_fd, "dup2");
break;
case FileAction::eFileActionOpen:
DupDescriptor(error_fd, action.GetFileSpec(), action.GetFD(),
action.GetActionArgument());
break;
case FileAction::eFileActionNone:
break;
}
}
const char **argv = info.GetArguments().GetConstArgumentVector();
// Change working directory
if (info.GetWorkingDirectory() &&
0 != ::chdir(info.GetWorkingDirectory().GetCString()))
ExitWithError(error_fd, "chdir");
// Disable ASLR if requested.
if (info.GetFlags().Test(lldb::eLaunchFlagDisableASLR)) {
const unsigned long personality_get_current = 0xffffffff;
int value = personality(personality_get_current);
if (value == -1)
ExitWithError(error_fd, "personality get");
value = personality(ADDR_NO_RANDOMIZE | value);
if (value == -1)
ExitWithError(error_fd, "personality set");
}
Args env = info.GetEnvironmentEntries();
FixupEnvironment(env);
const char **envp = env.GetConstArgumentVector();
// Clear the signal mask to prevent the child from being affected by
// any masking done by the parent.
sigset_t set;
if (sigemptyset(&set) != 0 ||
pthread_sigmask(SIG_SETMASK, &set, nullptr) != 0)
ExitWithError(error_fd, "pthread_sigmask");
if (info.GetFlags().Test(eLaunchFlagDebug)) {
// HACK:
// Close everything besides stdin, stdout, and stderr that has no file
// action to avoid leaking. Only do this when debugging, as elsewhere we
// actually rely on
// passing open descriptors to child processes.
for (int fd = 3; fd < sysconf(_SC_OPEN_MAX); ++fd)
if (!info.GetFileActionForFD(fd) && fd != error_fd)
close(fd);
// Start tracing this child that is about to exec.
if (ptrace(PTRACE_TRACEME, 0, nullptr, nullptr) == -1)
ExitWithError(error_fd, "ptrace");
}
// Execute. We should never return...
execve(argv[0], const_cast<char *const *>(argv),
const_cast<char *const *>(envp));
if (errno == ETXTBSY) {
// On android M and earlier we can get this error because the adb deamon can
// hold a write
// handle on the executable even after it has finished uploading it. This
// state lasts
// only a short time and happens only when there are many concurrent adb
// commands being
// issued, such as when running the test suite. (The file remains open when
// someone does
// an "adb shell" command in the fork() child before it has had a chance to
// exec.) Since
// this state should clear up quickly, wait a while and then give it one
// more go.
usleep(50000);
execve(argv[0], const_cast<char *const *>(argv),
//.........这里部分代码省略.........