从adb shell读取二进制stdout数据?

是否有可能从ADB shell命令读取二进制标准输出? 例如,如何使用screencap的所有例子包括两个步骤:

adb shell screencap -p /sdcard/foo.png adb pull /sdcard/foo.png 

但是,该服务支持写入标准输出。 你可以举例如下:

 adb shell "screencap -p > /sdcard/foo2.png" adb pull /sdcard/foo2.png 

这同样适用。 但是,如何读取亚行的产出呢? 我想要做的是以下几点:

 adb shell screencap -p > foo3.png 

并避免中间写入SD卡。 这产生了一个看起来像PNG文件(运行strings foo3.png生成一个IHDR,IEND等东西)和大小相同的大小,但就图像读者而言,该文件已损坏。

我也尝试在java中使用ddmlib来做到这一点,结果是一样的。 我会很乐意使用任何必要的图书馆。 我的目标是减less总捕获时间。 在我的设备上,使用双指令解决scheme,大约需要3秒钟才能获得图像。 使用ddmlib并捕获标准输出需要不到900毫秒,但它不工作!

是否有可能做到这一点?

编辑:这是两个文件的hexdump。 第一个,screen.png来自标准输出,并已损坏。 第二个,xscreen是来自两个命令的解决scheme并且工作。 图像应该在视觉上相同。

 $ hexdump -C screen.png | head 00000000 89 50 4e 47 0d 0d 0a 1a 0d 0a 00 00 00 0d 49 48 |.PNG..........IH| 00000010 44 52 00 00 02 d0 00 00 05 00 08 06 00 00 00 6e |DR.............n| 00000020 ce 65 3d 00 00 00 04 73 42 49 54 08 08 08 08 7c |.e=....sBIT....|| 00000030 08 64 88 00 00 20 00 49 44 41 54 78 9c ec bd 79 |.d... .IDATx...y| 00000040 9c 1d 55 9d f7 ff 3e 55 75 f7 de b7 74 77 d2 d9 |..U...>Uu...tw..| 00000050 bb b3 27 10 48 42 16 c0 20 01 86 5d 14 04 11 dc |..'.HB.. ..]....| 00000060 78 44 9d c7 d1 d1 11 78 70 7e 23 33 8e 1b 38 33 |xD.....xp~#3..83| 00000070 ea 2c 8c 8e 0d 0a 08 a8 23 2a 0e 10 82 ac c1 40 |.,......#*.....@| 00000080 12 02 81 24 64 ef ec 5b ef fb 5d 6b 3b bf 3f ea |...$d..[..]k;.?.| 00000090 de db dd 49 27 e9 ee 74 77 3a e3 79 bf 5e 37 e7 |...I'..tw:.y.^7.| $ hexdump -C xscreen.png | head 00000000 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 |.PNG........IHDR| 00000010 00 00 02 d0 00 00 05 00 08 06 00 00 00 6e ce 65 |.............ne| 00000020 3d 00 00 00 04 73 42 49 54 08 08 08 08 7c 08 64 |=....sBIT....|.d| 00000030 88 00 00 20 00 49 44 41 54 78 9c ec 9d 77 98 1c |... .IDATx...w..| 00000040 c5 99 ff 3f d5 dd 93 37 27 69 57 5a e5 55 4e 08 |...?...7'iWZ.UN.| 00000050 24 a1 00 58 18 04 26 08 8c 01 83 31 38 c0 19 9f |$..X..&....18...| 00000060 ef 7c c6 3e 1f 70 f8 7e 67 ee 71 e2 b0 ef ce f6 |.|.>.p.~gq....| 00000070 f9 ec 73 04 1b 1c 31 60 23 84 30 22 88 a0 40 10 |..s...1`#.0"..@.| 00000080 08 65 69 95 d3 4a 9b c3 c4 4e f5 fb a3 67 66 77 |.ei..J...N...gfw| 00000090 a5 95 b4 bb da a4 73 7d 9e 67 55 f3 ed 50 5d dd |......s}.gU..P].| 

只是快速浏览一下,似乎有一些额外的0x0d(13)字节被添加。 回车? 那响铃吗? 它是混合在一些空白行吗?

