6572_message_MWI (Message Waiting Information)

来源:互联网 发布:关口知宏近况 编辑:程序博客网 时间:2024/06/06 08:29

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的时候给创建出来的,所以实际上mPhoneGSMPhone的引用。

 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的示意图:

0 0
原创粉丝点击