Android R WiFi热点流程浅析

 Android R WiFi热点流程浅析

    Android上的WiFi SoftAp功能是用户常用的功能之一,它能让我们分享手机的网络给其他设备使用。

   那Android系统是如何实现SoftAp的呢,这里在FWK层面做一个简要的流程分析,供自己记录和大家参考。

   以Android R版本为例,我们知道Android大部分的系统FWK服务都在SystemServer中启动,SoftAp的Service也不例外:


    /**
     * Use with {@link #getSystemService(String)} to retrieve a {@link android.net.TetheringManager}
     * for managing tethering functions.
     * @hide
     * @see android.net.TetheringManager
     */
    @SystemApi
    public static final String TETHERING_SERVICE = "tethering";
 
   private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector";

    /**
     * Starts a miscellaneous grab bag of stuff that has yet to be refactored and organized.
     */
    private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
        t.traceBegin("startOtherServices");

        ......
        t.traceBegin("StartTethering");
        try {
            // TODO: hide implementation details, b/146312721.
            ConnectivityModuleConnector.getInstance().startModuleService(
                    TETHERING_CONNECTOR_CLASS,
                    PERMISSION_MAINLINE_NETWORK_STACK, service -> {
                    ServiceManager.addService(Context.TETHERING_SERVICE, service,
                    false /* allowIsolated */,
                        DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL);
                        });
        } catch (Throwable e) {
                reportWtf("starting Tethering", e);
        }
        t.traceEnd();
        ......
    }

