Android UI硬件加速环境初始化过程分析

本文深入探讨了Android应用程序UI硬件加速环境的初始化过程,包括如何创建Render Thread、如何将窗口绑定到Render Thread以及涉及到的关键组件如CanvasContext、OpenGL渲染上下文的创建。在Android 5.0后,Render Thread独立于主线程,通过RenderProxy发送drawFrame命令。初始化过程中,系统会判断是否启用硬件加速,考虑设备支持和内存开销等因素。同时分析了Render Thread的运行模型,包括其消息循环、Vsync信号处理和任务调度机制。
摘要由CSDN通过智能技术生成

在Android应用程序中,我们是通过Canvas API来绘制UI元素的。在硬件加速渲染环境中,这些Canvas API调用最终会转化为Open GL API调用(转化过程对应用程序来说是透明的)。由于Open GL API调用要求发生在Open GL环境中,因此在每当有新的Activity窗口启动时,系统都会为其初始化好Open GL环境。

Open GL环境也称为Open GL渲染上下文。一个Open GL渲染上下文只能与一个线程关联。在一个Open GL渲染上下文创建的Open GL对象一般来说只能在关联的Open GL线程中操作。这样就可以避免发生多线程并发访问发生的冲突问题。这与大多数的UI架构限制UI操作只能发生在UI线程的原理是差不多的。

在Android 5.0之前,Android应用程序的主线程同时也是一个Open GL线程。但是从Android 5.0之后,Android应用程序的Open GL线程就独立出来了,称为Render Thread:

在这里插入图片描述
Render Thread有一个Task Queue,Main Thread通过一个代理对象Render Proxy向这个Task Queue发送一个drawFrame命令,从而驱使Render Thread执行一次渲染操作。因此,Android应用程序UI硬件加速渲染环境的初始化过程任务之一就是要创建一个Render Thread。

一个Android应用程序可能存在多个Activity组件。在Android系统中,每一个Activity组件都是一个独立渲染的窗口。由于一个Android应用程序只有一个Render Thread,因此当Main Thread向Render Thread发出渲染命令时,Render Thread要知道当前要渲染的窗口是什么。从这个角度看,Android应用程序UI硬件加速渲染环境的初始化过程任务之二就是要告诉Render Thread当前要渲染的窗口是什么。

一旦Render Thread知道了当前要渲染的窗口,它就将可以将该窗口绑定到Open GL渲染上下文中去,从而使得后面的渲染操作都是针对被绑定的窗口的:

在这里插入图片描述
Java层的Activity窗口到了Open GL这一层,被抽象为一个ANativeWindow。将它绑定到Open GL渲染上下文之后,就可以通过eglSwapBuffer函数向SurfaceFlinger服务Dequeue和Queue Graphic Buffer。其中,Dequeue Graphic Buffer是为了在上面进行绘制UI,而Queue Graphic Buffer是为了将绘制好的UI交给Surface Flinger合成和显示。

接下来,我们就结合源代码分析Android应用程序UI硬件加速渲染环境的初始化过程,主要的关注点就是创建Render Thread的过程和绑定窗口到Render Thread的过程。

Activity组件在创建的过程中,也就是在其生命周期函数onCreate的调用过程中,一般会通过调用另外一个成员函数setContentView创建和初始化关联的窗口视图,最后通过调用ViewRoot类的成员函数setView完成这一过程。上述文章分析的源码是Android 2.3版本的。到了Android 4.0之后,ViewRoot类的名字改成了ViewRootImpl,它们的作用仍然一样的。

Android应用程序UI硬件加速渲染环境的初始化过程是在ViewRootImpl类的成员函数setView开始,如下所示:

public final class ViewRootImpl implements ViewParent,  
        View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
     
    ......  
  
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
     
        synchronized (this) {
     
            if (mView == null) {
     
                mView = view;  
                ......  
  
                if (view instanceof RootViewSurfaceTaker) {
     
                    mSurfaceHolderCallback =  
                            ((RootViewSurfaceTaker)view).willYouTakeTheSurface();  
                    if (mSurfaceHolderCallback != null) {
     
                        mSurfaceHolder = new TakenSurfaceHolder();  
                        mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);  
                    }  
                }  
  
                ......  
  
                // If the application owns the surface, don't enable hardware acceleration  
                if (mSurfaceHolder == null) {
     
                    enableHardwareAcceleration(attrs);  
                }  
  
                ......  
            }  
        }  
    }  
  
    ......  
} 

参数view描述的是当前正在创建的Activity窗口的顶级视图。如果它实现了RootViewSurfaceTaker接口,并且通过该接口的成员函数willYouTakeTheSurface提供了一个SurfaceHolder.Callback2接口,那么就表明应用程序想自己接管对窗口的一切渲染操作。这样创建出来的Activity窗口就类似于一个SurfaceView一样,完全由应用程序自己来控制它的渲染。

基本上我们是不会将一个Activity窗口当作一个SurfaceView来使用的,因此在ViewRootImpl类的成员变量mSurfaceHolder将保持为null值,这样就会导致ViewRootImpl类的成员函数enableHardwareAcceleration被调用为判断是否需要为当前创建的Activity窗口启用硬件加速渲染。

ViewRootImpl类的成员函数enableHardwareAcceleration的实现如下所示:

public final class ViewRootImpl implements ViewParent,  
        View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
     
    ......  
  
    private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
     
        mAttachInfo.mHardwareAccelerated = false;  
        mAttachInfo.mHardwareAccelerationRequested = false;  
  
        ......  
  
        // Try to enable hardware acceleration if requested  
        final boolean hardwareAccelerated =  
                (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;  
  
        if (hardwareAccelerated) {
     
            if (!HardwareRenderer.isAvailable()) {
     
                return;  
            }  
  
            // Persistent processes (including the system) should not do  
            // accelerated rendering on low-end devices.  In that case,  
            // sRendererDisabled will be set.  In addition, the system process  
            // itself should never do accelerated rendering.  In that case, both  
            // sRendererDisabled and sSystemRendererDisabled are set.  When  
            // sSystemRendererDisabled is set, PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED  
            // can be used by code on the system process to escape that and enable  
            // HW accelerated drawing.  (This is basically for the lock screen.)  
  
            final boolean fakeHwAccelerated = (attrs.privateFlags &  
                    WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED) != 0;  
            final boolean forceHwAccelerated = (attrs.privateFlags &  
                    WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0;  
  
            if (fakeHwAccelerated) {
     
                // This is exclusively for the preview windows the window manager  
                // shows for launching applications, so they will look more like  
                // the app being launched.  
                mAttachInfo.mHardwareAccelerationRequested = true;  
            } else if (!HardwareRenderer.sRendererDisabled  
                    || (HardwareRenderer.sSystemRendererDisabled && forceHwAccelerated)) {
     
                .......  
  
                mAttachInfo.mHardwareRenderer = HardwareRenderer.create(mContext, translucent);  
                if (mAttachInfo.mHardwareRenderer != null) {
     
                    .......  
                    mAttachInfo.mHardwareAccelerated =  
                            mAttachInfo.mHardwareAccelerationRequested = true;  
                }  
            }  
        }  
    }  
  
    ......  
}  

虽然硬件加速渲染是个好东西,但是也不是每一个需要绘制UI的进程都必需的。这样做是考虑到两个因素。第一个因素是并不是所有的Canvas API都可以被GPU支持。如果应用程序使用到了这些不被GPU支持的API,那么就需要禁用硬件加速渲染。第二个因素是支持硬件加速渲染的代价是增加了内存开销。例如,只是硬件加速渲染环境初始化这一操作,就要花掉8M的内存。因此,对于两类进程就不是很适合使用硬件加速渲染。

第一类进程是Persistent进程。Persistent进程是一种常驻进程,它们的优先级别很高,即使在内存紧张的时候也不会被AMS杀掉。对于低内存设备,这类进程是不适合使用硬件加速渲染的。在这种情况下,它们会将HardwareRenderer类的静态成员变量sRendererDisabled设置为true,表明要禁用硬件加速渲染。这里顺便提一下,一个应用程序进程可以在AndroidManifest.xml文件将Application标签的persistent属性设置为true来将自己设置为Persistent进程,不过只有系统级别的应用设置才有效。类似的进程有Phone、Bluetooth和Nfc等应用。

第二类进程是System进程。System进程有很多线程是需要显示UI的。这些UI一般都是比较简单的,并且System进程也像Persistent进程一样,在内存紧张时是无法杀掉的,因此它们完全没有必要通过硬件加速来渲染。于是,System进程就会将HardwareRenderer类的静态成员变量sRendererDisabled和sSystemRendererDisabled都会被设置为true,表示它要禁用硬件加速渲染。

对于System进程,有两种UI需要特殊处理。第一种UI是Starting Window。当一个Activity启动时,如果它的宿主进程还没有创建,那么在等待其宿主进程创建的过程中,System进程就会根据该Activity窗口设置的Theme显示一个Starting Window,也称为Preview Window。由于System进程是禁用了硬件加速渲染的,因此Starting Window是通过软件方式渲染的。但是为了使得Starting Window的渲染更像它对应的Activity窗口,我们将用来描述Starting Window属性的一个AttachInfo对象的成员变量mHardwareAccelerationRequested的值设置为true。这将会使得Starting Window的view_state_accelerated属性设置为true。该属性一旦被设置为true,将会使得Starting Window的另一属性colorBackgroundCacheHint被忽略。属性colorBackgroundCacheHint被忽略之后,Starting Window在绘制的过程中将不会被缓存。使用了硬件加速渲染的Activity窗口在渲染的过程中也是不会被缓存的。这就使得它们的渲染行为保持一致。Starting Window的这一特性是通过将参数attrs指向的一个WindowManager.LayoutParams对象的成员变量privateFlags的位WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED设置为1来描述的。

第二种UI是锁屏界面。锁屏界面是一个例外,它允许使用硬件加速渲染。但是System进程又表明了它要禁用硬件加速渲染,这时候就通过将参数attrs指向的一个WindowManager.LayoutParams对象的成员变量privateFlags的位WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED设置为1来强调锁屏界面不受System进程禁用硬件加速的限制。

除了上面提到的两类进程以及一些特殊的UI,其余的就根据Activity窗口自己是否请求了硬件加速渲染而决定是否要为其开启硬件加速。在默认情况下,Activity窗口是请求硬件加速渲染的,也就是参数attrs指向的一个WindowManager.LayoutParams对象的成员变量flags的位WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED是被设置为1的。不过即便如此,也是要设备本身支持硬件加速渲染才行。判断设备是否设置硬件加速渲染可以通过调用HardwareRenderer类的静态成员函数isAvailable来获得。

最后,如果当前创建的窗口支持硬件加速渲染,那么就会调用HardwareRenderer类的静态成员函数create创建一个HardwareRenderer对象,并且保存在与该窗口关联的一个AttachInfo对象的成员变量的成员变量mHardwareRenderer对象。这个HardwareRenderer对象以后将负责执行窗口硬件加速渲染的相关操作。

HardwareRenderer类的静态成员函数create的实现如下所示:

public abstract class HardwareRenderer {
     
    ......  
  
    static HardwareRenderer create(Context context, boolean translucent) {
     
        HardwareRenderer renderer = null;  
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值