全部博文(20)
分类: 嵌入式
2013-07-24 10:45:26
原文地址:从手机来电分析android消息机制 作者:点点未来
当RIL收到这个消息UNSOL_CALL_RING
然后调用mRingRegistrant.notifyRegistrant(new AsyncResult (null, ret, null));
mRingRegistrant是在哪里注册的呢?
在BaseCommands.java通过这个方法注册的:
public void setOnCallRing(Handler h, int what, Object obj) {
mRingRegistrant = new Registrant (h, what, obj);
}
setOnCallRing这个方法在phoneBase.java的构造函数种通过:
mCM.setOnCallRing(this, EVENT_CALL_RING, null);
ok,所以,此时,handleMessage处理EVENT_CALL_RING消息,
然后调用sendIncomingCallRingNotification()
在这个方法里面,做两件事情:
notifyIncomingRing();
sendMessageDelayed(obtainMessage(EVENT_CALL_RING_CONTINUE, token, 0), mCallRingDelay);
后面的方法作用是用来循环播放铃声的。延迟多少秒具体各手机厂商不同。
继续:notifyIncomingRing()方法里面主要是激活这个注册消息:
mIncomingRingRegistrants.notifyRegistrants(ar);
ok,我们继续看mIncomingRingRegistrants是在哪里注册的,
可以看出是phoneBase.java注册的
public void registerForIncomingRing(
Handler h, int what, Object obj) {
checkCorrectThread(h);
mIncomingRingRegistrants.addUnique(h, what, obj);
}
checkCorrectThread这个方法主要是为了验证当前的线程是不是和原来的线程保持一直,如果不是,抛出
异常
registerForIncomingRing这个方法是callManager.java注册的
phone.registerForIncomingRing(mHandler, EVENT_INCOMING_RING, null);
收到消息后,然后处理EVENT_INCOMING_RING
case EVENT_INCOMING_RING:
if (!hasActiveFgCall()) {
mIncomingRingRegistrants.notifyRegistrants((AsyncResult) msg.obj);
}
break;
然后判断当前有没有前台call,如果有,停止处理,如果没有,继续....
mIncomingRingRegistrants是在callManagar.java
public void registerForIncomingRing(Handler h, int what, Object obj){
mIncomingRingRegistrants.addUnique(h, what, obj);
}
然后registerForIncomingRing是在phoneapp种的callNotifier.java中注册:
mCM.registerForIncomingRing(this, PHONE_INCOMING_RING, null);
所以,最终到了phoneapp中的这里,然后phoneApp处理PHONE_INCOMING_RING消息,调用:
mRinger.ring()完成响铃和循环响铃的工作;
当然,来点的时候,这个消息只是其中消息的一个,仅仅是为了完成响铃而来的消息。下一步启动phone
的消息,是一个
叫UNSOL_RESPONSE_CALL_STATE_CHANGED 的消息,处理机制和上面的一致,其实,FW层基本上都是这种套
路,没什么特别。
这个架构非常好,各层之间低耦合,很不错。
ok,其实上面说的都是废话,这篇文章,其实我主要是想借助这一个消息,来说说RegistrantList这个类
是如何来管理各种消息之间
的不断添加和被激活的。上面文章谈到的那些mIncomingRingRegistrants都是RegistrantList.
其实,说白了,这个RegistrantList就是Registrant的集合,字面意思Registrant是个什么东东?哎,登
记的意思,就是
你要干什么活,先来人才中心登记下,等活来了,发现是你需要的,好,我通知你来干活。
Registrant本质上是个什么东东?其实就是handle 和message的组合体。具体如下:
首先我们看到RegistrantList里面添加消息方法:
public synchronized void
addUnique(Handler h, int what, Object obj)
{
// if the handler is already in the registrant list, remove it
remove(h);
add(new Registrant(h, what, obj));
}
首先移除当前的handler,如果它存在当前的list中的话。然后把当前的消息和handler添加到
RegistrantList中去,RegistrantList是个ArrayList.
对于这个add方法:
public synchronized void
add(Registrant r)
{
removeCleared(); //
registrants.add(r);
}
上面的removeCleared()方法内容如下:
public synchronized void
removeCleared()
{
for (int i = registrants.size() - 1; i >= 0 ; i--) {
Registrant r = (Registrant) registrants.get(i);
if (r.refH == null) {
registrants.remove(i);
}
}
}
可以看出其实这个方法就是移除ArrayList中的没有指定的handler的Registrant的。
r.refH 是一个java中的WeakRreference弱引用对象。什么事弱引用呢?简单点,就是可以保存某对象
的消息,又不影响他的回收。
好,继续,上面的代码先清除掉,然后添加到ArrayList中去保存。
ok, 在ril中mRingRegistrant.notifyRegistrant(new AsyncResult (null, ret, null));
后,调用:
public /*synchronized*/ void
notifyRegistrants(AsyncResult ar)
{
internalNotifyRegistrants(ar.result, ar.exception);
}
然后
private synchronized void
internalNotifyRegistrants (Object result, Throwable exception)
{
for (int i = 0, s = registrants.size(); i < s ; i++) {
Registrant r = (Registrant) registrants.get(i);
r.internalNotifyRegistrant(result, exception);
}
}
可以看出目前是在从ArrayList中取出所有的registrants,然后给触发他们处理消息。
从这里可以看出,我们可以为同一个ArrayList里面添加几个registrants,添加不同的what参数,
然后在这里都会被触发激活。
回到上面方法的r.internalNotifyRegistrant(result, exception);
/*package*/ void
internalNotifyRegistrant (Object result, Throwable exception)
{
Handler h = getHandler();
if (h == null) {
clear();
} else {
Message msg = Message.obtain();
msg.what = what;
msg.obj = new AsyncResult(userObj, result, exception);
h.sendMessage(msg);
}
}
其实,先不看这个方法,我们前面看到了,我们在add消息的时候
add(new Registrant(h, what, obj));是把消息封装成Registrant对象保存起来了。
看Registrant的构造方法:
public
Registrant(Handler h, int what, Object obj)
{
refH = new WeakReference(h);
this.what = what;
userObj = obj;
}
把当前的handler保存到弱引用中,待会可以通过get()方法拿到。然后把消息值等也保存起来。
然后,上面的方法internalNotifyRegistrant 中,我们可以看到第一步通过getHandler()方法获得
Handler对象
public Handler
getHandler()
{
if (refH == null)
return null;
return (Handler) refH.get(); //这里大家看明白了吧,前面说了的。
}
如果handler不存咋,调用clear方法清除。反之,通过消息机制,发送消息给这个消息归属的handler处
理,其实,就是前面的callNotifier.java并且带上PLD返回来的AsyncResult消息。
Message msg = Message.obtain(); //一般获得消息都是通过这个方法,不是直接实例化,因为这个方法
可以避免重复创建
msg.what = what;
msg.obj = new AsyncResult(userObj, result, exception);
h.sendMessage(msg);
哎,都说到这里了,顺便说说android的handler机制吧
首先,需要明白一些消息机制的概念:
Looper:一条线程可以产生一个looper对象,有他来管理此线程的messageQueue消息队列
Handler:咱们可以构造Handler对象来与Looper沟通,以便push新消息到MessageQueue
里面,或者接受Looper从消息队列里面送出来的消息。
MessageQueue: 消息队列,用来存放线程中放入的消息。
线程:不讲什么UI线程了,网上很多,自己去看,普及下知识,什么是线程?
线程就是一段代码逻辑从前到后的执行路径,新开条线程,相当于有两条路径可以走
ok,下面开始介绍android的handler和message机制
ok,大家平常听到的什么UI线程,大家可以去看activity的源码,在activity初始化的时候,
就会有ActivityThread.java来创建主线程,在activity中创建looper和messageQueue对象等。
这部分就不分析了,大家自己看看就行了。我分析的,仅限于当前的case
首先h.sendMessage(msg);我们看这个方法:(当然,这个msg里面包含了pld返回的object还有我们消息标志的what信息)
/**
* Pushes a message onto the end of the message queue after all pending messages
* before the current time. It will be received in #handleMessage},
* in the thread attached to this handler.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
继续:
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) { //判断小于0,不做处理
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
继续handler.java
/**
* Enqueue a message into the message queue after all pending messages
* before the absolute time (in milliseconds) uptimeMillis.
* The time-base is android.os.SystemClock#uptimeMillis}.
* You will receive it in #handleMessage}, in the thread attached
* to this handler.
*
* @param uptimeMillis The absolute time at which the message should be
* delivered, using the
* android.os.SystemClock#uptimeMillis} time-base.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the message will be processed -- if
* the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*/
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
{
boolean sent = false;
MessageQueue queue = mQueue; //这个mQueue待会再说
if (queue != null) { //如果消息队列有,就把当前的handler对象给target,并把消息给消息队列
msg.target = this;
sent = queue.enqueueMessage(msg, uptimeMillis);
}
else {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
}
return sent;
}
前提咱们必须知道的是,一条线程最多只有一个looper和一个messageQueue。
这里,我们要知道mQueue是从哪里来的?其实,应该能猜到,肯定要构造传进来啊
看handler的构造方法:
/**
* Default constructor associates this handler with the queue for the
* current thread.
*
* If there isn't one, this handler won't be able to receive messages.
*/
public Handler() {
if (FIND_POTENTIAL_LEAKS) {
final Class extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper(); //获得当前线程的looper对象
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue; //从looper对象中获取它管理的messageQueue
mCallback = null;
}
从looper对象构造方法可以看出:
private Looper() {
mQueue = new MessageQueue(); //实例化当前的messageQueue对象
mRun = true;
mThread = Thread.currentThread(); //取得当前线程
}
哈哈,懂了吧,最后看个方法,看消息如何存到messageQueue中的
final boolean enqueueMessage(Message msg, long when) {
if (msg.isInUse()) {
throw new AndroidRuntimeException(msg
+ " This message is already in use.");
}
if (msg.target == null && !mQuitAllowed) {
throw new RuntimeException("Main thread not allowed to quit");
}
final boolean needWake;
synchronized (this) {
if (mQuiting) {
RuntimeException e = new RuntimeException(
msg.target + " sending message to a Handler on a dead thread");
Log.w("MessageQueue", e.getMessage(), e);
return false;
} else if (msg.target == null) {
mQuiting = true;
}
msg.when = when;
//Log.d("MessageQueue", "Enqueing: " + msg);
Message p = mMessages;
if (p == null || when == 0 || when < p.when) {
msg.next = p; //好熟悉好熟悉啊,这个next肯定是message对象,百分之百,java实现链表数据结构就是这么写的啊,看来基础真的很重要
mMessages = msg;
needWake = mBlocked; // new head, might need to wake up
} else {
Message prev = null;
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
msg.next = prev.next;
prev.next = msg;
needWake = false; // still waiting on head, no need to wake up
}
}
if (needWake) {
nativeWake(mPtr);
}
return true;
}
其实上面的方法就是把一个一个的message对象通过java链表的方式给串起来。
ok,消息已经放到消息队列里面去了,那怎么取出来?什么时候取出来?如何取出来?
取出来给谁?
首先,我们要明白activity启动的流程。简单的说,是ActivityThread.java在做一系列的操作。
每个应用程序都以ActivityThread.main()为入口进入到消息循环处理。
对于一个进程来讲,我们需要这个闭合的处理框架。ActivitiyThread是应用程序概念空间的重要概念,他建立了应用进程运行的框架,并提供了一个IActivityThread接口作为与 Activity Manager Service的通讯接口.通过该接口ActivityManagerService可以将Activity的状态变化传递到客户端的Activity对象。
在ActivityThread.java的main入口方法中:
public static void main(String[] args) {
SamplingProfilerIntegration.start();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Process.setArgV0("
Looper.prepareMainLooper();
if (sMainThreadHandler == null) {
sMainThreadHandler = new Handler();
}
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
调用了当前线程的Looper.loop()方法循环从messageQueue中取出消息处理:
/**
* Run the message queue in this thread. Be sure to call
* #quit()} to end the loop.
*/
public static void loop() {
Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
while (true) {
Message msg = queue.next(); // might block
if (msg != null) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}
long wallStart = 0;
long threadStart = 0;
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
wallStart = SystemClock.currentTimeMicro();
threadStart = SystemClock.currentThreadTimeMicro();
}
msg.target.dispatchMessage(msg);
if (logging != null) {
long wallTime = SystemClock.currentTimeMicro() - wallStart;
long threadTime = SystemClock.currentThreadTimeMicro() - threadStart;
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
if (logging instanceof Profiler) {
((Profiler) logging).profile(msg, wallStart, wallTime,
threadStart, threadTime);
}
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycle();
}
}
}
可以,看出,此loop方法是个死循环,通过queue.next()取出消息后,然后通过handler的方法发送出去
从前面看出,那个给message的target就是handler。前面传入的
然后通过msg.target.dispatchMessage(msg);方法分发消息
handler.java:
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
callback默认为空,因为不是自己new出的线程,没有传入这个参数。
然后调用handleMessage方法处理。
这个方法默认是空实现:
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
注释已经说的很清楚,所以,你要处理消息,必须重写这个方法
总的来说:对于主线程的话,就是首先放消息到消息队列。然后主线程的looper
循环检查消息队列的消息,因为looper对应线程。handler对应looper。然后looper把
消息给主线程的handler处理,实现获得返回的状态。
如果不是主线程,系统没有为新开的线程默认开启looper和消息机制。所以,必须你自己去处理
在新线程中调用 Looper.prepare()方法构造looper对象
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* #loop()} after calling this method, and end it by calling
* #quit()}.
*/
public static void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
然后主动启动原来Activitythread.java--main()方法里做的操作,调用loop()方法等待消息:
eg:
class TestLooper extends Thread(){
public Handler mHandler;
public void run(){
Looper.prepare()
//下面实例化handler并处理消息
............
............
Looper.loop()
}
}
下次,分析下handler内部封装机制,其实,虽然我没看,但是也能猜到,就是java中的那些线程啊,数据结构之类的结合,基础,多么的重要。
累了,休息..........