在Android的消息机制中。不仅提供了供Application 开发使用的java的消息循环。事实上java的机制终于还是靠native来实现的。在native不仅提供一套消息传递和处理的机制,还提供了自己定义文件描写叙述符的I/O时间的监听机制。以下我们从详细代码中分析一下。

Native层的关键类:

Looper.cpp.该类中提供了pollOnce 和wake的休眠和唤醒机制。

同一时候在构造函数中也创建 管道 并增加epoll的机制中。来监听其状态变化。

Looper::Looper(bool allowNonCallbacks) :
mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
int wakeFds[2];
int result = pipe(wakeFds);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno); mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1]; result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d",
errno); result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",
errno); // Allocate the epoll instance and register the wake pipe.
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno); struct epoll_event eventItem;
memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
eventItem.events = EPOLLIN;
eventItem.data.fd = mWakeReadPipeFd;
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d",
errno);
}

详细epoll机制,请參看我还有一篇。转载的epoll机制。一种高效改良的poll机制。

事实上looper在整个消息循环中,主要是实现MessageQueue中休眠和唤醒机制。

 struct epoll_event eventItems[EPOLL_MAX_EVENTS];
int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis); // Acquire lock.
mLock.lock(); // Check for poll error.
if (eventCount < 0) {
if (errno == EINTR) {
goto Done;
}
ALOGW("Poll failed with an unexpected error, errno=%d", errno);
result = ALOOPER_POLL_ERROR;
goto Done;
} // Check for poll timeout.
if (eventCount == 0) {
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ pollOnce - timeout", this);
#endif
result = ALOOPER_POLL_TIMEOUT;
goto Done;
} // Handle all events.
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ pollOnce - handling events from %d fds", this, eventCount);
#endif for (int i = 0; i < eventCount; i++) {
int fd = eventItems[i].data.fd;
uint32_t epollEvents = eventItems[i].events;
if (fd == mWakeReadPipeFd) {
if (epollEvents & EPOLLIN) {
awoken();
} else {
ALOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.", epollEvents);
}
} else {
ssize_t requestIndex = mRequests.indexOfKey(fd);
if (requestIndex >= 0) {
int events = 0;
if (epollEvents & EPOLLIN) events |= ALOOPER_EVENT_INPUT;
if (epollEvents & EPOLLOUT) events |= ALOOPER_EVENT_OUTPUT;
if (epollEvents & EPOLLERR) events |= ALOOPER_EVENT_ERROR;
if (epollEvents & EPOLLHUP) events |= ALOOPER_EVENT_HANGUP;
pushResponse(events, mRequests.valueAt(requestIndex));
} else {
ALOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "
"no longer registered.", epollEvents, fd);
}
}

从以上代码中能够看出,looper的pollonce主要在监听管道的read端是否有事件到来,同一时候在else以下能够实现对 自己定义文件描写叙述符的监听作用。

详细获取下个消息,还是在MessageQueue.java 的next()实现并返回一个msg。

那什么时候应该唤醒和怎么唤醒呢?

參看MessageQueue的代码。在相关队列中加入一个msg时。调用用nativeWake方法

static void android_os_MessageQueue_nativeWake(JNIEnv* env, jobject obj, jint ptr) {
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
return nativeMessageQueue->wake();
}
void Looper::wake() {
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ wake", this);
#endif ssize_t nWrite;
do {
nWrite = write(mWakeWritePipeFd, "W", 1);
} while (nWrite == -1 && errno == EINTR); if (nWrite != 1) {
if (errno != EAGAIN) {
ALOGW("Could not write wake signal, errno=%d", errno);
}
}
}

唤醒的方法就是向mWakeWirtePipeFd写一个‘w',触发epoll的mWakeReadPipFdd唤醒进程,进而从MessageQueue的next方法,获取下一个msg。

