Чтение двоичных данных 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 shelltheadb exec-outкоманда не используетptyкоторый искажает двоичный выход. Так что вы можете сделатьadb exec-out screencap -p > test.pnghttps://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 shellV2 протокол.это довольно тривиально, чтобы заботиться о компьютере - просто обновите
platform-toolsпакет (который содержитadbbinary) до последней версии. Версия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/stty3.вставить "будут действовать до его закрытия -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:7080root-правами чтобы создать, надеюсь, правильное резервное копирование /данные/средства массовой информации