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, 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
<String> 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
<String> upstreamInterfacesRemoved(InterfaceSet newIfaces) {
-
if (mUpstreamIfaceSet == null) return new HashSet
<>();
-
-
final HashSet
<String> removed = new HashSet
<>(mUpstreamIfaceSet.ifnames);
-
removed.removeAll(newIfaces.ifnames);
-
return removed;
-
}
-
-
private Set
<String> upstreamInterfacesAdd(InterfaceSet newIfaces) {
-
final HashSet
<String> 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的开启的流程就粗略的过了一遍,至于大家工作中有跟其他细致流程相关的,可以根据这个流程进行自己的开发与分析了。
转载:https://blog.csdn.net/csdn_of_coder/article/details/129098947