[深入理解Android卷一全文-第八章]深入理解Surface系统

转载:https://blog.csdn.net/innost/article/details/47208337

第8章  深入理解Surface系统

本章主要内容

·  详细分析一个Activity的显示过程。

·  详细分析Surface。

·  详细分析SurfaceFlinger。

本章涉及的源代码文件名及位置:

· ActivityThread.java

framework/base/core/java/android/app/ActivityThread.java

·  Activity.java

framework/base/core/java/android/app/Activity.java

·  Instrumentation.java

扫描二维码关注公众号,回复: 1670085 查看本文章

framework/base/core/java/android/app/Instrumentation.java

·  PolicyManager.java

frameworks/policies/base/phone/com/android/internal/policy/impl/PolicyManager.java

·  Policy.java

frameworks/policies/base/phone/com/android/internal/policy/impl/Policy.java

·  PhoneWindow.java

frameworks/policies/base/phone/com/android/internal/policy/impl/PhoneWindow.java

·  Window.java

framework/base/core/java/android/view/Window.java

·  WindowManagerImpl

framework/ base/core/java/android/view/WindowManagerImpl.java

·  ViewRoot.java

framework/base/core/java/android/view/ViewRoot.java

·  Surface.java

framework/base/core/java/android/view/Surface.java

·  WindowManagerService.java

framework/base/services/java/com/android/server/WindowManagerService.java

·  IWindowSession.aidl

framework/base/core/java/android/view/IWindowSession.aidl

·  IWindow.aidl

framework/base/core/java/android/view/IWindow.aidl

·  SurfaceSession.java

framework/base/core/java/android/view/SurfaceSession.java

·  android_view_Surface.cpp

framework/base/core/jni/android_view_Surface.cpp

·  framebuffer_service.c

system/core/adb/framebuffer_service.c

·  SurfaceComposerClient.cpp

framework/base/libs/surfaceflinger_client/SurfaceComposerClient.cpp

·  SurfaceFlinger.cpp

framework/base/libs/surfaceflinger/SurfaceFlinger.cpp

·  ISurfaceComposer.h

framework/base/include/surfaceflinger/ISurfaceComposer.h

·  Layer.h

framework/base/include/surfaceflinger/Layer.h

·  Layer.cpp

framework/base/libs/surfaceflinger/Layer.cpp

·  LayerBase.cpp

framework/base/libs/surfaceflinger/LayerBase.cpp

·  Surface.cpp

framework/base/libs/surfaceflinger_client/Surface.cpp

·  SharedBufferStack.cpp

framework/base/libs/surfaceflinger_client/SharedBufferStack.cpp

·  GraphicBuffer.h

framework/base/include/ui/GraphicBuffer.h

·  GraphicBuffer.cpp

framework/base/libs/ui/GraphicBuffer.cpp

·  GraphicBufferAllocator.h

framework/base/include/ui/GraphicBufferAllocator.h

·  GraphicBufferAllocator.cpp

framework/base/libs/ui/GraphicBufferAllocator.cpp

·  GraphicBufferMapper.cpp

framework/base/libs/ui/GraphicBufferMapper.cpp

·  Android_natives.h

framework/base/include/ui/egl/Android_natives.h

·  android_native_buffer.h

framework/base/include/ui/android_native_buffer.h

·  native_handle.h

system/core/include/cutils/native_handle.h

·  gralloc.h

hardware/libhardware/include/hardware/gralloc.h

·  ISurface.cpp

framework/base/libs/surfaceflinger_client/ISurface.cpp

·  DisplayHardware.cpp

framework/base/libs/surfaceflinger/DisplayHardware.cpp

8.1  概述

Surface是继Audio系统后要破解第二个复杂的系统。它的难度和复杂度远远超过了Audio。基于这种情况,本章将集中精力打通Surface系统的“任督二脉”,这任督二脉分别是:

·  任脉:应用程序和Surface的关系。

·  督脉:Surface和SurfaceFlinger之间的关系。

当这二脉打通后,我们就可以自行修炼更高层次的功夫了。图8-1显示了这二脉的关系:


图8-1  Surface系统的任督二脉

其中,左图是任脉,右图是督脉。

·  先看左图。可以发现,不论Skia绘制二维图像,还是用OpenGL绘制三维图像,最终Application都要和Surface交互Surface就像是UI的画布,而App则像是在Surface上作画。所以要想打通任脉,就须破解App和Surface之间的关系。

·  再看右图。Surface和SurfaceFlinger的关系,很像Audio系统中AudioTrack和AudioFlinger的关系。Surface向SurfaceFlinger提供数据,而SurfaceFlinger则混合数据。所谓打通督脉的关键,就是破解Surface和SurfaceFlinger之间的关系。

目标已清楚,让我们开始“运功”破解代码吧!

说明:为书写方便起见,后文将SurfaceFlinger简写为SF。

8.2  一个Activity的显示

一般来说,应用程序的外表是通过Activity来展示的。那么,Activity是如何完成界面绘制工作的呢?根据前面所讲的知识,应用程序的显示和Surface有关,那么具体到Activity上,它和Surface又是什么关系呢?

本节就来讨论这些问题。首先从Activity的创建说起。

8.2.1  Activity的创建

我们已经知道了Activity的生命周期,如onCreate、onDestroy等,但大家是否考虑过这样一个问题:

·  如果没有创建Activity,那么onCreate和onDestroy就没有任何意义,可这个Activity究竟是在哪里创建的?。

第4章中的“Zygote分裂”一节已讲过,Zygote在响应请求后会fork一个子进程,这个子进程是App对应的进程,它的入口函数是ActivityThread类的main函数。ActivityThread类中有一个handleLaunchActivity函数,它就是创建Activity的地方。一起来看这个函数,代码如下所示:

[-->ActivityThread.java]

private final void handleLaunchActivity(ActivityRecord r, Intent customIntent) {

       //①performLaunchActivity返回一个Activity

       Activity a = performLaunchActivity(r, customIntent);

 

        if(a != null) {

           r.createdConfig = new Configuration(mConfiguration);

           Bundle oldState = r.state;

          //②调用handleResumeActivity

           handleResumeActivity(r.token, false, r.isForward);

   }

      ......

}

handleLaunchActivity函数中列出了两个关键点,下面对其分别介绍。

1. 创建Activity

第一个关键函数performLaunchActivity返回一个Activity,这个Activity就是App中的那个Activity(仅考虑App中只有一个Activity的情况),它是怎么创建的呢?其代码如下所示:

[-->ActivityThread.java]

private final Activity performLaunchActivity(ActivityRecord r,Intent customIntent) {

        

       ActivityInfo aInfo = r.activityInfo;

        ......//完成一些准备工作

      //Activity定义在Activity.java中

       Activity activity = null;

       try {

           java.lang.ClassLoader cl = r.packageInfo.getClassLoader();

     /*

     mInstrumentation为Instrumentation类型,源文件为Instrumentation.java。

     它在newActivity函数中根据Activity的类名通过Java反射机制来创建对应的Activity

     这个函数比较复杂,待会我们再分析它。

     */

           activity = mInstrumentation.newActivity(cl,component.getClassName(), r.intent);

            r.intent.setExtrasClassLoader(cl);

           if (r.state != null) {

               r.state.setClassLoader(cl);

           }

        }catch (Exception e) {

            ......

        }

 

       try {

           Application app =

             r.packageInfo.makeApplication(false,mInstrumentation);

 

            if (activity != null) {

               //在Activity中getContext函数返回的就是这个ContextImpl类型的对象

               ContextImpl appContext = new ContextImpl();

               ......

              //下面这个函数会调用Activity的onCreate函数

               mInstrumentation.callActivityOnCreate(activity, r.state);

                ......

       return activity;

 }

好了,performLaunchActivity函数的作用明白了吧?

·  根据类名以Java反射的方法创建一个Activity。

·  调用Activity的onCreate函数,开始SDK中大书特书Activity的生命周期。

那么,在onCreate函数中,我们一般会做什么呢?在这个函数中,和UI相关的重要工作就是调用setContentView来设置UI的外观。接下去,需要看handleLaunchActivity中第二个关键函数handleResumeActivity。

2. 分析handleResumeActivity

上面已创建好了一个Activity,再来看handleResumeActivity。它的代码如下所示:

[-->ActivityThread.java]

final void handleResumeActivity(IBinder token,boolean clearHide,boolean isForward) {

boolean willBeVisible = !a.mStartedActivity;

          

if (r.window == null && !a.mFinished&& willBeVisible) {

      r.window= r.activity.getWindow();

      //①获得一个View对象

      View decor = r.window.getDecorView();

     decor.setVisibility(View.INVISIBLE);

      //②获得ViewManager对象

      ViewManager wm = a.getWindowManager();

      ......

      //③把刚才的decor对象加入到ViewManager中

       wm.addView(decor,l);

   }

         ......//其他处理

}

上面有三个关键点。这些关键点似乎已经和UI部分(如View、Window)有联系了。那么这些联系是在什么时候建立的呢?在分析上面代码中的三个关键点之前,请大家想想在前面的过程中,哪些地方会和UI挂上钩呢?

·  答案就在onCreate函数中,Activity一般都在这个函数中通过setContentView设置UI界面。

看来,必须先分析setContentView,才能继续后面的征程。

3. 分析setContentView

setContentView有好几个同名函数,现在只看其中的一个就可以了。代码如下所示:

[-->Activity.java]

public void setContentView(View view) {

//getWindow返回的是什么呢?一起来看看。

 getWindow().setContentView(view);

}

public Window getWindow() {

  return mWindow; //返回一个类型为Window的mWindow,它是什么?

}

上面出现了两个和UI有关系的类:View和Window[①]。来看SDK文档是怎么描述这两个类的。这里先给出原文描述,然后进行对应翻译:


这里面有一句比较关键的话:Window将做为一个顶层的view加入到Window Manager中。

View 是一个基本的UI单元,占据屏幕的一块矩形区域,可用于绘制,并能处理事件。

从上面的View和Window的描述,再加上setContentView的代码,我们能想象一下这三者的关系,如图8-2所示:


图8-2  Window/View的假想关系图


(1)Activity的Window

据上文讲解可知,Window是一个抽象类。它实际的对象到底属于什么类型?先回到Activity创建的地方去看看。下面正是创建Activity时的代码,可当时没有深入地分析。

activity = mInstrumentation.newActivity( cl,component.getClassName(), r.intent);

[-->Instrumentation.java]

public Activity newActivity(Class<?>clazz, Context context,

           IBinder token, Application application, Intent intent,

            ActivityInfo info, CharSequencetitle, Activity parent,

String id,Object lastNonConfigurationInstance)

throws InstantiationException, IllegalAccessException{

       

Activity activity = (Activity)clazz.newInstance();

       ActivityThread aThread = null;

        //关键函数attach!!

       activity.attach(context, aThread, this, token, application, intent,

info, title,parent, id, lastNonConfigurationInstance,

new Configuration());

       return activity;

    }

看到关键函数attach了吧?Window的真相马上就要揭晓了,让我们用咆哮体来表达内心的激动之情吧!!!!

[-->Activity.java]

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) {

        ......

        //利用PolicyManager来创建Window对象,(PhoneWindow对象)

       mWindow = PolicyManager.makeNewWindow(this);

       mWindow.setCallback(this);

        ......

        //创建WindowManager对象

       mWindow.setWindowManager(null, mToken, mComponent.flattenToString());

        if(mParent != null) {

           mWindow.setContainer(mParent.getWindow());

        }

       //保存这个WindowManager对象

       mWindowManager = mWindow.getWindowManager();

       mCurrentConfig = config;

}

(2)水面下的冰山——PolicyManager

PolicyManager定义于PolicyManager.java文件,该文件在一个非常独立的目录下,现将其单独列出来:

·  frameworks/policies/base/phone/com/android/internal/policy/impl

注意,上面路径中的红色目录phone是针对智能手机这种小屏幕的;另外还有一个平级的目录叫mid,是针对Mid设备的。mid目录的代码比较少,可能目前还没有开发完毕。

下面来看这个PolicyManager,它比较简单。

[-->PolicyManager.java]

public final class PolicyManager {

    //通过Policy对象的makeNewWindow创建一个Window

    publicstatic Window makeNewWindow(Context context) {

       return sPolicy.makeNewWindow(context);

    }

}

这里有一个单例的sPolicy对象,它是Policy类型,请看它的定义。

(3)真正的Window

Policy类型的定义代码如下所示:

[-->Policy.java]

public class Policy implements IPolicy {

public PhoneWindow makeNewWindow(Contextcontext) {

        //makeNewWindow返回的是PhoneWindow对象

       return new PhoneWindow(context);

    }

}

(4)真正的WindowManager

先看WindowManager创建的代码,如下所示:

[-->Activity.java]

  ......//创建mWindow对象

   //调用mWindow的setWindowManager函数

mWindow.setWindowManager(null, mToken,mComponent.flattenToString());

   .....


[-->Window.java]

public void setWindowManager(WindowManager wm,IBinder appToken, String appName) {     //注意,传入的wm值为null

       mAppToken = appToken;

       mAppName = appName;

        if(wm == null) {

          //如果wm为空的话,则创建WindowManagerImpl对象

           wm = WindowManagerImpl.getDefault();

        }

       //mWindowManager是一个LocalWindowManager

       mWindowManager = new LocalWindowManager(wm);

    }

可得出以下结论:

·  Activity的mWindow成员变量其真实类型是PhoneWindow,而mWindowManager成员变量的真实类型是LocalWindowManager。

·  LocalWindowManager和WindowManagerImpl都实现了WindowManager接口。这里采用的是Proxy模式,表明LocalWindowManager将把它的工作委托WindowManagerImpl来完成。

(5)setContentView的总结

了解了上述知识后,重新回到setContentView函数。这次希望能分析得更深入些。

[-->Activity.java]

public void setContentView(View view) {

       getWindow().setContentView(view);//getWindow返回的是PhoneWindow

}

一起来看PhoneWindow的setContentView函数,代码如下所示:

[-->PhoneWindow]

public void setContentView(View view) {

   //调用另一个setContentView

   setContentView(view,new ViewGroup.LayoutParams(MATCH_PARENT,MATCH_PARENT));

}

 

public void setContentView(View view,ViewGroup.LayoutParams params) {

   //mContentParent为ViewGroup类型,它的初值为null,

  //(mDecor的一个子View,用于容纳Activity.setContentView(view) 设置的view)

     if(mContentParent == null) {

           installDecor();

     }else {

           mContentParent.removeAllViews();

     }

    //把view加入到ViewGroup中

    mContentParent.addView(view, params);

     ......

}

installDecor函数,其代码如下所示:

[-->PhoneWindow.java]

private void installDecor() {

    if (mDecor == null) {

     //创建mDecor,它为DecorView类型,从FrameLayout派生

     mDecor= generateDecor();

            ......

   }

  if(mContentParent == null) {

     //得到这个mContentParent(mDecor的一个子View)

mContentParent = generateLayout(mDecor);

    //创建标题栏

    mTitleView= (TextView)findViewById(com.android.internal.R.id.title);

......

}

generateLayout函数的输入参数为mDecor,输出为mContentParent,代码如下所示:

[-->PhoneWindow]

protected ViewGroup generateLayout(DecorViewdecor){

  ......

  int layoutResource;

  int features = getLocalFeatures();

  if((features & ((1 << FEATURE_LEFT_ICON) |(1 <<FEATURE_RIGHT_ICON))) != 0) {

      if(mIsFloating) {

      //根据情况取得对应标题栏的资源id

     layoutResource =  com.android.internal.R.layout.dialog_title_icons;

     }

       ......

}

  mDecor.startChanging();

 View in =mLayoutInflater.inflate(layoutResource, null);

 //加入标题栏

 decor.addView(in,new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));

   /*

     ID_ANDROID_CONTENT的值为”com.android.internal.R.id.content”

     这个contentParent由findViewById返回,实际上就是mDecorView的一部分。

   */

   ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);

   ......

   mDecor.finishChanging();

   return contentParent;

}

