从adb shell读取二进制标准输出数据?

内容来源于 Stack Overflow,遵循 CC BY-SA 4.0 许可协议进行翻译与使用。IT领域专用引擎提供翻译支持

腾讯云小微IT领域专用引擎提供翻译支持

原文
Stack Overflow用户 修改于2012-11-27
  • 该问题已被编辑
  • 提问者: Stack Overflow用户
  • 提问时间: 2012-11-27 14:16

是否可以从adb shell命令中读取二进制标准输出?例如,所有使用截图的示例都包含两个步骤:

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的输出呢?我想做的是:

adb shell screencap -p > foo3.png

并且避免了对SD卡的中间写入。这将生成类似于PNG文件的内容(运行 strings foo3.png 会生成带有IHDR、IEND等的内容)。并且大小大致相同,但就图像读取器而言,该文件已损坏。

我也尝试过在java中使用ddmlib来做这件事,结果是一样的。我很乐意使用任何必要的库。我的目标是减少获取捕获的总时间。在我的设备上,使用两个命令的解决方案,大约需要3秒来获取图像。使用ddmlib并捕获stdout只需要不到900ms,但它不起作用!

有可能做到这一点吗?

编辑:这是两个文件的十六进制转储。第一个是来自标准输出的screen.png,它被破坏了。第二个是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].|

快速浏览一下,似乎添加了几个额外的0x0d (13)字节。回车??这有什么特别之处吗?它是否混合在一些空行中?

浏览 359 关注 0 得票数 68
  • 得票数为Stack Overflow原文数据
原文
修改于2018-07-26
  • 该回答已被编辑
  • 回答者: Stack Overflow用户
  • 回答时间: 2012-11-27 23:13
得票数 15

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

让我来说明一下 adb shell adb 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 exec-out 命令中获益,设备和主机PC都必须支持 adb shell V2协议。

处理PC端相当简单-只需将 platform-tools 包(其中包含 adb 二进制文件)更新到最新版本即可。设备上的 adbd 守护程序的版本链接到安卓的版本。在Android5.0中引入了 adb shell V2协议以及完整的 adb 大修(从 c C++ 代码)。但是也有一些回归(也就是But ),所以 adb exec-out 在Android5.x中的可用性仍然是有限的。最后,它不支持Android4.x和更老的设备。幸运的是,那些仍在用于开发的旧设备的份额正在迅速下降。

修改于2012-11-28
  • 该回答已被编辑
  • 回答者: Stack Overflow用户
  • 回答时间: 2012-11-28 05:24
得票数 9

在深入研究十六进制转储之后,很明显,每次发出字符0x0A时,shell都会发出0x0D 0x0A。我用下面的代码修复了流,现在二进制数据是正确的。当然,现在的问题是,为什么亚行壳牌要这样做?但在任何情况下,这都解决了问题。

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);
        } else {
            baos.write(encoded[i]);
    try {
        baos.close();
    } catch (IOException ioe) {
    return baos.toByteArray();      
}

编辑:我突然明白了它为什么要这样做。它正在将LF转换为CR/LF,就像老式DOS一样。我想知道有没有什么地方可以把它关掉?

修改于2013-01-16
  • 该回答已被编辑
  • 回答者: Stack Overflow用户
  • 回答时间: 2013-01-16 15:30
得票数 50

很抱歉发布了一个老问题的答案,但我自己也遇到了这个问题,我只想通过shell来解决它。这对我来说效果很好:

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

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

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

对我来说也是如此。

修改于2018-01-01
  • 该回答已被编辑
  • 回答者: Stack Overflow用户
  • 回答时间: 2015-07-14 16:22
得票数 94

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

adb exec-out screencap -p > test.png

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

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

adb exec-out "tar -zcf - /system 2>/dev/null" > system.tar.gz
评论 0
0
修改于2018-05-10
  • 该回答已被编辑
  • 回答者: Stack Overflow用户
  • 回答时间: 2015-08-30 23:00
得票数 1

也可以使用base64实现此目的,因此只需使用以下命令对其进行编码:

base64 foo3.png>foo3.png.base64

然后在windows上使用一些 base64 utility 或notepad++来解密文件。

或者在linux /cygwin中:

base64 -d foo3.png.base64>foo3.png
操作
回答于2016-11-15
得票数 1

您还可以使用标准 dos2unix 命令(如果可用)。

(如果你使用的是Debian/Ubuntu,请使用 apt-get install dos2unix 。如果你用谷歌搜索,可能会有针对Windows、OS X等的构建。

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

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

或者,修复损坏的文件(就地):

dos2unix -f screenshot.png

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

修改于2017-07-21
  • 该回答已被编辑
  • 回答者: Stack Overflow用户
  • 回答时间: 2017-07-21 02:51
得票数 -1

对我来说, nc 是唯一有效的方式。使用:

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