Android Surface解析

2023-11-05

(源码截图是Android 5.1.1_r6)

 

 

一 App和Surface的关系是怎样的

不论是用Skia绘制二维图像,还是用OpenGL绘制三维图像,最终Application都要和Surface交互。Surface 是什么:

Handle onto a raw buffer that is being managed by the screen compositor.

由屏幕显示内容合成器(screen compositor)所管理的原始缓冲区的句柄,就像在C++语言中,可以通过一个文件的句柄,就可以获得文件的内容一样,通过Surface就可以获得原生缓冲器以及其中的内容,那App是怎么通过Surface获取的缓冲区去绘图的呢?

应用程序的外表是通过Activity显示的,首先我们来看一下Activity是怎么完成界面绘制工作的。从Activity启动开始跟。

Zygote在收到启动请求的时候,会fork一个子进程,这个子进程就是app的对应的进程,它的入口函数就是ActivityThread类的main函数,这个类里面有一个handleLaunchActivity函数,它就是创建Activity的地方。

然后接着看Activity创建的代码performLaunchActivity

Instrumentation.java

跳转到Activity attach中

Window是个抽象类,那当前Activity中的这个mWindow的具体实现类是哪个?

继续跟这个PolicyManager

这里获取了return 了 com.android.internal.policy.impl.Policy 的这个类 makeNewWindow(context)方法,继续跟Policy这个类

这里发现了,Activity中存在的Window是PhoneWindow。

然后继续Activity创建好后的方法handleResumeActivity();

这里三个方法都要跟,先看第一个r.getWindow.getDecorView();

r是ActivityClinetRecord 是Activity描述的类,对Activity进行了高度抽象,记录了Activity的各种信息,大家应该都清楚,这里就不再赘述了。

1.window.getDecorView。

ActivityClinetRecord记录着是是Activity的信息,所以这个window就是刚刚说的Activity里面的PhoneWindow,我们跟一下PhoneWindow这个方法

再看一下installDecor()方法,这个方法是不是有点眼熟,setContentView就是调的这个,我们看一下SetContentView

再跟一下这个installDecor

如果用户没有传这个layout,mContentParent就是decorView的子布局

再看一下generateLayout(mDecor)这个方法,方法太多截取了一下

再看一下这个findViewById

通过这个其实就能看出,Activity的onCreate函数中,通过setContentView设置的View其实只是DecorView的子View,DecorView还处理了标题栏显示等一系列的工作

2. 第二个方法 :ViewManager wm =a.getWindowManager()

这个WM的具体实现类是什么?

a是Activity,Activity的getWindowManager方法看一下

这个mWindowManager上面跟过了,是从mWindow里面拿出来的,mWindow的类型是PhoneWindow之前也跟过了,想要知道这个wm是什么类型的,继续跟PhoneWindow的setWindowManager方法

发现里面没有这个方法,PhoneWindow继承Window看看父类

这里有个小细节,4.2以下和4.2及以上的实现不太一样,下面是4.1的Window的源码

看一下这个LocalWindowManager是什么

LoaclWindowManager是Window的一个内部类,LocalWindowManager可以算个代理类,里面很多方法的具体实现还是在WindowManagerImpl。从 Android 4.2开始就已经没有这个东西了

下面是4.2及以上的代码,返回的只是WindowManagerImpl这个类的实例

这里就已经知道了Activity内缓存的WindowManager类型(4.2之前是LocalWindowManager,4.2及4.2之后是WindowManagerImpl)

这里可以顺便把之前Window 和View的关系理一下

3.这里知道wm的具体实现类型了,就可以跟最后一个方法了,wm.addView()。

其实4.2以下的LocalWindowManager也是调用的super.addView(),所以这里统一看WindowManagerImpl 中的addView(decor,l),这里也有个小细节,4.2及4.2版本以上引入了一个新的WindowManagerGlobal概念,这里以5.1的源码为准

提供与系统窗口管理器不需要上下文的低级别通信,看WindowManagerGlobal的addView方法

然后再看一下ViewRootImpl

好了,终于是发现Surface的踪迹了。看一下这个Surface的无参构造方法

里面什么都没做,只是创建了一个空的surface对象,W mWindow 是一个基于Binder通信的类,从IWindow.sutb派生出来的,这里先不管。

好了,这里Surface出现了,总结一下之前干的事情