下面看findViewById是如何实现的。它定义在Window.java中,代码如下所示:

[-->Window.java]

public View findViewById(int id) {

  //getDecorView将返回mDecorView,所以contentParent确实是DecorView的一部分

   return getDecorView().findViewById(id);

 }

大家还记得图8-2吗?介绍完上面的知识后,根据图8-2,可绘制更细致的图8-4:


图8-4  一个Activity中的UI组件

可从上图中看出,在Activity的onCreate函数中,通过setContentView设置的View,其实只是DecorView的子View。DecorView还处理了标题栏显示等一系列的工作

注意,这里使用了设计模式中的Decorator(装饰)模式,它也是UI编程中常用的模式之一。

 

4. 重回handleResumeActivity

看完setContentView的分析后,不知大家是否还记得这样一个问题:为什么要分析这个setContentView函数?在继续前行之前,先来回顾一下被setContentView打断的流程。

当时,我们正在分析handleResumeActivity,代码如下所示:

[-->ActivityThread.java]

final void handleResumeActivity(IBinder token,boolean clearHide,

boolean isForward) {

 booleanwillBeVisible = !a.mStartedActivity;

......

if (r.window == null && !a.mFinished&& willBeVisible) {

     r.window= r.activity.getWindow();

    //①获得一个View对象。现在知道这个view就是DecorView

   View decor = r.window.getDecorView();

   decor.setVisibility(View.INVISIBLE);

  //②获得ViewManager对象,这个wm就是LocalWindowManager

  ViewManager wm = a.getWindowManager();

  WindowManager.LayoutParamsl = r.window.getAttributes();

  if(a.mVisibleFromClient) {

       a.mWindowAdded= true;

       //③把刚才的decor对象加入到LocalWindowManager

      wm.addView(decor,l);

   }

......//其他处理

}


来看这个addView函数,它的代码如下所示:

[-->Window.java LocalWindowManager]

public final void addView(View view,ViewGroup.LayoutParams params) {

  

 WindowManager.LayoutParams wp =(WindowManager.LayoutParams)params;

 CharSequence curTitle = wp.getTitle();

 ...... //做一些操作,可以不管它

//还记得前面提到过的Proxy模式吗?mWindowManager对象实际上是WindowManagerImpl类型

mWindowManager.addView(view, params);

}

看来,要搞清楚这个addView函数还是比较麻烦的,因为现在必须到WindowManagerImpl中去看看。它的代码如下所示:

[-->WindowManagerImpl.java]

private void addView(View view,ViewGroup.LayoutParams params, boolean nest)

{

  ViewRoot root; //ViewRoot,幕后的主角终于登场了!

  synchronized(this) {

  //①创建ViewRoot

  root =new ViewRoot(view.getContext());

  root.mAddNesting = 1;

  view.setLayoutParams(wparams);

           

  if(mViews == null) {

      index = 1;

      mViews = new View[1];

      mRoots= new ViewRoot[1];

     mParams = new WindowManager.LayoutParams[1];

   } else{

     ......

    }

   index--;

   mViews[index]= view;

   mRoots[index]= root;//保存这个root(ViewRoot )

   mParams[index]= wparams;

 

//②setView,其中view是刚才我们介绍的DecorView

  root.setView(view,wparams, panelParentView);//

}

(1)ViewRoot是什么?

ViewRoot实现了ViewParent接口。但它和Android基本绘图单元中的View却不太一样,比如:ViewParent不处理绘画,因为它没有onDraw函数。

如上所述,ViewParent和绘画没有关系:

[-->ViewRoot.java::ViewRoot定义]

public final class ViewRoot extends Handler implements ViewParent,

       View.AttachInfo.Callbacks //从Handler类派生

{

private final Surface mSurface = new Surface();//这里创建了一个Surface对象

final W mWindow; //是IWindow类型,ViewRoot是Bn端(服务器),WMS是Bp端,

                                    // 用于WMS在接收触摸、按键等事件后分发到对应进程对应Window处理

View mView;

}

上面这段代码传达出了一些重要信息:

·  ViewRoot继承了Handler类,看来它能处理消息。ViewRoot果真重写了handleMessage函数。稍侯再来看它。

·  ViewRoot有一个成员变量叫mSurface,它是Surface类型。

·  ViewRoot还有一个W类型的mWindow和一个View类型的mView变量。

(2)神笔马良乎?

这里冒出来一个Surface类。它是什么?在回答此问题之前,先来考虑这样一个问题:

·  前文介绍的View、DecorView等都是UI单元,这些UI单元的绘画工作都在onDraw函数中完成。如果把onDraw想象成画图过程,那么画布是什么?

Android肯定不是“马良”,它也没有那支可以在任何物体上作画的“神笔”,所以我们需要一块实实在在的画布,这块画布就是Surface。SDK文档对Surface类的说明是:Handle on to a raw buffer thatis being managed by the screen compositor。这句话的意思是:

·  Surface有一块Raw buffer,至于是内存还是显存,不必管它。

·  Surface操作这块Raw buffer。

·  Screen compositor(其实就是SurfaceFlinger)管理这块Raw buffer

Surface和SF、ViewRoot有什么关系呢?相信,聪明的你此时已经明白些了,这里用图8-5描绘一下心中的想法:


图8-5  马良的神笔工作原理

结合之前所讲的知识,图8-5清晰地传达了如下几条信息:

·  ViewRoot有一个成员变量mSurface,它是Surface类型,它和一块Raw Buffer有关联。

·  ViewRoot是一个ViewParent,它的子View的绘画操作,是在画布Surface上展开的。

·  Surface和SurfaceFlinger有交互,这非常类似AudioTrack和AudioFlinger之间的交互。

既然本章题目为“深入理解Surface系统”,那么就需要重点关注Surface和SurfaceFlinger间的关系。建立这个关系需ViewRoot的参与,所以应先来分析ViewRoot的创建和它的setView函数。

(3)ViewRoot的创建和对setView的分析

来分析ViewRoot的构造。关于它所包含内容,代码如下所示:

[-->ViewRoot.java]

public ViewRoot(Context context) {

       super();

      ....

       // getWindowSession 将建立  Activity的ViewRoot  和 WindowManagerService  的关系

      // 得到一个IWindowSession对象,用于与WMS通讯。

      getWindowSession(context.getMainLooper());


      //是IWindow类型,ViewRoot是Bn端(服务器),WMS是Bp端,

       // 用于WMS在接收触摸、按键等事件后分发到对应进程对应Window处理

       mWindow= new W(this, context);

}

getWindowsession函数。代码如下所示:

[-->ViewRoot.java]

ublic static IWindowSession getWindowSession(Looper mainLooper) {

synchronized (mStaticInit) {

  if(!mInitialized) {

   try {

      InputMethodManager imm =

         InputMethodManager.getInstance(mainLooper);

 //先得到WindowManagerService的Binder代理,通过binder通讯 调用WindowManagerService的openSession

sWindowSession = IWindowManager.Stub.asInterface(ServiceManager.getService("window"))

                 .openSession(imm.getClient(), imm.getInputContext());

                    mInitialized = true;

               } catch (RemoteException e) {

               }

           }

           return sWindowSession;

        }

    }

WindowSession?WindowManagerService?第一次看到这些东西时,我快疯了。复杂,太复杂,无比复杂!要攻克这些难题,应先来回顾一下与Zygote相关的知识:

·  WindowManagerService(以后简称WMS)由System_Server进程启动,SurfaceFlinger服务也在这个进程中。

Activity的显示还不单纯是它自己的事,还需要和WMS建立联系才行。继续看。先看setView的处理。这个函数很复杂,注意其中关键的几句。

openSession的操作是一个使用Binder通信的跨进程调用,暂且记住这个函数,在精简流程之后再来分析。

代码如下所示:

[-->ViewRoot.java]

public void setView(View view, WindowManager.LayoutParamsattrs,

                        View panelParentView){//第一个参数view是DecorView

      ......

       mView= view;//保存这个view(DecorView)

       synchronized (this) {

           requestLayout(); //发送DO_TRAVERSAL消息ViewRoot是从Handler派生的,所以这个消息最后会由ViewRoot自己处理

               try {

                //调用IWindowSession的add函数,第一个参数是mWindow

                res =sWindowSession.add(mWindow, mWindowAttributes,getHostVisibility(), mAttachInfo.mContentInsets);

               }

          ......

}

ViewRoot的setView函数做了三件事:

·  保存传入的view参数为mView,这个mView指向PhoneWindow的DecorView。

·  调用requestLayout。

·  调用IWindowSession的add函数,这是一个跨进程的Binder通信,第一个参数是mWindow。

先来看这个requestLayout函数,它非常简单,就是往handler中发送了一个消息。注意,ViewRoot是从Handler派生的,所以这个消息最后会由ViewRoot自己处理

从上面的代码中可发现,ViewRoot和远端进程SystemServer的WMS有交互

·  ViewRoot调用openSession,得到一个IWindowSession对象,用于与WMS通讯。

·  调用WindowSession对象的add函数,把mWindow对象做为参数传入。

5. ViewRoot和WMS的关系

上面总结了ViewRoot和WMS的交互流程,其中一共有两个跨进程的调用。一起去看。

(1)调用流程分析

WMS的代码在WindowManagerService.java中:

[-->WindowManagerService.java]

public IWindowSession openSession(IInputMethodClient client,

                                        IInputContext inputContext) {

       ......

return new Session(client, inputContext);

}

Session是WMS定义的持内部类。它支Binder通信,并且属于Bn端

再来看它的add函数。代码如下所示:

[-->WindowManagerService.java::Session]

public int add(IWindow window,WindowManager.LayoutParams attrs,

               int viewVisibility, Rect outContentInsets) {

    //调用WMS的addWindow

    return addWindow(this, window, attrs, viewVisibility,outContentInsets);

}

[-->WindowManagerService.java]

public int addWindow(Session session, IWindowclient,

           WindowManager.LayoutParams attrs, int viewVisibility,

           Rect outContentInsets) {

           ......

          //创建一个WindowState

          win = new WindowState(session, client, token, attachedWindow, attrs,viewVisibility);

          ......

         //调用attach函数

          win.attach();

          ......

          return res;

}

WindowState类也是在WMS中定义的内部类,直接看它的attach函数,代码如下所示:

[-->WMS.java::WindowState]

void attach() {

      //mSession就是Session对象,调用它的windowAddedLocked函数

     mSession.windowAddedLocked();

}

[-->WMS.java::Session]

void windowAddedLocked() {

  if(mSurfaceSession == null) {

        ......

       //创建一个SurfaceSession对象

       mSurfaceSession= new SurfaceSession();

       ......

     }

      mNumWindow++;

}


(2)ViewRoot和WMS的关系梳理

ViewRoot和WMS之间的关系,可用图8-6来表示:


图8-6  ViewRoot和WMS的关系

总结一下图8-6中的知识点:

·  ViewRoot通过IWindowSession 跟WMS进程进行跨进程通信。IWindowSession定义在IWindowSession.aidl文件中。这个文件在编译时由aidl工具处理,最后会生成类似于Native Binder中Bn端和Bp端的代码,后文会介绍它。

·  ViewRoot内部有一个W类型的对象,它也是一个基于Binder通信的类,W是IWindow的Bn端,用于响应请求。IWindow定义在另一个aidl文件IWindow.aidl中。

为什么需要这两个特殊的类呢?简单介绍一下:

首先,来看IWindowSession.aidl对自己的描述:

·  System private per-application interface to the window manager:也就是说每个App进程都会和WMS建立一个IWindowSession会话。这个会话被App进程用于和WMS通信。后面会介绍它的requestLayout函数。

再看对IWindow.adil的描述:

·  API back to a client window that the Window Manager uses to informit of interesting things happening:这句话的大意是IWindow是WMS用来做事件通知的。每当发生一些事情时,WMS(Bp客户端)就会把这些事告诉某个IWindow。可以把IWindow想象成一个回调函数。


[-->IWindow.aidl定义]

void dispatchKey(in KeyEvent event);

void dispatchPointer(in MotionEvent event, longeventTime,

boolean callWhenDone);

void dispatchTrackball(in MotionEvent event,long eventTime,

boolean callWhenDone);

这里的事件指的就是按键、触屏等事件。那么,一个按键事件是如何被分发的呢?下面是它大致的流程:

·  WMS所在的SystemServer进程接收到按键事件

·  WMS找到UI位于屏幕顶端的进程所对应的IWindow对象,这是一个Bp端对象(保存在WMS中)。

·  调用这个IWindow对象的dispatchKey。IWindow对象的Bn端位于ViewRoot中,ViewRoot再根据内部View的位置信息找到真正处理这个事件的View,最后调用dispatchKey函数完成按键的处理

其实这些按键事件的分发机制可以拿Windows的UI编程来做类比,在Windows中应用程序的按键处理流程是:

·  每一个按键事件都会转化成一个消息,这个消息将由系统加入到对应进程消息队列该进程的消息在派发处理时,会根据消息的句柄找到对应的Window(窗口),继而该消息就由这个Window处理了

注意:上面的描述实际上大大简化了真实的处理流程,读者可在了解大体知识后进行更深入的研究。

上面介绍的是ViewRoot和WMS的交互,但是我们最关心的Surface还没有正式介绍,在此之前,还是先介绍Activity的流程。

8.2.2  Activity的UI绘制

ViewRoot的setView函数中,会有一个requestLayout。根据前面的分析可知,它会向ViewRoot发送一个DO_TRAVERSAL消息,来看它的handleMessage函数,代码如下所示:

[-->ViewRoot.java]

public void handleMessage(Message msg) {

       switch (msg.what) {

        ......

       case DO_TRAVERSAL:

            ......

           performTraversals();//调用performTraversals函数

......

           break;

       ......

}

}

再去看performTraversals函数,这个函数比较复杂,先只看它的关键部分,代码如下所示:

[-->ViewRoot.java]

private void performTraversals() {

 final View host = mView;//DecorView喔

 

  boolean initialized = false;

  boolean contentInsetsChanged = false;

  boolean visibleInsetsChanged;

  try {

    relayoutResult= //①关键函数relayoutWindow

   relayoutWindow(params, viewVisibility,insetsPending);

   }

......

  draw(fullRedrawNeeded);// ②开始绘制

......

}

1. relayoutWindow的分析

performTraversals函数比较复杂,暂时只关注其中的两个函数relayoutWindow和draw即可。先看第一个relayoutWindow,代码如下所示:

[-->ViewRoot.java]

private int relayoutWindow(WindowManager.LayoutParams params,

int viewVisibility, boolean insetsPending)throws RemoteException {

      

       //原来是调用IWindowSession的relayOut

       int relayoutResult = sWindowSession.relayout(

               mWindow, params,

               (int) (mView.mMeasuredWidth * appScale + 0.5f),

               (int) (mView.mMeasuredHeight * appScale + 0.5f),

               viewVisibility, insetsPending, mWinFrame,

               mPendingContentInsets, mPendingVisibleInsets,

               mPendingConfiguration, mSurface); mSurface做为参数传进去了。

       }

   ......

}

2. draw的分析

再来看draw函数。这个函数非常重要,它可是Acitivity漂亮脸蛋的塑造大师啊,代码如下所示:

[-->ViewRoot.java]

private void draw(boolean fullRedrawNeeded) {

       Surface surface = mSurface;//mSurface是ViewRoot的成员变量

       ......

        Canvas canvas;

       try {

           int left = dirty.left;

           int top = dirty.top;

           int right = dirty.right;

           int bottom = dirty.bottom;

           //从mSurface中lock一块Canvas

           canvas = surface.lockCanvas(dirty);

           ......

           mView.draw(canvas);//调用DecorView的draw函数,canvas就是画布的意思啦!

           ......

           //unlock画布,屏幕上马上就会见到漂亮宝贝的长相了。

           surface.unlockCanvasAndPost(canvas);

        }

          ......

    }

UI的显示好像很简单嘛!真的是这样的吗?在揭露这个“惊天秘密”之前我们先总结一下Activity的显示流程。

8.2.3  Activity总结

不得不承认的是前面几节的内容很多也很繁杂,为了让后面分析的过程更流畅轻松一些,所以我们必须要总结一下。关于Activity的创建和显示,前面几节的信息可提炼成如下几条:

·  Activity的顶层View是DecorView,而我们在onCreate函数中通过setContentView设置的View只不过是这个DecorView中的一部分罢了。DecorView是一个FrameLayout类型的ViewGroup。

·  Activity和UI有关,它包含一个Window(真实类型是PhoneWindow)和一个WindowManager(真实类型是LocalWindowManager)对象。这两个对象将控制整个Activity的显示

·  LocalWindowManager使用了WindowManagerImpl做为最终的处理对象(Proxy模式),这个WindowManagerImpl中有一个ViewRoot对象

·  ViewRoot实现了ViewParent接口,它有两个重要的成员变量,一个是mView,它指向Activity顶层UI单元的DecorView,另外有一个mSurface,这个Surface包含了一个Canvas(画布)。除此之外,ViewRoot还通过Binder系统和WindowManagerService进行了跨进程交互

·  ViewRoot能处理Handler的消息,Activity的显示就是由ViewRoot在它的performTraversals函数中完成的

·  整个Activity的绘图流程就是从mSurface中lock一块Canvas,然后交给mView去自由发挥画画的才能,最后unlockCanvasAndPost释放这块Canvas

这里和显示有关的就是最后三条了,其中最重要的内容都和Surface相关,既然mSurface是ViewRoot的本地变量,那就直接去看Surface。上面的代码分析一路走下来,真是比较流畅,波澜不惊,可事实果真如此吗?

8.3  初识Surface

本节将介绍Surface对象。它可是纵跨Java/JNI层的对象,想必读者朋友已经摩拳擦掌,跃跃欲试了。

8.3.1  和Surface有关的流程总结

这里,先总结一下前面讲解中和Surface有关的流程:

·  在ViewRoot构造时,会创建一个Surface,它使用无参构造函数,代码如下所示:

private final Surface mSurface = new Surface();

·  ViewRoot通过IWindowSession和WMS交互,会调用WMS中的一个attach函数,会构造一个SurfaceSession,代码如下所示:

void windowAddedLocked() {

   if(mSurfaceSession == null) {

        mSurfaceSession = new SurfaceSession();

        mNumWindow++;

}

}

·  ViewRoot在performTransval的处理过程中会调用IWindowSession的relayout函数。这个函数还没有分析。

·  ViewRoot调用Surface的lockCanvas,得到一块画布。

·  ViewRoot调用Surface的unlockCanvasAndPost释放这块画布。

这里从relayout函数开始分析,来看。

8.3.2  Surface之乾坤大挪移

1. 乾坤大挪移的表象

relayoutWindow的函数是一个跨进程的调用,由WMS完成实际处理。先到ViewRoot中看看调用方的用法,代码如下所示:

[-->ViewRoot.java]

private int relayoutWindow(WindowManager.LayoutParams params,

int viewVisibility, boolean insetsPending)

throws RemoteException {

       int relayoutResult = sWindowSession.relayout(

                mWindow, params,

               (int) (mView.mMeasuredWidth * appScale + 0.5f),

               (int) (mView.mMeasuredHeight * appScale + 0.5f),

               viewVisibility, insetsPending, mWinFrame,

               mPendingContentInsets, mPendingVisibleInsets,

               mPendingConfiguration, mSurface);//mSurface传了进去

        ......

       return relayoutResult;

    }

再看接收方的处理。它在WMS的Session中,代码如下所示:

[-->WindowManagerService.java::Session]

public int relayout(IWindow window,WindowManager.LayoutParams attrs,

               int requestedWidth, int requestedHeight, int viewFlags,

               boolean insetsPending, Rect outFrame, Rect outContentInsets,

               Rect outVisibleInsets, Configuration outConfig,

Surface outSurface) {

//注意最后这个参数的名字,叫outSurface

//调用外部类对象的relayoutWindow

   return relayoutWindow(this, window, attrs,

                    requestedWidth,requestedHeight, viewFlags, insetsPending,

                    outFrame, outContentInsets,outVisibleInsets, outConfig,

outSurface);

}

[-->WindowManagerService.java]

public int relayoutWindow(Session session,IWindow client,

           WindowManager.LayoutParams attrs, int requestedWidth,

           int requestedHeight, int viewVisibility, boolean insetsPending,

           Rect outFrame, Rect outContentInsets, Rect outVisibleInsets,

            Configuration outConfig, SurfaceoutSurface){

        .....

 try {

         //win就是WinState,这里将创建一个本地的Surface对象

         Surface surface = win.createSurfaceLocked();

          if(surface != null) {

            //先创建一个本地surface,然后在outSurface的对象上调用copyFrom

           //将本地Surface的信息拷贝到outSurface(ViewRoot中的)中

           outSurface.copyFrom(surface);

        ......

}

[-->WindowManagerService.java::WindowState]

Surface createSurfaceLocked() {

     ......

   try {

     //mSurfaceSession就是在Session上创建的SurfaceSession对象

     //这里,以它为参数,构造一个新的Surface对象

        mSurface = new Surface(

                mSession.mSurfaceSession, mSession.mPid,

                 mAttrs.getTitle().toString(),

                 0, w, h, mAttrs.format, flags);

      }

         Surface.openTransaction();//打开一个事务处理

        ......

         Surface.closeTransaction();//关闭一个事务处理。关于事务处理以后再分析

         ......

}

上面的代码段好像有点混乱。用图8-7来表示一下这个流程:


图8-7  复杂的Surface创建流程

根据图8-7可知:

·  WMS中的Surface是乾坤中的,它的构造使用了带SurfaceSession参数的构造函数。

·  ViewRoot中的Surface是乾坤中的,它的构造使用了无参构造函数。

·  copyFrom就是挪移,它将中的Surface信息,拷贝到中的Surface即outSurface里。

要是觉得乾坤大挪移就是这两三下,未免就太小看它了。为彻底揭示这期间的复杂过程,我们将使用必杀技——aidl工具。

2. 揭秘Surface的乾坤大挪移

奇怪!ViewRoot调用requestlayout竟然没有把outSurface信息传进去,这么说,服务端收到的Surface对象应该就是空吧?那怎么能调用copyFrom呢?还是来看服务端的处理,先看首先收到消息的onTransact函数,代码如下所示:

[-->test.java::Bn端::onTransact]

public boolean onTransact(int code,android.os.Parcel data,

                               android.os.Parcelreply, int flags)

                    throwsandroid.os.RemoteException

{

  switch(code)

  {

    caseTRANSACTION_relayout:

    {

      data.enforceInterface(DESCRIPTOR);

      android.view.IWindow_arg0;

      android.view.Surface_arg10;

      //刚才讲了,Surface信息并没有传过来,那么在relayOut中看到的outSurface是怎么

      //出来的呢?看下面这句可知,原来在服务端这边竟然new了一个新的Surface!!!

      _arg10= new android.view.Surface();

      int_result = this.relayout(_arg0, _arg1, _arg2, _arg3, _arg4,

      _arg5,_arg6, _arg7, _arg8, _arg9, _arg10);

      reply.writeNoException();

      reply.writeInt(_result);

      //_arg10就是调用copyFrom的那个outSurface,那怎么传到客户端呢?

      if((_arg10!=null)) {

           reply.writeInt(1);

           //调用outSurface的writeToParcel,把信息写到reply包中(返回给ViewRoot中的surface)。

           //注意最后一个参数为PARCELABLE_WRITE_RETURN_VALUE

           _arg10.writeToParcel(reply,android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);

        }

    }

    ......

   return true;

}

看完这个,会让人有点毛骨悚然。我最开始一直在JNI文件中寻找大挪移的踪迹,但有几个关键点始终不能明白,万不得已就使用了这个aidl必杀技,于是终于揭露出其真相了。

3. 乾坤大挪移的真相

这里,总结一下乾坤大挪移的整个过程,如图8-8表示:


图8-8  乾坤大挪移的真面目

上图非常清晰地列出了乾坤大挪移的过程,我们可结合代码来加深理解。

注意,这里,将BpWindowSession作为了IWindowSessionBinder在客户端的代表。

 

8.3.3  分析乾坤大挪移的JNI层

前文讲述的内容都集中在Java层,下面要按照流程顺序分析JNI层的内容。

1. Surface的无参构造分析

在JNI层,第一个被调用的是Surface的无参构造函数,其代码如下所示:

[-->Surface.java]

public Surface() {

        ......

       //CompatibleCanvas从Canvas类派生

       mCanvas = new CompatibleCanvas();

    }

Canvas是什么?根据SDK文档的介绍可知,画图需要“四大金刚”相互合作,这四大金刚是:

·  Bitmap:用于存储像素,也就是画布。可把它当做一块数据存储区域。

·  Canvas:用于记载画图的动作,比如画一个圆,画一个矩形等。Canvas类提供了这些基本的绘图函数。

·  Drawing primitive:绘图基元,例如矩形、圆、弧线、文本、图片等。

·  Paint:它用来描述绘画时使用的颜色、风格(如实线、虚线等)等。

在一般情况下,Canvas会封装一块Bitmap,而作图就是基于这块Bitmap的。前面说的画布,其实指的就是Canvas中的这块Bitmap

这些知识稍了解即可,不必去深究。Surface的无参构造函数没有什么有价值的内容,接着看下面的内容。

2. SurfaceSession的构造

现在要分析的是SurfaceSession,其构造函数如下所示:

[-->SurfaceSession.java]

public SurfaceSession() {

       init();//这是一个native函数

}

init是一个native函数。去看看它的JNI实现,它在android_view_Surface.cpp中,代码如下所示:

[-->android_view_Surface.cpp]

static void SurfaceSession_init(JNIEnv* env,jobject clazz)

{

     //创建一个SurfaceComposerClient对象

   sp<SurfaceComposerClient> client = new SurfaceComposerClient;

client->incStrong(clazz);

//在Java对象中保存这个client对象的指针到SurfaceSession,类型为SurfaceComposerClient

   env->SetIntField(clazz, sso.client, (int)client.get());

}

这里先不讨论SurfaceComposerClient的内容,拟继续把乾坤大挪移的流程走完。

3. Surface的有参构造

下一个调用的是Surface的有参构造,其参数中有一个SurfaceSession。先看Java层的代码,如下所示:

[-->Surface.java]

    //传入一个SurfaceSession对象

    publicSurface(SurfaceSession s,int pid, String name, int display, int w, int h, int format, int flags)

       throws OutOfResourcesException {

        ......

       mCanvas = new CompatibleCanvas();

      //又一个native函数,注意传递的参数:display  以后再说,w,h代表绘图区域的宽高值

       init(s,pid,name,display,w,h,format,flags);

       mName = name;

    }

Surface的native init函数的JNI实现,也在android_view_Surface.cpp中,一起来看:

[-->android_view_Surface.cpp]

static void Surface_init(

        JNIEnv*env, jobject clazz,

       jobject session,

       jint pid, jstring jname, jint dpy, jint w, jint h, jint format, jintflags)

{

   //从SurfaceSession对象中取出之前创建的那个SurfaceComposerClient对象

SurfaceComposerClient* client =

           (SurfaceComposerClient*)env->GetIntField(session, sso.client);

 

   sp<SurfaceControl> surface;//注意它的类型是SurfaceControl

if (jname == NULL) {

    /*

调用SurfaceComposerClient的createSurface函数,返回的surface是一个

SurfaceControl类型。

*/

       surface = client->createSurface(pid, dpy, w, h, format, flags);

    } else{

        ......

}

   //把这个surfaceControl对象设置到Java层的Surface对象中,对这个函数就不再分析了

   setSurfaceControl(env, clazz, surface);

}

4. copyFrom的分析

现在要分析的就是copyFrom了。它就是一个native函数。看它的JNI层代码:

[-->android_view_Surface.cpp]

static void Surface_copyFrom(JNIEnv* env,jobject clazz, jobject other)

{

   //根据JNI函数的规则,clazz是copyFrom的调用对象,而other是copyFrom的参数。

   //目标对象此时还没有设置SurfaceControl,而源对象在前面已经创建了SurfaceControl

   constsp<SurfaceControl>& surface = getSurfaceControl(env, clazz);

   constsp<SurfaceControl>& rhs = getSurfaceControl(env, other);

if (!SurfaceControl::isSameSurface(surface, rhs)) {

        //把源SurfaceControl对象设置到目标Surface中。

       setSurfaceControl(env, clazz, rhs);

    }

}

这一步还是比较简单的,下面看第五步writeToParcel函数的调用。

5. writeToParcel的分析

多亏了必杀技aidl工具的帮忙,才挖出这个隐藏的writeToParcel函数调用,下面就来看看它,代码如下所示:

[-->android_view_Surface.cpp]

static void Surface_writeToParcel(JNIEnv* env,jobject clazz,

jobject argParcel, jint flags)

{

   Parcel* parcel = (Parcel*)env->GetIntField(argParcel, no.native_parcel);

//clazz就是Surface对象,从这个Surface对象中取出保存的SurfaceControl对象

const sp<SurfaceControl>&control(getSurfaceControl(env, clazz));

/*

把SurfaceControl中的信息写到Parcel包中,然后利用Binder通信传递到对端,

对端通过readFromParcel来处理Parcel包。

*/

   SurfaceControl::writeSurfaceToParcel(control, parcel);

if (flags & PARCELABLE_WRITE_RETURN_VALUE) {

       //还记得PARCELABLE_WRITE_RETURN_VALUE吗?flags的值就等于它

       //所以本地Surface对象的SurfaceControl值被置空了

       setSurfaceControl(env, clazz, 0);

    }

}

 

6. readFromParcel的分析

再看作为客户端的ViewRoot所调用的readFromParcel函数。它也是一个native函数,JNI层的代码如下所示:

[-->android_view_Surface.cpp]

static void Surface_readFromParcel(

       JNIEnv* env, jobject clazz, jobject argParcel)

{

   Parcel* parcel = (Parcel*)env->GetIntField( argParcel,no.native_parcel);

  

   //注意下面定义的变量类型是Surface,而不是SurfaceControl

   const sp<Surface>&control(getSurface(env, clazz));

   //根据服务端传递的Parcel包来构造一个新的surface。

   sp<Surface> rhs = new Surface(*parcel);

if (!Surface::isSameSurface(control, rhs)) {

//把这个新surface赋给ViewRoot中的mSurface对象。

      setSurface(env,clazz, rhs);

    }

}

7. Surface乾坤大挪移的小结

可能有人会问,乾坤大挪移怎么这么复杂?这期间出现了多少对象?来总结一下,在此期间一共有三个关键对象(注意我们这里只考虑JNI层的Native对象),它们分别是:

·  SurfaceComposerClient。

·  SurfaceControl。

·  Surface,这个Surface对象属于Native层,和Java层的Surface相对应。

其中转移到ViewRoot成员变量mSurface中的,就是最后这个Surface对象了。这一路走来,真是异常坎坷。来回顾并概括总结一下这段历程。至于它的作用应该是很清楚了。以后要破解SurfaceFlinger,靠的就是这个精简的流程。

·  创建一个SurfaceComposerClient。

·  调用SurfaceComposerClient的createSurface得到一个SurfaceControl对象。

·  调用SurfaceControl的writeToParcel把一些信息写到Parcel包中。

·  根据Parcel包的信息构造一个Surface对象。这个Surface对象保存到Java层的mSurface对象中。这样,大挪移的结果是ViewRoot得到一个Native的Surface对象。

精简流程后,寥寥数语就可把过程说清楚。以后我们在研究代码时,也可以采取这种方式。

这个Surface对象非常重要,可它到底有什么用呢?这正是下一节要讲的内容。

8.3.4  Surface和画图

下面,来看最后两个和Surface相关的函数调用:一个是lockCanvas;另外一个是unlockCanvasAndPost。

1. lockCanvas的分析

要对lockCanvas进行分析,须先来看Java层的函数,代码如下所示:

[-->Surface.java::lockCanvas()]

public Canvas lockCanvas(Rect dirty)

throws OutOfResourcesException,IllegalArgumentException

 {

       return lockCanvasNative(dirty);//调用native的lockCanvasNative函数。

}

[-->android_view_Surface.cpp::Surface_lockCanvas()]

static jobject Surface_lockCanvas(JNIEnv* env,jobject clazz, jobject dirtyRect)

{

    //从Java中的Surface对象中,取出费尽千辛万苦得到的Native的Surface对象

    constsp<Surface>& surface(getSurface(env, clazz));

    ......

 

// dirtyRect表示需要重绘的矩形块,下面根据这个dirtyRect设置dirtyRegion

    RegiondirtyRegion;

    if(dirtyRect) {

       Rect dirty;

       dirty.left  =env->GetIntField(dirtyRect, ro.l);

       dirty.top   =env->GetIntField(dirtyRect, ro.t);

       dirty.right = env->GetIntField(dirtyRect, ro.r);

        dirty.bottom=env->GetIntField(dirtyRect, ro.b);

        if(!dirty.isEmpty()) {

           dirtyRegion.set(dirty);   

        }

    } else{

       dirtyRegion.set(Rect(0x3FFF,0x3FFF));

    }

   

//调用NativeSurface对象的lock函数

//传入了一个参数Surface::SurfaceInfo info和一块表示脏区域的dirtyRegion

   Surface::SurfaceInfo info;

   status_t err = surface->lock(&info, &dirtyRegion);

    ......

//Java的Surface对象构造的时候会创建一个CompatibleCanvas。

//这里就取出这个CompatibleCanvas对象

   jobject canvas = env->GetObjectField(clazz, so.canvas);

   env->SetIntField(canvas, co.surfaceFormat, info.format);

    //从Canvas对象中取出SkCanvas对象

   SkCanvas* nativeCanvas =(SkCanvas*)env->GetIntField(canvas, no.native_canvas);

    SkBitmap bitmap;

    ssize_t bpr = info.s *bytesPerPixel(info.format);

   bitmap.setConfig(convertPixelFormat(info.format), info.w, info.h, bpr);

   ......

if (info.w > 0 && info.h > 0) {

//info.bits指向一块存储区域。

       bitmap.setPixels(info.bits);

    } else{

        bitmap.setPixels(NULL);

}

//给这个SkCanvas设置一个Bitmap

//这里将Bitmap设置到这个Canvas中,这样进UI绘画时就有画布了。

   nativeCanvas->setBitmapDevice(bitmap);

    ......

   

    return canvas;

}

lockCanvas还算比较简单:

·  先获得一块存储区域,然后将它和Canvas绑定到一起,这样,UI绘画的结果就记录在这块存储区域里了。

注意,本书不拟讨论Android系统上Skia和OpenGL方面的知识,有兴趣的读者可自行研究。

接下来看unlockCanvasAndPost函数,它也是一个native函数:

2. unlockCanvasAndPost的分析

来看unlockCanvasAndPost的代码,如下所示:

[-->android_view_Surface.cpp]

static void Surface_unlockCanvasAndPost(JNIEnv*env, jobject clazz,

jobject argCanvas)

{

    jobjectcanvas = env->GetObjectField(clazz, so.canvas);

    //从Java中的Surface对象中,取出Native的Surface对象

const sp<Surface>& surface(getSurface(env,clazz));

//下面这些内容,不拟讨论,读者若有兴趣,可结合Skia库,自行研究。

SkCanvas* nativeCanvas =(SkCanvas*)env->GetIntField(canvas,

                                                 no.native_canvas);

    intsaveCount = env->GetIntField(clazz, so.saveCount);

   nativeCanvas->restoreToCount(saveCount);

   nativeCanvas->setBitmapDevice(SkBitmap());

   env->SetIntField(clazz, so.saveCount, 0);

 

    //调用Surface对象的unlockAndPost函数。

   status_t err = surface->unlockAndPost();

    ......

}

unlockCanvasAndPost也很简单,这里就不再多说了。

8.3.5  初识Surface总结

在本节的最后,我们来概括总结一下这一节所涉及到和Surface相关的调用流程,以备攻克下一个难关,如图8-9所示 :


图8-9  Surface的精简流程图

8.4  深入分析Surface

这一节,拟基于图8-9中的流程,对Surface进行深入分析。在分析之前,还需要介绍一些Android平台上图形/图像显示方面的知识,这里统称之为与Surface相关的基础知识。

8.4.1  与Surface相关的基础知识介绍

1. 显示层(Layer)和屏幕组成

你了解屏幕显示的漂亮界面是如何组织的吗?来看图8-10所展示的屏幕组成示意图:


图8-10  屏幕组成示意图

从图8-10中可以看出:

·  屏幕位于一个三维坐标系中,其中Z轴从屏幕内指向屏幕外

·  编号为①②③的矩形块叫显示层(Layer)。每一层有自己的属性,例如颜色、透明度、所处屏幕的位置、宽、高等。除了属性之外,每一层还有自己对应的显示内容,也就是需要显示的图像

在Android中,Surface系统工作时,会由SurfaceFlinger对这些按照Z轴排好序的显示层进行图像混混合后的图像就是在屏幕上看到的美妙画面了。这种按Z轴排序的方式符合我们在日常生活中的体验,例如前面的物体会遮挡住后面的物体。

注意,Surface系统中定义了一个名为Layer类型的类,为了区分广义概念上的Layer和代码中的Layer,这里称广义层的Layer为显示层,以免混淆。

Surface系统提供了三种属性,一共四种不同的显示层。简单介绍一下:

·  第一种属性是eFXSurfaceNormal属性,大多数的UI界面使用的就是这种属性。它有两种模式

       1)Normal模式,这种模式的数据,是通过前面的mView.draw(canvas)画上去的。这也是绝大多数UI所采用的方式。

       2)PushBuffer模式,这种模式对应于视频播放、摄像机摄录/预览等应用场景。以摄像机为例,当摄像机运行时,来自Camera的预览数据直接push到Buffer中,无须应用层自己再去draw了。

·  第二种属性是eFXSurfaceBlur属性这种属性的UI有点朦胧美,看起来很像隔着一层毛玻璃。

·  第三种属性是eFXSurfaceDim属性这种属性的UI看起来有点暗,好像隔了一层深色玻璃。从视觉上讲,虽然它的UI看起来有点暗,但并不模糊。而eFXSurfaceBlur不仅暗,还有些模糊。

图8-11展示了最后两种类型的视觉效果图,其中左边的是Blur模式,右边的是Dim模式。

图8-11  Blur和Dim效果图

注意,关于Surface系统的显示层属性定义,读者可参考ISurfaceComposer.h。

本章将重点分析第一种属性的两类显示层的工作原理。

2. FrameBuffer和PageFlipping

我们知道,在Audio系统中,音频数据传输的过程是:

·  由客户端把数据写到共享内存中。

·  然后由AudioFlinger从共享内存中取出数据再往Audio HAL中发送。

根据以上介绍可知,在音频数据传输的过程中,共享内存起到了数据承载的重要作用。                                                           无独有偶,Surface系统中的数据传输也存在同样的过程,但承载图像数据的是鼎鼎大名的FrameBuffer(简称FB)。

(1)FrameBuffer的介绍

FrameBuffer的中文名叫帧缓冲,它实际上包括两个不同的方面:

·  Frame:帧,就是指一幅图像。在屏幕上看到的那幅图像就是一帧。

·  Buffer:缓冲,就是一段存储区域,可这个区域存储的是帧。

FrameBuffer的概念很清晰,它就是一个存储 图形/图像帧数据的缓冲。这个缓冲来自哪里?理解这个问题,需要简单介绍一下Linux平台的虚拟显示设备FrameBuffer Device(简称FBD)。FBD是Linux系统中的一个虚拟设备,设备文件对应为/dev/fb%d(比如/dev/fb0)这个虚拟设备将不同硬件厂商实现的真实设备统一在一个框架下,这样应用层就可以通过标准的接口进行图形/图像的输入和输出了。图8-12展示了FBD示意图:


图8-12  Linux系统中的FBD示意图

从上图中可以看出,应用层通过标准的ioctl或mmap等系统调用,就可以操作显示设备,用起来非常方便。这里,把mmap的调用列出来,相信大部分读者都知道它的作用了。

FrameBuffer中的Buffer,就是通过mmap把设备中的显存映射到用户空间的,在这块缓冲上写数据,就相当于在屏幕上绘画。

注意:上面所说的框架将引出另外一个概念Linux FrameBuffer(简称LFB)。LFB是Linux平台提供的一种可直接操作FB的机制依托这个机制,应用层通过标准的系统调用,就可以操作显示设备了。从使用的角度来看,它和Linux Audio中的OSS有些类似。


前面在Audio系统中讲过,CB对象通过读写指针来协调生产者/消费者的步调Surface系统中也一样

(2)PageFlipping

图形/图像数据和音频数据不太一样,我们一般把音频数据叫音频流,它是没有边界的, 而图形/图像数据是一帧一帧的,是有边界的。这一点非常类似UDP和TCP之间的区别。所以在图形/图像数据的生产/消费过程中,人们使用了一种叫PageFlipping的技术。

PageFlipping的中文名叫画面交换,其操作过程如下所示:

·  分配一个能容纳两帧数据的缓冲,前面一个缓冲叫FrontBuffer,后面一个缓冲叫BackBuffer。

·  消费者使用FrontBuffer中的旧数据,而生产者用新数据填充BackBuffer,二者互不干扰。

·  当需要更新显示时,BackBuffer变成FrontBuffer,FrontBuffer变成BackBuffer。如此循环,这样就总能显示最新的内容了。这个过程很像我们平常的翻书动作,所以它被形象地称为PageFlipping。

说白了,PageFlipping其实就是使用了一个只有两个成员的帧缓冲队列,以后在分析数据传输的时候还会见到诸如dequeue和queue的操作。

3. 图像混合

在AudioFlinger中有混音线程,它能将来自多个数据源的数据混合后输出,Surface系统支持软硬两个层面的图像混合:

·  软件层面的混合:例如使用copyBlt进行源数据和目标数据的混合。

·  硬件层面的混合:使用Overlay系统提供的接口。

无论是硬件还是软件层面,都需将源数据和目标数据进行混合,混合需考虑很多内容,例如源的颜色和目标的颜色叠加后所产生的颜色。关于这方面的知识,读者可以学习计算机图形/图像学。这里只简单介绍一下copyBlt和Overlay。

·  copyBlt,从名字上看,是数据拷贝,它也可以由硬件实现,例如现在很多的2D图形加速就是将copyBlt改由硬件来实现,以提高速度的。但不必关心这些,我们只需关心如何调用copyBlt相关的函数进行数据混合即可

·  Overlay方法必须有硬件支持才可以,它主要用于视频的输出,例如视频播放、摄像机摄像等,因为视频的内容往往变化很快,所以如改用硬件进行混合效率会更高

总体来说,Surface是一个比较庞大的系统,由于篇幅和精力所限,本章后面的内容将重点关注Surface系统的框架和工作流程。在掌握框架和流程后,读者就可以在大的脉络中迅速定位到自己感兴趣的地方,然后展开更深入的研究了。

下面通过图8-9所示的精简流程,深入分析Android的Surface系统。

8.4.2  SurfaceComposerClient的分析

1. 创建SurfaceComposerClient

[-->SurfaceComposerClient.cpp]

SurfaceComposerClient::SurfaceComposerClient()

{

  //getComposerService()将返回SF的BpSurfaceFlinger对象

sp<ISurfaceComposer> sm(getComposerService());

//先调用SF的createConnection,再调用_init

  _init(sm, sm->createConnection());

 

    if(mClient != 0) {

       Mutex::Autolock _l(gLock);

       //gActiveConnections是全局变量,把刚才创建的client保存到这个map中去

       gActiveConnections.add(mClient->asBinder(), this);

    }

}

果然如此,SurfaceComposerClient建立了和SF的交互通道,下面直接转到SF的createConnection函数去观察。

(1)createConnection的分析

直接看代码,如下所示:

[-->SurfaceFlinger.cpp]

sp<ISurfaceFlingerClient>SurfaceFlinger::createConnection()

{

   Mutex::Autolock _l(mStateLock);

   uint32_t token = mTokens.acquire();

   //先创建一个Client。

   sp<Client> client = new Client(token, this);

    //把这个Client对象保存到mClientsMap中,token是它的标识。

   status_t err = mClientsMap.add(token, client);

/*

创建一个用于Binder通信的BClient,BClient派生于ISurfaceFlingerClient,

接受客户端的请求,然后把处理提交给SF,注意,并不是提交给Client

Client会创建一块共享内存,该内存由getControlBlockMemory函数返回

*/

   sp<BClient> bclient = new BClient(this, token,client->getControlBlockMemory());

    return bclient;

}

上面代码中提到,Client会创建一块共享内存。熟悉Audio的读者或许会认为,这可能是Surface的ControlBlock对象了!是的。CB对象在协调生产/消费步调时,起到了决定性的控制作用,所以非常重要,下面来看:

[-->SurfaceFlinger.cpp]

Client::Client(ClientID clientID, constsp<SurfaceFlinger>& flinger)

    :ctrlblk(0), cid(clientID), mPid(0), mBitmap(0), mFlinger(flinger)

{

const int pgsize = getpagesize();

//下面这个操作会使cblksize为页的大小,目前是4096字节。

    constint cblksize = ((sizeof(SharedClient)+(pgsize-1))&~(pgsize-1));

    //MemoryHeapBase是我们的老朋友了,共享内存操作封装类

   mCblkHeap = new MemoryHeapBase(cblksize, 0, "SurfaceFlinger Clientcontrol-block");

 

   ctrlblk = static_cast<SharedClient *>(mCblkHeap->getBase());

    if(ctrlblk) {

       new(ctrlblk) SharedClient; //使用了placement new

    }

}

原来,Surface的CB对象就是在共享内存中创建的这个SharedClient对象。先来认识一下这个SharedClient。

(2)SharedClient的分析

SharedClient定义了一些成员变量,代码如下所示:

class SharedClient

{

public:

   SharedClient();

   ~SharedClient();

   status_t validate(size_t token) const;

   uint32_t getIdentity(size_t token) const;//取出标识本Client的token

 

private:

    Mutexlock;

Condition cv; //支持跨进程的同步对象

//NUM_LAYERS_MAX为31,

// 一个Client最多支持31个显示层。每一个显示层的生产/消费 步调都由会对应的SharedBufferStack来控制。

// 而它内部就用了几个成员变量来控制读写位置。

   SharedBufferStack surfaces[ NUM_LAYERS_MAX ];

};

//SharedClient的构造函数,没什么新意,不如Audio的CB对象复杂

SharedClient::SharedClient()

    :lock(Mutex::SHARED), cv(Condition::SHARED)

{

}


认识一下SharedBufferStack的这几个控制变量,如下所示:

[-->SharedBufferStack.h]

class  SharedBufferStack{

     ......

    //Buffer是按块使用的,每个Buffer都有自己的编号,其实就是数组中的索引号。

   volatile int32_t head;     //FrontBuffer的编号

   volatile int32_t available; //空闲Buffer的个数

   volatile int32_t queued;  //脏Buffer的个数,脏Buffer表示有新数据的Buffer

   volatile int32_t inUse; //SF当前正在使用的Buffer的编号   

    volatilestatus_t status; //状态码

     ......

  }

注意,上面定义的SharedBufferStack是一个通用的控制结构,而不仅是针对于只有两个Buffer的情况。根据前面介绍的PageFlipping知识,如果只有两个FB,那么,SharedBufferStack的控制就比较简单了:

要么SF读1号Buffer,客户端写0号Buffer,要么SF读0号Buffer,客户端写1号Buffer。

图8-13是展示了SharedClient的示意图:


图8-13  SharedClient的示意图

从上图可知:

·  SF的Client变量分配一个跨进程共享的SharedClient对象。这个对象有31个SharedBufferStack元素,每一个SharedBufferStack对应于一个显示层。

·  一个显示层将创建两个Buffer,后续的PageFlipping就是基于这两个Buffer展开的。

另外,每一个显示层中,其数据的生产和消费并不是直接使用SharedClient对象来进行具体控制的,而是基于SharedBufferServerSharedBufferClient两个结构,由这两个结构来对该显示层使用的SharedBufferStack进行操作,这些内容在以后的分析中还会碰到。

注意,这里的显示层指的是Normal类型的显示层。

来接着分析后面的_init函数。

(3)_init函数的分析

先回顾一下之前的调用,代码如下所示:

[-->SurfaceComposerClient.cpp]

SurfaceComposerClient::SurfaceComposerClient()

{

   ......

   _init(sm, sm->createConnection());

   ......

}

来看这个_init函数,代码如下所示:

[-->SurfaceComposerClient.cpp]

void SurfaceComposerClient::_init(const sp<ISurfaceComposer>& sm, constsp<ISurfaceFlingerClient>& conn)

{

   mPrebuiltLayerState = 0;

   mTransactionOpen = 0;

   mStatus = NO_ERROR;

   mControl = 0;

 

   mClient = conn;//mClient就是BClient的客户端

    mControlMemory =mClient->getControlBlock();

mSignalServer = sm;// mSignalServer就是BpSurfaceFlinger

//mControl就是那个创建于共享内存之中的SharedClient

    mControl = static_cast<SharedClient*>(mControlMemory->getBase());

}

_init函数的作用,就是初始化SurfaceComposerClient中的一些成员变量。最重要的是得到了三个成员:

·  mSignalServer 它其实是SurfaceFlinger的客户端代理BpSurfaceFlinger,它的主要作用是,在客户端更新完BackBuffer后(也就是刷新了界面后),通知SF进行PageFlipping和输出等工作。

·  mControl它是跨进程共享的SharedClient,共享内存之中,是Surface系统的ControlBlock对象。

·  mClient它是BClient的客户端。

 

2. 到底有多少种对象?

这一节,出现了好几种类型的对象,通过图8-14来看看它们:


图8-14  类之间关系展示图

从上图中可以看出:

·  SurfaceFlinger是从Thread派生的,所以它会有一个单独运行的工作线程。

·  BClient和SF之间采用了Proxy模式,BClient支持Binder通信,它接收客户端的请求,并派发给SF执行

·  SharedClient构建于一块共享内存中,SurfaceComposerClient和Client对象均持有这块共享内存

在精简流程中,关于SurfaceComposerClient就分析到这里,下面分析第二个步骤中的SurfaceControl对象。

8.4.3  SurfaceControl的分析

1. SurfaceControl的来历

根据精简的流程可知,这一节要分析的是SurfaceControl对象。先回顾一下这个对象的创建过程,代码如下所示:

[-->android_view_Surface.cpp]

static void Surface_init(JNIEnv* env, jobjectclazz, jobject session,

       jint pid, jstring jname, jint dpy, jint w, jint h, jint format, jintflags)

{

    SurfaceComposerClient* client =

           (SurfaceComposerClient*)env->GetIntField(session, sso.client);

    //注意这个变量,类型是SurfaceControl,名字却叫surface,稍不留神就出错了。

    sp<SurfaceControl>surface;

if (jname == NULL) {

    //调用Client的createSurface函数,得到一个SurfaceControl对象。

   // 使用Binder通信将请求发给SF

    surface= client->createSurface(pid, dpy, w, h, format, flags);

    }

......

   //将这个SurfaceControl对象设置到Java层的对象中保存。

   setSurfaceControl(env, clazz, surface);

}

通过上面的代码可知,SurfaceControl对象由createSurface得来,下面看看这个函数。

此时,读者或许会被代码中随意起的变量名搞糊涂,因为我的处理方法碰到了容易混淆的地方,尽量以对象类型来表示这个对象。

(1)分析createSurface的请求端

在createSurface内部会使用Binder通信将请求发给SF,所以它分为请求和响应两端,先看请求端,代码如下所示:

[-->SurfaceComposerClient.cpp]

sp<SurfaceControl>SurfaceComposerClient::createSurface(

       int pid,

       DisplayID display,//DisplayID屏幕编号,例如双屏手机就有内屏和外屏两块屏幕。由于目前Android的Surface系统只支持一块屏幕,所以这个变量的取值都是0。

       uint32_t w,

       uint32_t h,

       PixelFormat format,

       uint32_t flags)

{

   String8 name;

    constsize_t SIZE = 128;

    charbuffer[SIZE];

   snprintf(buffer, SIZE, "<pid_%d>", getpid());

   name.append(buffer);

   //调用另外一个createSurface,多一个name参数

    return SurfaceComposerClient::createSurface(pid, name, display,w, h, format, flags);

}

再分析另外一个createSurface函数,它的代码如下所示:

[-->SurfaceComposerClient.cpp]

sp<SurfaceControl>SurfaceComposerClient::createSurface(

       int pid,const String8& name,DisplayID display,uint32_t w,

       uint32_t h,PixelFormat format,uint32_t flags)

{

   sp<SurfaceControl> result;

    if(mStatus == NO_ERROR) {

       ISurfaceFlingerClient::surface_data_t data;

        //调用BpSurfaceFlingerClient的createSurface函数

       sp<ISurface> surface = mClient->createSurface(&data, pid,name,display, w, h,format, flags);

        if(surface != 0) {

           if (uint32_t(data.token) < NUM_LAYERS_MAX) {

               //以返回的ISurface对象创建一个SurfaceControl对象

               result = new SurfaceControl(this, surface, data, w, h,format, flags);

           }

        }

}

    return result;//返回的是SurfaceControl对象

}

请求端的处理比较简单:

·  调用跨进程的createSurface函数,得到一个ISurface对象,根据Binder一章的知识可知,这个对象的真实类型是BpSurface。不过以后统称之为ISurface。

·  以这个ISurface对象为参数,构造一个SurfaceControl对象。

createSurface函数的响应端在SurfaceFlinger进程中,下面去看这个函数。

在Surface系统定义了很多类型,咱们也中途休息一下,不妨来看看和字符串“Surface”有关的有多少个类,权当其为小小的娱乐:

Native层有Surface、ISurface、SurfaceControl、SurfaceComposerClient。

Java层有Surface、SurfaceSession。

上面列出的还只是一部分,后面还有呢!*&@&*%¥*

(2)分析createSurface的响应端

前面讲过,可把BClient看作是SF的Proxy,它会把来自客户端的请求派发给SF处理,通过代码来看看,是不是这样的?如下所示:

[-->SurfaceFlinger.cpp]

sp<ISurface> BClient::createSurface(

       ISurfaceFlingerClient::surface_data_t* params, int pid,

       const String8& name,

       DisplayID display, uint32_t w, uint32_t h, PixelFormat format,

       uint32_t flags)

{

  //果然是交给SF处理,以后我们将跳过BClient这个代理。 

return mFlinger->createSurface(mId, pid,name, params, display, w, h,format, flags);

}

来看createSurface函数,它的目的就是创建一个ISurface对象,不过这中间的玄机还挺多,代码如下所示:

[-->SurfaceFlinger.cpp]

sp<ISurface>SurfaceFlinger::createSurface(ClientID clientId, int pid,

       const String8& name, ISurfaceFlingerClient::surface_data_t* params,

       DisplayID d, uint32_t w, uint32_t h, PixelFormat format,

       uint32_t flags)

{

sp<LayerBaseClient> layer;//LayerBaseClient是Layer家族的基类

//这里又冒出一个LayerBaseClient的内部类,它也叫Surface,

   sp<LayerBaseClient::Surface> surfaceHandle;

 

   

Mutex::Autolock _l(mStateLock);

//根据clientId找到createConnection时加入的那个Client对象

   sp<Client> client = mClientsMap.valueFor(clientId);

    ......

   //注意这个id,它的值表示Client创建的是第几个显示层,根据图8-14可以看出,这个id

//同时也表示将使用SharedBufferStatck数组的第id个元素。

int32_t id = client->generateId(pid);

//一个Client不能创建多于NUM_LAYERS_MAX个的Layer。

    if(uint32_t(id) >= NUM_LAYERS_MAX) {

       return surfaceHandle;

    }

   //根据flags参数来创建不同类型的显示层,我们在8.4.1节介绍过相关知识

    switch(flags & eFXSurfaceMask) {

       case eFXSurfaceNormal:

           if (UNLIKELY(flags & ePushBuffers)) {

             //创建PushBuffer类型的显示层,我们将在拓展思考部分分析它

            layer = createPushBuffersSurfaceLocked(client, d, id,

                        w, h, flags);

           } else {

               //①创建Normal类型的显示层,

               layer = createNormalSurfaceLocked(client, d, id,w, h, flags, format);

           }

           break;

       case eFXSurfaceBlur:

            //创建Blur类型的显示层

           layer = createBlurSurfaceLocked(client, d, id, w, h, flags);

           break;

        case eFXSurfaceDim:

            //创建Dim类型的显示层

           layer = createDimSurfaceLocked(client, d, id, w, h, flags);

           break;

    }

 

    if(layer != 0) {

       layer->setName(name);

       setTransactionFlags(eTransactionNeeded);

//从显示层对象中取出一个ISurface对象赋值给SurfaceHandle

       surfaceHandle = layer->getSurface();

        if(surfaceHandle != 0) {

           params->token = surfaceHandle->getToken();

           params->identity = surfaceHandle->getIdentity();

           params->width = w;

           params->height = h;

           params->format = format;

        }

    }

    return surfaceHandle;//ISurface的Bn端就是这个对象。就是要返回给客户端的ISurface

}

上面代码中的函数倒是很简单,知识代码里面冒出来的几个新类型和它们的名字却让人有点头晕。先用文字总结一下:

·  LayerBaseClient:前面提到的显示层在代码中的对应物,就是这个LayerBaseClient,不过这是一个大家族,不同类型的显示层将创建不同类型的LayerBaseClient。

·  LayerBaseClient中有一个内部类,名字叫Surface,这是一个支持Binder通信的类,它派生于ISurface。

关于Layer的故事,后面会有单独的章节来介绍。这里先继续分析createNormalSurfaceLocked函数。它的代码如下所示:

[-->SurfaceFlinger.cpp]

// 显示层创建

sp<LayerBaseClient>SurfaceFlinger::createNormalSurfaceLocked(

       const sp<Client>& client, DisplayID display,

       int32_t id, uint32_t w, uint32_t h, uint32_t flags,

       PixelFormat& format)

{

    //①创建一个Layer类型的对象

sp<Layer> layer = new Layer(this, display,client, id);

   //②设置Buffer

   status_t err = layer->setBuffers(w, h, format, flags);

if (LIKELY(err == NO_ERROR)) {

         //初始化这个新layer的一些状态

       layer->initStates(w, h, flags);

       //③ 还记得在图8-10中提到的Z轴吗?下面这个函数把这个layer加入到Z轴大军中。

       addLayer_l(layer);

}

......

    return layer;

}

createNormalSurfaceLocked函数有三个关键点,它们是:

·  构造一个Layer对象。

·  调用Layer对象的setBuffers函数。

·  调用SF的addLayer_l函数。

暂且记住这三个关键点,后文有单独章节分析它们。先继续分析SurfaceControl的流程。

(3)创建SurfaceControl对象

当跨进程的createSurface调用返回一个ISurface对象时,将通过ISurface对象创建一个SurfaceControl对象:

result = new SurfaceControl(this, surface, data,w, h,format, flags);

下面来看这个SurfaceControl对象为何物。它的代码如下所示:

[-->SurfaceControl.cpp]

SurfaceControl::SurfaceControl(

       const sp<SurfaceComposerClient>& client,

       const sp<ISurface>& surface,

       const ISurfaceFlingerClient::surface_data_t& data,

       uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)

    //mClient为SurfaceComposerClient,而mSurface指向跨进程createSurface调用

   //返回的ISurface对象。

    :mClient(client), mSurface(surface),

     mToken(data.token), mIdentity(data.identity),

     mWidth(data.width), mHeight(data.height), mFormat(data.format),

     mFlags(flags)

{

}

SurfaceControl类可以看作是一个wrapper类:

它封装了一些函数,通过这些函数可以方便地调用mClient或ISurface提供的函数。

在SurfaceControl的分析过程中,还遗留了和Layer相关的部分,下面就来解决它们。

2. Layer和它的家族

我们在createSurface中创建的是Normal的Layer,下面先看这个Layer的构造函数。

(1)Layer的构造

Layer是从LayerBaseClient派生的,其代码如下所示:

[-->Layer.cpp]

Layer::Layer(SurfaceFlinger* flinger, DisplayIDdisplay,

       const sp<Client>& c, int32_t i)//这个i表示SharedBufferStack数组的索引

    :   LayerBaseClient(flinger, display, c, i),//先调用基类构造函数

       mSecure(false),

       mNoEGLImageForSwBuffers(false),

       mNeedsBlending(true),

       mNeedsDithering(false)

{

     //getFrontBuffer实际取出的是FrontBuffer的位置

   mFrontBufferIndex = lcblk->getFrontBuffer();

}

再来看基类LayerBaseClient的构造函数,代码如下所示:

[-->LayerBaseClient.cpp]

LayerBaseClient::LayerBaseClient(SurfaceFlinger*flinger, DisplayID display,

       const sp<Client>& client, int32_t i)

    :LayerBase(flinger, display), lcblk(NULL), client(client), mIndex(i),

      mIdentity(uint32_t(android_atomic_inc(&sIdentity)))

{

   /*

    创建一个SharedBufferServer对象,注意它使用了SharedClient对象,

    并且传入了表示SharedBufferStack数组索引的i和一个常量NUM_BUFFERS

*/

lcblk = new SharedBufferServer(client->ctrlblk, i, NUM_BUFFERS,//该值为常量2,在Layer.h中定义

           mIdentity);

}

其实,之前在介绍SharedClient时曾提过与此相关的内容,这里再来认识一下,先看图8-15:


图8-15  ShardBufferServer的示意图

根据上图并结合前面的介绍,可以得出以下结论:

·  在SF进程中,Client的一个Layer将使用SharedBufferStack数组中的一个成员,并通过SharedBufferServer结构来控制这个成员,我们知道SF是消费者,所以可由SharedBufferServer来控制数据的读取。

·  与之相对应,客户端的进程也会有一个对象来使用这个SharedBufferStatck,可它是通过另外一个叫SharedBufferClient的结构来控制的。客户端为SF提供数据,所以可由SharedBufferClient控制数据的写入

(2)setBuffers的分析

[-->Layer.cpp]

status_t Layer::setBuffers( uint32_t w, uint32_th,PixelFormat format,uint32_t flags)

{

/*

创建Buffer,这里将创建两个GraphicBuffer。这两个GraphicBuffer就是我们前面

所说的FrontBuffer和BackBuffer。

    */

for (size_t i=0 ; i<NUM_BUFFERS ; i++) {

       mBuffers[i] = new GraphicBuffer();

}

//又冒出来一个SurfaceLayer类型

   mSurface = new SurfaceLayer(mFlinger, clientIndex(), this);

    return NO_ERROR;

}

(3)addLayer_l的分析

addLayer_l把这个新创建的layer加入自己的Z轴大军,下面来看:

[-->SurfaceFlinger.cpp]

status_t SurfaceFlinger::addLayer_l(constsp<LayerBase>& layer)

{

/*

mCurrentState是SurfaceFlinger定义的一个结构,它有一个成员变量叫

layersSortedByZ,其实就是一个排序数组。下面这个add函数将把这个新的layer按照

它在Z轴的位置加入到排序数组中。mCurrentState保存了所有的显示层。

*/

    ssize_t i = mCurrentState.layersSortedByZ.add(layer,&LayerBase::compareCurrentStateZ);

sp<LayerBaseClient> lbc =

LayerBase::dynamicCast< LayerBaseClient*>(layer.get());

    if(lbc != 0) {

       mLayerMap.add(lbc->serverIndex(), lbc);

    }

    return NO_ERROR;

}

对Layer的三个关键函数都已分析过了,下面正式介绍Layer家族。

(4)Layer家族的介绍

前面的内容确让人头晕眼花,现在应该帮大家恢复清晰的头脑。先来“一剂猛药”,见图8-16:


图8-16  Layer家族

通过上图可知:

·  LayerBaseClient从LayerBase类派生。

·  LayerBaseClient还有四个派生类,分别是Layer、LayerBuffer、LayerDim和LayerBlur。

·  LayerBaseClient定义了一个内部类Surface,这个Surface从ISurface类派生,它支持Binder通信。

·  针对不同的类型,Layer和LayerBuffer分别有一个内部类SurfaceLayer和SurfaceLayerBuffer,它们继承了LayerBaseClient的Surface类。所以对于Normal类型的显示层来说,getSurface返回的ISurface对象的真正类型是SurfaceLayer。

·  LayerDim和LayerBlur类没有定义自己的内部类,所以对于这两种类型的显示层来说,它们直接使用了LayerBaseClient的Surface。

·  ISurface接口提供了非常简单的函数,如requestBuffer、postBuffer等。

这里大量使用了内部类。我们知道,内部类最终都会把请求派发给外部类对象来处理,既然如此,在以后分析中,如果没有特殊情况,就会直接跳到外部类的处理函数中。

强烈建议Google把Surface相关代码好好整理一下,至少让类型名取得更直观些,现在这样确实有点让人头晕。好,来小小娱乐一下。看之前介绍的和“Surface”有关的名字:

Native层有Surface、ISurface、SurfaceControl、SurfaceComposerClient。

Java层有Surface、SurfaceSession。

在介绍完Layer家族后,与它相关的名字又多了几个,它们是

LayerBaseClient::Surface、Layer::SurfaceLayer、LayerBuffer::SurfaceLayerBuffer。

3. SurfaceControl总结

SurfaceControl创建后得到了什么呢?可用图8-17来表示:


图8-17  SurfaceControl创建后的结果图

通过上图可以知道:

·  mClient成员变量指向SurfaceComposerClient。

·  mSurface的Binder通信响应端为SurfaceLayer。

·  SurfaceLayer有一个变量mOwner指向它的外部类Layer,而Layer有一个成员变量mSurface指向SurfaceLayer。这个SurfaceLayer对象由getSurface函数返回。

注意,mOwner变量由SurfaceLayer的基类Surface(LayBaseClient的内部类)定义。

接下来就是writeToParcel分析和Native Surface对象的创建了。注意,这个Native的Surface可不是LayBaseClient的内部类Surface。

 

8.4.4  writeToParcel和Surface对象的创建

1. writeToParcel分析

writeToParcel比较简单,就是把一些信息写到Parcel中去。代码如下所示:

[-->SurfaceControl.cpp]

status_t SurfaceControl::writeSurfaceToParcel(const sp<SurfaceControl>& control, Parcel* parcel)

{

//SurfaceComposerClient的信息需要传递到Activity端,这样客户端那边会构造一个

//SurfaceComposerClient对象

parcel->writeStrongBinder(client!=0  ? client->connection() : NULL);

 

//把ISurface对象信息也写到Parcel中,这样Activity端那边也会构造一个ISurface对象

    parcel->writeStrongBinder(sur!=0?sur->asBinder(): NULL);

    return NO_ERROR;

}

Parce包发到Activity端后,readFromParcel将根据这个Parcel包构造一个Native的Surface对象,一起来看相关代码。

2. 分析Native的Surface创建过程

[-->android_view_Surface.cpp]

static void Surface_readFromParcel(

       JNIEnv* env, jobject clazz, jobject argParcel)

{

   Parcel* parcel = (Parcel*)env->GetIntField( argParcel, no.native_parcel);

const sp<Surface>& control(getSurface(env,clazz));

//根据服务端的parcel信息来构造客户端的Surface

   sp<Surface> rhs = new Surface(*parcel);

    if(!Surface::isSameSurface(control, rhs)) {

         setSurface(env, clazz, rhs);

    }

}

在Surface创建完后,得到什么了呢?看图8-18就可知道:


图8-18  Native Surface的示意图

上图很清晰地说明:

·  ShardBuffer家族依托共享内存结构SharedClient与它共同组成了Surface系统生产/消费协调的中枢控制机构,它在SF端的代表是SharedBufferServer,在Activity端的代表是SharedBufferClient(消费,显示数据)。

·  Native的Surface将和SF中的SurfaceLayer建立Binder联系。

另外,图中还特意画出了承载数据的GraphicBuffer数组,在代码的注释中也针对GraphicBuffer提出了一个问题:Surface中有两个GraphicBuffer,Layer也有两个,一共就有四个GraphicBuffer了,可是为什么这里只画出两个呢?

答案是,咱们不是有共享内存吗?这四个GraphicBuffer其实操纵的是同一段共享内存,所以为了简单,就只画了两个GraphicBuffer。在8.4.7节再介绍GraphicBuffer的故事。

下面,来看中枢控制机构的SharedBuffer家族。

3. SharedBuffer家族介绍

(1)SharedBuffer家族成员

SharedBuffer是一个家族名称,它包括多个成员,如图8-19所示:


图8-19  SharedBuffer家族介绍

从上图可以知道:

·  XXXCondition、XXXUpdate等都是内部类,它们主要是用来更新读写位置的。

(2)SharedBuffer家族和SharedClient的关系

前面介绍过,SharedBufferServer和SharedBufferClient控制的其实只是SharedBufferStack数组中的一个,下面通过SharedBufferBase的构造函数,来看是否如此。

[-->SharedBufferStack.cpp]

SharedBufferBase::SharedBufferBase(SharedClient*sharedClient,

       int surface, int num, int32_t identity)

: mSharedClient(sharedClient),

  mSharedStack(sharedClient->surfaces+ surface),

 mNumBuffers(num), //根据前面PageFlipping的知识可知,num值为2

mIdentity(identity)

{

 /*

上面的赋值语句中最重要的是第二句:

   mSharedStack(sharedClient->surfaces +surface)

   这条语句使得这个SharedBufferXXX对象,和SharedClient中SharedBufferStack数组

的第surface个元素建立了关系

*/

}

4. Native Surface总结

至此,Activity端Java的Surface对象,终于和一个Native Surface对象挂上了钩,并且这个Native Surface还准备好了绘图所需的一切,其中包括:

·  两个GraphicBuffer,这就是PageFlipping所需要的FrontBuffer和BackBuffer。

·  SharedBufferServer和SharedBufferClient结构,这两个结构将用于生产/消费的过程控制。

·  一个ISurface对象,这个对象连接着SF中的一个SurfaceLayer对象。

·  一个SurfaceComposerClient对象,这个对象连接着SF中的一个BClient对象。

资源都已经准备好了,可以开始绘制UI了。下面,分析两个关键的函数lockCanvas和unlockCanvasAndPost。

8.4.5  lockCanvas和unlockCanvasAndPost的分析

这一节,分析精简流程中的最后两个函数lockCanvas和unlockCanvasAndPost。

1. lockCanvas分析

据前文分析可知,UI在绘制前都需要通过lockCanvas得到一块存储空间,也就是所说的BackBuffer。这个过程中最终会调用Surface的lock函数。其代码如下所示:

[-->Surface.cpp]

status_t Surface::lock(SurfaceInfo* other,Region* dirtyIn, bool blocking)

{

    //传入的参数中,other用来接收一些返回信息,dirtyIn表示需要重绘的区域  

......

if (mApiLock.tryLock() != NO_ERROR) {//多线程的情况下要锁住

     ......

     return WOULD_BLOCK;

}

    //设置usage标志,这个标志在GraphicBuffer分配缓冲时有指导作用

   setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);

   

    //定义一个GraphicBuffer,名字就叫backBuffer。

    sp<GraphicBuffer>backBuffer;

   //①还记得我们说的2个元素的缓冲队列吗?下面的dequeueBuffer将取出一个空闲缓冲

    status_terr = dequeueBuffer(&backBuffer);

   if (err== NO_ERROR) {

        //② 锁住这块buffer

       err = lockBuffer(backBuffer.get());

        if(err == NO_ERROR) {

           const Rect bounds(backBuffer->width, backBuffer->height);

           Region scratch(bounds);

           Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch);

 

          ......

         //mPostedBuffer是上一次绘画时使用的Buffer,也就是现在的frontBuffer

           const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);

           if (frontBuffer !=0 &&

               backBuffer->width  ==frontBuffer->width &&

               backBuffer->height == frontBuffer->height &&

               !(mFlags & ISurfaceComposer::eDestroyBackbuffer))

           {

               const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));

               if (!copyback.isEmpty() && frontBuffer!=0) {

                    //③把frontBuffer中的数据拷贝到BackBuffer中

                    copyBlt(backBuffer,frontBuffer, copyback);

               }

           }

    }

   mApiLock.unlock();

    returnerr;

}

