應(yīng)用與WMS的關(guān)聯(lián)

簡(jiǎn)介

我之前分析過(guò),但是感覺(jué)當(dāng)時(shí)迷迷糊糊的,自己也沒(méi)徹底弄清楚,今天我再次突破,這次感覺(jué)比以前清楚了,為什么要寫這個(gè)關(guān)系,因?yàn)樵陧?xiàng)目中Activity中見到Window win = getWindow();這種寫法。所以要想了解Wundow類我們就要明白WMS與我們的應(yīng)用到底有什么聯(lián)系。

應(yīng)用于WMS關(guān)聯(lián)的來(lái)源

AT.handleLaunchActivity


private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    handleConfigurationChanged(null, null);
    //獲取WMS代理對(duì)象
    WindowManagerGlobal.initialize();//[1.1]
    Activity a = performLaunchActivity(r, customIntent);//[1.2]
    if (a != null) {
        //最終回調(diào)目標(biāo)Activity的onStart,onResume.
        handleResumeActivity(r.token, false, r.isForward, !r.activity.mFinished && !r.startsNotResumed);//[1.3]
        ...
    } else {
        ...
    }
    ...
}
image.png

1.1

我們?cè)赪indowManagerGlobal.java中看看

public final class WindowManagerGlobal {
    ...
    public static void initialize() {
        getWindowManagerService();
    }
    public static IWindowManager getWindowManagerService() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowManagerService == null) {
                sWindowManagerService = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
                ...
            }
            return sWindowManagerService;
        }
    }
    ...
}

通過(guò)這里可以看到WindowManagerGlobal 持有WMS的Binder代理并且唯一。

1.2

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {

    ...

    Activity activity = null;
    //獲取ClassLoader
    java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
    //創(chuàng)建目標(biāo)Activity對(duì)象
    activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
    ...
    //創(chuàng)建Application對(duì)象
    Application app = r.packageInfo.makeApplication(false, mInstrumentation);
    if (activity != null) {
        ...
        //變量賦值操作
        activity.attach(appContext, this, getInstrumentation(), r.token,
                r.ident, app, r.intent, r.activityInfo, title, r.parent,
                r.embeddedID, r.lastNonConfigurationInstances, config,
                r.referrer, r.voiceInteractor);//[2.1]
        ...
    }
    ...
    return activity;
}
  • 創(chuàng)建目標(biāo)Activity對(duì)象
  • 創(chuàng)建Application對(duì)象
  • 執(zhí)行activity.attach()

2.1

public class Activity extends ContextThemeWrapper implements ... {
    private Window mWindow;
    
    final void attach(...) {
        ...
        mWindow = new PhoneWindow(this); //創(chuàng)建PhoneWindow
        ...
        mUiThread = Thread.currentThread(); //獲取UI線程
        mToken = token; //遠(yuǎn)程ActivityRecord的appToken的代理端
        mApplication = application; //所屬的Appplication
        ...
        //設(shè)置并獲取WindowManagerImpl對(duì)象
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        ...
        mWindowManager = mWindow.getWindowManager();
        mCurrentConfig = config;
        ...
    }
}

Window.setWindowManager

由于PhoneWindow繼承Window

public void setWindowManager(WindowManager wm, IBinder appToken, String appName,boolean hardwareAccelerated) { 
    ...    
    mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    ...
}

我們看到通過(guò)mWindow.setWindowManager()這個(gè)方法我們創(chuàng)建并獲取了WindowManagerImpl對(duì)象

public final class WindowManagerImpl implements WindowManager {
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    ....
}

這里我們就看出,當(dāng)Activity執(zhí)行到attach方法的時(shí)候就會(huì)創(chuàng)建PhoneWindow,PhoneWindow創(chuàng)建WindowManagerImpl,WindowManagerImpl持有WindowManagerGlobal

所以每個(gè)Activity的mWindowManager 是WindowManagerImpl對(duì)象,WindowManagerImpl 存有WindowManagerGlobal這個(gè)對(duì)象是進(jìn)程唯一。

public final class WindowManagerGlobal {
    private final ArrayList<View> mViews = new ArrayList<View>();
    private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
    private final ArrayList<WindowManager.LayoutParams> mParams = new ArrayList<WindowManager.LayoutParams>();
    private final ArraySet<View> mDyingViews = new ArraySet<View>();
    ...

WindowManagerGlobal這個(gè)對(duì)象管理當(dāng)前進(jìn)程里面所有的View(DecorView),ViewRootImpl,WindowManager.LayoutParams(頂層View的layout參數(shù))

AT.handleLaunchActivity.png

應(yīng)用程序如何通知WMS呢?

public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
        
        final W mWindow;
        final IWindowSession mWindowSession;
        
        public ViewRootImpl(Context context, Display display) {
            ...
            mWindowSession = WindowManagerGlobal.getWindowSession();//[1.1]
            ...
        }
}        

1.1