首先跟踪了Acitivity在启动的时候做的一些事情,在performLaunchActivity(),中发现了Activity中存储了一个Window,一个WindowManager,这个WindowManager也同时存在Window里面,Window的类型是PhoneWindow的

在handleResumeActivity()中跟踪了三个方法

1.r.window.getDecorView(),

1.1在r.window.getDecorView()发现了DecorView和Activity 具体setContentView的关系,

2.a.getWindowManager(),

2.1在a.getWindowManager(),理清楚了Window ,WindowManager,Activity,DecorView,MyView的关系,

注: ” -->“ 继承

Activity里面缓存了PhoneWindow -->Window(抽象类) 和

WindowManager的实例,WindowManager缓存在Window当中,

WindowManager实例在4.2以下是 LocalWindowManager(Window的一个

内部类),4.2及4.2以上是

WindowManagerImpl -->WindowManager(interface) --

>ViewManager(interface)

3.在wm.addView(),发现了ViewRootImpl里面缓存了一个我们需要了解的Surface实例

接下里具体分析缓存了Surface实例的ViewRootImpl

二 :ViewRootImpl

继续跟上面ViewRootImpl的setView方法

先看到这个mWindowSession,他的实际类型是IWindowSession,看到这个大家应该就都明白咋回事了,这个是Session代理对象,就是WMS里面的那个成员变量mSessions里面装着的东西,如下图WindowManagerService的成员变量

Session继承于IWindowSession.Stub, 作为Binder服务端,同一进程中所有的ViewRootImpl对象只对应唯一相同的Session代理对象,所以这个addToDisplay()的函数是一个跨进程的调用,具体实现在Session类里,这里是ViewRootImpl和WMS的跨进程通信,和主题没什么关系,先不管它。

先继续跟requestLayout();

子线程不能刷新UI就是这个方法,ViewRootImpl里面有很多地方都调用了这个方法,这里就不一一贴了,由于本篇最之前看了,他是在onResume里面才被创建的,所以在某些极端情况onCreate里面在子线程刷新也是能成功的。

这边贴一个网图,就不再贴代码了,这里面大家应该都非常熟悉,主要工作是以DecorView为父容器开始自上而下的measure、layout、draw,measure确定View的测量宽和高,layout确定View的最终宽/高和四个顶点位置,draw将View绘制到屏幕上。

这个方法里面有两个地方和Surface相关,一个是relayoutWindow(),一个是drawSoftware()。看一下这两个方法

1. relayoutWindow()方法

其他参数可以先不用管,只要知道最后的mSuface就是ViewRootImpl 成员变量里面new出来的空的surface对象。

mWindowSession上面讲了,实际处理在Session的relayout里面,看一下代码

这个mService是WMS,再看一下WMS的 relayoutWindow方法

先跟一下winAnimator的createSurfaceLocked

继续跟

mNativeObject我的理解是native端返回的内存地址,如果为0说明对应的对象没有创建成功或者异常了。

继续跟native代码

这里主要做的事情是通过SurfaceControl的构造方法,把所有的信息和数据,都传到native层,在native层创建了一个SurfaceControl的对象,并将地址返回了。

SurfaceControl类可以看作是一个wrapper类:它对一些公开函数封装了一层,里面还有些Layer相关的东西暂且先不管它们。

再看一下Surface的copyFrom方法

继续跟native 层的创建

这边将之前native层创建的包含了所有信息和数据的SurfaceControl传到native层,通过这个control,在底层创建了一个含有真实数据信息的Surface,并将地址返回了,再看java层的 setNativeObjectLocked方法

这个方法就是把本地的ViewRootImpl 中的mSurface的内存地址替换了,换成了native层的地址,这样ViewRootImpl里面就持有了Native层的Surface对象了,并且拥有了数据和信息。

2.drawSoftware()方法;

看着好像挺简单的,我们来看一下lock和unlock到底做了什么事情,首先看 lockCanvas

这里多了两个参数,一个mNativeObject,一个 mCanvas,看一下是什么

看一下mNativeObject:

mNativeObject上面说了是个内存地址

看一下mCanvas;

mCanvas就是自己重新new了一个空白的没有内存指向的一个画布

Java层的函数到这就没了,跟一下native层 nativeLockCanvas

这个函数还是相对简单的,主要干的事:通过传进去的dirtyRectObj先获得一块存储区域,然后将它和之前创建的空白的没有指定存储区域的mCanvas绑定到一起,最终返回这块画布,这样UI绘画的结果就记录在这块区域里面了。

