Android10 高通平台 softap热点基本流程1

softap的入口在ConnectivityManager.java中,作为连接的一部分。老版本Android的入口在WifiManager.java中。应用启动softap时,调用ConnectivityManager.startTethering()开始。

    @SystemApi
    @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
    public void startTethering(int type, boolean showProvisioningUi,
            final OnStartTetheringCallback callback, Handler handler) {
        Preconditions.checkNotNull(callback, "OnStartTetheringCallback cannot be null.");

        ResultReceiver wrappedCallback = new ResultReceiver(handler) {
            @Override
            protected void onReceiveResult(int resultCode, Bundle resultData) {
                if (resultCode == TETHER_ERROR_NO_ERROR) {
                    callback.onTetheringStarted();
                } else {
                    callback.onTetheringFailed();
                }
            }
        };

        try {
            String pkgName = mContext.getOpPackageName();
            Log.i(TAG, "startTethering caller:" + pkgName);
            mService.startTethering(type, wrappedCallback, showProvisioningUi, pkgName);
        } catch (RemoteException e) {
            Log.e(TAG, "Exception trying to start tethering.", e);
            wrappedCallback.send(TETHER_ERROR_SERVICE_UNAVAIL, null);
        }
    }

参数type有三个类型:

ConnectivityManager.TETHERING_WIFI
ConnectivityManager.TETHERING_USB
ConnectivityManager.TETHERING_BLUETOOTH

我们现在关注的TETHERING_WIFI。进入到ConnectivityService.java中:

@ConnectivityService.java
    @Override
    public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi,
            String callerPkg) {
        ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
        if (!isTetheringSupported()) {
            receiver.send(ConnectivityManager.TETHER_ERROR_UNSUPPORTED, null);
            return;
        }
        mTethering.startTethering(type, receiver, showProvisioningUi);
    }

mTethering是Tethering类的实例。mTethering.startTethering的将调用enableTetheringInternal()方法。

    private void enableTetheringInternal(int type, boolean enable, ResultReceiver receiver) {
        int result;
        switch (type) {
            case TETHERING_WIFI:
                result = setWifiTethering(enable);
                sendTetherResult(receiver, result);
                break;
            case TETHERING_USB:
                result = setUsbTethering(enable);
                sendTetherResult(receiver, result);
                break;
            case TETHERING_BLUETOOTH:
                setBluetoothTethering(enable, receiver);
                break;
            default:
                Log.w(TAG, "Invalid tether type.");
                sendTetherResult(receiver, TETHER_ERROR_UNKNOWN_IFACE);
        }
    }
    
        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.startSoftAp(null /* use existing wifi config */)) ||
                    (!enable && mgr.stopSoftAp())) {
                    mWifiTetherRequested = enable;
                    return TETHER_ERROR_NO_ERROR;
                }
            }
        } finally {
            Binder.restoreCallingIdentity(ident);
        }

        return TETHER_ERROR_MASTER_ERROR;
    }

对于softap,在setWifiTethering()方法中,将调用WifiManager.startSoftAp(null),一切回到从前。

直接进入WifiServiceImpl.java中查看。

@WifiServiceImpl.java
public boolean startSoftAp(WifiConfiguration wifiConfig) {
    return startSoftApInternal(wifiConfig, WifiManager.IFACE_IP_MODE_TETHERED);
}

这里的wifiConfig参数为null。startSoftApInternal()方法实现为:

@WifiServiceImpl.java
private boolean startSoftApInternal(WifiConfiguration wifiConfig, int mode) {
    mLog.trace("startSoftApInternal uid=% mode=%")
            .c(Binder.getCallingUid()).c(mode).flush();

    if (wifiConfig == null && TextUtils.isEmpty(mCountryCode.getCountryCode())) {
        Log.d(TAG, "Starting softap without country code. Fallback to 2G band");
        wifiConfig = new WifiConfiguration(mWifiApConfigStore.getApConfiguration());
        wifiConfig.apBand = WifiConfiguration.AP_BAND_2GHZ;
    }
    
    setDualSapMode(wifiConfig);
    
    if (wifiConfig == null || WifiApConfigStore.validateApWifiConfiguration(wifiConfig)) {
            SoftApModeConfiguration softApConfig = new SoftApModeConfiguration(mode, wifiConfig);
            Log.i(TAG, "Starting softap 2 apChannel=" + wifiConfig.apChannel);
            mWifiController.sendMessage(CMD_SET_AP, 1, 0, softApConfig);
            return true;
        }
}

上面的代码,首先会尝试从WifiApConfigStore中获取已经保存的ap配置信息。这个信息是通过WifiManager.setWifiApConfiguration()方法写入的。如果WifiApConfigStore获取不到,null也可以继续往下传递。接下来有WifiController出来CMD_SET_AP消息。

CMD_SET_AP消息会在WifiController的父类状态DefaultState中处理。处理方法如下:

@WifiController.java
case CMD_SET_AP:
    // note: CMD_SET_AP is handled/dropped in ECM mode - will not start here

    // If request is to start dual sap, turn off sta.
    if (msg.arg1 == 1 && mWifiApConfigStore.getDualSapStatus()) {
        mActiveModeWarden.disableWifi();
        transitionTo(mStaDisabledState);
    }

    if (msg.arg1 == 1) {
        SoftApModeConfiguration config = (SoftApModeConfiguration) msg.obj;
        mActiveModeWarden.enterSoftAPMode((SoftApModeConfiguration) msg.obj);
    } else {
        mActiveModeWarden.stopSoftAPMode(msg.arg2);
    }
    break;

转入WIFI模式管理类进一步操作:

@ActiveModeWarden.java
public void enterSoftAPMode(@NonNull SoftApModeConfiguration wifiConfig) {
    mHandler.post(() -> {
        startSoftAp(wifiConfig);
    });
}

private void startSoftAp(SoftApModeConfiguration softapConfig) {
    Log.d(TAG, "Starting SoftApModeManager");

    WifiConfiguration config = softapConfig.getWifiConfiguration();
    if (config != null && config.SSID != null) {
        Log.d(TAG, "Passing config to SoftApManager! " + config);
    } else {
        config = null;
    }

    SoftApCallbackImpl callback = new SoftApCallbackImpl(softapConfig.getTargetMode());
    ActiveModeManager manager = mWifiInjector.makeSoftApManager(callback, softapConfig);
    callback.setActiveModeManager(manager);
    manager.start();
    mActiveModeManagers.add(manager);
    updateBatteryStatsWifiState(true);
}

SoftApCallbackImpl类中将调用WifiManager.SoftApCallbackImpl()注册的回调方法,通知到应用程序。makeSoftApManager构造一个SoftApManager对象。Client, softap都有一个父类为ActiveModeManager的状态管理类。makeSoftApManager()方法中传入了apconfig, 回调防暑等必要信息。

调用SoftApManager的start方法。

    public void start() {
        mStateMachine.sendMessage(SoftApStateMachine.CMD_START, mApConfig);
    }

向mStateMachine状态机发送CMD_START信息。

在SoftApManager.java中有SoftApStateMachine状态机。只有两种状态:

@SoftApManager.java
SoftApStateMachine(Looper looper) {
    super(TAG, looper);

    addState(mIdleState);
    addState(mStartedState);

    setInitialState(mIdleState);
    start();
}

CMD_START在IdleState中处理,首先会启动hostapd进程。

mApInterfaceName = mWifiNative.setupInterfaceForSoftApMode(
                                mWifiNativeInterfaceCallback);

最后将调用startSoftAp()。

@SoftApManager.java
private int startSoftAp(WifiConfiguration config) {
    //设置国家码
    mWifiNative.setCountryCodeHal(
                mApInterfaceName, mCountryCode.toUpperCase(Locale.ROOT));
    // 是否支持5G
    if (config.apBand == WifiConfiguration.AP_BAND_5GHZ
            && !mWifiNative.is5GhzBandSupported()) {
        mSoftApStartFailureDesc = WifiManager.WIFI_AP_FAILURE_DESC_NO_5GHZ_SUPPORT;
        Log.e(TAG, "Failed to start soft AP as 5Ghz band not supported");
        return ERROR_NO_CHANNEL;
    } else {
        mSoftApStartFailureDesc = "";
    }
    
// Make a copy of configuration for updating AP band and channel.
    WifiConfiguration localConfig = new WifiConfiguration(config);
    // 如果apchannel,根据配置文件config_wifi_framework_sap_2G_channel_list,随机查找一个信道
    int result = ApConfigUtil.updateApChannelConfig(
            mWifiNative, mCountryCode,
            mWifiApConfigStore.getAllowed2GChannel(), localConfig);
    // 开启SoftAp
    mWifiNative.startSoftAp(mApInterfaceName, localConfig, mSoftApListener);

    mStartTimestamp = SystemClock.elapsedRealtime();
}

上面函数,在通过检查国家码,是否支持5G信道后,来判断配置是否正确。如果apchannel=0,还会从xml设置的信道中,随机选择一个信道作为参数。最后调用WifiNative.startSoftAp().

public boolean startSoftAp(
        @NonNull String ifaceName, WifiConfiguration config, SoftApListener listener) {
    if (!mWificondControl.registerApListener(ifaceName, listener)) {
        Log.e(TAG, "Failed to register ap listener");
        return false;
    }
    
    if (mHostapdHal.isVendorHostapdHal()) {
        if (!mHostapdHal.addVendorAccessPoint(ifaceName, config, listener)) {
            Log.e(TAG, "Failed to add Vendor acccess point");
            mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
            return false;
        }
        }  
}
  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值