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 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 <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/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 <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。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章