清楚详解Android 进程间图传递图形buffer原理

目录
  • 进程间图怎么传递图形buffer
  • 大纲
  • 一、Surface.dequeueBuffer 代码流程简述
    • 调用过程
  • 二、进程间图传递图形buffer详解
    • 【1】SurfaceFlinger进程 和 IAllocator 服务之间传递图形显示的Buffer
      • SurfaceFlinger IAllocator 接口的 allocate 函数
      • allocator服务端的hidl接口实现
      • android::hardware::writeEmbeddedToParcel
    • 【2】App进程同 SurfaceFlinger 进程之间传递 GraphicBuffer 对象
      • 服务端 requestBuffer 流程
    • Parcel::write 写对象流程,
      • Parcel::write Parcel.h
      • Parcel::write Parcel.cpp
    • Parcel::writeDupFileDescriptor 写fd流程
    • 【3】linux内核部分,binder驱动对 BINDER_TYPE_FDA 、BINDER_TYPE_FD 类型的处理
      • binder_transaction
      • binder_translate_fd
  • 附、图形缓存的几个重要数据类型
    • 1、App端 Surface 同 SurfaceFlinger 用于传递共享内存 fd 的对象 GraphicBuffer
      • GraphicBuffer
      • ANativeWindowBuffer
      • native_handle_t
      • buffer_handle_t 同 native_handle_t
    • 2、hidl接口 进程间传递 fd 使用的数据类型 (HWbinder 传递 fd 的对象)
      • hidl_handle
  • 总结:

进程间图怎么传递图形buffer

写这篇文章的目的:讲解 进程间图怎么传递图形buffer的

最近研究图形缓存怎么在进程之间传递的,谷歌了所有的博客,发现没人讲的清楚

图形缓存是Android绘制的核心内容,8.0版本后却没有讲清楚明白的。

source.android.com/docs/core/a… 这里handle中有些线索,但没细说。

Android 不同进程间,并不传递图形缓存,而是使用“共享内存”机制操作图形缓存。

但是“共享内存”用到的fd怎么传递的,没人讲清楚

fd 时进程级别的 int 数值,正常情况不同进程的 fd 并不能传递。而 GraphicBuffer 这个对象怎么做到传递 共享内存fd 的?Java层的 Parcel 类有个 writeFileDescriptor 函数,用于传递 fd ,那么native层,hal层又是怎么传递的呢?

本文并不面面俱到,只讲核心内容。需要的一些比较硬的知识储备:

  • 了解binder

    • 用户层:binder数据传输中,数据对象Parcel类,生成序列化对象过程,以及解包过程。
    • 内核层:binder 内核中,对不同数据对象的解析
  • 内存知识:了解共享内存,了解mmap,了解内存分配和映射的本质
    • 对内存了解的不够深的话,一些地方还是比较难去理解的,并不是单纯看代码看的懂的,这或许是大部分博客讲不明白的原因
  • 了解Linux驱动
  • 了解Surface 到 SurfaceFlinger 交互过程

大纲

  • 一、Surface::dequeueBuffer 代码流程简述
  • 二、进程间图传递图形buffer详解
    • 【1】SurfaceFlinger进程 和 IAllocator 服务之间传递图形显示的Buffer
    • 【2】App进程同 SurfaceFlinger 进程之间传递 GraphicBuffer 对象服务端 requestBuffer 流程
    • 【3】linux内核部分,binder驱动对 BINDER_TYPE_FDA 、BINDER_TYPE_FD 类型的处理
  • 总结:

一、Surface.dequeueBuffer 代码流程简述

图形内存的分配核心在于 Surface.dequeueBuffer流程。

  • Surface.dequeueBuffer会调用 BufferQueueProducer.dequeueBuffer 去 SurfaceFlinger 端获取BufferSlot数组中可用Slot的下标值

    • 这个 BufferSlot 如果没有 GraphicBuffer,就会去new一个,并在构造函数中申请图形缓存,并把图形缓存映射到当前进程
    • 同时把 BufferQueueProducer::dequeueBuffer 返回值的标记位设置为 BUFFER_NEEDS_REALLOCATION
  • BufferQueueProducer.dequeueBuffer 的返回值如果带有 BUFFER_NEEDS_REALLOCATION标记,会调用 BufferQueueProducer.requestBuffer 获取 GraphicBuffer,同时把图形缓存映射到当前进程

