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

参考资料

以下分析基于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) {
        setAppRequestedModeLocked(displayId, modeId);
    }
}

private void setAppRequestedModeLocked(int displayId, int modeId) {
    // 做一个参数检查,确保displayId和modeId参数是可接受的
    final Display.Mode requestedMode = findModeByIdLocked(displayId, modeId);
    // 如果当前displayId下的modeId已经是App所需的modeId,就不用继续了
    if (Objects.equals(requestedMode, mAppRequestedModeByDisplay.get(displayId))) {
        return;
    }

    final Vote refreshRateVote;
    final Vote sizeVote;
    if (requestedMode != null) {
        // 保存当前App设置的参数
        mAppRequestedModeByDisplay.put(displayId, requestedMode);
        float refreshRate = requestedMode.getRefreshRate();
        // 创建刷新率Vote
        refreshRateVote = Vote.forRefreshRates(refreshRate, refreshRate);
        sizeVote = Vote.forSize(requestedMode.getPhysicalWidth(),
                requestedMode.getPhysicalHeight());
    } else {
        mAppRequestedModeByDisplay.remove(displayId);
        refreshRateVote = null;
        sizeVote = null;
    }

    updateVoteLocked(displayId, Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, refreshRateVote);
    updateVoteLocked(displayId, Vote.PRIORITY_APP_REQUEST_SIZE, sizeVote);
    return;
}

2.2 DisplayModeDirector.Vote.updateVoteLocked

更新Vote策略

private void updateVoteLocked(int displayId, int priority, Vote vote) {
    if (DEBUG) {
        Slog.i(TAG, "updateVoteLocked(displayId=" + displayId
                + ", priority=" + Vote.priorityToString(priority)
                + ", vote=" + vote + ")");
    }
    if (priority < Vote.MIN_PRIORITY || priority > Vote.MAX_PRIORITY) {
        Slog.w(TAG, "Received a vote with an invalid priority, ignoring:"
                + " priority=" + Vote.priorityToString(priority)
                + ", vote=" + vote, new Throwable());
        return;
    }
    // 获取当前display的所有Vote
    final SparseArray<Vote> votes = getOrCreateVotesByDisplay(displayId);
    // 获取PRIORITY_APP_REQUEST_REFRESH_RATE优先级的Vote,不过根本没有用?
    Vote currentVote = votes.get(priority);
    // 传入的Vote不为空,说明有符合要求的ModeId,就保存,没有就移除当前优先级的Vote
    if (vote != null) {
        votes.put(priority, vote);
    } else {
        votes.remove(priority);
    }

    if (votes.size() == 0) {
        if (DEBUG) {
            Slog.i(TAG, "No votes left for display " + displayId + ", removing.");
        }
        mVotesByDisplay.remove(displayId);
    }
    // 通知ModeId改变
    notifyAllowedModesChangedLocked();
}

2.3 DisplayModeDirector.Vote.notifyAllowedModesChangedLocked

private void notifyAllowedModesChangedLocked() {
    if (mListener != null && !mHandler.hasMessages(MSG_ALLOWED_MODES_CHANGED)) {
        // We need to post this to a handler to avoid calling out while holding the lock
        // since we know there are things that both listen for changes as well as provide
        // information. If we did call out while holding the lock, then there's no guaranteed
        // lock order and we run the real of risk deadlock.
        Message msg = mHandler.obtainMessage(MSG_ALLOWED_MODES_CHANGED, mListener);
        msg.sendToTarget();
    }
}

private final class DisplayModeDirectorHandler extends Handler {
    DisplayModeDirectorHandler(Looper looper) {
        super(looper, null, true /*async*/);
    }

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_ALLOWED_MODES_CHANGED:
                Listener listener = (Listener) msg.obj;
                listener.onAllowedDisplayModesChanged();
                break;
            ......
        }
    }
}

转到DisplayThread线程处理,也就是回调onAllowedDisplayModesChanged.
这里的mListener是调用DisplayModeDirector.setListener设置的,这个是在DisplayManagerService中:

/**
    * Called when the system is ready to go.
    */
public void systemReady(boolean safeMode, boolean onlyCore) {
    synchronized (mSyncRoot) {
        mSafeMode = safeMode;
        mOnlyCore = onlyCore;
        mSystemReady = true;
        // Just in case the top inset changed before the system was ready. At this point, any
        // relevant configuration should be in place.
        recordTopInsetLocked(mLogicalDisplays.get(Display.DEFAULT_DISPLAY));
    }

    // 这里:
    mDisplayModeDirector.setListener(new AllowedDisplayModeObserver());
    mDisplayModeDirector.start(mSensorManager);

    mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
}

