Android消息机制的疑难点说明

参考:
http://blog.csdn.net/chwan_gogogo/article/details/46953575 Java层
http://blog.csdn.net/chwan_gogogo/article/details/46953563 专讲C层文件描述符
http://blog.csdn.net/chwan_gogogo/article/details/46953549 专讲C层Looper.cpp

https://my.oschina.net/youranhongcha/blog/492591 C层和Java层,图文并茂
http://blog.csdn.net/kc58236582/article/details/51883024 C层和Java层
http://blog.csdn.net/kaiyoushiwo007/article/details/8270381  代码较旧

讲解eventfd使用的文章:
http://blog.csdn.net/hustfoxy/article/details/23613101
http://blog.chinaunix.net/uid-23146151-id-3069427.html

讲解epoll的文章:
http://www.cnblogs.com/venow/archive/2012/11/30/2790031.html
http://www.open-open.com/lib/view/open1410403215664.html
http://blog.csdn.net/xiajun07061225/article/details/9250579
http://www.cnblogs.com/Anker/p/3265058.html
https://my.oschina.net/dclink/blog/287198 主要讲原理,不涉及细节


1. Message
通过成员next自成链表,通过when在链表中排序,通过sPool用对象池技术,有异步和同步消息;
MessageQueue类中的removeMessages和Looper类中的loop会调用recycle。
继承了Parcelable,方便进程间通信的传递;
Object obj对象用来在进程通信时,传递框架层的Parcelable对象;
//从sPool的头节点取出一个message,或者创建一个新的message
public static Message obtain() {
    synchronized (sPoolSync) {
        if (sPool != null) {
            Message m = sPool;
            sPool = m.next;
            m.next = null;
            m.flags = 0; // clear in-use flag
            sPoolSize--;
            return m;
        }
    }
    return new Message();
}
//回收消息,放入sPool中
public void recycle() {
    if (isInUse()) {
    	//抛出异常
        return;
    }
    recycleUnchecked();
}
/**
 * Recycles a Message that may be in-use.
 * Used internally by the MessageQueue and Looper when disposing of queued Messages.
 */
void recycleUnchecked() {
    // Mark the message as in use while it remains in the recycled object pool.
    // Clear out all other details.
    flags = FLAG_IN_USE;
    what = 0;
    arg1 = 0;
    arg2 = 0;
    ......

    synchronized (sPoolSync) {
        if (sPoolSize < MAX_POOL_SIZE) {
            next = sPool;
            sPool = this;
            sPoolSize++;
        }
    }
}
2. Handler
创建并发送消息,最后再处理消息。对于一个线程来说,MessageQueue和Looper都是唯一的,而多个Handler是可以共享同一个线程的MessageQueue和Looper的引用。

Handler里面有以下几类核心函数共同完成上面的功能。
构造函数:可指定Looper或者用当前线程的Looper,可指定回调函数以及是否异步;
创建消息:调用Message.obtain方法;
发送消息:post和send系列方法可延时发送,调用MessageQueue的enqueueMessage
移除消息:调用MessageQueue的removeMessages
//消息分发及处理:调用Message自带的Runnable接口,或者Handler自带的callback接口,或者handleMessage
public void dispatchMessage(Message msg) {  
    if (msg.callback != null) {  
        handleCallback(msg);  //即message.callback.run();
    } else {  
        if (mCallback != null) {  
            if (mCallback.handleMessage(msg)) {  
                return;  
            }  
        }  
        handleMessage(msg);  
    }  
}

getIMessenger返回Binder的本地对象MessengerImpl,包含了send(Message)接口;

runWithScissors和BlockingRunnable

//当在同一个线程时,会直接执行这个runnable,否则runnable会放在handler所在线程的队列中,
//调用runWithScissors的线程会wait,直到runnable执行或者超时;
public final boolean runWithScissors(final Runnable r, long timeout) {
    if (Looper.myLooper() == mLooper) {
        r.run();
        return true;
    }

    BlockingRunnable br = new BlockingRunnable(r);
    return br.postAndWait(this, timeout);
}
private static final class BlockingRunnable implements Runnable {
    private final Runnable mTask;
    private boolean mDone;


    public BlockingRunnable(Runnable task) {
        mTask = task;
    }

    @Override
    public void run() {
        try {
            mTask.run();
        } finally {
            synchronized (this) {
                mDone = true;
                notifyAll();	//让执行runWithScissors的线程恢复
            }
        }
    }

    public boolean postAndWait(Handler handler, long timeout) {
        if (!handler.post(this)) {  //放到handler线程所在的队列中
            return false;
        }

        synchronized (this) {	//停止执行了runWithScissors的线程一段时间
            if (timeout > 0) {
                final long expirationTime = SystemClock.uptimeMillis() + timeout;
                while (!mDone) {
                    long delay = expirationTime - SystemClock.uptimeMillis();
                    if (delay <= 0) {
                        return false; // timeout
                    }
                    try {
                        wait(delay);
                    } catch (InterruptedException ex) {
                    }
                }
            } else {
                while (!mDone) {
                    try {
                        wait();
                    } catch (InterruptedException ex) {
                    }
                }
            }
        }
        return true;
    }
}
3. Looper
通过ThreadLocal将自己保存到线程独立的数据中;通过quit和quitSafely退出;
不停的从MessageQueue里面抽取消息,然后分发下去,直到抽取到的消息是退出消息,Looper结束,线程即将退出
public static void loop() {
    final Looper me = myLooper();
    final MessageQueue queue = me.mQueue;

    for (;;) {
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }
        try {
            msg.target.dispatchMessage(msg);
        } finally {
            ......
        }
        msg.recycleUnchecked();
    }
}
4. MessageQueue
mMessages指向第一个Message
IdleHandler子类的作用:当消息队列取不出消息时,提供一个接口,以便在空闲时做一些操作,如GC。

