View繪制流程2-安卓如何執(zhí)行measure/draw 全球最新
前言:
vsync信號(hào)其實(shí)主要有兩種,APP和SF兩種。
(資料圖)
兩種類(lèi)似的信號(hào)分別具有以下的作用:
1.APP類(lèi)型,我們常說(shuō)的Vsync信號(hào)其實(shí)指的就是這種類(lèi)型。
2.SF類(lèi)型,我感覺(jué)有可能是SurfaceFlinger的縮寫(xiě),這個(gè)同步信號(hào)主要是通知進(jìn)行數(shù)據(jù)buffer的合成。
本文主要探討的主APP類(lèi)型的Vsync信號(hào),SF類(lèi)型的會(huì)在另外一篇文章,View繪制流程中講解。
一.整體流程簡(jiǎn)介
我把a(bǔ)pp-VSync的整個(gè)流程分為四大塊:
第一塊,APP側(cè)發(fā)出請(qǐng)求信號(hào),通知到SurfaceFlinger;
第二塊,SurfaceFlinger收到通知后,作為消費(fèi)者側(cè)去緩存池中查詢(xún)是否存在VSYNC,如果有,則通知APP側(cè)。
第三塊,SurfaceFlinger中的生產(chǎn)者邏輯,生產(chǎn)下一次的Vsync信號(hào)。
第四塊,APP側(cè)收到Vsync信號(hào)后進(jìn)行處理,最終完成繪制流程。
整體的流程圖如下圖所示,后續(xù)文章也會(huì)按照這四大塊流程去細(xì)講。
二.客戶(hù)端發(fā)出信號(hào)
2.1 java端流轉(zhuǎn)
我們把代碼的開(kāi)始點(diǎn)設(shè)置為ViewRootImpl中的scheduleTraversals方法,如果想了解這個(gè)方法之前的流程,可以參看我的另外一篇文章:
View繪制流程2-安卓是如何執(zhí)行measure/layout/draw三個(gè)繪制流程_失落夏天的博客-CSDN博客
scheduleTraversals是負(fù)責(zé)渲染流程的,界面上任何布局上的改動(dòng),最終都會(huì)執(zhí)行這個(gè)方法進(jìn)行刷新操作。scheduleTraversals會(huì)通過(guò)Choreographer的postCallback方法去請(qǐng)求Vsync信號(hào)并且設(shè)置回調(diào)方法。
mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
Choreographer中的最終實(shí)現(xiàn)是postCallbackDelayedInternal方法:
private void postCallbackDelayedInternal(int callbackType, Object action, Object token, long delayMillis) { ... synchronized (mLock) { final long now = SystemClock.uptimeMillis(); final long dueTime = now + delayMillis; mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token); if (dueTime <= now) { scheduleFrameLocked(now); } ... } }
這個(gè)方法會(huì)把回調(diào)加入到mCallbackQueues中,然后通過(guò)scheduleFrameLocked方法開(kāi)始請(qǐng)求Vsync信號(hào)。
scheduleFrameLocked中又會(huì)進(jìn)行層層傳遞,最終調(diào)用到native方法。傳遞關(guān)系如下:
scheduleFrameLocked(Choreographer.java)->scheduleVsyncLocked(Choreographer.java)->scheduleVsync(DisplayEventReceiver.java)->nativeScheduleVsync(DisplayEventReceiver.java)
2.2 native方法中的邏輯流轉(zhuǎn)
nativeScheduleVsync在native層的注冊(cè)是DisplayEventReceiver.cpp中的nativeScheduleVsync方法,方法中通過(guò)NativeDisplayEventReceiver的scheduleVsync來(lái)完成請(qǐng)求:
static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) { spreceiver = reinterpret_cast(receiverPtr); status_t status = receiver->scheduleVsync(); ...}
NativeDisplayEventReceiver是DisplayEventDispatcher的子類(lèi),scheduleVsync方法會(huì)執(zhí)行到DisplayEventDispatcher中的scheduleVsync方法,調(diào)用DisplayEventReceiver的requestNextVsync繼續(xù)請(qǐng)求流程。
status_t DisplayEventDispatcher::scheduleVsync() { if (!mWaitingForVsync) { ... status_t status = mReceiver.requestNextVsync(); ... mWaitingForVsync = true; ... } return OK;}
這里有一個(gè)本地變量mWaitingForVsync,如果請(qǐng)求了一次sync,就會(huì)改為true,接下來(lái)的Vsync請(qǐng)求,都不會(huì)傳輸?shù)絊urfaceFlinger一層了,避免重復(fù)無(wú)意義請(qǐng)求。只有等到收到Vsync信號(hào)的時(shí)候,才會(huì)改為false。
DisplayEventReceiver中,會(huì)交給mEventConnection處理:
status_t DisplayEventReceiver::requestNextVsync() { if (mEventConnection != nullptr) { mEventConnection->requestNextVsync(); return NO_ERROR; } return NO_INIT;}
mEventConnection其實(shí)是一個(gè)binder客戶(hù)端,是在創(chuàng)建DisplayEventReceiver的時(shí)候通過(guò)binder方法創(chuàng)建的,其binder服務(wù)端實(shí)現(xiàn)在SurfaceFlinger進(jìn)程側(cè)的EventThread.cpp。
DisplayEventReceiver::DisplayEventReceiver( ISurfaceComposer::VsyncSource vsyncSource, ISurfaceComposer::EventRegistrationFlags eventRegistration) { spsf(ComposerService::getComposerService()); if (sf != nullptr) { mEventConnection = sf->createDisplayEventConnection(vsyncSource, eventRegistration); ... }}
三.SurfaceFlinger端Vsync信號(hào)消費(fèi)者
首先,SurfaceFlinger的總體結(jié)構(gòu)圖如下,SurfaceFlinger中存在一個(gè)Scheduler,Scheduler中存在多個(gè)VsyncDispatch。其中VSYNC-app負(fù)責(zé)所有APP的VSYNC信號(hào)的處理,本文主要講的也是這個(gè)流程中的。
其次,下圖是主流程圖中的一部分,也是本章要講的內(nèi)容。
3.1 EventThread收到通知后,轉(zhuǎn)發(fā)EventThread的工作線(xiàn)程
是接收方法如下,轉(zhuǎn)發(fā)到mEventThread的requestNextVsync方法中。
binder::Status EventThreadConnection::requestNextVsync() { ATRACE_CALL(); mEventThread->requestNextVsync(this); return binder::Status::ok();}
我們接著看一下EventThread中的requestNextVsync方法:
void EventThread::requestNextVsync(const sp& connection) { ... if (connection->vsyncRequest == VSyncRequest::None) { connection->vsyncRequest = VSyncRequest::Single; mCondition.notify_all(); } else if (connection->vsyncRequest == VSyncRequest::SingleSuppressCallback) { connection->vsyncRequest = VSyncRequest::Single; }}
這里的邏輯很簡(jiǎn)單,如果當(dāng)前的VSYNC狀態(tài)是None的話(huà),釋放鎖mCondition。
這里既然notify_all,那么一定有地方wait等待鎖,而等待的地方就是threadMain方法。
3.2 threadMain方法
這個(gè)方法算是整個(gè)Vsync流程的核心,它是一個(gè)無(wú)限循環(huán)的模式,其作用是不斷的從mPendingEvents中獲取Vsync信號(hào),然后轉(zhuǎn)交給APP端。并且在一次Vsync流程結(jié)束后,又通過(guò)VsyncSource請(qǐng)求下一次的Vsync信號(hào)。
threadMain方法是EventThread類(lèi)初始化的時(shí)候創(chuàng)建的線(xiàn)程去執(zhí)行的方法:
mThread = std::thread([this]() NO_THREAD_SAFETY_ANALYSIS { std::unique_locklock(mMutex); threadMain(lock); });
我們看一下精簡(jiǎn)后的threadMain方法:
void EventThread::threadMain(std::unique_lock& lock) { DisplayEventConsumers consumers; //只要沒(méi)有退出,就一直循環(huán) while (mState != State::Quit) { 執(zhí)行以下1-7的操作 }}
總體來(lái)說(shuō),分為以下四大步驟:
1.作為消費(fèi)者嘗試從mPendingEvents中獲取Vsync信號(hào),如果獲取成功,則賦值給event。
std::optionalevent; //查看mPendingEvents中是否存在Vsync信號(hào) if (!mPendingEvents.empty()) { event = mPendingEvents.front(); mPendingEvents.pop_front(); ... }
2.計(jì)算vsyncRequested的狀態(tài),只要客戶(hù)端消費(fèi)者的Connection保持連接,則vsyncRequested=true,并且上面步驟一獲取到event的話(huà),則把消費(fèi)者的connection加入到consumers集合中。
bool vsyncRequested = false; //獲取當(dāng)前的狀態(tài),并且判斷是否有客戶(hù)端的消費(fèi)者在請(qǐng)求,如果有則加入到consumers集合中 auto it = mDisplayEventConnections.begin(); while (it != mDisplayEventConnections.end()) { if (const auto connection = it->promote()) { //客戶(hù)端還是處于請(qǐng)求的狀態(tài) vsyncRequested |= connection->vsyncRequest != VSyncRequest::None; if (event && shouldConsumeEvent(*event, connection)) { consumers.push_back(connection); } ++it; } else { it = mDisplayEventConnections.erase(it); } }
3.如果consumers集合不為空,則進(jìn)行消費(fèi)。把Vsync信號(hào)分發(fā)給消費(fèi)者。(具體步驟我們下一小節(jié)中講)
//如果消費(fèi)者不為空,則通過(guò)dispatchEvent方法最終通知到APP一側(cè) if (!consumers.empty()) { dispatchEvent(*event, consumers); consumers.clear(); }
4.獲取下一個(gè)狀態(tài)
//mVSyncState不會(huì)為空,則主要是根據(jù)vsyncRequested來(lái)判斷的。vsyncRequested上面計(jì)算的 State nextState; if (mVSyncState && vsyncRequested) { nextState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync; } else { ALOGW_IF(!mVSyncState, "Ignoring VSYNC request while display is disconnected"); nextState = State::Idle; }
5.進(jìn)行判斷,確定是否需要請(qǐng)求VSYNC信號(hào)。這一塊挺有意思的,簡(jiǎn)單理解如下:
如果當(dāng)前是VSYNC狀態(tài),下一個(gè)狀態(tài)也是VSYNC狀態(tài),那么說(shuō)明信號(hào)還沒(méi)來(lái),所以沒(méi)必要重復(fù)發(fā)送。
如果當(dāng)前是Idle狀態(tài),下一個(gè)狀態(tài)是VSYNC狀態(tài),那么則要進(jìn)行VSYNC信號(hào)請(qǐng)求。
如果當(dāng)前是VSYNC狀態(tài),下一個(gè)狀態(tài)也是Idle狀態(tài),那么說(shuō)明信號(hào)已經(jīng)來(lái)了,下一次的客戶(hù)端請(qǐng)求還沒(méi)來(lái),所以不要進(jìn)行VSYNC信號(hào)請(qǐng)求,則會(huì)進(jìn)行取消操作。
if (mState != nextState) { if (mState == State::VSync) { mVSyncSource->setVSyncEnabled(false); } else if (nextState == State::VSync) { //如果下一個(gè)狀態(tài)還是VSync,則繼續(xù)去請(qǐng)求VSYNC信號(hào) mVSyncSource->setVSyncEnabled(true); } mState = nextState; }
如何開(kāi)始和結(jié)束去進(jìn)行VSYNC信號(hào)獲取的獲取操作,我們第四章中講,這個(gè)主要就是消費(fèi)者邏輯了。
6.如果event為空,說(shuō)明mPendingEvents中已經(jīng)取光了,則進(jìn)入休眠操作。
反之event不為空,說(shuō)明mPendingEvents中也許還存在未消費(fèi)的VSYNC信號(hào),則contine繼續(xù)消費(fèi)。
//如果處理了event,那么說(shuō)明此次已經(jīng)拿到了Vsync信號(hào),說(shuō)明后面有可能還有,則繼續(xù)拿 if (event) { continue; }
7.進(jìn)入休眠或者超時(shí)之后主動(dòng)模擬信號(hào)加入到mPendingEvents中。
//說(shuō)明Vsync信號(hào)已經(jīng)消費(fèi)完了,則進(jìn)入休眠模式,等到APP側(cè)的下一次通知進(jìn)行喚醒 // Wait for event or client registration/request. if (mState == State::Idle) { mCondition.wait(lock); } else { // Generate a fake VSYNC after a long timeout in case the driver stalls. When the // display is off, keep feeding clients at 60 Hz. const std::chrono::nanoseconds timeout = mState == State::SyntheticVSync ? 16ms : 1000ms; if (mCondition.wait_for(lock, timeout) == std::cv_status::timeout) { if (mState == State::VSync) { ALOGW("Faking VSYNC due to driver stall for thread %s", mThreadName); std::string debugInfo = "VsyncSource debug info:\n"; mVSyncSource->dump(debugInfo); // Log the debug info line-by-line to avoid logcat overflow auto pos = debugInfo.find("\n"); while (pos != std::string::npos) { ALOGW("%s", debugInfo.substr(0, pos).c_str()); debugInfo = debugInfo.substr(pos + 1); pos = debugInfo.find("\n"); } } LOG_FATAL_IF(!mVSyncState); const auto now = systemTime(SYSTEM_TIME_MONOTONIC); const auto deadlineTimestamp = now + timeout.count(); const auto expectedVSyncTime = deadlineTimestamp + timeout.count(); mPendingEvents.push_back(makeVSync(mVSyncState->displayId, now, ++mVSyncState->count, expectedVSyncTime, deadlineTimestamp)); } }
3.3 dispatchEvent方法把Vsync信號(hào)分發(fā)給消費(fèi)者
首先遍歷消費(fèi)者,調(diào)用postEvent進(jìn)行通知
void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event, const DisplayEventConsumers& consumers) { for (const auto& consumer : consumers) { ... switch (consumer->postEvent(copy)) { } }}
然后postEvent方法中,調(diào)用sendEvent進(jìn)行信號(hào)的發(fā)送
status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) { ... auto size = DisplayEventReceiver::sendEvents(&mChannel, mPendingEvents.data(), mPendingEvents.size()); ...}
最終通過(guò)Socket的方法進(jìn)行信號(hào)的發(fā)送,接受者就是APP側(cè)了。
ssize_t DisplayEventReceiver::sendEvents(gui::BitTube* dataChannel, Event const* events, size_t count){ return gui::BitTube::sendObjects(dataChannel, events, count);}
四.SurfaceFlinger端生產(chǎn)者
上面講到通過(guò)setVSyncEnabled方法去開(kāi)始或者結(jié)束獲取Vsync信號(hào)的操作。
4.1 獲取VSYNC信號(hào)
setVSyncEnabled方法如下:
void DispSyncSource::setVSyncEnabled(bool enable) { std::lock_guard lock(mVsyncMutex); if (enable) { mCallbackRepeater->start(mWorkDuration, mReadyDuration); } else { mCallbackRepeater->stop(); } mEnabled = enable;}
對(duì)應(yīng)的其實(shí)就是mCallbackRepeater的start和stop方法,其實(shí)現(xiàn)類(lèi)是DispSyncSource.cpp中的CallbackRepeater。
我們這里看到一個(gè)成員變量mWorkDuration,這個(gè)值其實(shí)就是控制Vscyn觸發(fā)時(shí)間的。這個(gè)我們后續(xù)小節(jié)再講,這里只是知道有這個(gè)值就好了。
4.2 把時(shí)間設(shè)置給Timer定時(shí)觸發(fā)
start方法中,記錄一下傳入的workDuration時(shí)間,然后傳遞給mRegistration處理。
void start(std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration) { std::lock_guard lock(mMutex); mStarted = true; mWorkDuration = workDuration; mReadyDuration = readyDuration; auto const scheduleResult = mRegistration.schedule({.workDuration = mWorkDuration.count(), .readyDuration = mReadyDuration.count(), .earliestVsync = mLastCallTime.count()}); }
mRegistration的實(shí)現(xiàn)類(lèi)是VSyncCallbackRegistration,其中schedule方法也是交給VSyncDispatchTimerQueue來(lái)處理:
ScheduleResult VSyncCallbackRegistration::schedule(VSyncDispatch::ScheduleTiming scheduleTiming) { if (!mValidToken) { return std::nullopt; } return mDispatch.get().schedule(mToken, scheduleTiming);}
schedule方法中,進(jìn)行一系列的合法判斷,最終會(huì)交給 rearmTimerSkippingUpdateFor方法處理。
然后我們就可以看到rearmTimerSkippingUpdateFor中去調(diào)用setTimer方法去設(shè)置定時(shí)觸發(fā)。
rearmTimerSkippingUpdateFor方法略,
setTimer方法如下:
void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t /*now*/) { mIntendedWakeupTime = targetTime; mTimeKeeper->alarmAt(std::bind(&VSyncDispatchTimerQueue::timerCallback, this), mIntendedWakeupTime); mLastTimerSchedule = mTimeKeeper->now();}
則到了targetTime之后,就會(huì)執(zhí)行timerCallBack方法。
4.3 生成Vsync信號(hào)加入mPendingEvents
timerCallback方法如下:
void VSyncDispatchTimerQueue::timerCallback() { struct Invocation { std::shared_ptrcallback; nsecs_t vsyncTimestamp; nsecs_t wakeupTimestamp; nsecs_t deadlineTimestamp; }; std::vectorinvocations; { std::lock_guard lock(mMutex); auto const now = mTimeKeeper->now(); mLastTimerCallback = now; for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) { auto& callback = it->second; auto const wakeupTime = callback->wakeupTime(); if (!wakeupTime) { continue; } auto const readyTime = callback->readyTime(); auto const lagAllowance = std::max(now - mIntendedWakeupTime, static_cast(0)); if (*wakeupTime < mIntendedWakeupTime + mTimerSlack + lagAllowance) { callback->executing(); invocations.emplace_back(Invocation{callback, *callback->lastExecutedVsyncTarget(), *wakeupTime, *readyTime}); } } mIntendedWakeupTime = kInvalidTime; rearmTimer(mTimeKeeper->now()); } for (auto const& invocation : invocations) { invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp, invocation.deadlineTimestamp); }
這里的核心邏輯其實(shí)就是遍歷mCallbacks,然后分別回調(diào)。
那么mCallbacks是怎么添加的呢? CallbackRepeater創(chuàng)建的時(shí)候,回去注冊(cè) mRegistration,同時(shí)會(huì)傳入CallbackRepeater::callback方法作為回調(diào),所以mCallbacks其實(shí)就是CallbackRepeater::callback。
void callback(nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime) { ... mCallback(vsyncTime, wakeupTime, readyTime); ... }
很明顯直接交給mCallback處理,所以我們又得看一下這個(gè)mCallback從何而來(lái)。
這個(gè)mCallback是CallbackRepeater創(chuàng)建時(shí)傳入的DispSyncSource::onVsyncCallback方法:
mCallbackRepeater = std::make_unique(vSyncDispatch, std::bind(&DispSyncSource::onVsyncCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), name, workDuration, readyDuration, std::chrono::steady_clock::now().time_since_epoch());
所以,最終會(huì)調(diào)用到DispSyncSource::onVsyncCallback方法:
void DispSyncSource::onVsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime) { VSyncSource::Callback* callback; { std::lock_guard lock(mCallbackMutex); callback = mCallback; } ... if (callback != nullptr) { callback->onVSyncEvent(targetWakeupTime, {vsyncTime, readyTime}); }}
又是回調(diào),這里很繞。這里的callback其實(shí)就是EventThread,仍然是在創(chuàng)建EventThread的時(shí)候設(shè)置的:
EventThread::EventThread(std::unique_ptrvsyncSource, android::frametimeline::TokenManager* tokenManager, InterceptVSyncsCallback interceptVSyncsCallback, ThrottleVsyncCallback throttleVsyncCallback, GetVsyncPeriodFunction getVsyncPeriodFunction) : mVSyncSource(std::move(vsyncSource)), mTokenManager(tokenManager), mInterceptVSyncsCallback(std::move(interceptVSyncsCallback)), mThrottleVsyncCallback(std::move(throttleVsyncCallback)), mGetVsyncPeriodFunction(std::move(getVsyncPeriodFunction)), mThreadName(mVSyncSource->getName()) { LOG_ALWAYS_FATAL_IF(getVsyncPeriodFunction == nullptr, "getVsyncPeriodFunction must not be null"); mVSyncSource->setCallback(this); ...}
所以,終于可以看到盡頭了。最終其實(shí)就是調(diào)用到EventThread的onVSyncEvent方法:
void EventThread::onVSyncEvent(nsecs_t timestamp, VSyncSource::VSyncData vsyncData) { std::lock_guardlock(mMutex); LOG_FATAL_IF(!mVSyncState); mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count, vsyncData.expectedPresentationTime, vsyncData.deadlineTimestamp)); mCondition.notify_all();}
這里我們看到,會(huì)生成一個(gè)VSync信號(hào),加入到mPendingEvents集合中,并且發(fā)出通知,讓threadMain去獲取,從而完成了VSync信號(hào)的生產(chǎn)者流程。
畫(huà)了如下的surfaceFlinger結(jié)構(gòu)圖,方便理解(非完整版):
五.APP層收到信號(hào)進(jìn)行刷新
本章講的主要流程如下圖紅圈所示:
5.1 APP端接受流程
3.3小節(jié)中講到,SurfaceFlinger會(huì)通過(guò)BitTube的方式傳遞給APP側(cè)Vsync信號(hào)。發(fā)送vscyn信號(hào)的方法在DisplayEventReceiver.cpp中,而接收方法也在這個(gè)類(lèi)當(dāng)中。而具體調(diào)用方則是DisplayEventDispatcher.cpp中的dispatchVsync方法。流程如下圖所示:
5.2 dispathVsync分發(fā)流程
上面在handleEvent中,processPendingEvents獲取到了Vsync信號(hào)VsyncEventData后,交給dispatchVsync方法負(fù)責(zé)處理。
dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData);
dispatchVsync方法的實(shí)現(xiàn)者是android_view_DisplayEventReceiver.cpp,如下:
void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count, VsyncEventData vsyncEventData) { JNIEnv* env = AndroidRuntime::getJNIEnv(); ... jobject javaVsyncEventData = createJavaVsyncEventData(env, vsyncEventData); env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, displayId.value, count, javaVsyncEventData); ...}
我們可以看到,先是把VsyncEventData轉(zhuǎn)換為java可以接受的jobject對(duì)象,然后通過(guò)CallVoidMethod方法通知到j(luò)ava層中DisplayEventReceiver.java中的dispatchVsync方法。
5.3 java中流程流轉(zhuǎn)
首先DisplayEventReceiver中dispatchVsync方法被調(diào)用:
// Called from native code. @SuppressWarnings("unused") private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame, VsyncEventData vsyncEventData) { onVsync(timestampNanos, physicalDisplayId, frame, vsyncEventData); }
該方法中直接調(diào)用onVsync方法,調(diào)用到Choreographer.java中FrameDisplayEventReceiver下的onVsync方法:
@Override public void onVsync(long timestampNanos, long physicalDisplayId, int frame, VsyncEventData vsyncEventData) { try { ... if (timestampNanos > now) { timestampNanos = now; } if (mHavePendingVsync) { } else { mHavePendingVsync = true; } mTimestampNanos = timestampNanos; mFrame = frame; mLastVsyncEventData = vsyncEventData; Message msg = Message.obtain(mHandler, this); msg.setAsynchronous(true); mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS); } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } }
onVsync方法中,主要判斷時(shí)間。如果timestampNanos>now,則是用當(dāng)前時(shí)間。所以還是以方法的調(diào)用時(shí)間為準(zhǔn)。然后通過(guò)handle轉(zhuǎn)發(fā)到主線(xiàn)程中執(zhí)行。
Message.obj=this,本身FrameDisplayEventReceiver又實(shí)現(xiàn)了Runnable接口,所以自然會(huì)執(zhí)行FrameDisplayEventReceiver下的run方法:
@Override public void run() { mHavePendingVsync = false; doFrame(mTimestampNanos, mFrame, mLastVsyncEventData); }
這時(shí)候我們就看到,執(zhí)行到了doFrame方法,而這個(gè)方法也是就是渲染流程的執(zhí)行者。
5.4 如何觸發(fā)handleEvent流程?
講到這里,你或許有個(gè)疑問(wèn),上面流程中,如何執(zhí)行到5.1中的handleEvent方法的呢?
主要是下圖所示的流程:
如果你斷點(diǎn)調(diào)試的時(shí)候,會(huì)發(fā)現(xiàn)下面所示的這個(gè)方法,竟然是主線(xiàn)程調(diào)用的:
DisplayEventReceiver.java // Called from native code. @SuppressWarnings("unused") private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame, long frameTimelineVsyncId, long frameDeadline, long frameInterval) { onVsync(timestampNanos, physicalDisplayId, frame, new VsyncEventData(frameTimelineVsyncId, frameDeadline, frameInterval)); }
為什么用竟然呢?因?yàn)橐话銇?lái)看,應(yīng)該是子線(xiàn)程等待接受SurfaceFlinger的信號(hào),收到了信號(hào)后交給主線(xiàn)程處理,如果是主線(xiàn)程去等待,豈不是主線(xiàn)程阻塞了?
這里使用looper.addFd()方法,在該方法中,用到了一個(gè)epoll_ctl的機(jī)制,即對(duì)FD文件進(jìn)行監(jiān)聽(tīng),當(dāng)FD改變時(shí)觸發(fā)主線(xiàn)程的回調(diào)。如果處理完回調(diào)任務(wù),則會(huì)進(jìn)入epoll_wait的阻塞,繼續(xù)監(jiān)聽(tīng)。
六.擴(kuò)展問(wèn)題
問(wèn):高頻次請(qǐng)求vsync信號(hào),會(huì)突破60FPS的限制嗎?
答:不會(huì)。
首先ViewRootImpl中做了一層處理,哪怕16ms改變了很多View的布局,最終執(zhí)行到了scheduleTraversals方法時(shí),因?yàn)橛腥缦碌呐袛啵远贾粫?huì)執(zhí)行一次vsync信號(hào)的請(qǐng)求和注冊(cè)一次回調(diào),直至收到VSYNC信號(hào)。
void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true; mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); } }
取消限制:
void doTraversal() { if (mTraversalScheduled) { mTraversalScheduled = false;}
其次,2.2小節(jié)中講到,native請(qǐng)求VSYNC信號(hào)時(shí)也有一次限制,等到VSYNC信號(hào)時(shí)是不會(huì)再次發(fā)送請(qǐng)求的。
status_t DisplayEventDispatcher::scheduleVsync() { if (!mWaitingForVsync) { ... status_t status = mReceiver.requestNextVsync(); ... mWaitingForVsync = true; ... } return OK;}
七.參考資料
https://www.jianshu.com/p/6083c590521b
https://www.jianshu.com/p/386bbb5fa29a //努比亞技術(shù)團(tuán)隊(duì)文章
八.聲明
1.本文是原創(chuàng),根據(jù)網(wǎng)上資料和閱讀ASOP的源碼之后得出的結(jié)論,如有問(wèn)題,歡迎指出。
2.圖中涉及到的流程圖如果想要高清大圖或者pos格式的原圖,可以私信我。
標(biāo)簽:
相關(guān)推薦:
精彩放送:
- []互惠保險(xiǎn)什么意思
- []恒輝安防:請(qǐng)您參考公司于2023年4月21日年報(bào)披露的股東人數(shù)信息
- []貨車(chē)買(mǎi)保險(xiǎn)去哪家
- []公積金比例怎么算
- []聯(lián)動(dòng)云有保險(xiǎn)嗎? 全球熱頭條
- []總決賽再演!浙江東陽(yáng)光擊敗廣東男籃,與遼寧隊(duì)會(huì)師半決賽
- []日本文字翻譯器 日本文字翻譯_報(bào)道
- []天天快資訊:季半夏傅斯年免費(fèi)閱讀
- []exands secure wifi_exands 天天看熱訊
- []今天要上班 這都可以?|速讀
- []全球快訊:驗(yàn)孕棒晚上測(cè)準(zhǔn)嗎月經(jīng)不調(diào)_驗(yàn)孕棒晚上測(cè)準(zhǔn)嗎
- []焦點(diǎn)快播:網(wǎng)傳3人在四川什邡天鵝林場(chǎng)服毒自殺,警方:確實(shí)發(fā)現(xiàn)3具尸體
- []香港明年起將4月23日定為“香港全民閱讀日”
- []萊曼談拜仁戰(zhàn)績(jī)不佳:球員無(wú)需負(fù)主要責(zé)任,因?yàn)樗麄兙驮趫?zhí)行戰(zhàn)術(shù) 今頭條
- []100名地鐵志愿者圓滿(mǎn)完成“青馬”服務(wù)保障|每日精選
- []中建、湖北文旅建發(fā)聯(lián)合拿下北京共有產(chǎn)權(quán)房項(xiàng)目用地 世界最資訊
- []環(huán)球即時(shí):奧克斯空調(diào)說(shuō)明書(shū)在哪_奧克斯空調(diào)說(shuō)明書(shū)
- []證監(jiān)會(huì)核發(fā)首批企業(yè)債券注冊(cè)批文 涉34個(gè)企業(yè)募集資金542億
- []世界快看:全國(guó)同業(yè)最多!成都住房公積金實(shí)現(xiàn)5類(lèi)核心業(yè)務(wù)場(chǎng)景數(shù)字人民幣應(yīng)用全覆蓋
- []同比增長(zhǎng)8.4%!湖南建筑業(yè)一季度實(shí)現(xiàn)較快增長(zhǎng)|環(huán)球新視野
- []潤(rùn)禾材料:公司是原材料供應(yīng)商,終端產(chǎn)品生產(chǎn)客戶(hù)會(huì)根據(jù)自身需求,采購(gòu)或定制其相關(guān)原材料
- []全球看熱訊:遼寧?。杭訌?qiáng)海外知識(shí)產(chǎn)權(quán)保護(hù)合作 為“走出去”企業(yè)保駕護(hù)航
- []廣東第一季度地區(qū)生產(chǎn)總值30178.23億 同比增長(zhǎng)4.0%
- []世界觀點(diǎn):打擊仿冒“得物包裝”案入選上海知識(shí)產(chǎn)權(quán)保護(hù)十大典型案例
- []中上協(xié)房地產(chǎn)行業(yè)委員會(huì)成立大會(huì)在杭州召開(kāi)
- []住進(jìn)“ICU”的神龍汽車(chē) 全面電動(dòng)化轉(zhuǎn)型能否“自救”成功_熱消息
- []世界看熱訊:深特發(fā)擬發(fā)行4.7億元超短期融資券 期限90天
- []焦點(diǎn)熱訊:讀書(shū)之美丨重溫文學(xué)經(jīng)典 影視主創(chuàng)把《平凡的世界》讀給你聽(tīng)
- []晶科能源2023年第一季度預(yù)計(jì)凈利16億-17億同比增長(zhǎng)299%-324% 全球市場(chǎng)需求旺盛_當(dāng)前觀察
- []2008年以來(lái)最高!美國(guó)主權(quán)CDS飆升,市場(chǎng)預(yù)期違約在即? 熱消息
- []【天天報(bào)資訊】北京昌平科技園2022年度第二期6億中期票據(jù)將于5月5日付息
- []中國(guó)上城發(fā)現(xiàn)4個(gè)主要內(nèi)部控制問(wèn)題 稱(chēng)已采取充分補(bǔ)救措施
- []天天微速訊:中辰股份:截至2023年4月20日,公司持股戶(hù)數(shù)為21328戶(hù)
- []國(guó)際實(shí)業(yè):截至2023年4月20日,公司的股東總戶(hù)數(shù)為39,474戶(hù)
- []山西玖和恒創(chuàng)機(jī)電設(shè)備有限公司-快消息
- []下周(4.24-4.30)全球市場(chǎng)大事提醒_速看
- []中創(chuàng)新航江門(mén)項(xiàng)目產(chǎn)品正式下線(xiàn)!6月將發(fā)布新型儲(chǔ)能電池
- []【報(bào)資訊】唐山哪家做包皮手術(shù)好?【唐山唐誠(chéng)醫(yī)院專(zhuān)業(yè)做包皮手術(shù)醫(yī)院】
- []信達(dá)地產(chǎn):公司2022年末對(duì)外提供擔(dān)保60.61億元 降幅為4.95%-精選
- []天天熱門(mén):安道麥A:公司在巴西的銷(xiāo)售業(yè)務(wù)主要以巴西雷亞爾進(jìn)行結(jié)算
- []每日熱議!中際旭創(chuàng):具體要看客戶(hù)的網(wǎng)絡(luò)架構(gòu),200G/800G光模塊可以與之配套
- []廣東宏大: 截止至2023年4月20日,公司在冊(cè)股東總戶(hù)數(shù)為30,460戶(hù)
- []熱點(diǎn)追蹤 | 用發(fā)展空間看公司未來(lái)|當(dāng)前觀點(diǎn)
- []環(huán)球新消息丨青島市市南區(qū)強(qiáng)招引促落地 打好招商引資“組合拳”
- []蘇能股份:子公司擬投15億元建徐州泉山經(jīng)開(kāi)區(qū)全域光伏項(xiàng)目 全球熱聞
- []最新快訊!糟糕的家庭,總是喜歡在小事上消耗孩子,慢慢毀掉孩子還不自知
- []林洋能源與國(guó)家電投集團(tuán)湖北電力有限公司、新源智儲(chǔ)能源發(fā)展(北京)有限公司簽訂戰(zhàn)略合作協(xié)議
- []N型電池片技術(shù)百花齊放 TOPCon產(chǎn)能率先放量
- []世界快消息!低碳裝機(jī)達(dá)26.07%!華電國(guó)際發(fā)布2022年ESG報(bào)告
- []要聞:浙江縉云抽蓄電站500千伏出線(xiàn)洞斜井段貫通
- []新型電力市場(chǎng)機(jī)制探索與發(fā)展趨勢(shì)
- []分布式光伏“南遷”_環(huán)球新資訊
- []全球關(guān)注:湖南寧鄉(xiāng)2022年儲(chǔ)能材料產(chǎn)值約440億 已集聚40多家鋰電企業(yè)
- []世界簡(jiǎn)訊:中國(guó)電力沂水獨(dú)立儲(chǔ)能電站項(xiàng)目成功并網(wǎng)
- []新湖中寶注冊(cè)發(fā)行20億元中期票據(jù) 用于改善公司債務(wù)融資結(jié)構(gòu)-世界頭條
- []聯(lián)創(chuàng)股份:截止3月底公司股東總數(shù)104,516戶(hù)
- []甘化科工股東戶(hù)數(shù)下降1.11%,戶(hù)均持股17.37萬(wàn)元|天天微資訊
- []北京住總12.2億元ABN將付息 A類(lèi)利率4.80%、B類(lèi)利率5% 環(huán)球關(guān)注
- []僑源股份:截至2023年4月20日公司的股東總數(shù)是5635|天天通訊
- []青島西海岸一宗商住用地將于下月法拍 起拍價(jià)1.61億元
- []當(dāng)前頭條:綠城38.58億元摘得西安高新區(qū)2宗居住地 為陳林村城改項(xiàng)目用地
- []淮南建發(fā)集團(tuán)30億元私募債券項(xiàng)目更新至“已反饋”
- []高鐵檢修保安全 快看
- []精測(cè)電子:截至2023年4月10日,公司股東總戶(hù)數(shù)16,226戶(hù) 全球微資訊
- []今日熱門(mén)!歐洲儲(chǔ)能系統(tǒng)商業(yè)模式的演變
- []動(dòng)力電池+儲(chǔ)能_天天最資訊
- []1.03~1.6元/Wh!11企業(yè)入圍中核1.2GW/3.2GWh儲(chǔ)能系統(tǒng)集采
- []攜程商旅國(guó)際打車(chē)服務(wù)上線(xiàn);美團(tuán)民宿發(fā)票服務(wù)升級(jí) | 一周商旅動(dòng)態(tài) 每日精選
- []夏邑縣汽車(chē)站時(shí)刻表_夏邑縣火車(chē)站
- []大眾子公司 PowerCo 正在加拿大建設(shè) 90 GWh 電池工廠
- []今頭條!3月儲(chǔ)能全動(dòng)態(tài)!超100GWh項(xiàng)目完成簽約
- []公募基金一季度調(diào)倉(cāng)思路全曝光:狂買(mǎi)三六零、??低暤華I概念股_全球快資訊
- []世界要聞:探索古籍奧秘 品讀家國(guó)情懷 新區(qū)舉辦古籍科普展弘揚(yáng)傳統(tǒng)文化
- []鄭州公共住宅建設(shè)3.8億元中票注冊(cè)文件需增加信息披露 全球速看
- []特發(fā)服務(wù):2022年實(shí)現(xiàn)收入20.05億元-今日熱訊
- []順網(wǎng)科技:公司在AI領(lǐng)域較強(qiáng)的技術(shù)儲(chǔ)備,可為AIGC等人工智能應(yīng)用提供算力、算法、云渲染等技術(shù)服務(wù)
- []合肥濱湖建投4.5億元中期票據(jù)將付息 利率3.5%-環(huán)球熱議
- []*ST日海:公司當(dāng)前未與上述公司開(kāi)展業(yè)務(wù)合作,主營(yíng)業(yè)務(wù)中沒(méi)有光模塊、CPO業(yè)務(wù)-全球動(dòng)態(tài)
- []焦點(diǎn)要聞:西安曲江新區(qū)推出1宗住宅用地 凈用地面積4萬(wàn)平方米
- []遠(yuǎn)興能源:截止2023年4月20日,公司股東人數(shù)為100,488戶(hù)
- []環(huán)球新動(dòng)態(tài):合肥:肥東撮鎮(zhèn)鎮(zhèn)大郭1片區(qū)擬征地 面積超1700畝
- []鴻博股份:公司各項(xiàng)業(yè)務(wù)均正常開(kāi)展,公司會(huì)根據(jù)市場(chǎng)的需求以及自身的實(shí)際情況進(jìn)行合理的業(yè)務(wù)規(guī)劃-全球熱聞
- []全球快看:孕前保健
- []中國(guó)電建2023年一季度新簽5億元以上項(xiàng)目55個(gè)!含9個(gè)儲(chǔ)能項(xiàng)目_精選
- []環(huán)球微資訊!光伏儲(chǔ)能繼續(xù)火爆,何種儲(chǔ)能路線(xiàn)最香?
- []儲(chǔ)能市場(chǎng)爆發(fā)已成共識(shí),但項(xiàng)目如何盈利仍是痛點(diǎn) 天天報(bào)道
- []【世界時(shí)快訊】立志是什么意思?立志的相關(guān)名言有哪些?
- []“梭哈魔咒”來(lái)了?知名游資殺瘋了 歷史上僅出現(xiàn)4次!TMT板塊大調(diào)整 機(jī)構(gòu)怎么看 動(dòng)態(tài)
- []金碧輝煌是什么意思?金碧輝煌出自哪里? 獨(dú)家
- []驚喜英文怎么說(shuō)?驚喜英文例句有哪些?
- []儲(chǔ)能招標(biāo)丨7.5MW/20.127MWh!江蘇蘇州儲(chǔ)能電站項(xiàng)目EPC招標(biāo)_當(dāng)前看點(diǎn)
- []【環(huán)球播資訊】冕寧縣景點(diǎn)有哪些?冕寧縣景點(diǎn)介紹?
- []天天熱點(diǎn)!去臺(tái)灣怎樣辦理通行證?去臺(tái)灣辦理通行證過(guò)程是怎樣的?
- []發(fā)電方式有哪些?常見(jiàn)的發(fā)電形式介紹?
- []【全球新視野】長(zhǎng)沙超300米金茂梅溪大廈塔樓核心筒封頂 預(yù)計(jì)5月底驗(yàn)收交付
- []今日熱聞!凸透鏡成像實(shí)驗(yàn)怎么做?凸透鏡成像的實(shí)驗(yàn)步驟有哪些?
- []要聞:沈葆楨的人物評(píng)價(jià)?沈葆楨資料介紹?
- []北京朝陽(yáng)孫河前葦溝地塊收到40億元報(bào)價(jià) 用地規(guī)模6.15萬(wàn)平方米 微速訊
- []海螺姑娘什么梗?海螺姑娘是什么故事? 世界熱聞
- []蝦蛄怎么做好吃?蝦蛄的做法介紹?
- View繪制流程2-安卓如何執(zhí)行measure/draw 全球最新
- 每日視點(diǎn)!陳小蘭:傳承中醫(yī)藥炮制技藝
- java中的心跳包是如何發(fā)送的?心跳檢測(cè)實(shí)現(xiàn)2.1-速讀
- “報(bào)復(fù)性出差”來(lái)了,2023年中國(guó)差旅復(fù)蘇勢(shì)頭領(lǐng)跑全球,支出增長(zhǎng)率預(yù)計(jì)達(dá)20%
- 產(chǎn)煤不見(jiàn)煤 智能化煤礦建設(shè)漸入佳境
- 恒瑞醫(yī)藥的2022,比想象中的更嚴(yán)峻-天天最新
- 【天天快播報(bào)】清朝皇帝陵墓在哪_清朝皇帝陵墓介紹
- 當(dāng)前時(shí)訊:掌中寶是什么資料_掌中寶是什么
- 天天新資訊:行政區(qū)劃體制改革_行政區(qū)劃體制
- 世界即時(shí):鄭州暴雨保險(xiǎn)賠嗎
- B站注冊(cè)資本增幅400%至5億 目前由陳睿全資持股
- 光源資本出任獨(dú)家財(cái)務(wù)顧問(wèn) 沐曦集成電路10億元A輪融資宣告完成
- 巨輪智能2021年上半年?duì)I收11.24億元 期內(nèi)研發(fā)費(fèi)用投入增長(zhǎng)19.05%
- 紅棗期貨尾盤(pán)拉升大漲近6% 目前紅棗市場(chǎng)總庫(kù)存約30萬(wàn)噸
- 嘉銀金科發(fā)布2021年Q2財(cái)報(bào) 期內(nèi)凈利潤(rùn)達(dá)1.27億元同比增長(zhǎng)208%
- 成都銀行2021上半年凈利33.89億元 期內(nèi)實(shí)現(xiàn)營(yíng)收同比增長(zhǎng)17.27億元
- 汽車(chē)之家發(fā)布2021年第二季度業(yè)績(jī) 期內(nèi)新能源汽車(chē)品牌收入增長(zhǎng)238%
- 中信銀行上半年實(shí)現(xiàn)凈利潤(rùn)290.31億元 期末不良貸款余額706.82億元
- 光伏概念掀起漲停潮交易價(jià)格創(chuàng)新高 全天成交額達(dá)1.29億元
- 上半年生物藥大增45% 關(guān)鍵財(cái)務(wù)指標(biāo)好轉(zhuǎn)營(yíng)收賬款持續(xù)下降
- 因未按時(shí)披露2021年年報(bào) 福建陽(yáng)光集團(tuán)收到上交所紀(jì)律處分決定書(shū)
- 南京新街口一辦公樓1.2億元二次流拍 為克莉絲汀執(zhí)董朱永寧所有
- 美亞柏科:目前6G通信技術(shù)尚處于研究和探索階段,暫無(wú)具體的6G標(biāo)準(zhǔn) 熱文
- 世界快看點(diǎn)丨同和藥業(yè)(300636.SZ):2022年度凈利增24.10%至1.01億元 擬10派0.45元
- 全球速看:金三江:拓展海外市場(chǎng)和拓展新領(lǐng)域是我司重點(diǎn)經(jīng)營(yíng)管理工作
- 全球觀察:中國(guó)金茂成立上海興秀茂商業(yè)管理公司 注冊(cè)資本5000萬(wàn)元
- 世界看熱訊:桃花姬阿膠糕的功效及食用方法 阿膠糕哪個(gè)牌子最好
- 熱頭條丨三問(wèn)金風(fēng)科技儲(chǔ)能布局
- 杭州藍(lán)然譚俊邀您共同參加第8屆動(dòng)力電池回收利用高峰論壇 天天快看
- 百億私募搶籌TMT 算力基礎(chǔ)設(shè)施賽道火熱(附潛力股)|全球時(shí)訊
- 江蘇:新增光伏市場(chǎng)化并網(wǎng)項(xiàng)目均需配備儲(chǔ)能_快資訊
- 總投資51億元!河南濮陽(yáng)鈉電池產(chǎn)業(yè)項(xiàng)目開(kāi)工
- 調(diào)研丨天賜材料:鋰電池材料為主要盈利點(diǎn),鋰電電解液市占率全球領(lǐng)先 觀熱點(diǎn)
- 恒榮實(shí)業(yè)拿下珠海里神前舊村改造項(xiàng)目地塊 二期地價(jià)款為1.14億元 環(huán)球新資訊
- 世界速遞!深圳前海一方恒融對(duì)5.01億華發(fā)優(yōu)生活A(yù)BN注冊(cè)文件補(bǔ)充信息
- 中超綜合 | 十人海港擊退深圳 亞泰讀秒絕殺大連人
- 世界熱推薦:珠海2023第一批次擬出讓5宗住宅用地 面積合計(jì)28.63公頃
- 萬(wàn)達(dá)商管股權(quán)出質(zhì)東莞東城萬(wàn)達(dá)廣場(chǎng)5億元 占后者股權(quán)比例100%
- 上海青浦區(qū)一宗超7萬(wàn)平商品房用地?cái)M拍賣(mài) 起價(jià)14.09億元
- 安寧股份:截至2023年4月20日股東人數(shù)19,167_環(huán)球訊息
- 亞聯(lián)機(jī)械IPO,經(jīng)營(yíng)性現(xiàn)金流波動(dòng)明顯,去年利潤(rùn)增加來(lái)自匯兌收益?_當(dāng)前速遞
- 北方多地最高氣溫不足10℃,部分地區(qū)同期積雪深度破紀(jì)錄
- 活動(dòng)回顧視頻 | 2023 環(huán)球旅訊數(shù)智論壇(廈門(mén)站)大咖分享合集
- 廣東省科學(xué)技術(shù)廳征集新型儲(chǔ)能技術(shù)攻關(guān)需求-今日熱議
- 農(nóng)發(fā)行烏蘭察布市分行信貸業(yè)務(wù)開(kāi)門(mén)紅“回頭看”顯成效
- 關(guān)注:織女星位于哪個(gè)星座?織女星資料介紹?
- 輪胎規(guī)格參數(shù)介紹?輪胎的類(lèi)型有哪些?-全球聚看點(diǎn)
- 防盜網(wǎng)有哪些種類(lèi)?防盜網(wǎng)種類(lèi)介紹?_天天熱點(diǎn)評(píng)
- 環(huán)球資訊:文章中的景物描寫(xiě)有什么作用?文章中的景物描的作用介紹?
- 生命樹(shù)是什么?生命樹(shù)出自哪里?
- 全球熱議:沒(méi)有廢除,也不是虛設(shè)!“深圳二手房指導(dǎo)價(jià)謝幕”傳聞一日游
- 每日視訊:湖北能源:公司年度長(zhǎng)協(xié)煤正在逐步簽訂和落實(shí)中,公司省內(nèi)煤電長(zhǎng)協(xié)覆蓋率現(xiàn)已達(dá)到接近80%
- 快看:踩腳襪是什么?踩腳襪有什么特點(diǎn)?
- 每日觀點(diǎn):深圳光明鳳凰碧眼片區(qū)規(guī)劃出爐 擬建綜合體育中心
- 成人高考專(zhuān)升本好考嗎?考試科目有哪些?
- 世界速看:軍嫂有什么優(yōu)待政策?軍嫂可以享受的優(yōu)待政策介紹?
- 嶧城區(qū)峨山鎮(zhèn)金山小學(xué):讀書(shū)讓我們飛得更遠(yuǎn)
- 深圳龍崗5.2億掛牌4宗產(chǎn)業(yè)用地 其中3宗用于寶龍生物藥二期建設(shè)
- 星巴克杯子怎么買(mǎi)?購(gòu)買(mǎi)星巴克杯子的具體操作步驟介紹?
- 今日熱搜:等腰直角三角形長(zhǎng)什么樣?等腰直角三角形有哪些性質(zhì)?
- 2023福耀玻璃工業(yè)集團(tuán)股份有限公司校園招聘(鄭州有崗)_環(huán)球快看
- 阿德巴約:樂(lè)福首發(fā)幫助了球隊(duì) 他不需得很多分但能做正確的事情-今熱點(diǎn)
- 杭州臨平區(qū)全域放寬限購(gòu):外地戶(hù)籍只需1個(gè)月社??少?gòu)房
- 觀天下!遠(yuǎn)洋集團(tuán)完成20億元PPN產(chǎn)品兌付
- 江蘇:一季度社會(huì)消費(fèi)品零售總額同比增7.8%至11706.8億元
- 建發(fā)房產(chǎn)擬使用10億中票的募資用于項(xiàng)目建設(shè)及并購(gòu)股權(quán) 全球觀熱點(diǎn)
- 環(huán)球快資訊:關(guān)于二手房交易,你了解多少?
- 賽摩智能: 公司目前暫無(wú)大語(yǔ)言模型方面的應(yīng)用 全球速看料
- 2023徐匯區(qū)零售消費(fèi)券使用時(shí)間+使用范圍_世界觀速訊
- 氫能運(yùn)輸分析與展望
- “應(yīng)退盡退”生態(tài)加速形成 常態(tài)化退市格局日趨明朗
- 韓國(guó)豪擲1000億“押注”固態(tài)電池
- 直連Colab,支持20種編程語(yǔ)言:谷歌版ChatGPT代碼水平反殺了?
- 云投集團(tuán)完成發(fā)行13億短期融資券 票面利率7.22%
- 天津北辰科技5億中期票據(jù)即將付息 利率7.50%
- 上海財(cái)政局回應(yīng)市民:將開(kāi)展家庭唯一住房出售環(huán)節(jié)增值稅問(wèn)題調(diào)研
- 焦點(diǎn)快播:每周金選:隆基綠能歸母凈利潤(rùn)147.79億元同比增加62.66%;寒武紀(jì)云端產(chǎn)品線(xiàn)業(yè)務(wù)收入大幅增長(zhǎng);海上風(fēng)機(jī)龍頭明陽(yáng)智能保持高速增長(zhǎng);高純晶硅龍頭通威股份歸母凈利潤(rùn)最高增長(zhǎng)231%;協(xié)鑫集成歸母凈利潤(rùn)或翻倍;
- 環(huán)球即時(shí)看!國(guó)美零售:委任開(kāi)元信德為新核數(shù)師 信永中和退出
- 【BT金融分析師】秦淮數(shù)據(jù)被指增長(zhǎng)放緩,分析師稱(chēng)起碼“私有化危機(jī)”消失了 世界報(bào)資訊
- 環(huán)球快消息!央行金中夏:引導(dǎo)金融機(jī)構(gòu)加大對(duì)民營(yíng)和小微外貿(mào)企業(yè)的支持力度
- 【BT金融分析師】華潤(rùn)電力前景向好,分析師稱(chēng)未來(lái)中國(guó)人均用電量增長(zhǎng)空間不少
- 建研設(shè)計(jì):公司建立有自己的數(shù)據(jù)存儲(chǔ)檔案庫(kù),主要服務(wù)于建筑設(shè)計(jì)與咨詢(xún)主營(yíng)業(yè)務(wù)
- 日推生化樂(lè)高moc分享--@bregmanicle的生化戰(zhàn)士作品”Lambda V3“
- 環(huán)球消息!高價(jià)值貨運(yùn)箱不翼而飛,加拿大機(jī)場(chǎng)上演“黃金大劫案”
- 【天天熱聞】鄉(xiāng)村閱讀空間——滋養(yǎng)“文化秧苗”茁壯成長(zhǎng)
- 【環(huán)球播資訊】關(guān)于召開(kāi)《電化學(xué)儲(chǔ)能電站能量管理系統(tǒng)技術(shù)規(guī)范》等四項(xiàng)團(tuán)體標(biāo)準(zhǔn)第一次工作會(huì)議的通知
- 儲(chǔ)能EPC環(huán)比降14.5%!大規(guī)模集采競(jìng)爭(zhēng)白熱化
- 五一云南旅游預(yù)訂暴漲400%!潑水節(jié)帶動(dòng)旅游熱,游客:潑起水來(lái)都看不到人
- 寧德時(shí)代再投40億!
- 恒運(yùn)儲(chǔ)能公司和用電與照明公司簽署戰(zhàn)略合作協(xié)議-世界球精選
- 年輕人為何成旅游特種兵:努力工作并希望快樂(lè) 最新快訊
- 天天實(shí)時(shí):臨洮縣成功簽約投資40億元的共享儲(chǔ)能項(xiàng)目
- 2023德國(guó)iF獎(jiǎng)揭曉,海信視像再獲4項(xiàng)國(guó)際設(shè)計(jì)大獎(jiǎng)
- 今日快看!2023年中牟五一限行規(guī)定
- 怡合達(dá):截至2023年4月20日,公司股東總數(shù)10098 環(huán)球短訊
- 北京市住宅產(chǎn)業(yè)化集團(tuán):工廠造房不是夢(mèng)
- 福州首批集中供地掛牌,10宗地總起拍價(jià)16.81億元 當(dāng)前速看
- 山西:一季度全省商品房銷(xiāo)售面積439.8萬(wàn)平方米_全球觀焦點(diǎn)
- 深圳:一季度住戶(hù)存款增加2148.00億元
- 當(dāng)前時(shí)訊:天邦食品:截止至2023年04月20日,公司股東總戶(hù)數(shù)112,258戶(hù)
- 重倉(cāng)房地產(chǎn)行業(yè) 廣州銀行嘗到了苦頭
- 山西:一季度全省地區(qū)生產(chǎn)總值為5824.33億元,同比上漲5.0%_熱文
- 晶澳科技:根據(jù)已披露的2022年年報(bào),公司沒(méi)有商譽(yù),不存在未減值商譽(yù) 全球最資訊
- 全球熱點(diǎn)評(píng)!酒店,需學(xué)會(huì)與周邊居民保持“熱戀”
- 研究機(jī)構(gòu)預(yù)測(cè)到2030年英國(guó)累計(jì)部署的電池儲(chǔ)能項(xiàng)目裝機(jī)規(guī)?;?qū)⑦_(dá)24GW|快看點(diǎn)
- 今日最新!天奈科技去年凈利潤(rùn)增長(zhǎng)43%,擬30億投建正極材料項(xiàng)目
- 全球今頭條!國(guó)內(nèi)首個(gè)氫能交易平臺(tái)啟動(dòng)
- 華發(fā)股份發(fā)布新一代優(yōu)+產(chǎn)品體系5.0
- 特斯拉吞下降價(jià)“苦果”
- 總投資360億元!愛(ài)旭股份30GW電池+30GW組件項(xiàng)目簽約濟(jì)南
- 海航控股:穩(wěn)中求進(jìn),打好效益翻身仗
- 外交部副部長(zhǎng)孫衛(wèi)東就韓國(guó)領(lǐng)導(dǎo)人涉臺(tái)灣問(wèn)題錯(cuò)誤言論向韓國(guó)駐華大使提出嚴(yán)正交涉_每日觀點(diǎn)
- 天天百事通!遠(yuǎn)洋控股集團(tuán):從未有過(guò)涉及接觸債權(quán)人討論成立債委會(huì)的任何情形
- 環(huán)球熱訊:天孚通信:截至2023年04月20日收盤(pán),公司股東人數(shù)為23635(合并信用賬戶(hù))
- 福州第一批10宗地塊定檔5月18日 起始總價(jià)16.81億元
- 焦點(diǎn)短訊!東吳蘇園產(chǎn)業(yè)REIT一季度收入約7251萬(wàn) 可供分配金額約3118萬(wàn)
- 【新視野】因未及時(shí)披露2021年年報(bào) 景瑞地產(chǎn)及負(fù)責(zé)人受到上交所通報(bào)批評(píng)
- 今日?qǐng)?bào)丨思創(chuàng)醫(yī)惠第一大股東存變更可能 受損投資者能否挽回權(quán)益?
- 因未按時(shí)披露2021年年報(bào) 上海世茂建設(shè)及有關(guān)責(zé)任人被通報(bào)批評(píng)
- 成都印發(fā)政策 “真金白銀”支持外貿(mào)轉(zhuǎn)型發(fā)展 熱議
