天天看點

基于Android5.1的雙屏異顯分析

平台:android5.1

場景:客戶的裝置需要使用到雙屏異顯。分析雙屏異顯時,framework所做的準備。

時間:2016.9.28

Android從4.2開始支援雙屏異顯,其Java使用示例代碼如下:

1.如何擷取裝置上的螢幕?

DisplayManager  mDisplayManager;//螢幕管理類
    Display[]  displays;//螢幕數組
    mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
    displays =mDisplayManager.getDisplays();
           

2.主屏和副屏的區分?

主屏:displays[0]

副屏:displays[1]

3.如何在副屏上展示内容?

通過Presentation來實作,Presentation繼承了Dialog。

假設我們寫了一個DifferentDislay的類,這個類是要繼承Presentation類:

privateclass DifferentDislay extends Presentation{
        public DifferentDislay(ContextouterContext, Display display) {
            super(outerContext,display);
            //TODOAuto-generated constructor stub  
        }
        @Override
        protectedvoid onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.diffrentdisplay_basket);
        }
    }
           

4.開啟副屏

DifferentDislay  mPresentation =new DifferentDislay (context,displays[]);//displays[1]是副屏
                     mPresentation.getWindow().setType(WindowManager.LayoutParams.TYPE_TOAST);
    mPresentation.show();
           

以上代碼的核心在于Presentation類,其繼承與Dialog。

從new DifferentDislay (context,displays[1]) 函數分析其初始化:

public Presentation(Context outerContext, Display display, int theme) {
        super(createPresentationContext(outerContext, display, theme), theme, false);      //核心函數

        mDisplay = display;
        mDisplayManager = (DisplayManager)getContext().getSystemService(Context.DISPLAY_SERVICE);

        getWindow().setGravity(Gravity.FILL);
        setCanceledOnTouchOutside(false);
    }
private static Context createPresentationContext(
            Context outerContext, Display display, int theme) {
...
          Context displayContext = outerContext.createDisplayContext(display);
...
        // Derive the display's window manager from the outer window manager.
        // We do this because the outer window manager have some extra information
        // such as the parent window, which is important if the presentation uses
        // an application window type.
        final WindowManagerImpl outerWindowManager =
                (WindowManagerImpl)outerContext.getSystemService(Context.WINDOW_SERVICE);
        final WindowManagerImpl displayWindowManager =
                outerWindowManager.createPresentationWindowManager(display);     //針對特定的display建立對應的WindowManagerImpl管理對象
        return new ContextThemeWrapper(displayContext, theme) {               //傳回的Context的getSystemService()被重載,通過此Context擷取的Window管理對象為上面建立的這個
            @Override
            public Object getSystemService(String name) {
                if (Context.WINDOW_SERVICE.equals(name)) {
                    return displayWindowManager;
                }
                return super.getSystemService(name);
            }
        };
}
           

上面代碼的設計原則:

每一個display擁有自己的管理對象以及context對象,這樣雙屏的操作互相獨立—Display是核心對象。對于上層而言,其即意味着一個螢幕。

mPresentation.show()拉開了雙屏異顯的序幕。結合上面的分析,WindowManagerImpl.java中的addView()方法将傳入上面初始化的display[1],繼而:

WindowManagerGlobal.java
    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
...
     root = new ViewRootImpl(view.getContext(), display);
...
}

ViewRootImpl.java
     public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
...
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mInputChannel);
...
}

WindowManagerService.java
    public int addWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
            Rect outContentInsets, Rect outStableInsets, InputChannel outInputChannel) {
...
     final DisplayContent displayContent = getDisplayContentLocked(displayId);     //先從mDisplayContents查詢。若沒有,則先判定displayId對應的裝置是否存在。若存在,則調用newDisplayContentLocked建立新的DisplayContent對象,并儲存到mDisplayContents
...
            win = new WindowState(this, session, client, token,
                    attachedWindow, appOp[], seq, attrs, viewVisibility, displayContent);          //DisplayContent内部儲存了mDisplayId,以都與相對的WindowState進行了綁定
...
} 
    private DisplayContent newDisplayContentLocked(final Display display) {
...
        DisplayInfo displayInfo = displayContent.getDisplayInfo();
        final Rect rect = new Rect();
        mDisplaySettings.getOverscanLocked(displayInfo.name, displayInfo.uniqueId, rect);
        synchronized (displayContent.mDisplaySizeLock) {
            displayInfo.overscanLeft = rect.left;
            displayInfo.overscanTop = rect.top;
            displayInfo.overscanRight = rect.right;
            displayInfo.overscanBottom = rect.bottom;
            mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(
                    displayId, displayInfo);     //此函數可以深究,目前存在雙屏,其在找到displayId對應屏的情況下,會發送DisplayManagerGlobal.EVENT_DISPLAY_CHANGED消息
        }
        configureDisplayPolicyLocked(displayContent);               //以上初始化displayContent中的displayInfo對象
...
}

