在学习Android Wifi的code时,到处可以看到StateMachie和AsyncChannel的影子,这里我们先大致分析一下它们两个的原理。
从图中我们可以看到State和StateMachie两个大类,StateMachine主要依靠SmHandler去完成消息的分发与处理,在SmHandler中通过mStateStack[]来维持各个State直接的层次关系,而State只定义了简单的几个方法,如enter()、exit()、processMessage()等,分别用来表示刚进入这个状态、退出这个状态以及在这个状态中处理消息。在构建StateMachine时,会把一个个State通过addState()方法加入到mStateInfo中来,通过StateInfo的结构我们可以看出,每个StateInfo不仅包含其自身State,并且也会包含其父State,并且还有active这样变量来表示这个状态是否处于可见状态,这样SmHandler就可以通过mStateStack和mStateInfo来找到当前处于顶端的State,并调用其processMessage()方法,我们稍后会来介绍这样。先进入到StateMachine的构造函数看一下:
/** * Constructor creates a StateMachine with its own thread. * * @param name of the state machine */ protected StateMachine(String name) { mSmThread = new HandlerThread(name); mSmThread.start(); Looper looper = mSmThread.getLooper(); initStateMachine(name, looper); } /** * Constructor creates a StateMachine using the looper. * * @param name of the state machine */ protected StateMachine(String name, Looper looper) { initStateMachine(name, looper); }
private void initStateMachine(String name, Looper looper) { mName = name; mSmHandler = new SmHandler(looper, this); }
public WifiService(Context context) { mContext = context; mInterfaceName = SystemProperties.get("wifi.interface", "wlan0"); mWifiStateMachine = new WifiStateMachine(mContext, mInterfaceName); mWifiStateMachine.enableRssiPolling(true); ....... HandlerThread wifiThread = new HandlerThread("WifiService"); wifiThread.start(); mClientHandler = new ClientHandler(wifiThread.getLooper()); mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper()); mWifiController = new WifiController(mContext, this, wifiThread.getLooper()); mWifiController.start();
进入到WifiStateMachine的构造函数分析,code在framwork/base/wifi/java/android/net/wifi/WifiStateMachine.java
public WifiStateMachine(Context context, String wlanInterface) { super("WifiStateMachine"); mContext = context; mInterfaceName = wlanInterface; ....... mWifiNative = new WifiNative(mInterfaceName); mWifiConfigStore = new WifiConfigStore(context, mWifiNative); mWifiMonitor = new WifiMonitor(this, mWifiNative); mWifiInfo = new WifiInfo(); mSupplicantStateTracker = new SupplicantStateTracker(context, this, mWifiConfigStore, getHandler()); ....... addState(mDefaultState); addState(mInitialState, mDefaultState); addState(mSupplicantStartingState, mDefaultState); addState(mSupplicantStartedState, mDefaultState); addState(mDriverStartingState, mSupplicantStartedState); addState(mDriverStartedState, mSupplicantStartedState); addState(mScanModeState, mDriverStartedState); addState(mConnectModeState, mDriverStartedState); addState(mL2ConnectedState, mConnectModeState); addState(mObtainingIpState, mL2ConnectedState); addState(mVerifyingLinkState, mL2ConnectedState); addState(mCaptivePortalCheckState, mL2ConnectedState); addState(mConnectedState, mL2ConnectedState); addState(mDisconnectingState, mConnectModeState); addState(mDisconnectedState, mConnectModeState); addState(mWpsRunningState, mConnectModeState); addState(mWaitForP2pDisableState, mSupplicantStartedState); addState(mDriverStoppingState, mSupplicantStartedState); addState(mDriverStoppedState, mSupplicantStartedState); addState(mSupplicantStoppingState, mDefaultState); addState(mSoftApStartingState, mDefaultState); addState(mSoftApStartedState, mDefaultState); addState(mTetheringState, mSoftApStartedState); addState(mTetheredState, mSoftApStartedState); addState(mUntetheringState, mSoftApStartedState); setInitialState(mInitialState); setLogRecSize(2000); setLogOnlyTransitions(false); if (DBG) setDbg(true); //start the state machine start(); ....... }
接着看WifiStateMachine的构造函数,我们会看到很多的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); } /** * Add a new state to the state machine, parent will be null * @param state to add */ protected final void addState(State state) { mSmHandler.addState(state, null); }
private final StateInfo addState(State state, State parent) { if (mDbg) { mSm.log("addStateInternal: E state=" + state.getName() + ",parent=" + ((parent == null) ? "" : parent.getName())); } StateInfo parentStateInfo = null; if (parent != null) { parentStateInfo = mStateInfo.get(parent); if (parentStateInfo == null) { // Recursively add our parent as it's not been added yet. parentStateInfo = addState(parent, null); } } StateInfo stateInfo = mStateInfo.get(state); if (stateInfo == null) { stateInfo = new StateInfo(); mStateInfo.put(state, stateInfo); } // Validate that we aren't adding the same state in two different hierarchies. if ((stateInfo.parentStateInfo != null) && (stateInfo.parentStateInfo != parentStateInfo)) { throw new RuntimeException("state already added"); } stateInfo.state = state; stateInfo.parentStateInfo = parentStateInfo; stateInfo.active = false; if (mDbg) mSm.log("addStateInternal: X stateInfo: " + stateInfo); return stateInfo; }
在WifiStateMachine构造函数中添加完所有的state后,会调用setInitialState将InitialState设为初始状态,代码比较简单。最后就调用start()方法,让WifiStateMachine运行起来。这里的start()方法并不是新建一个thread之类的运行,而是根据InitialState去构建好从最上层State到InitialState这条分支上面的所有State信息,然后发送一个SM_INIT_CMD给SmHandler让其做初始化处理,来看代码:
/** * Start the state machine. */ public void start() { // mSmHandler can be null if the state machine has quit. SmHandler smh = mSmHandler; if (smh == null) return; /** Send the complete construction message */ smh.completeConstruction(); } /** * Complete the construction of the state machine. */ private final void completeConstruction() { if (mDbg) mSm.log("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()) { int depth = 0; for (StateInfo i = si; i != null; depth++) { i = i.parentStateInfo; } if (maxDepth < depth) { maxDepth = depth; } } if (mDbg) mSm.log("completeConstruction: maxDepth=" + maxDepth); mStateStack = new StateInfo[maxDepth]; mTempStateStack = new StateInfo[maxDepth]; setupInitialStateStack(); /** Sending SM_INIT_CMD message to invoke enter methods asynchronously */ sendMessageAtFrontOfQueue(obtainMessage(SM_INIT_CMD, mSmHandlerObj)); if (mDbg) mSm.log("completeConstruction: X"); }
private final void setupInitialStateStack() { if (mDbg) { mSm.log("setupInitialStateStack: E mInitialState=" + mInitialState.getName()); } StateInfo curStateInfo = mStateInfo.get(mInitialState); for (mTempStateStackCount = 0; curStateInfo != null; mTempStateStackCount++) { mTempStateStack[mTempStateStackCount] = curStateInfo; curStateInfo = curStateInfo.parentStateInfo; } // Empty the StateStack mStateStackTopIndex = -1; moveTempStateStackToStateStack(); }
private final int moveTempStateStackToStateStack() { int startingIndex = mStateStackTopIndex + 1; int i = mTempStateStackCount - 1; int j = startingIndex; while (i >= 0) { if (mDbg) mSm.log("moveTempStackToStateStack: i=" + i + ",j=" + j); mStateStack[j] = mTempStateStack[i]; j += 1; i -= 1; } mStateStackTopIndex = j - 1; if (mDbg) { mSm.log("moveTempStackToStateStack: X mStateStackTop=" + mStateStackTopIndex + ",startingIndex=" + startingIndex + ",Top=" + mStateStack[mStateStackTopIndex].state.getName()); } return startingIndex; }
protected final void sendMessageAtFrontOfQueue(int what) { // mSmHandler can be null if the state machine has quit. SmHandler smh = mSmHandler; if (smh == null) return; smh.sendMessageAtFrontOfQueue(obtainMessage(what)); }
public final void handleMessage(Message msg) { if (!mHasQuit) { if (mDbg) mSm.log("handleMessage: E msg.what=" + msg.what); /** Save the current message */ mMsg = msg; /** State that processed the message */ State msgProcessedState = null; if (mIsConstructionCompleted) { /** Normal path */ msgProcessedState = processMsg(msg); } else if (!mIsConstructionCompleted && (mMsg.what == SM_INIT_CMD) && (mMsg.obj == mSmHandlerObj)) { /** Initial one time path. */ mIsConstructionCompleted = true; invokeEnterMethods(0); } else { throw new RuntimeException("StateMachine.handleMessage: " + "The start method not called, received msg: " + msg); } performTransitions(msgProcessedState, msg); // We need to check if mSm == null here as we could be quitting. if (mDbg && mSm != null) mSm.log("handleMessage: X"); } }
private final void invokeEnterMethods(int stateStackEnteringIndex) { for (int i = stateStackEnteringIndex; i <= mStateStackTopIndex; i++) { if (mDbg) mSm.log("invokeEnterMethods: " + mStateStack[i].state.getName()); mStateStack[i].state.enter(); mStateStack[i].active = true; } }
在StateMachine中有下面几种发送消息的方法:
publicfinalvoid sendMessage(int what); publicfinalvoid sendMessage(int what,Object obj); publicfinalvoid sendMessage(int what,int arg1); publicfinalvoid sendMessage(int what,int arg1,int arg2); publicfinalvoid sendMessage(int what,int arg1,int arg2,Object obj) protectedfinalvoid deferMessage(Message msg);
前面几种都比较是直接调用Handler的方法,比较简单。我们来看deferMessage(),顾名思义,defer是推迟的意思,deferMessage是将消息推迟处理,推迟到什么时候呢? 我们先来看看deferMessage的实现:
private final void deferMessage(Message msg) { if (mDbg) mSm.log("deferMessage: msg=" + msg.what); /* Copy the "msg" to "newMsg" as "msg" will be recycled */ Message newMsg = obtainMessage(); newMsg.copyFrom(msg); mDeferredMessages.add(newMsg); }
deferMessage将发送的msg拷贝到newMsg中,然后将它加入到mDeferredMessage中,mDeferredMessage是一个ArrayList,用来维护所有的defer message。接着我们来看看StateMachine的状态切换方法,在StateMachine中切换状态是通过transitionTo(IState destState)来实现的,状态的变换则意味着mStateStack的变化,那我们首先来看transitionTo(IState destState)的实现:
protected final void transitionTo(IState destState) { mSmHandler.transitionTo(destState); }
直接调用SmHandler的transitionTo方法:
private final void transitionTo(IState destState) { mDestState = (State) destState; if (mDbg) mSm.log("transitionTo: destState=" + mDestState.getName()); }
从图中我们可以看出,只有在发送state的transition的时候,才会有defer message的处理。到这里,StateMachine基本上讲完了,后面我们会在启动Wifi和连接AP中看到具体的State切换以及消息处理的过程。
在WiFi framework中,有很多地方都运用了AsyncChannel,主要有两种用处,一是发送异步消息,防止主线程被卡住,例如WifiManager和WifiService之间;另一种是发送同步消息,需要等待Server的回复,例如WifiService与WifiStateMachine之间,因为WifiService与WifiStateMachine处理消息的handler处于不同的Thread和looper当中,所以当WifiService给WifiStateMachine发送了一个消息需要等待回复时,这时候就需要用到SyncMananger,这是AsyncChannel中的一个内部类,主要用来发送这种同步的消息。下面就以WifiManager和WifiService、WifiService给WifiStateMachine分别来介绍AsyncChannel的使用方法。
private void init() { synchronized (sThreadRefLock) { if (++sThreadRefCount == 1) { Messenger messenger = getWifiServiceMessenger(); if (messenger == null) { sAsyncChannel = null; return; } sHandlerThread = new HandlerThread("WifiManager"); sAsyncChannel = new AsyncChannel(); sConnected = new CountDownLatch(1); sHandlerThread.start(); Handler handler = new ServiceHandler(sHandlerThread.getLooper()); sAsyncChannel.connect(mContext, handler, messenger); try { sConnected.await(); } catch (InterruptedException e) { Log.e(TAG, "interrupted wait at init"); } } } }
public void connect(Context srcContext, Handler srcHandler, Messenger dstMessenger) { if (DBG) log("connect srcHandler to the dstMessenger E"); // We are connected connected(srcContext, srcHandler, dstMessenger); // Tell source we are half connected replyHalfConnected(STATUS_SUCCESSFUL); if (DBG) log("connect srcHandler to the dstMessenger X"); } public void connected(Context srcContext, Handler srcHandler, Messenger dstMessenger) { if (DBG) log("connected srcHandler to the dstMessenger E"); // Initialize source fields mSrcContext = srcContext; mSrcHandler = srcHandler; mSrcMessenger = new Messenger(mSrcHandler); // Initialize destination fields mDstMessenger = dstMessenger; if (DBG) log("connected srcHandler to the dstMessenger X"); } private void replyHalfConnected(int status) { Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_HALF_CONNECTED); msg.arg1 = status; msg.obj = this; msg.replyTo = mDstMessenger; /* * Link to death only when bindService isn't used. */ if (mConnection == null) { mDeathMonitor = new DeathMonitor(); try { mDstMessenger.getBinder().linkToDeath(mDeathMonitor, 0); } catch (RemoteException e) { mDeathMonitor = null; // Override status to indicate failure msg.arg1 = STATUS_BINDING_UNSUCCESSFUL; } } mSrcHandler.sendMessage(msg); }
public void handleMessage(Message message) { Object listener = removeListener(message.arg2); switch (message.what) { case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { sAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); } else {
public void sendMessage(Message msg) { msg.replyTo = mSrcMessenger; try { mDstMessenger.send(msg); } catch (RemoteException e) { replyDisconnected(STATUS_SEND_UNSUCCESSFUL); } } public void sendMessage(int what) { Message msg = Message.obtain(); msg.what = what; sendMessage(msg); }
private class ClientHandler extends Handler { ClientHandler(android.os.Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: { AsyncChannel ac = new AsyncChannel(); ac.connect(mContext, this, msg.replyTo); break; }
public void connect(WifiConfiguration config, ActionListener listener) { if (config == null) throw new IllegalArgumentException("config cannot be null"); validateChannel(); // Use INVALID_NETWORK_ID for arg1 when passing a config object // arg1 is used to pass network id when the network already exists sAsyncChannel.sendMessage(CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID, putListener(listener), config); }
/* Client commands are forwarded to state machine */ case WifiManager.CONNECT_NETWORK: case WifiManager.SAVE_NETWORK: { WifiConfiguration config = (WifiConfiguration) msg.obj; int networkId = msg.arg1; if (config != null && config.isValid()) { // This is restricted because there is no UI for the user to // monitor/control PAC. if (config.proxySettings != ProxySettings.PAC) { if (DBG) Slog.d(TAG, "Connect with config" + config); mWifiStateMachine.sendMessage(Message.obtain(msg)); } else { Slog.e(TAG, "ClientHandler.handleMessage cannot process msg with PAC"); if (msg.what == WifiManager.CONNECT_NETWORK) { replyFailed(msg, WifiManager.CONNECT_NETWORK_FAILED); } else { replyFailed(msg, WifiManager.SAVE_NETWORK_FAILED); } } } else
private class WifiStateMachineHandler extends Handler { private AsyncChannel mWsmChannel; WifiStateMachineHandler(android.os.Looper looper) { super(looper); mWsmChannel = new AsyncChannel(); mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler()); } @Override public void handleMessage(Message msg) { switch (msg.what) { case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: { if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { mWifiStateMachineChannel = mWsmChannel; } else { Slog.e(TAG, "WifiStateMachine connection failure, error=" + msg.arg1); mWifiStateMachineChannel = null; } break; }
public boolean enableNetwork(int netId, boolean disableOthers) { enforceChangePermission(); if (mWifiStateMachineChannel != null) { return mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, netId, disableOthers); } else { Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); return false; } }
public boolean syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers) { Message resultMsg = channel.sendMessageSynchronously(CMD_ENABLE_NETWORK, netId, disableOthers ? 1 : 0); boolean result = (resultMsg.arg1 != FAILURE); resultMsg.recycle(); return result; }
public Message sendMessageSynchronously(int what, int arg1, int arg2) { Message msg = Message.obtain(); msg.what = what; msg.arg1 = arg1; msg.arg2 = arg2; Message resultMsg = sendMessageSynchronously(msg); return resultMsg; }
public Message sendMessageSynchronously(Message msg) { Message resultMsg = SyncMessenger.sendMessageSynchronously(mDstMessenger, msg); return resultMsg; } private static Message sendMessageSynchronously(Messenger dstMessenger, Message msg) { SyncMessenger sm = SyncMessenger.obtain(); try { if (dstMessenger != null && msg != null) { msg.replyTo = sm.mMessenger; synchronized (sm.mHandler.mLockObject) { dstMessenger.send(msg); sm.mHandler.mLockObject.wait(); } } else { sm.mHandler.mResultMsg = null; } } catch (InterruptedException e) { sm.mHandler.mResultMsg = null; } catch (RemoteException e) { sm.mHandler.mResultMsg = null; } Message resultMsg = sm.mHandler.mResultMsg; sm.recycle(); return resultMsg; } }
case CMD_ENABLE_NETWORK: ok = mWifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1); replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); break;
private void replyToMessage(Message msg, int what, int arg1) { if (msg.replyTo == null) return; Message dstMsg = obtainMessageWithArg2(msg); dstMsg.what = what; dstMsg.arg1 = arg1; mReplyChannel.replyToMessage(msg, dstMsg); }public void replyToMessage(Message srcMsg, Message dstMsg) { try { dstMsg.replyTo = mSrcMessenger; srcMsg.replyTo.send(dstMsg); } catch (RemoteException e) { log("TODO: handle replyToMessage RemoteException" + e); e.printStackTrace(); } }
private class SyncHandler extends Handler { /** The object used to wait/notify */ private Object mLockObject = new Object(); /** The resulting message */ private Message mResultMsg; /** Constructor */ private SyncHandler(Looper looper) { super(looper); } /** Handle of the reply message */ @Override public void handleMessage(Message msg) { mResultMsg = Message.obtain(); mResultMsg.copyFrom(msg); synchronized(mLockObject) { mLockObject.notify(); } } }