(1)dequeueBuffer的分析

dequeueBuffer的目的很简单,就是选取一个空闲的GraphicBuffer,其代码如下所示:

[-->Surface.cpp]

intSurface::dequeueBuffer(android_native_buffer_t** buffer)

{

sp<SurfaceComposerClient> client(getClient());

//①调用SharedBufferClient的dequeue函数,它返回当前空闲的缓冲号

  ssize_t bufIdx = mSharedBufferClient->dequeue();


   //调用getBufferLocked,需要进去看看。

       err = getBufferLocked(bufIdx, usage);

        if(err == NO_ERROR) {

           mWidth  =uint32_t(backBuffer->width);

           mHeight = uint32_t(backBuffer->height);

        }

}

[-->Surface.cpp]

tatus_t Surface::getBufferLocked(int index, intusage)

{

   sp<ISurface> s(mSurface);

//终于用上了ISurface对象,调用它的requestBuffer得到指定索引index的Buffer

    sp<GraphicBuffer> buffer =s->requestBuffer(index, usage);

        return err;

}

至此,getBufferLocked的目的,已比较清晰了:

·  调用ISurface的requestBuffer得到一个GraphicBuffer对象,这个GraphicBuffer对象被设置到本地的mBuffers数组中。看来Surface定义的这两个GraphicBuffer和Layer定义的两个GraphicBuffer是有联系的,所以图8-18中只画了两个GraphicBuffer。

