Android softap 打开流程

基于Android S 代码:http://aospxref.com/android-13.0.0_r3/

界面代码:http://aospxref.com/android-13.0.0_r3/xref/packages/apps/Settings/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java#onSwitchChanged
onSwitchChanged —> startTether()

    void startTether() {
        if (isWifiApActivated()) return;
        mSwitchBar.setEnabled(false);
        mConnectivityManager.startTethering(TETHERING_WIFI, true /* showProvisioningUi */,   ---> 继续看
                mOnStartTetheringCallback, new Handler(Looper.getMainLooper()));
    }

http://aospxref.com/android-13.0.0_r3/xref/packages/modules/Connectivity/framework/src/android/net/ConnectivityManager.java#2892

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) {
                // 如果没有传入 Handler,则直接运行任务
                command.run();
            } else {
                // 如果传入了 Handler,则在主线程上执行任务
                handler.post(command);
            }
        }
    };

    // 创建一个 StartTetheringCallback 对象,用于接收启动网络共享的回调事件
    final StartTetheringCallback tetheringCallback = new StartTetheringCallback() {
        @Override
        public void onTetheringStarted() {
            // 当网络共享启动时,调用传入的回调对象的相应方法
            callback.onTetheringStarted();
        }

        @Override
        public void onTetheringFailed(final int error) {
            // 当网络共享启动失败时,调用传入的回调对象的相应方法
            callback.onTetheringFailed();
        }
    };

    // 构建一个 TetheringRequest 对象,用于描述网络共享的请求参数
    final TetheringRequest request = new TetheringRequest.Builder(type)
            .setShouldShowEntitlementUi(showProvisioningUi).build();

    // 获取 TetheringManager 对象,并调用其 startTethering() 方法启动网络共享
    getTetheringManager().startTethering(request, executor, tetheringCallback);
}

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

http://aospxref.com/android-13.0.0_r3/xref/packages/modules/Connectivity/Tethering/src/com/android/networkstack/tethering/TetheringService.java#startTethering
然后调用到:http://aospxref.com/android-13.0.0_r3/xref/packages/modules/Connectivity/Tethering/src/com/android/networkstack/tethering/Tethering.java#startTethering

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

http://aospxref.com/android-13.0.0_r3/xref/packages/modules/Wifi/framework/java/android/net/wifi/WifiManager.java#4644
http://aospxref.com/android-13.0.0_r3/xref/packages/modules/Wifi/service/java/com/android/server/wifi/WifiServiceImpl.java#1572
一步步调用下来,最终处理在WifiServiceImpl中这里省略掉部分代码,只看流程相关的:

    public boolean startTetheredHotspot(@Nullable SoftApConfiguration softApConfig, @NonNull String packageName) {
        if (!startSoftApInternal(new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, softApConfig,
                mTetheredSoftApTracker.getSoftApCapability()), requestorWs)) {
            mTetheredSoftApTracker.setFailedWhileEnabling();
            return false;
        }
}

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

http://aospxref.com/android-13.0.0_r3/xref/packages/modules/Wifi/service/java/com/android/server/wifi/ActiveModeWarden.java#startSoftAp

    public void startSoftAp(SoftApModeConfiguration softApConfig, WorkSource requestorWs) {
        mWifiController.sendMessage(WifiController.CMD_SET_AP, 1, 0,
                Pair.create(softApConfig, requestorWs));
    }
    
	初始状态是取决于目前是什么模式:
	if (role == ROLE_CLIENT_PRIMARY) {  ---> client 模式
		startPrimaryClientModeManager(mLastPrimaryClientModeManagerRequestorWs);
        setInitialState(mEnabledState);
    } else if (role == ROLE_CLIENT_SCAN_ONLY) {   ---> 后台扫描模式
        startScanOnlyClientModeManager(mLastScanOnlyClientModeManagerRequestorWs);
        setInitialState(mEnabledState);
    } else {
        setInitialState(mDisabledState);
    }
    
   	无论是哪种模式,最终都是调用这个方法:
     	private void startSoftApModeManager( @NonNull SoftApModeConfiguration softApConfig, @NonNull WorkSource requestorWs) {
     	//SoftApModeConfiguration不能为null,但是这里的softapConfiguration为null,因为上面我们传配置的时候初始化为null
        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(  ---> 创建一个SoftApManager
                new SoftApListener(), callback, softApConfig, requestorWs,
                getRoleForSoftApIpMode(softApConfig.getTargetMode()), mVerboseLoggingEnabled);
        mSoftApManagers.add(manager);
    }

看下创建new的地方:http://aospxref.com/android-13.0.0_r3/xref/packages/modules/Wifi/service/java/com/android/server/wifi/SoftApManager.java#SoftApManager

   public SoftApManager(…………
   部分代码省略,只看几个和流程相关的地方
     mCurrentSoftApConfiguration = apConfig.getSoftApConfiguration();   ---> 刚说过,这里面是null
     if (mCurrentSoftApConfiguration == null) {
     	mCurrentSoftApConfiguration = mWifiApConfigStore.getApConfiguration(); ---> 拿默认配置,我们常修改热点名就是这个方法里面
     }
     // 重新打包成 SoftApModeConfiguration,因为现在SoftApConfiguration不为null了,当然前提是获取默认配置成功
     mOriginalModeConfiguration = new SoftApModeConfiguration(apConfig.getTargetMode(),
                mCurrentSoftApConfiguration, mCurrentSoftApCapability);
     mStateMachine.sendMessage(SoftApStateMachine.CMD_START, requestorWs);
     
    处理这个消息:CMD_START ,初始化状态是  setInitialState(mIdleState),在setInitialState状态机中处理,代码有点多,具体的大家细看代码,这里记录些总要的:
     private class IdleState extends State {
     	// 初始化接口
     	mApInterfaceName = mWifiNative.setupInterfaceForSoftApMode( mWifiNativeInterfaceCallback, mRequestorWs,mCurrentSoftApConfiguration.getBand(), isBridgeRequired(),SoftApManager.this);
     	// 更新状态
     	updateApState(WifiManager.WIFI_AP_STATE_ENABLING,WifiManager.WIFI_AP_STATE_DISABLED, 0);
     	//接口初始化没问题就开始启动了
        int result = startSoftAp();

    private int startSoftAp() {
        Log.d(getTag(), "startSoftAp: band " + mCurrentSoftApConfiguration.getBand()
                + " iface " + mApInterfaceName + " country " + mCountryCode);
        // 设置mac地址
        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;
        }
		// 继续调用,启动 SoftAP
        if (!mWifiNative.startSoftAp(mApInterfaceName,
                  localConfigBuilder.build(),
                  mOriginalModeConfiguration.getTargetMode() ==  WifiManager.IFACE_IP_MODE_TETHERED,
                  mSoftApHalCallback)) {
            Log.e(getTag(), "Soft AP start failed");
            return ERROR_GENERIC;
        }
		// 启动 Wi-Fi 诊断日志记录,将日志写入与热点接口名称相关的文件中
        mWifiDiagnostics.startLogging(mApInterfaceName);
        // 记录了 Soft AP 启动的时间戳
        mStartTimestamp = FORMATTER.format(new Date(System.currentTimeMillis()));
        Log.d(getTag(), "Soft AP is started ");
        return SUCCESS;
    }

http://aospxref.com/android-13.0.0_r3/xref/packages/modules/Wifi/service/java/com/android/server/wifi/WifiNative.java#startSoftAp

public boolean startSoftAp(@NonNull String ifaceName, SoftApConfiguration config, boolean isMetered,SoftApHalCallback callback) {
    // 检查是否支持 AP 信息回调
    if (mHostapdHal.isApInfoCallbackSupported()) {
        // 使用 Hostapd HAL 注册 AP HAL 事件回调
        if (!mHostapdHal.registerApCallback(ifaceName, callback)) {
            Log.e(TAG, "Failed to register ap hal event callback");
            return false;
        }
    } else {
        // 使用 Wificond 注册 AP HAL 事件回调
        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;
        }
    }

    // 添加访问点配置到 Hostapd HAL
    if (!mHostapdHal.addAccessPoint(ifaceName, config, isMetered, callback::onFailure)) {
        Log.e(TAG, "Failed to add acccess point");
        mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
        return false;
    }
    return true;
}

http://aospxref.com/android-13.0.0_r3/xref/packages/modules/Wifi/service/java/com/android/server/wifi/HostapdHal.java#addAccessPoint

    public boolean addAccessPoint(@NonNull String ifaceName, @NonNull SoftApConfiguration config,
                                  boolean isMetered, @NonNull Runnable onFailureListener) {
        synchronized (mLock) {
            String methodStr = "addAccessPoint";
            if (mIHostapd == null) {
                return handleNullIHostapd(methodStr);
            }
            return mIHostapd.addAccessPoint(ifaceName, config, isMetered, onFailureListener);
        }
    }

这里注意下 mIHostapd 具体是哪个, mIHostapd = createIHostapdHalMockable(),这里面有两个IHostapd可以提供:

    protected IHostapdHal createIHostapdHalMockable() {
        synchronized (mLock) {
            // Prefer AIDL implementation if service is declared.
            if (HostapdHalAidlImp.serviceDeclared()) {   ---> T版本之后支持
                Log.i(TAG, "Initializing hostapd using AIDL implementation.");
                return new HostapdHalAidlImp(mContext, mEventHandler);

            } else if (HostapdHalHidlImp.serviceDeclared()) {  ---> 目前看的是S版本的代码
                Log.i(TAG, "Initializing hostapd using HIDL implementation.");
                return new HostapdHalHidlImp(mContext, mEventHandler);
            }
            Log.e(TAG, "No HIDL or AIDL service available for hostapd.");
            return null;
        }
    }

所以这里是走的 HostapdHalHidlImp 类去添加一个 access point:http://aospxref.com/android-13.0.0_r3/xref/packages/modules/Wifi/service/java/com/android/server/wifi/HostapdHalHidlImp.java#addAccessPoint
根据硬件版本调用不同的接口实现

    public boolean addAccessPoint(@NonNull String ifaceName, @NonNull SoftApConfiguration config,
            boolean isMetered, @NonNull Runnable onFailureListener) {
        synchronized (mLock) {
            final String methodStr = "addAccessPoint";
            IHostapd.IfaceParams ifaceParamsV1_0 = prepareIfaceParamsV1_0(ifaceName, config);
            android.hardware.wifi.hostapd.V1_2.IHostapd.NetworkParams nwParamsV1_2 =
                    prepareNetworkParamsV1_2(config);
            if (nwParamsV1_2 == null) return false;
            if (!checkHostapdAndLogFailure(methodStr)) return false;
            try {
                HostapdStatus status;
                if (!isV1_1()) {
                    // V1_0 case
                    status = mIHostapd.addAccessPoint(ifaceParamsV1_0, nwParamsV1_2.V1_0);
                    if (!checkStatusAndLogFailure(status, methodStr)) {
                        return false;
                    }
                } else {
                    android.hardware.wifi.hostapd.V1_1.IHostapd.IfaceParams ifaceParamsV1_1 =
                            prepareIfaceParamsV1_1(ifaceParamsV1_0, config);
                    if (!isV1_2()) {
                        // V1_1 case
                        android.hardware.wifi.hostapd.V1_1.IHostapd iHostapdV1_1 =
                                getHostapdMockableV1_1();
                        if (iHostapdV1_1 == null) return false;
                        status = iHostapdV1_1.addAccessPoint_1_1(ifaceParamsV1_1,
                                nwParamsV1_2.V1_0);
                        if (!checkStatusAndLogFailure(status, methodStr)) {
                            return false;
                        }
                    } else {
                        // V1_2 & V1_3 case
                        android.hardware.wifi.hostapd.V1_2.HostapdStatus status12;
                        android.hardware.wifi.hostapd.V1_2.IHostapd.IfaceParams ifaceParamsV1_2 =
                                prepareIfaceParamsV1_2(ifaceParamsV1_1, config);
                        if (!isV1_3()) {
                            // V1_2 case
                            android.hardware.wifi.hostapd.V1_2.IHostapd iHostapdV1_2 =
                                    getHostapdMockableV1_2();
                            if (iHostapdV1_2 == null) return false;
                            status12 = iHostapdV1_2.addAccessPoint_1_2(ifaceParamsV1_2,
                                    nwParamsV1_2);
                        } else {
                            // V1_3 case
                            android.hardware.wifi.hostapd.V1_3
                                    .IHostapd.NetworkParams nwParamsV1_3 =
                                    new android.hardware.wifi.hostapd.V1_3
                                            .IHostapd.NetworkParams();
                            nwParamsV1_3.V1_2 = nwParamsV1_2;
                            nwParamsV1_3.isMetered = isMetered;
                            android.hardware.wifi.hostapd.V1_3.IHostapd.IfaceParams ifaceParams1_3 =
                                    prepareIfaceParamsV1_3(ifaceParamsV1_2, config);
                            android.hardware.wifi.hostapd.V1_3.IHostapd iHostapdV1_3 =
                                    getHostapdMockableV1_3();
                            if (iHostapdV1_3 == null) return false;
                            status12 = iHostapdV1_3.addAccessPoint_1_3(ifaceParams1_3,
                                    nwParamsV1_3);
                        }
                        if (!checkStatusAndLogFailure12(status12, methodStr)) {
                            return false;
                        }
                    }
                }

                mSoftApFailureListeners.put(ifaceName, onFailureListener);
                return true;
            } catch (IllegalArgumentException e) {
                Log.e(TAG, "Unrecognized apBand: " + config.getBand());
                return false;
            } catch (RemoteException e) {
                handleRemoteException(e, methodStr);
                return false;
            }
        }
    }

具体走的是哪个版本的,可以自己看下含有厂商的基线,比如MTK的实现就是1.3版本的,路径如下:/external/wpa_supplicant_8/hostapd/hidl/1.3/hostapd.cpp,这里面实现了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值