68

adb shell コマンドからバイナリ stdout を読み取ることは可能ですか? たとえば、screencap の使用方法のすべての例には、次の 2 つの手順が含まれます。

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

ただし、サービスは stdout への書き込みをサポートしています。たとえば、次のことができます。

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 を使用してこれを実行しようとしましたが、結果は同じです。必要なライブラリを喜んで使用します。私の目標は、キャプチャを取得するための合計時間を短縮することです。私のデバイスでは、2 コマンド ソリューションを使用して、画像を取得するのに約 3 秒かかります。ddmlib を使用して stdout をキャプチャするのに 900 ミリ秒もかかりませんが、うまくいきません!

これを行うことは可能ですか?

編集: これは 2 つのファイルの 16 進ダンプです。最初の screen.png は stdout からのもので、破損しています。2 つ目の xscreen は、2 コマンド ソリューションによるもので、動作します。画像は視覚的に同一である必要があります。

$ 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) バイトがいくつか追加されているように見えます。キャリッジリターン??それは何か鐘を鳴らしますか?空行が混じっていませんか?

4

18 に答える 18

96

コマンドとは異なりadb shell、バイナリ出力をマングルする which をadb exec-out使用しません。ptyだからあなたはすることができます

adb exec-out screencap -p > test.png

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
于 2015-07-14T08:22:48.183 に答える
50

古い質問への回答を投稿して申し訳ありませんが、私は自分でこの問題に遭遇し、シェルを介してのみそれをやりたかったのです。これは私にとってうまくいきました:

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

これ^Mは、ctrl + v-> ctrl + mを押して取得した文字ですが、コピーして貼り付けると機能しないことに気づきました。

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

私のためにもトリックをしました。

于 2013-01-16T07:30:57.347 に答える
15

The best solution is to use adb exec-out command like @AjeetKhadke suggested.

Let me illustrate the difference between adb shell and adb exec-out output:

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

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

It works in Windows (I am using hexdump from GNUWin32 Hextools for the demo) as well:

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

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

The downside is that in order to be able to benefit from using the adb exec-out command both the device and host PC have to support adb shell V2 protocol.

It is rather trivial to take care of the PC side - just update the platform-tools package (which contains the adb binary) to the latest version. The version of adbd daemon on the device is linked to the version of Android. The adb shell V2 protocol has been introduced in Android 5.0 together with complete adb overhaul (going from c to C++ code). But there were some regressions (aka bugs) so adb exec-out usefulness in Android 5.x was still limited. And finally there is no support for Android 4.x and older devices. Fortunately the share of those older devices still being used for development is dropping fast.

于 2012-11-27T15:13:00.867 に答える
15

前述のように、「adb shell」は改行 (0x0a) から改行 + 改行 (0x0d 0x0a) への変換を実行しています。これは、疑似 tty 回線規律によって実行されています。シェルで使用できる「stty」コマンドがないため、端末設定をいじる簡単な方法はありません。

ddmlib を使用して、必要なことを行うことができます。デバイスでコマンドを実行し、出力をキャプチャして、ネットワーク経由で送信するコードを作成する必要があります。これは多かれ少なかれ、特定の機能に対して DDMS が行うことです。これは、その価値よりも問題になる可能性があります。

解決策(repair()すべての CRLF を LF に変換する) は不安定に感じますが、「破損した」LF から CRLF への変換は決定論的であるため、実際には信頼できます。不注意な ASCII モードの FTP 転送を修復するために、以前は同じことをしていました。

PNG ファイル形式は、この (および関連する) 問題を正確に捕捉するように明示的に設計されていることに注意してください。マジック ナンバーは 0x89 で始まり、上位ビットを削除するものをすべてキャッチします。その後に「PNG」が続くため、ファイルの内容を簡単に確認できます。次に、さまざまな ASCII ライン コンバーターをキャッチするための CR LF が続きます。次に、古い MS-DOS プログラムをトラップするための 0x1a が続きます。特別なファイルの終わりマーカーとして Ctrl-Z を使用し、次に単独の LF を使用しました。ファイルの最初の数バイトを見ると、ファイルに何が行われたかを正確に知ることができます。