调用过程

  • Surface.dequeueBuffer【App·进程端】

    • BpGraphicBufferProducer.dequeueBuffer【接口层】

      • BufferQueueProducer.dequeueBuffer 【SurfaceFlinger 进程端】

        • dequeueBuffer 函数参数outSlot指针带回一个BufferSlot数组的下标 ,返回值返回标记位,但并未返回 GraphicBuffer
        • dequeueBuffer 函数中,在获取的 BufferSlot 没有GraphicBuffer时,会new一个GraphicBuffer,同时返回值的标记为 BUFFER_NEEDS_REALLOCATION
        • new GraphicBuffer( width, height, format, BQ_LAYER_COUNT, usage, {mConsumerName.string(), mConsumerName.size()});
          • GraphicBuffer 构造函数中会调用initWithSize,内部调用分配图形缓存的代码
          • initWithSize(inWidth, inHeight, inFormat, inLayerCount, inUsage, std::move(requestorName));
            • GraphicBufferAllocator.allocate

              • allocateHelper(width, height, format, layerCount, usage, handle, stride, requestorName, true)

                • Gralloc4Allocator.allocate

                  • hwbinder 服务调用:
                  • IAllocator::getService()->allocate(descriptor, bufferCount,[&](const auto& tmpError, const auto& tmpStride,const auto& tmpBuffers){...}
                    • 之后的代码需要看厂家的具体实现,最后无非是调用到内核驱动层分配内存,比如调用ion驱动层分配ion内存
                    • SurfaceFlinger 和 IAllocator 服务怎么传递 共享内存的,转“进程间图传递图形buffer详解【1】”章节
                    • 回调函数中调用 IMapper.importBuffer(tmpBuffers[i], &outBufferHandles[i]); // 内部使用 mmap 把内存映射到当前进程
    • 在 dequeueBuffer 返回值的标记为 BUFFER_NEEDS_REALLOCATION 时,
      • App端需要调用 requestBuffer,获取 GraphicBuffer 对象,
      • 同时,把 SurfaceFlinger 分配的图形缓存,映射到App进程
    • BpGraphicBufferProducer->requestBuffer(buf, &gbuf);【接口层】
      • BufferQueueProducer.requestBuffer-----请求返回 GraphicBuffer 对象
      • SurfaceFlinger 进程端 requestBuffer 代码非常简单,仅仅是把 dequeueBuffer 过程中分配的对象赋值给参数 gbuf ,传递给 App
      • 那么,图形缓存的 fd 是怎么传到App端的,App又是怎么映射的图形缓存呢?
      • 核心在 BpGraphicBufferProducer.requestBuffer 函数中 GraphicBuffer 对象的构建过程:
        • status_t result =remote()->transact(REQUEST_BUFFER, data, &reply);

          • 接下来GraphicBuffer 传输过程,见 进程间图传递图形buffer详解【2】
        • *buf = new GraphicBuffer();
        • result = reply.read(**buf);
          • read 过程会调用 GraphicBuffer.unflatten

            • GraphicBuffer.unflatten 函数内部调用了 GraphicBufferMapper.importBuffer

              • 内部也是调用IMapper.importBuffer,最终使用 mmap 把内存映射到当前进程
              • 调用 mmap 过程,可以参考 hardware/google/gchips/GrallocHAL/src/hidl_common/Mapper.cpp 代码
              • cs.android.com/android/pla…

二、进程间图传递图形buffer详解

【1】SurfaceFlinger进程 和 IAllocator 服务之间传递图形显示的Buffer

IAllocator 服务全称为 android.hardware.graphics.allocator@4.0::IAllocator/default

高通平台上的进程名为:vendor.qti.hardware.display.allocator-service

SurfaceFlinger IAllocator 接口的 allocate 函数

// frameworks/native/libs/ui/Gralloc4.cpp
status_t Gralloc4Allocator::allocate(std::string requestorName, uint32_t width, uint32_t height,
                                     android::PixelFormat format, uint32_t layerCount,
                                     uint64_t usage, uint32_t bufferCount, uint32_t* outStride,
                                     buffer_handle_t* outBufferHandles, bool importBuffers) const {
//...
	//===================关键代码============
    auto ret = mAllocator->allocate(descriptor, bufferCount,
                                    [&](const auto& tmpError, const auto& tmpStride,
                                        const auto& tmpBuffers) {// const auto& tmpBuffers 是个 hidl_handle 类型
                                        error = static_cast<status_t>(tmpError);
                                        if (tmpError != Error::NONE) {
                                            return;
                                        }
                                        if (importBuffers) {
                                            for (uint32_t i = 0; i < bufferCount; i++) {
                                                error = mMapper.importBuffer(tmpBuffers[i],
                                                                             &outBufferHandles[i]);
                                                if (error != NO_ERROR) {
                                                    for (uint32_t j = 0; j < i; j++) {
                                                        mMapper.freeBuffer(outBufferHandles[j]);
                                                        outBufferHandles[j] = nullptr;
                                                    }
                                                    return;
                                                }
                                            }
                                        } else {
											//....
                                        }
                                        *outStride = tmpStride;
                                    });
//...
    return (ret.isOk()) ? error : static_cast<status_t>(kTransactionError);
}

allocator服务端的hidl接口实现

不看具体的allocate函数实现,重点看数据传输过程

//out/soong/.intermediates/hardware/interfaces/graphics/allocator/4.0/android.hardware.graphics.allocator@4.0_genc++/gen/android/hardware/graphics/allocator/4.0/AllocatorAll.cpp
// 这部分代码是 hidl 接口编译完成后,out目录自动生成的代码,源码目录下没有
// Methods from ::android::hardware::graphics::allocator::V4_0::IAllocator follow.
::android::status_t BnHwAllocator::_hidl_allocate(
        ::android::hidl::base::V1_0::BnHwBase* _hidl_this,
        const ::android::hardware::Parcel &_hidl_data,
        ::android::hardware::Parcel *_hidl_reply,
        TransactCallback _hidl_cb) {
 //...
//========================调用服务端真正的实现=====================
    ::android::hardware::Return<void> _hidl_ret = static_cast<IAllocator*>(_hidl_this->getImpl().get())->allocate(*descriptor, count, [&](const auto &_hidl_out_error, const auto &_hidl_out_stride, const auto &_hidl_out_buffers) {
        if (_hidl_callbackCalled) {
            LOG_ALWAYS_FATAL("allocate: _hidl_cb called a second time, but must be called once.");
        }
        _hidl_callbackCalled = true;
//===============函数调用完成后,开始写返回数据========================
        ::android::hardware::writeToParcel(::android::hardware::Status::ok(), _hidl_reply);
        _hidl_err = _hidl_reply->writeInt32((int32_t)_hidl_out_error);
        if (_hidl_err != ::android::OK) { goto _hidl_error; }
        // 返回数据 tmpStride 的值
        _hidl_err = _hidl_reply->writeUint32(_hidl_out_stride);
        if (_hidl_err != ::android::OK) { goto _hidl_error; }
        size_t _hidl__hidl_out_buffers_parent;
        _hidl_err = _hidl_reply->writeBuffer(&_hidl_out_buffers, sizeof(_hidl_out_buffers), &_hidl__hidl_out_buffers_parent);
        if (_hidl_err != ::android::OK) { goto _hidl_error; }
        size_t _hidl__hidl_out_buffers_child;
        _hidl_err = ::android::hardware::writeEmbeddedToParcel(
                _hidl_out_buffers,
                _hidl_reply,
                _hidl__hidl_out_buffers_parent,
                0 /* parentOffset */, &_hidl__hidl_out_buffers_child);
        if (_hidl_err != ::android::OK) { goto _hidl_error; }
//关键代码====传输上边的回调函数的参数 const auto& tmpBuffers 的每个元素, 数据类型是 hidl_handle 类型
        for (size_t _hidl_index_0 = 0; _hidl_index_0 < _hidl_out_buffers.size(); ++_hidl_index_0) {
            // 关键函数 android::hardware::writeEmbeddedToParcel
            _hidl_err = ::android::hardware::writeEmbeddedToParcel(
                    _hidl_out_buffers[_hidl_index_0],
                    _hidl_reply,
                    _hidl__hidl_out_buffers_child,
                    _hidl_index_0 * sizeof(::android::hardware::hidl_handle));
            if (_hidl_err != ::android::OK) { goto _hidl_error; }
        }
//...
        if (_hidl_err != ::android::OK) { return; }
        _hidl_cb(*_hidl_reply);
    });
    _hidl_ret.assertOk();
    if (!_hidl_callbackCalled) {
        LOG_ALWAYS_FATAL("allocate: _hidl_cb not called, but must be called once.");
    }
    return _hidl_err;
}

android::hardware::writeEmbeddedToParcel

// system/libhidl/transport/HidlBinderSupport.cpp
status_t writeEmbeddedToParcel(const hidl_handle &handle,
        Parcel *parcel, size_t parentHandle, size_t parentOffset) {
    //此处调用了 hwbinder/Parcel.cpp 的writeEmbeddedNativeHandle 函数
    status_t _hidl_err = parcel->writeEmbeddedNativeHandle(
            handle.getNativeHandle(),
            parentHandle,
            parentOffset + hidl_handle::kOffsetOfNativeHandle);
    return _hidl_err;
}
// system/libhwbinder/Parcel.cpp
status_t Parcel::writeEmbeddedNativeHandle(const native_handle_t *handle,
                                           size_t parent_buffer_handle,
                                           size_t parent_offset)
{
    return writeNativeHandleNoDup(handle, true /* embedded */, parent_buffer_handle, parent_offset);
}
status_t Parcel::writeNativeHandleNoDup(const native_handle_t *handle,
                                        bool embedded,
                                        size_t parent_buffer_handle,
                                        size_t parent_offset)
{
//...
    struct binder_fd_array_object fd_array {
        .hdr = { .type = BINDER_TYPE_FDA }, // 关键代码: BINDER_TYPE_FDA 类型,binder内核驱动代码对这个类型有专门的处理
        .num_fds = static_cast<binder_size_t>(handle->numFds),
        .parent = buffer_handle,
        .parent_offset = offsetof(native_handle_t, data),
    };
    return writeObject(fd_array);
}

之后的代码,见 binder驱动对 BINDER_TYPE_FDA 、BINDER_TYPE_FD 类型的处理

【2】App进程同 SurfaceFlinger 进程之间传递 GraphicBuffer 对象

GraphicBuffer 对象

服务端 requestBuffer 流程

// frameworks/native/libs/gui/IGraphicBufferProducer.cpp
status_t BnGraphicBufferProducer::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch(code) {
        case REQUEST_BUFFER: {
            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
            int bufferIdx = data.readInt32();
            sp<GraphicBuffer> buffer;
            int result = requestBuffer(bufferIdx, &buffer);
            reply->writeInt32(buffer != nullptr);
            if (buffer != nullptr) {
                reply->write(*buffer);// GraphicBuffer 对象回写========!!!!!!!!!!!!!!=====
            }
            reply->writeInt32(result);
            return NO_ERROR;
        }
//...
    }
//...
}

