performLayout
frameworks\base\core\java\android\view\ViewRootImpl.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
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);
}
...
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
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
1
2
3
4
5
6
|
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
1
2
3
4
5
6
7
8
9
|
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
1
2
3
|
public
SurfaceSession() {
init();
}
|
该init()函数是一个native函数,其JNI实现如下:
frameworks\base\core\jni\ android_view_Surface.cpp
1
2
3
4
5
6
7
|
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的会话通道;