wifi移植(上)

           一、wifi模块的结构

       当设置enable后,调用WifiEnabler->WifiManager->WifiService->
WifiNatvie->android_net_wifi_wifi->wifi.c->wpa_supplicant.

      同时还有wifi事件的监听,密码设置

 WifiSettings->AccessPoint->WifiService->WifiStateTracker->WifiMonitor->WifiNatvie->android_net_wifi_wifi->wifi.c->wpa_supplicant.

  

      其中wpa_supplicant是通过socket与 hardware/libhardware_legacy/wifi/wifi.c通信

 

    二、wifi服务的启动

     在SystemServer启动时,生成一个 ConnectivityService 的实例
            try {
                Slog.i(TAG, "Connectivity Service");
                connectivity = ConnectivityService.getInstance(context);
                ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);
            } catch (Throwable e) {
                Slog.e(TAG, "Failure starting Connectivity Service", e);
            }

       在 ConnectivityService的构造函数里创建WifiService.

                case ConnectivityManager.TYPE_WIFI:
                if (DBG) Slog.v(TAG, "Starting Wifi Service.");
                WifiStateTracker wst = new WifiStateTracker(context, mHandler);
                WifiService wifiService = new WifiService(context, wst);
                ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
                wifiService.startWifi();//调用wifiService的startWifi
                mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst;
                wst.startMonitoring();//启动监听

        WifiService 负责启动关闭 wpa_supplicant、启动关闭 WifiMonitor 监视线程和把命令下发给wpa_supplicant,而 WifiMonitor 则负责从wpa_supplicant 接收事件通知。

     

  三、enable AP

   WirelessSettings 在初始化的时候配置了WifiEnabler

   protected void onCreate(Bundle savedInstanceState) {

          ....

           mWifiEnabler = new WifiEnabler(this, wifi);

          ...

  }
点击按钮创建WifiEnabler,由WifiEnabler调用 WifiManager 的 setWifiEnabled 接口函数,最终它调用WifiService的setWifiEnabled函数。然后sendEnableMessage到Wifiservice。

