Cuttlefish Android多屏显示

Android多屏

主要介绍cuttlefish Android环境中如何实现多屏和Android多屏一些介绍

1. 启动Android多屏

  • 在cuttlefish模拟环境下启动3屏幕
HOME=$PWD ./bin/launch_cvd -daemon 
-display0=width=1080,height=600,dpi=120 
-display1=width=400,height=600,dpi=120 
-display2=width=400,height=600,dpi=120 

在这里插入图片描述

2. Dispaly&Layers

  • display和ayers
    在这里插入图片描述

         Android多屏方案中:Drm驱动获取系统物理显示设备连接信息(如外接LVDS,HDMI等多个物理屏),hwcomposer向DRM获取显示信息并初始化
     多个Dispaly,向SurfaceFlinger上报多个displayID,SurfaceFlinger根据Layer当中的layerStack成员,获知需要将该Layer绘制到具体哪一个
     Display当中, 维护多displayID的input设备信息以及交互流程,hwc定期将layers合成到指定displayID并分别送至不同DisplayDevice显示。
    
  • dumpsys SurfaceFlinger

1.  从SF角度查看Display/Layers信息:3个Display,每个Display下有多个Layer,如Display xx7201坐标(0,0)开始有400*467400*600两个叠加Layer
2.  Layer合成方式:
      都是DEVICE,意为HWC进行Layer合成
3.  查看方式:
      dumpsys SurfaceFlinger --display-id 查看持的display信息

在这里插入图片描述

  • dumpsys display
4.  从HWC来看Display信息:
      有4个Display,id分别为0234
5.  Dispaly描述:
      Display 0为Built-in Screen,就是Android主屏
      Display 2为HDMI Screen
      Display 3为HDMI Screen,就是Android第三屏
      Display 4为Cluster-App-VD
6.  为何SF看3个Dispaly,HWC来看4个Dispaly?
      Display 2和Display 4叠加到一起显示到SF Display xx7201,也就是Android副屏

在这里插入图片描述

  • screencap
7.  对指定dispalyID进行截屏
      如截屏HWC display 4
      screencap -d 4 -p /data/tmp/display4.png

在这里插入图片描述

  • Am
 -  am start:将app启动到指定屏幕,重启
      #参数--display指定屏幕, display 0,表示第一块屏幕; display 1,表示第2块屏幕。
      #参数--user可以启动指定的用户,在多用户下有效,系统默认是--user 0 
      #如在display 2上启动百度网页
      am start -a android.intent.action.VIEW -d http://www.baidu.com --display 2 

在这里插入图片描述

 -  am display move-stack:将已启动app移动到另一屏,不重启
      #display move-stack <STACK_ID> <DISPLAY_ID> 
      #将<STACK_ID>从当前显示移动到<DISPLAY_ID>
      am stack list
      #如将maps移动到display 3
      am display move-stack 1000039 3 

在这里插入图片描述

  • 查找包名
 -  查找所有包名,用于am启动MainActivity
       dumpsys package | grep MainActivity
 -  查找所有包名
       pm list package
  • 虚拟屏
1.  增加一个虚拟屏,非物理屏:如下图中间主屏中所示
    开发者模式-> Simulate secondary displays

在这里插入图片描述

1.  从sf角度查看屏幕信息为虚拟屏
dumpsys SurfaceFlinger | grep DisplayDevice

在这里插入图片描述

3.多屏实现

在这里插入图片描述

如上图为cuttlefish Android基于drmvirgl的图形栈,以3屏启动为例:
1.  用户在launch_cvd时通过-display=传入3屏启动参数
2.  launch_cvd将参数以--gpu-display形式传递给crosvm,进而拉起Android虚拟机
3.  Android Drm初始化时,Virtio-gpu驱动向crosvm查询scanout,crosvm根据-display数目返回3个scanout给virtio-gpu驱动,
    virtio-gpu驱动为每一个scanout初始化crtc/connector/decoder/encoder
4.  hwcomposer通过libdrm查询到3个connector/crtc/decoder/encoder信息,并初始化3个display
  • cuttlefish日志