Parcel::write 写对象流程,

Parcel::write Parcel.h

// frameworks/native/libs/binder/include/binder/Parcel.h
template<typename T>
status_t Parcel::write(const Flattenable<T>& val) {// 对象需要继承 Flattenable
    const FlattenableHelper<T> helper(val);
    return write(helper);
}

Parcel::write Parcel.cpp

// frameworks/native/libs/binder/Parcel.cpp
status_t Parcel::write(const FlattenableHelperInterface& val)
{
    status_t err;
    // size if needed
    const size_t len = val.getFlattenedSize();
    // val.getFdCount(); 这个值为 GraphicBuffer.mTransportNumFds
    // 从这个接口获取
    // GrallocMapper::getTransportSize(buffer_handle_t bufferHandle, uint32_t* outNumFds, uint32_t* outNumInts)
    const size_t fd_count = val.getFdCount();// 这个值为 GraphicBuffer.mTransportNumFds
//...........
	// 调用对象的 flatten 写到缓存中
    err = val.flatten(buf, len, fds, fd_count);
    // fd_count 不为0,需要写 fd
    for (size_t i=0 ; i<fd_count && err==NO_ERROR ; i++) {
        err = this->writeDupFileDescriptor( fds[i] );
    }
    if (fd_count) {
        delete [] fds;
    }
    return err;
}

