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.java
private 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 // 停止Hostapd
kill(mPid, SIGTERM); // 结束Hostapd
waitpid(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 // 停止Hostapd
kill(mPid, SIGTERM); // 结束Hostapd
waitpid(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.java
mNwService.setInterfaceConfig
system/netd/CommandListener.cpp
else if (!strcmp(argv[1], "setcfg")){
...
ifc_set_addr
...
}
system/core/libnetutils/ifc_utils.c
int 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