我们知道DataConnectionTracker是跑在com.android.phone进程中,而MobileDataStateTracker是跑在system_server进程中,那么两者是如何通信的
在DataConnectionTracker的派生类GsmDataConnectionTracker的构造函数的最后一行:
public GsmDataConnectionTracker(PhoneBase p)
broadcastMessenger();//调用父类DataConnectiontracker的方法
DataConnectionTracker.java
protected void broadcastMessenger()
Intent intent = new Intent(DctConstants.ACTION_DATA_CONNECTION_TRACKER_MESSENGER);
intent.putExtra(DctConstants.EXTRA_MESSENGER, new Messenger(this));
mPhone.getContext().sendBroadcast(intent); //构造一个Messenger,通过intent发送出去
这个intent,会被MobileDataStateTracker收到,而正是这个Messenger(信使),搭建起了二者通信的桥梁。
既然是进程间通信,必然会存在一个Messenger.aidl接口,那么来看Messenger.aidl的实现:
package android.os;
parcelable Messenger; //这意味Messgenger可以通过parcelable的方式在进程间传输。
那么在一个进程里面,怎么给另外一个进程的Handler发消息,就像那个Handler在自己进程里面跑一样呢。
答案就是IMessenger.aidl接口,看IMessenger.aidl的实现
package android.os;
import android.os.Message;
/** @hide */
oneway interface IMessenger {
void send(in Message msg); //那么send接口可以跨进程调用
}
IMessenger的Stub代码,理所应当的在Handler.java中实现。
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
Handler.this.sendMessage(msg); //对方的进程,调用send,就是相当于调用本进程的Handler的sendMessage
}
}
那么怎么才能调用到这个接口呢,就是Messenger,Messeger对send接口进行的包装,看Messenger的构造方法实现
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
现在,可以来看MobileDataStateTracker的onReceiver方法
if (intent.getAction().equals(DctConstants
.ACTION_DATA_CONNECTION_TRACKER_MESSENGER)) {
if (VDBG) log(mApnType + " got ACTION_DATA_CONNECTION_TRACKER_MESSENGER");
mMessenger =
intent.getParcelableExtra(DctConstants.EXTRA_MESSENGER); //取出Messager实例
AsyncChannel ac = new AsyncChannel();
ac.connect(mContext, MobileDataStateTracker.this.mHandler, mMessenger); //构造一个AsyncChannel,把自己的Handler与Messenger联系起来,也就是跟DataConnectionTracker联系起来。
}
在来看AsyncChannel的connect实现:
framework/base/core/java/com/android/internal/util/AsyncChannel.java
public void connect(Context srcContext, Handler srcHandler, Messenger dstMessenger)
connected(srcContext, srcHandler, dstMessenger); //构造一个srcMessenger,与MobileDataStateTracker绑定起来
replyHalfConnected(STATUS_SUCCESSFUL); //给MoblieDataStateTracker发一个,告诉MobileDataStateTracker,我们已经连接一半了
那么MoblieDataStateTracker收到这个CMD之后,是怎么处理的。
public void handleMessage(Message msg)
if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
if (VDBG) {
mMdst.log("MdstHandler connected");
}
mMdst.mDataConnectionTrackerAc = (AsyncChannel) msg.obj; //这个obj其实就是刚在构造的AsyncChannel
}
那么这个通道已经建立起来了。
当ConnectivityService调用MoblieDataStateTracker的setUserDataEnable方法的时候(用户在设置里面把移动数据取消勾选)
MobileDataStateTracker.java
public void setUserDataEnable(boolean enabled)
final AsyncChannel channel = mDataConnectionTrackerAc;
channel.sendMessage(DctConstants.CMD_SET_USER_DATA_ENABLE,
enabled ? DctConstants.ENABLED : DctConstants.DISABLED); //构造一个DctConstants.CMD_SET_USER_DATA_ENABLE消息
看AsyncChannel怎么处理
public void sendMessage(Message msg)
msg.replyTo = mSrcMessenger;
mDstMessenger.send(msg); //这里看出,把那个消息发给了DataConnecionTracker。
再来看DataConnectionTracker是如何处理的
public void handleMessage(Message msg)
case DctConstants.CMD_SET_USER_DATA_ENABLE: {
final boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false;
onSetUserDataEnabled(enabled); //这里做开启数据,断开数据的操作
break;
}
可以看出,正是Handler的跨进程传输特型,才让AsyncChannel能够将两个进程的Handler联系起来。