Android4.0 wifi 启动流程3 之 wifi连接

Android4.0 wifi 启动流程3 wifi连接

当用户选择一个活跃的AP时,WifiSettings响应打开一个对话框来配置AP,比如加密方法和连接AP的验证模式。配置好AP后,WifiService添加或更新网络连接到特定的AP。代码在wifisettings.java中:

public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {

        if (preference instanceof AccessPoint) {

            mSelectedAccessPoint = (AccessPoint) preference;

            /** Bypass dialog for unsecured, unsaved networks */

            if (mSelectedAccessPoint.security == AccessPoint.SECURITY_NONE &&

                    mSelectedAccessPoint.networkId == INVALID_NETWORK_ID) {

                mSelectedAccessPoint.generateOpenNetworkConfig();

                mWifiManager.connectNetwork(mSelectedAccessPoint.getConfig());

            } else {

                showConfigUi(mSelectedAccessPoint, false);

            }

        } else {

            return super.onPreferenceTreeClick(screen, preference);

        }

        return true;

    }

调用showConfigUi(mSelectedAccessPoint, false);在屏幕上显示配置界面:

private void showConfigUi(AccessPoint accessPoint, boolean edit) {

        if (mInXlSetupWizard) {

            ((WifiSettingsForSetupWizardXL)getActivity()).showConfigUi(accessPoint, edit);

        } else {

            showDialog(accessPoint, edit);

        }

}

 

然后调用showDialog(accessPoint, edit)

private void showDialog(AccessPoint accessPoint, boolean edit) {

        if (mDialog != null) {

            removeDialog(WIFI_DIALOG_ID);

            mDialog = null;

        }

 

        // Save the access point and edit mode

        mDlgAccessPoint = accessPoint;

        mDlgEdit = edit;

 

        showDialog(WIFI_DIALOG_ID);

    }

然后通过WIFI_DIALOG_ID来创建该对话框:

public Dialog onCreateDialog(int dialogId) {

        AccessPoint ap = mDlgAccessPoint; // For manual launch

        if (ap == null) { // For re-launch from saved state

            if (mAccessPointSavedState != null) {

                ap = new AccessPoint(getActivity(), mAccessPointSavedState);

                // For repeated orientation changes

                mDlgAccessPoint = ap;

            }

        }

        // If it's still null, fine, it's for Add Network

        mSelectedAccessPoint = ap;

        mDialog = new WifiDialog(getActivity(), this, ap, mDlgEdit);

        return mDialog;

    }

这样配置ap密码的对话框就完成了。

当用户配置好之后点击连接时会调用onClick函数:

public void onClick(DialogInterface dialogInterface, int button) {

        if (mInXlSetupWizard) {

            if (button == WifiDialog.BUTTON_FORGET && mSelectedAccessPoint != null) {

                forget();

            } else if (button == WifiDialog.BUTTON_SUBMIT) {

                ((WifiSettingsForSetupWizardXL)getActivity()).onConnectButtonPressed();

            }

        } else {

            if (button == WifiDialog.BUTTON_FORGET && mSelectedAccessPoint != null) {

                forget();

            } else if (button == WifiDialog.BUTTON_SUBMIT) {

                submit(mDialog.getController());

            }

        }

 

    }

然后调用submit(mDialog.getController())函数进行提交:

void submit(WifiConfigController configController) {

        int networkSetup = configController.chosenNetworkSetupMethod();

        switch(networkSetup) {

            case WifiConfigController.WPS_PBC:

            case WifiConfigController.WPS_DISPLAY:

            case WifiConfigController.WPS_KEYPAD:

                mWifiManager.startWps(configController.getWpsConfig());

                break;

            case WifiConfigController.MANUAL:

                final WifiConfiguration config = configController.getConfig();

 

                if (config == null) {

                    if (mSelectedAccessPoint != null

                            && !requireKeyStore(mSelectedAccessPoint.getConfig())

                            && mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {

                        mWifiManager.connectNetwork(mSelectedAccessPoint.networkId);

                    }

                } else if (config.networkId != INVALID_NETWORK_ID) {

                    if (mSelectedAccessPoint != null) {

                        saveNetwork(config);

                    }

                } else {

                    if (configController.isEdit() || requireKeyStore(config)) {

                        saveNetwork(config);

                    } else {

                        mWifiManager.connectNetwork(config);

                    }

                }

                break;

        }

 

        if (mWifiManager.isWifiEnabled()) {

            mScanner.resume();

        }

        updateAccessPoints();

    }

然后调用mWifiManager.connectNetwork(mSelectedAccessPoint.networkId);函数进行连接:

public void connectNetwork(int networkId) {

        if (networkId < 0) {

            return;

        }

        mAsyncChannel.sendMessage(CMD_CONNECT_NETWORK, networkId);

}

发送了一个CMD_CONNECT_NETWORK消息,在wifiservice中:

case WifiManager.CMD_CONNECT_NETWORK: {

                    if (msg.obj != null) {

                        mWifiStateMachine.connectNetwork((WifiConfiguration)msg.obj);

                    } else {

                        mWifiStateMachine.connectNetwork(msg.arg1);

                    }

                    break;

                }

处理该消息,调用mWifiStateMachine.connectNetwork((WifiConfiguration)msg.obj)

public void connectNetwork(WifiConfiguration wifiConfig) {

        /* arg1 is used to indicate netId, force a netId value of

         * WifiConfiguration.INVALID_NETWORK_ID when we are passing

         * a configuration since the default value of 0 is a valid netId

         */

        sendMessage(obtainMessage(CMD_CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID,

                0, wifiConfig));

    }

发送了一个消息,在ConnectModeState状态处理该消息:

case CMD_CONNECT_NETWORK:

                    int netId = message.arg1;

                    WifiConfiguration config = (WifiConfiguration) message.obj;

 

                    /* We connect to a specific network by issuing a select

                     * to the WifiConfigStore. This enables the network,

                     * while disabling all other networks in the supplicant.

                     * Disabling a connected network will cause a disconnection

                     * from the network. A reconnectCommand() will then initiate

                     * a connection to the enabled network.

                     */

                    if (config != null) {

                        netId = WifiConfigStore.selectNetwork(config);

                    } else {

                        WifiConfigStore.selectNetwork(netId);

                    }

 

                    /* The state tracker handles enabling networks upon completion/failure */

                    mSupplicantStateTracker.sendMessage(CMD_CONNECT_NETWORK);

 

                    WifiNative.reconnectCommand();

                    mLastExplicitNetworkId = netId;

                    mLastNetworkChoiceTime  = SystemClock.elapsedRealtime();

                    mNextWifiActionExplicit = true;

                    if (DBG) log("Setting wifi connect explicit for netid " + netId);

                    /* Expect a disconnection from the old connection */

                    transitionTo(mDisconnectingState);

                    break;

 

调用WifiConfigStore.selectNetwork(netId)

static void selectNetwork(int netId) {

        // Reset the priority of each network at start or if it goes too high.

        if (sLastPriority == -1 || sLastPriority > 1000000) {

            synchronized (sConfiguredNetworks) {

                for(WifiConfiguration config : sConfiguredNetworks.values()) {

                    if (config.networkId != INVALID_NETWORK_ID) {

                        config.priority = 0;

                        addOrUpdateNetworkNative(config);

                    }

                }

            }

            sLastPriority = 0;

        }

 

        // Set to the highest priority and save the configuration.

        WifiConfiguration config = new WifiConfiguration();

        config.networkId = netId;

        config.priority = ++sLastPriority;

 

        addOrUpdateNetworkNative(config);

        WifiNative.saveConfigCommand();

 

        /* Enable the given network while disabling all other networks */

        enableNetworkWithoutBroadcast(netId, true);

 

       /* Avoid saving the config & sending a broadcast to prevent settings

        * from displaying a disabled list of networks */

}

重新设置各network的优先级,关闭其他网络,打开该网络。

addOrUpdateNetworkNative(config)添加网络。

WifiNative.saveConfigCommand():保存该网络。

调用enableNetworkWithoutBroadcast(netId, true)打开用户选择的网络,关闭其他网络:

static boolean enableNetworkWithoutBroadcast(int netId, boolean disableOthers) {

        boolean ret = WifiNative.enableNetworkCommand(netId, disableOthers);

 

        synchronized (sConfiguredNetworks) {

            WifiConfiguration config = sConfiguredNetworks.get(netId);

            if (config != null) config.status = Status.ENABLED;

        }

 

        if (disableOthers) {

            markAllNetworksDisabledExcept(netId);

        }

        return ret;

    }

调用JNI函数WifiNative.enableNetworkCommand,打开选定网络关闭其他的网络,同步更改各网络的状态。

 

发送消息mSupplicantStateTracker.sendMessage(CMD_CONNECT_NETWORK)处理正在打开的网络:

class DefaultState extends State {

case WifiStateMachine.CMD_CONNECT_NETWORK:

                    mNetworksDisabledDuringConnect = true;

                    break;

 

然后切换到mDisconnectingState状态。

 

 

Ip地址的配置:

wpa_supplicant连接到ap之后会向上层发送一个CONNECTED 事件,wifimonitor接收到该事件后:

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:

                    mStateMachine.sendMessage(SCAN_RESULTS_EVENT);

                    break;

 

                case UNKNOWN:

                    break;

            }

        }

调用handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED, remainder)函数:

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 (false) 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;

                }

            }

        }

        notifyNetworkStateChange(newState, BSSID, networkId);

    }

 

之后调用notifyNetworkStateChange(newState, BSSID, networkId)

void notifyNetworkStateChange(NetworkInfo.DetailedState newState, String BSSID, int netId) {

        if (newState == NetworkInfo.DetailedState.CONNECTED) {

            Message m = mStateMachine.obtainMessage(NETWORK_CONNECTION_EVENT,

                    netId, 0, BSSID);

            mStateMachine.sendMessage(m);

        } else {

            Message m = mStateMachine.obtainMessage(NETWORK_DISCONNECTION_EVENT,

                    netId, 0, BSSID);

            mStateMachine.sendMessage(m);

        }

    }

