基于rk3288平台android5.1系统的wifi流程分析 ---- 连接热点

来源:互联网 发布:淘宝买的手机如何保修 编辑:程序博客网 时间:2024/05/17 12:55

上一篇 http://blog.csdn.net/ballack_linux/article/details/78095182 讲了打开wifi 和 扫描热点的流程, 这一篇来了解下连接热点的流程 :

// ---------- packages/apps/settings/src/com/android/settings/wifi/WifiSettings.java ------------ //public boolean onContextItemSelected(MenuItem item) {    switch (item.getItemId()) {        case MENU_ID_CONNECT: {              if (mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {                  connect(mSelectedAccessPoint.networkId);              } else if (mSelectedAccessPoint.security == AccessPoint.SECURITY_NONE) {                  /** Bypass dialog for unsecured networks */                  mSelectedAccessPoint.generateOpenNetworkConfig();                  connect(mSelectedAccessPoint.getConfig());              } else {                  showDialog(mSelectedAccessPoint, true);              }              return true;          }    }}protected void connect(final WifiConfiguration config) {    mWifiManager.connect(config, mConnectListener);}protected void connect(final int networkId) {    mWifiManager.connect(networkId, mConnectListener);}
// -------------- frameworks/base/wifi/java/android/net/wifi/WifiManager.java ----------------- //// 其中第一个参数WifiConfiguration是当前需要连接的AP的配置信息,包括SSID、BSSID、密码以及加密方式等信息;// ActionListener作为callback来通知客户程序connect方法是否调用成功,这里的调用成功只是指参数是否正确,并不表示AP是否连接成功public void connect(WifiConfiguration config, ActionListener listener) {    sAsyncChannel.sendMessage(CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID,            putListener(listener), config);}
由sAsyncChannel的知识可以知道, 这时候是WifiService来处理这个CONNECT_NETWORK消息:

// ---------- frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java ------------ //private class ClientHandler extends Handler {    public void handleMessage(Message msg) {        switch (msg.what) {            case WifiManager.CONNECT_NETWORK:                if (DBG) Slog.d(TAG, "Connect with config" + config);                mWifiStateMachine.sendMessage(Message.obtain(msg));        }    }}

上一篇中scan的流程可以知道, scan之后WifiStateMachine状态机是处在ConnectModeState状态的, 那么该状态没有处理CONNECT_NETWORK事件,由其父类ConnectModeState处理:

