SwallowJoe的博客

Be a real go-getter,
NEVER SETTLE!

0%

App申请帧率(2)--Framework选择最近帧率范围

以下分析基于Android Q.

一. preferredDisplayModeId改变

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

1
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
@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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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}

注意这里的优先级:

name Value
PRIORITY_LOW_BRIGHTNESS 0
PRIORITY_USER_SETTING_MIN_REFRESH_RATE 1
PRIORITY_APP_REQUEST_REFRESH_RATE 2
PRIORITY_APP_REQUEST_SIZE 3
PRIORITY_USER_SETTING_PEAK_REFRESH_RATE 4
PRIORITY_LOW_POWER_MODE 5

当外层循环第一次执行时: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

1
2
3
4
@Override
public void performTraversal(SurfaceControl.Transaction t) {
performTraversalInternal(t);
}

3.2 DisplayManagerService.performTraversalInternal

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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

1
2
3
4
5
6
7
8
9
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@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

1
2
3
4
5
6
7
8
9
10
11
12
13
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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

1
2
3
4
5
6
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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去和硬件交互,通知切换刷新率了。

欢迎关注我的其它发布渠道