Wifi模块—源码分析Wifi热点的开启(Android P)

一 前言

Android使用一个修改版wpa_supplicant作为daemon来控制WIFI,它是一个安全中间件,代码位于external/wpa_supplicant,为各种无线网卡提供统一的安全机制。当然在这里只是介绍一下wpa_supplicant和 hostapd,研究分析的部分主要还是应用层和java框架层,有时也会涉及Native层。

wpa_supplicant_8主要有三个子目录 :

hostapd:当手机进入Soft AP模式时,手机将扮演AP的角色,需要hostapd来提供AP的功能,也就是wifi热点的实现。

wpa_supplicant:Station模式,也叫Managed模式,这是平时最常见的使用wifi连接AP的情况。

src:hostapd和wpa_supplicant中都包含一些通用的数据结构和处理方法,这些内容都放在此src目录中。

二 图示调用流程

三 具体代码流程

Android P之后,Wifi模块增加了packages/apps/Settings/src/com/android/settings/wifi/tether/路径,相当于把Wifi热点独立放到了tether文件夹下面,并添加了WifiTetherSettings.java类,对应着Wifi热点的界面,而Android P之前是没有的,Wifi热点界面之前是对应在TetherSettings的一部分,有些厂商也还是会改到TetherSettings上。

1 packages/apps/Settings/src/com/android/settings/wifi/tether/WifiTetherSettings.java

  1. @Override
  2. public void onActivityCreated(Bundle savedInstanceState) {
  3. super.onActivityCreated(savedInstanceState);
  4. // Assume we are in a SettingsActivity. This is only safe because we currently use
  5. // SettingsActivity as base for all preference fragments.
  6. final SettingsActivity activity = (SettingsActivity) getActivity();
  7. final SwitchBar switchBar = activity.getSwitchBar();
  8. mSwitchBarController = new WifiTetherSwitchBarController(activity,
  9. new SwitchBarController(switchBar));
  10. getLifecycle().addObserver(mSwitchBarController);
  11. switchBar.show();
  12. }

初始化mSwitchBarController,这个类含有SwitchBar的实例。

2 packages/apps/Settings/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java

  1. public class WifiTetherSwitchBarController implements SwitchWidgetController.OnSwitchChangeListener,
  2. LifecycleObserver, OnStart, OnStop, DataSaverBackend.Listener {

3 packages/apps/Settings/src/com/android/settings/widget/SwitchWidgetController.java

  1. /**
  2. * Interface definition for a callback to be invoked when the switch has been toggled.
  3. */
  4. public interface OnSwitchChangeListener {
  5. /**
  6. * Called when the checked state of the Switch has changed.
  7. *
  8. * @param isChecked The new checked state of switchView.
  9. *
  10. * @return true to update the state of the switch with the new value.
  11. */
  12. boolean onSwitchToggled(boolean isChecked);
  13. }

4 packages/apps/Settings/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java

  1. @Override
  2. public boolean onSwitchToggled(boolean isChecked) {
  3. if (!isChecked) {
  4. stopTether();
  5. } else if (!mWifiManager.isWifiApEnabled()) {
  6. startTether();
  7. }
  8. return true;
  9. }

startTether()。

  1. void startTether() {
  2. mSwitchBar.setEnabled(false);
  3. mConnectivityManager.startTethering(TETHERING_WIFI, true /* showProvisioningUi */,
  4. mOnStartTetheringCallback, new Handler(Looper.getMainLooper()));
  5. }

android O开始通过mConnectivityManager.startTethering来启动热点了,之前都是通过WifiManager的setWifiApEnable的方法,该方法现在也已废弃。

5 frameworks/base/core/java/android/net/ConnectivityManager.java

  1. /**
  2. * Convenient overload for
  3. * {@link #startTethering(int, boolean, OnStartTetheringCallback, Handler)} which passes a null
  4. * handler to run on the current thread's {@link Looper}.
  5. * @hide
  6. */
  7. @SystemApi
  8. @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
  9. public void startTethering(int type, boolean showProvisioningUi,
  10. final OnStartTetheringCallback callback) {
  11. startTethering(type, showProvisioningUi, callback, null);
  12. }

startTethering。

  1. /**
  2. * Runs tether provisioning for the given type if needed and then starts tethering if
  3. * the check succeeds. If no carrier provisioning is required for tethering, tethering is
  4. * enabled immediately. If provisioning fails, tethering will not be enabled. It also
  5. * schedules tether provisioning re-checks if appropriate.
  6. *
  7. * @param type The type of tethering to start. Must be one of
  8. * {@link ConnectivityManager.TETHERING_WIFI},
  9. * {@link ConnectivityManager.TETHERING_USB}, or
  10. * {@link ConnectivityManager.TETHERING_BLUETOOTH}.
  11. * @param showProvisioningUi a boolean indicating to show the provisioning app UI if there
  12. * is one. This should be true the first time this function is called and also any time
  13. * the user can see this UI. It gives users information from their carrier about the
  14. * check failing and how they can sign up for tethering if possible.
  15. * @param callback an {@link OnStartTetheringCallback} which will be called to notify the caller
  16. * of the result of trying to tether.
  17. * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
  18. * @hide
  19. */
  20. @SystemApi
  21. @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
  22. public void startTethering(int type, boolean showProvisioningUi,
  23. final OnStartTetheringCallback callback, Handler handler) {
  24. Preconditions.checkNotNull(callback, 'OnStartTetheringCallback cannot be null.');
  25. ResultReceiver wrappedCallback = new ResultReceiver(handler) {
  26. @Override
  27. protected void onReceiveResult(int resultCode, Bundle resultData) {
  28. if (resultCode == TETHER_ERROR_NO_ERROR) {
  29. callback.onTetheringStarted();
  30. } else {
  31. callback.onTetheringFailed();
  32. }
  33. }
  34. };
  35. try {
  36. String pkgName = mContext.getOpPackageName();
  37. Log.i(TAG, 'startTethering caller:' + pkgName);
  38. mService.startTethering(type, wrappedCallback, showProvisioningUi, pkgName);
  39. } catch (RemoteException e) {
  40. Log.e(TAG, 'Exception trying to start tethering.', e);
  41. wrappedCallback.send(TETHER_ERROR_SERVICE_UNAVAIL, null);
  42. }
  43. }

内部抽象类OnStartTetheringCallback。

  1. /**
  2. * Callback for use with {@link #startTethering} to find out whether tethering succeeded.
  3. * @hide
  4. */
  5. @SystemApi
  6. public static abstract class OnStartTetheringCallback {
  7. /**
  8. * Called when tethering has been successfully started.
  9. */
  10. public void onTetheringStarted() {};
  11. /**
  12. * Called when starting tethering failed.
  13. */
  14. public void onTetheringFailed() {};
  15. }

6 frameworks/base/services/core/java/com/android/server/ConnectivityService.java

  1. @Override
  2. public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi,
  3. String callerPkg) {
  4. ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
  5. if (!isTetheringSupported()) {
  6. receiver.send(ConnectivityManager.TETHER_ERROR_UNSUPPORTED, null);
  7. return;
  8. }
  9. mTethering.startTethering(type, receiver, showProvisioningUi);
  10. }

7 frameworks/base/services/core/java/com/android/server/connectivity/Tethering.java

  1. public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) {
  2. if (!isTetherProvisioningRequired()) {
  3. enableTetheringInternal(type, true, receiver);
  4. return;
  5. }
  6. if (showProvisioningUi) {
  7. runUiTetherProvisioningAndEnable(type, receiver);
  8. } else {
  9. runSilentTetherProvisioningAndEnable(type, receiver);
  10. }
  11. }

