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

Eri*_*nge 60 android adb

是否可以从adb shell命令读取二进制stdout?例如,如何使用screencap的所有示例包括两个步骤:

adb shell screencap -p /sdcard/foo.png
adb pull /sdcard/foo.png
Run Code Online (Sandbox Code Playgroud)

但是,该服务支持写入stdout.例如,您可以执行以下操作:

adb shell "screencap -p > /sdcard/foo2.png"
adb pull /sdcard/foo2.png
Run Code Online (Sandbox Code Playgroud)

这同样有效.但是,如何阅读亚行的产出呢?我想做的是以下内容:

adb shell screencap -p > foo3.png
Run Code Online (Sandbox Code Playgroud)

并避免中间写入SD卡.这会生成看起来像PNG文件的strings foo3.png东西(正在运行生成带有IHDR,IEND等的东西)并且大小大致相同,但就图像阅读器而言,文件已损坏.

我也尝试在java中使用ddmlib来做到这一点,结果是一样的.我很乐意使用任何必要的图书馆.我的目标是减少获取捕获的总时间.在我的设备上,使用双命令解决方案,获取图像大约需要3秒钟.使用ddmlib和捕获stdout需要不到900毫秒,但它不起作用!

是否有可能做到这一点?

编辑:这是两个文件的hexdump.第一个,screen.png来自stdout并且已损坏.第二个,xscreen来自双命令解决方案并且有效.图像应在视觉上相同.

$ 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  |.............n.e|
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.~g.q.....|
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].|
Run Code Online (Sandbox Code Playgroud)

只需快速浏览一下就可以添加几个额外的0x0d(13)字节.回车?这会敲响任何铃声吗?它是否混合在一些空白行中?

Aje*_*t47 85

与命令不同adb shell,adb exec-out不使用pty哪个修改二进制输出.所以你可以做到

adb exec-out screencap -p > test.png
Run Code Online (Sandbox Code Playgroud)

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

请注意,如果您将此技术用于在STDERR上生成输出的命令,则应将其重定向到/dev/null,否则adb将在其STDOUT中包含STDERR,从而破坏输出.例如,如果您尝试备份和压缩目录:

adb exec-out "tar -zcf - /system 2>/dev/null" > system.tar.gz
Run Code Online (Sandbox Code Playgroud)

  • 我跑这个时为什么会出现"错误:关闭"的想法?我有ADB版本1.0.32 (6认同)
  • @Ralph,PC 主机端的 adb 和设备端的 adbd 都需要支持 shell v2。您的设备太旧了。 (3认同)
  • 如果当今有人遇到相同的问题,这似乎是一个好主意。当然,这是一年零六天之前,当出血边缘伴侣1.0.32时。真正的答案是我在Windows上进行开发,即使exec-out应该忽略行尾问题,我也一直得到它。现在,答案对我来说是显而易见的:只需使用frickin的Linux开发Android,并停止尝试在Windows上伪造它。 (2认同)

Tom*_*mas 48

很抱歉发布一个旧问题的答案,但我自己只是遇到了这个问题,并希望只通过shell来完成.这对我很有用:

adb shell screencap -p | sed 's/^M$//' > screenshot.png
Run Code Online (Sandbox Code Playgroud)

^M是我通过按ctrl + v - > ctrl + m得到的一个字符,只是注意到它在复制粘贴时不起作用.

adb shell screencap -p | sed 's/\r$//' > screenshot.png
Run Code Online (Sandbox Code Playgroud)

也为我做了伎俩.

  • 虽然上面的方法在Ubuntu上运行得很好,但它在Mac OS X上对我不起作用.这种使用Perl代替sed的变体确实:`adb shell screencap -p | perl -pe的/\x0D\x0A /\x0A/g'> screen.png` (15认同)
  • 任何人都知道什么是适当的perl表达应该是Windows - 我有一个团队成员不幸在Windows平台上. (4认同)

fad*_*den 13

如上所述,"adb shell"正在执行换行(0x0a)到回车+换行(0x0d 0x0a)转换.这是由伪tty线路规则执行的.由于shell没有"stty"命令,因此没有简单的方法来处理终端设置.

这是可能做到你想要什么ddmlib.您需要编写在设备上执行命令的代码,捕获输出并通过线路发送.这或多或少是DDMS对某些功能的作用.这可能比它的价值更麻烦.

repair()解决方案-将所有CRLF到LF -感觉摇摇欲坠,但实际上是可靠的,因为"腐败" LF到CRLF的转换是确定性的.我曾经做过同样的事情来修复无意的ASCII模式FTP传输.

