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?
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.
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
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.
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?
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.
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.
une autre voie:
adb shell "busybox stty raw; screencap -p "> foo3.png
mais, comme @osexp2003 dit, qui ne fonctionne pas pour Windows OS.
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
essayez ce gars:
adb shell screencap -p | perl -pe 's/\x0D\x0A/\x0A/g' > screen.png
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
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.
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)
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 /
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
C'est la meilleure façon D'utiliser Shell dans OS
adb shell screencap -p | perl -pe 's/\x0D\x0A/\x0A/g' > screen.png