Buat file biner Android menggunakan sumber dan Android NDK. Kami memompa utilitas screencap

Saya terlibat dalam otomatisasi perangkat Android dan seringkali SDK atau OS Android tidak memiliki fungsi yang diperlukan atau kerjanya lambat / sangat lambat.

Dengan menggunakan kemampuan Native Development Kit (NDK), kita dapat menulis fungsionalitas yang akan dieksekusi lebih cepat daripada fungsionalitas yang sama di Jawa. Karena paus ini, kita dapat menambahkan kode yang ditulis dalam C / C ++ ke aplikasi kita atau membuat file biner kita sendiri untuk perangkat seluler Android.

Pada artikel ini saya akan memberi tahu Anda bagaimana kami dapat mengkonfigurasi kompilasi file biner untuk OS Android, dan juga menunjukkan proses bagaimana kami dapat melengkapi fungsionalitas file biner yang ada di OS ini.

Misalnya, saya "memompa" screencap, yang tidak hanya bisa mendapatkan tangkapan layar seluruh layar atau memberikan "data mentah", tetapi juga mengembalikan warna piksel pada titik tertentu atau mendapatkan gambar hanya pada area yang diinginkan. Jadi ayo pergi!

Instal NDK


Unduh Android NDK dan bongkar arsip atau instal melalui SDK Manager .

Jika belum, maka Anda dapat menambahkan ekstra. alat:

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

Dan buat "proyek" untuk arsitektur perangkat seluler Anda:

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

Karena HOMTOM HT16 saya memiliki arsitektur armeabi-v7a, saya akan menggunakan perintah:

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

Dan kami menunggu hingga skrip membuat semua file yang diperlukan (sekitar 5 menit).

Pemeriksaan Kinerja


Buat file hello_world.c dengan kode sederhana:

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

Dan coba kompilasi:

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

Menggunakan atribut -o , tentukan nama file, dan menggunakan -pie switch, kami menunjukkan bahwa file biner PIE dan semua dependensinya dimuat ke lokasi acak dalam memori virtual setiap kali aplikasi dieksekusi.

Jika kompilasi berhasil, unggah file ke ponsel:

 adb push ./hello_world /data/local/tmp 

Dan coba biner:

 adb shell /data/local/tmp/hello_world 

Jika Anda melihat output dari frase "hello world" - maka Anda melakukan semuanya dengan benar!

Jika Anda masih memiliki kesalahan, mungkin Anda telah memilih arsitektur yang salah, maka hapus saja direktori ini dan buat kembali dengan yang benar.

Untuk menentukan arsitektur, Anda dapat menjalankan perintah

 adb shell cat /proc/cpuinfo 

Sumber dan perpustakaan


Karena analisis file biner yang dikompilasi sangat memakan waktu, dan Android adalah sistem terbuka, mengapa tidak mengambil keuntungan dari kualitas ini!

Kami pergi ke sini dan mencari versi Android yang tepat. Nah, sudah - unduh arsipnya dan cari sumber file biner yang diinginkan. Meskipun, tentu saja, ada opsi - Google dan "permintaan yang tepat."

Dalam kasus saya, file yang saya butuhkan ada di tautan ini .

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


Kami akan menganalisis sebagian kode ini.

DEFAULT_DISPLAY_ID - pengidentifikasi tampilan tempat Anda ingin mendapatkan tangkapan layar. Dalam kasus kami, 0.

flinger2skia dan vinfoToPixelFormat - bertanggung jawab untuk menentukan format gambar yang seharusnya.

notifyMediaScanner - setelah gambar dibuat dalam sistem file, Anda harus mengirim siaran agar file dapat ditampilkan dengan benar. Jika Anda tidak memanggil siaran ini, maka tidak semua aplikasi akan dapat melihat file yang dibuat.
Fungsi utama tidak sulit untuk "dibaca", jadi kami hanya akan menganalisis poin-poin penting yang secara langsung bertanggung jawab untuk memperoleh data gambar.