WifiService.java:

       private class WifiHandler extends Handler {
        public WifiHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {

                case MESSAGE_ENABLE_WIFI:
                    setWifiEnabledBlocking(true, msg.arg1 == 1, msg.arg2);
                    if (mWifiWatchdogService == null) {
                        mWifiWatchdogService = new WifiWatchdogService(mContext, mWifiStateTracker);
                    }
                    sWakeLock.release();
                    break;

                  ....

}

     WifiService收到MESSAGE_ENABLE_WIFI消息,调用setWifiEnabledBlocking函数。

     private boolean setWifiEnabledBlocking(boolean enable, boolean persist, int uid) {
        final int eventualWifiState = enable ? WIFI_STATE_ENABLED : WIFI_STATE_DISABLED;
        final int wifiState = mWifiStateTracker.getWifiState();

        if (wifiState == eventualWifiState) {
            return true;
        }
        if (enable && isAirplaneModeOn() && !mAirplaneModeOverwridden) {
            return false;
        }

        /**
         * Multiple calls to unregisterReceiver() cause exception and a system crash.
         * This can happen if a supplicant is lost (or firmware crash occurs) and user indicates
         * disable wifi at the same time.
         * Avoid doing a disable when the current Wifi state is UNKNOWN
         * TODO: Handle driver load fail and supplicant lost as seperate states
         */
        if ((wifiState == WIFI_STATE_UNKNOWN) && !enable) {
            return false;
        }

        /**
         * Fail Wifi if AP is enabled
         * TODO: Deprecate WIFI_STATE_UNKNOWN and rename it
         * WIFI_STATE_FAILED
         */
        if ((mWifiApState == WIFI_AP_STATE_ENABLED) && enable) {
            setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
            return false;
        }

        setWifiEnabledState(enable ? WIFI_STATE_ENABLING : WIFI_STATE_DISABLING, uid);

        if (enable) {
            if (!mWifiStateTracker.loadDriver()) {
                Slog.e(TAG, "Failed to load Wi-Fi driver.");
                setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
                return false;
            }
            if (!mWifiStateTracker.startSupplicant()) {
                mWifiStateTracker.unloadDriver();
                Slog.e(TAG, "Failed to start supplicant daemon.");
                setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
                return false;
            }

            registerForBroadcasts();
            mWifiStateTracker.startEventLoop();

        } else {

            mContext.unregisterReceiver(mReceiver);
           // Remove notification (it will no-op if it isn't visible)
            mWifiStateTracker.setNotificationVisible(false, 0, false, 0);

            boolean failedToStopSupplicantOrUnloadDriver = false;

            if (!mWifiStateTracker.stopSupplicant()) {
                Slog.e(TAG, "Failed to stop supplicant daemon.");
                setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
                failedToStopSupplicantOrUnloadDriver = true;
            }

            /**
             * Reset connections and disable interface
             * before we unload the driver
             */
            mWifiStateTracker.resetConnections(true);

            if (!mWifiStateTracker.unloadDriver()) {
                Slog.e(TAG, "Failed to unload Wi-Fi driver.");
                if (!failedToStopSupplicantOrUnloadDriver) {
                    setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
                    failedToStopSupplicantOrUnloadDriver = true;
                }
            }

            if (failedToStopSupplicantOrUnloadDriver) {
                return false;
            }
        }

        // Success!

        if (persist) {
            persistWifiEnabled(enable);
        }
        setWifiEnabledState(eventualWifiState, uid);
        return true;
    }

      这个函数主要做三件事,一是加载wifi驱动模块,二是启动wpa_supplicant。之后是通过WifiStateTracker 来启动 WifiMonitor的事件监听线程。

       设置成功后,更新wifi状态,以广播方式发送WIFI_STATE_CHANGED_ACTION这个Intent。通知外界WIFI已经enable成功。代码如下:

       private void setWifiEnabledState(int wifiState, int uid) {
        final int previousWifiState = mWifiStateTracker.getWifiState();

        long ident = Binder.clearCallingIdentity();
        try {
            if (wifiState == WIFI_STATE_ENABLED) {
                mBatteryStats.noteWifiOn();
            } else if (wifiState == WIFI_STATE_DISABLED) {
                mBatteryStats.noteWifiOff();
            }
        } catch (RemoteException e) {
        } finally {
            Binder.restoreCallingIdentity(ident);
        }

        // Update state
        mWifiStateTracker.setWifiState(wifiState);

        // Broadcast
        final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
        intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState);
        intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState);
        mContext.sendStickyBroadcast(intent);
    }

   

   外界接受到WIFI_STATE_CHANGED_ACTION这个Intent后,在WifiSettings.java里

      private void updateWifiState(int state) {
        if (state == WifiManager.WIFI_STATE_ENABLED) {
            mScanner.resume();
            updateAccessPoints();
        } else {
            mScanner.pause();
            mAccessPoints.removeAll();
        }
    }
   开始扫描,并update AccessPoints.

   追踪代码,扫描函数在WifiStateTracker.java里  

   public synchronized boolean scan(boolean forceActive) {
        if (mWifiState.get() != WIFI_STATE_ENABLED || isDriverStopped()) {
            return false;
        }
        return WifiNative.scanCommand(forceActive);
    }


       在android_net_wifi_Wifi.cpp,也是往 wpa_supplicant 发送 SCAN 命令

     static jboolean android_net_wifi_scanCommand(JNIEnv* env, jobject clazz, jboolean forceActive)
{
    jboolean result;

    // Ignore any error from setting the scan mode.
    // The scan will still work.
    if (forceActive && !sScanModeActive)
        doSetScanMode(true);
    result = doBooleanCommand("SCAN", "OK");
    if (forceActive && !sScanModeActive)
        doSetScanMode(sScanModeActive);
    return result;
}

   获取扫描结果,并向控制台发送扫描事件。由于WifiMonitor.java的startMonitoring函数已经启动,监听线程已经启动。

   在WifiMonitor.java里

  class MonitorThread extends Thread {
        public MonitorThread() {
            super("WifiMonitor");
        }
        
        public void run() {

            if (connectToSupplicant()) {
                // Send a message indicating that it is now possible to send commands
                // to the supplicant
                mWifiStateTracker.notifySupplicantConnection();
            } else {
                mWifiStateTracker.notifySupplicantLost();
                return;
            }

            //noinspection InfiniteLoopStatement
            for (;;) {
                String eventStr = WifiNative.waitForEvent();

                // Skip logging the common but mostly uninteresting scan-results event
                if (Config.LOGD && eventStr.indexOf(scanResultsEvent) == -1) {
                    Log.v(TAG, "Event [" + eventStr + "]");
                }
                if (!eventStr.startsWith(eventPrefix)) {
                    if (eventStr.startsWith(wpaEventPrefix) &&
                            0 < eventStr.indexOf(passwordKeyMayBeIncorrectEvent)) {
                        handlePasswordKeyMayBeIncorrect();
                    }
                    continue;
                }

             ....

       }

      通过 WifiNative.waitForEvent()函数来接受扫描事件。

      void handleEvent(int event, String remainder) {
            switch (event) {
                case DISCONNECTED:
                    handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED, remainder);
                    break;

                case CONNECTED:
                    handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED, remainder);
                    break;

                case SCAN_RESULTS:
                    mWifiStateTracker.notifyScanResultsAvailable();
                    break;

                case UNKNOWN:
                    break;
            }
        }

     

         void notifyScanResultsAvailable() {
        // reset the supplicant's handling of scan results to "normal" mode
        setScanResultHandling(SUPPL_SCAN_HANDLING_NORMAL);
        sendEmptyMessage(EVENT_SCAN_RESULTS_AVAILABLE);
    }

      这样SCAN_RESULTS事件被执行。接着WifiStateTracker 则接着广播发送 SCAN_RESULTS_AVAILABLE_ACTION 这个 Intent
    case EVENT_SCAN_RESULTS_AVAILABLE:
                if (ActivityManagerNative.isSystemReady()) {
                    mContext.sendBroadcast(new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
                }
                sendScanResultsAvailable();
                /**
                 * On receiving the first scan results after connecting to
                 * the supplicant, switch scan mode over to passive.
                 */
                setScanMode(false);
                break;

      在扫描完后,执行updateAccessPoints()函数:

     WifiSettings.java:

     private void updateAccessPoints() {

     ...

      List<ScanResult> results = mWifiManager.getScanResults();//通过此函数获取AP扫描结果并保存在列表中。
        if (results != null) {
            for (ScanResult result : results) {
                // Ignore hidden and ad-hoc networks.
                if (result.SSID == null || result.SSID.length() == 0 ||
                        result.capabilities.contains("[IBSS]")) {
                    continue;
                }

                boolean found = false;
                for (AccessPoint accessPoint : accessPoints) {
                    if (accessPoint.update(result)) {
                        found = true;
                    }
                }
                if (!found) {
                    accessPoints.add(new AccessPoint(this, result));
                }
            }
        }

     ...

   }


四、加密部分

     在WifiDialog.java里:

     ifiConfiguration getConfig() {
        if (mAccessPoint != null && mAccessPoint.networkId != -1 && !edit) {
            return null;
        }

        WifiConfiguration config = new WifiConfiguration();

        if (mAccessPoint == null) {
            config.SSID = AccessPoint.convertToQuotedString(
                    mSsid.getText().toString());
            // If the user adds a network manually, assume that it is hidden.
            config.hiddenSSID = true;
        } else if (mAccessPoint.networkId == -1) {
            config.SSID = AccessPoint.convertToQuotedString(
                    mAccessPoint.ssid);
        } else {
            config.networkId = mAccessPoint.networkId;
        }

        switch (mSecurity) {
            case AccessPoint.SECURITY_NONE:
                config.allowedKeyManagement.set(KeyMgmt.NONE);
                return config;
            //加密方式WEP
            case AccessPoint.SECURITY_WEP:
                config.allowedKeyManagement.set(KeyMgmt.NONE);
                config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
                config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
                if (mPassword.length() != 0) {
                    int length = mPassword.length();
                    String password = mPassword.getText().toString();
                    // WEP-40, WEP-104, and 256-bit WEP (WEP-232?)
                    if ((length == 10 || length == 26 || length == 58) &&
                            password.matches("[0-9A-Fa-f]*")) {  //密码配对操作
                        config.wepKeys[0] = password;
                    } else {
                        config.wepKeys[0] = '"' + password + '"';
                    }
                }
                return config;
            //PSK
            case AccessPoint.SECURITY_PSK:
                config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
                if (mPassword.length() != 0) {
                    String password = mPassword.getText().toString();
                    if (password.matches("[0-9A-Fa-f]{64}")) { //密码配对操作
                        config.preSharedKey = password;
                    } else {
                        config.preSharedKey = '"' + password + '"';
                    }
                }
                return config;
            //EAP
            case AccessPoint.SECURITY_EAP:
                config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
                config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
                config.eap.setValue((String) mEapMethod.getSelectedItem());

                config.phase2.setValue((mPhase2.getSelectedItemPosition() == 0) ? "" :
                        "auth=" + mPhase2.getSelectedItem());
                config.ca_cert.setValue((mEapCaCert.getSelectedItemPosition() == 0) ? "" :
                        KEYSTORE_SPACE + Credentials.CA_CERTIFICATE +
                        (String) mEapCaCert.getSelectedItem());
                config.client_cert.setValue((mEapUserCert.getSelectedItemPosition() == 0) ? "" :
                        KEYSTORE_SPACE + Credentials.USER_CERTIFICATE +
                        (String) mEapUserCert.getSelectedItem());
                config.private_key.setValue((mEapUserCert.getSelectedItemPosition() == 0) ? "" :
                        KEYSTORE_SPACE + Credentials.USER_PRIVATE_KEY +
                        (String) mEapUserCert.getSelectedItem());
                config.identity.setValue((mEapIdentity.length() == 0) ? "" :
                        mEapIdentity.getText().toString());
                config.anonymous_identity.setValue((mEapAnonymous.length() == 0) ? "" :
                        mEapAnonymous.getText().toString());
                if (mPassword.length() != 0) {
                    config.password.setValue(mPassword.getText().toString());
                }
                return config;
        }
        return null;
    }

   向wpa_supplicant.conf文件设置一些值,比如加密方式,权限等。


   五、IP配置

    当 wpa_supplicant 成功连接上 AP 之后,它会向控制通道发送事件通知连接上 AP 了,从而wifi_wait_for_event 函数会接收到该事件,由此 WifiMonitor 中的 MonitorThread 会被执行这个事件

    void handleEvent(int event, String remainder) {

              ...

                   case CONNECTED:
                  handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED,remainder);
                   break;

              ...

}

