当前位置: 首页 > news >正文

未来做哪些网站致富电子商务营销模式有哪些

未来做哪些网站致富,电子商务营销模式有哪些,phpcms 做购物网站,wordpress主题logoAndroid 13 VSYNC重学习 引言 学无止境,一个字干就完事! 源码参考基于Android 13 aosp! 一. Android VSync模块开胃菜 在开始正式的分析之前,我们先简单对Android的Vsync模块简单介绍下,如下图所示,其中: HW_VSync是…

Android 13 VSYNC重学习



引言

学无止境,一个字干就完事!

源码参考基于Android 13 aosp!




一. Android VSync模块开胃菜

在开始正式的分析之前,我们先简单对Android的Vsync模块简单介绍下,如下图所示,其中:

  • HW_VSync是由屏幕产生的脉冲信号,用于控制屏幕的刷新
  • VSync-app和VSync-sf统称为软件VSync,它们是由SurfaceFlinger通过模拟硬件VSync而产生的VSync信号量,再分发给app和sf用来控制它们的合成节奏

image



image





二. Android VSync小结

这里有几点需要补充:

  • VSync-sf是没有对应的EventThread和DispSyncSource

  • VSync-app和VSync-appSf各自都有对应的EventThread和DispSyncSource

  • VSync-sf和VSync-app以及Sync-appSf通过Scheduler的成员mVsyncSchedule指向的VSyncDispatchTimerQueue实例对象关联



Android下VSync设计,牵涉的核心关系图如下:

image


2.1 VSync信号的分类

VSync信号分为两种:硬件VSync信号HW-VSync和软件VSync信号SW-VSync。SW-VSync信号由SW-VSync模型产生。HW-VSync信号负责对SW-VSync模型进行校准。


2.2 HW-Vsync信号的开启

三种场景下会开启硬件VSync信号HW-VSync会对软件VSync信号SW-VSync进行校准

  • SurfaceFlinger初始化。

  • 连续两次请求VSync-app信号的时间间隔超过750ms。

  • SurfaceFlinger合成后,添加FenceTime到VSyncTracker中导致模型计算误差过大。


2.3 SW-VSync模型与计算

谷歌官方采用一元线性回归分析预测法(最小二乘法),通过采样的HW-VSync信号样本(屏幕刷新率),计算对应的SW-VSync信号周期。最终得到一条y=bx+a的拟合曲线。其中,b称为回归系数,a称为截距。SW-VSync模型就是这这条曲线的回归系数和截距。


2.4 SW-VSync信号的分类

SW-VSync信号也分为两种,VSync-sf信号和Vsync-app信号。这两个信号,各司其职:

  • VSync-sf信号用于控制SurfaceFlinger的Layer合成
    - VSync-app信号用于控制App渲染UI

VSync-sf信号和VSync-app信号是在SW-VSync信号的基础上通过叠加不同的偏移量产生,这些偏移量被称为VSync相位偏移。由于偏移量不同VSync-sf信号和VSync-app信号的回调时机也不同。




三. VSync-sf的申请和分发

VSync-sf用于控制SurfaceFlinger合成和渲染一帧图像。当SurfaceFlinger上帧时(BufferQueue中有新的GraphicBuffer),SurfaceFlinger会触发MessageQueue的scheduleFrame方法。接下来我们看下,VSync-sf是如何完成从申请到分发的流程。

3.1 VSync-sf的申请