再看一下unlockCanvasAndPost

然后再看一下native层的代码

ViewRootImpl里面关于Surface的东西就已经说完了

最后总结一下这一段干的事情,ViewRootImpl创建的时候调用了Surface的无参构造方法,缓存并初始化了一个surface对象,在每次relayoutWindow通过Session的代理对象mWindowSession进行跨进程通信,在WMS里面通过JNI在native层创建了保存了各种信息和数据的SurfaceControl对象,然后用ViewRootImpl里面存储的surface将这个SurfaceControl通过JNI传回到native层,从中获取到带有数据信息的新的Surface对象,将地址返回,然后赋值给ViewRootImpl中的mSurface对象,至此ViewRootImpl中就持有了native层的surface对象。

持有了这个surface对象后就开始了draw操作,在每次onDraw的时候首先通过JNI将一块空白的画布和绘制区域传到native层,然后通过绘制区域在native申请存储空间,将存储空间传给SKBitmap,再将SKBitmap 实例设置到之前传入的空白画布上,然后将有存储空间的canvas返回,绘制完成之后,再将这个绘制好的canvas从surface上解绑,然后再将canvas上的数据保存到底层。

遗留问题

这次主要是以Surface为主线任务,跟踪从Activity创建开始,Surface和应用之间的关系以及它做的一些事情,中间其实遗留了很多支线任务没有拓展,比如ViewRootImpl的WMS的关系,以及他们之间跨进程通信;Surface在native层具体的实现和运转逻辑SurfaceSession,SurfaceFlingerd,如何创建,如何保存Canvas数据以及如何获取存储空间的等等.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android Surface解析 的相关文章

  • dagger.hilt.android.internal.managers.ViewComponentManager$FragmentContextWrapper 无法转换为 android.app.Activity

    我正在使用具有一些自定义视图实现的第三方库 在实现中 他们调用Utils showSoftKeyboard context as Activity 这与使用片段作为 AndroidEntryPoint 一起导致以下异常 java lang
  • 如何在再次恢复应用程序时不重新加载webview?

    我做了一个网络视图应用程序 一切都运转良好 但是 当用户点击后退按钮并打开 恢复 应用程序时 它会重新加载 Web 视图 我该如何预防呢 MainActivity java public class MainActivity extends
  • Android模拟器中的互联网连接始终显示连接状态

    我尝试了多种方法来检查我的 Android 模拟器中的互联网连接 ConnectivityManager conMgr ConnectivityManager getSystemService Context CONNECTIVITY SE
  • android ndk 多点触控?

    我正在编写一个仅使用本机代码的应用程序 那么ndk中是否可以获取多点触控事件呢 我感觉我已经搜索了整个网络 但什么也没找到 有谁知道如何做到这一点 是的 您可以检查名为native activity查看如何获取输入事件 寻找engine h
  • 如何使用数据绑定将点击侦听器设置为 LinearLayout

    我目前正在尝试将点击侦听器设置为LinearLayout查看在 xml使用数据绑定的布局文件 我已经设法让它在其他视图上很好地工作 比如Button or TextView 但由于某种原因 它不能与LinearLayout 这是我尝试的基本
  • 如何实现 ALTER TABLE 的示例[重复]

    这个问题在这里已经有答案了 我已经多次问过这个问题 但尚未得到完整的答案 如何实现 ALTER TABLE 语句以向数据库添加列 有人可以给我举个例子吗 请阅读SQLite ALTER TABLE 参考 http sqlite org la
  • Google 地图位于活动的中间区域

    我正在使用 Android studio 2 1 2 我检查了一下 大多数问题要么使用旧版本的 Android studio 要么使用一些旧的类 这些类不适用于我的情况 从文件 gt 新项目 gt 我使用了选项Google Maps Act
  • Android中如何使用JNI获取设备ID?

    我想从 c 获取 IMEIJNI 我使用下面的代码 但是遇到了未能获取的错误cls 它总是返回NULL 我检查了环境和上下文 它们都没有问题 为什么我不能得到Context班级 我在网上搜索了一下 有人说我们应该使用java lang Ob
  • 在 /dev/input/eventX 中写入事件需要哪些命令?

    我正在开发一个android需要将触摸事件发送到 dev input eventX 的应用程序 我知道C执行此类操作的代码结构如下 struct input event struct timeval time unsigned short
  • Monodroid 示例/带有源代码的小部件

    我是一名 NET 开发人员 我对用 C 开发 Android 应用程序感兴趣 并且我得到了 monodroid 是否有任何来源可以让我获得 monodroid 示例应用程序 带有源代码 这将帮助我在 monodroid 中开发应用程序 或者
  • 如何向 Android Studio 中的现有项目添加新活动?

    在 Eclipse 中 您只需单击 新建 按钮并选择 Android 活动即可添加新活动 但 Android Studio 有点不同 我无法找到如何向项目添加新活动 要添加一个Activity使用 Android Studio 此步骤与添加
  • Cordova + android:无法从应用程序打开拨号盘或邮件意图

    我有一个奇怪的问题 我无法从应用程序中打开带有预定义号码或邮件意图的拨号盘 我正在使用 netbeans 8 0 1 创建 cordova 应用程序 我的 Cordova 版本是 4 0 0 我按照步骤创建了一个应用程序 并选择了 Hell
  • 在 android studio 中找不到 SDK 位置

    我刚刚在 android studio 中导入了我的 eclipse 项目 我一直这么说 Error SDK location not found Define location with sdk dir in the local prop
  • 将非 Android 项目添加到 Android 项目

    我在 Eclipse 中有三个项目 Base Server 和 AndroidClient Base和Server是Java 1 7项目 而AndroidClient显然是一个android项目 基础项目具有在服务器和 Android 客户
  • Android NDK 支持区域设置吗?

    我真正想做的就是使用格式化日期strftime x 以正确的顺序 在大多数平台上调用setlocale 足够 在 Android 上 我不断收到 美国日期 那么 Android 不支持语言环境吗 No setlocale and strft
  • Android:如何创建模态进度“轮”叠加层?

    我想在我的视图上显示模式进度 轮子 叠加层 ProgressDialog 很接近 但我不想要对话框背景或边框 我尝试设置对话框窗口的背景可绘制 this progressDialog new ProgressDialog Main this
  • android系统用户和linux root用户有什么区别

    当我将手机连接到电脑并使用adb shell与我的手机通信并输入的命令ps命令输出当前在我的手机上运行的进程信息 我发现有两个特殊用户 一个是root 另一个是system 据我所知 Android是基于linux的 所以root用户是最大
  • 如何解决 greenDAO 在执行 InsertOrReplace 时“不存在这样的表错误”?

    我正在使用 greenDAO 并且已成功生成所有必需的类和实体 并且我可以看到我的表已创建 但是在要替换的行上放置断点后 我收到一条错误消息 告诉我 不存在这样的表错误 try appTimeUsageDao insertOrReplace
  • ARM Chromebook 上的 Android 开发环境?

    我尝试了多次安装和使用安卓工作室 https developer android com studio index html on an ARM Chromebook C100P https archlinuxarm org platfor
  • Keystore getEntry 在 Android 9 上返回 NULL

    c我已对存储在 Android 密钥库中的登录密码进行了加密和解密 在 Android 9 上 我观察到应用程序在尝试解密密码时崩溃 我无法重现它 但拥有 Pixel 3 的用户是崩溃的设备之一 下面是我如何从密钥库解密密码 private