public static IWindowSession getWindowSession() {
    synchronized (WindowManagerGlobal.class) {
        if (sWindowSession == null) {
            try {
                InputMethodManager imm = InputMethodManager.getInstance();
                IWindowManager windowManager = getWindowManagerService();
                sWindowSession = windowManager.openSession(
                        new IWindowSessionCallback.Stub() {
                            @Override
                            public void onAnimatorScaleChanged(float scale) {
                                ValueAnimator.setDurationScale(scale);
                            }
                        },
                        imm.getClient(), imm.getInputContext());
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
        return sWindowSession;
    }
}

由于前面說(shuō)過(guò)getWindowManagerService()返回的是WMS的代理,所以在WMS方法如下:

WMS

@Override
public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client,
        IInputContext inputContext) {
        ...
    Session session = new Session(this, callback, client, inputContext);
    return session;
}

Session是用aidl生成的Binder對(duì)象。因此WMS將這個(gè)Binder代理返回給了應(yīng)用程序,這樣應(yīng)用程序就可以通過(guò)WindowManagerGlobal 與WMS進(jìn)行通信了。其中WindowManagerGlobal持有的sWindowSession是WMS中的Session代理對(duì)象。

小結(jié)

也就是當(dāng)前應(yīng)用中有一份WindowManagerGlobal 唯一,這里有WMS的代理也有ViewRootImpl,ViewRootImpl 中的sWindowSession變量映射著WMS的Session Binder代理。

WMS如何通知應(yīng)用程序呢?

要想知道這個(gè)問(wèn)題我們就要研究ViewRootImpl這個(gè)類,我們就從它的成員變量開始:

public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
    
    final IWindowSession mWindowSession;
    final W mWindow;
    
    public ViewRootImpl(Context context, Display display) {
        
        mWindowSession = WindowManagerGlobal.getWindowSession();
        mWindow = new W(this);
    }
    ...
}

我們看到了W對(duì)象,這個(gè)對(duì)象是Binder對(duì)象。

與此同時(shí)我們應(yīng)該看看WindowState對(duì)象。

final class WindowState implements WindowManagerPolicy.WindowState {
    
    final WindowManagerService mService;
    final Session mSession;
    final IWindow mClient;
    
    WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
           WindowState attachedWindow, int appOp, int seq, WindowManager.LayoutParams a,
           int viewVisibility, final DisplayContent displayContent) {
           
        ...
        mService = service;
        mSession = s;
        mClient = c;
        ...   
    }
}

在WMS中:

public int addWindow(Session session, IWindow client, int seq,
        WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
        Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
        InputChannel outInputChannel) {
        ...
        final WindowState win = new WindowState(this, session, client, token, parentWindow,
            appOp[0], seq, attrs, viewVisibility, session.mUid,
            session.mCanAddInternalSystemWindow);
        ...
        win.attach();
        ...
}

我們看到在WMS中我們將這些核心的參數(shù)傳遞進(jìn)去,比如Session,client等。

上面這兩段代碼說(shuō)明,WindowState持有WMS,client,mSession的引用。持有這些引用就可以管理。Session我們知道,就是每一個(gè)WindowManagerGlobal持有唯一的一個(gè)由WMS產(chǎn)生的Session與app進(jìn)程對(duì)應(yīng)。client是什么?

這個(gè)就又要追溯到我們Activity的啟動(dòng)時(shí)候了。(也就是我們?cè)贏T.handleLaunchActivity中寫的1.3)

1.3

ActivityThread

final void handleResumeActivity(IBinder token,
        boolean clearHide, boolean isForward, boolean reallyResume) {
    //執(zhí)行到onResume方法()
    ActivityClientRecord r = performResumeActivity(token, clearHide);
    if (r != null) {
        final Activity a = r.activity;
        ...
        if (...) {
            ...
            mNumVisibleActivities++;
            if (...) {
                //添加視圖[1.3.1]
                r.activity.makeVisible(); 
            }
        }
        ...
    } else {
        ...
    }
}

1.3.1

Activity.makeVisible

void makeVisible() {
    if (!mWindowAdded) {
        ViewManager wm = getWindowManager();//得到WindowManagerImpl對(duì)象此對(duì)象內(nèi)部擁有WindowManagerGlobal 
        
        wm.addView(mDecor, getWindow().getAttributes());//[1.3.2]
        mWindowAdded = true;
    }
    mDecor.setVisibility(View.VISIBLE);
}

1.3.2

@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    applyDefaultToken(params);
    mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}

在這里也可以看的出來(lái),WindowManagerImpl其實(shí)都是轉(zhuǎn)調(diào)WindowManagerGlobal進(jìn)行操作。

WindowManagerGlobal

public void addView(View view, ViewGroup.LayoutParams params,
        Display display, Window parentWindow) {
        root = new ViewRootImpl(view.getContext(), display);
        mViews.add(view);//這里的View是頂層View
        mRoots.add(root);
        mParams.add(wparams);
        try {
            root.setView(view, wparams, panelParentView);
        } catch (RuntimeException e) {
            ...
            throw e;
        }
}

我們看到利用ViewRootImpl去做setView的工作。

public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
    final W mWindow;
    
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
        
            mView = view;//將頂層View保存
            res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
            ...
        }
}

mWindowSession是持有WMS里面的Session,使用addToDisplay,我們將mWindow也就是W對(duì)象傳入到Session。所以WMS就可以通過(guò)W對(duì)象與應(yīng)用程序進(jìn)行通信了。

我們最后小結(jié)核心就好:

  • WindowManagerImpl持有WindowManagerGlobal的引用
  • WindowManagerGlobal可以和WMS進(jìn)行通信
  • PhoneWindow可以得到WindowManagerImpl
  • PhoneWindow在actvitiy的attach中創(chuàng)建
  • WindowManagerGlobal.getWindowSession()得到WMS中Session(Binder)的代理
  • ViewRootImpl持有sessopn代理
  • ViewRootImpl中創(chuàng)建W對(duì)象
  • W對(duì)象在activity啟動(dòng)過(guò)程中setView方法到了WMS中
  • WMS在addView過(guò)程中通過(guò)WindowState將Session與W代理和WMS引用都保存。

應(yīng)用向WMS通信

image.png

WMS向應(yīng)用通信

image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容