正常逻辑:热点再没有连接的情况下,一段时间后会自动关闭
需求:启动热点后,保持热点长连接,不会自动关闭
思路:通过关闭热点函数,反向寻找 关闭热点的位置。
具体实现:
路径:Frameworks/opt/net/wifi/service/java/com/mediatek/server/wifi/MtkSoftApManager.java
关键点:
- getValue() //是否开启超时功能
- getConfigSoftApTimeoutDelay() //获取超时限制的时间
- CMD_NO_ASSOCIATED_STATIONS_TIMEOUT //超时后触发消息,关闭热点
我是偷懒,直接在消息触发后直接 break;这样永远就走不到关闭热点的逻辑
以下是热点开关的主要逻辑:
private class StartedState extends State {
private int mTimeoutDelay; //设置自动关闭热点时间
private WakeupMessage mSoftApTimeoutMessage;
private SoftApTimeoutEnabledSettingObserver mSettingObserver;
/**
* Observer for timeout settings changes.
*/
private class SoftApTimeoutEnabledSettingObserver extends ContentObserver {
SoftApTimeoutEnabledSettingObserver(Handler handler) {
super(handler);
}
public void register() {
mFrameworkFacade.registerContentObserver(mContext,
Settings.Global.getUriFor(Settings.Global.SOFT_AP_TIMEOUT_ENABLED),
true, this);
mTimeoutEnabled = getValue();//是否启用热点超时关闭功能
}
public void unregister() {
mFrameworkFacade.unregisterContentObserver(mContext, this);
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
mStateMachine.sendMessage(SoftApStateMachine.CMD_TIMEOUT_TOGGLE_CHANGED,
getValue() ? 1 : 0);
}
private boolean getValue() {
boolean enabled = mFrameworkFacade.getIntegerSetting(mContext,
Settings.Global.SOFT_AP_TIMEOUT_ENABLED, 1) == 1;
return enabled;
}
}
private int getConfigSoftApTimeoutDelay() {
int delay = mContext.getResources().getInteger(
R.integer.config_wifi_framework_soft_ap_timeout_delay);
if (delay < MIN_SOFT_AP_TIMEOUT_DELAY_MS) {
delay = MIN_SOFT_AP_TIMEOUT_DELAY_MS;
Log.w(TAG, "Overriding timeout delay with minimum limit value");
}
Log.d(TAG, "Timeout delay: " + delay);
return delay; //返回timeout时间(默认10min)
}
private void scheduleTimeoutMessage() {
if (!mTimeoutEnabled) {
return;
}
mSoftApTimeoutMessage.schedule(SystemClock.elapsedRealtime() + mTimeoutDelay);
Log.d(TAG, "Timeout message scheduled");
}
private void cancelTimeoutMessage() {
mSoftApTimeoutMessage.cancel();
Log.d(TAG, "Timeout message canceled");
}
/**
* Set number of stations associated with this soft AP
* @param numStations Number of connected stations
*/
private void setNumAssociatedStations(int numStations) {
if (mNumAssociatedStations == numStations) {
return;
}
mNumAssociatedStations = numStations;
Log.d(TAG, "Number of associated stations changed: " + mNumAssociatedStations);
if (mCallback != null) {
mCallback.onNumClientsChanged(mNumAssociatedStations);
} else {
Log.e(TAG, "SoftApCallback is null. Dropping NumClientsChanged event.");
}
mWifiMetrics.addSoftApNumAssociatedStationsChangedEvent(mNumAssociatedStations,
mMode);
if (mNumAssociatedStations == 0) {
scheduleTimeoutMessage();
} else {
cancelTimeoutMessage();
}
}
private void onUpChanged(boolean isUp) {
if (isUp == mIfaceIsUp) {
return; // no change
}
mIfaceIsUp = isUp;
if (isUp) {
Log.d(TAG, "SoftAp is ready for use");
updateApState(WifiManager.WIFI_AP_STATE_ENABLED,
WifiManager.WIFI_AP_STATE_ENABLING, 0);
mWifiMetrics.incrementSoftApStartResult(true, 0);
if (mCallback != null) {
mCallback.onNumClientsChanged(mNumAssociatedStations);
}
} else {
// the interface was up, but goes down
sendMessage(CMD_INTERFACE_DOWN);
}
mWifiMetrics.addSoftApUpChangedEvent(isUp, mMode);
}
@Override
public void enter() {
mIfaceIsUp = false;
onUpChanged(mWifiNative.isInterfaceUp(mApInterfaceName));
mTimeoutDelay = getConfigSoftApTimeoutDelay();
Handler handler = mStateMachine.getHandler();
mSoftApTimeoutMessage = new WakeupMessage(mContext, handler,
SOFT_AP_SEND_MESSAGE_TIMEOUT_TAG,
SoftApStateMachine.CMD_NO_ASSOCIATED_STATIONS_TIMEOUT);
mSettingObserver = new SoftApTimeoutEnabledSettingObserver(handler);
if (mSettingObserver != null) {
mSettingObserver.register();
}
Log.d(TAG, "Resetting num stations on start");
mNumAssociatedStations = 0;
scheduleTimeoutMessage();
// M: STA+SAP
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
mContext.registerReceiver(mWifiP2pReceiver, intentFilter);
}
@Override
public void exit() {
if (mApInterfaceName != null) {
stopSoftAp();
}
if (mSettingObserver != null) {
mSettingObserver.unregister();
}
Log.d(TAG, "Resetting num stations on stop");
mNumAssociatedStations = 0;
cancelTimeoutMessage();
// Need this here since we are exiting |Started| state and won't handle any
// future CMD_INTERFACE_STATUS_CHANGED events after this point
mWifiMetrics.addSoftApUpChangedEvent(false, mMode);
updateApState(WifiManager.WIFI_AP_STATE_DISABLED,
WifiManager.WIFI_AP_STATE_DISABLING, 0);
// M: Wi-Fi Hotspot Manager
MtkWifiApMonitor.deregisterAllHandler();
MtkWifiApMonitor.stopMonitoring(mApInterfaceName);
synchronized (mHotspotClients) {
mHotspotClients.clear();
}
sendClientsChangedBroadcast();
// M: STA+SAP
mContext.unregisterReceiver(mWifiP2pReceiver);
mApInterfaceName = null;
mIfaceIsUp = false;
mStateMachine.quitNow();
}
@Override
public boolean processMessage(Message message) {
switch (message.what) {
case CMD_NUM_ASSOCIATED_STATIONS_CHANGED:
if (message.arg1 < 0) {
Log.e(TAG, "Invalid number of associated stations: " + message.arg1);
break;
}
Log.d(TAG, "Setting num stations on CMD_NUM_ASSOCIATED_STATIONS_CHANGED");
setNumAssociatedStations(message.arg1);
break;
case CMD_SOFT_AP_CHANNEL_SWITCHED:
mReportedFrequency = message.arg1;
mReportedBandwidth = message.arg2;
Log.d(TAG, "Channel switched. Frequency: " + mReportedFrequency
+ " Bandwidth: " + mReportedBandwidth);
mWifiMetrics.addSoftApChannelSwitchedEvent(mReportedFrequency,
mReportedBandwidth, mMode);
int[] allowedChannels = new int[0];
if (mApConfig.apBand == WifiConfiguration.AP_BAND_2GHZ) {
allowedChannels =
mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_24_GHZ);
} else if (mApConfig.apBand == WifiConfiguration.AP_BAND_5GHZ) {
allowedChannels =
mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ);
} else if (mApConfig.apBand == WifiConfiguration.AP_BAND_ANY) {
int[] allowed2GChannels =
mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_24_GHZ);
int[] allowed5GChannels =
mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ);
allowedChannels = Stream.concat(
Arrays.stream(allowed2GChannels).boxed(),
Arrays.stream(allowed5GChannels).boxed())
.mapToInt(Integer::valueOf)
.toArray();
}
if (!ArrayUtils.contains(allowedChannels, mReportedFrequency)) {
Log.e(TAG, "Channel does not satisfy user band preference: "
+ mReportedFrequency);
mWifiMetrics.incrementNumSoftApUserBandPreferenceUnsatisfied();
}
break;
case CMD_TIMEOUT_TOGGLE_CHANGED:
boolean isEnabled = (message.arg1 == 1);
if (mTimeoutEnabled == isEnabled) {
break;
}
mTimeoutEnabled = isEnabled;
if (!mTimeoutEnabled) {
cancelTimeoutMessage();
}
if (mTimeoutEnabled && mNumAssociatedStations == 0) {
scheduleTimeoutMessage();
}
break;
case CMD_INTERFACE_STATUS_CHANGED:
boolean isUp = message.arg1 == 1;
onUpChanged(isUp);
break;
case CMD_START:
// Already started, ignore this command.
break;
case CMD_NO_ASSOCIATED_STATIONS_TIMEOUT:
//偷懒直接break
//*/Timeout wifi_ap is disabled
if(true) {
Log.d(TAG, "cancel wifi soft AP timeout disable.");
break;
}
//*/
if (!mTimeoutEnabled) {
Log.wtf(TAG, "Timeout message received while timeout is disabled."
+ " Dropping.");
break;
}
if (mNumAssociatedStations != 0) {
Log.wtf(TAG, "Timeout message received but has clients. Dropping.");
break;
}
Log.i(TAG, "Timeout message received. Stopping soft AP.");
updateApState(WifiManager.WIFI_AP_STATE_DISABLING,
WifiManager.WIFI_AP_STATE_ENABLED, 0);
transitionTo(mIdleState);
break;
case CMD_INTERFACE_DESTROYED:
Log.d(TAG, "Interface was cleanly destroyed.");
updateApState(WifiManager.WIFI_AP_STATE_DISABLING,
WifiManager.WIFI_AP_STATE_ENABLED, 0);
mApInterfaceName = null;
transitionTo(mIdleState);
break;
case CMD_INTERFACE_DOWN:
Log.w(TAG, "interface error, stop and report failure");
updateApState(WifiManager.WIFI_AP_STATE_FAILED,
WifiManager.WIFI_AP_STATE_ENABLED,
WifiManager.SAP_START_FAILURE_GENERAL);
updateApState(WifiManager.WIFI_AP_STATE_DISABLING,
WifiManager.WIFI_AP_STATE_FAILED, 0);
transitionTo(mIdleState);
break;
// M: Wi-Fi Hotspot Manager
case CMD_POLL_IP_ADDRESS:
String deviceAddress = (String) message.obj;
int count = message.arg1;
String ipAddress =
mWifiManager.getWifiHotspotManager().getClientIp(deviceAddress);
String deviceName =
mWifiManager.getWifiHotspotManager().getClientDeviceName(deviceAddress);
Log.d(TAG, "CMD_POLL_IP_ADDRESS ,deviceAddress = " +
message.obj + " ipAddress = " + ipAddress + ", count = " + count);
if (ipAddress == null && count < POLL_IP_TIMES) {
sendMessageDelayed(CMD_POLL_IP_ADDRESS, ++count, 0, deviceAddress,
POLL_IP_ADDRESS_INTERVAL_MSECS);
} else if (ipAddress != null) {
sendClientsIpReadyBroadcast(deviceAddress, ipAddress, deviceName);
}
break;
case MtkWifiApMonitor.AP_STA_CONNECTED_EVENT:
Log.d(TAG, "AP STA CONNECTED:" + message.obj);
String address = (String) message.obj;
synchronized (mHotspotClients) {
if (!mHotspotClients.containsKey(address)) {
mHotspotClients.put(address, new HotspotClient(address, false));
}
}
int start = 1;
sendMessageDelayed(CMD_POLL_IP_ADDRESS, start, 0, address,
POLL_IP_ADDRESS_INTERVAL_MSECS);
sendClientsChangedBroadcast();
break;
case MtkWifiApMonitor.AP_STA_DISCONNECTED_EVENT:
Log.d(TAG, "AP STA DISCONNECTED:" + message.obj);
address = (String) message.obj;
synchronized (mHotspotClients) {
HotspotClient client = mHotspotClients.get(address);
if (client != null && !client.isBlocked) {
mHotspotClients.remove(address);
}
}
sendClientsChangedBroadcast();
break;
default:
return NOT_HANDLED;
}
return HANDLED;
}
}
Dear Vistor:
感谢大家,如有更好的建议,留言哈。