我们已经知道,ISurface的Bn端实际上是定义在Layer.类中的SurfaceLayer,下面来看它实现的requestBuffer。由于SurfaceLayer是Layer的内部类,它的工作最终都会交给Layer的requestBuffer函数

[-->Layer.cpp]

sp<GraphicBuffer> Layer::requestBuffer(intindex, int usage)

{

   if(buffer!=0 && buffer->getStrongCount() == 1) {

        //①分配物理存储,后面会分析这个。

       err = buffer->reallocate(w, h, mFormat, effectiveUsage);

    } else{

       buffer.clear();

       //使用GraphicBuffer的有参构造,这也使得物理存储被分配

       buffer = new GraphicBuffer(w, h, mFormat, effectiveUsage);

       err = buffer->initCheck();

    }

    return buffer;//返回

}

(2)lockBuffer的分析

lockBuffer的代码如下所示:

[-->Surface.cpp]

int Surface::lockBuffer(android_native_buffer_t*buffer)

{

    err =mSharedBufferClient->lock(bufIdx); //调用SharedBufferClient的lock

    return err;

}

来看这个lock函数:

[-->SharedBufferStack.cpp]

status_t SharedBufferClient::lock(int buf)

{

   LockCondition condition(this, buf);//这个buf是BackBuffer的索引号

   status_t err = waitForCondition(condition);

    returnerr;

}

