您的位置:首页 > 大数据 > 人工智能

6572_message_MWI (Message Waiting Information)

2014-03-09 17:43 399 查看
6572_message_MWI

1.

前言

1.1 目的

本文介绍了一个mwi的接收过程,主要关注的是消息从modem上报到APP的主要处理流程。实际在总结的时候,先讲RIL层是如何处理mwi的消息的,并如何处理并传递给framework的,再一步步分析,framework里事件是如何传送到app的,APP是怎么收到事件并显示的。

文档注重事件流程,描述了事件是在软件分层的框架里的流向,并重点分析一些重点类的实例是如何创建并能为相应模块使用的。

希望本文能够对入手本模块的同事有帮助作用,并起到一个抛砖引玉的作用。

2. 增加MWI接收的流程分析

2.1 对RIL数据解析的修改

在\frameworks\opt\telephony\src\java\com\android\internal\telephony\gsm\SmsMessage.java类里面,在方法parseUserData里对数据进行解析时,根据3GPP TS 23.038 V7.0.0等相关协议,根据dataCodingScheme对消息类型进行判断,下面蓝色的地方是存在问题而修改的代码,原代码不能正确识别到mwi,导致Mwi消息从这里开始便不能被正确传递到app。

else if ((dataCodingScheme & 0xF0) == 0xC0
|| (dataCodingScheme & 0xF0) == 0xD0
|| (dataCodingScheme & 0xF0) == 0xE0) {
。。。

userDataCompressed = false;
boolean active = ((dataCodingScheme & 0x08) == 0x08);

// bit 0x04 reserved

/*
if ((dataCodingScheme & 0x03) == 0x00) {
isMwi = true;
mwiSense = active;
mwiDontStore = ((dataCodingScheme & 0xF0) == 0xC0);
} else {
isMwi = false;

Log.w(LOG_TAG, "MWI for fax, email, or other "
+ (dataCodingScheme & 0xff));
}
*/

isMwi = true;
mwiSense = active;
mwiDontStore = ((dataCodingScheme & 0xF0) == 0xC0);

if ((dataCodingScheme & 0x07) == 0x07) {
mwiType = 0x07;
Log.d(LOG_TAG, "[cc vedio type]");
} else {
mwiType = (int) (dataCodingScheme & 0x03);
}
mwiCount = 1;
。。。

}

if (hasUserDataHeader/* && ((dataCodingScheme & 0x03) == 0x00)*/) {
if (this.userDataHeader.getMwiElements().size() != 0) {
MessageWaitingIndication mwi = this.userDataHeader.getMwiElements().get(0);
isMwi = true;
mwiSense = mwi.getMwiCount() > 0 ? true : false;
mwiDontStore = mwiDontStore && mwi.isMwiDontStore();
mwiType = mwi.getMwiType();
mwiCount = mwi.getMwiCount();
}
}

2.2 对消息接收流程的修改

在GsmSMSDispatcher 的dispatchMessage会对收到的message做区分处理,mwi会在这里被分离出来,处理代码如下,蓝色的部分是新增加的处理,可以看出如果是mwi类型的消息,会调用setVoiceMessageWaitingExtension方法,之后便返回,不再走正常短信的流程。至于mwi是如何处理的,可看setVoiceMessageWaitingExtension的处理流程,它是根据相关协议完成数据的存储和显示的。

boolean isMWISetMessage = sms.isMWISetMessage();

if (sms.isMWISetMessage()) {
mPhone.setVoiceMessageWaitingExtension(1, sms.getMwiCount(), sms.getMwiType());

handled = sms.isMwiDontStore();
if (Config.DEBUG) {
Log.d(TAG, "Received voice mail indicator set SMS shouldStore=" + !handled);
}
} else if (sms.isMWIClearMessage()) {
//mPhone.setVoiceMessageWaiting(1, 0);
Log.i(TAG, "Clear_MwiType: " + sms.getMwiType());
mPhone.setVoiceMessageWaitingExtension(1, 0, sms.getMwiType());

handled = sms.isMwiDontStore();
if (Config.DEBUG) {
Log.d(TAG, "Received voice mail indicator clear SMS shouldStore=" + !handled);
}
}

if (handled) {
return Intents.RESULT_SMS_HANDLED;
}