Parcel::writeDupFileDescriptor 写fd流程

// frameworks/native/libs/binder/Parcel.cpp
status_t Parcel::writeDupFileDescriptor(int fd)
{
    int dupFd;
    if (status_t err = dupFileDescriptor(fd, &dupFd); err != OK) {
        return err;
    }
    //=============!!!!!!!!!!!!!===========
    status_t err = writeFileDescriptor(dupFd, true /*takeOwnership*/);
    if (err != OK) {
        close(dupFd);
    }
    return err;
}
status_t Parcel::writeFileDescriptor(int fd, bool takeOwnership) {
//........
#ifdef BINDER_WITH_KERNEL_IPC // frameworks/native/libs/binder/Android.bp 中定义了此宏  "-DBINDER_WITH_KERNEL_IPC",
    flat_binder_object obj;
    obj.hdr.type = BINDER_TYPE_FD;// 类型为 fd ,内核会自动创建fd
    obj.flags = 0;
    obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
    obj.handle = fd;
    obj.cookie = takeOwnership ? 1 : 0;
    return writeObject(obj, true);
#else  // BINDER_WITH_KERNEL_IPC
    LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
    (void)fd;
    (void)takeOwnership;
    return INVALID_OPERATION;
#endif // BINDER_WITH_KERNEL_IPC
}

之后的代码,见 binder驱动对 BINDER_TYPE_FDA 、BINDER_TYPE_FD 类型的处理

【3】linux内核部分,binder驱动对 BINDER_TYPE_FDA 、BINDER_TYPE_FD 类型的处理

binder_transaction

// 这里使用的 3.8 的内核版本,逻辑较为清晰
// 更新的内核版本需要看 binder_apply_fd_fixups 函数部分
// https://android.googlesource.com/kernel/msm/+/refs/heads/android-msm-coral-4.14-android10/drivers/android/binder.c
static void binder_transaction(struct binder_proc *proc,
			       struct binder_thread *thread,
			       struct binder_transaction_data *tr, int reply,
			       binder_size_t extra_buffers_size)
{
    //...
		case BINDER_TYPE_FD: {
			struct binder_fd_object *fp = to_binder_fd_object(hdr);
            //数据类型为 BINDER_TYPE_FD 时,调用了 binder_translate_fd
			int target_fd = binder_translate_fd(fp->fd, t, thread, in_reply_to);
			if (target_fd < 0) {
				return_error = BR_FAILED_REPLY;
				return_error_param = target_fd;
				return_error_line = __LINE__;
				goto err_translate_failed;
			}
			fp->pad_binder = 0;
			fp->fd = target_fd;
			binder_alloc_copy_to_buffer(&target_proc->alloc,
						    t->buffer, object_offset,
						    fp, sizeof(*fp));
		} break;
		case BINDER_TYPE_FDA: {
			struct binder_object ptr_object;
			binder_size_t parent_offset;
			struct binder_fd_array_object *fda =
				to_binder_fd_array_object(hdr);
			size_t num_valid = (buffer_offset - off_start_offset) /
						sizeof(binder_size_t);
			struct binder_buffer_object *parent =
				binder_validate_ptr(target_proc, t->buffer,
						    &ptr_object, fda->parent,
						    off_start_offset,
						    &parent_offset,
						    num_valid);
			if (!parent) {
				binder_user_error("%d:%d got transaction with invalid parent offset or type\n",
						  proc->pid, thread->pid);
				return_error = BR_FAILED_REPLY;
				return_error_param = -EINVAL;
				return_error_line = __LINE__;
				goto err_bad_parent;
			}
			if (!binder_validate_fixup(target_proc, t->buffer,
						   off_start_offset,
						   parent_offset,
						   fda->parent_offset,
						   last_fixup_obj_off,
						   last_fixup_min_off)) {
				binder_user_error("%d:%d got transaction with out-of-order buffer fixup\n",
						  proc->pid, thread->pid);
				return_error = BR_FAILED_REPLY;
				return_error_param = -EINVAL;
				return_error_line = __LINE__;
				goto err_bad_parent;
			}
            //数据类型为 BINDER_TYPE_FDA 时,调用了 binder_translate_fd
			ret = binder_translate_fd_array(fda, parent, t, thread, in_reply_to);
			if (ret < 0) {
				return_error = BR_FAILED_REPLY;
				return_error_param = ret;
				return_error_line = __LINE__;
				goto err_translate_failed;
			}
			last_fixup_obj_off = parent_offset;
			last_fixup_min_off =
				fda->parent_offset + sizeof(u32) * fda->num_fds;
		} break;
    //...
}

binder_translate_fd_array 函数中对每一个fd都调用了 binder_translate_fd 函数

binder_translate_fd

static int binder_translate_fd(int fd,
			       struct binder_transaction *t,
			       struct binder_thread *thread,
			       struct binder_transaction *in_reply_to)
{
	struct binder_proc *proc = thread->proc;
	struct binder_proc *target_proc = t->to_proc;
	int target_fd;
	struct file *file;
	int ret;
	bool target_allows_fd;
	if (in_reply_to)
		target_allows_fd = !!(in_reply_to->flags & TF_ACCEPT_FDS);
	else
		target_allows_fd = t->buffer->target_node->accept_fds;
	if (!target_allows_fd) {
		binder_user_error("%d:%d got %s with fd, %d, but target does not allow fds\n",
				  proc->pid, thread->pid,
				  in_reply_to ? "reply" : "transaction",
				  fd);
		ret = -EPERM;
		goto err_fd_not_accepted;
	}
	file = fget(fd);//从fd获取 file 对象
	if (!file) {
		binder_user_error("%d:%d got transaction with invalid fd, %d\n",
				  proc->pid, thread->pid, fd);
		ret = -EBADF;
		goto err_fget;
	}
    //se权限处理
	ret = security_binder_transfer_file(proc->tsk, target_proc->tsk, file);
	if (ret < 0) {
		ret = -EPERM;
		goto err_security;
	}
    //在目标进程中找到一个可用的fd
	target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);
	if (target_fd < 0) {
		ret = -ENOMEM;
		goto err_get_unused_fd;
	}
    // 调用task_fd_install将 file对象 关联到目标进程中的fd
	task_fd_install(target_proc, target_fd, file);
	trace_binder_transaction_fd(t, fd, target_fd);
	binder_debug(BINDER_DEBUG_TRANSACTION, "        fd %d -> %d\n",
		     fd, target_fd);
	return target_fd;
err_get_unused_fd:
err_security:
	fput(file);
err_fget:
err_fd_not_accepted:
	return ret;
}

附、图形缓存的几个重要数据类型

1、App端 Surface 同 SurfaceFlinger 用于传递共享内存 fd 的对象 GraphicBuffer

GraphicBuffer

// frameworks/native/libs/ui/include/ui/GraphicBuffer.h
class GraphicBuffer
    : public ANativeObjectBase<ANativeWindowBuffer, GraphicBuffer, RefBase>,
      public Flattenable<GraphicBuffer>
      { //...
    	status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const;
    	status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count);
        //...
      }
// frameworks/native/libs/ui/include/ui/ANativeObjectBase.h
/*
 * This helper class turns a ANativeXXX object type into a C++
 * reference-counted object; with proper type conversions.
 */
template <typename NATIVE_TYPE, typename TYPE, typename REF,
        typename NATIVE_BASE = android_native_base_t>
class ANativeObjectBase : public NATIVE_TYPE, public REF
{
    //...
}
//转换后:
class ANativeObjectBase : public ANativeWindowBuffer, public RefBase
{
    //...
}
  • GraphicBuffer 继承 ANativeWindowBuffer Flattenable
  • Flattenable 两个关键函数 flatten unflatten,用于binder序列化时使用。

ANativeWindowBuffer

// /frameworks/native/libs/nativebase/include/nativebase/nativebase.h
// 图形Buffer的Size = stride * height * 每像素字节数
typedef struct ANativeWindowBuffer
{
    ...
    int width;      // 图形Buffer的宽度
    int height;     // 图形Buffer的高度
    int stride;     // 图形Buffer的步长,为了处理对齐问题,与width可能不同
    int format;     // 图形Buffer的像素格式
    const native_handle_t* handle; // 指向一块图形Buffer
    uint64_t usage; // 图形Buffer的使用规则(gralloc会分配不同属性的图形Buffer)
    ...
} ANativeWindowBuffer_t;

native_handle_t

// system/core/libcutils/include/cutils/native_handle.h
typedef struct native_handle
{
    int version;        /* sizeof(native_handle_t) */
    // //data[0]中的文件描述符个数
    int numFds;         /* number of file-descriptors at &data[0] */
    // //&data[numFds]中int的个数
    int numInts;        /* number of ints at &data[numFds] */
    int data[0];        /* numFds + numInts ints */
} native_handle_t;

buffer_handle_t 同 native_handle_t

// system/core/libcutils/include/cutils/native_handle.h
typedef const native_handle_t* buffer_handle_t;

2、hidl接口 进程间传递 fd 使用的数据类型 (HWbinder 传递 fd 的对象)

  • hidl_handle 用于 SurfaceFlinger 同 IAllocator HIDL接口的服务之间传递 共享内存fd

    • 高通平台上,这个 HIDL 服务端对应的进程是 vendor.qti.hardware.display.allocator-service

hidl_handle

struct hidl_handle {
    hidl_handle();
    ~hidl_handle();
    hidl_handle(const native_handle_t *handle);
    // copy constructor.
    hidl_handle(const hidl_handle &other);
    // move constructor.
    hidl_handle(hidl_handle &&other) noexcept;
    // assignment operators
    hidl_handle &operator=(const hidl_handle &other);
    hidl_handle &operator=(const native_handle_t *native_handle);
    hidl_handle &operator=(hidl_handle &&other) noexcept;
    void setTo(native_handle_t* handle, bool shouldOwn = false);
    const native_handle_t* operator->() const;
    // implicit conversion to const native_handle_t*
    operator const native_handle_t *() const;
    // explicit conversion
    const native_handle_t *getNativeHandle() const;
    // offsetof(hidl_handle, mHandle) exposed since mHandle is private.
    static const size_t kOffsetOfNativeHandle;
private:
    void freeHandle();
	// 核心数据 native_handle_t mHandle;
    details::hidl_pointer<const native_handle_t> mHandle;
    bool mOwnsHandle;
    uint8_t mPad[7];
};