这里借助了ConnectivityModuleConnector工具类的startModuleService()函数去启动、绑定服务:

    /**
     * Start a module running in the network stack or system_server process. Should be called only
     * once for each module per device startup.
     *
     * <p>This method will start a networking module either in the network stack
     * process, or inside the system server on devices that do not support the corresponding
     * mainline network . The corresponding networking module service's binder
     * object will then be delivered asynchronously via the provided {@link ModuleServiceCallback}.
     *
     * @param serviceIntentBaseAction Base action to use for constructing the intent needed to
     *                                bind to the corresponding module.
     * @param servicePermissionName Permission to be held by the corresponding module.
     */
    public void startModuleService(
            @NonNull String serviceIntentBaseAction,
            @NonNull String servicePermissionName,
            @NonNull ModuleServiceCallback callback) {
        log("Starting networking module " + serviceIntentBaseAction);

        final PackageManager pm = mContext.getPackageManager();

        // Try to bind in-process if the device was shipped with an in-process version
        Intent intent = mDeps.getModuleServiceIntent(pm, serviceIntentBaseAction,
                servicePermissionName, true /* inSystemProcess */);

        // Otherwise use the updatable module version
        if (intent == null) {
            intent = mDeps.getModuleServiceIntent(pm, serviceIntentBaseAction,
                    servicePermissionName, false /* inSystemProcess */);
            log("Starting networking module in network_stack process");
        } else {
            log("Starting networking module in system_server process");
        }

        if (intent == null) {
            maybeCrashWithTerribleFailure("Could not resolve the networking module", null);
            return;
        }

        final String packageName = intent.getComponent().getPackageName();

        // Start the network stack. The service will be added to the service manager by the
        // corresponding client in ModuleServiceCallback.onModuleServiceConnected().
        if (!mContext.bindServiceAsUser(
                intent, new ModuleServiceConnection(packageName, callback),
                Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM)) {
            maybeCrashWithTerribleFailure(
                    "Could not bind to networking module in-process, or in app with "
                            + intent, packageName);
            return;
        }

        log("Networking module service start requested");
    }

    private class ModuleServiceConnection implements ServiceConnection {
        @NonNull
        private final String mPackageName;
        @NonNull
        private final ModuleServiceCallback mModuleServiceCallback;

        private ModuleServiceConnection(
                @NonNull String packageName,
                @NonNull ModuleServiceCallback moduleCallback) {
            mPackageName = packageName;
            mModuleServiceCallback = moduleCallback;
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            logi("Networking module service connected");
            mModuleServiceCallback.onModuleServiceConnected(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            // onServiceDisconnected is not being called on device shutdown, so this method being
            // called always indicates a bad state for the system server.
            // This code path is only run by the system server: only the system server binds
            // to the NetworkStack as a service. Other processes get the NetworkStack from
            // the ServiceManager.
            maybeCrashWithTerribleFailure("Lost network stack", mPackageName);
        }
    }

结合代码可知,就是通过bindService()启动一个服务,并通过一个lambda表达式在服务connect成功之后进行服务注册的过程,它绑定的服务的filter是:android.net.ITetheringConnector。

在源码中,该服务定义在frameworks\base\packages\Tethering\AndroidManifest.xml中:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.android.networkstack.tethering"
          android:sharedUserId="android.uid.networkstack">
    <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" />

    <!-- Permissions must be defined here, and not in the base manifest, as the tethering
         running in the system server process does not need any permission, and having
         privileged permissions added would cause crashes on startup unless they are also
         added to the privileged permissions whitelist for that package. -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
    <uses-permission android:name="android.permission.BROADCAST_STICKY" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.MANAGE_USB" />
    <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
    <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
    <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    <uses-permission android:name="android.permission.TETHER_PRIVILEGED" />
    <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
    <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />

    <protected-broadcast android:name="com.android.server.connectivity.tethering.DISABLE_TETHERING" />

    <application
        android:process="com.android.networkstack.process"
        android:extractNativeLibs="false"
        android:persistent="true">
        <service android:name="com.android.networkstack.tethering.TetheringService"
                 android:permission="android.permission.MAINLINE_NETWORK_STACK"
                 android:exported="true">
            <intent-filter>
                <action android:name="android.net.ITetheringConnector"/>
            </intent-filter>
        </service>
    </application>
</manifest>

它对应的Service是TetheringService,Tethering.apk封装了网络共享相关的主要服务实现,它的使用类似于Bluetooth.apk,被bind service拉起随后运行;继续看TetheringService:

/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.networkstack.tethering;


/**
 * Android service used to manage tethering.
 *
 * <p>The service returns a binder for the system server to communicate with the tethering.
 */
public class TetheringService extends Service {
    private static final String TAG = TetheringService.class.getSimpleName();

    private TetheringConnector mConnector;

    @Override
    public void onCreate() {
        final TetheringDependencies deps = makeTetheringDependencies();
        // The Tethering object needs a fully functional context to start, so this can't be done
        // in the constructor.
        mConnector = new TetheringConnector(makeTethering(deps), TetheringService.this);
    }

    /**
     * Make a reference to Tethering object.
     */
    @VisibleForTesting
    public Tethering makeTethering(TetheringDependencies deps) {
        System.loadLibrary("tetherutilsjni");
        return new Tethering(deps);
    }

    @NonNull
    @Override
    public IBinder onBind(Intent intent) {
        return mConnector;
    }

    private static class TetheringConnector extends ITetheringConnector.Stub {
        private final TetheringService mService;
        private final Tethering mTethering;

        TetheringConnector(Tethering tether, TetheringService service) {
            mTethering = tether;
            mService = service;
        }
    }
}


/** @hide */
oneway interface ITetheringConnector {
    void tether(String iface, String callerPkg, IIntResultListener receiver);

    void untether(String iface, String callerPkg, IIntResultListener receiver);

    void setUsbTethering(boolean enable, String callerPkg, IIntResultListener receiver);

    void startTethering(in TetheringRequestParcel request, String callerPkg,
            IIntResultListener receiver);

    void stopTethering(int type, String callerPkg, IIntResultListener receiver);

    void requestLatestTetheringEntitlementResult(int type, in ResultReceiver receiver,
            boolean showEntitlementUi, String callerPkg);

    void registerTetheringEventCallback(ITetheringEventCallback callback, String callerPkg);

    void unregisterTetheringEventCallback(ITetheringEventCallback callback, String callerPkg);

    void isTetheringSupported(String callerPkg, IIntResultListener receiver);

    void stopAllTethering(String callerPkg, IIntResultListener receiver);
}

TetheringService主要实现了AIDL ITetheringConnector定义的业务接口,根据function名称可以很清晰的知道,它主要针对的是网络共享。服务启动成功,会以tethering的名字注册进系统中,其他需要使用的组件就可以很容易的向Android查询、获取它。

Tethering组件正常启动之后,就是APP使用它了;我们以CarSetting为例:

/**
 * Fragment to host tethering-related preferences.
 */
@SearchIndexable
public class WifiTetherFragment extends SettingsFragment {

    private TetheringManager mTetheringManager;

    private void startTethering() {
        mTetheringManager.startTethering(ConnectivityManager.TETHERING_WIFI,
                ConcurrentUtils.DIRECT_EXECUTOR,
                new TetheringManager.StartTetheringCallback() {
                    @Override
                    public void onTetheringFailed(final int result) {
                        mTetherSwitch.setChecked(false);
                        mTetherSwitch.setEnabled(true);
                    }
                });
    }

    private void stopTethering() {
        mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
    }

    private void restartTethering() {
        stopTethering();
        mRestartBooked = true;
    }

}

WifiTetherFragment是实现开关热点的Fragment,可知它会调用TetherManager::startTethering()去开启WiFi共享,TetheringManager内部通过ITetheringConnector实现具体功能,类似于WifiManager:

    /**
     * Starts tethering and runs tether provisioning for the given type if needed. If provisioning
     * fails, stopTethering will be called automatically.
     *
     * <p>Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
     * fail if a tethering entitlement check is required.
     *
     * @param request a {@link TetheringRequest} which can specify the preferred configuration.
     * @param executor {@link Executor} to specify the thread upon which the callback of
     *         TetheringRequest will be invoked.
     * @param callback A callback that will be called to indicate the success status of the
     *                 tethering start request.
     */
    @RequiresPermission(anyOf = {
            android.Manifest.permission.TETHER_PRIVILEGED,
            android.Manifest.permission.WRITE_SETTINGS
    })
    public void startTethering(@NonNull final TetheringRequest request,
            @NonNull final Executor executor, @NonNull final StartTetheringCallback callback) {
        final String callerPkg = mContext.getOpPackageName();
        Log.i(TAG, "startTethering caller:" + callerPkg);

        final IIntResultListener listener = new IIntResultListener.Stub() {
            @Override
            public void onResult(final int resultCode) {
                executor.execute(() -> {
                    if (resultCode == TETHER_ERROR_NO_ERROR) {
                        callback.onTetheringStarted();
                    } else {
                        callback.onTetheringFailed(resultCode);
                    }
                });
            }
        };
        getConnector(c -> c.startTethering(request.getParcel(), callerPkg, listener));
    }

    /**
     * Starts tethering and runs tether provisioning for the given type if needed. If provisioning
     * fails, stopTethering will be called automatically.
     *
     * <p>Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
     * fail if a tethering entitlement check is required.
     *
     * @param type The tethering type, on of the {@code TetheringManager#TETHERING_*} constants.
     * @param executor {@link Executor} to specify the thread upon which the callback of
     *         TetheringRequest will be invoked.
     * @hide
     */
    @RequiresPermission(anyOf = {
            android.Manifest.permission.TETHER_PRIVILEGED,
            android.Manifest.permission.WRITE_SETTINGS
    })
    @SystemApi(client = MODULE_LIBRARIES)
    public void startTethering(int type, @NonNull final Executor executor,
            @NonNull final StartTetheringCallback callback) {
        startTethering(new TetheringRequest.Builder(type).build(), executor, callback);
    }

从前述可知,传入的Tethering type是ConnectivityManager.TETHERING_WIFI,直接看TetheringService:

       private final Tethering mTethering;

        @Override
        public void startTethering(TetheringRequestParcel request, String callerPkg,
                IIntResultListener listener) {
            if (checkAndNotifyCommonError(callerPkg,
                    request.exemptFromEntitlementCheck /* onlyAllowPrivileged */,
                    listener)) {
                return;
            }

            m

Tethering是一个包含各种网络共享业务逻辑的实现类,比如BT网络共享、USB网络共享,以及我们这里关注的WiFi网络共享:

/**
 *
 * This class holds much of the business logic to allow Android devices
 * to act as IP gateways via USB, BT, and WiFi interfaces.
 */
public class Tethering {


public Tethering(TetheringDependencies deps) {
        ......
        startStateMachineUpdaters();
    }

    /**
     * Start to register callbacks.
     * Call this function when tethering is ready to handle callback events.
     */
    private void startStateMachineUpdaters() {
        try {
            mNetd.registerUnsolicitedEventListener(mNetdCallback);
        } catch (RemoteException e) {
            mLog.e("Unable to register netd UnsolicitedEventListener");
        }
        mCarrierConfigChange.startListening();
        mContext.getSystemService(TelephonyManager.class).listen(mActiveDataSubIdListener,
                PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);

        IntentFilter filter = new IntentFilter();
        filter.addAction(UsbManager.ACTION_USB_STATE);
        filter.addAction(CONNECTIVITY_ACTION);
        filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
        filter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
        filter.addAction(UserManager.ACTION_USER_RESTRICTIONS_CHANGED);
        filter.addAction(ACTION_RESTRICT_BACKGROUND_CHANGED);
        mContext.registerReceiver(mStateReceiver, filter, null, mHandler);

        final IntentFilter noUpstreamFilter = new IntentFilter();
        noUpstreamFilter.addAction(TetheringNotificationUpdater.ACTION_DISABLE_TETHERING);
        mContext.registerReceiver(
                mStateReceiver, noUpstreamFilter, PERMISSION_MAINLINE_NETWORK_STACK, mHandler);

        final WifiManager wifiManager = getWifiManager();
        if (wifiManager != null) {
            wifiManager.registerSoftApCallback(mExecutor, new TetheringSoftApCallback());
        }

        startTrackDefaultNetwork();
    }

    private class StateReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context content, Intent intent) {
            final String action = intent.getAction();
            if (action == null) return;

            if (action.equals(UsbManager.ACTION_USB_STATE)) {
                handleUsbAction(intent);
            } else if (action.equals(CONNECTIVITY_ACTION)) {
                handleConnectivityAction(intent);
            } else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
                handleWifiApAction(intent);
            } else if (action.equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)) {
                handleWifiP2pAction(intent);
            } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
                mLog.log("OBSERVED configuration changed");
                updateConfiguration();
            } else if (action.equals(UserManager.ACTION_USER_RESTRICTIONS_CHANGED)) {
                mLog.log("OBSERVED user restrictions changed");
                handleUserRestrictionAction();
            } else if (action.equals(ACTION_RESTRICT_BACKGROUND_CHANGED)) {
                mLog.log("OBSERVED data saver changed");
                handleDataSaverChanged();
            } else if (action.equals(TetheringNotificationUpdater.ACTION_DISABLE_TETHERING)) {
                untetherAll();
            }
        }

    void startTethering(final TetheringRequestParcel request, final IIntResultListener listener) {
        mHandler.post(() -> {
            final TetheringRequestParcel unfinishedRequest = mActiveTetheringRequests.get(
                    request.tetheringType);
            // If tethering is already enabled with a different request,
            // disable before re-enabling.
            if (unfinishedRequest != null
                    && !TetheringUtils.isTetheringRequestEquals(unfinishedRequest, request)) {
                enableTetheringInternal(request.tetheringType, false /* disabled */, null);
                mEntitlementMgr.stopProvisioningIfNeeded(request.tetheringType);
            }
            mActiveTetheringRequests.put(request.tetheringType, request);

            if (request.exemptFromEntitlementCheck) {
                mEntitlementMgr.setExemptedDownstreamType(request.tetheringType);
            } else {
                mEntitlementMgr.startProvisioningIfNeeded(request.tetheringType,
                        request.showProvisioningUi);
            }
            enableTetheringInternal(request.tetheringType, true /* enabled */, listener);
        });
    }


    /**
     * Enables or disables tethering for the given type. If provisioning is required, it will
     * schedule provisioning rechecks for the specified interface.
     */
    private void enableTetheringInternal(int type, boolean enable,
            final IIntResultListener listener) {
        int result = TETHER_ERROR_NO_ERROR;
        switch (type) {
            case TETHERING_WIFI:
                result = setWifiTethering(enable);
                break;
            case TETHERING_USB:
                result = setUsbTethering(enable);
                break;
            case TETHERING_BLUETOOTH:
                setBluetoothTethering(enable, listener);
                break;
            case TETHERING_NCM:
                result = setNcmTethering(enable);
                break;
            case TETHERING_ETHERNET:
                result = setEthernetTethering(enable);
                break;
            default:
                Log.w(TAG, "Invalid tether type.");
                result = TETHER_ERROR_UNKNOWN_TYPE;
        }

        // The result of Bluetooth tethering will be sent by #setBluetoothTethering.
        if (type != TETHERING_BLUETOOTH) {
            sendTetherResult(listener, result, type);
        }
    }

    private int setWifiTethering(final boolean enable) {
        final long ident = Binder.clearCallingIdentity();
        try {
            synchronized (mPublicSync) {
                final WifiManager mgr = getWifiManager();
                if (mgr == null) {
                    mLog.e("setWifiTethering: failed to get WifiManager!");
                    return TETHER_ERROR_SERVICE_UNAVAIL;
                }
                if ((enable && mgr.startTetheredHotspot(null /* use existing softap config */))
                        || (!enable && mgr.stopSoftAp())) {
                    mWifiTetherRequested = enable;
                    return TETHER_ERROR_NO_ERROR;
                }
            }
        } finally {
            Binder.restoreCallingIdentity(ident);
        }

        return TETHER_ERROR_INTERNAL_ERROR;
    }

}

