AndroidによるWindowオブジェクトの管理メカニズムの分析


転載は出典を明記してください.http://blog.csdn.net/crazy1235/article/details/72625679
Windowオブジェクト管理に関するカテゴリ:
  • View Manager
  • WindowManager
  • WindowManagerImpl
  • WindowManagerGlobal
  • View Part
  • View RootImpl
  • ActvityThread
  • WindowManagerService
  • Windowは抽象的なタイプで、具体的な実現類はPhone Windowです.
    WindowはViewで積載されています.View RootImplにも対応しています.
    WindowにアクセスするにはWindowManagerを通じて実現しなければなりません.
    Windowの具体的な操作方法はWindowManager Impl類の中で実現して、方法はView Managerインターフェイスの中で定義します!
    public interface ViewManager
    {    
        public void addView(View view, ViewGroup.LayoutParams params);
        public void updateViewLayout(View view, ViewGroup.LayoutParams params);
        public void removeView(View view);
    }
    View Managerインターフェイスは三つの関数を定義しています.それぞれwindowの追加、更新、削除に対応しています.
    Android对Window对象的管理机制分析_第1张图片
    addView
     @Override
        public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
            applyDefaultToken(params);
            mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    
    実はWindowManagerImplも具体的な操作をしていません.WindowManagerGlobalに任せました.
    WindowManagerImplクラスで初期化されました.
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    WindowManager Global.java
    private WindowManagerGlobal() {
        }
    
        public static WindowManagerGlobal getInstance() {
            synchronized (WindowManagerGlobal.class) {
                if (sDefaultWindowManager == null) {
                    sDefaultWindowManager = new WindowManagerGlobal();
                }
                return sDefaultWindowManager;
            }
        }
    これは一例のパターンです.
    private final ArrayList mViews = new ArrayList();
    private final ArrayList mRoots = new ArrayList();
    private final ArrayList mParams =
                new ArrayList();
    private final ArraySet mDyingViews = new ArraySet();
    
    WindowManager Globalには4つの重要な集合があります.
  • mViewセットには、すべてのwindow対応のViewオブジェクトが格納されています.
  • mRoots集合は、すべてのwindowに対応するView RootImplオブジェクト
  • を記憶している.
  • mParamsのセットは、すべてのwindowに対応するレイアウトパラメータ
  • を記憶している.
  • mDyingViewのセットには、削除されているすべてのwindowオブジェクト
  • が格納されている.
    public void addView(View view, ViewGroup.LayoutParams params,
                Display display, Window parentWindow) {
            // 1.     !
            if (view == null) {
                throw new IllegalArgumentException("view must not be null");
            }
            if (display == null) {
                throw new IllegalArgumentException("display must not be null");
            }
            if (!(params instanceof WindowManager.LayoutParams)) {
                throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
            }
    
            final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
            if (parentWindow != null) {
                parentWindow.adjustLayoutParamsForSubWindow(wparams);
            } else {
                final Context context = view.getContext();
                if (context != null
                        && (context.getApplicationInfo().flags
                                & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
                    wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
                }
            }
    
            ViewRootImpl root; //   ViewRootImpl  
            View panelParentView = null; //   View  
    
            synchronized (mLock) {
                // ...
                //   view   index
                int index = findViewLocked(view, false);
                if (index >= 0) {
                    if (mDyingViews.contains(view)) {//              view,   ViewRootImpl.doDie()  
                        mRoots.get(index).doDie();
                    } else {
                        throw new IllegalStateException("View " + view
                                + " has already been added to the window manager.");
                    }
               }
    
                // ... 
    
                //   ViewRootImpl  
                root = new ViewRootImpl(view.getContext(), display);
                //       
                view.setLayoutParams(wparams);
    
                //   view    
                mViews.add(view);
                //   ViewRootImpl    
                mRoots.add(root);
                //   wparams      
                mParams.add(wparams);
            }
    
            try {
                //  view   ViewRootImpl !
                root.setView(view, wparams, panelParentView);
            } catch (RuntimeException e) {
                //        view
                synchronized (mLock) {
                    final int index = findViewLocked(view, false);
                    if (index >= 0) {
                        removeViewLocked(index, true);
                    }
                }
                throw e;
            }
        }
    関数は最後にView RootImpl.setView()を通じてwindowの添加過程を完成します.
    set View()の内部でrequest Layout()を呼び出し、描画プロセスを開始しました.
    Viewの描画プロセスはView RootImplによって完成されます.
    request Layout()描画プロセスが完了したら、WindowSessionを通じてWindowの追加プロセスが完了します.
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
                // ...
    
                try {
                        mOrigWindowType = mWindowAttributes.type;
                        mAttachInfo.mRecomputeGlobalAttributes = true;
                        collectViewAttributes();
                        res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                                getHostVisibility(), mDisplay.getDisplayId(),
                                mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                                mAttachInfo.mOutsets, mInputChannel);
                    } catch (RemoteException e) {
                        mAdded = false;
                        mView = null;
                        mAttachInfo.mRootView = null;
                        mInputChannel = null;
                        mFallbackEventHandler.setView(null);
                        unscheduleTraversals();
                        setAccessibilityFocus(null, null);
                        throw new RuntimeException("Adding window failed", e);
                    } finally {
                        if (restore) {
                            attrs.restore();
                        }
                    }
    
                // ...
    }
    mWindowSessionは、Binderオブジェクトです.
    本当の実現者はSessionです.
    @Override
        public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
                int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
                Rect outOutsets, InputChannel outInputChannel) {
            return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
                    outContentInsets, outStableInsets, outOutsets, outInputChannel);
        }
    ここでWindow Manager Serviceを通じてwindowの追加を実現します.そうすると、windowの追加事務はWMSに任せて処理します.
    udateView Layout
    WindowMangerImpl.java
    @Override
        public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
            applyDefaultToken(params);
            mGlobal.updateViewLayout(view, params);
        }
    public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
            // ...
            final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
            //         
            view.setLayoutParams(wparams); 
    
            synchronized (mLock) {
                int index = findViewLocked(view, true);
                ViewRootImpl root = mRoots.get(index);
                mParams.remove(index);
                mParams.add(index, wparams); //   mParams      
                root.setLayoutParams(wparams, false); //   ViewRootImpl    , false        view
            }
        }
    View RooImpl.java
    void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
            synchronized (this) {
                // ...
    
                if (newView) {
                    mSoftInputMode = attrs.softInputMode;
                    requestLayout();
                }
    
                //...
    
                mWindowAttributesChanged = true;
                scheduleTraversals();
            }
        }
    この関数では、scheduleTraversals()を呼び出して測定、レイアウト、描画プロセスを行います.
    removeView
    View Managerインターフェースには削除機能が一つしかありません.
    public void removeView(View view);
    WindowManagerインターフェースにviewを削除する方法が追加されました.
    public void removeViewImmediate(View view); //     
    この2つの方法は、同期削除を表し、非同期削除を表します.
    どちらもWindows ManagerGlobalのremoveView()関数を呼び出します.
    WindowManagerImpl.java
    @Override
        public void removeView(View view) {
            mGlobal.removeView(view, false);
        }
    @Override
        public void removeViewImmediate(View view) {
            mGlobal.removeView(view, true);
        }
    WindowManager Global.java
    public void removeView(View view, boolean immediate) {
            if (view == null) {
                throw new IllegalArgumentException("view must not be null");
            }
    
            synchronized (mLock) {
                //       view   
                int index = findViewLocked(view, true);
                //  mRoots       view  
                View curView = mRoots.get(index).getView();
                //       
                removeViewLocked(index, immediate);
                if (curView == view) {
                    return;
                }
    
                throw new IllegalStateException("Calling with view " + view
                        + " but the ViewAncestor is attached to " + curView);
            }
        }
    removeView()二つ目のパラメータはすぐに削除するかどうかを表します.
    private void removeViewLocked(int index, boolean immediate) {
            //   view   ViewRootImpl  
            ViewRootImpl root = mRoots.get(index);
            View view = root.getView();
    
            // ...
            //   View  die()  
            boolean deferred = root.die(immediate);
            if (view != null) {
                view.assignParent(null);
                if (deferred) { //             
                    mDyingViews.add(view);
                }
            }
        }
    View Root Impl.java
    boolean die(boolean immediate) {
            //      ,    doDie()           !    false
            if (immediate && !mIsInTraversal) {
                doDie();
                return false;
            }
    
            // ...
            //      ,           ,      true
            mHandler.sendEmptyMessage(MSG_DIE);
            return true;
        }
    実は非同期削除時に、handler処理時も呼び出したdoDie()関数で削除を完了します.
    case MSG_DIE:
       doDie();
       break;
    View Root Impl.java
    void doDie() {
            checkThread(); //     ,             !
    
            synchronized (this) {
                if (mRemoved) { // mRemoved   false,doDie()       true
                    return;
                }
                mRemoved = true;
                if (mAdded) { //     window          !     detach  
                    dispatchDetachedFromWindow();
                }
    
                if (mAdded && !mFirst) {
                    destroyHardwareRenderer(); //       
    
                    if (mView != null) {
                        int viewVisibility = mView.getVisibility();
                        boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
                        if (mWindowAttributesChanged || viewVisibilityChanged) { //   window            
    
                            try {
                                if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
                                        & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
                                    mWindowSession.finishDrawing(mWindow);
                                }
                            } catch (RemoteException e) {
                            }
                        }
    
                        mSurface.release(); //     
                    }
                }
    
                mAdded = false; //     
            }
            WindowManagerGlobal.getInstance().doRemoveView(this);
        }
    WindowManager Global.java
    void doRemoveView(ViewRootImpl root) {
            synchronized (mLock) {
                final int index = mRoots.indexOf(root); 
                if (index >= 0) {
                    mRoots.remove(index);//  ViewRootImpl     
                    mParams.remove(index); //         
                    final View view = mViews.remove(index); //      view
                    mDyingViews.remove(view);//             view
                }
            }
            if (ThreadedRenderer.sTrimForeground && ThreadedRenderer.isAvailable()) {
                doTrimForeground();
            }
        }
    dispatch DetachedFrom Window()関数を見に来てください.
    void dispatchDetachedFromWindow() {
            if (mView != null && mView.mAttachInfo != null) {
                mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
                mView.dispatchDetachedFromWindow(); //   view detach  !       onDetachedFromWidow()     onDetachedFromWindowInternal()  
            }
    
            // ...
    
            destroyHardwareRenderer();
    
            // ...
    
            mSurface.release();
    
            // ...
            try {
                mWindowSession.remove(mWindow);
            } catch (RemoteException e) {
            }
    
            // ...
    
            mDisplayManager.unregisterDisplayListener(mDisplayListener);
    
            unscheduleTraversals();
        }
    再度IPCでremove()関数を呼び出します.
    Session.java
    public void remove(IWindow window) {
            mService.removeWindow(this, window);
        }
    WMS.java
    public void removeWindow(Session session, IWindow client) {
            synchronized(mWindowMap) {
                WindowState win = windowForClientLocked(session, client, false);
                if (win == null) {
                    return;
                }
                removeWindowLocked(win);
            }
        }
    void removeWindowLocked(WindowState win) {
            removeWindowLocked(win, false);
        }
    void removeWindowLocked(WindowState win, boolean keepVisibleDeadWindow) {
            win.mWindowRemovalAllowed = true;
            // ...
    
            boolean wasVisible = false;
            // ...
    
            removeWindowInnerLocked(win);
            // ...
        }
    removewindowInner Locked(win);方法の内部分析はしばらく停止します!!