SurfaceFlinger启动流程

QuibblerQuibbler 2022-04-20 约 29 分钟 2975 次阅读

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分析文档

        

相关推荐

精选
ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager
Android

ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager

ViewPager1、ViewPagerandroidx.viewpager.widget.ViewPager,Android中使用非常广泛的控件,可以说是APP必备:首次打开引导页、页面Banner广告等。常用方法:setAdapter() 设置适配器setOffscreenPageLimit() 设置缓存的页面个数,默认是 1setCurrentItem() 跳转到特定的页面setOnPage

1.1k
获取Android内置WebView内核版本
Android

获取Android内置WebView内核版本

获取Android内置WebView内核版本竟然能遇到这样奇葩的事情,网页用的技术过于新颖,以至于只支持高版本Chromium内核的,低版本安卓系统中内置的内核版本较低,无法加载前端页面。1、设置查看在系统设置里 > 应用 > 应用管理 > 显示系统应用,查看WebView组件:2、页面查看通过WebView发起的网络请求,都会带上浏览器的UA,通常页面都可以通过UA判断浏览器的内核版本。这里有两

1.1w
Android 14适配总结
Android

Android 14适配总结

Android 14适配总结毕业工作至今已经适配了三个Android大版本,从Android 11到Android 12、再到Android 13。2023年,Google即将推出的Android 14,上半年已经开始第一批适配。现在,第四个Android版本已经适配完,总结记录一下。1、Android 14计划Google一般会在2月份对外发布预告,同时放出开发者预览版。“拉通”各大平台、厂商以

1.1w