PhoneSwitcher的处理流程 ,SIMStateReceiver的处理流程,PIN码设置、加密、存储,双卡加载流程,短信发送过程

 

第1章 PhoneSwitcher的处理流程

  1. 注意:PhoneSwitcher在PhoneFactory中初始化。PhoneSwitcher在初始时注册了广播接收器,监听数据卡的变化。

图1  PhoneSwitcher类,初始时注册了广播接收器

同时,TelephonyNetworkFactory初始时,注册成PhoneSwitcher的观察者,监听Phone数据能力的切换。

图2注册成PhoneSwitcher的观察者

2、当PhoneSwitcher收到数据卡变化的广播后,其handleMessage调用onEvaluate函数。

 

图3调用handleMessage进行消息处理,调用onEvaluate

onEvaluate函数判断出数据卡确实发生变化后,就会激活数据卡对应的Phone的拨号能力;

同时去激活非数据卡对应phone的拨号能力。

图4激活数据卡对应的phone拨号能力

PhoneSwitcher中定义了PhoneState类,专门用于处理激活和去激活Phone拨号能力的工作,

同时维护对应Phone的激活状态。

图5 PhoneState类处理和激活Phone拨号能力

在完成上述工作后,PhoneSwitcher就会通知TelephonyNetworkFactory发生了Active Phone Switch。

图6 PhoneSwitcher通知TelephonyNetworkFactory

3、TelephonyNetworkFactory收到通知后,就会调用onActivePhoneSwitch进行处理。

在onActivePhoneSwitch函数中,首先会调用PhoneSwitcher提供的isPhoneActive接口,

查询并更新TelephonyNetworkFactory的激活状态。

图7 调用PhoneSwitcher提供的isPhoneActive接口

此时,对于处于激活状态的TelephonyNetworkFactory来说,就可进入后续的拨号的流程;

对于非激活的TelephonyNetworkFactory而言,则会进入后续断开数据连接的流程。

图8

PhoneSwitcher的这部分流程实际上起到了一种承前启后的作用。

终端加载完APN、设置完数据卡后,必须在这一步激活数据卡对应Phone的拨号能力,

后续的数据拨号流程才能顺利完成。

4PhoneSwitcher的 InformDdsRil()方法

    4.1)在ConnectivityService构造的时候就创建了一个默认的defaultRequest,mDefauleRequest。网络工厂连接上以后,就请求网络连接

    4.2)在ConnectivityService的handleAsyncChannelHalfConnect里面,如果已经连接到网络工厂,就把网络请求CMD_REQUEST_NETWORK发到对应的网络工厂。

    接着就是网络工厂处理请求CMD_REQUEST_NETWORK。

    4.3)NetWorkFactory的handleAddRequest进行处理,调用evalRequest来判断是开启网络还是释放网络:

如果开启网络则调用needNetworkFor,如果是释放网络则调用releaseNetWorkFor;

现在先关注移动网络开启数据的,由于移动网络的网络工厂是TelephonyNetworkFactory,在dctController里面进行定义的。

 

    4.4)TelepjonyNetworkFactory:needNetworkFor

检查sub id是否符合,还有apn是否支持,如果符合条件,则调用requestNetWork

 

    4.5)DctController:request

把请求加入到队列mRequestInfo中,紧接着调用processRequests来处理队列中的请求。

    4.6)QtiDctController:onProcessRequest

根据请求判断是否需要切DDs,需要的话调用handleDdsSwitch

    4.7)qtiDctController:handleDdsSwitch

根据情况是要关闭当前的数据,还是开始建立连接,关闭调用doDisconnectAll,建立连接调用doConnect

    4.8)qtiDctController:doConnect

调用informDdsToRil通知底层默认的dds,然后通过DcSwitchAsyncchannel的connect发送请求Request_Connect

状态条转如下:IdleState->AttachingState->AttachedState->DetachingState->IdleState

在AttachingState会调用setDataAllowed为true,DetachingState会setDataAllowed为falsesetDataAllowed会把某个phone的ps变为attached,从而触发建立data call。

扩展:在插卡之前也会创建PhoneSwitcher,未插卡的时候PhoneId都为0;插卡之后把subid赋值给PhoneId。

 

 

 

 

 

第2章 SIMStateReceiver的处理流程