final Message next() {
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0; for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(mPtr, nextPollTimeoutMillis); synchronized (this) {
if (mQuiting) {
return null;
} // Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (false) Log.v("MessageQueue", "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}

Looper对文件描写叙述符监控和处理:

looper能够对普通文件,设备文件或套接字都能够监听。android本身已经提供了一套机制。

/**
* Adds a new file descriptor to be polled by the looper.
* If the same file descriptor was previously added, it is replaced.
*
* "fd" is the file descriptor to be added.
* "ident" is an identifier for this event, which is returned from ALooper_pollOnce().
* The identifier must be >= 0, or ALOOPER_POLL_CALLBACK if providing a non-NULL callback.
* "events" are the poll events to wake up on. Typically this is ALOOPER_EVENT_INPUT.
* "callback" is the function to call when there is an event on the file descriptor.
* "data" is a private data pointer to supply to the callback.
*
* There are two main uses of this function:
*
* (1) If "callback" is non-NULL, then this function will be called when there is
* data on the file descriptor. It should execute any events it has pending,
* appropriately reading from the file descriptor. The 'ident' is ignored in this case.
*
* (2) If "callback" is NULL, the 'ident' will be returned by ALooper_pollOnce
* when its file descriptor has data available, requiring the caller to take
* care of processing it.
*
* Returns 1 if the file descriptor was added or -1 if an error occurred.
*
* This method can be called on any thread.
* This method may block briefly if it needs to wake the poll.
*/
int ALooper_addFd(ALooper* looper, int fd, int ident, int events,
ALooper_callbackFunc callback, void* data);

通过以上接口,大家能够在native层实现各种文件的监听和处理。另外android 还提供Native层的message和MessageHandler来处理消息机制。

这些都在Looper.h文件里。大家有时间能够研究一下。

/**
* Interface for a Looper message handler.
*
* The Looper holds a strong reference to the message handler whenever it has
* a message to deliver to it. Make sure to call Looper::removeMessages
* to remove any pending messages destined for the handler so that the handler
* can be destroyed.
*/
class MessageHandler : public virtual RefBase {
protected:
virtual ~MessageHandler() { } public:
/**
* Handles a message.
*/
virtual void handleMessage(const Message& message) = 0;
};

感觉和java的非常类似吧。

Android Framework 分析---2消息机制Native层的更多相关文章

  1. Android消息传递之Handler消息机制

    前言: 无论是现在所做的项目还是以前的项目中,都会遇见线程之间通信.组件之间通信,目前统一采用EventBus来做处理,在总结学习EventBus之前,觉得还是需要学习总结一下最初的实现方式,也算是不 ...

  2. Chrome浏览器扩展开发系列之十四:本地消息机制Native messagin

    Chrome浏览器扩展开发系列之十四:本地消息机制Native messaging 2016-11-24 09:36 114人阅读 评论(0) 收藏 举报  分类: PPAPI(27)  通过将浏览器 ...

  3. android开发系列之消息机制

    最近接触到一个比较有挑战性的项目,我发现里面使用大量的消息机制,现在这篇博客我想具体分析一下:android里面的消息到底是什么东西,消息机制到底有什么好处呢? 其实说到android消息机制,我们可 ...

  4. Android Handle,Looper,Message消息机制

    尊重原创,转载请标明出处    http://blog.csdn.net/abcdef314159 我们知道在Android中更新UI都是在主线程中,而操作一些耗时的任务则须要在子线程中.假设存在多个 ...

  5. Android Handler MessageQueue Looper 消息机制原理

    提到Android里的消息机制,便会提到Message.Handler.Looper.MessageQueue这四个类,我先简单介绍以下这4个类 之间的爱恨情仇. Message 消息的封装类,里边存 ...

  6. Android学习笔记之消息机制

    Android的消息机制主要是指Handler的运行机制以及Handler所附带的MessageQueue和Looper的工作过程.   1.为什么要使用Handler? Android规定访问UI只 ...

  7. Chrome浏览器扩展开发系列之十四:本地消息机制Native messaging

    通过将浏览器所在客户端的本地应用注册为Chrome浏览器扩展的“本地消息主机(native messaging host)”,Chrome浏览器扩展还可以与客户端本地应用之间收发消息. 客户端的本地应 ...

  8. Android源代码分析-资源载入机制

    转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/23387079 (来自singwhatiwanna的csdn博客) 前言 我们 ...

  9. android 视频录制 混淆打包 之native层 异常的解决

    原文地址:http://www.cnblogs.com/linguanh/    (滑至文章末,直接看解决方法) 问题起因: 前5天,因为项目里面有个类似 仿微信 视频录制的功能, 先是上网找了个 开 ...

随机推荐

  1. 将双击“root的主文件”弹出的窗口设置为文件浏览器

    1.双击桌面"root的文件夹"图标, 在过去Centos版本之前,每次双击“root主文件夹”都会弹出文件管理窗口: 解决办法:         关闭所有窗口后,重新双击图标: ...

  2. 51nod 1240 莫比乌斯函数【数论+莫比乌斯函数】

    1240 莫比乌斯函数 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题  收藏  关注 莫比乌斯函数,由德国数学家和天文学家莫比乌斯提出.梅滕斯(Mertens)首先使用 ...

  3. Dfs【p1454】 圣诞夜的极光

    题目描述-->p1454 圣诞夜的极光 题意概括: 寻找联通块数量,这里的连通块定义与其他的不同. 这里定义为曼哈顿距离不超过2的都属于一个联通块. 什么?不知道曼哈顿距离是啥? 曼哈顿距离简易 ...

  4. 列(Column)

     同样是生肉,不同的生肉又有不同的特性,有的生肉是里脊肉,有的生肉是前臀尖,这块生肉是18公斤,而那块生肉是12公斤,这块生肉是12.2 元/公斤,而那块生肉是13.6 元/公斤.每块肉都有各自的不同 ...

  5. Xamarin XAML语言教程基本页面ContentPage占用面积(二)

    Xamarin XAML语言教程基本页面ContentPage占用面积(二) Xamarin XAML语言教程基本页面ContentPage占用面积(二)内容页面的添加 为了方便用户添加Content ...

  6. Mysql数据库的安装及配置

    本文转载自http://www.cnblogs.com/xiaoluo501395377/archive/2013/04/07/3003278.html 如果要在Linux上做j2ee开发,首先得搭建 ...

  7. [Codeforces 19E] Fiary

    Brief Intro: 给定一个无向图,询问删去哪条边能使得剩下的图为一个二分图,输出所有结果 Algorithm: 关于二分图的重要性质:一个图为二分图的充要条件为其中没有奇环 1.如果没有奇环, ...

  8. [Contest20180122]超级绵羊异或

    题意:求$a\ xor\left(a+b\right)xor\cdots xor\left(a+b\left(n-1\right)\right)$ 对每一位求答案,第$k$的答案是$\sum\limi ...

  9. [CF773D]Perishable Roads

    [CF773D]Perishable Roads 题目大意: 一个\(n(n\le2000)\)个点的完全图\(G\),定义\(d(x)\)为生成树上点\(x\)到根路径上的最小边权.问图\(G\)的 ...

  10. 微服务之SpringCloud实战(一):SpringCloud简介

    什么是微服务架构 微服务架构就是系统架构设计的一种风格,它主旨将一个独立的系统,拆分成各个微服务,各个微服务独立运行,他们之间通过Http的Restful API进行通信,拆分出来的微服务是根据原系统 ...