Android应用程序窗口设计框架四

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会话。

n峨V1系统中创建的所有IWindowSession都被记录到WMS服务的mSessions成员变量中,这样WMS就可以知道自己正在处理那些应用程序的请求。到此我们来梳理一下在WMS服务端都创建了那些对象:

1) WindowState对象,是应用程序窗口在WMS服务端的描述符;

2) Session对象,应用程序进程与WMS服务会话通道;

3) SurfaceSession对象,应用程序进程与SurfaceFlinger的会话通道;

猜你喜欢

转载自blog.csdn.net/linghu_java/article/details/42964719