问题背景
要做一个需求,大概是检测到某输入重启,于是写一个demo调试一下
c语言程序,交叉编译后在adb shell下运行
思路
用 am 命令直接重启
我们先手动验证一下,发现这个设备不支持am命令吗,遂排除
用 kill 命令杀掉进程,然后重新运行
- 写个demo,这个程序会循环等待输入,按q退出
void test_option()
{
}
int main(int argc, char **argv)
{
int ret;
char *sptr = NULL;
while(1)
{
sptr = input_fgets("Please input option: \n");
if(sptr[0] == 'q')
return 0;
else if (atoi(sptr) == 1)
test_option();
}
return 0;
}
- 另开一个cmd窗口,打开adb shell,查询进程号并杀掉重开
可以看到,通过另一个adb窗口可以很轻易地kill掉进程并重启
那么 直接用system函数写入命令行执行不就完事了?? ,我也是这么认为的。。。但是出问题了!!!
-
我手动执行ps看进程号,但是写程序获得进程号呢?
ps | grep nwy_data_test | awk '{print $1}' | head -n 1
这句命令表示取出ps结果的第一列的第一行并打印!也就是上图中的22122 -
取到22122了,怎么传给命令行呢?
发现会无限循环执行!!!
- 经过我的调试!!!发现问题出在input_fgets函数!!!
kill当前进程 重启一个不带input_fgets函数的情况下,只会kill不会运行新程序
kill当前进程 重启一个while里带input_fgets函数的情况下,不但会kill且会忽略input_fgets的阻塞!!
也就是说 只要kill当前进程后,重启的进程带fgets这种获取命令行输入的都有错!!!
static inline char *input_fgets(char *msg, ...)
{
static char ptr[130] = { 0 };
va_list ap;
va_start(ap, msg);
vprintf(msg, ap);
va_end(ap);
memset(ptr, 0, sizeof(ptr));
fgets(ptr, sizeof(ptr), stdin);
if(strlen(ptr) > 0) {
if('\n' == ptr[strlen(ptr) - 1]) {
ptr[strlen(ptr) - 1] = '\0';
}
}
return ptr;
}
-
通过打断点,发现错误大概率是由于kill的底层是通过fork创建一个子进程的,而子进程会关联到父进程的输入输出流,通过kill杀掉的进程,影响了正常的输入输出流!!!
-
为了验证我的猜想,我编写了如下程序
原始进程rst_test
后来进程ftp_test 请忽略名字,,我懒得改了
用 exit 命令退出adb shell,然后重新开启
根因分析
困难总结
-
kill进程之后,后面的指令不会继续运行了
-
程序内有while的话 脚本检测不到阻塞