Lire les données stdout binaires de shell adb?

est-il possible de lire un stdout binaire à partir d'une commande shell de la BAD? Par exemple, tous les exemples de la façon d'utiliser screencap comprennent deux étapes:

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

cependant, le service supporte l'écriture à stdout. Vous pouvez par exemple, faire ce qui suit:

adb shell "screencap -p > /sdcard/foo2.png"
adb pull /sdcard/foo2.png

et cela fonctionne également bien. Mais, qu'en est-il de la lecture de la sortie à travers ADB? Ce que je veux faire est le suivant:

adb shell screencap -p > foo3.png

et éviter la intermédiaire écrire à la carte SD. Cela génère quelque chose que ressemble à comme un fichier PNG (exécuter strings foo3.png génère quelque chose avec un IHDR, IEND, etc.) et est à peu près de la même taille, mais le fichier est corrompu en ce qui concerne les lecteurs d'image.

j'ai également essayé de le faire en utilisant ddmlib en java et les résultats sont les mêmes. Je serais heureux d'utiliser toute bibliothèque nécessaire. Mon but est de réduire le temps total pour obtenir la capture. Sur mon appareil, en utilisant la solution à deux commandes, il faut environ 3 secondes pour obtenir l'image. Utiliser ddmlib et capturer stdout prend moins de 900M, mais ça ne marche pas!

Est-il possible de faire cela?

EDIT: Voici l'hexdump de deux fichiers. Le premier, celui de l'écran.la png est venue de stdout et est corrompue. Le second, xscreen est issu de la solution à deux commandes et fonctionne. Les images doivent être visuellement identiques.

$ 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].|

D'un simple coup d'oeil, il semble que quelques octets supplémentaires de 0x0d (13) soient ajoutés. Retour chariot?? Le fait sonner les cloches? Est-ce que ça se mélange dans des lignes vierges?

53
demandé sur Eric Lange 2012-11-27 10:16:52

15 réponses

désolé de poster une réponse à une vieille question, mais je viens de rencontrer ce problème moi-même et je voulais le faire seulement à travers le shell. Cela a bien fonctionné pour moi:

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

que ^M est un caractère que j'ai obtenu en appuyant sur ctrl+v -> ctrl+m, juste remarqué qu'il ne fonctionne pas quand copier-coller.

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

a fait l'affaire pour moi aussi.

46
répondu Tomas 2013-01-16 09:29:10

contrairement à adb shell la commande adb exec-out n'utilise pas pty qui modifie la sortie binaire. De sorte que vous pouvez faire

adb exec-out screencap -p > test.png

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

notez que si vous utilisez cette technique pour une commande qui produit une sortie sur STDERR, vous devez la rediriger vers /dev/null , sinon adb comprendra STDERR dans son STDOUT corrompant votre sortie. Par exemple, si vous essayez de sauvegarder et compresser un répertoire:

adb exec-out "tar -zcf - /system 2>/dev/null" > system.tar.gz
70
répondu Ajeet Khadke 2018-01-01 05:19:59

comme noté," adb shell " exécute une conversion linefeed (0x0a) à carriage-return + linefeed (0x0d 0x0a). Ceci est effectué par la discipline de la ligne pseudo-tty. Comme il n'y a pas de commande" stty " disponible pour l'interpréteur de commandes, il n'y a pas de moyen facile de modifier les paramètres du terminal.

c'est possible de faire ce que vous voulez avec ddmlib. Vous avez besoin d'écrire le code qui a exécuté des commandes sur l'appareil, capturé la sortie, et l'a envoyé sur fil. C'est plus ou moins ce que fait le DSAD pour certaines fonctionnalités. Cela peut être plus de problèmes que de sa valeur.

la solution repair() -- convertir tous les CRLF en LF -- semble chancelante mais est en fait fiable puisque la conversion "corruptrice" de LF en CRLF est déterministe. J'avais l'habitude de faire la même chose pour réparer les transferts FTP en mode ASCII involontaires.

