|
先要 弄清楚以下幾點:
一、 Android顯示的WiFi名字,計算機都是以二進制處理的數(shù)據(jù)的,所以接受到的這個名字一定是一個二進制數(shù)據(jù),它是怎么變成字符串的呢?
在frameworks/base/wifi/java/android/net/wifi/WifiSsid.java中
@Override
public String toString() {
byte[] ssidBytes = octets.toByteArray();
// Supplicant returns \x00\x00\x00\x00\x00\x00\x00\x00 hex string
// for a hidden access point. Make sure we maintain the previous
// behavior of returning empty string for this case.
if (octets.size() <= 0 || isArrayAllZeroes(ssidBytes)) return "";
// TODO: Handle conversion to other charsets upon failure
Charset charset = Charset.forName("UTF-8");
CharsetDecoder decoder = charset.newDecoder()
.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE);
CharBuffer out = CharBuffer.allocate(32);
CoderResult result = decoder.decode(ByteBuffer.wrap(ssidBytes), out, true);
out.flip();
if (result.isError()) {
return NONE;
}
return out.toString();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
這段代碼很明顯是用了utf-8規(guī)則解碼了ssidBytes,ssidBytes在這里是一個字節(jié)數(shù)組,也就是Android所收到的WiFi名稱。問題來了,有些路由器的WiFi名稱是GBK編碼的,這里用utf-8編碼很顯然得不到正確的結(jié)果。所以看到的是亂碼,這里就有要兼容GBK編碼的問題。如果這里修改為兼容GBK編碼是不是就可以了,修改后會發(fā)現(xiàn),顯示正常了但是連不上,為什么呢,那就要知道連接過程了。
二、WiFi正真的連接工作是wpa_supplicant完成的。一般在init.xxxx.rc中會看到一個service 如下
service wpa_supplicant /system/bin/wpa_supplicant -iwlan0 -Dnl80211 -c/data/misc/wifi/wpa_supplicant.conf -O/data/misc/wifi/sockets -e/data/misc/wifi/entropy.bin -g@android:wpa_wlan0
class main
user root
group system wifi
socket wpa_wlan0 dgram 660 wifi wifi
disabled
oneshot
這里有一個配置文件wpa_supplicant.conf,Android會把WiFi熱點名稱,密碼等寫入這個文件,wpa_supplicant會通過這個配置文件去獲取WiFi名稱(ssid)和密碼, 然后與掃描到的進行比較,然后找到匹配的熱點然后再連接,比較函數(shù)位于external/wpa_supplicant_8/wpa_supplicant/events.c
static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
int i, struct wpa_bss *bss,
struct wpa_ssid *group,
int only_first_ssid)
{
u8 wpa_ie_len, rsn_ie_len;
int wpa;
struct wpa_blacklist *e;
const u8 *ie;
struct wpa_ssid *ssid;
int osen;
//省略部分代碼
if (check_ssid &&
(bss->ssid_len != ssid->ssid_len ||
os_memcmp(bss->ssid, ssid->ssid, bss->ssid_len) != 0)) {
wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID mismatch");
continue;
}
if (ssid->bssid_set &&
os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) {
wpa_dbg(wpa_s, MSG_DEBUG, " skip - BSSID mismatch");
continue;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
在上面可以看到比較了ssid,問題就在這里這里比較是通不過的,因為配置文件中的ssid是utf-8編碼的,而掃描到的是GBK編碼,而且這里你也不能強制讓他通過,因為在wpa_supplicant不僅僅是這里用到了配置文件中的ssid。那怎么辦,你肯定會想到是誰用utf-8把ssid保存到配置文件里的。
三、誰保存的這個ssid和密碼
在frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiConfigStore.java中
private String encodeSSID(String str){
String tmp = removeDoubleQuotes(str);
return String.format("%x", new BigInteger(1, tmp.getBytes(Charset.forName("UTF-8"))));
}
這里會把String 也就是你看到的WiFi名稱,轉(zhuǎn)換成二進制數(shù)據(jù),這里的二進制數(shù)據(jù)會存入wpa_supplicant.conf,這就是為什么比較通不過的原因了。
解決方法
了解了這個多,現(xiàn)在應該有一個思路了,顯示名稱時需要修改WifiSsid.java中的toString,以兼容GBK,存儲wpa_supplicant.conf,又需要正確的轉(zhuǎn)換成二進制數(shù)。
我的解決方法是在WifiSsid.java中的toString方法中兼容GBK,并且用map存儲string和二進制數(shù)的鍵值對。然后WifiConfigStore.java中的encodeSSID方法用string去這個map中取出二進制數(shù),注意有一種情況map中沒有這個string,map中存儲了所有掃描顯示了的WiFi熱點,還有一種map中沒有就是隱藏了的熱點,如果如果map中沒有,還需要用utf-8或者是GBK轉(zhuǎn)化成二進制。
|