随机推荐

  • 网络编程(详)

    一 概述 计算机网络 是指将地理位置不同的具有 独立功能的多台计算机及其外部设备 通过通信线路连接起来 在网络操作系统 网络管理软件及网络通信协议的管理和协调下 实现资源共享和信息传递的计算机系统 网络编程 在网络通信协议下 实现网络互连的
  • MATLAB—GUI新手入门教程

    GUI界面基本操作 1 GUI界面介绍 2 各个控件的使用方法 2 1 1 按钮 2 1 2 滑动条 2 1 3 文本框 2 1 4 单选框和复选框和切换按钮 2 1 5 弹出式菜单和列表框 2 1 6 按钮组 2 1 7 菜单编辑器 常见
  • 基于Xml方式Bean的配置-beanName个别名配置

    SpringBean配置详解 Bean的基础配置 例如前文涉及到的配置文件
  • 深入解读SpringBoot是什么?它到底有什么用?

    现在Spring Boot 非常火 各种技术文章 各种付费教程 多如牛毛 可能还有些不知道 Spring Boot 的 那它到底是什么呢 有什么用 今天给大家详细介绍一下 SpringBoot相关的教程 我是跟着动力节点王鹤老师讲的spri
  • Selenium Web自动化基础

    1 selenium环境配置 selenium是一个python的开源库 使用pip就可以安装 直接在cmd或者pycharm的终端执行pip install selenium 即可完成selenium库的安装 如果出现以下 Error c
  • 跟着angularjs2官方文档学习(四)

  • MySQL的复制原理以及流程,读写分离有哪些解决方案?

    MySQL的复制原理以及流程 主从复制 将主数据库中的DDL和DML操作通过二进制日志 BINLOG 传输到从数据库上 然后将这些日志重新执行 重做 从而使得从数据库的数据与主数据库保持一致 主从复制的作用 主数据库出现问题 可以切换到从数
  • 安卓手机格式化怎么弄_安卓手机怎样进入格式化?

    展开全部 硬格方法如下 在关机状态下 同时32313133353236313431303231363533e58685e5aeb931333365646261按住开机键和侧音量键下键 以开启手机 长按侧音量键下键约15秒钟 直至手机屏幕显示
  • shell脚本实现for循环打印数组

    array beijing tianjin hebei echo array 0 for i 0 i lt array i do echo array i done 数组要用括号加空格的方式进行声明 利用 或 可以将数组扩展成列表 然后使用
  • 电子产品量产工具项目开发中遇到的问题(更新......)

    1 找不到tslib h库的头文件 这是因为找不到tslib库的头文件 确定工具链中头文件 库文件目录 对于 IMX6ULL 命令如下 echo main arm linux gnueabihf gcc E v 找到了编译器arm linu
  • Python数据分析之pandas学习

    Python中的pandas模块进行数据分析 接下来pandas介绍中将学习到如下8块内容 1 数据结构简介 DataFrame和Series 2 数据索引index 3 利用pandas查询数据 4 利用pandas的DataFrames
  • 记一次win10+VM16双机调试的经历

    折腾了两天 终于成功 基础配置 宿主机和客户机均为win10 虚拟机是vm16 一 宿主机中的虚拟机配置 1 打开设置 删除打印机 也可以不删 网上很多教程 2 点击添加 选择串行端口 确定 3 选择2中添加的串行端口 选择 使用命名管道
  • CSS cubic-bezier() 函数 贝塞尔曲线 动画

    https www runoob com cssref func cubic bezier html
  • Jgit基础教程(Java调用git)

    前言 最近公司需要做一个java调用git的工具 这里简单的介绍了一下基本操作方法以及一些衍生的信息获取 或有不对的地方请大家批评指正 转载请注明出处 一 Jgit依赖导入
  • 【C】快速求最大公约数的三种办法

    最大公因数 也称最大公约数 最大公因子 指两个或多个整数共有约数中最大的一个 a b的最大公约数记为 a b 同样的 a b c的最大公约数记为 a b c 多个整数的最大公约数也有同样的记号 求最大公约数有多种方法 常见的有质因数分解法
  • yolo类检测算法解析——yolo v3

    每当听到有人问 如何入门计算机视觉 这个问题时 其实我内心是拒绝的 为什么呢 因为我们说的计算机视觉的发展史可谓很长了 它的分支很多 而且理论那是错综复杂交相辉映 就好像数学一样 如何学习数学 这问题似乎有点笼统 有点宽泛 所以我都会具体问
  • JavaWeb(13)超市订单管理系统smbms——登录功能及优化

    一 项目搭建 1 搭建一个maven web项目 2 配置Tomcat 3 测试项目是否能够跑起来 4 导入jar包 jsp servlet mysql驱动 jstl stand 5 创建项目包结构 6 编写实体类 ORM映射 表 类映射
  • [Shell] 常用写法

    iF9PzeAQm9 H7oi r6YdLk6 lxJ d c 常识 ls ls lh time style Y m d H M S awk condition move1 move2 文件名1 文件名2 NR 行数 索引 NF 列数 一般
  • JVM--基础--19.4--垃圾收集器--Parallel Scavenge

    JVM 基础 19 4 垃圾收集器 Parallel Scavenge 1 结构图 2 Parallel Scavenge 并行 收集器 2 1 特征 新生代收集器 使用复制算法 并行的多线程收集器 控制的吞吐量 吞吐量 运行用户代码时间
  • Android Surface解析

    源码截图是Android 5 1 1 r6 一 App和Surface的关系是怎样的 不论是用Skia绘制二维图像 还是用OpenGL绘制三维图像 最终Application都要和Surface交互 Surface 是什么 Handle o