从构造函数可知,它监听了WifiManager.WIFI_AP_STATE_CHANGED_ACTION AP状态改变的广播,这让它有了在驱动创建成功SoftAp iface后,为它配置IP的能力,这个后面再介绍。根据startTethering()的调用逻辑,发现它调用了 WifiManager.startTetheredHotspot(),WifiManager我们应该很熟悉:

/**
 * This class provides the primary API for managing all aspects of Wi-Fi
 * connectivity.
 * <p>
 * On releases before {@link android.os.Build.VERSION_CODES#N}, this object
 * should only be obtained from an {@linkplain Context#getApplicationContext()
 * application context}, and not from any other derived context to avoid memory
 * leaks within the calling process.
 * <p>
 * It deals with several categories of items:
 * </p>
 * <ul>
 * <li>The list of configured networks. The list can be viewed and updated, and
 * attributes of individual entries can be modified.</li>
 * <li>The currently active Wi-Fi network, if any. Connectivity can be
 * established or torn down, and dynamic information about the state of the
 * network can be queried.</li>
 * <li>Results of access point scans, containing enough information to make
 * decisions about what access point to connect to.</li>
 * <li>It defines the names of various Intent actions that are broadcast upon
 * any sort of change in Wi-Fi state.
 * </ul>
 * <p>
 * This is the API to use when performing Wi-Fi specific operations. To perform
 * operations that pertain to network connectivity at an abstract level, use
 * {@link android.net.ConnectivityManager}.
 * </p>
 */
@SystemService(Context.WIFI_SERVICE)
public class WifiManager {

