Cree archivos binarios de Android con código fuente y NDK de Android. Bombeamos la utilidad screencap

Me dedico a la automatización de dispositivos Android y, a menudo, el SDK o el sistema operativo Android no tienen la funcionalidad necesaria o su trabajo es lento / muy lento.

Usando las capacidades del Native Development Kit (NDK), podemos escribir funcionalidades que se ejecutarán más rápido que la misma funcionalidad en Java. Debido a esta ballena, podemos agregar código escrito en C / C ++ a nuestra aplicación o crear nuestros propios archivos binarios para dispositivos móviles Android.

En este artículo, le diré cómo podemos configurar la compilación de un archivo binario para el sistema operativo Android, y también mostraré el proceso de cómo podemos complementar la funcionalidad de los archivos binarios existentes en este sistema operativo.

Por ejemplo, "bombeo" una captura de pantalla, que no solo puede obtener una captura de pantalla de toda la pantalla o dar "datos en bruto", sino que también devuelve el color del píxel en un punto específico u obtiene una imagen del área deseada. ¡Entonces vamos!

Instalar NDK


Descarga Android NDK y descomprime el archivo o instálalo a través del SDK Manager .

Si aún no, puede agregar más. herramientas:

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

Y cree un "proyecto" para la arquitectura de su dispositivo móvil:

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

Como mi HOMTOM HT16 tiene arquitectura armeabi-v7a, usaré el comando:

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

Y esperamos hasta que el script cree todos los archivos necesarios (hasta 5 minutos aproximadamente).

Comprobación de rendimiento


Cree un archivo hello_world.c con código simple:

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

Y trata de compilarlo:

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

Usando el atributo -o , especifique el nombre del archivo, y usando el modificador -pie, indicamos que el archivo binario PIE y todas sus dependencias se cargan en ubicaciones aleatorias en la memoria virtual cada vez que se ejecuta la aplicación.

Si la compilación fue exitosa, suba el archivo al teléfono:

 adb push ./hello_world /data/local/tmp 

Y prueba el binario:

 adb shell /data/local/tmp/hello_world 

Si viste el resultado de la frase "hola mundo", ¡entonces hiciste todo bien!

Si todavía tiene errores, tal vez haya elegido la arquitectura incorrecta, simplemente elimine este directorio y vuelva a crearlo con el correcto.

Para determinar la arquitectura, puede ejecutar el comando

 adb shell cat /proc/cpuinfo 

Fuentes y bibliotecas


Dado que el análisis del archivo binario compilado lleva mucho tiempo, y Android es un sistema abierto, ¿por qué no aprovechar esta calidad?

Vamos aquí y buscamos la versión correcta de Android. Bueno, ya - descargue el archivo y busque la fuente deseada del archivo binario. Aunque, por supuesto, hay una opción: Google y la "solicitud correcta".

En mi caso, el archivo que necesito se encuentra en este enlace .

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; } 


Analizaremos parcialmente este código.

DEFAULT_DISPLAY_ID : identificador de la pantalla desde la que desea obtener una captura de pantalla. En nuestro caso, 0.

flinger2skia y vinfoToPixelFormat : es responsable de determinar en qué formato debe estar la imagen.

notifyMediaScanner : después de crear la imagen en el sistema de archivos, debe enviar la transmisión para que el archivo se pueda mostrar correctamente. Si no llama a esta transmisión, no todas las aplicaciones podrán ver el archivo creado.
La función principal no es difícil de "leer", por lo que analizaremos solo los puntos importantes que son directamente responsables de obtener datos de imagen.

/ dev / graphics / fb0 es el llamado framebuffer. Framebuffer es un área de memoria de video para el almacenamiento a corto plazo de uno o más cuadros de video. Según el código principal, se puede ver que hay versiones de dispositivos Android que almacenan la imagen de la pantalla en este archivo. Por lo tanto, si tiene “suerte”, reconozca vinfo.xoffset y vinfo.yoffset (en la mayoría de los casos serán 0) y utilizando la consola puede obtener fácilmente información de color:

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

En mi caso, todo resultó no ser tan simple y este archivo no contiene ninguna información de imagen.

screenshot.update es la segunda forma de obtener la imagen. Esta función tiene varios métodos sobrecargados que se pueden encontrar aquí .

Considere la descripción de la función con el mayor número de parámetros:

 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) 

pantalla : enlace a la pantalla requerida.
sourceCrop : recorte del área de imagen seleccionada. Puede contener las coordenadas del punto superior izquierdo y el inferior derecho (en total 4 parámetros xLeft, yTop, xRight, yBottom). El origen es la esquina superior izquierda.
reqWidth : ancho de la imagen devuelta
reqHeight : altura de la imagen devuelta
minLayerZ y maxLayerZ : no se pudo entender cómo funcionan estos parámetros. La enumeración de valores a veces produce un toque negro
useIdentityTransform : si es verdadero, deshabilita la capa superpuesta en la parte superior de las aplicaciones, es decir aquellas actividades que usan ACTION_MANAGE_OVERLAY_PERMISSION
rotación - rotación de la imagen.

Por lo tanto, para obtener el color del píxel, necesitamos establecer xLeft e yTop, desplazándolos por 1, porque la cuenta regresiva irá desde 0 y establecerá las coordenadas especificadas en xRight, yBottom. En reqWidth y reqHeight establezca el valor en 1. Al cambiar los parámetros de esta función, podemos determinar los límites del área que necesitamos.

Compilar un screencap.cpp básico


Esta es realmente la parte más difícil, que puede llevar varios días o una semana entera. Desafortunadamente, no pude encontrar ninguna solución rápida para construir una nueva versión de screencap en la red, así que tuve que atormentarme específicamente con el sonido metálico y sus parámetros.

Si inmediatamente intentas compilar este código, el compilador jurará constantemente que no hay ningún archivo, y a veces puede informar que el archivo está allí, pero no se necesita ningún constructor.

Por lo tanto, inicialmente agregué todos los archivos que no estaban en la biblioteca NDK. Los errores dan una idea de dónde se debe ubicar este o aquel archivo. Para hacer esto, debe agregar los archivos que faltan, y para averiguar dónde se encuentra sysroot (el directorio donde busca clang), puede usar la siguiente "función":

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

El error mostrará la ruta a este directorio. Si su sonido metálico se encuentra en otro lugar, cambie la ruta hacia él.

Registro
 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) (basado en 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. 


Nos dirigimos a Google y buscamos todos los archivos necesarios. En mi caso, tuve que agregar los siguientes directorios y archivos:

Directorios y archivos
 //  ~/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 


Y parece que aquí él es un éxito, todo lo que hay que agregar. Compilando

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

y obtenemos un resultado terrible:

No te veas nervioso
 /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) 


Para mí, fue un verdadero infierno, porque muchos archivos tenían errores, que en teoría no deberían serlo, porque el contenido de estos archivos no cambió. En esta etapa, me senté durante mucho tiempo y comencé a buscar activamente errores en Google, pero no encontré la respuesta que necesitaba. No recuerdo cómo decidí aprender el tutorial de clang, ¡pero esta solución me salvó!

Al final resultó que, clang tiene un parámetro (o más bien ld ) - símbolos no resueltos, que es responsable de trabajar con caracteres no resueltos.Aunque por el mismo error no puedes decir que este es el caso. Agregue el parámetro y compile nuevamente:

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

¡Finalmente, la compilación fue exitosa! De hecho, ya pensaba que la mayoría de los problemas habían desaparecido, pero no estaba allí. Comenzaron a aparecer errores, como los siguientes:

 CANNOT LINK EXECUTABLE: cannot locate symbol "_ZN7android12ProcessState4selfEv" 

Al final resultó que, el compilador tenía suficiente de nuestros archivos agregados, pero en el dispositivo Android todos estos archivos se almacenan en bibliotecas .so. Más tarde analizado más o menos bien en este asunto, encontré una forma relativamente simple de encontrar las bibliotecas necesarias. Para hacerlo, abra el archivo de captura de pantalla binario, que se encuentra en el dispositivo Android (/ system / bin / screencap) en un editor de texto y vea todos los nombres de las bibliotecas .so que se utilizan en este archivo. En mi caso, esta parte es:

Parte con los nombres de las bibliotecas utilizadas
 ...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... 


Puede comparar esta parte con su archivo compilado y encontrar qué bibliotecas falta. En este caso, resultaron ser: libgui.so, libui.so, libcutils.so, libutils.so, libbinder.so, libskia.so. Estamos buscando su ubicación (de hecho, están en el mismo lugar):

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

Copiamos todas las bibliotecas a sdcard / libs (ejemplo para libskia.so):

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

Usando adb pull copiamos archivos de mob. dispositivo a la computadora:

 adb pull /sdcard/libs ~/arm 

Los colocamos en el directorio que necesita y compilamos, pero con el nuevo parámetro * .so, que indica que debe usar todas las bibliotecas .so de la misma manera al ensamblar, o más bien especificar enlaces a ellas en el archivo.

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

Ahora la compilación será exitosa y el lanzamiento del archivo binario en la mafia. El dispositivo estará libre de errores.

Conclusión y resultado


Como habrás notado, agregar tu funcionalidad "al código de otra persona" no es una tarea muy simple.

El código del archivo de captura de pantalla modificado se muestra a continuación. Su montaje se realiza de la misma manera que el original. Los cambios agregados, creo, serán comprensibles para la mayoría de los lectores, por lo que decidí no comentarlo.

Screencap.cpp mejorado
 #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; } 


Un ejemplo de obtención de color de píxel:

 ./screencap -c 100 100 

Un ejemplo de obtención de una imagen en un área determinada:

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

Este proyecto se carga en GitHub , por lo que cualquier persona interesada es bienvenida.

PD: Si conoce la mejor manera de encontrar el código fuente necesario para el archivo ejecutable o las bibliotecas necesarias para la compilación, agregue un comentario y agregaré este consejo al artículo.

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


All Articles