总结:

  • SurfaceFlinger进程 和 IAllocator服务进程之间通过 hidl_handle 类型的数据传递 图形buffer共享内存的fd

    • 数据传输中对 hidl_handle 类型数据特化处理,并把binder数据类型设置为 BINDER_TYPE_FDA
    • binder内核对 BINDER_TYPE_FDA 类型数据特化处理
    • 同时在 IAllocator.allocate 的回调函数中调用 IMapper.importBuffer 把内存映射到当前进程
  • App进程 同 SurfaceFlinger进程之间使用 GraphicBuffer 对象传递 图形buffer共享内存的fd
    • 数据传输中对 GraphicBuffer 中的 native_handle_t 数据特化处理,并把binder数据类型设置为 BINDER_TYPE_FD
    • binder内核对 BINDER_TYPE_FD 类型数据特化处理
    • 同时在从binder读取数据创建GraphicBuffer对象时,调用 GraphicBuffer.unflatten,内部调用 IMapper.importBuffer 把内存映射到当前进程

后记

Android12 之后使用 BLASTBufferQueue ,虽然有些变化,但是理解了 GraphicBuffer 和 hidl_handle 传递 fd 的过程,这些都游刃有余

Android 的 aidl接口层、hidl接口层、binder bp 接口层 都隐藏了很多关键代码,导致看代码时,感觉总是云里雾里

  • 像hidl接口,生成的大量代码,在out/soong目录下,仅仅看源码树目录下的代码根本找不到好吧。

以上就是清楚详解Android 进程间图传递图形buffer原理的详细内容,更多关于Android 进程间图传递图形buffer的资料请关注我们其它相关文章!

(0)

