以前就知道有WindowManagerService这个东西,知道addView最终是跟WindowManagerService进行交互的,但是一直没有深入去看,去理解。
然后到网上搜搜资料。
看到老罗的文章后
http://blog.csdn.net/luoshengyang/article/details/8462738
我发现我更不懂了。还是试着自己看源码,自己尝试着去理解,虽然可能没有他理解的那么深刻,还有结构图,时序图,但是整个流程至少自己可以走通。
下面就贴上代码,把整个流程跑一遍。
注意:Android源码 2.3.1
这里我就从new Activity开始。
frameworks/base/core/java/android/app/ActivityThread
private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
...
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
...
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstance,
r.lastNonConfigurationChildInstances, config);
...
}
接收到AMS发来的消息后,开始创建Activity。
frameworks/base/core/java/android/app/Activity
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,
Object lastNonConfigurationInstance,
HashMap<String,Object> lastNonConfigurationChildInstances,
Configuration config) {
attachBaseContext(context);
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
...
mWindow.setWindowManager(null, mToken, mComponent.flattenToString());
...
}
本文就不过多的介绍中间跳转的过程了,因为直接会有很方法重载,我就直接贴出关键的调用代码,希望大家能自己跟一遍,对理解,记忆都非常有好处。
这里最重要的3行代码
-
PolicyManager.makeNewWindow
创建了PhoneWindow - 给PhoneWindow设置callback,也就是Activity本身。
- setWindowManager
frameworks/base/core/java/android/view/Window
public void setWindowManager(WindowManager wm,
IBinder appToken, String appName) {
mAppToken = appToken;
mAppName = appName;
if (wm == null) {
wm = WindowManagerImpl.getDefault();
}
mWindowManager = new LocalWindowManager(wm);
}
}
public WindowManager getWindowManager() {
return mWindowManager;
}
虽然getWindowManager得到的是LocalWindowManager,但是其实
LocalWindowManager可以算个代理类,里面很多方法的具体实现还是在WindowManagerImpl。
其实我们当前分析的addView,以及与WMS交互流程会比前面AMS交互要难,因为AMS交互大部分的过程都是连续的,可以一步走到底,可是我们现在分析的就很难一步走到底。当然这是我的个人感觉。
现在newActivity创建了一些变量,走不下去,我们就继续回过头看看。其实这个时候触发了Activity的onCreate方法了。
frameworks/base/core/java/android/app/ActivityThread
private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
mInstrumentation.callActivityOnCreate(activity, r.state);
...
}
回调我们写的onCreate。而这时候我们一般会setContentView去设置布局。
frameworks/base/core/java/android/app/Activity
public void setContentView(int layoutResID) {
getWindow().setContentView(layoutResID);
}
...
public Window getWindow() {
return mWindow;
}
...
getWindow其实获取到的就是刚才初始化Activity中的mWindow,也就是PhoneWindw.
frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindow
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();
} else {
mContentParent.removeAllViews();
}
mLayoutInflater.inflate(layoutResID, mContentParent);
final Callback cb = getCallback();
if (cb != null) {
cb.onContentChanged();
}
}
...
private void installDecor() {
if (mDecor == null) {
mDecor = generateDecor();
...
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
...
}
}
protected DecorView generateDecor() {
return new DecorView(getContext(), -1);
}
...
protected ViewGroup generateLayout(DecorView decor) {
...
View in = mLayoutInflater.inflate(layoutResource, null);
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
...
}
...
这里代码 稍微有点多,但是逻辑上很简单,基本上都能看得懂。首先是前面调用了Activity的setContentView,其实最终是调用了PhoneWindow的setContentView。
在PhoneWindow中会判断是否创建了DecorView。如果没有创建的话,就会new DecorView 然后再根据用户设置的主题还有属性,获取到对应的layout布局,然后inflater之后(这里姑且把inflater之后的布局叫做RootView)add到DecorView之中。RootView其实是一个LinearLayout,分为三大块,状态栏,标题栏,用户的内容栏(其实就是一个FrameLayout)。
最后其实是调用了mLayoutInflater.inflate(layoutResID, mContentParent);
把setContentView设置的layout,inflater之后add到用户的内容栏中。
到了这一步之后,发现又无路可走了,再往前看看,performLaunchActivity
也已经执行完了。然后确实是不知道下一步到底怎么走了,然后我搜了搜,其实这个时候触发了handleResumeActivity
frameworks/base/core/java/android/app/ActivityThread
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
...
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (a.mVisibleFromClient) {
a.mWindowAdded = true;
wm.addView(decor, l);
}
...
}
这几句代码很关键,因为我们知道其实整个界面最底层的其实是PhoneWindow,然后是DecorView,然后是RootView,接下来才是我们自己的View.前面流程只讲了创建DecorView然后add RootView 然后add 我们自定义的layout。
而这几句代码才把DecorView add到PhoneWindow中。
上面的getWindowManager()其实是LocalWindowManager,不过
LocalWindowManager其实只能算是一个代理类,具体的实现在WindowManagerImpl中。
frameworks/base/core/java/android/View/WindowManagerImpl
private void addView(View view, ViewGroup.LayoutParams params, boolean nest)
{
...
ViewRoot root;
...
root = new ViewRoot(view.getContext());
...
root.setView(view, wparams, panelParentView);
}
ViewRoot在添加View的过程中是很重要的一个角色,现在终于出现了,我当前android源码是2.3.1,后面的版本中,ViewRoot被替换成了ViewRootImpl,但是这并没有什么关系,我们能把 这里的源码看懂了,新版中虽然有改动,但是还是能很快的理解的。
frameworks/base/core/java/android/View/ViewRoot
public static IWindowSession getWindowSession(Looper mainLooper) {
synchronized (mStaticInit) {
if (!mInitialized) {
try {
InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
sWindowSession = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"))
.openSession(imm.getClient(), imm.getInputContext());
mInitialized = true;
} catch (RemoteException e) {
}
}
return sWindowSession;
}
}
public ViewRoot(Context context) {
super();
...
getWindowSession(context.getMainLooper());
...
}
看到getWindowSession这个方法其实会感到非常的熟悉,因为在前面AMS中也出现过相同的代码,就是创建一个代理类与ActivityManagerService利用Binder机制进行交互。这里也是一样的。是与WindowManagerService建立连接。
虽然代码看过去挺像的,但又有点不太一样,这里会比ActivityManagerService那里会稍微复杂点。下面我来具体分析下。
out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/view/IWindowManager
...
...
case TRANSACTION_openSession:
{
data.enforceInterface(DESCRIPTOR);
com.android.internal.view.IInputMethodClient _arg0;
_arg0 = com.android.internal.view.IInputMethodClient.Stub.asInterface(data.readStrongBinder());
com.android.internal.view.IInputContext _arg1;
_arg1 = com.android.internal.view.IInputContext.Stub.asInterface(data.readStrongBinder());
android.view.IWindowSession _result = this.openSession(_arg0, _arg1);
reply.writeNoException();
reply.writeStrongBinder((((_result!=null))?(_result.asBinder()):(null)));
return true;
}
...
public android.view.IWindowSession openSession(com.android.internal.view.IInputMethodClient client, com.android.internal.view.IInputContext inputContext) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
android.view.IWindowSession _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((client!=null))?(client.asBinder()):(null)));
_data.writeStrongBinder((((inputContext!=null))?(inputContext.asBinder()):(null)));
mRemote.transact(Stub.TRANSACTION_openSession, _data, _reply, 0);
_reply.readException();
_result = android.view.IWindowSession.Stub.asInterface(_reply.readStrongBinder());
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
...
使用Binder机制与WindowManagerService交互,调用WindowManagerService的openSession方法
frameworks/base/services/java/com/android/server/WindowManagerService
...
public IWindowSession openSession(IInputMethodClient client,
IInputContext inputContext) {
if (client == null) throw new IllegalArgumentException("null client");
if (inputContext == null) throw new IllegalArgumentException("null inputContext");
Session session = new Session(client, inputContext);
return session;
}
...
private final class Session extends IWindowSession.Stub
implements IBinder.DeathRecipient {
...
}
这个过程虽然有点复杂,但是还算连续,有了前面阅读过AMS源码经验,这里其实也是可以接受的。
最终的结果就是,调用WindowManagerService的openSession创建一个Session对象,这个Session对象其实也是IWindowSession.Stub的子类。然后把session这个对象重新write回来。然后调用
_result = android.view.IWindowSession.Stub.asInterface(_reply.readStrongBinder());
在App进程中,读取到这个Session后,使用Binder机制,在本地创建IWindowSession.Stub.Proxy对象与WindowManagerService那边的Session对象建立连接。
虽然只是一句简单的代码
sWindowSession = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"))
.openSession(imm.getClient(), imm.getInputContext());
但是里面涉及到了好多。
最终返回的sWindowSession,其实是一个IWindowSession.Stub.Proxy对象,用来与WindowManagerService的Session建立连接。
其实ViewRoot初始化的时候还有一个重要的变量。
public ViewRoot(Context context) {
...
mWindow = new W(this, context);
...
}
在前面介绍AMS的时候,我们都知道,App进程使用ActivityManagerProxy与ActivityManagerService进行交互,而ActivityManagerService则是使用ApplicationThreadProxy与App进程中的ApplicationThread进行交互。
大同小异,WindowManagerService想与App端进行交互,那么也需要一个类似ApplicationThread这样的Binder来接收WindowManagerService传递过来的信息。它就是W这个类。
那么我们继续往下看。
还是回到刚才的WindowManagerImpl,创建好了ViewRoot之后。
frameworks/base/core/java/android/view/WindowManagerImpl
private void addView(View view, ViewGroup.LayoutParams params, boolean nest)
{
private void addView(View view, ViewGroup.LayoutParams params, boolean nest)
{
...
ViewRoot root;
...
root = new ViewRoot(view.getContext());
...
root.setView(view, wparams, panelParentView);
}
继续是调用ViewRoot的setView
public void setView(View view, WindowManager.LayoutParams attrs,
View panelParentView) {
...
...
res = sWindowSession.add(mWindow, mWindowAttributes,
getHostVisibility(), mAttachInfo.mContentInsets,
mInputChannel);
...
}
调用刚才获取到的Session代理的add方法
out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/view/IWindowSession
...
...
case TRANSACTION_add:
{
data.enforceInterface(DESCRIPTOR);
android.view.IWindow _arg0;
_arg0 = android.view.IWindow.Stub.asInterface(data.readStrongBinder());
android.view.WindowManager.LayoutParams _arg1;
if ((0!=data.readInt())) {
_arg1 = android.view.WindowManager.LayoutParams.CREATOR.createFromParcel(data);
}
else {
_arg1 = null;
}
int _arg2;
_arg2 = data.readInt();
android.graphics.Rect _arg3;
_arg3 = new android.graphics.Rect();
android.view.InputChannel _arg4;
_arg4 = new android.view.InputChannel();
int _result = this.add(_arg0, _arg1, _arg2, _arg3, _arg4);
reply.writeNoException();
reply.writeInt(_result);
if ((_arg3!=null)) {
reply.writeInt(1);
_arg3.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else {
reply.writeInt(0);
}
if ((_arg4!=null)) {
reply.writeInt(1);
_arg4.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else {
reply.writeInt(0);
}
return true;
}
...
public int add(android.view.IWindow window, android.view.WindowManager.LayoutParams attrs, int viewVisibility, android.graphics.Rect outContentInsets, android.view.InputChannel outInputChannel) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((window!=null))?(window.asBinder()):(null)));
if ((attrs!=null)) {
_data.writeInt(1);
attrs.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
_data.writeInt(viewVisibility);
mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
if ((0!=_reply.readInt())) {
outContentInsets.readFromParcel(_reply);
}
if ((0!=_reply.readInt())) {
outInputChannel.readFromParcel(_reply);
}
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
...
还是使用Binder机制,调用了WindowManagerService下的Session对象的add方法。
其中值得关注的是,这里把我刚才提到的mWindow也就是W对象write给了WindowManagerService的Session,其实跟AMS的交互是一样的。Session那边可以利用W对象与App进程进行交互。
...
public int addWindow(Session session, IWindow client,
WindowManager.LayoutParams attrs, int viewVisibility,
Rect outContentInsets, InputChannel outInputChannel) {
}
...
private final class Session extends IWindowSession.Stub
implements IBinder.DeathRecipient {
...
...
public int add(IWindow window, WindowManager.LayoutParams attrs,
int viewVisibility, Rect outContentInsets, InputChannel outInputChannel) {
return addWindow(this, window, attrs, viewVisibility, outContentInsets,
outInputChannel);
}
...
}
Session其实是WindowManagerService的一个内部类,最后还是调用了WindowManagerService的add方法。
我发现到了这里之后我又走不下去了,又往前找。
frameworks/base/core/java/android/app/ActivityThread
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
...
ViewManager wm = a.getWindowManager();
View decor = r.window.getDecorView();
wm.updateViewLayout(decor, l);
...
}
addView之后,调用WindowManagerImpl的updateViewLayout。
frameworks/base/core/java/android/view/WindowManagerImpl
...
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}
final WindowManager.LayoutParams wparams
= (WindowManager.LayoutParams)params;
view.setLayoutParams(wparams);
synchronized (this) {
int index = findViewLocked(view, true);
ViewRoot root = mRoots[index];
mParams[index] = wparams;
root.setLayoutParams(wparams, false);
}
}
...
最后一行调用ViewRoot setLayoutParams
frameworks/base/core/java/android/view/ViewRoot
...
case DO_TRAVERSAL:
...
performTraversals();
...
break;
...
void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
...
scheduleTraversals();
}
}
...
public void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
sendEmptyMessage(DO_TRAVERSAL);
}
}
...
终于最后调用了,performTraversals
。由于这个方法很重要,所以这里单独提取出来。
private void performTraversals() {
final View host = mView;
...
...
host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
...
host.layout(0, 0, host.mMeasuredWidth, host.mMeasuredHeight);
...
...
draw(fullRedrawNeeded);
...
}
mView 其实就是刚才我们调用ViewRoote setView设置进来的DecorView。
多的我也就不说了,最熟悉的3个方法出现了。接下来其实就是遍历测量,遍历布局,遍历绘制。
总的来说,这里整个添加View的过程比前面的AMS管理生命周期代码跟踪起来要难。
这里我再简单的说下,界面显示后的,动态代码addView的过程。
frameworks/base/core/java/android/view/ViewGroup
public void addView(View child, int index, LayoutParams params) {
if (DBG) {
System.out.println(this + " addView");
}
// addViewInner() will call child.requestLayout() when setting the new LayoutParams
// therefore, we call requestLayout() on ourselves before, so that the child's request
// will be blocked at our level
requestLayout();
invalidate();
addViewInner(child, index, params, false);
}
requestLayout其实是View里的方法
frameworks/base/core/java/android/view/View
public void requestLayout() {
if (ViewDebug.TRACE_HIERARCHY) {
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.REQUEST_LAYOUT);
}
mPrivateFlags |= FORCE_LAYOUT;
if (mParent != null && !mParent.isLayoutRequested()) {
mParent.requestLayout();
}
}
最后其实是调用mParent的方法,mParent其实是当前View的父控件,所以一步步往上调用,最后的话是调用DecorView的parent。
这就尴尬了,DecorView的 parent是谁呢?
前面其实已经介绍到了,我们最终是调用了WindowManagerImpl的addView,然后调用了ViewRoot的setView,让我们再来看一下setView.
frameworks/base/core/java/android/view/ViewRoot
public void setView(View view, WindowManager.LayoutParams attrs,
View panelParentView) {
...
view.assignParent(this);
...
}
这里其实就看出来了,ViewRoot直接把自己设置为了DecorView的parent。
所以requestLayout其实还是调用了ViewRoot的requestLayout.
public void requestLayout() {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
最后还是调用了scheduleTraversals,然后还是跟前面的流程一样了。
好,过程很复杂,当时跟踪一遍了之后,还是收获很多的。