summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJimmy Chen <jimmycmchen@google.com>2020-05-29 07:57:08 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2020-05-29 07:57:08 +0000
commite1273d71ef5e5b4615e02aabad0b770c90b4ba15 (patch)
treef45989268cd5be27472316aa1009ae1e220250f9
parent81a23e98eb44199ac1bb7a77be2372d544b8a0ab (diff)
parent8ca6b95ba97672098cc2bffe9a99a52eaf7011ad (diff)
Merge "wifi: Register for IMS network callbacks to delay disconnection." into rvc-dev
-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());
}