enableTetheringInternal。

  1. /**
  2. * Enables or disables tethering for the given type. This should only be called once
  3. * provisioning has succeeded or is not necessary. It will also schedule provisioning rechecks
  4. * for the specified interface.
  5. */
  6. private void enableTetheringInternal(int type, boolean enable, ResultReceiver receiver) {
  7. boolean isProvisioningRequired = enable && isTetherProvisioningRequired();
  8. int result;
  9. switch (type) {
  10. case TETHERING_WIFI:
  11. result = setWifiTethering(enable);
  12. if (isProvisioningRequired && result == TETHER_ERROR_NO_ERROR) {
  13. scheduleProvisioningRechecks(type);
  14. }
  15. sendTetherResult(receiver, result);
  16. break;
  17. case TETHERING_USB:
  18. result = setUsbTethering(enable);
  19. if (isProvisioningRequired && result == TETHER_ERROR_NO_ERROR) {
  20. scheduleProvisioningRechecks(type);
  21. }
  22. sendTetherResult(receiver, result);
  23. break;
  24. case TETHERING_BLUETOOTH:
  25. setBluetoothTethering(enable, receiver);
  26. break;
  27. default:
  28. Log.w(TAG, 'Invalid tether type.');
  29. sendTetherResult(receiver, TETHER_ERROR_UNKNOWN_IFACE);
  30. }
  31. }

setWifiTethering。

  1. private int setWifiTethering(final boolean enable) {
  2. int rval = TETHER_ERROR_MASTER_ERROR;
  3. final long ident = Binder.clearCallingIdentity();
  4. try {
  5. synchronized (mPublicSync) {
  6. mWifiTetherRequested = enable;
  7. final WifiManager mgr = getWifiManager();
  8. if ((enable && mgr.startSoftAp(null /* use existing wifi config */)) ||
  9. (!enable && mgr.stopSoftAp())) {
  10. rval = TETHER_ERROR_NO_ERROR;
  11. }
  12. }
  13. } finally {
  14. Binder.restoreCallingIdentity(ident);
  15. }
  16. return rval;
  17. }

mgr.startSoftAp。

8 frameworks/base/wifi/java/android/net/wifi/WifiManager.java

  1. /**
  2. * Start SoftAp mode with the specified configuration.
  3. * Note that starting in access point mode disables station
  4. * mode operation
  5. * @param wifiConfig SSID, security and channel details as
  6. * part of WifiConfiguration
  7. * @return {@code true} if the operation succeeds, {@code false} otherwise
  8. *
  9. * @hide
  10. */
  11. public boolean startSoftAp(@Nullable WifiConfiguration wifiConfig) {
  12. try {
  13. return mService.startSoftAp(wifiConfig);
  14. } catch (RemoteException e) {
  15. throw e.rethrowFromSystemServer();
  16. }
  17. }

startSoftAp。

9 frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java

  1. /**
  2. * see {@link android.net.wifi.WifiManager#startSoftAp(WifiConfiguration)}
  3. * @param wifiConfig SSID, security and channel details as part of WifiConfiguration
  4. * @return {@code true} if softap start was triggered
  5. * @throws SecurityException if the caller does not have permission to start softap
  6. */
  7. @Override
  8. public boolean startSoftAp(WifiConfiguration wifiConfig) {
  9. // NETWORK_STACK is a signature only permission.
  10. enforceNetworkStackPermission();
  11. mLog.info('startSoftAp uid=%').c(Binder.getCallingUid()).flush();
  12. synchronized (mLocalOnlyHotspotRequests) {
  13. // If a tethering request comes in while we have LOHS running (or requested), call stop
  14. // for softap mode and restart softap with the tethering config.
  15. if (!mLocalOnlyHotspotRequests.isEmpty()) {
  16. stopSoftApInternal();
  17. }
  18. return startSoftApInternal(wifiConfig, WifiManager.IFACE_IP_MODE_TETHERED);
  19. }
  20. }

startSoftApInternal。

  1. /**
  2. * Internal method to start softap mode. Callers of this method should have already checked
  3. * proper permissions beyond the NetworkStack permission.
  4. */
  5. private boolean startSoftApInternal(WifiConfiguration wifiConfig, int mode) {
  6. mLog.trace('startSoftApInternal uid=% mode=%')
  7. .c(Binder.getCallingUid()).c(mode).flush();
  8. // null wifiConfig is a meaningful input for CMD_SET_AP
  9. if (wifiConfig == null || WifiApConfigStore.validateApWifiConfiguration(wifiConfig)) {
  10. SoftApModeConfiguration softApConfig = new SoftApModeConfiguration(mode, wifiConfig);
  11. mWifiController.sendMessage(CMD_SET_AP, 1, 0, softApConfig);
  12. return true;
  13. }
  14. Slog.e(TAG, 'Invalid WifiConfiguration');
  15. return false;
  16. }

