您的位置:首页 > 移动开发 > Android开发

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消息机制,以及状态机处理方法,分析这些方法对理清整个设置流程至关重要。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: