Android HDMI( 三)

姚善
2023-12-01

HDMI框架层控制部分别在两个部分:

frameworks/base/core/java/android/hardware/hdmi

frameworks/base/services/core/java/com/android/server/hdmi

 

如果平台是MTK的,

有会一个frameworks/base/services/core/java/com/mediatek/hdmi/MtkHdmiManagerService.java 类,此类有详细的执行操作,此文不做多的解释,

HDMI 首先在PhoneWindowManager中初始化状态

    void initializeHdmiState() {
        boolean plugged = false;
        // watch for HDMI plug messages if the hdmi switch exists
        if (new File("/sys/devices/virtual/switch/hdmi/state").exists()) {
            mHDMIObserver.startObserving("DEVPATH=/devices/virtual/switch/hdmi");

            final String filename = "/sys/class/switch/hdmi/state";
            FileReader reader = null;
            try {
                reader = new FileReader(filename);
                char[] buf = new char[15];
                int n = reader.read(buf);
                if (n > 1) {
                    plugged = 0 != Integer.parseInt(new String(buf, 0, n-1));
                }
            } catch (IOException ex) {
                Slog.w(TAG, "Couldn't read hdmi state from " + filename + ": " + ex);
            } catch (NumberFormatException ex) {
                Slog.w(TAG, "Couldn't read hdmi state from " + filename + ": " + ex);
            } finally {
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (IOException ex) {
                    }
                }
            }
        }
        // This dance forces the code in setHdmiPlugged to run.
        // Always do this so the sticky intent is stuck (to false) if there is no hdmi.
        mHdmiPlugged = !plugged;
        setHdmiPlugged(!mHdmiPlugged);
    }

就是去读state文件,如果连接了电视机则其值为:1,未连接则其值为:0

另外下面代码处是监听HDMI状态值的变化

    private UEventObserver mHDMIObserver = new UEventObserver() {
        @Override
        public void onUEvent(UEventObserver.UEvent event) {
            setHdmiPlugged("1".equals(event.get("SWITCH_STATE")));
        }
    };

在PhoneWindowManager.java::setInitialDisplaySize()中

SystemProperties.get("persist.demo.hdmirotation"))  是否允许HDMI连接后,竖屏显示,默认空

 mDemoHdmiRotationLock = SystemProperties.getBoolean("persist.demo.hdmirotationlock", false);  固定屏幕方向默认false,

如果固定HDMI连接屏的显示方向,则会执行下面的执行,

else if (mHdmiPlugged && mDemoHdmiRotationLock) {
                // Ignore sensor when plugged into HDMI when demo HDMI rotation lock enabled.
                // Note that the dock orientation overrides the HDMI orientation.
                preferredRotation = mDemoHdmiRotation;
            } 

mHdmiPlugged 状态为当前机器是否有HDMI连接设备,当前有连接则为true,反之则为false,

HDMIl连接设备对象的信息则是在frameworks\base\services\core\java\com\android\server\display\LocalDisplayAdapter.java中getDisplayDeviceInfoLocked()方法的中的else部分逻辑中生成

                  mInfo.type = Display.TYPE_HDMI;
                    mInfo.flags |= DisplayDeviceInfo.FLAG_PRESENTATION;
                    mInfo.name = getContext().getResources().getString(
                            com.android.internal.R.string.display_manager_hdmi_display_name);
                    mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
                    mInfo.setAssumedDensityForExternalDisplay(phys.width, phys.height);

                    // For demonstration purposes, allow rotation of the external display.
                    // In the future we might allow the user to configure this directly.
                    if ("portrait".equals(SystemProperties.get("persist.demo.hdmirotation"))) {
                        mInfo.rotation = Surface.ROTATION_270;
                    }

                    // For demonstration purposes, allow rotation of the external display
                    // to follow the built-in display.
                    if (SystemProperties.getBoolean("persist.demo.hdmirotates", false)) {
                        mInfo.flags |= DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
                    }

                    if (!res.getBoolean(
                                com.android.internal.R.bool.config_localDisplaysMirrorContent)) {
                        mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY;
                    }

另外再看看此类的registerLocked方法

    @Override
    public void registerLocked() {
        super.registerLocked();

        mHotplugReceiver = new HotplugDisplayEventReceiver(getHandler().getLooper());

        for (int builtInDisplayId : BUILT_IN_DISPLAY_IDS_TO_SCAN) {
            tryConnectDisplayLocked(builtInDisplayId);
        }
    }

BUILD_IN 跟HDMI,built_in可以理解成默认的显示屏,比如手机中默认的MIPI屏,而HDMI则是扩展屏(如电视机),目前在手机上集成HDMI接口的貌似不多,但是usb type c流行后,通过type c来扩展屏幕可能不少,这可能会是一个新的手机定制需求。

    private static final int[] BUILT_IN_DISPLAY_IDS_TO_SCAN = new int[] {
            SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN,
            SurfaceControl.BUILT_IN_DISPLAY_ID_HDMI,
    };

DMS中有很多类型的的DisplayAdapter

LocalDisplayAdapter是针对本地已经存在的物理显示屏设备(即HDMI显示)。
WifiDisplayAdapter针对WiFi Display
OverlayDisplayAdapter (这个悬浮显示,在设置-开发者选项-悬浮显示)
VirtualDisplayAdapter 显示一个虚拟屏幕,该功能可以在开发者选项中开启,可以去研究下这个,

DisplayManagerService.java中DMS服务启动之时onStart函数会被调用,这个函数中会外发一个MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER的消息。

    @Override
    public void onStart() {
        // We need to pre-load the persistent data store so it's ready before the default display
        // adapter is up so that we have it's configuration. We could load it lazily, but since
        // we're going to have to read it in eventually we may as well do it here rather than after
        // we've waited for the diplay to register itself with us.
        mPersistentDataStore.loadIfNeeded();
        mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER);

        publishBinderService(Context.DISPLAY_SERVICE, new BinderService(),
                true /*allowIsolated*/);
        publishLocalService(DisplayManagerInternal.class, new LocalService());
        publishLocalService(DisplayTransformManager.class, new DisplayTransformManager());
    }
    private void registerDefaultDisplayAdapter() {
        // Register default display adapter.
        synchronized (mSyncRoot) {
            registerDisplayAdapterLocked(new LocalDisplayAdapter(//构建一个LocalDisplayAdapter
                    mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
        }
    }

 其它文献:

android graphic(12)—display上层相关概念、关系

Android Display 系统分析

Android Display的初始化

如何获取显示器的EDID信息

Andrdoid6.0 DisplayManagerService

 类似资料: