从源代码角度去分析状态机的实现过程。
主要涉及到的文件有:
frameworks/base/wifi/java/android/net/wifi/WifiStateMachine.java
frameworks/base/core/java/com/android/internal/util/StateMachine.java
frameworks/base/core/java/com/android/internal/util/State.java
frameworks/base/core/java/com/android/internal/util/IState.java
其中IState是一个接口类:
上述的方法会由StateMachine来支配,决定何时调用,现有这个概念即可。
接着看StateMachine类中一些重要的内嵌类和函数。
public static class ProcessedMessageInfo {//包含一个状态的所有信息 private int what; private State state;//这个经常用到,表示当前处于那个状态 private State orgState;//表示接收到消息的状态 ........................................ ProcessedMessageInfo(Message message, State state, State orgState) { update(message, state, orgState);//更新当前状态 } .......................................... public void update(Message message, State state, State orgState) { this.what = message.what; this.state = state; this.orgState = orgState; } ....................................... }
private static class ProcessedMessages {//保存最近处理的20条消息,具体包括state,发送的message等 private static final int DEFAULT_SIZE = 20;//默认的最大状态个数,这个不是指所有的状态,而是当前活动状态往父类追溯得到的所有类的状态 private Vector<ProcessedMessageInfo> mMessages = new Vector<ProcessedMessageInfo>(); private int mMaxSize = DEFAULT_SIZE; .................................... ProcessedMessageInfo get(int index) {//根据索引获取状态信息 int nextIndex = mOldestIndex + index; if (nextIndex >= mMaxSize) { nextIndex -= mMaxSize; } if (nextIndex >= size()) { return null; } else { return mMessages.get(nextIndex); } } ......................................... void add(Message message, State state, State orgState) {//orgState为最底层状态节点,state为有能力处理message的节点,他们可能相等,或则state为orgState的祖类节点 mCount += 1; if (mMessages.size() < mMaxSize) { mMessages.add(new ProcessedMessageInfo(message, state, orgState)); } else { ProcessedMessageInfo pmi = mMessages.get(mOldestIndex); mOldestIndex += 1; if (mOldestIndex >= mMaxSize) { mOldestIndex = 0; } pmi.update(message, state, orgState); } } }
private static class SmHandler extends Handler { ................................. private StateInfo mStateStack[];//这里存放的是当前state以及父类的state private int mStateStackTopIndex = -1;//mStateStack数组的下标索引 private StateInfo mTempStateStack[];//状态信息缓存区 private HaltingState mHaltingState = new HaltingState();//状态挂起时候才会用到,一般用不上 private QuittingState mQuittingState = new QuittingState();//状态退出时候才会用上,一般用不上 private StateMachine mSm;//全局的StateMachine引用,在构造函数中this指针赋的值 private HashMap<State, StateInfo> mStateInfo = new HashMap<State, StateInfo>();//保存所有加入的state信息 private State mInitialState;//初始化的状态 private State mDestState;//切换时新的目标状态 @Override public final void handleMessage(Message msg) { processMsg(msg);//处理接收到的消息 performTransitions();//处理就状态到新状态的切换 if (mDbg) Log.d(TAG, "handleMessage: X"); } .......................... }
到这里,还是先把wifistatemachine的状态图写出来,以便好理解。
比如,如果当前状态为mDriverFailedState,则上面mStateStack存放的是[mDefaultState,mDriverUnloadedState,mDriverFailedState]三个状态的信息
StateMachine的构造函数做了些什么?
protected StateMachine(String name) { mSmThread = new HandlerThread(name); mSmThread.start(); Looper looper = mSmThread.getLooper(); initStateMachine(name, looper); }
private void initStateMachine(String name, Looper looper) { mName = name; mSmHandler = new SmHandler(looper, this); //mSmHandler是一个全局的handler,后面常用到 }
private SmHandler(Looper looper, StateMachine sm) { super(looper); mSm = sm;//mSm是一个全局的变量,后面经常用到 addState(mHaltingState, null);//状态挂起的时候调用 addState(mQuittingState, null);//状态退出的时候调用 }
主要是调用addState方法将wifi中创建的状态加入状态机中,最后setInitialState来设置初始化状态。具体过程如下:
protected final void addState(State state, State parent) {//将state添加到父节点parent下,如果parent为null,则state作为父节点 mSmHandler.addState(state, parent); }
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);//取出父节点的parentStateInfo信息 if (parentStateInfo == null) { //如果父节点为null,则递归调用,把当前节点作为父节点 // Recursively add our parent as it's not been added yet. parentStateInfo = addState(parent, null); } } StateInfo stateInfo = mStateInfo.get(state);//新节点,肯定为null了 if (stateInfo == null) { stateInfo = new StateInfo(); mStateInfo.put(state, stateInfo);//将state和stateInfo放入哈系表中,以后根据state即可取出stateInfo信息,前面说过,全局变量mStateInfo哈系表保存了所有state信息 } // Validate that we aren't adding the same state in two different hierarchies. if ((stateInfo.parentStateInfo != null) && //新创建还没有赋值,肯定为null啦,否则就抛出异常了 (stateInfo.parentStateInfo != parentStateInfo)) { throw new RuntimeException("state already added"); } stateInfo.state = state; stateInfo.parentStateInfo = parentStateInfo;//以后通过state可以找到父节点,一直递归,如果state的父节点为null,则表示到了顶部 stateInfo.active = false; //时候是当前活动状态标志 if (mDbg) Log.d(TAG, "addStateInternal: X stateInfo: " + stateInfo); return stateInfo; }
/** * Set the initial state. This must be invoked before * and messages are sent to the state machine. * * @param initialState is the state which will receive the first message. */ protected final void setInitialState(State initialState) { mSmHandler.setInitialState(initialState); }
private final void setInitialState(State initialState) { if (mDbg) Log.d(TAG, "setInitialState: initialState" + initialState.getName()); mInitialState = initialState;//先简单的保存到全局变量中,后续才用到 }
public void start() { // mSmHandler can be null if the state machine has quit. if (mSmHandler == null) return;//mSmHandler引用在前面构造函数中就赋值了,肯定不为null了 /** Send the complete construction message */ mSmHandler.completeConstruction(); } }
来看completeConstruction方法的实现:
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()) {//这个for循环就是遍历前面添加到哈系表中的状态,找出树的最大深度,根据前面的树形表可以看出,最大深度为5 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];//这个是最后存放当前活动state的,可以看到要得到最大深度的作用就是为了创建数组,因为当前活动state以及父类家族最多就为maxDepth mTempStateStack = new StateInfo[maxDepth];//这个是暂时存放state的 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"); }
private final void setupInitialStateStack() { if (mDbg) { Log.d(TAG, "setupInitialStateStack: E mInitialState=" + mInitialState.getName()); } StateInfo curStateInfo = mStateInfo.get(mInitialState);//取出初始化state,前面已经赋值过,这里为WifiStateMachine中mInitialState对应的stateInfo for (mTempStateStackCount = 0; curStateInfo != null; mTempStateStackCount++) { mTempStateStack[mTempStateStackCount] = curStateInfo;//最后mTempStateStack存放的值为[mInitialState,mDefaultState]对应的stateInfo curStateInfo = curStateInfo.parentStateInfo; } // Empty the StateStack mStateStackTopIndex = -1; moveTempStateStackToStateStack(); }
private final int moveTempStateStackToStateStack() { int startingIndex = mStateStackTopIndex + 1;// -1 + 1 = 0; int i = mTempStateStackCount - 1;//第一次进入,2 - 1 = 1; int j = startingIndex; while (i >= 0) { if (mDbg) Log.d(TAG, "moveTempStackToStateStack: i=" + i + ",j=" + j); mStateStack[j] = mTempStateStack[i]; j += 1; i -= 1; } mStateStackTopIndex = j - 1;// 2 - 1 = 1 if (mDbg) { Log.d(TAG, "moveTempStackToStateStack: X mStateStackTop=" + mStateStackTopIndex + ",startingIndex=" + startingIndex + ",Top=" + mStateStack[mStateStackTopIndex].state.getName()); } return startingIndex; //0 }这样,当前状态信息就保存在mStateStack中,为[mDefaultState, mInitialState]对应的状态信息。
回到completeConstruction中,接着invokeEnterMethods方法:
private final void invokeEnterMethods(int stateStackEnteringIndex) { for (int i = stateStackEnteringIndex; i <= mStateStackTopIndex; i++) {//前面分析可以,mStateStackTopIndex为1 if (mDbg) Log.d(TAG, "invokeEnterMethods: " + mStateStack[i].state.getName()); mStateStack[i].state.enter();//依次调用活动状态的enter方法,可以看到是从最顶层父类依次往下调用的 mStateStack[i].active = true; //把当前state置为true } }
class InitialState extends State { @Override //TODO: could move logging into a common class public void enter() { ...................................... if (WifiNative.isDriverLoaded()) { transitionTo(mDriverLoadedState);//如果我们打开过wifi,状态就会切换到mDriverLoadedState去了 } else { transitionTo(mDriverUnloadedState);//第一次打开是没有load过的,所以进入unload状态 } ................................. } }
protected final void transitionTo(IState destState) {//IState是所有state的接口类 mSmHandler.transitionTo(destState);调用handler方法来处理 }
private final void transitionTo(IState destState) { mDestState = (State) destState;//先保存到变量中,后续真正状态切换时候才用到 if (mDbg) Log.d(TAG, "StateMachine.transitionTo EX destState" + mDestState.getName()); }
private void performTransitions() { ..................... State destState = null; while (mDestState != null) { ...................................... destState = mDestState;//destState为mDriverUnLoadedState mDestState = null; .............................. StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState); invokeExitMethods(commonStateInfo); int stateStackEnteringIndex = moveTempStateStackToStateStack(); invokeEnterMethods(stateStackEnteringIndex); moveDeferredMessageAtFrontOfQueue(); } if (destState != null) { if (destState == mQuittingState) { cleanupAfterQuitting(); } else if (destState == mHaltingState) { mSm.halting(); } } }
invokeExitMethods方法则是从当前活动state顶层节点一次调用exit方法,并且设置state的active标记为false;这里要注意当前活动的还是是mStateStack中的信息,即[mDefaultState, mInitialState]对应的状态信息,exit方法一般是做一些善后工作。处理完成后
mStateStackTopIndex又自减为-1。
moveTempStateStackToStateStack和invokeEnterMethods方法前面已经分析过。完成后mStateStack的状态信息变为[mDefaultState,mDriverUnLoadedState]
最后一个函数moveDeferredMessageAtFrontOfQueue刷新消息队列的排序。该方法就是将mDeferredMessages容器中的消息按先后顺序发送出去,然后清空容器。至于消息是如何加入容器的,后面遇到再分析。
这样start方法就完成,整个WifiStateMachine构造函数也建立完成了。
如果我们打开wifi,会在WifiService中调用setWifiEnabled - >mWifiStateMachine.setWifiEnabled来启动。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方法是StateMachine实现的,它封装了Handler类的sendMessage方法,会被SmHandler类的handleMessage来接收处理。而它是调用一下两个方法来处理消息的:
processMsg(msg); performTransitions();先看第一个:
private final void processMsg(Message msg) { StateInfo curStateInfo = mStateStack[mStateStackTopIndex];//mStateStack保存信息的顺序为顶层节点->底层节点,mStateStackTopIndex为数组个数,这里取出的就为最底层节点的状态信息 if (mDbg) { Log.d(TAG, "processMsg: " + curStateInfo.state.getName()); } while (!curStateInfo.state.processMessage(msg)) {//所以从底层节点开始往上遍历,调用processMessage来处理消息,直到找到一个可以处理的节点后返回HANDLED(true),条件退出 /** * Not processed */ curStateInfo = curStateInfo.parentStateInfo; if (curStateInfo == null) {//找到顶层节点了,才用unhandledMessage,它不做什么事情,打印一句LOG信息而已 /** * No parents left so it's not handled */ mSm.unhandledMessage(msg); if (isQuit(msg)) {//如果命令是SM_QUIT_CMD才会退出,一般情况下是不会退出的 transitionTo(mQuittingState); } break; } if (mDbg) { Log.d(TAG, "processMsg: " + curStateInfo.state.getName()); } } /** * Record that we processed the message */ if (curStateInfo != null) { State orgState = mStateStack[mStateStackTopIndex].state; mProcessedMessages.add(msg, curStateInfo.state, orgState);//保存处理processMessage的消息到mProcessedMessages中,作为一个记录,一般保存最近的20条,这个最大值可以自己定义 } else { mProcessedMessages.add(msg, null, null); } }
这时mStateStack的状态信息变为[mDefaultState, mDriverUnLoadedState],先所以调用mDriverUnLoadedState的processMessage方法,而前面发送的消息为:
sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING, 0)); sendMessage(CMD_START_SUPPLICANT);
第一句的CMD_LOAD_DRIVER,发送给应用层的消息为WIFI_STATE_ENABLING:
class DriverUnloadedState extends State { @Override public void enter() { if (DBG) log(getName() + "\n"); EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); } @Override public boolean processMessage(Message message) { if (DBG) log(getName() + message.toString() + "\n"); switch (message.what) { case CMD_LOAD_DRIVER: mWifiP2pChannel.sendMessage(WIFI_ENABLE_PENDING);//这是发送消息给WifiP2pService,WifiP2pService会响应并返回消息WIFI_ENABLE_PROCEED,其中过程有点复杂,后续再分析 transitionTo(mWaitForP2pDisableState);//状态切换到了mWaitForP2pDisableState,其他好像没有做什么 break; case WifiP2pService.P2P_ENABLE_PENDING: mReplyChannel.replyToMessage(message, P2P_ENABLE_PROCEED); break; default: return NOT_HANDLED; } EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); return HANDLED; } }WaitForP2pDisableState的enter做什么了?
状态已经进入mWaitForP2pDisableState中了:
class WaitForP2pDisableState extends State { ............................. @Override public boolean processMessage(Message message) { case WifiP2pService.WIFI_ENABLE_PROCEED: //响应WifiP2pService消息 //restore argument from original message (CMD_LOAD_DRIVER) message.arg1 = mSavedArg; transitionTo(mDriverLoadingState); break; case CMD_LOAD_DRIVER: case CMD_UNLOAD_DRIVER: case CMD_START_SUPPLICANT: .......................... deferMessage(message); ............................. }
deferMessage将消息放入mDeferredMessages容器中,前面有提及过,作用是要把消息保存起来,等切换到下一个状态后,再将消息发送出去,让下一个状态接收;接下来的performTransitions方法中会将消息发送出去,并且在切换下一个状态前清空容器。
这时候状态在WaitForP2pDisableState中,WifiP2pService接收到消息WIFI_ENABLE_PENDING后,返回WIFI_ENABLE_PROCEED作为响应;
所以执行transitionTo(mDriverLoadingState)进入下一个状态。
processMsg就处理完成了,接着的performTransitions前面已经分析过,主要工作为调用当前状态的exit方法;切换新状态到mSupplicantStartingState,并调用新状态的enter方法,静等下一个消息的到来。
根据前面的分析可知,这时候先执行的是mDriverLoadingState的enter方法:
class DriverLoadingState extends State { @Override public void enter() { if (DBG) log(getName() + "\n"); EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); final Message message = new Message(); message.copyFrom(getCurrentMessage()); /* TODO: add a timeout to fail when driver load is hung. * Similarly for driver unload. */ new Thread(new Runnable() { public void run() { mWakeLock.acquire(); //enabling state switch(message.arg1) { case WIFI_STATE_ENABLING: setWifiState(WIFI_STATE_ENABLING); break; if(WifiNative.loadDriver()) { if (DBG) log("Driver load successful"); sendMessage(CMD_LOAD_DRIVER_SUCCESS); } else { loge("Failed to load driver!"); switch(message.arg1) { case WIFI_STATE_ENABLING: setWifiState(WIFI_STATE_UNKNOWN); break; case WIFI_AP_STATE_ENABLING: setWifiApState(WIFI_AP_STATE_FAILED); break; } sendMessage(CMD_LOAD_DRIVER_FAILURE); } mWakeLock.release(); } }).start(); @Override public boolean processMessage(Message message) { if (DBG) log(getName() + message.toString() + "\n"); switch (message.what) { case CMD_LOAD_DRIVER_SUCCESS: transitionTo(mDriverLoadedState); break; case CMD_LOAD_DRIVER_FAILURE: transitionTo(mDriverFailedState); break; case CMD_LOAD_DRIVER: case CMD_UNLOAD_DRIVER: case CMD_START_SUPPLICANT: case CMD_STOP_SUPPLICANT: case CMD_START_AP: case CMD_STOP_AP: case CMD_START_DRIVER: case CMD_STOP_DRIVER: case CMD_SET_SCAN_MODE: case CMD_SET_SCAN_TYPE: case CMD_SET_HIGH_PERF_MODE: case CMD_SET_COUNTRY_CODE: case CMD_SET_FREQUENCY_BAND: case CMD_START_PACKET_FILTERING: case CMD_STOP_PACKET_FILTERING: deferMessage(message); break; default: return NOT_HANDLED; } EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); return HANDLED; }
enter线程中的消息为前面发送的WIFI_STATE_ENABLING,setWifiState的作用是发送广播通知应用层wifi状态的改变,并且加载JNI的wifi驱动,成功后还发送CMD_LOAD_DRIVER_SUCCESS消息。
接着第二句命令CMD_START_SUPPLICANT,状态在mDriverLoadingState中,执行processMessage方法,这时候会先接收前面的延时消息CMD_LOAD_DRIVER_SUCCESS,接着接收CMD_LOAD_DRIVER,CMD_START_SUPPLICANT
状态就切换到了mDriverLoadedState,并且将其他两条消息延后再传给下一个状态。
后续WifiService会根据逻辑需求,发送各种命令过来进行状态的切换,但流程都和上述分析的一样,状态机能确保各种状态有条不紊的切换并保持控制流程的清晰明了。
最后画一幅流程图如下: