Android softap support (1)

Source: Internet
Author: User
Tags sendmsg

Softap literally means to use software to implement the AP function, so that your mobile devices can act as a route and link other sites.

In fact, the city needs hardware and driver support to truly implement this function.

Section 1 softap open process.

In the Wireless Configuration item on the setting interface of the Android system, a "portable wi-fi Hotspot" and a "Configure wi-fi hotspot setting" option are displayed. You can enter the system configuration AP name, encryption Method and password. For example

After you complete these settings, the system will accept the response and start the start of the entire android softap.

First, the onpreferencechange function of/packages/apps/settings/src/COM/Android/settings/tethersettings. Java receives the softap status change information.

    public boolean onPreferenceChange(Preference preference, Object value) {        boolean enable = (Boolean) value;        if (enable) {            startProvisioningIfNecessary(WIFI_TETHERING);        } else {            mWifiApEnabler.setSoftapEnabled(false);        }        return false;    }

If enable is true when softap is enabled, execute startprovisioningifnecessary (wifi_tethering );

    private void startProvisioningIfNecessary(int choice) {        mTetherChoice = choice;        if (isProvisioningNeeded()) {            Intent intent = new Intent(Intent.ACTION_MAIN);            intent.setClassName(mProvisionApp[0], mProvisionApp[1]);            startActivityForResult(intent, PROVISION_REQUEST);        } else {            startTethering();        }    }

Isprovisioningneeded is used to check whether some preparation work is required.

If no preparation is required, the starttethering drama is about to be staged.

    private void startTethering() {        switch (mTetherChoice) {            case WIFI_TETHERING:                mWifiApEnabler.setSoftapEnabled(true);                break;            case BLUETOOTH_TETHERING:                // turn on Bluetooth first                break;            case USB_TETHERING:                setUsbTethering(true);                break;            default:                //should not happen                break;        }    }

Here, mtetherchoice = wifi_tethering is used to execute the setsoftapenabled (true) function in wifiapenable. java.

The setting Code also jumped out of the framework layer of the android WiFi subsystem.

./Packages/apps/settings/src/COM/Android/settings/WiFi/wifiapenabler. Java

Public void setsoftapenabled (Boolean enable) {final contentresolver Cr = mcontext. getcontentresolver ();/*** disable WiFi if enabling tethering */INT wifistate = mwifimanager. getwifistate (); // get the status of the current wifi. If enabled, disable it and save the status information to the variable if (enable & (wifistate = wifimanager. wifi_state_enabling) | (wifistate = wifimanager. wifi_state_enabled) {mwifimanager. setwifienabled (false); settings. global. putint (Cr, settings. global. wifi_saved_state, 1);} If (mwifimanager. setwifiapenabled (null, enable) {/* disable here, enabled on logging ing success broadcast */mcheckbox. setenabled (false);} else {mcheckbox. setsummary (R. string. wifi_error);}/*** if needed, restore wifi on tether disable */If (! Enable) {int wifisavedstate = 0; try {wifisavedstate = settings. global. getint (Cr, settings. global. wifi_saved_state);} catch (settings. settingnotfoundexception e) {;} if (wifisavedstate = 1) {mwifimanager. setwifienabled (true); settings. global. putint (Cr, settings. global. wifi_saved_state, 0 );}}}

First, check the current status of wifi. If it is enabled or already enabled, disable WiFi and record the status so that it can automatically restore to the previous status when it is disabled. Android code is worthy of the ox X, which can be thought of... worship those Titans.

Call mwifimanager. setwifiapenabled (null, enable) "frameworks/base/WiFi/Java/Android/NET/WiFi/wifimanager. Java"

    public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {        try {            mService.setWifiApEnabled(wifiConfig, enabled);            return true;        } catch (RemoteException e) {            return false;        }    }

Setwifiapenabled "frameworks/base/services/Java/COM/Android/Server/wifiservice. Java"

    public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {        enforceChangePermission();        mWifiStateMachine.setWifiApEnabled(wifiConfig, enabled);    }

Thus, the setwifiapenabled instance in the most basic and important WiFi state machine is called. In fact, I really don't understand why Android code needs to be nested so many layers for calling, for security and convenience... which of the following is explained.

"Frameworks/base/WiFi/Java/Android/NET/WiFi/wifistatemachine. Java"

    public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enable) {        mLastApEnableUid.set(Binder.getCallingUid());        if (enable) {            /* Argument is the state that is entered prior to load */            sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_AP_STATE_ENABLING, 0));            sendMessage(obtainMessage(CMD_START_AP, wifiConfig));        } else {            sendMessage(CMD_STOP_AP);            /* Argument is the state that is entered upon success */            sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_DISABLED, 0));        }    }

Send the cmd_load_driver status to the mdriverloadingstate to load the driver corresponding to the AP. Here, the WiFi driver and the AP driver are distinguished. It can be seen that softap is not only implemented by software, but also needs the support of the hardware driver.

    class DriverLoadingState extends State {        @Override        public void enter() {            new Thread(new Runnable() {                public void run() {                    mWakeLock.acquire();                    //enabling state                    switch(message.arg1) {                        case WIFI_STATE_ENABLING:                            setWifiState(WIFI_STATE_ENABLING);                            break;                        case WIFI_AP_STATE_ENABLING:                            setWifiApState(WIFI_AP_STATE_ENABLING);                            break;                    }                    if(mWifiNative.loadDriver()) {                        if (DBG) log("Driver load successful");                        sendMessage(CMD_LOAD_DRIVER_SUCCESS);                    } else {                        loge("Failed to load driver!");                        switch(message.arg1) {                            case WIFI_STATE_ENABLING:                                setWifiState(WIFI_STATE_UNKNOWN);                                break;                            case WIFI_AP_STATE_ENABLING:                                setWifiApState(WIFI_AP_STATE_FAILED);                                break;                        }                        sendMessage(CMD_LOAD_DRIVER_FAILURE);                    }                    mWakeLock.release();                }            }).start();        }        @Override        public boolean processMessage(Message message) {            if (DBG) log(getName() + message.toString() + "\n");            switch (message.what) {                case CMD_LOAD_DRIVER_SUCCESS:                    transitionTo(mDriverLoadedState);                    break;                case CMD_LOAD_DRIVER_FAILURE:                    transitionTo(mDriverFailedState);                    break;                default:                    return NOT_HANDLED;            }            return HANDLED;        }    }

After the driver is loaded, the system is migrated to the mdriverloadedstate state.

The received cmd_start_ap message status is migrated to msoftapstartingstate.

    class DriverLoadedState extends State {        @Override        public void enter() {            if (DBG) log(getName() + "\n");            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());        }        @Override        public boolean processMessage(Message message) {            if (DBG) log(getName() + message.toString() + "\n");            switch(message.what) {                    /*                     ******                    */                case CMD_START_AP:                    transitionTo(mSoftApStartingState);                    break;                default:                    return NOT_HANDLED;            }            return HANDLED;        }    }

Softapstartingstate checks the validity of parameters transmitted over the upper layer, calls startsoftapwithconfig to configure and enable softap.

    class SoftApStartingState extends State {        @Override        public void enter() {            if (DBG) log(getName() + "\n");            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());            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);            }        }        @Override        public boolean processMessage(Message message) {            if (DBG) log(getName() + message.toString() + "\n");            switch(message.what) {                case CMD_LOAD_DRIVER:                case CMD_UNLOAD_DRIVER:                //....                case CMD_STOP_SUPPLICANT:                case CMD_START_AP:                //....            }        }    }

Obtain the network configuration of the softap. The AP name is encrypted ....

Configure the system driver (hardware.

    private void startSoftApWithConfig(final WifiConfiguration config) {        // start hostapd on a seperate thread        new Thread(new Runnable() {            public void run() {                try {                    mNwService.startAccessPoint(config, mInterfaceName);                } 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);                        return;                    }                }                if (DBG) log("Soft AP start successful");                sendMessage(CMD_START_AP_SUCCESS);            }        }).start();    }     //...  }

The startaccesspoint function in "frameworks/base/services/Java/COM/Android/Server/networkmanagementservice. Java" is called.

The function is as follows:

    public void startAccessPoint(            WifiConfiguration wifiConfig, String wlanIface) {        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);        try {            wifiFirmwareReload(wlanIface, "AP");            if (wifiConfig == null) {                mConnector.execute("softap", "set", wlanIface);            } else {                mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,                        getSecurityType(wifiConfig), wifiConfig.preSharedKey);            }            mConnector.execute("softap", "startap");        } catch (NativeDaemonConnectorException e) {            throw e.rethrowAsParcelableException();        }    }

1. Download the firmware corresponding to the AP

Wififirmwarereload (wlaniface, "AP ");

2. Set the ap ssid encryption mode and password

Mconnector.exe cute ("softap", "set", wlaniface, wificonfig. SSID, getsecuritytype (wificonfig), wificonfig. presharedkey );

3. Run softap

Mconnector.exe cute ("softap", "startap ");

Here, we use an instance of nativedaemonconnector mconneto call the specific implementation of the C ++ program. I don't understand it, but I know the actually called function. For more information, see some other materials.

The commandlistener: softapcmd: runcommand in "./system/netd/commandlistener. cpp" is actually called.

int CommandListener::SoftapCmd::runCommand(SocketClient *cli,                                        int argc, char **argv) {    int rc = 0, flag = 0;    char *retbuf = NULL;    if (argc < 2) {        cli->sendMsg(ResponseCode::CommandSyntaxError, "Softap Missing argument", false);        return 0;    }    if (!strcmp(argv[1], "startap")) {        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], "clients")) {        rc = sSoftapCtrl->clientsSoftap(&retbuf);        if (!rc) {            cli->sendMsg(ResponseCode::CommandOkay, retbuf, false);            free(retbuf);            return 0;        }    } else if (!strcmp(argv[1], "status")) {        asprintf(&retbuf, "Softap service %s",                 (sSoftapCtrl->isSoftapStarted() ? "started" : "stopped"));        cli->sendMsg(ResponseCode::SoftapStatusResult, retbuf, false);        free(retbuf);        return 0;    } else if (!strcmp(argv[1], "set")) {        rc = sSoftapCtrl->setSoftap(argc, argv);    } else {        cli->sendMsg(ResponseCode::CommandSyntaxError, "Softap Unknown cmd", false);        return 0;    }    if (!rc) {        cli->sendMsg(ResponseCode::CommandOkay, "Softap operation succeeded", false);    } else {        cli->sendMsg(ResponseCode::OperationFailed, "Softap operation failed", true);    }    return 0;}

First, the "set" command is called to C = ssoftapctrl-> setsoftap (argc, argv); to configure the network

Configure to write all upper-layer network settings to hostapd_conf_file [] = "/data/MISC/WiFi/hostapd. conf"

("System/netd/softapcontroller. cpp ")

/* * Arguments: *  argv[2] - wlan interface *  argv[3] - SSID *  argv[4] - Security *  argv[5] - Key *  argv[6] - Channel *  argv[7] - Preamble *  argv[8] - Max SCB */int SoftapController::setSoftap(int argc, char *argv[]) {    char psk_str[2*SHA256_DIGEST_LENGTH+1];    int ret = 0, i = 0, fd;    char *ssid, *iface;    /* ..... */    iface = argv[2];    char *wbuf = NULL;    char *fbuf = NULL;    if (argc > 3) {        ssid = argv[3];    } else {        ssid = (char *)"AndroidAP";    }    if (argc > 4) {        if (!strcmp(argv[4], "wpa-psk")) {            generatePsk(ssid, argv[5], psk_str);            asprintf(&fbuf, "%swpa=1\nwpa_pairwise=TKIP CCMP\nwpa_psk=%s\n", wbuf, psk_str);        } else if (!strcmp(argv[4], "wpa2-psk")) {            generatePsk(ssid, argv[5], psk_str);            asprintf(&fbuf, "%swpa=2\nrsn_pairwise=CCMP\nwpa_psk=%s\n", wbuf, psk_str);        } else if (!strcmp(argv[4], "open")) {            asprintf(&fbuf, "%s", wbuf);        }    } else {        asprintf(&fbuf, "%s", wbuf);    }    fd = open(HOSTAPD_CONF_FILE, O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW, 0660);    /*............*/    if (write(fd, fbuf, strlen(fbuf)) < 0) {        ALOGE("Cannot write to \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno));        ret = -1;    }    free(wbuf);    free(fbuf);    /* Note: apparently open can fail to set permissions correctly at times */    // .......}

Then the "startap" command calls rc = ssoftapctrl-> startsoftap (); actually enables softap

int SoftapController::startSoftap() {    pid_t pid = 1;    int ret = 0;    if (mPid) {        ALOGE("Softap already started");        return 0;    }    if (mSock < 0) {        ALOGE("Softap startap - failed to open socket");        return -1;    }    if ((pid = fork()) < 0) {        ALOGE("fork failed (%s)", strerror(errno));        return -1;    }    if (!pid) {        ensure_entropy_file_exists();        if (execl("/system/bin/hostapd", "/system/bin/hostapd",                  "-e", WIFI_ENTROPY_FILE,                  HOSTAPD_CONF_FILE, (char *) NULL)) {            ALOGE("execl failed (%s)", strerror(errno));        }        ALOGE("Should never get here!");        return -1;    } else {        mPid = pid;        ALOGD("Softap startap - Ok");        usleep(AP_BSS_START_DELAY);    }    return ret;}

The startsoftap function calls

Execl ("/system/bin/hostapd", "/system/bin/hostapd", "-e", wifi_entropy_file, hostapd_conf_file, (char *) null)

Here hostapd is the deamon program of softap, which is similar to wpa_supplicant of wifi.

 

So far, the process for all WiFi subsystems to open softap from the interface to how to run and call the deamon program to open softap is like this.

Later, we will introduce how to enable the setting interface "portable wi-fi" and some features of hostapd.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.