Android WiFi module Analysis

Source: Internet
Author: User
Tags bssid

Disclaimer: This document is purely online data collection, and the copyright is owned by the source author. Please mark it as a reprinted article during reprinting.

Now I have been familiar with the WiFi module of the Android platform for a while. Now I will make some brief summary for future reference and correction.

[WiFi module learning process]

I recently studied the Wi-Fi module and checked a lot of relevant information. However, I found that the analysis is basically based on the Android 2.3 version. Currently, the Android mobile platform developed is basically version, the difference from version 2.0 is also obvious in the WiFi module. In Version 2.3, the Wi-Fi module does not have wifilayer. Previously, wifilayer was mainly responsible for some complex WiFi functions, such as AP selection, to provide custom functions to users, the content in the new version is basically replaced by wifisettings.

This article is based on the WiFi Analysis of android2.3, which is divided into two parts:

(A) WiFi startup process (with code for Reference Analysis)

(B) Analysis of wifi module related files

(C) wpa_supplicant Parsing

[A] basic WiFi running process (for code)

First, I will give you a picture of my going down from the Internet. For versions earlier than 2.3, since they are not very good at drawing these pictures, we will be able to understand them as long as they can.

(1) initialization

A. Process

1. A connectivityservice instance is generated when systemserver is started.

2. The connectivityservice constructor will create wifiservice

3. the supervisor will create a wifimonitor to accept events from the underlying layer. wifiservice and wifimonitor are the core of the entire WiFi module. wifiservice is responsible for starting and disabling wpa_supplicant, starting and disabling wifimonitor monitoring thread and, wifimonitor is responsible for receiving Event Notifications from wpa_supplicant.

B. Code Analysis

To use the WiFi module, you must first enable wifi. When you press the WiFi enable button for the first time, wirelesssettings will instantiate a wifienabler object. The instantiation code is as follows:

Packages/apps/settings/src/COM/Android/settings/wirelesssettings. Java

protected void onCreate(Bundle savedInstanceState) {       super.onCreate(savedInstanceState);……              CheckBoxPreferencewifi = (CheckBoxPreference) findPreference(KEY_TOGGLE_WIFI);              mWifiEnabler= new WifiEnabler(this, wifi);……}

The definition of the wifienabler class is roughly as follows. It implements a listener interface. When the wifienabler object is initialized, It listens to the button action and calls the response function onpreferencechange (), this function calls the setwifienabled () function of wifimanager.

public class WifiEnabler implementsPreference.OnPreferenceChangeListener {……public boolean onPreferenceChange(Preference preference,Object value) {        booleanenable = (Boolean) value;……if (mWifiManager.setWifiEnabled(enable)) {                mCheckBox.setEnabled(false);……}……}

We all know that wifimanager is only a Service proxy, so it will call the setwifienabled () function of wifiservice, and this function will call the sendenablemessage () function to understand the android message processing mechanism, this function will eventually send
Message_enable_wifi messages are processed by the handlermessage () function defined in wifiservice, And the setwifienabledblocking () function is called. The following is the call process:

Mwifienabler. onpreferencechange () ==> mwifimanage. setwifienabled () ==> mwifiservice. setwifienabled () ==> mwifiservice. sendenablemessage ()

==> Mwifiservice. handlemessage () ==> mwifiservice. setwifienabledblocking ().

In the setwifienabledblocking () function, we mainly do the following: load the WiFi driver, start wpa_supplicant, register the broadcast receiver, and start the wifithread listening thread. The Code is as follows:

……if (enable) {           if (!mWifiStateTracker.loadDriver()) {               Slog.e(TAG, "Failed toload Wi-Fi driver.");               setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);                return false;           }           if (!mWifiStateTracker.startSupplicant()) {                mWifiStateTracker.unloadDriver();                Slog.e(TAG, "Failed tostart supplicant daemon.");               setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);                return false;           }            registerForBroadcasts();           mWifiStateTracker.startEventLoop();……

So far, the WiFi enabling (Enabled) has ended and the scanning phase is automatically started.

(2) Scanning AP

After the driver is loaded successfully, if the configuration file's ap_scan = 1, the scan starts automatically. wifimonitor will receive a message event_driver_state_changed from supplicant, call handledriverevent (), and then call mwifistatetracker. notifydriverstarted (), which adds event_driver_state_changed to the Message Queue. The handlermessage () function calls the scan () function when processing the message, and sends the scan command to wpa_supplicant through wifinative.

View code frameworks/base/WiFi/Java/Android/NET/WiFi/wifimonitor. Java

private void handleDriverEvent(Stringstate) {           if (state == null) {                return;           }           if (state.equals("STOPPED")) {               mWifiStateTracker.notifyDriverStopped();           } else if (state.equals("STARTED")) {                mWifiStateTracker.notifyDriverStarted();           } else if (state.equals("HANGED")) {                mWifiStateTracker.notifyDriverHung();           }}

Frameworks/base/WiFi/Java/Android/NET/WiFi/wifistatetracker. Java

...case EVENT_DRIVER_STATE_CHANGED:                switch(msg.arg1) {                case DRIVER_STARTED:                    /**                     *Set the number of allowed radio channels according                     *to the system setting, since it gets reset by the                     *driver upon changing to the STARTED state.                     */                    setNumAllowedChannels();                   synchronized (this) {                       if (mRunState == RUN_STATE_STARTING) {                           mRunState = RUN_STATE_RUNNING;                           if (!mIsScanOnly) {                                reconnectCommand();                           } else {                                // In somesituations, supplicant needs to be kickstarted to                                // start thebackground scanning                                scan(true);                           }                       }                    }                   break;             ...

The above is the AP scanning automatically when WiFi is started. You can also manually scan the AP. This part is implemented in wifiservice, where wifiservice uses startscan () the interface function sends the scan command to supplicant.

Code: Frameworks/base/WiFi/Java/Android/NET/WiFi/wifistatetracker. Java

public boolean startScan(booleanforceActive) {       enforceChangePermission();        switch (mWifiStateTracker.getSupplicantState()) {           case DISCONNECTED:           case INACTIVE:           case SCANNING:           case DORMANT:                break;           default:               mWifiStateTracker.setScanResultHandling(                       WifiStateTracker.SUPPL_SCAN_HANDLING_LIST_ONLY);                break;       }       return mWifiStateTracker.scan(forceActive);}

Then the following process is used for automatic scanning as shown in the preceding figure. Let's analyze where the manual scanning starts. We should know that manual scanning is responded by the scan key of the menu key, and the response should be the handlermessage () function of the handler class in the wifisettings class, it calls startscanactive () of wifimanager to call startscan () of wifiservice ().

Code example: packages/apps/settings/src/COM/Android/settings/wifiwifisettings. Java

public boolean onCreateOptionsMenu(Menu menu) {       menu.add(Menu.NONE, MENU_ID_SCAN, 0, R.string.wifi_menu_scan)               .setIcon(R.drawable.ic_menu_scan_network);       menu.add(Menu.NONE, MENU_ID_ADVANCED, 0, R.string.wifi_menu_advanced)               .setIcon(android.R.drawable.ic_menu_manage);       return super.onCreateOptionsMenu(menu);}

When you press the menu key, wifisetaskwill call this function to draw the menu. If the scan button is selected, wifisettings calls onoptionsitemselected ().

Packages/apps/settings/src/COM/Android/settings/wifiwifisettings. Java

public booleanonOptionsItemSelected(MenuItem item) {       switch (item.getItemId()) {           case MENU_ID_SCAN:                if(mWifiManager.isWifiEnabled()) {                    mScanner.resume();                }                return true;           case MENU_ID_ADVANCED:                startActivity(new Intent(this,AdvancedSettings.class));                return true;       }       return super.onOptionsItemSelected(item);}

Handler class:

private class Scanner extends Handler {       private int mRetry = 0;       void resume() {           if (!hasMessages(0)) {                sendEmptyMessage(0);           }       }       void pause() {           mRetry = 0;            mAccessPoints.setProgress(false);           removeMessages(0);       }        @Override       public void handleMessage(Message message) {           if (mWifiManager.startScanActive()){                mRetry = 0;           } else if (++mRetry >= 3) {                mRetry = 0;               Toast.makeText(WifiSettings.this, R.string.wifi_fail_to_scan,                       Toast.LENGTH_LONG).show();                return;           }           mAccessPoints.setProgress(mRetry != 0);           sendEmptyMessageDelayed(0, 6000);       }}

Mwifimanager. startscanactive () will call the startscan () function in the wifiservice. The following process is the same as above.

After supplicant completes the scan command, it sends a message to the upper layer to remind them that the scan has been completed. wifimonitor will receive the message and then send it to wifistatetracker.

Frameworks/base/WiFi/Java/Android/NET/WiFi/wifimonitor. Java

void handleEvent(int event, String remainder) {            switch (event) {                caseDISCONNECTED:                   handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED,remainder);                    break;                case CONNECTED:                   handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED,remainder);                    break;                case SCAN_RESULTS:                    mWifiStateTracker.notifyScanResultsAvailable();                    break;                case UNKNOWN:                    break;            }}

Wifistatetracker will broadcast the scan_results_available_action message:

Code example: Frameworks/base/WiFi/Java/Android/NET/WiFi/wifistatetracker. Java

public voidhandleMessage(Message msg) {        Intent intent;……case EVENT_SCAN_RESULTS_AVAILABLE:                if(ActivityManagerNative.isSystemReady()) {                    mContext.sendBroadcast(new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));                }                sendScanResultsAvailable();                /**                 * On receiving the first scanresults after connecting to                 * the supplicant, switch scanmode over to passive.                 */                setScanMode(false);                break;……}

Since the wifisettings class registers intent, it can process the scan_results_available_action message and it will call handleevent (). The call process is as follows.

Wifisettings. handleevent ()
====> Wifisettings. updateaccesspoints () ====> mwifimanager. getscanresults () ====> mservice. getscanresults () ==>
Mwifistatetracker. scanresults () ===> wifinative. scanresultscommand ()......
Send the command to obtain the AP list to supplicant, and then supplicant sends the scanning result through socket, which is received and displayed by the upper layer. This is basically the same as the previous message acquisition process.

(3) configure and connect to the AP
When you select an active AP, the wifisettings response opens a dialog box to configure the AP, such as the encryption method and the Authentication Mode for connecting to the AP. After the AP is configured, wifiservice adds or updates the network to connect to a specific AP.
Code example: packages/apps/settings/src/COM/Android/settings/WiFi/wifisetttings. Java

public booleanonPreferenceTreeClick(PreferenceScreen screen, Preference preference) {       if (preference instanceof AccessPoint) {           mSelected = (AccessPoint) preference;           showDialog(mSelected, false);       } else if (preference == mAddNetwork) {           mSelected = null;           showDialog(null, true);       } else if (preference == mNotifyOpenNetworks) {           Secure.putInt(getContentResolver(),                   Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,                   mNotifyOpenNetworks.isChecked() ? 1 : 0);       } else {           return super.onPreferenceTreeClick(screen, preference);       }       return true;}

After configuration, when you press connect press, wifisettings sends the list_network command to supplicant to check whether the network is configured. If the network does not exist or is not configured, wifiservice calls the addorupdatenetwork () function to add or update the network, and then sends a command to supplicant to connect to the network. The following code sends the connection command from the response connection button to the wifiservice:

Packages/apps/settings/src/COM/Android/settings/WiFi/wifisetttings. Java

public void onClick(DialogInterfacedialogInterface, int button) {       if (button == WifiDialog.BUTTON_FORGET && mSelected != null) {           forget(mSelected.networkId);       } else if (button == WifiDialog.BUTTON_SUBMIT && mDialog !=null) {           WifiConfiguration config = mDialog.getConfig();            if (config == null) {                if (mSelected != null&& !requireKeyStore(mSelected.getConfig())) {                    connect(mSelected.networkId);                }           } else if (config.networkId != -1) {                if (mSelected != null) {                    mWifiManager.updateNetwork(config);                    saveNetworks();                }           } else {                int networkId =mWifiManager.addNetwork(config);                if (networkId != -1) {                   mWifiManager.enableNetwork(networkId, false);                    config.networkId =networkId;                    if (mDialog.edit || requireKeyStore(config)){                        saveNetworks();                    } else {                        connect(networkId);                    }                }           }       }}

Frameworks \ base \ WiFi \ Java \ Android \ net \ WiFi \ wifimanager. Java

public intupdateNetwork(WifiConfiguration config) {        if(config == null || config.networkId < 0) {           return -1;        }        return addOrUpdateNetwork(config);}private intaddOrUpdateNetwork(WifiConfiguration config) {       try {           return mService.addOrUpdateNetwork(config);       } catch (RemoteException e) {           return -1;       }}

Wifiservice. addorupdatenetwork () sends the connection command to wpa_supplicant by calling mwifistatetracker. setnetworkvariable.

(4) obtain the IP address
When connected to supplicant, wifimonitor will notify wifistatetracker.

Code example: Frameworks/base/WiFi/Java/Android/NET/WiFi/wifimonitor. Java

Public void Run(){if (connectToSupplicant()) {                // Send a message indicatingthat it is now possible to send commands                // to the supplicant                mWifiStateTracker.notifySupplicantConnection();           } else {               mWifiStateTracker.notifySupplicantLost();                return;           }……}

Wifistatetracker sends the event_supplicant_connection message to the Message Queue. The message has its own handlermessage () function for processing. It starts a DHCP thread and waits for a message event, to enable DHCP to assign IP addresses.

Frameworks/base/WiFi/Java/Android/NET/WiFi/wifistatetracker. Java

Void notifysupplicantconnection () {sendemptymessage (event_supplicant_connection);} public void handlemessage (Message MSG) {intent; Switch (msg. What) {Case event_supplicant_connection :...... Handlerthread dhcpthread = newhandlerthread ("DHCP handler thread"); dhcpthread. Start (); mdhcptarget = newdhcphandler (dhcpthread. getlooper (), this );...... ......
           case EVENT_NETWORK_STATE_CHANGED:             ……               configureInterface();             ……

}}

Private void configureinterface () {checkpolltimer (); mlastsignallevel =-1; if (! Musestaticip) {// use the dynamic IP address of the DHCP thread if (! Mhaveipaddress &&! Mobtainingipaddress) {mobtainingipaddress = true; // initiate the DHCP thread to obtain the IP address mdhcptarget. sendemptymessage (event_dhcp_start) ;}} else {// use a static IP address. Obtain the intevent from mdhcpinfo. If (networkutils. configureinterface (minterfacename, mdhcpinfo) {mhaveipaddress = true; event = event_interface_configuration_succeeded; If (local_logd) log. V (TAG, "static IP configurationsucceeded");} else {mhaveipaddress = false; event = event_interface_configuration_failed; If (local_logd) log. V (TAG, "static IP configuration failed");} sendemptymessage (event); // send an IP address to get a successful message event }}

After wpa_supplicant connects to the AP, it sends a message to the upper layer to notify the connection to be successful. wifimonitor receives the message and reports it to wifistatetracker.

Frameworks/base/WiFi/Java/Android/NET/WiFi/wifimonitor. Java

void handleEvent(int event, String remainder) {           switch (event) {               case DISCONNECTED:                   handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED,remainder);                   break;               case CONNECTED:                   handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED,remainder);                   break;                ……} private void handleNetworkStateChange(NetworkInfo.DetailedState newState, String data) {        StringBSSID = null;        intnetworkId = -1;        if(newState == NetworkInfo.DetailedState.CONNECTED) {           Matcher match = mConnectedEventPattern.matcher(data);            if(!match.find()) {               if (Config.LOGD) Log.d(TAG, "Could not find BSSID in CONNECTEDevent string");            }else {               BSSID = match.group(1);               try {                   networkId = Integer.parseInt(match.group(2));               } catch (NumberFormatException e) {                   networkId = -1;                }            }        }        mWifiStateTracker.notifyStateChange(newState,BSSID, networkId);}      void notifyStateChange(DetailedState newState, StringBSSID, int networkId) {        Messagemsg = Message.obtain(           this, EVENT_NETWORK_STATE_CHANGED,            newNetworkStateChangeResult(newState, BSSID, networkId));       msg.sendToTarget();}

After dhcpthread obtains the event_dhcp_start message event, it calls the handlemessage () function to start the DHCP service to obtain the IP address.

Frameworks/base/WiFi/Java/Android/NET/WiFi/wifistatetracker. Java

Public void handlemessage (Message MSG) {intevent; Switch (msg. What) {Case event_dhcp_start :...... Log. D (TAG, "dhcphandler: DHCP requeststarted"); // start a dhcpclient genie process and assign an IP address to the minterfacename request if network( utils. rundhcp (minterfacename, mdhcpinfo) {event = event_interface_configuration_succeeded; If (local_logd) log. V (TAG, "dhcphandler: DHCP request succeeded");} else {event = event_interface_configuration_failed; log. I (TAG, "dhcphandler: DHCP request failed:" + networkutils. getdhcperror ()); }...... }}

Networkutils is called here. rundhcp () function. The networkutils class is a helper class for network services. It mainly defines some local interfaces that communicate with DHCP client through their JNI layer android_net_netutils.cpp file, and obtain the IP address.

So far, the IP address acquisition is complete, and the WiFi startup process is complete.

To be continued

(B) Analysis of wifi module related files

(C) wpa_supplicant Parsing

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.