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

在前面的【Android】从SurfaceFlinger中获取各layer图片(1)里面,提到通过获取surfaceFlinger中的GraphicBuffer结构中

的共享内存的fd来达到访问图像数据的内存地址,进而实现访问对应的图像数据,

理论上是可行的,但是实际处理会有问题,最终需要通过传送GraphicBuffer对象来达到这个目的。

这里记录下探索过程

 

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

./libs/gui/BufferQueueCore.cpp

 

在里面传送fd

 

Unknown:/data/local/tmp # ./screenget

add myService

onTransact called, case 4

Segmentation fault

 

使用char* base = new char[w*h*4];代替mmap操作,

可以保存图像,没有段错误,说明保存图像的方法没有问题

 

 

                        void* mappedAddress= mmap(0, w*h*4, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);

                        if (mappedAddress == MAP_FAILED) {

                       printf("Could not mmap %s \n\n", strerror(errno));

                       //return -errno;

                           }

 

 

Unknown:/data/local/tmp # ./screenget

add myService

onTransact called, case 4

fd=6, w=720, h=1280, format=1

1

Could not mmap Permission denied

 

====== base not null

 

【Android】从SurfaceFlinger中获取各layer图片(2)_第1张图片

 

 

可能是由于gralloc模块的内存不允许直接访问

 

改成read方法也报错,

if (read(fd, mappedAddress, w*h*4) == -1)

       {printf("Could not read, %s \n\n", strerror(errno));}

 

Could not read, Invalid argument

 

 

