SoftAP (Access Point,无线访问节点),就是通过软件方式提供接入功能,android手机开启AP或热点,其他手机通过wifi可以接入。其他手机称为Station,工作模式位Sta模式。

android softap框架


基于android6.0进行分析。

settings

从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 firstBluetoothAdapter 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 happenbreak;}}

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);}}

Framework Tethering

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);//调用wifiservicereturn 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_APif (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 yetSettings.Global.putInt(mContext.getContentResolver(),Settings.Global.WIFI_SAVED_STATE, WIFI_DISABLED);}//开启wifimWifiStateMachine.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 {@Overridepublic void enter() {WifiNative.stopHal(); 先停止halmWifiNative.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 optionmHalBasedPnoEnableInDevSettings = 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层驱动
}

HLA层 wifi

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_PATHchar 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_PARAMif (is_wifi_driver_loaded()) {return 0;}if (wifi_change_driver_state(WIFI_DRIVER_STATE_ON) < 0)//改变驱动状态return -1;
#endifproperty_set(DRIVER_PROP_NAME, "ok");//设置驱动属性已经ok,wlan.driver.statusreturn 0;
#endif
}int is_wifi_driver_loaded() {char driver_status[PROPERTY_VALUE_MAX];
#ifdef WIFI_DRIVER_MODULE_PATHFILE *proc;char line[sizeof(DRIVER_MODULE_TAG)+10];
#endifif (!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;
#elsereturn 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驱动加载完成。

enableSoftAp

继续使能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 {@Overridepublic 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 channelfinal 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 HereString countryCode = getCurrentCountryCode();//国家codeif (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 5GHzsendMessage(CMD_START_AP_FAILURE, WifiManager.SAP_START_FAILURE_GENERAL);return;}}} else {if (config.apBand != 0) {//countrycode is mandatory for 5GHzLog.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 channelsendMessage(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//supportedconfig.apBand = 0; //带宽config.apChannel = 6; //信道个数}}}} else {//for some old device, wifiHal may not be supportedconfig.apBand = 0;config.apChannel = 6;}// Start hostapd on a separate threadnew 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

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")) {开启aprc = 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);elsecli->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 <wlan iface> <AP|P2P|STA>");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/fwpathif (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");}//endreturn 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 <wlan iface> <SSID> <hidden/broadcast> <channel> <wpa2?-psk|open> <passphrase>");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;
}

startap

开启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。

android softap 热点配置分析相关推荐

  1. Android11 热点配置信息保存分析

    Android11 热点配置信息保存分析 文章目录 Android11 热点配置信息保存分析 一.Android11 wifi和热点 配置信息保存的文件位置 1.wifi和热点保存的实际位置 2.wi ...

  2. Android WiFi热点完全研究(自定义创建、跳转系统界面设置、读取配置、切换,Android6.0适配)...

    前言: WiFi热点设置页面的安全性选项在Android 4.x上有"无"."WPA PSK"."WPA2 PSK"三个选项,在Androi ...

  3. Android -- Wifi热点的打开与关闭流程简介

    Android -- Wifi热点的打开与关闭流程简介 在Android手机中,热点也是一个较为常用的功能.对于framework开发者来说,要开发.维护SoftAp,了解framework中热点开关 ...

  4. android wifi热点setting

    目录 一.wifi原生setting的入口在WifiTetherSettings.java 二.改热点Setting的时候可以直接只编译Settings.apk,并且替换, 三.wifi热点貌似官方支 ...

  5. 数据分析案例:APP热点标签分析

    文章目录 一.需求分析 二.主要思路及难点 三.主要流程: 四.开发过程: 整个案例结构: 具体操作流程(Linux系统上) 五.优化 一.需求分析 给定一批App名称及其描述信息,共52.9万条数据 ...

  6. Android以太网框架情景分析之启动简介

            Android以太网框架情景分析之启动简介 Android网络框架分析系列文章目录: Android P适配以太网功能开发指南 Android以太网框架情景分析之启动简介 Androi ...

  7. Android SoftAp SoftAp打开/关闭代码流程(基于android 7.0)

    在Android手机中,SoftAp也是一个较为常用的功能.对于framework开发者来说,要开发.维护SoftAp,了解framework中热点开关的具体流程是非常有必要的.下面就对这部分内容做一 ...

  8. Android SoftAP 实现框架

    Android SoftAP 实现框架 1. SoftAP 简介 2. 功能模块与框架图 框架图 3. 功能简单分析 3.1 设备启动与管理 3.2 网络共享功能的实现 4. SoftAP 运行时序图 ...

  9. 【Android RTMP】RTMPDumb 源码导入 Android Studio ( 交叉编译 | 配置 CMakeList.txt 构建脚本 )

    文章目录 安卓直播推流专栏博客总结 一. RTMP 协议 二. RTMP 协议使用 三. RTMPDump 源码下载 四. RTMPDump 源码交叉编译 五. RTMPDump 源码导入 Andro ...

最新文章

  1. fcitx输入法在wps、wineqq中失灵问题的解决
  2. python 监控股价 程序 tk_linux通过python监控股票股价
  3. 大庆东风中学高考成绩查询2021年,2021年大庆中考成绩和分数线什么时候公布(附查询入口)...
  4. explain 之key rows extra
  5. 跨服务器 快速 导入数据表记录 Insert into SELECT
  6. log4net日志文件的应用
  7. maven编译报程序包不存在_宝马730i空调不制冷,报冷却剂压缩机当前存在故障
  8. MaxCompute命令行工具——odpscmd的操作使用
  9. 手动安装MySQL8.0
  10. Qt中出现 exited with code 3错误的其中之一原因
  11. 嘉兴 机器人仓库 菜鸟_菜鸟在嘉兴推出全新智能仓 宣布将在双11启用超级机器人仓群...
  12. ubantu启动黑屏解决办法
  13. 1.第一节课,从头开始学C语言
  14. Altium的基本使用方法
  15. 云服务器能共享文件夹,云服务器能共享文件夹
  16. Build Your Own Angularjs 读书笔记(AngularJS牛逼的地方在于它内嵌了一个表达式到Function对象的编译器。。。当然还有DI框架)
  17. Java中super()的使用
  18. C语言学习代码,初学者笔记
  19. 40页PPT学会从0到1建设数据仓库
  20. PowerBuilder DeCompiler(PB DeCompiler) Demo download(PB反编译,支持5-12)

热门文章

  1. mysqli操作数据库,连接和四种取值方法
  2. 自定义浏览器滚动条样式
  3. windows下,怎么使用管理员运行cmd.exe程序。
  4. App Store/Google Play开发者如何收款?中国谷歌开发者收款方式总结
  5. 极客日报第92期:华为高管揭秘公司不上市的原因;微信回应「花钱就能查到聊天记录」;马斯克删除「超苹果只要几个月」评论
  6. 高新技术企业认定代办服务内容及代办多少钱
  7. 移动办理服务器密码修改委托书,重置密码授权委托书.DOC
  8. 第一部分:设计模式六大原则解读——什么是接口隔离
  9. matlab工作空间举证,MATLAB的工作空间
  10. ITS信号控制系统渠化图自动生成