【Android】从SurfaceFlinger中获取各layer图片(1)

Surfaceflinger进程提供一个入口来实现对各进程的surface画面进行合并处理,也就是说,Surfaceflinger进程中保存有各进程的图像,(即layer),这里尝试获取各layer图像数据,来加深对surface的理解。

 

图像保存方法,参考screencap里的截屏实现,

 

int writePNG(char* fileName, char*base, int w, int h, int f, int s)

{

     int fd = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, 0664);

      if (fd == -1)

      {

       fprintf(stderr, "Error opening file: %s (%s)\n", fileName, strerror(errno));

       return 1;

    }

cout << "writePNG called" << endl;

    

            const SkImageInfo info =

    SkImageInfo::Make(w, h, flinger2skia(f), kPremul_SkAlphaType,

        dataSpaceToColorSpace(HAL_DATASPACE_UNKNOWN));

        cout << "3" << endl;

 

        SkPixmap pixmap(info, base, s * bytesPerPixel(f));

        cout << "4" << endl;

        struct FDWStream final : public SkWStream {

          size_t fBytesWritten = 0;

          int fFd;

          FDWStream(int f) : fFd(f) {cout << "4.1" << endl;}

          size_t bytesWritten() const override {cout << "4.2" << endl; return fBytesWritten; }

          bool write(const void* buffer, size_t size) override {

            fBytesWritten += size;

            cout << "4.3" << endl;

//           cout << "fBytesWritten=" << fBytesWritten << ", size=" << size << endl;

            return size == 0 || ::write(fFd, buffer, size) > 0;

          }

        } fdStream(fd);

        cout << "5" << endl;

        /*

enum class SkEncodedImageFormat {

#ifdef GOOGLE3

    kUnknown,

#endif

    kBMP,

    kGIF,

    kICO,

    kJPEG,

    kPNG,

    kWBMP,

    kWEBP,

    kPKM,

    kKTX,

    kASTC,

    kDNG,

    kHEIF,

};

        */

        //so we can save the data as BMP

        (void)SkEncodeImage(&fdStream, pixmap, SkEncodedImageFormat::kPNG, 100);

                cout << "6" << endl;

        close(fd);

        

        return 0;

}

 

 

 

使用dumpsys SurfaceFlinger可以查看到所有可见的layer的信息,如

Visible layers (count = 6)

