Android StateMachine和AsyncChannel

转自: http://blog.csdn.net/lilian0118/article/details/21974229

在学习Android Wifi的code时,到处可以看到StateMachie和AsyncChannel的影子,这里我们先大致分析一下它们两个的原理。


StateMachine原理分析


顾名思义,StateMachine就是状态机的意思,从Goolge给出的解释: The state machine defined here is a hierarchical state machine which processes messages and can have states arranged hierarchically. 在Android世界里,StateMachine也叫做层次状态机,简称HSM,这里的HSM主要用来处理消息并且分层次管理其状态。引入HSM的原因是因为如果在代码当中写入很多swith...case..的语句,会比较难于管理其状态,并且代码也会写的比较复杂。而HSM并不是直接把message交友其本身来处理,而是传递给其State去处理,这样它本身就不必有任何改变,并且各个State直接还可以存在父子等关系,在处理消息的机制上面可以像面向对象的语言一样,父State定义一些基本的处理,子State去细化不同的实现,减少代码的冗余度。

  先来看一下HSM的架构图:


从图中我们可以看到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的构造函数看一下:


[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * Constructor creates a StateMachine with its own thread. 
  3.  * 
  4.  * @param name of the state machine 
  5.  */  
  6. protected StateMachine(String name) {  
  7.     mSmThread = new HandlerThread(name);  
  8.     mSmThread.start();  
  9.     Looper looper = mSmThread.getLooper();  
  10.   
  11.     initStateMachine(name, looper);  
  12. }  
  13.   
  14. /** 
  15.  * Constructor creates a StateMachine using the looper. 
  16.  * 
  17.  * @param name of the state machine 
  18.  */  
  19. protected StateMachine(String name, Looper looper) {  
  20.     initStateMachine(name, looper);  
  21. }  

这里有两中构造方法,一是只传入StateMachine的名字,StateMachine自己构造HanderThread;第二种是传入StateMachine的名字和一个looper,两种方法的区别在于处理的SmHandler将附在哪一个looper上面,后面我们将会看到这两种构造函数的使用。接着看 initStateMachine ( name ,  looper )

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. private void initStateMachine(String name, Looper looper) {  
  2.     mName = name;  
  3.     mSmHandler = new SmHandler(looper, this);  
  4. }  

下面我们以WifiStateMachine这个实例的来仔细分析StateMachine的创建以及运行,WifiStateMachine是继承与StateMachine,其创建过程在WifiService中,代码如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public WifiService(Context context) {  
  2.      mContext = context;  
  3.   
  4.      mInterfaceName =  SystemProperties.get("wifi.interface""wlan0");  
  5.   
  6.      mWifiStateMachine = new WifiStateMachine(mContext, mInterfaceName);  
  7.      mWifiStateMachine.enableRssiPolling(true);  
  8.   
  9.      .......  
  10.      HandlerThread wifiThread = new HandlerThread("WifiService");  
  11.      wifiThread.start();  
  12.      mClientHandler = new ClientHandler(wifiThread.getLooper());  
  13.      mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper());  
  14.      mWifiController = new WifiController(mContext, this, wifiThread.getLooper());  
  15.      mWifiController.start();  



    进入到WifiStateMachine的构造函数分析,code在framwork/base/wifi/java/android/net/wifi/WifiStateMachine.java

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1.     public WifiStateMachine(Context context, String wlanInterface) {  
  2.         super("WifiStateMachine");  
  3.         mContext = context;  
  4.         mInterfaceName = wlanInterface;  
  5.   
  6.     .......  
  7.   
  8.       mWifiNative = new WifiNative(mInterfaceName);  
  9.         mWifiConfigStore = new WifiConfigStore(context, mWifiNative);  
  10.         mWifiMonitor = new WifiMonitor(this, mWifiNative);  
  11.         mWifiInfo = new WifiInfo();  
  12.         mSupplicantStateTracker = new SupplicantStateTracker(context, this, mWifiConfigStore,  
  13.                 getHandler());  
  14.   
  15.     .......  
  16.   
  17.        addState(mDefaultState);  
  18.             addState(mInitialState, mDefaultState);  
  19.             addState(mSupplicantStartingState, mDefaultState);  
  20.             addState(mSupplicantStartedState, mDefaultState);  
  21.                 addState(mDriverStartingState, mSupplicantStartedState);  
  22.                 addState(mDriverStartedState, mSupplicantStartedState);  
  23.                     addState(mScanModeState, mDriverStartedState);  
  24.                     addState(mConnectModeState, mDriverStartedState);  
  25.                         addState(mL2ConnectedState, mConnectModeState);  
  26.                             addState(mObtainingIpState, mL2ConnectedState);  
  27.                             addState(mVerifyingLinkState, mL2ConnectedState);  
  28.                             addState(mCaptivePortalCheckState, mL2ConnectedState);  
  29.                             addState(mConnectedState, mL2ConnectedState);  
  30.                         addState(mDisconnectingState, mConnectModeState);  
  31.                         addState(mDisconnectedState, mConnectModeState);  
  32.                         addState(mWpsRunningState, mConnectModeState);  
  33.                 addState(mWaitForP2pDisableState, mSupplicantStartedState);  
  34.                 addState(mDriverStoppingState, mSupplicantStartedState);  
  35.                 addState(mDriverStoppedState, mSupplicantStartedState);  
  36.             addState(mSupplicantStoppingState, mDefaultState);  
  37.             addState(mSoftApStartingState, mDefaultState);  
  38.             addState(mSoftApStartedState, mDefaultState);  
  39.                 addState(mTetheringState, mSoftApStartedState);  
  40.                 addState(mTetheredState, mSoftApStartedState);  
  41.                 addState(mUntetheringState, mSoftApStartedState);  
  42.   
  43.         setInitialState(mInitialState);  
  44.   
  45.         setLogRecSize(2000);  
  46.         setLogOnlyTransitions(false);  
  47.         if (DBG) setDbg(true);  
  48.   
  49.         //start the state machine  
  50.         start();  
  51.      .......  
  52. }  

根据前面的StateMachine的构造函数,我们可以知道WifiStateMachine会新建一个HandlerThread,名字为“WifiStateMachine”,而在WifiService中创建的另一个对象WifiController将运行在WifiService本身创建的thread里,这些我们可以用DDMS去查看system_server这个进程的所有线程来确认:



接着看WifiStateMachine的构造函数,我们会看到很多的addState方法,进入到这个函数来分析:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * Add a new state to the state machine 
  3.  * @param state the state to add 
  4.  * @param parent the parent of state 
  5.  */  
  6. protected final void addState(State state, State parent) {  
  7.     mSmHandler.addState(state, parent);  
  8. }  
  9.   
  10. /** 
  11.  * Add a new state to the state machine, parent will be null 
  12.  * @param state to add 
  13.  */  
  14. protected final void addState(State state) {  
  15.     mSmHandler.addState(state, null);  
  16. }  

一般来说,HSM只有会一个最上层的父亲State,其它所有的State都是其子State,这一点比较像多叉树。addState只是简单的调用SmHander的addState方法,那我们进入到这个方法中分析:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. private final StateInfo addState(State state, State parent) {  
  2.     if (mDbg) {  
  3.         mSm.log("addStateInternal: E state=" + state.getName() + ",parent="  
  4.                 + ((parent == null) ? "" : parent.getName()));  
  5.     }  
  6.     StateInfo parentStateInfo = null;  
  7.     if (parent != null) {  
  8.         parentStateInfo = mStateInfo.get(parent);  
  9.         if (parentStateInfo == null) {  
  10.             // Recursively add our parent as it's not been added yet.  
  11.             parentStateInfo = addState(parent, null);  
  12.         }  
  13.     }  
  14.     StateInfo stateInfo = mStateInfo.get(state);  
  15.     if (stateInfo == null) {  
  16.         stateInfo = new StateInfo();  
  17.         mStateInfo.put(state, stateInfo);  
  18.     }  
  19.   
  20.     // Validate that we aren't adding the same state in two different hierarchies.  
  21.     if ((stateInfo.parentStateInfo != null)  
  22.             && (stateInfo.parentStateInfo != parentStateInfo)) {  
  23.         throw new RuntimeException("state already added");  
  24.     }  
  25.     stateInfo.state = state;  
  26.     stateInfo.parentStateInfo = parentStateInfo;  
  27.     stateInfo.active = false;  
  28.     if (mDbg) mSm.log("addStateInternal: X stateInfo: " + stateInfo);  
  29.     return stateInfo;  
  30. }  

mStateInfo是一个HashMap,键是State,值为StateInfo,用于保存和查找StateMachine中所有的StateInfo,前面我们介绍过,StateInfo除了包含其自身State以外,还包含其父StateInfo,所以通过mStateInfo结构,我们可以很方便的从一个State找到其所有的父State,这在后面介绍的处理消息流程中非常重要。我们接着来看addState方法,首先根据第二个参数parent是否为空来判断是否要将所有加入到mStateInfo的State的所有父State也加入进来,如果parent不为空,则先去mStateInfo中获取parent state的StateInfo,如果没有查找到,说明这个父State还没有加入进来,则先递归的加入所有的父State;如果parent为空或者所有的所有的父State已经全部进入进来了,则构造一个StateInfo并且对其state、parentStateInfo和active进行赋值,并把它加入到mStateInfo中。当WifiStateMachine中所有的state全部加入到mStateInfo后,我们会看到这样一个树形结构:


在WifiStateMachine构造函数中添加完所有的state后,会调用setInitialState将InitialState设为初始状态,代码比较简单。最后就调用start()方法,让WifiStateMachine运行起来。这里的start()方法并不是新建一个thread之类的运行,而是根据InitialState去构建好从最上层State到InitialState这条分支上面的所有State信息,然后发送一个SM_INIT_CMD给SmHandler让其做初始化处理,来看代码:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * Start the state machine. 
  3.  */  
  4. public void start() {  
  5.     // mSmHandler can be null if the state machine has quit.  
  6.     SmHandler smh = mSmHandler;  
  7.     if (smh == nullreturn;  
  8.   
  9.     /** Send the complete construction message */  
  10.     smh.completeConstruction();  
  11. }  
  12.   
  13.     /** 
  14.      * Complete the construction of the state machine. 
  15.      */  
  16.     private final void completeConstruction() {  
  17.         if (mDbg) mSm.log("completeConstruction: E");  
  18.   
  19.         /** 
  20.          * Determine the maximum depth of the state hierarchy 
  21.          * so we can allocate the state stacks. 
  22.          */  
  23.         int maxDepth = 0;  
  24.         for (StateInfo si : mStateInfo.values()) {  
  25.             int depth = 0;  
  26.             for (StateInfo i = si; i != null; depth++) {  
  27.                 i = i.parentStateInfo;  
  28.             }  
  29.             if (maxDepth < depth) {  
  30.                 maxDepth = depth;  
  31.             }  
  32.         }  
  33.         if (mDbg) mSm.log("completeConstruction: maxDepth=" + maxDepth);  
  34.   
  35.         mStateStack = new StateInfo[maxDepth];  
  36.         mTempStateStack = new StateInfo[maxDepth];  
  37.         setupInitialStateStack();  
  38.   
  39.         /** Sending SM_INIT_CMD message to invoke enter methods asynchronously */  
  40.         sendMessageAtFrontOfQueue(obtainMessage(SM_INIT_CMD, mSmHandlerObj));  
  41.   
  42.         if (mDbg) mSm.log("completeConstruction: X");  
  43.     }  

start方法很简单,只是调用SmHandler的completeConstruction(),在这个函数中,首先计算mStateInfo中最大的深度,然后new两个数组,mStateStack和mTempStateStack用于保存处于活动状态分支上的所有State信息,上图中所示的WifiStateMachine的maxDepth=6。接着来看setUpInitStateStack函数:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. private final void setupInitialStateStack() {  
  2.     if (mDbg) {  
  3.         mSm.log("setupInitialStateStack: E mInitialState=" + mInitialState.getName());  
  4.     }  
  5.   
  6.     StateInfo curStateInfo = mStateInfo.get(mInitialState);  
  7.     for (mTempStateStackCount = 0; curStateInfo != null; mTempStateStackCount++) {  
  8.         mTempStateStack[mTempStateStackCount] = curStateInfo;  
  9.         curStateInfo = curStateInfo.parentStateInfo;  
  10.     }  
  11.   
  12.     // Empty the StateStack  
  13.     mStateStackTopIndex = -1;  
  14.   
  15.     moveTempStateStackToStateStack();  
  16. }  

setUpInitStateStack根据mStateInfo和mInitialState来填充从根State到mInitialState这条路径上所有的State到mTempStateStack中,以WifiStateMachine来举例,即mTempStateStack内容为:0--InitialState, 1--DefaultState。接着来看moveTempStateStacktoStateStack():

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. private final int moveTempStateStackToStateStack() {  
  2.     int startingIndex = mStateStackTopIndex + 1;  
  3.     int i = mTempStateStackCount - 1;  
  4.     int j = startingIndex;  
  5.     while (i >= 0) {  
  6.         if (mDbg) mSm.log("moveTempStackToStateStack: i=" + i + ",j=" + j);  
  7.         mStateStack[j] = mTempStateStack[i];  
  8.         j += 1;  
  9.         i -= 1;  
  10.     }  
  11.   
  12.     mStateStackTopIndex = j - 1;  
  13.     if (mDbg) {  
  14.         mSm.log("moveTempStackToStateStack: X mStateStackTop=" + mStateStackTopIndex  
  15.                 + ",startingIndex=" + startingIndex + ",Top="  
  16.                 + mStateStack[mStateStackTopIndex].state.getName());  
  17.     }  
  18.     return startingIndex;  
  19. }  

从名字就可以看出moveTempStateStacktoStateStack只是把state信息从mTempStateStack移动到mStateStack,只不过把顺序反转了而已。反转后mStateStack的内容为:0--DefaultState, 1--InitialState。mStateStackTopIndex记录了栈底的state位置,即DefaultState在栈中的Index值。接着回到start函数调用的completeConstruction()中,在函数的最后会调用sendMessageAtFrontOfQueue():

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. protected final void sendMessageAtFrontOfQueue(int what) {  
  2.     // mSmHandler can be null if the state machine has quit.  
  3.     SmHandler smh = mSmHandler;  
  4.     if (smh == nullreturn;  
  5.   
  6.     smh.sendMessageAtFrontOfQueue(obtainMessage(what));  
  7. }  

这个函数只是封装了Handler的sendMessageAtFrontOfQueue,用来向MessageQueue的队列头部插入一条message,当MessageQueue从poll返回后,会马上处理这个消息,那我们到SmHandler的handlerMessage函数分析:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public final void handleMessage(Message msg) {  
  2.     if (!mHasQuit) {  
  3.         if (mDbg) mSm.log("handleMessage: E msg.what=" + msg.what);  
  4.   
  5.         /** Save the current message */  
  6.         mMsg = msg;  
  7.   
  8.         /** State that processed the message */  
  9.         State msgProcessedState = null;  
  10.         if (mIsConstructionCompleted) {  
  11.             /** Normal path */  
  12.             msgProcessedState = processMsg(msg);  
  13.         } else if (!mIsConstructionCompleted && (mMsg.what == SM_INIT_CMD)  
  14.                 && (mMsg.obj == mSmHandlerObj)) {  
  15.             /** Initial one time path. */  
  16.             mIsConstructionCompleted = true;  
  17.             invokeEnterMethods(0);  
  18.         } else {  
  19.             throw new RuntimeException("StateMachine.handleMessage: "  
  20.                     + "The start method not called, received msg: " + msg);  
  21.         }  
  22.         performTransitions(msgProcessedState, msg);  
  23.   
  24.         // We need to check if mSm == null here as we could be quitting.  
  25.         if (mDbg && mSm != null) mSm.log("handleMessage: X");  
  26.     }  
  27. }  

第一次调用start函数时,mIsConstructionCompleted将为false,等处理完SM_INIT_CMD后,mIsConstructionCompleted将变为true,以后处理所有的消息将进入到processMsg当中。我们先来看invokerEnterMethods(0):

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. private final void invokeEnterMethods(int stateStackEnteringIndex) {  
  2.     for (int i = stateStackEnteringIndex; i <= mStateStackTopIndex; i++) {  
  3.         if (mDbg) mSm.log("invokeEnterMethods: " + mStateStack[i].state.getName());  
  4.         mStateStack[i].state.enter();  
  5.         mStateStack[i].active = true;  
  6.     }  
  7. }  

这个函数比较简单,只是调用mStateStack中从stateStackEnteringIndex到mStateStackTopIndex中间所有state的enter方法,并把它的active变量置为true。即先调用DefaultState的enter函数,再调用InitialState的enter函数。这样StateMachine就运行成功了,后面再有任何消息的处理都将会走到processMsg中,到这里我们先来简单介绍一下StateMachine的几种sendMsg的方法以及状态切换,然后再来接着看processMsg()和performTransitions()方法。

  在StateMachine中有下面几种发送消息的方法:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. publicfinalvoid sendMessage(int what);  
  2. publicfinalvoid sendMessage(int what,Object obj);  
  3. publicfinalvoid sendMessage(int what,int arg1);  
  4. publicfinalvoid sendMessage(int what,int arg1,int arg2);  
  5. publicfinalvoid sendMessage(int what,int arg1,int arg2,Object obj)  
  6. protectedfinalvoid deferMessage(Message msg);  

 前面几种都比较是直接调用Handler的方法,比较简单。我们来看deferMessage(),顾名思义,defer是推迟的意思,deferMessage是将消息推迟处理,推迟到什么时候呢? 我们先来看看deferMessage的实现:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. private final void deferMessage(Message msg) {  
  2.     if (mDbg) mSm.log("deferMessage: msg=" + msg.what);  
  3.   
  4.     /* Copy the "msg" to "newMsg" as "msg" will be recycled */  
  5.     Message newMsg = obtainMessage();  
  6.     newMsg.copyFrom(msg);  
  7.   
  8.     mDeferredMessages.add(newMsg);  
  9. }  

deferMessage将发送的msg拷贝到newMsg中,然后将它加入到mDeferredMessage中,mDeferredMessage是一个ArrayList,用来维护所有的defer message。接着我们来看看StateMachine的状态切换方法,在StateMachine中切换状态是通过transitionTo(IState destState)来实现的,状态的变换则意味着mStateStack的变化,那我们首先来看transitionTo(IState destState)的实现:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. protected final void transitionTo(IState destState) {  
  2.     mSmHandler.transitionTo(destState);  
  3. }  

直接调用SmHandler的transitionTo方法:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. private final void transitionTo(IState destState) {  
  2.     mDestState = (State) destState;  
  3.     if (mDbg) mSm.log("transitionTo: destState=" + mDestState.getName());  
  4. }  

现在我们回到handlerMessage中来接着看processMsg()和performTransitions()方法,首先我们来总体看一下handlerMessage大概的流程图:


  从图中我们可以看出,只有在发送state的transition的时候,才会有defer message的处理。到这里,StateMachine基本上讲完了,后面我们会在启动Wifi和连接AP中看到具体的State切换以及消息处理的过程。


AsyncChannel分析

AsyncChannel类用于处理两个Handler之间的异步消息传递,消息传递的Handler可以出于同一进程,也可以处于不同进程,不同进程之间的Handler消息传递使用Android的Binder通信机制来实现。AsyncChannel有两种通信机制,一种单向通信,另一种是双向通信。单向通信主要用于Server不需要知道Client是谁,用于简单的request/reply这种协议;另一种双向通信,Server需要是哪个Client发起的请求,用于维护各个Client的不同状态。另外在Server和Client建立连接的时候,又分为同步连接和异步连接,下面来看一下这几种不同的连接框图:


在WiFi framework中,有很多地方都运用了AsyncChannel,主要有两种用处,一是发送异步消息,防止主线程被卡住,例如WifiManager和WifiService之间;另一种是发送同步消息,需要等待Server的回复,例如WifiService与WifiStateMachine之间,因为WifiService与WifiStateMachine处理消息的handler处于不同的Thread和looper当中,所以当WifiService给WifiStateMachine发送了一个消息需要等待回复时,这时候就需要用到SyncMananger,这是AsyncChannel中的一个内部类,主要用来发送这种同步的消息。下面就以WifiManager和WifiService、WifiService给WifiStateMachine分别来介绍AsyncChannel的使用方法。


双向通信连接的建立

以WifiManager和WifiService之间使用AsyncChannel为例来看看如果使两个handler建立连接来传递消息。首先看WifiManager创建AsyncChannel的过程,代码在WifiManager的init()函数当中:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. private void init() {  
  2.     synchronized (sThreadRefLock) {  
  3.         if (++sThreadRefCount == 1) {  
  4.             Messenger messenger = getWifiServiceMessenger();  
  5.             if (messenger == null) {  
  6.                 sAsyncChannel = null;  
  7.                 return;  
  8.             }  
  9.   
  10.             sHandlerThread = new HandlerThread("WifiManager");  
  11.             sAsyncChannel = new AsyncChannel();  
  12.             sConnected = new CountDownLatch(1);  
  13.   
  14.             sHandlerThread.start();  
  15.             Handler handler = new ServiceHandler(sHandlerThread.getLooper());  
  16.             sAsyncChannel.connect(mContext, handler, messenger);  
  17.             try {  
  18.                 sConnected.await();  
  19.             } catch (InterruptedException e) {  
  20.                 Log.e(TAG, "interrupted wait at init");  
  21.             }  
  22.         }  
  23.     }  
  24. }  

getWifiServiceMessenger利用WifiService中的成员mClientHandler构造一个Messenger对象,然后我们来看connect函数的实现:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public void connect(Context srcContext, Handler srcHandler, Messenger dstMessenger) {  
  2.     if (DBG) log("connect srcHandler to the dstMessenger  E");  
  3.   
  4.     // We are connected  
  5.     connected(srcContext, srcHandler, dstMessenger);  
  6.   
  7.     // Tell source we are half connected  
  8.     replyHalfConnected(STATUS_SUCCESSFUL);  
  9.   
  10.     if (DBG) log("connect srcHandler to the dstMessenger X");  
  11. }  
  12.   
  13. public void connected(Context srcContext, Handler srcHandler, Messenger dstMessenger) {  
  14.     if (DBG) log("connected srcHandler to the dstMessenger  E");  
  15.   
  16.     // Initialize source fields  
  17.     mSrcContext = srcContext;  
  18.     mSrcHandler = srcHandler;  
  19.     mSrcMessenger = new Messenger(mSrcHandler);  
  20.   
  21.     // Initialize destination fields  
  22.     mDstMessenger = dstMessenger;  
  23.   
  24.     if (DBG) log("connected srcHandler to the dstMessenger X");  
  25. }  
  26.   
  27. private void replyHalfConnected(int status) {  
  28.     Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_HALF_CONNECTED);  
  29.     msg.arg1 = status;  
  30.     msg.obj = this;  
  31.     msg.replyTo = mDstMessenger;  
  32.   
  33.     /* 
  34.      * Link to death only when bindService isn't used. 
  35.      */  
  36.     if (mConnection == null) {  
  37.         mDeathMonitor = new DeathMonitor();  
  38.         try {  
  39.             mDstMessenger.getBinder().linkToDeath(mDeathMonitor, 0);  
  40.         } catch (RemoteException e) {  
  41.             mDeathMonitor = null;  
  42.             // Override status to indicate failure  
  43.             msg.arg1 = STATUS_BINDING_UNSUCCESSFUL;  
  44.         }  
  45.     }  
  46.   
  47.     mSrcHandler.sendMessage(msg);  
  48. }  

从代码里面可以看到,connect函数只是简单的调用connected函数对一些成员变量进行赋值,然后调用replyHalfConnected函数向srcHandler发送一个CMD_CHANNEL_HALF_CONNECTED消息。同时我们看replyHalfConnected函数最后调用到linkToDeath函数,这是为了防止AsyncChannel用于不同进程通信时,若Server端所在的进程已经死掉,来通知Client端进程进行一些后期处理,例如调用disconnect断开连接。
回到WifiMananger的ServiceHandler看如何处理CMD_CHANNEL_HALF_CONNECTED消息:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public void handleMessage(Message message) {  
  2.     Object listener = removeListener(message.arg2);  
  3.     switch (message.what) {  
  4.         case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:  
  5.             if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {  
  6.                 sAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);  
  7.             } else {  

接着来看AsyncChannel的sendMessage方法:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public void sendMessage(Message msg) {  
  2.     msg.replyTo = mSrcMessenger;  
  3.     try {  
  4.         mDstMessenger.send(msg);  
  5.     } catch (RemoteException e) {  
  6.         replyDisconnected(STATUS_SEND_UNSUCCESSFUL);  
  7.     }  
  8. }  
  9.   
  10. public void sendMessage(int what) {  
  11.     Message msg = Message.obtain();  
  12.     msg.what = what;  
  13.     sendMessage(msg);  
  14. }  

这样在WifiService的mClientHandler对象将收到一个CMD_CHANNEL_FULL_CONNECTION的消息,我们来看具体代码:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. private class ClientHandler extends Handler {  
  2.   
  3.     ClientHandler(android.os.Looper looper) {  
  4.         super(looper);  
  5.     }  
  6.   
  7.     @Override  
  8.     public void handleMessage(Message msg) {  
  9.   
  10.                 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {  
  11.                 AsyncChannel ac = new AsyncChannel();  
  12.                 ac.connect(mContext, this, msg.replyTo);  
  13.                 break;  
  14.             }  

这里和上面的流程图里面有点差别的是调用的ac.connect而不是ac.connected,但由上面的connect函数实现我们来看,其实connect就是调用connected来实现的,只是多了一个向srcHandler发送一个CMD_CHANNEL_HALF_CONNECTED的消息,在mClientHandler收到这个消息后,会将WifiMananger的ServiceHandler加入到流量状态管理当中,用于以后通知ServiceHandler不同的状态。到此,双方就建立一个双向通信的连接,下面来简单的看一下WifiManager给WifiService发送一个消息的流程,以WifiManager的连接AP的connect函数为例:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public void connect(WifiConfiguration config, ActionListener listener) {  
  2.     if (config == nullthrow new IllegalArgumentException("config cannot be null");  
  3.     validateChannel();  
  4.     // Use INVALID_NETWORK_ID for arg1 when passing a config object  
  5.     // arg1 is used to pass network id when the network already exists  
  6.     sAsyncChannel.sendMessage(CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID,  
  7.             putListener(listener), config);  
  8. }  

由前面的知识,我们可以知道在WifiService的mClientHandler中将收到CONNECT_NETWORK这个消息,到具体代码中来看:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /* Client commands are forwarded to state machine */  
  2.                 case WifiManager.CONNECT_NETWORK:  
  3.                 case WifiManager.SAVE_NETWORK: {  
  4.                     WifiConfiguration config = (WifiConfiguration) msg.obj;  
  5.                     int networkId = msg.arg1;  
  6.                     if (config != null && config.isValid()) {  
  7.                         // This is restricted because there is no UI for the user to  
  8.                         // monitor/control PAC.  
  9.                         if (config.proxySettings != ProxySettings.PAC) {  
  10.                             if (DBG) Slog.d(TAG, "Connect with config" + config);  
  11.                             mWifiStateMachine.sendMessage(Message.obtain(msg));  
  12.                         } else {  
  13.                             Slog.e(TAG,  "ClientHandler.handleMessage cannot process msg with PAC");  
  14.                             if (msg.what == WifiManager.CONNECT_NETWORK) {  
  15.                                 replyFailed(msg, WifiManager.CONNECT_NETWORK_FAILED);  
  16.                             } else {  
  17.                                 replyFailed(msg, WifiManager.SAVE_NETWORK_FAILED);  
  18.                             }  
  19.                         }  
  20.                     } else  

这里WifiService只是简单的转发这个消息到WifiStateMachine当中,我们到后面再来分析WifiStateMachine如果处理这个消息并连接AP的流程。

单向通信连接的建立

下面以WifiService与WifiStateMachine之间使用的AsyncChannel来分析一下如何建立单向连接,并且使用AsynChannel来发送同步消息。在WifiService与WifiStateMachine之间,这两个对象中间的Handler其实是运行在不同的Thread和looper上,要在它们两个之间实现同步调用,就需要用到SyncMananger,我们也会看一个简单的例子来理解如何使用。首先来看AsyncChannel的创建:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. private class WifiStateMachineHandler extends Handler {  
  2.     private AsyncChannel mWsmChannel;  
  3.   
  4.     WifiStateMachineHandler(android.os.Looper looper) {  
  5.         super(looper);  
  6.         mWsmChannel = new AsyncChannel();  
  7.         mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler());  
  8.     }  
  9.   
  10.     @Override  
  11.     public void handleMessage(Message msg) {  
  12.         switch (msg.what) {  
  13.             case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {  
  14.                 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {  
  15.                     mWifiStateMachineChannel = mWsmChannel;  
  16.                 } else {  
  17.                     Slog.e(TAG, "WifiStateMachine connection failure, error=" + msg.arg1);  
  18.                     mWifiStateMachineChannel = null;  
  19.                 }  
  20.                 break;  
  21.             }  

以上就是AsyncChannel的实例化以及单向连接的建立过程,非常的简单,后面mWifiStateMachineChannel就可以直接发送消息给WifiStateMachine了。下面再来看一下如何在WifiService与WifiStateMachine实现同步,我们以enableNetwork为例来分析:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public boolean enableNetwork(int netId, boolean disableOthers) {  
  2.     enforceChangePermission();  
  3.     if (mWifiStateMachineChannel != null) {  
  4.         return mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, netId,  
  5.                 disableOthers);  
  6.     } else {  
  7.         Slog.e(TAG, "mWifiStateMachineChannel is not initialized");  
  8.         return false;  
  9.     }  
  10. }  

进入到WifiStateMachine的syncEnableNetwork来分析:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public boolean syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers) {  
  2.     Message resultMsg = channel.sendMessageSynchronously(CMD_ENABLE_NETWORK, netId,  
  3.             disableOthers ? 1 : 0);  
  4.     boolean result = (resultMsg.arg1 != FAILURE);  
  5.     resultMsg.recycle();  
  6.     return result;  
  7. }  

从这里可以看到调用sendMessageSynchronously后返回一个Message对象,那么这个Message对象是谁构造返回的呢?我们先来看看AsyncChannel的sendMessageSynchronously方法:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public Message sendMessageSynchronously(int what, int arg1, int arg2) {  
  2.     Message msg = Message.obtain();  
  3.     msg.what = what;  
  4.     msg.arg1 = arg1;  
  5.     msg.arg2 = arg2;  
  6.     Message resultMsg = sendMessageSynchronously(msg);  
  7.     return resultMsg;  
  8. }  
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public Message sendMessageSynchronously(Message msg) {  
  2.     Message resultMsg = SyncMessenger.sendMessageSynchronously(mDstMessenger, msg);  
  3.     return resultMsg;  
  4. }  
  5.   
  6.     private static Message sendMessageSynchronously(Messenger dstMessenger, Message msg) {  
  7.         SyncMessenger sm = SyncMessenger.obtain();  
  8.         try {  
  9.             if (dstMessenger != null && msg != null) {  
  10.                 msg.replyTo = sm.mMessenger;  
  11.                 synchronized (sm.mHandler.mLockObject) {  
  12.                     dstMessenger.send(msg);  
  13.                     sm.mHandler.mLockObject.wait();  
  14.                 }  
  15.             } else {  
  16.                 sm.mHandler.mResultMsg = null;  
  17.             }  
  18.         } catch (InterruptedException e) {  
  19.             sm.mHandler.mResultMsg = null;  
  20.         } catch (RemoteException e) {  
  21.             sm.mHandler.mResultMsg = null;  
  22.         }  
  23.         Message resultMsg = sm.mHandler.mResultMsg;  
  24.         sm.recycle();  
  25.         return resultMsg;  
  26.     }  
  27. }  

从SyncMananger的sendMessageSynchronously方法看,当其给dstMessenger发送消息后,当前调用的线程就进入wait阶段等待别的时机再来唤醒,等它被唤醒后,在sm.mHandler.mResultMsg中就有我们上面提到的Message对象了。那给被谁唤醒?sm.mHandler.mResultMsg又是如何得来,我们先来看WifiStateMachine如何处理CMD_ENABLE_NETWORK这个消息吧。以WifiStateMachine中的ConnectModeState来看,当收到CMD_ENABLE_NETWORK消息后的处理流程如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. case CMD_ENABLE_NETWORK:  
  2.     ok = mWifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1);  
  3.     replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);  
  4.     break;  

再来看replyToMessage的实现:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1.     private void replyToMessage(Message msg, int what, int arg1) {  
  2.         if (msg.replyTo == nullreturn;  
  3.         Message dstMsg = obtainMessageWithArg2(msg);  
  4.         dstMsg.what = what;  
  5.         dstMsg.arg1 = arg1;  
  6.         mReplyChannel.replyToMessage(msg, dstMsg);  
  7.     }<pre code_snippet_id="255785" snippet_file_name="blog_20140327_30_2518776" name="code" class="java">    public void replyToMessage(Message srcMsg, Message dstMsg) {  
  8.         try {  
  9.             dstMsg.replyTo = mSrcMessenger;  
  10.             srcMsg.replyTo.send(dstMsg);  
  11.         } catch (RemoteException e) {  
  12.             log("TODO: handle replyToMessage RemoteException" + e);  
  13.             e.printStackTrace();  
  14.         }  
  15.     }</pre><br>  
  16. <pre></pre>  
  17. <pre></pre>  
  18. <pre></pre>  

有SyncMananger的sendMessageSynchronously的实现我们可以知道,srcMsg.replyTo = sm.Messenger对象的,我们进入到sm.Messenger的handlerMessage分析:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. private class SyncHandler extends Handler {  
  2.     /** The object used to wait/notify */  
  3.     private Object mLockObject = new Object();  
  4.     /** The resulting message */  
  5.     private Message mResultMsg;  
  6.   
  7.     /** Constructor */  
  8.     private SyncHandler(Looper looper) {  
  9.         super(looper);  
  10.     }  
  11.   
  12.     /** Handle of the reply message */  
  13.     @Override  
  14.     public void handleMessage(Message msg) {  
  15.         mResultMsg = Message.obtain();  
  16.         mResultMsg.copyFrom(msg);  
  17.         synchronized(mLockObject) {  
  18.             mLockObject.notify();  
  19.         }  
  20.     }  
  21. }  

在SyncHandler收到消息后,先将它拷贝到mResultMsg中,然后调用mLockObject.notify()将先前进入wait()的线程唤醒,这样就实现了同步调用。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值