赞
踩
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的开启的流程就粗略的过了一遍,至于大家工作中有跟其他细致流程相关的,可以根据这个流程进行自己的开发与分析了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。