文章目录
- 参考资料
- 一. preferredDisplayModeId改变
- 二. DisplayModeDirector
- 三. 通知SurfaceFlinger变化
参考资料
以下分析基于Android Q.
一. preferredDisplayModeId改变
上篇文章讲到,只要将window的Param设置就可以更改屏幕分辨率:
wmParams!!.preferredDisplayModeId = highestMode.modeId
代码是和实现的呢, 在App接受vsync信号后,会回调Choreographer.CALLBACK_TRAVERSAL,也就会调用到ViewRootImpl.doTraversal.
调用栈如下:
- Choreographer.onVsync()
- Choreographer.doFrame() // doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
- ViewRootImpl.doTraversal()
- ViewRootImpl.performTraversals()
- ViewRootImpl.relayoutWindow() // 这里将当前Window的Attr传入WindowManagerService
- IWindowSession.relayout() // 通过binder调用 Session.relayout
- WindowManagerService.relayoutWindow() // 进入SystenServer进程
- WindowSurfacePlacer.performSurfacePlacement()
- WindowSurfacePlacer.performSurfacePlacementLoop()
- RootWindowContainer.performSurfacePlacement()
- RootWindowContainer.performSurfacePlacementNoTrace()
- RootWindowContainer.applySurfaceChangesTransaction()
- DisplayContent.applySurfaceChangesTransaction()
- DisplayContent.mApplySurfaceChangesTransaction // 对所有window遍历执行,如果有属性变化响应变化
- DisplayManagerService.setDisplayProperties // 计算并保存合适的modeId
- DisplayManagerInternal.performTraversal(mDisplayTransaction) // 应用modeId变化
- DisplayContent.applySurfaceChangesTransaction()
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