/ dev / graphics / fb0 adalah apa yang disebut framebuffer. Framebuffer adalah area memori video untuk penyimpanan jangka pendek dari satu atau lebih frame video. Berdasarkan kode utama, jelas bahwa ada versi perangkat Android yang menyimpan gambar layar dalam file ini. Jadi, jika Anda โ€œberuntungโ€, maka mengenali vinfo.xoffset dan vinfo.yoffset (dalam kebanyakan kasus mereka akan menjadi 0) dan menggunakan konsol Anda dapat dengan mudah mendapatkan informasi warna:

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

Dalam kasus saya, semuanya ternyata tidak begitu sederhana dan file ini tidak mengandung informasi gambar.

screenshot.update adalah cara kedua untuk mendapatkan gambar. Fungsi ini memiliki beberapa metode kelebihan beban yang dapat ditemukan di sini .

Pertimbangkan deskripsi fungsi dengan jumlah parameter terbesar:

 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) 

tampilan - tautan ke tampilan yang diperlukan.
sourceCrop - memotong area gambar yang dipilih. Ini dapat berisi koordinat titik kiri atas dan kanan bawah (total 4 parameter xLeft, yTop, xRight, yBottom). Asalnya adalah sudut kiri atas.
reqWidth - lebar gambar yang dikembalikan
reqHeight - tinggi dari gambar yang dikembalikan
minLayerZ dan maxLayerZ - cara kerja parameter ini tidak dapat dipahami. Pencacahan nilai terkadang menghasilkan keran hitam
useIdentityTransform - Jika benar, maka menonaktifkan lapisan overlay di atas aplikasi, mis. Aktivitas yang menggunakan ACTION_MANAGE_OVERLAY_PERMISSION
rotasi - rotasi gambar.

Jadi, untuk mendapatkan warna piksel, kita perlu mengatur xLeft dan yTop, menggesernya dengan 1, karena hitungan mundur akan berubah dari 0, dan atur koordinat yang ditentukan ke xRight, yBottom. Di reqWidth dan reqHeight atur nilainya menjadi 1. Dengan mengubah parameter fungsi ini, kita dapat menentukan batas-batas area yang kita butuhkan.

Kompilasi screencap.cpp dasar


Ini sebenarnya bagian tersulit, yang bisa memakan waktu beberapa hari atau satu minggu penuh. Sayangnya, saya tidak dapat menemukan solusi cepat untuk membangun versi baru screencap di jaringan, jadi saya harus secara khusus menyiksa diri sendiri dengan dentang dan parameternya.

Jika Anda segera mencoba mengkompilasi kode ini, kompiler akan terus bersumpah bahwa tidak ada file, dan kadang-kadang dapat melaporkan bahwa file ada di sana, tetapi tidak ada konstruktor yang diperlukan.

Oleh karena itu, awalnya saya menambahkan semua file yang tidak ada di perpustakaan NDK. Kesalahan memberikan gambaran tentang di mana file ini atau itu harus ditempatkan. Untuk melakukan ini, Anda perlu menambahkan file yang hilang, dan untuk mencari tahu di mana sysroot berada (direktori tempat dentang mencari), Anda dapat menggunakan "fitur" berikut:

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

Kesalahan akan menunjukkan jalur ke direktori ini. Jika dentang Anda berada di tempat lain, ubah jalur ke sana.

Log
 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) (berdasarkan 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. 


Kami beralih ke Google dan mencari semua file yang diperlukan. Dalam kasus saya, saya harus menambahkan direktori dan file berikut:

Direktori dan File
 //  ~/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 


Dan kelihatannya di sini dia sukses, semua itu perlu ditambahkan. Kompilasi

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

dan kami mendapatkan hasil yang mengerikan:

Jangan terlihat gugup
 /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) 