2.4 DisplayManagerService.onAllowedDisplayModesChangedInternal

private void onAllowedDisplayModesChangedInternal() {
    boolean changed = false;
    synchronized (mSyncRoot) {
        final int count = mLogicalDisplays.size();
        // 遍历所有的Display,依次设置
        for (int i = 0; i < count; i++) {
            LogicalDisplay display = mLogicalDisplays.valueAt(i);
            int displayId = mLogicalDisplays.keyAt(i);
            // 2.5 获取displayId对应的ModeIds
            int[] allowedModes = mDisplayModeDirector.getAllowedModes(displayId);
            // Note that order is important here since not all display devices are capable of
            // automatically switching, so we do actually want to check for equality and not
            // just equivalent contents (regardless of order).
            if (!Arrays.equals(allowedModes, display.getAllowedDisplayModesLocked())) {
                // 保存modeId集,以便判断是否有modeId变化,这个判断条件内getAllowedDisplayModesLocked
                // 拿到的modeId数组就是上一次在这里保存的
                display.setAllowedDisplayModesLocked(allowedModes);
                changed = true;
            }
        }
        // 有改变, 请求下一次Vsync, 以确保通知到SurfaceFlinger有modeId更改
        if (changed) {
            scheduleTraversalLocked(false);
        }
    }
}

2.5 DisplayModeDirector.getAllowedModes

@NonNull
public int[] getAllowedModes(int displayId) {
    synchronized (mLock) {
        // 取出displayId对应的所有Vote,注意这里包含GLOBAL_ID(-1), 即全局生效的Vote
        SparseArray<Vote> votes = getVotesLocked(displayId);
        Display.Mode[] modes = mSupportedModesByDisplay.get(displayId);
        Display.Mode defaultMode = mDefaultModeByDisplay.get(displayId);
        if (modes == null || defaultMode == null) {
            Slog.e(TAG, "Asked about unknown display, returning empty allowed set! (id="
                    + displayId + ")");
            return new int[0];
        }
        // 2.5.1 计算
        return getAllowedModesLocked(votes, modes, defaultMode);
    }
}

计算displayId对应允许的可自由切换的modeId列表

2.5.1 DisplayModeDirector.getAllowedModesLocked

@NonNull
private int[] getAllowedModesLocked(@NonNull SparseArray<Vote> votes,
        @NonNull Display.Mode[] modes, @NonNull Display.Mode defaultMode) {
    // 从最低优先级开始遍历,不过为什么会有两层循环?
    int lowestConsideredPriority = Vote.MIN_PRIORITY;
    while (lowestConsideredPriority <= Vote.MAX_PRIORITY) {
        float minRefreshRate = 0f;
        float maxRefreshRate = Float.POSITIVE_INFINITY;
        int height = Vote.INVALID_SIZE;
        int width = Vote.INVALID_SIZE;

        // 从优先级最大的开始遍历
        for (int priority = Vote.MAX_PRIORITY;
                priority >= lowestConsideredPriority;
                priority--) {
            Vote vote = votes.get(priority);
            if (vote == null) {
                continue;
            }
            // 刷新率最小值取两者中的较大值
            minRefreshRate = Math.max(minRefreshRate, vote.minRefreshRate);
            // 刷新率最大值取两者中的较小值
            maxRefreshRate = Math.min(maxRefreshRate, vote.maxRefreshRate);
            // 显示大小只需要取第一个值
            if (height == Vote.INVALID_SIZE && width == Vote.INVALID_SIZE
                    && vote.height > 0 && vote.width > 0) {
                width = vote.width;
                height = vote.height;
            }
        }

        // If we don't have anything specifying the width / height of the display, just use the
        // default width and height. We don't want these switching out from underneath us since
        // it's a pretty disruptive behavior.
        if (height == Vote.INVALID_SIZE || width == Vote.INVALID_SIZE) {
            width = defaultMode.getPhysicalWidth();
            height = defaultMode.getPhysicalHeight();
        }

        // 2.5.2 获取可取的mode
        int[] availableModes =
                filterModes(modes, width, height, minRefreshRate, maxRefreshRate);
        if (availableModes.length > 0) {
            return availableModes;
        }

        // 当前优先级下没有找到合适的modeId时,提高优先级重新搜索
        lowestConsideredPriority++;
    }

    // If we still haven't found anything that matches our current set of votes, just fall back
    // to the default mode.
    return new int[] { defaultMode.getModeId() };
}

