【Android显示系统初探】surface初相识

本文从实践应用角度窥探Android显示系统。通过C++程序获取surface与SurfaceFlinger交互,在应用中操作surface获取内存地址并写入color值实现显示。还使用dumpsys查看SurfaceFlinger信息,解释了状态栏覆盖绘制图层的原因是Z - order值不同。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android显示系统非常复杂,从早期版本演化至今有很大的变化和改进,所以从当前的版本直接去查看会很困难。

初学者看到繁多的概念和类会感到无从下手。

这里我们将从实践应用的方式来展开这一系列,试图对Android的显示系统进行窥探。

 

Android应用通过surface绘图和SurfaceFlinger进行图像数据交互,Java层的surface绘图流程比较繁琐,

这里我们直接通过一个C++程序来得到一个surface来和SurfaceFlinger进行交互,来达到一个直观的效果。


#define LOG_TAG "bindertest"

#include <stdio.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h>
#include <binder/IBinder.h>
#include <binder/Binder.h>
#include <binder/ProcessState.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>

#include <iostream>
#include <iomanip>

#include <unistd.h>

//for ALOGD
#include <log/log.h>

#include <cutils/memory.h>

//test socketpair
#include <sys/types.h>
#include <error.h>
#include <errno.h>

#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <android/native_window.h>


using namespace android;
using namespace std;
//

int main(int argc, char** argv)
{
	//the color is ABGR
	int color = 0xFF0000FF;
//这个用来确定当前屏幕的ARGB显示顺序
	if (argc == 2 && argv[1][0] == '1') color = 0xFFFF0000;
	if (argc == 2 && argv[1][0] == '2') color = 0xFF000000;
	if (argc == 2 && argv[1][0] == '3') color = 0xFF00FF00;
	if (argc == 2 && argv[1][0] == '4') color = 0x00FF00FF;
	if (argc == 2 && argv[1][0] == 'b') color = 0x00000000;
	if (argc == 2 && argv[1][0] == 'a') color = 0x00FF00FF;
		
    // set up the thread-pool
    sp<ProcessState> proc(ProcessState::self());
    ProcessState::self()->startThreadPool();

    // create a client to surfaceflinger
    sp<SurfaceComposerClient> client = new SurfaceComposerClient();
    
    sp<SurfaceControl> surfaceControl = client->createSurface(String8("testDraw"),
            160, 240, PIXEL_FORMAT_RGBA_8888, 0);

    sp<Surface> surface = surfaceControl->getSurface();

    SurfaceComposerClient::openGlobalTransaction();
    surfaceControl->setLayer(100000);
    SurfaceComposerClient::closeGlobalTransaction();

    ANativeWindow_Buffer outBuffer;
    surface->lock(&outBuffer, NULL);
    ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
    android_memset32((uint32_t*)outBuffer.bits, color, bpr*outBuffer.height);
    surface->unlockAndPost();

		cout << "outBuffer.stride = " << outBuffer.stride << ", bytesPerPixel(outBuffer.format) = "
		 << bytesPerPixel(outBuffer.format) << ", outBuffer.height = " << outBuffer.height << endl;

 
    IPCThreadState::self()->joinThreadPool();
    
    return 0;
}

 

Android.mk

LOCAL_PATH := $(call my-dir)

 

#for service

 

include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \

        service.cpp

      

LOCAL_SHARED_LIBRARIES := \

        libbase \

        libutils \

        liblog \

        libbinder \

        libcutils libskia libui libgui

 

 

LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code       

LOCAL_MODULE:= testDraw

 

include $(BUILD_EXECUTABLE)

 

这里通过对surface的操作,在应用中获取到了在SurfaceFlinger中分配的内存地址,

写入color值,在界面上进行了显示

 

    ANativeWindow_Buffer outBuffer;

    surface->lock(&outBuffer, NULL);

    ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);

    android_memset32((uint32_t*)outBuffer.bits, color, bpr*outBuffer.height);

   

 

surface->lock(&outBuffer, NULL);这句话是冰山一角,里面有一系列操作,

这篇的目的是对surface有个初步的概念,混个脸熟,所以在这里并不去深入的分析各处理流程,

 

这个程序的执行结果

在手机上显示160*240的surface

 

使用我们的老朋友dumpsys来和SurfaceFlinger来个心灵对话,可以看到在SurfaceFlinger中生成了相应的Layer

dumpsys SurfaceFlinger

 

