背景

  • Platform: RK3399
  • OS: Android7.1.2
  • Kernel: v4.4.103

问题及原因分析

项目中,我们使用Presentation开发了双屏异显功能。

不稳定问题

  • 在测试中,发现开机上电HDMI有时候有显示,有时候又没有,有时候甚至会一闪一闪的
    后面发现是硬件HPD脚不稳定,导致HDMI显示时好时坏。HPD为高时,主控才会通过DDC去读EDID。

    异显内容覆盖问题

  • 要显示在HDMI上的异显内容,覆盖显示在了本地的MIPI屏上,非必现。
    代码中,我们先调用了DisplayManagergetDisplays()获取屏幕的数量,只有2个才会调用Presentation去呈现异显内容。但因为上面的原因导致屏幕数量获取错误,从而出现了这个问题。
    后面我们改用使用广播监听的方式去检测HDMI的热插拔状态,而且硬件也修改,但获取的屏幕数量还是不对,
    最后我们使用DisplayManager.DisplayListeneronDisplayAddedonDisplayRemoved来监听屏幕的变化,监听到变化之后再调用getDisplays()方法来获取准确的屏幕信息,包括数量、Name等。使用广播的方式去监听热插拔然后马上去获取屏幕数量,可能这个时候HDMI还没有ready。

扩展

驱动代码

主要驱动代码:

  • dw-hdmi.c: HDMI驱动,包括内部I2C接口实现
  • drm_edid.c: edid相关
  • dw_hdmi-rockchip.c: drm框架部分
    插拔是否成功可以在check_hdmi_irq()@dw-hdmi.c中打印log

HDMI热插拔状态检测

比较常用的广播监听

注册一个动态广播来获取HDMI接口的插拔,它的Action的name为 “android.intent.action.HDMI_PLUGGED”,具体的代码如下:

private static BroadcastReceiver mReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent receivedIt) {
        String action = receivedIt.getAction();
        if (action.equals("android.intent.action.HDMI_PLUGGED")) {
            boolean state = receivedIt.getBooleanExtra("state", false);
            if (state) {
                isHdmiConnect = true;
            } else {
                isHdmiConnect = false;
            }
        }
    }
};

直接获取状态:

通过直接读取:/sys/devices/virtual/switch/hdmi/state

private static boolean isHdmiSwitchSet() {
    // The file '/sys/devices/virtual/switch/hdmi/state' holds an int -- if it's 1 then an HDMI device is connected.
    // An alternative file to check is '/sys/class/switch/hdmi/state' which exists instead on certain devices.
    File switchFile = new File("/sys/devices/virtual/switch/hdmi/state");
    if (!switchFile.exists()) {
        switchFile = new File("/sys/class/switch/hdmi/state");
    }
    try {
        Scanner switchFileScanner = new Scanner(switchFile);
        int switchValue = switchFileScanner.nextInt();
        switchFileScanner.close();
        return switchValue > 0;
    } catch (Exception e) {
        return false;
    }
}

但不能频繁操作

调试相关

/sys/class/drm/card0-HDMI-A-1

  • 设置drm的调试log等级:
    sys结点位置: /sys/module/drm/parameters/debug
    debug:Enable debug output, where each bit enables a debug category.
    Bit 0 (0x01) will enable CORE messages (drm core code)
    Bit 1 (0x02) will enable DRIVER messages (drm controller code)
    Bit 2 (0x04) will enable KMS messages (modesetting code)
    Bit 3 (0x08) will enable PRIME messages (prime code)
    Bit 4 (0x10) will enable ATOMIC messages (atomic code)
    Bit 5 (0x20) will enable VBL messages (vblank code) (int)
    示例: echo 0x0c > /sys/module/drm/parameters/debug
    打开了KMS, PRIME这些的打印, kernel驱动中使用DRM_DEBUG_KMS和
    DRM_DEBUG_PRIME打印的信息都可以打印出来
    一般设置为如下值:
    echo 0x1f > /sys/module/drm/parameters/debug
  • 查看EDID有没有识别
    dmesg | grep drm
  • 查看HDMI的状态
    cat /d/dw-hdmi/status

参考

  1. https://www.cnblogs.com/fuccc/p/7676813.html
  2. 关于DisplayManager的Android官方文档
  3. https://blog.csdn.net/zhuyong006/article/details/81709520