diff options
author | Roshan Pius <rpius@google.com> | 2017-07-07 09:34:08 -0700 |
---|---|---|
committer | Roshan Pius <rpius@google.com> | 2017-07-13 08:36:53 -0700 |
commit | ec0922425c007ba22527e0cacad1445d5f0d0ad8 (patch) | |
tree | a2a3e1c5d7b2acc2093ed257f1c8f285ac2da95f | |
parent | 80f9ea680d1fc7a2e343c8b5df0505cca5c3bc7f (diff) |
WifiStateMachine: Set Tx power limits during calls
Listen to telephony's call state change events so that we can set/reset
the tx power level to meet SAR requirements in STA mode.
a) When the call is in progress (OFFHOOK), set the tx power limit to
specified level.
b) When the call is done (IDLE), reset the tx power limit (will fallback
to default).
The set/reset is sent to the driver using the 2 new HIDL API's added to
the 1.1 wifi HAL package.
Also, this is an optional feature and we don't need to this unless the
|config_wifi_framework_enable_sar_tx_power_limit| is set on the device.
Bug: 62437848
Test: Manual tests.
Test: Unit tests to be added.
Change-Id: I990f867ce045dfc5f18833afdc9168ec10d929fa
-rw-r--r-- | service/java/com/android/server/wifi/WifiStateMachine.java | 71 | ||||
-rw-r--r-- | tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java | 178 |
2 files changed, 236 insertions, 13 deletions
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java index c58f83b74..183f32ff0 100644 --- a/service/java/com/android/server/wifi/WifiStateMachine.java +++ b/service/java/com/android/server/wifi/WifiStateMachine.java @@ -26,6 +26,8 @@ import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING; import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING; import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN; +import static android.telephony.TelephonyManager.CALL_STATE_IDLE; +import static android.telephony.TelephonyManager.CALL_STATE_OFFHOOK; import android.Manifest; import android.app.ActivityManager; @@ -93,6 +95,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.WorkSource; import android.provider.Settings; +import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; @@ -729,6 +732,12 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss /* Indicates that diagnostics should time out a connection start event. */ private static final int CMD_DIAGS_CONNECT_TIMEOUT = BASE + 252; + /* Used to set the tx power limit for SAR during the start of a phone call. */ + private static final int CMD_SET_SAR_TX_POWER_LIMIT = BASE + 253; + + /* Used to reset the tx power limit for SAR at end of a phone call. */ + private static final int CMD_RESET_SAR_TX_POWER_LIMIT = BASE + 254; + // For message logging. private static final Class[] sMessageClasses = { AsyncChannel.class, WifiStateMachine.class, DhcpClient.class }; @@ -786,6 +795,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss private final boolean mEnableLinkDebouncing; private final boolean mEnableChipWakeUpWhenAssociated; private final boolean mEnableRssiPollWhenAssociated; + private final boolean mEnableVoiceCallSarTxPowerLimit; + private final int mVoiceCallSarTxPowerLimitInDbm; int mRunningBeaconCount = 0; @@ -875,6 +886,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss } return mTelephonyManager; } + private final WifiPhoneStateListener mPhoneStateListener; private final IBatteryStats mBatteryStats; @@ -928,6 +940,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss mFacade.makeSupplicantStateTracker(context, mWifiConfigManager, getHandler()); mLinkProperties = new LinkProperties(); + mPhoneStateListener = new WifiPhoneStateListener(); mNetworkInfo.setIsAvailable(false); mLastBssid = null; @@ -1025,6 +1038,10 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz); mEnableLinkDebouncing = mContext.getResources().getBoolean( R.bool.config_wifi_enable_disconnection_debounce); + mEnableVoiceCallSarTxPowerLimit = mContext.getResources().getBoolean( + R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit); + mVoiceCallSarTxPowerLimitInDbm = mContext.getResources().getInteger( + R.integer.config_wifi_framework_voice_call_sar_tx_power_limit_in_dbm); mEnableChipWakeUpWhenAssociated = true; mEnableRssiPollWhenAssociated = true; @@ -3733,6 +3750,34 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss } } + /** + * Register the phone listener if we need to set/reset the power limits during voice call for + * this device. + */ + private void maybeRegisterPhoneListener() { + if (mEnableVoiceCallSarTxPowerLimit) { + logd("Registering for telephony call state changes"); + getTelephonyManager().listen( + mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); + } + } + + /** + * Listen for phone call state events to set/reset TX power limits for SAR requirements. + */ + private class WifiPhoneStateListener extends PhoneStateListener { + @Override + public void onCallStateChanged(int state, String incomingNumber) { + if (mEnableVoiceCallSarTxPowerLimit) { + if (state == CALL_STATE_OFFHOOK) { + sendMessage(CMD_SET_SAR_TX_POWER_LIMIT, mVoiceCallSarTxPowerLimitInDbm); + } else if (state == CALL_STATE_IDLE) { + sendMessage(CMD_RESET_SAR_TX_POWER_LIMIT); + } + } + } + } + /******************************************************** * HSM states *******************************************************/ @@ -3835,6 +3880,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss Log.e(TAG, "Failed to load from config store"); } maybeRegisterNetworkFactory(); + maybeRegisterPhoneListener(); break; case CMD_SCREEN_STATE_CHANGED: handleScreenStateChanged(message.arg1 != 0); @@ -3884,6 +3930,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss case CMD_ROAM_WATCHDOG_TIMER: case CMD_DISABLE_P2P_WATCHDOG_TIMER: case CMD_DISABLE_EPHEMERAL_NETWORK: + case CMD_SET_SAR_TX_POWER_LIMIT: + case CMD_RESET_SAR_TX_POWER_LIMIT: messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; break; case CMD_SET_SUSPEND_OPT_ENABLED: @@ -4272,6 +4320,16 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss * driver are changed to reduce interference with bluetooth */ mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); + // Check if there is a voice call on-going and set/reset the tx power limit + // appropriately. + if (mEnableVoiceCallSarTxPowerLimit) { + if (getTelephonyManager().isOffhook()) { + sendMessage(CMD_SET_SAR_TX_POWER_LIMIT, mVoiceCallSarTxPowerLimitInDbm); + } else if (getTelephonyManager().isIdle()) { + sendMessage(CMD_RESET_SAR_TX_POWER_LIMIT); + } + } + // initialize network state setNetworkDetailedState(DetailedState.DISCONNECTED); @@ -4453,6 +4511,19 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss mWifiConnectivityManager.forceConnectivityScan(); } break; + case CMD_SET_SAR_TX_POWER_LIMIT: + int txPowerLevelInDbm = message.arg1; + logd("Setting Tx power limit to " + txPowerLevelInDbm); + if (!mWifiNative.setTxPowerLimit(txPowerLevelInDbm)) { + loge("Failed to set TX power limit"); + } + break; + case CMD_RESET_SAR_TX_POWER_LIMIT: + logd("Resetting Tx power limit"); + if (!mWifiNative.resetTxPowerLimit()) { + loge("Failed to reset TX power limit"); + } + break; default: return NOT_HANDLED; } diff --git a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java index 4568b743e..52b4d3687 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java @@ -30,6 +30,7 @@ import static com.android.server.wifi.LocalOnlyHotspotRequestInfo.HOTSPOT_NO_ERR import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.*; @@ -41,7 +42,6 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.UserInfo; -import android.content.res.Resources; import android.net.ConnectivityManager; import android.net.DhcpResults; import android.net.LinkProperties; @@ -80,6 +80,8 @@ import android.os.UserManager; import android.os.test.TestLooper; import android.provider.Settings; import android.security.KeyStore; +import android.telephony.PhoneStateListener; +import android.telephony.TelephonyManager; import android.test.mock.MockContentProvider; import android.test.mock.MockContentResolver; import android.test.suitebuilder.annotation.SmallTest; @@ -202,9 +204,6 @@ public class WifiStateMachineTest { Context context = mock(Context.class); when(context.getPackageManager()).thenReturn(pkgMgr); - MockResources resources = new com.android.server.wifi.MockResources(); - when(context.getResources()).thenReturn(resources); - MockContentResolver mockContentResolver = new MockContentResolver(); mockContentResolver.addProvider(Settings.AUTHORITY, new MockContentProvider(context) { @@ -228,9 +227,11 @@ public class WifiStateMachineTest { return context; } - private Resources getMockResources() { + private MockResources getMockResources() { MockResources resources = new MockResources(); resources.setBoolean(R.bool.config_wifi_enable_wifi_firmware_debugging, false); + resources.setBoolean( + R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit, false); return resources; } @@ -310,7 +311,10 @@ public class WifiStateMachineTest { MockWifiMonitor mWifiMonitor; TestLooper mLooper; Context mContext; + MockResources mResources; + FrameworkFacade mFrameworkFacade; IpManager.Callback mIpManagerCallback; + PhoneStateListener mPhoneStateListener; final ArgumentCaptor<SoftApManager.Listener> mSoftApManagerListenerCaptor = ArgumentCaptor.forClass(SoftApManager.Listener.class); @@ -339,6 +343,7 @@ public class WifiStateMachineTest { @Mock PasspointManager mPasspointManager; @Mock SelfRecovery mSelfRecovery; @Mock IpManager mIpManager; + @Mock TelephonyManager mTelephonyManager; public WifiStateMachineTest() throws Exception { } @@ -379,6 +384,7 @@ public class WifiStateMachineTest { when(mWifiInjector.getWifiMonitor()).thenReturn(mWifiMonitor); when(mWifiInjector.getWifiNative()).thenReturn(mWifiNative); when(mWifiInjector.getSelfRecovery()).thenReturn(mSelfRecovery); + when(mWifiInjector.makeTelephonyManager()).thenReturn(mTelephonyManager); when(mWifiNative.setupForClientMode()) .thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, mClientInterface)); @@ -391,21 +397,21 @@ public class WifiStateMachineTest { when(mWifiNative.getFrameworkNetworkId(anyInt())).thenReturn(0); - FrameworkFacade factory = getFrameworkFacade(); + mFrameworkFacade = getFrameworkFacade(); mContext = getContext(); - Resources resources = getMockResources(); - when(mContext.getResources()).thenReturn(resources); + mResources = getMockResources(); + when(mContext.getResources()).thenReturn(mResources); - when(factory.getIntegerSetting(mContext, + when(mFrameworkFacade.getIntegerSetting(mContext, Settings.Global.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO)).thenReturn( WifiManager.WIFI_FREQUENCY_BAND_AUTO); - when(factory.makeApConfigStore(eq(mContext), eq(mBackupManagerProxy))) + when(mFrameworkFacade.makeApConfigStore(eq(mContext), eq(mBackupManagerProxy))) .thenReturn(mApConfigStore); - when(factory.makeSupplicantStateTracker( + when(mFrameworkFacade.makeSupplicantStateTracker( any(Context.class), any(WifiConfigManager.class), any(Handler.class))).thenReturn(mSupplicantStateTracker); @@ -418,8 +424,19 @@ public class WifiStateMachineTest { when(mApInterface.asBinder()).thenReturn(mApInterfaceBinder); when(mClientInterface.asBinder()).thenReturn(mClientInterfaceBinder); - mWsm = new WifiStateMachine(mContext, factory, mLooper.getLooper(), - mUserManager, mWifiInjector, mBackupManagerProxy, mCountryCode, mWifiNative); + doAnswer(new AnswerWithArguments() { + public void answer(PhoneStateListener phoneStateListener, int events) + throws Exception { + mPhoneStateListener = phoneStateListener; + } + }).when(mTelephonyManager).listen(any(PhoneStateListener.class), anyInt()); + + initializeWsm(); + } + + private void initializeWsm() throws Exception { + mWsm = new WifiStateMachine(mContext, mFrameworkFacade, mLooper.getLooper(), + mUserManager, mWifiInjector, mBackupManagerProxy, mCountryCode, mWifiNative); mWsmThread = getWsmHandlerThread(mWsm); final AsyncChannel channel = new AsyncChannel(); @@ -446,6 +463,10 @@ public class WifiStateMachineTest { /* Now channel is supposed to be connected */ mBinderToken = Binder.clearCallingIdentity(); + + /* Send the BOOT_COMPLETED message to setup some WSM state. */ + mWsm.sendMessage(WifiStateMachine.CMD_BOOT_COMPLETED); + mLooper.dispatchAll(); } @After @@ -1868,4 +1889,135 @@ public class WifiStateMachineTest { verify(mWifiNative).setupForClientMode(); verify(mWifiMetrics).incrementNumWifiOnFailureDueToWificond(); } + + /** + * Test that we don't register the telephony call state listener on devices which do not support + * setting/resetting Tx power limit. + */ + @Test + public void testVoiceCallSar_disabledTxPowerLimit_WifiOn() throws Exception { + loadComponentsInStaMode(); + mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE); + assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest()); + assertEquals("DisconnectedState", getCurrentState().getName()); + assertNull(mPhoneStateListener); + } + + /** + * Test that we do register the telephony call state listener on devices which do support + * setting/resetting Tx power limit. + */ + @Test + public void testVoiceCallSar_enabledTxPowerLimit_WifiOn() throws Exception { + mResources.setBoolean( + R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit, true); + initializeWsm(); + + loadComponentsInStaMode(); + mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE); + assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest()); + assertEquals("DisconnectedState", getCurrentState().getName()); + assertNotNull(mPhoneStateListener); + } + + /** + * Test that we do register the telephony call state listener on devices which do support + * setting/resetting Tx power limit and set the tx power level if we're in state + * {@link TelephonyManager#CALL_STATE_OFFHOOK}. + */ + @Test + public void testVoiceCallSar_enabledTxPowerLimitCallStateOffHook_WhenWifiTurnedOn() + throws Exception { + int powerLevelInDbm = -45; + mResources.setInteger( + R.integer.config_wifi_framework_voice_call_sar_tx_power_limit_in_dbm, + powerLevelInDbm); + mResources.setBoolean( + R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit, true); + initializeWsm(); + + when(mTelephonyManager.isOffhook()).thenReturn(true); + + loadComponentsInStaMode(); + mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE); + assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest()); + assertEquals("DisconnectedState", getCurrentState().getName()); + assertNotNull(mPhoneStateListener); + verify(mWifiNative).setTxPowerLimit(eq(powerLevelInDbm)); + } + + /** + * Test that we do register the telephony call state listener on devices which do support + * setting/resetting Tx power limit and set the tx power level if we're in state + * {@link TelephonyManager#CALL_STATE_IDLE}. + */ + @Test + public void testVoiceCallSar_enabledTxPowerLimitCallStateIdle_WhenWifiTurnedOn() + throws Exception { + mResources.setBoolean( + R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit, true); + initializeWsm(); + + when(mTelephonyManager.isIdle()).thenReturn(true); + + loadComponentsInStaMode(); + mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE); + assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest()); + assertEquals("DisconnectedState", getCurrentState().getName()); + assertNotNull(mPhoneStateListener); + verify(mWifiNative).resetTxPowerLimit(); + } + + /** + * Test that we invoke the corresponding WifiNative method when + * {@link PhoneStateListener#onCallStateChanged(int, String)} is invoked with state + * {@link TelephonyManager#CALL_STATE_OFFHOOK}. + */ + @Test + public void testVoiceCallSar_enabledTxPowerLimitCallStateOffHook_WhenWifiOn() throws Exception { + int powerLevelInDbm = -45; + mResources.setInteger( + R.integer.config_wifi_framework_voice_call_sar_tx_power_limit_in_dbm, + powerLevelInDbm); + testVoiceCallSar_enabledTxPowerLimit_WifiOn(); + + mPhoneStateListener.onCallStateChanged(TelephonyManager.CALL_STATE_OFFHOOK, ""); + mLooper.dispatchAll(); + verify(mWifiNative).setTxPowerLimit(eq(powerLevelInDbm)); + } + + /** + * Test that we invoke the corresponding WifiNative method when + * {@link PhoneStateListener#onCallStateChanged(int, String)} is invoked with state + * {@link TelephonyManager#CALL_STATE_IDLE}. + */ + @Test + public void testVoiceCallSar_enabledTxPowerLimitCallStateIdle_WhenWifiOn() throws Exception { + testVoiceCallSar_enabledTxPowerLimit_WifiOn(); + + mPhoneStateListener.onCallStateChanged(TelephonyManager.CALL_STATE_IDLE, ""); + mLooper.dispatchAll(); + verify(mWifiNative).resetTxPowerLimit(); + } + + /** + * Test that we don't invoke the corresponding WifiNative method when + * {@link PhoneStateListener#onCallStateChanged(int, String)} is invoked with state + * {@link TelephonyManager#CALL_STATE_IDLE} or {@link TelephonyManager#CALL_STATE_OFFHOOK} when + * wifi is off (state machine is not in SupplicantStarted state). + */ + @Test + public void testVoiceCallSar_enabledTxPowerLimitCallState_WhenWifiOff() throws Exception { + mResources.setBoolean( + R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit, true); + initializeWsm(); + + mPhoneStateListener.onCallStateChanged(TelephonyManager.CALL_STATE_OFFHOOK, ""); + mLooper.dispatchAll(); + verify(mWifiNative, never()).setTxPowerLimit(anyInt()); + + mPhoneStateListener.onCallStateChanged(TelephonyManager.CALL_STATE_IDLE, ""); + mLooper.dispatchAll(); + verify(mWifiNative, never()).resetTxPowerLimit(); + } } |