waitForCondition函数比较简单,就是等待一个条件为真,这个条件是否满足由condition()这条语句来判断。

(3)拷贝旧数据

OK,lockCanvas返回后,应用层将在这块画布上尽情作画。假设现在已经在BackBuffer上绘制好了图像,下面就要通过unlockCanvasAndPost进行后续工作了

2. unlockCanvasAndPost的分析

进入精简流程的最后一步,就是unlockCanvasAndPost函数,它的代码如下所示:

[-->Surface.cpp]

status_t Surface::unlockAndPost()

{

    //调用GraphicBuffer的unlock函数

status_t err = mLockedBuffer->unlock();

   //get返回这个GraphicBuffer的编号,queueBuffer将含有新数据的缓冲加入队中。

    err =queueBuffer(mLockedBuffer.get());

   mPostedBuffer = mLockedBuffer; //保存这个BackBuffer为mPostedBuffer

   mLockedBuffer = 0;

    returnerr;

}

来看queueBuffer调用,代码如下所示:

[-->Surface.cpp]

intSurface::queueBuffer(android_native_buffer_t* buffer)

{  

   sp<SurfaceComposerClient> client(getClient());

int32_t bufIdx =GraphicBuffer::getSelf(buffer)->getIndex();

//设置脏Region

mSharedBufferClient->setDirtyRegion(bufIdx,mDirtyRegion);

//更新写位置。

    err =mSharedBufferClient->queue(bufIdx);

     if (err== NO_ERROR) {

     //client是BpSurfaceFlinger,调用它的signalServer,这样SF就知道新数据准备好了

       client->signalServer();

    }

    returnerr;

}