一)整体流程总结

  1. 每次插拔SIM卡都会将联系人数据库中关于SIM卡的联系人删除;
  2. SimStateReceiver 通过接收 RIL 上报的关于 SIM 卡状态变化的广播去启动 SimContactsService;
  3.  SimContactsService 异步启动 IccProvider 去查询 SIM 卡联系人;
  4. 通过 IccPhoneBookInterfaceManager 一层层调用到 RIL 然后层层返回,最后构造MatrixCursor 插入数据库。
  • 涉及的相关类的功能
  1. IccProvider:对外暴露的接口,我们通过它来查询SIM卡中的contacts信息;
  2. IccPhoneBookInterfaceManager: PhoneBook操作的服务;
  3. IccPhoneBookInterfaceManagerProxy:对外的PhoneBook操作服务, 上面类的代理;
  4. IccRecord:存储与卡相关的一些信息;
  5. AdnRecord:一条联系人信息读取后被封装的类型;
  6. AdnRecordCache:对SIM卡中联系人信息进行Cache;
  7. AdnRecordLoader:实际通过IccFileHandler去获取adn信息的类;
  8. IccFileHandler:向RIL发起请求,或者接受反馈;
  9. RIL:向底层发起请求,并接收反馈。

三)具体代码分析

  1. Phone进程通过AndroidManifest.xml启动之后,设备开机后在用户解锁前会进入一个DirectBootMode,这是系统会发送ACTION_LOCKED_BOOT_COMPLETED广播,等用户解锁后,系统才会发送ACTION_ BOOT_COMPLETED广播。
  2. SimStateReceiver 通过接收 RIL 上报的关于 SIM 卡状态变化的广播去启动 SimContactsService;

以下是对此的详细代码分析:

 

图2.1

插卡后,收到卡的状态变化的消息,或者收到phone启动后发送的广播消息ACTION_ BOOT_COMPLETED。

这里拿收到ACTION_ BOOT_COMPLETED来举例说明,收到该消息之后会执行sendPhoneBoot函数;在sendPhoneBoot函数中,会启动SimContactsService。

图2.2启动SimContentsService

  1. SimContactsService 异步启动 IccProvider 去查询 SIM 卡联系人;
  2. 通过 IccPhoneBookInterfaceManager 一层层调用到 RIL 然后层层返回,最后构造MatrixCursor 插入数据库。

第3章 PIN码设置、加密、存储

1.前提介绍:该密码保存在/data/misc/keystore/user_0/.masterkey,可在adb shell后,ls –al /data/misc/keystore/user_0/.masterkey查看文件存在与否。

下面讲述的是,从设置点击 安全-屏幕锁定方式,设定pin-设置pin码,通知-完成,到pin如何进行加密和存储的。完成这个button是一个设置中通用的一个按键,不再通知界面的布局中。

2. 这个按键响应ChooseLockPassword.java的onClick方法,执行以下代码:

图3.1执行onclick()

进入handleNext()方法,当确认密码正确时,执行startSaveFinsh操作

 

图3.2执行startSaveAndFinsh()

看一下startSaveFinsh()函数的具体执行过程,在该过程中会调用SaveAndFinishWorker类的start方法。

 

图3.3在该过程中会调用ChooseLockPassword.java文件中的SaveAndFinishWorker的start()方法

3. 进入ChooseLockPassword.java文件中的SaveAndFinishWorker类里面执行start()方法,看一下start方法的详细内容。

SaveAndFinishWorker继承于SaveChosenLockWorkerBase类,在SaveAndFinishWorker的satrt方法的最后会执行staart(),这个start是SaveChosenLockWorkerBase类里面的方法。

 

图3.4 ChooseLockPassword.java文件的SaveAndFinishWorker类里执行start()

  1. 进入SaveChosenLockWorkerBase类查看具体的start方法。在该start方法中会调用ChooseLockPassword 类的saveAndVerifyInBackground()方法。

图3.5在该start方法中会结束ChooseLockPassword 的saveAndVerifyInBackground()

  1. ChooseLockPassword 类的saveAndVerifyInBackground(),在这个方法里面会调用LockPatternUtils.java文件的saveLockPassword()方法

 

图3.6调用LockPatternUtils.java文件的saveLockPassword()方法

  1. 看具体的LockPatternUtils.java文件的saveLockPassword()方法。进入该方法来保存密码。通过getLockSettings()间接调用LockSettingsService的setLockCredential方法。

