Activity和WMS的雙向通信

說雙向通信之前,首先了解下WindowManagerGlobalViewRootImpl的創建

WindowManagerGlobal的創建

創建過程如下圖

image.png

  • ActivityManagerService->ActivityThread
    AMS裏面的main函數裏會創建ActivityThread
public static void main(String[] args) {
//省略...
 ActivityThread thread = new ActivityThread();
//省略...
}

ActivityThread是應用程序的UI線程,它主要負責對Android四大組件的創建和管理,以及控制Activity的生命週期等。

  • ActivityThread-> WindowManagerGlobal

當我們執行startActivity啓動一個頁面時,最終會執行到ActivityThread
handlerLauncherActivity方法來。在這個方法裏,會創建一個WindowManagerGlobal

  private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
       //省略...
        // 創建Activity之前初始化WindowManagerGlobal
        WindowManagerGlobal.initialize();
       //省略...
    }

ViewRootImpl創建

創建過程如下圖

image.png

  • ActivityThread->Activity

創建Activity也是在AndroidThreadhandleLauncherActivity方法裏面,創建完WindowManagerGlobal之後調用

  private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
       //省略...
        // 創建Activity之前初始化WindowManagerGlobal
        Activity a = performLaunchActivity(r, customIntent);
       //省略...
    }
  • Activity->PhoneWindow
    來到performLaunchActivity方法裏面創建Activity,並且會執行Activityattach方法來創建PhoneWindow
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    //省略...
    Activity activity = null;
 //省略...
 try {
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            //省略...
        } catch (Exception e) {
             //省略...
        }
}
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, window);
     //省略...

}

- PhoneWindow->WindowManagerImpl

Activity裏的attach方法創建完PhoneWindow之後會執行WindowsetWindowManager方法。

 final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window) {
  //省略...
        mWindow = new PhoneWindow(this, window);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
  //省略...
 mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        if (mParent != null) {
            mWindow.setContainer(mParent.getWindow());
        }
        mWindowManager = mWindow.getWindowManager();
  //省略...
}

PhoneWindow它是Window的唯一實現類,它會在setContentView方法裏面創建DecoView,然後DecoView會添加一個id爲content的FrameLayout作爲根佈局,關係如下圖
PhoneWindow.png
創建好PhoneWindow後,繼續執行WindowsetWindowManager方法,去創建WindowManagerImpl對象

 public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
            boolean hardwareAccelerated) {
        mAppToken = appToken;
        mAppName = appName;
        mHardwareAccelerated = hardwareAccelerated
                || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
        if (wm == null) {
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }
  • WindowManagerImpl->WindowManagerGlobal

WindowManagerImpl裏面會和WindowManagerGlobal進行關聯,從而通過addView方法,removeView等方法來做爲管理View的橋樑,傳遞給WindowManagerGlobal

private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
 @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }
   @Override
    public void removeView(View view) {
        mGlobal.removeView(view, false);
    }

調用WindowManagerImpladdView的位置主要有兩個地方
1.ActivitymakeVisible方法會調用

  void makeVisible() {
        if (!mWindowAdded) {
            ViewManager wm = getWindowManager();
            wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;
        }
        mDecor.setVisibility(View.VISIBLE);
    }
  1. ActivityThreadhandleResumeActivity會直接執行addView方法
      final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
    //省略...
if (r.window == null && !a.mFinished && willBeVisible) {
//省略...
 if (a.mVisibleFromClient && !a.mWindowAdded) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l);
    }
}

//省略...
  if (!r.activity.mFinished && willBeVisible
                    && r.activity.mDecor != null && !r.hideForNow) {
    //省略...
     if (r.activity.mVisibleFromClient) {
                    r.activity.makeVisible();
     }
    //省略...
}
}

在添加DecoView的時候會調用addView方法,添加DecoViewView的時候就直接調用ActivitymakeVisible的方法,然後在makeVisible調用addView方法。

  • WindowManagerGlobal->ViewRootImpl

WindowManagerGlobaladdView方法裏面會創建ViewRootImpl

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

ViewRootImpl它主要管理Window中所有的View的類,每個Activity中ViewRootImpl的數量取決於調用mWindowManager.addView的調用次數,Activity提供與AMS通信的Token(IBinder對象),創建Window爲View提供顯示的地方,而具體的View管理任務由ViewRootImpl來完成。

