Android Softap开启流程分析

##Android Wifi架构

Android Softap开启流程分析_第1张图片


Android Softap开启流程

Softap字面意思是用软件实现AP的功能,让你的移动设备可以作为一个路由,让别的站点链接。当你在手机或平板上通过按钮开启softap时,系统接受ap设置界面变化打开的响应,从此开启了整个Android SoftAP的序幕。

首先./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(WIFI_TETHERING);  
    } else {  
        mWifiApEnabler.setSoftapEnabled(false);  
    }  
    return false;  
} 

Softap开启时,enable 为真,因而执行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 用来检测是否需要进行一些准备工作。如果无需准备工作则执行startTethering

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

这里mTetherChoice == WIFI_TETHERING,所以继而执行WiFiApEnable.java中的setSoftapEnabled(true)函数,从此处跳出了Setting的代码,跳入了Android WIFI 子系统的framework层

./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(); //获取当前wifi的状态 如果开启则关闭且保存状态信息到变量中  
    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 receiving 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);  
        }  
    }  
} 

上面的代码中我们看到了Google人的考虑事情的周全。首先检测Wifi当前状态,如果正在打开或者已经打开则关闭WIFI并将此状态记录下来,以便关闭softap时它能自动恢复到之前打开wifi的状态。这里调用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/wifi/WifiService.java

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

从而调用到最基础的也是最重要的Wifi状态机中的setWifiApEnabled 实例。

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

发送CMD_LOAD_DRIVER,状态迁移到mDriverLoadingState,加载AP对应的驱动。这里把WIFI的驱动跟AP的驱动做了区分,可见SoftAP不仅仅是软件实现的,需要硬件驱动的相应支持。

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

加载驱动成功后,系统迁移到mDriverLoadedState状态。
接收到 CMD_START_AP消息,状态又被迁移至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会检测上层传下的参数的有效性并调用startSoftApWithConfig配置、打开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:  
            //....  
        }  
    }  
}  

获取SoftAp的网络配置AP名称、加密方式、密码
进行系统驱动(硬件)的配置。

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

这里调用了./frameworks/base/services/java/com/android/server/NetworkManagementService.java 中的startAccessPoint函数
函数如下:

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、下载AP对应的firmware
wifiFirmwareReload(wlanIface, “AP”);

2、设置ap的ssid、加密方式以及密码
mConnector.execute(“softap”, “set”, wlanIface, wifiConfig.SSID, getSecurityType(wifiConfig), wifiConfig.preSharedKey);

3、运行softap
mConnector.execute(“softap”, “startap”);

这里通过一个NativeDaemonConnector的实例mConnector调用c++程序,具体的实现我是没看懂,但是知道最后实际调用的函数,想深入了解可以找一些其他的资料看

实际调用到了 ./system/netd/CommandListener.cpp中的CommandListener::SoftapCmd::runCommand

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

首先是"set" 命令, 调用到c = sSoftapCtrl->setSoftap(argc, argv); 来配置网络。即将所有上层的网络设置写到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 */  
    // .......  
} 

然后是"startap"命令调用rc = sSoftapCtrl->startSoftap(); 真正开启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;  
}  

在startSoftap函数中调用了execl("/system/bin/hostapd", “/system/bin/hostapd”, “-e”, WIFI_ENTROPY_FILE, HOSTAPD_CONF_FILE, (char *) NULL)
这里hostapd就是softap的daemon 程序 类似于wifi的wpa_supplicant

至此所有wifi子系统从界面打开softap 到如何运行调用到daemon程序打开Softap的流程就是这样的

原文地址:http://blog.csdn.net/jshazk1989/article/details/8988444

你可能感兴趣的:(wifi)