SurfaceFlinger::scheduleCommit(...)//请求上帧mScheduler->scheduleFrame()//MessageQueue.cppmVsync.registration->schedule()//这里的registration实现是VSyncCallbackRegistration,定义在Scheduler/VSyncDispatchTimerQueue.cppmDispatch.get().schedule()//这里的mDispatch指向VSyncDispatchTimerQueue对象/*** @brief * * @param token * @param scheduleTiming * @return ScheduleResult * 1)根据CallbackToken找到所有满足要求的VSyncDispatchTimerQueueEntry。VSyncDispatchTimerQueueEntry是VSyncDispatchTimerQueue中对外部VSync信号请求的封装。* 2)遍历调用VSyncDispatchTimerQueue的schedule方法,计算下一次VSync信号的发送时间。* 3)对发射时间进行定时,等待下一次VSync信号的发送*/
ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token,ScheduleTiming scheduleTiming) {...//根据CallbackToken找到所有满足要求的VSyncDispatchTimerQueueEntry。VSyncDispatchTimerQueueEntry是VSyncDispatchTimerQueue中对外部VSync信号请求的封装。auto it = mCallbacks.find(token);auto& callback = it->second;//遍历调用VSyncDispatchTimerQueue的schedule方法,计算下一次VSync信号的发送时间result = callback->schedule(scheduleTiming, mTracker, now);//对发射时间进行定时,等待下一次VSync-sf信号的发送rearmTimerSkippingUpdateFor(now, it);VSyncDispatchTimerQueue::setTimer()void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t /*now*/) {mIntendedWakeupTime = targetTime;mTimeKeeper->alarmAt(std::bind(&VSyncDispatchTimerQueue::timerCallback, this),mIntendedWakeupTime);mLastTimerSchedule = mTimeKeeper->now();
}     /*** @brief * 1)遍历CallbackMap找到达到唤醒时间的VSyncDispatchTimerQueueEntry,并封装成Invocation,加入Invocation列表。* 2)遍历Invocation列表,通过Invocation获取VSyncDispatchTimerQueueEntry,并调用VSyncDispatchTimerQueueEntry的callback方法分发VSync信号。*///Scheduler/VSyncDispatchTimerQueue.cpp
void VSyncDispatchTimerQueue::timerCallback() {struct Invocation {std::shared_ptr<VSyncDispatchTimerQueueEntry> callback;nsecs_t vsyncTimestamp;nsecs_t wakeupTimestamp;nsecs_t deadlineTimestamp;};std::vector<Invocation> invocations;{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<nsecs_t>(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);}
}}

3.2 VSync-sf的分发

那么VSync-df的callback是怎么注册到VSyncDispatchTimerQueue的呢,这个我们看下:

SurfaceFlinger::initScheduler(...)mScheduler->initVsync(...)//实现在Scheduler/MessageQueue.cpp中mVsync.registration = std::make_unique<scheduler::VSyncCallbackRegistration>(dispatch,std::bind(&MessageQueue::vsyncCallback, this,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3),"sf");//这里的dispatch指向VSyncDispatchTimerQueue//Scheduler/VSyncDispatchTimerQueue.cppVSyncCallbackRegistration::VSyncCallbackRegistration(VSyncDispatch& dispatch,VSyncDispatch::Callback callback,std::string callbackName): mDispatch(dispatch),mToken(dispatch.registerCallback(std::move(callback), std::move(callbackName))),mValidToken(true) {}       VSyncDispatchTimerQueue::CallbackToken VSyncDispatchTimerQueue::registerCallback(Callback callback, std::string callbackName) {std::lock_guard lock(mMutex);return CallbackToken{//最终注册到了mCallbacks中mCallbacks.emplace(++mCallbackToken,std::make_shared<VSyncDispatchTimerQueueEntry>(std::move(callbackName),std::move(callback),mMinVsyncDistance)).first->first};
}        

所以最后VSync-sf的分发会调用到MessageQueue::vsyncCallback中,我们看下它的实现:

//Scheduler/MessageQueue.cpp
MessageQueue::vsyncCallback(...)mHandler->dispatchFrame(vsyncId, vsyncTime)mQueue.mLooper->sendMessage(this, Message())//Handle的handleMessage接收前面发过来的消息
void MessageQueue::Handler::handleMessage(const Message&) {mFramePending.store(false);const nsecs_t frameTime = systemTime();auto& compositor = mQueue.mCompositor;//这里的compositor实现类是SurfaceFlingerif (!compositor.commit(frameTime, mVsyncId, mExpectedVsyncTime)) {return;}compositor.composite(frameTime, mVsyncId);compositor.sample();
}



四. VSync-app的申请和分发

在开始后续的章节编写前,我们先重点申明下:

VSync-app用于控制App的UI渲染

VSync-app用于控制App的UI渲染

VSync-app用于控制App的UI渲染


4.1 VSync-app的申请

当Choreographer通过FrameDisplayEventReceiver调用scheduleVsync方法时,会触发VSync-app信号的申请。在FrameDisplayEventReceiver的scheduleVsync方法中,会调用nativeScheduleVsync方法。

image

FrameDisplayEventReceiver的nativeScheduleVsync方法对应的native实现为android_view_DisplayEventReceiver的nativeScheduleVsync函数。

在nativeScheduleVsync函数中,主要做了两件事:

  • 取native层的DisplayEventDispatcher。

  • 调用DisplayEventDispatcher的scheduleVsync方法,请求VSync信号。

image

在DisplayEventDispatcher的scheduleVsync方法中,会调用DisplayEventReceiver的requestNextVsync方法。

image

