screencap

作者: xuefeng_apple | 来源:发表于2020-09-25 11:20 被阅读0次

    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

    相关文章

      网友评论

          本文标题:screencap

          本文链接:https://www.haomeiwen.com/subject/gttfuktx.html