用execvp实现时,运行adb,如果adb 服务没有启动,会启动adb服务,启动adb服务时,pipe返回的管道在读的时候堵塞了。

查看了popen的源码,发现popen是用sh -c来执行的,避免了这个问题

不知道sh -c做了些什么操作,使得popen可以避免这个问题

代码如下:

 #ifndef __RG_REDIRECT_H
#define __RG_REDIRECT_H //#ifdef _LINUX //for linux version #include <string> #ifdef _LINUX
#include <signal.h>
#endif #define WAIT_FOREVER 0 typedef void (*pReDirectCallBack)(const char* strOutput, bool bOver); class CRGReDirect
{
public:
CRGReDirect();
~CRGReDirect(); public:
//同步方式运行ADB命令,会阻塞。命令结果保存在strResult里面返回
//strCmd是需要执行的ADB命令。例如:adb_path devices
int RunCmdSync(std::string& strResult, const std::string& strCmd);
int RunCmdSync(std::string& strResult, const char *szCmd); //nTimeOut单位是秒
int RunCmdWithTimeOut(std::string& strResult, const std::string& strCmd, int nTimeOut = WAIT_FOREVER);
int RunCmdWithTimeOut(std::string& strResult, const char *szCmd, int nTimeOut = WAIT_FOREVER); //异步方式执行ADB命令,不会阻塞,直接返回线程的pid(失败返回-1)
//strCmd是需要执行的ADB命令。例如:adb_path devices
//ADB运行完成之后主动条用CallBack函数pFunc
//成功返回非零,失败返回-1
int RunCmdAsync(pReDirectCallBack pFunc, const std::string&strCmd);
int RunCmdAsync(pReDirectCallBack pFunc, const char *szCmd);
// const char* GetCmdResultString(void) const { return m_strResult.c_str(); } protected:
int RunCmd(pReDirectCallBack pFunc = NULL); void CancelCommand(); #ifdef _WIN32
HANDLE m_hTimer;
HANDLE m_hTimerQueue;
HANDLE m_hChildProcess; HANDLE m_hCmdThread;
static DWORD WINAPI RunProcess(void *arg);
static VOID CALLBACK HandleTimeOut( PVOID lpParameter, BOOLEAN TimerOrWaitFired);
#else
int SetTimer(int nSeconds, int nTimerID);
int KillTimer(timer_t nTimerID); timer_t m_timer_id;
pthread_t m_thread_id;
static void* RunProcess(void* arg);
static void HandleTimeOut(sigval_t v); pid_t *m_childpid; /* ptr to array allocated at run-time */
int m_maxfd; /* from our open_max(), {Prog openmax} */
FILE* m_hChildProcess; int open_max(void);
FILE * rgpopen(const char *cmdstring, const char *type); //模拟popen实现的版本
int rgpkill(FILE* fp); //根据文件指针关掉相应的进程
int rgpclose(FILE *fp); //关闭文件指针
#endif private:
std::string m_strResult;
std::string m_strCmd;
pReDirectCallBack m_adbCB;
volatile bool m_bAbort;
}; //#endif #endif
#ifndef _WIN32
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <pthread.h> // Compile and link with -pthread.
#include <cstring>
#include <cstdlib>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <errno.h>
#else
#include <Windows.h>
#endif #include "RGReDirect.h"
#include <cassert>
#include <cstdio> #define RG_TIMER_ID 51

std::string Trim(const std::string& strIn)
{
  std::string strMatch = " \t\r\n";
  size_t i = strIn.find_first_not_of(strMatch);
  size_t j = strIn.find_last_not_of(strMatch);


  if (i != std::string::npos)
    return strIn.substr(i, j-i+1);


  return "";
}

