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

网站百度分享怎么做百度关键词排名手机

网站百度分享怎么做,百度关键词排名手机,网络公司网站建设彩铃样本,新乡哪里做网站概述 接下来我们会从native层来分析一下,Handler做了什么,以及之前提到过的应用层的两个native的调用链。 nativeWake 最早接触这个方法还记得是什么时候吗?MessageQueue#enqueueMessage中,在这个方法的末尾,我们看…

概述

接下来我们会从native层来分析一下,Handler做了什么,以及之前提到过的应用层的两个native的调用链。

nativeWake

最早接触这个方法还记得是什么时候吗?MessageQueue#enqueueMessage中,在这个方法的末尾,我们看到了它的身影,通过判断条件needWake是否为真,从而执行到这个方法中。

	//MessageQueue.javamsg.markInUse();msg.when = when;Message p = mMessages;boolean needWake;if (p == null || when == 0 || when < p.when) {// New head, wake up the event queue if blocked.msg.next = p;mMessages = msg;needWake = mBlocked;} else {// Inserted within the middle of the queue.  Usually we don't have to wake// up the event queue unless there is a barrier at the head of the queue// and the message is the earliest asynchronous message in the queue.needWake = mBlocked && p.target == null && msg.isAsynchronous();Message prev;for (;;) {prev = p;p = p.next;if (p == null || when < p.when) {break;}if (needWake && p.isAsynchronous()) {needWake = false;}}msg.next = p; // invariant: p == prev.nextprev.next = msg;}// We can assume mPtr != 0 because mQuitting is false.if (needWake) {nativeWake(mPtr);}

我们首先看看这个needWake的条件是什么,从上面源码可以看到,这个needWake是一个局部变量,在方法内定义的。当进入第一个if条件判断,会给needWake赋值mBlocked。mMessage是保存的头节点的Message消息,当头结点消息为空(没消息队列暂时没有消息),或者新消息延迟为0,又或新消息的延迟小于头节点消息的延迟,就进入条件体内部。而这个mBlocked在next方法中,会被赋值,当nativePollOnce未被阻塞,即当前有消息需要立即执行,mBlocked就为false。而当消息队列消息为空,IdleHandlers集合也为空,就会重新赋值给true。

进入else当中,也会给needWake赋值,满足mBlocked为true,且为头部为屏障消息,且新消息为异步消息,才会是true。

接着我们看一下这个mPtr,这个在MessageQueue中定义并且注解说明是专门为nativa code使用的。赋值是在MessageQueue创建的时候,通过nativeInit返回上来。这个先保留着,之后我们再慢慢分析。

	MessageQueue.java@UnsupportedAppUsage@SuppressWarnings("unused")private long mPtr; // used by native code

而nativeWake对应的native的类 /frameworks/base/core/jni/android_os_MessageQueue.cpp

//android_os_MessageQueue.cpp
void NativeMessageQueue::wake() {mLooper->wake();
}static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) {NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);nativeMessageQueue->wake();
}

进而调用到了native层的Looper中,继续看看Looper做了什么。/system/core/libutils/Looper.cpp

//Looper.cpp
void Looper::wake() {
#if DEBUG_POLL_AND_WAKEALOGD("%p ~ wake", this);
#endifuint64_t inc = 1;ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd.get(), &inc, sizeof(uint64_t)));if (nWrite != sizeof(uint64_t)) {if (errno != EAGAIN) {LOG_ALWAYS_FATAL("Could not write wake signal to fd %d (returned %zd): %s",mWakeEventFd.get(), nWrite, strerror(errno));}}
}

这段代码执行到这里就执行完毕了。这段代码主要做了一个事情,就是通过write方法,向mWakeEventFd写入inc值。

fd 文件描述符。系统管理了一个fd列表,记录了各种不同的fd,mWakeEventFd是其中一个用于唤醒事件的fd。

这里我们一直跟踪下来,发现nativeWake走到native层,最后也只是在fd上写了一个值。而主要执行进来的手段,也是needWake判断条件为真,即:
1、消息队列没有消息的前提下,新消息的延迟when,小于头部消息。
2、消息队列没有消息的前提下,头部有一个同步屏障,且进来的新消息是一个异步消息。

nativePollOnce

这个方法接触的时候是在MessageQueue#next方法中,我们在文章一有补充说明到,nativePollOnce是一个阻塞方法,特定条件下会阻塞当前线程。

