Android Softap开启流程分析

来源:互联网 发布:南风知我意温南百度云 编辑:程序博客网 时间:2024/06/05 19:36

Android Wifi架构

这里写图片描述


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的deamon 程序 类似于wifi的wpa_supplicant

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

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