`
jandroid
  • 浏览: 1933736 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Android深入浅出之Surface

阅读更多

目的

本节的目的就是为了讲清楚 Android 中的 Surface 系统,大家耳熟能详的 SurfaceFlinger 到底是个什么东西,它的工作流程又是怎样的。当然,鉴于 SurfaceFlinger 的复杂性,我们依然将采用情景分析的办法,找到合适的切入点。

一个 Activity 是怎么在屏幕上显示出来的呢?我将首先把这个说清楚。

接着我们把其中的关键调用抽象在 Native 层,以这些函数调用为切入点来研究 SurfaceFlinger 。好了,开始我们的征途吧。

Activity 是如何显示的

最初的想法就是, Activity 获得一块显存,然后在上面绘图,最后交给设备去显示。这个道理是没错,但是 Android SurfaceFlinger 是在 System Server 进程中创建的, Activity 一般另有线程,这之间是如何 ... 如何挂上关系的呢?我可以先提前告诉大家,这个过程还比较复杂。呵呵。

好吧,我们从 Activity 最初的启动开始。代码在

framework/base/core/java/android/app/ActivityThread.java 中,这里有个函数叫 handleLaunchActivity

[---->ActivityThread:: handleLaunchActivity()]

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

      Activity a = performLaunchActivity(r, customIntent);

 

        if (a != null) {

            r.createdConfig = new Configuration(mConfiguration);

            Bundle oldState = r.state;

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

----> 调用handleResumeActivity

}

handleLaunchActivity 中会调用 handleResumeActivity

[--->ActivityThread:: handleResumeActivity]

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 decor = r.window.getDecorView();

                decor.setVisibility(View.INVISIBLE);

                ViewManager wm = a.getWindowManager();

                WindowManager.LayoutParams l = r.window.getAttributes();

                a.mDecor = decor;

                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;

                if (a.mVisibleFromClient) {

                     a.mWindowAdded = true;

                    wm.addView(decor, l); // 这个很关键。

                }

上面 addView 那几行非常关键,它关系到咱们在 Activity setContentView 后,整个 Window 到底都包含了些什么。我先告诉大家。所有你创建的 View 之上,还有一个 DecorView ,这是一个 FrameLayout ,另外还有一个 PhoneWindow 。上面这些东西的代码在

framework/Policies/Base/Phone/com/android/Internal/policy/impl 。这些隐藏的 View 的创建都是由你在 Acitivty onCreate 中调用 setContentView 导致的。

[---->PhoneWindow:: addContentView]

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

        if (mContentParent == null) {  // 刚创建的时候mContentParent 为空

            installDecor();

        }

        mContentParent.addView(view, params);

        final Callback cb = getCallback();

        if (cb != null) {

            cb.onContentChanged();

        }

}

installDecor 将创建mDecormContentParentmDecorDecorView 类型,

mContentParentViewGroup 类型

private void installDecor() {

        if (mDecor == null) {

            mDecor = generateDecor();

            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);

            mDecor.setIsRootNamespace(true);

        }

        if (mContentParent == null) {

            mContentParent = generateLayout(mDecor);

那么, ViewManager wm = a.getWindowManager() 又返回什么呢?

PhoneWindow Window 中派生, Acitivity 创建的时候会调用它的 setWindowManager 。而这个函数由 Window 类实现。

代码在 framework/base/core/java/android/view/Window.java

public void setWindowManager(WindowManager wm,IBinder appToken, String appName) {

        mAppToken = appToken;

        mAppName = appName;

        if (wm == null) {

            wm = WindowManagerImpl.getDefault();

        }

        mWindowManager = new LocalWindowManager(wm);

    }

你看见没,分析 JAVA 代码这个东西真的很复杂。 mWindowManager 的实现是 LocalWindowManager ,但由通过 Bridge 模式把功能交给 WindowManagerImpl 去实现了。

真的很复杂!

好了,罗里罗嗦的,我们回到 wm.addView(decor, l) 。最终会由 WindowManagerImpl 来完成

addView 操作,我们直接看它的实现好了。

代码在 framework/base/core/java/android/view/WindowManagerImpl.java

[---->addView]

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

    {

          ViewRoot root; //ViewRoot ,我们的主人公终于登场!

         synchronized (this) {

          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;

            mParams[index] = wparams;

        }

        root.setView(view, wparams, panelParentView);

}

ViewRoot 是整个显示系统中最为关键的东西,看起来这个东西好像和 View 有那么点关系,其实它根本和 View UI 关系不大,它不过是一个 Handler 罢了,唯一有关系的就是它其中有一个变量为 Surface 类型。我们看看它的定义。 ViewRoot 代码在

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

public final class ViewRoot extends Handler implements ViewParent,

        View.AttachInfo.Callbacks

{

private final Surface mSurface = new Surface();

}

它竟然从handler 派生,而ViewParent 不过定义了一些接口函数罢了。

看到 Surface 直觉上感到它和 SurfaceFlinger 有点关系。要不先去看看?

Surface 代码在 framework/base/core/java/android/view/Surface.java 中,我们调用的是无参构造函数。

public Surface() {

       mCanvas = new CompatibleCanvas(); // 就是创建一个Canvas

}

如果你有兴趣的话,看看 Surface 其他构造函数,最终都会调用 native 的实现,而这些 native 的实现将和 SurfaceFlinger 建立关系,但我们这里 ViewRoot 中的 mSurface 显然还没有到这一步。那它到底是怎么和 SurfaceFlinger 搞上的呢?这一切待会就会水落石出的。

另外,为什么 ViewRoot 是主人公呢?因为 ViewRoot 建立了客户端和 SystemServer 的关系。我们看看它的构造函数。

public ViewRoot(Context context) {

        super();

       ....

       getWindowSession(context.getMainLooper());

}

getWindowsession 将建立和WindowManagerService 的关系。

ublic static IWindowSession getWindowSession(Looper mainLooper) {

        synchronized (mStaticInit) {

            if (!mInitialized) {

                try {

                //sWindowSession 是通过Binder 机制创建的。终于让我们看到点希望了

                    InputMethodManager imm = InputMethodManager.getInstance(mainLooper);

                    sWindowSession = IWindowManager.Stub.asInterface(

                            ServiceManager.getService("window"))

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

                     mInitialized = true;

                } catch (RemoteException e) {

                }

            }

            return sWindowSession;

        }

    }

上面跨 Binder 的进程调用另一端是 WindowManagerService ,代码在

framework/base/services/java/com/android/server/WindowManagerService.java 中。我们先不说这个。

回过头来看看 ViewRoot 接下来的调用。

[-->ViewRoot::setView()] ,这个函数很复杂,我们看其中关键几句。

public void setView(View view, WindowManager.LayoutParams attrs,

            View panelParentView) {

        synchronized (this) {

            requestLayout();

                try {

                    res = sWindowSession.add(mWindow, mWindowAttributes,

                            getHostVisibility(), mAttachInfo.mContentInsets);

                }

}

requestLayout 实现很简单,就是往 handler 中发送了一个消息。

public void requestLayout() {

        checkThread();

        mLayoutRequested = true;

        scheduleTraversals(); // 发送DO_TRAVERSAL 消息

}

public void scheduleTraversals() {

        if (!mTraversalScheduled) {

             mTraversalScheduled = true;

            sendEmptyMessage(DO_TRAVERSAL);

        }

}

我们看看跨进程的那个调用。 sWindowSession.add 。它的最终实现在 WindowManagerService 中。

[--->WindowSession::add()]

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

                 int viewVisibility, Rect outContentInsets) {

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

        }

WindowSession 是个内部类,会调用外部类的 addWindow

这个函数巨复杂无比,但是我们的核心目标是找到创建显示相关的部分。所以,最后精简的话就简单了。

[--->WindowManagerService:: addWindow]

public int addWindow(Session session, IWindow client,

            WindowManager.LayoutParams attrs, int viewVisibility,

            Rect outContentInsets) {

        // 创建一个WindowState ,这个又是什么玩意儿呢?

              win = new WindowState(session, client, token,

                    attachedWindow, attrs, viewVisibility);

           win.attach();

           return res;

}

WindowState 类中有一个和 Surface 相关的成员变量,叫 SurfaceSession 。它会在

attach 函数中被创建。 SurfaceSession 嘛,就和 SurfaceFlinger 有关系了。我们待会看。

好,我们知道 ViewRoot 创建及调用 add 后,我们客户端的 View 系统就和 WindowManagerService 建立了牢不可破的关系。

另外,我们知道 ViewRoot 是一个 handler ,而且刚才我们调用了 requestLayout ,所以接下来消息循环下一个将调用的就是 ViewRoot handleMessage

public void handleMessage(Message msg) {

        switch (msg.what) {

       case DO_TRAVERSAL:

            performTraversals();

performTraversals 更加复杂无比,经过我仔细挑选,目标锁定为下面几个函数。当然,后面我们还会回到 performTraversals ,不过我们现在更感兴趣的是 Surface 是如何创建的。

private void performTraversals() {

        // cache mView since it is used so much below...

        final View host = mView;

 

          boolean initialized = false;

            boolean contentInsetsChanged = false;

            boolean visibleInsetsChanged;

            try {

//ViewRoot 也有一个Surface 成员变量,叫mSurface ,这个就是代表SurfaceFlinger 的客户端

//ViewRoot 在这个Surface 上作画,最后将由SurfaceFlinger 来合成显示。刚才说了mSurface 还没有什么内容。

           relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);

[---->ViewRoot:: relayoutWindow()]

private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,

            boolean insetsPending) throws RemoteException {

       

//relayOut 是跨进程调用,mSurface 做为参数传进去了,看来离真相越来越近了呀!

        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 做为参数传进去了。

       }

我们赶紧转到 WindowManagerService 去看看吧。、

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, Surface outSurface){

               .....

          try {

           // 看到这里,我内心一阵狂喜,有戏,太有戏了!

         // 其中win 是我们最初创建的WindowState

                    Surface surface = win.createSurfaceLocked();

                    if (surface != null) {

                  // 先创建一个本地surface ,然后把传入的参数outSurface copyFrom 一下

                         outSurface.copyFrom(surface);

                        win.mReportDestroySurface = false;

                        win.mSurfacePendingDestroy = false;

                       } else {

                       outSurface.release();

                     }

                }

}

[--->WindowState::createSurfaceLocked]

Surface createSurfaceLocked() {

         

                try {

                    mSurface = new Surface(

                            mSession.mSurfaceSession, mSession.mPid,

                             mAttrs.getTitle().toString(),

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

                  }

                Surface.openTransaction();

这里使用了 Surface 的另外一个构造函数。

    public Surface(SurfaceSession s,

            int pid, String name, int display, int w, int h, int format, int flags)

        throws OutOfResourcesException {

        mCanvas = new CompatibleCanvas();

        init(s,pid,name,display,w,h,format,flags); ----> 调用了nativeinit 函数。

        mName = name;

}

到这里,不进入 JNI 是不可能说清楚了。不过我们要先回顾下之前的关键步骤。

l          add 中, new 了一个 SurfaceSession

l          创建 new 了一个 Surface

l          调用 copyFrom ,把本地 Surface 信息传到 outSurface

JNI

上面两个类的 JNI 实现都在 framework/base/core/jni/android_view_Surface.cpp 中。

  [---->SurfaceSession:: SurfaceSession()]

public class SurfaceSession {

    /** Create a new connection with the surface flinger. */

    public SurfaceSession() {

        init();

}

它的 init 函数对应为:

[--->SurfaceSession_init]

static void SurfaceSession_init(JNIEnv* env, jobject clazz)

{

   //SurfaceSession 对应为SurfaceComposerClient

    sp<SurfaceComposerClient> client = new SurfaceComposerClient;

client->incStrong(clazz);

//Google 常用做法,在JAVA 对象中保存C++ 对象的指针。

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

}

Surface init 对应为:

[--->Surface_init]

static void Surface_init(

        JNIEnv* env, jobject clazz,

        jobject session,

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

{

   SurfaceComposerClient* client =

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

 

    sp<SurfaceControl> surface;

if (jname == NULL) { </

3
3
分享到:
评论

相关推荐

    Android深入浅出之Surface.pdf

    ### Android深入浅出之Surface详解 #### 一、引言 在深入了解Android系统中的Surface机制之前,我们需要明确几个核心概念。在Android系统中,Surface是一个关键的概念,它主要用于描述一个可以绘制图像的区域,...

    详解AndroidSurface

    在深入学习Surface时,可以参考提供的资源,如《详解Android Surface系统 - OPhoneAndroid技术讨论区 - 中国移动MM论坛.html》和《Android深入浅出之Surface.pdf》,这些资料将详细介绍Surface的原理、最佳实践以及...

    surfaceflinger 大杂烩

    包括《Android_图形系统分析-surfaceFlinger流程.doc》、《Android_Surfaceflinger研究-显示系统.pdf》、《Surfaceflinger详解.pdf》、《Android核心分析.pdf》和《Android深入浅出之Surface.pdf》,它们涵盖了从...

    android JNI video工程(surface显示输出)

    接着,使用FFmpeg解码出的YUV或者其他格式的像素数据,通过ANativeWindow_Buffer结构体更新到Surface上,实现视频的显示。 6. **视频帧的处理**:从FFmpeg解码出来的原始视频帧通常是YUV格式,需要进行色彩空间转换...

    Android中使用SurfaceTexture自定义相机

    本教程将深入探讨如何使用SurfaceTexture来实现自定义相机预览,并在PictureCallback回调中保存图片。 首先,了解SurfaceTexture的基本概念。SurfaceTexture是一个抽象接口,它与OpenGL ES纹理绑定,允许将硬件图形...

    android 通过surfacetexture绘制Bitmap

    android 通过surfacetexture绘制Bitmap,使用ISurfaceComposerClient创建新图层

    Android-Surface-.rar_android surface_surface

    这个压缩包“Android-Surface-.rar”包含了对Android Surface的深入学习资料,非常适合开发者进行参考学习。让我们一起深入了解Surface及其在Android开发中的作用。 首先,Surface是Android系统中的一个抽象接口,...

    android C使用surface实现画图功能

    在Android系统中,Surface是用来处理图形绘制的核心组件,它提供了硬件加速的图形渲染接口,使得开发者可以在不阻塞用户界面的情况下进行高效的图像处理。在这个项目中,我们将关注如何使用C语言来调用Surface来实现...

    android glsurface example

    "android glsurface example"就是关于如何在Android应用中使用GLSurfaceView和OpenGL ES进行图形渲染的一个示例项目。 GLSurfaceView类为开发者提供了一个框架,它处理了大部分与创建和管理OpenGL渲染线程、同步与...

    Android平台OpenGLES3将GL-TEXTURE-2D纹理id渲染到ImageReader提供的Surface上

    Android平台 将 GL_TEXTURE_2D纹理 渲染到 Surface 上 案例实现文章介绍: https://xiaxl.blog.csdn.net/article/details/131682521 技术实现流程大致如下: 1、OpenGLES3中加载GL_TEXTURE_2D纹理,生成纹理ID; 2...

    android surface 背景透明,图片拖拉

    在Android开发中,实现"android surface 背景透明,图片拖拉"的功能涉及到多个关键知识点,这将为用户提供一种交互式的地图编辑体验。以下是对这些技术要点的详细解释: 1. **SurfaceView**: SurfaceView是Android...

    Android Surface

    Android Surface Android Surface 是 Android 操作系统中的图形系统组件,负责提供图形绘制和显示功能。在 Android 中,Surface 是一个可供图形系统绘制的 surface,能够支持 2D 和 3D 图形绘制。下面将对 Android ...

    Android_Surface系统的实现

    通过深入研究这一过程,可以更好地理解Surface架构的工作原理。 #### WindowManagerService (WMS) WMS是在System_Server进程中启动的一项核心服务,它负责管理应用程序窗口的创建、控制以及消息的收集与分发。当...

    Android Surface画图游戏 示例代码

    "Android Surface画图游戏 示例代码"提供了一个完整的工程实例,可以帮助开发者深入理解如何利用SurfaceView及其相关组件来实现游戏的图形渲染。下面我们将详细探讨这个示例项目中的关键知识点。 1. **Android ...

    android mediacodec surface sample

    本示例“android mediacodec surface sample”主要关注如何使用MediaCodec API来解码H264编码的MP4视频,并将解码后的视频帧渲染到Surface上。以下是对这个示例涉及的知识点的详细解释: 1. **MediaCodec**:...

    android socket surface视频流播放器

    本文将详细解析"android socket surface mediacodec h264"这个主题,涵盖如何通过Socket接收视频流数据,并利用Surface和MediaCodec进行解码与播放。 首先,Socket是网络通信的基础,它提供了进程间的数据传输通道...

    深入理解Android 卷1.pdf

    第8章深入讲解了Surface系统的实现原理,分析了Surface与Activity之间以及Surface与SurfaceFlinger之间的关系、SurfaceFlinger的工作原理、Surface系统中的帧数据传输以及LayerBuffer的工作流程。第9章对Vold和Rild...

    android Surface详解

    本文档旨在为那些已经具备一定Android基础知识的学习者提供深入理解`Surface`及其相关组件的工作原理。 #### 二、Surface 的概念 `Surface` 可以简单地理解为一个可被多个线程安全访问的图形缓冲区。它是Android...

    深入理解Android卷1全

    深入理解Android 卷1 不是扫描版的,是全版电子书的,非PDF,可编辑,各种阅览器以打开!包括书签和同步目录! 第1章 阅读前的准备工作 / 1 1.1 系统架构 / 2 1.1.1 Android系统架构 / 2 1.1.2 本书的架构 / 3 1.2 ...

    android MediaPlayer+SurfaceView实现播放

    在Android开发中,多媒体播放是常见的功能之一,`MediaPlayer` 和 `SurfaceView` 的结合使用是实现视频播放的标准方式。本篇文章将详细讲解如何利用这两个组件来构建一个视频播放器。 首先,`MediaPlayer` 是...

Global site tag (gtag.js) - Google Analytics