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

来源:互联网 发布:五笔练习软件 编辑:程序博客网 时间:2024/05/22 11:55
performLayout

frameworks\base\core\java\android\view\ViewRootImpl.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
privatevoid performLayout() {
    mLayoutRequested = false;
    mScrollMayChange = true;
    finalView 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
privatevoid performDraw() {
    if(!mAttachInfo.mScreenOn && !mReportNextDraw) {
        return;
    }
    finalboolean 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
privatevoid draw(booleanfullRedrawNeeded) {
    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);
            }
        //使用软件渲染
        }elseif (!drawSoftware(surface, attachInfo, yoff, scalingRequired, dirty)) {
            return;
        }
    }
    ...
}


\

窗口添加过程

frameworks\base\services\java\com\android\server\wm\Session.java

?
1
2
3
4
5
publicint add(IWindow window, intseq, WindowManager.LayoutParams attrs,
        intviewVisibility, Rect outContentInsets, InputChannel outInputChannel) {
    returnmService.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
publicint addWindow(Session session, IWindow client, intseq,
        WindowManager.LayoutParams attrs, intviewVisibility,
        Rect outContentInsets, InputChannel outInputChannel) {
    //client为IWindow的代理对象,是Activity在WMS服务中的唯一标示
    intres = mPolicy.checkAddPermission(attrs);
    if(res != WindowManagerImpl.ADD_OKAY) {
        returnres;
    }
    booleanreportNewConfig = false;
    WindowState attachedWindow = null;
    WindowState win = null;
    longorigId;
    synchronized(mWindowMap) {
        if(mDisplay == null) {
            thrownew IllegalStateException("Display has not been initialialized");
        }
        //判断窗口是否已经存在
        if(mWindowMap.containsKey(client.asBinder())) {
            Slog.w(TAG,"Window " + client + " is already added");
            returnWindowManagerImpl.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.");
                returnWindowManagerImpl.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.");
                returnWindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN;
            }
        }
        booleanaddToken = false;
        //根据attrs.token从mWindowMap中取出应用程序窗口在WMS服务中的描述符WindowState
        WindowToken token = mTokenMap.get(attrs.token);
        if(token == null) {
            ...
            ①token = newWindowToken(this, attrs.token, -1,false);
            addToken = true;
        }
        //应用程序窗口
        elseif (attrs.type >= FIRST_APPLICATION_WINDOW
                && attrs.type <= LAST_APPLICATION_WINDOW) {
            AppWindowToken atoken = token.appWindowToken;
            ...
        }
        //输入法窗口
        elseif (attrs.type == TYPE_INPUT_METHOD) {
            ...
        }
        //墙纸窗口
        elseif (attrs.type == TYPE_WALLPAPER) {
            ...
        }
        //Dream窗口
        elseif (attrs.type == TYPE_DREAM) {
            ...
        }
        //为Activity窗口创建WindowState对象
        ②win = newWindowState(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);
        ...
    }
    ...
    returnres;
}
</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
voidattach() {
    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
voidwindowAddedLocked() {
    if(mSurfaceSession == null) {
        mSurfaceSession = newSurfaceSession();
        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
publicSurfaceSession() {
    init();
}

该init()函数是一个native函数,其JNI实现如下:

frameworks\base\core\jni\ android_view_Surface.cpp

?
1
2
3
4
5
6
7
staticvoid SurfaceSession_init(JNIEnv* env, jobject clazz)
{
    sp<surfacecomposerclient> client = newSurfaceComposerClient;
    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的会话通道;

0 0
原创粉丝点击