这里刷新率的算法是,遍历所有优先级的Vote,最终的minRefreshRate取所有Vote的最小刷新率中的最大值。
maxRefreshRate取所有Vote中最大刷新率的最小值。

这里有个地方一开始比较难理解,就是为什么是用双层循环,而且第一层循环是从优先级最低的开始,最内层是优先级最大的开始。不着急我们先看#2.5.2

2.5.2 DisplayModeDirector.filterModes

private int[] filterModes(Display.Mode[] supportedModes,
        int width, int height, float minRefreshRate, float maxRefreshRate) {
    ArrayList<Display.Mode> availableModes = new ArrayList<>();
    for (Display.Mode mode : supportedModes) {
        if (mode.getPhysicalWidth() != width || mode.getPhysicalHeight() != height) {
            continue;
        }
        final float refreshRate = mode.getRefreshRate();
        // EPSILON = 0.001f
        // 为啥会有这呢,因为小数计算会有误差
        // 比如60Hz的刷新的vsync间隔是16.666666ms
        // 计算得来的refreshRate就是:1000/16.666666 = 60.0000024
        // 不是恰好为60,所以需要去掉这个误差
        if (refreshRate < (minRefreshRate - EPSILON)
                || refreshRate > (maxRefreshRate + EPSILON)) {
            // 当该mode的刷新率不符合边界条件时,抛弃该mode
            continue;
        }
        availableModes.add(mode);
    }
    final int size = availableModes.size();
    int[] availableModeIds = new int[size];
    for (int i = 0; i < size; i++) {
        availableModeIds[i] = availableModes.get(i).getModeId();
    }
    // 返回符合要求的modeId集合
    return availableModeIds;
}

其实实际推演一下就不难理解了, 假设我们有如下Votes:

mSupportedModesByDisplay:
    0 -> [
        {id=1, width=1080, height=2376, fps=60.000004}, 
        {id=2, width=1440, height=3168, fps=120.00001}, 
        {id=3, width=1440, height=3168, fps=60.000004}, 
        {id=4, width=1080, height=2376, fps=120.00001}]

  mVotesByDisplay:
    -1:
      PRIORITY_LOW_POWER_MODE -> Vote{width=-1, height=-1, minRefreshRate=0.0, maxRefreshRate=60.0}
      PRIORITY_USER_SETTING_PEAK_REFRESH_RATE -> Vote{width=-1, height=-1, minRefreshRate=0.0, maxRefreshRate=120.0}
      PRIORITY_USER_SETTING_MIN_REFRESH_RATE -> Vote{width=-1, height=-1, minRefreshRate=0.0, maxRefreshRate=Infinity}
    0:
      PRIORITY_APP_REQUEST_SIZE -> Vote{width=1080, height=2376, minRefreshRate=0.0, maxRefreshRate=Infinity}
      PRIORITY_APP_REQUEST_REFRESH_RATE -> Vote{width=-1, height=-1, minRefreshRate=120.00001, maxRefreshRate=120.00001}

注意这里的优先级:

nameValue
PRIORITY_LOW_BRIGHTNESS0
PRIORITY_USER_SETTING_MIN_REFRESH_RATE1
PRIORITY_APP_REQUEST_REFRESH_RATE2
PRIORITY_APP_REQUEST_SIZE3
PRIORITY_USER_SETTING_PEAK_REFRESH_RATE4
PRIORITY_LOW_POWER_MODE5

当外层循环第一次执行时:lowestConsideredPriority = PRIORITY_LOW_BRIGHTNESS = 0

内层循环会遍历所有Vote(包含-1,和当前displayId,这里是0):

算出的minRefreshRate = Infinity, maxRefreshRate =0

当然,在filterModes中是找不到合适的mode的,所以优先级+1,继续搜索

外层循环第二次执行时:lowestConsideredPriority = PRIORITY_USER_SETTING_MIN_REFRESH_RATE = 1

此时排除优先级为0的所有Vote,其实结果还是一样,所以lowestConsideredPriority继续+1

外层循环第三次执行时:lowestConsideredPriority = PRIORITY_APP_REQUEST_REFRESH_RATE = 2

此时排除优先级小于PRIORITY_APP_REQUEST_REFRESH_RATE的所有Vote,结果还是一样,所以lowestConsideredPriority继续+1

外层循环第四次执行时:lowestConsideredPriority = PRIORITY_APP_REQUEST_SIZE = 3