3. lockCanvas和unlockCanvasAndPost的总结

总结一下lockCanvas和unlockCanvasAndPost这两个函数的工作流程,用图8-20表示:


图8-20  lockCanvas和unlockCanvasAndPost流程总结

 

8.4.6  GraphicBuffer的介绍

8.4.7  深入分析Surface总结

8.5  SurfaceFlinger的分析

这一节要对SurfaceFlinger进行分析。相比较而言,SurfaceFlinger不如AudioFlinger复杂。

8.5.1  SurfaceFlinger的诞生

SurfaceFlinger驻留于system_server进程。它创建的位置在SystemServer的init1函数中(第4章4.3.2节的第3点)。

[-->SurfaceFlinger.cpp]

void SurfaceFlinger::instantiate() {

   defaultServiceManager()->addService(String16("SurfaceFlinger"), new SurfaceFlinger());

}

前面在图8-14中指出了SF,同时从BnSurfaceComposer和Thread类中派生,相关代码如下所示:

class SurfaceFlinger : public BnSurfaceComposer,protected Thread

从Thread派生这件事给了我们一个很明确的提示:

·  SurfaceFlinger会单独启动一个工作线程

2. readyToRun的分析

SF的readyToRun函数将完成一些初始化工作,代码如下所示:

[-->SurfaceFlinger.cpp]