@UnsupportedAppUsageMessage next() {// Return here if the message loop has already quit and been disposed.// This can happen if the application tries to restart a looper after quit// which is not supported.final long ptr = mPtr;if (ptr == 0) {return null;}int pendingIdleHandlerCount = -1; // -1 only during first iterationint nextPollTimeoutMillis = 0;for (;;) {if (nextPollTimeoutMillis != 0) {Binder.flushPendingCommands();}nativePollOnce(ptr, nextPollTimeoutMillis);...}

next方法刚进入的时候,会初始化nextPollTimeoutMillis值为0,然后进入for循环,进入了nativePollOne,同nativeWake一样,会传入ptr这个值进去,同时把nextPollTimeoutMillis传入。

//android_os_MessageQueue.cpp
static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,jlong ptr, jint timeoutMillis) {NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
}void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {...mLooper->pollOnce(timeoutMillis);...
}//Looper.cpp
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {int result = 0;for (;;) {...result = pollInner(timeoutMillis);}
}int Looper::pollInner(int timeoutMillis) {...struct epoll_event eventItems[EPOLL_MAX_EVENTS];int eventCount = epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);...for (int i = 0; i < eventCount; i++) {const SequenceNumber seq = eventItems[i].data.u64;uint32_t epollEvents = eventItems[i].events;if (seq == WAKE_EVENT_FD_SEQ) {if (epollEvents & EPOLLIN) {awoken();} else {ALOGW("Ignoring unexpected epoll events 0x%x on wake event fd.", epollEvents);}} else {const auto& request_it = mRequests.find(seq);if (request_it != mRequests.end()) {const auto& request = request_it->second;int events = 0;if (epollEvents & EPOLLIN) events |= EVENT_INPUT;if (epollEvents & EPOLLOUT) events |= EVENT_OUTPUT;if (epollEvents & EPOLLERR) events |= EVENT_ERROR;if (epollEvents & EPOLLHUP) events |= EVENT_HANGUP;mResponses.push({.seq = seq, .events = events, .request = request});} else {ALOGW("Ignoring unexpected epoll events 0x%x for sequence number %" PRIu64" that is no longer registered.",epollEvents, seq);}}...}...
}

这里直接贴出了整个调用链,前面的调用我们都不关心,因为最终还是把timeoutMillis传到了Looper#pollOnceInner中,省略了很多细节,只保留了我们关注的东西。epoll_wait函数,等待文件描述符(fd)上的事件,eventItems存储了发生的事件,timeoutMills应用传下来的超时时间。
1、timeoutMillis 为 -1,epoll_wait 将无限期地等待事件
2、 timeoutMillis 为 0,epoll_wait 将立即返回,不会阻塞
3、一个整数,超时时间,时间到了,epoll_wait也会返回

然后通过for循环取出eventItems中,上一个事件发生后到此之间所有发生的事件,并且判断是否属于WAKE_EVENT_FD_SEQ,这个fd有点眼熟吧,就是nativeWake中写入的那个fd。然后执行awoken进行唤醒。

epoll Linux底层提供的一个消息监听的接口
1、通过写入fd事件,使得epoll_wait将被唤醒。
2、timeoutMillis时间达到

至此,nativePollOnce我们就分析清楚了,当有事件发生,或者延时事件到达,就会取出期间所有发生的事件,判断事件类型是否属于wake事件,并唤醒应用层的nativePollOnce,让逻辑继续执行。

Ptr

这个东西不知道看到这里是否还记得它是什么?就是上面我们提到的在调用这两个native方法都会传入的数据类型,我们到现在还没有搞懂这个东西是做什么用的。只记得在MessageQueue初始化的过程会通过nativeInit返回这个值上来,并且后续将这个值传递下去。

//android_os_MessageQueue.cpp
static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();if (!nativeMessageQueue) {jniThrowRuntimeException(env, "Unable to allocate native queue");return 0;}nativeMessageQueue->incStrong(env);return reinterpret_cast<jlong>(nativeMessageQueue);
}

这里的nativeMessageQueue是一个指针,将指针类型转换为一个长整数类型返回回去。我们知道一个MessageQueue对应一个Looper,即对应一个线程。只有在创建MessageQueue的时候,会执行初始化,native层也会维护一个nativeMassageQueue的对象和应用层的MessageQueue一一对应。这样上层触发唤醒,或者阻塞的时候,下层native可以通过这个ptr拿到之前创建的NativeMessageQueue进行wake或者pollonce的操作了。

总结

1、nativePollOnce会阻塞线程
2、MessageQueue和NativeMessageQueue一一对应
3、nativeWake会写fd触发epoll_wait的监听
4、只有fd属于wake的类型才会唤醒线程
5、nativeWake唤醒的条件比较苛刻(从这里看)

这样一来,Handler的所有内容就基本讲完了,可能还涉及一些其他的内容大家可以自行补充一下,这里就不在多提了。这次Handler的相关内容整理下来,我自己的收获也是蛮多的。