1.  Crosvm. launcher.log启动参数中向crosvm传递3个屏参数
--gpu=2D
--gpu-display=width=1080,height=600
--gpu-display=width=400,height=600
--gpu-display=width=400,height=600 
2.  Drm. Kernel.log内核日志:启动3屏scanout为3,启动1屏scanout为1
[drm] number of scanouts: 3
#logcat日志:3个display状态开启
VIRTUAL_DEVICE_DISPLAY_POWER_MODE_CHANGED display=0 mode=On
VIRTUAL_DEVICE_DISPLAY_POWER_MODE_CHANGED display=2 mode=On
VIRTUAL_DEVICE_DISPLAY_POWER_MODE_CHANGED display=1 mode=On  
  • Crosvm
# mod.rs::get_config(). 向virtio-gpu前端返回scanouts数目,个数由launch_cvd入参决定
fn get_config(&self) -> virtio_gpu_config {
        let mut events_read = 0;
        if self.config_event {
            events_read |= VIRTIO_GPU_EVENT_DISPLAY;
        }
        virtio_gpu_config {
            events_read: Le32::from(events_read),
            events_clear: Le32::from(0),
            num_scanouts: Le32::from(self.display_params.len() as u32), //scanouts个数由入参决定
            num_capsets: Le32::from(num_capsets),
        }
} 
  • virtio-gpu驱动
#virtio_gpu初始化. 从crosvm前端获取3个scanouts并初始化3套crtc/decoder/encoder/connector
virtio_gpu_probe
    virtio_gpu_init //模块初始化
        virtio_gpu_init_vq //初始化ctrlq,cursorq,收只有RESP,没有收的CMD
        virtio_has_feature //检测设备支持特性
        //日志打印:[drm]features: +virgl -edid +resource_blob +host_visible
        //从crosvm读取num_scanouts配置,一个scanout可认为一个物理屏
        virtio_cread_le(vgdev->vdev, struct virtio_gpu_config, num_scanouts, &num_scanouts); 
        virtio_gpu_modeset_init //mode初始化
            drmm_mode_config_init //mode_configuration结构初始化
            vgdev->ddev->mode_config.funcs //设置mode_config回调
            vgdev->ddev->mode_config.helper_private
            vgdev_output_init //对每一个scanout进行初始化,包含plane,crtc,connector,encoder
                virtio_gpu_plane_init
                drm_crtc_init_with_plane //为Atomic Mode Setting设置回调
                drm_connector_init  //Kernel Mode Setting设置回调
                drm_simple_encoder_init //简单初始化encoder
                drm_connector_attach_encoder //connector绑定到crtc
                drm_connector_register
        virtio_gpu_cmd_get_display_info //获取width/height/x/y
            VIRTIO_GPU_GET_DISPLAY_INFO
2屏启动时,scanout为2  capset为2

在这里插入图片描述

1屏启动时,scanout为1  capset为2

在这里插入图片描述

  • drm_hwcomposer
HwcLoader::load #HAL service,composer@2.4-service
HwcLoader::createHalWithAdapter 
HwcLoader::openDeviceWithAdapter #dlopen打开HAL so
DrmHwcTwo::HookDevOpen #HAL so,创建DrmHwcTwo对象
    DrmHwcTwo::Init #drm-hwc初始化
        ResourceManager::Init #打开设备节点,热插拔回调
            AddDrmDevice
            DrmDevice::Init  #Drm资源初始化
            drmModeGetResources #从内核获取硬件信息
                #有3个connector,代表3个物理屏
                #目前12 planes
                #主屏:vendor.hwc.drm.primary_display_order设置
                #如果找不到主屏,可用屏第一个为主屏
        DrmHwcTwo::CreateDisplay  #为每个屏创建Display
            HwcDisplay::Init #设置后端
                DrmDisplayCompositor::Init #为每个display初始化composer
                vsync_worker_.Init
        RegisterHotplugHandler #注册hotplug回调
2屏启动时,drm-hwc获取crtc,connector,encoder,display为2,plane为4

在这里插入图片描述

1屏启动时,drm-hwc获取crtc,connector,encoder,display为1,plane为2

在这里插入图片描述

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值