引言
分析 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方法注册
jni 静态注册
这是一个 FmodActivity 类,这个类中有一个 playVoice 的 native 方法,
package com.testndk.jnistudy.ui.activity;
public class FmodActivity extends BaseActivity {
public native void playVoice(int model, String path);
}
当 Java 层调用 navtie 函数时,会在 JNI 库中根据函数名查找对应的 JNI 函数。如果没找到,会报错。
如果找到了,则会在 native 函数与 JNI 函数之间建立关联关系,其实就是保存 JNI 函数的函数指针。
下次再调用 native 函数,就可以直接使用这个函数指针。
JNI函数名格式(需将”.”改为”_”)
Java_ + 包名(com.testndk.jnistudy.ui.activity)+ 类名(FmodActivity) + 函数名(playVoice)
展示如下
Java_com_testndk_jnistudy_ui_activity_FmodActivity_playVoice(JNIEnv *env, jobject thiz, jint model,
jstring file_path_) {}
静态方法的缺点:
- 要求
JNI函数的名字必须遵循JNI规范的命名格式; - 名字冗长,容易出错;
- 初次调用会根据函数名去搜索
JNI中对应的函数,会影响执行效率; - 需要编译所有声明了
native函数的Java类,每个所生成的class文件都要用javah工具生成一个头文件;
jni 动态注册
通过提供一个函数映射表,注册给JVM虚拟机,这样JVM就可以用函数映射表来调用相应的函数,就不必通过函数名来查找需要调用的函数。
这个可以看 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));
}
- 创建映射表后,调用
RegisterNatives函数将映射表注册给JVM; - 当
Java层通过System.loadLibrary加载JNI库时,会在库中查JNI_OnLoad函数。可将JNI_OnLoad视 为JNI库的入口函数,需要在这里完成所有函数映射和动态注册工作,及其他一些初始化工作。
这里就是 静态注册 和 动态注册的区别,至于优缺点这里不做过多的讨论,回归 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 服务的启动过程了。