Android 热点默认是10 分钟后没有设备关联是会自动关闭,如果需要设置默认不关闭热点可以有几种方式。
查阅网上资料Android 的做法:
找到:
CMD_NO_ASSOCIATED_STATIONS_TIMEOUT //超时后触发消息,关闭热点
修改:
case CMD_NO_ASSOCIATED_STATIONS_TIMEOUT:
break;这样永远就走不到关闭热点的逻辑
在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;
其实最好还是添加一个系统属性,可以动态设置是否自动关闭热点。
import android.os.SystemProperties;
//获取
boolean isSanitizeChannel = SystemProperties.getBoolean("persisit.hotspot_auto_close", false);
//设置
SystemProperties.set("key", bool + "");
从热点开启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;
}
}
}
从上面代码看重点是超时设置重点是看:
long timeout = mApConfig.getSoftApConfiguration().getShutdownTimeoutMillis();
if (timeout == 0) {
timeout = mDefaultShutDownTimeoutMills;
}
//(2)发送延时消息,成功打开热点会触发
//可以看到这里是当前时间+timeout时间,重点是研究timeout时间
mSoftApTimeoutMessage.schedule(SystemClock.elapsedRealtime()+ timeout);
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;
}
如果配置对象中没有设置数据的情况,那么就要看mDefaultShutDownTimeoutMills值了。
if (timeout == 0) {
timeout = mDefaultShutDownTimeoutMills;
}
还是 SoftApManager.java的代码
private long mDefaultShutDownTimeoutMills;
//构造方法中:
public SoftApManager (...) {
...
mDefaultShutDownTimeoutMills = mContext.getResources().getInteger(R.integer.config_wifiFrameworkSoftApShutDownTimeoutMilliseconds);
}
继续追config_wifiFrameworkSoftApShutDownTimeoutMilliseconds定义的文件:
frameworks\opt\net\wifi\service\res\values\config.xml
600000
所以 mDefaultShutDownTimeoutMills 的默认值是60000,600秒,即10分钟。
直接break;或者retrun;跳过后续关闭热点操作。
在资源配置文件中设置超时时间为永久:2147483647 (Int的最大数值)
2147483647
####(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());
}
有试过setShutdownTimeoutMillis 方法设置30 分钟的时间,发现过了30分钟没自动关闭!
具体原因,可以再源码中添加打印查看哈。
* 热点配置信息对象
* Android11 使用 WifiManager.setWifiApConfiguration(config); 已经过期,使用已经不能生效!
* 需要使用:WifiManager.setSoftApConfiguration(config);
具体实现可以看:
frameworks\opt\net\wifi\service\java\com\android\server\wifi\WifiServiceImpl.java
虽然最终都是调用:mWifiApConfigStore.setApConfiguration(softApConfig)
但是 setSoftApConfiguration 有更多的健全逻辑,比如:全局更新配置
mActiveModeWarden.updateSoftApConfiguration(softApConfig);
具体不做分析!