简介
我之前分析过,但是感觉当时迷迷糊糊的,自己也没彻底弄清楚,今天我再次突破,这次感觉比以前清楚了,为什么要写这个关系,因为在项目中Activity中见到Window win = getWindow();
这种写法。所以要想了解Wundow类我们就要明白WMS与我们的应用到底有什么联系。
应用于WMS关联的来源
AT.handleLaunchActivity
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
handleConfigurationChanged(null, null);
//获取WMS代理对象
WindowManagerGlobal.initialize();//[1.1]
Activity a = performLaunchActivity(r, customIntent);//[1.2]
if (a != null) {
//最终回调目标Activity的onStart,onResume.
handleResumeActivity(r.token, false, r.isForward, !r.activity.mFinished && !r.startsNotResumed);//[1.3]
...
} else {
...
}
...
}
1.1
我们在WindowManagerGlobal.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;
}
}
...
}
通过这里可以看到WindowManagerGlobal 持有WMS的Binder代理并且唯一。
1.2
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Activity activity = null;
//获取ClassLoader
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
//创建目标Activity对象
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
...
//创建Application对象
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;
}
- 创建目标Activity对象
- 创建Application对象
- 执行
activity.attach()
2.1
public class Activity extends ContextThemeWrapper implements ... {
private Window mWindow;
final void attach(...) {
...
mWindow = new PhoneWindow(this); //创建PhoneWindow
...
mUiThread = Thread.currentThread(); //获取UI线程
mToken = token; //远程ActivityRecord的appToken的代理端
mApplication = application; //所属的Appplication
...
//设置并获取WindowManagerImpl对象
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);
...
}
我们看到通过mWindow.setWindowManager()
这个方法我们创建并获取了WindowManagerImpl对象
public final class WindowManagerImpl implements WindowManager {
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
....
}
这里我们就看出,当Activity执行到attach方法的时候就会创建PhoneWindow,PhoneWindow创建WindowManagerImpl,WindowManagerImpl持有WindowManagerGlobal
所以每个Activity的mWindowManager 是WindowManagerImpl对象,WindowManagerImpl 存有WindowManagerGlobal这个对象是进程唯一。
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这个对象管理当前进程里面所有的View(DecorView),ViewRootImpl,WindowManager.LayoutParams(顶层View的layout参数)
应用程序如何通知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;
}
}
由于前面说过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对象。因此WMS将这个Binder代理返回给了应用程序,这样应用程序就可以通过WindowManagerGlobal 与WMS进行通信了。其中WindowManagerGlobal持有的sWindowSession是WMS中的Session代理对象。
小结
也就是当前应用中有一份WindowManagerGlobal 唯一,这里有WMS的代理也有ViewRootImpl,ViewRootImpl 中的sWindowSession变量映射着WMS的Session Binder代理。
WMS如何通知应用程序呢?
要想知道这个问题我们就要研究ViewRootImpl这个类,我们就从它的成员变量开始:
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对象,这个对象是Binder对象。
与此同时我们应该看看WindowState对象。
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中我们将这些核心的参数传递进去,比如Session,client等。
上面这两段代码说明,WindowState持有WMS,client,mSession的引用。持有这些引用就可以管理。Session我们知道,就是每一个WindowManagerGlobal持有唯一的一个由WMS产生的Session与app进程对应。client是什么?
这个就又要追溯到我们Activity的启动时候了。(也就是我们在AT.handleLaunchActivity中写的1.3)
1.3
ActivityThread
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume) {
//执行到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对象此对象内部拥有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);
}
在这里也可以看的出来,WindowManagerImpl其实都是转调WindowManagerGlobal进行操作。
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对象传入到Session。所以WMS就可以通过W对象与应用程序进行通信了。
我们最后小结核心就好:
- WindowManagerImpl持有WindowManagerGlobal的引用
- WindowManagerGlobal可以和WMS进行通信
- PhoneWindow可以得到WindowManagerImpl
- PhoneWindow在actvitiy的attach中创建
- WindowManagerGlobal.getWindowSession()得到WMS中Session(Binder)的代理
- ViewRootImpl持有sessopn代理
- ViewRootImpl中创建W对象
- W对象在activity启动过程中setView方法到了WMS中
- WMS在addView过程中通过WindowState将Session与W代理和WMS引用都保存。