SurfaceFlinger模块研究(一)

前言

之前有写过一篇文章对卡顿情况进行分析,有兴趣的朋友可以去看看
那么我们从trace对CPU状态进行卡顿分析了,这篇文章我们对显示系统进行一个学习。

启动

读取文件

在Android13版本中,SurfaceFlinger是由Android.bp去启动init.rc文件,然后再解析文件去加载SurfaceFlinger

frameworks/native/services/surfaceflinger/SurfaceFlinger.rc

service surfaceflinger /system/bin/surfaceflinger
    class core animation
    user system
    group graphics drmrpc readproc
    capabilities SYS_NICE
    onrestart restart --only-if-running 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

on property:vendor.debug.sf.restart=1
     restart surfaceflinger

on property:init.svc.zygote=restarting && property:debug.sf.toomanylayers=1
     restart surfaceflinger
     setprop debug.sf.toomanylayers "0"

然后以此来调用main_SurfaceFlinger.cpp文件的main函数
在这里面有这几点需要关注,首先是main函数中的ProcessState::self() 函数的调用

  1. 构建ProcessState全局对象gProcess
  2. 打开binder驱动,建立链接
  3. 在驱动内部创建该进程的binder_proc,binder_thread结构,保存该进程的进程信息和线程信息,并加入驱动的红黑树队列中。
  4. 获取驱动的版本信息
  5. 把该进程最多可同时启动的线程告诉驱动,并保存到改进程的binder_proc结构中
  6. 把设备文件/dev/binder映射到内存中

于此同时,还会把SF的自身调用限制在4线程中并设置SurfaceFlinger进程的优先级

	setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);

   	 set_sched_policy(0, SP_FOREGROUND);

//将大多数SurfaceFlinger线程放入系统后台cpuset防止我们不必要地使用大核心
//在绑定线程池初始化之后执行此操作

    #ifdef MTK_SF_CPU_POLICY
        if (SfCpuPolicyAdapter::isEnabled()
   	    && SfCpuPolicyAdapter::foregroundEnabled()){
  	        //do nothing
        }
        else
    #endif
   	    if (cpusets_enabled()) set_cpuset_policy(0, SP_SYSTEM);

在初始化的时候,会把优先级设置成前台foreground,优先跑在4个小核上,关于这一点可以使用命令

adb shell ‘cat /proc/(pid of surfaceflinger)/cpuset’

进行查看。如果有需求定制,可以在某个场景配置到特定的cpuset中,提高或者降低它的优先级

初始化

	// 实例化SF
    sp<SurfaceFlinger> flinger = surfaceflinger::createSurfaceFlinger();
	// 在客户端连接之前进行初始化
    flinger->init();
   // 将surfaceflinger放入servicemanager
    sp<IServiceManager> sm(defaultServiceManager());
    sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
                   IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
    // 运行surfaceflinger这个线程
    flinger->run();

工厂实例化

聪明的小明肯定注意到了在surfaceflinger文件夹中有这样一个文件,那就是SurfaceFlingerFactory。很明显这就是使用工厂模式去对surfaceflinger进行一个实例化

sp<SurfaceFlinger> createSurfaceFlinger() {
    static DefaultFactory factory;

    return new SurfaceFlinger(factory);
}

通过createSurfaceFlinger()方法创建了一个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信息。

  1. ISurfaceComposer 是Client端对SurfaceFlinger进程的binder接口调用。
  2. ComposerCallback,这个是HWC模块的回调,这个包含了三个很关键的回调函数,onComposerHotplug函数表示显示屏热插拔事件, onComposerHalRefresh函数表示Refresh事件,onComposerHalVsync表示Vsync信号事件。

在这些函数调用结束了之后,我们继续分析SurfaceFlinger的构造函数。在构造函数里,初始化了很多的全局变量,虽然我们可以在开发者模式中进行更改,但他们会影响代码的执行流程,如果不熟悉的话得先熟悉熟悉再进行修改哦。

初始化skia引擎

//当缓存大小被严格调整为单个显示时,发送maxFrameBufferAcquiredBuffers
auto builder = 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);
    if (auto type = chooseRenderEngineTypeViaSysProp()) {
        builder.setRenderEngineType(type.value());
    }
    mCompositionEngine->setRenderEngine(renderengine::RenderEngine::create(builder.build()));

