Android -- Wifi热点的打开与关闭流程简介

Android -- Wifi热点的打开与关闭流程简介


在Android手机中,热点也是一个较为常用的功能。对于framework开发者来说,要开发、维护SoftAp,了解framework中热点开关的具体流程是非常有必要的。下面就对这部分内容做一些介绍,以供后续查阅。

一、SoftAp打开流程

当我们在设置中打开热点时,会调用WifiManager::setWifiApEnabled(),参数enabled为true;间接调用同名的WifiServiceImpl::setWifiApEnabled():
[java] view plain copy
  1. /** 
  2.      * Start AccessPoint mode with the specified 
  3.      * configuration. If the radio is already running in 
  4.      * AP mode, update the new configuration 
  5.      * Note that starting in access point mode disables station 
  6.      * mode operation 
  7.      * @param wifiConfig SSID, security and channel details as 
  8.      *        part of WifiConfiguration 
  9.      * @return {@code true} if the operation succeeds, {@code false} otherwise 
  10.      * 
  11.      * @hide Dont open up yet 
  12.      */  
  13.     public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {  
  14.         try {  
  15.             mService.setWifiApEnabled(wifiConfig, enabled);  
  16.             return true;  
  17.         } catch (RemoteException e) {  
  18.             return false;  
  19.         }  
  20.     }  