相关推荐

  • Android 10 启动Init进程解析

    目录 按下电源键时,android做了啥? init进程解析 FirstStageMain SetupSelinux SecondStageMain init.rc 解析 按下电源键时,android做了啥? 当我们按下电源键时,手机开始上电,并从地址0x00000000处开始执行,而这个地址通常是Bootloader程序的首地址. bootloader是一段裸机程序,是直接与硬件打交道的,其最终目的是“初始化并检测硬件设备,准备好软件环境,最后调用操作系统内核”.除此之外,bootloader

  • Android10 App 启动分析进程创建源码解析

    目录 正文 RootActivityContainer ActivityStartController 调用startActivityUnchecked方法 ActivityStackSupervisor 启动进程 RuntimeInit.applicationInit这个方法 正文 从前文# Android 10 启动分析之SystemServer篇 (四)中可以得知,系统在完成所有的初始化工作后,会通过 mAtmInternal.startHomeOnAllDisplays(currentU

  • Android 解决WebView多进程崩溃的方法

    问题 在android 9.0系统上如果多个进程使用WebView需要使用官方提供的api在子进程中给webview的数据文件夹设置后缀: WebView.setDataDirectorySuffix(suffix); 否则将会报出以下错误: Using WebView from more than one process at once with the same data directory is not supported. https://crbug.com/558377 1 com.a

  • Android进程间大数据通信LocalSocket详解

    目录 前言 服务端初始化 客户端初始化 数据传输 发送数据 接收数据 传输复杂数据 写数据 读数据 传输超大数据 写入 读取 前言 说起Android进行间通信,大家第一时间会想到AIDL,但是由于Binder机制的限制,AIDL无法传输超大数据. 那么我们如何在进程间传输大数据呢? Android中给我们提供了另外一个机制:LocalSocket 它会在本地创建一个socket通道来进行数据传输. 那么它怎么使用? 首先我们需要两个应用:客户端和服务端 服务端初始化 override fun

  • 详解Android 进程

    多进程 如果需要的时候,app可以创建多进程. 在进程里面 各类组件元素的清单文件条目 . . 和 - 均支持 android:process 属性,此属性可以指定该组件应在哪个进程运行. 默认进程就是主进程.其他进程一般来说都是子进程. 2个activity在不同的进程里面,可以刷新UI吗? <activity android:name=".androidsample.ActivityProgressB" android:process=":progressb&quo

  • 详解Android进程保活的方法

    关于 Android 平台的进程保活这一块,想必是所有 Android 开发者瞩目的内容之一.你到网上搜 Android 进程保活,可以搜出各种各样神乎其技的做法,绝大多数都是极其不靠谱.前段时间,Github还出现了一个很火的"黑科技"进程保活库,声称可以做到进程永生不死. 怀着学习和膜拜的心情进去Github围观,结果发现很多人提了 Issue 说各种各样的机子无法成功保活. 看到这里,我瞬间就放心了.坦白的讲,我是真心不希望有这种黑科技存在的,它只会滋生更多的流氓应用,拖垮我大

  • 详解Android进程和线程

    写在前面的话 一个Android应用就是一个Linux进程,每个应用在各自的进程中运行,互不干扰,比较安全. 一个应用对应一个主线程,就是通常所说的UI线程,android遵守的就是单线程模型,所以说Ui操作不是线程安全的并且这些操作必须在UI线程中执行. 本文是对官方文档的翻译,原文链接:https://developer.android.com/guide/components/processes-and-threads.html 概述 当某个应用组件启动且该应用没有运行其他任何组件时,An

  • 详解Android Activity之间切换传递数据的方法

    前面照着android系统的裁剪图片的功能自己写了一个相似的工具.功能是大体上实现了,但留下了一个调用的问题:如何从我的程序调用这个裁剪工具,并且获得裁剪后的图片呢? 其实这个也很简单了,就是intent的基础用法. 先上个图(界面依旧没优化,难看就难看吧): 起始activity,打开图片选择窗口,随便选择一张图片 下面是跳转到裁剪界面 按下crop按钮,退出activity,回到原来界面,并显示裁剪后的图 流程就是这样,也算模拟了系统裁剪功能的整体过程.下面就是实现功能的关键代码和说明了.

  • 详解Android系统中的root权限获得原理

    前言 一直很好奇Android Root的原理,恰好最近碰到了一个跟Android默认带Root权限的问题,这里顺便记录一下Android系统root的原理. 原理 Android是基于Llinux内核的开源操作系统,与Ubuntu系统类似,所以在Android里获取root权限其实和在Linux系统下获取root权限是一回事.在Linux系统下获取root权限的方法是在命令行执行sudo或者su,接下来输入提权密码就可以获取root权限了.Android系统其实也是这样,例如应用层程序开发,在

  • Android 图文详解Binder进程通信底层原理

    之前了解到进程与多进程,涉及多进程不可避免的遇到了进程间通信,说到进程间通信,Binder 成了一道绕不过的坎.接下来咱们逐一了解.

  • 详解Android跨进程通信之AIDL

    需求描述 进程A调起第三方进程B进行第三方登录 – 实现双向通信 代码(进程A) 1.目录结构 2.LoginActivity.java public class LoginActivity extends AppCompatActivity { private ILoginInterface iLogin; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceSta

  • 详解Android aidl的使用方法

    AIDL是Android中IPC(Inter-Process Communication)方式中的一种,AIDL是Android Interface definition language的缩写(对于小白来说,AIDL的作用是让你可以在自己的APP里绑定一个其他APP的service,这样你的APP可以和其他APP交互.) AIDL只是Android中众多进程间通讯方式中的一种方式, AIDL和Messenger的区别: Messenger不适用大量并发的请求:Messenger以串行的方式来处

  • 详解Android Handler的使用

    目录 Handler 概要 构造器 sendMessageAtTime dispatchMessage ThreadLocal Looper MessageQueue IdleHandler AsyncMessage和SyncBarrier 阻塞和唤醒机制 Handler内存泄漏分析 Handler 概要 Handler用于线程间的消息传递,它可以将一个线程中的任务切换到另一个线程执行.切换的目标线程与Handler内部持有的Looper所在线程一致.若初始化Handler时未手动设置Loope

  • 详解Android中Service AIDL的使用

    目录 前言 Service基本用法--本地服务 远程服务 -- AIDL 服务端 客户端 前言 有些朋友可能是从事开发工作的时间不是特别的长,所以觉得Service相对与另外两个组件activity.broadcast receiver来说,使用可能并不是特别的多,所以对Service来说,理解不是特别的深入,只是有一个大概的概念,今天就和一块来走一下Service,希望能够帮助到大家对Service有更深入的理解. Service基本用法--本地服务 我们知道服务分为本地服务和远程服务,而本地

随机推荐