和你一起終身學習,這裏是程序員 Android
經典好文推薦,通過閱讀本文,您將收穫以下知識點:
一、Consumer端的FrameListener
二、消息隊列MessageQueue
三、顯示設備DispalyDevice
通過前面的簡單介紹,我們對HWC合成有大致的瞭解。下面我們根據實際代碼進行講解。前面章節,我們已經說過,Layer的創建,和BufferQueue,那麼Buffer進入到BufferQueue隊列中後,怎麼進行合成顯示的呢?我們繼續來看。
一、Consumer端的FrameListener
你還記得Producer的frameAvailableListener嗎?Buffer放入隊列BufferQueue後,是不是通過frameAvailableListener->onFrameAvailable
通知Consumer?大家可以再回望一下BufferQueueProducer::queueBuffer
。
frameAvailableListener是哪裏來的?
我們先來看一下Consumer中Listener間的相互關係
- BufferLayer有專門的Consumer,BufferLayerConsumer;BufferLayerConsumer繼承ConsumerBase。ConsumerBase通過IGraphicBufferConsumer和BufferQueue進行通信的。
- BufferQueue中的frameAvailableListener,是一個IConsumerListener的接口,對應的Binder的Bn端實現爲ProxyConsumerListener。
- BufferLayer實現了ContentsChangedListener,ContentsChangedListener繼承FrameAvailableListener。BufferLayer的Listener實現,被傳給了ConsumerBase。
- ConsumerBase實現ConsumerListener接口,構建ConsumerBase時,會創建ProxyConsumerListener,將ConsumerBase實現的Listener接口傳給ProxyConsumerListener。
- BufferQueue中Listener回調時,會回調到ConsumerBase中。ConsumerBase中再通過BufferLayer實現的,傳下來的Listener回調到BufferLayer中。
層層回調,別弄混淆了。
關鍵代碼:
BufferQueueProducer中通過frameAvailableListener->onFrameAvailable
回調到ProxyConsumerListener中:
* frameworks/native/libs/gui/BufferQueue.cpp
void BufferQueue::ProxyConsumerListener::onFrameAvailable(
const BufferItem& item) {
sp<ConsumerListener> listener(mConsumerListener.promote());
if (listener != NULL) {
listener->onFrameAvailable(item);
}
}
ProxyConsumerListener中的mConsumerListener是ConsumerBase中的實現。這裏的listener->onFrameAvailable
將回調到ConsumerBase中。
* frameworks/native/libs/gui/ConsumerBase.cpp
void ConsumerBase::onFrameAvailable(const BufferItem& item) {
CB_LOGV("onFrameAvailable");
sp<FrameAvailableListener> listener;
{ // scope for the lock
Mutex::Autolock lock(mFrameAvailableMutex);
listener = mFrameAvailableListener.promote();
}
if (listener != NULL) {
CB_LOGV("actually calling onFrameAvailable");
listener->onFrameAvailable(item);
}
}
ConsumerBase中的mFrameAvailableListener是BufferLayer中的實現:
* frameworks/native/services/surfaceflinger/BufferLayer.cpp
void BufferLayer::onFrameAvailable(const BufferItem& item) {
// Add this buffer from our internal queue tracker
{ // Autolock scope
Mutex::Autolock lock(mQueueItemLock);
mFlinger->mInterceptor.saveBufferUpdate(this, item.mGraphicBuffer->getWidth(),
item.mGraphicBuffer->getHeight(),
item.mFrameNumber);
// Reset the frame number tracker when we receive the first buffer after
// a frame number reset
if (item.mFrameNumber == 1) {
mLastFrameNumberReceived = 0;
}
// Ensure that callbacks are handled in order
while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
ms2ns(500));
if (result != NO_ERROR) {
ALOGE("[%s] Timed out waiting on callback", mName.string());
}
}
mQueueItems.push_back(item);
android_atomic_inc(&mQueuedFrames);
// Wake up any pending callbacks
mLastFrameNumberReceived = item.mFrameNumber;
mQueueItemCondition.broadcast();
}
mFlinger->signalLayerUpdate();
}
BufferLayer中調用onFrameAvailable,去通知SurfaceFlinger進行合成。
到這裏,應用端(Producer)生產完Buffer這件事,就通知到了SurfaceFlinger中了。
SurfaceFlinger的signalLayerUpdate,是通過MessageQueue來處理的,我們先來看看MessageQueue。
二、消息隊列MessageQueue
MessageQueue是SurfaceFlinger中的消息隊列,爲什麼需要消息隊列?我們應用有一個主線程,專門進行UI的處理。SurfaceFlinger同樣的,也有一個主線程,SurfaceFlinger的主線程主要進行顯示數據的處理,也就是合成。
SurfaceFlinger中,mEventQueue是MessageQueue的一個棧對象,採用mutable修飾。SurfaceFlinger在初次引用時,會對mEventQueue進行初始化。
* frameworks/native/services/surfaceflinger/MessageQueue.cpp
void MessageQueue::init(const sp<SurfaceFlinger>& flinger)
{
mFlinger = flinger;
mLooper = new Looper(true);
mHandler = new Handler(*this);
}
MessageQueue初始化時,創建了一個Looper和一個Handler。
此外,在SurfaceFlinger初始化時,創建了一個EventThread,並傳給了MessageQueue。
void SurfaceFlinger::init() {
... ...
sp<VSyncSource> sfVsyncSrc =
new DispSyncSource(&mPrimaryDispSync, SurfaceFlinger::sfVsyncPhaseOffsetNs, true, "sf");
mSFEventThread = new EventThread(sfVsyncSrc, *this, true);
mEventQueue.setEventThread(mSFEventThread);
MessageQueue的setEventThread函數如下:
void MessageQueue::setEventThread(const sp<EventThread>& eventThread)
{
if (mEventThread == eventThread) {
return;
}
if (mEventTube.getFd() >= 0) {
mLooper->removeFd(mEventTube.getFd());
}
mEventThread = eventThread;
mEvents = eventThread->createEventConnection();
mEvents->stealReceiveChannel(&mEventTube);
mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT,
MessageQueue::cb_eventReceiver, this);
}
MessageQueue在setEventThread時,主要做以下幾件事:
創建一個BitTube對象mEventTube
創建一個EventConnection
sp<EventThread::Connection> EventThread::createEventConnection() const {
return new Connection(const_cast<EventThread*>(this));
}
Connection在第一次引用時,將會被註冊到mEventThread中。
void EventThread::Connection::onFirstRef() {
// NOTE: mEventThread doesn't hold a strong reference on us
mEventThread->registerDisplayEventConnection(this);
}
在註冊時,Connection將會被添加到mDisplayEventConnections 中。
status_t EventThread::registerDisplayEventConnection(
const sp<EventThread::Connection>& connection) {
Mutex::Autolock _l(mLock);
mDisplayEventConnections.add(connection);
mCondition.broadcast();
return NO_ERROR;
}
mDisplayEventConnections是一個已經註冊的Connection的集合。
- 將mEventTube和EventConnection關聯
status_t EventThread::Connection::stealReceiveChannel(gui::BitTube* outChannel) {
outChannel->setReceiveFd(mChannel.moveReceiveFd());
return NO_ERROR;
}
Connection創建時,將默認創建一個4k的BitTube,BitTube封裝的是一對socket,一個發送,一個接收,可傳輸的Buffer大小爲4K。
void BitTube::init(size_t rcvbuf, size_t sndbuf) {
int sockets[2];
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) == 0) {
size_t size = DEFAULT_SOCKET_BUFFER_SIZE;
setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf));
setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf));
// since we don't use the "return channel", we keep it small...
setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
fcntl(sockets[0], F_SETFL, O_NONBLOCK);
fcntl(sockets[1], F_SETFL, O_NONBLOCK);
mReceiveFd.reset(sockets[0]);
mSendFd.reset(sockets[1]);
} else {
mReceiveFd.reset();
ALOGE("BitTube: pipe creation failed (%s)", strerror(errno));
}
}
MessageQueue中的mEventTube,和mReceiveFd關聯。
- addFd函數,將fd添加到MessageQueue的Looper中。
注意,Looper的callback爲MessageQueue::cb_eventReceiver
,data爲MessageQueue本身。
int MessageQueue::cb_eventReceiver(int fd, int events, void* data) {
MessageQueue* queue = reinterpret_cast<MessageQueue *>(data);
return queue->eventReceiver(fd, events);
}
回到SurfaceFlinger的signalLayerUpdate函數:
void SurfaceFlinger::signalLayerUpdate() {
mEventQueue.invalidate();
}
signalLayerUpdate中,調用MQ的invalidate。
void MessageQueue::invalidate() {
mEvents->requestNextVsync();
}
MQ的invalidate的函數,將請求下一個Vsync。Vsync是一種同步機制,垂直同步,我們可以理解爲SurfaceFlinger的工作節拍。
void EventThread::requestNextVsync(
const sp<EventThread::Connection>& connection) {
Mutex::Autolock _l(mLock);
mFlinger.resyncWithRateLimit();
if (connection->count < 0) {
connection->count = 0;
mCondition.broadcast();
}
}
注意這裏的count >= 0。
EventThread就是一個事件分發的線程,第一次引用時,線程啓動。
void EventThread::onFirstRef() {
run("EventThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
}
EventThread的threadLoop函數體如下:
bool EventThread::threadLoop() {
DisplayEventReceiver::Event event;
Vector< sp<EventThread::Connection> > signalConnections;
signalConnections = waitForEvent(&event);
// dispatch events to listeners...
const size_t count = signalConnections.size();
for (size_t i=0 ; i<count ; i++) {
const sp<Connection>& conn(signalConnections[i]);
// now see if we still need to report this event
status_t err = conn->postEvent(event);
if (err == -EAGAIN || err == -EWOULDBLOCK) {
... ...
ALOGW("EventThread: dropping event (%08x) for connection %p",
event.header.type, conn.get());
} else if (err < 0) {
removeDisplayEventConnection(signalConnections[i]);
}
}
return true;
}
waitForEvent,等待事件Event。看看哪些Connection是被觸發的,對於被觸發的Connection,signalConnections,通過postEvent將事件Event分發出去。
Event這邊的控制邏輯,基本都在waitForEvent中。waitForEvent中,採用while循環,條件是signalConnections爲空。EventThread中主要控制兩事件,Vsync事件和顯示屏的HotPlug熱插拔事件
enum {
DISPLAY_EVENT_VSYNC = fourcc('v', 's', 'y', 'n'),
DISPLAY_EVENT_HOTPLUG = fourcc('p', 'l', 'u', 'g'),
};
我們分段來看:
Vector< sp<EventThread::Connection> > EventThread::waitForEvent(
DisplayEventReceiver::Event* event)
{
Mutex::Autolock _l(mLock);
Vector< sp<EventThread::Connection> > signalConnections;
do {
bool eventPending = false;
bool waitForVSync = false;
size_t vsyncCount = 0;
nsecs_t timestamp = 0;
for (int32_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
timestamp = mVSyncEvent[i].header.timestamp;
if (timestamp) {
// 有一個Vsync事件要分發
if (mInterceptVSyncs) {
mFlinger.mInterceptor.saveVSyncEvent(timestamp);
}
*event = mVSyncEvent[i];
mVSyncEvent[i].header.timestamp = 0;
vsyncCount = mVSyncEvent[i].vsync.count;
break;
}
}
看看有沒有Vsync事件要分發,timestamp不爲0,表示有Vync事件要分發。
if (!timestamp) {
// no vsync event, see if there are some other event
eventPending = !mPendingEvents.isEmpty();
if (eventPending) {
// we have some other event to dispatch
*event = mPendingEvents[0];
mPendingEvents.removeAt(0);
}
}
mPendingEvents,這裏主要是是HotPlug事件。
找出在等待事件的Connection:
size_t count = mDisplayEventConnections.size();
for (size_t i=0 ; i<count ; ) {
sp<Connection> connection(mDisplayEventConnections[i].promote());
if (connection != NULL) {
bool added = false;
if (connection->count >= 0) {
// 需要Vsync,至少有一個Connection的count >= 0。
waitForVSync = true;
if (timestamp) {
// we consume the event only if it's time
// (ie: we received a vsync event)
if (connection->count == 0) {
// fired this time around
connection->count = -1;
signalConnections.add(connection);
added = true;
} else if (connection->count == 1 ||
(vsyncCount % connection->count) == 0) {
// continuous event, and time to report it
signalConnections.add(connection);
added = true;
}
}
}
if (eventPending && !timestamp && !added) {
// 沒有Vsync事件要處理,但是有其他的事件要處理
signalConnections.add(connection);
}
++i;
} else {
// Connection不存在了
mDisplayEventConnections.removeAt(i);
--count;
}
}
Connection的count >= 0表示需要Vsync。eventPending && !timestamp && !added
表示沒有Vsync事件要處理,但是有其他的事件要處理。
if (timestamp && !waitForVSync) {
disableVSyncLocked();
} else if (!timestamp && waitForVSync) {
enableVSyncLocked();
}
timestamp && !waitForVSync
如果有Vsync事件要分發,但是又沒有Connection需要Vsync事件時,把Vsync給關掉。相反,如果有Connection需要Vsync,而此時又沒有Vsync事件時,需要將Vsync打開。
if (!timestamp && !eventPending) {
if (waitForVSync) {
bool softwareSync = mUseSoftwareVSync;
nsecs_t timeout = softwareSync ? ms2ns(16) : ms2ns(1000);
if (mCondition.waitRelative(mLock, timeout) == TIMED_OUT) {
if (!softwareSync) {
ALOGW("Timed out waiting for hw vsync; faking it");
}
// FIXME: how do we decide which display id the fake
// vsync came from ?
mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
mVSyncEvent[0].header.id = DisplayDevice::DISPLAY_PRIMARY;
mVSyncEvent[0].header.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
mVSyncEvent[0].vsync.count++;
}
} else {
mCondition.wait(mLock);
}
}
} while (signalConnections.isEmpty());
return signalConnections;
}
如果此時沒有Vsync事件,或其他的Event事件,那就處於等待中。如果是等待Vsync,那麼通過mCondition.waitRelative
進行等待,如果是硬件Vsync還不能用或者出現問題時,設置一個超時時間,進行屏幕的喚醒。
如果Connection需要Vsync,那麼就進程sleep。
Vsync事件到來時,將回調到onVSyncEvent:
void EventThread::onVSyncEvent(nsecs_t timestamp) {
Mutex::Autolock _l(mLock);
mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
mVSyncEvent[0].header.id = 0;
mVSyncEvent[0].header.timestamp = timestamp;
mVSyncEvent[0].vsync.count++;
mCondition.broadcast();
}
Hotplug事件到來時,將回調到onHotplugReceived:
void EventThread::onHotplugReceived(int type, bool connected) {
ALOGE_IF(type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES,
"received hotplug event for an invalid display (id=%d)", type);
Mutex::Autolock _l(mLock);
if (type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
DisplayEventReceiver::Event event;
event.header.type = DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG;
event.header.id = type;
event.header.timestamp = systemTime();
event.hotplug.connected = connected;
mPendingEvents.add(event);
mCondition.broadcast();
}
}
注意,Event事件哪兒回調回來的我們先不管,我們先記住這裏的邏輯。
Vsync事件是跟屏幕的刷新頻率有關,比如60Hz的屏幕,兩個Vsync事件間的時間爲1/60s,也就是16.67ms左右。SurfaceFlinger每隔16.67ms進行一次合成,顯示。
另外,需要注意的是,SurfaceFlinger和App的EventThread是分開的,不是同一個。
void SurfaceFlinger::init() {
... ...
// start the EventThread
sp<VSyncSource> vsyncSrc =
new DispSyncSource(&mPrimaryDispSync, SurfaceFlinger::vsyncPhaseOffsetNs, true, "app");
mEventThread = new EventThread(vsyncSrc, *this, false);
sp<VSyncSource> sfVsyncSrc =
new DispSyncSource(&mPrimaryDispSync, SurfaceFlinger::sfVsyncPhaseOffsetNs, true, "sf");
mSFEventThread = new EventThread(sfVsyncSrc, *this, true);
mEventQueue.setEventThread(mSFEventThread);
回到MessageQueue,Connection通過postEvent將Event拋出來後,通過sendEvents將事件發出去。
status_t EventThread::Connection::postEvent(
const DisplayEventReceiver::Event& event) {
ssize_t size = DisplayEventReceiver::sendEvents(&mChannel, &event, 1);
return size < 0 ? status_t(size) : status_t(NO_ERROR);
}
DisplayEventReceiver中是通過BitTube將事件發出去,sendObjects注意這裏的參數。
ssize_t DisplayEventReceiver::sendEvents(gui::BitTube* dataChannel,
Event const* events, size_t count)
{
return gui::BitTube::sendObjects(dataChannel, events, count);
}
數據是什麼地方接受的呢?回到SurfaceFlinger
SurfaceFlinger線程run時,啓動一個死循環,循環等待事件。
void SurfaceFlinger::run() {
do {
waitForEvent();
} while (true);
}
waitForEvent中,調用MessageQueue的waitMessage函數:
void MessageQueue::waitMessage() {
do {
IPCThreadState::self()->flushCommands();
int32_t ret = mLooper->pollOnce(-1);
switch (ret) {
case Looper::POLL_WAKE:
case Looper::POLL_CALLBACK:
continue;
case Looper::POLL_ERROR:
ALOGE("Looper::POLL_ERROR");
continue;
case Looper::POLL_TIMEOUT:
// timeout (should not happen)
continue;
default:
// should not happen
ALOGE("Looper::pollOnce() returned unknown status %d", ret);
continue;
}
} while (true);
}
waitMessage,通過採用一個死循環,處理Looper的pollOnce。Looper內部的邏輯就不看了,主要是採用epoll_wait對fd進行監聽,BitTube發送Event對象後,epoll_wait結束,調用callback,處理事件
int callbackResult = response.request.callback->handleEvent(fd, events, data);
MessageQueue對應的callback爲cb_eventReceiver:
int MessageQueue::cb_eventReceiver(int fd, int events, void* data) {
MessageQueue* queue = reinterpret_cast<MessageQueue *>(data);
return queue->eventReceiver(fd, events);
}
eventReceiver,處理事件:
int MessageQueue::eventReceiver(int /*fd*/, int /*events*/) {
ssize_t n;
DisplayEventReceiver::Event buffer[8];
while ((n = DisplayEventReceiver::getEvents(&mEventTube, buffer, 8)) > 0) {
for (int i=0 ; i<n ; i++) {
if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
mHandler->dispatchInvalidate();
break;
}
}
}
return 1;
}
dispatchInvalidate,封裝爲MessageQueue::INVALIDATE
void MessageQueue::Handler::dispatchInvalidate() {
if ((android_atomic_or(eventMaskInvalidate, &mEventMask) & eventMaskInvalidate) == 0) {
mQueue.mLooper->sendMessage(this, Message(MessageQueue::INVALIDATE));
}
}
MessageQueue中,兩種Message,INVALIDATE和REFRESH:
enum {
INVALIDATE = 0,
REFRESH = 1,
};
Message的分發略過,Handler對Message的處理如下:
void MessageQueue::Handler::handleMessage(const Message& message) {
switch (message.what) {
case INVALIDATE:
android_atomic_and(~eventMaskInvalidate, &mEventMask);
mQueue.mFlinger->onMessageReceived(message.what);
break;
case REFRESH:
android_atomic_and(~eventMaskRefresh, &mEventMask);
mQueue.mFlinger->onMessageReceived(message.what);
break;
}
}
收到消息後,再調回SurfaceFlinger在onMessageReceived中處理。
再看SurfaceFlinger的處理之前,我們先稍微整理一下MessageQueue,MessageQueue的類圖如下:
三、顯示設備DispalyDevice
SurfaceFlinger中,每個顯示屏我們用DisplayDevice進行描述,它除了描述了Display的信息,還包括很多和合成相關的邏輯。相比於native層,Display信息是在Android的Framework層管理的,提供了專門的服務DisplayManagerService(DMS),DMS後續再介紹。
3.1 Display接口服務
。從Android 8.0開始,Vsync和hotplug的接收接口IDisplayEventReceiver作爲一個單獨的庫從SurfaceFlinger中獨立出來,設計爲3層模式,JAVA層,Native層和HAL層。編譯爲libdisplayservicehidl庫,代碼在如下位置:
frameworks/native/services/displayservice
Display 接口 Android.bp如下:
cc_library_shared {
name: "libdisplayservicehidl",
srcs: [
"DisplayService.cpp",
"DisplayEventReceiver.cpp",
],
shared_libs: [
"libbase",
"liblog",
"libgui",
"libhidlbase",
"libhidltransport",
"libutils",
"[email protected]",
],
export_include_dirs: ["include"],
export_shared_lib_headers: [
"[email protected]",
"libgui",
"libutils",
],
cflags: [
"-Werror",
"-Wall",
]
}
hal層也抽象出Display的單獨模塊displayservice。代碼爲在:
frameworks/hardware/interfaces/displayservice
displayservice的Android.bp如下:
hidl_interface {
name: "[email protected]",
root: "android.frameworks",
vndk: {
enabled: true,
},
srcs: [
"types.hal",
"IDisplayEventReceiver.hal",
"IDisplayService.hal",
"IEventCallback.hal",
],
interfaces: [
"[email protected]",
],
types: [
"Status",
],
gen_java: true,
}
displayservice還比較簡單,沒有太多接口:
- types中只定義了一個狀態
* frameworks/hardware/interfaces/displayservice/1.0/types.hal
package [email protected];
enum Status : uint32_t {
SUCCESS,
BAD_VALUE,
UNKNOWN,
};
- IDisplayEventReceiver.hal中定義了Receiver的接口
package [email protected];
import IEventCallback;
interface IDisplayEventReceiver {
/**
* 添加callback,開始接收Events事件,熱插拔是默認打開的,Vysnc需要通過setVsyncRate打開
*/
init(IEventCallback callback) generates (Status status);
/**
* 開始或停止發送callback
*/
setVsyncRate(int32_t count) generates (Status status);
/**
* 請求一個Vsync,如果setVsyncRate是0,這不起作用
*/
requestNextVsync() generates (Status status);
/**
* Server端丟棄所以的callback,停止發送
*/
close() generates (Status status);
};
- IDisplayService.hal
package [email protected];
import IDisplayEventReceiver;
interface IDisplayService {
/**
* 創建新的receiver.
*/
getEventReceiver() generates(IDisplayEventReceiver receiver);
};
- IEventCallback.hal
package [email protected];
interface IEventCallback {
/**
* Vsync事件
*/
oneway onVsync(uint64_t timestamp, uint32_t count);
/**
* hotplug事件
*/
oneway onHotplug(uint64_t timestamp, bool connected);
};
displayservice的接口,主要是提供給Vendor的HAL使用,讓Vendor的HAL也能夠接收Vsync數據。libdisplayservicehidl中也主要是DisplayEventReceiver。所以,這裏的IDisplayEventReceiver接口 這麼設計的 主要是提供給Vendor用。
3.2 顯示屏的類型
顯示屏幕什麼時候創建?各類型的顯示屏不一樣,Android支持3中類型的顯示屏:主顯,外顯,虛顯。
* frameworks/native/services/surfaceflinger/DisplayDevice.h
enum DisplayType {
DISPLAY_ID_INVALID = -1,
DISPLAY_PRIMARY = HWC_DISPLAY_PRIMARY,
DISPLAY_EXTERNAL = HWC_DISPLAY_EXTERNAL,
DISPLAY_VIRTUAL = HWC_DISPLAY_VIRTUAL,
NUM_BUILTIN_DISPLAY_TYPES = HWC_NUM_PHYSICAL_DISPLAY_TYPES,
};
主顯示屏幕和外顯,都採用熱插拔的形式,連接,斷開時從底層驅動上報熱插拔事件,這是在EventThread中處理的。
主顯示屏 DISPLAY_PRIMARY
主顯示屏幕默認是必現支持的,也就是說,開機時就應該上報 * 連接* 事件,知道屏幕關閉時,才斷開。這裏說的屏幕關閉是真正的關閉,休眠,鎖屏等狀態屏幕還是開着的。基本也就是關機的時候。外顯示屏 DISPLAY_EXTERNAL
外顯示屏幕,一般是有線連接的屏幕,比如HDMI,MHL或者是其他連接標準連接的屏幕,外顯一般經常進行熱插拔。虛擬顯示屏 DISPLAY_VIRTUAL
虛擬顯示屏,也就是說這個顯示屏是不存在物理設備的,是個虛擬的。
我們先看看DisplayDevice相關類之間的關係:
我們可以這麼來理解:
- Android支持多個顯示屏幕,每一個顯示屏幕用DisplayDevice進行描述,SurfaceFlinger中有這些顯示屏的信息即mDisplay
- 每個顯示屏幕,都一個相關聯的Buffer,這個Buffer用 DisplaySurface進行描述。
- 每種類型的顯示屏,具體採用的Buffer不盡相同,主屏和外顯採用FramebufferSurface,而虛擬顯示屏採用VirtualDisplaySurface。
- DisplaySurface有自己的BufferQueue,都繼承ConsumerBase,所以這裏DisplaySurface比較特殊,都是消費者。VirtualDisplaySurface更猛,它還繼承BnGraphicBufferProducer,也是生產者。
- RE_Surface是RE命名空間的Surface,和BufferQueue中的Surface同名,但是作用不一樣。主要是給RenderEngine用,RenderEngine是一個抽象類,渲染引擎,用於Client端的合成,一般用OpenGL進程合成。
3.3 DisplayDevice的熱插拔處理
SurfaceFlinger在初始化的時候,註冊Callback接口後。顯示屏幕插上和斷開時,將通過HAL回調回來。HAL回調的過程先不關注,從SurfaceFlinger中開始看。
void SurfaceFlinger::onHotplugReceived(int32_t sequenceId,
hwc2_display_t display, HWC2::Connection connection,
bool primaryDisplay) {
ALOGV("onHotplugReceived(%d, %" PRIu64 ", %s, %s)",
sequenceId, display,
connection == HWC2::Connection::Connected ?
"connected" : "disconnected",
primaryDisplay ? "primary" : "external");
ConditionalLock lock(mStateLock,
std::this_thread::get_id() != mMainThreadId);
if (primaryDisplay) {
getBE().mHwc->onHotplug(display, connection);
if (!mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY].get()) {
createBuiltinDisplayLocked(DisplayDevice::DISPLAY_PRIMARY);
}
createDefaultDisplayDevice();
} else {
if (sequenceId != getBE().mComposerSequenceId) {
return;
}
if (getBE().mHwc->isUsingVrComposer()) {
ALOGE("External displays are not supported by the vr hardware composer.");
return;
}
getBE().mHwc->onHotplug(display, connection);
auto type = DisplayDevice::DISPLAY_EXTERNAL;
if (connection == HWC2::Connection::Connected) {
createBuiltinDisplayLocked(type);
} else {
mCurrentState.displays.removeItem(mBuiltinDisplays[type]);
mBuiltinDisplays[type].clear();
}
setTransactionFlags(eDisplayTransactionNeeded);
}
}
接收到屏幕插拔事件後,主要做了如下的處理:
- 通知HWC onHotplug
通過onHotplug通知HWC;如果是連接,HWC將去獲取新添加Display的config信息,如果是斷開,將HWC中的Display同步斷開。
-
創建Display的Token
createBuiltinDisplayLocked如果是連接狀態,都將通過createBuiltinDisplayLocked創建Display的Token。添加到mBuiltinDisplays中,mBuiltinDisplays它只是Display的IBinder列表,我們也稱之爲Token列表。
sp<IBinder> mBuiltinDisplays[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES];
這個時候還沒有創建DisplayDevice,只是創建了一個Token而已。Display的Token通知添加到mCurrentState的displays中。
- 創建主屏幕對應的DisplayDevice
如果是主屏,還會通過createDefaultDisplayDevice創建默認的DisplayDevice。
void SurfaceFlinger::createDefaultDisplayDevice() {
const DisplayDevice::DisplayType type = DisplayDevice::DISPLAY_PRIMARY;
wp<IBinder> token = mBuiltinDisplays[type];
// All non-virtual displays are currently considered secure.
const bool isSecure = true;
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer);
sp<FramebufferSurface> fbs = new FramebufferSurface(*getBE().mHwc, type, consumer);
bool hasWideColorModes = false;
std::vector<android_color_mode_t> modes = getHwComposer().getColorModes(type);
for (android_color_mode_t colorMode : modes) {
switch (colorMode) {
case HAL_COLOR_MODE_DISPLAY_P3:
case HAL_COLOR_MODE_ADOBE_RGB:
case HAL_COLOR_MODE_DCI_P3:
hasWideColorModes = true;
break;
default:
break;
}
}
bool useWideColorMode = hasWideColorModes && hasWideColorDisplay && !mForceNativeColorMode;
sp<DisplayDevice> hw = new DisplayDevice(this, DisplayDevice::DISPLAY_PRIMARY, type, isSecure,
token, fbs, producer, useWideColorMode);
mDisplays.add(token, hw);
android_color_mode defaultColorMode = HAL_COLOR_MODE_NATIVE;
if (useWideColorMode) {
defaultColorMode = HAL_COLOR_MODE_SRGB;
}
setActiveColorModeInternal(hw, defaultColorMode);
hw->setCompositionDataSpace(HAL_DATASPACE_UNKNOWN);
// Add the primary display token to mDrawingState so we don't try to
// recreate the DisplayDevice for the primary display.
mDrawingState.displays.add(token, DisplayDeviceState(type, true));
// make the GLContext current so that we can create textures when creating
// Layers (which may happens before we render something)
hw->makeCurrent();
}
- 看到沒有,主Display的BufferQueue是就是此時創建的。並且創建了前面所說的FramebufferSurface,這就是FBTarget。
- DisplayDevice對應的類型爲DISPLAY_PRIMARY,創建了DisplayDevice後,添加到mDisplays中。而Display的Token被添加到mDrawingState的displays中,注意,是mDrawingState。
- 這裏還有顏色模式Colormode和數據空間DataSpace的設置,這兩個概念後續介紹。
- 最後,調用makeCurrent,表示該DisplayDevice進入可用狀態
bool DisplayDevice::makeCurrent() const {
bool success = mFlinger->getRenderEngine().setCurrentSurface(mSurface);
setViewportAndProjection();
return success;
}
makeCurrent主要做了兩件事:其一,設置RenderEngine的Surface,這個Surface封裝了前面BufferQueue中創建的Producer,以及對應的NativeWindow;其二,設置Display的Viewport和Projection,做過OpengGL開發的,對這個應該沒有什麼難題,視窗大小和投影矩陣。也是設置到RenderEngine中,GPU合成用。
非主屏刪除處理
非主屏時刪除時,將Display的Token從mBuiltinDisplays中刪掉,且Token也從mCurrentState中刪掉。注意,這裏的是mCurrentState。主屏一般只會添加一次,沒有斷開操縱,斷開時系統已經關了。Transaction處理
連接或斷開顯示屏,也算是一種Transaction。通過setTransactionFlags
,設置處理的flag eDisplayTransactionNeeded。
到此,連接時,主顯的Token是添加到mDrawingState中的,已經創建對應的DisplayDevice,且沒有斷開處理。而非主顯只創建了Display的Token,添加到這裏的是mCurrentState中,還沒有創建對應的DisplayDevice,斷開的屏幕,Token從mCurrentState刪除。簡單點來說,mDrawingState中的Token都創建了DisplayDevice;在mCurrentState中的不再mDrawingState中的,都是添加的;在mDrawingState中的,不在mCurrentState中的都是斷開的。
3.4 創建DisplayDevice
上面設置的setTransactionFlags什麼時候處理?Vsync來的時候,Vsync來後,通過INVALIDATE消息,又回到SurfaceFlinger處理。中間的過程稍後介紹,我們直接看對這裏設置的eDisplayTransactionNeeded的處理流程。
處理eDisplayTransactionNeeded時,其實就是同步 mDrawingState 和 mCurrentState 中displays。
-
屏幕斷開時的處理
先處理刪除的Display,屏幕的Token在mDrawingState中的,不在mCurrentState中的都是斷開的。邏輯如下:
void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
{
``` ```
if (transactionFlags & eDisplayTransactionNeeded) {
const KeyedVector< wp<IBinder>, DisplayDeviceState>& curr(mCurrentState.displays);
const KeyedVector< wp<IBinder>, DisplayDeviceState>& draw(mDrawingState.displays);
if (!curr.isIdenticalTo(draw)) {
mVisibleRegionsDirty = true;
const size_t cc = curr.size();
size_t dc = draw.size();
for (size_t i=0 ; i<dc ;) {
const ssize_t j = curr.indexOfKey(draw.keyAt(i));
if (j < 0) {
if (!draw[i].isMainDisplay()) {
const sp<const DisplayDevice> defaultDisplay(getDefaultDisplayDeviceLocked());
defaultDisplay->makeCurrent();
sp<DisplayDevice> hw(getDisplayDeviceLocked(draw.keyAt(i)));
if (hw != NULL)
hw->disconnect(getHwComposer());
if (draw[i].type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES)
mEventThread->onHotplugReceived(draw[i].type, false);
mDisplays.removeItem(draw.keyAt(i));
} else {
ALOGW("trying to remove the main display");
}
} else {
// this display is in both lists. see if something changed.
const DisplayDeviceState& state(curr[j]);
const wp<IBinder>& display(curr.keyAt(j));
const sp<IBinder> state_binder = IInterface::asBinder(state.surface);
const sp<IBinder> draw_binder = IInterface::asBinder(draw[i].surface);
if (state_binder != draw_binder) {
sp<DisplayDevice> hw(getDisplayDeviceLocked(display));
if (hw != NULL)
hw->disconnect(getHwComposer());
mDisplays.removeItem(display);
mDrawingState.displays.removeItemsAt(i);
dc--;
// at this point we must loop to the next item
continue;
}
const sp<DisplayDevice> disp(getDisplayDeviceLocked(display));
if (disp != NULL) {
if (state.layerStack != draw[i].layerStack) {
disp->setLayerStack(state.layerStack);
}
if ((state.orientation != draw[i].orientation)
|| (state.viewport != draw[i].viewport)
|| (state.frame != draw[i].frame))
{
disp->setProjection(state.orientation,
state.viewport, state.frame);
}
if (state.width != draw[i].width || state.height != draw[i].height) {
disp->setDisplaySize(state.width, state.height);
}
}
}
++i;
}
如果Token在mDrawingState中,而沒有在mCurrentState中,說明這個屏已經被斷開了,需要刪掉DisplayDevice。如果Token在兩個狀態中都存在,有修改,暫時將Token中mDrawingState刪掉。注意兩個狀態啊,要不然理解不對。
斷開時,調用DisplayDevice的disconnect,這其中將調用HWC中,HWC中創建的對應的Device也將被刪除。同時將DisplayDevice從mDisplays中刪除。
-
處理添加的Display
屏幕的Token在mCurrentState中的不再mDrawingState中的,都是添加的;處理邏輯如下。
void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
{
``` ```
for (size_t i=0 ; i<cc ; i++) {
if (draw.indexOfKey(curr.keyAt(i)) < 0) {
const DisplayDeviceState& state(curr[i]);
sp<DisplaySurface> dispSurface;
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferProducer> bqProducer;
sp<IGraphicBufferConsumer> bqConsumer;
BufferQueue::createBufferQueue(&bqProducer, &bqConsumer);
int32_t hwcId = -1;
if (state.isVirtualDisplay()) {
// Virtual displays without a surface are dormant:
// they have external state (layer stack, projection,
// etc.) but no internal state (i.e. a DisplayDevice).
if (state.surface != NULL) {
// 虛擬顯示用硬件
... ...
sp<VirtualDisplaySurface> vds =
new VirtualDisplaySurface(*getBE().mHwc,
hwcId, state.surface, bqProducer,
bqConsumer, state.displayName);
dispSurface = vds;
producer = vds;
}
} else {
ALOGE_IF(state.surface!=NULL,
"adding a supported display, but rendering "
"surface is provided (%p), ignoring it",
state.surface.get());
hwcId = state.type;
dispSurface = new FramebufferSurface(*getBE().mHwc, hwcId, bqConsumer);
producer = bqProducer;
}
const wp<IBinder>& display(curr.keyAt(i));
if (dispSurface != NULL) {
sp<DisplayDevice> hw =
new DisplayDevice(this, state.type, hwcId, state.isSecure, display,
dispSurface, producer, hasWideColorDisplay);
hw->setLayerStack(state.layerStack);
hw->setProjection(state.orientation,
state.viewport, state.frame);
hw->setDisplayName(state.displayName);
mDisplays.add(display, hw);
if (!state.isVirtualDisplay()) {
mEventThread->onHotplugReceived(state.type, true);
}
}
}
}
}
}
... ...
添加屏幕時,根據前面已經創建的BufferQueue,創建對應的DisplaySurface,外顯和虛顯的不一樣。創建DisplaySurface後,再創建DisplayDevice;設置DisplayDevice的stack,投影矩陣Projection;將創建的DisplayDevice添加到mDisplays中;最後,對外顯,調用EventThread的onHotplugReceived。
EventThread的onHotplugReceived函數中,將封裝一個hotplug的Event事件DISPLAY_EVENT_HOTPLUG,EventThread再將事件分發出去。這裏對hotplug感興趣的主要就是框架層了,回調給DisplayManagerService。
3.5 hotplug的流程
這裏主要將了Display相關的邏輯,主要是熱插拔的處理。下面是整個Android系統添加屏幕時的處理流程。
Display相關的就介紹到這裏,後續講合成時,還會有很多相關的流程。
作者:夕月風
鏈接:https://www.jianshu.com/p/fa115146949f
至此,本篇已結束。轉載網絡的文章,小編覺得很優秀,歡迎點擊閱讀原文,支持原創作者,如有侵權,懇請聯繫小編刪除,歡迎您的建議與指正。同時期待您的關注,感謝您的閱讀,謝謝!