screencap

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 %d\n", 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 概述架构:


图片.png

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


图片.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 < 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

你可能感兴趣的:(screencap)