赞
踩
近期在看一个热点启动的问题。发现网上基本上都算android 9 的wifi热点启动流程。自己去看android 13 的源码的时候发现与之前相比已经有一些小改动了。
在此总结一下wifie热点的启动流程。
我们直接从setting的热点开启按钮 点击事件开始看起。
按钮的初始化在
packages/apps/Settings/src/com/android/settings/wifi/tether/WifiTetherSettings.java
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- if (mUnavailable) {
- return;
- }
- // 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 SettingsMainSwitchBar switchBar = activity.getSwitchBar();
- switchBar.setTitle(getContext().getString(R.string.use_wifi_hotsopt_main_switch_title));
- mSwitchBarController = new WifiTetherSwitchBarController(activity, switchBar);
- getSettingsLifecycle().addObserver(mSwitchBarController);
- switchBar.show();
- }
可以看到按钮的控制类在 WifiTetherSwitchBarController 里面。
packages/apps/Settings/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java
- @Override
- public void onStart() {
- mDataSaverBackend.addListener(this);
- mSwitchBar.addOnSwitchChangeListener(this);
- mContext.registerReceiver(mReceiver, WIFI_INTENT_FILTER,
- Context.RECEIVER_EXPORTED_UNAUDITED);
- }
-
-
- @Override
- public void onSwitchChanged(Switch switchView, boolean isChecked) {
- // Filter out unnecessary callbacks when switch is disabled.
- if (!switchView.isEnabled()) return;
-
- if (isChecked) {
- startTether();
- } else {
- stopTether();
- }
- }
-
- void startTether() {
- if (isWifiApActivated()) return;
-
- mSwitchBar.setEnabled(false);
- mConnectivityManager.startTethering(TETHERING_WIFI, true /* showProvisioningUi */,
- mOnStartTetheringCallback, new Handler(Looper.getMainLooper()));
- }
-
- final ConnectivityManager.OnStartTetheringCallback mOnStartTetheringCallback =
- new ConnectivityManager.OnStartTetheringCallback() {
- @Override
- public void onTetheringFailed() {
- super.onTetheringFailed();
- Log.e(TAG, "Failed to start Wi-Fi Tethering.");
- handleWifiApStateChanged(mWifiManager.getWifiApState());
- }
- };

这个控制类为按钮设置的点击事件,点击事件里面就开始了开启wifi热点的流程 startTether()
startTether() 执行了 mConnectivityManager.startTethering() 然后就进入到了 ConnectivityManager 类里面。
- public void startTethering(int type, boolean showProvisioningUi,
- final OnStartTetheringCallback callback, Handler handler) {
- Objects.requireNonNull(callback, "OnStartTetheringCallback cannot be null.");
-
- final Executor executor = new Executor() {
- @Override
- public void execute(Runnable command) {
- if (handler == null) {
- command.run();
- } else {
- handler.post(command);
- }
- }
- };
-
- final StartTetheringCallback tetheringCallback = new StartTetheringCallback() {
- @Override
- public void onTetheringStarted() {
- callback.onTetheringStarted();
- }
-
- @Override
- public void onTetheringFailed(final int error) {
- callback.onTetheringFailed();
- }
- };
-
- final TetheringRequest request = new TetheringRequest.Builder(type)
- .setShouldShowEntitlementUi(showProvisioningUi).build();
-
- getTetheringManager().startTethering(request, executor, tetheringCallback);
- }

getTetheringManager().startTethering() 又进入到了packages/modules/Connectivity/Tethering/common/TetheringLib/src/android/net/TetheringManager.java中。
- public void startTethering(@NonNull final TetheringRequest request,
- @NonNull final Executor executor, @NonNull final StartTetheringCallback callback) {
- final String callerPkg = mContext.getOpPackageName();
- Log.i(TAG, "startTethering caller:" + callerPkg);
-
- final IIntResultListener listener = new IIntResultListener.Stub() {
- @Override
- public void onResult(final int resultCode) {
- executor.execute(() -> {
- if (resultCode == TETHER_ERROR_NO_ERROR) {
- callback.onTetheringStarted();
- } else {
- callback.onTetheringFailed(resultCode);
- }
- });
- }
- };
- getConnector(c -> c.startTethering(request.getParcel(), callerPkg,
- getAttributionTag(), listener));
- }
-
-
-
- private void getConnector(ConnectorConsumer consumer) {
- final ITetheringConnector connector;
- synchronized (mConnectorWaitQueue) {
- connector = mConnector;
- if (connector == null) {
- mConnectorWaitQueue.add(consumer);
- return;
- }
- }
-
- try {
- consumer.onConnectorAvailable(connector);
- } catch (RemoteException e) {
- throw new IllegalStateException(e);
- }
- }
-
- private interface ConnectorConsumer {
- void onConnectorAvailable(ITetheringConnector connector) throws RemoteException;
- }

由于ConnectorConsumer 是一个接口,所以consumer.onConnectorAvailable(connector)就相当于
调用了 connector.startTethering() 。ITetheringConnector connector 是一个aidl 接口,跨进程进去到了
packages/modules/Connectivity/Tethering/src/com/android/networkstack/tethering/TetheringService.java
- @Override
- public void startTethering(TetheringRequestParcel request, String callerPkg,
- String callingAttributionTag, IIntResultListener listener) {
- if (checkAndNotifyCommonError(callerPkg,
- callingAttributionTag,
- request.exemptFromEntitlementCheck /* onlyAllowPrivileged */,
- listener)) {
- return;
- }
-
- mTethering.startTethering(request, listener);
- }
这个里又调用到了mTethering.startTethering(request, listener);
frameworks/base/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
里面去了
- void startTethering(final TetheringRequestParcel request, final IIntResultListener listener) {
- mHandler.post(() -> {
- final TetheringRequestParcel unfinishedRequest = mActiveTetheringRequests.get(
- request.tetheringType);
- // If tethering is already enabled with a different request,
- // disable before re-enabling.
- if (unfinishedRequest != null
- && !TetheringUtils.isTetheringRequestEquals(unfinishedRequest, request)) {
- enableTetheringInternal(request.tetheringType, false /* disabled */, null);
- mEntitlementMgr.stopProvisioningIfNeeded(request.tetheringType);
- }
- mActiveTetheringRequests.put(request.tetheringType, request);
-
- if (request.exemptFromEntitlementCheck) {
- mEntitlementMgr.setExemptedDownstreamType(request.tetheringType);
- } else {
- mEntitlementMgr.startProvisioningIfNeeded(request.tetheringType,
- request.showProvisioningUi);
- }
- enableTetheringInternal(request.tetheringType, true /* enabled */, listener);
- });
- }

