一 前言
Android使用一個修改版wpa_supplicant作為daemon來控制WIFI,,它是一個安全中間件,,代碼位于external/wpa_supplicant,為各種無線網(wǎng)卡提供統(tǒng)一的安全機(jī)制,。當(dāng)然在這里只是介紹一下wpa_supplicant和 hostapd,,研究分析的部分主要還是應(yīng)用層和java框架層,有時也會涉及Native層。
wpa_supplicant_8主要有三個子目錄 :
hostapd:當(dāng)手機(jī)進(jìn)入Soft AP模式時,,手機(jī)將扮演AP的角色,,需要hostapd來提供AP的功能,也就是wifi熱點(diǎn)的實現(xiàn),。
wpa_supplicant:Station模式,,也叫Managed模式,這是平時最常見的使用wifi連接AP的情況,。
src:hostapd和wpa_supplicant中都包含一些通用的數(shù)據(jù)結(jié)構(gòu)和處理方法,這些內(nèi)容都放在此src目錄中,。
二 圖示調(diào)用流程
三 具體代碼流程
Android P之后,,Wifi模塊增加了packages/apps/Settings/src/com/android/settings/wifi/tether/路徑,相當(dāng)于把Wifi熱點(diǎn)獨(dú)立放到了tether文件夾下面,,并添加了WifiTetherSettings.java類,,對應(yīng)著Wifi熱點(diǎn)的界面,而Android P之前是沒有的,,Wifi熱點(diǎn)界面之前是對應(yīng)在TetherSettings的一部分,,有些廠商也還是會改到TetherSettings上。
1 packages/apps/Settings/src/com/android/settings/wifi/tether/WifiTetherSettings.java
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);
初始化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
public boolean onSwitchToggled(boolean isChecked) { } else if (!mWifiManager.isWifiApEnabled()) {
startTether(),。
mSwitchBar.setEnabled(false); mConnectivityManager.startTethering(TETHERING_WIFI, true /* showProvisioningUi */, mOnStartTetheringCallback, new Handler(Looper.getMainLooper()));
android O開始通過mConnectivityManager.startTethering來啟動熱點(diǎn)了,之前都是通過WifiManager的setWifiApEnable的方法,,該方法現(xiàn)在也已廢棄,。
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}. @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. @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) { protected void onReceiveResult(int resultCode, Bundle resultData) { if (resultCode == TETHER_ERROR_NO_ERROR) { callback.onTetheringStarted(); callback.onTetheringFailed(); 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);
內(nèi)部抽象類OnStartTetheringCallback,。
* Callback for use with {@link #startTethering} to find out whether tethering succeeded. 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
public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi, ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg); if (!isTetheringSupported()) { receiver.send(ConnectivityManager.TETHER_ERROR_UNSUPPORTED, null); 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); if (showProvisioningUi) { runUiTetherProvisioningAndEnable(type, receiver); 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(); result = setWifiTethering(enable); if (isProvisioningRequired && result == TETHER_ERROR_NO_ERROR) { scheduleProvisioningRechecks(type); sendTetherResult(receiver, result); result = setUsbTethering(enable); if (isProvisioningRequired && result == TETHER_ERROR_NO_ERROR) { scheduleProvisioningRechecks(type); sendTetherResult(receiver, result); case TETHERING_BLUETOOTH: setBluetoothTethering(enable, receiver); 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(); 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; Binder.restoreCallingIdentity(ident);
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 * @param wifiConfig SSID, security and channel details as * part of WifiConfiguration * @return {@code true} if the operation succeeds, {@code false} otherwise public boolean startSoftAp(@Nullable WifiConfiguration wifiConfig) { 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 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()) { 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); Slog.e(TAG, "Invalid WifiConfiguration");
mWifiController.sendMessage,。
10 frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiController.java
public class WifiController extends StateMachine
WifiController是個狀態(tài)機(jī),,看看它的初始狀態(tài),。
WifiController(Context context, WifiStateMachine wsm, Looper wifiStateMachineLooper, WifiSettingsStore wss, Looper wifiServiceLooper, FrameworkFacade f, WifiStateMachinePrime wsmp) { super(TAG, wifiServiceLooper); mWifiStateMachineLooper = wifiStateMachineLooper; mWifiStateMachinePrime = wsmp; // CHECKSTYLE:OFF IndentationCheck 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); 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 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) { mAirplaneModeOn = getPersistedAirplaneModeOn(); //位置1 mPersistWifiState = getPersistedWifiState(); mScanAlwaysAvailable = getPersistedScanAlwaysAvailable(); //位置2
看getPersistedScanAlwaysAvailable()方法,。
private boolean getPersistedScanAlwaysAvailable() { return Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE,
可以看到,,最終是判斷Wifi的狀態(tài)是不是處于一直可掃描的狀態(tài)。
由前面的mAirplaneModeOn = getPersistedAirplaneModeOn()再看mAirplaneModeOn的狀態(tài)是什么,。
private boolean getPersistedAirplaneModeOn() { return Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
可以看到,,最終是判斷手機(jī)是不是飛行模式,。
如果手機(jī)不是飛行模式并且Wifi的狀態(tài)是處于一直可掃描的狀態(tài),則返回true,,那么WifiController狀態(tài)機(jī)的初始狀態(tài)被設(shè)為StaDisabledState狀態(tài),,即setInitialState(mStaDisabledState)。否則,,初始狀態(tài)被設(shè)為StaDisabledWithScanState狀態(tài),,即setInitialState(mStaDisabledWithScanState)。我們現(xiàn)在是處于初始狀態(tài)為StaDisabledState的情況,。
WifiController狀態(tài)機(jī),,之前的博客有畫過該狀態(tài)機(jī)。
由于初始狀態(tài)是StaDisabledState,,狀態(tài)機(jī)會執(zhí)行從根狀態(tài)到StaDisabledState的所有enter()方法,,StaDisabledState的父狀態(tài)為DefultState。DefultState沒有重寫enter()方法,,直接看StaDisabledState的enter()方法,。
class StaDisabledState extends State { private int mDeferredEnableSerialNumber = 0; private boolean mHaveDeferredEnable = false; private long mDisabledTimestamp; 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()首先會關(guān)掉Wifi,這個就不再往后延展了,。
接著初始狀態(tài)StaDisabledState開始處理消息CMD_SET_AP,。
// first make sure we aren't in airplane mode if (mSettingsStore.isAirplaneModeOn()) { log("drop softap requests when in airplane mode"); // remember that we were disabled, but pass the command up to start softap mSettingsStore.setWifiSavedState(WifiSettingsStore.WIFI_DISABLED);
mSettingsStore.setWifiSavedState(WifiSettingsStore.WIFI_DISABLED)會記錄Wifi已經(jīng)關(guān)閉的狀態(tài),這個不再往后延展,。由于最后return NOT_HANDLED,,所以說明子狀態(tài)無法處理則轉(zhuǎn)給父狀態(tài)處理,即DefaultState,。
// 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"); SoftApModeConfiguration config = (SoftApModeConfiguration) msg.obj; mWifiStateMachinePrime.enterSoftAPMode((SoftApModeConfiguration) msg.obj); mWifiStateMachinePrime.stopSoftAPMode();
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) {
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); SoftApCallbackImpl callback = new SoftApCallbackImpl(); ActiveModeManager manager = mWifiInjector.makeSoftApManager(callback, softapConfig); callback.setActiveModeManager(manager); 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.
start(),。
15 frameworks/opt/net/wifi/service/java/com/android/server/wifi/SoftApManager.java
* Start soft AP with the supplied config. mStateMachine.sendMessage(SoftApStateMachine.CMD_START, mApConfig);
SoftApStateMachine.CMD_START。
SoftApStateMachine是SoftApManager的內(nèi)部類,。
public boolean processMessage(Message message) { 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); updateApState(WifiManager.WIFI_AP_STATE_ENABLING, WifiManager.WIFI_AP_STATE_DISABLED, 0); int result = startSoftAp((WifiConfiguration) message.obj); 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, mWifiMetrics.incrementSoftApStartResult(false, failureReason); transitionTo(mStartedState); // Ignore all other commands.
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"); // 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); Log.e(TAG, "Failed to update AP band and channel"); // 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 " if (localConfig.hiddenSSID) { Log.d(TAG, "SoftAP is a hidden network"); if (!mWifiNative.startSoftAp(mApInterfaceName, localConfig, mSoftApListener)) { Log.e(TAG, "Soft AP start failed"); Log.d(TAG, "Soft AP is started");
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(); if (!waitForHostapdConnection()) { Log.e(TAG, "Failed to establish connection to hostapd"); mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd(); if (!mHostapdHal.registerDeathHandler(new HostapdDeathHandlerInternal())) { Log.e(TAG, "Failed to register hostapd death handler"); mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd(); if (!mHostapdHal.addAccessPoint(ifaceName, config)) { Log.e(TAG, "Failed to add acccess point"); mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
做了這些操作:
mWificondControl.startHostapd
waitForHostapdConnection
mHostapdHal.registerDeathHandler
mHostapdHal.addAccessPoint
就以mWificondControl.startHostapd為主線進(jìn)行分析,。
17 frameworks/opt/net/wifi/service/java/com/android/server/wifi/WificondControl.java
* 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); Log.e(TAG, "No valid ap interface handler"); IApInterfaceEventCallback callback = new ApInterfaceEventCallback(listener); mApInterfaceListeners.put(ifaceName, callback); boolean success = iface.startHostapd(callback); Log.e(TAG, "Failed to start hostapd."); } catch (RemoteException e) { Log.e(TAG, "Exception in starting soft AP: " + e);
看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) { LOG(WARNING) << "Cannot start hostapd on dead ApInterface."; return binder::Status::ok(); *out_success = impl_->StartHostapd(); 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 <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" // 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. ApInterfaceImpl(const std::string& interface_name, uint32_t interface_index, NetlinkUtils* netlink_utils, wifi_system::InterfaceTool* if_tool, wifi_system::HostapdManager* hostapd_manager); // Get a pointer to the binder representing this ApInterfaceImpl. android::sp<android::net::wifi::IApInterface> GetBinder() const; std::string GetInterfaceName() { return interface_name_; } int GetNumberOfAssociatedStations() const; void Dump(std::stringstream* ss) const; 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); #endif // WIFICOND_AP_INTERFACE_IMPL_H_
StartHostapd()。
22 system/connectivity/wificond/ap_interface_impl.cpp
bool ApInterfaceImpl::StartHostapd() { return hostapd_manager_->StartHostapd();
|