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
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- // Assume we are in a SettingsActivity. This is only safe because we currently use
- // SettingsActivity as base for all preference fragments.
- final SettingsActivity activity = (SettingsActivity) getActivity();
- final SwitchBar switchBar = activity.getSwitchBar();
- mSwitchBarController = new WifiTetherSwitchBarController(activity,
- new SwitchBarController(switchBar));
- getLifecycle().addObserver(mSwitchBarController);
- switchBar.show();
- }
初始化mSwitchBarController,这个类含有SwitchBar的实例。
2 packages/apps/Settings/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java
- public class WifiTetherSwitchBarController implements SwitchWidgetController.OnSwitchChangeListener,
- LifecycleObserver, OnStart, OnStop, DataSaverBackend.Listener {
3 packages/apps/Settings/src/com/android/settings/widget/SwitchWidgetController.java
- /**
- * Interface definition for a callback to be invoked when the switch has been toggled.
- */
- public interface OnSwitchChangeListener {
- /**
- * Called when the checked state of the Switch has changed.
- *
- * @param isChecked The new checked state of switchView.
- *
- * @return true to update the state of the switch with the new value.
- */
- boolean onSwitchToggled(boolean isChecked);
- }
4 packages/apps/Settings/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java
- @Override
- public boolean onSwitchToggled(boolean isChecked) {
- if (!isChecked) {
- stopTether();
- } else if (!mWifiManager.isWifiApEnabled()) {
- startTether();
- }
- return true;
- }
startTether()。
- void startTether() {
- mSwitchBar.setEnabled(false);
- mConnectivityManager.startTethering(TETHERING_WIFI, true /* showProvisioningUi */,
- mOnStartTetheringCallback, new Handler(Looper.getMainLooper()));
- }
android O开始通过mConnectivityManager.startTethering来启动热点了,之前都是通过WifiManager的setWifiApEnable的方法,该方法现在也已废弃。
5 frameworks/base/core/java/android/net/ConnectivityManager.java
- /**
- * Convenient overload for
- * {@link #startTethering(int, boolean, OnStartTetheringCallback, Handler)} which passes a null
- * handler to run on the current thread's {@link Looper}.
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
- public void startTethering(int type, boolean showProvisioningUi,
- final OnStartTetheringCallback callback) {
- startTethering(type, showProvisioningUi, callback, null);
- }
startTethering。
- /**
- * Runs tether provisioning for the given type if needed and then starts tethering if
- * the check succeeds. If no carrier provisioning is required for tethering, tethering is
- * enabled immediately. If provisioning fails, tethering will not be enabled. It also
- * schedules tether provisioning re-checks if appropriate.
- *
- * @param type The type of tethering to start. Must be one of
- * {@link ConnectivityManager.TETHERING_WIFI},
- * {@link ConnectivityManager.TETHERING_USB}, or
- * {@link ConnectivityManager.TETHERING_BLUETOOTH}.
- * @param showProvisioningUi a boolean indicating to show the provisioning app UI if there
- * is one. This should be true the first time this function is called and also any time
- * the user can see this UI. It gives users information from their carrier about the
- * check failing and how they can sign up for tethering if possible.
- * @param callback an {@link OnStartTetheringCallback} which will be called to notify the caller
- * of the result of trying to tether.
- * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
- public void startTethering(int type, boolean showProvisioningUi,
- final OnStartTetheringCallback callback, Handler handler) {
- Preconditions.checkNotNull(callback, "OnStartTetheringCallback cannot be null.");
- ResultReceiver wrappedCallback = new ResultReceiver(handler) {
- @Override
- protected void onReceiveResult(int resultCode, Bundle resultData) {
- if (resultCode == TETHER_ERROR_NO_ERROR) {
- callback.onTetheringStarted();
- } else {
- callback.onTetheringFailed();
- }
- }
- };
- try {
- String pkgName = mContext.getOpPackageName();
- Log.i(TAG, "startTethering caller:" + pkgName);
- mService.startTethering(type, wrappedCallback, showProvisioningUi, pkgName);
- } catch (RemoteException e) {
- Log.e(TAG, "Exception trying to start tethering.", e);
- wrappedCallback.send(TETHER_ERROR_SERVICE_UNAVAIL, null);
- }
- }
内部抽象类OnStartTetheringCallback。
- /**
- * Callback for use with {@link #startTethering} to find out whether tethering succeeded.
- * @hide
- */
- @SystemApi
- public static abstract class OnStartTetheringCallback {
- /**
- * Called when tethering has been successfully started.
- */
- public void onTetheringStarted() {};
- /**
- * Called when starting tethering failed.
- */
- public void onTetheringFailed() {};
- }
6 frameworks/base/services/core/java/com/android/server/ConnectivityService.java
- @Override
- public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi,
- String callerPkg) {
- ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
- if (!isTetheringSupported()) {
- receiver.send(ConnectivityManager.TETHER_ERROR_UNSUPPORTED, null);
- return;
- }
- mTethering.startTethering(type, receiver, showProvisioningUi);
- }
7 frameworks/base/services/core/java/com/android/server/connectivity/Tethering.java
- public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) {
- if (!isTetherProvisioningRequired()) {
- enableTetheringInternal(type, true, receiver);
- return;
- }
- if (showProvisioningUi) {
- runUiTetherProvisioningAndEnable(type, receiver);
- } else {
- runSilentTetherProvisioningAndEnable(type, receiver);
- }
- }
enableTetheringInternal。
- /**
- * Enables or disables tethering for the given type. This should only be called once
- * provisioning has succeeded or is not necessary. It will also schedule provisioning rechecks
- * for the specified interface.
- */
- private void enableTetheringInternal(int type, boolean enable, ResultReceiver receiver) {
- boolean isProvisioningRequired = enable && isTetherProvisioningRequired();
- int result;
- switch (type) {
- case TETHERING_WIFI:
- result = setWifiTethering(enable);
- if (isProvisioningRequired && result == TETHER_ERROR_NO_ERROR) {
- scheduleProvisioningRechecks(type);
- }
- sendTetherResult(receiver, result);
- break;
- case TETHERING_USB:
- result = setUsbTethering(enable);
- if (isProvisioningRequired && result == TETHER_ERROR_NO_ERROR) {
- scheduleProvisioningRechecks(type);
- }
- sendTetherResult(receiver, result);
- break;
- case TETHERING_BLUETOOTH:
- setBluetoothTethering(enable, receiver);
- break;
- default:
- Log.w(TAG, "Invalid tether type.");
- sendTetherResult(receiver, TETHER_ERROR_UNKNOWN_IFACE);
- }
- }
setWifiTethering。
- private int setWifiTethering(final boolean enable) {
- int rval = TETHER_ERROR_MASTER_ERROR;
- final long ident = Binder.clearCallingIdentity();
- try {
- synchronized (mPublicSync) {
- mWifiTetherRequested = enable;
- final WifiManager mgr = getWifiManager();
- if ((enable && mgr.startSoftAp(null /* use existing wifi config */)) ||
- (!enable && mgr.stopSoftAp())) {
- rval = TETHER_ERROR_NO_ERROR;
- }
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- return rval;
- }
mgr.startSoftAp。
8 frameworks/base/wifi/java/android/net/wifi/WifiManager.java
- /**
- * Start SoftAp mode with the specified configuration.
- * Note that starting in access point mode disables station
- * mode operation
- * @param wifiConfig SSID, security and channel details as
- * part of WifiConfiguration
- * @return {@code true} if the operation succeeds, {@code false} otherwise
- *
- * @hide
- */
- public boolean startSoftAp(@Nullable WifiConfiguration wifiConfig) {
- try {
- return mService.startSoftAp(wifiConfig);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
startSoftAp。
9 frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java
- /**
- * see {@link android.net.wifi.WifiManager#startSoftAp(WifiConfiguration)}
- * @param wifiConfig SSID, security and channel details as part of WifiConfiguration
- * @return {@code true} if softap start was triggered
- * @throws SecurityException if the caller does not have permission to start softap
- */
- @Override
- public boolean startSoftAp(WifiConfiguration wifiConfig) {
- // NETWORK_STACK is a signature only permission.
- enforceNetworkStackPermission();
- mLog.info("startSoftAp uid=%").c(Binder.getCallingUid()).flush();
- synchronized (mLocalOnlyHotspotRequests) {
- // If a tethering request comes in while we have LOHS running (or requested), call stop
- // for softap mode and restart softap with the tethering config.
- if (!mLocalOnlyHotspotRequests.isEmpty()) {
- stopSoftApInternal();
- }
- return startSoftApInternal(wifiConfig, WifiManager.IFACE_IP_MODE_TETHERED);
- }
- }
startSoftApInternal。
- /**
- * Internal method to start softap mode. Callers of this method should have already checked
- * proper permissions beyond the NetworkStack permission.
- */
- private boolean startSoftApInternal(WifiConfiguration wifiConfig, int mode) {
- mLog.trace("startSoftApInternal uid=% mode=%")
- .c(Binder.getCallingUid()).c(mode).flush();
- // null wifiConfig is a meaningful input for CMD_SET_AP
- if (wifiConfig == null || WifiApConfigStore.validateApWifiConfiguration(wifiConfig)) {
- SoftApModeConfiguration softApConfig = new SoftApModeConfiguration(mode, wifiConfig);
- mWifiController.sendMessage(CMD_SET_AP, 1, 0, softApConfig);
- return true;
- }
- Slog.e(TAG, "Invalid WifiConfiguration");
- return false;
- }
mWifiController.sendMessage。
10 frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiController.java
public class WifiController extends StateMachine
WifiController是个状态机,看看它的初始状态。
- WifiController(Context context, WifiStateMachine wsm, Looper wifiStateMachineLooper,
- WifiSettingsStore wss, Looper wifiServiceLooper, FrameworkFacade f,
- WifiStateMachinePrime wsmp) {
- super(TAG, wifiServiceLooper);
- mFacade = f;
- mContext = context;
- mWifiStateMachine = wsm;
- mWifiStateMachineLooper = wifiStateMachineLooper;
- mWifiStateMachinePrime = wsmp;
- mSettingsStore = wss;
- // CHECKSTYLE:OFF IndentationCheck
- addState(mDefaultState);
- addState(mStaDisabledState, mDefaultState);
- addState(mStaEnabledState, mDefaultState);
- addState(mDeviceActiveState, mStaEnabledState);
- addState(mStaDisabledWithScanState, mDefaultState);
- addState(mEcmState, mDefaultState);
- // CHECKSTYLE:ON IndentationCheck
- boolean isAirplaneModeOn = mSettingsStore.isAirplaneModeOn();
- boolean isWifiEnabled = mSettingsStore.isWifiToggleEnabled();
- boolean isScanningAlwaysAvailable = mSettingsStore.isScanAlwaysAvailable();
- boolean isLocationModeActive =
- mSettingsStore.getLocationModeSetting(mContext)
- == Settings.Secure.LOCATION_MODE_OFF;
- log("isAirplaneModeOn = " + isAirplaneModeOn
- + ", isWifiEnabled = " + isWifiEnabled
- + ", isScanningAvailable = " + isScanningAlwaysAvailable
- + ", isLocationModeActive = " + isLocationModeActive);
- if (checkScanOnlyModeAvailable()) {
- setInitialState(mStaDisabledWithScanState);
- } else {
- setInitialState(mStaDisabledState);
- }
- ...
- }
看checkScanOnlyModeAvailable方法。
- private boolean checkScanOnlyModeAvailable() {
- // first check if Location service is disabled, if so return false
- if (mSettingsStore.getLocationModeSetting(mContext)
- == Settings.Secure.LOCATION_MODE_OFF) {
- return false;
- }
- return mSettingsStore.isScanAlwaysAvailable();
- }
mSettingsStore是WifiSettingsStore的对象,看其isScanAlwaysAvailable方法。
11 frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiSettingsStore.java
- public synchronized boolean isScanAlwaysAvailable() {
- return !mAirplaneModeOn && mScanAlwaysAvailable;
- }
看mScanAlwaysAvailable是什么。
- WifiSettingsStore(Context context) {
- mContext = context;
- mAirplaneModeOn = getPersistedAirplaneModeOn(); //位置1
- mPersistWifiState = getPersistedWifiState();
- mScanAlwaysAvailable = getPersistedScanAlwaysAvailable(); //位置2
- }
看getPersistedScanAlwaysAvailable()方法。
- private boolean getPersistedScanAlwaysAvailable() {
- return Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE,
- 0) == 1;
- }
可以看到,最终是判断Wifi的状态是不是处于一直可扫描的状态。
由前面的mAirplaneModeOn = getPersistedAirplaneModeOn()再看mAirplaneModeOn的状态是什么。
- private boolean getPersistedAirplaneModeOn() {
- return Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
- }
可以看到,最终是判断手机是不是飞行模式。
如果手机不是飞行模式并且Wifi的状态是处于一直可扫描的状态,则返回true,那么WifiController状态机的初始状态被设为StaDisabledState状态,即setInitialState(mStaDisabledState)。否则,初始状态被设为StaDisabledWithScanState状态,即setInitialState(mStaDisabledWithScanState)。我们现在是处于初始状态为StaDisabledState的情况。
WifiController状态机,之前的博客有画过该状态机。
由于初始状态是StaDisabledState,状态机会执行从根状态到StaDisabledState的所有enter()方法,StaDisabledState的父状态为DefultState。DefultState没有重写enter()方法,直接看StaDisabledState的enter()方法。
- class StaDisabledState extends State {
- private int mDeferredEnableSerialNumber = 0;
- private boolean mHaveDeferredEnable = false;
- private long mDisabledTimestamp;
- @Override
- public void enter() {
- mWifiStateMachinePrime.disableWifi();
- // Supplicant can't restart right away, so note the time we switched off
- mDisabledTimestamp = SystemClock.elapsedRealtime();
- mDeferredEnableSerialNumber++;
- mHaveDeferredEnable = false;
- mWifiStateMachine.clearANQPCache();
- }
- }
mWifiStateMachinePrime.disableWifi()首先会关掉Wifi,这个就不再往后延展了。
接着初始状态StaDisabledState开始处理消息CMD_SET_AP。
- case CMD_SET_AP:
- // first make sure we aren't in airplane mode
- if (mSettingsStore.isAirplaneModeOn()) {
- log("drop softap requests when in airplane mode");
- break;
- }
- if (msg.arg1 == 1) {
- // remember that we were disabled, but pass the command up to start softap
- mSettingsStore.setWifiSavedState(WifiSettingsStore.WIFI_DISABLED);
- }
- return NOT_HANDLED;
mSettingsStore.setWifiSavedState(WifiSettingsStore.WIFI_DISABLED)会记录Wifi已经关闭的状态,这个不再往后延展。由于最后return NOT_HANDLED,所以说明子状态无法处理则转给父状态处理,即DefaultState。
- case CMD_SET_AP:
- // note: CMD_SET_AP is handled/dropped in ECM mode - will not start here
- // first make sure we aren't in airplane mode
- if (mSettingsStore.isAirplaneModeOn()) {
- log("drop softap requests when in airplane mode");
- break;
- }
- if (msg.arg1 == 1) {
- SoftApModeConfiguration config = (SoftApModeConfiguration) msg.obj;
- mWifiStateMachinePrime.enterSoftAPMode((SoftApModeConfiguration) msg.obj);
- } else {
- mWifiStateMachinePrime.stopSoftAPMode();
- }
- break;
12 frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachinePrime.java
- /**
- * Method to enable soft ap for wifi hotspot.
- *
- * The supplied SoftApModeConfiguration includes the target softap WifiConfiguration (or null if
- * the persisted config is to be used) and the target operating mode (ex,
- * {@link WifiManager.IFACE_IP_MODE_TETHERED} {@link WifiManager.IFACE_IP_MODE_LOCAL_ONLY}).
- *
- * @param wifiConfig SoftApModeConfiguration for the hostapd softap
- */
- public void enterSoftAPMode(@NonNull SoftApModeConfiguration wifiConfig) {
- mHandler.post(() -> {
- startSoftAp(wifiConfig);
- });
- }
startSoftAp。
- private void startSoftAp(SoftApModeConfiguration softapConfig) {
- Log.d(TAG, "Starting SoftApModeManager");
- WifiConfiguration config = softapConfig.getWifiConfiguration();
- if (config != null && config.SSID != null) {
- Log.d(TAG, "Passing config to SoftApManager! " + config);
- } else {
- config = null;
- }
- SoftApCallbackImpl callback = new SoftApCallbackImpl();
- ActiveModeManager manager = mWifiInjector.makeSoftApManager(callback, softapConfig);
- callback.setActiveModeManager(manager);
- manager.start();
- mActiveModeManagers.add(manager);
- updateBatteryStatsWifiState(true);
- }
mWifiInjector.makeSoftApManager。
13 frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiInjector.java
- /**
- * Create a SoftApManager.
- * @param listener listener for SoftApManager
- * @param config SoftApModeConfiguration object holding the config and mode
- * @return an instance of SoftApManager
- */
- public SoftApManager makeSoftApManager(@NonNull WifiManager.SoftApCallback callback,
- @NonNull SoftApModeConfiguration config) {
- return new SoftApManager(mContext, mWifiStateMachineHandlerThread.getLooper(),
- mFrameworkFacade, mWifiNative, mCountryCode.getCountryCode(), callback,
- mWifiApConfigStore, config, mWifiMetrics);
- }
manager.start()。
14 frameworks/opt/net/wifi/service/java/com/android/server/wifi/ActiveModeManager.java
- /**
- * Method used to start the Manager for a given Wifi operational mode.
- */
- void start();
start()。
15 frameworks/opt/net/wifi/service/java/com/android/server/wifi/SoftApManager.java
- /**
- * Start soft AP with the supplied config.
- */
- public void start() {
- mStateMachine.sendMessage(SoftApStateMachine.CMD_START, mApConfig);
- }
SoftApStateMachine.CMD_START。
SoftApStateMachine是SoftApManager的内部类。
- @Override
- public boolean processMessage(Message message) {
- switch (message.what) {
- case CMD_START:
- mApInterfaceName = mWifiNative.setupInterfaceForSoftApMode(
- mWifiNativeInterfaceCallback);
- if (TextUtils.isEmpty(mApInterfaceName)) {
- Log.e(TAG, "setup failure when creating ap interface.");
- updateApState(WifiManager.WIFI_AP_STATE_FAILED,
- WifiManager.WIFI_AP_STATE_DISABLED,
- WifiManager.SAP_START_FAILURE_GENERAL);
- mWifiMetrics.incrementSoftApStartResult(
- false, WifiManager.SAP_START_FAILURE_GENERAL);
- break;
- }
- updateApState(WifiManager.WIFI_AP_STATE_ENABLING,
- WifiManager.WIFI_AP_STATE_DISABLED, 0);
- int result = startSoftAp((WifiConfiguration) message.obj);
- if (result != SUCCESS) {
- int failureReason = WifiManager.SAP_START_FAILURE_GENERAL;
- if (result == ERROR_NO_CHANNEL) {
- failureReason = WifiManager.SAP_START_FAILURE_NO_CHANNEL;
- }
- updateApState(WifiManager.WIFI_AP_STATE_FAILED,
- WifiManager.WIFI_AP_STATE_ENABLING,
- failureReason);
- stopSoftAp();
- mWifiMetrics.incrementSoftApStartResult(false, failureReason);
- break;
- }
- transitionTo(mStartedState);
- break;
- default:
- // Ignore all other commands.
- break;
- }
- return HANDLED;
- }
- }
startSoftAp。
- /**
- * Start a soft AP instance with the given configuration.
- * @param config AP configuration
- * @return integer result code
- */
- private int startSoftAp(WifiConfiguration config) {
- if (config == null || config.SSID == null) {
- Log.e(TAG, "Unable to start soft AP without valid configuration");
- return ERROR_GENERIC;
- }
- // Make a copy of configuration for updating AP band and channel.
- WifiConfiguration localConfig = new WifiConfiguration(config);
- int result = ApConfigUtil.updateApChannelConfig(
- mWifiNative, mCountryCode,
- mWifiApConfigStore.getAllowed2GChannel(), localConfig);
- if (result != SUCCESS) {
- Log.e(TAG, "Failed to update AP band and channel");
- return result;
- }
- // Setup country code if it is provided.
- if (mCountryCode != null) {
- // Country code is mandatory for 5GHz band, return an error if failed to set
- // country code when AP is configured for 5GHz band.
- if (!mWifiNative.setCountryCodeHal(
- mApInterfaceName, mCountryCode.toUpperCase(Locale.ROOT))
- && config.apBand == WifiConfiguration.AP_BAND_5GHZ) {
- Log.e(TAG, "Failed to set country code, required for setting up "
- + "soft ap in 5GHz");
- return ERROR_GENERIC;
- }
- }
- if (localConfig.hiddenSSID) {
- Log.d(TAG, "SoftAP is a hidden network");
- }
- if (!mWifiNative.startSoftAp(mApInterfaceName, localConfig, mSoftApListener)) {
- Log.e(TAG, "Soft AP start failed");
- return ERROR_GENERIC;
- }
- Log.d(TAG, "Soft AP is started");
- return SUCCESS;
- }
mWifiNative.startSoftAp。
16 frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java
- /**
- * Start Soft AP operation using the provided configuration.
- *
- * @param ifaceName Name of the interface.
- * @param config Configuration to use for the soft ap created.
- * @param listener Callback for AP events.
- * @return true on success, false otherwise.
- */
- public boolean startSoftAp(
- @NonNull String ifaceName, WifiConfiguration config, SoftApListener listener) {
- if (!mWificondControl.startHostapd(ifaceName, listener)) {
- Log.e(TAG, "Failed to start hostapd");
- mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
- return false;
- }
- if (!waitForHostapdConnection()) {
- Log.e(TAG, "Failed to establish connection to hostapd");
- mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
- return false;
- }
- if (!mHostapdHal.registerDeathHandler(new HostapdDeathHandlerInternal())) {
- Log.e(TAG, "Failed to register hostapd death handler");
- mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
- return false;
- }
- if (!mHostapdHal.addAccessPoint(ifaceName, config)) {
- Log.e(TAG, "Failed to add acccess point");
- mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
- return false;
- }
- return true;
- }
做了这些操作:
mWificondControl.startHostapd
waitForHostapdConnection
mHostapdHal.registerDeathHandler
mHostapdHal.addAccessPoint
就以mWificondControl.startHostapd为主线进行分析。
17 frameworks/opt/net/wifi/service/java/com/android/server/wifi/WificondControl.java
- /**
- * Start hostapd
- * TODO(b/71513606): Move this to a global operation.
- *
- * @param ifaceName Name of the interface.
- * @param listener Callback for AP events.
- * @return true on success, false otherwise.
- */
- public boolean startHostapd(@NonNull String ifaceName,
- SoftApListener listener) {
- IApInterface iface = getApInterface(ifaceName);
- if (iface == null) {
- Log.e(TAG, "No valid ap interface handler");
- return false;
- }
- try {
- IApInterfaceEventCallback callback = new ApInterfaceEventCallback(listener);
- mApInterfaceListeners.put(ifaceName, callback);
- boolean success = iface.startHostapd(callback);
- if (!success) {
- Log.e(TAG, "Failed to start hostapd.");
- return false;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Exception in starting soft AP: " + e);
- return false;
- }
- return true;
- }
看iface.startHostapd,走到Native层。
18 system/connectivity/wificond/aidl/android/net/wifi/IApInterface.aidl
- // Start up an instance of hostapd associated with this interface.
- //
- // @param callback Object to add a set of event callbacks.
- // @return true on success.
- boolean startHostapd(IApInterfaceEventCallback callback);
19 system/connectivity/wificond/ap_interface_binder.h
- binder::Status startHostapd(
- const sp<net::wifi::IApInterfaceEventCallback>& callback,
- bool* out_success) override;
20 system/connectivity/wificond/ap_interface_binder.cpp
startHostapd。
- binder::Status ApInterfaceBinder::startHostapd(
- const sp<IApInterfaceEventCallback>& callback, bool* out_success) {
- *out_success = false;
- if (!impl_) {
- LOG(WARNING) << "Cannot start hostapd on dead ApInterface.";
- return binder::Status::ok();
- }
- *out_success = impl_->StartHostapd();
- if (*out_success) {
- ap_interface_event_callback_ = callback;
- }
- return binder::Status::ok();
- }
impl_->StartHostapd()。
21 system/connectivity/wificond/ap_interface_impl.h
- #ifndef WIFICOND_AP_INTERFACE_IMPL_H_
- #define WIFICOND_AP_INTERFACE_IMPL_H_
- #include <string>
- #include <vector>
- #include <android-base/macros.h>
- #include <wifi_system/hostapd_manager.h>
- #include <wifi_system/interface_tool.h>
- #include "wificond/net/netlink_manager.h"
- #include "android/net/wifi/IApInterface.h"
- namespace android {
- namespace wificond {
- class ApInterfaceBinder;
- class NetlinkUtils;
- // Holds the guts of how we control network interfaces capable of exposing an AP
- // via hostapd. Because remote processes may hold on to the corresponding
- // binder object past the lifetime of the local object, we are forced to
- // keep this object separate from the binder representation of itself.
- class ApInterfaceImpl {
- public:
- ApInterfaceImpl(const std::string& interface_name,
- uint32_t interface_index,
- NetlinkUtils* netlink_utils,
- wifi_system::InterfaceTool* if_tool,
- wifi_system::HostapdManager* hostapd_manager);
- ~ApInterfaceImpl();
- // Get a pointer to the binder representing this ApInterfaceImpl.
- android::sp<android::net::wifi::IApInterface> GetBinder() const;
- bool StartHostapd();
- bool StopHostapd();
- std::string GetInterfaceName() { return interface_name_; }
- int GetNumberOfAssociatedStations() const;
- void Dump(std::stringstream* ss) const;
- private:
- const std::string interface_name_;
- const uint32_t interface_index_;
- NetlinkUtils* const netlink_utils_;
- wifi_system::InterfaceTool* const if_tool_;
- wifi_system::HostapdManager* const hostapd_manager_;
- const android::sp<ApInterfaceBinder> binder_;
- // Number of associated stations.
- int number_of_associated_stations_;
- void OnStationEvent(StationEvent event,
- const std::vector<uint8_t>& mac_address);
- void OnChannelSwitchEvent(uint32_t frequency, ChannelBandwidth bandwidth);
- DISALLOW_COPY_AND_ASSIGN(ApInterfaceImpl);
- };
- } // namespace wificond
- } // namespace android
- #endif // WIFICOND_AP_INTERFACE_IMPL_H_
StartHostapd()。
22 system/connectivity/wificond/ap_interface_impl.cpp
- bool ApInterfaceImpl::StartHostapd() {
- return hostapd_manager_->StartHostapd();
- }
联系客服