基于Android5.1的双屏异显分析
平臺:android5.1?
場景:客戶的設(shè)備需要使用到雙屏異顯。分析雙屏異顯時(shí),framework所做的準(zhǔn)備。?
時(shí)間:2016.9.28
Android從4.2開始支持雙屏異顯,其Java使用示例代碼如下:
1.如何獲取設(shè)備上的屏幕?
DisplayManager mDisplayManager;//屏幕管理類Display[] displays;//屏幕數(shù)組mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);displays =mDisplayManager.getDisplays();2.主屏和副屏的區(qū)分??
主屏:displays[0]?
副屏:displays[1]
3.如何在副屏上展示內(nèi)容??
通過Presentation來實(shí)現(xiàn),Presentation繼承了Dialog。?
假設(shè)我們寫了一個(gè)DifferentDislay的類,這個(gè)類是要繼承Presentation類:
4.開啟副屏
DifferentDislay mPresentation =new DifferentDislay (context,displays[1]);//displays[1]是副屏mPresentation.getWindow().setType(WindowManager.LayoutParams.TYPE_TOAST);mPresentation.show();以上代碼的核心在于Presentation類,其繼承與Dialog。?
從new DifferentDislay (context,displays[1]) 函數(shù)分析其初始化:
上面代碼的設(shè)計(jì)原則:?
每一個(gè)display擁有自己的管理對象以及context對象,這樣雙屏的操作互相獨(dú)立—Display是核心對象。對于上層而言,其即意味著一個(gè)屏幕。?
mPresentation.show()拉開了雙屏異顯的序幕。結(jié)合上面的分析,WindowManagerImpl.java中的addView()方法將傳入上面初始化的display[1],繼而:
接下來開始進(jìn)入到主題,framework為支持雙屏異顯做了哪些工作??
兩個(gè)重點(diǎn):?
1.檢測到雙屏(第二個(gè)屏)后,系統(tǒng)做了哪些準(zhǔn)備?(主屏幕和HDMI是兩個(gè)默認(rèn)開機(jī)就進(jìn)行檢測的屏幕設(shè)備,其他監(jiān)聽后使用hotplug處理)?
2.如何進(jìn)行/區(qū)分雙屏異顯?
上面提到Android4.2開始支持雙屏異顯,除了引入Presentation 類,其還定制了HWComposer,其構(gòu)造函數(shù)中:
if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))mCBContext->procs.hotplug = &hook_hotplug;elsemCBContext->procs.hotplug = NULL;即HWC的版本大于等于1.1即可支持雙屏異顯。我們從hook_hotplug開始查看檢測到插入新屏?xí)r的系統(tǒng)
HWComposer.cpp void HWComposer::hotplug(int disp, int connected)SurfaceFlinger.cpp void SurfaceFlinger::onHotplugReceived(int type, bool connected) //NUM_BUILTIN_DISPLAY_TYPES = HWC_NUM_PHYSICAL_DISPLAY_TYPES//默認(rèn)為2。當(dāng)type小于2時(shí),才會繼續(xù)執(zhí)行。即默認(rèn)最多支持兩個(gè)屏。此處的type標(biāo)示著屏幕類型,如下所示:enum DisplayType {DISPLAY_ID_INVALID = -1,DISPLAY_PRIMARY = HWC_DISPLAY_PRIMARY, //0,默認(rèn)屏幕DISPLAY_EXTERNAL = HWC_DISPLAY_EXTERNAL, //1,第二屏DISPLAY_VIRTUAL = HWC_DISPLAY_VIRTUAL, //虛擬屏幕NUM_BUILTIN_DISPLAY_TYPES = HWC_NUM_PHYSICAL_DISPLAY_TYPES,};void SurfaceFlinger::createBuiltinDisplayLocked(DisplayDevice::DisplayType type){ALOGW_IF(mBuiltinDisplays[type],"Overwriting display token for display type %d", type);mBuiltinDisplays[type] = new BBinder();DisplayDeviceState info(type);// All non-virtual displays are currently considered secure.info.isSecure = true;mCurrentState.displays.add(mBuiltinDisplays[type], info); //保存到mCurrentState.displays,此處的info為DisplayDeviceState對象,mBuiltinDisplays[type]為IBinder對象。 } uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) void SurfaceFlinger::signalTransaction() MessageQueue.cpp void MessageQueue::invalidate() { #if INVALIDATE_ON_VSYNC //此宏為1mEvents->requestNextVsync(); #elsemHandler->dispatchInvalidate(); #endif }EventThread.cpp void EventThread::requestNextVsync( const sp<EventThread::Connection>& connection) //mCondition.broadcast()將掛起的線程喚起 Vector< sp<EventThread::Connection> > EventThread::waitForEvent( DisplayEventReceiver::Event* event) //此函數(shù)中的mDisplayEventConnections值得深究。其通過registerDisplayEventConnection()<<<EventThread::Connection::onFirstRef()<<<EventThread::createEventConnection()<<<(SurfaceFlinger::createDisplayEventConnection() <<<DisplayEventReceiver::DisplayEventReceiver())---這個(gè)是mEventThread對象的 | (MessageQueue::setEventThread()<<<SurfaceFlinger::init())---這個(gè)是mSFEventThread對象的在此構(gòu)造函數(shù)中創(chuàng)建了DisplayEventConnection SurfaceFlinger.cpp void SurfaceFlinger::onMessageReceived(int32_t what) void SurfaceFlinger::handleTransaction(uint32_t transactionFlags){ ...// Here we're guaranteed that some transaction flags are set// so we can call handleTransactionLocked() unconditionally.// We call getTransactionFlags(), which will also clear the flags,// with mStateLock held to guarantee that mCurrentState won't change// until the transaction is committed.transactionFlags = getTransactionFlags(eTransactionMask); //此函數(shù)作用?handleTransactionLocked(transactionFlags); //上面函數(shù)看上去是將transactionFlags清零 ...invalidateHwcGeometry(); } void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags){ ...if (transactionFlags & eDisplayTransactionNeeded) {// here we take advantage of Vector's copy-on-write semantics to// improve performance by skipping the transaction entirely when// know that the lists are identicalconst KeyedVector< wp<IBinder>, DisplayDeviceState>& curr(mCurrentState.displays);const KeyedVector< wp<IBinder>, DisplayDeviceState>& draw(mDrawingState.displays);...const size_t cc = curr.size();...// find displays that were added// (ie: in current state but not in drawing state)for (size_t i=0 ; i<cc ; i++) {...BufferQueue::createBufferQueue(&bqProducer, &bqConsumer, new GraphicBufferAlloc()); //為對應(yīng)的display創(chuàng)建新的BufferQueue...else {mEventThread->onHotplugReceived(state.type, true); //通知有新屏設(shè)備接入,mEventThread對象中的Connection需要先創(chuàng)建,即createEventConnection()函數(shù)需要先被執(zhí)行,以便后面利用Connection內(nèi)部對象mChannel來通信!---注意區(qū)分與mSFEventThread差別}}} ... } EventThread.cpp void EventThread::onHotplugReceived(int type, bool connected){ //此時(shí)type為1,即DISPLAY_EXTERNAL。connected為trueMutex::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); //插入event,將在waitForEvent()讀取mCondition.broadcast();} } Vector< sp<EventThread::Connection> > EventThread::waitForEvent(DisplayEventReceiver::Event* event){ ...if (!timestamp) {// no vsync event, see if there are some other eventeventPending = !mPendingEvents.isEmpty();if (eventPending) {// we have some other event to dispatch*event = mPendingEvents[0]; //取出上面插入的eventmPendingEvents.removeAt(0);}}// find out connections waiting for eventssize_t count = mDisplayEventConnections.size(); //此處對應(yīng)新display的connectcion已經(jīng)建立,如何建立???...if (eventPending && !timestamp && !added) {// we don't have a vsync event to process// (timestamp==0), but we have some pending// messages.signalConnections.add(connection);} ...if (!timestamp && !eventPending) { //此時(shí)eventPending為true,不會進(jìn)入此if進(jìn)行wait,同時(shí)signalConnections.add(),所以會退出while循環(huán)...}while (signalConnections.isEmpty()); ... } bool EventThread::threadLoop() status_t EventThread::Connection::postEvent( const DisplayEventReceiver::Event& event) //sendEvents()中的mChannel為new new BitTube(),此對象用于pipe通信。關(guān)注此時(shí)signalConnections[i]來源,其決定pipe通信的兩端。 BitTube.cpp ssize_t BitTube::sendObjects(const sp<BitTube>& tube, void const* events, size_t count, size_t objSize) //objSize為模板size ssize_t BitTube::write(void const* vaddr, size_t size){ //vaddr為event的地址,size為objSize*count ...len = ::send(mSendFd, vaddr, size, MSG_DONTWAIT | MSG_NOSIGNAL); //socket函數(shù)進(jìn)行pipe通信。BitTube的構(gòu)造函數(shù)中,調(diào)用init函數(shù),其調(diào)用socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)初始化了mReceiveFd和mSendFd ... }至此,將新屏插入的event消息通過socket發(fā)出。?
那何處何時(shí)接收并處理此消息呢?從mReceiveFd逆向推出:
SF在創(chuàng)建事件線程時(shí),同時(shí)創(chuàng)建了監(jiān)聽回調(diào):
mSFEventThread = new EventThread(sfVsyncSrc);mEventQueue.setEventThread(mSFEventThread);void MessageQueue::setEventThread(const sp<EventThread>& eventThread) {mEventThread = eventThread;mEvents = eventThread->createEventConnection(); //其中new Connection(),即初始化了mChannel(new BitTube()),此通道用于監(jiān)聽注冊mEventTube = mEvents->getDataChannel(); //mChannelmLooper->addFd(mEventTube->getFd(), 0, Looper::EVENT_INPUT,MessageQueue::cb_eventReceiver, this); //Android自4.1后在SF嵌入了消息機(jī)制。mLooper->addFd()為注冊監(jiān)聽,MessageQueue::cb_eventReceiver為回調(diào)函數(shù),其調(diào)用了eventReceiver() }分析到此處,插入消息接收處理仿佛已經(jīng)找到,但 eventReceiver()只處理DISPLAY_EVENT_VSYNC,而我們event包含的是DISPLAY_EVENT_HOTPLUG消息,莫非不用處理??
addFd()先注冊了監(jiān)聽,當(dāng)向pipe寫入event插入消息時(shí),從消息隊(duì)列中喚起并執(zhí)行處理。
先關(guān)注mEventTube->getFd()監(jiān)聽的對象:?
setEventThread()只適用于mSFEventThread變量,而我們跟蹤的是另外EventThread對象mEventThread。?
所以上面并非正確的調(diào)用處。
回頭看DisplayEventReceiver::getEvents(),同時(shí)結(jié)合其構(gòu)造函數(shù)創(chuàng)建mEventConnection,等同創(chuàng)建mChannel,必然有地方提前初始化此對象。?
搜索”DisplayEventReceiver “:
此類繼承LooperCallback,說明其可以實(shí)現(xiàn)消息機(jī)制的回調(diào)。再查看注冊監(jiān)聽以及消息獲取:
int rc = mMessageQueue->getLooper()->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT, this, NULL); while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0)該有的都有了,斷定此處即為處理插入事件的地方。
在分析EventThread::waitForEvent()時(shí),此函數(shù)中的mDisplayEventConnections通過
registerDisplayEventConnection()<<<EventThread::Connection::onFirstRef()<<<EventThread::createEventConnection()<<<(SurfaceFlinger::createDisplayEventConnection() <<<DisplayEventReceiver::DisplayEventReceiver())"所以addFd(mReceiver.getFd(),xxx)和conn->postEvent(event)中的mChannel為同一個(gè)。?
關(guān)于native的消息機(jī)制,與java的原理類似,熟悉的Handler,Looper,MessageQueue。
總結(jié)一下mChannel這個(gè)變量:?
DisplayEventReceiver::mDataChannel<>EventThread::Connection::mChannel?
1).其為BitTube對象?
2).BitTube對象中的mReceiveFd和mSendFd為socket的兩端?
3).addFd注冊監(jiān)聽,傳入BitTube::mReceiveFd被epoll掛起監(jiān)聽。同時(shí)獲取消息時(shí),::recv(mReceiveFd, vaddr, size, MSG_DONTWAIT),從mReceiveFd讀取?
4).::send(mSendFd, vaddr, size, MSG_DONTWAIT | MSG_NOSIGNAL),mSendFd用于發(fā)送消息
現(xiàn)在搞清楚了監(jiān)聽注冊,接受消息,我們繼續(xù)看兩個(gè)問題:?
(1).對于插入新屏的處理?
(2).android_view_DisplayEventReceiver.cpp的初始化
android_view_DisplayEventReceiver.cpp
int NativeDisplayEventReceiver::handleEvent(int receiveFd, int events, void* data) //雖然傳入了receiveFd,但此函數(shù)內(nèi)部并沒有使用。為什么可以自己思考。 bool NativeDisplayEventReceiver::processPendingEvents( nsecs_t* outTimestamp, int32_t* outId, uint32_t* outCount){ ...while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {...case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:dispatchHotplug(ev.header.timestamp, ev.header.id, ev.hotplug.connected);break;} ... }DisplayEventReceiver.java //DisplayEventReceiver.java為抽象類,LocalDisplayAdapter.java的內(nèi)部類HotplugDisplayEventReceiver繼承了DisplayEventReceiver?
// Called from native code.?
@SuppressWarnings(“unused”)?
private void dispatchHotplug(long timestampNanos, int builtInDisplayId, boolean connected) {?
onHotplug(timestampNanos, builtInDisplayId, connected);?
}
LocalDisplayAdapter.java
private void tryConnectDisplayLocked(int builtInDisplayId){ //為ev.header.id,此處值為1IBinder displayToken = SurfaceControl.getBuiltInDisplay(builtInDisplayId);if (displayToken != null) {SurfaceControl.PhysicalDisplayInfo[] configs =SurfaceControl.getDisplayConfigs(displayToken); //查詢mBuiltinDisplays.此處configs何時(shí)被設(shè)定?if (configs == null) {// There are no valid configs for this device, so we can't use itSlog.w(TAG, "No valid configs found for display device " +builtInDisplayId);return;} ...LocalDisplayDevice device = mDevices.get(builtInDisplayId); //此處創(chuàng)建的是LocalDisplayDevice對象if (device == null) {// Display was added.device = new LocalDisplayDevice(displayToken, builtInDisplayId,configs, activeConfig);mDevices.put(builtInDisplayId, device);sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED); //此處場景為第一次插入第二個(gè)屏} ... }DisplayManagerService.java
private void handleDisplayDeviceAddedLocked(DisplayDevice device){ ...addLogicalDisplayLocked(device);Runnable work = updateDisplayStateLocked(device); //此device為FLAG_NEVER_BLANK并且mGlobalDisplayState狀態(tài)不一致時(shí),會調(diào)用SurfaceControl.setDisplayPowerMode(token, mode)if (work != null) {work.run();}scheduleTraversalLocked(false); //將調(diào)用WindowManagerService::performLayoutAndPlaceSurfacesLockedLoop()>>>performLayoutAndPlaceSurfacesLockedInner()>>>mDisplayManagerInternal.performTraversalInTransactionFromWindowManager()>>>DMS::performTraversalInTransactionLocked()>>>configureDisplayInTransactionLocked()>>>LogicalDisplay::configureDisplayInTransactionLocked()>>>DisplayDevice::setLayerStackInTransactionLocked()>>>SurfaceControl.setDisplayLayerStack(mDisplayToken, layerStack) 如此重要的調(diào)用,隱藏的好深!其最終對應(yīng)Composer::setDisplayLayerStack(),將新創(chuàng)建DisplayState對象并保存到mDisplayStates中,同時(shí)DisplayState對象設(shè)定狀態(tài)eLayerStackChanged和對應(yīng)layerstack,提供后面顯示使用 ... } private void addLogicalDisplayLocked(DisplayDevice device){ //Adds a new logical display based on the given display device. Sends notifications if needed. ...final int displayId = assignDisplayIdLocked(isDefault);final int layerStack = assignLayerStackLocked(displayId); //最開始提到的將displayid與layerstack一致便是此時(shí)完成LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);display.updateLocked(mDisplayDevices); ...sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED); }DisplayManagerGlobal.java
public void registerDisplayListener(DisplayListener listener, Handler handler) //收到EVENT_DISPLAY_ADDED消息,將調(diào)用參數(shù)listener的回調(diào)函數(shù)onDisplayAdded()。Presentation.java和ViewRootImpl.java對ADD是空操作,它們更關(guān)心CHANGE,REMOVE的變化到此,插入第二個(gè)屏基本結(jié)束。從SF開始,到WMS結(jié)束。?
其主要作用:在SF對新屏進(jìn)行了參數(shù)初始化,在DMS創(chuàng)建并保存了新的Display,DisplayDevice對象,使得displayId與layerstack對應(yīng)一致。?
注意:此處分析的是插入新屏,系統(tǒng)開機(jī)過程中,DMS默認(rèn)會對主屏和HDMI進(jìn)行掃描并創(chuàng)建設(shè)備對象:?
LocalDisplayAdapter.java
系統(tǒng)初始化了第二個(gè)的設(shè)備對象,那么是如何控制顯示的呢??
我們從ViewRootImpl說起:?
ViewRootImpl.java
WindowManagerService.java
public int relayoutWindow(Session session, IWindow client, int seq,WindowManager.LayoutParams attrs, int requestedWidth,int requestedHeight, int viewVisibility, int flags,Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,Rect outVisibleInsets, Rect outStableInsets, Configuration outConfig,Surface outSurface){ //此處outSurface為null,其在WMS被創(chuàng)建賦值,并返回給ViewRootImpl ...SurfaceControl surfaceControl = winAnimator.createSurfaceLocked();if (surfaceControl != null) {outSurface.copyFrom(surfaceControl);if (SHOW_TRANSACTIONS) Slog.i(TAG," OUT SURFACE " + outSurface + ": copied");} ... }WindowStateAnimator.java
SurfaceControl createSurfaceLocked(){ ... // Start a new transaction and apply position & offset.SurfaceControl.openTransaction(); ...if (displayContent != null) {mSurfaceControl.setLayerStack(displayContent.getDisplay().getLayerStack()); //此處只關(guān)注第二個(gè)屏,即layerstack的處理} ...SurfaceControl.closeTransaction(); //將此處的設(shè)置一并提交 ... }因?yàn)镾F與framework對應(yīng)的變量有著重重封裝,此處直接跳過:
SurfaceComposerClient.cpp
status_t Composer::setLayerStack(const sp<SurfaceComposerClient>& client,const sp<IBinder>& id, uint32_t layerStack) { //id為SurfaceControl.cpp中的mHandleMutex::Autolock _l(mLock);layer_state_t* s = getLayerStateLocked(client, id); //將第二個(gè)屏對應(yīng)的ComposerState對象添加到mComposerStates中。ComposerState對象s.client為SF的Bp端,s.state.surface為IBinder對象mHandleif (!s)return BAD_INDEX;s->what |= layer_state_t::eLayerStackChanged;s->layerStack = layerStack; //設(shè)置了flag和laystack,在closeTransaction()提交時(shí)處理return NO_ERROR; }//SurfaceControl.closeTransaction()的對應(yīng)處理 void Composer::closeGlobalTransactionImpl(bool synchronous) { ...transaction = mComposerStates;mComposerStates.clear();displayTransaction = mDisplayStates; //上面分析已經(jīng)提供mComposerStates和mDisplayStates的創(chuàng)建添加mDisplayStates.clear(); ...sm->setTransactionState(transaction, displayTransaction, flags); //因?yàn)榍懊嬉灿術(shù)etLayerStateLockedmSurfaceControl.setSize(),其會將mForceSynchronous賦值為true,所以flag有eSynchronous。 }SurfaceFlinger.cpp
void SurfaceFlinger::setTransactionState(const Vector<ComposerState>& state,const Vector<DisplayState>& displays,uint32_t flags) { ...count = state.size();for (size_t i=0 ; i<count ; i++) {const ComposerState& s(state[i]);if (s.client != NULL) {sp<IBinder> binder = s.client->asBinder();if (binder != NULL) {String16 desc(binder->getInterfaceDescriptor());if (desc == ISurfaceComposerClient::descriptor) {sp<Client> client( static_cast<Client *>(s.client.get()) );transactionFlags |= setClientStateLocked(client, s.state); //將調(diào)用Layer::setLayerStack(),將layerstack保存到mCurrentState.layerStack,為mTransactionFlags添加eTransactionNeeded,后面的onDraw()使用}}}} ...if (transactionFlags) { //此時(shí)eTransactionNeeded|eTraversalNeeded// this triggers the transactionsetTransactionFlags(transactionFlags); //將調(diào)用到handleTransactionLocked()// if this is a synchronous transaction, wait for it to take effect// before returning.if (flags & eSynchronous) { mTransactionPending = true;}if (flags & eAnimation) {mAnimTransactionPending = true;}while (mTransactionPending) { //此時(shí)mTransactionPending為truestatus_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));if (CC_UNLIKELY(err != NO_ERROR)) {// just in case something goes wrong in SF, return to the// called after a few seconds.ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!");mTransactionPending = false;break;}}} }void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags){ ...if (transactionFlags & eTraversalNeeded) {for (size_t i=0 ; i<count ; i++) {const sp<Layer>& layer(currentLayers[i]);uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded); //if (!trFlags) continue;const uint32_t flags = layer->doTransaction(0); //每個(gè)layer進(jìn)行遍歷處理,將調(diào)用Layer::commitTransaction()>>>mDrawingState = mCurrentState。這樣第二個(gè)屏的已經(jīng)轉(zhuǎn)變?yōu)閙DrawingState狀態(tài)。if (flags & Layer::eVisibleRegion)mVisibleRegionsDirty = true;}} ...commitTransaction(); //調(diào)用mTransactionCV.broadcast(),使得 SurfaceControl.closeTransaction()線程返回.同時(shí)mDrawingState = mCurrentState;updateCursorAsync(); }至此,已經(jīng)將SF和Layer中的mDrawingState與第二個(gè)屏綁定。performDraw()可以愉快在插入的新屏上繪制了。
http://www.voidcn.com/article/p-wxfimpep-bpd.html
總結(jié)
以上是生活随笔為你收集整理的基于Android5.1的双屏异显分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android P 图形显示系统
- 下一篇: Android7.1 Presentat