saveLockPassword中会做一次密码检查是否有空或者是否是4位,pin只能是4位,再传pin password,类型,userhandle下去。

 

图3.7通过getLockSettings()间接调用LockSettingsService的setLockCredential方法

 

a. LockPatternUtils.java文件的getLockSettings()方法。

(在LockSettingsService类的onstart方法中有把mLockSettingService赋值给lock_settings,然后在LockPatternUtils中对其进行调用)。

实际上是:通过AIDL,调用的是 LockSettingsService类的service端的setLockCredential()方法。

图3.8getLockSettings调用的是 LockSettingsService类的lock_settings

b. 通过AIDL,调用的是 LockSettingsService类service端的setLockCredential方法。LockSettingsService类的onstart方法中有把mLockSettingService赋值给lock_settings,然后在第8步被调用了。

图3.9 LockSettingsService类中的start方法

  1. LockSettingsService.java类。

在第7步中,LockPatternUtils.java文件的setLockCredential()方法中有如下代码:getLockSettings().setLockCredential(password, CREDENTIAL_TYPE_PASSWORD, savedPassword,  requestedQuality, userHandle)

注意:验证都是经过LockSettingsService,然后再到GateKeeper。

 

所以:通过AIDL,调用的是 LockSettingsService.java service端的setLockCredential方法。

setLockCredential方法会调用setLockCredentialInternal()方法。

  1. 看一下LockSettingsService的setLockCredential方法:

图3.10调用setLockCredentialInternal()方法

 

  1. 看一下LockSettingsService的setLockCredentialInternal()方法,在做writePasswordHash之前,有执行enrollCredential。

图3.11把pin存储起来

 

第4章 SIM卡锁定

1、IccLockSettings:

在UI界面,会触发onResume()函数。在onResume里面注册了ACTION_SIM_STATE_CHANGED这个事件,当收到这种广播的时候就会进行响应。

  1. 在这个函数里面会获取卡的状态,mDialogState第一次进入默认都是OFF_MODE,所以最后会执行resetDialogState()。

OFF_MODE状态代表关闭状态,也是无操作状态;

ICC_LOCK_MODE:进行pin码设定与解锁的状态;

ICC_OLD_MODE:更改pin码,输入旧pin码的状态;

ICC_NEW_MODE:更改pin码,输入新pin码的状态;

ICC_REENTER_MODE:更改pin码,再次输入pin码的状态。

图4.1获取卡状态,执行resetDialogState()

  1. resetDialogState()函数:

当我们点击要修改PIN时,mDialogState就会设置为ICC_OLD_MODE,接着就会执行setDialogValues()函数。

 

图4.2执行setDialogValues()

  1. setDialogValues()方法,重置Dialog状态。Dialog的状态包括,Dialog的title,以及message。

 

图4.3重置Dialog状态,最后执行setDialogMessage()

  1. DialogPreference.java setDialogMessage方法:该方法就是重置一下Dialog的相关信息。

4.4 setDialogMessage方法

总结:也就是说,当我们什么都不做时,默认的mDialogState==ICC_OLD_MODE状态。

2、pin码设定与解锁回调处理逻辑:

IccLockSettings.java中:

在第1步中的a.中onReceiver()会接收到TelephonyIntents发来的广播,接着就会发送MSG_SIM_STATE_CHABGED消息给自己,进行下一步处理。

4.5MSG_SIM_STATE_CHABGED消息处理

4.6 handleMessage处理消息

在updatePreferences()函数中获取当前PIN码的状态:

4.7获取当前PIN码的状态

  1. MSG_ENABLE_ICC_PIN_COMPLETE:开启/关闭  sim锁定。如果sucess为true,则说明成功的进行了锁定sim卡或者解锁sim卡。更新mPinToggle的check状态。如果为false,说明操作失败,给出toast提示。

success 为true的条件为:ar.exception == null。

4.8 MSG_ENABLE_ICC_PIN_COMPLETE消息处理

 

  1. MSG_CHANGE_IC_PIN_COMPLETE:更改pin码的message。同样的,success为true的条件和上一步雷同。无论成功还是失败,给出提示,并且最后都会执行resetDialogState();

4.9 MSG_CHANGE_IC_PIN_COMPLETE消息处理

  1. pin状态更迭onPinEnter()函数:

当我们点击修改或者提交按钮的时候,会触发点击事件 onPinEnter()。它会根据不同的case,然后调用不同的函数,在调的函数中会进行pin状态变化的设置。

当我们进行把手机pin开启或关闭,会触发onPreferenceTreeClick(),它会把mDialogstate的状态设置为ICC_LOCK_MODE,之后我们才可执行修改pin的操作,这个时候mDialogState==ICC_OLD_MODE。

图4.10

初始的mDialogState==ICC_OLD_MODE,

进入handleMessage进行消息处理,case ICC_OLD_MODE:mDialogState被赋值为 ICC_NEW_MODE,这个是输入旧密码;

然后就会进入handleMessage处理,case:ICC_NEW_MODE,mDialogState被赋值为 ICC_REENTER_MODE,这个是输入新密码;

然后再去handleMessage处理,case:ICC_REENTER_MODE,这个是确认新密码;

这个流程就像是我们修改密码的时候会让你输入 原始密码---》新密码---》确认新密码的流程。

如果正确,就去else中执行tryChangePin()执行修改pin操作。否则会再次执行循环,直至达到最大次数。

 

4.11 pin状态更迭

4.12 tryChangeIccLockState函数改变pin状态

总结:为了防止主线程卡死,都用异步的消息传递方法,也就是请求接口时,需要构建一个Message对象,里面包含MSG_ID和消息处理handler,一旦底层处理完,会根据MSG_ID将处理完结果回送给该消息对应的消息队列handler来处理。

 

4.8 tryChangePin函数改变pin的状态

 

4.13 showPinDialog()会回调setDialogValues()

tryChangeIccLockState改变pin状态为MSG_ENABLE_ICC_PIN_COMPLETE:开启PIN;

tryChangePin函数改变pin的状态为:MSG_CHANGE_ICC_PIN_COMPLETE:修改PIN;

showPinDialog()会回调setDialogValues()。

总结:其实无论是case那个状态最后都会执行showPinDialog()函数,然后会重新执行setDialogValues()。

5、 PIN码条件,4-8个字符。

 

图4.14 PIN码长度条件

 

图4.15 PIN码长度条

第5章 SIM卡锁定PIN解锁流程

1、插卡后,在卡初始化过程中,UiccController会从底层获取card状态,会知道要不要进行PIN校验,如果开启就暂停卡初始化流程,并弹出PIN输入框,输入正确的PIN之后,继续从卡中取信息,完成后续流程。

Sim锁定之后,开机会调用一个类,显示“请输入pin”的界面,输入pin密码之后,点击ok,调用checkPin();

通过启动一个线程CheckSimPin来调用TelephonyManager的supplyPinResultForSubscriber()接口;

并注册一个类似于Callback的虚函数onSimLockChangedResponse()并实现,这样当supplyPIN()调用返回时,触发该Callback函数。

KeyguardSimPinView.java类里面查看:

 

图5.1调用supplyPinReportResultForSubscriber()

  1. 查看PhoneInterfaceManager中的supplyPinReportResultForSubscriber()

首先创建一个线程并启动来维护一个Handler用于接收RIL传来的(SUPPLY_PIN_COMPLETE)消息。checkSimPin是IccCard类型。随后调用IccCard的supplyPin()方法并将Handler注册上去,此后一直wait,直到Hander收到指定消息后将其唤醒返回,并将操作结果传给其调用者。如果成功,返回值为true,代表PIN码验证成功。

unlockSim(IccCard …)里面的参数是IccCard类型的,下一步我们要去IccCard看。

  1. 查看PhoneInterfaceManager中的supplyPinReportResultForSubscriber

 

图5.2 supplyPinReportResultForSubscriber()调用unlockSim()

  1. UnclockSim()用的是IccCard的参数

图5.3 UnclockSim()用的是IccCard的参数

  1. 去IccCard看supplyPIN()

图5.4

  1. IccCardProxy是IccCard的代理,去IccCardProxy里面看一下supplyPin(),我们发现调用的是UiccApplication的supplyPin()

 

图5.5调用UiccApplication的supplyPin()

  1. 调用UiccApplication的supplyPin()

 

图5.6将Handler注册上去

 

图5.7将handleMessage处理,调用parsePinPukErrorResult()

parsePinPukErrorResult()函数:

 

图5.8返回一个attemptsRemaining,即result

接着我们看一下result:

 

图5.9如果成功,返回值为true,代表PIN码验证成功。

