summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJimmy Chen <jimmycmchen@google.com>2020-05-12 19:12:27 +0530
committerJimmy Chen <jimmycmchen@google.com>2020-05-29 13:37:03 +0800
commit8ca6b95ba97672098cc2bffe9a99a52eaf7011ad (patch)
treeb4e65bfa11659057c6116049a83a1abf58c23500
parentc1ef8e0266f1b638e4af850d21798d0bce9fa791 (diff)
wifi: Register for IMS network callbacks to delay disconnection.
Wifi disconnect is required to be delayed when Wifi Calling is in progress and user turns off wifi. ClientModeManager registers for registerImsRegistrationCallback() but onUnregistered() callback is received even before IMS PDN is tear down. This commit is to monitor for IMS NetworkCallbacks and disconnects wifi only when onLost() indication is received. On receiving onLost() indication, add additional delay based on overlay option 'config_wifiDelayDisconnectOnImsLostMs' (default 0). This is to insure IMS PDN on modem is cleaned up. Additionally, check all Subscription IDs for active VoWifi call in progress. Bug: 143612699 Test: atest FrameworksWifiTests Signed-off-by: Purushottam Kushwaha <quic_pkushwah@quicinc.com> Change-Id: I6f2e6271e52a39b4f5115fc84727153e240f5a3b
-rw-r--r--service/java/com/android/server/wifi/ClientModeManager.java99
-rw-r--r--service/res/values/config.xml3
-rw-r--r--service/res/values/overlayable.xml1
-rw-r--r--tests/wifitests/src/com/android/server/wifi/ClientModeManagerTest.java59
4 files changed, 147 insertions, 15 deletions
diff --git a/service/java/com/android/server/wifi/ClientModeManager.java b/service/java/com/android/server/wifi/ClientModeManager.java
index 66495ae9e..61df5191b 100644
--- a/service/java/com/android/server/wifi/ClientModeManager.java
+++ b/service/java/com/android/server/wifi/ClientModeManager.java
@@ -19,6 +19,11 @@ package com.android.server.wifi;
import android.annotation.NonNull;
import android.content.Context;
import android.content.Intent;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.HandlerExecutor;
@@ -28,6 +33,7 @@ import android.os.PersistableBundle;
import android.os.UserHandle;
import android.telephony.AccessNetworkConstants;
import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.ims.ImsException;
@@ -45,9 +51,11 @@ import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import com.android.server.wifi.WifiNative.InterfaceCallback;
import com.android.server.wifi.util.WifiHandler;
+import com.android.wifi.resources.R;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.List;
/**
* Manager WiFi in Client Mode where we connect to configured networks.
@@ -71,6 +79,7 @@ public class ClientModeManager implements ActiveModeManager {
private @Role int mRole = ROLE_UNSPECIFIED;
private DeferStopHandler mDeferStopHandler;
private int mTargetRole = ROLE_UNSPECIFIED;
+ private int mActiveSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
ClientModeManager(Context context, @NonNull Looper looper, Clock clock, WifiNative wifiNative,
Listener listener, WifiMetrics wifiMetrics, SarManager sarManager,
@@ -120,6 +129,8 @@ public class ClientModeManager implements ActiveModeManager {
private final Runnable mRunnable = () -> continueToStopWifi();
private int mMaximumDeferringTimeMillis = 0;
private long mDeferringStartTimeMillis = 0;
+ private NetworkRequest mImsRequest = null;
+ private ConnectivityManager mConnectivityManager = null;
private RegistrationManager.RegistrationCallback mImsRegistrationCallback =
new RegistrationManager.RegistrationCallback() {
@@ -136,10 +147,40 @@ public class ClientModeManager implements ActiveModeManager {
@Override
public void onUnregistered(ImsReasonInfo imsReasonInfo) {
Log.d(TAG, "on IMS unregistered");
- if (mIsDeferring) continueToStopWifi();
+ // Wait for onLost in NetworkCallback
}
};
+ private NetworkCallback mImsNetworkCallback = new NetworkCallback() {
+ private int mRegisteredImsNetworkCount = 0;
+ @Override
+ public void onAvailable(Network network) {
+ synchronized (this) {
+ Log.d(TAG, "IMS network available: " + network);
+ mRegisteredImsNetworkCount++;
+ }
+ }
+
+ @Override
+ public void onLost(Network network) {
+ synchronized (this) {
+ Log.d(TAG, "IMS network lost: " + network
+ + " ,isDeferring: " + mIsDeferring
+ + " ,registered IMS network count: " + mRegisteredImsNetworkCount);
+ mRegisteredImsNetworkCount--;
+ if (mIsDeferring && mRegisteredImsNetworkCount <= 0) {
+ mRegisteredImsNetworkCount = 0;
+ // Add delay for targets where IMS PDN down at modem takes additional delay.
+ int delay = mContext.getResources()
+ .getInteger(R.integer.config_wifiDelayDisconnectOnImsLostMs);
+ if (delay == 0 || !postDelayed(mRunnable, delay)) {
+ continueToStopWifi();
+ }
+ }
+ }
+ }
+ };
+
DeferStopHandler(String tag, Looper looper) {
super(tag, looper);
mLooper = looper;
@@ -156,8 +197,7 @@ public class ClientModeManager implements ActiveModeManager {
return;
}
- mImsMmTelManager = ImsMmTelManager.createForSubscriptionId(
- SubscriptionManager.getDefaultVoiceSubscriptionId());
+ mImsMmTelManager = ImsMmTelManager.createForSubscriptionId(mActiveSubId);
if (mImsMmTelManager == null || !postDelayed(mRunnable, delayMs)) {
// if no delay or failed to add runnable, stop Wifi immediately.
continueToStopWifi();
@@ -166,7 +206,7 @@ public class ClientModeManager implements ActiveModeManager {
mIsDeferring = true;
Log.d(TAG, "Start DeferWifiOff handler with deferring time "
- + delayMs + " ms.");
+ + delayMs + " ms for subId: " + mActiveSubId);
try {
mImsMmTelManager.registerImsRegistrationCallback(
new HandlerExecutor(new Handler(mLooper)),
@@ -174,7 +214,19 @@ public class ClientModeManager implements ActiveModeManager {
} catch (RuntimeException | ImsException e) {
Log.e(TAG, "registerImsRegistrationCallback failed", e);
continueToStopWifi();
+ return;
}
+
+ mImsRequest = new NetworkRequest.Builder()
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .build();
+
+ mConnectivityManager =
+ (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+
+ mConnectivityManager.registerNetworkCallback(mImsRequest, mImsNetworkCallback,
+ new Handler(mLooper));
}
private void continueToStopWifi() {
@@ -212,6 +264,11 @@ public class ClientModeManager implements ActiveModeManager {
Log.e(TAG, "unregisterImsRegistrationCallback failed", e);
}
}
+
+ if (mConnectivityManager != null) {
+ mConnectivityManager.unregisterNetworkCallback(mImsNetworkCallback);
+ }
+
mIsDeferring = false;
}
}
@@ -220,13 +277,35 @@ public class ClientModeManager implements ActiveModeManager {
* Get deferring time before turning off WiFi.
*/
private int getWifiOffDeferringTimeMs() {
- int defaultVoiceSubId = SubscriptionManager.getDefaultVoiceSubscriptionId();
- if (defaultVoiceSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ SubscriptionManager subscriptionManager = (SubscriptionManager) mContext.getSystemService(
+ Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+ if (subscriptionManager == null) {
+ return 0;
+ }
+
+ List<SubscriptionInfo> subInfoList = subscriptionManager.getActiveSubscriptionInfoList();
+ if (subInfoList == null) {
+ return 0;
+ }
+
+ // Get the maximum delay for the active subscription latched on IWLAN.
+ int maxDelay = 0;
+ for (SubscriptionInfo subInfo : subInfoList) {
+ int curDelay = getWifiOffDeferringTimeMs(subInfo.getSubscriptionId());
+ if (curDelay > maxDelay) {
+ maxDelay = curDelay;
+ mActiveSubId = subInfo.getSubscriptionId();
+ }
+ }
+ return maxDelay;
+ }
+
+ private int getWifiOffDeferringTimeMs(int subId) {
+ if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
return 0;
}
- ImsMmTelManager imsMmTelManager = ImsMmTelManager.createForSubscriptionId(
- defaultVoiceSubId);
+ ImsMmTelManager imsMmTelManager = ImsMmTelManager.createForSubscriptionId(subId);
// If no wifi calling, no delay
if (!imsMmTelManager.isAvailable(
MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
@@ -236,7 +315,7 @@ public class ClientModeManager implements ActiveModeManager {
TelephonyManager defaultVoiceTelephonyManager =
mContext.getSystemService(TelephonyManager.class)
- .createForSubscriptionId(defaultVoiceSubId);
+ .createForSubscriptionId(subId);
// if LTE is available, no delay needed as IMS will be registered over LTE
if (defaultVoiceTelephonyManager.getVoiceNetworkType()
== TelephonyManager.NETWORK_TYPE_LTE) {
@@ -245,7 +324,7 @@ public class ClientModeManager implements ActiveModeManager {
CarrierConfigManager configManager =
(CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
- PersistableBundle config = configManager.getConfigForSubId(defaultVoiceSubId);
+ PersistableBundle config = configManager.getConfigForSubId(subId);
return (config != null)
? config.getInt(CarrierConfigManager.Ims.KEY_WIFI_OFF_DEFERRING_TIME_MILLIS_INT)
: 0;
diff --git a/service/res/values/config.xml b/service/res/values/config.xml
index 4451f7c12..881373807 100644
--- a/service/res/values/config.xml
+++ b/service/res/values/config.xml
@@ -430,4 +430,7 @@
The scan interval backs off from this initial interval on subsequent scans.
This scan is performed when screen is off and disconnected. -->
<integer translatable="false" name="config_wifiStationaryPnoScanIntervalMillis">60000</integer>
+
+ <!-- integer indicating additional disconnect delay (in ms) after IMS onLost() indication is received -->
+ <integer translatable="false" name="config_wifiDelayDisconnectOnImsLostMs">0</integer>
</resources>
diff --git a/service/res/values/overlayable.xml b/service/res/values/overlayable.xml
index 9e0a18d7d..7b77da512 100644
--- a/service/res/values/overlayable.xml
+++ b/service/res/values/overlayable.xml
@@ -133,6 +133,7 @@
<item type="bool" name="config_wifiSoftapAcsIncludeDfs" />
<item type="integer" name="config_wifiMovingPnoScanIntervalMillis" />
<item type="integer" name="config_wifiStationaryPnoScanIntervalMillis" />
+ <item type="integer" name="config_wifiDelayDisconnectOnImsLostMs" />
<!-- Params from config.xml that can be overlayed -->
<!-- Params from strings.xml that can be overlayed -->
diff --git a/tests/wifitests/src/com/android/server/wifi/ClientModeManagerTest.java b/tests/wifitests/src/com/android/server/wifi/ClientModeManagerTest.java
index 182e8e4f8..b733ec0ac 100644
--- a/tests/wifitests/src/com/android/server/wifi/ClientModeManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/ClientModeManagerTest.java
@@ -40,11 +40,16 @@ import static org.mockito.Mockito.lenient;
import android.app.test.MockAnswerUtil.AnswerWithArguments;
import android.content.Context;
import android.content.Intent;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.NetworkRequest;
+import android.os.Handler;
import android.os.PersistableBundle;
import android.os.UserHandle;
import android.os.test.TestLooper;
import android.telephony.AccessNetworkConstants;
import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.ims.ImsMmTelManager;
@@ -52,6 +57,8 @@ import android.telephony.ims.RegistrationManager;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
+import com.android.wifi.resources.R;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -61,6 +68,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.MockitoSession;
+import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
@@ -73,6 +81,7 @@ public class ClientModeManagerTest extends WifiBaseTest {
private static final String TEST_INTERFACE_NAME = "testif0";
private static final String OTHER_INTERFACE_NAME = "notTestIf";
private static final int TEST_WIFI_OFF_DEFERRING_TIME_MS = 4000;
+ private static final int TEST_ACTIVE_SUBSCRIPTION_ID = 1;
TestLooper mLooper;
@@ -90,12 +99,20 @@ public class ClientModeManagerTest extends WifiBaseTest {
@Mock CarrierConfigManager mCarrierConfigManager;
@Mock PersistableBundle mCarrierConfigBundle;
@Mock ImsMmTelManager mImsMmTelManager;
+ @Mock ConnectivityManager mConnectivityManager;
+ @Mock SubscriptionManager mSubscriptionManager;
+ @Mock SubscriptionInfo mActiveSubscriptionInfo;
private RegistrationManager.RegistrationCallback mImsMmTelManagerRegistrationCallback = null;
private @RegistrationManager.ImsRegistrationState int mCurrentImsRegistrationState =
RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED;
private @AccessNetworkConstants.TransportType int mCurrentImsConnectionType =
AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
+ private NetworkRequest mImsRequest = null;
+ private NetworkCallback mImsNetworkCallback = null;
+ private Handler mImsNetworkCallbackHandler = null;
private long mElapsedSinceBootMillis = 0L;
+ private List<SubscriptionInfo> mSubscriptionInfoList = new ArrayList<>();
+ private MockResources mResources;
private MockitoSession mStaticMockSession = null;
@@ -110,6 +127,11 @@ public class ClientModeManagerTest extends WifiBaseTest {
when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
.thenReturn(mCarrierConfigManager);
+ when(mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE))
+ .thenReturn(mSubscriptionManager);
+ when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE))
+ .thenReturn(mConnectivityManager);
+ when(mContext.getResources()).thenReturn(mResources);
}
/*
@@ -124,6 +146,12 @@ public class ClientModeManagerTest extends WifiBaseTest {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+
+ // Prepare data
+ mResources = new MockResources();
+ mResources.setInteger(R.integer.config_wifiDelayDisconnectOnImsLostMs, 0);
+ mSubscriptionInfoList.add(mActiveSubscriptionInfo);
+
setUpSystemServiceForContext();
/**
@@ -136,11 +164,9 @@ public class ClientModeManagerTest extends WifiBaseTest {
.mockStatic(ImsMmTelManager.class)
.mockStatic(SubscriptionManager.class)
.startMocking();
- lenient().when(ImsMmTelManager.createForSubscriptionId(anyInt()))
+ lenient().when(ImsMmTelManager.createForSubscriptionId(eq(TEST_ACTIVE_SUBSCRIPTION_ID)))
.thenReturn(mImsMmTelManager);
- lenient().when(SubscriptionManager.getDefaultVoiceSubscriptionId())
- .thenReturn(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
- lenient().when(SubscriptionManager.isValidSubscriptionId(anyInt()))
+ lenient().when(SubscriptionManager.isValidSubscriptionId(eq(TEST_ACTIVE_SUBSCRIPTION_ID)))
.thenReturn(true);
doAnswer(new AnswerWithArguments() {
public void answer(Executor executor, RegistrationManager.RegistrationCallback c) {
@@ -169,7 +195,11 @@ public class ClientModeManagerTest extends WifiBaseTest {
any(RegistrationManager.RegistrationCallback.class));
when(mImsMmTelManager.isAvailable(anyInt(), anyInt())).thenReturn(false);
- when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
+ when(mActiveSubscriptionInfo.getSubscriptionId()).thenReturn(TEST_ACTIVE_SUBSCRIPTION_ID);
+ when(mSubscriptionManager.getActiveSubscriptionInfoList())
+ .thenReturn(mSubscriptionInfoList);
+ when(mTelephonyManager.createForSubscriptionId(eq(TEST_ACTIVE_SUBSCRIPTION_ID)))
+ .thenReturn(mTelephonyManager);
when(mTelephonyManager.getVoiceNetworkType())
.thenReturn(TelephonyManager.NETWORK_TYPE_UNKNOWN);
when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(mCarrierConfigBundle);
@@ -177,6 +207,18 @@ public class ClientModeManagerTest extends WifiBaseTest {
.getInt(eq(CarrierConfigManager.Ims.KEY_WIFI_OFF_DEFERRING_TIME_MILLIS_INT)))
.thenReturn(0);
doAnswer(new AnswerWithArguments() {
+ public void answer(NetworkRequest req, NetworkCallback callback, Handler handler) {
+ mImsRequest = req;
+ mImsNetworkCallback = callback;
+ mImsNetworkCallbackHandler = handler;
+ }
+ }).when(mConnectivityManager).registerNetworkCallback(any(), any(), any());
+ doAnswer(new AnswerWithArguments() {
+ public void answer(NetworkCallback callback) {
+ if (mImsNetworkCallback == callback) mImsNetworkCallback = null;
+ }
+ }).when(mConnectivityManager).unregisterNetworkCallback(any(NetworkCallback.class));
+ doAnswer(new AnswerWithArguments() {
public long answer() {
return mElapsedSinceBootMillis;
}
@@ -369,6 +411,7 @@ public class ClientModeManagerTest extends WifiBaseTest {
ClientModeImpl.SCAN_ONLY_MODE, TEST_INTERFACE_NAME);
verify(mSarManager, times(2)).setScanOnlyWifiState(WIFI_STATE_ENABLED);
+ verify(mContext).getSystemService(anyString());
verify(mImsMmTelManager, never()).registerImsRegistrationCallback(any(), any());
verify(mImsMmTelManager, never()).unregisterImsRegistrationCallback(any());
@@ -686,12 +729,15 @@ public class ClientModeManagerTest extends WifiBaseTest {
// Notify wifi service IMS service is de-registered.
assertNotNull(mImsMmTelManagerRegistrationCallback);
mImsMmTelManagerRegistrationCallback.onUnregistered(null);
+ assertNotNull(mImsNetworkCallback);
+ mImsNetworkCallback.onLost(null);
mLooper.dispatchAll();
// Now Wifi could be turned off actually.
verify(mImsMmTelManager).unregisterImsRegistrationCallback(
any(RegistrationManager.RegistrationCallback.class));
assertNull(mImsMmTelManagerRegistrationCallback);
+ assertNull(mImsNetworkCallback);
verify(mListener).onStopped();
verify(mWifiMetrics).noteWifiOff(eq(true), eq(false), anyInt());
@@ -1003,6 +1049,8 @@ public class ClientModeManagerTest extends WifiBaseTest {
// Notify wifi service IMS service is de-registered.
assertNotNull(mImsMmTelManagerRegistrationCallback);
mImsMmTelManagerRegistrationCallback.onUnregistered(null);
+ assertNotNull(mImsNetworkCallback);
+ mImsNetworkCallback.onLost(null);
mLooper.dispatchAll();
// Now Wifi could be switched to scan mode actually.
@@ -1010,6 +1058,7 @@ public class ClientModeManagerTest extends WifiBaseTest {
verify(mImsMmTelManager).unregisterImsRegistrationCallback(
any(RegistrationManager.RegistrationCallback.class));
assertNull(mImsMmTelManagerRegistrationCallback);
+ assertNull(mImsNetworkCallback);
verify(mWifiMetrics).noteWifiOff(eq(true), eq(false), anyInt());
}