分享

android状态机机制StateMachine

 android之情殇 2014-02-19

        最近在看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犀利之处,我等望洋兴叹!

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多