關于displayId與displayInfo.layerstack,當檢測到雙屏後:
    // Adds a new logical display based on the given display device.
    // Sends notifications if needed.
    private void addLogicalDisplayLocked(DisplayDevice device) {
...
        final int displayId = assignDisplayIdLocked(isDefault);
        final int layerStack = assignLayerStackLocked(displayId);     //直接将displayId指派給layerStack。即他們始終為同一個值
        LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);          //此處建立的LogicalDisplay對象為上面提供的display[]的某一真實對象
...
}
           

接下來開始進入到主題,framework為支援雙屏異顯做了哪些工作?

兩個重點:

1.檢測到雙屏(第二個屏)後,系統做了哪些準備?(主螢幕和HDMI是兩個預設開機就進行檢測的螢幕裝置,其他監聽後使用hotplug處理)

2.如何進行/區分雙屏異顯?

上面提到Android4.2開始支援雙屏異顯,除了引入Presentation 類,其還定制了HWComposer,其構造函數中:

if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
                mCBContext->procs.hotplug = &hook_hotplug;
            else
                mCBContext->procs.hotplug = NULL;
           

即HWC的版本大于等于1.1即可支援雙屏異顯。我們從hook_hotplug開始檢視檢測到插入新屏時的系統

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//預設為2。當type小于2時,才會繼續執行。即預設最多支援兩個屏。此處的type标示着螢幕類型,如下所示:
    enum DisplayType {
        DISPLAY_ID_INVALID = -,
        DISPLAY_PRIMARY     = HWC_DISPLAY_PRIMARY,     //0,預設螢幕
        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               //此宏為1
    mEvents->requestNextVsync();
#else
    mHandler->dispatchInvalidate();
#endif
}

EventThread.cpp
void EventThread::requestNextVsync( const sp<EventThread::Connection>& connection)          //mCondition.broadcast()将挂起的線程喚起
Vector< sp<EventThread::Connection> > EventThread::waitForEvent( DisplayEventReceiver::Event* event)     //此函數中的mDisplayEventConnections值得深究。其通過registerDisplayEventConnection()<<<EventThread::Connection::onFirstRef()<<<EventThread::createEventConnection()<<<(SurfaceFlinger::createDisplayEventConnection() <<<DisplayEventReceiver::DisplayEventReceiver())---這個是mEventThread對象的 | (MessageQueue::setEventThread()<<<SurfaceFlinger::init())---這個是mSFEventThread對象的在此構造函數中建立了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);          //此函數作用?
    handleTransactionLocked(transactionFlags);                    //上面函數看上去是将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 identical
        const 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= ; i<cc ; i++) {
                    ...
                    BufferQueue::createBufferQueue(&bqProducer, &bqConsumer, new GraphicBufferAlloc());             //為對應的display建立新的BufferQueue
                    ...
                    else {
                            mEventThread->onHotplugReceived(state.type, true);          //通知有新屏裝置接入,mEventThread對象中的Connection需要先建立,即createEventConnection()函數需要先被執行,以便後面利用Connection内部對象mChannel來通信!---注意區分與mSFEventThread差别
                        }
               }
     }
...
}
           
EventThread.cpp
void EventThread::onHotplugReceived(int type, bool connected){     //此時type為1,即DISPLAY_EXTERNAL。connected為true
    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);                    //插入event,将在waitForEvent()讀取
        mCondition.broadcast();
    }
}
Vector< sp<EventThread::Connection> > EventThread::waitForEvent(DisplayEventReceiver::Event* event){
...
        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[];               //取出上面插入的event
                mPendingEvents.removeAt();
            }
        }

        // find out connections waiting for events
        size_t count = mDisplayEventConnections.size();          //此處對應新display的connectcion已經建立,如何建立???
     ...
                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) {                         //此時eventPending為true,不會進入此if進行wait,同時signalConnections.add(),是以會退出while循環
          ...
          }
          while (signalConnections.isEmpty());
