上一篇文章學到了應用層請求Vsync的邏輯,其中SF[1]部分由於涉及流程太長跳過了,今天這篇文章就是SF篇了,在接著上章的流程跟蹤之前,需要介紹一些前置信息,一些關鍵部分是如何被初始化的以及他們之間的大概關係,了解了這些之後去跟蹤流程才會相對輕鬆一些.
在Android顯示管道中,SF主要負責其中的一環:接受緩衝區,對它們進行合成,然後發送到屏幕.另外它還負責處理HWVsync[2] 並生產SWVsync[3] 分發給關注此事件的消費者.
從bp文件中,我們可以看到入口文件,所以我們也就從這裡著手開始跟蹤:
filegroup {
name: "surfaceflinger_binary_sources",
srcs: ["main_surfaceflinger.cpp"],
}
cc_binary {
name: "surfaceflinger",
defaults: ["libsurfaceflinger_binary"],
init_rc: ["surfaceflinger.rc"],
srcs: [":surfaceflinger_binary_sources"],
shared_libs: [
"libsurfaceflinger",
"libSurfaceFlingerProp",
],
}
mainint main(int, char**) {
signal(SIGPIPE, SIG_IGN);
hardware::configureRpcThreadpool(1 /* maxThreads */,
false /* callerWillJoin */);
startGraphicsAllocatorService();
ProcessState::self()->setThreadPoolMaxThreadCount(4);
sp<ProcessState> ps(ProcessState::self());
ps->startThreadPool();
sp<SurfaceFlinger> flinger = surfaceflinger::createSurfaceFlinger();
...
flinger->init();
sp<IServiceManager> sm(defaultServiceManager());
sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
...
// run surface flinger in this thread
flinger->run();
return 0;
}mian函數執行時主要執行的大都是一些線程參數以及服務的配置操作:
實例化SurfaceFlinger,並調用init函數.調用SurfaceFlinger.run,進入消息隊列循環.initclass SurfaceFlinger : public BnSurfaceComposer,
public PriorityDumper,
public ClientCache::ErasedRecipient,
private IBinder::DeathRecipient,
private HWC2::ComposerCallback,
private ISchedulerCallback;
void SurfaceFlinger::init() {
Mutex::Autolock _l(mStateLock);
// Get a RenderEngine for the given display / config (can't fail)
int32_t renderEngineFeature = 0;
renderEngineFeature |= (useColorManagement ?
renderengine::RenderEngine::USE_COLOR_MANAGEMENT : 0);
renderEngineFeature |= (useContextPriority ?
renderengine::RenderEngine::USE_HIGH_PRIORITY_CONTEXT : 0);
renderEngineFeature |=
(enable_protected_contents(false) ? renderengine::RenderEngine::ENABLE_PROTECTED_CONTEXT
: 0);
...
mCompositionEngine->setRenderEngine(
renderengine::RenderEngine::create(static_cast<int32_t>(defaultCompositionPixelFormat),
renderEngineFeature, maxFrameBufferAcquiredBuffers));
mCompositionEngine->setHwComposer(getFactory().createHWComposer(getBE().mHwcServiceName));
mCompositionEngine->getHwComposer().registerCallback(this, getBE().mComposerSequenceId);
// Process any initial hotplug and resulting display changes.
processDisplayHotplugEventsLocked();
const auto display = getDefaultDisplayDeviceLocked();
...
if (useVrFlinger) {
...
}
// initialize our drawing state
mDrawingState = mCurrentState;
// set initial conditions (e.g. unblank default device)
initializeDisplays();
getRenderEngine().primeCache();
...
}
初始化CompositionEngine的各項參數,包括Render與HWC服務.註冊HWC的Listener,當註冊成功後,HWC會首先回調一次onHotplugReceived,SF會調用processDisplayHotplugEventsLocked來處理該事件.進行Shader緩存,這個流程在部分設備上會佔用非常久的時間,但該流程並不是必須的,你可以選擇不在這裡進行Shader緩存,這可以一定程度加速你的系統啟動流程.記住initializeDisplays這裡會向隊列中添加一個消息用於執行onInitializeDisplays,但是由於隊列還未循環起來,所以該事件會在後面執行(SurfaceFlinger.run).onHotplugReceivedvoid SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
HWC2::Connection connection) {
...
ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
mPendingHotplugEvents.emplace_back(HotplugEvent{hwcDisplayId, connection});
if (std::this_thread::get_id() == mMainThreadId) {
// Process all pending hot plug events immediately if we are on the main thread.
processDisplayHotplugEventsLocked();
}
...
}
void SurfaceFlinger::processDisplayHotplugEventsLocked() {
for (const auto& event : mPendingHotplugEvents) {
const std::optional<DisplayIdentificationInfo> info =
getHwComposer().onHotplug(event.hwcDisplayId, event.connection);
if (!info) {
continue;
}
if (event.connection == HWC2::Connection::Connected) {
if (!mPhysicalDisplayTokens.count(info->id)) {
ALOGV("Creating display %s", to_string(info->id).c_str());
if (event.hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) {
initScheduler(info->id);
}
mPhysicalDisplayTokens[info->id] = new BBinder();
DisplayDeviceState state;
state.displayId = info->id;
state.isSecure = true; // All physical displays are currently considered secure.
state.displayName = info->name;
mCurrentState.displays.add(mPhysicalDisplayTokens[info->id], state);
mInterceptor->saveDisplayCreation(state);
}
} else {
...
}
processDisplayChangesLocked();
}
mPendingHotplugEvents.clear();
}
前面我們註冊HWC listener後,HWC通常會迅速上報一個Connected事件.在該事件回調後,針對內置的物理顯示器我們會執行Scheduler的創建初始化工作.initScheduler從名字也可以大概看出來他的作用啦,主要負責初始化Scheduler,這裡會創建並運行多條線程,主要是如下:
DispSyncThread 用於根據HWVsync生成對應的SWVsync.EventControlThread 用於開關HWVsync.後續還會創建至少兩條線程,分別為EventThread(sf),EventThread(app) 用於處理回調註冊在各自線程上的DisplayEventReceiver.他們之間的關係如下:
void SurfaceFlinger::initScheduler(DisplayId primaryDisplayId) {
if (mScheduler) {
return;
}
...
// start the EventThread
mScheduler =
getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); },
*mRefreshRateConfigs);
mAppConnectionHandle =
mScheduler->createConnection("app", mVsyncModulator.getOffsets().app,
mPhaseOffsets->getOffsetThresholdForNextVsync(),
impl::EventThread::InterceptVSyncsCallback());
mSfConnectionHandle =
mScheduler->createConnection("sf", mVsyncModulator.getOffsets().sf,
mPhaseOffsets->getOffsetThresholdForNextVsync(),
[this](nsecs_t timestamp) {
mInterceptor->saveVSyncEvent(timestamp);
});
mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle));
mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(),
mSfConnectionHandle.get());
mRegionSamplingThread =
new RegionSamplingThread(*this, *mScheduler,
RegionSamplingThread::EnvironmentTimingTunables());
mScheduler->setChangeRefreshRateCallback(
[this](RefreshRateType type, Scheduler::ConfigEvent event) {
Mutex::Autolock lock(mStateLock);
setRefreshRateTo(type, event);
});
}
void MessageQueue::setEventConnection(const sp<EventThreadConnection>& connection) {
if (mEventTube.getFd() >= 0) {
mLooper->removeFd(mEventTube.getFd());
}
mEvents = connection;
mEvents->stealReceiveChannel(&mEventTube);
mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver,
this);
}
創建Scheduler,注意傳入的第一個參數,是個Lambda表達式,供Scheduler內進行回調,對應的函數為setPrimaryVsyncEnabled(enabled),其真正作用是控制HWVsync的開關.通過Scheduler構造兩個ConnectionHandle[4],分別為sf和app,用來處理不同的Connection.(SWVsync都是通過Connection來通知消費者的).setEventConnection這個函數實現是不是很熟悉的感覺,是的,這裡作為sf Vsync的消費者,其實現與上一章的DisplayEventReceiver裡的處理步驟是完全一樣的.創建SchedulerScheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function,
const scheduler::RefreshRateConfigs& refreshRateConfig)
: mHasSyncFramework(running_without_sync_framework(true)),
mDispSyncPresentTimeOffset(present_time_offset_from_vsync_ns(0)),
mPrimaryHWVsyncEnabled(false),
mHWVsyncAvailable(false),
mRefreshRateConfigs(refreshRateConfig) {
// Note: We create a local temporary with the real DispSync implementation
// type temporarily so we can initialize it with the configured values,
// before storing it for more generic use using the interface type.
auto primaryDispSync = std::make_unique<impl::DispSync>("SchedulerDispSync");
primaryDispSync->init(mHasSyncFramework, mDispSyncPresentTimeOffset);
mPrimaryDispSync = std::move(primaryDispSync);
mEventControlThread = std::make_unique<impl::EventControlThread>(function);
...
}在Scheduler被構造時,它會同時構造創建如下關鍵類:
創建並啟動EventControlThread,注意這裡將我們之前傳入的callback直接給到了EventControlThread.真正調用callback的地方是EventControlThread.創建DispSyncDispSync::DispSync(const char* name) : mName(name), mRefreshSkipCount(0) {
// This flag offers the ability to turn on systrace logging from the shell.
char value[PROPERTY_VALUE_MAX];
property_get("debug.sf.dispsync_trace_detailed_info", value, "1");
mTraceDetailedInfo = atoi(value);
mThread = new DispSyncThread(name, mTraceDetailedInfo);
}
void DispSync::init(bool hasSyncFramework, int64_t dispSyncPresentTimeOffset) {
mIgnorePresentFences = !hasSyncFramework;
mPresentTimeOffset = dispSyncPresentTimeOffset;
mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
// set DispSync to SCHED_FIFO to minimize jitter
struct sched_param param = {0};
param.sched_priority = 2;
if (sched_setscheduler(mThread->getTid(), SCHED_FIFO, ¶m) != 0) {
ALOGE("Couldn't set SCHED_FIFO for DispSyncThread");
}
android_set_rt_ioprio(mThread->getTid(), 1);
beginResync();
if (mTraceDetailedInfo && kEnableZeroPhaseTracer) {
mZeroPhaseTracer = std::make_unique<ZeroPhaseTracer>();
addEventListener("ZeroPhaseTracer", 0, mZeroPhaseTracer.get(), 0);
}
}
DispSync的構成也比較簡單,其內部會維護一條線程DispSyncThread.在init啟動並設置DispSyncThread.beginResync的作用是為後續通過HWVsync更新模型參數,重置所有參數,並unlock sync模型.線程工作起來後,將會執行到threadLoop函數.具體其工作時的流程我們後面再細跟.創建EventControlThreadEventControlThread::EventControlThread(EventControlThread::SetVSyncEnabledFunction function)
: mSetVSyncEnabled(function) {
pthread_setname_np(mThread.native_handle(), "EventControlThread");
pid_t tid = pthread_gettid_np(mThread.native_handle());
setpriority(PRIO_PROCESS, tid, ANDROID_PRIORITY_URGENT_DISPLAY);
set_sched_policy(tid, SP_FOREGROUND);
android_set_rt_ioprio(tid, 1);
}
EventControlThread::~EventControlThread() {
{
std::lock_guard<std::mutex> lock(mMutex);
mKeepRunning = false;
mCondition.notify_all();
}
mThread.join();
}
void EventControlThread::setVsyncEnabled(bool enabled) {
std::lock_guard<std::mutex> lock(mMutex);
mVsyncEnabled = enabled;
mCondition.notify_all();
}
// Unfortunately std::unique_lock gives warnings with -Wthread-safety
void EventControlThread::threadMain() NO_THREAD_SAFETY_ANALYSIS {
auto keepRunning = true;
auto currentVsyncEnabled = false;
while (keepRunning) {
mSetVSyncEnabled(currentVsyncEnabled);
std::unique_lock<std::mutex> lock(mMutex);
mCondition.wait(lock, [this, currentVsyncEnabled, keepRunning]() NO_THREAD_SAFETY_ANALYSIS {
return currentVsyncEnabled != mVsyncEnabled || keepRunning != mKeepRunning;
});
currentVsyncEnabled = mVsyncEnabled;
keepRunning = mKeepRunning;
}
}
這條線程的作用和代碼比較簡單,一眼就可以全部看完,就是負責調用mSetVSyncEnabled,開關HWVsync.mSetVSyncEnabled就是我們在initScheduler內傳入的Lambda:setPrimaryVsyncEnabled(enabled).調用setVsyncEnabled函數等價於調用SurfaceFlinger.setPrimaryVsyncEnabled.創建EventThreadsp<Scheduler::ConnectionHandle> Scheduler::createConnection(
const char* connectionName, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync,
impl::EventThread::InterceptVSyncsCallback interceptCallback) {
const int64_t id = sNextId++;
ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id);
std::unique_ptr<EventThread> eventThread =
makeEventThread(connectionName, mPrimaryDispSync.get(), phaseOffsetNs,
offsetThresholdForNextVsync, std::move(interceptCallback));
auto eventThreadConnection =
createConnectionInternal(eventThread.get(), ISurfaceComposer::eConfigChangedSuppress);
mConnections.emplace(id,std::make_unique<Connection>(new ConnectionHandle(id),
eventThreadConnection,
std::move(eventThread)));
return mConnections[id]->handle;
}
std::unique_ptr<EventThread> Scheduler::makeEventThread(
const char* connectionName, DispSync* dispSync, nsecs_t phaseOffsetNs,
nsecs_t offsetThresholdForNextVsync,
impl::EventThread::InterceptVSyncsCallback interceptCallback) {
std::unique_ptr<VSyncSource> eventThreadSource =
std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, offsetThresholdForNextVsync,
true, connectionName);
return std::make_unique<impl::EventThread>(std::move(eventThreadSource),
std::move(interceptCallback), connectionName);
}
EventThread::EventThread(VSyncSource* src, std::unique_ptr<VSyncSource> uniqueSrc,
InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName)
: mVSyncSource(src),
mVSyncSourceUnique(std::move(uniqueSrc)),
mInterceptVSyncsCallback(std::move(interceptVSyncsCallback)),
mThreadName(threadName) {
if (src == nullptr) {
mVSyncSource = mVSyncSourceUnique.get();
}
mVSyncSource->setCallback(this);
mThread = std::thread([this]() NO_THREAD_SAFETY_ANALYSIS {
std::unique_lock<std::mutex> lock(mMutex);
threadMain(lock);
});
pthread_setname_np(mThread.native_handle(), threadName);
...
}
上面scheduler的創建流程執行結束,那麼接下來就是創建eventThread.針對單個Connection可以傳入不同的偏移量,即Vsync偏移,該值具體作用以後細看.首先需要創建DispSyncSource,注意這裡我們將vsync偏移設置給你它.這個類的作用實際上是將EventThread和DispSyncThread聯繫起來.接下來創建EventThread,需要將之前創建的DispSyncSource以及connectionName(sf/app)傳入,其內部會調用DispSyncSource的setCallBack將自己設置為callback.以上創建的兩個對象,會被封裝為Connection,以id為key,裝入mConnections保存起來.以上幾條線程正常工作時的關係大致如下圖所示,圖中的細節我們的文章後面都會慢慢涉及到:
onInitializeDisplays以上,SurfaceFlinger的初始化工作就基本完成了,但是還有關鍵的一點主線程循環還未開始,並且由於顯示設備還未打開HWVsync還未上報,所以DispSync也還未進入正常循環.記得我們前面有說到的,initializeDisplays裡面post了一個消息到隊列中,而當flinger.run執行到,主線程循環就進入消息隊列循環了,這個消息也會首先得到執行:
void SurfaceFlinger::onInitializeDisplays() {
...
setPowerModeInternal(display, HWC_POWER_MODE_NORMAL);
...
}
void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, int mode) {
...
if (currentMode == HWC_POWER_MODE_OFF) {
// Turn on the display
getHwComposer().setPowerMode(*displayId, mode);
if (display->isPrimary() && mode != HWC_POWER_MODE_DOZE_SUSPEND) {
setVsyncEnabledInHWC(*displayId, mHWCVsyncPendingState);
mScheduler->onScreenAcquired(mAppConnectionHandle);
mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
}
mVisibleRegionsDirty = true;
mHasPoweredOff = true;
repaintEverything();
struct sched_param param = {0};
param.sched_priority = 1;
if (sched_setscheduler(0, SCHED_FIFO, ¶m) != 0) {
ALOGW("Couldn't set SCHED_FIFO on display on");
}
} else if (mode == HWC_POWER_MODE_OFF) {
...
}這個函數作用很關鍵,但是流程很簡單,就是打開顯示設備以及開啟該設備的HWVsync
首先判斷當前display的開關狀態,若為關閉狀態則通過HWC進入打開流程.設置合成引擎的狀態,以及調用resyncToHardwareVsync開啟HWVsync,並且傳入一個period,這個值是從hal獲取到的config中取到的,表示顯示設備的刷新周期,例如60HZ的顯示設備,該值為16.666666.resyncToHardwareVsyncvoid Scheduler::resyncToHardwareVsync(bool makeAvailable, nsecs_t period) {
{
std::lock_guard<std::mutex> lock(mHWVsyncLock);
if (makeAvailable) {
mHWVsyncAvailable = makeAvailable;
} else if (!mHWVsyncAvailable) {
return;
}
}
if (period <= 0) {
return;
}
setVsyncPeriod(period);
}
void Scheduler::setVsyncPeriod(const nsecs_t period) {
std::lock_guard<std::mutex> lock(mHWVsyncLock);
mPrimaryDispSync->setPeriod(period);
if (!mPrimaryHWVsyncEnabled) {
mPrimaryDispSync->beginResync();
mEventControlThread->setVsyncEnabled(true);
mPrimaryHWVsyncEnabled = true;
}
}
首先,這裡會將之前獲取到的顯示設備刷新周期設置到DispSync中保存在mPendingPeriod中.另外根據咱們之前對各個線程的了解,我們已經知道setVsyncEnabled會喚醒EventControlThread打開HWVsync,而HWVsync是通過之前註冊到HWC的ComposerCallback(SurfaceFlinger)來通知的.到這裡,SurfaceFlinger的線程進入循環準備接受HWVsync並設置其他線程依賴的參數使其他線程也可以進入正常的循環中.所以下一篇預計將要學習一下SurfaceFlinger是如何處理HWVsync信號的.DispSync是按照怎樣的一個模型生成SWVsync的,生成的SWVsync又是如何和我們第一篇分析的流程接上的.
參考資料[1]SF: SurfaceFlinger
[2]HWVsync: 指由顯示設備產生的垂直同步信號。
[3]SWVsync: 指軟體模擬產生的垂直同步信號。
[4]ConnectionHandle: 一個不透明句柄,用於標識一個Connection,