基于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,则维持原来的状态不变。
阅读全文
0 0
- 基于rk3288平台android5.1系统的wifi流程分析 ---- 连接热点
- 基于rk3288平台android5.1系统的wifi流程分析 ---- 打开wifi,扫描热点
- 基于rk3288平台android5.1系统的wifi流程分析 ---- 打开热点,作为AP
- RK3288 Android5.1系统编译
- rk3288 ap6335 linux下的wifi 热点功能使用
- wifi连接流程分析
- wifi连接流程分析
- wifi连接流程分析
- wifi连接流程分析
- wifi连接流程分析
- wifi连接流程分析
- WIFI连接流程分析
- wifi连接流程分析
- wifi连接流程分析
- wifi连接流程分析
- Wifi连接流程分析
- [android]WIFI热点启动流程分析
- [android]WIFI热点启动流程分析
- path-sum-ii
- 将JSON对象、数组的值赋给另外一个对象,(互不影响) 对象赋值
- GIT相关整理
- Java中的两种异常类型是什么?他们有什么区别?
- TCP协议
- 基于rk3288平台android5.1系统的wifi流程分析 ---- 连接热点
- Java全局变量与局部变量的整理
- 真正从零开始,TensorFlow详细安装入门图文教程
- Java线程工作内存与主内存变量交换过程及volatile关键字理解
- sun.misc.BASE64Encoder在Eclipse中不能直接使用的原因和解决方案
- 注解Butterknife使用 代替findViewById
- matlab 排序 sorttrows
- 搭建环境(二)Ubuntu14.04安装CUDA8.0
- 108. Convert Sorted Array to Binary Search Tree