[java] view plain copy
  1. /** 
  2.  * see {@link android.net.wifi.WifiManager#setWifiApEnabled(WifiConfiguration, boolean)} 
  3.  * @param wifiConfig SSID, security and channel details as 
  4.  *        part of WifiConfiguration 
  5.  * @param enabled true to enable and false to disable 
  6.  */  
  7. public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {  
  8.     enforceChangePermission();  
  9.     ConnectivityManager.enforceTetherChangePermission(mContext);  
  10.     if (mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {  
  11.         throw new SecurityException("DISALLOW_CONFIG_TETHERING is enabled for this user.");  
  12.     }  
  13.     // null wifiConfig is a meaningful input for CMD_SET_AP  
  14.     if (wifiConfig == null || isValid(wifiConfig)) {  
  15.         mWifiController.obtainMessage(CMD_SET_AP, enabled ? 1 : 00, wifiConfig).sendToTarget();  
  16.     } else {  
  17.         Slog.e(TAG, "Invalid WifiConfiguration");  
  18.     }  
  19. }  
参数中的wifiConfig对象保存了在Settings中操作时保留的热点信息,如热点名称、密钥和加密方式等等。与Wifi本身的打开和关闭类似,Wifi热点的打开流程也是通过WifiController状态机向WifiStateMachine转发消息的。与前面介绍的Wifi打开流程类似,CMD_SET_AP消息在ApStaDisabledState状态处理:
[java] view plain copy
  1. case CMD_SET_AP:  
  2.     if (msg.arg1 == 1) {  
  3.         mWifiStateMachine.setHostApRunning((WifiConfiguration) msg.obj,  
  4.                 true);  
  5.         transitionTo(mApEnabledState);//此时WifiController的状态停留在ApEnabledState  
  6.     }  
由此转入WifiStateMachine进行打开流程:
[java] view plain copy
  1. /** 
  2.  * TODO: doc 
  3.  */  
  4. public void setHostApRunning(WifiConfiguration wifiConfig, boolean enable) {  
  5.     if (enable) {  
  6.         sendMessage(CMD_START_AP, wifiConfig);  
  7.     } else {  
  8.         sendMessage(CMD_STOP_AP);  
  9.     }  
  10. }  
WifiStateMachine::InitialState会处理该消息:
[java] view plain copy
  1. case CMD_START_AP:  
  2.                     if (mWifiNative.loadDriver() == false) {  
  3.                         loge("Failed to load driver for softap");  
  4.                     } else {  
  5.                         if (enableSoftAp() == true) {  
  6.                             setWifiApState(WIFI_AP_STATE_ENABLING, 0);//该函数中会发送广播,告知外界当前热点的启动阶段  
  7.                             transitionTo(mSoftApStartingState);//切换状态  
  8.                         } else {  
  9.                             setWifiApState(WIFI_AP_STATE_FAILED,  
  10.                                     WifiManager.SAP_START_FAILURE_GENERAL);  
  11.                             transitionTo(mInitialState);  
  12.                         }  
  13.                     }  
  14.                     break;  
首先肯定是先加载驱动,驱动加载成功后通过enableSoftAp()配置Wifi热点:
[java] view plain copy
  1. /* SoftAP configuration */  
  2. private boolean enableSoftAp() {  
  3.     if (WifiNative.getInterfaces() != 0) {  
  4.         if (!mWifiNative.toggleInterface(0)) {  
  5.             if (DBG) Log.e(TAG, "toggleInterface failed");  
  6.             return false;  
  7.         }  
  8.     } else {  
  9.         if (DBG) Log.d(TAG, "No interfaces to toggle");  
  10.     }  
  11.   
  12.     try {  
  13.         mNwService.wifiFirmwareReload(mInterfaceName, "AP");//加载固件  
  14.         if (DBG) Log.d(TAG, "Firmware reloaded in AP mode");  
  15.     } catch (Exception e) {  
  16.         Log.e(TAG, "Failed to reload AP firmware " + e);  
  17.     }  
  18.   
  19.     if (WifiNative.startHal() == false) {//启动HAL层  
  20.         /* starting HAL is optional */  
  21.         Log.e(TAG, "Failed to start HAL");  
  22.     }  
  23.     return true;  
  24. }  
Wifi热点首先需要绑定端口信息,再以AP模式通过NetworkManagementService在wlan0端口下加载固件;同时热点功能也需要HAL层的支持。
setWifiApState()会发送广播,告知当前热点打开的过程信息;同理,也有setWifiState(),告知外界当前Wifi打开的过程信息;如果我们有必要知道当前热点打开的过程进行到什么阶段了,可以监听WifiManager.WIFI_AP_STATE_CHANGED_ACTION广播。最后状态切换到SoftApStartingState,如果流程有误,则会重新进入InitialState。
接着看SoftApStartingState::enter():
[java] view plain copy
  1. public void enter() {  
  2.     final Message message = getCurrentMessage();  
  3.     if (message.what == CMD_START_AP) {  
  4.         final WifiConfiguration config = (WifiConfiguration) message.obj;  
  5.   
  6.         if (config == null) {  
  7.             mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG);//1 - 获取先前或者默认的配置信息  
  8.         } else {  
  9.             mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config);//2 - 将上层传入的配置信息写到本地文件  
  10.             startSoftApWithConfig(config);//开启热点  
  11.         }  
  12.     } else {  
  13.         throw new RuntimeException("Illegal transition to SoftApStartingState: " + message);  
  14.     }  
  15. }  
首先会判断打开热点时传入的WifiConfiguration对象是否为null;如果为空,则会向WifiApConfigStore发送CMD_REQUEST_AP_CONFIG消息,请求一个热点配置信息
。我们一起介绍这两个分支过程。回过头看InitialState状态的enter():
[java] view plain copy
  1. public void enter() {  
  2.             WifiNative.stopHal();  
  3.             mWifiNative.unloadDriver();  
  4.             if (mWifiP2pChannel == null) {  
  5.                 mWifiP2pChannel = new AsyncChannel();  
  6.                 mWifiP2pChannel.connect(mContext, getHandler(),  
  7.                     mWifiP2pServiceImpl.getP2pStateMachineMessenger());  
  8.             }  
  9.   
  10.             if (mWifiApConfigChannel == null) {  
  11.                 mWifiApConfigChannel = new AsyncChannel();  
  12.                 mWifiApConfigStore = WifiApConfigStore.makeWifiApConfigStore(  
  13.                         mContext, getHandler());//WifiApConfigStore也是一个小的状态机,此时会构建mWifiApConfigStore对戏,并启动状态机  
  14.                 mWifiApConfigStore.loadApConfiguration();//在WifiApConfigStore中加载默认的热点配置信息  
  15.                 mWifiApConfigChannel.connectSync(mContext, getHandler(),  
  16.                         mWifiApConfigStore.getMessenger());//创建AsyncChannel对象,以供向WifiApConfigStore发送消息  
  17.             }  
  18.   
  19.             if (mWifiConfigStore.enableHalBasedPno.get()) {  
  20.                 // make sure developer Settings are in sync with the config option  
  21.                 mHalBasedPnoEnableInDevSettings = true;  
  22.             }  
  23.         }  