此时KeyguardSimPinView中的onSimLockChangedResponse()方法会被调用,它会通知KeyguardUpdateMonitor去更新SimState的状态为IccCard.State.READY,并通知锁屏程序解锁成功。

   如果失败,KeyguardSimPinView界面会一直存在,直到连续输入三次失败后,IccCard.java会发出一个Action为”ACTION_SIM_STATE_CHANGED_LOCKED”的广播,由于KeyguardUpdateMonitor对它进行了监听,所以它的onReceive()会被触发,并根据Intent携带的Extras进行SIMState的修改,此时由于reason为“PUK”,故将SIMState置为PUK_ REQUIRED,并触发所有注册监听SIM状态改变的Callback。KeyguardViewMediator的onSimStateChanged()被调用,由于SIMState状态为PUK_ REQUIRED,所以屏幕Mode被设置为LockScreen此时会进入锁屏界面按道理此时需要输入PUK码进行PIN码的修改。但是由于目前的流程中没有对PUK码的请求输入进行处理,所以导致锁屏界面解锁后整个界面不可操作,具体原因可能要调查现有的锁屏程序,不过据我所知目前Android原生态的锁屏都有这个问题,即一旦PIN码锁住之后,手机使用不了,必须将SIM拔出在支持PUK解锁的手机上解锁之后才可以继续使用。

 

 

 

第6章 双卡加载流程学习

1、 PhoneFactory中的makeDefaultPhone方法。

单卡还是双卡:

 

图6.1

TelephonyNetWorkFactory是创建网络代理的工厂;

 

图6.2

初始化网络模式和RIL,支持几张卡就初始化几个RIL。

 

图6.3

接着就是大致把流程梳理一下、其实这些都是上几次说过的内容,这次只不过把他们合并在一起、并稍微添加了一些内容。

1、开机后PhoneFactory创建出了UiccController,该对象将作为RIL的观察者,监听卡状态变化的事件。

2、当PhoneFactory创建出GsmCdmaPhone后,GsmCdmaPhone在其初始化函数中将创建出IccCardProxy对象。

IccCardProxy对象将作为UiccController的观察者,同样监听卡状态的变化。

 

3、当用户进行插卡操作且底层检卡成功后,modem将主动向RIL发送RIL_UNSOL_SIM_STATUS_CHANGED消息。

此时,RIL将通知它的观察者UiccController。

4、UiccController收到RIL的通知后,将调用getIccCardStatus函数主动从modem获取卡相关的信息。

一旦卡信息获取成功,UiccController将调用其onGetIccCardStatusDone函数。

5、在onGetIccCardStatusDone函数中,UiccController将判断是否创建过卡对应的UiccCard对象。

如果没有创建过,UiccController将根据卡信息创建出对应的UiccCard对象;

否则,仅进行UiccCard的更新操作。

6、当UiccCard对象被创建时,在它的构造函数中将进一步创建出对应的UiccCardApplication和IccRecords。

需要注意的是,IccRecords只是一个抽象类,

UiccCardApplication将根据modem上报的卡类型,创建出实际的子类,

即SIMRecords、RuimRecords等。

当IccRecords被创建后,同样将作为RIL的观察者,监听卡状态更新消息。

7、UiccController完成上述工作后,将通知其观察者IccCardProxy对象。

此时,卡信息还未完全加载完毕。

IccCardProxy收到UiccController的通知后,注册成为IccRecords的观察者。

8、收到modem主动上报的RIL_UNSOL_SIM_REFRESH消息后,RIL将通知IccRecords对象。

IccRecords对象收到通知后,将主动与modem通信,进一步获取卡相关的信息。

当SIMRecords收到RIL的通知后,将调用handleSimRefresh函数进行处理。

handleSimRefresh函数将负责获取或更新卡对应的文件信息。

fetchSimRecords函数,将向modem发送Request,获取卡对应的信息。

9、当卡信息加载完毕后,IccRecords将调用onAllRecordsLoaded函数,通知它的观察者。

10、IccCardProxy收到通知后,将调用broadcastInternalIccStateChangedInent函数,

发送ACTION_INTERNAL_SIM_STATE_CHANGED广播。

该广播发送后,将触发数据卡的选择流程。

1、在前文中我们提到了IccCardProxy在卡信息加载完毕后,会发送ACTION_INTERNAL_SIM_STATE_CHANGED广播。

SubscriptionInfoUpdater收到广播后,就会调用handleSimLoaded函数进行处理。

2、在handleSimLoaded函数中,主要工作将由updateSubscriptionInfoByIccId函数来承担。

updateSubscriptionInfoByIccId依次调用clearSubInfo和addSubscriptionInfoRecord函数完成实际的工作。

3、clearSubInfo主要用于清除slot Id和sub Id之间的关系。

毕竟在卡槽中重新插入一张卡后,sub Id可能发生了变化,因此需要先清理过去的缓存信息。

4、addSubscriptionInfoRecord函数调用SubscriptionController的接口进行实际工作。

SubscriptionController首先将更新一些数据库字段,

设置一些卡界面显示所需要的信息,例如SIM卡在设置界面中的名称、颜色等。

然后,SubscriptionController重新建立起Slot Id和Sub Id之间的映射关系。

最后,SubscriptionController判断终端中只有一张卡时,开始设置数据、语音和短信使用的Sub Id等。

数据卡设置完毕后,SubscriptionController将发送相应的广播信息。

5、此外,SubscriptionController调用setDefaultDataSubId设置数据卡后,

还需要利用ProxyController的接口设置每个Phone对应的无线能力,即设置每张卡使用的协议栈。

第7章 短信发送过程部分内容

1、短信应用包路径为packages/apps/Mms,查看配置文件AndroidManifest.xml文件,可以找到MMs应用的入口,就是ConversationList.java。

 

图7.1查看短信的入口

2、在默认的Android虚拟设备启动时,进入ConversationList.java显示短信的会话列表界面,不会有任何短信会话。

在ConversationList.java显示的短信会话列表界面,点击屏幕左下角的“新建短信”,进入短信编辑界面。此按钮的响应事件是ConversationList类中的createNewMessage(),他最主要的作用就是启动ComposeMessageActivity类的Activity。

 

图7.2启动ComposeMessageActivity类

  1. 在ComposeMessageActivity类里面,可以编辑短信的标题、内容等。当我们编辑好了,点击发送,会响应当前类里面的onClick方法,在onclick方法里面会调用confirmSendMessageIfNeeded()方法。(在10390行处)

 

图7.31发送短信调用confirmSendMessageIfNeeded()

confirmSendMessageIfNeeded()方法:

 

图7.32获取isMms,调用sendMsimMessage()、sendMessage()

sendMsimmessage()方法:

 

图7.33 sendMsimmessage()调用sendMessage()方法

 

confirmSendMessageIfNeeded()有两大作用:

  1. 获取编辑内容是短信还是彩信的标志isMms,并根据此标志判断输入的是短信接收方的地址是否正确,如果不正确弹出相应的信息提示。
  2. 调用当前类中的sendMessage方法中的处理逻辑,sendMessage方法最关键的是调用mWorkingMessage.send()继续发起发送短信的请求调用。

mWorkingMessage是WorkingMessage类型,当前编辑的短信内容被抽象成了WorkingMessage类,他实现了当前编辑的短信信息涉及的所有行为和操作,其中包含:发送当前信息、为当前信息增加主题或者附件、设置当前信息的类型(短信或者彩信)、保存草稿、丢弃当前信息、设置当前信息所属的会话等。

 

图7.4 sendMessage方法调用mWorkingMessage.send()

接着看一下WorkingMessage的send()

        ……

// 准备往磁盘中写

//短信和彩信分开处理,if中处理发送彩信,else中处理发送短信

//准备发送彩信所需要的参数如:mmsUri、persister、slideshow等

//启动线程完成发送短信的操作,目的是不影响界面的返回。

sendMmsWorker(…)//调用sendMmsWorker返回继续发送短信的请求;

updateSendStates()//更新Conversation列表的界面显示。

 

//启动线程发送短信的操作,目的是不影响界面的返回;

sendMmsWorker(…)//调用sendMmsWorker返回继续发送短信的请求;

 

图7.5 WorkingMessage处理短信发送

总结:WorkingMessage类应该看作发送短信的起点,在发送短信的时候首先调用其send方法。他的if…else分别处理发送彩信、短信,如果发送短信,将当前类中的preSendSmsWorker方法继续调用sendSmsWork方法,而sendSmsWork方法中的处理逻辑主要分为两步:

  1. 创建SmsMessageSender对象sender
  2. 调用sender.sendMessage继续发起发短信的请求。

 

