Andrdoid6.0 DisplayManagerService

之前在分析power模块的时候,需要设置背光那个时候分析过DisplayManagerService,但是不够详细、系统。前面在分析WMS旋转屏幕的时候,也涉及到了DisplayManagerService,所以我准备详细分析下。

一、缺省设备

我们先看DisplayManagerService在SystemServer中调用的顺序。先是构造了对象,然后调用了windowManagerAndInputReady函数,这个函数会触发WMS重新刷新UI。然后调用了systemReady函数。

        mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
        ......
        mDisplayManagerService.windowManagerAndInputReady();
        ......
        mDisplayManagerService.systemReady(safeMode, mOnlyCore);        

下面我们就先从DisplayManagerService的构造函数开始分析,构造函数就是初始化了一些变量。

    public DisplayManagerService(Context context) {
        super(context);
        mContext = context;
        mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper());
        mUiHandler = UiThread.getHandler();
        mDisplayAdapterListener = new DisplayAdapterListener();
        mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);

        PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
        mGlobalDisplayBrightness = pm.getDefaultScreenBrightnessSetting();
    }

我们再来看onStart函数,这里publish了BinderService和LocalService,然后发送了MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER消息。

    @Override
    public void onStart() {
        mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER);

        publishBinderService(Context.DISPLAY_SERVICE, new BinderService(),
                true /*allowIsolated*/);
        publishLocalService(DisplayManagerInternal.class, new LocalService());
    }

我们看下这个消息的处理,直接调用了registerDefaultDisplayAdapter函数。

            switch (msg.what) {
                case MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER:
                    registerDefaultDisplayAdapter();
                    break;

我们看下registerDefaultDisplayAdapter函数,直接新建一个LocalDisplayAdapter对象作为参数调用registerDisplayAdapterLocked函数。我们注意mDisplayAdapterListener这个参数。

    private void registerDefaultDisplayAdapter() {
        // Register default display adapter.
        synchronized (mSyncRoot) {
            registerDisplayAdapterLocked(new LocalDisplayAdapter(
                    mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
        }
    }

registerDisplayAdapterLocked函数把上面新建的LocalDisplayAdapter对象放入mDisplayAdapters中,然后调用了LocalDisplayAdapter的registerLocked函数。

    private void registerDisplayAdapterLocked(DisplayAdapter adapter) {
        mDisplayAdapters.add(adapter);
        adapter.registerLocked();
    }

LocalDisplayAdapter的构造函数比较简单就是调用父类的构造函数初始化一些成员变量,我们看下LocalDisplayAdapter的父类DisplayAdapter的构造函数,其中mListener就是上面传入的DisplayAdapterListener回调。

    public DisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
            Context context, Handler handler, Listener listener, String name) {
        mSyncRoot = syncRoot;
        mContext = context;
        mHandler = handler;
        mListener = listener;
        mName = name;
    }

我们再来看下其registerLocked函数,先是新建了一个热插拔的回调。然后遍历了BUILT_IN_DISPLAY_IDS_TO_SCAN调用tryConnectDisplayLocked函数。

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

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

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

BUILT_IN_DISPLAY_IDS_TO_SCAN函数如下:

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

 我们再来看看tryConnectDisplayLocked函数。先会传入builtInDisplayId参数调用SurfaceControl.getBuiltInDisplay函数来获取一个DisplayToken,这个token很关键是识别这个display的唯一性,然后我们看mDevices是否有一个builtInDisplayId的LocalDisplayDevice,没有的话就新建一个LocalDisplayDevice,并且放入mDevices中。然后sendDisplayDeviceEventLocked函数,参数是DISPLAY_DEVICE_EVENT_ADDED通知DisplayManagerService设备增加了。

    private void tryConnectDisplayLocked(int builtInDisplayId) {
        IBinder displayToken = SurfaceControl.getBuiltInDisplay(builtInDisplayId);//获取displayToken
        if (displayToken != null) {
            SurfaceControl.PhysicalDisplayInfo[] configs =
                    SurfaceControl.getDisplayConfigs(displayToken);
            if (configs == null) {
                // There are no valid configs for this device, so we can't use it
                Slog.w(TAG, "No valid configs found for display device " +
                        builtInDisplayId);
                return;
            }
            int activeConfig = SurfaceControl.getActiveConfig(displayToken);
            if (activeConfig < 0) {
                // There is no active config, and for now we don't have the
                // policy to set one.
                Slog.w(TAG, "No active config found for display device " +
                        builtInDisplayId);
                return;
            }
            LocalDisplayDevice device = mDevices.get(builtInDisplayId);
            if (device == null) {//mDevices没有builtInDisplayId对应的LocalDisplayDevice 
                // Display was added.
                device = new LocalDisplayDevice(displayToken, builtInDisplayId,//新建LocalDisplayDevice 
                        configs, activeConfig);
                mDevices.put(builtInDisplayId, device);
                sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);
            } else if (device.updatePhysicalDisplayInfoLocked(configs, activeConfig)) {
                // Display properties changed.
                sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED);
            }
        } else {
            // The display is no longer available. Ignore the attempt to add it.
            // If it was connected but has already been disconnected, we'll get a
            // disconnect event that will remove it from mDevices.
        }
    }

