Android Display的初始化

作者: wbo4958 | 来源:发表于2017-12-05 17:00 被阅读275次

    本文从Android Java层讲解Android Display相关类的初始化。

    整体流程如下:


    Display Device Discover

    1. DisplayAdapter获得DisplayDevice

    DisplayManagerService中取得DisplayDevice

    LocalDisplayAdapter从BUILT_IN_DISPLAY_IDS_TO_SCAN中获得DISPLAY ID往SurfaceFlinger中查询Display信息(tryConnectDisplayLocked)

        private static final int[] BUILT_IN_DISPLAY_IDS_TO_SCAN = new int[] {
                SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN,
                SurfaceControl.BUILT_IN_DISPLAY_ID_HDMI,
        };
    
    private void tryConnectDisplayLocked(int builtInDisplayId) {
        //通过display id号去SurfaceFlinger里获得对应的Binder token号
        IBinder displayToken = SurfaceControl.getBuiltInDisplay(builtInDisplayId);
        if (displayToken != null) {
            //通过token号再去SurfaceFlinger获得物理显示器的相关信息
            SurfaceControl.PhysicalDisplayInfo[] configs =
                    SurfaceControl.getDisplayConfigs(displayToken);
            int activeConfig = SurfaceControl.getActiveConfig(displayToken);
            int activeColorMode = SurfaceControl.getActiveColorMode(displayToken);
            int[] colorModes = SurfaceControl.getDisplayColorModes(displayToken);
            LocalDisplayDevice device = mDevices.get(builtInDisplayId);
            if (device == null) {
                // Display was added.
                device = new LocalDisplayDevice(displayToken, builtInDisplayId,
                        configs, activeConfig, colorModes, activeColorMode);
                mDevices.put(builtInDisplayId, device);
                sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);
            } else {
                ...
            }
        } else {
            ...
        }
    }
    

    系统启动时,LocalDisplayAdapter的mDevices并没有保存相关DisplayDevice的信息,所以tryConnectDisplayLocked会直接生成一个新的DisplayDevice,然后加入到LocalDisplayAdapter.mDevices中去, 如 图中标注1 所示, 最后发送一个DISPLAY_DEVICE_EVENT_ADDED信号通过Display已经加入了。

    接下来看下LocalDisplayDevice的初始化函数

    public LocalDisplayDevice(IBinder displayToken, int builtInDisplayId,
            SurfaceControl.PhysicalDisplayInfo[] physicalDisplayInfos, int activeDisplayInfo,
            int[] colorModes, int activeColorMode) {
        //储存信息
        super(LocalDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + builtInDisplayId);
        //当前LocalDisplayDevice的Display ID号是多少
        mBuiltInDisplayId = builtInDisplayId;
        updatePhysicalDisplayInfoLocked(physicalDisplayInfos, activeDisplayInfo,
                colorModes, activeColorMode);
        ...
    }
    

    LocalDisplayDevice继承于DisplayDevice, 首先通过super函数将一些信息存储在DisplayDevice中,比如与SurfaceFlinger通信的Display Token, uniq ID等

    然后又通过updatePhysicalDisplayInfoLocked去更新物理显示屏的信息到具体的类中, 如 图中标注2 所示。

    public boolean updatePhysicalDisplayInfoLocked(
            SurfaceControl.PhysicalDisplayInfo[] physicalDisplayInfos, int activeDisplayInfo,
            int[] colorModes, int activeColorMode) {
        //将从SurfaceFlinger获得的物理显示屏的信息全部保存在mDisplayInfos里
        mDisplayInfos = Arrays.copyOf(physicalDisplayInfos, physicalDisplayInfos.length);
        // mActivePhysIndex 指的是当前 Activity 的配置
        mActivePhysIndex = activeDisplayInfo;
        ArrayList<DisplayModeRecord> records = new ArrayList<DisplayModeRecord>();
        boolean modesAdded = false;
        for (int i = 0; i < physicalDisplayInfos.length; i++) {
            //通过将物理显示屏的信息放入到 records 中
            ...
        }
    
        // Get the currently active mode
        // 获得当前 Activity DisplayModeRecord
        DisplayModeRecord activeRecord = null;
        for (int i = 0; i < records.size(); i++) {
            DisplayModeRecord record = records.get(i);
            if (record.hasMatchingMode(physicalDisplayInfos[activeDisplayInfo])){
                activeRecord = record;
                break;
            }
        }
        // Check whether surface flinger spontaneously changed modes out from under us. Schedule
        // traversals to ensure that the correct state is reapplied if necessary.
        if (mActiveModeId != 0
                && mActiveModeId != activeRecord.mMode.getModeId()) {
            mActiveModeInvalid = true;
            sendTraversalRequestLocked();
        }
    
        boolean recordsChanged = records.size() != mSupportedModes.size() || modesAdded;
        // If the records haven't changed then we're done here.
        if (!recordsChanged && !forceUpdate) {
            return false;
        }
        // Update the index of modes.
        mHavePendingChanges = true;
    
        mSupportedModes.clear();
        // 将records加入到mSupportedModes中
        for (DisplayModeRecord record : records) {
            mSupportedModes.put(record.mMode.getModeId(), record);
        }
        
        ...
        return true;
    }
    
    

    那这些物理显示屏的信息具体有哪些呢?看下PhysicalDisplayInfo类中的定义便可知

    public int width;   //显示屏宽度 单位是px
    public int height; //显示屏高度 单位是px
    public float refreshRate;  //显示屏刷新率  59HZ 60HZ ...
    public float density;   //屏幕密度, 表示每粗寸上有多少个点 120/160/...
    public float xDpi;
    public float yDpi;
    public boolean secure;
    public long appVsyncOffsetNanos;
    public long presentationDeadlineNanos;
    

    density可以参考Pixel Density

    LocalDisplayAdapter将从SF获得的显示屏信息DisplayDevice通知DisplayManagerService Device Added了。

    private void handleDisplayDeviceAddedLocked(DisplayDevice device) {
        //getDisplayDeviceInfoLocked函数会将物理显示屏的active的信息保存到mInfo也就是DisplayDeviceInfo里
        DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
        if (mDisplayDevices.contains(device)) {
            return;
        }
    
        // mDebugLastLoggedDeviceInfo 表示的是上一次的DisplayDeviceInfo的信息
        device.mDebugLastLoggedDeviceInfo = info;
        
        //将DisplayDevice加入到DMS的mDisplayDevices中去
        //如图中标注3所示
        mDisplayDevices.add(device);
        
        //为物理显示屏生成一个 LogicalDisplay
        LogicalDisplay display = addLogicalDisplayLocked(device);
        
        //updateDisplayStateLocked会触发 DISPLAY_DEVICE_EVENT_CHANGED, 
        Runnable work = updateDisplayStateLocked(device);
        if (work != null) {
            work.run();
        }
        if (display != null && display.getPrimaryDisplayDeviceLocked() == device) {
            int colorMode = mPersistentDataStore.getColorMode(device);
            if (colorMode == Display.COLOR_MODE_INVALID) {
                if ((device.getDisplayDeviceInfoLocked().flags
                     & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0) {
                    colorMode = mDefaultDisplayDefaultColorMode;
                } else {
                    colorMode = Display.COLOR_MODE_DEFAULT;
                }
            }
            display.setRequestedColorModeLocked(colorMode);
        }
        scheduleTraversalLocked(false);
    }
    

    handleDisplayDeviceAddedLocked函数会为DisplayDevice生成一个对应的LogicalDevice, 同时会将LogicalDevice加入到DisplayManagerService中mLogicalDevices中,同时也将DisplayDevice加入到DisplayManagerService的mDisplayDevices中如 图中标注3图中标注4 所示

    为DisplayDevice生成一个LogicalDisplay

    private LogicalDisplay addLogicalDisplayLocked(DisplayDevice device) {
        DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked();
        boolean isDefault = (deviceInfo.flags
                & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0;
        // isDefault 表示的是否是默认的Display
        if (isDefault && mLogicalDisplays.get(Display.DEFAULT_DISPLAY) != null) {
            isDefault = false;
        }
    
        //如果不是默认的,而且系统只支持单显示屏模式,那就直接退出了
        if (!isDefault && mSingleDisplayDemoMode) {
            return null;
        }
    
        final int displayId = assignDisplayIdLocked(isDefault);
        final int layerStack = assignLayerStackLocked(displayId);
    
        LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);
        
        //用DisplayDevice中的DisplayDeviceInfo更新LogicalDisplay中的mBaseInfoDisplayInfo
        //如 图中标注5 所示
        display.updateLocked(mDisplayDevices);
        if (!display.isValidLocked()) {
            return null;
        }
    
        // 如图标注3所示
        mLogicalDisplays.put(displayId, display);
    
        // Wake up waitForDefaultDisplay.
        // 通知 SystemServer 线程继续执行下面的初始化 具体是在 DisplayManagerService的onBootPhase阶段
        // 这样systemserver继续初始化 pkms, wms 等等
        if (isDefault) {
            mSyncRoot.notifyAll();
        }
        
        // 通过 DISPLAY add
        sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
        return display;
    }
    

    handleDisplayDeviceChanged由updateDisplayStateLocked触发, 它的本意是 DisplayDevice(最底层的显示屏信息已经改变了)那么,就要通知改变它所对应的LogicalDisplay中的相关的信息,

    DisplayManagerService
    private void handleDisplayDeviceChanged(DisplayDevice device) {
        synchronized (mSyncRoot) {
            DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
            if (!mDisplayDevices.contains(device)) {
                return;
            }
    
            //mDebugLastLoggedDeviceInfo记录的是上一次的DisplayInfo
            int diff = device.mDebugLastLoggedDeviceInfo.diff(info);
            if (diff == DisplayDeviceInfo.DIFF_STATE) {
                Slog.i(TAG, "Display device changed state: \"" + info.name
                        + "\", " + Display.stateToString(info.state));
            } else if (diff != 0) {
                Slog.i(TAG, "Display device changed: " + info);
            }
            if ((diff & DisplayDeviceInfo.DIFF_COLOR_MODE) != 0) {
                try {
                    mPersistentDataStore.setColorMode(device, info.colorMode);
                } finally {
                    mPersistentDataStore.saveIfNeeded();
                }
            }
            //更新 Last DeviceInfo
            device.mDebugLastLoggedDeviceInfo = info;
    
            device.applyPendingDisplayDeviceInfoChangesLocked();
            if (updateLogicalDisplaysLocked()) {  //更新LogicalDisplay中的相关的信息
                scheduleTraversalLocked(false);  
            }
        }
    }
    

    2. WMS中关于Display类相关的初始化

    WindowManagerService中Display相关类初始化
    private WindowManagerService(Context context, InputManagerService inputManager,
            boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore,
            WindowManagerPolicy policy) {
        mRoot = new RootWindowContainer(this);
        mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
        mWindowPlacerLocked = new WindowSurfacePlacer(this);
        ...
        //获得 DisplayManager
        mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
        //通过DisplayManager去获得Displays
        mDisplays = mDisplayManager.getDisplays();
        for (Display display : mDisplays) {
            createDisplayContentLocked(display);
        }
    }  
    

    WMS通过DisplayManager的getDisplays()去获得所有的Display信息,这个可以参考第3小节,
    接下来看下 createDisplayContentLocked

    private void createDisplayContentLocked(final Display display) {
        mRoot.getDisplayContentOrCreate(display.getDisplayId());
    }
    
    DisplayContent getDisplayContentOrCreate(int displayId) {
        //检查displayId的DisplayContent是否已经创建过了
        DisplayContent dc = getDisplayContent(displayId);
        if (dc == null) {
            final Display display = mService.mDisplayManager.getDisplay(displayId);
            if (display != null) {
                final long callingIdentity = Binder.clearCallingIdentity();
                try {
                    dc = createDisplayContent(display);
                } finally {
                    Binder.restoreCallingIdentity(callingIdentity);
                }
            }
        }
        return dc;
    }
    
    private DisplayContent createDisplayContent(final Display display) {
        //生成一个新的DisplayContent
        final DisplayContent dc = new DisplayContent(display, mService, mLayersController,
                mWallpaperController);
        final int displayId = display.getDisplayId();
    
        final DisplayInfo displayInfo = dc.getDisplayInfo();
        final Rect rect = new Rect();
        //获得Overscan的区域, 这个是配置的 /data/system/display_settings.xml
        mService.mDisplaySettings.getOverscanLocked(displayInfo.name, displayInfo.uniqueId, rect);
        displayInfo.overscanLeft = rect.left;
        displayInfo.overscanTop = rect.top;
        displayInfo.overscanRight = rect.right;
        displayInfo.overscanBottom = rect.bottom;
        if (mService.mDisplayManagerInternal != null) {
             //这里可能会设置 mOverrideDisplayInfo 
            mService.mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(
                    displayId, displayInfo);
            mService.configureDisplayPolicyLocked(dc);
    
            // TODO(multi-display): Create an input channel for each display with touch capability.
            if (displayId == DEFAULT_DISPLAY && mService.canDispatchPointerEvents()) {
                dc.mTapDetector = new TaskTapPointerEventListener(
                        mService, dc);
                mService.registerPointerEventListener(dc.mTapDetector);
                mService.registerPointerEventListener(mService.mMousePositionTracker);
            }
        }
    
        return dc;
    }
    

    3. DisplayManager中相关初始化

    DisplayManager类初始化
    public Display[] getDisplays(String category) {
        final int[] displayIds = mGlobal.getDisplayIds(); //通过DisplayManagerGlobal去获得DisplayIds
        synchronized (mLock) {
            try {
                if (category == null) {  //进入该分支
                    addAllDisplaysLocked(mTempDisplays, displayIds);
                } else if (category.equals(DISPLAY_CATEGORY_PRESENTATION)) {
                    ...
                }
                return mTempDisplays.toArray(new Display[mTempDisplays.size()]);
            } finally {
                mTempDisplays.clear();
            }
        }
    }
    
    public int[] getDisplayIds() {
        try {
            synchronized (mLock) {
                if (USE_CACHE) {
                    if (mDisplayIdCache != null) {
                        return mDisplayIdCache;
                    }
                }
    
                int[] displayIds = mDm.getDisplayIds(); //通过DisplayManagerService获得当前的显示屏对应的 ID 值 
                if (USE_CACHE) { //是否使用缓存
                    mDisplayIdCache = displayIds;
                }
                //注册DisplayManagerCallback回调函数接收onDisplayEvent事件
                //比如 DISPLAY CHANGED/REMOVED/ADDED ... 这时DisplayManager就会更新APP注册过来的回调函数.
                registerCallbackIfNeededLocked();
                return displayIds;
            }
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }
    
    private void addAllDisplaysLocked(ArrayList<Display> displays, int[] displayIds) {
        for (int i = 0; i < displayIds.length; i++) {
            //getOrCreateDisplayLocked主要是getDisplayInfo接口去请求DMS的DisplayInfo,然后生成Display类
            Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/);
            if (display != null) {
                displays.add(display);
            }
        }
    } 
    

    可以看出来getDisplayInfoInternal主要是从LogicalDisplay中获得mInfo, 如图中标注6所示.
    而mInfo的信息大部分是从mBaseDisplayInfo中获得

    private DisplayInfo getDisplayInfoInternal(int displayId, int callingUid) {
        synchronized (mSyncRoot) {
            LogicalDisplay display = mLogicalDisplays.get(displayId);
            if (display != null) {
                DisplayInfo info = display.getDisplayInfoLocked();
                if (info.hasAccess(callingUid)
                        || isUidPresentOnDisplayInternal(callingUid, displayId)) {
                    return info;
                }
            }
            return null;
        }
    }
    

    4. ActivityStackSupervior中与Display的关系

    ASS与Display的关系
    void setWindowManager(WindowManagerService wm) {
        synchronized (mService) {
            mDisplayManager =
                    (DisplayManager)mService.mContext.getSystemService(Context.DISPLAY_SERVICE);
            //ActivityStackSupervior注册DisplayListener到DisplayManager中去接收Display改变的事件
            mDisplayManager.registerDisplayListener(this, null);
            mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
            //获得所有的Display信息
            Display[] displays = mDisplayManager.getDisplays();
            for (int displayNdx = displays.length - 1; displayNdx >= 0; --displayNdx) {
                final int displayId = displays[displayNdx].getDisplayId();
                //为display生成对应的 ActivityDisplay信息
                ActivityDisplay activityDisplay = new ActivityDisplay(displayId);
                mActivityDisplays.put(displayId, activityDisplay);
                calculateDefaultMinimalSizeOfResizeableTasks(activityDisplay);
            }
            ...
        }
    }
    

    相关文章

      网友评论

      • StephenYoung:请问,Activity或者Dialog源码中调用了Window的setWindowManager方法,然后调用了WindowManagerImpl的createLocalWindowManager方法,createLocalWindowManager方法就只是new了一个WindowManagerImpl实例,里面的成员变量mDisplay并没有赋值,而addView之类的方法有对mDisplay的判空,请问是哪里赋值的..百思不得其解

      本文标题:Android Display的初始化

      本文链接:https://www.haomeiwen.com/subject/nxbxixtx.html