其中的相关知识点说明如下:

--mPhone的实例化

在SMSDispatcher.java里声明了一个Phone类的引用mPhone,

protected final Phone mPhone;

并在其构造函数SMSDispatcher中初始化了这个引用,初始化的值是传递进来的PhoneBase phone,所以子类GsmSMSDispatcher.java能使用mPhone,

protected SMSDispatcher(PhoneBase phone, SmsStorageMonitor storageMonitor,
SmsUsageMonitor usageMonitor) {
mPhone = phone;

}
对于SMSDispatcher类的创建过程,如其他章节所描述,是其子类GsmSMSDispatcher创建的时候创建出来的。

GSMPhone是PhoneBase的子类,其构造函数会创建GsmSMSDispatcher,

mSMS = new GsmSMSDispatcher(this, mSmsStorageMonitor, mSmsUsageMonitor);

GsmSMSDispatcher的构造函数里会调用父类SMSDispatche的构造函数,

super(phone, storageMonitor, usageMonitor);

至于GSMPhone的创建,如下,是PhoneFactory类在实例化ProxyPhone的时候给创建出来的,所以实际上mPhone是GSMPhone的引用。

PhoneFactory.java

makeDefaultPhone

sCommandsInterface = new RIL(context, networkMode, cdmaSubscription);

// Instantiate UiccController so that all other classes can just call getInstance()

UiccController.make(context, sCommandsInterface);

int phoneType = TelephonyManager.getPhoneType(networkMode);

if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {

Rlog.i(LOG_TAG, "Creating GSMPhone");

sProxyPhone = new PhoneProxy(new GSMPhone(context,

sCommandsInterface, sPhoneNotifier));

-- setVoiceMessageWaitingExtension方法的添加

因为mPhone 是用Phone定义的,我们要使用GSMPhone实例的方法,由使用mPhone这个引用,所以需要在Phone接口定义新添加的方法setVoiceMessageWaitingExtension,在子类中实现,相关类的关系如下,根据这个关系我们可以在相关类添加方法和实现(黄色背景是接口)。



1.1 对MWI数据解析的存放

因为我们开发的是GSM手机,所以最终setVoiceMessageWaitingExtension是在SIMRecords里面实现的,主要功能是将数据存放到sim卡,并将消息通知到mPhone。

setVoiceMessageWaitingExtension(int line, int countWaiting, int mwiType)
{
。。。
mFh.updateEFLinearFixed(
EF_MWIS, 1, efMWIS, null,
obtainMessage (EVENT_UPDATE_DONE, EF_MWIS));
。。。
if(mwiType == android.telephony.SmsMessage.MWI_VOICEMAIL){
mRecordsEventsRegistrants.notifyResult(EVENT_MWI);
}else{
mRecordsEventsRegistrants.notifyResult(EVENT_MWI_EXT);
}
。。。
}
对于将数据存放到SIM的处理留待以后分析,这里主要说明事件向上的传递过程。

EVENT_MWI_EXT事件会被GSMPhone.java的processIccRecordEvents方法接收到,

private void processIccRecordEvents(int eventCode) {
switch (eventCode) {
case IccRecords.EVENT_CFI:
notifyCallForwardingIndicator();
break;

case IccRecords.EVENT_MWI_EXT:
notifyMessageWaitingIndicatorExtension();
break;

case IccRecords.EVENT_MWI:
notifyMessageWaitingIndicator();
break;
}
}

-- processIccRecordEvents

因为GSMPhone在registerForSimRecordEvents方法里注册了EVENT_ICC_RECORD_EVENTS事件,所以它能收到SIMRecords发出的通知事件。

如下是注册过程,

private void registerForSimRecordEvents() {
IccRecords r = mIccRecords.get();
if (r == null) {
return;
}
r.registerForNetworkSelectionModeAutomatic(
this, EVENT_SET_NETWORK_AUTOMATIC, null);
r.registerForNewSms(this, EVENT_NEW_ICC_SMS, null);
r.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
r.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
}

这里是注册的实现过程,需要注意的是handler就是注册里的this,因为GSMPhone间接继承了handler,所以能被当做一个handler。注册过程新建了一个Registrant实例。

public void registerForRecordsEvents(Handler h, int what, Object obj) {
Registrant r = new Registrant (h, what, obj);
mRecordsEventsRegistrants.add(r);
}

SIMRecords发出通知过程最后执行internalNotifyRegistrant,实际上是调用了注册过程传递的handler来发出事件,所以本质上是GSMPhone给自己发了一个消息。

internalNotifyRegistrant (Object result, Throwable exception)
{
Handler h = getHandler();

if (h == null) {
clear();

/// M: Registrant Debug Log Enhancement
Log.d("Registrant", "internalNotifyRegistrant(): Warning! Handler is null, it could be already GCed. ( what=" + what + ", userObj=" + userObj + ", result=" + result + ", exception=" + exception + " )");
} else {
Message msg = Message.obtain();

msg.what = what;

msg.obj = new AsyncResult(userObj, result, exception);

h.sendMessage(msg);
}
}

-- h.sendMessage

h.sendMessage 的调用次序依次是sendMessage ,sendMessageDelayed ,sendMessageAtTime ,enqueueMessage,实质上是将Message添加到Message队列里面去,而且每个handler都有自己独立的消息队列,因为在handler定义了final MessageQueue mQueue。对于hanler、MessageQueue 、Message更详细的描述,可参考其他文档后自行研究。

1.1 对MWI消息向上的通知

GSMPhone里对notifyMessageWaitingIndicatorExtension调用的实现,是在PhoneBase里完成的,

public void notifyMessageWaitingIndicatorExtension() {
// Do not notify voice mail waiting if device doesn't support voice
if (!mIsVoiceCapable)
return;
// This function is added to send the notification to DefaultPhoneNotifier.

mNotifier.notifyMessageWaitingChangedExtension(this);
}
这里用到了PhoneNotifier。

这里有两个问题,一个是mNotifier引用指向的对象,一个是方法notifyMessageWaitingChangedExtension的定义。

1)mNotifier是在PhoneBase构造时被赋值的,

protected PhoneBase(PhoneNotifier notifier, Context context, CommandsInterface ci,
boolean unitTestMode) {
this.mNotifier = notifier;
。。。
}

PhoneBase的创建则是在子类GSMPhone创建过程中创建的,

public GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode, int simId) {
super(notifier, context, ci, unitTestMode, simId);
。。。
}
其中的PhoneNotifier notifier也是在GSMPhone创建过程中传入的,如前所述,GSMPhone的创建是在PhoneFactory完成的,PhoneNotifier也是在PhoneFactory里创建的,所以mNotifier可以使用notifyMessageWaitingChangedExtension这个类。

。。。
sPhoneNotifier = new DefaultPhoneNotifier();
。。。
int phoneType = TelephonyManager.getPhoneType(networkMode);
if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
Log.i(LOG_TAG, "Creating GSMPhone");
sProxyPhone = new PhoneProxy(new GSMPhone(context,
sCommandsInterface, sPhoneNotifier));
}
。。。

2)在PhoneNotifier里定义了方法notifyMessageWaitingChangedExtension,其实现则在DefaultPhoneNotifier里面

public void notifyMessageWaitingChangedExtension(Phone sender) {
/*
notifyMessageWaitingChanged(sender);
int messageWaitingIndicatorType = sender.getMessageWaitingIndicatorType();
*/

try {
Log.d(LOG_TAG,"sender.getMessageWaitingIndicator(): " + sender.getMessageWaitingIndicator());
Log.d(LOG_TAG,"sender.getMessageWaitingIndicatorType(): " + sender.getMessageWaitingIndicatorType());
mRegistry.notifyMessageWaitingChangedExtension(sender.getMessageWaitingIndicator(),
sender.getMessageWaitingIndicatorType());
Log.d(LOG_TAG,"end defaultphonenotifier : notifyMessageWaitingChangedExtension");
} catch (RemoteException ex) {
// system process is dead
Log.e(LOG_TAG,"defaultphonenotifier : system process is dead");
}
}
mRegistry的定义是private ITelephonyRegistry mRegistry;

在构造函数中被初始化,

public DefaultPhoneNotifier() {
mRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
"telephony.registry"));
}
通过ITelephonyRegistry,我们能使用TelephonyRegistry的

