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<IBinder> display = SurfaceComposerClient::getBuiltInDisplay(displayId);
if (display == NULL) {
fprintf(stderr, "Unable to get handle for display %d\n", displayId);
// b/36066697: Avoid running static destructors.
_exit(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());
// 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<h ; y++) {
write(fd, base, w*Bpp);
base = (void *)((char *)base + s*Bpp);
}
}
}
close(fd);
if (mapbase != MAP_FAILED) {
munmap((void *)mapbase, mapsize);
}
// b/36066697: Avoid running static destructors.
_exit(0);
}
从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> surface = new Surface(producer, false);
ANativeWindow* window = surface.get();
sp<const DisplayDevice> 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 概述架构:
图片.png
screencap:合成使用egl(下图黄色流程)
图片.png
screencap 截图失败的原因,可能是下面的原因,内容做了保护
frameworks/native/libs/gui/ISurfaceComposer.cpp
111 virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* 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<int32_t>(reqDataspace));
120 data.writeInt32(static_cast<int32_t>(reqPixelFormat));
121 data.write(sourceCrop);
122 data.writeUint32(reqWidth);
123 data.writeUint32(reqHeight);
124 data.writeInt32(static_cast<int32_t>(useIdentityTransform));
125 data.writeInt32(static_cast<int32_t>(rotation));
126 data.writeInt32(static_cast<int32_t>(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<const DisplayDevice>& 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 < minLayerZ || 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
网友评论