追查handleNetworkStateChange函数

private void handleNetworkStateChange(NetworkInfo.DetailedState newState, String data) {
        String BSSID = null;
        int networkId = -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 CONNECTED event string");
            } else {
                BSSID = match.group(1);
                try {
                    networkId = Integer.parseInt(match.group(2));
                } catch (NumberFormatException e) {
                    networkId = -1;
                }
            }
        }
        mWifiStateTracker.notifyStateChange(newState, BSSID, networkId);
    }

  跟踪notifyStateChange

 void notifyStateChange(DetailedState newState, String BSSID, int networkId) {
        Message msg = Message.obtain(
            this, EVENT_NETWORK_STATE_CHANGED,
            new NetworkStateChangeResult(newState, BSSID, networkId));
        msg.sendToTarget();
    }

  得到 EVENT_NETWORK_STATE_CHANGED事件

case EVENT_NETWORK_STATE_CHANGED:

         ....

        if (result.state == DetailedState.CONNECTED) {//连接上

        configureInterface();//配置IP

         ...

        if (mHaveIpAddress) {//已经有IP地址没?
                        setDetailedState(DetailedState.CONNECTED);//有,已连接上
                    } else {
                        setDetailedState(DetailedState.OBTAINING_IPADDR);//木有,扫描获取IP地址
                    }

          ...

   看看configureInterface()函数,WifiStateTracker 则接着会往自身发送 EVENT_DHCP_START 消息来启动 DHCP 去获取 IP 地址

private void configureInterface() {
        checkPollTimer();
        mLastSignalLevel = -1;
        if (!mUseStaticIp) {
            if (!mHaveIpAddress && !mObtainingIpAddress) {
                mObtainingIpAddress = true;
                mDhcpTarget.sendEmptyMessage(EVENT_DHCP_START);
            }
        } else {
            int event;
            if (NetworkUtils.configureInterface(mInterfaceName, mDhcpInfo)) {
                mHaveIpAddress = true;
                event = EVENT_INTERFACE_CONFIGURATION_SUCCEEDED;//获取IP地址成功,发送该事件
                if (LOCAL_LOGD) Log.v(TAG, "Static IP configuration succeeded");
            } else {
                mHaveIpAddress = false;
                event = EVENT_INTERFACE_CONFIGURATION_FAILED;
                if (LOCAL_LOGD) Log.v(TAG, "Static IP configuration failed");
            }
            sendEmptyMessage(event);
        }
    }


  case EVENT_INTERFACE_CONFIGURATION_SUCCEEDED:
                /**
                 * Since this event is sent from another thread, it might have been
                 * sent after we closed our connection to the supplicant in the course
                 * of disabling Wi-Fi. In that case, we should just ignore the event.
                 */
                if (mWifiInfo.getSupplicantState() == SupplicantState.UNINITIALIZED) {
                    break;
                }
                mReconnectCount = 0;
                mHaveIpAddress = true;
                mObtainingIpAddress = false;
                mWifiInfo.setIpAddress(mDhcpInfo.ipAddress);//设置IP地址
                mLastSignalLevel = -1; // force update of signal strength
                if (mNetworkInfo.getDetailedState() != DetailedState.CONNECTED) {
                    setDetailedState(DetailedState.CONNECTED);
                    sendNetworkStateChangeBroadcast(mWifiInfo.getBSSID());
                } else {
                    msg = mTarget.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
                    msg.sendToTarget();
                }
                if (LOCAL_LOGD) Log.v(TAG, "IP configuration: " + mDhcpInfo);
                // Wi-Fi interface configuration state changed:
                // [31- 1] Reserved for future use
                // [ 0- 0] Interface configuration succeeded (1) or failed (0)   
                EventLog.writeEvent(EVENTLOG_INTERFACE_CONFIGURATION_STATE_CHANGED, 1);

                // We've connected successfully, so allow the notification again in the future
                resetNotificationTimer();//连接成功,再次通知
                break;

               WifiStateTracker处理EVENT_DHCP_SUCCEEDED消息,成功设置IP地址。

              结构部分分析到此为止,下节分析porting部分。

            

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值