CRGReDirect::CRGReDirect()
: m_adbCB(NULL)
#ifdef _WIN32
, m_hChildProcess(NULL)
, m_hCmdThread(NULL)
, m_hTimer(NULL)
, m_hTimerQueue(NULL)
#else
, m_thread_id()
, m_timer_id()
, m_childpid(NULL)
, m_maxfd()
, m_hChildProcess(NULL)
#endif
, m_bAbort(false)
{
} CRGReDirect::~CRGReDirect()
{
#ifdef _WIN32
if (m_hCmdThread)
{
WaitForSingleObject(m_hCmdThread, INFINITE);
CloseHandle(m_hCmdThread);
}
if (m_hTimer) DeleteTimerQueueTimer(m_hTimerQueue, m_hTimer, NULL);
if (m_hTimerQueue) DeleteTimerQueue(m_hTimerQueue); #else
if (m_thread_id) pthread_join(m_thread_id, NULL);
if(m_timer_id) timer_delete(m_timer_id);
if(m_childpid) free(m_childpid);
#endif
} int CRGReDirect::RunCmd(pReDirectCallBack pFunc /* = NULL */)
{
m_bAbort = false;
m_strResult.clear(); #ifdef _WIN32
std::string strTmpCmd = m_strCmd;
HANDLE hChildStdoutRd, hChildStdoutWr, hStdout;
SECURITY_ATTRIBUTES saAttr; // Set the bInheritHandle flag so pipe handles are inherited.
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL; // Get the handle to the current STDOUT.
hStdout = GetStdHandle(STD_OUTPUT_HANDLE); // Create a pipe for the child process's STDOUT.
if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, ))
return -; // Ensure the read handle to the pipe for STDOUT is not inherited.
SetHandleInformation( hChildStdoutRd, HANDLE_FLAG_INHERIT, ); char *szCmdline = new char[strTmpCmd.size() + ];
memset(szCmdline, , strTmpCmd.size() + );
strcpy(szCmdline, strTmpCmd.c_str()); PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo; // Set up members of the PROCESS_INFORMATION structure.
ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) ); // Set up members of the STARTUPINFO structure.
ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = hChildStdoutWr;
siStartInfo.hStdOutput = hChildStdoutWr;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES; // Create the child process.
BOOL bFuncRetn = CreateProcess(NULL,
szCmdline, // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
CREATE_NO_WINDOW, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION if (bFuncRetn == )
{
delete [] szCmdline;
return -;
}
else
{
m_hChildProcess = piProcInfo.hProcess;
CloseHandle(piProcInfo.hThread); const int BUFSIZE = ;
DWORD dwRead;
char chBuf[BUFSIZE] = {}; // Close the write end of the pipe before reading from the
// read end of the pipe.
if (!CloseHandle(hChildStdoutWr))
{
delete [] szCmdline;
return -;
} // Read output from the child process
while (m_bAbort == false)
{
if( !ReadFile( hChildStdoutRd, chBuf, BUFSIZE, &dwRead,
NULL) || dwRead == ) break;
chBuf[dwRead] = '\0';
if(pFunc) pFunc(chBuf, false);
else m_strResult += chBuf;
} CloseHandle(hChildStdoutRd); if(m_bAbort == false) //非终止进程,则自然关闭
{
CloseHandle(m_hChildProcess);
m_hChildProcess = NULL;
} if(pFunc) pFunc("", true); delete [] szCmdline;
return ;
} #else char line[] = {};
std::string strTmpCmd = m_strCmd + " 2>&1"; //重定向stderr至stdout if((m_hChildProcess = rgpopen(strTmpCmd.c_str(), "r")) == NULL)
{
fprintf(stderr, "rgpopen error\n");
return -;
} while(m_bAbort == false)
{
if(fgets(line, , m_hChildProcess) == NULL)
break;
if(pFunc) pFunc(line, false);
else m_strResult += line;
} if(pFunc) pFunc("", true); if (m_bAbort == false) //非终止进程,则自然关闭
{
rgpclose(m_hChildProcess);
m_hChildProcess = NULL;
} return ; #endif
} int CRGReDirect::RunCmdSync(std::string& strResult, const std::string& strCmd)
{
return RunCmdSync(strResult, strCmd.c_str());
} int CRGReDirect::RunCmdSync(std::string& strResult, const char *szCmd)
{
m_strCmd = szCmd;
m_adbCB = NULL; int nRet = RunCmd(m_adbCB); strResult = m_strResult; return nRet;
} int CRGReDirect::RunCmdAsync(pReDirectCallBack pFunc, const std::string&strCmd)
{
return RunCmdAsync(pFunc, strCmd.c_str());
} int CRGReDirect::RunCmdAsync(pReDirectCallBack pFunc, const char *szCmd)
{
assert(pFunc); m_adbCB = pFunc;
m_strCmd = szCmd; #ifdef _WIN32
DWORD dwThread;
HANDLE hThread = CreateThread(NULL, , RunProcess, this, , &dwThread);
if (hThread)
{
m_hCmdThread = hThread;
return ;
}
else
{
return -;
}
#else
pthread_t pid; if (pthread_create(&pid, NULL, RunProcess, this) == )
{
m_thread_id = pid;
return ;
}
else
{
return -;
}
#endif
} int CRGReDirect::RunCmdWithTimeOut(std::string& strResult, const std::string& strCmd, int nTimeOut)
{
return RunCmdWithTimeOut(strResult, strCmd.c_str(), nTimeOut);
} int CRGReDirect::RunCmdWithTimeOut(std::string& strResult, const char* szCmd, int nTimeOut)
{
if(nTimeOut == WAIT_FOREVER)
{
return RunCmdSync(strResult, szCmd);
} m_adbCB = NULL;
m_strCmd = szCmd; #ifdef _WIN32
DWORD dwThread;
HANDLE hThread = CreateThread(NULL, , RunProcess, this, , &dwThread);
if (hThread)
{
m_hCmdThread = hThread;
m_hTimerQueue = CreateTimerQueue();
CreateTimerQueueTimer(&m_hTimer, m_hTimerQueue, HandleTimeOut, this, nTimeOut * , , ); WaitForSingleObject(m_hCmdThread, INFINITE);
CloseHandle(m_hCmdThread);
m_hCmdThread = NULL; DeleteTimerQueueTimer(m_hTimerQueue, m_hTimer, NULL);
DeleteTimerQueue(m_hTimerQueue);
m_hTimer = m_hTimerQueue = NULL; strResult = m_strResult; LOG("%s\n", strResult); return ;
}
else
{
return -;
}
#else
pthread_t pid; if (pthread_create(&pid, NULL, RunProcess, this) == )
{
m_thread_id = pid; SetTimer(nTimeOut, RG_TIMER_ID); pthread_join(m_thread_id, NULL);
m_thread_id = ; KillTimer(m_timer_id);
m_timer_id = ;
strResult = m_strResult; return ;
}
else
{
return -;
}
#endif
} #ifdef _WIN32
void CRGReDirect::HandleTimeOut(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
#else
void CRGReDirect::HandleTimeOut(sigval_t v)
#endif
{
#ifdef _WIN32
CRGReDirect* pThis = (CRGReDirect*)lpParameter;
#else
CRGReDirect* pThis = (CRGReDirect*)(v.sival_ptr);
#endif
if (pThis)
{
printf("cancel command on timeout\n");
pThis->CancelCommand();
} #ifdef _DEBUG
printf("TimeOut on exit.\n");
#endif
} void CRGReDirect::CancelCommand()
{
m_bAbort = true; #ifdef _WIN32
if (m_hChildProcess) //进程未退出,强行终止
{
TerminateProcess(m_hChildProcess, );
CloseHandle(m_hChildProcess);
m_hChildProcess = NULL;
}
#else
if (m_hChildProcess)
{
rgpkill(m_hChildProcess);
m_hChildProcess = NULL;
}
#endif
} #ifdef _WIN32
DWORD WINAPI CRGReDirect::RunProcess(void* arg)
#else
void* CRGReDirect::RunProcess(void* arg)
#endif
{
CRGReDirect* pThis = (CRGReDirect *)arg;
assert(pThis); pThis->RunCmd(pThis->m_adbCB); #ifdef _WIN32
return ;
#else
return (void *);
#endif
} #ifndef _WIN32
int CRGReDirect::SetTimer(int nSeconds, int nTimerID)
{
timer_t tid;
struct sigevent se; memset(&se, , sizeof(se));
se.sigev_notify = SIGEV_THREAD;
se.sigev_notify_function = HandleTimeOut;
se.sigev_value.sival_ptr = this; if(timer_create(CLOCK_REALTIME, &se, &tid) < )
{
#ifdef _DEBUG
perror("timer_create:");
#endif
return -;
} struct itimerspec ts, ots;
ts.it_value.tv_sec = nSeconds;
ts.it_value.tv_nsec = ;
ts.it_interval.tv_sec = ;
ts.it_interval.tv_nsec = ; if(timer_settime(tid, , &ts, &ots) < )
{
#ifdef _DEBUG
perror("timer_settime:");
#endif
return -;
} m_timer_id = tid; return ;
} int CRGReDirect::KillTimer(timer_t nTimerID)
{
return timer_delete(nTimerID);
} #ifdef _ARM
#define SHELL "/system/bin/sh"
#else
#define SHELL "/bin/sh"
#endif int CRGReDirect::open_max()
{
struct rlimit rl;
if(getrlimit(RLIMIT_NOFILE, &rl) == )
return rl.rlim_max; return ; //default
} FILE* CRGReDirect::rgpopen(const char *cmdstring, const char *type)
{
int i, pfd[];
pid_t pid;
FILE *fp; /* only allow "r" or "w" */
if ((type[] != 'r' && type[] != 'w') || type[] != ) {
errno = EINVAL;
return(NULL);
} if (m_childpid == NULL) { /* first time through */
/* allocate zeroed out array for child pids */
m_maxfd = open_max();
if ( (m_childpid = (pid_t *)calloc(m_maxfd, sizeof(pid_t))) == NULL)
return(NULL);
} if (pipe(pfd) < )
return(NULL); /* errno set by pipe() */ if ( (pid = fork()) < )
return(NULL); /* errno set by fork() */
else if (pid == ) { /* child */
if (*type == 'r') {
close(pfd[]);
if (pfd[] != STDOUT_FILENO) {
dup2(pfd[], STDOUT_FILENO);
close(pfd[]);
}
} else {
close(pfd[]);
if (pfd[] != STDIN_FILENO) {
dup2(pfd[], STDIN_FILENO);
close(pfd[]);
}
}
/* close all descriptors in childpid[] */
for (i = ; i < m_maxfd; i++)
if (m_childpid[ i ] > )
close(i); execl(SHELL, "sh", "-c", cmdstring, (char *) );
_exit();
}
/* parent */
if (*type == 'r') {
close(pfd[]);
if ( (fp = fdopen(pfd[], type)) == NULL)
return(NULL);
} else {
close(pfd[]);
if ( (fp = fdopen(pfd[], type)) == NULL)
return(NULL);
}
m_childpid[fileno(fp)] = pid; /* remember child pid for this fd */
return(fp);
} int CRGReDirect::rgpkill(FILE* fp)
{
int fd, stat;
pid_t pid; if (m_childpid == NULL)
return(-); /* rgpopen() has never been called */ fd = fileno(fp);
if ( (pid = m_childpid[fd]) == )
return(-); /* fp wasn't opened by rgpopen() */ m_childpid[fd] = ;
fclose(fp); return kill(pid, SIGKILL);
} int CRGReDirect::rgpclose(FILE *fp)
{
int fd, stat;
pid_t pid; if (m_childpid == NULL)
return(-); /* rgpopen() has never been called */ fd = fileno(fp);
if ( (pid = m_childpid[fd]) == )
return(-); /* fp wasn't opened by rgpopen() */ m_childpid[fd] = ;
if (fclose(fp) == EOF)
return(-); while (waitpid(pid, &stat, ) < )
if (errno != EINTR)
return(-); /* error other than EINTR from waitpid() */ return(stat); /* return child's termination status */
} #endif

最新文章

  1. connect VisualVM to Tomcat
  2. C# SocketHelper 源码
  3. -_-#【JS】隐含全局变量
  4. [转]关于strtok和strtok_r函数的深度研究
  5. cf B. Two Heaps
  6. oracle的启动和关闭
  7. 最小生成树之Prim算法和Kruskal算法
  8. 利用Spring的ApplicationEvent执行自定义方法
  9. linux修改root账户的用户名所得的教训
  10. Spring Boot Security
  11. shell脚本命令远程连接ssh并执行命令
  12. Java开发面试题,3年工作经验的Java程序员面试经
  13. spring ,springmvc,mybatis 最基本的整合,没有多余的jar包和依赖 2018.9.29日
  14. [Oracle,2018-03-01] oracle常用函数
  15. JS HTML倒计时 进入页面
  16. ACG图片站\python爬虫\LAMP环境
  17. cocos2d-x在App中的应用
  18. TOJ3448: 小学生的作业
  19. windows10安装ubuntu16.04双系统
  20. LVS负载均衡服务

热门文章

  1. Wireshark 基本介绍和学习 TCP 三次握手
  2. 什么是:VGA SVGA XGA SXGA
  3. 最常用的Eclipse快捷键【转载】
  4. Android Intent传递对象小结
  5. android ContentProvider学习
  6. [Javascript] Log Levels and Semantic Methods
  7. 关于Build Active Architecture Only属性
  8. POJ 2049 Finding Nemo
  9. SSL证书制作
  10. COGS 渡轮问题 (LIS规定字典序输出方案数)