SurfaceFlinger是一个系统服务,作用就是接受不同layer的buffer数据进行合成,然后发送到显示设备进行显示。
SurfaceFlinger进程是什么时候起来的?
在之前的Android低版本手机上,SurfaceFlinger进程是在init.rc中启动的,在最新的高版本上SurfaceFlinger进程并不是直接在init.rc文件中启动的,而是通过Android.bp去包含启动surfaceflinger.rc文件,然后在该文件中再去启动SurfaceFlinger进程。
/framework/native/services/surfaceflinger/surfaceflinger.rc
service surfaceflinger /system/bin/surfaceflinger
class core animation
user system
group graphics drmrpc readproc
capabilities SYS_NICE
onrestart restart zygote
task_profiles HighPerformance
socket pdx/system/vr/display/client stream 0666 system graphics u:object_r:pdx_display_client_endpoint_socket:s0
socket pdx/system/vr/display/manager stream 0666 system graphics u:object_r:pdx_display_manager_endpoint_socket:s0
socket pdx/system/vr/display/vsync stream 0666 system graphics u:object_r:pdx_display_vsync_endpoint_socket:s0
关于init.rc文件的解析和Android.bp的编译脚本执行(Soong编译系统)本文不做深入研究,SurfaceFlinger进程启动了,就会执行到main函数。
/services/surfaceflinger/Main_surfaceflinger.cpp
main函数中,有几个关键的点需要关注。
ProcessState::self() 函数的调用,个人理解是同binder驱动建立链接,获取驱动的版本,通知驱动,可以同时启动15个线程来处理Client的请求。
总结:
(1)构建ProcessState全局对象gProcess
(2)打开binder驱动,建立链接
(3)在驱动内部创建该进程的binder_proc,binder_thread结构,保存该进程的进程信息和线程信息,并加入驱动的红黑树。
(4)获取驱动的版本信息
(5)把该进程最多可同时启动的线程告诉驱动,并保存到改进程的binder_proc结构中
(6)把设备文件/dev/binder映射到内存中
设置SurfaceFlinger进程的优先级
setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);
set_sched_policy(0, SP_FOREGROUND);
if(cpusets_enabled()){
set_cpuset_policy(0, SP_SYSTEM);
}
关于cpuset的使用,有一些简单的命令如下:
查看cpuset的所有分组
adb shell ls -l /dev/cpuset
查看system-background的cpuset的cpu
adb shell cat /dev/cpuset/system-background/cpus
查看system-background的应用
adb shell cat /dev/cpuset/system-background/tasks
查看SurfaceFlinger的cpuset
adb shell 'cat /proc/(pid of surfaceflinger)/cpuset'
我们也可以自定义cpuset,就是可以根据各自的需求,动态配置自定义的cpuset,例如SurfaceFlinger的线程默认跑到4个小核上,假如有个需求要把SurfaceFlinger的线程跑到大核上,就可以配置自定义cpuset,在进入某个场景的时候,把SurfaceFlinger进程pid配置到自定义的cpuset的tasks中。
3 初始化SurfaceFlinger
// 实例化 surfaceflinger
sp<SurfaceFlinger> flinger = surfaceflinger::createSurfaceFlinger();
// 初始化 surfaceflinger
flinger->init();
// 将 flinger 添加到 ServiceManager 进程中
sp<IServiceManager> sm(defaultServiceManager());
sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false, IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
//启动 DisplayService
startDisplayService();
// 启动 surfaceflinger
flinger->run();
实例化 surfaceflinger
有个SurfaceFlingerFactory.cpp,类似java中的工厂类,在头文件中定义了好多创建不同对象的函数。
/frameworks/native/services/surfaceflinger/SurfaceFlingerFactory.cpp
sp<SurfaceFlinger> createSurfaceFlinger() {
static DefaultFactory factory;
return new SurfaceFlinger(factory);
}
} // namespace android::surfaceflinger
通过SurfaceFlingerFactory.cpp创建了一个SurfaceFlinger对象。
/frameworks/native/services/surfaceflinger/SurfaceFlinger.h
class SurfaceFlinger : public BnSurfaceComposer,
public PriorityDumper,
private IBinder::DeathRecipient,
private HWC2::ComposerCallback,
private ISchedulerCallback
SurfaceFlinger继承BnSurfaceComposer,实现ISurfaceComposer接口,实现ComposerCallback,PriorityDumper是一个辅助类,提供了SurfaceFlinger的dump信息。
关于ISurfaceComposer的接口定义和实现,本文不做细节描述。
简单画了SurfaceFlinger的UML图。
ISurfaceComposer 是对SurfaceFlinger进程的binder调用。
HWC2::ComposerCallback,这个是面向底层硬件的回调,这个包含了三个很关键的回调函数,onComposerHotplug函数表示显示屏的热插拔通知给SurfaceFlinger进程的回调, onComposerHalRefresh函数表示底层硬件通知SurfaceFlinger进程HWC刷新的回调,onComposerHalVsync表示底层通知SurfaceFlinger进程同步信号的回调。
我们接下来看下SurfaceFlinger的构造函数。
在SurfaceFlinger中的构造方法中,初始化了大量的全局变量,有一些变量影响了整个代码的执行流程等等,而这些变量都可以在开发者模式中去更改它,就是SurfaceFlinger作为binder的服务端,设置页面中的开发者模式页面做为client端去调用更改,努比亚作为ROM厂商,SurfaceFlinger的代码中还包括了开关高通辅助功能的属性开关等等。
初始化 surfaceflinger
实例化surfaceflinger对象之后,调用该对象的init方法,这个方法里面有几个比较重要的代码。
构造SkiaRenderEngine渲染引擎
mCompositionEngine->setRenderEngine(renderengine::RenderEngine::create(
renderengine::RenderEngineCreationArgs::Builder()
.setPixelFormat(static_cast<int32_t>(defaultCompositionPixelFormat))
.setImageCacheSize(maxFrameBufferAcquiredBuffers)
.setUseColorManagerment(useColorManagement)
.setEnableProtectedContext(enable_protected_contents(false))
.setPrecacheToneMapperShaderOnly(false)
.setSupportsBackgroundBlur(mSupportsBlur)
.setContextPriority(
useContextPriority
? renderengine::RenderEngine::ContextPriority::REALTIME
: renderengine::RenderEngine::ContextPriority::MEDIUM)
.build()));
在Android S版本之前,这块的绘制流程都是opengles实现的,在Android S新版本上切换到skia库,mCompositionEngine这个类比较重要,主要负责layer的Client合成就是GPU合成,截图,录屏等核心功能都和这块有关系,Client合成有别于HWC合成,一个是GPU合成,一个是高通的硬件去合成。针对skia库的研究后面有单独的章节进行讲解。
构造Vsync
// Process any initial hotplug and resulting display changes.
processDisplayHotplugEventsLocked();
上面这个函数会被几个地方调用到,在init方法中,还有binder的调用中和ComposerCallback的回调中,我们重点看这个函数中调用了initScheduler方法,
// start the EventThread
mScheduler = getFactory().createScheduler(*mRefreshRateConfigs, *this);
const auto configs = mVsyncConfiguration->getCurrentConfigs();
const nsecs_t vsyncPeriod = currRefreshRate.getPeriodNsecs();
mAppConnectionHandle =
mScheduler->createConnection("app", mFrameTimeline->getTokenManager(),
/*workDuration=*/configs.late.appWorkDuration,
/*readyDuration=*/configs.late.sfWorkDuration,
impl::EventThread::InterceptVSyncsCallback());
mSfConnectionHandle =
mScheduler->createConnection("appSf", mFrameTimeline->getTokenManager(),
/*workDuration=*/std::chrono::nanoseconds(vsyncPeriod),
/*readyDuration=*/configs.late.sfWorkDuration,
[this](nsecs_t timestamp) {
mInterceptor->saveVSyncEvent(timestamp);
});
mEventQueue->initVsync(mScheduler->getVsyncDispatch(), *mFrameTimeline->getTokenManager(),
configs.late.sfWorkDuration);
上面把initScheduler方法中几个关键的代码贴出来,这个和Vsync研究密切相关,当我们要研究SurfaceFlinger的合成流程,也就本章节要讲的最核心的流程,合其触发的条件是由Vsync控制的,Vsync很像一个节拍器,SurfaceFlinger中每一帧的合成都需要跟随节拍器,太快或者太慢都会导致屏幕显示异常,一般表现为画面卡顿,不流畅,本章的主要讲解SurfaceFlinger的合成流程,关于Vsync的研究后面有独立章节进行讲解。
举例讲解一个init函数中高通一个so库的加载。
char layerExtProp[PROPERTY_VALUE_MAX];
property_get("vendor.display.use_layer_ext", layerExtProp, "0");
if(atoi(layerExtProp)){
mUseLayerExt = true;
}
当我们把vendor.display.use_layer_ext中配置成1,就会把mUseLayerExt的变量置为true,这个变量代表SurfaceFlinger使用liblayerext.qti.so。这个so库是判断当前的layer是不是游戏的layer,所以当这个库加载成功之后,会在BufferLayer对象在构造函数中初始化一个layer的变量mLayerClass。
if(mFlinger->mLayerExt){
mLayerClass = mFlinger -> mLayerExt ->GetLayerClass(mName);
}
当mLayerClass被初始化成功之后,第三方应用可以通过binder调用,查询SurfaceFlinger进程这个应用的layer是不是游戏的layer,如果是游戏的layer则可以处理自己的逻辑等等,在最新的Android S版本有个AppClassifier应用需要启动,如果被禁止会导致liblayerext.qti.so去判断layer的类型发生异常,这个apk是高通实现的,会监听应用的安装广播,所以会在数据库中存储一份不同应用对应的的类别信息。
将SurfaceFlinger添加到 ServiceManager进程中
这个逻辑主要是提供给app端通过binder来调用SurfaceFlinger的方法,SurfaceFlinger的onTransact函数会根据app端传递的code做不同的代码处理,下图是onTransact函数中一处code的处理。
case 1034: {
switch (n = data.readInt32()) {
case 0:
case 1:
enableRefreshRateOverlay(static_cast<bool>(n));
break;
default: {
Mutex::Autolock lock(mStateLock);
reply->writeBool(mRefreshRateOverlay != nullptr);
}
}
return NO_ERROR;
}
这个code是1034的逻辑,那么是那个app端发出来的么,答案是设置应用中的开发者模式页面中的功能按钮,搜索了Settings应用中关于1034的逻辑,找到了一个ShowRefreshRatePreferenceController.java包含这段逻辑。
/Settings/src/com/android/settings/development/ShowRefreshRatePreferenceController.java
private static final String SHOW_REFRESH_RATE_KEY = "show_refresh_rate";
@VisibleForTesting
static final int SURFACE_FLINGER_CODE = 1034;
public ShowRefreshRatePreferenceController(Context context) {
super(context);
mSurfaceFlinger = ServiceManager.getService(SURFACE_FLINGER_SERVICE_KEY);
}
@VisibleForTesting
void updateShowRefreshRateSetting() {
// magic communication with surface flinger.
try {
if (mSurfaceFlinger != null) {
final Parcel data = Parcel.obtain();
final Parcel reply = Parcel.obtain();
data.writeInterfaceToken(SURFACE_COMPOSER_INTERFACE_KEY);
data.writeInt(SETTING_VALUE_QUERY);
mSurfaceFlinger.transact(SURFACE_FLINGER_CODE, data, reply, 0 /* flags */);
final boolean enabled = reply.readBoolean();
((SwitchPreference) mPreference).setChecked(enabled);
reply.recycle();
data.recycle();
}
} catch (RemoteException ex) {
// intentional no-op
}
}
从上面的代码可以看到,App端对SurfaceFlinger进程进行了binder通讯。
启动 surfaceflinger
voidSurfaceFlinger::run() {
while (true) {
mEventQueue->waitMessage();
}
}
SurfaceFlinger onFirstRef方法
voidSurfaceFlinger::onFirstRef() {
mEventQueue->init(this);
}
在前面的main函数,SurfaceFlinger指针对象实际上还是一个智能指针,sp强引用指针。这种智能指针在第一次引用的时候,会调用onFirstRef方法,进一步实例化内部需要的对象,这个方法调用了mEventQueue的init方法,而这个对象就是线程安全的MessageQueue对象。
SurfaceFlinger中的MessageQueue和Android应用层开发的MessageQueue设计非常相似,只是个别角色做的事情稍微有一点不同。
SurfaceFlinger的MessageQueue机制的角色:
MessageQueue 同样做为消息队列向外暴露操作接口,不像应用层的MessageQueue一样作为Message链表的队列缓存,而是提供了相应的发送消息的接口以及等待消息方法。
native的Looper是整个MessageQueue的核心,以epoll_event为核心,event_fd为辅助构建一套快速的消息回调机制。
native的Handler则是实现handleMessage方法,当Looper回调的时候,将会调用Handler中的handleMessage方法处理回调函数。
MessageQueue init
/frameworks/native/services/surfaceflinger/Scheduler/MessageQueue.cpp
voidMessageQueue::init(constsp<SurfaceFlinger>&flinger) {
mFlinger=flinger;
mLooper=newLooper(true);
mHandler=newHandler(*this);
}
该init方法中实例化了Looper和Handle。
void MessageQueue::Handler::handleMessage(const Message& message) {
switch (message.what) {
case INVALIDATE:
mEventMask.fetch_and(~eventMaskInvalidate);
mQueue.mFlinger->onMessageReceived(message.what, mVsyncId, mExpectedVSyncTime);
break;
case REFRESH:
mEventMask.fetch_and(~eventMaskRefresh);
mQueue.mFlinger->onMessageReceived(message.what, mVsyncId, mExpectedVSyncTime);
break;
}
}
在上面的回调函数,可以看到注册了两种不同的刷新监听,一个是invalidate刷新,一个是refresh刷新。它们最后都会回调到SurfaceFlinger中的onMessageReceived中,换句话说,每当我们需要图元刷新的时候,就会通过mEventQueue的post方法,回调到SurfaceFlinger的主线程进行合成刷新。
以上就是SurfaceFlinger进程初始化的过程,中间提到了一些比较重要的类,接下来会通过几个章节对SurfaceFlinger进程中比较核心的逻辑进行代码讲解。
第1章 Vsync研究
第2章 BufferQueue研究
第3章 SurfaceFlinger动画研究
第4章 SurfaceFlinger主流程研究(分析handleMessage方法的逻辑)
第5章 HWC研究
第6章 Android显示流程研究
第7章 Skia库研究
第8章 截图/录屏流程研究
关于SurfaceFlinger的两篇文章都在《努比亚技术团队》简书中的账号发表过,这两篇是本人发表的,由于努比亚技术团队后续的文章不再更新,关于SurfaceFlinger模块的后续文章研究会在本人的博客下持续更新。