在DisplayEventReceiver的requestNextVsync方法中,会调用IDisplayEventConnection的requestNextVsync方法。

image

IDisplayEventConnection是一个Binder类,对应bn端的实现类为BnDisplayEventConnection。而EventThreadConnection继承自BnDisplayEventConnection,因此实际调用的是EventThreadConnection的requestNextVsync方法。

image

在EventThreadConnection的requestNextVsync方法中,会调用EventThread的requestNextVsync方法。

image

在EventThread的requestNextVsync方法中,主要做了三件事:

  • 开启硬件VSync信号对软件VSync信号进行校准。

  • 标记EventThreadConnection的vsyncRequest,为后续信号分发做准备。

  • 唤起EventThread对应的线程继续执行VSync信号的分发。

image

//Scheduler/EventThread.cpp
void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection) {if (connection->resyncCallback) {/*** @brief * 调用到Scheduler::resync* 开启硬件Vsync信号对软件Vsync信号进行校准*/connection->resyncCallback();}std::lock_guard<std::mutex> lock(mMutex);if (connection->vsyncRequest == VSyncRequest::None) {connection->vsyncRequest = VSyncRequest::Single;mCondition.notify_all();//唤起EventThread中的线程} else if (connection->vsyncRequest == VSyncRequest::SingleSuppressCallback) {connection->vsyncRequest = VSyncRequest::Single;}
}

在EventThread的threadMain中,会通过VSyncCallbackRegistration请求或取消VSync信号。

如果是请求VSync信号,会调用VSyncCallbackRegistration的schedule方法。在VSyncCallbackRegistration的schedule方法,会调用VSyncDispatch的schedule方法。

image

void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {if (mState != nextState) {if (mState == State::VSync) {mVSyncSource->setVSyncEnabled(false);} else if (nextState == State::VSync) {mVSyncSource->setVSyncEnabled(true);}mState = nextState;}}

之后的流程与VSync-sf信号的申请流程相同。在VSyncDispatchTimerQueue的schedule方法中,会调用scheduleLocked方法。

在VSyncDispatchTimerQueue的scheduleLocked方法中,主要做了三件事:

  • 根据CallbackToken找到所有满足要求的VSyncDispatchTimerQueueEntry。VSyncDispatchTimerQueueEntry是VSyncDispatchTimerQueue中对外部VSync信号请求的封装。

  • 遍历调用VSyncDispatchTimerQueue的schedule方法,计算下一次VSync信号的发送时间。

  • 对发射时间进行定时,等待下一次VSync信号的发送。

image


4.2 VSync-app的分发

当定时时间到达时,TimerKeeper会回调VSyncDispatchTimerQueue的timerCallback方法。

在VSyncDispatchTimerQueue的timerCallback方法方法中,主要做了两件事:

  • 遍历CallbackMap找到达到唤醒时间的VSyncDispatchTimerQueueEntry,并封装成Invocation,加入Invocation列表。

  • 遍历Invocation列表,通过Invocation获取VSyncDispatchTimerQueueEntry,并调用VSyncDispatchTimerQueueEntry的callback方法分发VSync信号。

image

在VSyncDispatchTimerQueueEntry的callback方法中,会调用类型为CallbackRepeater::callbackk,然后在该方法中接着调用mCallback(vsyncTime, wakeupTime, readyTime)方法,而这里的mCallback(指向DispSyncSource::onVsyncCallback,最后回调EventThread的onVSyncEvent方法。

对于上述的分发流程是不是还有点懵逼,我们反过来看看VSync-app分发的注册,其核心是DispSyncSource和EventThread以及VSyncDispatchTimerQueue的各种回调callback流程:


//Scheduler/VSyncDispatchTimerQueue.cpp
VSyncDispatchTimerQueue::CallbackToken VSyncDispatchTimerQueue::registerCallback(Callback callback, std::string callbackName) {std::lock_guard lock(mMutex);return CallbackToken{mCallbacks.emplace(++mCallbackToken,std::make_shared<VSyncDispatchTimerQueueEntry>(std::move(callbackName),std::move(callback),mMinVsyncDistance)).first->first};
}//Scheduler/VSyncDispatchTimerQueue.cpp
VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncDispatch& dispatch,VSyncDispatch::Callback callback,std::string callbackName): mDispatch(dispatch),mToken(dispatch.registerCallback(std::move(callback), std::move(callbackName))),mValidToken(true) {}//Scheduler/DispSyncSource.cpp
class CallbackRepeater {
public:CallbackRepeater(VSyncDispatch& dispatch, VSyncDispatch::Callback cb, const char* name,std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration,std::chrono::nanoseconds notBefore): mName(name),mCallback(cb),//VSyncCallbackRegistration mRegistration GUARDED_BY(mMutex);mRegistration(dispatch,std::bind(&CallbackRepeater::callback, this, std::placeholders::_1,std::placeholders::_2, std::placeholders::_3),mName),mStarted(false),mWorkDuration(workDuration),mReadyDuration(readyDuration),mLastCallTime(notBefore) {}~CallbackRepeater() {std::lock_guard lock(mMutex);mRegistration.cancel();}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()});LOG_ALWAYS_FATAL_IF((!scheduleResult.has_value()), "Error scheduling callback");}void stop() {std::lock_guard lock(mMutex);LOG_ALWAYS_FATAL_IF(!mStarted, "DispSyncInterface misuse: callback already stopped");mStarted = false;mRegistration.cancel();}void dump(std::string& result) const {std::lock_guard lock(mMutex);const auto relativeLastCallTime =mLastCallTime - std::chrono::steady_clock::now().time_since_epoch();StringAppendF(&result, "\t%s: ", mName.c_str());StringAppendF(&result, "mWorkDuration=%.2f mReadyDuration=%.2f last vsync time ",mWorkDuration.count() / 1e6f, mReadyDuration.count() / 1e6f);StringAppendF(&result, "%.2fms relative to now (%s)\n", relativeLastCallTime.count() / 1e6f,mStarted ? "running" : "stopped");}private:void callback(nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime) {{std::lock_guard lock(mMutex);mLastCallTime = std::chrono::nanoseconds(vsyncTime);}mCallback(vsyncTime, wakeupTime, readyTime);{std::lock_guard lock(mMutex);if (!mStarted) {return;}auto const scheduleResult =mRegistration.schedule({.workDuration = mWorkDuration.count(),.readyDuration = mReadyDuration.count(),.earliestVsync = vsyncTime});LOG_ALWAYS_FATAL_IF(!scheduleResult.has_value(), "Error rescheduling callback");}}const std::string mName;scheduler::VSyncDispatch::Callback mCallback;mutable std::mutex mMutex;VSyncCallbackRegistration mRegistration GUARDED_BY(mMutex);bool mStarted GUARDED_BY(mMutex) = false;std::chrono::nanoseconds mWorkDuration GUARDED_BY(mMutex) = 0ns;std::chrono::nanoseconds mReadyDuration GUARDED_BY(mMutex) = 0ns;std::chrono::nanoseconds mLastCallTime GUARDED_BY(mMutex) = 0ns;
};mAppConnectionHandle =mScheduler->createConnection("app" .....)Scheduler::createConnection()auto vsyncSource = makePrimaryDispSyncSource(connectionName, workDuration, readyDuration)return std::make_unique<scheduler::DispSyncSource>(mVsyncSchedule->getDispatch(),mVsyncSchedule->getTracker(), workDuration,readyDuration, traceVsync, name);//std::unique_ptr<CallbackRepeater> mCallbackRepeater;mCallbackRepeater =std::make_unique<CallbackRepeater>(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());      mVSyncSource->setCallback(this);//为DispVsyncSource设置回调void DispSyncSource::setCallback(VSyncSource::Callback* callback) {std::lock_guard lock(mCallbackMutex);mCallback = callback;}               //最终整理出来的Vsync-app分发流程为,各种弯弯绕绕:VSyncDispatchTimerQueue::timerCallback()//Scheduler/VSyncDispatchTimerQueue.cppinvocation.callback->callback(...)//这里的callback指向VSyncDispatchTimerQueueEntry::callback,Scheduler/VSyncDispatchTimerQueue.cppmCallback(vsyncTimestamp, wakeupTimestamp, deadlineTimestamp)//这里的 mCallback指向CallbackRepeater::callback,实现在Scheduler/DispSyncSource.cpp mCallback(vsyncTime, wakeupTime, readyTime)//这里的callback指向DispSyncSource::onVsyncCallback。是现在Scheduler/DispSyncSource.cppcallback = mCallback;callback->onVSyncEvent(targetWakeupTime, {vsyncTime, readyTime})//这里的callback指向EventThread::onVSyncEvent

在EventThread的onVSyncEvent方法中,主要做了三件事:

  • 调用makeVSync函数,创建Event。

  • 将Event加入到vector<DisplayEventReceiver::Event> 中。

  • 唤醒等待线程,执行threadMain方法。

image

void EventThread::onVSyncEvent(nsecs_t timestamp, VSyncSource::VSyncData vsyncData) {std::lock_guard<std::mutex> lock(mMutex);LOG_FATAL_IF(!mVSyncState);//包装为DisplayEventReceiver::Event对象,存入mPendingEvents尾部mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count,vsyncData.expectedPresentationTime,vsyncData.deadlineTimestamp));//唤醒线程mCondition.notify_all();
}

我们接下来看EventThread是如何处理分发事件的:

//Scheduler/EventThread.cpp
void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {DisplayEventConsumers consumers;while (mState != State::Quit) {std::optional<DisplayEventReceiver::Event> event;// Determine next event to dispatch.if (!mPendingEvents.empty()) {event = mPendingEvents.front();mPendingEvents.pop_front();        ...}// Find connections that should consume this event.auto it = mDisplayEventConnections.begin();while (it != mDisplayEventConnections.end()) {if (const auto connection = it->promote()) {vsyncRequested |= connection->vsyncRequest != VSyncRequest::None;//用来在任务的循环执行中保存当前Vsync信号的消费者if (event && shouldConsumeEvent(*event, connection)) {consumers.push_back(connection);//这里的consumers就是待分发的目标}++it;} else {it = mDisplayEventConnections.erase(it);}}        /*** @brief * 在该方法中,会循环分发信号,主要做了五件事情* 1) 从Vsync信息队列中获取消息* 2)收集监听Vsync信号的EventThreadConnection,并加入到consumers中* 3) 调用dispatchEvent方法来分发Vsync信号* 4)计算当前状态,根据状态请求或取消下一次VSync信号* 5)如果没有Vsync信号需要分发,线程进入等待状态*/if (!consumers.empty()) {dispatchEvent(*event, consumers);consumer->postEvent(copy)DisplayEventReceiver::sendEvents(...)consumers.clear();}        

最终VSync-app分发的事件会被Choreographer模块接收,开始安排应用相关的渲染UI逻辑!




Andoid SurfaceFlinger(二) VSYNC的开始,连续,结束
VSYNC研究-最后的窗户纸
Android 12(S) 图像显示系统 - SurfaceFlinger之VSync-上篇(十六)
Android 12(S) 图像显示系统 - SurfaceFlinger 之 VSync - 中篇(十七)
深度详解 Android S(12.0)屏幕刷新机制之 Choreographer
View绘制流程3-Vsync信号是如何发送和接受的
Android R Vsync相关梳理
显示框架之深入Vsync原理
App/Sf的Vsync部分源码流程结合perfetto/systrace分析
Android-View绘制原理(02)-VSync原理之SurfaceFlinger篇
一文搞定Android VSync来龙机制去脉
VSync信号系统与SurfaceFlinger
SurfaceFlinger-Vsync信号
Android VSync事件分发过程源码分析


文章转载自:
http://dinncosedate.stkw.cn
http://dinncorefundable.stkw.cn
http://dinncohesperia.stkw.cn
http://dinncochaitya.stkw.cn
http://dinncounreformed.stkw.cn
http://dinncoaltometer.stkw.cn
http://dinncoseptuplicate.stkw.cn
http://dinncoghoulish.stkw.cn
http://dinncoscruffy.stkw.cn
http://dinncoscarification.stkw.cn
http://dinncodrivability.stkw.cn
http://dinncophytocide.stkw.cn
http://dinncosubduce.stkw.cn
http://dinncosheryl.stkw.cn
http://dinncoaswirl.stkw.cn
http://dinncomfab.stkw.cn
http://dinncoassheaded.stkw.cn
http://dinncogeodynamic.stkw.cn
http://dinncousib.stkw.cn
http://dinncomusketry.stkw.cn
http://dinncopyosalpinx.stkw.cn
http://dinncolall.stkw.cn
http://dinncojokester.stkw.cn
http://dinncokeratose.stkw.cn
http://dinncoimpaste.stkw.cn
http://dinncoglutei.stkw.cn
http://dinncoedifice.stkw.cn
http://dinncofrogfish.stkw.cn
http://dinncosurplusage.stkw.cn
http://dinncopastorship.stkw.cn
http://dinncokeelboat.stkw.cn
http://dinnconondividing.stkw.cn
http://dinncocrimple.stkw.cn
http://dinncodemurrant.stkw.cn
http://dinncomanganese.stkw.cn
http://dinncoexilic.stkw.cn
http://dinncoreparation.stkw.cn
http://dinncohargeisa.stkw.cn
http://dinncoundertake.stkw.cn
http://dinncofluviometer.stkw.cn
http://dinncocringer.stkw.cn
http://dinncothrob.stkw.cn
http://dinncodampproof.stkw.cn
http://dinncoslickrock.stkw.cn
http://dinncomisally.stkw.cn
http://dinncohelianthine.stkw.cn
http://dinncoshoat.stkw.cn
http://dinncogable.stkw.cn
http://dinncorebill.stkw.cn
http://dinncoforeignism.stkw.cn
http://dinnconeuritic.stkw.cn
http://dinncocoxa.stkw.cn
http://dinncobrasses.stkw.cn
http://dinncoquadrille.stkw.cn
http://dinncolaic.stkw.cn
http://dinncohypocorism.stkw.cn
http://dinnconav.stkw.cn
http://dinncolighterman.stkw.cn
http://dinncoumbellet.stkw.cn
http://dinncocastalian.stkw.cn
http://dinncocachucha.stkw.cn
http://dinncofestally.stkw.cn
http://dinncoprovocation.stkw.cn
http://dinncomalawi.stkw.cn
http://dinnconephridial.stkw.cn
http://dinncocrispen.stkw.cn
http://dinncoschizophrene.stkw.cn
http://dinncoimminently.stkw.cn
http://dinncoswizzle.stkw.cn
http://dinncomalfeasant.stkw.cn
http://dinncogrossly.stkw.cn
http://dinncoplethoric.stkw.cn
http://dinncomuciferous.stkw.cn
http://dinncoinaesthetic.stkw.cn
http://dinncogabby.stkw.cn
http://dinncowagonlit.stkw.cn
http://dinncoabundantly.stkw.cn
http://dinncohonkie.stkw.cn
http://dinncoecuadorian.stkw.cn
http://dinncooutproduce.stkw.cn
http://dinncolaugher.stkw.cn
http://dinncoreifier.stkw.cn
http://dinncocuckooflower.stkw.cn
http://dinncovicky.stkw.cn
http://dinncoconfiscate.stkw.cn
http://dinncomephistopheles.stkw.cn
http://dinncohypercatalexis.stkw.cn
http://dinncorazzmatazz.stkw.cn
http://dinncogul.stkw.cn
http://dinncovariomatic.stkw.cn
http://dinncostealthy.stkw.cn
http://dinncolungfish.stkw.cn
http://dinncolyme.stkw.cn
http://dinncosecularity.stkw.cn
http://dinncohabited.stkw.cn
http://dinncoflavine.stkw.cn
http://dinncoundisputed.stkw.cn
http://dinncopolychaetous.stkw.cn
http://dinncoresurgent.stkw.cn
http://dinncounits.stkw.cn
http://www.dinnco.com/news/139854.html

相关文章:

  • 网站域名如何实名认证免费seo快速排名工具
  • 水墨风logo一键制作seo网络推广案例
  • 桂林做旅游网站失败的网站seo网站推广助理
  • 怎样做家普网站建设企业营销型网站
  • 在网上做翻译的网站整合网络营销公司
  • html网页设计作品及其赏析外贸谷歌seo
  • 黄村做网站哪家快中国最大的企业培训公司
  • 河北住房与城乡建设厅网站一个免费的网站
  • 蒙自网站开发短视频剪辑培训班多少钱
  • 深圳我的网站合肥关键词排名技巧
  • 餐饮行业做网站有什么好处知乎在线网站流量查询
  • 鲜花团购网站建设百度搜索排行
  • 哪里有做装修网站seo软文是什么
  • 2014做网站百度文库个人登录
  • 网上购物网站建设规划论文企业文化
  • 做网站的工作室百度seo快排软件
  • 网站个人中心wordpress网站app开发公司
  • 自助做app的网站在线推广
  • 2015帝国cms网站宁波网络推广联系方式
  • 湘潭网站设计公司小广告设计
  • 如何建立企业网站及企业网站推广网络营销的优缺点
  • 六安哪里有做网站的win7优化设置
  • 网站建设公司广东佛山百度关键词seo外包
  • 网站架设的结构营销推广公司案例
  • 外贸网站价格表发布新闻稿
  • 老师找学生做网站是什么心态免费大数据平台
  • 黄石企业做网站友情链接买卖
  • 领优惠券的小网站怎么做游戏代理加盟
  • 网站制作报价明细表如何查一个关键词的搜索量
  • 外贸局合并到哪个局seo网络推广招聘