mWifiController.sendMessage。

10 frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiController.java

public class WifiController extends StateMachine

WifiController是个状态机,看看它的初始状态。

  1. WifiController(Context context, WifiStateMachine wsm, Looper wifiStateMachineLooper,
  2. WifiSettingsStore wss, Looper wifiServiceLooper, FrameworkFacade f,
  3. WifiStateMachinePrime wsmp) {
  4. super(TAG, wifiServiceLooper);
  5. mFacade = f;
  6. mContext = context;
  7. mWifiStateMachine = wsm;
  8. mWifiStateMachineLooper = wifiStateMachineLooper;
  9. mWifiStateMachinePrime = wsmp;
  10. mSettingsStore = wss;
  11. // CHECKSTYLE:OFF IndentationCheck
  12. addState(mDefaultState);
  13. addState(mStaDisabledState, mDefaultState);
  14. addState(mStaEnabledState, mDefaultState);
  15. addState(mDeviceActiveState, mStaEnabledState);
  16. addState(mStaDisabledWithScanState, mDefaultState);
  17. addState(mEcmState, mDefaultState);
  18. // CHECKSTYLE:ON IndentationCheck
  19. boolean isAirplaneModeOn = mSettingsStore.isAirplaneModeOn();
  20. boolean isWifiEnabled = mSettingsStore.isWifiToggleEnabled();
  21. boolean isScanningAlwaysAvailable = mSettingsStore.isScanAlwaysAvailable();
  22. boolean isLocationModeActive =
  23. mSettingsStore.getLocationModeSetting(mContext)
  24. == Settings.Secure.LOCATION_MODE_OFF;
  25. log('isAirplaneModeOn = ' + isAirplaneModeOn
  26. + ', isWifiEnabled = ' + isWifiEnabled
  27. + ', isScanningAvailable = ' + isScanningAlwaysAvailable
  28. + ', isLocationModeActive = ' + isLocationModeActive);
  29. if (checkScanOnlyModeAvailable()) {
  30. setInitialState(mStaDisabledWithScanState);
  31. } else {
  32. setInitialState(mStaDisabledState);
  33. }
  34. ...
  35. }

看checkScanOnlyModeAvailable方法。

  1. private boolean checkScanOnlyModeAvailable() {
  2. // first check if Location service is disabled, if so return false
  3. if (mSettingsStore.getLocationModeSetting(mContext)
  4. == Settings.Secure.LOCATION_MODE_OFF) {
  5. return false;
  6. }
  7. return mSettingsStore.isScanAlwaysAvailable();
  8. }

mSettingsStore是WifiSettingsStore的对象,看其isScanAlwaysAvailable方法。

11 frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiSettingsStore.java

  1. public synchronized boolean isScanAlwaysAvailable() {
  2. return !mAirplaneModeOn && mScanAlwaysAvailable;
  3. }

看mScanAlwaysAvailable是什么。

  1. WifiSettingsStore(Context context) {
  2. mContext = context;
  3. mAirplaneModeOn = getPersistedAirplaneModeOn(); //位置1
  4. mPersistWifiState = getPersistedWifiState();
  5. mScanAlwaysAvailable = getPersistedScanAlwaysAvailable(); //位置2
  6. }

看getPersistedScanAlwaysAvailable()方法。

  1. private boolean getPersistedScanAlwaysAvailable() {
  2. return Settings.Global.getInt(mContext.getContentResolver(),
  3. Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE,
  4. 0) == 1;
  5. }

可以看到,最终是判断Wifi的状态是不是处于一直可扫描的状态。

