Android显示系统(01)- 架构分析
Android显示系统(02)- OpenGL ES - 概述
Android显示系统(03)- OpenGL ES - GLSurfaceView的使用
Android显示系统(04)- OpenGL ES - Shader绘制三角形
Android显示系统(05)- OpenGL ES - Shader绘制三角形(使用glsl文件)
Android显示系统(06)- OpenGL ES - VBO和EBO和VAO
Android显示系统(07)- OpenGL ES - 纹理Texture
Android显示系统(08)- OpenGL ES - 图片拉伸
Android显示系统(09)- SurfaceFlinger的使用
Android显示系统(10)- SurfaceFlinger内部结构
Android显示系统(11)- 向SurfaceFlinger申请Surface
Android显示系统(12)- 向SurfaceFlinger申请Buffer
Android显示系统(13)- 向SurfaceFlinger提交Buffer
一、前言:
之前文章讲解了Android显示系统的架构,并且花了大量时间介绍了OpenGL ES,以及为了保证OpenGL ES的平台无关性,Android引入的EGL。不过我们都是借助于GLSurfaceView
来学习的,而我们构建GLSurfaceView
对象的时候,在Native层做了很多的事情,其中,大多数逻辑都是SurfaceFlinger
辅助我们完成的,它才是整个Android显示系统的核心。
SurfaceFlinger
最重要的职责就是合成各个App传递过来的Surface。本文先学会在Native层使用SurfaceFlinger
,后续根据代码一点点引入不同知识。
**说明:**后续文章如果出现SF
那就是我对SurfaceFlinger
的缩写。
二、BootAnimation:
读者可能很郁闷,讲SF的使用,怎么突然蹦出来这么一个东西。其实,BootAnimation
是 Android 系统启动时显示的动画,通常包括启动画面、动画效果和加载过程中的图形展示。要学习Native层显示系统,它是最好的程序之一,因为,此时AMS、WMS那些复杂的服务还没有启动,干扰项少!
1、启动:
- 在
Android.bp
当中启动bootanim.rc
; - 解析文件内容启动
BootAnimation
进程; - 启动之后,就会调用
BootAnimation
的main函数;
这是base\cmds\bootanimation\bootanim.rc
内容,我都贴心的加了注释。
# 这行定义了一个名为 bootanim 的服务,服务的可执行文件是 /system/bin/bootanimation。
service bootanim /system/bin/bootanimation
# 这行指定了服务的类别。将其归类为 core 和 animation 意味着该服务属于系统的核心服务及动画服务类别,可能影响其调度和优先级
class core animation
# 这行指定了运行该服务的用户身份是 graphics
user graphics
# 这行指定该服务属于 graphics 和 audio 组。这样做是为了允许该服务访问所需的资源和设备,因此图形和音频相关的权限会得到支持。
group graphics audio
# 这表示该服务在系统启动时不会自动启动。
disabled
# 这个关键字指明该服务是一种一次性服务。它在启动后会运行一次并退出,而不是保持在后台持续运行
oneshot
# 这行设置了 I/O 调度优先级,rt 表示实时优先级,0 是优先级值。设置为 0 表示它具有较低的实时优先级
ioprio rt 0
# 这一行表示将该服务的进程 ID(PID)写入到特定路径 /dev/stune/top-app/tasks 中
writepid /dev/stune/top-app/tasks
注意,其中这一行disabled
表示这个服务不会自己启动,为什么呢?因为它要渲染开机画面,离不开大佬SurfaceFlinger
,SurfaceFlinger
启动之后,会将这个改成enable
,然后,bootanimation
服务就启动了,启动后当然就要执行main函数了。
2、流程概述:
我们假设自己没有阅读过BootAnimation
,但是,我们对SurfaceFlinger
比较熟悉,我们觉得应该怎么做?
- 获得
SurfaceFlinger
服务; - 通过
SurfaceFlinger
创建Surface
; - 开始循环:
- 得到surface里面的buffer;
- 设置给渲染引擎(比如之前的OpenGL ES),往buffer填充数据;
- 提交填充好的buffer;
后续我们阅读完开机动画代码之后再总结,只是会详细很多,透过现象看本质,大体思路不会变。
3、main函数:
文件路径:base\cmds\bootanimation\bootanimation_main.cpp
代码如下:
int main()
{
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
bool noBootAnimation = bootAnimationDisabled();
ALOGI_IF(noBootAnimation, "boot animation disabled");
if (!noBootAnimation) {
sp<ProcessState> proc(ProcessState::self());
ProcessState::self()->startThreadPool();
// create the boot animation object (may take up to 200ms for 2MB zip)
sp<BootAnimation> boot = new BootAnimation(audioplay::createAnimationCallbacks());
waitForSurfaceFlinger();
boot->run("BootAnimation", PRIORITY_DISPLAY);
ALOGV("Boot animation set up. Joining pool.");
IPCThreadState::self()->joinThreadPool();
}
return 0;
}
总体来看:
负责设置进程的优先级,检查是否禁用 BootAnimation
,启动并设置 BootAnimation
相关的状态和资源,同时确保在 SurfaceFlinger
可用后开始播放动画。通过这样的结构,系统能够顺利地处理BootAnimation
的显示,确保用户在设备开机时有良好的视觉体验。
详细看看:
-
设置进程优先级:
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
PRIO_PROCESS
指定要修改的是进程的优先级。0
表示当前进程(即当前执行的 main 函数)。ANDROID_PRIORITY_DISPLAY
是一个常量,通常是在 Android 中用于设置与显示相关的进程优先级,确保 Boot Animation 在显示时有足够的资源进行渲染。
-
检查是否禁用
BootAnimation
:bool noBootAnimation = bootAnimationDisabled();
如果没有禁用,才会执行主要逻辑;
-
打开
Binder
,并启动线程池:因为SF就是一个Binder服务,要想访问SF,必须先打开Binder;
sp<ProcessState> proc(ProcessState::self()); ProcessState::self()->startThreadPool();
其实
ProcessState::self()
主要作用就是打开binder,并将进程和线程的相关信息设置进binder的binder_proc,binder_thread结构当中。接着通过startThreadPool()
启动线程池,主要处理 IPC(进程间通信)请求。这样可以在后台异步处理工作而不阻塞主线程。 -
创建 BootAnimation 对象,并设置音频回调函数:
sp<BootAnimation> boot = new BootAnimation(audioplay::createAnimationCallbacks());
这回调函数应该是播放那个开机完了
噔噔噔噔
的,我没看!! -
等待
SurfaceFlinger
可用:waitForSurfaceFlinger();
-
运行
BootAnimation
:boot->run("BootAnimation", PRIORITY_DISPLAY);
传入“BootAnimation”的名称和显示优先级 PRIORITY_DISPLAY。
-
加入线程池:
IPCThreadState::self()->joinThreadPool();
当前的线程(也就是main方法所在的线程)加入Binder的线程池,并阻塞住,保证当前进程不退出。
4、启动BootAnimation:
4.1、重要方法:
- sp指针是Android当中的一个强智能指针(strong pointer,不是smart pointer),对应的还有wp就是weak pointer。
BootAnimation
继承自Thread
和DeathRecipient
(DeathRecipient
继承了RefBase
),也就是说BootAnimation