在创建完mWifiApConfigStore对象后,会调用mWifiApConfigStore.loadApConfiguration()加载热点配置信息:
[java] view plain copy
  1. void loadApConfiguration() {  
  2.     DataInputStream in = null;  
  3.     try {  
  4.         WifiConfiguration config = new WifiConfiguration();  
  5.         in = new DataInputStream(new BufferedInputStream(new FileInputStream(  
  6.                         AP_CONFIG_FILE)));  
  7.   
  8.         int version = in.readInt();  
  9.         if ((version != 1) && (version != 2)) {  
  10.             Log.e(TAG, "Bad version on hotspot configuration file, set defaults");  
  11.             setDefaultApConfiguration();  
  12.             return;  
  13.         }  
  14.         config.SSID = in.readUTF();  
  15.   
  16.         if (version >= 2) {  
  17.             config.apBand = in.readInt();  
  18.             config.apChannel = in.readInt();  
  19.         }  
  20.   
  21.         int authType = in.readInt();  
  22.         config.allowedKeyManagement.set(authType);  
  23.         if (authType != KeyMgmt.NONE) {  
  24.             config.preSharedKey = in.readUTF();  
  25.         }  
  26.   
  27.         mWifiApConfig = config;  
  28.     } catch (IOException ignore) {  
  29.         setDefaultApConfiguration();  
  30.     } finally {  
  31.         if (in != null) {  
  32.             try {  
  33.                 in.close();  
  34.             } catch (IOException e) {}  
  35.         }  
  36.     }  
  37. }  
主要是从/misc/wifi/softap.conf文件中读取其中的信息,并赋给WifiApConfigStore的成员变量mWifiApConfig,这个变量保存的就是当前SoftAp的配置信息。该文件一开始会有默认的信息保存其中,如果我们从没配置过热点,拿到的就是系统默认的信息;如果,上层配置了热点;我们也会将新的配置信息更新到softap.conf中,以供下载再次加载。再看消息处理过程:
[java] view plain copy
  1. case WifiStateMachine.CMD_REQUEST_AP_CONFIG:  
  2.                     mReplyChannel.replyToMessage(message,  
  3.                             WifiStateMachine.CMD_RESPONSE_AP_CONFIG, mWifiApConfig);  
向WifiStateMachine回复CMD_RESPONSE_AP_CONFIG消息,并附带mWifiApConfig对象。在SoftApStartingState::enter()中,如果config不为空,我们直接去调用startSoftApWithConfig()启动SoftAP;如果一开始config为null,通过处理CMD_RESPONSE_AP_CONFIG,获取到新的config对象,也应该去开启SoftAP了:
[java] view plain copy
  1. case WifiStateMachine.CMD_RESPONSE_AP_CONFIG:  
  2.                     WifiConfiguration config = (WifiConfiguration) message.obj;  
  3.                     if (config != null) {  
  4.                         startSoftApWithConfig(config);  
  5.                     } else {  
  6.                         loge("Softap config is null!");//config依然为null,则热点打开失败  
  7.                         sendMessage(CMD_START_AP_FAILURE, WifiManager.SAP_START_FAILURE_GENERAL);//SoftApStartingState处理,状态重新切换到InitialState  
  8.                     }  
  9.                     break;  