由前面的mAirplaneModeOn = getPersistedAirplaneModeOn()再看mAirplaneModeOn的状态是什么。

  1. private boolean getPersistedAirplaneModeOn() {
  2. return Settings.Global.getInt(mContext.getContentResolver(),
  3. Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
  4. }

       可以看到,最终是判断手机是不是飞行模式。

       如果手机不是飞行模式并且Wifi的状态是处于一直可扫描的状态,则返回true,那么WifiController状态机的初始状态被设为StaDisabledState状态,即setInitialState(mStaDisabledState)。否则,初始状态被设为StaDisabledWithScanState状态,即setInitialState(mStaDisabledWithScanState)。我们现在是处于初始状态为StaDisabledState的情况。

WifiController状态机,之前的博客有画过该状态机。

       由于初始状态是StaDisabledState,状态机会执行从根状态到StaDisabledState的所有enter()方法,StaDisabledState的父状态为DefultState。DefultState没有重写enter()方法,直接看StaDisabledState的enter()方法。

  1. class StaDisabledState extends State {
  2. private int mDeferredEnableSerialNumber = 0;
  3. private boolean mHaveDeferredEnable = false;
  4. private long mDisabledTimestamp;
  5. @Override
  6. public void enter() {
  7. mWifiStateMachinePrime.disableWifi();
  8. // Supplicant can't restart right away, so note the time we switched off
  9. mDisabledTimestamp = SystemClock.elapsedRealtime();
  10. mDeferredEnableSerialNumber++;
  11. mHaveDeferredEnable = false;
  12. mWifiStateMachine.clearANQPCache();
  13. }
  14. }

mWifiStateMachinePrime.disableWifi()首先会关掉Wifi,这个就不再往后延展了。

接着初始状态StaDisabledState开始处理消息CMD_SET_AP。

  1. case CMD_SET_AP:
  2. // first make sure we aren't in airplane mode
  3. if (mSettingsStore.isAirplaneModeOn()) {
  4. log('drop softap requests when in airplane mode');
  5. break;
  6. }
  7. if (msg.arg1 == 1) {
  8. // remember that we were disabled, but pass the command up to start softap
  9. mSettingsStore.setWifiSavedState(WifiSettingsStore.WIFI_DISABLED);
  10. }
  11. return NOT_HANDLED;

       mSettingsStore.setWifiSavedState(WifiSettingsStore.WIFI_DISABLED)会记录Wifi已经关闭的状态,这个不再往后延展。由于最后return NOT_HANDLED,所以说明子状态无法处理则转给父状态处理,即DefaultState。

  1. case CMD_SET_AP:
  2. // note: CMD_SET_AP is handled/dropped in ECM mode - will not start here
  3. // first make sure we aren't in airplane mode
  4. if (mSettingsStore.isAirplaneModeOn()) {
  5. log('drop softap requests when in airplane mode');
  6. break;
  7. }
  8. if (msg.arg1 == 1) {
  9. SoftApModeConfiguration config = (SoftApModeConfiguration) msg.obj;
  10. mWifiStateMachinePrime.enterSoftAPMode((SoftApModeConfiguration) msg.obj);
  11. } else {
  12. mWifiStateMachinePrime.stopSoftAPMode();
  13. }
  14. break;

12 frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachinePrime.java

  1. /**
  2. * Method to enable soft ap for wifi hotspot.
  3. *
  4. * The supplied SoftApModeConfiguration includes the target softap WifiConfiguration (or null if
  5. * the persisted config is to be used) and the target operating mode (ex,
  6. * {@link WifiManager.IFACE_IP_MODE_TETHERED} {@link WifiManager.IFACE_IP_MODE_LOCAL_ONLY}).
  7. *
  8. * @param wifiConfig SoftApModeConfiguration for the hostapd softap
  9. */
  10. public void enterSoftAPMode(@NonNull SoftApModeConfiguration wifiConfig) {
  11. mHandler.post(() -> {
  12. startSoftAp(wifiConfig);
  13. });
  14. }

startSoftAp。

  1. private void startSoftAp(SoftApModeConfiguration softapConfig) {
  2. Log.d(TAG, 'Starting SoftApModeManager');
  3. WifiConfiguration config = softapConfig.getWifiConfiguration();
  4. if (config != null && config.SSID != null) {
  5. Log.d(TAG, 'Passing config to SoftApManager! ' + config);
  6. } else {
  7. config = null;
  8. }
  9. SoftApCallbackImpl callback = new SoftApCallbackImpl();
  10. ActiveModeManager manager = mWifiInjector.makeSoftApManager(callback, softapConfig);
  11. callback.setActiveModeManager(manager);
  12. manager.start();
  13. mActiveModeManagers.add(manager);
  14. updateBatteryStatsWifiState(true);
  15. }

mWifiInjector.makeSoftApManager。

13 frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiInjector.java

  1. /**
  2. * Create a SoftApManager.
  3. * @param listener listener for SoftApManager
  4. * @param config SoftApModeConfiguration object holding the config and mode
  5. * @return an instance of SoftApManager
  6. */
  7. public SoftApManager makeSoftApManager(@NonNull WifiManager.SoftApCallback callback,
  8. @NonNull SoftApModeConfiguration config) {
  9. return new SoftApManager(mContext, mWifiStateMachineHandlerThread.getLooper(),
  10. mFrameworkFacade, mWifiNative, mCountryCode.getCountryCode(), callback,
  11. mWifiApConfigStore, config, mWifiMetrics);
  12. }

manager.start()。

14 frameworks/opt/net/wifi/service/java/com/android/server/wifi/ActiveModeManager.java

  1. /**
  2. * Method used to start the Manager for a given Wifi operational mode.
  3. */
  4. void start();

start()。

15 frameworks/opt/net/wifi/service/java/com/android/server/wifi/SoftApManager.java

  1. /**
  2. * Start soft AP with the supplied config.
  3. */
  4. public void start() {
  5. mStateMachine.sendMessage(SoftApStateMachine.CMD_START, mApConfig);
  6. }

SoftApStateMachine.CMD_START。

SoftApStateMachine是SoftApManager的内部类。

  1. @Override
  2. public boolean processMessage(Message message) {
  3. switch (message.what) {
  4. case CMD_START:
  5. mApInterfaceName = mWifiNative.setupInterfaceForSoftApMode(
  6. mWifiNativeInterfaceCallback);
  7. if (TextUtils.isEmpty(mApInterfaceName)) {
  8. Log.e(TAG, 'setup failure when creating ap interface.');
  9. updateApState(WifiManager.WIFI_AP_STATE_FAILED,
  10. WifiManager.WIFI_AP_STATE_DISABLED,
  11. WifiManager.SAP_START_FAILURE_GENERAL);
  12. mWifiMetrics.incrementSoftApStartResult(
  13. false, WifiManager.SAP_START_FAILURE_GENERAL);
  14. break;
  15. }
  16. updateApState(WifiManager.WIFI_AP_STATE_ENABLING,
  17. WifiManager.WIFI_AP_STATE_DISABLED, 0);
  18. int result = startSoftAp((WifiConfiguration) message.obj);
  19. if (result != SUCCESS) {
  20. int failureReason = WifiManager.SAP_START_FAILURE_GENERAL;
  21. if (result == ERROR_NO_CHANNEL) {
  22. failureReason = WifiManager.SAP_START_FAILURE_NO_CHANNEL;
  23. }
  24. updateApState(WifiManager.WIFI_AP_STATE_FAILED,
  25. WifiManager.WIFI_AP_STATE_ENABLING,
  26. failureReason);
  27. stopSoftAp();
  28. mWifiMetrics.incrementSoftApStartResult(false, failureReason);
  29. break;
  30. }
  31. transitionTo(mStartedState);
  32. break;
  33. default:
  34. // Ignore all other commands.
  35. break;
  36. }
  37. return HANDLED;
  38. }
  39. }

