前言
前面兩篇文章《最簡單的BufferQueue測試程序(一)》和《最簡單的BufferQueue測試程序(二)》演示的都是在本地同一進程中操作BufferQueue,而實際使用過程中往往會出現Producer和Consumer位於不同的進程,這時候就需要通過binder調用來實現跨進程操作BufferQueue了。
本篇將以最簡單的代碼形式,演示如何在遠程操作BufferQueue。
Android版本:8.1
參考代碼
server.cpp
#define LOG_TAG "MyTest"
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <gui/BufferQueue.h>
#include <thread>
using namespace android;
struct DummyConsumer : public BnConsumerListener {
void onFrameAvailable(const BufferItem& /* item */) override {}
void onBuffersReleased() override {}
void onSidebandStreamChanged() override {}
};
int main(int argc, char** argv)
{
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer);
consumer->consumerConnect(new DummyConsumer, false);
sp<IServiceManager> serviceManager = defaultServiceManager();
serviceManager->addService(String16("MyProducer"), IInterface::asBinder(producer));
serviceManager->addService(String16("MyConsumer"), IInterface::asBinder(consumer));
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
return 0;
}
client.cpp
#define LOG_TAG "MyTest"
#include <binder/IServiceManager.h>
#include <gui/BufferItem.h>
#include <gui/BufferQueue.h>
#include <gui/IProducerListener.h>
#include <ui/GraphicBuffer.h>
#include <system/window.h>
using namespace android;
int main(int argc, char** argv)
{
sp<IServiceManager> serviceManager = defaultServiceManager();
sp<IBinder> binderProducer = serviceManager->getService(String16("MyProducer"));
sp<IBinder> binderConsumer = serviceManager->getService(String16("MyConsumer"));
sp<IGraphicBufferProducer> producer = interface_cast<IGraphicBufferProducer>(binderProducer);
sp<IGraphicBufferConsumer> consumer = interface_cast<IGraphicBufferConsumer>(binderConsumer);
IGraphicBufferProducer::QueueBufferOutput output;
producer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false, &output);
/****************** Producer ***********************/
int slot;
sp<Fence> fence;
sp<GraphicBuffer> buffer;
producer->dequeueBuffer(&slot, &fence, 0, 0, 0,
GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr, nullptr);
producer->requestBuffer(slot, &buffer);
uint32_t* dataIn;
buffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN,
reinterpret_cast<void**>(&dataIn));
*dataIn = 0x12345678u;
buffer->unlock();
IGraphicBufferProducer::QueueBufferInput input(0, false, HAL_DATASPACE_UNKNOWN, Rect(1, 1),
NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
producer->queueBuffer(slot, input, &output);
/****************** Consumer ***********************/
BufferItem item;
consumer->acquireBuffer(&item, static_cast<nsecs_t>(0));
uint32_t* dataOut;
item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN,
reinterpret_cast<void**>(&dataOut));
printf("data out is 0x%08x\n", *dataOut);
item.mGraphicBuffer->unlock();
consumer->releaseBuffer(item.mSlot, item.mFrameNumber, EGL_NO_DISPLAY,
EGL_NO_SYNC_KHR, Fence::NO_FENCE);
return 0;
}
Android.bp
cc_test {
name: "client",
srcs: ["client.cpp"],
clang: true,
shared_libs: [
"liblog",
"libbinder",
"libgui",
"libui",
"libutils",
],
}
cc_test {
name: "server",
srcs: ["server.cpp"],
clang: true,
shared_libs: [
"liblog",
"libbinder",
"libgui",
"libui",
"libutils",
],
}
運行結果
$ adb shell /data/server &
$ adb shell /data/client
data out is 0x12345678
描述
- 首先啓動server進程,用於創建BufferQueue、Producer和Consumer對象;
- 在client端通過ServiceManager獲取到Producer & Consumer的遠程代理;
- 通過Producer & Consumer的遠程代理,完成BufferQueue的一系列操作(操作內容同《最簡單的BufferQueue測試程序(一)》一樣)。
注意: Android規定,BufferQueue必須在Consumer進程中創建。因此該示例將
consumerConnect()
放在了server.cpp中。如果放在client.cpp中,在調用queueBuffer()
時,程序會出現crash。
源碼下載
參考資料
Android BufferQueue自測試程序:BufferQueue_test.cpp: DISABLED_BufferQueueInAnotherProcess