WifiManage hotspot热点设置分析(高通平台 android 4.3)
2014-02-20 08:10
681 查看
WifiManage hotspot设置分析
高通MSM8226 平台提供了对hotspot的设置,通过setting->more->Tethering&portable hotspot的Portable Wi-Fihotspot 可以设置手机WIFI提供热点接入的功能,那么具体流程与原理是什么呢?
在\packages\apps\Settings\src\com\android\settings\wifi\WifiApEnabler.java文件中可以看到相关的具体的设置函数setSoftapEnabled,代码大致如下
/*如果hotspot 设置使能,并且现在wificlient出于打开状态,首先关闭WIFI*/
int wifiState =mWifiManager.getWifiState();
if (enable && ((wifiState == WifiManager.WIFI_STATE_ENABLING) ||
(wifiState == WifiManager.WIFI_STATE_ENABLED))){
mWifiManager.setWifiEnabled(false); }
/*调用这个WIFIManager类的接口设置AP使能,一会我们主要分析这个函数的实现*/
if (mWifiManager.setWifiApEnabled(null, enable)) {
/* Disable here, enabled on receiving success broadcast */
mCheckBox.setEnabled(false);
} else {
mCheckBox.setSummary(R.string.wifi_error);
}
/*当禁止AP时,查看之前WIFIclient状态,并恢复*/
if (!enable) {
if (wifiSavedState == 1) {
mWifiManager.setWifiEnabled(true);
Settings.Global.putInt(cr,Settings.Global.WIFI_SAVED_STATE, 0);
}
}
看来是WiFiManager这个类提供了setWifiApEnabled的接口,下面我从framework开始分析setWifiApEanble这个函数,
这个函数位于\frameworks\base\wifi\java\android\net\wifi\WifiManager.java, 函数实现如下
/*通过mService类又调用了setWifiApEnabled*/
public boolean setWifiApEnabled(WifiConfiguration wifiConfig, booleanenabled) {
try {
mService.setWifiApEnabled(wifiConfig, enabled);
return true;
} catch (RemoteException e) {
return false;
}
}
好的,看看mService是一个什么东西,其定义如下
IWifiManagermService;
??? IWifiManager是什么,通过搜索他的定义,无果,后来发现,在WifiManager.java同名目录下有一个IWifiManager.aidl文件,.aidl 全称android 接口描述语言,类似j2ee中的RMI, RMI是通过序列化传递对象实现跨进程数据共享,AIDL通过定义接口实现跨进程的数据共享 IWifiManager.aidl部分文件如下
packageandroid.net.wifi;
importandroid.net.wifi.PPPOEConfig;
importandroid.net.wifi.PPPOEInfo;
importandroid.net.wifi.WifiInfo;
importandroid.net.wifi.WifiConfiguration;
importandroid.net.wifi.ScanResult;
importandroid.net.DhcpInfo;
importandroid.os.Messenger;
importandroid.os.WorkSource;
/*这些个接口提供访问控制wifi的链接*/
interfaceIWifiManager
{
List<WifiConfiguration>getConfiguredNetworks();
int addOrUpdateNetwork(in WifiConfigurationconfig);
boolean removeNetwork(int netId);
boolean enableNetwork(int netId, booleandisableOthers);
boolean disableNetwork(int netId);
boolean pingSupplicant();
……此处省略N个字
}
通过搜索可以知道,其调用WifiService.java中的函数,代码如下
public voidsetWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
enforceChangePermission();
mWifiController.obtainMessage(CMD_SET_AP,enabled ? 1 : 0, 0, wifiConfig).sendToTarget();
}
可以看出,该函数通过CMD_SET_AP 命令进行设置,mWifiController.obtainMessage将message发送到消息处理函数,进一步的处理在WifiController中实现,WifiController继承了StateMachine,在StateMachine中实现了obtainMessage方法。该方法通过Message实现
Message.obtain(mSmHandler,what);
最终的调用结果如下
public staticMessage obtain(Handler h, int what,
int arg1, int arg2, Object obj) {
Message m = obtain();
m.target = h;
m.what = what;
m.arg1 = arg1;
m.arg2 = arg2;
m.obj = obj;
return m;
}
实际上对Message进行了初始化,信息通过Message对象的sendToTarget发送出去。
这个消息通过wificontroll.java中的ApStaDisabledState类中消息处理函数进行处理,代码如下
case CMD_SET_AP:
if (msg.arg1 == 1) {
mWifiStateMachine.setHostApRunning((WifiConfiguration) msg.obj,
true);
transitionTo(mApEnabledState);
}
break;
主要通过调用WifiStateMachine中的方法实现对hostAp的设置,该函数定义如下
public voidsetHostApRunning(WifiConfiguration wifiConfig, boolean enable) {
if (enable) {
sendMessage(CMD_START_AP,wifiConfig);
} else {
sendMessage(CMD_STOP_AP);
}
}
又是message,继续搜索CMD_START_AP,这个类的子类InitialState中的processMessage函数有对这个命令字的处理
case CMD_START_AP:
if(mWifiNative.loadDriver()) {
setWifiApState(WIFI_AP_STATE_ENABLING);
transitionTo(mSoftApStartingState);
} else {
loge("Failed toload driver for softap");
}
mWifiNative.loadDriver通过调用JNI接口加载驱动,其实现在android_net_wifi_Wifi.cpp文件的android_net_wifi_loadDriver函数,实现如下
staticJNINativeMethod gWifiMethods[] = {
/* name, signature, funcPtr */
{ "loadDriver","()Z", (void*)android_net_wifi_loadDriver },
此处省略N个字
}
setWifiApState(WIFI_AP_STATE_ENABLING);函数实现对WIFI状态向其他模块的通知,之后通过transitionTo(mSoftApStartingState); 进入到AP 启动中的状态,SoftApStartingState状态的enter函数中,这个函数很关键,走读到现在才发现最为关键的部分。
public voidenter() {
final Message message =getCurrentMessage();
/*如果要开启AP*/
if (message.what == CMD_START_AP) {
final WifiConfiguration config= (WifiConfiguration) message.obj;
/*obj这个参数实际上刚开始mWifiManager.setWifiApEnabled(null,enable)的null,所以这个时候为空,走这个分支*/
if (config == null) {
if (startSafeChannel!=0) {
Log.e(TAG, "CallingsetChannelRange ---CMD_START_AP SoftApStartingState()");
setChannelRange(startSafeChannel, endSafeChannel , 0);
}
mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG);
} else {/*没走到这里*/
mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config);
startSoftApWithConfig(config);
}
} else {
throw newRuntimeException("Illegal transition to SoftApStartingState: " +message);
}
}
setChannelRange应该是wifichannel情况的一些设置,我们暂时不管他。
从上面代码中看出,mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG)函数进一步设置,好吧,继续看CMD_REQUEST_AP_CONFIG,
这个AP设置请求的命令实际被WifiApConfigStore接收,如下
caseWifiStateMachine.CMD_REQUEST_AP_CONFIG:
mReplyChannel.replyToMessage(message,
WifiStateMachine.CMD_RESPONSE_AP_CONFIG, mWifiApConfig);
可以看出这实际上又返回了一个CMD_REQUEST_AP_CONFIG消息给SoftApStartingState状态,在将焦点集中到这个类的消息处理函数
caseWifiStateMachine.CMD_RESPONSE_AP_CONFIG:
WifiConfiguration config =(WifiConfiguration) message.obj;
if (config != null) { /*获取到了配置,正常不应该为空,走到这里*/
startSoftApWithConfig(config);
} else {
loge("Softapconfig is null!");
sendMessage(CMD_START_AP_FAILURE);
}
break;
继续关注startSoftApWithConfig(config);函数,其实现如下
private void startSoftApWithConfig(finalWifiConfiguration config) {
// start hostapd on a seperate thread
new Thread(new Runnable() {
public void run() {
try {
mNwService.startAccessPoint(config,mInterfaceName);
} catch (Exception e) {
不用去关注,省略
}
if (DBG) log("Soft APstart successful");
sendMessage(CMD_START_AP_SUCCESS);
}
}).start();
}
这个函数实现,启动了一个线程,可能配置需要时间,为了不阻塞用户而设计。startAccessPoint有用到了AIDL方法,调用其他进程函数,其调用了NetworkManagementService.java 的函数
public void startAccessPoint(
WifiConfiguration wifiConfig,String wlanIface) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
wifiFirmwareReload(wlanIface,"AP"); 、/*加载AP*/
if (wifiConfig == null) {
mConnector.execute("softap", "set", wlanIface);
} else {
/*执行了下面的函数*/
mConnector.execute("softap", "set", wlanIface,wifiConfig.SSID,
getSecurityType(wifiConfig), new SensitiveArg(wifiConfig.preSharedKey));
}
mConnector.execute("softap", "startap");
} catch (NativeDaemonConnectorExceptione) {
throwe.rethrowAsParcelableException();
}
}
可以看出其通过softap进行了AP的相关设置,softap的设置代码在NativeDaemonConnector类中,下面在framework是没有了,我们现在可以看出hotspot的设置实际是放在HAL层实现的,这也符合android设计的易图,因为HAL层能够隐藏厂商的设计,保护厂商的利益。简单看一下execute成员的实现
publicNativeDaemonEvent[] execute(int timeout, String cmd, Object... args)
throwsNativeDaemonConnectorException {
final long startTime =SystemClock.elapsedRealtime();
finalArrayList<NativeDaemonEvent> events = Lists.newArrayList();
final StringBuilder rawBuilder = newStringBuilder();
final StringBuilder logBuilder = newStringBuilder();
final int sequenceNumber =mSequenceNumber.incrementAndGet();
/*生成了命令*/
makeCommand(rawBuilder, logBuilder,sequenceNumber, cmd, args);
final String rawCmd =rawBuilder.toString();
final String logCmd =logBuilder.toString();
log("SND -> {" + logCmd + "}");
synchronized (mDaemonLock) {
if (mOutputStream == null) {
throw newNativeDaemonConnectorException("missing output stream");
} else {
try {
mOutputStream.write(rawCmd.getBytes(Charsets.UTF_8));
} catch (IOException e) {
throw newNativeDaemonConnectorException("problem sending command", e);
}
}
}
NativeDaemonEvent event = null;
do {
event =mResponseQueue.remove(sequenceNumber, timeout, logCmd);
if (event == null) {
loge("timed-out waitingfor response to " + logCmd);
throw newNativeDaemonFailureException(logCmd, event);
}
log("RMV <- {" + event+ "}");
events.add(event);
} while (event.isClassContinue());
final long endTime =SystemClock.elapsedRealtime();
if (endTime - startTime >WARN_EXECUTE_DELAY_MS) {
loge("NDC Command {" +logCmd + "} took too long (" + (endTime - startTime) +"ms)");
}
if (event.isClassClientError()) {
throw newNativeDaemonArgumentException(logCmd, event);
}
if (event.isClassServerError()) {
throw newNativeDaemonFailureException(logCmd, event);
}
return events.toArray(newNativeDaemonEvent[events.size()]);
}
上面的函数大概意思是生成一个命令,并通过localSocket传到对端。
在system目录中实现了对softAP的具体设置,实现为SoftapController.cpp文件的SoftapController::setSoftap函数
从整个分析过程来看,androidframework运用了大量的AIDL通信,message消息机制,以及状态机处理方法,分析这些方法对理清整个设置流程至关重要。
高通MSM8226 平台提供了对hotspot的设置,通过setting->more->Tethering&portable hotspot的Portable Wi-Fihotspot 可以设置手机WIFI提供热点接入的功能,那么具体流程与原理是什么呢?
在\packages\apps\Settings\src\com\android\settings\wifi\WifiApEnabler.java文件中可以看到相关的具体的设置函数setSoftapEnabled,代码大致如下
/*如果hotspot 设置使能,并且现在wificlient出于打开状态,首先关闭WIFI*/
int wifiState =mWifiManager.getWifiState();
if (enable && ((wifiState == WifiManager.WIFI_STATE_ENABLING) ||
(wifiState == WifiManager.WIFI_STATE_ENABLED))){
mWifiManager.setWifiEnabled(false); }
/*调用这个WIFIManager类的接口设置AP使能,一会我们主要分析这个函数的实现*/
if (mWifiManager.setWifiApEnabled(null, enable)) {
/* Disable here, enabled on receiving success broadcast */
mCheckBox.setEnabled(false);
} else {
mCheckBox.setSummary(R.string.wifi_error);
}
/*当禁止AP时,查看之前WIFIclient状态,并恢复*/
if (!enable) {
if (wifiSavedState == 1) {
mWifiManager.setWifiEnabled(true);
Settings.Global.putInt(cr,Settings.Global.WIFI_SAVED_STATE, 0);
}
}
看来是WiFiManager这个类提供了setWifiApEnabled的接口,下面我从framework开始分析setWifiApEanble这个函数,
这个函数位于\frameworks\base\wifi\java\android\net\wifi\WifiManager.java, 函数实现如下
/*通过mService类又调用了setWifiApEnabled*/
public boolean setWifiApEnabled(WifiConfiguration wifiConfig, booleanenabled) {
try {
mService.setWifiApEnabled(wifiConfig, enabled);
return true;
} catch (RemoteException e) {
return false;
}
}
好的,看看mService是一个什么东西,其定义如下
IWifiManagermService;
??? IWifiManager是什么,通过搜索他的定义,无果,后来发现,在WifiManager.java同名目录下有一个IWifiManager.aidl文件,.aidl 全称android 接口描述语言,类似j2ee中的RMI, RMI是通过序列化传递对象实现跨进程数据共享,AIDL通过定义接口实现跨进程的数据共享 IWifiManager.aidl部分文件如下
packageandroid.net.wifi;
importandroid.net.wifi.PPPOEConfig;
importandroid.net.wifi.PPPOEInfo;
importandroid.net.wifi.WifiInfo;
importandroid.net.wifi.WifiConfiguration;
importandroid.net.wifi.ScanResult;
importandroid.net.DhcpInfo;
importandroid.os.Messenger;
importandroid.os.WorkSource;
/*这些个接口提供访问控制wifi的链接*/
interfaceIWifiManager
{
List<WifiConfiguration>getConfiguredNetworks();
int addOrUpdateNetwork(in WifiConfigurationconfig);
boolean removeNetwork(int netId);
boolean enableNetwork(int netId, booleandisableOthers);
boolean disableNetwork(int netId);
boolean pingSupplicant();
……此处省略N个字
}
通过搜索可以知道,其调用WifiService.java中的函数,代码如下
public voidsetWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
enforceChangePermission();
mWifiController.obtainMessage(CMD_SET_AP,enabled ? 1 : 0, 0, wifiConfig).sendToTarget();
}
可以看出,该函数通过CMD_SET_AP 命令进行设置,mWifiController.obtainMessage将message发送到消息处理函数,进一步的处理在WifiController中实现,WifiController继承了StateMachine,在StateMachine中实现了obtainMessage方法。该方法通过Message实现
Message.obtain(mSmHandler,what);
最终的调用结果如下
public staticMessage obtain(Handler h, int what,
int arg1, int arg2, Object obj) {
Message m = obtain();
m.target = h;
m.what = what;
m.arg1 = arg1;
m.arg2 = arg2;
m.obj = obj;
return m;
}
实际上对Message进行了初始化,信息通过Message对象的sendToTarget发送出去。
这个消息通过wificontroll.java中的ApStaDisabledState类中消息处理函数进行处理,代码如下
case CMD_SET_AP:
if (msg.arg1 == 1) {
mWifiStateMachine.setHostApRunning((WifiConfiguration) msg.obj,
true);
transitionTo(mApEnabledState);
}
break;
主要通过调用WifiStateMachine中的方法实现对hostAp的设置,该函数定义如下
public voidsetHostApRunning(WifiConfiguration wifiConfig, boolean enable) {
if (enable) {
sendMessage(CMD_START_AP,wifiConfig);
} else {
sendMessage(CMD_STOP_AP);
}
}
又是message,继续搜索CMD_START_AP,这个类的子类InitialState中的processMessage函数有对这个命令字的处理
case CMD_START_AP:
if(mWifiNative.loadDriver()) {
setWifiApState(WIFI_AP_STATE_ENABLING);
transitionTo(mSoftApStartingState);
} else {
loge("Failed toload driver for softap");
}
mWifiNative.loadDriver通过调用JNI接口加载驱动,其实现在android_net_wifi_Wifi.cpp文件的android_net_wifi_loadDriver函数,实现如下
staticJNINativeMethod gWifiMethods[] = {
/* name, signature, funcPtr */
{ "loadDriver","()Z", (void*)android_net_wifi_loadDriver },
此处省略N个字
}
setWifiApState(WIFI_AP_STATE_ENABLING);函数实现对WIFI状态向其他模块的通知,之后通过transitionTo(mSoftApStartingState); 进入到AP 启动中的状态,SoftApStartingState状态的enter函数中,这个函数很关键,走读到现在才发现最为关键的部分。
public voidenter() {
final Message message =getCurrentMessage();
/*如果要开启AP*/
if (message.what == CMD_START_AP) {
final WifiConfiguration config= (WifiConfiguration) message.obj;
/*obj这个参数实际上刚开始mWifiManager.setWifiApEnabled(null,enable)的null,所以这个时候为空,走这个分支*/
if (config == null) {
if (startSafeChannel!=0) {
Log.e(TAG, "CallingsetChannelRange ---CMD_START_AP SoftApStartingState()");
setChannelRange(startSafeChannel, endSafeChannel , 0);
}
mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG);
} else {/*没走到这里*/
mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config);
startSoftApWithConfig(config);
}
} else {
throw newRuntimeException("Illegal transition to SoftApStartingState: " +message);
}
}
setChannelRange应该是wifichannel情况的一些设置,我们暂时不管他。
从上面代码中看出,mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG)函数进一步设置,好吧,继续看CMD_REQUEST_AP_CONFIG,
这个AP设置请求的命令实际被WifiApConfigStore接收,如下
caseWifiStateMachine.CMD_REQUEST_AP_CONFIG:
mReplyChannel.replyToMessage(message,
WifiStateMachine.CMD_RESPONSE_AP_CONFIG, mWifiApConfig);
可以看出这实际上又返回了一个CMD_REQUEST_AP_CONFIG消息给SoftApStartingState状态,在将焦点集中到这个类的消息处理函数
caseWifiStateMachine.CMD_RESPONSE_AP_CONFIG:
WifiConfiguration config =(WifiConfiguration) message.obj;
if (config != null) { /*获取到了配置,正常不应该为空,走到这里*/
startSoftApWithConfig(config);
} else {
loge("Softapconfig is null!");
sendMessage(CMD_START_AP_FAILURE);
}
break;
继续关注startSoftApWithConfig(config);函数,其实现如下
private void startSoftApWithConfig(finalWifiConfiguration config) {
// start hostapd on a seperate thread
new Thread(new Runnable() {
public void run() {
try {
mNwService.startAccessPoint(config,mInterfaceName);
} catch (Exception e) {
不用去关注,省略
}
if (DBG) log("Soft APstart successful");
sendMessage(CMD_START_AP_SUCCESS);
}
}).start();
}
这个函数实现,启动了一个线程,可能配置需要时间,为了不阻塞用户而设计。startAccessPoint有用到了AIDL方法,调用其他进程函数,其调用了NetworkManagementService.java 的函数
public void startAccessPoint(
WifiConfiguration wifiConfig,String wlanIface) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
wifiFirmwareReload(wlanIface,"AP"); 、/*加载AP*/
if (wifiConfig == null) {
mConnector.execute("softap", "set", wlanIface);
} else {
/*执行了下面的函数*/
mConnector.execute("softap", "set", wlanIface,wifiConfig.SSID,
getSecurityType(wifiConfig), new SensitiveArg(wifiConfig.preSharedKey));
}
mConnector.execute("softap", "startap");
} catch (NativeDaemonConnectorExceptione) {
throwe.rethrowAsParcelableException();
}
}
可以看出其通过softap进行了AP的相关设置,softap的设置代码在NativeDaemonConnector类中,下面在framework是没有了,我们现在可以看出hotspot的设置实际是放在HAL层实现的,这也符合android设计的易图,因为HAL层能够隐藏厂商的设计,保护厂商的利益。简单看一下execute成员的实现
publicNativeDaemonEvent[] execute(int timeout, String cmd, Object... args)
throwsNativeDaemonConnectorException {
final long startTime =SystemClock.elapsedRealtime();
finalArrayList<NativeDaemonEvent> events = Lists.newArrayList();
final StringBuilder rawBuilder = newStringBuilder();
final StringBuilder logBuilder = newStringBuilder();
final int sequenceNumber =mSequenceNumber.incrementAndGet();
/*生成了命令*/
makeCommand(rawBuilder, logBuilder,sequenceNumber, cmd, args);
final String rawCmd =rawBuilder.toString();
final String logCmd =logBuilder.toString();
log("SND -> {" + logCmd + "}");
synchronized (mDaemonLock) {
if (mOutputStream == null) {
throw newNativeDaemonConnectorException("missing output stream");
} else {
try {
mOutputStream.write(rawCmd.getBytes(Charsets.UTF_8));
} catch (IOException e) {
throw newNativeDaemonConnectorException("problem sending command", e);
}
}
}
NativeDaemonEvent event = null;
do {
event =mResponseQueue.remove(sequenceNumber, timeout, logCmd);
if (event == null) {
loge("timed-out waitingfor response to " + logCmd);
throw newNativeDaemonFailureException(logCmd, event);
}
log("RMV <- {" + event+ "}");
events.add(event);
} while (event.isClassContinue());
final long endTime =SystemClock.elapsedRealtime();
if (endTime - startTime >WARN_EXECUTE_DELAY_MS) {
loge("NDC Command {" +logCmd + "} took too long (" + (endTime - startTime) +"ms)");
}
if (event.isClassClientError()) {
throw newNativeDaemonArgumentException(logCmd, event);
}
if (event.isClassServerError()) {
throw newNativeDaemonFailureException(logCmd, event);
}
return events.toArray(newNativeDaemonEvent[events.size()]);
}
上面的函数大概意思是生成一个命令,并通过localSocket传到对端。
在system目录中实现了对softAP的具体设置,实现为SoftapController.cpp文件的SoftapController::setSoftap函数
从整个分析过程来看,androidframework运用了大量的AIDL通信,message消息机制,以及状态机处理方法,分析这些方法对理清整个设置流程至关重要。
相关文章推荐
- android lcd调试 高通平台lcd调试深入分析总结(mipi和rgb接口)
- 高通Android平台下zoom4X实验原理分析
- android lcd调试 高通平台lcd调试深入分析总结(mipi和rgb接口)
- 高通平台android环境搭建,编译,系统引导流程分析
- android lcd调试 高通平台lcd调试深入分析总结(mipi和rgb接口)
- android lcd调试 高通平台lcd调试深入分析总结(mipi和rgb接口)
- android高通平台下,设置栏、下拉状态栏去除wifi和Bluetooth功能
- android lcd调试 高通平台lcd调试深入分析总结(mipi和rgb接口)
- 高通平台Android源码分析之Linux内核设备树
- android lcd调试 高通平台lcd调试深入分析总结(mipi和rgb接口)
- android高通平台调用恢复出厂设置的方法
- Android Wi-Fi MIMO/SISO设置方法(基于高通平台)
- android lcd调试 高通平台lcd调试深入分析总结(mipi和rgb接口) .
- 转载:Android Display架构分析--侧重高通平台
- 高通平台Android源码分析之Linux内核设备树
- android lcd调试 高通平台lcd调试深入分析总结(mipi和rgb接口)
- android lcd调试 高通平台lcd调试深入分析总结(mipi和rgb接口)
- 高通 android平台LCD驱动分析
- Android Display架构分析--侧重高通平台