android中的一个层次状态机:HierarchicalStateMachine(A2DP)

来源:互联网 发布:python mysql 查询 编辑:程序博客网 时间:2024/05/22 13:01
 介绍的仅是代码跟踪,不是结构描述。感觉结构的话就是通过HierarchicalStateMachine.HsmHandler.StateInfo来维持的吧。子状态上面是父状态,于是形成了类似树一样的结构,每个字节点都只有一个父节点,于是便可以通过类似迷宫算法的逆向遍历来取得状态分支了。

     源自跟踪A2dp的连接方法connectSink:在类BluetoothService,

view plainprint?
  1. 1.  
  2. public boolean connectSink(String address) {  
  3.             BluetoothDeviceProfileState state = mDeviceProfileState.get(address);              
  4.             if (state != null) {  
  5.                     Message msg = new Message();  
  6.                     msg.arg1 = BluetoothDeviceProfileState.CONNECT_A2DP_OUTGOING;  
  7.                     msg.obj = state;  
  8.                     mA2dpProfileState.sendMessage(msg);  
  9.                     return true;  
  10.             }  
  11.             return false;  
  12. }  


     mA2dpProfileState是BluetoothProfileState的实例,而BluetoothProfileState继承自HierarchicalStateMachine。

     下面看一下HierarchicalStateMachine类:
     这个类只有几个表示名字或状态的常数,除此之外还有一个名为HsmHandler的内部类实例,这个类是Handler的子类,里面有大堆的方法和参数,而HierarchicalStateMachine的真正成员方法里面都是调用这个handler里面的方法。所以此状态机的实现都在这个 handler的类中,因此只需跟踪这个子类的代码即可。
     众所周知,直接看代码不如分析流程,所以现在回到主题,跟踪一下

view plainprint?
  1. 2.mA2dpProfileState.sendMessage(msg);  

这段代码。

        mA2dpProfileState初始化在BluetoothService中:

view plainprint?
  1. 3.mA2dpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.A2DP);    
  2. //...  
  3. mA2dpProfileState.start();  


     类BluetoothProfileState构造方法:

view plainprint?
  1. 4.public BluetoothProfileState(Context context, int profile) {  
  2. //...  
  3.         addState(mStableState);  
  4.         addState(mPendingCommandState);  
  5.         setInitialState(mStableState);  
  6. //...  
  7. }  


     addState()是调用的HierarchicalStateMachine中的方法,实际调用:HsmHandler类的addState方法:

view plainprint?
  1. 5.private final StateInfo addState(HierarchicalState state, HierarchicalState parent){  
  2.                 //...  
  3.                 stateInfo = new StateInfo();  
  4.                 mStateInfo.put(state, stateInfo);  
  5.                 //...  
  6. }  

        就是把一个状态放在mStateInfo中。我们可以想象,每一个状态机构造的不同state都放到这个HashMap中以供选择了。
      在HsmHandler类:

view plainprint?
  1. 6.private HashMap<HierarchicalState, StateInfo> mStateInfo = new HashMap<HierarchicalState, StateInfo>();  

      另外一个方法:

view plainprint?
  1. 7.setInitialState(HierarchicalState initialState){mInitialState = initialState;}  

        

  这个方法把mInitialState置为传入的状态。

        所以,BluetoothProfileState的初始化,做了两件事情:

                a>把mStableState和mPendingCommandState这两个HierarchicalState加入到mStateInfo中。

                b>把mInitialState设为mStableState。

       下面回到 代码3 的mA2dpProfileState.start();

        调用的就是HierarchicalStateMachine的start方法,实际调用HsmHandler的方法completeConstruction:

view plainprint?
  1. 8.private final void completeConstruction() {  
  2.       if (mDbg) Log.d(TAG, "completeConstruction: E");  
  3.   
  4.       /** 
  5.        * Determine the maximum depth of the state hierarchy 
  6.        * so we can allocate the state stacks. 
  7.        */  
  8.       int maxDepth = 0;  
  9.       for (StateInfo si : mStateInfo.values()) {  
  10.           int depth = 0;  
  11.           for (StateInfo i = si; i != null; depth++) {  
  12.               i = i.parentStateInfo;  
  13.           }  
  14.           if (maxDepth < depth) {  
  15.               maxDepth = depth;  
  16.           }  
  17.       }  
  18.       if (mDbg) Log.d(TAG, "completeConstruction: maxDepth=" + maxDepth);  
  19.   
  20.       mStateStack = new StateInfo[maxDepth];  
  21.       mTempStateStack = new StateInfo[maxDepth];  
  22.       setupInitialStateStack();  
  23.   
  24.       /** 
  25.        * Construction is complete call all enter methods 
  26.        * starting at the first entry. 
  27.        */  
  28.       mIsConstructionCompleted = true;  
  29.       mMsg = obtainMessage(HSM_INIT_CMD);  
  30.       invokeEnterMethods(0);  
  31.   
  32.       /** 
  33.        * Perform any transitions requested by the enter methods 
  34.        */  
  35.       performTransitions();  
  36.   
  37.       if (mDbg) Log.d(TAG, "completeConstruction: X");  
  38.   }  


        首先,从mStateInfo中查找长度最长的(状态最多的那条分支),该长度作为数组mStateStack的大小。而本例中所有状态都没有父状态所以最大长度应为1.

        mStateStack这个东西就是一个数组,里面装的是某个状态(StateInfo)(这个状态在状态机初始化的时候取值为mInitialState)

的分支(状态的父状态或者子状态的父状态或者子状态 ..and so on)。

        setupInitialStateStack().//这个方法显然就是从mStateInfo中取出某个状态然后把这个状态的分支放在了mStateStack数组中了。

        invokeEnterMethods(0);//这个方法就是调用当前mStateStack中所有状态的enter方法并且把active设为true。

         performTransitions();//由于初始状态mDestState为null,所以此时不做任何处理。

        然后初始化完成,等待接收新状态了。

        此时完成的内容是:

                a>把mInitialState即mStableState放到了mStateStack中。

                b>调用mStateStack中所有状态的enter方法。本例中则调用类:BluetoothProfileState.StableState的enter方法:

view plainprint?
  1. 9.mPendingDevice = null;  

        现在BluetoothProfileState这个状态机初始化完了。开始接收消息了。为了跟上面的初始化过程衔接起来,假设我们A2dp的连接请求是初始化之后的第一次请求。回到代码1:

        首先构造了一个Message,然后调用状态机的SendMessage方法。回到BluetoothProfileState中并未找到该方法,

说明没有覆盖,则调用的是HierarchicalStateMachine的相同方法:

        类HierarchicalStateMachine:


view plainprint?
  1. 10.public final void sendMessage(Message msg) {  
  2.     mHsmHandler.sendMessage(msg);  
  3. }  
        调用了Handler的sendMessage,原来是Handler机制,所以,该消息由类HsmHandler的handleMessage()方法来处理此消息:
        类:HsmHandler
view plainprint?
  1. 11.public final void handleMessage(Message msg) {//msg.what = null  
  2.     if (mDbg) Log.d(TAG, "handleMessage: E msg.what=" + msg.what);  
  3.   
  4.     /** Save the current message */  
  5.     mMsg = msg;  
  6.   
  7.     /** 
  8.      * Check that construction was completed 
  9.      */  
  10.     if (!mIsConstructionCompleted) {  
  11.         Log.e(TAG, "The start method not called, ignore msg: " + msg);  
  12.         return;  
  13.     }  
  14.   
  15.     /** 
  16.      * Process the message abiding by the hierarchical semantics 
  17.      * and perform any requested transitions. 
  18.      */  
  19.     processMsg(msg);  
  20.     performTransitions();  
  21.   
  22.     if (mDbg) Log.d(TAG, "handleMessage: X");  
  23. }  

        首先设置mMsg为传入msg,调用processMsg();        

        类 HsmHandler:

view plainprint?
  1. 12.private final void processMsg(Message msg) {  
  2.             StateInfo curStateInfo = mStateStack[mStateStackTopIndex];  
  3.             if (mDbg) {  
  4.                 Log.d(TAG, "processMsg: " + curStateInfo.state.getName());  
  5.             }  
  6.             while (!curStateInfo.state.processMessage(msg)) {//it is true, skip this scope  
  7.                 /** 
  8.                  * Not processed 
  9.                  */  
  10.                 curStateInfo = curStateInfo.parentStateInfo;  
  11.                 if (curStateInfo == null) {  
  12.                     /** 
  13.                      * No parents left so it's not handled 
  14.                      */  
  15.                     mHsm.unhandledMessage(msg);  
  16.                     if (isQuit(msg)) {  
  17.                         transitionTo(mQuittingState);  
  18.                     }  
  19.                     break;  
  20.                 }  
  21.                 if (mDbg) {  
  22.                     Log.d(TAG, "processMsg: " + curStateInfo.state.getName());  
  23.                 }  
  24.             }  
  25.   
  26.             /** 
  27.              * Record that we processed the message 
  28.              */  
  29.             if (curStateInfo != null) {  
  30.                 HierarchicalState orgState = mStateStack[mStateStackTopIndex].state;  
  31.                 mProcessedMessages.add(msg, curStateInfo.state, orgState);  
  32.             } else {  
  33.                 mProcessedMessages.add(msg, nullnull);  
  34.             }  
  35.         }  

看这句话:curStateInfo.state.processMessage(msg);curStateInfo是mStateStack中的栈顶元素,从刚才初始化中我们知道,此时mStateStack中装的是mStableState。
因此调用BluetoothProfileState.StableState.processMessage(msg);

类BluetoothProfileState.StableState:

view plainprint?
  1. 13.protected boolean processMessage(Message msg) {  
  2.             if (msg.what != TRANSITION_TO_STABLE) {  
  3.                 transitionTo(mPendingCommandState);//it is the mDestState in HierarchicalStateMachine,the initState is mStableState  
  4.             }  
  5.             return true;  
  6.         }  


从代码1中知道,msg.what显然不是TRANSITION_TO_STABLE,所以调用了
transitionTo(mPendingCommandState),transitionTo方法在
HierarchicalStateMachine.HsmHandler类中;

把mDestState这个成员变量设为mPendingCommandState。完了。没有了,可能是忘了。

回到代码11,发现还有一个方法没有执行呢。刚才我们处理的是processMsg方法。那么接下来,方法:HierarchicalStateMachine.HsmHandler.performTransitions():

view plainprint?
  1. 14.private void performTransitions() {  
  2.             /** 
  3.              * If transitionTo has been called, exit and then enter 
  4.              * the appropriate states. We loop on this to allow 
  5.              * enter and exit methods to use transitionTo. 
  6.              */  
  7.             HierarchicalState destState = null;  
  8.             while (mDestState != null) {  
  9.                 if (mDbg) Log.d(TAG, "handleMessage: new destination call exit");  
  10.   
  11.                 /** 
  12.                  * Save mDestState locally and set to null 
  13.                  * to know if enter/exit use transitionTo. 
  14.                  */  
  15.                 destState = mDestState;  
  16.                 mDestState = null;  
  17.   
  18.                 /** 
  19.                  * Determine the states to exit and enter and return the 
  20.                  * common ancestor state of the enter/exit states. Then 
  21.                  * invoke the exit methods then the enter methods. 
  22.                  */  
  23.                 StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState);  
  24.                 invokeExitMethods(commonStateInfo);  
  25.                 int stateStackEnteringIndex = moveTempStateStackToStateStack();  
  26.                 invokeEnterMethods(stateStackEnteringIndex);  
  27.   
  28.   
  29.                 /** 
  30.                  * Since we have transitioned to a new state we need to have 
  31.                  * any deferred messages moved to the front of the message queue 
  32.                  * so they will be processed before any other messages in the 
  33.                  * message queue. 
  34.                  */  
  35.                 moveDeferredMessageAtFrontOfQueue();  
  36.             }  
        记得刚才在状态机初始化的时候见过这个方法,不过好像因为有些原因没有任何处理,是什么原因呢,mDestState为空?

那么这一次这条原因则不成立,因为刚才我们通过transitionTo方法把mDestState已经变成了mPendingCommandState。

