Чтение двоичных данных stdout из оболочки adb?
можно ли прочитать двоичный stdout из команды оболочки adb? Например, все примеры использования screencap включают в себя два шага:
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 и т. д.) и примерно такого же размера, но файл поврежден что касается читателей изображения.
Я также попытался сделать это с помощью ddmlib в java, и результаты одинаковы. Я был бы рад использовать любую библиотеку надо. Моя цель состоит в том, чтобы сократить общее время, чтобы получить захват. На моем устройстве, используя решение с двумя командами, требуется около 3 секунд, чтобы получить изображение. Использование ddmlib и захват stdout занимает менее 900 МС, но это не работает!
можно ли это сделать?
EDIT: вот hexdump из двух файлов. Первый-экран.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].|
просто на быстрый взгляд кажется, что несколько дополнительных 0x0D (13) байт добавляются. Возврат каретки?? Делает это что-нибудь напоминает? Это смешивание в некоторых пустых строках?
15 ответов:
Извините, что публикую ответ на старый вопрос, но я просто столкнулся с этой проблемой сам и хотел сделать это только через оболочку. Это хорошо работало для меня:
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
theadb exec-out
команда не используетpty
который искажает двоичный выход. Так что вы можете сделатьadb exec-out screencap -p > test.png
https://android.googlesource.com/platform/system/core/+/5d9d434efadf1c535c7fea634d5306e18c68ef1f
обратите внимание, что если вы используете этот метод для команды, которая производит вывод на STDERR, вы должны перенаправить его на
/dev/null
, иначеadb
будет включать STDERR в его STDOUT развращает ваш выход. Например, если вы попытка резервного копирования и сжатия каталога:adb exec-out "tar -zcf - /system 2>/dev/null" > system.tar.gz
как уже отмечалось, "adb shell" выполняет преобразование linefeed (0x0a) в carriage-return + linefeed (0x0d 0x0a). Это выполняется псевдо-линейной дисциплиной. Поскольку в оболочке нет команды" stty", нет простого способа возиться с настройками терминала.
это возможно делать то, что вы хотите с ddmlib. Вам нужно будет написать код, который выполнял команды на устройстве, захватил вывод и отправил его по проводу. Это больше или меньше того, что DDMS делает для определенных функций. Это может быть больше проблем, чем стоит.
The
repair()
решение-преобразование всех CRLF в LF-чувствует себя шатким, но на самом деле надежно, так как "разрушающее" преобразование LF в CRLF является детерминированным. Я использовал то же самое, чтобы восстановить непреднамеренные передачи FTP в ASCII-режиме.стоит отметить, что формат файла PNG явно разработан, чтобы поймать именно эти (и связанные с ними) проблемы. Магическое число начинается с 0x89 в поймать все, что обнажает высокую битов, а затем "ПНГ", так что вы можете легко сказать, что в файл, с последующим CR LF в разнообразных символов ASCII строки преобразователи, затем 0x1a в ловушку старых версий MS-DOS программ, которые используют сочетания клавиш Ctrl-Z, как особый конец файла маркер, а потом одинокий ЛФ. Посмотрев на первые несколько байт файла, вы можете точно сказать, что с ним было сделано.
...что означает, что ваш
repair()
функция может принимать как" поврежденный", так и" чистый " вход и надежно определять, нужно ли это сделать ничего.Edit: еще одно примечание: двоичный файл на стороне устройства можно настроить tty, чтобы избежать преобразования, используя
cfmakeraw()
. Смотрите на screenrecord команда в Android 5.0, которая может отправлять необработанное видео с живого захвата экрана через соединение оболочки ADB.
после углубления в шестнадцатеричные дампы стало ясно, что каждый раз, когда символ 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(); }
EDIT: меня осенило, почему он это делает. Он преобразует LF в CR / LF, как в старой школе DOS. Интересно, есть ли где-нибудь настройка чтобы отключить это?
лучшее решение-использовать как @AjeetKhadke предложил.
позвольте мне проиллюстрировать разницу между
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 (я использую
hexdump
С GNUWin32 Hextools для демо), а также:C:\>adb shell "echo -n '\x0a'" | hexdump 00000000: 0D 0A C:\>adb exec-out "echo -n '\x0a'" | hexdump 00000000: 0A
недостатком является то, что для того, чтобы иметь возможность извлечь выгоду из использования
adb exec-out
команда как устройство, так и хост-ПК должны поддерживатьadb shell
V2 протокол.это довольно тривиально, чтобы заботиться о компьютере - просто обновите
platform-tools
пакет (который содержитadb
binary) до последней версии. Версияadbd
демон на устройстве связан с версией Android. Элементadb shell
протокол V2 был введен в Android 5.0 вместе с completeadb
капитальный ремонт (идя отc
доC++
код). Но были некоторые регрессии (ака ошибки) такadb exec-out
полезность в Android 5.х был еще ограниченный. И, наконец, нет поддержки для Android 4.x и более старые устройства. К счастью, доля тех старых устройств, которые все еще используются для разработки, быстро падает.
да, в Unix / Linux / Mac OS X вы можете получить двоичный вывод оболочки adb, добавив "stty-onlcr;" к вашей команде (нет ~~ нужно быть корневым android).
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.вставить "будут действовать до его закрытия -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, по умолчанию, LF из android будет преобразован в CR CR LF.
Даже если вы сделали выше шаг, вы все равно получите CR LF.
Это "кажется", потому что местный АБР.exe использовать fwrite, которые вызывают CR быть добавлены.
У меня нет никакого способа об этом, кроме преобразования CR LF в LF вручную на ОС Windows.
иначе:
adb shell "busybox stty raw; screencap -p "> foo3.png
но, как сказал @osexp2003,это не работает для ОС Windows.
вот решение, которое работает везде (Linux и Windows включены).
вам понадобится
netcat
утилиты, часто называютnc
.
Если обаnc
иbusybox nc
сбой на вашем устройстве, вам нужен свежийbusybox
. Вы можете либо использовать установщик busybox из Play Market (Требуется root), либо использовать решение от osexp2003 (скачать busybox из официальный сайт, положил его в/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
говоритnetcat
выступать в качестве сервера (прослушивать соединение), и-p 8080
говорит ему использовать TCP-порт 8080. Omiting>/dev/null
будет просто печатать, например, входящий запрос HTTP GET на ваш терминал.
Приведенный выше пример будет ждать, пока кто-то подключится, отправит скриншот и только затем завершит работу.
Конечно, вы можете запустить его безadb shell
, например, от эмулятора терминала на вашем устройстве.после выполнения команды выше, вы можете скачать его выхода из ваш телефон, открыв
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
для этого также можно использовать base64, поэтому просто Закодируйте его с помощью:
base64 foo3.png>foo3.png.base64
а затем на windows, используя некоторые утилита base64 или, может быть, Notepad++ для расшифровки файла.
или в linux / cygwin:
base64 -d foo3.png.base64>foo3.png
вы также можете использовать стандартный
dos2unix
команда, если она доступна.(
apt-get install dos2unix
Если вы находитесь на Debian / Ubuntu. Вероятно, есть сборки для Windows, OS X и т. д. там где-то, если вы google).
dos2unix
преобразует CRLF в LF так же, как Эрик Ланге
Я поставил метод для использования python get image bytes с помощью adb здесь, возможно, это будет полезно для тех, кто столкнулся с этой проблемой. Код выглядит следующим образом:
pipe = subprocess.Popen("adb shell screencap -p", stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=True) image_bytes = pipe.stdout.read().replace(b'\r\n', b'\n') gray_image = cv2.imdecode(np.fromstring(image_bytes, np.uint8), cv2.IMREAD_GRAYSCALE)
эта команда работала для меня ОС 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
root-правами чтобы создать, надеюсь, правильное резервное копирование /данные/средства массовой информации