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



http://www.cnblogs.com/dongtaochen2039/archive/2012/03/31/2424626.html

發佈了24 篇原創文章 · 獲贊 8 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章