图7.6 preSendSmsWorker方法调用sendSmsWork()

 

图7.7 sendSmsWork()创建SmsMessageSender对象sender,调用sender.sendMessage

  1. SmsMessageSender类,短信发送处理。

 

图7.8 sender.sendMessage()调用queueMessage()

……

//循环处理多个短信接收方

……

 

 

//调用Telephony Framework层中的addMessageToUri静态方法,记录待发送的短信的内容(将需要发送的短信内容保存到数据库)

//数据库操作异常

 

//发送ACTION_SEND_MESSAGE广播,SmsReceiver类中的onReceiver方法会接收。

 

图7.9发送ACTION_SEND_MESSAGE广播

6、SmsReceiver类中的onReceiver方法接受广播。

 

图7.10调用onReceiveWithPrivilege()

onReceiveWithPrivilege()方法详细作用:

 

图7.11启动SmsReceiverService

通过AIDL启动SmsReceiverService,进入SmsReceiverService类的onStartCommand方法。

7、SmsReceiverService

进入SmsReceiverService类的onStartCommand方法。此方法通过mServiceHandler对象,在当前类中进行Handler消息的发送和接收处理。在handleMessage方法中,根据Action请求的不同类型,分为4个分支,在短信发送请求的过程中,进入ACTION_SEND_MESSAGE分支调用handleSendMessage方法,而handleSendMessage方法会继续调用sendFirstQueuedMessage方法继续传递发送短信的请求。

 

图12 SmsReceiverService类的onStartCommand(),执行mServiceHandler.sendMessage(msg)将消息发给自己,然后去自己的handleMessage()处理

接着会进入自己的handleMessage处理,接收到的消息是第5步发送ACTION_SEND_MESSAGE广播,然后会调用handleSendMessage()方法。

 

图13 handleMessage处理调用handleSendMessage()

看一下handleSendMessage(),handleSendMessage()继续调用sendFirstQueuedMessage()继续传递发送短信的请求。

图14 handleSendMessage()调用sendFirstQueuedMessage()

sendFirstQueuedMessage()方法的处理逻辑是从数据库中读取等待发送的短信的内容,根据短信内容创建SmsSingleRecipientSender对象,并调用其sendMessage方法,继续发出发送短信的请求。

//从数据库中获取要发送的短信的内容

 

……

//根据短信的内容创建SmsSingleRecipientSender对象

//调用他的sendMessage方法

图15数据库中获取短信内容,调用SmsSingleRecipientSender对象的sendMessage

 

 

8、SmsSingleRecipientSender类:

查看SmsSingleRecipientSender对象的sendMessage()方法:

……

//获取SmsManager对象,SmsManager位于Telephony framework层

 

//根据彩信内容拆分出单个或者多个彩信

//根据短信内容长短拆分出单个或者多个短信

 

//验证拆分出来的短信个数是否正常,以及异常处理

 

//通过sms类的静态方法调用,将即将发送的短信保存到发件箱中

//deliveryIntents和sentIntents两个list增加对应的Intent对象

//调用Telephony Frameworks层中的方法,继续发起短信发送请求

图16 SmsSingleRecipientSender对象的sendMessage()方法

总结:SmsSingleRecipientSender对象的sendMessage()方法

  1. 调用SmsManager对象的divideMessage方法,完成短信的拆分;国内短信中的内容超过160byte,将会进行拆分;
  2. 调用Sms类中的静态方法moveMessageToFolder,将即将发送的短信移动到发件箱;
  3. deliveryIntents用于短信发送状态报告的回调Intent,sentIntent作为短信发送结果的回调intent;
  4. 调用SmsManager对象的sendMultipartTextMessage方法,完成单挑或者多条短信的发送。
    1. SmsManager类

SmsManager类在TelePhony Framework层提供短信操作的相关接口供应用层调用。该类提供了短信的拆分、发送、将短信复制到SIM卡上、从SIM卡上删除短信、小区广播等操作接口。

1) 首先获取SmsManager对象并调用它的getDefault方法;其次,调用SmsManager对象的divideMessage方法完成短信的拆分、调用SmsManager对象的sendMultipartTextMessage方法完成短信的发送。

注意:是Telephony目录下的,不是Telephony gsm目录下的SmsManager。

图17  调用sendMultipartTextMessageInternal()

