android softap 热点配置分析
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 热点配置分析相关推荐
- Android11 热点配置信息保存分析
Android11 热点配置信息保存分析 文章目录 Android11 热点配置信息保存分析 一.Android11 wifi和热点 配置信息保存的文件位置 1.wifi和热点保存的实际位置 2.wi ...
- Android WiFi热点完全研究(自定义创建、跳转系统界面设置、读取配置、切换,Android6.0适配)...
前言: WiFi热点设置页面的安全性选项在Android 4.x上有"无"."WPA PSK"."WPA2 PSK"三个选项,在Androi ...
- Android -- Wifi热点的打开与关闭流程简介
Android -- Wifi热点的打开与关闭流程简介 在Android手机中,热点也是一个较为常用的功能.对于framework开发者来说,要开发.维护SoftAp,了解framework中热点开关 ...
- android wifi热点setting
目录 一.wifi原生setting的入口在WifiTetherSettings.java 二.改热点Setting的时候可以直接只编译Settings.apk,并且替换, 三.wifi热点貌似官方支 ...
- 数据分析案例:APP热点标签分析
文章目录 一.需求分析 二.主要思路及难点 三.主要流程: 四.开发过程: 整个案例结构: 具体操作流程(Linux系统上) 五.优化 一.需求分析 给定一批App名称及其描述信息,共52.9万条数据 ...
- Android以太网框架情景分析之启动简介
Android以太网框架情景分析之启动简介 Android网络框架分析系列文章目录: Android P适配以太网功能开发指南 Android以太网框架情景分析之启动简介 Androi ...
- Android SoftAp SoftAp打开/关闭代码流程(基于android 7.0)
在Android手机中,SoftAp也是一个较为常用的功能.对于framework开发者来说,要开发.维护SoftAp,了解framework中热点开关的具体流程是非常有必要的.下面就对这部分内容做一 ...
- Android SoftAP 实现框架
Android SoftAP 实现框架 1. SoftAP 简介 2. 功能模块与框架图 框架图 3. 功能简单分析 3.1 设备启动与管理 3.2 网络共享功能的实现 4. SoftAP 运行时序图 ...
- 【Android RTMP】RTMPDumb 源码导入 Android Studio ( 交叉编译 | 配置 CMakeList.txt 构建脚本 )
文章目录 安卓直播推流专栏博客总结 一. RTMP 协议 二. RTMP 协议使用 三. RTMPDump 源码下载 四. RTMPDump 源码交叉编译 五. RTMPDump 源码导入 Andro ...
最新文章
- fcitx输入法在wps、wineqq中失灵问题的解决
- python 监控股价 程序 tk_linux通过python监控股票股价
- 大庆东风中学高考成绩查询2021年,2021年大庆中考成绩和分数线什么时候公布(附查询入口)...
- explain 之key rows extra
- 跨服务器 快速 导入数据表记录 Insert into SELECT
- log4net日志文件的应用
- maven编译报程序包不存在_宝马730i空调不制冷,报冷却剂压缩机当前存在故障
- MaxCompute命令行工具——odpscmd的操作使用
- 手动安装MySQL8.0
- Qt中出现 exited with code 3错误的其中之一原因
- 嘉兴 机器人仓库 菜鸟_菜鸟在嘉兴推出全新智能仓 宣布将在双11启用超级机器人仓群...
- ubantu启动黑屏解决办法
- 1.第一节课,从头开始学C语言
- Altium的基本使用方法
- 云服务器能共享文件夹,云服务器能共享文件夹
- Build Your Own Angularjs 读书笔记(AngularJS牛逼的地方在于它内嵌了一个表达式到Function对象的编译器。。。当然还有DI框架)
- Java中super()的使用
- C语言学习代码,初学者笔记
- 40页PPT学会从0到1建设数据仓库
- PowerBuilder DeCompiler(PB DeCompiler) Demo download(PB反编译,支持5-12)
热门文章
- mysqli操作数据库,连接和四种取值方法
- 自定义浏览器滚动条样式
- windows下,怎么使用管理员运行cmd.exe程序。
- App Store/Google Play开发者如何收款?中国谷歌开发者收款方式总结
- 极客日报第92期:华为高管揭秘公司不上市的原因;微信回应「花钱就能查到聊天记录」;马斯克删除「超苹果只要几个月」评论
- 高新技术企业认定代办服务内容及代办多少钱
- 移动办理服务器密码修改委托书,重置密码授权委托书.DOC
- 第一部分:设计模式六大原则解读——什么是接口隔离
- matlab工作空间举证,MATLAB的工作空间
- ITS信号控制系统渠化图自动生成