...これは、repair()関数が「破損した」入力と「純粋な」入力の両方を受け入れ、何かを行う必要があるかどうかを確実に判断できることを意味します。

編集: 1 つの追加の注意: を使用して、デバイス側のバイナリが変換を回避するように tty を構成することが可能ですcfmakeraw()Android 5.0 のscreenrecordprepareRawOutput()コマンドの関数を参照してください。これは、ADB シェル接続を介してライブ スクリーン キャプチャから未加工のビデオを送信できます。

于 2012-11-27T22:00:10.073 に答える
9

16 進ダンプを詳しく調べたところ、文字 0x0A が発行されるたびに、シェルが 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();      
}

編集:なぜこれを行っているのかがわかりました。古い学校の DOS のように LF を CR/LF に変換しています。それをオフにする設定がどこかにあるのだろうか?

于 2012-11-27T21:24:00.270 に答える
7

はい、Unix/Linux/Mac OS X では、先頭に「stty -onlcr;」を追加することで、adb シェルのバイナリ出力を受け取ることができます。あなたのコマンドに( いいえ~~ ルート化されたアンドロイドである必要はありません)。

1. 「stty」実行ファイルをダウンロードします。
http://www.busybox.net/downloads/binaries/latest/
古いアンドロイドならbusybox-armv5l、それ以外ならbusybox-armv7l。
ファイル名を「stty」に変更

2.ファイル「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 OS の場合、デフォルトでは、android の LF は CR CR LF に変換されます。
上記の手順を実行しても、CR LF が発生します。
これは、ローカルの adb.exe が fwrite を使用しており、CR が先頭に付加されるためと思われます。
Windows OSでCR LFをLFに手動で変換する以外に、これについては方法がありません。

于 2013-11-22T09:37:06.253 に答える
4

これは、どこでも機能するソリューションです(Linux と Windows を含む)。

netcat多くの場合、という名前のユーティリティが必要になりますncデバイスでとの
両方が失敗した場合は、 fresh が必要です。Play マーケットの busybox インストーラーを使用するか (root が必要)、osexp2003 によるソリューションを使用できます (公式サイトから busybox をダウンロードし、デバイスに配置して実行権限を追加します)。ncbusybox ncbusybox/data/local/tmp/

アイデアはnetcat、プリミティブ HTTP サーバーとして使用することです。
まあ、実際には適切なサーバーでさえありません。任意のTCP 接続 (ブラウザからの HTTP 要求、telnet 接続、または単に)への応答として入力を送信しnetcat、終了します。

次のように、出力を取得するコマンドを実行します。

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

上記の例でscreencap -pは、スクリーンショット (PNG 画像) を取得し、それを にパイプしnetcatます。サーバーとして動作する (接続をリッスンする) ように
-l指示し、TCP ポート 8080 を使用するように指示します。省略すると、着信 HTTP GET リクエストなどを端末に出力するだけです。 上記の例は、誰かが接続するのを待ち、スクリーンショットを送信してから終了します。 もちろん、デバイスのターミナル エミュレータなどから実行することもできます。netcat-p 8080>/dev/null

adb shell

上記のようにコマンドを実行した後、ブラウザで開くか、次のような他の手段を使用して、携帯電話から出力をダウンロードできますhttp://ip.of.your.phone:8080netcat

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
于 2015-12-11T04:24:25.447 に答える
1

これには base64 を使用することもできるため、次を使用してエンコードするだけです。

base64 foo3.png>foo3.png.base64

次に、Windowsでbase64ユーティリティまたはメモ帳++を使用してファイルを復号化します。

または linux / cygwin の場合:

base64 -d foo3.png.base64>foo3.png
于 2015-08-30T15:00:49.433 に答える
1

dos2unix利用可能な場合は、標準コマンドを使用することもできます。

apt-get install dos2unixDebian / Ubuntuを使用している場合。Googleで検索すると、おそらくWindows、OS Xなどのビルドがどこかにあるでしょう)。

dos2unixrepair()Eric Lange の関数と同じ方法で CRLF を LF に変換します。

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

または、破損したファイルを修正します (インプレース):

dos2unix -f screenshot.png

-fバイナリ ファイルを強制的に処理するには、 が必要です。

于 2016-11-15T07:13:56.867 に答える