Bagi saya, itu adalah neraka yang nyata, karena banyak file memiliki kesalahan, yang secara teori tidak boleh, karena isi dari file-file ini tidak berubah. Pada tahap ini, saya duduk untuk waktu yang lama dan mulai aktif kesalahan google, tetapi tidak menemukan jawaban yang saya butuhkan. Bagaimana saya memutuskan untuk mempelajari tutorial dentang yang tidak saya ingat, tetapi solusi ini menyelamatkan saya!

Ternyata, dentang memiliki parameter (atau lebih tepatnya ld ) --unresolved-simbol, yang bertanggung jawab untuk bekerja dengan karakter yang tidak terselesaikan (tidak terselesaikan).Meskipun dengan kesalahan Anda tidak dapat mengatakan bahwa ini adalah masalahnya. Tambahkan parameter dan kompilasi lagi:

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

Akhirnya kompilasi berhasil! Sebenarnya, saya sudah berpikir bahwa sebagian besar masalah sudah hilang, tetapi tidak ada. Kesalahan mulai muncul, seperti berikut ini:

 CANNOT LINK EXECUTABLE: cannot locate symbol "_ZN7android12ProcessState4selfEv" 

Ternyata, kompiler sudah cukup dengan file-file kami yang ditambahkan, tetapi pada perangkat Android semua file ini disimpan di perpustakaan .so. Kemudian diurai kurang lebih baik dalam hal ini, saya menemukan cara yang relatif sederhana untuk menemukan perpustakaan yang diperlukan. Untuk melakukan ini, buka file screencap biner, yang terletak di perangkat Android (/ system / bin / screencap) di editor teks dan lihat semua nama perpustakaan .so yang digunakan dalam file ini. Dalam kasus saya, bagian ini adalah:

Bagian dengan nama-nama perpustakaan yang digunakan
 ...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... 


Anda dapat membandingkan bagian ini dengan file yang dikompilasi dan menemukan perpustakaan mana yang Anda lewatkan. Dalam hal ini, mereka berubah menjadi: libgui.so, libui.so, libcutils.so, libutils.so, libbinder.so, libskia.so. Kami mencari lokasi mereka (sebenarnya, mereka berada di tempat yang sama):

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

Kami menyalin semua perpustakaan ke sdcard / libs (contoh untuk libskia.so):

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

Menggunakan adb pull, kami menyalin file dari mob. perangkat ke komputer:

 adb pull /sdcard/libs ~/arm 

Kami menempatkannya di direktori yang Anda butuhkan dan kompilasi, tetapi dengan parameter * .so yang baru, yang menunjukkan bahwa Anda perlu menggunakan semua perpustakaan .so dengan cara yang sama saat merakit, atau lebih tepatnya menentukan tautan ke mereka dalam file.

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

Sekarang kompilasi akan berhasil dan peluncuran file biner di mob. perangkat akan bebas dari kesalahan.

Kesimpulan dan Hasil


Seperti yang mungkin Anda perhatikan, menambahkan fungsionalitas "ke kode orang lain" bukanlah tugas yang sangat sederhana.

Kode file screencap yang dimodifikasi ditunjukkan di bawah ini. Perakitannya berlangsung dengan cara yang sama seperti aslinya. Perubahan yang ditambahkan, saya pikir, akan dimengerti oleh sebagian besar pembaca, jadi saya memutuskan untuk tidak mengomentarinya.

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


Contoh untuk memperoleh warna piksel:

 ./screencap -c 100 100 

Contoh memperoleh gambar di area tertentu:

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

Proyek ini diunggah ke GitHub , jadi siapa pun yang tertarik dipersilakan.

NB Jika Anda tahu cara terbaik untuk menemukan kode sumber yang diperlukan untuk file yang dapat dieksekusi atau perpustakaan yang diperlukan untuk kompilasi, silakan tambahkan komentar dan saya akan menambahkan saran ini ke artikel.

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


All Articles