引言
分析 SurfaceFlinger
的渲染应用程序的 UI
前,首先我们会对 SurfaceFlinger 的启动流程
、SurfaceFlinger 服务初始化硬件帧缓冲区的过程
以及 SurfaceFlinger服务的线程模型
有一个比较简单的认识,当然有喜欢看源码的朋友建议看下以下几篇文章:
- Android系统Surface机制的SurfaceFlinger服务的启动过程分析
- Android系统Surface机制的SurfaceFlinger服务对帧缓冲区(Frame Buffer)的管理分析
- # Android系统Surface机制的SurfaceFlinger服务的线程模型分析
源码基于 Ice Cream Sandwich MR1 | 4.0.4_r2.1 进行分析
SurfaceFlinger 的启动流程
简介
SurfaceFlinger
服务是在 System
进程中启动的,并且负责统一管理设备的帧缓冲区。SurfaceFlinger
服务在启动的过程中,会创建两个线程,其中一个线程用来监控控制台事件,而另外一个线程用来渲染系统的UI。System
进程是由 Zygote
进程启动的,并且是以 Java
层的 SystemServer
类的静态成员函数 main
为入口函数的。启动过程如下图
SystemServer.class
// 源码位置: https://www.androidos.net.cn/android/4.2.2_r1/xref/frameworks/base/services/java/com/android/server/SystemServer.java
public class SystemServer {
...
/**
* 这个方法从Zygote被调用来初始化系统。
* 这将导致本地服务(SurfaceFlinger, AudioFlinger等)启动。
* 之后,它会回调init2()来启动Android服务
*/
native public static void init1(String[] args);
public static void main(String[] args) {
...
System.loadLibrary("android_servers");
init1(args);
}
public static final void init2() {
Slog.i(TAG, "Entered the Android system server!");
Thread thr = new ServerThread();
thr.setName("android.server.ServerThread");
thr.start();
}
}
复制代码
这个类就没啥可说的,入口函数 main
中加载了 android_servers
系统服务 so
并且调用了 native 的 init1
的初始化方法,及 com_android_server_SystemServer.cpp
中的 android_server_SystemServer_init1
namespace android {
extern "C" int system_init();
static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz)
{
system_init();
}
/*
* JNI registration.
*/
static JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{ "init1", "([Ljava/lang/String;)V", (void*) android_server_SystemServer_init1 },
};
int register_android_server_SystemServer(JNIEnv* env)
{
return jniRegisterNativeMethods(env, "com/android/server/SystemServer",
gMethods, NELEM(gMethods));
}
}; // namespace android
复制代码
当然,可能有的盆友对 jni
不是很了解,这边稍微解释下是如何调用过来的。调用 jni
分为两种一种是静态注册,另外一种是动态注册。
jni 静态注册
这是一个 FmodActivity
类,这个类中有一个 playVoice
的 native
方法,
package com.testndk.jnistudy.ui.activity;
public class FmodActivity extends BaseActivity {
public native void playVoice(int model, String path);
}
复制代码
当你写完该方法,编译器会提示报错,你可以通过编译器在 c 文件生成以下固定格式的代码 Java_包名_类名_方法名
,当然前提是你得项目支持 c++
,这边不做过多讲解了。也可以通过 javah -jni
的指令生成,这个就自行百度。
Java_com_testndk_jnistudy_ui_activity_FmodActivity_playVoice(JNIEnv *env, jobject thiz, jint model,
jstring file_path_) {}
复制代码
这种情况就属于静态注册
jni 动态注册
这个可以看 SystemServer
类,他也有一个 native
的方法 init1
native public static void init1(String[] args);
复制代码
但是我们可以从 com_android_server_SystemServer
中没有找到类似于静态方法那样的代码格式,而是
/*
* JNI registration.
*/
static JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{ "init1", "([Ljava/lang/String;)V", (void*) android_server_SystemServer_init1 },
};
int register_android_server_SystemServer(JNIEnv* env)
{
return jniRegisterNativeMethods(env, "com/android/server/SystemServer",
gMethods, NELEM(gMethods));
}
复制代码
gMethods[]
的方式进行注册的。
这里就是 静态注册 和 动态注册的区别,至于优缺点这里不做过多的讨论,回归 SurfaceFlinger 启动的主流程
在 android_server_SystemServer_init1
中,调用了 system_init
的方法,可能看到这里的朋友都不知道这个 system_init
方法那里来的,看到下面这句代码就应该知道什么意思了
extern "C" int system_init();
复制代码
接着我们找到这个方法
// https://www.androidos.net.cn/android/4.0.4_r2.1/xref/frameworks/base/cmds/system_server/library/system_init.cpp
extern "C" status_t system_init()
{
LOGI("Entered system_init()");
sp<ProcessState> proc(ProcessState::self());
......
char propBuf[PROPERTY_VALUE_MAX];
property_get("system_init.startsurfaceflinger", propBuf, "1");
if (strcmp(propBuf, "1") == 0) {
// Start the SurfaceFlinger
SurfaceFlinger::instantiate();
}
......
if (proc->supportsProcesses()) {
LOGI("System server: entering thread pool.\n");
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
LOGI("System server: exiting thread pool.\n");
}
return NO_ERROR;
}
复制代码
函数首先获得 System
进程中的一个 ProcessState
单例,并且保存在变量 proc
中,后面会通过调用它的成员函数 supportsProcesses
来判断系统是否支持 Binder
进程间通信机制。函数接下来就检查系统中是否存在一个名称为 system_init.startsurfaceflinger
的属性。如果存在的话,就将它的值获取回来,并且保存在缓冲区 proBuf
中。如果不存在的话,那么函数 property_get
就会将缓冲区 proBuf
的值设置为 1
。当缓冲区 proBuf
的值等于 1
的时候,就表示需要在 System
进程中将 SurfaceFlinger
服务启动起来,这是通过调用 SurfaceFlinger
类的静态成员函数 instantiate
来实现的。
函数最后检查系统是否支持 Binder
进程间通信机制。如果支持的话,那么接下来就会调用当前进程中的ProcessState
单例的成员函数 startThreadPool
来启动一个 Binder
线程池,并且调用当前线程中的IPCThreadState
单例来将当前线程加入到前面所启动的 Binder
线程池中去。有了这个 Binder
线程池之后,SurfaceFlinger
服务在启动完成之后,就可以为系统中的其他组件或者进程提供服务了。
这里我们假设 system_init.startsurfaceflinger
属性的值为 1
,以便于走 SurfaceFlinger
初始化流程
// https://www.androidos.net.cn/android/4.0.4_r2.1/xref/frameworks/base/services/surfaceflinger/SurfaceFlinger.h
class SurfaceFlinger :
public BinderService<SurfaceFlinger>,
public BnSurfaceComposer,
private IBinder::DeathRecipient,
private Thread,
private HWComposer::EventHandler {
...
}
复制代码
这边我们可以看到 SurfaceFlinger
继承自 BinderService
,并且 SurfaceFlinger.cpp
中并没有 instantiate
方法的实现(SurfaceFlinger.cpp),只能从父类中找 instantiate
的实现
BinderService.h
// https://www.androidos.net.cn/android/4.0.4_r2.1/xref/frameworks/base/include/binder/BinderService.h
class BinderService
{
public:
static status_t publish() {
sp<IServiceManager> sm(defaultServiceManager());
return sm->addService(String16(SERVICE::getServiceName()), new SERVICE());
}
...
static void instantiate() { publish(); }
...
};
复制代码
BinderService
类的静态成员函数 instantiate
的实现很简单,它只是调用 BinderService
类的另外一个静态成员函数 publish
来继续执行启动 SurfaceFlinger
服务的操作。
BinderService
是一个模板类,它有一个模板参数 SERVICE
。当 BinderService
类被SurfaceFlinger
类继承时,模板参数 SERVICE
的值就等于 SurfaceFlinger
。因此,BinderService
类的静态成员函数 publish
所执行的操作就是创建一个 SurfaceFlinger
实例,用来作为系统的 SurfaceFlinger
服务。
SurfaceFlinger.cpp
// https://www.androidos.net.cn/android/4.0.4_r2.1/xref/frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp
SurfaceFlinger::SurfaceFlinger()
: BnSurfaceComposer(), Thread(false),
...
{
init();
}
void SurfaceFlinger::init()
{
LOGI("SurfaceFlinger is starting");
// debugging stuff...
char value[PROPERTY_VALUE_MAX];
property_get("debug.sf.showupdates", value, "0");
mDebugRegion = atoi(value);
property_get("debug.sf.showbackground", value, "0");
mDebugBackground = atoi(value);
property_get("debug.sf.ddms", value, "0");
mDebugDDMS = atoi(value);
if (mDebugDDMS) {
DdmConnection::start(getServiceName());
}
LOGI_IF(mDebugRegion, "showupdates enabled");
LOGI_IF(mDebugBackground, "showbackground enabled");
LOGI_IF(mDebugDDMS, "DDMS debugging enabled");
}
复制代码
并且将这个服务 addService
到 Service Manager
中去,这样系统中的其它组件或者进程就可以通过 Service Manager
来获得 SurfaceFlinger
服务的 Binder
代理对象,进而使用它所提供的服务。
由于 Service Manager
的 Binder
代理对象的成员函数 addService
的第二个参数是一个类型为IBinder的强指针引用。从 Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理可以得知,当一个对象第一次被一个强指针引用时,那么这个对象的成员函数 onFirstRef
就会被调用。
// https://www.androidos.net.cn/android/4.0.4_r2.1/xref/frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp#210
void SurfaceFlinger::onFirstRef() {
run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY);
// Wait for the main thread to be done with its initialization
mReadyToRunBarrier.wait();
}
复制代码
函数首先调用从父类继承下来的成员函数 run
来启动一个名秒为 SurfaceFlinger
的线程,用来执行 UI
渲染操作。这就是前面我们所说的 UI
渲染线程了。这个UI渲染线程创建完成之后,首先会调用 SurfaceFlinger
类的成员函数 readyToRun
来执行一些初始化操作,接着再循环调用 SurfaceFlinger
类的成员函数 threadLoop
来作为线程的执行体。
mReadyToRunBarrier
是 SurfaceFlinger
类的一个成员变量,它的类型是 Barrier
,用来描述一个屏障,是通过条件变量来实现的。我们可以把它看作是一个线程同步工具,即阻塞当前线程,直到 SurfaceFlinger
服务的 UI
渲染线程执行完成初始化操作为止。
我们就继续分析 SurfaceFlinger
类的成员函数 readyToRun
的实现,以便可以了解 SurfaceFlinger
服务的 UI
渲染线程的初始化过程。
// https://www.androidos.net.cn/android/4.0.4_r2.1/xref/frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp#223
status_t SurfaceFlinger::readyToRun()
{
LOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
// we only support one display currently
int dpy = 0;
{
// initialize the main display
// 首先创建了一个 DisplayHardware 对象 hw,用来描述设备的显示屏,并且用这个 DisplayHardware
// 对象来初始化 SurfaceFlinger 类的成员变量 mGraphicPlanes 所描述的一个 GraphicPlane 数组的第一个元素。
// 在 DisplayHardware 对象 hw 的创建过程中,会创建另外一个线程,用来监控控制台事件,
// 即监控硬件帧缓冲区的睡眠和唤醒事件。
GraphicPlane& plane(graphicPlane(dpy));
DisplayHardware* const hw = new DisplayHardware(this, dpy);
plane.setDisplayHardware(hw);
}
// create the shared control-block
// 创建了一块大小为 4096,即 4KB 的匿名共享内存,接着将这块匿名共享内存结构化为一个
// surface_flinger_cblk_t 对象来访问。这个 surface_flinger_cblk_t 对象就保存在 SurfaceFlinger
// 类的成员变量 mServerCblk 中。这块匿名共享内存用来保存设备显示屏的属性信息,
// 例如,宽度、高度、密度和每秒多少帧等信息
mServerHeap = new MemoryHeapBase(4096,
MemoryHeapBase::READ_ONLY, "SurfaceFlinger read-only heap");
LOGE_IF(mServerHeap==0, "can't create shared memory dealer");
mServerCblk = static_cast<surface_flinger_cblk_t*>(mServerHeap->getBase());
LOGE_IF(mServerCblk==0, "can't get to shared control block's address");
new(mServerCblk) surface_flinger_cblk_t;
// initialize primary screen
// (other display should be initialized in the same manner, but
// asynchronously, as they could come and go. None of this is supported
// yet).
// 这段代码首先获得 SurfaceFlinger 类的成员变量 mGraphicPlanes 所描述的一个 GraphicPlane
// 数组的第一个元素 plane,接着再设置它的宽度、长度和像素格式等作息,最后再调用它里面的一个
// DisplayHardware 对象 hw 的成员函数 makeCurrent 来将它作为系统的主显示屏。
// 这个 DisplayHardware 对象 hw 是在前面第一段代码中创建的,在创建的过程中,它会执行一些初始化操作,
// 这里将它设置为系统主显示屏之后,后面就可以将系统的UI渲染在它上面了。
const GraphicPlane& plane(graphicPlane(dpy));
const DisplayHardware& hw = plane.displayHardware();
const uint32_t w = hw.getWidth();
const uint32_t h = hw.getHeight();
const uint32_t f = hw.getFormat();
hw.makeCurrent();
// initialize the shared control block
// 这段代码将系统主显示屏的属性信息保存在前面所创建的一块匿名共享内存中,
// 以便可以将系统主显示屏的属性信息返回给系统中的其它进程访问。
mServerCblk->connected |= 1<<dpy;
display_cblk_t* dcblk = mServerCblk->displays + dpy;
memset(dcblk, 0, sizeof(display_cblk_t));
dcblk->w = plane.getWidth();
dcblk->h = plane.getHeight();
dcblk->format = f;
dcblk->orientation = ISurfaceComposer::eOrientationDefault;
dcblk->xdpi = hw.getDpiX();
dcblk->ydpi = hw.getDpiY();
dcblk->fps = hw.getRefreshRate();
dcblk->density = hw.getDensity();
// Initialize OpenGL|ES
// 这段代码用来初始化 OpenGL 库,因为 SurfaceFlinger 服务是通过 OpenGL 库提供的 API 来渲染系统的 UI 的。
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glPixelStorei(GL_PACK_ALIGNMENT, 4);
glEnableClientState(GL_VERTEX_ARRAY);
glEnable(GL_SCISSOR_TEST);
glShadeModel(GL_FLAT);
glDisable(GL_DITHER);
glDisable(GL_CULL_FACE);
const uint16_t g0 = pack565(0x0F,0x1F,0x0F);
const uint16_t g1 = pack565(0x17,0x2f,0x17);
const uint16_t wormholeTexData[4] = { g0, g1, g1, g0 };
glGenTextures(1, &mWormholeTexName);
glBindTexture(GL_TEXTURE_2D, mWormholeTexName);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0,
GL_RGB, GL_UNSIGNED_SHORT_5_6_5, wormholeTexData);
const uint16_t protTexData[] = { pack565(0x03, 0x03, 0x03) };
glGenTextures(1, &mProtectedTexName);
glBindTexture(GL_TEXTURE_2D, mProtectedTexName);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0,
GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData);
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// put the origin in the left-bottom corner
glOrthof(0, w, 0, h, 0, 1); // l=0, r=w ; b=0, t=h
// SurfaceFlinger 服务的 UI 渲染线程已经创建并且初始化完成了,
// 这时候 System 进程的主线程就可以继续向前执行其它操作了。
mReadyToRunBarrier.open();
/*
* We're now ready to accept clients...
*/
// start boot animation
// 调用函数 property_set 来设置系统中名称为 “ctl.start” 的属性,即将它的值设置为“bootanim”。
// 当它的值等于 “bootanim” 的时候,就表示要启动 Android 系统的开机动画。
property_set("ctl.start", "bootanim");
return NO_ERROR;
}
复制代码
从这里就可以看出,当我们看到 Android
系统的开机动画时,就说明 Android
系统的 SurfaceFlinger
服务已经启动起来了。至此,我们就分析完成 SurfaceFlinger
服务的启动过程了。