android softap 热点配置分析

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

android softap框架

android softap 热点配置分析_第1张图片
基于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 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);
    }

}

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);//调用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层驱动
}

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_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驱动加载完成。

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 {
    @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

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

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)