針對插單卡,開數據業務情況下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
ShutdownThread.shutdown()
Notifying thread to start shutdown longPressBehavior=1 打印出現在shutdownInner函數中。當重啓或關機時會分別觸發shutdown或reboot函數。最終都會走到shutdownInner函數。shutdownInner函數會觸發ShutdownThread 中static實例的start函數。因爲其繼承自thread,所以會觸發run函數。
關機畫面
shutdownInner中調用beginShutdownSequence
確保此函數只進入一次。
接着調用showShutdwonDialog()判斷是否去顯示關機動畫。
然後觸發ShutdownThread.run()
ShutdownThread.run()
發送廣播
注意其在調用sendOrderedBraodcastAsUser的參數br,即在發送廣播的同時,br會成爲此廣播的最後一個接受者。br的作用是爲了確保所有上層應用都收到關機廣播再走下面的流程。
等待廣播發送完畢
br最後收到廣播,將mActionDone設置爲true。 run函數中輪詢mActionDone,爲true時退出,走下面的流程。
關閉ActivityManager和PackageManager
關閉radio
調用shutdownRadio函數
shutdownRadio函數啓動一個thread執行關閉radio的操作。
shutdownRadio
首先判斷radio是否需要shutdown,若是則調用phone.shutdownMobileRadios來關閉radio。
然後輪詢needMobileRadioShutdown()狀態。如果radiooff則走下一步。
關閉radio
接下來針對關閉radio 重點分析一下流程。
判斷是否需要關閉radio
從上面截圖可以知道,就是判斷RIL.java的mState變量值。如果是RADIO_UNAVAILABLE則認爲不需要關機,否則需要關機。
mState狀態如何轉變爲UNAVAILABLE
有兩個情況會變爲UNAVAILBALBE:
radioIndication.java 被通知radioStateChanged時
對應log:
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]
RIL_REQUEST_SHUTDOWN請求返回時
詳細流程如下:
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]
關閉radio
對應log:
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()
開數據業務情況下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.
hangupAndPoweroff
最終是向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
成功power radio後的流程:
SST會收到EVENT_RADIO_POWER_OFF_DONE。
調用requestShutDown。又會走到ril。
裏面涉及到一個shutdown的狀態機。
這個狀態機如何觸發ril內部模塊shutdown呢?以內部的關卡狀態爲例。
在這裏將UimCardPowerReqMsg命令發出。
最終UimModule模塊處理。
最終發送出去,由UimModemEndpointModule處理:
最終通過qmi發送QMI_UIM_POWER_DOWN_REQ命令給modem。真是一個彎彎曲曲的流程。
RIL_REQUEST_SHUTDOWN執行完畢
不管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