wifi状态机发送消息:                                                                        Message m = mStateMachine.obtainMessage(NETWORK_CONNECTION_EVENT,

                    netId, 0, BSSID);

 

wifistateMachine.javaConnectModeState 状态处理该消息:

case WifiMonitor.NETWORK_CONNECTION_EVENT:

                    if (DBG) log("Network connection established");

                    mLastNetworkId = message.arg1;

                    mLastBssid = (String) message.obj;

 

                    //TODO: make supplicant modification to push this in events

                    mWifiInfo.setSSID(fetchSSID());

                    mWifiInfo.setBSSID(mLastBssid);

                    mWifiInfo.setNetworkId(mLastNetworkId);

                    if (mNextWifiActionExplicit &&

                        mWifiInfo.getNetworkId() == mLastExplicitNetworkId &&

                        SystemClock.elapsedRealtime() < mLastNetworkChoiceTime +

                                                            EXPLICIT_CONNECT_ALLOWED_DELAY_MS) {

                        mWifiInfo.setExplicitConnect(true);

                    }

                    mNextWifiActionExplicit = false;

                    /* send event to CM & network change broadcast */

                    setNetworkDetailedState(DetailedState.OBTAINING_IPADDR);

                    sendNetworkStateChangeBroadcast(mLastBssid);

                    transitionTo(mConnectingState);

                    break;

设置ssid等,然后切换到ConnectingState状态启动DHCP分配ip

class ConnectingState extends State {

 

        @Override

        public void enter() {

            if (DBG) log(getName() + "\n");

            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());

 

            try {

                mNwService.enableIpv6(mInterfaceName);

            } catch (RemoteException re) {

                loge("Failed to enable IPv6: " + re);

            } catch (IllegalStateException e) {

                loge("Failed to enable IPv6: " + e);

            }

 

            if (!WifiConfigStore.isUsingStaticIp(mLastNetworkId)) { //判断是使用静态IP还是动态分配

                //start DHCP

                mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(

                        mContext, WifiStateMachine.this, mInterfaceName);

                mDhcpStateMachine.registerForPreDhcpNotification();// 开启预分配

                mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);//DHCP状态机发送开始命令

            } else {

                DhcpInfoInternal dhcpInfoInternal = WifiConfigStore.getIpConfiguration(

                        mLastNetworkId);

                InterfaceConfiguration ifcg = new InterfaceConfiguration();

                ifcg.addr = dhcpInfoInternal.makeLinkAddress();

                ifcg.interfaceFlags = "[up]";

                try {

                    mNwService.setInterfaceConfig(mInterfaceName, ifcg);

                    if (DBG) log("Static IP configuration succeeded");

                    sendMessage(CMD_STATIC_IP_SUCCESS, dhcpInfoInternal);

                } catch (RemoteException re) {

                    loge("Static IP configuration failed: " + re);

                    sendMessage(CMD_STATIC_IP_FAILURE);

                } catch (IllegalStateException e) {

                    loge("Static IP configuration failed: " + e);

                    sendMessage(CMD_STATIC_IP_FAILURE);

                }

            }

        }

DhcpStateMachine.javs中:dhcp状态机的初始状态是StoppedState,该状态处理CMD_START_DHCP消息:

class StoppedState extends State {

        @Override

        public void enter() {

            if (DBG) Log.d(TAG, getName() + "\n");

        }

 

        @Override

        public boolean processMessage(Message message) {

            boolean retValue = HANDLED;

            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");

            switch (message.what) {

                case CMD_START_DHCP:

                    if (mRegisteredForPreDhcpNotification) {

                        /* Notify controller before starting DHCP */

                        mController.sendMessage(CMD_PRE_DHCP_ACTION);

                        transitionTo(mWaitBeforeStartState);

                    } else {

                        if (runDhcp(DhcpAction.START)) {

                            transitionTo(mRunningState);

                        }

                    }

                    break;

发送mController.sendMessage(CMD_PRE_DHCP_ACTION)消息,然后切换到 (mWaitBeforeStartState)状态, wifi状态机中ConnectingState状态接收该消息并处理:

case DhcpStateMachine.CMD_PRE_DHCP_ACTION:

                  handlePreDhcpSetup();

                  mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE);

                  break;

处理完分配地址前的一些操作,通知dhcp完成预分配mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE)dhcp当前状态WaitBeforeStartState接收该消息并处理:

case CMD_PRE_DHCP_ACTION_COMPLETE:

                    if (runDhcp(DhcpAction.START)) {

                        transitionTo(mRunningState);

                    } else {

                        transitionTo(mStoppedState);

                    }

                    break;

调用runDhcp开始分配ip地址,然后切换到mRunningState状态。在runDhcp函数中

调用NetworkUtils.runDhcp函数来分配ip地址:

if (dhcpAction == DhcpAction.START) {

            if (DBG) Log.d(TAG, "DHCP request on " + mInterfaceName);

            success = NetworkUtils.runDhcp(mInterfaceName, dhcpInfoInternal);

            mDhcpInfo = dhcpInfoInternal;

分配的ip地址和dns放在DhcpInfoInternal类中。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值