    /**
     * Start Soft AP (hotspot) mode for tethering purposes with the specified configuration.
     * Note that starting Soft AP mode may disable station mode operation if the device does not
     * support concurrency.
     * @param softApConfig A valid SoftApConfiguration specifying the configuration of the SAP,
     *                     or null to use the persisted Soft AP configuration that was previously
     *                     set using {@link #setSoftApConfiguration(softApConfiguration)}.
     * @return {@code true} if the operation succeeded, {@code false} otherwise
     *
     * @hide
     */
    @SystemApi
    @RequiresPermission(anyOf = {
            android.Manifest.permission.NETWORK_STACK,
            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
    })
    public boolean startTetheredHotspot(@Nullable SoftApConfiguration softApConfig) {
        try {
            return mService.startTetheredHotspot(softApConfig);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

}


/**
 * WifiService handles remote WiFi operation requests by implementing
 * the IWifiManager interface.
 */
public class WifiServiceImpl extends BaseWifiService {

    /**
     * see {@link android.net.wifi.WifiManager#startTetheredHotspot(SoftApConfiguration)}
     * @param softApConfig SSID, security and channel details as part of SoftApConfiguration
     * @return {@code true} if softap start was triggered
     * @throws SecurityException if the caller does not have permission to start softap
     */
    @Override
    public boolean startTetheredHotspot(@Nullable SoftApConfiguration softApConfig) {
        // NETWORK_STACK is a signature only permission.
        enforceNetworkStackPermission();

        mLog.info("startTetheredHotspot uid=%").c(Binder.getCallingUid()).flush();

        if (!mTetheredSoftApTracker.setEnablingIfAllowed()) {
            mLog.err("Tethering is already active.").flush();
            return false;
        }

        if (!mWifiThreadRunner.call(
                () -> mActiveModeWarden.canRequestMoreSoftApManagers(), false)) {
            // Take down LOHS if it is up.
            mLohsSoftApTracker.stopAll();
        }

        if (!startSoftApInternal(new SoftApModeConfiguration(
                WifiManager.IFACE_IP_MODE_TETHERED, softApConfig,
                mTetheredSoftApTracker.getSoftApCapability()))) {
            mTetheredSoftApTracker.setFailedWhileEnabling();
            return false;
        }

        return true;
    }

    /**
     * Internal method to start softap mode. Callers of this method should have already checked
     * proper permissions beyond the NetworkStack permission.
     */
    private boolean startSoftApInternal(SoftApModeConfiguration apConfig) {
        int uid = Binder.getCallingUid();
        boolean privileged = isSettingsOrSuw(Binder.getCallingPid(), uid);
        mLog.trace("startSoftApInternal uid=% mode=%")
                .c(uid).c(apConfig.getTargetMode()).flush();

        // null wifiConfig is a meaningful input for CMD_SET_AP; it means to use the persistent
        // AP config.
        SoftApConfiguration softApConfig = apConfig.getSoftApConfiguration();
        if (softApConfig != null
                && (!WifiApConfigStore.validateApWifiConfiguration(softApConfig, privileged)
                    || !validateSoftApBand(softApConfig.getBand()))) {
            Log.e(TAG, "Invalid SoftApConfiguration");
            return false;
        }

        mActiveModeWarden.startSoftAp(apConfig);
        return true;
    }

}

主要的,首先创建了一个目标共享MODE为WifiManager.IFACE_IP_MODE_TETHERED的SoftApModeConfiguration对象,它描述了我们对开启的热点的配置信息,随后调用ActiveModeWarden.startSoftAp():

/**
 * This class provides the implementation for different WiFi operating modes.
 */
public class ActiveModeWarden {
    /**
     * WifiController is the class used to manage wifi state for various operating
     * modes (normal, airplane, wifi hotspot, etc.).
     */
    private class WifiController extends StateMachine {
        WifiController() {
            super(TAG, mLooper);

            DefaultState defaultState = new DefaultState();
            addState(defaultState); {
                addState(mDisabledState, defaultState);
                addState(mEnabledState, defaultState);
            }

            setLogRecSize(100);
            setLogOnlyTransitions(false);

        }
        @Override
        public void start() {

            if (shouldEnableSta()) {
                startClientModeManager();
                setInitialState(mEnabledState);
            } else {
                setInitialState(mDisabledState);
            }
 
            super.start();
        }

        class DefaultState extends State {

        }

        class EnabledState extends BaseState {

            private boolean mIsDisablingDueToAirplaneMode;

            @Override
            public void enter() {
                log("EnabledState.enter()");
                super.enter();
                if (!hasAnyModeManager()) {
                    Log.e(TAG, "Entered EnabledState, but no active mode managers");
                }
                mIsDisablingDueToAirplaneMode = false;
            }

            @Override
            public void exit() {
                log("EnabledState.exit()");
                if (hasAnyModeManager()) {
                    Log.e(TAG, "Existing EnabledState, but has active mode managers");
                }
                super.exit();
            }

            @Override
            public boolean processMessageFiltered(Message msg) {
                switch (msg.what) {
                    case CMD_WIFI_TOGGLED:
                    case CMD_SCAN_ALWAYS_MODE_CHANGED:
                        if (shouldEnableSta()) {
                            if (hasAnyClientModeManager()) {
                                switchAllClientModeManagers();
                            } else {
                                startClientModeManager();
                            }
                        } else {
                            stopAllClientModeManagers();
                        }
                        break;
                    case CMD_SET_AP:
                        // note: CMD_SET_AP is handled/dropped in ECM mode - will not start here
                        if (msg.arg1 == 1) {
                            startSoftApModeManager((SoftApModeConfiguration) msg.obj);
                        } else {
                            stopSoftApModeManagers(msg.arg2);
                        }
                        break;
                    case CMD_AIRPLANE_TOGGLED:
                        // airplane mode toggled on is handled in the default state
                        if (mSettingsStore.isAirplaneModeOn()) {
                            mIsDisablingDueToAirplaneMode = true;
                            return NOT_HANDLED;
                        } else {
                            if (mIsDisablingDueToAirplaneMode) {
                                // Previous airplane mode toggle on is being processed, defer the
                                // message toggle off until previous processing is completed.
                                // Once previous airplane mode toggle is complete, we should
                                // transition to DisabledState. There, we will process the deferred
                                // airplane mode toggle message to disable airplane mode.
                                deferMessage(msg);
                            } else {
                                // when airplane mode is toggled off, but wifi is on, we can keep it
                                // on
                                log("airplane mode toggled - and airplane mode is off. return "
                                        + "handled");
                            }
                            return HANDLED;
                        }
                    case CMD_AP_STOPPED:
                    case CMD_AP_START_FAILURE:
                        if (!hasAnyModeManager()) {
                            if (shouldEnableSta()) {
                                log("SoftAp disabled, start client mode");
                                startClientModeManager();
                            } else {
                                log("SoftAp mode disabled, return to DisabledState");
                                transitionTo(mDisabledState);
                            }
                        } else {
                            log("AP disabled, remain in EnabledState.");
                        }
                        break;
                    case CMD_STA_START_FAILURE:
                    case CMD_STA_STOPPED:
                        // Client mode stopped. Head to Disabled to wait for next command if there
                        // no active mode managers.
                        if (!hasAnyModeManager()) {
                            log("STA disabled, return to DisabledState.");
                            transitionTo(mDisabledState);
                        } else {
                            log("STA disabled, remain in EnabledState.");
                        }
                        break;
                    case CMD_RECOVERY_RESTART_WIFI:
                        final String bugTitle;
                        final String bugDetail;
                        if (msg.arg1 < SelfRecovery.REASON_STRINGS.length && msg.arg1 >= 0) {
                            bugDetail = SelfRecovery.REASON_STRINGS[msg.arg1];
                            bugTitle = "Wi-Fi BugReport: " + bugDetail;
                        } else {
                            bugDetail = "";
                            bugTitle = "Wi-Fi BugReport";
                        }
                        if (msg.arg1 != SelfRecovery.REASON_LAST_RESORT_WATCHDOG) {
                            mHandler.post(() -> mClientModeImpl.takeBugReport(bugTitle, bugDetail));
                        }
                        log("Recovery triggered, disable wifi");
                        deferMessage(obtainMessage(CMD_DEFERRED_RECOVERY_RESTART_WIFI));
                        shutdownWifi();
                        // onStopped will move the state machine to "DisabledState".
                        break;
                    default:
                        return NOT_HANDLED;
                }
                return HANDLED;
            }
        }

        class DisabledState extends BaseState {
            @Override
            public void enter() {
                log("DisabledState.enter()");
                super.enter();
                if (hasAnyModeManager()) {
                    Log.e(TAG, "Entered DisabledState, but has active mode managers");
                }
            }

            @Override
            public void exit() {
                log("DisabledState.exit()");
                super.exit();
            }

            @Override
            public boolean processMessageFiltered(Message msg) {
                switch (msg.what) {
                    case CMD_WIFI_TOGGLED:
                    case CMD_SCAN_ALWAYS_MODE_CHANGED:
                        if (shouldEnableSta()) {
                            startClientModeManager();
                            transitionTo(mEnabledState);
                        }
                        break;
                    case CMD_SET_AP:
                        // note: CMD_SET_AP is handled/dropped in ECM mode - will not start here
                        if (msg.arg1 == 1) {
                            startSoftApModeManager((SoftApModeConfiguration) msg.obj);
                            transitionTo(mEnabledState);
                        }
                        break;
                    case CMD_RECOVERY_RESTART_WIFI:
                        log("Recovery triggered, already in disabled state");
                        // intentional fallthrough
                    case CMD_DEFERRED_RECOVERY_RESTART_WIFI:
                        // wait mRecoveryDelayMillis for letting driver clean reset.
                        sendMessageDelayed(CMD_RECOVERY_RESTART_WIFI_CONTINUE,
                                readWifiRecoveryDelay());
                        break;
                    case CMD_RECOVERY_RESTART_WIFI_CONTINUE:
                        if (shouldEnableSta()) {
                            startClientModeManager();
                            transitionTo(mEnabledState);
                        }
                        break;
                    default:
                        return NOT_HANDLED;
                }
                return HANDLED;
            }
        }
    }

    /** Starts SoftAp. */
    public void startSoftAp(SoftApModeConfiguration softApConfig) {
        mWifiController.sendMessage(WifiController.CMD_SET_AP, 1, 0, softApConfig);
    }

}

经常接触Wifi或者BT Framework框架的打工人应该很熟悉StateMachine的流程了,这里不再介绍相关的流程,只关注开启热点的处理流程,startSoftAp()的操作只是发送了WifiController.CMD_SET_AP命令,让状态机处理开启的流程,假设这是我们第一次开热点,也是只开热点,DisabledState状态处理该cmd:

case CMD_SET_AP:
// note: CMD_SET_AP is handled/dropped in ECM mode - will not start here
if (msg.arg1 == 1) {
     startSoftApModeManager((SoftApModeConfiguration) msg.obj);
     transitionTo(mEnabledState);
}

    /**
     * Method to enable soft ap for wifi hotspot.
     *
     * The supplied SoftApModeConfiguration includes the target softap WifiConfiguration (or null if
     * the persisted config is to be used) and the target operating mode (ex,
     * {@link WifiManager#IFACE_IP_MODE_TETHERED} {@link WifiManager#IFACE_IP_MODE_LOCAL_ONLY}).
     *
     * @param softApConfig SoftApModeConfiguration for the hostapd softap
     */
    private void startSoftApModeManager(@NonNull SoftApModeConfiguration softApConfig) {
        Log.d(TAG, "Starting SoftApModeManager config = "
                + softApConfig.getSoftApConfiguration());
        Preconditions.checkState(softApConfig.getTargetMode() == IFACE_IP_MODE_LOCAL_ONLY
                || softApConfig.getTargetMode() == IFACE_IP_MODE_TETHERED);

        WifiManager.SoftApCallback callback =
                softApConfig.getTargetMode() == IFACE_IP_MODE_LOCAL_ONLY
                        ? mLohsCallback : mSoftApCallback;
        SoftApListener listener = new SoftApListener();
        ActiveModeManager manager =
                mWifiInjector.makeSoftApManager(listener, callback, softApConfig);
        listener.setActiveModeManager(manager);
        manager.start();
        manager.setRole(getRoleForSoftApIpMode(softApConfig.getTargetMode()));
        mActiveModeManagers.add(manager);
    }

    private @ActiveModeManager.Role int getRoleForSoftApIpMode(int ipMode) {
        return ipMode == IFACE_IP_MODE_TETHERED
                ? ActiveModeManager.ROLE_SOFTAP_TETHERED : ActiveModeManager.ROLE_SOFTAP_LOCAL_ONLY;
    }

创建SoftApManager并调用其start(),因为之前我们创建的MODE是IFACE_IP_MODE_TETHERED所以给SoftApManager set的role这里是ROLE_SOFTAP_TETHERED;随后进入EnabledState。我们看SoftApManager,它是一个管理WiFi AP mode管理类:

/**
 * Manage WiFi in AP mode.
 * The internal state machine runs under the ClientModeImpl handler thread context.
 */
public class SoftApManager implements ActiveModeManager {

    /**
     * Listener for soft AP events.
     */
    private final SoftApListener mSoftApListener = new SoftApListener() {

        @Override
        public void onFailure() {
            mStateMachine.sendMessage(SoftApStateMachine.CMD_FAILURE);
        }

        @Override
        public void onConnectedClientsChanged(NativeWifiClient client, boolean isConnected) {
            if (client != null) {
                mStateMachine.sendMessage(SoftApStateMachine.CMD_ASSOCIATED_STATIONS_CHANGED,
                        isConnected ? 1 : 0, 0, client);
            } else {
                Log.e(TAG, "onConnectedClientsChanged: Invalid type returned");
            }
        }

        @Override
        public void onSoftApChannelSwitched(int frequency,
                @WifiAnnotations.Bandwidth int bandwidth) {
            mStateMachine.sendMessage(
                    SoftApStateMachine.CMD_SOFT_AP_CHANNEL_SWITCHED, frequency, bandwidth);
        }
    };

    public SoftApManager(@NonNull WifiContext context,
                         @NonNull Looper looper,
                         @NonNull FrameworkFacade framework,
                         @NonNull WifiNative wifiNative,
                         String countryCode,
                         @NonNull Listener listener,
                         @NonNull WifiManager.SoftApCallback callback,
                         @NonNull WifiApConfigStore wifiApConfigStore,
                         @NonNull SoftApModeConfiguration apConfig,
                         @NonNull WifiMetrics wifiMetrics,
                         @NonNull SarManager sarManager,
                         @NonNull BaseWifiDiagnostics wifiDiagnostics) {

        mStateMachine = new SoftApStateMachine(looper);
 
    }

    /**
     * Start soft AP, as configured in the constructor.
     */
    @Override
    public void start() {
        mStateMachine.sendMessage(SoftApStateMachine.CMD_START);
    }

    private class SoftApStateMachine extends StateMachine {

        private final State mIdleState = new IdleState();
        private final State mStartedState = new StartedState();

        private final InterfaceCallback mWifiNativeInterfaceCallback = new InterfaceCallback() {
            @Override
            public void onDestroyed(String ifaceName) {
                if (mApInterfaceName != null && mApInterfaceName.equals(ifaceName)) {
                    sendMessage(CMD_INTERFACE_DESTROYED);
                }
            }

            @Override
            public void onUp(String ifaceName) {
                if (mApInterfaceName != null && mApInterfaceName.equals(ifaceName)) {
                    sendMessage(CMD_INTERFACE_STATUS_CHANGED, 1);
                }
            }

            @Override
            public void onDown(String ifaceName) {
                if (mApInterfaceName != null && mApInterfaceName.equals(ifaceName)) {
                    sendMessage(CMD_INTERFACE_STATUS_CHANGED, 0);
                }
            }
        };

        SoftApStateMachine(Looper looper) {
            super(TAG, looper);

            addState(mIdleState);
            addState(mStartedState);

            setInitialState(mIdleState);
            start();
        }

        private class IdleState extends State {

        }

        private class StartedState extends State {

        }

    }

}

SoftApManager内部包含一个小的状态机SoftApStateMachine,它只有两个状态,Idle状态是初始状态,它处理发来的SoftApStateMachine.CMD_START:

        private class IdleState extends State {
            @Override
            public void enter() {
 
            }

            @Override
            public boolean processMessage(Message message) {
                switch (message.what) {
                    case CMD_START:
                        mApInterfaceName = mWifiNative.setupInterfaceForSoftApMode(
                                mWifiNativeInterfaceCallback);
                        if (TextUtils.isEmpty(mApInterfaceName)) {
                            Log.e(TAG, "setup failure when creating ap interface.");
                            updateApState(WifiManager.WIFI_AP_STATE_FAILED,
                                    WifiManager.WIFI_AP_STATE_DISABLED,
                                    WifiManager.SAP_START_FAILURE_GENERAL);
                            mWifiMetrics.incrementSoftApStartResult(
                                    false, WifiManager.SAP_START_FAILURE_GENERAL);
                            mModeListener.onStartFailure();
                            break;
                        }
                        mSoftApNotifier.dismissSoftApShutDownTimeoutExpiredNotification();
                        updateApState(WifiManager.WIFI_AP_STATE_ENABLING,
                                WifiManager.WIFI_AP_STATE_DISABLED, 0);
                        int result = startSoftAp();
                        if (result != SUCCESS) {
                            int failureReason = WifiManager.SAP_START_FAILURE_GENERAL;
                            if (result == ERROR_NO_CHANNEL) {
                                failureReason = WifiManager.SAP_START_FAILURE_NO_CHANNEL;
                            } else if (result == ERROR_UNSUPPORTED_CONFIGURATION) {
                                failureReason = WifiManager
                                        .SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION;
                            }
                            updateApState(WifiManager.WIFI_AP_STATE_FAILED,
                                    WifiManager.WIFI_AP_STATE_ENABLING,
                                    failureReason);
                            stopSoftAp();
                            mWifiMetrics.incrementSoftApStartResult(false, failureReason);
                            mModeListener.onStartFailure();
                            break;
                        }
                        transitionTo(mStartedState);
                        break;
        }
}

    /**
     * Start a soft AP instance as configured.
     *
     * @return integer result code
     */
    private int startSoftAp() {
        SoftApConfiguration config = mApConfig.getSoftApConfiguration();
        if (config == null || config.getSsid() == null) {
            Log.e(TAG, "Unable to start soft AP without valid configuration");
            return ERROR_GENERIC;
        }

        Log.d(TAG, "band " + config.getBand() + " iface "
                + mApInterfaceName + " country " + mCountryCode);

        int result = setMacAddress();
        if (result != SUCCESS) {
            return result;
        }

        result = setCountryCode();
        if (result != SUCCESS) {
            return result;
        }

        // Make a copy of configuration for updating AP band and channel.
        SoftApConfiguration.Builder localConfigBuilder = new SoftApConfiguration.Builder(config);

        boolean acsEnabled = mCurrentSoftApCapability.areFeaturesSupported(
                SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD);

        result = ApConfigUtil.updateApChannelConfig(
                mWifiNative, mContext.getResources(), mCountryCode, localConfigBuilder, config,
                acsEnabled);
        if (result != SUCCESS) {
            Log.e(TAG, "Failed to update AP band and channel");
            return result;
        }

        if (config.isHiddenSsid()) {
            Log.d(TAG, "SoftAP is a hidden network");
        }

        if (!ApConfigUtil.checkSupportAllConfiguration(config, mCurrentSoftApCapability)) {
            Log.d(TAG, "Unsupported Configuration detect! config = " + config);
            return ERROR_UNSUPPORTED_CONFIGURATION;
        }

        if (!mWifiNative.startSoftAp(mApInterfaceName,
                  localConfigBuilder.build(), mSoftApListener)) {
            Log.e(TAG, "Soft AP start failed");
            return ERROR_GENERIC;
        }

        mWifiDiagnostics.startLogging(mApInterfaceName);
        mStartTimestamp = FORMATTER.format(new Date(System.currentTimeMillis()));
        Log.d(TAG, "Soft AP is started ");

        return SUCCESS;
    }

主要的:

1、WifiNative.setupInterfaceForSoftApMode():创建一个供AP MODE使用的interface,它的状态由mWifiNativeInterfaceCallback回调管理.

2、SoftApManager.startSoftAp():按配置信息,在HAL/Driver层创建一个管理Soft ap的instance,它的状态由SoftApListener回调管理

如果都调用成功,进入StartedState:

        private class StartedState extends State {
            private WakeupMessage mSoftApTimeoutMessage;

            private void scheduleTimeoutMessage() {
                if (!mTimeoutEnabled || mConnectedClients.size() != 0) {
                    cancelTimeoutMessage();
                    return;
                }
                long timeout = mApConfig.getSoftApConfiguration().getShutdownTimeoutMillis();
                if (timeout == 0) {
                    timeout =  mDefaultShutDownTimeoutMills;
                }
                mSoftApTimeoutMessage.schedule(SystemClock.elapsedRealtime()
                        + timeout);
                Log.d(TAG, "Timeout message scheduled, delay = "
                        + timeout);
            }
            @Override
            public void enter() {
                mIfaceIsUp = false;
                mIfaceIsDestroyed = false;
                onUpChanged(mWifiNative.isInterfaceUp(mApInterfaceName));

                Handler handler = mStateMachine.getHandler();
                mSoftApTimeoutMessage = new WakeupMessage(mContext, handler,
                        SOFT_AP_SEND_MESSAGE_TIMEOUT_TAG,
                        SoftApStateMachine.CMD_NO_ASSOCIATED_STATIONS_TIMEOUT);

                mSarManager.setSapWifiState(WifiManager.WIFI_AP_STATE_ENABLED);

                Log.d(TAG, "Resetting connected clients on start");
                mConnectedClients.clear();
                mEverReportMetricsForMaxClient = false;
                scheduleTimeoutMessage();
            }
}

进入StartedState::enter()时,比较重要的是此时会设置一个默认600000ms(10min)的timeout超时机制,如果此时间段一直没有设备连接该AP,就会自动关闭AP。

整个开启AP的过程都会有对外通知当前AP状态改变的广播发送:

    /**
     * Update AP state.
     *
     * @param newState     new AP state
     * @param currentState current AP state
     * @param reason       Failure reason if the new AP state is in failure state
     */
    private void updateApState(int newState, int currentState, int reason) {
        mSoftApCallback.onStateChanged(newState, reason);

        //send the AP state change broadcast
        final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
        intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, newState);
        intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, currentState);
        if (newState == WifiManager.WIFI_AP_STATE_FAILED) {
            //only set reason number when softAP start failed
            intent.putExtra(WifiManager.EXTRA_WIFI_AP_FAILURE_REASON, reason);
        }

        intent.putExtra(WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME, mApInterfaceName);
        intent.putExtra(WifiManager.EXTRA_WIFI_AP_MODE, mApConfig.getTargetMode());
        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
    }

假设我们正常开启了热点,此时也会发送AP开启成功的广播。回到前面介绍Tethering的内容,它内部监听了该广播:

    private class StateReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context content, Intent intent) {
            final String action = intent.getAction();
            if (action == null) return;

            if (action.equals(UsbManager.ACTION_USB_STATE)) {
                handleUsbAction(intent);
            } else if (action.equals(CONNECTIVITY_ACTION)) {
                handleConnectivityAction(intent);
            } else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
                handleWifiApAction(intent);
            } else if (action.equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)) {
                handleWifiP2pAction(intent);
            } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
                mLog.log("OBSERVED configuration changed");
                updateConfiguration();
            } else if (action.equals(UserManager.ACTION_USER_RESTRICTIONS_CHANGED)) {
                mLog.log("OBSERVED user restrictions changed");
                handleUserRestrictionAction();
            } else if (action.equals(ACTION_RESTRICT_BACKGROUND_CHANGED)) {
                mLog.log("OBSERVED data saver changed");
                handleDataSaverChanged();
            } else if (action.equals(TetheringNotificationUpdater.ACTION_DISABLE_TETHERING)) {
                untetherAll();
            }
        }

        private void handleWifiApAction(Intent intent) {
            final int curState = intent.getIntExtra(EXTRA_WIFI_AP_STATE, WIFI_AP_STATE_DISABLED);
            final String ifname = intent.getStringExtra(EXTRA_WIFI_AP_INTERFACE_NAME);
            final int ipmode = intent.getIntExtra(EXTRA_WIFI_AP_MODE, IFACE_IP_MODE_UNSPECIFIED);

            synchronized (Tethering.this.mPublicSync) {
                switch (curState) {
                    case WifiManager.WIFI_AP_STATE_ENABLING:
                        // We can see this state on the way to both enabled and failure states.
                        break;
                    case WifiManager.WIFI_AP_STATE_ENABLED:
                        enableWifiIpServingLocked(ifname, ipmode);
                        break;
                    case WifiManager.WIFI_AP_STATE_DISABLING:
                        // We can see this state on the way to disabled.
                        break;
                    case WifiManager.WIFI_AP_STATE_DISABLED:
                    case WifiManager.WIFI_AP_STATE_FAILED:
                    default:
                        disableWifiIpServingLocked(ifname, curState);
                        break;
                }
            }
        }
}

    private void enableWifiIpServingLocked(String ifname, int wifiIpMode) {
        // Map wifiIpMode values to IpServer.Callback serving states, inferring
        // from mWifiTetherRequested as a final "best guess".
        final int ipServingMode;
        switch (wifiIpMode) {
            case IFACE_IP_MODE_TETHERED:
                ipServingMode = IpServer.STATE_TETHERED;
                break;
            case IFACE_IP_MODE_LOCAL_ONLY:
                ipServingMode = IpServer.STATE_LOCAL_ONLY;
                break;
            default:
                mLog.e("Cannot enable IP serving in unknown WiFi mode: " + wifiIpMode);
                return;
        }

        if (!TextUtils.isEmpty(ifname)) {
            maybeTrackNewInterfaceLocked(ifname);
            changeInterfaceState(ifname, ipServingMode);
        } else {
            mLog.e(String.format(
                    "Cannot enable IP serving in mode %s on missing interface name",
                    ipServingMode));
        }
    }

根据前面的说明,此处会调用Tethering.enableWifiIpServingLocked(),主要的处理有改变ipServerMode的值为IpServer.STATE_TETHERED,以及如下两个函数:

    private void maybeTrackNewInterfaceLocked(final String iface) {
        // If we don't care about this type of interface, ignore.
        final int interfaceType = ifaceNameToType(iface);
        if (interfaceType == TETHERING_INVALID) {
            mLog.log(iface + " is not a tetherable iface, ignoring");
            return;
        }
        maybeTrackNewInterfaceLocked(iface, interfaceType);
    }

    private void maybeTrackNewInterfaceLocked(final String iface, int interfaceType) {
        // If we have already started a TISM for this interface, skip.
        if (mTetherStates.containsKey(iface)) {
            mLog.log("active iface (" + iface + ") reported as added, ignoring");
            return;
        }

        mLog.log("adding TetheringInterfaceStateMachine for: " + iface);
        final TetherState tetherState = new TetherState(
                new IpServer(iface, mLooper, interfaceType, mLog, mNetd, mBpfCoordinator,
                             makeControlCallback(), mConfig.enableLegacyDhcpServer,
                             mConfig.isBpfOffloadEnabled(), mPrivateAddressCoordinator,
                             mDeps.getIpServerDependencies()));
        mTetherStates.put(iface, tetherState);
        tetherState.ipServer.start();
    }

    private void changeInterfaceState(String ifname, int requestedState) {
        final int result;
        switch (requestedState) {
            case IpServer.STATE_UNAVAILABLE:
            case IpServer.STATE_AVAILABLE:
                result = untether(ifname);
                break;
            case IpServer.STATE_TETHERED:
            case IpServer.STATE_LOCAL_ONLY:
                result = tether(ifname, requestedState);
                break;
            default:
                Log.wtf(TAG, "Unknown interface state: " + requestedState);
                return;
        }
        if (result != TETHER_ERROR_NO_ERROR) {
            Log.e(TAG, "unable start or stop tethering on iface " + ifname);
            return;
        }
    }

这里两个个函数的内容分别介绍,首先maybeTrackNewInterfaceLocked():

    private void maybeTrackNewInterfaceLocked(final String iface, int interfaceType) {
        // If we have already started a TISM for this interface, skip.
        if (mTetherStates.containsKey(iface)) {
            mLog.log("active iface (" + iface + ") reported as added, ignoring");
            return;
        }

        mLog.log("adding TetheringInterfaceStateMachine for: " + iface);
        final TetherState tetherState = new TetherState(
                new IpServer(iface, mLooper, interfaceType, mLog, mNetd, mBpfCoordinator,
                             makeControlCallback(), mConfig.enableLegacyDhcpServer,
                             mConfig.isBpfOffloadEnabled(), mPrivateAddressCoordinator,
                             mDeps.getIpServerDependencies()));
        mTetherStates.put(iface, tetherState);
        tetherState.ipServer.start();
    }

1、它为每个iface创建了TetherState对象,并保存一个Map里

2、同时创建了IpServer类型实例,并调用了IpServer.start(),它是给AP配置的IP地址的来源

/**
 * Provides the interface to IP-layer serving functionality for a given network
 * interface, e.g. for tethering or "local-only hotspot" mode.
 *
 * @hide
 */
public class IpServer extends StateMachine {

    /** IpServer callback. */
    public static class Callback {
        /**
         * Notify that |who| has changed its tethering state.
         *
         * @param who the calling instance of IpServer
         * @param state one of STATE_*
         * @param lastError one of TetheringManager.TETHER_ERROR_*
         */
        public void updateInterfaceState(IpServer who, int state, int lastError) { }

        /**
         * Notify that |who| has new LinkProperties.
         *
         * @param who the calling instance of IpServer
         * @param newLp the new LinkProperties to report
         */
        public void updateLinkProperties(IpServer who, LinkProperties newLp) { }

        /**
         * Notify that the DHCP leases changed in one of the IpServers.
         */
        public void dhcpLeasesChanged() { }

        /**
         * Request Tethering change.
         *
         * @param tetheringType the downstream type of this IpServer.
         * @param enabled enable or disable tethering.
         */
        public void requestEnableTethering(int tetheringType, boolean enabled) { }
    }

    private final State mInitialState;
    private final State mLocalHotspotState;
    private final State mTetheredState;
    private final State mUnavailableState;
    private final State mWaitingForRestartState;

    private LinkAddress mIpv4Address;

    // TODO: Add a dependency object to pass the data members or variables from the tethering
    // object. It helps to reduce the arguments of the constructor.
    public IpServer(
            String ifaceName, Looper looper, int interfaceType, SharedLog log,
            INetd netd, @NonNull BpfCoordinator coordinator, Callback callback,
            boolean usingLegacyDhcp, boolean usingBpfOffload,
            PrivateAddressCoordinator addressCoordinator, Dependencies deps) {


        mInitialState = new InitialState();
        mLocalHotspotState = new LocalHotspotState();
        mTetheredState = new TetheredState();
        mUnavailableState = new UnavailableState();
        mWaitingForRestartState = new WaitingForRestartState();
        addState(mInitialState);
        addState(mLocalHotspotState);
        addState(mTetheredState);
        addState(mWaitingForRestartState, 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的开启的流程就粗略的过了一遍,至于大家工作中有跟其他细致流程相关的,可以根据这个流程进行自己的开发与分析了。

猜你喜欢

转载自blog.csdn.net/csdn_of_coder/article/details/129098947