此时排除优先级小于PRIORITY_APP_REQUEST_SIZE的所有Vote,结果还是一样,所以lowestConsideredPriority继续+1

外层循环第五次执行时:lowestConsideredPriority = PRIORITY_USER_SETTING_PEAK_REFRESH_RATE = 4

此时排除优先级小于PRIORITY_USER_SETTING_PEAK_REFRESH_RATE的所有Vote

内层循环其实只有两个选项:

PRIORITY_LOW_POWER_MODE -> Vote{width=-1, height=-1, minRefreshRate=0.0, maxRefreshRate=60.0}

PRIORITY_USER_SETTING_PEAK_REFRESH_RATE -> Vote{width=-1, height=-1, minRefreshRate=0.0, maxRefreshRate=120.0}

此时结果为minRefreshRate = 60, maxRefreshRate =0,当然还是没有有效的modeId

外层循环第六次执行时:lowestConsideredPriority = PRIORITY_LOW_POWER_MODE = 5

只有选项:PRIORITY_LOW_POWER_MODE -> Vote{width=-1, height=-1, minRefreshRate=0.0, maxRefreshRate=60.0}

所以最终的minRefreshRate = 0.0, maxRefreshRate = 60.0,width=1080, height=2376

最后满足条件的modeId就只有mSupportedModesByDisplay中的0了.

最终算出来了modeId, 这里面计算复杂,弯弯绕绕,为什么Google如此设计呢,个人猜测是为了尽可能满足低优先级下的刷新率要求,并不是优先级最高就能决定modeId的取值,
而是找到尽快满足更多优先级下合适刷新率的modeId集提供给SurfaceFlinger选择.

继续往下看,framework将这个modeId集传给SurfaceFlinger.

三. 通知SurfaceFlinger变化

3.1 DisplayManagerInternal.performTraversal

@Override
public void performTraversal(SurfaceControl.Transaction t) {
    performTraversalInternal(t);
}

3.2 DisplayManagerService.performTraversalInternal

@VisibleForTesting
void performTraversalInternal(SurfaceControl.Transaction t) {
    synchronized (mSyncRoot) {
        if (!mPendingTraversal) {
            return;
        }
        mPendingTraversal = false;
        // 3.2.1 通知SF有相关状态变化
        performTraversalLocked(t);
    }

    // List is self-synchronized copy-on-write.
    for (DisplayTransactionListener listener : mDisplayTransactionListeners) {
        listener.onDisplayTransaction(t);
    }
}

3.2.1 DisplayManagerService.performTraversalLocked

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

    // 3.2.2 对每个Display都做配置
    final int count = mDisplayDevices.size();
    for (int i = 0; i < count; i++) {
        DisplayDevice device = mDisplayDevices.get(i);
        // 与SurfaceFlinger通信,这里的device我们视为默认的LocalDisplayDevice
        configureDisplayLocked(t, device);
        device.performTraversalLocked(t);
    }
    ......
}

3.2.2 DisplayManagerService.configureDisplayLocked

private void configureDisplayLocked(SurfaceControl.Transaction t, DisplayDevice device) {
    ......
    // 拿到对应LogicalDisplay
    LogicalDisplay display = findLogicalDisplayForDeviceLocked(device);
    ......
    // 3.2.3 应用状态变化
    display.configureDisplayLocked(t, device, info.state == Display.STATE_OFF);
    ......
}

3.2.3 LogicalDisplay.configureDisplayLocked

public void configureDisplayLocked(SurfaceControl.Transaction t,
        DisplayDevice device,
        boolean isBlanked) {
    // Set the layer stack.
    device.setLayerStackLocked(t, isBlanked ? BLANK_LAYER_STACK : mLayerStack);

    // 3.3 应用配置变化,注意这里的device是LocalDisplayDevice
    if (device == mPrimaryDisplayDevice) {
        device.setAllowedDisplayModesLocked(mAllowedDisplayModes);
        device.setRequestedColorModeLocked(mRequestedColorMode);
    } else {
        // Reset to default for non primary displays
        device.setAllowedDisplayModesLocked(new int[] {0});
        device.setRequestedColorModeLocked(0);
    }
    ......
}

3.3 LocalDisplayAdapter.LocalDisplayDevice.setAllowedDisplayModesLocked

@Override
public void setAllowedDisplayModesLocked(int[] modes) {
    updateAllowedModesLocked(modes);
}

public void updateAllowedModesLocked(int[] allowedModes) {
    if (Arrays.equals(allowedModes, mAllowedModeIds) && !mAllowedModeIdsInvalid) {
        return;
    }
    if (updateAllowedModesInternalLocked(allowedModes)) {
        updateDeviceInfoLocked();
    }
}

public boolean updateAllowedModesInternalLocked(int[] allowedModes) {
    if (DEBUG) {
        Slog.w(TAG, "updateAllowedModesInternalLocked(allowedModes="
                + Arrays.toString(allowedModes) + ")");
    }
    int[] allowedPhysIndexes = new int[allowedModes.length];
    int size = 0;
    // 将modeId转化为物理modeId,简单来说就是 physicalId = modeId - 1
    for (int modeId : allowedModes) {
        int physIndex = findDisplayInfoIndexLocked(modeId);
        if (physIndex < 0) {
            Slog.w(TAG, "Requested mode ID " + modeId + " not available,"
                    + " dropping from allowed set.");
        } else {
            allowedPhysIndexes[size++] = physIndex;
        }
    }
    ......
    // 3.4 通过SurfaceControl通知SurfaceFlinger有modeId变化,binder通信
    SurfaceControl.setAllowedDisplayConfigs(getDisplayTokenLocked(), allowedPhysIndexes);
    int activePhysIndex = SurfaceControl.getActiveConfig(getDisplayTokenLocked());
    return updateActiveModeLocked(activePhysIndex);
}

3.4 SurfaceControl.setAllowedDisplayConfigs

private static native boolean nativeSetAllowedDisplayConfigs(IBinder displayToken,
                                                                 int[] allowedConfigs);

public static boolean setAllowedDisplayConfigs(IBinder displayToken, int[] allowedConfigs) {
    if (displayToken == null) {
        throw new IllegalArgumentException("displayToken must not be null");
    }
    if (allowedConfigs == null) {
        throw new IllegalArgumentException("allowedConfigs must not be null");
    }
    // JNI调用
    return nativeSetAllowedDisplayConfigs(displayToken, allowedConfigs);
}

3.5 android_view_SurfaceControl::nativeSetAllowedDisplayConfigs

static jboolean nativeSetAllowedDisplayConfigs(JNIEnv* env, jclass clazz,
        jobject tokenObj, jintArray configArray) {
    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
    if (token == nullptr) return JNI_FALSE;

    std::vector<int32_t> allowedConfigs;
    jsize configArraySize = env->GetArrayLength(configArray);
    allowedConfigs.reserve(configArraySize);

    jint* configArrayElements = env->GetIntArrayElements(configArray, 0);
    for (int i = 0; i < configArraySize; i++) {
        allowedConfigs.push_back(configArrayElements[i]);
    }
    env->ReleaseIntArrayElements(configArray, configArrayElements, 0);
    // 3.5.1 通过SurfaceComposerClient
    size_t result = SurfaceComposerClient::setAllowedDisplayConfigs(token, allowedConfigs);
    return result == NO_ERROR ? JNI_TRUE : JNI_FALSE;
}

3.5.1 SurfaceComposerClient::setAllowedDisplayConfigs

status_t SurfaceComposerClient::setAllowedDisplayConfigs(
        const sp<IBinder>& displayToken, const std::vector<int32_t>& allowedConfigs) {
    // 通过binder调用到SurfaceFlinger
    return ComposerService::getComposerService()->setAllowedDisplayConfigs(displayToken,
                                                                           allowedConfigs);
}

3.6 SurfaceFlinger::setAllowedDisplayConfigs

status_t SurfaceFlinger::setAllowedDisplayConfigs(const sp<IBinder>& displayToken,
                                                  const std::vector<int32_t>& allowedConfigs) {
    ATRACE_CALL();

    if (!displayToken || allowedConfigs.empty()) {
        return BAD_VALUE;
    }

    if (mDebugDisplayConfigSetByBackdoor) {
        // ignore this request as config is overridden by backdoor
        return NO_ERROR;
    }

    postMessageSync(new LambdaMessage([&]() {
        const auto display = getDisplayDeviceLocked(displayToken);
        if (!display) {
            ALOGE("Attempt to set allowed display configs for invalid display token %p",
                  displayToken.get());
        } else if (display->isVirtual()) {
            ALOGW("Attempt to set allowed display configs for virtual display");
        } else {
            Mutex::Autolock lock(mStateLock);
            setAllowedDisplayConfigsInternal(display, allowedConfigs);
        }
    }));

    return NO_ERROR;
}

好了,app设置屏幕显示刷新的流程就走完了,接下来就是SurfaceFlinger去和硬件交互,通知切换刷新率了。

©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页