Android(安卓)中SoftAP架构研究
Android中网络的整体架构如下:
NetworkmanagementService
此模块运行在SystemService中,负责Java层的实现机制,提供对上层的一些运行接口,当然,上层是通过一些抽象类实现进程间通讯进行访问的。
NetD
此模块是C++的Daemon,负责底层部分对于一些关键网络服务的管理。对上面Java服务提供接口,采用进程间通讯的方式。
Wpa_supplicant
此模块是提供WIFI支持的模块,不做详细描述了。在Android中是一个关键的底层服务。
Dnsmasq
此服务实现了DHCP Server,用于辅助Hostapd,实现IP的管理。
Hosted
此服务实现了WIFI AP的关键服务,直接控制底层设备,此服务正常运行后,其他终端可以搜索到AP,并连接。
以下是启动WIFI AP 的流程:
以下是代码说明:
NetworkManagementService
base/wifi/java/android/net/wifi/WifiStateMachine.javaprivate void startSoftApWithConfig(final WifiConfiguration config)
frameworks/base/services/java/com/android/server/NetworkManagementService.java // 网路管理服务
startAccessPoint {...}wifiFirmwareReload(wlanIface, "AP");mConnector.execute("softap", "set", wlanIface);mConnector.execute("softap", "startap");
system/netd/CommandListener.cpp // 通讯用得CommandListener
CommandListener::SoftapCmd::runCommand
NetD 服务
system/netd/SoftapController.cpp
SoftapController::startSoftap()static const char HOSTAPD_CONF_FILE[] = "/data/misc/wifi/hostapd.conf";#define WIFI_ENTROPY_FILE "/data/misc/wifi/entropy.bin"ensure_entropy_file_exists(); // 检查需要加密文件是否存在 if (execl("/system/bin/hostapd", "/system/bin/hostapd", //启动Hostapd "-e", WIFI_ENTROPY_FILE, HOSTAPD_CONF_FILE, (char *) NULL)) { ALOGE("execl failed (%s)", strerror(errno));}SoftapController::stopSoftap // 停止Hostapdkill(mPid, SIGTERM); // 结束Hostapdwaitpid(mPid, NULL, 0) // 等待结束返回
system/netd/TetherController.cpp // DHCP daemon 管理
startTethering() {..."system/bin/dnsmasq" // 启动Dnsmasq后台进程...}
启动Hostapd
SoftapController::startSoftap()static const char HOSTAPD_CONF_FILE[] = "/data/misc/wifi/hostapd.conf";#define WIFI_ENTROPY_FILE "/data/misc/wifi/entropy.bin"ensure_entropy_file_exists(); // 检查需要加密文件是否存在 if (execl("/system/bin/hostapd", "/system/bin/hostapd", //启动Hostapd "-e", WIFI_ENTROPY_FILE, HOSTAPD_CONF_FILE, (char *) NULL)) { ALOGE("execl failed (%s)", strerror(errno));}SoftapController::stopSoftap // 停止Hostapdkill(mPid, SIGTERM); // 结束Hostapdwaitpid(mPid, NULL, 0) // 等待结束返回
WIFI AP 参数设置
int SoftapController::setSoftap(int argc, char *argv[]) {... property_get("wifi.interface", iface, "wlan0"); char *wbuf = NULL; char *fbuf = NULL; 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 (!strncmp("wep", argv[4], 3)){ if((strlen(argv[5]) == 5) || (strlen(argv[5]) == 13)) asprintf(&fbuf, "%swep_default_key=0\nwep_key0=\"%s\"\n", wbuf,argv[5]); else asprintf(&fbuf, "%swep_default_key=0\nwep_key0=%s\n", wbuf,argv[5]); } else if (!strcmp(argv[4], "open")) { asprintf(&fbuf, "%s", wbuf); } } else { asprintf(&fbuf, "%s", wbuf); } fd = open(HOSTAPD_CONF_FILE, O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW, 0660); if (fd < 0) { ALOGE("Cannot update \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno)); free(wbuf); free(fbuf); return -1; } if (write(fd, fbuf, strlen(fbuf)) < 0) { ALOGE("Cannot write to \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno)); ret = -1; } free(wbuf); free(fbuf); if (fchmod(fd, 0660) < 0) { ALOGE("Error changing permissions of %s to 0660: %s", HOSTAPD_CONF_FILE, strerror(errno)); close(fd); unlink(HOSTAPD_CONF_FILE); return -1; } if (fchown(fd, AID_SYSTEM, AID_WIFI) < 0) { ALOGE("Error changing group ownership of %s to %d: %s", HOSTAPD_CONF_FILE, AID_WIFI, strerror(errno)); close(fd); unlink(HOSTAPD_CONF_FILE); return -1; } close(fd); return ret;}
PSK Key 的生成
wpa-psk和wpa2-psk 需要生成PSK
#include void SoftapController::generatePsk(char *ssid, char *passphrase, char *psk_str) { unsigned char psk[SHA256_DIGEST_LENGTH]; int j; // Use the PKCS#5 PBKDF2 with 4096 iterations PKCS5_PBKDF2_HMAC_SHA1(passphrase, strlen(passphrase), reinterpret_cast(ssid), strlen(ssid), 4096, SHA256_DIGEST_LENGTH, psk); for (j=0; j < SHA256_DIGEST_LENGTH; j++) { sprintf(&psk_str[j<<1], "%02x", psk[j]); } psk_str[j<<1] = '\0';}
重载Firmware的机制
hardware/libhardware_legacy/wifi/wifi.c // wifi interface of HAL
system/netd/SoftapController.cpp wifi_change_fw_path 重载Firmware
hardware/libhardware_legacy/wifi/wifi.c wifi_change_fw_path 重载Firmware
重载固件用得设备节点定义
#define WIFI_DRIVER_FW_PATH_PARAM "/sys/module/wlan/parameters/fwpath" (原始) "/sys/module/bcmdhd/parameters/firmware_path" (k900)
固件文件的地址
WIFI_DRIVER_FW_PATH_AP "/system/etc/firmware/fw_bcmdhd_apsta.bin" 文件地址
Dnsmasq 代码启动流程如下
接收内核消息:Iface added wlan0然后就会调用到notifyInterfaceAdded
NetworkManagementService.java
private voidnotifyInterfaceAdded(String iface) { for(INetworkManagementEventObserverobs : mObservers) { try{ obs.interfaceAdded(iface);//回调tethering. interfaceAdded } catch(Exception ex) { Slog.w(TAG, "Observer notifier failed", ex); } } }
Tethering.java
public void interfaceAdded(String iface) {//被回调到的函数 if(VDBG) Log.d(TAG, "interfaceAdded "+ iface); booleanfound = false; booleanusb = false; synchronized(mPublicSync) { if(isWifi(iface)) { found = true; } if(isUsb(iface)) { found = true; usb = true; } if(isBluetooth(iface)) { found = true; } if(found == false) { if(VDBG) Log.d(TAG, iface + " is not a tetherable iface, ignoring"); return; } TetherInterfaceSM sm = mIfaces.get(iface); if(sm != null) { if(VDBG) Log.d(TAG, "active iface ("+ iface + ") reported as added, ignoring"); return; } sm = newTetherInterfaceSM(iface, mLooper, usb);//创建TetherInterfaceSM对象,然后会生成InitialState对象,调用InitialState.enter mIfaces.put(iface, sm); sm.start(); } } classInitialState extendsState { @Override public voidenter() { setAvailable(true); setTethered(false); sendTetherStateChangedBroadcast();//发送广播 } private voidsendTetherStateChangedBroadcast() { try{ if(!mConnService.isTetheringSupported()) return; } catch(RemoteException e) { return; } ArrayList availableList = newArrayList(); ArrayList activeList = newArrayList(); ArrayList erroredList = newArrayList(); booleanwifiTethered = false; booleanusbTethered = false; booleanbluetoothTethered = false; synchronized(mPublicSync) { Setifaces = mIfaces.keySet(); for(Object iface : ifaces) { TetherInterfaceSM sm = mIfaces.get(iface); if(sm != null) { if(sm.isErrored()) { erroredList.add((String)iface); } else if(sm.isAvailable()) { availableList.add((String)iface); } else if(sm.isTethered()) { if(isUsb((String)iface)) { usbTethered = true; } else if(isWifi((String)iface)) { wifiTethered = true; } else if(isBluetooth((String)iface)) { bluetoothTethered = true; } activeList.add((String)iface); } } } } Intent broadcast = newIntent(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);//发送广播到WifiStateMachine broadcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING| Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
WifiStateMachine.java
mContext.registerReceiver( newBroadcastReceiver() { @Override public voidonReceive(Context context, Intent intent) { ArrayList available = intent.getStringArrayListExtra( ConnectivityManager.EXTRA_AVAILABLE_TETHER); ArrayList active = intent.getStringArrayListExtra( ConnectivityManager.EXTRA_ACTIVE_TETHER); sendMessage(CMD_TETHER_STATE_CHANGE, newTetherStateChange(available, active));//发送消息 CMD_TETHER_STATE_CHANGE } },newIntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));//接收到广播 classSoftApStartedState extendsState { @Override public voidenter() { if(DBG) log(getName() + "\n"); EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); } @Override public booleanprocessMessage(Message message) { if(DBG) log(getName() + message.toString() + "\n"); switch(message.what) { case CMD_STOP_AP: if(DBG) log("Stopping Soft AP"); setWifiApState(WIFI_AP_STATE_DISABLING); /* We have not tethered at this point, so we just shutdown soft Ap */ try{ mNwService.stopAccessPoint(mInterfaceName); } catch(Exception e) { loge("Exception in stopAccessPoint()"); } transitionTo(mDriverLoadedState); break; case CMD_START_AP: // Ignore a start on a running access point break; /* Fail client mode operation when soft AP is enabled */ case CMD_START_SUPPLICANT: loge("Cannot start supplicant with a running soft AP"); setWifiState(WIFI_STATE_UNKNOWN); break; case CMD_TETHER_STATE_CHANGE://接收CMD_TETHER_STATE_CHANGE TetherStateChange stateChange = (TetherStateChange) message.obj; if (startTethering(stateChange.available)) {//调用startTethering transitionTo(mTetheringState); }private boolean startTethering(ArrayList available) { boolean wifiAvailable = false; checkAndSetConnectivityInstance(); String[] wifiRegexs = mCm.getTetherableWifiRegexs(); for (String intf : available) { for (String regex : wifiRegexs) { if (intf.matches(regex)) { InterfaceConfiguration ifcg = null; try { ifcg = mNwService.getInterfaceConfig(intf); if (ifcg != null) { /* IP/netmask: 192.168.43.1/255.255.255.0 */ ifcg.addr = new LinkAddress(NetworkUtils.numericToInetAddress( "192.168.43.1"), 24); ifcg.interfaceFlags = "[up]"; mNwService.setInterfaceConfig(intf, ifcg); } } catch (Exception e) { loge("Error configuring interface " + intf + ", :" + e); return false; } if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {// 调用ConnectivityManager. tether loge("Error tethering on " + intf); return false; }
ConnectivityManager.java
public int tether(String iface) { try { return mService.tether(iface);//调用ConnectivityService.tether } catch (RemoteException e) { return TETHER_ERROR_SERVICE_UNAVAIL; } }
ConnectivityService.java
// javadocfrom interface public inttether(String iface) { enforceTetherChangePermission(); if(isTetheringSupported()) { return mTethering.tether(iface);//调用Tethering.tether } else{ returnConnectivityManager.TETHER_ERROR_UNSUPPORTED; } }
Tethering.java (\\192.168.80.102\tomchen\8680v6\android\frameworks\base\services\java\com\android\server\connectivity)
public int tether(String iface)//调用这个函数
sm.sendMessage(TetherInterfaceSM.CMD_TETHER_REQUESTED);//发送消息
classInitialState extendsState { @Override public voidenter() { setAvailable(true); setTethered(false); sendTetherStateChangedBroadcast(); } @Override public booleanprocessMessage(Message message) { if(DBG) Log.d(TAG, "InitialState.processMessage what="+ message.what); booleanretValue = true; switch(message.what) { case CMD_TETHER_REQUESTED://接收消息 setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR); mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_REQUESTED, TetherInterfaceSM.this); transitionTo(mStartingState);//转到etherModeAliveState break; classTetherModeAliveState extendsTetherMasterUtilState { boolean mTryCell= !WAIT_FOR_NETWORK_TO_SETTLE; @Override public voidenter() { turnOnMasterTetherSettings(); // may transition us out//进入状态的时候会被调 mTryCell= !WAIT_FOR_NETWORK_TO_SETTLE; // better try something first pass // or crazy tests cases will fail chooseUpstreamType(mTryCell); mTryCell= !mTryCell; }
设置wlan0的IP地址
frameworks/base/wifi/java/android/net/wifi/WifiStateMachine.javamNwService.setInterfaceConfigsystem/netd/CommandListener.cppelse if (!strcmp(argv[1], "setcfg")){...ifc_set_addr...}system/core/libnetutils/ifc_utils.cint ifc_set_addr(const char *name, in_addr_t addr)
Lenovo K900中使能Hostapd的方法
echo "/system/etc/firmware/fw_bcmdhd_apsta.bin" > /sys/module/bcmdhd/parameters/firmware_path
ifconfig wlan0 up
hostapd -dd hostapd.conf
/system/bin/dnsmasq --keep-in-foreground --no-resolv --no-poll --dhcp-option-force=43,ANDROID_METERED --pid-file --dhcp-script=/system/bin/dhcp_announce --dhcp-range=2,5,1h
更多相关文章
- 使用android studio 配置搭建应用介绍
- Android~Fragment的替代方案
- Android(安卓)通过module进行开发
- Android应用开发笔记(12):Android应用的自动升级、更新模块的实现
- Android(安卓)MP3项目
- 在Ubuntu上为Android增加硬件抽象层(HAL)模块访问Linux内核驱动程
- Android运行时
- Android系统编译及单模块编译简介
- android添加底层核心服务