diff options
4 files changed, 713 insertions, 4 deletions
diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java index 0f785873b..5369b0e1e 100644 --- a/service/java/com/android/server/wifi/WifiNative.java +++ b/service/java/com/android/server/wifi/WifiNative.java @@ -2820,12 +2820,18 @@ public class WifiNative { } /** + * TODO: These constants will be removed in a future change + * They are left for the interim use + * * Tx power level scenarios that can be selected. */ public static final int TX_POWER_SCENARIO_NORMAL = 0; public static final int TX_POWER_SCENARIO_VOICE_CALL = 1; /** + * TODO: This method is deprecated and will be removed in a future change to use + * the interface with sarInfo as an input instead. + * * Select one of the pre-configured TX power level scenarios or reset it back to normal. * Primarily used for meeting SAR requirements during voice calls. * @@ -2837,6 +2843,17 @@ public class WifiNative { return mWifiVendorHal.selectTxPowerScenario(scenario); } + /** + * Select one of the pre-configured transmit power level scenarios or reset it back to normal. + * Primarily used for meeting SAR requirements. + * + * @param sarInfo The collection of inputs used to select the SAR scenario. + * @return true for success; false for failure or if the HAL version does not support this API. + */ + public boolean selectTxPowerScenario(SarInfo sarInfo) { + return mWifiVendorHal.selectTxPowerScenario(sarInfo); + } + /******************************************************** * JNI operations ********************************************************/ diff --git a/service/java/com/android/server/wifi/WifiVendorHal.java b/service/java/com/android/server/wifi/WifiVendorHal.java index 0d73459b5..fdbd97fb0 100644 --- a/service/java/com/android/server/wifi/WifiVendorHal.java +++ b/service/java/com/android/server/wifi/WifiVendorHal.java @@ -2653,7 +2653,7 @@ public class WifiVendorHal { return android.hardware.wifi.V1_2.IWifiStaIface.castFrom(iface); } - + /* TODO: This method is to be removed in a future change */ private int frameworkToHalTxPowerScenario(int scenario) { switch (scenario) { case WifiNative.TX_POWER_SCENARIO_VOICE_CALL: @@ -2664,6 +2664,10 @@ public class WifiVendorHal { } /** + * TODO: This method will be removed in a future change + * It will be replaced with another method receiving SarInfo + * instance instead of the int for scenario + * * Select one of the pre-configured TX power level scenarios or reset it back to normal. * Primarily used for meeting SAR requirements during voice calls. * @@ -2699,6 +2703,229 @@ public class WifiVendorHal { } } + /** + * sarPowerBackoffRequired_1_1() + * This method checks if we need to backoff wifi Tx power due to SAR requirements. + * It handles the case when the device is running the V1_1 version of WifiChip HAL + * In that HAL version, it is required to perform wifi Tx power backoff only if + * a voice call is ongoing. + */ + private boolean sarPowerBackoffRequired_1_1(SarInfo sarInfo) { + /* As long as no voice call is active, no backoff is needed */ + return sarInfo.mIsVoiceCall; + } + + /** + * frameworkToHalTxPowerScenario_1_1() + * This method maps the information inside the SarInfo instance into a SAR scenario + * when device is running the V1_1 version of WifiChip HAL. + * In this HAL version, only one scenario is defined which is for VOICE_CALL + * otherwise, an exception is thrown. + */ + private int frameworkToHalTxPowerScenario_1_1(SarInfo sarInfo) { + if (sarInfo.mIsVoiceCall) { + return android.hardware.wifi.V1_1.IWifiChip.TxPowerScenario.VOICE_CALL; + } else { + throw new IllegalArgumentException("bad scenario: voice call not active"); + } + } + + /** + * sarPowerBackoffRequired_1_2() + * This method checks if we need to backoff wifi Tx power due to SAR requirements. + * It handles the case when the device is running the V1_2 version of WifiChip HAL + * In that HAL version, behavior depends on if SAR sensor input is considered in this device. + * If it is, then whenever the device is near the user body/hand/head, back-off is required. + * Otherwise, we should revert to the V1_1 HAL behavior which is only to perform backoff when + * a voice call is ongoing. + */ + private boolean sarPowerBackoffRequired_1_2(SarInfo sarInfo) { + if (sarInfo.mSarSensorEnabled) { + return (sarInfo.mSensorState != SarInfo.SAR_SENSOR_FREE_SPACE); + } else { + return sarInfo.mIsVoiceCall; + } + } + + /** + * frameworkToHalTxPowerScenario_1_2() + * This method maps the information inside the SarInfo instance into a SAR scenario + * when device is running the V1_2 version of WifiChip HAL. + * In this HAL version, behavior depends on if SAR sensor input is considered in this device. + * If it is, then based on regulatory compliance requirements, + * - There is no need to treat NEAR_HAND different from NEAR_BODY, both can be considered + * near the user body. + * - Running in softAP mode can be treated the same way as running a voice call from tx power + * backoff perspective. + * If SAR sensor input is not considered in this device, then we should revert to the V1_1 HAL + * behavior, and the only valid scenario would be when a voice call is ongoing. + */ + private int frameworkToHalTxPowerScenario_1_2(SarInfo sarInfo) { + if (sarInfo.mSarSensorEnabled) { + switch(sarInfo.mSensorState) { + case SarInfo.SAR_SENSOR_NEAR_BODY: + case SarInfo.SAR_SENSOR_NEAR_HAND: + if (sarInfo.mIsVoiceCall || sarInfo.mIsWifiSapEnabled) { + return android.hardware.wifi.V1_2.IWifiChip + .TxPowerScenario.ON_BODY_CELL_ON; + } else { + return android.hardware.wifi.V1_2.IWifiChip + .TxPowerScenario.ON_BODY_CELL_OFF; + } + + case SarInfo.SAR_SENSOR_NEAR_HEAD: + if (sarInfo.mIsVoiceCall || sarInfo.mIsWifiSapEnabled) { + return android.hardware.wifi.V1_2.IWifiChip + .TxPowerScenario.ON_HEAD_CELL_ON; + } else { + return android.hardware.wifi.V1_2.IWifiChip + .TxPowerScenario.ON_HEAD_CELL_OFF; + } + + default: + throw new IllegalArgumentException("bad scenario: Invalid sensor state"); + } + } else { + /* SAR Sensors not enabled, act like V1_1 */ + if (sarInfo.mIsVoiceCall) { + return android.hardware.wifi.V1_1.IWifiChip.TxPowerScenario.VOICE_CALL; + } else { + throw new IllegalArgumentException("bad scenario: voice call not active"); + } + } + } + + /** + * Select one of the pre-configured TX power level scenarios or reset it back to normal. + * Primarily used for meeting SAR requirements during voice calls. + * + * Note: If it was found out that the scenario to be reported is the same as last reported one, + * then exit with success. + * This is to handle the case when some HAL versions deal with different inputs equally, + * in that case, we should not call the hal unless there is a change in scenario. + * Note: It is assumed that this method is only called if SAR is enabled. The logic of whether + * to call it or not resides in SarManager class. + * Note: This method is called whether SAR sensor is supported or not. The passed SarInfo object + * contains a flag to indicate the SAR sensor support. + * + * @param sarInfo The collection of inputs to select the SAR scenario. + * @return true for success; false for failure or if the HAL version does not support this API. + */ + public boolean selectTxPowerScenario(SarInfo sarInfo) { + synchronized (sLock) { + // First attempt to get a V_1_2 instance of the Wifi HAL. + android.hardware.wifi.V1_2.IWifiChip iWifiChipV12 = getWifiChipForV1_2Mockable(); + if (iWifiChipV12 != null) { + return selectTxPowerScenario_1_2(iWifiChipV12, sarInfo); + } + + // Now attempt to get a V_1_1 instance of the Wifi HAL. + android.hardware.wifi.V1_1.IWifiChip iWifiChipV11 = getWifiChipForV1_1Mockable(); + if (iWifiChipV11 != null) { + return selectTxPowerScenario_1_1(iWifiChipV11, sarInfo); + } + + // HAL version does not support SAR + return false; + } + } + + private boolean selectTxPowerScenario_1_1( + android.hardware.wifi.V1_1.IWifiChip iWifiChip, SarInfo sarInfo) { + WifiStatus status; + try { + if (sarPowerBackoffRequired_1_1(sarInfo)) { + // Power backoff is needed, so calculate the required scenario, + // and attempt to set it. + int halScenario = frameworkToHalTxPowerScenario_1_1(sarInfo); + if (sarInfo.setSarScenarioNeeded(halScenario)) { + status = iWifiChip.selectTxPowerScenario(halScenario); + if (ok(status)) { + mLog.e("Setting SAR scenario to " + halScenario); + return true; + } else { + mLog.e("Failed to set SAR scenario to " + halScenario); + return false; + } + } + + // Reaching here means setting SAR scenario would be redundant, + // do nothing and return with success. + return true; + } + + // We don't need to perform power backoff, so attempt to reset SAR scenario. + if (sarInfo.resetSarScenarioNeeded()) { + status = iWifiChip.resetTxPowerScenario(); + if (ok(status)) { + mLog.d("Resetting SAR scenario"); + return true; + } else { + mLog.e("Failed to reset SAR scenario"); + return false; + } + } + + // Resetting SAR scenario would be redundant, + // do nothing and return with success. + return true; + } catch (RemoteException e) { + handleRemoteException(e); + return false; + } catch (IllegalArgumentException e) { + mLog.err("Illegal argument for selectTxPowerScenario_1_1()").c(e.toString()).flush(); + return false; + } + } + + private boolean selectTxPowerScenario_1_2( + android.hardware.wifi.V1_2.IWifiChip iWifiChip, SarInfo sarInfo) { + WifiStatus status; + try { + if (sarPowerBackoffRequired_1_2(sarInfo)) { + // Power backoff is needed, so calculate the required scenario, + // and attempt to set it. + int halScenario = frameworkToHalTxPowerScenario_1_2(sarInfo); + if (sarInfo.setSarScenarioNeeded(halScenario)) { + status = iWifiChip.selectTxPowerScenario_1_2(halScenario); + if (ok(status)) { + mLog.e("Setting SAR scenario to " + halScenario); + return true; + } else { + mLog.e("Failed to set SAR scenario to " + halScenario); + return false; + } + } + + // Reaching here means setting SAR scenario would be redundant, + // do nothing and return with success. + return true; + } + + // We don't need to perform power backoff, so attempt to reset SAR scenario. + if (sarInfo.resetSarScenarioNeeded()) { + status = iWifiChip.resetTxPowerScenario(); + if (ok(status)) { + mLog.d("Resetting SAR scenario"); + return true; + } else { + mLog.e("Failed to reset SAR scenario"); + return false; + } + } + + // Resetting SAR scenario would be redundant, + // do nothing and return with success. + return true; + } catch (RemoteException e) { + handleRemoteException(e); + return false; + } catch (IllegalArgumentException e) { + mLog.err("Illegal argument for selectTxPowerScenario_1_2()").c(e.toString()).flush(); + return false; + } + } + // This creates a blob of IE elements from the array received. // TODO: This ugly conversion can be removed if we put IE elements in ScanResult. private static byte[] hidlIeArrayToFrameworkIeBlob(ArrayList<WifiInformationElement> ies) { diff --git a/tests/wifitests/src/com/android/server/wifi/WifiNativeTest.java b/tests/wifitests/src/com/android/server/wifi/WifiNativeTest.java index 31e7e553c..fbdc8f507 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiNativeTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiNativeTest.java @@ -586,4 +586,26 @@ public class WifiNativeTest { verify(mWificondControl).startHostapd(WIFI_IFACE_NAME, mockListener); verify(mWifiMetrics).incrementNumSetupSoftApInterfaceFailureDueToHostapd(); } + + /** + * Test that selectTxPowerScenario() calls into WifiVendorHal (success case) + */ + @Test + public void testSelectTxPowerScenario_success() throws Exception { + when(mWifiVendorHal.selectTxPowerScenario(any(SarInfo.class))).thenReturn(true); + SarInfo sarInfo = new SarInfo(true); + assertTrue(mWifiNative.selectTxPowerScenario(sarInfo)); + verify(mWifiVendorHal).selectTxPowerScenario(sarInfo); + } + + /** + * Test that selectTxPowerScenario() calls into WifiVendorHal (failure case) + */ + @Test + public void testSelectTxPowerScenario_failure() throws Exception { + when(mWifiVendorHal.selectTxPowerScenario(any(SarInfo.class))).thenReturn(false); + SarInfo sarInfo = new SarInfo(true); + assertFalse(mWifiNative.selectTxPowerScenario(sarInfo)); + verify(mWifiVendorHal).selectTxPowerScenario(sarInfo); + } } diff --git a/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java b/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java index 0f8f56f66..60b5f81ad 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java @@ -32,6 +32,7 @@ import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; @@ -99,6 +100,7 @@ import com.android.server.wifi.util.NativeUtil; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; +import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.stubbing.Answer; @@ -119,6 +121,7 @@ public class WifiVendorHalTest { private static final String TEST_IFACE_NAME = "wlan0"; private static final String TEST_IFACE_NAME_1 = "wlan1"; private static final MacAddress TEST_MAC_ADDRESS = MacAddress.fromString("ee:33:a2:94:10:92"); + private static final int SAR_SENSOR_INVALID_STATE = -6; WifiVendorHal mWifiVendorHal; private WifiStatus mWifiStatusSuccess; @@ -1997,11 +2000,14 @@ public class WifiVendorHalTest { } /** + * TODO: This test will be removed in a following change + * It is going to be replaced by another test using the new structure + * * Test the new selectTxPowerScenario HIDL method invocation. This should return failure if the * HAL service is exposing the 1.0 interface. */ @Test - public void testSelectTxPowerScenario() throws RemoteException { + public void testSelectTxPowerScenario_old() throws RemoteException { assertTrue(mWifiVendorHal.startVendorHalSta()); // Should fail because we exposed the 1.0 IWifiChip. assertFalse( @@ -2023,11 +2029,14 @@ public class WifiVendorHalTest { } /** + * TODO: This test will be removed in a following change + * It is going to be replaced by another test using the new structure + * * Test the new resetTxPowerScenario HIDL method invocation. This should return failure if the * HAL service is exposing the 1.0 interface. */ @Test - public void testResetTxPowerScenario() throws RemoteException { + public void testResetTxPowerScenario_old() throws RemoteException { assertTrue(mWifiVendorHal.startVendorHalSta()); // Should fail because we exposed the 1.0 IWifiChip. assertFalse(mWifiVendorHal.selectTxPowerScenario(WifiNative.TX_POWER_SCENARIO_NORMAL)); @@ -2046,10 +2055,13 @@ public class WifiVendorHalTest { } /** + * TODO: This test will be removed in a following change + * It is going to be replaced by another test using the new structure + * * Test the new selectTxPowerScenario HIDL method invocation with a bad scenario index. */ @Test - public void testInvalidSelectTxPowerScenario() throws RemoteException { + public void testInvalidSelectTxPowerScenario_old() throws RemoteException { // Expose the 1.1 IWifiChip. mWifiVendorHal = new WifiVendorHalSpyV1_1(mHalDeviceManager, mLooper.getLooper()); when(mIWifiChipV11.selectTxPowerScenario(anyInt())).thenReturn(mWifiStatusSuccess); @@ -2062,6 +2074,437 @@ public class WifiVendorHalTest { } /** + * Test the selectTxPowerScenario HIDL method invocation for 1.0 interface. + * This should return failure since SAR is not supported for this interface version. + */ + @Test + public void testSelectTxPowerScenario_1_0() throws RemoteException { + // Create a SAR info record (no sensor support) + SarInfo sarInfo = new SarInfo(false); + sarInfo.mIsVoiceCall = true; + + assertTrue(mWifiVendorHal.startVendorHalSta()); + // Should fail because we exposed the 1.0 IWifiChip. + assertFalse(mWifiVendorHal.selectTxPowerScenario(sarInfo)); + verify(mIWifiChipV11, never()).selectTxPowerScenario(anyInt()); + mWifiVendorHal.stopVendorHal(); + } + + /** + * Test the selectTxPowerScenario HIDL method invocation for 1.1 interface. + * This should return success. + */ + @Test + public void testSelectTxPowerScenario_1_1() throws RemoteException { + // Create a SAR info record (no sensor support) + SarInfo sarInfo = new SarInfo(false); + sarInfo.mIsVoiceCall = true; + + // Now expose the 1.1 IWifiChip. + mWifiVendorHal = new WifiVendorHalSpyV1_1(mHalDeviceManager, mLooper.getLooper()); + when(mIWifiChipV11.selectTxPowerScenario(anyInt())).thenReturn(mWifiStatusSuccess); + + assertTrue(mWifiVendorHal.startVendorHalSta()); + assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo)); + verify(mIWifiChipV11).selectTxPowerScenario( + eq(android.hardware.wifi.V1_1.IWifiChip.TxPowerScenario.VOICE_CALL)); + verify(mIWifiChipV11, never()).resetTxPowerScenario(); + mWifiVendorHal.stopVendorHal(); + } + + /** + * Test the selectTxPowerScenario HIDL method invocation for 1.2 interface. + * This should return success. + */ + @Test + public void testSelectTxPowerScenario_1_2() throws RemoteException { + // Create a SAR info record (no sensor support) + SarInfo sarInfo = new SarInfo(false); + sarInfo.mIsVoiceCall = true; + + // Now expose the 1.2 IWifiChip + mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper()); + when(mIWifiChipV12.selectTxPowerScenario_1_2(anyInt())).thenReturn(mWifiStatusSuccess); + + assertTrue(mWifiVendorHal.startVendorHalSta()); + assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo)); + verify(mIWifiChipV12).selectTxPowerScenario_1_2( + eq(android.hardware.wifi.V1_2.IWifiChip.TxPowerScenario.VOICE_CALL)); + verify(mIWifiChipV12, never()).resetTxPowerScenario(); + mWifiVendorHal.stopVendorHal(); + } + + /** + * Test the resetTxPowerScenario HIDL method invocation for 1.0 interface. + * This should return failure since it does not supprt SAR. + */ + @Test + public void testResetTxPowerScenario_1_0() throws RemoteException { + // Create a SAR info record (no sensor support) + SarInfo sarInfo = new SarInfo(false); + + assertTrue(mWifiVendorHal.startVendorHalSta()); + // Should fail because we exposed the 1.0 IWifiChip. + assertFalse(mWifiVendorHal.selectTxPowerScenario(sarInfo)); + verify(mIWifiChipV11, never()).resetTxPowerScenario(); + mWifiVendorHal.stopVendorHal(); + } + + /** + * Test the resetTxPowerScenario HIDL method invocation for 1.1 interface. + * This should return success. + */ + @Test + public void testResetTxPowerScenario_1_1() throws RemoteException { + // Create a SAR info record (no sensor support) + SarInfo sarInfo = new SarInfo(false); + + // Now expose the 1.1 IWifiChip. + mWifiVendorHal = new WifiVendorHalSpyV1_1(mHalDeviceManager, mLooper.getLooper()); + when(mIWifiChipV11.resetTxPowerScenario()).thenReturn(mWifiStatusSuccess); + + assertTrue(mWifiVendorHal.startVendorHalSta()); + assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo)); + verify(mIWifiChipV11).resetTxPowerScenario(); + verify(mIWifiChipV11, never()).selectTxPowerScenario(anyInt()); + mWifiVendorHal.stopVendorHal(); + } + + /** + * Test resetting SAR scenario when not needed, should return true without invoking + * the HAL method. + * This is using HAL 1.1 interface. + */ + @Test + public void testResetTxPowerScenario_not_needed_1_1() throws RemoteException { + InOrder inOrder = inOrder(mIWifiChipV11); + + // Create a SAR info record (no sensor support) + SarInfo sarInfo = new SarInfo(false); + + // Now expose the 1.1 IWifiChip. + mWifiVendorHal = new WifiVendorHalSpyV1_1(mHalDeviceManager, mLooper.getLooper()); + when(mIWifiChipV11.resetTxPowerScenario()).thenReturn(mWifiStatusSuccess); + + assertTrue(mWifiVendorHal.startVendorHalSta()); + + /* Calling reset once */ + assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo)); + inOrder.verify(mIWifiChipV11).resetTxPowerScenario(); + inOrder.verify(mIWifiChipV11, never()).selectTxPowerScenario(anyInt()); + sarInfo.reportingSuccessful(); + + /* Calling reset second time */ + assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo)); + inOrder.verify(mIWifiChipV11, never()).resetTxPowerScenario(); + inOrder.verify(mIWifiChipV11, never()).selectTxPowerScenario(anyInt()); + + mWifiVendorHal.stopVendorHal(); + } + + /** + * Test the new resetTxPowerScenario HIDL method invocation for 1.2 interface. + * This should return success. + */ + @Test + public void testResetTxPowerScenario_1_2() throws RemoteException { + // Create a SAR info record (no sensor support) + SarInfo sarInfo = new SarInfo(false); + + // Now expose the 1.2 IWifiChip. + mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper()); + when(mIWifiChipV12.resetTxPowerScenario()).thenReturn(mWifiStatusSuccess); + + assertTrue(mWifiVendorHal.startVendorHalSta()); + assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo)); + verify(mIWifiChipV12).resetTxPowerScenario(); + verify(mIWifiChipV12, never()).selectTxPowerScenario_1_2(anyInt()); + mWifiVendorHal.stopVendorHal(); + } + + /** + * Test resetting SAR scenario when not needed, should return true without invoking + * the HAL method. + * This is using HAL 1.2 interface. + */ + @Test + public void testResetTxPowerScenario_not_needed_1_2() throws RemoteException { + InOrder inOrder = inOrder(mIWifiChipV12); + + // Create a SAR info record (no sensor support) + SarInfo sarInfo = new SarInfo(false); + + // Now expose the 1.2 IWifiChip. + mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper()); + when(mIWifiChipV12.resetTxPowerScenario()).thenReturn(mWifiStatusSuccess); + + assertTrue(mWifiVendorHal.startVendorHalSta()); + + /* Calling reset once */ + assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo)); + inOrder.verify(mIWifiChipV12).resetTxPowerScenario(); + inOrder.verify(mIWifiChipV12, never()).selectTxPowerScenario(anyInt()); + sarInfo.reportingSuccessful(); + + /* Calling reset second time */ + assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo)); + inOrder.verify(mIWifiChipV12, never()).resetTxPowerScenario(); + inOrder.verify(mIWifiChipV12, never()).selectTxPowerScenario(anyInt()); + + mWifiVendorHal.stopVendorHal(); + } + + /** + * Test the selectTxPowerScenario HIDL method invocation with sensor related scenarios + * to IWifiChip 1.2 interface + */ + @Test + public void testHeadSensorScenarios_SelectTxPowerV1_2() throws RemoteException { + // Create a SAR info record (with sensor support) + SarInfo sarInfo = new SarInfo(true); + sarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD; + + // Expose the 1.2 IWifiChip. + mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper()); + when(mIWifiChipV12.selectTxPowerScenario_1_2(anyInt())).thenReturn(mWifiStatusSuccess); + + // ON_HEAD_CELL_OFF + assertTrue(mWifiVendorHal.startVendorHalSta()); + assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo)); + verify(mIWifiChipV12).selectTxPowerScenario_1_2( + eq(android.hardware.wifi.V1_2.IWifiChip.TxPowerScenario.ON_HEAD_CELL_OFF)); + verify(mIWifiChipV12, never()).resetTxPowerScenario(); + mWifiVendorHal.stopVendorHal(); + } + + /** + * Test setting SAR scenario when not needed, should return true without invoking + * the HAL method. + * This is using HAL 1.2 interface. + */ + @Test + public void testSetTxPowerScenario_not_needed_1_2() throws RemoteException { + InOrder inOrder = inOrder(mIWifiChipV12); + + // Create a SAR info record (no sensor support) + SarInfo sarInfo = new SarInfo(true); + sarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD; + + // Now expose the 1.2 IWifiChip. + mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper()); + when(mIWifiChipV12.selectTxPowerScenario_1_2(anyInt())).thenReturn(mWifiStatusSuccess); + + assertTrue(mWifiVendorHal.startVendorHalSta()); + + /* Calling set once */ + assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo)); + inOrder.verify(mIWifiChipV12).selectTxPowerScenario_1_2( + eq(android.hardware.wifi.V1_2.IWifiChip.TxPowerScenario.ON_HEAD_CELL_OFF)); + inOrder.verify(mIWifiChipV12, never()).resetTxPowerScenario(); + sarInfo.reportingSuccessful(); + + /* Calling set second time */ + assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo)); + inOrder.verify(mIWifiChipV12, never()).resetTxPowerScenario(); + inOrder.verify(mIWifiChipV12, never()).selectTxPowerScenario(anyInt()); + + mWifiVendorHal.stopVendorHal(); + } + + /** + * Test the selectTxPowerScenairo HIDL method invocation with sensor events for + * IWifiChip 1.2 interface (Near hand event) along with a voice call. + * This should be reverted to BODY events (First with CELL_OFF followed by CELL_ON). + */ + @Test + public void testHandSensorScenarios_SelectTxPowerV1_2() throws RemoteException { + // Create a SAR info record (with sensor support) + SarInfo sarInfo = new SarInfo(true); + sarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HAND; + + // Expose the 1.2 IWifiChip. + mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper()); + when(mIWifiChipV12.selectTxPowerScenario_1_2(anyInt())).thenReturn(mWifiStatusSuccess); + + assertTrue(mWifiVendorHal.startVendorHalSta()); + + // First select a scenario with cell off + assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo)); + verify(mIWifiChipV12).selectTxPowerScenario_1_2( + eq(android.hardware.wifi.V1_2.IWifiChip.TxPowerScenario.ON_BODY_CELL_OFF)); + + // Then select a scenario with cell on + sarInfo.mIsVoiceCall = true; + assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo)); + verify(mIWifiChipV12).selectTxPowerScenario_1_2( + eq(android.hardware.wifi.V1_2.IWifiChip.TxPowerScenario.ON_BODY_CELL_ON)); + + mWifiVendorHal.stopVendorHal(); + } + + /** + * Test the selectTxPowerScenario HIDL method invocation with a sensor info to IWifiChip + * 1.1 interface. + * Sensor mode should be ignored, and act only based on Cell on/off. + */ + @Test + public void testOnHeadCellOffOn_SelectTxPowerScenarioV1_1() throws RemoteException { + // Create a SAR info record (with sensor support) + SarInfo sarInfo = new SarInfo(true); + sarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD; + + // Expose the 1.1 IWifiChip. + mWifiVendorHal = new WifiVendorHalSpyV1_1(mHalDeviceManager, mLooper.getLooper()); + when(mIWifiChipV11.selectTxPowerScenario(anyInt())).thenReturn(mWifiStatusSuccess); + when(mIWifiChipV11.resetTxPowerScenario()).thenReturn(mWifiStatusSuccess); + + assertTrue(mWifiVendorHal.startVendorHalSta()); + + // First select a scenario with cell off + assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo)); + verify(mIWifiChipV11).resetTxPowerScenario(); + + // Then select a scenario with cell on + sarInfo.mIsVoiceCall = true; + assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo)); + verify(mIWifiChipV11).selectTxPowerScenario( + eq(android.hardware.wifi.V1_1.IWifiChip.TxPowerScenario.VOICE_CALL)); + + mWifiVendorHal.stopVendorHal(); + } + + /** + * Test the new selectTxPowerScenario HIDL method invocation with a bad input. + * This should not result into any calls to the HAL. + * Use IWifiChip 1.2 interface + */ + @Test + public void testInvalidSelectTxPowerScenario_1_2() throws RemoteException { + // Create a SAR info record (with sensor support) + SarInfo sarInfo = new SarInfo(true); + sarInfo.mSensorState = SAR_SENSOR_INVALID_STATE; + + // Expose the 1.2 IWifiChip. + mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper()); + + assertTrue(mWifiVendorHal.startVendorHalSta()); + assertFalse(mWifiVendorHal.selectTxPowerScenario(sarInfo)); + verify(mIWifiChipV12, never()).selectTxPowerScenario(anyInt()); + verify(mIWifiChipV12, never()).resetTxPowerScenario(); + mWifiVendorHal.stopVendorHal(); + } + + /** + * Test the selectTxPowerScenario HIDL method invocation with IWifiChip 1.2 interface. + * The following inputs: + * - Sensor support is enabled + * - Sensor state is NEAR_HEAD + * - SAP is enabled + * - No voice call + */ + @Test + public void testSelectTxPowerScenario_1_2_head_sap() throws RemoteException { + // Create a SAR info record (with sensor support) + SarInfo sarInfo = new SarInfo(true); + sarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD; + sarInfo.mIsWifiSapEnabled = true; + sarInfo.mIsVoiceCall = false; + + // Expose the 1.2 IWifiChip. + mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper()); + when(mIWifiChipV12.selectTxPowerScenario_1_2(anyInt())).thenReturn(mWifiStatusSuccess); + + assertTrue(mWifiVendorHal.startVendorHalSta()); + assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo)); + verify(mIWifiChipV12).selectTxPowerScenario_1_2( + eq(android.hardware.wifi.V1_2.IWifiChip.TxPowerScenario.ON_HEAD_CELL_ON)); + + mWifiVendorHal.stopVendorHal(); + } + + /** + * Test the selectTxPowerScenario HIDL method invocation with IWifiChip 1.2 interface. + * The following inputs: + * - Sensor support is enabled + * - Sensor state is NEAR_HEAD + * - SAP is enabled + * - voice call is enabled + */ + @Test + public void testSelectTxPowerScenario_1_2_head_sap_call() throws RemoteException { + // Create a SAR info record (with sensor support) + SarInfo sarInfo = new SarInfo(true); + sarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD; + sarInfo.mIsWifiSapEnabled = true; + sarInfo.mIsVoiceCall = true; + + // Expose the 1.2 IWifiChip. + mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper()); + when(mIWifiChipV12.selectTxPowerScenario_1_2(anyInt())).thenReturn(mWifiStatusSuccess); + + assertTrue(mWifiVendorHal.startVendorHalSta()); + assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo)); + verify(mIWifiChipV12).selectTxPowerScenario_1_2( + eq(android.hardware.wifi.V1_2.IWifiChip.TxPowerScenario.ON_HEAD_CELL_ON)); + + mWifiVendorHal.stopVendorHal(); + } + + /** + * Test the selectTxPowerScenario HIDL method invocation with IWifiChip 1.2 interface. + * The following inputs: + * - Sensor support is enabled + * - Sensor state is FREE_SPACE + * - SAP is enabled + * - No voice call + */ + @Test + public void testSelectTxPowerScenario_1_2_freespace_sap() throws RemoteException { + // Create a SAR info record (with sensor support) + SarInfo sarInfo = new SarInfo(true); + sarInfo.mSensorState = SarInfo.SAR_SENSOR_FREE_SPACE; + sarInfo.mIsWifiSapEnabled = true; + sarInfo.mIsVoiceCall = false; + + // Expose the 1.2 IWifiChip. + mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper()); + when(mIWifiChipV12.resetTxPowerScenario()).thenReturn(mWifiStatusSuccess); + + assertTrue(mWifiVendorHal.startVendorHalSta()); + assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo)); + + verify(mIWifiChipV12).resetTxPowerScenario(); + verify(mIWifiChipV12, never()).selectTxPowerScenario_1_2(anyInt()); + mWifiVendorHal.stopVendorHal(); + } + + /** + * Test the selectTxPowerScenario HIDL method invocation with IWifiChip 1.2 interface. + * The following inputs: + * - Sensor support is disabled + * - SAP is enabled + * - No voice call + */ + @Test + public void testSelectTxPowerScenario_1_2_no_sensors_sap() throws RemoteException { + // Create a SAR info record (with no sensor support) + SarInfo sarInfo = new SarInfo(false); + sarInfo.mIsWifiSapEnabled = true; + sarInfo.mIsVoiceCall = false; + + // Expose the 1.2 IWifiChip. + mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper()); + when(mIWifiChipV12.resetTxPowerScenario()).thenReturn(mWifiStatusSuccess); + + assertTrue(mWifiVendorHal.startVendorHalSta()); + assertTrue(mWifiVendorHal.selectTxPowerScenario(sarInfo)); + + verify(mIWifiChipV12).resetTxPowerScenario(); + verify(mIWifiChipV12, never()).selectTxPowerScenario_1_2(anyInt()); + mWifiVendorHal.stopVendorHal(); + } + + /** * Test the STA Iface creation failure due to iface name retrieval failure. */ @Test |