这里就是SurfaceFlinger初始化的第一段代码,可以看到是对renderengine进行初始化,并且设置一些参数。mCompositionEngine,也就是layer的Client合成引擎。这个类比较重要,Client也就是GPU合成。目前layer的合成方式有两种,一种是GPU合成,另外一种是HWC合成,也就是有些厂商所说的device合成。HWC合成一般用于游戏方面,性能会更加优异。

构造Vsync

    // 处理任何初始热插拔和由此产生的显示更改
    processDisplayHotplugEventsLocked();

在init方法中,重点看这个函数中调用了initScheduler方法,从字面意义上来看就是初始化调度器。

// 开始线程
	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);

注意,Vsync是整个SurfaceFlinger最重要的组成部分,也是最核心的合成流程。整个SurfaceFlinger的合成节奏都是跟着Vsync信号走的,也就是说Vsync就像一个节拍器,控制着整个绘制帧流程的节拍。太快或者太慢都会导致屏幕显示异常,一般表现为画面卡顿,不流畅。

注入

SurfaceFlinger模块提供很多binder接口,在服务端的onTransact函数会根据Client端传递的code做不同的代码处理

        case 1034: {
            auto future = mScheduler->schedule([&] {
                switch (n = data.readInt32()) {
                    case 0:
                    case 1:
                        FTL_FAKE_GUARD(mStateLock,
                                       enableRefreshRateOverlay(static_cast<bool>(n)));
                        break;
                    default: {
                        reply->writeBool(
                                FTL_FAKE_GUARD(mStateLock, isRefreshRateOverlayEnabled()));
                    }
                }
            });

            future.wait();
            return NO_ERROR;
        }

分析这一段,我们先不看这一段代码内部是在做什么。首先我们看到重点的case 1034,这明显是发送了一个信号去进行这一段逻辑代码的调用。那是从哪里发送的这个1034呢?我们在代码中进行检索发现在这里
在一级目录使用find . -iname “*.java” | xargs grep “1034” 命令

packages/app/Settings/src/com/android/settings/development/ShowRefreshRatePreferenceController.java

    @VisibleForTesting
    static final int SURFACE_FLINGER_CODE = 1034;
	
	......

    @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
        }
    }

    @VisibleForTesting
    void writeShowRefreshRateSetting(boolean isEnabled) {
        try {
            if (mSurfaceFlinger != null) {
                final Parcel data = Parcel.obtain();
                data.writeInterfaceToken(SURFACE_COMPOSER_INTERFACE_KEY);
                final int showRefreshRate = isEnabled ? SETTING_VALUE_ON : SETTING_VALUE_OFF;
                data.writeInt(showRefreshRate);
                mSurfaceFlinger.transact(SURFACE_FLINGER_CODE, data,
                        null /* reply */, 0 /* flags */);
                data.recycle();
            }
        } catch (RemoteException ex) {
            // intentional no-op
        }
        updateShowRefreshRateSetting();
    }

从上文可以看到,在刷新率配置菜单中去进行对应函数的调用,settings这个app对SurfaceFlinger进行了binder通信。

启动

void SurfaceFlinger::run() {
    mScheduler->run();
}
void SurfaceFlinger::onFirstRef() {
    mEventQueue->init(this);
}

SurfaceFlinger中的MessageQueue和Android应用层开发的MessageQueue设计非常相似,只是个别角色做的事情稍微有一点不同。

SurfaceFlinger的MessageQueue机制的角色:

  1. MessageQueue 同样做为消息队列向外暴露接口,不像应用层的MessageQueue一样作为Message链表的队列缓存,而是提供了相应的发送消息的接口以及等待消息方法。
  2. native的Looper是整个MessageQueue的核心,以epoll_event为核心,event_fd为辅助构建一套快速的消息回调机制。
  3. native的Handler则是实现handleMessage方法,当Looper回调的时候,将会调用Handler中的handleMessage方法处理回调函数。

MessageQueue init

/frameworks/native/services/surfaceflinger/Scheduler/MessageQueue.cpp

void MessageQueue::init(const sp<SurfaceFlinger>& flinger) {
    mFlinger = flinger;
    mLooper = new Looper(true);
    mHandler = new Handler(*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的主线程进行合成刷新。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值