星期一, 12月 27, 2010

Airplane mode

在追bug時,去Trace的結果,後來發現如果Phone的RIL層有問題的話,會造成看起來沒有進Airplane mode但實際上卻已經進去的奇怪現象 。Android裡,選Airplane mode以後會發生的事情:
  1. AirplaneModeEnabler送broadcast message出來。有3個人會收到:1.wifi 2.bluetooth 3.Phone。wifi 跟 bluetooth 裡收到訊息以後的處理都很簡單,Phone 裡主要是呼叫 phone.setRadioPower() 這行 (Packages/apps/Phone/src/com/android/phone/PhoneApp.java)。
  2. 這時候會呼叫 GSMPhone/CDMAPhone 的 setRadioPower,GSMPhone/CDMAPhone 都繼承自 ServiceStateTracker,所以是呼叫 ServiceStateTracker.setRadioPower。
  3. ServiceStateTracker.setRadioPower 會呼叫 setPowerStateToDesired (CdmaServiceStateTracker/GsmServiceStateTracker),實際上又是呼叫 cm.setRadioPower
  4. cm 的型別是 CommandsInterface,只有 RIL 有實作此 interface (frameworks/base/telephony/java/com/android/internal/telephony/RIL.java)。自此,訊息往下丟到 RIL daemon,參照 reference-ril 裡的 setRadioState,之後處理完會回傳 RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED。
  5. RIL.java 的 processUnsolicited() 會處理,這邊會呼叫 setRadioStateFromRILInt(),setRadioStateFromRILInt()裏面又再呼叫 setRadioState (frameworks/base/telephony/java/com/android/internal/telephony/BaseCommands.java),這裡會去 notify,所以根據 mRadioStateChangedRestrants 找 registerForRadioStateChanged()
  6. 找 registerForRadioStateChanged 的結果,可以看到 GsmServiceStateTracker/CdmaServiceStateTracker 有去呼叫。再看 ServiceStateTracker 裡的 handler 去處理 EVENT_RADIO_STATE_CHANGED 的部份:setPowerStateToDesired() => pollState() => pollStateDone(),pollStateDone() 裏面就可以看到有用 phone.notifyServiceStateChanged(),notifyServiceStateChange 又是呼叫父類別的 notifyServiceStateChangedP()。
  7. notifyServiceStateChangedP() 呼叫 mNotifier.notifyServiceState。mNotifier 則是 DefaultPhoneNotifier,再看 DefaultPhoneNotifier,裏面就有 registry.notifyServiceState() (TelephonyRegistry.java),這會再呼叫 broadcastServiceStateChanged()。從這裡的 TelephonyIntents.ACTION_SERVICE_STATE_CHANGED 去找,可以發現只有 PhoneStateIntentReceiver 有收這個 broadcast message。
  8. PhoneStateIntentReceiver 會再去 sendMessage。AirplaneModeEnabler 裡就有使用 PhoneStateIntentReceiver,並註冊了自己的 handler,所以 AirplaneModeEnabler 最後就會收到,並且改變項目的狀態。


這段過程幾乎都是以非同步的方式在傳遞,並不是平鋪直敘的,所以我看了好幾次才確定是這麼一回事...沒邊寫邊記的話,恐怕會多繞好幾天...

沒有留言: