android中,wifi的核心是WPAS(wpa_supplicant),它管理和控制Android平台中的Wi-Fi功能。在整个wifi模块中,其更像是一个一个服务端,实现了连接,认证等工作流程。
而客户端有wpa_cli,和wpa_supplicant之间的通信依靠wpa ctrl接口来实现,而在wifi的framework层,其实主要工作就是向下实现wpa_cli的功能和wpa_supplicant通信,向上实现WiFiManager的简易接口供上层app调用。
wifi的framework分析起来相对于wpa_supplicant比较简单,先记录这几天看代码的一些点(阅读《深入理解Android:WiFi模块 NFC和GPS卷 - 邓凡平》和android4.2代码的一些笔记)。
首先必须了解两个类:StateMachine和AsyncChannel
1、StateMachine
在wifi模块framework层的东西中,有很多地方都是用了状态机的机制:WifiStateMachine,SupplicantStateTracker,DhcpStateMachine,WifiWatchdogStateMachine等。了解状态机的运行方式,是了解wifi模块在framework层运作的基础。
StateMachine是具有层级关系的状态机类,记录几个重要的点:
(1)addState函数可以增加一个状态,同时,该函数可以指定父子层级关系。
setInitialState函数指定初始状态。调用start函数时,状态机开始运行。
(2)从一个状态跳转到另一个状态时调用transitionTo函数。进入另一个状态时会先调用到状态的enter函数,退出时调用exit函数,同时得考虑他们的层级关系,而不是直接跳转。以WifiWatchdogStateMachine的状态机map为例,从Disabled 状态转到Verifying ,会先调用Disabled的exit,再依次调用Enabled和Verifying的enter。
下面是WifiWatchdogStateMachine的状态机map:
/** * STATE MAP * Default * / \ * Disabled Enabled * / \ \ * NotConnected Verifying Connected * /---------\ * (all other states) */
(3)消息会在当前的状态中处理,对应的函数为processMessage。如果当前状态不能处理,会返回NOT_HANDLED。转到父状态处理,如果父状态依旧处理不了,则依次上去,如果都不能处理,最后unhandledMessage函数会被调用。
已经处理则返回HANDLED,如果一个消息想保留到下个状态再处理,可以调用deferMessage函数。
(4)由于StateMachine内部是围绕一个Handler来工作的, 所以外界只能调用StateMachine的obtainMessage函数以获取一个Message。发想送消息给StateMachine,调用sendMessage函数,StateMachine中的Handler会处理它。
2、AsyncChannel
这个类在wifi模块中也是被大量使用,是了解wifi的framework避不开的类。该类用于在两个handler之间传递消息。
有两种工作模式:一种是单通道模式,只有客户端连接了AsyncChannel,能向客户端发送请求,服务端只要回应即可。另一种是双通道模式,客户端服务端都连接AsyncChannel,双方均可以向对方发送请求。
单通道使用步骤:
(1)客户端拿到自己的handler;
(2)拿到服务端的Messenger(使用服务端handler构建),或者是服务端的handler;
(3)创建AsyncChannel对象,调用其connect函数,请求连接客户端自己的handler和服务端的Messenger;
(4)连接成功后,服务端会回应CMD_CHANNEL_HALF_CONNECTED消息。
双通道使用步骤:
其实双通道是在单通道的基础上完成的,
(1)客户端在接收到CMD_CHANNEL_HALF_CONNECTED消息后,
发送sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
(2)服务端在handler中会受到该消息,接着服务端也创建AsyncChannel对象,调用其connect函数connect(mContext, this, msg.replyTo)。
(3)另外还有一种比较方便的方法创建双通道,即调用该函数即可:
public int fullyConnectSync(Context srcContext, Handler srcHandler, Handler dstHandler)
需要传入客户端的context,客户端的handler和服务端的handler。返回值STATUS_SUCCESSFUL即代表建立成功。
一些例子:
(1)在wifi的framework层,WifiManager和WifiService之间建立起了双通道:
WifiManager作为客户端:
申请单通道连接:
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);
......
}
}
}
在单通道连接基础上,请求双通道连接
sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION):
private static class ServiceHandler extends Handler {
ServiceHandler(Looper looper) {
super(looper);
}
@Override
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 {
......
WifiService作为服务端,在接收到CMD_CHANNEL_FULL_CONNECTION消息后,请求connect:
private class ClientHandler extends Handler {
ClientHandler(android.os.Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
if (DBG) Slog.d(TAG, "New client listening to asynchronous messages");
// We track the clients by the Messenger
// since it is expected to be always available
mTrafficPoller.addClient(msg.replyTo);
} else {
Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
}
break;
}
......
case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
AsyncChannel ac = new AsyncChannel();
ac.connect(mContext, this, msg.replyTo);
break;
}
(2)WifiService和WifiStateMachine之间连接方式为单通道,WifiStateMachine作为服务端,WifiService作为客户端,连接后,使用sendMessageSynchronously来进行请求,而WifiStateMachine会使用replyToMessage来进行回复(WifiStateMachine会用到mReplyChannel这个对象):
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;
}