最近在看WifiService源碼,發現Android2.3中Wifi的狀態都是在WifiStateTracker中維護的,4.0中將Wifi的狀態全部放到WifiStateMachine中維護了。WifiStateMachine是一個狀態機,首先WifiStateMachine繼承於StateMachine,StateMachine是一個層次結構的狀態機,它可以處理一些消息,並維護一個層次結構的狀態。
閱讀StateMachine源碼,其結構大致如下:
。。。ProcessedMessageInfo類
。。。ProcessedMessages類
。。。SmHandler類
。。。。。。StateInfor
。。。。。。HaltingState
。。。。。。QuitingState
一、ProcessedMessageInfo類
先看下該類的源碼:
/** * {@hide} * * The information maintained for a processed message. */ public static class ProcessedMessageInfo { private int what; private State state; 消息現在的狀態 private State orgState; 消息沒被處理前的狀態 ProcessedMessageInfo(Message message, State state, State orgState) { this.what = message.what; this.state = state; this.orgState = orgState; }
從該類的構造函數可以看出,這個類就是保存了Message的一些信息。然後我們再瞭解下State類,狀態很簡單,只有自已的名字可以用getName()方法得到名稱(如"Connecting"表示當前正在連接 Wifi),然後還有一個處理 函數processMessage,它接收一個Message參數,顧名思義,它是用來處理某個事件。另外還有兩個函數 enter和exit,表示進入該狀態和退出該狀態作的一些一般操作,如enter可能會做一些初始化操作,而exit會做一些清理工作。
二、ProcessedMessages類
可以將這個類理解乘一個List,保存了若干剛處理過的Message的ProcessedMessageInfo對象。由類的成員函數: private Vector<ProcessedMessageInfo> mMessages = new Vector<ProcessedMessageInfo>();
可以看出。然後類中有一些定義Vector屬性的方法,比如它的Size獲得元素,和向Vector中加入新的剛處理過的Message元素。
三、SmHandler類
該類有三個內部類,源碼如下:
/** * Information about a state. * Used to maintain the hierarchy. */ private class StateInfo { /** The state */ State state; /** The parent of this state, null if there is no parent */ StateInfo parentStateInfo; /** True when the state has been entered and on the stack */ boolean active; /** * Convert StateInfo to string */
StateInfo類保存了State的基本信息。
/** * State entered when transitionToHaltingState is called. */ private class HaltingState extends State { @Override public boolean processMessage(Message msg) { mSm.haltedProcessMessage(msg); return true; } } /** * State entered when a valid quit message is handled. */ private class QuittingState extends State { @Override public boolean processMessage(Message msg) { return NOT_HANDLED; } }
HaltingState和QuittingState類繼承自State重寫了它的processMessage方法。
接下來就是SmsHandler的handleMessage方法了,在該方法中幹了兩件事,1,將Message交給State的processMessage方法處理消息,2,對stateStack中的state通過enter和exit操作進行處理消息的先後順序。
StateMachine的構造函數中開啓了一個HandlerThread專門用來發送給SmsHandler消息進而進行處理。源碼如下:
protected StateMachine(String name) { mSmThread = new HandlerThread(name); mSmThread.start(); Looper looper = mSmThread.getLooper(); mName = name; mSmHandler = new SmHandler(looper, this); }
可以看出在構造器裏面創建了有looper的handler對象,然後就開始各種send,obtain以及handle操作了。
現在有一個疑問就是StateMachine中的state是怎末加進來的呢?不解釋,看源碼:
在StateMachine裏有一addState()方法
/** * Add a new state to the state machine * @param state the state to add * @param parent the parent of state */ protected final void addState(State state, State parent) { mSmHandler.addState(state, parent); }
可以看出它調用了SmHandler的addState方法:
/** * Add a new state to the state machine. Bottom up addition * of states is allowed but the same state may only exist * in one hierarchy. * * @param state the state to add * @param parent the parent of state * @return stateInfo for this state */ private final StateInfo addState(State state, State parent) { if (mDbg) { Log.d(TAG, "addStateInternal: E state=" + state.getName() + ",parent=" + ((parent == null) ? "" : parent.getName())); } StateInfo parentStateInfo = null; if (parent != null) { parentStateInfo = mStateInfo.get(parent); //得到該parent state的詳細內容,返回stateInfo類型。 if (parentStateInfo == null) { // Recursively add our parent as it's not been added yet. parentStateInfo = addState(parent, null); //是遞歸算法 若parent state沒在StateMachine中,先將parentState加入到消息狀態機 } } StateInfo stateInfo = mStateInfo.get(state); if (stateInfo == null) { //該state沒有加入狀態機層次結構。 stateInfo = new StateInfo(); mStateInfo.put(state, stateInfo); //將該state放入StateMachine中 mStateInfo是HashMap源碼見底下 } // Validate that we aren't adding the same state in two different hierarchies. if ((stateInfo.parentStateInfo != null) && (stateInfo.parentStateInfo != parentStateInfo)) { //若待加入的state的父state沒有加入stateMachine則該state也不能加入 throw new RunTimexception("state already added"); } stateInfo.state = state; //向剛加入StateMachine的state所對應的StateInfo賦值 stateInfo.parentStateInfo = parentStateInfo; stateInfo.active = false; if (mDbg) Log.d(TAG, "addStateInternal: X stateInfo: " + stateInfo); return stateInfo; }
/** The map of all of the states in the state machine */ private HashMap<State, StateInfo> mStateInfo = new HashMap<State, StateInfo>();
由上可知stateMachine有層次結構,打個例子,就跟入黨一樣,必須得有介紹人你才能入,否則組織就不接受你。這個狀態機也一樣,假如state2要加如statemachine,先判斷它的父狀態 state1,是否已經加入,若沒,就
出現 Runimexception。這樣就會出現一龐大的層次樹結構。下面舉一例子介紹下它的樹狀層次結構:
StateMachine sm = /*Create a state machine*/; sm.addState(mP0, null); sm.addState(mP1, mP0); sm.addState(mS2, mP1); sm.addState(mS3, mS2); sm.addState(mS4, mS2); sm.addState(mS1,mP1); sm.addState(mS5, mS1); sm.addState(mS0, mP0); sm.setInitialState(mS5);
初始後的狀態機形如一個樹狀結構,如下圖所示:
#
mP0 #
/ \ #
mP1 mS0 #
/ \ #
mS2 mS1 #
/ \ \ #
mS3 mS4 mS5 ---> initial state |
通過以上的分析理解,可以認爲StateMachine是一個處理Message的一個棧,但是它的處理消息的順序
是可以任意變化的。通過transitionTo()函數就可以設置先處理哪一個state(message)了。而處理消息是在相應state的ProcessMessage(message)函數裏面進行。源碼如下:
private final void transitionTo(IState destState) { // destState爲要處理的State(Message) mDestState = (State) destState; if (mDbg) Log.d(TAG, "StateMachine.transitionTo EX destState" + mDestState.getName()); }
通過以上的學習對StateMachine有了大致的瞭解,現在我們再來學習wifiStateMachine類。
該類有很多內部類,但是整體架構很簡單,分爲兩部分繼承自state類的內部類,還有就是TetherStateChange類:
先看TetherStateChange類,因爲比較簡單,源碼:
private class TetherStateChange { ArrayList<String> available; ArrayList<String> active; TetherStateChange(ArrayList<String> av, ArrayList<String> ac) { available = av; active = ac; } }
一會再來分析
然後就是各種state類了。
接下來看wifistatemachine裏面的方法,他裏面的方法也很有規律,如有很多set....,裏面都有sendMessage方法,比如setWifiEnabled()等,源碼如下:
public void setWifiEnabled(boolean enable) { mLastEnableUid.set(Binder.getCallingUid()); if (enable) { /* Argument is the state that is entered prior to load */ sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING, 0)); sendMessage(CMD_START_SUPPLICANT); } else { sendMessage(CMD_STOP_SUPPLICANT); /* Argument is the state that is entered upon success */ sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_DISABLED, 0)); } }
觀察其 沒什麼特別的就是調用了sendMessage方法,進一步的看sendMessage的源碼我們發現:
public final void sendMessage(Message msg) { // mSmHandler can be null if the state machine has quit. if (mSmHandler == null) return; mSmHandler.sendMessage(msg); }
是將message發送到消息隊列中去,且調用的是StateMachine的內部類SmHandler的sendMessage方法,然後就該輪到SmHandler的handleMessage方法去處理了,在handleMessage裏面在進行一些TransitionTo操作,最後交給該state的ProcessMessage方法去解決問題。 由此可知所有調用sendMessage方法的函數都是同一種類型。
這時就我產生了一個疑問消息都發送到stateMachine了,爲什麼不addState()呢?否則TransitionTo怎末知道狀態機裏面的state呢?通過查看wifiStateMachine的構造函數我發現所有的addState操作都在裏面呢!
通過wifiStateMachine的構造函數我們知道這個構造函數就幹了兩件事,第一發送了兩個廣播,第二構建了狀態機的樹層次結構,接下來就是初始化變量了。部分源碼如下:
mContext.registerReceiver( //註冊第一個廣播 ??? new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { ArrayList<String> available = intent.getStringArrayListExtra( ConnectivityManager.EXTRA_AVAILABLE_TETHER); ArrayList<String> active = intent.getStringArrayListExtra( ConnectivityManager.EXTRA_ACTIVE_TETHER); sendMessage(CMD_TETHER_STATE_CHANGE, new TetherStateChange(available, active)); } },new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)); mContext.registerReceiver( //註冊第二個廣播 調用了startScan(false);方法關閉wifi熱點掃描 new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { startScan(false); } }, new IntentFilter(ACTION_START_SCAN)); mScanResultCache = new LruCache<String, ScanResult>(SCAN_RESULT_CACHE_SIZE); PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); addState(mDefaultState); //構建狀態機的樹層次結構 addState(mInitialState, mDefaultState); addState(mDriverUnloadingState, mDefaultState); addState(mDriverUnloadedState, mDefaultState); addState(mDriverFailedState, mDriverUnloadedState); addState(mDriverLoadingState, mDefaultState); addState(mDriverLoadedState, mDefaultState); addState(mSupplicantStartingState, mDefaultState); addState(mSupplicantStartedState, mDefaultState); addState(mDriverStartingState, mSupplicantStartedState); addState(mDriverStartedState, mSupplicantStartedState); addState(mScanModeState, mDriverStartedState); addState(mConnectModeState, mDriverStartedState); addState(mConnectingState, mConnectModeState); addState(mConnectedState, mConnectModeState); addState(mDisconnectingState, mConnectModeState); addState(mDisconnectedState, mConnectModeState); addState(mWaitForWpsCompletionState, mConnectModeState); addState(mDriverStoppingState, mSupplicantStartedState); addState(mDriverStoppedState, mSupplicantStartedState); addState(mSupplicantStoppingState, mDefaultState); addState(mSoftApStartingState, mDefaultState); addState(mSoftApStartedState, mDefaultState); addState(mTetheringState, mSoftApStartedState); addState(mTetheredState, mSoftApStartedState); addState(mSoftApStoppingState, mDefaultState); addState(mWaitForP2pDisableState, mDefaultState); setInitialState(mInitialState); //設置狀態機的初始狀態爲mInitialtate if (DBG) setDbg(true); //start the state machine //啓動狀態機 start();
狀態機的樹結構圖如下:
我們研究下start方法,該方法是StateMachine中的方法,在該方法中調用了mSmHandler.completeConstruction()方法,該方法完善了對StateMachine的初始化,其中比較重要的是計算出了狀態機層次結構的深度
源代碼如下:
/** * Complete the construction of the state machine. */ private final void completeConstruction() { if (mDbg) Log.d(TAG, "completeConstruction: E"); /** * Determine the maximum depth of the state hierarchy * so we can allocate the state stacks. */ int maxDepth = 0; for (StateInfo si : mStateInfo.values()) { //遍歷取出狀態機中通過addState方法加入的,所有的狀態。 int depth = 0; for (StateInfo i = si; i != null; depth++) { i = i.parentStateInfo; } if (maxDepth < depth) { maxDepth = depth; //求出樹的深度 } } if (mDbg) Log.d(TAG, "completeConstruction: maxDepth=" + maxDepth); mStateStack = new StateInfo[maxDepth]; mTempStateStack = new StateInfo[maxDepth]; setupInitialStateStack(); /** * Construction is complete call all enter methods * starting at the first entry. */ mIsConstructionCompleted = true; mMsg = obtainMessage(SM_INIT_CMD); invokeEnterMethods(0); /** * Perform any transitions requested by the enter methods */ performTransitions(); if (mDbg) Log.d(TAG, "completeConstruction: X"); }
其中invokeEnterMethods(0); 方法調用了mStateStack[]數組下標小於mStateStackTopIndex數的所有狀態(state)的enter方法,即進入了狀態機樹結構的下標爲mStateStackTopIndex的狀態。
setupInitialStateStack(); 這個方法首先初始化了mTempStateStack[]數組()(樹根保存在數組下標最大的那個元素上),然後又通過函數moveTempStateStackToStateStack()將mTempStateStack[]數組的值倒序付 給了mStateStack[]數組並且設置了 mStateStackTopIndex(棧頂序列號)的值爲數組的最大下標,方便在ProcessMsg()時取出的state爲棧頂元素。
mTempStateStack[]數組保存的是當前正在處理的樹葉狀態的所有父親,且樹根總是保存在數組下標最大的單元裏;它是中間進行值操作所用的
mStateStack[]數組是mTempStateStack[]元素的反向保存,所以,樹根永遠保存在小標爲0的單元裏。且它是最終應用的state
接下來在看 performTransitions();其部分源代碼如下:
/* Determine the states to exit and enter and return the * common ancestor state of the enter/exit states. Then * invoke the exit methods then the enter methods. */ 1 StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState); 2 invokeExitMethods(commonStateInfo); 3 int stateStackEnteringIndex = moveTempStateStackToStateStack(); 4 invokeEnterMethods(stateStackEnteringIndex); //從stateStackEnteringIndex向棧頂依次執行enter方法並設Active爲true /** * Since we have transitioned to a new state we need to have * any deferred messages moved to the front of the message queue * so they will be processed before any other messages in the * message queue. */ moveDeferredMessageAtFrontOfQueue(); //將消息移動到消息隊列的頂部以便馬上執行 }
1. StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState); 逐次向上查找destState的所有祖先直到該祖先的stateInfo.Active爲true才停止,並將值放到mTempStateStake 裏面,樹根對應下標最大的,commonstateInfo爲該祖先的 stateInfor屬性,在這個函數裏面也將mTempStateStake清空了,並重新賦值了。
2.invokeExitMethods(commonStateInfo)方法從mStateStack的頂部依次向下移動直到找到commonStateInfo,把這些之間的state的exit方法都執行,並將Active賦值爲false
3.int stateStackEnteringIndex = moveTempStateStackToStateStack()將mTempStateStack[]數組的值倒序付 給了mStateStack[]數組並且設置了 mStateStackTopIndex(棧頂序列號)的值爲數組的最大下標。
4. invokeEnterMethods(stateStackEnteringIndex); 從stateStackEnteringIndex向棧頂依次執行enter方法並設Active爲true
現在對上面4個函數做一總結,在函數1的時候傳入了一個destState參數,這個是目標stat,e即馬上想要處理的state,必須把它放置在棧頂才行,好了下面三個函數就是這麼做的。函數一先返回一個commonStateinfo就是下面所說的fatherState,這個stateInfo就是destState的一個滿足Active參數爲true且離他最近的父親設爲fatherState,並且重新賦了mTempStateStack的值,且值爲destState到fatherState之間的所有父親(fatherState的下標最大),函數2就是從當前mStateStack[](當前狀態棧)中的當前狀態開始一直到本棧中的fatherState都執行exit方法,且將Active值付爲false。這樣fatherState所在的mState棧的所有子State就都關閉了。函數三就是將經函數二處理過的mTempStateStake的值反序付給mStateStack且將mTempStateStake中樹根fatherState的值對應mStateStack中fatherState的值然後一直到destState,並將mStackstateTopIndex的值改變爲destState在mStateStack中的位置(這樣做是因爲在handlemessge裏面就是靠這個索引找目標state的),這樣就實現了mStateStack棧完美的轉換順序,最後再將更新後的mStateStack中fatherState到destState之間所有的子state都執行enter函數且將Active的值變爲true(棧中fatherState的所有父state不用執行enter操作因爲他們就沒有關閉一直處於active的狀態),;到此爲止所有的transmmit工作就結束了,然後不同的message就可以進入到相應的state進行處理。再次慨嘆google犀利之處,我等望洋興嘆!
http://www.cnblogs.com/dongtaochen2039/archive/2012/03/31/2424626.html