안드로이드/안드로이드 프레임워크

안드로이드 앱 프레임워크 학습(WindowManager) 1

냥냥냥냥냥냥 2024. 2. 28. 21:00

안드로이드 그래픽스 프레임워크 학습 2 (tistory.com)

 

안드로이드 그래픽스 프레임워크 학습 2

안드로이드 그래픽스 프레임워크 학습 1 (tistory.com) 안드로이드 그래픽스 프레임워크 학습 1 이번에 이 글을 작성하게 되는 이유는 위의 Android 공식 홈페이지의 기술되어 있는 부분들에 대해 코

nyaang.tistory.com

위의 분석에서 SurfaceFlinger의 createLayer를 통해 SurfaceFlinger에 layer가 추가 되는 과정을 알아 봤었습니다

이번에는 그럼, createLayer를 해주는 부분이 어디인지를 한 번 알아보는 것이 핵심입니다

 

먼저, createLayer 시작점을 보기 전에 WindowManager라는 개념을 먼저 알아야 합니다

 

native 단의(여기서 native는 c, c++) SurfaceFlinger는 layer 단위로 관리를 하고 있고 

java 단의 WindowManager는 window 단위로 관리를 합니다 

 

둘 사이는 SurfaceControl.Transaction 이라는 것을 통해 통신을 하고,  그 Transaction을 가지고 있는 것은 DisplayContent입니다

안드로이드에서는 display별로 DisplayContent를 가지게 되고, 그 displayContent는 RootWindowContainer의 child들로 관리가 됩니다

