• Android11 热点设置永不关闭


    Android11 热点设置永不关闭

    一、前言

    Android 热点默认是10 分钟后没有设备关联是会自动关闭,如果需要设置默认不关闭热点可以有几种方式。

    二、framework设置热点永不超时关闭

    查阅网上资料Android 的做法:

    找到:
    CMD_NO_ASSOCIATED_STATIONS_TIMEOUT //超时后触发消息,关闭热点 
    修改:
    case CMD_NO_ASSOCIATED_STATIONS_TIMEOUT: 
    break;这样永远就走不到关闭热点的逻辑
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在Android11 framwrok grep 遍历发现CMD_NO_ASSOCIATED_STATIONS_TIMEOUT 有的。

    所以在 case CMD_NO_ASSOCIATED_STATIONS_TIMEOUT: 添加 break;跳过关闭逻辑同样是生效的

    代码位置:

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

    //找到如下代码进行修改即可:

    
    case CMD_NO_ASSOCIATED_STATIONS_TIMEOUT:
        //添加break 即可完成跳过自动关闭热点逻辑。
        if (true) {
            Log.i(TAG, "timeout but no to close hotspot ap!");
            break;
        }
        if (mConnectedClients.size() != 0) {
            Log.wtf(TAG, "Timeout message received but has clients. Dropping.");
            break;
        }
        mSoftApNotifier.showSoftApShutDownTimeoutExpiredNotification();
        Log.i(TAG, "Timeout message received. Stopping soft AP.");
        updateApState(WifiManager.WIFI_AP_STATE_DISABLING,
        WifiManager.WIFI_AP_STATE_ENABLED, 0);
        transitionTo(mIdleState);
        break;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    其实最好还是添加一个系统属性,可以动态设置是否自动关闭热点。

    
    import android.os.SystemProperties;
    
    //获取
    boolean isSanitizeChannel = SystemProperties.getBoolean("persisit.hotspot_auto_close", false);
    
    //设置
    SystemProperties.set("key", bool + "");
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    三、基于 SoftApManager.java 研究超时逻辑

    从热点开启ConnectivityManager.startTethering 到 SoftApManager.start(),
    这个流程不在这里描述,有兴趣可以自己看看。
    这里只看超时相关的代码。

    
    public class SoftApManager implements ActiveModeManager {
    
        //内部类,不用在意里面真正消息处理,父类内部有Handler处理。
        private class SoftApStateMachine extends StateMachine {
            // Commands for the state machine.
            public static final int CMD_START = 0;
            public static final int CMD_STOP = 1;
            public static final int CMD_FAILURE = 2;
            public static final int CMD_INTERFACE_STATUS_CHANGED = 3;
            public static final int CMD_ASSOCIATED_STATIONS_CHANGED = 4;
            public static final int CMD_NO_ASSOCIATED_STATIONS_TIMEOUT = 5; //超时消息
    。。。
    
            //内部类的内部类!
            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;
                    }
                    //(2)发送延时消息,成功打开热点会触发
                    //可以看到这里是当前时间+timeout时间,重点是研究timeout时间
                    mSoftApTimeoutMessage.schedule(SystemClock.elapsedRealtime()+ timeout);
                    Log.d(TAG, "Timeout message scheduled, delay = "+ timeout);
                }
    
                private void cancelTimeoutMessage() {
                    //(3)关闭延时消息,关闭热点会触发
                    mSoftApTimeoutMessage.cancel();
                    Log.d(TAG, "Timeout message canceled");
                }
    
                @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); //(1)超时Message创建,调用启动热点会触发
    
                    mSarManager.setSapWifiState(WifiManager.WIFI_AP_STATE_ENABLED);
    
                    Log.d(TAG, "Resetting connected clients on start");
                    mConnectedClients.clear();
                    mEverReportMetricsForMaxClient = false;
                    scheduleTimeoutMessage();
                }
                
                @Override
                public boolean processMessage(Message message) {
                    switch (message.what) {
                    case CMD_ASSOCIATED_STATIONS_CHANGED:
                        if (!(message.obj instanceof NativeWifiClient)) {
                        Log.e(TAG, "Invalid type returned for"
                        + " CMD_ASSOCIATED_STATIONS_CHANGED");
                        break;
                        case CMD_NO_ASSOCIATED_STATIONS_TIMEOUT:
                        if (!mTimeoutEnabled) {
                        Log.wtf(TAG, "Timeout message received while timeout is disabled."
                        + " Dropping.");
                    break;
    
                    case CMD_NO_ASSOCIATED_STATIONS_TIMEOUT: //真正处理超时关闭热点的代码
                        if (!mTimeoutEnabled) {
                            Log.wtf(TAG, "Timeout message received while timeout is disabled." + " Dropping.");
                            break;
                        }
    。。。
                        mSoftApNotifier.showSoftApShutDownTimeoutExpiredNotification();
                        Log.i(TAG, "Timeout message received. Stopping soft AP.");
                        updateApState(WifiManager.WIFI_AP_STATE_DISABLING,
                        WifiManager.WIFI_AP_STATE_ENABLED, 0);
                        transitionTo(mIdleState);
                    break;
                }
                
            }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90

    从上面代码看重点是超时设置重点是看:

    
        long timeout = mApConfig.getSoftApConfiguration().getShutdownTimeoutMillis();
        if (timeout == 0) {
            timeout = mDefaultShutDownTimeoutMills;
        }
        //(2)发送延时消息,成功打开热点会触发
        //可以看到这里是当前时间+timeout时间,重点是研究timeout时间
        mSoftApTimeoutMessage.schedule(SystemClock.elapsedRealtime()+ timeout);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    1、mApConfig.getSoftApConfiguration().getShutdownTimeoutMillis();
    一看就是获取某个long数值,查看一下SoftApConfiguration.java 对象是否有相关方法,

    查看确实有set 和 get方法,是hide、SystemApi方法,说明系统应用中是可以设置热点超时时间的。

    
        /**
        * Delay in milliseconds before shutting down soft AP when
        * there are no connected devices.
        */
        private final long mShutdownTimeoutMillis;
    
        @NonNull
        public Builder setShutdownTimeoutMillis(@IntRange(from = 0) long timeoutMillis) {
            if (timeoutMillis < 0) {
                throw new IllegalArgumentException("Invalid timeout value");
            }
            mShutdownTimeoutMillis = timeoutMillis;
            return this;
        }
    
    
        /**
        * Returns the shutdown timeout in milliseconds.
        * The Soft AP will shutdown when there are no devices associated to it for
        * the timeout duration. See {@link Builder#setShutdownTimeoutMillis(long)}.
        *
        * @hide
        */
        @SystemApi
        public long getShutdownTimeoutMillis() {
            return mShutdownTimeoutMillis;
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    如果配置对象中没有设置数据的情况,那么就要看mDefaultShutDownTimeoutMills值了。

    if (timeout == 0) {
        timeout = mDefaultShutDownTimeoutMills;
    }
    
    • 1
    • 2
    • 3

    还是 SoftApManager.java的代码

    
        private long mDefaultShutDownTimeoutMills;
    
        
        //构造方法中:
        public SoftApManager (...) {
            ...
            mDefaultShutDownTimeoutMills = mContext.getResources().getInteger(R.integer.config_wifiFrameworkSoftApShutDownTimeoutMilliseconds);
        }
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    继续追config_wifiFrameworkSoftApShutDownTimeoutMilliseconds定义的文件:

    frameworks\opt\net\wifi\service\res\values\config.xml

    
    
    600000
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    所以 mDefaultShutDownTimeoutMills 的默认值是60000,600秒,即10分钟。

    三、总结:

    1、设置热点不关闭的方法:

    (1)在SoftApManager.java 找到case CMD_NO_ASSOCIATED_STATIONS_TIMEOUT

    直接break;或者retrun;跳过后续关闭热点操作。

    (2)设置热点开启时间长度

    在资源配置文件中设置超时时间为永久:2147483647 (Int的最大数值)

    
    2147483647
    
    
    • 1
    • 2
    • 3

    ####(3)在代码开启热点的对象设置超时时间

        //设置无密码,10信道,2.4G的热点信号
        public void setHotspot2_4(View view) {
            private WifiManager mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
            //使用Build形式配置对象
            SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder();
            configBuilder.setSsid(mHotspotName);
            configBuilder.setChannel(10, SoftApConfiguration.BAND_2GHZ);
            //30 分钟:30*60*1000 = 1800000 或者永久 2147483647
            configBuilder.setShutdownTimeoutMillis(2147483647);
            mWifiManager.setSoftApConfiguration(configBuilder.build());
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    有试过setShutdownTimeoutMillis 方法设置30 分钟的时间,发现过了30分钟没自动关闭!
    具体原因,可以再源码中添加打印查看哈。

    2、其他

         * 热点配置信息对象
         * Android11 使用 WifiManager.setWifiApConfiguration(config); 已经过期,使用已经不能生效!
         * 需要使用:WifiManager.setSoftApConfiguration(config);
    
    
    • 1
    • 2
    • 3
    • 4

    具体实现可以看:
    frameworks\opt\net\wifi\service\java\com\android\server\wifi\WifiServiceImpl.java

    虽然最终都是调用:mWifiApConfigStore.setApConfiguration(softApConfig)
    但是 setSoftApConfiguration 有更多的健全逻辑,比如:全局更新配置
    mActiveModeWarden.updateSoftApConfiguration(softApConfig);
    具体不做分析!

  • 相关阅读:
    北邮22级信通院数电:Verilog-FPGA(3)实验“跑通第一个例程”modelsim仿真及遇到的问题汇总(持续更新中)
    LabVIEW在OPC中使用基金会现场总线
    物联网边缘计算方案
    高并发研究
    【海思SS626 | 开发环境】VMware17安装Ubuntu 18.04.6
    Idea上传gitee注意事项,push reject错误
    .Net Core 3.0 对 MongoDB 的多条件(两种)查询操作
    关于四元数与欧拉角协方差阵转换的一些思考
    vue重新进入页面,js不加载
    瑞慈医疗:H1体检业务同比上涨101.2%,因何领跑医疗健康行业?
  • 原文地址:https://blog.csdn.net/wenzhi20102321/article/details/127737978