+ Layer 0x7787e84000 (com.android.systemui.ImageWallpaper#0)

 

 

尝试把slots中的画面获取显示出来

BufferQueueCore.cpp

 

+ Layer 0x73c42e7000 (testsurface#0)

  Region transparentRegion (this=0x73c42e7380, count=1)

    [  0,   0,   0,   0]

  Region visibleRegion (this=0x73c42e7010, count=1)

    [100, 100, 420, 800]

  Region surfaceDamageRegion (this=0x73c42e7088, count=1)

    [  0,   0,   0,   0]

      layerStack=   0, z=   100000, pos=(100,100), size=( 320, 700), crop=(   0,   0,  -1,  -1), finalCrop=(   0,   0,  -1,  -1), isOpaque=0, invalidate=0, dataspace=Default (0), pixelformat=RGBA_8888 alpha=1.000, flags=0x00000000, tr=[1.00, 0.00][0.00, 1.00]

      client=0x73c55a9180

      format= 1, activeBuffer=[ 320x 700: 320,  1], queued-frames=0, mRefreshPending=0

      mSecure=0, mProtectedByApp=0, mFiltering=0, mNeedsFiltering=0 mDestroyCalled=0

            mTexName=9 mCurrentTexture=0

            mCurrentCrop=[0,0,0,0] mCurrentTransform=0

            mAbandoned=0

            - BufferQueue mMaxAcquiredBufferCount=1 mMaxDequeuedBufferCount=2

              mDequeueBufferCannotBlock=0 mAsyncMode=0

              default-size=[320x700] default-format=1 transform-hint=00 frame-counter=1

            FIFO(0):

             this=0x73c4275800 (mConsumerName=testsurface#0, mConnectedApi=2, mConsumerUsageBits=2304, mId=168, mPid=362, producer=[17635:./testSurface], consumer=[362:/system/bin/surfaceflinger])

            Slots:

             >[00:0x73c8e40960] state=ACQUIRED 0x73c8e40b20 frame=1 [ 320x 700: 320,  1]

              [01:0x0] state=FREE   

              [02:0x0] state=FREE   

                *BufferQueueDump mIsBackupBufInited=0, mAcquiredBufs(size=1)

 

简单一点,dumpsys可以调用到获取layer数据的地方,我们就在 那里进行处理。

 

 

观察dumpsys

 

+ Layer 0x73c43cb000 (testsurface#0)

  Region transparentRegion (this=0x73c43cb380, count=1)

    [  0,   0,   0,   0]

  Region visibleRegion (this=0x73c43cb010, count=1)

    [100, 100, 420, 520]

  Region surfaceDamageRegion (this=0x73c43cb088, count=1)

    [  0,   0,   0,   0]

      layerStack=   0, z=   100000, pos=(100,100), size=( 320, 420), crop=(   0,   0,  -1,  -1), finalCrop=(   0,   0,  -1,  -1), isOpaque=0, invalidate=0, dataspace=Default (0), pixelformat=RGBA_8888 alpha=1.000, flags=0x00000000, tr=[1.00, 0.00][0.00, 1.00]

      client=0x73c55a9480

      format= 1, activeBuffer=[ 320x 420: 320,  1], queued-frames=0, mRefreshPending=0

      mSecure=0, mProtectedByApp=0, mFiltering=0, mNeedsFiltering=0 mDestroyCalled=0

            mTexName=7 mCurrentTexture=1

            mCurrentCrop=[0,0,0,0] mCurrentTransform=0

            mAbandoned=0

            - BufferQueue mMaxAcquiredBufferCount=1 mMaxDequeuedBufferCount=2

              mDequeueBufferCannotBlock=0 mAsyncMode=0

              default-size=[320x420] default-format=1 transform-hint=00 frame-counter=2

            FIFO(0):

             this=0x73c4275800 (mConsumerName=testsurface#0, mConnectedApi=2, mConsumerUsageBits=2304, mId=59, mPid=362, producer=[9070:./testSurface], consumer=[362:/system/bin/surfaceflinger])

            Slots:

             >[01:0x73c8e41300] state=ACQUIRED 0x73c8e414c0 frame=2 [ 320x 420: 320,  1]

              [00:0x73c8e40260] state=FREE     0x73c8e40c00 frame=1 [ 720x1280: 720,  1]

              [02:0x0] state=FREE   

                *BufferQueueDump mIsBackupBufInited=0, mAcquiredBufs(size=1)

                 [00] handle=0x73c8e414c0, fence=0x73c8e14230, time=0x45cff12d2788, xform=0x00

                 FPS ring buffer:

                 (0) 12:25:46.646 fps=0.33  dur=3027.87       max=3027.87       min=3027.87

+ Layer 0x73c4221000 (StatusBar#0)

 

 

调用到Layer.cpp中的dumpsys

 

 

    if (mSurfaceFlingerConsumer != 0) {

        mSurfaceFlingerConsumer->dumpState(result, "            ");

    }

 

 

void GLConsumer::dumpLocked(String8& result, const char* prefix) const

{

    result.appendFormat(

       "%smTexName=%d mCurrentTexture=%d\n"

       "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n",

       prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left,

       mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,

       mCurrentTransform);

 

    ConsumerBase::dumpLocked(result, prefix);

}

 

 

void ConsumerBase::dumpLocked(String8& result, const char* prefix) const {

    result.appendFormat("%smAbandoned=%d\n", prefix, int(mAbandoned));

 

    if (!mAbandoned) {

        String8 consumerState;

        mConsumer->dumpState(String8(prefix), &consumerState);

        result.append(consumerState);

    }

}

 

android$ find . -name *.cpp | xargs grep 'Slots:'

./frameworks/native/libs/gui/BufferQueueCore.cpp:    outResult->appendFormat("%sSlots:\n", prefix.string());

 

调用到

 

void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const {

 

    outResult->appendFormat("%sSlots:\n", prefix.string());

    for (int s : mActiveBuffers) {

        const sp& buffer(mSlots[s].mGraphicBuffer);

        // A dequeued buffer might be null if it's still being allocated

        if (buffer.get()) {

            outResult->appendFormat("%s %s[%02d:%p] ", prefix.string(),

                                    (mSlots[s].mBufferState.isAcquired()) ? ">" : " ", s,

                                    buffer.get());

            outResult->appendFormat("state=%-8s %p frame=%" PRIu64, mSlots[s].mBufferState.string(),

                                    buffer->handle, mSlots[s].mFrameNumber);

 

 

这里,使用到了GraphicBuffer

 

初步思路

 

参考screencap的code,写一个服务,用来接收fd,进行mmap后保存图片

 

LINUX/android/frameworks/native$ find . -name BufferQueueCore.cpp

./libs/gui/BufferQueueCore.cpp

 

在里面传送fd

 

你可能感兴趣的:(Android,Android显示系统)