概述
WIFI操作流程源码分析—扫描
在处理该消息的代码中做真正的使能工作:首先装载 WIFI 内核模块(该模块的位置硬编码为
"/system/lib/modules/wlan.ko" ), 然后启动 wpa_supplicant ( 配置文件硬编码为
"/data/misc/wifi/wpa_supplicant.conf") 再通过 WifiStateTracker 来启动 WifiMonitor 中的监视线程。
当使能成功后,会广播发送 WIFI_STATE_CHANGED_ACTION通知外界 WIFI已经成功使能了。
应用一侧扫描
WifiSettings创建的时候就会向 Android 注册接收WIFI_STATE_CHANGED_ACTION,因此它会收到该 Intent,从而开始扫描。
mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
handleEvent(context, intent);
}
};
private void handleEvent(Context context, Intent intent) {
String action = intent.getAction();
if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
updateWifiState(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
WifiManager.WIFI_STATE_UNKNOWN));
} else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action) ||
WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION.equals(action) ||
WifiManager.LINK_CONFIGURATION_CHANGED_ACTION.equals(action)) {
……
}
}
private void updateWifiState(int state) {
Activity activity = getActivity();
if (activity != null) {
activity.invalidateOptionsMenu();
}
switch (state) {
case WifiManager.WIFI_STATE_ENABLED:
mScanner.resume();
/// M: update priority
// if wifi has connectd, not need to updatePriority
WifiInfo mCurrentConnecdInfo = mWifiManager.getConnectionInfo();
if (mCurrentConnecdInfo != null && mCurrentConnecdInfo.getSSID() != null
&& mCurrentConnecdInfo.getSSID().length() > 0) {
mExt.updatePriority();
}
return; // not break, to avoid the call to pause() below
}
mLastInfo = null;
mLastState = null;
mScanner.pause();
}
Scanner是一个内部类,实现如下:
private class Scanner extends Handler {
private int mRetry = 0;
void resume() {
if (!hasMessages(0)) {
sendEmptyMessage(0);//首先发送消息
}
}
@Override
public void handleMessage(Message message) {
if (mWifiManager.startScanActive()) {
mRetry = 0;
} else if (++mRetry >= 3) {
mRetry = 0;
Activity activity = getActivity();
if (activity != null) {
Toast.makeText(activity, R.string.wifi_fail_to_scan,
Toast.LENGTH_LONG).show();
}
return;
}
sendEmptyMessageDelayed(0, WIFI_RESCAN_INTERVAL_MS);
}
}
由WifiManager中函数startScanActive进行处理
public boolean startScanActive() {
try {
mService.startScan(true);
return true;
} catch (RemoteException e) {
return false;
}
}
服务一侧扫描
通过 AIDL,实际调用的是 WifiService 的startScan函数,
public void startScan(boolean forceActive) {
enforceChangePermission();//首先判断是否有权限
mWifiStateMachine.startScan(forceActive);
noteScanStart();
}
WifiStateMachine中函数startScan会发送消息CMD_START_SCAN
public void startScan(boolean forceActive) {
sendMessage(obtainMessage(CMD_START_SCAN, forceActive ?
SCAN_ACTIVE : SCAN_PASSIVE, 0));
}
WifiStateMachine内部类DriverStartedState会处理该消息
class DriverStartedState extends State {
@Override
public boolean processMessage(Message message) {
case CMD_START_SCAN:
boolean forceActive = (message.arg1 == SCAN_ACTIVE);
if (forceActive && !mSetScanActive) {
mWifiNative.setScanMode(forceActive);
}
mWifiNative.scan();
if (forceActive && !mSetScanActive) {
mWifiNative.setScanMode(mSetScanActive);
}
mScanResultIsPending = true;
break;
}
}
WifiNative.java中函数如下:
public boolean scan() {
return doBooleanCommand("SCAN");
}
private boolean doBooleanCommand(String command) {
if (DBG) Log.d(mTAG, "doBoolean: " + command);
return doBooleanCommand(mInterface, command);
}
底层扫描
通过JNI进入函数android_net_wifi_doBooleanCommand,在android_net_wifi_Wifi.cpp
static jboolean android_net_wifi_doBooleanCommand(JNIEnv* env, jobject, jstring jIface,
jstring jCommand)
{
ScopedUtfChars ifname(env, jIface);
ScopedUtfChars command(env, jCommand);
if (command.c_str() == NULL) {
return JNI_FALSE;
}
if (DBG) ALOGD("doBoolean: %s", command.c_str());
return doBooleanCommand(ifname.c_str(), "OK", "%s", command.c_str());
}
static jboolean doBooleanCommand(const char *ifname, const char* expect, const char* fmt, ...)
{
char buf[BUF_SIZE] = {0};
va_list args;
va_start(args, fmt);
int byteCount = vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
if (byteCount < 0 || byteCount >= BUF_SIZE) {
return JNI_FALSE;
}
char reply[BUF_SIZE] = {0};
if (doCommand(ifname, buf, reply, sizeof(reply)) != 0) {
return JNI_FALSE;
}
return (strcmp(reply, expect) == 0);
}
static int doCommand(const char *cmd, char *replybuf, int replybuflen)
{
size_t reply_len = replybuflen - 1;
if (::wifi_command(cmd, replybuf, &reply_len) != 0)
return -1;
else {
// Strip off trailing newline
if (reply_len > 0 && replybuf[reply_len-1] == 'n')
replybuf[reply_len-1] = '