...
}
bool EventThread::threadLoop()
status_t EventThread::Connection::postEvent( const DisplayEventReceiver::Event& event)          //sendEvents()中的mChannel為new new BitTube(),此對象用于pipe通信。關注此時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函數進行pipe通信。BitTube的構造函數中,調用init函數,其調用socketpair(AF_UNIX, SOCK_SEQPACKET, , sockets)初始化了mReceiveFd和mSendFd
...
}
           

至此,将新屏插入的event消息通過socket發出。

那何處何時接收并處理此消息呢?從mReceiveFd逆向推出:

BitTube.cpp
ssize_t BitTube::read(void* vaddr, size_t size)
ssize_t BitTube::recvObjects(const sp<BitTube>& tube, void* events, size_t count, size_t objSize)
           
DisplayEventReceiver.cpp
DisplayEventReceiver::getEvents(mDataChannel, events, count)     //此處mDataChannel為mEventConnection建立時,初始化的針對此connection的資料通道,其為DisplayEventReceiver内部對象mEventConnection中的mChannel。event為讀取的插入事件指針
           
MessageQueue.cpp
int MessageQueue::eventReceiver(int /*fd*/, int /*events*/){          
    ssize_t n;
    DisplayEventReceiver::Event buffer[];
    while ((n = DisplayEventReceiver::getEvents(mEventTube, buffer, )) > ) {
        for (int i= ; i<n ; i++) {
            if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
#if INVALIDATE_ON_VSYNC
                mHandler->dispatchInvalidate();
#else
                mHandler->dispatchRefresh();
#endif
                break;
            }
        }
    }
    return ;
}
           

SF在建立事件線程時,同時建立了監聽回調:

mSFEventThread = new EventThread(sfVsyncSrc);
    mEventQueue.setEventThread(mSFEventThread);

void MessageQueue::setEventThread(const sp<EventThread>& eventThread)
{
    mEventThread = eventThread;
    mEvents = eventThread->createEventConnection();     //其中new Connection(),即初始化了mChannel(new BitTube()),此通道用于監聽注冊
    mEventTube = mEvents->getDataChannel();               //mChannel
    mLooper->addFd(mEventTube->getFd(), , Looper::EVENT_INPUT,
            MessageQueue::cb_eventReceiver, this);               //Android自4.1後在SF嵌入了消息機制。mLooper->addFd()為注冊監聽,MessageQueue::cb_eventReceiver為回調函數,其調用了eventReceiver()
}
           

分析到此處,插入消息接收處理仿佛已經找到,但 eventReceiver()隻處理DISPLAY_EVENT_VSYNC,而我們event包含的是DISPLAY_EVENT_HOTPLUG消息,莫非不用處理?

addFd()先注冊了監聽,當向pipe寫入event插入消息時,從消息隊列中喚起并執行處理。

先關注mEventTube->getFd()監聽的對象:

setEventThread()隻适用于mSFEventThread變量,而我們跟蹤的是另外EventThread對象mEventThread。

是以上面并非正确的調用處。

回頭看DisplayEventReceiver::getEvents(),同時結合其構造函數建立mEventConnection,等同建立mChannel,必然有地方提前初始化此對象。

搜尋”DisplayEventReceiver “:

android_view_DisplayEventReceiver.cpp
class NativeDisplayEventReceiver : public LooperCallback {
...    
     virtual int handleEvent(int receiveFd, int events, void* data);          //回調函數
     DisplayEventReceiver mReceiver;
...
}
           

此類繼承LooperCallback,說明其可以實作消息機制的回調。再檢視注冊監聽以及消息擷取:

int rc = mMessageQueue->getLooper()->addFd(mReceiver.getFd(), , Looper::EVENT_INPUT, this, NULL);          
while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > )
           

該有的都有了,斷定此處即為處理插入事件的地方。

在分析EventThread::waitForEvent()時,此函數中的mDisplayEventConnections通過

是以addFd(mReceiver.getFd(),xxx)和conn->postEvent(event)中的mChannel為同一個。

關于native的消息機制,與java的原理類似,熟悉的Handler,Looper,MessageQueue。

Looper.cpp
int Looper::pollInner(int timeoutMillis) {
...
     int callbackResult = response.request.callback->handleEvent(fd, events, data);          //setEventThread() 對應的mSFEventThread也使用了callback方式,其傳入了函數指針,被SimpleLooperCallback封裝
...
}
           

總結一下mChannel這個變量:

DisplayEventReceiver::mDataChannel<>EventThread::Connection::mChannel

1).其為BitTube對象

2).BitTube對象中的mReceiveFd和mSendFd為socket的兩端

3).addFd注冊監聽,傳入BitTube::mReceiveFd被epoll挂起監聽。同時擷取消息時,::recv(mReceiveFd, vaddr, size, MSG_DONTWAIT),從mReceiveFd讀取

4).::send(mSendFd, vaddr, size, MSG_DONTWAIT | MSG_NOSIGNAL),mSendFd用于發送消息

現在搞清楚了監聽注冊,接受消息,我們繼續看兩個問題:

(1).對于插入新屏的處理

(2).android_view_DisplayEventReceiver.cpp的初始化

android_view_DisplayEventReceiver.cpp

int NativeDisplayEventReceiver::handleEvent(int receiveFd, int events, void* data)     //雖然傳入了receiveFd,但此函數内部并沒有使用。為什麼可以自己思考。
bool NativeDisplayEventReceiver::processPendingEvents( nsecs_t* outTimestamp, int32_t* outId, uint32_t* outCount){
...
     while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > ) {
          ...
        case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
                dispatchHotplug(ev.header.timestamp, ev.header.id, ev.hotplug.connected);
                break;
     }
...
}
           

DisplayEventReceiver.java //DisplayEventReceiver.java為抽象類,LocalDisplayAdapter.java的内部類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,此處值為1
        IBinder displayToken = SurfaceControl.getBuiltInDisplay(builtInDisplayId);
        if (displayToken != null) {
            SurfaceControl.PhysicalDisplayInfo[] configs =
                    SurfaceControl.getDisplayConfigs(displayToken);                    //查詢mBuiltinDisplays.此處configs何時被設定?
            if (configs == null) {
                // There are no valid configs for this device, so we can't use it
                Slog.w(TAG, "No valid configs found for display device " +
                        builtInDisplayId);
                return;
            }
...
            LocalDisplayDevice device = mDevices.get(builtInDisplayId);               //此處建立的是LocalDisplayDevice對象
            if (device == null) {
                // Display was added.
                device = new LocalDisplayDevice(displayToken, builtInDisplayId,
                        configs, activeConfig);
                mDevices.put(builtInDisplayId, device);
                sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);               //此處場景為第一次插入第二個屏
            }
... 
}
           

DisplayManagerService.java

