performLayout
frameworks\base\core\java\android\view\ViewRootImpl.java
?
private void performLayout() {
mLayoutRequested = false ;
mScrollMayChange = true ;
final View host = mView;
if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
Log.v(TAG, "Laying out " + host + " to (" +
host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")" );
}
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout" );
try {
host.layout( 0 , 0 , host.getMeasuredWidth(), host.getMeasuredHeight());
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
|
performDraw
frameworks\base\core\java\android\view\ ViewRootImpl.java
?
private void performDraw() {
if (!mAttachInfo.mScreenOn && !mReportNextDraw) {
return ;
}
final boolean fullRedrawNeeded = mFullRedrawNeeded;
mFullRedrawNeeded = false ;
mIsDrawing = true ;
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw" );
try {
draw(fullRedrawNeeded);
} finally {
mIsDrawing = false ;
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
...
}
|
?
private void draw( boolean fullRedrawNeeded) {
Surface surface = mSurface;
if (surface == null || !surface.isValid()) {
return ;
}
...
if (!dirty.isEmpty() || mIsAnimating) {
//使用硬件渲染
if (attachInfo.mHardwareRenderer != null && attachInfo.mHardwareRenderer.isEnabled()) {
// Draw with hardware renderer.
mIsAnimating = false ;
mHardwareYOffset = yoff;
mResizeAlpha = resizeAlpha;
mCurrentDirty.set(dirty);
mCurrentDirty.union(mPreviousDirty);
mPreviousDirty.set(dirty);
dirty.setEmpty();
if (attachInfo.mHardwareRenderer.draw(mView, attachInfo, this ,
animating ? null : mCurrentDirty)) {
mPreviousDirty.set( 0 , 0 , mWidth, mHeight);
}
//使用软件渲染
} else if (!drawSoftware(surface, attachInfo, yoff, scalingRequired, dirty)) {
return ;
}
}
...
}
private void draw( boolean fullRedrawNeeded) {
Surface surface = mSurface;
if (surface == null || !surface.isValid()) {
return ;
}
...
if (!dirty.isEmpty() || mIsAnimating) {
//使用硬件渲染
if (attachInfo.mHardwareRenderer != null && attachInfo.mHardwareRenderer.isEnabled()) {
// Draw with hardware renderer.
mIsAnimating = false ;
mHardwareYOffset = yoff;
mResizeAlpha = resizeAlpha;
mCurrentDirty.set(dirty);
mCurrentDirty.union(mPreviousDirty);
mPreviousDirty.set(dirty);
dirty.setEmpty();
if (attachInfo.mHardwareRenderer.draw(mView, attachInfo, this ,
animating ? null : mCurrentDirty)) {
mPreviousDirty.set( 0 , 0 , mWidth, mHeight);
}
//使用软件渲染
} else if (!drawSoftware(surface, attachInfo, yoff, scalingRequired, dirty)) {
return ;
}
}
...
}
private void draw( boolean fullRedrawNeeded) {
Surface surface = mSurface;
if (surface == null || !surface.isValid()) {
return ;
}
...
if (!dirty.isEmpty() || mIsAnimating) {
//使用硬件渲染
if (attachInfo.mHardwareRenderer != null && attachInfo.mHardwareRenderer.isEnabled()) {
// Draw with hardware renderer.
mIsAnimating = false ;
mHardwareYOffset = yoff;
mResizeAlpha = resizeAlpha;
mCurrentDirty.set(dirty);
mCurrentDirty.union(mPreviousDirty);
mPreviousDirty.set(dirty);
dirty.setEmpty();
if (attachInfo.mHardwareRenderer.draw(mView, attachInfo, this ,
animating ? null : mCurrentDirty)) {
mPreviousDirty.set( 0 , 0 , mWidth, mHeight);
}
//使用软件渲染
} else if (!drawSoftware(surface, attachInfo, yoff, scalingRequired, dirty)) {
return ;
}
}
...
}
|
窗口添加过程
frameworks\base\services\java\com\android\server\wm\Session.java
?
1
2
3
4
5 |
public int add(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, Rect outContentInsets, InputChannel outInputChannel) {
return mService.addWindow( this , window, seq, attrs, viewVisibility, outContentInsets,
outInputChannel);
}
|
frameworks\base\services\java\com\android\server\wm\WindowManagerService.java
?
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility,
Rect outContentInsets, InputChannel outInputChannel) {
//client为IWindow的代理对象,是Activity在WMS服务中的唯一标示
int res = mPolicy.checkAddPermission(attrs);
if (res != WindowManagerImpl.ADD_OKAY) {
return res;
}
boolean reportNewConfig = false ;
WindowState attachedWindow = null ;
WindowState win = null ;
long origId;
synchronized (mWindowMap) {
if (mDisplay == null ) {
throw new IllegalStateException( "Display has not been initialialized" );
}
//判断窗口是否已经存在
if (mWindowMap.containsKey(client.asBinder())) {
Slog.w(TAG, "Window " + client + " is already added" );
return WindowManagerImpl.ADD_DUPLICATE_ADD;
}
//如果添加的是应用程序窗口
if (attrs.type >= FIRST_SUB_WINDOW && attrs.type <= LAST_SUB_WINDOW) {
//根据attrs.token从mWindowMap中取出应用程序窗口在WMS服务中的描述符WindowState
attachedWindow = windowForClientLocked( null , attrs.token, false );
if (attachedWindow == null ) {
Slog.w(TAG, "Attempted to add window with token that is not a window: "
+ attrs.token + ". Aborting." );
return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN;
}
if (attachedWindow.mAttrs.type >= FIRST_SUB_WINDOW
&& attachedWindow.mAttrs.type <= LAST_SUB_WINDOW) {
Slog.w(TAG, "Attempted to add window with token that is a sub-window: "
+ attrs.token + ". Aborting." );
return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN;
}
}
boolean addToken = false ;
//根据attrs.token从mWindowMap中取出应用程序窗口在WMS服务中的描述符WindowState
WindowToken token = mTokenMap.get(attrs.token);
if (token == null ) {
...
①token = new WindowToken( this , attrs.token, - 1 , false );
addToken = true ;
}
//应用程序窗口
else if (attrs.type >= FIRST_APPLICATION_WINDOW
&& attrs.type <= LAST_APPLICATION_WINDOW) {
AppWindowToken atoken = token.appWindowToken;
...
}
//输入法窗口
else if (attrs.type == TYPE_INPUT_METHOD) {
...
}
//墙纸窗口
else if (attrs.type == TYPE_WALLPAPER) {
...
}
//Dream窗口
else if (attrs.type == TYPE_DREAM) {
...
}
//为Activity窗口创建WindowState对象
②win = new WindowState( this , session, client, token,
attachedWindow, seq, attrs, viewVisibility);
...
if (outInputChannel != null && (attrs.inputFeatures& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0 ) {
String name = win.makeInputChannelName();
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
win.setInputChannel(inputChannels[ 0 ]);
inputChannels[ 1 ].transferTo(outInputChannel);
mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
}
...
//以键值对<iwindow.proxy token,windowtoken="">形式保存到mTokenMap表中
if (addToken) {
③mTokenMap.put(attrs.token, token);
}
④win.attach();
//以键值对<iwindow的代理对象,windowstate>形式保存到mWindowMap表中
⑤mWindowMap.put(client.asBinder(), win);
...
}
...
return res;
}
</iwindow的代理对象,windowstate></iwindow.proxy>
|
我们知道当应用程序进程添加一个DecorView到窗口管理器时,会为当前添加的窗口创建ViewRootImpl对象,同时构造了一个W本地Binder对象,无论是窗口视图对象DecorView还是ViewRootImpl对象,都只是存在于应用程序进程中,在添加窗口过程中仅仅将该窗口的W对象传递给WMS服务,经过Binder传输后,到达WMS服务端进程后变为IWindow.Proxy代理对象,因此该函数的参数client的类型为IWindow.Proxy。参数attrs的类型为WindowManager.LayoutParams,在应用程序进程启动Activity时,handleResumeActivity()函数通过WindowManager.LayoutParams l = r.window.getAttributes();来得到应用程序窗口布局参数,由于WindowManager.LayoutParams实现了Parcelable接口,因此WindowManager.LayoutParams对象可以跨进程传输,WMS服务的addWindow函数中的attrs参数就是应用程序进程发送过来的窗口布局参数。在LocalWindowManager的addView函数中为窗口布局参数设置了相应的token,如果是应用程序窗口,则布局参数的token设为W本地Binder对象。如果不是应用程序窗口,同时当前窗口没有父窗口,则设置token为当前窗口的IApplicationToken.Proxy代理对象,否则设置为父窗口的IApplicationToken.Proxy代理对象,由于应用程序和WMS分属于两个不同的进程空间,因此经过Binder传输后,布局参数的令牌attrs.token就转变为IWindow.Proxy或者Token。以上函数首先根据布局参数的token等信息构造一个WindowToken对象,然后在构造一个WindowState对象,并将添加的窗口信息记录到mTokenMap和mWindowMap哈希表中。
在WMS服务端创建了所需对象后,接着调用了WindowState的attach()来进一步完成窗口添加。
frameworks\base\services\java\com\android\server\wm\WindowState.java
?
void attach() {
if (WindowManagerService.localLOGV) Slog.v(
TAG, "Attaching " + this + " token=" + mToken
+ ", list=" + mToken.windows);
mSession.windowAddedLocked();
}
|
frameworks\base\services\java\com\android\server\wm\Session.java
?
void windowAddedLocked() {
if (mSurfaceSession == null ) {
mSurfaceSession = new SurfaceSession();
if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(
WindowManagerService.TAG, " NEW SURFACE SESSION " + mSurfaceSession);
mService.mSessions.add( this );
}
mNumWindow++; //记录对应的某个应用程序添加的窗口数量
}
|
到此一个新的应用程序窗口就添加完成了。总结一下:
应用程序通过IWindowSession接口请求WMS服务添加一个应用程序窗口,WMS服务首先在自己服务进程为应用程序创建创建一个对应的WindowState描述符,然后保存到成员变量mWindowMap中。如果还没有为应用程序进程创建连接SurfaceFlinger的会话,就接着创建该会话通道SurfaceSession,我们知道,Activity中的视图所使用的画布Surface是在WMS服务进程中创建的,但是该画布所使用的图形buffer确实在SurfaceFlinger进程中分配管理的,而图形的绘制确是在应用程序进程中完成的,所以Activity的显示过程需要三个进程的配合才能完成。应用程序进程只与WMS服务进程交互,并不直接和SurfaceFlinger进程交互,而是由WMS服务进程同SurfaceFlinger进程配合。前面我们介绍了应用程序进程是通过IWindowSession接口与WMS服务进程通信的,那WMS服务是如何与SurfaceFlinger进程通信的呢,这就是windowAddedLocked函数要完成的工作。
在windowAddedLocked函数中使用单例模式创建一个SurfaceSession对象,在构造该对象时,通过JNI在native层创建一个与SurfaceFlinger进程的连接。
frameworks\base\core\java\android\view\SurfaceSession.java
?
public SurfaceSession() {
init();
}
|
该init()函数是一个native函数,其JNI实现如下:
f
rameworks\base\core\jni\ android_view_Surface.cpp
?
static void SurfaceSession_init(JNIEnv* env, jobject clazz)
{
sp<surfacecomposerclient> client = new SurfaceComposerClient;
client->incStrong(clazz);
env->SetIntField(clazz, sso.client, ( int )client.get());
}
</surfacecomposerclient>
|
该函数构造了一个SurfaceComposerClient对象,在第一次强引用该对象时,会请求SurfaceFlinger创建一个专门处理当前应用程序进程请求的Client会话。
系统中创建的所有IWindowSession都被记录到WMS服务的mSessions成员变量中,这样WMS就可以知道自己正在处理那些应用程序的请求。到此我们来梳理一下在WMS服务端都创建了那些对象:
1) WindowState对象,是应用程序窗口在WMS服务端的描述符;
2) Session对象,应用程序进程与WMS服务会话通道;
3) SurfaceSession对象,应用程序进程与SurfaceFlinger的会话通道;