2) sendMultipartTextMessageInternal()方法介绍:

//判断短信的长度

//获取IccSmsInterfaceManager服务,调IccSmsInterfaceManager服务发送短信接口

 

//获取单个的deliveryIntent和sentIntent

 

图18 sendMultipartTextMessage间接调IccSmsInterfaceManager服务发送短信接口

3)IccSmsInterfaceManager服务发送短信接口:这里拿发送多条短息举例,单条短信发送与其相似。

UiccSmsController.javasendMultipartTextForSubscriber方法,该方法会调用IccSmsInterfaceManager服务发送短信接口。

 

图18该方法会调用IccSmsInterfaceManager服务发送短信接口,并调用他发送短信的方法

IccSmsInterfaceManager服务发送短信接口:

 

图19获取短信发送接口

图20调mDispatcher的方法发送短信

mDispatcher对象是SMSDispatcher类型的,字面理解“短信分发器”,他的创建与Tracker对象的创建时机一样,均是在Phone对象创建时同时构造。

总结:

SmsManager对象接收到sendMultipartTextMessage方法调用,分别处理长短信发送和普通短信发送;最后是调用RIL对象提供的sendSMS方法,完成短信发送的RIL请求调用。

短信发送到短信中心之后,RIL会向SMSDispatcher发起EVENT_SEND_SMS_COMPLETE类型的消息通知,SMSDispatcher对象最终调用handleSendComplete方法响应短信发送的返回结果。

    1. SMSDispatcher类

SMSDispatcher的sendText与sendMultipartText处理逻辑一样,可以分为两步:

1)将短信内容构造为SubmitPdu;

2)调用mCm.sendSMS方法向RIL发起短信发送请求。

SMSDispatcher短信分发器从调用sendText与sendMultipartText,到最后与RIL的交互,在这期间还会调用sendRawPdu、sendSms方法。

图21 mCi是RIL对象

mCi是RIL对象。至此短信传到了RIL层,短信请求从应用层分多个步骤传到Java Frameworks层,最后是Java Frameworks框架层拆分短信、创建PDU对象等操作,最终会调用RIL对象中发送短信的方法,将短信发送的请求转换为对应的RIL请求调用。

短信发送成功会保存对应的tracker对象到deliveryPendingList,在处理短信状态报告的同时会发出sentIntent的广播通知。短信发送失败有3次短信重发的处理机制。

图22保存对应的tracker对象到deliveryPendingList

 

图23调用onSent()发出sentIntent的广播通知

总结:短信发送成功决定性因素:

手机Modem将短信成功发送到短信中心;

短信中心成功发送短信到短信接收方。

    1. 短信发送状态处理机制

在与RIL交互的时候,将RIL请求处理的结果CallBack回调handler消息对象作为参数传递给RIL对象,RIL发起短信发送的AT命令,Modem将短信发送出去并将结果告诉RIL,RIL接收到response后将使用对应的handler对象发送消息通知进行回调;

1)接着查看GsmSMSDispatcher对象中的sendSms方法,向RIL发出短信发送请求。

 

图24sendSms方法调用sendSmsByPstn()

sendSmsByPstn()方法中

//创建回调的handler消息对象,消息类型为EVENT_SEND_SMS_COMPLETE

Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker);

//调用RI了对象的发送短信请求方法

mCi.sendSMS(……);

图25 tracker会保存在replay里面,传给RIL

看一下tracker

 

图26

2)SMSDispatcher会接收RIL对象发起的CallBack通知,在handleMessage中处理消息类型为EVEVT_SEND_SMS_COMPLETE消息。然后handleMessage会调用handlesendComplete方法处理。

 

总结:

1)SmsTracker对象在SMSDispatcher中创建,并传递给RIL,最后RIL对象会发出EVEVT_SEND_SMS_COMPLETE消息,该消息中仍然保存了SMSTracker对象,可见他是一直存在在SMSDispatcher与RIL对象的短信发送的请求的返回过程中。

2)通过SMSTracker对象获取sentIntent,并发出广播通知,根据sentIntent的创建过程,找到在SmsReceiver类中的onReceive方法接收此广播,然后启动SmsReceiverService服务,并在handleSmsSent方法中最终处理发送短信的返回结果。

3)短信如果发送失败,会有三次重发的机制,在SMSDispatcher类中的handleSendComplete方法中处理。

 

 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值