status_t SurfaceFlinger::readyToRun()

{

    intdpy = 0;

    {

        //①GraphicPlane

       GraphicPlane& plane(graphicPlane(dpy));

        //②为这个GraphicPlane设置一个HAL对象——DisplayHardware

       DisplayHardware* const hw = new DisplayHardware(this, dpy);

       plane.setDisplayHardware(hw);

    }

 

 //创建Surface系统中的“CB”对象,按照老规矩,应该先创建一块共享内存,然后使用placment new

   mServerHeap = new MemoryHeapBase(4096,

                            MemoryHeapBase::READ_ONLY,

                            "SurfaceFlingerread-only heap");

   //LayerDim是Dim类型的Layer

  LayerDim::initDimmer(this, w, h);

    //资源准备好后,init将启动bootanim程序,这样就见到开机动画了。

   property_set("ctl.start", "bootanim");

    return NO_ERROR;

}

在上面的代码中,列出了两个关键点,下面一一进行分析。

(1)GraphicPlane的介绍

GraphicPlane虽无什么特别之处,但它有一个重要的函数,叫setDisplayHardware,这个函数把代表显示设备的HAL对象和GraphicPlane关联起来。这也是下面要介绍的第二个关键点DisplayHardware。

(2)DisplayHardware的介绍