startSoftAp。

  1. /**
  2. * Start a soft AP instance with the given configuration.
  3. * @param config AP configuration
  4. * @return integer result code
  5. */
  6. private int startSoftAp(WifiConfiguration config) {
  7. if (config == null || config.SSID == null) {
  8. Log.e(TAG, 'Unable to start soft AP without valid configuration');
  9. return ERROR_GENERIC;
  10. }
  11. // Make a copy of configuration for updating AP band and channel.
  12. WifiConfiguration localConfig = new WifiConfiguration(config);
  13. int result = ApConfigUtil.updateApChannelConfig(
  14. mWifiNative, mCountryCode,
  15. mWifiApConfigStore.getAllowed2GChannel(), localConfig);
  16. if (result != SUCCESS) {
  17. Log.e(TAG, 'Failed to update AP band and channel');
  18. return result;
  19. }
  20. // Setup country code if it is provided.
  21. if (mCountryCode != null) {
  22. // Country code is mandatory for 5GHz band, return an error if failed to set
  23. // country code when AP is configured for 5GHz band.
  24. if (!mWifiNative.setCountryCodeHal(
  25. mApInterfaceName, mCountryCode.toUpperCase(Locale.ROOT))
  26. && config.apBand == WifiConfiguration.AP_BAND_5GHZ) {
  27. Log.e(TAG, 'Failed to set country code, required for setting up '
  28. + 'soft ap in 5GHz');
  29. return ERROR_GENERIC;
  30. }
  31. }
  32. if (localConfig.hiddenSSID) {
  33. Log.d(TAG, 'SoftAP is a hidden network');
  34. }
  35. if (!mWifiNative.startSoftAp(mApInterfaceName, localConfig, mSoftApListener)) {
  36. Log.e(TAG, 'Soft AP start failed');
  37. return ERROR_GENERIC;
  38. }
  39. Log.d(TAG, 'Soft AP is started');
  40. return SUCCESS;
  41. }