// 1. WindowManagerService의 RootWindowContainer
    // The root of the device window hierarchy.
    RootWindowContainer mRoot;
    
 // 2. RootWindowContainer 상속 관계
 class RootWindowContainer extends WindowContainer<DisplayContent>
 
 // 3. RootWindowContainer::SetWindowManager
     void setWindowManager(WindowManagerService wm) {
        mWindowManager = wm;
        ...


        final Display[] displays = mDisplayManager.getDisplays();
        for (int displayNdx = 0; displayNdx < displays.length; ++displayNdx) {
            final Display display = displays[displayNdx];
            final DisplayContent displayContent = new DisplayContent(display, this);
            addChild(displayContent, POSITION_BOTTOM);  // addChild
            if (displayContent.mDisplayId == DEFAULT_DISPLAY) {
                mDefaultDisplay = displayContent;
            }
        }
        
 // 4. WindowContainer::addChild
     /** Adds the input window container has a child of this container at the input index. */
    @CallSuper
    void addChild(E child, int index) {
        if (!child.mReparenting && child.getParent() != null) {
            throw new IllegalArgumentException("addChild: container=" + child.getName()
                    + " is already a child of container=" + child.getParent().getName()
                    + " can't add to container=" + getName()
                    + "\n callers=" + Debug.getCallers(15, "\n"));
        }

        if ((index < 0 && index != POSITION_BOTTOM)
                || (index > mChildren.size() && index != POSITION_TOP)) {
            throw new IllegalArgumentException("addChild: invalid position=" + index
                    + ", children number=" + mChildren.size());
        }

        if (index == POSITION_TOP) {
            index = mChildren.size();
        } else if (index == POSITION_BOTTOM) {
            index = 0;
        }

        mChildren.add(index, child);

        // Set the parent after we've actually added a child in case a subclass depends on this.
        child.setParent(this);
    }

2번을 보시면 RootWindowContainer는 WindowContainer를 상속받는데 제네릭으로 DisplayContent 형식을 받는 것을 볼 수 있습니다

3번을 보시면 setWindowManager 호출 시에, addChild를 호출 해주는 것을 볼 수있고

4번을 보시면 addChild의 구현부분 입니다

 

처음 궁금했던, createLayer가 불리기까지의 sequence는 아래와 같습니다

createLayer 불리기 까지 과정

 

위에서, SurfaceFlinger <-> WindowManager 간의 통신은 Transaction을 통해서 이루어 진다고 얘기를 했는데, 그 부분에 대해서 좀 알아보려고 합니다

 

SetTransactionState까지의 sequence

 

// 1. RootWindowContainer::performSurfacePlacementNoTrace
    void performSurfacePlacementNoTrace() {
    ...
        mWmService.openSurfaceTransaction();
        try {
            applySurfaceChangesTransaction();
        } catch (RuntimeException e) {
            Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
        } finally {
            mWmService.closeSurfaceTransaction("performLayoutAndPlaceSurfaces");
            ...
        }
        
// 2. WindowManagerService::opensurfaceTranaction, closeSurfaceTransaction
    void openSurfaceTransaction() {
        try {
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "openSurfaceTransaction");
            SurfaceControl.openTransaction();
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
    }

    /**
     * Closes a surface transaction.
     * @param where debug string indicating where the transaction originated
     */
    void closeSurfaceTransaction(String where) {
        try {
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "closeSurfaceTransaction");
            SurfaceControl.closeTransaction();
            mWindowTracing.logState(where);
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
    }


  // 3. SurfaceComposerClient::Transaction::merge
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) {
    for (auto const& [handle, composerState] : other.mComposerStates) {
        if (mComposerStates.count(handle) == 0) {
            mComposerStates[handle] = composerState;
        } else {
            mComposerStates[handle].state.merge(composerState.state);
        }
    }

    for (auto const& state : other.mDisplayStates) {
        ssize_t index = mDisplayStates.indexOf(state);
        if (index < 0) {
            mDisplayStates.add(state);
        } else {
            mDisplayStates.editItemAt(static_cast<size_t>(index)).merge(state);
        }
    }  
  
  // 4. SurfaceComposerClient::Transaction::apply
  status_t SurfaceComposerClient::Transaction::apply(bool synchronous) {
  ...
  
    Vector<ComposerState> composerStates;
    Vector<DisplayState> displayStates;

   ...

    for (auto const& kv : mComposerStates){
        composerStates.add(kv.second);
    }
    
    ...
    
    sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, flags, applyToken,
                            mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp,
                            {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/,
                            hasListenerCallbacks, listenerCallbacks, mId);

1번을 보시면 performSurfacePlacement 함수 내부의 performSurfacePlacementNoTrace 부분에 대한 설명입니다

performSurfacePlacement는 activity 전환 등 많은 경우에 불릴 수 있습니다

 

2번은 openSurfaceTransaction, closeSurfaceTransaction 부분의 코드 입니다

3번과 4번은 각각 openSurfaceTransaction, closeSurfaceTransaction시의 주요 사항 부분에 대한 코드 입니다

openSurfaceTransaction 일 때, SurfaceComposerClient::Transaction::merge가 불려서 mComposerStates와 mDisplayStates를 업데이트 시켜주고,

closeSurfaceTransaction이 불릴 때 SurfaceComposerClient::Transaction::apply가 불려서 SurfaceFlinger의 setTransactionState가 불리어 TransactionState를 넘겨줍니다

 

그 이후 SurfaceFlinger에서 queueTransaction를 통해 transaction을 저장했던 것을 flushTransactionQueues 시점에 업데이트 해줍니다  자세한 사항은 지난 번에 썼던 아래 부분과 연계가 되니 궁금하신 분은 확인 부탁드리겠습니다

 

 

안드로이드 그래픽스 프레임워크 학습 2 (tistory.com)

 

안드로이드 그래픽스 프레임워크 학습 2

안드로이드 그래픽스 프레임워크 학습 1 (tistory.com) 안드로이드 그래픽스 프레임워크 학습 1 이번에 이 글을 작성하게 되는 이유는 위의 Android 공식 홈페이지의 기술되어 있는 부분들에 대해 코

nyaang.tistory.com

 

이렇게 해서 SurfaceFlinger <-> WindowManger간의 통신은 어떻게 이루어 지는지, SurfaceFlinger의 createLayer는 누가 해주는 지를 분석해보았습니다

다음 번엔 WindowManager에 대해서 좀 더 자세하게 분석 해보도록 하겠습니다

 

감사합니다