清楚詳解Android?進(jìn)程間圖傳遞圖形buffer原理
進(jìn)程間圖怎么傳遞圖形buffer
寫這篇文章的目的:講解 進(jìn)程間圖怎么傳遞圖形buffer的
最近研究圖形緩存怎么在進(jìn)程之間傳遞的,谷歌了所有的博客,發(fā)現(xiàn)沒人講的清楚
圖形緩存是Android繪制的核心內(nèi)容,8.0版本后卻沒有講清楚明白的。
source.android.com/docs/core/a… 這里handle中有些線索,但沒細(xì)說。
Android 不同進(jìn)程間,并不傳遞圖形緩存,而是使用“共享內(nèi)存”機(jī)制操作圖形緩存。
但是“共享內(nèi)存”用到的fd怎么傳遞的,沒人講清楚
fd 時(shí)進(jìn)程級(jí)別的 int 數(shù)值,正常情況不同進(jìn)程的 fd 并不能傳遞。而 GraphicBuffer 這個(gè)對(duì)象怎么做到傳遞 共享內(nèi)存fd 的?Java層的 Parcel 類有個(gè) writeFileDescriptor 函數(shù),用于傳遞 fd ,那么native層,hal層又是怎么傳遞的呢?
本文并不面面俱到,只講核心內(nèi)容。需要的一些比較硬的知識(shí)儲(chǔ)備:
- 了解binder
- 用戶層:binder數(shù)據(jù)傳輸中,數(shù)據(jù)對(duì)象Parcel類,生成序列化對(duì)象過程,以及解包過程。
- 內(nèi)核層:binder 內(nèi)核中,對(duì)不同數(shù)據(jù)對(duì)象的解析
- 內(nèi)存知識(shí):了解共享內(nèi)存,了解mmap,了解內(nèi)存分配和映射的本質(zhì)
- 對(duì)內(nèi)存了解的不夠深的話,一些地方還是比較難去理解的,并不是單純看代碼看的懂的,這或許是大部分博客講不明白的原因
- 了解Linux驅(qū)動(dòng)
- 了解Surface 到 SurfaceFlinger 交互過程
大綱
- 一、Surface::dequeueBuffer 代碼流程簡(jiǎn)述
- 二、進(jìn)程間圖傳遞圖形buffer詳解
- 【1】SurfaceFlinger進(jìn)程 和 IAllocator 服務(wù)之間傳遞圖形顯示的Buffer
- 【2】App進(jìn)程同 SurfaceFlinger 進(jìn)程之間傳遞 GraphicBuffer 對(duì)象服務(wù)端 requestBuffer 流程
- 【3】linux內(nèi)核部分,binder驅(qū)動(dòng)對(duì) BINDER_TYPE_FDA 、BINDER_TYPE_FD 類型的處理
- 總結(jié):
一、Surface.dequeueBuffer 代碼流程簡(jiǎn)述
圖形內(nèi)存的分配核心在于 Surface.dequeueBuffer流程。
- Surface.dequeueBuffer會(huì)調(diào)用 BufferQueueProducer.dequeueBuffer 去 SurfaceFlinger 端獲取BufferSlot數(shù)組中可用Slot的下標(biāo)值
- 這個(gè) BufferSlot 如果沒有 GraphicBuffer,就會(huì)去new一個(gè),并在構(gòu)造函數(shù)中申請(qǐng)圖形緩存,并把圖形緩存映射到當(dāng)前進(jìn)程
- 同時(shí)把 BufferQueueProducer::dequeueBuffer 返回值的標(biāo)記位設(shè)置為
BUFFER_NEEDS_REALLOCATION
- BufferQueueProducer.dequeueBuffer 的返回值如果帶有
BUFFER_NEEDS_REALLOCATION標(biāo)記,會(huì)調(diào)用 BufferQueueProducer.requestBuffer 獲取 GraphicBuffer,同時(shí)把圖形緩存映射到當(dāng)前進(jìn)程
調(diào)用過程
- Surface.dequeueBuffer【App·進(jìn)程端】
- BpGraphicBufferProducer.dequeueBuffer【接口層】
- BufferQueueProducer.dequeueBuffer 【SurfaceFlinger 進(jìn)程端】
dequeueBuffer 函數(shù)參數(shù)outSlot指針帶回一個(gè)BufferSlot數(shù)組的下標(biāo) ,返回值返回標(biāo)記位,但并未返回 GraphicBuffer
dequeueBuffer 函數(shù)中,在獲取的 BufferSlot 沒有GraphicBuffer時(shí),會(huì)new一個(gè)GraphicBuffer,同時(shí)返回值的標(biāo)記為 BUFFER_NEEDS_REALLOCATION
new GraphicBuffer( width, height, format, BQ_LAYER_COUNT, usage, {mConsumerName.string(), mConsumerName.size()});
- GraphicBuffer 構(gòu)造函數(shù)中會(huì)調(diào)用initWithSize,內(nèi)部調(diào)用分配圖形緩存的代碼
- initWithSize(inWidth, inHeight, inFormat, inLayerCount, inUsage, std::move(requestorName));
- GraphicBufferAllocator.allocate
- allocateHelper(width, height, format, layerCount, usage, handle, stride, requestorName, true)
- Gralloc4Allocator.allocate
- hwbinder 服務(wù)調(diào)用:
- IAllocator::getService()->allocate(descriptor, bufferCount,[&](const auto& tmpError, const auto& tmpStride,const auto& tmpBuffers){...}
- 之后的代碼需要看廠家的具體實(shí)現(xiàn),最后無非是調(diào)用到內(nèi)核驅(qū)動(dòng)層分配內(nèi)存,比如調(diào)用ion驅(qū)動(dòng)層分配ion內(nèi)存
- SurfaceFlinger 和 IAllocator 服務(wù)怎么傳遞 共享內(nèi)存的,轉(zhuǎn)“進(jìn)程間圖傳遞圖形buffer詳解【1】”章節(jié)
- 回調(diào)函數(shù)中調(diào)用 IMapper.importBuffer(tmpBuffers[i], &outBufferHandles[i]); // 內(nèi)部使用 mmap 把內(nèi)存映射到當(dāng)前進(jìn)程
- Gralloc4Allocator.allocate
- allocateHelper(width, height, format, layerCount, usage, handle, stride, requestorName, true)
- GraphicBufferAllocator.allocate
- BufferQueueProducer.dequeueBuffer 【SurfaceFlinger 進(jìn)程端】
- 在 dequeueBuffer 返回值的標(biāo)記為 BUFFER_NEEDS_REALLOCATION 時(shí),
- App端需要調(diào)用 requestBuffer,獲取 GraphicBuffer 對(duì)象,
- 同時(shí),把 SurfaceFlinger 分配的圖形緩存,映射到App進(jìn)程
- BpGraphicBufferProducer->requestBuffer(buf, &gbuf);【接口層】
- BufferQueueProducer.requestBuffer-----請(qǐng)求返回 GraphicBuffer 對(duì)象
- SurfaceFlinger 進(jìn)程端 requestBuffer 代碼非常簡(jiǎn)單,僅僅是把 dequeueBuffer 過程中分配的對(duì)象賦值給參數(shù) gbuf ,傳遞給 App
- 那么,圖形緩存的 fd 是怎么傳到App端的,App又是怎么映射的圖形緩存呢?
- 核心在 BpGraphicBufferProducer.requestBuffer 函數(shù)中 GraphicBuffer 對(duì)象的構(gòu)建過程:
- status_t result =remote()->transact(REQUEST_BUFFER, data, &reply);
- 接下來GraphicBuffer 傳輸過程,見 進(jìn)程間圖傳遞圖形buffer詳解【2】
- *buf = new GraphicBuffer();
- result = reply.read(**buf);
- read 過程會(huì)調(diào)用 GraphicBuffer.unflatten
- GraphicBuffer.unflatten 函數(shù)內(nèi)部調(diào)用了 GraphicBufferMapper.importBuffer
- 內(nèi)部也是調(diào)用IMapper.importBuffer,最終使用 mmap 把內(nèi)存映射到當(dāng)前進(jìn)程
- 調(diào)用 mmap 過程,可以參考 hardware/google/gchips/GrallocHAL/src/hidl_common/Mapper.cpp 代碼
- cs.android.com/android/pla…
- GraphicBuffer.unflatten 函數(shù)內(nèi)部調(diào)用了 GraphicBufferMapper.importBuffer
- read 過程會(huì)調(diào)用 GraphicBuffer.unflatten
- status_t result =remote()->transact(REQUEST_BUFFER, data, &reply);
- BpGraphicBufferProducer.dequeueBuffer【接口層】
二、進(jìn)程間圖傳遞圖形buffer詳解
【1】SurfaceFlinger進(jìn)程 和 IAllocator 服務(wù)之間傳遞圖形顯示的Buffer
IAllocator 服務(wù)全稱為 android.hardware.graphics.allocator@4.0::IAllocator/default
高通平臺(tái)上的進(jìn)程名為:vendor.qti.hardware.display.allocator-service
SurfaceFlinger IAllocator 接口的 allocate 函數(shù)
// 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 {
//...
//===================關(guān)鍵代碼============
auto ret = mAllocator->allocate(descriptor, bufferCount,
[&](const auto& tmpError, const auto& tmpStride,
const auto& tmpBuffers) {// const auto& tmpBuffers 是個(gè) 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服務(wù)端的hidl接口實(shí)現(xiàn)
不看具體的allocate函數(shù)實(shí)現(xiàn),重點(diǎn)看數(shù)據(jù)傳輸過程
//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目錄自動(dòng)生成的代碼,源碼目錄下沒有
// 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) {
//...
//========================調(diào)用服務(wù)端真正的實(shí)現(xiàn)=====================
::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;
//===============函數(shù)調(diào)用完成后,開始寫返回?cái)?shù)據(jù)========================
::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; }
// 返回?cái)?shù)據(jù) 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; }
//關(guān)鍵代碼====傳輸上邊的回調(diào)函數(shù)的參數(shù) const auto& tmpBuffers 的每個(gè)元素, 數(shù)據(jù)類型是 hidl_handle 類型
for (size_t _hidl_index_0 = 0; _hidl_index_0 < _hidl_out_buffers.size(); ++_hidl_index_0) {
// 關(guān)鍵函數(shù) 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) {
//此處調(diào)用了 hwbinder/Parcel.cpp 的writeEmbeddedNativeHandle 函數(shù)
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 }, // 關(guān)鍵代碼: BINDER_TYPE_FDA 類型,binder內(nèi)核驅(qū)動(dòng)代碼對(duì)這個(gè)類型有專門的處理
.num_fds = static_cast<binder_size_t>(handle->numFds),
.parent = buffer_handle,
.parent_offset = offsetof(native_handle_t, data),
};
return writeObject(fd_array);
}
之后的代碼,見 binder驅(qū)動(dòng)對(duì) BINDER_TYPE_FDA 、BINDER_TYPE_FD 類型的處理
【2】App進(jìn)程同 SurfaceFlinger 進(jìn)程之間傳遞 GraphicBuffer 對(duì)象
GraphicBuffer 對(duì)象
服務(wù)端 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 對(duì)象回寫========!!!!!!!!!!!!!!=====
}
reply->writeInt32(result);
return NO_ERROR;
}
//...
}
//...
}
Parcel::write 寫對(duì)象流程,
Parcel::write Parcel.h
// frameworks/native/libs/binder/include/binder/Parcel.h
template<typename T>
status_t Parcel::write(const Flattenable<T>& val) {// 對(duì)象需要繼承 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(); 這個(gè)值為 GraphicBuffer.mTransportNumFds
// 從這個(gè)接口獲取
// GrallocMapper::getTransportSize(buffer_handle_t bufferHandle, uint32_t* outNumFds, uint32_t* outNumInts)
const size_t fd_count = val.getFdCount();// 這個(gè)值為 GraphicBuffer.mTransportNumFds
//...........
// 調(diào)用對(duì)象的 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 ,內(nèi)核會(huì)自動(dòng)創(chuàng)建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驅(qū)動(dòng)對(duì) BINDER_TYPE_FDA 、BINDER_TYPE_FD 類型的處理
【3】linux內(nèi)核部分,binder驅(qū)動(dòng)對(duì) BINDER_TYPE_FDA 、BINDER_TYPE_FD 類型的處理
binder_transaction
// 這里使用的 3.8 的內(nèi)核版本,邏輯較為清晰
// 更新的內(nèi)核版本需要看 binder_apply_fd_fixups 函數(shù)部分
// 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);
//數(shù)據(jù)類型為 BINDER_TYPE_FD 時(shí),調(diào)用了 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;
}
//數(shù)據(jù)類型為 BINDER_TYPE_FDA 時(shí),調(diào)用了 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 函數(shù)中對(duì)每一個(gè)fd都調(diào)用了 binder_translate_fd 函數(shù)
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 對(duì)象
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權(quán)限處理
ret = security_binder_transfer_file(proc->tsk, target_proc->tsk, file);
if (ret < 0) {
ret = -EPERM;
goto err_security;
}
//在目標(biāo)進(jìn)程中找到一個(gè)可用的fd
target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);
if (target_fd < 0) {
ret = -ENOMEM;
goto err_get_unused_fd;
}
// 調(diào)用task_fd_install將 file對(duì)象 關(guān)聯(lián)到目標(biāo)進(jìn)程中的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;
}
附、圖形緩存的幾個(gè)重要數(shù)據(jù)類型
1、App端 Surface 同 SurfaceFlinger 用于傳遞共享內(nèi)存 fd 的對(duì)象 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
{
//...
}
//轉(zhuǎn)換后:
class ANativeObjectBase : public ANativeWindowBuffer, public RefBase
{
//...
}
- GraphicBuffer 繼承 ANativeWindowBuffer Flattenable
- Flattenable 兩個(gè)關(guān)鍵函數(shù) flatten unflatten,用于binder序列化時(shí)使用。
ANativeWindowBuffer
// /frameworks/native/libs/nativebase/include/nativebase/nativebase.h
// 圖形Buffer的Size = stride * height * 每像素字節(jié)數(shù)
typedef struct ANativeWindowBuffer
{
...
int width; // 圖形Buffer的寬度
int height; // 圖形Buffer的高度
int stride; // 圖形Buffer的步長(zhǎng),為了處理對(duì)齊問題,與width可能不同
int format; // 圖形Buffer的像素格式
const native_handle_t* handle; // 指向一塊圖形Buffer
uint64_t usage; // 圖形Buffer的使用規(guī)則(gralloc會(huì)分配不同屬性的圖形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]中的文件描述符個(gè)數(shù)
int numFds; /* number of file-descriptors at &data[0] */
// //&data[numFds]中int的個(gè)數(shù)
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接口 進(jìn)程間傳遞 fd 使用的數(shù)據(jù)類型 (HWbinder 傳遞 fd 的對(duì)象)
- hidl_handle 用于 SurfaceFlinger 同 IAllocator HIDL接口的服務(wù)之間傳遞 共享內(nèi)存fd
- 高通平臺(tái)上,這個(gè) HIDL 服務(wù)端對(duì)應(yīng)的進(jìn)程是 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();
// 核心數(shù)據(jù) native_handle_t mHandle;
details::hidl_pointer<const native_handle_t> mHandle;
bool mOwnsHandle;
uint8_t mPad[7];
};
總結(jié):
- SurfaceFlinger進(jìn)程 和 IAllocator服務(wù)進(jìn)程之間通過 hidl_handle 類型的數(shù)據(jù)傳遞 圖形buffer共享內(nèi)存的fd
- 數(shù)據(jù)傳輸中對(duì) hidl_handle 類型數(shù)據(jù)特化處理,并把binder數(shù)據(jù)類型設(shè)置為 BINDER_TYPE_FDA
- binder內(nèi)核對(duì) BINDER_TYPE_FDA 類型數(shù)據(jù)特化處理
- 同時(shí)在 IAllocator.allocate 的回調(diào)函數(shù)中調(diào)用 IMapper.importBuffer 把內(nèi)存映射到當(dāng)前進(jìn)程
- App進(jìn)程 同 SurfaceFlinger進(jìn)程之間使用 GraphicBuffer 對(duì)象傳遞 圖形buffer共享內(nèi)存的fd
- 數(shù)據(jù)傳輸中對(duì) GraphicBuffer 中的 native_handle_t 數(shù)據(jù)特化處理,并把binder數(shù)據(jù)類型設(shè)置為 BINDER_TYPE_FD
- binder內(nèi)核對(duì) BINDER_TYPE_FD 類型數(shù)據(jù)特化處理
- 同時(shí)在從binder讀取數(shù)據(jù)創(chuàng)建GraphicBuffer對(duì)象時(shí),調(diào)用 GraphicBuffer.unflatten,內(nèi)部調(diào)用 IMapper.importBuffer 把內(nèi)存映射到當(dāng)前進(jìn)程
后記
Android12 之后使用 BLASTBufferQueue ,雖然有些變化,但是理解了 GraphicBuffer 和 hidl_handle 傳遞 fd 的過程,這些都游刃有余
Android 的 aidl接口層、hidl接口層、binder bp 接口層 都隱藏了很多關(guān)鍵代碼,導(dǎo)致看代碼時(shí),感覺總是云里霧里
- 像hidl接口,生成的大量代碼,在out/soong目錄下,僅僅看源碼樹目錄下的代碼根本找不到好吧。
以上就是清楚詳解Android 進(jìn)程間圖傳遞圖形buffer原理的詳細(xì)內(nèi)容,更多關(guān)于Android 進(jìn)程間圖傳遞圖形buffer的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android:Field can be converted to a local varible.的解決辦法
這篇文章主要介紹了Android:Field can be converted to a local varible.的解決辦法的相關(guān)資料,希望通過本文能幫助到大家,讓大家遇到這樣的問題輕松解決,需要的朋友可以參考下2017-10-10
Android ScrollView嵌套ExpandableListView顯示不正常的問題的解決辦法
這篇文章主要介紹了Android ScrollView嵌套ExpandableListView顯示不正常的問題的解決辦法的相關(guān)資料,需要的朋友可以參考下2017-02-02
Android 自定義TextView實(shí)現(xiàn)滑動(dòng)解鎖高亮文字
這篇文章主要介紹了Android 自定義TextView實(shí)現(xiàn)滑動(dòng)解鎖高亮文字的相關(guān)資料,需要的朋友可以參考下2018-03-03
Android下拉阻尼效果實(shí)現(xiàn)原理及簡(jiǎn)單實(shí)例
這篇文章主要為大家詳細(xì)介紹了Android下拉阻尼效果實(shí)現(xiàn)原理及簡(jiǎn)單實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-06-06
Android實(shí)現(xiàn)聲音采集回聲與回聲消除
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)聲音采集回聲與回聲消除,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08

