diff options
author | Jimmy Chen <jimmycmchen@google.com> | 2020-05-29 07:57:08 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2020-05-29 07:57:08 +0000 |
commit | e1273d71ef5e5b4615e02aabad0b770c90b4ba15 (patch) | |
tree | f45989268cd5be27472316aa1009ae1e220250f9 | |
parent | 81a23e98eb44199ac1bb7a77be2372d544b8a0ab (diff) | |
parent | 8ca6b95ba97672098cc2bffe9a99a52eaf7011ad (diff) |
Merge "wifi: Register for IMS network callbacks to delay disconnection." into rvc-dev
-rw-r--r-- | service/java/com/android/server/wifi/ClientModeManager.java | 99 | ||||
-rw-r--r-- | service/res/values/config.xml | 3 | ||||
-rw-r--r-- | service/res/values/overlayable.xml | 1 | ||||
-rw-r--r-- | tests/wifitests/src/com/android/server/wifi/ClientModeManagerTest.java | 59 |
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()); } |