从代码上看,这个和显示相关的HAL对象是在工作线程中new出来的,先看它的构造函数,代码如下所示:

[-->DisplayHardware.cpp]

DisplayHardware::DisplayHardware(const sp<SurfaceFlinger>& flinger,uint32_t dpy):DisplayHardwareBase(flinger, dpy)

{

   init(dpy); //最重要的是这个init函数。

}

init函数非常重要,应进去看看。下面先思考一个问题。

前面在介绍FrameBuffer时说过,显示这一块需要使用FrameBuffer,FrameBuffer是在init函数创建

[-->DisplayHardware.cpp]

void DisplayHardware::init(uint32_t dpy)

{

//FrameBufferNativeWindow实现了对FrameBuffer的管理和操作

//该类中创建了两个FrameBuffer,分别起到FrontBuffer和BackBuffer的作用。

mNativeWindow = new FramebufferNativeWindow();


  //EGLDisplay在EGL中代表屏幕

   EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

    ......

   /*

    surface是EGLSurface类型,下面这个函数会将EGL和Android中的Display系统绑定起来,

    后续就可以利用OpenGL在这个Surface上绘画,然后通过eglSwappBuffers输出图像了。

    */

    surface= eglCreateWindowSurface(display, config,mNativeWindow.get(),NULL);

}

根据上面的代码,现在可以回答前面的问题了:

·  SF创建FrameBuffer,并将各个Surface传输的数据(通过GraphicBuffer)混合后,再由自己传输到FrameBuffer中进行显示。

本节的内容,实际上涉及另外一个比Surface更复杂的Display系统,出于篇幅和精力的原因,本书目前不打算讨论它。

8.5.2  SF工作线程的分析

SF中的工作线程就是来做图像混合

[-->SurfaceFlinger.cpp]

bool SurfaceFlinger::threadLoop()

{

   waitForEvent();//① 等待事件

    //②处理PageFlipping工作

   handlePageFlip();

 

    constDisplayHardware& hw(graphicPlane(0).displayHardware());

if (LIKELY(hw.canDraw() && !isFrozen())) {

        //③处理重绘

        handleRepaint();

        hw.compositionComplete();

        //④投递BackBuffer

       unlockClients();

        postFramebuffer();

    } else{

       unlockClients();

       usleep(16667);

    }

    return true;

}

ThreadLoop一共有四个关键点,这里,分析除Transaction外的三个关键点。

1. waitForEvent

SF收到重绘消息后,将退出等待。

2. 分析handlePageFlip

[-->SurfaceFlinger.cpp]

void SurfaceFlinger::handlePageFlip()

{

bool visibleRegions = mVisibleRegionsDirty;

/*

还记得前面所说的mCurrentState吗?它保存了所有显示层的信息,而绘制的时候使用的

mDrawingState则保存了当前需要显示的显示层信息。

*/

LayerVector& currentLayers =const_cast<LayerVector&>(mDrawingState.layersSortedByZ);

//①调用lockPageFlip

//将根据FrontBuffer的内容生成一张纹理

visibleRegions |= lockPageFlip(currentLayers);

const DisplayHardware& hw =graphicPlane(0).displayHardware();

//取得屏幕的区域

const Region screenRegion(hw.bounds());

//② 调用unlockPageFlip

 //调用每个显示层的unlockPageFlip,做一些区域的清理工作

unlockPageFlip(currentLayers);

mDirtyRegion.andSelf(screenRegion);

}

handlePageFlip的工作其实很简单,以Layer类型为例来总结一下:

各个Layer需要从FrontBuffer中取得新数据,并生成一张OpenGL中的纹理。纹理可以看做是一个图片,这个图片的内容就是FrontBuffer中的图像。

现在每一个Layer都准备好了新数据,下一步的工作当然就是绘制了。来看handleRepaint函数

3. 分析handleRepaint函数

handleRepaint函数的代码如下所示:

[-->SurfaceFlinger.cpp]

void SurfaceFlinger::handleRepaint()

{

    // 在脏区域上进行绘制

   composeSurfaces(mDirtyRegion);

}

其中,composeSurfaces将不同的显示层内容进行混合,其实就是按Z轴的顺序由里到外依次绘制。当然,最后绘制的数据有可能遮盖前面绘制的数据,代码如下所示:

[-->SurfaceFlinger.cpp]

void SurfaceFlinger::composeSurfaces(constRegion& dirty)

{

    for(size_t i=0 ; i<count ; ++i) {

        if(!visibleRegion.isEmpty())  {

           const Region clip(dirty.intersect(visibleRegion));

           if (!clip.isEmpty()) {

               layer->draw(clip); //调用各个显示层的layer函数

            }

        }

    }

}

draw函数在LayerBase类中实现,代码如下所示:

[-->LayerBase.cpp]

void LayerBase::draw(const Region& inClip)const

    ......

    glEnable(GL_SCISSOR_TEST);

   onDraw(clip);//调用子类的onDraw函数

}

至于Layer是怎么实现这个onDraw函数的,代码如下所示:

[-->Layer.cpp]

void Layer::onDraw(const Region& clip) const

{

 drawWithOpenGL(clip,mTextures[index]);//将纹理画上去,里面有很多和OpenGL相关内容

}

drawWithOpenGL函数由LayerBase实现,看它是不是使用了这张纹理,代码如下所示:

[-->LayerBase.cpp]

void LayerBase::drawWithOpenGL(const Region&clip, const Texture& texture) const

{

    //下面就是OpenGL操作函数了

   glEnable(GL_TEXTURE_2D);

   glMatrixMode(GL_TEXTURE);

   glLoadIdentity();

 

    //坐标旋转

    switch(texture.transform) {

       case HAL_TRANSFORM_ROT_90:

           glTranslatef(0, 1, 0);

           glRotatef(-90, 0, 0, 1);

           break;

       case HAL_TRANSFORM_ROT_180:

           glTranslatef(1, 1, 0);

           glRotatef(-180, 0, 0, 1);

           break;

       case HAL_TRANSFORM_ROT_270:

           glTranslatef(1, 0, 0);

           glRotatef(-270, 0, 0, 1);

           break;

    }

 

if (texture.NPOTAdjust) {

        //缩放处理

       glScalef(texture.wScale, texture.hScale, 1.0f);

    }

   //使能纹理坐标

glEnableClientState(GL_TEXTURE_COORD_ARRAY);

//设置顶点坐标

glVertexPointer(2, GL_FIXED, 0, mVertices);

//设置纹理坐标

   glTexCoordPointer(2, GL_FIXED, 0, texCoords);

 

    while(it != end) {

       const Rect& r = *it++;

       const GLint sy = fbHeight - (r.top + r.height());

        //裁剪

       glScissor(r.left, sy, r.width(), r.height());

        //画矩形

       glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

}

//禁止纹理坐标

   glDisableClientState(GL_TEXTURE_COORD_ARRAY);

}

4. unlockClients和postFrameBuffer的分析

在绘制完图后,还有两项工作需要做,一个涉及unlockClients函数,另外一个涉及postFrameBuffer函数

[-->SurfaceFlinger.cpp]

void SurfaceFlinger::unlockClients()

{

    constLayerVector& drawingLayers(mDrawingState.layersSortedByZ);

    constsize_t count = drawingLayers.size();

   sp<LayerBase> const* const layers = drawingLayers.array();

    for (size_t i=0 ; i<count ; ++i) {

       const sp<LayerBase>& layer = layers[i];

 //释放FrontBufferIndex

       layer->finishPageFlip();

    }

}

原来,unlockClients会释放之前占着的FrontBuffer的索引号。下面看最后一个函数postFrameBuffer,代码如下所示:

[-->SurfaceFlinger.cpp]

void SurfaceFlinger::postFramebuffer()

{

    if(!mInvalidRegion.isEmpty()) {

// 调用这个函数后,混合后的图像就会传递到屏幕中显示了

// 内部调用eglSwapBuffers(dpy, surface);//PageFlipping,此后图像终于显示在屏幕上了!

       hw.flip(mInvalidRegion);

    }

}

8.5.3  Transaction的分析

Transaction是“事务”的意思。

SurfaceFlinger为什么需要事务呢?从对数据库事务的描述来看,是不是意味着一次执行多个请求呢?从一个例子入手吧。

8.5.4  SurfaceFlinger的总结

通过前面的分析,使我们感受了SurfaceFlinger的风采。从整体上看,SurfaceFlinger不如AudioFlinger复杂,它的工作集中在工作线程中,下面用图8-23来总线一下SF工作线程:


图8-23  SF工作线程的流程总结

 

8.6  拓展思考


猜你喜欢

转载自blog.csdn.net/qq_24451593/article/details/80397051
今日推荐