SoftAP (Access Point,无线访问节点),就是通过软件方式提供接入功能,android手机开启AP或热点,其他手机通过wifi可以接入。其他手机称为Station,工作模式位Sta模式。
android softap框架
从settings app开始在设置中开启:
/packages/apps/Settings/src/com/android/settings/TetherSettings.Java 的onPreferenceChange 函数接收到Softap状态改变信息
public boolean onPreferenceChange(Preference preference, Object value) {
boolean enable = (Boolean) value;
if (enable) {
startProvisioningIfNecessary(TETHERING_WIFI); //开启
} else {
if (TetherUtil.isProvisioningNeeded(getActivity())) {
TetherService.cancelRecheckAlarmIfNecessary(getActivity(), TETHERING_WIFI);
}
mWifiApEnabler.setSoftapEnabled(false);
}
return false;
}
private void startProvisioningIfNecessary(int choice) {
mTetherChoice = choice;
if (TetherUtil.isProvisioningNeeded(getActivity())) {//如果有准备工作,执行
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setClassName(mProvisionApp[0], mProvisionApp[1]);
intent.putExtra(TETHER_CHOICE, mTetherChoice);
startActivityForResult(intent, PROVISION_REQUEST);
} else {
startTethering();//继续开启
}
}
private void startTethering() {
switch (mTetherChoice) {
case TETHERING_WIFI:
mWifiApEnabler.setSoftapEnabled(true); //设置wifi使能
break;
case TETHERING_BLUETOOTH:
// turn on Bluetooth first
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter.getState() == BluetoothAdapter.STATE_OFF) {
mBluetoothEnableForTether = true;
adapter.enable();
mBluetoothTether.setSummary(R.string.bluetooth_turning_on);
mBluetoothTether.setEnabled(false);
} else {
BluetoothPan bluetoothPan = mBluetoothPan.get();
if (bluetoothPan != null) bluetoothPan.setBluetoothTethering(true);
mBluetoothTether.setSummary(R.string.bluetooth_tethering_available_subtext);
}
break;
case TETHERING_USB:
setUsbTethering(true);
break;
default:
//should not happen
break;
}
}
mWifiApEnabler.setSoftapEnabled(true) 调用,
./packages/apps/Settings/src/com/android/settings/wifi/WifiApEnabler.java
public void setSoftapEnabled(boolean enable) {
if (TetherUtil.setWifiTethering(enable, mContext)) { //继续设置
/* Disable here, enabled on receiving success broadcast */
mSwitch.setEnabled(false);
} else {
mSwitch.setSummary(R.string.wifi_error);
}
}
TetherUtil.setWifiTethering(enable, mContext)开始调用 frameworks层代码,进入了 frameworks层。
frameworks/base/packages/SettingsLib/TetherUtil.java
public static boolean setWifiTethering(boolean enable, Context context) {
final WifiManager wifiManager =
(WifiManager) context.getSystemService(Context.WIFI_SERVICE);
return wifiManager.setWifiApEnabled(null, enable);//调用WifiManager中setWifiApEnabled
}
./frameworks/base/wifi/java/android/net/wifi/WifiManager.java
public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
try {
mService.setWifiApEnabled(wifiConfig, enabled);//调用wifiservice
return true;
} catch (RemoteException e) {
return false;
}
}
服务层
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiService.java
public final class WifiService extends SystemService {
private static final String TAG = "WifiService";
final WifiServiceImpl mImpl;
public WifiService(Context context) {
super(context);
mImpl = new WifiServiceImpl(context);
}
}
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java
public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
enforceChangePermission();
ConnectivityManager.enforceTetherChangePermission(mContext);
if (mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {
throw new SecurityException("DISALLOW_CONFIG_TETHERING is enabled for this user.");
}
// null wifiConfig is a meaningful input for CMD_SET_AP
if (wifiConfig == null || isValid(wifiConfig)) {
//obtainMessage产生一个message并发送到mWifiController对象处理,CMD_SET_AP 使能
mWifiController.obtainMessage(CMD_SET_AP, enabled ? 1 : 0, 0, wifiConfig).sendToTarget();
} else {
Slog.e(TAG, "Invalid WifiConfiguration");
}
}
WifiController处理
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiController.java
//当前为disable状态
class ApStaDisabledState extends State {
public boolean processMessage(Message msg) {
switch (msg.what) {
case CMD_SET_AP:
if (msg.arg1 == 1) {
if (msg.arg2 == 0) { // previous wifi state has not been saved yet
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.WIFI_SAVED_STATE, WIFI_DISABLED);
}
//开启wifi
mWifiStateMachine.setHostApRunning((WifiConfiguration) msg.obj,
true);
transitionTo(mApEnabledState);
}
break;
......
}
}
进入wifi状态机
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java
public void setHostApRunning(WifiConfiguration wifiConfig, boolean enable) {
if (enable) {
sendMessage(CMD_START_AP, wifiConfig); //发送开启wifi ap命令
} else {
sendMessage(CMD_STOP_AP);
}
}
//当前为初始状态
class InitialState extends State {
@Override
public void enter() {
WifiNative.stopHal(); 先停止hal
mWifiNative.unloadDriver(); 卸载驱动
if (mWifiP2pChannel == null) {
mWifiP2pChannel = new AsyncChannel();
mWifiP2pChannel.connect(mContext, getHandler(),
mWifiP2pServiceImpl.getP2pStateMachineMessenger());
}
if (mWifiApConfigChannel == null) {
mWifiApConfigChannel = new AsyncChannel();
mWifiApConfigStore = WifiApConfigStore.makeWifiApConfigStore(
mContext, getHandler());
mWifiApConfigStore.loadApConfiguration();加载配置
mWifiApConfigChannel.connectSync(mContext, getHandler(),
mWifiApConfigStore.getMessenger());
}
if (mWifiConfigStore.enableHalBasedPno.get()) {
// make sure developer Settings are in sync with the config option
mHalBasedPnoEnableInDevSettings = true;
}
}
public boolean processMessage(Message message) {
logStateAndMessage(message, getClass().getSimpleName());
switch (message.what) {
......
case CMD_START_AP:
if (mWifiNative.loadDriver() == false) { 调用native jni方法,加载wifi ap驱动
loge("Failed to load driver for softap");
} else {
if (enableSoftAp() == true) { 继续
setWifiApState(WIFI_AP_STATE_ENABLING, 0);//转换状态
transitionTo(mSoftApStartingState);
} else {
setWifiApState(WIFI_AP_STATE_FAILED,
WifiManager.SAP_START_FAILURE_GENERAL);
transitionTo(mInitialState);
}
}
break;
.......
}
return HANDLED;
}
}
先看调用native jni方法,加载wifi ap驱动
frameworks/opt/net/wifi/service/jni/com_android_server_wifi_WifiNative.cpp
static jboolean android_net_wifi_loadDriver(JNIEnv* env, jobject)
{
return (::wifi_load_driver() == 0);继续调用HLA层驱动
}
hardware/libhardware_legacy/wifi/wifi.c
int wifi_load_driver()
{
//如果定义WIFI_DRIVER_MODULE_PATH,指定了驱动module路径,
//实际就是执行insmod安装驱动module
//WIFI_DRIVER_MODULE_PATH一般在device目录下mk文件中定义
//wifi驱动可以直接和kernel编译在一起,启动阶段就加载,所以不用module,也就不用定义WIFI_DRIVER_MODULE_PATH
#ifdef WIFI_DRIVER_MODULE_PATH
char driver_status[PROPERTY_VALUE_MAX];
int count = 100; /* wait at most 20 seconds for completion */
if (is_wifi_driver_loaded()) { //判断驱动是否已经加载,看属性值
return 0;
}
if (insmod(DRIVER_MODULE_PATH, DRIVER_MODULE_ARG) < 0) //安装ko驱动
return -1;
if (strcmp(FIRMWARE_LOADER,"") == 0) {
/* usleep(WIFI_DRIVER_LOADER_DELAY); */
property_set(DRIVER_PROP_NAME, "ok");//设置驱动属性已经ok,wlan.driver.status
}
else {
property_set("ctl.start", FIRMWARE_LOADER);
}
sched_yield();
while (count-- > 0) {
if (property_get(DRIVER_PROP_NAME, driver_status, NULL)) {
if (strcmp(driver_status, "ok") == 0)
return 0;
else if (strcmp(driver_status, "failed") == 0) {
wifi_unload_driver();
return -1;
}
}
usleep(200000);
}
property_set(DRIVER_PROP_NAME, "timeout");
wifi_unload_driver();
return -1;
#else
#ifdef WIFI_DRIVER_STATE_CTRL_PARAM
if (is_wifi_driver_loaded()) {
return 0;
}
if (wifi_change_driver_state(WIFI_DRIVER_STATE_ON) < 0)//改变驱动状态
return -1;
#endif
property_set(DRIVER_PROP_NAME, "ok");//设置驱动属性已经ok,wlan.driver.status
return 0;
#endif
}
int is_wifi_driver_loaded() {
char driver_status[PROPERTY_VALUE_MAX];
#ifdef WIFI_DRIVER_MODULE_PATH
FILE *proc;
char line[sizeof(DRIVER_MODULE_TAG)+10];
#endif
if (!property_get(DRIVER_PROP_NAME, driver_status, NULL)
|| strcmp(driver_status, "ok") != 0) {
return 0; /* driver not loaded */
}
#ifdef WIFI_DRIVER_MODULE_PATH
/*
* If the property says the driver is loaded, check to
* make sure that the property setting isn't just left
* over from a previous manual shutdown or a runtime
* crash.
*/
if ((proc = fopen(MODULE_FILE, "r")) == NULL) {
ALOGW("Could not open %s: %s", MODULE_FILE, strerror(errno));
property_set(DRIVER_PROP_NAME, "unloaded");
return 0;
}
while ((fgets(line, sizeof(line), proc)) != NULL) {
if (strncmp(line, DRIVER_MODULE_TAG, strlen(DRIVER_MODULE_TAG)) == 0) {
fclose(proc);
return 1;
}
}
fclose(proc);
property_set(DRIVER_PROP_NAME, "unloaded");
return 0;
#else
return 1;
#endif
}
#ifdef WIFI_DRIVER_STATE_CTRL_PARAM
int wifi_change_driver_state(const char *state)
{
int len;
int fd;
int ret = 0;
if (!state)
return -1;
fd = TEMP_FAILURE_RETRY(open(WIFI_DRIVER_STATE_CTRL_PARAM, O_WRONLY));
if (fd < 0) {
ALOGE("Failed to open driver state control param (%s)", strerror(errno));
return -1;
}
len = strlen(state) + 1;
if (TEMP_FAILURE_RETRY(write(fd, state, len)) != len) {
ALOGE("Failed to write driver state control param (%s)", strerror(errno));
ret = -1;
}
close(fd);
return ret;
}
#endif
至此wifi驱动加载完成。
继续使能softap,还是在状态机中
if (enableSoftAp() == true) { //继续
setWifiApState(WIFI_AP_STATE_ENABLING, 0);//转换状态
transitionTo(mSoftApStartingState);
}
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java
/* SoftAP configuration */
private boolean enableSoftAp() {
if (WifiNative.getInterfaces() != 0) {//native方法获取接口
if (!mWifiNative.toggleInterface(0)) {
if (DBG) Log.e(TAG, "toggleInterface failed");
return false;
}
} else {
if (DBG) Log.d(TAG, "No interfaces to toggle");
}
try {
mNwService.wifiFirmwareReload(mInterfaceName, "AP");//加载固件,接口名字和AP模式
if (DBG) Log.d(TAG, "Firmware reloaded in AP mode");
} catch (Exception e) {
Log.e(TAG, "Failed to reload AP firmware " + e);
}
if (WifiNative.startHal() == false) {//开启hal
/* starting HAL is optional */
Log.e(TAG, "Failed to start HAL");
}
return true;
}
mNwService.wifiFirmwareReload:
/frameworks/base/services/core/java/com/android/server/NetworkManagementService.java
NetworkManagementService由于通过 netd socket 和 Netd 交互
/* @param mode can be "AP", "STA" or "P2P" */
@Override
public void wifiFirmwareReload(String wlanIface, String mode) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
mConnector.execute("softap", "fwreload", wlanIface, mode); 和netd通信,执行命令softap,fwreload
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
}
后面再看netd
enableSoftAp成功后,wifi状态机转换状态到mSoftApStartingState
if (enableSoftAp() == true) { //继续
setWifiApState(WIFI_AP_STATE_ENABLING, 0);//转换状态
transitionTo(mSoftApStartingState);//转换状态机
}
class SoftApStartingState extends State {
@Override
public void enter() {
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); //进行配置
}
} else {
throw new RuntimeException("Illegal transition to SoftApStartingState: " + message);
}
}
startSoftApWithConfig:
/* Current design is to not set the config on a running hostapd but instead
* stop and start tethering when user changes config on a running access point
*
* TODO: Add control channel setup through hostapd that allows changing config
* on a running daemon
*/
private void startSoftApWithConfig(final WifiConfiguration configuration) {
// set channel
final WifiConfiguration config = new WifiConfiguration(configuration);
if (DBG) {
Log.d(TAG, "SoftAp config channel is: " + config.apChannel);
}
//We need HAL support to set country code and get available channel list, if HAL is
//not available, like razor, we regress to original implementaion (2GHz, channel 6)
if (mWifiNative.isHalStarted()) {
//set country code through HAL Here
String countryCode = getCurrentCountryCode();//国家code
if (countryCode != null) {
if (!mWifiNative.setCountryCodeHal(countryCode.toUpperCase(Locale.ROOT))) {
if (config.apBand != 0) {
Log.e(TAG, "Fail to set country code. Can not setup Softap on 5GHz");
//countrycode is mandatory for 5GHz
sendMessage(CMD_START_AP_FAILURE, WifiManager.SAP_START_FAILURE_GENERAL);
return;
}
}
} else {
if (config.apBand != 0) {
//countrycode is mandatory for 5GHz
Log.e(TAG, "Can not setup softAp on 5GHz without country code!");
sendMessage(CMD_START_AP_FAILURE, WifiManager.SAP_START_FAILURE_GENERAL);
return;
}
}
if (config.apChannel == 0) {
config.apChannel = chooseApChannel(config.apBand);
if (config.apChannel == 0) {
if(mWifiNative.isGetChannelsForBandSupported()) {
//fail to get available channel
sendMessage(CMD_START_AP_FAILURE, WifiManager.SAP_START_FAILURE_NO_CHANNEL);
return;
} else {
//for some old device, wifiHal may not be supportedget valid channels are not
//supported
config.apBand = 0; //带宽
config.apChannel = 6; //信道个数
}
}
}
} else {
//for some old device, wifiHal may not be supported
config.apBand = 0;
config.apChannel = 6;
}
// Start hostapd on a separate thread
new Thread(new Runnable() {
public void run() {
try {
mNwService.startAccessPoint(config, mInterfaceName);//开启ap
} catch (Exception e) {
loge("Exception in softap start " + e);
try {
mNwService.stopAccessPoint(mInterfaceName);
mNwService.startAccessPoint(config, mInterfaceName);
} catch (Exception e1) {
loge("Exception in softap re-start " + e1);
sendMessage(CMD_START_AP_FAILURE, WifiManager.SAP_START_FAILURE_GENERAL);
return;
}
}
if (DBG) log("Soft AP start successful");
sendMessage(CMD_START_AP_SUCCESS);
}
}).start();
}
startAccessPoint也在NetworkManagementService,其中创建NativeDaemonConnector和net通信
mConnector = new NativeDaemonConnector(
new NetdCallbackReceiver(), socket, 10, NETD_TAG, 160, wl,
FgThread.get().getLooper());
/frameworks/base/services/core/java/com/android/server/NetworkManagementService.java
public void startAccessPoint(
WifiConfiguration wifiConfig, String wlanIface) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
if (wifiConfig == null) { //和netd通信,执行命令softap,set,没有传递配置信息
mConnector.execute("softap", "set", wlanIface);
} else {
和netd通信,执行命令softap,set,传递配置信息,ssid,key等
mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
"broadcast", Integer.toString(wifiConfig.apChannel),
getSecurityType(wifiConfig),
new SensitiveArg(wifiConfig.preSharedKey));
}
mConnector.execute("softap", "startap"); //上面设置了信息,开启startap命令
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
}
至此,android层完成
主要完成了
1,调用hla层加载wifi driver
2,执行netd命令, 加载固件 execute(“softap”, “fwreload”, wlanIface, mode)
3,执行netd命令,配置网络信息 execute(“softap”, “set”, wlanIface, wifiConfig.SSID,
“broadcast”, Integer.toString(wifiConfig.apChannel),
getSecurityType(wifiConfig),
new SensitiveArg(wifiConfig.preSharedKey))
4,执行netd命令,开启ap热点 execute(“softap”, “startap”)
Netd 就是Network Daemon 的缩写,表示Network守护进程。Netd负责跟一些涉及网络的配置,操作,管理,查询等相关的功能实现,比如,例如带宽控制(Bandwidth),流量统计,带宽控制,网络地址转换(NAT),个人局域网(pan),PPP链接,soft-ap,共享上网(Tether),配置路由表,interface配置管理,等等……
通过netlink,虚拟文件系统,等linux内核提供的用户接口,通信内核,或者直接执行系统模块,管理网络相关部分。
Netd启动时将创建三个TCP监听socket,其名称分别为”netd”,”dnsproxyd”,”mdns”和“fwmarked”。
Framework层中的NetworkManagementService和NsdService将分别和”netd”及”mdns”监听socket建立链接并交互。
每一个调用和域名解析相关的socket API(如getaddrinfo或gethostbyname等)的进程都会借由”dnsproxyd”监听socket与netd建立链接。
fwmarkd 和底层kernel交互,防火墙firewall会对进来的包做标记。
只描述与SoftAP相关
接收framework层 NativeDaemonConnector socket消息,处理命令
int CommandListener::SoftapCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
int rc = ResponseCode::SoftapStatusResult;
char *retbuf = NULL;
if (sSoftapCtrl == NULL) {
cli->sendMsg(ResponseCode::ServiceStartFailed, "SoftAP is not available", false);
return -1;
}
if (argc < 2) {
cli->sendMsg(ResponseCode::CommandSyntaxError,
"Missing argument in a SoftAP command", false);
return 0;
}
if (!strcmp(argv[1], "startap")) {开启ap
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], "status")) {
asprintf(&retbuf, "Softap service %s running",
(sSoftapCtrl->isSoftapStarted() ? "is" : "is not"));
cli->sendMsg(rc, retbuf, false);
free(retbuf);
return 0;
} else if (!strcmp(argv[1], "set")) {设置网络配置
rc = sSoftapCtrl->setSoftap(argc, argv);
} else {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Unrecognized SoftAP command", false);
return 0;
}
if (rc >= 400 && rc < 600)
cli->sendMsg(rc, "SoftAP command has failed", false);
else
cli->sendMsg(rc, "Ok", false);
return 0;
}
加载固件 execute(“softap”, “fwreload”, wlanIface, mode)
int SoftapController::fwReloadSoftap(int argc, char *argv[])
{
char *fwpath = NULL;
if (argc < 4) {
ALOGE("SoftAP fwreload is missing arguments. Please use: softap " );
return ResponseCode::CommandSyntaxError;
}
if (strcmp(argv[3], "AP") == 0) {
fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_AP);//获取ap 固件路径
例如:WIFI_DRIVER_FW_PATH_AP := "/system/etc/firmware/fw_bcmdhd_apsta.bin"
} else if (strcmp(argv[3], "P2P") == 0) {
fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_P2P);
} else if (strcmp(argv[3], "STA") == 0) {
fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_STA);
}
if (!fwpath)
return ResponseCode::CommandParameterError;
if (wifi_change_fw_path((const char *)fwpath)) {//写路径
ALOGE("Softap fwReload failed");
return ResponseCode::OperationFailed;
}
else {
ALOGD("Softap fwReload - Ok");
}
return ResponseCode::SoftapStatusResult;
}
int wifi_change_fw_path(const char *fwpath)
{
int len;
int fd;
int ret = 0;
if (!fwpath)
return ret;
//例如:#define WIFI_DRIVER_FW_PATH_PARAM "/sys/module/wlan/parameters/fwpath"
fd = TEMP_FAILURE_RETRY(open(WIFI_DRIVER_FW_PATH_PARAM, O_WRONLY));
if (fd < 0) {
ALOGE("Failed to open wlan fw path param (%s)", strerror(errno));
return -1;
}
len = strlen(fwpath) + 1;
//把/system/etc/firmware/fw_bcmdhd_apsta.bin 路径写入/sys/module/wlan/parameters/fwpath
if (TEMP_FAILURE_RETRY(write(fd, fwpath, len)) != len) {
ALOGE("Failed to write wlan fw path param (%s)", strerror(errno));
ret = -1;
}
close(fd);
//LC: add for softap manager
/* Store current fw path in property */
if(strstr(fwpath, "ap")){
property_set(WIFI_MODE_PROP_NAME, "ap"); //设置wlan.mode 属性为ap
}else{
property_set(WIFI_MODE_PROP_NAME, "sta");
}
//end
return ret;
}
execute(“softap”, “set”, wlanIface, wifiConfig.SSID,
“broadcast”, Integer.toString(wifiConfig.apChannel),
getSecurityType(wifiConfig),
new SensitiveArg(wifiConfig.preSharedKey))
保存接口,SSID,密码等参数
/*
* Arguments:
* argv[2] - wlan interface
* argv[3] - SSID
* argv[4] - Broadcast/Hidden
* argv[5] - Channel
* argv[6] - Security
* argv[7] - Key
*/
int SoftapController::setSoftap(int argc, char *argv[]) {
int hidden = 0;
int channel = AP_CHANNEL_DEFAULT;
if (argc < 5) {
ALOGE("Softap set is missing arguments. Please use:");
ALOGE("softap " );
return ResponseCode::CommandSyntaxError;
}
if (!strcasecmp(argv[4], "hidden"))
hidden = 1;
if (argc >= 5) {
channel = atoi(argv[5]);
if (channel <= 0)
channel = AP_CHANNEL_DEFAULT;
}
std::string wbuf(StringPrintf("interface=%s\n"
"driver=nl80211\n"
"ctrl_interface=/data/misc/wifi/hostapd\n"
"ssid=%s\n"
"channel=%d\n"
"ieee80211n=1\n"
"hw_mode=%c\n"
"ignore_broadcast_ssid=%d\n"
"wowlan_triggers=any\n",
argv[2], argv[3], channel, (channel <= 14) ? 'g' : 'a', hidden));
std::string fbuf;
if (argc > 7) {
char psk_str[2*SHA256_DIGEST_LENGTH+1];
if (!strcmp(argv[6], "wpa-psk")) {
generatePsk(argv[3], argv[7], psk_str);
fbuf = StringPrintf("%swpa=3\nwpa_pairwise=TKIP CCMP\nwpa_psk=%s\n", wbuf.c_str(), psk_str);
} else if (!strcmp(argv[6], "wpa2-psk")) {
generatePsk(argv[3], argv[7], psk_str);
fbuf = StringPrintf("%swpa=2\nrsn_pairwise=CCMP\nwpa_psk=%s\n", wbuf.c_str(), psk_str);
} else if (!strcmp(argv[6], "open")) {
fbuf = wbuf;
}
} else if (argc > 6) {
if (!strcmp(argv[6], "open")) {
fbuf = wbuf;
}
} else {
fbuf = wbuf;
}
//HOSTAPD_CONF_FILE[] = "/data/misc/wifi/hostapd.conf"
//把配置参数都保存到hostapd.conf中
if (!WriteStringToFile(fbuf, HOSTAPD_CONF_FILE, 0660, AID_SYSTEM, AID_WIFI)) {
ALOGE("Cannot write to \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno));
return ResponseCode::OperationFailed;
}
return ResponseCode::SoftapStatusResult;
}
开启ap热点 execute(“softap”, “startap”)
int SoftapController::startSoftap() {
pid_t pid = 1;
if (mPid) {
ALOGE("SoftAP is already running");
return ResponseCode::SoftapStatusResult;
}
if (ensure_entropy_file_exists() < 0) {
ALOGE("Wi-Fi entropy file was not created");
}
if ((pid = fork()) < 0) {//fork一个子进程
ALOGE("fork failed (%s)", strerror(errno));
return ResponseCode::ServiceStartFailed;
}
if (!pid) {
ensure_entropy_file_exists();
//在子进程中执行hostapd守护进程,hostapd会解析hostapd.conf,和kernel wifi driver通信,配置网络
//HOSTAPD_BIN_FILE[] = "/system/bin/hostapd"
//HOSTAPD_CONF_FILE[] = "/data/misc/wifi/hostapd.conf"
//WIFI_ENTROPY_FILE "/data/misc/wifi/entropy.bin"
if (execl(HOSTAPD_BIN_FILE, HOSTAPD_BIN_FILE,
"-e", WIFI_ENTROPY_FILE,
HOSTAPD_CONF_FILE, (char *) NULL)) {
ALOGE("execl failed (%s)", strerror(errno));
}
ALOGE("SoftAP failed to start");
return ResponseCode::ServiceStartFailed;
} else {
mPid = pid;
ALOGD("SoftAP started successfully");
usleep(AP_BSS_START_DELAY);
}
return ResponseCode::SoftapStatusResult;
}
至此,ap配置完成,可以搜索到热点。
后续开启dhcp,dns。