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
@Overridepublic 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
@Overridepublic 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) {@Overrideprotected 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*/@SystemApipublic 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
@Overridepublic 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*/@Overridepublic 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_APif (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 IndentationCheckaddState(mDefaultState);addState(mStaDisabledState, mDefaultState);addState(mStaEnabledState, mDefaultState);addState(mDeviceActiveState, mStaEnabledState);addState(mStaDisabledWithScanState, mDefaultState);addState(mEcmState, mDefaultState);// CHECKSTYLE:ON IndentationCheckboolean 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 falseif (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(); //位置1mPersistWifiState = 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;@Overridepublic void enter() {mWifiStateMachinePrime.disableWifi();// Supplicant can't restart right away, so note the time we switched offmDisabledTimestamp = 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 modeif (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 softapmSettingsStore.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 modeif (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的内部类。
@Overridepublic 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();}