mWifiNative.startSoftAp。

16 frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java

  1. /**
  2. * Start Soft AP operation using the provided configuration.
  3. *
  4. * @param ifaceName Name of the interface.
  5. * @param config Configuration to use for the soft ap created.
  6. * @param listener Callback for AP events.
  7. * @return true on success, false otherwise.
  8. */
  9. public boolean startSoftAp(
  10. @NonNull String ifaceName, WifiConfiguration config, SoftApListener listener) {
  11. if (!mWificondControl.startHostapd(ifaceName, listener)) {
  12. Log.e(TAG, 'Failed to start hostapd');
  13. mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
  14. return false;
  15. }
  16. if (!waitForHostapdConnection()) {
  17. Log.e(TAG, 'Failed to establish connection to hostapd');
  18. mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
  19. return false;
  20. }
  21. if (!mHostapdHal.registerDeathHandler(new HostapdDeathHandlerInternal())) {
  22. Log.e(TAG, 'Failed to register hostapd death handler');
  23. mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
  24. return false;
  25. }
  26. if (!mHostapdHal.addAccessPoint(ifaceName, config)) {
  27. Log.e(TAG, 'Failed to add acccess point');
  28. mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
  29. return false;
  30. }
  31. return true;
  32. }

做了这些操作:

mWificondControl.startHostapd

waitForHostapdConnection

mHostapdHal.registerDeathHandler

mHostapdHal.addAccessPoint

就以mWificondControl.startHostapd为主线进行分析。

17 frameworks/opt/net/wifi/service/java/com/android/server/wifi/WificondControl.java

  1. /**
  2. * Start hostapd
  3. * TODO(b/71513606): Move this to a global operation.
  4. *
  5. * @param ifaceName Name of the interface.
  6. * @param listener Callback for AP events.
  7. * @return true on success, false otherwise.
  8. */
  9. public boolean startHostapd(@NonNull String ifaceName,
  10. SoftApListener listener) {
  11. IApInterface iface = getApInterface(ifaceName);
  12. if (iface == null) {
  13. Log.e(TAG, 'No valid ap interface handler');
  14. return false;
  15. }
  16. try {
  17. IApInterfaceEventCallback callback = new ApInterfaceEventCallback(listener);
  18. mApInterfaceListeners.put(ifaceName, callback);
  19. boolean success = iface.startHostapd(callback);
  20. if (!success) {
  21. Log.e(TAG, 'Failed to start hostapd.');
  22. return false;
  23. }
  24. } catch (RemoteException e) {
  25. Log.e(TAG, 'Exception in starting soft AP: ' + e);
  26. return false;
  27. }
  28. return true;
  29. }

