[Android] Android SurfaceFlinger 의 BufferQueue
44712 단어 안 드 로 이 드 지식 창고
1. BufferQueue 모드
BufferQueue 와 관련 된 소스 코드 는 frameworks / native / libs / gui / 에 있 으 며 다음 과 같은 몇 가지 중요 한 데이터 구조 와 관련된다.
class BufferQueue;
class BufferQueueCore;
class BufferQueueProducer;
class BufferQueueConsumer;
BufferQueue 는 전형 적 인 생산자 - 소비자 모델 에 속 하고 buffer 상 태 를 나타 내 는 BufferState 도 있 는데 모두 다섯 가지 상태 로 각각 FREE, DEQUEUED, QUEUED, ACQUIRED 와 SHARED 이다.FREE 는 buffer 가 Producer 에 의 해 dequeue 를 진행 할 수 있 음 을 나타 낸다. 이때 buffer 는 BufferQueue 에 속 하고 dequeue buffer 일 때 상태 가 DEQUEUED 로 변 한다.DEQUEUED 는 buffer 가 Producer dequeued 에 의 해 변경 되 었 으 나 아직 queued 와 canceled 에 의 해 변경 되 지 않 았 음 을 표시 합 니 다. 관련 release fence 알림 을 받 았 을 때 Producer 는 buffer 의 데 이 터 를 수정 할 수 있 습 니 다. 이때 buffer 는 Producer 에 속 하고 quue 나 attach buffer 에 속 할 때 상 태 는 QUEUED 로 변 하고 cancel 또는 detach buffer 에 속 할 때 상 태 는 FREE 로 변 합 니 다.QUEUED 는 Producer 가 buffer 를 채 우 고 Consumer queued 에 의 해 buffer 데이터 가 수 정 될 수 있 음 을 나타 내 며 fence 신호 와 관련 이 있 습 니 다. 이때 buffer 는 BufferQueue 에 속 합 니 다. acquire buffer 일 때 상 태 는 ACQUIRED 로 변 하고 다른 비동기 buffer 가 QUEUED 로 변 할 때 이 buffer 는 FREE 로 변 합 니 다.ACQUIRED 는 buffer 가 Consumer 에 의 해 acquired 되 고 buffer 데이터 가 수 정 될 수 있 음 을 나타 내 며 fence 신호 와 관련 이 있 습 니 다. 이때 buffer 는 Consumer 에 속 하고 release 또는 detach buffer 일 때 상태 가 FREE 로 변 합 니 다. buffer datach 후에 attach 를 진행 하면 그 상 태 는 ACQUIRED 로 변 합 니 다.SHARED 는 buffer 를 공유 모드 로 표시 하 는 동시에 FREE 를 제외 한 모든 상태 일 수 있 으 며, 여러 번 dequeud, queued, acquired 를 받 을 수 있 습 니 다.
buffer 의 몇 가지 상태 에서 Producer 와 Consumer 와 관련 되 고 그들의 상호작용 은 반드시 BufferQueue 라 는 관리자 나 중 개 를 통 해 이 루어 져 야 한다.Producer 는 일반적으로 응용 프로그램 으로 buffer 에 데 이 터 를 계속 채 워 줍 니 다. 그러나 먼저 BufferQueue 에 dequeue 를 진행 하여 buffer 를 신청 해 야 합 니 다. 이때 buffer 는 모든 것 이 고 데 이 터 를 채 운 후에 BufferQueue 에 queue 를 하고 제어 권 을 BufferQueue 에 돌려 주어 야 합 니 다. 이런 작업 은 모두 Producer 가 주동 적 으로 시작 한 것 입 니 다.한편, Consumer 는 수 동적 입 니 다. buffer 데이터 가 준 비 된 후에 야 소 비 를 하 라 는 통 지 를 받 았 습 니 다. 이 통 지 는 BufferQueue 에 의 해 시 작 된 것 입 니 다. BufferQueue 는 서비스 기구 입 니 다. 그 내부 에 Proxy Consumer Listener 가 있 고 buffer 데이터 가 준비 되면 Consumer 에 게 소 비 를 하 라 고 알 립 니 다.
2. BufferQueue 버퍼 할당 과정
전체 적 으로 BufferQueue 인 스 턴 스 가 없습니다. private BufferQueue 구조 함수 만 밝 혔 을 뿐 실현 되 지 않 았 습 니 다. 사실 사용 할 수 없습니다. static 함수 createBufferQueue 를 통 해 각각 BufferQueue Core, BufferQueue Producer 와 BufferQueue Consumer 를 만 들 었 습 니 다. 그 중에서 Buffer Queue Core 는 매개 변수 로 BufferQueue Producer 와 BufferQueue Consumer 에 전 달 했 습 니 다. 다음 과 같 습 니 다.
void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer,
const sp<IGraphicBufferAlloc>& allocator) {
LOG_ALWAYS_FATAL_IF(outProducer == NULL,
"BufferQueue: outProducer must not be NULL");
LOG_ALWAYS_FATAL_IF(outConsumer == NULL,
"BufferQueue: outConsumer must not be NULL");
sp<BufferQueueCore> core(new BufferQueueCore(allocator));
LOG_ALWAYS_FATAL_IF(core == NULL,
"BufferQueue: failed to create BufferQueueCore");
sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core));
LOG_ALWAYS_FATAL_IF(producer == NULL,
"BufferQueue: failed to create BufferQueueProducer");
sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));
LOG_ALWAYS_FATAL_IF(consumer == NULL,
"BufferQueue: failed to create BufferQueueConsumer");
*outProducer = producer;
*outConsumer = consumer;
}
Buffer Queue Core 는 Buffer Queue 를 관리 하 는 핵심 클래스 로 다음 과 같은 두 가지 중요 한 구성원 변수 가 있 습 니 다. mAllocator 는 Surface Flinger 와 연결 되 어 Graphic Buffer 를 만 들 고 mSlots 는 buffer 데 이 터 를 저장 하 는 데 사용 되 며 64 개의 buffer 를 지원 합 니 다. 그 중에서 Buffer Slot 는 Graphic Buffer 와 BufferState 를 저장 합 니 다.
sp mAllocator;
BufferQueueDefs::SlotsType mSlots;
namespace BufferQueueDefs {
enum { NUM_BUFFER_SLOTS = 64 };
typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS];
}
struct BufferSlot {
BufferSlot()
: mGraphicBuffer(nullptr),
mEglDisplay(EGL_NO_DISPLAY),
mBufferState(),
mRequestBufferCalled(false),
mFrameNumber(0),
mEglFence(EGL_NO_SYNC_KHR),
mFence(Fence::NO_FENCE),
mAcquireCalled(false),
mNeedsReallocation(false) {
}
sp mGraphicBuffer;
EGLDisplay mEglDisplay;
BufferState mBufferState;
bool mRequestBufferCalled;
uint64_t mFrameNumber;
EGLSyncKHR mEglFence;
sp mFence;
bool mAcquireCalled;
bool mNeedsReallocation;
};
위 에서 언급 한 buffer 분 배 는 생산자 에 의 해 시 작 됩 니 다. 즉, Buffer Queue Producer 의 deququeBuffer 작업 입 니 다. 함수 원형 은 다음 과 같 습 니 다.
status_t BufferQueueProducer::dequeueBuffer(int *outSlot,
sp<:fence> *outFence, uint32_t width, uint32_t height,
PixelFormat format, uint32_t usage) {
ATRACE_CALL();
{ // Autolock scope
Mutex::Autolock lock(mCore->mMutex);
mConsumerName = mCore->mConsumerName;
if (mCore->mIsAbandoned) {
BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned");
return NO_INIT;
}
if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
BQ_LOGE("dequeueBuffer: BufferQueue has no connected producer");
return NO_INIT;
}
} // Autolock scope
BQ_LOGV("dequeueBuffer: w=%u h=%u format=%#x, usage=%#x", width, height,
format, usage);
if ((width && !height) || (!width && height)) {
BQ_LOGE("dequeueBuffer: invalid size: w=%u h=%u", width, height);
return BAD_VALUE;
}
status_t returnFlags = NO_ERROR;
EGLDisplay eglDisplay = EGL_NO_DISPLAY;
EGLSyncKHR eglFence = EGL_NO_SYNC_KHR;
bool attachedByConsumer = false;
{ // Autolock scope
Mutex::Autolock lock(mCore->mMutex);
mCore->waitWhileAllocatingLocked();
if (format == 0) {
format = mCore->mDefaultBufferFormat;
}
// Enable the usage bits the consumer requested
usage |= mCore->mConsumerUsageBits;
const bool useDefaultSize = !width && !height;
if (useDefaultSize) {
width = mCore->mDefaultWidth;
height = mCore->mDefaultHeight;
}
int found = BufferItem::INVALID_BUFFER_SLOT;
while (found == BufferItem::INVALID_BUFFER_SLOT) {
status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue,
&found);
if (status != NO_ERROR) {
return status;
}
// This should not happen
if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
BQ_LOGE("dequeueBuffer: no available buffer slots");
return -EBUSY;
}
const sp& buffer(mSlots[found].mGraphicBuffer);
// If we are not allowed to allocate new buffers,
// waitForFreeSlotThenRelock must have returned a slot containing a
// buffer. If this buffer would require reallocation to meet the
// requested attributes, we free it and attempt to get another one.
if (!mCore->mAllowAllocation) {
if (buffer->needsReallocation(width, height, format, usage)) {
if (mCore->mSharedBufferSlot == found) {
BQ_LOGE("dequeueBuffer: cannot re-allocate a shared"
"buffer");
return BAD_VALUE;
}
mCore->mFreeSlots.insert(found);
mCore->clearBufferSlotLocked(found);
found = BufferItem::INVALID_BUFFER_SLOT;
continue;
}
}
}
const sp& buffer(mSlots[found].mGraphicBuffer);
if (mCore->mSharedBufferSlot == found &&
buffer->needsReallocation(width, height, format, usage)) {
BQ_LOGE("dequeueBuffer: cannot re-allocate a shared"
"buffer");
return BAD_VALUE;
}
if (mCore->mSharedBufferSlot != found) {
mCore->mActiveBuffers.insert(found);
}
*outSlot = found;
ATRACE_BUFFER_INDEX(found);
attachedByConsumer = mSlots[found].mNeedsReallocation;
mSlots[found].mNeedsReallocation = false;
mSlots[found].mBufferState.dequeue();
if ((buffer == NULL) ||
buffer->needsReallocation(width, height, format, usage))
{
mSlots[found].mAcquireCalled = false;
mSlots[found].mGraphicBuffer = NULL;
mSlots[found].mRequestBufferCalled = false;
mSlots[found].mEglDisplay = EGL_NO_DISPLAY;
mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
mSlots[found].mFence = Fence::NO_FENCE;
mCore->mBufferAge = 0;
mCore->mIsAllocating = true;
returnFlags |= BUFFER_NEEDS_REALLOCATION;
} else {
// We add 1 because that will be the frame number when this buffer
// is queued
mCore->mBufferAge =
mCore->mFrameCounter + 1 - mSlots[found].mFrameNumber;
}
BQ_LOGV("dequeueBuffer: setting buffer age to %" PRIu64,
mCore->mBufferAge);
if (CC_UNLIKELY(mSlots[found].mFence == NULL)) {
BQ_LOGE("dequeueBuffer: about to return a NULL fence - "
"slot=%d w=%d h=%d format=%u",
found, buffer->width, buffer->height, buffer->format);
}
eglDisplay = mSlots[found].mEglDisplay;
eglFence = mSlots[found].mEglFence;
// Don't return a fence in shared buffer mode, except for the first
// frame.
*outFence = (mCore->mSharedBufferMode &&
mCore->mSharedBufferSlot == found) ?
Fence::NO_FENCE : mSlots[found].mFence;
mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
mSlots[found].mFence = Fence::NO_FENCE;
// If shared buffer mode has just been enabled, cache the slot of the
// first buffer that is dequeued and mark it as the shared buffer.
if (mCore->mSharedBufferMode && mCore->mSharedBufferSlot ==
BufferQueueCore::INVALID_BUFFER_SLOT) {
mCore->mSharedBufferSlot = found;
mSlots[found].mBufferState.mShared = true;
}
} // Autolock scope
if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
status_t error;
BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot);
sp graphicBuffer(mCore->mAllocator->createGraphicBuffer(
width, height, format, usage,
{mConsumerName.string(), mConsumerName.size()}, &error));
{ // Autolock scope
Mutex::Autolock lock(mCore->mMutex);
if (graphicBuffer != NULL && !mCore->mIsAbandoned) {
graphicBuffer->setGenerationNumber(mCore->mGenerationNumber);
mSlots[*outSlot].mGraphicBuffer = graphicBuffer;
}
mCore->mIsAllocating = false;
mCore->mIsAllocatingCondition.broadcast();
if (graphicBuffer == NULL) {
mCore->mFreeSlots.insert(*outSlot);
mCore->clearBufferSlotLocked(*outSlot);
BQ_LOGE("dequeueBuffer: createGraphicBuffer failed");
return error;
}
if (mCore->mIsAbandoned) {
mCore->mFreeSlots.insert(*outSlot);
mCore->clearBufferSlotLocked(*outSlot);
BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned");
return NO_INIT;
}
VALIDATE_CONSISTENCY();
} // Autolock scope
}
if (attachedByConsumer) {
returnFlags |= BUFFER_NEEDS_REALLOCATION;
}
if (eglFence != EGL_NO_SYNC_KHR) {
EGLint result = eglClientWaitSyncKHR(eglDisplay, eglFence, 0,
1000000000);
// If something goes wrong, log the error, but return the buffer without
// synchronizing access to it. It's too late at this point to abort the
// dequeue operation.
if (result == EGL_FALSE) {
BQ_LOGE("dequeueBuffer: error %#x waiting for fence",
eglGetError());
} else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
BQ_LOGE("dequeueBuffer: timeout waiting for fence");
}
eglDestroySyncKHR(eglDisplay, eglFence);
}
BQ_LOGV("dequeueBuffer: returning slot=%d/%" PRIu64 " buf=%p flags=%#x",
*outSlot,
mSlots[*outSlot].mFrameNumber,
mSlots[*outSlot].mGraphicBuffer->handle, returnFlags);
return returnFlags;
}
deququeBuffer 의 목적 은 바로 Producer 에 사용 가능 한 buffer 를 신청 하 는 것 입 니 다. 최종 적 으로 buffer slots 배열 색인 을 얻 었 습 니 다. outSlot 매개 변 수 를 통 해 되 돌아 갑 니 다. outFence 는 동기 화 형식 입 니 다. Fence 를 사용 할 때 Fence 신 호 를 기 다 려 야 buffer 를 수정 할 수 있 습 니 다. width 와 height 참 수 는 일정한 제한 이 있 습 니 다. 최대 치 는 GL 을 초과 해 서 는 안 됩 니 다.MAX_VIEWPORT_DIMS 와 GLMAX_TEXTURE_SIZE 의 최소 값 입 니 다. 이 값 은 glGetIntegerv 를 통 해 얻 을 수 있 습 니 다. updateTexImage 와 관련 하여 width 와 height 가 0 일 때 기본 값 1 을 사용 합 니 다. 그 중 하나 가 0 이면 오류 가 발생 합 니 다. format 와 usage 는 buffer 의 형식 과 용 도 를 지정 합 니 다. format 가 0 일 때 기본 mDefault BufferFormat, 즉 PIXEL 을 사용 합 니 다.FORMAT_RGBA_8888。
deququeBuffer 함수 에 서 는 먼저 BufferQueue 가 사용 가능 한 지, BufferQueue 가 Producer, width, height 인자 에 연결 되 어 있 는 지, 실패 할 때 오류 가 발생 했 는 지 확인 합 니 다.그리고 while 순환 에 들 어가 사용 가능 한 buffer slot 를 찾 습 니 다. 그러나 그 전에 width, height, format, usage 변 수 를 처리 해 야 합 니 다. 다른 buffer 할당 작업 이 끝 날 때 까지 기 다 려 야 합 니 다. pthread 조건 변 수 를 사용 합 니 다.while 순환 에서 사용 가능 한 buffer slot 를 찾 을 때 먼저 wait ForFreeSlot Then Relock 에 들 어 갑 니 다. 이름 에서 알 수 있 듯 이 FREE 상 태 를 가 져 오 는 buffer slot 입 니 다. 또한 buffer 의 DEQUEUEED 와 ACQUIRED 상태의 개 수 를 통계 할 수 있 습 니 다. 제 한 된 최대 치 를 초과 할 수 없고 자주 disconect 를 한 후에 바로 connect 할 수 없습니다. 이 는 메모리 가 소 진 될 수 있 습 니 다.buffer 를 기다 리 는 동안 차단, 지연 효 과 는 buffer 조회 결과 에 영향 을 줍 니 다.buffer slot 를 가 져 온 후에 실제 buffer slot 의 배열 색인 입 니 다. 이 때 는 메모리 가 진정 으로 분배 되 지 않 았 습 니 다. 새로운 buffer 를 할당 할 수 있 는 권한 이 없 을 때 이 단 계 는 보통 사용 가능 한 buffer 로 돌아 갑 니 다. 그러나 주의해 야 할 것 은 이 buffer 가 가끔 가장 좋 은 것 이 아니 라 재 분 배 를 해 야 합 니 다. 이 비우 면이 buffer 는 free 로 떨 어 지고 뒤의 재 분 배 를 기다 릴 것 입 니 다.while 순환 후 buffer 가 재배 치 되 어야 할 경우 createGraphic Buffer 를 통 해 완성 되 며, 이로써 dequeueBuffer 가 완 료 됩 니 다.
dequeue Buffer 에서 가 져 온 것 은 buffer slot 색인 입 니 다. 그러면 서로 다른 프로 세 스 에 속 하 는 서버 와 클 라 이언 트 가 같은 메모리 에 접근 하 는 것 을 어떻게 보장 합 니까? 이것 은 Android 의 Binder 체 제 를 사 용 했 습 니 다. 다음 과 같은 몇 가지 관련 된 종 류 를 포함 합 니 다.
class BufferQueueProducer : public BnGraphicBufferProducer, private IBinder::DeathRecipient
class BnGraphicBufferProducer : public BnInterface
class BpGraphicBufferProducer : public BpInterface
다음은 BpGraphic Buffer Producer 의 dequeue Buffer 구현 입 니 다. 관건 은 reote 를 통 해 transact 를 호출 하 는 것 입 니 다. 이때 native BnGraphic Buffer Producer 의 onTransact 로 갑 니 다.
virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, uint32_t width,
uint32_t height, PixelFormat format, uint32_t usage) {
Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
data.writeUint32(width);
data.writeUint32(height);
data.writeInt32(static_cast<int32_t>(format));
data.writeUint32(usage);
status_t result = remote()->transact(DEQUEUE_BUFFER, data, &reply);
if (result != NO_ERROR) {
return result;
}
*buf = reply.readInt32();
bool nonNull = reply.readInt32();
if (nonNull) {
*fence = new Fence();
result = reply.read(**fence);
if (result != NO_ERROR) {
fence->clear();
return result;
}
}
result = reply.readInt32();
return result;
}
다음은 BnGraphic Buffer Producer 의 onTransact 부분 코드 입 니 다. DEQUEUEBUFFER 시 data 에서 파 라 메 터 를 가 져 온 후 buffer 생산자 의 dequeue Buffer 를 호출 한 후 결 과 를 reply 파라미터 로 되 돌려 줍 니 다.
status_t BnGraphicBufferProducer::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case DEQUEUE_BUFFER: {
CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
uint32_t width = data.readUint32();
uint32_t height = data.readUint32();
PixelFormat format = static_cast<PixelFormat>(data.readInt32());
uint32_t usage = data.readUint32();
int buf = 0;
sp<Fence> fence;
int result = dequeueBuffer(&buf, &fence, width, height, format,
usage);
reply->writeInt32(buf);
reply->writeInt32(fence != NULL);
if (fence != NULL) {
reply->write(*fence);
}
reply->writeInt32(result);
return NO_ERROR;
}
}
return BBinder::onTransact(code, data, reply, flags);
}
IGraphicBuffer Producer 에는 두 개의 struct 가 있 습 니 다. QueueBufferInput 과 QueueBuffer Output 은 다음 과 같 습 니 다. 그 중에서 QueueBuffer Input 은 Flattenable 프로 토 콜 을 사용 하여 한 대상 인 buffer 입 형 디지털화 에 사 용 됩 니 다.
struct QueueBufferInput : public Flattenable
struct QueueBufferOutput
3. 응용 프로그램 과 BufferQueue
앞에서 BufferQueue 의 기본 원 리 를 소 개 했 는데 어떻게 응용 프로그램 과 연결 되 었 습 니까?frameworks / base / cmds / bootanimation / 이 시스템 의 부팅 애니메이션 을 예 로 들 면 bootanimation 과 Surface Flinger 는 OpenGL ES 를 사용 하여 UI 디 스 플레이 를 완성 합 니 다. Android 장치 에 전기 가 들 어가 면 BootLoader 화면, Kernel 그림, Android 화면 등 몇 가지 다른 부팅 화면 이 표 시 될 수 있 습 니 다. bootanim. rc 시작 스 크 립 트 의 내용 은 다음 과 같 습 니 다.
service bootanim /system/bin/bootanimation
class core
user graphics
group graphics audio
disabled
oneshot
writepid /dev/stune/top-app/tasks
bootanimation 이 시 작 된 후에 먼저 다음 과 같은 main 함수 에 들 어가 속성 debug. sf. nobootanimation 을 통 해 애니메이션 을 시작 하 는 지 여 부 를 판단 하고 애니메이션 이 있 을 때 스 레 드 풀 을 시작 한 다음 에 BootAnimation 대상 을 만 들 고 스 레 드 풀 에 가입 합 니 다.
int main()
{
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
char value[PROPERTY_VALUE_MAX];
property_get("debug.sf.nobootanimation", value, "0");
int noBootAnimation = atoi(value);
ALOGI_IF(noBootAnimation, "boot animation disabled");
if (!noBootAnimation) {
sp proc(ProcessState::self());
ProcessState::self()->startThreadPool();
// create the boot animation object
sp boot = new BootAnimation();
IPCThreadState::self()->joinThreadPool();
}
return 0;
}
BootAnimation 은 애니메이션 을 시작 하 는 구현 클래스 로 Thread 와 Binder 를 계승 하여 구조 함수 에 Surface Composer Client 대상, 즉 mSession 을 생 성하 여 Surface Flinger 와 의 연결 채널 을 만 들 었 고 앞에서 언급 한 IGraphicBuffer Producer 는 응용 프로그램 과 BufferQueue 의 전송 채널 이 며 BufferQueue 는 모든 응용 프로그램의 회화 과정 을 책임 집 니 다.Surface Flinger 는 모든 프로그램의 최종 그림 결 과 를 혼합 하여 물리 화면 에 통일 적 으로 표시 합 니 다.
class BootAnimation : public Thread, public IBinder::DeathRecipient
BootAnimation::BootAnimation() : Thread(false), mClockEnabled(true), mTimeIsAccurate(false),
mTimeCheckThread(NULL) {
mSession = new SurfaceComposerClient();
// If the system has already booted, the animation is not being used for a boot.
mSystemBoot = !property_get_bool(BOOT_COMPLETED_PROP_NAME, 0);
}
BootAnimation 상속 자 RefBase 는 포인터 가 처음 인 용 될 때 onFirst Ref 함 수 를 터치 합 니 다. 원 격 Binder 서비스 와 연결 한 후 Binder 서비스 가 마 운 트 된 빈 공간 을 처리 하고 binder Died 함 수 를 다시 설치 한 다음 run 을 호출 하여 BootAnimation 스 레 드 를 시작 합 니 다.
void BootAnimation::onFirstRef() {
status_t err = mSession->linkToComposerDeath(this);
ALOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
if (err == NO_ERROR) {
run("BootAnimation", PRIORITY_DISPLAY);
}
}
void BootAnimation::binderDied(const wp<IBinder>&)
{
// woah, surfaceflinger died!
ALOGD("SurfaceFlinger died, exiting...");
// calling requestExit() is not enough here because the Surface code
// might be blocked on a condition variable that will never be updated.
kill( getpid(), SIGKILL );
requestExit();
audioplay::destroy();
}
다음은 ready ToRun 입 니 다. 관건 적 인 두 단 계 는 Surface ComposerClient 를 통 해 buffer 와 EGL 설정 을 만 드 는 것 입 니 다. 다음 코드 는 다음 과 같 습 니 다.
status_t BootAnimation::readyToRun() {
mAssets.addDefaultAssets();
sp dtoken(SurfaceComposerClient::getBuiltInDisplay(
ISurfaceComposer::eDisplayIdMain));
DisplayInfo dinfo;
status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo);
if (status)
return -1;
// create the native surface
sp control = session()->createSurface(String8("BootAnimation"),
dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
SurfaceComposerClient::openGlobalTransaction();
control->setLayer(0x40000000);
SurfaceComposerClient::closeGlobalTransaction();
sp s = control->getSurface();
// initialize opengl and egl
const EGLint attribs[] = {
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_DEPTH_SIZE, 0,
EGL_NONE
};
EGLint w, h;
EGLint numConfigs;
EGLConfig config;
EGLSurface surface;
EGLContext context;
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, 0, 0);
eglChooseConfig(display, attribs, &config, 1, &numConfigs);
surface = eglCreateWindowSurface(display, config, s.get(), NULL);
context = eglCreateContext(display, config, NULL, NULL);
eglQuerySurface(display, surface, EGL_WIDTH, &w);
eglQuerySurface(display, surface, EGL_HEIGHT, &h);
if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
return NO_INIT;
mDisplay = display;
mContext = context;
mSurface = surface;
mWidth = w;
mHeight = h;
mFlingerSurfaceControl = control;
mFlingerSurface = s;
// If the device has encryption turned on or is in process
// of being encrypted we show the encrypted boot animation.
char decrypt[PROPERTY_VALUE_MAX];
property_get("vold.decrypt", decrypt, "");
bool encryptedAnimation = atoi(decrypt) != 0 || !strcmp("trigger_restart_min_framework", decrypt);
if (encryptedAnimation && (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0)) {
mZipFileName = SYSTEM_ENCRYPTED_BOOTANIMATION_FILE;
}
else if (access(OEM_BOOTANIMATION_FILE, R_OK) == 0) {
mZipFileName = OEM_BOOTANIMATION_FILE;
}
else if (access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) {
mZipFileName = SYSTEM_BOOTANIMATION_FILE;
}
return NO_ERROR;
}
Surface ComposerClient 의 createSurface, Surface Flinger 에서 의 실현 은 바로 Client 의 createSurface 입 니 다. 다음 과 같 습 니 다.
status_t Client::createSurface(
const String8& name,
uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
sp* handle,
sp* gbp)
{
/*
* createSurface must be called from the GL thread so that it can
* have access to the GL context.
*/
class MessageCreateLayer : public MessageBase {
SurfaceFlinger* flinger;
Client* client;
sp* handle;
sp* gbp;
status_t result;
const String8& name;
uint32_t w, h;
PixelFormat format;
uint32_t flags;
public:
MessageCreateLayer(SurfaceFlinger* flinger,
const String8& name, Client* client,
uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
sp* handle,
sp* gbp)
: flinger(flinger), client(client),
handle(handle), gbp(gbp), result(NO_ERROR),
name(name), w(w), h(h), format(format), flags(flags) {
}
status_t getResult() const { return result; }
virtual bool handler() {
result = flinger->createLayer(name, client, w, h, format, flags,
handle, gbp);
return true;
}
};
sp msg = new MessageCreateLayer(mFlinger.get(),
name, this, w, h, format, flags, handle, gbp);
mFlinger->postMessageSync(msg);
return static_cast( msg.get() )->getResult();
}
Client:: createSurface 에서 메시지 post 를 Surface Flinger 에 동기 화 하 는 동안 Layer 를 만 들 었 습 니 다. 다음 createNormal Layer:
status_t SurfaceFlinger::createLayer(
const String8& name,
const sp& client,
uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
sp* handle, sp* gbp)
{
//ALOGD("createLayer for (%d x %d), name=%s", w, h, name.string());
if (int32_t(w|h) < 0) {
ALOGE("createLayer() failed, w or h is negative (w=%d, h=%d)",
int(w), int(h));
return BAD_VALUE;
}
status_t result = NO_ERROR;
sp layer;
switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
case ISurfaceComposerClient::eFXSurfaceNormal:
result = createNormalLayer(client,
name, w, h, flags, format,
handle, gbp, &layer);
break;
case ISurfaceComposerClient::eFXSurfaceDim:
result = createDimLayer(client,
name, w, h, flags,
handle, gbp, &layer);
break;
default:
result = BAD_VALUE;
break;
}
if (result != NO_ERROR) {
return result;
}
result = addClientLayer(client, *handle, *gbp, layer);
if (result != NO_ERROR) {
return result;
}
setTransactionFlags(eTransactionNeeded);
return result;
}
Surface Flinger:: create Normal Layer 를 통 해 알 수 있 듯 이 여기 서 진정 으로 Layer 대상 을 만 들 었 고 Buffer Queue 와 Surface Flinger Consumer, Monitor Producer 를 만 들 었 습 니 다. 이렇게 Buffer 중개, 생산자, 소비자 생 성 이 완료 되 었 습 니 다. Layer 는 마치 많은 그림 의 한 층 과 같 습 니 다. 마지막 으로 Surface Flinger 를 통 해 처리 하여 화면 에 표 시 됩 니 다.
status_t SurfaceFlinger::createNormalLayer(const sp& client,
const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
sp* handle, sp* gbp, sp* outLayer)
{
// initialize the surfaces
switch (format) {
case PIXEL_FORMAT_TRANSPARENT:
case PIXEL_FORMAT_TRANSLUCENT:
format = PIXEL_FORMAT_RGBA_8888;
break;
case PIXEL_FORMAT_OPAQUE:
format = PIXEL_FORMAT_RGBX_8888;
break;
}
*outLayer = new Layer(this, client, name, w, h, flags);
status_t err = (*outLayer)->setBuffers(w, h, format, flags);
if (err == NO_ERROR) {
*handle = (*outLayer)->getHandle();
*gbp = (*outLayer)->getProducer();
}
ALOGE_IF(err, "createNormalLayer() failed (%s)", strerror(-err));
return err;
}
이로써 buffer 생 성 이 완료 되 었 습 니 다. EGL 설정 이 완료 되 었 고 threadLoop 에 들 어 갔 습 니 다. 이 어 안 드 로 이 드 나 movie 가 될 수 있 습 니 다. 안 에는 모두 OpenGL 작업 으로 애니메이션 을 표시 하고 마지막 으로 EGL 을 통 해 자원 을 방출 하여 스 레 드 풀 을 종료 할 수 있 습 니 다.
bool BootAnimation::threadLoop()
{
bool r;
// We have no bootanimation file, so we use the stock android logo
// animation.
if (mZipFileName.isEmpty()) {
r = android();
} else {
r = movie();
}
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroyContext(mDisplay, mContext);
eglDestroySurface(mDisplay, mSurface);
mFlingerSurface.clear();
mFlingerSurfaceControl.clear();
eglTerminate(mDisplay);
eglReleaseThread();
IPCThreadState::self()->stopProcess();
return r;
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
[Android]Android 자바 동적 라 이브 러 리,정적 라 이브 러 리 의 컴 파일 및 사용BUILD_STATIC_JAVA_LIBRARY BUILD_STATIC_JAVA_LIBRARY컴 파일 결 과 는 자바 정적 라 이브 러 리 이 고 더 정확히 말 하면 안 드 로 이 드 와 무관 한 순수한 자바 패키지 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.