热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

screencap

1-如何使用screencapadbshellscreencap-d0-p/sdcard/fb0.pngadbshellscreencap

1-如何使用screencap

adb shell screencap -d 0 -p /sdcard/fb0.png
adb shell screencap -d 1 -p /sdcard/fb1.png

注意: android Q 上,-d 已经变成了id , 这个是固件的值,跟硬件相关
dumpsys SurfaceFlinger –display-id, 这个能获取display id ,就算虚拟屏,也是建立在真实的屏幕上,如果看dp 由没有显示,就截取实际dp 物理屏的显示就可以。

2-screencap 源码分析

frameworks/base/cmds/screencap/screencap.cpp

int main(int argc, char** argv) { 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; android_dataspace d; 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 }; // setThreadPoolMaxThreadCount(0) actually tells the kernel it's // not allowed to spawn any additional threads, but we still spawn // a binder thread from userspace when we call startThreadPool(). // See b/36066697 for rationale ProcessState::self()->setThreadPoolMaxThreadCount(0); ProcessState::self()->startThreadPool(); ScreenshotClient screenshot; sp display = SurfaceComposerClient::getBuiltInDisplay(displayId); if (display == NULL) { fprintf(stderr, "Unable to get handle for display %dn", displayId); // b/36066697: Avoid running static destructors. _exit(1); } Vector configs; SurfaceComposerClient::getDisplayConfigs(display, &configs); int activeCOnfig= SurfaceComposerClient::getActiveConfig(display); if (static_cast(activeConfig) >= configs.size()) { fprintf(stderr, "Active config %d not inside configs (size %zu)n", activeConfig, configs.size()); // b/36066697: Avoid running static destructors. _exit(1); } uint8_t displayOrientation = configs[activeConfig].orientation; uint32_t captureOrientation = ORIENTATION_MAP[displayOrientation]; status_t result = screenshot.update(display, Rect(), 0 /* reqWidth */, 0 /* reqHeight */, INT32_MIN, INT32_MAX, /* all layers */ false, captureOrientation); if (result == NO_ERROR) { base = screenshot.getPixels(); w = screenshot.getWidth(); h = screenshot.getHeight(); s = screenshot.getStride(); f = screenshot.getFormat(); d = screenshot.getDataSpace(); size = screenshot.getSize(); } if (base != NULL) { if (png) { const SkImageInfo info = SkImageInfo::Make(w, h, flinger2skia(f), kPremul_SkAlphaType, dataSpaceToColorSpace(d)); SkPixmap pixmap(info, base, s * bytesPerPixel(f)); struct FDWStream final : public SkWStream { size_t fBytesWritten = 0; int fFd; FDWStream(int f) : fFd(f) {} size_t bytesWritten() const override { return fBytesWritten; } bool write(const void* buffer, size_t size) override { fBytesWritten += size; return size == 0 || ::write(fFd, buffer, size) > 0; } } fdStream(fd); (void)SkEncodeImage(&fdStream, pixmap, SkEncodedImageFormat::kPNG, 100); if (fn != NULL) { notifyMediaScanner(fn); } } else { uint32_t c = dataSpaceToInt(d); write(fd, &w, 4); write(fd, &h, 4); write(fd, &f, 4); write(fd, &c, 4); size_t Bpp = bytesPerPixel(f); for (size_t y=0 ; y

从screencap 流程可以看出,获取图片内容, 进行编码,然后存储png 文件。 其中最重要的就是screenshot.update,看下screenshot.updat 流程

frameworks/native/libs/gui/SurfaceComposerClient.cpp screenshot.update --->ComposerService::getComposerService() //get SurfaceFlinger service ---->SurfaceFlinger::captureScreen [SurfaceFlinger.cpp] ---->captureScreenImplLocked [SurfaceFlinger.cpp] ---->mDrawingState.layersSortedByZ ---->eglCreateImageKHR // create an EGLImage from the buffer so we can later ---->renderScreenImplLocked ---->result = window->queueBuffer(window, buffer, syncFd);

SF:frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
SF:captureScreen :

status_t SurfaceFlinger::captureScreen { sp surface = new Surface(producer, false); ANativeWindow* window = surface.get(); sp device(getDisplayDeviceLocked(display)); result = captureScreenImplLocked(); /// 这里进行captureScreen result = window->queueBuffer(window, buffer, syncFd); //queueBuffer Buffer 绘制完成 }

captureScreenImplLocked —>layer->draw(hw, useIdentityTransform); 进行了绘制工作

3-screencap 总体截图总结

实际SF 就是对buffef ,进行控制,Zorder ,sourcecrop,等等。SF 对buffer 处理可以交给GPU ,也可以交给HWC .

SF 概述架构:

screencap
图片.png

screencap:合成使用egl(下图黄色流程)

screencap
图片.png

screencap 截图失败的原因,可能是下面的原因,内容做了保护

frameworks/native/libs/gui/ISurfaceComposer.cpp 111 virtual status_t captureScreen(const sp& display, sp* outBuffer, 112 bool& outCapturedSecureLayers, const ui::Dataspace reqDataspace, 113 const ui::PixelFormat reqPixelFormat, Rect sourceCrop, 114 uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform, 115 ISurfaceComposer::Rotation rotation, bool captureSecureLayers) { 116 Parcel data, reply; 117 data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); 118 data.writeStrongBinder(display); 119 data.writeInt32(static_cast(reqDataspace)); 120 data.writeInt32(static_cast(reqPixelFormat)); 121 data.write(sourceCrop); 122 data.writeUint32(reqWidth); 123 data.writeUint32(reqHeight); 124 data.writeInt32(static_cast(useIdentityTransform)); 125 data.writeInt32(static_cast(rotation)); 126 data.writeInt32(static_cast(captureSecureLayers)); 127 status_t result = remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply); 128 if (result != NO_ERROR) { 129 ALOGE("captureScreen failed to transact: %d", result); 130 return result; 131 } 132 result = reply.readInt32(); 133 if (result != NO_ERROR) { 134 ALOGE("captureScreen failed to readInt32: %d", result); ----》这里会有打印失败的原因 135 return result; 136 } 137 138 *outBuffer = new GraphicBuffer(); 139 reply.read(**outBuffer); 140 outCapturedSecureLayers = reply.readBool(); 141 142 return result; 143 }

SF:captureScreenImplLocked

status_t SurfaceFlinger::captureScreenImplLocked(const sp& hw, ANativeWindowBuffer* buffer, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform, Transform::orientation_flags rotation, bool isLocalScreenshot, int* outSyncFd) { ATRACE_CALL(); bool secureLayerIsVisible = false; for (const auto& layer : mDrawingState.layersSortedByZ) { const Layer::State& state(layer->getDrawingState()); if (!layer->belongsToDisplay(hw->getLayerStack(), false) || (state.z maxLayerZ)) { continue; } layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer *layer) { secureLayerIsVisible = secureLayerIsVisible || (layer->isVisible() && layer->isSecure()); }); } if (!isLocalScreenshot && secureLayerIsVisible) { ALOGW("FB is protected: PERMISSION_DENIED");----->如果上层的window 做了保护,就会导致screencap 失败 return PERMISSION_DENIED; }

REF:
https://www.jianshu.com/p/03c40afab7a5
https://www.jianshu.com/p/c954bcceb22a


推荐阅读
author-avatar
大笨猫的男人
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有