Android UI架构(十一)--App请求切换帧率(2)之DisplayModeId.md

本文详细解析了Android系统中应用如何请求切换屏幕刷新率的过程,从`preferredDisplayModeId`的改变到`DisplayModeDirector`的决策,再到如何通知`SurfaceFlinger`进行变化。文章介绍了`DisplayManagerService`、`DisplayModeDirector`和`SurfaceFlinger`在其中的角色,阐述了刷新率决策算法,以及模式变更的系统内部流程。
摘要由CSDN通过智能技术生成

参考资料

以下分析基于Android Q.

一. preferredDisplayModeId改变

上篇文章讲到,只要将window的Param设置就可以更改屏幕分辨率:

wmParams!!.preferredDisplayModeId = highestMode.modeId

代码是和实现的呢, 在App接受vsync信号后,会回调Choreographer.CALLBACK_TRAVERSAL,也就会调用到ViewRootImpl.doTraversal.

调用栈如下:

  1. Choreographer.onVsync()
  2. Choreographer.doFrame() // doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
  3. ViewRootImpl.doTraversal()
  4. ViewRootImpl.performTraversals()
  5. ViewRootImpl.relayoutWindow() // 这里将当前Window的Attr传入WindowManagerService
  6. IWindowSession.relayout() // 通过binder调用 Session.relayout
  7. WindowManagerService.relayoutWindow() // 进入SystenServer进程
  8. WindowSurfacePlacer.performSurfacePlacement()
  9. WindowSurfacePlacer.performSurfacePlacementLoop()
  10. RootWindowContainer.performSurfacePlacement()
  11. RootWindowContainer.performSurfacePlacementNoTrace()
  12. RootWindowContainer.applySurfaceChangesTransaction()
    1. DisplayContent.applySurfaceChangesTransaction()
      1. DisplayContent.mApplySurfaceChangesTransaction // 对所有window遍历执行,如果有属性变化响应变化
      2. DisplayManagerService.setDisplayProperties // 计算并保存合适的modeId
    2. DisplayManagerInternal.performTraversal(mDisplayTransaction) // 应用modeId变化

1.1 RootWindowContainer.applySurfaceChangesTransaction

private void applySurfaceChangesTransaction(boolean recoveringMemory) {
   
    ......

    final int count = mChildren.size();
    for (int j = 0; j < count; ++j) {
   
        final DisplayContent dc = mChildren.get(j);
        // 1.2 对每个display都计算变化
        dc.applySurfaceChangesTransaction(recoveringMemory);
    }

    // 3.1 通知SurfaceFlinger改变ModeId
    mWmService.mDisplayManagerInternal.performTraversal(mDisplayTransaction);
    SurfaceControl.mergeToGlobalTransaction(mDisplayTransaction);
}

1.2 DisplayContent.applySurfaceChangesTransaction()

void applySurfaceChangesTransaction(boolean recoveringMemory) {
   
    ......
    Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applyWindowSurfaceChanges");
    try {
   
        // 1.3 遍历所有window, 按照Z轴从上到下
        forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);
    } finally {
   
        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
    }
    prepareSurfaces();

    mLastHasContent = mTmpApplySurfaceChangesTransactionState.displayHasContent;
    // 1.4 应用需要Display属性变化
    mWmService.mDisplayManagerInternal.setDisplayProperties(mDisplayId,
            mLastHasContent,
            mTmpApplySurfaceChangesTransactionState.preferredRefreshRate,
            mTmpApplySurfaceChangesTransactionState.preferredModeId,
            true /* inTraversal, must call performTraversalInTrans... below */);
    ......
}

1.3 DisplayContent.mApplySurfaceChangesTransaction

private final Consumer<WindowState> mApplySurfaceChangesTransaction = w -> {
   
    ......
    if (!mTmpApplySurfaceChangesTransactionState.obscured) {
   
        ......
        // 获取wmParams.preferredDisplayModeId中的modeId
        final int preferredModeId = getDisplayPolicy().getRefreshRatePolicy()
                .getPreferredModeId(w);
        // 注意这里是按照Z轴从上到下遍历Window,所以只会取第一个可见的有Surface的且被设置的window的modeId
        if (mTmpApplySurfaceChangesTransactionState.preferredModeId == 0
                && preferredModeId != 0) {
   
            // 标记preferredModeId
            mTmpApplySurfaceChangesTransactionState.preferredModeId = preferredModeId;
        }
    }
    ......
}

1.4 DisplayManagerService.setDisplayProperties

@Override
public void setDisplayProperties(int displayId, boolean hasContent,
        float requestedRefreshRate, int requestedMode, boolean inTraversal) {
   
    setDisplayPropertiesInternal(displayId, hasContent, requestedRefreshRate,
            requestedMode, inTraversal);
}

private void setDisplayPropertiesInternal(int displayId, boolean hasContent,
        float requestedRefreshRate, int requestedModeId, boolean inTraversal) {
   
    synchronized (mSyncRoot) {
   
        LogicalDisplay display = mLogicalDisplays.get(displayId);
        if (display == null) {
   
            return;
        }
        if (display.hasContentLocked() != hasContent) {
   
            if (DEBUG) {
   
                Slog.d(TAG, "Display " + displayId + " hasContent flag changed: "
                        + "hasContent=" + hasContent + ", inTraversal=" + inTraversal);
            }

            display.setHasContentLocked(hasContent);
            scheduleTraversalLocked(inTraversal);
        }
        // 当应用仅仅设置了刷新率,而没有设置modeId时,需要找到一个合适的modeId
        // 为什么这么做呢,因为modeId不仅仅包含刷新率,还有分辨率。
        // 当请求刷新率变化时,是不能或不必要改变分辨率的,所以就需要找到分辨率不变的modeId
        if (requestedModeId == 0 && requestedRefreshRate != 0) {
   
            // Scan supported modes returned by display.getInfo() to find a mode with the same
            // size as the default display mode but with the specified refresh rate instead.
            requestedModeId = display.getDisplayInfoLocked().findDefaultModeByRefreshRate(
                    requestedRefreshRate);
        }
        // 2.1 发现有应用请求Display改变modeId
        mDisplayModeDirector.getAppRequestObserver().setAppRequestedMode(
                displayId, requestedModeId);
    }
}

二. DisplayModeDirector

这个类是用于决策当前设备刷新率的

2.1 DisplayModeDirector.AppRequestObserver.setAppRequestedMode

public void setAppRequestedMode(int displayId, int modeId) {
   
    synchronized (mLock) {
   
        setAppRequestedModeLocke
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值