Android R WiFi热点流程浅析
Posted 第一序列丶
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android R WiFi热点流程浅析相关的知识,希望对你有一定的参考价值。
android R WiFi热点流程浅析
Android上的WiFi SoftAp功能是用户常用的功能之一,它能让我们分享手机的网络给其他设备使用。
那Android系统是如何实现SoftAp的呢,这里在FWK层面做一个简要的流程分析,供自己记录和大家参考。
以Android R版本为例,我们知道Android大部分的系统FWK服务都在SystemServer中启动,SoftAp的Service也不例外:
/**
* Use with @link #getSystemService(String) to retrieve a @link android.net.TetheringManager
* for managing tethering functions.
* @hide
* @see android.net.TetheringManager
*/
@SystemApi
public static final String TETHERING_SERVICE = "tethering";
private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector";
/**
* Starts a miscellaneous grab bag of stuff that has yet to be refactored and organized.
*/
private void startOtherServices(@NonNull TimingsTraceAndSlog t)
t.traceBegin("startOtherServices");
......
t.traceBegin("StartTethering");
try
// TODO: hide implementation details, b/146312721.
ConnectivityModuleConnector.getInstance().startModuleService(
TETHERING_CONNECTOR_CLASS,
PERMISSION_MAINLINE_NETWORK_STACK, service ->
ServiceManager.addService(Context.TETHERING_SERVICE, service,
false /* allowIsolated */,
DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL);
);
catch (Throwable e)
reportWtf("starting Tethering", e);
t.traceEnd();
......
这里借助了ConnectivityModuleConnector工具类的startModuleService()函数去启动、绑定服务:
/**
* Start a module running in the network stack or system_server process. Should be called only
* once for each module per device startup.
*
* <p>This method will start a networking module either in the network stack
* process, or inside the system server on devices that do not support the corresponding
* mainline network . The corresponding networking module service's binder
* object will then be delivered asynchronously via the provided @link ModuleServiceCallback.
*
* @param serviceIntentBaseAction Base action to use for constructing the intent needed to
* bind to the corresponding module.
* @param servicePermissionName Permission to be held by the corresponding module.
*/
public void startModuleService(
@NonNull String serviceIntentBaseAction,
@NonNull String servicePermissionName,
@NonNull ModuleServiceCallback callback)
log("Starting networking module " + serviceIntentBaseAction);
final PackageManager pm = mContext.getPackageManager();
// Try to bind in-process if the device was shipped with an in-process version
Intent intent = mDeps.getModuleServiceIntent(pm, serviceIntentBaseAction,
servicePermissionName, true /* inSystemProcess */);
// Otherwise use the updatable module version
if (intent == null)
intent = mDeps.getModuleServiceIntent(pm, serviceIntentBaseAction,
servicePermissionName, false /* inSystemProcess */);
log("Starting networking module in network_stack process");
else
log("Starting networking module in system_server process");
if (intent == null)
maybeCrashWithTerribleFailure("Could not resolve the networking module", null);
return;
final String packageName = intent.getComponent().getPackageName();
// Start the network stack. The service will be added to the service manager by the
// corresponding client in ModuleServiceCallback.onModuleServiceConnected().
if (!mContext.bindServiceAsUser(
intent, new ModuleServiceConnection(packageName, callback),
Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM))
maybeCrashWithTerribleFailure(
"Could not bind to networking module in-process, or in app with "
+ intent, packageName);
return;
log("Networking module service start requested");
private class ModuleServiceConnection implements ServiceConnection
@NonNull
private final String mPackageName;
@NonNull
private final ModuleServiceCallback mModuleServiceCallback;
private ModuleServiceConnection(
@NonNull String packageName,
@NonNull ModuleServiceCallback moduleCallback)
mPackageName = packageName;
mModuleServiceCallback = moduleCallback;
@Override
public void onServiceConnected(ComponentName name, IBinder service)
logi("Networking module service connected");
mModuleServiceCallback.onModuleServiceConnected(service);
@Override
public void onServiceDisconnected(ComponentName name)
// onServiceDisconnected is not being called on device shutdown, so this method being
// called always indicates a bad state for the system server.
// This code path is only run by the system server: only the system server binds
// to the NetworkStack as a service. Other processes get the NetworkStack from
// the ServiceManager.
maybeCrashWithTerribleFailure("Lost network stack", mPackageName);
结合代码可知,就是通过bindService()启动一个服务,并通过一个lambda表达式在服务connect成功之后进行服务注册的过程,它绑定的服务的filter是:android.net.ITetheringConnector。
在源码中,该服务定义在frameworks\\base\\packages\\Tethering\\AndroidManifest.xml中:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.networkstack.tethering"
android:sharedUserId="android.uid.networkstack">
<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" />
<!-- Permissions must be defined here, and not in the base manifest, as the tethering
running in the system server process does not need any permission, and having
privileged permissions added would cause crashes on startup unless they are also
added to the privileged permissions whitelist for that package. -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.MANAGE_USB" />
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
<uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.TETHER_PRIVILEGED" />
<uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
<uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<protected-broadcast android:name="com.android.server.connectivity.tethering.DISABLE_TETHERING" />
<application
android:process="com.android.networkstack.process"
android:extractNativeLibs="false"
android:persistent="true">
<service android:name="com.android.networkstack.tethering.TetheringService"
android:permission="android.permission.MAINLINE_NETWORK_STACK"
android:exported="true">
<intent-filter>
<action android:name="android.net.ITetheringConnector"/>
</intent-filter>
</service>
</application>
</manifest>
它对应的Service是TetheringService,Tethering.apk封装了网络共享相关的主要服务实现,它的使用类似于Bluetooth.apk,被bind service拉起随后运行;继续看TetheringService:
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.networkstack.tethering;
/**
* Android service used to manage tethering.
*
* <p>The service returns a binder for the system server to communicate with the tethering.
*/
public class TetheringService extends Service
private static final String TAG = TetheringService.class.getSimpleName();
private TetheringConnector mConnector;
@Override
public void onCreate()
final TetheringDependencies deps = makeTetheringDependencies();
// The Tethering object needs a fully functional context to start, so this can't be done
// in the constructor.
mConnector = new TetheringConnector(makeTethering(deps), TetheringService.this);
/**
* Make a reference to Tethering object.
*/
@VisibleForTesting
public Tethering makeTethering(TetheringDependencies deps)
System.loadLibrary("tetherutilsjni");
return new Tethering(deps);
@NonNull
@Override
public IBinder onBind(Intent intent)
return mConnector;
private static class TetheringConnector extends ITetheringConnector.Stub
private final TetheringService mService;
private final Tethering mTethering;
TetheringConnector(Tethering tether, TetheringService service)
mTethering = tether;
mService = service;
/** @hide */
oneway interface ITetheringConnector
void tether(String iface, String callerPkg, IIntResultListener receiver);
void untether(String iface, String callerPkg, IIntResultListener receiver);
void setUsbTethering(boolean enable, String callerPkg, IIntResultListener receiver);
void startTethering(in TetheringRequestParcel request, String callerPkg,
IIntResultListener receiver);
void stopTethering(int type, String callerPkg, IIntResultListener receiver);
void requestLatestTetheringEntitlementResult(int type, in ResultReceiver receiver,
boolean showEntitlementUi, String callerPkg);
void registerTetheringEventCallback(ITetheringEventCallback callback, String callerPkg);
void unregisterTetheringEventCallback(ITetheringEventCallback callback, String callerPkg);
void isTetheringSupported(String callerPkg, IIntResultListener receiver);
void stopAllTethering(String callerPkg, IIntResultListener receiver);
TetheringService主要实现了AIDL ITetheringConnector定义的业务接口,根据function名称可以很清晰的知道,它主要针对的是网络共享。服务启动成功,会以tethering的名字注册进系统中,其他需要使用的组件就可以很容易的向Android查询、获取它。
Tethering组件正常启动之后,就是APP使用它了;我们以CarSetting为例:
/**
* Fragment to host tethering-related preferences.
*/
@SearchIndexable
public class WifiTetherFragment extends SettingsFragment
private TetheringManager mTetheringManager;
private void startTethering()
mTetheringManager.startTethering(ConnectivityManager.TETHERING_WIFI,
ConcurrentUtils.DIRECT_EXECUTOR,
new TetheringManager.StartTetheringCallback()
@Override
public void onTetheringFailed(final int result)
mTetherSwitch.setChecked(false);
mTetherSwitch.setEnabled(true);
);
private void stopTethering()
mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
private void restartTethering()
stopTethering();
mRestartBooked = true;
WifiTetherFragment是实现开关热点的Fragment,可知它会调用TetherManager::startTethering()去开启WiFi共享,TetheringManager内部通过ITetheringConnector实现具体功能,类似于WifiManager:
/**
* Starts tethering and runs tether provisioning for the given type if needed. If provisioning
* fails, stopTethering will be called automatically.
*
* <p>Without @link android.Manifest.permission.TETHER_PRIVILEGED permission, the call will
* fail if a tethering entitlement check is required.
*
* @param request a @link TetheringRequest which can specify the preferred configuration.
* @param executor @link Executor to specify the thread upon which the callback of
* TetheringRequest will be invoked.
* @param callback A callback that will be called to indicate the success status of the
* tethering start request.
*/
@RequiresPermission(anyOf =
android.Manifest.permission.TETHER_PRIVILEGED,
android.Manifest.permission.WRITE_SETTINGS
)
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, listener));
/**
* Starts tethering and runs tether provisioning for the given type if needed. If provisioning
* fails, stopTethering will be called automatically.
*
* <p>Without @link android.Manifest.permission.TETHER_PRIVILEGED permission, the call will
* fail if a tethering entitlement check is required.
*
* @param type The tethering type, on of the @code TetheringManager#TETHERING_* constants.
* @param executor @link Executor to specify the thread upon which the callback of
* TetheringRequest will be invoked.
* @hide
*/
@RequiresPermission(anyOf =
android.Manifest.permission.TETHER_PRIVILEGED,
android.Manifest.permission.WRITE_SETTINGS
)
@SystemApi(client = MODULE_LIBRARIES)
public void startTethering(int type, @NonNull final Executor executor,
@NonNull final StartTetheringCallback callback)
startTethering(new TetheringRequest.Builder(type).build(), executor, callback);
从前述可知,传入的Tethering type是ConnectivityManager.TETHERING_WIFI,直接看TetheringService:
private final Tethering mTethering;
@Override
public void startTethering(TetheringRequestParcel request, String callerPkg,
IIntResultListener listener)
if (checkAndNotifyCommonError(callerPkg,
request.exemptFromEntitlementCheck /* onlyAllowPrivileged */,
listener))
return;
m
Tethering是一个包含各种网络共享业务逻辑的实现类,比如BT网络共享、USB网络共享,以及我们这里关注的WiFi网络共享:
/**
*
* This class holds much of the business logic to allow Android devices
* to act as IP gateways via USB, BT, and WiFi interfaces.
*/
public class Tethering
public Tethering(TetheringDependencies deps)
......
startStateMachineUpdaters();
/**
* Start to register callbacks.
* Call this function when tethering is ready to handle callback events.
*/
private void startStateMachineUpdaters()
try
mNetd.registerUnsolicitedEventListener(mNetdCallback);
catch (RemoteException e)
mLog.e("Unable to register netd UnsolicitedEventListener");
mCarrierConfigChange.startListening();
mContext.getSystemService(TelephonyManager.class).listen(mActiveDataSubIdListener,
PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
IntentFilter filter = new IntentFilter();
filter.addAction(UsbManager.ACTION_USB_STATE);
filter.addAction(CONNECTIVITY_ACTION);
filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
filter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
filter.addAction(UserManager.ACTION_USER_RESTRICTIONS_CHANGED);
filter.addAction(ACTION_RESTRICT_BACKGROUND_CHANGED);
mContext.registerReceiver(mStateReceiver, filter, null, mHandler);
final IntentFilter noUpstreamFilter = new IntentFilter();
noUpstreamFilter.addAction(TetheringNotificationUpdater.ACTION_DISABLE_TETHERING);
mContext.registerReceiver(
mStateReceiver, noUpstreamFilter, PERMISSION_MAINLINE_NETWORK_STACK, mHandler);
final WifiManager wifiManager = getWifiManager();
if (wifiManager != null)
wifiManager.registerSoftApCallback(mExecutor, new TetheringSoftApCallback());
startTrackDefaultNetwork();
private class StateReceiver extends BroadcastReceiver
@Override
public void onReceive(Context content, Intent intent)
final String action = intent.getAction();
if (action == null) return;
if (action.equals(UsbManager.ACTION_USB_STATE))
handleUsbAction(intent);
else if (action.equals(CONNECTIVITY_ACTION))
handleConnectivityAction(intent);
else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION))
handleWifiApAction(intent);
else if (action.equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION))
handleWifiP2pAction(intent);
else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED))
mLog.log("OBSERVED configuration changed");
updateConfiguration();
else if (action.equals(UserManager.ACTION_USER_RESTRICTIONS_CHANGED))
mLog.log("OBSERVED user restrictions changed");
handleUserRestrictionAction();
else if (action.equals(ACTION_RESTRICT_BACKGROUND_CHANGED))
mLog.log("OBSERVED data saver changed");
handleDataSaverChanged();
else if (action.equals(TetheringNotificationUpdater.ACTION_DISABLE_TETHERING))
untetherAll();
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);
);
/**
* Enables or disables tethering for the given type. If provisioning is required, it will
* schedule provisioning rechecks for the specified interface.
*/
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;
从构造函数可知,它监听了WifiManager.WIFI_AP_STATE_CHANGED_ACTION AP状态改变的广播,这让它有了在驱动创建成功SoftAp iface后,为它配置IP的能力,这个后面再介绍。根据startTethering()的调用逻辑,发现它调用了 WifiManager.startTetheredHotspot(),WifiManager我们应该很熟悉:
/**
* This class provides the primary API for managing all aspects of Wi-Fi
* connectivity.
* <p>
* On releases before @link android.os.Build.VERSION_CODES#N, this object
* should only be obtained from an @linkplain Context#getApplicationContext()
* application context, and not from any other derived context to avoid memory
* leaks within the calling process.
* <p>
* It deals with several categories of items:
* </p>
* <ul>
* <li>The list of configured networks. The list can be viewed and updated, and
* attributes of individual entries can be modified.</li>
* <li>The currently active Wi-Fi network, if any. Connectivity can be
* established or torn down, and dynamic information about the state of the
* network can be queried.</li>
* <li>Results of access point scans, containing enough information to make
* decisions about what access point to connect to.</li>
* <li>It defines the names of various Intent actions that are broadcast upon
* any sort of change in Wi-Fi state.
* </ul>
* <p>
* This is the API to use when performing Wi-Fi specific operations. To perform
* operations that pertain to network connectivity at an abstract level, use
* @link android.net.ConnectivityManager.
* </p>
*/
@SystemService(Context.WIFI_SERVICE)
public class WifiManager
/**
* Start Soft AP (hotspot) mode for tethering purposes with the specified configuration.
* Note that starting Soft AP mode may disable station mode operation if the device does not
* support concurrency.
* @param softApConfig A valid SoftApConfiguration specifying the configuration of the SAP,
* or null to use the persisted Soft AP configuration that was previously
* set using @link #setSoftApConfiguration(softApConfiguration).
* @return @code true if the operation succeeded, @code false otherwise
*
* @hide
*/
@SystemApi
@RequiresPermission(anyOf =
android.Manifest.permission.NETWORK_STACK,
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
)
public boolean startTetheredHotspot(@Nullable SoftApConfiguration softApConfig)
try
return mService.startTetheredHotspot(softApConfig);
catch (RemoteException e)
throw e.rethrowFromSystemServer();
/**
* WifiService handles remote WiFi operation requests by implementing
* the IWifiManager interface.
*/
public class WifiServiceImpl extends BaseWifiService
/**
* see @link android.net.wifi.WifiManager#startTetheredHotspot(SoftApConfiguration)
* @param softApConfig SSID, security and channel details as part of SoftApConfiguration
* @return @code true if softap start was triggered
* @throws SecurityException if the caller does not have permission to start softap
*/
@Override
public boolean startTetheredHotspot(@Nullable SoftApConfiguration softApConfig)
// NETWORK_STACK is a signature only permission.
enforceNetworkStackPermission();
mLog.info("startTetheredHotspot uid=%").c(Binder.getCallingUid()).flush();
if (!mTetheredSoftApTracker.setEnablingIfAllowed())
mLog.err("Tethering is already active.").flush();
return false;
if (!mWifiThreadRunner.call(
() -> mActiveModeWarden.canRequestMoreSoftApManagers(), false))
// Take down LOHS if it is up.
mLohsSoftApTracker.stopAll();
if (!startSoftApInternal(new SoftApModeConfiguration(
WifiManager.IFACE_IP_MODE_TETHERED, softApConfig,
mTetheredSoftApTracker.getSoftApCapability())))
mTetheredSoftApTracker.setFailedWhileEnabling();
return false;
return true;
/**
* Internal method to start softap mode. Callers of this method should have already checked
* proper permissions beyond the NetworkStack permission.
*/
private boolean startSoftApInternal(SoftApModeConfiguration apConfig)
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)
|| !validateSoftApBand(softApConfig.getBand())))
Log.e(TAG, "Invalid SoftApConfiguration");
return false;
mActiveModeWarden.startSoftAp(apConfig);
return true;
主要的,首先创建了一个目标共享MODE为WifiManager.IFACE_IP_MODE_TETHERED的SoftApModeConfiguration对象,它描述了我们对开启的热点的配置信息,随后调用ActiveModeWarden.startSoftAp():
/**
* This class provides the implementation for different WiFi operating modes.
*/
public class ActiveModeWarden
/**
* WifiController is the class used to manage wifi state for various operating
* modes (normal, airplane, wifi hotspot, etc.).
*/
private class WifiController extends StateMachine
WifiController()
super(TAG, mLooper);
DefaultState defaultState = new DefaultState();
addState(defaultState);
addState(mDisabledState, defaultState);
addState(mEnabledState, defaultState);
setLogRecSize(100);
setLogOnlyTransitions(false);
@Override
public void start()
if (shouldEnableSta())
startClientModeManager();
setInitialState(mEnabledState);
else
setInitialState(mDisabledState);
super.start();
class DefaultState extends State
class EnabledState extends BaseState
private boolean mIsDisablingDueToAirplaneMode;
@Override
public void enter()
log("EnabledState.enter()");
super.enter();
if (!hasAnyModeManager())
Log.e(TAG, "Entered EnabledState, but no active mode managers");
mIsDisablingDueToAirplaneMode = false;
@Override
public void exit()
log("EnabledState.exit()");
if (hasAnyModeManager())
Log.e(TAG, "Existing EnabledState, but has active mode managers");
super.exit();
@Override
public boolean processMessageFiltered(Message msg)
switch (msg.what)
case CMD_WIFI_TOGGLED:
case CMD_SCAN_ALWAYS_MODE_CHANGED:
if (shouldEnableSta())
if (hasAnyClientModeManager())
switchAllClientModeManagers();
else
startClientModeManager();
else
stopAllClientModeManagers();
break;
case CMD_SET_AP:
// note: CMD_SET_AP is handled/dropped in ECM mode - will not start here
if (msg.arg1 == 1)
startSoftApModeManager((SoftApModeConfiguration) msg.obj);
else
stopSoftApModeManagers(msg.arg2);
break;
case CMD_AIRPLANE_TOGGLED:
// airplane mode toggled on is handled in the default state
if (mSettingsStore.isAirplaneModeOn())
mIsDisablingDueToAirplaneMode = true;
return NOT_HANDLED;
else
if (mIsDisablingDueToAirplaneMode)
// Previous airplane mode toggle on is being processed, defer the
// message toggle off until previous processing is completed.
// Once previous airplane mode toggle is complete, we should
// transition to DisabledState. There, we will process the deferred
// airplane mode toggle message to disable airplane mode.
deferMessage(msg);
else
// when airplane mode is toggled off, but wifi is on, we can keep it
// on
log("airplane mode toggled - and airplane mode is off. return "
+ "handled");
return HANDLED;
case CMD_AP_STOPPED:
case CMD_AP_START_FAILURE:
if (!hasAnyModeManager())
if (shouldEnableSta())
log("SoftAp disabled, start client mode");
startClientModeManager();
else
log("SoftAp mode disabled, return to DisabledState");
transitionTo(mDisabledState);
else
log("AP disabled, remain in EnabledState.");
break;
case CMD_STA_START_FAILURE:
case CMD_STA_STOPPED:
// Client mode stopped. Head to Disabled to wait for next command if there
// no active mode managers.
if (!hasAnyModeManager())
log("STA disabled, return to DisabledState.");
transitionTo(mDisabledState);
else
log("STA disabled, remain in EnabledState.");
break;
case CMD_RECOVERY_RESTART_WIFI:
final String bugTitle;
final String bugDetail;
if (msg.arg1 < SelfRecovery.REASON_STRINGS.length && msg.arg1 >= 0)
bugDetail = SelfRecovery.REASON_STRINGS[msg.arg1];
bugTitle = "Wi-Fi BugReport: " + bugDetail;
else
bugDetail = "";
bugTitle = "Wi-Fi BugReport";
if (msg.arg1 != SelfRecovery.REASON_LAST_RESORT_WATCHDOG)
mHandler.post(() -> mClientModeImpl.takeBugReport(bugTitle, bugDetail));
log("Recovery triggered, disable wifi");
deferMessage(obtainMessage(CMD_DEFERRED_RECOVERY_RESTART_WIFI));
shutdownWifi();
// onStopped will move the state machine to "DisabledState".
break;
default:
return NOT_HANDLED;
return HANDLED;
class DisabledState extends BaseState
@Override
public void enter()
log("DisabledState.enter()");
super.enter();
if (hasAnyModeManager())
Log.e(TAG, "Entered DisabledState, but has active mode managers");
@Override
public void exit()
log("DisabledState.exit()");
super.exit();
@Override
public boolean processMessageFiltered(Message msg)
switch (msg.what)
case CMD_WIFI_TOGGLED:
case CMD_SCAN_ALWAYS_MODE_CHANGED:
if (shouldEnableSta())
startClientModeManager();
transitionTo(mEnabledState);
break;
case CMD_SET_AP:
// note: CMD_SET_AP is handled/dropped in ECM mode - will not start here
if (msg.arg1 == 1)
startSoftApModeManager((SoftApModeConfiguration) msg.obj);
transitionTo(mEnabledState);
break;
case CMD_RECOVERY_RESTART_WIFI:
log("Recovery triggered, already in disabled state");
// intentional fallthrough
case CMD_DEFERRED_RECOVERY_RESTART_WIFI:
// wait mRecoveryDelayMillis for letting driver clean reset.
sendMessageDelayed(CMD_RECOVERY_RESTART_WIFI_CONTINUE,
readWifiRecoveryDelay());
break;
case CMD_RECOVERY_RESTART_WIFI_CONTINUE:
if (shouldEnableSta())
startClientModeManager();
transitionTo(mEnabledState);
break;
default:
return NOT_HANDLED;
return HANDLED;
/** Starts SoftAp. */
public void startSoftAp(SoftApModeConfiguration softApConfig)
mWifiController.sendMessage(WifiController.CMD_SET_AP, 1, 0, softApConfig);
经常接触Wifi或者BT Framework框架的打工人应该很熟悉StateMachine的流程了,这里不再介绍相关的流程,只关注开启热点的处理流程,startSoftAp()的操作只是发送了WifiController.CMD_SET_AP命令,让状态机处理开启的流程,假设这是我们第一次开热点,也是只开热点,DisabledState状态处理该cmd:
case CMD_SET_AP:
// note: CMD_SET_AP is handled/dropped in ECM mode - will not start here
if (msg.arg1 == 1)
startSoftApModeManager((SoftApModeConfiguration) msg.obj);
transitionTo(mEnabledState);
/**
* 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 softApConfig SoftApModeConfiguration for the hostapd softap
*/
private void startSoftApModeManager(@NonNull SoftApModeConfiguration softApConfig)
Log.d(TAG, "Starting SoftApModeManager config = "
+ softApConfig.getSoftApConfiguration());
Preconditions.checkState(softApConfig.getTargetMode() == IFACE_IP_MODE_LOCAL_ONLY
|| softApConfig.getTargetMode() == IFACE_IP_MODE_TETHERED);
WifiManager.SoftApCallback callback =
softApConfig.getTargetMode() == IFACE_IP_MODE_LOCAL_ONLY
? mLohsCallback : mSoftApCallback;
SoftApListener listener = new SoftApListener();
ActiveModeManager manager =
mWifiInjector.makeSoftApManager(listener, callback, softApConfig);
listener.setActiveModeManager(manager);
manager.start();
manager.setRole(getRoleForSoftApIpMode(softApConfig.getTargetMode()));
mActiveModeManagers.add(manager);
private @ActiveModeManager.Role int getRoleForSoftApIpMode(int ipMode)
return ipMode == IFACE_IP_MODE_TETHERED
? ActiveModeManager.ROLE_SOFTAP_TETHERED : ActiveModeManager.ROLE_SOFTAP_LOCAL_ONLY;
创建SoftApManager并调用其start(),因为之前我们创建的MODE是IFACE_IP_MODE_TETHERED所以给SoftApManager set的role这里是ROLE_SOFTAP_TETHERED;随后进入EnabledState。我们看SoftApManager,它是一个管理WiFi AP mode管理类:
/**
* Manage WiFi in AP mode.
* The internal state machine runs under the ClientModeImpl handler thread context.
*/
public class SoftApManager implements ActiveModeManager
/**
* Listener for soft AP events.
*/
private final SoftApListener mSoftApListener = new SoftApListener()
@Override
public void onFailure()
mStateMachine.sendMessage(SoftApStateMachine.CMD_FAILURE);
@Override
public void onConnectedClientsChanged(NativeWifiClient client, boolean isConnected)
if (client != null)
mStateMachine.sendMessage(SoftApStateMachine.CMD_ASSOCIATED_STATIONS_CHANGED,
isConnected ? 1 : 0, 0, client);
else
Log.e(TAG, "onConnectedClientsChanged: Invalid type returned");
@Override
public void onSoftApChannelSwitched(int frequency,
@WifiAnnotations.Bandwidth int bandwidth)
mStateMachine.sendMessage(
SoftApStateMachine.CMD_SOFT_AP_CHANNEL_SWITCHED, frequency, bandwidth);
;
public SoftApManager(@NonNull WifiContext context,
@NonNull Looper looper,
@NonNull FrameworkFacade framework,
@NonNull WifiNative wifiNative,
String countryCode,
@NonNull Listener listener,
@NonNull WifiManager.SoftApCallback callback,
@NonNull WifiApConfigStore wifiApConfigStore,
@NonNull SoftApModeConfiguration apConfig,
@NonNull WifiMetrics wifiMetrics,
@NonNull SarManager sarManager,
@NonNull BaseWifiDiagnostics wifiDiagnostics)
mStateMachine = new SoftApStateMachine(looper);
/**
* Start soft AP, as configured in the constructor.
*/
@Override
public void start()
mStateMachine.sendMessage(SoftApStateMachine.CMD_START);
private class SoftApStateMachine extends StateMachine
private final State mIdleState = new IdleState();
private final State mStartedState = new StartedState();
private final InterfaceCallback mWifiNativeInterfaceCallback = new InterfaceCallback()
@Override
public void onDestroyed(String ifaceName)
if (mApInterfaceName != null && mApInterfaceName.equals(ifaceName))
sendMessage(CMD_INTERFACE_DESTROYED);
@Override
public void onUp(String ifaceName)
if (mApInterfaceName != null && mApInterfaceName.equals(ifaceName))
sendMessage(CMD_INTERFACE_STATUS_CHANGED, 1);
@Override
public void onDown(String ifaceName)
if (mApInterfaceName != null && mApInterfaceName.equals(ifaceName))
sendMessage(CMD_INTERFACE_STATUS_CHANGED, 0);
;
SoftApStateMachine(Looper looper)
super(TAG, looper);
addState(mIdleState);
addState(mStartedState);
setInitialState(mIdleState);
start();
private class IdleState extends State
private class StartedState extends State
SoftApManager内部包含一个小的状态机SoftApStateMachine,它只有两个状态,Idle状态是初始状态,它处理发来的SoftApStateMachine.CMD_START:
private class IdleState extends State
@Override
public void enter()
@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);
mModeListener.onStartFailure();
break;
mSoftApNotifier.dismissSoftApShutDownTimeoutExpiredNotification();
updateApState(WifiManager.WIFI_AP_STATE_ENABLING,
WifiManager.WIFI_AP_STATE_DISABLED, 0);
int result = startSoftAp();
if (result != SUCCESS)
int failureReason = WifiManager.SAP_START_FAILURE_GENERAL;
if (result == ERROR_NO_CHANNEL)
failureReason = WifiManager.SAP_START_FAILURE_NO_CHANNEL;
else if (result == ERROR_UNSUPPORTED_CONFIGURATION)
failureReason = WifiManager
.SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION;
updateApState(WifiManager.WIFI_AP_STATE_FAILED,
WifiManager.WIFI_AP_STATE_ENABLING,
failureReason);
stopSoftAp();
mWifiMetrics.incrementSoftApStartResult(false, failureReason);
mModeListener.onStartFailure();
break;
transitionTo(mStartedState);
break;
/**
* Start a soft AP instance as configured.
*
* @return integer result code
*/
private int startSoftAp()
SoftApConfiguration config = mApConfig.getSoftApConfiguration();
if (config == null || config.getSsid() == null)
Log.e(TAG, "Unable to start soft AP without valid configuration");
return ERROR_GENERIC;
Log.d(TAG, "band " + config.getBand() + " iface "
+ mApInterfaceName + " country " + mCountryCode);
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(config);
boolean acsEnabled = mCurrentSoftApCapability.areFeaturesSupported(
SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD);
result = ApConfigUtil.updateApChannelConfig(
mWifiNative, mContext.getResources(), mCountryCode, localConfigBuilder, config,
acsEnabled);
if (result != SUCCESS)
Log.e(TAG, "Failed to update AP band and channel");
return result;
if (config.isHiddenSsid())
Log.d(TAG, "SoftAP is a hidden network");
if (!ApConfigUtil.checkSupportAllConfiguration(config, mCurrentSoftApCapability))
Log.d(TAG, "Unsupported Configuration detect! config = " + config);
return ERROR_UNSUPPORTED_CONFIGURATION;
if (!mWifiNative.startSoftAp(mApInterfaceName,
localConfigBuilder.build(), mSoftApListener))
Log.e(TAG, "Soft AP start failed");
return ERROR_GENERIC;
mWifiDiagnostics.startLogging(mApInterfaceName);
mStartTimestamp = FORMATTER.format(new Date(System.currentTimeMillis()));
Log.d(TAG, "Soft AP is started ");
return SUCCESS;
主要的:
1、WifiNative.setupInterfaceForSoftApMode():创建一个供AP MODE使用的interface,它的状态由mWifiNativeInterfaceCallback回调管理.
2、SoftApManager.startSoftAp():按配置信息,在HAL/Driver层创建一个管理Soft ap的instance,它的状态由SoftApListener回调管理
如果都调用成功,进入StartedState:
private class StartedState extends State
private WakeupMessage mSoftApTimeoutMessage;
private void scheduleTimeoutMessage()
if (!mTimeoutEnabled || mConnectedClients.size() != 0)
cancelTimeoutMessage();
return;
long timeout = mApConfig.getSoftApConfiguration().getShutdownTimeoutMillis();
if (timeout == 0)
timeout = mDefaultShutDownTimeoutMills;
mSoftApTimeoutMessage.schedule(SystemClock.elapsedRealtime()
+ timeout);
Log.d(TAG, "Timeout message scheduled, delay = "
+ timeout);
@Override
public void enter()
mIfaceIsUp = false;
mIfaceIsDestroyed = false;
onUpChanged(mWifiNative.isInterfaceUp(mApInterfaceName));
Handler handler = mStateMachine.getHandler();
mSoftApTimeoutMessage = new WakeupMessage(mContext, handler,
SOFT_AP_SEND_MESSAGE_TIMEOUT_TAG,
SoftApStateMachine.CMD_NO_ASSOCIATED_STATIONS_TIMEOUT);
mSarManager.setSapWifiState(WifiManager.WIFI_AP_STATE_ENABLED);
Log.d(TAG, "Resetting connected clients on start");
mConnectedClients.clear();
mEverReportMetricsForMaxClient = false;
scheduleTimeoutMessage();
进入StartedState::enter()时,比较重要的是此时会设置一个默认600000ms(10min)的timeout超时机制,如果此时间段一直没有设备连接该AP,就会自动关闭AP。
整个开启AP的过程都会有对外通知当前AP状态改变的广播发送:
/**
* Update AP state.
*
* @param newState new AP state
* @param currentState current AP state
* @param reason Failure reason if the new AP state is in failure state
*/
private void updateApState(int newState, int currentState, int reason)
mSoftApCallback.onStateChanged(newState, reason);
//send the AP state change broadcast
final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, newState);
intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, currentState);
if (newState == WifiManager.WIFI_AP_STATE_FAILED)
//only set reason number when softAP start failed
intent.putExtra(WifiManager.EXTRA_WIFI_AP_FAILURE_REASON, reason);
intent.putExtra(WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME, mApInterfaceName);
intent.putExtra(WifiManager.EXTRA_WIFI_AP_MODE, mApConfig.getTargetMode());
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
假设我们正常开启了热点,此时也会发送AP开启成功的广播。回到前面介绍Tethering的内容,它内部监听了该广播:
private class StateReceiver extends BroadcastReceiver
@Override
public void onReceive(Context content, Intent intent)
final String action = intent.getAction();
if (action == null) return;
if (action.equals(UsbManager.ACTION_USB_STATE))
handleUsbAction(intent);
else if (action.equals(CONNECTIVITY_ACTION))
handleConnectivityAction(intent);
else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION))
handleWifiApAction(intent);
else if (action.equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION))
handleWifiP2pAction(intent);
else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED))
mLog.log("OBSERVED configuration changed");
updateConfiguration();
else if (action.equals(UserManager.ACTION_USER_RESTRICTIONS_CHANGED))
mLog.log("OBSERVED user restrictions changed");
handleUserRestrictionAction();
else if (action.equals(ACTION_RESTRICT_BACKGROUND_CHANGED))
mLog.log("OBSERVED data saver changed");
handleDataSaverChanged();
else if (action.equals(TetheringNotificationUpdater.ACTION_DISABLE_TETHERING))
untetherAll();
private void handleWifiApAction(Intent intent)
final int curState = intent.getIntExtra(EXTRA_WIFI_AP_STATE, WIFI_AP_STATE_DISABLED);
final String ifname = intent.getStringExtra(EXTRA_WIFI_AP_INTERFACE_NAME);
final int ipmode = intent.getIntExtra(EXTRA_WIFI_AP_MODE, IFACE_IP_MODE_UNSPECIFIED);
synchronized (Tethering.this.mPublicSync)
switch (curState)
case WifiManager.WIFI_AP_STATE_ENABLING:
// We can see this state on the way to both enabled and failure states.
break;
case WifiManager.WIFI_AP_STATE_ENABLED:
enableWifiIpServingLocked(ifname, ipmode);
break;
case WifiManager.WIFI_AP_STATE_DISABLING:
// We can see this state on the way to disabled.
break;
case WifiManager.WIFI_AP_STATE_DISABLED:
case WifiManager.WIFI_AP_STATE_FAILED:
default:
disableWifiIpServingLocked(ifname, curState);
break;
private void enableWifiIpServingLocked(String ifname, int wifiIpMode)
// Map wifiIpMode values to IpServer.Callback serving states, inferring
// from mWifiTetherRequested as a final "best guess".
final int ipServingMode;
switch (wifiIpMode)
case IFACE_IP_MODE_TETHERED:
ipServingMode = IpServer.STATE_TETHERED;
break;
case IFACE_IP_MODE_LOCAL_ONLY:
ipServingMode = IpServer.STATE_LOCAL_ONLY;
break;
default:
mLog.e("Cannot enable IP serving in unknown WiFi mode: " + wifiIpMode);
return;
if (!TextUtils.isEmpty(ifname))
maybeTrackNewInterfaceLocked(ifname);
changeInterfaceState(ifname, ipServingMode);
else
mLog.e(String.format(
"Cannot enable IP serving in mode %s on missing interface name",
ipServingMode));
根据前面的说明,此处会调用Tethering.enableWifiIpServingLocked(),主要的处理有改变ipServerMode的值为IpServer.STATE_TETHERED,以及如下两个函数:
private void maybeTrackNewInterfaceLocked(final String iface)
// If we don't care about this type of interface, ignore.
final int interfaceType = ifaceNameToType(iface);
if (interfaceType == TETHERING_INVALID)
mLog.log(iface + " is not a tetherable iface, ignoring");
return;
maybeTrackNewInterfaceLocked(iface, interfaceType);
private void maybeTrackNewInterfaceLocked(final String iface, int interfaceType)
// If we have already started a TISM for this interface, skip.
if (mTetherStates.containsKey(iface))
mLog.log("active iface (" + iface + ") reported as added, ignoring");
return;
mLog.log("adding TetheringInterfaceStateMachine for: " + iface);
final TetherState tetherState = new TetherState(
new IpServer(iface, mLooper, interfaceType, mLog, mNetd, mBpfCoordinator,
makeControlCallback(), mConfig.enableLegacyDhcpServer,
mConfig.isBpfOffloadEnabled(), mPrivateAddressCoordinator,
mDeps.getIpServerDependencies()));
mTetherStates.put(iface, tetherState);
tetherState.ipServer.start();
private void changeInterfaceState(String ifname, int requestedState)
final int result;
switch (requestedState)
case IpServer.STATE_UNAVAILABLE:
case IpServer.STATE_AVAILABLE:
result = untether(ifname);
break;
case IpServer.STATE_TETHERED:
case IpServer.STATE_LOCAL_ONLY:
result = tether(ifname, requestedState);
break;
default:
Log.wtf(TAG, "Unknown interface state: " + requestedState);
return;
if (result != TETHER_ERROR_NO_ERROR)
Log.e(TAG, "unable start or stop tethering on iface " + ifname);
return;
这里两个个函数的内容分别介绍,首先maybeTrackNewInterfaceLocked():
private void maybeTrackNewInterfaceLocked(final String iface, int interfaceType)
// If we have already started a TISM for this interface, skip.
if (mTetherStates.containsKey(iface))
mLog.log("active iface (" + iface + ") reported as added, ignoring");
return;
mLog.log("adding TetheringInterfaceStateMachine for: " + iface);
final TetherState tetherState = new TetherState(
new IpServer(iface, mLooper, interfaceType, mLog, mNetd, mBpfCoordinator,
makeControlCallback(), mConfig.enableLegacyDhcpServer,
mConfig.isBpfOffloadEnabled(), mPrivateAddressCoordinator,
mDeps.getIpServerDependencies()));
mTetherStates.put(iface, tetherState);
tetherState.ipServer.start();
1、它为每个iface创建了TetherState对象,并保存一个Map里
2、同时创建了IpServer类型实例,并调用了IpServer.start(),它是给AP配置的IP地址的来源
/**
* Provides the interface to IP-layer serving functionality for a given network
* interface, e.g. for tethering or "local-only hotspot" mode.
*
* @hide
*/
public class IpServer extends StateMachine
/** IpServer callback. */
public static class Callback
/**
* Notify that |who| has changed its tethering state.
*
* @param who the calling instance of IpServer
* @param state one of STATE_*
* @param lastError one of TetheringManager.TETHER_ERROR_*
*/
public void updateInterfaceState(IpServer who, int state, int lastError)
/**
* Notify that |who| has new LinkProperties.
*
* @param who the calling instance of IpServer
* @param newLp the new LinkProperties to report
*/
public void updateLinkProperties(IpServer who, LinkProperties newLp)
/**
* Notify that the DHCP leases changed in one of the IpServers.
*/
public void dhcpLeasesChanged()
/**
* Request Tethering change.
*
* @param tetheringType the downstream type of this IpServer.
* @param enabled enable or disable tethering.
*/
public void requestEnableTethering(int tetheringType, boolean enabled)
private final State mInitialState;
private final State mLocalHotspotState;
private final State mTetheredState;
private final State mUnavailableState;
private final State mWaitingForRestartState;
private LinkAddress mIpv4Address;
// TODO: Add a dependency object to pass the data members or variables from the tethering
// object. It helps to reduce the arguments of the constructor.
public IpServer(
String ifaceName, Looper looper, int interfaceType, SharedLog log,
INetd netd, @NonNull BpfCoordinator coordinator, Callback callback,
boolean usingLegacyDhcp, boolean usingBpfOffload,
PrivateAddressCoordinator addressCoordinator, Dependencies deps)
mInitialState = new InitialState();
mLocalHotspotState = new LocalHotspotState();
mTetheredState = new TetheredState();
mUnavailableState = new UnavailableState();
mWaitingForRestartState = new WaitingForRestartState();
addState(mInitialState);
addState(mLocalHotspotState);
addState(mTetheredState);
addState(mWaitingForRestartState, mTet以上是关于Android R WiFi热点流程浅析的主要内容,如果未能解决你的问题,请参考以下文章