我们来看下sendDisplayDeviceEventLocked函数,就是调用了上面传入的回调

    protected final void sendDisplayDeviceEventLocked(
            final DisplayDevice device, final int event) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                mListener.onDisplayDeviceEvent(device, event);
            }
        });
    }

回调就是DisplayAdapterListener ,我们是DISPLAY_DEVICE_EVENT_ADDED设备增加事件,直接调用handleDisplayDeviceAdded函数。

    private final class DisplayAdapterListener implements DisplayAdapter.Listener {
        @Override
        public void onDisplayDeviceEvent(DisplayDevice device, int event) {
            switch (event) {
                case DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED:
                    handleDisplayDeviceAdded(device);
                    break;

                case DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED:
                    handleDisplayDeviceChanged(device);
                    break;

                case DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED:
                    handleDisplayDeviceRemoved(device);
                    break;
            }
        }

handleDisplayDeviceAdded直接调用了handleDisplayDeviceAddedLocked函数。handleDisplayDeviceAddedLocked函数会将device统一放入DisplayManagerService的mDisplayDevices中,类型是父类的DisplayDevice(这样方便统一管理),然后调用了addLogicalDisplayLocked函数。

    private void handleDisplayDeviceAdded(DisplayDevice device) {
        synchronized (mSyncRoot) {
            handleDisplayDeviceAddedLocked(device);
        }
    }

    private void handleDisplayDeviceAddedLocked(DisplayDevice device) {
        DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
        if (mDisplayDevices.contains(device)) {
            Slog.w(TAG, "Attempted to add already added display device: " + info);
            return;
        }

        Slog.i(TAG, "Display device added: " + info);
        device.mDebugLastLoggedDeviceInfo = info;

        mDisplayDevices.add(device);//将该device统一放入DisplayManagerService的mDisplayDevices中,类型是父类的DisplayDevice
        addLogicalDisplayLocked(device);
        Runnable work = updateDisplayStateLocked(device);
        if (work != null) {
            work.run();
        }
        scheduleTraversalLocked(false);//通知WMS会刷新UI
    }

addLogicalDisplayLocked函数,先调用assignDisplayIdLocked函数分配一个displayId(这个如果是isDefault就是固定id,其他的每次加1),然后新建一个LogicalDisplay并且把它放到mLogicalDisplays中,以displayId作为key。

    private void addLogicalDisplayLocked(DisplayDevice device) {
        DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked();
        boolean isDefault = (deviceInfo.flags
                & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0;
        ......

        final int displayId = assignDisplayIdLocked(isDefault);
        final int layerStack = assignLayerStackLocked(displayId);

        LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);
        display.updateLocked(mDisplayDevices);
        ......

        mLogicalDisplays.put(displayId, display);

        // Wake up waitForDefaultDisplay.
        if (isDefault) {
            mSyncRoot.notifyAll();
        }

        sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
    }

二、WIFIDisplay、虚拟设备等

剩下继续分析DisplayManagerService的systemReady函数

    public void systemReady(boolean safeMode, boolean onlyCore) {
        synchronized (mSyncRoot) {
            mSafeMode = safeMode;
            mOnlyCore = onlyCore;
        }

        mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
    }

看下消息处理是调用了registerAdditionalDisplayAdapters函数

                case MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS:
                    registerAdditionalDisplayAdapters();
                    break;

registerAdditionalDisplayAdapters函数和上面的registerDefaultDisplayAdapter函数类似。这里只是和WIFI、虚拟设备相关。流程类似最后都在DisplayManagerService中做管理。

先是新建一个DisplayAdapter 然后放入mDisplayAdapters中,然后在DisplayAdapter新建一个DisplayDevice。接着再到DisplayManagerService中放入到mDisplayDevices,接着又创建LogicalDisplay (当然这里可能不一样了)。

    private void registerAdditionalDisplayAdapters() {
        synchronized (mSyncRoot) {
            if (shouldRegisterNonEssentialDisplayAdaptersLocked()) {
                registerOverlayDisplayAdapterLocked();
                registerWifiDisplayAdapterLocked();
                registerVirtualDisplayAdapterLocked();
            }
        }
    }

后面的流程那我们就不分析了。但是一些虚拟设备的connect等,都是由应用进程通过DisplayManger类通过binder发起的。DisplayManager是面向应用进程的,我们比如下面这个函数是连接WIFIDisplay的,我们再来看下这个mGlobal对象。

    public void connectWifiDisplay(String deviceAddress) {
        mGlobal.connectWifiDisplay(deviceAddress);
    }

mGlobal最终还是通过Binder到DisplayManagerService。

    public DisplayManager(Context context) {
        mContext = context;
        mGlobal = DisplayManagerGlobal.getInstance();
    }
    public static DisplayManagerGlobal getInstance() {
        synchronized (DisplayManagerGlobal.class) {
            if (sInstance == null) {
                IBinder b = ServiceManager.getService(Context.DISPLAY_SERVICE);
                if (b != null) {
                    sInstance = new DisplayManagerGlobal(IDisplayManager.Stub.asInterface(b));
                }
            }
            return sInstance;
        }
    }

而DisplayManagerService的binder对象是放在了mDm成员变量中

    private DisplayManagerGlobal(IDisplayManager dm) {
        mDm = dm;
    }

最后是到DisplayManagerService的connectWifiDisplay中。

    public void connectWifiDisplay(String deviceAddress) {
        if (deviceAddress == null) {
            throw new IllegalArgumentException("deviceAddress must not be null");
        }

        try {
            mDm.connectWifiDisplay(deviceAddress);
        } catch (RemoteException ex) {
            Log.e(TAG, "Failed to connect to Wifi display " + deviceAddress + ".", ex);
        }
    }

DisplayManagerService的connectWifiDisplay函数调用connectWifiDisplayInternal

        @Override // Binder call
        public void connectWifiDisplay(String address) {
            if (address == null) {
                throw new IllegalArgumentException("address must not be null");
            }
            mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
                    "Permission required to connect to a wifi display");

            final long token = Binder.clearCallingIdentity();
            try {
                connectWifiDisplayInternal(address);
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        }

最后是用WIFIDisplay的适配器类调用函数的。

    private void connectWifiDisplayInternal(String address) {
        synchronized (mSyncRoot) {
            if (mWifiDisplayAdapter != null) {
                mWifiDisplayAdapter.requestConnectLocked(address);
            }
        }
    }

三、旋转屏幕

之前的旋转屏幕是调用了performTraversalInTransactionLocked函数

    private void performTraversalInTransactionLocked() {
        // Clear all viewports before configuring displays so that we can keep
        // track of which ones we have configured.
        clearViewportsLocked();

        // Configure each display device.
        final int count = mDisplayDevices.size();
        for (int i = 0; i < count; i++) {
            DisplayDevice device = mDisplayDevices.get(i);
            configureDisplayInTransactionLocked(device);
            device.performTraversalInTransactionLocked();
        }

        // Tell the input system about these new viewports.
        if (mInputManagerInternal != null) {
            mHandler.sendEmptyMessage(MSG_UPDATE_VIEWPORT);
        }
    }

我们主要还是看下configureDisplayInTransactionLocked函数,先还是用DisplayDevice的方法getDisplayDeviceInfoLocked(直接调用的是子类LocalDisplayDevice的getDisplayDeviceInfoLocked)获取DisplayDeviceInfo的信息,然后找到和该DisplayDevice对应的LogicalDisplay,然后调用其configureDisplayInTransactionLocked方法。

    private void configureDisplayInTransactionLocked(DisplayDevice device) {
        final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
        final boolean ownContent = (info.flags & DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY) != 0;

        LogicalDisplay display = findLogicalDisplayForDeviceLocked(device);
        if (!ownContent) {
            if (display != null && !display.hasContentLocked()) {
                // If the display does not have any content of its own, then
                // automatically mirror the default logical display contents.
                display = null;
            }
            if (display == null) {
                display = mLogicalDisplays.get(Display.DEFAULT_DISPLAY);
            }
        }
        ......
        display.configureDisplayInTransactionLocked(device, info.state == Display.STATE_OFF);
        ......
    }

最后在LogicalDisplay的configureDisplayInTransactionLocked方法中还是基本上调用了DisplayDevice的方法,最后真正设置方向是到DisplayDevice的setProjectionInTransactionLocked函数。

    public void configureDisplayInTransactionLocked(DisplayDevice device,
            boolean isBlanked) {
        // Set the layer stack.
        device.setLayerStackInTransactionLocked(isBlanked ? BLANK_LAYER_STACK : mLayerStack);

        // Set the color transform and mode.
        if (device == mPrimaryDisplayDevice) {
            device.requestColorTransformAndModeInTransactionLocked(
                    mRequestedColorTransformId, mRequestedModeId);
        } else {
            device.requestColorTransformAndModeInTransactionLocked(0, 0);  // Revert to default.
        }

        // Only grab the display info now as it may have been changed based on the requests above.
        final DisplayInfo displayInfo = getDisplayInfoLocked();
        final DisplayDeviceInfo displayDeviceInfo = device.getDisplayDeviceInfoLocked();

        // Set the viewport.
        // This is the area of the logical display that we intend to show on the
        // display device.  For now, it is always the full size of the logical display.
        mTempLayerStackRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);

        // Set the orientation.
        // The orientation specifies how the physical coordinate system of the display
        // is rotated when the contents of the logical display are rendered.
        int orientation = Surface.ROTATION_0;
        if ((displayDeviceInfo.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0) {
            orientation = displayInfo.rotation;
        }

        // Apply the physical rotation of the display device itself.
        orientation = (orientation + displayDeviceInfo.rotation) % 4;

        // Set the frame.
        // The frame specifies the rotated physical coordinates into which the viewport
        // is mapped.  We need to take care to preserve the aspect ratio of the viewport.
        // Currently we maximize the area to fill the display, but we could try to be
        // more clever and match resolutions.
        boolean rotated = (orientation == Surface.ROTATION_90
                || orientation == Surface.ROTATION_270);
        int physWidth = rotated ? displayDeviceInfo.height : displayDeviceInfo.width;
        int physHeight = rotated ? displayDeviceInfo.width : displayDeviceInfo.height;

        // Determine whether the width or height is more constrained to be scaled.
        //    physWidth / displayInfo.logicalWidth    => letter box
        // or physHeight / displayInfo.logicalHeight  => pillar box
        //
        // We avoid a division (and possible floating point imprecision) here by
        // multiplying the fractions by the product of their denominators before
        // comparing them.
        int displayRectWidth, displayRectHeight;
        if ((displayInfo.flags & Display.FLAG_SCALING_DISABLED) != 0) {
            displayRectWidth = displayInfo.logicalWidth;
            displayRectHeight = displayInfo.logicalHeight;
        } else if (physWidth * displayInfo.logicalHeight
                < physHeight * displayInfo.logicalWidth) {
            // Letter box.
            displayRectWidth = physWidth;
            displayRectHeight = displayInfo.logicalHeight * physWidth / displayInfo.logicalWidth;
        } else {
            // Pillar box.
            displayRectWidth = displayInfo.logicalWidth * physHeight / displayInfo.logicalHeight;
            displayRectHeight = physHeight;
        }
        int displayRectTop = (physHeight - displayRectHeight) / 2;
        int displayRectLeft = (physWidth - displayRectWidth) / 2;
        mTempDisplayRect.set(displayRectLeft, displayRectTop,
                displayRectLeft + displayRectWidth, displayRectTop + displayRectHeight);

        mTempDisplayRect.left += mDisplayOffsetX;
        mTempDisplayRect.right += mDisplayOffsetX;
        mTempDisplayRect.top += mDisplayOffsetY;
        mTempDisplayRect.bottom += mDisplayOffsetY;
        device.setProjectionInTransactionLocked(orientation, mTempLayerStackRect, mTempDisplayRect);
    }

DisplayDevice的setProjectionInTransactionLocked函数,最后也是调用SurfaceControl相关函数。

    public final void setProjectionInTransactionLocked(int orientation,
            Rect layerStackRect, Rect displayRect) {
        if (mCurrentOrientation != orientation
                || mCurrentLayerStackRect == null
                || !mCurrentLayerStackRect.equals(layerStackRect)
                || mCurrentDisplayRect == null
                || !mCurrentDisplayRect.equals(displayRect)) {
            mCurrentOrientation = orientation;

            if (mCurrentLayerStackRect == null) {
                mCurrentLayerStackRect = new Rect();
            }
            mCurrentLayerStackRect.set(layerStackRect);

            if (mCurrentDisplayRect == null) {
                mCurrentDisplayRect = new Rect();
            }
            mCurrentDisplayRect.set(displayRect);

            SurfaceControl.setDisplayProjection(mDisplayToken,
                    orientation, layerStackRect, displayRect);
        }
    }

至于SurfaceControl的相关函数我们以后分析,也是通过SurfaceComposerClient到SurfaceFlinger中。



    原文作者:kc专栏
    原文地址: https://blog.csdn.net/kc58236582/article/details/53814159
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