这里执行了enableTetheringInternal(request.tetheringType, true /* enabled */, listener);
- private void enableTetheringInternal(int type, boolean enable,
- final IIntResultListener listener) {
- int result = TETHER_ERROR_NO_ERROR;
- switch (type) {
- case TETHERING_WIFI:
- result = setWifiTethering(enable);
- break;
- case TETHERING_USB:
- result = setUsbTethering(enable);
- break;
- case TETHERING_BLUETOOTH:
- setBluetoothTethering(enable, listener);
- break;
- case TETHERING_NCM:
- result = setNcmTethering(enable);
- break;
- case TETHERING_ETHERNET:
- result = setEthernetTethering(enable);
- break;
- default:
- Log.w(TAG, "Invalid tether type.");
- result = TETHER_ERROR_UNKNOWN_TYPE;
- }
-
- // The result of Bluetooth tethering will be sent by #setBluetoothTethering.
- if (type != TETHERING_BLUETOOTH) {
- sendTetherResult(listener, result, type);
- }
- }
-
- private int setWifiTethering(final boolean enable) {
- final long ident = Binder.clearCallingIdentity();
- try {
- synchronized (mPublicSync) {
- final WifiManager mgr = getWifiManager();
- if (mgr == null) {
- mLog.e("setWifiTethering: failed to get WifiManager!");
- return TETHER_ERROR_SERVICE_UNAVAIL;
- }
- if ((enable && mgr.startTetheredHotspot(null /* use existing softap config */))
- || (!enable && mgr.stopSoftAp())) {
- mWifiTetherRequested = enable;
- return TETHER_ERROR_NO_ERROR;
- }
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
-
- return TETHER_ERROR_INTERNAL_ERROR;
- }

开启热点当然是执行 result = setWifiTethering(enable);
setWifiTethering()里面又执行了mgr.startTetheredHotspot(null /* use existing softap config */))
这个里面传了一个空的参数,这个参数是有意义的,代表在开启热点时,会根据配置文件的内容决定开启热点的参数。这个配置文件在手机的 data/misc/apexdata/com.android.wifi/ 下。里面有两个配置文件,一个是wifi的,一个是热点的。
WifiConfigStore.xml WifiConfigStoreSoftAp.xml
执行这个方法后又进入到了packages/modules/Wifi/framework/java/android/net/wifi/WifiManager.java类。
- public boolean startTetheredHotspot(@Nullable SoftApConfiguration softApConfig) {
- try {
- return mService.startTetheredHotspot(softApConfig, mContext.getOpPackageName());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
mService.startTetheredHotspot()又是一个aidl 接口。进入到了
packages/modules/Wifi/service/java/com/android/server/wifi/WifiServiceImpl.java 里面
- public boolean startTetheredHotspot(@Nullable SoftApConfiguration softApConfig,
- @NonNull String packageName) {
- // NETWORK_STACK is a signature only permission.
- enforceNetworkStackPermission();
- int callingUid = Binder.getCallingUid();
- mWifiPermissionsUtil.checkPackage(callingUid, packageName);
-
- // If user restriction is set, cannot start softap
- if (mWifiTetheringDisallowed) {
- mLog.err("startTetheredHotspot with user restriction: not permitted").flush();
- return false;
- }
-
- mLog.info("startTetheredHotspot uid=%").c(callingUid).flush();
-
- // TODO: b/233363886, handle timeout in general way.
- if (!checkSetEnablingIfAllowed()) {
- return false;
- }
-
- WorkSource requestorWs = new WorkSource(callingUid, packageName);
- if (!mWifiThreadRunner.call(
- () -> mActiveModeWarden.canRequestMoreSoftApManagers(requestorWs), false)) {
- // Take down LOHS if it is up.
- mLohsSoftApTracker.stopAll();
- }
-
- if (!startSoftApInternal(new SoftApModeConfiguration(
- WifiManager.IFACE_IP_MODE_TETHERED, softApConfig,
- mTetheredSoftApTracker.getSoftApCapability()), requestorWs)) {
- mTetheredSoftApTracker.setFailedWhileEnabling();
- return false;
- }
- mLastCallerInfoManager.put(WifiManager.API_TETHERED_HOTSPOT, Process.myTid(),
- callingUid, Binder.getCallingPid(), packageName, true);
- return true;
- }

执行了 startSoftApInternal()
- private boolean startSoftApInternal(SoftApModeConfiguration apConfig, WorkSource requestorWs) {
- int uid = Binder.getCallingUid();
- boolean privileged = isSettingsOrSuw(Binder.getCallingPid(), uid);
- mLog.trace("startSoftApInternal uid=% mode=%")
- .c(uid).c(apConfig.getTargetMode()).flush();
-
- // null wifiConfig is a meaningful input for CMD_SET_AP; it means to use the persistent
- // AP config.
- SoftApConfiguration softApConfig = apConfig.getSoftApConfiguration();
- if (softApConfig != null
- && (!WifiApConfigStore.validateApWifiConfiguration(
- softApConfig, privileged, mContext))) {
- Log.e(TAG, "Invalid SoftApConfiguration");
- return false;
- }
-
- mActiveModeWarden.startSoftAp(apConfig, requestorWs);
- return true;
- }

然后执行 mActiveModeWarden.startSoftAp(apConfig, requestorWs); 进入
packages/modules/Wifi/service/java/com/android/server/wifi/ActiveModeWarden.java
- public void startSoftAp(SoftApModeConfiguration softApConfig, WorkSource requestorWs) {
- stopStaIfRequired(softApConfig, requestorWs);
- mWifiController.sendMessage(WifiController.CMD_SET_AP, 1, 0,
- Pair.create(softApConfig, requestorWs));
- }
这里发送了一条消息进入到了ActiveModeWarden 的 内部类 EnabledState 里面。
- case CMD_SET_AP:
- // note: CMD_SET_AP is handled/dropped in ECM mode - will not start here
- if (msg.arg1 == 1) {
- Pair<SoftApModeConfiguration, WorkSource> softApConfigAndWs =
- (Pair) msg.obj;
- startSoftApModeManager(
- softApConfigAndWs.first, softApConfigAndWs.second);
- } else {
- stopSoftApModeManagers(msg.arg2);
- }
- break;
这里执行了
startSoftApModeManager( softApConfigAndWs.first, softApConfigAndWs.second);
- private void startSoftApModeManager(
- @NonNull SoftApModeConfiguration softApConfig, @NonNull WorkSource requestorWs) {
- Log.d(TAG, "Starting SoftApModeManager config = " + softApConfig.getSoftApConfiguration());
- Preconditions.checkState(softApConfig.getTargetMode() == IFACE_IP_MODE_LOCAL_ONLY
- || softApConfig.getTargetMode() == IFACE_IP_MODE_TETHERED);
-
- WifiServiceImpl.SoftApCallbackInternal callback =
- softApConfig.getTargetMode() == IFACE_IP_MODE_LOCAL_ONLY
- ? mLohsCallback : mSoftApCallback;
- SoftApManager manager = mWifiInjector.makeSoftApManager(
- new SoftApListener(), callback, softApConfig, requestorWs,
- getRoleForSoftApIpMode(softApConfig.getTargetMode()), mVerboseLoggingEnabled);
- mSoftApManagers.add(manager);
- }
这里的callback 传入的 mLohsCallback 。
后面又执行了mWifiInjector.makeSoftApManager()方法。进入到
packages/modules/Wifi/service/java/com/android/server/wifi/WifiInjector.java
- public SoftApManager makeSoftApManager(
- @NonNull ActiveModeManager.Listener<SoftApManager> listener,
- @NonNull WifiServiceImpl.SoftApCallbackInternal callback,
- @NonNull SoftApModeConfiguration config,
- @NonNull WorkSource requestorWs,
- @NonNull ActiveModeManager.SoftApRole role,
- boolean verboseLoggingEnabled) {
- return new SoftApManager(mContext, mWifiHandlerThread.getLooper(),
- mFrameworkFacade, mWifiNative, mCoexManager, makeBatteryManager(),
- mCountryCode.getCountryCode(), listener, callback, mWifiApConfigStore,
- config, mWifiMetrics, mSarManager, mWifiDiagnostics,
- new SoftApNotifier(mContext, mFrameworkFacade, mWifiNotificationManager),
- mCmiMonitor, mActiveModeWarden, mClock.getElapsedSinceBootMillis(),
- requestorWs, role, verboseLoggingEnabled);
- }
这里直接new了一个SoftApManger。进入到了构造方法里面。
- // null is a valid input and means we use the user-configured tethering settings.
- if (mCurrentSoftApConfiguration == null) {
- mCurrentSoftApConfiguration = mWifiApConfigStore.getApConfiguration();
- // may still be null if we fail to load the default config
- }
-
-
-
- mStateMachine = new SoftApStateMachine(looper); // 在这里真正的创建了热点的状态机
-
- mStateMachine.sendMessage(SoftApStateMachine.CMD_START, requestorWs);
由于之前的config 一直是空的,所以 mWifiApConfigStore.getApConfiguration() 这里面就从配置文件里,获取了热点的配置信息。
最后send一个message。由 SoftApManager 的内部类 IdleState processMessage() 捕获处理.
int result = startSoftAp();
里面有一段,调用了startSoftAp()方法。
- private int startSoftAp() {
- if (SdkLevel.isAtLeastS()) {
- Log.d(getTag(), "startSoftAp: channels " + mCurrentSoftApConfiguration.getChannels()
- + " iface " + mApInterfaceName + " country " + mCountryCode);
- } else {
- Log.d(getTag(), "startSoftAp: band " + mCurrentSoftApConfiguration.getBand());
- }
-
- int result = setMacAddress();
- if (result != SUCCESS) {
- return result;
- }
-
- result = setCountryCode();
- if (result != SUCCESS) {
- return result;
- }
-
- // Make a copy of configuration for updating AP band and channel.
- SoftApConfiguration.Builder localConfigBuilder =
- new SoftApConfiguration.Builder(mCurrentSoftApConfiguration);
-
- result = ApConfigUtil.updateApChannelConfig(
- mWifiNative, mCoexManager, mContext.getResources(), mCountryCode,
- localConfigBuilder, mCurrentSoftApConfiguration, mCurrentSoftApCapability);
- if (result != SUCCESS) {
- Log.e(getTag(), "Failed to update AP band and channel");
- return result;
- }
-
- if (mCurrentSoftApConfiguration.isHiddenSsid()) {
- Log.d(getTag(), "SoftAP is a hidden network");
- }
-
- if (!ApConfigUtil.checkSupportAllConfiguration(
- mCurrentSoftApConfiguration, mCurrentSoftApCapability)) {
- Log.d(getTag(), "Unsupported Configuration detect! config = "
- + mCurrentSoftApConfiguration);
- return ERROR_UNSUPPORTED_CONFIGURATION;
- }
-
- if (!mWifiNative.startSoftAp(mApInterfaceName,
- localConfigBuilder.build(),
- mOriginalModeConfiguration.getTargetMode() == WifiManager.IFACE_IP_MODE_TETHERED,
- mSoftApHalCallback)) {
- Log.e(getTag(), "Soft AP start failed");
- return ERROR_GENERIC;
- }
-
- mWifiDiagnostics.startLogging(mApInterfaceName);
- mStartTimestamp = FORMATTER.format(new Date(System.currentTimeMillis()));
- Log.d(getTag(), "Soft AP is started ");
-
- return SUCCESS;
- }

主要是调用mWifiNative.startSoftAp()方法
- public boolean startSoftAp(
- @NonNull String ifaceName, SoftApConfiguration config, boolean isMetered,
- SoftApHalCallback callback) {
- if (mHostapdHal.isApInfoCallbackSupported()) {
- if (!mHostapdHal.registerApCallback(ifaceName, callback)) {
- Log.e(TAG, "Failed to register ap hal event callback");
- return false;
- }
- } else {
- SoftApHalCallbackFromWificond softApHalCallbackFromWificond =
- new SoftApHalCallbackFromWificond(ifaceName, callback);
- if (!mWifiCondManager.registerApCallback(ifaceName,
- Runnable::run, softApHalCallbackFromWificond)) {
- Log.e(TAG, "Failed to register ap hal event callback from wificond");
- return false;
- }
- }
-
- if (!addAccessPoint(ifaceName, config, isMetered, callback)) {
- Log.e(TAG, "Failed to add acccess point");
- mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
- return false;
- }
-
- return true;
- }

后面会进入到
frameworks\opt\net\wifi\service\java\com\android\server\wifi\HostapdHal.java
- @Override
- public boolean addAccessPoint(@NonNull String ifaceName, @NonNull SoftApConfiguration config,
- boolean isMetered, Runnable onFailureListener) {
- synchronized (mLock) {
- final String methodStr = "addAccessPoint";
- Log.d(TAG, methodStr + ": " + ifaceName);
- if (!checkHostapdAndLogFailure(methodStr)) {
- return false;
- }
- try {
- IfaceParams ifaceParams = prepareIfaceParams(ifaceName, config);
- NetworkParams nwParams = prepareNetworkParams(isMetered, config);
- if (ifaceParams == null || nwParams == null) {
- Log.e(TAG, "addAccessPoint parameters could not be prepared.");
- return false;
- }
- mIHostapd.addAccessPoint(ifaceParams, nwParams);
- mSoftApFailureListeners.put(ifaceName, onFailureListener);
- return true;
- } catch (IllegalArgumentException e) {
- Log.e(TAG, "Unrecognized apBand: " + config.getBand());
- } catch (RemoteException e) {
- handleRemoteException(e, methodStr);
- } catch (ServiceSpecificException e) {
- handleServiceSpecificException(e, methodStr);
- }
- return false;
- }
- }

然后会调用到Hal层的方法。
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。