notifyMessageWaitingChangedExtension方法,

1.2 MWI消息在framework base部分的处理

TelephonyRegistry类在framework base部分,opt的telephony通过AIDL,将消息传递过来,给TelephonyRegistry的notifyMessageWaitingChangedExtension方法去处理。

TelephonyRegistry的notifyMessageWaitingChangedExtension方法:

public void notifyMessageWaitingChangedExtension(boolean mwi, int mwiType){
Slog.i(TAG, "TelephonyRegistry:notifyMessageWaitingChangedExtension");
Slog.i(TAG, "mwi: " + mwi + " mwiType:" + mwiType);

if (!checkNotifyPermission("notifyMessageWaitingChangedExtension()")) {
return;
}
synchronized (mRecords){
mMessageWaiting = mwi;
mMessageWaitingType = mwiType;

for (Record r : mRecords) {
if ((r.events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR_EXTENSION) != 0) {
try {
r.callback.onMessageWaitingIndicatorChangedExtension(mwi, mwiType);
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
}
}
handleRemoveListLocked();
}
}

可以看出,这个方法是遍历mRecords,调用每一个关注该事件的实例的callback成员的方法,而mRecords是在listen()里被添加callback 监听器IPhoneStateListener的,实际上这里就是一个注册过程。

listen():

。。。
synchronized (mRecords) {
// register
Record r = null;
find_and_add: {
IBinder b = callback.asBinder();
final int N = mRecords.size();
for (int i = 0; i < N; i++) {
r = mRecords.get(i);
if (b == r.binder) {
break find_and_add;
}
}
r = new Record();
r.binder = b;
r.callback = callback;
r.pkgForDebug = pkgForDebug;
r.callerUid = callerUid;
mRecords.add(r);
if (DBG) Slog.i(TAG, "listen: add new record=" + r);
}

至于如何向TelephonyRegistry注册监听器,在TelephonyManager里,定义了ITelephonyRegistry,并有初始化,

private static ITelephonyRegistry sRegistry;

private static ITelephonyRegistry mRegistry2;
private static ITelephonyRegistry mRegistry3;
private static ITelephonyRegistry mRegistry4;
。。。
public TelephonyManager(Context context) {
//MTK-START [mtk04070][111223][ALPS00106134]Merge to ICS 4.0.3
if (sContext == null) {
Context appContext = context.getApplicationContext();
if (appContext != null) {
sContext = appContext;
} else {
sContext = context;
}

sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
"telephony.registry"));

//MTK-START [mtk04070][111116][ALPS00093395]Add for Gemini Phone2
mRegistry2 = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
"telephony.registry2"));
//MTK-END [mtk04070][111116][ALPS00093395]Add for Gemini Phone2

if(PhoneConstants.GEMINI_SIM_NUM >=3){
mRegistry3 = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
"telephony.registry3"));
}
if(PhoneConstants.GEMINI_SIM_NUM >=4){

mRegistry4 = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
"telephony.registry4"));

}
}
//MTK-END [mtk04070][111223][ALPS00106134]Merge to ICS 4.0.3
}
TelephonyManager对外提供注册方法listen和listenGemini,让其他应用间接来向TelephonyRegistry注册。

public void listenGemini(PhoneStateListener listener, int events, int simId) {
String pkgForDebug = sContext != null ? sContext.getPackageName() : "<unknown>";
Log.d(TAG, "listenGemini,simId="+simId+",events="+events);

try {
Boolean notifyNow = (getITelephony() != null);
if (PhoneConstants.GEMINI_SIM_4 == simId) {
mRegistry4.listen(pkgForDebug, listener.callback, events, notifyNow);
} else if (PhoneConstants.GEMINI_SIM_3 == simId) {
mRegistry3.listen(pkgForDebug, listener.callback, events, notifyNow);
} else if (PhoneConstants.GEMINI_SIM_2 == simId) {
mRegistry2.listen(pkgForDebug, listener.callback, events, notifyNow);
} else {
sRegistry.listen(pkgForDebug, listener.callback, events, notifyNow);
}
} catch (RemoteException ex) {
ex.printStackTrace();
// system process dead
} catch (NullPointerException ex) {
ex.printStackTrace();
// system process dead
}
}

