目錄
想象這樣一個場景:你的手機通過某種方式連接上了一個wifi,有時你無法把連接上的wifi密碼告訴別人,所以你決定用手機開個熱點給別人使用。如果你運氣好,你手機能同時打開wifi和ap,如果運氣不好,打開熱點的時候,wifi就斷開了。那麼Android 到底能不能同時支持wifi和ap同時打開呢?
Android原生不支持Wifi和AP同時打開
Android原生是不支持開Wifi的同時,打開AP供其他設備連接的。目前市場上有部分手機支持兩者同時打開使用了,比如小米8 。 如果我們想實現Wifi共存的功能要怎麼處理呢?
(首先當然是你的wifi芯片得支持此功能,接着你得把驅動調好。本人不搞驅動,這塊不瞭解。這裏不多說)
Android原生爲什麼不支持同時打開wifI和AP? 讓我們先看下打開AP的流程,可參考https://blog.csdn.net/sinat_20059415/article/details/82556109,主要是要熟悉一下Wifi狀態機這塊。
Android對同時開Wifi和AP的限制地方
下面從應用到底層說明下Wifi和ap不能同時打開的限制地方。
1、設置:
在WifiEnabler.java 中打開wifi時,會做下面的判斷去關閉熱點。
if (mayDisableTethering(isChecked)) {
mConnectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
}
2、framework
如果你已經把之前的鏈接大致看了一遍,這裏會好理解些。核心在這裏,在WifiController.java 和WifiStateMachine.java 中有一些XXXState(比如DefaultState)是表示Wifi當前所處狀態的,但是google原生把wifi和熱點設置成了2種互斥的狀態,即不能同時處於wifi和熱點打開的狀態。我們要做的就是想辦法把wifi和ap的狀態給分隔開。
比如對於WifiController.java你可以用一個WifiStaController 和WifiApController分別去表示wifi和熱點的狀態。然後把使用到WifiController的地方根據其是wifi還是熱點,分別使用WifiStaController和WifiApController去代替。
在WifiStateMachine中AP狀態只有一種,即SoftApState。進入到SoftApState後,熱點的狀態具體是由SoftApManager.java 中的SoftApStateMachine進行管理的,這裏只有IdleState和StartedState兩種狀態。這裏倒沒什麼要改的。
3.Fwk與HAL層的代理
在設置Wifi或AP的過程中,都是通過WifiVendorHal,HalDeviceManager去操作底層芯片啥的。這兩個文件中也有些地方對2種狀態做了互斥處理,我們也需要放開。這個部分的核心是爲了給wifi或ap獲取對應的interface接口。
4.HAL層部分
在hardware\interfaces\wifi\1.1\default\wifi_chip.cpp 中的createApIfaceInternal和handleChipConfiguration函數中也有些互斥。hardware\interfaces\wifi\1.1\default\wifi_legacy_hal.cpp中的start函數處的CHECK 我本地調試時不去掉會執行出錯,這個應該是檢查芯片配置啥的。
可能遇到的問題
至此wifi和AP不能同時打開的互斥條件就算處理完了。如果你運氣不好,你可能遇到了下面這些問題:
- 把驅動修改爲共存模式後,設置中wifi掃描不到wifi,但命令可以掃描到。
- 用ifconfig 查看時,wlan0 和ap0處於同一個網段下192.168.43.1(如果你連接的是路由器,說不定不會遇到此問題),然後同時開了wifi和ap後連接上了wifi,但上不了網。
- 有時你設置的ap 用其他手機搜索不到。
關於問題一:
應該是掃描命令下發到ap0去了,所有在fwk層獲取interface時,需要把interface_name作爲參數傳下去,以便獲取到正確的interface,這個應該算google原生的一個bug。
https://github.com/FredProject/platform_system_connectivity_wificond/commit/47443838f760908b9a6571aed4f4fa4e93ad37bc 這兩個 patch 合進去試試。
關於問題二:
android源碼中默認的wifi共享的網段就是192.168.43.
你可以試着修改frameworks\base\services\core\java\com\android\server\connectivity\tethering\TetheringConfiguration.java 中DHCP_DEFAULT_RANGE的192.168.43.X 改爲其他的。
frameworks\base\services\core\java\com\android\server\connectivity\tethering\TetherInterfaceStateMachine.java 中的WIFI_HOST_IFACE_ADDR 也改掉。
關於問題三:
可搜下kernel log, 是否有類似
[wlan][273]p2pRoleFsmRunEventStartAP:(P2P INFO) p2pRoleFsmRunEventStartAP: start AP at CH 14 NSS=2.
這種log,上面的Channel是14.
在frameworks\base\wifi\java\android\net\wifi\WifiConfiguration.java 中的apChannel 中默認是0。 0代表會自動選擇一個可用的信道,但是國內只支持1~11 信道,因此它自動選擇的信道可能在國內用不了。(我覺得這個問題芯片廠商應該要做個控制能設置自由選擇的信道的範圍的,可惜了有時廠商不給力。。。。)
至此,我想應該就改好了。如果你走到了這一步,你會發現,你弄了應用到fwk到HAL層,就差驅動沒有涉獵了。你說你牛不牛B,值不值得吹噓一波。你說這篇文章值不值得點贊收藏加關注!
然而另一方面你會發現,網絡通信的核心其實你沒搞。出了任何問題,你依然提心吊膽,就問你怕不怕。。。
附:
修改默認AP名:frameworks\opt\net\wifi\service\java\com\android\server\wifi\WifiApConfigStore.java 中的getDefaultApConfiguration
設置AP默認不自動關閉:在packages\apps\SettingsProvider\src\com\android\providers\settings\DatabaseHelper.java 中的 loadSystemSettings 函數裏面添加 loadSetting(stmt, "wifi_hotspot_auto_disable", 0);