Android(安卓)WiFi之SoftAP
转载:
Android SoftAp支持 (一)
Android SoftAp支持 (二)
java测试用例
WifiAP将wifi作为AP
一、概要介绍
1.JAVA API部分
frameworks/base/wifi/java/android/net/wifi/WifiManager.java
public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) { mService.setWifiApEnabled(wifiConfig, enabled);}public int getWifiApState() { return mService.getWifiApEnabledState();}public boolean isWifiApEnabled() { return getWifiApState() == WIFI_AP_STATE_ENABLED;}public WifiConfiguration getWifiApConfiguration() { return mService.getWifiApConfiguration();}public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) { mService.setWifiApConfiguration(wifiConfig); return true;}
2.服务器端进程
frameworks/base/services/java/com/android/server/WifiService.java
public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) { mWifiStateMachine.setWifiApEnabled(wifiConfig, enabled);}public int getWifiApEnabledState() { return mWifiStateMachine.syncGetWifiApState();}public WifiConfiguration getWifiApConfiguration() { return mWifiStateMachine.syncGetWifiApConfiguration();}public void setWifiApConfiguration(WifiConfiguration wifiConfig) { mWifiStateMachine.setWifiApConfiguration(wifiConfig);}
消息循环,状态机 frameworks/base/wifi/java/android/net/wifi/WifiStateMachine.java
public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enable) { if (enable) { sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_AP_STATE_ENABLING, 0)); sendMessage(obtainMessage(CMD_START_AP, wifiConfig)); } else { sendMessage(CMD_STOP_AP); sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_DISABLED, 0)); }}public void setWifiApConfiguration(WifiConfiguration config) { mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config);}public WifiConfiguration syncGetWifiApConfiguration() { Message resultMsg = mWifiApConfigChannel.sendMessageSynchronously(CMD_REQUEST_AP_CONFIG); WifiConfiguration ret = (WifiConfiguration) resultMsg.obj; resultMsg.recycle(); return ret;}public int syncGetWifiApState() { return mWifiApState.get();}public String syncGetWifiApStateByName() { switch (mWifiApState.get()) { case WIFI_AP_STATE_DISABLING: return "disabling"; case WIFI_AP_STATE_DISABLED: return "disabled"; case WIFI_AP_STATE_ENABLING: return "enabling"; case WIFI_AP_STATE_ENABLED: return "enabled"; case WIFI_AP_STATE_FAILED: return "failed"; default: return "[invalid state]"; }}class SoftApStartingState extends State { @Override public void enter() { if (DBG) log(getName() + "\n"); EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); final Message message = getCurrentMessage(); if (message.what == CMD_START_AP) { final WifiConfiguration config = (WifiConfiguration) message.obj; if (config == null) { mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG); } else { mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config); startSoftApWithConfig(config); //开启Ap功能 } } else { throw new RuntimeException("Illegal transition to SoftApStartingState: " + message); } } @Override public boolean processMessage(Message message) { if (DBG) log(getName() + message.toString() + "\n"); switch(message.what) { case WifiStateMachine.CMD_RESPONSE_AP_CONFIG: WifiConfiguration config = (WifiConfiguration) message.obj; if (config != null) { startSoftApWithConfig(config); //开启Ap功能 } else { loge("Softap config is null!"); sendMessage(CMD_START_AP_FAILURE); } break; case CMD_START_AP_SUCCESS: setWifiApState(WIFI_AP_STATE_ENABLED); transitionTo(mSoftApStartedState); break; } }}private void startSoftApWithConfig(final WifiConfiguration config) { new Thread(new Runnable() { public void run() { try { mNwService.startAccessPoint(config, mInterfaceName); } catch (Exception e) { loge("Exception in softap start " + e); try { mNwService.stopAccessPoint(mInterfaceName); //开启Ap功能 mNwService.startAccessPoint(config, mInterfaceName); //开启Ap功能 } catch (Exception e1) { loge("Exception in softap re-start " + e1); sendMessage(CMD_START_AP_FAILURE); return; } } if (DBG) log("Soft AP start successful"); sendMessage(CMD_START_AP_SUCCESS); } }).start();}
3.NMS进程 frameworks/base/services/java/com/android/server/NetworkManagementService.java
public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface) { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); try { wifiFirmwareReload(wlanIface, "AP"); if (wifiConfig == null) { mConnector.execute("softap", "set", wlanIface);/*mConnector = new NativeDaemonConnector( new NetdCallbackReceiver(), "netd", 10, NETD_TAG, 160);*/ } else { mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID, getSecurityType(wifiConfig), wifiConfig.preSharedKey); } mConnector.execute("softap", "startap"); } catch (NativeDaemonConnectorException e) { throw e.rethrowAsParcelableException(); }}
4.netd进程 system/netd/CommandListener.cpp
int CommandListener::SoftapCmd::runCommand(SocketClient *cli, int argc, char **argv) { if (!strcmp(argv[1], "startap")) { rc = sSoftapCtrl->startSoftap(); } else if (!strcmp(argv[1], "stopap")) { rc = sSoftapCtrl->stopSoftap(); } else if (!strcmp(argv[1], "fwreload")) { rc = sSoftapCtrl->fwReloadSoftap(argc, argv); } else if (!strcmp(argv[1], "clients")) { rc = sSoftapCtrl->clientsSoftap(&retbuf); if (!rc) { cli->sendMsg(ResponseCode::CommandOkay, retbuf, false); free(retbuf); return 0; } } else if (!strcmp(argv[1], "status")) { asprintf(&retbuf, "Softap service %s", (sSoftapCtrl->isSoftapStarted() ? "started" : "stopped")); cli->sendMsg(ResponseCode::SoftapStatusResult, retbuf, false); free(retbuf); return 0; } else if (!strcmp(argv[1], "set")) { rc = sSoftapCtrl->setSoftap(argc, argv); } else { cli->sendMsg(ResponseCode::CommandSyntaxError, "Softap Unknown cmd", false); return 0; }}
system/netd/SoftapController.cpp int SoftapController::setSoftap(int argc, char *argv[]) { if (argc > 3) { ssid = argv[3]; } else { ssid = (char *)"AndroidAP"; } asprintf(&wbuf, "interface=%s\ndriver=nl80211\nctrl_interface=" "/data/misc/wifi/hostapd\nssid=%s\nchannel=6\nieee80211n=1\n", iface, ssid); if (argc > 4) { if (!strcmp(argv[4], "wpa-psk")) { generatePsk(ssid, argv[5], psk_str); asprintf(&fbuf, "%swpa=1\nwpa_pairwise=TKIP CCMP\nwpa_psk=%s\n", wbuf, psk_str); } else if (!strcmp(argv[4], "wpa2-psk")) { generatePsk(ssid, argv[5], psk_str); asprintf(&fbuf, "%swpa=2\nrsn_pairwise=CCMP\nwpa_psk=%s\n", wbuf, psk_str); } else if (!strcmp(argv[4], "open")) { asprintf(&fbuf, "%s", wbuf); } } else { asprintf(&fbuf, "%s", wbuf); } //static const char HOSTAPD_CONF_FILE[] = "/data/misc/wifi/hostapd.conf"; //配置文件/data/misc/wifi/hostapd.conf fd = open(HOSTAPD_CONF_FILE, O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW, 0660); if (write(fd, fbuf, strlen(fbuf)) < 0) { ALOGE("Cannot write to \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno)); ret = -1; }}int SoftapController::startSoftap() { if ((pid = fork()) < 0) { ALOGE("fork failed (%s)", strerror(errno)); return -1; } if (!pid) { ensure_entropy_file_exists(); if (execl("/system/bin/hostapd", "/system/bin/hostapd", "-e", WIFI_ENTROPY_FILE, HOSTAPD_CONF_FILE, (char *) NULL)) { ALOGE("execl failed (%s)", strerror(errno)); } ALOGE("Should never get here!"); return -1; } else { mPid = pid; ALOGD("Softap startap - Ok"); usleep(AP_BSS_START_DELAY); }}
补充:
dnsmasq及dhcp相关
system/netd/TetherController.cpp
iptables相关
system/netd/NetdConstants.cpp
5.hostapd进程
external/wpa_supplicant_8/hostapd/main.c
int main(int argc, char *argv[]){}
external/wpa_supplicant_8/src/ap/hostapd.c
鉴权相关
external/wpa_supplicant_8/hostapd/src/ap/wpa_auth.c
二、测试
基于NT667-Android4.2平台
1.加载wifi驱动
uid=0 gid=0@android:/system/lib/modules # isnmod 8812au.ko
2.运行AP功能
hostapd -e /data/misc/wifi/entropy.bin /data/misc/wifi/hostapd.conf
vi /data/misc/wifi/hostapd.conf
interface=wlan0driver=nl80211ctrl_interface=/data/misc/wifi/hostapdssid=TanKaiSoftAP#wpa_passphrase=0123456789channel=6ieee80211n=1wpa=0#wpa=2rsn_pairwise=CCMPwpa_psk=20c7dff358c6481bd7278907adb988b8ca7217bc407674b18a59b5c7f81bcc09
至此,可以搜索到SofrAP热点并连接上。
3.可以搜索到TanKaiSoftAP热点,并链接;卡在了获取IP地址这里
设置无线网卡IP
ifconfig wlan0 192.168.100.1 netmask 255.255.255.0
启动DHCP
dnsmasq --no-daemon --no-resolv --no-poll --dhcp-range=192.168.100.100,192.168.100.200,100h
当然也可以把相关配置写成文件再执行dnsmasq --conf-file=/*path*/dnsmasq.conf
至此,可以搜索到SoftAP并获取IP地址;但不能上外网。
5.可以获取IP地址,但不能上网;iptables设置
echo 1 > /proc/sys/net/ipv4/ip_forwardiptables -A FORWARD -i wlap0 -o eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT iptables -A FORWARD -i wlap0 -o eth0 -j ACCEPT iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
至此,软AP功能调通;手机连接具有软AP功能的电视可以正常访问外网。
三、wext驱动实现方式时的项目问题
我们使用的MTK平台SoftAP实现方式非Android标准;不使用hostapd,而且wifi驱动不是nl80211而是wext模式。
WIFI的Linux驱动部分wext和nl80211
转载:
MTK启动无线热点的过程
1.驱动加载
cd /system/lib/modulesinsmod mt7601Uap.koifconfig ra0 10.10.10.1
配置文件
/system/etc/Wireless/RT2870AP/RT2870AP.dat
卸载驱动
ifconfig ra0 downrmmod mt7601Uap.ko
2.调试netd--ndc
转载:
Android 4.1 Netd详细分析(一)概述与应用实例
ndc是Android为Netd提供的一个测试工具。其主要功能有:
监视Netd中发生的事情。
支持通过命令行发送命令给Netd去执行。
ndc softap set ra0 TankaiMtk closendc softap startapdnsmasq --no-daemon --no-resolv --no-poll --dhcp-range=10.10.10.100,10.10.10.200,100hecho 1 > /proc/sys/net/ipv4/ip_forwardiptables -A FORWARD -i ra0 -o eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT iptables -A FORWARD -i ra0 -o eth0 -j ACCEPT iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADEndc softap stopapifconfig ra0 down
3.桥接
brctl addbr br0brctl addif br0 eth0brctl addif br0 ra0ifconfig eth0 0.0.0.0ifconfig ra0 0.0.0.0ip link set br0 upip addr add 192.168.5.234/24 brd + dev br0ip route add default via 192.168.5.254
移植brctl: bridge-utils
运行报错:
add bridge failed: Package not installed
内核添加bridge支持:
linux-3.0/net/bridge/
make menuconfig
Networking support->Networking options->802.1d Ethernet Bridging
更多相关文章
- 在android下获取有线和无线IP地址的方法,经测试可用
- 圆角android
- framework——应用进程启动流程
- Android(安卓)Property System
- 搜集的android资源
- Android(安卓)ListView长按弹出CheckBox,实现全选,反选,批量删除功
- Android中实现输入图片地址浏览图片操作
- 整理 酷炫 Android(安卓)开源UI框架 刷新