android 13 热点启动流程

近期在看一个热点启动的问题。发现网上基本上都算android 9 的wifi热点启动流程。自己去看android 13 的源码的时候发现与之前相比已经有一些小改动了。

在此总结一下wifie热点的启动流程。

我们直接从setting的热点开启按钮 点击事件开始看起。

按钮的初始化在

packages/apps/Settings/src/com/android/settings/wifi/tether/WifiTetherSettings.java

@Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        if (mUnavailable) {
            return;
        }
        // Assume we are in a SettingsActivity. This is only safe because we currently use
        // SettingsActivity as base for all preference fragments.
        final SettingsActivity activity = (SettingsActivity) getActivity();
        final SettingsMainSwitchBar switchBar = activity.getSwitchBar();
        switchBar.setTitle(getContext().getString(R.string.use_wifi_hotsopt_main_switch_title));
        mSwitchBarController = new WifiTetherSwitchBarController(activity, switchBar);
        getSettingsLifecycle().addObserver(mSwitchBarController);
        switchBar.show();
    }

可以看到按钮的控制类在 WifiTetherSwitchBarController  里面。

packages/apps/Settings/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java

@Override
    public void onStart() {
        mDataSaverBackend.addListener(this);
        mSwitchBar.addOnSwitchChangeListener(this);
        mContext.registerReceiver(mReceiver, WIFI_INTENT_FILTER,
                Context.RECEIVER_EXPORTED_UNAUDITED);
    }


@Override
    public void onSwitchChanged(Switch switchView, boolean isChecked) {
        // Filter out unnecessary callbacks when switch is disabled.
        if (!switchView.isEnabled()) return;

        if (isChecked) {
            startTether();
        } else {
            stopTether();
        }
    }

void startTether() {
        if (isWifiApActivated()) return;

        mSwitchBar.setEnabled(false);
        mConnectivityManager.startTethering(TETHERING_WIFI, true /* showProvisioningUi */,
                mOnStartTetheringCallback, new Handler(Looper.getMainLooper()));
    }

final ConnectivityManager.OnStartTetheringCallback mOnStartTetheringCallback =
            new ConnectivityManager.OnStartTetheringCallback() {
                @Override
                public void onTetheringFailed() {
                    super.onTetheringFailed();
                    Log.e(TAG, "Failed to start Wi-Fi Tethering.");
                    handleWifiApStateChanged(mWifiManager.getWifiApState());
                }
            };

这个控制类为按钮设置的点击事件,点击事件里面就开始了开启wifi热点的流程  startTether()

startTether()  执行了 mConnectivityManager.startTethering() 然后就进入到了  ConnectivityManager  类里面。

 public void startTethering(int type, boolean showProvisioningUi,
            final OnStartTetheringCallback callback, Handler handler) {
        Objects.requireNonNull(callback, "OnStartTetheringCallback cannot be null.");

        final Executor executor = new Executor() {
            @Override
            public void execute(Runnable command) {
                if (handler == null) {
                    command.run();
                } else {
                    handler.post(command);
                }
            }
        };

        final StartTetheringCallback tetheringCallback = new StartTetheringCallback() {
            @Override
            public void onTetheringStarted() {
                callback.onTetheringStarted();
            }

            @Override
            public void onTetheringFailed(final int error) {
                callback.onTetheringFailed();
            }
        };

        final TetheringRequest request = new TetheringRequest.Builder(type)
                .setShouldShowEntitlementUi(showProvisioningUi).build();

        getTetheringManager().startTethering(request, executor, tetheringCallback);
    }

getTetheringManager().startTethering() 又进入到了packages/modules/Connectivity/Tethering/common/TetheringLib/src/android/net/TetheringManager.java中。

 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,
                getAttributionTag(), listener));
    }



private void getConnector(ConnectorConsumer consumer) {
        final ITetheringConnector connector;
        synchronized (mConnectorWaitQueue) {
            connector = mConnector;
            if (connector == null) {
                mConnectorWaitQueue.add(consumer);
                return;
            }
        }

        try {
            consumer.onConnectorAvailable(connector);
        } catch (RemoteException e) {
            throw new IllegalStateException(e);
        }
    }

private interface ConnectorConsumer {
        void onConnectorAvailable(ITetheringConnector connector) throws RemoteException;
    }

由于ConnectorConsumer 是一个接口,所以consumer.onConnectorAvailable(connector)就相当于

调用了   connector.startTethering()    。ITetheringConnector connector  是一个aidl 接口,跨进程进去到了

packages/modules/Connectivity/Tethering/src/com/android/networkstack/tethering/TetheringService.java

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

            mTethering.startTethering(request, listener);
        }

这个里又调用到了mTethering.startTethering(request, listener);

frameworks/base/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java

里面去了

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);
        });
    }

这里执行了enableTetheringInternal(request.tetheringType, true /* enabled */, listener);

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;
    }

开启热点当然是执行 result = setWifiTethering(enable);

