SurfaceFlinger启动流程

Quibbler 2022-4-20 1102

SurfaceFlinger启动流程


        好久没有看源码,恰好接触到SurfaceFlinger,简单了解一下SurfaceFlinger。SurfaceFlinger是一个系统服务,接受来自多个来源的数据缓冲区,对它们进行合成,然后发送到显示设备进行显示。


        在Zygote进程的启动一文中,了解到:在系统启动时,init进程读取位于/android/platform/system/core/rootdir目录下的init.rc文件,启动所有核心服务。其中,init进程入口是位于/system/core/init目录中的main.cpp

    int main(int argc, char** argv) {
    ...
        if (argc > 1) {
            ...
            if (!strcmp(argv[1], "second_stage")) {
                return SecondStageMain(argc, argv);    //第二阶段
            }
        }
        return FirstStageMain(argc, argv);             //第一阶段
    }

         当启动参数为"second_stage"时,走这里的SecondStageMain(argc, argv)方法,至于哪里传入先不管:

    int SecondStageMain(int argc, char** argv) {
        ...
        property_init();           //初始化属性服务
        ...
        LoadBootScripts(am, sm);   //加载启动脚本
        ..
        return 0;
    }

        再调用LoadBootScripts(am, sm)方法中加载解析前面提到的init.rc文件:

    static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
        Parser parser = CreateParser(action_manager, service_list);
        std::string bootscript = GetProperty("ro.boot.init_rc", "");
        if (bootscript.empty()) {
            parser.ParseConfig("/init.rc");
            if (!parser.ParseConfig("/system/etc/init")) {
                late_import_paths.emplace_back("/system/etc/init");
            }
            if (!parser.ParseConfig("/product/etc/init")) {
                late_import_paths.emplace_back("/product/etc/init");
            }
            if (!parser.ParseConfig("/product_services/etc/init")) {
                late_import_paths.emplace_back("/product_services/etc/init");
            }
            if (!parser.ParseConfig("/odm/etc/init")) {
                late_import_paths.emplace_back("/odm/etc/init");
            }
            if (!parser.ParseConfig("/vendor/etc/init")) {
                late_import_paths.emplace_back("/vendor/etc/init");
            }
        } else {
            parser.ParseConfig(bootscript);
        }
    }

        init.rc是用Android初始化语言(Android Init Language)编写的脚本配置文件,启动了所有核心服务:

    on boot
        # basic network init
        ifup lo
        hostname localhost
        domainname localdomain
        ...
        # Start standard binderized HAL daemons
        class_start hal
        class_start core

        其中就包括在/frameworks/native/services/surfaceflinger目录下的surfaceflinger.rc,而这正是SurfaceFlinger服务:

    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

        通过上面可知,SurfaceFlinger服务由 init 进程创建,之后独立的运行在 SurfaceFlinger进程中。


        SurfaceFlinger对应的可执行文件在/system/bin/surfaceflinger,其源码则位于/frameworks/native/services/surfaceflinger目录中。程序入口是main_surfaceflinger.cpp中的main()方法:

    int main(int, char**) {
        signal(SIGPIPE, SIG_IGN);
        
        //配置线程池:设置binder的线程池,用于设置 当前进程用于hwbinder通信的最大线程数:
        hardware::configureRpcThreadpool(1 /* maxThreads */, false /* callerWillJoin */);
        
        //启动图形分配器服务
        startGraphicsAllocatorService();
        
        // 当 SF 在自己的进程中启动时,将 binder 线程数限制为 4。
        ProcessState::self()->setThreadPoolMaxThreadCount(4);
        
        // Set uclamp.min setting on all threads, maybe an overkill but we want
        // to cover important threads like RenderEngine.
        if (SurfaceFlinger::setSchedAttr(true) != NO_ERROR) {
            ALOGW("Couldn't set uclamp.min: %s\n", strerror(errno));
        }
        // The binder threadpool we start will inherit sched policy and priority
        // of (this) creating thread. We want the binder thread pool to have
        // SCHED_FIFO policy and priority 1 (lowest RT priority)
        // Once the pool is created we reset this thread's priority back to
        // original.
        int newPriority = 0;
        int origPolicy = sched_getscheduler(0);
        struct sched_param origSchedParam;
        int errorInPriorityModification = sched_getparam(0, &origSchedParam);
        if (errorInPriorityModification == 0) {
            int policy = SCHED_FIFO;
            newPriority = sched_get_priority_min(policy);
            struct sched_param param;
            param.sched_priority = newPriority;
            errorInPriorityModification = sched_setscheduler(0, policy, &param);
        }
        
        // 启动线程池
        sp<ProcessState> ps(ProcessState::self());
        ps->startThreadPool();
        // Reset current thread's policy and priority
        if (errorInPriorityModification == 0) {
            errorInPriorityModification = sched_setscheduler(0, origPolicy, &origSchedParam);
        } else {
            ALOGE("Failed to set SurfaceFlinger binder threadpool priority to SCHED_FIFO");
        }
        
        // 创建surfaceflinger实例
        sp<SurfaceFlinger> flinger = surfaceflinger::createSurfaceFlinger();
        // Set the minimum policy of surfaceflinger node to be SCHED_FIFO.
        // So any thread with policy/priority lower than {SCHED_FIFO, 1}, will run
        // at least with SCHED_FIFO policy and priority 1.
        if (errorInPriorityModification == 0) {
            flinger->setMinSchedulerPolicy(SCHED_FIFO, newPriority);
        }
        setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);
        
        ////设置调度策略,SP_FOREGROUND优先级
        set_sched_policy(0, SP_FOREGROUND);
        
        // CPU 策略,限制SF在了小核
        if (cpusets_enabled()) set_cpuset_policy(0, SP_SYSTEM);
        
        // 在客户端可以连接之前初始化
        flinger->init();
        
        // 发布并注册SurfaceFlinger服务
        sp<IServiceManager> sm(defaultServiceManager());
        sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
                       IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
        
        //依赖于SF在上面注册,启动DisplayService
        startDisplayService();
        if (SurfaceFlinger::setSchedFifo(true) != NO_ERROR) {
            ALOGW("Couldn't set to SCHED_FIFO: %s", strerror(errno));
        }
        
        // 在当前这个线程运行SurfaceFlinger
        flinger->run();
        
        return 0;
    }

        从上面的main()方法可以看到,在SurfaceFlinger进程启动时,主要是执行初始化binder线程池、设定进程优先级和cgroup、创建SurfaceFlinger、启动SurfaceFlinger服务并添加到ServiceManager等操作。

        ①初始化binder线程池:调用的configureRpcThreadpool(size_t maxThreads, bool callerWillJoin)方法在/system/libhidl/transport中的HidlTransportSupport.cpp中。

    void configureRpcThreadpool(size_t maxThreads, bool callerWillJoin) {
        // TODO(b/32756130) this should be transport-dependent
        configureBinderRpcThreadpool(maxThreads, callerWillJoin);
    }

        内部调用了HidlBinderSupport.cpp中的:

    void configureBinderRpcThreadpool(size_t maxThreads, bool callerWillJoin) {
        status_t ret = ProcessState::self()->setThreadPoolConfiguration(
            maxThreads, callerWillJoin /*callerJoinsPool*/);
        LOG_ALWAYS_FATAL_IF(ret != OK, "Could not setThreadPoolConfiguration: %d", ret);
        gThreadPoolConfigured = true;
    }

        ②启动线程池ProcessState.cpp/system/libhwbinder目录下。

    sp<ProcessState> ProcessState::self()
    {
        Mutex::Autolock _l(gProcessMutex);
        if (gProcess != nullptr) {
            return gProcess;
        }
        gProcess = new ProcessState(DEFAULT_BINDER_VM_SIZE);
        return gProcess;
    }

        使用DEFAULT_BINDER_VM_SIZE作为默认参数即Binder底层共享内存大小,构造ProcessState实例:

    sp<ProcessState> ProcessState::initWithMmapSize(size_t mmap_size) {
        Mutex::Autolock _l(gProcessMutex);
        if (gProcess != nullptr) {
            LOG_ALWAYS_FATAL_IF(mmap_size != gProcess->getMmapSize(),
                    "ProcessState already initialized with a different mmap size.");
            return gProcess;
        }
        gProcess = new ProcessState(mmap_size);
        return gProcess;
    }

          随后调用startThreadPool()开启线程池:

    void ProcessState::startThreadPool()
    {
        AutoMutex _l(mLock);
        if (!mThreadPoolStarted) {
            mThreadPoolStarted = true;
            if (mSpawnThreadOnStart) {
                spawnPooledThread(true);
            }
        }
    }

        ③创建SurfaceFlinger实例:借助/frameworks/native/services/surfaceflinger里的SurfaceFlingerFactory.cpp工厂构造一个SurfaceFlinger实例。

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

        SurfaceFlinger初始化:/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp中的init()方法,初始化 EGL、创建 HWComposer、初始化非虚拟显示屏、启动 EventThread 线程、启动开机动画。

    // Do not call property_set on main thread which will be blocked by init
    // Use StartPropertySetThread instead.
    void SurfaceFlinger::init() {
        ALOGI(  "SurfaceFlinger's main thread ready to run. "
                "Initializing graphics H/W...");
        ALOGI("Phase offset NS: %" PRId64 "", mPhaseOffsets->getCurrentAppOffset());
        Mutex::Autolock _l(mStateLock);
        // start the EventThread
        mScheduler =
                getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); },
                                             mRefreshRateConfigs);
        auto resyncCallback =
                mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
        mAppConnectionHandle =
                mScheduler->createConnection("app", mPhaseOffsets->getCurrentAppOffset(),
                                             resyncCallback,
                                             impl::EventThread::InterceptVSyncsCallback());
        mSfConnectionHandle = mScheduler->createConnection("sf", mPhaseOffsets->getCurrentSfOffset(),
                                                           resyncCallback, [this](nsecs_t timestamp) {
                                                               mInterceptor->saveVSyncEvent(timestamp);
                                                           });
        ...
        mRefreshRateConfigs.populate(getHwComposer().getConfigs(*display->getId()));
        mRefreshRateStats.setConfigMode(getHwComposer().getActiveConfigIndex(*display->getId()));
        ALOGV("Done initializing");
    }

        SurfaceFlinger运行:SurfaceFlinger.cpp中的run()方法进入主循环。

    void SurfaceFlinger::run() {
        do {
            waitForEvent();
        } while (true);
    }


        之前在绘制性能分析一文中介绍了Systrace,通过Systrace可以判断是否出现掉帧,看的就是SurfaceFlinger部分。推荐阅读 Systrace 基础知识 这篇博客,在Triple Buffer 解读 > 掉帧检测 章节有非常详细的解读。


        对于SurfaceFlinger能了解到这些就行了,主要涉及底层的C++,这部分由专业的图形图像框架团队维护,应用开发者不用往下卷的很深。



相关资料:

        SurfaceFlinger 和 Hardware Composer

        Android 显示系统:SurfaceFlinger详解

        Android图形显示-专题

        Android P 图形显示系统硬件合成

        Android Q SurfaceFlinger合成

        SurfaceFlinger分析文档

        

不忘初心的阿甘
最新回复 (0)
    • 安卓笔记本
      2
        登录 注册 QQ
返回
仅供学习交流,切勿用于商业用途。如有错误欢迎指出:fluent0418@gmail.com