Créez des fichiers binaires Android à l'aide de la source et d'Android NDK. Nous pompons l'utilitaire screencap

Je suis engagé dans l'automatisation d'appareils Android et souvent le SDK ou Android OS n'a pas les fonctionnalités nécessaires ou son travail est lent / très lent.

En utilisant les capacités du Kit de développement natif (NDK), nous pouvons écrire des fonctionnalités qui s'exécuteront plus rapidement que la même fonctionnalité en Java. En raison de cette baleine, nous pouvons ajouter du code écrit en C / C ++ à notre application ou créer nos propres fichiers binaires pour les appareils mobiles Android.

Dans cet article, je vais vous expliquer comment configurer la compilation d'un fichier binaire pour le système d'exploitation Android et montrer également comment nous pouvons compléter la fonctionnalité des fichiers binaires existants dans ce système d'exploitation.

Par exemple, je «pompe» une capture d'écran, qui peut non seulement obtenir une capture d'écran de tout l'écran ou donner des «données brutes», mais aussi renvoyer la couleur des pixels à un point spécifié ou obtenir une image de la zone souhaitée uniquement. Alors allons-y!

Installer NDK


Téléchargez Android NDK et décompressez l'archive ou installez-le via le SDK Manager .

Si ce n'est pas encore fait, vous pouvez en ajouter. outils:

sudo apt-get install android-tools-adb android-tools-fastboot 

Et créez un «projet» pour l'architecture de votre appareil mobile:

  ./android-ndk-r12b/build/tools/make_standalone_toolchain.py --arch <arm or arm64 or other> --install-dir ~/arm 

Étant donné que mon HOMTOM HT16 a une architecture armeabi-v7a, j'utiliserai la commande:

  ./android-ndk-r12b/build/tools/make_standalone_toolchain.py --arch arm --install-dir ~/arm 

