前两天写Activity启动流程时挖个坑,ActivityThread调用Activity.resume后,紧接着调用WindowManager.addView()用来正在的显示View,以前讲的很草率,如今感受有必要写一下WindowManager的调用流程。android
本文基于android8.1.0_r15分支分析缓存
WindowManager简单介绍bash
首先WindowManager是一个接口继承自ViewManager,它做用是用于窗口的管理,咱们平时的使用比较多的是addView方法和LayoutParams参数,addView定义在基类ViewManager中,源码:session
ViewManagerapp
public interface ViewManager
{
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
}
复制代码
一共三个方法比较简单,注意看参数类型,咱们平时用WindowManager时候传的是WindowManager.LayoutParams,这里定义的是ViewGroup.LayoutParams params,我想确定前者继承后者吧,啥都不说,看看WindowManager.LayoutParams定义;ide
经常使用的type值ui
WindowManager毕竟只是一个接口,真正的实如今哪里?回想在ActivityThread.handleResumeActivity()中,调用了activity.getWindowManager(),咱们定位到Activity:this
Activity#getWindowManagerspa
public WindowManager getWindowManager() {
return mWindowManager;
}
复制代码
在Activity#getSystemService()中一样能够获得代理
@Override
public Object getSystemService(@ServiceName @NonNull String name) {
if (getBaseContext() == null) {
throw new IllegalStateException(
"System services not available to Activities before onCreate()");
}
//WINDOW_SERVICE比较特殊,不调用super的
if (WINDOW_SERVICE.equals(name)) {
return mWindowManager;
} else if (SEARCH_SERVICE.equals(name)) {
ensureSearchManager();
return mSearchManager;
}
return super.getSystemService(name);
}
复制代码
咱们注意到在调用getSystemService时,WINDOW_SERVICE比较特殊,没有调用super,直接返回mWindowManager,为何呢,咱们留到后文说;
mWindowManager何时赋值的呢,咱们在Activity.attach中找到了代码
Activity.attach
//设置系统的WindowManager
mWindow.setWindowManager(
//获取系统的WindowManager
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
//拿Window对象的
mWindowManager = mWindow.getWindowManager();
复制代码
也是直接获取系统的,可是通过mWindow转手了,这是为何呢,Window关于setWindowManager()定义
Window#setWindowManager
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,咱们查看WindowManagerImpl.addView方法:
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
调用mGlobal
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
@Override
public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.updateViewLayout(view, params);
}
private void applyDefaultToken(@NonNull ViewGroup.LayoutParams params) {
if (mDefaultToken != null && mParentWindow == null) {
if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
if (wparams.token == null) {
wparams.token = mDefaultToken;
}
}
}
复制代码
方法体首先执行applyDefaultToken,对wparams赋token值,而后直接调用mGlobal对应的方法,mGlobal是WindowManagerGlobal类型,它也继承自WindowManager么?接下来分析WindowManagerGlobal
WindowManagerGlobal
WindowManagerGlobal并非继承WindowManager,可是有着同样的方法名,这不是代理模式么,它一样有addView、updateViewLayout、removeView方法,咱们从addView方法分析
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
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");
}
//转成WindowManager.LayoutParams对象
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
//显示Activity的话window确定不为空
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;
View panelParentView = null;
synchronized (mLock) {
// Start watching for system property changes.
if (mSystemPropertyUpdater == null) {
mSystemPropertyUpdater = new Runnable() {
@Override public void run() {
synchronized (mLock) {
for (int i = mRoots.size() - 1; i >= 0; --i) {
mRoots.get(i).loadSystemProperties();
}
}
}
};
SystemProperties.addChangeCallback(mSystemPropertyUpdater);
}
//从mViews集合查找有没有添加过
int index = findViewLocked(view, false);
//有则调用对应的ViewRootImpl.doDie
if (index >= 0) {
if (mDyingViews.contains(view)) {
mRoots.get(index).doDie();
} else {
throw new IllegalStateException("View " + view
+ " has already been added to the window manager.");
}
// The previous removeView() had not completed executing. Now it has.
}
// If this is a panel window, then find the window it is being
// attached to for future reference.
if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
final int count = mViews.size();
for (int i = 0; i < count; i++) {
if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
panelParentView = mViews.get(i);
}
}
}
//建立ViewRootImpl对象
root = new ViewRootImpl(view.getContext(), display);
//参数最终给了decor
view.setLayoutParams(wparams);
mViews.add(view);//把Decor存起来
mRoots.add(root);//把ViewRootImpl纯起来
mParams.add(wparams);//把参数存起来
// do this last because it fires off messages to start doing things
try {
//设置View
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}
复制代码
简单分析addView做用:
继续分析updateViewLayout和removeView方法:
WindowManagerGlobal#updateViewLayout#removeView
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
if (view == null) {
throw new IllegalArgumentException("view must not be null");
}
if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
view.setLayoutParams(wparams);
synchronized (mLock) {
//去除以前的view对应的下标
int index = findViewLocked(view, true);
//缓存的root
ViewRootImpl root = mRoots.get(index);
//mParams集合从新添加
mParams.remove(index);
mParams.add(index, wparams);
//最终调用viewRootImpl的setLayoutParams
root.setLayoutParams(wparams, false);
}
}
public void removeView(View view, boolean immediate) {
if (view == null) {
throw new IllegalArgumentException("view must not be null");
}
synchronized (mLock) {
//集合里的全都删除掉
int index = findViewLocked(view, true);
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);
}
}
private void removeViewLocked(int index, boolean immediate) {
ViewRootImpl root = mRoots.get(index);
View view = root.getView();
if (view != null) {
InputMethodManager imm = InputMethodManager.getInstance();
if (imm != null) {
//关掉输入法
imm.windowDismissed(mViews.get(index).getWindowToken());
}
}
//调用ViewRootImpl.die
boolean deferred = root.die(immediate);
if (view != null) {
view.assignParent(null);
if (deferred) {
mDyingViews.add(view);
}
}
}
复制代码
更新和删除的代码比较简单,注释说的很清楚了,只要就是管理集合和调用ViewRootImpl的对应代码
调用顺序总结:
意义总结:
到这里尚未真正的看到IPC调用,由于一层一层代理,到了RootViewImpl这一层,真假美猴王应该能分晓了吧。
RootViewImpl调用IPC
上文分析RootViewImpl在WindowManagerGlobal.addView中构造,而且有三个方法setView()、setLayoutParams()、doDie()被调用,可是看了RootViewImpl代码头发有些发麻,代码量太大了。
因为鄙人水平有些,这篇博客只拿出它和WMS的IPC调用过程分析,这代码只能一片一片剖析。见谅啊!开始吧。
RootViewImpl构造方法
咱们发现RootViewImpl构造方法建立了两个window相关的对象,分别是
mWindowSession = WindowManagerGlobal.getWindowSession();
mWindow = new W(this);
复制代码
跟进WindowManagerGlobal看个究竟
WindowManagerGlobal#getWindowSession#getWindowManagerService
//获取WindowSession
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
InputMethodManager imm = InputMethodManager.getInstance();
IWindowManager windowManager = getWindowManagerService();
//通知WMS开启一个新的Session
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;
}
}
//获取WindowManagerService
public static IWindowManager getWindowManagerService() {
synchronized (WindowManagerGlobal.class) {
if (sWindowManagerService == null) {
sWindowManagerService = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
try {
if (sWindowManagerService != null) {
ValueAnimator.setDurationScale(
sWindowManagerService.getCurrentAnimatorScale());
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowManagerService;
}
}
复制代码
再看W这个类,它继承自IWindow.Stub,若是看过Activity启动流程的应该知道,这个W和ApplicationThread同样的道理啊,咱们接着看ViewRootImpl关键是的三个方法有没有mWindowSession和mWindow的调用
ViewRootImpl#setView
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
复制代码
ViewRootImpl#doDie
mWindowSession.finishDrawing(mWindow);
复制代码
IWindowSession.aild
interface IWindowSession {
int add(IWindow window, int seq, in WindowManager.LayoutParams attrs,
in int viewVisibility, out Rect outContentInsets, out Rect outStableInsets,
out InputChannel outInputChannel);
int addToDisplay(IWindow window, int seq, in WindowManager.LayoutParams attrs,
in int viewVisibility, in int layerStackId, out Rect outContentInsets,
out Rect outStableInsets, out Rect outOutsets, out InputChannel outInputChannel);
int addWithoutInputChannel(IWindow window, int seq, in WindowManager.LayoutParams attrs,
in int viewVisibility, out Rect outContentInsets, out Rect outStableInsets);
int addToDisplayWithoutInputChannel(IWindow window, int seq, in WindowManager.LayoutParams attrs,
in int viewVisibility, in int layerStackId, out Rect outContentInsets,
out Rect outStableInsets);
void remove(IWindow window);
...
}
复制代码
IWindow.aidl
oneway interface IWindow {
void executeCommand(String command, String parameters, in ParcelFileDescriptor descriptor);
void resized(in Rect frame, in Rect overscanInsets, in Rect contentInsets,
in Rect visibleInsets, in Rect stableInsets, in Rect outsets, boolean reportDraw,
in MergedConfiguration newMergedConfiguration, in Rect backDropFrame,
boolean forceLayout, boolean alwaysConsumeNavBar, int displayId);
void moved(int newX, int newY);
void dispatchAppVisibility(boolean visible);
void dispatchGetNewSurface();
void windowFocusChanged(boolean hasFocus, boolean inTouchMode);
void closeSystemDialogs(String reason);
...
}
复制代码
Session#addToDisplay
@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
Rect outOutsets, InputChannel outInputChannel) {
//调用WindowManagerService的addWindow
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outStableInsets, outOutsets, outInputChannel);
}
复制代码
WindowManagerService#addWindow
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
InputChannel outInputChannel) {
int[] appOp = new int[1];
int res = mPolicy.checkAddPermission(attrs, appOp);
if (res != WindowManagerGlobal.ADD_OKAY) {
return res;
}
boolean reportNewConfig = false;
WindowState parentWindow = null;
long origId;
final int callingUid = Binder.getCallingUid();
final int type = attrs.type;
synchronized(mWindowMap) {
if (!mDisplayReady) {
throw new IllegalStateException("Display has not been initialialized");
}
...
}
}
复制代码
既然涉及到binder双向通讯,app端确定得有handle来处理,果真在ViewRootImpl中定义了ViewRootHandler
这个类。
ViewRootHandler
final class ViewRootHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_INVALIDATE:
((View) msg.obj).invalidate();
break;
case MSG_INVALIDATE_RECT:
final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj;
info.target.invalidate(info.left, info.top, info.right, info.bottom);
info.recycle();
break;
case MSG_PROCESS_INPUT_EVENTS:
mProcessInputEventsScheduled = false;
doProcessInputEvents();
break;
case MSG_DISPATCH_APP_VISIBILITY:
handleAppVisibility(msg.arg1 != 0);
break;
case MSG_DISPATCH_GET_NEW_SURFACE:
handleGetNewSurface();
break;
case MSG_RESIZED: {
// Recycled in the fall through...
SomeArgs args = (SomeArgs) msg.obj;
if (mWinFrame.equals(args.arg1)
&& mPendingOverscanInsets.equals(args.arg5)
&& mPendingContentInsets.equals(args.arg2)
&& mPendingStableInsets.equals(args.arg6)
&& mPendingVisibleInsets.equals(args.arg3)
&& mPendingOutsets.equals(args.arg7)
&& mPendingBackDropFrame.equals(args.arg8)
&& args.arg4 == null
&& args.argi1 == 0
&& mDisplay.getDisplayId() == args.argi3) {
break;
}
}
...
}
}
复制代码
画一张图标识记忆一下吧。