il est intéressant de noter que le format de fichier PNG est explicitement conçu pour saisir exactement ceci (et liés à des problèmes. Le nombre magique commence avec 0x89 pour attraper tout ce qui dégrade les bits élevés, suivi de "PNG" de sorte que vous pouvez facilement dire ce qui est dans le fichier, suivi par CR LF pour attraper divers convertisseurs de ligne ASCII, puis 0x1a pour piéger les vieux programmes MS-DOS qui ont utilisé Ctrl-Z comme marqueur de fin de fichier spécial, et puis un LF Solitaire. En regardant les premiers octets du fichier, vous pouvez dire exactement ce qui a été fait pour elle.

...ce qui signifie que votre fonction repair() peut accepter les entrées" corrompues "et" pures", et déterminent de manière fiable s'il doit faire quoi que ce soit.

Edit: une remarque: il est possible que l'appareil côté binaire de configurer le terminal pour éviter la conversion, à l'aide de cfmakeraw() . Voir la fonction prepareRawOutput() dans la commande screenrecord dans Android 5.0, qui peut envoyer la vidéo brute à partir de la capture d'écran en direct à travers la connexion shell ADB.

11
répondu fadden 2014-11-30 17:16:15

après avoir creusé plus profondément dans les décharges hexadécimales, il est devenu clair que chaque fois que le caractère 0x0A était émis, le shell émettrait 0x0D 0x0A. J'ai réparé le flux avec le code suivant et maintenant les données binaires sont correctes. Maintenant, bien sûr, la question Est de savoir pourquoi shell fait ça? Mais dans tous les cas, cela résout le problème.

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: j'ai compris pourquoi il fait cela. Il convertit LF en CR / LF comme le DOS de la vieille école. Je me demande si il y a un paramètre quelque part pour désactiver cette fonction?

7
répondu Eric Lange 2012-11-27 21:33:19

la meilleure solution est d'utiliser adb exec-out commande comme @AjeetKhadke suggéré.

permettez-moi d'illustrer la différence entre adb shell et adb exec-out sortie:

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

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

il fonctionne sous Windows (j'utilise hexdump de GnuWin32 Hextools pour la démo) ainsi que:

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

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

l'inconvénient est que pour pouvoir bénéficier de en utilisant la commande adb exec-out le périphérique et le PC hôte doivent supporter le protocole adb shell V2.

il est assez trivial de prendre soin du côté du PC - il suffit de mettre à jour le paquet platform-tools (qui contient le binaire adb ) à la dernière version. La version de adbd démon sur l'appareil est lié à la version d'Android. Le protocole v2 adb shell a été introduit dans Android 5.0 avec Révision complète adb (allant de c à C++ code). Mais il y avait quelques régressions (alias bugs) donc adb exec-out utilité dans Android 5.x était encore limité. Enfin, il n'y a pas de support pour Android 4.x et des appareils plus anciens. Heureusement, la part de ces appareils plus anciens encore utilisés pour le développement diminue rapidement.

5
répondu Alex P. 2018-07-26 00:00:03

Oui, sur Unix/Linux/Mac OS X, vous pouvez recevoir binaire de sortie de la commande adb shell par ajouter le préfixe "stty -onlcr;" à votre commande ( NON ~~ besoin d'être enraciné android).

1. télécharger le fichier exécutable "stty".

http://www.busybox.net/downloads/binaries/latest/

Pour l'ancien android, Utilisez busybox-armv5l, D'autres utilisez busybox-armv7l.

renommer le fichier en" stty "

2. Uploda fichier "stty" pour android et jeu de l'autorisation appropriée.

adb push somelocaldir/stty /data/local/tmp/   
adb shell chmod 777 /data/local/tmp/stty 

3. Prepend "stty -onlcr;" à votre commande comme ceci:

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

fait!

mais pour Windows OS, par défaut, LF de android sera converti en CR CR LF.

Même si tu as dépassé les bornes, tu obtiens toujours CR LF.

Cela "semble" parce que la BAD locale.exe utiliser fwrite qui cause CR être prépayé.

Je n'ai aucun moyen à ce sujet, sauf convertir CR LF en LF manuellement sur Windows OS.

4
répondu osexp2003 2016-03-22 03:03:09

une autre voie:

adb shell "busybox stty raw; screencap -p "> foo3.png 

mais, comme @osexp2003 dit, qui ne fonctionne pas pour Windows OS.

2
répondu shao hongsheng 2015-09-11 07:41:04

Voici la solution que fonctionne partout (Linux et Windows inclus).

Vous aurez besoin de netcat utilitaire, souvent nommé nc .

Si les deux nc et busybox nc échouent sur votre appareil, vous avez besoin de nouveau busybox . Vous pouvez soit utiliser l'installateur de busybox de Play Market (root requis), ou utiliser solution par osexp2003 (télécharger busybox de site officiel , mettez-le dans /data/local/tmp/ sur l'appareil et ajoutez la permission d'exécution).

l'idée est d'utiliser netcat comme un serveur HTTP primitif.

Pas même un vrai serveur en fait. Il enverra simplement ses entrées en réponse à n'importe quelle "connexion TCP 1519430920" (que ce soit une requête HTTP du navigateur, une connexion telnet ou simplement netcat ) et se terminera.

Exécution de la commande que vous voulez obtenir à la sortie de comme ceci:

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

dans l'exemple ci-dessus, screencap -p prend une capture d'écran (Image PNG) et la redirige vers netcat .

-l dit netcat d'agir comme un serveur (écouter pour la connexion), et -p 8080 lui dit d'utiliser le port TCP 8080. Omettre >/dev/null n'aura qu'à imprimer par exemple la requête HTTP GET entrante sur votre terminal.

L'exemple ci-dessus attendra que quelqu'un se connecte, envoie la capture d'écran et ensuite se termine.

Bien sûr, vous pouvez l'exécuter sans adb shell , par exemple, à partir de l'émulateur de terminal sur votre appareil.

après avoir exécuté votre commande comme ci-dessus, vous pouvez télécharger sa sortie à partir de votre téléphone, en ouvrant "151919190920" dans le navigateur ou par tout autre moyen, par exemple en utilisant netcat :

busybox nc ip.of.your.phone:8080 >screenshot.png

si vous voulez utiliser le câble USB pour le téléchargement , vous devez transmettre la connexion en utilisant ADB comme ceci:

adb forward tcp:7080 tcp:8080

après cela vous pouvez utiliser localhost:7080 au lieu de ip.of.your.phone:8080 .

Vous pouvez supprimer cette redirection avec la commande suivante:

adb forward --remove tcp:7080
2
répondu EvgEnZh 2017-05-23 12:18:26

essayez ce gars:

adb shell screencap -p | perl -pe 's/\x0D\x0A/\x0A/g' > screen.png
1
répondu MrG 2017-10-24 08:16:56

il est également possible d'utiliser base64 pour cela, il suffit de l'encoder en utilisant:

base64 foo3.png>foo3.png.base64

et ensuite sur windows en utilisant quelque base64 utility ou peut-être notepad++ pour décrypter le fichier.

ou dans linux / cygwin:

base64 -d foo3.png.base64>foo3.png
1
répondu xdevs23 2018-05-10 10:39:55

vous pouvez également utiliser la commande standard dos2unix si elle est disponible.

( apt-get install dos2unix si vous êtes sur Debian/Ubuntu. Il y a probablement des constructions pour Windows, OS X, etc. là-bas quelque part si vous google).

dos2unix convertit CRLF en LF de la même manière que la fonction repair() D'Eric Lange.

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

ou, réparer un fichier corrompu (sur place) :

dos2unix -f screenshot.png

vous avez besoin de la -f pour la forcer à traiter des fichiers binaires.

0
répondu ejm 2016-11-15 07:13:56

j'ai mis la méthode pour utiliser python get image bytes en utilisant adb ici, peut-être que cela sera utile à quelqu'un qui a rencontré ce problème. Le code est le suivant:

 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)
0
répondu Wenmin-Wu 2018-01-15 06:20:09

cette commande a fonctionné pour moi sur Windows OS :

adb exec-out screencap -p > test.png && dos2unix.exe -f test.png

Mais vous voulez utiliser cette: https://sourceforge.net/projects/dos2unix /

-1
répondu Sebastien247 2017-07-08 14:51:01

nc était le seul moyen pour moi. Utilisé:

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

comme root pour créer une sauvegarde avec un peu de chance appropriée pour / data / media

-1
répondu Remko Bolt 2017-07-20 19:33:26

C'est la meilleure façon D'utiliser Shell dans OS

adb shell screencap -p | perl -pe 's/\x0D\x0A/\x0A/g' > screen.png

-1
répondu Joolah 2017-12-27 08:31:28