Activity->WMS通信

Activity到WMS通信主要是通過WindowManagerGlobalViewRootImpl來完成的,上面說到WindowManagerGlobalinitialize方法

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

首先可以知道WindowManagerGlobal是個單例,最終調用的是getWindowManagerService方法。ServiceManager.getService("window")獲取一個IBinder對象,來到getService方法

    public static IBinder getService(String name) {
        try {
            IBinder service = sCache.get(name);
            if (service != null) {
                return service;
            } else {
                return getIServiceManager().getService(name);
            }
        } catch (RemoteException e) {
            Log.e(TAG, "error in getService", e);
        }
        return null;
    }

然後來到getIServiceManager()方法

  private static IServiceManager getIServiceManager() {
        if (sServiceManager != null) {
            return sServiceManager;
        }

        // Find the service manager
        sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
        return sServiceManager;
    }

這裏可以通過如下圖來解釋

圖片來源<a href=https://blog.csdn.net/luoshengyang/article/details/6642463羅老師博客.png” title=”” />

BinderInternal.getContextObject()其實獲取的是BinderProxy這個代理類,然後通過asInterface()方法傳給IServiceManager的代理類ServiceManagerProxy,也是ServiceManagerJava遠程接口,從而實現Binder通信。

然後回到getService()方法,傳入一個name參數,然後通過name獲取指定的service,比如這裏傳入的是window,也就是獲取到WindowManagerService對應的IBinder對象。最後調用IWindowManager.Stub.asInterface()方法獲取到WindowManagerService的抽象類IWindowManager

獲取到WMS之後,然後會在ViewRootImpl初始化的時候調用openSession,獲取IWindowSession

 final IWindowSession mWindowSession;
 public ViewRootImpl(Context context, Display display) {
      mWindowSession = WindowManagerGlobal.getWindowSession();
}

getWindowSession方法

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;
        }
    }

通過上面獲取到的IWindowManager去調用openSession獲取IWindowSession對象。然後通過IWindowSession進行通信。如下圖
image.png
IWindowSessionClient端的代理,而它的Server端是SessionSession接收到請求後,就會轉交給WMS進行處理。流程如下圖

時序圖.png

這樣就實現了ActivityWMS的通信

WMS -> Activity通信

WMSActivity通信,也是使用的代理模式,通過IWindow.Stub接口來實現,而WMS的代理對象就是在ViewRootImpl裏面的W內部類,它通過上面獲取的IWindowSession來在ViewRootImplsetView方法裏面調用addToDisplay方法把W代理傳遞給WMS

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

它傳遞的第一個參數mWindow就是WmWindow中保存了W類型的Binder本地對象,這樣通過函數addToDisplay就可以將W的代理對象傳遞Session然後給WMS服務。SessionaddToDisplay如下

 @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);
    }

然後來到WindowManagerServiceaddWindow方法,從這裏可以看出每次ViewRootImplsetView調用一次,對應一個Session請求。然後來到addWindow方法裏面,在裏面創建了一個WindowState對象,並且把W保存的Binder對象和Session保存在WindowState中,

public int addWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            InputChannel outInputChannel) {
      //省略...
       WindowState win = new WindowState(this, session, client, token,
                    attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
      //省略...
    win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
     win.attach();
      win.applyScrollIfNeeded();
    win.applyAdjustForImeIfNeeded();
}

創建WindowState

WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
           WindowState attachedWindow, int appOp, int seq, WindowManager.LayoutParams a,
           int viewVisibility, final DisplayContent displayContent) {
  mWindowId = new IWindowId.Stub() {
            @Override
            public void registerFocusObserver(IWindowFocusObserver observer) {
                WindowState.this.registerFocusObserver(observer);
            }
            @Override
            public void unregisterFocusObserver(IWindowFocusObserver observer) {
                WindowState.this.unregisterFocusObserver(observer);
            }
            @Override
            public boolean isFocused() {
                return WindowState.this.isFocused();
            }
        };
}

創建IWindowId主要是用於標識指定窗口。它會在ViewgetWindowId方法裏面獲取到。

綜上,WMSActivity的通信主要是通過IWindow的代理對象W來進行通信。過程如下

WMS到Activity.png

Activity到WMS是通過IWindowSession來通信,WMS到Activity是通過IWindow代理w來通信

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章