从系统启动LOG开始分析驱动加载流程:
SurfaceFlinger服务启动过程会创建RenderEngine,在异步线程中创建SkiaGLRenderEngine,创建第一步会调用eglGetDisplay,这时调用到libEGL.so,EGL会判断是否初始化,如果未初始化就会去可能的路径中去加载OpenGLes的驱动库,具体执行的方法就是
Loader::attempt_to_load_system_driver
这个方法会执行三次,代表了优先级。
1.通过读取环境属性去获得libGLES的后缀名,组装后在system/lib或者vendor/lib/egl目录下查找。
static const char*HAL_SUBNAME_KEY_PROPERTIES[3]= {
PERSIST_DRIVER_SUFFIX_PROPERTY,
};
2.如果加载不到,则尝试不加后缀名的库,例如
libGLES.so,libEGL.so, libGLESv1_CM.so,libGLESv2.so
3.再找不到就任意匹配关键字,只要包含GLES的就可以。
只要找到了库,就会通过Loader::initialize_api去加载函数符号,第一个加载的是eglGetProcAddress,然后通过"egl_entries.in"中描述的函数符号字符串列表,通过dlsym方法直接加载,如果加载不到即符号隐藏了,就通过调用eglGetProcAddress来加载这个函数符号。
再加载GLESv1_CM的符号,最后加载GLESv2的符号。
这里加载V1符号时,会将V1中的符号和整个gl符号作对比,根据V1在GL符号列表中的占位顺序去加载。
任意一个使用OpenGLes的进程都会执行加载符号这一过程,所以一般情况下,我们在真正去使用API绘制之前需要将一些warm up的代码写在初始化的地方,这样绘制时就不会有启动耗时。
所有加载库的信息都放在egl_connection_t结构体中,声明对象是一个全局变量egl_connection_t gEGLImpl,后面的所有调用都会从它的platform中实现的函数进入,最终调用到egl中的符号,这些符号来自vendor的驱动库实现。
Platform的函数列表加载是在egl_connection_t构造时即执行的。使用platform作为入口的原因是它支持加载多个backend,比如angle,且优先使用angle。