setWifiTethering()里面又执行了mgr.startTetheredHotspot(null /* use existing softap config */))

这个里面传了一个空的参数,这个参数是有意义的,代表在开启热点时,会根据配置文件的内容决定开启热点的参数。这个配置文件在手机的  data/misc/apexdata/com.android.wifi/     下。里面有两个配置文件,一个是wifi的,一个是热点的。

WifiConfigStore.xml  WifiConfigStoreSoftAp.xml

执行这个方法后又进入到了packages/modules/Wifi/framework/java/android/net/wifi/WifiManager.java类。

public boolean startTetheredHotspot(@Nullable SoftApConfiguration softApConfig) {
        try {
            return mService.startTetheredHotspot(softApConfig, mContext.getOpPackageName());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

mService.startTetheredHotspot()又是一个aidl 接口。进入到了

packages/modules/Wifi/service/java/com/android/server/wifi/WifiServiceImpl.java 里面

 public boolean startTetheredHotspot(@Nullable SoftApConfiguration softApConfig,
            @NonNull String packageName) {
        // NETWORK_STACK is a signature only permission.
        enforceNetworkStackPermission();
        int callingUid = Binder.getCallingUid();
        mWifiPermissionsUtil.checkPackage(callingUid, packageName);

        // If user restriction is set, cannot start softap
        if (mWifiTetheringDisallowed) {
            mLog.err("startTetheredHotspot with user restriction: not permitted").flush();
            return false;
        }

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

        // TODO: b/233363886, handle timeout in general way.
        if (!checkSetEnablingIfAllowed()) {
            return false;
        }

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

        if (!startSoftApInternal(new SoftApModeConfiguration(
                WifiManager.IFACE_IP_MODE_TETHERED, softApConfig,
                mTetheredSoftApTracker.getSoftApCapability()), requestorWs)) {
            mTetheredSoftApTracker.setFailedWhileEnabling();
            return false;
        }
        mLastCallerInfoManager.put(WifiManager.API_TETHERED_HOTSPOT, Process.myTid(),
                callingUid, Binder.getCallingPid(), packageName, true);
        return true;
    }
执行了 startSoftApInternal()
private boolean startSoftApInternal(SoftApModeConfiguration apConfig, WorkSource requestorWs) {
        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, mContext))) {
            Log.e(TAG, "Invalid SoftApConfiguration");
            return false;
        }

        mActiveModeWarden.startSoftAp(apConfig, requestorWs);
        return true;
    }
然后执行   mActiveModeWarden.startSoftAp(apConfig, requestorWs);  进入

packages/modules/Wifi/service/java/com/android/server/wifi/ActiveModeWarden.java

public void startSoftAp(SoftApModeConfiguration softApConfig, WorkSource requestorWs) {
        stopStaIfRequired(softApConfig, requestorWs);
        mWifiController.sendMessage(WifiController.CMD_SET_AP, 1, 0,
                Pair.create(softApConfig, requestorWs));
    }

这里发送了一条消息进入到了ActiveModeWarden 的 内部类 EnabledState 里面。

case CMD_SET_AP:
                        // note: CMD_SET_AP is handled/dropped in ECM mode - will not start here
                        if (msg.arg1 == 1) {
                            Pair<SoftApModeConfiguration, WorkSource> softApConfigAndWs =
                                    (Pair) msg.obj;
                            startSoftApModeManager(
                                    softApConfigAndWs.first, softApConfigAndWs.second);
                        } else {
                            stopSoftApModeManagers(msg.arg2);
                        }
                        break;

这里执行了

startSoftApModeManager(
        softApConfigAndWs.first, softApConfigAndWs.second);
private void startSoftApModeManager(
            @NonNull SoftApModeConfiguration softApConfig, @NonNull WorkSource requestorWs) {
        Log.d(TAG, "Starting SoftApModeManager config = " + softApConfig.getSoftApConfiguration());
        Preconditions.checkState(softApConfig.getTargetMode() == IFACE_IP_MODE_LOCAL_ONLY
                || softApConfig.getTargetMode() == IFACE_IP_MODE_TETHERED);

        WifiServiceImpl.SoftApCallbackInternal callback =
                softApConfig.getTargetMode() == IFACE_IP_MODE_LOCAL_ONLY
                        ? mLohsCallback : mSoftApCallback;
        SoftApManager manager = mWifiInjector.makeSoftApManager(
                new SoftApListener(), callback, softApConfig, requestorWs,
                getRoleForSoftApIpMode(softApConfig.getTargetMode()), mVerboseLoggingEnabled);
        mSoftApManagers.add(manager);
    }

这里的callback  传入的 mLohsCallback   。

后面又执行了mWifiInjector.makeSoftApManager()方法。进入到

