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.
*
* 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中:
它对应的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.
*
* 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.
*
* 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.
*
*
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.
*
* 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.
*
* It deals with several categories of items:
*
*
* - The list of configured networks. The list can be viewed and updated, and
* attributes of individual entries can be modified.
* - 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.
* - Results of access point scans, containing enough information to make
* decisions about what access point to connect to.
* - It defines the names of various Intent actions that are broadcast upon
* any sort of change in Wi-Fi state.
*
*
* 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}.
*
*/
@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, mTetheredState);
addState(mUnavailableState);
setInitialState(mInitialState);
}
class InitialState extends State {
}
class BaseServingState extends State {
}
class LocalHotspotState extends BaseServingState{
}
class TetheredState extends BaseServingState {
}
/**
* This state is terminal for the per interface state machine. At this
* point, the master state machine should have removed this interface
* specific state machine from its list of possible recipients of
* tethering requests. The state machine itself will hang around until
* the garbage collector finds it.
*/
class UnavailableState extends State {
@Override
public void enter() {
mIpNeighborMonitor.stop();
mLastError = TetheringManager.TETHER_ERROR_NO_ERROR;
sendInterfaceState(STATE_UNAVAILABLE);
}
}
class WaitingForRestartState extends State {
@Override
public boolean processMessage(Message message) {
logMessage(this, message.what);
switch (message.what) {
case CMD_TETHER_UNREQUESTED:
transitionTo(mInitialState);
mLog.i("Untethered (unrequested) and restarting " + mIfaceName);
mCallback.requestEnableTethering(mInterfaceType, true /* enabled */);
break;
case CMD_INTERFACE_DOWN:
transitionTo(mUnavailableState);
mLog.i("Untethered (interface down) and restarting" + mIfaceName);
mCallback.requestEnableTethering(mInterfaceType, true /* enabled */);
break;
default:
return false;
}
return true;
}
}
}
IpServer也是一个小状态机,它主要是计算IP地址并在对应的iface进行地址配置,这样我们ifconfig查看网卡信息时,才能看到配置的信息。IpServer.start()启动之后,处理暂时告一段落.
接着看Tethering.changeInterfaceState():
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;
}
}
根据前面的Mode,我们进入Tethering.tether():
private int tether(String iface, int requestedState) {
if (DBG) Log.d(TAG, "Tethering " + iface);
synchronized (mPublicSync) {
TetherState tetherState = mTetherStates.get(iface);
if (tetherState == null) {
Log.e(TAG, "Tried to Tether an unknown iface: " + iface + ", ignoring");
return TETHER_ERROR_UNKNOWN_IFACE;
}
// Ignore the error status of the interface. If the interface is available,
// the errors are referring to past tethering attempts anyway.
if (tetherState.lastState != IpServer.STATE_AVAILABLE) {
Log.e(TAG, "Tried to Tether an unavailable iface: " + iface + ", ignoring");
return TETHER_ERROR_UNAVAIL_IFACE;
}
// NOTE: If a CMD_TETHER_REQUESTED message is already in the TISM's queue but not yet
// processed, this will be a no-op and it will not return an error.
//
// This code cannot race with untether() because they both synchronize on mPublicSync.
// TODO: reexamine the threading and messaging model to totally remove mPublicSync.
final int type = tetherState.ipServer.interfaceType();
final TetheringRequestParcel request = mActiveTetheringRequests.get(type, null);
if (request != null) {
mActiveTetheringRequests.delete(type);
}
tetherState.ipServer.sendMessage(IpServer.CMD_TETHER_REQUESTED, requestedState, 0,
request);
return TETHER_ERROR_NO_ERROR;
}
}
主要向IpServer这个StateMachine发送CMD_TETHER_REQUESTED cmd,它的初始状态是InitialState,它处理此消息:
class InitialState extends State {
@Override
public void enter() {
sendInterfaceState(STATE_AVAILABLE);
}
@Override
public boolean processMessage(Message message) {
logMessage(this, message.what);
switch (message.what) {
case CMD_TETHER_REQUESTED:
mLastError = TetheringManager.TETHER_ERROR_NO_ERROR;
switch (message.arg1) {
case STATE_LOCAL_ONLY:
maybeConfigureStaticIp((TetheringRequestParcel) message.obj);
transitionTo(mLocalHotspotState);
break;
case STATE_TETHERED:
maybeConfigureStaticIp((TetheringRequestParcel) message.obj);
transitionTo(mTetheredState);
break;
default:
mLog.e("Invalid tethering interface serving state specified.");
}
break;
case CMD_INTERFACE_DOWN:
transitionTo(mUnavailableState);
break;
case CMD_IPV6_TETHER_UPDATE:
updateUpstreamIPv6LinkProperties((LinkProperties) message.obj, message.arg1);
break;
default:
return NOT_HANDLED;
}
return HANDLED;
}
}
private void maybeConfigureStaticIp(final TetheringRequestParcel request) {
// Ignore static address configuration if they are invalid or null. In theory, static
// addresses should not be invalid here because TetheringManager do not allow caller to
// specify invalid static address configuration.
if (request == null || request.localIPv4Address == null
|| request.staticClientAddress == null || !checkStaticAddressConfiguration(
request.localIPv4Address, request.staticClientAddress)) {
return;
}
mStaticIpv4ServerAddr = request.localIPv4Address;
mStaticIpv4ClientAddr = request.staticClientAddress;
}
// Handling errors in BaseServingState.enter() by transitioning is
// problematic because transitioning during a multi-state jump yields
// a Log.wtf(). Ultimately, there should be only one ServingState,
// and forwarding and NAT rules should be handled by a coordinating
// functional element outside of IpServer.
class TetheredState extends BaseServingState {
@Override
public void enter() {
super.enter();
if (mLastError != TetheringManager.TETHER_ERROR_NO_ERROR) {
transitionTo(mInitialState);
}
if (DBG) Log.d(TAG, "Tethered " + mIfaceName);
sendInterfaceState(STATE_TETHERED);
}
@Override
public void exit() {
cleanupUpstream();
super.exit();
}
private void cleanupUpstream() {
if (mUpstreamIfaceSet == null) return;
for (String ifname : mUpstreamIfaceSet.ifnames) cleanupUpstreamInterface(ifname);
mUpstreamIfaceSet = null;
clearIpv6ForwardingRules();
}
private void cleanupUpstreamInterface(String upstreamIface) {
// Note that we don't care about errors here.
// Sometimes interfaces are gone before we get
// to remove their rules, which generates errors.
// Just do the best we can.
try {
mNetd.ipfwdRemoveInterfaceForward(mIfaceName, upstreamIface);
} catch (RemoteException | ServiceSpecificException e) {
mLog.e("Exception in ipfwdRemoveInterfaceForward: " + e.toString());
}
try {
mNetd.tetherRemoveForward(mIfaceName, upstreamIface);
} catch (RemoteException | ServiceSpecificException e) {
mLog.e("Exception in disableNat: " + e.toString());
}
}
@Override
public boolean processMessage(Message message) {
if (super.processMessage(message)) return true;
logMessage(this, message.what);
switch (message.what) {
case CMD_TETHER_REQUESTED:
mLog.e("CMD_TETHER_REQUESTED while already tethering.");
break;
case CMD_TETHER_CONNECTION_CHANGED:
final InterfaceSet newUpstreamIfaceSet = (InterfaceSet) message.obj;
if (noChangeInUpstreamIfaceSet(newUpstreamIfaceSet)) {
if (VDBG) Log.d(TAG, "Connection changed noop - dropping");
break;
}
if (newUpstreamIfaceSet == null) {
cleanupUpstream();
break;
}
for (String removed : upstreamInterfacesRemoved(newUpstreamIfaceSet)) {
cleanupUpstreamInterface(removed);
}
final Set added = upstreamInterfacesAdd(newUpstreamIfaceSet);
// This makes the call to cleanupUpstream() in the error
// path for any interface neatly cleanup all the interfaces.
mUpstreamIfaceSet = newUpstreamIfaceSet;
for (String ifname : added) {
try {
mNetd.tetherAddForward(mIfaceName, ifname);
mNetd.ipfwdAddInterfaceForward(mIfaceName, ifname);
} catch (RemoteException | ServiceSpecificException e) {
mLog.e("Exception enabling NAT: " + e.toString());
cleanupUpstream();
mLastError = TetheringManager.TETHER_ERROR_ENABLE_FORWARDING_ERROR;
transitionTo(mInitialState);
return true;
}
}
break;
case CMD_NEIGHBOR_EVENT:
handleNeighborEvent((NeighborEvent) message.obj);
break;
default:
return false;
}
return true;
}
private boolean noChangeInUpstreamIfaceSet(InterfaceSet newIfaces) {
if (mUpstreamIfaceSet == null && newIfaces == null) return true;
if (mUpstreamIfaceSet != null && newIfaces != null) {
return mUpstreamIfaceSet.equals(newIfaces);
}
return false;
}
private Set upstreamInterfacesRemoved(InterfaceSet newIfaces) {
if (mUpstreamIfaceSet == null) return new HashSet<>();
final HashSet removed = new HashSet<>(mUpstreamIfaceSet.ifnames);
removed.removeAll(newIfaces.ifnames);
return removed;
}
private Set upstreamInterfacesAdd(InterfaceSet newIfaces) {
final HashSet added = new HashSet<>(newIfaces.ifnames);
if (mUpstreamIfaceSet != null) added.removeAll(mUpstreamIfaceSet.ifnames);
return added;
}
}
class BaseServingState extends State {
@Override
public void enter() {
if (!startIPv4()) {
mLastError = TetheringManager.TETHER_ERROR_IFACE_CFG_ERROR;
return;
}
try {
NetdUtils.tetherInterface(mNetd, mIfaceName, asIpPrefix(mIpv4Address));
} catch (RemoteException | ServiceSpecificException | IllegalStateException e) {
mLog.e("Error Tethering", e);
mLastError = TetheringManager.TETHER_ERROR_TETHER_IFACE_ERROR;
return;
}
if (!startIPv6()) {
mLog.e("Failed to startIPv6");
// TODO: Make this a fatal error once Bluetooth IPv6 is sorted.
return;
}
}
@Override
public void exit() {
// Note that at this point, we're leaving the tethered state. We can fail any
// of these operations, but it doesn't really change that we have to try them
// all in sequence.
stopIPv6();
try {
NetdUtils.untetherInterface(mNetd, mIfaceName);
} catch (RemoteException | ServiceSpecificException e) {
mLastError = TetheringManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
mLog.e("Failed to untether interface: " + e);
}
stopIPv4();
resetLinkProperties();
}
maybeConfigureStaticIp()主要是根据传入的config信息初始化一下变量,以便后续配置为设定的static ip;这里假设没有指定IP,直接进入mTetheredState,根据StateMachine的切换逻辑,首先执行父状态的enter(),其中:
/** Internals. */
private boolean startIPv4() {
return configureIPv4(true);
}
private boolean configureIPv4(boolean enabled) {
if (VDBG) Log.d(TAG, "configureIPv4(" + enabled + ")");
if (enabled) {
mIpv4Address = requestIpv4Address();
}
if (mIpv4Address == null) {
mLog.e("No available ipv4 address");
return false;
}
if (mInterfaceType == TetheringManager.TETHERING_BLUETOOTH) {
// BT configures the interface elsewhere: only start DHCP.
// TODO: make all tethering types behave the same way, and delete the bluetooth
// code that calls into NetworkManagementService directly.
return configureDhcp(enabled, mIpv4Address, null /* clientAddress */);
}
final IpPrefix ipv4Prefix = asIpPrefix(mIpv4Address);
final Boolean setIfaceUp;
if (mInterfaceType == TetheringManager.TETHERING_WIFI
|| mInterfaceType == TetheringManager.TETHERING_WIFI_P2P
|| mInterfaceType == TetheringManager.TETHERING_ETHERNET
|| mInterfaceType == TetheringManager.TETHERING_WIGIG) {
// The WiFi and Ethernet stack has ownership of the interface up/down state.
// It is unclear whether the Bluetooth or USB stacks will manage their own
// state.
setIfaceUp = null;
} else {
setIfaceUp = enabled;
}
if (!mInterfaceCtrl.setInterfaceConfiguration(mIpv4Address, setIfaceUp)) {
mLog.e("Error configuring interface");
if (!enabled) stopDhcp();
return false;
}
if (enabled) {
mLinkProperties.addLinkAddress(mIpv4Address);
mLinkProperties.addRoute(getDirectConnectedRoute(mIpv4Address));
} else {
mLinkProperties.removeLinkAddress(mIpv4Address);
mLinkProperties.removeRoute(getDirectConnectedRoute(mIpv4Address));
}
return configureDhcp(enabled, mIpv4Address, mStaticIpv4ClientAddr);
}
private LinkAddress requestIpv4Address() {
if (mStaticIpv4ServerAddr != null) return mStaticIpv4ServerAddr;
if (mInterfaceType == TetheringManager.TETHERING_BLUETOOTH) {
return new LinkAddress(BLUETOOTH_IFACE_ADDR);
}
return mPrivateAddressCoordinator.requestDownstreamAddress(this);
}
private boolean configureDhcp(boolean enable, final LinkAddress serverAddr,
final LinkAddress clientAddr) {
if (enable) {
return startDhcp(serverAddr, clientAddr);
} else {
stopDhcp();
return true;
}
}
private boolean startDhcp(final LinkAddress serverLinkAddr, final LinkAddress clientLinkAddr) {
if (mUsingLegacyDhcp) {
return true;
}
final Inet4Address addr = (Inet4Address) serverLinkAddr.getAddress();
final Inet4Address clientAddr = clientLinkAddr == null ? null :
(Inet4Address) clientLinkAddr.getAddress();
final DhcpServingParamsParcel params = makeServingParams(addr /* defaultRouter */,
addr /* dnsServer */, serverLinkAddr, clientAddr);
mDhcpServerStartIndex++;
mDeps.makeDhcpServer(
mIfaceName, params, new DhcpServerCallbacksImpl(mDhcpServerStartIndex));
return true;
}
这里我们没指定static Ip,就会通过requestIpv4Address()函数获取一个随机的IP地址(基本是xxx.xxx.xxx.xxx/netmask),获取到地址后,紧接着就是去设置和通过DHCP为interface配置IP了。
之后就是通过Netd配置iface,因为这类网络共享需要一些路由配置,这部分要由Netd的内部负责处理:
NetdUtils.tetherInterface(mNetd, mIfaceName, asIpPrefix(mIpv4Address));
随后进入TetheredState。
这样SoftAp的开启的流程就粗略的过了一遍,至于大家工作中有跟其他细致流程相关的,可以根据这个流程进行自己的开发与分析了。