在平时的android开发中,经常会用到wifi相关操作,其实就应用而言,系统都是通过WifiManager对应的api来进行对应的操作
我们可以从源码的frameworks/base/api目录中看到当前系统提供的所有api
public class WifiManager {
method public int addNetwork(android.net.wifi.WifiConfiguration);
method public static int calculateSignalLevel(int, int);
method public void cancelWps(android.net.wifi.WifiManager.WpsCallback);
method public static int compareSignalLevel(int, int);
method public android.net.wifi.WifiManager.MulticastLock createMulticastLock(java.lang.String);
method public android.net.wifi.WifiManager.WifiLock createWifiLock(int, java.lang.String);
method public android.net.wifi.WifiManager.WifiLock createWifiLock(java.lang.String);
method public boolean disableNetwork(int);
method public boolean disconnect();
method public boolean enableNetwork(int, boolean);
method public java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks();
method public android.net.wifi.WifiInfo getConnectionInfo();
method public android.net.DhcpInfo getDhcpInfo();
method public java.util.List<android.net.wifi.ScanResult> getScanResults();
method public int getWifiState();
method public boolean is5GHzBandSupported();
method public boolean isDeviceToApRttSupported();
method public boolean isEnhancedPowerReportingSupported();
method public boolean isP2pSupported();
method public boolean isPreferredNetworkOffloadSupported();
method public boolean isScanAlwaysAvailable();
method public boolean isTdlsSupported();
method public boolean isWifiEnabled();
method public boolean pingSupplicant();
method public boolean reassociate();
method public boolean reconnect();
method public boolean removeNetwork(int);
method public boolean saveConfiguration();
method public void setTdlsEnabled(java.net.InetAddress, boolean);
method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
method public boolean setWifiEnabled(boolean);
method public boolean startScan();
method public void startWps(android.net.wifi.WpsInfo, android.net.wifi.WifiManager.WpsCallback);
method public int updateNetwork(android.net.wifi.WifiConfiguration);
field public static final java.lang.String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
field public static final java.lang.String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE = "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
field public static final int ERROR_AUTHENTICATING = 1; // 0x1
field public static final java.lang.String EXTRA_BSSID = "bssid";
field public static final java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
field public static final java.lang.String EXTRA_NEW_RSSI = "newRssi";
field public static final java.lang.String EXTRA_NEW_STATE = "newState";
field public static final java.lang.String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state";
field public static final java.lang.String EXTRA_RESULTS_UPDATED = "resultsUpdated";
field public static final java.lang.String EXTRA_SUPPLICANT_CONNECTED = "connected";
field public static final java.lang.String EXTRA_SUPPLICANT_ERROR = "supplicantError";
field public static final java.lang.String EXTRA_WIFI_INFO = "wifiInfo";
field public static final java.lang.String EXTRA_WIFI_STATE = "wifi_state";
field public static final java.lang.String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED";
field public static final java.lang.String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE";
field public static final java.lang.String RSSI_CHANGED_ACTION = "android.net.wifi.RSSI_CHANGED";
field public static final java.lang.String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS";
field public static final java.lang.String SUPPLICANT_CONNECTION_CHANGE_ACTION = "android.net.wifi.supplicant.CONNECTION_CHANGE";
field public static final java.lang.String SUPPLICANT_STATE_CHANGED_ACTION = "android.net.wifi.supplicant.STATE_CHANGE";
field public static final int WIFI_MODE_FULL = 1; // 0x1
field public static final int WIFI_MODE_FULL_HIGH_PERF = 3; // 0x3
field public static final int WIFI_MODE_SCAN_ONLY = 2; // 0x2
field public static final java.lang.String WIFI_STATE_CHANGED_ACTION = "android.net.wifi.WIFI_STATE_CHANGED";
field public static final int WIFI_STATE_DISABLED = 1; // 0x1
field public static final int WIFI_STATE_DISABLING = 0; // 0x0
field public static final int WIFI_STATE_ENABLED = 3; // 0x3
field public static final int WIFI_STATE_ENABLING = 2; // 0x2
field public static final int WIFI_STATE_UNKNOWN = 4; // 0x4
field public static final int WPS_AUTH_FAILURE = 6; // 0x6
field public static final int WPS_OVERLAP_ERROR = 3; // 0x3
field public static final int WPS_TIMED_OUT = 7; // 0x7
field public static final int WPS_TKIP_ONLY_PROHIBITED = 5; // 0x5
field public static final int WPS_WEP_PROHIBITED = 4; // 0x4
}
WifiManager和WifiServiceImpl远程通信
其实关于WifiManager操作基本都是通过远程服务端实现,这一点稍后讨论,WifiManager中的常用方法:
// 连接到指定网络
public void connect(int networkId, ActionListener listener) {
if (networkId < 0) throw new IllegalArgumentException("Network id cannot be negative");
validateChannel();
sAsyncChannel.sendMessage(CONNECT_NETWORK, networkId, putListener(listener));
}
// 保存网络
public void save(WifiConfiguration config, ActionListener listener) {
if (config == null) throw new IllegalArgumentException("config cannot be null");
validateChannel();
sAsyncChannel.sendMessage(SAVE_NETWORK, 0, putListener(listener), config);
}
// 忘记网络
public void forget(int netId, ActionListener listener) {
if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
validateChannel();
sAsyncChannel.sendMessage(FORGET_NETWORK, netId, putListener(listener));
}
可以面这种操作网络的实际上都是通过sAsyncChannel中进一步实现的,sAsyncChannel是一个AsyncChannel类型,其实AsyncChannel是连接WifiManager和WifiServiceImpl的桥梁
AsyncChannel
在WifiManager构造方法中,调用了init()方法来初始化一些参数
private void init() {
synchronized (sThreadRefLock) {
if (++sThreadRefCount == 1) {
// 获取服务端(WifiServiceImpl)中对应的mClientHandler,WifiServiceImpl继承自IWifiManager.Stub
Messenger messenger = getWifiServiceMessenger();
if (messenger == null) {
sAsyncChannel = null;
return;
}
sHandlerThread = new HandlerThread("WifiManager");
sAsyncChannel = new AsyncChannel();
// CountDownLatch是一个同步辅助类,犹如倒计时计数器,创建对象时通过构造方法设置初始值,调用CountDownLatch对象的await()方法则处于等待状态,调用countDown()方法就将计数器减1,当计数到达0时,则所有等待者或单个等待者开始执行。
sConnected = new CountDownLatch(1);
sHandlerThread.start();
Handler handler = new ServiceHandler(sHandlerThread.getLooper());
// 1. 调用连接AsyncChannel.connect进行半连接
sAsyncChannel.connect(mContext, handler, messenger);
try {
sConnected.await();
} catch (InterruptedException e) {
Log.e(TAG, "interrupted wait at init");
}
}
}
}
上面代码主要做了两件事:
1.通过getWifiServiceMessenger()获取WifiServiceImpl中对应的mClientHandler
2.调用连接AsyncChannel.connect进行半连接
为什么第二步是半连接?分析代码吧
我们看下AsyncChannel#connect方法
public class AsyncChannel {
....
public void connect(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
// 连接srcHandler和dstMessenger
connected(srcContext, srcHandler, dstMessenger);
// 在replyHalfConnected中会发送CMD_CHANNEL_HALF_CONNECTED到srcHandler处理
replyHalfConnected(STATUS_SUCCESSFUL);
}
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);
// 这里的dstMessenger就是传递过来的WifiServiceImpl中对应的mClientHandler
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;
// 创建一个死亡监听,当当前mDstMessenger对应的binder死亡以后,会在DeathMonitor中发送一个"STATUS_REMOTE_DISCONNECTION"消息
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;
}
}
// 发送CMD_CHANNEL_HALF_CONNECTED消息到mSrcHandler也就是在init方法中1.中传递进来的ServiceHandler
mSrcHandler.sendMessage(msg);
}
....
}
上述mSrcHandler.sendMessage(msg);中mSrcHandler是WifiManager$ServiceHandler的一个内部类
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) {
sAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
} else {
sAsyncChannel = null;
}
sConnected.countDown();
break;
}
}
....
}
在ServiceHandler处理” CMD_CHANNEL_HALF_CONNECTED”消息,会继续通过AsyncChannel发送一个”CMD_CHANNEL_FULL_CONNECTION”消息
public void sendMessage(Message msg) {
// 2.这里会向mDstMessenger对应的handler发送一条消息,然后由其处理
msg.replyTo = mSrcMessenger;
try {
mDstMessenger.send(msg);
} catch (RemoteException e) {
replyDisconnected(STATUS_SEND_UNSUCCESSFUL);
}
}
上述mDstMessenger就是在1.处传递的Messenger,也就是通过WifiServiceImpl#getWifiServiceMessenger的
public Messenger getWifiServiceMessenger() {
enforceAccessPermission();
enforceChangePermission();
return new Messenger(mClientHandler);
}
因此,2.处发送的”CMD_CHANNEL_FULL_CONNECTION”消息,将会交给WifiServiceImpl中的ClientHandler来处理
看下WifiServiceImpl的内部类ClientHandler,ClientHandler#handleMessage方法
public void handleMessage(Message msg) {
....
public void handleMessage(Message msg) {
case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
AsyncChannel ac = new AsyncChannel();
// 这里的msg.replyTo就是上一步的mSrcMessenger
ac.connect(mContext, this, msg.replyTo);
break;
}
}
....
}
此时程序又走了一边AsyncChannel#connect方法
public class AsyncChannel {
....
public void connect(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
// 连接srcHandler(WifiServiceImpl$ClientHandler)和dstMessenger(对应WifiManager$ServiceHandler)
connected(srcContext, srcHandler, dstMessenger);
// 在replyHalfConnected中会发送CMD_CHANNEL_HALF_CONNECTED到ClientHandler处理
replyHalfConnected(STATUS_SUCCESSFUL);
}
只不过此时的mSrcHandle就是ClientHandler自己,mDstMessenger对应处理的Handler是WifiManager中的ServiceHandler,在replyHalfConnected方法中
private void replyHalfConnected(int status) {
Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_HALF_CONNECTED);
msg.arg1 = status;
msg.obj = this;
msg.replyTo = mDstMessenger;
// 创建一个死亡监听,当当前mDstMessenger对应的binder死亡以后,会在DeathMonitor中发送一个"STATUS_REMOTE_DISCONNECTION"消息
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;
}
}
// 发送CMD_CHANNEL_HALF_CONNECTED消息到ClientHandler
mSrcHandler.sendMessage(msg);
}
....
}
所以这次发出的”CMD_CHANNEL_HALF_CONNECTED”消息,交给了WifiServiceImpl$ClientHandler处理
public void handleMessage(Message msg) {
switch (msg.what) {
case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
// 在WifiTrafficPoller中将当前客户端的所有Messenger(和WifiManager$ServiceHandler相关联的),添加到mClients对应的list集合中
mTrafficPoller.addClient(msg.replyTo);
} else {
Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
}
break;
}
到此为止WifiManager和WifiServiceImpl通过AsyncChannel(实质上是通过messenger和handler)建立的连接就完成了,这里类似于TCP中的三次握手,猜测是确保建立连接万无一失
总结一下:
在WifiManager的init方法中,通过AsyncChannel的connect方法
a. 先发送CMD_CHANNEL_HALF_CONNECTED到自己WifiManager内部类ServiceHandler的处理
b. 在WifiManager内部类ServiceHandler处理CMD_CHANNEL_HALF_CONNECTED消息时候,发送CMD_CHANNEL_FULL_CONNECTION消息,由于上一步在AsyncChannel#connect方法中的初始化,这里会交给WifiServiceImpl内部类ClientHandler处理在WifiServiceImpl内部类ClientHandler处理”CMD_CHANNEL_FULL_CONNECTION”消息
会再次建立连接,只不过此时的mSrcHandle就是ClientHandler自己,mDstMessenger对应处理的Handler是WifiManager中的ServiceHandler,最终会在Service服务端的WifiTrafficPoller中将当前和客户端建立的所有Messenger(和WifiManager内部类ServiceHandler相关联的),添加到mClients对应的list集合中
如下图:
连接流程
WifiManager#connect
public void connect(WifiConfiguration config, ActionListener listener) {
if (config == null) throw new IllegalArgumentException("config cannot be null");
validateChannel();
sAsyncChannel.sendMessage(CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID,
putListener(listener), config);
}
这里通过sAsyncChannel发送了一个”CONNECT_NETWORK”消息到WifiServiceImpl服务端处理,在WifiServiceImpl$ClientHandler中对于CONNECT_NETWORK消息进一步交给WifiStateMachine处理
class ConnectModeState extends State {
public boolean processMessage(Message message) {
case WifiManager.CONNECT_NETWORK:
/**
* The connect message can contain a network id passed as arg1 on message or
* or a config passed as obj on message.
* For a new network, a config is passed to create and connect.
* For an existing network, a network id is passed
*/
netId = message.arg1;
config = (WifiConfiguration) message.obj;
mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
boolean updatedExisting = false;
/* Save the network config */
if (config != null) {
// When connecting to an access point, WifiStateMachine wants to update the
// relevant config with administrative data. This update should not be
// considered a 'real' update, therefore lockdown by Device Owner must be
// disregarded.
if (!recordUidIfAuthorized(config, message.sendingUid,
/* onlyAnnotate */ true)) {
replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
WifiManager.NOT_AUTHORIZED);
break;
}
String configKey = config.configKey(true /* allowCached */);
WifiConfiguration savedConfig =
mWifiConfigStore.getWifiConfiguration(configKey);
if (savedConfig != null) {
config = savedConfig;
logd("CONNECT_NETWORK updating existing config with id=" +
config.networkId + " configKey=" + configKey);
config.ephemeral = false;
config.autoJoinStatus = WifiConfiguration.AUTO_JOIN_ENABLED;
updatedExisting = true;
}
// 1.保存当前网络
result = mWifiConfigStore.saveNetwork(config, message.sendingUid);
netId = result.getNetworkId();
}
config = mWifiConfigStore.getWifiConfiguration(netId);
if (config == null) {
logd("CONNECT_NETWORK no config for id=" + Integer.toString(netId) + " "
+ mSupplicantStateTracker.getSupplicantStateName() + " my state "
+ getCurrentState().getName());
replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
WifiManager.ERROR);
break;
} else {
String wasSkipped = config.autoJoinBailedDueToLowRssi ? " skipped" : "";
}
autoRoamSetBSSID(netId, "any");
if (message.sendingUid == Process.WIFI_UID
|| message.sendingUid == Process.SYSTEM_UID) {
clearConfigBSSID(config, "CONNECT_NETWORK");
}
if (deferForUserInput(message, netId, true)) {
break;
} else if (mWifiConfigStore.getWifiConfiguration(netId).userApproved ==
WifiConfiguration.USER_BANNED) {
replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
WifiManager.NOT_AUTHORIZED);
break;
}
mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE;
boolean persist =
mWifiConfigStore.checkConfigOverridePermission(message.sendingUid);
mWifiAutoJoinController.updateConfigurationHistory(netId, true, persist);
mWifiConfigStore.setLastSelectedConfiguration(netId);
didDisconnect = false;
if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID
&& mLastNetworkId != netId) {
/** Supplicant will ignore the reconnect if we are currently associated,
* hence trigger a disconnect
*/
didDisconnect = true;
mWifiNative.disconnect();
}
// Make sure the network is enabled, since supplicant will not reenable it
mWifiConfigStore.enableNetworkWithoutBroadcast(netId, false);
// 2.选择当前网络,通过mWifiNative.reconnect()连接
if (mWifiConfigStore.selectNetwork(config, /* updatePriorities = */ true,
message.sendingUid) && mWifiNative.reconnect()) {
lastConnectAttemptTimestamp = System.currentTimeMillis();
targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId);
/* The state tracker handles enabling networks upon completion/failure */
mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK);
3. 回调回去WifiManager$ServiceHandler处理
replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED);
if (didDisconnect) {
/* Expect a disconnection from the old connection */
transitionTo(mDisconnectingState);
} else if (updatedExisting && getCurrentState() == mConnectedState &&
getCurrentWifiConfiguration().networkId == netId) {
// Update the current set of network capabilities, but stay in the
// current state.
updateCapabilities(config);
} else {
/**
* Directly go to disconnected state where we
* process the connection events from supplicant
**/
transitionTo(mDisconnectedState);
}
} else {
loge("Failed to connect config: " + config + " netId: " + netId);
replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
WifiManager.ERROR);
break;
}
break;
}
}
忘记网络
public void forget(int netId, ActionListener listener) {
if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
validateChannel();
sAsyncChannel.sendMessage(FORGET_NETWORK, netId, putListener(listener));
}
同样的发送消息到WifiServiceImpl服务端,在由WifiServiceImpl发送消息到WifiStateMachine
case WifiManager.FORGET_NETWORK:
// Debug only, remember last configuration that was forgotten
WifiConfiguration toRemove
= mWifiConfigStore.getWifiConfiguration(message.arg1);
if (toRemove == null) {
lastForgetConfigurationAttempt = null;
} else {
lastForgetConfigurationAttempt = new WifiConfiguration(toRemove);
}
// check that the caller owns this network
netId = message.arg1;
if (!mWifiConfigStore.canModifyNetwork(message.sendingUid, netId,
/* onlyAnnotate */ false)) {
logw("Not authorized to forget network "
+ " cnid=" + netId
+ " uid=" + message.sendingUid);
replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
WifiManager.NOT_AUTHORIZED);
break;
}
// 忘记网络
if (mWifiConfigStore.forgetNetwork(message.arg1)) {
replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED);
broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_FORGOT,
(WifiConfiguration) message.obj);
} else {
loge("Failed to forget network");
replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
WifiManager.ERROR);
}
break;
其他的操作都是类似的,算是简单的一个记录,今天就到这里了。