SurfaceFlinger::init()
本节来看看init()的最后一部分内容initializeDisplays()。
//frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
void SurfaceFlinger::init() {
//省略
initializeDisplays();
//省略
}
initializeDisplays()
//frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
void SurfaceFlinger::initializeDisplays() {
// Async since we may be called from the main thread.
static_cast<void>(schedule([this]() MAIN_THREAD { onInitializeDisplays(); }));
}
template <typename F, typename T>
inline std::future<T> SurfaceFlinger::schedule(F&& f) {
auto [task, future] = makeTask(std::move(f));
mEventQueue->postMessage(std::move(task));
return std::move(future);
}
//frameworks/native/services/surfaceflinger/Scheduler/MessageQueue.h
template <typename F>
inline auto makeTask(F&& f) {
sp<Task<F>> task = new Task<F>(std::move(f));
return std::make_pair(task, task->mTask.get_future());
}
initializeDisplays()方法内调用了schedule()模板函数,而schedule()方法内部首先创建一个Task,然后再将这个Task发送到MessageQueue中(关于MessageQueue的工作原理后续章节讲解),MessageQueue监测到队列(其实内部实现是vector,习惯性叫队列,听起来符合大众认知)中有消息,那么就处理。这里其实就是执行Task实现的handleMessage()函数。
//frameworks/native/services/surfaceflinger/Scheduler/MessageQueue.h
template <typename F>
class Task : public MessageHandler {
template <typename G>
friend auto makeTask(G&&);
explicit Task(F&& f) : mTask(std::move(f)) {}
void handleMessage(const Message&) override { mTask(); }
using T = std::invoke_result_t<F>;
std::packaged_task<T()> mTask;
};
从代码可以看到handleMessage()调用的是mTask()函数,而这个函数就是前面被赋值的schedule()函数参数传进来的那个lambda表达式。也就是说,MessageQueue处理消息时,最终调用的就是onInitializeDisplays()方法。
那么接下来就继续看onInitializeDisplays()方法。
onInitializeDisplays()
//frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
void SurfaceFlinger::onInitializeDisplays() {
const auto display = getDefaultDisplayDeviceLocked();
if (!display) return;
const sp<IBinder> token = display->getDisplayToken().promote();
LOG_ALWAYS_FATAL_IF(token == nullptr);
// reset screen orientation and use primary layer stack
Vector<ComposerState> state;
Vector<DisplayState> displays;
DisplayState d;
d.what = DisplayState::eDisplayProjectionChanged |
DisplayState::eLayerStackChanged;
d.token = token;
d.layerStack = 0;
d.orientation = ui::ROTATION_0;
d.orientedDisplaySpaceRect.makeInvalid();
d.layerStackSpaceRect.makeInvalid();
d.width = 0;
d.height = 0;
displays.add(d);
nsecs_t now = systemTime();
// It should be on the main thread, apply it directly.
applyTransactionState(FrameTimelineInfo{}, state, displays, 0, mInputWindowCommands,
/* desiredPresentTime */ now, true, {}, /* postTime */ now, true, false,
{}, getpid(), getuid(), 0 /* Undefined transactionId */);
setPowerModeInternal(display, hal::PowerMode::ON);
const nsecs_t vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod);
mDefaultDisplayTransformHint = display->getTransformHint();
// Use phase of 0 since phase is not known.
// Use latency of 0, which will snap to the ideal latency.
DisplayStatInfo stats{0 /* vsyncTime */, vsyncPeriod};
setCompositorTimingSnapped(stats, 0);
}
开头直接获取primary display的DisplayDevice,再从中取出和它绑定的身份令牌token。创建一个DisplayState并初始化其内部各个变量,同时将前面的token也保存到其中。将这个DisplayState加入到Vector中保存起来。
再接下来就进入到applyTransactionState()函数中了。
applyTransactionState()
通过传入的参数可以发现:除了刚刚创建的名叫displays的Vector,其他的参数要么是空值要么就是false,没几个实质行的参数传入。这样的话,该函数内部很多部分就执行不到了,暂时就不用关注。
//frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
void SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelineInfo,
const Vector<ComposerState>& states,
const Vector<DisplayState>& displays, uint32_t flags,
const InputWindowCommands& inputWindowCommands,
const int64_t desiredPresentTime, bool isAutoTimestamp,
const client_cache_t& uncacheBuffer,
const int64_t postTime, uint32_t permissions,
bool hasListenerCallbacks,
const std::vector<ListenerCallbacks>& listenerCallbacks,
int originPid, int originUid, uint64_t transactionId) {
uint32_t transactionFlags = 0;
for (const DisplayState& display : displays) {
transactionFlags |= setDisplayStateLocked(display);
}
//省略
if (permissions & Permission::ACCESS_SURFACE_FLINGER) {
transactionFlags |= addInputWindowCommands(inputWindowCommands);
} else if (!inputWindowCommands.empty()) {
ALOGE("Only privileged callers are allowed to send input commands.");
}
//省略
if (transactionFlags) {
//省略
if (transactionFlags) {
setTransactionFlags(transactionFlags);
}
//省略
}
}
把执行不到的内容省略后,看上去还是挺简洁的。
- setDisplayStateLocked()其实挺简单的,就是将mCurrentState和当前的DisplayState的一些值进行比较来判定是否要设置transactionFLags为eDisplayTransactionNeeded。
- addInputWindowCommands()传入的参数在其内部其实就是自己和自己进行运算,返回结果为0。
- setTransactionFlags()函数做了两件事情,其一是更新surfaceflinger中的各项work duration值,其二是向MessageQueue发送invalidate消息。但是这个阶段其实两者都没有执行到。
我们来看下setTransactionFlags()的代码:
setTransactionFlags()
//frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) {
return setTransactionFlags(flags, TransactionSchedule::Late);
}
uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, TransactionSchedule schedule,
const sp<IBinder>& token) {
uint32_t old = mTransactionFlags.fetch_or(flags);
modulateVsync(&VsyncModulator::setTransactionSchedule, schedule, token);
if ((old & flags) == 0) signalTransaction();
return old;
}
其实setTransactionFlags()在前面(onComposerHalHotplug()函数中)已经被调用过一次了,且flags传入的值也是为eDisplayTransactionNeeded,所以在本次调用时获取到的old和当前传入的flags值是一样的,那么本次就不会再调用signalTransaction()。那么,就看看modulateVsync()做了什么事:
//frameworks/native/services/surfaceflinger/SurfaceFlinger.h
template <typename... Args,
typename Handler = VsyncModulator::VsyncConfigOpt (VsyncModulator::*)(Args...)>
void modulateVsync(Handler handler, Args... args) {
if (const auto config = (*mVsyncModulator.*handler)(args...)) {
const auto vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
setVsyncConfig(*config, vsyncPeriod);
}
}
这里的mVsyncModulator已经在前面的章节中讲解过了,不记得的可以翻到前面回顾一下,看下类图就明白了。
其实if()里面执行的就是mVsyncModulator的setTransactionSchedule()函数:
//frameworks/native/services/surfaceflinger/Scheduler/VsyncModulator.cpp
VsyncModulator::VsyncConfigOpt VsyncModulator::setTransactionSchedule(TransactionSchedule schedule,
const sp<IBinder>& token) {
std::lock_guard<std::mutex> lock(mMutex);
switch (schedule) {
case Schedule::EarlyStart:
if (token) {
mEarlyWakeupRequests.emplace(token);
token->linkToDeath(this);
} else {
ALOGW("%s: EarlyStart requested without a valid token", __func__);
}
break;
case Schedule::EarlyEnd: {
if (token && mEarlyWakeupRequests.erase(token) > 0) {
token->unlinkToDeath(this);
} else {
ALOGW("%s: Unexpected EarlyEnd", __func__);
}
break;
}
case Schedule::Late:
// No change to mEarlyWakeup for non-explicit states.
break;
}
if (mTraceDetailedInfo) {
ATRACE_INT("mEarlyWakeup", static_cast<int>(mEarlyWakeupRequests.size()));
}
if (mEarlyWakeupRequests.empty() && schedule == Schedule::EarlyEnd) {
mEarlyTransactionFrames = MIN_EARLY_TRANSACTION_FRAMES;
mEarlyTransactionStartTime = mNow();
}
// An early transaction stays an early transaction.
if (schedule == mTransactionSchedule || mTransactionSchedule == Schedule::EarlyEnd) {
return std::nullopt;
}
mTransactionSchedule = schedule;
return updateVsyncConfigLocked();
}
setTransactionSchedule()函数在此时传入了两个参数:一个为TransactionSchedule::Late,另个为空指针。而且,mVsyncModulator的成员mTransactionSchedule的初始值也为TransactionSchedule::Late,所以,函数执行到最后一个if()条件的时候,schedule == mTransactionSchedule是成立的,故而直接返回std::nullopt,下面的updateVsyncConfigLocked()执行不到。返回到modulateVsync()中的if()条件中config也为空,因此setVsyncConfig()也不会执行。
到这里applyTransactionState()执行结束。
setPowerModeInternal()
该函数传入的参数是primary diplay对应的DisplayDevice和hal::PowerMode::ON。
//frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) {
//省略
const auto displayId = display->getPhysicalId();
ALOGD("Setting power mode %d on display %s", mode, to_string(displayId).c_str());
const hal::PowerMode currentMode = display->getPowerMode();
if (mode == currentMode) {
return;
}
display->setPowerMode(mode);
//省略
const auto vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
if (currentMode == hal::PowerMode::OFF) {
// Keep uclamp in a separate syscall and set it before changing to RT due to b/190237315.
// We can merge the syscall later.
if (SurfaceFlinger::setSchedAttr(true) != NO_ERROR) {
ALOGW("Couldn't set uclamp.min on display on: %s\n", strerror(errno));
}
if (SurfaceFlinger::setSchedFifo(true) != NO_ERROR) {
ALOGW("Couldn't set SCHED_FIFO on display on: %s\n", strerror(errno));
}
getHwComposer().setPowerMode(displayId, mode);
if (display->isPrimary() && mode != hal::PowerMode::DOZE_SUSPEND) {
getHwComposer().setVsyncEnabled(displayId, mHWCVsyncPendingState);
mScheduler->onScreenAcquired(mAppConnectionHandle);
mScheduler->resyncToHardwareVsync(true, vsyncPeriod);
}
mVisibleRegionsDirty = true;
mHasPoweredOff = true;
repaintEverything();
}
//省略
if (display->isPrimary()) {
mTimeStats->setPowerMode(mode);
mRefreshRateStats->setPowerMode(mode);
mScheduler->setDisplayPowerState(mode == hal::PowerMode::ON);
}
ALOGD("Finished setting power mode %d on display %s", mode, to_string(displayId).c_str());
}
获取到的currentMode等于hal::PowerMode::OFF,所以只走第一个条件分支。setPowerMode()的功能:将PowerMode保存进自己的mPowerMode中、使能Output的OutputCompositionState的composition以及暂时设置dirtyRegion为全屏大小,OutputCompositionState的注释还是很丰富的:
//frameworks/native/services/surfaceflinger/CompositionEngine/src/Output.cpp
struct OutputCompositionState {
// If false, composition will not be performed for this display
bool isEnabled{false};
// If false, this output is not considered secure
bool isSecure{false};
// If true, the current frame on this output uses client composition
bool usesClientComposition{false};
// If true, the current frame on this output uses device composition
bool usesDeviceComposition{false};
// If true, the client target should be flipped when performing client composition
bool flipClientTarget{false};
// If true, the current frame reused the buffer from a previous client composition
bool reusedClientComposition{false};
// If true, this output displays layers that are internal-only
bool layerStackInternal{false};
// The layer stack to display on this display
uint32_t layerStackId{~0u};
// The common space for all layers in the layer stack. layerStackSpace.content is the Rect
// which gets projected on the display. The orientation of this space is always ROTATION_0.
ProjectionSpace layerStackSpace;
// Oriented physical display space. It will have the same size as displaySpace oriented to
// match the orientation of layerStackSpace. The orientation of this space is always ROTATION_0.
ProjectionSpace orientedDisplaySpace;
// The space of the framebuffer. Its bounds match the size of the framebuffer and its
// orientation matches the orientation of the display. Typically the framebuffer space will
// be identical to the physical display space.
ProjectionSpace framebufferSpace;
// The space of the physical display. It is as big as the currently active display mode. The
// content in this space can be rotated.
ProjectionSpace displaySpace;
// Transformation from layerStackSpace to displaySpace
ui::Transform transform;
// If true, RenderEngine filtering should be enabled
bool needsFiltering{false};
// The logical coordinates for the dirty region for the display.
// dirtyRegion is semi-persistent state. Dirty rectangles are added to it
// by the FE until composition happens, at which point it is cleared.
Region dirtyRegion;
// The logical coordinates for the undefined region for the display.
// The undefined region is internal to the composition engine. It is
// updated every time the geometry changes.
Region undefinedRegion;
// True if the last composition frame had visible layers
bool lastCompositionHadVisibleLayers{false};
// The color transform matrix to apply
mat4 colorTransformMatrix;
// Current active color mode
ui::ColorMode colorMode{ui::ColorMode::NATIVE};
// Current active render intent
ui::RenderIntent renderIntent{ui::RenderIntent::COLORIMETRIC};
// Current active dataspace
ui::Dataspace dataspace{ui::Dataspace::UNKNOWN};
// Current target dataspace
ui::Dataspace targetDataspace{ui::Dataspace::UNKNOWN};
// The earliest time to send the present command to the HAL
std::chrono::steady_clock::time_point earliestPresentTime;
// The previous present fence. Used together with earliestPresentTime
// to prevent an early presentation of a frame.
std::shared_ptr<FenceTime> previousPresentFence;
// Current display brightness
float displayBrightnessNits{-1.f};
// SDR white point
float sdrWhitePointNits{-1.f};
// Debugging
void dump(std::string& result) const;
};
getHwComposer().setPowerMode()最终会一路调用到HWC中,HWC需要调用DPU driver的接口power on硬件。
getHwComposer().setVsyncEnabled()同样也是调用到HWC中打开硬件VSYNC功能。
mScheduler->onScreenAcquired(mAppConnectionHandle)这个没有仔细的去研究,不过大概是这样的:打开Scheduler中mAppConnectionHandle中的vsync使能(synthetic设置为false)标记位,这里为什么要传入mAppConnectionHandle呢?我个人猜测可能是为BootAnimation的启动服务的,因为它在surfaceflinger启动完成以后就要紧接着运行显示起来,它要通过DisplayEventReceiver取获取vsync信号。
mScheduler->resyncToHardwareVsync()使surfaceflinger内部的vsync模型开始和硬件vsync同步。
最后是更新mTimeStats、mRefreshRateStats、mScheduler三个state的状态。
setCompositorTimingSnapped()函数暂未仔细研究,大概的功能是设置 SurfaceFlinger 的合成器时间,使其与显示的 vsync周期对齐。这有助于减少由于调度抖动(scheduling jitter)引起的合成和显示时间的误差,从而提高显示效果的准确性和一致性。
到这里,initializeDisplays()函数就讲完了。
primeShaderCache
在图形渲染中,着色器(Shader)是用于在 GPU 上执行渲染操作的小程序。着色器需要先编译,然后在运行时链接到特定的渲染管线中。这一过程可能会带来一定的性能开销,特别是在首次使用特定着色器时。
primeShaderCache用于控制是否在启动时预先加载(prime)着色器缓存(shader cache)。这个设置选项的意义在于提高首次渲染性能,减少应用程序在第一次使用特定着色器时的延迟。
但是这个功能有利也有弊,如果打开该功能surfaceflinger启动过程中会导致启动时间延长好几秒。对于开机时间要求比较严格的产品(如车机),建议将该功能关闭。
onPrimaryDisplaySizeChanged()
在之前创建FrameBufferSurface之后已经执行过一次了,不知再执行一次是为了什么,后续再研究。
StartPropertySetThread
首先,从HWC中获取硬件是否具备PRESENT_FENCE_IS_NOT_RELIABLE的能力。然后,创建一个StartPropertySetThread线程并将PRESENT_FENCE_IS_NOT_RELIABLE的结果保存在内,关于PRESENT_FENCE_IS_NOT_RELIABLE这个功能暂时没有去关注过。StartPropertySetThread线程的作用主要是启动Android的BootAnimation动画功能。BootAnimation的停止播放则是由WMS通知。
结尾
到这里,surfaceflinger的启动过程就整体结束了。本节没有去画图了,因为这节内容只创建了一个新内容:StartPropertySetThread。其他的内容在前面的章节都总结过了。
总体来看,启动过程还是蛮复杂的,画时间去整理一遍是很有必要的。