针对插单卡,开数据业务情况下radio关机流程分析。
先贴一下ShutdownThread的log:
05-24 03:48:17.226 1354 1354 D ShutdownThread: Notifying thread to start shutdown longPressBehavior=1
05-24 03:48:17.298 1354 4205 I ShutdownThread: Sending shutdown broadcast...
05-24 03:48:17.422 1354 4205 I ShutdownThread: Shutting down activity manager...
05-24 03:48:17.500 1354 4205 I ShutdownThread: Shutting down package manager...
05-24 03:48:17.511 1354 4213 W ShutdownThread: Turning off cellular radios...
05-24 03:48:17.516 1354 4213 I ShutdownThread: Waiting for Radio...
05-24 03:48:18.422 1354 4213 I ShutdownThread: Radio turned off.
05-24 03:48:18.422 1354 4213 I ShutdownThread: Radio shutdown complete.
05-24 03:48:19.226 1354 4205 I ShutdownThread: Shutdown critical subsyslist is :modem :
05-24 03:48:19.226 1354 4205 I ShutdownThread: Waiting for a maximum of 10000ms
05-24 03:48:19.227 1354 4205 I ShutdownThread: Vendor subsystem(s) shutdown successful
05-24 03:48:19.734 1354 4205 I ShutdownThread: Performing low-level shutdown...
每一步的耗时时间:
05-24 03:48:17.422 1354 4205 D ShutdownTiming: SendShutdownBroadcast took to complete: 124ms
05-24 03:48:17.500 1354 4205 D ShutdownTiming: ShutdownActivityManager took to complete: 77ms
05-24 03:48:17.509 1354 4205 D ShutdownTiming: ShutdownPackageManager took to complete: 9ms
05-24 03:48:18.422 1354 4213 D ShutdownTiming: ShutdownRadio took to complete: 911ms
05-24 03:48:18.422 1354 4205 D ShutdownTiming: ShutdownRadios took to complete: 914ms
//在rebootorShutdown函数前的每一步耗时
05-24 03:48:18.422 1354 4205 D ShutdownTiming: SystemServerShutdown took to complete: 1133ms
Notifying thread to start shutdown longPressBehavior=1 打印出现在shutdownInner函数中。当重启或关机时会分别触发shutdown或reboot函数。最终都会走到shutdownInner函数。shutdownInner函数会触发ShutdownThread 中static实例的start函数。因为其继承自thread,所以会触发run函数。
shutdownInner中调用beginShutdownSequence
确保此函数只进入一次。
接着调用showShutdwonDialog()判断是否去显示关机动画。
然后触发ShutdownThread.run()
注意其在调用sendOrderedBraodcastAsUser的参数br,即在发送广播的同时,br会成为此广播的最后一个接受者。br的作用是为了确保所有上层应用都收到关机广播再走下面的流程。
br最后收到广播,将mActionDone设置为true。 run函数中轮询mActionDone,为true时退出,走下面的流程。
调用shutdownRadio函数
shutdownRadio函数启动一个thread执行关闭radio的操作。
首先判断radio是否需要shutdown,若是则调用phone.shutdownMobileRadios来关闭radio。
然后轮询needMobileRadioShutdown()状态。如果radiooff则走下一步。
接下来针对关闭radio 重点分析一下流程。
从上面截图可以知道,就是判断RIL.java的mState变量值。如果是RADIO_UNAVAILABLE则认为不需要关机,否则需要关机。
有两个情况会变为UNAVAILBALBE:
05-24 03:48:19.179 2128 2287 D RILJ : [UNSL]< UNSOL_RESPONSE_RADIO_STATE_CHANGED radioStateChanged: RADIO_UNAVAILABLE [SUB0]
05-24 03:48:19.184 2128 2287 D RILJ : [UNSL]< UNSOL_RESPONSE_RADIO_STATE_CHANGED radioStateChanged: RADIO_UNAVAILABLE [SUB1]
详细流程如下:
RILC 返回response时通过RadioResponse的对应接口返回。
对应RIL_REQUEST_SHUTDOWN是requestShutdownResponse().
在responseVoid函数中,先通过RIL.java的processResponse做一些处理。
然后通过sendMessageResponse通知AP上层的发送方,命令执行情况。
最后通过processResponseDone来打印收到的response信息。
对应log:
05-24 03:48:18.120 2128 2128 D RILJ : [4151]> RIL_REQUEST_SHUTDOWN [SUB1]
05-24 03:48:18.124 2128 2128 D RILJ : [4152]> RIL_REQUEST_SHUTDOWN [SUB1]
05-24 03:48:18.134 2128 2287 D RILJ : [4151]< RIL_REQUEST_SHUTDOWN [SUB1]
05-24 03:48:18.149 2128 2287 D RILJ : [4152]< RIL_REQUEST_SHUTDOWN [SUB1]
05-24 03:48:18.212 2128 2128 D RILJ : [4153]> RIL_REQUEST_SHUTDOWN [SUB0]
05-24 03:48:18.214 2128 2128 D RILJ : [4154]> RIL_REQUEST_SHUTDOWN [SUB0]
05-24 03:48:18.374 2128 2287 D RILJ : [4153]< RIL_REQUEST_SHUTDOWN [SUB0]
05-24 03:48:19.108 2128 2287 D RILJ : [4154]< RIL_REQUEST_SHUTDOWN [SUB0]
05-24 03:48:17.513 SST : [0] mDeviceShuttingDown=true, mDesiredPowerState=false, getRadioState=RADIO_ON, mPowerOffDelayNeed=true, mAlarmSwitch=false, mRadioDisabledByCarrier=false
05-24 03:48:17.515 SST : [1] mDeviceShuttingDown=true, mDesiredPowerState=false, getRadioState=RADIO_ON, mPowerOffDelayNeed=true, mAlarmSwitch=false, mRadioDisabledByCarrier=false
当插单卡,开数据业务,接着调用poweOffRadioSafely()
调用流程如下:
ShutDownThread.shutdownRadios()-》phone.shutdownMobileRadios (ITelephone–>PhoneInterfaceManager)->PhoneInterfaceManager.shutdownRadiosUsingID()->Phone.shutdownRadio()->ServiceStateTracker.requestShutDown()->setPowerStateToDesired()->powerOffRadioSafely->DcTracker.clearUpAllConnections() 同事registerForAllDataDisconnected(EVENT_All_DATA_DISCONNECTED)
即使 插单卡,只要有数据业务,两个sub都会调用dcTracker.cleanUpAllConnections()。 无卡的那个sub还会关注EVENT_All_DATA_DISCONNECTED。
在cleanUpAllConnections()中,针对每一个APN调用一次cleanUpConnection。mDisconnectPendingCount 在cleanUpConnection ()中会自加1.
cleanUpConnection 中tearDown apn。 mDisconnectPendingCount 自加1. 关闭成功后收到EVENT_DISCONNECT_DONE.
无卡sub 的cleanUpAllConnections中,直接调用notifyAllDataDisconnected().
数据业务sub data断开后触发onDisconnectDone,mDisconnectPendingCount 减1至0后,也调用notifyAllDataDisconnected。
数据业务卡是在onDisconnectDone中触发processPendingRadioPowerOffAfterDataOff().进而调用hangupAndPowerOff。
非数据业务卡,或无卡sub,在SST(serviceStateTracker) 处理EVENT_ALL_DATA_DISCONNTECD时调用hangupAndPowerOff
无卡sub等待EVENT_All_DATA_DISCONNECTED
log:
//不插卡,或无数据业务的卡。等待另一张卡关数据业务
05-24 03:48:17.516 2128 2412 D SST : [1] Data is active on DDS. Wait for all data disconnect
//两个sub 都等待30s,都会设置mPendingPowerOffAfterDataOff
05-24 03:48:17.514 2128 2412 D SST : [0] Wait upto 30s for data to disconnect, then turn off radio.
05-24 03:48:17.516 2128 2412 D SST : [1] Wait upto 30s for data to disconnect, then turn off radio.
//两个sub,一个无卡mDisconnectPendingCount 为0,一个volte和data两个apn,所以mDisconnectPendingCount = 2
05-24 03:48:17.515 2128 2128 D QtiDCT : [0]cleanUpConnection: tearing down using gen#1apnContext={mApnType=default mState=CONNECTED mWaitingApns={[[ApnSettingV5] APN_NAME_CMNET, 2463, 46002, cmnet, , , , , , -1, default | net | supl, IPV4V6, IPV4V6, true, 0, 0, 0, false, 0, 0, 0, 0, , , false, 0, 0]} mApnSetting={[ApnSettingV5] APN_NAME_CMNET, 2463, 46002, cmnet, , , , , , -1, default | net | supl, IPV4V6, IPV4V6, true, 0, 0, 0, false, 0, 0, 0, 0, , , false, 0, 0} mReason=radioTurnedOff mDataEnabled=true mDependencyMet=true}
05-24 03:48:17.515 2128 2128 D QtiDCT : [0]cleanUpConnection: tearing down using gen#1apnContext={mApnType=ims mState=CONNECTED mWaitingApns={[[ApnSettingV5] China Mobile (IMS), 2466, 46002, ims, , , , , , -1, ims, IPV4V6, IPV4V6, true, 0, 0, 2, true, 1023, 0, 300, 0, , , false, 0, 0]} mApnSetting={[ApnSettingV5] China Mobile (IMS), 2466, 46002, ims, , , , , , -1, ims, IPV4V6, IPV4V6, true, 0, 0, 2, true, 1023, 0, 300, 0, , , false, 0, 0} mReason=radioTurnedOff mDataEnabled=true mDependencyMet=true}
05-24 03:48:17.523 2128 2128 D QtiDCT : [0]cleanUpConnection: mDisconnectPendingCount = 2
05-24 03:48:17.535 2128 2128 D QtiDCT : [1]cleanUpConnection: mDisconnectPendingCount = 0
//使能数据业务的sub log,分别关闭数据和volte的apn
//QtiDcTracker.java继承自DcTracker.java,由于多态,调用基本是DcTracker的函数
05-24 03:48:17.568 2128 2128 D QtiDCT : [0]getValidApnContext (onDisconnectDone) on {mApnType=ims mState=DISCONNECTING mWaitingApns={[[ApnSettingV5] China Mobile (IMS), 2466, 46002, ims, , , , , , -1, ims, IPV4V6, IPV4V6, true, 0, 0, 2, true, 1023, 0, 300, 0, , , false, 0, 0]} mApnSetting={[ApnSettingV5] China Mobile (IMS), 2466, 46002, ims, , , , , , -1, ims, IPV4V6, IPV4V6, true, 0, 0, 2, true, 1023, 0, 300, 0, , , false, 0, 0} mReason=radioTurnedOff mDataEnabled=true mDependencyMet=true} got 1 vs 1
05-24 03:48:17.568 2128 2128 D QtiDCT : [0]onDisconnectDone: EVENT_DISCONNECT_DONE apnContext={mApnType=ims mState=DISCONNECTING mWaitingApns={[[ApnSettingV5] China Mobile (IMS), 2466, 46002, ims, , , , , , -1, ims, IPV4V6, IPV4V6, true, 0, 0, 2, true, 1023, 0, 300, 0, , , false, 0, 0]} mApnSetting={[ApnSettingV5] China Mobile (IMS), 2466, 46002, ims, , , , , , -1, ims, IPV4V6, IPV4V6, true, 0, 0, 2, true, 1023, 0, 300, 0, , , false, 0, 0} mReason=radioTurnedOff mDataEnabled=true mDependencyMet=true}
05-24 03:48:17.583 2128 2128 D QtiDCT : [0]onDisconnectDone: not retrying
05-24 03:48:17.600 2128 2128 D QtiDCT : [0]getValidApnContext (onDisconnectDone) on {mApnType=default mState=DISCONNECTING mWaitingApns={[[ApnSettingV5] APN_NAME_CMNET, 2463, 46002, cmnet, , , , , , -1, default | net | supl, IPV4V6, IPV4V6, true, 0, 0, 0, false, 0, 0, 0, 0, , , false, 0, 0]} mApnSetting={[ApnSettingV5] APN_NAME_CMNET, 2463, 46002, cmnet, , , , , , -1, default | net | supl, IPV4V6, IPV4V6, true, 0, 0, 0, false, 0, 0, 0, 0, , , false, 0, 0} mReason=radioTurnedOff mDataEnabled=true mDependencyMet=true} got 1 vs 1
05-24 03:48:17.600 2128 2128 D QtiDCT : [0]onDisconnectDone: EVENT_DISCONNECT_DONE apnContext={mApnType=default mState=DISCONNECTING mWaitingApns={[[ApnSettingV5] APN_NAME_CMNET, 2463, 46002, cmnet, , , , , , -1, default | net | supl, IPV4V6, IPV4V6, true, 0, 0, 0, false, 0, 0, 0, 0, , , false, 0, 0]} mApnSetting={[ApnSettingV5] APN_NAME_CMNET, 2463, 46002, cmnet, , , , , , -1, default | net | supl, IPV4V6, IPV4V6, true, 0, 0, 0, false, 0, 0, 0, 0, , , false, 0, 0} mReason=radioTurnedOff mDataEnabled=true mDependencyMet=true}
05-24 03:48:17.606 2128 2128 D SST : [0] Process pending request to turn radio off.
05-24 03:48:17.608 2128 2128 D QtiDCT : [0]onDisconnectDone: radio will be turned off, no retries
//数据业务sub调用hangupAndPowerOff
05-24 03:48:17.606 2128 2128 D SST : [0] Process pending request to turn radio off.
//非数据业务sub调用hangupAndPowerOff
05-24 03:48:17.610 2128 2128 D SST : [1] EVENT_ALL_DATA_DISCONNECTED, turn radio off now.
最终是向ril发送RIL_REQUEST_RADIO_POWER
qcril_qmi_nas_request_power
对应log:
05-24 03:48:17.608 2128 2128 D RILJ : [4127]> RADIO_POWER on = false [SUB0]
05-24 03:48:17.612 2128 2128 D RILJ : [4128]> RADIO_POWER on = false [SUB1]
05-24 03:48:17.997 2128 2287 D RILJ : [4128]< RADIO_POWER [SUB1]
05-24 03:48:18.003 2128 2287 D RILJ : [4127]< RADIO_POWER [SUB0]
05-24 03:48:18.117 2128 2128 D SST : [1] EVENT_RADIO_POWER_OFF_DONE
05-24 03:48:18.210 2128 2128 D SST : [0] EVENT_RADIO_POWER_OFF_DONE
SST会收到EVENT_RADIO_POWER_OFF_DONE。
调用requestShutDown。又会走到ril。
里面涉及到一个shutdown的状态机。
这个状态机如何触发ril内部模块shutdown呢?以内部的关卡状态为例。
在这里将UimCardPowerReqMsg命令发出。
最终UimModule模块处理。
最终发送出去,由UimModemEndpointModule处理:
最终通过qmi发送QMI_UIM_POWER_DOWN_REQ命令给modem。真是一个弯弯曲曲的流程。
不管ril内部的复杂流程。当执行完后,会通知上层么?
从代码看,调用是没有提供参数。所以不会通知上层。但是后续radio状态机会发生变化。
并且RIL_REQUEST_SHUTDOWN 处理完毕后 ,RIl.java 会处理。也会将Radio状态设置为unavailable。所以发送shutdown后,终端在radio还没有到unavailabe时,ril层就提前转到unavialable了。
05-24 03:48:18.120 2128 2128 D RILJ : [4151]> RIL_REQUEST_SHUTDOWN [SUB1]
05-24 03:48:18.124 2128 2128 D RILJ : [4152]> RIL_REQUEST_SHUTDOWN [SUB1]
05-24 03:48:18.134 2128 2287 D RILJ : [4151]< RIL_REQUEST_SHUTDOWN [SUB1]
05-24 03:48:18.149 2128 2287 D RILJ : [4152]< RIL_REQUEST_SHUTDOWN [SUB1]
05-24 03:48:18.212 2128 2128 D RILJ : [4153]> RIL_REQUEST_SHUTDOWN [SUB0]
05-24 03:48:18.214 2128 2128 D RILJ : [4154]> RIL_REQUEST_SHUTDOWN [SUB0]
05-24 03:48:18.374 2128 2287 D RILJ : [4153]< RIL_REQUEST_SHUTDOWN [SUB0]
// radio state 变为 unavialable是 03:48:19.175,但是由于RIL_REQUEST_SHUTDOWN 03:48:18.374时已经都执行完了。所以ShutdownThread的轮询认为radio turned off。在shutdownRadios中出现如下打印
05-24 03:48:18.422 1354 4213 I ShutdownThread: Radio turned off.
05-24 03:48:18.422 1354 4213 I ShutdownThread: Radio shutdown complete.
05-24 03:48:19.108 2128 2287 D RILJ : [4154]< RIL_REQUEST_SHUTDOWN [SUB0]
05-24 03:48:18.001 1208 1269 D RILC : radioStateChangedInd: radioState 0
05-24 03:48:18.006 1193 1255 D RILC : radioStateChangedInd: radioState 0
05-24 03:48:19.175 1193 1255 D RILC : radioStateChangedInd: radioState 1
05-24 03:48:19.182 1208 1269 D RILC : radioStateChangedInd: radioState 1
这个内部状态机曾经发送过变化。之所以关注到这个代码的改动,是因为比较不同机器的ShutdownTiming: ShutdownRadio took to complete的时间打印在终端同样插卡开数据volte的情况下,稳定的存在差异。最后发现主要差异在RIL_REQUEST_SHUTDOWN 执行时间不同。新平台机器的时间要长。 最后对比了日志,发现在状态2至状态3时,新平台有500ms差异,而老平台没有。看了代码才发现,状态名变了,等待的事件变了(从ims service的ims-reg状态,到ims pdp connected状态)。 这个变化是为了确保ims从网络侧de-registered。