Android 11 WiFi开启流程
從剛接觸WiFi時跟過wifi的開啟流程,當時還是android9。到了Android11代碼架構有了不小的改動,在這里重新梳理一遍,便于在工作中更快速的跟蹤代碼。
一、Settings里改動不大,還是從WifiEnabler開始,調用WiFiManager的setWifiEnabled。
packages/apps/Settings/src/com/android/settings/wifi/WifiEnabler.java
二、這里要注意了,Android11默認加入了支持雙WiFi的代碼。這里打開WiFi就提供了倆個接口
frameworks/base/wifi/java/android/net/wifi/WifiManager.java
正常打開WiFi是調用這個單參的函數。
如果是指定打開哪個STA,就要調用雙參的函數。
public boolean setWifiEnabled(int staId, boolean enabled) {try {return mService.setWifiEnabled2(mContext.getOpPackageName(), staId, enabled);} catch (RemoteException e) {throw e.rethrowFromSystemServer();} }三、可以看到Wifimanager中正常打開WiFi和指定打開哪個STA的區別就是在WifiServiceImpl中setWifiEnabled2的參數不同。如果是打開第一個WiFi,則參數2為STA_PRIMARY,如果是打開其他WiFi,則參數2為傳入的staId。
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java
四、可以看到wifiservice調用了ActiveModeWarden的wifiToggled,發送了CMD_WIFI_TOGGLED的消息,通知WiFi切換了。
frameworks/opt/net/wifi/service/java/com/android/server/wifi/ActiveModeWarden.java
五、我們看WifiController是怎么處理這個消息的。WifiController是ActiveModeWarden中的一個狀態機,用來管理WiFi的操作,包括熱點啊飛行模式什么的。
打開WiFi之前,狀態機應該是在Disabled狀態,我們看Disable狀態里的處理。
啟動一個新的客戶端管理。
private boolean startClientModeManager() {Log.d(TAG, "Starting ClientModeManager");ClientListener listener = new ClientListener();ClientModeManager manager = mWifiInjector.makeClientModeManager(listener);listener.setActiveModeManager(manager);manager.start();if (!switchClientModeManagerRole(manager)) {return false;}mActiveModeManagers.add(manager);return true; }六、start了ClientModeManager
frameworks/opt/net/wifi/service/java/com/android/server/wifi/ClientModeManager.java
看一下是誰處理了這個START消息呢
private class IdleState extends State {@Overridepublic boolean processMessage(Message message) {switch (message.what) {case CMD_START:// Always start in scan mode first.mClientInterfaceName =mWifiNative.setupInterfaceForClientInScanMode(mWifiNativeInterfaceCallback);if (TextUtils.isEmpty(mClientInterfaceName)) {Log.e(TAG, "Failed to create ClientInterface. Sit in Idle");mModeListener.onStartFailure();break;}transitionTo(mScanOnlyModeState);break;} }七、這里可以看出,WifiNative先去啟動HAL
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java
八、啟動HAL
WifiVendorHal.java-->startVendorHal --> HalDeviceManager.java --> startWifi --> IWifi.startmWifi.start()方法是啟動實際加載WiFi動作的調用,這里涉及HIDL機制調用。通過獲取IWifi接口對象,調用其方法。這里IWifi接口對象是IWifi.hal文件中實現。
android/hardware/interfaces/wifi/1.0/IWifi.hal在編譯時,編譯器會將IWifi.hal解析為IWifi.java文件,直接看該文件中的start方法實現即可。
android/out/soong//.intermediates/hardware/interfaces/wifi/1.0/android.hardware.wifi-V1.0-java_gen_java/gen/srcs/android/hardware/wifi/V1_0/IWifi.javapublic android.hardware.wifi.V1_0.WifiStatus start() throws android.os.RemoteException {try {... ... ... ...mRemote.transact(3 /* start */, _hidl_request, _hidl_reply, 0 /* flags */);_hidl_reply.verifySuccess();_hidl_request.releaseTemporaryStorage();return _hidl_out_status;} finally {_hidl_reply.release();}}通過binder調用,將調用到wifi.cpp中的start()方法.
android/hardware/interfaces/wifi/1.4/default/wifi.cppReturn<void> Wifi::start(start_cb hidl_status_cb) {return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,&Wifi::startInternal, hidl_status_cb);}wifi.cpp->start() ==> wifi.cpp->startInternal() ==> wifi.cpp->initializeModeControllerAndLegacyHal()==> WifiModeController->initialize() ==> DriverTool->LoadDriver()通過調用DriverTool->LoadDriver將返回到Android framework中。下面是LoadDriver()的實現。
android/frameworks/opt/net/wifi/libwifi_hal/include/wifi_hal/driver_tool.cppbool DriverTool::LoadDriver() {return ::wifi_load_driver() == 0;}在wifi_load_driver()方法中,將調用系統接口加載WiFi驅動ko。關于系統insmod接口的調用,本文不做分析。到這里,已梳理完在WifiNative類中調用的startHal()方法。
android/frameworks/opt/net/wifi/libwifi_hal/wifi_hal_common.cppint wifi_load_driver() {... ... ... ...insmod(file,args);... ... ... ...}調用WifiNl80211Manager類的setupInterfaceForClientMode()方法。
該類的主要對WiFi 80211nl管理接口的封裝,接口在WiFicond守護進程中呈現給WiFi框架。該類提供的接口僅使用與WiFi框架,訪問權限受selinux權限保護。
setupInterfaceForClientMode()方法主要為Station模式設置接口。
android/frameworks/base/wifi/java/android/net/wifi/nl80211/WifiNl80211Manager.javapublic boolean setupInterfaceForClientMode(@NonNull String ifaceName,@NonNull @CallbackExecutor Executor executor,@NonNull ScanEventCallback scanCallback, @NonNull ScanEventCallback pnoScanCallback) {... ... ... ...// Refresh HandlersmClientInterfaces.put(ifaceName, clientInterface);try {IWifiScannerImpl wificondScanner = clientInterface.getWifiScannerImpl();mWificondScanners.put(ifaceName, wificondScanner);Binder.allowBlocking(wificondScanner.asBinder());ScanEventHandler scanEventHandler = new ScanEventHandler(executor, scanCallback);mScanEventHandlers.put(ifaceName, scanEventHandler);wificondScanner.subscribeScanEvents(scanEventHandler);PnoScanEventHandler pnoScanEventHandler = new PnoScanEventHandler(executor,pnoScanCallback);mPnoScanEventHandlers.put(ifaceName, pnoScanEventHandler);wificondScanner.subscribePnoScanEvents(pnoScanEventHandler);... ... ... ...}到這里,ClientModeStateMachine狀態機在IdleState狀態成功處理完了CMD_START消息。狀態機將轉到“mScanOnlyModeState”狀態,將會執行以下調用流程(具體原因可查看狀態機機制)。
IdleState.exit()->StartedState.enter()->StartedState.exit()->ScanOnlyModeState.enter()。九、啟動HAL以后,就要啟動supplicant了。
在第五步的時候我們調用了ActiveModeWarden.java的startClientModeManagerh函數。start以后會執行switchClientModeManagerRole
十、從上一步可以看出setRole的參數為ROLE_CLIENT_SCAN_ONLY,所以這里發送的是CMD_SWITCH_TO_CONNECT_MODE廣播
frameworks/opt/net/wifi/service/java/com/android/server/wifi/ClientModeManager.java
十一、看一下CMD_SWITCH_TO_CONNECT_MODE的處理,這里先執行了switchClientInterfaceToConnectivityMode
private class StartedState extends State {public boolean processMessage(Message message) {switch(message.what) {case CMD_SWITCH_TO_CONNECT_MODE:mRole = message.arg1; // could be any one of possible connect mode roles.updateConnectModeState(WifiManager.WIFI_STATE_ENABLING,WifiManager.WIFI_STATE_DISABLED);if (!mWifiNative.switchClientInterfaceToConnectivityMode(mClientInterfaceName)) {updateConnectModeState(WifiManager.WIFI_STATE_UNKNOWN,WifiManager.WIFI_STATE_ENABLING);updateConnectModeState(WifiManager.WIFI_STATE_DISABLED,WifiManager.WIFI_STATE_UNKNOWN);mModeListener.onStartFailure();break;}transitionTo(mConnectModeState);break;十二、可以看到這里啟動了supplicant
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java
在這里等待與supplicant建立連接
private boolean startAndWaitForSupplicantConnection() {// Start initialization if not already started.if (!mSupplicantStaIfaceHal.isInitializationStarted()&& !mSupplicantStaIfaceHal.initialize()) {return false;}if (!mSupplicantStaIfaceHal.startDaemon()) {Log.e(TAG, "Failed to startup supplicant");return false;}boolean connected = false;int connectTries = 0;while (!connected && connectTries++ < CONNECT_TO_SUPPLICANT_RETRY_TIMES) {// Check if the initialization is complete.connected = mSupplicantStaIfaceHal.isInitializationComplete();if (connected) {break;}try {Thread.sleep(CONNECT_TO_SUPPLICANT_RETRY_INTERVAL_MS);} catch (InterruptedException ignore) {}}return connected; }十三、這里是通過HIDL來打開supplicant的
frameworks/opt/net/wifi/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java
十四、 在這個方法中將觸發啟動wpa_supplicant進程,這里需要注意,在manifest.xml中對其需要進行配置,運行時會將服務名稱注冊到hwservicemanager中。
wpa_supplicant目錄下文件調用:
main.c ==> wpa_supplicant.c->wpa_supplicant_init() ==> notify.c->wpas_notify_supplicant_initialized() ==> hidl.cpp->wpas_hidl_init() ==> Hidl_manager.cpp->registerHidlService() int HidlManager::registerHidlService(struct wpa_global *global){// Create the main hidl service object and register it.supplicant_object_ = new Supplicant(global);if (supplicant_object_->registerAsService("wpa_supplicant") != android::NO_ERROR) {return 1;}return 0;}十五、將wpa_supplicant添加注冊到hwservicemanager,SupplicantStaIfaceHal.getSupplicantMockable()執行完成返回。
這里再深入看下“supplicant_object_->registerAsService(“wpa_supplicant”)”是如何通過調用注冊的呢?
android/out/soong/.intermediates/hardware/interfaces/wifi/supplicant/1.3/android.hardware.wifi.supplicant@1.3_genc++/gen/android/hardware/wifi/supplicant/1.3/SupplicantAll.cppandroid/system/libhidl/transport/ServiceManagement.cppandroid/system/hwservicemanager/ServiceManager.cpp supplicant_object_->registerAsService("wpa_supplicant") ==> ISupplicant.hal ==> ISupplicantAll.cpp->registerAsService() ==> ::android::hardware::details::registerAsServiceInternal(this, serviceName) ==> ServiceManagement.cpp->registerAsServiceInternal() ==> ServiceManager->addWithChain()==> ServiceManager->addImpl()十六、wpa_supplicant注冊完成后,SupplicantStaIfaceHal類中將收到回調通知信息,
private final IServiceNotification mServiceNotificationCallback = new IServiceNotification.Stub() { public void onRegistration(String fqName, String name, boolean preexisting) { synchronized (mLock) { if (!initSupplicantService()) { supplicantServiceDiedHandler(mDeathRecipientCookie); }返回通知的調用邏輯。
SupplicantStaIfaceHal.initSupplicantService() -> SupplicantStaIfaceHal.getSupplicantMockable()十七、到此位置supplicant已經啟動。
switchClientInterfaceToConnectivityMode會繼續調用SupplicantStaIfaceHal.setupIface()方法設置接口。設置成功后,就會打印成功的日志。
十八、CMD_SWITCH_TO_CONNECT_MODE消息處理完以后狀態機就會切換到ConnectModeState。
這里會調用setOperationalMode
十九、這里會進入到mDisconnectedState
frameworks/opt/net/wifi/service/java/com/android/server/wifi/ClientModeImpl.java
二十、ActiveModeWarden類中設置的ClientLister將被觸發回調。 wifiScaner.setScanningEnabled()發送消息CMD_ENABLE,給到WiFiscanningSerivceimpl類中。
到這里,WiFi已處于打開狀態,并將進行掃描網絡,待連接。WiFi打開流程分析完成。
總結
以上是生活随笔為你收集整理的Android 11 WiFi开启流程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: codeblocks错误
- 下一篇: android sina oauth2.