对不起,要发布一个老问题的答案,但我只是自己遇到这个问题,只想通过壳来做到这一点。 这对我很好:

 adb shell screencap -p | sed 's/^M$//' > screenshot.png 

^M是我通过按Ctrl + V – > Ctrl + ^M得到的字符,只是注意到它复制粘贴时不起作用。

 adb shell screencap -p | sed 's/\r$//' > screenshot.png 

也为我做了诡计。

adb shell不同的是, adb exec-out命令不使用pty ,这会破坏二进制输出。 所以你可以做

 adb exec-out screencap -p > test.png 

https://android.googlesource.com/platform/system/core/+/5d9d434efadf1c535c7fea634d5306e18c68ef1f

如上所述,“adb shell”正在执行换行(0x0a)到回车+换行(0x0d 0x0a)的转换。 这是由伪tty线纪律执行。 由于shell没有“stty”命令,所以没有简单的方法来搞乱terminal设置。

可以用ddmlib来做你想做的事情。 您需要编写在设备上执行命令的代码,捕获输出并通过线路发送。 这或多或less是DDMS为某些function所做的。 这可能比它的价值更麻烦。

repair()解决scheme – 将所有CRLF转换为LF – 感觉不稳定,但实际上是可靠的,因为“破坏”的LF到CRLF转换是确定性的。 我曾经做过同样的事情来修复无意的ASCII模式FTP传输。

值得注意的是,PNG文件格式是明确devise的,以准确捕捉这个(和相关的)问题。 神奇的数字以0x89开始,抓住任何剥去高位的东西,然后是“PNG”,这样你就可以很容易地知道文件中的内容,接下来是CR LF来捕获各种ASCII行转换器,然后0x1a来捕获旧的MS-DOS程序使用Ctrl-Z作为特殊的文件结束标记,然后是一个单独的LF。 通过查看文件的前几个字节,您可以确切地知道对它做了什么。

…这意味着您的repair()函数可以接受“损坏”和“纯”input,并可靠地确定是否需要执行任何操作。

编辑:另外一个注意事项:设备端的二进制文件可以使用cfmakeraw()configurationtty来避免转换。 请参阅Android 5.0中的prepareRawOutput()命令中的prepareRawOutput()函数,该函数可以通过ADBshell连接从实况屏幕捕获发送原始video。

深入挖掘hex转储后,很明显,每当字符0x0A发出时,shell就会发出0x0D 0x0A。 我用下面的代码修复了stream,现在二进制数据是正确的。 当然,现在的问题是为什么adb shell会这样做呢? 但无论如何,这解决了这个问题。

 static byte[] repair(byte[] encoded) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); for (int i=0; i<encoded.length; i++) { if (encoded.length > i+1 && encoded[i] == 0x0d && encoded[i+1] == 0x0a) { baos.write(0x0a); i++; } else { baos.write(encoded[i]); } } try { baos.close(); } catch (IOException ioe) { } return baos.toByteArray(); } 

编辑:它曙光我为什么这样做。 它像老式DOS一样将LF转换为CR / LF。 我想知道是否有一个设置某处可以closures?

是的,在Unix / Linux / Mac OS X上,您可以通过预先input“stty -onlcr;”来接收adb shell的二进制输出 到你的命令( 没有 ~~需要成为一个扎根的机器人)。

1. 下载“stty”可执行文件。
http://www.busybox.net/downloads/binaries/latest/
对于旧的android,使用busybox-armv5l,其他使用busybox-armv7l。
重命名文件为“stty”

2. Uploda文件“stty”到android并设置适当的权限。

 adb push somelocaldir/stty /data/local/tmp/ adb shell chmod 777 /data/local/tmp/stty 

3. 加上“stty -onlcr” 像你这样的命令

 adb shell /data/local/tmp/stty -onlcr\; screencap -p > somelocaldir/output.png or: adb shell "/data/local/tmp/stty -onlcr; screencap -p" > somelocaldir/output.png or (Only for Windows): adb shell /data/local/tmp/stty -onlcr; screencap -p > somelocaldir/output.png 

完成!

但是对于Windows操作系统,默认情况下,来自android的LF将被转换为CR CR LF。
即使你做了上面的步骤,你仍然得到CR LF。
这个“看起来”是因为本地的adb.exe使用fwrite导致CR被前置。
我没有办法,除了在Windows操作系统上手动将CR LF转换为LF。

自Android版本6.0以来,你可以使用toybox base64 applet:

  adb shell "screencap -p | toybox base64" | base64 -di >screencap.png 

但最好的解决scheme是使用adb exec-out命令,如@AjeetKhadkebuild议的。

让我来说明一下adb shelladb exec-out输出的区别:

 adb shell "echo -n '\x0a'" | xxd -g1 00000000: 0d 0a adb exec-out "echo -n '\x0a'" | xxd -g1 00000000: 0a 

它在Windows中工作(我使用GNUWin32 Hextools的 hexdump进行演示):

 C:\>adb shell "echo -n '\x0a'" | hexdump 00000000: 0D 0A C:\>adb exec-out "echo -n '\x0a'" | hexdump 00000000: 0A 

其他方式:

 adb shell "busybox stty raw; screencap -p "> foo3.png 

但是,正如@ osexp2003所说, 这不适用于Windows操作系统。

这也可以使用base64,所以只需使用以下命令对其进行encryption:

 base64 foo3.png>foo3.png.base64 

然后在Windows上使用一些base64工具或记事本++解密文件。

或者在linux / cygwin中:

 base64 -d foo3.png.base64>foo3.png 

这里是无处不在的解决scheme(包括Linux和Windows)。

您将需要netcat实用程序,通常命名为nc
如果ncbusybox nc在您的设备上都失败,则需要新的busybox 。 您可以从Play Market使用busybox安装程序(需要root用户),或者使用osexp2003的解决scheme (从官方网站下载busybox,将其放入/data/local/tmp/ on设备并添加执行权限)。

这个想法是使用netcat作为一个原始的HTTP服务器。
那么,事实上,甚至不是一个合适的服务器。 它只是将其input作为响应发送到任何 TCP连接(不pipe是来自浏览器的HTTP请求,telnet连接还是只是netcat )并终止。

运行命令你想得到这样的输出:

 adb shell 'screencap -p | busybox nc -p 8080 -l >/dev/null' 

在上面的例子中, screencap -p会截取一个截图(PNG图像)并将其传递给netcat
-l告诉netcat充当服务器(侦听连接),- -p 8080告诉它使用TCP端口8080.忽略>/dev/null将简单地打印例如传入HTTP GET请求到您的terminal。
上面的例子将等待有人连接,发送屏幕截图,然后才能终止。
当然,你可以在没有adb shell情况下运行它,例如从你的设备上的terminal仿真器。

如上所述运行命令后, 可以通过在浏览器中打开http://ip.of.your.phone:8080或通过任何其他方式(例如使用netcat手机下载其输出。

 busybox nc ip.of.your.phone:8080 >screenshot.png 

如果要使用USB电缆进行下载 ,则需要使用ADB转发连接,如下所示:

 adb forward tcp:7080 tcp:8080 

之后,您可以使用localhost:7080而不是ip.of.your.phone:8080
您可以使用以下命令删除此转发:

 adb forward --remove tcp:7080 

如果可用的话,也可以使用标准的dos2unix命令。

apt-get install dos2unix如果你在Debian / Ubuntu上的话,如果你是google的话,可能会在Windows,OS X等等的地方安装。

dos2unix将CRLF转换为LF,与Eric Lange的repair()函数相同。

 adb shell screencap -p | dos2unix -f > screenshot.png 

或者,修复损坏的文件(in-place):

 dos2unix -f screenshot.png 

您需要-f强制它处理二进制文件。

这个命令适用于Windows操作系统

 adb exec-out screencap -p > test.png && dos2unix.exe -f test.png 

但是你想用这个: https : //sourceforge.net/projects/dos2unix/

nc是它为我工作的唯一方法。 用过的:

 adb forward tcp:7080 tcp:8080 &&\ adb shell 'tar -zcvf - /data/media | nc -p 8080 -l 1>/dev/null' &\ sleep 1;\ nc localhost 7080 > media.tar.gz &&\ adb forward --remove tcp:7080 

作为根用来为/ data / media创build一个合适的备份

试试这个家伙:

 adb shell screencap -p | perl -pe 's/\x0D\x0A/\x0A/g' > screen.png