Barrier的作用:当往queue里插入了一个barrier,会阻碍了同步消息的处理,而对异步消息没有影响。只有remove了这个barrier,queue里面的同步消息才能继续被处理。这也是同步消息与异步消息的区别所在。

next(){
	int pendingIdleHandlerCount = -1; //特殊标记-1,表示可以执行一次空闲回调
        int nextPollTimeoutMillis = 0;	//每次执行next时都先不休眠

	for(;;){
		//nextPollTimeoutMillis为-1表示一直阻塞,0表示不阻塞,大于零表示阻塞一段时间
		nativePollOnce(ptr, nextPollTimeoutMillis);

		尝试取得消息队列的第一个消息;
		if(是barrier),则找到后面的第一个异步消息;
		if(找到了一个消息,可同可异){
			如果消息的触发时间还未到达,则算出nextPollTimeoutMillis表示还需休眠的时间,否则从消息队列中取下并返回此消息,循环结束;
		}else{
			队列中无消息则nextPollTimeoutMillis为-1,表示将要一直休眠;
		}

		如果设置了退出Looper标志,则循环结束;

		如果没有注册空闲回调,那么进入下一次循环;

		处理空闲时的回调,之后将nextPollTimeoutMillis设置为0,表示下次循环开始时不阻塞;因为空闲回调中可能会插入新消息,要马上进行检查和处理;
	}
}

quit(boolean safe)为true将调用removeAllFutureMessagesLocked,表示删除未到执行时间的所有message,
为false调用removeAllMessagesLocked,表示立刻删除所有message
enqueueMessage(Message msg, long when),按照when的顺序放入msg,并根据next函数中是否让线程阻塞,来判断是否需要唤醒该线程


SparseArray<FileDescriptorRecord> mFileDescriptorRecords,作用是注册FileDescriptor以及感兴趣的Events,例如文件输入、输出和错误,设置回调函数,最后调用nativeSetFileDescriptorEvents注册到C++层中,当产生相应事件时,由C++层调用Java层的dispatchEvents,激活相应的回调函数。


5. MessageQueue的C++层实现
在MessageQueue.java的构造函数中,调用nativeInit创建了NativeMessageQueue对象,并且把指针变量返回给Java层的mPtr。

MessageQueue(boolean quitAllowed) {  
    mQuitAllowed = quitAllowed;  
    mPtr = nativeInit();  
}  

android_os_MessageQueue.cpp中的NativeMessageQueue的构造函数中会在当前线程中创建C++的Looper对象。
NativeMessageQueue::NativeMessageQueue() :  
    mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {  
    mLooper = Looper::getForThread();  
    if (mLooper == NULL) {  
        mLooper = new Looper(false);  
        Looper::setForThread(mLooper);  
    }  
}  

6. C++的Looper
控制eventfd的读写,通过epool监听eventfd的变化,来阻塞调用pollOnce,和恢复调用wake当前线程;
通过epoll监听其它文件描述符的变化;
通过epoll处理C++层的消息机制,当调用Looper::sendMessageAtTime后,调用wake出发epoll。

Looper的构造函数,创建一个eventfd(以前的版本是pipe),eventfd它的主要是用于进程或者线程间的通信,然后创建epoll来监听该eventfd的变化;

Looper::Looper(bool allowNonCallbacks) :  
        mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),  
        mPolling(false), mEpollFd(-1), mEpollRebuildRequired(false),  
        mNextRequestSeq(0), mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {  
    mWakeEventFd = eventfd(0, EFD_NONBLOCK);  
    LOG_ALWAYS_FATAL_IF(mWakeEventFd < 0, "Could not make wake event fd.  errno=%d", errno);  
  
    AutoMutex _l(mLock);  
    rebuildEpollLocked();  
} 
void Looper::rebuildEpollLocked() {
    // Close old epoll instance if we have one.
    if (mEpollFd >= 0) {
        close(mEpollFd);
    }

    // Allocate the new epoll instance and register the wake pipe.
    mEpollFd = epoll_create(EPOLL_SIZE_HINT);

    struct epoll_event eventItem;
    memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
    eventItem.events = EPOLLIN;
    eventItem.data.fd = mWakeEventFd;
    int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, & eventItem);
                        strerror(errno));
	......
}

Looper::pollOnce(int timeoutMillis)内部调用了pollInner,再调用epoll_wait(mEpollFd, ..., timeoutMillis)阻塞timeoutMillis时间,并监听文件描述符mEpollFd的变化,当时间到了或者有消息到来,即eventfd被写入内容后,从epoll_wait继续往下执行,处理epoll_wait返回的消息,该消息既有可能是eventfd产生的,也有可能是其它文件描述符产生的。处理顺序是,先处理普通的C++消息队列mMessageEnvelopes,然后处理之前addFd的事件,最后从pollOnce返回,会继续MessageQueue.java的next()函数,去取得Java层的消息来处理;
Looper类的wake,函数只是往mWakeEventfd中写了一些内容,这个fd只是通知而已,类似pipe,最后会把epoll_wait唤醒,线程就不阻塞了继续先发送c层消息,然后处理之前addFd的事件,然后处理java层的消息。
void Looper::wake() {
    uint64_t inc = 1;  
    ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));  
    ......
}
void Looper::awoken() {
    uint64_t counter;
    TEMP_FAILURE_RETRY(read(mWakeEventFd, &counter, sizeof(uint64_t)));
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值