1.3 MWI消息如何传递给app

在CallNotifier.java的listenPhoneState方法里,调用了telephonyManager的listenGemini或listen,来间接向TelephonyRegistry注册。

private void listenPhoneState() {
。。。
if (GeminiUtils.isGeminiSupport()) {
。。。
telephonyManager.listenGemini(mPhoneStateListeners[i], PHONE_STATE_LISTENER_EVENT, geminiSlots[i]);
}
} else {
。。。
telephonyManager.listen(mPhoneStateListeners[0], PHONE_STATE_LISTENER_EVENT);
}
}
我们在注册的事件PHONE_STATE_LISTENER_EVENT里添加我们新加入的事件

| PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR_EXTENSION

在注册的GeminiPhoneStateListener监听器类里添加我们要的接口,让PhoneStateListener能够访问:

@Override
public void onMessageWaitingIndicatorChangedExtension(boolean mwi, int mwiType) {
Log.i(LOG_TAG, "PhoneStateListener.onMessageWaitingIndicatorChangedExtension: mwi=" + mwi+" mwiType= "+mwiType);
onMwiChanged(mwi, mSlotId, mwiType);
}

GeminiPhoneStateListener的父类是PhoneStateListener。在telephonyManager里我们实际上是使用了PhoneStateListener的callback调用Registry.listen注册,正如record里面的callback一样,PhoneStateListener的callback也是用IPhoneStateListener定义的。我们要在TelephonyRegistry调用r.callback.onMessageWaitingIndicatorChangedExtension,必须在PhoneStateListener里面实现它。

IPhoneStateListener callback = new IPhoneStateListener.Stub() {
。。。
public void onMessageWaitingIndicatorChangedExtension(boolean mwi, int mwitype){
Message.obtain(mHandler, LISTEN_MESSAGE_WAITING_INDICATOR_EXTENSION, mwi ? 1 : 0, mwitype, null)
.sendToTarget();
}
}

并且在IPhoneStateListener定义onMessageWaitingIndicatorChangedExtension,

oneway interface IPhoneStateListener {
void onServiceStateChanged(in ServiceState serviceState);
void onSignalStrengthChanged(int asu);
void onMessageWaitingIndicatorChanged(boolean mwi);
void onMessageWaitingIndicatorChangedExtension(boolean mwi, int mwitype);

onMessageWaitingIndicatorChangedExtension实现的功能是创建一个消息,并发送到handler,所以在对应的handler里要对这个事件处理,

Handler mHandler = new Handler() {
。。。
case LISTEN_MESSAGE_WAITING_INDICATOR_EXTENSION:
PhoneStateListener.this.onMessageWaitingIndicatorChangedExtension(
msg.arg1 != 0, msg.arg2);
break;
这个处理过程实际上就是调用GeminiPhoneStateListener里添加的接口,用来把消息最终传递给app。

所以这个过程是通过注册监听器,让TelephonyRegistry把事件传递给监听器iPhoneStateListener,监听器再把事件传递给应用的过程。再就是注册过程使用了一次AIDL调用,telephony将ril的数据给TelephonyRegistry的时候使用了一次AIDL调用。

1.4 MWI消息在app部分的处理

上面提到CallNotifier.java里的GeminiPhoneStateListener监听器类,这里添加的接口onMessageWaitingIndicatorChangedExtension,就是PhoneStateListener将Telephony事件传递到APP的接口,它又调用了onMwiChanged(),这个方法也是我们添加的。

private void onMwiChanged(boolean visible, int simId, int mwiType) {
log("onMwiChanged(): " + visible + " simid:" + simId + " mwiType:" + mwiType);
mApplication.notificationMgr.updateMwi(visible, simId, mwiType);
}

如上,我们再将这个消息通知到NotificationMgr,自己实现updateMwi(),

void updateMwi(boolean visible, int simId, int type)
这个类比较长,主要的功能就是区分mwi的类型,是email提示,还是video提示等,并读取数目,最后用发送到NotificationManager,给用户一个提示,最终完成事件的通知。

1.5 MWI消息处理关系图

最后总结一下,这个处理过程的关系图如下,

相关类创建的示意图:



在framework处理mwi消息的示意图:



Framework将mwi消息发送到UI的示意图:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