59struct private_handle_t : public native_handle {

60#else

61struct private_handle_t {

62    struct native_handle nativeHandle;

63#endif

64

65    enum {

66        PRIV_FLAGS_FRAMEBUFFER = 0x00000001

67    };

68

69    // file-descriptors

70    int     fd;

71    // ints

72    int     magic;

73    int     flags;

74    int     size;

75    int     offset;

76

77    // FIXME: the attributes below should be out-of-line

78    uint64_t base __attribute__((aligned(8)));

 

尝试去获取base指针,报错

         //error: cast from 'const int *' to 'uint64_t *' (aka 'unsigned long *')

         // increases required alignment from 4 to 8 [-Werror,-Wcast-align]

 

         //const int* pint = &(buffer->handle->data[5]);

         //uint64_t* ptr = (uint64_t*)pint;

         //void* vaddr = (void*)(*ptr);

  

 

 

 

Memcpy报错

 

01-01 13:24:54.387 15611 15611 F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x100000500

01-01 13:24:54.388 15611 15611 F DEBUG   :     x0   000000748617f000  x1   0000000100000500  x2   0000000000384000  x3   000000748617f000

01-01 13:24:54.388 15611 15611 F DEBUG   :     x4   0000000100384500  x5   0000007486503000  x6   000000000000000a  x7   000000000000000a

01-01 13:24:54.388 15611 15611 F DEBUG   :     x8   000000748bb7266c  x9   0000000000000000  x10  0000000000000001  x11  0000000000000000

 

01-01 13:24:54.439 15611 15611 F DEBUG   : backtrace:

01-01 13:24:54.440 15611 15611 F DEBUG   :     #00 pc 000000000001c418  /system/lib64/libc.so (memcpy+232)

01-01 13:24:54.441 15611 15611 F DEBUG   :     #01 pc 000000000005ce1c  /system/lib64/libgui.so (android::BufferQueueCore::dumpState(android::String8 const&, android::String8*) const+1112)

01-01 13:24:54.441 15611 15611 F DEBUG   :     #02 pc 000000000005b1d8  /system/lib64/libgui.so (android::BufferQueueConsumer::dumpState(android::String8 const&, android::String8*) const+172)

01-01 13:24:54.443 15611 15611 F DEBUG   :     #03 pc 0000000000065f64  /system/lib64/libgui.so (android::ConsumerBase::dumpLocked(android::String8&, char const*) const+120)

01-01 13:24:54.443 15611 15611 F DEBUG   :     #04 pc 0000000000065ed4  /system/lib64/libgui.so (android::ConsumerBase::dumpState(android::String8&, char const*) const+60)

 

 

这个base指针的内容有问题?

 

 

查看log

==== the fd = 101, handle numFds=3, size=0, offset=720

 

为什么fd的数量是3,

看来有必要把fd都打印出来,

         outResult->appendFormat("==== the fd = %d, handle numFds=%d, data[1]=%d,data[2]=%d size=%d, offset=%d\n\n",

         buffer->handle->data[0], buffer->handle->numFds,

         buffer->handle->data[1], buffer->handle->data[2],

         buffer->handle->data[3], buffer->handle->data[4]);

 

 

打印结果

==== the fd = 87, handle numFds=3, data[1]=89,data[2]=90 size=0, offset=320

 

查看surfaceflinger进程的fd

Unknown:/ $ ps -ef|grep sur

system         479     1 9 11:58:19 ?     00:00:28 surfaceflinger

shell         6460  6456 7 12:03:29 pts/13 00:00:00 grep sur

 

adb shell ls -l /proc/479/fd > fd_sf.txt

 

【Android】从SurfaceFlinger中获取各layer图片(2)_第2张图片

 

 

87是anon_inode:gralloc_extra

90是/dev/ashem

难道data[2]才是需要传递的共享内存fd?

 

接下来测试,

writePNG called

Bus error

 

 

传送fd的方式报错,

Unknown:/data/local/tmp # ./screenget

add myService

onTransact called, case 4

onTransact called, case 4

fd=6, w=320, h=700, format=1

1

====== base not null

====== base[2]=

==base[0]=255, base[1]=255, base[2]=255, base[3]=255, base[4]=255

 

i=0

i=1

i=2

Bus error

 

 

 

这个fd的映射空间不能访问

直接在surfaceflinger进程中看看相应的内存是否可以访问

 

导入private_handle_t,可以直接获取到数据

const private_handle_t* pt = (private_handle_t*)buffer->handle;

              uint64_t value=0;

              memcpy(&value, &(buffer->handle->data[5]), sizeof(uint64_t));

                                          void* vaddr = (void*)value;

                                          void* vaddr2 = (void*)pt->base;

              outResult->appendFormat("==== vaddr=%p, vaddr2=%p ", vaddr, vaddr2);

 

vaddr与vaddr2的值一样,说明使用memcpy得到的指针是没有问题的

 

char c;

char* base = (char*)vaddr2;

for (int i = 0; i < h; i++)

 {

      for (int j = 0; j < w*4; j++)

      {

             c = base[i*w*4 + j];

      }

      ALOGD("==== i=%d, \n", i);

 

这段代码执行会出问题,说明这个base指针不能直接使用,可能和gralloc里面的处理有关。

 

5-16

考虑传送GraphicBuffer对象,写入到parcel中

 

                        Parcel data;

                        Parcel reply;

//                     int fd = buffer->handle->data[2];

//                     data.writeFileDescriptor(fd);

                        data.writeInt32(buffer->width);

                        data.writeInt32(buffer->height);

                        data.writeInt32(buffer->format);

     sp gbuffer = buffer;

           

            if (buffer != 0) {

                data.write(*gbuffer);

            }                  

                        

                    int err = service->transact(5, data, &reply, 0);

 

 

 

接收端

 

                       

                        sp buf = new GraphicBuffer();;

                        data.read(*buf);

                       

                        Region newDirtyRegion;

                        const Rect bounds(w, h);

                        newDirtyRegion.set(bounds);

                       

                        int fenceFd = -1;

                        void* vaddr;

                        //GRALLOC_USAGE_SW_READ_OFTEN 0x00000003U

                        //GRALLOC_USAGE_SW_WRITE_OFTEN 0x00000030U

        status_t res = buf->lockAsync(0x00000003U | 0x00000030U,

                newDirtyRegion.bounds(), &vaddr, fenceFd);

               

              printf("==== vaddr=%p\n", vaddr);

             

              char pname[32] = {0};

                        sprintf(pname, "%02d.png", icode++);

                        char* base = (char*)vaddr;                

                        writePNG(pname, base, w, h, format, s);

 

通过dumpsys进行触发调用,可以保存各surface的图像了

 

你可能感兴趣的:(Linux/Unix,C/C++,Android显示系统)