admin管理员组文章数量:1620370
上一篇 http://blog.csdn/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 (mSelectedAccessPointworkId != INVALID_NETWORK_ID) {
connect(mSelectedAccessPointworkId);
} 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,则维持原来的状态不变。
版权声明:本文标题:基于rk3288平台android5.1系统的wifi流程分析 ---- 连接热点 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/dianzi/1728818520a1175174.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论