class ConnectModeState extends State {    public boolean processMessage(Message message) {        switch (message.what) {            case WifiManager.CONNECT_NETWORK:                // WifiConfigStore.saveNetwork(config)将AP的配置信息写入到wpa_supplicant.conf中;                // WifiConfigStore.selectNetwork(netId)用于enable即将要连接的AP,而disable掉其它的AP;                // WifiNative.reconnect()发起重新连接的请求给wpa_supplicant。接着transition到DisconnectingState                                mWifiConfigStore.saveNetwork(config, message.sendingUid);                if (mWifiConfigStore.selectNetwork(netId) &&                        mWifiNative.reconnect()) {                    transitionTo(mDisconnectingState);                }        }    }}
当执行完WifiNative.reconnect(),wpa_supplicant会不断的往WifiMonitor发送包括CTRL-EVENT-STATE-CHANGE、ASSOCIATING、ASSOCIATED、FOUR_WAY_HANDSHARK、GROUP_HANDSHARK等event,WifiMonitor会不断的去parse这些event, 并向WifiStatemachine发送消息,其中一个比较重要的消息就是当wpa_supplicant的状态改变是会发送WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT,上面的DisconnectiongState 收到这个消息后,会transition到DisconnectedState:
class DisconnectingState extends State {    public boolean processMessage(Message message) {        switch (message.what) {            case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:                deferMessage(message);                handleNetworkDisconnect();                transitionTo(mDisconnectedState);        }    }}
当Wifi和AP之间已经连接成功后,就会收到wpa_supplicant发送上来的CTRL-EVENT-CONNECTED这个event,
WifiMonitor收到这个消息后,会向WifiStateMachine发送NETWORK_CONNECTION_EVENT表示已经和AP之间成功的连线,
由于WifiStateMachine的DisconnectedState不处理这个消息, 故其父类ConnectModeState会来处理这个消息:

class ConnectModeState extends State {    public boolean processMessage(Message message) {        switch (message.what) {            case WifiMonitor.NETWORK_CONNECTION_EVENT:                transitionTo(mObtainingIpState);        }    }}
class ObtainingIpState extends State {    if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) {        if (isRoaming()) {                                              // 是否正在漫游,以后再研究             renewDhcp();        } else {            // Remove any IP address on the interface in case we're switching from static            // IP configuration to DHCP. This is safe because if we get here when not            // roaming, we don't have a usable address.            clearIPv4Address(mInterfaceName);            startDhcp();                                                // 动态获取ip地址        }    } else {        stopDhcp();        StaticIpConfiguration config = mWifiConfigStore.getStaticIpConfiguration(mLastNetworkId);        InterfaceConfiguration ifcg = new InterfaceConfiguration();        ifcg.setLinkAddress(config.ipAddress);                          // 从配置里面读取固定ip地址        ifcg.setInterfaceUp();        mNwService.setInterfaceConfig(mInterfaceName, ifcg);        if (DBG) log("Static IP configuration succeeded");        DhcpResults dhcpResults = new DhcpResults(config);        sendMessage(CMD_STATIC_IP_SUCCESS, dhcpResults);                // 发送设置成功的标志    }}
void startDhcp() {    if (mDhcpStateMachine == null) {        mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(                mContext, WifiStateMachine.this, mInterfaceName);    }    mDhcpStateMachine.registerForPreDhcpNotification();                 // mRegisteredForPreDhcpNotification = true    mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);     // 发送CMD_START_DHCP消息}
// ------------- frameworks/base/core/java/android/net/DhcpStateMachine.java ---------------- //public class DhcpStateMachine extends StateMachine {    public static DhcpStateMachine makeDhcpStateMachine(Context context, StateMachine controller, String intf) {        DhcpStateMachine dsm = new DhcpStateMachine(context, controller, intf);        dsm.start();        return dsm;    }    private DhcpStateMachine(Context context, StateMachine controller, String intf) {        mController = controller;                                       // 可以知道mController指向WifiStateMachine类的对象        setInitialState(mStoppedState);    }    class StoppedState extends State {        public boolean processMessage(Message message) {            switch (message.what) {                case CMD_START_DHCP:                    if (mRegisteredForPreDhcpNotification) {                        /* Notify controller before starting DHCP */                        mController.sendMessage(CMD_PRE_DHCP_ACTION);   // 向WifiStateMachine类发送CMD_PRE_DHCP_ACTION消息                        transitionTo(mWaitBeforeStartState);            // 切换到mWaitBeforeStartState状态                    } else {                        if (runDhcp(DhcpAction.START)) {                            transitionTo(mRunningState);                        }                    }                    break;            }        }    }}
由上面可以知道WifiStateMachine的当前状态是ObtainingIpState, 而ObtainingIpState不处理CMD_PRE_DHCP_ACTION消息, 交由其父类mL2ConnectedState处理:
class L2ConnectedState extends State {    public boolean processMessage(Message message) {        switch (message.what) {            case DhcpStateMachine.CMD_PRE_DHCP_ACTION:                handlePreDhcpSetup();                break;    }}void handlePreDhcpSetup() {    Message msg = new Message();    msg.what = WifiP2pServiceImpl.BLOCK_DISCOVERY;    msg.arg1 = WifiP2pServiceImpl.ENABLED;    msg.arg2 = DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE;    msg.obj = mDhcpStateMachine;    mWifiP2pChannel.sendMessage(msg);}
其中mWifiP2pChannel.connect(mContext, getHandler(), mWifiP2pServiceImpl.getP2pStateMachineMessenger());
故上面是向mWifiP2pServiceImpl发送WifiP2pServiceImpl.BLOCK_DISCOVERY消息,那当前WifiP2pServiceImpl处在什么状态呢?
还记得在打开wifi的时候,会执行以下命令:
mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P);

由于P2pStateMachine初始状态是P2pDisabledState, 故由其来处理CMD_ENABLE_P2P: 

class P2pDisabledState extends State {    public boolean processMessage(Message message) {        switch (message.what) {            case WifiStateMachine.CMD_ENABLE_P2P:                mNwService.setInterfaceUp(mInterface);                mWifiMonitor.startMonitoring();                transitionTo(mP2pEnablingState);        }    }}
P2pStateMachine会切换到mP2pEnablingState状态, 由于mP2pEnablingState状态不处理BLOCK_DISCOVERY消息,故由其父类mDefaultState处理:

// ---------- frameworks/opt/net/wifi/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java ------------ //class DefaultState extends State {    public boolean processMessage(Message message) {        switch (message.what) {            case BLOCK_DISCOVERY:                mDiscoveryBlocked = (message.arg1 == ENABLED ? true : false);                mDiscoveryPostponed = false;                if (mDiscoveryBlocked) {                    StateMachine m = (StateMachine)message.obj;     // 这里message.obj就是mDHCPStateMachine                    m.sendMessage(message.arg2);                    // 这里message.arg2就是DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE                }        }    }}
从上面可以知道, handlePreDhcpSetup其实就是向DhcpStateMachine类发送CMD_PRE_DHCP_ACTION_COMPLETE消息:
当前DhcpStateMachine类处于mWaitBeforeStartState状态:
// ---------- frameworks/base/core/java/android/net/DhcpStateMachine.java ---------- //class WaitBeforeStartState extends State {    public boolean processMessage(Message message) {        switch (message.what) {            case CMD_PRE_DHCP_ACTION_COMPLETE:                if (runDhcp(DhcpAction.START)) {                    transitionTo(mRunningState);                } else {                    transitionTo(mStoppedState);                }        }    }}private boolean runDhcp(DhcpAction dhcpAction) {    if (dhcpAction == DhcpAction.START) {        /* Stop any existing DHCP daemon before starting new */        NetworkUtils.stopDhcp(mInterfaceName);        success = NetworkUtils.runDhcp(mInterfaceName, dhcpResults);        mDhcpResults = dhcpResults;        // 向WifiStateMachine发送CMD_POST_DHCP_ACTION消息        mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, dhcpResults).sendToTarget();       }}
// ---------------- frameworks/base/core/jni/android_net_NetUtils.cpp ------------------ //static JNINativeMethod gNetworkUtilMethods[] = {    { "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpResults;)Z",  (void *)android_net_utils_runDhcp },}static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info){    return android_net_utils_runDhcpCommon(env, clazz, ifname, info, false);}static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstring ifname, jobject dhcpResults, bool renew) {    if (renew) {        result = ::dhcp_do_request_renew(nameStr, ipaddr, gateway, &prefixLength,                dns, server, &lease, vendorInfo, domains, mtu);    } else {        result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength,                dns, server, &lease, vendorInfo, domains, mtu);    }}
// -------------------- system/core/libnetutils/Dhcp_utils.c ---------------------- //static const char DAEMON_NAME[]        = "dhcpcd";static const char DAEMON_PROP_NAME[]   = "init.svc.dhcpcd";static const char HOSTNAME_PROP_NAME[] = "net.hostname";static const char DHCP_PROP_NAME_PREFIX[]  = "dhcp";static const char DHCP_CONFIG_PATH[]   = "/system/etc/dhcpcd/dhcpcd.conf";int dhcp_do_request(const char *interface,        char *ipaddr,        char *gateway,        uint32_t *prefixLength,        char *dns[],        char *server,        uint32_t *lease,        char *vendorInfo,        char *domain,        char *mtu){    char daemon_cmd[PROPERTY_VALUE_MAX * 2 + sizeof(DHCP_CONFIG_PATH)];    const char *ctrl_prop = "ctl.start";    const char *desired_status = "running";    /* Interface name after converting p2p0-p2p0-X to p2p to reuse system properties */    char p2p_interface[MAX_INTERFACE_LENGTH];    get_p2p_interface_replacement(interface, p2p_interface);                    // 获取p2p_interface    snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",        // 例:dhcp.wlan0.result            DHCP_PROP_NAME_PREFIX,            p2p_interface);    snprintf(daemon_prop_name, sizeof(daemon_prop_name), "%s_%s",               // 例:init.svc.dhcpcd_wlan0            DAEMON_PROP_NAME,            p2p_interface);    /* Erase any previous setting of the dhcp result property */    property_set(result_prop_name, "");    /* Start the daemon and wait until it's ready */    if (property_get(HOSTNAME_PROP_NAME, prop_value, NULL) && (prop_value[0] != '/0')) {        // -----------------prop_value实例: [net.hostname]: [android-7a296df9ee18dade]        // dhcpcd_wlan0:-f /system/etc/dhcpcd/dhcpcd.conf -h android-7a296df9ee18dade wlan0 -t 60        snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:-f %s -h %s %s -t 60", DAEMON_NAME,                p2p_interface, DHCP_CONFIG_PATH, prop_value, interface);    }    else {        // dhcpcd_wlan0:-f /system/etc/dhcpcd/dhcpcd.conf  wlan0 -t 60        snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:-f %s %s -t 60", DAEMON_NAME,                p2p_interface, DHCP_CONFIG_PATH, interface);    }    memset(prop_value, '/0', PROPERTY_VALUE_MAX);    property_set(ctrl_prop, daemon_cmd);                                    // ctl.start -----    if (wait_for_property(daemon_prop_name, desired_status, 10) < 0) {      // wait for init.svc.dhcpcd_wlan0 changed to running        snprintf(errmsg, sizeof(errmsg), "%s", "Timed out waiting for dhcpcd to start");        return -1;    }    /* Wait for the daemon to return a result */    if (wait_for_property(result_prop_name, NULL, 60) < 0) {        snprintf(errmsg, sizeof(errmsg), "%s", "Timed out waiting for DHCP to finish");        return -1;    }    if (strcmp(prop_value, "ok") == 0) {        char dns_prop_name[PROPERTY_KEY_MAX];        // fill_ip_info函数用于填充传入的参数, 包括ipaddr, gateway, prefixLength, dns, server, lease, vendorInfo, domain, mtu        if (fill_ip_info(interface, ipaddr, gateway, prefixLength, dns,                    server, lease, vendorInfo, domain, mtu) == -1) {            return -1;        }        return 0;    }}
由上面可以知道WifiStateMachine的当前状态是ObtainingIpState, 而ObtainingIpState不处理CMD_POST_DHCP_ACTION消息,
交由其父类mL2ConnectedState处理:
// -------- frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java ----------- //class L2ConnectedState extends State {    public boolean processMessage(Message message) {        switch (message.what) {            case DhcpStateMachine.CMD_POST_DHCP_ACTION:                handlePostDhcpSetup();                if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) {                    if (DBG) log("WifiStateMachine DHCP successful");                    handleIPv4Success((DhcpResults) message.obj, DhcpStateMachine.DHCP_SUCCESS);                    // We advance to mVerifyingLinkState because handleIPv4Success will call                    // updateLinkProperties, which then sends CMD_IP_CONFIGURATION_SUCCESSFUL.      // 发送CMD_IP_CONFIGURATION_SUCCESSFUL                }                break;            case CMD_IP_CONFIGURATION_SUCCESSFUL:                handleSuccessfulIpConfiguration();                sendConnectedState();                transitionTo(mConnectedState);                break;        }    }}
class ConnectedState extends State {    public boolean processMessage(Message message) {        switch (message.what) {            // 如果信号不好, 则跳转到mVerifyingLinkState状态            case WifiWatchdogStateMachine.POOR_LINK_DETECTED:                if (DBG) log("Watchdog reports poor link");                transitionTo(mVerifyingLinkState);                break;        }    }}
class VerifyingLinkState extends State {    public void enter() {        setNetworkDetailedState(DetailedState.VERIFYING_POOR_LINK);        mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.VERIFYING_POOR_LINK);        sendNetworkStateChangeBroadcast(mLastBssid);        // End roaming        mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE;    }    public boolean processMessage(Message message) {        switch (message.what) {            case WifiWatchdogStateMachine.POOR_LINK_DETECTED:                log(getName() + " POOR_LINK_DETECTED: no transition");                break;            case WifiWatchdogStateMachine.GOOD_LINK_DETECTED:                log(getName() + " GOOD_LINK_DETECTED: transition to CONNECTED");                sendConnectedState();                transitionTo(mConnectedState);                break;        }    }}
在VerifyingLinkState主要是来验证当前连接状况的,主要方式是通过统计信号强度以及丢包率,
这些工作是交给WifiWatchdogStateMachine来做的,当WifiAP的信号强度增强或者变弱,会发送两种消息给WifiStateMachine,
一种是WifiWatchdogStateMachine.GOOD_LINK_DETECTED,另一种是WifiWatchdogStateMachine.POOR_LINK_DETECTED。
当收到GOOD_LINK_DETECTED消息后,就会跳转到mConnectedState中;当收到的是POOR_LINK_DETECTED,则维持原来的状态不变。




原创粉丝点击