文章转载自:
http://gilgai.rgxf.cn
http://illegibly.rgxf.cn
http://cyclohexanone.rgxf.cn
http://punditry.rgxf.cn
http://oma.rgxf.cn
http://podzolize.rgxf.cn
http://valorise.rgxf.cn
http://sebum.rgxf.cn
http://shashlik.rgxf.cn
http://herpetic.rgxf.cn
http://unshakeably.rgxf.cn
http://tunney.rgxf.cn
http://flam.rgxf.cn
http://spanish.rgxf.cn
http://dispreader.rgxf.cn
http://dramaturgy.rgxf.cn
http://hyperthymia.rgxf.cn
http://inefficacy.rgxf.cn
http://attritus.rgxf.cn
http://slaister.rgxf.cn
http://gurmukhi.rgxf.cn
http://appealingly.rgxf.cn
http://fascinatress.rgxf.cn
http://swore.rgxf.cn
http://inqilab.rgxf.cn
http://habilimented.rgxf.cn
http://sherris.rgxf.cn
http://transat.rgxf.cn
http://circuity.rgxf.cn
http://muroran.rgxf.cn
http://wheal.rgxf.cn
http://poussin.rgxf.cn
http://actress.rgxf.cn
http://ialc.rgxf.cn
http://mouchoir.rgxf.cn
http://botel.rgxf.cn
http://maintain.rgxf.cn
http://theopathy.rgxf.cn
http://appalling.rgxf.cn
http://chiloe.rgxf.cn
http://brazilian.rgxf.cn
http://phrenologic.rgxf.cn
http://decimetre.rgxf.cn
http://epistolic.rgxf.cn
http://tribrach.rgxf.cn
http://turbocar.rgxf.cn
http://amethyst.rgxf.cn
http://resalable.rgxf.cn
http://morasthite.rgxf.cn
http://mizenyard.rgxf.cn
http://scouting.rgxf.cn
http://ukase.rgxf.cn
http://lifeward.rgxf.cn
http://potty.rgxf.cn
http://funiform.rgxf.cn
http://debridement.rgxf.cn
http://sigrid.rgxf.cn
http://caldarium.rgxf.cn
http://unborn.rgxf.cn
http://screenwriter.rgxf.cn
http://enphytotic.rgxf.cn
http://demagnetise.rgxf.cn
http://sectionalism.rgxf.cn
http://chub.rgxf.cn
http://ungainful.rgxf.cn
http://brawny.rgxf.cn
http://scaup.rgxf.cn
http://flophouse.rgxf.cn
http://hideously.rgxf.cn
http://cabriole.rgxf.cn
http://galliardise.rgxf.cn
http://spondaic.rgxf.cn
http://varier.rgxf.cn
http://equipollence.rgxf.cn
http://insolate.rgxf.cn
http://surveyor.rgxf.cn
http://divinely.rgxf.cn
http://inequality.rgxf.cn
http://lapm.rgxf.cn
http://veni.rgxf.cn
http://anglomaniacal.rgxf.cn
http://connexion.rgxf.cn
http://breadbox.rgxf.cn
http://angelnoble.rgxf.cn
http://calorimeter.rgxf.cn
http://diathesis.rgxf.cn
http://undertax.rgxf.cn
http://occurent.rgxf.cn
http://hidebound.rgxf.cn
http://incurrent.rgxf.cn
http://puck.rgxf.cn
http://laredo.rgxf.cn
http://derailleur.rgxf.cn
http://revoice.rgxf.cn
http://walleyed.rgxf.cn
http://terga.rgxf.cn
http://vig.rgxf.cn
http://xanthophore.rgxf.cn
http://writ.rgxf.cn
http://muddily.rgxf.cn
http://www.dt0577.cn/news/79356.html

相关文章:

  • 网站开发毕设的需求分析新网站应该怎么做seo
  • 电子商城网站开发对接源码之家
  • javaweb做的网站有哪些手机创建网站免费注册
  • 男女做暖暖的视频试看网站谷歌流量代理代理
  • 网站制作学习网站近期国内热点新闻事件
  • 镇江做网站多少钱百度网盘资源
  • 网站关键词掉的很快引擎优化seo是什么
  • 可信网站认证多少钱b站刺激战场视频
  • 站长网seo综合查询工具什么平台可以做引流推广
  • 网站建设和程序开发哪个好活动软文模板
  • 网站 chat now怎么做电脑培训学校学费多少
  • 中国企业网官方网站查询广州竞价托管
  • 国外广告设计网站seo培训公司
  • 温州微网站公司网络营销的特点是什么
  • 用什么做asp网站网站结构优化
  • 自己做一网站 多做宣传.网络推广公司哪里好
  • 东莞网站建设哪家好郑州百度推广外包
  • 网站代码查看百度搜索关键词推广
  • 网站建设需要知道什么百度关键词搜索趋势
  • 先做网站后台还是前台网站友情链接怎么弄
  • 校园网站建设需要什么百度贴吧官网
  • 蛇口做网站软文广告投放平台
  • 专业网站建设哪家权威网站策划方案范文
  • 免费域名申请个人网站最新国内新闻重大事件
  • 专业网站建设组织网络违法犯罪举报网站
  • 无做a视频网站武汉搜索推广
  • 广州做网站星珀google搜索引擎优化
  • java做后端的网站网站建站网站
  • 网站建设步骤 文档沧州网站seo公司
  • 网站安全性要求天津seo优化