值得注意的是,PNG文件格式是明确设计用于捕获这个(和相关的)问题.神奇的数字从0x89开始,以捕获任何剥离高位的内容,然后是"PNG",这样您就可以轻松地告诉文件中的内容,然后使用CR LF来捕获各种ASCII行转换器,然后使用0x1a来捕获旧的MS-DOS程序使用Ctrl-Z作为特殊的文件结束标记,然后使用单独的LF.通过查看文件的前几个字节,您可以准确地告诉它对它做了什么.

...这意味着您的repair()函数可以接受"损坏"和"纯粹"输入,并可靠地确定它是否需要执行任何操作.

编辑:另外一个注意事项:设备端二进制文件可以配置tty以避免转换,使用cfmakeraw().请参阅Android 5.0中screenrecord命令中的prepareRawOutput()函数,该函数可以通过ADB shell连接从实时屏幕捕获发送原始视频.

  • 在这种情况下,CRLF成为CRCRLF.如果CRLF未经修改通过,则不可逆转. (4认同)

Ale*_* P. 10

最好的解决方案是使用adb exec-out@AjeetKhadke建议的命令.

让我说明adb shelladb exec-out输出之间的区别:

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

~$ adb exec-out "echo -n '\x0a'" | xxd -g1
00000000: 0a
Run Code Online (Sandbox Code Playgroud)

它的工作原理在Windows中(我用hexdump的GnuWin32 Hextools用于演示),以及:

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

C:\>adb exec-out "echo -n '\x0a'" | hexdump
00000000: 0A
Run Code Online (Sandbox Code Playgroud)

缺点是,为了能够从使用adb exec-out命令中受益,设备和主机PC都必须支持adb shellV2协议.

照顾PC端是相当简单的 - 只需将platform-tools包(包含adb二进制文件)更新到最新版本即可.adbd设备上的守护程序版本链接到Android版本.的adb shellV2协议已在的Android 5.0与完整一起被引入adb大修(从去cC++代码).但是有一些回归(又称错误),因此adb exec-outAndroid 5.x的实用性仍然有限.最后,不支持Android 4.x和旧设备.幸运的是,那些仍在用于开发的旧设备的份额正在快速下降.


Eri*_*nge 8

深入挖掘十六进制转储后,很明显每次发出字符0x0A时,shell都会发出0x0D 0x0A.我使用以下代码修复了流,现在二进制数据是正确的.当然,现在问题是为什么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();      
}
Run Code Online (Sandbox Code Playgroud)

编辑:我明白为什么要这样做.它将LF转换为CR/LF,就像老式DOS一样.我想知道是否有某个地方可以关闭它?

  • 如 [Glenn Willen](http://stackoverflow.com/a/13642296/427545) 所述,可以在运行 shell 命令之前使用 `stty raw` 禁用它。 (2认同)

ose*_*003 6

是的,在Unix / Linux / Mac OS X上,可以通过在前面加上“ stty -onlcr;”来接收adb shell的二进制输出。你的指挥( NO ~~需要一个根深蒂固的Android)。

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

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

adb push somelocaldir/stty /data/local/tmp/   
adb shell chmod 777 /data/local/tmp/stty 
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

做完了!

但对于Windows OS,默认情况下,来自Android的LF将转换为CR CR LF。
即使您执行了上述步骤,您仍然可以获得CR LF。
这“似乎”是因为本地adb.exe使用fwrite导致CR被前置。
除了在Windows OS上手动将CR LF转换为LF之外,我没有其他办法。


Evg*_*nZh 5

这是适用于任何地方(包括 Linux 和 Windows)的解决方案。

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

这个想法是用作netcat原始 HTTP 服务器。
好吧,事实上甚至不是一个合适的服务器。它只会发送其输入作为对任何TCP 连接的响应(无论是来自浏览器的 HTTP 请求、telnet 连接还是只是netcat)并终止。

运行您想要从中获取输出的命令,如下所示:

adb shell 'screencap -p | busybox nc -p 8080 -l >/dev/null'
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,screencap -p获取屏幕截图(PNG 图像)并将其通过管道传输到netcat.
-l告诉它netcat充当服务器(监听连接),并-p 8080告诉它使用 TCP 端口 8080。省略>/dev/null将简单地打印例如传入的 HTTP GET 请求到您的终端。
上面的示例将等待某人连接、发送屏幕截图,然后才终止。
当然,您可以在没有 的情况下运行它adb shell,例如从设备上的终端模拟器。

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

busybox nc ip.of.your.phone:8080 >screenshot.png
Run Code Online (Sandbox Code Playgroud)

如果你想使用USB线下载,你需要使用ADB转发连接,如下所示:

adb forward tcp:7080 tcp:8080
Run Code Online (Sandbox Code Playgroud)

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

adb forward --remove tcp:7080
Run Code Online (Sandbox Code Playgroud)