这个方法做了什么呢?

        >把mDestState赋给临时状态,然后置空;

        >调用setupTempStateStackWithStatesToEnter(destState);把destState的状态分支都放到临时状态栈:mTempStateStack中,

刚才忘记说了,这个临时栈跟mStateStack结构相同,每次有不同时序的处理的时候起到辅助作用,

由于在本例中作用不明显未做深究;

        >然后mStateStack中的所有状态调用exit方法,active置为false;

        >调用mStateStack中所有状态的enter方法。本例中即调用:BluetoothProfileState.PendingCommandState.enter():

view plainprint?
  1. 15.protected void enter() {  
  2.             log("Entering PendingCommandState State");  
  3.             dispatchMessage(getCurrentMessage());//  
  4.             log(getCurrentMessage());  
  5.         }  

getCurrentMessage得到的就是mMsg即 代码11 中传入的消息,也就是本次调用要处理的消息。然后调用BluetoothProfileState.PendingCommandState.dispatchMessage():

view plainprint?
  1. 16.private void dispatchMessage(Message msg) {  
  2.             BluetoothDeviceProfileState deviceProfileMgr =  
  3.               (BluetoothDeviceProfileState)msg.obj;  
  4.             int cmd = msg.arg1;  
  5.             if (mPendingDevice == null || mPendingDevice.equals(deviceProfileMgr.getDevice())) {  
  6.                 mPendingDevice = deviceProfileMgr.getDevice();  
  7.                 deviceProfileMgr.sendMessage(cmd);  
  8.             } else {  
  9.                 Message deferMsg = new Message();  
  10.                 deferMsg.arg1 = cmd;  
  11.                 deferMsg.obj = deviceProfileMgr;  
  12.                 deferMessage(deferMsg);  
  13.             }  
  14.         }  


首先,BluetoothDeviceProfileState deviceProfileMgr;回到代码1 查看msg.obj发现这个变量的值为

mDeviceProfileState.get(address);

        address则为要连接音频设备的mac,mDeviceProfileState是一个hashMap储存了不同设备mac地址及设备协议状态。

它的初始化及赋值什么的都在BluetoothService中,这个hashMap里的值来自两个方面:

一是在蓝牙打开时把已经配对的设备,加到里面;

二是配对成功后,把相应设备加到这个hashMap中。

因此,每个设备对应了一个deviceProfileMgr,即BluetoothDeviceProfileState,这也是个状态机,先放在这里,我们等会再看。

        接下来判断:if (mPendingDevice == null || mPendingDevice.equals(deviceProfileMgr.getDevice()))

        哦,记得之前把mPengingDevice置为空过,在 代码 9中:

判断条件符合mPendingDevice置为当前device,然后deviceProfileMgr.sendMessage(cmd);

然后,没了。

        只剩下了 deviceProfileMgr.sendMessage(cmd);

        不过这个形式挺眼熟,之前好想见到过,见 代码1.

                mA2dpProfileState.sendMessage(msg);

        只不过mA2dpProfileState换成了deviceProfileMgr,状态机由BluetoothProfileState换成了BluetoothDeviceProfileState。

其他的真的一点变化都没有,于是也就不用分析了。跟上面一样。

        追到最后发现,其实connectSink方法最后调用:

BluetoothA2dpService.connectSinkInternal(BluetoothDevice device)

-------------------------------------------------

        总结:状态机发送一个msg,通过父类HierarchicalStateMachine的成员handler中的handleMessage处理,

然后调用processMsg,实际调用的是mStateStack中存储的state的processMessage方法,然后调用performTransitions方法,

检测mDestState是否为空,不为空则将当前mStateStack的状态全部调用exit方法且avtive置为false,

然后把mDestState的状态分支都放进mStateStack中,调用这些状态的enter方法,且把active置为true。

        更简单一点就是,状态机发送msg--->mStateStack--当前状态分支的exit方法--->调用mDestState状态分支的enter方法

-->其中msg里面的参数,会存在mMsg中可以通过getCurrentMsg来取得之。


原创粉丝点击