packages/modules/Wifi/service/java/com/android/server/wifi/WifiInjector.java

 public SoftApManager makeSoftApManager(
            @NonNull ActiveModeManager.Listener<SoftApManager> listener,
            @NonNull WifiServiceImpl.SoftApCallbackInternal callback,
            @NonNull SoftApModeConfiguration config,
            @NonNull WorkSource requestorWs,
            @NonNull ActiveModeManager.SoftApRole role,
            boolean verboseLoggingEnabled) {
        return new SoftApManager(mContext, mWifiHandlerThread.getLooper(),
                mFrameworkFacade, mWifiNative, mCoexManager, makeBatteryManager(),
                mCountryCode.getCountryCode(), listener, callback, mWifiApConfigStore,
                config, mWifiMetrics, mSarManager, mWifiDiagnostics,
                new SoftApNotifier(mContext, mFrameworkFacade, mWifiNotificationManager),
                mCmiMonitor, mActiveModeWarden, mClock.getElapsedSinceBootMillis(),
                requestorWs, role, verboseLoggingEnabled);
    }

这里直接new了一个SoftApManger。进入到了构造方法里面。

// null is a valid input and means we use the user-configured tethering settings.
        if (mCurrentSoftApConfiguration == null) {
            mCurrentSoftApConfiguration = mWifiApConfigStore.getApConfiguration();
            // may still be null if we fail to load the default config
        }



mStateMachine = new SoftApStateMachine(looper);  //  在这里真正的创建了热点的状态机

 mStateMachine.sendMessage(SoftApStateMachine.CMD_START, requestorWs);

由于之前的config  一直是空的,所以  mWifiApConfigStore.getApConfiguration()    这里面就从配置文件里,获取了热点的配置信息。

最后send一个message。由  SoftApManager  的内部类  IdleState processMessage() 捕获处理.

int result = startSoftAp();

里面有一段,调用了startSoftAp()方法。

 private int startSoftAp() {
        if (SdkLevel.isAtLeastS()) {
            Log.d(getTag(), "startSoftAp: channels " + mCurrentSoftApConfiguration.getChannels()
                    + " iface " + mApInterfaceName + " country " + mCountryCode);
        } else {
            Log.d(getTag(), "startSoftAp: band " + mCurrentSoftApConfiguration.getBand());
        }

        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(mCurrentSoftApConfiguration);

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

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

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

        if (!mWifiNative.startSoftAp(mApInterfaceName,
                  localConfigBuilder.build(),
                  mOriginalModeConfiguration.getTargetMode() ==  WifiManager.IFACE_IP_MODE_TETHERED,
                  mSoftApHalCallback)) {
            Log.e(getTag(), "Soft AP start failed");
            return ERROR_GENERIC;
        }

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

        return SUCCESS;
    }

主要是调用mWifiNative.startSoftAp()方法

 public boolean startSoftAp(
            @NonNull String ifaceName, SoftApConfiguration config, boolean isMetered,
            SoftApHalCallback callback) {
        if (mHostapdHal.isApInfoCallbackSupported()) {
            if (!mHostapdHal.registerApCallback(ifaceName, callback)) {
                Log.e(TAG, "Failed to register ap hal event callback");
                return false;
            }
        } else {
            SoftApHalCallbackFromWificond softApHalCallbackFromWificond =
                    new SoftApHalCallbackFromWificond(ifaceName, callback);
            if (!mWifiCondManager.registerApCallback(ifaceName,
                    Runnable::run, softApHalCallbackFromWificond)) {
                Log.e(TAG, "Failed to register ap hal event callback from wificond");
                return false;
            }
        }

        if (!addAccessPoint(ifaceName, config, isMetered, callback)) {
            Log.e(TAG, "Failed to add acccess point");
            mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
            return false;
        }

        return true;
    }

后面会进入到

frameworks\opt\net\wifi\service\java\com\android\server\wifi\HostapdHal.java

@Override
    public boolean addAccessPoint(@NonNull String ifaceName, @NonNull SoftApConfiguration config,
            boolean isMetered, Runnable onFailureListener) {
        synchronized (mLock) {
            final String methodStr = "addAccessPoint";
            Log.d(TAG, methodStr + ": " + ifaceName);
            if (!checkHostapdAndLogFailure(methodStr)) {
                return false;
            }
            try {
                IfaceParams ifaceParams = prepareIfaceParams(ifaceName, config);
                NetworkParams nwParams = prepareNetworkParams(isMetered, config);
                if (ifaceParams == null || nwParams == null) {
                    Log.e(TAG, "addAccessPoint parameters could not be prepared.");
                    return false;
                }
                mIHostapd.addAccessPoint(ifaceParams, nwParams);
                mSoftApFailureListeners.put(ifaceName, onFailureListener);
                return true;
            } catch (IllegalArgumentException e) {
                Log.e(TAG, "Unrecognized apBand: " + config.getBand());
            } catch (RemoteException e) {
                handleRemoteException(e, methodStr);
            } catch (ServiceSpecificException e) {
                handleServiceSpecificException(e, methodStr);
            }
            return false;
        }
    }

然后会调用到Hal层的方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值