android狀態機機制StateMachine


        最近在看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犀利之處,我等望洋興嘆!



  















































免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM