重载adb管道时读取信息延迟

2018-05-14  本文已影响0人  赵海洋

几年前项目中就遇到过,当时没有深入研究。
使用CreateProcess+重载管道的方式启动adb,然后通过管道读取adb的输出数据。
但在处理某个命令行时,比如:adb.exe -s 10.95.27.100 install -r D:\apk\zhiwudazhanjiangshi2.apk

直接在win+R中运行,或在cmd.exe、或cmder、或Microsoft Code打开终端执行,它的输出都是以下文字,然后停在那里等待连接:

error: no devices/emulators found
adb: error: failed to get feature set: no devices/emulators found
- waiting for device -

但无论是使用我们的管道,还是使用boost::process,获取的结果都仅是从stdout中获取了一行:
adb: error: failed to get feature set: no devices/emulators found

如果把这个命令行放到vs的“生成前命令行”或者“生成后命令行”,在输出时也只会输出一行。
如下所示:

1>------ 已启动生成: 项目: xxx, 配置: debug Win32 ------
1>adb : error : failed to get feature set: no devices/emulators found
1>E:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\VC\VCTargets\Microsoft.CppCommon.targets(123,5): warning MSB5021: 终止任务可执行文件“cmd”及其子进程,因为已取消生成。
1>已完成生成项目“xxx.vcxproj”的操作 - 失败。

查看adb源码,并没有发现什么不同点,仅发现它对应上面第1行和第3行是使用fprintf(stderr,xxx)来输出的。但按理讲stderr已经被重定向了,应该能够正确的输出才是。

直接在main那里使用两行代码来测试输出。

fprintf(stderr, "test adb stderrr \n");
printf("test adb stdcout! \n");

编译后依然不会立即输出,最后将所有的fprintfprintf使用宏替换成重新实现的myprintf函数,myprintf函数内在printf之后添加fflush(stderr)和flush(stdout)才能解决。

// adb.h
int myprintf(char* format, ...);
int myfprintf(void* pipe, char* format, ...);

#define fprintf myfprintf
#define printf myprintf

// adb.c
int myprintf(char*  fmt,...)
{
    va_list ap;
    va_start(ap, fmt);
    vfprintf(stdout, fmt, ap);    
    va_end(ap);
    fflush(stdout);
    return 1;
}

具体原理不明,可能是控制台程序原生管道和我们重载的管道里的某些特殊参数不一致。

上一篇 下一篇

猜你喜欢

热点阅读