一: Wifi热点后台定时扫描间隔
1.如果在 xml 设置了 "wifi_supplicant_scan_interval_ms" 【Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS】项 那么wifi扫描间 优先取这个值
2.如果是亮屏 使用 config_wifi_supplicant_scan_interval 大约15秒当做间隔
<integer translatable="false" name="config_wifi_supplicant_scan_interval">15000</integer>
3.如果是灭屏 使用 config_wifi_framework_scan_interval 大约5分钟 当做间隔
<integer translatable="false" name="config_wifi_framework_scan_interval">300000</integer>
分析如下:
4.WifiStateMachine.java
public static final String WIFI_SUPPLICANT_SCAN_INTERVAL_MS ="wifi_supplicant_scan_interval_ms"; //wifi扫描间隔设置项
mSupplicantScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(),
Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS,
PowerManager.isScreenOn() ? mContext.getResources().getInteger(R.integer.config_wifi_supplicant_scan_interval)
: mContext.getResources().getInteger(R.integer.config_wifi_framework_scan_interval));
mWifiNative.setScanInterval((int) mSupplicantScanIntervalMs / 1000);
5.SwitchToWifiUtils.java
public void setAlarm() {
int mSupplicantScanIntervalMs = Settings.Global.getLong(
context.getContentResolver(),
Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS,
context.getResources().getInteger(com.android.internal.R.integer.config_wifi_supplicant_scan_interval));
long time = SystemClock.elapsedRealtime()+ (mPowerManager.isScreenOn() ? mSupplicantScanIntervalMs : context.getResources().getInteger(R.integer.config_wifi_framework_scan_interval));
Intent intent = new Intent("com.android.settings.action.START_SCAN_WIFI"); // Wifi扫描的Action
PendingIntent mPendingIntent = PendingIntent.getBroadcast(context,0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager.set(AlarmManager.ELAPSED_REALTIME, time, mPendingIntent); //在AlarMmanager设置在time时间后执行发送mPendingIntent
}
亮屏 灭屏 后台自动扫描的LOG
adb logcat | findstr "CTRL-EVENT-SCAN-STARTED"
09-30 15:57:02.441 1001 27326 D WifiHW : [1] get event: IFNAME=wlan0 <3>CTRL-EVENT-SCAN-STARTED
09-30 15:57:02.441 1001 27326 D WifiHW : [2] get event: IFNAME=wlan0 CTRL-EVENT-SCAN-STARTED
09-30 15:57:02.445 1001 27326 E WifiMonitor: handleEvent unknown: 14 CTRL-EVENT-SCAN-STARTED
09-30 15:57:08.439 1001 27326 D WifiHW : [1] get event: IFNAME=wlan0 <3>CTRL-EVENT-SCAN-STARTED
09-30 15:57:08.439 1001 27326 D WifiHW : [2] get event: IFNAME=wlan0 CTRL-EVENT-SCAN-STARTED
09-30 15:57:08.443 1001 27326 E WifiMonitor: handleEvent unknown: 14 CTRL-EVENT-SCAN-STARTED
【大概6秒】
09-30 15:57:14.470 1001 27326 D WifiHW : [1] get event: IFNAME=wlan0 <3>CTRL-EVENT-SCAN-STARTED
09-30 15:57:14.471 1001 27326 D WifiHW : [2] get event: IFNAME=wlan0 CTRL-EVENT-SCAN-STARTED
09-30 15:57:14.472 1001 27326 E WifiMonitor: handleEvent unknown: 14 CTRL-EVENT-SCAN-STARTED
【大概6秒】
09-30 15:57:20.498 1001 27326 D WifiHW : [1] get event: IFNAME=wlan0 <3>CTRL-EVENT-SCAN-STARTED
09-30 15:57:20.498 1001 27326 D WifiHW : [2] get event: IFNAME=wlan0 CTRL-EVENT-SCAN-STARTED
09-30 15:57:20.504 1001 27326 E WifiMonitor: handleEvent unknown: 14 CTRL-EVENT-SCAN-STARTED
【大概6秒】
09-30 15:57:26.568 1001 27326 D WifiHW : [1] get event: IFNAME=wlan0 <3>CTRL-EVENT-SCAN-STARTED
09-30 15:57:26.568 1001 27326 D WifiHW : [2] get event: IFNAME=wlan0 CTRL-EVENT-SCAN-STARTED
09-30 15:57:26.569 1001 27326 E WifiMonitor: handleEvent unknown: 14 CTRL-EVENT-SCAN-STARTED
【五分钟】
09-30 16:02:22.272 1001 27326 D WifiHW : [1] get event: IFNAME=wlan0 <3>CTRL-EVENT-SCAN-STARTED
09-30 16:02:22.272 1001 27326 D WifiHW : [2] get event: IFNAME=wlan0 CTRL-EVENT-SCAN-STARTED
09-30 16:02:22.275 1001 27326 E WifiMonitor: handleEvent unknown: 14 CTRL-EVENT-SCAN-STARTED
【五分钟】
09-30 16:07:22.267 1001 27326 D WifiHW : [1] get event: IFNAME=wlan0 <3>CTRL-EVENT-SCAN-STARTED
09-30 16:07:22.267 1001 27326 D WifiHW : [2] get event: IFNAME=wlan0 CTRL-EVENT-SCAN-STARTED
09-30 16:07:22.273 1001 27326 E WifiMonitor: handleEvent unknown: 14 CTRL-EVENT-SCAN-STARTED
二: Wif的Mac地址获取流程分析
WIFI的Mac地址获取流程( 未完待续 )
cat /sys/class/net/wlan0/address ##查看mac地址
#1.APP层
WifiManager mWifiManager = (WifiManager) getActivity().getApplicationContext().getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
wifiInfo.getMacAddress();
#2. android.net.WifiInfo.java
public class WifiInfo implements Parcelable {
public static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00";
private String mMacAddress = DEFAULT_MAC_ADDRESS;
public String getMacAddress() {
return mMacAddress;
}
public WifiInfo(WifiInfo source) {
......
mMacAddress = source.mMacAddress;
......
}
public void setMacAddress(String macAddress) {
this.mMacAddress = macAddress;
}
}
#3. frameworks\opt\net\wifi\service\java\com\android\server\wifi\WifiStateMachine.java
public class WifiStateMachine {
WifiInfo mWifiInfo;
WifiNative mWifiNative;
public WifiStateMachine(Context context, String wlanInterface,WifiTrafficPoller trafficPoller) {
mWifiNative = new WifiNative(mInterfaceName);
mWifiInfo = new WifiInfo();
mWifiInfo.setMacAddress(mWifiNative.getMacAddress());
}
}
#4. frameworks\opt\net\wifi\service\java\com\android\server\wifi\WifiNative.java
// 调用本地的 doStringCommand 方法得到一个字符串 "MACADDR=XX.XX.XX.XX.XX.XX" 然后分割返回 XX.XX.XX.XX.XX.XX
public String getMacAddress() {
//Macaddr = XX.XX.XX.XX.XX.XX
String ret = doStringCommand("DRIVER MACADDR");
if (!TextUtils.isEmpty(ret)) {
String[] tokens = ret.split(" = ");
if (tokens.length == 2) return tokens[1];
}
return null;
}
private static int sCmdId; // 一个用于标记发送命令的标志 每次发送自增
private static int getNewCmdIdLocked() {
return sCmdId++;
}
interfaceName = "wlan0";
mInterfacePrefix ="IFNAME=" + interfaceName + " ";
private String doStringCommand(String command) {
synchronized (mLock) {
int cmdId = getNewCmdIdLocked();
String toLog = Integer.toString(cmdId) + ":" + mInterfacePrefix + command; //类似于 88:IFNAME=wlan0 DRIVER MACADDR
//调用本地 doStringCommandNative方法(Java层的JNI方法) 方法传入 IFNAME=wlan0 DRIVER MACADDR
String result = doStringCommandNative(mInterfacePrefix + command);
if (result == null) {
if (DBG) Log.d(mTAG, "doStringCommandNative no result");
} else {
if (!command.startsWith("STATUS-")) {
localLog(toLog + " -> " + result);
}
}
return result;
}
}
private native String doStringCommandNative(String command); //JNI方法调用到 com_android_server_wifi_WifiNative.cpp JNI文件
#4.frameworks\opt\net\wifi\service\jni\com_android_server_wifi_WifiNative.cpp 包含 Wifi.h Wifi.cpp 的引用
// 找到对应的 C方法 android_net_wifi_doStringCommand
{"doStringCommandNative", "(Ljava/lang/String;)Ljava/lang/String;",(void*) android_net_wifi_doStringCommand }
static jstring android_net_wifi_doStringCommand(JNIEnv* env, jobject, jstring javaCommand) {
return doStringCommand(env,javaCommand);
}
#define REPLY_BUF_SIZE 4096
static jstring doStringCommand(JNIEnv* env, jstring javaCommand) {
char reply[REPLY_BUF_SIZE]= {0}; // 4096个字节的字符串
if (!doCommand(env, javaCommand, reply, sizeof(reply))) { //调用本地 doCommand 方法 reply是C语言的字符数组
return NULL;
}
return env->NewStringUTF(reply); // 把reply是C语言的字符数组 转为JAVA 可识别的字符 返回
}
static bool doCommand(JNIEnv* env, jstring javaCommand,char* reply, size_t reply_len) {
ScopedUtfChars command(env, javaCommand); // 把 jstring 转为 C语言能识别处理的字符串
if (command.c_str() == NULL) {
return false; // ScopedUtfChars already threw on error.
}
--reply_len; // 保留最后的字节 用来填充 "\0" 字符串结束标志
if (::wifi_command(command.c_str(), reply, &reply_len) != 0) { // 调用 wifi_command 方法
return false;
}
if (reply_len > 0 && reply[reply_len-1] == '\n') {
reply[reply_len-1] = '\0';
} else {
reply[reply_len] = '\0';
}
return true;
}
#5.Wifi.h (hardware\libhardware_legacy\include\hardware_legacy)
int wifi_command(const char *command, char *reply, size_t *reply_len); //在Wifi.h 声明了 wifi_command 函数
Wifi.c
static struct wpa_ctrl *ctrl_conn;【ctrl_conn = wpa_ctrl_open(path); 用于通信连接的信息结构体】
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
{
struct wpa_ctrl *ctrl;
DWORD mode;
TCHAR name[256];
int i, ret;
ctrl = os_malloc(sizeof(*ctrl));
if (ctrl == NULL) return NULL;
os_memset(ctrl, 0, sizeof(*ctrl));
if (os_snprintf_error(256, ret)) {
os_free(ctrl);
return NULL;
}
for (i = 0; i < 10; i++) {
ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0,NULL, OPEN_EXISTING, 0, NULL); // ctrl->pipe创建 管道
if (ctrl->pipe != INVALID_HANDLE_VALUE ||GetLastError() != ERROR_PIPE_BUSY) break;
WaitNamedPipe(name, 1000);
}
if (ctrl->pipe == INVALID_HANDLE_VALUE) {
os_free(ctrl);
return NULL;
}
mode = PIPE_READMODE_MESSAGE;
if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) {
CloseHandle(ctrl->pipe);
os_free(ctrl);
return NULL;
}
return ctrl;
}
int wifi_command(const char *command, char *reply, size_t *reply_len)
{
return wifi_send_command(command, reply, reply_len); // 调用本地的 wifi_send_command 函数
}
int wifi_send_command(const char *cmd, char *reply, size_t *reply_len)
{
int ret;
if (ctrl_conn == NULL) {
ALOGV("Not connected to wpa_supplicant - \"%s\" command dropped.\n", cmd);
return -1;
}
// 调用 wpa_ctrl_request函数 ctrl_conn已经完成初始化 , 并完成对 OUT参数 char *reply的赋值
ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), reply, reply_len, NULL);
if (ret == -2) {
ALOGD("'%s' command timed out.\n", cmd);
TEMP_FAILURE_RETRY(write(exit_sockets[0], "T", 1));
return -2;
} else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) {
return -1;
}
if (strncmp(cmd, "PING", 4) == 0) {
reply[*reply_len] = '\0';
}
return 0;
}
//完成数据的请求? 正常处理返回0 出现异常返回-1
int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,char *reply, size_t *reply_len, void (*msg_cb)(char *msg, size_t len))
{
DWORD written;
DWORD readlen = *reply_len;
if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL)) // 往 ctrl->pipe 管道( 文件 ) 写数据? 写入 【IFNAME=wlan0 DRIVER MACADDR】
return -1;
if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL)) // 从ctrl->pipe管道( 文件 ) 读取数据? reply在ReadFile完成赋值
return -1;
*reply_len = readlen;
return 0;
}
WriteFile 用于往ctrl->pipe管道 写数据
bool WriteFile(HANDLE hFile, LPCVOID buffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, void* dummyforAPI)
{
int written_len = 0;
//usleep(3000);
fd_set writefd;
struct timeval timeout;
//Ruoyao: timeout from 500ms to 5s
//timeout.tv_sec = 0;
//timeout.tv_usec = 500000;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
bool is_written = false;
while(!is_written)
{
FD_ZERO(&writefd);
FD_SET(hFile, &writefd);
if( select(hFile+1, NULL , &writefd, NULL, &timeout) > 0)
{
int ifd;
for(ifd=0; ifd < hFile+1; ifd++)
{
if (FD_ISSET(ifd, &writefd))
{
if(ifd == hFile)
{
// buffer就是 【IFNAME=wlan0 DRIVER MACADDR】通过把该字符串写入到 管道 使得驱动得到命令?
written_len = write(hFile, buffer, nNumberOfBytesToWrite);
is_written = true;
}
}
}
}
else
{
//log_linux_errno("WriteFile.select()");
break;
}
}
if(written_len >= 0)
{
if(lpNumberOfBytesWritten != NULL)
{
*lpNumberOfBytesWritten = written_len;
}
return true;
}
else
{
//log_linux_errno("WriteFile.write()");
if(lpNumberOfBytesWritten != NULL)
{
*lpNumberOfBytesWritten = 0;
}
return false;
}
}
ReadFile 用于往ctrl->pipe管道 读取数据
bool ReadFile(HANDLE hFile, LPVOID buffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, void* dummyforAPI)
{
int read_len = 0;
//usleep(3000);
fd_set readfd;
struct timeval timeout;
//Ruoyao: timeout from 500ms to 5s
//timeout.tv_sec = 0;
//timeout.tv_usec = 50000; //50ms
timeout.tv_sec = 5;
timeout.tv_usec = 0;
bool is_read = false;
while(!is_read)
{
FD_ZERO(&readfd);
FD_SET(hFile, &readfd);
if( select(hFile+1, &readfd , NULL, NULL, &timeout) > 0)
{
int ifd;
for(ifd=0; ifd < hFile+1; ifd++)
{
if (FD_ISSET(ifd, &readfd))
{
if(ifd == hFile)
{
// buffer就是cahr* reply 就是需要返回到的数据 通过读取 管道 得到数据
read_len = read(hFile, buffer, nNumberOfBytesToRead);
is_read = true;
}
}
}
}
else
{
//log_linux_errno("ReadFile.select()");
break;
}
}
if(read_len >= 0)
{
if(lpNumberOfBytesRead != NULL)
{
*lpNumberOfBytesRead = read_len;
}
return true;
}
else
{
//log_linux_errno("ReadFile.read()");
if(lpNumberOfBytesRead != NULL)
{
*lpNumberOfBytesRead = 0;
}
return false;
}
}
## hFile 文件对应的驱动 怎么实现 还需要跟踪( 未完待续 )