Et nous attendons que le script crée tous les fichiers nécessaires (jusqu'à 5 minutes environ).

Vérification des performances


Créez un fichier hello_world.c avec un code simple:

 #include <stdio.h> int main () { puts("hello world"); } 

Et essayez de le compiler:

 ~/arm/bin/clang -pie hello_world.c -o hello_world 

En utilisant l'attribut -o , spécifiez le nom du fichier et en utilisant le commutateur -pie, nous indiquons que le fichier binaire PIE et toutes ses dépendances sont chargés dans des emplacements aléatoires dans la mémoire virtuelle à chaque exécution de l'application.

Si la compilation a réussi, téléchargez le fichier sur le téléphone:

 adb push ./hello_world /data/local/tmp 

Et essayez le binaire:

 adb shell /data/local/tmp/hello_world 

Si vous avez vu la sortie de l'expression "bonjour le monde" - alors vous avez tout fait correctement!

Si vous avez encore des erreurs, vous avez peut-être choisi la mauvaise architecture, puis supprimez simplement ce répertoire et recréez-le avec le bon.

Pour déterminer l'architecture, vous pouvez exécuter la commande

 adb shell cat /proc/cpuinfo 

Sources et bibliothèques


Puisque l'analyse du fichier binaire compilé prend beaucoup de temps, et Android est un système ouvert, pourquoi ne pas profiter de cette qualité!

Nous allons ici et cherchons la bonne version d'Android. Eh bien, déjà - téléchargez l'archive et recherchez la source souhaitée du fichier binaire. Bien sûr, il existe une option - Google et la «bonne demande».

Dans mon cas, le fichier dont j'ai besoin se trouve sur ce lien .

screencap.cpp
 #include <errno.h> #include <unistd.h> #include <stdio.h> #include <fcntl.h> #include <stdlib.h> #include <string.h> #include <linux/fb.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <binder/ProcessState.h> #include <gui/SurfaceComposerClient.h> #include <gui/ISurfaceComposer.h> #include <ui/DisplayInfo.h> #include <ui/PixelFormat.h> // TODO: Fix Skia. #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #include <SkImageEncoder.h> #include <SkData.h> #pragma GCC diagnostic pop using namespace android; static uint32_t DEFAULT_DISPLAY_ID = ISurfaceComposer::eDisplayIdMain; static void usage(const char* pname) { fprintf(stderr, "usage: %s [-hp] [-d display-id] [FILENAME]\n" " -h: this message\n" " -p: save the file as a png.\n" " -d: specify the display id to capture, default %d.\n" "If FILENAME ends with .png it will be saved as a png.\n" "If FILENAME is not given, the results will be printed to stdout.\n", pname, DEFAULT_DISPLAY_ID ); } static SkColorType flinger2skia(PixelFormat f) { switch (f) { case PIXEL_FORMAT_RGB_565: return kRGB_565_SkColorType; default: return kN32_SkColorType; } } static status_t vinfoToPixelFormat(const fb_var_screeninfo& vinfo, uint32_t* bytespp, uint32_t* f) { switch (vinfo.bits_per_pixel) { case 16: *f = PIXEL_FORMAT_RGB_565; *bytespp = 2; break; case 24: *f = PIXEL_FORMAT_RGB_888; *bytespp = 3; break; case 32: // TODO: do better decoding of vinfo here *f = PIXEL_FORMAT_RGBX_8888; *bytespp = 4; break; default: return BAD_VALUE; } return NO_ERROR; } static status_t notifyMediaScanner(const char* fileName) { String8 cmd("am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d file://"); String8 fileUrl("\""); fileUrl.append(fileName); fileUrl.append("\""); cmd.append(fileName); cmd.append(" > /dev/null"); int result = system(cmd.string()); if (result < 0) { fprintf(stderr, "Unable to broadcast intent for media scanner.\n"); return UNKNOWN_ERROR; } return NO_ERROR; } int main(int argc, char** argv) { ProcessState::self()->startThreadPool(); const char* pname = argv[0]; bool png = false; int32_t displayId = DEFAULT_DISPLAY_ID; int c; while ((c = getopt(argc, argv, "phd:")) != -1) { switch (c) { case 'p': png = true; break; case 'd': displayId = atoi(optarg); break; case '?': case 'h': usage(pname); return 1; } } argc -= optind; argv += optind; int fd = -1; const char* fn = NULL; if (argc == 0) { fd = dup(STDOUT_FILENO); } else if (argc == 1) { fn = argv[0]; fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664); if (fd == -1) { fprintf(stderr, "Error opening file: %s (%s)\n", fn, strerror(errno)); return 1; } const int len = strlen(fn); if (len >= 4 && 0 == strcmp(fn+len-4, ".png")) { png = true; } } if (fd == -1) { usage(pname); return 1; } void const* mapbase = MAP_FAILED; ssize_t mapsize = -1; void const* base = NULL; uint32_t w, s, h, f; size_t size = 0; // Maps orientations from DisplayInfo to ISurfaceComposer static const uint32_t ORIENTATION_MAP[] = { ISurfaceComposer::eRotateNone, // 0 == DISPLAY_ORIENTATION_0 ISurfaceComposer::eRotate270, // 1 == DISPLAY_ORIENTATION_90 ISurfaceComposer::eRotate180, // 2 == DISPLAY_ORIENTATION_180 ISurfaceComposer::eRotate90, // 3 == DISPLAY_ORIENTATION_270 }; ScreenshotClient screenshot; sp<IBinder> display = SurfaceComposerClient::getBuiltInDisplay(displayId); if (display == NULL) { fprintf(stderr, "Unable to get handle for display %d\n", displayId); return 1; } Vector<DisplayInfo> configs; SurfaceComposerClient::getDisplayConfigs(display, &configs); int activeConfig = SurfaceComposerClient::getActiveConfig(display); if (static_cast<size_t>(activeConfig) >= configs.size()) { fprintf(stderr, "Active config %d not inside configs (size %zu)\n", activeConfig, configs.size()); return 1; } uint8_t displayOrientation = configs[activeConfig].orientation; uint32_t captureOrientation = ORIENTATION_MAP[displayOrientation]; status_t result = screenshot.update(display, Rect(), 0, 0, 0, -1U, false, captureOrientation); if (result == NO_ERROR) { base = screenshot.getPixels(); w = screenshot.getWidth(); h = screenshot.getHeight(); s = screenshot.getStride(); f = screenshot.getFormat(); size = screenshot.getSize(); } else { const char* fbpath = "/dev/graphics/fb0"; int fb = open(fbpath, O_RDONLY); if (fb >= 0) { struct fb_var_screeninfo vinfo; if (ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) == 0) { uint32_t bytespp; if (vinfoToPixelFormat(vinfo, &bytespp, &f) == NO_ERROR) { size_t offset = (vinfo.xoffset + vinfo.yoffset*vinfo.xres) * bytespp; w = vinfo.xres; h = vinfo.yres; s = vinfo.xres; size = w*h*bytespp; mapsize = offset + size; mapbase = mmap(0, mapsize, PROT_READ, MAP_PRIVATE, fb, 0); if (mapbase != MAP_FAILED) { base = (void const *)((char const *)mapbase + offset); } } } close(fb); } } if (base != NULL) { if (png) { const SkImageInfo info = SkImageInfo::Make(w, h, flinger2skia(f), kPremul_SkAlphaType); SkAutoTUnref<SkData> data(SkImageEncoder::EncodeData(info, base, s*bytesPerPixel(f), SkImageEncoder::kPNG_Type, SkImageEncoder::kDefaultQuality)); if (data.get()) { write(fd, data->data(), data->size()); } if (fn != NULL) { notifyMediaScanner(fn); } } else { write(fd, &w, 4); write(fd, &h, 4); write(fd, &f, 4); size_t Bpp = bytesPerPixel(f); for (size_t y=0 ; y<h ; y++) { write(fd, base, w*Bpp); base = (void *)((char *)base + s*Bpp); } } } close(fd); if (mapbase != MAP_FAILED) { munmap((void *)mapbase, mapsize); } return 0; } 


Nous analyserons partiellement ce code.

DEFAULT_DISPLAY_ID - identifiant de l'affichage à partir duquel vous souhaitez obtenir une capture d'écran. Dans notre cas, 0.

flinger2skia et vinfoToPixelFormat - est responsable de la détermination du format de l'image.

notifyMediaScanner - une fois l'image créée dans le système de fichiers, vous devez envoyer une diffusion afin que le fichier puisse s'afficher correctement. Si vous n'appelez pas cette diffusion, toutes les applications ne pourront pas voir le fichier créé.
La fonction principale n'est pas difficile à «lire», nous n'analyserons donc que les points importants qui sont directement responsables de l'obtention des données d'image.

/ dev / graphics / fb0 est le soi-disant framebuffer. Framebuffer est une zone de mémoire vidéo pour le stockage à court terme d'une ou plusieurs images vidéo. Sur la base du code principal, il peut être constaté qu'il existe des versions d'appareils Android qui stockent l'image d'écran dans ce fichier. Ainsi, si vous êtes «chanceux», alors reconnaître vinfo.xoffset et vinfo.yoffset (dans la plupart des cas, ils seront 0) et en utilisant la console, vous pouvez facilement obtenir des informations sur les couleurs:

 dd if=/dev/graphics/fb0 bs=<bytes per pixel> count=1 skip=<pixel offset> 2>/dev/null | hd 

Dans mon cas, tout s'est avéré pas si simple et ce fichier ne contient aucune information d'image.

screenshot.update est la deuxième façon d'obtenir l'image. Cette fonction a plusieurs méthodes surchargées qui peuvent être trouvées ici .

Considérez la description de la fonction avec le plus grand nombre de paramètres:

 ScreenshotClient::update(const sp<IBinder>& display, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ, bool useIdentityTransform, uint32_t rotation) 

affichage - lien vers l'affichage requis.
sourceCrop - recadre la zone d'image sélectionnée. Il peut contenir les coordonnées du point supérieur gauche et inférieur droit (au total 4 paramètres xLeft, yTop, xRight, yBottom). L'origine est le coin supérieur gauche.
reqWidth - largeur de l'image retournée
reqHeight - hauteur de l'image retournée
minLayerZ et maxLayerZ - le fonctionnement de ces paramètres n'a pas pu être compris. L'énumération des valeurs a parfois produit un robinet noir
useIdentityTransform - Si vrai, désactive la couche de superposition au-dessus des applications, c'est-à-dire les activités qui utilisent ACTION_MANAGE_OVERLAY_PERMISSION
rotation - rotation de l'image.

Ainsi, afin d'obtenir la couleur des pixels, nous devons définir xLeft et yTop, en les décalant de 1, car le compte à rebours passera de 0 et définira les coordonnées spécifiées sur xRight, yBottom. Dans reqWidth et reqHeight, définissez la valeur sur 1. En modifiant les paramètres de cette fonction, nous pouvons déterminer les limites de la zone dont nous avons besoin.

Compilation d'un screencap.cpp de base


C'est en fait la partie la plus difficile, qui peut prendre plusieurs jours ou une semaine entière. Malheureusement, je n'ai pas pu trouver de solutions rapides pour construire une nouvelle version de screencap sur le réseau, j'ai donc dû me tourmenter spécifiquement avec clang et ses paramètres.

Si vous essayez immédiatement de compiler ce code, le compilateur jurera constamment qu'il n'y a pas de fichier, et parfois il peut signaler que le fichier est là, mais aucun constructeur n'est nécessaire.

Par conséquent, au départ, j'ai ajouté tous les fichiers qui n'étaient pas dans la bibliothèque NDK. Les erreurs donnent une idée de l'emplacement de tel ou tel fichier. Pour ce faire, vous devez ajouter les fichiers manquants et pour savoir où se trouve sysroot (le répertoire où clang recherche), vous pouvez utiliser la "fonctionnalité" suivante:

 echo "#include <bogus.h> int main(){}" > tc; ~/arm/bin/clang -v tc; rm tc 

L'erreur affichera le chemin d'accès à ce répertoire. Si votre clang se trouve ailleurs, changez de chemin.

Journal
 Android (4751641 based on r328903) clang version 7.0.2 (https://android.googlesource.com/toolchain/clang 003100370607242ddd5815e4a043907ea9004281) (https://android.googlesource.com/toolchain/llvm 1d739ffb0366421d383e04ff80ec2ee591315116) (based on LLVM 7.0.2svn) Target: armv7a-none-linux-android16 Thread model: posix InstalledDir: /Users/macbookair/arm/bin Found candidate GCC installation: /Users/macbookair/arm/bin/../lib/gcc/arm-linux-androideabi/4.9.x Selected GCC installation: /Users/macbookair/arm/bin/../lib/gcc/arm-linux-androideabi/4.9.x Candidate multilib: thumb;@mthumb Candidate multilib: armv7-a;@march=armv7-a Candidate multilib: armv7-a/thumb;@march=armv7-a@mthumb Candidate multilib: .; Selected multilib: armv7-a;@march=armv7-a "/Users/macbookair/arm/bin/clang70" -cc1 -triple armv7-none-linux-android16 -emit-obj -mrelax-all -disable-free -disable-llvm-verifier -discard-value-names -main-file-name tc -mrelocation-model pic -pic-level 2 -pic-is-pie -mthread-model posix -mdisable-fp-elim -fmath-errno -masm-verbose -mconstructor-aliases -fuse-init-array -target-cpu generic -target-feature +soft-float-abi -target-abi aapcs-linux -mfloat-abi soft -fallow-half-arguments-and-returns -dwarf-column-info -debugger-tuning=gdb -target-linker-version 241.9 -v -resource-dir /Users/macbookair/arm/lib64/clang/7.0.2 -isysroot /Users/macbookair/arm/bin/../sysroot -internal-isystem /Users/macbookair/arm/bin/../sysroot/usr/local/include -internal-isystem /Users/macbookair/arm/lib64/clang/7.0.2/include -internal-externc-isystem /Users/macbookair/arm/bin/../sysroot/include -internal-externc-isystem /Users/macbookair/arm/bin/../sysroot/usr/include -fdebug-compilation-dir /Users/macbookair/Downloads/sji-android-screen-capture-master/src/android/capture -ferror-limit 19 -fmessage-length 80 -fno-signed-char -fobjc-runtime=gcc -fdiagnostics-show-option -fcolor-diagnostics -o /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/t-9f5ef7.o -xc tc clang -cc1 version 7.0.2 based upon LLVM 7.0.2svn default target x86_64-apple-darwin18.0.0 ignoring nonexistent directory "/Users/macbookair/arm/bin/../sysroot/include" #include "..." search starts here: #include <...> search starts here: /Users/macbookair/arm/bin/../sysroot/usr/local/include /Users/macbookair/arm/lib64/clang/7.0.2/include /Users/macbookair/arm/bin/../sysroot/usr/include End of search list. tc:1:10: error: expected "FILENAME" or <FILENAME> #include <bogus.h> int main(){} ^ 1 error generated. https://android.googlesource.com/toolchain/clang 003100370607242ddd5815e4a043907ea9004281) (https://android.googlesource.com/toolchain/llvm 1d739ffb0366421d383e04ff80ec2ee591315116) (basé sur LLVM 7.0. Android (4751641 based on r328903) clang version 7.0.2 (https://android.googlesource.com/toolchain/clang 003100370607242ddd5815e4a043907ea9004281) (https://android.googlesource.com/toolchain/llvm 1d739ffb0366421d383e04ff80ec2ee591315116) (based on LLVM 7.0.2svn) Target: armv7a-none-linux-android16 Thread model: posix InstalledDir: /Users/macbookair/arm/bin Found candidate GCC installation: /Users/macbookair/arm/bin/../lib/gcc/arm-linux-androideabi/4.9.x Selected GCC installation: /Users/macbookair/arm/bin/../lib/gcc/arm-linux-androideabi/4.9.x Candidate multilib: thumb;@mthumb Candidate multilib: armv7-a;@march=armv7-a Candidate multilib: armv7-a/thumb;@march=armv7-a@mthumb Candidate multilib: .; Selected multilib: armv7-a;@march=armv7-a "/Users/macbookair/arm/bin/clang70" -cc1 -triple armv7-none-linux-android16 -emit-obj -mrelax-all -disable-free -disable-llvm-verifier -discard-value-names -main-file-name tc -mrelocation-model pic -pic-level 2 -pic-is-pie -mthread-model posix -mdisable-fp-elim -fmath-errno -masm-verbose -mconstructor-aliases -fuse-init-array -target-cpu generic -target-feature +soft-float-abi -target-abi aapcs-linux -mfloat-abi soft -fallow-half-arguments-and-returns -dwarf-column-info -debugger-tuning=gdb -target-linker-version 241.9 -v -resource-dir /Users/macbookair/arm/lib64/clang/7.0.2 -isysroot /Users/macbookair/arm/bin/../sysroot -internal-isystem /Users/macbookair/arm/bin/../sysroot/usr/local/include -internal-isystem /Users/macbookair/arm/lib64/clang/7.0.2/include -internal-externc-isystem /Users/macbookair/arm/bin/../sysroot/include -internal-externc-isystem /Users/macbookair/arm/bin/../sysroot/usr/include -fdebug-compilation-dir /Users/macbookair/Downloads/sji-android-screen-capture-master/src/android/capture -ferror-limit 19 -fmessage-length 80 -fno-signed-char -fobjc-runtime=gcc -fdiagnostics-show-option -fcolor-diagnostics -o /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/t-9f5ef7.o -xc tc clang -cc1 version 7.0.2 based upon LLVM 7.0.2svn default target x86_64-apple-darwin18.0.0 ignoring nonexistent directory "/Users/macbookair/arm/bin/../sysroot/include" #include "..." search starts here: #include <...> search starts here: /Users/macbookair/arm/bin/../sysroot/usr/local/include /Users/macbookair/arm/lib64/clang/7.0.2/include /Users/macbookair/arm/bin/../sysroot/usr/include End of search list. tc:1:10: error: expected "FILENAME" or <FILENAME> #include <bogus.h> int main(){} ^ 1 error generated. 


Nous nous tournons vers Google et recherchons tous les fichiers nécessaires. Dans mon cas, j'ai dû ajouter les répertoires et fichiers suivants:

Répertoires et fichiers
 //  ~/arm/sysroot/usr/include/binder ~/arm/sysroot/usr/include/utils ~/arm/sysroot/usr/include/cutils ~/arm/sysroot/usr/include/log ~/arm/sysroot/usr/include/system ~/arm/sysroot/usr/include/gui ~/arm/sysroot/usr/include/ui ~/arm/sysroot/usr/include/hardware ~/arm/sysroot/usr/ports //  ~/arm/sysroot/usr/include/SkAnnotation.h ~/arm/sysroot/usr/include/SkAtomics.h ~/arm/sysroot/usr/include/SkBBHFactory.h ~/arm/sysroot/usr/include/SkBitmap.h ~/arm/sysroot/usr/include/SkBitmapDevice.h ~/arm/sysroot/usr/include/SkBlitRow.h ~/arm/sysroot/usr/include/SkBlurTypes.h ~/arm/sysroot/usr/include/SkCanvas.h ~/arm/sysroot/usr/include/SkChunkAlloc.h ~/arm/sysroot/usr/include/SkClipStack.h ~/arm/sysroot/usr/include/SkColor.h ~/arm/sysroot/usr/include/SkColorFilter.h ~/arm/sysroot/usr/include/SkColorPriv.h ~/arm/sysroot/usr/include/SkColorTable.h ~/arm/sysroot/usr/include/SkComposeShader.h ~/arm/sysroot/usr/include/SkData.h ~/arm/sysroot/usr/include/SkDataTable.h ~/arm/sysroot/usr/include/SkDeque.h ~/arm/sysroot/usr/include/SkDevice.h ~/arm/sysroot/usr/include/SkDither.h ~/arm/sysroot/usr/include/SkDocument.h ~/arm/sysroot/usr/include/SkDraw.h ~/arm/sysroot/usr/include/SkDrawable.h ~/arm/sysroot/usr/include/SkDrawFilter.h ~/arm/sysroot/usr/include/SkDrawLooper.h ~/arm/sysroot/usr/include/SkDrawPictureCallback.h ~/arm/sysroot/usr/include/SkEndian.h ~/arm/sysroot/usr/include/SkError.h ~/arm/sysroot/usr/include/SkFilterQuality.h ~/arm/sysroot/usr/include/SkFixed.h ~/arm/sysroot/usr/include/SkFlattenable.h ~/arm/sysroot/usr/include/SkFlattenableSerialization.h ~/arm/sysroot/usr/include/SkFloatBits.h ~/arm/sysroot/usr/include/SkFloatingPoint.h ~/arm/sysroot/usr/include/SkFont.h ~/arm/sysroot/usr/include/SkFontHost.h ~/arm/sysroot/usr/include/SkFontLCDConfig.h ~/arm/sysroot/usr/include/SkFontStyle.h ~/arm/sysroot/usr/include/SkGraphics.h ~/arm/sysroot/usr/include/SkImage.h ~/arm/sysroot/usr/include/SkImageDecoder.h ~/arm/sysroot/usr/include/SkImageEncoder.h ~/arm/sysroot/usr/include/SkImageFilter.h ~/arm/sysroot/usr/include/SkImageGenerator.h ~/arm/sysroot/usr/include/SkImageInfo.h ~/arm/sysroot/usr/include/SkInstCnt.h ~/arm/sysroot/usr/include/SkLazyPtr.h ~/arm/sysroot/usr/include/SkMallocPixelRef.h ~/arm/sysroot/usr/include/SkMask.h ~/arm/sysroot/usr/include/SkMaskFilter.h ~/arm/sysroot/usr/include/SkMath.h ~/arm/sysroot/usr/include/SkMatrix.h ~/arm/sysroot/usr/include/SkMetaData.h ~/arm/sysroot/usr/include/SkMultiPictureDraw.h ~/arm/sysroot/usr/include/SkMutex.h ~/arm/sysroot/usr/include/SkOnce.h ~/arm/sysroot/usr/include/SkOSFile.h ~/arm/sysroot/usr/include/SkPackBits.h ~/arm/sysroot/usr/include/SkPaint.h ~/arm/sysroot/usr/include/SkPath.h ~/arm/sysroot/usr/include/SkPathEffect.h ~/arm/sysroot/usr/include/SkPathMeasure.h ~/arm/sysroot/usr/include/SkPathRef.h ~/arm/sysroot/usr/include/SkPicture.h ~/arm/sysroot/usr/include/SkPictureRecorder.h ~/arm/sysroot/usr/include/SkPixelRef.h ~/arm/sysroot/usr/include/SkPixelSerializer.h ~/arm/sysroot/usr/include/SkPoint.h ~/arm/sysroot/usr/include/SkPostConfig.h ~/arm/sysroot/usr/include/SkPreConfig.h ~/arm/sysroot/usr/include/SkRasterizer.h ~/arm/sysroot/usr/include/SkRect.h ~/arm/sysroot/usr/include/SkRefCnt.h ~/arm/sysroot/usr/include/SkRegion.h ~/arm/sysroot/usr/include/SkRRect.h ~/arm/sysroot/usr/include/SkScalar.h ~/arm/sysroot/usr/include/SkShader.h ~/arm/sysroot/usr/include/SkSize.h ~/arm/sysroot/usr/include/SkSpinlock.h ~/arm/sysroot/usr/include/SkStream.h ~/arm/sysroot/usr/include/SkString.h ~/arm/sysroot/usr/include/SkStrokeRec.h ~/arm/sysroot/usr/include/SkSurface.h ~/arm/sysroot/usr/include/SkSurfaceProps.h ~/arm/sysroot/usr/include/SkTArray.h ~/arm/sysroot/usr/include/SkTDArray.h ~/arm/sysroot/usr/include/SkTDict.h ~/arm/sysroot/usr/include/SkTDStack.h ~/arm/sysroot/usr/include/SkTemplates.h ~/arm/sysroot/usr/include/SkTextBlob.h ~/arm/sysroot/usr/include/SkThread.h ~/arm/sysroot/usr/include/SkTime.h ~/arm/sysroot/usr/include/SkTInternalLList.h ~/arm/sysroot/usr/include/SkTLazy.h ~/arm/sysroot/usr/include/SkTRegistry.h ~/arm/sysroot/usr/include/SkTSearch.h ~/arm/sysroot/usr/include/SkTypeface.h ~/arm/sysroot/usr/include/SkTypes.h ~/arm/sysroot/usr/include/SkUnPreMultiply.h ~/arm/sysroot/usr/include/SkUserConfig.h ~/arm/sysroot/usr/include/SkUtils.h ~/arm/sysroot/usr/include/SkWeakRefCnt.h ~/arm/sysroot/usr/include/SkWriteBuffer.h ~/arm/sysroot/usr/include/SkWriter32.h ~/arm/sysroot/usr/include/SkXfermode.h //    ~/arm/sysroot/usr/include/android/log.h 


Et il semblerait qu'ici il soit un succès, tout ce qu'il faut ajouter. Compilation

 ~/arm/bin/clang -pie screencap.cpp -o ./screencap 

et nous obtenons un résultat terrible:

Ne semble pas nerveux
 /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function main: error: undefined reference to 'android::ProcessState::self()' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function main: error: undefined reference to 'android::ProcessState::startThreadPool()' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function main: error: undefined reference to 'android::ScreenshotClient::ScreenshotClient()' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function main: error: undefined reference to 'android::SurfaceComposerClient::getBuiltInDisplay(int)' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function main: error: undefined reference to 'android::SurfaceComposerClient::getDisplayConfigs(android::sp<android::IBinder> const&, android::Vector<android::DisplayInfo>*)' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function main: error: undefined reference to 'android::SurfaceComposerClient::getActiveConfig(android::sp<android::IBinder> const&)' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function main: error: undefined reference to 'android::ScreenshotClient::update(android::sp<android::IBinder> const&, android::Rect, unsigned int, unsigned int, unsigned int, unsigned int, bool, unsigned int)' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function main: error: undefined reference to 'android::ScreenshotClient::getPixels() const' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function main: error: undefined reference to 'android::ScreenshotClient::getWidth() const' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function main: error: undefined reference to 'android::ScreenshotClient::getHeight() const' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function main: error: undefined reference to 'android::ScreenshotClient::getStride() const' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function main: error: undefined reference to 'android::ScreenshotClient::getFormat() const' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function main: error: undefined reference to 'android::ScreenshotClient::getSize() const' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function main: error: undefined reference to 'android::bytesPerPixel(int)' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function main: error: undefined reference to 'SkImageEncoder::EncodeData(SkImageInfo const&, void const*, unsigned int, SkImageEncoder::Type, int)' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function main: error: undefined reference to 'android::bytesPerPixel(int)' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function main: error: undefined reference to 'android::ScreenshotClient::~ScreenshotClient()' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function main: error: undefined reference to 'android::ScreenshotClient::~ScreenshotClient()' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function main: error: undefined reference to 'stderr' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function main: error: undefined reference to 'stderr' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function main: error: undefined reference to 'stderr' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function usage(char const*): error: undefined reference to 'stderr' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function notifyMediaScanner(char const*): error: undefined reference to 'android::String8::String8(char const*)' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function notifyMediaScanner(char const*): error: undefined reference to 'android::String8::String8(char const*)' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function notifyMediaScanner(char const*): error: undefined reference to 'android::String8::append(char const*)' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function notifyMediaScanner(char const*): error: undefined reference to 'android::String8::append(char const*)' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function notifyMediaScanner(char const*): error: undefined reference to 'android::String8::append(char const*)' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function notifyMediaScanner(char const*): error: undefined reference to 'android::String8::append(char const*)' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function notifyMediaScanner(char const*): error: undefined reference to 'android::String8::~String8()' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function notifyMediaScanner(char const*): error: undefined reference to 'android::String8::~String8()' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function notifyMediaScanner(char const*): error: undefined reference to 'android::String8::~String8()' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function notifyMediaScanner(char const*): error: undefined reference to 'android::String8::~String8()' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o(.ARM.extab+0x0): error: undefined reference to '__gxx_personality_v0' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o(.ARM.extab+0x48): error: undefined reference to '__gxx_personality_v0' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function android::sp<android::ProcessState>::~sp(): error: undefined reference to 'android::RefBase::decStrong(void const*) const' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o(.ARM.extab.text._ZN7android2spINS_12ProcessStateEED2Ev+0x0): error: undefined reference to '__gxx_personality_v0' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function android::Vector<android::DisplayInfo>::Vector(): error: undefined reference to 'android::VectorImpl::VectorImpl(unsigned int, unsigned int)' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function android::Vector<android::DisplayInfo>::operator[](unsigned int) const: error: undefined reference to '__android_log_assert' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o(.ARM.extab.text._ZN12SkAutoTUnrefI6SkDataED2Ev+0x0): error: undefined reference to '__gxx_personality_v0' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function android::Vector<android::DisplayInfo>::~Vector(): error: undefined reference to 'android::VectorImpl::finish_vector()' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function android::Vector<android::DisplayInfo>::~Vector(): error: undefined reference to 'android::VectorImpl::~VectorImpl()' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function android::Vector<android::DisplayInfo>::~Vector(): error: undefined reference to 'android::VectorImpl::~VectorImpl()' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function android::sp<android::IBinder>::~sp(): error: undefined reference to 'android::RefBase::decStrong(void const*) const' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function __clang_call_terminate: error: undefined reference to '__cxa_begin_catch' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function __clang_call_terminate: error: undefined reference to 'std::terminate()' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function android::Vector<android::DisplayInfo>::~Vector(): error: undefined reference to 'operator delete(void*)' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:function SkRefCntBase::unref() const: error: undefined reference to 'SkDebugf(char const*, ...)' /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:typeinfo for android::Vector<android::DisplayInfo>: error: undefined reference to 'vtable for __cxxabiv1::__vmi_class_type_info' /Users/macbookair/Documents/test/bin/../lib/gcc/arm-linux-androideabi/4.9.x/../../../../arm-linux-androideabi/bin/ld: the vtable symbol may be undefined because the class is missing its key function /var/folders/_4/7d51802j1hz2rnmql8kngx5w0000gn/T/screencap-175810.o:screencap.cpp:typeinfo for android::Vector<android::DisplayInfo>: error: undefined reference to 'typeinfo for android::VectorImpl' clang70: error: linker command failed with exit code 1 (use -v to see invocation) 


Pour moi, c'était un vrai enfer, car de nombreux fichiers comportaient des erreurs, ce qui ne devrait pas l'être en théorie, car le contenu de ces fichiers n'a pas changé. À ce stade, je me suis assis pendant longtemps et j'ai commencé à rechercher activement les erreurs sur Google, mais je n'ai pas trouvé la réponse dont j'avais besoin. Comment j'ai décidé d'étudier le tutoriel sur le clang, je ne m'en souviens pas, mais cette solution m'a sauvé!

Il s'est avéré que clang a un paramètre (ou plutôt ld ) - symboles non résolus, qui est responsable du travail avec les caractères non résolus. , . :

 ~/arm/bin/clang -pie screencap.cpp -o ./screencap -Wl,--unresolved-symbols=ignore-all -s 

- ! , , , . , :

 CANNOT LINK EXECUTABLE: cannot locate symbol "_ZN7android12ProcessState4selfEv" 

, , Android .so . , . screencap, Android- (/system/bin/screencap) .so , . :

 ...libdl.so__libc_initlibc.so__cxa_atexit__register_atfork__gnu_Unwind_Find_exidxLIBC_PRIVATE_ZNK7android6VectorINS_11DisplayInfoEE12do_constructEPvj__snprintf_chk__aeabi_memset__aeabi_memcpy_ZNK7android6VectorINS_11DisplayInfoEE10do_destroyEPvj_ZNK7android6VectorINS_11DisplayInfoEE7do_copyEPvPKvj_ZNK7android6VectorINS_11DisplayInfoEE8do_splatEPvPKvj_ZNK7android6VectorINS_11DisplayInfoEE15do_move_forwardEPvPKvj_ZNK7android6VectorINS_11DisplayInfoEE16do_move_backwardEPvPKvj_ZN7android10VectorImpl13finish_vectorEv_ZN7android10VectorImplD2Ev_ZTVN7android6VectorINS_11DisplayInfoEEE_ZdlPvsignal__android_log_print_ZN7android12ProcessState4selfEv_ZN7android12ProcessState15startThreadPoolEv_ZNK7android7RefBase9decStrongEPKvgetoptatoidupopen__errnostrerrorfprintfstrlenstrcmp_ZN7android16ScreenshotClientC1Ev_ZN7android21SurfaceComposerClient17getBuiltInDisplayEi_ZN7android10VectorImplC2Ejj_ZN7android21SurfaceComposerClient17getDisplayConfigsERKNS_2spINS_7IBinderEEEPNS_6VectorINS_11DisplayInfoEEE_ZN7android21SurfaceComposerClient15getActiveConfigERKNS_2spINS_7IBinderEEE_ZN7android16ScreenshotClient6updateERKNS_2spINS_7IBinderEEENS_4RectEjjjjbj_ZNK7android16ScreenshotClient9getPixelsEv_ZNK7android16ScreenshotClient8getWidthEv_ZNK7android16ScreenshotClient9getHeightEv_ZNK7android16ScreenshotClient9getStrideEv_ZNK7android16ScreenshotClient9getFormatEv_ZNK7android16ScreenshotClient7getSizeEvioctlclose_ZN7android13bytesPerPixelEi_ZN14SkImageEncoder10EncodeDataERK11SkImageInfoPKvjNS_4TypeEiwrite_ZN7android7String8C1EPKc_ZN7android7String86appendEPKcsystemfputs_ZN7android7String8D1Evmunmap_ZN7android16ScreenshotClientD1Evmmapoptargstderroptindabort_edata__bss_start_endlibcutils.solibutils.solibbinder.solibskia.solibui.solibgui.solibc++.solibm.so... 


, . : libgui.so, libui.so, libcutils.so, libutils.so, libbinder.so, libskia.so. ( , ):

 find -name 'libskia.so' 2>/dev/null /system/lib/libskia.so 

sdcard/libs ( libskia.so):

 ./system/lib/libskia.so /sdcard/ 

adb pull . :

 adb pull /sdcard/libs ~/arm 

, *.so, , .so , — .

 ~/arm/bin/clang -pie screencap.cpp *.so -o ./screencap -Wl,--unresolved-symbols=ignore-all -s 

. .


, « » .

screencap . , . , .

screencap.cpp
 #include <errno.h> #include <unistd.h> #include <stdio.h> #include <fcntl.h> #include <stdlib.h> #include <string.h> #include <linux/fb.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <binder/ProcessState.h> #include <gui/SurfaceComposerClient.h> #include <gui/ISurfaceComposer.h> #include <ui/DisplayInfo.h> #include <ui/PixelFormat.h> // TODO: Fix Skia. #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #include <SkImageEncoder.h> #include <SkData.h> #pragma GCC diagnostic pop using namespace android; static uint32_t DEFAULT_DISPLAY_ID = ISurfaceComposer::eDisplayIdMain; static void usage(const char* pname) { fprintf(stderr, "usage: %s [-hpcr] [-d display-id] [FILENAME] [x1 y1] [x2 y2]\n" " -h: this message\n" " -p: save the file as a png.\n" " -d: specify the display id to capture, default %d.\n" " -c: print pixel color [xy].\n" " -r: get rectangle area [x1 - left y1 - top x2 - right y2 - bottom].\n" "If FILENAME ends with .png it will be saved as a png.\n" "If FILENAME is not given, the results will be printed to stdout.\n", pname, DEFAULT_DISPLAY_ID ); } static SkColorType flinger2skia(PixelFormat f) { switch (f) { case PIXEL_FORMAT_RGB_565: return kRGB_565_SkColorType; default: return kN32_SkColorType; } } static status_t vinfoToPixelFormat(const fb_var_screeninfo& vinfo, uint32_t* bytespp, uint32_t* f) { switch (vinfo.bits_per_pixel) { case 16: *f = PIXEL_FORMAT_RGB_565; *bytespp = 2; break; case 24: *f = PIXEL_FORMAT_RGB_888; *bytespp = 3; break; case 32: // TODO: do better decoding of vinfo here *f = PIXEL_FORMAT_RGBX_8888; *bytespp = 4; break; default: return BAD_VALUE; } return NO_ERROR; } static status_t notifyMediaScanner(const char* fileName) { String8 cmd("am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d file://"); String8 fileUrl("\""); fileUrl.append(fileName); fileUrl.append("\""); cmd.append(fileName); cmd.append(" > /dev/null"); int result = system(cmd.string()); if (result < 0) { fprintf(stderr, "Unable to broadcast intent for media scanner.\n"); return UNKNOWN_ERROR; } return NO_ERROR; } int main(int argc, char** argv) { ProcessState::self()->startThreadPool(); const char* pname = argv[0]; int x1,x2,y1,y2; bool png = false; bool color = false; bool rectangle = false; int32_t displayId = DEFAULT_DISPLAY_ID; int c; while ((c = getopt(argc, argv, "phdcr:")) != -1) { switch (c) { case 'p': png = true; break; case 'd': displayId = atoi(optarg); break; case 'c': color = true; break; case 'r': rectangle = true; break; case '?': case 'h': usage(pname); return 1; } } argc -= optind; if (color) { x1 = atoi(argv[2])-1; y1 = atoi(argv[3])-1; x2 = atoi(argv[2]); y2 = atoi(argv[3]); } else if (rectangle) { x1 = atoi(argv[3]); y1 = atoi(argv[4]); x2 = atoi(argv[5]); y2 = atoi(argv[6]); optind--; } argv += optind; int fd = -1; const char* fn = NULL; if (argc == 0) { fd = dup(STDOUT_FILENO); } else if (argc == 1 || argc == 4) { fn = argv[0]; fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664); if (fd == -1) { fprintf(stderr, "Error opening file: %s (%s)\n", fn, strerror(errno)); return 1; } const int len = strlen(fn); if (len >= 4 && 0 == strcmp(fn+len-4, ".png")) { png = true; } } if (fd == -1 && !color && !rectangle) { usage(pname); return 1; } void const* mapbase = MAP_FAILED; ssize_t mapsize = -1; void const* base = NULL; uint32_t w, s, h, f; size_t size = 0; // Maps orientations from DisplayInfo to ISurfaceComposer static const uint32_t ORIENTATION_MAP[] = { ISurfaceComposer::eRotateNone, // 0 == DISPLAY_ORIENTATION_0 ISurfaceComposer::eRotate270, // 1 == DISPLAY_ORIENTATION_90 ISurfaceComposer::eRotate180, // 2 == DISPLAY_ORIENTATION_180 ISurfaceComposer::eRotate90, // 3 == DISPLAY_ORIENTATION_270 }; ScreenshotClient screenshot; sp<IBinder> display = SurfaceComposerClient::getBuiltInDisplay(displayId); if (display == NULL) { fprintf(stderr, "Unable to get handle for display %d\n", displayId); return 1; } Vector<DisplayInfo> configs; SurfaceComposerClient::getDisplayConfigs(display, &configs); int activeConfig = SurfaceComposerClient::getActiveConfig(display); if (static_cast<size_t>(activeConfig) >= configs.size()) { fprintf(stderr, "Active config %d not inside configs (size %zu)\n", activeConfig, configs.size()); return 1; } uint8_t displayOrientation = configs[activeConfig].orientation; uint32_t captureOrientation = ORIENTATION_MAP[displayOrientation]; status_t result; if (color || rectangle) { result = screenshot.update(display, Rect(x1,y1,x2,y2), x2-x1, y2-y1, 0, -1U, false, captureOrientation); } else { result = screenshot.update(display, Rect(), 0, 0, 0, -1U, false, captureOrientation); } if (result == NO_ERROR) { base = screenshot.getPixels(); w = screenshot.getWidth(); h = screenshot.getHeight(); s = screenshot.getStride(); f = screenshot.getFormat(); size = screenshot.getSize(); if (color) { size_t Bpp = 4; //bytesPerPixel char* rawImageData; rawImageData = (char *)base; base = (void *)((char *)base + Bpp); for (int i=0; i<sizeof(rawImageData); i++) { printf( "%02X", rawImageData[i]); } return 1; } } else { const char* fbpath = "/dev/graphics/fb0"; int fb = open(fbpath, O_RDONLY); if (fb >= 0) { struct fb_var_screeninfo vinfo; if (ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) == 0) { uint32_t bytespp; if (vinfoToPixelFormat(vinfo, &bytespp, &f) == NO_ERROR) { size_t offset = (vinfo.xoffset + vinfo.yoffset*vinfo.xres) * bytespp; w = vinfo.xres; h = vinfo.yres; s = vinfo.xres; size = w*h*bytespp; mapsize = offset + size; mapbase = mmap(0, mapsize, PROT_READ, MAP_PRIVATE, fb, 0); if (mapbase != MAP_FAILED) { base = (void const *)((char const *)mapbase + offset); } } } close(fb); } } if (base != NULL) { if (png) { const SkImageInfo info = SkImageInfo::Make(w, h, flinger2skia(f), kPremul_SkAlphaType); SkAutoTUnref<SkData> data(SkImageEncoder::EncodeData(info, base, s*bytesPerPixel(f), SkImageEncoder::kPNG_Type, SkImageEncoder::kDefaultQuality)); if (data.get()) { write(fd, data->data(), data->size()); } if (fn != NULL) { notifyMediaScanner(fn); } } else { write(fd, &w, 4); write(fd, &h, 4); write(fd, &f, 4); size_t Bpp = bytesPerPixel(f); for (size_t y=0 ; y<h ; y++) { write(fd, base, w*Bpp); base = (void *)((char *)base + s*Bpp); } } } close(fd); if (mapbase != MAP_FAILED) { munmap((void *)mapbase, mapsize); } return 0; } 


:

 ./screencap -c 100 100 

:

 ./screencap -r /sdcard/test.png 0 0 720 640 

GitHub , — .

PS , — .

Source: https://habr.com/ru/post/fr456264/


All Articles