看iface.startHostapd,走到Native层。

18 system/connectivity/wificond/aidl/android/net/wifi/IApInterface.aidl

  1. // Start up an instance of hostapd associated with this interface.
  2. //
  3. // @param callback Object to add a set of event callbacks.
  4. // @return true on success.
  5. boolean startHostapd(IApInterfaceEventCallback callback);

19 system/connectivity/wificond/ap_interface_binder.h

  1. binder::Status startHostapd(
  2. const sp<net::wifi::IApInterfaceEventCallback>& callback,
  3. bool* out_success) override;

20 system/connectivity/wificond/ap_interface_binder.cpp

startHostapd。

  1. binder::Status ApInterfaceBinder::startHostapd(
  2. const sp<IApInterfaceEventCallback>& callback, bool* out_success) {
  3. *out_success = false;
  4. if (!impl_) {
  5. LOG(WARNING) << 'Cannot start hostapd on dead ApInterface.';
  6. return binder::Status::ok();
  7. }
  8. *out_success = impl_->StartHostapd();
  9. if (*out_success) {
  10. ap_interface_event_callback_ = callback;
  11. }
  12. return binder::Status::ok();
  13. }

impl_->StartHostapd()。

21 system/connectivity/wificond/ap_interface_impl.h

  1. #ifndef WIFICOND_AP_INTERFACE_IMPL_H_
  2. #define WIFICOND_AP_INTERFACE_IMPL_H_
  3. #include <string>
  4. #include <vector>
  5. #include <android-base/macros.h>
  6. #include <wifi_system/hostapd_manager.h>
  7. #include <wifi_system/interface_tool.h>
  8. #include 'wificond/net/netlink_manager.h'
  9. #include 'android/net/wifi/IApInterface.h'
  10. namespace android {
  11. namespace wificond {
  12. class ApInterfaceBinder;
  13. class NetlinkUtils;
  14. // Holds the guts of how we control network interfaces capable of exposing an AP
  15. // via hostapd. Because remote processes may hold on to the corresponding
  16. // binder object past the lifetime of the local object, we are forced to
  17. // keep this object separate from the binder representation of itself.
  18. class ApInterfaceImpl {
  19. public:
  20. ApInterfaceImpl(const std::string& interface_name,
  21. uint32_t interface_index,
  22. NetlinkUtils* netlink_utils,
  23. wifi_system::InterfaceTool* if_tool,
  24. wifi_system::HostapdManager* hostapd_manager);
  25. ~ApInterfaceImpl();
  26. // Get a pointer to the binder representing this ApInterfaceImpl.
  27. android::sp<android::net::wifi::IApInterface> GetBinder() const;
  28. bool StartHostapd();
  29. bool StopHostapd();
  30. std::string GetInterfaceName() { return interface_name_; }
  31. int GetNumberOfAssociatedStations() const;
  32. void Dump(std::stringstream* ss) const;
  33. private:
  34. const std::string interface_name_;
  35. const uint32_t interface_index_;
  36. NetlinkUtils* const netlink_utils_;
  37. wifi_system::InterfaceTool* const if_tool_;
  38. wifi_system::HostapdManager* const hostapd_manager_;
  39. const android::sp<ApInterfaceBinder> binder_;
  40. // Number of associated stations.
  41. int number_of_associated_stations_;
  42. void OnStationEvent(StationEvent event,
  43. const std::vector<uint8_t>& mac_address);
  44. void OnChannelSwitchEvent(uint32_t frequency, ChannelBandwidth bandwidth);
  45. DISALLOW_COPY_AND_ASSIGN(ApInterfaceImpl);
  46. };
  47. } // namespace wificond
  48. } // namespace android
  49. #endif // WIFICOND_AP_INTERFACE_IMPL_H_

StartHostapd()。

22 system/connectivity/wificond/ap_interface_impl.cpp

  1. bool ApInterfaceImpl::StartHostapd() {
  2. return hostapd_manager_->StartHostapd();
  3. }
(0)

相关推荐