+ Layer 0x76b8edd000 (testDraw#0)

  Region transparentRegion (this=0x76b8edd380, count=1)

    [  0,   0,   0,   0]

  Region visibleRegion (this=0x76b8edd010, count=1)

    [  0,   0, 160, 240]

  Region surfaceDamageRegion (this=0x76b8edd088, count=1)

    [  0,   0,   0,   0]

      layerStack=   0, z=   100000, pos=(0,0), size=( 160, 240), crop=(   0,   0,  -1,  -1), finalCrop=(   0,   0,  -1,  -1), isOpaque=0, invalidate=0, dataspace=Default (0), pixelformat=RGBA_8888 alpha=1.000, flags=0x00000000, tr=[1.00, 0.00][0.00, 1.00]

      client=0x76ba1aa2c0

      format= 1, activeBuffer=[ 160x 240: 160,  1], queued-frames=0, mRefreshPending=0

      mSecure=0, mProtectedByApp=0, mFiltering=0, mNeedsFiltering=0 mDestroyCalled=0

            mTexName=8 mCurrentTexture=0

            mCurrentCrop=[0,0,0,0] mCurrentTransform=0

            mAbandoned=0

            - BufferQueue mMaxAcquiredBufferCount=1 mMaxDequeuedBufferCount=2

              mDequeueBufferCannotBlock=0 mAsyncMode=0

              default-size=[160x240] default-format=1 transform-hint=00 frame-counter=1

            FIFO(0):

             this=0x76ba1c9000 (mConsumerName=testDraw#0, mConnectedApi=2, mConsumerUsageBits=2304, mId=19, mPid=8411, producer=[12222:./testDraw], consumer=[8411:/system/bin/surfaceflinger])

            Slots:

             >[00:0x76bd8407a0] state=ACQUIRED 0x76bd840f80 frame=1 [ 160x 240: 160,  1]

 

在上面的图片中,你会发现,状态栏(statusbar)覆盖在我们所绘制的图层上面,为什么呢,

查看下dumpsys中打印的信息就清楚了,

Display 0 HWC layers:

-------------------------------------------------------------------------------

 Layer name

           Z |  Comp Type |   Disp Frame (LTRB) |          Source Crop (LTRB)

-------------------------------------------------------------------------------

 com.google.android.googlequicksearch[...]ps.gsa.searchnow.SearchNowActivity#1

       21005 |     Device |    0    0  720 1280 |    0.0    0.0  720.0 1280.0

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

 InputMethod#0

       22005 |     Device |    0   48  720 1280 |    0.0    0.0  720.0 1232.0

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

 testDraw#0

      100000 |     Device |    0    0  160  240 |    0.0    0.0  160.0  240.0

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

 StatusBar#0

      181000 |     Device |    0    0  720   48 |    0.0    0.0  720.0   48.0

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

 

我们设置的图层Z-order值是100000

surfaceControl->setLayer(100000)

小于StatusBar的181000,所以181000显示在了最上层

 

小结:

这篇文章主要是通过一个浅显的例子来加深我们的理解,即应用通过surface进行绘图,SurfaceFlinger管理应用的图层

<think>好的,我现在需要回答用户关于“Source Crop (LTRB) in HWC layers display debugging meaning and usage”的问题。首先,我需要理解Source Crop (LTRB)在HWC层中的具体含义和用途。根据用户提供的引用内容,特别是引用[1]中的BufferLayer信息,里面提到了Rect mCrop这个成员变量。Rect通常用来表示一个矩形区域,而LTRB可能代表Left, Top, Right, Bottom,即矩形的四个边界值。 接下来,我需要确认Source Crop在HWC(硬件合成器)中的作用。HWC负责将不同的图层合成到显示设备上,而Source Crop可能用于指定从源图层中裁剪出一个子区域进行显示。这在调试显示问题时非常有用,例如当图层内容超出预期范围或需要调整显示区域时,可以通过查看Source Crop的值来确认是否正确设置。 此外,用户提到显示调试信息,因此需要说明在调试过程中如何利用Source Crop参数。比如,开发者可以通过检查这些值来验证是否有意外的裁剪,或者调整裁剪区域以优化显示效果。结合引用[1]中的mCrop,应该是在BufferLayer中存储了裁剪信息,传递给OutputLayer进行合成。 最后,需要确保回答符合用户的要求,结构清晰,使用中文,正确应用LaTeX格式,并在引用处添加标识。同时生成相关问题,帮助用户进一步理解相关概念。</think>### Source Crop (LTRB) 的含义与用途 在显示合成(HWC)中,**Source Crop (LTRB)** 是一个用于定义图层源数据裁剪区域的参数,其名称由 **Left(左)、Top(上)、Right(右)、Bottom(下)** 四个边界值组成。它以矩形(`Rect`)的形式表示,单位通常为像素或坐标系中的比例值(取决于具体实现)。 #### 具体含义: - **作用**:指定从原始图层(如图像、视频或UI元素)中裁剪出一个子区域,仅显示该区域的內容。 - **数据结构**:在Android框架中,`Rect mCrop`(如引用[1]中的`BufferLayer::BufferInfo`)保存了裁剪信息,其值通过LTRB四个参数定义,例如: $$(left=10, top=20, right=200, bottom=300)$$ 表示从原始图层左上角坐标$(10,20)$到右下角坐标$(200,300)$的区域被保留。 #### 调试中的用途: 1. **显示异常排查** 当图层内容显示不完整或位置偏移时,检查`Source Crop`是否错误地裁剪了有效内容。例如,若右边界值过小,可能导致内容右侧被截断。 2. **性能优化** 通过裁剪不需要渲染的区域(如透明边距),减少实际传输到显示器的数据量,降低GPU负载[^1]。 3. **多图层合成验证** 在多层叠加场景中(如视频播放+悬浮控件),通过对比各图层的`Source Crop`与实际显示区域,确认合成逻辑是否正确。 #### 典型应用场景: - **视频播放**:裁剪黑边或特定画面区域。 - **UI适配**:针对不同屏幕比例调整控件显示范围。 - **动态特效**:通过动态修改裁剪区域实现动画效果。 ### 相关问题 1. 如何通过Android系统工具(如`dumpsys SurfaceFlinger`)查看当前图层的`Source Crop`值? 2. `Source Crop`与`Destination Frame`在显示合成中的区别是什么? 3. 在Android图形系统中,如何处理裁剪区域与变换(Transform)的叠加效果? [^1]: 引用[1]中的`BufferLayer::BufferInfo`结构体存储了裁剪信息(`mCrop`),这些信息最终传递给`OutputLayer`用于合成。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值