private void handleDisplayDeviceAddedLocked(DisplayDevice device){
...
     addLogicalDisplayLocked(device);
       Runnable work = updateDisplayStateLocked(device);          //此device為FLAG_NEVER_BLANK并且mGlobalDisplayState狀态不一緻時,會調用SurfaceControl.setDisplayPowerMode(token, mode)
        if (work != null) {
            work.run();
       }
        scheduleTraversalLocked(false);          //将調用WindowManagerService::performLayoutAndPlaceSurfacesLockedLoop()>>>performLayoutAndPlaceSurfacesLockedInner()>>>mDisplayManagerInternal.performTraversalInTransactionFromWindowManager()>>>DMS::performTraversalInTransactionLocked()>>>configureDisplayInTransactionLocked()>>>LogicalDisplay::configureDisplayInTransactionLocked()>>>DisplayDevice::setLayerStackInTransactionLocked()>>>SurfaceControl.setDisplayLayerStack(mDisplayToken, layerStack)
如此重要的調用,隐藏的好深!其最終對應Composer::setDisplayLayerStack(),将新建立DisplayState對象并儲存到mDisplayStates中,同時DisplayState對象設定狀态eLayerStackChanged和對應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一緻便是此時完成

        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消息,将調用參數listener的回調函數onDisplayAdded()。Presentation.java和ViewRootImpl.java對ADD是空操作,它們更關心CHANGE,REMOVE的變化
           

到此,插入第二個屏基本結束。從SF開始,到WMS結束。

其主要作用:在SF對新屏進行了參數初始化,在DMS建立并儲存了新的Display,DisplayDevice對象,使得displayId與layerstack對應一緻。

注意:此處分析的是插入新屏,系統開機過程中,DMS預設會對主屏和HDMI進行掃描并建立裝置對象:

LocalDisplayAdapter.java

public void registerLocked() {
        super.registerLocked();

        mHotplugReceiver = new HotplugDisplayEventReceiver(getHandler().getLooper());

        for (int builtInDisplayId : BUILT_IN_DISPLAY_IDS_TO_SCAN) {
            tryConnectDisplayLocked(builtInDisplayId);
        }
    }
           

系統初始化了第二個的裝置對象,那麼是如何控制顯示的呢?

我們從ViewRootImpl說起:

ViewRootImpl.java

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
...
                    requestLayout();     //下面的跨程序調用addToDisplay()先建立了win,并綁定了對應的displayId。此處将通過Handler執行performTraversals()
...
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mInputChannel);
...
}
     private void performTraversals() {
...
               relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);      //建立對應的Surface畫布
...
               performDraw();   //在建立并傳回的Surface上執行繪畫
...
}
           

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被建立指派,并傳回給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());          //此處隻關注第二個屏,即layerstack的處理
                    }
...
               SurfaceControl.closeTransaction();     //将此處的設定一并送出
...
}
           

因為SF與framework對應的變量有着重重封裝,此處直接跳過:

SurfaceComposerClient.cpp

status_t Composer::setLayerStack(const sp<SurfaceComposerClient>& client,
        const sp<IBinder>& id, uint32_t layerStack) {          //id為SurfaceControl.cpp中的mHandle
    Mutex::Autolock _l(mLock);
    layer_state_t* s = getLayerStateLocked(client, id);     //将第二個屏對應的ComposerState對象添加到mComposerStates中。ComposerState對象s.client為SF的Bp端,s.state.surface為IBinder對象mHandle
    if (!s)
        return BAD_INDEX;
    s->what |= layer_state_t::eLayerStackChanged;
    s->layerStack = layerStack;                                   //設定了flag和laystack,在closeTransaction()送出時處理
    return NO_ERROR;
}

//SurfaceControl.closeTransaction()的對應處理
void Composer::closeGlobalTransactionImpl(bool synchronous) {
...
        transaction = mComposerStates;
        mComposerStates.clear();

        displayTransaction = mDisplayStates;               //上面分析已經提供mComposerStates和mDisplayStates的建立添加
        mDisplayStates.clear();
...
     sm->setTransactionState(transaction, displayTransaction, flags);          //因為前面也有getLayerStateLockedmSurfaceControl.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= ; 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);     //将調用Layer::setLayerStack(),将layerstack儲存到mCurrentState.layerStack,為mTransactionFlags添加eTransactionNeeded,後面的onDraw()使用
                }
            }
        }
    }
...
    if (transactionFlags) {          //此時eTransactionNeeded|eTraversalNeeded
        // this triggers the transaction
        setTransactionFlags(transactionFlags);          //将調用到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) {               //此時mTransactionPending為true
            status_t err = mTransactionCV.waitRelative(mStateLock, s2ns());
            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= ; i<count ; i++) {
            const sp<Layer>& layer(currentLayers[i]);
            uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);          //
            if (!trFlags) continue;

            const uint32_t flags = layer->doTransaction();          //每個layer進行周遊處理,将調用Layer::commitTransaction()>>>mDrawingState = mCurrentState。這樣第二個屏的已經轉變為mDrawingState狀态。
            if (flags & Layer::eVisibleRegion)
                mVisibleRegionsDirty = true;
        }
    }
...
           commitTransaction();          //調用mTransactionCV.broadcast(),使得 SurfaceControl.closeTransaction()線程傳回.同時mDrawingState = mCurrentState;
           updateCursorAsync();
}
           

至此,已經将SF和Layer中的mDrawingState與第二個屏綁定。performDraw()可以愉快在插入的新屏上繪制了。