如果一开始的config对象不为空,从代码可知我们会先发送CMD_SET_AP_CONFIG消息,通知WifiApConfigStore更新配置信息,看处理流程:
[java] view plain copy
  1. class InactiveState extends State {  
  2.     public boolean processMessage(Message message) {  
  3.         switch (message.what) {  
  4.             case WifiStateMachine.CMD_SET_AP_CONFIG:  
  5.                  WifiConfiguration config = (WifiConfiguration)message.obj;  
  6.                 if (config.SSID != null) {  
  7.                     mWifiApConfig = config;//将上层传入的配置信息先保存到成员变量中  
  8.                     transitionTo(mActiveState);//切换状态  
  9.                 } else {  
  10.                     Log.e(TAG, "Try to setup AP config without SSID: " + message);  
  11.                 }  
首先将传入的配置对象保存到mWifiApConfig,接着切换状态:
[java] view plain copy
  1. class ActiveState extends State {  
  2.     public void enter() {  
  3.         new Thread(new Runnable() {  
  4.             public void run() {  
  5.                 writeApConfiguration(mWifiApConfig);//更新配置信息到本地  
  6.                 sendMessage(WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED);//发送更新完成消息  
  7.             }  
  8.         }).start();  
  9.     }  
  10.   
  11.     public boolean processMessage(Message message) {  
  12.         switch (message.what) {  
  13.             //TODO: have feedback to the user when we do this  
  14.             //to indicate the write is currently in progress  
  15.             case WifiStateMachine.CMD_SET_AP_CONFIG:  
  16.                 deferMessage(message);  
  17.                 break;  
  18.             case WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED:  
  19.                 transitionTo(mInactiveState);  
  20.                 break;  
  21.             default:  
  22.                 return NOT_HANDLED;  
  23.         }  
  24.         return HANDLED;  
  25.     }  
  26. }  
enter()函数中,会调用writeApConfiguration()将mWifiApConfig的信息更新到/misc/wifi/softap.conf文件中,供下次加载使用:
[java] view plain copy
  1. private void writeApConfiguration(final WifiConfiguration config) {  
  2.     DataOutputStream out = null;  
  3.     try {  
  4.         out = new DataOutputStream(new BufferedOutputStream(  
  5.                     new FileOutputStream(AP_CONFIG_FILE)));  
  6.   
  7.         out.writeInt(AP_CONFIG_FILE_VERSION);  
  8.         out.writeUTF(config.SSID);  
  9.         out.writeInt(config.apBand);  
  10.         out.writeInt(config.apChannel);  
  11.         int authType = config.getAuthType();  
  12.         out.writeInt(authType);  
  13.         if(authType != KeyMgmt.NONE) {  
  14.             out.writeUTF(config.preSharedKey);  
  15.         }  
  16.     } catch (IOException e) {  
  17.         Log.e(TAG, "Error writing hotspot configuration" + e);  
  18.     } finally {  
  19.         if (out != null) {  
  20.             try {  
  21.                 out.close();  
  22.             } catch (IOException e) {}  
  23.         }  
  24.     }  
  25. }  
处理比较简单,接着给自己发送CMD_SET_AP_CONFIG_COMPLETED消息,告知配置信息更新已经完毕,并重新进入InactiveState,重新等待下次配置信息的更新处理。
我们再返回到WifiStateMachine::SoftApStartingState处理CMD_RESPONSE_AP_CONFIG,如果再次获取后的config依然为null,则通知热点打开失败。接着就是真正开启热点的函数处理:
[java] view plain copy
  1. /* Current design is to not set the config on a running hostapd but instead 
  2.  * stop and start tethering when user changes config on a running access point 
  3.  * 
  4.  * TODO: Add control channel setup through hostapd that allows changing config 
  5.  * on a running daemon 
  6.  */  
  7. private void startSoftApWithConfig(final WifiConfiguration configuration) {  
  8.     // set channel  
  9.     final WifiConfiguration config = new WifiConfiguration(configuration);  
  10.   
  11.     if (DBG) {  
  12.         Log.d(TAG, "SoftAp config channel is: " + config.apChannel);  
  13.     }  
  14.   
  15.     //We need HAL support to set country code and get available channel list, if HAL is  
  16.     //not available, like razor, we regress to original implementaion (2GHz, channel 6)  
  17.     if (mWifiNative.isHalStarted()) {//因为SoftAp需要HAL层的支持,所有首先要进行确定,再继续配置  
  18.         //set country code through HAL Here  
  19.         if (mSetCountryCode != null) {  
  20.             if (!mWifiNative.setCountryCodeHal(mSetCountryCode.toUpperCase(Locale.ROOT))) {  
  21.                 if (config.apBand != 0) {  
  22.                     Log.e(TAG, "Fail to set country code. Can not setup Softap on 5GHz");  
  23.                     //countrycode is mandatory for 5GHz  
  24.                     sendMessage(CMD_START_AP_FAILURE, WifiManager.SAP_START_FAILURE_GENERAL);  
  25.                     return;  
  26.                 }  
  27.             }  
  28.         } else {  
  29.             if (config.apBand != 0) {  
  30.                 //countrycode is mandatory for 5GHz  
  31.                 Log.e(TAG, "Can not setup softAp on 5GHz without country code!");  
  32.                 sendMessage(CMD_START_AP_FAILURE, WifiManager.SAP_START_FAILURE_GENERAL);  
  33.                 return;  
  34.             }  
  35.         }  
  36.   
  37.         if (config.apChannel == 0) {  
  38.             config.apChannel = chooseApChannel(config.apBand);  
  39.             if (config.apChannel == 0) {  
  40.                 if(mWifiNative.isGetChannelsForBandSupported()) {  
  41.                     //fail to get available channel  
  42.                     sendMessage(CMD_START_AP_FAILURE, WifiManager.SAP_START_FAILURE_NO_CHANNEL);  
  43.                     return;  
  44.                 } else {  
  45.                     //for some old device, wifiHal may not be supportedget valid channels are not  
  46.                     //supported  
  47.                     config.apBand = 0;  
  48.                     config.apChannel = 6;  
  49.                 }  
  50.             }  
  51.         }  
  52.     } else {  
  53.         //for some old device, wifiHal may not be supported  
  54.         config.apBand = 0;  
  55.         config.apChannel = 6;  
  56.     }  
  57.     // Start hostapd on a separate thread  
  58.     new Thread(new Runnable() {//开启一个新线程,来启动hostapd;我们支持wpa_s是支持Wifi的,hostapd则是支持SoftAP的  
  59.         public void run() {  
  60.             try {  
  61.                 mNwService.startAccessPoint(config, mInterfaceName);//通过NetworkManagerService,在无线端口上,按传入的配置信息开启SoftAP;  
  62.             } catch (Exception e) {  
  63.                 loge("Exception in softap start " + e);  
  64.                 try {  
  65.                     mNwService.stopAccessPoint(mInterfaceName);  
  66.                     mNwService.startAccessPoint(config, mInterfaceName);  
  67.                 } catch (Exception e1) {  
  68.                     loge("Exception in softap re-start " + e1);  
  69.                     sendMessage(CMD_START_AP_FAILURE, WifiManager.SAP_START_FAILURE_GENERAL);//打开失败,状态会重新切换到InitialState;等待下一次过程  
  70.                     return;  
  71.                 }  
  72.             }  
  73.             if (DBG) log("Soft AP start successful");  
  74.             sendMessage(CMD_START_AP_SUCCESS);//打开成功  
  75.         }  
  76.     }).start();  
  77. }  
如果最后热点打开成功,发送CMD_START_AP_SUCCESS,看处理过程,SoftApStartingState:
[java] view plain copy
  1. case CMD_START_AP_SUCCESS:  
  2.     setWifiApState(WIFI_AP_STATE_ENABLED, 0);//发送广播,告知SoftAp已经成功打开  
  3.     transitionTo(mSoftApStartedState);//切换状态  
  4.     break;  
  5. case CMD_START_AP_FAILURE:  
  6.     setWifiApState(WIFI_AP_STATE_FAILED, message.arg1);//发送广播,告知SoftAp未成功打开  
  7.     transitionTo(mInitialState);//切换到初始状态  
最终状态在SoftApStartedState:
[java] view plain copy
  1. class SoftApStartedState extends State {  
  2.     @Override  
  3.     public boolean processMessage(Message message) {  
  4.         logStateAndMessage(message, getClass().getSimpleName());  
  5.   
  6.         switch(message.what) {  
  7.             case CMD_STOP_AP:  
  8.                 if (DBG) log("Stopping Soft AP");  
  9.                 /* We have not tethered at this point, so we just shutdown soft Ap */  
  10.                 try {  
  11.                     mNwService.stopAccessPoint(mInterfaceName);  
  12.                 } catch(Exception e) {  
  13.                     loge("Exception in stopAccessPoint()");  
  14.                 }  
  15.                 setWifiApState(WIFI_AP_STATE_DISABLED, 0);  
  16.                 transitionTo(mInitialState);  
  17.                 break;  
  18.             case CMD_START_AP:  
  19.                 // Ignore a start on a running access point  
  20.                 break;  
  21.                 // Fail client mode operation when soft AP is enabled  
  22.             case CMD_START_SUPPLICANT:  
  23.                 loge("Cannot start supplicant with a running soft AP");  
  24.                 setWifiState(WIFI_STATE_UNKNOWN);  
  25.                 break;  
  26.             case CMD_TETHER_STATE_CHANGE:  
  27.                 TetherStateChange stateChange = (TetherStateChange) message.obj;  
  28.                 if (startTethering(stateChange.available)) {  
  29.                     transitionTo(mTetheringState);  
  30.                 }  
  31.                 break;  
  32.             default:  
  33.                 return NOT_HANDLED;  
  34.         }  
  35.         return HANDLED;  
  36.     }  
到这里,一个完整的SoftAp打开流程就结束了。

二、SoftAp关闭流程

关闭SoftAp的方法调用与打开SoftAp一致,不过enabled此时是为false:
[java] view plain copy
  1. public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled)   
由第一部分的内容可知WifiController状态机在处理完SoftAp打开后,停在ApEnabledState状态,那么我们看它是怎么处理CMD_SET_AP的:
[java] view plain copy
  1. case CMD_SET_AP:  
  2.      if (msg.arg1 == 0) {  
  3.              mWifiStateMachine.setHostApRunning(nullfalse);//在WifiStateMachine中开始热点关闭流程  
  4.              transitionTo(mApStaDisabledState);//切换到初始状态  
  5.       }  
  6.       break;  
有前述可知,如果参数enabled为false,mag.arg1就应该为0,调用setHostApRunning()走关闭流程,并将WifiController中的状态重置为ApStaDisabledState,等待下一次流程的开始。看setHostApRunning():
[java] view plain copy
  1. /** 
  2.  * TODO: doc 
  3.  */  
  4. public void setHostApRunning(WifiConfiguration wifiConfig, boolean enable) {  
  5.     if (enable) {  
  6.         sendMessage(CMD_START_AP, wifiConfig);  
  7.     } else {  
  8.         sendMessage(CMD_STOP_AP);  
  9.     }  
  10. }  
发送CMD_STOP_AP消息;已知SoftAp成功打开后,WifiStateMachine停留在SoftApStartedState,看其处理:
[java] view plain copy
  1. case CMD_STOP_AP:  
  2.     if (DBG) log("Stopping Soft AP");  
  3.     /* We have not tethered at this point, so we just shutdown soft Ap */  
  4.     try {  
  5.         mNwService.stopAccessPoint(mInterfaceName);//直接关闭SoftAp  
  6.     } catch(Exception e) {  
  7.         loge("Exception in stopAccessPoint()");  
  8.     }  
  9.     setWifiApState(WIFI_AP_STATE_DISABLED, 0);//发送广播,告知外界SoftAp的状态  
  10.     transitionTo(mInitialState);//切换到初始状态  
首先,通过NetworkManagermentService关闭SoftAp,并发送广播通知SoftAp的状态改变;最后WifiStateMachine切换到InitialState:
[java] view plain copy
  1. public void enter() {  
  2.             WifiNative.stopHal();  
  3.             mWifiNative.unloadDriver();  
  4.             if (mWifiP2pChannel == null) {  
  5.                 mWifiP2pChannel = new AsyncChannel();  
  6.                 mWifiP2pChannel.connect(mContext, getHandler(),  
  7.                     mWifiP2pServiceImpl.getP2pStateMachineMessenger());  
  8.             }  
  9.   
  10.             if (mWifiApConfigChannel == null) {  
  11.                 mWifiApConfigChannel = new AsyncChannel();  
  12.                 mWifiApConfigStore = WifiApConfigStore.makeWifiApConfigStore(  
  13.                         mContext, getHandler());  
  14.                 mWifiApConfigStore.loadApConfiguration();  
  15.                 mWifiApConfigChannel.connectSync(mContext, getHandler(),  
  16.                         mWifiApConfigStore.getMessenger());  
  17.             }  
  18.   
  19.             if (mWifiConfigStore.enableHalBasedPno.get()) {  
  20.                 // make sure developer Settings are in sync with the config option  
  21.                 mHalBasedPnoEnableInDevSettings = true;  
  22.             }  
  23.         }  
停掉HAL层,卸载驱动;重新等待下一次Wifi/SoftAp的启动过程。到此,热点关闭的动作就结束了。
PS:
WifiManager中提供了两个关于SoftAp的操作函数:
1、设置SoftAP的配置信息
[java] view plain copy
  1. /** 
  2.  * Sets the Wi-Fi AP Configuration. 
  3.  * @return {@code true} if the operation succeeded, {@code false} otherwise 
  4.  * 
  5.  * @hide Dont open yet 
  6.  */  
  7. public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {  
  8.     try {  
  9.         mService.setWifiApConfiguration(wifiConfig);  
  10.         return true;  
  11.     } catch (RemoteException e) {  
  12.         return false;  
  13.     }  
  14. }  
设置Wi-Fi AP的配置信息,它真正的处理过程是向WifiApConfigStore发送CMD_SET_AP_CONFIG消息,告知其要更新配置信息了。这一部分处理在第一部分已经分析过。
2、获取当前SoftAp正在使用的配置信息
[java] view plain copy
  1. /** 
  2.  * Gets the Wi-Fi AP Configuration. 
  3.  * @return AP details in WifiConfiguration 
  4.  * 
  5.  * @hide Dont open yet 
  6.  */  
  7. public WifiConfiguration getWifiApConfiguration() {  
  8.     try {  
  9.         return mService.getWifiApConfiguration();  
  10.     } catch (RemoteException e) {  
  11.         return null;  
  12.     }  
  13. }  
它真正的处理过程是向WifiApConfigStore发送CMD_REQUEST_AP_CONFIG消息,请求WifiApConfigStore::mWifiApConfig成员,第一部分也已经说过,该变量保存的就是当前SoftAp正在使用的配置信息。

你可能感兴趣的:(android,网络框架接入分析)